diff --git a/Source/Android/jni/ButtonManager.cpp b/Source/Android/jni/ButtonManager.cpp index 83dcfb64e7..7db0fe31ed 100644 --- a/Source/Android/jni/ButtonManager.cpp +++ b/Source/Android/jni/ButtonManager.cpp @@ -11,620 +11,454 @@ namespace ButtonManager { - const std::string touchScreenKey = "Touchscreen"; - std::unordered_map m_controllers; - std::vector configStrings = { - // GC - "InputA", - "InputB", - "InputStart", - "InputX", - "InputY", - "InputZ", - "DPadUp", - "DPadDown", - "DPadLeft", - "DPadRight", - "MainUp", - "MainDown", - "MainLeft", - "MainRight", - "CStickUp", - "CStickDown", - "CStickLeft", - "CStickRight", - "InputL", - "InputR", - // Wiimote - "WiimoteA", - "WiimoteB", - "WiimoteMinus", - "WiimotePlus", - "WiimoteHome", - "Wiimote1", - "Wiimote2", - "WiimoteUp", - "WiimoteDown", - "WiimoteLeft", - "WiimoteRight", - "IRUp", - "IRDown", - "IRLeft", - "IRRight", - "IRForward", - "IRBackward", - "IRHide", - "SwingUp", - "SwingDown", - "SwingLeft", - "SwingRight", - "SwingForward", - "SwingBackward", - "TiltForward", - "TiltBackward", - "TiltLeft", - "TiltRight", - "TiltModifier" - "ShakeX", - "ShakeY", - "ShakeZ", - // Nunchuk - "NunchukC", - "NunchukZ", - "NunchukUp", - "NunchukDown", - "NunchukLeft", - "NunchukRight", - "NunchukSwingUp", - "NunchukSwingDown", - "NunchukSwingLeft", - "NunchukSwingRight", - "NunchukSwingForward", - "NunchukSwingBackward", - "NunchukTiltForward", - "NunchukTiltBackward", - "NunchukTiltLeft", - "NunchukTiltRight", - "NunchukTiltModifier", - "NunchukShakeX", - "NunchukShakeY", - "NunchukShakeZ", - // Classic - "ClassicA", - "ClassicB", - "ClassicX", - "ClassicY", - "ClassicMinus", - "ClassicPlus", - "ClassicHome", - "ClassicZL", - "ClassicZR", - "ClassicUp", - "ClassicDown", - "ClassicLeft", - "ClassicRight", - "ClassicLeftStickUp", - "ClassicLeftStickDown", - "ClassicLeftStickLeft", - "ClassicLeftStickRight", - "ClassicRightStickUp", - "ClassicRightStickDown", - "ClassicRightStickLeft", - "ClassicRightStickRight", - "ClassicTriggerL", - "ClassicTriggerR", - // Guitar - "GuitarMinus", - "GuitarPlus", - "GuitarGreen", - "GuitarRed", - "GuitarYellow", - "GuitarBue", - "GuitarOrange", - "GuitarStrumUp", - "GuitarStrumDown", - "GuitarUp", - "GuitarDown", - "GuitarLeft", - "GuitarRight", - "GuitarWhammy", - // Drums - "DrumsMinus", - "DrumsPlus", - "DrumsRed", - "DrumsYellow", - "DrumsBlue", - "DrumsGreen", - "DrumsOrange", - "DrumsBass", - "DrumsUp", - "DrumsDown", - "DrumsLeft", - "DrumsRight", - // Turntable - "TurntableGreenLeft", - "TurntableRedLeft", - "TurntableBlueLeft", - "TurntableGreenRight", - "TurntableRedRight", - "TurntableBlueRight", - "TurntableMinus", - "TurntablePlus", - "TurntableHome", - "TurntableEuphoria", - "TurntableLeftTLeft", - "TurntableLeftTRight", - "TurntableRightTLeft", - "TurntableRightTRight", - "TurntableUp", - "TurntableDown", - "TurntableLeft", - "TurntableRight", - "TurntableEffDial", - "TurntableCrossLeft", - "TurntableCrossRight", - }; - std::vector configTypes = { - // GC - BUTTON_A, - BUTTON_B, - BUTTON_START, - BUTTON_X, - BUTTON_Y, - BUTTON_Z, - BUTTON_UP, - BUTTON_DOWN, - BUTTON_LEFT, - BUTTON_RIGHT, - STICK_MAIN_UP, - STICK_MAIN_DOWN, - STICK_MAIN_LEFT, - STICK_MAIN_RIGHT, - STICK_C_UP, - STICK_C_DOWN, - STICK_C_LEFT, - STICK_C_RIGHT, - TRIGGER_L, - TRIGGER_R, - // Wiimote - WIIMOTE_BUTTON_A, - WIIMOTE_BUTTON_B, - WIIMOTE_BUTTON_MINUS, - WIIMOTE_BUTTON_PLUS, - WIIMOTE_BUTTON_HOME, - WIIMOTE_BUTTON_1, - WIIMOTE_BUTTON_2, - WIIMOTE_UP, - WIIMOTE_DOWN, - WIIMOTE_LEFT, - WIIMOTE_RIGHT, - WIIMOTE_IR_UP, - WIIMOTE_IR_DOWN, - WIIMOTE_IR_LEFT, - WIIMOTE_IR_RIGHT, - WIIMOTE_IR_FORWARD, - WIIMOTE_IR_BACKWARD, - WIIMOTE_IR_HIDE, - WIIMOTE_SWING_UP, - WIIMOTE_SWING_DOWN, - WIIMOTE_SWING_LEFT, - WIIMOTE_SWING_RIGHT, - WIIMOTE_SWING_FORWARD, - WIIMOTE_SWING_BACKWARD, - WIIMOTE_TILT_FORWARD, - WIIMOTE_TILT_BACKWARD, - WIIMOTE_TILT_LEFT, - WIIMOTE_TILT_RIGHT, - WIIMOTE_TILT_MODIFIER, - WIIMOTE_SHAKE_X, - WIIMOTE_SHAKE_Y, - WIIMOTE_SHAKE_Z, - // Nunchuk - NUNCHUK_BUTTON_C, - NUNCHUK_BUTTON_Z, - NUNCHUK_STICK_UP, - NUNCHUK_STICK_DOWN, - NUNCHUK_STICK_LEFT, - NUNCHUK_STICK_RIGHT, - NUNCHUK_SWING_UP, - NUNCHUK_SWING_DOWN, - NUNCHUK_SWING_LEFT, - NUNCHUK_SWING_RIGHT, - NUNCHUK_SWING_FORWARD, - NUNCHUK_SWING_BACKWARD, - NUNCHUK_TILT_FORWARD, - NUNCHUK_TILT_BACKWARD, - NUNCHUK_TILT_LEFT, - NUNCHUK_TILT_RIGHT, - NUNCHUK_TILT_MODIFIER, - NUNCHUK_SHAKE_X, - NUNCHUK_SHAKE_Y, - NUNCHUK_SHAKE_Z, - // Classic - CLASSIC_BUTTON_A, - CLASSIC_BUTTON_B, - CLASSIC_BUTTON_X, - CLASSIC_BUTTON_Y, - CLASSIC_BUTTON_MINUS, - CLASSIC_BUTTON_PLUS, - CLASSIC_BUTTON_HOME, - CLASSIC_BUTTON_ZL, - CLASSIC_BUTTON_ZR, - CLASSIC_DPAD_UP, - CLASSIC_DPAD_DOWN, - CLASSIC_DPAD_LEFT, - CLASSIC_DPAD_RIGHT, - CLASSIC_STICK_LEFT_UP, - CLASSIC_STICK_LEFT_DOWN, - CLASSIC_STICK_LEFT_LEFT, - CLASSIC_STICK_LEFT_RIGHT, - CLASSIC_STICK_RIGHT_UP, - CLASSIC_STICK_RIGHT_DOWN, - CLASSIC_STICK_RIGHT_LEFT, - CLASSIC_STICK_RIGHT_RIGHT, - CLASSIC_TRIGGER_L, - CLASSIC_TRIGGER_R, - // Guitar - GUITAR_BUTTON_MINUS, - GUITAR_BUTTON_PLUS, - GUITAR_FRET_GREEN, - GUITAR_FRET_RED, - GUITAR_FRET_YELLOW, - GUITAR_FRET_BLUE, - GUITAR_FRET_ORANGE, - GUITAR_STRUM_UP, - GUITAR_STRUM_DOWN, - GUITAR_STICK_UP, - GUITAR_STICK_DOWN, - GUITAR_STICK_LEFT, - GUITAR_STICK_RIGHT, - GUITAR_WHAMMY_BAR, - // Drums - DRUMS_BUTTON_MINUS, - DRUMS_BUTTON_PLUS, - DRUMS_PAD_RED, - DRUMS_PAD_YELLOW, - DRUMS_PAD_BLUE, - DRUMS_PAD_GREEN, - DRUMS_PAD_ORANGE, - DRUMS_PAD_BASS, - DRUMS_STICK_UP, - DRUMS_STICK_DOWN, - DRUMS_STICK_LEFT, - DRUMS_STICK_RIGHT, - // Turntable - TURNTABLE_BUTTON_GREEN_LEFT, - TURNTABLE_BUTTON_RED_LEFT, - TURNTABLE_BUTTON_BLUE_LEFT, - TURNTABLE_BUTTON_GREEN_RIGHT, - TURNTABLE_BUTTON_RED_RIGHT, - TURNTABLE_BUTTON_BLUE_RIGHT, - TURNTABLE_BUTTON_MINUS, - TURNTABLE_BUTTON_PLUS, - TURNTABLE_BUTTON_HOME, - TURNTABLE_BUTTON_EUPHORIA, - TURNTABLE_TABLE_LEFT_LEFT, - TURNTABLE_TABLE_LEFT_RIGHT, - TURNTABLE_TABLE_RIGHT_LEFT, - TURNTABLE_TABLE_RIGHT_RIGHT, - TURNTABLE_STICK_UP, - TURNTABLE_STICK_DOWN, - TURNTABLE_STICK_LEFT, - TURNTABLE_STICK_RIGHT, - TURNTABLE_EFFECT_DIAL, - TURNTABLE_CROSSFADE_LEFT, - TURNTABLE_CROSSFADE_RIGHT, - }; +const std::string touchScreenKey = "Touchscreen"; +std::unordered_map m_controllers; +std::vector configStrings = { + // GC + "InputA", "InputB", "InputStart", "InputX", "InputY", "InputZ", "DPadUp", "DPadDown", + "DPadLeft", "DPadRight", "MainUp", "MainDown", "MainLeft", "MainRight", "CStickUp", + "CStickDown", "CStickLeft", "CStickRight", "InputL", "InputR", + // Wiimote + "WiimoteA", "WiimoteB", "WiimoteMinus", "WiimotePlus", "WiimoteHome", "Wiimote1", "Wiimote2", + "WiimoteUp", "WiimoteDown", "WiimoteLeft", "WiimoteRight", "IRUp", "IRDown", "IRLeft", + "IRRight", "IRForward", "IRBackward", "IRHide", "SwingUp", "SwingDown", "SwingLeft", + "SwingRight", "SwingForward", "SwingBackward", "TiltForward", "TiltBackward", "TiltLeft", + "TiltRight", "TiltModifier" + "ShakeX", + "ShakeY", "ShakeZ", + // Nunchuk + "NunchukC", "NunchukZ", "NunchukUp", "NunchukDown", "NunchukLeft", "NunchukRight", + "NunchukSwingUp", "NunchukSwingDown", "NunchukSwingLeft", "NunchukSwingRight", + "NunchukSwingForward", "NunchukSwingBackward", "NunchukTiltForward", "NunchukTiltBackward", + "NunchukTiltLeft", "NunchukTiltRight", "NunchukTiltModifier", "NunchukShakeX", "NunchukShakeY", + "NunchukShakeZ", + // Classic + "ClassicA", "ClassicB", "ClassicX", "ClassicY", "ClassicMinus", "ClassicPlus", "ClassicHome", + "ClassicZL", "ClassicZR", "ClassicUp", "ClassicDown", "ClassicLeft", "ClassicRight", + "ClassicLeftStickUp", "ClassicLeftStickDown", "ClassicLeftStickLeft", "ClassicLeftStickRight", + "ClassicRightStickUp", "ClassicRightStickDown", "ClassicRightStickLeft", + "ClassicRightStickRight", "ClassicTriggerL", "ClassicTriggerR", + // Guitar + "GuitarMinus", "GuitarPlus", "GuitarGreen", "GuitarRed", "GuitarYellow", "GuitarBue", + "GuitarOrange", "GuitarStrumUp", "GuitarStrumDown", "GuitarUp", "GuitarDown", "GuitarLeft", + "GuitarRight", "GuitarWhammy", + // Drums + "DrumsMinus", "DrumsPlus", "DrumsRed", "DrumsYellow", "DrumsBlue", "DrumsGreen", "DrumsOrange", + "DrumsBass", "DrumsUp", "DrumsDown", "DrumsLeft", "DrumsRight", + // Turntable + "TurntableGreenLeft", "TurntableRedLeft", "TurntableBlueLeft", "TurntableGreenRight", + "TurntableRedRight", "TurntableBlueRight", "TurntableMinus", "TurntablePlus", "TurntableHome", + "TurntableEuphoria", "TurntableLeftTLeft", "TurntableLeftTRight", "TurntableRightTLeft", + "TurntableRightTRight", "TurntableUp", "TurntableDown", "TurntableLeft", "TurntableRight", + "TurntableEffDial", "TurntableCrossLeft", "TurntableCrossRight", +}; +std::vector configTypes = { + // GC + BUTTON_A, BUTTON_B, BUTTON_START, BUTTON_X, BUTTON_Y, BUTTON_Z, BUTTON_UP, BUTTON_DOWN, + BUTTON_LEFT, BUTTON_RIGHT, STICK_MAIN_UP, STICK_MAIN_DOWN, STICK_MAIN_LEFT, STICK_MAIN_RIGHT, + STICK_C_UP, STICK_C_DOWN, STICK_C_LEFT, STICK_C_RIGHT, TRIGGER_L, TRIGGER_R, + // Wiimote + WIIMOTE_BUTTON_A, WIIMOTE_BUTTON_B, WIIMOTE_BUTTON_MINUS, WIIMOTE_BUTTON_PLUS, + WIIMOTE_BUTTON_HOME, WIIMOTE_BUTTON_1, WIIMOTE_BUTTON_2, WIIMOTE_UP, WIIMOTE_DOWN, WIIMOTE_LEFT, + WIIMOTE_RIGHT, WIIMOTE_IR_UP, WIIMOTE_IR_DOWN, WIIMOTE_IR_LEFT, WIIMOTE_IR_RIGHT, + WIIMOTE_IR_FORWARD, WIIMOTE_IR_BACKWARD, WIIMOTE_IR_HIDE, WIIMOTE_SWING_UP, WIIMOTE_SWING_DOWN, + WIIMOTE_SWING_LEFT, WIIMOTE_SWING_RIGHT, WIIMOTE_SWING_FORWARD, WIIMOTE_SWING_BACKWARD, + WIIMOTE_TILT_FORWARD, WIIMOTE_TILT_BACKWARD, WIIMOTE_TILT_LEFT, WIIMOTE_TILT_RIGHT, + WIIMOTE_TILT_MODIFIER, WIIMOTE_SHAKE_X, WIIMOTE_SHAKE_Y, WIIMOTE_SHAKE_Z, + // Nunchuk + NUNCHUK_BUTTON_C, NUNCHUK_BUTTON_Z, NUNCHUK_STICK_UP, NUNCHUK_STICK_DOWN, NUNCHUK_STICK_LEFT, + NUNCHUK_STICK_RIGHT, NUNCHUK_SWING_UP, NUNCHUK_SWING_DOWN, NUNCHUK_SWING_LEFT, + NUNCHUK_SWING_RIGHT, NUNCHUK_SWING_FORWARD, NUNCHUK_SWING_BACKWARD, NUNCHUK_TILT_FORWARD, + NUNCHUK_TILT_BACKWARD, NUNCHUK_TILT_LEFT, NUNCHUK_TILT_RIGHT, NUNCHUK_TILT_MODIFIER, + NUNCHUK_SHAKE_X, NUNCHUK_SHAKE_Y, NUNCHUK_SHAKE_Z, + // Classic + CLASSIC_BUTTON_A, CLASSIC_BUTTON_B, CLASSIC_BUTTON_X, CLASSIC_BUTTON_Y, CLASSIC_BUTTON_MINUS, + CLASSIC_BUTTON_PLUS, CLASSIC_BUTTON_HOME, CLASSIC_BUTTON_ZL, CLASSIC_BUTTON_ZR, CLASSIC_DPAD_UP, + CLASSIC_DPAD_DOWN, CLASSIC_DPAD_LEFT, CLASSIC_DPAD_RIGHT, CLASSIC_STICK_LEFT_UP, + CLASSIC_STICK_LEFT_DOWN, CLASSIC_STICK_LEFT_LEFT, CLASSIC_STICK_LEFT_RIGHT, + CLASSIC_STICK_RIGHT_UP, CLASSIC_STICK_RIGHT_DOWN, CLASSIC_STICK_RIGHT_LEFT, + CLASSIC_STICK_RIGHT_RIGHT, CLASSIC_TRIGGER_L, CLASSIC_TRIGGER_R, + // Guitar + GUITAR_BUTTON_MINUS, GUITAR_BUTTON_PLUS, GUITAR_FRET_GREEN, GUITAR_FRET_RED, GUITAR_FRET_YELLOW, + GUITAR_FRET_BLUE, GUITAR_FRET_ORANGE, GUITAR_STRUM_UP, GUITAR_STRUM_DOWN, GUITAR_STICK_UP, + GUITAR_STICK_DOWN, GUITAR_STICK_LEFT, GUITAR_STICK_RIGHT, GUITAR_WHAMMY_BAR, + // Drums + DRUMS_BUTTON_MINUS, DRUMS_BUTTON_PLUS, DRUMS_PAD_RED, DRUMS_PAD_YELLOW, DRUMS_PAD_BLUE, + DRUMS_PAD_GREEN, DRUMS_PAD_ORANGE, DRUMS_PAD_BASS, DRUMS_STICK_UP, DRUMS_STICK_DOWN, + DRUMS_STICK_LEFT, DRUMS_STICK_RIGHT, + // Turntable + TURNTABLE_BUTTON_GREEN_LEFT, TURNTABLE_BUTTON_RED_LEFT, TURNTABLE_BUTTON_BLUE_LEFT, + TURNTABLE_BUTTON_GREEN_RIGHT, TURNTABLE_BUTTON_RED_RIGHT, TURNTABLE_BUTTON_BLUE_RIGHT, + TURNTABLE_BUTTON_MINUS, TURNTABLE_BUTTON_PLUS, TURNTABLE_BUTTON_HOME, TURNTABLE_BUTTON_EUPHORIA, + TURNTABLE_TABLE_LEFT_LEFT, TURNTABLE_TABLE_LEFT_RIGHT, TURNTABLE_TABLE_RIGHT_LEFT, + TURNTABLE_TABLE_RIGHT_RIGHT, TURNTABLE_STICK_UP, TURNTABLE_STICK_DOWN, TURNTABLE_STICK_LEFT, + TURNTABLE_STICK_RIGHT, TURNTABLE_EFFECT_DIAL, TURNTABLE_CROSSFADE_LEFT, + TURNTABLE_CROSSFADE_RIGHT, +}; - static void AddBind(const std::string& dev, sBind *bind) - { - auto it = m_controllers.find(dev); - if (it != m_controllers.end()) - { - it->second->AddBind(bind); - return; - } - m_controllers[dev] = new InputDevice(dev); - m_controllers[dev]->AddBind(bind); - } - - void Init() - { - // Initialize our touchScreenKey buttons - for (int a = 0; a < 8; ++a) - { - // GC - AddBind(touchScreenKey, new sBind(a, BUTTON_A, BIND_BUTTON, BUTTON_A, 1.0f)); - AddBind(touchScreenKey, new sBind(a, BUTTON_B, BIND_BUTTON, BUTTON_B, 1.0f)); - AddBind(touchScreenKey, new sBind(a, BUTTON_START, BIND_BUTTON, BUTTON_START, 1.0f)); - AddBind(touchScreenKey, new sBind(a, BUTTON_X, BIND_BUTTON, BUTTON_X, 1.0f)); - AddBind(touchScreenKey, new sBind(a, BUTTON_Y, BIND_BUTTON, BUTTON_Y, 1.0f)); - AddBind(touchScreenKey, new sBind(a, BUTTON_Z, BIND_BUTTON, BUTTON_Z, 1.0f)); - AddBind(touchScreenKey, new sBind(a, BUTTON_UP, BIND_BUTTON, BUTTON_UP, 1.0f)); - AddBind(touchScreenKey, new sBind(a, BUTTON_DOWN, BIND_BUTTON, BUTTON_DOWN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, BUTTON_LEFT, BIND_BUTTON, BUTTON_LEFT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, BUTTON_RIGHT, BIND_BUTTON, BUTTON_RIGHT, 1.0f)); - - AddBind(touchScreenKey, new sBind(a, STICK_MAIN_UP, BIND_AXIS, STICK_MAIN_UP, -1.0f)); - AddBind(touchScreenKey, new sBind(a, STICK_MAIN_DOWN, BIND_AXIS, STICK_MAIN_DOWN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, STICK_MAIN_LEFT, BIND_AXIS, STICK_MAIN_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, STICK_MAIN_RIGHT, BIND_AXIS, STICK_MAIN_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, STICK_C_UP, BIND_AXIS, STICK_C_UP, -1.0f)); - AddBind(touchScreenKey, new sBind(a, STICK_C_DOWN, BIND_AXIS, STICK_C_DOWN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, STICK_C_LEFT, BIND_AXIS, STICK_C_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, STICK_C_RIGHT, BIND_AXIS, STICK_C_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TRIGGER_L, BIND_AXIS, TRIGGER_L, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TRIGGER_R, BIND_AXIS, TRIGGER_R, 1.0f)); - - // Wiimote - AddBind(touchScreenKey, new sBind(a, WIIMOTE_BUTTON_A, BIND_BUTTON, WIIMOTE_BUTTON_A, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_BUTTON_B, BIND_BUTTON, WIIMOTE_BUTTON_B, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_BUTTON_MINUS, BIND_BUTTON, WIIMOTE_BUTTON_MINUS, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_BUTTON_PLUS, BIND_BUTTON, WIIMOTE_BUTTON_PLUS, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_BUTTON_HOME, BIND_BUTTON, WIIMOTE_BUTTON_HOME, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_BUTTON_1, BIND_BUTTON, WIIMOTE_BUTTON_1, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_BUTTON_2, BIND_BUTTON, WIIMOTE_BUTTON_2, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_UP, BIND_BUTTON, WIIMOTE_UP, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_DOWN, BIND_BUTTON, WIIMOTE_DOWN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_LEFT, BIND_BUTTON, WIIMOTE_LEFT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_RIGHT, BIND_BUTTON, WIIMOTE_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_IR_HIDE, BIND_BUTTON, WIIMOTE_IR_HIDE, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_TILT_MODIFIER, BIND_BUTTON, WIIMOTE_TILT_MODIFIER, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_SHAKE_X, BIND_BUTTON, WIIMOTE_SHAKE_X, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_SHAKE_Y, BIND_BUTTON, WIIMOTE_SHAKE_Y, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_SHAKE_Z, BIND_BUTTON, WIIMOTE_SHAKE_Z, 1.0f)); - - AddBind(touchScreenKey, new sBind(a, WIIMOTE_IR_UP, BIND_AXIS, WIIMOTE_IR_UP, -1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_IR_DOWN, BIND_AXIS, WIIMOTE_IR_DOWN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_IR_LEFT, BIND_AXIS, WIIMOTE_IR_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_IR_RIGHT, BIND_AXIS, WIIMOTE_IR_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_IR_FORWARD, BIND_AXIS, WIIMOTE_IR_FORWARD, -1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_IR_BACKWARD, BIND_AXIS, WIIMOTE_IR_BACKWARD, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_SWING_UP, BIND_AXIS, WIIMOTE_SWING_UP, -1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_SWING_DOWN, BIND_AXIS, WIIMOTE_SWING_DOWN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_SWING_LEFT, BIND_AXIS, WIIMOTE_SWING_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_SWING_RIGHT, BIND_AXIS, WIIMOTE_SWING_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_SWING_FORWARD, BIND_AXIS, WIIMOTE_SWING_FORWARD, -1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_SWING_BACKWARD, BIND_AXIS, WIIMOTE_SWING_BACKWARD, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_TILT_FORWARD, BIND_AXIS, WIIMOTE_TILT_FORWARD, -1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_TILT_BACKWARD, BIND_AXIS, WIIMOTE_TILT_BACKWARD, 1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_TILT_LEFT, BIND_AXIS, WIIMOTE_TILT_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, WIIMOTE_TILT_RIGHT, BIND_AXIS, WIIMOTE_TILT_RIGHT, 1.0f)); - - // Wii: Nunchuk - AddBind(touchScreenKey, new sBind(a, NUNCHUK_BUTTON_C, BIND_BUTTON, NUNCHUK_BUTTON_C, 1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_BUTTON_Z, BIND_BUTTON, NUNCHUK_BUTTON_Z, 1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_TILT_MODIFIER, BIND_BUTTON, NUNCHUK_TILT_MODIFIER, 1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_SHAKE_X, BIND_BUTTON, NUNCHUK_SHAKE_X, 1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_SHAKE_Y, BIND_BUTTON, NUNCHUK_SHAKE_Y, 1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_SHAKE_Z, BIND_BUTTON, NUNCHUK_SHAKE_Z, 1.0f)); - - AddBind(touchScreenKey, new sBind(a, NUNCHUK_SWING_UP, BIND_AXIS, NUNCHUK_SWING_UP, -1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_SWING_DOWN, BIND_AXIS, NUNCHUK_SWING_DOWN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_SWING_LEFT, BIND_AXIS, NUNCHUK_SWING_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_SWING_RIGHT, BIND_AXIS, NUNCHUK_SWING_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_SWING_FORWARD, BIND_AXIS, NUNCHUK_SWING_FORWARD, -1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_SWING_BACKWARD, BIND_BUTTON, NUNCHUK_SWING_BACKWARD, 1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_TILT_FORWARD, BIND_AXIS, NUNCHUK_TILT_FORWARD, -1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_TILT_BACKWARD, BIND_AXIS, NUNCHUK_TILT_BACKWARD, 1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_TILT_LEFT, BIND_AXIS, NUNCHUK_TILT_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_TILT_RIGHT, BIND_AXIS, NUNCHUK_TILT_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_STICK_UP, BIND_AXIS, NUNCHUK_STICK_UP, -1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_STICK_DOWN, BIND_AXIS, NUNCHUK_STICK_DOWN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_STICK_LEFT, BIND_AXIS, NUNCHUK_STICK_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, NUNCHUK_STICK_RIGHT, BIND_AXIS, NUNCHUK_STICK_RIGHT, 1.0f)); - - // Wii: Classic - AddBind(touchScreenKey, new sBind(a, CLASSIC_BUTTON_A, BIND_BUTTON, CLASSIC_BUTTON_A, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_BUTTON_B, BIND_BUTTON, CLASSIC_BUTTON_B, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_BUTTON_X, BIND_BUTTON, CLASSIC_BUTTON_X, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_BUTTON_Y, BIND_BUTTON, CLASSIC_BUTTON_Y, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_BUTTON_MINUS, BIND_BUTTON, CLASSIC_BUTTON_MINUS, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_BUTTON_PLUS, BIND_BUTTON, CLASSIC_BUTTON_PLUS, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_BUTTON_HOME, BIND_BUTTON, CLASSIC_BUTTON_HOME, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_BUTTON_ZL, BIND_BUTTON, CLASSIC_BUTTON_ZL, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_BUTTON_ZR, BIND_BUTTON, CLASSIC_BUTTON_ZR, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_DPAD_UP, BIND_BUTTON, CLASSIC_DPAD_UP, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_DPAD_DOWN, BIND_BUTTON, CLASSIC_DPAD_DOWN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_DPAD_LEFT, BIND_BUTTON, CLASSIC_DPAD_LEFT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_DPAD_RIGHT, BIND_BUTTON, CLASSIC_DPAD_RIGHT, 1.0f)); - - AddBind(touchScreenKey, new sBind(a, CLASSIC_STICK_LEFT_UP, BIND_AXIS, CLASSIC_STICK_LEFT_UP, -1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_STICK_LEFT_DOWN, BIND_AXIS, CLASSIC_STICK_LEFT_DOWN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_STICK_LEFT_LEFT, BIND_AXIS, CLASSIC_STICK_LEFT_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_STICK_LEFT_RIGHT, BIND_AXIS, CLASSIC_STICK_LEFT_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_STICK_RIGHT_UP, BIND_AXIS, CLASSIC_STICK_RIGHT_UP, -1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_STICK_RIGHT_DOWN, BIND_AXIS, CLASSIC_STICK_RIGHT_DOWN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_STICK_RIGHT_LEFT, BIND_AXIS, CLASSIC_STICK_RIGHT_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_STICK_RIGHT_RIGHT, BIND_AXIS, CLASSIC_STICK_RIGHT_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_TRIGGER_L, BIND_AXIS, CLASSIC_TRIGGER_L, 1.0f)); - AddBind(touchScreenKey, new sBind(a, CLASSIC_TRIGGER_R, BIND_AXIS, CLASSIC_TRIGGER_R, 1.0f)); - - // Wii: Guitar - AddBind(touchScreenKey, new sBind(a, GUITAR_BUTTON_MINUS, BIND_BUTTON, GUITAR_BUTTON_MINUS, 1.0f)); - AddBind(touchScreenKey, new sBind(a, GUITAR_BUTTON_PLUS, BIND_BUTTON, GUITAR_BUTTON_PLUS, 1.0f)); - AddBind(touchScreenKey, new sBind(a, GUITAR_FRET_GREEN, BIND_BUTTON, GUITAR_FRET_GREEN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, GUITAR_FRET_RED, BIND_BUTTON, GUITAR_FRET_RED, 1.0f)); - AddBind(touchScreenKey, new sBind(a, GUITAR_FRET_YELLOW, BIND_BUTTON, GUITAR_FRET_YELLOW, 1.0f)); - AddBind(touchScreenKey, new sBind(a, GUITAR_FRET_BLUE, BIND_BUTTON, GUITAR_FRET_BLUE, 1.0f)); - AddBind(touchScreenKey, new sBind(a, GUITAR_FRET_ORANGE, BIND_BUTTON, GUITAR_FRET_ORANGE, 1.0f)); - AddBind(touchScreenKey, new sBind(a, GUITAR_STRUM_UP, BIND_BUTTON, GUITAR_STRUM_UP, 1.0f)); - AddBind(touchScreenKey, new sBind(a, GUITAR_STRUM_DOWN, BIND_BUTTON, GUITAR_STRUM_DOWN, 1.0f)); - - AddBind(touchScreenKey, new sBind(a, GUITAR_STICK_UP, BIND_AXIS, GUITAR_STICK_UP, -1.0f)); - AddBind(touchScreenKey, new sBind(a, GUITAR_STICK_DOWN, BIND_AXIS, GUITAR_STICK_DOWN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, GUITAR_STICK_LEFT, BIND_AXIS, GUITAR_STICK_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, GUITAR_STICK_RIGHT, BIND_AXIS, GUITAR_STICK_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, GUITAR_WHAMMY_BAR, BIND_AXIS, GUITAR_WHAMMY_BAR, 1.0f)); - - // Wii: Drums - AddBind(touchScreenKey, new sBind(a, DRUMS_BUTTON_MINUS, BIND_BUTTON, DRUMS_BUTTON_MINUS, 1.0f)); - AddBind(touchScreenKey, new sBind(a, DRUMS_BUTTON_PLUS, BIND_BUTTON, DRUMS_BUTTON_PLUS, 1.0f)); - AddBind(touchScreenKey, new sBind(a, DRUMS_PAD_RED, BIND_BUTTON, DRUMS_PAD_RED, 1.0f)); - AddBind(touchScreenKey, new sBind(a, DRUMS_PAD_YELLOW, BIND_BUTTON, DRUMS_PAD_YELLOW, 1.0f)); - AddBind(touchScreenKey, new sBind(a, DRUMS_PAD_BLUE, BIND_BUTTON, DRUMS_PAD_BLUE, 1.0f)); - AddBind(touchScreenKey, new sBind(a, DRUMS_PAD_GREEN, BIND_BUTTON, DRUMS_PAD_GREEN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, DRUMS_PAD_ORANGE, BIND_BUTTON, DRUMS_PAD_ORANGE, 1.0f)); - AddBind(touchScreenKey, new sBind(a, DRUMS_PAD_BASS, BIND_BUTTON, DRUMS_PAD_BASS, 1.0f)); - - AddBind(touchScreenKey, new sBind(a, DRUMS_STICK_UP, BIND_AXIS, DRUMS_STICK_UP, -1.0f)); - AddBind(touchScreenKey, new sBind(a, DRUMS_STICK_DOWN, BIND_AXIS, DRUMS_STICK_DOWN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, DRUMS_STICK_LEFT, BIND_AXIS, DRUMS_STICK_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, DRUMS_STICK_RIGHT, BIND_AXIS, DRUMS_STICK_RIGHT, 1.0f)); - - // Wii: Turntable - AddBind(touchScreenKey, new sBind(a, TURNTABLE_BUTTON_GREEN_LEFT, BIND_BUTTON, TURNTABLE_BUTTON_GREEN_LEFT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_BUTTON_RED_LEFT, BIND_BUTTON, TURNTABLE_BUTTON_RED_LEFT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_BUTTON_BLUE_LEFT, BIND_BUTTON, TURNTABLE_BUTTON_BLUE_LEFT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_BUTTON_GREEN_RIGHT, BIND_BUTTON, TURNTABLE_BUTTON_GREEN_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_BUTTON_RED_RIGHT, BIND_BUTTON, TURNTABLE_BUTTON_RED_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_BUTTON_BLUE_RIGHT, BIND_BUTTON, TURNTABLE_BUTTON_BLUE_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_BUTTON_MINUS, BIND_BUTTON, TURNTABLE_BUTTON_MINUS, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_BUTTON_PLUS, BIND_BUTTON, TURNTABLE_BUTTON_PLUS, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_BUTTON_HOME, BIND_BUTTON, TURNTABLE_BUTTON_HOME, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_BUTTON_EUPHORIA, BIND_BUTTON, TURNTABLE_BUTTON_EUPHORIA, 1.0f)); - - AddBind(touchScreenKey, new sBind(a, TURNTABLE_TABLE_LEFT_LEFT, BIND_AXIS, TURNTABLE_TABLE_LEFT_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_TABLE_LEFT_RIGHT, BIND_AXIS, TURNTABLE_TABLE_LEFT_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_TABLE_RIGHT_LEFT, BIND_AXIS, TURNTABLE_TABLE_RIGHT_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_TABLE_RIGHT_RIGHT, BIND_AXIS, TURNTABLE_TABLE_RIGHT_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_STICK_UP, BIND_AXIS, TURNTABLE_STICK_UP, -1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_STICK_DOWN, BIND_AXIS, TURNTABLE_STICK_DOWN, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_STICK_LEFT, BIND_AXIS, TURNTABLE_STICK_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_STICK_RIGHT, BIND_AXIS, TURNTABLE_STICK_RIGHT, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_EFFECT_DIAL, BIND_AXIS, TURNTABLE_EFFECT_DIAL, 1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_CROSSFADE_LEFT, BIND_AXIS, TURNTABLE_CROSSFADE_LEFT, -1.0f)); - AddBind(touchScreenKey, new sBind(a, TURNTABLE_CROSSFADE_RIGHT, BIND_AXIS, TURNTABLE_CROSSFADE_RIGHT, 1.0f)); - } - // Init our controller bindings - IniFile ini; - ini.Load(File::GetUserPath(D_CONFIG_IDX) + std::string("Dolphin.ini")); - for (u32 a = 0; a < configStrings.size(); ++a) - { - for (int padID = 0; padID < 8; ++padID) - { - std::ostringstream config; - config << configStrings[a] << "_" << padID; - BindType type; - int bindnum; - char dev[128]; - bool hasbind = false; - char modifier = '+'; - std::string value; - ini.GetOrCreateSection("Android")->Get(config.str(), &value, "None"); - if (value == "None") - continue; - if (std::string::npos != value.find("Axis")) - { - hasbind = true; - type = BIND_AXIS; - sscanf(value.c_str(), "Device '%127[^\']'-Axis %d%c", dev, &bindnum, &modifier); - } - else if (std::string::npos != value.find("Button")) - { - hasbind = true; - type = BIND_BUTTON; - sscanf(value.c_str(), "Device '%127[^\']'-Button %d", dev, &bindnum); - } - if (hasbind) - AddBind(std::string(dev), new sBind(padID, configTypes[a], type, bindnum, modifier == '-' ? -1.0f : 1.0f)); - } - } - - } - bool GetButtonPressed(int padID, ButtonType button) - { - bool pressed = m_controllers[touchScreenKey]->ButtonValue(padID, button); - - for (const auto& ctrl : m_controllers) - pressed |= ctrl.second->ButtonValue(padID, button); - - return pressed; - } - float GetAxisValue(int padID, ButtonType axis) - { - float value = m_controllers[touchScreenKey]->AxisValue(padID, axis); - if (value == 0.0f) - { - for (const auto& ctrl : m_controllers) - { - value = ctrl.second->AxisValue(padID, axis); - if (value != 0.0f) - return value; - } - } - return value; - } - bool GamepadEvent(const std::string& dev, int button, int action) - { - auto it = m_controllers.find(dev); - if (it != m_controllers.end()) - return it->second->PressEvent(button, action); - return false; - } - void GamepadAxisEvent(const std::string& dev, int axis, float value) - { - auto it = m_controllers.find(dev); - if (it != m_controllers.end()) - it->second->AxisEvent(axis, value); - } - void Shutdown() - { - for (const auto& controller : m_controllers) - delete controller.second; - m_controllers.clear(); - } - - // InputDevice - bool InputDevice::PressEvent(int button, int action) - { - bool handled = false; - for (const auto& binding : _inputbinds) - { - if (binding.second->_bind == button) - { - if (binding.second->_bindtype == BIND_BUTTON) - _buttons[binding.second->_buttontype] = action == BUTTON_PRESSED ? true : false; - else - _axises[binding.second->_buttontype] = action == BUTTON_PRESSED ? 1.0f : 0.0f; - handled = true; - } - } - return handled; - } - void InputDevice::AxisEvent(int axis, float value) - { - for (const auto& binding : _inputbinds) - { - if (binding.second->_bind == axis) - { - if (binding.second->_bindtype == BIND_AXIS) - _axises[binding.second->_buttontype] = value; - else - _buttons[binding.second->_buttontype] = value > 0.5f ? true : false; - } - } - } - bool InputDevice::ButtonValue(int padID, ButtonType button) - { - const auto& binding = _inputbinds.find(std::make_pair(padID, button)); - if (binding == _inputbinds.end()) - return false; - - if (binding->second->_bindtype == BIND_BUTTON) - return _buttons[binding->second->_buttontype]; - else - return (_axises[binding->second->_buttontype] * binding->second->_neg) > 0.5f; - } - float InputDevice::AxisValue(int padID, ButtonType axis) - { - const auto& binding = _inputbinds.find(std::make_pair(padID, axis)); - if (binding == _inputbinds.end()) - return 0.0f; - - if (binding->second->_bindtype == BIND_AXIS) - return _axises[binding->second->_buttontype] * binding->second->_neg; - else - return _buttons[binding->second->_buttontype] == BUTTON_PRESSED ? 1.0f : 0.0f; - } +static void AddBind(const std::string& dev, sBind* bind) +{ + auto it = m_controllers.find(dev); + if (it != m_controllers.end()) + { + it->second->AddBind(bind); + return; + } + m_controllers[dev] = new InputDevice(dev); + m_controllers[dev]->AddBind(bind); +} + +void Init() +{ + // Initialize our touchScreenKey buttons + for (int a = 0; a < 8; ++a) + { + // GC + AddBind(touchScreenKey, new sBind(a, BUTTON_A, BIND_BUTTON, BUTTON_A, 1.0f)); + AddBind(touchScreenKey, new sBind(a, BUTTON_B, BIND_BUTTON, BUTTON_B, 1.0f)); + AddBind(touchScreenKey, new sBind(a, BUTTON_START, BIND_BUTTON, BUTTON_START, 1.0f)); + AddBind(touchScreenKey, new sBind(a, BUTTON_X, BIND_BUTTON, BUTTON_X, 1.0f)); + AddBind(touchScreenKey, new sBind(a, BUTTON_Y, BIND_BUTTON, BUTTON_Y, 1.0f)); + AddBind(touchScreenKey, new sBind(a, BUTTON_Z, BIND_BUTTON, BUTTON_Z, 1.0f)); + AddBind(touchScreenKey, new sBind(a, BUTTON_UP, BIND_BUTTON, BUTTON_UP, 1.0f)); + AddBind(touchScreenKey, new sBind(a, BUTTON_DOWN, BIND_BUTTON, BUTTON_DOWN, 1.0f)); + AddBind(touchScreenKey, new sBind(a, BUTTON_LEFT, BIND_BUTTON, BUTTON_LEFT, 1.0f)); + AddBind(touchScreenKey, new sBind(a, BUTTON_RIGHT, BIND_BUTTON, BUTTON_RIGHT, 1.0f)); + + AddBind(touchScreenKey, new sBind(a, STICK_MAIN_UP, BIND_AXIS, STICK_MAIN_UP, -1.0f)); + AddBind(touchScreenKey, new sBind(a, STICK_MAIN_DOWN, BIND_AXIS, STICK_MAIN_DOWN, 1.0f)); + AddBind(touchScreenKey, new sBind(a, STICK_MAIN_LEFT, BIND_AXIS, STICK_MAIN_LEFT, -1.0f)); + AddBind(touchScreenKey, new sBind(a, STICK_MAIN_RIGHT, BIND_AXIS, STICK_MAIN_RIGHT, 1.0f)); + AddBind(touchScreenKey, new sBind(a, STICK_C_UP, BIND_AXIS, STICK_C_UP, -1.0f)); + AddBind(touchScreenKey, new sBind(a, STICK_C_DOWN, BIND_AXIS, STICK_C_DOWN, 1.0f)); + AddBind(touchScreenKey, new sBind(a, STICK_C_LEFT, BIND_AXIS, STICK_C_LEFT, -1.0f)); + AddBind(touchScreenKey, new sBind(a, STICK_C_RIGHT, BIND_AXIS, STICK_C_RIGHT, 1.0f)); + AddBind(touchScreenKey, new sBind(a, TRIGGER_L, BIND_AXIS, TRIGGER_L, 1.0f)); + AddBind(touchScreenKey, new sBind(a, TRIGGER_R, BIND_AXIS, TRIGGER_R, 1.0f)); + + // Wiimote + AddBind(touchScreenKey, new sBind(a, WIIMOTE_BUTTON_A, BIND_BUTTON, WIIMOTE_BUTTON_A, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_BUTTON_B, BIND_BUTTON, WIIMOTE_BUTTON_B, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, WIIMOTE_BUTTON_MINUS, BIND_BUTTON, WIIMOTE_BUTTON_MINUS, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, WIIMOTE_BUTTON_PLUS, BIND_BUTTON, WIIMOTE_BUTTON_PLUS, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, WIIMOTE_BUTTON_HOME, BIND_BUTTON, WIIMOTE_BUTTON_HOME, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_BUTTON_1, BIND_BUTTON, WIIMOTE_BUTTON_1, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_BUTTON_2, BIND_BUTTON, WIIMOTE_BUTTON_2, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_UP, BIND_BUTTON, WIIMOTE_UP, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_DOWN, BIND_BUTTON, WIIMOTE_DOWN, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_LEFT, BIND_BUTTON, WIIMOTE_LEFT, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_RIGHT, BIND_BUTTON, WIIMOTE_RIGHT, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_IR_HIDE, BIND_BUTTON, WIIMOTE_IR_HIDE, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, WIIMOTE_TILT_MODIFIER, BIND_BUTTON, WIIMOTE_TILT_MODIFIER, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_SHAKE_X, BIND_BUTTON, WIIMOTE_SHAKE_X, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_SHAKE_Y, BIND_BUTTON, WIIMOTE_SHAKE_Y, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_SHAKE_Z, BIND_BUTTON, WIIMOTE_SHAKE_Z, 1.0f)); + + AddBind(touchScreenKey, new sBind(a, WIIMOTE_IR_UP, BIND_AXIS, WIIMOTE_IR_UP, -1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_IR_DOWN, BIND_AXIS, WIIMOTE_IR_DOWN, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_IR_LEFT, BIND_AXIS, WIIMOTE_IR_LEFT, -1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_IR_RIGHT, BIND_AXIS, WIIMOTE_IR_RIGHT, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_IR_FORWARD, BIND_AXIS, WIIMOTE_IR_FORWARD, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, WIIMOTE_IR_BACKWARD, BIND_AXIS, WIIMOTE_IR_BACKWARD, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_SWING_UP, BIND_AXIS, WIIMOTE_SWING_UP, -1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_SWING_DOWN, BIND_AXIS, WIIMOTE_SWING_DOWN, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_SWING_LEFT, BIND_AXIS, WIIMOTE_SWING_LEFT, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, WIIMOTE_SWING_RIGHT, BIND_AXIS, WIIMOTE_SWING_RIGHT, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, WIIMOTE_SWING_FORWARD, BIND_AXIS, WIIMOTE_SWING_FORWARD, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, WIIMOTE_SWING_BACKWARD, BIND_AXIS, WIIMOTE_SWING_BACKWARD, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, WIIMOTE_TILT_FORWARD, BIND_AXIS, WIIMOTE_TILT_FORWARD, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, WIIMOTE_TILT_BACKWARD, BIND_AXIS, WIIMOTE_TILT_BACKWARD, 1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_TILT_LEFT, BIND_AXIS, WIIMOTE_TILT_LEFT, -1.0f)); + AddBind(touchScreenKey, new sBind(a, WIIMOTE_TILT_RIGHT, BIND_AXIS, WIIMOTE_TILT_RIGHT, 1.0f)); + + // Wii: Nunchuk + AddBind(touchScreenKey, new sBind(a, NUNCHUK_BUTTON_C, BIND_BUTTON, NUNCHUK_BUTTON_C, 1.0f)); + AddBind(touchScreenKey, new sBind(a, NUNCHUK_BUTTON_Z, BIND_BUTTON, NUNCHUK_BUTTON_Z, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, NUNCHUK_TILT_MODIFIER, BIND_BUTTON, NUNCHUK_TILT_MODIFIER, 1.0f)); + AddBind(touchScreenKey, new sBind(a, NUNCHUK_SHAKE_X, BIND_BUTTON, NUNCHUK_SHAKE_X, 1.0f)); + AddBind(touchScreenKey, new sBind(a, NUNCHUK_SHAKE_Y, BIND_BUTTON, NUNCHUK_SHAKE_Y, 1.0f)); + AddBind(touchScreenKey, new sBind(a, NUNCHUK_SHAKE_Z, BIND_BUTTON, NUNCHUK_SHAKE_Z, 1.0f)); + + AddBind(touchScreenKey, new sBind(a, NUNCHUK_SWING_UP, BIND_AXIS, NUNCHUK_SWING_UP, -1.0f)); + AddBind(touchScreenKey, new sBind(a, NUNCHUK_SWING_DOWN, BIND_AXIS, NUNCHUK_SWING_DOWN, 1.0f)); + AddBind(touchScreenKey, new sBind(a, NUNCHUK_SWING_LEFT, BIND_AXIS, NUNCHUK_SWING_LEFT, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, NUNCHUK_SWING_RIGHT, BIND_AXIS, NUNCHUK_SWING_RIGHT, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, NUNCHUK_SWING_FORWARD, BIND_AXIS, NUNCHUK_SWING_FORWARD, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, NUNCHUK_SWING_BACKWARD, BIND_BUTTON, NUNCHUK_SWING_BACKWARD, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, NUNCHUK_TILT_FORWARD, BIND_AXIS, NUNCHUK_TILT_FORWARD, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, NUNCHUK_TILT_BACKWARD, BIND_AXIS, NUNCHUK_TILT_BACKWARD, 1.0f)); + AddBind(touchScreenKey, new sBind(a, NUNCHUK_TILT_LEFT, BIND_AXIS, NUNCHUK_TILT_LEFT, -1.0f)); + AddBind(touchScreenKey, new sBind(a, NUNCHUK_TILT_RIGHT, BIND_AXIS, NUNCHUK_TILT_RIGHT, 1.0f)); + AddBind(touchScreenKey, new sBind(a, NUNCHUK_STICK_UP, BIND_AXIS, NUNCHUK_STICK_UP, -1.0f)); + AddBind(touchScreenKey, new sBind(a, NUNCHUK_STICK_DOWN, BIND_AXIS, NUNCHUK_STICK_DOWN, 1.0f)); + AddBind(touchScreenKey, new sBind(a, NUNCHUK_STICK_LEFT, BIND_AXIS, NUNCHUK_STICK_LEFT, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, NUNCHUK_STICK_RIGHT, BIND_AXIS, NUNCHUK_STICK_RIGHT, 1.0f)); + + // Wii: Classic + AddBind(touchScreenKey, new sBind(a, CLASSIC_BUTTON_A, BIND_BUTTON, CLASSIC_BUTTON_A, 1.0f)); + AddBind(touchScreenKey, new sBind(a, CLASSIC_BUTTON_B, BIND_BUTTON, CLASSIC_BUTTON_B, 1.0f)); + AddBind(touchScreenKey, new sBind(a, CLASSIC_BUTTON_X, BIND_BUTTON, CLASSIC_BUTTON_X, 1.0f)); + AddBind(touchScreenKey, new sBind(a, CLASSIC_BUTTON_Y, BIND_BUTTON, CLASSIC_BUTTON_Y, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, CLASSIC_BUTTON_MINUS, BIND_BUTTON, CLASSIC_BUTTON_MINUS, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, CLASSIC_BUTTON_PLUS, BIND_BUTTON, CLASSIC_BUTTON_PLUS, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, CLASSIC_BUTTON_HOME, BIND_BUTTON, CLASSIC_BUTTON_HOME, 1.0f)); + AddBind(touchScreenKey, new sBind(a, CLASSIC_BUTTON_ZL, BIND_BUTTON, CLASSIC_BUTTON_ZL, 1.0f)); + AddBind(touchScreenKey, new sBind(a, CLASSIC_BUTTON_ZR, BIND_BUTTON, CLASSIC_BUTTON_ZR, 1.0f)); + AddBind(touchScreenKey, new sBind(a, CLASSIC_DPAD_UP, BIND_BUTTON, CLASSIC_DPAD_UP, 1.0f)); + AddBind(touchScreenKey, new sBind(a, CLASSIC_DPAD_DOWN, BIND_BUTTON, CLASSIC_DPAD_DOWN, 1.0f)); + AddBind(touchScreenKey, new sBind(a, CLASSIC_DPAD_LEFT, BIND_BUTTON, CLASSIC_DPAD_LEFT, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, CLASSIC_DPAD_RIGHT, BIND_BUTTON, CLASSIC_DPAD_RIGHT, 1.0f)); + + AddBind(touchScreenKey, + new sBind(a, CLASSIC_STICK_LEFT_UP, BIND_AXIS, CLASSIC_STICK_LEFT_UP, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, CLASSIC_STICK_LEFT_DOWN, BIND_AXIS, CLASSIC_STICK_LEFT_DOWN, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, CLASSIC_STICK_LEFT_LEFT, BIND_AXIS, CLASSIC_STICK_LEFT_LEFT, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, CLASSIC_STICK_LEFT_RIGHT, BIND_AXIS, CLASSIC_STICK_LEFT_RIGHT, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, CLASSIC_STICK_RIGHT_UP, BIND_AXIS, CLASSIC_STICK_RIGHT_UP, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, CLASSIC_STICK_RIGHT_DOWN, BIND_AXIS, CLASSIC_STICK_RIGHT_DOWN, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, CLASSIC_STICK_RIGHT_LEFT, BIND_AXIS, CLASSIC_STICK_RIGHT_LEFT, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, CLASSIC_STICK_RIGHT_RIGHT, BIND_AXIS, CLASSIC_STICK_RIGHT_RIGHT, 1.0f)); + AddBind(touchScreenKey, new sBind(a, CLASSIC_TRIGGER_L, BIND_AXIS, CLASSIC_TRIGGER_L, 1.0f)); + AddBind(touchScreenKey, new sBind(a, CLASSIC_TRIGGER_R, BIND_AXIS, CLASSIC_TRIGGER_R, 1.0f)); + + // Wii: Guitar + AddBind(touchScreenKey, + new sBind(a, GUITAR_BUTTON_MINUS, BIND_BUTTON, GUITAR_BUTTON_MINUS, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, GUITAR_BUTTON_PLUS, BIND_BUTTON, GUITAR_BUTTON_PLUS, 1.0f)); + AddBind(touchScreenKey, new sBind(a, GUITAR_FRET_GREEN, BIND_BUTTON, GUITAR_FRET_GREEN, 1.0f)); + AddBind(touchScreenKey, new sBind(a, GUITAR_FRET_RED, BIND_BUTTON, GUITAR_FRET_RED, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, GUITAR_FRET_YELLOW, BIND_BUTTON, GUITAR_FRET_YELLOW, 1.0f)); + AddBind(touchScreenKey, new sBind(a, GUITAR_FRET_BLUE, BIND_BUTTON, GUITAR_FRET_BLUE, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, GUITAR_FRET_ORANGE, BIND_BUTTON, GUITAR_FRET_ORANGE, 1.0f)); + AddBind(touchScreenKey, new sBind(a, GUITAR_STRUM_UP, BIND_BUTTON, GUITAR_STRUM_UP, 1.0f)); + AddBind(touchScreenKey, new sBind(a, GUITAR_STRUM_DOWN, BIND_BUTTON, GUITAR_STRUM_DOWN, 1.0f)); + + AddBind(touchScreenKey, new sBind(a, GUITAR_STICK_UP, BIND_AXIS, GUITAR_STICK_UP, -1.0f)); + AddBind(touchScreenKey, new sBind(a, GUITAR_STICK_DOWN, BIND_AXIS, GUITAR_STICK_DOWN, 1.0f)); + AddBind(touchScreenKey, new sBind(a, GUITAR_STICK_LEFT, BIND_AXIS, GUITAR_STICK_LEFT, -1.0f)); + AddBind(touchScreenKey, new sBind(a, GUITAR_STICK_RIGHT, BIND_AXIS, GUITAR_STICK_RIGHT, 1.0f)); + AddBind(touchScreenKey, new sBind(a, GUITAR_WHAMMY_BAR, BIND_AXIS, GUITAR_WHAMMY_BAR, 1.0f)); + + // Wii: Drums + AddBind(touchScreenKey, + new sBind(a, DRUMS_BUTTON_MINUS, BIND_BUTTON, DRUMS_BUTTON_MINUS, 1.0f)); + AddBind(touchScreenKey, new sBind(a, DRUMS_BUTTON_PLUS, BIND_BUTTON, DRUMS_BUTTON_PLUS, 1.0f)); + AddBind(touchScreenKey, new sBind(a, DRUMS_PAD_RED, BIND_BUTTON, DRUMS_PAD_RED, 1.0f)); + AddBind(touchScreenKey, new sBind(a, DRUMS_PAD_YELLOW, BIND_BUTTON, DRUMS_PAD_YELLOW, 1.0f)); + AddBind(touchScreenKey, new sBind(a, DRUMS_PAD_BLUE, BIND_BUTTON, DRUMS_PAD_BLUE, 1.0f)); + AddBind(touchScreenKey, new sBind(a, DRUMS_PAD_GREEN, BIND_BUTTON, DRUMS_PAD_GREEN, 1.0f)); + AddBind(touchScreenKey, new sBind(a, DRUMS_PAD_ORANGE, BIND_BUTTON, DRUMS_PAD_ORANGE, 1.0f)); + AddBind(touchScreenKey, new sBind(a, DRUMS_PAD_BASS, BIND_BUTTON, DRUMS_PAD_BASS, 1.0f)); + + AddBind(touchScreenKey, new sBind(a, DRUMS_STICK_UP, BIND_AXIS, DRUMS_STICK_UP, -1.0f)); + AddBind(touchScreenKey, new sBind(a, DRUMS_STICK_DOWN, BIND_AXIS, DRUMS_STICK_DOWN, 1.0f)); + AddBind(touchScreenKey, new sBind(a, DRUMS_STICK_LEFT, BIND_AXIS, DRUMS_STICK_LEFT, -1.0f)); + AddBind(touchScreenKey, new sBind(a, DRUMS_STICK_RIGHT, BIND_AXIS, DRUMS_STICK_RIGHT, 1.0f)); + + // Wii: Turntable + AddBind(touchScreenKey, new sBind(a, TURNTABLE_BUTTON_GREEN_LEFT, BIND_BUTTON, + TURNTABLE_BUTTON_GREEN_LEFT, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, TURNTABLE_BUTTON_RED_LEFT, BIND_BUTTON, TURNTABLE_BUTTON_RED_LEFT, 1.0f)); + AddBind(touchScreenKey, new sBind(a, TURNTABLE_BUTTON_BLUE_LEFT, BIND_BUTTON, + TURNTABLE_BUTTON_BLUE_LEFT, 1.0f)); + AddBind(touchScreenKey, new sBind(a, TURNTABLE_BUTTON_GREEN_RIGHT, BIND_BUTTON, + TURNTABLE_BUTTON_GREEN_RIGHT, 1.0f)); + AddBind(touchScreenKey, new sBind(a, TURNTABLE_BUTTON_RED_RIGHT, BIND_BUTTON, + TURNTABLE_BUTTON_RED_RIGHT, 1.0f)); + AddBind(touchScreenKey, new sBind(a, TURNTABLE_BUTTON_BLUE_RIGHT, BIND_BUTTON, + TURNTABLE_BUTTON_BLUE_RIGHT, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, TURNTABLE_BUTTON_MINUS, BIND_BUTTON, TURNTABLE_BUTTON_MINUS, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, TURNTABLE_BUTTON_PLUS, BIND_BUTTON, TURNTABLE_BUTTON_PLUS, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, TURNTABLE_BUTTON_HOME, BIND_BUTTON, TURNTABLE_BUTTON_HOME, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, TURNTABLE_BUTTON_EUPHORIA, BIND_BUTTON, TURNTABLE_BUTTON_EUPHORIA, 1.0f)); + + AddBind(touchScreenKey, + new sBind(a, TURNTABLE_TABLE_LEFT_LEFT, BIND_AXIS, TURNTABLE_TABLE_LEFT_LEFT, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, TURNTABLE_TABLE_LEFT_RIGHT, BIND_AXIS, TURNTABLE_TABLE_LEFT_RIGHT, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, TURNTABLE_TABLE_RIGHT_LEFT, BIND_AXIS, TURNTABLE_TABLE_RIGHT_LEFT, -1.0f)); + AddBind(touchScreenKey, new sBind(a, TURNTABLE_TABLE_RIGHT_RIGHT, BIND_AXIS, + TURNTABLE_TABLE_RIGHT_RIGHT, 1.0f)); + AddBind(touchScreenKey, new sBind(a, TURNTABLE_STICK_UP, BIND_AXIS, TURNTABLE_STICK_UP, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, TURNTABLE_STICK_DOWN, BIND_AXIS, TURNTABLE_STICK_DOWN, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, TURNTABLE_STICK_LEFT, BIND_AXIS, TURNTABLE_STICK_LEFT, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, TURNTABLE_STICK_RIGHT, BIND_AXIS, TURNTABLE_STICK_RIGHT, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, TURNTABLE_EFFECT_DIAL, BIND_AXIS, TURNTABLE_EFFECT_DIAL, 1.0f)); + AddBind(touchScreenKey, + new sBind(a, TURNTABLE_CROSSFADE_LEFT, BIND_AXIS, TURNTABLE_CROSSFADE_LEFT, -1.0f)); + AddBind(touchScreenKey, + new sBind(a, TURNTABLE_CROSSFADE_RIGHT, BIND_AXIS, TURNTABLE_CROSSFADE_RIGHT, 1.0f)); + } + // Init our controller bindings + IniFile ini; + ini.Load(File::GetUserPath(D_CONFIG_IDX) + std::string("Dolphin.ini")); + for (u32 a = 0; a < configStrings.size(); ++a) + { + for (int padID = 0; padID < 8; ++padID) + { + std::ostringstream config; + config << configStrings[a] << "_" << padID; + BindType type; + int bindnum; + char dev[128]; + bool hasbind = false; + char modifier = '+'; + std::string value; + ini.GetOrCreateSection("Android")->Get(config.str(), &value, "None"); + if (value == "None") + continue; + if (std::string::npos != value.find("Axis")) + { + hasbind = true; + type = BIND_AXIS; + sscanf(value.c_str(), "Device '%127[^\']'-Axis %d%c", dev, &bindnum, &modifier); + } + else if (std::string::npos != value.find("Button")) + { + hasbind = true; + type = BIND_BUTTON; + sscanf(value.c_str(), "Device '%127[^\']'-Button %d", dev, &bindnum); + } + if (hasbind) + AddBind(std::string(dev), + new sBind(padID, configTypes[a], type, bindnum, modifier == '-' ? -1.0f : 1.0f)); + } + } +} +bool GetButtonPressed(int padID, ButtonType button) +{ + bool pressed = m_controllers[touchScreenKey]->ButtonValue(padID, button); + + for (const auto& ctrl : m_controllers) + pressed |= ctrl.second->ButtonValue(padID, button); + + return pressed; +} +float GetAxisValue(int padID, ButtonType axis) +{ + float value = m_controllers[touchScreenKey]->AxisValue(padID, axis); + if (value == 0.0f) + { + for (const auto& ctrl : m_controllers) + { + value = ctrl.second->AxisValue(padID, axis); + if (value != 0.0f) + return value; + } + } + return value; +} +bool GamepadEvent(const std::string& dev, int button, int action) +{ + auto it = m_controllers.find(dev); + if (it != m_controllers.end()) + return it->second->PressEvent(button, action); + return false; +} +void GamepadAxisEvent(const std::string& dev, int axis, float value) +{ + auto it = m_controllers.find(dev); + if (it != m_controllers.end()) + it->second->AxisEvent(axis, value); +} +void Shutdown() +{ + for (const auto& controller : m_controllers) + delete controller.second; + m_controllers.clear(); +} + +// InputDevice +bool InputDevice::PressEvent(int button, int action) +{ + bool handled = false; + for (const auto& binding : _inputbinds) + { + if (binding.second->_bind == button) + { + if (binding.second->_bindtype == BIND_BUTTON) + _buttons[binding.second->_buttontype] = action == BUTTON_PRESSED ? true : false; + else + _axises[binding.second->_buttontype] = action == BUTTON_PRESSED ? 1.0f : 0.0f; + handled = true; + } + } + return handled; +} +void InputDevice::AxisEvent(int axis, float value) +{ + for (const auto& binding : _inputbinds) + { + if (binding.second->_bind == axis) + { + if (binding.second->_bindtype == BIND_AXIS) + _axises[binding.second->_buttontype] = value; + else + _buttons[binding.second->_buttontype] = value > 0.5f ? true : false; + } + } +} +bool InputDevice::ButtonValue(int padID, ButtonType button) +{ + const auto& binding = _inputbinds.find(std::make_pair(padID, button)); + if (binding == _inputbinds.end()) + return false; + + if (binding->second->_bindtype == BIND_BUTTON) + return _buttons[binding->second->_buttontype]; + else + return (_axises[binding->second->_buttontype] * binding->second->_neg) > 0.5f; +} +float InputDevice::AxisValue(int padID, ButtonType axis) +{ + const auto& binding = _inputbinds.find(std::make_pair(padID, axis)); + if (binding == _inputbinds.end()) + return 0.0f; + + if (binding->second->_bindtype == BIND_AXIS) + return _axises[binding->second->_buttontype] * binding->second->_neg; + else + return _buttons[binding->second->_buttontype] == BUTTON_PRESSED ? 1.0f : 0.0f; +} } diff --git a/Source/Android/jni/ButtonManager.h b/Source/Android/jni/ButtonManager.h index 575ef1c4dd..c65d8180f0 100644 --- a/Source/Android/jni/ButtonManager.h +++ b/Source/Android/jni/ButtonManager.h @@ -9,249 +9,249 @@ namespace ButtonManager { - enum ButtonType - { - // GC - BUTTON_A = 0, - BUTTON_B = 1, - BUTTON_START = 2, - BUTTON_X = 3, - BUTTON_Y = 4, - BUTTON_Z = 5, - BUTTON_UP = 6, - BUTTON_DOWN = 7, - BUTTON_LEFT = 8, - BUTTON_RIGHT = 9, - STICK_MAIN = 10, // Used on Java Side - STICK_MAIN_UP = 11, - STICK_MAIN_DOWN = 12, - STICK_MAIN_LEFT = 13, - STICK_MAIN_RIGHT = 14, - STICK_C = 15, // Used on Java Side - STICK_C_UP = 16, - STICK_C_DOWN = 17, - STICK_C_LEFT = 18, - STICK_C_RIGHT = 19, - TRIGGER_L = 20, - TRIGGER_R = 21, - // Wiimote - WIIMOTE_BUTTON_A = 100, - WIIMOTE_BUTTON_B = 101, - WIIMOTE_BUTTON_MINUS = 102, - WIIMOTE_BUTTON_PLUS = 103, - WIIMOTE_BUTTON_HOME = 104, - WIIMOTE_BUTTON_1 = 105, - WIIMOTE_BUTTON_2 = 106, - WIIMOTE_UP = 107, - WIIMOTE_DOWN = 108, - WIIMOTE_LEFT = 109, - WIIMOTE_RIGHT = 110, - WIIMOTE_IR = 111, // To Be Used on Java Side - WIIMOTE_IR_UP = 112, - WIIMOTE_IR_DOWN = 113, - WIIMOTE_IR_LEFT = 114, - WIIMOTE_IR_RIGHT = 115, - WIIMOTE_IR_FORWARD = 116, - WIIMOTE_IR_BACKWARD = 117, - WIIMOTE_IR_HIDE = 118, - WIIMOTE_SWING = 119, // To Be Used on Java Side - WIIMOTE_SWING_UP = 120, - WIIMOTE_SWING_DOWN = 121, - WIIMOTE_SWING_LEFT = 122, - WIIMOTE_SWING_RIGHT = 123, - WIIMOTE_SWING_FORWARD = 124, - WIIMOTE_SWING_BACKWARD = 125, - WIIMOTE_TILT = 126, // To Be Used on Java Side - WIIMOTE_TILT_FORWARD = 127, - WIIMOTE_TILT_BACKWARD = 128, - WIIMOTE_TILT_LEFT = 129, - WIIMOTE_TILT_RIGHT = 130, - WIIMOTE_TILT_MODIFIER = 131, - WIIMOTE_SHAKE_X = 132, - WIIMOTE_SHAKE_Y = 133, - WIIMOTE_SHAKE_Z = 134, - //Nunchuk - NUNCHUK_BUTTON_C = 200, - NUNCHUK_BUTTON_Z = 201, - NUNCHUK_STICK = 202, // To Be Used on Java Side - NUNCHUK_STICK_UP = 203, - NUNCHUK_STICK_DOWN = 204, - NUNCHUK_STICK_LEFT = 205, - NUNCHUK_STICK_RIGHT = 206, - NUNCHUK_SWING = 207, // To Be Used on Java Side - NUNCHUK_SWING_UP = 208, - NUNCHUK_SWING_DOWN = 209, - NUNCHUK_SWING_LEFT = 210, - NUNCHUK_SWING_RIGHT = 211, - NUNCHUK_SWING_FORWARD = 212, - NUNCHUK_SWING_BACKWARD = 213, - NUNCHUK_TILT = 214, // To Be Used on Java Side - NUNCHUK_TILT_FORWARD = 215, - NUNCHUK_TILT_BACKWARD = 216, - NUNCHUK_TILT_LEFT = 217, - NUNCHUK_TILT_RIGHT = 218, - NUNCHUK_TILT_MODIFIER = 219, - NUNCHUK_SHAKE_X = 220, - NUNCHUK_SHAKE_Y = 221, - NUNCHUK_SHAKE_Z = 222, - //Classic - CLASSIC_BUTTON_A = 300, - CLASSIC_BUTTON_B = 301, - CLASSIC_BUTTON_X = 302, - CLASSIC_BUTTON_Y = 303, - CLASSIC_BUTTON_MINUS = 304, - CLASSIC_BUTTON_PLUS = 305, - CLASSIC_BUTTON_HOME = 306, - CLASSIC_BUTTON_ZL = 307, - CLASSIC_BUTTON_ZR = 308, - CLASSIC_DPAD_UP = 309, - CLASSIC_DPAD_DOWN = 310, - CLASSIC_DPAD_LEFT = 311, - CLASSIC_DPAD_RIGHT = 312, - CLASSIC_STICK_LEFT = 313, // To Be Used on Java Side - CLASSIC_STICK_LEFT_UP = 314, - CLASSIC_STICK_LEFT_DOWN = 315, - CLASSIC_STICK_LEFT_LEFT = 316, - CLASSIC_STICK_LEFT_RIGHT = 317, - CLASSIC_STICK_RIGHT = 318, // To Be Used on Java Side - CLASSIC_STICK_RIGHT_UP = 319, - CLASSIC_STICK_RIGHT_DOWN = 320, - CLASSIC_STICK_RIGHT_LEFT = 321, - CLASSIC_STICK_RIGHT_RIGHT = 322, - CLASSIC_TRIGGER_L = 323, - CLASSIC_TRIGGER_R = 324, - //Guitar - GUITAR_BUTTON_MINUS = 400, - GUITAR_BUTTON_PLUS = 401, - GUITAR_FRET_GREEN = 402, - GUITAR_FRET_RED = 403, - GUITAR_FRET_YELLOW = 404, - GUITAR_FRET_BLUE = 405, - GUITAR_FRET_ORANGE = 406, - GUITAR_STRUM_UP = 407, - GUITAR_STRUM_DOWN = 408, - GUITAR_STICK = 409, // To Be Used on Java Side - GUITAR_STICK_UP = 410, - GUITAR_STICK_DOWN = 411, - GUITAR_STICK_LEFT = 412, - GUITAR_STICK_RIGHT = 413, - GUITAR_WHAMMY_BAR = 414, - //Drums - DRUMS_BUTTON_MINUS = 500, - DRUMS_BUTTON_PLUS = 501, - DRUMS_PAD_RED = 502, - DRUMS_PAD_YELLOW = 503, - DRUMS_PAD_BLUE = 504, - DRUMS_PAD_GREEN = 505, - DRUMS_PAD_ORANGE = 506, - DRUMS_PAD_BASS = 507, - DRUMS_STICK = 508, // To Be Used on Java Side - DRUMS_STICK_UP = 509, - DRUMS_STICK_DOWN = 510, - DRUMS_STICK_LEFT = 511, - DRUMS_STICK_RIGHT = 512, - //Turntable - TURNTABLE_BUTTON_GREEN_LEFT = 600, - TURNTABLE_BUTTON_RED_LEFT = 601, - TURNTABLE_BUTTON_BLUE_LEFT = 602, - TURNTABLE_BUTTON_GREEN_RIGHT = 603, - TURNTABLE_BUTTON_RED_RIGHT = 604, - TURNTABLE_BUTTON_BLUE_RIGHT = 605, - TURNTABLE_BUTTON_MINUS = 606, - TURNTABLE_BUTTON_PLUS = 607, - TURNTABLE_BUTTON_HOME = 608, - TURNTABLE_BUTTON_EUPHORIA = 609, - TURNTABLE_TABLE_LEFT = 610, // To Be Used on Java Side - TURNTABLE_TABLE_LEFT_LEFT = 611, - TURNTABLE_TABLE_LEFT_RIGHT = 612, - TURNTABLE_TABLE_RIGHT = 613, // To Be Used on Java Side - TURNTABLE_TABLE_RIGHT_LEFT = 614, - TURNTABLE_TABLE_RIGHT_RIGHT = 615, - TURNTABLE_STICK = 616, // To Be Used on Java Side - TURNTABLE_STICK_UP = 617, - TURNTABLE_STICK_DOWN = 618, - TURNTABLE_STICK_LEFT = 619, - TURNTABLE_STICK_RIGHT = 620, - TURNTABLE_EFFECT_DIAL = 621, - TURNTABLE_CROSSFADE = 622, // To Be Used on Java Side - TURNTABLE_CROSSFADE_LEFT = 623, - TURNTABLE_CROSSFADE_RIGHT = 624, - }; - enum ButtonState - { - BUTTON_RELEASED = 0, - BUTTON_PRESSED = 1 - }; - enum BindType - { - BIND_BUTTON = 0, - BIND_AXIS - }; - class Button - { - private: - ButtonState m_state; - public: - Button() : m_state(BUTTON_RELEASED) {} - void SetState(ButtonState state) { m_state = state; } - bool Pressed() { return m_state == BUTTON_PRESSED; } +enum ButtonType +{ + // GC + BUTTON_A = 0, + BUTTON_B = 1, + BUTTON_START = 2, + BUTTON_X = 3, + BUTTON_Y = 4, + BUTTON_Z = 5, + BUTTON_UP = 6, + BUTTON_DOWN = 7, + BUTTON_LEFT = 8, + BUTTON_RIGHT = 9, + STICK_MAIN = 10, // Used on Java Side + STICK_MAIN_UP = 11, + STICK_MAIN_DOWN = 12, + STICK_MAIN_LEFT = 13, + STICK_MAIN_RIGHT = 14, + STICK_C = 15, // Used on Java Side + STICK_C_UP = 16, + STICK_C_DOWN = 17, + STICK_C_LEFT = 18, + STICK_C_RIGHT = 19, + TRIGGER_L = 20, + TRIGGER_R = 21, + // Wiimote + WIIMOTE_BUTTON_A = 100, + WIIMOTE_BUTTON_B = 101, + WIIMOTE_BUTTON_MINUS = 102, + WIIMOTE_BUTTON_PLUS = 103, + WIIMOTE_BUTTON_HOME = 104, + WIIMOTE_BUTTON_1 = 105, + WIIMOTE_BUTTON_2 = 106, + WIIMOTE_UP = 107, + WIIMOTE_DOWN = 108, + WIIMOTE_LEFT = 109, + WIIMOTE_RIGHT = 110, + WIIMOTE_IR = 111, // To Be Used on Java Side + WIIMOTE_IR_UP = 112, + WIIMOTE_IR_DOWN = 113, + WIIMOTE_IR_LEFT = 114, + WIIMOTE_IR_RIGHT = 115, + WIIMOTE_IR_FORWARD = 116, + WIIMOTE_IR_BACKWARD = 117, + WIIMOTE_IR_HIDE = 118, + WIIMOTE_SWING = 119, // To Be Used on Java Side + WIIMOTE_SWING_UP = 120, + WIIMOTE_SWING_DOWN = 121, + WIIMOTE_SWING_LEFT = 122, + WIIMOTE_SWING_RIGHT = 123, + WIIMOTE_SWING_FORWARD = 124, + WIIMOTE_SWING_BACKWARD = 125, + WIIMOTE_TILT = 126, // To Be Used on Java Side + WIIMOTE_TILT_FORWARD = 127, + WIIMOTE_TILT_BACKWARD = 128, + WIIMOTE_TILT_LEFT = 129, + WIIMOTE_TILT_RIGHT = 130, + WIIMOTE_TILT_MODIFIER = 131, + WIIMOTE_SHAKE_X = 132, + WIIMOTE_SHAKE_Y = 133, + WIIMOTE_SHAKE_Z = 134, + // Nunchuk + NUNCHUK_BUTTON_C = 200, + NUNCHUK_BUTTON_Z = 201, + NUNCHUK_STICK = 202, // To Be Used on Java Side + NUNCHUK_STICK_UP = 203, + NUNCHUK_STICK_DOWN = 204, + NUNCHUK_STICK_LEFT = 205, + NUNCHUK_STICK_RIGHT = 206, + NUNCHUK_SWING = 207, // To Be Used on Java Side + NUNCHUK_SWING_UP = 208, + NUNCHUK_SWING_DOWN = 209, + NUNCHUK_SWING_LEFT = 210, + NUNCHUK_SWING_RIGHT = 211, + NUNCHUK_SWING_FORWARD = 212, + NUNCHUK_SWING_BACKWARD = 213, + NUNCHUK_TILT = 214, // To Be Used on Java Side + NUNCHUK_TILT_FORWARD = 215, + NUNCHUK_TILT_BACKWARD = 216, + NUNCHUK_TILT_LEFT = 217, + NUNCHUK_TILT_RIGHT = 218, + NUNCHUK_TILT_MODIFIER = 219, + NUNCHUK_SHAKE_X = 220, + NUNCHUK_SHAKE_Y = 221, + NUNCHUK_SHAKE_Z = 222, + // Classic + CLASSIC_BUTTON_A = 300, + CLASSIC_BUTTON_B = 301, + CLASSIC_BUTTON_X = 302, + CLASSIC_BUTTON_Y = 303, + CLASSIC_BUTTON_MINUS = 304, + CLASSIC_BUTTON_PLUS = 305, + CLASSIC_BUTTON_HOME = 306, + CLASSIC_BUTTON_ZL = 307, + CLASSIC_BUTTON_ZR = 308, + CLASSIC_DPAD_UP = 309, + CLASSIC_DPAD_DOWN = 310, + CLASSIC_DPAD_LEFT = 311, + CLASSIC_DPAD_RIGHT = 312, + CLASSIC_STICK_LEFT = 313, // To Be Used on Java Side + CLASSIC_STICK_LEFT_UP = 314, + CLASSIC_STICK_LEFT_DOWN = 315, + CLASSIC_STICK_LEFT_LEFT = 316, + CLASSIC_STICK_LEFT_RIGHT = 317, + CLASSIC_STICK_RIGHT = 318, // To Be Used on Java Side + CLASSIC_STICK_RIGHT_UP = 319, + CLASSIC_STICK_RIGHT_DOWN = 320, + CLASSIC_STICK_RIGHT_LEFT = 321, + CLASSIC_STICK_RIGHT_RIGHT = 322, + CLASSIC_TRIGGER_L = 323, + CLASSIC_TRIGGER_R = 324, + // Guitar + GUITAR_BUTTON_MINUS = 400, + GUITAR_BUTTON_PLUS = 401, + GUITAR_FRET_GREEN = 402, + GUITAR_FRET_RED = 403, + GUITAR_FRET_YELLOW = 404, + GUITAR_FRET_BLUE = 405, + GUITAR_FRET_ORANGE = 406, + GUITAR_STRUM_UP = 407, + GUITAR_STRUM_DOWN = 408, + GUITAR_STICK = 409, // To Be Used on Java Side + GUITAR_STICK_UP = 410, + GUITAR_STICK_DOWN = 411, + GUITAR_STICK_LEFT = 412, + GUITAR_STICK_RIGHT = 413, + GUITAR_WHAMMY_BAR = 414, + // Drums + DRUMS_BUTTON_MINUS = 500, + DRUMS_BUTTON_PLUS = 501, + DRUMS_PAD_RED = 502, + DRUMS_PAD_YELLOW = 503, + DRUMS_PAD_BLUE = 504, + DRUMS_PAD_GREEN = 505, + DRUMS_PAD_ORANGE = 506, + DRUMS_PAD_BASS = 507, + DRUMS_STICK = 508, // To Be Used on Java Side + DRUMS_STICK_UP = 509, + DRUMS_STICK_DOWN = 510, + DRUMS_STICK_LEFT = 511, + DRUMS_STICK_RIGHT = 512, + // Turntable + TURNTABLE_BUTTON_GREEN_LEFT = 600, + TURNTABLE_BUTTON_RED_LEFT = 601, + TURNTABLE_BUTTON_BLUE_LEFT = 602, + TURNTABLE_BUTTON_GREEN_RIGHT = 603, + TURNTABLE_BUTTON_RED_RIGHT = 604, + TURNTABLE_BUTTON_BLUE_RIGHT = 605, + TURNTABLE_BUTTON_MINUS = 606, + TURNTABLE_BUTTON_PLUS = 607, + TURNTABLE_BUTTON_HOME = 608, + TURNTABLE_BUTTON_EUPHORIA = 609, + TURNTABLE_TABLE_LEFT = 610, // To Be Used on Java Side + TURNTABLE_TABLE_LEFT_LEFT = 611, + TURNTABLE_TABLE_LEFT_RIGHT = 612, + TURNTABLE_TABLE_RIGHT = 613, // To Be Used on Java Side + TURNTABLE_TABLE_RIGHT_LEFT = 614, + TURNTABLE_TABLE_RIGHT_RIGHT = 615, + TURNTABLE_STICK = 616, // To Be Used on Java Side + TURNTABLE_STICK_UP = 617, + TURNTABLE_STICK_DOWN = 618, + TURNTABLE_STICK_LEFT = 619, + TURNTABLE_STICK_RIGHT = 620, + TURNTABLE_EFFECT_DIAL = 621, + TURNTABLE_CROSSFADE = 622, // To Be Used on Java Side + TURNTABLE_CROSSFADE_LEFT = 623, + TURNTABLE_CROSSFADE_RIGHT = 624, +}; +enum ButtonState +{ + BUTTON_RELEASED = 0, + BUTTON_PRESSED = 1 +}; +enum BindType +{ + BIND_BUTTON = 0, + BIND_AXIS +}; +class Button +{ +private: + ButtonState m_state; - ~Button() {} - }; - class Axis - { - private: - float m_value; - public: - Axis() : m_value(0.0f) {} - void SetValue(float value) { m_value = value; } - float AxisValue() { return m_value; } +public: + Button() : m_state(BUTTON_RELEASED) {} + void SetState(ButtonState state) { m_state = state; } + bool Pressed() { return m_state == BUTTON_PRESSED; } + ~Button() {} +}; +class Axis +{ +private: + float m_value; - ~Axis() {} - }; +public: + Axis() : m_value(0.0f) {} + void SetValue(float value) { m_value = value; } + float AxisValue() { return m_value; } + ~Axis() {} +}; - struct sBind - { - const int _padID; - const ButtonType _buttontype; - const BindType _bindtype; - const int _bind; - const float _neg; - sBind(int padID, ButtonType buttontype, BindType bindtype, int bind, float neg) - : _padID(padID), _buttontype(buttontype), _bindtype(bindtype), _bind(bind), _neg(neg) - {} - }; +struct sBind +{ + const int _padID; + const ButtonType _buttontype; + const BindType _bindtype; + const int _bind; + const float _neg; + sBind(int padID, ButtonType buttontype, BindType bindtype, int bind, float neg) + : _padID(padID), _buttontype(buttontype), _bindtype(bindtype), _bind(bind), _neg(neg) + { + } +}; +class InputDevice +{ +private: + const std::string _dev; + std::map _buttons; + std::map _axises; - class InputDevice - { - private: - const std::string _dev; - std::map _buttons; - std::map _axises; + // Key is padID and ButtonType + std::map, sBind*> _inputbinds; - // Key is padID and ButtonType - std::map, sBind*> _inputbinds; - public: - InputDevice(std::string dev) - : _dev(dev) {} - ~InputDevice() - { - for (const auto& bind : _inputbinds) - delete bind.second; - _inputbinds.clear(); - } - void AddBind(sBind* bind) { _inputbinds[std::make_pair(bind->_padID, bind->_buttontype)] = bind; } - bool PressEvent(int button, int action); - void AxisEvent(int axis, float value); - bool ButtonValue(int padID, ButtonType button); - float AxisValue(int padID, ButtonType axis); - }; +public: + InputDevice(std::string dev) : _dev(dev) {} + ~InputDevice() + { + for (const auto& bind : _inputbinds) + delete bind.second; + _inputbinds.clear(); + } + void AddBind(sBind* bind) { _inputbinds[std::make_pair(bind->_padID, bind->_buttontype)] = bind; } + bool PressEvent(int button, int action); + void AxisEvent(int axis, float value); + bool ButtonValue(int padID, ButtonType button); + float AxisValue(int padID, ButtonType axis); +}; - void Init(); - bool GetButtonPressed(int padID, ButtonType button); - float GetAxisValue(int padID, ButtonType axis); - bool GamepadEvent(const std::string& dev, int button, int action); - void GamepadAxisEvent(const std::string& dev, int axis, float value); - void Shutdown(); +void Init(); +bool GetButtonPressed(int padID, ButtonType button); +float GetAxisValue(int padID, ButtonType axis); +bool GamepadEvent(const std::string& dev, int button, int action); +void GamepadAxisEvent(const std::string& dev, int axis, float value); +void Shutdown(); } diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index 6b30bc5409..796a2b5409 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -2,6 +2,9 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include +#include +#include #include #include #include @@ -9,15 +12,12 @@ #include #include #include -#include -#include -#include #include "ButtonManager.h" +#include "Common/CPUDetect.h" #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" -#include "Common/CPUDetect.h" #include "Common/Event.h" #include "Common/FileUtil.h" #include "Common/GL/GLInterfaceBase.h" @@ -26,12 +26,12 @@ #include "Core/BootManager.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/Host.h" -#include "Core/State.h" #include "Core/HW/Wiimote.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" +#include "Core/Host.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/Profiler.h" +#include "Core/State.h" #include "DiscIO/Volume.h" #include "DiscIO/VolumeCreator.h" @@ -58,13 +58,17 @@ jmethodID g_jni_method_end; */ jint JNI_OnLoad(JavaVM* vm, void* reserved) { - g_java_vm = vm; + g_java_vm = vm; - return JNI_VERSION_1_6; + return JNI_VERSION_1_6; } -void Host_NotifyMapLoaded() {} -void Host_RefreshDSPDebuggerWindow() {} +void Host_NotifyMapLoaded() +{ +} +void Host_RefreshDSPDebuggerWindow() +{ +} // The Core only supports using a single Host thread. // If multiple threads want to call host functions then they need to queue @@ -74,37 +78,43 @@ Common::Event updateMainFrameEvent; static bool s_have_wm_user_stop = false; void Host_Message(int Id) { - if (Id == WM_USER_JOB_DISPATCH) - { - updateMainFrameEvent.Set(); - } - else if (Id == WM_USER_STOP) - { - s_have_wm_user_stop = true; - if (Core::IsRunning()) - Core::QueueHostJob(&Core::Stop); - } + if (Id == WM_USER_JOB_DISPATCH) + { + updateMainFrameEvent.Set(); + } + else if (Id == WM_USER_STOP) + { + s_have_wm_user_stop = true; + if (Core::IsRunning()) + Core::QueueHostJob(&Core::Stop); + } } void* Host_GetRenderHandle() { - return surf; + return surf; } void Host_UpdateTitle(const std::string& title) { - __android_log_write(ANDROID_LOG_INFO, DOLPHIN_TAG, title.c_str()); + __android_log_write(ANDROID_LOG_INFO, DOLPHIN_TAG, title.c_str()); } -void Host_UpdateDisasmDialog(){} +void Host_UpdateDisasmDialog() +{ +} void Host_UpdateMainFrame() { } -void Host_RequestRenderWindowSize(int width, int height) {} +void Host_RequestRenderWindowSize(int width, int height) +{ +} -void Host_RequestFullscreen(bool enable_fullscreen) {} +void Host_RequestFullscreen(bool enable_fullscreen) +{ +} void Host_SetStartupDebuggingParameters() { @@ -112,614 +122,716 @@ void Host_SetStartupDebuggingParameters() bool Host_UIHasFocus() { - return true; + return true; } bool Host_RendererHasFocus() { - return true; + return true; } bool Host_RendererIsFullscreen() { - return false; + return false; } -void Host_ConnectWiimote(int wm_idx, bool connect) {} +void Host_ConnectWiimote(int wm_idx, bool connect) +{ +} -void Host_SetWiiMoteConnectionState(int _State) {} +void Host_SetWiiMoteConnectionState(int _State) +{ +} -void Host_ShowVideoConfig(void*, const std::string&, const std::string&) {} +void Host_ShowVideoConfig(void*, const std::string&, const std::string&) +{ +} static bool MsgAlert(const char* caption, const char* text, bool yes_no, int /*Style*/) { - __android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "%s:%s", caption, text); + __android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "%s:%s", caption, text); - // Associate the current Thread with the Java VM. - JNIEnv* env; - g_java_vm->AttachCurrentThread(&env, NULL); + // Associate the current Thread with the Java VM. + JNIEnv* env; + g_java_vm->AttachCurrentThread(&env, NULL); - // Execute the Java method. - env->CallStaticVoidMethod(g_jni_class, g_jni_method_alert, env->NewStringUTF(text)); + // Execute the Java method. + env->CallStaticVoidMethod(g_jni_class, g_jni_method_alert, env->NewStringUTF(text)); - // Must be called before the current thread exits; might as well do it here. - g_java_vm->DetachCurrentThread(); + // Must be called before the current thread exits; might as well do it here. + g_java_vm->DetachCurrentThread(); - return false; + return false; } #define DVD_BANNER_WIDTH 96 #define DVD_BANNER_HEIGHT 32 -static inline u32 Average32(u32 a, u32 b) { - return ((a >> 1) & 0x7f7f7f7f) + ((b >> 1) & 0x7f7f7f7f); -} - -static inline u32 GetPixel(u32 *buffer, unsigned int x, unsigned int y) { - // thanks to unsignedness, these also check for <0 automatically. - if (x > 191) return 0; - if (y > 63) return 0; - return buffer[y * 192 + x]; -} - -static bool LoadBanner(std::string filename, u32 *Banner) +static inline u32 Average32(u32 a, u32 b) { - std::unique_ptr pVolume(DiscIO::CreateVolumeFromFilename(filename)); + return ((a >> 1) & 0x7f7f7f7f) + ((b >> 1) & 0x7f7f7f7f); +} - if (pVolume != nullptr) - { - int Width, Height; - std::vector BannerVec = pVolume->GetBanner(&Width, &Height); - // This code (along with above inlines) is moved from - // elsewhere. Someone who knows anything about Android - // please get rid of it and use proper high-resolution - // images. - if (Height == 64 && Width == 192) - { - u32* Buffer = &BannerVec[0]; - for (int y = 0; y < 32; y++) - { - for (int x = 0; x < 96; x++) - { - // simplified plus-shaped "gaussian" - u32 surround = Average32( - Average32(GetPixel(Buffer, x*2 - 1, y*2), GetPixel(Buffer, x*2 + 1, y*2)), - Average32(GetPixel(Buffer, x*2, y*2 - 1), GetPixel(Buffer, x*2, y*2 + 1))); - Banner[y * 96 + x] = Average32(GetPixel(Buffer, x*2, y*2), surround); - } - } - return true; - } - else if (Height == 32 && Width == 96) - { - memcpy(Banner, &BannerVec[0], 96 * 32 * 4); - return true; - } - } +static inline u32 GetPixel(u32* buffer, unsigned int x, unsigned int y) +{ + // thanks to unsignedness, these also check for <0 automatically. + if (x > 191) + return 0; + if (y > 63) + return 0; + return buffer[y * 192 + x]; +} - return false; +static bool LoadBanner(std::string filename, u32* Banner) +{ + std::unique_ptr pVolume(DiscIO::CreateVolumeFromFilename(filename)); + + if (pVolume != nullptr) + { + int Width, Height; + std::vector BannerVec = pVolume->GetBanner(&Width, &Height); + // This code (along with above inlines) is moved from + // elsewhere. Someone who knows anything about Android + // please get rid of it and use proper high-resolution + // images. + if (Height == 64 && Width == 192) + { + u32* Buffer = &BannerVec[0]; + for (int y = 0; y < 32; y++) + { + for (int x = 0; x < 96; x++) + { + // simplified plus-shaped "gaussian" + u32 surround = Average32( + Average32(GetPixel(Buffer, x * 2 - 1, y * 2), GetPixel(Buffer, x * 2 + 1, y * 2)), + Average32(GetPixel(Buffer, x * 2, y * 2 - 1), GetPixel(Buffer, x * 2, y * 2 + 1))); + Banner[y * 96 + x] = Average32(GetPixel(Buffer, x * 2, y * 2), surround); + } + } + return true; + } + else if (Height == 32 && Width == 96) + { + memcpy(Banner, &BannerVec[0], 96 * 32 * 4); + return true; + } + } + + return false; } static int GetCountry(std::string filename) { - std::unique_ptr pVolume(DiscIO::CreateVolumeFromFilename(filename)); + std::unique_ptr pVolume(DiscIO::CreateVolumeFromFilename(filename)); - if (pVolume != nullptr) - { - DiscIO::IVolume::ECountry country = pVolume->GetCountry(); + if (pVolume != nullptr) + { + DiscIO::IVolume::ECountry country = pVolume->GetCountry(); - __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Country Code: %i", country); + __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Country Code: %i", country); - return country; - } + return country; + } - // Return UNKNOWN - return 13; + // Return UNKNOWN + return 13; } static int GetPlatform(std::string filename) { - std::unique_ptr pVolume(DiscIO::CreateVolumeFromFilename(filename)); + std::unique_ptr pVolume(DiscIO::CreateVolumeFromFilename(filename)); - if (pVolume != nullptr) - { - switch (pVolume->GetVolumeType()) - { - case DiscIO::IVolume::GAMECUBE_DISC: - __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Volume is a GameCube disc."); - return 0; - case DiscIO::IVolume::WII_DISC: - __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Volume is a Wii disc."); - return 1; - case DiscIO::IVolume::WII_WAD: - __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Volume is a Wii WAD."); - return 2; - } - } + if (pVolume != nullptr) + { + switch (pVolume->GetVolumeType()) + { + case DiscIO::IVolume::GAMECUBE_DISC: + __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Volume is a GameCube disc."); + return 0; + case DiscIO::IVolume::WII_DISC: + __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Volume is a Wii disc."); + return 1; + case DiscIO::IVolume::WII_WAD: + __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Volume is a Wii WAD."); + return 2; + } + } - return -1; + return -1; } static std::string GetTitle(std::string filename) { - __android_log_print(ANDROID_LOG_WARN, DOLPHIN_TAG, "Getting Title for file: %s", filename.c_str()); + __android_log_print(ANDROID_LOG_WARN, DOLPHIN_TAG, "Getting Title for file: %s", + filename.c_str()); - std::unique_ptr pVolume(DiscIO::CreateVolumeFromFilename(filename)); + std::unique_ptr pVolume(DiscIO::CreateVolumeFromFilename(filename)); - if (pVolume != nullptr) { - std::map titles = pVolume->GetNames(true); + if (pVolume != nullptr) + { + std::map titles = pVolume->GetNames(true); - /* - bool is_wii_title = pVolume->GetVolumeType() != DiscIO::IVolume::GAMECUBE_DISC; - DiscIO::IVolume::ELanguage language = SConfig::GetInstance().GetCurrentLanguage(is_wii_title); + /* + bool is_wii_title = pVolume->GetVolumeType() != DiscIO::IVolume::GAMECUBE_DISC; + DiscIO::IVolume::ELanguage language = SConfig::GetInstance().GetCurrentLanguage(is_wii_title); - auto it = titles.find(language); - if (it != end) - return it->second;*/ + auto it = titles.find(language); + if (it != end) + return it->second;*/ - auto end = titles.end(); + auto end = titles.end(); - // English tends to be a good fallback when the requested language isn't available - //if (language != DiscIO::IVolume::ELanguage::LANGUAGE_ENGLISH) { - auto it = titles.find(DiscIO::IVolume::ELanguage::LANGUAGE_ENGLISH); - if (it != end) - return it->second; - //} + // English tends to be a good fallback when the requested language isn't available + // if (language != DiscIO::IVolume::ELanguage::LANGUAGE_ENGLISH) { + auto it = titles.find(DiscIO::IVolume::ELanguage::LANGUAGE_ENGLISH); + if (it != end) + return it->second; + //} + // If English isn't available either, just pick something + if (!titles.empty()) + return titles.cbegin()->second; - // If English isn't available either, just pick something - if (!titles.empty()) - return titles.cbegin()->second; + // No usable name, return filename (better than nothing) + std::string name; + SplitPath(filename, nullptr, &name, nullptr); + return name; + } - // No usable name, return filename (better than nothing) - std::string name; - SplitPath(filename, nullptr, &name, nullptr); - return name; - } - - return std::string (""); + return std::string(""); } static std::string GetDescription(std::string filename) { - __android_log_print(ANDROID_LOG_WARN, DOLPHIN_TAG, "Getting Description for file: %s", filename.c_str()); + __android_log_print(ANDROID_LOG_WARN, DOLPHIN_TAG, "Getting Description for file: %s", + filename.c_str()); - std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(filename)); + std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(filename)); - if (volume != nullptr) - { - std::map descriptions = volume->GetDescriptions(); + if (volume != nullptr) + { + std::map descriptions = volume->GetDescriptions(); - /* - bool is_wii_title = pVolume->GetVolumeType() != DiscIO::IVolume::GAMECUBE_DISC; - DiscIO::IVolume::ELanguage language = SConfig::GetInstance().GetCurrentLanguage(is_wii_title); + /* + bool is_wii_title = pVolume->GetVolumeType() != DiscIO::IVolume::GAMECUBE_DISC; + DiscIO::IVolume::ELanguage language = SConfig::GetInstance().GetCurrentLanguage(is_wii_title); - auto it = descriptions.find(language); - if (it != end) - return it->second;*/ + auto it = descriptions.find(language); + if (it != end) + return it->second;*/ - auto end = descriptions.end(); + auto end = descriptions.end(); - // English tends to be a good fallback when the requested language isn't available - //if (language != DiscIO::IVolume::ELanguage::LANGUAGE_ENGLISH) { - auto it = descriptions.find(DiscIO::IVolume::ELanguage::LANGUAGE_ENGLISH); - if (it != end) - return it->second; - //} + // English tends to be a good fallback when the requested language isn't available + // if (language != DiscIO::IVolume::ELanguage::LANGUAGE_ENGLISH) { + auto it = descriptions.find(DiscIO::IVolume::ELanguage::LANGUAGE_ENGLISH); + if (it != end) + return it->second; + //} - // If English isn't available either, just pick something - if (!descriptions.empty()) - return descriptions.cbegin()->second; - } + // If English isn't available either, just pick something + if (!descriptions.empty()) + return descriptions.cbegin()->second; + } - return std::string(); + return std::string(); } static std::string GetGameId(std::string filename) { - __android_log_print(ANDROID_LOG_WARN, DOLPHIN_TAG, "Getting ID for file: %s", filename.c_str()); + __android_log_print(ANDROID_LOG_WARN, DOLPHIN_TAG, "Getting ID for file: %s", filename.c_str()); - std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(filename)); - if (volume == nullptr) - return std::string(); + std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(filename)); + if (volume == nullptr) + return std::string(); - std::string id = volume->GetUniqueID(); - __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Game ID: %s", id.c_str()); - return id; + std::string id = volume->GetUniqueID(); + __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Game ID: %s", id.c_str()); + return id; } static std::string GetCompany(std::string filename) { - __android_log_print(ANDROID_LOG_WARN, DOLPHIN_TAG, "Getting Company for file: %s", filename.c_str()); + __android_log_print(ANDROID_LOG_WARN, DOLPHIN_TAG, "Getting Company for file: %s", + filename.c_str()); - std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(filename)); - if (volume == nullptr) - return std::string(); + std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(filename)); + if (volume == nullptr) + return std::string(); - std::string company = DiscIO::GetCompanyFromID(volume->GetMakerID()); - __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Company: %s", company.c_str()); - return company; + std::string company = DiscIO::GetCompanyFromID(volume->GetMakerID()); + __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Company: %s", company.c_str()); + return company; } static u64 GetFileSize(std::string filename) { - __android_log_print(ANDROID_LOG_WARN, DOLPHIN_TAG, "Getting size of file: %s", filename.c_str()); + __android_log_print(ANDROID_LOG_WARN, DOLPHIN_TAG, "Getting size of file: %s", filename.c_str()); - std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(filename)); - if (volume == nullptr) - return -1; + std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(filename)); + if (volume == nullptr) + return -1; - u64 size = volume->GetSize(); - __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Size: %" PRIu64, size); - return size; + u64 size = volume->GetSize(); + __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Size: %" PRIu64, size); + return size; } -static std::string GetJString(JNIEnv *env, jstring jstr) +static std::string GetJString(JNIEnv* env, jstring jstr) { - std::string result = ""; - if (!jstr) - return result; + std::string result = ""; + if (!jstr) + return result; - const char *s = env->GetStringUTFChars(jstr, nullptr); - result = s; - env->ReleaseStringUTFChars(jstr, s); - return result; + const char* s = env->GetStringUTFChars(jstr, nullptr); + result = s; + env->ReleaseStringUTFChars(jstr, s); + return result; } #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_UnPauseEmulation(JNIEnv *env, jobject obj); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_PauseEmulation(JNIEnv *env, jobject obj); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv *env, jobject obj); -JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadEvent(JNIEnv *env, jobject obj, jstring jDevice, jint Button, jint Action); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadMoveEvent(JNIEnv *env, jobject obj, jstring jDevice, jint Axis, jfloat Value); -JNIEXPORT jintArray JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetBanner(JNIEnv *env, jobject obj, jstring jFile);JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetTitle(JNIEnv *env, jobject obj, jstring jFilename); -JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetDescription(JNIEnv *env, jobject obj, jstring jFilename); -JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGameId(JNIEnv *env, jobject obj, jstring jFilename); -JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetCountry(JNIEnv *env, jobject obj, jstring jFilename); -JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetCompany(JNIEnv *env, jobject obj, jstring jFilename); -JNIEXPORT jlong JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetFilesize(JNIEnv *env, jobject obj, jstring jFilename); -JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetPlatform(JNIEnv *env, jobject obj, jstring jFilename); -JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv *env, jobject obj); -JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SupportsNEON(JNIEnv *env, jobject obj); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveScreenShot(JNIEnv *env, jobject obj); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_eglBindAPI(JNIEnv *env, jobject obj, jint api); -JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetConfig(JNIEnv *env, jobject obj, jstring jFile, jstring jSection, jstring jKey, jstring jDefault); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetConfig(JNIEnv *env, jobject obj, jstring jFile, jstring jSection, jstring jKey, jstring jValue); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetFilename(JNIEnv *env, jobject obj, jstring jFile); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveState(JNIEnv *env, jobject obj, jint slot); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadState(JNIEnv *env, jobject obj, jint slot); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_CreateUserFolders(JNIEnv *env, jobject obj); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory(JNIEnv *env, jobject obj, jstring jDirectory); -JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetUserDirectory(JNIEnv *env, jobject obj); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling(JNIEnv *env, jobject obj, jboolean enable); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfileResults(JNIEnv *env, jobject obj); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_CacheClassesAndMethods(JNIEnv *env, jobject obj); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv *env, jobject obj); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChanged(JNIEnv *env, jobject obj, jobject _surf); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv *env, jobject obj); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_UnPauseEmulation(JNIEnv* env, + jobject obj); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_PauseEmulation(JNIEnv* env, + jobject obj); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv* env, + jobject obj); +JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadEvent( + JNIEnv* env, jobject obj, jstring jDevice, jint Button, jint Action); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadMoveEvent( + JNIEnv* env, jobject obj, jstring jDevice, jint Axis, jfloat Value); +JNIEXPORT jintArray JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetBanner(JNIEnv* env, + jobject obj, + jstring jFile); +JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetTitle(JNIEnv* env, + jobject obj, + jstring jFilename); +JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetDescription( + JNIEnv* env, jobject obj, jstring jFilename); +JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGameId(JNIEnv* env, + jobject obj, + jstring jFilename); +JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetCountry(JNIEnv* env, + jobject obj, + jstring jFilename); +JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetCompany( + JNIEnv* env, jobject obj, jstring jFilename); +JNIEXPORT jlong JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetFilesize(JNIEnv* env, + jobject obj, + jstring jFilename); +JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetPlatform(JNIEnv* env, + jobject obj, + jstring jFilename); +JNIEXPORT jstring JNICALL +Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv* env, jobject obj); +JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SupportsNEON(JNIEnv* env, + jobject obj); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveScreenShot(JNIEnv* env, + jobject obj); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_eglBindAPI(JNIEnv* env, + jobject obj, + jint api); +JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetConfig( + JNIEnv* env, jobject obj, jstring jFile, jstring jSection, jstring jKey, jstring jDefault); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetConfig( + JNIEnv* env, jobject obj, jstring jFile, jstring jSection, jstring jKey, jstring jValue); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetFilename(JNIEnv* env, + jobject obj, + jstring jFile); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveState(JNIEnv* env, + jobject obj, + jint slot); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadState(JNIEnv* env, + jobject obj, + jint slot); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_CreateUserFolders(JNIEnv* env, + jobject obj); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory( + JNIEnv* env, jobject obj, jstring jDirectory); +JNIEXPORT jstring JNICALL +Java_org_dolphinemu_dolphinemu_NativeLibrary_GetUserDirectory(JNIEnv* env, jobject obj); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling(JNIEnv* env, + jobject obj, + jboolean enable); +JNIEXPORT void JNICALL +Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfileResults(JNIEnv* env, jobject obj); +JNIEXPORT void JNICALL +Java_org_dolphinemu_dolphinemu_NativeLibrary_CacheClassesAndMethods(JNIEnv* env, jobject obj); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv* env, jobject obj); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChanged(JNIEnv* env, + jobject obj, + jobject _surf); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv* env, + jobject obj); -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_UnPauseEmulation(JNIEnv *env, jobject obj) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_UnPauseEmulation(JNIEnv* env, + jobject obj) { - std::lock_guard guard(s_host_identity_lock); - Core::SetState(Core::CORE_RUN); + std::lock_guard guard(s_host_identity_lock); + Core::SetState(Core::CORE_RUN); } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_PauseEmulation(JNIEnv *env, jobject obj) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_PauseEmulation(JNIEnv* env, + jobject obj) { - std::lock_guard guard(s_host_identity_lock); - Core::SetState(Core::CORE_PAUSE); + std::lock_guard guard(s_host_identity_lock); + Core::SetState(Core::CORE_PAUSE); } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv *env, jobject obj) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv* env, + jobject obj) { - std::lock_guard guard(s_host_identity_lock); - Core::SaveScreenShot("thumb"); - Renderer::s_screenshotCompleted.WaitFor(std::chrono::seconds(2)); - Core::Stop(); - updateMainFrameEvent.Set(); // Kick the waiting event + std::lock_guard guard(s_host_identity_lock); + Core::SaveScreenShot("thumb"); + Renderer::s_screenshotCompleted.WaitFor(std::chrono::seconds(2)); + Core::Stop(); + updateMainFrameEvent.Set(); // Kick the waiting event } -JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadEvent(JNIEnv *env, jobject obj, jstring jDevice, jint Button, jint Action) +JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadEvent( + JNIEnv* env, jobject obj, jstring jDevice, jint Button, jint Action) { - return ButtonManager::GamepadEvent(GetJString(env, jDevice), Button, Action); + return ButtonManager::GamepadEvent(GetJString(env, jDevice), Button, Action); } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadMoveEvent(JNIEnv *env, jobject obj, jstring jDevice, jint Axis, jfloat Value) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadMoveEvent( + JNIEnv* env, jobject obj, jstring jDevice, jint Axis, jfloat Value) { - ButtonManager::GamepadAxisEvent(GetJString(env, jDevice), Axis, Value); + ButtonManager::GamepadAxisEvent(GetJString(env, jDevice), Axis, Value); } -JNIEXPORT jintArray JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetBanner(JNIEnv *env, jobject obj, jstring jFile) +JNIEXPORT jintArray JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetBanner(JNIEnv* env, + jobject obj, + jstring jFile) { - std::string file = GetJString(env, jFile); - u32 uBanner[DVD_BANNER_WIDTH * DVD_BANNER_HEIGHT]; - jintArray Banner = env->NewIntArray(DVD_BANNER_WIDTH * DVD_BANNER_HEIGHT); + std::string file = GetJString(env, jFile); + u32 uBanner[DVD_BANNER_WIDTH * DVD_BANNER_HEIGHT]; + jintArray Banner = env->NewIntArray(DVD_BANNER_WIDTH * DVD_BANNER_HEIGHT); - if (LoadBanner(file, uBanner)) - { - env->SetIntArrayRegion(Banner, 0, DVD_BANNER_WIDTH * DVD_BANNER_HEIGHT, (jint*)uBanner); - } - return Banner; + if (LoadBanner(file, uBanner)) + { + env->SetIntArrayRegion(Banner, 0, DVD_BANNER_WIDTH * DVD_BANNER_HEIGHT, (jint*)uBanner); + } + return Banner; } -JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetTitle(JNIEnv *env, jobject obj, jstring jFilename) +JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetTitle(JNIEnv* env, + jobject obj, + jstring jFilename) { - std::string filename = GetJString(env, jFilename); - std::string name = GetTitle(filename); - return env->NewStringUTF(name.c_str()); + std::string filename = GetJString(env, jFilename); + std::string name = GetTitle(filename); + return env->NewStringUTF(name.c_str()); } -JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetDescription(JNIEnv *env, jobject obj, jstring jFilename) +JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetDescription( + JNIEnv* env, jobject obj, jstring jFilename) { - std::string filename = GetJString(env, jFilename); - std::string description = GetDescription(filename); - return env->NewStringUTF(description.c_str()); + std::string filename = GetJString(env, jFilename); + std::string description = GetDescription(filename); + return env->NewStringUTF(description.c_str()); } -JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGameId(JNIEnv *env, jobject obj, jstring jFilename) +JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGameId(JNIEnv* env, + jobject obj, + jstring jFilename) { - std::string filename = GetJString(env, jFilename); - std::string id = GetGameId(filename); - return env->NewStringUTF(id.c_str()); + std::string filename = GetJString(env, jFilename); + std::string id = GetGameId(filename); + return env->NewStringUTF(id.c_str()); } -JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetCompany(JNIEnv *env, jobject obj, jstring jFilename) +JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetCompany(JNIEnv* env, + jobject obj, + jstring jFilename) { - std::string filename = GetJString(env, jFilename); - std::string company = GetCompany(filename); - return env->NewStringUTF(company.c_str()); + std::string filename = GetJString(env, jFilename); + std::string company = GetCompany(filename); + return env->NewStringUTF(company.c_str()); } -JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetCountry(JNIEnv *env, jobject obj, jstring jFilename) +JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetCountry(JNIEnv* env, + jobject obj, + jstring jFilename) { - std::string filename = GetJString(env, jFilename); - int country = GetCountry(filename); - return country; + std::string filename = GetJString(env, jFilename); + int country = GetCountry(filename); + return country; } -JNIEXPORT jlong JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetFilesize(JNIEnv *env, jobject obj, jstring jFilename) +JNIEXPORT jlong JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetFilesize(JNIEnv* env, + jobject obj, + jstring jFilename) { - std::string filename = GetJString(env, jFilename); - u64 size = GetFileSize(filename); - return size; + std::string filename = GetJString(env, jFilename); + u64 size = GetFileSize(filename); + return size; } -JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetPlatform(JNIEnv *env, jobject obj, jstring jFilename) +JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetPlatform(JNIEnv* env, + jobject obj, + jstring jFilename) { - std::string filename = GetJString(env, jFilename); - int platform = GetPlatform(filename); - return platform; + std::string filename = GetJString(env, jFilename); + int platform = GetPlatform(filename); + return platform; } -JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv *env, jobject obj) +JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv* env, + jobject obj) { - return env->NewStringUTF(scm_rev_str.c_str()); + return env->NewStringUTF(scm_rev_str.c_str()); } -JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SupportsNEON(JNIEnv *env, jobject obj) +JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SupportsNEON(JNIEnv* env, + jobject obj) { - return cpu_info.bASIMD; + return cpu_info.bASIMD; } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveScreenShot(JNIEnv *env, jobject obj) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveScreenShot(JNIEnv* env, + jobject obj) { - std::lock_guard guard(s_host_identity_lock); - Core::SaveScreenShot(); + std::lock_guard guard(s_host_identity_lock); + Core::SaveScreenShot(); } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_eglBindAPI(JNIEnv *env, jobject obj, jint api) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_eglBindAPI(JNIEnv* env, + jobject obj, + jint api) { - eglBindAPI(api); + eglBindAPI(api); } -JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetConfig(JNIEnv *env, jobject obj, jstring jFile, jstring jSection, jstring jKey, jstring jDefault) +JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetConfig( + JNIEnv* env, jobject obj, jstring jFile, jstring jSection, jstring jKey, jstring jDefault) { - IniFile ini; - std::string file = GetJString(env, jFile); - std::string section = GetJString(env, jSection); - std::string key = GetJString(env, jKey); - std::string defaultValue = GetJString(env, jDefault); + IniFile ini; + std::string file = GetJString(env, jFile); + std::string section = GetJString(env, jSection); + std::string key = GetJString(env, jKey); + std::string defaultValue = GetJString(env, jDefault); - ini.Load(File::GetUserPath(D_CONFIG_IDX) + std::string(file)); - std::string value; + ini.Load(File::GetUserPath(D_CONFIG_IDX) + std::string(file)); + std::string value; - ini.GetOrCreateSection(section)->Get(key, &value, defaultValue); + ini.GetOrCreateSection(section)->Get(key, &value, defaultValue); - return env->NewStringUTF(value.c_str()); + return env->NewStringUTF(value.c_str()); } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetConfig(JNIEnv *env, jobject obj, jstring jFile, jstring jSection, jstring jKey, jstring jValue) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetConfig( + JNIEnv* env, jobject obj, jstring jFile, jstring jSection, jstring jKey, jstring jValue) { - IniFile ini; - std::string file = GetJString(env, jFile); - std::string section = GetJString(env, jSection); - std::string key = GetJString(env, jKey); - std::string value = GetJString(env, jValue); + IniFile ini; + std::string file = GetJString(env, jFile); + std::string section = GetJString(env, jSection); + std::string key = GetJString(env, jKey); + std::string value = GetJString(env, jValue); - ini.Load(File::GetUserPath(D_CONFIG_IDX) + std::string(file)); + ini.Load(File::GetUserPath(D_CONFIG_IDX) + std::string(file)); - ini.GetOrCreateSection(section)->Set(key, value); - ini.Save(File::GetUserPath(D_CONFIG_IDX) + std::string(file)); + ini.GetOrCreateSection(section)->Set(key, value); + ini.Save(File::GetUserPath(D_CONFIG_IDX) + std::string(file)); } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetFilename(JNIEnv *env, jobject obj, jstring jFile) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetFilename(JNIEnv* env, + jobject obj, + jstring jFile) { - g_filename = GetJString(env, jFile); + g_filename = GetJString(env, jFile); } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveState(JNIEnv *env, jobject obj, jint slot) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveState(JNIEnv* env, + jobject obj, + jint slot) { - std::lock_guard guard(s_host_identity_lock); - State::Save(slot); + std::lock_guard guard(s_host_identity_lock); + State::Save(slot); } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadState(JNIEnv *env, jobject obj, jint slot) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadState(JNIEnv* env, + jobject obj, + jint slot) { - std::lock_guard guard(s_host_identity_lock); - State::Load(slot); + std::lock_guard guard(s_host_identity_lock); + State::Load(slot); } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_CreateUserFolders(JNIEnv *env, jobject obj) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_CreateUserFolders(JNIEnv* env, + jobject obj) { - File::CreateFullPath(File::GetUserPath(D_CONFIG_IDX)); - File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX)); - File::CreateFullPath(File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP WII_WC24CONF_DIR DIR_SEP "mbox" DIR_SEP); - File::CreateFullPath(File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP "shared2" DIR_SEP "succession" DIR_SEP); - File::CreateFullPath(File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP "shared2" DIR_SEP "ec" DIR_SEP); - File::CreateFullPath(File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP WII_SYSCONF_DIR DIR_SEP); - File::CreateFullPath(File::GetUserPath(D_CACHE_IDX)); - File::CreateFullPath(File::GetUserPath(D_DUMPDSP_IDX)); - File::CreateFullPath(File::GetUserPath(D_DUMPTEXTURES_IDX)); - File::CreateFullPath(File::GetUserPath(D_HIRESTEXTURES_IDX)); - File::CreateFullPath(File::GetUserPath(D_SCREENSHOTS_IDX)); - File::CreateFullPath(File::GetUserPath(D_STATESAVES_IDX)); - File::CreateFullPath(File::GetUserPath(D_MAILLOGS_IDX)); - File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX) + "Anaglyph" DIR_SEP); - File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + USA_DIR DIR_SEP); - File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + EUR_DIR DIR_SEP); - File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + JAP_DIR DIR_SEP); + File::CreateFullPath(File::GetUserPath(D_CONFIG_IDX)); + File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX)); + File::CreateFullPath(File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP WII_WC24CONF_DIR DIR_SEP + "mbox" DIR_SEP); + File::CreateFullPath(File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP "shared2" DIR_SEP + "succession" DIR_SEP); + File::CreateFullPath(File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP "shared2" DIR_SEP "ec" DIR_SEP); + File::CreateFullPath(File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP WII_SYSCONF_DIR DIR_SEP); + File::CreateFullPath(File::GetUserPath(D_CACHE_IDX)); + File::CreateFullPath(File::GetUserPath(D_DUMPDSP_IDX)); + File::CreateFullPath(File::GetUserPath(D_DUMPTEXTURES_IDX)); + File::CreateFullPath(File::GetUserPath(D_HIRESTEXTURES_IDX)); + File::CreateFullPath(File::GetUserPath(D_SCREENSHOTS_IDX)); + File::CreateFullPath(File::GetUserPath(D_STATESAVES_IDX)); + File::CreateFullPath(File::GetUserPath(D_MAILLOGS_IDX)); + File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX) + "Anaglyph" DIR_SEP); + File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + USA_DIR DIR_SEP); + File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + EUR_DIR DIR_SEP); + File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + JAP_DIR DIR_SEP); } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory(JNIEnv *env, jobject obj, jstring jDirectory) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory( + JNIEnv* env, jobject obj, jstring jDirectory) { - std::lock_guard guard(s_host_identity_lock); - std::string directory = GetJString(env, jDirectory); - g_set_userpath = directory; - UICommon::SetUserDirectory(directory); + std::lock_guard guard(s_host_identity_lock); + std::string directory = GetJString(env, jDirectory); + g_set_userpath = directory; + UICommon::SetUserDirectory(directory); } -JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetUserDirectory(JNIEnv *env, jobject obj) +JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetUserDirectory(JNIEnv* env, + jobject obj) { - return env->NewStringUTF(File::GetUserPath(D_USER_IDX).c_str()); + return env->NewStringUTF(File::GetUserPath(D_USER_IDX).c_str()); } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling(JNIEnv *env, jobject obj, jboolean enable) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling(JNIEnv* env, + jobject obj, + jboolean enable) { - std::lock_guard guard(s_host_identity_lock); - Core::SetState(Core::CORE_PAUSE); - JitInterface::ClearCache(); - Profiler::g_ProfileBlocks = enable; - Core::SetState(Core::CORE_RUN); + std::lock_guard guard(s_host_identity_lock); + Core::SetState(Core::CORE_PAUSE); + JitInterface::ClearCache(); + Profiler::g_ProfileBlocks = enable; + Core::SetState(Core::CORE_RUN); } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfileResults(JNIEnv *env, jobject obj) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfileResults(JNIEnv* env, + jobject obj) { - std::lock_guard guard(s_host_identity_lock); - std::string filename = File::GetUserPath(D_DUMP_IDX) + "Debug/profiler.txt"; - File::CreateFullPath(filename); - JitInterface::WriteProfileResults(filename); + std::lock_guard guard(s_host_identity_lock); + std::string filename = File::GetUserPath(D_DUMP_IDX) + "Debug/profiler.txt"; + File::CreateFullPath(filename); + JitInterface::WriteProfileResults(filename); } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_CacheClassesAndMethods(JNIEnv *env, jobject obj) +JNIEXPORT void JNICALL +Java_org_dolphinemu_dolphinemu_NativeLibrary_CacheClassesAndMethods(JNIEnv* env, jobject obj) { - // This class reference is only valid for the lifetime of this method. - jclass localClass = env->FindClass("org/dolphinemu/dolphinemu/NativeLibrary"); + // This class reference is only valid for the lifetime of this method. + jclass localClass = env->FindClass("org/dolphinemu/dolphinemu/NativeLibrary"); - // This reference, however, is valid until we delete it. - g_jni_class = reinterpret_cast(env->NewGlobalRef(localClass)); + // This reference, however, is valid until we delete it. + g_jni_class = reinterpret_cast(env->NewGlobalRef(localClass)); - // TODO Find a place for this. - // So we don't leak a reference to NativeLibrary.class. - // env->DeleteGlobalRef(g_jni_class); + // TODO Find a place for this. + // So we don't leak a reference to NativeLibrary.class. + // env->DeleteGlobalRef(g_jni_class); - // Method signature taken from javap -s Source/Android/app/build/intermediates/classes/arm/debug/org/dolphinemu/dolphinemu/NativeLibrary.class - g_jni_method_alert = env->GetStaticMethodID(g_jni_class, "displayAlertMsg", "(Ljava/lang/String;)V"); - g_jni_method_end = env->GetStaticMethodID(g_jni_class, "endEmulationActivity", "()V"); + // Method signature taken from javap -s + // Source/Android/app/build/intermediates/classes/arm/debug/org/dolphinemu/dolphinemu/NativeLibrary.class + g_jni_method_alert = + env->GetStaticMethodID(g_jni_class, "displayAlertMsg", "(Ljava/lang/String;)V"); + g_jni_method_end = env->GetStaticMethodID(g_jni_class, "endEmulationActivity", "()V"); } // Surface Handling -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChanged(JNIEnv *env, jobject obj, jobject _surf) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChanged(JNIEnv* env, + jobject obj, + jobject _surf) { - surf = ANativeWindow_fromSurface(env, _surf); - if (surf == nullptr) - __android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "Error: Surface is null."); + surf = ANativeWindow_fromSurface(env, _surf); + if (surf == nullptr) + __android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "Error: Surface is null."); - // If GLInterface isn't a thing yet then we don't need to let it know that the surface has changed - if (GLInterface) - { - GLInterface->UpdateHandle(surf); - Renderer::s_ChangedSurface.Reset(); - Renderer::s_SurfaceNeedsChanged.Set(); - Renderer::s_ChangedSurface.Wait(); - } + // If GLInterface isn't a thing yet then we don't need to let it know that the surface has changed + if (GLInterface) + { + GLInterface->UpdateHandle(surf); + Renderer::s_ChangedSurface.Reset(); + Renderer::s_SurfaceNeedsChanged.Set(); + Renderer::s_ChangedSurface.Wait(); + } } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv *env, jobject obj) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv* env, + jobject obj) { - if (surf) - { - ANativeWindow_release(surf); - surf = nullptr; - } + if (surf) + { + ANativeWindow_release(surf); + surf = nullptr; + } - // If GLInterface isn't a thing yet then we don't need to let it know that the surface has changed - if (GLInterface) - { - GLInterface->UpdateHandle(nullptr); - Renderer::s_ChangedSurface.Reset(); - Renderer::s_SurfaceNeedsChanged.Set(); - Renderer::s_ChangedSurface.Wait(); - } + // If GLInterface isn't a thing yet then we don't need to let it know that the surface has changed + if (GLInterface) + { + GLInterface->UpdateHandle(nullptr); + Renderer::s_ChangedSurface.Reset(); + Renderer::s_SurfaceNeedsChanged.Set(); + Renderer::s_ChangedSurface.Wait(); + } } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_RefreshWiimotes(JNIEnv *env, jobject obj) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_RefreshWiimotes(JNIEnv* env, + jobject obj) { - std::lock_guard guard(s_host_identity_lock); - WiimoteReal::Refresh(); + std::lock_guard guard(s_host_identity_lock); + WiimoteReal::Refresh(); } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv *env, jobject obj) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv* env, jobject obj) { - __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", g_filename.c_str()); + __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", g_filename.c_str()); - // Install our callbacks - OSD::AddCallback(OSD::CallbackType::Initialization, ButtonManager::Init); - OSD::AddCallback(OSD::CallbackType::Shutdown, ButtonManager::Shutdown); + // Install our callbacks + OSD::AddCallback(OSD::CallbackType::Initialization, ButtonManager::Init); + OSD::AddCallback(OSD::CallbackType::Shutdown, ButtonManager::Shutdown); - RegisterMsgAlertHandler(&MsgAlert); + RegisterMsgAlertHandler(&MsgAlert); - std::unique_lock guard(s_host_identity_lock); - UICommon::SetUserDirectory(g_set_userpath); - UICommon::Init(); + std::unique_lock guard(s_host_identity_lock); + UICommon::SetUserDirectory(g_set_userpath); + UICommon::Init(); - WiimoteReal::InitAdapterClass(); + WiimoteReal::InitAdapterClass(); - // No use running the loop when booting fails - s_have_wm_user_stop = false; - if ( BootManager::BootCore( g_filename.c_str() ) ) - { - static constexpr int TIMEOUT = 10000; - static constexpr int WAIT_STEP = 25; - int time_waited = 0; - // A Core::CORE_ERROR state would be helpful here. - while (!Core::IsRunning() && time_waited < TIMEOUT && !s_have_wm_user_stop) - { - std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_STEP)); - time_waited += WAIT_STEP; - } - while (Core::IsRunning()) - { - guard.unlock(); - updateMainFrameEvent.Wait(); - guard.lock(); - Core::HostDispatchJobs(); - } - } + // No use running the loop when booting fails + s_have_wm_user_stop = false; + if (BootManager::BootCore(g_filename.c_str())) + { + static constexpr int TIMEOUT = 10000; + static constexpr int WAIT_STEP = 25; + int time_waited = 0; + // A Core::CORE_ERROR state would be helpful here. + while (!Core::IsRunning() && time_waited < TIMEOUT && !s_have_wm_user_stop) + { + std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_STEP)); + time_waited += WAIT_STEP; + } + while (Core::IsRunning()) + { + guard.unlock(); + updateMainFrameEvent.Wait(); + guard.lock(); + Core::HostDispatchJobs(); + } + } - Core::Shutdown(); - UICommon::Shutdown(); - guard.unlock(); + Core::Shutdown(); + UICommon::Shutdown(); + guard.unlock(); - if (surf) - { - ANativeWindow_release(surf); - surf = nullptr; - } + if (surf) + { + ANativeWindow_release(surf); + surf = nullptr; + } - // Execute the Java method. - env->CallStaticVoidMethod(g_jni_class, g_jni_method_end); + // Execute the Java method. + env->CallStaticVoidMethod(g_jni_class, g_jni_method_end); } - #ifdef __cplusplus } #endif diff --git a/Source/Core/AudioCommon/AOSoundStream.cpp b/Source/Core/AudioCommon/AOSoundStream.cpp index c9bacac206..6dc1219e88 100644 --- a/Source/Core/AudioCommon/AOSoundStream.cpp +++ b/Source/Core/AudioCommon/AOSoundStream.cpp @@ -6,77 +6,77 @@ #include "AudioCommon/AOSoundStream.h" #include "AudioCommon/Mixer.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #if defined(HAVE_AO) && HAVE_AO void AOSound::SoundLoop() { - Common::SetCurrentThreadName("Audio thread - ao"); + Common::SetCurrentThreadName("Audio thread - ao"); - uint_32 numBytesToRender = 256; - ao_initialize(); - default_driver = ao_default_driver_id(); - format.bits = 16; - format.channels = 2; - format.rate = m_mixer->GetSampleRate(); - format.byte_format = AO_FMT_LITTLE; + uint_32 numBytesToRender = 256; + ao_initialize(); + default_driver = ao_default_driver_id(); + format.bits = 16; + format.channels = 2; + format.rate = m_mixer->GetSampleRate(); + format.byte_format = AO_FMT_LITTLE; - device = ao_open_live(default_driver, &format, nullptr /* no options */); - if (!device) - { - PanicAlertT("AudioCommon: Error opening AO device.\n"); - ao_shutdown(); - Stop(); - return; - } + device = ao_open_live(default_driver, &format, nullptr /* no options */); + if (!device) + { + PanicAlertT("AudioCommon: Error opening AO device.\n"); + ao_shutdown(); + Stop(); + return; + } - buf_size = format.bits/8 * format.channels * format.rate; + buf_size = format.bits / 8 * format.channels * format.rate; - while (m_run_thread.load()) - { - m_mixer->Mix(realtimeBuffer, numBytesToRender >> 2); + while (m_run_thread.load()) + { + m_mixer->Mix(realtimeBuffer, numBytesToRender >> 2); - { - std::lock_guard lk(soundCriticalSection); - ao_play(device, (char*)realtimeBuffer, numBytesToRender); - } + { + std::lock_guard lk(soundCriticalSection); + ao_play(device, (char*)realtimeBuffer, numBytesToRender); + } - soundSyncEvent.Wait(); - } + soundSyncEvent.Wait(); + } } bool AOSound::Start() { - m_run_thread.store(true); - memset(realtimeBuffer, 0, sizeof(realtimeBuffer)); + m_run_thread.store(true); + memset(realtimeBuffer, 0, sizeof(realtimeBuffer)); - thread = std::thread(&AOSound::SoundLoop, this); - return true; + thread = std::thread(&AOSound::SoundLoop, this); + return true; } void AOSound::Update() { - soundSyncEvent.Set(); + soundSyncEvent.Set(); } void AOSound::Stop() { - m_run_thread.store(false); - soundSyncEvent.Set(); + m_run_thread.store(false); + soundSyncEvent.Set(); - { - std::lock_guard lk(soundCriticalSection); - thread.join(); + { + std::lock_guard lk(soundCriticalSection); + thread.join(); - if (device) - ao_close(device); + if (device) + ao_close(device); - ao_shutdown(); + ao_shutdown(); - device = nullptr; - } + device = nullptr; + } } #endif diff --git a/Source/Core/AudioCommon/AOSoundStream.h b/Source/Core/AudioCommon/AOSoundStream.h index a37c3f9467..a62aafd35f 100644 --- a/Source/Core/AudioCommon/AOSoundStream.h +++ b/Source/Core/AudioCommon/AOSoundStream.h @@ -19,29 +19,25 @@ class AOSound final : public SoundStream { #if defined(HAVE_AO) && HAVE_AO - std::thread thread; - std::atomic m_run_thread; - std::mutex soundCriticalSection; - Common::Event soundSyncEvent; + std::thread thread; + std::atomic m_run_thread; + std::mutex soundCriticalSection; + Common::Event soundSyncEvent; - int buf_size; + int buf_size; - ao_device *device; - ao_sample_format format; - int default_driver; + ao_device* device; + ao_sample_format format; + int default_driver; - short realtimeBuffer[1024 * 1024]; + short realtimeBuffer[1024 * 1024]; public: - bool Start() override; - void SoundLoop() override; - void Stop() override; - void Update() override; - - static bool isValid() - { - return true; - } + bool Start() override; + void SoundLoop() override; + void Stop() override; + void Update() override; + static bool isValid() { return true; } #endif }; diff --git a/Source/Core/AudioCommon/AlsaSoundStream.cpp b/Source/Core/AudioCommon/AlsaSoundStream.cpp index 19a21acf66..3598958c75 100644 --- a/Source/Core/AudioCommon/AlsaSoundStream.cpp +++ b/Source/Core/AudioCommon/AlsaSoundStream.cpp @@ -6,230 +6,229 @@ #include "AudioCommon/AlsaSoundStream.h" #include "Common/CommonTypes.h" -#include "Common/Thread.h" #include "Common/Logging/Log.h" +#include "Common/Thread.h" AlsaSound::AlsaSound() - : m_thread_status(ALSAThreadStatus::STOPPED) - , handle(nullptr) - , frames_to_deliver(FRAME_COUNT_MIN) + : m_thread_status(ALSAThreadStatus::STOPPED), handle(nullptr), + frames_to_deliver(FRAME_COUNT_MIN) { } bool AlsaSound::Start() { - m_thread_status.store(ALSAThreadStatus::RUNNING); - if (!AlsaInit()) - { - m_thread_status.store(ALSAThreadStatus::STOPPED); - return false; - } + m_thread_status.store(ALSAThreadStatus::RUNNING); + if (!AlsaInit()) + { + m_thread_status.store(ALSAThreadStatus::STOPPED); + return false; + } - thread = std::thread(&AlsaSound::SoundLoop, this); - return true; + thread = std::thread(&AlsaSound::SoundLoop, this); + return true; } void AlsaSound::Stop() { - m_thread_status.store(ALSAThreadStatus::STOPPING); + m_thread_status.store(ALSAThreadStatus::STOPPING); - //Give the opportunity to the audio thread - //to realize we are stopping the emulation - cv.notify_one(); - thread.join(); + // Give the opportunity to the audio thread + // to realize we are stopping the emulation + cv.notify_one(); + thread.join(); } void AlsaSound::Update() { - // don't need to do anything here. + // don't need to do anything here. } // Called on audio thread. void AlsaSound::SoundLoop() { - Common::SetCurrentThreadName("Audio thread - alsa"); - while (m_thread_status.load() != ALSAThreadStatus::STOPPING) - { - while (m_thread_status.load() == ALSAThreadStatus::RUNNING) - { - m_mixer->Mix(mix_buffer, frames_to_deliver); - int rc = snd_pcm_writei(handle, mix_buffer, frames_to_deliver); - if (rc == -EPIPE) - { - // Underrun - snd_pcm_prepare(handle); - } - else if (rc < 0) - { - ERROR_LOG(AUDIO, "writei fail: %s", snd_strerror(rc)); - } - } - if (m_thread_status.load() == ALSAThreadStatus::PAUSED) - { - snd_pcm_drop(handle); // Stop sound output + Common::SetCurrentThreadName("Audio thread - alsa"); + while (m_thread_status.load() != ALSAThreadStatus::STOPPING) + { + while (m_thread_status.load() == ALSAThreadStatus::RUNNING) + { + m_mixer->Mix(mix_buffer, frames_to_deliver); + int rc = snd_pcm_writei(handle, mix_buffer, frames_to_deliver); + if (rc == -EPIPE) + { + // Underrun + snd_pcm_prepare(handle); + } + else if (rc < 0) + { + ERROR_LOG(AUDIO, "writei fail: %s", snd_strerror(rc)); + } + } + if (m_thread_status.load() == ALSAThreadStatus::PAUSED) + { + snd_pcm_drop(handle); // Stop sound output - // Block until thread status changes. - std::unique_lock lock(cv_m); - cv.wait(lock, [this]{ return m_thread_status.load() != ALSAThreadStatus::PAUSED; }); + // Block until thread status changes. + std::unique_lock lock(cv_m); + cv.wait(lock, [this] { return m_thread_status.load() != ALSAThreadStatus::PAUSED; }); - snd_pcm_prepare(handle); // resume sound output - } - } - AlsaShutdown(); - m_thread_status.store(ALSAThreadStatus::STOPPED); + snd_pcm_prepare(handle); // resume sound output + } + } + AlsaShutdown(); + m_thread_status.store(ALSAThreadStatus::STOPPED); } - void AlsaSound::Clear(bool muted) { - m_muted = muted; - m_thread_status.store(muted ? ALSAThreadStatus::PAUSED : ALSAThreadStatus::RUNNING); - cv.notify_one(); // Notify thread that status has changed + m_muted = muted; + m_thread_status.store(muted ? ALSAThreadStatus::PAUSED : ALSAThreadStatus::RUNNING); + cv.notify_one(); // Notify thread that status has changed } bool AlsaSound::AlsaInit() { - unsigned int sample_rate = m_mixer->GetSampleRate(); - int err; - int dir; - snd_pcm_sw_params_t *swparams; - snd_pcm_hw_params_t *hwparams; - snd_pcm_uframes_t buffer_size,buffer_size_max; - unsigned int periods; + unsigned int sample_rate = m_mixer->GetSampleRate(); + int err; + int dir; + snd_pcm_sw_params_t* swparams; + snd_pcm_hw_params_t* hwparams; + snd_pcm_uframes_t buffer_size, buffer_size_max; + unsigned int periods; - err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); - if (err < 0) - { - ERROR_LOG(AUDIO, "Audio open error: %s\n", snd_strerror(err)); - return false; - } + err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); + if (err < 0) + { + ERROR_LOG(AUDIO, "Audio open error: %s\n", snd_strerror(err)); + return false; + } - snd_pcm_hw_params_alloca(&hwparams); + snd_pcm_hw_params_alloca(&hwparams); - err = snd_pcm_hw_params_any(handle, hwparams); - if (err < 0) - { - ERROR_LOG(AUDIO, "Broken configuration for this PCM: %s\n", snd_strerror(err)); - return false; - } + err = snd_pcm_hw_params_any(handle, hwparams); + if (err < 0) + { + ERROR_LOG(AUDIO, "Broken configuration for this PCM: %s\n", snd_strerror(err)); + return false; + } - err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); - if (err < 0) - { - ERROR_LOG(AUDIO, "Access type not available: %s\n", snd_strerror(err)); - return false; - } + err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); + if (err < 0) + { + ERROR_LOG(AUDIO, "Access type not available: %s\n", snd_strerror(err)); + return false; + } - err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE); - if (err < 0) - { - ERROR_LOG(AUDIO, "Sample format not available: %s\n", snd_strerror(err)); - return false; - } + err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE); + if (err < 0) + { + ERROR_LOG(AUDIO, "Sample format not available: %s\n", snd_strerror(err)); + return false; + } - dir = 0; - err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &sample_rate, &dir); - if (err < 0) - { - ERROR_LOG(AUDIO, "Rate not available: %s\n", snd_strerror(err)); - return false; - } + dir = 0; + err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &sample_rate, &dir); + if (err < 0) + { + ERROR_LOG(AUDIO, "Rate not available: %s\n", snd_strerror(err)); + return false; + } - err = snd_pcm_hw_params_set_channels(handle, hwparams, CHANNEL_COUNT); - if (err < 0) - { - ERROR_LOG(AUDIO, "Channels count not available: %s\n", snd_strerror(err)); - return false; - } + err = snd_pcm_hw_params_set_channels(handle, hwparams, CHANNEL_COUNT); + if (err < 0) + { + ERROR_LOG(AUDIO, "Channels count not available: %s\n", snd_strerror(err)); + return false; + } - periods = BUFFER_SIZE_MAX / FRAME_COUNT_MIN; - err = snd_pcm_hw_params_set_periods_max(handle, hwparams, &periods, &dir); - if (err < 0) - { - ERROR_LOG(AUDIO, "Cannot set maximum periods per buffer: %s\n", snd_strerror(err)); - return false; - } + periods = BUFFER_SIZE_MAX / FRAME_COUNT_MIN; + err = snd_pcm_hw_params_set_periods_max(handle, hwparams, &periods, &dir); + if (err < 0) + { + ERROR_LOG(AUDIO, "Cannot set maximum periods per buffer: %s\n", snd_strerror(err)); + return false; + } - buffer_size_max = BUFFER_SIZE_MAX; - err = snd_pcm_hw_params_set_buffer_size_max(handle, hwparams, &buffer_size_max); - if (err < 0) - { - ERROR_LOG(AUDIO, "Cannot set maximum buffer size: %s\n", snd_strerror(err)); - return false; - } + buffer_size_max = BUFFER_SIZE_MAX; + err = snd_pcm_hw_params_set_buffer_size_max(handle, hwparams, &buffer_size_max); + if (err < 0) + { + ERROR_LOG(AUDIO, "Cannot set maximum buffer size: %s\n", snd_strerror(err)); + return false; + } - err = snd_pcm_hw_params(handle, hwparams); - if (err < 0) - { - ERROR_LOG(AUDIO, "Unable to install hw params: %s\n", snd_strerror(err)); - return false; - } + err = snd_pcm_hw_params(handle, hwparams); + if (err < 0) + { + ERROR_LOG(AUDIO, "Unable to install hw params: %s\n", snd_strerror(err)); + return false; + } - err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); - if (err < 0) - { - ERROR_LOG(AUDIO, "Cannot get buffer size: %s\n", snd_strerror(err)); - return false; - } + err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); + if (err < 0) + { + ERROR_LOG(AUDIO, "Cannot get buffer size: %s\n", snd_strerror(err)); + return false; + } - err = snd_pcm_hw_params_get_periods_max(hwparams, &periods, &dir); - if (err < 0) - { - ERROR_LOG(AUDIO, "Cannot get periods: %s\n", snd_strerror(err)); - return false; - } + err = snd_pcm_hw_params_get_periods_max(hwparams, &periods, &dir); + if (err < 0) + { + ERROR_LOG(AUDIO, "Cannot get periods: %s\n", snd_strerror(err)); + return false; + } - //periods is the number of fragments alsa can wait for during one - //buffer_size - frames_to_deliver = buffer_size / periods; - //limit the minimum size. pulseaudio advertises a minimum of 32 samples. - if (frames_to_deliver < FRAME_COUNT_MIN) - frames_to_deliver = FRAME_COUNT_MIN; - //it is probably a bad idea to try to send more than one buffer of data - if ((unsigned int)frames_to_deliver > buffer_size) - frames_to_deliver = buffer_size; - NOTICE_LOG(AUDIO, "ALSA gave us a %ld sample \"hardware\" buffer with %d periods. Will send %d samples per fragments.\n", buffer_size, periods, frames_to_deliver); + // periods is the number of fragments alsa can wait for during one + // buffer_size + frames_to_deliver = buffer_size / periods; + // limit the minimum size. pulseaudio advertises a minimum of 32 samples. + if (frames_to_deliver < FRAME_COUNT_MIN) + frames_to_deliver = FRAME_COUNT_MIN; + // it is probably a bad idea to try to send more than one buffer of data + if ((unsigned int)frames_to_deliver > buffer_size) + frames_to_deliver = buffer_size; + NOTICE_LOG(AUDIO, "ALSA gave us a %ld sample \"hardware\" buffer with %d periods. Will send %d " + "samples per fragments.\n", + buffer_size, periods, frames_to_deliver); - snd_pcm_sw_params_alloca(&swparams); + snd_pcm_sw_params_alloca(&swparams); - err = snd_pcm_sw_params_current(handle, swparams); - if (err < 0) - { - ERROR_LOG(AUDIO, "cannot init sw params: %s\n", snd_strerror(err)); - return false; - } + err = snd_pcm_sw_params_current(handle, swparams); + if (err < 0) + { + ERROR_LOG(AUDIO, "cannot init sw params: %s\n", snd_strerror(err)); + return false; + } - err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0U); - if (err < 0) - { - ERROR_LOG(AUDIO, "cannot set start thresh: %s\n", snd_strerror(err)); - return false; - } + err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0U); + if (err < 0) + { + ERROR_LOG(AUDIO, "cannot set start thresh: %s\n", snd_strerror(err)); + return false; + } - err = snd_pcm_sw_params(handle, swparams); - if (err < 0) - { - ERROR_LOG(AUDIO, "cannot set sw params: %s\n", snd_strerror(err)); - return false; - } + err = snd_pcm_sw_params(handle, swparams); + if (err < 0) + { + ERROR_LOG(AUDIO, "cannot set sw params: %s\n", snd_strerror(err)); + return false; + } - err = snd_pcm_prepare(handle); - if (err < 0) - { - ERROR_LOG(AUDIO, "Unable to prepare: %s\n", snd_strerror(err)); - return false; - } - NOTICE_LOG(AUDIO, "ALSA successfully initialized.\n"); - return true; + err = snd_pcm_prepare(handle); + if (err < 0) + { + ERROR_LOG(AUDIO, "Unable to prepare: %s\n", snd_strerror(err)); + return false; + } + NOTICE_LOG(AUDIO, "ALSA successfully initialized.\n"); + return true; } void AlsaSound::AlsaShutdown() { - if (handle != nullptr) - { - snd_pcm_drop(handle); - snd_pcm_close(handle); - handle = nullptr; - } + if (handle != nullptr) + { + snd_pcm_drop(handle); + snd_pcm_close(handle); + handle = nullptr; + } } - diff --git a/Source/Core/AudioCommon/AlsaSoundStream.h b/Source/Core/AudioCommon/AlsaSoundStream.h index 915316f279..162713f84a 100644 --- a/Source/Core/AudioCommon/AlsaSoundStream.h +++ b/Source/Core/AudioCommon/AlsaSoundStream.h @@ -20,47 +20,43 @@ class AlsaSound final : public SoundStream { #if defined(HAVE_ALSA) && HAVE_ALSA public: - AlsaSound(); + AlsaSound(); - bool Start() override; - void SoundLoop() override; - void Stop() override; - void Update() override; - void Clear(bool) override; - - static bool isValid() - { - return true; - } + bool Start() override; + void SoundLoop() override; + void Stop() override; + void Update() override; + void Clear(bool) override; + static bool isValid() { return true; } private: - // maximum number of frames the buffer can hold - static constexpr size_t BUFFER_SIZE_MAX = 8192; + // maximum number of frames the buffer can hold + static constexpr size_t BUFFER_SIZE_MAX = 8192; - // minimum number of frames to deliver in one transfer - static constexpr u32 FRAME_COUNT_MIN = 256; + // minimum number of frames to deliver in one transfer + static constexpr u32 FRAME_COUNT_MIN = 256; - // number of channels per frame - static constexpr u32 CHANNEL_COUNT = 2; + // number of channels per frame + static constexpr u32 CHANNEL_COUNT = 2; - enum class ALSAThreadStatus - { - RUNNING, - PAUSED, - STOPPING, - STOPPED, - }; + enum class ALSAThreadStatus + { + RUNNING, + PAUSED, + STOPPING, + STOPPED, + }; - bool AlsaInit(); - void AlsaShutdown(); + bool AlsaInit(); + void AlsaShutdown(); - s16 mix_buffer[BUFFER_SIZE_MAX * CHANNEL_COUNT]; - std::thread thread; - std::atomic m_thread_status; - std::condition_variable cv; - std::mutex cv_m; + s16 mix_buffer[BUFFER_SIZE_MAX * CHANNEL_COUNT]; + std::thread thread; + std::atomic m_thread_status; + std::condition_variable cv; + std::mutex cv_m; - snd_pcm_t *handle; - unsigned int frames_to_deliver; + snd_pcm_t* handle; + unsigned int frames_to_deliver; #endif }; diff --git a/Source/Core/AudioCommon/AudioCommon.cpp b/Source/Core/AudioCommon/AudioCommon.cpp index 3dde3bf54f..ca67a3b5ff 100644 --- a/Source/Core/AudioCommon/AudioCommon.cpp +++ b/Source/Core/AudioCommon/AudioCommon.cpp @@ -2,22 +2,21 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - -#include "AudioCommon/AlsaSoundStream.h" -#include "AudioCommon/AOSoundStream.h" #include "AudioCommon/AudioCommon.h" +#include "AudioCommon/AOSoundStream.h" +#include "AudioCommon/AlsaSoundStream.h" #include "AudioCommon/CoreAudioSoundStream.h" #include "AudioCommon/Mixer.h" #include "AudioCommon/NullSoundStream.h" #include "AudioCommon/OpenALStream.h" #include "AudioCommon/OpenSLESStream.h" #include "AudioCommon/PulseAudioStream.h" -#include "AudioCommon/XAudio2_7Stream.h" #include "AudioCommon/XAudio2Stream.h" +#include "AudioCommon/XAudio2_7Stream.h" #include "Common/Common.h" #include "Common/FileUtil.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "Core/ConfigManager.h" #include "Core/Movie.h" @@ -28,182 +27,182 @@ static bool s_audio_dump_start = false; namespace AudioCommon { - static const int AUDIO_VOLUME_MIN = 0; - static const int AUDIO_VOLUME_MAX = 100; +static const int AUDIO_VOLUME_MIN = 0; +static const int AUDIO_VOLUME_MAX = 100; - SoundStream* InitSoundStream() - { - std::string backend = SConfig::GetInstance().sBackend; - if (backend == BACKEND_OPENAL && OpenALStream::isValid()) - g_sound_stream = new OpenALStream(); - else if (backend == BACKEND_NULLSOUND && NullSound::isValid()) - g_sound_stream = new NullSound(); - else if (backend == BACKEND_XAUDIO2) - { - if (XAudio2::isValid()) - g_sound_stream = new XAudio2(); - else if (XAudio2_7::isValid()) - g_sound_stream = new XAudio2_7(); - } - else if (backend == BACKEND_AOSOUND && AOSound::isValid()) - g_sound_stream = new AOSound(); - else if (backend == BACKEND_ALSA && AlsaSound::isValid()) - g_sound_stream = new AlsaSound(); - else if (backend == BACKEND_COREAUDIO && CoreAudioSound::isValid()) - g_sound_stream = new CoreAudioSound(); - else if (backend == BACKEND_PULSEAUDIO && PulseAudio::isValid()) - g_sound_stream = new PulseAudio(); - else if (backend == BACKEND_OPENSLES && OpenSLESStream::isValid()) - g_sound_stream = new OpenSLESStream(); +SoundStream* InitSoundStream() +{ + std::string backend = SConfig::GetInstance().sBackend; + if (backend == BACKEND_OPENAL && OpenALStream::isValid()) + g_sound_stream = new OpenALStream(); + else if (backend == BACKEND_NULLSOUND && NullSound::isValid()) + g_sound_stream = new NullSound(); + else if (backend == BACKEND_XAUDIO2) + { + if (XAudio2::isValid()) + g_sound_stream = new XAudio2(); + else if (XAudio2_7::isValid()) + g_sound_stream = new XAudio2_7(); + } + else if (backend == BACKEND_AOSOUND && AOSound::isValid()) + g_sound_stream = new AOSound(); + else if (backend == BACKEND_ALSA && AlsaSound::isValid()) + g_sound_stream = new AlsaSound(); + else if (backend == BACKEND_COREAUDIO && CoreAudioSound::isValid()) + g_sound_stream = new CoreAudioSound(); + else if (backend == BACKEND_PULSEAUDIO && PulseAudio::isValid()) + g_sound_stream = new PulseAudio(); + else if (backend == BACKEND_OPENSLES && OpenSLESStream::isValid()) + g_sound_stream = new OpenSLESStream(); - if (!g_sound_stream && NullSound::isValid()) - { - WARN_LOG(AUDIO, "Could not initialize backend %s, using %s instead.", - backend.c_str(), BACKEND_NULLSOUND); - g_sound_stream = new NullSound(); - } + if (!g_sound_stream && NullSound::isValid()) + { + WARN_LOG(AUDIO, "Could not initialize backend %s, using %s instead.", backend.c_str(), + BACKEND_NULLSOUND); + g_sound_stream = new NullSound(); + } - if (g_sound_stream) - { - UpdateSoundStream(); - if (!g_sound_stream->Start()) - { - ERROR_LOG(AUDIO, "Could not start backend %s, using %s instead", - backend.c_str(), BACKEND_NULLSOUND); - delete g_sound_stream; - g_sound_stream = new NullSound(); - g_sound_stream->Start(); - } + if (g_sound_stream) + { + UpdateSoundStream(); + if (!g_sound_stream->Start()) + { + ERROR_LOG(AUDIO, "Could not start backend %s, using %s instead", backend.c_str(), + BACKEND_NULLSOUND); + delete g_sound_stream; + g_sound_stream = new NullSound(); + g_sound_stream->Start(); + } - if (SConfig::GetInstance().m_DumpAudio && !s_audio_dump_start) - StartAudioDump(); + if (SConfig::GetInstance().m_DumpAudio && !s_audio_dump_start) + StartAudioDump(); - return g_sound_stream; - } + return g_sound_stream; + } - PanicAlertT("Sound backend %s is not valid.", backend.c_str()); + PanicAlertT("Sound backend %s is not valid.", backend.c_str()); - delete g_sound_stream; - g_sound_stream = nullptr; - return nullptr; - } - - void ShutdownSoundStream() - { - INFO_LOG(AUDIO, "Shutting down sound stream"); - - if (g_sound_stream) - { - g_sound_stream->Stop(); - if (SConfig::GetInstance().m_DumpAudio && s_audio_dump_start) - StopAudioDump(); - delete g_sound_stream; - g_sound_stream = nullptr; - } - - INFO_LOG(AUDIO, "Done shutting down sound stream"); - } - - std::vector GetSoundBackends() - { - std::vector backends; - - if (NullSound::isValid()) - backends.push_back(BACKEND_NULLSOUND); - if (XAudio2_7::isValid() || XAudio2::isValid()) - backends.push_back(BACKEND_XAUDIO2); - if (AOSound::isValid()) - backends.push_back(BACKEND_AOSOUND); - if (AlsaSound::isValid()) - backends.push_back(BACKEND_ALSA); - if (CoreAudioSound::isValid()) - backends.push_back(BACKEND_COREAUDIO); - if (PulseAudio::isValid()) - backends.push_back(BACKEND_PULSEAUDIO); - if (OpenALStream::isValid()) - backends.push_back(BACKEND_OPENAL); - if (OpenSLESStream::isValid()) - backends.push_back(BACKEND_OPENSLES); - return backends; - } - - void UpdateSoundStream() - { - if (g_sound_stream) - { - int volume = SConfig::GetInstance().m_IsMuted ? 0 : SConfig::GetInstance().m_Volume; - g_sound_stream->SetVolume(volume); - } - } - - void ClearAudioBuffer(bool mute) - { - if (g_sound_stream) - g_sound_stream->Clear(mute); - } - - void SendAIBuffer(short *samples, unsigned int num_samples) - { - if (!g_sound_stream) - return; - - if (SConfig::GetInstance().m_DumpAudio && !s_audio_dump_start) - StartAudioDump(); - else if (!SConfig::GetInstance().m_DumpAudio && s_audio_dump_start) - StopAudioDump(); - - CMixer* pMixer = g_sound_stream->GetMixer(); - - if (pMixer && samples) - { - pMixer->PushSamples(samples, num_samples); - } - - g_sound_stream->Update(); - } - - void StartAudioDump() - { - std::string audio_file_name_dtk = File::GetUserPath(D_DUMPAUDIO_IDX) + "dtkdump.wav"; - std::string audio_file_name_dsp = File::GetUserPath(D_DUMPAUDIO_IDX) + "dspdump.wav"; - File::CreateFullPath(audio_file_name_dtk); - File::CreateFullPath(audio_file_name_dsp); - g_sound_stream->GetMixer()->StartLogDTKAudio(audio_file_name_dtk); - g_sound_stream->GetMixer()->StartLogDSPAudio(audio_file_name_dsp); - s_audio_dump_start = true; - } - - void StopAudioDump() - { - g_sound_stream->GetMixer()->StopLogDTKAudio(); - g_sound_stream->GetMixer()->StopLogDSPAudio(); - s_audio_dump_start = false; - } - - void IncreaseVolume(unsigned short offset) - { - SConfig::GetInstance().m_IsMuted = false; - int& currentVolume = SConfig::GetInstance().m_Volume; - currentVolume += offset; - if (currentVolume > AUDIO_VOLUME_MAX) - currentVolume = AUDIO_VOLUME_MAX; - UpdateSoundStream(); - } - - void DecreaseVolume(unsigned short offset) - { - SConfig::GetInstance().m_IsMuted = false; - int& currentVolume = SConfig::GetInstance().m_Volume; - currentVolume -= offset; - if (currentVolume < AUDIO_VOLUME_MIN) - currentVolume = AUDIO_VOLUME_MIN; - UpdateSoundStream(); - } - - void ToggleMuteVolume() - { - bool& isMuted = SConfig::GetInstance().m_IsMuted; - isMuted = !isMuted; - UpdateSoundStream(); - } + delete g_sound_stream; + g_sound_stream = nullptr; + return nullptr; +} + +void ShutdownSoundStream() +{ + INFO_LOG(AUDIO, "Shutting down sound stream"); + + if (g_sound_stream) + { + g_sound_stream->Stop(); + if (SConfig::GetInstance().m_DumpAudio && s_audio_dump_start) + StopAudioDump(); + delete g_sound_stream; + g_sound_stream = nullptr; + } + + INFO_LOG(AUDIO, "Done shutting down sound stream"); +} + +std::vector GetSoundBackends() +{ + std::vector backends; + + if (NullSound::isValid()) + backends.push_back(BACKEND_NULLSOUND); + if (XAudio2_7::isValid() || XAudio2::isValid()) + backends.push_back(BACKEND_XAUDIO2); + if (AOSound::isValid()) + backends.push_back(BACKEND_AOSOUND); + if (AlsaSound::isValid()) + backends.push_back(BACKEND_ALSA); + if (CoreAudioSound::isValid()) + backends.push_back(BACKEND_COREAUDIO); + if (PulseAudio::isValid()) + backends.push_back(BACKEND_PULSEAUDIO); + if (OpenALStream::isValid()) + backends.push_back(BACKEND_OPENAL); + if (OpenSLESStream::isValid()) + backends.push_back(BACKEND_OPENSLES); + return backends; +} + +void UpdateSoundStream() +{ + if (g_sound_stream) + { + int volume = SConfig::GetInstance().m_IsMuted ? 0 : SConfig::GetInstance().m_Volume; + g_sound_stream->SetVolume(volume); + } +} + +void ClearAudioBuffer(bool mute) +{ + if (g_sound_stream) + g_sound_stream->Clear(mute); +} + +void SendAIBuffer(short* samples, unsigned int num_samples) +{ + if (!g_sound_stream) + return; + + if (SConfig::GetInstance().m_DumpAudio && !s_audio_dump_start) + StartAudioDump(); + else if (!SConfig::GetInstance().m_DumpAudio && s_audio_dump_start) + StopAudioDump(); + + CMixer* pMixer = g_sound_stream->GetMixer(); + + if (pMixer && samples) + { + pMixer->PushSamples(samples, num_samples); + } + + g_sound_stream->Update(); +} + +void StartAudioDump() +{ + std::string audio_file_name_dtk = File::GetUserPath(D_DUMPAUDIO_IDX) + "dtkdump.wav"; + std::string audio_file_name_dsp = File::GetUserPath(D_DUMPAUDIO_IDX) + "dspdump.wav"; + File::CreateFullPath(audio_file_name_dtk); + File::CreateFullPath(audio_file_name_dsp); + g_sound_stream->GetMixer()->StartLogDTKAudio(audio_file_name_dtk); + g_sound_stream->GetMixer()->StartLogDSPAudio(audio_file_name_dsp); + s_audio_dump_start = true; +} + +void StopAudioDump() +{ + g_sound_stream->GetMixer()->StopLogDTKAudio(); + g_sound_stream->GetMixer()->StopLogDSPAudio(); + s_audio_dump_start = false; +} + +void IncreaseVolume(unsigned short offset) +{ + SConfig::GetInstance().m_IsMuted = false; + int& currentVolume = SConfig::GetInstance().m_Volume; + currentVolume += offset; + if (currentVolume > AUDIO_VOLUME_MAX) + currentVolume = AUDIO_VOLUME_MAX; + UpdateSoundStream(); +} + +void DecreaseVolume(unsigned short offset) +{ + SConfig::GetInstance().m_IsMuted = false; + int& currentVolume = SConfig::GetInstance().m_Volume; + currentVolume -= offset; + if (currentVolume < AUDIO_VOLUME_MIN) + currentVolume = AUDIO_VOLUME_MIN; + UpdateSoundStream(); +} + +void ToggleMuteVolume() +{ + bool& isMuted = SConfig::GetInstance().m_IsMuted; + isMuted = !isMuted; + UpdateSoundStream(); +} } diff --git a/Source/Core/AudioCommon/AudioCommon.h b/Source/Core/AudioCommon/AudioCommon.h index b404e20731..e6a725ef71 100644 --- a/Source/Core/AudioCommon/AudioCommon.h +++ b/Source/Core/AudioCommon/AudioCommon.h @@ -7,22 +7,21 @@ #include "AudioCommon/SoundStream.h" #include "Common/CommonTypes.h" - class CMixer; -extern SoundStream *g_sound_stream; +extern SoundStream* g_sound_stream; namespace AudioCommon { - SoundStream* InitSoundStream(); - void ShutdownSoundStream(); - std::vector GetSoundBackends(); - void UpdateSoundStream(); - void ClearAudioBuffer(bool mute); - void SendAIBuffer(short* samples, unsigned int num_samples); - void StartAudioDump(); - void StopAudioDump(); - void IncreaseVolume(unsigned short offset); - void DecreaseVolume(unsigned short offset); - void ToggleMuteVolume(); +SoundStream* InitSoundStream(); +void ShutdownSoundStream(); +std::vector GetSoundBackends(); +void UpdateSoundStream(); +void ClearAudioBuffer(bool mute); +void SendAIBuffer(short* samples, unsigned int num_samples); +void StartAudioDump(); +void StopAudioDump(); +void IncreaseVolume(unsigned short offset); +void DecreaseVolume(unsigned short offset); +void ToggleMuteVolume(); } diff --git a/Source/Core/AudioCommon/CoreAudioSoundStream.cpp b/Source/Core/AudioCommon/CoreAudioSoundStream.cpp index 38f11fb766..54ba660129 100644 --- a/Source/Core/AudioCommon/CoreAudioSoundStream.cpp +++ b/Source/Core/AudioCommon/CoreAudioSoundStream.cpp @@ -7,105 +7,94 @@ #include "AudioCommon/CoreAudioSoundStream.h" #include "Common/Logging/Log.h" -OSStatus CoreAudioSound::callback(void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, - UInt32 inNumberFrames, AudioBufferList *ioData) +OSStatus CoreAudioSound::callback(void* inRefCon, AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, + UInt32 inNumberFrames, AudioBufferList* ioData) { - for (UInt32 i = 0; i < ioData->mNumberBuffers; i++) - ((CoreAudioSound *)inRefCon)->m_mixer-> - Mix((short *)ioData->mBuffers[i].mData, - ioData->mBuffers[i].mDataByteSize / 4); + for (UInt32 i = 0; i < ioData->mNumberBuffers; i++) + ((CoreAudioSound*)inRefCon) + ->m_mixer->Mix((short*)ioData->mBuffers[i].mData, ioData->mBuffers[i].mDataByteSize / 4); - return noErr; + return noErr; } bool CoreAudioSound::Start() { - OSStatus err; - AURenderCallbackStruct callback_struct; - AudioStreamBasicDescription format; - AudioComponentDescription desc; - AudioComponent component; + OSStatus err; + AURenderCallbackStruct callback_struct; + AudioStreamBasicDescription format; + AudioComponentDescription desc; + AudioComponent component; - desc.componentType = kAudioUnitType_Output; - desc.componentSubType = kAudioUnitSubType_DefaultOutput; - desc.componentFlags = 0; - desc.componentFlagsMask = 0; - desc.componentManufacturer = kAudioUnitManufacturer_Apple; - component = AudioComponentFindNext(nullptr, &desc); - if (component == nullptr) - { - ERROR_LOG(AUDIO, "error finding audio component"); - return false; - } + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_DefaultOutput; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + component = AudioComponentFindNext(nullptr, &desc); + if (component == nullptr) + { + ERROR_LOG(AUDIO, "error finding audio component"); + return false; + } - err = AudioComponentInstanceNew(component, &audioUnit); - if (err != noErr) - { - ERROR_LOG(AUDIO, "error opening audio component"); - return false; - } + err = AudioComponentInstanceNew(component, &audioUnit); + if (err != noErr) + { + ERROR_LOG(AUDIO, "error opening audio component"); + return false; + } - FillOutASBDForLPCM(format, m_mixer->GetSampleRate(), - 2, 16, 16, false, false, false); - err = AudioUnitSetProperty(audioUnit, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 0, &format, - sizeof(AudioStreamBasicDescription)); - if (err != noErr) - { - ERROR_LOG(AUDIO, "error setting audio format"); - return false; - } + FillOutASBDForLPCM(format, m_mixer->GetSampleRate(), 2, 16, 16, false, false, false); + err = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, + &format, sizeof(AudioStreamBasicDescription)); + if (err != noErr) + { + ERROR_LOG(AUDIO, "error setting audio format"); + return false; + } - callback_struct.inputProc = callback; - callback_struct.inputProcRefCon = this; - err = AudioUnitSetProperty(audioUnit, - kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, 0, &callback_struct, - sizeof callback_struct); - if (err != noErr) - { - ERROR_LOG(AUDIO, "error setting audio callback"); - return false; - } + callback_struct.inputProc = callback; + callback_struct.inputProcRefCon = this; + err = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, + 0, &callback_struct, sizeof callback_struct); + if (err != noErr) + { + ERROR_LOG(AUDIO, "error setting audio callback"); + return false; + } - err = AudioUnitSetParameter(audioUnit, - kHALOutputParam_Volume, - kAudioUnitScope_Output, 0, - m_volume / 100., 0); - if (err != noErr) - ERROR_LOG(AUDIO, "error setting volume"); + err = AudioUnitSetParameter(audioUnit, kHALOutputParam_Volume, kAudioUnitScope_Output, 0, + m_volume / 100., 0); + if (err != noErr) + ERROR_LOG(AUDIO, "error setting volume"); - err = AudioUnitInitialize(audioUnit); - if (err != noErr) - { - ERROR_LOG(AUDIO, "error initializing audiounit"); - return false; - } + err = AudioUnitInitialize(audioUnit); + if (err != noErr) + { + ERROR_LOG(AUDIO, "error initializing audiounit"); + return false; + } - err = AudioOutputUnitStart(audioUnit); - if (err != noErr) - { - ERROR_LOG(AUDIO, "error starting audiounit"); - return false; - } + err = AudioOutputUnitStart(audioUnit); + if (err != noErr) + { + ERROR_LOG(AUDIO, "error starting audiounit"); + return false; + } - return true; + return true; } void CoreAudioSound::SetVolume(int volume) { - OSStatus err; - m_volume = volume; + OSStatus err; + m_volume = volume; - err = AudioUnitSetParameter(audioUnit, - kHALOutputParam_Volume, - kAudioUnitScope_Output, 0, - volume / 100., 0); - if (err != noErr) - ERROR_LOG(AUDIO, "error setting volume"); + err = AudioUnitSetParameter(audioUnit, kHALOutputParam_Volume, kAudioUnitScope_Output, 0, + volume / 100., 0); + if (err != noErr) + ERROR_LOG(AUDIO, "error setting volume"); } void CoreAudioSound::SoundLoop() @@ -114,19 +103,19 @@ void CoreAudioSound::SoundLoop() void CoreAudioSound::Stop() { - OSStatus err; + OSStatus err; - err = AudioOutputUnitStop(audioUnit); - if (err != noErr) - ERROR_LOG(AUDIO, "error stopping audiounit"); + err = AudioOutputUnitStop(audioUnit); + if (err != noErr) + ERROR_LOG(AUDIO, "error stopping audiounit"); - err = AudioUnitUninitialize(audioUnit); - if (err != noErr) - ERROR_LOG(AUDIO, "error uninitializing audiounit"); + err = AudioUnitUninitialize(audioUnit); + if (err != noErr) + ERROR_LOG(AUDIO, "error uninitializing audiounit"); - err = AudioComponentInstanceDispose(audioUnit); - if (err != noErr) - ERROR_LOG(AUDIO, "error closing audio component"); + err = AudioComponentInstanceDispose(audioUnit); + if (err != noErr) + ERROR_LOG(AUDIO, "error closing audio component"); } void CoreAudioSound::Update() diff --git a/Source/Core/AudioCommon/CoreAudioSoundStream.h b/Source/Core/AudioCommon/CoreAudioSoundStream.h index 083fbb6e37..8e4f35a8e9 100644 --- a/Source/Core/AudioCommon/CoreAudioSoundStream.h +++ b/Source/Core/AudioCommon/CoreAudioSoundStream.h @@ -14,25 +14,19 @@ class CoreAudioSound final : public SoundStream { #ifdef __APPLE__ public: - bool Start() override; - void SetVolume(int volume) override; - void SoundLoop() override; - void Stop() override; - void Update() override; - - static bool isValid() - { - return true; - } + bool Start() override; + void SetVolume(int volume) override; + void SoundLoop() override; + void Stop() override; + void Update() override; + static bool isValid() { return true; } private: - AudioUnit audioUnit; - int m_volume; + AudioUnit audioUnit; + int m_volume; - static OSStatus callback(void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData); + static OSStatus callback(void* inRefCon, AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, + UInt32 inNumberFrames, AudioBufferList* ioData); #endif }; diff --git a/Source/Core/AudioCommon/DPL2Decoder.cpp b/Source/Core/AudioCommon/DPL2Decoder.cpp index 036f0e96c8..fa483249e6 100644 --- a/Source/Core/AudioCommon/DPL2Decoder.cpp +++ b/Source/Core/AudioCommon/DPL2Decoder.cpp @@ -35,54 +35,56 @@ static float adapt_l_gain, adapt_r_gain, adapt_lpr_gain, adapt_lmr_gain; static std::vector lf, rf, lr, rr, cf, cr; static float LFE_buf[256]; static unsigned int lfe_pos; -static float *filter_coefs_lfe; +static float* filter_coefs_lfe; static unsigned int len125; -template -static _ftype_t DotProduct(int count, const T *buf, const _ftype_t *coefficients) +template +static _ftype_t DotProduct(int count, const T* buf, const _ftype_t* coefficients) { - int i; - float sum0 = 0.0f, sum1 = 0.0f, sum2 = 0.0f, sum3 = 0.0f; + int i; + float sum0 = 0.0f, sum1 = 0.0f, sum2 = 0.0f, sum3 = 0.0f; - // Unrolled loop - for (i = 0; (i + 3) < count; i += 4) - { - sum0 += buf[i + 0] * coefficients[i + 0]; - sum1 += buf[i + 1] * coefficients[i + 1]; - sum2 += buf[i + 2] * coefficients[i + 2]; - sum3 += buf[i + 3] * coefficients[i + 3]; - } + // Unrolled loop + for (i = 0; (i + 3) < count; i += 4) + { + sum0 += buf[i + 0] * coefficients[i + 0]; + sum1 += buf[i + 1] * coefficients[i + 1]; + sum2 += buf[i + 2] * coefficients[i + 2]; + sum3 += buf[i + 3] * coefficients[i + 3]; + } - // Epilogue of unrolled loop - for (; i < count; i++) - sum0 += buf[i] * coefficients[i]; + // Epilogue of unrolled loop + for (; i < count; i++) + sum0 += buf[i] * coefficients[i]; - return sum0 + sum1 + sum2 + sum3; + return sum0 + sum1 + sum2 + sum3; } -template -static T FIRFilter(const T *buf, int pos, int len, int count, const float *coefficients) +template +static T FIRFilter(const T* buf, int pos, int len, int count, const float* coefficients) { - int count1, count2; + int count1, count2; - if (pos >= count) - { - pos -= count; - count1 = count; count2 = 0; - } - else - { - count2 = pos; - count1 = count - pos; - pos = len - count1; - } + if (pos >= count) + { + pos -= count; + count1 = count; + count2 = 0; + } + else + { + count2 = pos; + count1 = count - pos; + pos = len - count1; + } - // high part of window - const T *ptr = &buf[pos]; + // high part of window + const T* ptr = &buf[pos]; - float r1 = DotProduct(count1, ptr, coefficients); coefficients += count1; - float r2 = DotProduct(count2, buf, coefficients); - return T(r1 + r2); + float r1 = DotProduct(count1, ptr, coefficients); + coefficients += count1; + float r2 = DotProduct(count2, buf, coefficients); + return T(r1 + r2); } /* @@ -96,11 +98,11 @@ static T FIRFilter(const T *buf, int pos, int len, int count, const float *coeff */ static void Hamming(int n, float* w) { - float k = float(2*M_PI/((float)(n - 1))); // 2*pi/(N-1) + float k = float(2 * M_PI / ((float)(n - 1))); // 2*pi/(N-1) - // Calculate window coefficients - for (int i = 0; i < n; i++) - *w++ = float(0.54 - 0.46*cos(k*(float)i)); + // Calculate window coefficients + for (int i = 0; i < n; i++) + *w++ = float(0.54 - 0.46 * cos(k * (float)i)); } /****************************************************************************** @@ -120,276 +122,270 @@ opt beta constant used only when designing using kaiser windows returns 0 if OK, -1 if fail */ -static float* DesignFIR(unsigned int *n, float* fc, float opt) +static float* DesignFIR(unsigned int* n, float* fc, float opt) { - unsigned int o = *n & 1; // Indicator for odd filter length - unsigned int end = ((*n + 1) >> 1) - o; // Loop end + unsigned int o = *n & 1; // Indicator for odd filter length + unsigned int end = ((*n + 1) >> 1) - o; // Loop end - float k1 = 2 * float(M_PI); // 2*pi*fc1 - float k2 = 0.5f * (float)(1 - o); // Constant used if the filter has even length - float g = 0.0f; // Gain - float t1; // Temporary variables - float fc1; // Cutoff frequencies + float k1 = 2 * float(M_PI); // 2*pi*fc1 + float k2 = 0.5f * (float)(1 - o); // Constant used if the filter has even length + float g = 0.0f; // Gain + float t1; // Temporary variables + float fc1; // Cutoff frequencies - // Sanity check - if (*n == 0) - return nullptr; + // Sanity check + if (*n == 0) + return nullptr; - fc[0] = MathUtil::Clamp(fc[0], 0.001f, 1.0f); + fc[0] = MathUtil::Clamp(fc[0], 0.001f, 1.0f); - float *w = (float*)calloc(sizeof(float), *n); + float* w = (float*)calloc(sizeof(float), *n); - // Get window coefficients - Hamming(*n, w); + // Get window coefficients + Hamming(*n, w); - fc1 = *fc; - // Cutoff frequency must be < 0.5 where 0.5 <=> Fs/2 - fc1 = ((fc1 <= 1.0) && (fc1 > 0.0)) ? fc1 / 2 : 0.25f; - k1 *= fc1; + fc1 = *fc; + // Cutoff frequency must be < 0.5 where 0.5 <=> Fs/2 + fc1 = ((fc1 <= 1.0) && (fc1 > 0.0)) ? fc1 / 2 : 0.25f; + k1 *= fc1; - // Low pass filter + // Low pass filter - // If the filter length is odd, there is one point which is exactly - // in the middle. The value at this point is 2*fCutoff*sin(x)/x, - // where x is zero. To make sure nothing strange happens, we set this - // value separately. - if (o) - { - w[end] = fc1 * w[end] * 2.0f; - g = w[end]; - } + // If the filter length is odd, there is one point which is exactly + // in the middle. The value at this point is 2*fCutoff*sin(x)/x, + // where x is zero. To make sure nothing strange happens, we set this + // value separately. + if (o) + { + w[end] = fc1 * w[end] * 2.0f; + g = w[end]; + } - // Create filter - for (u32 i = 0; i < end; i++) - { - t1 = (float)(i + 1) - k2; - w[end - i - 1] = w[*n - end + i] = float(w[end - i - 1] * sin(k1 * t1)/(M_PI * t1)); // Sinc - g += 2*w[end - i - 1]; // Total gain in filter - } + // Create filter + for (u32 i = 0; i < end; i++) + { + t1 = (float)(i + 1) - k2; + w[end - i - 1] = w[*n - end + i] = float(w[end - i - 1] * sin(k1 * t1) / (M_PI * t1)); // Sinc + g += 2 * w[end - i - 1]; // Total gain in filter + } + // Normalize gain + g = 1 / g; + for (u32 i = 0; i < *n; i++) + w[i] *= g; - // Normalize gain - g = 1/g; - for (u32 i = 0; i < *n; i++) - w[i] *= g; - - return w; + return w; } static void OnSeek() { - l_fwr = r_fwr = lpr_fwr = lmr_fwr = 0; - std::fill(fwrbuf_l.begin(), fwrbuf_l.end(), 0.0f); - std::fill(fwrbuf_r.begin(), fwrbuf_r.end(), 0.0f); - adapt_l_gain = adapt_r_gain = adapt_lpr_gain = adapt_lmr_gain = 0; - std::fill(lf.begin(), lf.end(), 0.0f); - std::fill(rf.begin(), rf.end(), 0.0f); - std::fill(lr.begin(), lr.end(), 0.0f); - std::fill(rr.begin(), rr.end(), 0.0f); - std::fill(cf.begin(), cf.end(), 0.0f); - std::fill(cr.begin(), cr.end(), 0.0f); - lfe_pos = 0; - memset(LFE_buf, 0, sizeof(LFE_buf)); + l_fwr = r_fwr = lpr_fwr = lmr_fwr = 0; + std::fill(fwrbuf_l.begin(), fwrbuf_l.end(), 0.0f); + std::fill(fwrbuf_r.begin(), fwrbuf_r.end(), 0.0f); + adapt_l_gain = adapt_r_gain = adapt_lpr_gain = adapt_lmr_gain = 0; + std::fill(lf.begin(), lf.end(), 0.0f); + std::fill(rf.begin(), rf.end(), 0.0f); + std::fill(lr.begin(), lr.end(), 0.0f); + std::fill(rr.begin(), rr.end(), 0.0f); + std::fill(cf.begin(), cf.end(), 0.0f); + std::fill(cr.begin(), cr.end(), 0.0f); + lfe_pos = 0; + memset(LFE_buf, 0, sizeof(LFE_buf)); } static void Done() { - OnSeek(); + OnSeek(); - if (filter_coefs_lfe) - { - free(filter_coefs_lfe); - } + if (filter_coefs_lfe) + { + free(filter_coefs_lfe); + } - filter_coefs_lfe = nullptr; + filter_coefs_lfe = nullptr; } static float* CalculateCoefficients125HzLowpass(int rate) { - len125 = 256; - float f = 125.0f / (rate / 2); - float *coeffs = DesignFIR(&len125, &f, 0); - static const float M3_01DB = 0.7071067812f; - for (unsigned int i = 0; i < len125; i++) - { - coeffs[i] *= M3_01DB; - } - return coeffs; + len125 = 256; + float f = 125.0f / (rate / 2); + float* coeffs = DesignFIR(&len125, &f, 0); + static const float M3_01DB = 0.7071067812f; + for (unsigned int i = 0; i < len125; i++) + { + coeffs[i] *= M3_01DB; + } + return coeffs; } static float PassiveLock(float x) { - static const float MATAGCLOCK = 0.2f; /* AGC range (around 1) where the matrix behaves passively */ - const float x1 = x - 1; - const float ax1s = fabs(x - 1) * (1.0f / MATAGCLOCK); - return x1 - x1 / (1 + ax1s * ax1s) + 1; + static const float MATAGCLOCK = + 0.2f; /* AGC range (around 1) where the matrix behaves passively */ + const float x1 = x - 1; + const float ax1s = fabs(x - 1) * (1.0f / MATAGCLOCK); + return x1 - x1 / (1 + ax1s * ax1s) + 1; } -static void MatrixDecode(const float *in, const int k, const int il, - const int ir, bool decode_rear, - const int _dlbuflen, - float _l_fwr, float _r_fwr, - float _lpr_fwr, float _lmr_fwr, - float *_adapt_l_gain, float *_adapt_r_gain, - float *_adapt_lpr_gain, float *_adapt_lmr_gain, - float *_lf, float *_rf, float *_lr, - float *_rr, float *_cf) +static void MatrixDecode(const float* in, const int k, const int il, const int ir, bool decode_rear, + const int _dlbuflen, float _l_fwr, float _r_fwr, float _lpr_fwr, + float _lmr_fwr, float* _adapt_l_gain, float* _adapt_r_gain, + float* _adapt_lpr_gain, float* _adapt_lmr_gain, float* _lf, float* _rf, + float* _lr, float* _rr, float* _cf) { - static const float M9_03DB = 0.3535533906f; - static const float MATAGCTRIG = 8.0f; /* (Fuzzy) AGC trigger */ - static const float MATAGCDECAY = 1.0f; /* AGC baseline decay rate (1/samp.) */ - static const float MATCOMPGAIN = 0.37f; /* Cross talk compensation gain, 0.50 - 0.55 is full cancellation. */ + static const float M9_03DB = 0.3535533906f; + static const float MATAGCTRIG = 8.0f; /* (Fuzzy) AGC trigger */ + static const float MATAGCDECAY = 1.0f; /* AGC baseline decay rate (1/samp.) */ + static const float MATCOMPGAIN = + 0.37f; /* Cross talk compensation gain, 0.50 - 0.55 is full cancellation. */ - const int kr = (k + olddelay) % _dlbuflen; - float l_gain = (_l_fwr + _r_fwr) / (1 + _l_fwr + _l_fwr); - float r_gain = (_l_fwr + _r_fwr) / (1 + _r_fwr + _r_fwr); - // The 2nd axis has strong gain fluctuations, and therefore require - // limits. The factor corresponds to the 1 / amplification of (Lt - // - Rt) when (Lt, Rt) is strongly correlated. (e.g. during - // dialogues). It should be bigger than -12 dB to prevent - // distortion. - float lmr_lim_fwr = _lmr_fwr > M9_03DB * _lpr_fwr ? _lmr_fwr : M9_03DB * _lpr_fwr; - float lpr_gain = (_lpr_fwr + lmr_lim_fwr) / (1 + _lpr_fwr + _lpr_fwr); - float lmr_gain = (_lpr_fwr + lmr_lim_fwr) / (1 + lmr_lim_fwr + lmr_lim_fwr); - float lmr_unlim_gain = (_lpr_fwr + _lmr_fwr) / (1 + _lmr_fwr + _lmr_fwr); - float lpr, lmr; - float l_agc, r_agc, lpr_agc, lmr_agc; - float f, d_gain, c_gain, c_agc_cfk; + const int kr = (k + olddelay) % _dlbuflen; + float l_gain = (_l_fwr + _r_fwr) / (1 + _l_fwr + _l_fwr); + float r_gain = (_l_fwr + _r_fwr) / (1 + _r_fwr + _r_fwr); + // The 2nd axis has strong gain fluctuations, and therefore require + // limits. The factor corresponds to the 1 / amplification of (Lt + // - Rt) when (Lt, Rt) is strongly correlated. (e.g. during + // dialogues). It should be bigger than -12 dB to prevent + // distortion. + float lmr_lim_fwr = _lmr_fwr > M9_03DB * _lpr_fwr ? _lmr_fwr : M9_03DB * _lpr_fwr; + float lpr_gain = (_lpr_fwr + lmr_lim_fwr) / (1 + _lpr_fwr + _lpr_fwr); + float lmr_gain = (_lpr_fwr + lmr_lim_fwr) / (1 + lmr_lim_fwr + lmr_lim_fwr); + float lmr_unlim_gain = (_lpr_fwr + _lmr_fwr) / (1 + _lmr_fwr + _lmr_fwr); + float lpr, lmr; + float l_agc, r_agc, lpr_agc, lmr_agc; + float f, d_gain, c_gain, c_agc_cfk; - /*** AXIS NO. 1: (Lt, Rt) -> (C, Ls, Rs) ***/ - /* AGC adaption */ - d_gain = (fabs(l_gain - *_adapt_l_gain) + fabs(r_gain - *_adapt_r_gain)) * 0.5f; - f = d_gain * (1.0f / MATAGCTRIG); - f = MATAGCDECAY - MATAGCDECAY / (1 + f * f); - *_adapt_l_gain = (1 - f) * *_adapt_l_gain + f * l_gain; - *_adapt_r_gain = (1 - f) * *_adapt_r_gain + f * r_gain; - /* Matrix */ - l_agc = in[il] * PassiveLock(*_adapt_l_gain); - r_agc = in[ir] * PassiveLock(*_adapt_r_gain); - _cf[k] = (l_agc + r_agc) * (float)M_SQRT1_2; - if (decode_rear) - { - _lr[kr] = _rr[kr] = (l_agc - r_agc) * (float)M_SQRT1_2; - // Stereo rear channel is steered with the same AGC steering as - // the decoding matrix. Note this requires a fast updating AGC - // at the order of 20 ms (which is the case here). - _lr[kr] *= (_l_fwr + _l_fwr) / (1 + _l_fwr + _r_fwr); - _rr[kr] *= (_r_fwr + _r_fwr) / (1 + _l_fwr + _r_fwr); - } + /*** AXIS NO. 1: (Lt, Rt) -> (C, Ls, Rs) ***/ + /* AGC adaption */ + d_gain = (fabs(l_gain - *_adapt_l_gain) + fabs(r_gain - *_adapt_r_gain)) * 0.5f; + f = d_gain * (1.0f / MATAGCTRIG); + f = MATAGCDECAY - MATAGCDECAY / (1 + f * f); + *_adapt_l_gain = (1 - f) * *_adapt_l_gain + f * l_gain; + *_adapt_r_gain = (1 - f) * *_adapt_r_gain + f * r_gain; + /* Matrix */ + l_agc = in[il] * PassiveLock(*_adapt_l_gain); + r_agc = in[ir] * PassiveLock(*_adapt_r_gain); + _cf[k] = (l_agc + r_agc) * (float)M_SQRT1_2; + if (decode_rear) + { + _lr[kr] = _rr[kr] = (l_agc - r_agc) * (float)M_SQRT1_2; + // Stereo rear channel is steered with the same AGC steering as + // the decoding matrix. Note this requires a fast updating AGC + // at the order of 20 ms (which is the case here). + _lr[kr] *= (_l_fwr + _l_fwr) / (1 + _l_fwr + _r_fwr); + _rr[kr] *= (_r_fwr + _r_fwr) / (1 + _l_fwr + _r_fwr); + } - /*** AXIS NO. 2: (Lt + Rt, Lt - Rt) -> (L, R) ***/ - lpr = (in[il] + in[ir]) * (float)M_SQRT1_2; - lmr = (in[il] - in[ir]) * (float)M_SQRT1_2; - /* AGC adaption */ - d_gain = fabs(lmr_unlim_gain - *_adapt_lmr_gain); - f = d_gain * (1.0f / MATAGCTRIG); - f = MATAGCDECAY - MATAGCDECAY / (1 + f * f); - *_adapt_lpr_gain = (1 - f) * *_adapt_lpr_gain + f * lpr_gain; - *_adapt_lmr_gain = (1 - f) * *_adapt_lmr_gain + f * lmr_gain; - /* Matrix */ - lpr_agc = lpr * PassiveLock(*_adapt_lpr_gain); - lmr_agc = lmr * PassiveLock(*_adapt_lmr_gain); - _lf[k] = (lpr_agc + lmr_agc) * (float)M_SQRT1_2; - _rf[k] = (lpr_agc - lmr_agc) * (float)M_SQRT1_2; + /*** AXIS NO. 2: (Lt + Rt, Lt - Rt) -> (L, R) ***/ + lpr = (in[il] + in[ir]) * (float)M_SQRT1_2; + lmr = (in[il] - in[ir]) * (float)M_SQRT1_2; + /* AGC adaption */ + d_gain = fabs(lmr_unlim_gain - *_adapt_lmr_gain); + f = d_gain * (1.0f / MATAGCTRIG); + f = MATAGCDECAY - MATAGCDECAY / (1 + f * f); + *_adapt_lpr_gain = (1 - f) * *_adapt_lpr_gain + f * lpr_gain; + *_adapt_lmr_gain = (1 - f) * *_adapt_lmr_gain + f * lmr_gain; + /* Matrix */ + lpr_agc = lpr * PassiveLock(*_adapt_lpr_gain); + lmr_agc = lmr * PassiveLock(*_adapt_lmr_gain); + _lf[k] = (lpr_agc + lmr_agc) * (float)M_SQRT1_2; + _rf[k] = (lpr_agc - lmr_agc) * (float)M_SQRT1_2; - /*** CENTER FRONT CANCELLATION ***/ - // A heuristic approach exploits that Lt + Rt gain contains the - // information about Lt, Rt correlation. This effectively reshapes - // the front and rear "cones" to concentrate Lt + Rt to C and - // introduce Lt - Rt in L, R. - /* 0.67677 is the empirical lower bound for lpr_gain. */ - c_gain = 8 * (*_adapt_lpr_gain - 0.67677f); - c_gain = c_gain > 0 ? c_gain : 0; - // c_gain should not be too high, not even reaching full - // cancellation (~ 0.50 - 0.55 at current AGC implementation), or - // the center will sound too narrow. */ - c_gain = MATCOMPGAIN / (1 + c_gain * c_gain); - c_agc_cfk = c_gain * _cf[k]; - _lf[k] -= c_agc_cfk; - _rf[k] -= c_agc_cfk; - _cf[k] += c_agc_cfk + c_agc_cfk; + /*** CENTER FRONT CANCELLATION ***/ + // A heuristic approach exploits that Lt + Rt gain contains the + // information about Lt, Rt correlation. This effectively reshapes + // the front and rear "cones" to concentrate Lt + Rt to C and + // introduce Lt - Rt in L, R. + /* 0.67677 is the empirical lower bound for lpr_gain. */ + c_gain = 8 * (*_adapt_lpr_gain - 0.67677f); + c_gain = c_gain > 0 ? c_gain : 0; + // c_gain should not be too high, not even reaching full + // cancellation (~ 0.50 - 0.55 at current AGC implementation), or + // the center will sound too narrow. */ + c_gain = MATCOMPGAIN / (1 + c_gain * c_gain); + c_agc_cfk = c_gain * _cf[k]; + _lf[k] -= c_agc_cfk; + _rf[k] -= c_agc_cfk; + _cf[k] += c_agc_cfk + c_agc_cfk; } -void DPL2Decode(float *samples, int numsamples, float *out) +void DPL2Decode(float* samples, int numsamples, float* out) { - static const unsigned int FWRDURATION = 240; // FWR average duration (samples) - static const int cfg_delay = 0; - static const unsigned int fmt_freq = 48000; - static const unsigned int fmt_nchannels = 2; // input channels + static const unsigned int FWRDURATION = 240; // FWR average duration (samples) + static const int cfg_delay = 0; + static const unsigned int fmt_freq = 48000; + static const unsigned int fmt_nchannels = 2; // input channels - int cur = 0; + int cur = 0; - if (olddelay != cfg_delay || oldfreq != fmt_freq) - { - Done(); - olddelay = cfg_delay; - oldfreq = fmt_freq; - dlbuflen = std::max(FWRDURATION, (fmt_freq * cfg_delay / 1000)); //+(len7000-1); - cyc_pos = dlbuflen - 1; - fwrbuf_l.resize(dlbuflen); - fwrbuf_r.resize(dlbuflen); - lf.resize(dlbuflen); - rf.resize(dlbuflen); - lr.resize(dlbuflen); - rr.resize(dlbuflen); - cf.resize(dlbuflen); - cr.resize(dlbuflen); - filter_coefs_lfe = CalculateCoefficients125HzLowpass(fmt_freq); - lfe_pos = 0; - memset(LFE_buf, 0, sizeof(LFE_buf)); - } + if (olddelay != cfg_delay || oldfreq != fmt_freq) + { + Done(); + olddelay = cfg_delay; + oldfreq = fmt_freq; + dlbuflen = std::max(FWRDURATION, (fmt_freq * cfg_delay / 1000)); //+(len7000-1); + cyc_pos = dlbuflen - 1; + fwrbuf_l.resize(dlbuflen); + fwrbuf_r.resize(dlbuflen); + lf.resize(dlbuflen); + rf.resize(dlbuflen); + lr.resize(dlbuflen); + rr.resize(dlbuflen); + cf.resize(dlbuflen); + cr.resize(dlbuflen); + filter_coefs_lfe = CalculateCoefficients125HzLowpass(fmt_freq); + lfe_pos = 0; + memset(LFE_buf, 0, sizeof(LFE_buf)); + } - float *in = samples; // Input audio data - float *end = in + numsamples * fmt_nchannels; // Loop end + float* in = samples; // Input audio data + float* end = in + numsamples * fmt_nchannels; // Loop end - while (in < end) - { - const int k = cyc_pos; + while (in < end) + { + const int k = cyc_pos; - const int fwr_pos = (k + FWRDURATION) % dlbuflen; - /* Update the full wave rectified total amplitude */ - /* Input matrix decoder */ - l_fwr += fabs(in[0]) - fabs(fwrbuf_l[fwr_pos]); - r_fwr += fabs(in[1]) - fabs(fwrbuf_r[fwr_pos]); - lpr_fwr += fabs(in[0] + in[1]) - fabs(fwrbuf_l[fwr_pos] + fwrbuf_r[fwr_pos]); - lmr_fwr += fabs(in[0] - in[1]) - fabs(fwrbuf_l[fwr_pos] - fwrbuf_r[fwr_pos]); + const int fwr_pos = (k + FWRDURATION) % dlbuflen; + /* Update the full wave rectified total amplitude */ + /* Input matrix decoder */ + l_fwr += fabs(in[0]) - fabs(fwrbuf_l[fwr_pos]); + r_fwr += fabs(in[1]) - fabs(fwrbuf_r[fwr_pos]); + lpr_fwr += fabs(in[0] + in[1]) - fabs(fwrbuf_l[fwr_pos] + fwrbuf_r[fwr_pos]); + lmr_fwr += fabs(in[0] - in[1]) - fabs(fwrbuf_l[fwr_pos] - fwrbuf_r[fwr_pos]); - /* Matrix encoded 2 channel sources */ - fwrbuf_l[k] = in[0]; - fwrbuf_r[k] = in[1]; - MatrixDecode(in, k, 0, 1, true, dlbuflen, - l_fwr, r_fwr, - lpr_fwr, lmr_fwr, - &adapt_l_gain, &adapt_r_gain, - &adapt_lpr_gain, &adapt_lmr_gain, - &lf[0], &rf[0], &lr[0], &rr[0], &cf[0]); + /* Matrix encoded 2 channel sources */ + fwrbuf_l[k] = in[0]; + fwrbuf_r[k] = in[1]; + MatrixDecode(in, k, 0, 1, true, dlbuflen, l_fwr, r_fwr, lpr_fwr, lmr_fwr, &adapt_l_gain, + &adapt_r_gain, &adapt_lpr_gain, &adapt_lmr_gain, &lf[0], &rf[0], &lr[0], &rr[0], + &cf[0]); - out[cur + 0] = lf[k]; - out[cur + 1] = rf[k]; - out[cur + 2] = cf[k]; - LFE_buf[lfe_pos] = (lf[k] + rf[k] + 2.0f * cf[k] + lr[k] + rr[k]) / 2.0f; - out[cur + 3] = FIRFilter(LFE_buf, lfe_pos, len125, len125, filter_coefs_lfe); - lfe_pos++; - if (lfe_pos == len125) - { - lfe_pos = 0; - } - out[cur + 4] = lr[k]; - out[cur + 5] = rr[k]; - // Next sample... - in += 2; - cur += 6; - cyc_pos--; - if (cyc_pos < 0) - { - cyc_pos += dlbuflen; - } - } + out[cur + 0] = lf[k]; + out[cur + 1] = rf[k]; + out[cur + 2] = cf[k]; + LFE_buf[lfe_pos] = (lf[k] + rf[k] + 2.0f * cf[k] + lr[k] + rr[k]) / 2.0f; + out[cur + 3] = FIRFilter(LFE_buf, lfe_pos, len125, len125, filter_coefs_lfe); + lfe_pos++; + if (lfe_pos == len125) + { + lfe_pos = 0; + } + out[cur + 4] = lr[k]; + out[cur + 5] = rr[k]; + // Next sample... + in += 2; + cur += 6; + cyc_pos--; + if (cyc_pos < 0) + { + cyc_pos += dlbuflen; + } + } } void DPL2Reset() { - olddelay = -1; - oldfreq = 0; - filter_coefs_lfe = nullptr; + olddelay = -1; + oldfreq = 0; + filter_coefs_lfe = nullptr; } diff --git a/Source/Core/AudioCommon/DPL2Decoder.h b/Source/Core/AudioCommon/DPL2Decoder.h index 5bcc5ea244..7e5678d8f2 100644 --- a/Source/Core/AudioCommon/DPL2Decoder.h +++ b/Source/Core/AudioCommon/DPL2Decoder.h @@ -4,5 +4,5 @@ #pragma once -void DPL2Decode(float *samples, int numsamples, float *out); +void DPL2Decode(float* samples, int numsamples, float* out); void DPL2Reset(); diff --git a/Source/Core/AudioCommon/Mixer.cpp b/Source/Core/AudioCommon/Mixer.cpp index 5e3aef733a..66a47b2141 100644 --- a/Source/Core/AudioCommon/Mixer.cpp +++ b/Source/Core/AudioCommon/Mixer.cpp @@ -8,18 +8,17 @@ #include "AudioCommon/Mixer.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" -#include "Common/MathUtil.h" #include "Common/Logging/Log.h" +#include "Common/MathUtil.h" #include "Core/ConfigManager.h" #if _M_SSE >= 0x301 && !(defined __GNUC__ && !defined __SSSE3__) #include #endif -CMixer::CMixer(unsigned int BackendSampleRate) - : m_sampleRate(BackendSampleRate) +CMixer::CMixer(unsigned int BackendSampleRate) : m_sampleRate(BackendSampleRate) { - INFO_LOG(AUDIO_INTERFACE, "Mixer is initialized"); + INFO_LOG(AUDIO_INTERFACE, "Mixer is initialized"); } CMixer::~CMixer() @@ -27,249 +26,253 @@ CMixer::~CMixer() } // Executed from sound stream thread -unsigned int CMixer::MixerFifo::Mix(short* samples, unsigned int numSamples, bool consider_framelimit) +unsigned int CMixer::MixerFifo::Mix(short* samples, unsigned int numSamples, + bool consider_framelimit) { - unsigned int currentSample = 0; + unsigned int currentSample = 0; - // Cache access in non-volatile variable - // This is the only function changing the read value, so it's safe to - // cache it locally although it's written here. - // The writing pointer will be modified outside, but it will only increase, - // so we will just ignore new written data while interpolating. - // Without this cache, the compiler wouldn't be allowed to optimize the - // interpolation loop. - u32 indexR = m_indexR.load(); - u32 indexW = m_indexW.load(); + // Cache access in non-volatile variable + // This is the only function changing the read value, so it's safe to + // cache it locally although it's written here. + // The writing pointer will be modified outside, but it will only increase, + // so we will just ignore new written data while interpolating. + // Without this cache, the compiler wouldn't be allowed to optimize the + // interpolation loop. + u32 indexR = m_indexR.load(); + u32 indexW = m_indexW.load(); - u32 low_waterwark = m_input_sample_rate * SConfig::GetInstance().iTimingVariance / 1000; - low_waterwark = std::min(low_waterwark, MAX_SAMPLES / 2); + u32 low_waterwark = m_input_sample_rate * SConfig::GetInstance().iTimingVariance / 1000; + low_waterwark = std::min(low_waterwark, MAX_SAMPLES / 2); - float numLeft = (float)(((indexW - indexR) & INDEX_MASK) / 2); - m_numLeftI = (numLeft + m_numLeftI*(CONTROL_AVG-1)) / CONTROL_AVG; - float offset = (m_numLeftI - low_waterwark) * CONTROL_FACTOR; - if (offset > MAX_FREQ_SHIFT) offset = MAX_FREQ_SHIFT; - if (offset < -MAX_FREQ_SHIFT) offset = -MAX_FREQ_SHIFT; + float numLeft = (float)(((indexW - indexR) & INDEX_MASK) / 2); + m_numLeftI = (numLeft + m_numLeftI * (CONTROL_AVG - 1)) / CONTROL_AVG; + float offset = (m_numLeftI - low_waterwark) * CONTROL_FACTOR; + if (offset > MAX_FREQ_SHIFT) + offset = MAX_FREQ_SHIFT; + if (offset < -MAX_FREQ_SHIFT) + offset = -MAX_FREQ_SHIFT; - //render numleft sample pairs to samples[] - //advance indexR with sample position - //remember fractional offset + // render numleft sample pairs to samples[] + // advance indexR with sample position + // remember fractional offset - float emulationspeed = SConfig::GetInstance().m_EmulationSpeed; - float aid_sample_rate = m_input_sample_rate + offset; - if (consider_framelimit && emulationspeed > 0.0f) - { - aid_sample_rate = aid_sample_rate * emulationspeed; - } + float emulationspeed = SConfig::GetInstance().m_EmulationSpeed; + float aid_sample_rate = m_input_sample_rate + offset; + if (consider_framelimit && emulationspeed > 0.0f) + { + aid_sample_rate = aid_sample_rate * emulationspeed; + } - const u32 ratio = (u32)(65536.0f * aid_sample_rate / (float)m_mixer->m_sampleRate); + const u32 ratio = (u32)(65536.0f * aid_sample_rate / (float)m_mixer->m_sampleRate); - s32 lvolume = m_LVolume.load(); - s32 rvolume = m_RVolume.load(); + s32 lvolume = m_LVolume.load(); + s32 rvolume = m_RVolume.load(); - // TODO: consider a higher-quality resampling algorithm. - for (; currentSample < numSamples * 2 && ((indexW-indexR) & INDEX_MASK) > 2; currentSample += 2) - { - u32 indexR2 = indexR + 2; //next sample + // TODO: consider a higher-quality resampling algorithm. + for (; currentSample < numSamples * 2 && ((indexW - indexR) & INDEX_MASK) > 2; currentSample += 2) + { + u32 indexR2 = indexR + 2; // next sample - s16 l1 = Common::swap16(m_buffer[indexR & INDEX_MASK]); //current - s16 l2 = Common::swap16(m_buffer[indexR2 & INDEX_MASK]); //next - int sampleL = ((l1 << 16) + (l2 - l1) * (u16)m_frac) >> 16; - sampleL = (sampleL * lvolume) >> 8; - sampleL += samples[currentSample + 1]; - samples[currentSample + 1] = MathUtil::Clamp(sampleL, -32767, 32767); + s16 l1 = Common::swap16(m_buffer[indexR & INDEX_MASK]); // current + s16 l2 = Common::swap16(m_buffer[indexR2 & INDEX_MASK]); // next + int sampleL = ((l1 << 16) + (l2 - l1) * (u16)m_frac) >> 16; + sampleL = (sampleL * lvolume) >> 8; + sampleL += samples[currentSample + 1]; + samples[currentSample + 1] = MathUtil::Clamp(sampleL, -32767, 32767); - s16 r1 = Common::swap16(m_buffer[(indexR + 1) & INDEX_MASK]); //current - s16 r2 = Common::swap16(m_buffer[(indexR2 + 1) & INDEX_MASK]); //next - int sampleR = ((r1 << 16) + (r2 - r1) * (u16)m_frac) >> 16; - sampleR = (sampleR * rvolume) >> 8; - sampleR += samples[currentSample]; - samples[currentSample] = MathUtil::Clamp(sampleR, -32767, 32767); + s16 r1 = Common::swap16(m_buffer[(indexR + 1) & INDEX_MASK]); // current + s16 r2 = Common::swap16(m_buffer[(indexR2 + 1) & INDEX_MASK]); // next + int sampleR = ((r1 << 16) + (r2 - r1) * (u16)m_frac) >> 16; + sampleR = (sampleR * rvolume) >> 8; + sampleR += samples[currentSample]; + samples[currentSample] = MathUtil::Clamp(sampleR, -32767, 32767); - m_frac += ratio; - indexR += 2 * (u16)(m_frac >> 16); - m_frac &= 0xffff; - } + m_frac += ratio; + indexR += 2 * (u16)(m_frac >> 16); + m_frac &= 0xffff; + } - // Padding - short s[2]; - s[0] = Common::swap16(m_buffer[(indexR - 1) & INDEX_MASK]); - s[1] = Common::swap16(m_buffer[(indexR - 2) & INDEX_MASK]); - s[0] = (s[0] * rvolume) >> 8; - s[1] = (s[1] * lvolume) >> 8; - for (; currentSample < numSamples * 2; currentSample += 2) - { - int sampleR = MathUtil::Clamp(s[0] + samples[currentSample + 0], -32767, 32767); - int sampleL = MathUtil::Clamp(s[1] + samples[currentSample + 1], -32767, 32767); + // Padding + short s[2]; + s[0] = Common::swap16(m_buffer[(indexR - 1) & INDEX_MASK]); + s[1] = Common::swap16(m_buffer[(indexR - 2) & INDEX_MASK]); + s[0] = (s[0] * rvolume) >> 8; + s[1] = (s[1] * lvolume) >> 8; + for (; currentSample < numSamples * 2; currentSample += 2) + { + int sampleR = MathUtil::Clamp(s[0] + samples[currentSample + 0], -32767, 32767); + int sampleL = MathUtil::Clamp(s[1] + samples[currentSample + 1], -32767, 32767); - samples[currentSample + 0] = sampleR; - samples[currentSample + 1] = sampleL; - } + samples[currentSample + 0] = sampleR; + samples[currentSample + 1] = sampleL; + } - // Flush cached variable - m_indexR.store(indexR); + // Flush cached variable + m_indexR.store(indexR); - return numSamples; + return numSamples; } unsigned int CMixer::Mix(short* samples, unsigned int num_samples, bool consider_framelimit) { - if (!samples) - return 0; + if (!samples) + return 0; - memset(samples, 0, num_samples * 2 * sizeof(short)); + memset(samples, 0, num_samples * 2 * sizeof(short)); - m_dma_mixer.Mix(samples, num_samples, consider_framelimit); - m_streaming_mixer.Mix(samples, num_samples, consider_framelimit); - m_wiimote_speaker_mixer.Mix(samples, num_samples, consider_framelimit); - return num_samples; + m_dma_mixer.Mix(samples, num_samples, consider_framelimit); + m_streaming_mixer.Mix(samples, num_samples, consider_framelimit); + m_wiimote_speaker_mixer.Mix(samples, num_samples, consider_framelimit); + return num_samples; } -void CMixer::MixerFifo::PushSamples(const short *samples, unsigned int num_samples) +void CMixer::MixerFifo::PushSamples(const short* samples, unsigned int num_samples) { - // Cache access in non-volatile variable - // indexR isn't allowed to cache in the audio throttling loop as it - // needs to get updates to not deadlock. - u32 indexW = m_indexW.load(); + // Cache access in non-volatile variable + // indexR isn't allowed to cache in the audio throttling loop as it + // needs to get updates to not deadlock. + u32 indexW = m_indexW.load(); - // Check if we have enough free space - // indexW == m_indexR results in empty buffer, so indexR must always be smaller than indexW - if (num_samples * 2 + ((indexW - m_indexR.load()) & INDEX_MASK) >= MAX_SAMPLES * 2) - return; + // Check if we have enough free space + // indexW == m_indexR results in empty buffer, so indexR must always be smaller than indexW + if (num_samples * 2 + ((indexW - m_indexR.load()) & INDEX_MASK) >= MAX_SAMPLES * 2) + return; - // AyuanX: Actual re-sampling work has been moved to sound thread - // to alleviate the workload on main thread - // and we simply store raw data here to make fast mem copy - int over_bytes = num_samples * 4 - (MAX_SAMPLES * 2 - (indexW & INDEX_MASK)) * sizeof(short); - if (over_bytes > 0) - { - memcpy(&m_buffer[indexW & INDEX_MASK], samples, num_samples * 4 - over_bytes); - memcpy(&m_buffer[0], samples + (num_samples * 4 - over_bytes) / sizeof(short), over_bytes); - } - else - { - memcpy(&m_buffer[indexW & INDEX_MASK], samples, num_samples * 4); - } + // AyuanX: Actual re-sampling work has been moved to sound thread + // to alleviate the workload on main thread + // and we simply store raw data here to make fast mem copy + int over_bytes = num_samples * 4 - (MAX_SAMPLES * 2 - (indexW & INDEX_MASK)) * sizeof(short); + if (over_bytes > 0) + { + memcpy(&m_buffer[indexW & INDEX_MASK], samples, num_samples * 4 - over_bytes); + memcpy(&m_buffer[0], samples + (num_samples * 4 - over_bytes) / sizeof(short), over_bytes); + } + else + { + memcpy(&m_buffer[indexW & INDEX_MASK], samples, num_samples * 4); + } - m_indexW.fetch_add(num_samples * 2); + m_indexW.fetch_add(num_samples * 2); } -void CMixer::PushSamples(const short *samples, unsigned int num_samples) +void CMixer::PushSamples(const short* samples, unsigned int num_samples) { - m_dma_mixer.PushSamples(samples, num_samples); - if (m_log_dsp_audio) - m_wave_writer_dsp.AddStereoSamplesBE(samples, num_samples); + m_dma_mixer.PushSamples(samples, num_samples); + if (m_log_dsp_audio) + m_wave_writer_dsp.AddStereoSamplesBE(samples, num_samples); } -void CMixer::PushStreamingSamples(const short *samples, unsigned int num_samples) +void CMixer::PushStreamingSamples(const short* samples, unsigned int num_samples) { - m_streaming_mixer.PushSamples(samples, num_samples); - if (m_log_dtk_audio) - m_wave_writer_dtk.AddStereoSamplesBE(samples, num_samples); + m_streaming_mixer.PushSamples(samples, num_samples); + if (m_log_dtk_audio) + m_wave_writer_dtk.AddStereoSamplesBE(samples, num_samples); } -void CMixer::PushWiimoteSpeakerSamples(const short *samples, unsigned int num_samples, unsigned int sample_rate) +void CMixer::PushWiimoteSpeakerSamples(const short* samples, unsigned int num_samples, + unsigned int sample_rate) { - short samples_stereo[MAX_SAMPLES * 2]; + short samples_stereo[MAX_SAMPLES * 2]; - if (num_samples < MAX_SAMPLES) - { - m_wiimote_speaker_mixer.SetInputSampleRate(sample_rate); + if (num_samples < MAX_SAMPLES) + { + m_wiimote_speaker_mixer.SetInputSampleRate(sample_rate); - for (unsigned int i = 0; i < num_samples; ++i) - { - samples_stereo[i * 2] = Common::swap16(samples[i]); - samples_stereo[i * 2 + 1] = Common::swap16(samples[i]); - } + for (unsigned int i = 0; i < num_samples; ++i) + { + samples_stereo[i * 2] = Common::swap16(samples[i]); + samples_stereo[i * 2 + 1] = Common::swap16(samples[i]); + } - m_wiimote_speaker_mixer.PushSamples(samples_stereo, num_samples); - } + m_wiimote_speaker_mixer.PushSamples(samples_stereo, num_samples); + } } void CMixer::SetDMAInputSampleRate(unsigned int rate) { - m_dma_mixer.SetInputSampleRate(rate); + m_dma_mixer.SetInputSampleRate(rate); } void CMixer::SetStreamInputSampleRate(unsigned int rate) { - m_streaming_mixer.SetInputSampleRate(rate); + m_streaming_mixer.SetInputSampleRate(rate); } void CMixer::SetStreamingVolume(unsigned int lvolume, unsigned int rvolume) { - m_streaming_mixer.SetVolume(lvolume, rvolume); + m_streaming_mixer.SetVolume(lvolume, rvolume); } void CMixer::SetWiimoteSpeakerVolume(unsigned int lvolume, unsigned int rvolume) { - m_wiimote_speaker_mixer.SetVolume(lvolume, rvolume); + m_wiimote_speaker_mixer.SetVolume(lvolume, rvolume); } void CMixer::StartLogDTKAudio(const std::string& filename) { - if (!m_log_dtk_audio) - { - m_log_dtk_audio = true; - m_wave_writer_dtk.Start(filename, 48000); - m_wave_writer_dtk.SetSkipSilence(false); - NOTICE_LOG(AUDIO, "Starting DTK Audio logging"); - } - else - { - WARN_LOG(AUDIO, "DTK Audio logging has already been started"); - } + if (!m_log_dtk_audio) + { + m_log_dtk_audio = true; + m_wave_writer_dtk.Start(filename, 48000); + m_wave_writer_dtk.SetSkipSilence(false); + NOTICE_LOG(AUDIO, "Starting DTK Audio logging"); + } + else + { + WARN_LOG(AUDIO, "DTK Audio logging has already been started"); + } } void CMixer::StopLogDTKAudio() { - if (m_log_dtk_audio) - { - m_log_dtk_audio = false; - m_wave_writer_dtk.Stop(); - NOTICE_LOG(AUDIO, "Stopping DTK Audio logging"); - } - else - { - WARN_LOG(AUDIO, "DTK Audio logging has already been stopped"); - } + if (m_log_dtk_audio) + { + m_log_dtk_audio = false; + m_wave_writer_dtk.Stop(); + NOTICE_LOG(AUDIO, "Stopping DTK Audio logging"); + } + else + { + WARN_LOG(AUDIO, "DTK Audio logging has already been stopped"); + } } void CMixer::StartLogDSPAudio(const std::string& filename) { - if (!m_log_dsp_audio) - { - m_log_dsp_audio = true; - m_wave_writer_dsp.Start(filename, 32000); - m_wave_writer_dsp.SetSkipSilence(false); - NOTICE_LOG(AUDIO, "Starting DSP Audio logging"); - } - else - { - WARN_LOG(AUDIO, "DSP Audio logging has already been started"); - } + if (!m_log_dsp_audio) + { + m_log_dsp_audio = true; + m_wave_writer_dsp.Start(filename, 32000); + m_wave_writer_dsp.SetSkipSilence(false); + NOTICE_LOG(AUDIO, "Starting DSP Audio logging"); + } + else + { + WARN_LOG(AUDIO, "DSP Audio logging has already been started"); + } } void CMixer::StopLogDSPAudio() { - if (m_log_dsp_audio) - { - m_log_dsp_audio = false; - m_wave_writer_dsp.Stop(); - NOTICE_LOG(AUDIO, "Stopping DSP Audio logging"); - } - else - { - WARN_LOG(AUDIO, "DSP Audio logging has already been stopped"); - } + if (m_log_dsp_audio) + { + m_log_dsp_audio = false; + m_wave_writer_dsp.Stop(); + NOTICE_LOG(AUDIO, "Stopping DSP Audio logging"); + } + else + { + WARN_LOG(AUDIO, "DSP Audio logging has already been stopped"); + } } void CMixer::MixerFifo::SetInputSampleRate(unsigned int rate) { - m_input_sample_rate = rate; + m_input_sample_rate = rate; } void CMixer::MixerFifo::SetVolume(unsigned int lvolume, unsigned int rvolume) { - m_LVolume.store(lvolume + (lvolume >> 7)); - m_RVolume.store(rvolume + (rvolume >> 7)); + m_LVolume.store(lvolume + (lvolume >> 7)); + m_RVolume.store(rvolume + (rvolume >> 7)); } diff --git a/Source/Core/AudioCommon/Mixer.h b/Source/Core/AudioCommon/Mixer.h index 008e059e44..ea8666fbc7 100644 --- a/Source/Core/AudioCommon/Mixer.h +++ b/Source/Core/AudioCommon/Mixer.h @@ -13,74 +13,73 @@ class CMixer final { public: - explicit CMixer(unsigned int BackendSampleRate); - ~CMixer(); + explicit CMixer(unsigned int BackendSampleRate); + ~CMixer(); - // Called from audio threads - unsigned int Mix(short* samples, unsigned int numSamples, bool consider_framelimit = true); + // Called from audio threads + unsigned int Mix(short* samples, unsigned int numSamples, bool consider_framelimit = true); - // Called from main thread - void PushSamples(const short* samples, unsigned int num_samples); - void PushStreamingSamples(const short* samples, unsigned int num_samples); - void PushWiimoteSpeakerSamples(const short* samples, unsigned int num_samples, unsigned int sample_rate); - unsigned int GetSampleRate() const { return m_sampleRate; } + // Called from main thread + void PushSamples(const short* samples, unsigned int num_samples); + void PushStreamingSamples(const short* samples, unsigned int num_samples); + void PushWiimoteSpeakerSamples(const short* samples, unsigned int num_samples, + unsigned int sample_rate); + unsigned int GetSampleRate() const { return m_sampleRate; } + void SetDMAInputSampleRate(unsigned int rate); + void SetStreamInputSampleRate(unsigned int rate); + void SetStreamingVolume(unsigned int lvolume, unsigned int rvolume); + void SetWiimoteSpeakerVolume(unsigned int lvolume, unsigned int rvolume); - void SetDMAInputSampleRate(unsigned int rate); - void SetStreamInputSampleRate(unsigned int rate); - void SetStreamingVolume(unsigned int lvolume, unsigned int rvolume); - void SetWiimoteSpeakerVolume(unsigned int lvolume, unsigned int rvolume); + void StartLogDTKAudio(const std::string& filename); + void StopLogDTKAudio(); - void StartLogDTKAudio(const std::string& filename); - void StopLogDTKAudio(); - - void StartLogDSPAudio(const std::string& filename); - void StopLogDSPAudio(); - - float GetCurrentSpeed() const { return m_speed.load(); } - void UpdateSpeed(float val) { m_speed.store(val); } + void StartLogDSPAudio(const std::string& filename); + void StopLogDSPAudio(); + float GetCurrentSpeed() const { return m_speed.load(); } + void UpdateSpeed(float val) { m_speed.store(val); } private: - static constexpr u32 MAX_SAMPLES = 1024 * 4; // 128 ms - static constexpr u32 INDEX_MASK = MAX_SAMPLES * 2 - 1; - static constexpr int MAX_FREQ_SHIFT = 200; // Per 32000 Hz - static constexpr float CONTROL_FACTOR = 0.2f; - static constexpr u32 CONTROL_AVG = 32; // In freq_shift per FIFO size offset + static constexpr u32 MAX_SAMPLES = 1024 * 4; // 128 ms + static constexpr u32 INDEX_MASK = MAX_SAMPLES * 2 - 1; + static constexpr int MAX_FREQ_SHIFT = 200; // Per 32000 Hz + static constexpr float CONTROL_FACTOR = 0.2f; + static constexpr u32 CONTROL_AVG = 32; // In freq_shift per FIFO size offset - class MixerFifo final - { - public: - MixerFifo(CMixer* mixer, unsigned sample_rate) - : m_mixer(mixer) - , m_input_sample_rate(sample_rate) - { - } - void PushSamples(const short* samples, unsigned int num_samples); - unsigned int Mix(short* samples, unsigned int numSamples, bool consider_framelimit = true); - void SetInputSampleRate(unsigned int rate); - void SetVolume(unsigned int lvolume, unsigned int rvolume); - private: - CMixer* m_mixer; - unsigned m_input_sample_rate; - std::array m_buffer{}; - std::atomic m_indexW{0}; - std::atomic m_indexR{0}; - // Volume ranges from 0-256 - std::atomic m_LVolume{256}; - std::atomic m_RVolume{256}; - float m_numLeftI = 0.0f; - u32 m_frac = 0; - }; - MixerFifo m_dma_mixer{this, 32000}; - MixerFifo m_streaming_mixer{this, 48000}; - MixerFifo m_wiimote_speaker_mixer{this, 3000}; - unsigned int m_sampleRate; + class MixerFifo final + { + public: + MixerFifo(CMixer* mixer, unsigned sample_rate) + : m_mixer(mixer), m_input_sample_rate(sample_rate) + { + } + void PushSamples(const short* samples, unsigned int num_samples); + unsigned int Mix(short* samples, unsigned int numSamples, bool consider_framelimit = true); + void SetInputSampleRate(unsigned int rate); + void SetVolume(unsigned int lvolume, unsigned int rvolume); - WaveFileWriter m_wave_writer_dtk; - WaveFileWriter m_wave_writer_dsp; + private: + CMixer* m_mixer; + unsigned m_input_sample_rate; + std::array m_buffer{}; + std::atomic m_indexW{0}; + std::atomic m_indexR{0}; + // Volume ranges from 0-256 + std::atomic m_LVolume{256}; + std::atomic m_RVolume{256}; + float m_numLeftI = 0.0f; + u32 m_frac = 0; + }; + MixerFifo m_dma_mixer{this, 32000}; + MixerFifo m_streaming_mixer{this, 48000}; + MixerFifo m_wiimote_speaker_mixer{this, 3000}; + unsigned int m_sampleRate; - bool m_log_dtk_audio = false; - bool m_log_dsp_audio = false; + WaveFileWriter m_wave_writer_dtk; + WaveFileWriter m_wave_writer_dsp; - // Current rate of emulation (1.0 = 100% speed) - std::atomic m_speed{0.0f}; + bool m_log_dtk_audio = false; + bool m_log_dsp_audio = false; + + // Current rate of emulation (1.0 = 100% speed) + std::atomic m_speed{0.0f}; }; diff --git a/Source/Core/AudioCommon/NullSoundStream.cpp b/Source/Core/AudioCommon/NullSoundStream.cpp index 049ce2b269..d55c61bbc3 100644 --- a/Source/Core/AudioCommon/NullSoundStream.cpp +++ b/Source/Core/AudioCommon/NullSoundStream.cpp @@ -13,7 +13,7 @@ void NullSound::SoundLoop() bool NullSound::Start() { - return true; + return true; } void NullSound::SetVolume(int volume) @@ -22,19 +22,22 @@ void NullSound::SetVolume(int volume) void NullSound::Update() { - // num_samples_to_render in this update - depends on SystemTimers::AUDIO_DMA_PERIOD. - constexpr u32 stereo_16_bit_size = 4; - constexpr u32 dma_length = 32; - const u64 audio_dma_period = SystemTimers::GetTicksPerSecond() / (AudioInterface::GetAIDSampleRate() * stereo_16_bit_size / dma_length); - const u64 ais_samples_per_second = 48000 * stereo_16_bit_size; - const u64 num_samples_to_render = (audio_dma_period * ais_samples_per_second) / SystemTimers::GetTicksPerSecond(); + // num_samples_to_render in this update - depends on SystemTimers::AUDIO_DMA_PERIOD. + constexpr u32 stereo_16_bit_size = 4; + constexpr u32 dma_length = 32; + const u64 audio_dma_period = + SystemTimers::GetTicksPerSecond() / + (AudioInterface::GetAIDSampleRate() * stereo_16_bit_size / dma_length); + const u64 ais_samples_per_second = 48000 * stereo_16_bit_size; + const u64 num_samples_to_render = + (audio_dma_period * ais_samples_per_second) / SystemTimers::GetTicksPerSecond(); - m_mixer->Mix(m_realtime_buffer.data(), (unsigned int)num_samples_to_render); + m_mixer->Mix(m_realtime_buffer.data(), (unsigned int)num_samples_to_render); } void NullSound::Clear(bool mute) { - m_muted = mute; + m_muted = mute; } void NullSound::Stop() diff --git a/Source/Core/AudioCommon/NullSoundStream.h b/Source/Core/AudioCommon/NullSoundStream.h index d27ac520f1..a3d0393e13 100644 --- a/Source/Core/AudioCommon/NullSoundStream.h +++ b/Source/Core/AudioCommon/NullSoundStream.h @@ -10,18 +10,17 @@ class NullSound final : public SoundStream { public: - bool Start() override; - void SoundLoop() override; - void SetVolume(int volume) override; - void Stop() override; - void Clear(bool mute) override; - void Update() override; - - static bool isValid() { return true; } + bool Start() override; + void SoundLoop() override; + void SetVolume(int volume) override; + void Stop() override; + void Clear(bool mute) override; + void Update() override; + static bool isValid() { return true; } private: - static constexpr size_t BUFFER_SIZE = 48000 * 4 / 32; + static constexpr size_t BUFFER_SIZE = 48000 * 4 / 32; - // Playback position - std::array m_realtime_buffer; + // Playback position + std::array m_realtime_buffer; }; diff --git a/Source/Core/AudioCommon/OpenALStream.cpp b/Source/Core/AudioCommon/OpenALStream.cpp index b99e7e5bf7..9f0ea2af57 100644 --- a/Source/Core/AudioCommon/OpenALStream.cpp +++ b/Source/Core/AudioCommon/OpenALStream.cpp @@ -5,11 +5,11 @@ #include #include -#include "AudioCommon/aldlist.h" #include "AudioCommon/DPL2Decoder.h" #include "AudioCommon/OpenALStream.h" -#include "Common/Thread.h" +#include "AudioCommon/aldlist.h" #include "Common/Logging/Log.h" +#include "Common/Thread.h" #include "Core/ConfigManager.h" #if defined HAVE_OPENAL && HAVE_OPENAL @@ -25,351 +25,363 @@ static soundtouch::SoundTouch soundTouch; // bool OpenALStream::Start() { - m_run_thread.store(true); - bool bReturn = false; + m_run_thread.store(true); + bool bReturn = false; - ALDeviceList pDeviceList; - if (pDeviceList.GetNumDevices()) - { - char *defDevName = pDeviceList.GetDeviceName(pDeviceList.GetDefaultDevice()); + ALDeviceList pDeviceList; + if (pDeviceList.GetNumDevices()) + { + char* defDevName = pDeviceList.GetDeviceName(pDeviceList.GetDefaultDevice()); - WARN_LOG(AUDIO, "Found OpenAL device %s", defDevName); + WARN_LOG(AUDIO, "Found OpenAL device %s", defDevName); - ALCdevice *pDevice = alcOpenDevice(defDevName); - if (pDevice) - { - ALCcontext *pContext = alcCreateContext(pDevice, nullptr); - if (pContext) - { - // Used to determine an appropriate period size (2x period = total buffer size) - //ALCint refresh; - //alcGetIntegerv(pDevice, ALC_REFRESH, 1, &refresh); - //period_size_in_millisec = 1000 / refresh; + ALCdevice* pDevice = alcOpenDevice(defDevName); + if (pDevice) + { + ALCcontext* pContext = alcCreateContext(pDevice, nullptr); + if (pContext) + { + // Used to determine an appropriate period size (2x period = total buffer size) + // ALCint refresh; + // alcGetIntegerv(pDevice, ALC_REFRESH, 1, &refresh); + // period_size_in_millisec = 1000 / refresh; - alcMakeContextCurrent(pContext); - thread = std::thread(&OpenALStream::SoundLoop, this); - bReturn = true; - } - else - { - alcCloseDevice(pDevice); - PanicAlertT("OpenAL: can't create context for device %s", defDevName); - } - } - else - { - PanicAlertT("OpenAL: can't open device %s", defDevName); - } - } - else - { - PanicAlertT("OpenAL: can't find sound devices"); - } + alcMakeContextCurrent(pContext); + thread = std::thread(&OpenALStream::SoundLoop, this); + bReturn = true; + } + else + { + alcCloseDevice(pDevice); + PanicAlertT("OpenAL: can't create context for device %s", defDevName); + } + } + else + { + PanicAlertT("OpenAL: can't open device %s", defDevName); + } + } + else + { + PanicAlertT("OpenAL: can't find sound devices"); + } - // Initialize DPL2 parameters - DPL2Reset(); + // Initialize DPL2 parameters + DPL2Reset(); - soundTouch.clear(); - return bReturn; + soundTouch.clear(); + return bReturn; } void OpenALStream::Stop() { - m_run_thread.store(false); - // kick the thread if it's waiting - soundSyncEvent.Set(); + m_run_thread.store(false); + // kick the thread if it's waiting + soundSyncEvent.Set(); - soundTouch.clear(); + soundTouch.clear(); - thread.join(); + thread.join(); - alSourceStop(uiSource); - alSourcei(uiSource, AL_BUFFER, 0); + alSourceStop(uiSource); + alSourcei(uiSource, AL_BUFFER, 0); - // Clean up buffers and sources - alDeleteSources(1, &uiSource); - uiSource = 0; - alDeleteBuffers(numBuffers, uiBuffers); + // Clean up buffers and sources + alDeleteSources(1, &uiSource); + uiSource = 0; + alDeleteBuffers(numBuffers, uiBuffers); - ALCcontext *pContext = alcGetCurrentContext(); - ALCdevice *pDevice = alcGetContextsDevice(pContext); + ALCcontext* pContext = alcGetCurrentContext(); + ALCdevice* pDevice = alcGetContextsDevice(pContext); - alcMakeContextCurrent(nullptr); - alcDestroyContext(pContext); - alcCloseDevice(pDevice); + alcMakeContextCurrent(nullptr); + alcDestroyContext(pContext); + alcCloseDevice(pDevice); } void OpenALStream::SetVolume(int volume) { - fVolume = (float)volume / 100.0f; + fVolume = (float)volume / 100.0f; - if (uiSource) - alSourcef(uiSource, AL_GAIN, fVolume); + if (uiSource) + alSourcef(uiSource, AL_GAIN, fVolume); } void OpenALStream::Update() { - soundSyncEvent.Set(); + soundSyncEvent.Set(); } void OpenALStream::Clear(bool mute) { - m_muted = mute; + m_muted = mute; - if (m_muted) - { - soundTouch.clear(); - alSourceStop(uiSource); - } - else - { - alSourcePlay(uiSource); - } + if (m_muted) + { + soundTouch.clear(); + alSourceStop(uiSource); + } + else + { + alSourcePlay(uiSource); + } } void OpenALStream::SoundLoop() { - Common::SetCurrentThreadName("Audio thread - openal"); + Common::SetCurrentThreadName("Audio thread - openal"); - bool surround_capable = SConfig::GetInstance().bDPL2Decoder; + bool surround_capable = SConfig::GetInstance().bDPL2Decoder; #if defined(__APPLE__) - bool float32_capable = false; - const ALenum AL_FORMAT_STEREO_FLOAT32 = 0; - // OS X does not have the alext AL_FORMAT_51CHN32 yet. - surround_capable = false; - const ALenum AL_FORMAT_51CHN32 = 0; - const ALenum AL_FORMAT_51CHN16 = 0; + bool float32_capable = false; + const ALenum AL_FORMAT_STEREO_FLOAT32 = 0; + // OS X does not have the alext AL_FORMAT_51CHN32 yet. + surround_capable = false; + const ALenum AL_FORMAT_51CHN32 = 0; + const ALenum AL_FORMAT_51CHN16 = 0; #else - bool float32_capable = true; + bool float32_capable = true; #endif - u32 ulFrequency = m_mixer->GetSampleRate(); - numBuffers = SConfig::GetInstance().iLatency + 2; // OpenAL requires a minimum of two buffers + u32 ulFrequency = m_mixer->GetSampleRate(); + numBuffers = SConfig::GetInstance().iLatency + 2; // OpenAL requires a minimum of two buffers - memset(uiBuffers, 0, numBuffers * sizeof(ALuint)); - uiSource = 0; + memset(uiBuffers, 0, numBuffers * sizeof(ALuint)); + uiSource = 0; - // Checks if a X-Fi is being used. If it is, disable FLOAT32 support as this sound card has no support for it even though it reports it does. - if (strstr(alGetString(AL_RENDERER), "X-Fi")) - float32_capable = false; + // Checks if a X-Fi is being used. If it is, disable FLOAT32 support as this sound card has no + // support for it even though it reports it does. + if (strstr(alGetString(AL_RENDERER), "X-Fi")) + float32_capable = false; - // Generate some AL Buffers for streaming - alGenBuffers(numBuffers, (ALuint *)uiBuffers); - // Generate a Source to playback the Buffers - alGenSources(1, &uiSource); + // Generate some AL Buffers for streaming + alGenBuffers(numBuffers, (ALuint*)uiBuffers); + // Generate a Source to playback the Buffers + alGenSources(1, &uiSource); - // Short Silence - if (float32_capable) - memset(sampleBuffer, 0, OAL_MAX_SAMPLES * numBuffers * FRAME_SURROUND_FLOAT); - else - memset(sampleBuffer, 0, OAL_MAX_SAMPLES * numBuffers * FRAME_SURROUND_SHORT); + // Short Silence + if (float32_capable) + memset(sampleBuffer, 0, OAL_MAX_SAMPLES * numBuffers * FRAME_SURROUND_FLOAT); + else + memset(sampleBuffer, 0, OAL_MAX_SAMPLES * numBuffers * FRAME_SURROUND_SHORT); - memset(realtimeBuffer, 0, OAL_MAX_SAMPLES * FRAME_STEREO_SHORT); + memset(realtimeBuffer, 0, OAL_MAX_SAMPLES * FRAME_STEREO_SHORT); - for (int i = 0; i < numBuffers; i++) - { - if (surround_capable) - { - if (float32_capable) - alBufferData(uiBuffers[i], AL_FORMAT_51CHN32, sampleBuffer, 4 * FRAME_SURROUND_FLOAT, ulFrequency); - else - alBufferData(uiBuffers[i], AL_FORMAT_51CHN16, sampleBuffer, 4 * FRAME_SURROUND_SHORT, ulFrequency); - } - else - { - alBufferData(uiBuffers[i], AL_FORMAT_STEREO16, realtimeBuffer, 4 * FRAME_STEREO_SHORT, ulFrequency); - } - } - alSourceQueueBuffers(uiSource, numBuffers, uiBuffers); - alSourcePlay(uiSource); + for (int i = 0; i < numBuffers; i++) + { + if (surround_capable) + { + if (float32_capable) + alBufferData(uiBuffers[i], AL_FORMAT_51CHN32, sampleBuffer, 4 * FRAME_SURROUND_FLOAT, + ulFrequency); + else + alBufferData(uiBuffers[i], AL_FORMAT_51CHN16, sampleBuffer, 4 * FRAME_SURROUND_SHORT, + ulFrequency); + } + else + { + alBufferData(uiBuffers[i], AL_FORMAT_STEREO16, realtimeBuffer, 4 * FRAME_STEREO_SHORT, + ulFrequency); + } + } + alSourceQueueBuffers(uiSource, numBuffers, uiBuffers); + alSourcePlay(uiSource); - // Set the default sound volume as saved in the config file. - alSourcef(uiSource, AL_GAIN, fVolume); + // Set the default sound volume as saved in the config file. + alSourcef(uiSource, AL_GAIN, fVolume); - // TODO: Error handling - //ALenum err = alGetError(); + // TODO: Error handling + // ALenum err = alGetError(); - ALint iBuffersFilled = 0; - ALint iBuffersProcessed = 0; - ALint iState = 0; - ALuint uiBufferTemp[OAL_MAX_BUFFERS] = { 0 }; + ALint iBuffersFilled = 0; + ALint iBuffersProcessed = 0; + ALint iState = 0; + ALuint uiBufferTemp[OAL_MAX_BUFFERS] = {0}; - soundTouch.setChannels(2); - soundTouch.setSampleRate(ulFrequency); - soundTouch.setTempo(1.0); - soundTouch.setSetting(SETTING_USE_QUICKSEEK, 0); - soundTouch.setSetting(SETTING_USE_AA_FILTER, 0); - soundTouch.setSetting(SETTING_SEQUENCE_MS, 1); - soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 28); - soundTouch.setSetting(SETTING_OVERLAP_MS, 12); + soundTouch.setChannels(2); + soundTouch.setSampleRate(ulFrequency); + soundTouch.setTempo(1.0); + soundTouch.setSetting(SETTING_USE_QUICKSEEK, 0); + soundTouch.setSetting(SETTING_USE_AA_FILTER, 0); + soundTouch.setSetting(SETTING_SEQUENCE_MS, 1); + soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 28); + soundTouch.setSetting(SETTING_OVERLAP_MS, 12); - while (m_run_thread.load()) - { - // num_samples_to_render in this update - depends on SystemTimers::AUDIO_DMA_PERIOD. - const u32 stereo_16_bit_size = 4; - const u32 dma_length = 32; - const u64 ais_samples_per_second = 48000 * stereo_16_bit_size; - u64 audio_dma_period = SystemTimers::GetTicksPerSecond() / (AudioInterface::GetAIDSampleRate() * stereo_16_bit_size / dma_length); - u64 num_samples_to_render = (audio_dma_period * ais_samples_per_second) / SystemTimers::GetTicksPerSecond(); + while (m_run_thread.load()) + { + // num_samples_to_render in this update - depends on SystemTimers::AUDIO_DMA_PERIOD. + const u32 stereo_16_bit_size = 4; + const u32 dma_length = 32; + const u64 ais_samples_per_second = 48000 * stereo_16_bit_size; + u64 audio_dma_period = SystemTimers::GetTicksPerSecond() / + (AudioInterface::GetAIDSampleRate() * stereo_16_bit_size / dma_length); + u64 num_samples_to_render = + (audio_dma_period * ais_samples_per_second) / SystemTimers::GetTicksPerSecond(); - unsigned int numSamples = (unsigned int)num_samples_to_render; - unsigned int minSamples = surround_capable ? 240 : 0; // DPL2 accepts 240 samples minimum (FWRDURATION) + unsigned int numSamples = (unsigned int)num_samples_to_render; + unsigned int minSamples = + surround_capable ? 240 : 0; // DPL2 accepts 240 samples minimum (FWRDURATION) - numSamples = (numSamples > OAL_MAX_SAMPLES) ? OAL_MAX_SAMPLES : numSamples; - numSamples = m_mixer->Mix(realtimeBuffer, numSamples, false); + numSamples = (numSamples > OAL_MAX_SAMPLES) ? OAL_MAX_SAMPLES : numSamples; + numSamples = m_mixer->Mix(realtimeBuffer, numSamples, false); - // Convert the samples from short to float - float dest[OAL_MAX_SAMPLES * STEREO_CHANNELS]; - for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i) - dest[i] = (float)realtimeBuffer[i] / (1 << 15); + // Convert the samples from short to float + float dest[OAL_MAX_SAMPLES * STEREO_CHANNELS]; + for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i) + dest[i] = (float)realtimeBuffer[i] / (1 << 15); - soundTouch.putSamples(dest, numSamples); + soundTouch.putSamples(dest, numSamples); - if (iBuffersProcessed == iBuffersFilled) - { - alGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &iBuffersProcessed); - iBuffersFilled = 0; - } + if (iBuffersProcessed == iBuffersFilled) + { + alGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &iBuffersProcessed); + iBuffersFilled = 0; + } - if (iBuffersProcessed) - { - double rate = (double)m_mixer->GetCurrentSpeed(); - if (rate <= 0) - { - Core::RequestRefreshInfo(); - rate = (double)m_mixer->GetCurrentSpeed(); - } + if (iBuffersProcessed) + { + double rate = (double)m_mixer->GetCurrentSpeed(); + if (rate <= 0) + { + Core::RequestRefreshInfo(); + rate = (double)m_mixer->GetCurrentSpeed(); + } - // Place a lower limit of 10% speed. When a game boots up, there will be - // many silence samples. These do not need to be timestretched. - if (rate > 0.10) - { - soundTouch.setTempo(rate); - if (rate > 10) - { - soundTouch.clear(); - } - } + // Place a lower limit of 10% speed. When a game boots up, there will be + // many silence samples. These do not need to be timestretched. + if (rate > 0.10) + { + soundTouch.setTempo(rate); + if (rate > 10) + { + soundTouch.clear(); + } + } - unsigned int nSamples = soundTouch.receiveSamples(sampleBuffer, OAL_MAX_SAMPLES * numBuffers); + unsigned int nSamples = soundTouch.receiveSamples(sampleBuffer, OAL_MAX_SAMPLES * numBuffers); - if (nSamples <= minSamples) - continue; + if (nSamples <= minSamples) + continue; - // Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer) - if (iBuffersFilled == 0) - { - alSourceUnqueueBuffers(uiSource, iBuffersProcessed, uiBufferTemp); - ALenum err = alGetError(); - if (err != 0) - { - ERROR_LOG(AUDIO, "Error unqueuing buffers: %08x", err); - } - } + // Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued + // Buffer) + if (iBuffersFilled == 0) + { + alSourceUnqueueBuffers(uiSource, iBuffersProcessed, uiBufferTemp); + ALenum err = alGetError(); + if (err != 0) + { + ERROR_LOG(AUDIO, "Error unqueuing buffers: %08x", err); + } + } - if (surround_capable) - { - float dpl2[OAL_MAX_SAMPLES * OAL_MAX_BUFFERS * SURROUND_CHANNELS]; - DPL2Decode(sampleBuffer, nSamples, dpl2); + if (surround_capable) + { + float dpl2[OAL_MAX_SAMPLES * OAL_MAX_BUFFERS * SURROUND_CHANNELS]; + DPL2Decode(sampleBuffer, nSamples, dpl2); - // zero-out the subwoofer channel - DPL2Decode generates a pretty - // good 5.0 but not a good 5.1 output. Sadly there is not a 5.0 - // AL_FORMAT_50CHN32 to make this super-explicit. - // DPL2Decode output: LEFTFRONT, RIGHTFRONT, CENTREFRONT, (sub), LEFTREAR, RIGHTREAR - for (u32 i = 0; i < nSamples; ++i) - { - dpl2[i*SURROUND_CHANNELS + 3 /*sub/lfe*/] = 0.0f; - } + // zero-out the subwoofer channel - DPL2Decode generates a pretty + // good 5.0 but not a good 5.1 output. Sadly there is not a 5.0 + // AL_FORMAT_50CHN32 to make this super-explicit. + // DPL2Decode output: LEFTFRONT, RIGHTFRONT, CENTREFRONT, (sub), LEFTREAR, RIGHTREAR + for (u32 i = 0; i < nSamples; ++i) + { + dpl2[i * SURROUND_CHANNELS + 3 /*sub/lfe*/] = 0.0f; + } - if (float32_capable) - { - alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_51CHN32, dpl2, nSamples * FRAME_SURROUND_FLOAT, ulFrequency); - } - else - { - short surround_short[OAL_MAX_SAMPLES * SURROUND_CHANNELS * OAL_MAX_BUFFERS]; - for (u32 i = 0; i < nSamples * SURROUND_CHANNELS; ++i) - surround_short[i] = (short)((float)dpl2[i] * (1 << 15)); + if (float32_capable) + { + alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_51CHN32, dpl2, + nSamples * FRAME_SURROUND_FLOAT, ulFrequency); + } + else + { + short surround_short[OAL_MAX_SAMPLES * SURROUND_CHANNELS * OAL_MAX_BUFFERS]; + for (u32 i = 0; i < nSamples * SURROUND_CHANNELS; ++i) + surround_short[i] = (short)((float)dpl2[i] * (1 << 15)); - alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_51CHN16, surround_short, nSamples * FRAME_SURROUND_SHORT, ulFrequency); - } + alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_51CHN16, surround_short, + nSamples * FRAME_SURROUND_SHORT, ulFrequency); + } - ALenum err = alGetError(); - if (err == AL_INVALID_ENUM) - { - // 5.1 is not supported by the host, fallback to stereo - WARN_LOG(AUDIO, "Unable to set 5.1 surround mode. Updating OpenAL Soft might fix this issue."); - surround_capable = false; - } - else if (err != 0) - { - ERROR_LOG(AUDIO, "Error occurred while buffering data: %08x", err); - } - } + ALenum err = alGetError(); + if (err == AL_INVALID_ENUM) + { + // 5.1 is not supported by the host, fallback to stereo + WARN_LOG(AUDIO, + "Unable to set 5.1 surround mode. Updating OpenAL Soft might fix this issue."); + surround_capable = false; + } + else if (err != 0) + { + ERROR_LOG(AUDIO, "Error occurred while buffering data: %08x", err); + } + } - else - { - if (float32_capable) - { - alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO_FLOAT32, sampleBuffer, nSamples * FRAME_STEREO_FLOAT, ulFrequency); - ALenum err = alGetError(); - if (err == AL_INVALID_ENUM) - { - float32_capable = false; - } - else if (err != 0) - { - ERROR_LOG(AUDIO, "Error occurred while buffering float32 data: %08x", err); - } - } + else + { + if (float32_capable) + { + alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO_FLOAT32, sampleBuffer, + nSamples * FRAME_STEREO_FLOAT, ulFrequency); + ALenum err = alGetError(); + if (err == AL_INVALID_ENUM) + { + float32_capable = false; + } + else if (err != 0) + { + ERROR_LOG(AUDIO, "Error occurred while buffering float32 data: %08x", err); + } + } - else - { - // Convert the samples from float to short - short stereo[OAL_MAX_SAMPLES * STEREO_CHANNELS * OAL_MAX_BUFFERS]; - for (u32 i = 0; i < nSamples * STEREO_CHANNELS; ++i) - stereo[i] = (short)((float)sampleBuffer[i] * (1 << 15)); + else + { + // Convert the samples from float to short + short stereo[OAL_MAX_SAMPLES * STEREO_CHANNELS * OAL_MAX_BUFFERS]; + for (u32 i = 0; i < nSamples * STEREO_CHANNELS; ++i) + stereo[i] = (short)((float)sampleBuffer[i] * (1 << 15)); - alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO16, stereo, nSamples * FRAME_STEREO_SHORT, ulFrequency); - } - } + alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO16, stereo, + nSamples * FRAME_STEREO_SHORT, ulFrequency); + } + } - alSourceQueueBuffers(uiSource, 1, &uiBufferTemp[iBuffersFilled]); - ALenum err = alGetError(); - if (err != 0) - { - ERROR_LOG(AUDIO, "Error queuing buffers: %08x", err); - } - iBuffersFilled++; + alSourceQueueBuffers(uiSource, 1, &uiBufferTemp[iBuffersFilled]); + ALenum err = alGetError(); + if (err != 0) + { + ERROR_LOG(AUDIO, "Error queuing buffers: %08x", err); + } + iBuffersFilled++; - if (iBuffersFilled == numBuffers) - { - alSourcePlay(uiSource); - err = alGetError(); - if (err != 0) - { - ERROR_LOG(AUDIO, "Error occurred during playback: %08x", err); - } - } + if (iBuffersFilled == numBuffers) + { + alSourcePlay(uiSource); + err = alGetError(); + if (err != 0) + { + ERROR_LOG(AUDIO, "Error occurred during playback: %08x", err); + } + } - alGetSourcei(uiSource, AL_SOURCE_STATE, &iState); - if (iState != AL_PLAYING) - { - // Buffer underrun occurred, resume playback - alSourcePlay(uiSource); - err = alGetError(); - if (err != 0) - { - ERROR_LOG(AUDIO, "Error occurred resuming playback: %08x", err); - } - } - } - else - { - soundSyncEvent.Wait(); - } - } + alGetSourcei(uiSource, AL_SOURCE_STATE, &iState); + if (iState != AL_PLAYING) + { + // Buffer underrun occurred, resume playback + alSourcePlay(uiSource); + err = alGetError(); + if (err != 0) + { + ERROR_LOG(AUDIO, "Error occurred resuming playback: %08x", err); + } + } + } + else + { + soundSyncEvent.Wait(); + } + } } -#endif //HAVE_OPENAL - +#endif // HAVE_OPENAL diff --git a/Source/Core/AudioCommon/OpenALStream.h b/Source/Core/AudioCommon/OpenALStream.h index 4e0389eb30..5528a7cdf5 100644 --- a/Source/Core/AudioCommon/OpenALStream.h +++ b/Source/Core/AudioCommon/OpenALStream.h @@ -32,56 +32,52 @@ #define BOOL SoundTouch_BOOL #endif -#include #include +#include #ifdef __APPLE__ #undef BOOL #endif // 16 bit Stereo -#define SFX_MAX_SOURCE 1 -#define OAL_MAX_BUFFERS 32 -#define OAL_MAX_SAMPLES 256 -#define STEREO_CHANNELS 2 -#define SURROUND_CHANNELS 6 // number of channels in surround mode -#define SIZE_SHORT 2 -#define SIZE_FLOAT 4 // size of a float in bytes -#define FRAME_STEREO_SHORT STEREO_CHANNELS * SIZE_SHORT -#define FRAME_STEREO_FLOAT STEREO_CHANNELS * SIZE_FLOAT -#define FRAME_SURROUND_FLOAT SURROUND_CHANNELS * SIZE_FLOAT -#define FRAME_SURROUND_SHORT SURROUND_CHANNELS * SIZE_SHORT +#define SFX_MAX_SOURCE 1 +#define OAL_MAX_BUFFERS 32 +#define OAL_MAX_SAMPLES 256 +#define STEREO_CHANNELS 2 +#define SURROUND_CHANNELS 6 // number of channels in surround mode +#define SIZE_SHORT 2 +#define SIZE_FLOAT 4 // size of a float in bytes +#define FRAME_STEREO_SHORT STEREO_CHANNELS* SIZE_SHORT +#define FRAME_STEREO_FLOAT STEREO_CHANNELS* SIZE_FLOAT +#define FRAME_SURROUND_FLOAT SURROUND_CHANNELS* SIZE_FLOAT +#define FRAME_SURROUND_SHORT SURROUND_CHANNELS* SIZE_SHORT #endif class OpenALStream final : public SoundStream { #if defined HAVE_OPENAL && HAVE_OPENAL public: - OpenALStream() : uiSource(0) - { - } - - bool Start() override; - void SoundLoop() override; - void SetVolume(int volume) override; - void Stop() override; - void Clear(bool mute) override; - void Update() override; - - static bool isValid() { return true; } + OpenALStream() : uiSource(0) {} + bool Start() override; + void SoundLoop() override; + void SetVolume(int volume) override; + void Stop() override; + void Clear(bool mute) override; + void Update() override; + static bool isValid() { return true; } private: - std::thread thread; - std::atomic m_run_thread; + std::thread thread; + std::atomic m_run_thread; - Common::Event soundSyncEvent; + Common::Event soundSyncEvent; - short realtimeBuffer[OAL_MAX_SAMPLES * STEREO_CHANNELS]; - soundtouch::SAMPLETYPE sampleBuffer[OAL_MAX_SAMPLES * SURROUND_CHANNELS * OAL_MAX_BUFFERS]; - ALuint uiBuffers[OAL_MAX_BUFFERS]; - ALuint uiSource; - ALfloat fVolume; + short realtimeBuffer[OAL_MAX_SAMPLES * STEREO_CHANNELS]; + soundtouch::SAMPLETYPE sampleBuffer[OAL_MAX_SAMPLES * SURROUND_CHANNELS * OAL_MAX_BUFFERS]; + ALuint uiBuffers[OAL_MAX_BUFFERS]; + ALuint uiSource; + ALfloat fVolume; - u8 numBuffers; -#endif // HAVE_OPENAL + u8 numBuffers; +#endif // HAVE_OPENAL }; diff --git a/Source/Core/AudioCommon/OpenSLESStream.cpp b/Source/Core/AudioCommon/OpenSLESStream.cpp index 9c02338fa5..339af3a5ad 100644 --- a/Source/Core/AudioCommon/OpenSLESStream.cpp +++ b/Source/Core/AudioCommon/OpenSLESStream.cpp @@ -24,7 +24,7 @@ static SLPlayItf bqPlayerPlay; static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue; static SLMuteSoloItf bqPlayerMuteSolo; static SLVolumeItf bqPlayerVolume; -static CMixer *g_mixer; +static CMixer* g_mixer; #define BUFFER_SIZE 512 #define BUFFER_SIZE_IN_SAMPLES (BUFFER_SIZE / 2) @@ -32,106 +32,107 @@ static CMixer *g_mixer; static short buffer[2][BUFFER_SIZE]; static int curBuffer = 0; -static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) +static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context) { - assert(bq == bqPlayerBufferQueue); - assert(nullptr == context); + assert(bq == bqPlayerBufferQueue); + assert(nullptr == context); - // Render to the fresh buffer - g_mixer->Mix(reinterpret_cast(buffer[curBuffer]), BUFFER_SIZE_IN_SAMPLES); - SLresult result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[curBuffer], sizeof(buffer[0])); - curBuffer ^= 1; // Switch buffer + // Render to the fresh buffer + g_mixer->Mix(reinterpret_cast(buffer[curBuffer]), BUFFER_SIZE_IN_SAMPLES); + SLresult result = + (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[curBuffer], sizeof(buffer[0])); + curBuffer ^= 1; // Switch buffer - // Comment from sample code: - // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT, - // which for this code example would indicate a programming error - _assert_msg_(AUDIO, SL_RESULT_SUCCESS == result, "Couldn't enqueue audio stream."); + // Comment from sample code: + // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT, + // which for this code example would indicate a programming error + _assert_msg_(AUDIO, SL_RESULT_SUCCESS == result, "Couldn't enqueue audio stream."); } bool OpenSLESStream::Start() { - SLresult result; - // create engine - result = slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr); - assert(SL_RESULT_SUCCESS == result); - result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); - assert(SL_RESULT_SUCCESS == result); - result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); - assert(SL_RESULT_SUCCESS == result); - result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, 0, 0); - assert(SL_RESULT_SUCCESS == result); - result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); - assert(SL_RESULT_SUCCESS == result); + SLresult result; + // create engine + result = slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr); + assert(SL_RESULT_SUCCESS == result); + result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); + assert(SL_RESULT_SUCCESS == result); + result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); + assert(SL_RESULT_SUCCESS == result); + result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, 0, 0); + assert(SL_RESULT_SUCCESS == result); + result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); + assert(SL_RESULT_SUCCESS == result); - SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; - SLDataFormat_PCM format_pcm = { - SL_DATAFORMAT_PCM, - 2, - m_mixer->GetSampleRate() * 1000, - SL_PCMSAMPLEFORMAT_FIXED_16, - SL_PCMSAMPLEFORMAT_FIXED_16, - SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, - SL_BYTEORDER_LITTLEENDIAN - }; + SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; + SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, + 2, + m_mixer->GetSampleRate() * 1000, + SL_PCMSAMPLEFORMAT_FIXED_16, + SL_PCMSAMPLEFORMAT_FIXED_16, + SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, + SL_BYTEORDER_LITTLEENDIAN}; - SLDataSource audioSrc = {&loc_bufq, &format_pcm}; + SLDataSource audioSrc = {&loc_bufq, &format_pcm}; - // configure audio sink - SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; - SLDataSink audioSnk = {&loc_outmix, nullptr}; + // configure audio sink + SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; + SLDataSink audioSnk = {&loc_outmix, nullptr}; - // create audio player - const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME}; - const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; - result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req); - assert(SL_RESULT_SUCCESS == result); + // create audio player + const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME}; + const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; + result = + (*engineEngine) + ->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req); + assert(SL_RESULT_SUCCESS == result); - result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE); - assert(SL_RESULT_SUCCESS == result); - result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay); - assert(SL_RESULT_SUCCESS == result); - result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, - &bqPlayerBufferQueue); - assert(SL_RESULT_SUCCESS == result); - result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, nullptr); - assert(SL_RESULT_SUCCESS == result); - result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); - assert(SL_RESULT_SUCCESS == result); + result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE); + assert(SL_RESULT_SUCCESS == result); + result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay); + assert(SL_RESULT_SUCCESS == result); + result = + (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, &bqPlayerBufferQueue); + assert(SL_RESULT_SUCCESS == result); + result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, nullptr); + assert(SL_RESULT_SUCCESS == result); + result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); + assert(SL_RESULT_SUCCESS == result); - // Render and enqueue a first buffer. - curBuffer ^= 1; - g_mixer = m_mixer.get(); + // Render and enqueue a first buffer. + curBuffer ^= 1; + g_mixer = m_mixer.get(); - result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[0], sizeof(buffer[0])); - if (SL_RESULT_SUCCESS != result) - return false; + result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[0], sizeof(buffer[0])); + if (SL_RESULT_SUCCESS != result) + return false; - return true; + return true; } void OpenSLESStream::Stop() { - if (bqPlayerObject != nullptr) - { - (*bqPlayerObject)->Destroy(bqPlayerObject); - bqPlayerObject = nullptr; - bqPlayerPlay = nullptr; - bqPlayerBufferQueue = nullptr; - bqPlayerMuteSolo = nullptr; - bqPlayerVolume = nullptr; - } + if (bqPlayerObject != nullptr) + { + (*bqPlayerObject)->Destroy(bqPlayerObject); + bqPlayerObject = nullptr; + bqPlayerPlay = nullptr; + bqPlayerBufferQueue = nullptr; + bqPlayerMuteSolo = nullptr; + bqPlayerVolume = nullptr; + } - if (outputMixObject != nullptr) - { - (*outputMixObject)->Destroy(outputMixObject); - outputMixObject = nullptr; - } + if (outputMixObject != nullptr) + { + (*outputMixObject)->Destroy(outputMixObject); + outputMixObject = nullptr; + } - if (engineObject != nullptr) - { - (*engineObject)->Destroy(engineObject); - engineObject = nullptr; - engineEngine = nullptr; - } + if (engineObject != nullptr) + { + (*engineObject)->Destroy(engineObject); + engineObject = nullptr; + engineEngine = nullptr; + } } #endif diff --git a/Source/Core/AudioCommon/OpenSLESStream.h b/Source/Core/AudioCommon/OpenSLESStream.h index d56b0dfd97..0521f0e2e5 100644 --- a/Source/Core/AudioCommon/OpenSLESStream.h +++ b/Source/Core/AudioCommon/OpenSLESStream.h @@ -13,12 +13,11 @@ class OpenSLESStream final : public SoundStream { #ifdef ANDROID public: - bool Start() override; - void Stop() override; - static bool isValid() { return true; } - + bool Start() override; + void Stop() override; + static bool isValid() { return true; } private: - std::thread thread; - Common::Event soundSyncEvent; -#endif // HAVE_OPENSL + std::thread thread; + Common::Event soundSyncEvent; +#endif // HAVE_OPENSL }; diff --git a/Source/Core/AudioCommon/PulseAudioStream.cpp b/Source/Core/AudioCommon/PulseAudioStream.cpp index 544d377f64..7ada6478bd 100644 --- a/Source/Core/AudioCommon/PulseAudioStream.cpp +++ b/Source/Core/AudioCommon/PulseAudioStream.cpp @@ -7,245 +7,247 @@ #include "AudioCommon/DPL2Decoder.h" #include "AudioCommon/PulseAudioStream.h" #include "Common/CommonTypes.h" -#include "Common/Thread.h" #include "Common/Logging/Log.h" +#include "Common/Thread.h" #include "Core/ConfigManager.h" namespace { -const size_t BUFFER_SAMPLES = 512; // ~10 ms - needs to be at least 240 for surround +const size_t BUFFER_SAMPLES = 512; // ~10 ms - needs to be at least 240 for surround } -PulseAudio::PulseAudio() - : m_thread() - , m_run_thread() +PulseAudio::PulseAudio() : m_thread(), m_run_thread() { } bool PulseAudio::Start() { - m_stereo = !SConfig::GetInstance().bDPL2Decoder; - m_channels = m_stereo ? 2 : 5; // will tell PA we use a Stereo or 5.0 channel setup + m_stereo = !SConfig::GetInstance().bDPL2Decoder; + m_channels = m_stereo ? 2 : 5; // will tell PA we use a Stereo or 5.0 channel setup - NOTICE_LOG(AUDIO, "PulseAudio backend using %d channels", m_channels); + NOTICE_LOG(AUDIO, "PulseAudio backend using %d channels", m_channels); - m_run_thread = true; - m_thread = std::thread(&PulseAudio::SoundLoop, this); + m_run_thread = true; + m_thread = std::thread(&PulseAudio::SoundLoop, this); - // Initialize DPL2 parameters - DPL2Reset(); + // Initialize DPL2 parameters + DPL2Reset(); - return true; + return true; } void PulseAudio::Stop() { - m_run_thread = false; - m_thread.join(); + m_run_thread = false; + m_thread.join(); } void PulseAudio::Update() { - // don't need to do anything here. + // don't need to do anything here. } // Called on audio thread. void PulseAudio::SoundLoop() { - Common::SetCurrentThreadName("Audio thread - pulse"); + Common::SetCurrentThreadName("Audio thread - pulse"); - if (PulseInit()) - { - while (m_run_thread.load() && m_pa_connected == 1 && m_pa_error >= 0) - m_pa_error = pa_mainloop_iterate(m_pa_ml, 1, nullptr); + if (PulseInit()) + { + while (m_run_thread.load() && m_pa_connected == 1 && m_pa_error >= 0) + m_pa_error = pa_mainloop_iterate(m_pa_ml, 1, nullptr); - if (m_pa_error < 0) - ERROR_LOG(AUDIO, "PulseAudio error: %s", pa_strerror(m_pa_error)); + if (m_pa_error < 0) + ERROR_LOG(AUDIO, "PulseAudio error: %s", pa_strerror(m_pa_error)); - PulseShutdown(); - } + PulseShutdown(); + } } bool PulseAudio::PulseInit() { - m_pa_error = 0; - m_pa_connected = 0; + m_pa_error = 0; + m_pa_connected = 0; - // create pulseaudio main loop and context - // also register the async state callback which is called when the connection to the pa server has changed - m_pa_ml = pa_mainloop_new(); - m_pa_mlapi = pa_mainloop_get_api(m_pa_ml); - m_pa_ctx = pa_context_new(m_pa_mlapi, "dolphin-emu"); - m_pa_error = pa_context_connect(m_pa_ctx, nullptr, PA_CONTEXT_NOFLAGS, nullptr); - pa_context_set_state_callback(m_pa_ctx, StateCallback, this); + // create pulseaudio main loop and context + // also register the async state callback which is called when the connection to the pa server has + // changed + m_pa_ml = pa_mainloop_new(); + m_pa_mlapi = pa_mainloop_get_api(m_pa_ml); + m_pa_ctx = pa_context_new(m_pa_mlapi, "dolphin-emu"); + m_pa_error = pa_context_connect(m_pa_ctx, nullptr, PA_CONTEXT_NOFLAGS, nullptr); + pa_context_set_state_callback(m_pa_ctx, StateCallback, this); - // wait until we're connected to the pulseaudio server - while (m_pa_connected == 0 && m_pa_error >= 0) - m_pa_error = pa_mainloop_iterate(m_pa_ml, 1, nullptr); + // wait until we're connected to the pulseaudio server + while (m_pa_connected == 0 && m_pa_error >= 0) + m_pa_error = pa_mainloop_iterate(m_pa_ml, 1, nullptr); - if (m_pa_connected == 2 || m_pa_error < 0) - { - ERROR_LOG(AUDIO, "PulseAudio failed to initialize: %s", pa_strerror(m_pa_error)); - return false; - } + if (m_pa_connected == 2 || m_pa_error < 0) + { + ERROR_LOG(AUDIO, "PulseAudio failed to initialize: %s", pa_strerror(m_pa_error)); + return false; + } - // create a new audio stream with our sample format - // also connect the callbacks for this stream - pa_sample_spec ss; - pa_channel_map channel_map; - pa_channel_map* channel_map_p = nullptr; // auto channel map - if (m_stereo) - { - ss.format = PA_SAMPLE_S16LE; - m_bytespersample = sizeof(s16); - } - else - { - // surround is remixed in floats, use a float PA buffer to save another conversion - ss.format = PA_SAMPLE_FLOAT32NE; - m_bytespersample = sizeof(float); + // create a new audio stream with our sample format + // also connect the callbacks for this stream + pa_sample_spec ss; + pa_channel_map channel_map; + pa_channel_map* channel_map_p = nullptr; // auto channel map + if (m_stereo) + { + ss.format = PA_SAMPLE_S16LE; + m_bytespersample = sizeof(s16); + } + else + { + // surround is remixed in floats, use a float PA buffer to save another conversion + ss.format = PA_SAMPLE_FLOAT32NE; + m_bytespersample = sizeof(float); - channel_map_p = &channel_map; // explicit channel map: - channel_map.channels = 5; - channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - channel_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; - channel_map.map[3] = PA_CHANNEL_POSITION_REAR_LEFT; - channel_map.map[4] = PA_CHANNEL_POSITION_REAR_RIGHT; - } - ss.channels = m_channels; - ss.rate = m_mixer->GetSampleRate(); - assert(pa_sample_spec_valid(&ss)); - m_pa_s = pa_stream_new(m_pa_ctx, "Playback", &ss, channel_map_p); - pa_stream_set_write_callback(m_pa_s, WriteCallback, this); - pa_stream_set_underflow_callback(m_pa_s, UnderflowCallback, this); + channel_map_p = &channel_map; // explicit channel map: + channel_map.channels = 5; + channel_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + channel_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + channel_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; + channel_map.map[3] = PA_CHANNEL_POSITION_REAR_LEFT; + channel_map.map[4] = PA_CHANNEL_POSITION_REAR_RIGHT; + } + ss.channels = m_channels; + ss.rate = m_mixer->GetSampleRate(); + assert(pa_sample_spec_valid(&ss)); + m_pa_s = pa_stream_new(m_pa_ctx, "Playback", &ss, channel_map_p); + pa_stream_set_write_callback(m_pa_s, WriteCallback, this); + pa_stream_set_underflow_callback(m_pa_s, UnderflowCallback, this); - // connect this audio stream to the default audio playback - // limit buffersize to reduce latency - m_pa_ba.fragsize = -1; - m_pa_ba.maxlength = -1; // max buffer, so also max latency - m_pa_ba.minreq = -1; // don't read every byte, try to group them _a bit_ - m_pa_ba.prebuf = -1; // start as early as possible - m_pa_ba.tlength = BUFFER_SAMPLES * m_channels * m_bytespersample; // designed latency, only change this flag for low latency output - pa_stream_flags flags = pa_stream_flags(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE); - m_pa_error = pa_stream_connect_playback(m_pa_s, nullptr, &m_pa_ba, flags, nullptr, nullptr); - if (m_pa_error < 0) - { - ERROR_LOG(AUDIO, "PulseAudio failed to initialize: %s", pa_strerror(m_pa_error)); - return false; - } + // connect this audio stream to the default audio playback + // limit buffersize to reduce latency + m_pa_ba.fragsize = -1; + m_pa_ba.maxlength = -1; // max buffer, so also max latency + m_pa_ba.minreq = -1; // don't read every byte, try to group them _a bit_ + m_pa_ba.prebuf = -1; // start as early as possible + m_pa_ba.tlength = + BUFFER_SAMPLES * m_channels * + m_bytespersample; // designed latency, only change this flag for low latency output + pa_stream_flags flags = pa_stream_flags(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | + PA_STREAM_AUTO_TIMING_UPDATE); + m_pa_error = pa_stream_connect_playback(m_pa_s, nullptr, &m_pa_ba, flags, nullptr, nullptr); + if (m_pa_error < 0) + { + ERROR_LOG(AUDIO, "PulseAudio failed to initialize: %s", pa_strerror(m_pa_error)); + return false; + } - INFO_LOG(AUDIO, "Pulse successfully initialized"); - return true; + INFO_LOG(AUDIO, "Pulse successfully initialized"); + return true; } void PulseAudio::PulseShutdown() { - pa_context_disconnect(m_pa_ctx); - pa_context_unref(m_pa_ctx); - pa_mainloop_free(m_pa_ml); + pa_context_disconnect(m_pa_ctx); + pa_context_unref(m_pa_ctx); + pa_mainloop_free(m_pa_ml); } void PulseAudio::StateCallback(pa_context* c) { - pa_context_state_t state = pa_context_get_state(c); - switch (state) - { - case PA_CONTEXT_FAILED: - case PA_CONTEXT_TERMINATED: - m_pa_connected = 2; - break; - case PA_CONTEXT_READY: - m_pa_connected = 1; - break; - default: - break; - } + pa_context_state_t state = pa_context_get_state(c); + switch (state) + { + case PA_CONTEXT_FAILED: + case PA_CONTEXT_TERMINATED: + m_pa_connected = 2; + break; + case PA_CONTEXT_READY: + m_pa_connected = 1; + break; + default: + break; + } } // on underflow, increase pulseaudio latency in ~10ms steps void PulseAudio::UnderflowCallback(pa_stream* s) { - m_pa_ba.tlength += BUFFER_SAMPLES * m_channels * m_bytespersample; - pa_operation* op = pa_stream_set_buffer_attr(s, &m_pa_ba, nullptr, nullptr); - pa_operation_unref(op); + m_pa_ba.tlength += BUFFER_SAMPLES * m_channels * m_bytespersample; + pa_operation* op = pa_stream_set_buffer_attr(s, &m_pa_ba, nullptr, nullptr); + pa_operation_unref(op); - WARN_LOG(AUDIO, "pulseaudio underflow, new latency: %d bytes", m_pa_ba.tlength); + WARN_LOG(AUDIO, "pulseaudio underflow, new latency: %d bytes", m_pa_ba.tlength); } void PulseAudio::WriteCallback(pa_stream* s, size_t length) { - int bytes_per_frame = m_channels * m_bytespersample; - int frames = (length / bytes_per_frame); - size_t trunc_length = frames * bytes_per_frame; + int bytes_per_frame = m_channels * m_bytespersample; + int frames = (length / bytes_per_frame); + size_t trunc_length = frames * bytes_per_frame; - // fetch dst buffer directly from pulseaudio, so no memcpy is needed - void* buffer; - m_pa_error = pa_stream_begin_write(s, &buffer, &trunc_length); + // fetch dst buffer directly from pulseaudio, so no memcpy is needed + void* buffer; + m_pa_error = pa_stream_begin_write(s, &buffer, &trunc_length); - if (!buffer || m_pa_error < 0) - return; // error will be printed from main loop + if (!buffer || m_pa_error < 0) + return; // error will be printed from main loop - if (m_stereo) - { - // use the raw s16 stereo mix - m_mixer->Mix((s16*) buffer, frames); - } - else - { - // get a floating point mix - s16 s16buffer_stereo[frames * 2]; - m_mixer->Mix(s16buffer_stereo, frames); // implicitly mixes to 16-bit stereo + if (m_stereo) + { + // use the raw s16 stereo mix + m_mixer->Mix((s16*)buffer, frames); + } + else + { + // get a floating point mix + s16 s16buffer_stereo[frames * 2]; + m_mixer->Mix(s16buffer_stereo, frames); // implicitly mixes to 16-bit stereo - float floatbuffer_stereo[frames * 2]; - // s16 to float - for (int i=0; i < frames * 2; ++i) - { - floatbuffer_stereo[i] = s16buffer_stereo[i] / float(1 << 15); - } + float floatbuffer_stereo[frames * 2]; + // s16 to float + for (int i = 0; i < frames * 2; ++i) + { + floatbuffer_stereo[i] = s16buffer_stereo[i] / float(1 << 15); + } - if (m_channels == 5) // Extract dpl2/5.0 Surround - { - float floatbuffer_6chan[frames * 6]; - // DPL2Decode output: LEFTFRONT, RIGHTFRONT, CENTREFRONT, (sub), LEFTREAR, RIGHTREAR - DPL2Decode(floatbuffer_stereo, frames, floatbuffer_6chan); + if (m_channels == 5) // Extract dpl2/5.0 Surround + { + float floatbuffer_6chan[frames * 6]; + // DPL2Decode output: LEFTFRONT, RIGHTFRONT, CENTREFRONT, (sub), LEFTREAR, RIGHTREAR + DPL2Decode(floatbuffer_stereo, frames, floatbuffer_6chan); - // Discard the subwoofer channel - DPL2Decode generates a pretty - // good 5.0 but not a good 5.1 output. - const int dpl2_to_5chan[] = {0,1,2,4,5}; - for (int i=0; i < frames; ++i) - { - for (int j=0; j < m_channels; ++j) - { - ((float*)buffer)[m_channels * i + j] = floatbuffer_6chan[6 * i + dpl2_to_5chan[j]]; - } - } - } - else - { - ERROR_LOG(AUDIO, "Unsupported number of PA channels requested: %d", (int)m_channels); - return; - } - } + // Discard the subwoofer channel - DPL2Decode generates a pretty + // good 5.0 but not a good 5.1 output. + const int dpl2_to_5chan[] = {0, 1, 2, 4, 5}; + for (int i = 0; i < frames; ++i) + { + for (int j = 0; j < m_channels; ++j) + { + ((float*)buffer)[m_channels * i + j] = floatbuffer_6chan[6 * i + dpl2_to_5chan[j]]; + } + } + } + else + { + ERROR_LOG(AUDIO, "Unsupported number of PA channels requested: %d", (int)m_channels); + return; + } + } - m_pa_error = pa_stream_write(s, buffer, trunc_length, nullptr, 0, PA_SEEK_RELATIVE); + m_pa_error = pa_stream_write(s, buffer, trunc_length, nullptr, 0, PA_SEEK_RELATIVE); } // Callbacks that forward to internal methods (required because PulseAudio is a C API). void PulseAudio::StateCallback(pa_context* c, void* userdata) { - PulseAudio* p = (PulseAudio*) userdata; - p->StateCallback(c); + PulseAudio* p = (PulseAudio*)userdata; + p->StateCallback(c); } void PulseAudio::UnderflowCallback(pa_stream* s, void* userdata) { - PulseAudio* p = (PulseAudio*) userdata; - p->UnderflowCallback(s); + PulseAudio* p = (PulseAudio*)userdata; + p->UnderflowCallback(s); } void PulseAudio::WriteCallback(pa_stream* s, size_t length, void* userdata) { - PulseAudio* p = (PulseAudio*) userdata; - p->WriteCallback(s, length); + PulseAudio* p = (PulseAudio*)userdata; + p->WriteCallback(s, length); } diff --git a/Source/Core/AudioCommon/PulseAudioStream.h b/Source/Core/AudioCommon/PulseAudioStream.h index b47c580caa..b2c1a58414 100644 --- a/Source/Core/AudioCommon/PulseAudioStream.h +++ b/Source/Core/AudioCommon/PulseAudioStream.h @@ -18,42 +18,41 @@ class PulseAudio final : public SoundStream { #if defined(HAVE_PULSEAUDIO) && HAVE_PULSEAUDIO public: - PulseAudio(); + PulseAudio(); - bool Start() override; - void Stop() override; - void Update() override; + bool Start() override; + void Stop() override; + void Update() override; - static bool isValid() { return true; } - - void StateCallback(pa_context *c); - void WriteCallback(pa_stream *s, size_t length); - void UnderflowCallback(pa_stream *s); + static bool isValid() { return true; } + void StateCallback(pa_context* c); + void WriteCallback(pa_stream* s, size_t length); + void UnderflowCallback(pa_stream* s); private: - void SoundLoop() override; + void SoundLoop() override; - bool PulseInit(); - void PulseShutdown(); + bool PulseInit(); + void PulseShutdown(); - // wrapper callback functions, last parameter _must_ be PulseAudio* - static void StateCallback(pa_context *c, void *userdata); - static void WriteCallback(pa_stream *s, size_t length, void *userdata); - static void UnderflowCallback(pa_stream *s, void *userdata); + // wrapper callback functions, last parameter _must_ be PulseAudio* + static void StateCallback(pa_context* c, void* userdata); + static void WriteCallback(pa_stream* s, size_t length, void* userdata); + static void UnderflowCallback(pa_stream* s, void* userdata); - std::thread m_thread; - std::atomic m_run_thread; + std::thread m_thread; + std::atomic m_run_thread; - bool m_stereo; // stereo, else surround - int m_bytespersample; - int m_channels; + bool m_stereo; // stereo, else surround + int m_bytespersample; + int m_channels; - int m_pa_error; - int m_pa_connected; - pa_mainloop *m_pa_ml; - pa_mainloop_api *m_pa_mlapi; - pa_context *m_pa_ctx; - pa_stream *m_pa_s; - pa_buffer_attr m_pa_ba; + int m_pa_error; + int m_pa_connected; + pa_mainloop* m_pa_ml; + pa_mainloop_api* m_pa_mlapi; + pa_context* m_pa_ctx; + pa_stream* m_pa_s; + pa_buffer_attr m_pa_ba; #endif }; diff --git a/Source/Core/AudioCommon/SoundStream.h b/Source/Core/AudioCommon/SoundStream.h index db7070890f..7253a49a96 100644 --- a/Source/Core/AudioCommon/SoundStream.h +++ b/Source/Core/AudioCommon/SoundStream.h @@ -14,51 +14,49 @@ class SoundStream { protected: - std::unique_ptr m_mixer; - bool m_logAudio; - WaveFileWriter g_wave_writer; - bool m_muted; + std::unique_ptr m_mixer; + bool m_logAudio; + WaveFileWriter g_wave_writer; + bool m_muted; public: - SoundStream() : m_mixer(new CMixer(48000)), m_logAudio(false), m_muted(false) {} - virtual ~SoundStream() { } + SoundStream() : m_mixer(new CMixer(48000)), m_logAudio(false), m_muted(false) {} + virtual ~SoundStream() {} + static bool isValid() { return false; } + CMixer* GetMixer() const { return m_mixer.get(); } + virtual bool Start() { return false; } + virtual void SetVolume(int) {} + virtual void SoundLoop() {} + virtual void Stop() {} + virtual void Update() {} + virtual void Clear(bool mute) { m_muted = mute; } + bool IsMuted() const { return m_muted; } + void StartLogAudio(const std::string& filename) + { + if (!m_logAudio) + { + m_logAudio = true; + g_wave_writer.Start(filename, m_mixer->GetSampleRate()); + g_wave_writer.SetSkipSilence(false); + NOTICE_LOG(AUDIO, "Starting Audio logging"); + } + else + { + WARN_LOG(AUDIO, "Audio logging already started"); + } + } - static bool isValid() { return false; } - CMixer* GetMixer() const { return m_mixer.get(); } - virtual bool Start() { return false; } - virtual void SetVolume(int) {} - virtual void SoundLoop() {} - virtual void Stop() {} - virtual void Update() {} - virtual void Clear(bool mute) { m_muted = mute; } - bool IsMuted() const { return m_muted; } - - void StartLogAudio(const std::string& filename) - { - if (!m_logAudio) - { - m_logAudio = true; - g_wave_writer.Start(filename, m_mixer->GetSampleRate()); - g_wave_writer.SetSkipSilence(false); - NOTICE_LOG(AUDIO, "Starting Audio logging"); - } - else - { - WARN_LOG(AUDIO, "Audio logging already started"); - } - } - - void StopLogAudio() - { - if (m_logAudio) - { - m_logAudio = false; - g_wave_writer.Stop(); - NOTICE_LOG(AUDIO, "Stopping Audio logging"); - } - else - { - WARN_LOG(AUDIO, "Audio logging already stopped"); - } - } + void StopLogAudio() + { + if (m_logAudio) + { + m_logAudio = false; + g_wave_writer.Stop(); + NOTICE_LOG(AUDIO, "Stopping Audio logging"); + } + else + { + WARN_LOG(AUDIO, "Audio logging already stopped"); + } + } }; diff --git a/Source/Core/AudioCommon/WaveFile.cpp b/Source/Core/AudioCommon/WaveFile.cpp index 16089db8e3..96463158b7 100644 --- a/Source/Core/AudioCommon/WaveFile.cpp +++ b/Source/Core/AudioCommon/WaveFile.cpp @@ -17,127 +17,130 @@ WaveFileWriter::WaveFileWriter() WaveFileWriter::~WaveFileWriter() { - Stop(); + Stop(); } bool WaveFileWriter::Start(const std::string& filename, unsigned int HLESampleRate) { - // Check if the file is already open - if (file) - { - PanicAlertT("The file %s was already open, the file header will not be written.", filename.c_str()); - return false; - } + // Check if the file is already open + if (file) + { + PanicAlertT("The file %s was already open, the file header will not be written.", + filename.c_str()); + return false; + } - file.Open(filename, "wb"); - if (!file) - { - PanicAlertT("The file %s could not be opened for writing. Please check if it's already opened by another program.", filename.c_str()); - return false; - } + file.Open(filename, "wb"); + if (!file) + { + PanicAlertT("The file %s could not be opened for writing. Please check if it's already opened " + "by another program.", + filename.c_str()); + return false; + } - audio_size = 0; + audio_size = 0; - // ----------------- - // Write file header - // ----------------- - Write4("RIFF"); - Write(100 * 1000 * 1000); // write big value in case the file gets truncated - Write4("WAVE"); - Write4("fmt "); + // ----------------- + // Write file header + // ----------------- + Write4("RIFF"); + Write(100 * 1000 * 1000); // write big value in case the file gets truncated + Write4("WAVE"); + Write4("fmt "); - Write(16); // size of fmt block - Write(0x00020001); //two channels, uncompressed + Write(16); // size of fmt block + Write(0x00020001); // two channels, uncompressed - const u32 sample_rate = HLESampleRate; - Write(sample_rate); - Write(sample_rate * 2 * 2); //two channels, 16bit + const u32 sample_rate = HLESampleRate; + Write(sample_rate); + Write(sample_rate * 2 * 2); // two channels, 16bit - Write(0x00100004); - Write4("data"); - Write(100 * 1000 * 1000 - 32); + Write(0x00100004); + Write4("data"); + Write(100 * 1000 * 1000 - 32); - // We are now at offset 44 - if (file.Tell() != 44) - PanicAlert("Wrong offset: %lld", (long long)file.Tell()); + // We are now at offset 44 + if (file.Tell() != 44) + PanicAlert("Wrong offset: %lld", (long long)file.Tell()); - return true; + return true; } void WaveFileWriter::Stop() { - // u32 file_size = (u32)ftello(file); - file.Seek(4, SEEK_SET); - Write(audio_size + 36); + // u32 file_size = (u32)ftello(file); + file.Seek(4, SEEK_SET); + Write(audio_size + 36); - file.Seek(40, SEEK_SET); - Write(audio_size); + file.Seek(40, SEEK_SET); + Write(audio_size); - file.Close(); + file.Close(); } void WaveFileWriter::Write(u32 value) { - file.WriteArray(&value, 1); + file.WriteArray(&value, 1); } -void WaveFileWriter::Write4(const char *ptr) +void WaveFileWriter::Write4(const char* ptr) { - file.WriteBytes(ptr, 4); + file.WriteBytes(ptr, 4); } -void WaveFileWriter::AddStereoSamples(const short *sample_data, u32 count) +void WaveFileWriter::AddStereoSamples(const short* sample_data, u32 count) { - if (!file) - PanicAlertT("WaveFileWriter - file not open."); + if (!file) + PanicAlertT("WaveFileWriter - file not open."); - if (skip_silence) - { - bool all_zero = true; + if (skip_silence) + { + bool all_zero = true; - for (u32 i = 0; i < count * 2; i++) - { - if (sample_data[i]) - all_zero = false; - } + for (u32 i = 0; i < count * 2; i++) + { + if (sample_data[i]) + all_zero = false; + } - if (all_zero) - return; - } + if (all_zero) + return; + } - file.WriteBytes(sample_data, count * 4); - audio_size += count * 4; + file.WriteBytes(sample_data, count * 4); + audio_size += count * 4; } -void WaveFileWriter::AddStereoSamplesBE(const short *sample_data, u32 count) +void WaveFileWriter::AddStereoSamplesBE(const short* sample_data, u32 count) { - if (!file) - PanicAlertT("WaveFileWriter - file not open."); + if (!file) + PanicAlertT("WaveFileWriter - file not open."); - if (count > BUFFER_SIZE * 2) - PanicAlert("WaveFileWriter - buffer too small (count = %u).", count); + if (count > BUFFER_SIZE * 2) + PanicAlert("WaveFileWriter - buffer too small (count = %u).", count); - if (skip_silence) - { - bool all_zero = true; + if (skip_silence) + { + bool all_zero = true; - for (u32 i = 0; i < count * 2; i++) - { - if (sample_data[i]) - all_zero = false; - } + for (u32 i = 0; i < count * 2; i++) + { + if (sample_data[i]) + all_zero = false; + } - if (all_zero) - return; - } + if (all_zero) + return; + } - for (u32 i = 0; i < count; i++) - { - //Flip the audio channels from RL to LR - conv_buffer[2 * i] = Common::swap16((u16)sample_data[2 * i + 1]); - conv_buffer[2 * i + 1] = Common::swap16((u16)sample_data[2 * i]); - } + for (u32 i = 0; i < count; i++) + { + // Flip the audio channels from RL to LR + conv_buffer[2 * i] = Common::swap16((u16)sample_data[2 * i + 1]); + conv_buffer[2 * i + 1] = Common::swap16((u16)sample_data[2 * i]); + } - file.WriteBytes(conv_buffer.data(), count * 4); - audio_size += count * 4; + file.WriteBytes(conv_buffer.data(), count * 4); + audio_size += count * 4; } diff --git a/Source/Core/AudioCommon/WaveFile.h b/Source/Core/AudioCommon/WaveFile.h index 7028acae3b..be0c8b7c5f 100644 --- a/Source/Core/AudioCommon/WaveFile.h +++ b/Source/Core/AudioCommon/WaveFile.h @@ -23,25 +23,23 @@ class WaveFileWriter : NonCopyable { public: - WaveFileWriter(); - ~WaveFileWriter(); + WaveFileWriter(); + ~WaveFileWriter(); - bool Start(const std::string& filename, unsigned int HLESampleRate); - void Stop(); - - void SetSkipSilence(bool skip) { skip_silence = skip; } - - void AddStereoSamples(const short *sample_data, u32 count); - void AddStereoSamplesBE(const short *sample_data, u32 count); // big endian - u32 GetAudioSize() const { return audio_size; } + bool Start(const std::string& filename, unsigned int HLESampleRate); + void Stop(); + void SetSkipSilence(bool skip) { skip_silence = skip; } + void AddStereoSamples(const short* sample_data, u32 count); + void AddStereoSamplesBE(const short* sample_data, u32 count); // big endian + u32 GetAudioSize() const { return audio_size; } private: - static constexpr size_t BUFFER_SIZE = 32 * 1024; + static constexpr size_t BUFFER_SIZE = 32 * 1024; - File::IOFile file; - bool skip_silence = false; - u32 audio_size = 0; - std::array conv_buffer{}; - void Write(u32 value); - void Write4(const char* ptr); + File::IOFile file; + bool skip_silence = false; + u32 audio_size = 0; + std::array conv_buffer{}; + void Write(u32 value); + void Write4(const char* ptr); }; diff --git a/Source/Core/AudioCommon/XAudio2Stream.cpp b/Source/Core/AudioCommon/XAudio2Stream.cpp index 01acb2fc26..959cbd0b71 100644 --- a/Source/Core/AudioCommon/XAudio2Stream.cpp +++ b/Source/Core/AudioCommon/XAudio2Stream.cpp @@ -2,12 +2,12 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "AudioCommon/XAudio2Stream.h" #include #include "AudioCommon/AudioCommon.h" -#include "AudioCommon/XAudio2Stream.h" #include "Common/Event.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #ifndef XAUDIO2_DLL #error You are building this module against the wrong version of DirectX. You probably need to remove DXSDK_DIR from your include path. @@ -16,29 +16,28 @@ struct StreamingVoiceContext : public IXAudio2VoiceCallback { private: - CMixer* const m_mixer; - Common::Event& m_sound_sync_event; - IXAudio2SourceVoice* m_source_voice; - std::unique_ptr xaudio_buffer; + CMixer* const m_mixer; + Common::Event& m_sound_sync_event; + IXAudio2SourceVoice* m_source_voice; + std::unique_ptr xaudio_buffer; - void SubmitBuffer(PBYTE buf_data); + void SubmitBuffer(PBYTE buf_data); public: - StreamingVoiceContext(IXAudio2 *pXAudio2, CMixer *pMixer, Common::Event& pSyncEvent); + StreamingVoiceContext(IXAudio2* pXAudio2, CMixer* pMixer, Common::Event& pSyncEvent); - ~StreamingVoiceContext(); + ~StreamingVoiceContext(); - void StreamingVoiceContext::Stop(); - void StreamingVoiceContext::Play(); + void StreamingVoiceContext::Stop(); + void StreamingVoiceContext::Play(); - STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) {} - STDMETHOD_(void, OnVoiceProcessingPassStart) (UINT32) {} - STDMETHOD_(void, OnVoiceProcessingPassEnd) () {} - STDMETHOD_(void, OnBufferStart) (void*) {} - STDMETHOD_(void, OnLoopEnd) (void*) {} - STDMETHOD_(void, OnStreamEnd) () {} - - STDMETHOD_(void, OnBufferEnd) (void* context); + STDMETHOD_(void, OnVoiceError)(THIS_ void* pBufferContext, HRESULT Error) {} + STDMETHOD_(void, OnVoiceProcessingPassStart)(UINT32) {} + STDMETHOD_(void, OnVoiceProcessingPassEnd)() {} + STDMETHOD_(void, OnBufferStart)(void*) {} + STDMETHOD_(void, OnLoopEnd)(void*) {} + STDMETHOD_(void, OnStreamEnd)() {} + STDMETHOD_(void, OnBufferEnd)(void* context); }; const int NUM_BUFFERS = 3; @@ -50,199 +49,199 @@ const int BUFFER_SIZE_BYTES = BUFFER_SIZE * sizeof(s16); void StreamingVoiceContext::SubmitBuffer(PBYTE buf_data) { - XAUDIO2_BUFFER buf = {}; - buf.AudioBytes = BUFFER_SIZE_BYTES; - buf.pContext = buf_data; - buf.pAudioData = buf_data; + XAUDIO2_BUFFER buf = {}; + buf.AudioBytes = BUFFER_SIZE_BYTES; + buf.pContext = buf_data; + buf.pAudioData = buf_data; - m_source_voice->SubmitSourceBuffer(&buf); + m_source_voice->SubmitSourceBuffer(&buf); } -StreamingVoiceContext::StreamingVoiceContext(IXAudio2 *pXAudio2, CMixer *pMixer, Common::Event& pSyncEvent) - : m_mixer(pMixer) - , m_sound_sync_event(pSyncEvent) - , xaudio_buffer(new BYTE[NUM_BUFFERS * BUFFER_SIZE_BYTES]()) +StreamingVoiceContext::StreamingVoiceContext(IXAudio2* pXAudio2, CMixer* pMixer, + Common::Event& pSyncEvent) + : m_mixer(pMixer), m_sound_sync_event(pSyncEvent), + xaudio_buffer(new BYTE[NUM_BUFFERS * BUFFER_SIZE_BYTES]()) { - WAVEFORMATEXTENSIBLE wfx = {}; + WAVEFORMATEXTENSIBLE wfx = {}; - wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - wfx.Format.nSamplesPerSec = m_mixer->GetSampleRate(); - wfx.Format.nChannels = 2; - wfx.Format.wBitsPerSample = 16; - wfx.Format.nBlockAlign = wfx.Format.nChannels*wfx.Format.wBitsPerSample / 8; - wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign; - wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - wfx.Samples.wValidBitsPerSample = 16; - wfx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; - wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wfx.Format.nSamplesPerSec = m_mixer->GetSampleRate(); + wfx.Format.nChannels = 2; + wfx.Format.wBitsPerSample = 16; + wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8; + wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign; + wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + wfx.Samples.wValidBitsPerSample = 16; + wfx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; + wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - // create source voice - HRESULT hr; - if (FAILED(hr = pXAudio2->CreateSourceVoice(&m_source_voice, &wfx.Format, XAUDIO2_VOICE_NOSRC, 1.0f, this))) - { - PanicAlert("XAudio2 CreateSourceVoice failed: %#X", hr); - return; - } + // create source voice + HRESULT hr; + if (FAILED(hr = pXAudio2->CreateSourceVoice(&m_source_voice, &wfx.Format, XAUDIO2_VOICE_NOSRC, + 1.0f, this))) + { + PanicAlert("XAudio2 CreateSourceVoice failed: %#X", hr); + return; + } - m_source_voice->Start(); + m_source_voice->Start(); - // start buffers with silence - for (int i = 0; i != NUM_BUFFERS; ++i) - SubmitBuffer(xaudio_buffer.get() + (i * BUFFER_SIZE_BYTES)); + // start buffers with silence + for (int i = 0; i != NUM_BUFFERS; ++i) + SubmitBuffer(xaudio_buffer.get() + (i * BUFFER_SIZE_BYTES)); } StreamingVoiceContext::~StreamingVoiceContext() { - if (m_source_voice) - { - m_source_voice->Stop(); - m_source_voice->DestroyVoice(); - } + if (m_source_voice) + { + m_source_voice->Stop(); + m_source_voice->DestroyVoice(); + } } void StreamingVoiceContext::Stop() { - if (m_source_voice) - m_source_voice->Stop(); + if (m_source_voice) + m_source_voice->Stop(); } void StreamingVoiceContext::Play() { - if (m_source_voice) - m_source_voice->Start(); + if (m_source_voice) + m_source_voice->Start(); } void StreamingVoiceContext::OnBufferEnd(void* context) { - // buffer end callback; gets SAMPLES_PER_BUFFER samples for a new buffer + // buffer end callback; gets SAMPLES_PER_BUFFER samples for a new buffer - if (!m_source_voice || !context) - return; + if (!m_source_voice || !context) + return; - //m_sound_sync_event->Wait(); // sync - //m_sound_sync_event->Spin(); // or tight sync + // m_sound_sync_event->Wait(); // sync + // m_sound_sync_event->Spin(); // or tight sync - m_mixer->Mix(static_cast(context), SAMPLES_PER_BUFFER); - SubmitBuffer(static_cast(context)); + m_mixer->Mix(static_cast(context), SAMPLES_PER_BUFFER); + SubmitBuffer(static_cast(context)); } HMODULE XAudio2::m_xaudio2_dll = nullptr; typedef decltype(&XAudio2Create) XAudio2Create_t; -void *XAudio2::PXAudio2Create = nullptr; +void* XAudio2::PXAudio2Create = nullptr; bool XAudio2::InitLibrary() { - if (m_xaudio2_dll) - { - return true; - } + if (m_xaudio2_dll) + { + return true; + } - m_xaudio2_dll = ::LoadLibrary(XAUDIO2_DLL); - if (!m_xaudio2_dll) - { - return false; - } + m_xaudio2_dll = ::LoadLibrary(XAUDIO2_DLL); + if (!m_xaudio2_dll) + { + return false; + } - if (!PXAudio2Create) - { - PXAudio2Create = (XAudio2Create_t)::GetProcAddress(m_xaudio2_dll, "XAudio2Create"); - if (!PXAudio2Create) - { - ::FreeLibrary(m_xaudio2_dll); - m_xaudio2_dll = nullptr; - return false; - } - } + if (!PXAudio2Create) + { + PXAudio2Create = (XAudio2Create_t)::GetProcAddress(m_xaudio2_dll, "XAudio2Create"); + if (!PXAudio2Create) + { + ::FreeLibrary(m_xaudio2_dll); + m_xaudio2_dll = nullptr; + return false; + } + } - return true; + return true; } XAudio2::XAudio2() - : m_mastering_voice(nullptr) - , m_volume(1.0f) - , m_cleanup_com(SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) + : m_mastering_voice(nullptr), m_volume(1.0f), + m_cleanup_com(SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) { } XAudio2::~XAudio2() { - Stop(); - if (m_cleanup_com) - CoUninitialize(); + Stop(); + if (m_cleanup_com) + CoUninitialize(); } bool XAudio2::Start() { - HRESULT hr; + HRESULT hr; - // callback doesn't seem to run on a specific CPU anyways - IXAudio2* xaudptr; - if (FAILED(hr = ((XAudio2Create_t)PXAudio2Create)(&xaudptr, 0, XAUDIO2_DEFAULT_PROCESSOR))) - { - PanicAlert("XAudio2 init failed: %#X", hr); - Stop(); - return false; - } - m_xaudio2 = std::unique_ptr(xaudptr); + // callback doesn't seem to run on a specific CPU anyways + IXAudio2* xaudptr; + if (FAILED(hr = ((XAudio2Create_t)PXAudio2Create)(&xaudptr, 0, XAUDIO2_DEFAULT_PROCESSOR))) + { + PanicAlert("XAudio2 init failed: %#X", hr); + Stop(); + return false; + } + m_xaudio2 = std::unique_ptr(xaudptr); - // XAudio2 master voice - // XAUDIO2_DEFAULT_CHANNELS instead of 2 for expansion? - if (FAILED(hr = m_xaudio2->CreateMasteringVoice(&m_mastering_voice, 2, m_mixer->GetSampleRate()))) - { - PanicAlert("XAudio2 master voice creation failed: %#X", hr); - Stop(); - return false; - } + // XAudio2 master voice + // XAUDIO2_DEFAULT_CHANNELS instead of 2 for expansion? + if (FAILED(hr = m_xaudio2->CreateMasteringVoice(&m_mastering_voice, 2, m_mixer->GetSampleRate()))) + { + PanicAlert("XAudio2 master voice creation failed: %#X", hr); + Stop(); + return false; + } - // Volume - m_mastering_voice->SetVolume(m_volume); + // Volume + m_mastering_voice->SetVolume(m_volume); - m_voice_context = std::unique_ptr - (new StreamingVoiceContext(m_xaudio2.get(), m_mixer.get(), m_sound_sync_event)); + m_voice_context = std::unique_ptr( + new StreamingVoiceContext(m_xaudio2.get(), m_mixer.get(), m_sound_sync_event)); - return true; + return true; } void XAudio2::SetVolume(int volume) { - //linear 1- .01 - m_volume = (float)volume / 100.f; + // linear 1- .01 + m_volume = (float)volume / 100.f; - if (m_mastering_voice) - m_mastering_voice->SetVolume(m_volume); + if (m_mastering_voice) + m_mastering_voice->SetVolume(m_volume); } void XAudio2::Clear(bool mute) { - m_muted = mute; + m_muted = mute; - if (m_voice_context) - { - if (m_muted) - m_voice_context->Stop(); - else - m_voice_context->Play(); - } + if (m_voice_context) + { + if (m_muted) + m_voice_context->Stop(); + else + m_voice_context->Play(); + } } void XAudio2::Stop() { - //m_sound_sync_event.Set(); + // m_sound_sync_event.Set(); - m_voice_context.reset(); + m_voice_context.reset(); - if (m_mastering_voice) - { - m_mastering_voice->DestroyVoice(); - m_mastering_voice = nullptr; - } + if (m_mastering_voice) + { + m_mastering_voice->DestroyVoice(); + m_mastering_voice = nullptr; + } - m_xaudio2.reset(); // release interface + m_xaudio2.reset(); // release interface - if (m_xaudio2_dll) - { - ::FreeLibrary(m_xaudio2_dll); - m_xaudio2_dll = nullptr; - PXAudio2Create = nullptr; - } + if (m_xaudio2_dll) + { + ::FreeLibrary(m_xaudio2_dll); + m_xaudio2_dll = nullptr; + PXAudio2Create = nullptr; + } } diff --git a/Source/Core/AudioCommon/XAudio2Stream.h b/Source/Core/AudioCommon/XAudio2Stream.h index 5561c4af91..eb45634154 100644 --- a/Source/Core/AudioCommon/XAudio2Stream.h +++ b/Source/Core/AudioCommon/XAudio2Stream.h @@ -26,40 +26,40 @@ class XAudio2 final : public SoundStream #ifdef _WIN32 private: - class Releaser - { - public: - template - void operator()(R* ptr) - { - ptr->Release(); - } - }; + class Releaser + { + public: + template + void operator()(R* ptr) + { + ptr->Release(); + } + }; - std::unique_ptr m_xaudio2; - std::unique_ptr m_voice_context; - IXAudio2MasteringVoice *m_mastering_voice; + std::unique_ptr m_xaudio2; + std::unique_ptr m_voice_context; + IXAudio2MasteringVoice* m_mastering_voice; - Common::Event m_sound_sync_event; - float m_volume; + Common::Event m_sound_sync_event; + float m_volume; - const bool m_cleanup_com; + const bool m_cleanup_com; - static HMODULE m_xaudio2_dll; - static void *PXAudio2Create; + static HMODULE m_xaudio2_dll; + static void* PXAudio2Create; - static bool InitLibrary(); + static bool InitLibrary(); public: - XAudio2(); - virtual ~XAudio2(); + XAudio2(); + virtual ~XAudio2(); - bool Start() override; - void Stop() override; + bool Start() override; + void Stop() override; - void Clear(bool mute) override; - void SetVolume(int volume) override; + void Clear(bool mute) override; + void SetVolume(int volume) override; - static bool isValid() { return InitLibrary(); } + static bool isValid() { return InitLibrary(); } #endif }; diff --git a/Source/Core/AudioCommon/XAudio2_7Stream.cpp b/Source/Core/AudioCommon/XAudio2_7Stream.cpp index f4a14370d9..74df4d35c4 100644 --- a/Source/Core/AudioCommon/XAudio2_7Stream.cpp +++ b/Source/Core/AudioCommon/XAudio2_7Stream.cpp @@ -10,35 +10,34 @@ #include "AudioCommon/AudioCommon.h" #include "AudioCommon/XAudio2_7Stream.h" #include "Common/Event.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" struct StreamingVoiceContext2_7 : public IXAudio2VoiceCallback { private: - CMixer* const m_mixer; - Common::Event& m_sound_sync_event; - IXAudio2SourceVoice* m_source_voice; - std::unique_ptr xaudio_buffer; + CMixer* const m_mixer; + Common::Event& m_sound_sync_event; + IXAudio2SourceVoice* m_source_voice; + std::unique_ptr xaudio_buffer; - void SubmitBuffer(PBYTE buf_data); + void SubmitBuffer(PBYTE buf_data); public: - StreamingVoiceContext2_7(IXAudio2 *pXAudio2, CMixer *pMixer, Common::Event& pSyncEvent); + StreamingVoiceContext2_7(IXAudio2* pXAudio2, CMixer* pMixer, Common::Event& pSyncEvent); - ~StreamingVoiceContext2_7(); + ~StreamingVoiceContext2_7(); - void StreamingVoiceContext2_7::Stop(); - void StreamingVoiceContext2_7::Play(); + void StreamingVoiceContext2_7::Stop(); + void StreamingVoiceContext2_7::Play(); - STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) {} - STDMETHOD_(void, OnVoiceProcessingPassStart) (UINT32) {} - STDMETHOD_(void, OnVoiceProcessingPassEnd) () {} - STDMETHOD_(void, OnBufferStart) (void*) {} - STDMETHOD_(void, OnLoopEnd) (void*) {} - STDMETHOD_(void, OnStreamEnd) () {} - - STDMETHOD_(void, OnBufferEnd) (void* context); + STDMETHOD_(void, OnVoiceError)(THIS_ void* pBufferContext, HRESULT Error) {} + STDMETHOD_(void, OnVoiceProcessingPassStart)(UINT32) {} + STDMETHOD_(void, OnVoiceProcessingPassEnd)() {} + STDMETHOD_(void, OnBufferStart)(void*) {} + STDMETHOD_(void, OnLoopEnd)(void*) {} + STDMETHOD_(void, OnStreamEnd)() {} + STDMETHOD_(void, OnBufferEnd)(void* context); }; const int NUM_BUFFERS = 3; @@ -50,186 +49,186 @@ const int BUFFER_SIZE_BYTES = BUFFER_SIZE * sizeof(s16); void StreamingVoiceContext2_7::SubmitBuffer(PBYTE buf_data) { - XAUDIO2_BUFFER buf = {}; - buf.AudioBytes = BUFFER_SIZE_BYTES; - buf.pContext = buf_data; - buf.pAudioData = buf_data; + XAUDIO2_BUFFER buf = {}; + buf.AudioBytes = BUFFER_SIZE_BYTES; + buf.pContext = buf_data; + buf.pAudioData = buf_data; - m_source_voice->SubmitSourceBuffer(&buf); + m_source_voice->SubmitSourceBuffer(&buf); } -StreamingVoiceContext2_7::StreamingVoiceContext2_7(IXAudio2 *pXAudio2, CMixer *pMixer, Common::Event& pSyncEvent) - : m_mixer(pMixer) - , m_sound_sync_event(pSyncEvent) - , xaudio_buffer(new BYTE[NUM_BUFFERS * BUFFER_SIZE_BYTES]()) +StreamingVoiceContext2_7::StreamingVoiceContext2_7(IXAudio2* pXAudio2, CMixer* pMixer, + Common::Event& pSyncEvent) + : m_mixer(pMixer), m_sound_sync_event(pSyncEvent), + xaudio_buffer(new BYTE[NUM_BUFFERS * BUFFER_SIZE_BYTES]()) { - WAVEFORMATEXTENSIBLE wfx = {}; + WAVEFORMATEXTENSIBLE wfx = {}; - wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - wfx.Format.nSamplesPerSec = m_mixer->GetSampleRate(); - wfx.Format.nChannels = 2; - wfx.Format.wBitsPerSample = 16; - wfx.Format.nBlockAlign = wfx.Format.nChannels*wfx.Format.wBitsPerSample / 8; - wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign; - wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - wfx.Samples.wValidBitsPerSample = 16; - wfx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; - wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wfx.Format.nSamplesPerSec = m_mixer->GetSampleRate(); + wfx.Format.nChannels = 2; + wfx.Format.wBitsPerSample = 16; + wfx.Format.nBlockAlign = wfx.Format.nChannels * wfx.Format.wBitsPerSample / 8; + wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign; + wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + wfx.Samples.wValidBitsPerSample = 16; + wfx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; + wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - // create source voice - HRESULT hr; - if (FAILED(hr = pXAudio2->CreateSourceVoice(&m_source_voice, &wfx.Format, XAUDIO2_VOICE_NOSRC, 1.0f, this))) - { - PanicAlert("XAudio2_7 CreateSourceVoice failed: %#X", hr); - return; - } + // create source voice + HRESULT hr; + if (FAILED(hr = pXAudio2->CreateSourceVoice(&m_source_voice, &wfx.Format, XAUDIO2_VOICE_NOSRC, + 1.0f, this))) + { + PanicAlert("XAudio2_7 CreateSourceVoice failed: %#X", hr); + return; + } - m_source_voice->Start(); + m_source_voice->Start(); - // start buffers with silence - for (int i = 0; i != NUM_BUFFERS; ++i) - SubmitBuffer(xaudio_buffer.get() + (i * BUFFER_SIZE_BYTES)); + // start buffers with silence + for (int i = 0; i != NUM_BUFFERS; ++i) + SubmitBuffer(xaudio_buffer.get() + (i * BUFFER_SIZE_BYTES)); } StreamingVoiceContext2_7::~StreamingVoiceContext2_7() { - if (m_source_voice) - { - m_source_voice->Stop(); - m_source_voice->DestroyVoice(); - } + if (m_source_voice) + { + m_source_voice->Stop(); + m_source_voice->DestroyVoice(); + } } void StreamingVoiceContext2_7::Stop() { - if (m_source_voice) - m_source_voice->Stop(); + if (m_source_voice) + m_source_voice->Stop(); } void StreamingVoiceContext2_7::Play() { - if (m_source_voice) - m_source_voice->Start(); + if (m_source_voice) + m_source_voice->Start(); } void StreamingVoiceContext2_7::OnBufferEnd(void* context) { - // buffer end callback; gets SAMPLES_PER_BUFFER samples for a new buffer + // buffer end callback; gets SAMPLES_PER_BUFFER samples for a new buffer - if (!m_source_voice || !context) - return; + if (!m_source_voice || !context) + return; - //m_sound_sync_event->Wait(); // sync - //m_sound_sync_event->Spin(); // or tight sync + // m_sound_sync_event->Wait(); // sync + // m_sound_sync_event->Spin(); // or tight sync - m_mixer->Mix(static_cast(context), SAMPLES_PER_BUFFER); - SubmitBuffer(static_cast(context)); + m_mixer->Mix(static_cast(context), SAMPLES_PER_BUFFER); + SubmitBuffer(static_cast(context)); } HMODULE XAudio2_7::m_xaudio2_dll = nullptr; void XAudio2_7::ReleaseIXAudio2(IXAudio2* ptr) { - ptr->Release(); + ptr->Release(); } bool XAudio2_7::InitLibrary() { - if (m_xaudio2_dll) - { - return true; - } + if (m_xaudio2_dll) + { + return true; + } - m_xaudio2_dll = ::LoadLibrary(TEXT("xaudio2_7.dll")); + m_xaudio2_dll = ::LoadLibrary(TEXT("xaudio2_7.dll")); - return m_xaudio2_dll != nullptr; + return m_xaudio2_dll != nullptr; } XAudio2_7::XAudio2_7() - : m_mastering_voice(nullptr) - , m_volume(1.0f) - , m_cleanup_com(SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) + : m_mastering_voice(nullptr), m_volume(1.0f), + m_cleanup_com(SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) { } XAudio2_7::~XAudio2_7() { - Stop(); - if (m_cleanup_com) - CoUninitialize(); + Stop(); + if (m_cleanup_com) + CoUninitialize(); } bool XAudio2_7::Start() { - HRESULT hr; + HRESULT hr; - // callback doesn't seem to run on a specific CPU anyways - IXAudio2* xaudptr; - if (FAILED(hr = XAudio2Create(&xaudptr, 0, XAUDIO2_DEFAULT_PROCESSOR))) - { - PanicAlert("XAudio2_7 init failed: %#X", hr); - Stop(); - return false; - } - m_xaudio2 = std::unique_ptr(xaudptr); + // callback doesn't seem to run on a specific CPU anyways + IXAudio2* xaudptr; + if (FAILED(hr = XAudio2Create(&xaudptr, 0, XAUDIO2_DEFAULT_PROCESSOR))) + { + PanicAlert("XAudio2_7 init failed: %#X", hr); + Stop(); + return false; + } + m_xaudio2 = std::unique_ptr(xaudptr); - // XAudio2 master voice - // XAUDIO2_DEFAULT_CHANNELS instead of 2 for expansion? - if (FAILED(hr = m_xaudio2->CreateMasteringVoice(&m_mastering_voice, 2, m_mixer->GetSampleRate()))) - { - PanicAlert("XAudio2_7 master voice creation failed: %#X", hr); - Stop(); - return false; - } + // XAudio2 master voice + // XAUDIO2_DEFAULT_CHANNELS instead of 2 for expansion? + if (FAILED(hr = m_xaudio2->CreateMasteringVoice(&m_mastering_voice, 2, m_mixer->GetSampleRate()))) + { + PanicAlert("XAudio2_7 master voice creation failed: %#X", hr); + Stop(); + return false; + } - // Volume - m_mastering_voice->SetVolume(m_volume); + // Volume + m_mastering_voice->SetVolume(m_volume); - m_voice_context = std::unique_ptr - (new StreamingVoiceContext2_7(m_xaudio2.get(), m_mixer.get(), m_sound_sync_event)); + m_voice_context = std::unique_ptr( + new StreamingVoiceContext2_7(m_xaudio2.get(), m_mixer.get(), m_sound_sync_event)); - return true; + return true; } void XAudio2_7::SetVolume(int volume) { - //linear 1- .01 - m_volume = (float)volume / 100.f; + // linear 1- .01 + m_volume = (float)volume / 100.f; - if (m_mastering_voice) - m_mastering_voice->SetVolume(m_volume); + if (m_mastering_voice) + m_mastering_voice->SetVolume(m_volume); } void XAudio2_7::Clear(bool mute) { - m_muted = mute; + m_muted = mute; - if (m_voice_context) - { - if (m_muted) - m_voice_context->Stop(); - else - m_voice_context->Play(); - } + if (m_voice_context) + { + if (m_muted) + m_voice_context->Stop(); + else + m_voice_context->Play(); + } } void XAudio2_7::Stop() { - //m_sound_sync_event.Set(); + // m_sound_sync_event.Set(); - m_voice_context.reset(); + m_voice_context.reset(); - if (m_mastering_voice) - { - m_mastering_voice->DestroyVoice(); - m_mastering_voice = nullptr; - } + if (m_mastering_voice) + { + m_mastering_voice->DestroyVoice(); + m_mastering_voice = nullptr; + } - m_xaudio2.reset(); // release interface + m_xaudio2.reset(); // release interface - if (m_xaudio2_dll) - { - ::FreeLibrary(m_xaudio2_dll); - m_xaudio2_dll = nullptr; - } + if (m_xaudio2_dll) + { + ::FreeLibrary(m_xaudio2_dll); + m_xaudio2_dll = nullptr; + } } diff --git a/Source/Core/AudioCommon/XAudio2_7Stream.h b/Source/Core/AudioCommon/XAudio2_7Stream.h index e47ebbd39c..7a7193ea16 100644 --- a/Source/Core/AudioCommon/XAudio2_7Stream.h +++ b/Source/Core/AudioCommon/XAudio2_7Stream.h @@ -32,41 +32,41 @@ class XAudio2_7 final : public SoundStream #ifdef _WIN32 private: - static void ReleaseIXAudio2(IXAudio2 *ptr); + static void ReleaseIXAudio2(IXAudio2* ptr); - class Releaser - { - public: - template - void operator()(R *ptr) - { - ReleaseIXAudio2(ptr); - } - }; + class Releaser + { + public: + template + void operator()(R* ptr) + { + ReleaseIXAudio2(ptr); + } + }; - std::unique_ptr m_xaudio2; - std::unique_ptr m_voice_context; - IXAudio2MasteringVoice *m_mastering_voice; + std::unique_ptr m_xaudio2; + std::unique_ptr m_voice_context; + IXAudio2MasteringVoice* m_mastering_voice; - Common::Event m_sound_sync_event; - float m_volume; + Common::Event m_sound_sync_event; + float m_volume; - const bool m_cleanup_com; + const bool m_cleanup_com; - static HMODULE m_xaudio2_dll; + static HMODULE m_xaudio2_dll; - static bool InitLibrary(); + static bool InitLibrary(); public: - XAudio2_7(); - virtual ~XAudio2_7(); + XAudio2_7(); + virtual ~XAudio2_7(); - bool Start() override; - void Stop() override; + bool Start() override; + void Stop() override; - void Clear(bool mute) override; - void SetVolume(int volume) override; + void Clear(bool mute) override; + void SetVolume(int volume) override; - static bool isValid() { return InitLibrary(); } + static bool isValid() { return InitLibrary(); } #endif }; diff --git a/Source/Core/AudioCommon/aldlist.cpp b/Source/Core/AudioCommon/aldlist.cpp index 4480c6ca86..accd13c595 100644 --- a/Source/Core/AudioCommon/aldlist.cpp +++ b/Source/Core/AudioCommon/aldlist.cpp @@ -6,23 +6,35 @@ * Copyright (c) 2006, Creative Labs Inc. * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided * that the following conditions are met: * - * * Redistributions of source code must retain the above copyright notice, this list of conditions and + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and * the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to endorse or + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to + * endorse or * promote products derived from this software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE * POSSIBILITY OF SUCH DAMAGE. */ @@ -42,101 +54,104 @@ #include #endif - /* * Init call */ ALDeviceList::ALDeviceList() { - ALDEVICEINFO ALDeviceInfo; + ALDEVICEINFO ALDeviceInfo; - // DeviceInfo vector stores, for each enumerated device, it's device name, selection status, spec version #, and extension support - vDeviceInfo.clear(); - vDeviceInfo.reserve(10); + // DeviceInfo vector stores, for each enumerated device, it's device name, selection status, spec + // version #, and extension support + vDeviceInfo.clear(); + vDeviceInfo.reserve(10); - defaultDeviceIndex = 0; + defaultDeviceIndex = 0; - // grab function pointers for 1.0-API functions, and if successful proceed to enumerate all devices - //if (LoadOAL10Library(nullptr, &ALFunction) == TRUE) { - if (alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) - { - const char *devices = alcGetString(nullptr, ALC_DEVICE_SPECIFIER); - const char *defaultDeviceName = alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER); - // go through device list (each device terminated with a single nullptr, list terminated with double nullptr) - for (s32 index = 0; devices != nullptr && strlen(devices) > 0; index++, devices += strlen(devices) + 1) - { - if (strcmp(defaultDeviceName, devices) == 0) - { - defaultDeviceIndex = index; - } - ALCdevice *device = alcOpenDevice(devices); - if (device) - { - ALCcontext *context = alcCreateContext(device, nullptr); - if (context) - { - alcMakeContextCurrent(context); - // if new actual device name isn't already in the list, then add it... - const char *actualDeviceName = alcGetString(device, ALC_DEVICE_SPECIFIER); - bool bNewName = true; - for (s32 i = 0; i < GetNumDevices(); i++) - { - if (strcmp(GetDeviceName(i), actualDeviceName) == 0) - { - bNewName = false; - } - } - if ((bNewName) && (actualDeviceName != nullptr) && (strlen(actualDeviceName) > 0)) - { - ALDeviceInfo.bSelected = true; - ALDeviceInfo.strDeviceName = actualDeviceName; - alcGetIntegerv(device, ALC_MAJOR_VERSION, sizeof(s32), &ALDeviceInfo.iMajorVersion); - alcGetIntegerv(device, ALC_MINOR_VERSION, sizeof(s32), &ALDeviceInfo.iMinorVersion); + // grab function pointers for 1.0-API functions, and if successful proceed to enumerate all + // devices + // if (LoadOAL10Library(nullptr, &ALFunction) == TRUE) { + if (alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + { + const char* devices = alcGetString(nullptr, ALC_DEVICE_SPECIFIER); + const char* defaultDeviceName = alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER); + // go through device list (each device terminated with a single nullptr, list terminated with + // double nullptr) + for (s32 index = 0; devices != nullptr && strlen(devices) > 0; + index++, devices += strlen(devices) + 1) + { + if (strcmp(defaultDeviceName, devices) == 0) + { + defaultDeviceIndex = index; + } + ALCdevice* device = alcOpenDevice(devices); + if (device) + { + ALCcontext* context = alcCreateContext(device, nullptr); + if (context) + { + alcMakeContextCurrent(context); + // if new actual device name isn't already in the list, then add it... + const char* actualDeviceName = alcGetString(device, ALC_DEVICE_SPECIFIER); + bool bNewName = true; + for (s32 i = 0; i < GetNumDevices(); i++) + { + if (strcmp(GetDeviceName(i), actualDeviceName) == 0) + { + bNewName = false; + } + } + if ((bNewName) && (actualDeviceName != nullptr) && (strlen(actualDeviceName) > 0)) + { + ALDeviceInfo.bSelected = true; + ALDeviceInfo.strDeviceName = actualDeviceName; + alcGetIntegerv(device, ALC_MAJOR_VERSION, sizeof(s32), &ALDeviceInfo.iMajorVersion); + alcGetIntegerv(device, ALC_MINOR_VERSION, sizeof(s32), &ALDeviceInfo.iMinorVersion); - ALDeviceInfo.pvstrExtensions = new std::vector; + ALDeviceInfo.pvstrExtensions = new std::vector; - // Check for ALC Extensions - if (alcIsExtensionPresent(device, "ALC_EXT_CAPTURE") == AL_TRUE) - ALDeviceInfo.pvstrExtensions->push_back("ALC_EXT_CAPTURE"); - if (alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_TRUE) - ALDeviceInfo.pvstrExtensions->push_back("ALC_EXT_EFX"); + // Check for ALC Extensions + if (alcIsExtensionPresent(device, "ALC_EXT_CAPTURE") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("ALC_EXT_CAPTURE"); + if (alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("ALC_EXT_EFX"); - // Check for AL Extensions - if (alIsExtensionPresent("AL_EXT_OFFSET") == AL_TRUE) - ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_OFFSET"); + // Check for AL Extensions + if (alIsExtensionPresent("AL_EXT_OFFSET") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_OFFSET"); - if (alIsExtensionPresent("AL_EXT_LINEAR_DISTANCE") == AL_TRUE) - ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_LINEAR_DISTANCE"); - if (alIsExtensionPresent("AL_EXT_EXPONENT_DISTANCE") == AL_TRUE) - ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_EXPONENT_DISTANCE"); + if (alIsExtensionPresent("AL_EXT_LINEAR_DISTANCE") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_LINEAR_DISTANCE"); + if (alIsExtensionPresent("AL_EXT_EXPONENT_DISTANCE") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_EXPONENT_DISTANCE"); - if (alIsExtensionPresent("EAX2.0") == AL_TRUE) - ALDeviceInfo.pvstrExtensions->push_back("EAX2.0"); - if (alIsExtensionPresent("EAX3.0") == AL_TRUE) - ALDeviceInfo.pvstrExtensions->push_back("EAX3.0"); - if (alIsExtensionPresent("EAX4.0") == AL_TRUE) - ALDeviceInfo.pvstrExtensions->push_back("EAX4.0"); - if (alIsExtensionPresent("EAX5.0") == AL_TRUE) - ALDeviceInfo.pvstrExtensions->push_back("EAX5.0"); + if (alIsExtensionPresent("EAX2.0") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("EAX2.0"); + if (alIsExtensionPresent("EAX3.0") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("EAX3.0"); + if (alIsExtensionPresent("EAX4.0") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("EAX4.0"); + if (alIsExtensionPresent("EAX5.0") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("EAX5.0"); - if (alIsExtensionPresent("EAX-RAM") == AL_TRUE) - ALDeviceInfo.pvstrExtensions->push_back("EAX-RAM"); + if (alIsExtensionPresent("EAX-RAM") == AL_TRUE) + ALDeviceInfo.pvstrExtensions->push_back("EAX-RAM"); - // Get Source Count - ALDeviceInfo.uiSourceCount = GetMaxNumSources(); + // Get Source Count + ALDeviceInfo.uiSourceCount = GetMaxNumSources(); - vDeviceInfo.push_back(ALDeviceInfo); - } - alcMakeContextCurrent(nullptr); - alcDestroyContext(context); - } - alcCloseDevice(device); - } - } - } - //} + vDeviceInfo.push_back(ALDeviceInfo); + } + alcMakeContextCurrent(nullptr); + alcDestroyContext(context); + } + alcCloseDevice(device); + } + } + } + //} - ResetFilters(); + ResetFilters(); } /* @@ -144,16 +159,16 @@ ALDeviceList::ALDeviceList() */ ALDeviceList::~ALDeviceList() { - for (auto& di : vDeviceInfo) - { - if (di.pvstrExtensions) - { - di.pvstrExtensions->clear(); - delete di.pvstrExtensions; - } - } + for (auto& di : vDeviceInfo) + { + if (di.pvstrExtensions) + { + di.pvstrExtensions->clear(); + delete di.pvstrExtensions; + } + } - vDeviceInfo.clear(); + vDeviceInfo.clear(); } /* @@ -161,32 +176,33 @@ ALDeviceList::~ALDeviceList() */ s32 ALDeviceList::GetNumDevices() { - return (s32)vDeviceInfo.size(); + return (s32)vDeviceInfo.size(); } /* * Returns the device name at an index in the complete device list */ -char * ALDeviceList::GetDeviceName(s32 index) +char* ALDeviceList::GetDeviceName(s32 index) { - if (index < GetNumDevices()) - return (char *)vDeviceInfo[index].strDeviceName.c_str(); - else - return nullptr; + if (index < GetNumDevices()) + return (char*)vDeviceInfo[index].strDeviceName.c_str(); + else + return nullptr; } /* - * Returns the major and minor version numbers for a device at a specified index in the complete list + * Returns the major and minor version numbers for a device at a specified index in the complete + * list */ -void ALDeviceList::GetDeviceVersion(s32 index, s32 *major, s32 *minor) +void ALDeviceList::GetDeviceVersion(s32 index, s32* major, s32* minor) { - if (index < GetNumDevices()) - { - if (major) - *major = vDeviceInfo[index].iMajorVersion; - if (minor) - *minor = vDeviceInfo[index].iMinorVersion; - } + if (index < GetNumDevices()) + { + if (major) + *major = vDeviceInfo[index].iMajorVersion; + if (minor) + *minor = vDeviceInfo[index].iMinorVersion; + } } /* @@ -194,32 +210,32 @@ void ALDeviceList::GetDeviceVersion(s32 index, s32 *major, s32 *minor) */ u32 ALDeviceList::GetMaxNumSources(s32 index) { - if (index < GetNumDevices()) - return vDeviceInfo[index].uiSourceCount; - else - return 0; + if (index < GetNumDevices()) + return vDeviceInfo[index].uiSourceCount; + else + return 0; } /* * Checks if the extension is supported on the given device */ -bool ALDeviceList::IsExtensionSupported(s32 index, char *szExtName) +bool ALDeviceList::IsExtensionSupported(s32 index, char* szExtName) { - bool bReturn = false; + bool bReturn = false; - if (index < GetNumDevices()) - { - for (auto& ext : *vDeviceInfo[index].pvstrExtensions) - { - if (!strcasecmp(ext.c_str(), szExtName)) - { - bReturn = true; - break; - } - } - } + if (index < GetNumDevices()) + { + for (auto& ext : *vDeviceInfo[index].pvstrExtensions) + { + if (!strcasecmp(ext.c_str(), szExtName)) + { + bReturn = true; + break; + } + } + } - return bReturn; + return bReturn; } /* @@ -227,7 +243,7 @@ bool ALDeviceList::IsExtensionSupported(s32 index, char *szExtName) */ s32 ALDeviceList::GetDefaultDevice() { - return defaultDeviceIndex; + return defaultDeviceIndex; } /* @@ -235,15 +251,15 @@ s32 ALDeviceList::GetDefaultDevice() */ void ALDeviceList::FilterDevicesMinVer(s32 major, s32 minor) { - s32 dMajor = 0, dMinor = 0; - for (u32 i = 0; i < vDeviceInfo.size(); i++) - { - GetDeviceVersion(i, &dMajor, &dMinor); - if ((dMajor < major) || ((dMajor == major) && (dMinor < minor))) - { - vDeviceInfo[i].bSelected = false; - } - } + s32 dMajor = 0, dMinor = 0; + for (u32 i = 0; i < vDeviceInfo.size(); i++) + { + GetDeviceVersion(i, &dMajor, &dMinor); + if ((dMajor < major) || ((dMajor == major) && (dMinor < minor))) + { + vDeviceInfo[i].bSelected = false; + } + } } /* @@ -251,39 +267,39 @@ void ALDeviceList::FilterDevicesMinVer(s32 major, s32 minor) */ void ALDeviceList::FilterDevicesMaxVer(s32 major, s32 minor) { - s32 dMajor = 0, dMinor = 0; - for (u32 i = 0; i < vDeviceInfo.size(); i++) - { - GetDeviceVersion(i, &dMajor, &dMinor); - if ((dMajor > major) || ((dMajor == major) && (dMinor > minor))) - { - vDeviceInfo[i].bSelected = false; - } - } + s32 dMajor = 0, dMinor = 0; + for (u32 i = 0; i < vDeviceInfo.size(); i++) + { + GetDeviceVersion(i, &dMajor, &dMinor); + if ((dMajor > major) || ((dMajor == major) && (dMinor > minor))) + { + vDeviceInfo[i].bSelected = false; + } + } } /* * Deselects device which don't support the given extension name */ -void ALDeviceList::FilterDevicesExtension(char *szExtName) +void ALDeviceList::FilterDevicesExtension(char* szExtName) { - bool bFound; + bool bFound; - for (auto& di : vDeviceInfo) - { - bFound = false; - for (auto& ext : *di.pvstrExtensions) - { - if (!strcasecmp(ext.c_str(), szExtName)) - { - bFound = true; - break; - } - } + for (auto& di : vDeviceInfo) + { + bFound = false; + for (auto& ext : *di.pvstrExtensions) + { + if (!strcasecmp(ext.c_str(), szExtName)) + { + bFound = true; + break; + } + } - if (!bFound) - di.bSelected = false; - } + if (!bFound) + di.bSelected = false; + } } /* @@ -291,12 +307,12 @@ void ALDeviceList::FilterDevicesExtension(char *szExtName) */ void ALDeviceList::ResetFilters() { - for (s32 i = 0; i < GetNumDevices(); i++) - { - vDeviceInfo[i].bSelected = true; - } + for (s32 i = 0; i < GetNumDevices(); i++) + { + vDeviceInfo[i].bSelected = true; + } - filterIndex = 0; + filterIndex = 0; } /* @@ -304,18 +320,18 @@ void ALDeviceList::ResetFilters() */ s32 ALDeviceList::GetFirstFilteredDevice() { - s32 i; + s32 i; - for (i = 0; i < GetNumDevices(); i++) - { - if (vDeviceInfo[i].bSelected == true) - { - break; - } - } + for (i = 0; i < GetNumDevices(); i++) + { + if (vDeviceInfo[i].bSelected == true) + { + break; + } + } - filterIndex = i + 1; - return i; + filterIndex = i + 1; + return i; } /* @@ -323,18 +339,18 @@ s32 ALDeviceList::GetFirstFilteredDevice() */ s32 ALDeviceList::GetNextFilteredDevice() { - s32 i; + s32 i; - for (i = filterIndex; i < GetNumDevices(); i++) - { - if (vDeviceInfo[i].bSelected == true) - { - break; - } - } + for (i = filterIndex; i < GetNumDevices(); i++) + { + if (vDeviceInfo[i].bSelected == true) + { + break; + } + } - filterIndex = i + 1; - return i; + filterIndex = i + 1; + return i; } /* @@ -342,29 +358,29 @@ s32 ALDeviceList::GetNextFilteredDevice() */ u32 ALDeviceList::GetMaxNumSources() { - ALuint uiSources[256]; - u32 iSourceCount = 0; + ALuint uiSources[256]; + u32 iSourceCount = 0; - // Clear AL Error Code - alGetError(); + // Clear AL Error Code + alGetError(); - // Generate up to 256 Sources, checking for any errors - for (iSourceCount = 0; iSourceCount < 256; iSourceCount++) - { - alGenSources(1, &uiSources[iSourceCount]); - if (alGetError() != AL_NO_ERROR) - break; - } + // Generate up to 256 Sources, checking for any errors + for (iSourceCount = 0; iSourceCount < 256; iSourceCount++) + { + alGenSources(1, &uiSources[iSourceCount]); + if (alGetError() != AL_NO_ERROR) + break; + } - // Release the Sources - alDeleteSources(iSourceCount, uiSources); - if (alGetError() != AL_NO_ERROR) - { - for (auto& uiSource : uiSources) - { - alDeleteSources(1, &uiSource); - } - } + // Release the Sources + alDeleteSources(iSourceCount, uiSources); + if (alGetError() != AL_NO_ERROR) + { + for (auto& uiSource : uiSources) + { + alDeleteSources(1, &uiSource); + } + } - return iSourceCount; + return iSourceCount; } diff --git a/Source/Core/AudioCommon/aldlist.h b/Source/Core/AudioCommon/aldlist.h index 8de6ef2871..733c407ae7 100644 --- a/Source/Core/AudioCommon/aldlist.h +++ b/Source/Core/AudioCommon/aldlist.h @@ -10,43 +10,43 @@ #include "Common/CommonTypes.h" #ifdef _WIN32 -#pragma warning(disable: 4786) //disable warning "identifier was truncated to - //'255' characters in the browser information" +#pragma warning(disable : 4786) // disable warning "identifier was truncated to +//'255' characters in the browser information" #endif typedef struct { - std::string strDeviceName; - s32 iMajorVersion; - s32 iMinorVersion; - u32 uiSourceCount; - std::vector* pvstrExtensions; - bool bSelected; + std::string strDeviceName; + s32 iMajorVersion; + s32 iMinorVersion; + u32 uiSourceCount; + std::vector* pvstrExtensions; + bool bSelected; } ALDEVICEINFO, *LPALDEVICEINFO; class ALDeviceList { private: - std::vector vDeviceInfo; - s32 defaultDeviceIndex; - s32 filterIndex; + std::vector vDeviceInfo; + s32 defaultDeviceIndex; + s32 filterIndex; public: - ALDeviceList(); - ~ALDeviceList(); - s32 GetNumDevices(); - char* GetDeviceName(s32 index); - void GetDeviceVersion(s32 index, s32* major, s32* minor); - u32 GetMaxNumSources(s32 index); - bool IsExtensionSupported(s32 index, char* szExtName); - s32 GetDefaultDevice(); - void FilterDevicesMinVer(s32 major, s32 minor); - void FilterDevicesMaxVer(s32 major, s32 minor); - void FilterDevicesExtension(char* szExtName); - void ResetFilters(); - s32 GetFirstFilteredDevice(); - s32 GetNextFilteredDevice(); + ALDeviceList(); + ~ALDeviceList(); + s32 GetNumDevices(); + char* GetDeviceName(s32 index); + void GetDeviceVersion(s32 index, s32* major, s32* minor); + u32 GetMaxNumSources(s32 index); + bool IsExtensionSupported(s32 index, char* szExtName); + s32 GetDefaultDevice(); + void FilterDevicesMinVer(s32 major, s32 minor); + void FilterDevicesMaxVer(s32 major, s32 minor); + void FilterDevicesExtension(char* szExtName); + void ResetFilters(); + s32 GetFirstFilteredDevice(); + s32 GetNextFilteredDevice(); private: - u32 GetMaxNumSources(); + u32 GetMaxNumSources(); }; diff --git a/Source/Core/Common/Analytics.cpp b/Source/Core/Common/Analytics.cpp index 29359cc815..1110c5ed60 100644 --- a/Source/Core/Common/Analytics.cpp +++ b/Source/Core/Common/Analytics.cpp @@ -4,8 +4,8 @@ #include #include -#include #include +#include #include "Common/Analytics.h" #include "Common/CommonTypes.h" @@ -23,211 +23,201 @@ constexpr u8 WIRE_FORMAT_VERSION = 0; // format. enum class TypeId : u8 { - STRING = 0, - BOOL = 1, - UINT = 2, - SINT = 3, - FLOAT = 4, + STRING = 0, + BOOL = 1, + UINT = 2, + SINT = 3, + FLOAT = 4, }; void AppendBool(std::string* out, bool v) { - out->push_back(v ? '\xFF' : '\x00'); + out->push_back(v ? '\xFF' : '\x00'); } void AppendVarInt(std::string* out, u64 v) { - do - { - u8 current_byte = v & 0x7F; - v >>= 7; - current_byte |= (!!v) << 7; - out->push_back(current_byte); - } - while (v); + do + { + u8 current_byte = v & 0x7F; + v >>= 7; + current_byte |= (!!v) << 7; + out->push_back(current_byte); + } while (v); } -void AppendBytes(std::string* out, const u8* bytes, u32 length, - bool encode_length = true) +void AppendBytes(std::string* out, const u8* bytes, u32 length, bool encode_length = true) { - if (encode_length) - { - AppendVarInt(out, length); - } - out->append(reinterpret_cast(bytes), length); + if (encode_length) + { + AppendVarInt(out, length); + } + out->append(reinterpret_cast(bytes), length); } void AppendType(std::string* out, TypeId type) { - out->push_back(static_cast(type)); + out->push_back(static_cast(type)); } // Dummy write function for curl. size_t DummyCurlWriteFunction(char* ptr, size_t size, size_t nmemb, void* userdata) { - return size * nmemb; + return size * nmemb; } } // namespace AnalyticsReportBuilder::AnalyticsReportBuilder() { - m_report.push_back(WIRE_FORMAT_VERSION); + m_report.push_back(WIRE_FORMAT_VERSION); } -void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, - const std::string& v) +void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, const std::string& v) { - AppendType(report, TypeId::STRING); - AppendBytes(report, reinterpret_cast(v.data()), static_cast(v.size())); + AppendType(report, TypeId::STRING); + AppendBytes(report, reinterpret_cast(v.data()), static_cast(v.size())); } -void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, - const char* v) +void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, const char* v) { - AppendSerializedValue(report, std::string(v)); + AppendSerializedValue(report, std::string(v)); } -void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, - bool v) +void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, bool v) { - AppendType(report, TypeId::BOOL); - AppendBool(report, v); + AppendType(report, TypeId::BOOL); + AppendBool(report, v); } -void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, - u64 v) +void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, u64 v) { - AppendType(report, TypeId::UINT); - AppendVarInt(report, v); + AppendType(report, TypeId::UINT); + AppendVarInt(report, v); } -void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, - s64 v) +void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, s64 v) { - AppendType(report, TypeId::SINT); - AppendBool(report, v >= 0); - AppendVarInt(report, static_cast(std::abs(v))); + AppendType(report, TypeId::SINT); + AppendBool(report, v >= 0); + AppendVarInt(report, static_cast(std::abs(v))); } -void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, - u32 v) +void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, u32 v) { - AppendSerializedValue(report, static_cast(v)); + AppendSerializedValue(report, static_cast(v)); } -void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, - s32 v) +void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, s32 v) { - AppendSerializedValue(report, static_cast(v)); + AppendSerializedValue(report, static_cast(v)); } -void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, - float v) +void AnalyticsReportBuilder::AppendSerializedValue(std::string* report, float v) { - AppendType(report, TypeId::FLOAT); - AppendBytes(report, reinterpret_cast(&v), sizeof (v), false); + AppendType(report, TypeId::FLOAT); + AppendBytes(report, reinterpret_cast(&v), sizeof(v), false); } AnalyticsReporter::AnalyticsReporter() { - m_reporter_thread = std::thread(&AnalyticsReporter::ThreadProc, this); + m_reporter_thread = std::thread(&AnalyticsReporter::ThreadProc, this); } AnalyticsReporter::~AnalyticsReporter() { - // Set the exit request flag and wait for the thread to honor it. - m_reporter_stop_request.Set(); - m_reporter_event.Set(); - m_reporter_thread.join(); + // Set the exit request flag and wait for the thread to honor it. + m_reporter_stop_request.Set(); + m_reporter_event.Set(); + m_reporter_thread.join(); } void AnalyticsReporter::Send(AnalyticsReportBuilder&& report) { - // Put a bound on the size of the queue to avoid uncontrolled memory growth. - constexpr u32 QUEUE_SIZE_LIMIT = 25; - if (m_reports_queue.Size() < QUEUE_SIZE_LIMIT) - { - m_reports_queue.Push(report.Consume()); - m_reporter_event.Set(); - } + // Put a bound on the size of the queue to avoid uncontrolled memory growth. + constexpr u32 QUEUE_SIZE_LIMIT = 25; + if (m_reports_queue.Size() < QUEUE_SIZE_LIMIT) + { + m_reports_queue.Push(report.Consume()); + m_reporter_event.Set(); + } } void AnalyticsReporter::ThreadProc() { - while (true) - { - m_reporter_event.Wait(); - if (m_reporter_stop_request.IsSet()) - { - return; - } + while (true) + { + m_reporter_event.Wait(); + if (m_reporter_stop_request.IsSet()) + { + return; + } - while (!m_reports_queue.Empty()) - { - std::shared_ptr backend(m_backend); + while (!m_reports_queue.Empty()) + { + std::shared_ptr backend(m_backend); - if (backend) - { - std::string report; - m_reports_queue.Pop(report); - backend->Send(std::move(report)); - } - else - { - break; - } + if (backend) + { + std::string report; + m_reports_queue.Pop(report); + backend->Send(std::move(report)); + } + else + { + break; + } - // Recheck after each report sent. - if (m_reporter_stop_request.IsSet()) - { - return; - } - } - } + // Recheck after each report sent. + if (m_reporter_stop_request.IsSet()) + { + return; + } + } + } } void StdoutAnalyticsBackend::Send(std::string report) { - printf("Analytics report sent:\n%s", HexDump( - reinterpret_cast(report.data()), report.size()).c_str()); + printf("Analytics report sent:\n%s", + HexDump(reinterpret_cast(report.data()), report.size()).c_str()); } HttpAnalyticsBackend::HttpAnalyticsBackend(const std::string& endpoint) { - CURL* curl = curl_easy_init(); - if (curl) - { - curl_easy_setopt(curl, CURLOPT_URL, endpoint.c_str()); - curl_easy_setopt(curl, CURLOPT_POST, true); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &DummyCurlWriteFunction); - curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 3000); + CURL* curl = curl_easy_init(); + if (curl) + { + curl_easy_setopt(curl, CURLOPT_URL, endpoint.c_str()); + curl_easy_setopt(curl, CURLOPT_POST, true); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &DummyCurlWriteFunction); + curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 3000); #ifdef _WIN32 - // ALPN support is enabled by default but requires Windows >= 8.1. - curl_easy_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, false); + // ALPN support is enabled by default but requires Windows >= 8.1. + curl_easy_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, false); #endif - m_curl = curl; - } + m_curl = curl; + } } HttpAnalyticsBackend::~HttpAnalyticsBackend() { - if (m_curl) - { - curl_easy_cleanup(m_curl); - } + if (m_curl) + { + curl_easy_cleanup(m_curl); + } } void HttpAnalyticsBackend::Send(std::string report) { - if (!m_curl) - return; + if (!m_curl) + return; - curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, report.c_str()); - curl_easy_setopt(m_curl, CURLOPT_POSTFIELDSIZE, report.size()); - curl_easy_perform(m_curl); + curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, report.c_str()); + curl_easy_setopt(m_curl, CURLOPT_POSTFIELDSIZE, report.size()); + curl_easy_perform(m_curl); } } // namespace Common diff --git a/Source/Core/Common/Analytics.h b/Source/Core/Common/Analytics.h index 608496cc3f..e656d4fd4c 100644 --- a/Source/Core/Common/Analytics.h +++ b/Source/Core/Common/Analytics.h @@ -41,132 +41,123 @@ typedef void CURL; namespace Common { - // Generic interface for an analytics reporting backends. The main // implementation used in Dolphin can be found in Core/Analytics.h. class AnalyticsReportingBackend { public: - virtual ~AnalyticsReportingBackend() {} - - // Called from the AnalyticsReporter backend thread. - virtual void Send(std::string report) = 0; + virtual ~AnalyticsReportingBackend() {} + // Called from the AnalyticsReporter backend thread. + virtual void Send(std::string report) = 0; }; // Builder object for an analytics report. class AnalyticsReportBuilder { public: - AnalyticsReportBuilder(); - ~AnalyticsReportBuilder() = default; + AnalyticsReportBuilder(); + ~AnalyticsReportBuilder() = default; - AnalyticsReportBuilder(const AnalyticsReportBuilder& other) - { - *this = other; - } + AnalyticsReportBuilder(const AnalyticsReportBuilder& other) { *this = other; } + AnalyticsReportBuilder(AnalyticsReportBuilder&& other) + { + std::lock_guard lk(other.m_lock); + m_report = std::move(other.m_report); + } - AnalyticsReportBuilder(AnalyticsReportBuilder&& other) - { - std::lock_guard lk(other.m_lock); - m_report = std::move(other.m_report); - } + const AnalyticsReportBuilder& operator=(const AnalyticsReportBuilder& other) + { + if (this != &other) + { + std::lock_guard lk(m_lock); + std::lock_guard lk2(other.m_lock); + m_report = other.m_report; + } + return *this; + } - const AnalyticsReportBuilder& operator=(const AnalyticsReportBuilder& other) - { - if (this != &other) - { - std::lock_guard lk(m_lock); - std::lock_guard lk2(other.m_lock); - m_report = other.m_report; - } - return *this; - } + // Append another builder to this one. + AnalyticsReportBuilder& AddBuilder(const AnalyticsReportBuilder& other) + { + // Get before locking the object to avoid deadlocks with this += this. + std::string other_report = other.Get(); + std::lock_guard lk(m_lock); + m_report += other_report; + return *this; + } - // Append another builder to this one. - AnalyticsReportBuilder& AddBuilder(const AnalyticsReportBuilder& other) - { - // Get before locking the object to avoid deadlocks with this += this. - std::string other_report = other.Get(); - std::lock_guard lk(m_lock); - m_report += other_report; - return *this; - } + template + AnalyticsReportBuilder& AddData(const std::string& key, const T& value) + { + std::lock_guard lk(m_lock); + AppendSerializedValue(&m_report, key); + AppendSerializedValue(&m_report, value); + return *this; + } - template - AnalyticsReportBuilder& AddData(const std::string& key, const T& value) - { - std::lock_guard lk(m_lock); - AppendSerializedValue(&m_report, key); - AppendSerializedValue(&m_report, value); - return *this; - } + std::string Get() const + { + std::lock_guard lk(m_lock); + return m_report; + } - std::string Get() const - { - std::lock_guard lk(m_lock); - return m_report; - } - - // More efficient version of Get(). - std::string Consume() - { - std::lock_guard lk(m_lock); - return std::move(m_report); - } + // More efficient version of Get(). + std::string Consume() + { + std::lock_guard lk(m_lock); + return std::move(m_report); + } protected: - static void AppendSerializedValue(std::string* report, const std::string& v); - static void AppendSerializedValue(std::string* report, const char* v); - static void AppendSerializedValue(std::string* report, bool v); - static void AppendSerializedValue(std::string* report, u64 v); - static void AppendSerializedValue(std::string* report, s64 v); - static void AppendSerializedValue(std::string* report, u32 v); - static void AppendSerializedValue(std::string* report, s32 v); - static void AppendSerializedValue(std::string* report, float v); + static void AppendSerializedValue(std::string* report, const std::string& v); + static void AppendSerializedValue(std::string* report, const char* v); + static void AppendSerializedValue(std::string* report, bool v); + static void AppendSerializedValue(std::string* report, u64 v); + static void AppendSerializedValue(std::string* report, s64 v); + static void AppendSerializedValue(std::string* report, u32 v); + static void AppendSerializedValue(std::string* report, s32 v); + static void AppendSerializedValue(std::string* report, float v); - // Should really be a std::shared_mutex, unfortunately that's C++17 only. - mutable std::mutex m_lock; - std::string m_report; + // Should really be a std::shared_mutex, unfortunately that's C++17 only. + mutable std::mutex m_lock; + std::string m_report; }; class AnalyticsReporter { public: - AnalyticsReporter(); - ~AnalyticsReporter(); + AnalyticsReporter(); + ~AnalyticsReporter(); - // Sets a reporting backend and enables sending reports. Do not set a remote - // backend without user consent. - void SetBackend(std::unique_ptr backend) - { - m_backend = std::move(backend); - m_reporter_event.Set(); // In case reports are waiting queued. - } + // Sets a reporting backend and enables sending reports. Do not set a remote + // backend without user consent. + void SetBackend(std::unique_ptr backend) + { + m_backend = std::move(backend); + m_reporter_event.Set(); // In case reports are waiting queued. + } - // Gets the base report builder which is closed for each subsequent report - // being sent. DO NOT use this builder to send a report. Only use it to add - // new fields that should be globally available. - AnalyticsReportBuilder& BaseBuilder() { return m_base_builder; } - - // Gets a cloned builder that can be used to send a report. - AnalyticsReportBuilder Builder() const { return m_base_builder; } - - // Enqueues a report for sending. Consumes the report builder. - void Send(AnalyticsReportBuilder&& report); - - // For convenience. - void Send(AnalyticsReportBuilder& report) { Send(std::move(report)); } + // Gets the base report builder which is closed for each subsequent report + // being sent. DO NOT use this builder to send a report. Only use it to add + // new fields that should be globally available. + AnalyticsReportBuilder& BaseBuilder() { return m_base_builder; } + // Gets a cloned builder that can be used to send a report. + AnalyticsReportBuilder Builder() const { return m_base_builder; } + // Enqueues a report for sending. Consumes the report builder. + void Send(AnalyticsReportBuilder&& report); + // For convenience. + void Send(AnalyticsReportBuilder& report) { Send(std::move(report)); } protected: - void ThreadProc(); + void ThreadProc(); - std::shared_ptr m_backend; - AnalyticsReportBuilder m_base_builder; + std::shared_ptr m_backend; + AnalyticsReportBuilder m_base_builder; - std::thread m_reporter_thread; - Common::Event m_reporter_event; - Common::Flag m_reporter_stop_request; - FifoQueue m_reports_queue; + std::thread m_reporter_thread; + Common::Event m_reporter_event; + Common::Flag m_reporter_stop_request; + FifoQueue m_reports_queue; }; // Analytics backend to be used for debugging purpose, which dumps reports to @@ -174,7 +165,7 @@ protected: class StdoutAnalyticsBackend : public AnalyticsReportingBackend { public: - void Send(std::string report) override; + void Send(std::string report) override; }; // Analytics backend that POSTs data to a remote HTTP(s) endpoint. WARNING: @@ -182,13 +173,13 @@ public: class HttpAnalyticsBackend : public AnalyticsReportingBackend { public: - HttpAnalyticsBackend(const std::string& endpoint); - ~HttpAnalyticsBackend() override; + HttpAnalyticsBackend(const std::string& endpoint); + ~HttpAnalyticsBackend() override; - void Send(std::string report) override; + void Send(std::string report) override; protected: - CURL* m_curl = nullptr; + CURL* m_curl = nullptr; }; } // namespace Common diff --git a/Source/Core/Common/Arm64Emitter.cpp b/Source/Core/Common/Arm64Emitter.cpp index d7c53ba289..380437e3b0 100644 --- a/Source/Core/Common/Arm64Emitter.cpp +++ b/Source/Core/Common/Arm64Emitter.cpp @@ -13,4161 +13,4304 @@ namespace Arm64Gen { - const int kWRegSizeInBits = 32; const int kXRegSizeInBits = 64; // The below few functions are taken from V8. static int CountLeadingZeros(uint64_t value, int width) { - // TODO(jbramley): Optimize this for ARM64 hosts. - int count = 0; - uint64_t bit_test = 1ULL << (width - 1); - while ((count < width) && ((bit_test & value) == 0)) - { - count++; - bit_test >>= 1; - } - return count; + // TODO(jbramley): Optimize this for ARM64 hosts. + int count = 0; + uint64_t bit_test = 1ULL << (width - 1); + while ((count < width) && ((bit_test & value) == 0)) + { + count++; + bit_test >>= 1; + } + return count; } static uint64_t LargestPowerOf2Divisor(uint64_t value) { - return value & -(int64_t)value; + return value & -(int64_t)value; } static bool IsPowerOfTwo(uint64_t x) { - return (x != 0) && ((x & (x - 1)) == 0); + return (x != 0) && ((x & (x - 1)) == 0); } #define V8_UINT64_C(x) ((uint64_t)(x)) bool IsImmArithmetic(uint64_t input, u32* val, bool* shift) { - if (input < 4096) - { - *val = input; - *shift = false; - return true; - } - else if ((input & 0xFFF000) == input) - { - *val = input >> 12; - *shift = true; - return true; - } - return false; + if (input < 4096) + { + *val = input; + *shift = false; + return true; + } + else if ((input & 0xFFF000) == input) + { + *val = input >> 12; + *shift = true; + return true; + } + return false; } -bool IsImmLogical(uint64_t value, unsigned int width, unsigned int* n, unsigned int* imm_s, unsigned int* imm_r) +bool IsImmLogical(uint64_t value, unsigned int width, unsigned int* n, unsigned int* imm_s, + unsigned int* imm_r) { - //DCHECK((n != NULL) && (imm_s != NULL) && (imm_r != NULL)); - // DCHECK((width == kWRegSizeInBits) || (width == kXRegSizeInBits)); + // DCHECK((n != NULL) && (imm_s != NULL) && (imm_r != NULL)); + // DCHECK((width == kWRegSizeInBits) || (width == kXRegSizeInBits)); - bool negate = false; + bool negate = false; - // Logical immediates are encoded using parameters n, imm_s and imm_r using - // the following table: - // - // N imms immr size S R - // 1 ssssss rrrrrr 64 UInt(ssssss) UInt(rrrrrr) - // 0 0sssss xrrrrr 32 UInt(sssss) UInt(rrrrr) - // 0 10ssss xxrrrr 16 UInt(ssss) UInt(rrrr) - // 0 110sss xxxrrr 8 UInt(sss) UInt(rrr) - // 0 1110ss xxxxrr 4 UInt(ss) UInt(rr) - // 0 11110s xxxxxr 2 UInt(s) UInt(r) - // (s bits must not be all set) - // - // A pattern is constructed of size bits, where the least significant S+1 bits - // are set. The pattern is rotated right by R, and repeated across a 32 or - // 64-bit value, depending on destination register width. - // - // Put another way: the basic format of a logical immediate is a single - // contiguous stretch of 1 bits, repeated across the whole word at intervals - // given by a power of 2. To identify them quickly, we first locate the - // lowest stretch of 1 bits, then the next 1 bit above that; that combination - // is different for every logical immediate, so it gives us all the - // information we need to identify the only logical immediate that our input - // could be, and then we simply check if that's the value we actually have. - // - // (The rotation parameter does give the possibility of the stretch of 1 bits - // going 'round the end' of the word. To deal with that, we observe that in - // any situation where that happens the bitwise NOT of the value is also a - // valid logical immediate. So we simply invert the input whenever its low bit - // is set, and then we know that the rotated case can't arise.) + // Logical immediates are encoded using parameters n, imm_s and imm_r using + // the following table: + // + // N imms immr size S R + // 1 ssssss rrrrrr 64 UInt(ssssss) UInt(rrrrrr) + // 0 0sssss xrrrrr 32 UInt(sssss) UInt(rrrrr) + // 0 10ssss xxrrrr 16 UInt(ssss) UInt(rrrr) + // 0 110sss xxxrrr 8 UInt(sss) UInt(rrr) + // 0 1110ss xxxxrr 4 UInt(ss) UInt(rr) + // 0 11110s xxxxxr 2 UInt(s) UInt(r) + // (s bits must not be all set) + // + // A pattern is constructed of size bits, where the least significant S+1 bits + // are set. The pattern is rotated right by R, and repeated across a 32 or + // 64-bit value, depending on destination register width. + // + // Put another way: the basic format of a logical immediate is a single + // contiguous stretch of 1 bits, repeated across the whole word at intervals + // given by a power of 2. To identify them quickly, we first locate the + // lowest stretch of 1 bits, then the next 1 bit above that; that combination + // is different for every logical immediate, so it gives us all the + // information we need to identify the only logical immediate that our input + // could be, and then we simply check if that's the value we actually have. + // + // (The rotation parameter does give the possibility of the stretch of 1 bits + // going 'round the end' of the word. To deal with that, we observe that in + // any situation where that happens the bitwise NOT of the value is also a + // valid logical immediate. So we simply invert the input whenever its low bit + // is set, and then we know that the rotated case can't arise.) - if (value & 1) - { - // If the low bit is 1, negate the value, and set a flag to remember that we - // did (so that we can adjust the return values appropriately). - negate = true; - value = ~value; - } + if (value & 1) + { + // If the low bit is 1, negate the value, and set a flag to remember that we + // did (so that we can adjust the return values appropriately). + negate = true; + value = ~value; + } - if (width == kWRegSizeInBits) - { - // To handle 32-bit logical immediates, the very easiest thing is to repeat - // the input value twice to make a 64-bit word. The correct encoding of that - // as a logical immediate will also be the correct encoding of the 32-bit - // value. + if (width == kWRegSizeInBits) + { + // To handle 32-bit logical immediates, the very easiest thing is to repeat + // the input value twice to make a 64-bit word. The correct encoding of that + // as a logical immediate will also be the correct encoding of the 32-bit + // value. - // The most-significant 32 bits may not be zero (ie. negate is true) so - // shift the value left before duplicating it. - value <<= kWRegSizeInBits; - value |= value >> kWRegSizeInBits; - } + // The most-significant 32 bits may not be zero (ie. negate is true) so + // shift the value left before duplicating it. + value <<= kWRegSizeInBits; + value |= value >> kWRegSizeInBits; + } - // The basic analysis idea: imagine our input word looks like this. - // - // 0011111000111110001111100011111000111110001111100011111000111110 - // c b a - // |<--d-->| - // - // We find the lowest set bit (as an actual power-of-2 value, not its index) - // and call it a. Then we add a to our original number, which wipes out the - // bottommost stretch of set bits and replaces it with a 1 carried into the - // next zero bit. Then we look for the new lowest set bit, which is in - // position b, and subtract it, so now our number is just like the original - // but with the lowest stretch of set bits completely gone. Now we find the - // lowest set bit again, which is position c in the diagram above. Then we'll - // measure the distance d between bit positions a and c (using CLZ), and that - // tells us that the only valid logical immediate that could possibly be equal - // to this number is the one in which a stretch of bits running from a to just - // below b is replicated every d bits. - uint64_t a = LargestPowerOf2Divisor(value); - uint64_t value_plus_a = value + a; - uint64_t b = LargestPowerOf2Divisor(value_plus_a); - uint64_t value_plus_a_minus_b = value_plus_a - b; - uint64_t c = LargestPowerOf2Divisor(value_plus_a_minus_b); + // The basic analysis idea: imagine our input word looks like this. + // + // 0011111000111110001111100011111000111110001111100011111000111110 + // c b a + // |<--d-->| + // + // We find the lowest set bit (as an actual power-of-2 value, not its index) + // and call it a. Then we add a to our original number, which wipes out the + // bottommost stretch of set bits and replaces it with a 1 carried into the + // next zero bit. Then we look for the new lowest set bit, which is in + // position b, and subtract it, so now our number is just like the original + // but with the lowest stretch of set bits completely gone. Now we find the + // lowest set bit again, which is position c in the diagram above. Then we'll + // measure the distance d between bit positions a and c (using CLZ), and that + // tells us that the only valid logical immediate that could possibly be equal + // to this number is the one in which a stretch of bits running from a to just + // below b is replicated every d bits. + uint64_t a = LargestPowerOf2Divisor(value); + uint64_t value_plus_a = value + a; + uint64_t b = LargestPowerOf2Divisor(value_plus_a); + uint64_t value_plus_a_minus_b = value_plus_a - b; + uint64_t c = LargestPowerOf2Divisor(value_plus_a_minus_b); - int d, clz_a, out_n; - uint64_t mask; + int d, clz_a, out_n; + uint64_t mask; - if (c != 0) - { - // The general case, in which there is more than one stretch of set bits. - // Compute the repeat distance d, and set up a bitmask covering the basic - // unit of repetition (i.e. a word with the bottom d bits set). Also, in all - // of these cases the N bit of the output will be zero. - clz_a = CountLeadingZeros(a, kXRegSizeInBits); - int clz_c = CountLeadingZeros(c, kXRegSizeInBits); - d = clz_a - clz_c; - mask = ((V8_UINT64_C(1) << d) - 1); - out_n = 0; - } - else - { - // Handle degenerate cases. - // - // If any of those 'find lowest set bit' operations didn't find a set bit at - // all, then the word will have been zero thereafter, so in particular the - // last lowest_set_bit operation will have returned zero. So we can test for - // all the special case conditions in one go by seeing if c is zero. - if (a == 0) - { - // The input was zero (or all 1 bits, which will come to here too after we - // inverted it at the start of the function), for which we just return - // false. - return false; - } - else - { - // Otherwise, if c was zero but a was not, then there's just one stretch - // of set bits in our word, meaning that we have the trivial case of - // d == 64 and only one 'repetition'. Set up all the same variables as in - // the general case above, and set the N bit in the output. - clz_a = CountLeadingZeros(a, kXRegSizeInBits); - d = 64; - mask = ~V8_UINT64_C(0); - out_n = 1; - } - } + if (c != 0) + { + // The general case, in which there is more than one stretch of set bits. + // Compute the repeat distance d, and set up a bitmask covering the basic + // unit of repetition (i.e. a word with the bottom d bits set). Also, in all + // of these cases the N bit of the output will be zero. + clz_a = CountLeadingZeros(a, kXRegSizeInBits); + int clz_c = CountLeadingZeros(c, kXRegSizeInBits); + d = clz_a - clz_c; + mask = ((V8_UINT64_C(1) << d) - 1); + out_n = 0; + } + else + { + // Handle degenerate cases. + // + // If any of those 'find lowest set bit' operations didn't find a set bit at + // all, then the word will have been zero thereafter, so in particular the + // last lowest_set_bit operation will have returned zero. So we can test for + // all the special case conditions in one go by seeing if c is zero. + if (a == 0) + { + // The input was zero (or all 1 bits, which will come to here too after we + // inverted it at the start of the function), for which we just return + // false. + return false; + } + else + { + // Otherwise, if c was zero but a was not, then there's just one stretch + // of set bits in our word, meaning that we have the trivial case of + // d == 64 and only one 'repetition'. Set up all the same variables as in + // the general case above, and set the N bit in the output. + clz_a = CountLeadingZeros(a, kXRegSizeInBits); + d = 64; + mask = ~V8_UINT64_C(0); + out_n = 1; + } + } - // If the repeat period d is not a power of two, it can't be encoded. - if (!IsPowerOfTwo(d)) - return false; + // If the repeat period d is not a power of two, it can't be encoded. + if (!IsPowerOfTwo(d)) + return false; - // If the bit stretch (b - a) does not fit within the mask derived from the - // repeat period, then fail. - if (((b - a) & ~mask) != 0) - return false; + // If the bit stretch (b - a) does not fit within the mask derived from the + // repeat period, then fail. + if (((b - a) & ~mask) != 0) + return false; - // The only possible option is b - a repeated every d bits. Now we're going to - // actually construct the valid logical immediate derived from that - // specification, and see if it equals our original input. - // - // To repeat a value every d bits, we multiply it by a number of the form - // (1 + 2^d + 2^(2d) + ...), i.e. 0x0001000100010001 or similar. These can - // be derived using a table lookup on CLZ(d). - static const std::array multipliers = - { - 0x0000000000000001UL, - 0x0000000100000001UL, - 0x0001000100010001UL, - 0x0101010101010101UL, - 0x1111111111111111UL, - 0x5555555555555555UL, - }; + // The only possible option is b - a repeated every d bits. Now we're going to + // actually construct the valid logical immediate derived from that + // specification, and see if it equals our original input. + // + // To repeat a value every d bits, we multiply it by a number of the form + // (1 + 2^d + 2^(2d) + ...), i.e. 0x0001000100010001 or similar. These can + // be derived using a table lookup on CLZ(d). + static const std::array multipliers = { + 0x0000000000000001UL, 0x0000000100000001UL, 0x0001000100010001UL, + 0x0101010101010101UL, 0x1111111111111111UL, 0x5555555555555555UL, + }; - int multiplier_idx = CountLeadingZeros(d, kXRegSizeInBits) - 57; + int multiplier_idx = CountLeadingZeros(d, kXRegSizeInBits) - 57; - // Ensure that the index to the multipliers array is within bounds. - _dbg_assert_(DYNA_REC, (multiplier_idx >= 0) && - (static_cast(multiplier_idx) < multipliers.size())); + // Ensure that the index to the multipliers array is within bounds. + _dbg_assert_(DYNA_REC, + (multiplier_idx >= 0) && (static_cast(multiplier_idx) < multipliers.size())); - uint64_t multiplier = multipliers[multiplier_idx]; - uint64_t candidate = (b - a) * multiplier; + uint64_t multiplier = multipliers[multiplier_idx]; + uint64_t candidate = (b - a) * multiplier; - // The candidate pattern doesn't match our input value, so fail. - if (value != candidate) - return false; + // The candidate pattern doesn't match our input value, so fail. + if (value != candidate) + return false; - // We have a match! This is a valid logical immediate, so now we have to - // construct the bits and pieces of the instruction encoding that generates - // it. + // We have a match! This is a valid logical immediate, so now we have to + // construct the bits and pieces of the instruction encoding that generates + // it. - // Count the set bits in our basic stretch. The special case of clz(0) == -1 - // makes the answer come out right for stretches that reach the very top of - // the word (e.g. numbers like 0xffffc00000000000). - int clz_b = (b == 0) ? -1 : CountLeadingZeros(b, kXRegSizeInBits); - int s = clz_a - clz_b; + // Count the set bits in our basic stretch. The special case of clz(0) == -1 + // makes the answer come out right for stretches that reach the very top of + // the word (e.g. numbers like 0xffffc00000000000). + int clz_b = (b == 0) ? -1 : CountLeadingZeros(b, kXRegSizeInBits); + int s = clz_a - clz_b; - // Decide how many bits to rotate right by, to put the low bit of that basic - // stretch in position a. - int r; - if (negate) - { - // If we inverted the input right at the start of this function, here's - // where we compensate: the number of set bits becomes the number of clear - // bits, and the rotation count is based on position b rather than position - // a (since b is the location of the 'lowest' 1 bit after inversion). - s = d - s; - r = (clz_b + 1) & (d - 1); - } - else - { - r = (clz_a + 1) & (d - 1); - } + // Decide how many bits to rotate right by, to put the low bit of that basic + // stretch in position a. + int r; + if (negate) + { + // If we inverted the input right at the start of this function, here's + // where we compensate: the number of set bits becomes the number of clear + // bits, and the rotation count is based on position b rather than position + // a (since b is the location of the 'lowest' 1 bit after inversion). + s = d - s; + r = (clz_b + 1) & (d - 1); + } + else + { + r = (clz_a + 1) & (d - 1); + } - // Now we're done, except for having to encode the S output in such a way that - // it gives both the number of set bits and the length of the repeated - // segment. The s field is encoded like this: - // - // imms size S - // ssssss 64 UInt(ssssss) - // 0sssss 32 UInt(sssss) - // 10ssss 16 UInt(ssss) - // 110sss 8 UInt(sss) - // 1110ss 4 UInt(ss) - // 11110s 2 UInt(s) - // - // So we 'or' (-d << 1) with our computed s to form imms. - *n = out_n; - *imm_s = ((-d << 1) | (s - 1)) & 0x3f; - *imm_r = r; + // Now we're done, except for having to encode the S output in such a way that + // it gives both the number of set bits and the length of the repeated + // segment. The s field is encoded like this: + // + // imms size S + // ssssss 64 UInt(ssssss) + // 0sssss 32 UInt(sssss) + // 10ssss 16 UInt(ssss) + // 110sss 8 UInt(sss) + // 1110ss 4 UInt(ss) + // 11110s 2 UInt(s) + // + // So we 'or' (-d << 1) with our computed s to form imms. + *n = out_n; + *imm_s = ((-d << 1) | (s - 1)) & 0x3f; + *imm_r = r; - return true; + return true; } void ARM64XEmitter::SetCodePtrUnsafe(u8* ptr) { - m_code = ptr; + m_code = ptr; } void ARM64XEmitter::SetCodePtr(u8* ptr) { - SetCodePtrUnsafe(ptr); - m_lastCacheFlushEnd = ptr; + SetCodePtrUnsafe(ptr); + m_lastCacheFlushEnd = ptr; } const u8* ARM64XEmitter::GetCodePtr() const { - return m_code; + return m_code; } u8* ARM64XEmitter::GetWritableCodePtr() { - return m_code; + return m_code; } void ARM64XEmitter::ReserveCodeSpace(u32 bytes) { - for (u32 i = 0; i < bytes/4; i++) - BRK(0); + for (u32 i = 0; i < bytes / 4; i++) + BRK(0); } const u8* ARM64XEmitter::AlignCode16() { - int c = int((u64)m_code & 15); - if (c) - ReserveCodeSpace(16-c); - return m_code; + int c = int((u64)m_code & 15); + if (c) + ReserveCodeSpace(16 - c); + return m_code; } const u8* ARM64XEmitter::AlignCodePage() { - int c = int((u64)m_code & 4095); - if (c) - ReserveCodeSpace(4096-c); - return m_code; + int c = int((u64)m_code & 4095); + if (c) + ReserveCodeSpace(4096 - c); + return m_code; } void ARM64XEmitter::Write32(u32 value) { - std::memcpy(m_code, &value, sizeof(u32)); - m_code += sizeof(u32); + std::memcpy(m_code, &value, sizeof(u32)); + m_code += sizeof(u32); } void ARM64XEmitter::FlushIcache() { - FlushIcacheSection(m_lastCacheFlushEnd, m_code); - m_lastCacheFlushEnd = m_code; + FlushIcacheSection(m_lastCacheFlushEnd, m_code); + m_lastCacheFlushEnd = m_code; } void ARM64XEmitter::FlushIcacheSection(u8* start, u8* end) { - if (start == end) - return; + if (start == end) + return; #if defined(IOS) - // Header file says this is equivalent to: sys_icache_invalidate(start, end - start); - sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start); + // Header file says this is equivalent to: sys_icache_invalidate(start, end - start); + sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start); #else #ifdef __clang__ - __clear_cache(start, end); + __clear_cache(start, end); #else - __builtin___clear_cache(start, end); + __builtin___clear_cache(start, end); #endif #endif } // Exception generation static const u32 ExcEnc[][3] = { - {0, 0, 1}, // SVC - {0, 0, 2}, // HVC - {0, 0, 3}, // SMC - {1, 0, 0}, // BRK - {2, 0, 0}, // HLT - {5, 0, 1}, // DCPS1 - {5, 0, 2}, // DCPS2 - {5, 0, 3}, // DCPS3 + {0, 0, 1}, // SVC + {0, 0, 2}, // HVC + {0, 0, 3}, // SMC + {1, 0, 0}, // BRK + {2, 0, 0}, // HLT + {5, 0, 1}, // DCPS1 + {5, 0, 2}, // DCPS2 + {5, 0, 3}, // DCPS3 }; // Arithmetic generation static const u32 ArithEnc[] = { - 0x058, // ADD - 0x258, // SUB + 0x058, // ADD + 0x258, // SUB }; // Conditional Select static const u32 CondSelectEnc[][2] = { - {0, 0}, // CSEL - {0, 1}, // CSINC - {1, 0}, // CSINV - {1, 1}, // CSNEG + {0, 0}, // CSEL + {0, 1}, // CSINC + {1, 0}, // CSINV + {1, 1}, // CSNEG }; // Data-Processing (1 source) static const u32 Data1SrcEnc[][2] = { - {0, 0}, // RBIT - {0, 1}, // REV16 - {0, 2}, // REV32 - {0, 3}, // REV64 - {0, 4}, // CLZ - {0, 5}, // CLS + {0, 0}, // RBIT + {0, 1}, // REV16 + {0, 2}, // REV32 + {0, 3}, // REV64 + {0, 4}, // CLZ + {0, 5}, // CLS }; // Data-Processing (2 source) static const u32 Data2SrcEnc[] = { - 0x02, // UDIV - 0x03, // SDIV - 0x08, // LSLV - 0x09, // LSRV - 0x0A, // ASRV - 0x0B, // RORV - 0x10, // CRC32B - 0x11, // CRC32H - 0x12, // CRC32W - 0x14, // CRC32CB - 0x15, // CRC32CH - 0x16, // CRC32CW - 0x13, // CRC32X (64bit Only) - 0x17, // XRC32CX (64bit Only) + 0x02, // UDIV + 0x03, // SDIV + 0x08, // LSLV + 0x09, // LSRV + 0x0A, // ASRV + 0x0B, // RORV + 0x10, // CRC32B + 0x11, // CRC32H + 0x12, // CRC32W + 0x14, // CRC32CB + 0x15, // CRC32CH + 0x16, // CRC32CW + 0x13, // CRC32X (64bit Only) + 0x17, // XRC32CX (64bit Only) }; // Data-Processing (3 source) static const u32 Data3SrcEnc[][2] = { - {0, 0}, // MADD - {0, 1}, // MSUB - {1, 0}, // SMADDL (64Bit Only) - {1, 1}, // SMSUBL (64Bit Only) - {2, 0}, // SMULH (64Bit Only) - {5, 0}, // UMADDL (64Bit Only) - {5, 1}, // UMSUBL (64Bit Only) - {6, 0}, // UMULH (64Bit Only) + {0, 0}, // MADD + {0, 1}, // MSUB + {1, 0}, // SMADDL (64Bit Only) + {1, 1}, // SMSUBL (64Bit Only) + {2, 0}, // SMULH (64Bit Only) + {5, 0}, // UMADDL (64Bit Only) + {5, 1}, // UMSUBL (64Bit Only) + {6, 0}, // UMULH (64Bit Only) }; // Logical (shifted register) static const u32 LogicalEnc[][2] = { - {0, 0}, // AND - {0, 1}, // BIC - {1, 0}, // OOR - {1, 1}, // ORN - {2, 0}, // EOR - {2, 1}, // EON - {3, 0}, // ANDS - {3, 1}, // BICS + {0, 0}, // AND + {0, 1}, // BIC + {1, 0}, // OOR + {1, 1}, // ORN + {2, 0}, // EOR + {2, 1}, // EON + {3, 0}, // ANDS + {3, 1}, // BICS }; // Load/Store Exclusive static const u32 LoadStoreExcEnc[][5] = { - {0, 0, 0, 0, 0}, // STXRB - {0, 0, 0, 0, 1}, // STLXRB - {0, 0, 1, 0, 0}, // LDXRB - {0, 0, 1, 0, 1}, // LDAXRB - {0, 1, 0, 0, 1}, // STLRB - {0, 1, 1, 0, 1}, // LDARB - {1, 0, 0, 0, 0}, // STXRH - {1, 0, 0, 0, 1}, // STLXRH - {1, 0, 1, 0, 0}, // LDXRH - {1, 0, 1, 0, 1}, // LDAXRH - {1, 1, 0, 0, 1}, // STLRH - {1, 1, 1, 0, 1}, // LDARH - {2, 0, 0, 0, 0}, // STXR - {3, 0, 0, 0, 0}, // (64bit) STXR - {2, 0, 0, 0, 1}, // STLXR - {3, 0, 0, 0, 1}, // (64bit) STLXR - {2, 0, 0, 1, 0}, // STXP - {3, 0, 0, 1, 0}, // (64bit) STXP - {2, 0, 0, 1, 1}, // STLXP - {3, 0, 0, 1, 1}, // (64bit) STLXP - {2, 0, 1, 0, 0}, // LDXR - {3, 0, 1, 0, 0}, // (64bit) LDXR - {2, 0, 1, 0, 1}, // LDAXR - {3, 0, 1, 0, 1}, // (64bit) LDAXR - {2, 0, 1, 1, 0}, // LDXP - {3, 0, 1, 1, 0}, // (64bit) LDXP - {2, 0, 1, 1, 1}, // LDAXP - {3, 0, 1, 1, 1}, // (64bit) LDAXP - {2, 1, 0, 0, 1}, // STLR - {3, 1, 0, 0, 1}, // (64bit) STLR - {2, 1, 1, 0, 1}, // LDAR - {3, 1, 1, 0, 1}, // (64bit) LDAR + {0, 0, 0, 0, 0}, // STXRB + {0, 0, 0, 0, 1}, // STLXRB + {0, 0, 1, 0, 0}, // LDXRB + {0, 0, 1, 0, 1}, // LDAXRB + {0, 1, 0, 0, 1}, // STLRB + {0, 1, 1, 0, 1}, // LDARB + {1, 0, 0, 0, 0}, // STXRH + {1, 0, 0, 0, 1}, // STLXRH + {1, 0, 1, 0, 0}, // LDXRH + {1, 0, 1, 0, 1}, // LDAXRH + {1, 1, 0, 0, 1}, // STLRH + {1, 1, 1, 0, 1}, // LDARH + {2, 0, 0, 0, 0}, // STXR + {3, 0, 0, 0, 0}, // (64bit) STXR + {2, 0, 0, 0, 1}, // STLXR + {3, 0, 0, 0, 1}, // (64bit) STLXR + {2, 0, 0, 1, 0}, // STXP + {3, 0, 0, 1, 0}, // (64bit) STXP + {2, 0, 0, 1, 1}, // STLXP + {3, 0, 0, 1, 1}, // (64bit) STLXP + {2, 0, 1, 0, 0}, // LDXR + {3, 0, 1, 0, 0}, // (64bit) LDXR + {2, 0, 1, 0, 1}, // LDAXR + {3, 0, 1, 0, 1}, // (64bit) LDAXR + {2, 0, 1, 1, 0}, // LDXP + {3, 0, 1, 1, 0}, // (64bit) LDXP + {2, 0, 1, 1, 1}, // LDAXP + {3, 0, 1, 1, 1}, // (64bit) LDAXP + {2, 1, 0, 0, 1}, // STLR + {3, 1, 0, 0, 1}, // (64bit) STLR + {2, 1, 1, 0, 1}, // LDAR + {3, 1, 1, 0, 1}, // (64bit) LDAR }; void ARM64XEmitter::EncodeCompareBranchInst(u32 op, ARM64Reg Rt, const void* ptr) { - bool b64Bit = Is64Bit(Rt); - s64 distance = (s64)ptr - (s64)m_code; + bool b64Bit = Is64Bit(Rt); + s64 distance = (s64)ptr - (s64)m_code; - _assert_msg_(DYNA_REC, !(distance & 0x3), "%s: distance must be a multiple of 4: %lx", __FUNCTION__, distance); + _assert_msg_(DYNA_REC, !(distance & 0x3), "%s: distance must be a multiple of 4: %lx", + __FUNCTION__, distance); - distance >>= 2; + distance >>= 2; - _assert_msg_(DYNA_REC, distance >= -0x40000 && distance <= 0x3FFFF, "%s: Received too large distance: %lx", __FUNCTION__, distance); + _assert_msg_(DYNA_REC, distance >= -0x40000 && distance <= 0x3FFFF, + "%s: Received too large distance: %lx", __FUNCTION__, distance); - Rt = DecodeReg(Rt); - Write32((b64Bit << 31) | (0x34 << 24) | (op << 24) | \ - (((u32)distance << 5) & 0xFFFFE0) | Rt); + Rt = DecodeReg(Rt); + Write32((b64Bit << 31) | (0x34 << 24) | (op << 24) | (((u32)distance << 5) & 0xFFFFE0) | Rt); } void ARM64XEmitter::EncodeTestBranchInst(u32 op, ARM64Reg Rt, u8 bits, const void* ptr) { - bool b64Bit = Is64Bit(Rt); - s64 distance = (s64)ptr - (s64)m_code; + bool b64Bit = Is64Bit(Rt); + s64 distance = (s64)ptr - (s64)m_code; - _assert_msg_(DYNA_REC, !(distance & 0x3), "%s: distance must be a multiple of 4: %lx", __FUNCTION__, distance); + _assert_msg_(DYNA_REC, !(distance & 0x3), "%s: distance must be a multiple of 4: %lx", + __FUNCTION__, distance); - distance >>= 2; + distance >>= 2; - _assert_msg_(DYNA_REC, distance >= -0x3FFF && distance < 0x3FFF, "%s: Received too large distance: %lx", __FUNCTION__, distance); + _assert_msg_(DYNA_REC, distance >= -0x3FFF && distance < 0x3FFF, + "%s: Received too large distance: %lx", __FUNCTION__, distance); - Rt = DecodeReg(Rt); - Write32((b64Bit << 31) | (0x36 << 24) | (op << 24) | \ - (bits << 19) | (((u32)distance << 5) & 0x7FFE0) | Rt); + Rt = DecodeReg(Rt); + Write32((b64Bit << 31) | (0x36 << 24) | (op << 24) | (bits << 19) | + (((u32)distance << 5) & 0x7FFE0) | Rt); } void ARM64XEmitter::EncodeUnconditionalBranchInst(u32 op, const void* ptr) { - s64 distance = (s64)ptr - s64(m_code); + s64 distance = (s64)ptr - s64(m_code); - _assert_msg_(DYNA_REC, !(distance & 0x3), "%s: distance must be a multiple of 4: %lx", __FUNCTION__, distance); + _assert_msg_(DYNA_REC, !(distance & 0x3), "%s: distance must be a multiple of 4: %lx", + __FUNCTION__, distance); - distance >>= 2; + distance >>= 2; - _assert_msg_(DYNA_REC, distance >= -0x2000000LL && distance <= 0x1FFFFFFLL, "%s: Received too large distance: %lx", __FUNCTION__, distance); + _assert_msg_(DYNA_REC, distance >= -0x2000000LL && distance <= 0x1FFFFFFLL, + "%s: Received too large distance: %lx", __FUNCTION__, distance); - Write32((op << 31) | (0x5 << 26) | (distance & 0x3FFFFFF)); + Write32((op << 31) | (0x5 << 26) | (distance & 0x3FFFFFF)); } void ARM64XEmitter::EncodeUnconditionalBranchInst(u32 opc, u32 op2, u32 op3, u32 op4, ARM64Reg Rn) { - Rn = DecodeReg(Rn); - Write32((0x6B << 25) | (opc << 21) | (op2 << 16) | (op3 << 10) | (Rn << 5) | op4); + Rn = DecodeReg(Rn); + Write32((0x6B << 25) | (opc << 21) | (op2 << 16) | (op3 << 10) | (Rn << 5) | op4); } void ARM64XEmitter::EncodeExceptionInst(u32 instenc, u32 imm) { - _assert_msg_(DYNA_REC, !(imm & ~0xFFFF), "%s: Exception instruction too large immediate: %d", __FUNCTION__, imm); + _assert_msg_(DYNA_REC, !(imm & ~0xFFFF), "%s: Exception instruction too large immediate: %d", + __FUNCTION__, imm); - Write32((0xD4 << 24) | (ExcEnc[instenc][0] << 21) | (imm << 5) | (ExcEnc[instenc][1] << 2) | ExcEnc[instenc][2]); + Write32((0xD4 << 24) | (ExcEnc[instenc][0] << 21) | (imm << 5) | (ExcEnc[instenc][1] << 2) | + ExcEnc[instenc][2]); } void ARM64XEmitter::EncodeSystemInst(u32 op0, u32 op1, u32 CRn, u32 CRm, u32 op2, ARM64Reg Rt) { - Write32((0x354 << 22) | (op0 << 19) | (op1 << 16) | (CRn << 12) | (CRm << 8) | (op2 << 5) | Rt); + Write32((0x354 << 22) | (op0 << 19) | (op1 << 16) | (CRn << 12) | (CRm << 8) | (op2 << 5) | Rt); } -void ARM64XEmitter::EncodeArithmeticInst(u32 instenc, bool flags, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option) +void ARM64XEmitter::EncodeArithmeticInst(u32 instenc, bool flags, ARM64Reg Rd, ARM64Reg Rn, + ARM64Reg Rm, ArithOption Option) { - bool b64Bit = Is64Bit(Rd); + bool b64Bit = Is64Bit(Rd); - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - Rm = DecodeReg(Rm); - Write32((b64Bit << 31) | (flags << 29) | (ArithEnc[instenc] << 21) | \ - (Option.GetType() == ArithOption::TYPE_EXTENDEDREG ? (1 << 21) : 0) | (Rm << 16) | Option.GetData() | (Rn << 5) | Rd); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); + Write32((b64Bit << 31) | (flags << 29) | (ArithEnc[instenc] << 21) | + (Option.GetType() == ArithOption::TYPE_EXTENDEDREG ? (1 << 21) : 0) | (Rm << 16) | + Option.GetData() | (Rn << 5) | Rd); } -void ARM64XEmitter::EncodeArithmeticCarryInst(u32 op, bool flags, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +void ARM64XEmitter::EncodeArithmeticCarryInst(u32 op, bool flags, ARM64Reg Rd, ARM64Reg Rn, + ARM64Reg Rm) { - bool b64Bit = Is64Bit(Rd); + bool b64Bit = Is64Bit(Rd); - Rd = DecodeReg(Rd); - Rm = DecodeReg(Rm); - Rn = DecodeReg(Rn); - Write32((b64Bit << 31) | (op << 30) | (flags << 29) | \ - (0xD0 << 21) | (Rm << 16) | (Rn << 5) | Rd); + Rd = DecodeReg(Rd); + Rm = DecodeReg(Rm); + Rn = DecodeReg(Rn); + Write32((b64Bit << 31) | (op << 30) | (flags << 29) | (0xD0 << 21) | (Rm << 16) | (Rn << 5) | Rd); } void ARM64XEmitter::EncodeCondCompareImmInst(u32 op, ARM64Reg Rn, u32 imm, u32 nzcv, CCFlags cond) { - bool b64Bit = Is64Bit(Rn); + bool b64Bit = Is64Bit(Rn); - _assert_msg_(DYNA_REC, !(imm & ~0x1F), "%s: too large immediate: %d", __FUNCTION__, imm) - _assert_msg_(DYNA_REC, !(nzcv & ~0xF), "%s: Flags out of range: %d", __FUNCTION__, nzcv) + _assert_msg_(DYNA_REC, !(imm & ~0x1F), "%s: too large immediate: %d", __FUNCTION__, imm) + _assert_msg_(DYNA_REC, !(nzcv & ~0xF), "%s: Flags out of range: %d", __FUNCTION__, nzcv) - Rn = DecodeReg(Rn); - Write32((b64Bit << 31) | (op << 30) | (1 << 29) | (0xD2 << 21) | \ - (imm << 16) | (cond << 12) | (1 << 11) | (Rn << 5) | nzcv); + Rn = DecodeReg(Rn); + Write32((b64Bit << 31) | (op << 30) | (1 << 29) | (0xD2 << 21) | (imm << 16) | (cond << 12) | + (1 << 11) | (Rn << 5) | nzcv); } -void ARM64XEmitter::EncodeCondCompareRegInst(u32 op, ARM64Reg Rn, ARM64Reg Rm, u32 nzcv, CCFlags cond) +void ARM64XEmitter::EncodeCondCompareRegInst(u32 op, ARM64Reg Rn, ARM64Reg Rm, u32 nzcv, + CCFlags cond) { - bool b64Bit = Is64Bit(Rm); + bool b64Bit = Is64Bit(Rm); - _assert_msg_(DYNA_REC, !(nzcv & ~0xF), "%s: Flags out of range: %d", __FUNCTION__, nzcv) + _assert_msg_(DYNA_REC, !(nzcv & ~0xF), "%s: Flags out of range: %d", __FUNCTION__, nzcv) - Rm = DecodeReg(Rm); - Rn = DecodeReg(Rn); - Write32((b64Bit << 31) | (op << 30) | (1 << 29) | (0xD2 << 21) | \ - (Rm << 16) | (cond << 12) | (Rn << 5) | nzcv); + Rm = DecodeReg(Rm); + Rn = DecodeReg(Rn); + Write32((b64Bit << 31) | (op << 30) | (1 << 29) | (0xD2 << 21) | (Rm << 16) | (cond << 12) | + (Rn << 5) | nzcv); } -void ARM64XEmitter::EncodeCondSelectInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond) +void ARM64XEmitter::EncodeCondSelectInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, + CCFlags cond) { - bool b64Bit = Is64Bit(Rd); + bool b64Bit = Is64Bit(Rd); - Rd = DecodeReg(Rd); - Rm = DecodeReg(Rm); - Rn = DecodeReg(Rn); - Write32((b64Bit << 31) | (CondSelectEnc[instenc][0] << 30) | \ - (0xD4 << 21) | (Rm << 16) | (cond << 12) | (CondSelectEnc[instenc][1] << 10) | \ - (Rn << 5) | Rd); + Rd = DecodeReg(Rd); + Rm = DecodeReg(Rm); + Rn = DecodeReg(Rn); + Write32((b64Bit << 31) | (CondSelectEnc[instenc][0] << 30) | (0xD4 << 21) | (Rm << 16) | + (cond << 12) | (CondSelectEnc[instenc][1] << 10) | (Rn << 5) | Rd); } void ARM64XEmitter::EncodeData1SrcInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn) { - bool b64Bit = Is64Bit(Rd); + bool b64Bit = Is64Bit(Rd); - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - Write32((b64Bit << 31) | (0x2D6 << 21) | \ - (Data1SrcEnc[instenc][0] << 16) | (Data1SrcEnc[instenc][1] << 10) | \ - (Rn << 5) | Rd); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Write32((b64Bit << 31) | (0x2D6 << 21) | (Data1SrcEnc[instenc][0] << 16) | + (Data1SrcEnc[instenc][1] << 10) | (Rn << 5) | Rd); } void ARM64XEmitter::EncodeData2SrcInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - bool b64Bit = Is64Bit(Rd); + bool b64Bit = Is64Bit(Rd); - Rd = DecodeReg(Rd); - Rm = DecodeReg(Rm); - Rn = DecodeReg(Rn); - Write32((b64Bit << 31) | (0x0D6 << 21) | \ - (Rm << 16) | (Data2SrcEnc[instenc] << 10) | \ - (Rn << 5) | Rd); + Rd = DecodeReg(Rd); + Rm = DecodeReg(Rm); + Rn = DecodeReg(Rn); + Write32((b64Bit << 31) | (0x0D6 << 21) | (Rm << 16) | (Data2SrcEnc[instenc] << 10) | (Rn << 5) | + Rd); } -void ARM64XEmitter::EncodeData3SrcInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) +void ARM64XEmitter::EncodeData3SrcInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, + ARM64Reg Ra) { - bool b64Bit = Is64Bit(Rd); + bool b64Bit = Is64Bit(Rd); - Rd = DecodeReg(Rd); - Rm = DecodeReg(Rm); - Rn = DecodeReg(Rn); - Ra = DecodeReg(Ra); - Write32((b64Bit << 31) | (0xD8 << 21) | (Data3SrcEnc[instenc][0] << 21) | \ - (Rm << 16) | (Data3SrcEnc[instenc][1] << 15) | \ - (Ra << 10) | (Rn << 5) | Rd); + Rd = DecodeReg(Rd); + Rm = DecodeReg(Rm); + Rn = DecodeReg(Rn); + Ra = DecodeReg(Ra); + Write32((b64Bit << 31) | (0xD8 << 21) | (Data3SrcEnc[instenc][0] << 21) | (Rm << 16) | + (Data3SrcEnc[instenc][1] << 15) | (Ra << 10) | (Rn << 5) | Rd); } -void ARM64XEmitter::EncodeLogicalInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) +void ARM64XEmitter::EncodeLogicalInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, + ArithOption Shift) { - bool b64Bit = Is64Bit(Rd); + bool b64Bit = Is64Bit(Rd); - Rd = DecodeReg(Rd); - Rm = DecodeReg(Rm); - Rn = DecodeReg(Rn); - Write32((b64Bit << 31) | (LogicalEnc[instenc][0] << 29) | (0x5 << 25) | (LogicalEnc[instenc][1] << 21) | \ - Shift.GetData() | (Rm << 16) | (Rn << 5) | Rd); + Rd = DecodeReg(Rd); + Rm = DecodeReg(Rm); + Rn = DecodeReg(Rn); + Write32((b64Bit << 31) | (LogicalEnc[instenc][0] << 29) | (0x5 << 25) | + (LogicalEnc[instenc][1] << 21) | Shift.GetData() | (Rm << 16) | (Rn << 5) | Rd); } void ARM64XEmitter::EncodeLoadRegisterInst(u32 bitop, ARM64Reg Rt, u32 imm) { - bool b64Bit = Is64Bit(Rt); - bool bVec = IsVector(Rt); + bool b64Bit = Is64Bit(Rt); + bool bVec = IsVector(Rt); - _assert_msg_(DYNA_REC, !(imm & 0xFFFFF), "%s: offset too large %d", __FUNCTION__, imm); + _assert_msg_(DYNA_REC, !(imm & 0xFFFFF), "%s: offset too large %d", __FUNCTION__, imm); - Rt = DecodeReg(Rt); - if (b64Bit && bitop != 0x2) // LDRSW(0x2) uses 64bit reg, doesn't have 64bit bit set - bitop |= 0x1; - Write32((bitop << 30) | (bVec << 26) | (0x18 << 24) | (imm << 5) | Rt); + Rt = DecodeReg(Rt); + if (b64Bit && bitop != 0x2) // LDRSW(0x2) uses 64bit reg, doesn't have 64bit bit set + bitop |= 0x1; + Write32((bitop << 30) | (bVec << 26) | (0x18 << 24) | (imm << 5) | Rt); } -void ARM64XEmitter::EncodeLoadStoreExcInst(u32 instenc, - ARM64Reg Rs, ARM64Reg Rt2, ARM64Reg Rn, ARM64Reg Rt) +void ARM64XEmitter::EncodeLoadStoreExcInst(u32 instenc, ARM64Reg Rs, ARM64Reg Rt2, ARM64Reg Rn, + ARM64Reg Rt) { - Rs = DecodeReg(Rs); - Rt2 = DecodeReg(Rt2); - Rn = DecodeReg(Rn); - Rt = DecodeReg(Rt); - Write32((LoadStoreExcEnc[instenc][0] << 30) | (0x8 << 24) | (LoadStoreExcEnc[instenc][1] << 23) | \ - (LoadStoreExcEnc[instenc][2] << 22) | (LoadStoreExcEnc[instenc][3] << 21) | (Rs << 16) | \ - (LoadStoreExcEnc[instenc][4] << 15) | (Rt2 << 10) | (Rn << 5) | Rt); + Rs = DecodeReg(Rs); + Rt2 = DecodeReg(Rt2); + Rn = DecodeReg(Rn); + Rt = DecodeReg(Rt); + Write32((LoadStoreExcEnc[instenc][0] << 30) | (0x8 << 24) | (LoadStoreExcEnc[instenc][1] << 23) | + (LoadStoreExcEnc[instenc][2] << 22) | (LoadStoreExcEnc[instenc][3] << 21) | (Rs << 16) | + (LoadStoreExcEnc[instenc][4] << 15) | (Rt2 << 10) | (Rn << 5) | Rt); } -void ARM64XEmitter::EncodeLoadStorePairedInst(u32 op, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, u32 imm) +void ARM64XEmitter::EncodeLoadStorePairedInst(u32 op, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, + u32 imm) { - bool b64Bit = Is64Bit(Rt); - bool b128Bit = IsQuad(Rt); - bool bVec = IsVector(Rt); + bool b64Bit = Is64Bit(Rt); + bool b128Bit = IsQuad(Rt); + bool bVec = IsVector(Rt); - if (b128Bit) - imm >>= 4; - else if (b64Bit) - imm >>= 3; - else - imm >>= 2; + if (b128Bit) + imm >>= 4; + else if (b64Bit) + imm >>= 3; + else + imm >>= 2; - _assert_msg_(DYNA_REC, !(imm & ~0xF), "%s: offset too large %d", __FUNCTION__, imm); + _assert_msg_(DYNA_REC, !(imm & ~0xF), "%s: offset too large %d", __FUNCTION__, imm); - u32 opc = 0; - if (b128Bit) - opc = 2; - else if (b64Bit && bVec) - opc = 1; - else if (b64Bit && !bVec) - opc = 2; + u32 opc = 0; + if (b128Bit) + opc = 2; + else if (b64Bit && bVec) + opc = 1; + else if (b64Bit && !bVec) + opc = 2; - Rt = DecodeReg(Rt); - Rt2 = DecodeReg(Rt2); - Rn = DecodeReg(Rn); - Write32((opc << 30) | (bVec << 26) | (op << 22) | (imm << 15) | (Rt2 << 10) | (Rn << 5) | Rt); + Rt = DecodeReg(Rt); + Rt2 = DecodeReg(Rt2); + Rn = DecodeReg(Rn); + Write32((opc << 30) | (bVec << 26) | (op << 22) | (imm << 15) | (Rt2 << 10) | (Rn << 5) | Rt); } void ARM64XEmitter::EncodeLoadStoreIndexedInst(u32 op, u32 op2, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - bool b64Bit = Is64Bit(Rt); - bool bVec = IsVector(Rt); + bool b64Bit = Is64Bit(Rt); + bool bVec = IsVector(Rt); - u32 offset = imm & 0x1FF; + u32 offset = imm & 0x1FF; - _assert_msg_(DYNA_REC, !(imm < -256 || imm > 255), "%s: offset too large %d", __FUNCTION__, imm); + _assert_msg_(DYNA_REC, !(imm < -256 || imm > 255), "%s: offset too large %d", __FUNCTION__, imm); - Rt = DecodeReg(Rt); - Rn = DecodeReg(Rn); - Write32((b64Bit << 30) | (op << 22) | (bVec << 26) | (offset << 12) | (op2 << 10) | (Rn << 5) | Rt); + Rt = DecodeReg(Rt); + Rn = DecodeReg(Rn); + Write32((b64Bit << 30) | (op << 22) | (bVec << 26) | (offset << 12) | (op2 << 10) | (Rn << 5) | + Rt); } void ARM64XEmitter::EncodeLoadStoreIndexedInst(u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm, u8 size) { - bool b64Bit = Is64Bit(Rt); - bool bVec = IsVector(Rt); + bool b64Bit = Is64Bit(Rt); + bool bVec = IsVector(Rt); - if (size == 64) - imm >>= 3; - else if (size == 32) - imm >>= 2; - else if (size == 16) - imm >>= 1; + if (size == 64) + imm >>= 3; + else if (size == 32) + imm >>= 2; + else if (size == 16) + imm >>= 1; - _assert_msg_(DYNA_REC, imm >= 0, "%s(INDEX_UNSIGNED): offset must be positive %d", __FUNCTION__, imm); - _assert_msg_(DYNA_REC, !(imm & ~0xFFF), "%s(INDEX_UNSIGNED): offset too large %d", __FUNCTION__, imm); + _assert_msg_(DYNA_REC, imm >= 0, "%s(INDEX_UNSIGNED): offset must be positive %d", __FUNCTION__, + imm); + _assert_msg_(DYNA_REC, !(imm & ~0xFFF), "%s(INDEX_UNSIGNED): offset too large %d", __FUNCTION__, + imm); - Rt = DecodeReg(Rt); - Rn = DecodeReg(Rn); - Write32((b64Bit << 30) | (op << 22) | (bVec << 26) | (imm << 10) | (Rn << 5) | Rt); + Rt = DecodeReg(Rt); + Rn = DecodeReg(Rn); + Write32((b64Bit << 30) | (op << 22) | (bVec << 26) | (imm << 10) | (Rn << 5) | Rt); } void ARM64XEmitter::EncodeMOVWideInst(u32 op, ARM64Reg Rd, u32 imm, ShiftAmount pos) { - bool b64Bit = Is64Bit(Rd); + bool b64Bit = Is64Bit(Rd); - _assert_msg_(DYNA_REC, !(imm & ~0xFFFF), "%s: immediate out of range: %d", __FUNCTION__, imm); + _assert_msg_(DYNA_REC, !(imm & ~0xFFFF), "%s: immediate out of range: %d", __FUNCTION__, imm); - Rd = DecodeReg(Rd); - Write32((b64Bit << 31) | (op << 29) | (0x25 << 23) | (pos << 21) | (imm << 5) | Rd); + Rd = DecodeReg(Rd); + Write32((b64Bit << 31) | (op << 29) | (0x25 << 23) | (pos << 21) | (imm << 5) | Rd); } void ARM64XEmitter::EncodeBitfieldMOVInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms) { - bool b64Bit = Is64Bit(Rd); + bool b64Bit = Is64Bit(Rd); - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - Write32((b64Bit << 31) | (op << 29) | (0x26 << 23) | (b64Bit << 22) | \ - (immr << 16) | (imms << 10) | (Rn << 5) | Rd); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Write32((b64Bit << 31) | (op << 29) | (0x26 << 23) | (b64Bit << 22) | (immr << 16) | + (imms << 10) | (Rn << 5) | Rd); } -void ARM64XEmitter::EncodeLoadStoreRegisterOffset(u32 size, u32 opc, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) +void ARM64XEmitter::EncodeLoadStoreRegisterOffset(u32 size, u32 opc, ARM64Reg Rt, ARM64Reg Rn, + ArithOption Rm) { - Rt = DecodeReg(Rt); - Rn = DecodeReg(Rn); - ARM64Reg decoded_Rm = DecodeReg(Rm.GetReg()); + Rt = DecodeReg(Rt); + Rn = DecodeReg(Rn); + ARM64Reg decoded_Rm = DecodeReg(Rm.GetReg()); - Write32((size << 30) | (opc << 22) | (0x1C1 << 21) | (decoded_Rm << 16) | \ - Rm.GetData() | (1 << 11) | (Rn << 5) | Rt); + Write32((size << 30) | (opc << 22) | (0x1C1 << 21) | (decoded_Rm << 16) | Rm.GetData() | + (1 << 11) | (Rn << 5) | Rt); } -void ARM64XEmitter::EncodeAddSubImmInst(u32 op, bool flags, u32 shift, u32 imm, ARM64Reg Rn, ARM64Reg Rd) +void ARM64XEmitter::EncodeAddSubImmInst(u32 op, bool flags, u32 shift, u32 imm, ARM64Reg Rn, + ARM64Reg Rd) { - bool b64Bit = Is64Bit(Rd); + bool b64Bit = Is64Bit(Rd); - _assert_msg_(DYNA_REC, !(imm & ~0xFFF), "%s: immediate too large: %x", __FUNCTION__, imm); + _assert_msg_(DYNA_REC, !(imm & ~0xFFF), "%s: immediate too large: %x", __FUNCTION__, imm); - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - Write32((b64Bit << 31) | (op << 30) | (flags << 29) | (0x11 << 24) | (shift << 22) | \ - (imm << 10) | (Rn << 5) | Rd); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Write32((b64Bit << 31) | (op << 30) | (flags << 29) | (0x11 << 24) | (shift << 22) | (imm << 10) | + (Rn << 5) | Rd); } -void ARM64XEmitter::EncodeLogicalImmInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, int n) +void ARM64XEmitter::EncodeLogicalImmInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, + int n) { - // Sometimes Rd is fixed to SP, but can still be 32bit or 64bit. - // Use Rn to determine bitness here. - bool b64Bit = Is64Bit(Rn); + // Sometimes Rd is fixed to SP, but can still be 32bit or 64bit. + // Use Rn to determine bitness here. + bool b64Bit = Is64Bit(Rn); - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); - Write32((b64Bit << 31) | (op << 29) | (0x24 << 23) | (n << 22) | \ - (immr << 16) | (imms << 10) | (Rn << 5) | Rd); + Write32((b64Bit << 31) | (op << 29) | (0x24 << 23) | (n << 22) | (immr << 16) | (imms << 10) | + (Rn << 5) | Rd); } -void ARM64XEmitter::EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm) +void ARM64XEmitter::EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, + ARM64Reg Rn, s32 imm) { - bool b64Bit = Is64Bit(Rt); - u32 type_encode = 0; + bool b64Bit = Is64Bit(Rt); + u32 type_encode = 0; - switch (type) - { - case INDEX_SIGNED: - type_encode = 0b010; - break; - case INDEX_POST: - type_encode = 0b001; - break; - case INDEX_PRE: - type_encode = 0b011; - break; - case INDEX_UNSIGNED: - _assert_msg_(DYNA_REC, false, "%s doesn't support INDEX_UNSIGNED!", __FUNCTION__); - break; - } + switch (type) + { + case INDEX_SIGNED: + type_encode = 0b010; + break; + case INDEX_POST: + type_encode = 0b001; + break; + case INDEX_PRE: + type_encode = 0b011; + break; + case INDEX_UNSIGNED: + _assert_msg_(DYNA_REC, false, "%s doesn't support INDEX_UNSIGNED!", __FUNCTION__); + break; + } - if (b64Bit) - { - op |= 0b10; - imm >>= 3; - } - else - { - imm >>= 2; - } + if (b64Bit) + { + op |= 0b10; + imm >>= 3; + } + else + { + imm >>= 2; + } - Rt = DecodeReg(Rt); - Rt2 = DecodeReg(Rt2); - Rn = DecodeReg(Rn); + Rt = DecodeReg(Rt); + Rt2 = DecodeReg(Rt2); + Rn = DecodeReg(Rn); - Write32((op << 30) | (0b101 << 27) | (type_encode << 23) | (load << 22) | \ - ((imm & 0x7F) << 15) | (Rt2 << 10) | (Rn << 5) | Rt); + Write32((op << 30) | (0b101 << 27) | (type_encode << 23) | (load << 22) | ((imm & 0x7F) << 15) | + (Rt2 << 10) | (Rn << 5) | Rt); } void ARM64XEmitter::EncodeAddressInst(u32 op, ARM64Reg Rd, s32 imm) { - Rd = DecodeReg(Rd); + Rd = DecodeReg(Rd); - Write32((op << 31) | ((imm & 0x3) << 29) | (0x10 << 24) | \ - ((imm & 0x1FFFFC) << 3) | Rd); + Write32((op << 31) | ((imm & 0x3) << 29) | (0x10 << 24) | ((imm & 0x1FFFFC) << 3) | Rd); } void ARM64XEmitter::EncodeLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - _assert_msg_(DYNA_REC, !(imm < -256 || imm > 255), "%s received too large offset: %d", __FUNCTION__, imm); - Rt = DecodeReg(Rt); - Rn = DecodeReg(Rn); + _assert_msg_(DYNA_REC, !(imm < -256 || imm > 255), "%s received too large offset: %d", + __FUNCTION__, imm); + Rt = DecodeReg(Rt); + Rn = DecodeReg(Rn); - Write32((size << 30) | (0b111 << 27) | (op << 22) | ((imm & 0x1FF) << 12) | (Rn << 5) | Rt); + Write32((size << 30) | (0b111 << 27) | (op << 22) | ((imm & 0x1FF) << 12) | (Rn << 5) | Rt); } static constexpr bool IsInRangeImm19(s64 distance) { - return (distance >= -0x40000 && distance <= 0x3FFFF); + return (distance >= -0x40000 && distance <= 0x3FFFF); } static constexpr bool IsInRangeImm14(s64 distance) { - return (distance >= -0x2000 && distance <= 0x1FFF); + return (distance >= -0x2000 && distance <= 0x1FFF); } static constexpr bool IsInRangeImm26(s64 distance) { - return (distance >= -0x2000000 && distance <= 0x1FFFFFF); + return (distance >= -0x2000000 && distance <= 0x1FFFFFF); } static constexpr u32 MaskImm19(s64 distance) { - return distance & 0x7FFFF; + return distance & 0x7FFFF; } static constexpr u32 MaskImm14(s64 distance) { - return distance & 0x3FFF; + return distance & 0x3FFF; } static constexpr u32 MaskImm26(s64 distance) { - return distance & 0x3FFFFFF; + return distance & 0x3FFFFFF; } // FixupBranch branching void ARM64XEmitter::SetJumpTarget(FixupBranch const& branch) { - bool Not = false; - u32 inst = 0; - s64 distance = (s64)(m_code - branch.ptr); - distance >>= 2; + bool Not = false; + u32 inst = 0; + s64 distance = (s64)(m_code - branch.ptr); + distance >>= 2; - switch (branch.type) - { - case 1: // CBNZ - Not = true; - case 0: // CBZ - { - _assert_msg_(DYNA_REC, IsInRangeImm19(distance), "%s(%d): Received too large distance: %lx", __FUNCTION__, branch.type, distance); - bool b64Bit = Is64Bit(branch.reg); - ARM64Reg reg = DecodeReg(branch.reg); - inst = (b64Bit << 31) | (0x1A << 25) | (Not << 24) | (MaskImm19(distance) << 5) | reg; - } - break; - case 2: // B (conditional) - _assert_msg_(DYNA_REC, IsInRangeImm19(distance), "%s(%d): Received too large distance: %lx", __FUNCTION__, branch.type, distance); - inst = (0x2A << 25) | (MaskImm19(distance) << 5) | branch.cond; - break; - case 4: // TBNZ - Not = true; - case 3: // TBZ - { - _assert_msg_(DYNA_REC, IsInRangeImm14(distance), "%s(%d): Received too large distance: %lx", __FUNCTION__, branch.type, distance); - ARM64Reg reg = DecodeReg(branch.reg); - inst = ((branch.bit & 0x20) << 26) | (0x1B << 25) | (Not << 24) | ((branch.bit & 0x1F) << 19) | (MaskImm14(distance) << 5) | reg; - } - break; - case 5: // B (uncoditional) - _assert_msg_(DYNA_REC, IsInRangeImm26(distance), "%s(%d): Received too large distance: %lx", __FUNCTION__, branch.type, distance); - inst = (0x5 << 26) | MaskImm26(distance); - break; - case 6: // BL (unconditional) - _assert_msg_(DYNA_REC, IsInRangeImm26(distance), "%s(%d): Received too large distance: %lx", __FUNCTION__, branch.type, distance); - inst = (0x25 << 26) | MaskImm26(distance); - break; - } - *(u32*)branch.ptr = inst; + switch (branch.type) + { + case 1: // CBNZ + Not = true; + case 0: // CBZ + { + _assert_msg_(DYNA_REC, IsInRangeImm19(distance), "%s(%d): Received too large distance: %lx", + __FUNCTION__, branch.type, distance); + bool b64Bit = Is64Bit(branch.reg); + ARM64Reg reg = DecodeReg(branch.reg); + inst = (b64Bit << 31) | (0x1A << 25) | (Not << 24) | (MaskImm19(distance) << 5) | reg; + } + break; + case 2: // B (conditional) + _assert_msg_(DYNA_REC, IsInRangeImm19(distance), "%s(%d): Received too large distance: %lx", + __FUNCTION__, branch.type, distance); + inst = (0x2A << 25) | (MaskImm19(distance) << 5) | branch.cond; + break; + case 4: // TBNZ + Not = true; + case 3: // TBZ + { + _assert_msg_(DYNA_REC, IsInRangeImm14(distance), "%s(%d): Received too large distance: %lx", + __FUNCTION__, branch.type, distance); + ARM64Reg reg = DecodeReg(branch.reg); + inst = ((branch.bit & 0x20) << 26) | (0x1B << 25) | (Not << 24) | ((branch.bit & 0x1F) << 19) | + (MaskImm14(distance) << 5) | reg; + } + break; + case 5: // B (uncoditional) + _assert_msg_(DYNA_REC, IsInRangeImm26(distance), "%s(%d): Received too large distance: %lx", + __FUNCTION__, branch.type, distance); + inst = (0x5 << 26) | MaskImm26(distance); + break; + case 6: // BL (unconditional) + _assert_msg_(DYNA_REC, IsInRangeImm26(distance), "%s(%d): Received too large distance: %lx", + __FUNCTION__, branch.type, distance); + inst = (0x25 << 26) | MaskImm26(distance); + break; + } + *(u32*)branch.ptr = inst; } FixupBranch ARM64XEmitter::CBZ(ARM64Reg Rt) { - FixupBranch branch; - branch.ptr = m_code; - branch.type = 0; - branch.reg = Rt; - HINT(HINT_NOP); - return branch; + FixupBranch branch; + branch.ptr = m_code; + branch.type = 0; + branch.reg = Rt; + HINT(HINT_NOP); + return branch; } FixupBranch ARM64XEmitter::CBNZ(ARM64Reg Rt) { - FixupBranch branch; - branch.ptr = m_code; - branch.type = 1; - branch.reg = Rt; - HINT(HINT_NOP); - return branch; + FixupBranch branch; + branch.ptr = m_code; + branch.type = 1; + branch.reg = Rt; + HINT(HINT_NOP); + return branch; } FixupBranch ARM64XEmitter::B(CCFlags cond) { - FixupBranch branch; - branch.ptr = m_code; - branch.type = 2; - branch.cond = cond; - HINT(HINT_NOP); - return branch; + FixupBranch branch; + branch.ptr = m_code; + branch.type = 2; + branch.cond = cond; + HINT(HINT_NOP); + return branch; } FixupBranch ARM64XEmitter::TBZ(ARM64Reg Rt, u8 bit) { - FixupBranch branch; - branch.ptr = m_code; - branch.type = 3; - branch.reg = Rt; - branch.bit = bit; - HINT(HINT_NOP); - return branch; + FixupBranch branch; + branch.ptr = m_code; + branch.type = 3; + branch.reg = Rt; + branch.bit = bit; + HINT(HINT_NOP); + return branch; } FixupBranch ARM64XEmitter::TBNZ(ARM64Reg Rt, u8 bit) { - FixupBranch branch; - branch.ptr = m_code; - branch.type = 4; - branch.reg = Rt; - branch.bit = bit; - HINT(HINT_NOP); - return branch; + FixupBranch branch; + branch.ptr = m_code; + branch.type = 4; + branch.reg = Rt; + branch.bit = bit; + HINT(HINT_NOP); + return branch; } FixupBranch ARM64XEmitter::B() { - FixupBranch branch; - branch.ptr = m_code; - branch.type = 5; - HINT(HINT_NOP); - return branch; + FixupBranch branch; + branch.ptr = m_code; + branch.type = 5; + HINT(HINT_NOP); + return branch; } FixupBranch ARM64XEmitter::BL() { - FixupBranch branch; - branch.ptr = m_code; - branch.type = 6; - HINT(HINT_NOP); - return branch; + FixupBranch branch; + branch.ptr = m_code; + branch.type = 6; + HINT(HINT_NOP); + return branch; } // Compare and Branch void ARM64XEmitter::CBZ(ARM64Reg Rt, const void* ptr) { - EncodeCompareBranchInst(0, Rt, ptr); + EncodeCompareBranchInst(0, Rt, ptr); } void ARM64XEmitter::CBNZ(ARM64Reg Rt, const void* ptr) { - EncodeCompareBranchInst(1, Rt, ptr); + EncodeCompareBranchInst(1, Rt, ptr); } // Conditional Branch void ARM64XEmitter::B(CCFlags cond, const void* ptr) { - s64 distance = (s64)ptr - (s64)m_code; + s64 distance = (s64)ptr - (s64)m_code; - distance >>= 2; + distance >>= 2; - _assert_msg_(DYNA_REC, IsInRangeImm19(distance), "%s: Received too large distance: %p->%p %ld %lx", __FUNCTION__, m_code, ptr, distance, distance); - Write32((0x54 << 24) | (MaskImm19(distance) << 5) | cond); + _assert_msg_(DYNA_REC, IsInRangeImm19(distance), + "%s: Received too large distance: %p->%p %ld %lx", __FUNCTION__, m_code, ptr, + distance, distance); + Write32((0x54 << 24) | (MaskImm19(distance) << 5) | cond); } // Test and Branch void ARM64XEmitter::TBZ(ARM64Reg Rt, u8 bits, const void* ptr) { - EncodeTestBranchInst(0, Rt, bits, ptr); + EncodeTestBranchInst(0, Rt, bits, ptr); } void ARM64XEmitter::TBNZ(ARM64Reg Rt, u8 bits, const void* ptr) { - EncodeTestBranchInst(1, Rt, bits, ptr); + EncodeTestBranchInst(1, Rt, bits, ptr); } // Unconditional Branch void ARM64XEmitter::B(const void* ptr) { - EncodeUnconditionalBranchInst(0, ptr); + EncodeUnconditionalBranchInst(0, ptr); } void ARM64XEmitter::BL(const void* ptr) { - EncodeUnconditionalBranchInst(1, ptr); + EncodeUnconditionalBranchInst(1, ptr); } void ARM64XEmitter::QuickCallFunction(ARM64Reg scratchreg, const void* func) { - s64 distance = (s64)func - (s64)m_code; - distance >>= 2; // Can only branch to opcode-aligned (4) addresses - if (!IsInRangeImm26(distance)) - { - // WARN_LOG(DYNA_REC, "Distance too far in function call (%p to %p)! Using scratch.", m_code, func); - MOVI2R(scratchreg, (uintptr_t)func); - BLR(scratchreg); - } - else - { - BL(func); - } + s64 distance = (s64)func - (s64)m_code; + distance >>= 2; // Can only branch to opcode-aligned (4) addresses + if (!IsInRangeImm26(distance)) + { + // WARN_LOG(DYNA_REC, "Distance too far in function call (%p to %p)! Using scratch.", m_code, + // func); + MOVI2R(scratchreg, (uintptr_t)func); + BLR(scratchreg); + } + else + { + BL(func); + } } // Unconditional Branch (register) void ARM64XEmitter::BR(ARM64Reg Rn) { - EncodeUnconditionalBranchInst(0, 0x1F, 0, 0, Rn); + EncodeUnconditionalBranchInst(0, 0x1F, 0, 0, Rn); } void ARM64XEmitter::BLR(ARM64Reg Rn) { - EncodeUnconditionalBranchInst(1, 0x1F, 0, 0, Rn); + EncodeUnconditionalBranchInst(1, 0x1F, 0, 0, Rn); } void ARM64XEmitter::RET(ARM64Reg Rn) { - EncodeUnconditionalBranchInst(2, 0x1F, 0, 0, Rn); + EncodeUnconditionalBranchInst(2, 0x1F, 0, 0, Rn); } void ARM64XEmitter::ERET() { - EncodeUnconditionalBranchInst(4, 0x1F, 0, 0, SP); + EncodeUnconditionalBranchInst(4, 0x1F, 0, 0, SP); } void ARM64XEmitter::DRPS() { - EncodeUnconditionalBranchInst(5, 0x1F, 0, 0, SP); + EncodeUnconditionalBranchInst(5, 0x1F, 0, 0, SP); } // Exception generation void ARM64XEmitter::SVC(u32 imm) { - EncodeExceptionInst(0, imm); + EncodeExceptionInst(0, imm); } void ARM64XEmitter::HVC(u32 imm) { - EncodeExceptionInst(1, imm); + EncodeExceptionInst(1, imm); } void ARM64XEmitter::SMC(u32 imm) { - EncodeExceptionInst(2, imm); + EncodeExceptionInst(2, imm); } void ARM64XEmitter::BRK(u32 imm) { - EncodeExceptionInst(3, imm); + EncodeExceptionInst(3, imm); } void ARM64XEmitter::HLT(u32 imm) { - EncodeExceptionInst(4, imm); + EncodeExceptionInst(4, imm); } void ARM64XEmitter::DCPS1(u32 imm) { - EncodeExceptionInst(5, imm); + EncodeExceptionInst(5, imm); } void ARM64XEmitter::DCPS2(u32 imm) { - EncodeExceptionInst(6, imm); + EncodeExceptionInst(6, imm); } void ARM64XEmitter::DCPS3(u32 imm) { - EncodeExceptionInst(7, imm); + EncodeExceptionInst(7, imm); } // System void ARM64XEmitter::_MSR(PStateField field, u8 imm) { - u32 op1 = 0, op2 = 0; - switch (field) - { - case FIELD_SPSel: op1 = 0; op2 = 5; break; - case FIELD_DAIFSet: op1 = 3; op2 = 6; break; - case FIELD_DAIFClr: op1 = 3; op2 = 7; break; - default: - _assert_msg_(DYNA_REC, false, "Invalid PStateField to do a imm move to"); - break; - } - EncodeSystemInst(0, op1, 4, imm, op2, WSP); + u32 op1 = 0, op2 = 0; + switch (field) + { + case FIELD_SPSel: + op1 = 0; + op2 = 5; + break; + case FIELD_DAIFSet: + op1 = 3; + op2 = 6; + break; + case FIELD_DAIFClr: + op1 = 3; + op2 = 7; + break; + default: + _assert_msg_(DYNA_REC, false, "Invalid PStateField to do a imm move to"); + break; + } + EncodeSystemInst(0, op1, 4, imm, op2, WSP); } static void GetSystemReg(PStateField field, int& o0, int& op1, int& CRn, int& CRm, int& op2) { - switch (field) -{ - case FIELD_NZCV: - o0 = 3; op1 = 3; CRn = 4; CRm = 2; op2 = 0; - break; - case FIELD_FPCR: - o0 = 3; op1 = 3; CRn = 4; CRm = 4; op2 = 0; - break; - case FIELD_FPSR: - o0 = 3; op1 = 3; CRn = 4; CRm = 4; op2 = 1; - break; - case FIELD_PMCR_EL0: - o0 = 3; op1 = 3; CRn = 9; CRm = 6; op2 = 0; - break; - case FIELD_PMCCNTR_EL0: - o0 = 3; op1 = 3; CRn = 9; CRm = 7; op2 = 0; - break; - default: - _assert_msg_(DYNA_REC, false, "Invalid PStateField to do a register move from/to"); - break; - } + switch (field) + { + case FIELD_NZCV: + o0 = 3; + op1 = 3; + CRn = 4; + CRm = 2; + op2 = 0; + break; + case FIELD_FPCR: + o0 = 3; + op1 = 3; + CRn = 4; + CRm = 4; + op2 = 0; + break; + case FIELD_FPSR: + o0 = 3; + op1 = 3; + CRn = 4; + CRm = 4; + op2 = 1; + break; + case FIELD_PMCR_EL0: + o0 = 3; + op1 = 3; + CRn = 9; + CRm = 6; + op2 = 0; + break; + case FIELD_PMCCNTR_EL0: + o0 = 3; + op1 = 3; + CRn = 9; + CRm = 7; + op2 = 0; + break; + default: + _assert_msg_(DYNA_REC, false, "Invalid PStateField to do a register move from/to"); + break; + } } void ARM64XEmitter::_MSR(PStateField field, ARM64Reg Rt) { - int o0 = 0, op1 = 0, CRn = 0, CRm = 0, op2 = 0; - _assert_msg_(DYNA_REC, Is64Bit(Rt), "MSR: Rt must be 64-bit"); - GetSystemReg(field, o0, op1, CRn, CRm, op2); - EncodeSystemInst(o0, op1, CRn, CRm, op2, DecodeReg(Rt)); + int o0 = 0, op1 = 0, CRn = 0, CRm = 0, op2 = 0; + _assert_msg_(DYNA_REC, Is64Bit(Rt), "MSR: Rt must be 64-bit"); + GetSystemReg(field, o0, op1, CRn, CRm, op2); + EncodeSystemInst(o0, op1, CRn, CRm, op2, DecodeReg(Rt)); } void ARM64XEmitter::MRS(ARM64Reg Rt, PStateField field) { - int o0 = 0, op1 = 0, CRn = 0, CRm = 0, op2 = 0; - _assert_msg_(DYNA_REC, Is64Bit(Rt), "MRS: Rt must be 64-bit"); - GetSystemReg(field, o0, op1, CRn, CRm, op2); - EncodeSystemInst(o0 | 4, op1, CRn, CRm, op2, DecodeReg(Rt)); + int o0 = 0, op1 = 0, CRn = 0, CRm = 0, op2 = 0; + _assert_msg_(DYNA_REC, Is64Bit(Rt), "MRS: Rt must be 64-bit"); + GetSystemReg(field, o0, op1, CRn, CRm, op2); + EncodeSystemInst(o0 | 4, op1, CRn, CRm, op2, DecodeReg(Rt)); } void ARM64XEmitter::HINT(SystemHint op) { - EncodeSystemInst(0, 3, 2, 0, op, WSP); + EncodeSystemInst(0, 3, 2, 0, op, WSP); } void ARM64XEmitter::CLREX() { - EncodeSystemInst(0, 3, 3, 0, 2, WSP); + EncodeSystemInst(0, 3, 3, 0, 2, WSP); } void ARM64XEmitter::DSB(BarrierType type) { - EncodeSystemInst(0, 3, 3, type, 4, WSP); + EncodeSystemInst(0, 3, 3, type, 4, WSP); } void ARM64XEmitter::DMB(BarrierType type) { - EncodeSystemInst(0, 3, 3, type, 5, WSP); + EncodeSystemInst(0, 3, 3, type, 5, WSP); } void ARM64XEmitter::ISB(BarrierType type) { - EncodeSystemInst(0, 3, 3, type, 6, WSP); + EncodeSystemInst(0, 3, 3, type, 6, WSP); } // Add/Subtract (extended register) void ARM64XEmitter::ADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - ADD(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); + ADD(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } void ARM64XEmitter::ADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option) { - EncodeArithmeticInst(0, false, Rd, Rn, Rm, Option); + EncodeArithmeticInst(0, false, Rd, Rn, Rm, Option); } void ARM64XEmitter::ADDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeArithmeticInst(0, true, Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); + EncodeArithmeticInst(0, true, Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } void ARM64XEmitter::ADDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option) { - EncodeArithmeticInst(0, true, Rd, Rn, Rm, Option); + EncodeArithmeticInst(0, true, Rd, Rn, Rm, Option); } void ARM64XEmitter::SUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - SUB(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); + SUB(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } void ARM64XEmitter::SUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option) { - EncodeArithmeticInst(1, false, Rd, Rn, Rm, Option); + EncodeArithmeticInst(1, false, Rd, Rn, Rm, Option); } void ARM64XEmitter::SUBS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeArithmeticInst(1, true, Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); + EncodeArithmeticInst(1, true, Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } void ARM64XEmitter::SUBS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option) { - EncodeArithmeticInst(1, true, Rd, Rn, Rm, Option); + EncodeArithmeticInst(1, true, Rd, Rn, Rm, Option); } void ARM64XEmitter::CMN(ARM64Reg Rn, ARM64Reg Rm) { - CMN(Rn, Rm, ArithOption(Rn, ST_LSL, 0)); + CMN(Rn, Rm, ArithOption(Rn, ST_LSL, 0)); } void ARM64XEmitter::CMN(ARM64Reg Rn, ARM64Reg Rm, ArithOption Option) { - EncodeArithmeticInst(0, true, Is64Bit(Rn) ? ZR : WZR, Rn, Rm, Option); + EncodeArithmeticInst(0, true, Is64Bit(Rn) ? ZR : WZR, Rn, Rm, Option); } void ARM64XEmitter::CMP(ARM64Reg Rn, ARM64Reg Rm) { - CMP(Rn, Rm, ArithOption(Rn, ST_LSL, 0)); + CMP(Rn, Rm, ArithOption(Rn, ST_LSL, 0)); } void ARM64XEmitter::CMP(ARM64Reg Rn, ARM64Reg Rm, ArithOption Option) { - EncodeArithmeticInst(1, true, Is64Bit(Rn) ? ZR : WZR, Rn, Rm, Option); + EncodeArithmeticInst(1, true, Is64Bit(Rn) ? ZR : WZR, Rn, Rm, Option); } // Add/Subtract (with carry) void ARM64XEmitter::ADC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeArithmeticCarryInst(0, false, Rd, Rn, Rm); + EncodeArithmeticCarryInst(0, false, Rd, Rn, Rm); } void ARM64XEmitter::ADCS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeArithmeticCarryInst(0, true, Rd, Rn, Rm); + EncodeArithmeticCarryInst(0, true, Rd, Rn, Rm); } void ARM64XEmitter::SBC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeArithmeticCarryInst(1, false, Rd, Rn, Rm); + EncodeArithmeticCarryInst(1, false, Rd, Rn, Rm); } void ARM64XEmitter::SBCS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeArithmeticCarryInst(1, true, Rd, Rn, Rm); + EncodeArithmeticCarryInst(1, true, Rd, Rn, Rm); } // Conditional Compare (immediate) void ARM64XEmitter::CCMN(ARM64Reg Rn, u32 imm, u32 nzcv, CCFlags cond) { - EncodeCondCompareImmInst(0, Rn, imm, nzcv, cond); + EncodeCondCompareImmInst(0, Rn, imm, nzcv, cond); } void ARM64XEmitter::CCMP(ARM64Reg Rn, u32 imm, u32 nzcv, CCFlags cond) { - EncodeCondCompareImmInst(1, Rn, imm, nzcv, cond); + EncodeCondCompareImmInst(1, Rn, imm, nzcv, cond); } // Conditiona Compare (register) void ARM64XEmitter::CCMN(ARM64Reg Rn, ARM64Reg Rm, u32 nzcv, CCFlags cond) { - EncodeCondCompareRegInst(0, Rn, Rm, nzcv, cond); + EncodeCondCompareRegInst(0, Rn, Rm, nzcv, cond); } void ARM64XEmitter::CCMP(ARM64Reg Rn, ARM64Reg Rm, u32 nzcv, CCFlags cond) { - EncodeCondCompareRegInst(1, Rn, Rm, nzcv, cond); + EncodeCondCompareRegInst(1, Rn, Rm, nzcv, cond); } // Conditional Select void ARM64XEmitter::CSEL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond) { - EncodeCondSelectInst(0, Rd, Rn, Rm, cond); + EncodeCondSelectInst(0, Rd, Rn, Rm, cond); } void ARM64XEmitter::CSINC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond) { - EncodeCondSelectInst(1, Rd, Rn, Rm, cond); + EncodeCondSelectInst(1, Rd, Rn, Rm, cond); } void ARM64XEmitter::CSINV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond) { - EncodeCondSelectInst(2, Rd, Rn, Rm, cond); + EncodeCondSelectInst(2, Rd, Rn, Rm, cond); } void ARM64XEmitter::CSNEG(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond) { - EncodeCondSelectInst(3, Rd, Rn, Rm, cond); + EncodeCondSelectInst(3, Rd, Rn, Rm, cond); } // Data-Processing 1 source void ARM64XEmitter::RBIT(ARM64Reg Rd, ARM64Reg Rn) { - EncodeData1SrcInst(0, Rd, Rn); + EncodeData1SrcInst(0, Rd, Rn); } void ARM64XEmitter::REV16(ARM64Reg Rd, ARM64Reg Rn) { - EncodeData1SrcInst(1, Rd, Rn); + EncodeData1SrcInst(1, Rd, Rn); } void ARM64XEmitter::REV32(ARM64Reg Rd, ARM64Reg Rn) { - EncodeData1SrcInst(2, Rd, Rn); + EncodeData1SrcInst(2, Rd, Rn); } void ARM64XEmitter::REV64(ARM64Reg Rd, ARM64Reg Rn) { - EncodeData1SrcInst(3, Rd, Rn); + EncodeData1SrcInst(3, Rd, Rn); } void ARM64XEmitter::CLZ(ARM64Reg Rd, ARM64Reg Rn) { - EncodeData1SrcInst(4, Rd, Rn); + EncodeData1SrcInst(4, Rd, Rn); } void ARM64XEmitter::CLS(ARM64Reg Rd, ARM64Reg Rn) { - EncodeData1SrcInst(5, Rd, Rn); + EncodeData1SrcInst(5, Rd, Rn); } // Data-Processing 2 source void ARM64XEmitter::UDIV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData2SrcInst(0, Rd, Rn, Rm); + EncodeData2SrcInst(0, Rd, Rn, Rm); } void ARM64XEmitter::SDIV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData2SrcInst(1, Rd, Rn, Rm); + EncodeData2SrcInst(1, Rd, Rn, Rm); } void ARM64XEmitter::LSLV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData2SrcInst(2, Rd, Rn, Rm); + EncodeData2SrcInst(2, Rd, Rn, Rm); } void ARM64XEmitter::LSRV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData2SrcInst(3, Rd, Rn, Rm); + EncodeData2SrcInst(3, Rd, Rn, Rm); } void ARM64XEmitter::ASRV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData2SrcInst(4, Rd, Rn, Rm); + EncodeData2SrcInst(4, Rd, Rn, Rm); } void ARM64XEmitter::RORV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData2SrcInst(5, Rd, Rn, Rm); + EncodeData2SrcInst(5, Rd, Rn, Rm); } void ARM64XEmitter::CRC32B(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData2SrcInst(6, Rd, Rn, Rm); + EncodeData2SrcInst(6, Rd, Rn, Rm); } void ARM64XEmitter::CRC32H(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData2SrcInst(7, Rd, Rn, Rm); + EncodeData2SrcInst(7, Rd, Rn, Rm); } void ARM64XEmitter::CRC32W(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData2SrcInst(8, Rd, Rn, Rm); + EncodeData2SrcInst(8, Rd, Rn, Rm); } void ARM64XEmitter::CRC32CB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData2SrcInst(9, Rd, Rn, Rm); + EncodeData2SrcInst(9, Rd, Rn, Rm); } void ARM64XEmitter::CRC32CH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData2SrcInst(10, Rd, Rn, Rm); + EncodeData2SrcInst(10, Rd, Rn, Rm); } void ARM64XEmitter::CRC32CW(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData2SrcInst(11, Rd, Rn, Rm); + EncodeData2SrcInst(11, Rd, Rn, Rm); } void ARM64XEmitter::CRC32X(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData2SrcInst(12, Rd, Rn, Rm); + EncodeData2SrcInst(12, Rd, Rn, Rm); } void ARM64XEmitter::CRC32CX(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData2SrcInst(13, Rd, Rn, Rm); + EncodeData2SrcInst(13, Rd, Rn, Rm); } // Data-Processing 3 source void ARM64XEmitter::MADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) { - EncodeData3SrcInst(0, Rd, Rn, Rm, Ra); + EncodeData3SrcInst(0, Rd, Rn, Rm, Ra); } void ARM64XEmitter::MSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) { - EncodeData3SrcInst(1, Rd, Rn, Rm, Ra); + EncodeData3SrcInst(1, Rd, Rn, Rm, Ra); } void ARM64XEmitter::SMADDL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) { - EncodeData3SrcInst(2, Rd, Rn, Rm, Ra); + EncodeData3SrcInst(2, Rd, Rn, Rm, Ra); } void ARM64XEmitter::SMULL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - SMADDL(Rd, Rn, Rm, SP); + SMADDL(Rd, Rn, Rm, SP); } void ARM64XEmitter::SMSUBL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) { - EncodeData3SrcInst(3, Rd, Rn, Rm, Ra); + EncodeData3SrcInst(3, Rd, Rn, Rm, Ra); } void ARM64XEmitter::SMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData3SrcInst(4, Rd, Rn, Rm, SP); + EncodeData3SrcInst(4, Rd, Rn, Rm, SP); } void ARM64XEmitter::UMADDL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) { - EncodeData3SrcInst(5, Rd, Rn, Rm, Ra); + EncodeData3SrcInst(5, Rd, Rn, Rm, Ra); } void ARM64XEmitter::UMULL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - UMADDL(Rd, Rn, Rm, SP); + UMADDL(Rd, Rn, Rm, SP); } void ARM64XEmitter::UMSUBL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) { - EncodeData3SrcInst(6, Rd, Rn, Rm, Ra); + EncodeData3SrcInst(6, Rd, Rn, Rm, Ra); } void ARM64XEmitter::UMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData3SrcInst(7, Rd, Rn, Rm, SP); + EncodeData3SrcInst(7, Rd, Rn, Rm, SP); } void ARM64XEmitter::MUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData3SrcInst(0, Rd, Rn, Rm, SP); + EncodeData3SrcInst(0, Rd, Rn, Rm, SP); } void ARM64XEmitter::MNEG(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EncodeData3SrcInst(1, Rd, Rn, Rm, SP); + EncodeData3SrcInst(1, Rd, Rn, Rm, SP); } // Logical (shifted register) void ARM64XEmitter::AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) { - EncodeLogicalInst(0, Rd, Rn, Rm, Shift); + EncodeLogicalInst(0, Rd, Rn, Rm, Shift); } void ARM64XEmitter::BIC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) { - EncodeLogicalInst(1, Rd, Rn, Rm, Shift); + EncodeLogicalInst(1, Rd, Rn, Rm, Shift); } void ARM64XEmitter::ORR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) { - EncodeLogicalInst(2, Rd, Rn, Rm, Shift); + EncodeLogicalInst(2, Rd, Rn, Rm, Shift); } void ARM64XEmitter::ORN(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) { - EncodeLogicalInst(3, Rd, Rn, Rm, Shift); + EncodeLogicalInst(3, Rd, Rn, Rm, Shift); } void ARM64XEmitter::EOR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) { - EncodeLogicalInst(4, Rd, Rn, Rm, Shift); + EncodeLogicalInst(4, Rd, Rn, Rm, Shift); } void ARM64XEmitter::EON(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) { - EncodeLogicalInst(5, Rd, Rn, Rm, Shift); + EncodeLogicalInst(5, Rd, Rn, Rm, Shift); } void ARM64XEmitter::ANDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) { - EncodeLogicalInst(6, Rd, Rn, Rm, Shift); + EncodeLogicalInst(6, Rd, Rn, Rm, Shift); } void ARM64XEmitter::BICS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift) { - EncodeLogicalInst(7, Rd, Rn, Rm, Shift); + EncodeLogicalInst(7, Rd, Rn, Rm, Shift); } void ARM64XEmitter::MOV(ARM64Reg Rd, ARM64Reg Rm, ArithOption Shift) { - ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, Shift); + ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, Shift); } void ARM64XEmitter::MOV(ARM64Reg Rd, ARM64Reg Rm) { - if (IsGPR(Rd) && IsGPR(Rm)) - ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_LSL, 0)); - else - _assert_msg_(DYNA_REC, false, "Non-GPRs not supported in MOV"); + if (IsGPR(Rd) && IsGPR(Rm)) + ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_LSL, 0)); + else + _assert_msg_(DYNA_REC, false, "Non-GPRs not supported in MOV"); } void ARM64XEmitter::MVN(ARM64Reg Rd, ARM64Reg Rm) { - ORN(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_LSL, 0)); + ORN(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_LSL, 0)); } void ARM64XEmitter::LSL(ARM64Reg Rd, ARM64Reg Rm, int shift) { - ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_LSL, shift)); + ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_LSL, shift)); } void ARM64XEmitter::LSR(ARM64Reg Rd, ARM64Reg Rm, int shift) { - ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_LSR, shift)); + ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_LSR, shift)); } void ARM64XEmitter::ASR(ARM64Reg Rd, ARM64Reg Rm, int shift) { - ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_ASR, shift)); + ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_ASR, shift)); } void ARM64XEmitter::ROR(ARM64Reg Rd, ARM64Reg Rm, int shift) { - ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_ROR, shift)); + ORR(Rd, Is64Bit(Rd) ? ZR : WZR, Rm, ArithOption(Rm, ST_ROR, shift)); } // Logical (immediate) void ARM64XEmitter::AND(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, bool invert) { - EncodeLogicalImmInst(0, Rd, Rn, immr, imms, invert); + EncodeLogicalImmInst(0, Rd, Rn, immr, imms, invert); } void ARM64XEmitter::ANDS(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, bool invert) { - EncodeLogicalImmInst(3, Rd, Rn, immr, imms, invert); + EncodeLogicalImmInst(3, Rd, Rn, immr, imms, invert); } void ARM64XEmitter::EOR(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, bool invert) { - EncodeLogicalImmInst(2, Rd, Rn, immr, imms, invert); + EncodeLogicalImmInst(2, Rd, Rn, immr, imms, invert); } void ARM64XEmitter::ORR(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, bool invert) { - EncodeLogicalImmInst(1, Rd, Rn, immr, imms, invert); + EncodeLogicalImmInst(1, Rd, Rn, immr, imms, invert); } void ARM64XEmitter::TST(ARM64Reg Rn, u32 immr, u32 imms, bool invert) { - EncodeLogicalImmInst(3, Is64Bit(Rn) ? ZR : WZR, Rn, immr, imms, invert); + EncodeLogicalImmInst(3, Is64Bit(Rn) ? ZR : WZR, Rn, immr, imms, invert); } // Add/subtract (immediate) void ARM64XEmitter::ADD(ARM64Reg Rd, ARM64Reg Rn, u32 imm, bool shift) { - EncodeAddSubImmInst(0, false, shift, imm, Rn, Rd); + EncodeAddSubImmInst(0, false, shift, imm, Rn, Rd); } void ARM64XEmitter::ADDS(ARM64Reg Rd, ARM64Reg Rn, u32 imm, bool shift) { - EncodeAddSubImmInst(0, true, shift, imm, Rn, Rd); + EncodeAddSubImmInst(0, true, shift, imm, Rn, Rd); } void ARM64XEmitter::SUB(ARM64Reg Rd, ARM64Reg Rn, u32 imm, bool shift) { - EncodeAddSubImmInst(1, false, shift, imm, Rn, Rd); + EncodeAddSubImmInst(1, false, shift, imm, Rn, Rd); } void ARM64XEmitter::SUBS(ARM64Reg Rd, ARM64Reg Rn, u32 imm, bool shift) { - EncodeAddSubImmInst(1, true, shift, imm, Rn, Rd); + EncodeAddSubImmInst(1, true, shift, imm, Rn, Rd); } void ARM64XEmitter::CMP(ARM64Reg Rn, u32 imm, bool shift) { - EncodeAddSubImmInst(1, true, shift, imm, Rn, Is64Bit(Rn) ? SP : WSP); + EncodeAddSubImmInst(1, true, shift, imm, Rn, Is64Bit(Rn) ? SP : WSP); } // Data Processing (Immediate) void ARM64XEmitter::MOVZ(ARM64Reg Rd, u32 imm, ShiftAmount pos) { - EncodeMOVWideInst(2, Rd, imm, pos); + EncodeMOVWideInst(2, Rd, imm, pos); } void ARM64XEmitter::MOVN(ARM64Reg Rd, u32 imm, ShiftAmount pos) { - EncodeMOVWideInst(0, Rd, imm, pos); + EncodeMOVWideInst(0, Rd, imm, pos); } void ARM64XEmitter::MOVK(ARM64Reg Rd, u32 imm, ShiftAmount pos) { - EncodeMOVWideInst(3, Rd, imm, pos); + EncodeMOVWideInst(3, Rd, imm, pos); } // Bitfield move void ARM64XEmitter::BFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms) { - EncodeBitfieldMOVInst(1, Rd, Rn, immr, imms); + EncodeBitfieldMOVInst(1, Rd, Rn, immr, imms); } void ARM64XEmitter::SBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms) { - EncodeBitfieldMOVInst(0, Rd, Rn, immr, imms); + EncodeBitfieldMOVInst(0, Rd, Rn, immr, imms); } void ARM64XEmitter::UBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms) { - EncodeBitfieldMOVInst(2, Rd, Rn, immr, imms); + EncodeBitfieldMOVInst(2, Rd, Rn, immr, imms); } void ARM64XEmitter::BFI(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width) { - u32 size = Is64Bit(Rn) ? 64 : 32; - _assert_msg_(DYNA_REC, (lsb + width) <= size, "%s passed lsb %d and width %d which is greater than the register size!", - __FUNCTION__, lsb, width); - EncodeBitfieldMOVInst(1, Rd, Rn, (size - lsb) % size, width - 1); + u32 size = Is64Bit(Rn) ? 64 : 32; + _assert_msg_(DYNA_REC, (lsb + width) <= size, + "%s passed lsb %d and width %d which is greater than the register size!", + __FUNCTION__, lsb, width); + EncodeBitfieldMOVInst(1, Rd, Rn, (size - lsb) % size, width - 1); } void ARM64XEmitter::UBFIZ(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width) { - u32 size = Is64Bit(Rn) ? 64 : 32; - _assert_msg_(DYNA_REC, (lsb + width) <= size, "%s passed lsb %d and width %d which is greater than the register size!", - __FUNCTION__, lsb, width); - EncodeBitfieldMOVInst(2, Rd, Rn, (size - lsb) % size, width - 1); + u32 size = Is64Bit(Rn) ? 64 : 32; + _assert_msg_(DYNA_REC, (lsb + width) <= size, + "%s passed lsb %d and width %d which is greater than the register size!", + __FUNCTION__, lsb, width); + EncodeBitfieldMOVInst(2, Rd, Rn, (size - lsb) % size, width - 1); } void ARM64XEmitter::EXTR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u32 shift) { - bool sf = Is64Bit(Rd); - bool N = sf; - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - Rm = DecodeReg(Rm); - Write32((sf << 31) | (0x27 << 23) | (N << 22) | (Rm << 16) | (shift << 10) | (Rm << 5) | Rd); + bool sf = Is64Bit(Rd); + bool N = sf; + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); + Write32((sf << 31) | (0x27 << 23) | (N << 22) | (Rm << 16) | (shift << 10) | (Rm << 5) | Rd); } void ARM64XEmitter::SXTB(ARM64Reg Rd, ARM64Reg Rn) { - SBFM(Rd, Rn, 0, 7); + SBFM(Rd, Rn, 0, 7); } void ARM64XEmitter::SXTH(ARM64Reg Rd, ARM64Reg Rn) { - SBFM(Rd, Rn, 0, 15); + SBFM(Rd, Rn, 0, 15); } void ARM64XEmitter::SXTW(ARM64Reg Rd, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, Is64Bit(Rd), "%s requires 64bit register as destination", __FUNCTION__); - SBFM(Rd, Rn, 0, 31); + _assert_msg_(DYNA_REC, Is64Bit(Rd), "%s requires 64bit register as destination", __FUNCTION__); + SBFM(Rd, Rn, 0, 31); } void ARM64XEmitter::UXTB(ARM64Reg Rd, ARM64Reg Rn) { - UBFM(Rd, Rn, 0, 7); + UBFM(Rd, Rn, 0, 7); } void ARM64XEmitter::UXTH(ARM64Reg Rd, ARM64Reg Rn) { - UBFM(Rd, Rn, 0, 15); + UBFM(Rd, Rn, 0, 15); } // Load Register (Literal) void ARM64XEmitter::LDR(ARM64Reg Rt, u32 imm) { - EncodeLoadRegisterInst(0, Rt, imm); + EncodeLoadRegisterInst(0, Rt, imm); } void ARM64XEmitter::LDRSW(ARM64Reg Rt, u32 imm) { - EncodeLoadRegisterInst(2, Rt, imm); + EncodeLoadRegisterInst(2, Rt, imm); } void ARM64XEmitter::PRFM(ARM64Reg Rt, u32 imm) { - EncodeLoadRegisterInst(3, Rt, imm); + EncodeLoadRegisterInst(3, Rt, imm); } // Load/Store pair void ARM64XEmitter::LDP(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm) { - EncodeLoadStorePair(0, 1, type, Rt, Rt2, Rn, imm); + EncodeLoadStorePair(0, 1, type, Rt, Rt2, Rn, imm); } void ARM64XEmitter::LDPSW(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm) { - EncodeLoadStorePair(1, 1, type, Rt, Rt2, Rn, imm); + EncodeLoadStorePair(1, 1, type, Rt, Rt2, Rn, imm); } void ARM64XEmitter::STP(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm) { - EncodeLoadStorePair(0, 0, type, Rt, Rt2, Rn, imm); + EncodeLoadStorePair(0, 0, type, Rt, Rt2, Rn, imm); } // Load/Store Exclusive void ARM64XEmitter::STXRB(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(0, Rs, SP, Rt, Rn); + EncodeLoadStoreExcInst(0, Rs, SP, Rt, Rn); } void ARM64XEmitter::STLXRB(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(1, Rs, SP, Rt, Rn); + EncodeLoadStoreExcInst(1, Rs, SP, Rt, Rn); } void ARM64XEmitter::LDXRB(ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(2, SP, SP, Rt, Rn); + EncodeLoadStoreExcInst(2, SP, SP, Rt, Rn); } void ARM64XEmitter::LDAXRB(ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(3, SP, SP, Rt, Rn); + EncodeLoadStoreExcInst(3, SP, SP, Rt, Rn); } void ARM64XEmitter::STLRB(ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(4, SP, SP, Rt, Rn); + EncodeLoadStoreExcInst(4, SP, SP, Rt, Rn); } void ARM64XEmitter::LDARB(ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(5, SP, SP, Rt, Rn); + EncodeLoadStoreExcInst(5, SP, SP, Rt, Rn); } void ARM64XEmitter::STXRH(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(6, Rs, SP, Rt, Rn); + EncodeLoadStoreExcInst(6, Rs, SP, Rt, Rn); } void ARM64XEmitter::STLXRH(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(7, Rs, SP, Rt, Rn); + EncodeLoadStoreExcInst(7, Rs, SP, Rt, Rn); } void ARM64XEmitter::LDXRH(ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(8, SP, SP, Rt, Rn); + EncodeLoadStoreExcInst(8, SP, SP, Rt, Rn); } void ARM64XEmitter::LDAXRH(ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(9, SP, SP, Rt, Rn); + EncodeLoadStoreExcInst(9, SP, SP, Rt, Rn); } void ARM64XEmitter::STLRH(ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(10, SP, SP, Rt, Rn); + EncodeLoadStoreExcInst(10, SP, SP, Rt, Rn); } void ARM64XEmitter::LDARH(ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(11, SP, SP, Rt, Rn); + EncodeLoadStoreExcInst(11, SP, SP, Rt, Rn); } void ARM64XEmitter::STXR(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(12 + Is64Bit(Rt), Rs, SP, Rt, Rn); + EncodeLoadStoreExcInst(12 + Is64Bit(Rt), Rs, SP, Rt, Rn); } void ARM64XEmitter::STLXR(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(14 + Is64Bit(Rt), Rs, SP, Rt, Rn); + EncodeLoadStoreExcInst(14 + Is64Bit(Rt), Rs, SP, Rt, Rn); } void ARM64XEmitter::STXP(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn) { - EncodeLoadStoreExcInst(16 + Is64Bit(Rt), Rs, Rt2, Rt, Rn); + EncodeLoadStoreExcInst(16 + Is64Bit(Rt), Rs, Rt2, Rt, Rn); } void ARM64XEmitter::STLXP(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn) { - EncodeLoadStoreExcInst(18 + Is64Bit(Rt), Rs, Rt2, Rt, Rn); + EncodeLoadStoreExcInst(18 + Is64Bit(Rt), Rs, Rt2, Rt, Rn); } void ARM64XEmitter::LDXR(ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(20 + Is64Bit(Rt), SP, SP, Rt, Rn); + EncodeLoadStoreExcInst(20 + Is64Bit(Rt), SP, SP, Rt, Rn); } void ARM64XEmitter::LDAXR(ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(22 + Is64Bit(Rt), SP, SP, Rt, Rn); + EncodeLoadStoreExcInst(22 + Is64Bit(Rt), SP, SP, Rt, Rn); } void ARM64XEmitter::LDXP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn) { - EncodeLoadStoreExcInst(24 + Is64Bit(Rt), SP, Rt2, Rt, Rn); + EncodeLoadStoreExcInst(24 + Is64Bit(Rt), SP, Rt2, Rt, Rn); } void ARM64XEmitter::LDAXP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn) { - EncodeLoadStoreExcInst(26 + Is64Bit(Rt), SP, Rt2, Rt, Rn); + EncodeLoadStoreExcInst(26 + Is64Bit(Rt), SP, Rt2, Rt, Rn); } void ARM64XEmitter::STLR(ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(28 + Is64Bit(Rt), SP, SP, Rt, Rn); + EncodeLoadStoreExcInst(28 + Is64Bit(Rt), SP, SP, Rt, Rn); } void ARM64XEmitter::LDAR(ARM64Reg Rt, ARM64Reg Rn) { - EncodeLoadStoreExcInst(30 + Is64Bit(Rt), SP, SP, Rt, Rn); + EncodeLoadStoreExcInst(30 + Is64Bit(Rt), SP, SP, Rt, Rn); } // Load/Store no-allocate pair (offset) void ARM64XEmitter::STNP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, u32 imm) { - EncodeLoadStorePairedInst(0xA0, Rt, Rt2, Rn, imm); + EncodeLoadStorePairedInst(0xA0, Rt, Rt2, Rn, imm); } void ARM64XEmitter::LDNP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, u32 imm) { - EncodeLoadStorePairedInst(0xA1, Rt, Rt2, Rn, imm); + EncodeLoadStorePairedInst(0xA1, Rt, Rt2, Rn, imm); } // Load/Store register (immediate post-indexed) // XXX: Most of these support vectors void ARM64XEmitter::STRB(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(0x0E4, Rt, Rn, imm, 8); - else - EncodeLoadStoreIndexedInst(0x0E0, - type == INDEX_POST ? 1 : 3, Rt, Rn, imm); + if (type == INDEX_UNSIGNED) + EncodeLoadStoreIndexedInst(0x0E4, Rt, Rn, imm, 8); + else + EncodeLoadStoreIndexedInst(0x0E0, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); } void ARM64XEmitter::LDRB(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(0x0E5, Rt, Rn, imm, 8); - else - EncodeLoadStoreIndexedInst(0x0E1, - type == INDEX_POST ? 1 : 3, Rt, Rn, imm); + if (type == INDEX_UNSIGNED) + EncodeLoadStoreIndexedInst(0x0E5, Rt, Rn, imm, 8); + else + EncodeLoadStoreIndexedInst(0x0E1, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); } void ARM64XEmitter::LDRSB(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x0E6 : 0x0E7, Rt, Rn, imm, 8); - else - EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x0E2 : 0x0E3, - type == INDEX_POST ? 1 : 3, Rt, Rn, imm); + if (type == INDEX_UNSIGNED) + EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x0E6 : 0x0E7, Rt, Rn, imm, 8); + else + EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x0E2 : 0x0E3, type == INDEX_POST ? 1 : 3, Rt, Rn, + imm); } void ARM64XEmitter::STRH(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(0x1E4, Rt, Rn, imm, 16); - else - EncodeLoadStoreIndexedInst(0x1E0, - type == INDEX_POST ? 1 : 3, Rt, Rn, imm); + if (type == INDEX_UNSIGNED) + EncodeLoadStoreIndexedInst(0x1E4, Rt, Rn, imm, 16); + else + EncodeLoadStoreIndexedInst(0x1E0, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); } void ARM64XEmitter::LDRH(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(0x1E5, Rt, Rn, imm, 16); - else - EncodeLoadStoreIndexedInst(0x1E1, - type == INDEX_POST ? 1 : 3, Rt, Rn, imm); + if (type == INDEX_UNSIGNED) + EncodeLoadStoreIndexedInst(0x1E5, Rt, Rn, imm, 16); + else + EncodeLoadStoreIndexedInst(0x1E1, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); } void ARM64XEmitter::LDRSH(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x1E6 : 0x1E7, Rt, Rn, imm, 16); - else - EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x1E2 : 0x1E3, - type == INDEX_POST ? 1 : 3, Rt, Rn, imm); + if (type == INDEX_UNSIGNED) + EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x1E6 : 0x1E7, Rt, Rn, imm, 16); + else + EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x1E2 : 0x1E3, type == INDEX_POST ? 1 : 3, Rt, Rn, + imm); } void ARM64XEmitter::STR(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E4 : 0x2E4, Rt, Rn, imm, Is64Bit(Rt) ? 64 : 32); - else - EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E0 : 0x2E0, - type == INDEX_POST ? 1 : 3, Rt, Rn, imm); + if (type == INDEX_UNSIGNED) + EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E4 : 0x2E4, Rt, Rn, imm, Is64Bit(Rt) ? 64 : 32); + else + EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E0 : 0x2E0, type == INDEX_POST ? 1 : 3, Rt, Rn, + imm); } void ARM64XEmitter::LDR(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E5 : 0x2E5, Rt, Rn, imm, Is64Bit(Rt) ? 64 : 32); - else - EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E1 : 0x2E1, - type == INDEX_POST ? 1 : 3, Rt, Rn, imm); + if (type == INDEX_UNSIGNED) + EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E5 : 0x2E5, Rt, Rn, imm, Is64Bit(Rt) ? 64 : 32); + else + EncodeLoadStoreIndexedInst(Is64Bit(Rt) ? 0x3E1 : 0x2E1, type == INDEX_POST ? 1 : 3, Rt, Rn, + imm); } void ARM64XEmitter::LDRSW(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - if (type == INDEX_UNSIGNED) - EncodeLoadStoreIndexedInst(0x2E6, Rt, Rn, imm, 32); - else - EncodeLoadStoreIndexedInst(0x2E2, - type == INDEX_POST ? 1 : 3, Rt, Rn, imm); + if (type == INDEX_UNSIGNED) + EncodeLoadStoreIndexedInst(0x2E6, Rt, Rn, imm, 32); + else + EncodeLoadStoreIndexedInst(0x2E2, type == INDEX_POST ? 1 : 3, Rt, Rn, imm); } // Load/Store register (register offset) void ARM64XEmitter::STRB(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) { - EncodeLoadStoreRegisterOffset(0, 0, Rt, Rn, Rm); + EncodeLoadStoreRegisterOffset(0, 0, Rt, Rn, Rm); } void ARM64XEmitter::LDRB(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) { - EncodeLoadStoreRegisterOffset(0, 1, Rt, Rn, Rm); + EncodeLoadStoreRegisterOffset(0, 1, Rt, Rn, Rm); } void ARM64XEmitter::LDRSB(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) { - bool b64Bit = Is64Bit(Rt); - EncodeLoadStoreRegisterOffset(0, 3 - b64Bit, Rt, Rn, Rm); + bool b64Bit = Is64Bit(Rt); + EncodeLoadStoreRegisterOffset(0, 3 - b64Bit, Rt, Rn, Rm); } void ARM64XEmitter::STRH(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) { - EncodeLoadStoreRegisterOffset(1, 0, Rt, Rn, Rm); + EncodeLoadStoreRegisterOffset(1, 0, Rt, Rn, Rm); } void ARM64XEmitter::LDRH(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) { - EncodeLoadStoreRegisterOffset(1, 1, Rt, Rn, Rm); + EncodeLoadStoreRegisterOffset(1, 1, Rt, Rn, Rm); } void ARM64XEmitter::LDRSH(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) { - bool b64Bit = Is64Bit(Rt); - EncodeLoadStoreRegisterOffset(1, 3 - b64Bit, Rt, Rn, Rm); + bool b64Bit = Is64Bit(Rt); + EncodeLoadStoreRegisterOffset(1, 3 - b64Bit, Rt, Rn, Rm); } void ARM64XEmitter::STR(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) { - bool b64Bit = Is64Bit(Rt); - EncodeLoadStoreRegisterOffset(2 + b64Bit, 0, Rt, Rn, Rm); + bool b64Bit = Is64Bit(Rt); + EncodeLoadStoreRegisterOffset(2 + b64Bit, 0, Rt, Rn, Rm); } void ARM64XEmitter::LDR(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) { - bool b64Bit = Is64Bit(Rt); - EncodeLoadStoreRegisterOffset(2 + b64Bit, 1, Rt, Rn, Rm); + bool b64Bit = Is64Bit(Rt); + EncodeLoadStoreRegisterOffset(2 + b64Bit, 1, Rt, Rn, Rm); } void ARM64XEmitter::LDRSW(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) { - EncodeLoadStoreRegisterOffset(2, 2, Rt, Rn, Rm); + EncodeLoadStoreRegisterOffset(2, 2, Rt, Rn, Rm); } void ARM64XEmitter::PRFM(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) { - EncodeLoadStoreRegisterOffset(3, 2, Rt, Rn, Rm); + EncodeLoadStoreRegisterOffset(3, 2, Rt, Rn, Rm); } // Load/Store register (unscaled offset) void ARM64XEmitter::STURB(ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - EncodeLoadStoreUnscaled(0, 0, Rt, Rn, imm); + EncodeLoadStoreUnscaled(0, 0, Rt, Rn, imm); } void ARM64XEmitter::LDURB(ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - EncodeLoadStoreUnscaled(0, 1, Rt, Rn, imm); + EncodeLoadStoreUnscaled(0, 1, Rt, Rn, imm); } void ARM64XEmitter::LDURSB(ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - EncodeLoadStoreUnscaled(0, Is64Bit(Rt) ? 2 : 3, Rt, Rn, imm); + EncodeLoadStoreUnscaled(0, Is64Bit(Rt) ? 2 : 3, Rt, Rn, imm); } void ARM64XEmitter::STURH(ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - EncodeLoadStoreUnscaled(1, 0, Rt, Rn, imm); + EncodeLoadStoreUnscaled(1, 0, Rt, Rn, imm); } void ARM64XEmitter::LDURH(ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - EncodeLoadStoreUnscaled(1, 1, Rt, Rn, imm); + EncodeLoadStoreUnscaled(1, 1, Rt, Rn, imm); } void ARM64XEmitter::LDURSH(ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - EncodeLoadStoreUnscaled(1, Is64Bit(Rt) ? 2 : 3, Rt, Rn, imm); + EncodeLoadStoreUnscaled(1, Is64Bit(Rt) ? 2 : 3, Rt, Rn, imm); } void ARM64XEmitter::STUR(ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - EncodeLoadStoreUnscaled(Is64Bit(Rt) ? 3 : 2, 0, Rt, Rn, imm); + EncodeLoadStoreUnscaled(Is64Bit(Rt) ? 3 : 2, 0, Rt, Rn, imm); } void ARM64XEmitter::LDUR(ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - EncodeLoadStoreUnscaled(Is64Bit(Rt) ? 3 : 2, 1, Rt, Rn, imm); + EncodeLoadStoreUnscaled(Is64Bit(Rt) ? 3 : 2, 1, Rt, Rn, imm); } void ARM64XEmitter::LDURSW(ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - _assert_msg_(DYNA_REC, !Is64Bit(Rt), "%s must have a 64bit destination register!", __FUNCTION__); - EncodeLoadStoreUnscaled(2, 2, Rt, Rn, imm); + _assert_msg_(DYNA_REC, !Is64Bit(Rt), "%s must have a 64bit destination register!", __FUNCTION__); + EncodeLoadStoreUnscaled(2, 2, Rt, Rn, imm); } // Address of label/page PC-relative void ARM64XEmitter::ADR(ARM64Reg Rd, s32 imm) { - EncodeAddressInst(0, Rd, imm); + EncodeAddressInst(0, Rd, imm); } void ARM64XEmitter::ADRP(ARM64Reg Rd, s32 imm) { - EncodeAddressInst(1, Rd, imm >> 12); + EncodeAddressInst(1, Rd, imm >> 12); } // Wrapper around MOVZ+MOVK (and later MOVN) void ARM64XEmitter::MOVI2R(ARM64Reg Rd, u64 imm, bool optimize) { - unsigned int parts = Is64Bit(Rd) ? 4 : 2; - BitSet32 upload_part(0); + unsigned int parts = Is64Bit(Rd) ? 4 : 2; + BitSet32 upload_part(0); - // Always start with a movz! Kills the dependency on the register. - bool use_movz = true; + // Always start with a movz! Kills the dependency on the register. + bool use_movz = true; - if (!imm) - { - // Zero immediate, just clear the register. EOR is pointless when we have MOVZ, which looks clearer in disasm too. - MOVZ(Rd, 0, SHIFT_0); - return; - } + if (!imm) + { + // Zero immediate, just clear the register. EOR is pointless when we have MOVZ, which looks + // clearer in disasm too. + MOVZ(Rd, 0, SHIFT_0); + return; + } - if ((Is64Bit(Rd) && imm == std::numeric_limits::max()) || - (!Is64Bit(Rd) && imm == std::numeric_limits::max())) - { - // Max unsigned value (or if signed, -1) - // Set to ~ZR - ARM64Reg ZR = Is64Bit(Rd) ? SP : WSP; - ORN(Rd, ZR, ZR, ArithOption(ZR, ST_LSL, 0)); - return; - } + if ((Is64Bit(Rd) && imm == std::numeric_limits::max()) || + (!Is64Bit(Rd) && imm == std::numeric_limits::max())) + { + // Max unsigned value (or if signed, -1) + // Set to ~ZR + ARM64Reg ZR = Is64Bit(Rd) ? SP : WSP; + ORN(Rd, ZR, ZR, ArithOption(ZR, ST_LSL, 0)); + return; + } - // TODO: Make some more systemic use of MOVN, but this will take care of most cases. - // Small negative integer. Use MOVN - if (!Is64Bit(Rd) && (imm | 0xFFFF0000) == imm) -{ - MOVN(Rd, ~imm, SHIFT_0); - return; - } + // TODO: Make some more systemic use of MOVN, but this will take care of most cases. + // Small negative integer. Use MOVN + if (!Is64Bit(Rd) && (imm | 0xFFFF0000) == imm) + { + MOVN(Rd, ~imm, SHIFT_0); + return; + } + // XXX: Use MOVN when possible. + // XXX: Optimize more + // XXX: Support rotating immediates to save instructions + if (optimize) + { + for (unsigned int i = 0; i < parts; ++i) + { + if ((imm >> (i * 16)) & 0xFFFF) + upload_part[i] = 1; + } + } - // XXX: Use MOVN when possible. - // XXX: Optimize more - // XXX: Support rotating immediates to save instructions - if (optimize) - { - for (unsigned int i = 0; i < parts; ++i) - { - if ((imm >> (i * 16)) & 0xFFFF) - upload_part[i] = 1; - } - } + u64 aligned_pc = (u64)GetCodePtr() & ~0xFFF; + s64 aligned_offset = (s64)imm - (s64)aligned_pc; + if (upload_part.Count() > 1 && std::abs(aligned_offset) < 0xFFFFFFFFLL) + { + // Immediate we are loading is within 4GB of our aligned range + // Most likely a address that we can load in one or two instructions + if (!(std::abs(aligned_offset) & 0xFFF)) + { + // Aligned ADR + ADRP(Rd, (s32)aligned_offset); + return; + } + else + { + // If the address is within 1MB of PC we can load it in a single instruction still + s64 offset = (s64)imm - (s64)GetCodePtr(); + if (offset >= -0xFFFFF && offset <= 0xFFFFF) + { + ADR(Rd, (s32)offset); + return; + } + else + { + ADRP(Rd, (s32)(aligned_offset & ~0xFFF)); + ADD(Rd, Rd, imm & 0xFFF); + return; + } + } + } - u64 aligned_pc = (u64)GetCodePtr() & ~0xFFF; - s64 aligned_offset = (s64)imm - (s64)aligned_pc; - if (upload_part.Count() > 1 && std::abs(aligned_offset) < 0xFFFFFFFFLL) - { - // Immediate we are loading is within 4GB of our aligned range - // Most likely a address that we can load in one or two instructions - if (!(std::abs(aligned_offset) & 0xFFF)) - { - // Aligned ADR - ADRP(Rd, (s32)aligned_offset); - return; - } - else - { - // If the address is within 1MB of PC we can load it in a single instruction still - s64 offset = (s64)imm - (s64)GetCodePtr(); - if (offset >= -0xFFFFF && offset <= 0xFFFFF) - { - ADR(Rd, (s32)offset); - return; - } - else - { - ADRP(Rd, (s32)(aligned_offset & ~0xFFF)); - ADD(Rd, Rd, imm & 0xFFF); - return; - } - } - } - - for (unsigned i = 0; i < parts; ++i) - { - if (use_movz && upload_part[i]) - { - MOVZ(Rd, (imm >> (i * 16)) & 0xFFFF, (ShiftAmount)i); - use_movz = false; - } - else - { - if (upload_part[i] || !optimize) - MOVK(Rd, (imm >> (i * 16)) & 0xFFFF, (ShiftAmount)i); - } - } + for (unsigned i = 0; i < parts; ++i) + { + if (use_movz && upload_part[i]) + { + MOVZ(Rd, (imm >> (i * 16)) & 0xFFFF, (ShiftAmount)i); + use_movz = false; + } + else + { + if (upload_part[i] || !optimize) + MOVK(Rd, (imm >> (i * 16)) & 0xFFFF, (ShiftAmount)i); + } + } } void ARM64XEmitter::ABI_PushRegisters(BitSet32 registers) { - int num_regs = registers.Count(); + int num_regs = registers.Count(); - if (num_regs % 2) - { - bool first = true; + if (num_regs % 2) + { + bool first = true; - // Stack is required to be quad-word aligned. - u32 stack_size = ROUND_UP(num_regs * 8, 16); - u32 current_offset = 0; - std::vector reg_pair; + // Stack is required to be quad-word aligned. + u32 stack_size = ROUND_UP(num_regs * 8, 16); + u32 current_offset = 0; + std::vector reg_pair; - for (auto it : registers) - { - if (first) - { - STR(INDEX_PRE, (ARM64Reg)(X0 + it), SP, -(s32)stack_size); - first = false; - current_offset += 16; - } - else - { - reg_pair.push_back((ARM64Reg)(X0 + it)); - if (reg_pair.size() == 2) - { - STP(INDEX_SIGNED, reg_pair[0], reg_pair[1], SP, current_offset); - reg_pair.clear(); - current_offset += 16; - } - } - } - } - else - { - std::vector reg_pair; + for (auto it : registers) + { + if (first) + { + STR(INDEX_PRE, (ARM64Reg)(X0 + it), SP, -(s32)stack_size); + first = false; + current_offset += 16; + } + else + { + reg_pair.push_back((ARM64Reg)(X0 + it)); + if (reg_pair.size() == 2) + { + STP(INDEX_SIGNED, reg_pair[0], reg_pair[1], SP, current_offset); + reg_pair.clear(); + current_offset += 16; + } + } + } + } + else + { + std::vector reg_pair; - for (auto it : registers) - { - reg_pair.push_back((ARM64Reg)(X0 + it)); - if (reg_pair.size() == 2) - { - STP(INDEX_PRE, reg_pair[0], reg_pair[1], SP, -16); - reg_pair.clear(); - } - } - } + for (auto it : registers) + { + reg_pair.push_back((ARM64Reg)(X0 + it)); + if (reg_pair.size() == 2) + { + STP(INDEX_PRE, reg_pair[0], reg_pair[1], SP, -16); + reg_pair.clear(); + } + } + } } void ARM64XEmitter::ABI_PopRegisters(BitSet32 registers, BitSet32 ignore_mask) { - int num_regs = registers.Count(); + int num_regs = registers.Count(); - if (num_regs % 2) - { - bool first = true; + if (num_regs % 2) + { + bool first = true; - std::vector reg_pair; + std::vector reg_pair; - for (auto it : registers) - { - if (ignore_mask[it]) - it = WSP; + for (auto it : registers) + { + if (ignore_mask[it]) + it = WSP; - if (first) - { - LDR(INDEX_POST, (ARM64Reg)(X0 + it), SP, 16); - first = false; - } - else - { - reg_pair.push_back((ARM64Reg)(X0 + it)); - if (reg_pair.size() == 2) - { - LDP(INDEX_POST, reg_pair[0], reg_pair[1], SP, 16); - reg_pair.clear(); - } - } - } - } - else - { - std::vector reg_pair; + if (first) + { + LDR(INDEX_POST, (ARM64Reg)(X0 + it), SP, 16); + first = false; + } + else + { + reg_pair.push_back((ARM64Reg)(X0 + it)); + if (reg_pair.size() == 2) + { + LDP(INDEX_POST, reg_pair[0], reg_pair[1], SP, 16); + reg_pair.clear(); + } + } + } + } + else + { + std::vector reg_pair; - for (int i = 31; i >= 0; --i) - { - if (!registers[i]) - continue; + for (int i = 31; i >= 0; --i) + { + if (!registers[i]) + continue; - int reg = i; + int reg = i; - if (ignore_mask[reg]) - reg = WSP; + if (ignore_mask[reg]) + reg = WSP; - reg_pair.push_back((ARM64Reg)(X0 + reg)); - if (reg_pair.size() == 2) - { - LDP(INDEX_POST, reg_pair[1], reg_pair[0], SP, 16); - reg_pair.clear(); - } - } - } + reg_pair.push_back((ARM64Reg)(X0 + reg)); + if (reg_pair.size() == 2) + { + LDP(INDEX_POST, reg_pair[1], reg_pair[0], SP, 16); + reg_pair.clear(); + } + } + } } // Float Emitter -void ARM64FloatEmitter::EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) +void ARM64FloatEmitter::EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type, ARM64Reg Rt, + ARM64Reg Rn, s32 imm) { - Rt = DecodeReg(Rt); - Rn = DecodeReg(Rn); - u32 encoded_size = 0; - u32 encoded_imm = 0; + Rt = DecodeReg(Rt); + Rn = DecodeReg(Rn); + u32 encoded_size = 0; + u32 encoded_imm = 0; - if (size == 8) - encoded_size = 0; - else if (size == 16) - encoded_size = 1; - else if (size == 32) - encoded_size = 2; - else if (size == 64) - encoded_size = 3; - else if (size == 128) - encoded_size = 0; + if (size == 8) + encoded_size = 0; + else if (size == 16) + encoded_size = 1; + else if (size == 32) + encoded_size = 2; + else if (size == 64) + encoded_size = 3; + else if (size == 128) + encoded_size = 0; - if (type == INDEX_UNSIGNED) - { - _assert_msg_(DYNA_REC, !(imm & ((size - 1) >> 3)), "%s(INDEX_UNSIGNED) immediate offset must be aligned to size! (%d) (%p)", __FUNCTION__, imm, m_emit->GetCodePtr()); - _assert_msg_(DYNA_REC, imm >= 0, "%s(INDEX_UNSIGNED) immediate offset must be positive!", __FUNCTION__); - if (size == 16) - imm >>= 1; - else if (size == 32) - imm >>= 2; - else if (size == 64) - imm >>= 3; - else if (size == 128) - imm >>= 4; - encoded_imm = (imm & 0xFFF); - } - else - { - _assert_msg_(DYNA_REC, !(imm < -256 || imm > 255), "%s immediate offset must be within range of -256 to 256!", __FUNCTION__); - encoded_imm = (imm & 0x1FF) << 2; - if (type == INDEX_POST) - encoded_imm |= 1; - else - encoded_imm |= 3; - } + if (type == INDEX_UNSIGNED) + { + _assert_msg_(DYNA_REC, !(imm & ((size - 1) >> 3)), + "%s(INDEX_UNSIGNED) immediate offset must be aligned to size! (%d) (%p)", + __FUNCTION__, imm, m_emit->GetCodePtr()); + _assert_msg_(DYNA_REC, imm >= 0, "%s(INDEX_UNSIGNED) immediate offset must be positive!", + __FUNCTION__); + if (size == 16) + imm >>= 1; + else if (size == 32) + imm >>= 2; + else if (size == 64) + imm >>= 3; + else if (size == 128) + imm >>= 4; + encoded_imm = (imm & 0xFFF); + } + else + { + _assert_msg_(DYNA_REC, !(imm < -256 || imm > 255), + "%s immediate offset must be within range of -256 to 256!", __FUNCTION__); + encoded_imm = (imm & 0x1FF) << 2; + if (type == INDEX_POST) + encoded_imm |= 1; + else + encoded_imm |= 3; + } - Write32((encoded_size << 30) | (0xF << 26) | (type == INDEX_UNSIGNED ? (1 << 24) : 0) | \ - (size == 128 ? (1 << 23) : 0) | (opc << 22) | (encoded_imm << 10) | (Rn << 5) | Rt); + Write32((encoded_size << 30) | (0xF << 26) | (type == INDEX_UNSIGNED ? (1 << 24) : 0) | + (size == 128 ? (1 << 23) : 0) | (opc << 22) | (encoded_imm << 10) | (Rn << 5) | Rt); } -void ARM64FloatEmitter::EmitScalar2Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +void ARM64FloatEmitter::EmitScalar2Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, + ARM64Reg Rn, ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s only supports double and single registers!", __FUNCTION__); - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - Rm = DecodeReg(Rm); + _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s only supports double and single registers!", + __FUNCTION__); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); - Write32((M << 31) | (S << 29) | (0b11110001 << 21) | (type << 22) | (Rm << 16) | \ - (opcode << 12) | (1 << 11) | (Rn << 5) | Rd); + Write32((M << 31) | (S << 29) | (0b11110001 << 21) | (type << 22) | (Rm << 16) | (opcode << 12) | + (1 << 11) | (Rn << 5) | Rd); } -void ARM64FloatEmitter::EmitThreeSame(bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +void ARM64FloatEmitter::EmitThreeSame(bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, + ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); - bool quad = IsQuad(Rd); - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - Rm = DecodeReg(Rm); + _assert_msg_(DYNA_REC, !IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); + bool quad = IsQuad(Rd); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); - Write32((quad << 30) | (U << 29) | (0b1110001 << 21) | (size << 22) | \ - (Rm << 16) | (opcode << 11) | (1 << 10) | (Rn << 5) | Rd); + Write32((quad << 30) | (U << 29) | (0b1110001 << 21) | (size << 22) | (Rm << 16) | + (opcode << 11) | (1 << 10) | (Rn << 5) | Rd); } void ARM64FloatEmitter::EmitCopy(bool Q, u32 op, u32 imm5, u32 imm4, ARM64Reg Rd, ARM64Reg Rn) { - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); - Write32((Q << 30) | (op << 29) | (0b111 << 25) | (imm5 << 16) | (imm4 << 11) | \ - (1 << 10) | (Rn << 5) | Rd); + Write32((Q << 30) | (op << 29) | (0b111 << 25) | (imm5 << 16) | (imm4 << 11) | (1 << 10) | + (Rn << 5) | Rd); } void ARM64FloatEmitter::Emit2RegMisc(bool Q, bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, !IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); + _assert_msg_(DYNA_REC, !IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); - Write32((Q << 30) | (U << 29) | (0b1110001 << 21) | (size << 22) | \ - (opcode << 12) | (1 << 11) | (Rn << 5) | Rd); + Write32((Q << 30) | (U << 29) | (0b1110001 << 21) | (size << 22) | (opcode << 12) | (1 << 11) | + (Rn << 5) | Rd); } -void ARM64FloatEmitter::EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, ARM64Reg Rn) +void ARM64FloatEmitter::EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, + ARM64Reg Rt, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, !IsSingle(Rt), "%s doesn't support singles!", __FUNCTION__); - bool quad = IsQuad(Rt); - Rt = DecodeReg(Rt); - Rn = DecodeReg(Rn); + _assert_msg_(DYNA_REC, !IsSingle(Rt), "%s doesn't support singles!", __FUNCTION__); + bool quad = IsQuad(Rt); + Rt = DecodeReg(Rt); + Rn = DecodeReg(Rn); - Write32((quad << 30) | (0b1101 << 24) | (L << 22) | (R << 21) | (opcode << 13) | \ - (S << 12) | (size << 10) | (Rn << 5) | Rt); + Write32((quad << 30) | (0b1101 << 24) | (L << 22) | (R << 21) | (opcode << 13) | (S << 12) | + (size << 10) | (Rn << 5) | Rt); } -void ARM64FloatEmitter::EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm) +void ARM64FloatEmitter::EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, + ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !IsSingle(Rt), "%s doesn't support singles!", __FUNCTION__); - bool quad = IsQuad(Rt); - Rt = DecodeReg(Rt); - Rn = DecodeReg(Rn); - Rm = DecodeReg(Rm); + _assert_msg_(DYNA_REC, !IsSingle(Rt), "%s doesn't support singles!", __FUNCTION__); + bool quad = IsQuad(Rt); + Rt = DecodeReg(Rt); + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); - Write32((quad << 30) | (0x1B << 23) | (L << 22) | (R << 21) | (Rm << 16) | \ - (opcode << 13) | (S << 12) | (size << 10) | (Rn << 5) | Rt); + Write32((quad << 30) | (0x1B << 23) | (L << 22) | (R << 21) | (Rm << 16) | (opcode << 13) | + (S << 12) | (size << 10) | (Rn << 5) | Rt); } void ARM64FloatEmitter::Emit1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); + _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); - Write32((M << 31) | (S << 29) | (0xF1 << 21) | (type << 22) | (opcode << 15) | \ - (1 << 14) | (Rn << 5) | Rd); + Write32((M << 31) | (S << 29) | (0xF1 << 21) | (type << 22) | (opcode << 15) | (1 << 14) | + (Rn << 5) | Rd); } -void ARM64FloatEmitter::EmitConversion(bool sf, bool S, u32 type, u32 rmode, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) +void ARM64FloatEmitter::EmitConversion(bool sf, bool S, u32 type, u32 rmode, u32 opcode, + ARM64Reg Rd, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, Rn <= SP, "%s only supports GPR as source!", __FUNCTION__); - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); + _assert_msg_(DYNA_REC, Rn <= SP, "%s only supports GPR as source!", __FUNCTION__); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); - Write32((sf << 31) | (S << 29) | (0xF1 << 21) | (type << 22) | (rmode << 19) | \ - (opcode << 16) | (Rn << 5) | Rd); + Write32((sf << 31) | (S << 29) | (0xF1 << 21) | (type << 22) | (rmode << 19) | (opcode << 16) | + (Rn << 5) | Rd); } -void ARM64FloatEmitter::EmitConvertScalarToInt(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round, bool sign) +void ARM64FloatEmitter::EmitConvertScalarToInt(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round, + bool sign) { - _dbg_assert_msg_(DYNA_REC, IsScalar(Rn), "fcvts: Rn must be floating point"); - if (IsGPR(Rd)) - { - // Use the encoding that transfers the result to a GPR. - bool sf = Is64Bit(Rd); - int type = IsDouble(Rn) ? 1 : 0; - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - int opcode = (sign ? 1 : 0); - int rmode = 0; - switch (round) - { - case ROUND_A: rmode = 0; opcode |= 4; break; - case ROUND_P: rmode = 1; break; - case ROUND_M: rmode = 2; break; - case ROUND_Z: rmode = 3; break; - case ROUND_N: rmode = 0; break; - } - EmitConversion2(sf, 0, true, type, rmode, opcode, 0, Rd, Rn); - } - else - { - // Use the encoding (vector, single) that keeps the result in the fp register. - int sz = IsDouble(Rn); - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - int opcode = 0; - switch (round) - { - case ROUND_A: opcode = 0x1C; break; - case ROUND_N: opcode = 0x1A; break; - case ROUND_M: opcode = 0x1B; break; - case ROUND_P: opcode = 0x1A; sz |= 2; break; - case ROUND_Z: opcode = 0x1B; sz |= 2; break; - } - Write32((0x5E << 24) | (sign << 29) | (sz << 22) | (1 << 21) | (opcode << 12) | (2 << 10) | (Rn << 5) | Rd); - } + _dbg_assert_msg_(DYNA_REC, IsScalar(Rn), "fcvts: Rn must be floating point"); + if (IsGPR(Rd)) + { + // Use the encoding that transfers the result to a GPR. + bool sf = Is64Bit(Rd); + int type = IsDouble(Rn) ? 1 : 0; + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + int opcode = (sign ? 1 : 0); + int rmode = 0; + switch (round) + { + case ROUND_A: + rmode = 0; + opcode |= 4; + break; + case ROUND_P: + rmode = 1; + break; + case ROUND_M: + rmode = 2; + break; + case ROUND_Z: + rmode = 3; + break; + case ROUND_N: + rmode = 0; + break; + } + EmitConversion2(sf, 0, true, type, rmode, opcode, 0, Rd, Rn); + } + else + { + // Use the encoding (vector, single) that keeps the result in the fp register. + int sz = IsDouble(Rn); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + int opcode = 0; + switch (round) + { + case ROUND_A: + opcode = 0x1C; + break; + case ROUND_N: + opcode = 0x1A; + break; + case ROUND_M: + opcode = 0x1B; + break; + case ROUND_P: + opcode = 0x1A; + sz |= 2; + break; + case ROUND_Z: + opcode = 0x1B; + sz |= 2; + break; + } + Write32((0x5E << 24) | (sign << 29) | (sz << 22) | (1 << 21) | (opcode << 12) | (2 << 10) | + (Rn << 5) | Rd); + } } void ARM64FloatEmitter::FCVTS(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round) { - EmitConvertScalarToInt(Rd, Rn, round, false); + EmitConvertScalarToInt(Rd, Rn, round, false); } void ARM64FloatEmitter::FCVTU(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round) { - EmitConvertScalarToInt(Rd, Rn, round, true); + EmitConvertScalarToInt(Rd, Rn, round, true); } -void ARM64FloatEmitter::EmitConversion2(bool sf, bool S, bool direction, u32 type, u32 rmode, u32 opcode, int scale, ARM64Reg Rd, ARM64Reg Rn) +void ARM64FloatEmitter::EmitConversion2(bool sf, bool S, bool direction, u32 type, u32 rmode, + u32 opcode, int scale, ARM64Reg Rd, ARM64Reg Rn) { - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); - Write32((sf << 31) | (S << 29) | (0xF0 << 21) | (direction << 21) | (type << 22) | (rmode << 19) | \ - (opcode << 16) | (scale << 10) | (Rn << 5) | Rd); + Write32((sf << 31) | (S << 29) | (0xF0 << 21) | (direction << 21) | (type << 22) | (rmode << 19) | + (opcode << 16) | (scale << 10) | (Rn << 5) | Rd); } void ARM64FloatEmitter::EmitCompare(bool M, bool S, u32 op, u32 opcode2, ARM64Reg Rn, ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !IsQuad(Rn), "%s doesn't support vector!", __FUNCTION__); - bool is_double = IsDouble(Rn); + _assert_msg_(DYNA_REC, !IsQuad(Rn), "%s doesn't support vector!", __FUNCTION__); + bool is_double = IsDouble(Rn); - Rn = DecodeReg(Rn); - Rm = DecodeReg(Rm); + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); - Write32((M << 31) | (S << 29) | (0xF1 << 21) | (is_double << 22) | (Rm << 16) | \ - (op << 14) | (1 << 13) | (Rn << 5) | opcode2); + Write32((M << 31) | (S << 29) | (0xF1 << 21) | (is_double << 22) | (Rm << 16) | (op << 14) | + (1 << 13) | (Rn << 5) | opcode2); } -void ARM64FloatEmitter::EmitCondSelect(bool M, bool S, CCFlags cond, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +void ARM64FloatEmitter::EmitCondSelect(bool M, bool S, CCFlags cond, ARM64Reg Rd, ARM64Reg Rn, + ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); - bool is_double = IsDouble(Rd); + _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); + bool is_double = IsDouble(Rd); - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - Rm = DecodeReg(Rm); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); - Write32((M << 31) | (S << 29) | (0xF1 << 21) | (is_double << 22) | (Rm << 16) | \ - (cond << 12) | (3 << 10) | (Rn << 5) | Rd); + Write32((M << 31) | (S << 29) | (0xF1 << 21) | (is_double << 22) | (Rm << 16) | (cond << 12) | + (3 << 10) | (Rn << 5) | Rd); } void ARM64FloatEmitter::EmitPermute(u32 size, u32 op, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); + _assert_msg_(DYNA_REC, !IsSingle(Rd), "%s doesn't support singles!", __FUNCTION__); - bool quad = IsQuad(Rd); + bool quad = IsQuad(Rd); - u32 encoded_size = 0; - if (size == 16) - encoded_size = 1; - else if (size == 32) - encoded_size = 2; - else if (size == 64) - encoded_size = 3; + u32 encoded_size = 0; + if (size == 16) + encoded_size = 1; + else if (size == 32) + encoded_size = 2; + else if (size == 64) + encoded_size = 3; - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - Rm = DecodeReg(Rm); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); - Write32((quad << 30) | (7 << 25) | (encoded_size << 22) | (Rm << 16) | (op << 12) | \ - (1 << 11) | (Rn << 5) | Rd); + Write32((quad << 30) | (7 << 25) | (encoded_size << 22) | (Rm << 16) | (op << 12) | (1 << 11) | + (Rn << 5) | Rd); } void ARM64FloatEmitter::EmitScalarImm(bool M, bool S, u32 type, u32 imm5, ARM64Reg Rd, u32 imm8) { - _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); + _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); - bool is_double = !IsSingle(Rd); + bool is_double = !IsSingle(Rd); - Rd = DecodeReg(Rd); + Rd = DecodeReg(Rd); - Write32((M << 31) | (S << 29) | (0xF1 << 21) | (is_double << 22) | (type << 22) | \ - (imm8 << 13) | (1 << 12) | (imm5 << 5) | Rd); + Write32((M << 31) | (S << 29) | (0xF1 << 21) | (is_double << 22) | (type << 22) | (imm8 << 13) | + (1 << 12) | (imm5 << 5) | Rd); } -void ARM64FloatEmitter::EmitShiftImm(bool Q, bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) +void ARM64FloatEmitter::EmitShiftImm(bool Q, bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, + ARM64Reg Rn) { - _assert_msg_(DYNA_REC, immh, "%s bad encoding! Can't have zero immh", __FUNCTION__); + _assert_msg_(DYNA_REC, immh, "%s bad encoding! Can't have zero immh", __FUNCTION__); - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); - Write32((Q << 30) | (U << 29) | (0xF << 24) | (immh << 19) | (immb << 16) | \ - (opcode << 11) | (1 << 10) | (Rn << 5) | Rd); + Write32((Q << 30) | (U << 29) | (0xF << 24) | (immh << 19) | (immb << 16) | (opcode << 11) | + (1 << 10) | (Rn << 5) | Rd); } -void ARM64FloatEmitter::EmitScalarShiftImm(bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) +void ARM64FloatEmitter::EmitScalarShiftImm(bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, + ARM64Reg Rn) { - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); - Write32((2 << 30) | (U << 29) | (0x3E << 23) | (immh << 19) | (immb << 16) | (opcode << 11) | (1 << 10) | (Rn << 5) | Rd); + Write32((2 << 30) | (U << 29) | (0x3E << 23) | (immh << 19) | (immb << 16) | (opcode << 11) | + (1 << 10) | (Rn << 5) | Rd); } -void ARM64FloatEmitter::EmitLoadStoreMultipleStructure(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn) +void ARM64FloatEmitter::EmitLoadStoreMultipleStructure(u32 size, bool L, u32 opcode, ARM64Reg Rt, + ARM64Reg Rn) { - bool quad = IsQuad(Rt); - u32 encoded_size = 0; + bool quad = IsQuad(Rt); + u32 encoded_size = 0; - if (size == 16) - encoded_size = 1; - else if (size == 32) - encoded_size = 2; - else if (size == 64) - encoded_size = 3; + if (size == 16) + encoded_size = 1; + else if (size == 32) + encoded_size = 2; + else if (size == 64) + encoded_size = 3; - Rt = DecodeReg(Rt); - Rn = DecodeReg(Rn); + Rt = DecodeReg(Rt); + Rn = DecodeReg(Rn); - Write32((quad << 30) | (3 << 26) | (L << 22) | (opcode << 12) | \ - (encoded_size << 10) | (Rn << 5) | Rt); + Write32((quad << 30) | (3 << 26) | (L << 22) | (opcode << 12) | (encoded_size << 10) | (Rn << 5) | + Rt); } -void ARM64FloatEmitter::EmitLoadStoreMultipleStructurePost(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm) +void ARM64FloatEmitter::EmitLoadStoreMultipleStructurePost(u32 size, bool L, u32 opcode, + ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm) { - bool quad = IsQuad(Rt); - u32 encoded_size = 0; + bool quad = IsQuad(Rt); + u32 encoded_size = 0; - if (size == 16) - encoded_size = 1; - else if (size == 32) - encoded_size = 2; - else if (size == 64) - encoded_size = 3; + if (size == 16) + encoded_size = 1; + else if (size == 32) + encoded_size = 2; + else if (size == 64) + encoded_size = 3; - Rt = DecodeReg(Rt); - Rn = DecodeReg(Rn); - Rm = DecodeReg(Rm); - - Write32((quad << 30) | (0b11001 << 23) | (L << 22) | (Rm << 16) | (opcode << 12) | \ - (encoded_size << 10) | (Rn << 5) | Rt); + Rt = DecodeReg(Rt); + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); + Write32((quad << 30) | (0b11001 << 23) | (L << 22) | (Rm << 16) | (opcode << 12) | + (encoded_size << 10) | (Rn << 5) | Rt); } -void ARM64FloatEmitter::EmitScalar1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn) +void ARM64FloatEmitter::EmitScalar1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, + ARM64Reg Rn) { - _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); + _assert_msg_(DYNA_REC, !IsQuad(Rd), "%s doesn't support vector!", __FUNCTION__); - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); - Write32((M << 31) | (S << 29) | (0xF1 << 21) | (type << 22) | \ - (opcode << 15) | (1 << 14) | (Rn << 5) | Rd); + Write32((M << 31) | (S << 29) | (0xF1 << 21) | (type << 22) | (opcode << 15) | (1 << 14) | + (Rn << 5) | Rd); } -void ARM64FloatEmitter::EmitVectorxElement(bool U, u32 size, bool L, u32 opcode, bool H, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) +void ARM64FloatEmitter::EmitVectorxElement(bool U, u32 size, bool L, u32 opcode, bool H, + ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - bool quad = IsQuad(Rd); + bool quad = IsQuad(Rd); - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - Rm = DecodeReg(Rm); + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); - Write32((quad << 30) | (U << 29) | (0xF << 24) | (size << 22) | (L << 21) | \ - (Rm << 16) | (opcode << 12) | (H << 11) | (Rn << 5) | Rd); + Write32((quad << 30) | (U << 29) | (0xF << 24) | (size << 22) | (L << 21) | (Rm << 16) | + (opcode << 12) | (H << 11) | (Rn << 5) | Rd); } void ARM64FloatEmitter::EmitLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - _assert_msg_(DYNA_REC, !(imm < -256 || imm > 255), "%s received too large offset: %d", __FUNCTION__, imm); - Rt = DecodeReg(Rt); - Rn = DecodeReg(Rn); + _assert_msg_(DYNA_REC, !(imm < -256 || imm > 255), "%s received too large offset: %d", + __FUNCTION__, imm); + Rt = DecodeReg(Rt); + Rn = DecodeReg(Rn); - Write32((size << 30) | (0xF << 26) | (op << 22) | ((imm & 0x1FF) << 12) | (Rn << 5) | Rt); + Write32((size << 30) | (0xF << 26) | (op << 22) | ((imm & 0x1FF) << 12) | (Rn << 5) | Rt); } -void ARM64FloatEmitter::EncodeLoadStorePair(u32 size, bool load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm) +void ARM64FloatEmitter::EncodeLoadStorePair(u32 size, bool load, IndexType type, ARM64Reg Rt, + ARM64Reg Rt2, ARM64Reg Rn, s32 imm) { - u32 type_encode = 0; - u32 opc = 0; + u32 type_encode = 0; + u32 opc = 0; - switch (type) - { - case INDEX_SIGNED: - type_encode = 0b010; - break; - case INDEX_POST: - type_encode = 0b001; - break; - case INDEX_PRE: - type_encode = 0b011; - break; - case INDEX_UNSIGNED: - _assert_msg_(DYNA_REC, false, "%s doesn't support INDEX_UNSIGNED!", __FUNCTION__); - break; - } + switch (type) + { + case INDEX_SIGNED: + type_encode = 0b010; + break; + case INDEX_POST: + type_encode = 0b001; + break; + case INDEX_PRE: + type_encode = 0b011; + break; + case INDEX_UNSIGNED: + _assert_msg_(DYNA_REC, false, "%s doesn't support INDEX_UNSIGNED!", __FUNCTION__); + break; + } - if (size == 128) - { - _assert_msg_(DYNA_REC, !(imm & 0xF), "%s received invalid offset 0x%x!", __FUNCTION__, imm); - opc = 2; - imm >>= 4; - } - else if (size == 64) - { - _assert_msg_(DYNA_REC, !(imm & 0x7), "%s received invalid offset 0x%x!", __FUNCTION__, imm); - opc = 1; - imm >>= 3; - } - else if (size == 32) - { - _assert_msg_(DYNA_REC, !(imm & 0x3), "%s received invalid offset 0x%x!", __FUNCTION__, imm); - opc = 0; - imm >>= 2; - } + if (size == 128) + { + _assert_msg_(DYNA_REC, !(imm & 0xF), "%s received invalid offset 0x%x!", __FUNCTION__, imm); + opc = 2; + imm >>= 4; + } + else if (size == 64) + { + _assert_msg_(DYNA_REC, !(imm & 0x7), "%s received invalid offset 0x%x!", __FUNCTION__, imm); + opc = 1; + imm >>= 3; + } + else if (size == 32) + { + _assert_msg_(DYNA_REC, !(imm & 0x3), "%s received invalid offset 0x%x!", __FUNCTION__, imm); + opc = 0; + imm >>= 2; + } - Rt = DecodeReg(Rt); - Rt2 = DecodeReg(Rt2); - Rn = DecodeReg(Rn); - - Write32((opc << 30) | (0b1011 << 26) | (type_encode << 23) | (load << 22) | \ - ((imm & 0x7F) << 15) | (Rt2 << 10) | (Rn << 5) | Rt); + Rt = DecodeReg(Rt); + Rt2 = DecodeReg(Rt2); + Rn = DecodeReg(Rn); + Write32((opc << 30) | (0b1011 << 26) | (type_encode << 23) | (load << 22) | ((imm & 0x7F) << 15) | + (Rt2 << 10) | (Rn << 5) | Rt); } -void ARM64FloatEmitter::EncodeLoadStoreRegisterOffset(u32 size, bool load, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) +void ARM64FloatEmitter::EncodeLoadStoreRegisterOffset(u32 size, bool load, ARM64Reg Rt, ARM64Reg Rn, + ArithOption Rm) { - _assert_msg_(DYNA_REC, Rm.GetType() == ArithOption::TYPE_EXTENDEDREG, "%s must contain an extended reg as Rm!", __FUNCTION__); + _assert_msg_(DYNA_REC, Rm.GetType() == ArithOption::TYPE_EXTENDEDREG, + "%s must contain an extended reg as Rm!", __FUNCTION__); - u32 encoded_size = 0; - u32 encoded_op = 0; + u32 encoded_size = 0; + u32 encoded_op = 0; - if (size == 8) - { - encoded_size = 0; - encoded_op = 0; - } - else if (size == 16) - { - encoded_size = 1; - encoded_op = 0; - } - else if (size == 32) - { - encoded_size = 2; - encoded_op = 0; - } - else if (size == 64) - { - encoded_size = 3; - encoded_op = 0; - } - else if (size == 128) - { - encoded_size = 0; - encoded_op = 2; - } + if (size == 8) + { + encoded_size = 0; + encoded_op = 0; + } + else if (size == 16) + { + encoded_size = 1; + encoded_op = 0; + } + else if (size == 32) + { + encoded_size = 2; + encoded_op = 0; + } + else if (size == 64) + { + encoded_size = 3; + encoded_op = 0; + } + else if (size == 128) + { + encoded_size = 0; + encoded_op = 2; + } - if (load) - encoded_op |= 1; + if (load) + encoded_op |= 1; - Rt = DecodeReg(Rt); - Rn = DecodeReg(Rn); - ARM64Reg decoded_Rm = DecodeReg(Rm.GetReg()); + Rt = DecodeReg(Rt); + Rn = DecodeReg(Rn); + ARM64Reg decoded_Rm = DecodeReg(Rm.GetReg()); - Write32((encoded_size << 30) | (encoded_op << 22) | (0b111100001 << 21) | (decoded_Rm << 16) | \ - Rm.GetData() | (1 << 11) | (Rn << 5) | Rt); + Write32((encoded_size << 30) | (encoded_op << 22) | (0b111100001 << 21) | (decoded_Rm << 16) | + Rm.GetData() | (1 << 11) | (Rn << 5) | Rt); } void ARM64FloatEmitter::EncodeModImm(bool Q, u8 op, u8 cmode, u8 o2, ARM64Reg Rd, u8 abcdefgh) { - union - { - u8 hex; - struct - { - unsigned defgh : 5; - unsigned abc : 3; - }; - } v; - v.hex = abcdefgh; - Rd = DecodeReg(Rd); - Write32((Q << 30) | (op << 29) | (0xF << 24) | (v.abc << 16) | (cmode << 12) | \ - (o2 << 11) | (1 << 10) | (v.defgh << 5) | Rd); + union { + u8 hex; + struct + { + unsigned defgh : 5; + unsigned abc : 3; + }; + } v; + v.hex = abcdefgh; + Rd = DecodeReg(Rd); + Write32((Q << 30) | (op << 29) | (0xF << 24) | (v.abc << 16) | (cmode << 12) | (o2 << 11) | + (1 << 10) | (v.defgh << 5) | Rd); } void ARM64FloatEmitter::LDR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - EmitLoadStoreImmediate(size, 1, type, Rt, Rn, imm); + EmitLoadStoreImmediate(size, 1, type, Rt, Rn, imm); } void ARM64FloatEmitter::STR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - EmitLoadStoreImmediate(size, 0, type, Rt, Rn, imm); + EmitLoadStoreImmediate(size, 0, type, Rt, Rn, imm); } // Loadstore unscaled void ARM64FloatEmitter::LDUR(u8 size, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - u32 encoded_size = 0; - u32 encoded_op = 0; + u32 encoded_size = 0; + u32 encoded_op = 0; - if (size == 8) - { - encoded_size = 0; - encoded_op = 1; - } - else if (size == 16) - { - encoded_size = 1; - encoded_op = 1; - } - else if (size == 32) - { - encoded_size = 2; - encoded_op = 1; - } - else if (size == 64) - { - encoded_size = 3; - encoded_op = 1; - } - else if (size == 128) - { - encoded_size = 0; - encoded_op = 3; - } + if (size == 8) + { + encoded_size = 0; + encoded_op = 1; + } + else if (size == 16) + { + encoded_size = 1; + encoded_op = 1; + } + else if (size == 32) + { + encoded_size = 2; + encoded_op = 1; + } + else if (size == 64) + { + encoded_size = 3; + encoded_op = 1; + } + else if (size == 128) + { + encoded_size = 0; + encoded_op = 3; + } - EmitLoadStoreUnscaled(encoded_size, encoded_op, Rt, Rn, imm); + EmitLoadStoreUnscaled(encoded_size, encoded_op, Rt, Rn, imm); } void ARM64FloatEmitter::STUR(u8 size, ARM64Reg Rt, ARM64Reg Rn, s32 imm) { - u32 encoded_size = 0; - u32 encoded_op = 0; + u32 encoded_size = 0; + u32 encoded_op = 0; - if (size == 8) - { - encoded_size = 0; - encoded_op = 0; - } - else if (size == 16) - { - encoded_size = 1; - encoded_op = 0; - } - else if (size == 32) - { - encoded_size = 2; - encoded_op = 0; - } - else if (size == 64) - { - encoded_size = 3; - encoded_op = 0; - } - else if (size == 128) - { - encoded_size = 0; - encoded_op = 2; - } - - EmitLoadStoreUnscaled(encoded_size, encoded_op, Rt, Rn, imm); + if (size == 8) + { + encoded_size = 0; + encoded_op = 0; + } + else if (size == 16) + { + encoded_size = 1; + encoded_op = 0; + } + else if (size == 32) + { + encoded_size = 2; + encoded_op = 0; + } + else if (size == 64) + { + encoded_size = 3; + encoded_op = 0; + } + else if (size == 128) + { + encoded_size = 0; + encoded_op = 2; + } + EmitLoadStoreUnscaled(encoded_size, encoded_op, Rt, Rn, imm); } // Loadstore single structure void ARM64FloatEmitter::LD1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn) { - bool S = 0; - u32 opcode = 0; - u32 encoded_size = 0; - ARM64Reg encoded_reg = INVALID_REG; + bool S = 0; + u32 opcode = 0; + u32 encoded_size = 0; + ARM64Reg encoded_reg = INVALID_REG; - if (size == 8) - { - S = (index & 4) != 0; - opcode = 0; - encoded_size = index & 3; - if (index & 8) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); + if (size == 8) + { + S = (index & 4) != 0; + opcode = 0; + encoded_size = index & 3; + if (index & 8) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } + else if (size == 16) + { + S = (index & 2) != 0; + opcode = 2; + encoded_size = (index & 1) << 1; + if (index & 4) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } + else if (size == 32) + { + S = (index & 1) != 0; + opcode = 4; + encoded_size = 0; + if (index & 2) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } + else if (size == 64) + { + S = 0; + opcode = 4; + encoded_size = 1; + if (index == 1) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } - } - else if (size == 16) - { - S = (index & 2) != 0; - opcode = 2; - encoded_size = (index & 1) << 1; - if (index & 4) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); - - } - else if (size == 32) - { - S = (index & 1) != 0; - opcode = 4; - encoded_size = 0; - if (index & 2) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); - } - else if (size == 64) - { - S = 0; - opcode = 4; - encoded_size = 1; - if (index == 1) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); - } - - EmitLoadStoreSingleStructure(1, 0, opcode, S, encoded_size, encoded_reg, Rn); + EmitLoadStoreSingleStructure(1, 0, opcode, S, encoded_size, encoded_reg, Rn); } void ARM64FloatEmitter::LD1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn, ARM64Reg Rm) { - bool S = 0; - u32 opcode = 0; - u32 encoded_size = 0; - ARM64Reg encoded_reg = INVALID_REG; + bool S = 0; + u32 opcode = 0; + u32 encoded_size = 0; + ARM64Reg encoded_reg = INVALID_REG; - if (size == 8) - { - S = (index & 4) != 0; - opcode = 0; - encoded_size = index & 3; - if (index & 8) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); + if (size == 8) + { + S = (index & 4) != 0; + opcode = 0; + encoded_size = index & 3; + if (index & 8) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } + else if (size == 16) + { + S = (index & 2) != 0; + opcode = 2; + encoded_size = (index & 1) << 1; + if (index & 4) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } + else if (size == 32) + { + S = (index & 1) != 0; + opcode = 4; + encoded_size = 0; + if (index & 2) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } + else if (size == 64) + { + S = 0; + opcode = 4; + encoded_size = 1; + if (index == 1) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } - } - else if (size == 16) - { - S = (index & 2) != 0; - opcode = 2; - encoded_size = (index & 1) << 1; - if (index & 4) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); - - } - else if (size == 32) - { - S = (index & 1) != 0; - opcode = 4; - encoded_size = 0; - if (index & 2) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); - } - else if (size == 64) - { - S = 0; - opcode = 4; - encoded_size = 1; - if (index == 1) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); - } - - EmitLoadStoreSingleStructure(1, 0, opcode, S, encoded_size, encoded_reg, Rn, Rm); + EmitLoadStoreSingleStructure(1, 0, opcode, S, encoded_size, encoded_reg, Rn, Rm); } void ARM64FloatEmitter::LD1R(u8 size, ARM64Reg Rt, ARM64Reg Rn) { - EmitLoadStoreSingleStructure(1, 0, 6, 0, size >> 4, Rt, Rn); + EmitLoadStoreSingleStructure(1, 0, 6, 0, size >> 4, Rt, Rn); } void ARM64FloatEmitter::LD2R(u8 size, ARM64Reg Rt, ARM64Reg Rn) { - EmitLoadStoreSingleStructure(1, 1, 6, 0, size >> 4, Rt, Rn); + EmitLoadStoreSingleStructure(1, 1, 6, 0, size >> 4, Rt, Rn); } void ARM64FloatEmitter::LD1R(u8 size, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm) { - EmitLoadStoreSingleStructure(1, 0, 6, 0, size >> 4, Rt, Rn, Rm); + EmitLoadStoreSingleStructure(1, 0, 6, 0, size >> 4, Rt, Rn, Rm); } void ARM64FloatEmitter::LD2R(u8 size, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm) { - EmitLoadStoreSingleStructure(1, 1, 6, 0, size >> 4, Rt, Rn, Rm); + EmitLoadStoreSingleStructure(1, 1, 6, 0, size >> 4, Rt, Rn, Rm); } void ARM64FloatEmitter::ST1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn) { - bool S = 0; - u32 opcode = 0; - u32 encoded_size = 0; - ARM64Reg encoded_reg = INVALID_REG; + bool S = 0; + u32 opcode = 0; + u32 encoded_size = 0; + ARM64Reg encoded_reg = INVALID_REG; - if (size == 8) - { - S = (index & 4) != 0; - opcode = 0; - encoded_size = index & 3; - if (index & 8) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); + if (size == 8) + { + S = (index & 4) != 0; + opcode = 0; + encoded_size = index & 3; + if (index & 8) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } + else if (size == 16) + { + S = (index & 2) != 0; + opcode = 2; + encoded_size = (index & 1) << 1; + if (index & 4) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } + else if (size == 32) + { + S = (index & 1) != 0; + opcode = 4; + encoded_size = 0; + if (index & 2) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } + else if (size == 64) + { + S = 0; + opcode = 4; + encoded_size = 1; + if (index == 1) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } - } - else if (size == 16) - { - S = (index & 2) != 0; - opcode = 2; - encoded_size = (index & 1) << 1; - if (index & 4) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); - - } - else if (size == 32) - { - S = (index & 1) != 0; - opcode = 4; - encoded_size = 0; - if (index & 2) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); - } - else if (size == 64) - { - S = 0; - opcode = 4; - encoded_size = 1; - if (index == 1) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); - } - - EmitLoadStoreSingleStructure(0, 0, opcode, S, encoded_size, encoded_reg, Rn); + EmitLoadStoreSingleStructure(0, 0, opcode, S, encoded_size, encoded_reg, Rn); } void ARM64FloatEmitter::ST1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn, ARM64Reg Rm) { - bool S = 0; - u32 opcode = 0; - u32 encoded_size = 0; - ARM64Reg encoded_reg = INVALID_REG; + bool S = 0; + u32 opcode = 0; + u32 encoded_size = 0; + ARM64Reg encoded_reg = INVALID_REG; - if (size == 8) - { - S = (index & 4) != 0; - opcode = 0; - encoded_size = index & 3; - if (index & 8) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); + if (size == 8) + { + S = (index & 4) != 0; + opcode = 0; + encoded_size = index & 3; + if (index & 8) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } + else if (size == 16) + { + S = (index & 2) != 0; + opcode = 2; + encoded_size = (index & 1) << 1; + if (index & 4) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } + else if (size == 32) + { + S = (index & 1) != 0; + opcode = 4; + encoded_size = 0; + if (index & 2) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } + else if (size == 64) + { + S = 0; + opcode = 4; + encoded_size = 1; + if (index == 1) + encoded_reg = EncodeRegToQuad(Rt); + else + encoded_reg = EncodeRegToDouble(Rt); + } - } - else if (size == 16) - { - S = (index & 2) != 0; - opcode = 2; - encoded_size = (index & 1) << 1; - if (index & 4) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); - - } - else if (size == 32) - { - S = (index & 1) != 0; - opcode = 4; - encoded_size = 0; - if (index & 2) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); - } - else if (size == 64) - { - S = 0; - opcode = 4; - encoded_size = 1; - if (index == 1) - encoded_reg = EncodeRegToQuad(Rt); - else - encoded_reg = EncodeRegToDouble(Rt); - } - - EmitLoadStoreSingleStructure(0, 0, opcode, S, encoded_size, encoded_reg, Rn, Rm); + EmitLoadStoreSingleStructure(0, 0, opcode, S, encoded_size, encoded_reg, Rn, Rm); } // Loadstore multiple structure void ARM64FloatEmitter::LD1(u8 size, u8 count, ARM64Reg Rt, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, !(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", __FUNCTION__); - u32 opcode = 0; - if (count == 1) - opcode = 0b111; - else if (count == 2) - opcode = 0b1010; - else if (count == 3) - opcode = 0b0110; - else if (count == 4) - opcode = 0b0010; - EmitLoadStoreMultipleStructure(size, 1, opcode, Rt, Rn); + _assert_msg_(DYNA_REC, !(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", + __FUNCTION__); + u32 opcode = 0; + if (count == 1) + opcode = 0b111; + else if (count == 2) + opcode = 0b1010; + else if (count == 3) + opcode = 0b0110; + else if (count == 4) + opcode = 0b0010; + EmitLoadStoreMultipleStructure(size, 1, opcode, Rt, Rn); } -void ARM64FloatEmitter::LD1(u8 size, u8 count, IndexType type, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm) +void ARM64FloatEmitter::LD1(u8 size, u8 count, IndexType type, ARM64Reg Rt, ARM64Reg Rn, + ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", __FUNCTION__); - _assert_msg_(DYNA_REC, type == INDEX_POST, "%s only supports post indexing!", __FUNCTION__); + _assert_msg_(DYNA_REC, !(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", + __FUNCTION__); + _assert_msg_(DYNA_REC, type == INDEX_POST, "%s only supports post indexing!", __FUNCTION__); - u32 opcode = 0; - if (count == 1) - opcode = 0b111; - else if (count == 2) - opcode = 0b1010; - else if (count == 3) - opcode = 0b0110; - else if (count == 4) - opcode = 0b0010; - EmitLoadStoreMultipleStructurePost(size, 1, opcode, Rt, Rn, Rm); + u32 opcode = 0; + if (count == 1) + opcode = 0b111; + else if (count == 2) + opcode = 0b1010; + else if (count == 3) + opcode = 0b0110; + else if (count == 4) + opcode = 0b0010; + EmitLoadStoreMultipleStructurePost(size, 1, opcode, Rt, Rn, Rm); } void ARM64FloatEmitter::ST1(u8 size, u8 count, ARM64Reg Rt, ARM64Reg Rn) { - _assert_msg_(DYNA_REC, !(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", __FUNCTION__); - u32 opcode = 0; - if (count == 1) - opcode = 0b111; - else if (count == 2) - opcode = 0b1010; - else if (count == 3) - opcode = 0b0110; - else if (count == 4) - opcode = 0b0010; - EmitLoadStoreMultipleStructure(size, 0, opcode, Rt, Rn); + _assert_msg_(DYNA_REC, !(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", + __FUNCTION__); + u32 opcode = 0; + if (count == 1) + opcode = 0b111; + else if (count == 2) + opcode = 0b1010; + else if (count == 3) + opcode = 0b0110; + else if (count == 4) + opcode = 0b0010; + EmitLoadStoreMultipleStructure(size, 0, opcode, Rt, Rn); } -void ARM64FloatEmitter::ST1(u8 size, u8 count, IndexType type, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm) +void ARM64FloatEmitter::ST1(u8 size, u8 count, IndexType type, ARM64Reg Rt, ARM64Reg Rn, + ARM64Reg Rm) { - _assert_msg_(DYNA_REC, !(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", __FUNCTION__); - _assert_msg_(DYNA_REC, type == INDEX_POST, "%s only supports post indexing!", __FUNCTION__); + _assert_msg_(DYNA_REC, !(count == 0 || count > 4), "%s must have a count of 1 to 4 registers!", + __FUNCTION__); + _assert_msg_(DYNA_REC, type == INDEX_POST, "%s only supports post indexing!", __FUNCTION__); - u32 opcode = 0; - if (count == 1) - opcode = 0b111; - else if (count == 2) - opcode = 0b1010; - else if (count == 3) - opcode = 0b0110; - else if (count == 4) - opcode = 0b0010; - EmitLoadStoreMultipleStructurePost(size, 0, opcode, Rt, Rn, Rm); + u32 opcode = 0; + if (count == 1) + opcode = 0b111; + else if (count == 2) + opcode = 0b1010; + else if (count == 3) + opcode = 0b0110; + else if (count == 4) + opcode = 0b0010; + EmitLoadStoreMultipleStructurePost(size, 0, opcode, Rt, Rn, Rm); } // Scalar - 1 Source void ARM64FloatEmitter::FMOV(ARM64Reg Rd, ARM64Reg Rn, bool top) { - if (IsScalar(Rd) && IsScalar(Rn)) - { - EmitScalar1Source(0, 0, IsDouble(Rd), 0, Rd, Rn); - } - else - { - _assert_msg_(DYNA_REC, !IsQuad(Rd) && !IsQuad(Rn), "FMOV can't move to/from quads"); - int rmode = 0; - int opcode = 6; - int sf = 0; - if (IsSingle(Rd) && !Is64Bit(Rn) && !top) - { - // GPR to scalar single - opcode |= 1; - } - else if (!Is64Bit(Rd) && IsSingle(Rn) && !top) - { - // Scalar single to GPR - defaults are correct - } - else - { - // TODO - _assert_msg_(DYNA_REC, 0, "FMOV: Unhandled case"); - } - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - Write32((sf << 31) | (0x1e2 << 20) | (rmode << 19) | (opcode << 16) | (Rn << 5) | Rd); - } + if (IsScalar(Rd) && IsScalar(Rn)) + { + EmitScalar1Source(0, 0, IsDouble(Rd), 0, Rd, Rn); + } + else + { + _assert_msg_(DYNA_REC, !IsQuad(Rd) && !IsQuad(Rn), "FMOV can't move to/from quads"); + int rmode = 0; + int opcode = 6; + int sf = 0; + if (IsSingle(Rd) && !Is64Bit(Rn) && !top) + { + // GPR to scalar single + opcode |= 1; + } + else if (!Is64Bit(Rd) && IsSingle(Rn) && !top) + { + // Scalar single to GPR - defaults are correct + } + else + { + // TODO + _assert_msg_(DYNA_REC, 0, "FMOV: Unhandled case"); + } + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Write32((sf << 31) | (0x1e2 << 20) | (rmode << 19) | (opcode << 16) | (Rn << 5) | Rd); + } } // Loadstore paired -void ARM64FloatEmitter::LDP(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm) +void ARM64FloatEmitter::LDP(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, + s32 imm) { - EncodeLoadStorePair(size, true, type, Rt, Rt2, Rn, imm); + EncodeLoadStorePair(size, true, type, Rt, Rt2, Rn, imm); } -void ARM64FloatEmitter::STP(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm) +void ARM64FloatEmitter::STP(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, + s32 imm) { - EncodeLoadStorePair(size, false, type, Rt, Rt2, Rn, imm); + EncodeLoadStorePair(size, false, type, Rt, Rt2, Rn, imm); } // Loadstore register offset void ARM64FloatEmitter::STR(u8 size, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) { - EncodeLoadStoreRegisterOffset(size, false, Rt, Rn, Rm); + EncodeLoadStoreRegisterOffset(size, false, Rt, Rn, Rm); } void ARM64FloatEmitter::LDR(u8 size, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm) { - EncodeLoadStoreRegisterOffset(size, true, Rt, Rn, Rm); + EncodeLoadStoreRegisterOffset(size, true, Rt, Rn, Rm); } void ARM64FloatEmitter::FABS(ARM64Reg Rd, ARM64Reg Rn) { - EmitScalar1Source(0, 0, IsDouble(Rd), 1, Rd, Rn); + EmitScalar1Source(0, 0, IsDouble(Rd), 1, Rd, Rn); } void ARM64FloatEmitter::FNEG(ARM64Reg Rd, ARM64Reg Rn) { - EmitScalar1Source(0, 0, IsDouble(Rd), 2, Rd, Rn); + EmitScalar1Source(0, 0, IsDouble(Rd), 2, Rd, Rn); } void ARM64FloatEmitter::FSQRT(ARM64Reg Rd, ARM64Reg Rn) { - EmitScalar1Source(0, 0, IsDouble(Rd), 3, Rd, Rn); + EmitScalar1Source(0, 0, IsDouble(Rd), 3, Rd, Rn); } - // Scalar - 2 Source void ARM64FloatEmitter::FADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitScalar2Source(0, 0, IsDouble(Rd), 2, Rd, Rn, Rm); + EmitScalar2Source(0, 0, IsDouble(Rd), 2, Rd, Rn, Rm); } void ARM64FloatEmitter::FMUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitScalar2Source(0, 0, IsDouble(Rd), 0, Rd, Rn, Rm); + EmitScalar2Source(0, 0, IsDouble(Rd), 0, Rd, Rn, Rm); } void ARM64FloatEmitter::FSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitScalar2Source(0, 0, IsDouble(Rd), 3, Rd, Rn, Rm); + EmitScalar2Source(0, 0, IsDouble(Rd), 3, Rd, Rn, Rm); } void ARM64FloatEmitter::FDIV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitScalar2Source(0, 0, IsDouble(Rd), 1, Rd, Rn, Rm); + EmitScalar2Source(0, 0, IsDouble(Rd), 1, Rd, Rn, Rm); } void ARM64FloatEmitter::FMAX(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitScalar2Source(0, 0, IsDouble(Rd), 4, Rd, Rn, Rm); + EmitScalar2Source(0, 0, IsDouble(Rd), 4, Rd, Rn, Rm); } void ARM64FloatEmitter::FMIN(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitScalar2Source(0, 0, IsDouble(Rd), 5, Rd, Rn, Rm); + EmitScalar2Source(0, 0, IsDouble(Rd), 5, Rd, Rn, Rm); } void ARM64FloatEmitter::FMAXNM(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitScalar2Source(0, 0, IsDouble(Rd), 6, Rd, Rn, Rm); + EmitScalar2Source(0, 0, IsDouble(Rd), 6, Rd, Rn, Rm); } void ARM64FloatEmitter::FMINNM(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitScalar2Source(0, 0, IsDouble(Rd), 7, Rd, Rn, Rm); + EmitScalar2Source(0, 0, IsDouble(Rd), 7, Rd, Rn, Rm); } void ARM64FloatEmitter::FNMUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitScalar2Source(0, 0, IsDouble(Rd), 8, Rd, Rn, Rm); + EmitScalar2Source(0, 0, IsDouble(Rd), 8, Rd, Rn, Rm); } void ARM64FloatEmitter::FMADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) { - EmitScalar3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 0); + EmitScalar3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 0); } void ARM64FloatEmitter::FMSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) { - EmitScalar3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 1); + EmitScalar3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 1); } void ARM64FloatEmitter::FNMADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) { - EmitScalar3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 2); + EmitScalar3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 2); } void ARM64FloatEmitter::FNMSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra) { - EmitScalar3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 3); + EmitScalar3Source(IsDouble(Rd), Rd, Rn, Rm, Ra, 3); } -void ARM64FloatEmitter::EmitScalar3Source(bool isDouble, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra, int opcode) +void ARM64FloatEmitter::EmitScalar3Source(bool isDouble, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, + ARM64Reg Ra, int opcode) { - int type = isDouble ? 1 : 0; - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - Rm = DecodeReg(Rm); - Ra = DecodeReg(Ra); - int o1 = opcode >> 1; - int o0 = opcode & 1; - m_emit->Write32((0x1F << 24) | (type << 22) | (o1 << 21) | (Rm << 16) | (o0 << 15) | (Ra << 10) | (Rn << 5) | Rd); + int type = isDouble ? 1 : 0; + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + Rm = DecodeReg(Rm); + Ra = DecodeReg(Ra); + int o1 = opcode >> 1; + int o0 = opcode & 1; + m_emit->Write32((0x1F << 24) | (type << 22) | (o1 << 21) | (Rm << 16) | (o0 << 15) | (Ra << 10) | + (Rn << 5) | Rd); } // Scalar floating point immediate void ARM64FloatEmitter::FMOV(ARM64Reg Rd, uint8_t imm8) { - EmitScalarImm(0, 0, 0, 0, Rd, imm8); + EmitScalarImm(0, 0, 0, 0, Rd, imm8); } // Vector void ARM64FloatEmitter::AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitThreeSame(0, 0, 3, Rd, Rn, Rm); + EmitThreeSame(0, 0, 3, Rd, Rn, Rm); } void ARM64FloatEmitter::BSL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitThreeSame(1, 1, 3, Rd, Rn, Rm); + EmitThreeSame(1, 1, 3, Rd, Rn, Rm); } void ARM64FloatEmitter::DUP(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index) { - u32 imm5 = 0; + u32 imm5 = 0; - if (size == 8) - { - imm5 = 1; - imm5 |= index << 1; - } - else if (size == 16) - { - imm5 = 2; - imm5 |= index << 2; - } - else if (size == 32) - { - imm5 = 4; - imm5 |= index << 3; - } - else if (size == 64) - { - imm5 = 8; - imm5 |= index << 4; - } + if (size == 8) + { + imm5 = 1; + imm5 |= index << 1; + } + else if (size == 16) + { + imm5 = 2; + imm5 |= index << 2; + } + else if (size == 32) + { + imm5 = 4; + imm5 |= index << 3; + } + else if (size == 64) + { + imm5 = 8; + imm5 |= index << 4; + } - EmitCopy(IsQuad(Rd), 0, imm5, 0, Rd, Rn); + EmitCopy(IsQuad(Rd), 0, imm5, 0, Rd, Rn); } void ARM64FloatEmitter::FABS(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 0, 2 | (size >> 6), 0xF, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 0, 2 | (size >> 6), 0xF, Rd, Rn); } void ARM64FloatEmitter::FADD(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitThreeSame(0, size >> 6, 0x1A, Rd, Rn, Rm); + EmitThreeSame(0, size >> 6, 0x1A, Rd, Rn, Rm); } void ARM64FloatEmitter::FMAX(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitThreeSame(0, size >> 6, 0b11110, Rd, Rn, Rm); + EmitThreeSame(0, size >> 6, 0b11110, Rd, Rn, Rm); } void ARM64FloatEmitter::FMLA(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitThreeSame(0, size >> 6, 0x19, Rd, Rn, Rm); + EmitThreeSame(0, size >> 6, 0x19, Rd, Rn, Rm); } void ARM64FloatEmitter::FMIN(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitThreeSame(0, 2 | size >> 6, 0b11110, Rd, Rn, Rm); + EmitThreeSame(0, 2 | size >> 6, 0b11110, Rd, Rn, Rm); } void ARM64FloatEmitter::FCVTL(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(false, 0, size >> 6, 0x17, Rd, Rn); + Emit2RegMisc(false, 0, size >> 6, 0x17, Rd, Rn); } void ARM64FloatEmitter::FCVTL2(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(true, 0, size >> 6, 0x17, Rd, Rn); + Emit2RegMisc(true, 0, size >> 6, 0x17, Rd, Rn); } void ARM64FloatEmitter::FCVTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 0, dest_size >> 5, 0x16, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 0, dest_size >> 5, 0x16, Rd, Rn); } void ARM64FloatEmitter::FCVTZS(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 0, 2 | (size >> 6), 0x1B, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 0, 2 | (size >> 6), 0x1B, Rd, Rn); } void ARM64FloatEmitter::FCVTZU(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 1, 2 | (size >> 6), 0x1B, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 1, 2 | (size >> 6), 0x1B, Rd, Rn); } void ARM64FloatEmitter::FDIV(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitThreeSame(1, size >> 6, 0x1F, Rd, Rn, Rm); + EmitThreeSame(1, size >> 6, 0x1F, Rd, Rn, Rm); } void ARM64FloatEmitter::FMUL(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitThreeSame(1, size >> 6, 0x1B, Rd, Rn, Rm); + EmitThreeSame(1, size >> 6, 0x1B, Rd, Rn, Rm); } void ARM64FloatEmitter::FNEG(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 1, 2 | (size >> 6), 0xF, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 1, 2 | (size >> 6), 0xF, Rd, Rn); } void ARM64FloatEmitter::FRSQRTE(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 1, 2 | (size >> 6), 0x1D, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 1, 2 | (size >> 6), 0x1D, Rd, Rn); } void ARM64FloatEmitter::FSUB(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitThreeSame(0, 2 | (size >> 6), 0x1A, Rd, Rn, Rm); + EmitThreeSame(0, 2 | (size >> 6), 0x1A, Rd, Rn, Rm); } void ARM64FloatEmitter::FMLS(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitThreeSame(0, 2 | (size >> 6), 0x19, Rd, Rn, Rm); + EmitThreeSame(0, 2 | (size >> 6), 0x19, Rd, Rn, Rm); } void ARM64FloatEmitter::NOT(ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 1, 0, 5, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 1, 0, 5, Rd, Rn); } void ARM64FloatEmitter::ORR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitThreeSame(0, 2, 3, Rd, Rn, Rm); + EmitThreeSame(0, 2, 3, Rd, Rn, Rm); } void ARM64FloatEmitter::REV16(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 0, size >> 4, 1, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 0, size >> 4, 1, Rd, Rn); } void ARM64FloatEmitter::REV32(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 1, size >> 4, 0, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 1, size >> 4, 0, Rd, Rn); } void ARM64FloatEmitter::REV64(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 0, size >> 4, 0, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 0, size >> 4, 0, Rd, Rn); } void ARM64FloatEmitter::SCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 0, size >> 6, 0x1D, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 0, size >> 6, 0x1D, Rd, Rn); } void ARM64FloatEmitter::UCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 1, size >> 6, 0x1D, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 1, size >> 6, 0x1D, Rd, Rn); } void ARM64FloatEmitter::SCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn, int scale) { - int imm = size * 2 - scale; - EmitShiftImm(IsQuad(Rd), 0, imm >> 3, imm & 7, 0x1C, Rd, Rn); + int imm = size * 2 - scale; + EmitShiftImm(IsQuad(Rd), 0, imm >> 3, imm & 7, 0x1C, Rd, Rn); } void ARM64FloatEmitter::UCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn, int scale) { - int imm = size * 2 - scale; - EmitShiftImm(IsQuad(Rd), 1, imm >> 3, imm & 7, 0x1C, Rd, Rn); + int imm = size * 2 - scale; + EmitShiftImm(IsQuad(Rd), 1, imm >> 3, imm & 7, 0x1C, Rd, Rn); } void ARM64FloatEmitter::SQXTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(false, 0, dest_size >> 4, 0b10100, Rd, Rn); + Emit2RegMisc(false, 0, dest_size >> 4, 0b10100, Rd, Rn); } void ARM64FloatEmitter::SQXTN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(true, 0, dest_size >> 4, 0b10100, Rd, Rn); + Emit2RegMisc(true, 0, dest_size >> 4, 0b10100, Rd, Rn); } void ARM64FloatEmitter::UQXTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(false, 1, dest_size >> 4, 0b10100, Rd, Rn); + Emit2RegMisc(false, 1, dest_size >> 4, 0b10100, Rd, Rn); } void ARM64FloatEmitter::UQXTN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(true, 1, dest_size >> 4, 0b10100, Rd, Rn); + Emit2RegMisc(true, 1, dest_size >> 4, 0b10100, Rd, Rn); } void ARM64FloatEmitter::XTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(false, 0, dest_size >> 4, 0b10010, Rd, Rn); + Emit2RegMisc(false, 0, dest_size >> 4, 0b10010, Rd, Rn); } void ARM64FloatEmitter::XTN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(true, 0, dest_size >> 4, 0b10010, Rd, Rn); + Emit2RegMisc(true, 0, dest_size >> 4, 0b10010, Rd, Rn); } // Move void ARM64FloatEmitter::DUP(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - u32 imm5 = 0; + u32 imm5 = 0; - if (size == 8) - imm5 = 1; - else if (size == 16) - imm5 = 2; - else if (size == 32) - imm5 = 4; - else if (size == 64) - imm5 = 8; - - EmitCopy(IsQuad(Rd), 0, imm5, 1, Rd, Rn); + if (size == 8) + imm5 = 1; + else if (size == 16) + imm5 = 2; + else if (size == 32) + imm5 = 4; + else if (size == 64) + imm5 = 8; + EmitCopy(IsQuad(Rd), 0, imm5, 1, Rd, Rn); } void ARM64FloatEmitter::INS(u8 size, ARM64Reg Rd, u8 index, ARM64Reg Rn) { - u32 imm5 = 0; + u32 imm5 = 0; - if (size == 8) - { - imm5 = 1; - imm5 |= index << 1; - } - else if (size == 16) - { - imm5 = 2; - imm5 |= index << 2; - } - else if (size == 32) - { - imm5 = 4; - imm5 |= index << 3; - } - else if (size == 64) - { - imm5 = 8; - imm5 |= index << 4; - } + if (size == 8) + { + imm5 = 1; + imm5 |= index << 1; + } + else if (size == 16) + { + imm5 = 2; + imm5 |= index << 2; + } + else if (size == 32) + { + imm5 = 4; + imm5 |= index << 3; + } + else if (size == 64) + { + imm5 = 8; + imm5 |= index << 4; + } - EmitCopy(1, 0, imm5, 3, Rd, Rn); + EmitCopy(1, 0, imm5, 3, Rd, Rn); } void ARM64FloatEmitter::INS(u8 size, ARM64Reg Rd, u8 index1, ARM64Reg Rn, u8 index2) { - u32 imm5 = 0, imm4 = 0; + u32 imm5 = 0, imm4 = 0; - if (size == 8) - { - imm5 = 1; - imm5 |= index1 << 1; - imm4 = index2; - } - else if (size == 16) - { - imm5 = 2; - imm5 |= index1 << 2; - imm4 = index2 << 1; - } - else if (size == 32) - { - imm5 = 4; - imm5 |= index1 << 3; - imm4 = index2 << 2; - } - else if (size == 64) - { - imm5 = 8; - imm5 |= index1 << 4; - imm4 = index2 << 3; - } + if (size == 8) + { + imm5 = 1; + imm5 |= index1 << 1; + imm4 = index2; + } + else if (size == 16) + { + imm5 = 2; + imm5 |= index1 << 2; + imm4 = index2 << 1; + } + else if (size == 32) + { + imm5 = 4; + imm5 |= index1 << 3; + imm4 = index2 << 2; + } + else if (size == 64) + { + imm5 = 8; + imm5 |= index1 << 4; + imm4 = index2 << 3; + } - EmitCopy(1, 1, imm5, imm4, Rd, Rn); + EmitCopy(1, 1, imm5, imm4, Rd, Rn); } void ARM64FloatEmitter::UMOV(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index) { - bool b64Bit = Is64Bit(Rd); - _assert_msg_(DYNA_REC, Rd < SP, "%s destination must be a GPR!", __FUNCTION__); - _assert_msg_(DYNA_REC, !(b64Bit && size != 64), "%s must have a size of 64 when destination is 64bit!", __FUNCTION__); - u32 imm5 = 0; + bool b64Bit = Is64Bit(Rd); + _assert_msg_(DYNA_REC, Rd < SP, "%s destination must be a GPR!", __FUNCTION__); + _assert_msg_(DYNA_REC, !(b64Bit && size != 64), + "%s must have a size of 64 when destination is 64bit!", __FUNCTION__); + u32 imm5 = 0; - if (size == 8) - { - imm5 = 1; - imm5 |= index << 1; - } - else if (size == 16) - { - imm5 = 2; - imm5 |= index << 2; - } - else if (size == 32) - { - imm5 = 4; - imm5 |= index << 3; - } - else if (size == 64) - { - imm5 = 8; - imm5 |= index << 4; - } + if (size == 8) + { + imm5 = 1; + imm5 |= index << 1; + } + else if (size == 16) + { + imm5 = 2; + imm5 |= index << 2; + } + else if (size == 32) + { + imm5 = 4; + imm5 |= index << 3; + } + else if (size == 64) + { + imm5 = 8; + imm5 |= index << 4; + } - EmitCopy(b64Bit, 0, imm5, 7, Rd, Rn); + EmitCopy(b64Bit, 0, imm5, 7, Rd, Rn); } void ARM64FloatEmitter::SMOV(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index) { - bool b64Bit = Is64Bit(Rd); - _assert_msg_(DYNA_REC, Rd < SP, "%s destination must be a GPR!", __FUNCTION__); - _assert_msg_(DYNA_REC, size != 64, "%s doesn't support 64bit destination. Use UMOV!", __FUNCTION__); - u32 imm5 = 0; + bool b64Bit = Is64Bit(Rd); + _assert_msg_(DYNA_REC, Rd < SP, "%s destination must be a GPR!", __FUNCTION__); + _assert_msg_(DYNA_REC, size != 64, "%s doesn't support 64bit destination. Use UMOV!", + __FUNCTION__); + u32 imm5 = 0; - if (size == 8) - { - imm5 = 1; - imm5 |= index << 1; - } - else if (size == 16) - { - imm5 = 2; - imm5 |= index << 2; - } - else if (size == 32) - { - imm5 = 4; - imm5 |= index << 3; - } + if (size == 8) + { + imm5 = 1; + imm5 |= index << 1; + } + else if (size == 16) + { + imm5 = 2; + imm5 |= index << 2; + } + else if (size == 32) + { + imm5 = 4; + imm5 |= index << 3; + } - EmitCopy(b64Bit, 0, imm5, 5, Rd, Rn); + EmitCopy(b64Bit, 0, imm5, 5, Rd, Rn); } // One source void ARM64FloatEmitter::FCVT(u8 size_to, u8 size_from, ARM64Reg Rd, ARM64Reg Rn) { - u32 dst_encoding = 0; - u32 src_encoding = 0; + u32 dst_encoding = 0; + u32 src_encoding = 0; - if (size_to == 16) - dst_encoding = 3; - else if (size_to == 32) - dst_encoding = 0; - else if (size_to == 64) - dst_encoding = 1; + if (size_to == 16) + dst_encoding = 3; + else if (size_to == 32) + dst_encoding = 0; + else if (size_to == 64) + dst_encoding = 1; - if (size_from == 16) - src_encoding = 3; - else if (size_from == 32) - src_encoding = 0; - else if (size_from == 64) - src_encoding = 1; + if (size_from == 16) + src_encoding = 3; + else if (size_from == 32) + src_encoding = 0; + else if (size_from == 64) + src_encoding = 1; - Emit1Source(0, 0, src_encoding, 4 | dst_encoding, Rd, Rn); + Emit1Source(0, 0, src_encoding, 4 | dst_encoding, Rd, Rn); } void ARM64FloatEmitter::SCVTF(ARM64Reg Rd, ARM64Reg Rn) { - if (IsScalar(Rn)) - { - // Source is in FP register (like destination!). We must use a vector encoding. - bool sign = false; - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - int sz = IsDouble(Rn); - Write32((0x5e << 24) | (sign << 29) | (sz << 22) | (0x876 << 10) | (Rn << 5) | Rd); - } - else - { - bool sf = Is64Bit(Rn); - u32 type = 0; - if (IsDouble(Rd)) - type = 1; - EmitConversion(sf, 0, type, 0, 2, Rd, Rn); - } + if (IsScalar(Rn)) + { + // Source is in FP register (like destination!). We must use a vector encoding. + bool sign = false; + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + int sz = IsDouble(Rn); + Write32((0x5e << 24) | (sign << 29) | (sz << 22) | (0x876 << 10) | (Rn << 5) | Rd); + } + else + { + bool sf = Is64Bit(Rn); + u32 type = 0; + if (IsDouble(Rd)) + type = 1; + EmitConversion(sf, 0, type, 0, 2, Rd, Rn); + } } void ARM64FloatEmitter::UCVTF(ARM64Reg Rd, ARM64Reg Rn) { - if (IsScalar(Rn)) - { - // Source is in FP register (like destination!). We must use a vector encoding. - bool sign = true; - Rd = DecodeReg(Rd); - Rn = DecodeReg(Rn); - int sz = IsDouble(Rn); - Write32((0x5e << 24) | (sign << 29) | (sz << 22) | (0x876 << 10) | (Rn << 5) | Rd); - } - else - { - bool sf = Is64Bit(Rn); - u32 type = 0; - if (IsDouble(Rd)) - type = 1; + if (IsScalar(Rn)) + { + // Source is in FP register (like destination!). We must use a vector encoding. + bool sign = true; + Rd = DecodeReg(Rd); + Rn = DecodeReg(Rn); + int sz = IsDouble(Rn); + Write32((0x5e << 24) | (sign << 29) | (sz << 22) | (0x876 << 10) | (Rn << 5) | Rd); + } + else + { + bool sf = Is64Bit(Rn); + u32 type = 0; + if (IsDouble(Rd)) + type = 1; - EmitConversion(sf, 0, type, 0, 3, Rd, Rn); - } + EmitConversion(sf, 0, type, 0, 3, Rd, Rn); + } } void ARM64FloatEmitter::SCVTF(ARM64Reg Rd, ARM64Reg Rn, int scale) { - bool sf = Is64Bit(Rn); - u32 type = 0; - if (IsDouble(Rd)) - type = 1; + bool sf = Is64Bit(Rn); + u32 type = 0; + if (IsDouble(Rd)) + type = 1; - EmitConversion2(sf, 0, false, type, 0, 2, 64 - scale, Rd, Rn); + EmitConversion2(sf, 0, false, type, 0, 2, 64 - scale, Rd, Rn); } void ARM64FloatEmitter::UCVTF(ARM64Reg Rd, ARM64Reg Rn, int scale) { - bool sf = Is64Bit(Rn); - u32 type = 0; - if (IsDouble(Rd)) - type = 1; + bool sf = Is64Bit(Rn); + u32 type = 0; + if (IsDouble(Rd)) + type = 1; - EmitConversion2(sf, 0, false, type, 0, 3, 64 - scale, Rd, Rn); + EmitConversion2(sf, 0, false, type, 0, 3, 64 - scale, Rd, Rn); } void ARM64FloatEmitter::FCMP(ARM64Reg Rn, ARM64Reg Rm) { - EmitCompare(0, 0, 0, 0, Rn, Rm); + EmitCompare(0, 0, 0, 0, Rn, Rm); } void ARM64FloatEmitter::FCMP(ARM64Reg Rn) { - EmitCompare(0, 0, 0, 8, Rn, (ARM64Reg)0); + EmitCompare(0, 0, 0, 8, Rn, (ARM64Reg)0); } void ARM64FloatEmitter::FCMPE(ARM64Reg Rn, ARM64Reg Rm) { - EmitCompare(0, 0, 0, 0x10, Rn, Rm); + EmitCompare(0, 0, 0, 0x10, Rn, Rm); } void ARM64FloatEmitter::FCMPE(ARM64Reg Rn) { - EmitCompare(0, 0, 0, 0x18, Rn, (ARM64Reg)0); + EmitCompare(0, 0, 0, 0x18, Rn, (ARM64Reg)0); } void ARM64FloatEmitter::FCMEQ(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitThreeSame(0, size >> 6, 0x1C, Rd, Rn, Rm); + EmitThreeSame(0, size >> 6, 0x1C, Rd, Rn, Rm); } void ARM64FloatEmitter::FCMEQ(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 0, 2 | (size >> 6), 0xD, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 0, 2 | (size >> 6), 0xD, Rd, Rn); } void ARM64FloatEmitter::FCMGE(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitThreeSame(1, size >> 6, 0x1C, Rd, Rn, Rm); + EmitThreeSame(1, size >> 6, 0x1C, Rd, Rn, Rm); } void ARM64FloatEmitter::FCMGE(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 1, 2 | (size >> 6), 0x0C, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 1, 2 | (size >> 6), 0x0C, Rd, Rn); } void ARM64FloatEmitter::FCMGT(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitThreeSame(1, 2 | (size >> 6), 0x1C, Rd, Rn, Rm); + EmitThreeSame(1, 2 | (size >> 6), 0x1C, Rd, Rn, Rm); } void ARM64FloatEmitter::FCMGT(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 0, 2 | (size >> 6), 0x0C, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 0, 2 | (size >> 6), 0x0C, Rd, Rn); } void ARM64FloatEmitter::FCMLE(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 1, 2 | (size >> 6), 0xD, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 1, 2 | (size >> 6), 0xD, Rd, Rn); } void ARM64FloatEmitter::FCMLT(u8 size, ARM64Reg Rd, ARM64Reg Rn) { - Emit2RegMisc(IsQuad(Rd), 0, 2 | (size >> 6), 0xE, Rd, Rn); + Emit2RegMisc(IsQuad(Rd), 0, 2 | (size >> 6), 0xE, Rd, Rn); } void ARM64FloatEmitter::FCSEL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond) { - EmitCondSelect(0, 0, cond, Rd, Rn, Rm); + EmitCondSelect(0, 0, cond, Rd, Rn, Rm); } // Permute void ARM64FloatEmitter::UZP1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitPermute(size, 0b001, Rd, Rn, Rm); + EmitPermute(size, 0b001, Rd, Rn, Rm); } void ARM64FloatEmitter::TRN1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitPermute(size, 0b010, Rd, Rn, Rm); + EmitPermute(size, 0b010, Rd, Rn, Rm); } void ARM64FloatEmitter::ZIP1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitPermute(size, 0b011, Rd, Rn, Rm); + EmitPermute(size, 0b011, Rd, Rn, Rm); } void ARM64FloatEmitter::UZP2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitPermute(size, 0b101, Rd, Rn, Rm); + EmitPermute(size, 0b101, Rd, Rn, Rm); } void ARM64FloatEmitter::TRN2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitPermute(size, 0b110, Rd, Rn, Rm); + EmitPermute(size, 0b110, Rd, Rn, Rm); } void ARM64FloatEmitter::ZIP2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { - EmitPermute(size, 0b111, Rd, Rn, Rm); + EmitPermute(size, 0b111, Rd, Rn, Rm); } // Shift by immediate void ARM64FloatEmitter::SSHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) { - SSHLL(src_size, Rd, Rn, shift, false); + SSHLL(src_size, Rd, Rn, shift, false); } void ARM64FloatEmitter::SSHLL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) { - SSHLL(src_size, Rd, Rn, shift, true); + SSHLL(src_size, Rd, Rn, shift, true); } void ARM64FloatEmitter::SHRN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) { - SHRN(dest_size, Rd, Rn, shift, false); + SHRN(dest_size, Rd, Rn, shift, false); } void ARM64FloatEmitter::SHRN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) { - SHRN(dest_size, Rd, Rn, shift, true); + SHRN(dest_size, Rd, Rn, shift, true); } void ARM64FloatEmitter::USHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) { - USHLL(src_size, Rd, Rn, shift, false); + USHLL(src_size, Rd, Rn, shift, false); } void ARM64FloatEmitter::USHLL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift) { - USHLL(src_size, Rd, Rn, shift, true); + USHLL(src_size, Rd, Rn, shift, true); } void ARM64FloatEmitter::SXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn) { - SXTL(src_size, Rd, Rn, false); + SXTL(src_size, Rd, Rn, false); } void ARM64FloatEmitter::SXTL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn) { - SXTL(src_size, Rd, Rn, true); + SXTL(src_size, Rd, Rn, true); } void ARM64FloatEmitter::UXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn) { - UXTL(src_size, Rd, Rn, false); + UXTL(src_size, Rd, Rn, false); } void ARM64FloatEmitter::UXTL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn) { - UXTL(src_size, Rd, Rn, true); + UXTL(src_size, Rd, Rn, true); } void ARM64FloatEmitter::SSHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper) { - _assert_msg_(DYNA_REC, shift < src_size, "%s shift amount must less than the element size!", __FUNCTION__); - u32 immh = 0; - u32 immb = shift & 0xFFF; + _assert_msg_(DYNA_REC, shift < src_size, "%s shift amount must less than the element size!", + __FUNCTION__); + u32 immh = 0; + u32 immb = shift & 0xFFF; - if (src_size == 8) - { - immh = 1; - } - else if (src_size == 16) - { - immh = 2 | ((shift >> 3) & 1); - } - else if (src_size == 32) - { - immh = 4 | ((shift >> 3) & 3);; - } - EmitShiftImm(upper, 0, immh, immb, 0b10100, Rd, Rn); + if (src_size == 8) + { + immh = 1; + } + else if (src_size == 16) + { + immh = 2 | ((shift >> 3) & 1); + } + else if (src_size == 32) + { + immh = 4 | ((shift >> 3) & 3); + ; + } + EmitShiftImm(upper, 0, immh, immb, 0b10100, Rd, Rn); } void ARM64FloatEmitter::USHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper) { - _assert_msg_(DYNA_REC, shift < src_size, "%s shift amount must less than the element size!", __FUNCTION__); - u32 immh = 0; - u32 immb = shift & 0xFFF; + _assert_msg_(DYNA_REC, shift < src_size, "%s shift amount must less than the element size!", + __FUNCTION__); + u32 immh = 0; + u32 immb = shift & 0xFFF; - if (src_size == 8) - { - immh = 1; - } - else if (src_size == 16) - { - immh = 2 | ((shift >> 3) & 1); - } - else if (src_size == 32) - { - immh = 4 | ((shift >> 3) & 3);; - } - EmitShiftImm(upper, 1, immh, immb, 0b10100, Rd, Rn); + if (src_size == 8) + { + immh = 1; + } + else if (src_size == 16) + { + immh = 2 | ((shift >> 3) & 1); + } + else if (src_size == 32) + { + immh = 4 | ((shift >> 3) & 3); + ; + } + EmitShiftImm(upper, 1, immh, immb, 0b10100, Rd, Rn); } void ARM64FloatEmitter::SHRN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper) { - _assert_msg_(DYNA_REC, shift < dest_size, "%s shift amount must less than the element size!", __FUNCTION__); - u32 immh = 0; - u32 immb = shift & 0xFFF; + _assert_msg_(DYNA_REC, shift < dest_size, "%s shift amount must less than the element size!", + __FUNCTION__); + u32 immh = 0; + u32 immb = shift & 0xFFF; - if (dest_size == 8) - { - immh = 1; - } - else if (dest_size == 16) - { - immh = 2 | ((shift >> 3) & 1); - } - else if (dest_size == 32) - { - immh = 4 | ((shift >> 3) & 3);; - } - EmitShiftImm(upper, 1, immh, immb, 0b10000, Rd, Rn); + if (dest_size == 8) + { + immh = 1; + } + else if (dest_size == 16) + { + immh = 2 | ((shift >> 3) & 1); + } + else if (dest_size == 32) + { + immh = 4 | ((shift >> 3) & 3); + ; + } + EmitShiftImm(upper, 1, immh, immb, 0b10000, Rd, Rn); } void ARM64FloatEmitter::SXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, bool upper) { - SSHLL(src_size, Rd, Rn, 0, upper); + SSHLL(src_size, Rd, Rn, 0, upper); } void ARM64FloatEmitter::UXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, bool upper) { - USHLL(src_size, Rd, Rn, 0, upper); + USHLL(src_size, Rd, Rn, 0, upper); } // vector x indexed element void ARM64FloatEmitter::FMUL(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u8 index) { - _assert_msg_(DYNA_REC, size == 32 || size == 64, "%s only supports 32bit or 64bit size!", __FUNCTION__); + _assert_msg_(DYNA_REC, size == 32 || size == 64, "%s only supports 32bit or 64bit size!", + __FUNCTION__); - bool L = false; - bool H = false; - if (size == 32) - { - L = index & 1; - H = (index >> 1) & 1; - } - else if (size == 64) - { - H = index == 1; - } + bool L = false; + bool H = false; + if (size == 32) + { + L = index & 1; + H = (index >> 1) & 1; + } + else if (size == 64) + { + H = index == 1; + } - EmitVectorxElement(0, 2 | (size >> 6), L, 0x9, H, Rd, Rn, Rm); + EmitVectorxElement(0, 2 | (size >> 6), L, 0x9, H, Rd, Rn, Rm); } void ARM64FloatEmitter::FMLA(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u8 index) { - _assert_msg_(DYNA_REC, size == 32 || size == 64, "%s only supports 32bit or 64bit size!", __FUNCTION__); + _assert_msg_(DYNA_REC, size == 32 || size == 64, "%s only supports 32bit or 64bit size!", + __FUNCTION__); - bool L = false; - bool H = false; - if (size == 32) - { - L = index & 1; - H = (index >> 1) & 1; - } - else if (size == 64) - { - H = index == 1; - } + bool L = false; + bool H = false; + if (size == 32) + { + L = index & 1; + H = (index >> 1) & 1; + } + else if (size == 64) + { + H = index == 1; + } - EmitVectorxElement(0, 2 | (size >> 6), L, 1, H, Rd, Rn, Rm); + EmitVectorxElement(0, 2 | (size >> 6), L, 1, H, Rd, Rn, Rm); } // Modified Immediate void ARM64FloatEmitter::MOVI(u8 size, ARM64Reg Rd, u64 imm, u8 shift) { - bool Q = IsQuad(Rd); - u8 cmode = 0; - u8 op = 0; - u8 abcdefgh = imm & 0xFF; - if (size == 8) - { - _assert_msg_(DYNA_REC, shift == 0, "%s(size8) doesn't support shift!", __FUNCTION__); - _assert_msg_(DYNA_REC, !(imm & ~0xFFULL), "%s(size8) only supports 8bit values!", __FUNCTION__); - } - else if (size == 16) - { - _assert_msg_(DYNA_REC, shift == 0 || shift == 8, "%s(size16) only supports shift of {0, 8}!", __FUNCTION__); - _assert_msg_(DYNA_REC, !(imm & ~0xFFULL), "%s(size16) only supports 8bit values!", __FUNCTION__); + bool Q = IsQuad(Rd); + u8 cmode = 0; + u8 op = 0; + u8 abcdefgh = imm & 0xFF; + if (size == 8) + { + _assert_msg_(DYNA_REC, shift == 0, "%s(size8) doesn't support shift!", __FUNCTION__); + _assert_msg_(DYNA_REC, !(imm & ~0xFFULL), "%s(size8) only supports 8bit values!", __FUNCTION__); + } + else if (size == 16) + { + _assert_msg_(DYNA_REC, shift == 0 || shift == 8, "%s(size16) only supports shift of {0, 8}!", + __FUNCTION__); + _assert_msg_(DYNA_REC, !(imm & ~0xFFULL), "%s(size16) only supports 8bit values!", + __FUNCTION__); - if (shift == 8) - cmode |= 2; - } - else if (size == 32) - { - _assert_msg_(DYNA_REC, - shift == 0 || shift == 8 || shift == 16 || shift == 24, - "%s(size32) only supports shift of {0, 8, 16, 24}!", __FUNCTION__); - // XXX: Implement support for MOVI - shifting ones variant - _assert_msg_(DYNA_REC, !(imm & ~0xFFULL), "%s(size32) only supports 8bit values!", __FUNCTION__); - switch (shift) - { - case 8: cmode |= 2; break; - case 16: cmode |= 4; break; - case 24: cmode |= 6; break; - default: break; - } - } - else // 64 - { - _assert_msg_(DYNA_REC, shift == 0, "%s(size64) doesn't support shift!", __FUNCTION__); + if (shift == 8) + cmode |= 2; + } + else if (size == 32) + { + _assert_msg_(DYNA_REC, shift == 0 || shift == 8 || shift == 16 || shift == 24, + "%s(size32) only supports shift of {0, 8, 16, 24}!", __FUNCTION__); + // XXX: Implement support for MOVI - shifting ones variant + _assert_msg_(DYNA_REC, !(imm & ~0xFFULL), "%s(size32) only supports 8bit values!", + __FUNCTION__); + switch (shift) + { + case 8: + cmode |= 2; + break; + case 16: + cmode |= 4; + break; + case 24: + cmode |= 6; + break; + default: + break; + } + } + else // 64 + { + _assert_msg_(DYNA_REC, shift == 0, "%s(size64) doesn't support shift!", __FUNCTION__); - op = 1; - cmode = 0xE; - abcdefgh = 0; - for (int i = 0; i < 8; ++i) - { - u8 tmp = (imm >> (i << 3)) & 0xFF; - _assert_msg_(DYNA_REC, tmp == 0xFF || tmp == 0, "%s(size64) Invalid immediate!", __FUNCTION__); - if (tmp == 0xFF) - abcdefgh |= (1 << i); - } - } - EncodeModImm(Q, op, cmode, 0, Rd, abcdefgh); + op = 1; + cmode = 0xE; + abcdefgh = 0; + for (int i = 0; i < 8; ++i) + { + u8 tmp = (imm >> (i << 3)) & 0xFF; + _assert_msg_(DYNA_REC, tmp == 0xFF || tmp == 0, "%s(size64) Invalid immediate!", + __FUNCTION__); + if (tmp == 0xFF) + abcdefgh |= (1 << i); + } + } + EncodeModImm(Q, op, cmode, 0, Rd, abcdefgh); } void ARM64FloatEmitter::BIC(u8 size, ARM64Reg Rd, u8 imm, u8 shift) { - bool Q = IsQuad(Rd); - u8 cmode = 1; - u8 op = 1; - if (size == 16) - { - _assert_msg_(DYNA_REC, shift == 0 || shift == 8, "%s(size16) only supports shift of {0, 8}!", __FUNCTION__); + bool Q = IsQuad(Rd); + u8 cmode = 1; + u8 op = 1; + if (size == 16) + { + _assert_msg_(DYNA_REC, shift == 0 || shift == 8, "%s(size16) only supports shift of {0, 8}!", + __FUNCTION__); - if (shift == 8) - cmode |= 2; - } - else if (size == 32) - { - _assert_msg_(DYNA_REC, - shift == 0 || shift == 8 || shift == 16 || shift == 24, - "%s(size32) only supports shift of {0, 8, 16, 24}!", __FUNCTION__); - // XXX: Implement support for MOVI - shifting ones variant - switch (shift) - { - case 8: cmode |= 2; break; - case 16: cmode |= 4; break; - case 24: cmode |= 6; break; - default: break; - } - } - else - _assert_msg_(DYNA_REC, false, "%s only supports size of {16, 32}!", __FUNCTION__); - EncodeModImm(Q, op, cmode, 0, Rd, imm); + if (shift == 8) + cmode |= 2; + } + else if (size == 32) + { + _assert_msg_(DYNA_REC, shift == 0 || shift == 8 || shift == 16 || shift == 24, + "%s(size32) only supports shift of {0, 8, 16, 24}!", __FUNCTION__); + // XXX: Implement support for MOVI - shifting ones variant + switch (shift) + { + case 8: + cmode |= 2; + break; + case 16: + cmode |= 4; + break; + case 24: + cmode |= 6; + break; + default: + break; + } + } + else + _assert_msg_(DYNA_REC, false, "%s only supports size of {16, 32}!", __FUNCTION__); + EncodeModImm(Q, op, cmode, 0, Rd, imm); } void ARM64FloatEmitter::ABI_PushRegisters(BitSet32 registers, ARM64Reg tmp) { - bool bundled_loadstore = false; + bool bundled_loadstore = false; - for (int i = 0; i < 32; ++i) - { - if (!registers[i]) - continue; + for (int i = 0; i < 32; ++i) + { + if (!registers[i]) + continue; - int count = 0; - while (++count < 4 && (i + count) < 32 && registers[i + count]) {} - if (count > 1) - { - bundled_loadstore = true; - break; - } - } + int count = 0; + while (++count < 4 && (i + count) < 32 && registers[i + count]) + { + } + if (count > 1) + { + bundled_loadstore = true; + break; + } + } - if (bundled_loadstore && tmp != INVALID_REG) - { - int num_regs = registers.Count(); - m_emit->SUB(SP, SP, num_regs * 16); - m_emit->ADD(tmp, SP, 0); - std::vector island_regs; - for (int i = 0; i < 32; ++i) - { - if (!registers[i]) - continue; + if (bundled_loadstore && tmp != INVALID_REG) + { + int num_regs = registers.Count(); + m_emit->SUB(SP, SP, num_regs * 16); + m_emit->ADD(tmp, SP, 0); + std::vector island_regs; + for (int i = 0; i < 32; ++i) + { + if (!registers[i]) + continue; - int count = 0; + int count = 0; - // 0 = true - // 1 < 4 && registers[i + 1] true! - // 2 < 4 && registers[i + 2] true! - // 3 < 4 && registers[i + 3] true! - // 4 < 4 && registers[i + 4] false! - while (++count < 4 && (i + count) < 32 && registers[i + count]) {} + // 0 = true + // 1 < 4 && registers[i + 1] true! + // 2 < 4 && registers[i + 2] true! + // 3 < 4 && registers[i + 3] true! + // 4 < 4 && registers[i + 4] false! + while (++count < 4 && (i + count) < 32 && registers[i + count]) + { + } - if (count == 1) - island_regs.push_back((ARM64Reg)(Q0 + i)); - else - ST1(64, count, INDEX_POST, (ARM64Reg)(Q0 + i), tmp); + if (count == 1) + island_regs.push_back((ARM64Reg)(Q0 + i)); + else + ST1(64, count, INDEX_POST, (ARM64Reg)(Q0 + i), tmp); - i += count - 1; - } + i += count - 1; + } - // Handle island registers - std::vector pair_regs; - for (auto& it : island_regs) - { - pair_regs.push_back(it); - if (pair_regs.size() == 2) - { - STP(128, INDEX_POST, pair_regs[0], pair_regs[1], tmp, 32); - pair_regs.clear(); - } - } - if (pair_regs.size()) - STR(128, INDEX_POST, pair_regs[0], tmp, 16); - } - else - { - std::vector pair_regs; - for (auto it : registers) - { - pair_regs.push_back((ARM64Reg)(Q0 + it)); - if (pair_regs.size() == 2) - { - STP(128, INDEX_PRE, pair_regs[0], pair_regs[1], SP, -32); - pair_regs.clear(); - } - } - if (pair_regs.size()) - STR(128, INDEX_PRE, pair_regs[0], SP, -16); - } + // Handle island registers + std::vector pair_regs; + for (auto& it : island_regs) + { + pair_regs.push_back(it); + if (pair_regs.size() == 2) + { + STP(128, INDEX_POST, pair_regs[0], pair_regs[1], tmp, 32); + pair_regs.clear(); + } + } + if (pair_regs.size()) + STR(128, INDEX_POST, pair_regs[0], tmp, 16); + } + else + { + std::vector pair_regs; + for (auto it : registers) + { + pair_regs.push_back((ARM64Reg)(Q0 + it)); + if (pair_regs.size() == 2) + { + STP(128, INDEX_PRE, pair_regs[0], pair_regs[1], SP, -32); + pair_regs.clear(); + } + } + if (pair_regs.size()) + STR(128, INDEX_PRE, pair_regs[0], SP, -16); + } } void ARM64FloatEmitter::ABI_PopRegisters(BitSet32 registers, ARM64Reg tmp) { - bool bundled_loadstore = false; - int num_regs = registers.Count(); + bool bundled_loadstore = false; + int num_regs = registers.Count(); - for (int i = 0; i < 32; ++i) - { - if (!registers[i]) - continue; + for (int i = 0; i < 32; ++i) + { + if (!registers[i]) + continue; - int count = 0; - while (++count < 4 && (i + count) < 32 && registers[i + count]) {} - if (count > 1) - { - bundled_loadstore = true; - break; - } - } + int count = 0; + while (++count < 4 && (i + count) < 32 && registers[i + count]) + { + } + if (count > 1) + { + bundled_loadstore = true; + break; + } + } - if (bundled_loadstore && tmp != INVALID_REG) - { - // The temporary register is only used to indicate that we can use this code path - std::vector island_regs; - for (int i = 0; i < 32; ++i) - { - if (!registers[i]) - continue; + if (bundled_loadstore && tmp != INVALID_REG) + { + // The temporary register is only used to indicate that we can use this code path + std::vector island_regs; + for (int i = 0; i < 32; ++i) + { + if (!registers[i]) + continue; - int count = 0; - while (++count < 4 && (i + count) < 32 && registers[i + count]) {} + int count = 0; + while (++count < 4 && (i + count) < 32 && registers[i + count]) + { + } - if (count == 1) - island_regs.push_back((ARM64Reg)(Q0 + i)); - else - LD1(64, count, INDEX_POST, (ARM64Reg)(Q0 + i), SP); + if (count == 1) + island_regs.push_back((ARM64Reg)(Q0 + i)); + else + LD1(64, count, INDEX_POST, (ARM64Reg)(Q0 + i), SP); - i += count - 1; - } + i += count - 1; + } - // Handle island registers - std::vector pair_regs; - for (auto& it : island_regs) - { - pair_regs.push_back(it); - if (pair_regs.size() == 2) - { - LDP(128, INDEX_POST, pair_regs[0], pair_regs[1], SP, 32); - pair_regs.clear(); - } - } - if (pair_regs.size()) - LDR(128, INDEX_POST, pair_regs[0], SP, 16); - } - else - { - bool odd = num_regs % 2; - std::vector pair_regs; - for (int i = 31; i >= 0; --i) - { - if (!registers[i]) - continue; + // Handle island registers + std::vector pair_regs; + for (auto& it : island_regs) + { + pair_regs.push_back(it); + if (pair_regs.size() == 2) + { + LDP(128, INDEX_POST, pair_regs[0], pair_regs[1], SP, 32); + pair_regs.clear(); + } + } + if (pair_regs.size()) + LDR(128, INDEX_POST, pair_regs[0], SP, 16); + } + else + { + bool odd = num_regs % 2; + std::vector pair_regs; + for (int i = 31; i >= 0; --i) + { + if (!registers[i]) + continue; - if (odd) - { - // First load must be a regular LDR if odd - odd = false; - LDR(128, INDEX_POST, (ARM64Reg)(Q0 + i), SP, 16); - } - else - { - pair_regs.push_back((ARM64Reg)(Q0 + i)); - if (pair_regs.size() == 2) - { - LDP(128, INDEX_POST, pair_regs[1], pair_regs[0], SP, 32); - pair_regs.clear(); - } - } - } - } + if (odd) + { + // First load must be a regular LDR if odd + odd = false; + LDR(128, INDEX_POST, (ARM64Reg)(Q0 + i), SP, 16); + } + else + { + pair_regs.push_back((ARM64Reg)(Q0 + i)); + if (pair_regs.size() == 2) + { + LDP(128, INDEX_POST, pair_regs[1], pair_regs[0], SP, 32); + pair_regs.clear(); + } + } + } + } } - void ARM64XEmitter::ANDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) { - unsigned int n, imm_s, imm_r; - if (!Is64Bit(Rn)) - imm &= 0xFFFFFFFF; - if (IsImmLogical(imm, Is64Bit(Rn) ? 64 : 32, &n, &imm_s, &imm_r)) - { - AND(Rd, Rn, imm_r, imm_s, n != 0); - } - else - { - _assert_msg_(DYNA_REC, scratch != INVALID_REG, "ANDSI2R - failed to construct logical immediate value from %08x, need scratch", (u32)imm); - MOVI2R(scratch, imm); - AND(Rd, Rn, scratch); - } + unsigned int n, imm_s, imm_r; + if (!Is64Bit(Rn)) + imm &= 0xFFFFFFFF; + if (IsImmLogical(imm, Is64Bit(Rn) ? 64 : 32, &n, &imm_s, &imm_r)) + { + AND(Rd, Rn, imm_r, imm_s, n != 0); + } + else + { + _assert_msg_(DYNA_REC, scratch != INVALID_REG, + "ANDSI2R - failed to construct logical immediate value from %08x, need scratch", + (u32)imm); + MOVI2R(scratch, imm); + AND(Rd, Rn, scratch); + } } void ARM64XEmitter::ORRI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) { - unsigned int n, imm_s, imm_r; - if (IsImmLogical(imm, Is64Bit(Rn) ? 64 : 32, &n, &imm_s, &imm_r)) - { - ORR(Rd, Rn, imm_r, imm_s, n != 0); - } - else - { - _assert_msg_(DYNA_REC, scratch != INVALID_REG, "ORRI2R - failed to construct logical immediate value from %08x, need scratch", (u32)imm); - MOVI2R(scratch, imm); - ORR(Rd, Rn, scratch); - } + unsigned int n, imm_s, imm_r; + if (IsImmLogical(imm, Is64Bit(Rn) ? 64 : 32, &n, &imm_s, &imm_r)) + { + ORR(Rd, Rn, imm_r, imm_s, n != 0); + } + else + { + _assert_msg_(DYNA_REC, scratch != INVALID_REG, + "ORRI2R - failed to construct logical immediate value from %08x, need scratch", + (u32)imm); + MOVI2R(scratch, imm); + ORR(Rd, Rn, scratch); + } } void ARM64XEmitter::EORI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) { - unsigned int n, imm_s, imm_r; - if (IsImmLogical(imm, Is64Bit(Rn) ? 64 : 32, &n, &imm_s, &imm_r)) - { - EOR(Rd, Rn, imm_r, imm_s, n != 0); - } - else - { - _assert_msg_(DYNA_REC, scratch != INVALID_REG, "EORI2R - failed to construct logical immediate value from %08x, need scratch", (u32)imm); - MOVI2R(scratch, imm); - EOR(Rd, Rn, scratch); - } + unsigned int n, imm_s, imm_r; + if (IsImmLogical(imm, Is64Bit(Rn) ? 64 : 32, &n, &imm_s, &imm_r)) + { + EOR(Rd, Rn, imm_r, imm_s, n != 0); + } + else + { + _assert_msg_(DYNA_REC, scratch != INVALID_REG, + "EORI2R - failed to construct logical immediate value from %08x, need scratch", + (u32)imm); + MOVI2R(scratch, imm); + EOR(Rd, Rn, scratch); + } } void ARM64XEmitter::ANDSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) { - unsigned int n, imm_s, imm_r; - if (IsImmLogical(imm, Is64Bit(Rn) ? 64 : 32, &n, &imm_s, &imm_r)) - { - ANDS(Rd, Rn, imm_r, imm_s, n != 0); - } - else - { - _assert_msg_(DYNA_REC, scratch != INVALID_REG, "ANDSI2R - failed to construct logical immediate value from %08x, need scratch", (u32)imm); - MOVI2R(scratch, imm); - ANDS(Rd, Rn, scratch); - } + unsigned int n, imm_s, imm_r; + if (IsImmLogical(imm, Is64Bit(Rn) ? 64 : 32, &n, &imm_s, &imm_r)) + { + ANDS(Rd, Rn, imm_r, imm_s, n != 0); + } + else + { + _assert_msg_(DYNA_REC, scratch != INVALID_REG, + "ANDSI2R - failed to construct logical immediate value from %08x, need scratch", + (u32)imm); + MOVI2R(scratch, imm); + ANDS(Rd, Rn, scratch); + } } void ARM64XEmitter::ADDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) { - u32 val; - bool shift; - if (IsImmArithmetic(imm, &val, &shift)) - { - ADD(Rd, Rn, val, shift); - } - else - { - _assert_msg_(DYNA_REC, scratch != INVALID_REG, "ADDI2R - failed to construct arithmetic immediate value from %08x, need scratch", (u32)imm); - MOVI2R(scratch, imm); - ADD(Rd, Rn, scratch); - } + u32 val; + bool shift; + if (IsImmArithmetic(imm, &val, &shift)) + { + ADD(Rd, Rn, val, shift); + } + else + { + _assert_msg_(DYNA_REC, scratch != INVALID_REG, + "ADDI2R - failed to construct arithmetic immediate value from %08x, need scratch", + (u32)imm); + MOVI2R(scratch, imm); + ADD(Rd, Rn, scratch); + } } void ARM64XEmitter::SUBI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) { - u32 val; - bool shift; - if (IsImmArithmetic(imm, &val, &shift)) - { - SUB(Rd, Rn, val, shift); - } - else - { - _assert_msg_(DYNA_REC, scratch != INVALID_REG, "SUBI2R - failed to construct arithmetic immediate value from %08x, need scratch", (u32)imm); - MOVI2R(scratch, imm); - SUB(Rd, Rn, scratch); - } + u32 val; + bool shift; + if (IsImmArithmetic(imm, &val, &shift)) + { + SUB(Rd, Rn, val, shift); + } + else + { + _assert_msg_(DYNA_REC, scratch != INVALID_REG, + "SUBI2R - failed to construct arithmetic immediate value from %08x, need scratch", + (u32)imm); + MOVI2R(scratch, imm); + SUB(Rd, Rn, scratch); + } } void ARM64XEmitter::CMPI2R(ARM64Reg Rn, u64 imm, ARM64Reg scratch) { - u32 val; - bool shift; - if (IsImmArithmetic(imm, &val, &shift)) - { - CMP(Rn, val, shift); - } - else - { - _assert_msg_(DYNA_REC, scratch != INVALID_REG, "CMPI2R - failed to construct arithmetic immediate value from %08x, need scratch", (u32)imm); - MOVI2R(scratch, imm); - CMP(Rn, scratch); - } + u32 val; + bool shift; + if (IsImmArithmetic(imm, &val, &shift)) + { + CMP(Rn, val, shift); + } + else + { + _assert_msg_(DYNA_REC, scratch != INVALID_REG, + "CMPI2R - failed to construct arithmetic immediate value from %08x, need scratch", + (u32)imm); + MOVI2R(scratch, imm); + CMP(Rn, scratch); + } } bool ARM64XEmitter::TryADDI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm) { - u32 val; - bool shift; - if (IsImmArithmetic(imm, &val, &shift)) - ADD(Rd, Rn, val, shift); - else - return false; + u32 val; + bool shift; + if (IsImmArithmetic(imm, &val, &shift)) + ADD(Rd, Rn, val, shift); + else + return false; - return true; + return true; } bool ARM64XEmitter::TrySUBI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm) { - u32 val; - bool shift; - if (IsImmArithmetic(imm, &val, &shift)) - SUB(Rd, Rn, val, shift); - else - return false; + u32 val; + bool shift; + if (IsImmArithmetic(imm, &val, &shift)) + SUB(Rd, Rn, val, shift); + else + return false; - return true; + return true; } bool ARM64XEmitter::TryCMPI2R(ARM64Reg Rn, u32 imm) { - u32 val; - bool shift; - if (IsImmArithmetic(imm, &val, &shift)) - CMP(Rn, val, shift); - else - return false; + u32 val; + bool shift; + if (IsImmArithmetic(imm, &val, &shift)) + CMP(Rn, val, shift); + else + return false; - return true; + return true; } bool ARM64XEmitter::TryANDI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm) { - u32 n, imm_r, imm_s; - if (IsImmLogical(imm, 32, &n, &imm_s, &imm_r)) - AND(Rd, Rn, imm_r, imm_s, n != 0); - else - return false; + u32 n, imm_r, imm_s; + if (IsImmLogical(imm, 32, &n, &imm_s, &imm_r)) + AND(Rd, Rn, imm_r, imm_s, n != 0); + else + return false; - return true; + return true; } bool ARM64XEmitter::TryORRI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm) { - u32 n, imm_r, imm_s; - if (IsImmLogical(imm, 32, &n, &imm_s, &imm_r)) - ORR(Rd, Rn, imm_r, imm_s, n != 0); - else - return false; + u32 n, imm_r, imm_s; + if (IsImmLogical(imm, 32, &n, &imm_s, &imm_r)) + ORR(Rd, Rn, imm_r, imm_s, n != 0); + else + return false; - return true; + return true; } bool ARM64XEmitter::TryEORI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm) { - u32 n, imm_r, imm_s; - if (IsImmLogical(imm, 32, &n, &imm_s, &imm_r)) - EOR(Rd, Rn, imm_r, imm_s, n != 0); - else - return false; + u32 n, imm_r, imm_s; + if (IsImmLogical(imm, 32, &n, &imm_s, &imm_r)) + EOR(Rd, Rn, imm_r, imm_s, n != 0); + else + return false; - return true; + return true; } float FPImm8ToFloat(uint8_t bits) { - int sign = bits >> 7; - uint32_t f = (sign << 31); - int bit6 = (bits >> 6) & 1; - uint32_t exp = ((!bit6) << 7) | (0x7C * bit6) | ((bits >> 4) & 3); - uint32_t mantissa = (bits & 0xF) << 19; - f |= exp << 23; - f |= mantissa; - float fl; - memcpy(&fl, &f, sizeof(float)); - return fl; + int sign = bits >> 7; + uint32_t f = (sign << 31); + int bit6 = (bits >> 6) & 1; + uint32_t exp = ((!bit6) << 7) | (0x7C * bit6) | ((bits >> 4) & 3); + uint32_t mantissa = (bits & 0xF) << 19; + f |= exp << 23; + f |= mantissa; + float fl; + memcpy(&fl, &f, sizeof(float)); + return fl; } bool FPImm8FromFloat(float value, uint8_t* immOut) { - uint32_t f; - memcpy(&f, &value, sizeof(float)); - uint32_t mantissa4 = (f & 0x7FFFFF) >> 19; - uint32_t exponent = (f >> 23) & 0xFF; - uint32_t sign = f >> 31; - if ((exponent >> 7) == ((exponent >> 6) & 1)) - return false; - uint8_t imm8 = (sign << 7) | ((!(exponent >> 7)) << 6) | ((exponent & 3) << 4) | mantissa4; - float newFloat = FPImm8ToFloat(imm8); - if (newFloat == value) - *immOut = imm8; - else - return false; - return true; + uint32_t f; + memcpy(&f, &value, sizeof(float)); + uint32_t mantissa4 = (f & 0x7FFFFF) >> 19; + uint32_t exponent = (f >> 23) & 0xFF; + uint32_t sign = f >> 31; + if ((exponent >> 7) == ((exponent >> 6) & 1)) + return false; + uint8_t imm8 = (sign << 7) | ((!(exponent >> 7)) << 6) | ((exponent & 3) << 4) | mantissa4; + float newFloat = FPImm8ToFloat(imm8); + if (newFloat == value) + *immOut = imm8; + else + return false; + return true; } void ARM64FloatEmitter::MOVI2F(ARM64Reg Rd, float value, ARM64Reg scratch, bool negate) { - _assert_msg_(DYNA_REC, !IsDouble(Rd), "MOVI2F does not yet support double precision"); - uint8_t imm8; - if (value == 0.0) - { - FMOV(Rd, IsDouble(Rd) ? ZR : WZR); - if (negate) - FNEG(Rd, Rd); - // TODO: There are some other values we could generate with the float-imm instruction, like 1.0... - } - else if (FPImm8FromFloat(value, &imm8)) - { - FMOV(Rd, imm8); - } - else - { - _assert_msg_(DYNA_REC, scratch != INVALID_REG, "Failed to find a way to generate FP immediate %f without scratch", value); - u32 ival; - if (negate) - value = -value; + _assert_msg_(DYNA_REC, !IsDouble(Rd), "MOVI2F does not yet support double precision"); + uint8_t imm8; + if (value == 0.0) + { + FMOV(Rd, IsDouble(Rd) ? ZR : WZR); + if (negate) + FNEG(Rd, Rd); + // TODO: There are some other values we could generate with the float-imm instruction, like + // 1.0... + } + else if (FPImm8FromFloat(value, &imm8)) + { + FMOV(Rd, imm8); + } + else + { + _assert_msg_(DYNA_REC, scratch != INVALID_REG, + "Failed to find a way to generate FP immediate %f without scratch", value); + u32 ival; + if (negate) + value = -value; - memcpy(&ival, &value, sizeof(ival)); - m_emit->MOVI2R(scratch, ival); - FMOV(Rd, scratch); - } + memcpy(&ival, &value, sizeof(ival)); + m_emit->MOVI2R(scratch, ival); + FMOV(Rd, scratch); + } } // TODO: Quite a few values could be generated easily using the MOVI instruction and friends. void ARM64FloatEmitter::MOVI2FDUP(ARM64Reg Rd, float value, ARM64Reg scratch) { - // TODO: Make it work with more element sizes - // TODO: Optimize - there are shorter solution for many values - ARM64Reg s = (ARM64Reg)(S0 + DecodeReg(Rd)); - MOVI2F(s, value, scratch); - DUP(32, Rd, Rd, 0); + // TODO: Make it work with more element sizes + // TODO: Optimize - there are shorter solution for many values + ARM64Reg s = (ARM64Reg)(S0 + DecodeReg(Rd)); + MOVI2F(s, value, scratch); + DUP(32, Rd, Rd, 0); } void ARM64XEmitter::SUBSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch) { - u32 val; - bool shift; - if (IsImmArithmetic(imm, &val, &shift)) - { - SUBS(Rd, Rn, val, shift); - } - else - { - _assert_msg_(DYNA_REC, scratch != INVALID_REG, "ANDSI2R - failed to construct immediate value from %08x, need scratch", (u32)imm); - MOVI2R(scratch, imm); - SUBS(Rd, Rn, scratch); - } + u32 val; + bool shift; + if (IsImmArithmetic(imm, &val, &shift)) + { + SUBS(Rd, Rn, val, shift); + } + else + { + _assert_msg_(DYNA_REC, scratch != INVALID_REG, + "ANDSI2R - failed to construct immediate value from %08x, need scratch", (u32)imm); + MOVI2R(scratch, imm); + SUBS(Rd, Rn, scratch); + } } } // namespace diff --git a/Source/Core/Common/Arm64Emitter.h b/Source/Core/Common/Arm64Emitter.h index 098b48fd25..34fab4f1d8 100644 --- a/Source/Core/Common/Arm64Emitter.h +++ b/Source/Core/Common/Arm64Emitter.h @@ -14,7 +14,6 @@ namespace Arm64Gen { - // X30 serves a dual purpose as a link register // Encoded as // Types: @@ -25,78 +24,261 @@ namespace Arm64Gen // 110 - VFP quad precision enum ARM64Reg { - // 32bit registers - W0 = 0, W1, W2, W3, W4, W5, W6, - W7, W8, W9, W10, W11, W12, W13, W14, - W15, W16, W17, W18, W19, W20, W21, W22, - W23, W24, W25, W26, W27, W28, W29, W30, + // 32bit registers + W0 = 0, + W1, + W2, + W3, + W4, + W5, + W6, + W7, + W8, + W9, + W10, + W11, + W12, + W13, + W14, + W15, + W16, + W17, + W18, + W19, + W20, + W21, + W22, + W23, + W24, + W25, + W26, + W27, + W28, + W29, + W30, - WSP, // 32bit stack pointer + WSP, // 32bit stack pointer - // 64bit registers - X0 = 0x20, X1, X2, X3, X4, X5, X6, - X7, X8, X9, X10, X11, X12, X13, X14, - X15, X16, X17, X18, X19, X20, X21, X22, - X23, X24, X25, X26, X27, X28, X29, X30, + // 64bit registers + X0 = 0x20, + X1, + X2, + X3, + X4, + X5, + X6, + X7, + X8, + X9, + X10, + X11, + X12, + X13, + X14, + X15, + X16, + X17, + X18, + X19, + X20, + X21, + X22, + X23, + X24, + X25, + X26, + X27, + X28, + X29, + X30, - SP, // 64bit stack pointer + SP, // 64bit stack pointer - // VFP single precision registers - S0 = 0x40, S1, S2, S3, S4, S5, S6, - S7, S8, S9, S10, S11, S12, S13, - S14, S15, S16, S17, S18, S19, S20, - S21, S22, S23, S24, S25, S26, S27, - S28, S29, S30, S31, + // VFP single precision registers + S0 = 0x40, + S1, + S2, + S3, + S4, + S5, + S6, + S7, + S8, + S9, + S10, + S11, + S12, + S13, + S14, + S15, + S16, + S17, + S18, + S19, + S20, + S21, + S22, + S23, + S24, + S25, + S26, + S27, + S28, + S29, + S30, + S31, - // VFP Double Precision registers - D0 = 0x80, D1, D2, D3, D4, D5, D6, D7, - D8, D9, D10, D11, D12, D13, D14, D15, - D16, D17, D18, D19, D20, D21, D22, D23, - D24, D25, D26, D27, D28, D29, D30, D31, + // VFP Double Precision registers + D0 = 0x80, + D1, + D2, + D3, + D4, + D5, + D6, + D7, + D8, + D9, + D10, + D11, + D12, + D13, + D14, + D15, + D16, + D17, + D18, + D19, + D20, + D21, + D22, + D23, + D24, + D25, + D26, + D27, + D28, + D29, + D30, + D31, - // ASIMD Quad-Word registers - Q0 = 0xC0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, - Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, - Q16, Q17, Q18, Q19, Q20, Q21, Q22, Q23, - Q24, Q25, Q26, Q27, Q28, Q29, Q30, Q31, + // ASIMD Quad-Word registers + Q0 = 0xC0, + Q1, + Q2, + Q3, + Q4, + Q5, + Q6, + Q7, + Q8, + Q9, + Q10, + Q11, + Q12, + Q13, + Q14, + Q15, + Q16, + Q17, + Q18, + Q19, + Q20, + Q21, + Q22, + Q23, + Q24, + Q25, + Q26, + Q27, + Q28, + Q29, + Q30, + Q31, - // For PRFM(prefetch memory) encoding - // This is encoded in the Rt register - // Data preload - PLDL1KEEP = 0, PLDL1STRM, - PLDL2KEEP, PLDL2STRM, - PLDL3KEEP, PLDL3STRM, - // Instruction preload - PLIL1KEEP = 8, PLIL1STRM, - PLIL2KEEP, PLIL2STRM, - PLIL3KEEP, PLIL3STRM, - // Prepare for store - PLTL1KEEP = 16, PLTL1STRM, - PLTL2KEEP, PLTL2STRM, - PLTL3KEEP, PLTL3STRM, + // For PRFM(prefetch memory) encoding + // This is encoded in the Rt register + // Data preload + PLDL1KEEP = 0, + PLDL1STRM, + PLDL2KEEP, + PLDL2STRM, + PLDL3KEEP, + PLDL3STRM, + // Instruction preload + PLIL1KEEP = 8, + PLIL1STRM, + PLIL2KEEP, + PLIL2STRM, + PLIL3KEEP, + PLIL3STRM, + // Prepare for store + PLTL1KEEP = 16, + PLTL1STRM, + PLTL2KEEP, + PLTL2STRM, + PLTL3KEEP, + PLTL3STRM, - WZR = WSP, - ZR = SP, + WZR = WSP, + ZR = SP, - INVALID_REG = 0xFFFFFFFF + INVALID_REG = 0xFFFFFFFF }; -constexpr bool Is64Bit(ARM64Reg reg) { return (reg & 0x20) != 0; } -constexpr bool IsSingle(ARM64Reg reg) { return (reg & 0xC0) == 0x40; } -constexpr bool IsDouble(ARM64Reg reg) { return (reg & 0xC0) == 0x80; } -constexpr bool IsScalar(ARM64Reg reg) { return IsSingle(reg) || IsDouble(reg); } -constexpr bool IsQuad(ARM64Reg reg) { return (reg & 0xC0) == 0xC0; } -constexpr bool IsVector(ARM64Reg reg) { return (reg & 0xC0) != 0; } -constexpr bool IsGPR(ARM64Reg reg) { return static_cast(reg) < 0x40; } +constexpr bool Is64Bit(ARM64Reg reg) +{ + return (reg & 0x20) != 0; +} +constexpr bool IsSingle(ARM64Reg reg) +{ + return (reg & 0xC0) == 0x40; +} +constexpr bool IsDouble(ARM64Reg reg) +{ + return (reg & 0xC0) == 0x80; +} +constexpr bool IsScalar(ARM64Reg reg) +{ + return IsSingle(reg) || IsDouble(reg); +} +constexpr bool IsQuad(ARM64Reg reg) +{ + return (reg & 0xC0) == 0xC0; +} +constexpr bool IsVector(ARM64Reg reg) +{ + return (reg & 0xC0) != 0; +} +constexpr bool IsGPR(ARM64Reg reg) +{ + return static_cast(reg) < 0x40; +} -constexpr ARM64Reg DecodeReg(ARM64Reg reg) { return static_cast(reg & 0x1F); } -constexpr ARM64Reg EncodeRegTo64(ARM64Reg reg) { return static_cast(reg | 0x20); } -constexpr ARM64Reg EncodeRegToSingle(ARM64Reg reg) { return static_cast(DecodeReg(reg) + S0); } -constexpr ARM64Reg EncodeRegToDouble(ARM64Reg reg) { return static_cast((reg & ~0xC0) | 0x80); } -constexpr ARM64Reg EncodeRegToQuad(ARM64Reg reg) { return static_cast(reg | 0xC0); } +constexpr ARM64Reg DecodeReg(ARM64Reg reg) +{ + return static_cast(reg & 0x1F); +} +constexpr ARM64Reg EncodeRegTo64(ARM64Reg reg) +{ + return static_cast(reg | 0x20); +} +constexpr ARM64Reg EncodeRegToSingle(ARM64Reg reg) +{ + return static_cast(DecodeReg(reg) + S0); +} +constexpr ARM64Reg EncodeRegToDouble(ARM64Reg reg) +{ + return static_cast((reg & ~0xC0) | 0x80); +} +constexpr ARM64Reg EncodeRegToQuad(ARM64Reg reg) +{ + return static_cast(reg | 0xC0); +} // For AND/TST/ORR/EOR etc -bool IsImmLogical(uint64_t value, unsigned int width, unsigned int* n, unsigned int* imm_s, unsigned int* imm_r); +bool IsImmLogical(uint64_t value, unsigned int width, unsigned int* n, unsigned int* imm_s, + unsigned int* imm_r); // For ADD/SUB bool IsImmArithmetic(uint64_t input, u32* val, bool* shift); @@ -105,870 +287,855 @@ bool FPImm8FromFloat(float value, uint8_t* immOut); enum OpType { - TYPE_IMM = 0, - TYPE_REG, - TYPE_IMMSREG, - TYPE_RSR, - TYPE_MEM + TYPE_IMM = 0, + TYPE_REG, + TYPE_IMMSREG, + TYPE_RSR, + TYPE_MEM }; enum ShiftType { - ST_LSL = 0, - ST_LSR = 1, - ST_ASR = 2, - ST_ROR = 3, + ST_LSL = 0, + ST_LSR = 1, + ST_ASR = 2, + ST_ROR = 3, }; enum IndexType { - INDEX_UNSIGNED, - INDEX_POST, - INDEX_PRE, - INDEX_SIGNED, // used in LDP/STP + INDEX_UNSIGNED, + INDEX_POST, + INDEX_PRE, + INDEX_SIGNED, // used in LDP/STP }; enum ShiftAmount { - SHIFT_0 = 0, - SHIFT_16 = 1, - SHIFT_32 = 2, - SHIFT_48 = 3, + SHIFT_0 = 0, + SHIFT_16 = 1, + SHIFT_32 = 2, + SHIFT_48 = 3, }; -enum RoundingMode { - ROUND_A, // round to nearest, ties to away - ROUND_M, // round towards -inf - ROUND_N, // round to nearest, ties to even - ROUND_P, // round towards +inf - ROUND_Z, // round towards zero +enum RoundingMode +{ + ROUND_A, // round to nearest, ties to away + ROUND_M, // round towards -inf + ROUND_N, // round to nearest, ties to even + ROUND_P, // round towards +inf + ROUND_Z, // round towards zero }; struct FixupBranch { - u8* ptr; - // Type defines - // 0 = CBZ (32bit) - // 1 = CBNZ (32bit) - // 2 = B (conditional) - // 3 = TBZ - // 4 = TBNZ - // 5 = B (unconditional) - // 6 = BL (unconditional) - u32 type; + u8* ptr; + // Type defines + // 0 = CBZ (32bit) + // 1 = CBNZ (32bit) + // 2 = B (conditional) + // 3 = TBZ + // 4 = TBNZ + // 5 = B (unconditional) + // 6 = BL (unconditional) + u32 type; - // Used with B.cond - CCFlags cond; + // Used with B.cond + CCFlags cond; - // Used with TBZ/TBNZ - u8 bit; + // Used with TBZ/TBNZ + u8 bit; - // Used with Test/Compare and Branch - ARM64Reg reg; + // Used with Test/Compare and Branch + ARM64Reg reg; }; enum PStateField { - FIELD_SPSel = 0, - FIELD_DAIFSet, - FIELD_DAIFClr, - FIELD_NZCV, // The only system registers accessible from EL0 (user space) - FIELD_PMCR_EL0, - FIELD_PMCCNTR_EL0, - FIELD_FPCR = 0x340, - FIELD_FPSR = 0x341, + FIELD_SPSel = 0, + FIELD_DAIFSet, + FIELD_DAIFClr, + FIELD_NZCV, // The only system registers accessible from EL0 (user space) + FIELD_PMCR_EL0, + FIELD_PMCCNTR_EL0, + FIELD_FPCR = 0x340, + FIELD_FPSR = 0x341, }; enum SystemHint { - HINT_NOP = 0, - HINT_YIELD, - HINT_WFE, - HINT_WFI, - HINT_SEV, - HINT_SEVL, + HINT_NOP = 0, + HINT_YIELD, + HINT_WFE, + HINT_WFI, + HINT_SEV, + HINT_SEVL, }; enum BarrierType { - OSHLD = 1, - OSHST = 2, - OSH = 3, - NSHLD = 5, - NSHST = 6, - NSH = 7, - ISHLD = 9, - ISHST = 10, - ISH = 11, - LD = 13, - ST = 14, - SY = 15, + OSHLD = 1, + OSHST = 2, + OSH = 3, + NSHLD = 5, + NSHST = 6, + NSH = 7, + ISHLD = 9, + ISHST = 10, + ISH = 11, + LD = 13, + ST = 14, + SY = 15, }; class ArithOption { public: - enum WidthSpecifier - { - WIDTH_DEFAULT, - WIDTH_32BIT, - WIDTH_64BIT, - }; + enum WidthSpecifier + { + WIDTH_DEFAULT, + WIDTH_32BIT, + WIDTH_64BIT, + }; - enum ExtendSpecifier - { - EXTEND_UXTB = 0x0, - EXTEND_UXTH = 0x1, - EXTEND_UXTW = 0x2, /* Also LSL on 32bit width */ - EXTEND_UXTX = 0x3, /* Also LSL on 64bit width */ - EXTEND_SXTB = 0x4, - EXTEND_SXTH = 0x5, - EXTEND_SXTW = 0x6, - EXTEND_SXTX = 0x7, - }; + enum ExtendSpecifier + { + EXTEND_UXTB = 0x0, + EXTEND_UXTH = 0x1, + EXTEND_UXTW = 0x2, /* Also LSL on 32bit width */ + EXTEND_UXTX = 0x3, /* Also LSL on 64bit width */ + EXTEND_SXTB = 0x4, + EXTEND_SXTH = 0x5, + EXTEND_SXTW = 0x6, + EXTEND_SXTX = 0x7, + }; - enum TypeSpecifier - { - TYPE_EXTENDEDREG, - TYPE_IMM, - TYPE_SHIFTEDREG, - }; + enum TypeSpecifier + { + TYPE_EXTENDEDREG, + TYPE_IMM, + TYPE_SHIFTEDREG, + }; private: - ARM64Reg m_destReg; - WidthSpecifier m_width; - ExtendSpecifier m_extend; - TypeSpecifier m_type; - ShiftType m_shifttype; - u32 m_shift; + ARM64Reg m_destReg; + WidthSpecifier m_width; + ExtendSpecifier m_extend; + TypeSpecifier m_type; + ShiftType m_shifttype; + u32 m_shift; public: - ArithOption(ARM64Reg Rd, bool index = false) - { - // Indexed registers are a certain feature of AARch64 - // On Loadstore instructions that use a register offset - // We can have the register as an index - // If we are indexing then the offset register will - // be shifted to the left so we are indexing at intervals - // of the size of what we are loading - // 8-bit: Index does nothing - // 16-bit: Index LSL 1 - // 32-bit: Index LSL 2 - // 64-bit: Index LSL 3 - if (index) - m_shift = 4; - else - m_shift = 0; + ArithOption(ARM64Reg Rd, bool index = false) + { + // Indexed registers are a certain feature of AARch64 + // On Loadstore instructions that use a register offset + // We can have the register as an index + // If we are indexing then the offset register will + // be shifted to the left so we are indexing at intervals + // of the size of what we are loading + // 8-bit: Index does nothing + // 16-bit: Index LSL 1 + // 32-bit: Index LSL 2 + // 64-bit: Index LSL 3 + if (index) + m_shift = 4; + else + m_shift = 0; - m_destReg = Rd; - m_type = TYPE_EXTENDEDREG; - if (Is64Bit(Rd)) - { - m_width = WIDTH_64BIT; - m_extend = EXTEND_UXTX; - } - else - { - m_width = WIDTH_32BIT; - m_extend = EXTEND_UXTW; - } - m_shifttype = ST_LSL; - } - ArithOption(ARM64Reg Rd, ShiftType shift_type, u32 shift) - { - m_destReg = Rd; - m_shift = shift; - m_shifttype = shift_type; - m_type = TYPE_SHIFTEDREG; - if (Is64Bit(Rd)) - { - m_width = WIDTH_64BIT; - if (shift == 64) - m_shift = 0; - } - else - { - m_width = WIDTH_32BIT; - if (shift == 32) - m_shift = 0; - } - } - TypeSpecifier GetType() const - { - return m_type; - } - ARM64Reg GetReg() const - { - return m_destReg; - } - u32 GetData() const - { - switch (m_type) - { - case TYPE_EXTENDEDREG: - return (m_extend << 13) | - (m_shift << 10); - break; - case TYPE_SHIFTEDREG: - return (m_shifttype << 22) | - (m_shift << 10); - break; - default: - _dbg_assert_msg_(DYNA_REC, false, "Invalid type in GetData"); - break; - } - return 0; - } + m_destReg = Rd; + m_type = TYPE_EXTENDEDREG; + if (Is64Bit(Rd)) + { + m_width = WIDTH_64BIT; + m_extend = EXTEND_UXTX; + } + else + { + m_width = WIDTH_32BIT; + m_extend = EXTEND_UXTW; + } + m_shifttype = ST_LSL; + } + ArithOption(ARM64Reg Rd, ShiftType shift_type, u32 shift) + { + m_destReg = Rd; + m_shift = shift; + m_shifttype = shift_type; + m_type = TYPE_SHIFTEDREG; + if (Is64Bit(Rd)) + { + m_width = WIDTH_64BIT; + if (shift == 64) + m_shift = 0; + } + else + { + m_width = WIDTH_32BIT; + if (shift == 32) + m_shift = 0; + } + } + TypeSpecifier GetType() const { return m_type; } + ARM64Reg GetReg() const { return m_destReg; } + u32 GetData() const + { + switch (m_type) + { + case TYPE_EXTENDEDREG: + return (m_extend << 13) | (m_shift << 10); + break; + case TYPE_SHIFTEDREG: + return (m_shifttype << 22) | (m_shift << 10); + break; + default: + _dbg_assert_msg_(DYNA_REC, false, "Invalid type in GetData"); + break; + } + return 0; + } }; class ARM64XEmitter { - friend class ARM64FloatEmitter; + friend class ARM64FloatEmitter; private: - u8* m_code; - u8* m_lastCacheFlushEnd; + u8* m_code; + u8* m_lastCacheFlushEnd; - void EncodeCompareBranchInst(u32 op, ARM64Reg Rt, const void* ptr); - void EncodeTestBranchInst(u32 op, ARM64Reg Rt, u8 bits, const void* ptr); - void EncodeUnconditionalBranchInst(u32 op, const void* ptr); - void EncodeUnconditionalBranchInst(u32 opc, u32 op2, u32 op3, u32 op4, ARM64Reg Rn); - void EncodeExceptionInst(u32 instenc, u32 imm); - void EncodeSystemInst(u32 op0, u32 op1, u32 CRn, u32 CRm, u32 op2, ARM64Reg Rt); - void EncodeArithmeticInst(u32 instenc, bool flags, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option); - void EncodeArithmeticCarryInst(u32 op, bool flags, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void EncodeCondCompareImmInst(u32 op, ARM64Reg Rn, u32 imm, u32 nzcv, CCFlags cond); - void EncodeCondCompareRegInst(u32 op, ARM64Reg Rn, ARM64Reg Rm, u32 nzcv, CCFlags cond); - void EncodeCondSelectInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond); - void EncodeData1SrcInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn); - void EncodeData2SrcInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void EncodeData3SrcInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); - void EncodeLogicalInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); - void EncodeLoadRegisterInst(u32 bitop, ARM64Reg Rt, u32 imm); - void EncodeLoadStoreExcInst(u32 instenc, ARM64Reg Rs, ARM64Reg Rt2, ARM64Reg Rn, ARM64Reg Rt); - void EncodeLoadStorePairedInst(u32 op, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, u32 imm); - void EncodeLoadStoreIndexedInst(u32 op, u32 op2, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void EncodeLoadStoreIndexedInst(u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm, u8 size); - void EncodeMOVWideInst(u32 op, ARM64Reg Rd, u32 imm, ShiftAmount pos); - void EncodeBitfieldMOVInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms); - void EncodeLoadStoreRegisterOffset(u32 size, u32 opc, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); - void EncodeAddSubImmInst(u32 op, bool flags, u32 shift, u32 imm, ARM64Reg Rn, ARM64Reg Rd); - void EncodeLogicalImmInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, int n); - void EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm); - void EncodeAddressInst(u32 op, ARM64Reg Rd, s32 imm); - void EncodeLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void EncodeCompareBranchInst(u32 op, ARM64Reg Rt, const void* ptr); + void EncodeTestBranchInst(u32 op, ARM64Reg Rt, u8 bits, const void* ptr); + void EncodeUnconditionalBranchInst(u32 op, const void* ptr); + void EncodeUnconditionalBranchInst(u32 opc, u32 op2, u32 op3, u32 op4, ARM64Reg Rn); + void EncodeExceptionInst(u32 instenc, u32 imm); + void EncodeSystemInst(u32 op0, u32 op1, u32 CRn, u32 CRm, u32 op2, ARM64Reg Rt); + void EncodeArithmeticInst(u32 instenc, bool flags, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, + ArithOption Option); + void EncodeArithmeticCarryInst(u32 op, bool flags, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void EncodeCondCompareImmInst(u32 op, ARM64Reg Rn, u32 imm, u32 nzcv, CCFlags cond); + void EncodeCondCompareRegInst(u32 op, ARM64Reg Rn, ARM64Reg Rm, u32 nzcv, CCFlags cond); + void EncodeCondSelectInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond); + void EncodeData1SrcInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn); + void EncodeData2SrcInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void EncodeData3SrcInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); + void EncodeLogicalInst(u32 instenc, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); + void EncodeLoadRegisterInst(u32 bitop, ARM64Reg Rt, u32 imm); + void EncodeLoadStoreExcInst(u32 instenc, ARM64Reg Rs, ARM64Reg Rt2, ARM64Reg Rn, ARM64Reg Rt); + void EncodeLoadStorePairedInst(u32 op, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, u32 imm); + void EncodeLoadStoreIndexedInst(u32 op, u32 op2, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void EncodeLoadStoreIndexedInst(u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm, u8 size); + void EncodeMOVWideInst(u32 op, ARM64Reg Rd, u32 imm, ShiftAmount pos); + void EncodeBitfieldMOVInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms); + void EncodeLoadStoreRegisterOffset(u32 size, u32 opc, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); + void EncodeAddSubImmInst(u32 op, bool flags, u32 shift, u32 imm, ARM64Reg Rn, ARM64Reg Rd); + void EncodeLogicalImmInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, int n); + void EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, + s32 imm); + void EncodeAddressInst(u32 op, ARM64Reg Rd, s32 imm); + void EncodeLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm); protected: - void Write32(u32 value); + void Write32(u32 value); public: - ARM64XEmitter() - : m_code(nullptr), m_lastCacheFlushEnd(nullptr) - { - } + ARM64XEmitter() : m_code(nullptr), m_lastCacheFlushEnd(nullptr) {} + ARM64XEmitter(u8* code_ptr) + { + m_code = code_ptr; + m_lastCacheFlushEnd = code_ptr; + } - ARM64XEmitter(u8* code_ptr) { - m_code = code_ptr; - m_lastCacheFlushEnd = code_ptr; - } + virtual ~ARM64XEmitter() {} + void SetCodePtr(u8* ptr); + void SetCodePtrUnsafe(u8* ptr); + void ReserveCodeSpace(u32 bytes); + const u8* AlignCode16(); + const u8* AlignCodePage(); + const u8* GetCodePtr() const; + void FlushIcache(); + void FlushIcacheSection(u8* start, u8* end); + u8* GetWritableCodePtr(); - virtual ~ARM64XEmitter() - { - } + // FixupBranch branching + void SetJumpTarget(FixupBranch const& branch); + FixupBranch CBZ(ARM64Reg Rt); + FixupBranch CBNZ(ARM64Reg Rt); + FixupBranch B(CCFlags cond); + FixupBranch TBZ(ARM64Reg Rt, u8 bit); + FixupBranch TBNZ(ARM64Reg Rt, u8 bit); + FixupBranch B(); + FixupBranch BL(); - void SetCodePtr(u8* ptr); - void SetCodePtrUnsafe(u8* ptr); - void ReserveCodeSpace(u32 bytes); - const u8* AlignCode16(); - const u8* AlignCodePage(); - const u8* GetCodePtr() const; - void FlushIcache(); - void FlushIcacheSection(u8* start, u8* end); - u8* GetWritableCodePtr(); + // Compare and Branch + void CBZ(ARM64Reg Rt, const void* ptr); + void CBNZ(ARM64Reg Rt, const void* ptr); - // FixupBranch branching - void SetJumpTarget(FixupBranch const& branch); - FixupBranch CBZ(ARM64Reg Rt); - FixupBranch CBNZ(ARM64Reg Rt); - FixupBranch B(CCFlags cond); - FixupBranch TBZ(ARM64Reg Rt, u8 bit); - FixupBranch TBNZ(ARM64Reg Rt, u8 bit); - FixupBranch B(); - FixupBranch BL(); + // Conditional Branch + void B(CCFlags cond, const void* ptr); - // Compare and Branch - void CBZ(ARM64Reg Rt, const void* ptr); - void CBNZ(ARM64Reg Rt, const void* ptr); + // Test and Branch + void TBZ(ARM64Reg Rt, u8 bits, const void* ptr); + void TBNZ(ARM64Reg Rt, u8 bits, const void* ptr); - // Conditional Branch - void B(CCFlags cond, const void* ptr); + // Unconditional Branch + void B(const void* ptr); + void BL(const void* ptr); - // Test and Branch - void TBZ(ARM64Reg Rt, u8 bits, const void* ptr); - void TBNZ(ARM64Reg Rt, u8 bits, const void* ptr); + // Unconditional Branch (register) + void BR(ARM64Reg Rn); + void BLR(ARM64Reg Rn); + void RET(ARM64Reg Rn = X30); + void ERET(); + void DRPS(); - // Unconditional Branch - void B(const void* ptr); - void BL(const void* ptr); + // Exception generation + void SVC(u32 imm); + void HVC(u32 imm); + void SMC(u32 imm); + void BRK(u32 imm); + void HLT(u32 imm); + void DCPS1(u32 imm); + void DCPS2(u32 imm); + void DCPS3(u32 imm); - // Unconditional Branch (register) - void BR(ARM64Reg Rn); - void BLR(ARM64Reg Rn); - void RET(ARM64Reg Rn = X30); - void ERET(); - void DRPS(); + // System + void _MSR(PStateField field, u8 imm); - // Exception generation - void SVC(u32 imm); - void HVC(u32 imm); - void SMC(u32 imm); - void BRK(u32 imm); - void HLT(u32 imm); - void DCPS1(u32 imm); - void DCPS2(u32 imm); - void DCPS3(u32 imm); + void _MSR(PStateField field, ARM64Reg Rt); + void MRS(ARM64Reg Rt, PStateField field); - // System - void _MSR(PStateField field, u8 imm); + void HINT(SystemHint op); + void CLREX(); + void DSB(BarrierType type); + void DMB(BarrierType type); + void ISB(BarrierType type); - void _MSR(PStateField field, ARM64Reg Rt); - void MRS(ARM64Reg Rt, PStateField field); + // Add/Subtract (Extended/Shifted register) + void ADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void ADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option); + void ADDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void ADDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option); + void SUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void SUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option); + void SUBS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void SUBS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option); + void CMN(ARM64Reg Rn, ARM64Reg Rm); + void CMN(ARM64Reg Rn, ARM64Reg Rm, ArithOption Option); + void CMP(ARM64Reg Rn, ARM64Reg Rm); + void CMP(ARM64Reg Rn, ARM64Reg Rm, ArithOption Option); - void HINT(SystemHint op); - void CLREX(); - void DSB(BarrierType type); - void DMB(BarrierType type); - void ISB(BarrierType type); + // Add/Subtract (with carry) + void ADC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void ADCS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void SBC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void SBCS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - // Add/Subtract (Extended/Shifted register) - void ADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void ADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option); - void ADDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void ADDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option); - void SUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void SUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option); - void SUBS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void SUBS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Option); - void CMN(ARM64Reg Rn, ARM64Reg Rm); - void CMN(ARM64Reg Rn, ARM64Reg Rm, ArithOption Option); - void CMP(ARM64Reg Rn, ARM64Reg Rm); - void CMP(ARM64Reg Rn, ARM64Reg Rm, ArithOption Option); + // Conditional Compare (immediate) + void CCMN(ARM64Reg Rn, u32 imm, u32 nzcv, CCFlags cond); + void CCMP(ARM64Reg Rn, u32 imm, u32 nzcv, CCFlags cond); - // Add/Subtract (with carry) - void ADC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void ADCS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void SBC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void SBCS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + // Conditional Compare (register) + void CCMN(ARM64Reg Rn, ARM64Reg Rm, u32 nzcv, CCFlags cond); + void CCMP(ARM64Reg Rn, ARM64Reg Rm, u32 nzcv, CCFlags cond); - // Conditional Compare (immediate) - void CCMN(ARM64Reg Rn, u32 imm, u32 nzcv, CCFlags cond); - void CCMP(ARM64Reg Rn, u32 imm, u32 nzcv, CCFlags cond); + // Conditional Select + void CSEL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond); + void CSINC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond); + void CSINV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond); + void CSNEG(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond); - // Conditional Compare (register) - void CCMN(ARM64Reg Rn, ARM64Reg Rm, u32 nzcv, CCFlags cond); - void CCMP(ARM64Reg Rn, ARM64Reg Rm, u32 nzcv, CCFlags cond); + // Aliases + void CSET(ARM64Reg Rd, CCFlags cond) + { + ARM64Reg zr = Is64Bit(Rd) ? ZR : WZR; + CSINC(Rd, zr, zr, (CCFlags)((u32)cond ^ 1)); + } + void NEG(ARM64Reg Rd, ARM64Reg Rs) { SUB(Rd, Is64Bit(Rd) ? ZR : WZR, Rs); } + // Data-Processing 1 source + void RBIT(ARM64Reg Rd, ARM64Reg Rn); + void REV16(ARM64Reg Rd, ARM64Reg Rn); + void REV32(ARM64Reg Rd, ARM64Reg Rn); + void REV64(ARM64Reg Rd, ARM64Reg Rn); + void CLZ(ARM64Reg Rd, ARM64Reg Rn); + void CLS(ARM64Reg Rd, ARM64Reg Rn); - // Conditional Select - void CSEL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond); - void CSINC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond); - void CSINV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond); - void CSNEG(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond); + // Data-Processing 2 source + void UDIV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void SDIV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void LSLV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void LSRV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void ASRV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void RORV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void CRC32B(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void CRC32H(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void CRC32W(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void CRC32CB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void CRC32CH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void CRC32CW(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void CRC32X(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void CRC32CX(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - // Aliases - void CSET(ARM64Reg Rd, CCFlags cond) - { - ARM64Reg zr = Is64Bit(Rd) ? ZR : WZR; - CSINC(Rd, zr, zr, (CCFlags)((u32)cond ^ 1)); - } - void NEG(ARM64Reg Rd, ARM64Reg Rs) - { - SUB(Rd, Is64Bit(Rd) ? ZR : WZR, Rs); - } + // Data-Processing 3 source + void MADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); + void MSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); + void SMADDL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); + void SMULL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void SMSUBL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); + void SMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void UMADDL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); + void UMULL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void UMSUBL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); + void UMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void MUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void MNEG(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - // Data-Processing 1 source - void RBIT(ARM64Reg Rd, ARM64Reg Rn); - void REV16(ARM64Reg Rd, ARM64Reg Rn); - void REV32(ARM64Reg Rd, ARM64Reg Rn); - void REV64(ARM64Reg Rd, ARM64Reg Rn); - void CLZ(ARM64Reg Rd, ARM64Reg Rn); - void CLS(ARM64Reg Rd, ARM64Reg Rn); + // Logical (shifted register) + void AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); + void BIC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); + void ORR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); + void ORN(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); + void EOR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); + void EON(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); + void ANDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); + void BICS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); - // Data-Processing 2 source - void UDIV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void SDIV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void LSLV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void LSRV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void ASRV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void RORV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void CRC32B(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void CRC32H(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void CRC32W(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void CRC32CB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void CRC32CH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void CRC32CW(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void CRC32X(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void CRC32CX(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + // Wrap the above for saner syntax + void AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { AND(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } + void BIC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { BIC(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } + void ORR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { ORR(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } + void ORN(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { ORN(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } + void EOR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { EOR(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } + void EON(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { EON(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } + void ANDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { ANDS(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } + void BICS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { BICS(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } + // Convenience wrappers around ORR. These match the official convenience syntax. + void MOV(ARM64Reg Rd, ARM64Reg Rm, ArithOption Shift); + void MOV(ARM64Reg Rd, ARM64Reg Rm); + void MVN(ARM64Reg Rd, ARM64Reg Rm); - // Data-Processing 3 source - void MADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); - void MSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); - void SMADDL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); - void SMULL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void SMSUBL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); - void SMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void UMADDL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); - void UMULL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void UMSUBL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); - void UMULH(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void MUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void MNEG(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + // TODO: These are "slow" as they use arith+shift, should be replaced with UBFM/EXTR variants. + void LSR(ARM64Reg Rd, ARM64Reg Rm, int shift); + void LSL(ARM64Reg Rd, ARM64Reg Rm, int shift); + void ASR(ARM64Reg Rd, ARM64Reg Rm, int shift); + void ROR(ARM64Reg Rd, ARM64Reg Rm, int shift); - // Logical (shifted register) - void AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); - void BIC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); - void ORR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); - void ORN(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); - void EOR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); - void EON(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); - void ANDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); - void BICS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ArithOption Shift); + // Logical (immediate) + void AND(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, bool invert = false); + void ANDS(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, bool invert = false); + void EOR(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, bool invert = false); + void ORR(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, bool invert = false); + void TST(ARM64Reg Rn, u32 immr, u32 imms, bool invert = false); + void TST(ARM64Reg Rn, ARM64Reg Rm) { ANDS(Is64Bit(Rn) ? ZR : WZR, Rn, Rm); } + // Add/subtract (immediate) + void ADD(ARM64Reg Rd, ARM64Reg Rn, u32 imm, bool shift = false); + void ADDS(ARM64Reg Rd, ARM64Reg Rn, u32 imm, bool shift = false); + void SUB(ARM64Reg Rd, ARM64Reg Rn, u32 imm, bool shift = false); + void SUBS(ARM64Reg Rd, ARM64Reg Rn, u32 imm, bool shift = false); + void CMP(ARM64Reg Rn, u32 imm, bool shift = false); - // Wrap the above for saner syntax - void AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { AND(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } - void BIC(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { BIC(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } - void ORR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { ORR(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } - void ORN(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { ORN(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } - void EOR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { EOR(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } - void EON(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { EON(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } - void ANDS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { ANDS(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } - void BICS(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) { BICS(Rd, Rn, Rm, ArithOption(Rd, ST_LSL, 0)); } + // Data Processing (Immediate) + void MOVZ(ARM64Reg Rd, u32 imm, ShiftAmount pos = SHIFT_0); + void MOVN(ARM64Reg Rd, u32 imm, ShiftAmount pos = SHIFT_0); + void MOVK(ARM64Reg Rd, u32 imm, ShiftAmount pos = SHIFT_0); - // Convenience wrappers around ORR. These match the official convenience syntax. - void MOV(ARM64Reg Rd, ARM64Reg Rm, ArithOption Shift); - void MOV(ARM64Reg Rd, ARM64Reg Rm); - void MVN(ARM64Reg Rd, ARM64Reg Rm); + // Bitfield move + void BFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms); + void SBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms); + void UBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms); + void BFI(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width); + void UBFIZ(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width); - // TODO: These are "slow" as they use arith+shift, should be replaced with UBFM/EXTR variants. - void LSR(ARM64Reg Rd, ARM64Reg Rm, int shift); - void LSL(ARM64Reg Rd, ARM64Reg Rm, int shift); - void ASR(ARM64Reg Rd, ARM64Reg Rm, int shift); - void ROR(ARM64Reg Rd, ARM64Reg Rm, int shift); + // Extract register (ROR with two inputs, if same then faster on A67) + void EXTR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u32 shift); - // Logical (immediate) - void AND(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, bool invert = false); - void ANDS(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, bool invert = false); - void EOR(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, bool invert = false); - void ORR(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms, bool invert = false); - void TST(ARM64Reg Rn, u32 immr, u32 imms, bool invert = false); - void TST(ARM64Reg Rn, ARM64Reg Rm) - { - ANDS(Is64Bit(Rn) ? ZR : WZR, Rn, Rm); - } + // Aliases + void SXTB(ARM64Reg Rd, ARM64Reg Rn); + void SXTH(ARM64Reg Rd, ARM64Reg Rn); + void SXTW(ARM64Reg Rd, ARM64Reg Rn); + void UXTB(ARM64Reg Rd, ARM64Reg Rn); + void UXTH(ARM64Reg Rd, ARM64Reg Rn); - // Add/subtract (immediate) - void ADD(ARM64Reg Rd, ARM64Reg Rn, u32 imm, bool shift = false); - void ADDS(ARM64Reg Rd, ARM64Reg Rn, u32 imm, bool shift = false); - void SUB(ARM64Reg Rd, ARM64Reg Rn, u32 imm, bool shift = false); - void SUBS(ARM64Reg Rd, ARM64Reg Rn, u32 imm, bool shift = false); - void CMP(ARM64Reg Rn, u32 imm, bool shift = false); + void UBFX(ARM64Reg Rd, ARM64Reg Rn, int lsb, int width) { UBFM(Rd, Rn, lsb, lsb + width - 1); } + // Load Register (Literal) + void LDR(ARM64Reg Rt, u32 imm); + void LDRSW(ARM64Reg Rt, u32 imm); + void PRFM(ARM64Reg Rt, u32 imm); - // Data Processing (Immediate) - void MOVZ(ARM64Reg Rd, u32 imm, ShiftAmount pos = SHIFT_0); - void MOVN(ARM64Reg Rd, u32 imm, ShiftAmount pos = SHIFT_0); - void MOVK(ARM64Reg Rd, u32 imm, ShiftAmount pos = SHIFT_0); + // Load/Store Exclusive + void STXRB(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn); + void STLXRB(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn); + void LDXRB(ARM64Reg Rt, ARM64Reg Rn); + void LDAXRB(ARM64Reg Rt, ARM64Reg Rn); + void STLRB(ARM64Reg Rt, ARM64Reg Rn); + void LDARB(ARM64Reg Rt, ARM64Reg Rn); + void STXRH(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn); + void STLXRH(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn); + void LDXRH(ARM64Reg Rt, ARM64Reg Rn); + void LDAXRH(ARM64Reg Rt, ARM64Reg Rn); + void STLRH(ARM64Reg Rt, ARM64Reg Rn); + void LDARH(ARM64Reg Rt, ARM64Reg Rn); + void STXR(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn); + void STLXR(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn); + void STXP(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn); + void STLXP(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn); + void LDXR(ARM64Reg Rt, ARM64Reg Rn); + void LDAXR(ARM64Reg Rt, ARM64Reg Rn); + void LDXP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn); + void LDAXP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn); + void STLR(ARM64Reg Rt, ARM64Reg Rn); + void LDAR(ARM64Reg Rt, ARM64Reg Rn); - // Bitfield move - void BFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms); - void SBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms); - void UBFM(ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms); - void BFI(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width); - void UBFIZ(ARM64Reg Rd, ARM64Reg Rn, u32 lsb, u32 width); + // Load/Store no-allocate pair (offset) + void STNP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, u32 imm); + void LDNP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, u32 imm); - // Extract register (ROR with two inputs, if same then faster on A67) - void EXTR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u32 shift); + // Load/Store register (immediate indexed) + void STRB(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void LDRB(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void LDRSB(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void STRH(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void LDRH(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void LDRSH(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void STR(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void LDR(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void LDRSW(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - // Aliases - void SXTB(ARM64Reg Rd, ARM64Reg Rn); - void SXTH(ARM64Reg Rd, ARM64Reg Rn); - void SXTW(ARM64Reg Rd, ARM64Reg Rn); - void UXTB(ARM64Reg Rd, ARM64Reg Rn); - void UXTH(ARM64Reg Rd, ARM64Reg Rn); + // Load/Store register (register offset) + void STRB(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); + void LDRB(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); + void LDRSB(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); + void STRH(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); + void LDRH(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); + void LDRSH(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); + void STR(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); + void LDR(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); + void LDRSW(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); + void PRFM(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); - void UBFX(ARM64Reg Rd, ARM64Reg Rn, int lsb, int width) - { - UBFM(Rd, Rn, lsb, lsb + width - 1); - } + // Load/Store register (unscaled offset) + void STURB(ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void LDURB(ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void LDURSB(ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void STURH(ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void LDURH(ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void LDURSH(ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void STUR(ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void LDUR(ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void LDURSW(ARM64Reg Rt, ARM64Reg Rn, s32 imm); - // Load Register (Literal) - void LDR(ARM64Reg Rt, u32 imm); - void LDRSW(ARM64Reg Rt, u32 imm); - void PRFM(ARM64Reg Rt, u32 imm); + // Load/Store pair + void LDP(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm); + void LDPSW(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm); + void STP(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm); - // Load/Store Exclusive - void STXRB(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn); - void STLXRB(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn); - void LDXRB(ARM64Reg Rt, ARM64Reg Rn); - void LDAXRB(ARM64Reg Rt, ARM64Reg Rn); - void STLRB(ARM64Reg Rt, ARM64Reg Rn); - void LDARB(ARM64Reg Rt, ARM64Reg Rn); - void STXRH(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn); - void STLXRH(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn); - void LDXRH(ARM64Reg Rt, ARM64Reg Rn); - void LDAXRH(ARM64Reg Rt, ARM64Reg Rn); - void STLRH(ARM64Reg Rt, ARM64Reg Rn); - void LDARH(ARM64Reg Rt, ARM64Reg Rn); - void STXR(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn); - void STLXR(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rn); - void STXP(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn); - void STLXP(ARM64Reg Rs, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn); - void LDXR(ARM64Reg Rt, ARM64Reg Rn); - void LDAXR(ARM64Reg Rt, ARM64Reg Rn); - void LDXP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn); - void LDAXP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn); - void STLR(ARM64Reg Rt, ARM64Reg Rn); - void LDAR(ARM64Reg Rt, ARM64Reg Rn); + // Address of label/page PC-relative + void ADR(ARM64Reg Rd, s32 imm); + void ADRP(ARM64Reg Rd, s32 imm); - // Load/Store no-allocate pair (offset) - void STNP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, u32 imm); - void LDNP(ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, u32 imm); + // Wrapper around MOVZ+MOVK + void MOVI2R(ARM64Reg Rd, u64 imm, bool optimize = true); + template + void MOVP2R(ARM64Reg Rd, P* ptr) + { + _assert_msg_(DYNA_REC, Is64Bit(Rd), "Can't store pointers in 32-bit registers"); + MOVI2R(Rd, (uintptr_t)ptr); + } - // Load/Store register (immediate indexed) - void STRB(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void LDRB(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void LDRSB(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void STRH(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void LDRH(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void LDRSH(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void STR(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void LDR(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void LDRSW(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + // Wrapper around AND x, y, imm etc. If you are sure the imm will work, no need to pass a scratch + // register. + void ANDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); + void ANDSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); + void TSTI2R(ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG) + { + ANDSI2R(Is64Bit(Rn) ? ZR : WZR, Rn, imm, scratch); + } + void ORRI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); + void EORI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); + void CMPI2R(ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); - // Load/Store register (register offset) - void STRB(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); - void LDRB(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); - void LDRSB(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); - void STRH(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); - void LDRH(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); - void LDRSH(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); - void STR(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); - void LDR(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); - void LDRSW(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); - void PRFM(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); + void ADDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); + void SUBI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); + void SUBSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); - // Load/Store register (unscaled offset) - void STURB(ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void LDURB(ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void LDURSB(ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void STURH(ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void LDURH(ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void LDURSH(ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void STUR(ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void LDUR(ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void LDURSW(ARM64Reg Rt, ARM64Reg Rn, s32 imm); + bool TryADDI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm); + bool TrySUBI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm); + bool TryCMPI2R(ARM64Reg Rn, u32 imm); - // Load/Store pair - void LDP(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm); - void LDPSW(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm); - void STP(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm); + bool TryANDI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm); + bool TryORRI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm); + bool TryEORI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm); - // Address of label/page PC-relative - void ADR(ARM64Reg Rd, s32 imm); - void ADRP(ARM64Reg Rd, s32 imm); + // ABI related + void ABI_PushRegisters(BitSet32 registers); + void ABI_PopRegisters(BitSet32 registers, BitSet32 ignore_mask = BitSet32(0)); - // Wrapper around MOVZ+MOVK - void MOVI2R(ARM64Reg Rd, u64 imm, bool optimize = true); - template - void MOVP2R(ARM64Reg Rd, P* ptr) - { - _assert_msg_(DYNA_REC, Is64Bit(Rd), "Can't store pointers in 32-bit registers"); - MOVI2R(Rd, (uintptr_t)ptr); - } + // Utility to generate a call to a std::function object. + // + // Unfortunately, calling operator() directly is undefined behavior in C++ + // (this method might be a thunk in the case of multi-inheritance) so we + // have to go through a trampoline function. + template + static T CallLambdaTrampoline(const std::function* f, Args... args) + { + return (*f)(args...); + } - // Wrapper around AND x, y, imm etc. If you are sure the imm will work, no need to pass a scratch register. - void ANDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); - void ANDSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); - void TSTI2R(ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG) { ANDSI2R(Is64Bit(Rn) ? ZR : WZR, Rn, imm, scratch); } - void ORRI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); - void EORI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); - void CMPI2R(ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); + // This function expects you to have set up the state. + // Overwrites X0 and X30 + template + ARM64Reg ABI_SetupLambda(const std::function* f) + { + auto trampoline = &ARM64XEmitter::CallLambdaTrampoline; + MOVI2R(X30, (uintptr_t)trampoline); + MOVI2R(X0, (uintptr_t) const_cast((const void*)f)); + return X30; + } - void ADDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); - void SUBI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); - void SUBSI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm, ARM64Reg scratch = INVALID_REG); - - bool TryADDI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm); - bool TrySUBI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm); - bool TryCMPI2R(ARM64Reg Rn, u32 imm); - - bool TryANDI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm); - bool TryORRI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm); - bool TryEORI2R(ARM64Reg Rd, ARM64Reg Rn, u32 imm); - - // ABI related - void ABI_PushRegisters(BitSet32 registers); - void ABI_PopRegisters(BitSet32 registers, BitSet32 ignore_mask = BitSet32(0)); - - // Utility to generate a call to a std::function object. - // - // Unfortunately, calling operator() directly is undefined behavior in C++ - // (this method might be a thunk in the case of multi-inheritance) so we - // have to go through a trampoline function. - template - static T CallLambdaTrampoline(const std::function* f, Args... args) - { - return (*f)(args...); - } - - // This function expects you to have set up the state. - // Overwrites X0 and X30 - template - ARM64Reg ABI_SetupLambda(const std::function* f) - { - auto trampoline = &ARM64XEmitter::CallLambdaTrampoline; - MOVI2R(X30, (uintptr_t)trampoline); - MOVI2R(X0, (uintptr_t)const_cast((const void*)f)); - return X30; - } - - // Plain function call - void QuickCallFunction(ARM64Reg scratchreg, const void* func); - template void QuickCallFunction(ARM64Reg scratchreg, T func) - { - QuickCallFunction(scratchreg, (const void*)func); - } + // Plain function call + void QuickCallFunction(ARM64Reg scratchreg, const void* func); + template + void QuickCallFunction(ARM64Reg scratchreg, T func) + { + QuickCallFunction(scratchreg, (const void*)func); + } }; class ARM64FloatEmitter { public: - ARM64FloatEmitter(ARM64XEmitter* emit) : m_emit(emit) {} + ARM64FloatEmitter(ARM64XEmitter* emit) : m_emit(emit) {} + void LDR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void STR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void LDR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void STR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + // Loadstore unscaled + void LDUR(u8 size, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void STUR(u8 size, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - // Loadstore unscaled - void LDUR(u8 size, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void STUR(u8 size, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + // Loadstore single structure + void LD1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn); + void LD1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn, ARM64Reg Rm); + void LD1R(u8 size, ARM64Reg Rt, ARM64Reg Rn); + void LD2R(u8 size, ARM64Reg Rt, ARM64Reg Rn); + void LD1R(u8 size, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm); + void LD2R(u8 size, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm); + void ST1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn); + void ST1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn, ARM64Reg Rm); - // Loadstore single structure - void LD1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn); - void LD1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn, ARM64Reg Rm); - void LD1R(u8 size, ARM64Reg Rt, ARM64Reg Rn); - void LD2R(u8 size, ARM64Reg Rt, ARM64Reg Rn); - void LD1R(u8 size, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm); - void LD2R(u8 size, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm); - void ST1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn); - void ST1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn, ARM64Reg Rm); + // Loadstore multiple structure + void LD1(u8 size, u8 count, ARM64Reg Rt, ARM64Reg Rn); + void LD1(u8 size, u8 count, IndexType type, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm = SP); + void ST1(u8 size, u8 count, ARM64Reg Rt, ARM64Reg Rn); + void ST1(u8 size, u8 count, IndexType type, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm = SP); - // Loadstore multiple structure - void LD1(u8 size, u8 count, ARM64Reg Rt, ARM64Reg Rn); - void LD1(u8 size, u8 count, IndexType type, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm = SP); - void ST1(u8 size, u8 count, ARM64Reg Rt, ARM64Reg Rn); - void ST1(u8 size, u8 count, IndexType type, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm = SP); + // Loadstore paired + void LDP(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm); + void STP(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm); - // Loadstore paired - void LDP(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm); - void STP(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm); + // Loadstore register offset + void STR(u8 size, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); + void LDR(u8 size, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); - // Loadstore register offset - void STR(u8 size, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); - void LDR(u8 size, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); + // Scalar - 1 Source + void FABS(ARM64Reg Rd, ARM64Reg Rn); + void FNEG(ARM64Reg Rd, ARM64Reg Rn); + void FSQRT(ARM64Reg Rd, ARM64Reg Rn); + void FMOV(ARM64Reg Rd, ARM64Reg Rn, bool top = false); // Also generalized move between GPR/FP - // Scalar - 1 Source - void FABS(ARM64Reg Rd, ARM64Reg Rn); - void FNEG(ARM64Reg Rd, ARM64Reg Rn); - void FSQRT(ARM64Reg Rd, ARM64Reg Rn); - void FMOV(ARM64Reg Rd, ARM64Reg Rn, bool top = false); // Also generalized move between GPR/FP + // Scalar - 2 Source + void FADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FMUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FDIV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FMAX(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FMIN(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FMAXNM(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FMINNM(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FNMUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - // Scalar - 2 Source - void FADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FMUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FDIV(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FMAX(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FMIN(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FMAXNM(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FMINNM(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FNMUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + // Scalar - 3 Source. Note - the accumulator is last on ARM! + void FMADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); + void FMSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); + void FNMADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); + void FNMSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); - // Scalar - 3 Source. Note - the accumulator is last on ARM! - void FMADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); - void FMSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); - void FNMADD(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); - void FNMSUB(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra); + // Scalar floating point immediate + void FMOV(ARM64Reg Rd, uint8_t imm8); - // Scalar floating point immediate - void FMOV(ARM64Reg Rd, uint8_t imm8); + // Vector + void AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void BSL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void DUP(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index); + void FABS(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FADD(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FMAX(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FMLA(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FMLS(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FMIN(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FCVTL(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FCVTL2(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FCVTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); + void FCVTN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); + void FCVTZS(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FCVTZU(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FDIV(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FMUL(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FNEG(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FRSQRTE(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FSUB(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void NOT(ARM64Reg Rd, ARM64Reg Rn); + void ORR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void MOV(ARM64Reg Rd, ARM64Reg Rn) { ORR(Rd, Rn, Rn); } + void REV16(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void REV32(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void REV64(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void SCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void UCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void SCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn, int scale); + void UCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn, int scale); + void SQXTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); + void SQXTN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); + void UQXTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); + void UQXTN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); + void XTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); + void XTN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); - // Vector - void AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void BSL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void DUP(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index); - void FABS(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void FADD(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FMAX(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FMLA(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FMLS(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FMIN(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FCVTL(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void FCVTL2(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void FCVTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); - void FCVTN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); - void FCVTZS(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void FCVTZU(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void FDIV(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FMUL(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FNEG(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void FRSQRTE(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void FSUB(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void NOT(ARM64Reg Rd, ARM64Reg Rn); - void ORR(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void MOV(ARM64Reg Rd, ARM64Reg Rn) - { - ORR(Rd, Rn, Rn); - } - void REV16(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void REV32(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void REV64(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void SCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void UCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void SCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn, int scale); - void UCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn, int scale); - void SQXTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); - void SQXTN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); - void UQXTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); - void UQXTN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); - void XTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); - void XTN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn); + // Move + void DUP(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void INS(u8 size, ARM64Reg Rd, u8 index, ARM64Reg Rn); + void INS(u8 size, ARM64Reg Rd, u8 index1, ARM64Reg Rn, u8 index2); + void UMOV(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index); + void SMOV(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index); - // Move - void DUP(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void INS(u8 size, ARM64Reg Rd, u8 index, ARM64Reg Rn); - void INS(u8 size, ARM64Reg Rd, u8 index1, ARM64Reg Rn, u8 index2); - void UMOV(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index); - void SMOV(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index); + // One source + void FCVT(u8 size_to, u8 size_from, ARM64Reg Rd, ARM64Reg Rn); - // One source - void FCVT(u8 size_to, u8 size_from, ARM64Reg Rd, ARM64Reg Rn); + // Scalar convert float to int, in a lot of variants. + // Note that the scalar version of this operation has two encodings, one that goes to an integer + // register + // and one that outputs to a scalar fp register. + void FCVTS(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round); + void FCVTU(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round); - // Scalar convert float to int, in a lot of variants. - // Note that the scalar version of this operation has two encodings, one that goes to an integer register - // and one that outputs to a scalar fp register. - void FCVTS(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round); - void FCVTU(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round); + // Scalar convert int to float. No rounding mode specifier necessary. + void SCVTF(ARM64Reg Rd, ARM64Reg Rn); + void UCVTF(ARM64Reg Rd, ARM64Reg Rn); - // Scalar convert int to float. No rounding mode specifier necessary. - void SCVTF(ARM64Reg Rd, ARM64Reg Rn); - void UCVTF(ARM64Reg Rd, ARM64Reg Rn); + // Scalar fixed point to float. scale is the number of fractional bits. + void SCVTF(ARM64Reg Rd, ARM64Reg Rn, int scale); + void UCVTF(ARM64Reg Rd, ARM64Reg Rn, int scale); - // Scalar fixed point to float. scale is the number of fractional bits. - void SCVTF(ARM64Reg Rd, ARM64Reg Rn, int scale); - void UCVTF(ARM64Reg Rd, ARM64Reg Rn, int scale); + // Float comparison + void FCMP(ARM64Reg Rn, ARM64Reg Rm); + void FCMP(ARM64Reg Rn); + void FCMPE(ARM64Reg Rn, ARM64Reg Rm); + void FCMPE(ARM64Reg Rn); + void FCMEQ(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FCMEQ(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FCMGE(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FCMGE(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FCMGT(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void FCMGT(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FCMLE(u8 size, ARM64Reg Rd, ARM64Reg Rn); + void FCMLT(u8 size, ARM64Reg Rd, ARM64Reg Rn); - // Float comparison - void FCMP(ARM64Reg Rn, ARM64Reg Rm); - void FCMP(ARM64Reg Rn); - void FCMPE(ARM64Reg Rn, ARM64Reg Rm); - void FCMPE(ARM64Reg Rn); - void FCMEQ(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FCMEQ(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void FCMGE(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FCMGE(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void FCMGT(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void FCMGT(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void FCMLE(u8 size, ARM64Reg Rd, ARM64Reg Rn); - void FCMLT(u8 size, ARM64Reg Rd, ARM64Reg Rn); + // Conditional select + void FCSEL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond); - // Conditional select - void FCSEL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, CCFlags cond); + // Permute + void UZP1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void TRN1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void ZIP1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void UZP2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void TRN2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void ZIP2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - // Permute - void UZP1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void TRN1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void ZIP1(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void UZP2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void TRN2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void ZIP2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + // Shift by immediate + void SSHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); + void SSHLL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); + void USHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); + void USHLL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); + void SHRN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); + void SHRN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); + void SXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn); + void SXTL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn); + void UXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn); + void UXTL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn); - // Shift by immediate - void SSHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); - void SSHLL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); - void USHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); - void USHLL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); - void SHRN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); - void SHRN2(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift); - void SXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn); - void SXTL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn); - void UXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn); - void UXTL2(u8 src_size, ARM64Reg Rd, ARM64Reg Rn); + // vector x indexed element + void FMUL(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u8 index); + void FMLA(u8 esize, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u8 index); - // vector x indexed element - void FMUL(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u8 index); - void FMLA(u8 esize, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, u8 index); + // Modified Immediate + void MOVI(u8 size, ARM64Reg Rd, u64 imm, u8 shift = 0); + void BIC(u8 size, ARM64Reg Rd, u8 imm, u8 shift = 0); - // Modified Immediate - void MOVI(u8 size, ARM64Reg Rd, u64 imm, u8 shift = 0); - void BIC(u8 size, ARM64Reg Rd, u8 imm, u8 shift = 0); + void MOVI2F(ARM64Reg Rd, float value, ARM64Reg scratch = INVALID_REG, bool negate = false); + void MOVI2FDUP(ARM64Reg Rd, float value, ARM64Reg scratch = INVALID_REG); - void MOVI2F(ARM64Reg Rd, float value, ARM64Reg scratch = INVALID_REG, bool negate = false); - void MOVI2FDUP(ARM64Reg Rd, float value, ARM64Reg scratch = INVALID_REG); - - // ABI related - void ABI_PushRegisters(BitSet32 registers, ARM64Reg tmp = INVALID_REG); - void ABI_PopRegisters(BitSet32 registers, ARM64Reg tmp = INVALID_REG); + // ABI related + void ABI_PushRegisters(BitSet32 registers, ARM64Reg tmp = INVALID_REG); + void ABI_PopRegisters(BitSet32 registers, ARM64Reg tmp = INVALID_REG); private: - ARM64XEmitter* m_emit; - inline void Write32(u32 value) { m_emit->Write32(value); } + ARM64XEmitter* m_emit; + inline void Write32(u32 value) { m_emit->Write32(value); } + // Emitting functions + void EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void EmitScalar2Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, + ARM64Reg Rm); + void EmitThreeSame(bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void EmitCopy(bool Q, u32 op, u32 imm5, u32 imm4, ARM64Reg Rd, ARM64Reg Rn); + void Emit2RegMisc(bool Q, bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); + void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, + ARM64Reg Rn); + void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, + ARM64Reg Rn, ARM64Reg Rm); + void Emit1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); + void EmitConversion(bool sf, bool S, u32 type, u32 rmode, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); + void EmitConversion2(bool sf, bool S, bool direction, u32 type, u32 rmode, u32 opcode, int scale, + ARM64Reg Rd, ARM64Reg Rn); + void EmitCompare(bool M, bool S, u32 op, u32 opcode2, ARM64Reg Rn, ARM64Reg Rm); + void EmitCondSelect(bool M, bool S, CCFlags cond, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void EmitPermute(u32 size, u32 op, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); + void EmitScalarImm(bool M, bool S, u32 type, u32 imm5, ARM64Reg Rd, u32 imm8); + void EmitShiftImm(bool Q, bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); + void EmitScalarShiftImm(bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); + void EmitLoadStoreMultipleStructure(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn); + void EmitLoadStoreMultipleStructurePost(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn, + ARM64Reg Rm); + void EmitScalar1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); + void EmitVectorxElement(bool U, u32 size, bool L, u32 opcode, bool H, ARM64Reg Rd, ARM64Reg Rn, + ARM64Reg Rm); + void EmitLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm); + void EmitConvertScalarToInt(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round, bool sign); + void EmitScalar3Source(bool isDouble, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra, + int opcode); + void EncodeLoadStorePair(u32 size, bool load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, + ARM64Reg Rn, s32 imm); + void EncodeLoadStoreRegisterOffset(u32 size, bool load, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); + void EncodeModImm(bool Q, u8 op, u8 cmode, u8 o2, ARM64Reg Rd, u8 abcdefgh); - // Emitting functions - void EmitLoadStoreImmediate(u8 size, u32 opc, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void EmitScalar2Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void EmitThreeSame(bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void EmitCopy(bool Q, u32 op, u32 imm5, u32 imm4, ARM64Reg Rd, ARM64Reg Rn); - void Emit2RegMisc(bool Q, bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); - void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, ARM64Reg Rn); - void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm); - void Emit1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); - void EmitConversion(bool sf, bool S, u32 type, u32 rmode, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); - void EmitConversion2(bool sf, bool S, bool direction, u32 type, u32 rmode, u32 opcode, int scale, ARM64Reg Rd, ARM64Reg Rn); - void EmitCompare(bool M, bool S, u32 op, u32 opcode2, ARM64Reg Rn, ARM64Reg Rm); - void EmitCondSelect(bool M, bool S, CCFlags cond, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void EmitPermute(u32 size, u32 op, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void EmitScalarImm(bool M, bool S, u32 type, u32 imm5, ARM64Reg Rd, u32 imm8); - void EmitShiftImm(bool Q, bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); - void EmitScalarShiftImm(bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); - void EmitLoadStoreMultipleStructure(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn); - void EmitLoadStoreMultipleStructurePost(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm); - void EmitScalar1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn); - void EmitVectorxElement(bool U, u32 size, bool L, u32 opcode, bool H, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm); - void EmitLoadStoreUnscaled(u32 size, u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm); - void EmitConvertScalarToInt(ARM64Reg Rd, ARM64Reg Rn, RoundingMode round, bool sign); - void EmitScalar3Source(bool isDouble, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm, ARM64Reg Ra, int opcode); - void EncodeLoadStorePair(u32 size, bool load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm); - void EncodeLoadStoreRegisterOffset(u32 size, bool load, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm); - void EncodeModImm(bool Q, u8 op, u8 cmode, u8 o2, ARM64Reg Rd, u8 abcdefgh); - - void SSHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper); - void USHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper); - void SHRN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper); - void SXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, bool upper); - void UXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, bool upper); + void SSHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper); + void USHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper); + void SHRN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift, bool upper); + void SXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, bool upper); + void UXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, bool upper); }; class ARM64CodeBlock : public CodeBlock { private: - void PoisonMemory() override - { - u32* ptr = (u32*)region; - u32* maxptr = (u32*)(region + region_size); - // If our memory isn't a multiple of u32 then this won't write the last remaining bytes with anything - // Less than optimal, but there would be nothing we could do but throw a runtime warning anyway. - // AArch64: 0xD4200000 = BRK 0 - while (ptr < maxptr) - *ptr++ = 0xD4200000; - } + void PoisonMemory() override + { + u32* ptr = (u32*)region; + u32* maxptr = (u32*)(region + region_size); + // If our memory isn't a multiple of u32 then this won't write the last remaining bytes with + // anything + // Less than optimal, but there would be nothing we could do but throw a runtime warning anyway. + // AArch64: 0xD4200000 = BRK 0 + while (ptr < maxptr) + *ptr++ = 0xD4200000; + } }; } - diff --git a/Source/Core/Common/ArmCPUDetect.cpp b/Source/Core/Common/ArmCPUDetect.cpp index 4e68054410..64e36b0d67 100644 --- a/Source/Core/Common/ArmCPUDetect.cpp +++ b/Source/Core/Common/ArmCPUDetect.cpp @@ -2,87 +2,92 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #include #include -#include -#include #include +#include -#include "Common/CommonTypes.h" #include "Common/CPUDetect.h" +#include "Common/CommonTypes.h" #include "Common/StringUtil.h" const char procfile[] = "/proc/cpuinfo"; static std::string GetCPUString() { - const std::string marker = "Hardware\t: "; - std::string cpu_string = "Unknown"; + const std::string marker = "Hardware\t: "; + std::string cpu_string = "Unknown"; - std::string line; - std::ifstream file(procfile); + std::string line; + std::ifstream file(procfile); - if (!file) - return cpu_string; + if (!file) + return cpu_string; - while (std::getline(file, line)) - { - if (line.find(marker) != std::string::npos) - { - cpu_string = line.substr(marker.length()); - break; - } - } + while (std::getline(file, line)) + { + if (line.find(marker) != std::string::npos) + { + cpu_string = line.substr(marker.length()); + break; + } + } - return cpu_string; + return cpu_string; } CPUInfo cpu_info; CPUInfo::CPUInfo() { - Detect(); + Detect(); } // Detects the various CPU features void CPUInfo::Detect() { - // Set some defaults here - // When ARMv8 CPUs come out, these need to be updated. - HTT = false; - OS64bit = true; - CPU64bit = true; - Mode64bit = true; - vendor = VENDOR_ARM; + // Set some defaults here + // When ARMv8 CPUs come out, these need to be updated. + HTT = false; + OS64bit = true; + CPU64bit = true; + Mode64bit = true; + vendor = VENDOR_ARM; - // Get the information about the CPU - num_cores = sysconf(_SC_NPROCESSORS_CONF); - strncpy(cpu_string, GetCPUString().c_str(), sizeof(cpu_string)); + // Get the information about the CPU + num_cores = sysconf(_SC_NPROCESSORS_CONF); + strncpy(cpu_string, GetCPUString().c_str(), sizeof(cpu_string)); - unsigned long hwcaps = getauxval(AT_HWCAP); - bFP = hwcaps & HWCAP_FP; - bASIMD = hwcaps & HWCAP_ASIMD; - bAES = hwcaps & HWCAP_AES; - bCRC32 = hwcaps & HWCAP_CRC32; - bSHA1 = hwcaps & HWCAP_SHA1; - bSHA2 = hwcaps & HWCAP_SHA2; + unsigned long hwcaps = getauxval(AT_HWCAP); + bFP = hwcaps & HWCAP_FP; + bASIMD = hwcaps & HWCAP_ASIMD; + bAES = hwcaps & HWCAP_AES; + bCRC32 = hwcaps & HWCAP_CRC32; + bSHA1 = hwcaps & HWCAP_SHA1; + bSHA2 = hwcaps & HWCAP_SHA2; } // Turn the CPU info into a string we can show std::string CPUInfo::Summarize() { - std::string sum; - if (num_cores == 1) - sum = StringFromFormat("%s, %i core", cpu_string, num_cores); - else - sum = StringFromFormat("%s, %i cores", cpu_string, num_cores); + std::string sum; + if (num_cores == 1) + sum = StringFromFormat("%s, %i core", cpu_string, num_cores); + else + sum = StringFromFormat("%s, %i cores", cpu_string, num_cores); - if (bAES) sum += ", AES"; - if (bCRC32) sum += ", CRC32"; - if (bSHA1) sum += ", SHA1"; - if (bSHA2) sum += ", SHA2"; - if (CPU64bit) sum += ", 64-bit"; + if (bAES) + sum += ", AES"; + if (bCRC32) + sum += ", CRC32"; + if (bSHA1) + sum += ", SHA1"; + if (bSHA2) + sum += ", SHA2"; + if (CPU64bit) + sum += ", 64-bit"; - return sum; + return sum; } diff --git a/Source/Core/Common/ArmCommon.h b/Source/Core/Common/ArmCommon.h index 3dd1592d0a..a18795110e 100644 --- a/Source/Core/Common/ArmCommon.h +++ b/Source/Core/Common/ArmCommon.h @@ -6,23 +6,22 @@ enum CCFlags { - CC_EQ = 0, // Equal - CC_NEQ, // Not equal - CC_CS, // Carry Set - CC_CC, // Carry Clear - CC_MI, // Minus (Negative) - CC_PL, // Plus - CC_VS, // Overflow - CC_VC, // No Overflow - CC_HI, // Unsigned higher - CC_LS, // Unsigned lower or same - CC_GE, // Signed greater than or equal - CC_LT, // Signed less than - CC_GT, // Signed greater than - CC_LE, // Signed less than or equal - CC_AL, // Always (unconditional) 14 - CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same - CC_LO = CC_CC, // Alias of CC_CC Unsigned lower + CC_EQ = 0, // Equal + CC_NEQ, // Not equal + CC_CS, // Carry Set + CC_CC, // Carry Clear + CC_MI, // Minus (Negative) + CC_PL, // Plus + CC_VS, // Overflow + CC_VC, // No Overflow + CC_HI, // Unsigned higher + CC_LS, // Unsigned lower or same + CC_GE, // Signed greater than or equal + CC_LT, // Signed less than + CC_GT, // Signed greater than + CC_LE, // Signed less than or equal + CC_AL, // Always (unconditional) 14 + CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same + CC_LO = CC_CC, // Alias of CC_CC Unsigned lower }; const u32 NO_COND = 0xE0000000; - diff --git a/Source/Core/Common/Assert.h b/Source/Core/Common/Assert.h index 5114808e7e..fe067b900a 100644 --- a/Source/Core/Common/Assert.h +++ b/Source/Core/Common/Assert.h @@ -6,42 +6,46 @@ #include "Common/Common.h" #include "Common/CommonFuncs.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #ifdef _WIN32 -#define _assert_msg_(_t_, _a_, _fmt_, ...) \ - if (!(_a_)) {\ - if (!PanicYesNo(_fmt_, __VA_ARGS__)) \ - Crash(); \ - } +#define _assert_msg_(_t_, _a_, _fmt_, ...) \ + if (!(_a_)) \ + { \ + if (!PanicYesNo(_fmt_, __VA_ARGS__)) \ + Crash(); \ + } -#define _dbg_assert_msg_(_t_, _a_, _msg_, ...)\ - if (MAX_LOGLEVEL >= LogTypes::LOG_LEVELS::LDEBUG && !(_a_)) {\ - ERROR_LOG(_t_, _msg_, __VA_ARGS__); \ - if (!PanicYesNo(_msg_, __VA_ARGS__)) \ - Crash(); \ - } +#define _dbg_assert_msg_(_t_, _a_, _msg_, ...) \ + if (MAX_LOGLEVEL >= LogTypes::LOG_LEVELS::LDEBUG && !(_a_)) \ + { \ + ERROR_LOG(_t_, _msg_, __VA_ARGS__); \ + if (!PanicYesNo(_msg_, __VA_ARGS__)) \ + Crash(); \ + } #else -#define _assert_msg_(_t_, _a_, _fmt_, ...) \ - if (!(_a_)) {\ - if (!PanicYesNo(_fmt_, ##__VA_ARGS__)) \ - Crash(); \ - } +#define _assert_msg_(_t_, _a_, _fmt_, ...) \ + if (!(_a_)) \ + { \ + if (!PanicYesNo(_fmt_, ##__VA_ARGS__)) \ + Crash(); \ + } -#define _dbg_assert_msg_(_t_, _a_, _msg_, ...)\ - if (MAX_LOGLEVEL >= LogTypes::LOG_LEVELS::LDEBUG && !(_a_)) {\ - ERROR_LOG(_t_, _msg_, ##__VA_ARGS__); \ - if (!PanicYesNo(_msg_, ##__VA_ARGS__)) \ - Crash(); \ - } +#define _dbg_assert_msg_(_t_, _a_, _msg_, ...) \ + if (MAX_LOGLEVEL >= LogTypes::LOG_LEVELS::LDEBUG && !(_a_)) \ + { \ + ERROR_LOG(_t_, _msg_, ##__VA_ARGS__); \ + if (!PanicYesNo(_msg_, ##__VA_ARGS__)) \ + Crash(); \ + } #endif -#define _assert_(_a_) \ - _assert_msg_(MASTER_LOG, _a_, \ - _trans("An error occurred.\n\n Line: %d\n File: %s\n\nIgnore and continue?"), \ - __LINE__, __FILE__) +#define _assert_(_a_) \ + _assert_msg_(MASTER_LOG, _a_, \ + _trans("An error occurred.\n\n Line: %d\n File: %s\n\nIgnore and continue?"), \ + __LINE__, __FILE__) -#define _dbg_assert_(_t_, _a_) \ - if (MAX_LOGLEVEL >= LogTypes::LOG_LEVELS::LDEBUG) \ - _assert_(_a_) +#define _dbg_assert_(_t_, _a_) \ + if (MAX_LOGLEVEL >= LogTypes::LOG_LEVELS::LDEBUG) \ + _assert_(_a_) diff --git a/Source/Core/Common/Atomic.h b/Source/Core/Common/Atomic.h index 54c8e5b591..2b252a6924 100644 --- a/Source/Core/Common/Atomic.h +++ b/Source/Core/Common/Atomic.h @@ -6,11 +6,11 @@ #ifdef _WIN32 -#include "Common/Atomic_Win32.h" // IWYU pragma: export +#include "Common/Atomic_Win32.h" // IWYU pragma: export #else // GCC-compatible compiler assumed! -#include "Common/Atomic_GCC.h" // IWYU pragma: export +#include "Common/Atomic_GCC.h" // IWYU pragma: export #endif diff --git a/Source/Core/Common/Atomic_GCC.h b/Source/Core/Common/Atomic_GCC.h index 227d698395..d1f4626a1c 100644 --- a/Source/Core/Common/Atomic_GCC.h +++ b/Source/Core/Common/Atomic_GCC.h @@ -25,30 +25,29 @@ namespace Common { - inline void AtomicAdd(volatile u32& target, u32 value) { - __sync_add_and_fetch(&target, value); + __sync_add_and_fetch(&target, value); } inline void AtomicAnd(volatile u32& target, u32 value) { - __sync_and_and_fetch(&target, value); + __sync_and_and_fetch(&target, value); } inline void AtomicDecrement(volatile u32& target) { - __sync_add_and_fetch(&target, -1); + __sync_add_and_fetch(&target, -1); } inline void AtomicIncrement(volatile u32& target) { - __sync_add_and_fetch(&target, 1); + __sync_add_and_fetch(&target, 1); } inline void AtomicOr(volatile u32& target, u32 value) { - __sync_or_and_fetch(&target, value); + __sync_or_and_fetch(&target, value); } #ifndef __ATOMIC_RELAXED @@ -58,31 +57,30 @@ inline void AtomicOr(volatile u32& target, u32 value) template inline T AtomicLoad(volatile T& src) { - return __atomic_load_n(&src, __ATOMIC_RELAXED); + return __atomic_load_n(&src, __ATOMIC_RELAXED); } template inline T AtomicLoadAcquire(volatile T& src) { - return __atomic_load_n(&src, __ATOMIC_ACQUIRE); + return __atomic_load_n(&src, __ATOMIC_ACQUIRE); } template inline void AtomicStore(volatile T& dest, U value) { - __atomic_store_n(&dest, value, __ATOMIC_RELAXED); + __atomic_store_n(&dest, value, __ATOMIC_RELAXED); } template inline void AtomicStoreRelease(volatile T& dest, U value) { - __atomic_store_n(&dest, value, __ATOMIC_RELEASE); + __atomic_store_n(&dest, value, __ATOMIC_RELEASE); } template inline T* AtomicExchangeAcquire(T* volatile& loc, U newval) { - return __atomic_exchange_n(&loc, newval, __ATOMIC_ACQ_REL); + return __atomic_exchange_n(&loc, newval, __ATOMIC_ACQ_REL); } - } diff --git a/Source/Core/Common/Atomic_Win32.h b/Source/Core/Common/Atomic_Win32.h index 8b9a795832..1a6f160b86 100644 --- a/Source/Core/Common/Atomic_Win32.h +++ b/Source/Core/Common/Atomic_Win32.h @@ -31,63 +31,61 @@ namespace Common { - inline void AtomicAdd(volatile u32& target, u32 value) { - _InterlockedExchangeAdd((volatile LONG*)&target, (LONG)value); + _InterlockedExchangeAdd((volatile LONG*)&target, (LONG)value); } inline void AtomicAnd(volatile u32& target, u32 value) { - _InterlockedAnd((volatile LONG*)&target, (LONG)value); + _InterlockedAnd((volatile LONG*)&target, (LONG)value); } inline void AtomicIncrement(volatile u32& target) { - _InterlockedIncrement((volatile LONG*)&target); + _InterlockedIncrement((volatile LONG*)&target); } inline void AtomicDecrement(volatile u32& target) { - _InterlockedDecrement((volatile LONG*)&target); + _InterlockedDecrement((volatile LONG*)&target); } inline void AtomicOr(volatile u32& target, u32 value) { - _InterlockedOr((volatile LONG*)&target, (LONG)value); + _InterlockedOr((volatile LONG*)&target, (LONG)value); } template inline T AtomicLoad(volatile T& src) { - return src; // 32-bit reads are always atomic. + return src; // 32-bit reads are always atomic. } template inline T AtomicLoadAcquire(volatile T& src) { - T result = src; // 32-bit reads are always atomic. - _ReadBarrier(); // Compiler instruction only. x86 loads always have acquire semantics. - return result; + T result = src; // 32-bit reads are always atomic. + _ReadBarrier(); // Compiler instruction only. x86 loads always have acquire semantics. + return result; } template inline void AtomicStore(volatile T& dest, U value) { - dest = (T) value; // 32-bit writes are always atomic. + dest = (T)value; // 32-bit writes are always atomic. } template inline void AtomicStoreRelease(volatile T& dest, U value) { - _WriteBarrier(); // Compiler instruction only. x86 stores always have release semantics. - dest = (T) value; // 32-bit writes are always atomic. + _WriteBarrier(); // Compiler instruction only. x86 stores always have release semantics. + dest = (T)value; // 32-bit writes are always atomic. } template inline T* AtomicExchangeAcquire(T* volatile& loc, U newval) { - return (T*) _InterlockedExchangePointer_acq((void* volatile*) &loc, (void*) newval); + return (T*)_InterlockedExchangePointer_acq((void* volatile*)&loc, (void*)newval); } - } diff --git a/Source/Core/Common/BitField.h b/Source/Core/Common/BitField.h index 65f9c8d3f5..10312f1c38 100644 --- a/Source/Core/Common/BitField.h +++ b/Source/Core/Common/BitField.h @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // Copyright 2014 Tony Wasserka // All rights reserved. // @@ -30,7 +29,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - #pragma once #include @@ -111,78 +109,73 @@ * symptoms. */ #pragma pack(1) -template +template struct BitField { private: - // This constructor might be considered ambiguous: - // Would it initialize the storage or just the bitfield? - // Hence, delete it. Use the assignment operator to set bitfield values! - BitField(T val) = delete; + // This constructor might be considered ambiguous: + // Would it initialize the storage or just the bitfield? + // Hence, delete it. Use the assignment operator to set bitfield values! + BitField(T val) = delete; public: - // Force default constructor to be created - // so that we can use this within unions - BitField() = default; + // Force default constructor to be created + // so that we can use this within unions + BitField() = default; - // We explicitly delete the copy assignment operator here, because the - // default copy assignment would copy the full storage value, rather than - // just the bits relevant to this particular bit field. - // Ideally, we would just implement the copy assignment to copy only the - // relevant bits, but this requires compiler support for unrestricted - // unions. - // TODO: Implement this operator properly once all target compilers - // support unrestricted unions. - BitField& operator=(const BitField&) = delete; + // We explicitly delete the copy assignment operator here, because the + // default copy assignment would copy the full storage value, rather than + // just the bits relevant to this particular bit field. + // Ideally, we would just implement the copy assignment to copy only the + // relevant bits, but this requires compiler support for unrestricted + // unions. + // TODO: Implement this operator properly once all target compilers + // support unrestricted unions. + BitField& operator=(const BitField&) = delete; - __forceinline BitField& operator=(T val) - { - storage = (storage & ~GetMask()) | ((val << position) & GetMask()); - return *this; - } + __forceinline BitField& operator=(T val) + { + storage = (storage & ~GetMask()) | ((val << position) & GetMask()); + return *this; + } - __forceinline T Value() const - { - if (std::numeric_limits::is_signed) - { - std::size_t shift = 8 * sizeof(T) - bits; - return (T)((storage << (shift - position)) >> shift); - } - else - { - return (T)((storage & GetMask()) >> position); - } - } - - __forceinline operator T() const - { - return Value(); - } + __forceinline T Value() const + { + if (std::numeric_limits::is_signed) + { + std::size_t shift = 8 * sizeof(T) - bits; + return (T)((storage << (shift - position)) >> shift); + } + else + { + return (T)((storage & GetMask()) >> position); + } + } + __forceinline operator T() const { return Value(); } private: - // StorageType is T for non-enum types and the underlying type of T if - // T is an enumeration. Note that T is wrapped within an enable_if in the - // former case to workaround compile errors which arise when using - // std::underlying_type::type directly. - typedef typename std::conditional::value, - std::underlying_type, - std::enable_if>::type::type StorageType; + // StorageType is T for non-enum types and the underlying type of T if + // T is an enumeration. Note that T is wrapped within an enable_if in the + // former case to workaround compile errors which arise when using + // std::underlying_type::type directly. + typedef typename std::conditional::value, std::underlying_type, + std::enable_if>::type::type StorageType; - // Unsigned version of StorageType - typedef typename std::make_unsigned::type StorageTypeU; + // Unsigned version of StorageType + typedef typename std::make_unsigned::type StorageTypeU; - __forceinline StorageType GetMask() const - { - return (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; - } + __forceinline StorageType GetMask() const + { + return (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; + } - StorageType storage; + StorageType storage; - static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); + static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); - // And, you know, just in case people specify something stupid like bits=position=0x80000000 - static_assert(position < 8 * sizeof(T), "Invalid position"); - static_assert(bits <= 8 * sizeof(T), "Invalid number of bits"); - static_assert(bits > 0, "Invalid number of bits"); + // And, you know, just in case people specify something stupid like bits=position=0x80000000 + static_assert(position < 8 * sizeof(T), "Invalid position"); + static_assert(bits <= 8 * sizeof(T), "Invalid number of bits"); + static_assert(bits > 0, "Invalid number of bits"); }; #pragma pack() diff --git a/Source/Core/Common/BitSet.h b/Source/Core/Common/BitSet.h index 97f54b1362..c04fee8746 100644 --- a/Source/Core/Common/BitSet.h +++ b/Source/Core/Common/BitSet.h @@ -16,53 +16,76 @@ template static inline int CountSetBits(T v) { - // from https://graphics.stanford.edu/~seander/bithacks.html - // GCC has this built in, but MSVC's intrinsic will only emit the actual - // POPCNT instruction, which we're not depending on - v = v - ((v >> 1) & (T)~(T)0/3); - v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3); - v = (v + (v >> 4)) & (T)~(T)0/255*15; - return (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * 8; + // from https://graphics.stanford.edu/~seander/bithacks.html + // GCC has this built in, but MSVC's intrinsic will only emit the actual + // POPCNT instruction, which we're not depending on + v = v - ((v >> 1) & (T) ~(T)0 / 3); + v = (v & (T) ~(T)0 / 15 * 3) + ((v >> 2) & (T) ~(T)0 / 15 * 3); + v = (v + (v >> 4)) & (T) ~(T)0 / 255 * 15; + return (T)(v * ((T) ~(T)0 / 255)) >> (sizeof(T) - 1) * 8; } static inline int LeastSignificantSetBit(u8 val) { - unsigned long index; - _BitScanForward(&index, val); - return (int)index; + unsigned long index; + _BitScanForward(&index, val); + return (int)index; } static inline int LeastSignificantSetBit(u16 val) { - unsigned long index; - _BitScanForward(&index, val); - return (int)index; + unsigned long index; + _BitScanForward(&index, val); + return (int)index; } static inline int LeastSignificantSetBit(u32 val) { - unsigned long index; - _BitScanForward(&index, val); - return (int)index; + unsigned long index; + _BitScanForward(&index, val); + return (int)index; } static inline int LeastSignificantSetBit(u64 val) { - unsigned long index; - _BitScanForward64(&index, val); - return (int)index; + unsigned long index; + _BitScanForward64(&index, val); + return (int)index; } #else -static inline int CountSetBits(u8 val) { return __builtin_popcount(val); } -static inline int CountSetBits(u16 val) { return __builtin_popcount(val); } -static inline int CountSetBits(u32 val) { return __builtin_popcount(val); } -static inline int CountSetBits(u64 val) { return __builtin_popcountll(val); } -static inline int LeastSignificantSetBit(u8 val) { return __builtin_ctz(val); } -static inline int LeastSignificantSetBit(u16 val) { return __builtin_ctz(val); } -static inline int LeastSignificantSetBit(u32 val) { return __builtin_ctz(val); } -static inline int LeastSignificantSetBit(u64 val) { return __builtin_ctzll(val); } +static inline int CountSetBits(u8 val) +{ + return __builtin_popcount(val); +} +static inline int CountSetBits(u16 val) +{ + return __builtin_popcount(val); +} +static inline int CountSetBits(u32 val) +{ + return __builtin_popcount(val); +} +static inline int CountSetBits(u64 val) +{ + return __builtin_popcountll(val); +} +static inline int LeastSignificantSetBit(u8 val) +{ + return __builtin_ctz(val); +} +static inline int LeastSignificantSetBit(u16 val) +{ + return __builtin_ctz(val); +} +static inline int LeastSignificantSetBit(u32 val) +{ + return __builtin_ctz(val); +} +static inline int LeastSignificantSetBit(u64 val) +{ + return __builtin_ctzll(val); +} #endif // namespace avoids conflict with OS X Carbon; don't use BitSet directly namespace BS { - // Similar to std::bitset, this is a class which encapsulates a bitset, i.e. // using the set bits of an integer to represent a set of integers. Like that // class, it acts like an array of bools: @@ -86,101 +109,107 @@ namespace BS template class BitSet { - static_assert(!std::is_signed::value, "BitSet should not be used with signed types"); + static_assert(!std::is_signed::value, "BitSet should not be used with signed types"); + public: - // A reference to a particular bit, returned from operator[]. - class Ref - { - public: - Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {} - Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {} - operator bool() const { return (m_bs->m_val & m_mask) != 0; } - bool operator=(bool set) - { - m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0); - return set; - } - private: - BitSet* m_bs; - IntTy m_mask; - }; + // A reference to a particular bit, returned from operator[]. + class Ref + { + public: + Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {} + Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {} + operator bool() const { return (m_bs->m_val & m_mask) != 0; } + bool operator=(bool set) + { + m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0); + return set; + } - // A STL-like iterator is required to be able to use range-based for loops. - class Iterator - { - public: - Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {} - Iterator(IntTy val, int bit) : m_val(val), m_bit(bit) {} - Iterator& operator=(Iterator other) { new (this) Iterator(other); return *this; } - int operator*() { return m_bit; } - Iterator& operator++() - { - if (m_val == 0) - { - m_bit = -1; - } - else - { - int bit = LeastSignificantSetBit(m_val); - m_val &= ~(1 << bit); - m_bit = bit; - } - return *this; - } - Iterator operator++(int _) - { - Iterator other(*this); - ++*this; - return other; - } - bool operator==(Iterator other) const { return m_bit == other.m_bit; } - bool operator!=(Iterator other) const { return m_bit != other.m_bit; } - private: - IntTy m_val; - int m_bit; - }; + private: + BitSet* m_bs; + IntTy m_mask; + }; - BitSet() : m_val(0) {} - explicit BitSet(IntTy val) : m_val(val) {} - BitSet(std::initializer_list init) - { - m_val = 0; - for (int bit : init) - m_val |= (IntTy)1 << bit; - } + // A STL-like iterator is required to be able to use range-based for loops. + class Iterator + { + public: + Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {} + Iterator(IntTy val, int bit) : m_val(val), m_bit(bit) {} + Iterator& operator=(Iterator other) + { + new (this) Iterator(other); + return *this; + } + int operator*() { return m_bit; } + Iterator& operator++() + { + if (m_val == 0) + { + m_bit = -1; + } + else + { + int bit = LeastSignificantSetBit(m_val); + m_val &= ~(1 << bit); + m_bit = bit; + } + return *this; + } + Iterator operator++(int _) + { + Iterator other(*this); + ++*this; + return other; + } + bool operator==(Iterator other) const { return m_bit == other.m_bit; } + bool operator!=(Iterator other) const { return m_bit != other.m_bit; } + private: + IntTy m_val; + int m_bit; + }; - static BitSet AllTrue(size_t count) - { - return BitSet(count == sizeof(IntTy)*8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1)); - } + BitSet() : m_val(0) {} + explicit BitSet(IntTy val) : m_val(val) {} + BitSet(std::initializer_list init) + { + m_val = 0; + for (int bit : init) + m_val |= (IntTy)1 << bit; + } - Ref operator[](size_t bit) { return Ref(this, (IntTy)1 << bit); } - const Ref operator[](size_t bit) const { return (*const_cast(this))[bit]; } - bool operator==(BitSet other) const { return m_val == other.m_val; } - bool operator!=(BitSet other) const { return m_val != other.m_val; } - bool operator<(BitSet other) const { return m_val < other.m_val; } - bool operator>(BitSet other) const { return m_val > other.m_val; } - BitSet operator|(BitSet other) const { return BitSet(m_val | other.m_val); } - BitSet operator&(BitSet other) const { return BitSet(m_val & other.m_val); } - BitSet operator^(BitSet other) const { return BitSet(m_val ^ other.m_val); } - BitSet operator~() const { return BitSet(~m_val); } - BitSet& operator|=(BitSet other) { return *this = *this | other; } - BitSet& operator&=(BitSet other) { return *this = *this & other; } - BitSet& operator^=(BitSet other) { return *this = *this ^ other; } - explicit operator bool() const { return m_val != 0; } + static BitSet AllTrue(size_t count) + { + return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1)); + } - // Warning: Even though on modern CPUs this is a single fast instruction, - // Dolphin's official builds do not currently assume POPCNT support on x86, - // so slower explicit bit twiddling is generated. Still should generally - // be faster than a loop. - unsigned int Count() const { return CountSetBits(m_val); } - - Iterator begin() const { Iterator it(m_val, 0); return ++it; } - Iterator end() const { return Iterator(m_val, -1); } - - IntTy m_val; + Ref operator[](size_t bit) { return Ref(this, (IntTy)1 << bit); } + const Ref operator[](size_t bit) const { return (*const_cast(this))[bit]; } + bool operator==(BitSet other) const { return m_val == other.m_val; } + bool operator!=(BitSet other) const { return m_val != other.m_val; } + bool operator<(BitSet other) const { return m_val < other.m_val; } + bool operator>(BitSet other) const { return m_val > other.m_val; } + BitSet operator|(BitSet other) const { return BitSet(m_val | other.m_val); } + BitSet operator&(BitSet other) const { return BitSet(m_val & other.m_val); } + BitSet operator^(BitSet other) const { return BitSet(m_val ^ other.m_val); } + BitSet operator~() const { return BitSet(~m_val); } + BitSet& operator|=(BitSet other) { return *this = *this | other; } + BitSet& operator&=(BitSet other) { return *this = *this & other; } + BitSet& operator^=(BitSet other) { return *this = *this ^ other; } + explicit operator bool() const { return m_val != 0; } + // Warning: Even though on modern CPUs this is a single fast instruction, + // Dolphin's official builds do not currently assume POPCNT support on x86, + // so slower explicit bit twiddling is generated. Still should generally + // be faster than a loop. + unsigned int Count() const { return CountSetBits(m_val); } + Iterator begin() const + { + Iterator it(m_val, 0); + return ++it; + } + Iterator end() const { return Iterator(m_val, -1); } + IntTy m_val; }; - } typedef BS::BitSet BitSet8; diff --git a/Source/Core/Common/BlockingLoop.h b/Source/Core/Common/BlockingLoop.h index 7d4fec495b..da148fccd4 100644 --- a/Source/Core/Common/BlockingLoop.h +++ b/Source/Core/Common/BlockingLoop.h @@ -13,207 +13,197 @@ namespace Common { - // This class provides a synchronized loop. // It's a thread-safe way to trigger a new iteration without busy loops. -// It's optimized for high-usage iterations which usually are already running while it's triggered often. -// Be careful when using Wait() and Wakeup() at the same time. Wait() may block forever while Wakeup() is called regularly. +// It's optimized for high-usage iterations which usually are already running while it's triggered +// often. +// Be careful when using Wait() and Wakeup() at the same time. Wait() may block forever while +// Wakeup() is called regularly. class BlockingLoop { public: - BlockingLoop() - { - m_stopped.Set(); - } + BlockingLoop() { m_stopped.Set(); } + ~BlockingLoop() { Stop(); } + // Triggers to rerun the payload of the Run() function at least once again. + // This function will never block and is designed to finish as fast as possible. + void Wakeup() + { + // Already running, so no need for a wakeup. + // This is the common case, so try to get this as fast as possible. + if (m_running_state.load() >= STATE_NEED_EXECUTION) + return; - ~BlockingLoop() - { - Stop(); - } + // Mark that new data is available. If the old state will rerun the payload + // itself, we don't have to set the event to interrupt the worker. + if (m_running_state.exchange(STATE_NEED_EXECUTION) != STATE_SLEEPING) + return; - // Triggers to rerun the payload of the Run() function at least once again. - // This function will never block and is designed to finish as fast as possible. - void Wakeup() - { - // Already running, so no need for a wakeup. - // This is the common case, so try to get this as fast as possible. - if (m_running_state.load() >= STATE_NEED_EXECUTION) - return; + // Else as the worker thread may sleep now, we have to set the event. + m_new_work_event.Set(); + } - // Mark that new data is available. If the old state will rerun the payload - // itself, we don't have to set the event to interrupt the worker. - if (m_running_state.exchange(STATE_NEED_EXECUTION) != STATE_SLEEPING) - return; + // Wait for a complete payload run after the last Wakeup() call. + // If stopped, this returns immediately. + void Wait() + { + // already done + if (IsDone()) + return; - // Else as the worker thread may sleep now, we have to set the event. - m_new_work_event.Set(); - } + // notifying this event will only wake up one thread, so use a mutex here to + // allow only one waiting thread. And in this way, we get an event free wakeup + // but for the first thread for free + std::lock_guard lk(m_wait_lock); - // Wait for a complete payload run after the last Wakeup() call. - // If stopped, this returns immediately. - void Wait() - { - // already done - if (IsDone()) - return; + // Wait for the worker thread to finish. + while (!IsDone()) + { + m_done_event.Wait(); + } - // notifying this event will only wake up one thread, so use a mutex here to - // allow only one waiting thread. And in this way, we get an event free wakeup - // but for the first thread for free - std::lock_guard lk(m_wait_lock); + // As we wanted to wait for the other thread, there is likely no work remaining. + // So there is no need for a busy loop any more. + m_may_sleep.Set(); + } - // Wait for the worker thread to finish. - while (!IsDone()) - { - m_done_event.Wait(); - } + // Half start the worker. + // So this object is in a running state and Wait() will block until the worker calls Run(). + // This may be called from any thread and is supposed to be called at least once before Wait() is + // used. + void Prepare() + { + // There is a race condition if the other threads call this function while + // the loop thread is initializing. Using this lock will ensure a valid state. + std::lock_guard lk(m_prepare_lock); - // As we wanted to wait for the other thread, there is likely no work remaining. - // So there is no need for a busy loop any more. - m_may_sleep.Set(); - } + if (!m_stopped.TestAndClear()) + return; + m_running_state.store( + STATE_LAST_EXECUTION); // so the payload will only be executed once without any Wakeup call + m_shutdown.Clear(); + m_may_sleep.Set(); + } - // Half start the worker. - // So this object is in a running state and Wait() will block until the worker calls Run(). - // This may be called from any thread and is supposed to be called at least once before Wait() is used. - void Prepare() - { - // There is a race condition if the other threads call this function while - // the loop thread is initializing. Using this lock will ensure a valid state. - std::lock_guard lk(m_prepare_lock); + // Main loop of this object. + // The payload callback is called at least as often as it's needed to match the Wakeup() + // requirements. + // The optional timeout parameter is a timeout for how periodically the payload should be called. + // Use timeout = 0 to run without a timeout at all. + template + void Run(F payload, int64_t timeout = 0) + { + // Asserts that Prepare is called at least once before we enter the loop. + // But a good implementation should call this before already. + Prepare(); - if (!m_stopped.TestAndClear()) - return; - m_running_state.store(STATE_LAST_EXECUTION); // so the payload will only be executed once without any Wakeup call - m_shutdown.Clear(); - m_may_sleep.Set(); - } + while (!m_shutdown.IsSet()) + { + payload(); - // Main loop of this object. - // The payload callback is called at least as often as it's needed to match the Wakeup() requirements. - // The optional timeout parameter is a timeout for how periodically the payload should be called. - // Use timeout = 0 to run without a timeout at all. - template void Run(F payload, int64_t timeout = 0) - { - // Asserts that Prepare is called at least once before we enter the loop. - // But a good implementation should call this before already. - Prepare(); + switch (m_running_state.load()) + { + case STATE_NEED_EXECUTION: + // We won't get notified while we are in the STATE_NEED_EXECUTION state, so maybe Wakeup was + // called. + // So we have to assume on finishing the STATE_NEED_EXECUTION state, that there may be some + // remaining tasks. + // To process this tasks, we call the payload again within the STATE_LAST_EXECUTION state. + m_running_state--; + break; - while (!m_shutdown.IsSet()) - { - payload(); + case STATE_LAST_EXECUTION: + // If we're still in the STATE_LAST_EXECUTION state, then Wakeup wasn't called within the + // last + // execution of the payload. This means we should be ready now. + // But bad luck, Wakeup may have been called right now. So break and rerun the payload + // if the state was touched. + if (m_running_state-- != STATE_LAST_EXECUTION) + break; - switch (m_running_state.load()) - { - case STATE_NEED_EXECUTION: - // We won't get notified while we are in the STATE_NEED_EXECUTION state, so maybe Wakeup was called. - // So we have to assume on finishing the STATE_NEED_EXECUTION state, that there may be some remaining tasks. - // To process this tasks, we call the payload again within the STATE_LAST_EXECUTION state. - m_running_state--; - break; + // Else we're likely in the STATE_DONE state now, so wakeup the waiting threads right now. + // However, if we're not in the STATE_DONE state any more, the event should also be + // triggered so that we'll skip the next waiting call quite fast. + m_done_event.Set(); - case STATE_LAST_EXECUTION: - // If we're still in the STATE_LAST_EXECUTION state, then Wakeup wasn't called within the last - // execution of the payload. This means we should be ready now. - // But bad luck, Wakeup may have been called right now. So break and rerun the payload - // if the state was touched. - if (m_running_state-- != STATE_LAST_EXECUTION) - break; + case STATE_DONE: + // We're done now. So time to check if we want to sleep or if we want to stay in a busy + // loop. + if (m_may_sleep.TestAndClear()) + { + // Try to set the sleeping state. + if (m_running_state-- != STATE_DONE) + break; + } + else + { + // Busy loop. + break; + } - // Else we're likely in the STATE_DONE state now, so wakeup the waiting threads right now. - // However, if we're not in the STATE_DONE state any more, the event should also be - // triggered so that we'll skip the next waiting call quite fast. - m_done_event.Set(); + case STATE_SLEEPING: + // Just relax + if (timeout > 0) + { + m_new_work_event.WaitFor(std::chrono::milliseconds(timeout)); + } + else + { + m_new_work_event.Wait(); + } + break; + } + } - case STATE_DONE: - // We're done now. So time to check if we want to sleep or if we want to stay in a busy loop. - if (m_may_sleep.TestAndClear()) - { - // Try to set the sleeping state. - if (m_running_state-- != STATE_DONE) - break; - } - else - { - // Busy loop. - break; - } + // Shutdown down, so get a safe state + m_running_state.store(STATE_DONE); + m_stopped.Set(); - case STATE_SLEEPING: - // Just relax - if (timeout > 0) - { - m_new_work_event.WaitFor(std::chrono::milliseconds(timeout)); - } - else - { - m_new_work_event.Wait(); - } - break; - } - } + // Wake up the last Wait calls. + m_done_event.Set(); + } - // Shutdown down, so get a safe state - m_running_state.store(STATE_DONE); - m_stopped.Set(); + // Quits the main loop. + // By default, it will wait until the main loop quits. + // Be careful to not use the blocking way within the payload of the Run() method. + void Stop(bool block = true) + { + if (m_stopped.IsSet()) + return; - // Wake up the last Wait calls. - m_done_event.Set(); - } + m_shutdown.Set(); - // Quits the main loop. - // By default, it will wait until the main loop quits. - // Be careful to not use the blocking way within the payload of the Run() method. - void Stop(bool block = true) - { - if (m_stopped.IsSet()) - return; + // We have to interrupt the sleeping call to let the worker shut down soon. + Wakeup(); - m_shutdown.Set(); - - // We have to interrupt the sleeping call to let the worker shut down soon. - Wakeup(); - - if (block) - Wait(); - } - - bool IsRunning() const - { - return !m_stopped.IsSet() && !m_shutdown.IsSet(); - } - - bool IsDone() const - { - return m_stopped.IsSet() || m_running_state.load() <= STATE_DONE; - } - - // This function should be triggered regularly over time so - // that we will fall back from the busy loop to sleeping. - void AllowSleep() - { - m_may_sleep.Set(); - } + if (block) + Wait(); + } + bool IsRunning() const { return !m_stopped.IsSet() && !m_shutdown.IsSet(); } + bool IsDone() const { return m_stopped.IsSet() || m_running_state.load() <= STATE_DONE; } + // This function should be triggered regularly over time so + // that we will fall back from the busy loop to sleeping. + void AllowSleep() { m_may_sleep.Set(); } private: - std::mutex m_wait_lock; - std::mutex m_prepare_lock; + std::mutex m_wait_lock; + std::mutex m_prepare_lock; - Flag m_stopped; // If this is set, Wait() shall not block. - Flag m_shutdown; // If this is set, the loop shall end. + Flag m_stopped; // If this is set, Wait() shall not block. + Flag m_shutdown; // If this is set, the loop shall end. - Event m_new_work_event; - Event m_done_event; + Event m_new_work_event; + Event m_done_event; - enum RUNNING_TYPE { - STATE_SLEEPING = 0, - STATE_DONE = 1, - STATE_LAST_EXECUTION = 2, - STATE_NEED_EXECUTION = 3 - }; - std::atomic m_running_state; // must be of type RUNNING_TYPE + enum RUNNING_TYPE + { + STATE_SLEEPING = 0, + STATE_DONE = 1, + STATE_LAST_EXECUTION = 2, + STATE_NEED_EXECUTION = 3 + }; + std::atomic m_running_state; // must be of type RUNNING_TYPE - Flag m_may_sleep; // If this is set, we fall back from the busy loop to an event based synchronization. + Flag m_may_sleep; // If this is set, we fall back from the busy loop to an event based + // synchronization. }; - } diff --git a/Source/Core/Common/BreakPoints.cpp b/Source/Core/Common/BreakPoints.cpp index 59ea6864d2..769afcfcf0 100644 --- a/Source/Core/Common/BreakPoints.cpp +++ b/Source/Core/Common/BreakPoints.cpp @@ -14,297 +14,295 @@ bool BreakPoints::IsAddressBreakPoint(u32 address) const { - for (const TBreakPoint& bp : m_BreakPoints) - if (bp.iAddress == address) - return true; + for (const TBreakPoint& bp : m_BreakPoints) + if (bp.iAddress == address) + return true; - return false; + return false; } bool BreakPoints::IsTempBreakPoint(u32 address) const { - for (const TBreakPoint& bp : m_BreakPoints) - if (bp.iAddress == address && bp.bTemporary) - return true; + for (const TBreakPoint& bp : m_BreakPoints) + if (bp.iAddress == address && bp.bTemporary) + return true; - return false; + return false; } BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const { - TBreakPointsStr bps; - for (const TBreakPoint& bp : m_BreakPoints) - { - if (!bp.bTemporary) - { - std::stringstream ss; - ss << std::hex << bp.iAddress << " " << (bp.bOn ? "n" : ""); - bps.push_back(ss.str()); - } - } + TBreakPointsStr bps; + for (const TBreakPoint& bp : m_BreakPoints) + { + if (!bp.bTemporary) + { + std::stringstream ss; + ss << std::hex << bp.iAddress << " " << (bp.bOn ? "n" : ""); + bps.push_back(ss.str()); + } + } - return bps; + return bps; } void BreakPoints::AddFromStrings(const TBreakPointsStr& bpstrs) { - for (const std::string& bpstr : bpstrs) - { - TBreakPoint bp; - std::stringstream ss; - ss << std::hex << bpstr; - ss >> bp.iAddress; - bp.bOn = bpstr.find("n") != bpstr.npos; - bp.bTemporary = false; - Add(bp); - } + for (const std::string& bpstr : bpstrs) + { + TBreakPoint bp; + std::stringstream ss; + ss << std::hex << bpstr; + ss >> bp.iAddress; + bp.bOn = bpstr.find("n") != bpstr.npos; + bp.bTemporary = false; + Add(bp); + } } void BreakPoints::Add(const TBreakPoint& bp) { - if (!IsAddressBreakPoint(bp.iAddress)) - { - m_BreakPoints.push_back(bp); - if (jit) - jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4, true); - } + if (!IsAddressBreakPoint(bp.iAddress)) + { + m_BreakPoints.push_back(bp); + if (jit) + jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4, true); + } } void BreakPoints::Add(u32 em_address, bool temp) { - if (!IsAddressBreakPoint(em_address)) // only add new addresses - { - TBreakPoint pt; // breakpoint settings - pt.bOn = true; - pt.bTemporary = temp; - pt.iAddress = em_address; + if (!IsAddressBreakPoint(em_address)) // only add new addresses + { + TBreakPoint pt; // breakpoint settings + pt.bOn = true; + pt.bTemporary = temp; + pt.iAddress = em_address; - m_BreakPoints.push_back(pt); + m_BreakPoints.push_back(pt); - if (jit) - jit->GetBlockCache()->InvalidateICache(em_address, 4, true); - } + if (jit) + jit->GetBlockCache()->InvalidateICache(em_address, 4, true); + } } void BreakPoints::Remove(u32 em_address) { - for (auto i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) - { - if (i->iAddress == em_address) - { - m_BreakPoints.erase(i); - if (jit) - jit->GetBlockCache()->InvalidateICache(em_address, 4, true); - return; - } - } + for (auto i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) + { + if (i->iAddress == em_address) + { + m_BreakPoints.erase(i); + if (jit) + jit->GetBlockCache()->InvalidateICache(em_address, 4, true); + return; + } + } } void BreakPoints::Clear() { - if (jit) - { - for (const TBreakPoint& bp : m_BreakPoints) - { - jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4, true); - } - } + if (jit) + { + for (const TBreakPoint& bp : m_BreakPoints) + { + jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4, true); + } + } - m_BreakPoints.clear(); + m_BreakPoints.clear(); } void BreakPoints::ClearAllTemporary() { - for (const TBreakPoint& bp : m_BreakPoints) - { - if (bp.bTemporary) - { - if (jit) - jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4, true); - Remove(bp.iAddress); - } - } + for (const TBreakPoint& bp : m_BreakPoints) + { + if (bp.bTemporary) + { + if (jit) + jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4, true); + Remove(bp.iAddress); + } + } } MemChecks::TMemChecksStr MemChecks::GetStrings() const { - TMemChecksStr mcs; - for (const TMemCheck& bp : m_MemChecks) - { - std::stringstream mc; - mc << std::hex << bp.StartAddress; - mc << " " << (bp.bRange ? bp.EndAddress : bp.StartAddress) << " " << - (bp.bRange ? "n" : "") << (bp.OnRead ? "r" : "") << - (bp.OnWrite ? "w" : "") << (bp.Log ? "l" : "") << (bp.Break ? "p" : ""); - mcs.push_back(mc.str()); - } + TMemChecksStr mcs; + for (const TMemCheck& bp : m_MemChecks) + { + std::stringstream mc; + mc << std::hex << bp.StartAddress; + mc << " " << (bp.bRange ? bp.EndAddress : bp.StartAddress) << " " << (bp.bRange ? "n" : "") + << (bp.OnRead ? "r" : "") << (bp.OnWrite ? "w" : "") << (bp.Log ? "l" : "") + << (bp.Break ? "p" : ""); + mcs.push_back(mc.str()); + } - return mcs; + return mcs; } void MemChecks::AddFromStrings(const TMemChecksStr& mcstrs) { - for (const std::string& mcstr : mcstrs) - { - TMemCheck mc; - std::stringstream ss; - ss << std::hex << mcstr; - ss >> mc.StartAddress; - mc.bRange = mcstr.find("n") != mcstr.npos; - mc.OnRead = mcstr.find("r") != mcstr.npos; - mc.OnWrite = mcstr.find("w") != mcstr.npos; - mc.Log = mcstr.find("l") != mcstr.npos; - mc.Break = mcstr.find("p") != mcstr.npos; - if (mc.bRange) - ss >> mc.EndAddress; - else - mc.EndAddress = mc.StartAddress; - Add(mc); - } + for (const std::string& mcstr : mcstrs) + { + TMemCheck mc; + std::stringstream ss; + ss << std::hex << mcstr; + ss >> mc.StartAddress; + mc.bRange = mcstr.find("n") != mcstr.npos; + mc.OnRead = mcstr.find("r") != mcstr.npos; + mc.OnWrite = mcstr.find("w") != mcstr.npos; + mc.Log = mcstr.find("l") != mcstr.npos; + mc.Break = mcstr.find("p") != mcstr.npos; + if (mc.bRange) + ss >> mc.EndAddress; + else + mc.EndAddress = mc.StartAddress; + Add(mc); + } } void MemChecks::Add(const TMemCheck& _rMemoryCheck) { - bool had_any = HasAny(); - if (GetMemCheck(_rMemoryCheck.StartAddress) == nullptr) - m_MemChecks.push_back(_rMemoryCheck); - // If this is the first one, clear the JIT cache so it can switch to - // watchpoint-compatible code. - if (!had_any && jit) - jit->ClearCache(); + bool had_any = HasAny(); + if (GetMemCheck(_rMemoryCheck.StartAddress) == nullptr) + m_MemChecks.push_back(_rMemoryCheck); + // If this is the first one, clear the JIT cache so it can switch to + // watchpoint-compatible code. + if (!had_any && jit) + jit->ClearCache(); } void MemChecks::Remove(u32 _Address) { - for (auto i = m_MemChecks.begin(); i != m_MemChecks.end(); ++i) - { - if (i->StartAddress == _Address) - { - m_MemChecks.erase(i); - return; - } - } - if (!HasAny() && jit) - jit->ClearCache(); + for (auto i = m_MemChecks.begin(); i != m_MemChecks.end(); ++i) + { + if (i->StartAddress == _Address) + { + m_MemChecks.erase(i); + return; + } + } + if (!HasAny() && jit) + jit->ClearCache(); } TMemCheck* MemChecks::GetMemCheck(u32 address) { - for (TMemCheck& bp : m_MemChecks) - { - if (bp.bRange) - { - if (address >= bp.StartAddress && address <= bp.EndAddress) - return &(bp); - } - else if (bp.StartAddress == address) - { - return &(bp); - } - } + for (TMemCheck& bp : m_MemChecks) + { + if (bp.bRange) + { + if (address >= bp.StartAddress && address <= bp.EndAddress) + return &(bp); + } + else if (bp.StartAddress == address) + { + return &(bp); + } + } - // none found - return nullptr; + // none found + return nullptr; } -bool TMemCheck::Action(DebugInterface* debug_interface, u32 iValue, u32 addr, bool write, int size, u32 pc) +bool TMemCheck::Action(DebugInterface* debug_interface, u32 iValue, u32 addr, bool write, int size, + u32 pc) { - if ((write && OnWrite) || (!write && OnRead)) - { - if (Log) - { - INFO_LOG(MEMMAP, "CHK %08x (%s) %s%i %0*x at %08x (%s)", - pc, debug_interface->GetDescription(pc).c_str(), - write ? "Write" : "Read", size*8, size*2, iValue, addr, - debug_interface->GetDescription(addr).c_str() - ); - } + if ((write && OnWrite) || (!write && OnRead)) + { + if (Log) + { + INFO_LOG(MEMMAP, "CHK %08x (%s) %s%i %0*x at %08x (%s)", pc, + debug_interface->GetDescription(pc).c_str(), write ? "Write" : "Read", size * 8, + size * 2, iValue, addr, debug_interface->GetDescription(addr).c_str()); + } - return true; - } - return false; + return true; + } + return false; } - bool Watches::IsAddressWatch(u32 _iAddress) const { - for (const TWatch& bp : m_Watches) - if (bp.iAddress == _iAddress) - return true; + for (const TWatch& bp : m_Watches) + if (bp.iAddress == _iAddress) + return true; - return false; + return false; } Watches::TWatchesStr Watches::GetStrings() const { - TWatchesStr bps; - for (const TWatch& bp : m_Watches) - { - std::stringstream ss; - ss << std::hex << bp.iAddress << " " << bp.name; - bps.push_back(ss.str()); - } + TWatchesStr bps; + for (const TWatch& bp : m_Watches) + { + std::stringstream ss; + ss << std::hex << bp.iAddress << " " << bp.name; + bps.push_back(ss.str()); + } - return bps; + return bps; } void Watches::AddFromStrings(const TWatchesStr& bpstrs) { - for (const std::string& bpstr : bpstrs) - { - TWatch bp; - std::stringstream ss; - ss << std::hex << bpstr; - ss >> bp.iAddress; - ss >> std::ws; - getline(ss, bp.name); - Add(bp); - } + for (const std::string& bpstr : bpstrs) + { + TWatch bp; + std::stringstream ss; + ss << std::hex << bpstr; + ss >> bp.iAddress; + ss >> std::ws; + getline(ss, bp.name); + Add(bp); + } } void Watches::Add(const TWatch& bp) { - if (!IsAddressWatch(bp.iAddress)) - { - m_Watches.push_back(bp); - } + if (!IsAddressWatch(bp.iAddress)) + { + m_Watches.push_back(bp); + } } void Watches::Add(u32 em_address) { - if (!IsAddressWatch(em_address)) // only add new addresses - { - TWatch pt; // breakpoint settings - pt.bOn = true; - pt.iAddress = em_address; + if (!IsAddressWatch(em_address)) // only add new addresses + { + TWatch pt; // breakpoint settings + pt.bOn = true; + pt.iAddress = em_address; - m_Watches.push_back(pt); - } + m_Watches.push_back(pt); + } } void Watches::Update(int count, u32 em_address) { - m_Watches.at(count).iAddress = em_address; + m_Watches.at(count).iAddress = em_address; } void Watches::UpdateName(int count, const std::string name) { - m_Watches.at(count).name = name; + m_Watches.at(count).name = name; } void Watches::Remove(u32 em_address) { - for (auto i = m_Watches.begin(); i != m_Watches.end(); ++i) - { - if (i->iAddress == em_address) - { - m_Watches.erase(i); - return; - } - } + for (auto i = m_Watches.begin(); i != m_Watches.end(); ++i) + { + if (i->iAddress == em_address) + { + m_Watches.erase(i); + return; + } + } } void Watches::Clear() { - m_Watches.clear(); + m_Watches.clear(); } diff --git a/Source/Core/Common/BreakPoints.h b/Source/Core/Common/BreakPoints.h index d7592ee54b..186236b23c 100644 --- a/Source/Core/Common/BreakPoints.h +++ b/Source/Core/Common/BreakPoints.h @@ -13,124 +13,118 @@ class DebugInterface; struct TBreakPoint { - u32 iAddress; - bool bOn; - bool bTemporary; + u32 iAddress; + bool bOn; + bool bTemporary; }; struct TMemCheck { - TMemCheck() - { - numHits = 0; - StartAddress = EndAddress = 0; - bRange = OnRead = OnWrite = Log = Break = false; - } + TMemCheck() + { + numHits = 0; + StartAddress = EndAddress = 0; + bRange = OnRead = OnWrite = Log = Break = false; + } - u32 StartAddress; - u32 EndAddress; + u32 StartAddress; + u32 EndAddress; - bool bRange; + bool bRange; - bool OnRead; - bool OnWrite; + bool OnRead; + bool OnWrite; - bool Log; - bool Break; + bool Log; + bool Break; - u32 numHits; + u32 numHits; - // returns whether to break - bool Action(DebugInterface* dbg_interface, u32 _iValue, u32 addr, - bool write, int size, u32 pc); + // returns whether to break + bool Action(DebugInterface* dbg_interface, u32 _iValue, u32 addr, bool write, int size, u32 pc); }; struct TWatch { - std::string name = ""; - u32 iAddress; - bool bOn; + std::string name = ""; + u32 iAddress; + bool bOn; }; // Code breakpoints. class BreakPoints { public: - typedef std::vector TBreakPoints; - typedef std::vector TBreakPointsStr; + typedef std::vector TBreakPoints; + typedef std::vector TBreakPointsStr; - const TBreakPoints& GetBreakPoints() { return m_BreakPoints; } + const TBreakPoints& GetBreakPoints() { return m_BreakPoints; } + TBreakPointsStr GetStrings() const; + void AddFromStrings(const TBreakPointsStr& bps); - TBreakPointsStr GetStrings() const; - void AddFromStrings(const TBreakPointsStr& bps); + // is address breakpoint + bool IsAddressBreakPoint(u32 address) const; + bool IsTempBreakPoint(u32 address) const; - // is address breakpoint - bool IsAddressBreakPoint(u32 address) const; - bool IsTempBreakPoint(u32 address) const; + // Add BreakPoint + void Add(u32 em_address, bool temp = false); + void Add(const TBreakPoint& bp); - // Add BreakPoint - void Add(u32 em_address, bool temp = false); - void Add(const TBreakPoint& bp); - - // Remove Breakpoint - void Remove(u32 _iAddress); - void Clear(); - void ClearAllTemporary(); + // Remove Breakpoint + void Remove(u32 _iAddress); + void Clear(); + void ClearAllTemporary(); private: - TBreakPoints m_BreakPoints; + TBreakPoints m_BreakPoints; }; - // Memory breakpoints class MemChecks { public: - typedef std::vector TMemChecks; - typedef std::vector TMemChecksStr; + typedef std::vector TMemChecks; + typedef std::vector TMemChecksStr; - TMemChecks m_MemChecks; + TMemChecks m_MemChecks; - const TMemChecks& GetMemChecks() { return m_MemChecks; } + const TMemChecks& GetMemChecks() { return m_MemChecks; } + TMemChecksStr GetStrings() const; + void AddFromStrings(const TMemChecksStr& mcs); - TMemChecksStr GetStrings() const; - void AddFromStrings(const TMemChecksStr& mcs); + void Add(const TMemCheck& _rMemoryCheck); - void Add(const TMemCheck& _rMemoryCheck); + // memory breakpoint + TMemCheck* GetMemCheck(u32 address); + void Remove(u32 _Address); - // memory breakpoint - TMemCheck* GetMemCheck(u32 address); - void Remove(u32 _Address); - - void Clear() { m_MemChecks.clear(); } - - bool HasAny() const { return !m_MemChecks.empty(); } + void Clear() { m_MemChecks.clear(); } + bool HasAny() const { return !m_MemChecks.empty(); } }; class Watches { public: - typedef std::vector TWatches; - typedef std::vector TWatchesStr; + typedef std::vector TWatches; + typedef std::vector TWatchesStr; - const TWatches& GetWatches() { return m_Watches; } + const TWatches& GetWatches() { return m_Watches; } + TWatchesStr GetStrings() const; + void AddFromStrings(const TWatchesStr& bps); - TWatchesStr GetStrings() const; - void AddFromStrings(const TWatchesStr& bps); + bool IsAddressWatch(u32 _iAddress) const; - bool IsAddressWatch(u32 _iAddress) const; + // Add BreakPoint + void Add(u32 em_address); + void Add(const TWatch& bp); - // Add BreakPoint - void Add(u32 em_address); - void Add(const TWatch& bp); + void Update(int count, u32 em_address); + void UpdateName(int count, const std::string name); - void Update(int count, u32 em_address); - void UpdateName(int count, const std::string name); - - // Remove Breakpoint - void Remove(u32 _iAddress); - void Clear(); + // Remove Breakpoint + void Remove(u32 _iAddress); + void Clear(); private: - TWatches m_Watches; + TWatches m_Watches; }; diff --git a/Source/Core/Common/CDUtils.cpp b/Source/Core/Common/CDUtils.cpp index 9ea5c23a1f..c829189cf9 100644 --- a/Source/Core/Common/CDUtils.cpp +++ b/Source/Core/Common/CDUtils.cpp @@ -25,10 +25,10 @@ #include #else #include -#include #include +#include #include -#endif // WIN32 +#endif // WIN32 #ifdef __linux__ #include @@ -38,171 +38,163 @@ // takes a root drive path, returns true if it is a cdrom drive bool is_cdrom(const TCHAR* drive) { - return (DRIVE_CDROM == GetDriveType(drive)); + return (DRIVE_CDROM == GetDriveType(drive)); } // Returns a vector with the device names std::vector cdio_get_devices() { - std::vector drives; + std::vector drives; - const DWORD buffsize = GetLogicalDriveStrings(0, nullptr); - std::vector buff(buffsize); - if (GetLogicalDriveStrings(buffsize, buff.data()) == buffsize - 1) - { - auto drive = buff.data(); - while (*drive) - { - if (is_cdrom(drive)) - { - std::string str(TStrToUTF8(drive)); - str.pop_back(); // we don't want the final backslash - drives.push_back(std::move(str)); - } + const DWORD buffsize = GetLogicalDriveStrings(0, nullptr); + std::vector buff(buffsize); + if (GetLogicalDriveStrings(buffsize, buff.data()) == buffsize - 1) + { + auto drive = buff.data(); + while (*drive) + { + if (is_cdrom(drive)) + { + std::string str(TStrToUTF8(drive)); + str.pop_back(); // we don't want the final backslash + drives.push_back(std::move(str)); + } - // advance to next drive - while (*drive++) {} - } - } - return drives; + // advance to next drive + while (*drive++) + { + } + } + } + return drives; } #elif defined __APPLE__ // Returns a pointer to an array of strings with the device names std::vector cdio_get_devices() { - io_object_t next_media; - mach_port_t master_port; - kern_return_t kern_result; - io_iterator_t media_iterator; - CFMutableDictionaryRef classes_to_match; - std::vector drives; + io_object_t next_media; + mach_port_t master_port; + kern_return_t kern_result; + io_iterator_t media_iterator; + CFMutableDictionaryRef classes_to_match; + std::vector drives; - kern_result = IOMasterPort(MACH_PORT_NULL, &master_port); - if (kern_result != KERN_SUCCESS) - return drives; + kern_result = IOMasterPort(MACH_PORT_NULL, &master_port); + if (kern_result != KERN_SUCCESS) + return drives; - classes_to_match = IOServiceMatching(kIOCDMediaClass); - if (classes_to_match == nullptr) - return drives; + classes_to_match = IOServiceMatching(kIOCDMediaClass); + if (classes_to_match == nullptr) + return drives; - CFDictionarySetValue(classes_to_match, - CFSTR(kIOMediaEjectableKey), kCFBooleanTrue); + CFDictionarySetValue(classes_to_match, CFSTR(kIOMediaEjectableKey), kCFBooleanTrue); - kern_result = IOServiceGetMatchingServices(master_port, - classes_to_match, &media_iterator); - if (kern_result != KERN_SUCCESS) - return drives; + kern_result = IOServiceGetMatchingServices(master_port, classes_to_match, &media_iterator); + if (kern_result != KERN_SUCCESS) + return drives; - next_media = IOIteratorNext(media_iterator); - if (next_media != 0) - { - CFTypeRef str_bsd_path; + next_media = IOIteratorNext(media_iterator); + if (next_media != 0) + { + CFTypeRef str_bsd_path; - do - { - str_bsd_path = - IORegistryEntryCreateCFProperty(next_media, - CFSTR(kIOBSDNameKey), kCFAllocatorDefault, - 0); - if (str_bsd_path == nullptr) - { - IOObjectRelease(next_media); - continue; - } + do + { + str_bsd_path = + IORegistryEntryCreateCFProperty(next_media, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0); + if (str_bsd_path == nullptr) + { + IOObjectRelease(next_media); + continue; + } - if (CFGetTypeID(str_bsd_path) == CFStringGetTypeID()) - { - size_t buf_size = CFStringGetLength((CFStringRef)str_bsd_path) * 4 + 1; - char* buf = new char[buf_size]; + if (CFGetTypeID(str_bsd_path) == CFStringGetTypeID()) + { + size_t buf_size = CFStringGetLength((CFStringRef)str_bsd_path) * 4 + 1; + char* buf = new char[buf_size]; - if (CFStringGetCString((CFStringRef)str_bsd_path, buf, buf_size, kCFStringEncodingUTF8)) - { - // Below, by appending 'r' to the BSD node name, we indicate - // a raw disk. Raw disks receive I/O requests directly and - // don't go through a buffer cache. - drives.push_back(std::string(_PATH_DEV "r") + buf); - } + if (CFStringGetCString((CFStringRef)str_bsd_path, buf, buf_size, kCFStringEncodingUTF8)) + { + // Below, by appending 'r' to the BSD node name, we indicate + // a raw disk. Raw disks receive I/O requests directly and + // don't go through a buffer cache. + drives.push_back(std::string(_PATH_DEV "r") + buf); + } - delete[] buf; - } - CFRelease(str_bsd_path); - IOObjectRelease(next_media); - } while ((next_media = IOIteratorNext(media_iterator)) != 0); - } - IOObjectRelease(media_iterator); - return drives; + delete[] buf; + } + CFRelease(str_bsd_path); + IOObjectRelease(next_media); + } while ((next_media = IOIteratorNext(media_iterator)) != 0); + } + IOObjectRelease(media_iterator); + return drives; } #else // checklist: /dev/cdrom, /dev/dvd /dev/hd?, /dev/scd? /dev/sr? static struct { - const char* format; - unsigned int num_min; - unsigned int num_max; -} checklist[] = - { + const char* format; + unsigned int num_min; + unsigned int num_max; +} checklist[] = { #ifdef __linux__ - { "/dev/cdrom", 0, 0 }, - { "/dev/dvd", 0, 0 }, - { "/dev/hd%c", 'a', 'z' }, - { "/dev/scd%d", 0, 27 }, - { "/dev/sr%d", 0, 27 }, + {"/dev/cdrom", 0, 0}, {"/dev/dvd", 0, 0}, {"/dev/hd%c", 'a', 'z'}, + {"/dev/scd%d", 0, 27}, {"/dev/sr%d", 0, 27}, #else - { "/dev/acd%d", 0, 27 }, - { "/dev/cd%d", 0, 27 }, + {"/dev/acd%d", 0, 27}, + {"/dev/cd%d", 0, 27}, #endif - { nullptr, 0, 0 } - }; + {nullptr, 0, 0}}; // Returns true if a device is a block or char device and not a symbolic link static bool is_device(const std::string& source_name) { - struct stat buf; - if (0 != lstat(source_name.c_str(), &buf)) - return false; + struct stat buf; + if (0 != lstat(source_name.c_str(), &buf)) + return false; - return ((S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode)) && - !S_ISLNK(buf.st_mode)); + return ((S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode)) && !S_ISLNK(buf.st_mode)); } // Check a device to see if it is a DVD/CD-ROM drive static bool is_cdrom(const std::string& drive, char* mnttype) { - // Check if the device exists - if (!is_device(drive)) - return false; + // Check if the device exists + if (!is_device(drive)) + return false; - bool is_cd = false; - // If it does exist, verify that it is a cdrom/dvd drive - int cdfd = open(drive.c_str(), (O_RDONLY | O_NONBLOCK), 0); - if (cdfd >= 0) - { + bool is_cd = false; + // If it does exist, verify that it is a cdrom/dvd drive + int cdfd = open(drive.c_str(), (O_RDONLY | O_NONBLOCK), 0); + if (cdfd >= 0) + { #ifdef __linux__ - if (ioctl(cdfd, CDROM_GET_CAPABILITY, 0) != -1) + if (ioctl(cdfd, CDROM_GET_CAPABILITY, 0) != -1) #endif - is_cd = true; - close(cdfd); - } - return is_cd; + is_cd = true; + close(cdfd); + } + return is_cd; } // Returns a pointer to an array of strings with the device names std::vector cdio_get_devices() { - std::vector drives; - // Scan the system for DVD/CD-ROM drives. - for (unsigned int i = 0; checklist[i].format; ++i) - { - for (unsigned int j = checklist[i].num_min; j <= checklist[i].num_max; ++j) - { - std::string drive = StringFromFormat(checklist[i].format, j); - if (is_cdrom(drive, nullptr)) - { - drives.push_back(std::move(drive)); - } - } - } - return drives; + std::vector drives; + // Scan the system for DVD/CD-ROM drives. + for (unsigned int i = 0; checklist[i].format; ++i) + { + for (unsigned int j = checklist[i].num_min; j <= checklist[i].num_max; ++j) + { + std::string drive = StringFromFormat(checklist[i].format, j); + if (is_cdrom(drive, nullptr)) + { + drives.push_back(std::move(drive)); + } + } + } + return drives; } #endif @@ -210,20 +202,20 @@ std::vector cdio_get_devices() bool cdio_is_cdrom(std::string device) { #ifndef _WIN32 - // Resolve symbolic links. This allows symbolic links to valid - // drives to be passed from the command line with the -e flag. - char resolved_path[MAX_PATH]; - char* devname = realpath(device.c_str(), resolved_path); - if (!devname) - return false; - device = devname; + // Resolve symbolic links. This allows symbolic links to valid + // drives to be passed from the command line with the -e flag. + char resolved_path[MAX_PATH]; + char* devname = realpath(device.c_str(), resolved_path); + if (!devname) + return false; + device = devname; #endif - std::vector devices = cdio_get_devices(); - for (const std::string& d : devices) - { - if (d == device) - return true; - } - return false; + std::vector devices = cdio_get_devices(); + for (const std::string& d : devices) + { + if (d == device) + return true; + } + return false; } diff --git a/Source/Core/Common/CPUDetect.h b/Source/Core/Common/CPUDetect.h index 4913c124ec..ab3162a5f5 100644 --- a/Source/Core/Common/CPUDetect.h +++ b/Source/Core/Common/CPUDetect.h @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // Detect the CPU, so we'll know which optimizations to use #pragma once @@ -10,68 +9,68 @@ enum CPUVendor { - VENDOR_INTEL = 0, - VENDOR_AMD = 1, - VENDOR_ARM = 2, - VENDOR_OTHER = 3, + VENDOR_INTEL = 0, + VENDOR_AMD = 1, + VENDOR_ARM = 2, + VENDOR_OTHER = 3, }; struct CPUInfo { - CPUVendor vendor = VENDOR_INTEL; + CPUVendor vendor = VENDOR_INTEL; - char cpu_string[0x41] = {}; - char brand_string[0x21] = {}; - bool OS64bit = false; - bool CPU64bit = false; - bool Mode64bit = false; + char cpu_string[0x41] = {}; + char brand_string[0x21] = {}; + bool OS64bit = false; + bool CPU64bit = false; + bool Mode64bit = false; - bool HTT = false; - int num_cores = 0; - int logical_cpu_count = 0; + bool HTT = false; + int num_cores = 0; + int logical_cpu_count = 0; - bool bSSE = false; - bool bSSE2 = false; - bool bSSE3 = false; - bool bSSSE3 = false; - bool bPOPCNT = false; - bool bSSE4_1 = false; - bool bSSE4_2 = false; - bool bLZCNT = false; - bool bSSE4A = false; - bool bAVX = false; - bool bAVX2 = false; - bool bBMI1 = false; - bool bBMI2 = false; - bool bFMA = false; - bool bFMA4 = false; - bool bAES = false; - // FXSAVE/FXRSTOR - bool bFXSR = false; - bool bMOVBE = false; - // This flag indicates that the hardware supports some mode - // in which denormal inputs _and_ outputs are automatically set to (signed) zero. - bool bFlushToZero = false; - bool bLAHFSAHF64 = false; - bool bLongMode = false; - bool bAtom = false; + bool bSSE = false; + bool bSSE2 = false; + bool bSSE3 = false; + bool bSSSE3 = false; + bool bPOPCNT = false; + bool bSSE4_1 = false; + bool bSSE4_2 = false; + bool bLZCNT = false; + bool bSSE4A = false; + bool bAVX = false; + bool bAVX2 = false; + bool bBMI1 = false; + bool bBMI2 = false; + bool bFMA = false; + bool bFMA4 = false; + bool bAES = false; + // FXSAVE/FXRSTOR + bool bFXSR = false; + bool bMOVBE = false; + // This flag indicates that the hardware supports some mode + // in which denormal inputs _and_ outputs are automatically set to (signed) zero. + bool bFlushToZero = false; + bool bLAHFSAHF64 = false; + bool bLongMode = false; + bool bAtom = false; - // ARMv8 specific - bool bFP = false; - bool bASIMD = false; - bool bCRC32 = false; - bool bSHA1 = false; - bool bSHA2 = false; + // ARMv8 specific + bool bFP = false; + bool bASIMD = false; + bool bCRC32 = false; + bool bSHA1 = false; + bool bSHA2 = false; - // Call Detect() - explicit CPUInfo(); + // Call Detect() + explicit CPUInfo(); - // Turn the CPU info into a string we can show - std::string Summarize(); + // Turn the CPU info into a string we can show + std::string Summarize(); private: - // Detects the various CPU features - void Detect(); + // Detects the various CPU features + void Detect(); }; extern CPUInfo cpu_info; diff --git a/Source/Core/Common/ChunkFile.h b/Source/Core/Common/ChunkFile.h index 67066dd206..4253bbf968 100644 --- a/Source/Core/Common/ChunkFile.h +++ b/Source/Core/Common/ChunkFile.h @@ -34,11 +34,14 @@ // ewww #ifndef __has_feature - #define __has_feature(x) (0) +#define __has_feature(x) (0) #endif -#if (__has_feature(is_trivially_copyable) && (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || (defined(__GNUC__) && __GNUC__ >= 5) -#define IsTriviallyCopyable(T) std::is_trivially_copyable::type>::value +#if (__has_feature(is_trivially_copyable) && \ + (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \ + (defined(__GNUC__) && __GNUC__ >= 5) +#define IsTriviallyCopyable(T) \ + std::is_trivially_copyable::type>::value #elif __GNUC__ #define IsTriviallyCopyable(T) std::has_trivial_copy_constructor::value #elif _MSC_VER @@ -48,312 +51,310 @@ #error No version of is_trivially_copyable #endif - template struct LinkedListItem : public T { - LinkedListItem *next; + LinkedListItem* next; }; // Wrapper class class PointerWrap { public: - enum Mode - { - MODE_READ = 1, // load - MODE_WRITE, // save - MODE_MEASURE, // calculate size - MODE_VERIFY, // compare - }; + enum Mode + { + MODE_READ = 1, // load + MODE_WRITE, // save + MODE_MEASURE, // calculate size + MODE_VERIFY, // compare + }; - u8 **ptr; - Mode mode; + u8** ptr; + Mode mode; public: - PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_) {} + PointerWrap(u8** ptr_, Mode mode_) : ptr(ptr_), mode(mode_) {} + void SetMode(Mode mode_) { mode = mode_; } + Mode GetMode() const { return mode; } + template + void Do(std::map& x) + { + u32 count = (u32)x.size(); + Do(count); - void SetMode(Mode mode_) { mode = mode_; } - Mode GetMode() const { return mode; } + switch (mode) + { + case MODE_READ: + for (x.clear(); count != 0; --count) + { + std::pair pair; + Do(pair.first); + Do(pair.second); + x.insert(pair); + } + break; - template - void Do(std::map& x) - { - u32 count = (u32)x.size(); - Do(count); + case MODE_WRITE: + case MODE_MEASURE: + case MODE_VERIFY: + for (auto& elem : x) + { + Do(elem.first); + Do(elem.second); + } + break; + } + } - switch (mode) - { - case MODE_READ: - for (x.clear(); count != 0; --count) - { - std::pair pair; - Do(pair.first); - Do(pair.second); - x.insert(pair); - } - break; + template + void Do(std::set& x) + { + u32 count = (u32)x.size(); + Do(count); - case MODE_WRITE: - case MODE_MEASURE: - case MODE_VERIFY: - for (auto& elem : x) - { - Do(elem.first); - Do(elem.second); - } - break; - } - } + switch (mode) + { + case MODE_READ: + for (x.clear(); count != 0; --count) + { + V value; + Do(value); + x.insert(value); + } + break; - template - void Do(std::set& x) - { - u32 count = (u32)x.size(); - Do(count); + case MODE_WRITE: + case MODE_MEASURE: + case MODE_VERIFY: + for (V& val : x) + { + Do(val); + } + break; + } + } - switch (mode) - { - case MODE_READ: - for (x.clear(); count != 0; --count) - { - V value; - Do(value); - x.insert(value); - } - break; + template + void Do(std::vector& x) + { + DoContainer(x); + } - case MODE_WRITE: - case MODE_MEASURE: - case MODE_VERIFY: - for (V& val : x) - { - Do(val); - } - break; - } - } + template + void Do(std::list& x) + { + DoContainer(x); + } - template - void Do(std::vector& x) - { - DoContainer(x); - } + template + void Do(std::deque& x) + { + DoContainer(x); + } - template - void Do(std::list& x) - { - DoContainer(x); - } + template + void Do(std::basic_string& x) + { + DoContainer(x); + } - template - void Do(std::deque& x) - { - DoContainer(x); - } + template + void Do(std::pair& x) + { + Do(x.first); + Do(x.second); + } - template - void Do(std::basic_string& x) - { - DoContainer(x); - } + template + void DoArray(std::array& x) + { + DoArray(x.data(), (u32)x.size()); + } - template - void Do(std::pair& x) - { - Do(x.first); - Do(x.second); - } + template + void DoArray(T* x, u32 count) + { + static_assert(IsTriviallyCopyable(T), "Only sane for trivially copyable types"); + DoVoid(x, count * sizeof(T)); + } - template - void DoArray(std::array& x) - { - DoArray(x.data(), (u32)x.size()); - } + template + void DoArray(T (&arr)[N]) + { + DoArray(arr, static_cast(N)); + } - template - void DoArray(T* x, u32 count) - { - static_assert(IsTriviallyCopyable(T), "Only sane for trivially copyable types"); - DoVoid(x, count * sizeof(T)); - } + void Do(Common::Flag& flag) + { + bool s = flag.IsSet(); + Do(s); + if (mode == MODE_READ) + flag.Set(s); + } - template - void DoArray(T (&arr)[N]) - { - DoArray(arr, static_cast(N)); - } + template + void Do(std::atomic& atomic) + { + T temp = atomic.load(); + Do(temp); + if (mode == MODE_READ) + atomic.store(temp); + } - void Do(Common::Flag& flag) - { - bool s = flag.IsSet(); - Do(s); - if (mode == MODE_READ) - flag.Set(s); - } + template + void Do(T& x) + { + static_assert(IsTriviallyCopyable(T), "Only sane for trivially copyable types"); + // Note: + // Usually we can just use x = **ptr, etc. However, this doesn't work + // for unions containing BitFields (long story, stupid language rules) + // or arrays. This will get optimized anyway. + DoVoid((void*)&x, sizeof(x)); + } - template - void Do(std::atomic& atomic) - { - T temp = atomic.load(); - Do(temp); - if (mode == MODE_READ) - atomic.store(temp); - } + template + void DoPOD(T& x) + { + DoVoid((void*)&x, sizeof(x)); + } - template - void Do(T& x) - { - static_assert(IsTriviallyCopyable(T), "Only sane for trivially copyable types"); - // Note: - // Usually we can just use x = **ptr, etc. However, this doesn't work - // for unions containing BitFields (long story, stupid language rules) - // or arrays. This will get optimized anyway. - DoVoid((void*)&x, sizeof(x)); - } + void Do(bool& x) + { + // bool's size can vary depending on platform, which can + // cause breakages. This treats all bools as if they were + // 8 bits in size. + u8 stable = static_cast(x); - template - void DoPOD(T& x) - { - DoVoid((void*)&x, sizeof(x)); - } + Do(stable); + if (mode == MODE_READ) + x = stable != 0; + } - void Do(bool& x) - { - // bool's size can vary depending on platform, which can - // cause breakages. This treats all bools as if they were - // 8 bits in size. - u8 stable = static_cast(x); + template + void DoPointer(T*& x, T* const base) + { + // pointers can be more than 2^31 apart, but you're using this function wrong if you need that + // much range + ptrdiff_t offset = x - base; + Do(offset); + if (mode == MODE_READ) + { + x = base + offset; + } + } - Do(stable); + // Let's pretend std::list doesn't exist! + template * (*TNew)(), void (*TFree)(LinkedListItem*), + void (*TDo)(PointerWrap&, T*)> + void DoLinkedList(LinkedListItem*& list_start, LinkedListItem** list_end = 0) + { + LinkedListItem* list_cur = list_start; + LinkedListItem* prev = nullptr; - if (mode == MODE_READ) - x = stable != 0; - } + while (true) + { + u8 shouldExist = !!list_cur; + Do(shouldExist); + if (shouldExist == 1) + { + LinkedListItem* cur = list_cur ? list_cur : TNew(); + TDo(*this, (T*)cur); + if (!list_cur) + { + if (mode == MODE_READ) + { + cur->next = nullptr; + list_cur = cur; + if (prev) + prev->next = cur; + else + list_start = cur; + } + else + { + TFree(cur); + continue; + } + } + } + else + { + if (mode == MODE_READ) + { + if (prev) + prev->next = nullptr; + if (list_end) + *list_end = prev; + if (list_cur) + { + if (list_start == list_cur) + list_start = nullptr; + do + { + LinkedListItem* next = list_cur->next; + TFree(list_cur); + list_cur = next; + } while (list_cur); + } + } + break; + } + prev = list_cur; + list_cur = list_cur->next; + } + } - template - void DoPointer(T*& x, T* const base) - { - // pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range - ptrdiff_t offset = x - base; - Do(offset); - if (mode == MODE_READ) - { - x = base + offset; - } - } + void DoMarker(const std::string& prevName, u32 arbitraryNumber = 0x42) + { + u32 cookie = arbitraryNumber; + Do(cookie); - // Let's pretend std::list doesn't exist! - template * (*TNew)(), void (*TFree)(LinkedListItem*), void (*TDo)(PointerWrap&, T*)> - void DoLinkedList(LinkedListItem*& list_start, LinkedListItem** list_end=0) - { - LinkedListItem* list_cur = list_start; - LinkedListItem* prev = nullptr; - - while (true) - { - u8 shouldExist = !!list_cur; - Do(shouldExist); - if (shouldExist == 1) - { - LinkedListItem* cur = list_cur ? list_cur : TNew(); - TDo(*this, (T*)cur); - if (!list_cur) - { - if (mode == MODE_READ) - { - cur->next = nullptr; - list_cur = cur; - if (prev) - prev->next = cur; - else - list_start = cur; - } - else - { - TFree(cur); - continue; - } - } - } - else - { - if (mode == MODE_READ) - { - if (prev) - prev->next = nullptr; - if (list_end) - *list_end = prev; - if (list_cur) - { - if (list_start == list_cur) - list_start = nullptr; - do - { - LinkedListItem* next = list_cur->next; - TFree(list_cur); - list_cur = next; - } while (list_cur); - } - } - break; - } - prev = list_cur; - list_cur = list_cur->next; - } - } - - void DoMarker(const std::string& prevName, u32 arbitraryNumber = 0x42) - { - u32 cookie = arbitraryNumber; - Do(cookie); - - if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) - { - PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", - prevName.c_str(), cookie, cookie, arbitraryNumber, arbitraryNumber); - mode = PointerWrap::MODE_MEASURE; - } - } + if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) + { + PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting " + "savestate load...", + prevName.c_str(), cookie, cookie, arbitraryNumber, arbitraryNumber); + mode = PointerWrap::MODE_MEASURE; + } + } private: - template - void DoContainer(T& x) - { - u32 size = (u32)x.size(); - Do(size); - x.resize(size); + template + void DoContainer(T& x) + { + u32 size = (u32)x.size(); + Do(size); + x.resize(size); - for (auto& elem : x) - Do(elem); - } + for (auto& elem : x) + Do(elem); + } - __forceinline - void DoVoid(void* data, u32 size) - { - switch (mode) - { - case MODE_READ: - memcpy(data, *ptr, size); - break; + __forceinline void DoVoid(void* data, u32 size) + { + switch (mode) + { + case MODE_READ: + memcpy(data, *ptr, size); + break; - case MODE_WRITE: - memcpy(*ptr, data, size); - break; + case MODE_WRITE: + memcpy(*ptr, data, size); + break; - case MODE_MEASURE: - break; + case MODE_MEASURE: + break; - case MODE_VERIFY: - _dbg_assert_msg_(COMMON, !memcmp(data, *ptr, size), - "Savestate verification failure: buf %p != %p (size %u).\n", - data, *ptr, size); - break; - } + case MODE_VERIFY: + _dbg_assert_msg_(COMMON, !memcmp(data, *ptr, size), + "Savestate verification failure: buf %p != %p (size %u).\n", data, *ptr, + size); + break; + } - *ptr += size; - } + *ptr += size; + } }; // NOTE: this class is only used in DolphinWX/ISOFile.cpp for caching loaded @@ -361,120 +362,119 @@ private: class CChunkFileReader { public: - // Load file template - template - static bool Load(const std::string& _rFilename, u32 _Revision, T& _class) - { - INFO_LOG(COMMON, "ChunkReader: Loading %s", _rFilename.c_str()); + // Load file template + template + static bool Load(const std::string& _rFilename, u32 _Revision, T& _class) + { + INFO_LOG(COMMON, "ChunkReader: Loading %s", _rFilename.c_str()); - if (!File::Exists(_rFilename)) - return false; + if (!File::Exists(_rFilename)) + return false; - // Check file size - const u64 fileSize = File::GetSize(_rFilename); - static const u64 headerSize = sizeof(SChunkHeader); - if (fileSize < headerSize) - { - ERROR_LOG(COMMON, "ChunkReader: File too small"); - return false; - } + // Check file size + const u64 fileSize = File::GetSize(_rFilename); + static const u64 headerSize = sizeof(SChunkHeader); + if (fileSize < headerSize) + { + ERROR_LOG(COMMON, "ChunkReader: File too small"); + return false; + } - File::IOFile pFile(_rFilename, "rb"); - if (!pFile) - { - ERROR_LOG(COMMON, "ChunkReader: Can't open file for reading"); - return false; - } + File::IOFile pFile(_rFilename, "rb"); + if (!pFile) + { + ERROR_LOG(COMMON, "ChunkReader: Can't open file for reading"); + return false; + } - // read the header - SChunkHeader header; - if (!pFile.ReadArray(&header, 1)) - { - ERROR_LOG(COMMON, "ChunkReader: Bad header size"); - return false; - } + // read the header + SChunkHeader header; + if (!pFile.ReadArray(&header, 1)) + { + ERROR_LOG(COMMON, "ChunkReader: Bad header size"); + return false; + } - // Check revision - if (header.Revision != _Revision) - { - ERROR_LOG(COMMON, "ChunkReader: Wrong file revision, got %d expected %d", - header.Revision, _Revision); - return false; - } + // Check revision + if (header.Revision != _Revision) + { + ERROR_LOG(COMMON, "ChunkReader: Wrong file revision, got %d expected %d", header.Revision, + _Revision); + return false; + } - // get size - const u32 sz = (u32)(fileSize - headerSize); - if (header.ExpectedSize != sz) - { - ERROR_LOG(COMMON, "ChunkReader: Bad file size, got %d expected %d", - sz, header.ExpectedSize); - return false; - } + // get size + const u32 sz = (u32)(fileSize - headerSize); + if (header.ExpectedSize != sz) + { + ERROR_LOG(COMMON, "ChunkReader: Bad file size, got %d expected %d", sz, header.ExpectedSize); + return false; + } - // read the state - std::vector buffer(sz); - if (!pFile.ReadArray(&buffer[0], sz)) - { - ERROR_LOG(COMMON, "ChunkReader: Error reading file"); - return false; - } + // read the state + std::vector buffer(sz); + if (!pFile.ReadArray(&buffer[0], sz)) + { + ERROR_LOG(COMMON, "ChunkReader: Error reading file"); + return false; + } - u8* ptr = &buffer[0]; - PointerWrap p(&ptr, PointerWrap::MODE_READ); - _class.DoState(p); + u8* ptr = &buffer[0]; + PointerWrap p(&ptr, PointerWrap::MODE_READ); + _class.DoState(p); - INFO_LOG(COMMON, "ChunkReader: Done loading %s", _rFilename.c_str()); - return true; - } + INFO_LOG(COMMON, "ChunkReader: Done loading %s", _rFilename.c_str()); + return true; + } - // Save file template - template - static bool Save(const std::string& _rFilename, u32 _Revision, T& _class) - { - INFO_LOG(COMMON, "ChunkReader: Writing %s", _rFilename.c_str()); - File::IOFile pFile(_rFilename, "wb"); - if (!pFile) - { - ERROR_LOG(COMMON, "ChunkReader: Error opening file for write"); - return false; - } + // Save file template + template + static bool Save(const std::string& _rFilename, u32 _Revision, T& _class) + { + INFO_LOG(COMMON, "ChunkReader: Writing %s", _rFilename.c_str()); + File::IOFile pFile(_rFilename, "wb"); + if (!pFile) + { + ERROR_LOG(COMMON, "ChunkReader: Error opening file for write"); + return false; + } - // Get data - u8* ptr = nullptr; - PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); - _class.DoState(p); - size_t const sz = (size_t)ptr; - std::vector buffer(sz); - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_WRITE); - _class.DoState(p); + // Get data + u8* ptr = nullptr; + PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); + _class.DoState(p); + size_t const sz = (size_t)ptr; + std::vector buffer(sz); + ptr = &buffer[0]; + p.SetMode(PointerWrap::MODE_WRITE); + _class.DoState(p); - // Create header - SChunkHeader header; - header.Revision = _Revision; - header.ExpectedSize = (u32)sz; + // Create header + SChunkHeader header; + header.Revision = _Revision; + header.ExpectedSize = (u32)sz; - // Write to file - if (!pFile.WriteArray(&header, 1)) - { - ERROR_LOG(COMMON, "ChunkReader: Failed writing header"); - return false; - } + // Write to file + if (!pFile.WriteArray(&header, 1)) + { + ERROR_LOG(COMMON, "ChunkReader: Failed writing header"); + return false; + } - if (!pFile.WriteArray(&buffer[0], sz)) - { - ERROR_LOG(COMMON, "ChunkReader: Failed writing data"); - return false; - } + if (!pFile.WriteArray(&buffer[0], sz)) + { + ERROR_LOG(COMMON, "ChunkReader: Failed writing data"); + return false; + } - INFO_LOG(COMMON, "ChunkReader: Done writing %s", _rFilename.c_str()); - return true; - } + INFO_LOG(COMMON, "ChunkReader: Done writing %s", _rFilename.c_str()); + return true; + } private: - struct SChunkHeader - { - u32 Revision; - u32 ExpectedSize; - }; + struct SChunkHeader + { + u32 Revision; + u32 ExpectedSize; + }; }; diff --git a/Source/Core/Common/CodeBlock.h b/Source/Core/Common/CodeBlock.h index e399b1003a..1666f270a4 100644 --- a/Source/Core/Common/CodeBlock.h +++ b/Source/Core/Common/CodeBlock.h @@ -13,98 +13,92 @@ // having to prefix them with gen-> or something similar. // Example implementation: // class JIT : public CodeBlock {} -template class CodeBlock : public T, NonCopyable +template +class CodeBlock : public T, NonCopyable { private: - // A privately used function to set the executable RAM space to something invalid. - // For debugging usefulness it should be used to set the RAM to a host specific breakpoint instruction - virtual void PoisonMemory() = 0; + // A privately used function to set the executable RAM space to something invalid. + // For debugging usefulness it should be used to set the RAM to a host specific breakpoint + // instruction + virtual void PoisonMemory() = 0; protected: - u8* region; - size_t region_size; - size_t parent_region_size; + u8* region; + size_t region_size; + size_t parent_region_size; - bool m_has_child; - bool m_is_child; - CodeBlock* m_child; + bool m_has_child; + bool m_is_child; + CodeBlock* m_child; public: - CodeBlock() - : region(nullptr), region_size(0), parent_region_size(0), - m_has_child(false), m_is_child(false), m_child(nullptr) - { - } + CodeBlock() + : region(nullptr), region_size(0), parent_region_size(0), m_has_child(false), + m_is_child(false), m_child(nullptr) + { + } - virtual ~CodeBlock() { if (region) FreeCodeSpace(); } + virtual ~CodeBlock() + { + if (region) + FreeCodeSpace(); + } - // Call this before you generate any code. - void AllocCodeSpace(int size, bool need_low = true) - { - region_size = size; - region = (u8*)AllocateExecutableMemory(region_size, need_low); - T::SetCodePtr(region); - } + // Call this before you generate any code. + void AllocCodeSpace(int size, bool need_low = true) + { + region_size = size; + region = (u8*)AllocateExecutableMemory(region_size, need_low); + T::SetCodePtr(region); + } - // Always clear code space with breakpoints, so that if someone accidentally executes - // uninitialized, it just breaks into the debugger. - void ClearCodeSpace() - { - PoisonMemory(); - ResetCodePtr(); - } + // Always clear code space with breakpoints, so that if someone accidentally executes + // uninitialized, it just breaks into the debugger. + void ClearCodeSpace() + { + PoisonMemory(); + ResetCodePtr(); + } - // Call this when shutting down. Don't rely on the destructor, even though it'll do the job. - void FreeCodeSpace() - { - FreeMemoryPages(region, region_size); - region = nullptr; - region_size = 0; - parent_region_size = 0; - if (m_has_child) - { - m_child->region = nullptr; - m_child->region_size = 0; - } - } + // Call this when shutting down. Don't rely on the destructor, even though it'll do the job. + void FreeCodeSpace() + { + FreeMemoryPages(region, region_size); + region = nullptr; + region_size = 0; + parent_region_size = 0; + if (m_has_child) + { + m_child->region = nullptr; + m_child->region_size = 0; + } + } - bool IsInSpace(u8* ptr) const - { - return (ptr >= region) && (ptr < (region + region_size)); - } + bool IsInSpace(u8* ptr) const { return (ptr >= region) && (ptr < (region + region_size)); } + // Cannot currently be undone. Will write protect the entire code region. + // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()). + void WriteProtect() { WriteProtectMemory(region, region_size, true); } + void ResetCodePtr() { T::SetCodePtr(region); } + size_t GetSpaceLeft() const + { + return (m_has_child ? parent_region_size : region_size) - (T::GetCodePtr() - region); + } - // Cannot currently be undone. Will write protect the entire code region. - // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()). - void WriteProtect() - { - WriteProtectMemory(region, region_size, true); - } - - void ResetCodePtr() - { - T::SetCodePtr(region); - } - - size_t GetSpaceLeft() const - { - return (m_has_child ? parent_region_size : region_size) - (T::GetCodePtr() - region); - } - - bool IsAlmostFull() const - { - // This should be bigger than the biggest block ever. - return GetSpaceLeft() < 0x10000; - } - void AddChildCodeSpace(CodeBlock* child, size_t size) - { - _assert_msg_(DYNA_REC, !m_has_child, "Already have a child! Can't have another!"); - m_child = child; - m_has_child = true; - m_child->m_is_child = true; - u8* child_region = region + region_size - size; - m_child->region = child_region; - m_child->region_size = size; - m_child->ResetCodePtr(); - parent_region_size = region_size - size; - } + bool IsAlmostFull() const + { + // This should be bigger than the biggest block ever. + return GetSpaceLeft() < 0x10000; + } + void AddChildCodeSpace(CodeBlock* child, size_t size) + { + _assert_msg_(DYNA_REC, !m_has_child, "Already have a child! Can't have another!"); + m_child = child; + m_has_child = true; + m_child->m_is_child = true; + u8* child_region = region + region_size - size; + m_child->region = child_region; + m_child->region_size = size; + m_child->ResetCodePtr(); + parent_region_size = region_size - size; + } }; diff --git a/Source/Core/Common/ColorUtil.cpp b/Source/Core/Common/ColorUtil.cpp index 4204c7c29d..a4f01da453 100644 --- a/Source/Core/Common/ColorUtil.cpp +++ b/Source/Core/Common/ColorUtil.cpp @@ -7,82 +7,74 @@ namespace ColorUtil { +static const int s_lut5to8[] = {0x00, 0x08, 0x10, 0x18, 0x20, 0x29, 0x31, 0x39, 0x41, 0x4A, 0x52, + 0x5A, 0x62, 0x6A, 0x73, 0x7B, 0x83, 0x8B, 0x94, 0x9C, 0xA4, 0xAC, + 0xB4, 0xBD, 0xC5, 0xCD, 0xD5, 0xDE, 0xE6, 0xEE, 0xF6, 0xFF}; -static const int s_lut5to8[] = { - 0x00,0x08,0x10,0x18,0x20,0x29,0x31,0x39, - 0x41,0x4A,0x52,0x5A,0x62,0x6A,0x73,0x7B, - 0x83,0x8B,0x94,0x9C,0xA4,0xAC,0xB4,0xBD, - 0xC5,0xCD,0xD5,0xDE,0xE6,0xEE,0xF6,0xFF -}; +static const int s_lut4to8[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; -static const int s_lut4to8[] = { - 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77, - 0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF -}; - -static const int s_lut3to8[] = { - 0x00,0x24,0x48,0x6D,0x91,0xB6,0xDA,0xFF -}; +static const int s_lut3to8[] = {0x00, 0x24, 0x48, 0x6D, 0x91, 0xB6, 0xDA, 0xFF}; static u32 Decode5A3(u16 val) { - const u32 bg_color = 0x00000000; + const u32 bg_color = 0x00000000; - int r, g, b, a; + int r, g, b, a; - if (val & 0x8000) - { - r = s_lut5to8[(val >> 10) & 0x1f]; - g = s_lut5to8[(val >> 5) & 0x1f]; - b = s_lut5to8[(val) & 0x1f]; - a = 0xFF; - } - else - { - a = s_lut3to8[(val >> 12) & 0x7]; - r = (s_lut4to8[(val >> 8) & 0xf] * a + (bg_color & 0xFF) * (255 - a)) / 255; - g = (s_lut4to8[(val >> 4) & 0xf] * a + ((bg_color >> 8) & 0xFF) * (255 - a)) / 255; - b = (s_lut4to8[(val) & 0xf] * a + ((bg_color >> 16) & 0xFF) * (255 - a)) / 255; - a = 0xFF; - } - return (a << 24) | (r << 16) | (g << 8) | b; + if (val & 0x8000) + { + r = s_lut5to8[(val >> 10) & 0x1f]; + g = s_lut5to8[(val >> 5) & 0x1f]; + b = s_lut5to8[(val)&0x1f]; + a = 0xFF; + } + else + { + a = s_lut3to8[(val >> 12) & 0x7]; + r = (s_lut4to8[(val >> 8) & 0xf] * a + (bg_color & 0xFF) * (255 - a)) / 255; + g = (s_lut4to8[(val >> 4) & 0xf] * a + ((bg_color >> 8) & 0xFF) * (255 - a)) / 255; + b = (s_lut4to8[(val)&0xf] * a + ((bg_color >> 16) & 0xFF) * (255 - a)) / 255; + a = 0xFF; + } + return (a << 24) | (r << 16) | (g << 8) | b; } void decode5A3image(u32* dst, u16* src, int width, int height) { - for (int y = 0; y < height; y += 4) - { - for (int x = 0; x < width; x += 4) - { - for (int iy = 0; iy < 4; iy++, src += 4) - { - for (int ix = 0; ix < 4; ix++) - { - u32 RGBA = Decode5A3(Common::swap16(src[ix])); - dst[(y + iy) * width + (x + ix)] = RGBA; - } - } - } - } + for (int y = 0; y < height; y += 4) + { + for (int x = 0; x < width; x += 4) + { + for (int iy = 0; iy < 4; iy++, src += 4) + { + for (int ix = 0; ix < 4; ix++) + { + u32 RGBA = Decode5A3(Common::swap16(src[ix])); + dst[(y + iy) * width + (x + ix)] = RGBA; + } + } + } + } } void decodeCI8image(u32* dst, u8* src, u16* pal, int width, int height) { - for (int y = 0; y < height; y += 4) - { - for (int x = 0; x < width; x += 8) - { - for (int iy = 0; iy < 4; iy++, src += 8) - { - u32* tdst = dst+(y+iy)*width+x; - for (int ix = 0; ix < 8; ix++) - { - // huh, this seems wrong. CI8, not 5A3, no? - tdst[ix] = ColorUtil::Decode5A3(Common::swap16(pal[src[ix]])); - } - } - } - } + for (int y = 0; y < height; y += 4) + { + for (int x = 0; x < width; x += 8) + { + for (int iy = 0; iy < 4; iy++, src += 8) + { + u32* tdst = dst + (y + iy) * width + x; + for (int ix = 0; ix < 8; ix++) + { + // huh, this seems wrong. CI8, not 5A3, no? + tdst[ix] = ColorUtil::Decode5A3(Common::swap16(pal[src[ix]])); + } + } + } + } } } // namespace diff --git a/Source/Core/Common/ColorUtil.h b/Source/Core/Common/ColorUtil.h index 14cc7075c5..bc2b100dc7 100644 --- a/Source/Core/Common/ColorUtil.h +++ b/Source/Core/Common/ColorUtil.h @@ -8,7 +8,6 @@ namespace ColorUtil { - void decode5A3image(u32* dst, u16* src, int width, int height); void decodeCI8image(u32* dst, u8* src, u16* pal, int width, int height); diff --git a/Source/Core/Common/Common.h b/Source/Core/Common/Common.h index 4d60332d6c..a48203a874 100644 --- a/Source/Core/Common/Common.h +++ b/Source/Core/Common/Common.h @@ -35,25 +35,32 @@ extern const std::string scm_distributor_str; #if defined _WIN32 // Memory leak checks - #define CHECK_HEAP_INTEGRITY() +#define CHECK_HEAP_INTEGRITY() // Since they are always around on Windows - #define HAVE_WX 1 - #define HAVE_OPENAL 1 +#define HAVE_WX 1 +#define HAVE_OPENAL 1 - #define HAVE_PORTAUDIO 1 +#define HAVE_PORTAUDIO 1 // Debug definitions - #if defined(_DEBUG) - #include - #undef CHECK_HEAP_INTEGRITY - #define CHECK_HEAP_INTEGRITY() {if (!_CrtCheckMemory()) PanicAlert("memory corruption detected. see log.");} - // If you want to see how much a pain in the ass singletons are, for example: - // {614} normal block at 0x030C5310, 188 bytes long. - // Data: 4D 61 73 74 65 72 20 4C 6F 67 00 00 00 00 00 00 - struct CrtDebugBreak { CrtDebugBreak(int spot) { _CrtSetBreakAlloc(spot); } }; - //CrtDebugBreak breakAt(614); - #endif // end DEBUG/FAST +#if defined(_DEBUG) +#include +#undef CHECK_HEAP_INTEGRITY +#define CHECK_HEAP_INTEGRITY() \ + { \ + if (!_CrtCheckMemory()) \ + PanicAlert("memory corruption detected. see log."); \ + } +// If you want to see how much a pain in the ass singletons are, for example: +// {614} normal block at 0x030C5310, 188 bytes long. +// Data: 4D 61 73 74 65 72 20 4C 6F 67 00 00 00 00 00 00 +struct CrtDebugBreak +{ + CrtDebugBreak(int spot) { _CrtSetBreakAlloc(spot); } +}; +// CrtDebugBreak breakAt(614); +#endif // end DEBUG/FAST #endif @@ -80,17 +87,17 @@ extern const std::string scm_distributor_str; // Host communication. enum HOST_COMM { - // Begin at 10 in case there is already messages with wParam = 0, 1, 2 and so on - WM_USER_STOP = 10, - WM_USER_CREATE, - WM_USER_SETCURSOR, - WM_USER_JOB_DISPATCH, + // Begin at 10 in case there is already messages with wParam = 0, 1, 2 and so on + WM_USER_STOP = 10, + WM_USER_CREATE, + WM_USER_SETCURSOR, + WM_USER_JOB_DISPATCH, }; // Used for notification on emulation state enum EMUSTATE_CHANGE { - EMUSTATE_CHANGE_PLAY = 1, - EMUSTATE_CHANGE_PAUSE, - EMUSTATE_CHANGE_STOP + EMUSTATE_CHANGE_PLAY = 1, + EMUSTATE_CHANGE_PAUSE, + EMUSTATE_CHANGE_STOP }; diff --git a/Source/Core/Common/CommonFuncs.h b/Source/Core/Common/CommonFuncs.h index 1d0aa07bcd..a1d6b17185 100644 --- a/Source/Core/Common/CommonFuncs.h +++ b/Source/Core/Common/CommonFuncs.h @@ -16,15 +16,15 @@ template constexpr size_t ArraySize(T (&arr)[N]) { - return N; + return N; } -#define b2(x) ( (x) | ( (x) >> 1) ) -#define b4(x) ( b2(x) | ( b2(x) >> 2) ) -#define b8(x) ( b4(x) | ( b4(x) >> 4) ) -#define b16(x) ( b8(x) | ( b8(x) >> 8) ) -#define b32(x) (b16(x) | (b16(x) >>16) ) -#define ROUND_UP_POW2(x) (b32(x - 1) + 1) +#define b2(x) ((x) | ((x) >> 1)) +#define b4(x) (b2(x) | (b2(x) >> 2)) +#define b8(x) (b4(x) | (b4(x) >> 4)) +#define b16(x) (b8(x) | (b8(x) >> 8)) +#define b32(x) (b16(x) | (b16(x) >> 16)) +#define ROUND_UP_POW2(x) (b32(x - 1) + 1) #ifndef _WIN32 @@ -36,59 +36,66 @@ constexpr size_t ArraySize(T (&arr)[N]) #endif // go to debugger mode -#define Crash() { __builtin_trap(); } +#define Crash() \ + { \ + __builtin_trap(); \ + } // GCC 4.8 defines all the rotate functions now // Small issue with GCC's lrotl/lrotr intrinsics is they are still 32bit while we require 64bit #ifndef _rotl inline u32 _rotl(u32 x, int shift) { - shift &= 31; - if (!shift) return x; - return (x << shift) | (x >> (32 - shift)); + shift &= 31; + if (!shift) + return x; + return (x << shift) | (x >> (32 - shift)); } inline u32 _rotr(u32 x, int shift) { - shift &= 31; - if (!shift) return x; - return (x >> shift) | (x << (32 - shift)); + shift &= 31; + if (!shift) + return x; + return (x >> shift) | (x << (32 - shift)); } #endif inline u64 _rotl64(u64 x, unsigned int shift) { - unsigned int n = shift % 64; - return (x << n) | (x >> (64 - n)); + unsigned int n = shift % 64; + return (x << n) | (x >> (64 - n)); } inline u64 _rotr64(u64 x, unsigned int shift) { - unsigned int n = shift % 64; - return (x >> n) | (x << (64 - n)); + unsigned int n = shift % 64; + return (x >> n) | (x << (64 - n)); } -#else // WIN32 +#else // WIN32 // Function Cross-Compatibility - #define strcasecmp _stricmp - #define strncasecmp _strnicmp - #define unlink _unlink - #define vscprintf _vscprintf +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define unlink _unlink +#define vscprintf _vscprintf // 64 bit offsets for Windows - #define fseeko _fseeki64 - #define ftello _ftelli64 - #define atoll _atoi64 - #define stat64 _stat64 - #define fstat64 _fstat64 - #define fileno _fileno +#define fseeko _fseeki64 +#define ftello _ftelli64 +#define atoll _atoi64 +#define stat64 _stat64 +#define fstat64 _fstat64 +#define fileno _fileno -extern "C" -{ - __declspec(dllimport) void __stdcall DebugBreak(void); +extern "C" { +__declspec(dllimport) void __stdcall DebugBreak(void); } - #define Crash() {DebugBreak();} -#endif // WIN32 ndef +#define Crash() \ + { \ + DebugBreak(); \ + } +#endif // WIN32 ndef // Generic function to get last error message. // Call directly after the command or use the error num. @@ -98,8 +105,14 @@ std::string GetLastErrorMsg(); namespace Common { -inline u8 swap8(u8 _data) {return _data;} -inline u32 swap24(const u8* _data) {return (_data[0] << 16) | (_data[1] << 8) | _data[2];} +inline u8 swap8(u8 _data) +{ + return _data; +} +inline u32 swap24(const u8* _data) +{ + return (_data[0] << 16) | (_data[1] << 8) | _data[2]; +} #ifdef ANDROID #undef swap16 @@ -108,69 +121,121 @@ inline u32 swap24(const u8* _data) {return (_data[0] << 16) | (_data[1] << 8) | #endif #ifdef _WIN32 -inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);} -inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);} -inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);} +inline u16 swap16(u16 _data) +{ + return _byteswap_ushort(_data); +} +inline u32 swap32(u32 _data) +{ + return _byteswap_ulong(_data); +} +inline u64 swap64(u64 _data) +{ + return _byteswap_uint64(_data); +} #elif __linux__ && !(ANDROID && _M_ARM_64) // Android NDK r10c has broken builtin byte swap routines // Disabled for now. -inline u16 swap16(u16 _data) {return bswap_16(_data);} -inline u32 swap32(u32 _data) {return bswap_32(_data);} -inline u64 swap64(u64 _data) {return bswap_64(_data);} +inline u16 swap16(u16 _data) +{ + return bswap_16(_data); +} +inline u32 swap32(u32 _data) +{ + return bswap_32(_data); +} +inline u64 swap64(u64 _data) +{ + return bswap_64(_data); +} #elif __APPLE__ inline __attribute__((always_inline)) u16 swap16(u16 _data) - {return OSSwapInt16(_data);} +{ + return OSSwapInt16(_data); +} inline __attribute__((always_inline)) u32 swap32(u32 _data) - {return OSSwapInt32(_data);} +{ + return OSSwapInt32(_data); +} inline __attribute__((always_inline)) u64 swap64(u64 _data) - {return OSSwapInt64(_data);} +{ + return OSSwapInt64(_data); +} #elif __FreeBSD__ -inline u16 swap16(u16 _data) {return bswap16(_data);} -inline u32 swap32(u32 _data) {return bswap32(_data);} -inline u64 swap64(u64 _data) {return bswap64(_data);} +inline u16 swap16(u16 _data) +{ + return bswap16(_data); +} +inline u32 swap32(u32 _data) +{ + return bswap32(_data); +} +inline u64 swap64(u64 _data) +{ + return bswap64(_data); +} #else // Slow generic implementation. -inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);} -inline u32 swap32(u32 data) {return (swap16(data) << 16) | swap16(data >> 16);} -inline u64 swap64(u64 data) {return ((u64)swap32(data) << 32) | swap32(data >> 32);} +inline u16 swap16(u16 data) +{ + return (data >> 8) | (data << 8); +} +inline u32 swap32(u32 data) +{ + return (swap16(data) << 16) | swap16(data >> 16); +} +inline u64 swap64(u64 data) +{ + return ((u64)swap32(data) << 32) | swap32(data >> 32); +} #endif -inline u16 swap16(const u8* _pData) {return swap16(*(const u16*)_pData);} -inline u32 swap32(const u8* _pData) {return swap32(*(const u32*)_pData);} -inline u64 swap64(const u8* _pData) {return swap64(*(const u64*)_pData);} +inline u16 swap16(const u8* _pData) +{ + return swap16(*(const u16*)_pData); +} +inline u32 swap32(const u8* _pData) +{ + return swap32(*(const u32*)_pData); +} +inline u64 swap64(const u8* _pData) +{ + return swap64(*(const u64*)_pData); +} template void swap(u8*); template <> inline void swap<1>(u8* data) -{} +{ +} template <> inline void swap<2>(u8* data) { - *reinterpret_cast(data) = swap16(data); + *reinterpret_cast(data) = swap16(data); } template <> inline void swap<4>(u8* data) { - *reinterpret_cast(data) = swap32(data); + *reinterpret_cast(data) = swap32(data); } template <> inline void swap<8>(u8* data) { - *reinterpret_cast(data) = swap64(data); + *reinterpret_cast(data) = swap64(data); } template inline T FromBigEndian(T data) { - static_assert(std::is_arithmetic::value, "function only makes sense with arithmetic types"); + static_assert(std::is_arithmetic::value, "function only makes sense with arithmetic types"); - swap(reinterpret_cast(&data)); - return data; + swap(reinterpret_cast(&data)); + return data; } } // Namespace Common diff --git a/Source/Core/Common/CommonPaths.h b/Source/Core/Common/CommonPaths.h index c6d559e2e5..7f799dbf4c 100644 --- a/Source/Core/Common/CommonPaths.h +++ b/Source/Core/Common/CommonPaths.h @@ -11,35 +11,35 @@ // The user data dir #define ROOT_DIR "." #ifdef _WIN32 - #define USERDATA_DIR "User" - #define DOLPHIN_DATA_DIR "Dolphin" +#define USERDATA_DIR "User" +#define DOLPHIN_DATA_DIR "Dolphin" #elif defined __APPLE__ - // On OS X, USERDATA_DIR exists within the .app, but *always* reference - // the copy in Application Support instead! (Copied on first run) - // You can use the File::GetUserPath() util for this - #define USERDATA_DIR "Contents/Resources/User" - #define DOLPHIN_DATA_DIR "Library/Application Support/Dolphin" +// On OS X, USERDATA_DIR exists within the .app, but *always* reference +// the copy in Application Support instead! (Copied on first run) +// You can use the File::GetUserPath() util for this +#define USERDATA_DIR "Contents/Resources/User" +#define DOLPHIN_DATA_DIR "Library/Application Support/Dolphin" #elif defined ANDROID - #define USERDATA_DIR "user" - #define DOLPHIN_DATA_DIR "/sdcard/dolphin-emu" +#define USERDATA_DIR "user" +#define DOLPHIN_DATA_DIR "/sdcard/dolphin-emu" #else - #define USERDATA_DIR "user" - #define DOLPHIN_DATA_DIR "dolphin-emu" +#define USERDATA_DIR "user" +#define DOLPHIN_DATA_DIR "dolphin-emu" #endif // Shared data dirs (Sys and shared User for Linux) #if defined(_WIN32) || defined(LINUX_LOCAL_DEV) - #define SYSDATA_DIR "Sys" +#define SYSDATA_DIR "Sys" #elif defined __APPLE__ - #define SYSDATA_DIR "Contents/Resources/Sys" +#define SYSDATA_DIR "Contents/Resources/Sys" #elif defined ANDROID - #define SYSDATA_DIR "/sdcard/dolphin-emu" +#define SYSDATA_DIR "/sdcard/dolphin-emu" #else - #ifdef DATA_DIR - #define SYSDATA_DIR DATA_DIR "sys" - #else - #define SYSDATA_DIR "sys" - #endif +#ifdef DATA_DIR +#define SYSDATA_DIR DATA_DIR "sys" +#else +#define SYSDATA_DIR "sys" +#endif #endif // Dirs in both User and Sys @@ -48,72 +48,72 @@ #define JAP_DIR "JAP" // Subdirs in the User dir returned by GetUserPath(D_USER_IDX) -#define GC_USER_DIR "GC" -#define WII_USER_DIR "Wii" -#define CONFIG_DIR "Config" -#define GAMESETTINGS_DIR "GameSettings" -#define MAPS_DIR "Maps" -#define CACHE_DIR "Cache" -#define SHADERCACHE_DIR "Shaders" -#define STATESAVES_DIR "StateSaves" -#define SCREENSHOTS_DIR "ScreenShots" -#define LOAD_DIR "Load" -#define HIRES_TEXTURES_DIR "Textures" -#define DUMP_DIR "Dump" -#define DUMP_TEXTURES_DIR "Textures" -#define DUMP_FRAMES_DIR "Frames" -#define DUMP_AUDIO_DIR "Audio" -#define DUMP_DSP_DIR "DSP" -#define LOGS_DIR "Logs" -#define MAIL_LOGS_DIR "Mail" -#define SHADERS_DIR "Shaders" -#define WII_SYSCONF_DIR "shared2" DIR_SEP "sys" -#define WII_WC24CONF_DIR "shared2" DIR_SEP "wc24" -#define RESOURCES_DIR "Resources" -#define THEMES_DIR "Themes" -#define ANAGLYPH_DIR "Anaglyph" -#define PIPES_DIR "Pipes" -#define MEMORYWATCHER_DIR "MemoryWatcher" +#define GC_USER_DIR "GC" +#define WII_USER_DIR "Wii" +#define CONFIG_DIR "Config" +#define GAMESETTINGS_DIR "GameSettings" +#define MAPS_DIR "Maps" +#define CACHE_DIR "Cache" +#define SHADERCACHE_DIR "Shaders" +#define STATESAVES_DIR "StateSaves" +#define SCREENSHOTS_DIR "ScreenShots" +#define LOAD_DIR "Load" +#define HIRES_TEXTURES_DIR "Textures" +#define DUMP_DIR "Dump" +#define DUMP_TEXTURES_DIR "Textures" +#define DUMP_FRAMES_DIR "Frames" +#define DUMP_AUDIO_DIR "Audio" +#define DUMP_DSP_DIR "DSP" +#define LOGS_DIR "Logs" +#define MAIL_LOGS_DIR "Mail" +#define SHADERS_DIR "Shaders" +#define WII_SYSCONF_DIR "shared2" DIR_SEP "sys" +#define WII_WC24CONF_DIR "shared2" DIR_SEP "wc24" +#define RESOURCES_DIR "Resources" +#define THEMES_DIR "Themes" +#define ANAGLYPH_DIR "Anaglyph" +#define PIPES_DIR "Pipes" +#define MEMORYWATCHER_DIR "MemoryWatcher" // This one is only used to remove it if it was present #define SHADERCACHE_LEGACY_DIR "ShaderCache" // Filenames // Files in the directory returned by GetUserPath(D_CONFIG_IDX) -#define DOLPHIN_CONFIG "Dolphin.ini" +#define DOLPHIN_CONFIG "Dolphin.ini" #define DEBUGGER_CONFIG "Debugger.ini" -#define LOGGER_CONFIG "Logger.ini" +#define LOGGER_CONFIG "Logger.ini" // Files in the directory returned by GetUserPath(D_LOGS_IDX) -#define MAIN_LOG "dolphin.log" +#define MAIN_LOG "dolphin.log" // Files in the directory returned by GetUserPath(D_WIISYSCONF_IDX) #define WII_SYSCONF "SYSCONF" // Files in the directory returned by GetUserPath(D_DUMP_IDX) -#define RAM_DUMP "ram.raw" -#define ARAM_DUMP "aram.raw" +#define RAM_DUMP "ram.raw" +#define ARAM_DUMP "aram.raw" #define FAKEVMEM_DUMP "fakevmem.raw" // Files in the directory returned by GetUserPath(D_MEMORYWATCHER_IDX) #define MEMORYWATCHER_LOCATIONS "Locations.txt" -#define MEMORYWATCHER_SOCKET "MemoryWatcher" +#define MEMORYWATCHER_SOCKET "MemoryWatcher" // Sys files -#define TOTALDB "totaldb.dsy" +#define TOTALDB "totaldb.dsy" -#define FONT_ANSI "font_ansi.bin" -#define FONT_SJIS "font_sjis.bin" +#define FONT_ANSI "font_ansi.bin" +#define FONT_SJIS "font_sjis.bin" -#define DSP_IROM "dsp_rom.bin" -#define DSP_COEF "dsp_coef.bin" +#define DSP_IROM "dsp_rom.bin" +#define DSP_COEF "dsp_coef.bin" -#define GC_IPL "IPL.bin" -#define GC_SRAM "SRAM.raw" +#define GC_IPL "IPL.bin" +#define GC_SRAM "SRAM.raw" #define GC_MEMCARDA "MemoryCardA" #define GC_MEMCARDB "MemoryCardB" -#define WII_STATE "state.dat" +#define WII_STATE "state.dat" #define WII_SETTING "setting.txt" diff --git a/Source/Core/Common/CommonTypes.h b/Source/Core/Common/CommonTypes.h index 6dde328fcd..c87ebf1719 100644 --- a/Source/Core/Common/CommonTypes.h +++ b/Source/Core/Common/CommonTypes.h @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // This header contains type definitions that are shared between the Dolphin core and // other parts of the code. Any definitions that are only used by the core should be // placed in "Common.h" instead. @@ -19,12 +18,12 @@ #define LONG int #endif -typedef uint8_t u8; +typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; -typedef int8_t s8; +typedef int8_t s8; typedef int16_t s16; typedef int32_t s32; typedef int64_t s64; diff --git a/Source/Core/Common/Crypto/bn.cpp b/Source/Core/Common/Crypto/bn.cpp index 9a7ddb54d0..78ea444384 100644 --- a/Source/Core/Common/Crypto/bn.cpp +++ b/Source/Core/Common/Crypto/bn.cpp @@ -10,103 +10,108 @@ static void bn_zero(u8* d, u32 n) { - memset(d, 0, n); + memset(d, 0, n); } static void bn_copy(u8* d, const u8* a, u32 n) { - memcpy(d, a, n); + memcpy(d, a, n); } int bn_compare(const u8* a, const u8* b, u32 n) { - u32 i; + u32 i; - for (i = 0; i < n; i++) { - if (a[i] < b[i]) - return -1; - if (a[i] > b[i]) - return 1; - } + for (i = 0; i < n; i++) + { + if (a[i] < b[i]) + return -1; + if (a[i] > b[i]) + return 1; + } - return 0; + return 0; } void bn_sub_modulus(u8* a, const u8* N, u32 n) { - u32 i; - u32 dig; - u8 c; + u32 i; + u32 dig; + u8 c; - c = 0; - for (i = n - 1; i < n; i--) { - dig = N[i] + c; - c = (a[i] < dig); - a[i] -= dig; - } + c = 0; + for (i = n - 1; i < n; i--) + { + dig = N[i] + c; + c = (a[i] < dig); + a[i] -= dig; + } } void bn_add(u8* d, const u8* a, const u8* b, const u8* N, u32 n) { - u32 i; - u32 dig; - u8 c; + u32 i; + u32 dig; + u8 c; - c = 0; - for (i = n - 1; i < n; i--) { - dig = a[i] + b[i] + c; - c = (dig >= 0x100); - d[i] = dig; - } + c = 0; + for (i = n - 1; i < n; i--) + { + dig = a[i] + b[i] + c; + c = (dig >= 0x100); + d[i] = dig; + } - if (c) - bn_sub_modulus(d, N, n); + if (c) + bn_sub_modulus(d, N, n); - if (bn_compare(d, N, n) >= 0) - bn_sub_modulus(d, N, n); + if (bn_compare(d, N, n) >= 0) + bn_sub_modulus(d, N, n); } void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, u32 n) { - u32 i; - u8 mask; + u32 i; + u8 mask; - bn_zero(d, n); + bn_zero(d, n); - for (i = 0; i < n; i++) - for (mask = 0x80; mask != 0; mask >>= 1) { - bn_add(d, d, d, N, n); - if ((a[i] & mask) != 0) - bn_add(d, d, b, N, n); - } + for (i = 0; i < n; i++) + for (mask = 0x80; mask != 0; mask >>= 1) + { + bn_add(d, d, d, N, n); + if ((a[i] & mask) != 0) + bn_add(d, d, b, N, n); + } } void bn_exp(u8* d, const u8* a, const u8* N, u32 n, const u8* e, u32 en) { - u8 t[512]; - u32 i; - u8 mask; + u8 t[512]; + u32 i; + u8 mask; - bn_zero(d, n); - d[n-1] = 1; - for (i = 0; i < en; i++) - for (mask = 0x80; mask != 0; mask >>= 1) { - bn_mul(t, d, d, N, n); - if ((e[i] & mask) != 0) - bn_mul(d, t, a, N, n); - else - bn_copy(d, t, n); - } + bn_zero(d, n); + d[n - 1] = 1; + for (i = 0; i < en; i++) + for (mask = 0x80; mask != 0; mask >>= 1) + { + bn_mul(t, d, d, N, n); + if ((e[i] & mask) != 0) + bn_mul(d, t, a, N, n); + else + bn_copy(d, t, n); + } } // only for prime N -- stupid but lazy, see if I care void bn_inv(u8* d, const u8* a, const u8* N, u32 n) { - u8 t[512], s[512]; + u8 t[512], s[512]; - bn_copy(t, N, n); - bn_zero(s, n); - s[n-1] = 2; - bn_sub_modulus(t, s, n); - bn_exp(d, a, N, n, t, n); + bn_copy(t, N, n); + bn_zero(s, n); + s[n - 1] = 2; + bn_sub_modulus(t, s, n); + bn_exp(d, a, N, n, t, n); } diff --git a/Source/Core/Common/Crypto/bn.h b/Source/Core/Common/Crypto/bn.h index ffb6b35dd4..5c0c85b157 100644 --- a/Source/Core/Common/Crypto/bn.h +++ b/Source/Core/Common/Crypto/bn.h @@ -12,5 +12,5 @@ int bn_compare(const u8* a, const u8* b, u32 n); void bn_sub_modulus(u8* a, const u8* N, u32 n); void bn_add(u8* d, const u8* a, const u8* b, const u8* N, u32 n); void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, u32 n); -void bn_inv(u8* d, const u8* a, const u8* N, u32 n); // only for prime N +void bn_inv(u8* d, const u8* a, const u8* N, u32 n); // only for prime N void bn_exp(u8* d, const u8* a, const u8* N, u32 n, const u8* e, u32 en); diff --git a/Source/Core/Common/Crypto/ec.cpp b/Source/Core/Common/Crypto/ec.cpp index 7aafdd4838..93bbbad31d 100644 --- a/Source/Core/Common/Crypto/ec.cpp +++ b/Source/Core/Common/Crypto/ec.cpp @@ -16,379 +16,391 @@ #include "Common/Crypto/ec.h" // y**2 + x*y = x**3 + x + b -UNUSED static const u8 ec_b[30] = - {0x00,0x66,0x64,0x7e,0xde,0x6c,0x33,0x2c,0x7f,0x8c,0x09,0x23,0xbb,0x58,0x21 - ,0x3b,0x33,0x3b,0x20,0xe9,0xce,0x42,0x81,0xfe,0x11,0x5f,0x7d,0x8f,0x90,0xad}; +UNUSED static const u8 ec_b[30] = {0x00, 0x66, 0x64, 0x7e, 0xde, 0x6c, 0x33, 0x2c, 0x7f, 0x8c, + 0x09, 0x23, 0xbb, 0x58, 0x21, 0x3b, 0x33, 0x3b, 0x20, 0xe9, + 0xce, 0x42, 0x81, 0xfe, 0x11, 0x5f, 0x7d, 0x8f, 0x90, 0xad}; // order of the addition group of points -static const u8 ec_N[30] = - {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - ,0x13,0xe9,0x74,0xe7,0x2f,0x8a,0x69,0x22,0x03,0x1d,0x26,0x03,0xcf,0xe0,0xd7}; +static const u8 ec_N[30] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xe9, 0x74, 0xe7, 0x2f, + 0x8a, 0x69, 0x22, 0x03, 0x1d, 0x26, 0x03, 0xcf, 0xe0, 0xd7}; // base point -static const u8 ec_G[60] = - {0x00,0xfa,0xc9,0xdf,0xcb,0xac,0x83,0x13,0xbb,0x21,0x39,0xf1,0xbb,0x75,0x5f - ,0xef,0x65,0xbc,0x39,0x1f,0x8b,0x36,0xf8,0xf8,0xeb,0x73,0x71,0xfd,0x55,0x8b - ,0x01,0x00,0x6a,0x08,0xa4,0x19,0x03,0x35,0x06,0x78,0xe5,0x85,0x28,0xbe,0xbf - ,0x8a,0x0b,0xef,0xf8,0x67,0xa7,0xca,0x36,0x71,0x6f,0x7e,0x01,0xf8,0x10,0x52}; +static const u8 ec_G[60] = {0x00, 0xfa, 0xc9, 0xdf, 0xcb, 0xac, 0x83, 0x13, 0xbb, 0x21, 0x39, 0xf1, + 0xbb, 0x75, 0x5f, 0xef, 0x65, 0xbc, 0x39, 0x1f, 0x8b, 0x36, 0xf8, 0xf8, + 0xeb, 0x73, 0x71, 0xfd, 0x55, 0x8b, 0x01, 0x00, 0x6a, 0x08, 0xa4, 0x19, + 0x03, 0x35, 0x06, 0x78, 0xe5, 0x85, 0x28, 0xbe, 0xbf, 0x8a, 0x0b, 0xef, + 0xf8, 0x67, 0xa7, 0xca, 0x36, 0x71, 0x6f, 0x7e, 0x01, 0xf8, 0x10, 0x52}; static void elt_copy(u8* d, const u8* a) { - memcpy(d, a, 30); + memcpy(d, a, 30); } static void elt_zero(u8* d) { - memset(d, 0, 30); + memset(d, 0, 30); } static int elt_is_zero(const u8* d) { - u32 i; + u32 i; - for (i = 0; i < 30; i++) - if (d[i] != 0) - return 0; + for (i = 0; i < 30; i++) + if (d[i] != 0) + return 0; - return 1; + return 1; } static void elt_add(u8* d, const u8* a, const u8* b) { - u32 i; + u32 i; - for (i = 0; i < 30; i++) - d[i] = a[i] ^ b[i]; + for (i = 0; i < 30; i++) + d[i] = a[i] ^ b[i]; } static void elt_mul_x(u8* d, const u8* a) { - u8 carry, x, y; - u32 i; + u8 carry, x, y; + u32 i; - carry = a[0] & 1; + carry = a[0] & 1; - x = 0; - for (i = 0; i < 29; i++) { - y = a[i + 1]; - d[i] = x ^ (y >> 7); - x = y << 1; - } - d[29] = x ^ carry; + x = 0; + for (i = 0; i < 29; i++) + { + y = a[i + 1]; + d[i] = x ^ (y >> 7); + x = y << 1; + } + d[29] = x ^ carry; - d[20] ^= carry << 2; + d[20] ^= carry << 2; } static void elt_mul(u8* d, const u8* a, const u8* b) { - u32 i, n; - u8 mask; + u32 i, n; + u8 mask; - elt_zero(d); + elt_zero(d); - i = 0; - mask = 1; - for (n = 0; n < 233; n++) { - elt_mul_x(d, d); + i = 0; + mask = 1; + for (n = 0; n < 233; n++) + { + elt_mul_x(d, d); - if ((a[i] & mask) != 0) - elt_add(d, d, b); + if ((a[i] & mask) != 0) + elt_add(d, d, b); - mask >>= 1; - if (mask == 0) { - mask = 0x80; - i++; - } - } + mask >>= 1; + if (mask == 0) + { + mask = 0x80; + i++; + } + } } -static const u8 square[16] = - {0x00,0x01,0x04,0x05,0x10,0x11,0x14,0x15,0x40,0x41,0x44,0x45,0x50,0x51,0x54,0x55}; +static const u8 square[16] = {0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15, + 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55}; static void elt_square_to_wide(u8* d, const u8* a) { - u32 i; + u32 i; - for (i = 0; i < 30; i++) { - d[2*i] = square[a[i] >> 4]; - d[2*i + 1] = square[a[i] & 15]; - } + for (i = 0; i < 30; i++) + { + d[2 * i] = square[a[i] >> 4]; + d[2 * i + 1] = square[a[i] & 15]; + } } static void wide_reduce(u8* d) { - u32 i; - u8 x; + u32 i; + u8 x; - for (i = 0; i < 30; i++) { - x = d[i]; + for (i = 0; i < 30; i++) + { + x = d[i]; - d[i + 19] ^= x >> 7; - d[i + 20] ^= x << 1; + d[i + 19] ^= x >> 7; + d[i + 20] ^= x << 1; - d[i + 29] ^= x >> 1; - d[i + 30] ^= x << 7; - } + d[i + 29] ^= x >> 1; + d[i + 30] ^= x << 7; + } - x = d[30] & ~1; + x = d[30] & ~1; - d[49] ^= x >> 7; - d[50] ^= x << 1; + d[49] ^= x >> 7; + d[50] ^= x << 1; - d[59] ^= x >> 1; + d[59] ^= x >> 1; - d[30] &= 1; + d[30] &= 1; } static void elt_square(u8* d, const u8* a) { - u8 wide[60]; + u8 wide[60]; - elt_square_to_wide(wide, a); - wide_reduce(wide); + elt_square_to_wide(wide, a); + wide_reduce(wide); - elt_copy(d, wide + 30); + elt_copy(d, wide + 30); } static void itoh_tsujii(u8* d, const u8* a, const u8* b, u32 j) { - u8 t[30]; + u8 t[30]; - elt_copy(t, a); - while (j--) { - elt_square(d, t); - elt_copy(t, d); - } + elt_copy(t, a); + while (j--) + { + elt_square(d, t); + elt_copy(t, d); + } - elt_mul(d, t, b); + elt_mul(d, t, b); } static void elt_inv(u8* d, const u8* a) { - u8 t[30]; - u8 s[30]; + u8 t[30]; + u8 s[30]; - itoh_tsujii(t, a, a, 1); - itoh_tsujii(s, t, a, 1); - itoh_tsujii(t, s, s, 3); - itoh_tsujii(s, t, a, 1); - itoh_tsujii(t, s, s, 7); - itoh_tsujii(s, t, t, 14); - itoh_tsujii(t, s, a, 1); - itoh_tsujii(s, t, t, 29); - itoh_tsujii(t, s, s, 58); - itoh_tsujii(s, t, t, 116); - elt_square(d, s); + itoh_tsujii(t, a, a, 1); + itoh_tsujii(s, t, a, 1); + itoh_tsujii(t, s, s, 3); + itoh_tsujii(s, t, a, 1); + itoh_tsujii(t, s, s, 7); + itoh_tsujii(s, t, t, 14); + itoh_tsujii(t, s, a, 1); + itoh_tsujii(s, t, t, 29); + itoh_tsujii(t, s, s, 58); + itoh_tsujii(s, t, t, 116); + elt_square(d, s); } UNUSED static int point_is_on_curve(u8* p) { - u8 s[30], t[30]; - u8* x, *y; + u8 s[30], t[30]; + u8 *x, *y; - x = p; - y = p + 30; + x = p; + y = p + 30; - elt_square(t, x); - elt_mul(s, t, x); + elt_square(t, x); + elt_mul(s, t, x); - elt_add(s, s, t); + elt_add(s, s, t); - elt_square(t, y); - elt_add(s, s, t); + elt_square(t, y); + elt_add(s, s, t); - elt_mul(t, x, y); - elt_add(s, s, t); + elt_mul(t, x, y); + elt_add(s, s, t); - elt_add(s, s, ec_b); + elt_add(s, s, ec_b); - return elt_is_zero(s); + return elt_is_zero(s); } static int point_is_zero(const u8* p) { - return elt_is_zero(p) && elt_is_zero(p + 30); + return elt_is_zero(p) && elt_is_zero(p + 30); } static void point_double(u8* r, const u8* p) { - u8 s[30], t[30]; - const u8* px, *py; - u8* rx, *ry; + u8 s[30], t[30]; + const u8 *px, *py; + u8 *rx, *ry; - px = p; - py = p + 30; - rx = r; - ry = r + 30; + px = p; + py = p + 30; + rx = r; + ry = r + 30; - if (elt_is_zero(px)) { - elt_zero(rx); - elt_zero(ry); + if (elt_is_zero(px)) + { + elt_zero(rx); + elt_zero(ry); - return; - } + return; + } - elt_inv(t, px); - elt_mul(s, py, t); - elt_add(s, s, px); + elt_inv(t, px); + elt_mul(s, py, t); + elt_add(s, s, px); - elt_square(t, px); + elt_square(t, px); - elt_square(rx, s); - elt_add(rx, rx, s); - rx[29] ^= 1; + elt_square(rx, s); + elt_add(rx, rx, s); + rx[29] ^= 1; - elt_mul(ry, s, rx); - elt_add(ry, ry, rx); - elt_add(ry, ry, t); + elt_mul(ry, s, rx); + elt_add(ry, ry, rx); + elt_add(ry, ry, t); } static void point_add(u8* r, const u8* p, const u8* q) { - u8 s[30], t[30], u[30]; - const u8* px, *py, *qx, *qy; - u8* rx, *ry; + u8 s[30], t[30], u[30]; + const u8 *px, *py, *qx, *qy; + u8 *rx, *ry; - px = p; - py = p + 30; - qx = q; - qy = q + 30; - rx = r; - ry = r + 30; + px = p; + py = p + 30; + qx = q; + qy = q + 30; + rx = r; + ry = r + 30; - if (point_is_zero(p)) { - elt_copy(rx, qx); - elt_copy(ry, qy); - return; - } + if (point_is_zero(p)) + { + elt_copy(rx, qx); + elt_copy(ry, qy); + return; + } - if (point_is_zero(q)) { - elt_copy(rx, px); - elt_copy(ry, py); - return; - } + if (point_is_zero(q)) + { + elt_copy(rx, px); + elt_copy(ry, py); + return; + } - elt_add(u, px, qx); + elt_add(u, px, qx); - if (elt_is_zero(u)) { - elt_add(u, py, qy); - if (elt_is_zero(u)) - point_double(r, p); - else { - elt_zero(rx); - elt_zero(ry); - } + if (elt_is_zero(u)) + { + elt_add(u, py, qy); + if (elt_is_zero(u)) + point_double(r, p); + else + { + elt_zero(rx); + elt_zero(ry); + } - return; - } + return; + } - elt_inv(t, u); - elt_add(u, py, qy); - elt_mul(s, t, u); + elt_inv(t, u); + elt_add(u, py, qy); + elt_mul(s, t, u); - elt_square(t, s); - elt_add(t, t, s); - elt_add(t, t, qx); - t[29] ^= 1; + elt_square(t, s); + elt_add(t, t, s); + elt_add(t, t, qx); + t[29] ^= 1; - elt_mul(u, s, t); - elt_add(s, u, py); - elt_add(rx, t, px); - elt_add(ry, s, rx); + elt_mul(u, s, t); + elt_add(s, u, py); + elt_add(rx, t, px); + elt_add(ry, s, rx); } -static void point_mul(u8* d, const u8* a, const u8* b) // a is bignum +static void point_mul(u8* d, const u8* a, const u8* b) // a is bignum { - u32 i; - u8 mask; + u32 i; + u8 mask; - elt_zero(d); - elt_zero(d + 30); + elt_zero(d); + elt_zero(d + 30); - for (i = 0; i < 30; i++) - for (mask = 0x80; mask != 0; mask >>= 1) { - point_double(d, d); - if ((a[i] & mask) != 0) - point_add(d, d, b); - } + for (i = 0; i < 30; i++) + for (mask = 0x80; mask != 0; mask >>= 1) + { + point_double(d, d); + if ((a[i] & mask) != 0) + point_add(d, d, b); + } } -static void silly_random(u8 * rndArea, u8 count) +static void silly_random(u8* rndArea, u8 count) { - u16 i; - srand((unsigned) (time(nullptr))); + u16 i; + srand((unsigned)(time(nullptr))); - for (i=0;i= 0) - bn_sub_modulus(R, ec_N, 30); + point_mul(mG, m, ec_G); + elt_copy(R, mG); + if (bn_compare(R, ec_N, 30) >= 0) + bn_sub_modulus(R, ec_N, 30); - // S = m**-1*(e + Rk) (mod N) + // S = m**-1*(e + Rk) (mod N) - elt_copy(kk, k); - if (bn_compare(kk, ec_N, 30) >= 0) - bn_sub_modulus(kk, ec_N, 30); - bn_mul(S, R, kk, ec_N, 30); - bn_add(kk, S, e, ec_N, 30); - bn_inv(minv, m, ec_N, 30); - bn_mul(S, minv, kk, ec_N, 30); + elt_copy(kk, k); + if (bn_compare(kk, ec_N, 30) >= 0) + bn_sub_modulus(kk, ec_N, 30); + bn_mul(S, R, kk, ec_N, 30); + bn_add(kk, S, e, ec_N, 30); + bn_inv(minv, m, ec_N, 30); + bn_mul(S, minv, kk, ec_N, 30); } UNUSED static int check_ecdsa(u8* Q, u8* R, u8* S, const u8* hash) { - u8 Sinv[30]; - u8 e[30]; - u8 w1[30], w2[30]; - u8 r1[60], r2[60]; + u8 Sinv[30]; + u8 e[30]; + u8 w1[30], w2[30]; + u8 r1[60], r2[60]; - bn_inv(Sinv, S, ec_N, 30); + bn_inv(Sinv, S, ec_N, 30); - elt_zero(e); - memcpy(e + 10, hash, 20); + elt_zero(e); + memcpy(e + 10, hash, 20); - bn_mul(w1, e, Sinv, ec_N, 30); - bn_mul(w2, R, Sinv, ec_N, 30); + bn_mul(w1, e, Sinv, ec_N, 30); + bn_mul(w2, R, Sinv, ec_N, 30); - point_mul(r1, w1, ec_G); - point_mul(r2, w2, Q); + point_mul(r1, w1, ec_G); + point_mul(r2, w2, Q); - point_add(r1, r1, r2); + point_add(r1, r1, r2); - if (bn_compare(r1, ec_N, 30) >= 0) - bn_sub_modulus(r1, ec_N, 30); + if (bn_compare(r1, ec_N, 30) >= 0) + bn_sub_modulus(r1, ec_N, 30); - return (bn_compare(r1, R, 30) == 0); + return (bn_compare(r1, R, 30) == 0); } void ec_priv_to_pub(const u8* k, u8* Q) { - point_mul(Q, k, ec_G); + point_mul(Q, k, ec_G); } diff --git a/Source/Core/Common/DebugInterface.h b/Source/Core/Common/DebugInterface.h index 9ba89dfb06..a8fbea4efc 100644 --- a/Source/Core/Common/DebugInterface.h +++ b/Source/Core/Common/DebugInterface.h @@ -10,31 +10,34 @@ class DebugInterface { protected: - virtual ~DebugInterface() {} - + virtual ~DebugInterface() {} public: - virtual std::string Disassemble(unsigned int /*address*/) { return "NODEBUGGER"; } - virtual void GetRawMemoryString(int /*memory*/, unsigned int /*address*/, char* dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");} - virtual int GetInstructionSize(int /*instruction*/) {return 1;} - virtual bool IsAlive() {return true;} - virtual bool IsBreakpoint(unsigned int /*address*/) {return false;} - virtual void SetBreakpoint(unsigned int /*address*/){} - virtual void ClearBreakpoint(unsigned int /*address*/){} - virtual void ClearAllBreakpoints() {} - virtual void ToggleBreakpoint(unsigned int /*address*/){} - virtual void AddWatch(unsigned int /*address*/){} - virtual void ClearAllMemChecks() {} - virtual bool IsMemCheck(unsigned int /*address*/) {return false;} - virtual void ToggleMemCheck(unsigned int /*address*/){} - virtual unsigned int ReadMemory(unsigned int /*address*/){return 0;} - virtual void WriteExtraMemory(int /*memory*/, unsigned int /*value*/, unsigned int /*address*/) {} - virtual unsigned int ReadExtraMemory(int /*memory*/, unsigned int /*address*/){return 0;} - virtual unsigned int ReadInstruction(unsigned int /*address*/){return 0;} - virtual unsigned int GetPC() {return 0;} - virtual void SetPC(unsigned int /*address*/) {} - virtual void Step() {} - virtual void RunToBreakpoint() {} - virtual void InsertBLR(unsigned int /*address*/, unsigned int /*value*/) {} - virtual int GetColor(unsigned int /*address*/){return 0xFFFFFFFF;} - virtual std::string GetDescription(unsigned int /*address*/) = 0; + virtual std::string Disassemble(unsigned int /*address*/) { return "NODEBUGGER"; } + virtual void GetRawMemoryString(int /*memory*/, unsigned int /*address*/, char* dest, + int /*max_size*/) + { + strcpy(dest, "NODEBUGGER"); + } + virtual int GetInstructionSize(int /*instruction*/) { return 1; } + virtual bool IsAlive() { return true; } + virtual bool IsBreakpoint(unsigned int /*address*/) { return false; } + virtual void SetBreakpoint(unsigned int /*address*/) {} + virtual void ClearBreakpoint(unsigned int /*address*/) {} + virtual void ClearAllBreakpoints() {} + virtual void ToggleBreakpoint(unsigned int /*address*/) {} + virtual void AddWatch(unsigned int /*address*/) {} + virtual void ClearAllMemChecks() {} + virtual bool IsMemCheck(unsigned int /*address*/) { return false; } + virtual void ToggleMemCheck(unsigned int /*address*/) {} + virtual unsigned int ReadMemory(unsigned int /*address*/) { return 0; } + virtual void WriteExtraMemory(int /*memory*/, unsigned int /*value*/, unsigned int /*address*/) {} + virtual unsigned int ReadExtraMemory(int /*memory*/, unsigned int /*address*/) { return 0; } + virtual unsigned int ReadInstruction(unsigned int /*address*/) { return 0; } + virtual unsigned int GetPC() { return 0; } + virtual void SetPC(unsigned int /*address*/) {} + virtual void Step() {} + virtual void RunToBreakpoint() {} + virtual void InsertBLR(unsigned int /*address*/, unsigned int /*value*/) {} + virtual int GetColor(unsigned int /*address*/) { return 0xFFFFFFFF; } + virtual std::string GetDescription(unsigned int /*address*/) = 0; }; diff --git a/Source/Core/Common/ENetUtil.cpp b/Source/Core/Common/ENetUtil.cpp index 365d69b04e..8ad19fb0bf 100644 --- a/Source/Core/Common/ENetUtil.cpp +++ b/Source/Core/Common/ENetUtil.cpp @@ -8,35 +8,32 @@ namespace ENetUtil { - void WakeupThread(ENetHost* host) { - // Send ourselves a spurious message. This is hackier than it should be. - // comex reported this as https://github.com/lsalzman/enet/issues/23, so - // hopefully there will be a better way to do it in the future. - ENetAddress address; - if (host->address.port != 0) - address.port = host->address.port; - else - enet_socket_get_address(host->socket, &address); - address.host = 0x0100007f; // localhost - u8 byte = 0; - ENetBuffer buf; - buf.data = &byte; - buf.dataLength = 1; - enet_socket_send(host->socket, &address, &buf, 1); + // Send ourselves a spurious message. This is hackier than it should be. + // comex reported this as https://github.com/lsalzman/enet/issues/23, so + // hopefully there will be a better way to do it in the future. + ENetAddress address; + if (host->address.port != 0) + address.port = host->address.port; + else + enet_socket_get_address(host->socket, &address); + address.host = 0x0100007f; // localhost + u8 byte = 0; + ENetBuffer buf; + buf.data = &byte; + buf.dataLength = 1; + enet_socket_send(host->socket, &address, &buf, 1); } int ENET_CALLBACK InterceptCallback(ENetHost* host, ENetEvent* event) { - // wakeup packet received - if (host->receivedDataLength == 1 && host->receivedData[0] == 0) - { - event->type = (ENetEventType) 42; - return 1; - } - return 0; + // wakeup packet received + if (host->receivedDataLength == 1 && host->receivedData[0] == 0) + { + event->type = (ENetEventType)42; + return 1; + } + return 0; } - - } diff --git a/Source/Core/Common/ENetUtil.h b/Source/Core/Common/ENetUtil.h index b727f9e108..7b3ee9e7a4 100644 --- a/Source/Core/Common/ENetUtil.h +++ b/Source/Core/Common/ENetUtil.h @@ -8,8 +8,6 @@ namespace ENetUtil { - void WakeupThread(ENetHost* host); int ENET_CALLBACK InterceptCallback(ENetHost* host, ENetEvent* event); - } diff --git a/Source/Core/Common/Event.h b/Source/Core/Common/Event.h index 49cf543ead..a85f3326a7 100644 --- a/Source/Core/Common/Event.h +++ b/Source/Core/Common/Event.h @@ -22,54 +22,53 @@ #include "Common/Flag.h" -namespace Common { - +namespace Common +{ class Event final { public: - void Set() - { - if (m_flag.TestAndSet()) - { - std::lock_guard lk(m_mutex); - m_condvar.notify_one(); - } - } + void Set() + { + if (m_flag.TestAndSet()) + { + std::lock_guard lk(m_mutex); + m_condvar.notify_one(); + } + } - void Wait() - { - if (m_flag.TestAndClear()) - return; + void Wait() + { + if (m_flag.TestAndClear()) + return; - std::unique_lock lk(m_mutex); - m_condvar.wait(lk, [&]{ return m_flag.TestAndClear(); }); - } + std::unique_lock lk(m_mutex); + m_condvar.wait(lk, [&] { return m_flag.TestAndClear(); }); + } - template - bool WaitFor(const std::chrono::duration& rel_time) - { - if (m_flag.TestAndClear()) - return true; + template + bool WaitFor(const std::chrono::duration& rel_time) + { + if (m_flag.TestAndClear()) + return true; - std::unique_lock lk(m_mutex); - bool signaled = m_condvar.wait_for(lk, rel_time, - [&]{ return m_flag.TestAndClear(); }); + std::unique_lock lk(m_mutex); + bool signaled = m_condvar.wait_for(lk, rel_time, [&] { return m_flag.TestAndClear(); }); - return signaled; - } + return signaled; + } - void Reset() - { - // no other action required, since wait loops on - // the predicate and any lingering signal will get - // cleared on the first iteration - m_flag.Clear(); - } + void Reset() + { + // no other action required, since wait loops on + // the predicate and any lingering signal will get + // cleared on the first iteration + m_flag.Clear(); + } private: - Flag m_flag; - std::condition_variable m_condvar; - std::mutex m_mutex; + Flag m_flag; + std::condition_variable m_condvar; + std::mutex m_mutex; }; } // namespace Common diff --git a/Source/Core/Common/FPURoundMode.h b/Source/Core/Common/FPURoundMode.h index cf3f496c16..a2270c6d5b 100644 --- a/Source/Core/Common/FPURoundMode.h +++ b/Source/Core/Common/FPURoundMode.h @@ -8,29 +8,30 @@ namespace FPURoundMode { - // TODO: MSVC currently produces broken code: - // https://connect.microsoft.com/VisualStudio/feedback/details/828892/vc-2013-miscompilation-with-enums-and-bit-fields - // Once that is fixed, change types in SetRoundMode(), SetSIMDMode(), and in UReg_FPSCR to 'RoundMode'. +// TODO: MSVC currently produces broken code: +// https://connect.microsoft.com/VisualStudio/feedback/details/828892/vc-2013-miscompilation-with-enums-and-bit-fields +// Once that is fixed, change types in SetRoundMode(), SetSIMDMode(), and in UReg_FPSCR to +// 'RoundMode'. - enum RoundMode - { - ROUND_NEAR = 0, - ROUND_CHOP = 1, - ROUND_UP = 2, - ROUND_DOWN = 3 - }; - enum PrecisionMode - { - PREC_24 = 0, - PREC_53 = 1, - PREC_64 = 2 - }; +enum RoundMode +{ + ROUND_NEAR = 0, + ROUND_CHOP = 1, + ROUND_UP = 2, + ROUND_DOWN = 3 +}; +enum PrecisionMode +{ + PREC_24 = 0, + PREC_53 = 1, + PREC_64 = 2 +}; - void SetRoundMode(int mode); +void SetRoundMode(int mode); - void SetPrecisionMode(PrecisionMode mode); +void SetPrecisionMode(PrecisionMode mode); - void SetSIMDMode(int rounding_mode, bool non_ieee_mode); +void SetSIMDMode(int rounding_mode, bool non_ieee_mode); /* * There are two different flavors of float to int conversion: @@ -39,7 +40,7 @@ namespace FPURoundMode * The first rounds according to the MXCSR rounding bits. * The second one always uses round towards zero. */ - void SaveSIMDState(); - void LoadSIMDState(); - void LoadDefaultSIMDState(); +void SaveSIMDState(); +void LoadSIMDState(); +void LoadDefaultSIMDState(); } diff --git a/Source/Core/Common/FifoQueue.h b/Source/Core/Common/FifoQueue.h index 1aa2bcc1b4..1a3c5d817d 100644 --- a/Source/Core/Common/FifoQueue.h +++ b/Source/Core/Common/FifoQueue.h @@ -15,111 +15,96 @@ namespace Common { - template class FifoQueue { public: - FifoQueue() : m_size(0) - { - m_write_ptr = m_read_ptr = new ElementPtr(); - } + FifoQueue() : m_size(0) { m_write_ptr = m_read_ptr = new ElementPtr(); } + ~FifoQueue() + { + // this will empty out the whole queue + delete m_read_ptr; + } - ~FifoQueue() - { - // this will empty out the whole queue - delete m_read_ptr; - } + u32 Size() const + { + static_assert(NeedSize, "using Size() on FifoQueue without NeedSize"); + return m_size.load(); + } - u32 Size() const - { - static_assert(NeedSize, "using Size() on FifoQueue without NeedSize"); - return m_size.load(); - } + bool Empty() const { return !m_read_ptr->next.load(); } + T& Front() const { return m_read_ptr->current; } + template + void Push(Arg&& t) + { + // create the element, add it to the queue + m_write_ptr->current = std::forward(t); + // set the next pointer to a new element ptr + // then advance the write pointer + ElementPtr* new_ptr = new ElementPtr(); + m_write_ptr->next.store(new_ptr, std::memory_order_release); + m_write_ptr = new_ptr; + if (NeedSize) + m_size++; + } - bool Empty() const - { - return !m_read_ptr->next.load(); - } + void Pop() + { + if (NeedSize) + m_size--; + ElementPtr* tmpptr = m_read_ptr; + // advance the read pointer + m_read_ptr = tmpptr->next.load(); + // set the next element to nullptr to stop the recursive deletion + tmpptr->next.store(nullptr); + delete tmpptr; // this also deletes the element + } - T& Front() const - { - return m_read_ptr->current; - } + bool Pop(T& t) + { + if (Empty()) + return false; - template - void Push(Arg&& t) - { - // create the element, add it to the queue - m_write_ptr->current = std::forward(t); - // set the next pointer to a new element ptr - // then advance the write pointer - ElementPtr* new_ptr = new ElementPtr(); - m_write_ptr->next.store(new_ptr, std::memory_order_release); - m_write_ptr = new_ptr; - if (NeedSize) - m_size++; - } + if (NeedSize) + m_size--; - void Pop() - { - if (NeedSize) - m_size--; - ElementPtr* tmpptr = m_read_ptr; - // advance the read pointer - m_read_ptr = tmpptr->next.load(); - // set the next element to nullptr to stop the recursive deletion - tmpptr->next.store(nullptr); - delete tmpptr; // this also deletes the element - } + ElementPtr* tmpptr = m_read_ptr; + m_read_ptr = tmpptr->next.load(std::memory_order_acquire); + t = std::move(tmpptr->current); + tmpptr->next.store(nullptr); + delete tmpptr; + return true; + } - bool Pop(T& t) - { - if (Empty()) - return false; - - if (NeedSize) - m_size--; - - ElementPtr* tmpptr = m_read_ptr; - m_read_ptr = tmpptr->next.load(std::memory_order_acquire); - t = std::move(tmpptr->current); - tmpptr->next.store(nullptr); - delete tmpptr; - return true; - } - - // not thread-safe - void Clear() - { - m_size.store(0); - delete m_read_ptr; - m_write_ptr = m_read_ptr = new ElementPtr(); - } + // not thread-safe + void Clear() + { + m_size.store(0); + delete m_read_ptr; + m_write_ptr = m_read_ptr = new ElementPtr(); + } private: - // stores a pointer to element - // and a pointer to the next ElementPtr - class ElementPtr - { - public: - ElementPtr() : next(nullptr) {} + // stores a pointer to element + // and a pointer to the next ElementPtr + class ElementPtr + { + public: + ElementPtr() : next(nullptr) {} + ~ElementPtr() + { + ElementPtr* next_ptr = next.load(); - ~ElementPtr() - { - ElementPtr* next_ptr = next.load(); + if (next_ptr) + delete next_ptr; + } - if (next_ptr) - delete next_ptr; - } + T current; + std::atomic next; + }; - T current; - std::atomic next; - }; - - ElementPtr* m_write_ptr; - ElementPtr* m_read_ptr; - std::atomic m_size; + ElementPtr* m_write_ptr; + ElementPtr* m_read_ptr; + std::atomic m_size; }; - } diff --git a/Source/Core/Common/FileSearch.cpp b/Source/Core/Common/FileSearch.cpp index 451c451030..6a53f12e02 100644 --- a/Source/Core/Common/FileSearch.cpp +++ b/Source/Core/Common/FileSearch.cpp @@ -9,47 +9,51 @@ #include "Common/FileSearch.h" #include "Common/FileUtil.h" -static std::vector FileSearchWithTest(const std::vector& directories, bool recursive, std::function callback) +static std::vector +FileSearchWithTest(const std::vector& directories, bool recursive, + std::function callback) { - std::vector result; - for (const std::string& directory : directories) - { - File::FSTEntry top = File::ScanDirectoryTree(directory, recursive); + std::vector result; + for (const std::string& directory : directories) + { + File::FSTEntry top = File::ScanDirectoryTree(directory, recursive); - std::function DoEntry; - DoEntry = [&](File::FSTEntry& entry) { - if (callback(entry)) - result.push_back(entry.physicalName); - for (auto& child : entry.children) - DoEntry(child); - }; - for (auto& child : top.children) - DoEntry(child); - } - // remove duplicates - std::sort(result.begin(), result.end()); - result.erase(std::unique(result.begin(), result.end()), result.end()); - return result; + std::function DoEntry; + DoEntry = [&](File::FSTEntry& entry) { + if (callback(entry)) + result.push_back(entry.physicalName); + for (auto& child : entry.children) + DoEntry(child); + }; + for (auto& child : top.children) + DoEntry(child); + } + // remove duplicates + std::sort(result.begin(), result.end()); + result.erase(std::unique(result.begin(), result.end()), result.end()); + return result; } -std::vector DoFileSearch(const std::vector& exts, const std::vector& directories, bool recursive) +std::vector DoFileSearch(const std::vector& exts, + const std::vector& directories, bool recursive) { - bool accept_all = std::find(exts.begin(), exts.end(), "") != exts.end(); - return FileSearchWithTest(directories, recursive, [&](const File::FSTEntry& entry) { - if (accept_all) - return true; - std::string name = entry.virtualName; - std::transform(name.begin(), name.end(), name.begin(), ::tolower); - return std::any_of(exts.begin(), exts.end(), [&](const std::string& ext) { - return name.length() >= ext.length() && name.compare(name.length() - ext.length(), ext.length(), ext) == 0; - }); - }); + bool accept_all = std::find(exts.begin(), exts.end(), "") != exts.end(); + return FileSearchWithTest(directories, recursive, [&](const File::FSTEntry& entry) { + if (accept_all) + return true; + std::string name = entry.virtualName; + std::transform(name.begin(), name.end(), name.begin(), ::tolower); + return std::any_of(exts.begin(), exts.end(), [&](const std::string& ext) { + return name.length() >= ext.length() && + name.compare(name.length() - ext.length(), ext.length(), ext) == 0; + }); + }); } // Result includes the passed directories themselves as well as their subdirectories. -std::vector FindSubdirectories(const std::vector& directories, bool recursive) +std::vector FindSubdirectories(const std::vector& directories, + bool recursive) { - return FileSearchWithTest(directories, true, [&](const File::FSTEntry& entry) { - return entry.isDirectory; - }); + return FileSearchWithTest(directories, true, + [&](const File::FSTEntry& entry) { return entry.isDirectory; }); } diff --git a/Source/Core/Common/FileSearch.h b/Source/Core/Common/FileSearch.h index 153408e7ff..da29f4fb8a 100644 --- a/Source/Core/Common/FileSearch.h +++ b/Source/Core/Common/FileSearch.h @@ -7,5 +7,8 @@ #include #include -std::vector DoFileSearch(const std::vector& exts, const std::vector& directories, bool recursive = false); -std::vector FindSubdirectories(const std::vector& directories, bool recursive); +std::vector DoFileSearch(const std::vector& exts, + const std::vector& directories, + bool recursive = false); +std::vector FindSubdirectories(const std::vector& directories, + bool recursive); diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index c4563c397f..8317550297 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -9,8 +9,8 @@ #include #include #include -#include #include +#include #include "Common/Common.h" #include "Common/CommonFuncs.h" @@ -20,10 +20,10 @@ #include "Common/Logging/Log.h" #ifdef _WIN32 -#include // for GetSaveFileName -#include // getcwd +#include // for GetSaveFileName +#include // getcwd #include -#include // guid stuff +#include // guid stuff #include #include #else @@ -42,7 +42,7 @@ #endif #ifndef S_ISDIR -#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) +#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) #endif #if defined BSD4_4 || defined __FreeBSD__ @@ -55,971 +55,964 @@ // REMEMBER: strdup considered harmful! namespace File { - // Remove any ending forward slashes from directory paths // Modifies argument. static void StripTailDirSlashes(std::string& fname) { - if (fname.length() > 1) - { - while (fname.back() == DIR_SEP_CHR) - fname.pop_back(); - } + if (fname.length() > 1) + { + while (fname.back() == DIR_SEP_CHR) + fname.pop_back(); + } } // Returns true if file filename exists bool Exists(const std::string& filename) { - struct stat64 file_info; + struct stat64 file_info; - std::string copy(filename); - StripTailDirSlashes(copy); + std::string copy(filename); + StripTailDirSlashes(copy); #ifdef _WIN32 - int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); + int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); #else - int result = stat64(copy.c_str(), &file_info); + int result = stat64(copy.c_str(), &file_info); #endif - return (result == 0); + return (result == 0); } // Returns true if filename is a directory bool IsDirectory(const std::string& filename) { - struct stat64 file_info; + struct stat64 file_info; - std::string copy(filename); - StripTailDirSlashes(copy); + std::string copy(filename); + StripTailDirSlashes(copy); #ifdef _WIN32 - int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); + int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); #else - int result = stat64(copy.c_str(), &file_info); + int result = stat64(copy.c_str(), &file_info); #endif - if (result < 0) - { - WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s", - filename.c_str(), GetLastErrorMsg().c_str()); - return false; - } + if (result < 0) + { + WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s", filename.c_str(), + GetLastErrorMsg().c_str()); + return false; + } - return S_ISDIR(file_info.st_mode); + return S_ISDIR(file_info.st_mode); } // Deletes a given filename, return true on success // Doesn't supports deleting a directory bool Delete(const std::string& filename) { - INFO_LOG(COMMON, "Delete: file %s", filename.c_str()); + INFO_LOG(COMMON, "Delete: file %s", filename.c_str()); - // Return true because we care about the file no - // being there, not the actual delete. - if (!Exists(filename)) - { - WARN_LOG(COMMON, "Delete: %s does not exist", filename.c_str()); - return true; - } + // Return true because we care about the file no + // being there, not the actual delete. + if (!Exists(filename)) + { + WARN_LOG(COMMON, "Delete: %s does not exist", filename.c_str()); + return true; + } - // We can't delete a directory - if (IsDirectory(filename)) - { - WARN_LOG(COMMON, "Delete failed: %s is a directory", filename.c_str()); - return false; - } + // We can't delete a directory + if (IsDirectory(filename)) + { + WARN_LOG(COMMON, "Delete failed: %s is a directory", filename.c_str()); + return false; + } #ifdef _WIN32 - if (!DeleteFile(UTF8ToTStr(filename).c_str())) - { - WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", - filename.c_str(), GetLastErrorMsg().c_str()); - return false; - } + if (!DeleteFile(UTF8ToTStr(filename).c_str())) + { + WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", filename.c_str(), + GetLastErrorMsg().c_str()); + return false; + } #else - if (unlink(filename.c_str()) == -1) - { - WARN_LOG(COMMON, "Delete: unlink failed on %s: %s", - filename.c_str(), GetLastErrorMsg().c_str()); - return false; - } + if (unlink(filename.c_str()) == -1) + { + WARN_LOG(COMMON, "Delete: unlink failed on %s: %s", filename.c_str(), + GetLastErrorMsg().c_str()); + return false; + } #endif - return true; + return true; } // Returns true if successful, or path already exists. bool CreateDir(const std::string& path) { - INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str()); + INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str()); #ifdef _WIN32 - if (::CreateDirectory(UTF8ToTStr(path).c_str(), nullptr)) - return true; - DWORD error = GetLastError(); - if (error == ERROR_ALREADY_EXISTS) - { - WARN_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str()); - return true; - } - ERROR_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: %i", path.c_str(), error); - return false; + if (::CreateDirectory(UTF8ToTStr(path).c_str(), nullptr)) + return true; + DWORD error = GetLastError(); + if (error == ERROR_ALREADY_EXISTS) + { + WARN_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str()); + return true; + } + ERROR_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: %i", path.c_str(), error); + return false; #else - if (mkdir(path.c_str(), 0755) == 0) - return true; + if (mkdir(path.c_str(), 0755) == 0) + return true; - int err = errno; + int err = errno; - if (err == EEXIST) - { - WARN_LOG(COMMON, "CreateDir: mkdir failed on %s: already exists", path.c_str()); - return true; - } + if (err == EEXIST) + { + WARN_LOG(COMMON, "CreateDir: mkdir failed on %s: already exists", path.c_str()); + return true; + } - ERROR_LOG(COMMON, "CreateDir: mkdir failed on %s: %s", path.c_str(), strerror(err)); - return false; + ERROR_LOG(COMMON, "CreateDir: mkdir failed on %s: %s", path.c_str(), strerror(err)); + return false; #endif } // Creates the full path of fullPath returns true on success bool CreateFullPath(const std::string& fullPath) { - int panicCounter = 100; - INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str()); + int panicCounter = 100; + INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str()); - if (File::Exists(fullPath)) - { - INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str()); - return true; - } + if (File::Exists(fullPath)) + { + INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str()); + return true; + } - size_t position = 0; - while (true) - { - // Find next sub path - position = fullPath.find(DIR_SEP_CHR, position); + size_t position = 0; + while (true) + { + // Find next sub path + position = fullPath.find(DIR_SEP_CHR, position); - // we're done, yay! - if (position == fullPath.npos) - return true; + // we're done, yay! + if (position == fullPath.npos) + return true; - // Include the '/' so the first call is CreateDir("/") rather than CreateDir("") - std::string const subPath(fullPath.substr(0, position + 1)); - if (!File::IsDirectory(subPath)) - File::CreateDir(subPath); + // Include the '/' so the first call is CreateDir("/") rather than CreateDir("") + std::string const subPath(fullPath.substr(0, position + 1)); + if (!File::IsDirectory(subPath)) + File::CreateDir(subPath); - // A safety check - panicCounter--; - if (panicCounter <= 0) - { - ERROR_LOG(COMMON, "CreateFullPath: directory structure is too deep"); - return false; - } - position++; - } + // A safety check + panicCounter--; + if (panicCounter <= 0) + { + ERROR_LOG(COMMON, "CreateFullPath: directory structure is too deep"); + return false; + } + position++; + } } - // Deletes a directory filename, returns true on success bool DeleteDir(const std::string& filename) { - INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str()); + INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str()); - // check if a directory - if (!File::IsDirectory(filename)) - { - ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str()); - return false; - } + // check if a directory + if (!File::IsDirectory(filename)) + { + ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str()); + return false; + } #ifdef _WIN32 - if (::RemoveDirectory(UTF8ToTStr(filename).c_str())) - return true; + if (::RemoveDirectory(UTF8ToTStr(filename).c_str())) + return true; #else - if (rmdir(filename.c_str()) == 0) - return true; + if (rmdir(filename.c_str()) == 0) + return true; #endif - ERROR_LOG(COMMON, "DeleteDir: %s: %s", filename.c_str(), GetLastErrorMsg().c_str()); + ERROR_LOG(COMMON, "DeleteDir: %s: %s", filename.c_str(), GetLastErrorMsg().c_str()); - return false; + return false; } // renames file srcFilename to destFilename, returns true on success bool Rename(const std::string& srcFilename, const std::string& destFilename) { - INFO_LOG(COMMON, "Rename: %s --> %s", - srcFilename.c_str(), destFilename.c_str()); + INFO_LOG(COMMON, "Rename: %s --> %s", srcFilename.c_str(), destFilename.c_str()); #ifdef _WIN32 - auto sf = UTF8ToTStr(srcFilename); - auto df = UTF8ToTStr(destFilename); - // The Internet seems torn about whether ReplaceFile is atomic or not. - // Hopefully it's atomic enough... - if (ReplaceFile(df.c_str(), sf.c_str(), nullptr, REPLACEFILE_IGNORE_MERGE_ERRORS, nullptr, nullptr)) - return true; - // Might have failed because the destination doesn't exist. - if (GetLastError() == ERROR_FILE_NOT_FOUND) - { - if (MoveFile(sf.c_str(), df.c_str())) - return true; - } + auto sf = UTF8ToTStr(srcFilename); + auto df = UTF8ToTStr(destFilename); + // The Internet seems torn about whether ReplaceFile is atomic or not. + // Hopefully it's atomic enough... + if (ReplaceFile(df.c_str(), sf.c_str(), nullptr, REPLACEFILE_IGNORE_MERGE_ERRORS, nullptr, + nullptr)) + return true; + // Might have failed because the destination doesn't exist. + if (GetLastError() == ERROR_FILE_NOT_FOUND) + { + if (MoveFile(sf.c_str(), df.c_str())) + return true; + } #else - if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) - return true; + if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) + return true; #endif - ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); - return false; + ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), + GetLastErrorMsg().c_str()); + return false; } #ifndef _WIN32 static void FSyncPath(const char* path) { - int fd = open(path, O_RDONLY); - if (fd != -1) - { - fsync(fd); - close(fd); - } + int fd = open(path, O_RDONLY); + if (fd != -1) + { + fsync(fd); + close(fd); + } } #endif bool RenameSync(const std::string& srcFilename, const std::string& destFilename) { - if (!Rename(srcFilename, destFilename)) - return false; + if (!Rename(srcFilename, destFilename)) + return false; #ifdef _WIN32 - int fd = _topen(UTF8ToTStr(srcFilename).c_str(), _O_RDONLY); - if (fd != -1) - { - _commit(fd); - close(fd); - } + int fd = _topen(UTF8ToTStr(srcFilename).c_str(), _O_RDONLY); + if (fd != -1) + { + _commit(fd); + close(fd); + } #else - char* path = strdup(srcFilename.c_str()); - FSyncPath(path); - FSyncPath(dirname(path)); - free(path); - path = strdup(destFilename.c_str()); - FSyncPath(dirname(path)); - free(path); + char* path = strdup(srcFilename.c_str()); + FSyncPath(path); + FSyncPath(dirname(path)); + free(path); + path = strdup(destFilename.c_str()); + FSyncPath(dirname(path)); + free(path); #endif - return true; + return true; } // copies file srcFilename to destFilename, returns true on success bool Copy(const std::string& srcFilename, const std::string& destFilename) { - INFO_LOG(COMMON, "Copy: %s --> %s", - srcFilename.c_str(), destFilename.c_str()); + INFO_LOG(COMMON, "Copy: %s --> %s", srcFilename.c_str(), destFilename.c_str()); #ifdef _WIN32 - if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE)) - return true; + if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE)) + return true; - ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); - return false; + ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), + GetLastErrorMsg().c_str()); + return false; #else - // buffer size +// buffer size #define BSIZE 1024 - char buffer[BSIZE]; + char buffer[BSIZE]; - // Open input file - std::ifstream input; - OpenFStream(input, srcFilename, std::ifstream::in | std::ifstream::binary); - if (!input.is_open()) - { - ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); - return false; - } + // Open input file + std::ifstream input; + OpenFStream(input, srcFilename, std::ifstream::in | std::ifstream::binary); + if (!input.is_open()) + { + ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), + GetLastErrorMsg().c_str()); + return false; + } - // open output file - File::IOFile output(destFilename, "wb"); + // open output file + File::IOFile output(destFilename, "wb"); - if (!output.IsOpen()) - { - ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); - return false; - } + if (!output.IsOpen()) + { + ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s", srcFilename.c_str(), + destFilename.c_str(), GetLastErrorMsg().c_str()); + return false; + } - // copy loop - while (!input.eof()) - { - // read input - input.read(buffer, BSIZE); - if (!input) - { - ERROR_LOG(COMMON, - "Copy: failed reading from source, %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); - return false; - } + // copy loop + while (!input.eof()) + { + // read input + input.read(buffer, BSIZE); + if (!input) + { + ERROR_LOG(COMMON, "Copy: failed reading from source, %s --> %s: %s", srcFilename.c_str(), + destFilename.c_str(), GetLastErrorMsg().c_str()); + return false; + } - // write output - if (!output.WriteBytes(buffer, BSIZE)) - { - ERROR_LOG(COMMON, - "Copy: failed writing to output, %s --> %s: %s", - srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str()); - return false; - } - } + // write output + if (!output.WriteBytes(buffer, BSIZE)) + { + ERROR_LOG(COMMON, "Copy: failed writing to output, %s --> %s: %s", srcFilename.c_str(), + destFilename.c_str(), GetLastErrorMsg().c_str()); + return false; + } + } - return true; + return true; #endif } // Returns the size of filename (64bit) u64 GetSize(const std::string& filename) { - if (!Exists(filename)) - { - WARN_LOG(COMMON, "GetSize: failed %s: No such file", filename.c_str()); - return 0; - } + if (!Exists(filename)) + { + WARN_LOG(COMMON, "GetSize: failed %s: No such file", filename.c_str()); + return 0; + } - if (IsDirectory(filename)) - { - WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str()); - return 0; - } + if (IsDirectory(filename)) + { + WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str()); + return 0; + } - struct stat64 buf; + struct stat64 buf; #ifdef _WIN32 - if (_tstat64(UTF8ToTStr(filename).c_str(), &buf) == 0) + if (_tstat64(UTF8ToTStr(filename).c_str(), &buf) == 0) #else - if (stat64(filename.c_str(), &buf) == 0) + if (stat64(filename.c_str(), &buf) == 0) #endif - { - DEBUG_LOG(COMMON, "GetSize: %s: %lld", - filename.c_str(), (long long)buf.st_size); - return buf.st_size; - } + { + DEBUG_LOG(COMMON, "GetSize: %s: %lld", filename.c_str(), (long long)buf.st_size); + return buf.st_size; + } - ERROR_LOG(COMMON, "GetSize: Stat failed %s: %s", - filename.c_str(), GetLastErrorMsg().c_str()); - return 0; + ERROR_LOG(COMMON, "GetSize: Stat failed %s: %s", filename.c_str(), GetLastErrorMsg().c_str()); + return 0; } // Overloaded GetSize, accepts file descriptor u64 GetSize(const int fd) { - struct stat64 buf; - if (fstat64(fd, &buf) != 0) - { - ERROR_LOG(COMMON, "GetSize: stat failed %i: %s", - fd, GetLastErrorMsg().c_str()); - return 0; - } - return buf.st_size; + struct stat64 buf; + if (fstat64(fd, &buf) != 0) + { + ERROR_LOG(COMMON, "GetSize: stat failed %i: %s", fd, GetLastErrorMsg().c_str()); + return 0; + } + return buf.st_size; } // Overloaded GetSize, accepts FILE* u64 GetSize(FILE* f) { - // can't use off_t here because it can be 32-bit - u64 pos = ftello(f); - if (fseeko(f, 0, SEEK_END) != 0) - { - ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", - f, GetLastErrorMsg().c_str()); - return 0; - } + // can't use off_t here because it can be 32-bit + u64 pos = ftello(f); + if (fseeko(f, 0, SEEK_END) != 0) + { + ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", f, GetLastErrorMsg().c_str()); + return 0; + } - u64 size = ftello(f); - if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) - { - ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", - f, GetLastErrorMsg().c_str()); - return 0; - } + u64 size = ftello(f); + if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) + { + ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", f, GetLastErrorMsg().c_str()); + return 0; + } - return size; + return size; } // creates an empty file filename, returns true on success bool CreateEmptyFile(const std::string& filename) { - INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); + INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); - if (!File::IOFile(filename, "wb")) - { - ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", - filename.c_str(), GetLastErrorMsg().c_str()); - return false; - } + if (!File::IOFile(filename, "wb")) + { + ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", filename.c_str(), + GetLastErrorMsg().c_str()); + return false; + } - return true; + return true; } - // Scans the directory tree gets, starting from _Directory and adds the // results into parentEntry. Returns the number of files+directories found FSTEntry ScanDirectoryTree(const std::string& directory, bool recursive) { - INFO_LOG(COMMON, "ScanDirectoryTree: directory %s", directory.c_str()); - // How many files + directories we found - FSTEntry parent_entry; - parent_entry.physicalName = directory; - parent_entry.isDirectory = true; - parent_entry.size = 0; + INFO_LOG(COMMON, "ScanDirectoryTree: directory %s", directory.c_str()); + // How many files + directories we found + FSTEntry parent_entry; + parent_entry.physicalName = directory; + parent_entry.isDirectory = true; + parent_entry.size = 0; #ifdef _WIN32 - // Find the first file in the directory. - WIN32_FIND_DATA ffd; + // Find the first file in the directory. + WIN32_FIND_DATA ffd; - HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); - if (hFind == INVALID_HANDLE_VALUE) - { - FindClose(hFind); - return parent_entry; - } - // Windows loop - do - { - const std::string virtual_name(TStrToUTF8(ffd.cFileName)); + HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); + if (hFind == INVALID_HANDLE_VALUE) + { + FindClose(hFind); + return parent_entry; + } + // Windows loop + do + { + const std::string virtual_name(TStrToUTF8(ffd.cFileName)); #else - struct dirent dirent, *result = nullptr; + struct dirent dirent, *result = nullptr; - DIR* dirp = opendir(directory.c_str()); - if (!dirp) - return parent_entry; + DIR* dirp = opendir(directory.c_str()); + if (!dirp) + return parent_entry; - // non Windows loop - while (!readdir_r(dirp, &dirent, &result) && result) - { - const std::string virtual_name(result->d_name); - #endif - if (virtual_name == "." || virtual_name == "..") - continue; - auto physical_name = directory + DIR_SEP + virtual_name; - FSTEntry entry; - entry.isDirectory = IsDirectory(physical_name); - if (entry.isDirectory) - { - if (recursive) - entry = ScanDirectoryTree(physical_name, true); - else - entry.size = 0; - parent_entry.size += entry.size; - } - else - { - entry.size = GetSize(physical_name); - } - entry.virtualName = virtual_name; - entry.physicalName = physical_name; - - ++parent_entry.size; - // Push into the tree - parent_entry.children.push_back(entry); - #ifdef _WIN32 - } while (FindNextFile(hFind, &ffd) != 0); - FindClose(hFind); -#else - } - closedir(dirp); + // non Windows loop + while (!readdir_r(dirp, &dirent, &result) && result) + { + const std::string virtual_name(result->d_name); #endif - // Return number of entries found. - return parent_entry; -} + if (virtual_name == "." || virtual_name == "..") + continue; + auto physical_name = directory + DIR_SEP + virtual_name; + FSTEntry entry; + entry.isDirectory = IsDirectory(physical_name); + if (entry.isDirectory) + { + if (recursive) + entry = ScanDirectoryTree(physical_name, true); + else + entry.size = 0; + parent_entry.size += entry.size; + } + else + { + entry.size = GetSize(physical_name); + } + entry.virtualName = virtual_name; + entry.physicalName = physical_name; + ++parent_entry.size; + // Push into the tree + parent_entry.children.push_back(entry); +#ifdef _WIN32 + } while (FindNextFile(hFind, &ffd) != 0); + FindClose(hFind); +#else + } + closedir(dirp); +#endif + // Return number of entries found. + return parent_entry; +} // Deletes the given directory and anything under it. Returns true on success. bool DeleteDirRecursively(const std::string& directory) { - INFO_LOG(COMMON, "DeleteDirRecursively: %s", directory.c_str()); - bool success = true; + INFO_LOG(COMMON, "DeleteDirRecursively: %s", directory.c_str()); + bool success = true; #ifdef _WIN32 - // Find the first file in the directory. - WIN32_FIND_DATA ffd; - HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); + // Find the first file in the directory. + WIN32_FIND_DATA ffd; + HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); - if (hFind == INVALID_HANDLE_VALUE) - { - FindClose(hFind); - return false; - } + if (hFind == INVALID_HANDLE_VALUE) + { + FindClose(hFind); + return false; + } - // Windows loop - do - { - const std::string virtualName(TStrToUTF8(ffd.cFileName)); + // Windows loop + do + { + const std::string virtualName(TStrToUTF8(ffd.cFileName)); #else - struct dirent dirent, *result = nullptr; - DIR* dirp = opendir(directory.c_str()); - if (!dirp) - return false; + struct dirent dirent, *result = nullptr; + DIR* dirp = opendir(directory.c_str()); + if (!dirp) + return false; - // non Windows loop - while (!readdir_r(dirp, &dirent, &result) && result) - { - const std::string virtualName = result->d_name; + // non Windows loop + while (!readdir_r(dirp, &dirent, &result) && result) + { + const std::string virtualName = result->d_name; #endif - // check for "." and ".." - if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || - ((virtualName[0] == '.') && (virtualName[1] == '.') && - (virtualName[2] == '\0'))) - continue; + // check for "." and ".." + if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || + ((virtualName[0] == '.') && (virtualName[1] == '.') && (virtualName[2] == '\0'))) + continue; - std::string newPath = directory + DIR_SEP_CHR + virtualName; - if (IsDirectory(newPath)) - { - if (!DeleteDirRecursively(newPath)) - { - success = false; - break; - } - } - else - { - if (!File::Delete(newPath)) - { - success = false; - break; - } - } + std::string newPath = directory + DIR_SEP_CHR + virtualName; + if (IsDirectory(newPath)) + { + if (!DeleteDirRecursively(newPath)) + { + success = false; + break; + } + } + else + { + if (!File::Delete(newPath)) + { + success = false; + break; + } + } #ifdef _WIN32 - } while (FindNextFile(hFind, &ffd) != 0); - FindClose(hFind); + } while (FindNextFile(hFind, &ffd) != 0); + FindClose(hFind); #else - } - closedir(dirp); + } + closedir(dirp); #endif - if (success) - File::DeleteDir(directory); + if (success) + File::DeleteDir(directory); - return success; + return success; } // Create directory and copy contents (does not overwrite existing files) void CopyDir(const std::string& source_path, const std::string& dest_path) { - if (source_path == dest_path) return; - if (!File::Exists(source_path)) return; - if (!File::Exists(dest_path)) File::CreateFullPath(dest_path); + if (source_path == dest_path) + return; + if (!File::Exists(source_path)) + return; + if (!File::Exists(dest_path)) + File::CreateFullPath(dest_path); #ifdef _WIN32 - WIN32_FIND_DATA ffd; - HANDLE hFind = FindFirstFile(UTF8ToTStr(source_path + "\\*").c_str(), &ffd); + WIN32_FIND_DATA ffd; + HANDLE hFind = FindFirstFile(UTF8ToTStr(source_path + "\\*").c_str(), &ffd); - if (hFind == INVALID_HANDLE_VALUE) - { - FindClose(hFind); - return; - } + if (hFind == INVALID_HANDLE_VALUE) + { + FindClose(hFind); + return; + } - do - { - const std::string virtualName(TStrToUTF8(ffd.cFileName)); + do + { + const std::string virtualName(TStrToUTF8(ffd.cFileName)); #else - struct dirent dirent, *result = nullptr; - DIR* dirp = opendir(source_path.c_str()); - if (!dirp) return; + struct dirent dirent, *result = nullptr; + DIR* dirp = opendir(source_path.c_str()); + if (!dirp) + return; - while (!readdir_r(dirp, &dirent, &result) && result) - { - const std::string virtualName(result->d_name); + while (!readdir_r(dirp, &dirent, &result) && result) + { + const std::string virtualName(result->d_name); #endif - // check for "." and ".." - if (virtualName == "." || virtualName == "..") - continue; + // check for "." and ".." + if (virtualName == "." || virtualName == "..") + continue; - std::string source = source_path + DIR_SEP + virtualName; - std::string dest = dest_path + DIR_SEP + virtualName; - if (IsDirectory(source)) - { - if (!File::Exists(dest)) File::CreateFullPath(dest + DIR_SEP); - CopyDir(source, dest); - } - else if (!File::Exists(dest)) File::Copy(source, dest); + std::string source = source_path + DIR_SEP + virtualName; + std::string dest = dest_path + DIR_SEP + virtualName; + if (IsDirectory(source)) + { + if (!File::Exists(dest)) + File::CreateFullPath(dest + DIR_SEP); + CopyDir(source, dest); + } + else if (!File::Exists(dest)) + File::Copy(source, dest); #ifdef _WIN32 - } while (FindNextFile(hFind, &ffd) != 0); - FindClose(hFind); + } while (FindNextFile(hFind, &ffd) != 0); + FindClose(hFind); #else - } - closedir(dirp); + } + closedir(dirp); #endif } // Returns the current directory std::string GetCurrentDir() { - char* dir; - // Get the current working directory (getcwd uses malloc) - if (!(dir = __getcwd(nullptr, 0))) - { - ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s", - GetLastErrorMsg().c_str()); - return nullptr; - } - std::string strDir = dir; - free(dir); - return strDir; + char* dir; + // Get the current working directory (getcwd uses malloc) + if (!(dir = __getcwd(nullptr, 0))) + { + ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s", GetLastErrorMsg().c_str()); + return nullptr; + } + std::string strDir = dir; + free(dir); + return strDir; } // Sets the current directory to the given directory bool SetCurrentDir(const std::string& directory) { - return __chdir(directory.c_str()) == 0; + return __chdir(directory.c_str()) == 0; } std::string CreateTempDir() { #ifdef _WIN32 - TCHAR temp[MAX_PATH]; - if (!GetTempPath(MAX_PATH, temp)) - return ""; + TCHAR temp[MAX_PATH]; + if (!GetTempPath(MAX_PATH, temp)) + return ""; - GUID guid; - CoCreateGuid(&guid); - TCHAR tguid[40]; - StringFromGUID2(guid, tguid, 39); - tguid[39] = 0; - std::string dir = TStrToUTF8(temp) + "/" + TStrToUTF8(tguid); - if (!CreateDir(dir)) - return ""; - dir = ReplaceAll(dir, "\\", DIR_SEP); - return dir; + GUID guid; + CoCreateGuid(&guid); + TCHAR tguid[40]; + StringFromGUID2(guid, tguid, 39); + tguid[39] = 0; + std::string dir = TStrToUTF8(temp) + "/" + TStrToUTF8(tguid); + if (!CreateDir(dir)) + return ""; + dir = ReplaceAll(dir, "\\", DIR_SEP); + return dir; #else - const char* base = getenv("TMPDIR") ?: "/tmp"; - std::string path = std::string(base) + "/DolphinWii.XXXXXX"; - if (!mkdtemp(&path[0])) - return ""; - return path; + const char* base = getenv("TMPDIR") ?: "/tmp"; + std::string path = std::string(base) + "/DolphinWii.XXXXXX"; + if (!mkdtemp(&path[0])) + return ""; + return path; #endif } std::string GetTempFilenameForAtomicWrite(const std::string& path) { - std::string abs = path; + std::string abs = path; #ifdef _WIN32 - TCHAR absbuf[MAX_PATH]; - if (_tfullpath(absbuf, UTF8ToTStr(path).c_str(), MAX_PATH) != nullptr) - abs = TStrToUTF8(absbuf); + TCHAR absbuf[MAX_PATH]; + if (_tfullpath(absbuf, UTF8ToTStr(path).c_str(), MAX_PATH) != nullptr) + abs = TStrToUTF8(absbuf); #else - char absbuf[PATH_MAX]; - if (realpath(path.c_str(), absbuf) != nullptr) - abs = absbuf; + char absbuf[PATH_MAX]; + if (realpath(path.c_str(), absbuf) != nullptr) + abs = absbuf; #endif - return abs + ".xxx"; + return abs + ".xxx"; } #if defined(__APPLE__) std::string GetBundleDirectory() { - CFURLRef BundleRef; - char AppBundlePath[MAXPATHLEN]; - // Get the main bundle for the app - BundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle()); - CFStringRef BundlePath = CFURLCopyFileSystemPath(BundleRef, kCFURLPOSIXPathStyle); - CFStringGetFileSystemRepresentation(BundlePath, AppBundlePath, sizeof(AppBundlePath)); - CFRelease(BundleRef); - CFRelease(BundlePath); + CFURLRef BundleRef; + char AppBundlePath[MAXPATHLEN]; + // Get the main bundle for the app + BundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + CFStringRef BundlePath = CFURLCopyFileSystemPath(BundleRef, kCFURLPOSIXPathStyle); + CFStringGetFileSystemRepresentation(BundlePath, AppBundlePath, sizeof(AppBundlePath)); + CFRelease(BundleRef); + CFRelease(BundlePath); - return AppBundlePath; + return AppBundlePath; } #endif std::string& GetExeDirectory() { - static std::string DolphinPath; - if (DolphinPath.empty()) - { + static std::string DolphinPath; + if (DolphinPath.empty()) + { #ifdef _WIN32 - TCHAR Dolphin_exe_Path[2048]; - TCHAR Dolphin_exe_Clean_Path[MAX_PATH]; - GetModuleFileName(nullptr, Dolphin_exe_Path, 2048); - if (_tfullpath(Dolphin_exe_Clean_Path, Dolphin_exe_Path, MAX_PATH) != nullptr) - DolphinPath = TStrToUTF8(Dolphin_exe_Clean_Path); - else - DolphinPath = TStrToUTF8(Dolphin_exe_Path); - DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\')); + TCHAR Dolphin_exe_Path[2048]; + TCHAR Dolphin_exe_Clean_Path[MAX_PATH]; + GetModuleFileName(nullptr, Dolphin_exe_Path, 2048); + if (_tfullpath(Dolphin_exe_Clean_Path, Dolphin_exe_Path, MAX_PATH) != nullptr) + DolphinPath = TStrToUTF8(Dolphin_exe_Clean_Path); + else + DolphinPath = TStrToUTF8(Dolphin_exe_Path); + DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\')); #else - char Dolphin_exe_Path[PATH_MAX]; - ssize_t len = ::readlink("/proc/self/exe", Dolphin_exe_Path, sizeof(Dolphin_exe_Path)); - if (len == -1 || len == sizeof(Dolphin_exe_Path)) - { - len = 0; - } - Dolphin_exe_Path[len] = '\0'; - DolphinPath = Dolphin_exe_Path; - DolphinPath = DolphinPath.substr(0, DolphinPath.rfind('/')); + char Dolphin_exe_Path[PATH_MAX]; + ssize_t len = ::readlink("/proc/self/exe", Dolphin_exe_Path, sizeof(Dolphin_exe_Path)); + if (len == -1 || len == sizeof(Dolphin_exe_Path)) + { + len = 0; + } + Dolphin_exe_Path[len] = '\0'; + DolphinPath = Dolphin_exe_Path; + DolphinPath = DolphinPath.substr(0, DolphinPath.rfind('/')); #endif - } - return DolphinPath; + } + return DolphinPath; } std::string GetSysDirectory() { - std::string sysDir; + std::string sysDir; -#if defined (__APPLE__) - sysDir = GetBundleDirectory() + DIR_SEP + SYSDATA_DIR; -#elif defined (_WIN32) || defined (LINUX_LOCAL_DEV) - sysDir = GetExeDirectory() + DIR_SEP + SYSDATA_DIR; +#if defined(__APPLE__) + sysDir = GetBundleDirectory() + DIR_SEP + SYSDATA_DIR; +#elif defined(_WIN32) || defined(LINUX_LOCAL_DEV) + sysDir = GetExeDirectory() + DIR_SEP + SYSDATA_DIR; #else - sysDir = SYSDATA_DIR; + sysDir = SYSDATA_DIR; #endif - sysDir += DIR_SEP; + sysDir += DIR_SEP; - INFO_LOG(COMMON, "GetSysDirectory: Setting to %s:", sysDir.c_str()); - return sysDir; + INFO_LOG(COMMON, "GetSysDirectory: Setting to %s:", sysDir.c_str()); + return sysDir; } static std::string s_user_paths[NUM_PATH_INDICES]; static void RebuildUserDirectories(unsigned int dir_index) { - switch (dir_index) - { - case D_USER_IDX: - s_user_paths[D_GCUSER_IDX] = s_user_paths[D_USER_IDX] + GC_USER_DIR DIR_SEP; - s_user_paths[D_WIIROOT_IDX] = s_user_paths[D_USER_IDX] + WII_USER_DIR; - s_user_paths[D_CONFIG_IDX] = s_user_paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; - s_user_paths[D_GAMESETTINGS_IDX] = s_user_paths[D_USER_IDX] + GAMESETTINGS_DIR DIR_SEP; - s_user_paths[D_MAPS_IDX] = s_user_paths[D_USER_IDX] + MAPS_DIR DIR_SEP; - s_user_paths[D_CACHE_IDX] = s_user_paths[D_USER_IDX] + CACHE_DIR DIR_SEP; - s_user_paths[D_SHADERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + SHADERCACHE_DIR DIR_SEP; - s_user_paths[D_SHADERS_IDX] = s_user_paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; - s_user_paths[D_STATESAVES_IDX] = s_user_paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; - s_user_paths[D_SCREENSHOTS_IDX] = s_user_paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; - s_user_paths[D_LOAD_IDX] = s_user_paths[D_USER_IDX] + LOAD_DIR DIR_SEP; - s_user_paths[D_HIRESTEXTURES_IDX] = s_user_paths[D_LOAD_IDX] + HIRES_TEXTURES_DIR DIR_SEP; - s_user_paths[D_DUMP_IDX] = s_user_paths[D_USER_IDX] + DUMP_DIR DIR_SEP; - s_user_paths[D_DUMPFRAMES_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; - s_user_paths[D_DUMPAUDIO_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; - s_user_paths[D_DUMPTEXTURES_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; - s_user_paths[D_DUMPDSP_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_DSP_DIR DIR_SEP; - s_user_paths[D_LOGS_IDX] = s_user_paths[D_USER_IDX] + LOGS_DIR DIR_SEP; - s_user_paths[D_MAILLOGS_IDX] = s_user_paths[D_LOGS_IDX] + MAIL_LOGS_DIR DIR_SEP; - s_user_paths[D_THEMES_IDX] = s_user_paths[D_USER_IDX] + THEMES_DIR DIR_SEP; - s_user_paths[D_PIPES_IDX] = s_user_paths[D_USER_IDX] + PIPES_DIR DIR_SEP; - s_user_paths[F_DOLPHINCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + DOLPHIN_CONFIG; - s_user_paths[F_DEBUGGERCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; - s_user_paths[F_LOGGERCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + LOGGER_CONFIG; - s_user_paths[F_MAINLOG_IDX] = s_user_paths[D_LOGS_IDX] + MAIN_LOG; - s_user_paths[F_RAMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + RAM_DUMP; - s_user_paths[F_ARAMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + ARAM_DUMP; - s_user_paths[F_FAKEVMEMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + FAKEVMEM_DUMP; - s_user_paths[F_GCSRAM_IDX] = s_user_paths[D_GCUSER_IDX] + GC_SRAM; + switch (dir_index) + { + case D_USER_IDX: + s_user_paths[D_GCUSER_IDX] = s_user_paths[D_USER_IDX] + GC_USER_DIR DIR_SEP; + s_user_paths[D_WIIROOT_IDX] = s_user_paths[D_USER_IDX] + WII_USER_DIR; + s_user_paths[D_CONFIG_IDX] = s_user_paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; + s_user_paths[D_GAMESETTINGS_IDX] = s_user_paths[D_USER_IDX] + GAMESETTINGS_DIR DIR_SEP; + s_user_paths[D_MAPS_IDX] = s_user_paths[D_USER_IDX] + MAPS_DIR DIR_SEP; + s_user_paths[D_CACHE_IDX] = s_user_paths[D_USER_IDX] + CACHE_DIR DIR_SEP; + s_user_paths[D_SHADERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + SHADERCACHE_DIR DIR_SEP; + s_user_paths[D_SHADERS_IDX] = s_user_paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; + s_user_paths[D_STATESAVES_IDX] = s_user_paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; + s_user_paths[D_SCREENSHOTS_IDX] = s_user_paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; + s_user_paths[D_LOAD_IDX] = s_user_paths[D_USER_IDX] + LOAD_DIR DIR_SEP; + s_user_paths[D_HIRESTEXTURES_IDX] = s_user_paths[D_LOAD_IDX] + HIRES_TEXTURES_DIR DIR_SEP; + s_user_paths[D_DUMP_IDX] = s_user_paths[D_USER_IDX] + DUMP_DIR DIR_SEP; + s_user_paths[D_DUMPFRAMES_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; + s_user_paths[D_DUMPAUDIO_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; + s_user_paths[D_DUMPTEXTURES_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; + s_user_paths[D_DUMPDSP_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_DSP_DIR DIR_SEP; + s_user_paths[D_LOGS_IDX] = s_user_paths[D_USER_IDX] + LOGS_DIR DIR_SEP; + s_user_paths[D_MAILLOGS_IDX] = s_user_paths[D_LOGS_IDX] + MAIL_LOGS_DIR DIR_SEP; + s_user_paths[D_THEMES_IDX] = s_user_paths[D_USER_IDX] + THEMES_DIR DIR_SEP; + s_user_paths[D_PIPES_IDX] = s_user_paths[D_USER_IDX] + PIPES_DIR DIR_SEP; + s_user_paths[F_DOLPHINCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + DOLPHIN_CONFIG; + s_user_paths[F_DEBUGGERCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; + s_user_paths[F_LOGGERCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + LOGGER_CONFIG; + s_user_paths[F_MAINLOG_IDX] = s_user_paths[D_LOGS_IDX] + MAIN_LOG; + s_user_paths[F_RAMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + RAM_DUMP; + s_user_paths[F_ARAMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + ARAM_DUMP; + s_user_paths[F_FAKEVMEMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + FAKEVMEM_DUMP; + s_user_paths[F_GCSRAM_IDX] = s_user_paths[D_GCUSER_IDX] + GC_SRAM; - s_user_paths[D_MEMORYWATCHER_IDX] = s_user_paths[D_USER_IDX] + MEMORYWATCHER_DIR DIR_SEP; - s_user_paths[F_MEMORYWATCHERLOCATIONS_IDX] = s_user_paths[D_MEMORYWATCHER_IDX] + MEMORYWATCHER_LOCATIONS; - s_user_paths[F_MEMORYWATCHERSOCKET_IDX] = s_user_paths[D_MEMORYWATCHER_IDX] + MEMORYWATCHER_SOCKET; + s_user_paths[D_MEMORYWATCHER_IDX] = s_user_paths[D_USER_IDX] + MEMORYWATCHER_DIR DIR_SEP; + s_user_paths[F_MEMORYWATCHERLOCATIONS_IDX] = + s_user_paths[D_MEMORYWATCHER_IDX] + MEMORYWATCHER_LOCATIONS; + s_user_paths[F_MEMORYWATCHERSOCKET_IDX] = + s_user_paths[D_MEMORYWATCHER_IDX] + MEMORYWATCHER_SOCKET; - // The shader cache has moved to the cache directory, so remove the old one. - // TODO: remove that someday. - File::DeleteDirRecursively(s_user_paths[D_USER_IDX] + SHADERCACHE_LEGACY_DIR DIR_SEP); - break; + // The shader cache has moved to the cache directory, so remove the old one. + // TODO: remove that someday. + File::DeleteDirRecursively(s_user_paths[D_USER_IDX] + SHADERCACHE_LEGACY_DIR DIR_SEP); + break; - case D_CONFIG_IDX: - s_user_paths[F_DOLPHINCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + DOLPHIN_CONFIG; - s_user_paths[F_DEBUGGERCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; - s_user_paths[F_LOGGERCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + LOGGER_CONFIG; - break; + case D_CONFIG_IDX: + s_user_paths[F_DOLPHINCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + DOLPHIN_CONFIG; + s_user_paths[F_DEBUGGERCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; + s_user_paths[F_LOGGERCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + LOGGER_CONFIG; + break; - case D_CACHE_IDX: - s_user_paths[D_SHADERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + SHADERCACHE_DIR DIR_SEP; - break; + case D_CACHE_IDX: + s_user_paths[D_SHADERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + SHADERCACHE_DIR DIR_SEP; + break; - case D_GCUSER_IDX: - s_user_paths[F_GCSRAM_IDX] = s_user_paths[D_GCUSER_IDX] + GC_SRAM; - break; + case D_GCUSER_IDX: + s_user_paths[F_GCSRAM_IDX] = s_user_paths[D_GCUSER_IDX] + GC_SRAM; + break; - case D_DUMP_IDX: - s_user_paths[D_DUMPFRAMES_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; - s_user_paths[D_DUMPAUDIO_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; - s_user_paths[D_DUMPTEXTURES_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; - s_user_paths[D_DUMPDSP_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_DSP_DIR DIR_SEP; - s_user_paths[F_RAMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + RAM_DUMP; - s_user_paths[F_ARAMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + ARAM_DUMP; - s_user_paths[F_FAKEVMEMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + FAKEVMEM_DUMP; - break; + case D_DUMP_IDX: + s_user_paths[D_DUMPFRAMES_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; + s_user_paths[D_DUMPAUDIO_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; + s_user_paths[D_DUMPTEXTURES_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; + s_user_paths[D_DUMPDSP_IDX] = s_user_paths[D_DUMP_IDX] + DUMP_DSP_DIR DIR_SEP; + s_user_paths[F_RAMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + RAM_DUMP; + s_user_paths[F_ARAMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + ARAM_DUMP; + s_user_paths[F_FAKEVMEMDUMP_IDX] = s_user_paths[D_DUMP_IDX] + FAKEVMEM_DUMP; + break; - case D_LOGS_IDX: - s_user_paths[D_MAILLOGS_IDX] = s_user_paths[D_LOGS_IDX] + MAIL_LOGS_DIR DIR_SEP; - s_user_paths[F_MAINLOG_IDX] = s_user_paths[D_LOGS_IDX] + MAIN_LOG; - break; + case D_LOGS_IDX: + s_user_paths[D_MAILLOGS_IDX] = s_user_paths[D_LOGS_IDX] + MAIL_LOGS_DIR DIR_SEP; + s_user_paths[F_MAINLOG_IDX] = s_user_paths[D_LOGS_IDX] + MAIN_LOG; + break; - case D_LOAD_IDX: - s_user_paths[D_HIRESTEXTURES_IDX] = s_user_paths[D_LOAD_IDX] + HIRES_TEXTURES_DIR DIR_SEP; - break; - } + case D_LOAD_IDX: + s_user_paths[D_HIRESTEXTURES_IDX] = s_user_paths[D_LOAD_IDX] + HIRES_TEXTURES_DIR DIR_SEP; + break; + } } // Gets a set user directory path // Don't call prior to setting the base user directory const std::string& GetUserPath(unsigned int dir_index) { - return s_user_paths[dir_index]; + return s_user_paths[dir_index]; } // Sets a user directory path // Rebuilds internal directory structure to compensate for the new directory void SetUserPath(unsigned int dir_index, const std::string& path) { - if (path.empty()) - return; + if (path.empty()) + return; - s_user_paths[dir_index] = path; - RebuildUserDirectories(dir_index); + s_user_paths[dir_index] = path; + RebuildUserDirectories(dir_index); } std::string GetThemeDir(const std::string& theme_name) { - std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/"; + std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/"; - // If theme does not exist in user's dir load from shared directory - if (!File::Exists(dir)) - dir = GetSysDirectory() + THEMES_DIR "/" + theme_name + "/"; + // If theme does not exist in user's dir load from shared directory + if (!File::Exists(dir)) + dir = GetSysDirectory() + THEMES_DIR "/" + theme_name + "/"; - return dir; + return dir; } bool WriteStringToFile(const std::string& str, const std::string& filename) { - return File::IOFile(filename, "wb").WriteBytes(str.data(), str.size()); + return File::IOFile(filename, "wb").WriteBytes(str.data(), str.size()); } bool ReadFileToString(const std::string& filename, std::string& str) { - File::IOFile file(filename, "rb"); - auto const f = file.GetHandle(); + File::IOFile file(filename, "rb"); + auto const f = file.GetHandle(); - if (!f) - return false; + if (!f) + return false; - size_t read_size; - str.resize(GetSize(f)); - bool retval = file.ReadArray(&str[0], str.size(), &read_size); + size_t read_size; + str.resize(GetSize(f)); + bool retval = file.ReadArray(&str[0], str.size(), &read_size); - return retval; + return retval; } -IOFile::IOFile() - : m_file(nullptr), m_good(true) -{} - -IOFile::IOFile(std::FILE* file) - : m_file(file), m_good(true) -{} - -IOFile::IOFile(const std::string& filename, const char openmode[]) - : m_file(nullptr), m_good(true) +IOFile::IOFile() : m_file(nullptr), m_good(true) { - Open(filename, openmode); +} + +IOFile::IOFile(std::FILE* file) : m_file(file), m_good(true) +{ +} + +IOFile::IOFile(const std::string& filename, const char openmode[]) : m_file(nullptr), m_good(true) +{ + Open(filename, openmode); } IOFile::~IOFile() { - Close(); + Close(); } -IOFile::IOFile(IOFile&& other) - : m_file(nullptr), m_good(true) +IOFile::IOFile(IOFile&& other) : m_file(nullptr), m_good(true) { - Swap(other); + Swap(other); } IOFile& IOFile::operator=(IOFile&& other) { - Swap(other); - return *this; + Swap(other); + return *this; } void IOFile::Swap(IOFile& other) { - std::swap(m_file, other.m_file); - std::swap(m_good, other.m_good); + std::swap(m_file, other.m_file); + std::swap(m_good, other.m_good); } bool IOFile::Open(const std::string& filename, const char openmode[]) { - Close(); + Close(); #ifdef _WIN32 - _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str()); + _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str()); #else - m_file = fopen(filename.c_str(), openmode); + m_file = fopen(filename.c_str(), openmode); #endif - m_good = IsOpen(); - return m_good; + m_good = IsOpen(); + return m_good; } bool IOFile::Close() { - if (!IsOpen() || 0 != std::fclose(m_file)) - m_good = false; + if (!IsOpen() || 0 != std::fclose(m_file)) + m_good = false; - m_file = nullptr; - return m_good; + m_file = nullptr; + return m_good; } std::FILE* IOFile::ReleaseHandle() { - std::FILE* const ret = m_file; - m_file = nullptr; - return ret; + std::FILE* const ret = m_file; + m_file = nullptr; + return ret; } void IOFile::SetHandle(std::FILE* file) { - Close(); - Clear(); - m_file = file; + Close(); + Clear(); + m_file = file; } u64 IOFile::GetSize() { - if (IsOpen()) - return File::GetSize(m_file); - else - return 0; + if (IsOpen()) + return File::GetSize(m_file); + else + return 0; } bool IOFile::Seek(s64 off, int origin) { - if (!IsOpen() || 0 != fseeko(m_file, off, origin)) - m_good = false; + if (!IsOpen() || 0 != fseeko(m_file, off, origin)) + m_good = false; - return m_good; + return m_good; } u64 IOFile::Tell() const { - if (IsOpen()) - return ftello(m_file); - else - return -1; + if (IsOpen()) + return ftello(m_file); + else + return -1; } bool IOFile::Flush() { - if (!IsOpen() || 0 != std::fflush(m_file)) - m_good = false; + if (!IsOpen() || 0 != std::fflush(m_file)) + m_good = false; - return m_good; + return m_good; } bool IOFile::Resize(u64 size) { - if (!IsOpen() || 0 != + if (!IsOpen() || + 0 != #ifdef _WIN32 - // ector: _chsize sucks, not 64-bit safe - // F|RES: changed to _chsize_s. i think it is 64-bit safe - _chsize_s(_fileno(m_file), size) + // ector: _chsize sucks, not 64-bit safe + // F|RES: changed to _chsize_s. i think it is 64-bit safe + _chsize_s(_fileno(m_file), size) #else - // TODO: handle 64bit and growing - ftruncate(fileno(m_file), size) + // TODO: handle 64bit and growing + ftruncate(fileno(m_file), size) #endif - ) - m_good = false; + ) + m_good = false; - return m_good; + return m_good; } -} // namespace +} // namespace diff --git a/Source/Core/Common/FileUtil.h b/Source/Core/Common/FileUtil.h index fcc3c20269..b1168561c4 100644 --- a/Source/Core/Common/FileUtil.h +++ b/Source/Core/Common/FileUtil.h @@ -18,55 +18,56 @@ #endif // User directory indices for GetUserPath -enum { - D_USER_IDX, - D_GCUSER_IDX, - D_WIIROOT_IDX, // always points to User/Wii or global user-configured directory - D_SESSION_WIIROOT_IDX, // may point to minimal temporary directory for determinism - D_CONFIG_IDX, // global settings - D_GAMESETTINGS_IDX, // user-specified settings which override both the global and the default settings (per game) - D_MAPS_IDX, - D_CACHE_IDX, - D_SHADERCACHE_IDX, - D_SHADERS_IDX, - D_STATESAVES_IDX, - D_SCREENSHOTS_IDX, - D_HIRESTEXTURES_IDX, - D_DUMP_IDX, - D_DUMPFRAMES_IDX, - D_DUMPAUDIO_IDX, - D_DUMPTEXTURES_IDX, - D_DUMPDSP_IDX, - D_LOAD_IDX, - D_LOGS_IDX, - D_MAILLOGS_IDX, - D_THEMES_IDX, - D_PIPES_IDX, - D_MEMORYWATCHER_IDX, - F_DOLPHINCONFIG_IDX, - F_DEBUGGERCONFIG_IDX, - F_LOGGERCONFIG_IDX, - F_MAINLOG_IDX, - F_RAMDUMP_IDX, - F_ARAMDUMP_IDX, - F_FAKEVMEMDUMP_IDX, - F_GCSRAM_IDX, - F_MEMORYWATCHERLOCATIONS_IDX, - F_MEMORYWATCHERSOCKET_IDX, - NUM_PATH_INDICES +enum +{ + D_USER_IDX, + D_GCUSER_IDX, + D_WIIROOT_IDX, // always points to User/Wii or global user-configured directory + D_SESSION_WIIROOT_IDX, // may point to minimal temporary directory for determinism + D_CONFIG_IDX, // global settings + D_GAMESETTINGS_IDX, // user-specified settings which override both the global and the default + // settings (per game) + D_MAPS_IDX, + D_CACHE_IDX, + D_SHADERCACHE_IDX, + D_SHADERS_IDX, + D_STATESAVES_IDX, + D_SCREENSHOTS_IDX, + D_HIRESTEXTURES_IDX, + D_DUMP_IDX, + D_DUMPFRAMES_IDX, + D_DUMPAUDIO_IDX, + D_DUMPTEXTURES_IDX, + D_DUMPDSP_IDX, + D_LOAD_IDX, + D_LOGS_IDX, + D_MAILLOGS_IDX, + D_THEMES_IDX, + D_PIPES_IDX, + D_MEMORYWATCHER_IDX, + F_DOLPHINCONFIG_IDX, + F_DEBUGGERCONFIG_IDX, + F_LOGGERCONFIG_IDX, + F_MAINLOG_IDX, + F_RAMDUMP_IDX, + F_ARAMDUMP_IDX, + F_FAKEVMEMDUMP_IDX, + F_GCSRAM_IDX, + F_MEMORYWATCHERLOCATIONS_IDX, + F_MEMORYWATCHERSOCKET_IDX, + NUM_PATH_INDICES }; namespace File { - // FileSystem tree node/ struct FSTEntry { - bool isDirectory; - u64 size; // File length, or for directories, recursive count of children - std::string physicalName; // Name on disk - std::string virtualName; // Name in FST names table - std::vector children; + bool isDirectory; + u64 size; // File length, or for directories, recursive count of children + std::string physicalName; // Name on disk + std::string virtualName; // Name in FST names table + std::vector children; }; // Returns true if file filename exists @@ -159,78 +160,80 @@ bool ReadFileToString(const std::string& filename, std::string& str); class IOFile : public NonCopyable { public: - IOFile(); - IOFile(std::FILE* file); - IOFile(const std::string& filename, const char openmode[]); + IOFile(); + IOFile(std::FILE* file); + IOFile(const std::string& filename, const char openmode[]); - ~IOFile(); + ~IOFile(); - IOFile(IOFile&& other); - IOFile& operator=(IOFile&& other); + IOFile(IOFile&& other); + IOFile& operator=(IOFile&& other); - void Swap(IOFile& other); + void Swap(IOFile& other); - bool Open(const std::string& filename, const char openmode[]); - bool Close(); + bool Open(const std::string& filename, const char openmode[]); + bool Close(); - template - bool ReadArray(T* data, size_t length, size_t* pReadBytes = nullptr) - { - size_t read_bytes = 0; - if (!IsOpen() || length != (read_bytes = std::fread(data, sizeof(T), length, m_file))) - m_good = false; + template + bool ReadArray(T* data, size_t length, size_t* pReadBytes = nullptr) + { + size_t read_bytes = 0; + if (!IsOpen() || length != (read_bytes = std::fread(data, sizeof(T), length, m_file))) + m_good = false; - if (pReadBytes) - *pReadBytes = read_bytes; + if (pReadBytes) + *pReadBytes = read_bytes; - return m_good; - } + return m_good; + } - template - bool WriteArray(const T* data, size_t length) - { - if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file)) - m_good = false; + template + bool WriteArray(const T* data, size_t length) + { + if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file)) + m_good = false; - return m_good; - } + return m_good; + } - bool ReadBytes(void* data, size_t length) - { - return ReadArray(reinterpret_cast(data), length); - } + bool ReadBytes(void* data, size_t length) + { + return ReadArray(reinterpret_cast(data), length); + } - bool WriteBytes(const void* data, size_t length) - { - return WriteArray(reinterpret_cast(data), length); - } + bool WriteBytes(const void* data, size_t length) + { + return WriteArray(reinterpret_cast(data), length); + } - bool IsOpen() const { return nullptr != m_file; } + bool IsOpen() const { return nullptr != m_file; } + // m_good is set to false when a read, write or other function fails + bool IsGood() const { return m_good; } + operator void*() { return m_good ? m_file : nullptr; } + std::FILE* ReleaseHandle(); - // m_good is set to false when a read, write or other function fails - bool IsGood() const { return m_good; } - operator void*() { return m_good ? m_file : nullptr; } + std::FILE* GetHandle() { return m_file; } + void SetHandle(std::FILE* file); - std::FILE* ReleaseHandle(); + bool Seek(s64 off, int origin); + u64 Tell() const; + u64 GetSize(); + bool Resize(u64 size); + bool Flush(); - std::FILE* GetHandle() { return m_file; } + // clear error state + void Clear() + { + m_good = true; + std::clearerr(m_file); + } - void SetHandle(std::FILE* file); + std::FILE* m_file; + bool m_good; - bool Seek(s64 off, int origin); - u64 Tell() const; - u64 GetSize(); - bool Resize(u64 size); - bool Flush(); - - // clear error state - void Clear() { m_good = true; std::clearerr(m_file); } - - std::FILE* m_file; - bool m_good; private: - IOFile(IOFile&); - IOFile& operator=(IOFile& other); + IOFile(IOFile&); + IOFile& operator=(IOFile& other); }; } // namespace @@ -240,8 +243,8 @@ template void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) { #ifdef _WIN32 - fstream.open(UTF8ToTStr(filename).c_str(), openmode); + fstream.open(UTF8ToTStr(filename).c_str(), openmode); #else - fstream.open(filename.c_str(), openmode); + fstream.open(filename.c_str(), openmode); #endif } diff --git a/Source/Core/Common/FixedSizeQueue.h b/Source/Core/Common/FixedSizeQueue.h index 6543c1698a..4afd38dbe7 100644 --- a/Source/Core/Common/FixedSizeQueue.h +++ b/Source/Core/Common/FixedSizeQueue.h @@ -16,62 +16,53 @@ template class FixedSizeQueue { - T* storage; - int head; - int tail; - int count; // sacrifice 4 bytes for a simpler implementation. may optimize away in the future. - - // Make copy constructor private for now. - FixedSizeQueue(FixedSizeQueue& other) {} + T* storage; + int head; + int tail; + int count; // sacrifice 4 bytes for a simpler implementation. may optimize away in the future. + // Make copy constructor private for now. + FixedSizeQueue(FixedSizeQueue& other) {} public: - FixedSizeQueue() - { - storage = new T[N]; - clear(); - } + FixedSizeQueue() + { + storage = new T[N]; + clear(); + } - ~FixedSizeQueue() - { - delete[] storage; - } + ~FixedSizeQueue() { delete[] storage; } + void clear() + { + head = 0; + tail = 0; + count = 0; + } - void clear() - { - head = 0; - tail = 0; - count = 0; - } + void push(T t) + { + storage[tail] = t; + tail++; + if (tail == N) + tail = 0; + count++; + } - void push(T t) - { - storage[tail] = t; - tail++; - if (tail == N) - tail = 0; - count++; - } + void pop() + { + head++; + if (head == N) + head = 0; + count--; + } - void pop() - { - head++; - if (head == N) - head = 0; - count--; - } + T pop_front() + { + const T& temp = storage[head]; + pop(); + return temp; + } - T pop_front() - { - const T& temp = storage[head]; - pop(); - return temp; - } - - T& front() { return storage[head]; } - const T& front() const { return storage[head]; } - - size_t size() const - { - return count; - } + T& front() { return storage[head]; } + const T& front() const { return storage[head]; } + size_t size() const { return count; } }; diff --git a/Source/Core/Common/Flag.h b/Source/Core/Common/Flag.h index 846f953280..31573aaced 100644 --- a/Source/Core/Common/Flag.h +++ b/Source/Core/Common/Flag.h @@ -19,44 +19,27 @@ #include -namespace Common { - +namespace Common +{ class Flag final { public: - // Declared as explicit since we do not want "= true" to work on a flag - // object - it should be made explicit that a flag is *not* a normal - // variable. - explicit Flag(bool initial_value = false) : m_val(initial_value) {} - - void Set(bool val = true) - { - m_val.store(val); - } - - void Clear() - { - Set(false); - } - - bool IsSet() const - { - return m_val.load(); - } - - bool TestAndSet(bool val = true) - { - bool expected = !val; - return m_val.compare_exchange_strong(expected, val); - } - - bool TestAndClear() - { - return TestAndSet(false); - } + // Declared as explicit since we do not want "= true" to work on a flag + // object - it should be made explicit that a flag is *not* a normal + // variable. + explicit Flag(bool initial_value = false) : m_val(initial_value) {} + void Set(bool val = true) { m_val.store(val); } + void Clear() { Set(false); } + bool IsSet() const { return m_val.load(); } + bool TestAndSet(bool val = true) + { + bool expected = !val; + return m_val.compare_exchange_strong(expected, val); + } + bool TestAndClear() { return TestAndSet(false); } private: - std::atomic_bool m_val; + std::atomic_bool m_val; }; } // namespace Common diff --git a/Source/Core/Common/GL/GLExtensions/AMD_pinned_memory.h b/Source/Core/Common/GL/GLExtensions/AMD_pinned_memory.h index dd0034ec79..ae015dc058 100644 --- a/Source/Core/Common/GL/GLExtensions/AMD_pinned_memory.h +++ b/Source/Core/Common/GL/GLExtensions/AMD_pinned_memory.h @@ -24,4 +24,3 @@ #include "Common/GL/GLExtensions/gl_common.h" #define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160 - diff --git a/Source/Core/Common/GL/GLExtensions/ARB_ES2_compatibility.h b/Source/Core/Common/GL/GLExtensions/ARB_ES2_compatibility.h index 42f00d7495..cd89ff7adb 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_ES2_compatibility.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_ES2_compatibility.h @@ -23,11 +23,14 @@ #include "Common/GL/GLExtensions/gl_common.h" -typedef void (APIENTRYP PFNDOLRELEASESHADERCOMPILERPROC) (void); -typedef void (APIENTRYP PFNDOLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); -typedef void (APIENTRYP PFNDOLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); -typedef void (APIENTRYP PFNDOLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); -typedef void (APIENTRYP PFNDOLCLEARDEPTHFPROC) (GLfloat d); +typedef void(APIENTRYP PFNDOLRELEASESHADERCOMPILERPROC)(void); +typedef void(APIENTRYP PFNDOLSHADERBINARYPROC)(GLsizei count, const GLuint* shaders, + GLenum binaryformat, const void* binary, + GLsizei length); +typedef void(APIENTRYP PFNDOLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, + GLint* range, GLint* precision); +typedef void(APIENTRYP PFNDOLDEPTHRANGEFPROC)(GLfloat n, GLfloat f); +typedef void(APIENTRYP PFNDOLCLEARDEPTHFPROC)(GLfloat d); extern PFNDOLCLEARDEPTHFPROC dolClearDepthf; extern PFNDOLDEPTHRANGEFPROC dolDepthRangef; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_blend_func_extended.h b/Source/Core/Common/GL/GLExtensions/ARB_blend_func_extended.h index b050f5f958..f945b083fd 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_blend_func_extended.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_blend_func_extended.h @@ -28,8 +28,9 @@ #define GL_ONE_MINUS_SRC1_ALPHA 0x88FB #define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC -typedef void (APIENTRYP PFNDOLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); -typedef GLint (APIENTRYP PFNDOLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name); +typedef void(APIENTRYP PFNDOLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, + GLuint index, const GLchar* name); +typedef GLint(APIENTRYP PFNDOLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar* name); extern PFNDOLBINDFRAGDATALOCATIONINDEXEDPROC dolBindFragDataLocationIndexed; extern PFNDOLGETFRAGDATAINDEXPROC dolGetFragDataIndex; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_buffer_storage.h b/Source/Core/Common/GL/GLExtensions/ARB_buffer_storage.h index 386c1bcbc3..776da7bf10 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_buffer_storage.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_buffer_storage.h @@ -33,8 +33,10 @@ #define GL_BUFFER_IMMUTABLE_STORAGE 0x821F #define GL_BUFFER_STORAGE_FLAGS 0x8220 -typedef void (APIENTRYP PFNDOLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); -typedef void (APIENTRYP PFNDOLNAMEDBUFFERSTORAGEEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); +typedef void(APIENTRYP PFNDOLBUFFERSTORAGEPROC)(GLenum target, GLsizeiptr size, const void* data, + GLbitfield flags); +typedef void(APIENTRYP PFNDOLNAMEDBUFFERSTORAGEEXTPROC)(GLuint buffer, GLsizeiptr size, + const void* data, GLbitfield flags); extern PFNDOLBUFFERSTORAGEPROC dolBufferStorage; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_clip_control.h b/Source/Core/Common/GL/GLExtensions/ARB_clip_control.h index df0964f391..1f14c34669 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_clip_control.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_clip_control.h @@ -23,12 +23,12 @@ #include "Common/GL/GLExtensions/gl_common.h" -#define GL_NEGATIVE_ONE_TO_ONE 0x935E -#define GL_ZERO_TO_ONE 0x935F -#define GL_CLIP_ORIGIN 0x935C -#define GL_CLIP_DEPTH_MODE 0x935D +#define GL_NEGATIVE_ONE_TO_ONE 0x935E +#define GL_ZERO_TO_ONE 0x935F +#define GL_CLIP_ORIGIN 0x935C +#define GL_CLIP_DEPTH_MODE 0x935D -typedef void (APIENTRYP PFNDOLCLIPCONTROLPROC) (GLenum origin, GLenum depth); +typedef void(APIENTRYP PFNDOLCLIPCONTROLPROC)(GLenum origin, GLenum depth); extern PFNDOLCLIPCONTROLPROC dolClipControl; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_copy_image.h b/Source/Core/Common/GL/GLExtensions/ARB_copy_image.h index c75957ecd8..b7f7bbcb34 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_copy_image.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_copy_image.h @@ -23,7 +23,12 @@ #include "Common/GL/GLExtensions/gl_common.h" -typedef void (APIENTRYP PFNDOLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +typedef void(APIENTRYP PFNDOLCOPYIMAGESUBDATAPROC)(GLuint srcName, GLenum srcTarget, GLint srcLevel, + GLint srcX, GLint srcY, GLint srcZ, + GLuint dstName, GLenum dstTarget, GLint dstLevel, + GLint dstX, GLint dstY, GLint dstZ, + GLsizei srcWidth, GLsizei srcHeight, + GLsizei srcDepth); extern PFNDOLCOPYIMAGESUBDATAPROC dolCopyImageSubData; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_debug_output.h b/Source/Core/Common/GL/GLExtensions/ARB_debug_output.h index a0a11c1e65..2099708e74 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_debug_output.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_debug_output.h @@ -23,34 +23,44 @@ #include "Common/GL/GLExtensions/gl_common.h" -typedef void (APIENTRYP GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); -#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 +typedef void(APIENTRYP GLDEBUGPROCARB)(GLenum source, GLenum type, GLuint id, GLenum severity, + GLsizei length, const GLchar* message, + const void* userParam); +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 -#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 -#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 -#define GL_DEBUG_SOURCE_API_ARB 0x8246 +#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 +#define GL_DEBUG_SOURCE_API_ARB 0x8246 #define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 #define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 -#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 -#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A -#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B -#define GL_DEBUG_TYPE_ERROR_ARB 0x824C +#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A +#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B +#define GL_DEBUG_TYPE_ERROR_ARB 0x824C #define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D #define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E -#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F -#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 -#define GL_DEBUG_TYPE_OTHER_ARB 0x8251 -#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 -#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 -#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 -#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 -#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 -#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 +#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 +#define GL_DEBUG_TYPE_OTHER_ARB 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 +#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 -typedef void (APIENTRYP PFNDOLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -typedef void (APIENTRYP PFNDOLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -typedef void (APIENTRYP PFNDOLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const void *userParam); -typedef GLuint (APIENTRYP PFNDOLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +typedef void(APIENTRYP PFNDOLDEBUGMESSAGECONTROLARBPROC)(GLenum source, GLenum type, + GLenum severity, GLsizei count, + const GLuint* ids, GLboolean enabled); +typedef void(APIENTRYP PFNDOLDEBUGMESSAGEINSERTARBPROC)(GLenum source, GLenum type, GLuint id, + GLenum severity, GLsizei length, + const GLchar* buf); +typedef void(APIENTRYP PFNDOLDEBUGMESSAGECALLBACKARBPROC)(GLDEBUGPROCARB callback, + const void* userParam); +typedef GLuint(APIENTRYP PFNDOLGETDEBUGMESSAGELOGARBPROC)(GLuint count, GLsizei bufSize, + GLenum* sources, GLenum* types, + GLuint* ids, GLenum* severities, + GLsizei* lengths, GLchar* messageLog); extern PFNDOLDEBUGMESSAGECALLBACKARBPROC dolDebugMessageCallbackARB; extern PFNDOLDEBUGMESSAGECONTROLARBPROC dolDebugMessageControlARB; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_draw_elements_base_vertex.h b/Source/Core/Common/GL/GLExtensions/ARB_draw_elements_base_vertex.h index d4154e4940..f01e0152c0 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_draw_elements_base_vertex.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_draw_elements_base_vertex.h @@ -23,10 +23,21 @@ #include "Common/GL/GLExtensions/gl_common.h" -typedef void (APIENTRYP PFNDOLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); -typedef void (APIENTRYP PFNDOLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); -typedef void (APIENTRYP PFNDOLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); -typedef void (APIENTRYP PFNDOLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); +typedef void(APIENTRYP PFNDOLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, + const void* indices, GLint basevertex); +typedef void(APIENTRYP PFNDOLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, + GLsizei count, GLenum type, + const void* indices, + GLint basevertex); +typedef void(APIENTRYP PFNDOLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, + GLenum type, const void* indices, + GLsizei instancecount, + GLint basevertex); +typedef void(APIENTRYP PFNDOLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei* count, + GLenum type, + const void* const* indices, + GLsizei drawcount, + const GLint* basevertex); extern PFNDOLDRAWELEMENTSBASEVERTEXPROC dolDrawElementsBaseVertex; extern PFNDOLDRAWELEMENTSINSTANCEDBASEVERTEXPROC dolDrawElementsInstancedBaseVertex; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_framebuffer_object.h b/Source/Core/Common/GL/GLExtensions/ARB_framebuffer_object.h index 3627707944..acbf630304 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_framebuffer_object.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_framebuffer_object.h @@ -23,26 +23,44 @@ #include "Common/GL/GLExtensions/gl_common.h" -typedef void (APIENTRYP PFNDOLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); -typedef void (APIENTRYP PFNDOLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNDOLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -typedef GLenum (APIENTRYP PFNDOLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); -typedef void (APIENTRYP PFNDOLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); -typedef void (APIENTRYP PFNDOLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); -typedef void (APIENTRYP PFNDOLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNDOLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNDOLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNDOLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (APIENTRYP PFNDOLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (APIENTRYP PFNDOLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); -typedef void (APIENTRYP PFNDOLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); -typedef void (APIENTRYP PFNDOLGENERATEMIPMAPPROC) (GLenum target); -typedef void (APIENTRYP PFNDOLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef GLboolean (APIENTRYP PFNDOLISFRAMEBUFFERPROC) (GLuint framebuffer); -typedef GLboolean (APIENTRYP PFNDOLISRENDERBUFFERPROC) (GLuint renderbuffer); -typedef void (APIENTRYP PFNDOLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNDOLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNDOLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +typedef void(APIENTRYP PFNDOLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +typedef void(APIENTRYP PFNDOLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, + GLint srcY1, GLint dstX0, GLint dstY0, + GLint dstX1, GLint dstY1, GLbitfield mask, + GLenum filter); +typedef GLenum(APIENTRYP PFNDOLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +typedef void(APIENTRYP PFNDOLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint* framebuffers); +typedef void(APIENTRYP PFNDOLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint* renderbuffers); +typedef void(APIENTRYP PFNDOLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer); +typedef void(APIENTRYP PFNDOLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level); +typedef void(APIENTRYP PFNDOLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level); +typedef void(APIENTRYP PFNDOLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level, GLint zoffset); +typedef void(APIENTRYP PFNDOLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer); +typedef void(APIENTRYP PFNDOLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint* framebuffers); +typedef void(APIENTRYP PFNDOLGENRENDERBUFFERSPROC)(GLsizei n, GLuint* renderbuffers); +typedef void(APIENTRYP PFNDOLGENERATEMIPMAPPROC)(GLenum target); +typedef void(APIENTRYP PFNDOLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, + GLenum attachment, + GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, + GLint* params); +typedef GLboolean(APIENTRYP PFNDOLISFRAMEBUFFERPROC)(GLuint framebuffer); +typedef GLboolean(APIENTRYP PFNDOLISRENDERBUFFERPROC)(GLuint renderbuffer); +typedef void(APIENTRYP PFNDOLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, + GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNDOLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, + GLenum internalformat, + GLsizei width, GLsizei height); extern PFNDOLBINDFRAMEBUFFERPROC dolBindFramebuffer; extern PFNDOLBINDRENDERBUFFERPROC dolBindRenderbuffer; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_get_program_binary.h b/Source/Core/Common/GL/GLExtensions/ARB_get_program_binary.h index 8c834badaa..586c844794 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_get_program_binary.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_get_program_binary.h @@ -28,9 +28,11 @@ #define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE #define GL_PROGRAM_BINARY_FORMATS 0x87FF -typedef void (APIENTRYP PFNDOLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); -typedef void (APIENTRYP PFNDOLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); -typedef void (APIENTRYP PFNDOLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); +typedef void(APIENTRYP PFNDOLGETPROGRAMBINARYPROC)(GLuint program, GLsizei bufSize, GLsizei* length, + GLenum* binaryFormat, void* binary); +typedef void(APIENTRYP PFNDOLPROGRAMBINARYPROC)(GLuint program, GLenum binaryFormat, + const void* binary, GLsizei length); +typedef void(APIENTRYP PFNDOLPROGRAMPARAMETERIPROC)(GLuint program, GLenum pname, GLint value); extern PFNDOLGETPROGRAMBINARYPROC dolGetProgramBinary; extern PFNDOLPROGRAMBINARYPROC dolProgramBinary; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_map_buffer_range.h b/Source/Core/Common/GL/GLExtensions/ARB_map_buffer_range.h index 4e71748553..05935fa475 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_map_buffer_range.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_map_buffer_range.h @@ -23,8 +23,10 @@ #include "Common/GL/GLExtensions/gl_common.h" -typedef void *(APIENTRYP PFNDOLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -typedef void (APIENTRYP PFNDOLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); +typedef void*(APIENTRYP PFNDOLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, + GLbitfield access); +typedef void(APIENTRYP PFNDOLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, + GLsizeiptr length); extern PFNDOLFLUSHMAPPEDBUFFERRANGEPROC dolFlushMappedBufferRange; extern PFNDOLMAPBUFFERRANGEPROC dolMapBufferRange; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_sample_shading.h b/Source/Core/Common/GL/GLExtensions/ARB_sample_shading.h index fae8e8a313..73e56b6dbd 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_sample_shading.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_sample_shading.h @@ -23,7 +23,7 @@ #include "Common/GL/GLExtensions/gl_common.h" -typedef void (APIENTRYP PFNDOLMINSAMPLESHADINGARBPROC) (GLfloat value); +typedef void(APIENTRYP PFNDOLMINSAMPLESHADINGARBPROC)(GLfloat value); extern PFNDOLMINSAMPLESHADINGARBPROC dolMinSampleShading; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_sampler_objects.h b/Source/Core/Common/GL/GLExtensions/ARB_sampler_objects.h index 99e244d908..40334e7c50 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_sampler_objects.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_sampler_objects.h @@ -23,20 +23,28 @@ #include "Common/GL/GLExtensions/gl_common.h" -typedef void (APIENTRYP PFNDOLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); -typedef void (APIENTRYP PFNDOLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); -typedef GLboolean (APIENTRYP PFNDOLISSAMPLERPROC) (GLuint sampler); -typedef void (APIENTRYP PFNDOLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); -typedef void (APIENTRYP PFNDOLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); -typedef void (APIENTRYP PFNDOLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); -typedef void (APIENTRYP PFNDOLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNDOLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); -typedef void (APIENTRYP PFNDOLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param); -typedef void (APIENTRYP PFNDOLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param); -typedef void (APIENTRYP PFNDOLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNDOLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params); +typedef void(APIENTRYP PFNDOLGENSAMPLERSPROC)(GLsizei count, GLuint* samplers); +typedef void(APIENTRYP PFNDOLDELETESAMPLERSPROC)(GLsizei count, const GLuint* samplers); +typedef GLboolean(APIENTRYP PFNDOLISSAMPLERPROC)(GLuint sampler); +typedef void(APIENTRYP PFNDOLBINDSAMPLERPROC)(GLuint unit, GLuint sampler); +typedef void(APIENTRYP PFNDOLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param); +typedef void(APIENTRYP PFNDOLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, + const GLint* param); +typedef void(APIENTRYP PFNDOLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNDOLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, + const GLfloat* param); +typedef void(APIENTRYP PFNDOLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, + const GLint* param); +typedef void(APIENTRYP PFNDOLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, + const GLuint* param); +typedef void(APIENTRYP PFNDOLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, + GLint* params); +typedef void(APIENTRYP PFNDOLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, + GLint* params); +typedef void(APIENTRYP PFNDOLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, + GLfloat* params); +typedef void(APIENTRYP PFNDOLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, + GLuint* params); extern PFNDOLBINDSAMPLERPROC dolBindSampler; extern PFNDOLDELETESAMPLERSPROC dolDeleteSamplers; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_shader_storage_buffer_object.h b/Source/Core/Common/GL/GLExtensions/ARB_shader_storage_buffer_object.h index 6af54a251a..4f7a82e6b6 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_shader_storage_buffer_object.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_shader_storage_buffer_object.h @@ -40,7 +40,9 @@ #define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE #define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF -typedef void (APIENTRY * PFNDOLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); +typedef void(APIENTRY* PFNDOLSHADERSTORAGEBLOCKBINDINGPROC)(GLuint program, + GLuint storageBlockIndex, + GLuint storageBlockBinding); extern PFNDOLSHADERSTORAGEBLOCKBINDINGPROC dolShaderStorageBlockBinding; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_sync.h b/Source/Core/Common/GL/GLExtensions/ARB_sync.h index 12dbf34a52..e40aa6bbe0 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_sync.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_sync.h @@ -23,14 +23,15 @@ #include "Common/GL/GLExtensions/gl_common.h" -typedef GLsync (APIENTRYP PFNDOLFENCESYNCPROC) (GLenum condition, GLbitfield flags); -typedef GLboolean (APIENTRYP PFNDOLISSYNCPROC) (GLsync sync); -typedef void (APIENTRYP PFNDOLDELETESYNCPROC) (GLsync sync); -typedef GLenum (APIENTRYP PFNDOLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); -typedef void (APIENTRYP PFNDOLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); -typedef void (APIENTRYP PFNDOLGETINTEGER64VPROC) (GLenum pname, GLint64 *data); -typedef void (APIENTRYP PFNDOLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -typedef void (APIENTRYP PFNDOLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); +typedef GLsync(APIENTRYP PFNDOLFENCESYNCPROC)(GLenum condition, GLbitfield flags); +typedef GLboolean(APIENTRYP PFNDOLISSYNCPROC)(GLsync sync); +typedef void(APIENTRYP PFNDOLDELETESYNCPROC)(GLsync sync); +typedef GLenum(APIENTRYP PFNDOLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void(APIENTRYP PFNDOLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void(APIENTRYP PFNDOLGETINTEGER64VPROC)(GLenum pname, GLint64* data); +typedef void(APIENTRYP PFNDOLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei bufSize, + GLsizei* length, GLint* values); +typedef void(APIENTRYP PFNDOLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64* data); extern PFNDOLCLIENTWAITSYNCPROC dolClientWaitSync; extern PFNDOLDELETESYNCPROC dolDeleteSync; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_texture_multisample.h b/Source/Core/Common/GL/GLExtensions/ARB_texture_multisample.h index 3a51d30cad..dbab31b849 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_texture_multisample.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_texture_multisample.h @@ -23,10 +23,16 @@ #include "Common/GL/GLExtensions/gl_common.h" -typedef void (APIENTRYP PFNDOLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNDOLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNDOLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); -typedef void (APIENTRYP PFNDOLSAMPLEMASKIPROC) (GLuint maskNumber, GLbitfield mask); +typedef void(APIENTRYP PFNDOLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, + GLsizei height, + GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNDOLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, + GLsizei height, GLsizei depth, + GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNDOLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat* val); +typedef void(APIENTRYP PFNDOLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); extern PFNDOLTEXIMAGE2DMULTISAMPLEPROC dolTexImage2DMultisample; extern PFNDOLTEXIMAGE3DMULTISAMPLEPROC dolTexImage3DMultisample; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_texture_storage_multisample.h b/Source/Core/Common/GL/GLExtensions/ARB_texture_storage_multisample.h index 980d0ecfb4..3911d5e50c 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_texture_storage_multisample.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_texture_storage_multisample.h @@ -23,8 +23,14 @@ #include "Common/GL/GLExtensions/gl_common.h" -typedef void (APIENTRYP PFNDOLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNDOLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNDOLTEXSTORAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, + GLsizei height, + GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNDOLTEXSTORAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, + GLsizei height, GLsizei depth, + GLboolean fixedsamplelocations); extern PFNDOLTEXSTORAGE2DMULTISAMPLEPROC dolTexStorage2DMultisample; extern PFNDOLTEXSTORAGE3DMULTISAMPLEPROC dolTexStorage3DMultisample; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_uniform_buffer_object.h b/Source/Core/Common/GL/GLExtensions/ARB_uniform_buffer_object.h index 36173860c5..2475578353 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_uniform_buffer_object.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_uniform_buffer_object.h @@ -23,16 +23,29 @@ #include "Common/GL/GLExtensions/gl_common.h" -typedef void (APIENTRYP PFNDOLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); -typedef void (APIENTRYP PFNDOLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNDOLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); -typedef void (APIENTRYP PFNDOLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); -typedef void (APIENTRYP PFNDOLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); -typedef GLuint (APIENTRYP PFNDOLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); -typedef void (APIENTRYP PFNDOLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); -typedef void (APIENTRYP PFNDOLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +typedef void(APIENTRYP PFNDOLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint* data); +typedef void(APIENTRYP PFNDOLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, + GLintptr offset, GLsizeiptr size); +typedef void(APIENTRYP PFNDOLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); +typedef void(APIENTRYP PFNDOLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, + const GLchar* const* uniformNames, + GLuint* uniformIndices); +typedef void(APIENTRYP PFNDOLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, + const GLuint* uniformIndices, GLenum pname, + GLint* params); +typedef void(APIENTRYP PFNDOLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, + GLsizei bufSize, GLsizei* length, + GLchar* uniformName); +typedef GLuint(APIENTRYP PFNDOLGETUNIFORMBLOCKINDEXPROC)(GLuint program, + const GLchar* uniformBlockName); +typedef void(APIENTRYP PFNDOLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, + GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, + GLuint uniformBlockIndex, + GLsizei bufSize, GLsizei* length, + GLchar* uniformBlockName); +typedef void(APIENTRYP PFNDOLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, + GLuint uniformBlockBinding); extern PFNDOLBINDBUFFERBASEPROC dolBindBufferBase; extern PFNDOLBINDBUFFERRANGEPROC dolBindBufferRange; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_vertex_array_object.h b/Source/Core/Common/GL/GLExtensions/ARB_vertex_array_object.h index 7ffb12f04a..df9b5fd9f2 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_vertex_array_object.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_vertex_array_object.h @@ -23,10 +23,10 @@ #include "Common/GL/GLExtensions/gl_common.h" -typedef void (APIENTRYP PFNDOLBINDVERTEXARRAYPROC) (GLuint array); -typedef void (APIENTRYP PFNDOLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); -typedef void (APIENTRYP PFNDOLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); -typedef GLboolean (APIENTRYP PFNDOLISVERTEXARRAYPROC) (GLuint array); +typedef void(APIENTRYP PFNDOLBINDVERTEXARRAYPROC)(GLuint array); +typedef void(APIENTRYP PFNDOLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint* arrays); +typedef void(APIENTRYP PFNDOLGENVERTEXARRAYSPROC)(GLsizei n, GLuint* arrays); +typedef GLboolean(APIENTRYP PFNDOLISVERTEXARRAYPROC)(GLuint array); extern PFNDOLBINDVERTEXARRAYPROC dolBindVertexArray; extern PFNDOLDELETEVERTEXARRAYSPROC dolDeleteVertexArrays; diff --git a/Source/Core/Common/GL/GLExtensions/ARB_viewport_array.h b/Source/Core/Common/GL/GLExtensions/ARB_viewport_array.h index 3ca49f652e..bd29c1b139 100644 --- a/Source/Core/Common/GL/GLExtensions/ARB_viewport_array.h +++ b/Source/Core/Common/GL/GLExtensions/ARB_viewport_array.h @@ -23,16 +23,18 @@ #include "Common/GL/GLExtensions/gl_common.h" -typedef void (APIENTRYP PFNDOLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v); -typedef void (APIENTRYP PFNDOLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); -typedef void (APIENTRYP PFNDOLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNDOLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v); -typedef void (APIENTRYP PFNDOLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNDOLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNDOLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v); -typedef void (APIENTRYP PFNDOLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f); -typedef void (APIENTRYP PFNDOLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data); -typedef void (APIENTRYP PFNDOLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data); +typedef void(APIENTRYP PFNDOLVIEWPORTARRAYVPROC)(GLuint first, GLsizei count, const GLfloat* v); +typedef void(APIENTRYP PFNDOLVIEWPORTINDEXEDFPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat w, + GLfloat h); +typedef void(APIENTRYP PFNDOLVIEWPORTINDEXEDFVPROC)(GLuint index, const GLfloat* v); +typedef void(APIENTRYP PFNDOLSCISSORARRAYVPROC)(GLuint first, GLsizei count, const GLint* v); +typedef void(APIENTRYP PFNDOLSCISSORINDEXEDPROC)(GLuint index, GLint left, GLint bottom, + GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNDOLSCISSORINDEXEDVPROC)(GLuint index, const GLint* v); +typedef void(APIENTRYP PFNDOLDEPTHRANGEARRAYVPROC)(GLuint first, GLsizei count, const GLdouble* v); +typedef void(APIENTRYP PFNDOLDEPTHRANGEINDEXEDPROC)(GLuint index, GLdouble n, GLdouble f); +typedef void(APIENTRYP PFNDOLGETFLOATI_VPROC)(GLenum target, GLuint index, GLfloat* data); +typedef void(APIENTRYP PFNDOLGETDOUBLEI_VPROC)(GLenum target, GLuint index, GLdouble* data); extern PFNDOLDEPTHRANGEARRAYVPROC dolDepthRangeArrayv; extern PFNDOLDEPTHRANGEINDEXEDPROC dolDepthRangeIndexed; diff --git a/Source/Core/Common/GL/GLExtensions/GLExtensions.cpp b/Source/Core/Common/GL/GLExtensions/GLExtensions.cpp index c4bd2e1586..62b33d9140 100644 --- a/Source/Core/Common/GL/GLExtensions/GLExtensions.cpp +++ b/Source/Core/Common/GL/GLExtensions/GLExtensions.cpp @@ -5,11 +5,10 @@ #include #include -#include "Common/GL/GLInterfaceBase.h" #include "Common/GL/GLExtensions/GLExtensions.h" +#include "Common/GL/GLInterfaceBase.h" #include "Common/Logging/Log.h" - #if defined(__linux__) || defined(__APPLE__) #include #endif @@ -650,7 +649,8 @@ PFNDOLGETINTEGER64I_VPROC dolGetInteger64i_v; // gl 4_2 PFNDOLDRAWARRAYSINSTANCEDBASEINSTANCEPROC dolDrawArraysInstancedBaseInstance; PFNDOLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC dolDrawElementsInstancedBaseInstance; -PFNDOLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC dolDrawElementsInstancedBaseVertexBaseInstance; +PFNDOLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC + dolDrawElementsInstancedBaseVertexBaseInstance; PFNDOLGETINTERNALFORMATIVPROC dolGetInternalformativ; PFNDOLGETACTIVEATOMICCOUNTERBUFFERIVPROC dolGetActiveAtomicCounterBufferiv; PFNDOLBINDIMAGETEXTUREPROC dolBindImageTexture; @@ -985,1438 +985,1218 @@ PFNDOLCOPYIMAGESUBDATAPROC dolCopyImageSubData; PFNDOLSHADERSTORAGEBLOCKBINDINGPROC dolShaderStorageBlockBinding; // Creates a GLFunc object that requires a feature -#define GLFUNC_REQUIRES(x, y) { (void**)&x, #x, y } +#define GLFUNC_REQUIRES(x, y) \ + { \ + (void**)&x, #x, y \ + } // Creates a GLFunc object with a different function suffix // For when we want to use the same function pointer, but different function name -#define GLFUNC_SUFFIX(x, y, z) { (void**)&x, #x #y, z } +#define GLFUNC_SUFFIX(x, y, z) \ + { \ + (void**)&x, #x #y, z \ + } // Creates a GLFunc object that should always be able to get grabbed // Used for Desktop OpenGL functions that should /always/ be provided. // aka GL 1.1/1.2/1.3/1.4 -#define GLFUNC_ALWAYS_REQUIRED(x) { (void**)&x, #x, "VERSION_GL" } +#define GLFUNC_ALWAYS_REQUIRED(x) \ + { \ + (void**)&x, #x, "VERSION_GL" \ + } // Creates a GLFunc object that should be able to get grabbed // on both GL and ES -#define GL_ES_FUNC_ALWAYS_REQUIRED(x) { (void**)&x, #x, "VERSION_GL |VERSION_GLES_2" } +#define GL_ES_FUNC_ALWAYS_REQUIRED(x) \ + { \ + (void**)&x, #x, "VERSION_GL |VERSION_GLES_2" \ + } // Creates a GLFunc object that should be able to get grabbed // on both GL and ES 3.0 -#define GL_ES3_FUNC_ALWAYS_REQUIRED(x) { (void**)&x, #x, "VERSION_GL |VERSION_GLES_3" } +#define GL_ES3_FUNC_ALWAYS_REQUIRED(x) \ + { \ + (void**)&x, #x, "VERSION_GL |VERSION_GLES_3" \ + } // Creates a GLFunc object that should be able to get grabbed // on both GL and ES 3.2 -#define GL_ES32_FUNC_ALWAYS_REQUIRED(x) { (void**)&x, #x, "VERSION_GL |VERSION_GLES_3_2" } +#define GL_ES32_FUNC_ALWAYS_REQUIRED(x) \ + { \ + (void**)&x, #x, "VERSION_GL |VERSION_GLES_3_2" \ + } struct GLFunc { - void** function_ptr; - const std::string function_name; - const std::string requirements; + void** function_ptr; + const std::string function_name; + const std::string requirements; }; -const GLFunc gl_function_array[] = -{ - // gl_1_1 - GLFUNC_ALWAYS_REQUIRED(glClearIndex), - GLFUNC_ALWAYS_REQUIRED(glIndexMask), - GLFUNC_ALWAYS_REQUIRED(glAlphaFunc), - GLFUNC_ALWAYS_REQUIRED(glLogicOp), - GLFUNC_ALWAYS_REQUIRED(glPointSize), - GLFUNC_ALWAYS_REQUIRED(glLineStipple), - GLFUNC_ALWAYS_REQUIRED(glPolygonMode), - GLFUNC_ALWAYS_REQUIRED(glPolygonStipple), - GLFUNC_ALWAYS_REQUIRED(glGetPolygonStipple), - GLFUNC_ALWAYS_REQUIRED(glEdgeFlag), - GLFUNC_ALWAYS_REQUIRED(glEdgeFlagv), - GLFUNC_ALWAYS_REQUIRED(glClipPlane), - GLFUNC_ALWAYS_REQUIRED(glGetClipPlane), - GLFUNC_ALWAYS_REQUIRED(glDrawBuffer), - GLFUNC_ALWAYS_REQUIRED(glEnableClientState), - GLFUNC_ALWAYS_REQUIRED(glDisableClientState), - GLFUNC_ALWAYS_REQUIRED(glGetDoublev), - GLFUNC_ALWAYS_REQUIRED(glPushAttrib), - GLFUNC_ALWAYS_REQUIRED(glPopAttrib), - GLFUNC_ALWAYS_REQUIRED(glPushClientAttrib), - GLFUNC_ALWAYS_REQUIRED(glPopClientAttrib), - GLFUNC_ALWAYS_REQUIRED(glRenderMode), - GLFUNC_ALWAYS_REQUIRED(glClearDepth), - GLFUNC_ALWAYS_REQUIRED(glDepthRange), - GLFUNC_ALWAYS_REQUIRED(glClearAccum), - GLFUNC_ALWAYS_REQUIRED(glAccum), - GLFUNC_ALWAYS_REQUIRED(glMatrixMode), - GLFUNC_ALWAYS_REQUIRED(glOrtho), - GLFUNC_ALWAYS_REQUIRED(glFrustum), - GLFUNC_ALWAYS_REQUIRED(glPushMatrix), - GLFUNC_ALWAYS_REQUIRED(glPopMatrix), - GLFUNC_ALWAYS_REQUIRED(glLoadIdentity), - GLFUNC_ALWAYS_REQUIRED(glLoadMatrixd), - GLFUNC_ALWAYS_REQUIRED(glLoadMatrixf), - GLFUNC_ALWAYS_REQUIRED(glMultMatrixd), - GLFUNC_ALWAYS_REQUIRED(glMultMatrixf), - GLFUNC_ALWAYS_REQUIRED(glRotated), - GLFUNC_ALWAYS_REQUIRED(glRotatef), - GLFUNC_ALWAYS_REQUIRED(glScaled), - GLFUNC_ALWAYS_REQUIRED(glScalef), - GLFUNC_ALWAYS_REQUIRED(glTranslated), - GLFUNC_ALWAYS_REQUIRED(glTranslatef), - GLFUNC_ALWAYS_REQUIRED(glIsList), - GLFUNC_ALWAYS_REQUIRED(glDeleteLists), - GLFUNC_ALWAYS_REQUIRED(glGenLists), - GLFUNC_ALWAYS_REQUIRED(glNewList), - GLFUNC_ALWAYS_REQUIRED(glEndList), - GLFUNC_ALWAYS_REQUIRED(glCallList), - GLFUNC_ALWAYS_REQUIRED(glCallLists), - GLFUNC_ALWAYS_REQUIRED(glListBase), - GLFUNC_ALWAYS_REQUIRED(glBegin), - GLFUNC_ALWAYS_REQUIRED(glEnd), - GLFUNC_ALWAYS_REQUIRED(glVertex2d), - GLFUNC_ALWAYS_REQUIRED(glVertex2f), - GLFUNC_ALWAYS_REQUIRED(glVertex2i), - GLFUNC_ALWAYS_REQUIRED(glVertex2s), - GLFUNC_ALWAYS_REQUIRED(glVertex3d), - GLFUNC_ALWAYS_REQUIRED(glVertex3f), - GLFUNC_ALWAYS_REQUIRED(glVertex3i), - GLFUNC_ALWAYS_REQUIRED(glVertex3s), - GLFUNC_ALWAYS_REQUIRED(glVertex4d), - GLFUNC_ALWAYS_REQUIRED(glVertex4f), - GLFUNC_ALWAYS_REQUIRED(glVertex4i), - GLFUNC_ALWAYS_REQUIRED(glVertex4s), - GLFUNC_ALWAYS_REQUIRED(glVertex2dv), - GLFUNC_ALWAYS_REQUIRED(glVertex2fv), - GLFUNC_ALWAYS_REQUIRED(glVertex2iv), - GLFUNC_ALWAYS_REQUIRED(glVertex2sv), - GLFUNC_ALWAYS_REQUIRED(glVertex3dv), - GLFUNC_ALWAYS_REQUIRED(glVertex3fv), - GLFUNC_ALWAYS_REQUIRED(glVertex3iv), - GLFUNC_ALWAYS_REQUIRED(glVertex3sv), - GLFUNC_ALWAYS_REQUIRED(glVertex4dv), - GLFUNC_ALWAYS_REQUIRED(glVertex4fv), - GLFUNC_ALWAYS_REQUIRED(glVertex4iv), - GLFUNC_ALWAYS_REQUIRED(glVertex4sv), - GLFUNC_ALWAYS_REQUIRED(glNormal3b), - GLFUNC_ALWAYS_REQUIRED(glNormal3d), - GLFUNC_ALWAYS_REQUIRED(glNormal3f), - GLFUNC_ALWAYS_REQUIRED(glNormal3i), - GLFUNC_ALWAYS_REQUIRED(glNormal3s), - GLFUNC_ALWAYS_REQUIRED(glNormal3bv), - GLFUNC_ALWAYS_REQUIRED(glNormal3dv), - GLFUNC_ALWAYS_REQUIRED(glNormal3fv), - GLFUNC_ALWAYS_REQUIRED(glNormal3iv), - GLFUNC_ALWAYS_REQUIRED(glNormal3sv), - GLFUNC_ALWAYS_REQUIRED(glIndexd), - GLFUNC_ALWAYS_REQUIRED(glIndexf), - GLFUNC_ALWAYS_REQUIRED(glIndexi), - GLFUNC_ALWAYS_REQUIRED(glIndexs), - GLFUNC_ALWAYS_REQUIRED(glIndexub), - GLFUNC_ALWAYS_REQUIRED(glIndexdv), - GLFUNC_ALWAYS_REQUIRED(glIndexfv), - GLFUNC_ALWAYS_REQUIRED(glIndexiv), - GLFUNC_ALWAYS_REQUIRED(glIndexsv), - GLFUNC_ALWAYS_REQUIRED(glIndexubv), - GLFUNC_ALWAYS_REQUIRED(glColor3b), - GLFUNC_ALWAYS_REQUIRED(glColor3d), - GLFUNC_ALWAYS_REQUIRED(glColor3f), - GLFUNC_ALWAYS_REQUIRED(glColor3i), - GLFUNC_ALWAYS_REQUIRED(glColor3s), - GLFUNC_ALWAYS_REQUIRED(glColor3ub), - GLFUNC_ALWAYS_REQUIRED(glColor3ui), - GLFUNC_ALWAYS_REQUIRED(glColor3us), - GLFUNC_ALWAYS_REQUIRED(glColor4b), - GLFUNC_ALWAYS_REQUIRED(glColor4d), - GLFUNC_ALWAYS_REQUIRED(glColor4f), - GLFUNC_ALWAYS_REQUIRED(glColor4i), - GLFUNC_ALWAYS_REQUIRED(glColor4s), - GLFUNC_ALWAYS_REQUIRED(glColor4ub), - GLFUNC_ALWAYS_REQUIRED(glColor4ui), - GLFUNC_ALWAYS_REQUIRED(glColor4us), - GLFUNC_ALWAYS_REQUIRED(glColor3bv), - GLFUNC_ALWAYS_REQUIRED(glColor3dv), - GLFUNC_ALWAYS_REQUIRED(glColor3fv), - GLFUNC_ALWAYS_REQUIRED(glColor3iv), - GLFUNC_ALWAYS_REQUIRED(glColor3sv), - GLFUNC_ALWAYS_REQUIRED(glColor3ubv), - GLFUNC_ALWAYS_REQUIRED(glColor3uiv), - GLFUNC_ALWAYS_REQUIRED(glColor3usv), - GLFUNC_ALWAYS_REQUIRED(glColor4bv), - GLFUNC_ALWAYS_REQUIRED(glColor4dv), - GLFUNC_ALWAYS_REQUIRED(glColor4fv), - GLFUNC_ALWAYS_REQUIRED(glColor4iv), - GLFUNC_ALWAYS_REQUIRED(glColor4sv), - GLFUNC_ALWAYS_REQUIRED(glColor4ubv), - GLFUNC_ALWAYS_REQUIRED(glColor4uiv), - GLFUNC_ALWAYS_REQUIRED(glColor4usv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord1d), - GLFUNC_ALWAYS_REQUIRED(glTexCoord1f), - GLFUNC_ALWAYS_REQUIRED(glTexCoord1i), - GLFUNC_ALWAYS_REQUIRED(glTexCoord1s), - GLFUNC_ALWAYS_REQUIRED(glTexCoord2d), - GLFUNC_ALWAYS_REQUIRED(glTexCoord2f), - GLFUNC_ALWAYS_REQUIRED(glTexCoord2i), - GLFUNC_ALWAYS_REQUIRED(glTexCoord2s), - GLFUNC_ALWAYS_REQUIRED(glTexCoord3d), - GLFUNC_ALWAYS_REQUIRED(glTexCoord3f), - GLFUNC_ALWAYS_REQUIRED(glTexCoord3i), - GLFUNC_ALWAYS_REQUIRED(glTexCoord3s), - GLFUNC_ALWAYS_REQUIRED(glTexCoord4d), - GLFUNC_ALWAYS_REQUIRED(glTexCoord4f), - GLFUNC_ALWAYS_REQUIRED(glTexCoord4i), - GLFUNC_ALWAYS_REQUIRED(glTexCoord4s), - GLFUNC_ALWAYS_REQUIRED(glTexCoord1dv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord1fv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord1iv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord1sv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord2dv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord2fv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord2iv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord2sv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord3dv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord3fv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord3iv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord3sv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord4dv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord4fv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord4iv), - GLFUNC_ALWAYS_REQUIRED(glTexCoord4sv), - GLFUNC_ALWAYS_REQUIRED(glRasterPos2d), - GLFUNC_ALWAYS_REQUIRED(glRasterPos2f), - GLFUNC_ALWAYS_REQUIRED(glRasterPos2i), - GLFUNC_ALWAYS_REQUIRED(glRasterPos2s), - GLFUNC_ALWAYS_REQUIRED(glRasterPos3d), - GLFUNC_ALWAYS_REQUIRED(glRasterPos3f), - GLFUNC_ALWAYS_REQUIRED(glRasterPos3i), - GLFUNC_ALWAYS_REQUIRED(glRasterPos3s), - GLFUNC_ALWAYS_REQUIRED(glRasterPos4d), - GLFUNC_ALWAYS_REQUIRED(glRasterPos4f), - GLFUNC_ALWAYS_REQUIRED(glRasterPos4i), - GLFUNC_ALWAYS_REQUIRED(glRasterPos4s), - GLFUNC_ALWAYS_REQUIRED(glRasterPos2dv), - GLFUNC_ALWAYS_REQUIRED(glRasterPos2fv), - GLFUNC_ALWAYS_REQUIRED(glRasterPos2iv), - GLFUNC_ALWAYS_REQUIRED(glRasterPos2sv), - GLFUNC_ALWAYS_REQUIRED(glRasterPos3dv), - GLFUNC_ALWAYS_REQUIRED(glRasterPos3fv), - GLFUNC_ALWAYS_REQUIRED(glRasterPos3iv), - GLFUNC_ALWAYS_REQUIRED(glRasterPos3sv), - GLFUNC_ALWAYS_REQUIRED(glRasterPos4dv), - GLFUNC_ALWAYS_REQUIRED(glRasterPos4fv), - GLFUNC_ALWAYS_REQUIRED(glRasterPos4iv), - GLFUNC_ALWAYS_REQUIRED(glRasterPos4sv), - GLFUNC_ALWAYS_REQUIRED(glRectd), - GLFUNC_ALWAYS_REQUIRED(glRectf), - GLFUNC_ALWAYS_REQUIRED(glRecti), - GLFUNC_ALWAYS_REQUIRED(glRects), - GLFUNC_ALWAYS_REQUIRED(glRectdv), - GLFUNC_ALWAYS_REQUIRED(glRectfv), - GLFUNC_ALWAYS_REQUIRED(glRectiv), - GLFUNC_ALWAYS_REQUIRED(glRectsv), - GLFUNC_ALWAYS_REQUIRED(glVertexPointer), - GLFUNC_ALWAYS_REQUIRED(glNormalPointer), - GLFUNC_ALWAYS_REQUIRED(glColorPointer), - GLFUNC_ALWAYS_REQUIRED(glIndexPointer), - GLFUNC_ALWAYS_REQUIRED(glTexCoordPointer), - GLFUNC_ALWAYS_REQUIRED(glEdgeFlagPointer), - GLFUNC_ALWAYS_REQUIRED(glArrayElement), - GLFUNC_ALWAYS_REQUIRED(glInterleavedArrays), - GLFUNC_ALWAYS_REQUIRED(glShadeModel), - GLFUNC_ALWAYS_REQUIRED(glLightf), - GLFUNC_ALWAYS_REQUIRED(glLighti), - GLFUNC_ALWAYS_REQUIRED(glLightfv), - GLFUNC_ALWAYS_REQUIRED(glLightiv), - GLFUNC_ALWAYS_REQUIRED(glGetLightfv), - GLFUNC_ALWAYS_REQUIRED(glGetLightiv), - GLFUNC_ALWAYS_REQUIRED(glLightModelf), - GLFUNC_ALWAYS_REQUIRED(glLightModeli), - GLFUNC_ALWAYS_REQUIRED(glLightModelfv), - GLFUNC_ALWAYS_REQUIRED(glLightModeliv), - GLFUNC_ALWAYS_REQUIRED(glMaterialf), - GLFUNC_ALWAYS_REQUIRED(glMateriali), - GLFUNC_ALWAYS_REQUIRED(glMaterialfv), - GLFUNC_ALWAYS_REQUIRED(glMaterialiv), - GLFUNC_ALWAYS_REQUIRED(glGetMaterialfv), - GLFUNC_ALWAYS_REQUIRED(glGetMaterialiv), - GLFUNC_ALWAYS_REQUIRED(glColorMaterial), - GLFUNC_ALWAYS_REQUIRED(glPixelZoom), - GLFUNC_ALWAYS_REQUIRED(glPixelStoref), - GLFUNC_ALWAYS_REQUIRED(glPixelTransferf), - GLFUNC_ALWAYS_REQUIRED(glPixelTransferi), - GLFUNC_ALWAYS_REQUIRED(glPixelMapfv), - GLFUNC_ALWAYS_REQUIRED(glPixelMapuiv), - GLFUNC_ALWAYS_REQUIRED(glPixelMapusv), - GLFUNC_ALWAYS_REQUIRED(glGetPixelMapfv), - GLFUNC_ALWAYS_REQUIRED(glGetPixelMapuiv), - GLFUNC_ALWAYS_REQUIRED(glGetPixelMapusv), - GLFUNC_ALWAYS_REQUIRED(glBitmap), - GLFUNC_ALWAYS_REQUIRED(glDrawPixels), - GLFUNC_ALWAYS_REQUIRED(glCopyPixels), - GLFUNC_ALWAYS_REQUIRED(glTexGend), - GLFUNC_ALWAYS_REQUIRED(glTexGenf), - GLFUNC_ALWAYS_REQUIRED(glTexGeni), - GLFUNC_ALWAYS_REQUIRED(glTexGendv), - GLFUNC_ALWAYS_REQUIRED(glTexGenfv), - GLFUNC_ALWAYS_REQUIRED(glTexGeniv), - GLFUNC_ALWAYS_REQUIRED(glGetTexGendv), - GLFUNC_ALWAYS_REQUIRED(glGetTexGenfv), - GLFUNC_ALWAYS_REQUIRED(glGetTexGeniv), - GLFUNC_ALWAYS_REQUIRED(glTexEnvf), - GLFUNC_ALWAYS_REQUIRED(glTexEnvi), - GLFUNC_ALWAYS_REQUIRED(glTexEnvfv), - GLFUNC_ALWAYS_REQUIRED(glTexEnviv), - GLFUNC_ALWAYS_REQUIRED(glGetTexEnvfv), - GLFUNC_ALWAYS_REQUIRED(glGetTexEnviv), - GLFUNC_ALWAYS_REQUIRED(glGetTexLevelParameterfv), - GLFUNC_ALWAYS_REQUIRED(glGetTexLevelParameteriv), - GLFUNC_ALWAYS_REQUIRED(glTexImage1D), - GLFUNC_ALWAYS_REQUIRED(glGetTexImage), - GLFUNC_ALWAYS_REQUIRED(glPrioritizeTextures), - GLFUNC_ALWAYS_REQUIRED(glAreTexturesResident), - GLFUNC_ALWAYS_REQUIRED(glTexSubImage1D), - GLFUNC_ALWAYS_REQUIRED(glCopyTexImage1D), - GLFUNC_ALWAYS_REQUIRED(glCopyTexSubImage1D), - GLFUNC_ALWAYS_REQUIRED(glMap1d), - GLFUNC_ALWAYS_REQUIRED(glMap1f), - GLFUNC_ALWAYS_REQUIRED(glMap2d), - GLFUNC_ALWAYS_REQUIRED(glMap2f), - GLFUNC_ALWAYS_REQUIRED(glGetMapdv), - GLFUNC_ALWAYS_REQUIRED(glGetMapfv), - GLFUNC_ALWAYS_REQUIRED(glGetMapiv), - GLFUNC_ALWAYS_REQUIRED(glEvalCoord1d), - GLFUNC_ALWAYS_REQUIRED(glEvalCoord1f), - GLFUNC_ALWAYS_REQUIRED(glEvalCoord1dv), - GLFUNC_ALWAYS_REQUIRED(glEvalCoord1fv), - GLFUNC_ALWAYS_REQUIRED(glEvalCoord2d), - GLFUNC_ALWAYS_REQUIRED(glEvalCoord2f), - GLFUNC_ALWAYS_REQUIRED(glEvalCoord2dv), - GLFUNC_ALWAYS_REQUIRED(glEvalCoord2fv), - GLFUNC_ALWAYS_REQUIRED(glMapGrid1d), - GLFUNC_ALWAYS_REQUIRED(glMapGrid1f), - GLFUNC_ALWAYS_REQUIRED(glMapGrid2d), - GLFUNC_ALWAYS_REQUIRED(glMapGrid2f), - GLFUNC_ALWAYS_REQUIRED(glEvalPoint1), - GLFUNC_ALWAYS_REQUIRED(glEvalPoint2), - GLFUNC_ALWAYS_REQUIRED(glEvalMesh1), - GLFUNC_ALWAYS_REQUIRED(glEvalMesh2), - GLFUNC_ALWAYS_REQUIRED(glFogf), - GLFUNC_ALWAYS_REQUIRED(glFogi), - GLFUNC_ALWAYS_REQUIRED(glFogfv), - GLFUNC_ALWAYS_REQUIRED(glFogiv), - GLFUNC_ALWAYS_REQUIRED(glFeedbackBuffer), - GLFUNC_ALWAYS_REQUIRED(glPassThrough), - GLFUNC_ALWAYS_REQUIRED(glSelectBuffer), - GLFUNC_ALWAYS_REQUIRED(glInitNames), - GLFUNC_ALWAYS_REQUIRED(glLoadName), - GLFUNC_ALWAYS_REQUIRED(glPushName), - GLFUNC_ALWAYS_REQUIRED(glPopName), - GL_ES_FUNC_ALWAYS_REQUIRED(glTexImage2D), - GL_ES_FUNC_ALWAYS_REQUIRED(glClearColor), - GL_ES_FUNC_ALWAYS_REQUIRED(glClear), - GL_ES_FUNC_ALWAYS_REQUIRED(glColorMask), - GL_ES_FUNC_ALWAYS_REQUIRED(glBlendFunc), - GL_ES_FUNC_ALWAYS_REQUIRED(glCullFace), - GL_ES_FUNC_ALWAYS_REQUIRED(glFrontFace), - GL_ES_FUNC_ALWAYS_REQUIRED(glLineWidth), - GL_ES_FUNC_ALWAYS_REQUIRED(glPolygonOffset), - GL_ES_FUNC_ALWAYS_REQUIRED(glScissor), - GL_ES_FUNC_ALWAYS_REQUIRED(glEnable), - GL_ES_FUNC_ALWAYS_REQUIRED(glDisable), - GL_ES_FUNC_ALWAYS_REQUIRED(glIsEnabled), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetBooleanv), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetFloatv), - GL_ES_FUNC_ALWAYS_REQUIRED(glFinish), - GL_ES_FUNC_ALWAYS_REQUIRED(glFlush), - GL_ES_FUNC_ALWAYS_REQUIRED(glHint), - GL_ES_FUNC_ALWAYS_REQUIRED(glDepthFunc), - GL_ES_FUNC_ALWAYS_REQUIRED(glDepthMask), - GL_ES_FUNC_ALWAYS_REQUIRED(glViewport), - GL_ES_FUNC_ALWAYS_REQUIRED(glDrawArrays), - GL_ES_FUNC_ALWAYS_REQUIRED(glDrawElements), - GL_ES_FUNC_ALWAYS_REQUIRED(glPixelStorei), - GL_ES_FUNC_ALWAYS_REQUIRED(glReadPixels), - GL_ES_FUNC_ALWAYS_REQUIRED(glStencilFunc), - GL_ES_FUNC_ALWAYS_REQUIRED(glStencilMask), - GL_ES_FUNC_ALWAYS_REQUIRED(glStencilOp), - GL_ES_FUNC_ALWAYS_REQUIRED(glClearStencil), - GL_ES_FUNC_ALWAYS_REQUIRED(glTexParameterf), - GL_ES_FUNC_ALWAYS_REQUIRED(glTexParameteri), - GL_ES_FUNC_ALWAYS_REQUIRED(glTexParameterfv), - GL_ES_FUNC_ALWAYS_REQUIRED(glTexParameteriv), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetTexParameterfv), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetTexParameteriv), - GL_ES_FUNC_ALWAYS_REQUIRED(glGenTextures), - GL_ES_FUNC_ALWAYS_REQUIRED(glDeleteTextures), - GL_ES_FUNC_ALWAYS_REQUIRED(glBindTexture), - GL_ES_FUNC_ALWAYS_REQUIRED(glIsTexture), - GL_ES_FUNC_ALWAYS_REQUIRED(glTexSubImage2D), - GL_ES_FUNC_ALWAYS_REQUIRED(glCopyTexImage2D), - GL_ES_FUNC_ALWAYS_REQUIRED(glCopyTexSubImage2D), - GL_ES3_FUNC_ALWAYS_REQUIRED(glReadBuffer), - GL_ES32_FUNC_ALWAYS_REQUIRED(glGetPointerv), +const GLFunc gl_function_array[] = { + // gl_1_1 + GLFUNC_ALWAYS_REQUIRED(glClearIndex), GLFUNC_ALWAYS_REQUIRED(glIndexMask), + GLFUNC_ALWAYS_REQUIRED(glAlphaFunc), GLFUNC_ALWAYS_REQUIRED(glLogicOp), + GLFUNC_ALWAYS_REQUIRED(glPointSize), GLFUNC_ALWAYS_REQUIRED(glLineStipple), + GLFUNC_ALWAYS_REQUIRED(glPolygonMode), GLFUNC_ALWAYS_REQUIRED(glPolygonStipple), + GLFUNC_ALWAYS_REQUIRED(glGetPolygonStipple), GLFUNC_ALWAYS_REQUIRED(glEdgeFlag), + GLFUNC_ALWAYS_REQUIRED(glEdgeFlagv), GLFUNC_ALWAYS_REQUIRED(glClipPlane), + GLFUNC_ALWAYS_REQUIRED(glGetClipPlane), GLFUNC_ALWAYS_REQUIRED(glDrawBuffer), + GLFUNC_ALWAYS_REQUIRED(glEnableClientState), GLFUNC_ALWAYS_REQUIRED(glDisableClientState), + GLFUNC_ALWAYS_REQUIRED(glGetDoublev), GLFUNC_ALWAYS_REQUIRED(glPushAttrib), + GLFUNC_ALWAYS_REQUIRED(glPopAttrib), GLFUNC_ALWAYS_REQUIRED(glPushClientAttrib), + GLFUNC_ALWAYS_REQUIRED(glPopClientAttrib), GLFUNC_ALWAYS_REQUIRED(glRenderMode), + GLFUNC_ALWAYS_REQUIRED(glClearDepth), GLFUNC_ALWAYS_REQUIRED(glDepthRange), + GLFUNC_ALWAYS_REQUIRED(glClearAccum), GLFUNC_ALWAYS_REQUIRED(glAccum), + GLFUNC_ALWAYS_REQUIRED(glMatrixMode), GLFUNC_ALWAYS_REQUIRED(glOrtho), + GLFUNC_ALWAYS_REQUIRED(glFrustum), GLFUNC_ALWAYS_REQUIRED(glPushMatrix), + GLFUNC_ALWAYS_REQUIRED(glPopMatrix), GLFUNC_ALWAYS_REQUIRED(glLoadIdentity), + GLFUNC_ALWAYS_REQUIRED(glLoadMatrixd), GLFUNC_ALWAYS_REQUIRED(glLoadMatrixf), + GLFUNC_ALWAYS_REQUIRED(glMultMatrixd), GLFUNC_ALWAYS_REQUIRED(glMultMatrixf), + GLFUNC_ALWAYS_REQUIRED(glRotated), GLFUNC_ALWAYS_REQUIRED(glRotatef), + GLFUNC_ALWAYS_REQUIRED(glScaled), GLFUNC_ALWAYS_REQUIRED(glScalef), + GLFUNC_ALWAYS_REQUIRED(glTranslated), GLFUNC_ALWAYS_REQUIRED(glTranslatef), + GLFUNC_ALWAYS_REQUIRED(glIsList), GLFUNC_ALWAYS_REQUIRED(glDeleteLists), + GLFUNC_ALWAYS_REQUIRED(glGenLists), GLFUNC_ALWAYS_REQUIRED(glNewList), + GLFUNC_ALWAYS_REQUIRED(glEndList), GLFUNC_ALWAYS_REQUIRED(glCallList), + GLFUNC_ALWAYS_REQUIRED(glCallLists), GLFUNC_ALWAYS_REQUIRED(glListBase), + GLFUNC_ALWAYS_REQUIRED(glBegin), GLFUNC_ALWAYS_REQUIRED(glEnd), + GLFUNC_ALWAYS_REQUIRED(glVertex2d), GLFUNC_ALWAYS_REQUIRED(glVertex2f), + GLFUNC_ALWAYS_REQUIRED(glVertex2i), GLFUNC_ALWAYS_REQUIRED(glVertex2s), + GLFUNC_ALWAYS_REQUIRED(glVertex3d), GLFUNC_ALWAYS_REQUIRED(glVertex3f), + GLFUNC_ALWAYS_REQUIRED(glVertex3i), GLFUNC_ALWAYS_REQUIRED(glVertex3s), + GLFUNC_ALWAYS_REQUIRED(glVertex4d), GLFUNC_ALWAYS_REQUIRED(glVertex4f), + GLFUNC_ALWAYS_REQUIRED(glVertex4i), GLFUNC_ALWAYS_REQUIRED(glVertex4s), + GLFUNC_ALWAYS_REQUIRED(glVertex2dv), GLFUNC_ALWAYS_REQUIRED(glVertex2fv), + GLFUNC_ALWAYS_REQUIRED(glVertex2iv), GLFUNC_ALWAYS_REQUIRED(glVertex2sv), + GLFUNC_ALWAYS_REQUIRED(glVertex3dv), GLFUNC_ALWAYS_REQUIRED(glVertex3fv), + GLFUNC_ALWAYS_REQUIRED(glVertex3iv), GLFUNC_ALWAYS_REQUIRED(glVertex3sv), + GLFUNC_ALWAYS_REQUIRED(glVertex4dv), GLFUNC_ALWAYS_REQUIRED(glVertex4fv), + GLFUNC_ALWAYS_REQUIRED(glVertex4iv), GLFUNC_ALWAYS_REQUIRED(glVertex4sv), + GLFUNC_ALWAYS_REQUIRED(glNormal3b), GLFUNC_ALWAYS_REQUIRED(glNormal3d), + GLFUNC_ALWAYS_REQUIRED(glNormal3f), GLFUNC_ALWAYS_REQUIRED(glNormal3i), + GLFUNC_ALWAYS_REQUIRED(glNormal3s), GLFUNC_ALWAYS_REQUIRED(glNormal3bv), + GLFUNC_ALWAYS_REQUIRED(glNormal3dv), GLFUNC_ALWAYS_REQUIRED(glNormal3fv), + GLFUNC_ALWAYS_REQUIRED(glNormal3iv), GLFUNC_ALWAYS_REQUIRED(glNormal3sv), + GLFUNC_ALWAYS_REQUIRED(glIndexd), GLFUNC_ALWAYS_REQUIRED(glIndexf), + GLFUNC_ALWAYS_REQUIRED(glIndexi), GLFUNC_ALWAYS_REQUIRED(glIndexs), + GLFUNC_ALWAYS_REQUIRED(glIndexub), GLFUNC_ALWAYS_REQUIRED(glIndexdv), + GLFUNC_ALWAYS_REQUIRED(glIndexfv), GLFUNC_ALWAYS_REQUIRED(glIndexiv), + GLFUNC_ALWAYS_REQUIRED(glIndexsv), GLFUNC_ALWAYS_REQUIRED(glIndexubv), + GLFUNC_ALWAYS_REQUIRED(glColor3b), GLFUNC_ALWAYS_REQUIRED(glColor3d), + GLFUNC_ALWAYS_REQUIRED(glColor3f), GLFUNC_ALWAYS_REQUIRED(glColor3i), + GLFUNC_ALWAYS_REQUIRED(glColor3s), GLFUNC_ALWAYS_REQUIRED(glColor3ub), + GLFUNC_ALWAYS_REQUIRED(glColor3ui), GLFUNC_ALWAYS_REQUIRED(glColor3us), + GLFUNC_ALWAYS_REQUIRED(glColor4b), GLFUNC_ALWAYS_REQUIRED(glColor4d), + GLFUNC_ALWAYS_REQUIRED(glColor4f), GLFUNC_ALWAYS_REQUIRED(glColor4i), + GLFUNC_ALWAYS_REQUIRED(glColor4s), GLFUNC_ALWAYS_REQUIRED(glColor4ub), + GLFUNC_ALWAYS_REQUIRED(glColor4ui), GLFUNC_ALWAYS_REQUIRED(glColor4us), + GLFUNC_ALWAYS_REQUIRED(glColor3bv), GLFUNC_ALWAYS_REQUIRED(glColor3dv), + GLFUNC_ALWAYS_REQUIRED(glColor3fv), GLFUNC_ALWAYS_REQUIRED(glColor3iv), + GLFUNC_ALWAYS_REQUIRED(glColor3sv), GLFUNC_ALWAYS_REQUIRED(glColor3ubv), + GLFUNC_ALWAYS_REQUIRED(glColor3uiv), GLFUNC_ALWAYS_REQUIRED(glColor3usv), + GLFUNC_ALWAYS_REQUIRED(glColor4bv), GLFUNC_ALWAYS_REQUIRED(glColor4dv), + GLFUNC_ALWAYS_REQUIRED(glColor4fv), GLFUNC_ALWAYS_REQUIRED(glColor4iv), + GLFUNC_ALWAYS_REQUIRED(glColor4sv), GLFUNC_ALWAYS_REQUIRED(glColor4ubv), + GLFUNC_ALWAYS_REQUIRED(glColor4uiv), GLFUNC_ALWAYS_REQUIRED(glColor4usv), + GLFUNC_ALWAYS_REQUIRED(glTexCoord1d), GLFUNC_ALWAYS_REQUIRED(glTexCoord1f), + GLFUNC_ALWAYS_REQUIRED(glTexCoord1i), GLFUNC_ALWAYS_REQUIRED(glTexCoord1s), + GLFUNC_ALWAYS_REQUIRED(glTexCoord2d), GLFUNC_ALWAYS_REQUIRED(glTexCoord2f), + GLFUNC_ALWAYS_REQUIRED(glTexCoord2i), GLFUNC_ALWAYS_REQUIRED(glTexCoord2s), + GLFUNC_ALWAYS_REQUIRED(glTexCoord3d), GLFUNC_ALWAYS_REQUIRED(glTexCoord3f), + GLFUNC_ALWAYS_REQUIRED(glTexCoord3i), GLFUNC_ALWAYS_REQUIRED(glTexCoord3s), + GLFUNC_ALWAYS_REQUIRED(glTexCoord4d), GLFUNC_ALWAYS_REQUIRED(glTexCoord4f), + GLFUNC_ALWAYS_REQUIRED(glTexCoord4i), GLFUNC_ALWAYS_REQUIRED(glTexCoord4s), + GLFUNC_ALWAYS_REQUIRED(glTexCoord1dv), GLFUNC_ALWAYS_REQUIRED(glTexCoord1fv), + GLFUNC_ALWAYS_REQUIRED(glTexCoord1iv), GLFUNC_ALWAYS_REQUIRED(glTexCoord1sv), + GLFUNC_ALWAYS_REQUIRED(glTexCoord2dv), GLFUNC_ALWAYS_REQUIRED(glTexCoord2fv), + GLFUNC_ALWAYS_REQUIRED(glTexCoord2iv), GLFUNC_ALWAYS_REQUIRED(glTexCoord2sv), + GLFUNC_ALWAYS_REQUIRED(glTexCoord3dv), GLFUNC_ALWAYS_REQUIRED(glTexCoord3fv), + GLFUNC_ALWAYS_REQUIRED(glTexCoord3iv), GLFUNC_ALWAYS_REQUIRED(glTexCoord3sv), + GLFUNC_ALWAYS_REQUIRED(glTexCoord4dv), GLFUNC_ALWAYS_REQUIRED(glTexCoord4fv), + GLFUNC_ALWAYS_REQUIRED(glTexCoord4iv), GLFUNC_ALWAYS_REQUIRED(glTexCoord4sv), + GLFUNC_ALWAYS_REQUIRED(glRasterPos2d), GLFUNC_ALWAYS_REQUIRED(glRasterPos2f), + GLFUNC_ALWAYS_REQUIRED(glRasterPos2i), GLFUNC_ALWAYS_REQUIRED(glRasterPos2s), + GLFUNC_ALWAYS_REQUIRED(glRasterPos3d), GLFUNC_ALWAYS_REQUIRED(glRasterPos3f), + GLFUNC_ALWAYS_REQUIRED(glRasterPos3i), GLFUNC_ALWAYS_REQUIRED(glRasterPos3s), + GLFUNC_ALWAYS_REQUIRED(glRasterPos4d), GLFUNC_ALWAYS_REQUIRED(glRasterPos4f), + GLFUNC_ALWAYS_REQUIRED(glRasterPos4i), GLFUNC_ALWAYS_REQUIRED(glRasterPos4s), + GLFUNC_ALWAYS_REQUIRED(glRasterPos2dv), GLFUNC_ALWAYS_REQUIRED(glRasterPos2fv), + GLFUNC_ALWAYS_REQUIRED(glRasterPos2iv), GLFUNC_ALWAYS_REQUIRED(glRasterPos2sv), + GLFUNC_ALWAYS_REQUIRED(glRasterPos3dv), GLFUNC_ALWAYS_REQUIRED(glRasterPos3fv), + GLFUNC_ALWAYS_REQUIRED(glRasterPos3iv), GLFUNC_ALWAYS_REQUIRED(glRasterPos3sv), + GLFUNC_ALWAYS_REQUIRED(glRasterPos4dv), GLFUNC_ALWAYS_REQUIRED(glRasterPos4fv), + GLFUNC_ALWAYS_REQUIRED(glRasterPos4iv), GLFUNC_ALWAYS_REQUIRED(glRasterPos4sv), + GLFUNC_ALWAYS_REQUIRED(glRectd), GLFUNC_ALWAYS_REQUIRED(glRectf), + GLFUNC_ALWAYS_REQUIRED(glRecti), GLFUNC_ALWAYS_REQUIRED(glRects), + GLFUNC_ALWAYS_REQUIRED(glRectdv), GLFUNC_ALWAYS_REQUIRED(glRectfv), + GLFUNC_ALWAYS_REQUIRED(glRectiv), GLFUNC_ALWAYS_REQUIRED(glRectsv), + GLFUNC_ALWAYS_REQUIRED(glVertexPointer), GLFUNC_ALWAYS_REQUIRED(glNormalPointer), + GLFUNC_ALWAYS_REQUIRED(glColorPointer), GLFUNC_ALWAYS_REQUIRED(glIndexPointer), + GLFUNC_ALWAYS_REQUIRED(glTexCoordPointer), GLFUNC_ALWAYS_REQUIRED(glEdgeFlagPointer), + GLFUNC_ALWAYS_REQUIRED(glArrayElement), GLFUNC_ALWAYS_REQUIRED(glInterleavedArrays), + GLFUNC_ALWAYS_REQUIRED(glShadeModel), GLFUNC_ALWAYS_REQUIRED(glLightf), + GLFUNC_ALWAYS_REQUIRED(glLighti), GLFUNC_ALWAYS_REQUIRED(glLightfv), + GLFUNC_ALWAYS_REQUIRED(glLightiv), GLFUNC_ALWAYS_REQUIRED(glGetLightfv), + GLFUNC_ALWAYS_REQUIRED(glGetLightiv), GLFUNC_ALWAYS_REQUIRED(glLightModelf), + GLFUNC_ALWAYS_REQUIRED(glLightModeli), GLFUNC_ALWAYS_REQUIRED(glLightModelfv), + GLFUNC_ALWAYS_REQUIRED(glLightModeliv), GLFUNC_ALWAYS_REQUIRED(glMaterialf), + GLFUNC_ALWAYS_REQUIRED(glMateriali), GLFUNC_ALWAYS_REQUIRED(glMaterialfv), + GLFUNC_ALWAYS_REQUIRED(glMaterialiv), GLFUNC_ALWAYS_REQUIRED(glGetMaterialfv), + GLFUNC_ALWAYS_REQUIRED(glGetMaterialiv), GLFUNC_ALWAYS_REQUIRED(glColorMaterial), + GLFUNC_ALWAYS_REQUIRED(glPixelZoom), GLFUNC_ALWAYS_REQUIRED(glPixelStoref), + GLFUNC_ALWAYS_REQUIRED(glPixelTransferf), GLFUNC_ALWAYS_REQUIRED(glPixelTransferi), + GLFUNC_ALWAYS_REQUIRED(glPixelMapfv), GLFUNC_ALWAYS_REQUIRED(glPixelMapuiv), + GLFUNC_ALWAYS_REQUIRED(glPixelMapusv), GLFUNC_ALWAYS_REQUIRED(glGetPixelMapfv), + GLFUNC_ALWAYS_REQUIRED(glGetPixelMapuiv), GLFUNC_ALWAYS_REQUIRED(glGetPixelMapusv), + GLFUNC_ALWAYS_REQUIRED(glBitmap), GLFUNC_ALWAYS_REQUIRED(glDrawPixels), + GLFUNC_ALWAYS_REQUIRED(glCopyPixels), GLFUNC_ALWAYS_REQUIRED(glTexGend), + GLFUNC_ALWAYS_REQUIRED(glTexGenf), GLFUNC_ALWAYS_REQUIRED(glTexGeni), + GLFUNC_ALWAYS_REQUIRED(glTexGendv), GLFUNC_ALWAYS_REQUIRED(glTexGenfv), + GLFUNC_ALWAYS_REQUIRED(glTexGeniv), GLFUNC_ALWAYS_REQUIRED(glGetTexGendv), + GLFUNC_ALWAYS_REQUIRED(glGetTexGenfv), GLFUNC_ALWAYS_REQUIRED(glGetTexGeniv), + GLFUNC_ALWAYS_REQUIRED(glTexEnvf), GLFUNC_ALWAYS_REQUIRED(glTexEnvi), + GLFUNC_ALWAYS_REQUIRED(glTexEnvfv), GLFUNC_ALWAYS_REQUIRED(glTexEnviv), + GLFUNC_ALWAYS_REQUIRED(glGetTexEnvfv), GLFUNC_ALWAYS_REQUIRED(glGetTexEnviv), + GLFUNC_ALWAYS_REQUIRED(glGetTexLevelParameterfv), + GLFUNC_ALWAYS_REQUIRED(glGetTexLevelParameteriv), GLFUNC_ALWAYS_REQUIRED(glTexImage1D), + GLFUNC_ALWAYS_REQUIRED(glGetTexImage), GLFUNC_ALWAYS_REQUIRED(glPrioritizeTextures), + GLFUNC_ALWAYS_REQUIRED(glAreTexturesResident), GLFUNC_ALWAYS_REQUIRED(glTexSubImage1D), + GLFUNC_ALWAYS_REQUIRED(glCopyTexImage1D), GLFUNC_ALWAYS_REQUIRED(glCopyTexSubImage1D), + GLFUNC_ALWAYS_REQUIRED(glMap1d), GLFUNC_ALWAYS_REQUIRED(glMap1f), + GLFUNC_ALWAYS_REQUIRED(glMap2d), GLFUNC_ALWAYS_REQUIRED(glMap2f), + GLFUNC_ALWAYS_REQUIRED(glGetMapdv), GLFUNC_ALWAYS_REQUIRED(glGetMapfv), + GLFUNC_ALWAYS_REQUIRED(glGetMapiv), GLFUNC_ALWAYS_REQUIRED(glEvalCoord1d), + GLFUNC_ALWAYS_REQUIRED(glEvalCoord1f), GLFUNC_ALWAYS_REQUIRED(glEvalCoord1dv), + GLFUNC_ALWAYS_REQUIRED(glEvalCoord1fv), GLFUNC_ALWAYS_REQUIRED(glEvalCoord2d), + GLFUNC_ALWAYS_REQUIRED(glEvalCoord2f), GLFUNC_ALWAYS_REQUIRED(glEvalCoord2dv), + GLFUNC_ALWAYS_REQUIRED(glEvalCoord2fv), GLFUNC_ALWAYS_REQUIRED(glMapGrid1d), + GLFUNC_ALWAYS_REQUIRED(glMapGrid1f), GLFUNC_ALWAYS_REQUIRED(glMapGrid2d), + GLFUNC_ALWAYS_REQUIRED(glMapGrid2f), GLFUNC_ALWAYS_REQUIRED(glEvalPoint1), + GLFUNC_ALWAYS_REQUIRED(glEvalPoint2), GLFUNC_ALWAYS_REQUIRED(glEvalMesh1), + GLFUNC_ALWAYS_REQUIRED(glEvalMesh2), GLFUNC_ALWAYS_REQUIRED(glFogf), + GLFUNC_ALWAYS_REQUIRED(glFogi), GLFUNC_ALWAYS_REQUIRED(glFogfv), + GLFUNC_ALWAYS_REQUIRED(glFogiv), GLFUNC_ALWAYS_REQUIRED(glFeedbackBuffer), + GLFUNC_ALWAYS_REQUIRED(glPassThrough), GLFUNC_ALWAYS_REQUIRED(glSelectBuffer), + GLFUNC_ALWAYS_REQUIRED(glInitNames), GLFUNC_ALWAYS_REQUIRED(glLoadName), + GLFUNC_ALWAYS_REQUIRED(glPushName), GLFUNC_ALWAYS_REQUIRED(glPopName), + GL_ES_FUNC_ALWAYS_REQUIRED(glTexImage2D), GL_ES_FUNC_ALWAYS_REQUIRED(glClearColor), + GL_ES_FUNC_ALWAYS_REQUIRED(glClear), GL_ES_FUNC_ALWAYS_REQUIRED(glColorMask), + GL_ES_FUNC_ALWAYS_REQUIRED(glBlendFunc), GL_ES_FUNC_ALWAYS_REQUIRED(glCullFace), + GL_ES_FUNC_ALWAYS_REQUIRED(glFrontFace), GL_ES_FUNC_ALWAYS_REQUIRED(glLineWidth), + GL_ES_FUNC_ALWAYS_REQUIRED(glPolygonOffset), GL_ES_FUNC_ALWAYS_REQUIRED(glScissor), + GL_ES_FUNC_ALWAYS_REQUIRED(glEnable), GL_ES_FUNC_ALWAYS_REQUIRED(glDisable), + GL_ES_FUNC_ALWAYS_REQUIRED(glIsEnabled), GL_ES_FUNC_ALWAYS_REQUIRED(glGetBooleanv), + GL_ES_FUNC_ALWAYS_REQUIRED(glGetFloatv), GL_ES_FUNC_ALWAYS_REQUIRED(glFinish), + GL_ES_FUNC_ALWAYS_REQUIRED(glFlush), GL_ES_FUNC_ALWAYS_REQUIRED(glHint), + GL_ES_FUNC_ALWAYS_REQUIRED(glDepthFunc), GL_ES_FUNC_ALWAYS_REQUIRED(glDepthMask), + GL_ES_FUNC_ALWAYS_REQUIRED(glViewport), GL_ES_FUNC_ALWAYS_REQUIRED(glDrawArrays), + GL_ES_FUNC_ALWAYS_REQUIRED(glDrawElements), GL_ES_FUNC_ALWAYS_REQUIRED(glPixelStorei), + GL_ES_FUNC_ALWAYS_REQUIRED(glReadPixels), GL_ES_FUNC_ALWAYS_REQUIRED(glStencilFunc), + GL_ES_FUNC_ALWAYS_REQUIRED(glStencilMask), GL_ES_FUNC_ALWAYS_REQUIRED(glStencilOp), + GL_ES_FUNC_ALWAYS_REQUIRED(glClearStencil), GL_ES_FUNC_ALWAYS_REQUIRED(glTexParameterf), + GL_ES_FUNC_ALWAYS_REQUIRED(glTexParameteri), GL_ES_FUNC_ALWAYS_REQUIRED(glTexParameterfv), + GL_ES_FUNC_ALWAYS_REQUIRED(glTexParameteriv), GL_ES_FUNC_ALWAYS_REQUIRED(glGetTexParameterfv), + GL_ES_FUNC_ALWAYS_REQUIRED(glGetTexParameteriv), GL_ES_FUNC_ALWAYS_REQUIRED(glGenTextures), + GL_ES_FUNC_ALWAYS_REQUIRED(glDeleteTextures), GL_ES_FUNC_ALWAYS_REQUIRED(glBindTexture), + GL_ES_FUNC_ALWAYS_REQUIRED(glIsTexture), GL_ES_FUNC_ALWAYS_REQUIRED(glTexSubImage2D), + GL_ES_FUNC_ALWAYS_REQUIRED(glCopyTexImage2D), GL_ES_FUNC_ALWAYS_REQUIRED(glCopyTexSubImage2D), + GL_ES3_FUNC_ALWAYS_REQUIRED(glReadBuffer), GL_ES32_FUNC_ALWAYS_REQUIRED(glGetPointerv), - // gl_1_2 - GL_ES3_FUNC_ALWAYS_REQUIRED(glCopyTexSubImage3D), - GL_ES3_FUNC_ALWAYS_REQUIRED(glDrawRangeElements), - GL_ES3_FUNC_ALWAYS_REQUIRED(glTexImage3D), - GL_ES3_FUNC_ALWAYS_REQUIRED(glTexSubImage3D), + // gl_1_2 + GL_ES3_FUNC_ALWAYS_REQUIRED(glCopyTexSubImage3D), + GL_ES3_FUNC_ALWAYS_REQUIRED(glDrawRangeElements), GL_ES3_FUNC_ALWAYS_REQUIRED(glTexImage3D), + GL_ES3_FUNC_ALWAYS_REQUIRED(glTexSubImage3D), - // gl_1_3 - GLFUNC_ALWAYS_REQUIRED(glClientActiveTexture), - GLFUNC_ALWAYS_REQUIRED(glCompressedTexImage1D), - GLFUNC_ALWAYS_REQUIRED(glCompressedTexSubImage1D), - GLFUNC_ALWAYS_REQUIRED(glGetCompressedTexImage), - GLFUNC_ALWAYS_REQUIRED(glLoadTransposeMatrixd), - GLFUNC_ALWAYS_REQUIRED(glLoadTransposeMatrixf), - GLFUNC_ALWAYS_REQUIRED(glMultTransposeMatrixd), - GLFUNC_ALWAYS_REQUIRED(glMultTransposeMatrixf), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1d), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1dv), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1f), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1fv), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1i), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1iv), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1s), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1sv), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2d), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2dv), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2f), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2fv), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2i), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2iv), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2s), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2sv), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3d), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3dv), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3f), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3fv), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3i), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3iv), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3s), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3sv), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4d), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4dv), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4f), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4fv), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4i), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4iv), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4s), - GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4sv), - GL_ES_FUNC_ALWAYS_REQUIRED(glSampleCoverage), - GL_ES_FUNC_ALWAYS_REQUIRED(glActiveTexture), - GL_ES_FUNC_ALWAYS_REQUIRED(glCompressedTexImage2D), - GL_ES_FUNC_ALWAYS_REQUIRED(glCompressedTexSubImage2D), - GL_ES3_FUNC_ALWAYS_REQUIRED(glCompressedTexImage3D), - GL_ES3_FUNC_ALWAYS_REQUIRED(glCompressedTexSubImage3D), + // gl_1_3 + GLFUNC_ALWAYS_REQUIRED(glClientActiveTexture), GLFUNC_ALWAYS_REQUIRED(glCompressedTexImage1D), + GLFUNC_ALWAYS_REQUIRED(glCompressedTexSubImage1D), + GLFUNC_ALWAYS_REQUIRED(glGetCompressedTexImage), GLFUNC_ALWAYS_REQUIRED(glLoadTransposeMatrixd), + GLFUNC_ALWAYS_REQUIRED(glLoadTransposeMatrixf), GLFUNC_ALWAYS_REQUIRED(glMultTransposeMatrixd), + GLFUNC_ALWAYS_REQUIRED(glMultTransposeMatrixf), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1d), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1dv), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1f), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1fv), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1i), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1iv), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1s), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1sv), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2d), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2dv), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2f), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2fv), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2i), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2iv), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2s), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2sv), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3d), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3dv), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3f), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3fv), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3i), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3iv), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3s), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3sv), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4d), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4dv), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4f), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4fv), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4i), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4iv), GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4s), + GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4sv), GL_ES_FUNC_ALWAYS_REQUIRED(glSampleCoverage), + GL_ES_FUNC_ALWAYS_REQUIRED(glActiveTexture), GL_ES_FUNC_ALWAYS_REQUIRED(glCompressedTexImage2D), + GL_ES_FUNC_ALWAYS_REQUIRED(glCompressedTexSubImage2D), + GL_ES3_FUNC_ALWAYS_REQUIRED(glCompressedTexImage3D), + GL_ES3_FUNC_ALWAYS_REQUIRED(glCompressedTexSubImage3D), - // gl_1_4 - GLFUNC_ALWAYS_REQUIRED(glFogCoordPointer), - GLFUNC_ALWAYS_REQUIRED(glFogCoordd), - GLFUNC_ALWAYS_REQUIRED(glFogCoorddv), - GLFUNC_ALWAYS_REQUIRED(glFogCoordf), - GLFUNC_ALWAYS_REQUIRED(glFogCoordfv), - GLFUNC_ALWAYS_REQUIRED(glMultiDrawArrays), - GLFUNC_ALWAYS_REQUIRED(glMultiDrawElements), - GLFUNC_ALWAYS_REQUIRED(glPointParameterf), - GLFUNC_ALWAYS_REQUIRED(glPointParameterfv), - GLFUNC_ALWAYS_REQUIRED(glPointParameteri), - GLFUNC_ALWAYS_REQUIRED(glPointParameteriv), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3b), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3bv), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3d), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3dv), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3f), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3fv), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3i), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3iv), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3s), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3sv), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3ub), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3ubv), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3ui), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3uiv), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3us), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3usv), - GLFUNC_ALWAYS_REQUIRED(glSecondaryColorPointer), - GLFUNC_ALWAYS_REQUIRED(glWindowPos2d), - GLFUNC_ALWAYS_REQUIRED(glWindowPos2dv), - GLFUNC_ALWAYS_REQUIRED(glWindowPos2f), - GLFUNC_ALWAYS_REQUIRED(glWindowPos2fv), - GLFUNC_ALWAYS_REQUIRED(glWindowPos2i), - GLFUNC_ALWAYS_REQUIRED(glWindowPos2iv), - GLFUNC_ALWAYS_REQUIRED(glWindowPos2s), - GLFUNC_ALWAYS_REQUIRED(glWindowPos2sv), - GLFUNC_ALWAYS_REQUIRED(glWindowPos3d), - GLFUNC_ALWAYS_REQUIRED(glWindowPos3dv), - GLFUNC_ALWAYS_REQUIRED(glWindowPos3f), - GLFUNC_ALWAYS_REQUIRED(glWindowPos3fv), - GLFUNC_ALWAYS_REQUIRED(glWindowPos3i), - GLFUNC_ALWAYS_REQUIRED(glWindowPos3iv), - GLFUNC_ALWAYS_REQUIRED(glWindowPos3s), - GLFUNC_ALWAYS_REQUIRED(glWindowPos3sv), - GL_ES_FUNC_ALWAYS_REQUIRED(glBlendColor), - GL_ES_FUNC_ALWAYS_REQUIRED(glBlendEquation), - GL_ES_FUNC_ALWAYS_REQUIRED(glBlendFuncSeparate), + // gl_1_4 + GLFUNC_ALWAYS_REQUIRED(glFogCoordPointer), GLFUNC_ALWAYS_REQUIRED(glFogCoordd), + GLFUNC_ALWAYS_REQUIRED(glFogCoorddv), GLFUNC_ALWAYS_REQUIRED(glFogCoordf), + GLFUNC_ALWAYS_REQUIRED(glFogCoordfv), GLFUNC_ALWAYS_REQUIRED(glMultiDrawArrays), + GLFUNC_ALWAYS_REQUIRED(glMultiDrawElements), GLFUNC_ALWAYS_REQUIRED(glPointParameterf), + GLFUNC_ALWAYS_REQUIRED(glPointParameterfv), GLFUNC_ALWAYS_REQUIRED(glPointParameteri), + GLFUNC_ALWAYS_REQUIRED(glPointParameteriv), GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3b), + GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3bv), GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3d), + GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3dv), GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3f), + GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3fv), GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3i), + GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3iv), GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3s), + GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3sv), GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3ub), + GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3ubv), GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3ui), + GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3uiv), GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3us), + GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3usv), GLFUNC_ALWAYS_REQUIRED(glSecondaryColorPointer), + GLFUNC_ALWAYS_REQUIRED(glWindowPos2d), GLFUNC_ALWAYS_REQUIRED(glWindowPos2dv), + GLFUNC_ALWAYS_REQUIRED(glWindowPos2f), GLFUNC_ALWAYS_REQUIRED(glWindowPos2fv), + GLFUNC_ALWAYS_REQUIRED(glWindowPos2i), GLFUNC_ALWAYS_REQUIRED(glWindowPos2iv), + GLFUNC_ALWAYS_REQUIRED(glWindowPos2s), GLFUNC_ALWAYS_REQUIRED(glWindowPos2sv), + GLFUNC_ALWAYS_REQUIRED(glWindowPos3d), GLFUNC_ALWAYS_REQUIRED(glWindowPos3dv), + GLFUNC_ALWAYS_REQUIRED(glWindowPos3f), GLFUNC_ALWAYS_REQUIRED(glWindowPos3fv), + GLFUNC_ALWAYS_REQUIRED(glWindowPos3i), GLFUNC_ALWAYS_REQUIRED(glWindowPos3iv), + GLFUNC_ALWAYS_REQUIRED(glWindowPos3s), GLFUNC_ALWAYS_REQUIRED(glWindowPos3sv), + GL_ES_FUNC_ALWAYS_REQUIRED(glBlendColor), GL_ES_FUNC_ALWAYS_REQUIRED(glBlendEquation), + GL_ES_FUNC_ALWAYS_REQUIRED(glBlendFuncSeparate), - // gl_1_5 - GLFUNC_ALWAYS_REQUIRED(glGetBufferSubData), - GLFUNC_ALWAYS_REQUIRED(glGetQueryObjectiv), - GLFUNC_ALWAYS_REQUIRED(glMapBuffer), - GL_ES_FUNC_ALWAYS_REQUIRED(glBindBuffer), - GL_ES_FUNC_ALWAYS_REQUIRED(glBufferData), - GL_ES_FUNC_ALWAYS_REQUIRED(glBufferSubData), - GL_ES_FUNC_ALWAYS_REQUIRED(glDeleteBuffers), - GL_ES_FUNC_ALWAYS_REQUIRED(glGenBuffers), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetBufferParameteriv), - GL_ES_FUNC_ALWAYS_REQUIRED(glIsBuffer), - GL_ES3_FUNC_ALWAYS_REQUIRED(glBeginQuery), - GL_ES3_FUNC_ALWAYS_REQUIRED(glDeleteQueries), - GL_ES3_FUNC_ALWAYS_REQUIRED(glEndQuery), - GL_ES3_FUNC_ALWAYS_REQUIRED(glGenQueries), - GL_ES3_FUNC_ALWAYS_REQUIRED(glIsQuery), - GL_ES3_FUNC_ALWAYS_REQUIRED(glGetQueryiv), - GL_ES3_FUNC_ALWAYS_REQUIRED(glGetQueryObjectuiv), - GL_ES3_FUNC_ALWAYS_REQUIRED(glGetBufferPointerv), - GL_ES3_FUNC_ALWAYS_REQUIRED(glUnmapBuffer), + // gl_1_5 + GLFUNC_ALWAYS_REQUIRED(glGetBufferSubData), GLFUNC_ALWAYS_REQUIRED(glGetQueryObjectiv), + GLFUNC_ALWAYS_REQUIRED(glMapBuffer), GL_ES_FUNC_ALWAYS_REQUIRED(glBindBuffer), + GL_ES_FUNC_ALWAYS_REQUIRED(glBufferData), GL_ES_FUNC_ALWAYS_REQUIRED(glBufferSubData), + GL_ES_FUNC_ALWAYS_REQUIRED(glDeleteBuffers), GL_ES_FUNC_ALWAYS_REQUIRED(glGenBuffers), + GL_ES_FUNC_ALWAYS_REQUIRED(glGetBufferParameteriv), GL_ES_FUNC_ALWAYS_REQUIRED(glIsBuffer), + GL_ES3_FUNC_ALWAYS_REQUIRED(glBeginQuery), GL_ES3_FUNC_ALWAYS_REQUIRED(glDeleteQueries), + GL_ES3_FUNC_ALWAYS_REQUIRED(glEndQuery), GL_ES3_FUNC_ALWAYS_REQUIRED(glGenQueries), + GL_ES3_FUNC_ALWAYS_REQUIRED(glIsQuery), GL_ES3_FUNC_ALWAYS_REQUIRED(glGetQueryiv), + GL_ES3_FUNC_ALWAYS_REQUIRED(glGetQueryObjectuiv), + GL_ES3_FUNC_ALWAYS_REQUIRED(glGetBufferPointerv), GL_ES3_FUNC_ALWAYS_REQUIRED(glUnmapBuffer), - // gl_2_0 - GLFUNC_ALWAYS_REQUIRED(glGetVertexAttribdv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib1d), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib1dv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib1s), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib1sv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib2d), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib2dv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib2s), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib2sv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib3d), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib3dv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib3s), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib3sv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nbv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Niv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nsv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nub), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nubv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nuiv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nusv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4bv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4d), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4dv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4iv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4s), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4sv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4ubv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4uiv), - GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4usv), - GL_ES_FUNC_ALWAYS_REQUIRED(glAttachShader), - GL_ES_FUNC_ALWAYS_REQUIRED(glBindAttribLocation), - GL_ES_FUNC_ALWAYS_REQUIRED(glBlendEquationSeparate), - GL_ES_FUNC_ALWAYS_REQUIRED(glCompileShader), - GL_ES_FUNC_ALWAYS_REQUIRED(glCreateProgram), - GL_ES_FUNC_ALWAYS_REQUIRED(glCreateShader), - GL_ES_FUNC_ALWAYS_REQUIRED(glDeleteProgram), - GL_ES_FUNC_ALWAYS_REQUIRED(glDeleteShader), - GL_ES_FUNC_ALWAYS_REQUIRED(glDetachShader), - GL_ES_FUNC_ALWAYS_REQUIRED(glDisableVertexAttribArray), - GL_ES_FUNC_ALWAYS_REQUIRED(glEnableVertexAttribArray), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetActiveAttrib), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetActiveUniform), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetAttachedShaders), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetAttribLocation), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetProgramInfoLog), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetProgramiv), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetShaderInfoLog), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetShaderSource), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetShaderiv), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetUniformLocation), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetUniformfv), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetUniformiv), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetVertexAttribPointerv), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetVertexAttribfv), - GL_ES_FUNC_ALWAYS_REQUIRED(glGetVertexAttribiv), - GL_ES_FUNC_ALWAYS_REQUIRED(glIsProgram), - GL_ES_FUNC_ALWAYS_REQUIRED(glIsShader), - GL_ES_FUNC_ALWAYS_REQUIRED(glLinkProgram), - GL_ES_FUNC_ALWAYS_REQUIRED(glShaderSource), - GL_ES_FUNC_ALWAYS_REQUIRED(glStencilFuncSeparate), - GL_ES_FUNC_ALWAYS_REQUIRED(glStencilMaskSeparate), - GL_ES_FUNC_ALWAYS_REQUIRED(glStencilOpSeparate), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform1f), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform1fv), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform1i), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform1iv), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform2f), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform2fv), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform2i), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform2iv), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform3f), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform3fv), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform3i), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform3iv), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform4f), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform4fv), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform4i), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniform4iv), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniformMatrix2fv), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniformMatrix3fv), - GL_ES_FUNC_ALWAYS_REQUIRED(glUniformMatrix4fv), - GL_ES_FUNC_ALWAYS_REQUIRED(glUseProgram), - GL_ES_FUNC_ALWAYS_REQUIRED(glValidateProgram), - GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib1f), - GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib1fv), - GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib2f), - GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib2fv), - GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib3f), - GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib3fv), - GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib4f), - GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib4fv), - GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttribPointer), - GL_ES3_FUNC_ALWAYS_REQUIRED(glDrawBuffers), + // gl_2_0 + GLFUNC_ALWAYS_REQUIRED(glGetVertexAttribdv), GLFUNC_ALWAYS_REQUIRED(glVertexAttrib1d), + GLFUNC_ALWAYS_REQUIRED(glVertexAttrib1dv), GLFUNC_ALWAYS_REQUIRED(glVertexAttrib1s), + GLFUNC_ALWAYS_REQUIRED(glVertexAttrib1sv), GLFUNC_ALWAYS_REQUIRED(glVertexAttrib2d), + GLFUNC_ALWAYS_REQUIRED(glVertexAttrib2dv), GLFUNC_ALWAYS_REQUIRED(glVertexAttrib2s), + GLFUNC_ALWAYS_REQUIRED(glVertexAttrib2sv), GLFUNC_ALWAYS_REQUIRED(glVertexAttrib3d), + GLFUNC_ALWAYS_REQUIRED(glVertexAttrib3dv), GLFUNC_ALWAYS_REQUIRED(glVertexAttrib3s), + GLFUNC_ALWAYS_REQUIRED(glVertexAttrib3sv), GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nbv), + GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Niv), GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nsv), + GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nub), GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nubv), + GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nuiv), GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nusv), + GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4bv), GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4d), + GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4dv), GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4iv), + GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4s), GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4sv), + GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4ubv), GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4uiv), + GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4usv), GL_ES_FUNC_ALWAYS_REQUIRED(glAttachShader), + GL_ES_FUNC_ALWAYS_REQUIRED(glBindAttribLocation), + GL_ES_FUNC_ALWAYS_REQUIRED(glBlendEquationSeparate), + GL_ES_FUNC_ALWAYS_REQUIRED(glCompileShader), GL_ES_FUNC_ALWAYS_REQUIRED(glCreateProgram), + GL_ES_FUNC_ALWAYS_REQUIRED(glCreateShader), GL_ES_FUNC_ALWAYS_REQUIRED(glDeleteProgram), + GL_ES_FUNC_ALWAYS_REQUIRED(glDeleteShader), GL_ES_FUNC_ALWAYS_REQUIRED(glDetachShader), + GL_ES_FUNC_ALWAYS_REQUIRED(glDisableVertexAttribArray), + GL_ES_FUNC_ALWAYS_REQUIRED(glEnableVertexAttribArray), + GL_ES_FUNC_ALWAYS_REQUIRED(glGetActiveAttrib), GL_ES_FUNC_ALWAYS_REQUIRED(glGetActiveUniform), + GL_ES_FUNC_ALWAYS_REQUIRED(glGetAttachedShaders), + GL_ES_FUNC_ALWAYS_REQUIRED(glGetAttribLocation), + GL_ES_FUNC_ALWAYS_REQUIRED(glGetProgramInfoLog), GL_ES_FUNC_ALWAYS_REQUIRED(glGetProgramiv), + GL_ES_FUNC_ALWAYS_REQUIRED(glGetShaderInfoLog), GL_ES_FUNC_ALWAYS_REQUIRED(glGetShaderSource), + GL_ES_FUNC_ALWAYS_REQUIRED(glGetShaderiv), GL_ES_FUNC_ALWAYS_REQUIRED(glGetUniformLocation), + GL_ES_FUNC_ALWAYS_REQUIRED(glGetUniformfv), GL_ES_FUNC_ALWAYS_REQUIRED(glGetUniformiv), + GL_ES_FUNC_ALWAYS_REQUIRED(glGetVertexAttribPointerv), + GL_ES_FUNC_ALWAYS_REQUIRED(glGetVertexAttribfv), + GL_ES_FUNC_ALWAYS_REQUIRED(glGetVertexAttribiv), GL_ES_FUNC_ALWAYS_REQUIRED(glIsProgram), + GL_ES_FUNC_ALWAYS_REQUIRED(glIsShader), GL_ES_FUNC_ALWAYS_REQUIRED(glLinkProgram), + GL_ES_FUNC_ALWAYS_REQUIRED(glShaderSource), GL_ES_FUNC_ALWAYS_REQUIRED(glStencilFuncSeparate), + GL_ES_FUNC_ALWAYS_REQUIRED(glStencilMaskSeparate), + GL_ES_FUNC_ALWAYS_REQUIRED(glStencilOpSeparate), GL_ES_FUNC_ALWAYS_REQUIRED(glUniform1f), + GL_ES_FUNC_ALWAYS_REQUIRED(glUniform1fv), GL_ES_FUNC_ALWAYS_REQUIRED(glUniform1i), + GL_ES_FUNC_ALWAYS_REQUIRED(glUniform1iv), GL_ES_FUNC_ALWAYS_REQUIRED(glUniform2f), + GL_ES_FUNC_ALWAYS_REQUIRED(glUniform2fv), GL_ES_FUNC_ALWAYS_REQUIRED(glUniform2i), + GL_ES_FUNC_ALWAYS_REQUIRED(glUniform2iv), GL_ES_FUNC_ALWAYS_REQUIRED(glUniform3f), + GL_ES_FUNC_ALWAYS_REQUIRED(glUniform3fv), GL_ES_FUNC_ALWAYS_REQUIRED(glUniform3i), + GL_ES_FUNC_ALWAYS_REQUIRED(glUniform3iv), GL_ES_FUNC_ALWAYS_REQUIRED(glUniform4f), + GL_ES_FUNC_ALWAYS_REQUIRED(glUniform4fv), GL_ES_FUNC_ALWAYS_REQUIRED(glUniform4i), + GL_ES_FUNC_ALWAYS_REQUIRED(glUniform4iv), GL_ES_FUNC_ALWAYS_REQUIRED(glUniformMatrix2fv), + GL_ES_FUNC_ALWAYS_REQUIRED(glUniformMatrix3fv), GL_ES_FUNC_ALWAYS_REQUIRED(glUniformMatrix4fv), + GL_ES_FUNC_ALWAYS_REQUIRED(glUseProgram), GL_ES_FUNC_ALWAYS_REQUIRED(glValidateProgram), + GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib1f), GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib1fv), + GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib2f), GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib2fv), + GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib3f), GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib3fv), + GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib4f), GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttrib4fv), + GL_ES_FUNC_ALWAYS_REQUIRED(glVertexAttribPointer), GL_ES3_FUNC_ALWAYS_REQUIRED(glDrawBuffers), - // gl_2_1 - GLFUNC_ALWAYS_REQUIRED(glUniformMatrix2x3fv), - GLFUNC_ALWAYS_REQUIRED(glUniformMatrix2x4fv), - GLFUNC_ALWAYS_REQUIRED(glUniformMatrix3x2fv), - GLFUNC_ALWAYS_REQUIRED(glUniformMatrix3x4fv), - GLFUNC_ALWAYS_REQUIRED(glUniformMatrix4x2fv), - GLFUNC_ALWAYS_REQUIRED(glUniformMatrix4x3fv), + // gl_2_1 + GLFUNC_ALWAYS_REQUIRED(glUniformMatrix2x3fv), GLFUNC_ALWAYS_REQUIRED(glUniformMatrix2x4fv), + GLFUNC_ALWAYS_REQUIRED(glUniformMatrix3x2fv), GLFUNC_ALWAYS_REQUIRED(glUniformMatrix3x4fv), + GLFUNC_ALWAYS_REQUIRED(glUniformMatrix4x2fv), GLFUNC_ALWAYS_REQUIRED(glUniformMatrix4x3fv), - // gl_3_0 - GLFUNC_REQUIRES(glBeginConditionalRender, "VERSION_3_0"), - GLFUNC_REQUIRES(glBindFragDataLocation, "VERSION_3_0"), - GLFUNC_REQUIRES(glClampColor, "VERSION_3_0"), - GLFUNC_REQUIRES(glEndConditionalRender, "VERSION_3_0"), - GLFUNC_REQUIRES(glGetBooleani_v, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI1i, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI1iv, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI1ui, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI1uiv, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI2i, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI2iv, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI2ui, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI2uiv, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI3i, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI3iv, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI3ui, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI3uiv, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI4bv, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI4sv, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI4ubv, "VERSION_3_0"), - GLFUNC_REQUIRES(glVertexAttribI4usv, "VERSION_3_0"), - GLFUNC_REQUIRES(glBeginTransformFeedback, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glClearBufferfi, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glClearBufferfv, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glClearBufferiv, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glClearBufferuiv, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glEndTransformFeedback, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetFragDataLocation, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetStringi, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetTransformFeedbackVarying, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetUniformuiv, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetVertexAttribIiv, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetVertexAttribIuiv, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glTransformFeedbackVaryings, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glUniform1ui, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glUniform1uiv, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glUniform2ui, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glUniform2uiv, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glUniform3ui, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glUniform3uiv, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glUniform4ui, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glUniform4uiv, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glVertexAttribI4i, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glVertexAttribI4iv, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glVertexAttribI4ui, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glVertexAttribI4uiv, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glVertexAttribIPointer, "VERSION_3_0 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glColorMaski, "VERSION_3_0 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glDisablei, "VERSION_3_0 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glEnablei, "VERSION_3_0 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glGetTexParameterIiv, "VERSION_3_0 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glGetTexParameterIuiv, "VERSION_3_0 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glIsEnabledi, "VERSION_3_0 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glTexParameterIiv, "VERSION_3_0 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glTexParameterIuiv, "VERSION_3_0 |VERSION_GLES_3_2"), + // gl_3_0 + GLFUNC_REQUIRES(glBeginConditionalRender, "VERSION_3_0"), + GLFUNC_REQUIRES(glBindFragDataLocation, "VERSION_3_0"), + GLFUNC_REQUIRES(glClampColor, "VERSION_3_0"), + GLFUNC_REQUIRES(glEndConditionalRender, "VERSION_3_0"), + GLFUNC_REQUIRES(glGetBooleani_v, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI1i, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI1iv, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI1ui, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI1uiv, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI2i, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI2iv, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI2ui, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI2uiv, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI3i, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI3iv, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI3ui, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI3uiv, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI4bv, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI4sv, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI4ubv, "VERSION_3_0"), + GLFUNC_REQUIRES(glVertexAttribI4usv, "VERSION_3_0"), + GLFUNC_REQUIRES(glBeginTransformFeedback, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glClearBufferfi, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glClearBufferfv, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glClearBufferiv, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glClearBufferuiv, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glEndTransformFeedback, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetFragDataLocation, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetStringi, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetTransformFeedbackVarying, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetUniformuiv, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetVertexAttribIiv, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetVertexAttribIuiv, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glTransformFeedbackVaryings, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glUniform1ui, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glUniform1uiv, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glUniform2ui, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glUniform2uiv, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glUniform3ui, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glUniform3uiv, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glUniform4ui, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glUniform4uiv, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glVertexAttribI4i, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glVertexAttribI4iv, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glVertexAttribI4ui, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glVertexAttribI4uiv, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glVertexAttribIPointer, "VERSION_3_0 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glColorMaski, "VERSION_3_0 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glDisablei, "VERSION_3_0 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glEnablei, "VERSION_3_0 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glGetTexParameterIiv, "VERSION_3_0 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glGetTexParameterIuiv, "VERSION_3_0 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glIsEnabledi, "VERSION_3_0 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glTexParameterIiv, "VERSION_3_0 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glTexParameterIuiv, "VERSION_3_0 |VERSION_GLES_3_2"), + // gl_3_1 + GLFUNC_REQUIRES(glPrimitiveRestartIndex, "VERSION_3_1"), + GLFUNC_REQUIRES(glDrawArraysInstanced, "VERSION_3_1 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glDrawElementsInstanced, "VERSION_3_1 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glTexBuffer, "VERSION_3_1 |VERSION_GLES_3_2"), - // gl_3_1 - GLFUNC_REQUIRES(glPrimitiveRestartIndex, "VERSION_3_1"), - GLFUNC_REQUIRES(glDrawArraysInstanced, "VERSION_3_1 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glDrawElementsInstanced, "VERSION_3_1 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glTexBuffer, "VERSION_3_1 |VERSION_GLES_3_2"), + // gl_3_2 + GLFUNC_REQUIRES(glGetBufferParameteri64v, "VERSION_3_2 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetInteger64i_v, "VERSION_3_2 |VERSION_GLES_3"), + GLFUNC_REQUIRES(glFramebufferTexture, "VERSION_3_2 |VERSION_GLES_3_2"), - // gl_3_2 - GLFUNC_REQUIRES(glGetBufferParameteri64v, "VERSION_3_2 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetInteger64i_v, "VERSION_3_2 |VERSION_GLES_3"), - GLFUNC_REQUIRES(glFramebufferTexture, "VERSION_3_2 |VERSION_GLES_3_2"), + // gl_4_2 + GLFUNC_REQUIRES(glDrawArraysInstancedBaseInstance, "VERSION_4_2"), + GLFUNC_REQUIRES(glDrawElementsInstancedBaseInstance, "VERSION_4_2"), + GLFUNC_REQUIRES(glDrawElementsInstancedBaseVertexBaseInstance, "VERSION_4_2"), + GLFUNC_REQUIRES(glGetInternalformativ, "VERSION_4_2"), + GLFUNC_REQUIRES(glGetActiveAtomicCounterBufferiv, "VERSION_4_2"), + GLFUNC_REQUIRES(glBindImageTexture, "VERSION_4_2"), + GLFUNC_REQUIRES(glMemoryBarrier, "VERSION_4_2"), GLFUNC_REQUIRES(glTexStorage1D, "VERSION_4_2"), + GLFUNC_REQUIRES(glTexStorage2D, "VERSION_4_2"), GLFUNC_REQUIRES(glTexStorage3D, "VERSION_4_2"), + GLFUNC_REQUIRES(glDrawTransformFeedbackInstanced, "VERSION_4_2"), + GLFUNC_REQUIRES(glDrawTransformFeedbackStreamInstanced, "VERSION_4_2"), - // gl_4_2 - GLFUNC_REQUIRES(glDrawArraysInstancedBaseInstance, "VERSION_4_2"), - GLFUNC_REQUIRES(glDrawElementsInstancedBaseInstance, "VERSION_4_2"), - GLFUNC_REQUIRES(glDrawElementsInstancedBaseVertexBaseInstance, "VERSION_4_2"), - GLFUNC_REQUIRES(glGetInternalformativ, "VERSION_4_2"), - GLFUNC_REQUIRES(glGetActiveAtomicCounterBufferiv, "VERSION_4_2"), - GLFUNC_REQUIRES(glBindImageTexture, "VERSION_4_2"), - GLFUNC_REQUIRES(glMemoryBarrier, "VERSION_4_2"), - GLFUNC_REQUIRES(glTexStorage1D, "VERSION_4_2"), - GLFUNC_REQUIRES(glTexStorage2D, "VERSION_4_2"), - GLFUNC_REQUIRES(glTexStorage3D, "VERSION_4_2"), - GLFUNC_REQUIRES(glDrawTransformFeedbackInstanced, "VERSION_4_2"), - GLFUNC_REQUIRES(glDrawTransformFeedbackStreamInstanced, "VERSION_4_2"), + // gl_4_3 + GLFUNC_REQUIRES(glClearBufferData, "VERSION_4_3"), + GLFUNC_REQUIRES(glClearBufferSubData, "VERSION_4_3"), + GLFUNC_REQUIRES(glDispatchCompute, "VERSION_4_3"), + GLFUNC_REQUIRES(glDispatchComputeIndirect, "VERSION_4_3"), + GLFUNC_REQUIRES(glCopyImageSubData, "VERSION_4_3"), + GLFUNC_REQUIRES(glFramebufferParameteri, "VERSION_4_3"), + GLFUNC_REQUIRES(glGetFramebufferParameteriv, "VERSION_4_3"), + GLFUNC_REQUIRES(glGetInternalformati64v, "VERSION_4_3"), + GLFUNC_REQUIRES(glInvalidateTexSubImage, "VERSION_4_3"), + GLFUNC_REQUIRES(glInvalidateTexImage, "VERSION_4_3"), + GLFUNC_REQUIRES(glInvalidateBufferSubData, "VERSION_4_3"), + GLFUNC_REQUIRES(glInvalidateBufferData, "VERSION_4_3"), + GLFUNC_REQUIRES(glInvalidateFramebuffer, "VERSION_4_3"), + GLFUNC_REQUIRES(glInvalidateSubFramebuffer, "VERSION_4_3"), + GLFUNC_REQUIRES(glMultiDrawArraysIndirect, "VERSION_4_3"), + GLFUNC_REQUIRES(glMultiDrawElementsIndirect, "VERSION_4_3"), + GLFUNC_REQUIRES(glGetProgramInterfaceiv, "VERSION_4_3"), + GLFUNC_REQUIRES(glGetProgramResourceIndex, "VERSION_4_3"), + GLFUNC_REQUIRES(glGetProgramResourceName, "VERSION_4_3"), + GLFUNC_REQUIRES(glGetProgramResourceiv, "VERSION_4_3"), + GLFUNC_REQUIRES(glGetProgramResourceLocation, "VERSION_4_3"), + GLFUNC_REQUIRES(glGetProgramResourceLocationIndex, "VERSION_4_3"), + GLFUNC_REQUIRES(glShaderStorageBlockBinding, "VERSION_4_3"), + GLFUNC_REQUIRES(glTexBufferRange, "VERSION_4_3"), + GLFUNC_REQUIRES(glTexStorage2DMultisample, "VERSION_4_3"), + GLFUNC_REQUIRES(glTexStorage3DMultisample, "VERSION_4_3"), + GLFUNC_REQUIRES(glTextureView, "VERSION_4_3"), + GLFUNC_REQUIRES(glBindVertexBuffer, "VERSION_4_3"), + GLFUNC_REQUIRES(glVertexAttribFormat, "VERSION_4_3"), + GLFUNC_REQUIRES(glVertexAttribIFormat, "VERSION_4_3"), + GLFUNC_REQUIRES(glVertexAttribLFormat, "VERSION_4_3"), + GLFUNC_REQUIRES(glVertexAttribBinding, "VERSION_4_3"), + GLFUNC_REQUIRES(glVertexBindingDivisor, "VERSION_4_3"), + GLFUNC_REQUIRES(glDebugMessageControl, "VERSION_4_3"), + GLFUNC_REQUIRES(glDebugMessageInsert, "VERSION_4_3"), + GLFUNC_REQUIRES(glDebugMessageCallback, "VERSION_4_3"), + GLFUNC_REQUIRES(glGetDebugMessageLog, "VERSION_4_3"), + GLFUNC_REQUIRES(glPushDebugGroup, "VERSION_4_3"), + GLFUNC_REQUIRES(glPopDebugGroup, "VERSION_4_3"), GLFUNC_REQUIRES(glObjectLabel, "VERSION_4_3"), + GLFUNC_REQUIRES(glGetObjectLabel, "VERSION_4_3"), + GLFUNC_REQUIRES(glObjectPtrLabel, "VERSION_4_3"), + GLFUNC_REQUIRES(glGetObjectPtrLabel, "VERSION_4_3"), + // gl_4_4 + GLFUNC_REQUIRES(glBufferStorage, "VERSION_4_4"), + GLFUNC_REQUIRES(glClearTexImage, "VERSION_4_4"), + GLFUNC_REQUIRES(glClearTexSubImage, "VERSION_4_4"), + GLFUNC_REQUIRES(glBindBuffersBase, "VERSION_4_4"), + GLFUNC_REQUIRES(glBindBuffersRange, "VERSION_4_4"), + GLFUNC_REQUIRES(glBindTextures, "VERSION_4_4"), GLFUNC_REQUIRES(glBindSamplers, "VERSION_4_4"), + GLFUNC_REQUIRES(glBindImageTextures, "VERSION_4_4"), + GLFUNC_REQUIRES(glBindVertexBuffers, "VERSION_4_4"), - // gl_4_3 - GLFUNC_REQUIRES(glClearBufferData, "VERSION_4_3"), - GLFUNC_REQUIRES(glClearBufferSubData, "VERSION_4_3"), - GLFUNC_REQUIRES(glDispatchCompute, "VERSION_4_3"), - GLFUNC_REQUIRES(glDispatchComputeIndirect, "VERSION_4_3"), - GLFUNC_REQUIRES(glCopyImageSubData, "VERSION_4_3"), - GLFUNC_REQUIRES(glFramebufferParameteri, "VERSION_4_3"), - GLFUNC_REQUIRES(glGetFramebufferParameteriv, "VERSION_4_3"), - GLFUNC_REQUIRES(glGetInternalformati64v, "VERSION_4_3"), - GLFUNC_REQUIRES(glInvalidateTexSubImage, "VERSION_4_3"), - GLFUNC_REQUIRES(glInvalidateTexImage, "VERSION_4_3"), - GLFUNC_REQUIRES(glInvalidateBufferSubData, "VERSION_4_3"), - GLFUNC_REQUIRES(glInvalidateBufferData, "VERSION_4_3"), - GLFUNC_REQUIRES(glInvalidateFramebuffer, "VERSION_4_3"), - GLFUNC_REQUIRES(glInvalidateSubFramebuffer, "VERSION_4_3"), - GLFUNC_REQUIRES(glMultiDrawArraysIndirect, "VERSION_4_3"), - GLFUNC_REQUIRES(glMultiDrawElementsIndirect, "VERSION_4_3"), - GLFUNC_REQUIRES(glGetProgramInterfaceiv, "VERSION_4_3"), - GLFUNC_REQUIRES(glGetProgramResourceIndex, "VERSION_4_3"), - GLFUNC_REQUIRES(glGetProgramResourceName, "VERSION_4_3"), - GLFUNC_REQUIRES(glGetProgramResourceiv, "VERSION_4_3"), - GLFUNC_REQUIRES(glGetProgramResourceLocation, "VERSION_4_3"), - GLFUNC_REQUIRES(glGetProgramResourceLocationIndex, "VERSION_4_3"), - GLFUNC_REQUIRES(glShaderStorageBlockBinding, "VERSION_4_3"), - GLFUNC_REQUIRES(glTexBufferRange, "VERSION_4_3"), - GLFUNC_REQUIRES(glTexStorage2DMultisample, "VERSION_4_3"), - GLFUNC_REQUIRES(glTexStorage3DMultisample, "VERSION_4_3"), - GLFUNC_REQUIRES(glTextureView, "VERSION_4_3"), - GLFUNC_REQUIRES(glBindVertexBuffer, "VERSION_4_3"), - GLFUNC_REQUIRES(glVertexAttribFormat, "VERSION_4_3"), - GLFUNC_REQUIRES(glVertexAttribIFormat, "VERSION_4_3"), - GLFUNC_REQUIRES(glVertexAttribLFormat, "VERSION_4_3"), - GLFUNC_REQUIRES(glVertexAttribBinding, "VERSION_4_3"), - GLFUNC_REQUIRES(glVertexBindingDivisor, "VERSION_4_3"), - GLFUNC_REQUIRES(glDebugMessageControl, "VERSION_4_3"), - GLFUNC_REQUIRES(glDebugMessageInsert, "VERSION_4_3"), - GLFUNC_REQUIRES(glDebugMessageCallback, "VERSION_4_3"), - GLFUNC_REQUIRES(glGetDebugMessageLog, "VERSION_4_3"), - GLFUNC_REQUIRES(glPushDebugGroup, "VERSION_4_3"), - GLFUNC_REQUIRES(glPopDebugGroup, "VERSION_4_3"), - GLFUNC_REQUIRES(glObjectLabel, "VERSION_4_3"), - GLFUNC_REQUIRES(glGetObjectLabel, "VERSION_4_3"), - GLFUNC_REQUIRES(glObjectPtrLabel, "VERSION_4_3"), - GLFUNC_REQUIRES(glGetObjectPtrLabel, "VERSION_4_3"), + // gl_4_5 + GLFUNC_REQUIRES(glClipControl, "VERSION_4_5"), + GLFUNC_REQUIRES(glCreateTransformFeedbacks, "VERSION_4_5"), + GLFUNC_REQUIRES(glTransformFeedbackBufferBase, "VERSION_4_5"), + GLFUNC_REQUIRES(glTransformFeedbackBufferRange, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetTransformFeedbackiv, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetTransformFeedbacki_v, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetTransformFeedbacki64_v, "VERSION_4_5"), + GLFUNC_REQUIRES(glCreateBuffers, "VERSION_4_5"), + GLFUNC_REQUIRES(glNamedBufferStorage, "VERSION_4_5"), + GLFUNC_REQUIRES(glNamedBufferData, "VERSION_4_5"), + GLFUNC_REQUIRES(glNamedBufferSubData, "VERSION_4_5"), + GLFUNC_REQUIRES(glCopyNamedBufferSubData, "VERSION_4_5"), + GLFUNC_REQUIRES(glClearNamedBufferData, "VERSION_4_5"), + GLFUNC_REQUIRES(glClearNamedBufferSubData, "VERSION_4_5"), + GLFUNC_REQUIRES(glMapNamedBuffer, "VERSION_4_5"), + GLFUNC_REQUIRES(glMapNamedBufferRange, "VERSION_4_5"), + GLFUNC_REQUIRES(glUnmapNamedBuffer, "VERSION_4_5"), + GLFUNC_REQUIRES(glFlushMappedNamedBufferRange, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetNamedBufferParameteriv, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetNamedBufferParameteri64v, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetNamedBufferPointerv, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetNamedBufferSubData, "VERSION_4_5"), + GLFUNC_REQUIRES(glCreateFramebuffers, "VERSION_4_5"), + GLFUNC_REQUIRES(glNamedFramebufferRenderbuffer, "VERSION_4_5"), + GLFUNC_REQUIRES(glNamedFramebufferParameteri, "VERSION_4_5"), + GLFUNC_REQUIRES(glNamedFramebufferTexture, "VERSION_4_5"), + GLFUNC_REQUIRES(glNamedFramebufferTextureLayer, "VERSION_4_5"), + GLFUNC_REQUIRES(glNamedFramebufferDrawBuffer, "VERSION_4_5"), + GLFUNC_REQUIRES(glNamedFramebufferDrawBuffers, "VERSION_4_5"), + GLFUNC_REQUIRES(glNamedFramebufferReadBuffer, "VERSION_4_5"), + GLFUNC_REQUIRES(glInvalidateNamedFramebufferData, "VERSION_4_5"), + GLFUNC_REQUIRES(glInvalidateNamedFramebufferSubData, "VERSION_4_5"), + GLFUNC_REQUIRES(glClearNamedFramebufferiv, "VERSION_4_5"), + GLFUNC_REQUIRES(glClearNamedFramebufferuiv, "VERSION_4_5"), + GLFUNC_REQUIRES(glClearNamedFramebufferfv, "VERSION_4_5"), + GLFUNC_REQUIRES(glClearNamedFramebufferfi, "VERSION_4_5"), + GLFUNC_REQUIRES(glBlitNamedFramebuffer, "VERSION_4_5"), + GLFUNC_REQUIRES(glCheckNamedFramebufferStatus, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetNamedFramebufferParameteriv, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetNamedFramebufferAttachmentParameteriv, "VERSION_4_5"), + GLFUNC_REQUIRES(glCreateRenderbuffers, "VERSION_4_5"), + GLFUNC_REQUIRES(glNamedRenderbufferStorage, "VERSION_4_5"), + GLFUNC_REQUIRES(glNamedRenderbufferStorageMultisample, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetNamedRenderbufferParameteriv, "VERSION_4_5"), + GLFUNC_REQUIRES(glCreateTextures, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureBuffer, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureBufferRange, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureStorage1D, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureStorage2D, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureStorage3D, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureStorage2DMultisample, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureStorage3DMultisample, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureSubImage1D, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureSubImage2D, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureSubImage3D, "VERSION_4_5"), + GLFUNC_REQUIRES(glCompressedTextureSubImage1D, "VERSION_4_5"), + GLFUNC_REQUIRES(glCompressedTextureSubImage2D, "VERSION_4_5"), + GLFUNC_REQUIRES(glCompressedTextureSubImage3D, "VERSION_4_5"), + GLFUNC_REQUIRES(glCopyTextureSubImage1D, "VERSION_4_5"), + GLFUNC_REQUIRES(glCopyTextureSubImage2D, "VERSION_4_5"), + GLFUNC_REQUIRES(glCopyTextureSubImage3D, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureParameterf, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureParameterfv, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureParameteri, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureParameterIiv, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureParameterIuiv, "VERSION_4_5"), + GLFUNC_REQUIRES(glTextureParameteriv, "VERSION_4_5"), + GLFUNC_REQUIRES(glGenerateTextureMipmap, "VERSION_4_5"), + GLFUNC_REQUIRES(glBindTextureUnit, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetTextureImage, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetCompressedTextureImage, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetTextureLevelParameterfv, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetTextureLevelParameteriv, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetTextureParameterfv, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetTextureParameterIiv, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetTextureParameterIuiv, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetTextureParameteriv, "VERSION_4_5"), + GLFUNC_REQUIRES(glCreateVertexArrays, "VERSION_4_5"), + GLFUNC_REQUIRES(glDisableVertexArrayAttrib, "VERSION_4_5"), + GLFUNC_REQUIRES(glEnableVertexArrayAttrib, "VERSION_4_5"), + GLFUNC_REQUIRES(glVertexArrayElementBuffer, "VERSION_4_5"), + GLFUNC_REQUIRES(glVertexArrayVertexBuffer, "VERSION_4_5"), + GLFUNC_REQUIRES(glVertexArrayVertexBuffers, "VERSION_4_5"), + GLFUNC_REQUIRES(glVertexArrayAttribBinding, "VERSION_4_5"), + GLFUNC_REQUIRES(glVertexArrayAttribFormat, "VERSION_4_5"), + GLFUNC_REQUIRES(glVertexArrayAttribIFormat, "VERSION_4_5"), + GLFUNC_REQUIRES(glVertexArrayAttribLFormat, "VERSION_4_5"), + GLFUNC_REQUIRES(glVertexArrayBindingDivisor, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetVertexArrayiv, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetVertexArrayIndexediv, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetVertexArrayIndexed64iv, "VERSION_4_5"), + GLFUNC_REQUIRES(glCreateSamplers, "VERSION_4_5"), + GLFUNC_REQUIRES(glCreateProgramPipelines, "VERSION_4_5"), + GLFUNC_REQUIRES(glCreateQueries, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetQueryBufferObjecti64v, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetQueryBufferObjectiv, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetQueryBufferObjectui64v, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetQueryBufferObjectuiv, "VERSION_4_5"), + GLFUNC_REQUIRES(glMemoryBarrierByRegion, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetTextureSubImage, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetCompressedTextureSubImage, "VERSION_4_5"), + GLFUNC_REQUIRES(glGetGraphicsResetStatus, "VERSION_4_5"), + GLFUNC_REQUIRES(glReadnPixels, "VERSION_4_5"), GLFUNC_REQUIRES(glTextureBarrier, "VERSION_4_5"), + // AMD's video driver is trash and doesn't expose these function pointers + // Remove them for now until they learn how to implement the spec properly. + // GLFUNC_REQUIRES(glGetnCompressedTexImage, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnTexImage, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnUniformdv, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnUniformfv, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnUniformiv, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnUniformuiv, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnMapdv, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnMapfv, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnMapiv, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnPixelMapfv, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnPixelMapuiv, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnPixelMapusv, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnPolygonStipple, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnColorTable, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnConvolutionFilter, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnSeparableFilter, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnHistogram, "VERSION_4_5"), + // GLFUNC_REQUIRES(glGetnMinmax, "VERSION_4_5"), - // gl_4_4 - GLFUNC_REQUIRES(glBufferStorage, "VERSION_4_4"), - GLFUNC_REQUIRES(glClearTexImage, "VERSION_4_4"), - GLFUNC_REQUIRES(glClearTexSubImage, "VERSION_4_4"), - GLFUNC_REQUIRES(glBindBuffersBase, "VERSION_4_4"), - GLFUNC_REQUIRES(glBindBuffersRange, "VERSION_4_4"), - GLFUNC_REQUIRES(glBindTextures, "VERSION_4_4"), - GLFUNC_REQUIRES(glBindSamplers, "VERSION_4_4"), - GLFUNC_REQUIRES(glBindImageTextures, "VERSION_4_4"), - GLFUNC_REQUIRES(glBindVertexBuffers, "VERSION_4_4"), + // ARB_uniform_buffer_object + GLFUNC_REQUIRES(glGetActiveUniformName, "GL_ARB_uniform_buffer_object"), + GLFUNC_REQUIRES(glBindBufferBase, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), + GLFUNC_REQUIRES(glBindBufferRange, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetActiveUniformBlockName, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetActiveUniformBlockiv, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetActiveUniformsiv, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetIntegeri_v, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetUniformBlockIndex, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetUniformIndices, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), + GLFUNC_REQUIRES(glUniformBlockBinding, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), - // gl_4_5 - GLFUNC_REQUIRES(glClipControl, "VERSION_4_5"), - GLFUNC_REQUIRES(glCreateTransformFeedbacks, "VERSION_4_5"), - GLFUNC_REQUIRES(glTransformFeedbackBufferBase, "VERSION_4_5"), - GLFUNC_REQUIRES(glTransformFeedbackBufferRange, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetTransformFeedbackiv, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetTransformFeedbacki_v, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetTransformFeedbacki64_v, "VERSION_4_5"), - GLFUNC_REQUIRES(glCreateBuffers, "VERSION_4_5"), - GLFUNC_REQUIRES(glNamedBufferStorage, "VERSION_4_5"), - GLFUNC_REQUIRES(glNamedBufferData, "VERSION_4_5"), - GLFUNC_REQUIRES(glNamedBufferSubData, "VERSION_4_5"), - GLFUNC_REQUIRES(glCopyNamedBufferSubData, "VERSION_4_5"), - GLFUNC_REQUIRES(glClearNamedBufferData, "VERSION_4_5"), - GLFUNC_REQUIRES(glClearNamedBufferSubData, "VERSION_4_5"), - GLFUNC_REQUIRES(glMapNamedBuffer, "VERSION_4_5"), - GLFUNC_REQUIRES(glMapNamedBufferRange, "VERSION_4_5"), - GLFUNC_REQUIRES(glUnmapNamedBuffer, "VERSION_4_5"), - GLFUNC_REQUIRES(glFlushMappedNamedBufferRange, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetNamedBufferParameteriv, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetNamedBufferParameteri64v, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetNamedBufferPointerv, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetNamedBufferSubData, "VERSION_4_5"), - GLFUNC_REQUIRES(glCreateFramebuffers, "VERSION_4_5"), - GLFUNC_REQUIRES(glNamedFramebufferRenderbuffer, "VERSION_4_5"), - GLFUNC_REQUIRES(glNamedFramebufferParameteri, "VERSION_4_5"), - GLFUNC_REQUIRES(glNamedFramebufferTexture, "VERSION_4_5"), - GLFUNC_REQUIRES(glNamedFramebufferTextureLayer, "VERSION_4_5"), - GLFUNC_REQUIRES(glNamedFramebufferDrawBuffer, "VERSION_4_5"), - GLFUNC_REQUIRES(glNamedFramebufferDrawBuffers, "VERSION_4_5"), - GLFUNC_REQUIRES(glNamedFramebufferReadBuffer, "VERSION_4_5"), - GLFUNC_REQUIRES(glInvalidateNamedFramebufferData, "VERSION_4_5"), - GLFUNC_REQUIRES(glInvalidateNamedFramebufferSubData, "VERSION_4_5"), - GLFUNC_REQUIRES(glClearNamedFramebufferiv, "VERSION_4_5"), - GLFUNC_REQUIRES(glClearNamedFramebufferuiv, "VERSION_4_5"), - GLFUNC_REQUIRES(glClearNamedFramebufferfv, "VERSION_4_5"), - GLFUNC_REQUIRES(glClearNamedFramebufferfi, "VERSION_4_5"), - GLFUNC_REQUIRES(glBlitNamedFramebuffer, "VERSION_4_5"), - GLFUNC_REQUIRES(glCheckNamedFramebufferStatus, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetNamedFramebufferParameteriv, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetNamedFramebufferAttachmentParameteriv, "VERSION_4_5"), - GLFUNC_REQUIRES(glCreateRenderbuffers, "VERSION_4_5"), - GLFUNC_REQUIRES(glNamedRenderbufferStorage, "VERSION_4_5"), - GLFUNC_REQUIRES(glNamedRenderbufferStorageMultisample, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetNamedRenderbufferParameteriv, "VERSION_4_5"), - GLFUNC_REQUIRES(glCreateTextures, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureBuffer, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureBufferRange, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureStorage1D, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureStorage2D, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureStorage3D, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureStorage2DMultisample, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureStorage3DMultisample, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureSubImage1D, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureSubImage2D, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureSubImage3D, "VERSION_4_5"), - GLFUNC_REQUIRES(glCompressedTextureSubImage1D, "VERSION_4_5"), - GLFUNC_REQUIRES(glCompressedTextureSubImage2D, "VERSION_4_5"), - GLFUNC_REQUIRES(glCompressedTextureSubImage3D, "VERSION_4_5"), - GLFUNC_REQUIRES(glCopyTextureSubImage1D, "VERSION_4_5"), - GLFUNC_REQUIRES(glCopyTextureSubImage2D, "VERSION_4_5"), - GLFUNC_REQUIRES(glCopyTextureSubImage3D, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureParameterf, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureParameterfv, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureParameteri, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureParameterIiv, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureParameterIuiv, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureParameteriv, "VERSION_4_5"), - GLFUNC_REQUIRES(glGenerateTextureMipmap, "VERSION_4_5"), - GLFUNC_REQUIRES(glBindTextureUnit, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetTextureImage, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetCompressedTextureImage, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetTextureLevelParameterfv, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetTextureLevelParameteriv, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetTextureParameterfv, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetTextureParameterIiv, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetTextureParameterIuiv, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetTextureParameteriv, "VERSION_4_5"), - GLFUNC_REQUIRES(glCreateVertexArrays, "VERSION_4_5"), - GLFUNC_REQUIRES(glDisableVertexArrayAttrib, "VERSION_4_5"), - GLFUNC_REQUIRES(glEnableVertexArrayAttrib, "VERSION_4_5"), - GLFUNC_REQUIRES(glVertexArrayElementBuffer, "VERSION_4_5"), - GLFUNC_REQUIRES(glVertexArrayVertexBuffer, "VERSION_4_5"), - GLFUNC_REQUIRES(glVertexArrayVertexBuffers, "VERSION_4_5"), - GLFUNC_REQUIRES(glVertexArrayAttribBinding, "VERSION_4_5"), - GLFUNC_REQUIRES(glVertexArrayAttribFormat, "VERSION_4_5"), - GLFUNC_REQUIRES(glVertexArrayAttribIFormat, "VERSION_4_5"), - GLFUNC_REQUIRES(glVertexArrayAttribLFormat, "VERSION_4_5"), - GLFUNC_REQUIRES(glVertexArrayBindingDivisor, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetVertexArrayiv, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetVertexArrayIndexediv, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetVertexArrayIndexed64iv, "VERSION_4_5"), - GLFUNC_REQUIRES(glCreateSamplers, "VERSION_4_5"), - GLFUNC_REQUIRES(glCreateProgramPipelines, "VERSION_4_5"), - GLFUNC_REQUIRES(glCreateQueries, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetQueryBufferObjecti64v, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetQueryBufferObjectiv, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetQueryBufferObjectui64v, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetQueryBufferObjectuiv, "VERSION_4_5"), - GLFUNC_REQUIRES(glMemoryBarrierByRegion, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetTextureSubImage, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetCompressedTextureSubImage, "VERSION_4_5"), - GLFUNC_REQUIRES(glGetGraphicsResetStatus, "VERSION_4_5"), - GLFUNC_REQUIRES(glReadnPixels, "VERSION_4_5"), - GLFUNC_REQUIRES(glTextureBarrier, "VERSION_4_5"), - // AMD's video driver is trash and doesn't expose these function pointers - // Remove them for now until they learn how to implement the spec properly. - // GLFUNC_REQUIRES(glGetnCompressedTexImage, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnTexImage, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnUniformdv, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnUniformfv, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnUniformiv, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnUniformuiv, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnMapdv, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnMapfv, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnMapiv, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnPixelMapfv, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnPixelMapuiv, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnPixelMapusv, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnPolygonStipple, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnColorTable, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnConvolutionFilter, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnSeparableFilter, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnHistogram, "VERSION_4_5"), - // GLFUNC_REQUIRES(glGetnMinmax, "VERSION_4_5"), + // ARB_sampler_objects + GLFUNC_REQUIRES(glBindSampler, "GL_ARB_sampler_objects |VERSION_GLES_3"), + GLFUNC_REQUIRES(glDeleteSamplers, "GL_ARB_sampler_objects |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGenSamplers, "GL_ARB_sampler_objects |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetSamplerParameterfv, "GL_ARB_sampler_objects |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetSamplerParameteriv, "GL_ARB_sampler_objects |VERSION_GLES_3"), + GLFUNC_REQUIRES(glIsSampler, "GL_ARB_sampler_objects |VERSION_GLES_3"), + GLFUNC_REQUIRES(glSamplerParameterf, "GL_ARB_sampler_objects |VERSION_GLES_3"), + GLFUNC_REQUIRES(glSamplerParameterfv, "GL_ARB_sampler_objects |VERSION_GLES_3"), + GLFUNC_REQUIRES(glSamplerParameteri, "GL_ARB_sampler_objects |VERSION_GLES_3"), + GLFUNC_REQUIRES(glSamplerParameteriv, "GL_ARB_sampler_objects |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetSamplerParameterIiv, "GL_ARB_sampler_objects |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glGetSamplerParameterIuiv, "GL_ARB_sampler_objects |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glSamplerParameterIiv, "GL_ARB_sampler_objects |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glSamplerParameterIuiv, "GL_ARB_sampler_objects |VERSION_GLES_3_2"), - // ARB_uniform_buffer_object - GLFUNC_REQUIRES(glGetActiveUniformName, "GL_ARB_uniform_buffer_object"), - GLFUNC_REQUIRES(glBindBufferBase, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), - GLFUNC_REQUIRES(glBindBufferRange, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetActiveUniformBlockName, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetActiveUniformBlockiv, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetActiveUniformsiv, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetIntegeri_v, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetUniformBlockIndex, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetUniformIndices, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), - GLFUNC_REQUIRES(glUniformBlockBinding, "GL_ARB_uniform_buffer_object |VERSION_GLES_3"), + // ARB_map_buffer_range + GLFUNC_REQUIRES(glFlushMappedBufferRange, "GL_ARB_map_buffer_range |VERSION_GLES_3"), + GLFUNC_REQUIRES(glMapBufferRange, "GL_ARB_map_buffer_range |VERSION_GLES_3"), - // ARB_sampler_objects - GLFUNC_REQUIRES(glBindSampler, "GL_ARB_sampler_objects |VERSION_GLES_3"), - GLFUNC_REQUIRES(glDeleteSamplers, "GL_ARB_sampler_objects |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGenSamplers, "GL_ARB_sampler_objects |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetSamplerParameterfv, "GL_ARB_sampler_objects |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetSamplerParameteriv, "GL_ARB_sampler_objects |VERSION_GLES_3"), - GLFUNC_REQUIRES(glIsSampler, "GL_ARB_sampler_objects |VERSION_GLES_3"), - GLFUNC_REQUIRES(glSamplerParameterf, "GL_ARB_sampler_objects |VERSION_GLES_3"), - GLFUNC_REQUIRES(glSamplerParameterfv, "GL_ARB_sampler_objects |VERSION_GLES_3"), - GLFUNC_REQUIRES(glSamplerParameteri, "GL_ARB_sampler_objects |VERSION_GLES_3"), - GLFUNC_REQUIRES(glSamplerParameteriv, "GL_ARB_sampler_objects |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetSamplerParameterIiv, "GL_ARB_sampler_objects |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glGetSamplerParameterIuiv, "GL_ARB_sampler_objects |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glSamplerParameterIiv, "GL_ARB_sampler_objects |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glSamplerParameterIuiv, "GL_ARB_sampler_objects |VERSION_GLES_3_2"), + // ARB_vertex_array_object + GLFUNC_REQUIRES(glBindVertexArray, "GL_ARB_vertex_array_object |VERSION_GLES_3"), + GLFUNC_REQUIRES(glDeleteVertexArrays, "GL_ARB_vertex_array_object |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGenVertexArrays, "GL_ARB_vertex_array_object |VERSION_GLES_3"), + GLFUNC_REQUIRES(glIsVertexArray, "GL_ARB_vertex_array_object |VERSION_GLES_3"), - // ARB_map_buffer_range - GLFUNC_REQUIRES(glFlushMappedBufferRange, "GL_ARB_map_buffer_range |VERSION_GLES_3"), - GLFUNC_REQUIRES(glMapBufferRange, "GL_ARB_map_buffer_range |VERSION_GLES_3"), + // APPLE_vertex_array_object + GLFUNC_SUFFIX(glBindVertexArray, APPLE, + "GL_APPLE_vertex_array_object !GL_ARB_vertex_array_object"), + GLFUNC_SUFFIX(glDeleteVertexArrays, APPLE, + "GL_APPLE_vertex_array_object !GL_ARB_vertex_array_object"), + GLFUNC_SUFFIX(glGenVertexArrays, APPLE, + "GL_APPLE_vertex_array_object !GL_ARB_vertex_array_object"), + GLFUNC_SUFFIX(glIsVertexArray, APPLE, + "GL_APPLE_vertex_array_object !GL_ARB_vertex_array_object"), - // ARB_vertex_array_object - GLFUNC_REQUIRES(glBindVertexArray, "GL_ARB_vertex_array_object |VERSION_GLES_3"), - GLFUNC_REQUIRES(glDeleteVertexArrays, "GL_ARB_vertex_array_object |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGenVertexArrays, "GL_ARB_vertex_array_object |VERSION_GLES_3"), - GLFUNC_REQUIRES(glIsVertexArray, "GL_ARB_vertex_array_object |VERSION_GLES_3"), + // ARB_framebuffer_object + GLFUNC_REQUIRES(glFramebufferTexture1D, "GL_ARB_framebuffer_object"), + GLFUNC_REQUIRES(glFramebufferTexture3D, "GL_ARB_framebuffer_object"), + GLFUNC_REQUIRES(glBindFramebuffer, "GL_ARB_framebuffer_object |VERSION_GLES_2"), + GLFUNC_REQUIRES(glBindRenderbuffer, "GL_ARB_framebuffer_object |VERSION_GLES_2"), + GLFUNC_REQUIRES(glBlitFramebuffer, "GL_ARB_framebuffer_object |VERSION_GLES_3"), + GLFUNC_REQUIRES(glCheckFramebufferStatus, "GL_ARB_framebuffer_object |VERSION_GLES_2"), + GLFUNC_REQUIRES(glDeleteFramebuffers, "GL_ARB_framebuffer_object |VERSION_GLES_2"), + GLFUNC_REQUIRES(glDeleteRenderbuffers, "GL_ARB_framebuffer_object |VERSION_GLES_2"), + GLFUNC_REQUIRES(glFramebufferRenderbuffer, "GL_ARB_framebuffer_object |VERSION_GLES_2"), + GLFUNC_REQUIRES(glFramebufferTexture2D, "GL_ARB_framebuffer_object |VERSION_GLES_2"), + GLFUNC_REQUIRES(glFramebufferTextureLayer, "GL_ARB_framebuffer_object |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGenFramebuffers, "GL_ARB_framebuffer_object |VERSION_GLES_2"), + GLFUNC_REQUIRES(glGenRenderbuffers, "GL_ARB_framebuffer_object |VERSION_GLES_2"), + GLFUNC_REQUIRES(glGenerateMipmap, "GL_ARB_framebuffer_object |VERSION_GLES_2"), + GLFUNC_REQUIRES(glGetFramebufferAttachmentParameteriv, + "GL_ARB_framebuffer_object |VERSION_GLES_2"), + GLFUNC_REQUIRES(glGetRenderbufferParameteriv, "GL_ARB_framebuffer_object |VERSION_GLES_2"), + GLFUNC_REQUIRES(glIsFramebuffer, "GL_ARB_framebuffer_object |VERSION_GLES_2"), + GLFUNC_REQUIRES(glIsRenderbuffer, "GL_ARB_framebuffer_object |VERSION_GLES_2"), + GLFUNC_REQUIRES(glRenderbufferStorage, "GL_ARB_framebuffer_object |VERSION_GLES_2"), + GLFUNC_REQUIRES(glRenderbufferStorageMultisample, "GL_ARB_framebuffer_object |VERSION_GLES_3"), - // APPLE_vertex_array_object - GLFUNC_SUFFIX(glBindVertexArray, APPLE, "GL_APPLE_vertex_array_object !GL_ARB_vertex_array_object"), - GLFUNC_SUFFIX(glDeleteVertexArrays, APPLE, "GL_APPLE_vertex_array_object !GL_ARB_vertex_array_object"), - GLFUNC_SUFFIX(glGenVertexArrays, APPLE, "GL_APPLE_vertex_array_object !GL_ARB_vertex_array_object"), - GLFUNC_SUFFIX(glIsVertexArray, APPLE, "GL_APPLE_vertex_array_object !GL_ARB_vertex_array_object"), + // ARB_get_program_binary + GLFUNC_REQUIRES(glGetProgramBinary, "GL_ARB_get_program_binary |VERSION_GLES_3"), + GLFUNC_REQUIRES(glProgramBinary, "GL_ARB_get_program_binary |VERSION_GLES_3"), + GLFUNC_REQUIRES(glProgramParameteri, "GL_ARB_get_program_binary |VERSION_GLES_3"), - // ARB_framebuffer_object - GLFUNC_REQUIRES(glFramebufferTexture1D, "GL_ARB_framebuffer_object"), - GLFUNC_REQUIRES(glFramebufferTexture3D, "GL_ARB_framebuffer_object"), - GLFUNC_REQUIRES(glBindFramebuffer, "GL_ARB_framebuffer_object |VERSION_GLES_2"), - GLFUNC_REQUIRES(glBindRenderbuffer, "GL_ARB_framebuffer_object |VERSION_GLES_2"), - GLFUNC_REQUIRES(glBlitFramebuffer, "GL_ARB_framebuffer_object |VERSION_GLES_3"), - GLFUNC_REQUIRES(glCheckFramebufferStatus, "GL_ARB_framebuffer_object |VERSION_GLES_2"), - GLFUNC_REQUIRES(glDeleteFramebuffers, "GL_ARB_framebuffer_object |VERSION_GLES_2"), - GLFUNC_REQUIRES(glDeleteRenderbuffers, "GL_ARB_framebuffer_object |VERSION_GLES_2"), - GLFUNC_REQUIRES(glFramebufferRenderbuffer, "GL_ARB_framebuffer_object |VERSION_GLES_2"), - GLFUNC_REQUIRES(glFramebufferTexture2D, "GL_ARB_framebuffer_object |VERSION_GLES_2"), - GLFUNC_REQUIRES(glFramebufferTextureLayer, "GL_ARB_framebuffer_object |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGenFramebuffers, "GL_ARB_framebuffer_object |VERSION_GLES_2"), - GLFUNC_REQUIRES(glGenRenderbuffers, "GL_ARB_framebuffer_object |VERSION_GLES_2"), - GLFUNC_REQUIRES(glGenerateMipmap, "GL_ARB_framebuffer_object |VERSION_GLES_2"), - GLFUNC_REQUIRES(glGetFramebufferAttachmentParameteriv, "GL_ARB_framebuffer_object |VERSION_GLES_2"), - GLFUNC_REQUIRES(glGetRenderbufferParameteriv, "GL_ARB_framebuffer_object |VERSION_GLES_2"), - GLFUNC_REQUIRES(glIsFramebuffer, "GL_ARB_framebuffer_object |VERSION_GLES_2"), - GLFUNC_REQUIRES(glIsRenderbuffer, "GL_ARB_framebuffer_object |VERSION_GLES_2"), - GLFUNC_REQUIRES(glRenderbufferStorage, "GL_ARB_framebuffer_object |VERSION_GLES_2"), - GLFUNC_REQUIRES(glRenderbufferStorageMultisample, "GL_ARB_framebuffer_object |VERSION_GLES_3"), + // ARB_sync + GLFUNC_REQUIRES(glClientWaitSync, "GL_ARB_sync |VERSION_GLES_3"), + GLFUNC_REQUIRES(glDeleteSync, "GL_ARB_sync |VERSION_GLES_3"), + GLFUNC_REQUIRES(glFenceSync, "GL_ARB_sync |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetInteger64v, "GL_ARB_sync |VERSION_GLES_3"), + GLFUNC_REQUIRES(glGetSynciv, "GL_ARB_sync |VERSION_GLES_3"), + GLFUNC_REQUIRES(glIsSync, "GL_ARB_sync |VERSION_GLES_3"), + GLFUNC_REQUIRES(glWaitSync, "GL_ARB_sync |VERSION_GLES_3"), - // ARB_get_program_binary - GLFUNC_REQUIRES(glGetProgramBinary, "GL_ARB_get_program_binary |VERSION_GLES_3"), - GLFUNC_REQUIRES(glProgramBinary, "GL_ARB_get_program_binary |VERSION_GLES_3"), - GLFUNC_REQUIRES(glProgramParameteri, "GL_ARB_get_program_binary |VERSION_GLES_3"), + // ARB_texture_multisample + GLFUNC_REQUIRES(glTexImage2DMultisample, "GL_ARB_texture_multisample"), + GLFUNC_REQUIRES(glTexImage3DMultisample, "GL_ARB_texture_multisample"), + GLFUNC_REQUIRES(glGetMultisamplefv, "GL_ARB_texture_multisample"), + GLFUNC_REQUIRES(glSampleMaski, "GL_ARB_texture_multisample"), - // ARB_sync - GLFUNC_REQUIRES(glClientWaitSync, "GL_ARB_sync |VERSION_GLES_3"), - GLFUNC_REQUIRES(glDeleteSync, "GL_ARB_sync |VERSION_GLES_3"), - GLFUNC_REQUIRES(glFenceSync, "GL_ARB_sync |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetInteger64v, "GL_ARB_sync |VERSION_GLES_3"), - GLFUNC_REQUIRES(glGetSynciv, "GL_ARB_sync |VERSION_GLES_3"), - GLFUNC_REQUIRES(glIsSync, "GL_ARB_sync |VERSION_GLES_3"), - GLFUNC_REQUIRES(glWaitSync, "GL_ARB_sync |VERSION_GLES_3"), + // ARB_texture_storage_multisample + GLFUNC_REQUIRES(glTexStorage2DMultisample, + "GL_ARB_texture_storage_multisample !VERSION_4_3 |VERSION_GLES_3_1"), + GLFUNC_REQUIRES(glTexStorage3DMultisample, + "GL_ARB_texture_storage_multisample !VERSION_4_3 |VERSION_GLES_3_2"), + GLFUNC_SUFFIX(glTexStorage3DMultisample, OES, + "GL_OES_texture_storage_multisample_2d_array !VERSION_GLES_3_2"), - // ARB_texture_multisample - GLFUNC_REQUIRES(glTexImage2DMultisample, "GL_ARB_texture_multisample"), - GLFUNC_REQUIRES(glTexImage3DMultisample, "GL_ARB_texture_multisample"), - GLFUNC_REQUIRES(glGetMultisamplefv, "GL_ARB_texture_multisample"), - GLFUNC_REQUIRES(glSampleMaski, "GL_ARB_texture_multisample"), + // ARB_ES2_compatibility + GLFUNC_REQUIRES(glClearDepthf, "GL_ARB_ES2_compatibility |VERSION_GLES_2"), + GLFUNC_REQUIRES(glDepthRangef, "GL_ARB_ES2_compatibility |VERSION_GLES_2"), + GLFUNC_REQUIRES(glGetShaderPrecisionFormat, "GL_ARB_ES2_compatibility |VERSION_GLES_2"), + GLFUNC_REQUIRES(glReleaseShaderCompiler, "GL_ARB_ES2_compatibility |VERSION_GLES_2"), + GLFUNC_REQUIRES(glShaderBinary, "GL_ARB_ES2_compatibility |VERSION_GLES_2"), - // ARB_texture_storage_multisample - GLFUNC_REQUIRES(glTexStorage2DMultisample, "GL_ARB_texture_storage_multisample !VERSION_4_3 |VERSION_GLES_3_1"), - GLFUNC_REQUIRES(glTexStorage3DMultisample, "GL_ARB_texture_storage_multisample !VERSION_4_3 |VERSION_GLES_3_2"), - GLFUNC_SUFFIX(glTexStorage3DMultisample, OES, "GL_OES_texture_storage_multisample_2d_array !VERSION_GLES_3_2"), + // NV_primitive_restart + GLFUNC_REQUIRES(glPrimitiveRestartIndexNV, "GL_NV_primitive_restart"), + GLFUNC_REQUIRES(glPrimitiveRestartNV, "GL_NV_primitive_restart"), - // ARB_ES2_compatibility - GLFUNC_REQUIRES(glClearDepthf, "GL_ARB_ES2_compatibility |VERSION_GLES_2"), - GLFUNC_REQUIRES(glDepthRangef, "GL_ARB_ES2_compatibility |VERSION_GLES_2"), - GLFUNC_REQUIRES(glGetShaderPrecisionFormat, "GL_ARB_ES2_compatibility |VERSION_GLES_2"), - GLFUNC_REQUIRES(glReleaseShaderCompiler, "GL_ARB_ES2_compatibility |VERSION_GLES_2"), - GLFUNC_REQUIRES(glShaderBinary, "GL_ARB_ES2_compatibility |VERSION_GLES_2"), + // ARB_blend_func_extended + GLFUNC_REQUIRES(glBindFragDataLocationIndexed, "GL_ARB_blend_func_extended"), + GLFUNC_REQUIRES(glGetFragDataIndex, "GL_ARB_blend_func_extended"), - // NV_primitive_restart - GLFUNC_REQUIRES(glPrimitiveRestartIndexNV, "GL_NV_primitive_restart"), - GLFUNC_REQUIRES(glPrimitiveRestartNV, "GL_NV_primitive_restart"), + // ARB_viewport_array + GLFUNC_REQUIRES(glDepthRangeArrayv, "GL_ARB_viewport_array"), + GLFUNC_REQUIRES(glDepthRangeIndexed, "GL_ARB_viewport_array"), + GLFUNC_REQUIRES(glGetDoublei_v, "GL_ARB_viewport_array"), + GLFUNC_REQUIRES(glGetFloati_v, "GL_ARB_viewport_array"), + GLFUNC_REQUIRES(glScissorArrayv, "GL_ARB_viewport_array"), + GLFUNC_REQUIRES(glScissorIndexed, "GL_ARB_viewport_array"), + GLFUNC_REQUIRES(glScissorIndexedv, "GL_ARB_viewport_array"), + GLFUNC_REQUIRES(glViewportArrayv, "GL_ARB_viewport_array"), + GLFUNC_REQUIRES(glViewportIndexedf, "GL_ARB_viewport_array"), + GLFUNC_REQUIRES(glViewportIndexedfv, "GL_ARB_viewport_array"), - // ARB_blend_func_extended - GLFUNC_REQUIRES(glBindFragDataLocationIndexed, "GL_ARB_blend_func_extended"), - GLFUNC_REQUIRES(glGetFragDataIndex, "GL_ARB_blend_func_extended"), + // ARB_draw_elements_base_vertex + GLFUNC_REQUIRES(glDrawElementsBaseVertex, "GL_ARB_draw_elements_base_vertex |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glDrawElementsInstancedBaseVertex, + "GL_ARB_draw_elements_base_vertex |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glDrawRangeElementsBaseVertex, + "GL_ARB_draw_elements_base_vertex |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glMultiDrawElementsBaseVertex, "GL_ARB_draw_elements_base_vertex"), - // ARB_viewport_array - GLFUNC_REQUIRES(glDepthRangeArrayv, "GL_ARB_viewport_array"), - GLFUNC_REQUIRES(glDepthRangeIndexed, "GL_ARB_viewport_array"), - GLFUNC_REQUIRES(glGetDoublei_v, "GL_ARB_viewport_array"), - GLFUNC_REQUIRES(glGetFloati_v, "GL_ARB_viewport_array"), - GLFUNC_REQUIRES(glScissorArrayv, "GL_ARB_viewport_array"), - GLFUNC_REQUIRES(glScissorIndexed, "GL_ARB_viewport_array"), - GLFUNC_REQUIRES(glScissorIndexedv, "GL_ARB_viewport_array"), - GLFUNC_REQUIRES(glViewportArrayv, "GL_ARB_viewport_array"), - GLFUNC_REQUIRES(glViewportIndexedf, "GL_ARB_viewport_array"), - GLFUNC_REQUIRES(glViewportIndexedfv, "GL_ARB_viewport_array"), + // OES_draw_elements_base_vertex + GLFUNC_SUFFIX(glDrawElementsBaseVertex, OES, + "GL_OES_draw_elements_base_vertex !VERSION_GLES_3_2"), + GLFUNC_SUFFIX(glDrawElementsInstancedBaseVertex, OES, + "GL_OES_draw_elements_base_vertex VERSION_GLES_3 !VERSION_GLES_3_2"), + GLFUNC_SUFFIX(glDrawRangeElementsBaseVertex, OES, + "GL_OES_draw_elements_base_vertex VERSION_GLES_3 !VERSION_GLES_3_2"), + GLFUNC_SUFFIX(glMultiDrawElementsBaseVertex, OES, + "GL_OES_draw_elements_base_vertex GL_EXT_multi_draw_arrays"), - // ARB_draw_elements_base_vertex - GLFUNC_REQUIRES(glDrawElementsBaseVertex, "GL_ARB_draw_elements_base_vertex |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glDrawElementsInstancedBaseVertex, "GL_ARB_draw_elements_base_vertex |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glDrawRangeElementsBaseVertex, "GL_ARB_draw_elements_base_vertex |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glMultiDrawElementsBaseVertex, "GL_ARB_draw_elements_base_vertex"), + // EXT_draw_elements_base_vertex + GLFUNC_SUFFIX( + glDrawElementsBaseVertex, EXT, + "GL_EXT_draw_elements_base_vertex !GL_OES_draw_elements_base_vertex !VERSION_GLES_3_2"), + GLFUNC_SUFFIX(glDrawElementsInstancedBaseVertex, EXT, + "GL_EXT_draw_elements_base_vertex VERSION_GLES_3 " + "!GL_OES_draw_elements_base_vertex !VERSION_GLES_3_2"), + GLFUNC_SUFFIX(glDrawRangeElementsBaseVertex, EXT, + "GL_EXT_draw_elements_base_vertex VERSION_GLES_3 " + "!GL_OES_draw_elements_base_vertex !VERSION_GLES_3_2"), + GLFUNC_SUFFIX(glMultiDrawElementsBaseVertex, EXT, + "GL_EXT_draw_elements_base_vertex GL_EXT_multi_draw_arrays " + "!GL_OES_draw_elements_base_vertex !VERSION_GLES_3_2"), - // OES_draw_elements_base_vertex - GLFUNC_SUFFIX(glDrawElementsBaseVertex, OES, "GL_OES_draw_elements_base_vertex !VERSION_GLES_3_2"), - GLFUNC_SUFFIX(glDrawElementsInstancedBaseVertex, OES, "GL_OES_draw_elements_base_vertex VERSION_GLES_3 !VERSION_GLES_3_2"), - GLFUNC_SUFFIX(glDrawRangeElementsBaseVertex, OES, "GL_OES_draw_elements_base_vertex VERSION_GLES_3 !VERSION_GLES_3_2"), - GLFUNC_SUFFIX(glMultiDrawElementsBaseVertex, OES, "GL_OES_draw_elements_base_vertex GL_EXT_multi_draw_arrays"), + // ARB_sample_shading + GLFUNC_SUFFIX(glMinSampleShading, ARB, "GL_ARB_sample_shading"), - // EXT_draw_elements_base_vertex - GLFUNC_SUFFIX(glDrawElementsBaseVertex, EXT, "GL_EXT_draw_elements_base_vertex !GL_OES_draw_elements_base_vertex !VERSION_GLES_3_2"), - GLFUNC_SUFFIX(glDrawElementsInstancedBaseVertex, EXT, "GL_EXT_draw_elements_base_vertex VERSION_GLES_3 !GL_OES_draw_elements_base_vertex !VERSION_GLES_3_2"), - GLFUNC_SUFFIX(glDrawRangeElementsBaseVertex, EXT, "GL_EXT_draw_elements_base_vertex VERSION_GLES_3 !GL_OES_draw_elements_base_vertex !VERSION_GLES_3_2"), - GLFUNC_SUFFIX(glMultiDrawElementsBaseVertex, EXT, "GL_EXT_draw_elements_base_vertex GL_EXT_multi_draw_arrays !GL_OES_draw_elements_base_vertex !VERSION_GLES_3_2"), + // OES_sample_shading + GLFUNC_SUFFIX(glMinSampleShading, OES, "GL_OES_sample_shading !VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glMinSampleShading, "VERSION_GLES_3_2"), - // ARB_sample_shading - GLFUNC_SUFFIX(glMinSampleShading, ARB, "GL_ARB_sample_shading"), + // ARB_debug_output + GLFUNC_REQUIRES(glDebugMessageCallbackARB, "GL_ARB_debug_output"), + GLFUNC_REQUIRES(glDebugMessageControlARB, "GL_ARB_debug_output"), + GLFUNC_REQUIRES(glDebugMessageInsertARB, "GL_ARB_debug_output"), + GLFUNC_REQUIRES(glGetDebugMessageLogARB, "GL_ARB_debug_output"), - // OES_sample_shading - GLFUNC_SUFFIX(glMinSampleShading, OES, "GL_OES_sample_shading !VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glMinSampleShading, "VERSION_GLES_3_2"), + // KHR_debug + GLFUNC_SUFFIX(glDebugMessageCallback, KHR, "GL_KHR_debug VERSION_GLES_3"), + GLFUNC_SUFFIX(glDebugMessageControl, KHR, "GL_KHR_debug VERSION_GLES_3"), + GLFUNC_SUFFIX(glDebugMessageInsert, KHR, "GL_KHR_debug VERSION_GLES_3"), + GLFUNC_SUFFIX(glGetDebugMessageLog, KHR, "GL_KHR_debug VERSION_GLES_3"), + GLFUNC_SUFFIX(glGetObjectLabel, KHR, "GL_KHR_debug VERSION_GLES_3"), + GLFUNC_SUFFIX(glGetObjectPtrLabel, KHR, "GL_KHR_debug VERSION_GLES_3"), + GLFUNC_SUFFIX(glObjectLabel, KHR, "GL_KHR_debug VERSION_GLES_3"), + GLFUNC_SUFFIX(glObjectPtrLabel, KHR, "GL_KHR_debug VERSION_GLES_3"), + GLFUNC_SUFFIX(glPopDebugGroup, KHR, "GL_KHR_debug VERSION_GLES_3"), + GLFUNC_SUFFIX(glPushDebugGroup, KHR, "GL_KHR_debug VERSION_GLES_3"), + GLFUNC_REQUIRES(glDebugMessageCallback, + "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glDebugMessageControl, + "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glDebugMessageInsert, + "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glGetDebugMessageLog, + "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glGetObjectLabel, + "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glGetObjectPtrLabel, + "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glObjectLabel, + "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glObjectPtrLabel, + "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glPopDebugGroup, + "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), + GLFUNC_REQUIRES(glPushDebugGroup, + "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), - // ARB_debug_output - GLFUNC_REQUIRES(glDebugMessageCallbackARB, "GL_ARB_debug_output"), - GLFUNC_REQUIRES(glDebugMessageControlARB, "GL_ARB_debug_output"), - GLFUNC_REQUIRES(glDebugMessageInsertARB, "GL_ARB_debug_output"), - GLFUNC_REQUIRES(glGetDebugMessageLogARB, "GL_ARB_debug_output"), + // ARB_buffer_storage + GLFUNC_REQUIRES(glBufferStorage, "GL_ARB_buffer_storage !VERSION_4_4"), + GLFUNC_SUFFIX(glNamedBufferStorage, EXT, + "GL_ARB_buffer_storage GL_EXT_direct_state_access !VERSION_4_5"), - // KHR_debug - GLFUNC_SUFFIX(glDebugMessageCallback, KHR, "GL_KHR_debug VERSION_GLES_3"), - GLFUNC_SUFFIX(glDebugMessageControl, KHR, "GL_KHR_debug VERSION_GLES_3"), - GLFUNC_SUFFIX(glDebugMessageInsert, KHR, "GL_KHR_debug VERSION_GLES_3"), - GLFUNC_SUFFIX(glGetDebugMessageLog, KHR, "GL_KHR_debug VERSION_GLES_3"), - GLFUNC_SUFFIX(glGetObjectLabel, KHR, "GL_KHR_debug VERSION_GLES_3"), - GLFUNC_SUFFIX(glGetObjectPtrLabel, KHR, "GL_KHR_debug VERSION_GLES_3"), - GLFUNC_SUFFIX(glObjectLabel, KHR, "GL_KHR_debug VERSION_GLES_3"), - GLFUNC_SUFFIX(glObjectPtrLabel, KHR, "GL_KHR_debug VERSION_GLES_3"), - GLFUNC_SUFFIX(glPopDebugGroup, KHR, "GL_KHR_debug VERSION_GLES_3"), - GLFUNC_SUFFIX(glPushDebugGroup, KHR, "GL_KHR_debug VERSION_GLES_3"), - GLFUNC_REQUIRES(glDebugMessageCallback, "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glDebugMessageControl, "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glDebugMessageInsert, "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glGetDebugMessageLog, "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glGetObjectLabel, "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glGetObjectPtrLabel, "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glObjectLabel, "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glObjectPtrLabel, "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glPopDebugGroup, "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), - GLFUNC_REQUIRES(glPushDebugGroup, "GL_KHR_debug !VERSION_GLES_3 !VERSION_GL_4_3 |VERSION_GLES_3_2"), + // EXT_buffer_storage + GLFUNC_SUFFIX(glBufferStorage, EXT, + "GL_EXT_buffer_storage !GL_ARB_buffer_storage !VERSION_4_4"), - // ARB_buffer_storage - GLFUNC_REQUIRES(glBufferStorage, "GL_ARB_buffer_storage !VERSION_4_4"), - GLFUNC_SUFFIX(glNamedBufferStorage, EXT, "GL_ARB_buffer_storage GL_EXT_direct_state_access !VERSION_4_5"), + // EXT_geometry_shader + GLFUNC_SUFFIX(glFramebufferTexture, EXT, "GL_EXT_geometry_shader !VERSION_3_2"), - // EXT_buffer_storage - GLFUNC_SUFFIX(glBufferStorage, EXT, "GL_EXT_buffer_storage !GL_ARB_buffer_storage !VERSION_4_4"), + // NV_occlusion_query_samples + GLFUNC_REQUIRES(glGenOcclusionQueriesNV, "GL_NV_occlusion_query_samples"), + GLFUNC_REQUIRES(glDeleteOcclusionQueriesNV, "GL_NV_occlusion_query_samples"), + GLFUNC_REQUIRES(glIsOcclusionQueryNV, "GL_NV_occlusion_query_samples"), + GLFUNC_REQUIRES(glBeginOcclusionQueryNV, "GL_NV_occlusion_query_samples"), + GLFUNC_REQUIRES(glEndOcclusionQueryNV, "GL_NV_occlusion_query_samples"), + GLFUNC_REQUIRES(glGetOcclusionQueryivNV, "GL_NV_occlusion_query_samples"), + GLFUNC_REQUIRES(glGetOcclusionQueryuivNV, "GL_NV_occlusion_query_samples"), - // EXT_geometry_shader - GLFUNC_SUFFIX(glFramebufferTexture, EXT, "GL_EXT_geometry_shader !VERSION_3_2"), + // ARB_clip_control + GLFUNC_REQUIRES(glClipControl, "GL_ARB_clip_control !VERSION_4_5"), - // NV_occlusion_query_samples - GLFUNC_REQUIRES(glGenOcclusionQueriesNV, "GL_NV_occlusion_query_samples"), - GLFUNC_REQUIRES(glDeleteOcclusionQueriesNV, "GL_NV_occlusion_query_samples"), - GLFUNC_REQUIRES(glIsOcclusionQueryNV, "GL_NV_occlusion_query_samples"), - GLFUNC_REQUIRES(glBeginOcclusionQueryNV, "GL_NV_occlusion_query_samples"), - GLFUNC_REQUIRES(glEndOcclusionQueryNV, "GL_NV_occlusion_query_samples"), - GLFUNC_REQUIRES(glGetOcclusionQueryivNV, "GL_NV_occlusion_query_samples"), - GLFUNC_REQUIRES(glGetOcclusionQueryuivNV, "GL_NV_occlusion_query_samples"), + // ARB_copy_image + GLFUNC_REQUIRES(glCopyImageSubData, "GL_ARB_copy_image !VERSION_4_3 |VERSION_GLES_3_2"), - // ARB_clip_control - GLFUNC_REQUIRES(glClipControl, "GL_ARB_clip_control !VERSION_4_5"), + // NV_copy_image + GLFUNC_SUFFIX(glCopyImageSubData, NV, "GL_NV_copy_image !GL_ARB_copy_image !VERSION_GLES_3_2"), - // ARB_copy_image - GLFUNC_REQUIRES(glCopyImageSubData, "GL_ARB_copy_image !VERSION_4_3 |VERSION_GLES_3_2"), + // OES_copy_image + GLFUNC_SUFFIX(glCopyImageSubData, OES, "GL_OES_copy_image !VERSION_GLES_3_2"), - // NV_copy_image - GLFUNC_SUFFIX(glCopyImageSubData, NV, "GL_NV_copy_image !GL_ARB_copy_image !VERSION_GLES_3_2"), + // EXT_copy_image + GLFUNC_SUFFIX(glCopyImageSubData, EXT, + "GL_EXT_copy_image !GL_OES_copy_image !VERSION_GLES_3_2"), - // OES_copy_image - GLFUNC_SUFFIX(glCopyImageSubData, OES, "GL_OES_copy_image !VERSION_GLES_3_2"), + // EXT_texture_buffer + GLFUNC_SUFFIX(glTexBuffer, OES, "GL_OES_texture_buffer !VERSION_GLES_3_2"), - // EXT_copy_image - GLFUNC_SUFFIX(glCopyImageSubData, EXT, "GL_EXT_copy_image !GL_OES_copy_image !VERSION_GLES_3_2"), + // EXT_texture_buffer + GLFUNC_SUFFIX(glTexBuffer, EXT, + "GL_EXT_texture_buffer !GL_OES_texture_buffer !VERSION_GLES_3_2"), - // EXT_texture_buffer - GLFUNC_SUFFIX(glTexBuffer, OES, "GL_OES_texture_buffer !VERSION_GLES_3_2"), + // EXT_blend_func_extended + GLFUNC_SUFFIX(glBindFragDataLocationIndexed, EXT, "GL_EXT_blend_func_extended"), + GLFUNC_SUFFIX(glGetFragDataIndex, EXT, "GL_EXT_blend_func_extended"), - // EXT_texture_buffer - GLFUNC_SUFFIX(glTexBuffer, EXT, "GL_EXT_texture_buffer !GL_OES_texture_buffer !VERSION_GLES_3_2"), - - // EXT_blend_func_extended - GLFUNC_SUFFIX(glBindFragDataLocationIndexed, EXT, "GL_EXT_blend_func_extended"), - GLFUNC_SUFFIX(glGetFragDataIndex, EXT, "GL_EXT_blend_func_extended"), - - // ARB_shader_storage_buffer_object - GLFUNC_REQUIRES(glShaderStorageBlockBinding, "ARB_shader_storage_buffer_object !VERSION_4_3"), + // ARB_shader_storage_buffer_object + GLFUNC_REQUIRES(glShaderStorageBlockBinding, "ARB_shader_storage_buffer_object !VERSION_4_3"), }; namespace GLExtensions { - // Private members and functions - static bool _isES; - static u32 _GLVersion; - static std::unordered_map m_extension_list; +// Private members and functions +static bool _isES; +static u32 _GLVersion; +static std::unordered_map m_extension_list; - // Private initialization functions - bool InitFunctionPointers(); +// Private initialization functions +bool InitFunctionPointers(); - // Initializes the extension list the old way - static void InitExtensionList21() - { - const char* extensions = (const char*)glGetString(GL_EXTENSIONS); - std::string tmp(extensions); - std::istringstream buffer(tmp); +// Initializes the extension list the old way +static void InitExtensionList21() +{ + const char* extensions = (const char*)glGetString(GL_EXTENSIONS); + std::string tmp(extensions); + std::istringstream buffer(tmp); - while (buffer >> tmp) - m_extension_list[tmp] = true; - } - - static void InitExtensionList() - { - m_extension_list.clear(); - if (_isES) - { - switch (_GLVersion) - { - default: - case 320: - m_extension_list["VERSION_GLES_3_2"] = true; - case 310: - m_extension_list["VERSION_GLES_3_1"] = true; - case 300: - m_extension_list["VERSION_GLES_3"] = true; - break; - } - - // We always have ES 2.0 - m_extension_list["VERSION_GLES_2"] = true; - } - else - { - // Some OpenGL implementations chose to not expose core extensions as extensions - // Let's add them to the list manually depending on which version of OpenGL we have - // We need to be slightly careful here - // When an extension got merged in to core, the naming may have changed - - // This has intentional fall through - switch (_GLVersion) - { - default: - case 450: - { - std::string gl450exts[] = { - "GL_ARB_ES3_1_compatibility", - "GL_ARB_clip_control", - "GL_ARB_conditional_render_inverted", - "GL_ARB_cull_distance", - "GL_ARB_derivative_control", - "GL_ARB_direct_state_access", - "GL_ARB_get_texture_sub_image", - "GL_ARB_robustness", - "GL_ARB_shader_texture_image_samples", - "GL_ARB_texture_barrier", - "VERSION_4_5", - }; - for (auto it : gl450exts) - m_extension_list[it] = true; - } - case 440: - { - std::string gl440exts[] = { - "GL_ARB_buffer_storage", - "GL_ARB_clear_texture", - "GL_ARB_enhanced_layouts", - "GL_ARB_multi_bind", - "GL_ARB_query_buffer_object", - "GL_ARB_texture_mirror_clamp_to_edge", - "GL_ARB_texture_stencil8", - "GL_ARB_vertex_type_10f_11f_11f_rev", - "VERSION_4_4", - }; - for (auto it : gl440exts) - m_extension_list[it] = true; - } - case 430: - { - std::string gl430exts[] = { - "GL_ARB_ES3_compatibility", - "GL_ARB_arrays_of_arrays", - "GL_ARB_clear_buffer_object", - "GL_ARB_compute_shader", - "GL_ARB_copy_image", - "GL_ARB_explicit_uniform_location", - "GL_ARB_fragment_layer_viewport", - "GL_ARB_framebuffer_no_attachments", - "GL_ARB_internalformat_query2", - "GL_ARB_invalidate_subdata", - "GL_ARB_multi_draw_indirect", - "GL_ARB_program_interface_query", - "GL_ARB_shader_image_size", - "GL_ARB_shader_storage_buffer_object", - "GL_ARB_stencil_texturing", - "GL_ARB_texture_buffer_range", - "GL_ARB_texture_query_levels", - "GL_ARB_texture_storage_multisample", - "GL_ARB_texture_view", - "GL_ARB_vertex_attrib_binding", - "VERSION_4_3", - }; - for (auto it : gl430exts) - m_extension_list[it] = true; - } - case 420: - { - std::string gl420exts[] = { - "GL_ARB_base_instance", - "GL_ARB_compressed_texture_pixel_storage", - "GL_ARB_conservative_depth", - "GL_ARB_internalformat_query", - "GL_ARB_map_buffer_alignment", - "GL_ARB_shader_atomic_counters", - "GL_ARB_shader_image_load_store", - "GL_ARB_shading_language_420pack", - "GL_ARB_shading_language_packing", - "GL_ARB_texture_compression_BPTC", - "GL_ARB_texture_storage", - "GL_ARB_transform_feedback_instanced", - "VERSION_4_2", - }; - for (auto it : gl420exts) - m_extension_list[it] = true; - } - case 410: - { - std::string gl410exts[] = { - "GL_ARB_ES2_compatibility", - "GL_ARB_get_program_binary", - "GL_ARB_separate_shader_objects", - "GL_ARB_shader_precision", - "GL_ARB_vertex_attrib_64_bit", - "GL_ARB_viewport_array", - "VERSION_4_1", - }; - for (auto it : gl410exts) - m_extension_list[it] = true; - } - case 400: - { - std::string gl400exts[] = { - "GL_ARB_draw_indirect", - "GL_ARB_gpu_shader5", - "GL_ARB_gpu_shader_fp64", - "GL_ARB_sample_shading", - "GL_ARB_shader_subroutine", - "GL_ARB_tessellation_shader", - "GL_ARB_texture_buffer_object_rgb32", - "GL_ARB_texture_cube_map_array", - "GL_ARB_texture_gather", - "GL_ARB_texture_query_lod", - "GL_ARB_transform_feedback2", - "GL_ARB_transform_feedback3", - "VERSION_4_0", - }; - for (auto it : gl400exts) - m_extension_list[it] = true; - } - case 330: - { - std::string gl330exts[] = { - "GL_ARB_shader_bit_encoding", - "GL_ARB_blend_func_extended", - "GL_ARB_explicit_attrib_location", - "GL_ARB_occlusion_query2", - "GL_ARB_sampler_objects", - "GL_ARB_texture_swizzle", - "GL_ARB_timer_query", - "GL_ARB_instanced_arrays", - "GL_ARB_texture_rgb10_a2ui", - "GL_ARB_vertex_type_2_10_10_10_rev", - "VERSION_3_3", - }; - for (auto it : gl330exts) - m_extension_list[it] = true; - } - case 320: - { - std::string gl320exts[] = { - "GL_ARB_geometry_shader4", - "GL_ARB_sync", - "GL_ARB_vertex_array_bgra", - "GL_ARB_draw_elements_base_vertex", - "GL_ARB_seamless_cube_map", - "GL_ARB_texture_multisample", - "GL_ARB_fragment_coord_conventions", - "GL_ARB_provoking_vertex", - "GL_ARB_depth_clamp", - "VERSION_3_2", - }; - for (auto it : gl320exts) - m_extension_list[it] = true; - } - case 310: - { - // Can't add NV_primitive_restart since function name changed - std::string gl310exts[] = { - "GL_ARB_draw_instanced", - "GL_ARB_copy_buffer", - "GL_ARB_texture_buffer_object", - "GL_ARB_texture_rectangle", - "GL_ARB_uniform_buffer_object", - //"GL_NV_primitive_restart", - "VERSION_3_1", - }; - for (auto it : gl310exts) - m_extension_list[it] = true; - } - case 300: - { - // Quite a lot of these had their names changed when merged in to core - // Disable the ones that have - std::string gl300exts[] = { - "GL_ARB_map_buffer_range", - //"GL_EXT_gpu_shader4", - //"GL_APPLE_flush_buffer_range", - "GL_ARB_color_buffer_float", - //"GL_NV_depth_buffer_float", - "GL_ARB_texture_float", - //"GL_EXT_packed_float", - //"GL_EXT_texture_shared_exponent", - "GL_ARB_half_float_pixel", - //"GL_NV_half_float", - "GL_ARB_framebuffer_object", - //"GL_EXT_framebuffer_sRGB", - "GL_ARB_texture_float", - //"GL_EXT_texture_integer", - //"GL_EXT_draw_buffers2", - //"GL_EXT_texture_integer", - //"GL_EXT_texture_array", - //"GL_EXT_texture_compression_rgtc", - //"GL_EXT_transform_feedback", - "GL_ARB_vertex_array_object", - //"GL_NV_conditional_render", - "VERSION_3_0", - }; - for (auto it : gl300exts) - m_extension_list[it] = true; - } - case 210: - case 200: - case 150: - case 140: - case 130: - case 121: - case 120: - case 110: - case 100: - break; - } - // So we can easily determine if we are running dekstop GL - m_extension_list["VERSION_GL"] = true; - } - - if (_GLVersion < 300) - { - InitExtensionList21(); - return; - } - GLint NumExtension = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &NumExtension); - for (GLint i = 0; i < NumExtension; ++i) - m_extension_list[std::string((const char*)glGetStringi(GL_EXTENSIONS, i))] = true; - } - static void InitVersion() - { - GLint major, minor; - glGetIntegerv(GL_MAJOR_VERSION, &major); - glGetIntegerv(GL_MINOR_VERSION, &minor); - if (glGetError() == GL_NO_ERROR) - _GLVersion = major * 100 + minor * 10; - else - _GLVersion = 210; - } - - static void* GetFuncAddress(const std::string& name, void **func) - { - *func = GLInterface->GetFuncAddress(name); - if (*func == nullptr) - { -#if defined(__linux__) || defined(__APPLE__) - // Give it a second try with dlsym - *func = dlsym(RTLD_NEXT, name.c_str()); -#endif - if (*func == nullptr) - ERROR_LOG(VIDEO, "Couldn't load function %s", name.c_str()); - } - return *func; - } - - // Public members - u32 Version() { return _GLVersion; } - bool Supports(const std::string& name) - { - return m_extension_list[name]; - } - - bool Init() - { - _isES = GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL; - - // Grab a few functions for initial checking - // We need them to grab the extension list - // Also to check if there is an error grabbing the version - if (GetFuncAddress("glGetIntegerv", (void**)&glGetIntegerv) == nullptr) - return false; - if (GetFuncAddress("glGetString", (void**)&glGetString) == nullptr) - return false; - if (GetFuncAddress("glGetError", (void**)&glGetError) == nullptr) - return false; - - InitVersion(); - - // We need to use glGetStringi to get the extension list - // if we are using GLES3 or a GL version greater than 2.1 - if (_GLVersion > 210 && GetFuncAddress("glGetStringi", (void**)&glGetStringi) == nullptr) - return false; - - InitExtensionList(); - - return InitFunctionPointers(); - } - - // Private initialization functions - static bool HasFeatures(const std::string& extensions) - { - bool result = true; - std::string tmp; - std::istringstream buffer(extensions); - - while (buffer >> tmp) - { - if (tmp[0] == '!') - result &= !m_extension_list[tmp.erase(0, 1)]; - else if (tmp[0] == '|') - result |= m_extension_list[tmp.erase(0, 1)]; - else - result &= m_extension_list[tmp]; - } - return result; - } - bool InitFunctionPointers() - { - bool result = true; - for (const auto &it : gl_function_array) - if (HasFeatures(it.requirements)) - result &= !!GetFuncAddress(it.function_name, it.function_ptr); - return result; - } + while (buffer >> tmp) + m_extension_list[tmp] = true; } +static void InitExtensionList() +{ + m_extension_list.clear(); + if (_isES) + { + switch (_GLVersion) + { + default: + case 320: + m_extension_list["VERSION_GLES_3_2"] = true; + case 310: + m_extension_list["VERSION_GLES_3_1"] = true; + case 300: + m_extension_list["VERSION_GLES_3"] = true; + break; + } + + // We always have ES 2.0 + m_extension_list["VERSION_GLES_2"] = true; + } + else + { + // Some OpenGL implementations chose to not expose core extensions as extensions + // Let's add them to the list manually depending on which version of OpenGL we have + // We need to be slightly careful here + // When an extension got merged in to core, the naming may have changed + + // This has intentional fall through + switch (_GLVersion) + { + default: + case 450: + { + std::string gl450exts[] = { + "GL_ARB_ES3_1_compatibility", + "GL_ARB_clip_control", + "GL_ARB_conditional_render_inverted", + "GL_ARB_cull_distance", + "GL_ARB_derivative_control", + "GL_ARB_direct_state_access", + "GL_ARB_get_texture_sub_image", + "GL_ARB_robustness", + "GL_ARB_shader_texture_image_samples", + "GL_ARB_texture_barrier", + "VERSION_4_5", + }; + for (auto it : gl450exts) + m_extension_list[it] = true; + } + case 440: + { + std::string gl440exts[] = { + "GL_ARB_buffer_storage", + "GL_ARB_clear_texture", + "GL_ARB_enhanced_layouts", + "GL_ARB_multi_bind", + "GL_ARB_query_buffer_object", + "GL_ARB_texture_mirror_clamp_to_edge", + "GL_ARB_texture_stencil8", + "GL_ARB_vertex_type_10f_11f_11f_rev", + "VERSION_4_4", + }; + for (auto it : gl440exts) + m_extension_list[it] = true; + } + case 430: + { + std::string gl430exts[] = { + "GL_ARB_ES3_compatibility", + "GL_ARB_arrays_of_arrays", + "GL_ARB_clear_buffer_object", + "GL_ARB_compute_shader", + "GL_ARB_copy_image", + "GL_ARB_explicit_uniform_location", + "GL_ARB_fragment_layer_viewport", + "GL_ARB_framebuffer_no_attachments", + "GL_ARB_internalformat_query2", + "GL_ARB_invalidate_subdata", + "GL_ARB_multi_draw_indirect", + "GL_ARB_program_interface_query", + "GL_ARB_shader_image_size", + "GL_ARB_shader_storage_buffer_object", + "GL_ARB_stencil_texturing", + "GL_ARB_texture_buffer_range", + "GL_ARB_texture_query_levels", + "GL_ARB_texture_storage_multisample", + "GL_ARB_texture_view", + "GL_ARB_vertex_attrib_binding", + "VERSION_4_3", + }; + for (auto it : gl430exts) + m_extension_list[it] = true; + } + case 420: + { + std::string gl420exts[] = { + "GL_ARB_base_instance", + "GL_ARB_compressed_texture_pixel_storage", + "GL_ARB_conservative_depth", + "GL_ARB_internalformat_query", + "GL_ARB_map_buffer_alignment", + "GL_ARB_shader_atomic_counters", + "GL_ARB_shader_image_load_store", + "GL_ARB_shading_language_420pack", + "GL_ARB_shading_language_packing", + "GL_ARB_texture_compression_BPTC", + "GL_ARB_texture_storage", + "GL_ARB_transform_feedback_instanced", + "VERSION_4_2", + }; + for (auto it : gl420exts) + m_extension_list[it] = true; + } + case 410: + { + std::string gl410exts[] = { + "GL_ARB_ES2_compatibility", + "GL_ARB_get_program_binary", + "GL_ARB_separate_shader_objects", + "GL_ARB_shader_precision", + "GL_ARB_vertex_attrib_64_bit", + "GL_ARB_viewport_array", + "VERSION_4_1", + }; + for (auto it : gl410exts) + m_extension_list[it] = true; + } + case 400: + { + std::string gl400exts[] = { + "GL_ARB_draw_indirect", + "GL_ARB_gpu_shader5", + "GL_ARB_gpu_shader_fp64", + "GL_ARB_sample_shading", + "GL_ARB_shader_subroutine", + "GL_ARB_tessellation_shader", + "GL_ARB_texture_buffer_object_rgb32", + "GL_ARB_texture_cube_map_array", + "GL_ARB_texture_gather", + "GL_ARB_texture_query_lod", + "GL_ARB_transform_feedback2", + "GL_ARB_transform_feedback3", + "VERSION_4_0", + }; + for (auto it : gl400exts) + m_extension_list[it] = true; + } + case 330: + { + std::string gl330exts[] = { + "GL_ARB_shader_bit_encoding", + "GL_ARB_blend_func_extended", + "GL_ARB_explicit_attrib_location", + "GL_ARB_occlusion_query2", + "GL_ARB_sampler_objects", + "GL_ARB_texture_swizzle", + "GL_ARB_timer_query", + "GL_ARB_instanced_arrays", + "GL_ARB_texture_rgb10_a2ui", + "GL_ARB_vertex_type_2_10_10_10_rev", + "VERSION_3_3", + }; + for (auto it : gl330exts) + m_extension_list[it] = true; + } + case 320: + { + std::string gl320exts[] = { + "GL_ARB_geometry_shader4", + "GL_ARB_sync", + "GL_ARB_vertex_array_bgra", + "GL_ARB_draw_elements_base_vertex", + "GL_ARB_seamless_cube_map", + "GL_ARB_texture_multisample", + "GL_ARB_fragment_coord_conventions", + "GL_ARB_provoking_vertex", + "GL_ARB_depth_clamp", + "VERSION_3_2", + }; + for (auto it : gl320exts) + m_extension_list[it] = true; + } + case 310: + { + // Can't add NV_primitive_restart since function name changed + std::string gl310exts[] = { + "GL_ARB_draw_instanced", "GL_ARB_copy_buffer", "GL_ARB_texture_buffer_object", + "GL_ARB_texture_rectangle", "GL_ARB_uniform_buffer_object", + //"GL_NV_primitive_restart", + "VERSION_3_1", + }; + for (auto it : gl310exts) + m_extension_list[it] = true; + } + case 300: + { + // Quite a lot of these had their names changed when merged in to core + // Disable the ones that have + std::string gl300exts[] = { + "GL_ARB_map_buffer_range", + //"GL_EXT_gpu_shader4", + //"GL_APPLE_flush_buffer_range", + "GL_ARB_color_buffer_float", + //"GL_NV_depth_buffer_float", + "GL_ARB_texture_float", + //"GL_EXT_packed_float", + //"GL_EXT_texture_shared_exponent", + "GL_ARB_half_float_pixel", + //"GL_NV_half_float", + "GL_ARB_framebuffer_object", + //"GL_EXT_framebuffer_sRGB", + "GL_ARB_texture_float", + //"GL_EXT_texture_integer", + //"GL_EXT_draw_buffers2", + //"GL_EXT_texture_integer", + //"GL_EXT_texture_array", + //"GL_EXT_texture_compression_rgtc", + //"GL_EXT_transform_feedback", + "GL_ARB_vertex_array_object", + //"GL_NV_conditional_render", + "VERSION_3_0", + }; + for (auto it : gl300exts) + m_extension_list[it] = true; + } + case 210: + case 200: + case 150: + case 140: + case 130: + case 121: + case 120: + case 110: + case 100: + break; + } + // So we can easily determine if we are running dekstop GL + m_extension_list["VERSION_GL"] = true; + } + + if (_GLVersion < 300) + { + InitExtensionList21(); + return; + } + GLint NumExtension = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &NumExtension); + for (GLint i = 0; i < NumExtension; ++i) + m_extension_list[std::string((const char*)glGetStringi(GL_EXTENSIONS, i))] = true; +} +static void InitVersion() +{ + GLint major, minor; + glGetIntegerv(GL_MAJOR_VERSION, &major); + glGetIntegerv(GL_MINOR_VERSION, &minor); + if (glGetError() == GL_NO_ERROR) + _GLVersion = major * 100 + minor * 10; + else + _GLVersion = 210; +} + +static void* GetFuncAddress(const std::string& name, void** func) +{ + *func = GLInterface->GetFuncAddress(name); + if (*func == nullptr) + { +#if defined(__linux__) || defined(__APPLE__) + // Give it a second try with dlsym + *func = dlsym(RTLD_NEXT, name.c_str()); +#endif + if (*func == nullptr) + ERROR_LOG(VIDEO, "Couldn't load function %s", name.c_str()); + } + return *func; +} + +// Public members +u32 Version() +{ + return _GLVersion; +} +bool Supports(const std::string& name) +{ + return m_extension_list[name]; +} + +bool Init() +{ + _isES = GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL; + + // Grab a few functions for initial checking + // We need them to grab the extension list + // Also to check if there is an error grabbing the version + if (GetFuncAddress("glGetIntegerv", (void**)&glGetIntegerv) == nullptr) + return false; + if (GetFuncAddress("glGetString", (void**)&glGetString) == nullptr) + return false; + if (GetFuncAddress("glGetError", (void**)&glGetError) == nullptr) + return false; + + InitVersion(); + + // We need to use glGetStringi to get the extension list + // if we are using GLES3 or a GL version greater than 2.1 + if (_GLVersion > 210 && GetFuncAddress("glGetStringi", (void**)&glGetStringi) == nullptr) + return false; + + InitExtensionList(); + + return InitFunctionPointers(); +} + +// Private initialization functions +static bool HasFeatures(const std::string& extensions) +{ + bool result = true; + std::string tmp; + std::istringstream buffer(extensions); + + while (buffer >> tmp) + { + if (tmp[0] == '!') + result &= !m_extension_list[tmp.erase(0, 1)]; + else if (tmp[0] == '|') + result |= m_extension_list[tmp.erase(0, 1)]; + else + result &= m_extension_list[tmp]; + } + return result; +} +bool InitFunctionPointers() +{ + bool result = true; + for (const auto& it : gl_function_array) + if (HasFeatures(it.requirements)) + result &= !!GetFuncAddress(it.function_name, it.function_ptr); + return result; +} +} diff --git a/Source/Core/Common/GL/GLExtensions/GLExtensions.h b/Source/Core/Common/GL/GLExtensions/GLExtensions.h index 3cfa6863b4..fa00aa4a97 100644 --- a/Source/Core/Common/GL/GLExtensions/GLExtensions.h +++ b/Source/Core/Common/GL/GLExtensions/GLExtensions.h @@ -7,14 +7,14 @@ #include "Common/CommonTypes.h" #include "Common/GL/GLExtensions/AMD_pinned_memory.h" +#include "Common/GL/GLExtensions/ARB_ES2_compatibility.h" +#include "Common/GL/GLExtensions/ARB_ES3_compatibility.h" #include "Common/GL/GLExtensions/ARB_blend_func_extended.h" #include "Common/GL/GLExtensions/ARB_buffer_storage.h" #include "Common/GL/GLExtensions/ARB_clip_control.h" #include "Common/GL/GLExtensions/ARB_copy_image.h" #include "Common/GL/GLExtensions/ARB_debug_output.h" #include "Common/GL/GLExtensions/ARB_draw_elements_base_vertex.h" -#include "Common/GL/GLExtensions/ARB_ES2_compatibility.h" -#include "Common/GL/GLExtensions/ARB_ES3_compatibility.h" #include "Common/GL/GLExtensions/ARB_framebuffer_object.h" #include "Common/GL/GLExtensions/ARB_get_program_binary.h" #include "Common/GL/GLExtensions/ARB_map_buffer_range.h" @@ -29,6 +29,10 @@ #include "Common/GL/GLExtensions/ARB_vertex_array_object.h" #include "Common/GL/GLExtensions/ARB_viewport_array.h" #include "Common/GL/GLExtensions/EXT_texture_filter_anisotropic.h" +#include "Common/GL/GLExtensions/HP_occlusion_test.h" +#include "Common/GL/GLExtensions/KHR_debug.h" +#include "Common/GL/GLExtensions/NV_occlusion_query_samples.h" +#include "Common/GL/GLExtensions/NV_primitive_restart.h" #include "Common/GL/GLExtensions/gl_1_1.h" #include "Common/GL/GLExtensions/gl_1_2.h" #include "Common/GL/GLExtensions/gl_1_3.h" @@ -43,20 +47,16 @@ #include "Common/GL/GLExtensions/gl_4_3.h" #include "Common/GL/GLExtensions/gl_4_4.h" #include "Common/GL/GLExtensions/gl_4_5.h" -#include "Common/GL/GLExtensions/HP_occlusion_test.h" -#include "Common/GL/GLExtensions/KHR_debug.h" -#include "Common/GL/GLExtensions/NV_occlusion_query_samples.h" -#include "Common/GL/GLExtensions/NV_primitive_restart.h" namespace GLExtensions { - // Initializes the interface - bool Init(); +// Initializes the interface +bool Init(); - // Function for checking if the hardware supports an extension - // example: if (GLExtensions::Supports("GL_ARB_multi_map")) - bool Supports(const std::string& name); +// Function for checking if the hardware supports an extension +// example: if (GLExtensions::Supports("GL_ARB_multi_map")) +bool Supports(const std::string& name); - // Returns OpenGL version in format 430 - u32 Version(); +// Returns OpenGL version in format 430 +u32 Version(); } diff --git a/Source/Core/Common/GL/GLExtensions/HP_occlusion_test.h b/Source/Core/Common/GL/GLExtensions/HP_occlusion_test.h index 4123c04423..633823a3ec 100644 --- a/Source/Core/Common/GL/GLExtensions/HP_occlusion_test.h +++ b/Source/Core/Common/GL/GLExtensions/HP_occlusion_test.h @@ -23,5 +23,5 @@ #include "Common/GL/GLExtensions/gl_common.h" -#define GL_OCCLUSION_TEST_HP 0x8165 -#define GL_OCCLUSION_TEST_RESULT_HP 0x8166 +#define GL_OCCLUSION_TEST_HP 0x8165 +#define GL_OCCLUSION_TEST_RESULT_HP 0x8166 diff --git a/Source/Core/Common/GL/GLExtensions/KHR_debug.h b/Source/Core/Common/GL/GLExtensions/KHR_debug.h index e7abcf1ddc..99ca0c2d2b 100644 --- a/Source/Core/Common/GL/GLExtensions/KHR_debug.h +++ b/Source/Core/Common/GL/GLExtensions/KHR_debug.h @@ -64,18 +64,31 @@ #define GL_DEBUG_SEVERITY_LOW 0x9148 #define GL_DEBUG_OUTPUT 0x92E0 -typedef void (APIENTRYP GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void(APIENTRYP GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, + GLsizei length, const GLchar* message, const void* userParam); -typedef void (APIENTRYP PFNDOLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const GLvoid *userParam); -typedef void (APIENTRYP PFNDOLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled); -typedef void (APIENTRYP PFNDOLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf); -typedef GLuint (APIENTRYP PFNDOLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufsize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog); -typedef void (APIENTRYP PFNDOLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei* length, GLchar *label); -typedef void (APIENTRYP PFNDOLGETOBJECTPTRLABELPROC) (void* ptr, GLsizei bufSize, GLsizei* length, GLchar *label); -typedef void (APIENTRYP PFNDOLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar* label); -typedef void (APIENTRYP PFNDOLOBJECTPTRLABELPROC) (void* ptr, GLsizei length, const GLchar* label); -typedef void (APIENTRYP PFNDOLPOPDEBUGGROUPPROC) (void); -typedef void (APIENTRYP PFNDOLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar * message); +typedef void(APIENTRYP PFNDOLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, + const GLvoid* userParam); +typedef void(APIENTRYP PFNDOLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, + GLsizei count, const GLuint* ids, + GLboolean enabled); +typedef void(APIENTRYP PFNDOLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, + GLenum severity, GLsizei length, + const GLchar* buf); +typedef GLuint(APIENTRYP PFNDOLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufsize, + GLenum* sources, GLenum* types, GLuint* ids, + GLenum* severities, GLsizei* lengths, + GLchar* messageLog); +typedef void(APIENTRYP PFNDOLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, + GLsizei* length, GLchar* label); +typedef void(APIENTRYP PFNDOLGETOBJECTPTRLABELPROC)(void* ptr, GLsizei bufSize, GLsizei* length, + GLchar* label); +typedef void(APIENTRYP PFNDOLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, + const GLchar* label); +typedef void(APIENTRYP PFNDOLOBJECTPTRLABELPROC)(void* ptr, GLsizei length, const GLchar* label); +typedef void(APIENTRYP PFNDOLPOPDEBUGGROUPPROC)(void); +typedef void(APIENTRYP PFNDOLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, + const GLchar* message); extern PFNDOLDEBUGMESSAGECALLBACKPROC dolDebugMessageCallback; extern PFNDOLDEBUGMESSAGECONTROLPROC dolDebugMessageControl; diff --git a/Source/Core/Common/GL/GLExtensions/NV_occlusion_query_samples.h b/Source/Core/Common/GL/GLExtensions/NV_occlusion_query_samples.h index 3f271702cc..4bf1f5c353 100644 --- a/Source/Core/Common/GL/GLExtensions/NV_occlusion_query_samples.h +++ b/Source/Core/Common/GL/GLExtensions/NV_occlusion_query_samples.h @@ -23,18 +23,18 @@ #include "Common/GL/GLExtensions/gl_common.h" -#define GL_PIXEL_COUNTER_BITS_NV 0x8864 -#define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 -#define GL_PIXEL_COUNT_NV 0x8866 -#define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 +#define GL_PIXEL_COUNTER_BITS_NV 0x8864 +#define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 +#define GL_PIXEL_COUNT_NV 0x8866 +#define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 -typedef void (APIENTRYP PFNDOLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNDOLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids); -typedef GLboolean (APIENTRYP PFNDOLISOCCLUSIONQUERYNVPROC) (GLuint id); -typedef void (APIENTRYP PFNDOLBEGINOCCLUSIONQUERYNVPROC) (GLuint id); -typedef void (APIENTRYP PFNDOLENDOCCLUSIONQUERYNVPROC) (void); -typedef void (APIENTRYP PFNDOLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params); +typedef void(APIENTRYP PFNDOLGENOCCLUSIONQUERIESNVPROC)(GLsizei n, GLuint* ids); +typedef void(APIENTRYP PFNDOLDELETEOCCLUSIONQUERIESNVPROC)(GLsizei n, const GLuint* ids); +typedef GLboolean(APIENTRYP PFNDOLISOCCLUSIONQUERYNVPROC)(GLuint id); +typedef void(APIENTRYP PFNDOLBEGINOCCLUSIONQUERYNVPROC)(GLuint id); +typedef void(APIENTRYP PFNDOLENDOCCLUSIONQUERYNVPROC)(void); +typedef void(APIENTRYP PFNDOLGETOCCLUSIONQUERYIVNVPROC)(GLuint id, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLGETOCCLUSIONQUERYUIVNVPROC)(GLuint id, GLenum pname, GLuint* params); extern PFNDOLGENOCCLUSIONQUERIESNVPROC dolGenOcclusionQueriesNV; extern PFNDOLDELETEOCCLUSIONQUERIESNVPROC dolDeleteOcclusionQueriesNV; diff --git a/Source/Core/Common/GL/GLExtensions/NV_primitive_restart.h b/Source/Core/Common/GL/GLExtensions/NV_primitive_restart.h index 917f12026d..0bed4bd430 100644 --- a/Source/Core/Common/GL/GLExtensions/NV_primitive_restart.h +++ b/Source/Core/Common/GL/GLExtensions/NV_primitive_restart.h @@ -26,8 +26,8 @@ #define GL_PRIMITIVE_RESTART_NV 0x8558 #define GL_PRIMITIVE_RESTART_INDEX_NV 0x8559 -typedef void (APIENTRYP PFNDOLPRIMITIVERESTARTINDEXNVPROC) (GLuint index); -typedef void (APIENTRYP PFNDOLPRIMITIVERESTARTNVPROC) (void); +typedef void(APIENTRYP PFNDOLPRIMITIVERESTARTINDEXNVPROC)(GLuint index); +typedef void(APIENTRYP PFNDOLPRIMITIVERESTARTNVPROC)(void); extern PFNDOLPRIMITIVERESTARTINDEXNVPROC dolPrimitiveRestartIndexNV; extern PFNDOLPRIMITIVERESTARTNVPROC dolPrimitiveRestartNV; diff --git a/Source/Core/Common/GL/GLExtensions/gl_1_1.h b/Source/Core/Common/GL/GLExtensions/gl_1_1.h index 52c622e7fd..2012a42fea 100644 --- a/Source/Core/Common/GL/GLExtensions/gl_1_1.h +++ b/Source/Core/Common/GL/GLExtensions/gl_1_1.h @@ -28,940 +28,984 @@ */ /* Boolean values */ -#define GL_FALSE 0 -#define GL_TRUE 1 +#define GL_FALSE 0 +#define GL_TRUE 1 /* Data types */ -#define GL_BYTE 0x1400 -#define GL_UNSIGNED_BYTE 0x1401 -#define GL_SHORT 0x1402 -#define GL_UNSIGNED_SHORT 0x1403 -#define GL_INT 0x1404 -#define GL_UNSIGNED_INT 0x1405 -#define GL_FLOAT 0x1406 -#define GL_2_BYTES 0x1407 -#define GL_3_BYTES 0x1408 -#define GL_4_BYTES 0x1409 -#define GL_DOUBLE 0x140A +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_2_BYTES 0x1407 +#define GL_3_BYTES 0x1408 +#define GL_4_BYTES 0x1409 +#define GL_DOUBLE 0x140A /* Primitives */ -#define GL_POINTS 0x0000 -#define GL_LINES 0x0001 -#define GL_LINE_LOOP 0x0002 -#define GL_LINE_STRIP 0x0003 -#define GL_TRIANGLES 0x0004 -#define GL_TRIANGLE_STRIP 0x0005 -#define GL_TRIANGLE_FAN 0x0006 -#define GL_QUADS 0x0007 -#define GL_QUAD_STRIP 0x0008 -#define GL_POLYGON 0x0009 +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_QUADS 0x0007 +#define GL_QUAD_STRIP 0x0008 +#define GL_POLYGON 0x0009 /* Vertex Arrays */ -#define GL_VERTEX_ARRAY 0x8074 -#define GL_NORMAL_ARRAY 0x8075 -#define GL_COLOR_ARRAY 0x8076 -#define GL_INDEX_ARRAY 0x8077 -#define GL_TEXTURE_COORD_ARRAY 0x8078 -#define GL_EDGE_FLAG_ARRAY 0x8079 -#define GL_VERTEX_ARRAY_SIZE 0x807A -#define GL_VERTEX_ARRAY_TYPE 0x807B -#define GL_VERTEX_ARRAY_STRIDE 0x807C -#define GL_NORMAL_ARRAY_TYPE 0x807E -#define GL_NORMAL_ARRAY_STRIDE 0x807F -#define GL_COLOR_ARRAY_SIZE 0x8081 -#define GL_COLOR_ARRAY_TYPE 0x8082 -#define GL_COLOR_ARRAY_STRIDE 0x8083 -#define GL_INDEX_ARRAY_TYPE 0x8085 -#define GL_INDEX_ARRAY_STRIDE 0x8086 -#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 -#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 -#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A -#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C -#define GL_VERTEX_ARRAY_POINTER 0x808E -#define GL_NORMAL_ARRAY_POINTER 0x808F -#define GL_COLOR_ARRAY_POINTER 0x8090 -#define GL_INDEX_ARRAY_POINTER 0x8091 -#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 -#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093 -#define GL_V2F 0x2A20 -#define GL_V3F 0x2A21 -#define GL_C4UB_V2F 0x2A22 -#define GL_C4UB_V3F 0x2A23 -#define GL_C3F_V3F 0x2A24 -#define GL_N3F_V3F 0x2A25 -#define GL_C4F_N3F_V3F 0x2A26 -#define GL_T2F_V3F 0x2A27 -#define GL_T4F_V4F 0x2A28 -#define GL_T2F_C4UB_V3F 0x2A29 -#define GL_T2F_C3F_V3F 0x2A2A -#define GL_T2F_N3F_V3F 0x2A2B -#define GL_T2F_C4F_N3F_V3F 0x2A2C -#define GL_T4F_C4F_N3F_V4F 0x2A2D +#define GL_VERTEX_ARRAY 0x8074 +#define GL_NORMAL_ARRAY 0x8075 +#define GL_COLOR_ARRAY 0x8076 +#define GL_INDEX_ARRAY 0x8077 +#define GL_TEXTURE_COORD_ARRAY 0x8078 +#define GL_EDGE_FLAG_ARRAY 0x8079 +#define GL_VERTEX_ARRAY_SIZE 0x807A +#define GL_VERTEX_ARRAY_TYPE 0x807B +#define GL_VERTEX_ARRAY_STRIDE 0x807C +#define GL_NORMAL_ARRAY_TYPE 0x807E +#define GL_NORMAL_ARRAY_STRIDE 0x807F +#define GL_COLOR_ARRAY_SIZE 0x8081 +#define GL_COLOR_ARRAY_TYPE 0x8082 +#define GL_COLOR_ARRAY_STRIDE 0x8083 +#define GL_INDEX_ARRAY_TYPE 0x8085 +#define GL_INDEX_ARRAY_STRIDE 0x8086 +#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 +#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 +#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A +#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C +#define GL_VERTEX_ARRAY_POINTER 0x808E +#define GL_NORMAL_ARRAY_POINTER 0x808F +#define GL_COLOR_ARRAY_POINTER 0x8090 +#define GL_INDEX_ARRAY_POINTER 0x8091 +#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 +#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093 +#define GL_V2F 0x2A20 +#define GL_V3F 0x2A21 +#define GL_C4UB_V2F 0x2A22 +#define GL_C4UB_V3F 0x2A23 +#define GL_C3F_V3F 0x2A24 +#define GL_N3F_V3F 0x2A25 +#define GL_C4F_N3F_V3F 0x2A26 +#define GL_T2F_V3F 0x2A27 +#define GL_T4F_V4F 0x2A28 +#define GL_T2F_C4UB_V3F 0x2A29 +#define GL_T2F_C3F_V3F 0x2A2A +#define GL_T2F_N3F_V3F 0x2A2B +#define GL_T2F_C4F_N3F_V3F 0x2A2C +#define GL_T4F_C4F_N3F_V4F 0x2A2D /* Matrix Mode */ -#define GL_MATRIX_MODE 0x0BA0 -#define GL_MODELVIEW 0x1700 -#define GL_PROJECTION 0x1701 -#define GL_TEXTURE 0x1702 +#define GL_MATRIX_MODE 0x0BA0 +#define GL_MODELVIEW 0x1700 +#define GL_PROJECTION 0x1701 +#define GL_TEXTURE 0x1702 /* Points */ -#define GL_POINT_SMOOTH 0x0B10 -#define GL_POINT_SIZE 0x0B11 -#define GL_POINT_SIZE_GRANULARITY 0x0B13 -#define GL_POINT_SIZE_RANGE 0x0B12 +#define GL_POINT_SMOOTH 0x0B10 +#define GL_POINT_SIZE 0x0B11 +#define GL_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_POINT_SIZE_RANGE 0x0B12 /* Lines */ -#define GL_LINE_SMOOTH 0x0B20 -#define GL_LINE_STIPPLE 0x0B24 -#define GL_LINE_STIPPLE_PATTERN 0x0B25 -#define GL_LINE_STIPPLE_REPEAT 0x0B26 -#define GL_LINE_WIDTH 0x0B21 -#define GL_LINE_WIDTH_GRANULARITY 0x0B23 -#define GL_LINE_WIDTH_RANGE 0x0B22 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_LINE_STIPPLE 0x0B24 +#define GL_LINE_STIPPLE_PATTERN 0x0B25 +#define GL_LINE_STIPPLE_REPEAT 0x0B26 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_LINE_WIDTH_RANGE 0x0B22 /* Polygons */ -#define GL_POINT 0x1B00 -#define GL_LINE 0x1B01 -#define GL_FILL 0x1B02 -#define GL_CW 0x0900 -#define GL_CCW 0x0901 -#define GL_FRONT 0x0404 -#define GL_BACK 0x0405 -#define GL_POLYGON_MODE 0x0B40 -#define GL_POLYGON_SMOOTH 0x0B41 -#define GL_POLYGON_STIPPLE 0x0B42 -#define GL_EDGE_FLAG 0x0B43 -#define GL_CULL_FACE 0x0B44 -#define GL_CULL_FACE_MODE 0x0B45 -#define GL_FRONT_FACE 0x0B46 -#define GL_POLYGON_OFFSET_FACTOR 0x8038 -#define GL_POLYGON_OFFSET_UNITS 0x2A00 -#define GL_POLYGON_OFFSET_POINT 0x2A01 -#define GL_POLYGON_OFFSET_LINE 0x2A02 -#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POINT 0x1B00 +#define GL_LINE 0x1B01 +#define GL_FILL 0x1B02 +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_POLYGON_MODE 0x0B40 +#define GL_POLYGON_SMOOTH 0x0B41 +#define GL_POLYGON_STIPPLE 0x0B42 +#define GL_EDGE_FLAG 0x0B43 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_FILL 0x8037 /* Display Lists */ -#define GL_COMPILE 0x1300 -#define GL_COMPILE_AND_EXECUTE 0x1301 -#define GL_LIST_BASE 0x0B32 -#define GL_LIST_INDEX 0x0B33 -#define GL_LIST_MODE 0x0B30 +#define GL_COMPILE 0x1300 +#define GL_COMPILE_AND_EXECUTE 0x1301 +#define GL_LIST_BASE 0x0B32 +#define GL_LIST_INDEX 0x0B33 +#define GL_LIST_MODE 0x0B30 /* Depth buffer */ -#define GL_NEVER 0x0200 -#define GL_LESS 0x0201 -#define GL_EQUAL 0x0202 -#define GL_LEQUAL 0x0203 -#define GL_GREATER 0x0204 -#define GL_NOTEQUAL 0x0205 -#define GL_GEQUAL 0x0206 -#define GL_ALWAYS 0x0207 -#define GL_DEPTH_TEST 0x0B71 -#define GL_DEPTH_BITS 0x0D56 -#define GL_DEPTH_CLEAR_VALUE 0x0B73 -#define GL_DEPTH_FUNC 0x0B74 -#define GL_DEPTH_RANGE 0x0B70 -#define GL_DEPTH_WRITEMASK 0x0B72 -#define GL_DEPTH_COMPONENT 0x1902 +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_BITS 0x0D56 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_COMPONENT 0x1902 /* Lighting */ -#define GL_LIGHTING 0x0B50 -#define GL_LIGHT0 0x4000 -#define GL_LIGHT1 0x4001 -#define GL_LIGHT2 0x4002 -#define GL_LIGHT3 0x4003 -#define GL_LIGHT4 0x4004 -#define GL_LIGHT5 0x4005 -#define GL_LIGHT6 0x4006 -#define GL_LIGHT7 0x4007 -#define GL_SPOT_EXPONENT 0x1205 -#define GL_SPOT_CUTOFF 0x1206 -#define GL_CONSTANT_ATTENUATION 0x1207 -#define GL_LINEAR_ATTENUATION 0x1208 -#define GL_QUADRATIC_ATTENUATION 0x1209 -#define GL_AMBIENT 0x1200 -#define GL_DIFFUSE 0x1201 -#define GL_SPECULAR 0x1202 -#define GL_SHININESS 0x1601 -#define GL_EMISSION 0x1600 -#define GL_POSITION 0x1203 -#define GL_SPOT_DIRECTION 0x1204 -#define GL_AMBIENT_AND_DIFFUSE 0x1602 -#define GL_COLOR_INDEXES 0x1603 -#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 -#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 -#define GL_LIGHT_MODEL_AMBIENT 0x0B53 -#define GL_FRONT_AND_BACK 0x0408 -#define GL_SHADE_MODEL 0x0B54 -#define GL_FLAT 0x1D00 -#define GL_SMOOTH 0x1D01 -#define GL_COLOR_MATERIAL 0x0B57 -#define GL_COLOR_MATERIAL_FACE 0x0B55 -#define GL_COLOR_MATERIAL_PARAMETER 0x0B56 -#define GL_NORMALIZE 0x0BA1 +#define GL_LIGHTING 0x0B50 +#define GL_LIGHT0 0x4000 +#define GL_LIGHT1 0x4001 +#define GL_LIGHT2 0x4002 +#define GL_LIGHT3 0x4003 +#define GL_LIGHT4 0x4004 +#define GL_LIGHT5 0x4005 +#define GL_LIGHT6 0x4006 +#define GL_LIGHT7 0x4007 +#define GL_SPOT_EXPONENT 0x1205 +#define GL_SPOT_CUTOFF 0x1206 +#define GL_CONSTANT_ATTENUATION 0x1207 +#define GL_LINEAR_ATTENUATION 0x1208 +#define GL_QUADRATIC_ATTENUATION 0x1209 +#define GL_AMBIENT 0x1200 +#define GL_DIFFUSE 0x1201 +#define GL_SPECULAR 0x1202 +#define GL_SHININESS 0x1601 +#define GL_EMISSION 0x1600 +#define GL_POSITION 0x1203 +#define GL_SPOT_DIRECTION 0x1204 +#define GL_AMBIENT_AND_DIFFUSE 0x1602 +#define GL_COLOR_INDEXES 0x1603 +#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 +#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 +#define GL_LIGHT_MODEL_AMBIENT 0x0B53 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_SHADE_MODEL 0x0B54 +#define GL_FLAT 0x1D00 +#define GL_SMOOTH 0x1D01 +#define GL_COLOR_MATERIAL 0x0B57 +#define GL_COLOR_MATERIAL_FACE 0x0B55 +#define GL_COLOR_MATERIAL_PARAMETER 0x0B56 +#define GL_NORMALIZE 0x0BA1 /* User clipping planes */ -#define GL_CLIP_PLANE0 0x3000 -#define GL_CLIP_PLANE1 0x3001 -#define GL_CLIP_PLANE2 0x3002 -#define GL_CLIP_PLANE3 0x3003 -#define GL_CLIP_PLANE4 0x3004 -#define GL_CLIP_PLANE5 0x3005 +#define GL_CLIP_PLANE0 0x3000 +#define GL_CLIP_PLANE1 0x3001 +#define GL_CLIP_PLANE2 0x3002 +#define GL_CLIP_PLANE3 0x3003 +#define GL_CLIP_PLANE4 0x3004 +#define GL_CLIP_PLANE5 0x3005 /* Accumulation buffer */ -#define GL_ACCUM_RED_BITS 0x0D58 -#define GL_ACCUM_GREEN_BITS 0x0D59 -#define GL_ACCUM_BLUE_BITS 0x0D5A -#define GL_ACCUM_ALPHA_BITS 0x0D5B -#define GL_ACCUM_CLEAR_VALUE 0x0B80 -#define GL_ACCUM 0x0100 -#define GL_ADD 0x0104 -#define GL_LOAD 0x0101 -#define GL_MULT 0x0103 -#define GL_RETURN 0x0102 +#define GL_ACCUM_RED_BITS 0x0D58 +#define GL_ACCUM_GREEN_BITS 0x0D59 +#define GL_ACCUM_BLUE_BITS 0x0D5A +#define GL_ACCUM_ALPHA_BITS 0x0D5B +#define GL_ACCUM_CLEAR_VALUE 0x0B80 +#define GL_ACCUM 0x0100 +#define GL_ADD 0x0104 +#define GL_LOAD 0x0101 +#define GL_MULT 0x0103 +#define GL_RETURN 0x0102 /* Alpha testing */ -#define GL_ALPHA_TEST 0x0BC0 -#define GL_ALPHA_TEST_REF 0x0BC2 -#define GL_ALPHA_TEST_FUNC 0x0BC1 +#define GL_ALPHA_TEST 0x0BC0 +#define GL_ALPHA_TEST_REF 0x0BC2 +#define GL_ALPHA_TEST_FUNC 0x0BC1 /* Blending */ -#define GL_BLEND 0x0BE2 -#define GL_BLEND_SRC 0x0BE1 -#define GL_BLEND_DST 0x0BE0 -#define GL_ZERO 0 -#define GL_ONE 1 -#define GL_SRC_COLOR 0x0300 -#define GL_ONE_MINUS_SRC_COLOR 0x0301 -#define GL_SRC_ALPHA 0x0302 -#define GL_ONE_MINUS_SRC_ALPHA 0x0303 -#define GL_DST_ALPHA 0x0304 -#define GL_ONE_MINUS_DST_ALPHA 0x0305 -#define GL_DST_COLOR 0x0306 -#define GL_ONE_MINUS_DST_COLOR 0x0307 -#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_BLEND 0x0BE2 +#define GL_BLEND_SRC 0x0BE1 +#define GL_BLEND_DST 0x0BE0 +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 /* Render Mode */ -#define GL_FEEDBACK 0x1C01 -#define GL_RENDER 0x1C00 -#define GL_SELECT 0x1C02 +#define GL_FEEDBACK 0x1C01 +#define GL_RENDER 0x1C00 +#define GL_SELECT 0x1C02 /* Feedback */ -#define GL_2D 0x0600 -#define GL_3D 0x0601 -#define GL_3D_COLOR 0x0602 -#define GL_3D_COLOR_TEXTURE 0x0603 -#define GL_4D_COLOR_TEXTURE 0x0604 -#define GL_POINT_TOKEN 0x0701 -#define GL_LINE_TOKEN 0x0702 -#define GL_LINE_RESET_TOKEN 0x0707 -#define GL_POLYGON_TOKEN 0x0703 -#define GL_BITMAP_TOKEN 0x0704 -#define GL_DRAW_PIXEL_TOKEN 0x0705 -#define GL_COPY_PIXEL_TOKEN 0x0706 -#define GL_PASS_THROUGH_TOKEN 0x0700 -#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0 -#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1 -#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2 +#define GL_2D 0x0600 +#define GL_3D 0x0601 +#define GL_3D_COLOR 0x0602 +#define GL_3D_COLOR_TEXTURE 0x0603 +#define GL_4D_COLOR_TEXTURE 0x0604 +#define GL_POINT_TOKEN 0x0701 +#define GL_LINE_TOKEN 0x0702 +#define GL_LINE_RESET_TOKEN 0x0707 +#define GL_POLYGON_TOKEN 0x0703 +#define GL_BITMAP_TOKEN 0x0704 +#define GL_DRAW_PIXEL_TOKEN 0x0705 +#define GL_COPY_PIXEL_TOKEN 0x0706 +#define GL_PASS_THROUGH_TOKEN 0x0700 +#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0 +#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1 +#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2 /* Selection */ -#define GL_SELECTION_BUFFER_POINTER 0x0DF3 -#define GL_SELECTION_BUFFER_SIZE 0x0DF4 +#define GL_SELECTION_BUFFER_POINTER 0x0DF3 +#define GL_SELECTION_BUFFER_SIZE 0x0DF4 /* Fog */ -#define GL_FOG 0x0B60 -#define GL_FOG_MODE 0x0B65 -#define GL_FOG_DENSITY 0x0B62 -#define GL_FOG_COLOR 0x0B66 -#define GL_FOG_INDEX 0x0B61 -#define GL_FOG_START 0x0B63 -#define GL_FOG_END 0x0B64 -#define GL_LINEAR 0x2601 -#define GL_EXP 0x0800 -#define GL_EXP2 0x0801 +#define GL_FOG 0x0B60 +#define GL_FOG_MODE 0x0B65 +#define GL_FOG_DENSITY 0x0B62 +#define GL_FOG_COLOR 0x0B66 +#define GL_FOG_INDEX 0x0B61 +#define GL_FOG_START 0x0B63 +#define GL_FOG_END 0x0B64 +#define GL_LINEAR 0x2601 +#define GL_EXP 0x0800 +#define GL_EXP2 0x0801 /* Logic Ops */ -#define GL_LOGIC_OP 0x0BF1 -#define GL_INDEX_LOGIC_OP 0x0BF1 -#define GL_COLOR_LOGIC_OP 0x0BF2 -#define GL_LOGIC_OP_MODE 0x0BF0 -#define GL_CLEAR 0x1500 -#define GL_SET 0x150F -#define GL_COPY 0x1503 -#define GL_COPY_INVERTED 0x150C -#define GL_NOOP 0x1505 -#define GL_INVERT 0x150A -#define GL_AND 0x1501 -#define GL_NAND 0x150E -#define GL_OR 0x1507 -#define GL_NOR 0x1508 -#define GL_XOR 0x1506 -#define GL_EQUIV 0x1509 -#define GL_AND_REVERSE 0x1502 -#define GL_AND_INVERTED 0x1504 -#define GL_OR_REVERSE 0x150B -#define GL_OR_INVERTED 0x150D +#define GL_LOGIC_OP 0x0BF1 +#define GL_INDEX_LOGIC_OP 0x0BF1 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_LOGIC_OP_MODE 0x0BF0 +#define GL_CLEAR 0x1500 +#define GL_SET 0x150F +#define GL_COPY 0x1503 +#define GL_COPY_INVERTED 0x150C +#define GL_NOOP 0x1505 +#define GL_INVERT 0x150A +#define GL_AND 0x1501 +#define GL_NAND 0x150E +#define GL_OR 0x1507 +#define GL_NOR 0x1508 +#define GL_XOR 0x1506 +#define GL_EQUIV 0x1509 +#define GL_AND_REVERSE 0x1502 +#define GL_AND_INVERTED 0x1504 +#define GL_OR_REVERSE 0x150B +#define GL_OR_INVERTED 0x150D /* Stencil */ -#define GL_STENCIL_BITS 0x0D57 -#define GL_STENCIL_TEST 0x0B90 -#define GL_STENCIL_CLEAR_VALUE 0x0B91 -#define GL_STENCIL_FUNC 0x0B92 -#define GL_STENCIL_VALUE_MASK 0x0B93 -#define GL_STENCIL_FAIL 0x0B94 -#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 -#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 -#define GL_STENCIL_REF 0x0B97 -#define GL_STENCIL_WRITEMASK 0x0B98 -#define GL_STENCIL_INDEX 0x1901 -#define GL_KEEP 0x1E00 -#define GL_REPLACE 0x1E01 -#define GL_INCR 0x1E02 -#define GL_DECR 0x1E03 +#define GL_STENCIL_BITS 0x0D57 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_STENCIL_INDEX 0x1901 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 /* Buffers, Pixel Drawing/Reading */ -#define GL_NONE 0 -#define GL_LEFT 0x0406 -#define GL_RIGHT 0x0407 +#define GL_NONE 0 +#define GL_LEFT 0x0406 +#define GL_RIGHT 0x0407 /*GL_FRONT 0x0404 */ /*GL_BACK 0x0405 */ /*GL_FRONT_AND_BACK 0x0408 */ -#define GL_FRONT_LEFT 0x0400 -#define GL_FRONT_RIGHT 0x0401 -#define GL_BACK_LEFT 0x0402 -#define GL_BACK_RIGHT 0x0403 -#define GL_AUX0 0x0409 -#define GL_AUX1 0x040A -#define GL_AUX2 0x040B -#define GL_AUX3 0x040C -#define GL_COLOR_INDEX 0x1900 -#define GL_RED 0x1903 -#define GL_GREEN 0x1904 -#define GL_BLUE 0x1905 -#define GL_ALPHA 0x1906 -#define GL_LUMINANCE 0x1909 -#define GL_LUMINANCE_ALPHA 0x190A -#define GL_ALPHA_BITS 0x0D55 -#define GL_RED_BITS 0x0D52 -#define GL_GREEN_BITS 0x0D53 -#define GL_BLUE_BITS 0x0D54 -#define GL_INDEX_BITS 0x0D51 -#define GL_SUBPIXEL_BITS 0x0D50 -#define GL_AUX_BUFFERS 0x0C00 -#define GL_READ_BUFFER 0x0C02 -#define GL_DRAW_BUFFER 0x0C01 -#define GL_DOUBLEBUFFER 0x0C32 -#define GL_STEREO 0x0C33 -#define GL_BITMAP 0x1A00 -#define GL_COLOR 0x1800 -#define GL_DEPTH 0x1801 -#define GL_STENCIL 0x1802 -#define GL_DITHER 0x0BD0 -#define GL_RGB 0x1907 -#define GL_RGBA 0x1908 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 +#define GL_BACK_LEFT 0x0402 +#define GL_BACK_RIGHT 0x0403 +#define GL_AUX0 0x0409 +#define GL_AUX1 0x040A +#define GL_AUX2 0x040B +#define GL_AUX3 0x040C +#define GL_COLOR_INDEX 0x1900 +#define GL_RED 0x1903 +#define GL_GREEN 0x1904 +#define GL_BLUE 0x1905 +#define GL_ALPHA 0x1906 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_ALPHA_BITS 0x0D55 +#define GL_RED_BITS 0x0D52 +#define GL_GREEN_BITS 0x0D53 +#define GL_BLUE_BITS 0x0D54 +#define GL_INDEX_BITS 0x0D51 +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_AUX_BUFFERS 0x0C00 +#define GL_READ_BUFFER 0x0C02 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_DOUBLEBUFFER 0x0C32 +#define GL_STEREO 0x0C33 +#define GL_BITMAP 0x1A00 +#define GL_COLOR 0x1800 +#define GL_DEPTH 0x1801 +#define GL_STENCIL 0x1802 +#define GL_DITHER 0x0BD0 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 /* Implementation limits */ -#define GL_MAX_LIST_NESTING 0x0B31 -#define GL_MAX_EVAL_ORDER 0x0D30 -#define GL_MAX_LIGHTS 0x0D31 -#define GL_MAX_CLIP_PLANES 0x0D32 -#define GL_MAX_TEXTURE_SIZE 0x0D33 -#define GL_MAX_PIXEL_MAP_TABLE 0x0D34 -#define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35 -#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 -#define GL_MAX_NAME_STACK_DEPTH 0x0D37 -#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 -#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 -#define GL_MAX_VIEWPORT_DIMS 0x0D3A -#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B +#define GL_MAX_LIST_NESTING 0x0B31 +#define GL_MAX_EVAL_ORDER 0x0D30 +#define GL_MAX_LIGHTS 0x0D31 +#define GL_MAX_CLIP_PLANES 0x0D32 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_PIXEL_MAP_TABLE 0x0D34 +#define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35 +#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 +#define GL_MAX_NAME_STACK_DEPTH 0x0D37 +#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 +#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B /* Gets */ -#define GL_ATTRIB_STACK_DEPTH 0x0BB0 -#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 -#define GL_COLOR_CLEAR_VALUE 0x0C22 -#define GL_COLOR_WRITEMASK 0x0C23 -#define GL_CURRENT_INDEX 0x0B01 -#define GL_CURRENT_COLOR 0x0B00 -#define GL_CURRENT_NORMAL 0x0B02 -#define GL_CURRENT_RASTER_COLOR 0x0B04 -#define GL_CURRENT_RASTER_DISTANCE 0x0B09 -#define GL_CURRENT_RASTER_INDEX 0x0B05 -#define GL_CURRENT_RASTER_POSITION 0x0B07 -#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06 -#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08 -#define GL_CURRENT_TEXTURE_COORDS 0x0B03 -#define GL_INDEX_CLEAR_VALUE 0x0C20 -#define GL_INDEX_MODE 0x0C30 -#define GL_INDEX_WRITEMASK 0x0C21 -#define GL_MODELVIEW_MATRIX 0x0BA6 -#define GL_MODELVIEW_STACK_DEPTH 0x0BA3 -#define GL_NAME_STACK_DEPTH 0x0D70 -#define GL_PROJECTION_MATRIX 0x0BA7 -#define GL_PROJECTION_STACK_DEPTH 0x0BA4 -#define GL_RENDER_MODE 0x0C40 -#define GL_RGBA_MODE 0x0C31 -#define GL_TEXTURE_MATRIX 0x0BA8 -#define GL_TEXTURE_STACK_DEPTH 0x0BA5 -#define GL_VIEWPORT 0x0BA2 +#define GL_ATTRIB_STACK_DEPTH 0x0BB0 +#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_CURRENT_INDEX 0x0B01 +#define GL_CURRENT_COLOR 0x0B00 +#define GL_CURRENT_NORMAL 0x0B02 +#define GL_CURRENT_RASTER_COLOR 0x0B04 +#define GL_CURRENT_RASTER_DISTANCE 0x0B09 +#define GL_CURRENT_RASTER_INDEX 0x0B05 +#define GL_CURRENT_RASTER_POSITION 0x0B07 +#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06 +#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08 +#define GL_CURRENT_TEXTURE_COORDS 0x0B03 +#define GL_INDEX_CLEAR_VALUE 0x0C20 +#define GL_INDEX_MODE 0x0C30 +#define GL_INDEX_WRITEMASK 0x0C21 +#define GL_MODELVIEW_MATRIX 0x0BA6 +#define GL_MODELVIEW_STACK_DEPTH 0x0BA3 +#define GL_NAME_STACK_DEPTH 0x0D70 +#define GL_PROJECTION_MATRIX 0x0BA7 +#define GL_PROJECTION_STACK_DEPTH 0x0BA4 +#define GL_RENDER_MODE 0x0C40 +#define GL_RGBA_MODE 0x0C31 +#define GL_TEXTURE_MATRIX 0x0BA8 +#define GL_TEXTURE_STACK_DEPTH 0x0BA5 +#define GL_VIEWPORT 0x0BA2 /* Evaluators */ -#define GL_AUTO_NORMAL 0x0D80 -#define GL_MAP1_COLOR_4 0x0D90 -#define GL_MAP1_INDEX 0x0D91 -#define GL_MAP1_NORMAL 0x0D92 -#define GL_MAP1_TEXTURE_COORD_1 0x0D93 -#define GL_MAP1_TEXTURE_COORD_2 0x0D94 -#define GL_MAP1_TEXTURE_COORD_3 0x0D95 -#define GL_MAP1_TEXTURE_COORD_4 0x0D96 -#define GL_MAP1_VERTEX_3 0x0D97 -#define GL_MAP1_VERTEX_4 0x0D98 -#define GL_MAP2_COLOR_4 0x0DB0 -#define GL_MAP2_INDEX 0x0DB1 -#define GL_MAP2_NORMAL 0x0DB2 -#define GL_MAP2_TEXTURE_COORD_1 0x0DB3 -#define GL_MAP2_TEXTURE_COORD_2 0x0DB4 -#define GL_MAP2_TEXTURE_COORD_3 0x0DB5 -#define GL_MAP2_TEXTURE_COORD_4 0x0DB6 -#define GL_MAP2_VERTEX_3 0x0DB7 -#define GL_MAP2_VERTEX_4 0x0DB8 -#define GL_MAP1_GRID_DOMAIN 0x0DD0 -#define GL_MAP1_GRID_SEGMENTS 0x0DD1 -#define GL_MAP2_GRID_DOMAIN 0x0DD2 -#define GL_MAP2_GRID_SEGMENTS 0x0DD3 -#define GL_COEFF 0x0A00 -#define GL_ORDER 0x0A01 -#define GL_DOMAIN 0x0A02 +#define GL_AUTO_NORMAL 0x0D80 +#define GL_MAP1_COLOR_4 0x0D90 +#define GL_MAP1_INDEX 0x0D91 +#define GL_MAP1_NORMAL 0x0D92 +#define GL_MAP1_TEXTURE_COORD_1 0x0D93 +#define GL_MAP1_TEXTURE_COORD_2 0x0D94 +#define GL_MAP1_TEXTURE_COORD_3 0x0D95 +#define GL_MAP1_TEXTURE_COORD_4 0x0D96 +#define GL_MAP1_VERTEX_3 0x0D97 +#define GL_MAP1_VERTEX_4 0x0D98 +#define GL_MAP2_COLOR_4 0x0DB0 +#define GL_MAP2_INDEX 0x0DB1 +#define GL_MAP2_NORMAL 0x0DB2 +#define GL_MAP2_TEXTURE_COORD_1 0x0DB3 +#define GL_MAP2_TEXTURE_COORD_2 0x0DB4 +#define GL_MAP2_TEXTURE_COORD_3 0x0DB5 +#define GL_MAP2_TEXTURE_COORD_4 0x0DB6 +#define GL_MAP2_VERTEX_3 0x0DB7 +#define GL_MAP2_VERTEX_4 0x0DB8 +#define GL_MAP1_GRID_DOMAIN 0x0DD0 +#define GL_MAP1_GRID_SEGMENTS 0x0DD1 +#define GL_MAP2_GRID_DOMAIN 0x0DD2 +#define GL_MAP2_GRID_SEGMENTS 0x0DD3 +#define GL_COEFF 0x0A00 +#define GL_ORDER 0x0A01 +#define GL_DOMAIN 0x0A02 /* Hints */ -#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 -#define GL_POINT_SMOOTH_HINT 0x0C51 -#define GL_LINE_SMOOTH_HINT 0x0C52 -#define GL_POLYGON_SMOOTH_HINT 0x0C53 -#define GL_FOG_HINT 0x0C54 -#define GL_DONT_CARE 0x1100 -#define GL_FASTEST 0x1101 -#define GL_NICEST 0x1102 +#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 +#define GL_POINT_SMOOTH_HINT 0x0C51 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_FOG_HINT 0x0C54 +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 /* Scissor box */ -#define GL_SCISSOR_BOX 0x0C10 -#define GL_SCISSOR_TEST 0x0C11 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 /* Pixel Mode / Transfer */ -#define GL_MAP_COLOR 0x0D10 -#define GL_MAP_STENCIL 0x0D11 -#define GL_INDEX_SHIFT 0x0D12 -#define GL_INDEX_OFFSET 0x0D13 -#define GL_RED_SCALE 0x0D14 -#define GL_RED_BIAS 0x0D15 -#define GL_GREEN_SCALE 0x0D18 -#define GL_GREEN_BIAS 0x0D19 -#define GL_BLUE_SCALE 0x0D1A -#define GL_BLUE_BIAS 0x0D1B -#define GL_ALPHA_SCALE 0x0D1C -#define GL_ALPHA_BIAS 0x0D1D -#define GL_DEPTH_SCALE 0x0D1E -#define GL_DEPTH_BIAS 0x0D1F -#define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1 -#define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0 -#define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2 -#define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3 -#define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4 -#define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5 -#define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6 -#define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7 -#define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8 -#define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9 -#define GL_PIXEL_MAP_S_TO_S 0x0C71 -#define GL_PIXEL_MAP_I_TO_I 0x0C70 -#define GL_PIXEL_MAP_I_TO_R 0x0C72 -#define GL_PIXEL_MAP_I_TO_G 0x0C73 -#define GL_PIXEL_MAP_I_TO_B 0x0C74 -#define GL_PIXEL_MAP_I_TO_A 0x0C75 -#define GL_PIXEL_MAP_R_TO_R 0x0C76 -#define GL_PIXEL_MAP_G_TO_G 0x0C77 -#define GL_PIXEL_MAP_B_TO_B 0x0C78 -#define GL_PIXEL_MAP_A_TO_A 0x0C79 -#define GL_PACK_ALIGNMENT 0x0D05 -#define GL_PACK_LSB_FIRST 0x0D01 -#define GL_PACK_ROW_LENGTH 0x0D02 -#define GL_PACK_SKIP_PIXELS 0x0D04 -#define GL_PACK_SKIP_ROWS 0x0D03 -#define GL_PACK_SWAP_BYTES 0x0D00 -#define GL_UNPACK_ALIGNMENT 0x0CF5 -#define GL_UNPACK_LSB_FIRST 0x0CF1 -#define GL_UNPACK_ROW_LENGTH 0x0CF2 -#define GL_UNPACK_SKIP_PIXELS 0x0CF4 -#define GL_UNPACK_SKIP_ROWS 0x0CF3 -#define GL_UNPACK_SWAP_BYTES 0x0CF0 -#define GL_ZOOM_X 0x0D16 -#define GL_ZOOM_Y 0x0D17 +#define GL_MAP_COLOR 0x0D10 +#define GL_MAP_STENCIL 0x0D11 +#define GL_INDEX_SHIFT 0x0D12 +#define GL_INDEX_OFFSET 0x0D13 +#define GL_RED_SCALE 0x0D14 +#define GL_RED_BIAS 0x0D15 +#define GL_GREEN_SCALE 0x0D18 +#define GL_GREEN_BIAS 0x0D19 +#define GL_BLUE_SCALE 0x0D1A +#define GL_BLUE_BIAS 0x0D1B +#define GL_ALPHA_SCALE 0x0D1C +#define GL_ALPHA_BIAS 0x0D1D +#define GL_DEPTH_SCALE 0x0D1E +#define GL_DEPTH_BIAS 0x0D1F +#define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1 +#define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0 +#define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2 +#define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3 +#define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4 +#define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5 +#define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6 +#define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7 +#define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8 +#define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9 +#define GL_PIXEL_MAP_S_TO_S 0x0C71 +#define GL_PIXEL_MAP_I_TO_I 0x0C70 +#define GL_PIXEL_MAP_I_TO_R 0x0C72 +#define GL_PIXEL_MAP_I_TO_G 0x0C73 +#define GL_PIXEL_MAP_I_TO_B 0x0C74 +#define GL_PIXEL_MAP_I_TO_A 0x0C75 +#define GL_PIXEL_MAP_R_TO_R 0x0C76 +#define GL_PIXEL_MAP_G_TO_G 0x0C77 +#define GL_PIXEL_MAP_B_TO_B 0x0C78 +#define GL_PIXEL_MAP_A_TO_A 0x0C79 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_PACK_LSB_FIRST 0x0D01 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SWAP_BYTES 0x0D00 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_UNPACK_LSB_FIRST 0x0CF1 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SWAP_BYTES 0x0CF0 +#define GL_ZOOM_X 0x0D16 +#define GL_ZOOM_Y 0x0D17 /* Texture mapping */ -#define GL_TEXTURE_ENV 0x2300 -#define GL_TEXTURE_ENV_MODE 0x2200 -#define GL_TEXTURE_1D 0x0DE0 -#define GL_TEXTURE_2D 0x0DE1 -#define GL_TEXTURE_WRAP_S 0x2802 -#define GL_TEXTURE_WRAP_T 0x2803 -#define GL_TEXTURE_MAG_FILTER 0x2800 -#define GL_TEXTURE_MIN_FILTER 0x2801 -#define GL_TEXTURE_ENV_COLOR 0x2201 -#define GL_TEXTURE_GEN_S 0x0C60 -#define GL_TEXTURE_GEN_T 0x0C61 -#define GL_TEXTURE_GEN_R 0x0C62 -#define GL_TEXTURE_GEN_Q 0x0C63 -#define GL_TEXTURE_GEN_MODE 0x2500 -#define GL_TEXTURE_BORDER_COLOR 0x1004 -#define GL_TEXTURE_WIDTH 0x1000 -#define GL_TEXTURE_HEIGHT 0x1001 -#define GL_TEXTURE_BORDER 0x1005 -#define GL_TEXTURE_COMPONENTS 0x1003 -#define GL_TEXTURE_RED_SIZE 0x805C -#define GL_TEXTURE_GREEN_SIZE 0x805D -#define GL_TEXTURE_BLUE_SIZE 0x805E -#define GL_TEXTURE_ALPHA_SIZE 0x805F -#define GL_TEXTURE_LUMINANCE_SIZE 0x8060 -#define GL_TEXTURE_INTENSITY_SIZE 0x8061 -#define GL_NEAREST_MIPMAP_NEAREST 0x2700 -#define GL_NEAREST_MIPMAP_LINEAR 0x2702 -#define GL_LINEAR_MIPMAP_NEAREST 0x2701 -#define GL_LINEAR_MIPMAP_LINEAR 0x2703 -#define GL_OBJECT_LINEAR 0x2401 -#define GL_OBJECT_PLANE 0x2501 -#define GL_EYE_LINEAR 0x2400 -#define GL_EYE_PLANE 0x2502 -#define GL_SPHERE_MAP 0x2402 -#define GL_DECAL 0x2101 -#define GL_MODULATE 0x2100 -#define GL_NEAREST 0x2600 -#define GL_REPEAT 0x2901 -#define GL_CLAMP 0x2900 -#define GL_S 0x2000 -#define GL_T 0x2001 -#define GL_R 0x2002 -#define GL_Q 0x2003 +#define GL_TEXTURE_ENV 0x2300 +#define GL_TEXTURE_ENV_MODE 0x2200 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_ENV_COLOR 0x2201 +#define GL_TEXTURE_GEN_S 0x0C60 +#define GL_TEXTURE_GEN_T 0x0C61 +#define GL_TEXTURE_GEN_R 0x0C62 +#define GL_TEXTURE_GEN_Q 0x0C63 +#define GL_TEXTURE_GEN_MODE 0x2500 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_TEXTURE_WIDTH 0x1000 +#define GL_TEXTURE_HEIGHT 0x1001 +#define GL_TEXTURE_BORDER 0x1005 +#define GL_TEXTURE_COMPONENTS 0x1003 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_GREEN_SIZE 0x805D +#define GL_TEXTURE_BLUE_SIZE 0x805E +#define GL_TEXTURE_ALPHA_SIZE 0x805F +#define GL_TEXTURE_LUMINANCE_SIZE 0x8060 +#define GL_TEXTURE_INTENSITY_SIZE 0x8061 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_OBJECT_LINEAR 0x2401 +#define GL_OBJECT_PLANE 0x2501 +#define GL_EYE_LINEAR 0x2400 +#define GL_EYE_PLANE 0x2502 +#define GL_SPHERE_MAP 0x2402 +#define GL_DECAL 0x2101 +#define GL_MODULATE 0x2100 +#define GL_NEAREST 0x2600 +#define GL_REPEAT 0x2901 +#define GL_CLAMP 0x2900 +#define GL_S 0x2000 +#define GL_T 0x2001 +#define GL_R 0x2002 +#define GL_Q 0x2003 /* Utility */ -#define GL_VENDOR 0x1F00 -#define GL_RENDERER 0x1F01 -#define GL_VERSION 0x1F02 -#define GL_EXTENSIONS 0x1F03 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 /* Errors */ -#define GL_NO_ERROR 0 -#define GL_INVALID_ENUM 0x0500 -#define GL_INVALID_VALUE 0x0501 -#define GL_INVALID_OPERATION 0x0502 -#define GL_STACK_OVERFLOW 0x0503 -#define GL_STACK_UNDERFLOW 0x0504 -#define GL_OUT_OF_MEMORY 0x0505 +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_STACK_OVERFLOW 0x0503 +#define GL_STACK_UNDERFLOW 0x0504 +#define GL_OUT_OF_MEMORY 0x0505 /* glPush/PopAttrib bits */ -#define GL_CURRENT_BIT 0x00000001 -#define GL_POINT_BIT 0x00000002 -#define GL_LINE_BIT 0x00000004 -#define GL_POLYGON_BIT 0x00000008 -#define GL_POLYGON_STIPPLE_BIT 0x00000010 -#define GL_PIXEL_MODE_BIT 0x00000020 -#define GL_LIGHTING_BIT 0x00000040 -#define GL_FOG_BIT 0x00000080 -#define GL_DEPTH_BUFFER_BIT 0x00000100 -#define GL_ACCUM_BUFFER_BIT 0x00000200 -#define GL_STENCIL_BUFFER_BIT 0x00000400 -#define GL_VIEWPORT_BIT 0x00000800 -#define GL_TRANSFORM_BIT 0x00001000 -#define GL_ENABLE_BIT 0x00002000 -#define GL_COLOR_BUFFER_BIT 0x00004000 -#define GL_HINT_BIT 0x00008000 -#define GL_EVAL_BIT 0x00010000 -#define GL_LIST_BIT 0x00020000 -#define GL_TEXTURE_BIT 0x00040000 -#define GL_SCISSOR_BIT 0x00080000 -#define GL_ALL_ATTRIB_BITS 0x000FFFFF - +#define GL_CURRENT_BIT 0x00000001 +#define GL_POINT_BIT 0x00000002 +#define GL_LINE_BIT 0x00000004 +#define GL_POLYGON_BIT 0x00000008 +#define GL_POLYGON_STIPPLE_BIT 0x00000010 +#define GL_PIXEL_MODE_BIT 0x00000020 +#define GL_LIGHTING_BIT 0x00000040 +#define GL_FOG_BIT 0x00000080 +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_ACCUM_BUFFER_BIT 0x00000200 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_VIEWPORT_BIT 0x00000800 +#define GL_TRANSFORM_BIT 0x00001000 +#define GL_ENABLE_BIT 0x00002000 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_HINT_BIT 0x00008000 +#define GL_EVAL_BIT 0x00010000 +#define GL_LIST_BIT 0x00020000 +#define GL_TEXTURE_BIT 0x00040000 +#define GL_SCISSOR_BIT 0x00080000 +#define GL_ALL_ATTRIB_BITS 0x000FFFFF /* OpenGL 1.1 */ -#define GL_PROXY_TEXTURE_1D 0x8063 -#define GL_PROXY_TEXTURE_2D 0x8064 -#define GL_TEXTURE_PRIORITY 0x8066 -#define GL_TEXTURE_RESIDENT 0x8067 -#define GL_TEXTURE_BINDING_1D 0x8068 -#define GL_TEXTURE_BINDING_2D 0x8069 -#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 -#define GL_ALPHA4 0x803B -#define GL_ALPHA8 0x803C -#define GL_ALPHA12 0x803D -#define GL_ALPHA16 0x803E -#define GL_LUMINANCE4 0x803F -#define GL_LUMINANCE8 0x8040 -#define GL_LUMINANCE12 0x8041 -#define GL_LUMINANCE16 0x8042 -#define GL_LUMINANCE4_ALPHA4 0x8043 -#define GL_LUMINANCE6_ALPHA2 0x8044 -#define GL_LUMINANCE8_ALPHA8 0x8045 -#define GL_LUMINANCE12_ALPHA4 0x8046 -#define GL_LUMINANCE12_ALPHA12 0x8047 -#define GL_LUMINANCE16_ALPHA16 0x8048 -#define GL_INTENSITY 0x8049 -#define GL_INTENSITY4 0x804A -#define GL_INTENSITY8 0x804B -#define GL_INTENSITY12 0x804C -#define GL_INTENSITY16 0x804D -#define GL_R3_G3_B2 0x2A10 -#define GL_RGB4 0x804F -#define GL_RGB5 0x8050 -#define GL_RGB8 0x8051 -#define GL_RGB10 0x8052 -#define GL_RGB12 0x8053 -#define GL_RGB16 0x8054 -#define GL_RGBA2 0x8055 -#define GL_RGBA4 0x8056 -#define GL_RGB5_A1 0x8057 -#define GL_RGBA8 0x8058 -#define GL_RGB10_A2 0x8059 -#define GL_RGBA12 0x805A -#define GL_RGBA16 0x805B -#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001 -#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 -#define GL_ALL_CLIENT_ATTRIB_BITS 0xFFFFFFFF -#define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF +#define GL_PROXY_TEXTURE_1D 0x8063 +#define GL_PROXY_TEXTURE_2D 0x8064 +#define GL_TEXTURE_PRIORITY 0x8066 +#define GL_TEXTURE_RESIDENT 0x8067 +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_ALPHA4 0x803B +#define GL_ALPHA8 0x803C +#define GL_ALPHA12 0x803D +#define GL_ALPHA16 0x803E +#define GL_LUMINANCE4 0x803F +#define GL_LUMINANCE8 0x8040 +#define GL_LUMINANCE12 0x8041 +#define GL_LUMINANCE16 0x8042 +#define GL_LUMINANCE4_ALPHA4 0x8043 +#define GL_LUMINANCE6_ALPHA2 0x8044 +#define GL_LUMINANCE8_ALPHA8 0x8045 +#define GL_LUMINANCE12_ALPHA4 0x8046 +#define GL_LUMINANCE12_ALPHA12 0x8047 +#define GL_LUMINANCE16_ALPHA16 0x8048 +#define GL_INTENSITY 0x8049 +#define GL_INTENSITY4 0x804A +#define GL_INTENSITY8 0x804B +#define GL_INTENSITY12 0x804C +#define GL_INTENSITY16 0x804D +#define GL_R3_G3_B2 0x2A10 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB8 0x8051 +#define GL_RGB10 0x8052 +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGBA2 0x8055 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#define GL_CLIENT_PIXEL_STORE_BIT 0x00000001 +#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 +#define GL_ALL_CLIENT_ATTRIB_BITS 0xFFFFFFFF +#define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF -typedef void (APIENTRYP PFNDOLCLEARINDEXPROC) ( GLfloat c ); -typedef void (APIENTRYP PFNDOLCLEARCOLORPROC) ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ); -typedef void (APIENTRYP PFNDOLCLEARPROC) ( GLbitfield mask ); -typedef void (APIENTRYP PFNDOLINDEXMASKPROC) ( GLuint mask ); -typedef void (APIENTRYP PFNDOLCOLORMASKPROC) ( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha ); -typedef void (APIENTRYP PFNDOLALPHAFUNCPROC) ( GLenum func, GLclampf ref ); -typedef void (APIENTRYP PFNDOLBLENDFUNCPROC) ( GLenum sfactor, GLenum dfactor ); -typedef void (APIENTRYP PFNDOLLOGICOPPROC) ( GLenum opcode ); -typedef void (APIENTRYP PFNDOLCULLFACEPROC) ( GLenum mode ); -typedef void (APIENTRYP PFNDOLFRONTFACEPROC) ( GLenum mode ); -typedef void (APIENTRYP PFNDOLPOINTSIZEPROC) ( GLfloat size ); -typedef void (APIENTRYP PFNDOLLINEWIDTHPROC) ( GLfloat width ); -typedef void (APIENTRYP PFNDOLLINESTIPPLEPROC) ( GLint factor, GLushort pattern ); -typedef void (APIENTRYP PFNDOLPOLYGONMODEPROC) ( GLenum face, GLenum mode ); -typedef void (APIENTRYP PFNDOLPOLYGONOFFSETPROC) ( GLfloat factor, GLfloat units ); -typedef void (APIENTRYP PFNDOLPOLYGONSTIPPLEPROC) ( const GLubyte *mask ); -typedef void (APIENTRYP PFNDOLGETPOLYGONSTIPPLEPROC) ( GLubyte *mask ); -typedef void (APIENTRYP PFNDOLEDGEFLAGPROC) ( GLboolean flag ); -typedef void (APIENTRYP PFNDOLEDGEFLAGVPROC) ( const GLboolean *flag ); -typedef void (APIENTRYP PFNDOLSCISSORPROC) ( GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNDOLCLIPPLANEPROC) ( GLenum plane, const GLdouble *equation ); -typedef void (APIENTRYP PFNDOLGETCLIPPLANEPROC) ( GLenum plane, GLdouble *equation ); -typedef void (APIENTRYP PFNDOLDRAWBUFFERPROC) ( GLenum mode ); -typedef void (APIENTRYP PFNDOLREADBUFFERPROC) ( GLenum mode ); -typedef void (APIENTRYP PFNDOLENABLEPROC) ( GLenum cap ); -typedef void (APIENTRYP PFNDOLDISABLEPROC) ( GLenum cap ); -typedef GLboolean (APIENTRYP PFNDOLISENABLEDPROC) ( GLenum cap ); -typedef void (APIENTRYP PFNDOLENABLECLIENTSTATEPROC) ( GLenum cap ); /* 1.1 */ -typedef void (APIENTRYP PFNDOLDISABLECLIENTSTATEPROC) ( GLenum cap ); /* 1.1 */ -typedef void (APIENTRYP PFNDOLGETBOOLEANVPROC) ( GLenum pname, GLboolean *params ); -typedef void (APIENTRYP PFNDOLGETDOUBLEVPROC) ( GLenum pname, GLdouble *params ); -typedef void (APIENTRYP PFNDOLGETFLOATVPROC) ( GLenum pname, GLfloat *params ); -typedef void (APIENTRYP PFNDOLGETINTEGERVPROC) ( GLenum pname, GLint *params ); -typedef void (APIENTRYP PFNDOLPUSHATTRIBPROC) ( GLbitfield mask ); -typedef void (APIENTRYP PFNDOLPOPATTRIBPROC) ( void ); -typedef void (APIENTRYP PFNDOLPUSHCLIENTATTRIBPROC) ( GLbitfield mask ); /* 1.1 */ -typedef void (APIENTRYP PFNDOLPOPCLIENTATTRIBPROC) ( void ); /* 1.1 */ -typedef GLint (APIENTRYP PFNDOLRENDERMODEPROC) ( GLenum mode ); -typedef GLenum (APIENTRYP PFNDOLGETERRORPROC) ( void ); -typedef const GLubyte* (APIENTRYP PFNDOLGETSTRINGPROC) ( GLenum name ); -typedef void (APIENTRYP PFNDOLFINISHPROC) ( void ); -typedef void (APIENTRYP PFNDOLFLUSHPROC) ( void ); -typedef void (APIENTRYP PFNDOLHINTPROC) ( GLenum target, GLenum mode ); -typedef void (APIENTRYP PFNDOLCLEARDEPTHPROC) ( GLclampd depth ); -typedef void (APIENTRYP PFNDOLDEPTHFUNCPROC) ( GLenum func ); -typedef void (APIENTRYP PFNDOLDEPTHMASKPROC) ( GLboolean flag ); -typedef void (APIENTRYP PFNDOLDEPTHRANGEPROC) ( GLclampd near_val, GLclampd far_val ); -typedef void (APIENTRYP PFNDOLCLEARACCUMPROC) ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ); -typedef void (APIENTRYP PFNDOLACCUMPROC) ( GLenum op, GLfloat value ); -typedef void (APIENTRYP PFNDOLMATRIXMODEPROC) ( GLenum mode ); -typedef void (APIENTRYP PFNDOLORTHOPROC) ( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val ); -typedef void (APIENTRYP PFNDOLFRUSTUMPROC) ( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val ); -typedef void (APIENTRYP PFNDOLVIEWPORTPROC) ( GLint x, GLint y, GLsizei width, GLsizei height ); -typedef void (APIENTRYP PFNDOLPUSHMATRIXPROC) ( void ); -typedef void (APIENTRYP PFNDOLPOPMATRIXPROC) ( void ); -typedef void (APIENTRYP PFNDOLLOADIDENTITYPROC) ( void ); -typedef void (APIENTRYP PFNDOLLOADMATRIXDPROC) ( const GLdouble *m ); -typedef void (APIENTRYP PFNDOLLOADMATRIXFPROC) ( const GLfloat *m ); -typedef void (APIENTRYP PFNDOLMULTMATRIXDPROC) ( const GLdouble *m ); -typedef void (APIENTRYP PFNDOLMULTMATRIXFPROC) ( const GLfloat *m ); -typedef void (APIENTRYP PFNDOLROTATEDPROC) ( GLdouble angle, GLdouble x, GLdouble y, GLdouble z ); -typedef void (APIENTRYP PFNDOLROTATEFPROC) ( GLfloat angle, GLfloat x, GLfloat y, GLfloat z ); -typedef void (APIENTRYP PFNDOLSCALEDPROC) ( GLdouble x, GLdouble y, GLdouble z ); -typedef void (APIENTRYP PFNDOLSCALEFPROC) ( GLfloat x, GLfloat y, GLfloat z ); -typedef void (APIENTRYP PFNDOLTRANSLATEDPROC) ( GLdouble x, GLdouble y, GLdouble z ); -typedef void (APIENTRYP PFNDOLTRANSLATEFPROC) ( GLfloat x, GLfloat y, GLfloat z ); -typedef GLboolean (APIENTRYP PFNDOLISLISTPROC) ( GLuint list ); -typedef void (APIENTRYP PFNDOLDELETELISTSPROC) ( GLuint list, GLsizei range ); -typedef GLuint (APIENTRYP PFNDOLGENLISTSPROC) ( GLsizei range ); -typedef void (APIENTRYP PFNDOLNEWLISTPROC) ( GLuint list, GLenum mode ); -typedef void (APIENTRYP PFNDOLENDLISTPROC) ( void ); -typedef void (APIENTRYP PFNDOLCALLLISTPROC) ( GLuint list ); -typedef void (APIENTRYP PFNDOLCALLLISTSPROC) ( GLsizei n, GLenum type, const GLvoid *lists ); -typedef void (APIENTRYP PFNDOLLISTBASEPROC) ( GLuint base ); -typedef void (APIENTRYP PFNDOLBEGINPROC) ( GLenum mode ); -typedef void (APIENTRYP PFNDOLENDPROC) ( void ); -typedef void (APIENTRYP PFNDOLVERTEX2DPROC) ( GLdouble x, GLdouble y ); -typedef void (APIENTRYP PFNDOLVERTEX2FPROC) ( GLfloat x, GLfloat y ); -typedef void (APIENTRYP PFNDOLVERTEX2IPROC) ( GLint x, GLint y ); -typedef void (APIENTRYP PFNDOLVERTEX2SPROC) ( GLshort x, GLshort y ); -typedef void (APIENTRYP PFNDOLVERTEX3DPROC) ( GLdouble x, GLdouble y, GLdouble z ); -typedef void (APIENTRYP PFNDOLVERTEX3FPROC) ( GLfloat x, GLfloat y, GLfloat z ); -typedef void (APIENTRYP PFNDOLVERTEX3IPROC) ( GLint x, GLint y, GLint z ); -typedef void (APIENTRYP PFNDOLVERTEX3SPROC) ( GLshort x, GLshort y, GLshort z ); -typedef void (APIENTRYP PFNDOLVERTEX4DPROC) ( GLdouble x, GLdouble y, GLdouble z, GLdouble w ); -typedef void (APIENTRYP PFNDOLVERTEX4FPROC) ( GLfloat x, GLfloat y, GLfloat z, GLfloat w ); -typedef void (APIENTRYP PFNDOLVERTEX4IPROC) ( GLint x, GLint y, GLint z, GLint w ); -typedef void (APIENTRYP PFNDOLVERTEX4SPROC) ( GLshort x, GLshort y, GLshort z, GLshort w ); -typedef void (APIENTRYP PFNDOLVERTEX2DVPROC) ( const GLdouble *v ); -typedef void (APIENTRYP PFNDOLVERTEX2FVPROC) ( const GLfloat *v ); -typedef void (APIENTRYP PFNDOLVERTEX2IVPROC) ( const GLint *v ); -typedef void (APIENTRYP PFNDOLVERTEX2SVPROC) ( const GLshort *v ); -typedef void (APIENTRYP PFNDOLVERTEX3DVPROC) ( const GLdouble *v ); -typedef void (APIENTRYP PFNDOLVERTEX3FVPROC) ( const GLfloat *v ); -typedef void (APIENTRYP PFNDOLVERTEX3IVPROC) ( const GLint *v ); -typedef void (APIENTRYP PFNDOLVERTEX3SVPROC) ( const GLshort *v ); -typedef void (APIENTRYP PFNDOLVERTEX4DVPROC) ( const GLdouble *v ); -typedef void (APIENTRYP PFNDOLVERTEX4FVPROC) ( const GLfloat *v ); -typedef void (APIENTRYP PFNDOLVERTEX4IVPROC) ( const GLint *v ); -typedef void (APIENTRYP PFNDOLVERTEX4SVPROC) ( const GLshort *v ); -typedef void (APIENTRYP PFNDOLNORMAL3BPROC) ( GLbyte nx, GLbyte ny, GLbyte nz ); -typedef void (APIENTRYP PFNDOLNORMAL3DPROC) ( GLdouble nx, GLdouble ny, GLdouble nz ); -typedef void (APIENTRYP PFNDOLNORMAL3FPROC) ( GLfloat nx, GLfloat ny, GLfloat nz ); -typedef void (APIENTRYP PFNDOLNORMAL3IPROC) ( GLint nx, GLint ny, GLint nz ); -typedef void (APIENTRYP PFNDOLNORMAL3SPROC) ( GLshort nx, GLshort ny, GLshort nz ); -typedef void (APIENTRYP PFNDOLNORMAL3BVPROC) ( const GLbyte *v ); -typedef void (APIENTRYP PFNDOLNORMAL3DVPROC) ( const GLdouble *v ); -typedef void (APIENTRYP PFNDOLNORMAL3FVPROC) ( const GLfloat *v ); -typedef void (APIENTRYP PFNDOLNORMAL3IVPROC) ( const GLint *v ); -typedef void (APIENTRYP PFNDOLNORMAL3SVPROC) ( const GLshort *v ); -typedef void (APIENTRYP PFNDOLINDEXDPROC) ( GLdouble c ); -typedef void (APIENTRYP PFNDOLINDEXFPROC) ( GLfloat c ); -typedef void (APIENTRYP PFNDOLINDEXIPROC) ( GLint c ); -typedef void (APIENTRYP PFNDOLINDEXSPROC) ( GLshort c ); -typedef void (APIENTRYP PFNDOLINDEXUBPROC) ( GLubyte c ); /* 1.1 */ -typedef void (APIENTRYP PFNDOLINDEXDVPROC) ( const GLdouble *c ); -typedef void (APIENTRYP PFNDOLINDEXFVPROC) ( const GLfloat *c ); -typedef void (APIENTRYP PFNDOLINDEXIVPROC) ( const GLint *c ); -typedef void (APIENTRYP PFNDOLINDEXSVPROC) ( const GLshort *c ); -typedef void (APIENTRYP PFNDOLINDEXUBVPROC) ( const GLubyte *c ); /* 1.1 */ -typedef void (APIENTRYP PFNDOLCOLOR3BPROC) ( GLbyte red, GLbyte green, GLbyte blue ); -typedef void (APIENTRYP PFNDOLCOLOR3DPROC) ( GLdouble red, GLdouble green, GLdouble blue ); -typedef void (APIENTRYP PFNDOLCOLOR3FPROC) ( GLfloat red, GLfloat green, GLfloat blue ); -typedef void (APIENTRYP PFNDOLCOLOR3IPROC) ( GLint red, GLint green, GLint blue ); -typedef void (APIENTRYP PFNDOLCOLOR3SPROC) ( GLshort red, GLshort green, GLshort blue ); -typedef void (APIENTRYP PFNDOLCOLOR3UBPROC) ( GLubyte red, GLubyte green, GLubyte blue ); -typedef void (APIENTRYP PFNDOLCOLOR3UIPROC) ( GLuint red, GLuint green, GLuint blue ); -typedef void (APIENTRYP PFNDOLCOLOR3USPROC) ( GLushort red, GLushort green, GLushort blue ); -typedef void (APIENTRYP PFNDOLCOLOR4BPROC) ( GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha ); -typedef void (APIENTRYP PFNDOLCOLOR4DPROC) ( GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha ); -typedef void (APIENTRYP PFNDOLCOLOR4FPROC) ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ); -typedef void (APIENTRYP PFNDOLCOLOR4IPROC) ( GLint red, GLint green, GLint blue, GLint alpha ); -typedef void (APIENTRYP PFNDOLCOLOR4SPROC) ( GLshort red, GLshort green, GLshort blue, GLshort alpha ); -typedef void (APIENTRYP PFNDOLCOLOR4UBPROC) ( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha ); -typedef void (APIENTRYP PFNDOLCOLOR4UIPROC) ( GLuint red, GLuint green, GLuint blue, GLuint alpha ); -typedef void (APIENTRYP PFNDOLCOLOR4USPROC) ( GLushort red, GLushort green, GLushort blue, GLushort alpha ); -typedef void (APIENTRYP PFNDOLCOLOR3BVPROC) ( const GLbyte *v ); -typedef void (APIENTRYP PFNDOLCOLOR3DVPROC) ( const GLdouble *v ); -typedef void (APIENTRYP PFNDOLCOLOR3FVPROC) ( const GLfloat *v ); -typedef void (APIENTRYP PFNDOLCOLOR3IVPROC) ( const GLint *v ); -typedef void (APIENTRYP PFNDOLCOLOR3SVPROC) ( const GLshort *v ); -typedef void (APIENTRYP PFNDOLCOLOR3UBVPROC) ( const GLubyte *v ); -typedef void (APIENTRYP PFNDOLCOLOR3UIVPROC) ( const GLuint *v ); -typedef void (APIENTRYP PFNDOLCOLOR3USVPROC) ( const GLushort *v ); -typedef void (APIENTRYP PFNDOLCOLOR4BVPROC) ( const GLbyte *v ); -typedef void (APIENTRYP PFNDOLCOLOR4DVPROC) ( const GLdouble *v ); -typedef void (APIENTRYP PFNDOLCOLOR4FVPROC) ( const GLfloat *v ); -typedef void (APIENTRYP PFNDOLCOLOR4IVPROC) ( const GLint *v ); -typedef void (APIENTRYP PFNDOLCOLOR4SVPROC) ( const GLshort *v ); -typedef void (APIENTRYP PFNDOLCOLOR4UBVPROC) ( const GLubyte *v ); -typedef void (APIENTRYP PFNDOLCOLOR4UIVPROC) ( const GLuint *v ); -typedef void (APIENTRYP PFNDOLCOLOR4USVPROC) ( const GLushort *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD1DPROC) ( GLdouble s ); -typedef void (APIENTRYP PFNDOLTEXCOORD1FPROC) ( GLfloat s ); -typedef void (APIENTRYP PFNDOLTEXCOORD1IPROC) ( GLint s ); -typedef void (APIENTRYP PFNDOLTEXCOORD1SPROC) ( GLshort s ); -typedef void (APIENTRYP PFNDOLTEXCOORD2DPROC) ( GLdouble s, GLdouble t ); -typedef void (APIENTRYP PFNDOLTEXCOORD2FPROC) ( GLfloat s, GLfloat t ); -typedef void (APIENTRYP PFNDOLTEXCOORD2IPROC) ( GLint s, GLint t ); -typedef void (APIENTRYP PFNDOLTEXCOORD2SPROC) ( GLshort s, GLshort t ); -typedef void (APIENTRYP PFNDOLTEXCOORD3DPROC) ( GLdouble s, GLdouble t, GLdouble r ); -typedef void (APIENTRYP PFNDOLTEXCOORD3FPROC) ( GLfloat s, GLfloat t, GLfloat r ); -typedef void (APIENTRYP PFNDOLTEXCOORD3IPROC) ( GLint s, GLint t, GLint r ); -typedef void (APIENTRYP PFNDOLTEXCOORD3SPROC) ( GLshort s, GLshort t, GLshort r ); -typedef void (APIENTRYP PFNDOLTEXCOORD4DPROC) ( GLdouble s, GLdouble t, GLdouble r, GLdouble q ); -typedef void (APIENTRYP PFNDOLTEXCOORD4FPROC) ( GLfloat s, GLfloat t, GLfloat r, GLfloat q ); -typedef void (APIENTRYP PFNDOLTEXCOORD4IPROC) ( GLint s, GLint t, GLint r, GLint q ); -typedef void (APIENTRYP PFNDOLTEXCOORD4SPROC) ( GLshort s, GLshort t, GLshort r, GLshort q ); -typedef void (APIENTRYP PFNDOLTEXCOORD1DVPROC) ( const GLdouble *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD1FVPROC) ( const GLfloat *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD1IVPROC) ( const GLint *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD1SVPROC) ( const GLshort *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD2DVPROC) ( const GLdouble *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD2FVPROC) ( const GLfloat *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD2IVPROC) ( const GLint *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD2SVPROC) ( const GLshort *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD3DVPROC) ( const GLdouble *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD3FVPROC) ( const GLfloat *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD3IVPROC) ( const GLint *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD3SVPROC) ( const GLshort *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD4DVPROC) ( const GLdouble *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD4FVPROC) ( const GLfloat *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD4IVPROC) ( const GLint *v ); -typedef void (APIENTRYP PFNDOLTEXCOORD4SVPROC) ( const GLshort *v ); -typedef void (APIENTRYP PFNDOLRASTERPOS2DPROC) ( GLdouble x, GLdouble y ); -typedef void (APIENTRYP PFNDOLRASTERPOS2FPROC) ( GLfloat x, GLfloat y ); -typedef void (APIENTRYP PFNDOLRASTERPOS2IPROC) ( GLint x, GLint y ); -typedef void (APIENTRYP PFNDOLRASTERPOS2SPROC) ( GLshort x, GLshort y ); -typedef void (APIENTRYP PFNDOLRASTERPOS3DPROC) ( GLdouble x, GLdouble y, GLdouble z ); -typedef void (APIENTRYP PFNDOLRASTERPOS3FPROC) ( GLfloat x, GLfloat y, GLfloat z ); -typedef void (APIENTRYP PFNDOLRASTERPOS3IPROC) ( GLint x, GLint y, GLint z ); -typedef void (APIENTRYP PFNDOLRASTERPOS3SPROC) ( GLshort x, GLshort y, GLshort z ); -typedef void (APIENTRYP PFNDOLRASTERPOS4DPROC) ( GLdouble x, GLdouble y, GLdouble z, GLdouble w ); -typedef void (APIENTRYP PFNDOLRASTERPOS4FPROC) ( GLfloat x, GLfloat y, GLfloat z, GLfloat w ); -typedef void (APIENTRYP PFNDOLRASTERPOS4IPROC) ( GLint x, GLint y, GLint z, GLint w ); -typedef void (APIENTRYP PFNDOLRASTERPOS4SPROC) ( GLshort x, GLshort y, GLshort z, GLshort w ); -typedef void (APIENTRYP PFNDOLRASTERPOS2DVPROC) ( const GLdouble *v ); -typedef void (APIENTRYP PFNDOLRASTERPOS2FVPROC) ( const GLfloat *v ); -typedef void (APIENTRYP PFNDOLRASTERPOS2IVPROC) ( const GLint *v ); -typedef void (APIENTRYP PFNDOLRASTERPOS2SVPROC) ( const GLshort *v ); -typedef void (APIENTRYP PFNDOLRASTERPOS3DVPROC) ( const GLdouble *v ); -typedef void (APIENTRYP PFNDOLRASTERPOS3FVPROC) ( const GLfloat *v ); -typedef void (APIENTRYP PFNDOLRASTERPOS3IVPROC) ( const GLint *v ); -typedef void (APIENTRYP PFNDOLRASTERPOS3SVPROC) ( const GLshort *v ); -typedef void (APIENTRYP PFNDOLRASTERPOS4DVPROC) ( const GLdouble *v ); -typedef void (APIENTRYP PFNDOLRASTERPOS4FVPROC) ( const GLfloat *v ); -typedef void (APIENTRYP PFNDOLRASTERPOS4IVPROC) ( const GLint *v ); -typedef void (APIENTRYP PFNDOLRASTERPOS4SVPROC) ( const GLshort *v ); -typedef void (APIENTRYP PFNDOLRECTDPROC) ( GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2 ); -typedef void (APIENTRYP PFNDOLRECTFPROC) ( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 ); -typedef void (APIENTRYP PFNDOLRECTIPROC) ( GLint x1, GLint y1, GLint x2, GLint y2 ); -typedef void (APIENTRYP PFNDOLRECTSPROC) ( GLshort x1, GLshort y1, GLshort x2, GLshort y2 ); -typedef void (APIENTRYP PFNDOLRECTDVPROC) ( const GLdouble *v1, const GLdouble *v2 ); -typedef void (APIENTRYP PFNDOLRECTFVPROC) ( const GLfloat *v1, const GLfloat *v2 ); -typedef void (APIENTRYP PFNDOLRECTIVPROC) ( const GLint *v1, const GLint *v2 ); -typedef void (APIENTRYP PFNDOLRECTSVPROC) ( const GLshort *v1, const GLshort *v2 ); -typedef void (APIENTRYP PFNDOLVERTEXPOINTERPROC) ( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr ); -typedef void (APIENTRYP PFNDOLNORMALPOINTERPROC) ( GLenum type, GLsizei stride, const GLvoid *ptr ); -typedef void (APIENTRYP PFNDOLCOLORPOINTERPROC) ( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr ); -typedef void (APIENTRYP PFNDOLINDEXPOINTERPROC) ( GLenum type, GLsizei stride, const GLvoid *ptr ); -typedef void (APIENTRYP PFNDOLTEXCOORDPOINTERPROC) ( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr ); -typedef void (APIENTRYP PFNDOLEDGEFLAGPOINTERPROC) ( GLsizei stride, const GLvoid *ptr ); -typedef void (APIENTRYP PFNDOLGETPOINTERVPROC) ( GLenum pname, GLvoid **params ); -typedef void (APIENTRYP PFNDOLARRAYELEMENTPROC) ( GLint i ); -typedef void (APIENTRYP PFNDOLDRAWARRAYSPROC) ( GLenum mode, GLint first, GLsizei count ); -typedef void (APIENTRYP PFNDOLDRAWELEMENTSPROC) ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices ); -typedef void (APIENTRYP PFNDOLINTERLEAVEDARRAYSPROC) ( GLenum format, GLsizei stride, const GLvoid *pointer ); -typedef void (APIENTRYP PFNDOLSHADEMODELPROC) ( GLenum mode ); -typedef void (APIENTRYP PFNDOLLIGHTFPROC) ( GLenum light, GLenum pname, GLfloat param ); -typedef void (APIENTRYP PFNDOLLIGHTIPROC) ( GLenum light, GLenum pname, GLint param ); -typedef void (APIENTRYP PFNDOLLIGHTFVPROC) ( GLenum light, GLenum pname, const GLfloat *params ); -typedef void (APIENTRYP PFNDOLLIGHTIVPROC) ( GLenum light, GLenum pname, const GLint *params ); -typedef void (APIENTRYP PFNDOLGETLIGHTFVPROC) ( GLenum light, GLenum pname, GLfloat *params ); -typedef void (APIENTRYP PFNDOLGETLIGHTIVPROC) ( GLenum light, GLenum pname, GLint *params ); -typedef void (APIENTRYP PFNDOLLIGHTMODELFPROC) ( GLenum pname, GLfloat param ); -typedef void (APIENTRYP PFNDOLLIGHTMODELIPROC) ( GLenum pname, GLint param ); -typedef void (APIENTRYP PFNDOLLIGHTMODELFVPROC) ( GLenum pname, const GLfloat *params ); -typedef void (APIENTRYP PFNDOLLIGHTMODELIVPROC) ( GLenum pname, const GLint *params ); -typedef void (APIENTRYP PFNDOLMATERIALFPROC) ( GLenum face, GLenum pname, GLfloat param ); -typedef void (APIENTRYP PFNDOLMATERIALIPROC) ( GLenum face, GLenum pname, GLint param ); -typedef void (APIENTRYP PFNDOLMATERIALFVPROC) ( GLenum face, GLenum pname, const GLfloat *params ); -typedef void (APIENTRYP PFNDOLMATERIALIVPROC) ( GLenum face, GLenum pname, const GLint *params ); -typedef void (APIENTRYP PFNDOLGETMATERIALFVPROC) ( GLenum face, GLenum pname, GLfloat *params ); -typedef void (APIENTRYP PFNDOLGETMATERIALIVPROC) ( GLenum face, GLenum pname, GLint *params ); -typedef void (APIENTRYP PFNDOLCOLORMATERIALPROC) ( GLenum face, GLenum mode ); -typedef void (APIENTRYP PFNDOLPIXELZOOMPROC) ( GLfloat xfactor, GLfloat yfactor ); -typedef void (APIENTRYP PFNDOLPIXELSTOREFPROC) ( GLenum pname, GLfloat param ); -typedef void (APIENTRYP PFNDOLPIXELSTOREIPROC) ( GLenum pname, GLint param ); -typedef void (APIENTRYP PFNDOLPIXELTRANSFERFPROC) ( GLenum pname, GLfloat param ); -typedef void (APIENTRYP PFNDOLPIXELTRANSFERIPROC) ( GLenum pname, GLint param ); -typedef void (APIENTRYP PFNDOLPIXELMAPFVPROC) ( GLenum map, GLsizei mapsize, const GLfloat *values ); -typedef void (APIENTRYP PFNDOLPIXELMAPUIVPROC) ( GLenum map, GLsizei mapsize, const GLuint *values ); -typedef void (APIENTRYP PFNDOLPIXELMAPUSVPROC) ( GLenum map, GLsizei mapsize, const GLushort *values ); -typedef void (APIENTRYP PFNDOLGETPIXELMAPFVPROC) ( GLenum map, GLfloat *values ); -typedef void (APIENTRYP PFNDOLGETPIXELMAPUIVPROC) ( GLenum map, GLuint *values ); -typedef void (APIENTRYP PFNDOLGETPIXELMAPUSVPROC) ( GLenum map, GLushort *values ); -typedef void (APIENTRYP PFNDOLBITMAPPROC) ( GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap ); -typedef void (APIENTRYP PFNDOLREADPIXELSPROC) ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels ); -typedef void (APIENTRYP PFNDOLDRAWPIXELSPROC) ( GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ); -typedef void (APIENTRYP PFNDOLCOPYPIXELSPROC) ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum type ); -typedef void (APIENTRYP PFNDOLSTENCILFUNCPROC) ( GLenum func, GLint ref, GLuint mask ); -typedef void (APIENTRYP PFNDOLSTENCILMASKPROC) ( GLuint mask ); -typedef void (APIENTRYP PFNDOLSTENCILOPPROC) ( GLenum fail, GLenum zfail, GLenum zpass ); -typedef void (APIENTRYP PFNDOLCLEARSTENCILPROC) ( GLint s ); -typedef void (APIENTRYP PFNDOLTEXGENDPROC) ( GLenum coord, GLenum pname, GLdouble param ); -typedef void (APIENTRYP PFNDOLTEXGENFPROC) ( GLenum coord, GLenum pname, GLfloat param ); -typedef void (APIENTRYP PFNDOLTEXGENIPROC) ( GLenum coord, GLenum pname, GLint param ); -typedef void (APIENTRYP PFNDOLTEXGENDVPROC) ( GLenum coord, GLenum pname, const GLdouble *params ); -typedef void (APIENTRYP PFNDOLTEXGENFVPROC) ( GLenum coord, GLenum pname, const GLfloat *params ); -typedef void (APIENTRYP PFNDOLTEXGENIVPROC) ( GLenum coord, GLenum pname, const GLint *params ); -typedef void (APIENTRYP PFNDOLGETTEXGENDVPROC) ( GLenum coord, GLenum pname, GLdouble *params ); -typedef void (APIENTRYP PFNDOLGETTEXGENFVPROC) ( GLenum coord, GLenum pname, GLfloat *params ); -typedef void (APIENTRYP PFNDOLGETTEXGENIVPROC) ( GLenum coord, GLenum pname, GLint *params ); -typedef void (APIENTRYP PFNDOLTEXENVFPROC) ( GLenum target, GLenum pname, GLfloat param ); -typedef void (APIENTRYP PFNDOLTEXENVIPROC) ( GLenum target, GLenum pname, GLint param ); -typedef void (APIENTRYP PFNDOLTEXENVFVPROC) ( GLenum target, GLenum pname, const GLfloat *params ); -typedef void (APIENTRYP PFNDOLTEXENVIVPROC) ( GLenum target, GLenum pname, const GLint *params ); -typedef void (APIENTRYP PFNDOLGETTEXENVFVPROC) ( GLenum target, GLenum pname, GLfloat *params ); -typedef void (APIENTRYP PFNDOLGETTEXENVIVPROC) ( GLenum target, GLenum pname, GLint *params ); -typedef void (APIENTRYP PFNDOLTEXPARAMETERFPROC) ( GLenum target, GLenum pname, GLfloat param ); -typedef void (APIENTRYP PFNDOLTEXPARAMETERIPROC) ( GLenum target, GLenum pname, GLint param ); -typedef void (APIENTRYP PFNDOLTEXPARAMETERFVPROC) ( GLenum target, GLenum pname, const GLfloat *params ); -typedef void (APIENTRYP PFNDOLTEXPARAMETERIVPROC) ( GLenum target, GLenum pname, const GLint *params ); -typedef void (APIENTRYP PFNDOLGETTEXPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNDOLGETTEXPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params ); -typedef void (APIENTRYP PFNDOLGETTEXLEVELPARAMETERFVPROC) ( GLenum target, GLint level, GLenum pname, GLfloat *params ); -typedef void (APIENTRYP PFNDOLGETTEXLEVELPARAMETERIVPROC) ( GLenum target, GLint level, GLenum pname, GLint *params ); -typedef void (APIENTRYP PFNDOLTEXIMAGE1DPROC) ( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels ); -typedef void (APIENTRYP PFNDOLTEXIMAGE2DPROC) ( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ); -typedef void (APIENTRYP PFNDOLGETTEXIMAGEPROC) ( GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels ); -typedef void (APIENTRYP PFNDOLGENTEXTURESPROC) ( GLsizei n, GLuint *textures ); -typedef void (APIENTRYP PFNDOLDELETETEXTURESPROC) ( GLsizei n, const GLuint *textures); -typedef void (APIENTRYP PFNDOLBINDTEXTUREPROC) ( GLenum target, GLuint texture ); -typedef void (APIENTRYP PFNDOLPRIORITIZETEXTURESPROC) ( GLsizei n, const GLuint *textures, const GLclampf *priorities ); -typedef GLboolean (APIENTRYP PFNDOLARETEXTURESRESIDENTPROC) ( GLsizei n, const GLuint *textures, GLboolean *residences ); -typedef GLboolean (APIENTRYP PFNDOLISTEXTUREPROC) ( GLuint texture ); -typedef void (APIENTRYP PFNDOLTEXSUBIMAGE1DPROC) ( GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels ); -typedef void (APIENTRYP PFNDOLTEXSUBIMAGE2DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ); -typedef void (APIENTRYP PFNDOLCOPYTEXIMAGE1DPROC) ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border ); -typedef void (APIENTRYP PFNDOLCOPYTEXIMAGE2DPROC) ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ); -typedef void (APIENTRYP PFNDOLCOPYTEXSUBIMAGE1DPROC) ( GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width ); -typedef void (APIENTRYP PFNDOLCOPYTEXSUBIMAGE2DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ); -typedef void (APIENTRYP PFNDOLMAP1DPROC) ( GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points ); -typedef void (APIENTRYP PFNDOLMAP1FPROC) ( GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points ); -typedef void (APIENTRYP PFNDOLMAP2DPROC) ( GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points ); -typedef void (APIENTRYP PFNDOLMAP2FPROC) ( GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points ); -typedef void (APIENTRYP PFNDOLGETMAPDVPROC) ( GLenum target, GLenum query, GLdouble *v ); -typedef void (APIENTRYP PFNDOLGETMAPFVPROC) ( GLenum target, GLenum query, GLfloat *v ); -typedef void (APIENTRYP PFNDOLGETMAPIVPROC) ( GLenum target, GLenum query, GLint *v ); -typedef void (APIENTRYP PFNDOLEVALCOORD1DPROC) ( GLdouble u ); -typedef void (APIENTRYP PFNDOLEVALCOORD1FPROC) ( GLfloat u ); -typedef void (APIENTRYP PFNDOLEVALCOORD1DVPROC) ( const GLdouble *u ); -typedef void (APIENTRYP PFNDOLEVALCOORD1FVPROC) ( const GLfloat *u ); -typedef void (APIENTRYP PFNDOLEVALCOORD2DPROC) ( GLdouble u, GLdouble v ); -typedef void (APIENTRYP PFNDOLEVALCOORD2FPROC) ( GLfloat u, GLfloat v ); -typedef void (APIENTRYP PFNDOLEVALCOORD2DVPROC) ( const GLdouble *u ); -typedef void (APIENTRYP PFNDOLEVALCOORD2FVPROC) ( const GLfloat *u ); -typedef void (APIENTRYP PFNDOLMAPGRID1DPROC) ( GLint un, GLdouble u1, GLdouble u2 ); -typedef void (APIENTRYP PFNDOLMAPGRID1FPROC) ( GLint un, GLfloat u1, GLfloat u2 ); -typedef void (APIENTRYP PFNDOLMAPGRID2DPROC) ( GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2 ); -typedef void (APIENTRYP PFNDOLMAPGRID2FPROC) ( GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2 ); -typedef void (APIENTRYP PFNDOLEVALPOINT1PROC) ( GLint i ); -typedef void (APIENTRYP PFNDOLEVALPOINT2PROC) ( GLint i, GLint j ); -typedef void (APIENTRYP PFNDOLEVALMESH1PROC) ( GLenum mode, GLint i1, GLint i2 ); -typedef void (APIENTRYP PFNDOLEVALMESH2PROC) ( GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2 ); -typedef void (APIENTRYP PFNDOLFOGFPROC) ( GLenum pname, GLfloat param ); -typedef void (APIENTRYP PFNDOLFOGIPROC) ( GLenum pname, GLint param ); -typedef void (APIENTRYP PFNDOLFOGFVPROC) ( GLenum pname, const GLfloat *params ); -typedef void (APIENTRYP PFNDOLFOGIVPROC) ( GLenum pname, const GLint *params ); -typedef void (APIENTRYP PFNDOLFEEDBACKBUFFERPROC) ( GLsizei size, GLenum type, GLfloat *buffer ); -typedef void (APIENTRYP PFNDOLPASSTHROUGHPROC) ( GLfloat token ); -typedef void (APIENTRYP PFNDOLSELECTBUFFERPROC) ( GLsizei size, GLuint *buffer ); -typedef void (APIENTRYP PFNDOLINITNAMESPROC) ( void ); -typedef void (APIENTRYP PFNDOLLOADNAMEPROC) ( GLuint name ); -typedef void (APIENTRYP PFNDOLPUSHNAMEPROC) ( GLuint name ); -typedef void (APIENTRYP PFNDOLPOPNAMEPROC) ( void ); +typedef void(APIENTRYP PFNDOLCLEARINDEXPROC)(GLfloat c); +typedef void(APIENTRYP PFNDOLCLEARCOLORPROC)(GLclampf red, GLclampf green, GLclampf blue, + GLclampf alpha); +typedef void(APIENTRYP PFNDOLCLEARPROC)(GLbitfield mask); +typedef void(APIENTRYP PFNDOLINDEXMASKPROC)(GLuint mask); +typedef void(APIENTRYP PFNDOLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, + GLboolean alpha); +typedef void(APIENTRYP PFNDOLALPHAFUNCPROC)(GLenum func, GLclampf ref); +typedef void(APIENTRYP PFNDOLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); +typedef void(APIENTRYP PFNDOLLOGICOPPROC)(GLenum opcode); +typedef void(APIENTRYP PFNDOLCULLFACEPROC)(GLenum mode); +typedef void(APIENTRYP PFNDOLFRONTFACEPROC)(GLenum mode); +typedef void(APIENTRYP PFNDOLPOINTSIZEPROC)(GLfloat size); +typedef void(APIENTRYP PFNDOLLINEWIDTHPROC)(GLfloat width); +typedef void(APIENTRYP PFNDOLLINESTIPPLEPROC)(GLint factor, GLushort pattern); +typedef void(APIENTRYP PFNDOLPOLYGONMODEPROC)(GLenum face, GLenum mode); +typedef void(APIENTRYP PFNDOLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); +typedef void(APIENTRYP PFNDOLPOLYGONSTIPPLEPROC)(const GLubyte* mask); +typedef void(APIENTRYP PFNDOLGETPOLYGONSTIPPLEPROC)(GLubyte* mask); +typedef void(APIENTRYP PFNDOLEDGEFLAGPROC)(GLboolean flag); +typedef void(APIENTRYP PFNDOLEDGEFLAGVPROC)(const GLboolean* flag); +typedef void(APIENTRYP PFNDOLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNDOLCLIPPLANEPROC)(GLenum plane, const GLdouble* equation); +typedef void(APIENTRYP PFNDOLGETCLIPPLANEPROC)(GLenum plane, GLdouble* equation); +typedef void(APIENTRYP PFNDOLDRAWBUFFERPROC)(GLenum mode); +typedef void(APIENTRYP PFNDOLREADBUFFERPROC)(GLenum mode); +typedef void(APIENTRYP PFNDOLENABLEPROC)(GLenum cap); +typedef void(APIENTRYP PFNDOLDISABLEPROC)(GLenum cap); +typedef GLboolean(APIENTRYP PFNDOLISENABLEDPROC)(GLenum cap); +typedef void(APIENTRYP PFNDOLENABLECLIENTSTATEPROC)(GLenum cap); /* 1.1 */ +typedef void(APIENTRYP PFNDOLDISABLECLIENTSTATEPROC)(GLenum cap); /* 1.1 */ +typedef void(APIENTRYP PFNDOLGETBOOLEANVPROC)(GLenum pname, GLboolean* params); +typedef void(APIENTRYP PFNDOLGETDOUBLEVPROC)(GLenum pname, GLdouble* params); +typedef void(APIENTRYP PFNDOLGETFLOATVPROC)(GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNDOLGETINTEGERVPROC)(GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLPUSHATTRIBPROC)(GLbitfield mask); +typedef void(APIENTRYP PFNDOLPOPATTRIBPROC)(void); +typedef void(APIENTRYP PFNDOLPUSHCLIENTATTRIBPROC)(GLbitfield mask); /* 1.1 */ +typedef void(APIENTRYP PFNDOLPOPCLIENTATTRIBPROC)(void); /* 1.1 */ +typedef GLint(APIENTRYP PFNDOLRENDERMODEPROC)(GLenum mode); +typedef GLenum(APIENTRYP PFNDOLGETERRORPROC)(void); +typedef const GLubyte*(APIENTRYP PFNDOLGETSTRINGPROC)(GLenum name); +typedef void(APIENTRYP PFNDOLFINISHPROC)(void); +typedef void(APIENTRYP PFNDOLFLUSHPROC)(void); +typedef void(APIENTRYP PFNDOLHINTPROC)(GLenum target, GLenum mode); +typedef void(APIENTRYP PFNDOLCLEARDEPTHPROC)(GLclampd depth); +typedef void(APIENTRYP PFNDOLDEPTHFUNCPROC)(GLenum func); +typedef void(APIENTRYP PFNDOLDEPTHMASKPROC)(GLboolean flag); +typedef void(APIENTRYP PFNDOLDEPTHRANGEPROC)(GLclampd near_val, GLclampd far_val); +typedef void(APIENTRYP PFNDOLCLEARACCUMPROC)(GLfloat red, GLfloat green, GLfloat blue, + GLfloat alpha); +typedef void(APIENTRYP PFNDOLACCUMPROC)(GLenum op, GLfloat value); +typedef void(APIENTRYP PFNDOLMATRIXMODEPROC)(GLenum mode); +typedef void(APIENTRYP PFNDOLORTHOPROC)(GLdouble left, GLdouble right, GLdouble bottom, + GLdouble top, GLdouble near_val, GLdouble far_val); +typedef void(APIENTRYP PFNDOLFRUSTUMPROC)(GLdouble left, GLdouble right, GLdouble bottom, + GLdouble top, GLdouble near_val, GLdouble far_val); +typedef void(APIENTRYP PFNDOLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNDOLPUSHMATRIXPROC)(void); +typedef void(APIENTRYP PFNDOLPOPMATRIXPROC)(void); +typedef void(APIENTRYP PFNDOLLOADIDENTITYPROC)(void); +typedef void(APIENTRYP PFNDOLLOADMATRIXDPROC)(const GLdouble* m); +typedef void(APIENTRYP PFNDOLLOADMATRIXFPROC)(const GLfloat* m); +typedef void(APIENTRYP PFNDOLMULTMATRIXDPROC)(const GLdouble* m); +typedef void(APIENTRYP PFNDOLMULTMATRIXFPROC)(const GLfloat* m); +typedef void(APIENTRYP PFNDOLROTATEDPROC)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +typedef void(APIENTRYP PFNDOLROTATEFPROC)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +typedef void(APIENTRYP PFNDOLSCALEDPROC)(GLdouble x, GLdouble y, GLdouble z); +typedef void(APIENTRYP PFNDOLSCALEFPROC)(GLfloat x, GLfloat y, GLfloat z); +typedef void(APIENTRYP PFNDOLTRANSLATEDPROC)(GLdouble x, GLdouble y, GLdouble z); +typedef void(APIENTRYP PFNDOLTRANSLATEFPROC)(GLfloat x, GLfloat y, GLfloat z); +typedef GLboolean(APIENTRYP PFNDOLISLISTPROC)(GLuint list); +typedef void(APIENTRYP PFNDOLDELETELISTSPROC)(GLuint list, GLsizei range); +typedef GLuint(APIENTRYP PFNDOLGENLISTSPROC)(GLsizei range); +typedef void(APIENTRYP PFNDOLNEWLISTPROC)(GLuint list, GLenum mode); +typedef void(APIENTRYP PFNDOLENDLISTPROC)(void); +typedef void(APIENTRYP PFNDOLCALLLISTPROC)(GLuint list); +typedef void(APIENTRYP PFNDOLCALLLISTSPROC)(GLsizei n, GLenum type, const GLvoid* lists); +typedef void(APIENTRYP PFNDOLLISTBASEPROC)(GLuint base); +typedef void(APIENTRYP PFNDOLBEGINPROC)(GLenum mode); +typedef void(APIENTRYP PFNDOLENDPROC)(void); +typedef void(APIENTRYP PFNDOLVERTEX2DPROC)(GLdouble x, GLdouble y); +typedef void(APIENTRYP PFNDOLVERTEX2FPROC)(GLfloat x, GLfloat y); +typedef void(APIENTRYP PFNDOLVERTEX2IPROC)(GLint x, GLint y); +typedef void(APIENTRYP PFNDOLVERTEX2SPROC)(GLshort x, GLshort y); +typedef void(APIENTRYP PFNDOLVERTEX3DPROC)(GLdouble x, GLdouble y, GLdouble z); +typedef void(APIENTRYP PFNDOLVERTEX3FPROC)(GLfloat x, GLfloat y, GLfloat z); +typedef void(APIENTRYP PFNDOLVERTEX3IPROC)(GLint x, GLint y, GLint z); +typedef void(APIENTRYP PFNDOLVERTEX3SPROC)(GLshort x, GLshort y, GLshort z); +typedef void(APIENTRYP PFNDOLVERTEX4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void(APIENTRYP PFNDOLVERTEX4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void(APIENTRYP PFNDOLVERTEX4IPROC)(GLint x, GLint y, GLint z, GLint w); +typedef void(APIENTRYP PFNDOLVERTEX4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); +typedef void(APIENTRYP PFNDOLVERTEX2DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLVERTEX2FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLVERTEX2IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLVERTEX2SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLVERTEX3DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLVERTEX3FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLVERTEX3IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLVERTEX3SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLVERTEX4DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLVERTEX4FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLVERTEX4IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLVERTEX4SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLNORMAL3BPROC)(GLbyte nx, GLbyte ny, GLbyte nz); +typedef void(APIENTRYP PFNDOLNORMAL3DPROC)(GLdouble nx, GLdouble ny, GLdouble nz); +typedef void(APIENTRYP PFNDOLNORMAL3FPROC)(GLfloat nx, GLfloat ny, GLfloat nz); +typedef void(APIENTRYP PFNDOLNORMAL3IPROC)(GLint nx, GLint ny, GLint nz); +typedef void(APIENTRYP PFNDOLNORMAL3SPROC)(GLshort nx, GLshort ny, GLshort nz); +typedef void(APIENTRYP PFNDOLNORMAL3BVPROC)(const GLbyte* v); +typedef void(APIENTRYP PFNDOLNORMAL3DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLNORMAL3FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLNORMAL3IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLNORMAL3SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLINDEXDPROC)(GLdouble c); +typedef void(APIENTRYP PFNDOLINDEXFPROC)(GLfloat c); +typedef void(APIENTRYP PFNDOLINDEXIPROC)(GLint c); +typedef void(APIENTRYP PFNDOLINDEXSPROC)(GLshort c); +typedef void(APIENTRYP PFNDOLINDEXUBPROC)(GLubyte c); /* 1.1 */ +typedef void(APIENTRYP PFNDOLINDEXDVPROC)(const GLdouble* c); +typedef void(APIENTRYP PFNDOLINDEXFVPROC)(const GLfloat* c); +typedef void(APIENTRYP PFNDOLINDEXIVPROC)(const GLint* c); +typedef void(APIENTRYP PFNDOLINDEXSVPROC)(const GLshort* c); +typedef void(APIENTRYP PFNDOLINDEXUBVPROC)(const GLubyte* c); /* 1.1 */ +typedef void(APIENTRYP PFNDOLCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); +typedef void(APIENTRYP PFNDOLCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); +typedef void(APIENTRYP PFNDOLCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); +typedef void(APIENTRYP PFNDOLCOLOR3IPROC)(GLint red, GLint green, GLint blue); +typedef void(APIENTRYP PFNDOLCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); +typedef void(APIENTRYP PFNDOLCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); +typedef void(APIENTRYP PFNDOLCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); +typedef void(APIENTRYP PFNDOLCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); +typedef void(APIENTRYP PFNDOLCOLOR4BPROC)(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +typedef void(APIENTRYP PFNDOLCOLOR4DPROC)(GLdouble red, GLdouble green, GLdouble blue, + GLdouble alpha); +typedef void(APIENTRYP PFNDOLCOLOR4FPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void(APIENTRYP PFNDOLCOLOR4IPROC)(GLint red, GLint green, GLint blue, GLint alpha); +typedef void(APIENTRYP PFNDOLCOLOR4SPROC)(GLshort red, GLshort green, GLshort blue, GLshort alpha); +typedef void(APIENTRYP PFNDOLCOLOR4UBPROC)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +typedef void(APIENTRYP PFNDOLCOLOR4UIPROC)(GLuint red, GLuint green, GLuint blue, GLuint alpha); +typedef void(APIENTRYP PFNDOLCOLOR4USPROC)(GLushort red, GLushort green, GLushort blue, + GLushort alpha); +typedef void(APIENTRYP PFNDOLCOLOR3BVPROC)(const GLbyte* v); +typedef void(APIENTRYP PFNDOLCOLOR3DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLCOLOR3FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLCOLOR3IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLCOLOR3SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLCOLOR3UBVPROC)(const GLubyte* v); +typedef void(APIENTRYP PFNDOLCOLOR3UIVPROC)(const GLuint* v); +typedef void(APIENTRYP PFNDOLCOLOR3USVPROC)(const GLushort* v); +typedef void(APIENTRYP PFNDOLCOLOR4BVPROC)(const GLbyte* v); +typedef void(APIENTRYP PFNDOLCOLOR4DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLCOLOR4FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLCOLOR4IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLCOLOR4SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLCOLOR4UBVPROC)(const GLubyte* v); +typedef void(APIENTRYP PFNDOLCOLOR4UIVPROC)(const GLuint* v); +typedef void(APIENTRYP PFNDOLCOLOR4USVPROC)(const GLushort* v); +typedef void(APIENTRYP PFNDOLTEXCOORD1DPROC)(GLdouble s); +typedef void(APIENTRYP PFNDOLTEXCOORD1FPROC)(GLfloat s); +typedef void(APIENTRYP PFNDOLTEXCOORD1IPROC)(GLint s); +typedef void(APIENTRYP PFNDOLTEXCOORD1SPROC)(GLshort s); +typedef void(APIENTRYP PFNDOLTEXCOORD2DPROC)(GLdouble s, GLdouble t); +typedef void(APIENTRYP PFNDOLTEXCOORD2FPROC)(GLfloat s, GLfloat t); +typedef void(APIENTRYP PFNDOLTEXCOORD2IPROC)(GLint s, GLint t); +typedef void(APIENTRYP PFNDOLTEXCOORD2SPROC)(GLshort s, GLshort t); +typedef void(APIENTRYP PFNDOLTEXCOORD3DPROC)(GLdouble s, GLdouble t, GLdouble r); +typedef void(APIENTRYP PFNDOLTEXCOORD3FPROC)(GLfloat s, GLfloat t, GLfloat r); +typedef void(APIENTRYP PFNDOLTEXCOORD3IPROC)(GLint s, GLint t, GLint r); +typedef void(APIENTRYP PFNDOLTEXCOORD3SPROC)(GLshort s, GLshort t, GLshort r); +typedef void(APIENTRYP PFNDOLTEXCOORD4DPROC)(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void(APIENTRYP PFNDOLTEXCOORD4FPROC)(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void(APIENTRYP PFNDOLTEXCOORD4IPROC)(GLint s, GLint t, GLint r, GLint q); +typedef void(APIENTRYP PFNDOLTEXCOORD4SPROC)(GLshort s, GLshort t, GLshort r, GLshort q); +typedef void(APIENTRYP PFNDOLTEXCOORD1DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLTEXCOORD1FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLTEXCOORD1IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLTEXCOORD1SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLTEXCOORD2DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLTEXCOORD2FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLTEXCOORD2IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLTEXCOORD2SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLTEXCOORD3DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLTEXCOORD3FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLTEXCOORD3IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLTEXCOORD3SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLTEXCOORD4DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLTEXCOORD4FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLTEXCOORD4IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLTEXCOORD4SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLRASTERPOS2DPROC)(GLdouble x, GLdouble y); +typedef void(APIENTRYP PFNDOLRASTERPOS2FPROC)(GLfloat x, GLfloat y); +typedef void(APIENTRYP PFNDOLRASTERPOS2IPROC)(GLint x, GLint y); +typedef void(APIENTRYP PFNDOLRASTERPOS2SPROC)(GLshort x, GLshort y); +typedef void(APIENTRYP PFNDOLRASTERPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); +typedef void(APIENTRYP PFNDOLRASTERPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); +typedef void(APIENTRYP PFNDOLRASTERPOS3IPROC)(GLint x, GLint y, GLint z); +typedef void(APIENTRYP PFNDOLRASTERPOS3SPROC)(GLshort x, GLshort y, GLshort z); +typedef void(APIENTRYP PFNDOLRASTERPOS4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void(APIENTRYP PFNDOLRASTERPOS4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void(APIENTRYP PFNDOLRASTERPOS4IPROC)(GLint x, GLint y, GLint z, GLint w); +typedef void(APIENTRYP PFNDOLRASTERPOS4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); +typedef void(APIENTRYP PFNDOLRASTERPOS2DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLRASTERPOS2FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLRASTERPOS2IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLRASTERPOS2SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLRASTERPOS3DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLRASTERPOS3FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLRASTERPOS3IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLRASTERPOS3SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLRASTERPOS4DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLRASTERPOS4FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLRASTERPOS4IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLRASTERPOS4SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLRECTDPROC)(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +typedef void(APIENTRYP PFNDOLRECTFPROC)(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +typedef void(APIENTRYP PFNDOLRECTIPROC)(GLint x1, GLint y1, GLint x2, GLint y2); +typedef void(APIENTRYP PFNDOLRECTSPROC)(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +typedef void(APIENTRYP PFNDOLRECTDVPROC)(const GLdouble* v1, const GLdouble* v2); +typedef void(APIENTRYP PFNDOLRECTFVPROC)(const GLfloat* v1, const GLfloat* v2); +typedef void(APIENTRYP PFNDOLRECTIVPROC)(const GLint* v1, const GLint* v2); +typedef void(APIENTRYP PFNDOLRECTSVPROC)(const GLshort* v1, const GLshort* v2); +typedef void(APIENTRYP PFNDOLVERTEXPOINTERPROC)(GLint size, GLenum type, GLsizei stride, + const GLvoid* ptr); +typedef void(APIENTRYP PFNDOLNORMALPOINTERPROC)(GLenum type, GLsizei stride, const GLvoid* ptr); +typedef void(APIENTRYP PFNDOLCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, + const GLvoid* ptr); +typedef void(APIENTRYP PFNDOLINDEXPOINTERPROC)(GLenum type, GLsizei stride, const GLvoid* ptr); +typedef void(APIENTRYP PFNDOLTEXCOORDPOINTERPROC)(GLint size, GLenum type, GLsizei stride, + const GLvoid* ptr); +typedef void(APIENTRYP PFNDOLEDGEFLAGPOINTERPROC)(GLsizei stride, const GLvoid* ptr); +typedef void(APIENTRYP PFNDOLGETPOINTERVPROC)(GLenum pname, GLvoid** params); +typedef void(APIENTRYP PFNDOLARRAYELEMENTPROC)(GLint i); +typedef void(APIENTRYP PFNDOLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); +typedef void(APIENTRYP PFNDOLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, + const GLvoid* indices); +typedef void(APIENTRYP PFNDOLINTERLEAVEDARRAYSPROC)(GLenum format, GLsizei stride, + const GLvoid* pointer); +typedef void(APIENTRYP PFNDOLSHADEMODELPROC)(GLenum mode); +typedef void(APIENTRYP PFNDOLLIGHTFPROC)(GLenum light, GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNDOLLIGHTIPROC)(GLenum light, GLenum pname, GLint param); +typedef void(APIENTRYP PFNDOLLIGHTFVPROC)(GLenum light, GLenum pname, const GLfloat* params); +typedef void(APIENTRYP PFNDOLLIGHTIVPROC)(GLenum light, GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNDOLGETLIGHTFVPROC)(GLenum light, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNDOLGETLIGHTIVPROC)(GLenum light, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLLIGHTMODELFPROC)(GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNDOLLIGHTMODELIPROC)(GLenum pname, GLint param); +typedef void(APIENTRYP PFNDOLLIGHTMODELFVPROC)(GLenum pname, const GLfloat* params); +typedef void(APIENTRYP PFNDOLLIGHTMODELIVPROC)(GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNDOLMATERIALFPROC)(GLenum face, GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNDOLMATERIALIPROC)(GLenum face, GLenum pname, GLint param); +typedef void(APIENTRYP PFNDOLMATERIALFVPROC)(GLenum face, GLenum pname, const GLfloat* params); +typedef void(APIENTRYP PFNDOLMATERIALIVPROC)(GLenum face, GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNDOLGETMATERIALFVPROC)(GLenum face, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNDOLGETMATERIALIVPROC)(GLenum face, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLCOLORMATERIALPROC)(GLenum face, GLenum mode); +typedef void(APIENTRYP PFNDOLPIXELZOOMPROC)(GLfloat xfactor, GLfloat yfactor); +typedef void(APIENTRYP PFNDOLPIXELSTOREFPROC)(GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNDOLPIXELSTOREIPROC)(GLenum pname, GLint param); +typedef void(APIENTRYP PFNDOLPIXELTRANSFERFPROC)(GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNDOLPIXELTRANSFERIPROC)(GLenum pname, GLint param); +typedef void(APIENTRYP PFNDOLPIXELMAPFVPROC)(GLenum map, GLsizei mapsize, const GLfloat* values); +typedef void(APIENTRYP PFNDOLPIXELMAPUIVPROC)(GLenum map, GLsizei mapsize, const GLuint* values); +typedef void(APIENTRYP PFNDOLPIXELMAPUSVPROC)(GLenum map, GLsizei mapsize, const GLushort* values); +typedef void(APIENTRYP PFNDOLGETPIXELMAPFVPROC)(GLenum map, GLfloat* values); +typedef void(APIENTRYP PFNDOLGETPIXELMAPUIVPROC)(GLenum map, GLuint* values); +typedef void(APIENTRYP PFNDOLGETPIXELMAPUSVPROC)(GLenum map, GLushort* values); +typedef void(APIENTRYP PFNDOLBITMAPPROC)(GLsizei width, GLsizei height, GLfloat xorig, + GLfloat yorig, GLfloat xmove, GLfloat ymove, + const GLubyte* bitmap); +typedef void(APIENTRYP PFNDOLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLvoid* pixels); +typedef void(APIENTRYP PFNDOLDRAWPIXELSPROC)(GLsizei width, GLsizei height, GLenum format, + GLenum type, const GLvoid* pixels); +typedef void(APIENTRYP PFNDOLCOPYPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum type); +typedef void(APIENTRYP PFNDOLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); +typedef void(APIENTRYP PFNDOLSTENCILMASKPROC)(GLuint mask); +typedef void(APIENTRYP PFNDOLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); +typedef void(APIENTRYP PFNDOLCLEARSTENCILPROC)(GLint s); +typedef void(APIENTRYP PFNDOLTEXGENDPROC)(GLenum coord, GLenum pname, GLdouble param); +typedef void(APIENTRYP PFNDOLTEXGENFPROC)(GLenum coord, GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNDOLTEXGENIPROC)(GLenum coord, GLenum pname, GLint param); +typedef void(APIENTRYP PFNDOLTEXGENDVPROC)(GLenum coord, GLenum pname, const GLdouble* params); +typedef void(APIENTRYP PFNDOLTEXGENFVPROC)(GLenum coord, GLenum pname, const GLfloat* params); +typedef void(APIENTRYP PFNDOLTEXGENIVPROC)(GLenum coord, GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNDOLGETTEXGENDVPROC)(GLenum coord, GLenum pname, GLdouble* params); +typedef void(APIENTRYP PFNDOLGETTEXGENFVPROC)(GLenum coord, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNDOLGETTEXGENIVPROC)(GLenum coord, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLTEXENVFPROC)(GLenum target, GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNDOLTEXENVIPROC)(GLenum target, GLenum pname, GLint param); +typedef void(APIENTRYP PFNDOLTEXENVFVPROC)(GLenum target, GLenum pname, const GLfloat* params); +typedef void(APIENTRYP PFNDOLTEXENVIVPROC)(GLenum target, GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNDOLGETTEXENVFVPROC)(GLenum target, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNDOLGETTEXENVIVPROC)(GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNDOLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +typedef void(APIENTRYP PFNDOLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, + const GLfloat* params); +typedef void(APIENTRYP PFNDOLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNDOLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNDOLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, + GLfloat* params); +typedef void(APIENTRYP PFNDOLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, + GLint* params); +typedef void(APIENTRYP PFNDOLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLint border, GLenum format, + GLenum type, const GLvoid* pixels); +typedef void(APIENTRYP PFNDOLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalFormat, + GLsizei width, GLsizei height, GLint border, + GLenum format, GLenum type, const GLvoid* pixels); +typedef void(APIENTRYP PFNDOLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, + GLenum type, GLvoid* pixels); +typedef void(APIENTRYP PFNDOLGENTEXTURESPROC)(GLsizei n, GLuint* textures); +typedef void(APIENTRYP PFNDOLDELETETEXTURESPROC)(GLsizei n, const GLuint* textures); +typedef void(APIENTRYP PFNDOLBINDTEXTUREPROC)(GLenum target, GLuint texture); +typedef void(APIENTRYP PFNDOLPRIORITIZETEXTURESPROC)(GLsizei n, const GLuint* textures, + const GLclampf* priorities); +typedef GLboolean(APIENTRYP PFNDOLARETEXTURESRESIDENTPROC)(GLsizei n, const GLuint* textures, + GLboolean* residences); +typedef GLboolean(APIENTRYP PFNDOLISTEXTUREPROC)(GLuint texture); +typedef void(APIENTRYP PFNDOLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, + GLsizei width, GLenum format, GLenum type, + const GLvoid* pixels); +typedef void(APIENTRYP PFNDOLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLenum type, const GLvoid* pixels); +typedef void(APIENTRYP PFNDOLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, + GLint x, GLint y, GLsizei width, GLint border); +typedef void(APIENTRYP PFNDOLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, + GLint x, GLint y, GLsizei width, GLsizei height, + GLint border); +typedef void(APIENTRYP PFNDOLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, + GLint x, GLint y, GLsizei width); +typedef void(APIENTRYP PFNDOLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLint x, GLint y, GLsizei width, + GLsizei height); +typedef void(APIENTRYP PFNDOLMAP1DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint stride, + GLint order, const GLdouble* points); +typedef void(APIENTRYP PFNDOLMAP1FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint stride, + GLint order, const GLfloat* points); +typedef void(APIENTRYP PFNDOLMAP2DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, + GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, + GLint vorder, const GLdouble* points); +typedef void(APIENTRYP PFNDOLMAP2FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, + GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, + GLint vorder, const GLfloat* points); +typedef void(APIENTRYP PFNDOLGETMAPDVPROC)(GLenum target, GLenum query, GLdouble* v); +typedef void(APIENTRYP PFNDOLGETMAPFVPROC)(GLenum target, GLenum query, GLfloat* v); +typedef void(APIENTRYP PFNDOLGETMAPIVPROC)(GLenum target, GLenum query, GLint* v); +typedef void(APIENTRYP PFNDOLEVALCOORD1DPROC)(GLdouble u); +typedef void(APIENTRYP PFNDOLEVALCOORD1FPROC)(GLfloat u); +typedef void(APIENTRYP PFNDOLEVALCOORD1DVPROC)(const GLdouble* u); +typedef void(APIENTRYP PFNDOLEVALCOORD1FVPROC)(const GLfloat* u); +typedef void(APIENTRYP PFNDOLEVALCOORD2DPROC)(GLdouble u, GLdouble v); +typedef void(APIENTRYP PFNDOLEVALCOORD2FPROC)(GLfloat u, GLfloat v); +typedef void(APIENTRYP PFNDOLEVALCOORD2DVPROC)(const GLdouble* u); +typedef void(APIENTRYP PFNDOLEVALCOORD2FVPROC)(const GLfloat* u); +typedef void(APIENTRYP PFNDOLMAPGRID1DPROC)(GLint un, GLdouble u1, GLdouble u2); +typedef void(APIENTRYP PFNDOLMAPGRID1FPROC)(GLint un, GLfloat u1, GLfloat u2); +typedef void(APIENTRYP PFNDOLMAPGRID2DPROC)(GLint un, GLdouble u1, GLdouble u2, GLint vn, + GLdouble v1, GLdouble v2); +typedef void(APIENTRYP PFNDOLMAPGRID2FPROC)(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, + GLfloat v2); +typedef void(APIENTRYP PFNDOLEVALPOINT1PROC)(GLint i); +typedef void(APIENTRYP PFNDOLEVALPOINT2PROC)(GLint i, GLint j); +typedef void(APIENTRYP PFNDOLEVALMESH1PROC)(GLenum mode, GLint i1, GLint i2); +typedef void(APIENTRYP PFNDOLEVALMESH2PROC)(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +typedef void(APIENTRYP PFNDOLFOGFPROC)(GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNDOLFOGIPROC)(GLenum pname, GLint param); +typedef void(APIENTRYP PFNDOLFOGFVPROC)(GLenum pname, const GLfloat* params); +typedef void(APIENTRYP PFNDOLFOGIVPROC)(GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNDOLFEEDBACKBUFFERPROC)(GLsizei size, GLenum type, GLfloat* buffer); +typedef void(APIENTRYP PFNDOLPASSTHROUGHPROC)(GLfloat token); +typedef void(APIENTRYP PFNDOLSELECTBUFFERPROC)(GLsizei size, GLuint* buffer); +typedef void(APIENTRYP PFNDOLINITNAMESPROC)(void); +typedef void(APIENTRYP PFNDOLLOADNAMEPROC)(GLuint name); +typedef void(APIENTRYP PFNDOLPUSHNAMEPROC)(GLuint name); +typedef void(APIENTRYP PFNDOLPOPNAMEPROC)(void); extern PFNDOLCLEARINDEXPROC dolClearIndex; extern PFNDOLCLEARCOLORPROC dolClearColor; diff --git a/Source/Core/Common/GL/GLExtensions/gl_1_2.h b/Source/Core/Common/GL/GLExtensions/gl_1_2.h index 097cedd135..e3778cd4ff 100644 --- a/Source/Core/Common/GL/GLExtensions/gl_1_2.h +++ b/Source/Core/Common/GL/GLExtensions/gl_1_2.h @@ -23,52 +23,62 @@ #include "Common/GL/GLExtensions/gl_common.h" -#define GL_RESCALE_NORMAL 0x803A -#define GL_CLAMP_TO_EDGE 0x812F -#define GL_MAX_ELEMENTS_VERTICES 0x80E8 -#define GL_MAX_ELEMENTS_INDICES 0x80E9 -#define GL_BGR 0x80E0 -#define GL_BGRA 0x80E1 -#define GL_UNSIGNED_BYTE_3_3_2 0x8032 -#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 -#define GL_UNSIGNED_SHORT_5_6_5 0x8363 -#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 -#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 -#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 -#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 -#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 -#define GL_UNSIGNED_INT_8_8_8_8 0x8035 -#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#define GL_UNSIGNED_INT_10_10_10_2 0x8036 -#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 -#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 -#define GL_SINGLE_COLOR 0x81F9 -#define GL_SEPARATE_SPECULAR_COLOR 0x81FA -#define GL_TEXTURE_MIN_LOD 0x813A -#define GL_TEXTURE_MAX_LOD 0x813B -#define GL_TEXTURE_BASE_LEVEL 0x813C -#define GL_TEXTURE_MAX_LEVEL 0x813D -#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 -#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 -#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 -#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 -#define GL_ALIASED_POINT_SIZE_RANGE 0x846D -#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E -#define GL_PACK_SKIP_IMAGES 0x806B -#define GL_PACK_IMAGE_HEIGHT 0x806C -#define GL_UNPACK_SKIP_IMAGES 0x806D -#define GL_UNPACK_IMAGE_HEIGHT 0x806E -#define GL_TEXTURE_3D 0x806F -#define GL_PROXY_TEXTURE_3D 0x8070 -#define GL_TEXTURE_DEPTH 0x8071 -#define GL_TEXTURE_WRAP_R 0x8072 -#define GL_MAX_3D_TEXTURE_SIZE 0x8073 -#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_RESCALE_NORMAL 0x803A +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 +#define GL_SINGLE_COLOR 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR 0x81FA +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_TEXTURE_BINDING_3D 0x806A -typedef void (APIENTRYP PFNDOLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); -typedef void (APIENTRYP PFNDOLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNDOLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNDOLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNDOLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, + GLsizei count, GLenum type, + const GLvoid* indices); +typedef void(APIENTRYP PFNDOLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, + const GLvoid* pixels); +typedef void(APIENTRYP PFNDOLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, + GLenum type, const GLvoid* pixels); +typedef void(APIENTRYP PFNDOLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLint zoffset, GLint x, GLint y, + GLsizei width, GLsizei height); extern PFNDOLCOPYTEXSUBIMAGE3DPROC dolCopyTexSubImage3D; extern PFNDOLDRAWRANGEELEMENTSPROC dolDrawRangeElements; diff --git a/Source/Core/Common/GL/GLExtensions/gl_1_3.h b/Source/Core/Common/GL/GLExtensions/gl_1_3.h index 330d9b5b5a..7f78d94bbe 100644 --- a/Source/Core/Common/GL/GLExtensions/gl_1_3.h +++ b/Source/Core/Common/GL/GLExtensions/gl_1_3.h @@ -24,159 +24,184 @@ #include "Common/GL/GLExtensions/gl_common.h" /* multitexture */ -#define GL_TEXTURE0 0x84C0 -#define GL_TEXTURE1 0x84C1 -#define GL_TEXTURE2 0x84C2 -#define GL_TEXTURE3 0x84C3 -#define GL_TEXTURE4 0x84C4 -#define GL_TEXTURE5 0x84C5 -#define GL_TEXTURE6 0x84C6 -#define GL_TEXTURE7 0x84C7 -#define GL_TEXTURE8 0x84C8 -#define GL_TEXTURE9 0x84C9 -#define GL_TEXTURE10 0x84CA -#define GL_TEXTURE11 0x84CB -#define GL_TEXTURE12 0x84CC -#define GL_TEXTURE13 0x84CD -#define GL_TEXTURE14 0x84CE -#define GL_TEXTURE15 0x84CF -#define GL_TEXTURE16 0x84D0 -#define GL_TEXTURE17 0x84D1 -#define GL_TEXTURE18 0x84D2 -#define GL_TEXTURE19 0x84D3 -#define GL_TEXTURE20 0x84D4 -#define GL_TEXTURE21 0x84D5 -#define GL_TEXTURE22 0x84D6 -#define GL_TEXTURE23 0x84D7 -#define GL_TEXTURE24 0x84D8 -#define GL_TEXTURE25 0x84D9 -#define GL_TEXTURE26 0x84DA -#define GL_TEXTURE27 0x84DB -#define GL_TEXTURE28 0x84DC -#define GL_TEXTURE29 0x84DD -#define GL_TEXTURE30 0x84DE -#define GL_TEXTURE31 0x84DF -#define GL_ACTIVE_TEXTURE 0x84E0 -#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 -#define GL_MAX_TEXTURE_UNITS 0x84E2 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 +#define GL_MAX_TEXTURE_UNITS 0x84E2 /* texture_cube_map */ -#define GL_NORMAL_MAP 0x8511 -#define GL_REFLECTION_MAP 0x8512 -#define GL_TEXTURE_CUBE_MAP 0x8513 -#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 -#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 -#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A -#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B -#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_NORMAL_MAP 0x8511 +#define GL_REFLECTION_MAP 0x8512 +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C /* texture_compression */ -#define GL_COMPRESSED_ALPHA 0x84E9 -#define GL_COMPRESSED_LUMINANCE 0x84EA -#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB -#define GL_COMPRESSED_INTENSITY 0x84EC -#define GL_COMPRESSED_RGB 0x84ED -#define GL_COMPRESSED_RGBA 0x84EE -#define GL_TEXTURE_COMPRESSION_HINT 0x84EF -#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 -#define GL_TEXTURE_COMPRESSED 0x86A1 -#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 -#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_COMPRESSED_ALPHA 0x84E9 +#define GL_COMPRESSED_LUMINANCE 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB +#define GL_COMPRESSED_INTENSITY 0x84EC +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 /* multisample */ -#define GL_MULTISAMPLE 0x809D -#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE 0x809F -#define GL_SAMPLE_COVERAGE 0x80A0 -#define GL_SAMPLE_BUFFERS 0x80A8 -#define GL_SAMPLES 0x80A9 -#define GL_SAMPLE_COVERAGE_VALUE 0x80AA -#define GL_SAMPLE_COVERAGE_INVERT 0x80AB -#define GL_MULTISAMPLE_BIT 0x20000000 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_MULTISAMPLE_BIT 0x20000000 /* transpose_matrix */ -#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 -#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 -#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 -#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 +#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 +#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 +#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 +#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 /* texture_env_combine */ -#define GL_COMBINE 0x8570 -#define GL_COMBINE_RGB 0x8571 -#define GL_COMBINE_ALPHA 0x8572 -#define GL_SOURCE0_RGB 0x8580 -#define GL_SOURCE1_RGB 0x8581 -#define GL_SOURCE2_RGB 0x8582 -#define GL_SOURCE0_ALPHA 0x8588 -#define GL_SOURCE1_ALPHA 0x8589 -#define GL_SOURCE2_ALPHA 0x858A -#define GL_OPERAND0_RGB 0x8590 -#define GL_OPERAND1_RGB 0x8591 -#define GL_OPERAND2_RGB 0x8592 -#define GL_OPERAND0_ALPHA 0x8598 -#define GL_OPERAND1_ALPHA 0x8599 -#define GL_OPERAND2_ALPHA 0x859A -#define GL_RGB_SCALE 0x8573 -#define GL_ADD_SIGNED 0x8574 -#define GL_INTERPOLATE 0x8575 -#define GL_SUBTRACT 0x84E7 -#define GL_CONSTANT 0x8576 -#define GL_PRIMARY_COLOR 0x8577 -#define GL_PREVIOUS 0x8578 +#define GL_COMBINE 0x8570 +#define GL_COMBINE_RGB 0x8571 +#define GL_COMBINE_ALPHA 0x8572 +#define GL_SOURCE0_RGB 0x8580 +#define GL_SOURCE1_RGB 0x8581 +#define GL_SOURCE2_RGB 0x8582 +#define GL_SOURCE0_ALPHA 0x8588 +#define GL_SOURCE1_ALPHA 0x8589 +#define GL_SOURCE2_ALPHA 0x858A +#define GL_OPERAND0_RGB 0x8590 +#define GL_OPERAND1_RGB 0x8591 +#define GL_OPERAND2_RGB 0x8592 +#define GL_OPERAND0_ALPHA 0x8598 +#define GL_OPERAND1_ALPHA 0x8599 +#define GL_OPERAND2_ALPHA 0x859A +#define GL_RGB_SCALE 0x8573 +#define GL_ADD_SIGNED 0x8574 +#define GL_INTERPOLATE 0x8575 +#define GL_SUBTRACT 0x84E7 +#define GL_CONSTANT 0x8576 +#define GL_PRIMARY_COLOR 0x8577 +#define GL_PREVIOUS 0x8578 /* texture_env_dot3 */ -#define GL_DOT3_RGB 0x86AE -#define GL_DOT3_RGBA 0x86AF +#define GL_DOT3_RGB 0x86AE +#define GL_DOT3_RGBA 0x86AF /* texture_border_clamp */ -#define GL_CLAMP_TO_BORDER 0x812D +#define GL_CLAMP_TO_BORDER 0x812D -typedef void (APIENTRYP PFNDOLACTIVETEXTUREPROC) (GLenum texture); -typedef void (APIENTRYP PFNDOLSAMPLECOVERAGEPROC) (GLclampf value, GLboolean invert); -typedef void (APIENTRYP PFNDOLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNDOLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNDOLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNDOLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNDOLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNDOLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNDOLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img); +typedef void(APIENTRYP PFNDOLACTIVETEXTUREPROC)(GLenum texture); +typedef void(APIENTRYP PFNDOLSAMPLECOVERAGEPROC)(GLclampf value, GLboolean invert); +typedef void(APIENTRYP PFNDOLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, + GLenum internalformat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, + GLsizei imageSize, const GLvoid* data); +typedef void(APIENTRYP PFNDOLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, + GLenum internalformat, GLsizei width, + GLsizei height, GLint border, + GLsizei imageSize, const GLvoid* data); +typedef void(APIENTRYP PFNDOLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, + GLenum internalformat, GLsizei width, + GLint border, GLsizei imageSize, + const GLvoid* data); +typedef void(APIENTRYP PFNDOLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, + GLsizei depth, GLenum format, + GLsizei imageSize, const GLvoid* data); +typedef void(APIENTRYP PFNDOLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, + GLint yoffset, GLsizei width, + GLsizei height, GLenum format, + GLsizei imageSize, const GLvoid* data); +typedef void(APIENTRYP PFNDOLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, + GLsizei width, GLenum format, + GLsizei imageSize, const GLvoid* data); +typedef void(APIENTRYP PFNDOLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, GLvoid* img); -typedef void (APIENTRYP PFNDOLACTIVETEXTUREARBPROC) (GLenum texture); -typedef void (APIENTRYP PFNDOLCLIENTACTIVETEXTUREARBPROC) (GLenum texture); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); -typedef void (APIENTRYP PFNDOLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v); -typedef void (APIENTRYP PFNDOLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); -typedef void (APIENTRYP PFNDOLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); -typedef void (APIENTRYP PFNDOLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); -typedef void (APIENTRYP PFNDOLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); -typedef void (APIENTRYP PFNDOLSAMPLECOVERAGEARBPROC) (GLfloat value, GLboolean invert); +typedef void(APIENTRYP PFNDOLACTIVETEXTUREARBPROC)(GLenum texture); +typedef void(APIENTRYP PFNDOLCLIENTACTIVETEXTUREARBPROC)(GLenum texture); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD1DARBPROC)(GLenum target, GLdouble s); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD1DVARBPROC)(GLenum target, const GLdouble* v); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD1FARBPROC)(GLenum target, GLfloat s); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD1FVARBPROC)(GLenum target, const GLfloat* v); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD1IARBPROC)(GLenum target, GLint s); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD1IVARBPROC)(GLenum target, const GLint* v); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD1SARBPROC)(GLenum target, GLshort s); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD1SVARBPROC)(GLenum target, const GLshort* v); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD2DARBPROC)(GLenum target, GLdouble s, GLdouble t); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD2DVARBPROC)(GLenum target, const GLdouble* v); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD2FARBPROC)(GLenum target, GLfloat s, GLfloat t); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD2FVARBPROC)(GLenum target, const GLfloat* v); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD2IARBPROC)(GLenum target, GLint s, GLint t); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD2IVARBPROC)(GLenum target, const GLint* v); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD2SARBPROC)(GLenum target, GLshort s, GLshort t); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD2SVARBPROC)(GLenum target, const GLshort* v); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD3DARBPROC)(GLenum target, GLdouble s, GLdouble t, + GLdouble r); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD3DVARBPROC)(GLenum target, const GLdouble* v); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD3FARBPROC)(GLenum target, GLfloat s, GLfloat t, + GLfloat r); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD3FVARBPROC)(GLenum target, const GLfloat* v); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD3IARBPROC)(GLenum target, GLint s, GLint t, GLint r); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD3IVARBPROC)(GLenum target, const GLint* v); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD3SARBPROC)(GLenum target, GLshort s, GLshort t, + GLshort r); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD3SVARBPROC)(GLenum target, const GLshort* v); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD4DARBPROC)(GLenum target, GLdouble s, GLdouble t, + GLdouble r, GLdouble q); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD4DVARBPROC)(GLenum target, const GLdouble* v); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD4FARBPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r, + GLfloat q); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD4FVARBPROC)(GLenum target, const GLfloat* v); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD4IARBPROC)(GLenum target, GLint s, GLint t, GLint r, + GLint q); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD4IVARBPROC)(GLenum target, const GLint* v); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD4SARBPROC)(GLenum target, GLshort s, GLshort t, GLshort r, + GLshort q); +typedef void(APIENTRYP PFNDOLMULTITEXCOORD4SVARBPROC)(GLenum target, const GLshort* v); +typedef void(APIENTRYP PFNDOLLOADTRANSPOSEMATRIXFARBPROC)(const GLfloat* m); +typedef void(APIENTRYP PFNDOLLOADTRANSPOSEMATRIXDARBPROC)(const GLdouble* m); +typedef void(APIENTRYP PFNDOLMULTTRANSPOSEMATRIXFARBPROC)(const GLfloat* m); +typedef void(APIENTRYP PFNDOLMULTTRANSPOSEMATRIXDARBPROC)(const GLdouble* m); +typedef void(APIENTRYP PFNDOLSAMPLECOVERAGEARBPROC)(GLfloat value, GLboolean invert); extern PFNDOLACTIVETEXTUREARBPROC dolActiveTexture; extern PFNDOLCLIENTACTIVETEXTUREARBPROC dolClientActiveTexture; diff --git a/Source/Core/Common/GL/GLExtensions/gl_1_4.h b/Source/Core/Common/GL/GLExtensions/gl_1_4.h index 1c0ce3641d..b50b0b01a0 100644 --- a/Source/Core/Common/GL/GLExtensions/gl_1_4.h +++ b/Source/Core/Common/GL/GLExtensions/gl_1_4.h @@ -23,102 +23,107 @@ #include "Common/GL/GLExtensions/gl_common.h" -#define GL_BLEND_DST_RGB 0x80C8 -#define GL_BLEND_SRC_RGB 0x80C9 -#define GL_BLEND_DST_ALPHA 0x80CA -#define GL_BLEND_SRC_ALPHA 0x80CB -#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 -#define GL_DEPTH_COMPONENT16 0x81A5 -#define GL_DEPTH_COMPONENT24 0x81A6 -#define GL_DEPTH_COMPONENT32 0x81A7 -#define GL_MIRRORED_REPEAT 0x8370 -#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD -#define GL_TEXTURE_LOD_BIAS 0x8501 -#define GL_INCR_WRAP 0x8507 -#define GL_DECR_WRAP 0x8508 -#define GL_TEXTURE_DEPTH_SIZE 0x884A -#define GL_TEXTURE_COMPARE_MODE 0x884C -#define GL_TEXTURE_COMPARE_FUNC 0x884D -#define GL_POINT_SIZE_MIN 0x8126 -#define GL_POINT_SIZE_MAX 0x8127 -#define GL_POINT_DISTANCE_ATTENUATION 0x8129 -#define GL_GENERATE_MIPMAP 0x8191 -#define GL_GENERATE_MIPMAP_HINT 0x8192 -#define GL_FOG_COORDINATE_SOURCE 0x8450 -#define GL_FOG_COORDINATE 0x8451 -#define GL_FRAGMENT_DEPTH 0x8452 -#define GL_CURRENT_FOG_COORDINATE 0x8453 -#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 -#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 -#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 -#define GL_FOG_COORDINATE_ARRAY 0x8457 -#define GL_COLOR_SUM 0x8458 -#define GL_CURRENT_SECONDARY_COLOR 0x8459 -#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A -#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B -#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C -#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D -#define GL_SECONDARY_COLOR_ARRAY 0x845E -#define GL_TEXTURE_FILTER_CONTROL 0x8500 -#define GL_DEPTH_TEXTURE_MODE 0x884B -#define GL_COMPARE_R_TO_TEXTURE 0x884E -#define GL_FUNC_ADD 0x8006 -#define GL_FUNC_SUBTRACT 0x800A -#define GL_FUNC_REVERSE_SUBTRACT 0x800B -#define GL_MIN 0x8007 -#define GL_MAX 0x8008 -#define GL_CONSTANT_COLOR 0x8001 -#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 -#define GL_CONSTANT_ALPHA 0x8003 -#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_POINT_SIZE_MIN 0x8126 +#define GL_POINT_SIZE_MAX 0x8127 +#define GL_POINT_DISTANCE_ATTENUATION 0x8129 +#define GL_GENERATE_MIPMAP 0x8191 +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_FOG_COORDINATE_SOURCE 0x8450 +#define GL_FOG_COORDINATE 0x8451 +#define GL_FRAGMENT_DEPTH 0x8452 +#define GL_CURRENT_FOG_COORDINATE 0x8453 +#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 +#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 +#define GL_FOG_COORDINATE_ARRAY 0x8457 +#define GL_COLOR_SUM 0x8458 +#define GL_CURRENT_SECONDARY_COLOR 0x8459 +#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A +#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B +#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C +#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D +#define GL_SECONDARY_COLOR_ARRAY 0x845E +#define GL_TEXTURE_FILTER_CONTROL 0x8500 +#define GL_DEPTH_TEXTURE_MODE 0x884B +#define GL_COMPARE_R_TO_TEXTURE 0x884E +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 -typedef void (APIENTRYP PFNDOLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); -typedef void (APIENTRYP PFNDOLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); -typedef void (APIENTRYP PFNDOLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); -typedef void (APIENTRYP PFNDOLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNDOLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNDOLPOINTPARAMETERIPROC) (GLenum pname, GLint param); -typedef void (APIENTRYP PFNDOLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNDOLFOGCOORDFPROC) (GLfloat coord); -typedef void (APIENTRYP PFNDOLFOGCOORDFVPROC) (const GLfloat *coord); -typedef void (APIENTRYP PFNDOLFOGCOORDDPROC) (GLdouble coord); -typedef void (APIENTRYP PFNDOLFOGCOORDDVPROC) (const GLdouble *coord); -typedef void (APIENTRYP PFNDOLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3BVPROC) (const GLbyte *v); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3DVPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3FVPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3IVPROC) (const GLint *v); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3SVPROC) (const GLshort *v); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3UBVPROC) (const GLubyte *v); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3UIVPROC) (const GLuint *v); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue); -typedef void (APIENTRYP PFNDOLSECONDARYCOLOR3USVPROC) (const GLushort *v); -typedef void (APIENTRYP PFNDOLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNDOLWINDOWPOS2DPROC) (GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNDOLWINDOWPOS2DVPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNDOLWINDOWPOS2FPROC) (GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNDOLWINDOWPOS2FVPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNDOLWINDOWPOS2IPROC) (GLint x, GLint y); -typedef void (APIENTRYP PFNDOLWINDOWPOS2IVPROC) (const GLint *v); -typedef void (APIENTRYP PFNDOLWINDOWPOS2SPROC) (GLshort x, GLshort y); -typedef void (APIENTRYP PFNDOLWINDOWPOS2SVPROC) (const GLshort *v); -typedef void (APIENTRYP PFNDOLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNDOLWINDOWPOS3DVPROC) (const GLdouble *v); -typedef void (APIENTRYP PFNDOLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNDOLWINDOWPOS3FVPROC) (const GLfloat *v); -typedef void (APIENTRYP PFNDOLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNDOLWINDOWPOS3IVPROC) (const GLint *v); -typedef void (APIENTRYP PFNDOLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNDOLWINDOWPOS3SVPROC) (const GLshort *v); -typedef void (APIENTRYP PFNDOLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -typedef void (APIENTRYP PFNDOLBLENDEQUATIONPROC) (GLenum mode); +typedef void(APIENTRYP PFNDOLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void(APIENTRYP PFNDOLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint* first, + const GLsizei* count, GLsizei drawcount); +typedef void(APIENTRYP PFNDOLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei* count, GLenum type, + const void* const* indices, GLsizei drawcount); +typedef void(APIENTRYP PFNDOLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNDOLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat* params); +typedef void(APIENTRYP PFNDOLPOINTPARAMETERIPROC)(GLenum pname, GLint param); +typedef void(APIENTRYP PFNDOLPOINTPARAMETERIVPROC)(GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNDOLFOGCOORDFPROC)(GLfloat coord); +typedef void(APIENTRYP PFNDOLFOGCOORDFVPROC)(const GLfloat* coord); +typedef void(APIENTRYP PFNDOLFOGCOORDDPROC)(GLdouble coord); +typedef void(APIENTRYP PFNDOLFOGCOORDDVPROC)(const GLdouble* coord); +typedef void(APIENTRYP PFNDOLFOGCOORDPOINTERPROC)(GLenum type, GLsizei stride, const void* pointer); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3BVPROC)(const GLbyte* v); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3IPROC)(GLint red, GLint green, GLint blue); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3UBVPROC)(const GLubyte* v); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3UIVPROC)(const GLuint* v); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); +typedef void(APIENTRYP PFNDOLSECONDARYCOLOR3USVPROC)(const GLushort* v); +typedef void(APIENTRYP PFNDOLSECONDARYCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, + const void* pointer); +typedef void(APIENTRYP PFNDOLWINDOWPOS2DPROC)(GLdouble x, GLdouble y); +typedef void(APIENTRYP PFNDOLWINDOWPOS2DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLWINDOWPOS2FPROC)(GLfloat x, GLfloat y); +typedef void(APIENTRYP PFNDOLWINDOWPOS2FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLWINDOWPOS2IPROC)(GLint x, GLint y); +typedef void(APIENTRYP PFNDOLWINDOWPOS2IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLWINDOWPOS2SPROC)(GLshort x, GLshort y); +typedef void(APIENTRYP PFNDOLWINDOWPOS2SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLWINDOWPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); +typedef void(APIENTRYP PFNDOLWINDOWPOS3DVPROC)(const GLdouble* v); +typedef void(APIENTRYP PFNDOLWINDOWPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); +typedef void(APIENTRYP PFNDOLWINDOWPOS3FVPROC)(const GLfloat* v); +typedef void(APIENTRYP PFNDOLWINDOWPOS3IPROC)(GLint x, GLint y, GLint z); +typedef void(APIENTRYP PFNDOLWINDOWPOS3IVPROC)(const GLint* v); +typedef void(APIENTRYP PFNDOLWINDOWPOS3SPROC)(GLshort x, GLshort y, GLshort z); +typedef void(APIENTRYP PFNDOLWINDOWPOS3SVPROC)(const GLshort* v); +typedef void(APIENTRYP PFNDOLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, + GLfloat alpha); +typedef void(APIENTRYP PFNDOLBLENDEQUATIONPROC)(GLenum mode); // These two are provided by ARB_imaging as well extern PFNDOLBLENDCOLORPROC dolBlendColor; diff --git a/Source/Core/Common/GL/GLExtensions/gl_1_5.h b/Source/Core/Common/GL/GLExtensions/gl_1_5.h index 2867182984..19a8e22fea 100644 --- a/Source/Core/Common/GL/GLExtensions/gl_1_5.h +++ b/Source/Core/Common/GL/GLExtensions/gl_1_5.h @@ -23,76 +23,79 @@ #include "Common/GL/GLExtensions/gl_common.h" -#define GL_BUFFER_SIZE 0x8764 -#define GL_BUFFER_USAGE 0x8765 -#define GL_QUERY_COUNTER_BITS 0x8864 -#define GL_CURRENT_QUERY 0x8865 -#define GL_QUERY_RESULT 0x8866 -#define GL_QUERY_RESULT_AVAILABLE 0x8867 -#define GL_ARRAY_BUFFER 0x8892 -#define GL_ELEMENT_ARRAY_BUFFER 0x8893 -#define GL_ARRAY_BUFFER_BINDING 0x8894 -#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F -#define GL_READ_ONLY 0x88B8 -#define GL_WRITE_ONLY 0x88B9 -#define GL_READ_WRITE 0x88BA -#define GL_BUFFER_ACCESS 0x88BB -#define GL_BUFFER_MAPPED 0x88BC -#define GL_BUFFER_MAP_POINTER 0x88BD -#define GL_STREAM_DRAW 0x88E0 -#define GL_STREAM_READ 0x88E1 -#define GL_STREAM_COPY 0x88E2 -#define GL_STATIC_DRAW 0x88E4 -#define GL_STATIC_READ 0x88E5 -#define GL_STATIC_COPY 0x88E6 -#define GL_DYNAMIC_DRAW 0x88E8 -#define GL_DYNAMIC_READ 0x88E9 -#define GL_DYNAMIC_COPY 0x88EA -#define GL_SAMPLES_PASSED 0x8914 -#define GL_SRC1_ALPHA 0x8589 -#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 -#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 -#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 -#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SRC1_ALPHA 0x8589 +#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 #define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A #define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B #define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C #define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D -#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E -#define GL_FOG_COORD_SRC 0x8450 -#define GL_FOG_COORD 0x8451 -#define GL_CURRENT_FOG_COORD 0x8453 -#define GL_FOG_COORD_ARRAY_TYPE 0x8454 -#define GL_FOG_COORD_ARRAY_STRIDE 0x8455 -#define GL_FOG_COORD_ARRAY_POINTER 0x8456 -#define GL_FOG_COORD_ARRAY 0x8457 +#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E +#define GL_FOG_COORD_SRC 0x8450 +#define GL_FOG_COORD 0x8451 +#define GL_CURRENT_FOG_COORD 0x8453 +#define GL_FOG_COORD_ARRAY_TYPE 0x8454 +#define GL_FOG_COORD_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORD_ARRAY_POINTER 0x8456 +#define GL_FOG_COORD_ARRAY 0x8457 #define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D -#define GL_SRC0_RGB 0x8580 -#define GL_SRC1_RGB 0x8581 -#define GL_SRC2_RGB 0x8582 -#define GL_SRC0_ALPHA 0x8588 -#define GL_SRC2_ALPHA 0x858A +#define GL_SRC0_RGB 0x8580 +#define GL_SRC1_RGB 0x8581 +#define GL_SRC2_RGB 0x8582 +#define GL_SRC0_ALPHA 0x8588 +#define GL_SRC2_ALPHA 0x858A -typedef void (APIENTRYP PFNDOLGENQUERIESPROC) (GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNDOLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); -typedef GLboolean (APIENTRYP PFNDOLISQUERYPROC) (GLuint id); -typedef void (APIENTRYP PFNDOLBEGINQUERYPROC) (GLenum target, GLuint id); -typedef void (APIENTRYP PFNDOLENDQUERYPROC) (GLenum target); -typedef void (APIENTRYP PFNDOLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNDOLBINDBUFFERPROC) (GLenum target, GLuint buffer); -typedef void (APIENTRYP PFNDOLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); -typedef void (APIENTRYP PFNDOLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); -typedef GLboolean (APIENTRYP PFNDOLISBUFFERPROC) (GLuint buffer); -typedef void (APIENTRYP PFNDOLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage); -typedef void (APIENTRYP PFNDOLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); -typedef void (APIENTRYP PFNDOLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void *data); -typedef void *(APIENTRYP PFNDOLMAPBUFFERPROC) (GLenum target, GLenum access); -typedef GLboolean (APIENTRYP PFNDOLUNMAPBUFFERPROC) (GLenum target); -typedef void (APIENTRYP PFNDOLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params); +typedef void(APIENTRYP PFNDOLGENQUERIESPROC)(GLsizei n, GLuint* ids); +typedef void(APIENTRYP PFNDOLDELETEQUERIESPROC)(GLsizei n, const GLuint* ids); +typedef GLboolean(APIENTRYP PFNDOLISQUERYPROC)(GLuint id); +typedef void(APIENTRYP PFNDOLBEGINQUERYPROC)(GLenum target, GLuint id); +typedef void(APIENTRYP PFNDOLENDQUERYPROC)(GLenum target); +typedef void(APIENTRYP PFNDOLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint* params); +typedef void(APIENTRYP PFNDOLBINDBUFFERPROC)(GLenum target, GLuint buffer); +typedef void(APIENTRYP PFNDOLDELETEBUFFERSPROC)(GLsizei n, const GLuint* buffers); +typedef void(APIENTRYP PFNDOLGENBUFFERSPROC)(GLsizei n, GLuint* buffers); +typedef GLboolean(APIENTRYP PFNDOLISBUFFERPROC)(GLuint buffer); +typedef void(APIENTRYP PFNDOLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void* data, + GLenum usage); +typedef void(APIENTRYP PFNDOLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, + const void* data); +typedef void(APIENTRYP PFNDOLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, + void* data); +typedef void*(APIENTRYP PFNDOLMAPBUFFERPROC)(GLenum target, GLenum access); +typedef GLboolean(APIENTRYP PFNDOLUNMAPBUFFERPROC)(GLenum target); +typedef void(APIENTRYP PFNDOLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void** params); extern PFNDOLBEGINQUERYPROC dolBeginQuery; extern PFNDOLBINDBUFFERPROC dolBindBuffer; diff --git a/Source/Core/Common/GL/GLExtensions/gl_2_0.h b/Source/Core/Common/GL/GLExtensions/gl_2_0.h index acac1d80f0..fad38d567c 100644 --- a/Source/Core/Common/GL/GLExtensions/gl_2_0.h +++ b/Source/Core/Common/GL/GLExtensions/gl_2_0.h @@ -23,184 +23,207 @@ #include "Common/GL/GLExtensions/gl_common.h" -#define GL_BLEND_EQUATION_RGB 0x8009 -#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 -#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 -#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 -#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 -#define GL_CURRENT_VERTEX_ATTRIB 0x8626 -#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 -#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 -#define GL_STENCIL_BACK_FUNC 0x8800 -#define GL_STENCIL_BACK_FAIL 0x8801 -#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 -#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 -#define GL_MAX_DRAW_BUFFERS 0x8824 -#define GL_DRAW_BUFFER0 0x8825 -#define GL_DRAW_BUFFER1 0x8826 -#define GL_DRAW_BUFFER2 0x8827 -#define GL_DRAW_BUFFER3 0x8828 -#define GL_DRAW_BUFFER4 0x8829 -#define GL_DRAW_BUFFER5 0x882A -#define GL_DRAW_BUFFER6 0x882B -#define GL_DRAW_BUFFER7 0x882C -#define GL_DRAW_BUFFER8 0x882D -#define GL_DRAW_BUFFER9 0x882E -#define GL_DRAW_BUFFER10 0x882F -#define GL_DRAW_BUFFER11 0x8830 -#define GL_DRAW_BUFFER12 0x8831 -#define GL_DRAW_BUFFER13 0x8832 -#define GL_DRAW_BUFFER14 0x8833 -#define GL_DRAW_BUFFER15 0x8834 -#define GL_BLEND_EQUATION_ALPHA 0x883D -#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A -#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 -#define GL_FRAGMENT_SHADER 0x8B30 -#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 -#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A -#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D -#define GL_SHADER_TYPE 0x8B4F -#define GL_FLOAT_VEC2 0x8B50 -#define GL_FLOAT_VEC3 0x8B51 -#define GL_FLOAT_VEC4 0x8B52 -#define GL_INT_VEC2 0x8B53 -#define GL_INT_VEC3 0x8B54 -#define GL_INT_VEC4 0x8B55 -#define GL_BOOL 0x8B56 -#define GL_BOOL_VEC2 0x8B57 -#define GL_BOOL_VEC3 0x8B58 -#define GL_BOOL_VEC4 0x8B59 -#define GL_FLOAT_MAT2 0x8B5A -#define GL_FLOAT_MAT3 0x8B5B -#define GL_FLOAT_MAT4 0x8B5C -#define GL_SAMPLER_1D 0x8B5D -#define GL_SAMPLER_2D 0x8B5E -#define GL_SAMPLER_3D 0x8B5F -#define GL_SAMPLER_CUBE 0x8B60 -#define GL_SAMPLER_1D_SHADOW 0x8B61 -#define GL_SAMPLER_2D_SHADOW 0x8B62 -#define GL_DELETE_STATUS 0x8B80 -#define GL_COMPILE_STATUS 0x8B81 -#define GL_LINK_STATUS 0x8B82 -#define GL_VALIDATE_STATUS 0x8B83 -#define GL_INFO_LOG_LENGTH 0x8B84 -#define GL_ATTACHED_SHADERS 0x8B85 -#define GL_ACTIVE_UNIFORMS 0x8B86 -#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 -#define GL_SHADER_SOURCE_LENGTH 0x8B88 -#define GL_ACTIVE_ATTRIBUTES 0x8B89 -#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B -#define GL_SHADING_LANGUAGE_VERSION 0x8B8C -#define GL_CURRENT_PROGRAM 0x8B8D -#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 -#define GL_LOWER_LEFT 0x8CA1 -#define GL_UPPER_LEFT 0x8CA2 -#define GL_STENCIL_BACK_REF 0x8CA3 -#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 -#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 -#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 -#define GL_POINT_SPRITE 0x8861 -#define GL_COORD_REPLACE 0x8862 -#define GL_MAX_TEXTURE_COORDS 0x8871 +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 +#define GL_POINT_SPRITE 0x8861 +#define GL_COORD_REPLACE 0x8862 +#define GL_MAX_TEXTURE_COORDS 0x8871 -typedef void (APIENTRYP PFNDOLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); -typedef void (APIENTRYP PFNDOLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); -typedef void (APIENTRYP PFNDOLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); -typedef void (APIENTRYP PFNDOLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); -typedef void (APIENTRYP PFNDOLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); -typedef void (APIENTRYP PFNDOLATTACHSHADERPROC) (GLuint program, GLuint shader); -typedef void (APIENTRYP PFNDOLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); -typedef void (APIENTRYP PFNDOLCOMPILESHADERPROC) (GLuint shader); -typedef GLuint (APIENTRYP PFNDOLCREATEPROGRAMPROC) (void); -typedef GLuint (APIENTRYP PFNDOLCREATESHADERPROC) (GLenum type); -typedef void (APIENTRYP PFNDOLDELETEPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNDOLDELETESHADERPROC) (GLuint shader); -typedef void (APIENTRYP PFNDOLDETACHSHADERPROC) (GLuint program, GLuint shader); -typedef void (APIENTRYP PFNDOLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); -typedef void (APIENTRYP PFNDOLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); -typedef void (APIENTRYP PFNDOLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNDOLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNDOLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); -typedef GLint (APIENTRYP PFNDOLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNDOLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef void (APIENTRYP PFNDOLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); -typedef void (APIENTRYP PFNDOLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); -typedef GLint (APIENTRYP PFNDOLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNDOLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); -typedef void (APIENTRYP PFNDOLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); -typedef void (APIENTRYP PFNDOLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); -typedef void (APIENTRYP PFNDOLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNDOLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer); -typedef GLboolean (APIENTRYP PFNDOLISPROGRAMPROC) (GLuint program); -typedef GLboolean (APIENTRYP PFNDOLISSHADERPROC) (GLuint shader); -typedef void (APIENTRYP PFNDOLLINKPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNDOLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); -typedef void (APIENTRYP PFNDOLUSEPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNDOLUNIFORM1FPROC) (GLint location, GLfloat v0); -typedef void (APIENTRYP PFNDOLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); -typedef void (APIENTRYP PFNDOLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -typedef void (APIENTRYP PFNDOLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -typedef void (APIENTRYP PFNDOLUNIFORM1IPROC) (GLint location, GLint v0); -typedef void (APIENTRYP PFNDOLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); -typedef void (APIENTRYP PFNDOLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); -typedef void (APIENTRYP PFNDOLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -typedef void (APIENTRYP PFNDOLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNDOLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNDOLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNDOLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); -typedef void (APIENTRYP PFNDOLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNDOLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNDOLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNDOLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); -typedef void (APIENTRYP PFNDOLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNDOLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNDOLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNDOLVALIDATEPROGRAMPROC) (GLuint program); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB1SPROC) (GLuint index, GLshort x); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +typedef void(APIENTRYP PFNDOLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); +typedef void(APIENTRYP PFNDOLDRAWBUFFERSPROC)(GLsizei n, const GLenum* bufs); +typedef void(APIENTRYP PFNDOLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, + GLenum dppass); +typedef void(APIENTRYP PFNDOLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, + GLuint mask); +typedef void(APIENTRYP PFNDOLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); +typedef void(APIENTRYP PFNDOLATTACHSHADERPROC)(GLuint program, GLuint shader); +typedef void(APIENTRYP PFNDOLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, + const GLchar* name); +typedef void(APIENTRYP PFNDOLCOMPILESHADERPROC)(GLuint shader); +typedef GLuint(APIENTRYP PFNDOLCREATEPROGRAMPROC)(void); +typedef GLuint(APIENTRYP PFNDOLCREATESHADERPROC)(GLenum type); +typedef void(APIENTRYP PFNDOLDELETEPROGRAMPROC)(GLuint program); +typedef void(APIENTRYP PFNDOLDELETESHADERPROC)(GLuint shader); +typedef void(APIENTRYP PFNDOLDETACHSHADERPROC)(GLuint program, GLuint shader); +typedef void(APIENTRYP PFNDOLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); +typedef void(APIENTRYP PFNDOLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); +typedef void(APIENTRYP PFNDOLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, + GLsizei* length, GLint* size, GLenum* type, + GLchar* name); +typedef void(APIENTRYP PFNDOLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, + GLsizei* length, GLint* size, GLenum* type, + GLchar* name); +typedef void(APIENTRYP PFNDOLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, + GLsizei* count, GLuint* shaders); +typedef GLint(APIENTRYP PFNDOLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar* name); +typedef void(APIENTRYP PFNDOLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, + GLsizei* length, GLchar* infoLog); +typedef void(APIENTRYP PFNDOLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei* length, + GLchar* infoLog); +typedef void(APIENTRYP PFNDOLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei* length, + GLchar* source); +typedef GLint(APIENTRYP PFNDOLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar* name); +typedef void(APIENTRYP PFNDOLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat* params); +typedef void(APIENTRYP PFNDOLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint* params); +typedef void(APIENTRYP PFNDOLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble* params); +typedef void(APIENTRYP PFNDOLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNDOLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, + void** pointer); +typedef GLboolean(APIENTRYP PFNDOLISPROGRAMPROC)(GLuint program); +typedef GLboolean(APIENTRYP PFNDOLISSHADERPROC)(GLuint shader); +typedef void(APIENTRYP PFNDOLLINKPROGRAMPROC)(GLuint program); +typedef void(APIENTRYP PFNDOLSHADERSOURCEPROC)(GLuint shader, GLsizei count, + const GLchar* const* string, const GLint* length); +typedef void(APIENTRYP PFNDOLUSEPROGRAMPROC)(GLuint program); +typedef void(APIENTRYP PFNDOLUNIFORM1FPROC)(GLint location, GLfloat v0); +typedef void(APIENTRYP PFNDOLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); +typedef void(APIENTRYP PFNDOLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void(APIENTRYP PFNDOLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, + GLfloat v3); +typedef void(APIENTRYP PFNDOLUNIFORM1IPROC)(GLint location, GLint v0); +typedef void(APIENTRYP PFNDOLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); +typedef void(APIENTRYP PFNDOLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); +typedef void(APIENTRYP PFNDOLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void(APIENTRYP PFNDOLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNDOLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNDOLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNDOLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat* value); +typedef void(APIENTRYP PFNDOLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNDOLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNDOLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNDOLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint* value); +typedef void(APIENTRYP PFNDOLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, + GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNDOLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, + GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNDOLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, + GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNDOLVALIDATEPROGRAMPROC)(GLuint program); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, + GLubyte w); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, + GLdouble w); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, + GLfloat w); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4IVPROC)(GLuint index, const GLint* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, + GLshort w); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, + GLboolean normalized, GLsizei stride, + const void* pointer); extern PFNDOLATTACHSHADERPROC dolAttachShader; extern PFNDOLBINDATTRIBLOCATIONPROC dolBindAttribLocation; diff --git a/Source/Core/Common/GL/GLExtensions/gl_2_1.h b/Source/Core/Common/GL/GLExtensions/gl_2_1.h index 48c1f03312..cfb164ab40 100644 --- a/Source/Core/Common/GL/GLExtensions/gl_2_1.h +++ b/Source/Core/Common/GL/GLExtensions/gl_2_1.h @@ -47,12 +47,18 @@ #define GL_COMPRESSED_SLUMINANCE 0x8C4A #define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B -typedef void (APIENTRYP PFNDOLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNDOLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNDOLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNDOLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNDOLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNDOLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void(APIENTRYP PFNDOLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, + GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNDOLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, + GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNDOLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, + GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNDOLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, + GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNDOLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, + GLboolean transpose, const GLfloat* value); +typedef void(APIENTRYP PFNDOLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, + GLboolean transpose, const GLfloat* value); extern PFNDOLUNIFORMMATRIX2X3FVPROC dolUniformMatrix2x3fv; extern PFNDOLUNIFORMMATRIX2X4FVPROC dolUniformMatrix2x4fv; diff --git a/Source/Core/Common/GL/GLExtensions/gl_3_0.h b/Source/Core/Common/GL/GLExtensions/gl_3_0.h index de28cb75ce..ecf24e33c7 100644 --- a/Source/Core/Common/GL/GLExtensions/gl_3_0.h +++ b/Source/Core/Common/GL/GLExtensions/gl_3_0.h @@ -23,110 +23,110 @@ #include "Common/GL/GLExtensions/gl_common.h" -#define GL_COMPARE_REF_TO_TEXTURE 0x884E -#define GL_CLIP_DISTANCE0 0x3000 -#define GL_CLIP_DISTANCE1 0x3001 -#define GL_CLIP_DISTANCE2 0x3002 -#define GL_CLIP_DISTANCE3 0x3003 -#define GL_CLIP_DISTANCE4 0x3004 -#define GL_CLIP_DISTANCE5 0x3005 -#define GL_CLIP_DISTANCE6 0x3006 -#define GL_CLIP_DISTANCE7 0x3007 -#define GL_MAX_CLIP_DISTANCES 0x0D32 -#define GL_MAJOR_VERSION 0x821B -#define GL_MINOR_VERSION 0x821C -#define GL_NUM_EXTENSIONS 0x821D -#define GL_CONTEXT_FLAGS 0x821E -#define GL_COMPRESSED_RED 0x8225 -#define GL_COMPRESSED_RG 0x8226 +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_CLIP_DISTANCE0 0x3000 +#define GL_CLIP_DISTANCE1 0x3001 +#define GL_CLIP_DISTANCE2 0x3002 +#define GL_CLIP_DISTANCE3 0x3003 +#define GL_CLIP_DISTANCE4 0x3004 +#define GL_CLIP_DISTANCE5 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RG 0x8226 #define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 -#define GL_RGBA32F 0x8814 -#define GL_RGB32F 0x8815 -#define GL_RGBA16F 0x881A -#define GL_RGB16F 0x881B -#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD -#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF -#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 -#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 -#define GL_CLAMP_READ_COLOR 0x891C -#define GL_FIXED_ONLY 0x891D -#define GL_MAX_VARYING_COMPONENTS 0x8B4B -#define GL_TEXTURE_1D_ARRAY 0x8C18 -#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 -#define GL_TEXTURE_2D_ARRAY 0x8C1A -#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B -#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C -#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D -#define GL_R11F_G11F_B10F 0x8C3A -#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B -#define GL_RGB9_E5 0x8C3D -#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E -#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_FIXED_ONLY 0x891D +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_RGB9_E5 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_TEXTURE_SHARED_SIZE 0x8C3F #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 -#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 -#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_PRIMITIVES_GENERATED 0x8C87 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 -#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_RASTERIZER_DISCARD 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B -#define GL_INTERLEAVED_ATTRIBS 0x8C8C -#define GL_SEPARATE_ATTRIBS 0x8C8D -#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F -#define GL_RGBA32UI 0x8D70 -#define GL_RGB32UI 0x8D71 -#define GL_RGBA16UI 0x8D76 -#define GL_RGB16UI 0x8D77 -#define GL_RGBA8UI 0x8D7C -#define GL_RGB8UI 0x8D7D -#define GL_RGBA32I 0x8D82 -#define GL_RGB32I 0x8D83 -#define GL_RGBA16I 0x8D88 -#define GL_RGB16I 0x8D89 -#define GL_RGBA8I 0x8D8E -#define GL_RGB8I 0x8D8F -#define GL_RED_INTEGER 0x8D94 -#define GL_GREEN_INTEGER 0x8D95 -#define GL_BLUE_INTEGER 0x8D96 -#define GL_RGB_INTEGER 0x8D98 -#define GL_RGBA_INTEGER 0x8D99 -#define GL_BGR_INTEGER 0x8D9A -#define GL_BGRA_INTEGER 0x8D9B -#define GL_SAMPLER_1D_ARRAY 0x8DC0 -#define GL_SAMPLER_2D_ARRAY 0x8DC1 -#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 -#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 -#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 -#define GL_UNSIGNED_INT_VEC2 0x8DC6 -#define GL_UNSIGNED_INT_VEC3 0x8DC7 -#define GL_UNSIGNED_INT_VEC4 0x8DC8 -#define GL_INT_SAMPLER_1D 0x8DC9 -#define GL_INT_SAMPLER_2D 0x8DCA -#define GL_INT_SAMPLER_3D 0x8DCB -#define GL_INT_SAMPLER_CUBE 0x8DCC -#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE -#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF -#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 -#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 -#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 -#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 -#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 -#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 -#define GL_QUERY_WAIT 0x8E13 -#define GL_QUERY_NO_WAIT 0x8E14 -#define GL_QUERY_BY_REGION_WAIT 0x8E15 -#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 -#define GL_BUFFER_ACCESS_FLAGS 0x911F -#define GL_BUFFER_MAP_LENGTH 0x9120 -#define GL_BUFFER_MAP_OFFSET 0x9121 -#define GL_DEPTH_COMPONENT32F 0x8CAC -#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_BGR_INTEGER 0x8D9A +#define GL_BGRA_INTEGER 0x8D9B +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_QUERY_WAIT 0x8E13 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD -#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 #define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 @@ -135,216 +135,252 @@ #define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 #define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 #define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 -#define GL_FRAMEBUFFER_DEFAULT 0x8218 -#define GL_FRAMEBUFFER_UNDEFINED 0x8219 -#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A -#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 -#define GL_DEPTH_STENCIL 0x84F9 -#define GL_UNSIGNED_INT_24_8 0x84FA -#define GL_DEPTH24_STENCIL8 0x88F0 -#define GL_TEXTURE_STENCIL_SIZE 0x88F1 -#define GL_TEXTURE_RED_TYPE 0x8C10 -#define GL_TEXTURE_GREEN_TYPE 0x8C11 -#define GL_TEXTURE_BLUE_TYPE 0x8C12 -#define GL_TEXTURE_ALPHA_TYPE 0x8C13 -#define GL_TEXTURE_DEPTH_TYPE 0x8C16 -#define GL_UNSIGNED_NORMALIZED 0x8C17 -#define GL_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 -#define GL_RENDERBUFFER_BINDING 0x8CA7 -#define GL_READ_FRAMEBUFFER 0x8CA8 -#define GL_DRAW_FRAMEBUFFER 0x8CA9 -#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA -#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 -#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC -#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD -#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF -#define GL_COLOR_ATTACHMENT0 0x8CE0 -#define GL_COLOR_ATTACHMENT1 0x8CE1 -#define GL_COLOR_ATTACHMENT2 0x8CE2 -#define GL_COLOR_ATTACHMENT3 0x8CE3 -#define GL_COLOR_ATTACHMENT4 0x8CE4 -#define GL_COLOR_ATTACHMENT5 0x8CE5 -#define GL_COLOR_ATTACHMENT6 0x8CE6 -#define GL_COLOR_ATTACHMENT7 0x8CE7 -#define GL_COLOR_ATTACHMENT8 0x8CE8 -#define GL_COLOR_ATTACHMENT9 0x8CE9 -#define GL_COLOR_ATTACHMENT10 0x8CEA -#define GL_COLOR_ATTACHMENT11 0x8CEB -#define GL_COLOR_ATTACHMENT12 0x8CEC -#define GL_COLOR_ATTACHMENT13 0x8CED -#define GL_COLOR_ATTACHMENT14 0x8CEE -#define GL_COLOR_ATTACHMENT15 0x8CEF -#define GL_COLOR_ATTACHMENT16 0x8CF0 -#define GL_COLOR_ATTACHMENT17 0x8CF1 -#define GL_COLOR_ATTACHMENT18 0x8CF2 -#define GL_COLOR_ATTACHMENT19 0x8CF3 -#define GL_COLOR_ATTACHMENT20 0x8CF4 -#define GL_COLOR_ATTACHMENT21 0x8CF5 -#define GL_COLOR_ATTACHMENT22 0x8CF6 -#define GL_COLOR_ATTACHMENT23 0x8CF7 -#define GL_COLOR_ATTACHMENT24 0x8CF8 -#define GL_COLOR_ATTACHMENT25 0x8CF9 -#define GL_COLOR_ATTACHMENT26 0x8CFA -#define GL_COLOR_ATTACHMENT27 0x8CFB -#define GL_COLOR_ATTACHMENT28 0x8CFC -#define GL_COLOR_ATTACHMENT29 0x8CFD -#define GL_COLOR_ATTACHMENT30 0x8CFE -#define GL_COLOR_ATTACHMENT31 0x8CFF -#define GL_DEPTH_ATTACHMENT 0x8D00 -#define GL_STENCIL_ATTACHMENT 0x8D20 -#define GL_FRAMEBUFFER 0x8D40 -#define GL_RENDERBUFFER 0x8D41 -#define GL_RENDERBUFFER_WIDTH 0x8D42 -#define GL_RENDERBUFFER_HEIGHT 0x8D43 -#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 -#define GL_STENCIL_INDEX1 0x8D46 -#define GL_STENCIL_INDEX4 0x8D47 -#define GL_STENCIL_INDEX8 0x8D48 -#define GL_STENCIL_INDEX16 0x8D49 -#define GL_RENDERBUFFER_RED_SIZE 0x8D50 -#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 -#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 -#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 -#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 -#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_COLOR_ATTACHMENT16 0x8CF0 +#define GL_COLOR_ATTACHMENT17 0x8CF1 +#define GL_COLOR_ATTACHMENT18 0x8CF2 +#define GL_COLOR_ATTACHMENT19 0x8CF3 +#define GL_COLOR_ATTACHMENT20 0x8CF4 +#define GL_COLOR_ATTACHMENT21 0x8CF5 +#define GL_COLOR_ATTACHMENT22 0x8CF6 +#define GL_COLOR_ATTACHMENT23 0x8CF7 +#define GL_COLOR_ATTACHMENT24 0x8CF8 +#define GL_COLOR_ATTACHMENT25 0x8CF9 +#define GL_COLOR_ATTACHMENT26 0x8CFA +#define GL_COLOR_ATTACHMENT27 0x8CFB +#define GL_COLOR_ATTACHMENT28 0x8CFC +#define GL_COLOR_ATTACHMENT29 0x8CFD +#define GL_COLOR_ATTACHMENT30 0x8CFE +#define GL_COLOR_ATTACHMENT31 0x8CFF +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 -#define GL_MAX_SAMPLES 0x8D57 -#define GL_INDEX 0x8222 -#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 -#define GL_TEXTURE_INTENSITY_TYPE 0x8C15 -#define GL_FRAMEBUFFER_SRGB 0x8DB9 -#define GL_HALF_FLOAT 0x140B -#define GL_MAP_READ_BIT 0x0001 -#define GL_MAP_WRITE_BIT 0x0002 -#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 -#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 -#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 -#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 -#define GL_COMPRESSED_RED_RGTC1 0x8DBB -#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC -#define GL_COMPRESSED_RG_RGTC2 0x8DBD -#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE -#define GL_RG 0x8227 -#define GL_RG_INTEGER 0x8228 -#define GL_R8 0x8229 -#define GL_R16 0x822A -#define GL_RG8 0x822B -#define GL_RG16 0x822C -#define GL_R16F 0x822D -#define GL_R32F 0x822E -#define GL_RG16F 0x822F -#define GL_RG32F 0x8230 -#define GL_R8I 0x8231 -#define GL_R8UI 0x8232 -#define GL_R16I 0x8233 -#define GL_R16UI 0x8234 -#define GL_R32I 0x8235 -#define GL_R32UI 0x8236 -#define GL_RG8I 0x8237 -#define GL_RG8UI 0x8238 -#define GL_RG16I 0x8239 -#define GL_RG16UI 0x823A -#define GL_RG32I 0x823B -#define GL_RG32UI 0x823C -#define GL_VERTEX_ARRAY_BINDING 0x85B5 -#define GL_CLAMP_VERTEX_COLOR 0x891A -#define GL_CLAMP_FRAGMENT_COLOR 0x891B -#define GL_ALPHA_INTEGER 0x8D97 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_INDEX 0x8222 +#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 +#define GL_TEXTURE_INTENSITY_TYPE 0x8C15 +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_HALF_FLOAT 0x140B +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#define GL_CLAMP_VERTEX_COLOR 0x891A +#define GL_CLAMP_FRAGMENT_COLOR 0x891B +#define GL_ALPHA_INTEGER 0x8D97 -typedef void (APIENTRYP PFNDOLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); -typedef void (APIENTRYP PFNDOLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data); -typedef void (APIENTRYP PFNDOLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); -typedef void (APIENTRYP PFNDOLENABLEIPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNDOLDISABLEIPROC) (GLenum target, GLuint index); -typedef GLboolean (APIENTRYP PFNDOLISENABLEDIPROC) (GLenum target, GLuint index); -typedef void (APIENTRYP PFNDOLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); -typedef void (APIENTRYP PFNDOLENDTRANSFORMFEEDBACKPROC) (void); -typedef void (APIENTRYP PFNDOLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNDOLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); -typedef void (APIENTRYP PFNDOLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); -typedef void (APIENTRYP PFNDOLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); -typedef void (APIENTRYP PFNDOLCLAMPCOLORPROC) (GLenum target, GLenum clamp); -typedef void (APIENTRYP PFNDOLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode); -typedef void (APIENTRYP PFNDOLENDCONDITIONALRENDERPROC) (void); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); -typedef void (APIENTRYP PFNDOLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI1IPROC) (GLuint index, GLint x); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNDOLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); -typedef void (APIENTRYP PFNDOLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name); -typedef GLint (APIENTRYP PFNDOLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); -typedef void (APIENTRYP PFNDOLUNIFORM1UIPROC) (GLint location, GLuint v0); -typedef void (APIENTRYP PFNDOLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); -typedef void (APIENTRYP PFNDOLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); -typedef void (APIENTRYP PFNDOLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); -typedef void (APIENTRYP PFNDOLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNDOLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNDOLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNDOLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); -typedef void (APIENTRYP PFNDOLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNDOLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNDOLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNDOLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); -typedef void (APIENTRYP PFNDOLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); -typedef void (APIENTRYP PFNDOLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); -typedef void (APIENTRYP PFNDOLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); -typedef const GLubyte *(APIENTRYP PFNDOLGETSTRINGIPROC) (GLenum name, GLuint index); -typedef GLboolean (APIENTRYP PFNDOLISRENDERBUFFERPROC) (GLuint renderbuffer); -typedef void (APIENTRYP PFNDOLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); -typedef void (APIENTRYP PFNDOLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); -typedef void (APIENTRYP PFNDOLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); -typedef void (APIENTRYP PFNDOLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNDOLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef GLboolean (APIENTRYP PFNDOLISFRAMEBUFFERPROC) (GLuint framebuffer); -typedef void (APIENTRYP PFNDOLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); -typedef void (APIENTRYP PFNDOLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); -typedef void (APIENTRYP PFNDOLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); -typedef GLenum (APIENTRYP PFNDOLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); -typedef void (APIENTRYP PFNDOLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNDOLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -typedef void (APIENTRYP PFNDOLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); -typedef void (APIENTRYP PFNDOLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNDOLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGENERATEMIPMAPPROC) (GLenum target); -typedef void (APIENTRYP PFNDOLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -typedef void (APIENTRYP PFNDOLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNDOLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void *(APIENTRYP PFNDOLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); -typedef void (APIENTRYP PFNDOLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); -typedef void (APIENTRYP PFNDOLBINDVERTEXARRAYPROC) (GLuint array); -typedef void (APIENTRYP PFNDOLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); -typedef void (APIENTRYP PFNDOLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); -typedef GLboolean (APIENTRYP PFNDOLISVERTEXARRAYPROC) (GLuint array); +typedef void(APIENTRYP PFNDOLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, + GLboolean a); +typedef void(APIENTRYP PFNDOLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean* data); +typedef void(APIENTRYP PFNDOLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint* data); +typedef void(APIENTRYP PFNDOLENABLEIPROC)(GLenum target, GLuint index); +typedef void(APIENTRYP PFNDOLDISABLEIPROC)(GLenum target, GLuint index); +typedef GLboolean(APIENTRYP PFNDOLISENABLEDIPROC)(GLenum target, GLuint index); +typedef void(APIENTRYP PFNDOLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); +typedef void(APIENTRYP PFNDOLENDTRANSFORMFEEDBACKPROC)(void); +typedef void(APIENTRYP PFNDOLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, + GLintptr offset, GLsizeiptr size); +typedef void(APIENTRYP PFNDOLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); +typedef void(APIENTRYP PFNDOLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, + const GLchar* const* varyings, + GLenum bufferMode); +typedef void(APIENTRYP PFNDOLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, + GLsizei bufSize, GLsizei* length, + GLsizei* size, GLenum* type, + GLchar* name); +typedef void(APIENTRYP PFNDOLCLAMPCOLORPROC)(GLenum target, GLenum clamp); +typedef void(APIENTRYP PFNDOLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); +typedef void(APIENTRYP PFNDOLENDCONDITIONALRENDERPROC)(void); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, + GLsizei stride, const void* pointer); +typedef void(APIENTRYP PFNDOLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint* params); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, + GLuint w); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte* v); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort* v); +typedef void(APIENTRYP PFNDOLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint* params); +typedef void(APIENTRYP PFNDOLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, + const GLchar* name); +typedef GLint(APIENTRYP PFNDOLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar* name); +typedef void(APIENTRYP PFNDOLUNIFORM1UIPROC)(GLint location, GLuint v0); +typedef void(APIENTRYP PFNDOLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); +typedef void(APIENTRYP PFNDOLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void(APIENTRYP PFNDOLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, + GLuint v3); +typedef void(APIENTRYP PFNDOLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNDOLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNDOLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNDOLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint* value); +typedef void(APIENTRYP PFNDOLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint* params); +typedef void(APIENTRYP PFNDOLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, + const GLuint* params); +typedef void(APIENTRYP PFNDOLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint* params); +typedef void(APIENTRYP PFNDOLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, + const GLint* value); +typedef void(APIENTRYP PFNDOLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, + const GLuint* value); +typedef void(APIENTRYP PFNDOLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, + const GLfloat* value); +typedef void(APIENTRYP PFNDOLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, + GLint stencil); +typedef const GLubyte*(APIENTRYP PFNDOLGETSTRINGIPROC)(GLenum name, GLuint index); +typedef GLboolean(APIENTRYP PFNDOLISRENDERBUFFERPROC)(GLuint renderbuffer); +typedef void(APIENTRYP PFNDOLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +typedef void(APIENTRYP PFNDOLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint* renderbuffers); +typedef void(APIENTRYP PFNDOLGENRENDERBUFFERSPROC)(GLsizei n, GLuint* renderbuffers); +typedef void(APIENTRYP PFNDOLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, + GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNDOLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, + GLint* params); +typedef GLboolean(APIENTRYP PFNDOLISFRAMEBUFFERPROC)(GLuint framebuffer); +typedef void(APIENTRYP PFNDOLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +typedef void(APIENTRYP PFNDOLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint* framebuffers); +typedef void(APIENTRYP PFNDOLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint* framebuffers); +typedef GLenum(APIENTRYP PFNDOLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +typedef void(APIENTRYP PFNDOLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level); +typedef void(APIENTRYP PFNDOLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level); +typedef void(APIENTRYP PFNDOLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level, GLint zoffset); +typedef void(APIENTRYP PFNDOLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer); +typedef void(APIENTRYP PFNDOLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, + GLenum attachment, + GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLGENERATEMIPMAPPROC)(GLenum target); +typedef void(APIENTRYP PFNDOLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, + GLint srcY1, GLint dstX0, GLint dstY0, + GLint dstX1, GLint dstY1, GLbitfield mask, + GLenum filter); +typedef void(APIENTRYP PFNDOLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, + GLenum internalformat, + GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNDOLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer); +typedef void*(APIENTRYP PFNDOLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, + GLbitfield access); +typedef void(APIENTRYP PFNDOLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, + GLsizeiptr length); +typedef void(APIENTRYP PFNDOLBINDVERTEXARRAYPROC)(GLuint array); +typedef void(APIENTRYP PFNDOLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint* arrays); +typedef void(APIENTRYP PFNDOLGENVERTEXARRAYSPROC)(GLsizei n, GLuint* arrays); +typedef GLboolean(APIENTRYP PFNDOLISVERTEXARRAYPROC)(GLuint array); extern PFNDOLBEGINCONDITIONALRENDERPROC dolBeginConditionalRender; extern PFNDOLBEGINTRANSFORMFEEDBACKPROC dolBeginTransformFeedback; diff --git a/Source/Core/Common/GL/GLExtensions/gl_3_1.h b/Source/Core/Common/GL/GLExtensions/gl_3_1.h index 3f7fa5f73c..79c775f5b8 100644 --- a/Source/Core/Common/GL/GLExtensions/gl_3_1.h +++ b/Source/Core/Common/GL/GLExtensions/gl_3_1.h @@ -23,80 +23,96 @@ #include "Common/GL/GLExtensions/gl_common.h" -#define GL_SAMPLER_2D_RECT 0x8B63 -#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 -#define GL_SAMPLER_BUFFER 0x8DC2 -#define GL_INT_SAMPLER_2D_RECT 0x8DCD -#define GL_INT_SAMPLER_BUFFER 0x8DD0 -#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 -#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 -#define GL_TEXTURE_BUFFER 0x8C2A -#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B -#define GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define GL_SAMPLER_BUFFER 0x8DC2 +#define GL_INT_SAMPLER_2D_RECT 0x8DCD +#define GL_INT_SAMPLER_BUFFER 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define GL_TEXTURE_BUFFER 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D -#define GL_TEXTURE_RECTANGLE 0x84F5 -#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 -#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 -#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 -#define GL_R8_SNORM 0x8F94 -#define GL_RG8_SNORM 0x8F95 -#define GL_RGB8_SNORM 0x8F96 -#define GL_RGBA8_SNORM 0x8F97 -#define GL_R16_SNORM 0x8F98 -#define GL_RG16_SNORM 0x8F99 -#define GL_RGB16_SNORM 0x8F9A -#define GL_RGBA16_SNORM 0x8F9B -#define GL_SIGNED_NORMALIZED 0x8F9C -#define GL_PRIMITIVE_RESTART 0x8F9D -#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E -#define GL_COPY_READ_BUFFER 0x8F36 -#define GL_COPY_WRITE_BUFFER 0x8F37 -#define GL_UNIFORM_BUFFER 0x8A11 -#define GL_UNIFORM_BUFFER_BINDING 0x8A28 -#define GL_UNIFORM_BUFFER_START 0x8A29 -#define GL_UNIFORM_BUFFER_SIZE 0x8A2A -#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B -#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C -#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D -#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E -#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F -#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_TEXTURE_RECTANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define GL_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_R16_SNORM 0x8F98 +#define GL_RG16_SNORM 0x8F99 +#define GL_RGB16_SNORM 0x8F9A +#define GL_RGBA16_SNORM 0x8F9B +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_PRIMITIVE_RESTART 0x8F9D +#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 #define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 #define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 #define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 #define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 #define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 -#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 -#define GL_UNIFORM_TYPE 0x8A37 -#define GL_UNIFORM_SIZE 0x8A38 -#define GL_UNIFORM_NAME_LENGTH 0x8A39 -#define GL_UNIFORM_BLOCK_INDEX 0x8A3A -#define GL_UNIFORM_OFFSET 0x8A3B -#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C -#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D -#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E -#define GL_UNIFORM_BLOCK_BINDING 0x8A3F -#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 -#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 -#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 #define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 #define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 #define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 -#define GL_INVALID_INDEX 0xFFFFFFFFu +#define GL_INVALID_INDEX 0xFFFFFFFFu -typedef void (APIENTRYP PFNDOLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); -typedef void (APIENTRYP PFNDOLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); -typedef void (APIENTRYP PFNDOLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer); -typedef void (APIENTRYP PFNDOLPRIMITIVERESTARTINDEXPROC) (GLuint index); -typedef void (APIENTRYP PFNDOLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -typedef void (APIENTRYP PFNDOLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); -typedef void (APIENTRYP PFNDOLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); -typedef GLuint (APIENTRYP PFNDOLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); -typedef void (APIENTRYP PFNDOLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); -typedef void (APIENTRYP PFNDOLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +typedef void(APIENTRYP PFNDOLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, + GLsizei instancecount); +typedef void(APIENTRYP PFNDOLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, + const void* indices, GLsizei instancecount); +typedef void(APIENTRYP PFNDOLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer); +typedef void(APIENTRYP PFNDOLPRIMITIVERESTARTINDEXPROC)(GLuint index); +typedef void(APIENTRYP PFNDOLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, + GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size); +typedef void(APIENTRYP PFNDOLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, + const GLchar* const* uniformNames, + GLuint* uniformIndices); +typedef void(APIENTRYP PFNDOLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, + const GLuint* uniformIndices, GLenum pname, + GLint* params); +typedef void(APIENTRYP PFNDOLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, + GLsizei bufSize, GLsizei* length, + GLchar* uniformName); +typedef GLuint(APIENTRYP PFNDOLGETUNIFORMBLOCKINDEXPROC)(GLuint program, + const GLchar* uniformBlockName); +typedef void(APIENTRYP PFNDOLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, + GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, + GLuint uniformBlockIndex, + GLsizei bufSize, GLsizei* length, + GLchar* uniformBlockName); +typedef void(APIENTRYP PFNDOLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, + GLuint uniformBlockBinding); extern PFNDOLDRAWARRAYSINSTANCEDPROC dolDrawArraysInstanced; extern PFNDOLDRAWELEMENTSINSTANCEDPROC dolDrawElementsInstanced; diff --git a/Source/Core/Common/GL/GLExtensions/gl_3_2.h b/Source/Core/Common/GL/GLExtensions/gl_3_2.h index 1731c2aab7..304960505b 100644 --- a/Source/Core/Common/GL/GLExtensions/gl_3_2.h +++ b/Source/Core/Common/GL/GLExtensions/gl_3_2.h @@ -23,90 +23,110 @@ #include "Common/GL/GLExtensions/gl_common.h" -#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 #define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 -#define GL_LINES_ADJACENCY 0x000A -#define GL_LINE_STRIP_ADJACENCY 0x000B -#define GL_TRIANGLES_ADJACENCY 0x000C -#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D -#define GL_PROGRAM_POINT_SIZE 0x8642 +#define GL_LINES_ADJACENCY 0x000A +#define GL_LINE_STRIP_ADJACENCY 0x000B +#define GL_TRIANGLES_ADJACENCY 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define GL_PROGRAM_POINT_SIZE 0x8642 #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 -#define GL_GEOMETRY_SHADER 0x8DD9 -#define GL_GEOMETRY_VERTICES_OUT 0x8916 -#define GL_GEOMETRY_INPUT_TYPE 0x8917 -#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define GL_GEOMETRY_SHADER 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT 0x8916 +#define GL_GEOMETRY_INPUT_TYPE 0x8917 +#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 -#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 -#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 #define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 -#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 -#define GL_CONTEXT_PROFILE_MASK 0x9126 -#define GL_DEPTH_CLAMP 0x864F +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_DEPTH_CLAMP 0x864F #define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C -#define GL_FIRST_VERTEX_CONVENTION 0x8E4D -#define GL_LAST_VERTEX_CONVENTION 0x8E4E -#define GL_PROVOKING_VERTEX 0x8E4F -#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F -#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 -#define GL_OBJECT_TYPE 0x9112 -#define GL_SYNC_CONDITION 0x9113 -#define GL_SYNC_STATUS 0x9114 -#define GL_SYNC_FLAGS 0x9115 -#define GL_SYNC_FENCE 0x9116 -#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 -#define GL_UNSIGNALED 0x9118 -#define GL_SIGNALED 0x9119 -#define GL_ALREADY_SIGNALED 0x911A -#define GL_TIMEOUT_EXPIRED 0x911B -#define GL_CONDITION_SATISFIED 0x911C -#define GL_WAIT_FAILED 0x911D -#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull -#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 -#define GL_SAMPLE_POSITION 0x8E50 -#define GL_SAMPLE_MASK 0x8E51 -#define GL_SAMPLE_MASK_VALUE 0x8E52 -#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 -#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 -#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 -#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define GL_LAST_VERTEX_CONVENTION 0x8E4E +#define GL_PROVOKING_VERTEX 0x8E4F +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 #define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 -#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_SAMPLES 0x9106 #define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 -#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 -#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A -#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B #define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D -#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E -#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F -#define GL_MAX_INTEGER_SAMPLES 0x9110 +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_INTEGER_SAMPLES 0x9110 -typedef void (APIENTRYP PFNDOLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); -typedef void (APIENTRYP PFNDOLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); -typedef void (APIENTRYP PFNDOLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); -typedef void (APIENTRYP PFNDOLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); -typedef void (APIENTRYP PFNDOLPROVOKINGVERTEXPROC) (GLenum mode); -typedef GLsync (APIENTRYP PFNDOLFENCESYNCPROC) (GLenum condition, GLbitfield flags); -typedef GLboolean (APIENTRYP PFNDOLISSYNCPROC) (GLsync sync); -typedef void (APIENTRYP PFNDOLDELETESYNCPROC) (GLsync sync); -typedef GLenum (APIENTRYP PFNDOLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); -typedef void (APIENTRYP PFNDOLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); -typedef void (APIENTRYP PFNDOLGETINTEGER64VPROC) (GLenum pname, GLint64 *data); -typedef void (APIENTRYP PFNDOLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); -typedef void (APIENTRYP PFNDOLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); -typedef void (APIENTRYP PFNDOLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); -typedef void (APIENTRYP PFNDOLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNDOLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNDOLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNDOLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); -typedef void (APIENTRYP PFNDOLSAMPLEMASKIPROC) (GLuint maskNumber, GLbitfield mask); +typedef void(APIENTRYP PFNDOLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, + const void* indices, GLint basevertex); +typedef void(APIENTRYP PFNDOLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, + GLsizei count, GLenum type, + const void* indices, + GLint basevertex); +typedef void(APIENTRYP PFNDOLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, + GLenum type, const void* indices, + GLsizei instancecount, + GLint basevertex); +typedef void(APIENTRYP PFNDOLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei* count, + GLenum type, + const void* const* indices, + GLsizei drawcount, + const GLint* basevertex); +typedef void(APIENTRYP PFNDOLPROVOKINGVERTEXPROC)(GLenum mode); +typedef GLsync(APIENTRYP PFNDOLFENCESYNCPROC)(GLenum condition, GLbitfield flags); +typedef GLboolean(APIENTRYP PFNDOLISSYNCPROC)(GLsync sync); +typedef void(APIENTRYP PFNDOLDELETESYNCPROC)(GLsync sync); +typedef GLenum(APIENTRYP PFNDOLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void(APIENTRYP PFNDOLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void(APIENTRYP PFNDOLGETINTEGER64VPROC)(GLenum pname, GLint64* data); +typedef void(APIENTRYP PFNDOLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei bufSize, + GLsizei* length, GLint* values); +typedef void(APIENTRYP PFNDOLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64* data); +typedef void(APIENTRYP PFNDOLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, + GLint64* params); +typedef void(APIENTRYP PFNDOLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, + GLuint texture, GLint level); +typedef void(APIENTRYP PFNDOLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, + GLsizei height, + GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNDOLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, + GLsizei height, GLsizei depth, + GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNDOLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat* val); +typedef void(APIENTRYP PFNDOLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); extern PFNDOLFRAMEBUFFERTEXTUREPROC dolFramebufferTexture; extern PFNDOLGETBUFFERPARAMETERI64VPROC dolGetBufferParameteri64v; diff --git a/Source/Core/Common/GL/GLExtensions/gl_4_2.h b/Source/Core/Common/GL/GLExtensions/gl_4_2.h index d5ed625161..bb9286bf32 100644 --- a/Source/Core/Common/GL/GLExtensions/gl_4_2.h +++ b/Source/Core/Common/GL/GLExtensions/gl_4_2.h @@ -23,24 +23,24 @@ #include "Common/GL/GLExtensions/gl_common.h" -#define GL_COPY_READ_BUFFER_BINDING 0x8F36 -#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 -#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 -#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 -#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 +#define GL_COPY_READ_BUFFER_BINDING 0x8F36 +#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 +#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 +#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 +#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 #define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 -#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 -#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A -#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B -#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C -#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D -#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E -#define GL_NUM_SAMPLE_COUNTS 0x9380 -#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC -#define GL_ATOMIC_COUNTER_BUFFER 0x92C0 -#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 -#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 -#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 +#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 +#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A +#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B +#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C +#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D +#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E +#define GL_NUM_SAMPLE_COUNTS 0x9380 +#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC +#define GL_ATOMIC_COUNTER_BUFFER 0x92C0 +#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 +#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 +#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 #define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 #define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 #define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 @@ -55,103 +55,123 @@ #define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF #define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 #define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 -#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 +#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 -#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 -#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 -#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 +#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 +#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 +#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 #define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 #define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC -#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 +#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 #define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA -#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB +#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB #define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 -#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 -#define GL_UNIFORM_BARRIER_BIT 0x00000004 -#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 +#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 +#define GL_UNIFORM_BARRIER_BIT 0x00000004 +#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 #define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 -#define GL_COMMAND_BARRIER_BIT 0x00000040 -#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 -#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 -#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 -#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 +#define GL_COMMAND_BARRIER_BIT 0x00000040 +#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 +#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 +#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 +#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 #define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 -#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 -#define GL_ALL_BARRIER_BITS 0xFFFFFFFF -#define GL_MAX_IMAGE_UNITS 0x8F38 +#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 +#define GL_ALL_BARRIER_BITS 0xFFFFFFFF +#define GL_MAX_IMAGE_UNITS 0x8F38 #define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 -#define GL_IMAGE_BINDING_NAME 0x8F3A -#define GL_IMAGE_BINDING_LEVEL 0x8F3B -#define GL_IMAGE_BINDING_LAYERED 0x8F3C -#define GL_IMAGE_BINDING_LAYER 0x8F3D -#define GL_IMAGE_BINDING_ACCESS 0x8F3E -#define GL_IMAGE_1D 0x904C -#define GL_IMAGE_2D 0x904D -#define GL_IMAGE_3D 0x904E -#define GL_IMAGE_2D_RECT 0x904F -#define GL_IMAGE_CUBE 0x9050 -#define GL_IMAGE_BUFFER 0x9051 -#define GL_IMAGE_1D_ARRAY 0x9052 -#define GL_IMAGE_2D_ARRAY 0x9053 -#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 -#define GL_IMAGE_2D_MULTISAMPLE 0x9055 -#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 -#define GL_INT_IMAGE_1D 0x9057 -#define GL_INT_IMAGE_2D 0x9058 -#define GL_INT_IMAGE_3D 0x9059 -#define GL_INT_IMAGE_2D_RECT 0x905A -#define GL_INT_IMAGE_CUBE 0x905B -#define GL_INT_IMAGE_BUFFER 0x905C -#define GL_INT_IMAGE_1D_ARRAY 0x905D -#define GL_INT_IMAGE_2D_ARRAY 0x905E -#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F -#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 +#define GL_IMAGE_BINDING_NAME 0x8F3A +#define GL_IMAGE_BINDING_LEVEL 0x8F3B +#define GL_IMAGE_BINDING_LAYERED 0x8F3C +#define GL_IMAGE_BINDING_LAYER 0x8F3D +#define GL_IMAGE_BINDING_ACCESS 0x8F3E +#define GL_IMAGE_1D 0x904C +#define GL_IMAGE_2D 0x904D +#define GL_IMAGE_3D 0x904E +#define GL_IMAGE_2D_RECT 0x904F +#define GL_IMAGE_CUBE 0x9050 +#define GL_IMAGE_BUFFER 0x9051 +#define GL_IMAGE_1D_ARRAY 0x9052 +#define GL_IMAGE_2D_ARRAY 0x9053 +#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 +#define GL_IMAGE_2D_MULTISAMPLE 0x9055 +#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 +#define GL_INT_IMAGE_1D 0x9057 +#define GL_INT_IMAGE_2D 0x9058 +#define GL_INT_IMAGE_3D 0x9059 +#define GL_INT_IMAGE_2D_RECT 0x905A +#define GL_INT_IMAGE_CUBE 0x905B +#define GL_INT_IMAGE_BUFFER 0x905C +#define GL_INT_IMAGE_1D_ARRAY 0x905D +#define GL_INT_IMAGE_2D_ARRAY 0x905E +#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F +#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 #define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 -#define GL_UNSIGNED_INT_IMAGE_1D 0x9062 -#define GL_UNSIGNED_INT_IMAGE_2D 0x9063 -#define GL_UNSIGNED_INT_IMAGE_3D 0x9064 -#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 -#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 -#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 -#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 -#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 +#define GL_UNSIGNED_INT_IMAGE_1D 0x9062 +#define GL_UNSIGNED_INT_IMAGE_2D 0x9063 +#define GL_UNSIGNED_INT_IMAGE_3D 0x9064 +#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 +#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 +#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 +#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 +#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 #define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C -#define GL_MAX_IMAGE_SAMPLES 0x906D -#define GL_IMAGE_BINDING_FORMAT 0x906E +#define GL_MAX_IMAGE_SAMPLES 0x906D +#define GL_IMAGE_BINDING_FORMAT 0x906E #define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 -#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA +#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA #define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB #define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC -#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD -#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE -#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF -#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C +#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD +#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE +#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF +#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C #define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D #define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E #define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F -#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F +#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F -typedef void (APIENTRYP PFNDOLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); -typedef void (APIENTRYP PFNDOLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); -typedef void (APIENTRYP PFNDOLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); -typedef void (APIENTRYP PFNDOLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); -typedef void (APIENTRYP PFNDOLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); -typedef void (APIENTRYP PFNDOLMEMORYBARRIERPROC) (GLbitfield barriers); -typedef void (APIENTRYP PFNDOLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); -typedef void (APIENTRYP PFNDOLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNDOLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -typedef void (APIENTRYP PFNDOLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount); -typedef void (APIENTRYP PFNDOLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); +typedef void(APIENTRYP PFNDOLDRAWARRAYSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLint first, + GLsizei count, + GLsizei instancecount, + GLuint baseinstance); +typedef void(APIENTRYP PFNDOLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLsizei count, + GLenum type, + const void* indices, + GLsizei instancecount, + GLuint baseinstance); +typedef void(APIENTRYP PFNDOLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC)( + GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount, + GLint basevertex, GLuint baseinstance); +typedef void(APIENTRYP PFNDOLGETINTERNALFORMATIVPROC)(GLenum target, GLenum internalformat, + GLenum pname, GLsizei bufSize, GLint* params); +typedef void(APIENTRYP PFNDOLGETACTIVEATOMICCOUNTERBUFFERIVPROC)(GLuint program, GLuint bufferIndex, + GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLBINDIMAGETEXTUREPROC)(GLuint unit, GLuint texture, GLint level, + GLboolean layered, GLint layer, GLenum access, + GLenum format); +typedef void(APIENTRYP PFNDOLMEMORYBARRIERPROC)(GLbitfield barriers); +typedef void(APIENTRYP PFNDOLTEXSTORAGE1DPROC)(GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width); +typedef void(APIENTRYP PFNDOLTEXSTORAGE2DPROC)(GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNDOLTEXSTORAGE3DPROC)(GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth); +typedef void(APIENTRYP PFNDOLDRAWTRANSFORMFEEDBACKINSTANCEDPROC)(GLenum mode, GLuint id, + GLsizei instancecount); +typedef void(APIENTRYP PFNDOLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC)(GLenum mode, GLuint id, + GLuint stream, + GLsizei instancecount); extern PFNDOLDRAWARRAYSINSTANCEDBASEINSTANCEPROC dolDrawArraysInstancedBaseInstance; extern PFNDOLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC dolDrawElementsInstancedBaseInstance; -extern PFNDOLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC dolDrawElementsInstancedBaseVertexBaseInstance; +extern PFNDOLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC + dolDrawElementsInstancedBaseVertexBaseInstance; extern PFNDOLGETINTERNALFORMATIVPROC dolGetInternalformativ; extern PFNDOLGETACTIVEATOMICCOUNTERBUFFERIVPROC dolGetActiveAtomicCounterBufferiv; extern PFNDOLBINDIMAGETEXTUREPROC dolBindImageTexture; diff --git a/Source/Core/Common/GL/GLExtensions/gl_4_3.h b/Source/Core/Common/GL/GLExtensions/gl_4_3.h index 2f38f65f32..e81b24e370 100644 --- a/Source/Core/Common/GL/GLExtensions/gl_4_3.h +++ b/Source/Core/Common/GL/GLExtensions/gl_4_3.h @@ -23,235 +23,235 @@ #include "Common/GL/GLExtensions/gl_common.h" -#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 -#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E -#define GL_COMPRESSED_RGB8_ETC2 0x9274 -#define GL_COMPRESSED_SRGB8_ETC2 0x9275 +#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 +#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E +#define GL_COMPRESSED_RGB8_ETC2 0x9274 +#define GL_COMPRESSED_SRGB8_ETC2 0x9275 #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 #define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 -#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 #define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 -#define GL_COMPRESSED_R11_EAC 0x9270 -#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 -#define GL_COMPRESSED_RG11_EAC 0x9272 -#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 -#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 +#define GL_COMPRESSED_R11_EAC 0x9270 +#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 +#define GL_COMPRESSED_RG11_EAC 0x9272 +#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 +#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 #define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A -#define GL_MAX_ELEMENT_INDEX 0x8D6B -#define GL_COMPUTE_SHADER 0x91B9 -#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB +#define GL_MAX_ELEMENT_INDEX 0x8D6B +#define GL_COMPUTE_SHADER 0x91B9 +#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB #define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC -#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD +#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD #define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 #define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 #define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 -#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 +#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 #define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 #define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB -#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE -#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF -#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267 +#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE +#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF +#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267 #define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED -#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE +#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE #define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF -#define GL_COMPUTE_SHADER_BIT 0x00000020 -#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_COMPUTE_SHADER_BIT 0x00000020 +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 -#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 -#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 -#define GL_DEBUG_SOURCE_API 0x8246 -#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 -#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 -#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 -#define GL_DEBUG_SOURCE_APPLICATION 0x824A -#define GL_DEBUG_SOURCE_OTHER 0x824B -#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_TYPE_ERROR 0x824C #define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D -#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E -#define GL_DEBUG_TYPE_PORTABILITY 0x824F -#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 -#define GL_DEBUG_TYPE_OTHER 0x8251 -#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 -#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 -#define GL_DEBUG_LOGGED_MESSAGES 0x9145 -#define GL_DEBUG_SEVERITY_HIGH 0x9146 -#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 -#define GL_DEBUG_SEVERITY_LOW 0x9148 -#define GL_DEBUG_TYPE_MARKER 0x8268 -#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 -#define GL_DEBUG_TYPE_POP_GROUP 0x826A -#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B -#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C -#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D -#define GL_BUFFER 0x82E0 -#define GL_SHADER 0x82E1 -#define GL_PROGRAM 0x82E2 -#define GL_QUERY 0x82E3 -#define GL_PROGRAM_PIPELINE 0x82E4 -#define GL_SAMPLER 0x82E6 -#define GL_MAX_LABEL_LENGTH 0x82E8 -#define GL_DEBUG_OUTPUT 0x92E0 -#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 -#define GL_MAX_UNIFORM_LOCATIONS 0x826E -#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 -#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 -#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 -#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_OTHER 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define GL_BUFFER 0x82E0 +#define GL_SHADER 0x82E1 +#define GL_PROGRAM 0x82E2 +#define GL_QUERY 0x82E3 +#define GL_PROGRAM_PIPELINE 0x82E4 +#define GL_SAMPLER 0x82E6 +#define GL_MAX_LABEL_LENGTH 0x82E8 +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_MAX_UNIFORM_LOCATIONS 0x826E +#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 +#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 +#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 +#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 #define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 -#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 -#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 -#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 -#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 -#define GL_INTERNALFORMAT_SUPPORTED 0x826F -#define GL_INTERNALFORMAT_PREFERRED 0x8270 -#define GL_INTERNALFORMAT_RED_SIZE 0x8271 -#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272 -#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273 -#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 -#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 -#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 -#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277 -#define GL_INTERNALFORMAT_RED_TYPE 0x8278 -#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279 -#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A -#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B -#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C -#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D -#define GL_MAX_WIDTH 0x827E -#define GL_MAX_HEIGHT 0x827F -#define GL_MAX_DEPTH 0x8280 -#define GL_MAX_LAYERS 0x8281 -#define GL_MAX_COMBINED_DIMENSIONS 0x8282 -#define GL_COLOR_COMPONENTS 0x8283 -#define GL_DEPTH_COMPONENTS 0x8284 -#define GL_STENCIL_COMPONENTS 0x8285 -#define GL_COLOR_RENDERABLE 0x8286 -#define GL_DEPTH_RENDERABLE 0x8287 -#define GL_STENCIL_RENDERABLE 0x8288 -#define GL_FRAMEBUFFER_RENDERABLE 0x8289 +#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 +#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 +#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 +#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 +#define GL_INTERNALFORMAT_SUPPORTED 0x826F +#define GL_INTERNALFORMAT_PREFERRED 0x8270 +#define GL_INTERNALFORMAT_RED_SIZE 0x8271 +#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272 +#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273 +#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 +#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 +#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 +#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277 +#define GL_INTERNALFORMAT_RED_TYPE 0x8278 +#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279 +#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A +#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B +#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C +#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D +#define GL_MAX_WIDTH 0x827E +#define GL_MAX_HEIGHT 0x827F +#define GL_MAX_DEPTH 0x8280 +#define GL_MAX_LAYERS 0x8281 +#define GL_MAX_COMBINED_DIMENSIONS 0x8282 +#define GL_COLOR_COMPONENTS 0x8283 +#define GL_DEPTH_COMPONENTS 0x8284 +#define GL_STENCIL_COMPONENTS 0x8285 +#define GL_COLOR_RENDERABLE 0x8286 +#define GL_DEPTH_RENDERABLE 0x8287 +#define GL_STENCIL_RENDERABLE 0x8288 +#define GL_FRAMEBUFFER_RENDERABLE 0x8289 #define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A -#define GL_FRAMEBUFFER_BLEND 0x828B -#define GL_READ_PIXELS 0x828C -#define GL_READ_PIXELS_FORMAT 0x828D -#define GL_READ_PIXELS_TYPE 0x828E -#define GL_TEXTURE_IMAGE_FORMAT 0x828F -#define GL_TEXTURE_IMAGE_TYPE 0x8290 -#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 -#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292 -#define GL_MIPMAP 0x8293 -#define GL_MANUAL_GENERATE_MIPMAP 0x8294 -#define GL_AUTO_GENERATE_MIPMAP 0x8295 -#define GL_COLOR_ENCODING 0x8296 -#define GL_SRGB_READ 0x8297 -#define GL_SRGB_WRITE 0x8298 -#define GL_FILTER 0x829A -#define GL_VERTEX_TEXTURE 0x829B -#define GL_TESS_CONTROL_TEXTURE 0x829C -#define GL_TESS_EVALUATION_TEXTURE 0x829D -#define GL_GEOMETRY_TEXTURE 0x829E -#define GL_FRAGMENT_TEXTURE 0x829F -#define GL_COMPUTE_TEXTURE 0x82A0 -#define GL_TEXTURE_SHADOW 0x82A1 -#define GL_TEXTURE_GATHER 0x82A2 -#define GL_TEXTURE_GATHER_SHADOW 0x82A3 -#define GL_SHADER_IMAGE_LOAD 0x82A4 -#define GL_SHADER_IMAGE_STORE 0x82A5 -#define GL_SHADER_IMAGE_ATOMIC 0x82A6 -#define GL_IMAGE_TEXEL_SIZE 0x82A7 -#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 -#define GL_IMAGE_PIXEL_FORMAT 0x82A9 -#define GL_IMAGE_PIXEL_TYPE 0x82AA +#define GL_FRAMEBUFFER_BLEND 0x828B +#define GL_READ_PIXELS 0x828C +#define GL_READ_PIXELS_FORMAT 0x828D +#define GL_READ_PIXELS_TYPE 0x828E +#define GL_TEXTURE_IMAGE_FORMAT 0x828F +#define GL_TEXTURE_IMAGE_TYPE 0x8290 +#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 +#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292 +#define GL_MIPMAP 0x8293 +#define GL_MANUAL_GENERATE_MIPMAP 0x8294 +#define GL_AUTO_GENERATE_MIPMAP 0x8295 +#define GL_COLOR_ENCODING 0x8296 +#define GL_SRGB_READ 0x8297 +#define GL_SRGB_WRITE 0x8298 +#define GL_FILTER 0x829A +#define GL_VERTEX_TEXTURE 0x829B +#define GL_TESS_CONTROL_TEXTURE 0x829C +#define GL_TESS_EVALUATION_TEXTURE 0x829D +#define GL_GEOMETRY_TEXTURE 0x829E +#define GL_FRAGMENT_TEXTURE 0x829F +#define GL_COMPUTE_TEXTURE 0x82A0 +#define GL_TEXTURE_SHADOW 0x82A1 +#define GL_TEXTURE_GATHER 0x82A2 +#define GL_TEXTURE_GATHER_SHADOW 0x82A3 +#define GL_SHADER_IMAGE_LOAD 0x82A4 +#define GL_SHADER_IMAGE_STORE 0x82A5 +#define GL_SHADER_IMAGE_ATOMIC 0x82A6 +#define GL_IMAGE_TEXEL_SIZE 0x82A7 +#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 +#define GL_IMAGE_PIXEL_FORMAT 0x82A9 +#define GL_IMAGE_PIXEL_TYPE 0x82AA #define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC #define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD #define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE #define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF #define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1 #define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2 -#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 -#define GL_CLEAR_BUFFER 0x82B4 -#define GL_TEXTURE_VIEW 0x82B5 -#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6 -#define GL_FULL_SUPPORT 0x82B7 -#define GL_CAVEAT_SUPPORT 0x82B8 -#define GL_IMAGE_CLASS_4_X_32 0x82B9 -#define GL_IMAGE_CLASS_2_X_32 0x82BA -#define GL_IMAGE_CLASS_1_X_32 0x82BB -#define GL_IMAGE_CLASS_4_X_16 0x82BC -#define GL_IMAGE_CLASS_2_X_16 0x82BD -#define GL_IMAGE_CLASS_1_X_16 0x82BE -#define GL_IMAGE_CLASS_4_X_8 0x82BF -#define GL_IMAGE_CLASS_2_X_8 0x82C0 -#define GL_IMAGE_CLASS_1_X_8 0x82C1 -#define GL_IMAGE_CLASS_11_11_10 0x82C2 -#define GL_IMAGE_CLASS_10_10_10_2 0x82C3 -#define GL_VIEW_CLASS_128_BITS 0x82C4 -#define GL_VIEW_CLASS_96_BITS 0x82C5 -#define GL_VIEW_CLASS_64_BITS 0x82C6 -#define GL_VIEW_CLASS_48_BITS 0x82C7 -#define GL_VIEW_CLASS_32_BITS 0x82C8 -#define GL_VIEW_CLASS_24_BITS 0x82C9 -#define GL_VIEW_CLASS_16_BITS 0x82CA -#define GL_VIEW_CLASS_8_BITS 0x82CB -#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC -#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD -#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE -#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF -#define GL_VIEW_CLASS_RGTC1_RED 0x82D0 -#define GL_VIEW_CLASS_RGTC2_RG 0x82D1 -#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 -#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 -#define GL_UNIFORM 0x92E1 -#define GL_UNIFORM_BLOCK 0x92E2 -#define GL_PROGRAM_INPUT 0x92E3 -#define GL_PROGRAM_OUTPUT 0x92E4 -#define GL_BUFFER_VARIABLE 0x92E5 -#define GL_SHADER_STORAGE_BLOCK 0x92E6 -#define GL_VERTEX_SUBROUTINE 0x92E8 -#define GL_TESS_CONTROL_SUBROUTINE 0x92E9 -#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA -#define GL_GEOMETRY_SUBROUTINE 0x92EB -#define GL_FRAGMENT_SUBROUTINE 0x92EC -#define GL_COMPUTE_SUBROUTINE 0x92ED -#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE +#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 +#define GL_CLEAR_BUFFER 0x82B4 +#define GL_TEXTURE_VIEW 0x82B5 +#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6 +#define GL_FULL_SUPPORT 0x82B7 +#define GL_CAVEAT_SUPPORT 0x82B8 +#define GL_IMAGE_CLASS_4_X_32 0x82B9 +#define GL_IMAGE_CLASS_2_X_32 0x82BA +#define GL_IMAGE_CLASS_1_X_32 0x82BB +#define GL_IMAGE_CLASS_4_X_16 0x82BC +#define GL_IMAGE_CLASS_2_X_16 0x82BD +#define GL_IMAGE_CLASS_1_X_16 0x82BE +#define GL_IMAGE_CLASS_4_X_8 0x82BF +#define GL_IMAGE_CLASS_2_X_8 0x82C0 +#define GL_IMAGE_CLASS_1_X_8 0x82C1 +#define GL_IMAGE_CLASS_11_11_10 0x82C2 +#define GL_IMAGE_CLASS_10_10_10_2 0x82C3 +#define GL_VIEW_CLASS_128_BITS 0x82C4 +#define GL_VIEW_CLASS_96_BITS 0x82C5 +#define GL_VIEW_CLASS_64_BITS 0x82C6 +#define GL_VIEW_CLASS_48_BITS 0x82C7 +#define GL_VIEW_CLASS_32_BITS 0x82C8 +#define GL_VIEW_CLASS_24_BITS 0x82C9 +#define GL_VIEW_CLASS_16_BITS 0x82CA +#define GL_VIEW_CLASS_8_BITS 0x82CB +#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC +#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD +#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE +#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF +#define GL_VIEW_CLASS_RGTC1_RED 0x82D0 +#define GL_VIEW_CLASS_RGTC2_RG 0x82D1 +#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 +#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 +#define GL_UNIFORM 0x92E1 +#define GL_UNIFORM_BLOCK 0x92E2 +#define GL_PROGRAM_INPUT 0x92E3 +#define GL_PROGRAM_OUTPUT 0x92E4 +#define GL_BUFFER_VARIABLE 0x92E5 +#define GL_SHADER_STORAGE_BLOCK 0x92E6 +#define GL_VERTEX_SUBROUTINE 0x92E8 +#define GL_TESS_CONTROL_SUBROUTINE 0x92E9 +#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA +#define GL_GEOMETRY_SUBROUTINE 0x92EB +#define GL_FRAGMENT_SUBROUTINE 0x92EC +#define GL_COMPUTE_SUBROUTINE 0x92ED +#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE #define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF #define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0 -#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 -#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 -#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 -#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 -#define GL_ACTIVE_RESOURCES 0x92F5 -#define GL_MAX_NAME_LENGTH 0x92F6 -#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 +#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 +#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 +#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 +#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 +#define GL_ACTIVE_RESOURCES 0x92F5 +#define GL_MAX_NAME_LENGTH 0x92F6 +#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 #define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8 -#define GL_NAME_LENGTH 0x92F9 -#define GL_TYPE 0x92FA -#define GL_ARRAY_SIZE 0x92FB -#define GL_OFFSET 0x92FC -#define GL_BLOCK_INDEX 0x92FD -#define GL_ARRAY_STRIDE 0x92FE -#define GL_MATRIX_STRIDE 0x92FF -#define GL_IS_ROW_MAJOR 0x9300 -#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 -#define GL_BUFFER_BINDING 0x9302 -#define GL_BUFFER_DATA_SIZE 0x9303 -#define GL_NUM_ACTIVE_VARIABLES 0x9304 -#define GL_ACTIVE_VARIABLES 0x9305 -#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 +#define GL_NAME_LENGTH 0x92F9 +#define GL_TYPE 0x92FA +#define GL_ARRAY_SIZE 0x92FB +#define GL_OFFSET 0x92FC +#define GL_BLOCK_INDEX 0x92FD +#define GL_ARRAY_STRIDE 0x92FE +#define GL_MATRIX_STRIDE 0x92FF +#define GL_IS_ROW_MAJOR 0x9300 +#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 +#define GL_BUFFER_BINDING 0x9302 +#define GL_BUFFER_DATA_SIZE 0x9303 +#define GL_NUM_ACTIVE_VARIABLES 0x9304 +#define GL_ACTIVE_VARIABLES 0x9305 +#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 #define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307 #define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308 -#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 -#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A -#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B -#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C -#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D -#define GL_LOCATION 0x930E -#define GL_LOCATION_INDEX 0x930F -#define GL_IS_PER_PATCH 0x92E7 -#define GL_SHADER_STORAGE_BUFFER 0x90D2 -#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 -#define GL_SHADER_STORAGE_BUFFER_START 0x90D4 -#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 +#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 +#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A +#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B +#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C +#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D +#define GL_LOCATION 0x930E +#define GL_LOCATION_INDEX 0x930F +#define GL_IS_PER_PATCH 0x92E7 +#define GL_SHADER_STORAGE_BUFFER 0x90D2 +#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 +#define GL_SHADER_STORAGE_BUFFER_START 0x90D4 +#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 #define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 #define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 #define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 @@ -260,57 +260,91 @@ #define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB #define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC #define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD -#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE +#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE #define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF #define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 -#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA -#define GL_TEXTURE_BUFFER_OFFSET 0x919D -#define GL_TEXTURE_BUFFER_SIZE 0x919E +#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA +#define GL_TEXTURE_BUFFER_OFFSET 0x919D +#define GL_TEXTURE_BUFFER_SIZE 0x919E #define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F -#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB -#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC -#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD -#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE -#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF -#define GL_VERTEX_ATTRIB_BINDING 0x82D4 -#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 -#define GL_VERTEX_BINDING_DIVISOR 0x82D6 -#define GL_VERTEX_BINDING_OFFSET 0x82D7 -#define GL_VERTEX_BINDING_STRIDE 0x82D8 +#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB +#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC +#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD +#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE +#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF +#define GL_VERTEX_ATTRIB_BINDING 0x82D4 +#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 +#define GL_VERTEX_BINDING_DIVISOR 0x82D6 +#define GL_VERTEX_BINDING_OFFSET 0x82D7 +#define GL_VERTEX_BINDING_STRIDE 0x82D8 #define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 -#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA -#define GL_VERTEX_BINDING_BUFFER 0x8F4F -#define GL_DISPLAY_LIST 0x82E7 +#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA +#define GL_VERTEX_BINDING_BUFFER 0x8F4F +#define GL_DISPLAY_LIST 0x82E7 -typedef void (APIENTRYP PFNDOLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNDOLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNDOLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); -typedef void (APIENTRYP PFNDOLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect); -typedef void (APIENTRYP PFNDOLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRYP PFNDOLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); -typedef void (APIENTRYP PFNDOLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); -typedef void (APIENTRYP PFNDOLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level); -typedef void (APIENTRYP PFNDOLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); -typedef void (APIENTRYP PFNDOLINVALIDATEBUFFERDATAPROC) (GLuint buffer); -typedef void (APIENTRYP PFNDOLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); -typedef void (APIENTRYP PFNDOLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNDOLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); -typedef void (APIENTRYP PFNDOLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); -typedef void (APIENTRYP PFNDOLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params); -typedef GLuint (APIENTRYP PFNDOLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); -typedef void (APIENTRYP PFNDOLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); -typedef void (APIENTRYP PFNDOLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); -typedef GLint (APIENTRYP PFNDOLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name); -typedef GLint (APIENTRYP PFNDOLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); -typedef void (APIENTRYP PFNDOLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNDOLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); -typedef void (APIENTRYP PFNDOLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (APIENTRYP PFNDOLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex); -typedef void (APIENTRYP PFNDOLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor); +typedef void(APIENTRYP PFNDOLCLEARBUFFERDATAPROC)(GLenum target, GLenum internalformat, + GLenum format, GLenum type, const void* data); +typedef void(APIENTRYP PFNDOLCLEARBUFFERSUBDATAPROC)(GLenum target, GLenum internalformat, + GLintptr offset, GLsizeiptr size, + GLenum format, GLenum type, const void* data); +typedef void(APIENTRYP PFNDOLDISPATCHCOMPUTEPROC)(GLuint num_groups_x, GLuint num_groups_y, + GLuint num_groups_z); +typedef void(APIENTRYP PFNDOLDISPATCHCOMPUTEINDIRECTPROC)(GLintptr indirect); +typedef void(APIENTRYP PFNDOLFRAMEBUFFERPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +typedef void(APIENTRYP PFNDOLGETFRAMEBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, + GLint* params); +typedef void(APIENTRYP PFNDOLGETINTERNALFORMATI64VPROC)(GLenum target, GLenum internalformat, + GLenum pname, GLsizei bufSize, + GLint64* params); +typedef void(APIENTRYP PFNDOLINVALIDATETEXSUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, + GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth); +typedef void(APIENTRYP PFNDOLINVALIDATETEXIMAGEPROC)(GLuint texture, GLint level); +typedef void(APIENTRYP PFNDOLINVALIDATEBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, + GLsizeiptr length); +typedef void(APIENTRYP PFNDOLINVALIDATEBUFFERDATAPROC)(GLuint buffer); +typedef void(APIENTRYP PFNDOLINVALIDATEFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, + const GLenum* attachments); +typedef void(APIENTRYP PFNDOLINVALIDATESUBFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, + const GLenum* attachments, GLint x, + GLint y, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNDOLMULTIDRAWARRAYSINDIRECTPROC)(GLenum mode, const void* indirect, + GLsizei drawcount, GLsizei stride); +typedef void(APIENTRYP PFNDOLMULTIDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, + const void* indirect, GLsizei drawcount, + GLsizei stride); +typedef void(APIENTRYP PFNDOLGETPROGRAMINTERFACEIVPROC)(GLuint program, GLenum programInterface, + GLenum pname, GLint* params); +typedef GLuint(APIENTRYP PFNDOLGETPROGRAMRESOURCEINDEXPROC)(GLuint program, GLenum programInterface, + const GLchar* name); +typedef void(APIENTRYP PFNDOLGETPROGRAMRESOURCENAMEPROC)(GLuint program, GLenum programInterface, + GLuint index, GLsizei bufSize, + GLsizei* length, GLchar* name); +typedef void(APIENTRYP PFNDOLGETPROGRAMRESOURCEIVPROC)(GLuint program, GLenum programInterface, + GLuint index, GLsizei propCount, + const GLenum* props, GLsizei bufSize, + GLsizei* length, GLint* params); +typedef GLint(APIENTRYP PFNDOLGETPROGRAMRESOURCELOCATIONPROC)(GLuint program, + GLenum programInterface, + const GLchar* name); +typedef GLint(APIENTRYP PFNDOLGETPROGRAMRESOURCELOCATIONINDEXPROC)(GLuint program, + GLenum programInterface, + const GLchar* name); +typedef void(APIENTRYP PFNDOLTEXBUFFERRANGEPROC)(GLenum target, GLenum internalformat, + GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void(APIENTRYP PFNDOLTEXTUREVIEWPROC)(GLuint texture, GLenum target, GLuint origtexture, + GLenum internalformat, GLuint minlevel, + GLuint numlevels, GLuint minlayer, GLuint numlayers); +typedef void(APIENTRYP PFNDOLBINDVERTEXBUFFERPROC)(GLuint bindingindex, GLuint buffer, + GLintptr offset, GLsizei stride); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBFORMATPROC)(GLuint attribindex, GLint size, GLenum type, + GLboolean normalized, GLuint relativeoffset); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBIFORMATPROC)(GLuint attribindex, GLint size, GLenum type, + GLuint relativeoffset); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBLFORMATPROC)(GLuint attribindex, GLint size, GLenum type, + GLuint relativeoffset); +typedef void(APIENTRYP PFNDOLVERTEXATTRIBBINDINGPROC)(GLuint attribindex, GLuint bindingindex); +typedef void(APIENTRYP PFNDOLVERTEXBINDINGDIVISORPROC)(GLuint bindingindex, GLuint divisor); extern PFNDOLCLEARBUFFERDATAPROC dolClearBufferData; extern PFNDOLCLEARBUFFERSUBDATAPROC dolClearBufferSubData; diff --git a/Source/Core/Common/GL/GLExtensions/gl_4_4.h b/Source/Core/Common/GL/GLExtensions/gl_4_4.h index 4f30731543..1ec2305531 100644 --- a/Source/Core/Common/GL/GLExtensions/gl_4_4.h +++ b/Source/Core/Common/GL/GLExtensions/gl_4_4.h @@ -23,33 +23,44 @@ #include "Common/GL/GLExtensions/gl_common.h" -#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 +#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 #define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221 -#define GL_TEXTURE_BUFFER_BINDING 0x8C2A -#define GL_DYNAMIC_STORAGE_BIT 0x0100 -#define GL_CLIENT_STORAGE_BIT 0x0200 +#define GL_TEXTURE_BUFFER_BINDING 0x8C2A +#define GL_DYNAMIC_STORAGE_BIT 0x0100 +#define GL_CLIENT_STORAGE_BIT 0x0200 #define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000 -#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F -#define GL_BUFFER_STORAGE_FLAGS 0x8220 -#define GL_CLEAR_TEXTURE 0x9365 -#define GL_LOCATION_COMPONENT 0x934A +#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F +#define GL_BUFFER_STORAGE_FLAGS 0x8220 +#define GL_CLEAR_TEXTURE 0x9365 +#define GL_LOCATION_COMPONENT 0x934A #define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B #define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C -#define GL_QUERY_BUFFER 0x9192 -#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000 -#define GL_QUERY_BUFFER_BINDING 0x9193 -#define GL_QUERY_RESULT_NO_WAIT 0x9194 -#define GL_MIRROR_CLAMP_TO_EDGE 0x8743 +#define GL_QUERY_BUFFER 0x9192 +#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000 +#define GL_QUERY_BUFFER_BINDING 0x9193 +#define GL_QUERY_RESULT_NO_WAIT 0x9194 +#define GL_MIRROR_CLAMP_TO_EDGE 0x8743 -typedef void (APIENTRYP PFNDOLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); -typedef void (APIENTRYP PFNDOLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNDOLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNDOLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers); -typedef void (APIENTRYP PFNDOLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); -typedef void (APIENTRYP PFNDOLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); -typedef void (APIENTRYP PFNDOLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers); -typedef void (APIENTRYP PFNDOLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); -typedef void (APIENTRYP PFNDOLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); +typedef void(APIENTRYP PFNDOLBUFFERSTORAGEPROC)(GLenum target, GLsizeiptr size, const void* data, + GLbitfield flags); +typedef void(APIENTRYP PFNDOLCLEARTEXIMAGEPROC)(GLuint texture, GLint level, GLenum format, + GLenum type, const void* data); +typedef void(APIENTRYP PFNDOLCLEARTEXSUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, + GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, + GLenum type, const void* data); +typedef void(APIENTRYP PFNDOLBINDBUFFERSBASEPROC)(GLenum target, GLuint first, GLsizei count, + const GLuint* buffers); +typedef void(APIENTRYP PFNDOLBINDBUFFERSRANGEPROC)(GLenum target, GLuint first, GLsizei count, + const GLuint* buffers, const GLintptr* offsets, + const GLsizeiptr* sizes); +typedef void(APIENTRYP PFNDOLBINDTEXTURESPROC)(GLuint first, GLsizei count, const GLuint* textures); +typedef void(APIENTRYP PFNDOLBINDSAMPLERSPROC)(GLuint first, GLsizei count, const GLuint* samplers); +typedef void(APIENTRYP PFNDOLBINDIMAGETEXTURESPROC)(GLuint first, GLsizei count, + const GLuint* textures); +typedef void(APIENTRYP PFNDOLBINDVERTEXBUFFERSPROC)(GLuint first, GLsizei count, + const GLuint* buffers, const GLintptr* offsets, + const GLsizei* strides); extern PFNDOLCLEARTEXIMAGEPROC dolClearTexImage; extern PFNDOLCLEARTEXSUBIMAGEPROC dolClearTexSubImage; diff --git a/Source/Core/Common/GL/GLExtensions/gl_4_5.h b/Source/Core/Common/GL/GLExtensions/gl_4_5.h index 3db03d98c0..e6025feca0 100644 --- a/Source/Core/Common/GL/GLExtensions/gl_4_5.h +++ b/Source/Core/Common/GL/GLExtensions/gl_4_5.h @@ -23,151 +23,293 @@ #include "Common/GL/GLExtensions/gl_common.h" -#define GL_CONTEXT_LOST 0x0507 -#define GL_NEGATIVE_ONE_TO_ONE 0x935E -#define GL_ZERO_TO_ONE 0x935F -#define GL_CLIP_ORIGIN 0x935C -#define GL_CLIP_DEPTH_MODE 0x935D -#define GL_QUERY_WAIT_INVERTED 0x8E17 -#define GL_QUERY_NO_WAIT_INVERTED 0x8E18 -#define GL_QUERY_BY_REGION_WAIT_INVERTED 0x8E19 +#define GL_CONTEXT_LOST 0x0507 +#define GL_NEGATIVE_ONE_TO_ONE 0x935E +#define GL_ZERO_TO_ONE 0x935F +#define GL_CLIP_ORIGIN 0x935C +#define GL_CLIP_DEPTH_MODE 0x935D +#define GL_QUERY_WAIT_INVERTED 0x8E17 +#define GL_QUERY_NO_WAIT_INVERTED 0x8E18 +#define GL_QUERY_BY_REGION_WAIT_INVERTED 0x8E19 #define GL_QUERY_BY_REGION_NO_WAIT_INVERTED 0x8E1A -#define GL_MAX_CULL_DISTANCES 0x82F9 +#define GL_MAX_CULL_DISTANCES 0x82F9 #define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA -#define GL_TEXTURE_TARGET 0x1006 -#define GL_QUERY_TARGET 0x82EA -#define GL_GUILTY_CONTEXT_RESET 0x8253 -#define GL_INNOCENT_CONTEXT_RESET 0x8254 -#define GL_UNKNOWN_CONTEXT_RESET 0x8255 -#define GL_RESET_NOTIFICATION_STRATEGY 0x8256 -#define GL_LOSE_CONTEXT_ON_RESET 0x8252 -#define GL_NO_RESET_NOTIFICATION 0x8261 +#define GL_TEXTURE_TARGET 0x1006 +#define GL_QUERY_TARGET 0x82EA +#define GL_GUILTY_CONTEXT_RESET 0x8253 +#define GL_INNOCENT_CONTEXT_RESET 0x8254 +#define GL_UNKNOWN_CONTEXT_RESET 0x8255 +#define GL_RESET_NOTIFICATION_STRATEGY 0x8256 +#define GL_LOSE_CONTEXT_ON_RESET 0x8252 +#define GL_NO_RESET_NOTIFICATION 0x8261 #define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004 -#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB +#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB #define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC -typedef void (APIENTRYP PFNDOLCLIPCONTROLPROC) (GLenum origin, GLenum depth); -typedef void (APIENTRYP PFNDOLCREATETRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNDOLTRANSFORMFEEDBACKBUFFERBASEPROC) (GLuint xfb, GLuint index, GLuint buffer); -typedef void (APIENTRYP PFNDOLTRANSFORMFEEDBACKBUFFERRANGEPROC) (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNDOLGETTRANSFORMFEEDBACKIVPROC) (GLuint xfb, GLenum pname, GLint *param); -typedef void (APIENTRYP PFNDOLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint *param); -typedef void (APIENTRYP PFNDOLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64 *param); -typedef void (APIENTRYP PFNDOLCREATEBUFFERSPROC) (GLsizei n, GLuint *buffers); -typedef void (APIENTRYP PFNDOLNAMEDBUFFERSTORAGEPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); -typedef void (APIENTRYP PFNDOLNAMEDBUFFERDATAPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); -typedef void (APIENTRYP PFNDOLNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); -typedef void (APIENTRYP PFNDOLCOPYNAMEDBUFFERSUBDATAPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); -typedef void (APIENTRYP PFNDOLCLEARNAMEDBUFFERDATAPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNDOLCLEARNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); -typedef void *(APIENTRYP PFNDOLMAPNAMEDBUFFERPROC) (GLuint buffer, GLenum access); -typedef void *(APIENTRYP PFNDOLMAPNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); -typedef GLboolean (APIENTRYP PFNDOLUNMAPNAMEDBUFFERPROC) (GLuint buffer); -typedef void (APIENTRYP PFNDOLFLUSHMAPPEDNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); -typedef void (APIENTRYP PFNDOLGETNAMEDBUFFERPARAMETERIVPROC) (GLuint buffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETNAMEDBUFFERPARAMETERI64VPROC) (GLuint buffer, GLenum pname, GLint64 *params); -typedef void (APIENTRYP PFNDOLGETNAMEDBUFFERPOINTERVPROC) (GLuint buffer, GLenum pname, void **params); -typedef void (APIENTRYP PFNDOLGETNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); -typedef void (APIENTRYP PFNDOLCREATEFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); -typedef void (APIENTRYP PFNDOLNAMEDFRAMEBUFFERRENDERBUFFERPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); -typedef void (APIENTRYP PFNDOLNAMEDFRAMEBUFFERPARAMETERIPROC) (GLuint framebuffer, GLenum pname, GLint param); -typedef void (APIENTRYP PFNDOLNAMEDFRAMEBUFFERTEXTUREPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNDOLNAMEDFRAMEBUFFERTEXTURELAYERPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); -typedef void (APIENTRYP PFNDOLNAMEDFRAMEBUFFERDRAWBUFFERPROC) (GLuint framebuffer, GLenum buf); -typedef void (APIENTRYP PFNDOLNAMEDFRAMEBUFFERDRAWBUFFERSPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs); -typedef void (APIENTRYP PFNDOLNAMEDFRAMEBUFFERREADBUFFERPROC) (GLuint framebuffer, GLenum src); -typedef void (APIENTRYP PFNDOLINVALIDATENAMEDFRAMEBUFFERDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments); -typedef void (APIENTRYP PFNDOLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNDOLCLEARNAMEDFRAMEBUFFERIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value); -typedef void (APIENTRYP PFNDOLCLEARNAMEDFRAMEBUFFERUIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value); -typedef void (APIENTRYP PFNDOLCLEARNAMEDFRAMEBUFFERFVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value); -typedef void (APIENTRYP PFNDOLCLEARNAMEDFRAMEBUFFERFIPROC) (GLuint framebuffer, GLenum buffer, const GLfloat depth, GLint stencil); -typedef void (APIENTRYP PFNDOLBLITNAMEDFRAMEBUFFERPROC) (GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -typedef GLenum (APIENTRYP PFNDOLCHECKNAMEDFRAMEBUFFERSTATUSPROC) (GLuint framebuffer, GLenum target); -typedef void (APIENTRYP PFNDOLGETNAMEDFRAMEBUFFERPARAMETERIVPROC) (GLuint framebuffer, GLenum pname, GLint *param); -typedef void (APIENTRYP PFNDOLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLCREATERENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); -typedef void (APIENTRYP PFNDOLNAMEDRENDERBUFFERSTORAGEPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNDOLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNDOLGETNAMEDRENDERBUFFERPARAMETERIVPROC) (GLuint renderbuffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLCREATETEXTURESPROC) (GLenum target, GLsizei n, GLuint *textures); -typedef void (APIENTRYP PFNDOLTEXTUREBUFFERPROC) (GLuint texture, GLenum internalformat, GLuint buffer); -typedef void (APIENTRYP PFNDOLTEXTUREBUFFERRANGEPROC) (GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); -typedef void (APIENTRYP PFNDOLTEXTURESTORAGE1DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width); -typedef void (APIENTRYP PFNDOLTEXTURESTORAGE2DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNDOLTEXTURESTORAGE3DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); -typedef void (APIENTRYP PFNDOLTEXTURESTORAGE2DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNDOLTEXTURESTORAGE3DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNDOLTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNDOLTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNDOLTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); -typedef void (APIENTRYP PFNDOLCOMPRESSEDTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNDOLCOMPRESSEDTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNDOLCOMPRESSEDTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); -typedef void (APIENTRYP PFNDOLCOPYTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNDOLCOPYTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNDOLCOPYTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNDOLTEXTUREPARAMETERFPROC) (GLuint texture, GLenum pname, GLfloat param); -typedef void (APIENTRYP PFNDOLTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, const GLfloat *param); -typedef void (APIENTRYP PFNDOLTEXTUREPARAMETERIPROC) (GLuint texture, GLenum pname, GLint param); -typedef void (APIENTRYP PFNDOLTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNDOLTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, const GLuint *params); -typedef void (APIENTRYP PFNDOLTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, const GLint *param); -typedef void (APIENTRYP PFNDOLGENERATETEXTUREMIPMAPPROC) (GLuint texture); -typedef void (APIENTRYP PFNDOLBINDTEXTUREUNITPROC) (GLuint unit, GLuint texture); -typedef void (APIENTRYP PFNDOLGETTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); -typedef void (APIENTRYP PFNDOLGETCOMPRESSEDTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLsizei bufSize, void *pixels); -typedef void (APIENTRYP PFNDOLGETTEXTURELEVELPARAMETERFVPROC) (GLuint texture, GLint level, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNDOLGETTEXTURELEVELPARAMETERIVPROC) (GLuint texture, GLint level, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNDOLGETTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLGETTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, GLuint *params); -typedef void (APIENTRYP PFNDOLGETTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNDOLCREATEVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); -typedef void (APIENTRYP PFNDOLDISABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index); -typedef void (APIENTRYP PFNDOLENABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index); -typedef void (APIENTRYP PFNDOLVERTEXARRAYELEMENTBUFFERPROC) (GLuint vaobj, GLuint buffer); -typedef void (APIENTRYP PFNDOLVERTEXARRAYVERTEXBUFFERPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); -typedef void (APIENTRYP PFNDOLVERTEXARRAYVERTEXBUFFERSPROC) (GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); -typedef void (APIENTRYP PFNDOLVERTEXARRAYATTRIBBINDINGPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex); -typedef void (APIENTRYP PFNDOLVERTEXARRAYATTRIBFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); -typedef void (APIENTRYP PFNDOLVERTEXARRAYATTRIBIFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (APIENTRYP PFNDOLVERTEXARRAYATTRIBLFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); -typedef void (APIENTRYP PFNDOLVERTEXARRAYBINDINGDIVISORPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor); -typedef void (APIENTRYP PFNDOLGETVERTEXARRAYIVPROC) (GLuint vaobj, GLenum pname, GLint *param); -typedef void (APIENTRYP PFNDOLGETVERTEXARRAYINDEXEDIVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param); -typedef void (APIENTRYP PFNDOLGETVERTEXARRAYINDEXED64IVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint64 *param); -typedef void (APIENTRYP PFNDOLCREATESAMPLERSPROC) (GLsizei n, GLuint *samplers); -typedef void (APIENTRYP PFNDOLCREATEPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); -typedef void (APIENTRYP PFNDOLCREATEQUERIESPROC) (GLenum target, GLsizei n, GLuint *ids); -typedef void (APIENTRYP PFNDOLGETQUERYBUFFEROBJECTI64VPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -typedef void (APIENTRYP PFNDOLGETQUERYBUFFEROBJECTIVPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -typedef void (APIENTRYP PFNDOLGETQUERYBUFFEROBJECTUI64VPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -typedef void (APIENTRYP PFNDOLGETQUERYBUFFEROBJECTUIVPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); -typedef void (APIENTRYP PFNDOLMEMORYBARRIERBYREGIONPROC) (GLbitfield barriers); -typedef void (APIENTRYP PFNDOLGETTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels); -typedef void (APIENTRYP PFNDOLGETCOMPRESSEDTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels); -typedef GLenum (APIENTRYP PFNDOLGETGRAPHICSRESETSTATUSPROC) (void); -typedef void (APIENTRYP PFNDOLGETNCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint lod, GLsizei bufSize, void *pixels); -typedef void (APIENTRYP PFNDOLGETNTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); -typedef void (APIENTRYP PFNDOLGETNUNIFORMDVPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); -typedef void (APIENTRYP PFNDOLGETNUNIFORMFVPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); -typedef void (APIENTRYP PFNDOLGETNUNIFORMIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); -typedef void (APIENTRYP PFNDOLGETNUNIFORMUIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); -typedef void (APIENTRYP PFNDOLREADNPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); -typedef void (APIENTRYP PFNDOLGETNMAPDVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); -typedef void (APIENTRYP PFNDOLGETNMAPFVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); -typedef void (APIENTRYP PFNDOLGETNMAPIVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v); -typedef void (APIENTRYP PFNDOLGETNPIXELMAPFVPROC) (GLenum map, GLsizei bufSize, GLfloat *values); -typedef void (APIENTRYP PFNDOLGETNPIXELMAPUIVPROC) (GLenum map, GLsizei bufSize, GLuint *values); -typedef void (APIENTRYP PFNDOLGETNPIXELMAPUSVPROC) (GLenum map, GLsizei bufSize, GLushort *values); -typedef void (APIENTRYP PFNDOLGETNPOLYGONSTIPPLEPROC) (GLsizei bufSize, GLubyte *pattern); -typedef void (APIENTRYP PFNDOLGETNCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); -typedef void (APIENTRYP PFNDOLGETNCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); -typedef void (APIENTRYP PFNDOLGETNSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); -typedef void (APIENTRYP PFNDOLGETNHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); -typedef void (APIENTRYP PFNDOLGETNMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); -typedef void (APIENTRYP PFNDOLTEXTUREBARRIERPROC) (void); +typedef void(APIENTRYP PFNDOLCLIPCONTROLPROC)(GLenum origin, GLenum depth); +typedef void(APIENTRYP PFNDOLCREATETRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint* ids); +typedef void(APIENTRYP PFNDOLTRANSFORMFEEDBACKBUFFERBASEPROC)(GLuint xfb, GLuint index, + GLuint buffer); +typedef void(APIENTRYP PFNDOLTRANSFORMFEEDBACKBUFFERRANGEPROC)(GLuint xfb, GLuint index, + GLuint buffer, GLintptr offset, + GLsizeiptr size); +typedef void(APIENTRYP PFNDOLGETTRANSFORMFEEDBACKIVPROC)(GLuint xfb, GLenum pname, GLint* param); +typedef void(APIENTRYP PFNDOLGETTRANSFORMFEEDBACKI_VPROC)(GLuint xfb, GLenum pname, GLuint index, + GLint* param); +typedef void(APIENTRYP PFNDOLGETTRANSFORMFEEDBACKI64_VPROC)(GLuint xfb, GLenum pname, GLuint index, + GLint64* param); +typedef void(APIENTRYP PFNDOLCREATEBUFFERSPROC)(GLsizei n, GLuint* buffers); +typedef void(APIENTRYP PFNDOLNAMEDBUFFERSTORAGEPROC)(GLuint buffer, GLsizeiptr size, + const void* data, GLbitfield flags); +typedef void(APIENTRYP PFNDOLNAMEDBUFFERDATAPROC)(GLuint buffer, GLsizeiptr size, const void* data, + GLenum usage); +typedef void(APIENTRYP PFNDOLNAMEDBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, + GLsizeiptr size, const void* data); +typedef void(APIENTRYP PFNDOLCOPYNAMEDBUFFERSUBDATAPROC)(GLuint readBuffer, GLuint writeBuffer, + GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size); +typedef void(APIENTRYP PFNDOLCLEARNAMEDBUFFERDATAPROC)(GLuint buffer, GLenum internalformat, + GLenum format, GLenum type, + const void* data); +typedef void(APIENTRYP PFNDOLCLEARNAMEDBUFFERSUBDATAPROC)(GLuint buffer, GLenum internalformat, + GLintptr offset, GLsizeiptr size, + GLenum format, GLenum type, + const void* data); +typedef void*(APIENTRYP PFNDOLMAPNAMEDBUFFERPROC)(GLuint buffer, GLenum access); +typedef void*(APIENTRYP PFNDOLMAPNAMEDBUFFERRANGEPROC)(GLuint buffer, GLintptr offset, + GLsizeiptr length, GLbitfield access); +typedef GLboolean(APIENTRYP PFNDOLUNMAPNAMEDBUFFERPROC)(GLuint buffer); +typedef void(APIENTRYP PFNDOLFLUSHMAPPEDNAMEDBUFFERRANGEPROC)(GLuint buffer, GLintptr offset, + GLsizeiptr length); +typedef void(APIENTRYP PFNDOLGETNAMEDBUFFERPARAMETERIVPROC)(GLuint buffer, GLenum pname, + GLint* params); +typedef void(APIENTRYP PFNDOLGETNAMEDBUFFERPARAMETERI64VPROC)(GLuint buffer, GLenum pname, + GLint64* params); +typedef void(APIENTRYP PFNDOLGETNAMEDBUFFERPOINTERVPROC)(GLuint buffer, GLenum pname, + void** params); +typedef void(APIENTRYP PFNDOLGETNAMEDBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, + GLsizeiptr size, void* data); +typedef void(APIENTRYP PFNDOLCREATEFRAMEBUFFERSPROC)(GLsizei n, GLuint* framebuffers); +typedef void(APIENTRYP PFNDOLNAMEDFRAMEBUFFERRENDERBUFFERPROC)(GLuint framebuffer, + GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer); +typedef void(APIENTRYP PFNDOLNAMEDFRAMEBUFFERPARAMETERIPROC)(GLuint framebuffer, GLenum pname, + GLint param); +typedef void(APIENTRYP PFNDOLNAMEDFRAMEBUFFERTEXTUREPROC)(GLuint framebuffer, GLenum attachment, + GLuint texture, GLint level); +typedef void(APIENTRYP PFNDOLNAMEDFRAMEBUFFERTEXTURELAYERPROC)(GLuint framebuffer, + GLenum attachment, GLuint texture, + GLint level, GLint layer); +typedef void(APIENTRYP PFNDOLNAMEDFRAMEBUFFERDRAWBUFFERPROC)(GLuint framebuffer, GLenum buf); +typedef void(APIENTRYP PFNDOLNAMEDFRAMEBUFFERDRAWBUFFERSPROC)(GLuint framebuffer, GLsizei n, + const GLenum* bufs); +typedef void(APIENTRYP PFNDOLNAMEDFRAMEBUFFERREADBUFFERPROC)(GLuint framebuffer, GLenum src); +typedef void(APIENTRYP PFNDOLINVALIDATENAMEDFRAMEBUFFERDATAPROC)(GLuint framebuffer, + GLsizei numAttachments, + const GLenum* attachments); +typedef void(APIENTRYP PFNDOLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC)(GLuint framebuffer, + GLsizei numAttachments, + const GLenum* attachments, + GLint x, GLint y, GLsizei width, + GLsizei height); +typedef void(APIENTRYP PFNDOLCLEARNAMEDFRAMEBUFFERIVPROC)(GLuint framebuffer, GLenum buffer, + GLint drawbuffer, const GLint* value); +typedef void(APIENTRYP PFNDOLCLEARNAMEDFRAMEBUFFERUIVPROC)(GLuint framebuffer, GLenum buffer, + GLint drawbuffer, const GLuint* value); +typedef void(APIENTRYP PFNDOLCLEARNAMEDFRAMEBUFFERFVPROC)(GLuint framebuffer, GLenum buffer, + GLint drawbuffer, const GLfloat* value); +typedef void(APIENTRYP PFNDOLCLEARNAMEDFRAMEBUFFERFIPROC)(GLuint framebuffer, GLenum buffer, + const GLfloat depth, GLint stencil); +typedef void(APIENTRYP PFNDOLBLITNAMEDFRAMEBUFFERPROC)(GLuint readFramebuffer, + GLuint drawFramebuffer, GLint srcX0, + GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, + GLint dstY1, GLbitfield mask, GLenum filter); +typedef GLenum(APIENTRYP PFNDOLCHECKNAMEDFRAMEBUFFERSTATUSPROC)(GLuint framebuffer, GLenum target); +typedef void(APIENTRYP PFNDOLGETNAMEDFRAMEBUFFERPARAMETERIVPROC)(GLuint framebuffer, GLenum pname, + GLint* param); +typedef void(APIENTRYP PFNDOLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLuint framebuffer, + GLenum attachment, + GLenum pname, + GLint* params); +typedef void(APIENTRYP PFNDOLCREATERENDERBUFFERSPROC)(GLsizei n, GLuint* renderbuffers); +typedef void(APIENTRYP PFNDOLNAMEDRENDERBUFFERSTORAGEPROC)(GLuint renderbuffer, + GLenum internalformat, GLsizei width, + GLsizei height); +typedef void(APIENTRYP PFNDOLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC)( + GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNDOLGETNAMEDRENDERBUFFERPARAMETERIVPROC)(GLuint renderbuffer, GLenum pname, + GLint* params); +typedef void(APIENTRYP PFNDOLCREATETEXTURESPROC)(GLenum target, GLsizei n, GLuint* textures); +typedef void(APIENTRYP PFNDOLTEXTUREBUFFERPROC)(GLuint texture, GLenum internalformat, + GLuint buffer); +typedef void(APIENTRYP PFNDOLTEXTUREBUFFERRANGEPROC)(GLuint texture, GLenum internalformat, + GLuint buffer, GLintptr offset, + GLsizeiptr size); +typedef void(APIENTRYP PFNDOLTEXTURESTORAGE1DPROC)(GLuint texture, GLsizei levels, + GLenum internalformat, GLsizei width); +typedef void(APIENTRYP PFNDOLTEXTURESTORAGE2DPROC)(GLuint texture, GLsizei levels, + GLenum internalformat, GLsizei width, + GLsizei height); +typedef void(APIENTRYP PFNDOLTEXTURESTORAGE3DPROC)(GLuint texture, GLsizei levels, + GLenum internalformat, GLsizei width, + GLsizei height, GLsizei depth); +typedef void(APIENTRYP PFNDOLTEXTURESTORAGE2DMULTISAMPLEPROC)(GLuint texture, GLsizei samples, + GLenum internalformat, GLsizei width, + GLsizei height, + GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNDOLTEXTURESTORAGE3DMULTISAMPLEPROC)(GLuint texture, GLsizei samples, + GLenum internalformat, GLsizei width, + GLsizei height, GLsizei depth, + GLboolean fixedsamplelocations); +typedef void(APIENTRYP PFNDOLTEXTURESUBIMAGE1DPROC)(GLuint texture, GLint level, GLint xoffset, + GLsizei width, GLenum format, GLenum type, + const void* pixels); +typedef void(APIENTRYP PFNDOLTEXTURESUBIMAGE2DPROC)(GLuint texture, GLint level, GLint xoffset, + GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLenum type, const void* pixels); +typedef void(APIENTRYP PFNDOLTEXTURESUBIMAGE3DPROC)(GLuint texture, GLint level, GLint xoffset, + GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, + GLenum type, const void* pixels); +typedef void(APIENTRYP PFNDOLCOMPRESSEDTEXTURESUBIMAGE1DPROC)(GLuint texture, GLint level, + GLint xoffset, GLsizei width, + GLenum format, GLsizei imageSize, + const void* data); +typedef void(APIENTRYP PFNDOLCOMPRESSEDTEXTURESUBIMAGE2DPROC)(GLuint texture, GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, + const void* data); +typedef void(APIENTRYP PFNDOLCOMPRESSEDTEXTURESUBIMAGE3DPROC)( + GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data); +typedef void(APIENTRYP PFNDOLCOPYTEXTURESUBIMAGE1DPROC)(GLuint texture, GLint level, GLint xoffset, + GLint x, GLint y, GLsizei width); +typedef void(APIENTRYP PFNDOLCOPYTEXTURESUBIMAGE2DPROC)(GLuint texture, GLint level, GLint xoffset, + GLint yoffset, GLint x, GLint y, + GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNDOLCOPYTEXTURESUBIMAGE3DPROC)(GLuint texture, GLint level, GLint xoffset, + GLint yoffset, GLint zoffset, GLint x, + GLint y, GLsizei width, GLsizei height); +typedef void(APIENTRYP PFNDOLTEXTUREPARAMETERFPROC)(GLuint texture, GLenum pname, GLfloat param); +typedef void(APIENTRYP PFNDOLTEXTUREPARAMETERFVPROC)(GLuint texture, GLenum pname, + const GLfloat* param); +typedef void(APIENTRYP PFNDOLTEXTUREPARAMETERIPROC)(GLuint texture, GLenum pname, GLint param); +typedef void(APIENTRYP PFNDOLTEXTUREPARAMETERIIVPROC)(GLuint texture, GLenum pname, + const GLint* params); +typedef void(APIENTRYP PFNDOLTEXTUREPARAMETERIUIVPROC)(GLuint texture, GLenum pname, + const GLuint* params); +typedef void(APIENTRYP PFNDOLTEXTUREPARAMETERIVPROC)(GLuint texture, GLenum pname, + const GLint* param); +typedef void(APIENTRYP PFNDOLGENERATETEXTUREMIPMAPPROC)(GLuint texture); +typedef void(APIENTRYP PFNDOLBINDTEXTUREUNITPROC)(GLuint unit, GLuint texture); +typedef void(APIENTRYP PFNDOLGETTEXTUREIMAGEPROC)(GLuint texture, GLint level, GLenum format, + GLenum type, GLsizei bufSize, void* pixels); +typedef void(APIENTRYP PFNDOLGETCOMPRESSEDTEXTUREIMAGEPROC)(GLuint texture, GLint level, + GLsizei bufSize, void* pixels); +typedef void(APIENTRYP PFNDOLGETTEXTURELEVELPARAMETERFVPROC)(GLuint texture, GLint level, + GLenum pname, GLfloat* params); +typedef void(APIENTRYP PFNDOLGETTEXTURELEVELPARAMETERIVPROC)(GLuint texture, GLint level, + GLenum pname, GLint* params); +typedef void(APIENTRYP PFNDOLGETTEXTUREPARAMETERFVPROC)(GLuint texture, GLenum pname, + GLfloat* params); +typedef void(APIENTRYP PFNDOLGETTEXTUREPARAMETERIIVPROC)(GLuint texture, GLenum pname, + GLint* params); +typedef void(APIENTRYP PFNDOLGETTEXTUREPARAMETERIUIVPROC)(GLuint texture, GLenum pname, + GLuint* params); +typedef void(APIENTRYP PFNDOLGETTEXTUREPARAMETERIVPROC)(GLuint texture, GLenum pname, + GLint* params); +typedef void(APIENTRYP PFNDOLCREATEVERTEXARRAYSPROC)(GLsizei n, GLuint* arrays); +typedef void(APIENTRYP PFNDOLDISABLEVERTEXARRAYATTRIBPROC)(GLuint vaobj, GLuint index); +typedef void(APIENTRYP PFNDOLENABLEVERTEXARRAYATTRIBPROC)(GLuint vaobj, GLuint index); +typedef void(APIENTRYP PFNDOLVERTEXARRAYELEMENTBUFFERPROC)(GLuint vaobj, GLuint buffer); +typedef void(APIENTRYP PFNDOLVERTEXARRAYVERTEXBUFFERPROC)(GLuint vaobj, GLuint bindingindex, + GLuint buffer, GLintptr offset, + GLsizei stride); +typedef void(APIENTRYP PFNDOLVERTEXARRAYVERTEXBUFFERSPROC)(GLuint vaobj, GLuint first, + GLsizei count, const GLuint* buffers, + const GLintptr* offsets, + const GLsizei* strides); +typedef void(APIENTRYP PFNDOLVERTEXARRAYATTRIBBINDINGPROC)(GLuint vaobj, GLuint attribindex, + GLuint bindingindex); +typedef void(APIENTRYP PFNDOLVERTEXARRAYATTRIBFORMATPROC)(GLuint vaobj, GLuint attribindex, + GLint size, GLenum type, + GLboolean normalized, + GLuint relativeoffset); +typedef void(APIENTRYP PFNDOLVERTEXARRAYATTRIBIFORMATPROC)(GLuint vaobj, GLuint attribindex, + GLint size, GLenum type, + GLuint relativeoffset); +typedef void(APIENTRYP PFNDOLVERTEXARRAYATTRIBLFORMATPROC)(GLuint vaobj, GLuint attribindex, + GLint size, GLenum type, + GLuint relativeoffset); +typedef void(APIENTRYP PFNDOLVERTEXARRAYBINDINGDIVISORPROC)(GLuint vaobj, GLuint bindingindex, + GLuint divisor); +typedef void(APIENTRYP PFNDOLGETVERTEXARRAYIVPROC)(GLuint vaobj, GLenum pname, GLint* param); +typedef void(APIENTRYP PFNDOLGETVERTEXARRAYINDEXEDIVPROC)(GLuint vaobj, GLuint index, GLenum pname, + GLint* param); +typedef void(APIENTRYP PFNDOLGETVERTEXARRAYINDEXED64IVPROC)(GLuint vaobj, GLuint index, + GLenum pname, GLint64* param); +typedef void(APIENTRYP PFNDOLCREATESAMPLERSPROC)(GLsizei n, GLuint* samplers); +typedef void(APIENTRYP PFNDOLCREATEPROGRAMPIPELINESPROC)(GLsizei n, GLuint* pipelines); +typedef void(APIENTRYP PFNDOLCREATEQUERIESPROC)(GLenum target, GLsizei n, GLuint* ids); +typedef void(APIENTRYP PFNDOLGETQUERYBUFFEROBJECTI64VPROC)(GLuint id, GLuint buffer, GLenum pname, + GLintptr offset); +typedef void(APIENTRYP PFNDOLGETQUERYBUFFEROBJECTIVPROC)(GLuint id, GLuint buffer, GLenum pname, + GLintptr offset); +typedef void(APIENTRYP PFNDOLGETQUERYBUFFEROBJECTUI64VPROC)(GLuint id, GLuint buffer, GLenum pname, + GLintptr offset); +typedef void(APIENTRYP PFNDOLGETQUERYBUFFEROBJECTUIVPROC)(GLuint id, GLuint buffer, GLenum pname, + GLintptr offset); +typedef void(APIENTRYP PFNDOLMEMORYBARRIERBYREGIONPROC)(GLbitfield barriers); +typedef void(APIENTRYP PFNDOLGETTEXTURESUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, + GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, GLenum format, + GLenum type, GLsizei bufSize, void* pixels); +typedef void(APIENTRYP PFNDOLGETCOMPRESSEDTEXTURESUBIMAGEPROC)(GLuint texture, GLint level, + GLint xoffset, GLint yoffset, + GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, + GLsizei bufSize, void* pixels); +typedef GLenum(APIENTRYP PFNDOLGETGRAPHICSRESETSTATUSPROC)(void); +typedef void(APIENTRYP PFNDOLGETNCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint lod, GLsizei bufSize, + void* pixels); +typedef void(APIENTRYP PFNDOLGETNTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, + GLenum type, GLsizei bufSize, void* pixels); +typedef void(APIENTRYP PFNDOLGETNUNIFORMDVPROC)(GLuint program, GLint location, GLsizei bufSize, + GLdouble* params); +typedef void(APIENTRYP PFNDOLGETNUNIFORMFVPROC)(GLuint program, GLint location, GLsizei bufSize, + GLfloat* params); +typedef void(APIENTRYP PFNDOLGETNUNIFORMIVPROC)(GLuint program, GLint location, GLsizei bufSize, + GLint* params); +typedef void(APIENTRYP PFNDOLGETNUNIFORMUIVPROC)(GLuint program, GLint location, GLsizei bufSize, + GLuint* params); +typedef void(APIENTRYP PFNDOLREADNPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei bufSize, + void* data); +typedef void(APIENTRYP PFNDOLGETNMAPDVPROC)(GLenum target, GLenum query, GLsizei bufSize, + GLdouble* v); +typedef void(APIENTRYP PFNDOLGETNMAPFVPROC)(GLenum target, GLenum query, GLsizei bufSize, + GLfloat* v); +typedef void(APIENTRYP PFNDOLGETNMAPIVPROC)(GLenum target, GLenum query, GLsizei bufSize, GLint* v); +typedef void(APIENTRYP PFNDOLGETNPIXELMAPFVPROC)(GLenum map, GLsizei bufSize, GLfloat* values); +typedef void(APIENTRYP PFNDOLGETNPIXELMAPUIVPROC)(GLenum map, GLsizei bufSize, GLuint* values); +typedef void(APIENTRYP PFNDOLGETNPIXELMAPUSVPROC)(GLenum map, GLsizei bufSize, GLushort* values); +typedef void(APIENTRYP PFNDOLGETNPOLYGONSTIPPLEPROC)(GLsizei bufSize, GLubyte* pattern); +typedef void(APIENTRYP PFNDOLGETNCOLORTABLEPROC)(GLenum target, GLenum format, GLenum type, + GLsizei bufSize, void* table); +typedef void(APIENTRYP PFNDOLGETNCONVOLUTIONFILTERPROC)(GLenum target, GLenum format, GLenum type, + GLsizei bufSize, void* image); +typedef void(APIENTRYP PFNDOLGETNSEPARABLEFILTERPROC)(GLenum target, GLenum format, GLenum type, + GLsizei rowBufSize, void* row, + GLsizei columnBufSize, void* column, + void* span); +typedef void(APIENTRYP PFNDOLGETNHISTOGRAMPROC)(GLenum target, GLboolean reset, GLenum format, + GLenum type, GLsizei bufSize, void* values); +typedef void(APIENTRYP PFNDOLGETNMINMAXPROC)(GLenum target, GLboolean reset, GLenum format, + GLenum type, GLsizei bufSize, void* values); +typedef void(APIENTRYP PFNDOLTEXTUREBARRIERPROC)(void); extern PFNDOLCREATETRANSFORMFEEDBACKSPROC dolCreateTransformFeedbacks; extern PFNDOLTRANSFORMFEEDBACKBUFFERBASEPROC dolTransformFeedbackBufferBase; @@ -207,7 +349,8 @@ extern PFNDOLCLEARNAMEDFRAMEBUFFERFIPROC dolClearNamedFramebufferfi; extern PFNDOLBLITNAMEDFRAMEBUFFERPROC dolBlitNamedFramebuffer; extern PFNDOLCHECKNAMEDFRAMEBUFFERSTATUSPROC dolCheckNamedFramebufferStatus; extern PFNDOLGETNAMEDFRAMEBUFFERPARAMETERIVPROC dolGetNamedFramebufferParameteriv; -extern PFNDOLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC dolGetNamedFramebufferAttachmentParameteriv; +extern PFNDOLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC + dolGetNamedFramebufferAttachmentParameteriv; extern PFNDOLCREATERENDERBUFFERSPROC dolCreateRenderbuffers; extern PFNDOLNAMEDRENDERBUFFERSTORAGEPROC dolNamedRenderbufferStorage; extern PFNDOLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC dolNamedRenderbufferStorageMultisample; @@ -412,5 +555,3 @@ extern PFNDOLTEXTUREBARRIERPROC dolTextureBarrier; #define glGetnHistogram dolGetnHistogram #define glGetnMinmax dolGetnMinmax #define glTextureBarrier dolTextureBarrier - - diff --git a/Source/Core/Common/GL/GLExtensions/gl_common.h b/Source/Core/Common/GL/GLExtensions/gl_common.h index 2d3e57b459..317bb3a94a 100644 --- a/Source/Core/Common/GL/GLExtensions/gl_common.h +++ b/Source/Core/Common/GL/GLExtensions/gl_common.h @@ -32,7 +32,7 @@ #define APIENTRY #endif #ifndef APIENTRYP -#define APIENTRYP APIENTRY * +#define APIENTRYP APIENTRY* #endif #ifndef GLAPI #define GLAPI extern @@ -42,27 +42,27 @@ * Datatypes */ #include -typedef unsigned int GLenum; -typedef unsigned char GLboolean; -typedef unsigned int GLbitfield; -typedef void GLvoid; -typedef signed char GLbyte; /* 1-byte signed */ -typedef short GLshort; /* 2-byte signed */ -typedef int GLint; /* 4-byte signed */ -typedef unsigned char GLubyte; /* 1-byte unsigned */ -typedef unsigned short GLushort; /* 2-byte unsigned */ -typedef unsigned int GLuint; /* 4-byte unsigned */ -typedef int GLsizei; /* 4-byte signed */ -typedef float GLfloat; /* single precision float */ -typedef float GLclampf; /* single precision float in [0,1] */ -typedef double GLdouble; /* double precision float */ -typedef double GLclampd; /* double precision float in [0,1] */ +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef signed char GLbyte; /* 1-byte signed */ +typedef short GLshort; /* 2-byte signed */ +typedef int GLint; /* 4-byte signed */ +typedef unsigned char GLubyte; /* 1-byte unsigned */ +typedef unsigned short GLushort; /* 2-byte unsigned */ +typedef unsigned int GLuint; /* 4-byte unsigned */ +typedef int GLsizei; /* 4-byte signed */ +typedef float GLfloat; /* single precision float */ +typedef float GLclampf; /* single precision float in [0,1] */ +typedef double GLdouble; /* double precision float */ +typedef double GLclampd; /* double precision float in [0,1] */ typedef char GLchar; typedef unsigned short GLhalf; typedef ptrdiff_t GLsizeiptr; typedef ptrdiff_t GLintptr; -typedef struct __GLsync *GLsync; +typedef struct __GLsync* GLsync; #ifndef GLEXT_64_TYPES_DEFINED /* This code block is duplicated in glxext.h, so must be protected */ #define GLEXT_64_TYPES_DEFINED @@ -81,7 +81,7 @@ typedef long long int int64_t; typedef unsigned long long int uint64_t; #endif /* __arch64__ */ #endif /* __STDC__ */ -#elif defined( __VMS ) || defined(__sgi) +#elif defined(__VMS) || defined(__sgi) #include #elif defined(__SCO__) || defined(__USLC__) #include diff --git a/Source/Core/Common/GL/GLInterface/AGL.cpp b/Source/Core/Common/GL/GLInterface/AGL.cpp index d5d905b5c5..78b2db2ea4 100644 --- a/Source/Core/Common/GL/GLInterface/AGL.cpp +++ b/Source/Core/Common/GL/GLInterface/AGL.cpp @@ -7,100 +7,100 @@ void cInterfaceAGL::Swap() { - [cocoaCtx flushBuffer]; + [cocoaCtx flushBuffer]; } // Create rendering window. // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() -bool cInterfaceAGL::Create(void *window_handle, bool core) +bool cInterfaceAGL::Create(void* window_handle, bool core) { - cocoaWin = reinterpret_cast(window_handle); - NSSize size = [cocoaWin frame].size; + cocoaWin = reinterpret_cast(window_handle); + NSSize size = [cocoaWin frame].size; - // Enable high-resolution display support. - [cocoaWin setWantsBestResolutionOpenGLSurface:YES]; + // Enable high-resolution display support. + [cocoaWin setWantsBestResolutionOpenGLSurface:YES]; - NSWindow *window = [cocoaWin window]; + NSWindow* window = [cocoaWin window]; - float scale = [window backingScaleFactor]; - size.width *= scale; - size.height *= scale; + float scale = [window backingScaleFactor]; + size.width *= scale; + size.height *= scale; - // Control window size and picture scaling - s_backbuffer_width = size.width; - s_backbuffer_height = size.height; + // Control window size and picture scaling + s_backbuffer_width = size.width; + s_backbuffer_height = size.height; - NSOpenGLPixelFormatAttribute attr[] = { NSOpenGLPFADoubleBuffer, NSOpenGLPFAOpenGLProfile, core ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy, NSOpenGLPFAAccelerated, 0 }; - NSOpenGLPixelFormat *fmt = [[NSOpenGLPixelFormat alloc] - initWithAttributes: attr]; - if (fmt == nil) - { - ERROR_LOG(VIDEO, "failed to create pixel format"); - return false; - } + NSOpenGLPixelFormatAttribute attr[] = {NSOpenGLPFADoubleBuffer, NSOpenGLPFAOpenGLProfile, + core ? NSOpenGLProfileVersion3_2Core : + NSOpenGLProfileVersionLegacy, + NSOpenGLPFAAccelerated, 0}; + NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; + if (fmt == nil) + { + ERROR_LOG(VIDEO, "failed to create pixel format"); + return false; + } - cocoaCtx = [[NSOpenGLContext alloc] initWithFormat: fmt shareContext: nil]; - [fmt release]; - if (cocoaCtx == nil) - { - ERROR_LOG(VIDEO, "failed to create context"); - return false; - } + cocoaCtx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:nil]; + [fmt release]; + if (cocoaCtx == nil) + { + ERROR_LOG(VIDEO, "failed to create context"); + return false; + } - if (cocoaWin == nil) - { - ERROR_LOG(VIDEO, "failed to create window"); - return false; - } + if (cocoaWin == nil) + { + ERROR_LOG(VIDEO, "failed to create window"); + return false; + } - [window makeFirstResponder:cocoaWin]; - [cocoaCtx setView: cocoaWin]; - [window makeKeyAndOrderFront: nil]; + [window makeFirstResponder:cocoaWin]; + [cocoaCtx setView:cocoaWin]; + [window makeKeyAndOrderFront:nil]; - return true; + return true; } bool cInterfaceAGL::MakeCurrent() { - [cocoaCtx makeCurrentContext]; - return true; + [cocoaCtx makeCurrentContext]; + return true; } bool cInterfaceAGL::ClearCurrent() { - [NSOpenGLContext clearCurrentContext]; - return true; + [NSOpenGLContext clearCurrentContext]; + return true; } // Close backend void cInterfaceAGL::Shutdown() { - [cocoaCtx clearDrawable]; - [cocoaCtx release]; - cocoaCtx = nil; + [cocoaCtx clearDrawable]; + [cocoaCtx release]; + cocoaCtx = nil; } void cInterfaceAGL::Update() { - NSWindow *window = [cocoaWin window]; - NSSize size = [cocoaWin frame].size; + NSWindow* window = [cocoaWin window]; + NSSize size = [cocoaWin frame].size; - float scale = [window backingScaleFactor]; - size.width *= scale; - size.height *= scale; + float scale = [window backingScaleFactor]; + size.width *= scale; + size.height *= scale; - if (s_backbuffer_width == size.width && - s_backbuffer_height == size.height) - return; + if (s_backbuffer_width == size.width && s_backbuffer_height == size.height) + return; - s_backbuffer_width = size.width; - s_backbuffer_height = size.height; + s_backbuffer_width = size.width; + s_backbuffer_height = size.height; - [cocoaCtx update]; + [cocoaCtx update]; } void cInterfaceAGL::SwapInterval(int interval) { - [cocoaCtx setValues:(GLint *)&interval forParameter:NSOpenGLCPSwapInterval]; + [cocoaCtx setValues:(GLint*)&interval forParameter:NSOpenGLCPSwapInterval]; } - diff --git a/Source/Core/Common/GL/GLInterface/AGL.h b/Source/Core/Common/GL/GLInterface/AGL.h index f9aeb77a95..d326b04499 100644 --- a/Source/Core/Common/GL/GLInterface/AGL.h +++ b/Source/Core/Common/GL/GLInterface/AGL.h @@ -13,15 +13,15 @@ class cInterfaceAGL : public cInterfaceBase { private: - NSView* cocoaWin; - NSOpenGLContext* cocoaCtx; -public: - void Swap() override; - bool Create(void* window_handle, bool core) override; - bool MakeCurrent() override; - bool ClearCurrent() override; - void Shutdown() override; - void Update() override; - void SwapInterval(int interval) override; + NSView* cocoaWin; + NSOpenGLContext* cocoaCtx; +public: + void Swap() override; + bool Create(void* window_handle, bool core) override; + bool MakeCurrent() override; + bool ClearCurrent() override; + void Shutdown() override; + void Update() override; + void SwapInterval(int interval) override; }; diff --git a/Source/Core/Common/GL/GLInterface/EGL.cpp b/Source/Core/Common/GL/GLInterface/EGL.cpp index 77bd67bc29..df5ed4d8fd 100644 --- a/Source/Core/Common/GL/GLInterface/EGL.cpp +++ b/Source/Core/Common/GL/GLInterface/EGL.cpp @@ -12,376 +12,364 @@ #ifndef EGL_KHR_create_context #define EGL_KHR_create_context 1 -#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 -#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB -#define EGL_CONTEXT_FLAGS_KHR 0x30FC +#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 +#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB +#define EGL_CONTEXT_FLAGS_KHR 0x30FC #define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD #define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD -#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE -#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF -#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 +#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE +#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF +#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 #define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 -#define EGL_OPENGL_ES3_BIT_KHR 0x00000040 +#define EGL_OPENGL_ES3_BIT_KHR 0x00000040 #endif /* EGL_KHR_create_context */ // Show the current FPS void cInterfaceEGL::Swap() { - if (egl_surf != EGL_NO_SURFACE) - eglSwapBuffers(egl_dpy, egl_surf); + if (egl_surf != EGL_NO_SURFACE) + eglSwapBuffers(egl_dpy, egl_surf); } void cInterfaceEGL::SwapInterval(int Interval) { - eglSwapInterval(egl_dpy, Interval); + eglSwapInterval(egl_dpy, Interval); } void* cInterfaceEGL::GetFuncAddress(const std::string& name) { - return (void*)eglGetProcAddress(name.c_str()); + return (void*)eglGetProcAddress(name.c_str()); } void cInterfaceEGL::DetectMode() { - if (s_opengl_mode != GLInterfaceMode::MODE_DETECT) - return; + if (s_opengl_mode != GLInterfaceMode::MODE_DETECT) + return; - EGLint num_configs; - bool supportsGL = false, supportsGLES2 = false, supportsGLES3 = false; - std::array renderable_types = { - EGL_OPENGL_BIT, - (1 << 6), /* EGL_OPENGL_ES3_BIT_KHR */ - EGL_OPENGL_ES2_BIT, - }; + EGLint num_configs; + bool supportsGL = false, supportsGLES2 = false, supportsGLES3 = false; + std::array renderable_types = { + EGL_OPENGL_BIT, (1 << 6), /* EGL_OPENGL_ES3_BIT_KHR */ + EGL_OPENGL_ES2_BIT, + }; - for (auto renderable_type : renderable_types) - { - // attributes for a visual in RGBA format with at least - // 8 bits per color - int attribs[] = { - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_RENDERABLE_TYPE, renderable_type, - EGL_NONE - }; + for (auto renderable_type : renderable_types) + { + // attributes for a visual in RGBA format with at least + // 8 bits per color + int attribs[] = {EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, EGL_RENDERABLE_TYPE, renderable_type, + EGL_NONE}; - // Get how many configs there are - if (!eglChooseConfig( egl_dpy, attribs, nullptr, 0, &num_configs)) - { - INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config\n"); - continue; - } + // Get how many configs there are + if (!eglChooseConfig(egl_dpy, attribs, nullptr, 0, &num_configs)) + { + INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config\n"); + continue; + } - EGLConfig* config = new EGLConfig[num_configs]; + EGLConfig* config = new EGLConfig[num_configs]; - // Get all the configurations - if (!eglChooseConfig(egl_dpy, attribs, config, num_configs, &num_configs)) - { - INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config\n"); - delete[] config; - continue; - } + // Get all the configurations + if (!eglChooseConfig(egl_dpy, attribs, config, num_configs, &num_configs)) + { + INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config\n"); + delete[] config; + continue; + } - for (int i = 0; i < num_configs; ++i) - { - EGLint attribVal; - bool ret; - ret = eglGetConfigAttrib(egl_dpy, config[i], EGL_RENDERABLE_TYPE, &attribVal); - if (ret) - { - if (attribVal & EGL_OPENGL_BIT) - supportsGL = true; - if (attribVal & (1 << 6)) /* EGL_OPENGL_ES3_BIT_KHR */ - supportsGLES3 = true; - if (attribVal & EGL_OPENGL_ES2_BIT) - supportsGLES2 = true; - } - } - delete[] config; - } + for (int i = 0; i < num_configs; ++i) + { + EGLint attribVal; + bool ret; + ret = eglGetConfigAttrib(egl_dpy, config[i], EGL_RENDERABLE_TYPE, &attribVal); + if (ret) + { + if (attribVal & EGL_OPENGL_BIT) + supportsGL = true; + if (attribVal & (1 << 6)) /* EGL_OPENGL_ES3_BIT_KHR */ + supportsGLES3 = true; + if (attribVal & EGL_OPENGL_ES2_BIT) + supportsGLES2 = true; + } + } + delete[] config; + } - if (supportsGL) - s_opengl_mode = GLInterfaceMode::MODE_OPENGL; - else if (supportsGLES3) - s_opengl_mode = GLInterfaceMode::MODE_OPENGLES3; - else if (supportsGLES2) - s_opengl_mode = GLInterfaceMode::MODE_OPENGLES2; + if (supportsGL) + s_opengl_mode = GLInterfaceMode::MODE_OPENGL; + else if (supportsGLES3) + s_opengl_mode = GLInterfaceMode::MODE_OPENGLES3; + else if (supportsGLES2) + s_opengl_mode = GLInterfaceMode::MODE_OPENGLES2; - if (s_opengl_mode == GLInterfaceMode::MODE_DETECT) // Errored before we found a mode - s_opengl_mode = GLInterfaceMode::MODE_OPENGL; // Fall back to OpenGL + if (s_opengl_mode == GLInterfaceMode::MODE_DETECT) // Errored before we found a mode + s_opengl_mode = GLInterfaceMode::MODE_OPENGL; // Fall back to OpenGL } // Create rendering window. // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() -bool cInterfaceEGL::Create(void *window_handle, bool core) +bool cInterfaceEGL::Create(void* window_handle, bool core) { - EGLint egl_major, egl_minor; - bool supports_core_profile = false; + EGLint egl_major, egl_minor; + bool supports_core_profile = false; - egl_dpy = OpenDisplay(); - m_host_window = (EGLNativeWindowType) window_handle; - m_has_handle = !!window_handle; - m_core = core; + egl_dpy = OpenDisplay(); + m_host_window = (EGLNativeWindowType)window_handle; + m_has_handle = !!window_handle; + m_core = core; - if (!egl_dpy) - { - INFO_LOG(VIDEO, "Error: eglGetDisplay() failed\n"); - return false; - } + if (!egl_dpy) + { + INFO_LOG(VIDEO, "Error: eglGetDisplay() failed\n"); + return false; + } - if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) - { - INFO_LOG(VIDEO, "Error: eglInitialize() failed\n"); - return false; - } + if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) + { + INFO_LOG(VIDEO, "Error: eglInitialize() failed\n"); + return false; + } - /* Detection code */ - EGLint num_configs; + /* Detection code */ + EGLint num_configs; - DetectMode(); + DetectMode(); - // attributes for a visual in RGBA format with at least - // 8 bits per color - int attribs[] = { - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_NONE }; + // attributes for a visual in RGBA format with at least + // 8 bits per color + int attribs[] = {EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_NONE}; - std::vector ctx_attribs; - switch (s_opengl_mode) - { - case GLInterfaceMode::MODE_OPENGL: - attribs[1] = EGL_OPENGL_BIT; - ctx_attribs = { EGL_NONE }; - break; - case GLInterfaceMode::MODE_OPENGLES2: - attribs[1] = EGL_OPENGL_ES2_BIT; - ctx_attribs = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; - break; - case GLInterfaceMode::MODE_OPENGLES3: - attribs[1] = (1 << 6); /* EGL_OPENGL_ES3_BIT_KHR */ - ctx_attribs = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE }; - break; - default: - ERROR_LOG(VIDEO, "Unknown opengl mode set\n"); - return false; - break; - } + std::vector ctx_attribs; + switch (s_opengl_mode) + { + case GLInterfaceMode::MODE_OPENGL: + attribs[1] = EGL_OPENGL_BIT; + ctx_attribs = {EGL_NONE}; + break; + case GLInterfaceMode::MODE_OPENGLES2: + attribs[1] = EGL_OPENGL_ES2_BIT; + ctx_attribs = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; + break; + case GLInterfaceMode::MODE_OPENGLES3: + attribs[1] = (1 << 6); /* EGL_OPENGL_ES3_BIT_KHR */ + ctx_attribs = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE}; + break; + default: + ERROR_LOG(VIDEO, "Unknown opengl mode set\n"); + return false; + break; + } - if (!eglChooseConfig( egl_dpy, attribs, &m_config, 1, &num_configs)) - { - INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config\n"); - return false; - } + if (!eglChooseConfig(egl_dpy, attribs, &m_config, 1, &num_configs)) + { + INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config\n"); + return false; + } - if (s_opengl_mode == GLInterfaceMode::MODE_OPENGL) - eglBindAPI(EGL_OPENGL_API); - else - eglBindAPI(EGL_OPENGL_ES_API); + if (s_opengl_mode == GLInterfaceMode::MODE_OPENGL) + eglBindAPI(EGL_OPENGL_API); + else + eglBindAPI(EGL_OPENGL_ES_API); - std::string tmp; - std::istringstream buffer(eglQueryString(egl_dpy, EGL_EXTENSIONS)); - while (buffer >> tmp) - { - if (tmp == "EGL_KHR_surfaceless_context") - m_supports_surfaceless = true; - else if (tmp == "EGL_KHR_create_context") - supports_core_profile = true; - } + std::string tmp; + std::istringstream buffer(eglQueryString(egl_dpy, EGL_EXTENSIONS)); + while (buffer >> tmp) + { + if (tmp == "EGL_KHR_surfaceless_context") + m_supports_surfaceless = true; + else if (tmp == "EGL_KHR_create_context") + supports_core_profile = true; + } - if (supports_core_profile && core && s_opengl_mode == GLInterfaceMode::MODE_OPENGL) - { - std::array, 7> versions_to_try = - {{ - { 4, 5 }, - { 4, 4 }, - { 4, 3 }, - { 4, 2 }, - { 4, 1 }, - { 4, 0 }, - { 3, 3 }, - }}; + if (supports_core_profile && core && s_opengl_mode == GLInterfaceMode::MODE_OPENGL) + { + std::array, 7> versions_to_try = {{ + {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, + }}; - for (const auto& version : versions_to_try) - { - std::vector core_attribs = - { - EGL_CONTEXT_MAJOR_VERSION_KHR, version.first, - EGL_CONTEXT_MINOR_VERSION_KHR, version.second, - EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, - EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, - EGL_NONE - }; + for (const auto& version : versions_to_try) + { + std::vector core_attribs = {EGL_CONTEXT_MAJOR_VERSION_KHR, + version.first, + EGL_CONTEXT_MINOR_VERSION_KHR, + version.second, + EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, + EGL_CONTEXT_FLAGS_KHR, + EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, + EGL_NONE}; - egl_ctx = eglCreateContext(egl_dpy, m_config, EGL_NO_CONTEXT, &core_attribs[0]); - if (egl_ctx) - break; - } - } + egl_ctx = eglCreateContext(egl_dpy, m_config, EGL_NO_CONTEXT, &core_attribs[0]); + if (egl_ctx) + break; + } + } - if (!egl_ctx) - { - m_core = false; - egl_ctx = eglCreateContext(egl_dpy, m_config, EGL_NO_CONTEXT, &ctx_attribs[0]); - } + if (!egl_ctx) + { + m_core = false; + egl_ctx = eglCreateContext(egl_dpy, m_config, EGL_NO_CONTEXT, &ctx_attribs[0]); + } - if (!egl_ctx) - { - INFO_LOG(VIDEO, "Error: eglCreateContext failed\n"); - return false; - } + if (!egl_ctx) + { + INFO_LOG(VIDEO, "Error: eglCreateContext failed\n"); + return false; + } - if (!CreateWindowSurface()) - { - ERROR_LOG(VIDEO, "Error: CreateWindowSurface failed 0x%04x\n", eglGetError()); - return false; - } - return true; + if (!CreateWindowSurface()) + { + ERROR_LOG(VIDEO, "Error: CreateWindowSurface failed 0x%04x\n", eglGetError()); + return false; + } + return true; } std::unique_ptr cInterfaceEGL::CreateSharedContext() { - std::unique_ptr context = std::make_unique(); - if (!context->Create(this)) - return nullptr; - return context; + std::unique_ptr context = std::make_unique(); + if (!context->Create(this)) + return nullptr; + return context; } bool cInterfaceEGL::Create(cInterfaceBase* main_context) { - cInterfaceEGL* egl_context = static_cast(main_context); + cInterfaceEGL* egl_context = static_cast(main_context); - egl_dpy = egl_context->egl_dpy; - m_core = egl_context->m_core; - m_config = egl_context->m_config; - m_supports_surfaceless = egl_context->m_supports_surfaceless; - m_is_shared = true; - m_has_handle = false; + egl_dpy = egl_context->egl_dpy; + m_core = egl_context->m_core; + m_config = egl_context->m_config; + m_supports_surfaceless = egl_context->m_supports_surfaceless; + m_is_shared = true; + m_has_handle = false; - EGLint ctx_attribs[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE - }; + EGLint ctx_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; - switch (egl_context->GetMode()) - { - case GLInterfaceMode::MODE_OPENGL: - ctx_attribs[0] = EGL_NONE; - break; - case GLInterfaceMode::MODE_OPENGLES2: - ctx_attribs[1] = 2; - break; - case GLInterfaceMode::MODE_OPENGLES3: - ctx_attribs[1] = 3; - break; - default: - INFO_LOG(VIDEO, "Unknown opengl mode set\n"); - return false; - break; - } + switch (egl_context->GetMode()) + { + case GLInterfaceMode::MODE_OPENGL: + ctx_attribs[0] = EGL_NONE; + break; + case GLInterfaceMode::MODE_OPENGLES2: + ctx_attribs[1] = 2; + break; + case GLInterfaceMode::MODE_OPENGLES3: + ctx_attribs[1] = 3; + break; + default: + INFO_LOG(VIDEO, "Unknown opengl mode set\n"); + return false; + break; + } - if (egl_context->GetMode() == GLInterfaceMode::MODE_OPENGL) - eglBindAPI(EGL_OPENGL_API); - else - eglBindAPI(EGL_OPENGL_ES_API); + if (egl_context->GetMode() == GLInterfaceMode::MODE_OPENGL) + eglBindAPI(EGL_OPENGL_API); + else + eglBindAPI(EGL_OPENGL_ES_API); - egl_ctx = eglCreateContext(egl_dpy, m_config, egl_context->egl_ctx, ctx_attribs ); - if (!egl_ctx) - { - INFO_LOG(VIDEO, "Error: eglCreateContext failed 0x%04x\n", eglGetError()); - return false; - } + egl_ctx = eglCreateContext(egl_dpy, m_config, egl_context->egl_ctx, ctx_attribs); + if (!egl_ctx) + { + INFO_LOG(VIDEO, "Error: eglCreateContext failed 0x%04x\n", eglGetError()); + return false; + } - if (!CreateWindowSurface()) - { - ERROR_LOG(VIDEO, "Error: CreateWindowSurface failed 0x%04x\n", eglGetError()); - return false; - } - return true; + if (!CreateWindowSurface()) + { + ERROR_LOG(VIDEO, "Error: CreateWindowSurface failed 0x%04x\n", eglGetError()); + return false; + } + return true; } bool cInterfaceEGL::CreateWindowSurface() { - if (m_has_handle) - { - EGLNativeWindowType native_window = InitializePlatform(m_host_window, m_config); - egl_surf = eglCreateWindowSurface(egl_dpy, m_config, native_window, nullptr); - if (!egl_surf) - { - INFO_LOG(VIDEO, "Error: eglCreateWindowSurface failed\n"); - return false; - } - } - else if (!m_supports_surfaceless) - { - EGLint attrib_list[] = - { - EGL_NONE, - }; - egl_surf = eglCreatePbufferSurface(egl_dpy, m_config, attrib_list); - if (!egl_surf) - { - INFO_LOG(VIDEO, "Error: eglCreatePbufferSurface failed"); - return false; - } - } - else - { - egl_surf = EGL_NO_SURFACE; - } - return true; + if (m_has_handle) + { + EGLNativeWindowType native_window = InitializePlatform(m_host_window, m_config); + egl_surf = eglCreateWindowSurface(egl_dpy, m_config, native_window, nullptr); + if (!egl_surf) + { + INFO_LOG(VIDEO, "Error: eglCreateWindowSurface failed\n"); + return false; + } + } + else if (!m_supports_surfaceless) + { + EGLint attrib_list[] = { + EGL_NONE, + }; + egl_surf = eglCreatePbufferSurface(egl_dpy, m_config, attrib_list); + if (!egl_surf) + { + INFO_LOG(VIDEO, "Error: eglCreatePbufferSurface failed"); + return false; + } + } + else + { + egl_surf = EGL_NO_SURFACE; + } + return true; } void cInterfaceEGL::DestroyWindowSurface() { - if (egl_surf != EGL_NO_SURFACE && !eglDestroySurface(egl_dpy, egl_surf)) - NOTICE_LOG(VIDEO, "Could not destroy window surface."); - egl_surf = EGL_NO_SURFACE; + if (egl_surf != EGL_NO_SURFACE && !eglDestroySurface(egl_dpy, egl_surf)) + NOTICE_LOG(VIDEO, "Could not destroy window surface."); + egl_surf = EGL_NO_SURFACE; } bool cInterfaceEGL::MakeCurrent() { - return eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx); + return eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx); } void cInterfaceEGL::UpdateHandle(void* window_handle) { - m_host_window = (EGLNativeWindowType)window_handle; - m_has_handle = !!window_handle; + m_host_window = (EGLNativeWindowType)window_handle; + m_has_handle = !!window_handle; } void cInterfaceEGL::UpdateSurface() { - ClearCurrent(); - DestroyWindowSurface(); - CreateWindowSurface(); - MakeCurrent(); + ClearCurrent(); + DestroyWindowSurface(); + CreateWindowSurface(); + MakeCurrent(); } bool cInterfaceEGL::ClearCurrent() { - return eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + return eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } // Close backend void cInterfaceEGL::Shutdown() { - ShutdownPlatform(); - if (egl_ctx) - { - if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) - NOTICE_LOG(VIDEO, "Could not release drawing context."); - eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (!eglDestroyContext(egl_dpy, egl_ctx)) - NOTICE_LOG(VIDEO, "Could not destroy drawing context."); - DestroyWindowSurface(); - if (!m_is_shared && !eglTerminate(egl_dpy)) - NOTICE_LOG(VIDEO, "Could not destroy display connection."); - egl_ctx = nullptr; - } + ShutdownPlatform(); + if (egl_ctx) + { + if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) + NOTICE_LOG(VIDEO, "Could not release drawing context."); + eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!eglDestroyContext(egl_dpy, egl_ctx)) + NOTICE_LOG(VIDEO, "Could not destroy drawing context."); + DestroyWindowSurface(); + if (!m_is_shared && !eglTerminate(egl_dpy)) + NOTICE_LOG(VIDEO, "Could not destroy display connection."); + egl_ctx = nullptr; + } } diff --git a/Source/Core/Common/GL/GLInterface/EGL.h b/Source/Core/Common/GL/GLInterface/EGL.h index 05f07aea5c..2352f9b646 100644 --- a/Source/Core/Common/GL/GLInterface/EGL.h +++ b/Source/Core/Common/GL/GLInterface/EGL.h @@ -4,44 +4,46 @@ #pragma once -#include #include #include +#include #include "Common/GL/GLInterfaceBase.h" class cInterfaceEGL : public cInterfaceBase { private: - EGLConfig m_config; - bool m_has_handle; - EGLNativeWindowType m_host_window; - bool m_supports_surfaceless = false; + EGLConfig m_config; + bool m_has_handle; + EGLNativeWindowType m_host_window; + bool m_supports_surfaceless = false; - bool CreateWindowSurface(); - void DestroyWindowSurface(); + bool CreateWindowSurface(); + void DestroyWindowSurface(); protected: - void DetectMode(); - EGLSurface egl_surf; - EGLContext egl_ctx; - EGLDisplay egl_dpy; - - virtual EGLDisplay OpenDisplay() { return eglGetDisplay(EGL_DEFAULT_DISPLAY); } - virtual EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) { return (EGLNativeWindowType)EGL_DEFAULT_DISPLAY; } - virtual void ShutdownPlatform() {} + void DetectMode(); + EGLSurface egl_surf; + EGLContext egl_ctx; + EGLDisplay egl_dpy; + virtual EGLDisplay OpenDisplay() { return eglGetDisplay(EGL_DEFAULT_DISPLAY); } + virtual EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) + { + return (EGLNativeWindowType)EGL_DEFAULT_DISPLAY; + } + virtual void ShutdownPlatform() {} public: - void Swap() override; - void SwapInterval(int interval) override; - void SetMode(GLInterfaceMode mode) override { s_opengl_mode = mode; } - void* GetFuncAddress(const std::string& name) override; - bool Create(void* window_handle, bool core) override; - bool Create(cInterfaceBase* main_context) override; - bool MakeCurrent() override; - bool ClearCurrent() override; - void Shutdown() override; - void UpdateHandle(void* window_handle) override; - void UpdateSurface() override; - std::unique_ptr CreateSharedContext() override; + void Swap() override; + void SwapInterval(int interval) override; + void SetMode(GLInterfaceMode mode) override { s_opengl_mode = mode; } + void* GetFuncAddress(const std::string& name) override; + bool Create(void* window_handle, bool core) override; + bool Create(cInterfaceBase* main_context) override; + bool MakeCurrent() override; + bool ClearCurrent() override; + void Shutdown() override; + void UpdateHandle(void* window_handle) override; + void UpdateSurface() override; + std::unique_ptr CreateSharedContext() override; }; diff --git a/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp b/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp index c2204d3ec7..44fb41f1d2 100644 --- a/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp @@ -6,23 +6,23 @@ EGLDisplay cInterfaceEGLAndroid::OpenDisplay() { - return eglGetDisplay(EGL_DEFAULT_DISPLAY); + return eglGetDisplay(EGL_DEFAULT_DISPLAY); } -EGLNativeWindowType cInterfaceEGLAndroid::InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) +EGLNativeWindowType cInterfaceEGLAndroid::InitializePlatform(EGLNativeWindowType host_window, + EGLConfig config) { - EGLint format; - eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &format); - ANativeWindow_setBuffersGeometry(host_window, 0, 0, format); + EGLint format; + eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &format); + ANativeWindow_setBuffersGeometry(host_window, 0, 0, format); - const int width = ANativeWindow_getWidth(host_window); - const int height = ANativeWindow_getHeight(host_window); - GLInterface->SetBackBufferDimensions(width, height); + const int width = ANativeWindow_getWidth(host_window); + const int height = ANativeWindow_getHeight(host_window); + GLInterface->SetBackBufferDimensions(width, height); - return host_window; + return host_window; } void cInterfaceEGLAndroid::ShutdownPlatform() { } - diff --git a/Source/Core/Common/GL/GLInterface/EGLAndroid.h b/Source/Core/Common/GL/GLInterface/EGLAndroid.h index 9347027b74..8a43f261c9 100644 --- a/Source/Core/Common/GL/GLInterface/EGLAndroid.h +++ b/Source/Core/Common/GL/GLInterface/EGLAndroid.h @@ -10,7 +10,8 @@ class cInterfaceEGLAndroid : public cInterfaceEGL { protected: - EGLDisplay OpenDisplay() override; - EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) override; - void ShutdownPlatform() override; + EGLDisplay OpenDisplay() override; + EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, + EGLConfig config) override; + void ShutdownPlatform() override; }; diff --git a/Source/Core/Common/GL/GLInterface/EGLX11.cpp b/Source/Core/Common/GL/GLInterface/EGLX11.cpp index e2e5d7b51b..432f0aa601 100644 --- a/Source/Core/Common/GL/GLInterface/EGLX11.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLX11.cpp @@ -7,39 +7,39 @@ EGLDisplay cInterfaceEGLX11::OpenDisplay() { - dpy = XOpenDisplay(nullptr); - XWindow.Initialize(dpy); - return eglGetDisplay(dpy); + dpy = XOpenDisplay(nullptr); + XWindow.Initialize(dpy); + return eglGetDisplay(dpy); } -EGLNativeWindowType cInterfaceEGLX11::InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) +EGLNativeWindowType cInterfaceEGLX11::InitializePlatform(EGLNativeWindowType host_window, + EGLConfig config) { - EGLint vid; - eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid); + EGLint vid; + eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid); - XVisualInfo visTemplate; - visTemplate.visualid = vid; + XVisualInfo visTemplate; + visTemplate.visualid = vid; - XVisualInfo *vi; - int nVisuals; - vi = XGetVisualInfo(dpy, VisualIDMask, &visTemplate, &nVisuals); + XVisualInfo* vi; + int nVisuals; + vi = XGetVisualInfo(dpy, VisualIDMask, &visTemplate, &nVisuals); - XWindowAttributes attribs; - if (!XGetWindowAttributes(dpy, (Window)host_window, &attribs)) - { - ERROR_LOG(VIDEO, "Window attribute retrieval failed"); - return 0; - } + XWindowAttributes attribs; + if (!XGetWindowAttributes(dpy, (Window)host_window, &attribs)) + { + ERROR_LOG(VIDEO, "Window attribute retrieval failed"); + return 0; + } - s_backbuffer_width = attribs.width; - s_backbuffer_height = attribs.height; + s_backbuffer_width = attribs.width; + s_backbuffer_height = attribs.height; - return (EGLNativeWindowType) XWindow.CreateXWindow((Window) host_window, vi); + return (EGLNativeWindowType)XWindow.CreateXWindow((Window)host_window, vi); } void cInterfaceEGLX11::ShutdownPlatform() { - XWindow.DestroyXWindow(); - XCloseDisplay(dpy); + XWindow.DestroyXWindow(); + XCloseDisplay(dpy); } - diff --git a/Source/Core/Common/GL/GLInterface/EGLX11.h b/Source/Core/Common/GL/GLInterface/EGLX11.h index 58841fa7f9..dab5a38d8e 100644 --- a/Source/Core/Common/GL/GLInterface/EGLX11.h +++ b/Source/Core/Common/GL/GLInterface/EGLX11.h @@ -12,10 +12,12 @@ class cInterfaceEGLX11 : public cInterfaceEGL { private: - cX11Window XWindow; - Display *dpy; + cX11Window XWindow; + Display* dpy; + protected: - EGLDisplay OpenDisplay() override; - EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) override; - void ShutdownPlatform() override; + EGLDisplay OpenDisplay() override; + EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, + EGLConfig config) override; + void ShutdownPlatform() override; }; diff --git a/Source/Core/Common/GL/GLInterface/GLInterface.cpp b/Source/Core/Common/GL/GLInterface/GLInterface.cpp index c7f2169c5a..e134544311 100644 --- a/Source/Core/Common/GL/GLInterface/GLInterface.cpp +++ b/Source/Core/Common/GL/GLInterface/GLInterface.cpp @@ -26,21 +26,21 @@ std::unique_ptr HostGL_CreateGLInterface() { - #if defined(__APPLE__) - return std::make_unique(); - #elif defined(_WIN32) - return std::make_unique(); - #elif defined(USE_EGL) && defined(USE_HEADLESS) - return std::make_unique(); - #elif defined(HAVE_X11) && HAVE_X11 - #if defined(USE_EGL) && USE_EGL - return std::make_unique(); - #else - return std::make_unique(); - #endif - #elif ANDROID - return std::make_unique(); - #else - return nullptr; - #endif +#if defined(__APPLE__) + return std::make_unique(); +#elif defined(_WIN32) + return std::make_unique(); +#elif defined(USE_EGL) && defined(USE_HEADLESS) + return std::make_unique(); +#elif defined(HAVE_X11) && HAVE_X11 +#if defined(USE_EGL) && USE_EGL + return std::make_unique(); +#else + return std::make_unique(); +#endif +#elif ANDROID + return std::make_unique(); +#else + return nullptr; +#endif } diff --git a/Source/Core/Common/GL/GLInterface/GLX.cpp b/Source/Core/Common/GL/GLInterface/GLX.cpp index 8ac73b5fd4..d3550c688f 100644 --- a/Source/Core/Common/GL/GLInterface/GLX.cpp +++ b/Source/Core/Common/GL/GLInterface/GLX.cpp @@ -7,191 +7,195 @@ #include "Common/GL/GLInterface/GLX.h" #include "Common/Logging/Log.h" -#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 -typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSPROC)(Display*, GLXFBConfig, GLXContext, Bool, const int*); -typedef int ( * PFNGLXSWAPINTERVALSGIPROC) (int interval); +typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSPROC)(Display*, GLXFBConfig, GLXContext, Bool, + const int*); +typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int interval); static PFNGLXCREATECONTEXTATTRIBSPROC glXCreateContextAttribs = nullptr; static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr; static bool s_glxError; -static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) +static int ctxErrorHandler(Display* dpy, XErrorEvent* ev) { - s_glxError = true; - return 0; + s_glxError = true; + return 0; } void cInterfaceGLX::SwapInterval(int Interval) { - if (glXSwapIntervalSGI) - glXSwapIntervalSGI(Interval); - else - ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate)."); + if (glXSwapIntervalSGI) + glXSwapIntervalSGI(Interval); + else + ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate)."); } void* cInterfaceGLX::GetFuncAddress(const std::string& name) { - return (void*)glXGetProcAddress((const GLubyte*)name.c_str()); + return (void*)glXGetProcAddress((const GLubyte*)name.c_str()); } void cInterfaceGLX::Swap() { - glXSwapBuffers(dpy, win); + glXSwapBuffers(dpy, win); } // Create rendering window. // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() -bool cInterfaceGLX::Create(void *window_handle, bool core) +bool cInterfaceGLX::Create(void* window_handle, bool core) { - dpy = XOpenDisplay(nullptr); - int screen = DefaultScreen(dpy); + dpy = XOpenDisplay(nullptr); + int screen = DefaultScreen(dpy); - // checking glx version - int glxMajorVersion, glxMinorVersion; - glXQueryVersion(dpy, &glxMajorVersion, &glxMinorVersion); - if (glxMajorVersion < 1 || (glxMajorVersion == 1 && glxMinorVersion < 4)) - { - ERROR_LOG(VIDEO, "glX-Version %d.%d detected, but need at least 1.4", - glxMajorVersion, glxMinorVersion); - return false; - } + // checking glx version + int glxMajorVersion, glxMinorVersion; + glXQueryVersion(dpy, &glxMajorVersion, &glxMinorVersion); + if (glxMajorVersion < 1 || (glxMajorVersion == 1 && glxMinorVersion < 4)) + { + ERROR_LOG(VIDEO, "glX-Version %d.%d detected, but need at least 1.4", glxMajorVersion, + glxMinorVersion); + return false; + } - // loading core context creation function - glXCreateContextAttribs = (PFNGLXCREATECONTEXTATTRIBSPROC)GetFuncAddress("glXCreateContextAttribsARB"); - if (!glXCreateContextAttribs) - { - ERROR_LOG(VIDEO, "glXCreateContextAttribsARB not found, do you support GLX_ARB_create_context?"); - return false; - } + // loading core context creation function + glXCreateContextAttribs = + (PFNGLXCREATECONTEXTATTRIBSPROC)GetFuncAddress("glXCreateContextAttribsARB"); + if (!glXCreateContextAttribs) + { + ERROR_LOG(VIDEO, + "glXCreateContextAttribsARB not found, do you support GLX_ARB_create_context?"); + return false; + } - // choosing framebuffer - int visual_attribs[] = - { - GLX_X_RENDERABLE , True, - GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, - GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR, - GLX_RED_SIZE , 8, - GLX_GREEN_SIZE , 8, - GLX_BLUE_SIZE , 8, - GLX_DEPTH_SIZE , 0, - GLX_STENCIL_SIZE , 0, - GLX_DOUBLEBUFFER , True, - None - }; - int fbcount = 0; - GLXFBConfig* fbc = glXChooseFBConfig(dpy, screen, visual_attribs, &fbcount); - if (!fbc || !fbcount) - { - ERROR_LOG(VIDEO, "Failed to retrieve a framebuffer config"); - return false; - } - fbconfig = *fbc; - XFree(fbc); + // choosing framebuffer + int visual_attribs[] = {GLX_X_RENDERABLE, + True, + GLX_DRAWABLE_TYPE, + GLX_WINDOW_BIT, + GLX_X_VISUAL_TYPE, + GLX_TRUE_COLOR, + GLX_RED_SIZE, + 8, + GLX_GREEN_SIZE, + 8, + GLX_BLUE_SIZE, + 8, + GLX_DEPTH_SIZE, + 0, + GLX_STENCIL_SIZE, + 0, + GLX_DOUBLEBUFFER, + True, + None}; + int fbcount = 0; + GLXFBConfig* fbc = glXChooseFBConfig(dpy, screen, visual_attribs, &fbcount); + if (!fbc || !fbcount) + { + ERROR_LOG(VIDEO, "Failed to retrieve a framebuffer config"); + return false; + } + fbconfig = *fbc; + XFree(fbc); - // Get an appropriate visual - XVisualInfo* vi = glXGetVisualFromFBConfig(dpy, fbconfig); + // Get an appropriate visual + XVisualInfo* vi = glXGetVisualFromFBConfig(dpy, fbconfig); - s_glxError = false; - XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler); + s_glxError = false; + XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler); - // Create a GLX context. - // We try to get a 4.0 core profile, else we try 3.3, else try it with anything we get. - int context_attribs[] = - { - GLX_CONTEXT_MAJOR_VERSION_ARB, 4, - GLX_CONTEXT_MINOR_VERSION_ARB, 0, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, - None - }; - ctx = nullptr; - if (core) - { - ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs); - XSync(dpy, False); - } - if (core && (!ctx || s_glxError)) - { - int context_attribs_33[] = - { - GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 3, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, - None - }; - s_glxError = false; - ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs_33); - XSync(dpy, False); + // Create a GLX context. + // We try to get a 4.0 core profile, else we try 3.3, else try it with anything we get. + int context_attribs[] = {GLX_CONTEXT_MAJOR_VERSION_ARB, + 4, + GLX_CONTEXT_MINOR_VERSION_ARB, + 0, + GLX_CONTEXT_PROFILE_MASK_ARB, + GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + GLX_CONTEXT_FLAGS_ARB, + GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + None}; + ctx = nullptr; + if (core) + { + ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs); + XSync(dpy, False); + } + if (core && (!ctx || s_glxError)) + { + int context_attribs_33[] = {GLX_CONTEXT_MAJOR_VERSION_ARB, + 3, + GLX_CONTEXT_MINOR_VERSION_ARB, + 3, + GLX_CONTEXT_PROFILE_MASK_ARB, + GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + GLX_CONTEXT_FLAGS_ARB, + GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + None}; + s_glxError = false; + ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs_33); + XSync(dpy, False); + } + if (!ctx || s_glxError) + { + int context_attribs_legacy[] = {GLX_CONTEXT_MAJOR_VERSION_ARB, 1, GLX_CONTEXT_MINOR_VERSION_ARB, + 0, None}; + s_glxError = false; + ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs_legacy); + XSync(dpy, False); + } + if (!ctx || s_glxError) + { + ERROR_LOG(VIDEO, "Unable to create GL context."); + return false; + } + XSetErrorHandler(oldHandler); - } - if (!ctx || s_glxError) - { - int context_attribs_legacy[] = - { - GLX_CONTEXT_MAJOR_VERSION_ARB, 1, - GLX_CONTEXT_MINOR_VERSION_ARB, 0, - None - }; - s_glxError = false; - ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs_legacy); - XSync(dpy, False); + XWindow.Initialize(dpy); - } - if (!ctx || s_glxError) - { - ERROR_LOG(VIDEO, "Unable to create GL context."); - return false; - } - XSetErrorHandler(oldHandler); + Window parent = (Window)window_handle; - XWindow.Initialize(dpy); + XWindowAttributes attribs; + if (!XGetWindowAttributes(dpy, parent, &attribs)) + { + ERROR_LOG(VIDEO, "Window attribute retrieval failed"); + return false; + } - Window parent = (Window)window_handle; + s_backbuffer_width = attribs.width; + s_backbuffer_height = attribs.height; - XWindowAttributes attribs; - if (!XGetWindowAttributes(dpy, parent, &attribs)) - { - ERROR_LOG(VIDEO, "Window attribute retrieval failed"); - return false; - } + win = XWindow.CreateXWindow(parent, vi); + XFree(vi); - s_backbuffer_width = attribs.width; - s_backbuffer_height = attribs.height; - - win = XWindow.CreateXWindow(parent, vi); - XFree(vi); - - return true; + return true; } bool cInterfaceGLX::MakeCurrent() { - bool success = glXMakeCurrent(dpy, win, ctx); - if (success) - { - // load this function based on the current bound context - glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)GLInterface->GetFuncAddress("glXSwapIntervalSGI"); - } - return success; + bool success = glXMakeCurrent(dpy, win, ctx); + if (success) + { + // load this function based on the current bound context + glXSwapIntervalSGI = + (PFNGLXSWAPINTERVALSGIPROC)GLInterface->GetFuncAddress("glXSwapIntervalSGI"); + } + return success; } bool cInterfaceGLX::ClearCurrent() { - return glXMakeCurrent(dpy, None, nullptr); + return glXMakeCurrent(dpy, None, nullptr); } - // Close backend void cInterfaceGLX::Shutdown() { - XWindow.DestroyXWindow(); - if (ctx) - { - glXDestroyContext(dpy, ctx); - XCloseDisplay(dpy); - ctx = nullptr; - } + XWindow.DestroyXWindow(); + if (ctx) + { + glXDestroyContext(dpy, ctx); + XCloseDisplay(dpy); + ctx = nullptr; + } } - diff --git a/Source/Core/Common/GL/GLInterface/GLX.h b/Source/Core/Common/GL/GLInterface/GLX.h index 35deb33b6a..20feba27e0 100644 --- a/Source/Core/Common/GL/GLInterface/GLX.h +++ b/Source/Core/Common/GL/GLInterface/GLX.h @@ -4,27 +4,28 @@ #pragma once -#include #include +#include -#include "Common/GL/GLInterfaceBase.h" #include "Common/GL/GLInterface/X11_Util.h" +#include "Common/GL/GLInterfaceBase.h" class cInterfaceGLX : public cInterfaceBase { private: - cX11Window XWindow; - Display *dpy; - Window win; - GLXContext ctx; - GLXFBConfig fbconfig; + cX11Window XWindow; + Display* dpy; + Window win; + GLXContext ctx; + GLXFBConfig fbconfig; + public: - friend class cX11Window; - void SwapInterval(int Interval) override; - void Swap() override; - void* GetFuncAddress(const std::string& name) override; - bool Create(void *window_handle, bool core) override; - bool MakeCurrent() override; - bool ClearCurrent() override; - void Shutdown() override; + friend class cX11Window; + void SwapInterval(int Interval) override; + void Swap() override; + void* GetFuncAddress(const std::string& name) override; + bool Create(void* window_handle, bool core) override; + bool MakeCurrent() override; + bool ClearCurrent() override; + void Shutdown() override; }; diff --git a/Source/Core/Common/GL/GLInterface/WGL.cpp b/Source/Core/Common/GL/GLInterface/WGL.cpp index c0a1266804..ea13b60e36 100644 --- a/Source/Core/Common/GL/GLInterface/WGL.cpp +++ b/Source/Core/Common/GL/GLInterface/WGL.cpp @@ -5,174 +5,174 @@ #include #include -#include "Common/MsgHandler.h" #include "Common/GL/GLInterface/WGL.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" -static HDC hDC = nullptr; // Private GDI Device Context -static HGLRC hRC = nullptr; // Permanent Rendering Context -static HINSTANCE dllHandle = nullptr; // Handle to OpenGL32.dll +static HDC hDC = nullptr; // Private GDI Device Context +static HGLRC hRC = nullptr; // Permanent Rendering Context +static HINSTANCE dllHandle = nullptr; // Handle to OpenGL32.dll // typedef from wglext.h -typedef BOOL(WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); +typedef BOOL(WINAPI* PFNWGLSWAPINTERVALEXTPROC)(int interval); static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr; void cInterfaceWGL::SwapInterval(int Interval) { - if (wglSwapIntervalEXT) - wglSwapIntervalEXT(Interval); - else - ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate)."); + if (wglSwapIntervalEXT) + wglSwapIntervalEXT(Interval); + else + ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate)."); } void cInterfaceWGL::Swap() { - SwapBuffers(hDC); + SwapBuffers(hDC); } void* cInterfaceWGL::GetFuncAddress(const std::string& name) { - void* func = (void*)wglGetProcAddress((LPCSTR)name.c_str()); - if (func == nullptr) - func = (void*)GetProcAddress(dllHandle, (LPCSTR)name.c_str()); - return func; + void* func = (void*)wglGetProcAddress((LPCSTR)name.c_str()); + if (func == nullptr) + func = (void*)GetProcAddress(dllHandle, (LPCSTR)name.c_str()); + return func; } // Draw messages on top of the screen bool cInterfaceWGL::PeekMessages() { - // TODO: peekmessage - MSG msg; - while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - return FALSE; - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return TRUE; + // TODO: peekmessage + MSG msg; + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + return FALSE; + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return TRUE; } // Create rendering window. // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() -bool cInterfaceWGL::Create(void *window_handle, bool core) +bool cInterfaceWGL::Create(void* window_handle, bool core) { - if (window_handle == nullptr) - return false; + if (window_handle == nullptr) + return false; - HWND window_handle_reified = reinterpret_cast(window_handle); - RECT window_rect = {0}; + HWND window_handle_reified = reinterpret_cast(window_handle); + RECT window_rect = {0}; - if (!GetClientRect(window_handle_reified, &window_rect)) - return false; + if (!GetClientRect(window_handle_reified, &window_rect)) + return false; - // Control window size and picture scaling - int twidth = (window_rect.right - window_rect.left); - int theight = (window_rect.bottom - window_rect.top); - s_backbuffer_width = twidth; - s_backbuffer_height = theight; + // Control window size and picture scaling + int twidth = (window_rect.right - window_rect.left); + int theight = (window_rect.bottom - window_rect.top); + s_backbuffer_width = twidth; + s_backbuffer_height = theight; - m_window_handle = window_handle_reified; + m_window_handle = window_handle_reified; - dllHandle = LoadLibrary(TEXT("OpenGL32.dll")); + dllHandle = LoadLibrary(TEXT("OpenGL32.dll")); - PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be - { - sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor - 1, // Version Number - PFD_DRAW_TO_WINDOW | // Format Must Support Window - PFD_SUPPORT_OPENGL | // Format Must Support OpenGL - PFD_DOUBLEBUFFER, // Must Support Double Buffering - PFD_TYPE_RGBA, // Request An RGBA Format - 32, // Select Our Color Depth - 0, 0, 0, 0, 0, 0, // Color Bits Ignored - 0, // 8bit Alpha Buffer - 0, // Shift Bit Ignored - 0, // No Accumulation Buffer - 0, 0, 0, 0, // Accumulation Bits Ignored - 0, // 0Bit Z-Buffer (Depth Buffer) - 0, // 0bit Stencil Buffer - 0, // No Auxiliary Buffer - PFD_MAIN_PLANE, // Main Drawing Layer - 0, // Reserved - 0, 0, 0 // Layer Masks Ignored - }; + PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be + { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, // Version Number + PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + PFD_DOUBLEBUFFER, // Must Support Double Buffering + PFD_TYPE_RGBA, // Request An RGBA Format + 32, // Select Our Color Depth + 0, + 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // 8bit Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + 0, // 0Bit Z-Buffer (Depth Buffer) + 0, // 0bit Stencil Buffer + 0, // No Auxiliary Buffer + PFD_MAIN_PLANE, // Main Drawing Layer + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; - int PixelFormat; // Holds The Results After Searching For A Match + int PixelFormat; // Holds The Results After Searching For A Match - if (!(hDC = GetDC(window_handle_reified))) - { - PanicAlert("(1) Can't create an OpenGL Device context. Fail."); - return false; - } + if (!(hDC = GetDC(window_handle_reified))) + { + PanicAlert("(1) Can't create an OpenGL Device context. Fail."); + return false; + } - if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) - { - PanicAlert("(2) Can't find a suitable PixelFormat."); - return false; - } + if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) + { + PanicAlert("(2) Can't find a suitable PixelFormat."); + return false; + } - if (!SetPixelFormat(hDC, PixelFormat, &pfd)) - { - PanicAlert("(3) Can't set the PixelFormat."); - return false; - } + if (!SetPixelFormat(hDC, PixelFormat, &pfd)) + { + PanicAlert("(3) Can't set the PixelFormat."); + return false; + } - if (!(hRC = wglCreateContext(hDC))) - { - PanicAlert("(4) Can't create an OpenGL rendering context."); - return false; - } + if (!(hRC = wglCreateContext(hDC))) + { + PanicAlert("(4) Can't create an OpenGL rendering context."); + return false; + } - return true; + return true; } bool cInterfaceWGL::MakeCurrent() { - bool success = wglMakeCurrent(hDC, hRC) ? true : false; - if (success) - { - // Grab the swap interval function pointer - wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)GLInterface->GetFuncAddress("wglSwapIntervalEXT"); - } - return success; + bool success = wglMakeCurrent(hDC, hRC) ? true : false; + if (success) + { + // Grab the swap interval function pointer + wglSwapIntervalEXT = + (PFNWGLSWAPINTERVALEXTPROC)GLInterface->GetFuncAddress("wglSwapIntervalEXT"); + } + return success; } bool cInterfaceWGL::ClearCurrent() { - return wglMakeCurrent(hDC, nullptr) ? true : false; + return wglMakeCurrent(hDC, nullptr) ? true : false; } // Update window width, size and etc. Called from Render.cpp void cInterfaceWGL::Update() { - RECT rcWindow; - GetClientRect(m_window_handle, &rcWindow); + RECT rcWindow; + GetClientRect(m_window_handle, &rcWindow); - // Get the new window width and height - s_backbuffer_width = (rcWindow.right - rcWindow.left); - s_backbuffer_height = (rcWindow.bottom - rcWindow.top); + // Get the new window width and height + s_backbuffer_width = (rcWindow.right - rcWindow.left); + s_backbuffer_height = (rcWindow.bottom - rcWindow.top); } // Close backend void cInterfaceWGL::Shutdown() { - if (hRC) - { - if (!wglMakeCurrent(nullptr, nullptr)) - NOTICE_LOG(VIDEO, "Could not release drawing context."); + if (hRC) + { + if (!wglMakeCurrent(nullptr, nullptr)) + NOTICE_LOG(VIDEO, "Could not release drawing context."); - if (!wglDeleteContext(hRC)) - ERROR_LOG(VIDEO, "Attempt to release rendering context failed."); + if (!wglDeleteContext(hRC)) + ERROR_LOG(VIDEO, "Attempt to release rendering context failed."); - hRC = nullptr; - } + hRC = nullptr; + } - if (hDC && !ReleaseDC(m_window_handle, hDC)) - { - ERROR_LOG(VIDEO, "Attempt to release device context failed."); - hDC = nullptr; - } - FreeLibrary(dllHandle); + if (hDC && !ReleaseDC(m_window_handle, hDC)) + { + ERROR_LOG(VIDEO, "Attempt to release device context failed."); + hDC = nullptr; + } + FreeLibrary(dllHandle); } - - diff --git a/Source/Core/Common/GL/GLInterface/WGL.h b/Source/Core/Common/GL/GLInterface/WGL.h index b82a521b16..c71e403884 100644 --- a/Source/Core/Common/GL/GLInterface/WGL.h +++ b/Source/Core/Common/GL/GLInterface/WGL.h @@ -10,17 +10,17 @@ class cInterfaceWGL : public cInterfaceBase { public: - void SwapInterval(int interval) override; - void Swap() override; - void* GetFuncAddress(const std::string& name) override; - bool Create(void* window_handle, bool core) override; - bool MakeCurrent() override; - bool ClearCurrent() override; - void Shutdown() override; + void SwapInterval(int interval) override; + void Swap() override; + void* GetFuncAddress(const std::string& name) override; + bool Create(void* window_handle, bool core) override; + bool MakeCurrent() override; + bool ClearCurrent() override; + void Shutdown() override; - void Update() override; - bool PeekMessages() override; + void Update() override; + bool PeekMessages() override; private: - HWND m_window_handle = nullptr; + HWND m_window_handle = nullptr; }; diff --git a/Source/Core/Common/GL/GLInterface/X11_Util.cpp b/Source/Core/Common/GL/GLInterface/X11_Util.cpp index 1a15d100ee..ed884a9ffd 100644 --- a/Source/Core/Common/GL/GLInterface/X11_Util.cpp +++ b/Source/Core/Common/GL/GLInterface/X11_Util.cpp @@ -2,73 +2,71 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Common/Thread.h" -#include "Common/GL/GLInterfaceBase.h" #include "Common/GL/GLInterface/X11_Util.h" +#include "Common/GL/GLInterfaceBase.h" #include "Common/Logging/Log.h" +#include "Common/Thread.h" -void cX11Window::Initialize(Display *_dpy) +void cX11Window::Initialize(Display* _dpy) { - dpy = _dpy; + dpy = _dpy; } -Window cX11Window::CreateXWindow(Window parent, XVisualInfo *vi) +Window cX11Window::CreateXWindow(Window parent, XVisualInfo* vi) { - XSetWindowAttributes attr; + XSetWindowAttributes attr; - colormap = XCreateColormap(dpy, parent, vi->visual, AllocNone); + colormap = XCreateColormap(dpy, parent, vi->visual, AllocNone); - // Setup window attributes - attr.colormap = colormap; + // Setup window attributes + attr.colormap = colormap; - XWindowAttributes attribs; - if (!XGetWindowAttributes(dpy, parent, &attribs)) - { - ERROR_LOG(VIDEO, "Window attribute retrieval failed"); - return 0; - } + XWindowAttributes attribs; + if (!XGetWindowAttributes(dpy, parent, &attribs)) + { + ERROR_LOG(VIDEO, "Window attribute retrieval failed"); + return 0; + } - // Create the window - win = XCreateWindow(dpy, parent, - 0, 0, attribs.width, attribs.height, 0, - vi->depth, InputOutput, vi->visual, - CWColormap, &attr); - XSelectInput(dpy, parent, StructureNotifyMask); - XMapWindow(dpy, win); - XSync(dpy, True); + // Create the window + win = XCreateWindow(dpy, parent, 0, 0, attribs.width, attribs.height, 0, vi->depth, InputOutput, + vi->visual, CWColormap, &attr); + XSelectInput(dpy, parent, StructureNotifyMask); + XMapWindow(dpy, win); + XSync(dpy, True); - xEventThread = std::thread(&cX11Window::XEventThread, this); + xEventThread = std::thread(&cX11Window::XEventThread, this); - return win; + return win; } void cX11Window::DestroyXWindow(void) { - XUnmapWindow(dpy, win); - win = 0; - if (xEventThread.joinable()) - xEventThread.join(); - XFreeColormap(dpy, colormap); + XUnmapWindow(dpy, win); + win = 0; + if (xEventThread.joinable()) + xEventThread.join(); + XFreeColormap(dpy, colormap); } void cX11Window::XEventThread() { - while (win) - { - XEvent event; - for (int num_events = XPending(dpy); num_events > 0; num_events--) - { - XNextEvent(dpy, &event); - switch (event.type) - { - case ConfigureNotify: - XResizeWindow(dpy, win, event.xconfigure.width, event.xconfigure.height); - GLInterface->SetBackBufferDimensions(event.xconfigure.width, event.xconfigure.height); - break; - default: - break; - } - } - Common::SleepCurrentThread(20); - } + while (win) + { + XEvent event; + for (int num_events = XPending(dpy); num_events > 0; num_events--) + { + XNextEvent(dpy, &event); + switch (event.type) + { + case ConfigureNotify: + XResizeWindow(dpy, win, event.xconfigure.width, event.xconfigure.height); + GLInterface->SetBackBufferDimensions(event.xconfigure.width, event.xconfigure.height); + break; + default: + break; + } + } + Common::SleepCurrentThread(20); + } } diff --git a/Source/Core/Common/GL/GLInterface/X11_Util.h b/Source/Core/Common/GL/GLInterface/X11_Util.h index 86a5fb1d93..e79a6fe1df 100644 --- a/Source/Core/Common/GL/GLInterface/X11_Util.h +++ b/Source/Core/Common/GL/GLInterface/X11_Util.h @@ -4,23 +4,24 @@ #pragma once -#include -#include -#include #include #include +#include +#include +#include class cX11Window { private: - void XEventThread(); - std::thread xEventThread; - Colormap colormap; -public: - void Initialize(Display *dpy); - Window CreateXWindow(Window parent, XVisualInfo *vi); - void DestroyXWindow(); + void XEventThread(); + std::thread xEventThread; + Colormap colormap; - Display *dpy; - Window win; +public: + void Initialize(Display* dpy); + Window CreateXWindow(Window parent, XVisualInfo* vi); + void DestroyXWindow(); + + Display* dpy; + Window win; }; diff --git a/Source/Core/Common/GL/GLInterfaceBase.h b/Source/Core/Common/GL/GLInterfaceBase.h index 2cc022faee..b19f5698bc 100644 --- a/Source/Core/Common/GL/GLInterfaceBase.h +++ b/Source/Core/Common/GL/GLInterfaceBase.h @@ -11,43 +11,47 @@ enum class GLInterfaceMode { - MODE_DETECT, - MODE_OPENGL, - MODE_OPENGLES2, - MODE_OPENGLES3, + MODE_DETECT, + MODE_OPENGL, + MODE_OPENGLES2, + MODE_OPENGLES3, }; class cInterfaceBase { protected: - // Window dimensions. - u32 s_backbuffer_width = 0; - u32 s_backbuffer_height = 0; - bool m_core = false; - bool m_is_shared = false; + // Window dimensions. + u32 s_backbuffer_width = 0; + u32 s_backbuffer_height = 0; + bool m_core = false; + bool m_is_shared = false; + + GLInterfaceMode s_opengl_mode = GLInterfaceMode::MODE_DETECT; - GLInterfaceMode s_opengl_mode = GLInterfaceMode::MODE_DETECT; public: - virtual ~cInterfaceBase() {} - virtual void Swap() {} - virtual void SetMode(GLInterfaceMode mode) { s_opengl_mode = GLInterfaceMode::MODE_OPENGL; } - virtual GLInterfaceMode GetMode() { return s_opengl_mode; } - virtual void* GetFuncAddress(const std::string& name) { return nullptr; } - virtual bool Create(void *window_handle, bool core = true) { return true; } - virtual bool Create(cInterfaceBase* main_context) { return true; } - virtual bool MakeCurrent() { return true; } - virtual bool ClearCurrent() { return true; } - virtual void Shutdown() {} - - virtual void SwapInterval(int Interval) { } - virtual u32 GetBackBufferWidth() { return s_backbuffer_width; } - virtual u32 GetBackBufferHeight() { return s_backbuffer_height; } - virtual void SetBackBufferDimensions(u32 W, u32 H) {s_backbuffer_width = W; s_backbuffer_height = H; } - virtual void Update() { } - virtual bool PeekMessages() { return false; } - virtual void UpdateHandle(void* window_handle) {} - virtual void UpdateSurface() {} - virtual std::unique_ptr CreateSharedContext() { return nullptr; } + virtual ~cInterfaceBase() {} + virtual void Swap() {} + virtual void SetMode(GLInterfaceMode mode) { s_opengl_mode = GLInterfaceMode::MODE_OPENGL; } + virtual GLInterfaceMode GetMode() { return s_opengl_mode; } + virtual void* GetFuncAddress(const std::string& name) { return nullptr; } + virtual bool Create(void* window_handle, bool core = true) { return true; } + virtual bool Create(cInterfaceBase* main_context) { return true; } + virtual bool MakeCurrent() { return true; } + virtual bool ClearCurrent() { return true; } + virtual void Shutdown() {} + virtual void SwapInterval(int Interval) {} + virtual u32 GetBackBufferWidth() { return s_backbuffer_width; } + virtual u32 GetBackBufferHeight() { return s_backbuffer_height; } + virtual void SetBackBufferDimensions(u32 W, u32 H) + { + s_backbuffer_width = W; + s_backbuffer_height = H; + } + virtual void Update() {} + virtual bool PeekMessages() { return false; } + virtual void UpdateHandle(void* window_handle) {} + virtual void UpdateSurface() {} + virtual std::unique_ptr CreateSharedContext() { return nullptr; } }; extern std::unique_ptr GLInterface; diff --git a/Source/Core/Common/GL/GLUtil.cpp b/Source/Core/Common/GL/GLUtil.cpp index 6c3072ab54..578f6641e4 100644 --- a/Source/Core/Common/GL/GLUtil.cpp +++ b/Source/Core/Common/GL/GLUtil.cpp @@ -15,126 +15,132 @@ static GLuint attributelessVBO = 0; void InitInterface() { - GLInterface = HostGL_CreateGLInterface(); + GLInterface = HostGL_CreateGLInterface(); } GLuint OpenGL_CompileProgram(const std::string& vertexShader, const std::string& fragmentShader) { - // generate objects - GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER); - GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); - GLuint programID = glCreateProgram(); + // generate objects + GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER); + GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); + GLuint programID = glCreateProgram(); - // compile vertex shader - const char* shader = vertexShader.c_str(); - glShaderSource(vertexShaderID, 1, &shader, nullptr); - glCompileShader(vertexShaderID); + // compile vertex shader + const char* shader = vertexShader.c_str(); + glShaderSource(vertexShaderID, 1, &shader, nullptr); + glCompileShader(vertexShaderID); #if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL) - GLint Result = GL_FALSE; - char stringBuffer[1024]; - GLsizei stringBufferUsage = 0; - glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &Result); - glGetShaderInfoLog(vertexShaderID, 1024, &stringBufferUsage, stringBuffer); + GLint Result = GL_FALSE; + char stringBuffer[1024]; + GLsizei stringBufferUsage = 0; + glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &Result); + glGetShaderInfoLog(vertexShaderID, 1024, &stringBufferUsage, stringBuffer); - if (Result && stringBufferUsage) - { - ERROR_LOG(VIDEO, "GLSL vertex shader warnings:\n%s%s", stringBuffer, vertexShader.c_str()); - } - else if (!Result) - { - ERROR_LOG(VIDEO, "GLSL vertex shader error:\n%s%s", stringBuffer, vertexShader.c_str()); - } - else - { - DEBUG_LOG(VIDEO, "GLSL vertex shader compiled:\n%s", vertexShader.c_str()); - } + if (Result && stringBufferUsage) + { + ERROR_LOG(VIDEO, "GLSL vertex shader warnings:\n%s%s", stringBuffer, vertexShader.c_str()); + } + else if (!Result) + { + ERROR_LOG(VIDEO, "GLSL vertex shader error:\n%s%s", stringBuffer, vertexShader.c_str()); + } + else + { + DEBUG_LOG(VIDEO, "GLSL vertex shader compiled:\n%s", vertexShader.c_str()); + } - bool shader_errors = !Result; + bool shader_errors = !Result; #endif - // compile fragment shader - shader = fragmentShader.c_str(); - glShaderSource(fragmentShaderID, 1, &shader, nullptr); - glCompileShader(fragmentShaderID); + // compile fragment shader + shader = fragmentShader.c_str(); + glShaderSource(fragmentShaderID, 1, &shader, nullptr); + glCompileShader(fragmentShaderID); #if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL) - glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &Result); - glGetShaderInfoLog(fragmentShaderID, 1024, &stringBufferUsage, stringBuffer); + glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &Result); + glGetShaderInfoLog(fragmentShaderID, 1024, &stringBufferUsage, stringBuffer); - if (Result && stringBufferUsage) - { - ERROR_LOG(VIDEO, "GLSL fragment shader warnings:\n%s%s", stringBuffer, fragmentShader.c_str()); - } - else if (!Result) - { - ERROR_LOG(VIDEO, "GLSL fragment shader error:\n%s%s", stringBuffer, fragmentShader.c_str()); - } - else - { - DEBUG_LOG(VIDEO, "GLSL fragment shader compiled:\n%s", fragmentShader.c_str()); - } + if (Result && stringBufferUsage) + { + ERROR_LOG(VIDEO, "GLSL fragment shader warnings:\n%s%s", stringBuffer, fragmentShader.c_str()); + } + else if (!Result) + { + ERROR_LOG(VIDEO, "GLSL fragment shader error:\n%s%s", stringBuffer, fragmentShader.c_str()); + } + else + { + DEBUG_LOG(VIDEO, "GLSL fragment shader compiled:\n%s", fragmentShader.c_str()); + } - shader_errors |= !Result; + shader_errors |= !Result; #endif - // link them - glAttachShader(programID, vertexShaderID); - glAttachShader(programID, fragmentShaderID); - glLinkProgram(programID); + // link them + glAttachShader(programID, vertexShaderID); + glAttachShader(programID, fragmentShaderID); + glLinkProgram(programID); #if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL) - glGetProgramiv(programID, GL_LINK_STATUS, &Result); - glGetProgramInfoLog(programID, 1024, &stringBufferUsage, stringBuffer); + glGetProgramiv(programID, GL_LINK_STATUS, &Result); + glGetProgramInfoLog(programID, 1024, &stringBufferUsage, stringBuffer); - if (Result && stringBufferUsage) - { - ERROR_LOG(VIDEO, "GLSL linker warnings:\n%s%s%s", stringBuffer, vertexShader.c_str(), fragmentShader.c_str()); - } - else if (!Result && !shader_errors) - { - ERROR_LOG(VIDEO, "GLSL linker error:\n%s%s%s", stringBuffer, vertexShader.c_str(), fragmentShader.c_str()); - } + if (Result && stringBufferUsage) + { + ERROR_LOG(VIDEO, "GLSL linker warnings:\n%s%s%s", stringBuffer, vertexShader.c_str(), + fragmentShader.c_str()); + } + else if (!Result && !shader_errors) + { + ERROR_LOG(VIDEO, "GLSL linker error:\n%s%s%s", stringBuffer, vertexShader.c_str(), + fragmentShader.c_str()); + } #endif - // cleanup - glDeleteShader(vertexShaderID); - glDeleteShader(fragmentShaderID); + // cleanup + glDeleteShader(vertexShaderID); + glDeleteShader(fragmentShaderID); - return programID; + return programID; } void OpenGL_CreateAttributelessVAO() { - glGenVertexArrays(1, &attributelessVAO); - _dbg_assert_msg_(VIDEO, attributelessVAO != 0, "Attributeless VAO should have been created successfully.") + glGenVertexArrays(1, &attributelessVAO); + _dbg_assert_msg_(VIDEO, attributelessVAO != 0, + "Attributeless VAO should have been created successfully.") - // In a compatibility context, we require a valid, bound array buffer. - glGenBuffers(1, &attributelessVBO); - _dbg_assert_msg_(VIDEO, attributelessVBO != 0, "Attributeless VBO should have been created successfully.") + // In a compatibility context, we require a valid, bound array buffer. + glGenBuffers(1, &attributelessVBO); + _dbg_assert_msg_(VIDEO, attributelessVBO != 0, + "Attributeless VBO should have been created successfully.") - // Initialize the buffer with nothing. 16 floats is an arbitrary size that may work around driver issues. - glBindBuffer(GL_ARRAY_BUFFER, attributelessVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 16, nullptr, GL_STATIC_DRAW); + // Initialize the buffer with nothing. 16 floats is an arbitrary size that may work around + // driver issues. + glBindBuffer(GL_ARRAY_BUFFER, attributelessVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 16, nullptr, GL_STATIC_DRAW); - // We must also define vertex attribute 0. - glBindVertexArray(attributelessVAO); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr); - glEnableVertexAttribArray(0); + // We must also define vertex attribute 0. + glBindVertexArray(attributelessVAO); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + glEnableVertexAttribArray(0); } void OpenGL_BindAttributelessVAO() { - _dbg_assert_msg_(VIDEO, attributelessVAO != 0, "Attributeless VAO should have already been created.") - glBindVertexArray(attributelessVAO); + _dbg_assert_msg_(VIDEO, attributelessVAO != 0, + "Attributeless VAO should have already been created.") + glBindVertexArray(attributelessVAO); } void OpenGL_DeleteAttributelessVAO() { - _dbg_assert_msg_(VIDEO, attributelessVAO != 0, "Attributeless VAO should have already been created.") - if (attributelessVAO != 0) - { - glDeleteVertexArrays(1, &attributelessVAO); - glDeleteBuffers(1, &attributelessVBO); + _dbg_assert_msg_(VIDEO, attributelessVAO != 0, + "Attributeless VAO should have already been created.") if (attributelessVAO != 0) + { + glDeleteVertexArrays(1, &attributelessVAO); + glDeleteBuffers(1, &attributelessVBO); - attributelessVAO = 0; - attributelessVBO = 0; - } + attributelessVAO = 0; + attributelessVBO = 0; + } } diff --git a/Source/Core/Common/GL/GLUtil.h b/Source/Core/Common/GL/GLUtil.h index 718ee225da..a386395739 100644 --- a/Source/Core/Common/GL/GLUtil.h +++ b/Source/Core/Common/GL/GLUtil.h @@ -26,7 +26,8 @@ void OpenGL_DeleteAttributelessVAO(); // Binds the VAO suitable for attributeless rendering. void OpenGL_BindAttributelessVAO(); -// this should be removed in future, but as long as glsl is unstable, we should really read this messages +// this should be removed in future, but as long as glsl is unstable, we should really read this +// messages #if defined(_DEBUG) || defined(DEBUGFAST) #define DEBUG_GLSL 1 #else diff --git a/Source/Core/Common/GekkoDisassembler.cpp b/Source/Core/Common/GekkoDisassembler.cpp index b638faf429..e6b4aec326 100644 --- a/Source/Core/Common/GekkoDisassembler.cpp +++ b/Source/Core/Common/GekkoDisassembler.cpp @@ -43,97 +43,75 @@ #define PPCDISASM_REV 6 // general defines -#define PPCIDXMASK 0xfc000000 -#define PPCIDX2MASK 0x000007fe -#define PPCDMASK 0x03e00000 -#define PPCAMASK 0x001f0000 -#define PPCBMASK 0x0000f800 -#define PPCCMASK 0x000007c0 -#define PPCMMASK 0x0000003e -#define PPCCRDMASK 0x03800000 -#define PPCCRAMASK 0x001c0000 -#define PPCLMASK 0x00600000 -#define PPCOE 0x00000400 -#define PPCVRC 0x00000400 -#define PPCDST 0x02000000 -#define PPCSTRM 0x00600000 +#define PPCIDXMASK 0xfc000000 +#define PPCIDX2MASK 0x000007fe +#define PPCDMASK 0x03e00000 +#define PPCAMASK 0x001f0000 +#define PPCBMASK 0x0000f800 +#define PPCCMASK 0x000007c0 +#define PPCMMASK 0x0000003e +#define PPCCRDMASK 0x03800000 +#define PPCCRAMASK 0x001c0000 +#define PPCLMASK 0x00600000 +#define PPCOE 0x00000400 +#define PPCVRC 0x00000400 +#define PPCDST 0x02000000 +#define PPCSTRM 0x00600000 -#define PPCIDXSH 26 -#define PPCDSH 21 -#define PPCASH 16 -#define PPCBSH 11 -#define PPCCSH 6 -#define PPCMSH 1 -#define PPCCRDSH 23 -#define PPCCRASH 18 -#define PPCLSH 21 -#define PPCIDX2SH 1 - -#define PPCGETIDX(x) (((x)&PPCIDXMASK)>>PPCIDXSH) -#define PPCGETD(x) (((x)&PPCDMASK)>>PPCDSH) -#define PPCGETA(x) (((x)&PPCAMASK)>>PPCASH) -#define PPCGETB(x) (((x)&PPCBMASK)>>PPCBSH) -#define PPCGETC(x) (((x)&PPCCMASK)>>PPCCSH) -#define PPCGETM(x) (((x)&PPCMMASK)>>PPCMSH) -#define PPCGETCRD(x) (((x)&PPCCRDMASK)>>PPCCRDSH) -#define PPCGETCRA(x) (((x)&PPCCRAMASK)>>PPCCRASH) -#define PPCGETL(x) (((x)&PPCLMASK)>>PPCLSH) -#define PPCGETIDX2(x) (((x)&PPCIDX2MASK)>>PPCIDX2SH) -#define PPCGETSTRM(x) (((x)&PPCSTRM)>>PPCDSH) +#define PPCIDXSH 26 +#define PPCDSH 21 +#define PPCASH 16 +#define PPCBSH 11 +#define PPCCSH 6 +#define PPCMSH 1 +#define PPCCRDSH 23 +#define PPCCRASH 18 +#define PPCLSH 21 +#define PPCIDX2SH 1 +#define PPCGETIDX(x) (((x)&PPCIDXMASK) >> PPCIDXSH) +#define PPCGETD(x) (((x)&PPCDMASK) >> PPCDSH) +#define PPCGETA(x) (((x)&PPCAMASK) >> PPCASH) +#define PPCGETB(x) (((x)&PPCBMASK) >> PPCBSH) +#define PPCGETC(x) (((x)&PPCCMASK) >> PPCCSH) +#define PPCGETM(x) (((x)&PPCMMASK) >> PPCMSH) +#define PPCGETCRD(x) (((x)&PPCCRDMASK) >> PPCCRDSH) +#define PPCGETCRA(x) (((x)&PPCCRAMASK) >> PPCCRASH) +#define PPCGETL(x) (((x)&PPCLMASK) >> PPCLSH) +#define PPCGETIDX2(x) (((x)&PPCIDX2MASK) >> PPCIDX2SH) +#define PPCGETSTRM(x) (((x)&PPCSTRM) >> PPCDSH) static const char* trap_condition[32] = { - nullptr, "lgt", "llt", nullptr, "eq", "lge", "lle", nullptr, - "gt", nullptr, nullptr, nullptr, "ge", nullptr, nullptr, nullptr, - "lt", nullptr, nullptr, nullptr, "le", nullptr, nullptr, nullptr, - "ne", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr -}; + nullptr, "lgt", "llt", nullptr, "eq", "lge", "lle", nullptr, + "gt", nullptr, nullptr, nullptr, "ge", nullptr, nullptr, nullptr, + "lt", nullptr, nullptr, nullptr, "le", nullptr, nullptr, nullptr, + "ne", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; -static const char* cmpname[4] = { - "cmpw", "cmpd", "cmplw", "cmpld" -}; +static const char* cmpname[4] = {"cmpw", "cmpd", "cmplw", "cmpld"}; -static const char* ps_cmpname[4] = { - "ps_cmpu0", "ps_cmpo0", "ps_cmpu1", "ps_cmpo1" -}; +static const char* ps_cmpname[4] = {"ps_cmpu0", "ps_cmpo0", "ps_cmpu1", "ps_cmpo1"}; -static const char* b_ext[4] = { - "", "l", "a", "la" -}; +static const char* b_ext[4] = {"", "l", "a", "la"}; -static const char* b_condition[8] = { - "ge", "le", "ne", "ns", "lt", "gt", "eq", "so" -}; +static const char* b_condition[8] = {"ge", "le", "ne", "ns", "lt", "gt", "eq", "so"}; -static const char* b_decr[16] = { - "nzf", "zf", nullptr, nullptr, "nzt", "zt", nullptr, nullptr, - "nz", "z", nullptr, nullptr, "nz", "z", nullptr, nullptr -}; +static const char* b_decr[16] = {"nzf", "zf", nullptr, nullptr, "nzt", "zt", nullptr, nullptr, + "nz", "z", nullptr, nullptr, "nz", "z", nullptr, nullptr}; -static const char* regsel[2] = { - "", "r" -}; +static const char* regsel[2] = {"", "r"}; -static const char* oesel[2] = { - "", "o" -}; +static const char* oesel[2] = {"", "o"}; -static const char* rcsel[2] = { - "", "." -}; +static const char* rcsel[2] = {"", "."}; -static const char* ldstnames[24] = { - "lwz", "lwzu", "lbz", "lbzu", "stw", "stwu", "stb", "stbu", "lhz", "lhzu", - "lha", "lhau", "sth", "sthu", "lmw", "stmw", "lfs", "lfsu", "lfd", "lfdu", - "stfs", "stfsu", "stfd", "stfdu" -}; +static const char* ldstnames[24] = {"lwz", "lwzu", "lbz", "lbzu", "stw", "stwu", "stb", "stbu", + "lhz", "lhzu", "lha", "lhau", "sth", "sthu", "lmw", "stmw", + "lfs", "lfsu", "lfd", "lfdu", "stfs", "stfsu", "stfd", "stfdu"}; -static const char* regnames[32] = { - "r0", "sp", "rtoc", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" -}; +static const char* regnames[32] = {"r0", "sp", "rtoc", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"}; // Initialize static class variables. u32* GekkoDisassembler::m_instr = nullptr; @@ -145,115 +123,183 @@ unsigned char GekkoDisassembler::m_flags = PPCF_ILLEGAL; unsigned short GekkoDisassembler::m_sreg = 0; u32 GekkoDisassembler::m_displacement = 0; - static std::string spr_name(int i) { - switch (i) - { - case 1: return "XER"; - case 8: return "LR"; - case 9: return "CTR"; - case 18: return "DSIR"; - case 19: return "DAR"; - case 22: return "DEC"; - case 25: return "SDR1"; - case 26: return "SRR0"; - case 27: return "SRR1"; - case 272: return "SPRG0"; - case 273: return "SPRG1"; - case 274: return "SPRG2"; - case 275: return "SPRG3"; - case 282: return "EAR"; - case 287: return "PVR"; - case 528: return "IBAT0U"; - case 529: return "IBAT0L"; - case 530: return "IBAT1U"; - case 531: return "IBAT1L"; - case 532: return "IBAT2U"; - case 533: return "IBAT2L"; - case 534: return "IBAT3U"; - case 535: return "IBAT3L"; - case 536: return "DBAT0U"; - case 537: return "DBAT0L"; - case 538: return "DBAT1U"; - case 539: return "DBAT1L"; - case 540: return "DBAT2U"; - case 541: return "DBAT2L"; - case 542: return "DBAT3U"; - case 543: return "DBAT3L"; - case 912: return "GQR0"; - case 913: return "GQR1"; - case 914: return "GQR2"; - case 915: return "GQR3"; - case 916: return "GQR4"; - case 917: return "GQR5"; - case 918: return "GQR6"; - case 919: return "GQR7"; - case 920: return "HID2"; - case 921: return "WPAR"; - case 922: return "DMA_U"; - case 923: return "DMA_L"; - case 924: return "ECID_U"; - case 925: return "ECID_M"; - case 926: return "ECID_L"; - case 936: return "UMMCR0"; - case 937: return "UPMC1"; - case 938: return "UPMC2"; - case 939: return "USIA"; - case 940: return "UMMCR1"; - case 941: return "UPMC3"; - case 942: return "UPMC4"; - case 943: return "USDA"; - case 952: return "MMCR0"; - case 953: return "PMC1"; - case 954: return "PMC2"; - case 955: return "SIA"; - case 956: return "MMCR1"; - case 957: return "PMC3"; - case 958: return "PMC4"; - case 959: return "SDA"; - case 1008: return "HID0"; - case 1009: return "HID1"; - case 1010: return "IABR"; - case 1011: return "HID4"; - case 1013: return "DABR"; - case 1017: return "L2CR"; - case 1019: return "ICTC"; - case 1020: return "THRM1"; - case 1021: return "THRM2"; - case 1022: return "THRM3"; - } + switch (i) + { + case 1: + return "XER"; + case 8: + return "LR"; + case 9: + return "CTR"; + case 18: + return "DSIR"; + case 19: + return "DAR"; + case 22: + return "DEC"; + case 25: + return "SDR1"; + case 26: + return "SRR0"; + case 27: + return "SRR1"; + case 272: + return "SPRG0"; + case 273: + return "SPRG1"; + case 274: + return "SPRG2"; + case 275: + return "SPRG3"; + case 282: + return "EAR"; + case 287: + return "PVR"; + case 528: + return "IBAT0U"; + case 529: + return "IBAT0L"; + case 530: + return "IBAT1U"; + case 531: + return "IBAT1L"; + case 532: + return "IBAT2U"; + case 533: + return "IBAT2L"; + case 534: + return "IBAT3U"; + case 535: + return "IBAT3L"; + case 536: + return "DBAT0U"; + case 537: + return "DBAT0L"; + case 538: + return "DBAT1U"; + case 539: + return "DBAT1L"; + case 540: + return "DBAT2U"; + case 541: + return "DBAT2L"; + case 542: + return "DBAT3U"; + case 543: + return "DBAT3L"; + case 912: + return "GQR0"; + case 913: + return "GQR1"; + case 914: + return "GQR2"; + case 915: + return "GQR3"; + case 916: + return "GQR4"; + case 917: + return "GQR5"; + case 918: + return "GQR6"; + case 919: + return "GQR7"; + case 920: + return "HID2"; + case 921: + return "WPAR"; + case 922: + return "DMA_U"; + case 923: + return "DMA_L"; + case 924: + return "ECID_U"; + case 925: + return "ECID_M"; + case 926: + return "ECID_L"; + case 936: + return "UMMCR0"; + case 937: + return "UPMC1"; + case 938: + return "UPMC2"; + case 939: + return "USIA"; + case 940: + return "UMMCR1"; + case 941: + return "UPMC3"; + case 942: + return "UPMC4"; + case 943: + return "USDA"; + case 952: + return "MMCR0"; + case 953: + return "PMC1"; + case 954: + return "PMC2"; + case 955: + return "SIA"; + case 956: + return "MMCR1"; + case 957: + return "PMC3"; + case 958: + return "PMC4"; + case 959: + return "SDA"; + case 1008: + return "HID0"; + case 1009: + return "HID1"; + case 1010: + return "IABR"; + case 1011: + return "HID4"; + case 1013: + return "DABR"; + case 1017: + return "L2CR"; + case 1019: + return "ICTC"; + case 1020: + return "THRM1"; + case 1021: + return "THRM2"; + case 1022: + return "THRM3"; + } - return StringFromFormat("%d", i); + return StringFromFormat("%d", i); } - static u32 swapda(u32 w) { - return ((w & 0xfc00ffff) | ((w&PPCAMASK) << 5) | ((w&PPCDMASK) >> 5)); + return ((w & 0xfc00ffff) | ((w & PPCAMASK) << 5) | ((w & PPCDMASK) >> 5)); } - static u32 swapab(u32 w) { - return ((w & 0xffe007ff) | ((w&PPCBMASK) << 5) | ((w&PPCAMASK) >> 5)); + return ((w & 0xffe007ff) | ((w & PPCBMASK) << 5) | ((w & PPCAMASK) >> 5)); } - void GekkoDisassembler::ill(u32 in) { - if (in == 0) - { - m_opcode = ""; - m_operands = "---"; - } - else - { - m_opcode = "(ill)"; - m_operands = StringFromFormat("%08x", in); - } + if (in == 0) + { + m_opcode = ""; + m_operands = "---"; + } + else + { + m_opcode = "(ill)"; + m_operands = StringFromFormat("%08x", in); + } - m_flags |= PPCF_ILLEGAL; + m_flags |= PPCF_ILLEGAL; } // Generate immediate instruction operand. @@ -264,677 +310,663 @@ void GekkoDisassembler::ill(u32 in) // Type 3: A register is ignored (li) std::string GekkoDisassembler::imm(u32 in, int uimm, int type, bool hex) { - int i = (int)(in & 0xffff); + int i = (int)(in & 0xffff); - m_type = PPCINSTR_IMM; + m_type = PPCINSTR_IMM; - if (uimm == 0) - { - if (i > 0x7fff) - i -= 0x10000; - } - else - { - m_flags |= PPCF_UNSIGNED; - } - m_displacement = i; + if (uimm == 0) + { + if (i > 0x7fff) + i -= 0x10000; + } + else + { + m_flags |= PPCF_UNSIGNED; + } + m_displacement = i; - switch (type) - { - case 0: - return StringFromFormat("%s, %s, %d", regnames[(int)PPCGETD(in)], regnames[(int)PPCGETA(in)], i); + switch (type) + { + case 0: + return StringFromFormat("%s, %s, %d", regnames[(int)PPCGETD(in)], regnames[(int)PPCGETA(in)], + i); - case 1: - if (hex) - return StringFromFormat("%s, %s, 0x%.4X", regnames[(int)PPCGETA(in)], regnames[(int)PPCGETD(in)], i); - else - return StringFromFormat("%s, %s, %d", regnames[(int)PPCGETA(in)], regnames[(int)PPCGETD(in)], i); + case 1: + if (hex) + return StringFromFormat("%s, %s, 0x%.4X", regnames[(int)PPCGETA(in)], + regnames[(int)PPCGETD(in)], i); + else + return StringFromFormat("%s, %s, %d", regnames[(int)PPCGETA(in)], regnames[(int)PPCGETD(in)], + i); - case 2: - return StringFromFormat("%s, %d", regnames[(int)PPCGETA(in)], i); + case 2: + return StringFromFormat("%s, %d", regnames[(int)PPCGETA(in)], i); - case 3: - if (hex) - return StringFromFormat("%s, 0x%.4X", regnames[(int)PPCGETD(in)], i); - else - return StringFromFormat("%s, %d", regnames[(int)PPCGETD(in)], i); + case 3: + if (hex) + return StringFromFormat("%s, 0x%.4X", regnames[(int)PPCGETD(in)], i); + else + return StringFromFormat("%s, %d", regnames[(int)PPCGETD(in)], i); - default: - return StringFromFormat("%s", "imm(): Wrong type"); - } + default: + return StringFromFormat("%s", "imm(): Wrong type"); + } } - std::string GekkoDisassembler::ra_rb(u32 in) { - return StringFromFormat("%s, %s", regnames[(int)PPCGETA(in)], regnames[(int)PPCGETB(in)]); + return StringFromFormat("%s, %s", regnames[(int)PPCGETA(in)], regnames[(int)PPCGETB(in)]); } - std::string GekkoDisassembler::rd_ra_rb(u32 in, int mask) { - std::string result; + std::string result; - if (mask) - { - if (mask & 4) - result += StringFromFormat("%s, ", regnames[(int)PPCGETD(in)]); - if (mask & 2) - result += StringFromFormat("%s, ", regnames[(int)PPCGETA(in)]); - if (mask & 1) - result += StringFromFormat("%s, ", regnames[(int)PPCGETB(in)]); + if (mask) + { + if (mask & 4) + result += StringFromFormat("%s, ", regnames[(int)PPCGETD(in)]); + if (mask & 2) + result += StringFromFormat("%s, ", regnames[(int)PPCGETA(in)]); + if (mask & 1) + result += StringFromFormat("%s, ", regnames[(int)PPCGETB(in)]); - size_t pos = result.rfind(", "); - if (pos != std::string::npos) - { - result.erase(pos, result.length() - pos); - } - } + size_t pos = result.rfind(", "); + if (pos != std::string::npos) + { + result.erase(pos, result.length() - pos); + } + } - return result; + return result; } - std::string GekkoDisassembler::fd_ra_rb(u32 in, int mask) { - std::string result; + std::string result; - if (mask) - { - if (mask & 4) - result += StringFromFormat("f%d,", (int)PPCGETD(in)); - if (mask & 2) - result += StringFromFormat("%s,", regnames[(int)PPCGETA(in)]); - if (mask & 1) - result += StringFromFormat("%s,", regnames[(int)PPCGETB(in)]); + if (mask) + { + if (mask & 4) + result += StringFromFormat("f%d,", (int)PPCGETD(in)); + if (mask & 2) + result += StringFromFormat("%s,", regnames[(int)PPCGETA(in)]); + if (mask & 1) + result += StringFromFormat("%s,", regnames[(int)PPCGETB(in)]); - // Drop the trailing comma - result.pop_back(); - } + // Drop the trailing comma + result.pop_back(); + } - return result; + return result; } - void GekkoDisassembler::trapi(u32 in, unsigned char dmode) { - const char* cnd = trap_condition[PPCGETD(in)]; + const char* cnd = trap_condition[PPCGETD(in)]; - - m_flags |= dmode; - if (cnd != nullptr) - { - m_opcode = StringFromFormat("t%c%s", dmode ? 'd' : 'w', cnd); - } - else - { - m_opcode = StringFromFormat("t%ci", dmode ? 'd' : 'w'); - m_operands = StringFromFormat("%d, ", PPCGETD(in)); - } - m_operands += imm(in, 0, 2, false); + m_flags |= dmode; + if (cnd != nullptr) + { + m_opcode = StringFromFormat("t%c%s", dmode ? 'd' : 'w', cnd); + } + else + { + m_opcode = StringFromFormat("t%ci", dmode ? 'd' : 'w'); + m_operands = StringFromFormat("%d, ", PPCGETD(in)); + } + m_operands += imm(in, 0, 2, false); } - void GekkoDisassembler::cmpi(u32 in, int uimm) { - int i = (int)PPCGETL(in); + int i = (int)PPCGETL(in); - if (i < 2) - { - if (i != 0) - m_flags |= PPCF_64; + if (i < 2) + { + if (i != 0) + m_flags |= PPCF_64; - m_opcode = StringFromFormat("%si", cmpname[uimm * 2 + i]); + m_opcode = StringFromFormat("%si", cmpname[uimm * 2 + i]); - i = (int)PPCGETCRD(in); - if (i != 0) - { - m_operands += StringFromFormat("cr%c, ", '0' + i); - } + i = (int)PPCGETCRD(in); + if (i != 0) + { + m_operands += StringFromFormat("cr%c, ", '0' + i); + } - m_operands += imm(in, uimm, 2, false); - } - else - { - ill(in); - } + m_operands += imm(in, uimm, 2, false); + } + else + { + ill(in); + } } - void GekkoDisassembler::addi(u32 in, const std::string& ext) { - if ((in & 0x08000000) && !PPCGETA(in)) - { - m_opcode = StringFromFormat("l%s", ext.c_str()); // li, lis + if ((in & 0x08000000) && !PPCGETA(in)) + { + m_opcode = StringFromFormat("l%s", ext.c_str()); // li, lis - if (ext == "i") - m_operands = imm(in, 0, 3, false); - else - m_operands = imm(in, 1, 3, true); - } - else - { - m_opcode = StringFromFormat("%s%s", (in & 0x8000) ? "sub" : "add", ext.c_str()); + if (ext == "i") + m_operands = imm(in, 0, 3, false); + else + m_operands = imm(in, 1, 3, true); + } + else + { + m_opcode = StringFromFormat("%s%s", (in & 0x8000) ? "sub" : "add", ext.c_str()); - if (in & 0x8000) - in = (in ^ 0xffff) + 1; + if (in & 0x8000) + in = (in ^ 0xffff) + 1; - m_operands = imm(in, 1, 0, false); - } + m_operands = imm(in, 1, 0, false); + } } // Build a branch instr. and return number of chars written to operand. size_t GekkoDisassembler::branch(u32 in, const char* bname, int aform, int bdisp) { - int bo = (int)PPCGETD(in); - int bi = (int)PPCGETA(in); - char y = (char)(bo & 1); - const char* ext = b_ext[aform * 2 + (int)(in & 1)]; + int bo = (int)PPCGETD(in); + int bi = (int)PPCGETA(in); + char y = (char)(bo & 1); + const char* ext = b_ext[aform * 2 + (int)(in & 1)]; - if (bdisp < 0) - y ^= 1; - y = (y != 0) ? '+' : '-'; + if (bdisp < 0) + y ^= 1; + y = (y != 0) ? '+' : '-'; - if (bo & 4) - { - // standard case - no decrement - if (bo & 16) - { - // branch always - if (PPCGETIDX(in) != 16) - { - m_opcode = StringFromFormat("b%s%s", bname, ext); - } - else - { - m_opcode = StringFromFormat("bc%s", ext); - m_operands = StringFromFormat("%d, %d", bo, bi); - } - } - else // Branch conditional - { - m_opcode = StringFromFormat("b%s%s%s%c", b_condition[((bo & 8) >> 1) + (bi & 3)], bname, ext, y); + if (bo & 4) + { + // standard case - no decrement + if (bo & 16) + { + // branch always + if (PPCGETIDX(in) != 16) + { + m_opcode = StringFromFormat("b%s%s", bname, ext); + } + else + { + m_opcode = StringFromFormat("bc%s", ext); + m_operands = StringFromFormat("%d, %d", bo, bi); + } + } + else // Branch conditional + { + m_opcode = + StringFromFormat("b%s%s%s%c", b_condition[((bo & 8) >> 1) + (bi & 3)], bname, ext, y); - if (bi >= 4) - { - m_operands = StringFromFormat("cr%d", bi >> 2); - } - } - } - else - { - // CTR is decremented and checked - m_opcode = StringFromFormat("bd%s%s%s%c", b_decr[bo >> 1], bname, ext, y); + if (bi >= 4) + { + m_operands = StringFromFormat("cr%d", bi >> 2); + } + } + } + else + { + // CTR is decremented and checked + m_opcode = StringFromFormat("bd%s%s%s%c", b_decr[bo >> 1], bname, ext, y); - if ((bo & 16) == 0) - { - m_operands = StringFromFormat("%d", bi); - } - } + if ((bo & 16) == 0) + { + m_operands = StringFromFormat("%d", bi); + } + } - return m_operands.length(); + return m_operands.length(); } - void GekkoDisassembler::bc(u32 in) { - unsigned int d = (int)(in & 0xfffc); + unsigned int d = (int)(in & 0xfffc); - if (d & 0x8000) - d |= 0xffff0000; + if (d & 0x8000) + d |= 0xffff0000; - branch(in, "", (in & 2) ? 1 : 0, d); + branch(in, "", (in & 2) ? 1 : 0, d); - if (in & 2) // AA ? - m_operands = StringFromFormat("%s ->0x%.8X", m_operands.c_str(), d); - else - m_operands = StringFromFormat("%s ->0x%.8X", m_operands.c_str(), *m_iaddr + d); + if (in & 2) // AA ? + m_operands = StringFromFormat("%s ->0x%.8X", m_operands.c_str(), d); + else + m_operands = StringFromFormat("%s ->0x%.8X", m_operands.c_str(), *m_iaddr + d); - m_type = PPCINSTR_BRANCH; - m_displacement = d; + m_type = PPCINSTR_BRANCH; + m_displacement = d; } - void GekkoDisassembler::bli(u32 in) { - unsigned int d = (unsigned int)(in & 0x3fffffc); + unsigned int d = (unsigned int)(in & 0x3fffffc); - if (d & 0x02000000) - d |= 0xfc000000; + if (d & 0x02000000) + d |= 0xfc000000; - m_opcode = StringFromFormat("b%s", b_ext[in & 3]); + m_opcode = StringFromFormat("b%s", b_ext[in & 3]); - if (in & 2) // AA ? - m_operands = StringFromFormat("->0x%.8X", d); - else - m_operands = StringFromFormat("->0x%.8X", *m_iaddr + d); + if (in & 2) // AA ? + m_operands = StringFromFormat("->0x%.8X", d); + else + m_operands = StringFromFormat("->0x%.8X", *m_iaddr + d); - m_type = PPCINSTR_BRANCH; - m_displacement = d; + m_type = PPCINSTR_BRANCH; + m_displacement = d; } - void GekkoDisassembler::mcrf(u32 in, char c) { - if ((in & 0x0063f801) == 0) - { - m_opcode = StringFromFormat("mcrf%c", c); - m_operands = StringFromFormat("cr%d, cr%d", (int)PPCGETCRD(in), (int)PPCGETCRA(in)); - } - else - { - ill(in); - } + if ((in & 0x0063f801) == 0) + { + m_opcode = StringFromFormat("mcrf%c", c); + m_operands = StringFromFormat("cr%d, cr%d", (int)PPCGETCRD(in), (int)PPCGETCRA(in)); + } + else + { + ill(in); + } } - void GekkoDisassembler::crop(u32 in, const char* n1, const char* n2) { - int crd = (int)PPCGETD(in); - int cra = (int)PPCGETA(in); - int crb = (int)PPCGETB(in); + int crd = (int)PPCGETD(in); + int cra = (int)PPCGETA(in); + int crb = (int)PPCGETB(in); - if ((in & 1) == 0) - { - m_opcode = StringFromFormat("cr%s", (cra == crb && n2) ? n2 : n1); - if (cra == crb && n2) - m_operands = StringFromFormat("%d, %d", crd, cra); - else - m_operands = StringFromFormat("%d, %d, %d", crd, cra, crb); - } - else - { - ill(in); - } + if ((in & 1) == 0) + { + m_opcode = StringFromFormat("cr%s", (cra == crb && n2) ? n2 : n1); + if (cra == crb && n2) + m_operands = StringFromFormat("%d, %d", crd, cra); + else + m_operands = StringFromFormat("%d, %d, %d", crd, cra, crb); + } + else + { + ill(in); + } } - void GekkoDisassembler::nooper(u32 in, const char* name, unsigned char dmode) { - if (in & (PPCDMASK | PPCAMASK | PPCBMASK | 1)) - { - ill(in); - } - else - { - m_flags |= dmode; - m_opcode = name; - } + if (in & (PPCDMASK | PPCAMASK | PPCBMASK | 1)) + { + ill(in); + } + else + { + m_flags |= dmode; + m_opcode = name; + } } void GekkoDisassembler::rlw(u32 in, const char* name, int i) { - int s = (int)PPCGETD(in); - int a = (int)PPCGETA(in); - int bsh = (int)PPCGETB(in); - int mb = (int)PPCGETC(in); - int me = (int)PPCGETM(in); + int s = (int)PPCGETD(in); + int a = (int)PPCGETA(in); + int bsh = (int)PPCGETB(in); + int mb = (int)PPCGETC(in); + int me = (int)PPCGETM(in); - m_opcode = StringFromFormat("rlw%s%c", name, in & 1 ? '.' : '\0'); - m_operands = StringFromFormat("%s, %s, %s%d, %d, %d (%08x)", regnames[a], regnames[s], regsel[i], bsh, mb, me, HelperRotateMask(bsh, mb, me)); + m_opcode = StringFromFormat("rlw%s%c", name, in & 1 ? '.' : '\0'); + m_operands = StringFromFormat("%s, %s, %s%d, %d, %d (%08x)", regnames[a], regnames[s], regsel[i], + bsh, mb, me, HelperRotateMask(bsh, mb, me)); } - void GekkoDisassembler::ori(u32 in, const char* name) { - m_opcode = name; - m_operands = imm(in, 1, 1, true); + m_opcode = name; + m_operands = imm(in, 1, 1, true); } - void GekkoDisassembler::rld(u32 in, const char* name, int i) { - int s = (int)PPCGETD(in); - int a = (int)PPCGETA(in); - int bsh = i ? (int)PPCGETB(in) : (int)(((in & 2) << 4) + PPCGETB(in)); - int m = (int)(in & 0x7e0) >> 5; + int s = (int)PPCGETD(in); + int a = (int)PPCGETA(in); + int bsh = i ? (int)PPCGETB(in) : (int)(((in & 2) << 4) + PPCGETB(in)); + int m = (int)(in & 0x7e0) >> 5; - m_flags |= PPCF_64; - m_opcode = StringFromFormat("rld%s%c", name, in & 1 ? '.' : '\0'); - m_operands = StringFromFormat("%s, %s, %s%d, %d", regnames[a], regnames[s], regsel[i], bsh, m); + m_flags |= PPCF_64; + m_opcode = StringFromFormat("rld%s%c", name, in & 1 ? '.' : '\0'); + m_operands = StringFromFormat("%s, %s, %s%d, %d", regnames[a], regnames[s], regsel[i], bsh, m); } - void GekkoDisassembler::cmp(u32 in) { - int i = (int)PPCGETL(in); + int i = (int)PPCGETL(in); - if (i < 2) - { - if (i != 0) - m_flags |= PPCF_64; + if (i < 2) + { + if (i != 0) + m_flags |= PPCF_64; - m_opcode = cmpname[((in&PPCIDX2MASK) ? 2 : 0) + i]; + m_opcode = cmpname[((in & PPCIDX2MASK) ? 2 : 0) + i]; - i = (int)PPCGETCRD(in); - if (i != 0) - m_operands += StringFromFormat("cr%c,", '0' + i); + i = (int)PPCGETCRD(in); + if (i != 0) + m_operands += StringFromFormat("cr%c,", '0' + i); - m_operands += ra_rb(in); - } - else - { - ill(in); - } + m_operands += ra_rb(in); + } + else + { + ill(in); + } } - void GekkoDisassembler::trap(u32 in, unsigned char dmode) { - int to = (int)PPCGETD(in); - const char* cnd = trap_condition[to]; + int to = (int)PPCGETD(in); + const char* cnd = trap_condition[to]; - if (cnd != nullptr) - { - m_flags |= dmode; - m_opcode = StringFromFormat("t%c%s", dmode ? 'd' : 'w', cnd); - m_operands = ra_rb(in); - } - else - { - if (to == 31) - { - if (dmode) - { - m_flags |= dmode; - m_opcode = "td"; - m_operands = "31,0,0"; - } - else - { - m_opcode = "trap"; - } - } - else - { - ill(in); - } - } + if (cnd != nullptr) + { + m_flags |= dmode; + m_opcode = StringFromFormat("t%c%s", dmode ? 'd' : 'w', cnd); + m_operands = ra_rb(in); + } + else + { + if (to == 31) + { + if (dmode) + { + m_flags |= dmode; + m_opcode = "td"; + m_operands = "31,0,0"; + } + else + { + m_opcode = "trap"; + } + } + else + { + ill(in); + } + } } // Standard instruction: xxxx rD,rA,rB -void GekkoDisassembler::dab(u32 in, const char* name, int mask, int smode, int chkoe, int chkrc, unsigned char dmode) +void GekkoDisassembler::dab(u32 in, const char* name, int mask, int smode, int chkoe, int chkrc, + unsigned char dmode) { - if (chkrc >= 0 && ((in & 1) != (unsigned int)chkrc)) - { - ill(in); - } - else - { - m_flags |= dmode; + if (chkrc >= 0 && ((in & 1) != (unsigned int)chkrc)) + { + ill(in); + } + else + { + m_flags |= dmode; - // rA,rS,rB - if (smode) - in = swapda(in); + // rA,rS,rB + if (smode) + in = swapda(in); - m_opcode = StringFromFormat("%s%s%s", name, oesel[chkoe && (in&PPCOE)], rcsel[(chkrc < 0) && (in & 1)]); - m_operands = rd_ra_rb(in, mask); - } + m_opcode = StringFromFormat("%s%s%s", name, oesel[chkoe && (in & PPCOE)], + rcsel[(chkrc < 0) && (in & 1)]); + m_operands = rd_ra_rb(in, mask); + } } // Last operand is no register: xxxx rD,rA,NB -void GekkoDisassembler::rrn(u32 in, const char* name, int smode, int chkoe, int chkrc, unsigned char dmode) +void GekkoDisassembler::rrn(u32 in, const char* name, int smode, int chkoe, int chkrc, + unsigned char dmode) { - if (chkrc >= 0 && ((in & 1) != (unsigned int)chkrc)) - { - ill(in); - } - else - { - m_flags |= dmode; + if (chkrc >= 0 && ((in & 1) != (unsigned int)chkrc)) + { + ill(in); + } + else + { + m_flags |= dmode; - // rA,rS,NB - if (smode) - in = swapda(in); + // rA,rS,NB + if (smode) + in = swapda(in); - m_opcode = StringFromFormat("%s%s%s", name, oesel[chkoe && (in&PPCOE)], rcsel[(chkrc < 0) && (in & 1)]); + m_opcode = StringFromFormat("%s%s%s", name, oesel[chkoe && (in & PPCOE)], + rcsel[(chkrc < 0) && (in & 1)]); - m_operands = rd_ra_rb(in, 6); - m_operands += StringFromFormat(",%d",(int)PPCGETB(in)); - } + m_operands = rd_ra_rb(in, 6); + m_operands += StringFromFormat(",%d", (int)PPCGETB(in)); + } } - void GekkoDisassembler::mtcr(u32 in) { - int s = (int)PPCGETD(in); - int crm = (int)(in & 0x000ff000) >> 12; + int s = (int)PPCGETD(in); + int crm = (int)(in & 0x000ff000) >> 12; - if (in & 0x00100801) - { - ill(in); - } - else - { - m_opcode = StringFromFormat("mtcr%c", crm == 0xff ? '\0' : 'f'); + if (in & 0x00100801) + { + ill(in); + } + else + { + m_opcode = StringFromFormat("mtcr%c", crm == 0xff ? '\0' : 'f'); - if (crm != 0xff) - m_operands += StringFromFormat("0x%02x,", crm); + if (crm != 0xff) + m_operands += StringFromFormat("0x%02x,", crm); - m_operands += regnames[s]; - } + m_operands += regnames[s]; + } } - void GekkoDisassembler::msr(u32 in, int smode) { - int s = (int)PPCGETD(in); - int sr = (int)(in & 0x000f0000) >> 16; + int s = (int)PPCGETD(in); + int sr = (int)(in & 0x000f0000) >> 16; - if (in & 0x0010f801) - { - ill(in); - } - else - { - m_flags |= PPCF_SUPER; - m_opcode = StringFromFormat("m%csr", smode ? 't' : 'f'); + if (in & 0x0010f801) + { + ill(in); + } + else + { + m_flags |= PPCF_SUPER; + m_opcode = StringFromFormat("m%csr", smode ? 't' : 'f'); - if (smode) - m_operands = StringFromFormat("%d, %s", sr, regnames[s]); - else - m_operands = StringFromFormat("%s, %d", regnames[s], sr); - } + if (smode) + m_operands = StringFromFormat("%d, %s", sr, regnames[s]); + else + m_operands = StringFromFormat("%s, %d", regnames[s], sr); + } } - void GekkoDisassembler::mspr(u32 in, int smode) { - int d = (int)PPCGETD(in); - int spr = (int)((PPCGETB(in) << 5) + PPCGETA(in)); - int fmt = 0; + int d = (int)PPCGETD(in); + int spr = (int)((PPCGETB(in) << 5) + PPCGETA(in)); + int fmt = 0; - if (in & 1) - { - ill(in); - } - else - { - if (spr != 1 && spr != 8 && spr != 9) - m_flags |= PPCF_SUPER; + if (in & 1) + { + ill(in); + } + else + { + if (spr != 1 && spr != 8 && spr != 9) + m_flags |= PPCF_SUPER; - const char* x; - switch (spr) - { - case 1: - x = "xer"; - break; + const char* x; + switch (spr) + { + case 1: + x = "xer"; + break; - case 8: - x = "lr"; - break; + case 8: + x = "lr"; + break; - case 9: - x = "ctr"; - break; + case 9: + x = "ctr"; + break; - default: - x = "spr"; - fmt = 1; - break; - } + default: + x = "spr"; + fmt = 1; + break; + } - m_opcode = StringFromFormat("m%c%s", smode ? 't' : 'f', x); + m_opcode = StringFromFormat("m%c%s", smode ? 't' : 'f', x); - if (fmt) - { - if (smode) - m_operands = StringFromFormat("%s, %s", spr_name(spr).c_str(), regnames[d]); - else - m_operands = StringFromFormat("%s, %s", regnames[d], spr_name(spr).c_str()); - } - else - { - m_operands = regnames[d]; - } - } + if (fmt) + { + if (smode) + m_operands = StringFromFormat("%s, %s", spr_name(spr).c_str(), regnames[d]); + else + m_operands = StringFromFormat("%s, %s", regnames[d], spr_name(spr).c_str()); + } + else + { + m_operands = regnames[d]; + } + } } - void GekkoDisassembler::mtb(u32 in) { - int d = (int)PPCGETD(in); - int tbr = (int)((PPCGETB(in) << 5) + PPCGETA(in)); + int d = (int)PPCGETD(in); + int tbr = (int)((PPCGETB(in) << 5) + PPCGETA(in)); - if (in & 1) - { - ill(in); - } - else - { - m_operands += regnames[d]; + if (in & 1) + { + ill(in); + } + else + { + m_operands += regnames[d]; - char x; - switch (tbr) - { - case 268: - x = 'l'; - break; + char x; + switch (tbr) + { + case 268: + x = 'l'; + break; - case 269: - x = 'u'; - break; + case 269: + x = 'u'; + break; - default: - x = '\0'; - m_flags |= PPCF_SUPER; - m_operands += StringFromFormat(",%d", tbr); - break; - } + default: + x = '\0'; + m_flags |= PPCF_SUPER; + m_operands += StringFromFormat(",%d", tbr); + break; + } - m_opcode = StringFromFormat("mftb%c", x); - } + m_opcode = StringFromFormat("mftb%c", x); + } } - void GekkoDisassembler::sradi(u32 in) { - int s = (int)PPCGETD(in); - int a = (int)PPCGETA(in); - int bsh = (int)(((in & 2) << 4) + PPCGETB(in)); + int s = (int)PPCGETD(in); + int a = (int)PPCGETA(in); + int bsh = (int)(((in & 2) << 4) + PPCGETB(in)); - m_flags |= PPCF_64; - m_opcode = StringFromFormat("sradi%c", in & 1 ? '.' : '\0'); - m_operands = StringFromFormat("%s, %s, %d", regnames[a], regnames[s], bsh); + m_flags |= PPCF_64; + m_opcode = StringFromFormat("sradi%c", in & 1 ? '.' : '\0'); + m_operands = StringFromFormat("%s, %s, %d", regnames[a], regnames[s], bsh); } void GekkoDisassembler::ldst(u32 in, const char* name, char reg, unsigned char dmode) { - int s = (int)PPCGETD(in); - int a = (int)PPCGETA(in); - int d = (u32)(in & 0xffff); + int s = (int)PPCGETD(in); + int a = (int)PPCGETA(in); + int d = (u32)(in & 0xffff); - m_type = PPCINSTR_LDST; - m_flags |= dmode; - m_sreg = (short)a; - // if (d >= 0x8000) - // d -= 0x10000; - m_displacement = (u32)d; - m_opcode = name; + m_type = PPCINSTR_LDST; + m_flags |= dmode; + m_sreg = (short)a; + // if (d >= 0x8000) + // d -= 0x10000; + m_displacement = (u32)d; + m_opcode = name; - if (reg == 'r') - { - m_operands = StringFromFormat("%s, %s (%s)", regnames[s], ldst_offs(d).c_str(), regnames[a]); - } - else - { - m_operands = StringFromFormat("%c%d, %s (%s)", reg, s, ldst_offs(d).c_str(), regnames[a]); - } + if (reg == 'r') + { + m_operands = StringFromFormat("%s, %s (%s)", regnames[s], ldst_offs(d).c_str(), regnames[a]); + } + else + { + m_operands = StringFromFormat("%c%d, %s (%s)", reg, s, ldst_offs(d).c_str(), regnames[a]); + } } // Standard floating point instruction: xxxx fD,fA,fC,fB void GekkoDisassembler::fdabc(u32 in, const char* name, int mask, unsigned char dmode) { - int err = 0; + int err = 0; - m_flags |= dmode; - m_opcode = StringFromFormat("f%s%s", name, rcsel[in & 1]); - m_operands += StringFromFormat("f%d,", (int)PPCGETD(in)); + m_flags |= dmode; + m_opcode = StringFromFormat("f%s%s", name, rcsel[in & 1]); + m_operands += StringFromFormat("f%d,", (int)PPCGETD(in)); - if (mask & 4) - m_operands += StringFromFormat("f%d,", (int)PPCGETA(in)); - else - err |= (int)PPCGETA(in); + if (mask & 4) + m_operands += StringFromFormat("f%d,", (int)PPCGETA(in)); + else + err |= (int)PPCGETA(in); - if (mask & 2) - m_operands += StringFromFormat("f%d,", (int)PPCGETC(in)); - else if (PPCGETC(in)) - err |= (int)PPCGETC(in); + if (mask & 2) + m_operands += StringFromFormat("f%d,", (int)PPCGETC(in)); + else if (PPCGETC(in)) + err |= (int)PPCGETC(in); - if (mask & 1) - m_operands += StringFromFormat("f%d,", (int)PPCGETB(in)); - else if (!(mask & 8)) - err |= (int)PPCGETB(in); + if (mask & 1) + m_operands += StringFromFormat("f%d,", (int)PPCGETB(in)); + else if (!(mask & 8)) + err |= (int)PPCGETB(in); - // Drop the trailing comma - m_operands.pop_back(); + // Drop the trailing comma + m_operands.pop_back(); - if (err) - ill(in); + if (err) + ill(in); } void GekkoDisassembler::fmr(u32 in) { - m_opcode = StringFromFormat("fmr%s", rcsel[in & 1]); - m_operands = StringFromFormat("f%d, f%d", (int)PPCGETD(in), (int)PPCGETB(in)); + m_opcode = StringFromFormat("fmr%s", rcsel[in & 1]); + m_operands = StringFromFormat("f%d, f%d", (int)PPCGETD(in), (int)PPCGETB(in)); } // Indexed float instruction: xxxx fD,rA,rB void GekkoDisassembler::fdab(u32 in, const char* name, int mask) { - m_opcode = name; - m_operands = fd_ra_rb(in, mask); + m_opcode = name; + m_operands = fd_ra_rb(in, mask); } - void GekkoDisassembler::fcmp(u32 in, char c) { - if (in & 0x00600001) - { - ill(in); - } - else - { - m_opcode = StringFromFormat("fcmp%c", c); - m_operands = StringFromFormat("cr%d,f%d,f%d", (int)PPCGETCRD(in), (int)PPCGETA(in), (int)PPCGETB(in)); - } + if (in & 0x00600001) + { + ill(in); + } + else + { + m_opcode = StringFromFormat("fcmp%c", c); + m_operands = + StringFromFormat("cr%d,f%d,f%d", (int)PPCGETCRD(in), (int)PPCGETA(in), (int)PPCGETB(in)); + } } - void GekkoDisassembler::mtfsb(u32 in, int n) { - if (in & (PPCAMASK | PPCBMASK)) - { - ill(in); - } - else - { - m_opcode = StringFromFormat("mtfsb%d%s", n, rcsel[in & 1]); - m_operands = StringFromFormat("%d", (int)PPCGETD(in)); - } + if (in & (PPCAMASK | PPCBMASK)) + { + ill(in); + } + else + { + m_opcode = StringFromFormat("mtfsb%d%s", n, rcsel[in & 1]); + m_operands = StringFromFormat("%d", (int)PPCGETD(in)); + } } - // Paired instructions #define RA ((inst >> 16) & 0x1f) @@ -986,1304 +1018,1299 @@ void GekkoDisassembler::mtfsb(u32 in, int n) #define IX ((inst >> 7) & 0x7) #define WX ((inst >> 10) & 0x1) - void GekkoDisassembler::ps(u32 inst) { - switch ((inst >> 1) & 0x1F) - { - case 6: - m_opcode = inst & 0x40 ? "psq_lux" : "psq_lx"; - m_operands = StringFromFormat("p%u, (r%u + r%u), %d, qr%d", FD, RA, RB, WX, IX); - return; + switch ((inst >> 1) & 0x1F) + { + case 6: + m_opcode = inst & 0x40 ? "psq_lux" : "psq_lx"; + m_operands = StringFromFormat("p%u, (r%u + r%u), %d, qr%d", FD, RA, RB, WX, IX); + return; - case 7: - m_opcode = inst & 0x40 ? "psq_stux" : "psq_stx"; - m_operands = StringFromFormat("p%u, r%u, r%u, %d, qr%d", FS, RA, RB, WX, IX); - return; + case 7: + m_opcode = inst & 0x40 ? "psq_stux" : "psq_stx"; + m_operands = StringFromFormat("p%u, r%u, r%u, %d, qr%d", FS, RA, RB, WX, IX); + return; - case 18: - m_opcode = "ps_div"; - m_operands = StringFromFormat("p%u, p%u/p%u", FD, FA, FB); - return; + case 18: + m_opcode = "ps_div"; + m_operands = StringFromFormat("p%u, p%u/p%u", FD, FA, FB); + return; - case 20: - m_opcode = "ps_sub"; - m_operands = StringFromFormat("p%u, p%u-p%u", FD, FA, FB); - return; + case 20: + m_opcode = "ps_sub"; + m_operands = StringFromFormat("p%u, p%u-p%u", FD, FA, FB); + return; - case 21: - m_opcode = "ps_add"; - m_operands = StringFromFormat("p%u, p%u+p%u", FD, FA, FB); - return; + case 21: + m_opcode = "ps_add"; + m_operands = StringFromFormat("p%u, p%u+p%u", FD, FA, FB); + return; - case 23: - m_opcode = "ps_sel"; - m_operands = StringFromFormat("p%u>=0?p%u:p%u", FD, FA, FC); - return; + case 23: + m_opcode = "ps_sel"; + m_operands = StringFromFormat("p%u>=0?p%u:p%u", FD, FA, FC); + return; - case 24: - m_opcode = "ps_res"; - m_operands = StringFromFormat("p%u, (1/p%u)", FD, FB); - return; + case 24: + m_opcode = "ps_res"; + m_operands = StringFromFormat("p%u, (1/p%u)", FD, FB); + return; - case 25: - m_opcode = "ps_mul"; - m_operands = StringFromFormat("p%u, p%u*p%u", FD, FA, FC); - return; + case 25: + m_opcode = "ps_mul"; + m_operands = StringFromFormat("p%u, p%u*p%u", FD, FA, FC); + return; - case 26: // rsqrte - m_opcode = "ps_rsqrte"; - m_operands = StringFromFormat("p%u, p%u", FD, FB); - return; + case 26: // rsqrte + m_opcode = "ps_rsqrte"; + m_operands = StringFromFormat("p%u, p%u", FD, FB); + return; - case 28: // msub - m_opcode = "ps_msub"; - m_operands = StringFromFormat("p%u, p%u*p%u-p%u", FD, FA, FC, FB); - return; + case 28: // msub + m_opcode = "ps_msub"; + m_operands = StringFromFormat("p%u, p%u*p%u-p%u", FD, FA, FC, FB); + return; - case 29: // madd - m_opcode = "ps_madd"; - m_operands = StringFromFormat("p%u, p%u*p%u+p%u", FD, FA, FC, FB); - return; + case 29: // madd + m_opcode = "ps_madd"; + m_operands = StringFromFormat("p%u, p%u*p%u+p%u", FD, FA, FC, FB); + return; - case 30: // nmsub - m_opcode = "ps_nmsub"; - m_operands = StringFromFormat("p%u, -(p%u*p%u-p%u)", FD, FA, FC, FB); - return; + case 30: // nmsub + m_opcode = "ps_nmsub"; + m_operands = StringFromFormat("p%u, -(p%u*p%u-p%u)", FD, FA, FC, FB); + return; - case 31: // nmadd - m_opcode = "ps_nmadd"; - m_operands = StringFromFormat("p%u, -(p%u*p%u+p%u)", FD, FA, FC, FB); - return; + case 31: // nmadd + m_opcode = "ps_nmadd"; + m_operands = StringFromFormat("p%u, -(p%u*p%u+p%u)", FD, FA, FC, FB); + return; - case 10: - m_opcode = "ps_sum0"; - m_operands = StringFromFormat("p%u, 0=p%u+p%u, 1=p%u", FD, FA, FB, FC); - return; + case 10: + m_opcode = "ps_sum0"; + m_operands = StringFromFormat("p%u, 0=p%u+p%u, 1=p%u", FD, FA, FB, FC); + return; - case 11: - m_opcode = "ps_sum1"; - m_operands = StringFromFormat("p%u, 0=p%u, 1=p%u+p%u", FD, FC, FA, FB); - return; + case 11: + m_opcode = "ps_sum1"; + m_operands = StringFromFormat("p%u, 0=p%u, 1=p%u+p%u", FD, FC, FA, FB); + return; - case 12: - m_opcode = "ps_muls0"; - m_operands = StringFromFormat("p%u, p%u*p%u[0]", FD, FA, FC); - return; + case 12: + m_opcode = "ps_muls0"; + m_operands = StringFromFormat("p%u, p%u*p%u[0]", FD, FA, FC); + return; - case 13: - m_opcode = "ps_muls1"; - m_operands = StringFromFormat("p%u, p%u*p%u[1]", FD, FA, FC); - return; + case 13: + m_opcode = "ps_muls1"; + m_operands = StringFromFormat("p%u, p%u*p%u[1]", FD, FA, FC); + return; - case 14: - m_opcode = "ps_madds0"; - m_operands = StringFromFormat("p%u, p%u*p%u[0]+p%u", FD, FA, FC, FB); - return; + case 14: + m_opcode = "ps_madds0"; + m_operands = StringFromFormat("p%u, p%u*p%u[0]+p%u", FD, FA, FC, FB); + return; - case 15: - m_opcode = "ps_madds1"; - m_operands = StringFromFormat("p%u, p%u*p%u[1]+p%u", FD, FA, FC, FB); - return; - } + case 15: + m_opcode = "ps_madds1"; + m_operands = StringFromFormat("p%u, p%u*p%u[1]+p%u", FD, FA, FC, FB); + return; + } - switch ((inst >> 1) & 0x3FF) - { - // 10-bit suckers (?) - case 40: // nmadd - m_opcode = "ps_neg"; - m_operands = StringFromFormat("p%u, -p%u", FD, FB); - return; + switch ((inst >> 1) & 0x3FF) + { + // 10-bit suckers (?) + case 40: // nmadd + m_opcode = "ps_neg"; + m_operands = StringFromFormat("p%u, -p%u", FD, FB); + return; - case 72: // nmadd - m_opcode = "ps_mr"; - m_operands = StringFromFormat("p%u, p%u", FD, FB); - return; + case 72: // nmadd + m_opcode = "ps_mr"; + m_operands = StringFromFormat("p%u, p%u", FD, FB); + return; - case 136: - m_opcode = "ps_nabs"; - m_operands = StringFromFormat("p%u, -|p%u|", FD, FB); - return; + case 136: + m_opcode = "ps_nabs"; + m_operands = StringFromFormat("p%u, -|p%u|", FD, FB); + return; - case 264: - m_opcode = "ps_abs"; - m_operands = StringFromFormat("p%u, |p%u|", FD, FB); - return; + case 264: + m_opcode = "ps_abs"; + m_operands = StringFromFormat("p%u, |p%u|", FD, FB); + return; - case 0: - case 32: - case 64: - case 96: - { - m_opcode = ps_cmpname[(inst >> 6) & 0x3]; + case 0: + case 32: + case 64: + case 96: + { + m_opcode = ps_cmpname[(inst >> 6) & 0x3]; - int i = (int)PPCGETCRD(inst); - if (i != 0) - m_operands += StringFromFormat("cr%c, ", '0' + i); - m_operands += StringFromFormat("p%u, p%u", FA, FB); - return; - } - case 528: - m_opcode = "ps_merge00"; - m_operands = StringFromFormat("p%u, p%u[0],p%u[0]", FD, FA, FB); - return; + int i = (int)PPCGETCRD(inst); + if (i != 0) + m_operands += StringFromFormat("cr%c, ", '0' + i); + m_operands += StringFromFormat("p%u, p%u", FA, FB); + return; + } + case 528: + m_opcode = "ps_merge00"; + m_operands = StringFromFormat("p%u, p%u[0],p%u[0]", FD, FA, FB); + return; - case 560: - m_opcode = "ps_merge01"; - m_operands = StringFromFormat("p%u, p%u[0],p%u[1]", FD, FA, FB); - return; + case 560: + m_opcode = "ps_merge01"; + m_operands = StringFromFormat("p%u, p%u[0],p%u[1]", FD, FA, FB); + return; - case 592: - m_opcode = "ps_merge10"; - m_operands = StringFromFormat("p%u, p%u[1],p%u[0]", FD, FA, FB); - return; + case 592: + m_opcode = "ps_merge10"; + m_operands = StringFromFormat("p%u, p%u[1],p%u[0]", FD, FA, FB); + return; - case 624: - m_opcode = "ps_merge11"; - m_operands = StringFromFormat("p%u, p%u[1],p%u[1]", FD, FA, FB); - return; + case 624: + m_opcode = "ps_merge11"; + m_operands = StringFromFormat("p%u, p%u[1],p%u[1]", FD, FA, FB); + return; - case 1014: - if (inst & PPCDMASK) - ill(inst); - else - dab(inst, "dcbz_l", 3, 0, 0, 0, 0); - } + case 1014: + if (inst & PPCDMASK) + ill(inst); + else + dab(inst, "dcbz_l", 3, 0, 0, 0, 0); + } - // default: - m_opcode = StringFromFormat("ps_%i", ((inst >> 1) & 0x1f)); - m_operands = "---"; + // default: + m_opcode = StringFromFormat("ps_%i", ((inst >> 1) & 0x1f)); + m_operands = "---"; } void GekkoDisassembler::ps_mem(u32 inst) { - switch (PPCGETIDX(inst)) - { - case 56: - m_opcode = "psq_l"; - m_operands = StringFromFormat("p%u, %i(r%u), %d, qr%d", RS, SEX12(inst & 0xFFF), RA, W, I); - break; + switch (PPCGETIDX(inst)) + { + case 56: + m_opcode = "psq_l"; + m_operands = StringFromFormat("p%u, %i(r%u), %d, qr%d", RS, SEX12(inst & 0xFFF), RA, W, I); + break; - case 57: - m_opcode = "psq_lu"; - m_operands = StringFromFormat("p%u, %i(r%u), %d, qr%d", RS, SEX12(inst & 0xFFF), RA, W, I);; - break; + case 57: + m_opcode = "psq_lu"; + m_operands = StringFromFormat("p%u, %i(r%u), %d, qr%d", RS, SEX12(inst & 0xFFF), RA, W, I); + ; + break; - case 60: - m_opcode = "psq_st"; - m_operands = StringFromFormat("p%u, %i(r%u), %d, qr%d", RS, SEX12(inst & 0xFFF), RA, W, I); - break; + case 60: + m_opcode = "psq_st"; + m_operands = StringFromFormat("p%u, %i(r%u), %d, qr%d", RS, SEX12(inst & 0xFFF), RA, W, I); + break; - case 61: - m_opcode = "psq_stu"; - m_operands = StringFromFormat("p%u, %i(r%u), %d, qr%d", RS, SEX12(inst & 0xFFF), RA, W, I); - break; - } + case 61: + m_opcode = "psq_stu"; + m_operands = StringFromFormat("p%u, %i(r%u), %d, qr%d", RS, SEX12(inst & 0xFFF), RA, W, I); + break; + } } // Disassemble PPC instruction and return a pointer to the next // instruction, or nullptr if an error occurred. u32* GekkoDisassembler::DoDisassembly(bool big_endian) { - u32 in = *m_instr; - - if (!big_endian) - { - in = (in & 0xff) << 24 | (in & 0xff00) << 8 | (in & 0xff0000) >> 8 | - (in & 0xff000000) >> 24; - } - - m_opcode.clear(); - m_operands.clear(); - m_type = PPCINSTR_OTHER; - m_flags = 0; - - switch (PPCGETIDX(in)) - { - case 2: - trapi(in, PPCF_64); // tdi - break; - - case 3: - trapi(in, 0); // twi - break; - - case 4: - ps(in); - break; - - case 56: - case 57: - case 60: - case 61: - ps_mem(in); - break; - - case 7: - m_opcode = "mulli"; - m_operands = imm(in, 0, 0, false); - break; - - case 8: - m_opcode = "subfic"; - m_operands = imm(in, 0, 0, false); - break; - - case 10: - cmpi(in, 1); // cmpli - break; - - case 11: - cmpi(in, 0); // cmpi - break; - - case 12: - addi(in, "ic"); // addic - break; - - case 13: - addi(in, "ic."); // addic. - break; - - case 14: - addi(in, "i"); // addi - break; - - case 15: - addi(in, "is"); // addis - break; - - case 16: - bc(in); - break; - - case 17: - if ((in & ~PPCIDXMASK) == 2) - m_opcode = "sc"; - else - ill(in); - break; - - case 18: - bli(in); - break; - - case 19: - switch (PPCGETIDX2(in)) - { - case 0: - mcrf(in, '\0'); // mcrf - break; - - case 16: - branch(in, "lr", 0, 0); // bclr - break; - - case 33: - crop(in, "nor", "not"); // crnor - break; - - case 50: - nooper(in, "rfi", PPCF_SUPER); - break; - - case 129: - crop(in, "andc", nullptr); // crandc - break; - - case 150: - nooper(in, "isync", 0); - break; - - case 193: - crop(in, "xor", "clr"); // crxor - break; - - case 225: - crop(in, "nand", nullptr); // crnand - break; - - case 257: - crop(in, "and", nullptr); // crand - break; - - case 289: - crop(in, "eqv", "set"); // creqv - break; - - case 417: - crop(in, "orc", nullptr); // crorc - break; - - case 449: - crop(in, "or", "move"); // cror - break; - - case 528: - branch(in, "ctr", 0, 0); // bcctr - break; - - default: - ill(in); - break; - } - break; - - case 20: - rlw(in, "imi", 0); // rlwimi - break; - - case 21: - rlw(in, "inm", 0); // rlwinm - break; - - case 23: - rlw(in, "nm", 1); // rlwnm - break; - - case 24: - if (in & ~PPCIDXMASK) - ori(in, "ori"); - else - m_opcode = "nop"; - break; - - case 25: - ori(in, "oris"); - break; - - case 26: - ori(in, "xori"); - break; - - case 27: - ori(in, "xoris"); - break; - - case 28: - ori(in, "andi."); - break; - - case 29: - ori(in, "andis."); - break; - - case 30: - switch (in & 0x1c) - { - case 0: - rld(in, "icl", 0); // rldicl - break; - case 1: - rld(in, "icr", 0); // rldicr - break; - case 2: - rld(in, "ic", 0); // rldic - break; - case 3: - rld(in, "imi", 0); // rldimi - break; - case 4: - rld(in, in & 2 ? "cl" : "cr", 1); // rldcl, rldcr - break; - default: - ill(in); - break; - } - break; - - case 31: - switch (PPCGETIDX2(in)) - { - case 0: - case 32: - if (in & 1) - ill(in); - else - cmp(in); // cmp, cmpl - break; - - case 4: - if (in & 1) - ill(in); - else - trap(in, 0); // tw - break; - - case 8: - case (PPCOE >> 1) + 8: - dab(swapab(in), "subc", 7, 0, 1, -1, 0); - break; - - case 9: - dab(in, "mulhdu", 7, 0, 0, -1, PPCF_64); - break; - - case 10: - case (PPCOE >> 1) + 10: - dab(in, "addc", 7, 0, 1, -1, 0); - break; - - case 11: - dab(in, "mulhwu", 7, 0, 0, -1, 0); - break; - - case 19: - if (in & (PPCAMASK | PPCBMASK)) - ill(in); - else - dab(in, "mfcr", 4, 0, 0, 0, 0); - break; - - case 20: - dab(in, "lwarx", 7, 0, 0, 0, 0); - break; - - case 21: - dab(in, "ldx", 7, 0, 0, 0, PPCF_64); - break; - - case 23: - dab(in, "lwzx", 7, 0, 0, 0, 0); - break; - - case 24: - dab(in, "slw", 7, 1, 0, -1, 0); - break; - - case 26: - if (in & PPCBMASK) - ill(in); - else - dab(in, "cntlzw", 6, 1, 0, -1, 0); - break; - - case 27: - dab(in, "sld", 7, 1, 0, -1, PPCF_64); - break; - - case 28: - dab(in, "and", 7, 1, 0, -1, 0); - break; - - case 40: - case (PPCOE >> 1) + 40: - dab(swapab(in), "sub", 7, 0, 1, -1, 0); - break; - - case 53: - dab(in, "ldux", 7, 0, 0, 0, PPCF_64); - break; - - case 54: - if (in & PPCDMASK) - ill(in); - else - dab(in, "dcbst", 3, 0, 0, 0, 0); - break; - - case 55: - dab(in, "lwzux", 7, 0, 0, 0, 0); - break; - - case 58: - if (in & PPCBMASK) - ill(in); - else - dab(in, "cntlzd", 6, 1, 0, -1, PPCF_64); - break; - - case 60: - dab(in, "andc", 7, 1, 0, -1, 0); - break; - - case 68: - trap(in, PPCF_64); // td - break; - - case 73: - dab(in, "mulhd", 7, 0, 0, -1, PPCF_64); - break; - - case 75: - dab(in, "mulhw", 7, 0, 0, -1, 0); - break; - - case 83: - if (in & (PPCAMASK | PPCBMASK)) - ill(in); - else - dab(in, "mfmsr", 4, 0, 0, 0, PPCF_SUPER); - break; - - case 84: - dab(in, "ldarx", 7, 0, 0, 0, PPCF_64); - break; - - case 86: - if (in & PPCDMASK) - ill(in); - else - dab(in, "dcbf", 3, 0, 0, 0, 0); - break; - - case 87: - dab(in, "lbzx", 7, 0, 0, 0, 0); - break; - - case 104: - case (PPCOE >> 1) + 104: - if (in & PPCBMASK) - ill(in); - else - dab(in, "neg", 6, 0, 1, -1, 0); - break; - - case 119: - dab(in, "lbzux", 7, 0, 0, 0, 0); - break; - - case 124: - if (PPCGETD(in) == PPCGETB(in)) - dab(in, "not", 6, 1, 0, -1, 0); - else - dab(in, "nor", 7, 1, 0, -1, 0); - break; - - case 136: - case (PPCOE >> 1) + 136: - dab(in, "subfe", 7, 0, 1, -1, 0); - break; - - case 138: - case (PPCOE >> 1) + 138: - dab(in, "adde", 7, 0, 1, -1, 0); - break; - - case 144: - mtcr(in); - break; - - case 146: - if (in & (PPCAMASK | PPCBMASK)) - ill(in); - else - dab(in, "mtmsr", 4, 0, 0, 0, PPCF_SUPER); - break; - - case 149: - dab(in, "stdx", 7, 0, 0, 0, PPCF_64); - break; - - case 150: - dab(in, "stwcx.", 7, 0, 0, 1, 0); - break; - - case 151: - dab(in, "stwx", 7, 0, 0, 0, 0); - break; - - case 181: - dab(in, "stdux", 7, 0, 0, 0, PPCF_64); - break; - - case 183: - dab(in, "stwux", 7, 0, 0, 0, 0); - break; - - case 200: - case (PPCOE >> 1) + 200: - if (in & PPCBMASK) - ill(in); - else - dab(in, "subfze", 6, 0, 1, -1, 0); - break; - - case 202: - case (PPCOE >> 1) + 202: - if (in & PPCBMASK) - ill(in); - else - dab(in, "addze", 6, 0, 1, -1, 0); - break; - - case 210: - msr(in, 1); // mfsr - break; - - case 214: - dab(in, "stdcx.", 7, 0, 0, 1, PPCF_64); - break; - - case 215: - dab(in, "stbx", 7, 0, 0, 0, 0); - break; - - case 232: - case (PPCOE >> 1) + 232: - if (in & PPCBMASK) - ill(in); - else - dab(in, "subfme", 6, 0, 1, -1, 0); - break; - - case 233: - case (PPCOE >> 1) + 233: - dab(in, "mulld", 7, 0, 1, -1, PPCF_64); - break; - - case 234: - case (PPCOE >> 1) + 234: - if (in & PPCBMASK) - ill(in); - else - dab(in, "addme", 6, 0, 1, -1, 0); - break; - - case 235: - case (PPCOE >> 1) + 235: - dab(in, "mullw", 7, 0, 1, -1, 0); - break; - - case 242: - if (in & PPCAMASK) - ill(in); - else - dab(in, "mtsrin", 5, 0, 0, 0, PPCF_SUPER); - break; - - case 246: - if (in & PPCDMASK) - ill(in); - else - dab(in, "dcbtst", 3, 0, 0, 0, 0); - break; - - case 247: - dab(in, "stbux", 7, 0, 0, 0, 0); - break; - - case 266: - case (PPCOE >> 1) + 266: - dab(in, "add", 7, 0, 1, -1, 0); - break; - - case 278: - if (in & PPCDMASK) - ill(in); - else - dab(in, "dcbt", 3, 0, 0, 0, 0); - break; - - case 279: - dab(in, "lhzx", 7, 0, 0, 0, 0); - break; - - case 284: - dab(in, "eqv", 7, 1, 0, -1, 0); - break; - - case 306: - if (in & (PPCDMASK | PPCAMASK)) - ill(in); - else - dab(in, "tlbie", 1, 0, 0, 0, PPCF_SUPER); - break; - - case 310: - dab(in, "eciwx", 7, 0, 0, 0, 0); - break; - - case 311: - dab(in, "lhzux", 7, 0, 0, 0, 0); - break; - - case 316: - dab(in, "xor", 7, 1, 0, -1, 0); - break; - - case 339: - mspr(in, 0); // mfspr - break; - - case 341: - dab(in, "lwax", 7, 0, 0, 0, PPCF_64); - break; - - case 343: - dab(in, "lhax", 7, 0, 0, 0, 0); - break; - - case 370: - nooper(in, "tlbia", PPCF_SUPER); - break; - - case 371: - mtb(in); // mftb - break; - - case 373: - dab(in, "lwaux", 7, 0, 0, 0, PPCF_64); - break; - - case 375: - dab(in, "lhaux", 7, 0, 0, 0, 0); - break; - - case 407: - dab(in, "sthx", 7, 0, 0, 0, 0); - break; - - case 412: - dab(in, "orc", 7, 1, 0, -1, 0); - break; - - case 413: - sradi(in); // sradi - break; - - case 434: - if (in & (PPCDMASK | PPCAMASK)) - ill(in); - else - dab(in, "slbie", 1, 0, 0, 0, PPCF_SUPER | PPCF_64); - break; - - case 438: - dab(in, "ecowx", 7, 0, 0, 0, 0); - break; - - case 439: - dab(in, "sthux", 7, 0, 0, 0, 0); - break; - - case 444: - if (PPCGETD(in) == PPCGETB(in)) - dab(in, "mr", 6, 1, 0, -1, 0); - else - dab(in, "or", 7, 1, 0, -1, 0); - break; - - case 457: - case (PPCOE >> 1) + 457: - dab(in, "divdu", 7, 0, 1, -1, PPCF_64); - break; - - case 459: - case (PPCOE >> 1) + 459: - dab(in, "divwu", 7, 0, 1, -1, 0); - break; - - case 467: - mspr(in, 1); // mtspr - break; - - case 470: - if (in & PPCDMASK) - ill(in); - else - dab(in, "dcbi", 3, 0, 0, 0, 0); - break; - - case 476: - dab(in, "nand", 7, 1, 0, -1, 0); - break; - - case 489: - case (PPCOE >> 1) + 489: - dab(in, "divd", 7, 0, 1, -1, PPCF_64); - break; - - case 491: - case (PPCOE >> 1) + 491: - dab(in, "divw", 7, 0, 1, -1, 0); - break; - - case 498: - nooper(in, "slbia", PPCF_SUPER | PPCF_64); - break; - - case 512: - if (in & 0x007ff801) - { - ill(in); - } - else - { - m_opcode = "mcrxr"; - m_operands = StringFromFormat("cr%d", (int)PPCGETCRD(in)); - } - break; - - case 533: - dab(in, "lswx", 7, 0, 0, 0, 0); - break; - - case 534: - dab(in, "lwbrx", 7, 0, 0, 0, 0); - break; - - case 535: - fdab(in, "lfsx", 7); - break; - - case 536: - dab(in, "srw", 7, 1, 0, -1, 0); - break; - - case 539: - dab(in, "srd", 7, 1, 0, -1, PPCF_64); - break; - - case 566: - nooper(in, "tlbsync", PPCF_SUPER); - break; - - case 567: - fdab(in, "lfsux", 7); - break; - - case 595: - msr(in, 0); // mfsr - break; - - case 597: - rrn(in, "lswi", 0, 0, 0, 0); - break; - - case 598: - nooper(in, "sync", PPCF_SUPER); - break; - - case 599: - fdab(in, "lfdx", 7); - break; - - case 631: - fdab(in, "lfdux", 7); - break; - - case 659: - if (in & PPCAMASK) - ill(in); - else - dab(in, "mfsrin", 5, 0, 0, 0, PPCF_SUPER); - break; - - case 661: - dab(in, "stswx", 7, 0, 0, 0, 0); - break; - - case 662: - dab(in, "stwbrx", 7, 0, 0, 0, 0); - break; - - case 663: - fdab(in, "stfsx", 7); - break; - - case 695: - fdab(in, "stfsux", 7); - break; - - case 725: - rrn(in, "stswi", 0, 0, 0, 0); - break; - - case 727: - fdab(in, "stfdx", 7); - break; - - case 759: - fdab(in, "stfdux", 7); - break; - - case 790: - dab(in, "lhbrx", 7, 0, 0, 0, 0); - break; - - case 792: - dab(in, "sraw", 7, 1, 0, -1, 0); - break; - - case 794: - dab(in, "srad", 7, 1, 0, -1, PPCF_64); - break; - - case 824: - rrn(in, "srawi", 1, 0, -1, 0); - break; - - case 854: - nooper(in, "eieio", PPCF_SUPER); - break; - - case 918: - dab(in, "sthbrx", 7, 0, 0, 0, 0); - break; - - case 922: - if (in & PPCBMASK) - ill(in); - else - dab(in, "extsh", 6, 1, 0, -1, 0); - break; - - case 954: - if (in & PPCBMASK) - ill(in); - else - dab(in, "extsb", 6, 1, 0, -1, 0); - break; - - case 982: - if (in & PPCDMASK) - ill(in); - else - dab(in, "icbi", 3, 0, 0, 0, 0); - break; - - case 983: - fdab(in, "stfiwx", 7); - break; - - case 986: - if (in & PPCBMASK) - ill(in); - else - dab(in, "extsw", 6, 1, 0, -1, PPCF_64); - break; - - case 1014: - if (in & PPCDMASK) - ill(in); - else - dab(in, "dcbz", 3, 0, 0, 0, 0); - break; - - default: - ill(in); - break; - } - break; - - case 32: - case 33: - case 34: - case 35: - case 36: - case 37: - case 38: - case 39: - case 40: - case 41: - case 42: - case 43: - case 44: - case 45: - case 46: - case 47: - ldst(in, ldstnames[PPCGETIDX(in) - 32], 'r', 0); - break; - - case 48: - case 49: - case 50: - case 51: - case 52: - case 53: - case 54: - case 55: - ldst(in, ldstnames[PPCGETIDX(in) - 32], 'f', 0); - break; - - case 58: - switch (in & 3) - { - case 0: - ldst(in&~3, "ld", 'r', PPCF_64); - break; - case 1: - ldst(in&~3, "ldu", 'r', PPCF_64); - break; - case 2: - ldst(in&~3, "lwa", 'r', PPCF_64); - break; - default: - ill(in); - break; - } - break; - - case 59: - switch (in & 0x3e) - { - case 36: - fdabc(in, "divs", 5, 0); - break; - - case 40: - fdabc(in, "subs", 5, 0); - break; - - case 42: - fdabc(in, "adds", 5, 0); - break; - - case 44: - fdabc(in, "sqrts", 1, 0); - break; - - case 48: - fdabc(in, "res", 1, 0); - break; - - case 50: - fdabc(in, "muls", 6, 0); - break; - - case 56: - fdabc(in, "msubs", 7, 0); - break; - - case 58: - fdabc(in, "madds", 7, 0); - break; - - case 60: - fdabc(in, "nmsubs", 7, 0); - break; - - case 62: - fdabc(in, "nmadds", 7, 0); - break; - - default: - ill(in); - break; - } - break; - - case 62: - switch (in & 3) - { - case 0: - ldst(in&~3, "std", 'r', PPCF_64); - break; - case 1: - ldst(in&~3, "stdu", 'r', PPCF_64); - break; - default: - ill(in); - break; - } - break; - - case 63: - if (in & 32) - { - switch (in & 0x1e) - { - case 4: - fdabc(in, "div", 5, 0); - break; - - case 8: - fdabc(in, "sub", 5, 0); - break; - - case 10: - fdabc(in, "add", 5, 0); - break; - - case 12: - fdabc(in, "sqrt", 1, 0); - break; - - case 14: - fdabc(in, "sel", 7, 0); - break; - - case 18: - fdabc(in, "mul", 6, 0); - break; - - case 20: - fdabc(in, "rsqrte", 1, 0); - break; - - case 24: - fdabc(in, "msub", 7, 0); - break; - - case 26: - fdabc(in, "madd", 7, 0); - break; - - case 28: - fdabc(in, "nmsub", 7, 0); - break; - - case 30: - fdabc(in, "nmadd", 7, 0); - break; - - default: - ill(in); - break; - } - } - else - { - switch (PPCGETIDX2(in)) - { - case 0: - fcmp(in, 'u'); - break; - - case 12: - fdabc(in, "rsp", 1, 0); - break; - - case 14: - fdabc(in, "ctiw", 1, 0); - break; - - case 15: - fdabc(in, "ctiwz", 1, 0); - break; - - case 32: - fcmp(in, 'o'); - break; - - case 38: - mtfsb(in, 1); - break; - - case 40: - fdabc(in, "neg", 10, 0); - break; - - case 64: - mcrf(in, 's'); // mcrfs - break; - - case 70: - mtfsb(in, 0); - break; - - case 72: - fmr(in); - break; - - case 134: - if ((in & 0x006f0800) == 0) - { - m_opcode = StringFromFormat("mtfsfi%s", rcsel[in & 1]); - m_operands = StringFromFormat("cr%d,%d", (int)PPCGETCRD(in), (int)(in & 0xf000) >> 12); - } - else - { - ill(in); - } - break; - - case 136: - fdabc(in, "nabs", 10, 0); - break; - - case 264: - fdabc(in, "abs", 10, 0); - break; - - case 583: - if (in & (PPCAMASK | PPCBMASK)) - ill(in); - else - dab(in, "mffs", 4, 0, 0, -1, 0); - break; - - case 711: - if ((in & 0x02010000) == 0) - { - m_opcode = StringFromFormat("mtfsf%s", rcsel[in & 1]); - m_operands = StringFromFormat("0x%x,%u", (unsigned int)(in >> 17) & 0x01fe, (unsigned int)PPCGETB(in)); - } - else - { - ill(in); - } - break; - - case 814: - fdabc(in, "fctid", 10, PPCF_64); - break; - - case 815: - fdabc(in, "fctidz", 10, PPCF_64); - break; - - case 846: - fdabc(in, "fcfid", 10, PPCF_64); - break; - - default: - ill(in); - break; - } - } - break; - - default: - ill(in); - break; - } - return (m_instr + 1); + u32 in = *m_instr; + + if (!big_endian) + { + in = (in & 0xff) << 24 | (in & 0xff00) << 8 | (in & 0xff0000) >> 8 | (in & 0xff000000) >> 24; + } + + m_opcode.clear(); + m_operands.clear(); + m_type = PPCINSTR_OTHER; + m_flags = 0; + + switch (PPCGETIDX(in)) + { + case 2: + trapi(in, PPCF_64); // tdi + break; + + case 3: + trapi(in, 0); // twi + break; + + case 4: + ps(in); + break; + + case 56: + case 57: + case 60: + case 61: + ps_mem(in); + break; + + case 7: + m_opcode = "mulli"; + m_operands = imm(in, 0, 0, false); + break; + + case 8: + m_opcode = "subfic"; + m_operands = imm(in, 0, 0, false); + break; + + case 10: + cmpi(in, 1); // cmpli + break; + + case 11: + cmpi(in, 0); // cmpi + break; + + case 12: + addi(in, "ic"); // addic + break; + + case 13: + addi(in, "ic."); // addic. + break; + + case 14: + addi(in, "i"); // addi + break; + + case 15: + addi(in, "is"); // addis + break; + + case 16: + bc(in); + break; + + case 17: + if ((in & ~PPCIDXMASK) == 2) + m_opcode = "sc"; + else + ill(in); + break; + + case 18: + bli(in); + break; + + case 19: + switch (PPCGETIDX2(in)) + { + case 0: + mcrf(in, '\0'); // mcrf + break; + + case 16: + branch(in, "lr", 0, 0); // bclr + break; + + case 33: + crop(in, "nor", "not"); // crnor + break; + + case 50: + nooper(in, "rfi", PPCF_SUPER); + break; + + case 129: + crop(in, "andc", nullptr); // crandc + break; + + case 150: + nooper(in, "isync", 0); + break; + + case 193: + crop(in, "xor", "clr"); // crxor + break; + + case 225: + crop(in, "nand", nullptr); // crnand + break; + + case 257: + crop(in, "and", nullptr); // crand + break; + + case 289: + crop(in, "eqv", "set"); // creqv + break; + + case 417: + crop(in, "orc", nullptr); // crorc + break; + + case 449: + crop(in, "or", "move"); // cror + break; + + case 528: + branch(in, "ctr", 0, 0); // bcctr + break; + + default: + ill(in); + break; + } + break; + + case 20: + rlw(in, "imi", 0); // rlwimi + break; + + case 21: + rlw(in, "inm", 0); // rlwinm + break; + + case 23: + rlw(in, "nm", 1); // rlwnm + break; + + case 24: + if (in & ~PPCIDXMASK) + ori(in, "ori"); + else + m_opcode = "nop"; + break; + + case 25: + ori(in, "oris"); + break; + + case 26: + ori(in, "xori"); + break; + + case 27: + ori(in, "xoris"); + break; + + case 28: + ori(in, "andi."); + break; + + case 29: + ori(in, "andis."); + break; + + case 30: + switch (in & 0x1c) + { + case 0: + rld(in, "icl", 0); // rldicl + break; + case 1: + rld(in, "icr", 0); // rldicr + break; + case 2: + rld(in, "ic", 0); // rldic + break; + case 3: + rld(in, "imi", 0); // rldimi + break; + case 4: + rld(in, in & 2 ? "cl" : "cr", 1); // rldcl, rldcr + break; + default: + ill(in); + break; + } + break; + + case 31: + switch (PPCGETIDX2(in)) + { + case 0: + case 32: + if (in & 1) + ill(in); + else + cmp(in); // cmp, cmpl + break; + + case 4: + if (in & 1) + ill(in); + else + trap(in, 0); // tw + break; + + case 8: + case (PPCOE >> 1) + 8: + dab(swapab(in), "subc", 7, 0, 1, -1, 0); + break; + + case 9: + dab(in, "mulhdu", 7, 0, 0, -1, PPCF_64); + break; + + case 10: + case (PPCOE >> 1) + 10: + dab(in, "addc", 7, 0, 1, -1, 0); + break; + + case 11: + dab(in, "mulhwu", 7, 0, 0, -1, 0); + break; + + case 19: + if (in & (PPCAMASK | PPCBMASK)) + ill(in); + else + dab(in, "mfcr", 4, 0, 0, 0, 0); + break; + + case 20: + dab(in, "lwarx", 7, 0, 0, 0, 0); + break; + + case 21: + dab(in, "ldx", 7, 0, 0, 0, PPCF_64); + break; + + case 23: + dab(in, "lwzx", 7, 0, 0, 0, 0); + break; + + case 24: + dab(in, "slw", 7, 1, 0, -1, 0); + break; + + case 26: + if (in & PPCBMASK) + ill(in); + else + dab(in, "cntlzw", 6, 1, 0, -1, 0); + break; + + case 27: + dab(in, "sld", 7, 1, 0, -1, PPCF_64); + break; + + case 28: + dab(in, "and", 7, 1, 0, -1, 0); + break; + + case 40: + case (PPCOE >> 1) + 40: + dab(swapab(in), "sub", 7, 0, 1, -1, 0); + break; + + case 53: + dab(in, "ldux", 7, 0, 0, 0, PPCF_64); + break; + + case 54: + if (in & PPCDMASK) + ill(in); + else + dab(in, "dcbst", 3, 0, 0, 0, 0); + break; + + case 55: + dab(in, "lwzux", 7, 0, 0, 0, 0); + break; + + case 58: + if (in & PPCBMASK) + ill(in); + else + dab(in, "cntlzd", 6, 1, 0, -1, PPCF_64); + break; + + case 60: + dab(in, "andc", 7, 1, 0, -1, 0); + break; + + case 68: + trap(in, PPCF_64); // td + break; + + case 73: + dab(in, "mulhd", 7, 0, 0, -1, PPCF_64); + break; + + case 75: + dab(in, "mulhw", 7, 0, 0, -1, 0); + break; + + case 83: + if (in & (PPCAMASK | PPCBMASK)) + ill(in); + else + dab(in, "mfmsr", 4, 0, 0, 0, PPCF_SUPER); + break; + + case 84: + dab(in, "ldarx", 7, 0, 0, 0, PPCF_64); + break; + + case 86: + if (in & PPCDMASK) + ill(in); + else + dab(in, "dcbf", 3, 0, 0, 0, 0); + break; + + case 87: + dab(in, "lbzx", 7, 0, 0, 0, 0); + break; + + case 104: + case (PPCOE >> 1) + 104: + if (in & PPCBMASK) + ill(in); + else + dab(in, "neg", 6, 0, 1, -1, 0); + break; + + case 119: + dab(in, "lbzux", 7, 0, 0, 0, 0); + break; + + case 124: + if (PPCGETD(in) == PPCGETB(in)) + dab(in, "not", 6, 1, 0, -1, 0); + else + dab(in, "nor", 7, 1, 0, -1, 0); + break; + + case 136: + case (PPCOE >> 1) + 136: + dab(in, "subfe", 7, 0, 1, -1, 0); + break; + + case 138: + case (PPCOE >> 1) + 138: + dab(in, "adde", 7, 0, 1, -1, 0); + break; + + case 144: + mtcr(in); + break; + + case 146: + if (in & (PPCAMASK | PPCBMASK)) + ill(in); + else + dab(in, "mtmsr", 4, 0, 0, 0, PPCF_SUPER); + break; + + case 149: + dab(in, "stdx", 7, 0, 0, 0, PPCF_64); + break; + + case 150: + dab(in, "stwcx.", 7, 0, 0, 1, 0); + break; + + case 151: + dab(in, "stwx", 7, 0, 0, 0, 0); + break; + + case 181: + dab(in, "stdux", 7, 0, 0, 0, PPCF_64); + break; + + case 183: + dab(in, "stwux", 7, 0, 0, 0, 0); + break; + + case 200: + case (PPCOE >> 1) + 200: + if (in & PPCBMASK) + ill(in); + else + dab(in, "subfze", 6, 0, 1, -1, 0); + break; + + case 202: + case (PPCOE >> 1) + 202: + if (in & PPCBMASK) + ill(in); + else + dab(in, "addze", 6, 0, 1, -1, 0); + break; + + case 210: + msr(in, 1); // mfsr + break; + + case 214: + dab(in, "stdcx.", 7, 0, 0, 1, PPCF_64); + break; + + case 215: + dab(in, "stbx", 7, 0, 0, 0, 0); + break; + + case 232: + case (PPCOE >> 1) + 232: + if (in & PPCBMASK) + ill(in); + else + dab(in, "subfme", 6, 0, 1, -1, 0); + break; + + case 233: + case (PPCOE >> 1) + 233: + dab(in, "mulld", 7, 0, 1, -1, PPCF_64); + break; + + case 234: + case (PPCOE >> 1) + 234: + if (in & PPCBMASK) + ill(in); + else + dab(in, "addme", 6, 0, 1, -1, 0); + break; + + case 235: + case (PPCOE >> 1) + 235: + dab(in, "mullw", 7, 0, 1, -1, 0); + break; + + case 242: + if (in & PPCAMASK) + ill(in); + else + dab(in, "mtsrin", 5, 0, 0, 0, PPCF_SUPER); + break; + + case 246: + if (in & PPCDMASK) + ill(in); + else + dab(in, "dcbtst", 3, 0, 0, 0, 0); + break; + + case 247: + dab(in, "stbux", 7, 0, 0, 0, 0); + break; + + case 266: + case (PPCOE >> 1) + 266: + dab(in, "add", 7, 0, 1, -1, 0); + break; + + case 278: + if (in & PPCDMASK) + ill(in); + else + dab(in, "dcbt", 3, 0, 0, 0, 0); + break; + + case 279: + dab(in, "lhzx", 7, 0, 0, 0, 0); + break; + + case 284: + dab(in, "eqv", 7, 1, 0, -1, 0); + break; + + case 306: + if (in & (PPCDMASK | PPCAMASK)) + ill(in); + else + dab(in, "tlbie", 1, 0, 0, 0, PPCF_SUPER); + break; + + case 310: + dab(in, "eciwx", 7, 0, 0, 0, 0); + break; + + case 311: + dab(in, "lhzux", 7, 0, 0, 0, 0); + break; + + case 316: + dab(in, "xor", 7, 1, 0, -1, 0); + break; + + case 339: + mspr(in, 0); // mfspr + break; + + case 341: + dab(in, "lwax", 7, 0, 0, 0, PPCF_64); + break; + + case 343: + dab(in, "lhax", 7, 0, 0, 0, 0); + break; + + case 370: + nooper(in, "tlbia", PPCF_SUPER); + break; + + case 371: + mtb(in); // mftb + break; + + case 373: + dab(in, "lwaux", 7, 0, 0, 0, PPCF_64); + break; + + case 375: + dab(in, "lhaux", 7, 0, 0, 0, 0); + break; + + case 407: + dab(in, "sthx", 7, 0, 0, 0, 0); + break; + + case 412: + dab(in, "orc", 7, 1, 0, -1, 0); + break; + + case 413: + sradi(in); // sradi + break; + + case 434: + if (in & (PPCDMASK | PPCAMASK)) + ill(in); + else + dab(in, "slbie", 1, 0, 0, 0, PPCF_SUPER | PPCF_64); + break; + + case 438: + dab(in, "ecowx", 7, 0, 0, 0, 0); + break; + + case 439: + dab(in, "sthux", 7, 0, 0, 0, 0); + break; + + case 444: + if (PPCGETD(in) == PPCGETB(in)) + dab(in, "mr", 6, 1, 0, -1, 0); + else + dab(in, "or", 7, 1, 0, -1, 0); + break; + + case 457: + case (PPCOE >> 1) + 457: + dab(in, "divdu", 7, 0, 1, -1, PPCF_64); + break; + + case 459: + case (PPCOE >> 1) + 459: + dab(in, "divwu", 7, 0, 1, -1, 0); + break; + + case 467: + mspr(in, 1); // mtspr + break; + + case 470: + if (in & PPCDMASK) + ill(in); + else + dab(in, "dcbi", 3, 0, 0, 0, 0); + break; + + case 476: + dab(in, "nand", 7, 1, 0, -1, 0); + break; + + case 489: + case (PPCOE >> 1) + 489: + dab(in, "divd", 7, 0, 1, -1, PPCF_64); + break; + + case 491: + case (PPCOE >> 1) + 491: + dab(in, "divw", 7, 0, 1, -1, 0); + break; + + case 498: + nooper(in, "slbia", PPCF_SUPER | PPCF_64); + break; + + case 512: + if (in & 0x007ff801) + { + ill(in); + } + else + { + m_opcode = "mcrxr"; + m_operands = StringFromFormat("cr%d", (int)PPCGETCRD(in)); + } + break; + + case 533: + dab(in, "lswx", 7, 0, 0, 0, 0); + break; + + case 534: + dab(in, "lwbrx", 7, 0, 0, 0, 0); + break; + + case 535: + fdab(in, "lfsx", 7); + break; + + case 536: + dab(in, "srw", 7, 1, 0, -1, 0); + break; + + case 539: + dab(in, "srd", 7, 1, 0, -1, PPCF_64); + break; + + case 566: + nooper(in, "tlbsync", PPCF_SUPER); + break; + + case 567: + fdab(in, "lfsux", 7); + break; + + case 595: + msr(in, 0); // mfsr + break; + + case 597: + rrn(in, "lswi", 0, 0, 0, 0); + break; + + case 598: + nooper(in, "sync", PPCF_SUPER); + break; + + case 599: + fdab(in, "lfdx", 7); + break; + + case 631: + fdab(in, "lfdux", 7); + break; + + case 659: + if (in & PPCAMASK) + ill(in); + else + dab(in, "mfsrin", 5, 0, 0, 0, PPCF_SUPER); + break; + + case 661: + dab(in, "stswx", 7, 0, 0, 0, 0); + break; + + case 662: + dab(in, "stwbrx", 7, 0, 0, 0, 0); + break; + + case 663: + fdab(in, "stfsx", 7); + break; + + case 695: + fdab(in, "stfsux", 7); + break; + + case 725: + rrn(in, "stswi", 0, 0, 0, 0); + break; + + case 727: + fdab(in, "stfdx", 7); + break; + + case 759: + fdab(in, "stfdux", 7); + break; + + case 790: + dab(in, "lhbrx", 7, 0, 0, 0, 0); + break; + + case 792: + dab(in, "sraw", 7, 1, 0, -1, 0); + break; + + case 794: + dab(in, "srad", 7, 1, 0, -1, PPCF_64); + break; + + case 824: + rrn(in, "srawi", 1, 0, -1, 0); + break; + + case 854: + nooper(in, "eieio", PPCF_SUPER); + break; + + case 918: + dab(in, "sthbrx", 7, 0, 0, 0, 0); + break; + + case 922: + if (in & PPCBMASK) + ill(in); + else + dab(in, "extsh", 6, 1, 0, -1, 0); + break; + + case 954: + if (in & PPCBMASK) + ill(in); + else + dab(in, "extsb", 6, 1, 0, -1, 0); + break; + + case 982: + if (in & PPCDMASK) + ill(in); + else + dab(in, "icbi", 3, 0, 0, 0, 0); + break; + + case 983: + fdab(in, "stfiwx", 7); + break; + + case 986: + if (in & PPCBMASK) + ill(in); + else + dab(in, "extsw", 6, 1, 0, -1, PPCF_64); + break; + + case 1014: + if (in & PPCDMASK) + ill(in); + else + dab(in, "dcbz", 3, 0, 0, 0, 0); + break; + + default: + ill(in); + break; + } + break; + + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + ldst(in, ldstnames[PPCGETIDX(in) - 32], 'r', 0); + break; + + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + ldst(in, ldstnames[PPCGETIDX(in) - 32], 'f', 0); + break; + + case 58: + switch (in & 3) + { + case 0: + ldst(in & ~3, "ld", 'r', PPCF_64); + break; + case 1: + ldst(in & ~3, "ldu", 'r', PPCF_64); + break; + case 2: + ldst(in & ~3, "lwa", 'r', PPCF_64); + break; + default: + ill(in); + break; + } + break; + + case 59: + switch (in & 0x3e) + { + case 36: + fdabc(in, "divs", 5, 0); + break; + + case 40: + fdabc(in, "subs", 5, 0); + break; + + case 42: + fdabc(in, "adds", 5, 0); + break; + + case 44: + fdabc(in, "sqrts", 1, 0); + break; + + case 48: + fdabc(in, "res", 1, 0); + break; + + case 50: + fdabc(in, "muls", 6, 0); + break; + + case 56: + fdabc(in, "msubs", 7, 0); + break; + + case 58: + fdabc(in, "madds", 7, 0); + break; + + case 60: + fdabc(in, "nmsubs", 7, 0); + break; + + case 62: + fdabc(in, "nmadds", 7, 0); + break; + + default: + ill(in); + break; + } + break; + + case 62: + switch (in & 3) + { + case 0: + ldst(in & ~3, "std", 'r', PPCF_64); + break; + case 1: + ldst(in & ~3, "stdu", 'r', PPCF_64); + break; + default: + ill(in); + break; + } + break; + + case 63: + if (in & 32) + { + switch (in & 0x1e) + { + case 4: + fdabc(in, "div", 5, 0); + break; + + case 8: + fdabc(in, "sub", 5, 0); + break; + + case 10: + fdabc(in, "add", 5, 0); + break; + + case 12: + fdabc(in, "sqrt", 1, 0); + break; + + case 14: + fdabc(in, "sel", 7, 0); + break; + + case 18: + fdabc(in, "mul", 6, 0); + break; + + case 20: + fdabc(in, "rsqrte", 1, 0); + break; + + case 24: + fdabc(in, "msub", 7, 0); + break; + + case 26: + fdabc(in, "madd", 7, 0); + break; + + case 28: + fdabc(in, "nmsub", 7, 0); + break; + + case 30: + fdabc(in, "nmadd", 7, 0); + break; + + default: + ill(in); + break; + } + } + else + { + switch (PPCGETIDX2(in)) + { + case 0: + fcmp(in, 'u'); + break; + + case 12: + fdabc(in, "rsp", 1, 0); + break; + + case 14: + fdabc(in, "ctiw", 1, 0); + break; + + case 15: + fdabc(in, "ctiwz", 1, 0); + break; + + case 32: + fcmp(in, 'o'); + break; + + case 38: + mtfsb(in, 1); + break; + + case 40: + fdabc(in, "neg", 10, 0); + break; + + case 64: + mcrf(in, 's'); // mcrfs + break; + + case 70: + mtfsb(in, 0); + break; + + case 72: + fmr(in); + break; + + case 134: + if ((in & 0x006f0800) == 0) + { + m_opcode = StringFromFormat("mtfsfi%s", rcsel[in & 1]); + m_operands = StringFromFormat("cr%d,%d", (int)PPCGETCRD(in), (int)(in & 0xf000) >> 12); + } + else + { + ill(in); + } + break; + + case 136: + fdabc(in, "nabs", 10, 0); + break; + + case 264: + fdabc(in, "abs", 10, 0); + break; + + case 583: + if (in & (PPCAMASK | PPCBMASK)) + ill(in); + else + dab(in, "mffs", 4, 0, 0, -1, 0); + break; + + case 711: + if ((in & 0x02010000) == 0) + { + m_opcode = StringFromFormat("mtfsf%s", rcsel[in & 1]); + m_operands = StringFromFormat("0x%x,%u", (unsigned int)(in >> 17) & 0x01fe, + (unsigned int)PPCGETB(in)); + } + else + { + ill(in); + } + break; + + case 814: + fdabc(in, "fctid", 10, PPCF_64); + break; + + case 815: + fdabc(in, "fctidz", 10, PPCF_64); + break; + + case 846: + fdabc(in, "fcfid", 10, PPCF_64); + break; + + default: + ill(in); + break; + } + } + break; + + default: + ill(in); + break; + } + return (m_instr + 1); } // simplified interface -std::string GekkoDisassembler::Disassemble(u32 opcode, u32 current_instruction_address, bool big_endian) +std::string GekkoDisassembler::Disassemble(u32 opcode, u32 current_instruction_address, + bool big_endian) { - u32 opc = opcode; - u32 addr = current_instruction_address; + u32 opc = opcode; + u32 addr = current_instruction_address; - m_instr = (u32*)&opc; - m_iaddr = (u32*)&addr; + m_instr = (u32*)&opc; + m_iaddr = (u32*)&addr; - DoDisassembly(big_endian); + DoDisassembly(big_endian); - return m_opcode.append("\t").append(m_operands); + return m_opcode.append("\t").append(m_operands); } -static const char* gprnames[] = -{ - " r0", " r1", " r2", " r3", " r4", " r5", " r6", " r7", - " r8", " r9", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" -}; +static const char* gprnames[] = {" r0", " r1", " r2", " r3", " r4", " r5", " r6", " r7", + " r8", " r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"}; const char* GekkoDisassembler::GetGPRName(u32 index) { - if (index < 32) - return gprnames[index]; + if (index < 32) + return gprnames[index]; - return nullptr; + return nullptr; } -static const char* fprnames[] = -{ - " f0", " f1", " f2", " f3", " f4", " f5", " f6", " f7", - " f8", " f9", "f10", "f11", "f12", "f13", "f14", "f15", - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" -}; +static const char* fprnames[] = {" f0", " f1", " f2", " f3", " f4", " f5", " f6", " f7", + " f8", " f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"}; const char* GekkoDisassembler::GetFPRName(u32 index) { - if (index < 32) - return fprnames[index]; + if (index < 32) + return fprnames[index]; - return nullptr; + return nullptr; } diff --git a/Source/Core/Common/GekkoDisassembler.h b/Source/Core/Common/GekkoDisassembler.h index bfd293f10d..684ae92052 100644 --- a/Source/Core/Common/GekkoDisassembler.h +++ b/Source/Core/Common/GekkoDisassembler.h @@ -43,114 +43,112 @@ class GekkoDisassembler final { public: - static std::string Disassemble(u32 opcode, u32 current_instruction_address, bool big_endian = true); - static const char* GetGPRName(u32 index); - static const char* GetFPRName(u32 index); + static std::string Disassemble(u32 opcode, u32 current_instruction_address, + bool big_endian = true); + static const char* GetGPRName(u32 index); + static const char* GetFPRName(u32 index); private: - GekkoDisassembler() = delete; + GekkoDisassembler() = delete; - static void ill(u32 in); - static std::string imm(u32 in, int uimm, int type, bool hex); + static void ill(u32 in); + static std::string imm(u32 in, int uimm, int type, bool hex); - static std::string ra_rb(u32 in); - static std::string rd_ra_rb(u32 in, int mask); - static std::string fd_ra_rb(u32 in, int mask); + static std::string ra_rb(u32 in); + static std::string rd_ra_rb(u32 in, int mask); + static std::string fd_ra_rb(u32 in, int mask); - static void trapi(u32 in, unsigned char dmode); - static void cmpi(u32 in, int uimm); - static void addi(u32 in, const std::string& ext); - static size_t branch(u32 in, const char* bname, int aform, int bdisp); - static void bc(u32 in); - static void bli(u32 in); - static void mcrf(u32 in, char c); - static void crop(u32 in, const char* n1, const char* n2); - static void nooper(u32 in, const char* name, unsigned char dmode); - static void rlw(u32 in, const char* name, int i); - static void ori(u32 in, const char* name); - static void rld(u32 in, const char* name, int i); - static void cmp(u32 in); - static void trap(u32 in, unsigned char dmode); - static void dab(u32 in, const char* name, int mask, int smode, int chkoe, int chkrc, unsigned char dmode); - static void rrn(u32 in, const char* name, int smode, int chkoe, int chkrc, unsigned char dmode); - static void mtcr(u32 in); - static void msr(u32 in, int smode); - static void mspr(u32 in, int smode); - static void mtb(u32 in); - static void sradi(u32 in); - static void ldst(u32 in, const char* name, char reg, unsigned char dmode); - static void fdabc(u32 in, const char* name, int mask, unsigned char dmode); - static void fmr(u32 in); - static void fdab(u32 in, const char* name, int mask); - static void fcmp(u32 in, char c); - static void mtfsb(u32 in, int n); - static void ps(u32 inst); - static void ps_mem(u32 inst); + static void trapi(u32 in, unsigned char dmode); + static void cmpi(u32 in, int uimm); + static void addi(u32 in, const std::string& ext); + static size_t branch(u32 in, const char* bname, int aform, int bdisp); + static void bc(u32 in); + static void bli(u32 in); + static void mcrf(u32 in, char c); + static void crop(u32 in, const char* n1, const char* n2); + static void nooper(u32 in, const char* name, unsigned char dmode); + static void rlw(u32 in, const char* name, int i); + static void ori(u32 in, const char* name); + static void rld(u32 in, const char* name, int i); + static void cmp(u32 in); + static void trap(u32 in, unsigned char dmode); + static void dab(u32 in, const char* name, int mask, int smode, int chkoe, int chkrc, + unsigned char dmode); + static void rrn(u32 in, const char* name, int smode, int chkoe, int chkrc, unsigned char dmode); + static void mtcr(u32 in); + static void msr(u32 in, int smode); + static void mspr(u32 in, int smode); + static void mtb(u32 in); + static void sradi(u32 in); + static void ldst(u32 in, const char* name, char reg, unsigned char dmode); + static void fdabc(u32 in, const char* name, int mask, unsigned char dmode); + static void fmr(u32 in); + static void fdab(u32 in, const char* name, int mask); + static void fcmp(u32 in, char c); + static void mtfsb(u32 in, int n); + static void ps(u32 inst); + static void ps_mem(u32 inst); - static u32* DoDisassembly(bool big_endian); + static u32* DoDisassembly(bool big_endian); - static u32 HelperRotateMask(int r, int mb, int me) - { - //first make 001111111111111 part - unsigned int begin = 0xFFFFFFFF >> mb; - //then make 000000000001111 part, which is used to flip the bits of the first one - unsigned int end = me < 31 ? (0xFFFFFFFF >> (me + 1)) : 0; - //do the bitflip - unsigned int mask = begin ^ end; - //and invert if backwards - if (me < mb) - mask = ~mask; - //rotate the mask so it can be applied to source reg - //return _rotl(mask, 32 - r); - return (mask << (32 - r)) | (mask >> r); - } + static u32 HelperRotateMask(int r, int mb, int me) + { + // first make 001111111111111 part + unsigned int begin = 0xFFFFFFFF >> mb; + // then make 000000000001111 part, which is used to flip the bits of the first one + unsigned int end = me < 31 ? (0xFFFFFFFF >> (me + 1)) : 0; + // do the bitflip + unsigned int mask = begin ^ end; + // and invert if backwards + if (me < mb) + mask = ~mask; + // rotate the mask so it can be applied to source reg + // return _rotl(mask, 32 - r); + return (mask << (32 - r)) | (mask >> r); + } - static std::string ldst_offs(u32 val) - { - if (val == 0) - { - return "0"; - } - else - { - if (val & 0x8000) - { - return StringFromFormat("-0x%.4X", ((~val) & 0xffff) + 1); - } - else - { - return StringFromFormat("0x%.4X", val); - } - } - } + static std::string ldst_offs(u32 val) + { + if (val == 0) + { + return "0"; + } + else + { + if (val & 0x8000) + { + return StringFromFormat("-0x%.4X", ((~val) & 0xffff) + 1); + } + else + { + return StringFromFormat("0x%.4X", val); + } + } + } - static int SEX12(u32 x) - { - return x & 0x800 ? (x | 0xFFFFF000) : x; - } + static int SEX12(u32 x) { return x & 0x800 ? (x | 0xFFFFF000) : x; } + enum InstructionType + { + PPCINSTR_OTHER = 0, // No additional info for other instr. + PPCINSTR_BRANCH = 1, // Branch dest. = PC+displacement + PPCINSTR_LDST = 2, // Load/store instruction: displ(sreg) + PPCINSTR_IMM = 3, // 16-bit immediate val. in displacement + }; - enum InstructionType - { - PPCINSTR_OTHER = 0, // No additional info for other instr. - PPCINSTR_BRANCH = 1, // Branch dest. = PC+displacement - PPCINSTR_LDST = 2, // Load/store instruction: displ(sreg) - PPCINSTR_IMM = 3, // 16-bit immediate val. in displacement - }; + enum Flags + { + PPCF_ILLEGAL = (1 << 0), // Illegal PowerPC instruction + PPCF_UNSIGNED = (1 << 1), // Unsigned immediate instruction + PPCF_SUPER = (1 << 2), // Supervisor level instruction + PPCF_64 = (1 << 3), // 64-bit only instruction + }; - enum Flags - { - PPCF_ILLEGAL = (1 << 0), // Illegal PowerPC instruction - PPCF_UNSIGNED = (1 << 1), // Unsigned immediate instruction - PPCF_SUPER = (1 << 2), // Supervisor level instruction - PPCF_64 = (1 << 3), // 64-bit only instruction - }; - - static u32* m_instr; // Pointer to instruction to disassemble - static u32* m_iaddr; // Instruction.address., usually the same as instr - static std::string m_opcode; // Buffer for opcode, min. 10 chars. - static std::string m_operands; // Operand buffer, min. 24 chars. - static unsigned char m_type; // Type of instruction, see below - static unsigned char m_flags; // Additional flags - static unsigned short m_sreg; // Register in load/store instructions - static u32 m_displacement; // Branch- or load/store displacement + static u32* m_instr; // Pointer to instruction to disassemble + static u32* m_iaddr; // Instruction.address., usually the same as instr + static std::string m_opcode; // Buffer for opcode, min. 10 chars. + static std::string m_operands; // Operand buffer, min. 24 chars. + static unsigned char m_type; // Type of instruction, see below + static unsigned char m_flags; // Additional flags + static unsigned short m_sreg; // Register in load/store instructions + static u32 m_displacement; // Branch- or load/store displacement }; diff --git a/Source/Core/Common/GenericCPUDetect.cpp b/Source/Core/Common/GenericCPUDetect.cpp index 8c82fb8667..f005c18509 100644 --- a/Source/Core/Common/GenericCPUDetect.cpp +++ b/Source/Core/Common/GenericCPUDetect.cpp @@ -6,9 +6,11 @@ CPUInfo cpu_info; -CPUInfo::CPUInfo() {} +CPUInfo::CPUInfo() +{ +} std::string CPUInfo::Summarize() { - return "Generic"; + return "Generic"; } diff --git a/Source/Core/Common/GenericFPURoundMode.cpp b/Source/Core/Common/GenericFPURoundMode.cpp index 506e619217..91c02841e7 100644 --- a/Source/Core/Common/GenericFPURoundMode.cpp +++ b/Source/Core/Common/GenericFPURoundMode.cpp @@ -8,22 +8,22 @@ // Generic, do nothing namespace FPURoundMode { - void SetRoundMode(int mode) - { - } - void SetPrecisionMode(PrecisionMode mode) - { - } - void SetSIMDMode(int rounding_mode, bool non_ieee_mode) - { - } - void SaveSIMDState() - { - } - void LoadSIMDState() - { - } - void LoadDefaultSIMDState() - { - } +void SetRoundMode(int mode) +{ +} +void SetPrecisionMode(PrecisionMode mode) +{ +} +void SetSIMDMode(int rounding_mode, bool non_ieee_mode) +{ +} +void SaveSIMDState() +{ +} +void LoadSIMDState() +{ +} +void LoadDefaultSIMDState() +{ +} } diff --git a/Source/Core/Common/Hash.cpp b/Source/Core/Common/Hash.cpp index da0e09978c..27d0e412bc 100644 --- a/Source/Core/Common/Hash.cpp +++ b/Source/Core/Common/Hash.cpp @@ -2,11 +2,11 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Common/Hash.h" #include #include -#include "Common/CommonFuncs.h" #include "Common/CPUDetect.h" -#include "Common/Hash.h" +#include "Common/CommonFuncs.h" #include "Common/Intrinsics.h" static u64 (*ptrHashFunction)(const u8* src, u32 len, u32 samples) = &GetMurmurHash3; @@ -16,88 +16,86 @@ static u64 (*ptrHashFunction)(const u8* src, u32 len, u32 samples) = &GetMurmurH // Implementation from Wikipedia. u32 HashFletcher(const u8* data_u8, size_t length) { - const u16* data = (const u16*)data_u8; /* Pointer to the data to be summed */ - size_t len = (length + 1) / 2; /* Length in 16-bit words */ - u32 sum1 = 0xffff, sum2 = 0xffff; + const u16* data = (const u16*)data_u8; /* Pointer to the data to be summed */ + size_t len = (length + 1) / 2; /* Length in 16-bit words */ + u32 sum1 = 0xffff, sum2 = 0xffff; - while (len) - { - size_t tlen = len > 360 ? 360 : len; - len -= tlen; + while (len) + { + size_t tlen = len > 360 ? 360 : len; + len -= tlen; - do - { - sum1 += *data++; - sum2 += sum1; - } while (--tlen); + do + { + sum1 += *data++; + sum2 += sum1; + } while (--tlen); - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - } + sum1 = (sum1 & 0xffff) + (sum1 >> 16); + sum2 = (sum2 & 0xffff) + (sum2 >> 16); + } - // Second reduction step to reduce sums to 16 bits - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - return(sum2 << 16 | sum1); + // Second reduction step to reduce sums to 16 bits + sum1 = (sum1 & 0xffff) + (sum1 >> 16); + sum2 = (sum2 & 0xffff) + (sum2 >> 16); + return (sum2 << 16 | sum1); } - // Implementation from Wikipedia // Slightly slower than Fletcher above, but slightly more reliable. // data: Pointer to the data to be summed; len is in bytes u32 HashAdler32(const u8* data, size_t len) { - static const u32 MOD_ADLER = 65521; - u32 a = 1, b = 0; + static const u32 MOD_ADLER = 65521; + u32 a = 1, b = 0; - while (len) - { - size_t tlen = len > 5550 ? 5550 : len; - len -= tlen; + while (len) + { + size_t tlen = len > 5550 ? 5550 : len; + len -= tlen; - do - { - a += *data++; - b += a; - } while (--tlen); + do + { + a += *data++; + b += a; + } while (--tlen); - a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER); - b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER); - } + a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER); + b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER); + } - // It can be shown that a <= 0x1013a here, so a single subtract will do. - if (a >= MOD_ADLER) - { - a -= MOD_ADLER; - } + // It can be shown that a <= 0x1013a here, so a single subtract will do. + if (a >= MOD_ADLER) + { + a -= MOD_ADLER; + } - // It can be shown that b can reach 0xfff87 here. - b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER); + // It can be shown that b can reach 0xfff87 here. + b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER); - if (b >= MOD_ADLER) - { - b -= MOD_ADLER; - } + if (b >= MOD_ADLER) + { + b -= MOD_ADLER; + } - return((b << 16) | a); + return ((b << 16) | a); } // Stupid hash - but can't go back now :) // Don't use for new things. At least it's reasonably fast. u32 HashEctor(const u8* ptr, int length) { - u32 crc = 0; + u32 crc = 0; - for (int i = 0; i < length; i++) - { - crc ^= ptr[i]; - crc = (crc << 3) | (crc >> 29); - } + for (int i = 0; i < length; i++) + { + crc ^= ptr[i]; + crc = (crc << 3) | (crc >> 29); + } - return(crc); + return (crc); } - #if _ARCH_64 //----------------------------------------------------------------------------- @@ -106,33 +104,33 @@ u32 HashEctor(const u8* ptr, int length) inline u64 getblock(const u64* p, int i) { - return p[i]; + return p[i]; } //---------- // Block mix - combine the key bits with the hash bits and scramble everything -inline void bmix64(u64 & h1, u64 & h2, u64 & k1, u64 & k2, u64 & c1, u64 & c2) +inline void bmix64(u64& h1, u64& h2, u64& k1, u64& k2, u64& c1, u64& c2) { - k1 *= c1; - k1 = _rotl64(k1, 23); - k1 *= c2; - h1 ^= k1; - h1 += h2; + k1 *= c1; + k1 = _rotl64(k1, 23); + k1 *= c2; + h1 ^= k1; + h1 += h2; - h2 = _rotl64(h2, 41); + h2 = _rotl64(h2, 41); - k2 *= c2; - k2 = _rotl64(k2, 23); - k2 *= c1; - h2 ^= k2; - h2 += h1; + k2 *= c2; + k2 = _rotl64(k2, 23); + k2 *= c1; + h2 ^= k2; + h2 += h1; - h1 = h1 * 3 + 0x52dce729; - h2 = h2 * 3 + 0x38495ab5; + h1 = h1 * 3 + 0x52dce729; + h2 = h2 * 3 + 0x38495ab5; - c1 = c1 * 5 + 0x7b7d159c; - c2 = c2 * 5 + 0x6bce6396; + c1 = c1 * 5 + 0x7b7d159c; + c2 = c2 * 5 + 0x6bce6396; } //---------- @@ -140,192 +138,195 @@ inline void bmix64(u64 & h1, u64 & h2, u64 & k1, u64 & k2, u64 & c1, u64 & c2) inline u64 fmix64(u64 k) { - k ^= k >> 33; - k *= 0xff51afd7ed558ccd; - k ^= k >> 33; - k *= 0xc4ceb9fe1a85ec53; - k ^= k >> 33; + k ^= k >> 33; + k *= 0xff51afd7ed558ccd; + k ^= k >> 33; + k *= 0xc4ceb9fe1a85ec53; + k ^= k >> 33; - return k; + return k; } u64 GetMurmurHash3(const u8* src, u32 len, u32 samples) { - const u8* data = (const u8*)src; - const int nblocks = len / 16; - u32 Step = (len / 8); - if (samples == 0) - samples = std::max(Step, 1u); - Step = Step / samples; - if (Step < 1) - Step = 1; + const u8* data = (const u8*)src; + const int nblocks = len / 16; + u32 Step = (len / 8); + if (samples == 0) + samples = std::max(Step, 1u); + Step = Step / samples; + if (Step < 1) + Step = 1; - u64 h1 = 0x9368e53c2f6af274; - u64 h2 = 0x586dcd208f7cd3fd; + u64 h1 = 0x9368e53c2f6af274; + u64 h2 = 0x586dcd208f7cd3fd; - u64 c1 = 0x87c37b91114253d5; - u64 c2 = 0x4cf5ad432745937f; + u64 c1 = 0x87c37b91114253d5; + u64 c2 = 0x4cf5ad432745937f; + //---------- + // body - //---------- - // body + const u64* blocks = (const u64*)(data); - const u64* blocks = (const u64*)(data); + for (int i = 0; i < nblocks; i += Step) + { + u64 k1 = getblock(blocks, i * 2 + 0); + u64 k2 = getblock(blocks, i * 2 + 1); - for (int i = 0; i < nblocks; i+=Step) - { - u64 k1 = getblock(blocks, i*2+0); - u64 k2 = getblock(blocks, i*2+1); + bmix64(h1, h2, k1, k2, c1, c2); + } - bmix64(h1,h2,k1,k2,c1,c2); - } + //---------- + // tail - //---------- - // tail + const u8* tail = (const u8*)(data + nblocks * 16); - const u8* tail = (const u8*)(data + nblocks*16); + u64 k1 = 0; + u64 k2 = 0; - u64 k1 = 0; - u64 k2 = 0; + switch (len & 15) + { + case 15: + k2 ^= u64(tail[14]) << 48; + case 14: + k2 ^= u64(tail[13]) << 40; + case 13: + k2 ^= u64(tail[12]) << 32; + case 12: + k2 ^= u64(tail[11]) << 24; + case 11: + k2 ^= u64(tail[10]) << 16; + case 10: + k2 ^= u64(tail[9]) << 8; + case 9: + k2 ^= u64(tail[8]) << 0; - switch (len & 15) - { - case 15: k2 ^= u64(tail[14]) << 48; - case 14: k2 ^= u64(tail[13]) << 40; - case 13: k2 ^= u64(tail[12]) << 32; - case 12: k2 ^= u64(tail[11]) << 24; - case 11: k2 ^= u64(tail[10]) << 16; - case 10: k2 ^= u64(tail[ 9]) << 8; - case 9: k2 ^= u64(tail[ 8]) << 0; + case 8: + k1 ^= u64(tail[7]) << 56; + case 7: + k1 ^= u64(tail[6]) << 48; + case 6: + k1 ^= u64(tail[5]) << 40; + case 5: + k1 ^= u64(tail[4]) << 32; + case 4: + k1 ^= u64(tail[3]) << 24; + case 3: + k1 ^= u64(tail[2]) << 16; + case 2: + k1 ^= u64(tail[1]) << 8; + case 1: + k1 ^= u64(tail[0]) << 0; + bmix64(h1, h2, k1, k2, c1, c2); + }; - case 8: k1 ^= u64(tail[ 7]) << 56; - case 7: k1 ^= u64(tail[ 6]) << 48; - case 6: k1 ^= u64(tail[ 5]) << 40; - case 5: k1 ^= u64(tail[ 4]) << 32; - case 4: k1 ^= u64(tail[ 3]) << 24; - case 3: k1 ^= u64(tail[ 2]) << 16; - case 2: k1 ^= u64(tail[ 1]) << 8; - case 1: k1 ^= u64(tail[ 0]) << 0; - bmix64(h1,h2,k1,k2,c1,c2); - }; + //---------- + // finalization - //---------- - // finalization + h2 ^= len; - h2 ^= len; + h1 += h2; + h2 += h1; - h1 += h2; - h2 += h1; + h1 = fmix64(h1); + h2 = fmix64(h2); - h1 = fmix64(h1); - h2 = fmix64(h2); + h1 += h2; - h1 += h2; - - return h1; + return h1; } - // CRC32 hash using the SSE4.2 instruction u64 GetCRC32(const u8* src, u32 len, u32 samples) { #if _M_SSE >= 0x402 || defined(_M_ARM_64) - u64 h[4] = { len, 0, 0, 0 }; - u32 Step = (len / 8); - const u64* data = (const u64*)src; - const u64* end = data + Step; - if (samples == 0) - samples = std::max(Step, 1u); - Step = Step / samples; - if (Step < 1) - Step = 1; + u64 h[4] = {len, 0, 0, 0}; + u32 Step = (len / 8); + const u64* data = (const u64*)src; + const u64* end = data + Step; + if (samples == 0) + samples = std::max(Step, 1u); + Step = Step / samples; + if (Step < 1) + Step = 1; #endif #if _M_SSE >= 0x402 - while (data < end - Step * 3) - { - h[0] = _mm_crc32_u64(h[0], data[Step * 0]); - h[1] = _mm_crc32_u64(h[1], data[Step * 1]); - h[2] = _mm_crc32_u64(h[2], data[Step * 2]); - h[3] = _mm_crc32_u64(h[3], data[Step * 3]); - data += Step * 4; - } - if (data < end - Step * 0) - h[0] = _mm_crc32_u64(h[0], data[Step * 0]); - if (data < end - Step * 1) - h[1] = _mm_crc32_u64(h[1], data[Step * 1]); - if (data < end - Step * 2) - h[2] = _mm_crc32_u64(h[2], data[Step * 2]); + while (data < end - Step * 3) + { + h[0] = _mm_crc32_u64(h[0], data[Step * 0]); + h[1] = _mm_crc32_u64(h[1], data[Step * 1]); + h[2] = _mm_crc32_u64(h[2], data[Step * 2]); + h[3] = _mm_crc32_u64(h[3], data[Step * 3]); + data += Step * 4; + } + if (data < end - Step * 0) + h[0] = _mm_crc32_u64(h[0], data[Step * 0]); + if (data < end - Step * 1) + h[1] = _mm_crc32_u64(h[1], data[Step * 1]); + if (data < end - Step * 2) + h[2] = _mm_crc32_u64(h[2], data[Step * 2]); - if (len & 7) - { - u64 temp = 0; - memcpy(&temp, end, len & 7); - h[0] = _mm_crc32_u64(h[0], temp); - } + if (len & 7) + { + u64 temp = 0; + memcpy(&temp, end, len & 7); + h[0] = _mm_crc32_u64(h[0], temp); + } #elif defined(_M_ARM_64) - // We should be able to use intrinsics for this - // Too bad the intrinsics for this instruction was added in GCC 4.9.1 - // The Android NDK (as of r10e) only has GCC 4.9 - // Once the Android NDK has a newer GCC version, update these to use intrinsics - while (data < end - Step * 3) - { - asm ("crc32x %w[res], %w[two], %x[three]" - : [res] "=r" (h[0]) - : [two] "r" (h[0]), - [three] "r" (data[Step * 0])); - asm ("crc32x %w[res], %w[two], %x[three]" - : [res] "=r" (h[1]) - : [two] "r" (h[1]), - [three] "r" (data[Step * 1])); - asm ("crc32x %w[res], %w[two], %x[three]" - : [res] "=r" (h[2]) - : [two] "r" (h[2]), - [three] "r" (data[Step * 2])); - asm ("crc32x %w[res], %w[two], %x[three]" - : [res] "=r" (h[3]) - : [two] "r" (h[3]), - [three] "r" (data[Step * 3])); + // We should be able to use intrinsics for this + // Too bad the intrinsics for this instruction was added in GCC 4.9.1 + // The Android NDK (as of r10e) only has GCC 4.9 + // Once the Android NDK has a newer GCC version, update these to use intrinsics + while (data < end - Step * 3) + { + asm("crc32x %w[res], %w[two], %x[three]" + : [res] "=r"(h[0]) + : [two] "r"(h[0]), [three] "r"(data[Step * 0])); + asm("crc32x %w[res], %w[two], %x[three]" + : [res] "=r"(h[1]) + : [two] "r"(h[1]), [three] "r"(data[Step * 1])); + asm("crc32x %w[res], %w[two], %x[three]" + : [res] "=r"(h[2]) + : [two] "r"(h[2]), [three] "r"(data[Step * 2])); + asm("crc32x %w[res], %w[two], %x[three]" + : [res] "=r"(h[3]) + : [two] "r"(h[3]), [three] "r"(data[Step * 3])); - data += Step * 4; - } - if (data < end - Step * 0) - asm ("crc32x %w[res], %w[two], %x[three]" - : [res] "=r" (h[0]) - : [two] "r" (h[0]), - [three] "r" (data[Step * 0])); - if (data < end - Step * 1) - asm ("crc32x %w[res], %w[two], %x[three]" - : [res] "=r" (h[1]) - : [two] "r" (h[1]), - [three] "r" (data[Step * 1])); - if (data < end - Step * 2) - asm ("crc32x %w[res], %w[two], %x[three]" - : [res] "=r" (h[2]) - : [two] "r" (h[2]), - [three] "r" (data[Step * 2])); + data += Step * 4; + } + if (data < end - Step * 0) + asm("crc32x %w[res], %w[two], %x[three]" + : [res] "=r"(h[0]) + : [two] "r"(h[0]), [three] "r"(data[Step * 0])); + if (data < end - Step * 1) + asm("crc32x %w[res], %w[two], %x[three]" + : [res] "=r"(h[1]) + : [two] "r"(h[1]), [three] "r"(data[Step * 1])); + if (data < end - Step * 2) + asm("crc32x %w[res], %w[two], %x[three]" + : [res] "=r"(h[2]) + : [two] "r"(h[2]), [three] "r"(data[Step * 2])); - if (len & 7) - { - u64 temp = 0; - memcpy(&temp, end, len & 7); - asm ("crc32x %w[res], %w[two], %x[three]" - : [res] "=r" (h[0]) - : [two] "r" (h[0]), - [three] "r" (temp)); - } + if (len & 7) + { + u64 temp = 0; + memcpy(&temp, end, len & 7); + asm("crc32x %w[res], %w[two], %x[three]" + : [res] "=r"(h[0]) + : [two] "r"(h[0]), [three] "r"(temp)); + } #endif #if _M_SSE >= 0x402 || defined(_M_ARM_64) - // FIXME: is there a better way to combine these partial hashes? - return h[0] + (h[1] << 10) + (h[2] << 21) + (h[3] << 32); + // FIXME: is there a better way to combine these partial hashes? + return h[0] + (h[1] << 10) + (h[2] << 21) + (h[3] << 32); #else - return 0; + return 0; #endif - } - /* * NOTE: This hash function is used for custom texture loading/dumping, so * it should not be changed, which would require all custom textures to be @@ -335,72 +336,79 @@ u64 GetCRC32(const u8* src, u32 len, u32 samples) */ u64 GetHashHiresTexture(const u8* src, u32 len, u32 samples) { - const u64 m = 0xc6a4a7935bd1e995; - u64 h = len * m; - const int r = 47; - u32 Step = (len / 8); - const u64* data = (const u64*)src; - const u64* end = data + Step; - if (samples == 0) - samples = std::max(Step, 1u); - Step = Step / samples; - if (Step < 1) - Step = 1; - while (data < end) - { - u64 k = data[0]; - data+=Step; - k *= m; - k ^= k >> r; - k *= m; - h ^= k; - h *= m; - } + const u64 m = 0xc6a4a7935bd1e995; + u64 h = len * m; + const int r = 47; + u32 Step = (len / 8); + const u64* data = (const u64*)src; + const u64* end = data + Step; + if (samples == 0) + samples = std::max(Step, 1u); + Step = Step / samples; + if (Step < 1) + Step = 1; + while (data < end) + { + u64 k = data[0]; + data += Step; + k *= m; + k ^= k >> r; + k *= m; + h ^= k; + h *= m; + } - const u8 * data2 = (const u8*)end; + const u8* data2 = (const u8*)end; - switch (len & 7) - { - case 7: h ^= u64(data2[6]) << 48; - case 6: h ^= u64(data2[5]) << 40; - case 5: h ^= u64(data2[4]) << 32; - case 4: h ^= u64(data2[3]) << 24; - case 3: h ^= u64(data2[2]) << 16; - case 2: h ^= u64(data2[1]) << 8; - case 1: h ^= u64(data2[0]); - h *= m; - }; + switch (len & 7) + { + case 7: + h ^= u64(data2[6]) << 48; + case 6: + h ^= u64(data2[5]) << 40; + case 5: + h ^= u64(data2[4]) << 32; + case 4: + h ^= u64(data2[3]) << 24; + case 3: + h ^= u64(data2[2]) << 16; + case 2: + h ^= u64(data2[1]) << 8; + case 1: + h ^= u64(data2[0]); + h *= m; + }; - h ^= h >> r; - h *= m; - h ^= h >> r; + h ^= h >> r; + h *= m; + h ^= h >> r; - return h; + return h; } #else // CRC32 hash using the SSE4.2 instruction u64 GetCRC32(const u8* src, u32 len, u32 samples) { #if _M_SSE >= 0x402 - u32 h = len; - u32 Step = (len/4); - const u32* data = (const u32 *)src; - const u32* end = data + Step; - if (samples == 0) - samples = std::max(Step, 1u); - Step = Step / samples; - if (Step < 1) - Step = 1; - while (data < end) - { - h = _mm_crc32_u32(h, data[0]); - data += Step; - } + u32 h = len; + u32 Step = (len / 4); + const u32* data = (const u32*)src; + const u32* end = data + Step; + if (samples == 0) + samples = std::max(Step, 1u); + Step = Step / samples; + if (Step < 1) + Step = 1; + while (data < end) + { + h = _mm_crc32_u32(h, data[0]); + data += Step; + } - const u8* data2 = (const u8*)end; - return (u64)_mm_crc32_u32(h, u32(data2[0])); + const u8* data2 = (const u8*)end; + return (u64)_mm_crc32_u32(h, u32(data2[0])); #else - return 0; + return 0; #endif } @@ -410,7 +418,7 @@ u64 GetCRC32(const u8* src, u32 len, u32 samples) inline u32 getblock(const u32* p, int i) { - return p[i]; + return p[i]; } //---------- @@ -420,109 +428,116 @@ inline u32 getblock(const u32* p, int i) inline u32 fmix32(u32 h) { - h ^= h >> 16; - h *= 0x85ebca6b; - h ^= h >> 13; - h *= 0xc2b2ae35; - h ^= h >> 16; + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; - return h; + return h; } -inline void bmix32(u32 & h1, u32 & h2, u32 & k1, u32 & k2, u32 & c1, u32 & c2) +inline void bmix32(u32& h1, u32& h2, u32& k1, u32& k2, u32& c1, u32& c2) { - k1 *= c1; - k1 = _rotl(k1, 11); - k1 *= c2; - h1 ^= k1; - h1 += h2; + k1 *= c1; + k1 = _rotl(k1, 11); + k1 *= c2; + h1 ^= k1; + h1 += h2; - h2 = _rotl(h2, 17); + h2 = _rotl(h2, 17); - k2 *= c2; - k2 = _rotl(k2, 11); - k2 *= c1; - h2 ^= k2; - h2 += h1; + k2 *= c2; + k2 = _rotl(k2, 11); + k2 *= c1; + h2 ^= k2; + h2 += h1; - h1 = h1*3+0x52dce729; - h2 = h2*3+0x38495ab5; + h1 = h1 * 3 + 0x52dce729; + h2 = h2 * 3 + 0x38495ab5; - c1 = c1*5+0x7b7d159c; - c2 = c2*5+0x6bce6396; + c1 = c1 * 5 + 0x7b7d159c; + c2 = c2 * 5 + 0x6bce6396; } //---------- u64 GetMurmurHash3(const u8* src, u32 len, u32 samples) { - const u8* data = (const u8*)src; - u32 out[2]; - const int nblocks = len / 8; - u32 Step = (len / 4); - if (samples == 0) - samples = std::max(Step, 1u); - Step = Step / samples; - if (Step < 1) - Step = 1; + const u8* data = (const u8*)src; + u32 out[2]; + const int nblocks = len / 8; + u32 Step = (len / 4); + if (samples == 0) + samples = std::max(Step, 1u); + Step = Step / samples; + if (Step < 1) + Step = 1; - u32 h1 = 0x8de1c3ac; - u32 h2 = 0xbab98226; + u32 h1 = 0x8de1c3ac; + u32 h2 = 0xbab98226; - u32 c1 = 0x95543787; - u32 c2 = 0x2ad7eb25; + u32 c1 = 0x95543787; + u32 c2 = 0x2ad7eb25; - //---------- - // body + //---------- + // body - const u32* blocks = (const u32*)(data + nblocks*8); + const u32* blocks = (const u32*)(data + nblocks * 8); - for (int i = -nblocks; i < 0; i+=Step) - { - u32 k1 = getblock(blocks,i*2+0); - u32 k2 = getblock(blocks,i*2+1); + for (int i = -nblocks; i < 0; i += Step) + { + u32 k1 = getblock(blocks, i * 2 + 0); + u32 k2 = getblock(blocks, i * 2 + 1); - bmix32(h1,h2,k1,k2,c1,c2); - } + bmix32(h1, h2, k1, k2, c1, c2); + } - //---------- - // tail + //---------- + // tail - const u8* tail = (const u8*)(data + nblocks*8); + const u8* tail = (const u8*)(data + nblocks * 8); - u32 k1 = 0; - u32 k2 = 0; + u32 k1 = 0; + u32 k2 = 0; - switch (len & 7) - { - case 7: k2 ^= tail[6] << 16; - case 6: k2 ^= tail[5] << 8; - case 5: k2 ^= tail[4] << 0; - case 4: k1 ^= tail[3] << 24; - case 3: k1 ^= tail[2] << 16; - case 2: k1 ^= tail[1] << 8; - case 1: k1 ^= tail[0] << 0; - bmix32(h1,h2,k1,k2,c1,c2); - }; + switch (len & 7) + { + case 7: + k2 ^= tail[6] << 16; + case 6: + k2 ^= tail[5] << 8; + case 5: + k2 ^= tail[4] << 0; + case 4: + k1 ^= tail[3] << 24; + case 3: + k1 ^= tail[2] << 16; + case 2: + k1 ^= tail[1] << 8; + case 1: + k1 ^= tail[0] << 0; + bmix32(h1, h2, k1, k2, c1, c2); + }; - //---------- - // finalization + //---------- + // finalization - h2 ^= len; + h2 ^= len; - h1 += h2; - h2 += h1; + h1 += h2; + h2 += h1; - h1 = fmix32(h1); - h2 = fmix32(h2); + h1 = fmix32(h1); + h2 = fmix32(h2); - h1 += h2; - h2 += h1; + h1 += h2; + h2 += h1; - out[0] = h1; - out[1] = h2; + out[0] = h1; + out[1] = h2; - return *((u64*)&out); + return *((u64*)&out); } /* @@ -532,75 +547,79 @@ u64 GetMurmurHash3(const u8* src, u32 len, u32 samples) */ u64 GetHashHiresTexture(const u8* src, u32 len, u32 samples) { - const u64 m = 0xc6a4a7935bd1e995ULL; - u64 h = len * m; - const int r = 47; - u32 Step = (len / 8); - const u64* data = (const u64*)src; - const u64* end = data + Step; - if (samples == 0) - samples = std::max(Step, 1u); - Step = Step / samples; - if (Step < 1) - Step = 1; - while (data < end) - { - u64 k = data[0]; - data+=Step; - k *= m; - k ^= k >> r; - k *= m; - h ^= k; - h *= m; - } + const u64 m = 0xc6a4a7935bd1e995ULL; + u64 h = len * m; + const int r = 47; + u32 Step = (len / 8); + const u64* data = (const u64*)src; + const u64* end = data + Step; + if (samples == 0) + samples = std::max(Step, 1u); + Step = Step / samples; + if (Step < 1) + Step = 1; + while (data < end) + { + u64 k = data[0]; + data += Step; + k *= m; + k ^= k >> r; + k *= m; + h ^= k; + h *= m; + } - const u8* data2 = (const u8*)end; + const u8* data2 = (const u8*)end; - switch (len & 7) - { - case 7: h ^= u64(data2[6]) << 48; - case 6: h ^= u64(data2[5]) << 40; - case 5: h ^= u64(data2[4]) << 32; - case 4: h ^= u64(data2[3]) << 24; - case 3: h ^= u64(data2[2]) << 16; - case 2: h ^= u64(data2[1]) << 8; - case 1: h ^= u64(data2[0]); - h *= m; - }; + switch (len & 7) + { + case 7: + h ^= u64(data2[6]) << 48; + case 6: + h ^= u64(data2[5]) << 40; + case 5: + h ^= u64(data2[4]) << 32; + case 4: + h ^= u64(data2[3]) << 24; + case 3: + h ^= u64(data2[2]) << 16; + case 2: + h ^= u64(data2[1]) << 8; + case 1: + h ^= u64(data2[0]); + h *= m; + }; - h ^= h >> r; - h *= m; - h ^= h >> r; + h ^= h >> r; + h *= m; + h ^= h >> r; - return h; + return h; } #endif u64 GetHash64(const u8* src, u32 len, u32 samples) { - return ptrHashFunction(src, len, samples); + return ptrHashFunction(src, len, samples); } // sets the hash function used for the texture cache void SetHash64Function() { #if _M_SSE >= 0x402 - if (cpu_info.bSSE4_2) // sse crc32 version - { - ptrHashFunction = &GetCRC32; - } - else + if (cpu_info.bSSE4_2) // sse crc32 version + { + ptrHashFunction = &GetCRC32; + } + else #elif defined(_M_ARM_64) - if (cpu_info.bCRC32) - { - ptrHashFunction = &GetCRC32; - } - else + if (cpu_info.bCRC32) + { + ptrHashFunction = &GetCRC32; + } + else #endif - { - ptrHashFunction = &GetMurmurHash3; - } + { + ptrHashFunction = &GetMurmurHash3; + } } - - - diff --git a/Source/Core/Common/IniFile.cpp b/Source/Core/Common/IniFile.cpp index 0c53d9569e..1383f04c10 100644 --- a/Source/Core/Common/IniFile.cpp +++ b/Source/Core/Common/IniFile.cpp @@ -20,412 +20,412 @@ void IniFile::ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut) { - if (line[0] == '#') - return; + if (line[0] == '#') + return; - size_t firstEquals = line.find("=", 0); + size_t firstEquals = line.find("=", 0); - if (firstEquals != std::string::npos) - { - // Yes, a valid line! - *keyOut = StripSpaces(line.substr(0, firstEquals)); + if (firstEquals != std::string::npos) + { + // Yes, a valid line! + *keyOut = StripSpaces(line.substr(0, firstEquals)); - if (valueOut) - { - *valueOut = StripQuotes(StripSpaces(line.substr(firstEquals + 1, std::string::npos))); - } - } + if (valueOut) + { + *valueOut = StripQuotes(StripSpaces(line.substr(firstEquals + 1, std::string::npos))); + } + } } const std::string& IniFile::NULL_STRING = ""; void IniFile::Section::Set(const std::string& key, const std::string& newValue) { - auto it = values.find(key); - if (it != values.end()) - it->second = newValue; - else - { - values[key] = newValue; - keys_order.push_back(key); - } + auto it = values.find(key); + if (it != values.end()) + it->second = newValue; + else + { + values[key] = newValue; + keys_order.push_back(key); + } } -void IniFile::Section::Set(const std::string& key, const std::string& newValue, const std::string& defaultValue) +void IniFile::Section::Set(const std::string& key, const std::string& newValue, + const std::string& defaultValue) { - if (newValue != defaultValue) - Set(key, newValue); - else - Delete(key); + if (newValue != defaultValue) + Set(key, newValue); + else + Delete(key); } void IniFile::Section::Set(const std::string& key, const std::vector& newValues) { - std::string temp; - // Join the strings with , - for (const std::string& value : newValues) - { - temp = value + ","; - } - // remove last , - temp.resize(temp.length() - 1); - Set(key, temp); + std::string temp; + // Join the strings with , + for (const std::string& value : newValues) + { + temp = value + ","; + } + // remove last , + temp.resize(temp.length() - 1); + Set(key, temp); } -bool IniFile::Section::Get(const std::string& key, std::string* value, const std::string& defaultValue) const +bool IniFile::Section::Get(const std::string& key, std::string* value, + const std::string& defaultValue) const { - auto it = values.find(key); - if (it != values.end()) - { - *value = it->second; - return true; - } - else if (&defaultValue != &NULL_STRING) - { - *value = defaultValue; - return true; - } + auto it = values.find(key); + if (it != values.end()) + { + *value = it->second; + return true; + } + else if (&defaultValue != &NULL_STRING) + { + *value = defaultValue; + return true; + } - return false; + return false; } bool IniFile::Section::Get(const std::string& key, std::vector* out) const { - std::string temp; - bool retval = Get(key, &temp); - if (!retval || temp.empty()) - { - return false; - } + std::string temp; + bool retval = Get(key, &temp); + if (!retval || temp.empty()) + { + return false; + } - // ignore starting comma, if any - size_t subStart = temp.find_first_not_of(","); + // ignore starting comma, if any + size_t subStart = temp.find_first_not_of(","); - // split by comma - while (subStart != std::string::npos) - { - // Find next comma - size_t subEnd = temp.find(',', subStart); - if (subStart != subEnd) - { - // take from first char until next comma - out->push_back(StripSpaces(temp.substr(subStart, subEnd - subStart))); - } + // split by comma + while (subStart != std::string::npos) + { + // Find next comma + size_t subEnd = temp.find(',', subStart); + if (subStart != subEnd) + { + // take from first char until next comma + out->push_back(StripSpaces(temp.substr(subStart, subEnd - subStart))); + } - // Find the next non-comma char - subStart = temp.find_first_not_of(",", subEnd); - } + // Find the next non-comma char + subStart = temp.find_first_not_of(",", subEnd); + } - return true; + return true; } bool IniFile::Section::Get(const std::string& key, int* value, int defaultValue) const { - std::string temp; - bool retval = Get(key, &temp); + std::string temp; + bool retval = Get(key, &temp); - if (retval && TryParse(temp, value)) - return true; + if (retval && TryParse(temp, value)) + return true; - *value = defaultValue; - return false; + *value = defaultValue; + return false; } bool IniFile::Section::Get(const std::string& key, u32* value, u32 defaultValue) const { - std::string temp; - bool retval = Get(key, &temp); + std::string temp; + bool retval = Get(key, &temp); - if (retval && TryParse(temp, value)) - return true; + if (retval && TryParse(temp, value)) + return true; - *value = defaultValue; - return false; + *value = defaultValue; + return false; } bool IniFile::Section::Get(const std::string& key, bool* value, bool defaultValue) const { - std::string temp; - bool retval = Get(key, &temp); + std::string temp; + bool retval = Get(key, &temp); - if (retval && TryParse(temp, value)) - return true; + if (retval && TryParse(temp, value)) + return true; - *value = defaultValue; - return false; + *value = defaultValue; + return false; } bool IniFile::Section::Get(const std::string& key, float* value, float defaultValue) const { - std::string temp; - bool retval = Get(key, &temp); + std::string temp; + bool retval = Get(key, &temp); - if (retval && TryParse(temp, value)) - return true; + if (retval && TryParse(temp, value)) + return true; - *value = defaultValue; - return false; + *value = defaultValue; + return false; } bool IniFile::Section::Get(const std::string& key, double* value, double defaultValue) const { - std::string temp; - bool retval = Get(key, &temp); + std::string temp; + bool retval = Get(key, &temp); - if (retval && TryParse(temp, value)) - return true; + if (retval && TryParse(temp, value)) + return true; - *value = defaultValue; - return false; + *value = defaultValue; + return false; } bool IniFile::Section::Exists(const std::string& key) const { - return values.find(key) != values.end(); + return values.find(key) != values.end(); } bool IniFile::Section::Delete(const std::string& key) { - auto it = values.find(key); - if (it == values.end()) - return false; + auto it = values.find(key); + if (it == values.end()) + return false; - values.erase(it); - keys_order.erase(std::find(keys_order.begin(), keys_order.end(), key)); - return true; + values.erase(it); + keys_order.erase(std::find(keys_order.begin(), keys_order.end(), key)); + return true; } // IniFile const IniFile::Section* IniFile::GetSection(const std::string& sectionName) const { - for (const Section& sect : sections) - if (!strcasecmp(sect.name.c_str(), sectionName.c_str())) - return (&(sect)); - return nullptr; + for (const Section& sect : sections) + if (!strcasecmp(sect.name.c_str(), sectionName.c_str())) + return (&(sect)); + return nullptr; } IniFile::Section* IniFile::GetSection(const std::string& sectionName) { - for (Section& sect : sections) - if (!strcasecmp(sect.name.c_str(), sectionName.c_str())) - return (&(sect)); - return nullptr; + for (Section& sect : sections) + if (!strcasecmp(sect.name.c_str(), sectionName.c_str())) + return (&(sect)); + return nullptr; } IniFile::Section* IniFile::GetOrCreateSection(const std::string& sectionName) { - Section* section = GetSection(sectionName); - if (!section) - { - sections.emplace_back(sectionName); - section = §ions.back(); - } - return section; + Section* section = GetSection(sectionName); + if (!section) + { + sections.emplace_back(sectionName); + section = §ions.back(); + } + return section; } bool IniFile::DeleteSection(const std::string& sectionName) { - Section* s = GetSection(sectionName); - if (!s) - return false; - for (auto iter = sections.begin(); iter != sections.end(); ++iter) - { - if (&(*iter) == s) - { - sections.erase(iter); - return true; - } - } - return false; + Section* s = GetSection(sectionName); + if (!s) + return false; + for (auto iter = sections.begin(); iter != sections.end(); ++iter) + { + if (&(*iter) == s) + { + sections.erase(iter); + return true; + } + } + return false; } bool IniFile::Exists(const std::string& sectionName, const std::string& key) const { - const Section* section = GetSection(sectionName); - if (!section) - return false; - return section->Exists(key); + const Section* section = GetSection(sectionName); + if (!section) + return false; + return section->Exists(key); } -void IniFile::SetLines(const std::string& sectionName, const std::vector &lines) +void IniFile::SetLines(const std::string& sectionName, const std::vector& lines) { - Section* section = GetOrCreateSection(sectionName); - section->lines = lines; + Section* section = GetOrCreateSection(sectionName); + section->lines = lines; } bool IniFile::DeleteKey(const std::string& sectionName, const std::string& key) { - Section* section = GetSection(sectionName); - if (!section) - return false; - return section->Delete(key); + Section* section = GetSection(sectionName); + if (!section) + return false; + return section->Delete(key); } // Return a list of all keys in a section bool IniFile::GetKeys(const std::string& sectionName, std::vector* keys) const { - const Section* section = GetSection(sectionName); - if (!section) - { - return false; - } - *keys = section->keys_order; - return true; + const Section* section = GetSection(sectionName); + if (!section) + { + return false; + } + *keys = section->keys_order; + return true; } // Return a list of all lines in a section -bool IniFile::GetLines(const std::string& sectionName, std::vector* lines, const bool remove_comments) const +bool IniFile::GetLines(const std::string& sectionName, std::vector* lines, + const bool remove_comments) const { - lines->clear(); + lines->clear(); - const Section* section = GetSection(sectionName); - if (!section) - return false; + const Section* section = GetSection(sectionName); + if (!section) + return false; - for (std::string line : section->lines) - { - line = StripSpaces(line); + for (std::string line : section->lines) + { + line = StripSpaces(line); - if (remove_comments) - { - size_t commentPos = line.find('#'); - if (commentPos == 0) - { - continue; - } + if (remove_comments) + { + size_t commentPos = line.find('#'); + if (commentPos == 0) + { + continue; + } - if (commentPos != std::string::npos) - { - line = StripSpaces(line.substr(0, commentPos)); - } - } + if (commentPos != std::string::npos) + { + line = StripSpaces(line.substr(0, commentPos)); + } + } - lines->push_back(line); - } + lines->push_back(line); + } - return true; + return true; } void IniFile::SortSections() { - sections.sort(); + sections.sort(); } bool IniFile::Load(const std::string& filename, bool keep_current_data) { - if (!keep_current_data) - sections.clear(); - // first section consists of the comments before the first real section + if (!keep_current_data) + sections.clear(); + // first section consists of the comments before the first real section - // Open file - std::ifstream in; - OpenFStream(in, filename, std::ios::in); + // Open file + std::ifstream in; + OpenFStream(in, filename, std::ios::in); - if (in.fail()) - return false; + if (in.fail()) + return false; - Section* current_section = nullptr; - bool first_line = true; - while (!in.eof()) - { - std::string line; + Section* current_section = nullptr; + bool first_line = true; + while (!in.eof()) + { + std::string line; - if (!std::getline(in, line)) - { - if (in.eof()) - return true; - else - return false; - } + if (!std::getline(in, line)) + { + if (in.eof()) + return true; + else + return false; + } - // Skips the UTF-8 BOM at the start of files. Notepad likes to add this. - if (first_line && line.substr(0, 3) == "\xEF\xBB\xBF") - line = line.substr(3); - first_line = false; + // Skips the UTF-8 BOM at the start of files. Notepad likes to add this. + if (first_line && line.substr(0, 3) == "\xEF\xBB\xBF") + line = line.substr(3); + first_line = false; #ifndef _WIN32 - // Check for CRLF eol and convert it to LF - if (!line.empty() && line.at(line.size()-1) == '\r') - { - line.erase(line.size()-1); - } + // Check for CRLF eol and convert it to LF + if (!line.empty() && line.at(line.size() - 1) == '\r') + { + line.erase(line.size() - 1); + } #endif - if (line.size() > 0) - { - if (line[0] == '[') - { - size_t endpos = line.find("]"); + if (line.size() > 0) + { + if (line[0] == '[') + { + size_t endpos = line.find("]"); - if (endpos != std::string::npos) - { - // New section! - std::string sub = line.substr(1, endpos - 1); - current_section = GetOrCreateSection(sub); - } - } - else - { - if (current_section) - { - std::string key, value; - ParseLine(line, &key, &value); + if (endpos != std::string::npos) + { + // New section! + std::string sub = line.substr(1, endpos - 1); + current_section = GetOrCreateSection(sub); + } + } + else + { + if (current_section) + { + std::string key, value; + ParseLine(line, &key, &value); - // Lines starting with '$', '*' or '+' are kept verbatim. - // Kind of a hack, but the support for raw lines inside an - // INI is a hack anyway. - if ((key == "" && value == "") || - (line.size() >= 1 && - (line[0] == '$' || - line[0] == '+' || - line[0] == '*'))) - current_section->lines.push_back(line); - else - current_section->Set(key, value); - } - } - } - } + // Lines starting with '$', '*' or '+' are kept verbatim. + // Kind of a hack, but the support for raw lines inside an + // INI is a hack anyway. + if ((key == "" && value == "") || + (line.size() >= 1 && (line[0] == '$' || line[0] == '+' || line[0] == '*'))) + current_section->lines.push_back(line); + else + current_section->Set(key, value); + } + } + } + } - in.close(); - return true; + in.close(); + return true; } bool IniFile::Save(const std::string& filename) { - std::ofstream out; - std::string temp = File::GetTempFilenameForAtomicWrite(filename); - OpenFStream(out, temp, std::ios::out); + std::ofstream out; + std::string temp = File::GetTempFilenameForAtomicWrite(filename); + OpenFStream(out, temp, std::ios::out); - if (out.fail()) - { - return false; - } + if (out.fail()) + { + return false; + } - for (const Section& section : sections) - { - if (section.keys_order.size() != 0 || section.lines.size() != 0) - out << "[" << section.name << "]" << std::endl; + for (const Section& section : sections) + { + if (section.keys_order.size() != 0 || section.lines.size() != 0) + out << "[" << section.name << "]" << std::endl; - if (section.keys_order.size() == 0) - { - for (const std::string& s : section.lines) - out << s << std::endl; - } - else - { - for (const std::string& kvit : section.keys_order) - { - auto pair = section.values.find(kvit); - out << pair->first << " = " << pair->second << std::endl; - } - } - } + if (section.keys_order.size() == 0) + { + for (const std::string& s : section.lines) + out << s << std::endl; + } + else + { + for (const std::string& kvit : section.keys_order) + { + auto pair = section.values.find(kvit); + out << pair->first << " = " << pair->second << std::endl; + } + } + } - out.close(); + out.close(); - return File::RenameSync(temp, filename); + return File::RenameSync(temp, filename); } // Unit test. TODO: Move to the real unit test framework. diff --git a/Source/Core/Common/IniFile.h b/Source/Core/Common/IniFile.h index ed20cd6fa0..d0b3ec3618 100644 --- a/Source/Core/Common/IniFile.h +++ b/Source/Core/Common/IniFile.h @@ -16,141 +16,135 @@ struct CaseInsensitiveStringCompare { - bool operator() (const std::string& a, const std::string& b) const - { - return strcasecmp(a.c_str(), b.c_str()) < 0; - } + bool operator()(const std::string& a, const std::string& b) const + { + return strcasecmp(a.c_str(), b.c_str()) < 0; + } }; class IniFile { public: - class Section - { - friend class IniFile; + class Section + { + friend class IniFile; - public: - Section() {} - Section(const std::string& _name) : name(_name) {} + public: + Section() {} + Section(const std::string& _name) : name(_name) {} + bool Exists(const std::string& key) const; + bool Delete(const std::string& key); - bool Exists(const std::string& key) const; - bool Delete(const std::string& key); + void Set(const std::string& key, const std::string& newValue); + void Set(const std::string& key, const std::string& newValue, const std::string& defaultValue); - void Set(const std::string& key, const std::string& newValue); - void Set(const std::string& key, const std::string& newValue, const std::string& defaultValue); + void Set(const std::string& key, u32 newValue) + { + Set(key, StringFromFormat("0x%08x", newValue)); + } - void Set(const std::string& key, u32 newValue) - { - Set(key, StringFromFormat("0x%08x", newValue)); - } + void Set(const std::string& key, float newValue) + { + Set(key, StringFromFormat("%#.9g", newValue)); + } - void Set(const std::string& key, float newValue) - { - Set(key, StringFromFormat("%#.9g", newValue)); - } + void Set(const std::string& key, double newValue) + { + Set(key, StringFromFormat("%#.17g", newValue)); + } - void Set(const std::string& key, double newValue) - { - Set(key, StringFromFormat("%#.17g", newValue)); - } + void Set(const std::string& key, int newValue) { Set(key, StringFromInt(newValue)); } + void Set(const std::string& key, bool newValue) { Set(key, StringFromBool(newValue)); } + template + void Set(const std::string& key, T newValue, const T defaultValue) + { + if (newValue != defaultValue) + Set(key, newValue); + else + Delete(key); + } - void Set(const std::string& key, int newValue) - { - Set(key, StringFromInt(newValue)); - } + void Set(const std::string& key, const std::vector& newValues); - void Set(const std::string& key, bool newValue) - { - Set(key, StringFromBool(newValue)); - } + bool Get(const std::string& key, std::string* value, + const std::string& defaultValue = NULL_STRING) const; + bool Get(const std::string& key, int* value, int defaultValue = 0) const; + bool Get(const std::string& key, u32* value, u32 defaultValue = 0) const; + bool Get(const std::string& key, bool* value, bool defaultValue = false) const; + bool Get(const std::string& key, float* value, float defaultValue = 0.0f) const; + bool Get(const std::string& key, double* value, double defaultValue = 0.0) const; + bool Get(const std::string& key, std::vector* values) const; - template - void Set(const std::string& key, T newValue, const T defaultValue) - { - if (newValue != defaultValue) - Set(key, newValue); - else - Delete(key); - } + bool operator<(const Section& other) const { return name < other.name; } + protected: + std::string name; - void Set(const std::string& key, const std::vector& newValues); + std::vector keys_order; + std::map values; - bool Get(const std::string& key, std::string* value, const std::string& defaultValue = NULL_STRING) const; - bool Get(const std::string& key, int* value, int defaultValue = 0) const; - bool Get(const std::string& key, u32* value, u32 defaultValue = 0) const; - bool Get(const std::string& key, bool* value, bool defaultValue = false) const; - bool Get(const std::string& key, float* value, float defaultValue = 0.0f) const; - bool Get(const std::string& key, double* value, double defaultValue = 0.0) const; - bool Get(const std::string& key, std::vector* values) const; + std::vector lines; + }; - bool operator < (const Section& other) const - { - return name < other.name; - } + /** + * Loads sections and keys. + * @param filename filename of the ini file which should be loaded + * @param keep_current_data If true, "extends" the currently loaded list of sections and keys with + * the loaded data (and replaces existing entries). If false, existing data will be erased. + * @warning Using any other operations than "Get*" and "Exists" is untested and will behave + * unexpectedly + * @todo This really is just a hack to support having two levels of gameinis (defaults and + * user-specified) and should eventually be replaced with a less stupid system. + */ + bool Load(const std::string& filename, bool keep_current_data = false); - protected: - std::string name; + bool Save(const std::string& filename); - std::vector keys_order; - std::map values; + // Returns true if key exists in section + bool Exists(const std::string& sectionName, const std::string& key) const; - std::vector lines; - }; + template + bool GetIfExists(const std::string& sectionName, const std::string& key, T* value) + { + if (Exists(sectionName, key)) + return GetOrCreateSection(sectionName)->Get(key, value); - /** - * Loads sections and keys. - * @param filename filename of the ini file which should be loaded - * @param keep_current_data If true, "extends" the currently loaded list of sections and keys with the loaded data (and replaces existing entries). If false, existing data will be erased. - * @warning Using any other operations than "Get*" and "Exists" is untested and will behave unexpectedly - * @todo This really is just a hack to support having two levels of gameinis (defaults and user-specified) and should eventually be replaced with a less stupid system. - */ - bool Load(const std::string& filename, bool keep_current_data = false); + return false; + } - bool Save(const std::string& filename); + template + bool GetIfExists(const std::string& sectionName, const std::string& key, T* value, T defaultValue) + { + if (Exists(sectionName, key)) + return GetOrCreateSection(sectionName)->Get(key, value, defaultValue); + else + *value = defaultValue; - // Returns true if key exists in section - bool Exists(const std::string& sectionName, const std::string& key) const; + return false; + } - template bool GetIfExists(const std::string& sectionName, const std::string& key, T* value) - { - if (Exists(sectionName, key)) - return GetOrCreateSection(sectionName)->Get(key, value); + bool GetKeys(const std::string& sectionName, std::vector* keys) const; - return false; - } + void SetLines(const std::string& sectionName, const std::vector& lines); + bool GetLines(const std::string& sectionName, std::vector* lines, + const bool remove_comments = true) const; - template bool GetIfExists(const std::string& sectionName, const std::string& key, T* value, T defaultValue) - { - if (Exists(sectionName, key)) - return GetOrCreateSection(sectionName)->Get(key, value, defaultValue); - else - *value = defaultValue; + bool DeleteKey(const std::string& sectionName, const std::string& key); + bool DeleteSection(const std::string& sectionName); - return false; - } + void SortSections(); - bool GetKeys(const std::string& sectionName, std::vector* keys) const; + Section* GetOrCreateSection(const std::string& section); - void SetLines(const std::string& sectionName, const std::vector& lines); - bool GetLines(const std::string& sectionName, std::vector* lines, const bool remove_comments = true) const; - - bool DeleteKey(const std::string& sectionName, const std::string& key); - bool DeleteSection(const std::string& sectionName); - - void SortSections(); - - Section* GetOrCreateSection(const std::string& section); - - // This function is related to parsing data from lines of INI files - // It's used outside of IniFile, which is why it is exposed publicly - // In particular it is used in PostProcessing for its configuration - static void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut); + // This function is related to parsing data from lines of INI files + // It's used outside of IniFile, which is why it is exposed publicly + // In particular it is used in PostProcessing for its configuration + static void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut); private: - std::list
sections; + std::list
sections; - const Section* GetSection(const std::string& section) const; - Section* GetSection(const std::string& section); + const Section* GetSection(const std::string& section) const; + Section* GetSection(const std::string& section); - static const std::string& NULL_STRING; + static const std::string& NULL_STRING; }; diff --git a/Source/Core/Common/Intrinsics.h b/Source/Core/Common/Intrinsics.h index 15858d537e..6ea9038c67 100644 --- a/Source/Core/Common/Intrinsics.h +++ b/Source/Core/Common/Intrinsics.h @@ -13,19 +13,19 @@ #endif #if defined _M_GENERIC -# define _M_SSE 0 +#define _M_SSE 0 #elif _MSC_VER || __INTEL_COMPILER -# define _M_SSE 0x402 +#define _M_SSE 0x402 #elif defined __GNUC__ -# if defined __SSE4_2__ -# define _M_SSE 0x402 -# elif defined __SSE4_1__ -# define _M_SSE 0x401 -# elif defined __SSSE3__ -# define _M_SSE 0x301 -# elif defined __SSE3__ -# define _M_SSE 0x300 -# endif +#if defined __SSE4_2__ +#define _M_SSE 0x402 +#elif defined __SSE4_1__ +#define _M_SSE 0x401 +#elif defined __SSSE3__ +#define _M_SSE 0x301 +#elif defined __SSE3__ +#define _M_SSE 0x300 +#endif #endif -#endif // _M_X86 +#endif // _M_X86 diff --git a/Source/Core/Common/JitRegister.cpp b/Source/Core/Common/JitRegister.cpp index 4b8fd0b619..45a04d6149 100644 --- a/Source/Core/Common/JitRegister.cpp +++ b/Source/Core/Common/JitRegister.cpp @@ -37,71 +37,66 @@ static File::IOFile s_perf_map_file; namespace JitRegister { - void Init(const std::string& perf_dir) { #if defined USE_OPROFILE && USE_OPROFILE - s_agent = op_open_agent(); + s_agent = op_open_agent(); #endif - if (!perf_dir.empty() || getenv("PERF_BUILDID_DIR")) - { - std::string dir = perf_dir.empty() ? "/tmp" : perf_dir; - std::string filename = StringFromFormat("%s/perf-%d.map", dir.data(), getpid()); - s_perf_map_file.Open(filename, "w"); - // Disable buffering in order to avoid missing some mappings - // if the event of a crash: - std::setvbuf(s_perf_map_file.GetHandle(), nullptr, _IONBF, 0); - } + if (!perf_dir.empty() || getenv("PERF_BUILDID_DIR")) + { + std::string dir = perf_dir.empty() ? "/tmp" : perf_dir; + std::string filename = StringFromFormat("%s/perf-%d.map", dir.data(), getpid()); + s_perf_map_file.Open(filename, "w"); + // Disable buffering in order to avoid missing some mappings + // if the event of a crash: + std::setvbuf(s_perf_map_file.GetHandle(), nullptr, _IONBF, 0); + } } void Shutdown() { #if defined USE_OPROFILE && USE_OPROFILE - op_close_agent(s_agent); - s_agent = nullptr; + op_close_agent(s_agent); + s_agent = nullptr; #endif #ifdef USE_VTUNE - iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, nullptr); + iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, nullptr); #endif - if (s_perf_map_file.IsOpen()) - s_perf_map_file.Close(); + if (s_perf_map_file.IsOpen()) + s_perf_map_file.Close(); } -void RegisterV(const void* base_address, u32 code_size, - const char* format, va_list args) +void RegisterV(const void* base_address, u32 code_size, const char* format, va_list args) { #if !(defined USE_OPROFILE && USE_OPROFILE) && !defined(USE_VTUNE) - if (!s_perf_map_file.IsOpen()) - return; + if (!s_perf_map_file.IsOpen()) + return; #endif - std::string symbol_name = StringFromFormatV(format, args); + std::string symbol_name = StringFromFormatV(format, args); #if defined USE_OPROFILE && USE_OPROFILE - op_write_native_code(s_agent, symbol_name.data(), (u64)base_address, - base_address, code_size); + op_write_native_code(s_agent, symbol_name.data(), (u64)base_address, base_address, code_size); #endif #ifdef USE_VTUNE - iJIT_Method_Load jmethod = {0}; - jmethod.method_id = iJIT_GetNewMethodID(); - jmethod.method_load_address = const_cast(base_address); - jmethod.method_size = code_size; - jmethod.method_name = const_cast(symbol_name.data()); - iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&jmethod); + iJIT_Method_Load jmethod = {0}; + jmethod.method_id = iJIT_GetNewMethodID(); + jmethod.method_load_address = const_cast(base_address); + jmethod.method_size = code_size; + jmethod.method_name = const_cast(symbol_name.data()); + iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&jmethod); #endif - // Linux perf /tmp/perf-$pid.map: - if (s_perf_map_file.IsOpen()) - { - std::string entry = StringFromFormat( - "%" PRIx64 " %x %s\n", - (u64)base_address, code_size, symbol_name.data()); - s_perf_map_file.WriteBytes(entry.data(), entry.size()); - } + // Linux perf /tmp/perf-$pid.map: + if (s_perf_map_file.IsOpen()) + { + std::string entry = + StringFromFormat("%" PRIx64 " %x %s\n", (u64)base_address, code_size, symbol_name.data()); + s_perf_map_file.WriteBytes(entry.data(), entry.size()); + } } - } diff --git a/Source/Core/Common/JitRegister.h b/Source/Core/Common/JitRegister.h index 9342392a41..f4068bc282 100644 --- a/Source/Core/Common/JitRegister.h +++ b/Source/Core/Common/JitRegister.h @@ -9,29 +9,24 @@ namespace JitRegister { - void Init(const std::string& perf_dir); void Shutdown(); -void RegisterV(const void* base_address, u32 code_size, - const char* format, va_list args); +void RegisterV(const void* base_address, u32 code_size, const char* format, va_list args); -inline void Register(const void* base_address, u32 code_size, - const char* format, ...) +inline void Register(const void* base_address, u32 code_size, const char* format, ...) { - va_list args; - va_start(args, format); - RegisterV(base_address, code_size, format, args); - va_end(args); + va_list args; + va_start(args, format); + RegisterV(base_address, code_size, format, args); + va_end(args); } -inline void Register(const void* start, const void* end, - const char* format, ...) +inline void Register(const void* start, const void* end, const char* format, ...) { - va_list args; - va_start(args, format); - u32 code_size = (u32) ((const char*) end - (const char*) start); - RegisterV(start, code_size, format, args); - va_end(args); + va_list args; + va_start(args, format); + u32 code_size = (u32)((const char*)end - (const char*)start); + RegisterV(start, code_size, format, args); + va_end(args); } - } diff --git a/Source/Core/Common/LinearDiskCache.h b/Source/Core/Common/LinearDiskCache.h index 264c1f3b6b..2db1a0ad82 100644 --- a/Source/Core/Common/LinearDiskCache.h +++ b/Source/Core/Common/LinearDiskCache.h @@ -14,14 +14,14 @@ #include "Common/FileUtil.h" // On disk format: -//header{ +// header{ // u32 'DCAC'; // u32 version; // svn_rev // u16 sizeof(key_type); // u16 sizeof(value_type); //} -//key_value_pair{ +// key_value_pair{ // u32 value_size; // key_type key; // value_type[value_size] value; @@ -31,7 +31,7 @@ template class LinearDiskCacheReader { public: - virtual void Read(const K& key, const V* value, u32 value_size) = 0; + virtual void Read(const K& key, const V* value, u32 value_size) = 0; }; // Dead simple unsorted key-value store with append functionality. @@ -50,151 +50,143 @@ template class LinearDiskCache { public: - // return number of read entries - u32 OpenAndRead(const std::string& filename, LinearDiskCacheReader &reader) - { - using std::ios_base; + // return number of read entries + u32 OpenAndRead(const std::string& filename, LinearDiskCacheReader& reader) + { + using std::ios_base; - // Since we're reading/writing directly to the storage of K instances, - // K must be trivially copyable. TODO: Remove #if once GCC 5.0 is a - // minimum requirement. +// Since we're reading/writing directly to the storage of K instances, +// K must be trivially copyable. TODO: Remove #if once GCC 5.0 is a +// minimum requirement. #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 - static_assert(std::has_trivial_copy_constructor::value, "K must be a trivially copyable type"); + static_assert(std::has_trivial_copy_constructor::value, + "K must be a trivially copyable type"); #else - static_assert(std::is_trivially_copyable::value, "K must be a trivially copyable type"); + static_assert(std::is_trivially_copyable::value, "K must be a trivially copyable type"); #endif - // close any currently opened file - Close(); - m_num_entries = 0; + // close any currently opened file + Close(); + m_num_entries = 0; - // try opening for reading/writing - OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary); + // try opening for reading/writing + OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary); - m_file.seekg(0, std::ios::end); - std::fstream::pos_type end_pos = m_file.tellg(); - m_file.seekg(0, std::ios::beg); - std::fstream::pos_type start_pos = m_file.tellg(); - std::streamoff file_size = end_pos - start_pos; + m_file.seekg(0, std::ios::end); + std::fstream::pos_type end_pos = m_file.tellg(); + m_file.seekg(0, std::ios::beg); + std::fstream::pos_type start_pos = m_file.tellg(); + std::streamoff file_size = end_pos - start_pos; - m_header.Init(); - if (m_file.is_open() && ValidateHeader()) - { - // good header, read some key/value pairs - K key; + m_header.Init(); + if (m_file.is_open() && ValidateHeader()) + { + // good header, read some key/value pairs + K key; - V* value = nullptr; - u32 value_size = 0; - u32 entry_number = 0; + V* value = nullptr; + u32 value_size = 0; + u32 entry_number = 0; - std::fstream::pos_type last_pos = m_file.tellg(); + std::fstream::pos_type last_pos = m_file.tellg(); - while (Read(&value_size)) - { - std::streamoff next_extent = (last_pos - start_pos) + sizeof(value_size) + value_size; - if (next_extent > file_size) - break; + while (Read(&value_size)) + { + std::streamoff next_extent = (last_pos - start_pos) + sizeof(value_size) + value_size; + if (next_extent > file_size) + break; - delete[] value; - value = new V[value_size]; + delete[] value; + value = new V[value_size]; - // read key/value and pass to reader - if (Read(&key) && - Read(value, value_size) && - Read(&entry_number) && - entry_number == m_num_entries+1) - { - reader.Read(key, value, value_size); - } - else - { - break; - } + // read key/value and pass to reader + if (Read(&key) && Read(value, value_size) && Read(&entry_number) && + entry_number == m_num_entries + 1) + { + reader.Read(key, value, value_size); + } + else + { + break; + } - m_num_entries++; - last_pos = m_file.tellg(); - } - m_file.seekp(last_pos); - m_file.clear(); + m_num_entries++; + last_pos = m_file.tellg(); + } + m_file.seekp(last_pos); + m_file.clear(); - delete[] value; - return m_num_entries; - } + delete[] value; + return m_num_entries; + } - // failed to open file for reading or bad header - // close and recreate file - Close(); - m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary); - WriteHeader(); - return 0; - } + // failed to open file for reading or bad header + // close and recreate file + Close(); + m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary); + WriteHeader(); + return 0; + } - void Sync() - { - m_file.flush(); - } + void Sync() { m_file.flush(); } + void Close() + { + if (m_file.is_open()) + m_file.close(); + // clear any error flags + m_file.clear(); + } - void Close() - { - if (m_file.is_open()) - m_file.close(); - // clear any error flags - m_file.clear(); - } - - // Appends a key-value pair to the store. - void Append(const K& key, const V* value, u32 value_size) - { - // TODO: Should do a check that we don't already have "key"? (I think each caller does that already.) - Write(&value_size); - Write(&key); - Write(value, value_size); - m_num_entries++; - Write(&m_num_entries); - } + // Appends a key-value pair to the store. + void Append(const K& key, const V* value, u32 value_size) + { + // TODO: Should do a check that we don't already have "key"? (I think each caller does that + // already.) + Write(&value_size); + Write(&key); + Write(value, value_size); + m_num_entries++; + Write(&m_num_entries); + } private: - void WriteHeader() - { - Write(&m_header); - } + void WriteHeader() { Write(&m_header); } + bool ValidateHeader() + { + char file_header[sizeof(Header)]; - bool ValidateHeader() - { - char file_header[sizeof(Header)]; + return (Read(file_header, sizeof(Header)) && + !memcmp((const char*)&m_header, file_header, sizeof(Header))); + } - return (Read(file_header, sizeof(Header)) && - !memcmp((const char*)&m_header, file_header, sizeof(Header))); - } + template + bool Write(const D* data, u32 count = 1) + { + return m_file.write((const char*)data, count * sizeof(D)).good(); + } - template - bool Write(const D* data, u32 count = 1) - { - return m_file.write((const char*)data, count * sizeof(D)).good(); - } + template + bool Read(const D* data, u32 count = 1) + { + return m_file.read((char*)data, count * sizeof(D)).good(); + } - template - bool Read(const D* data, u32 count = 1) - { - return m_file.read((char*)data, count * sizeof(D)).good(); - } + struct Header + { + void Init() + { + // Null-terminator is intentionally not copied. + std::memcpy(&id, "DCAC", sizeof(u32)); + std::memcpy(ver, scm_rev_git_str.c_str(), std::min(scm_rev_git_str.size(), sizeof(ver))); + } - struct Header - { - void Init() - { - // Null-terminator is intentionally not copied. - std::memcpy(&id, "DCAC", sizeof(u32)); - std::memcpy(ver, scm_rev_git_str.c_str(), std::min(scm_rev_git_str.size(), sizeof(ver))); - } + u32 id; + const u16 key_t_size = sizeof(K); + const u16 value_t_size = sizeof(V); + char ver[40] = {}; - u32 id; - const u16 key_t_size = sizeof(K); - const u16 value_t_size = sizeof(V); - char ver[40] = {}; + } m_header; - } m_header; - - std::fstream m_file; - u32 m_num_entries; + std::fstream m_file; + u32 m_num_entries; }; diff --git a/Source/Core/Common/Logging/ConsoleListener.h b/Source/Core/Common/Logging/ConsoleListener.h index 06b34cdf8f..0a10c8855b 100644 --- a/Source/Core/Common/Logging/ConsoleListener.h +++ b/Source/Core/Common/Logging/ConsoleListener.h @@ -9,11 +9,11 @@ class ConsoleListener : public LogListener { public: - ConsoleListener(); - ~ConsoleListener(); + ConsoleListener(); + ~ConsoleListener(); - void Log(LogTypes::LOG_LEVELS, const char* text) override; + void Log(LogTypes::LOG_LEVELS, const char* text) override; private: - bool m_use_color; + bool m_use_color; }; diff --git a/Source/Core/Common/Logging/ConsoleListenerDroid.cpp b/Source/Core/Common/Logging/ConsoleListenerDroid.cpp index 9637200813..81b3a1335f 100644 --- a/Source/Core/Common/Logging/ConsoleListenerDroid.cpp +++ b/Source/Core/Common/Logging/ConsoleListenerDroid.cpp @@ -16,27 +16,27 @@ ConsoleListener::~ConsoleListener() void ConsoleListener::Log(LogTypes::LOG_LEVELS level, const char* text) { - android_LogPriority logLevel = ANDROID_LOG_UNKNOWN; + android_LogPriority logLevel = ANDROID_LOG_UNKNOWN; - // Map dolphin's log levels to android's - switch(level) - { - case LogTypes::LOG_LEVELS::LDEBUG: - logLevel = ANDROID_LOG_DEBUG; - break; - case LogTypes::LOG_LEVELS::LINFO: - logLevel = ANDROID_LOG_INFO; - break; - case LogTypes::LOG_LEVELS::LWARNING: - logLevel = ANDROID_LOG_WARN; - break; - case LogTypes::LOG_LEVELS::LERROR: - logLevel = ANDROID_LOG_ERROR; - break; - case LogTypes::LOG_LEVELS::LNOTICE: - logLevel = ANDROID_LOG_INFO; - break; - } + // Map dolphin's log levels to android's + switch (level) + { + case LogTypes::LOG_LEVELS::LDEBUG: + logLevel = ANDROID_LOG_DEBUG; + break; + case LogTypes::LOG_LEVELS::LINFO: + logLevel = ANDROID_LOG_INFO; + break; + case LogTypes::LOG_LEVELS::LWARNING: + logLevel = ANDROID_LOG_WARN; + break; + case LogTypes::LOG_LEVELS::LERROR: + logLevel = ANDROID_LOG_ERROR; + break; + case LogTypes::LOG_LEVELS::LNOTICE: + logLevel = ANDROID_LOG_INFO; + break; + } - __android_log_write(logLevel, "Dolphinemu", text); + __android_log_write(logLevel, "Dolphinemu", text); } diff --git a/Source/Core/Common/Logging/ConsoleListenerNix.cpp b/Source/Core/Common/Logging/ConsoleListenerNix.cpp index 4526bc82b6..6bb5e12686 100644 --- a/Source/Core/Common/Logging/ConsoleListenerNix.cpp +++ b/Source/Core/Common/Logging/ConsoleListenerNix.cpp @@ -14,39 +14,39 @@ ConsoleListener::ConsoleListener() { - m_use_color = !!isatty(fileno(stdout)); + m_use_color = !!isatty(fileno(stdout)); } ConsoleListener::~ConsoleListener() { - fflush(nullptr); + fflush(nullptr); } void ConsoleListener::Log(LogTypes::LOG_LEVELS level, const char* text) { - char color_attr[16] = ""; - char reset_attr[16] = ""; + char color_attr[16] = ""; + char reset_attr[16] = ""; - if (m_use_color) - { - strcpy(reset_attr, "\x1b[0m"); - switch (level) - { - case LogTypes::LOG_LEVELS::LNOTICE: - // light green - strcpy(color_attr, "\x1b[92m"); - break; - case LogTypes::LOG_LEVELS::LERROR: - // light red - strcpy(color_attr, "\x1b[91m"); - break; - case LogTypes::LOG_LEVELS::LWARNING: - // light yellow - strcpy(color_attr, "\x1b[93m"); - break; - default: - break; - } - } - fprintf(stderr, "%s%s%s", color_attr, text, reset_attr); + if (m_use_color) + { + strcpy(reset_attr, "\x1b[0m"); + switch (level) + { + case LogTypes::LOG_LEVELS::LNOTICE: + // light green + strcpy(color_attr, "\x1b[92m"); + break; + case LogTypes::LOG_LEVELS::LERROR: + // light red + strcpy(color_attr, "\x1b[91m"); + break; + case LogTypes::LOG_LEVELS::LWARNING: + // light yellow + strcpy(color_attr, "\x1b[93m"); + break; + default: + break; + } + } + fprintf(stderr, "%s%s%s", color_attr, text, reset_attr); } diff --git a/Source/Core/Common/Logging/ConsoleListenerWin.cpp b/Source/Core/Common/Logging/ConsoleListenerWin.cpp index 8b5eeaf573..1a6bdf16e9 100644 --- a/Source/Core/Common/Logging/ConsoleListenerWin.cpp +++ b/Source/Core/Common/Logging/ConsoleListenerWin.cpp @@ -16,5 +16,5 @@ ConsoleListener::~ConsoleListener() void ConsoleListener::Log(LogTypes::LOG_LEVELS level, const char* text) { - ::OutputDebugStringA(text); + ::OutputDebugStringA(text); } diff --git a/Source/Core/Common/Logging/Log.h b/Source/Core/Common/Logging/Log.h index 7ed6ea7e63..8245eb8d01 100644 --- a/Source/Core/Common/Logging/Log.h +++ b/Source/Core/Common/Logging/Log.h @@ -6,95 +6,115 @@ namespace LogTypes { - enum LOG_TYPE { - ACTIONREPLAY, - AUDIO, - AUDIO_INTERFACE, - BOOT, - COMMANDPROCESSOR, - COMMON, - CONSOLE, - DISCIO, - DSPHLE, - DSPLLE, - DSP_MAIL, - DSPINTERFACE, - DVDINTERFACE, - DYNA_REC, - EXPANSIONINTERFACE, - FILEMON, - GDB_STUB, - GPFIFO, - HOST_GPU, - MASTER_LOG, - MEMMAP, - MEMCARD_MANAGER, - NETPLAY, - OSHLE, - OSREPORT, - PAD, - PIXELENGINE, - PROCESSORINTERFACE, - POWERPC, - SERIALINTERFACE, - SP1, - VIDEO, - VIDEOINTERFACE, - WII_IPC, - WII_IPC_DVD, - WII_IPC_ES, - WII_IPC_FILEIO, - WII_IPC_HID, - WII_IPC_HLE, - WII_IPC_NET, - WII_IPC_SD, - WII_IPC_SSL, - WII_IPC_STM, - WII_IPC_WC24, - WII_IPC_WIIMOTE, - WIIMOTE, + ACTIONREPLAY, + AUDIO, + AUDIO_INTERFACE, + BOOT, + COMMANDPROCESSOR, + COMMON, + CONSOLE, + DISCIO, + DSPHLE, + DSPLLE, + DSP_MAIL, + DSPINTERFACE, + DVDINTERFACE, + DYNA_REC, + EXPANSIONINTERFACE, + FILEMON, + GDB_STUB, + GPFIFO, + HOST_GPU, + MASTER_LOG, + MEMMAP, + MEMCARD_MANAGER, + NETPLAY, + OSHLE, + OSREPORT, + PAD, + PIXELENGINE, + PROCESSORINTERFACE, + POWERPC, + SERIALINTERFACE, + SP1, + VIDEO, + VIDEOINTERFACE, + WII_IPC, + WII_IPC_DVD, + WII_IPC_ES, + WII_IPC_FILEIO, + WII_IPC_HID, + WII_IPC_HLE, + WII_IPC_NET, + WII_IPC_SD, + WII_IPC_SSL, + WII_IPC_STM, + WII_IPC_WC24, + WII_IPC_WIIMOTE, + WIIMOTE, - NUMBER_OF_LOGS // Must be last + NUMBER_OF_LOGS // Must be last }; enum LOG_LEVELS { - LNOTICE = 1, // VERY important information that is NOT errors. Like startup and OSReports. - LERROR = 2, // Critical errors - LWARNING = 3, // Something is suspicious. - LINFO = 4, // General information. - LDEBUG = 5, // Detailed debugging - might make things slow. + LNOTICE = 1, // VERY important information that is NOT errors. Like startup and OSReports. + LERROR = 2, // Critical errors + LWARNING = 3, // Something is suspicious. + LINFO = 4, // General information. + LDEBUG = 5, // Detailed debugging - might make things slow. }; static const char LOG_LEVEL_TO_CHAR[7] = "-NEWID"; } // namespace -void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, - const char* file, int line, const char* fmt, ...) +void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, + const char* fmt, ...) #ifdef __GNUC__ - __attribute__((format(printf, 5, 6))) + __attribute__((format(printf, 5, 6))) #endif - ; + ; #if defined LOGGING || defined _DEBUG || defined DEBUGFAST #define MAX_LOGLEVEL LogTypes::LOG_LEVELS::LDEBUG #else #ifndef MAX_LOGLEVEL #define MAX_LOGLEVEL LogTypes::LOG_LEVELS::LWARNING -#endif // loglevel -#endif // logging +#endif // loglevel +#endif // logging // Let the compiler optimize this out -#define GENERIC_LOG(t, v, ...) { \ - if (v <= MAX_LOGLEVEL) \ - GenericLog(v, t, __FILE__, __LINE__, __VA_ARGS__); \ - } +#define GENERIC_LOG(t, v, ...) \ + { \ + if (v <= MAX_LOGLEVEL) \ + GenericLog(v, t, __FILE__, __LINE__, __VA_ARGS__); \ + } -#define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (0) -#define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (0) -#define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (0) -#define INFO_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LINFO, __VA_ARGS__) } while (0) -#define DEBUG_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LDEBUG, __VA_ARGS__) } while (0) +#define ERROR_LOG(t, ...) \ + do \ + { \ + GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) \ + } while (0) +#define WARN_LOG(t, ...) \ + do \ + { \ + GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) \ + } while (0) +#define NOTICE_LOG(t, ...) \ + do \ + { \ + GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) \ + } while (0) +#define INFO_LOG(t, ...) \ + do \ + { \ + GENERIC_LOG(LogTypes::t, LogTypes::LINFO, __VA_ARGS__) \ + } while (0) +#define DEBUG_LOG(t, ...) \ + do \ + { \ + GENERIC_LOG(LogTypes::t, LogTypes::LDEBUG, __VA_ARGS__) \ + } while (0) diff --git a/Source/Core/Common/Logging/LogManager.cpp b/Source/Core/Common/Logging/LogManager.cpp index 006a5f6ffc..a24a0bbc9a 100644 --- a/Source/Core/Common/Logging/LogManager.cpp +++ b/Source/Core/Common/Logging/LogManager.cpp @@ -11,160 +11,155 @@ #include "Common/FileUtil.h" #include "Common/IniFile.h" -#include "Common/StringUtil.h" -#include "Common/Timer.h" #include "Common/Logging/ConsoleListener.h" #include "Common/Logging/Log.h" #include "Common/Logging/LogManager.h" +#include "Common/StringUtil.h" +#include "Common/Timer.h" -void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, - const char* file, int line, const char* fmt, ...) +void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, + const char* fmt, ...) { - va_list args; - va_start(args, fmt); - if (LogManager::GetInstance()) - LogManager::GetInstance()->Log(level, type, - file, line, fmt, args); - va_end(args); + va_list args; + va_start(args, fmt); + if (LogManager::GetInstance()) + LogManager::GetInstance()->Log(level, type, file, line, fmt, args); + va_end(args); } LogManager* LogManager::m_logManager = nullptr; LogManager::LogManager() { - // create log containers - m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay"); - m_Log[LogTypes::AUDIO] = new LogContainer("Audio", "Audio Emulator"); - m_Log[LogTypes::AUDIO_INTERFACE] = new LogContainer("AI", "Audio Interface (AI)"); - m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot"); - m_Log[LogTypes::COMMANDPROCESSOR] = new LogContainer("CP", "CommandProc"); - m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common"); - m_Log[LogTypes::CONSOLE] = new LogContainer("CONSOLE", "Dolphin Console"); - m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO"); - m_Log[LogTypes::DSPHLE] = new LogContainer("DSPHLE", "DSP HLE"); - m_Log[LogTypes::DSPLLE] = new LogContainer("DSPLLE", "DSP LLE"); - m_Log[LogTypes::DSP_MAIL] = new LogContainer("DSPMails", "DSP Mails"); - m_Log[LogTypes::DSPINTERFACE] = new LogContainer("DSP", "DSPInterface"); - m_Log[LogTypes::DVDINTERFACE] = new LogContainer("DVD", "DVD Interface"); - m_Log[LogTypes::DYNA_REC] = new LogContainer("JIT", "Dynamic Recompiler"); - m_Log[LogTypes::EXPANSIONINTERFACE] = new LogContainer("EXI", "Expansion Interface"); - m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor"); - m_Log[LogTypes::GDB_STUB] = new LogContainer("GDB_STUB", "GDB Stub"); - m_Log[LogTypes::GPFIFO] = new LogContainer("GP", "GPFifo"); - m_Log[LogTypes::HOST_GPU] = new LogContainer("Host GPU", "Host GPU"); - m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log"); - m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); - m_Log[LogTypes::MEMMAP] = new LogContainer("MI", "MI & memmap"); - m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); - m_Log[LogTypes::OSHLE] = new LogContainer("HLE", "HLE"); - m_Log[LogTypes::OSREPORT] = new LogContainer("OSREPORT", "OSReport"); - m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad"); - m_Log[LogTypes::PIXELENGINE] = new LogContainer("PE", "PixelEngine"); - m_Log[LogTypes::PROCESSORINTERFACE] = new LogContainer("PI", "ProcessorInt"); - m_Log[LogTypes::POWERPC] = new LogContainer("PowerPC", "IBM CPU"); - m_Log[LogTypes::SERIALINTERFACE] = new LogContainer("SI", "Serial Interface (SI)"); - m_Log[LogTypes::SP1] = new LogContainer("SP1", "Serial Port 1"); - m_Log[LogTypes::VIDEO] = new LogContainer("Video", "Video Backend"); - m_Log[LogTypes::VIDEOINTERFACE] = new LogContainer("VI", "Video Interface (VI)"); - m_Log[LogTypes::WIIMOTE] = new LogContainer("Wiimote", "Wiimote"); - m_Log[LogTypes::WII_IPC] = new LogContainer("WII_IPC", "WII IPC"); - m_Log[LogTypes::WII_IPC_DVD] = new LogContainer("WII_IPC_DVD", "WII IPC DVD"); - m_Log[LogTypes::WII_IPC_ES] = new LogContainer("WII_IPC_ES", "WII IPC ES"); - m_Log[LogTypes::WII_IPC_FILEIO] = new LogContainer("WII_IPC_FILEIO", "WII IPC FILEIO"); - m_Log[LogTypes::WII_IPC_HID] = new LogContainer("WII_IPC_HID", "WII IPC HID"); - m_Log[LogTypes::WII_IPC_HLE] = new LogContainer("WII_IPC_HLE", "WII IPC HLE"); - m_Log[LogTypes::WII_IPC_SD] = new LogContainer("WII_IPC_SD", "WII IPC SD"); - m_Log[LogTypes::WII_IPC_SSL] = new LogContainer("WII_IPC_SSL", "WII IPC SSL"); - m_Log[LogTypes::WII_IPC_STM] = new LogContainer("WII_IPC_STM", "WII IPC STM"); - m_Log[LogTypes::WII_IPC_NET] = new LogContainer("WII_IPC_NET", "WII IPC NET"); - m_Log[LogTypes::WII_IPC_WC24] = new LogContainer("WII_IPC_WC24", "WII IPC WC24"); - m_Log[LogTypes::WII_IPC_WIIMOTE] = new LogContainer("WII_IPC_WIIMOTE", "WII IPC WIIMOTE"); + // create log containers + m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay"); + m_Log[LogTypes::AUDIO] = new LogContainer("Audio", "Audio Emulator"); + m_Log[LogTypes::AUDIO_INTERFACE] = new LogContainer("AI", "Audio Interface (AI)"); + m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot"); + m_Log[LogTypes::COMMANDPROCESSOR] = new LogContainer("CP", "CommandProc"); + m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common"); + m_Log[LogTypes::CONSOLE] = new LogContainer("CONSOLE", "Dolphin Console"); + m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO"); + m_Log[LogTypes::DSPHLE] = new LogContainer("DSPHLE", "DSP HLE"); + m_Log[LogTypes::DSPLLE] = new LogContainer("DSPLLE", "DSP LLE"); + m_Log[LogTypes::DSP_MAIL] = new LogContainer("DSPMails", "DSP Mails"); + m_Log[LogTypes::DSPINTERFACE] = new LogContainer("DSP", "DSPInterface"); + m_Log[LogTypes::DVDINTERFACE] = new LogContainer("DVD", "DVD Interface"); + m_Log[LogTypes::DYNA_REC] = new LogContainer("JIT", "Dynamic Recompiler"); + m_Log[LogTypes::EXPANSIONINTERFACE] = new LogContainer("EXI", "Expansion Interface"); + m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor"); + m_Log[LogTypes::GDB_STUB] = new LogContainer("GDB_STUB", "GDB Stub"); + m_Log[LogTypes::GPFIFO] = new LogContainer("GP", "GPFifo"); + m_Log[LogTypes::HOST_GPU] = new LogContainer("Host GPU", "Host GPU"); + m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log"); + m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); + m_Log[LogTypes::MEMMAP] = new LogContainer("MI", "MI & memmap"); + m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); + m_Log[LogTypes::OSHLE] = new LogContainer("HLE", "HLE"); + m_Log[LogTypes::OSREPORT] = new LogContainer("OSREPORT", "OSReport"); + m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad"); + m_Log[LogTypes::PIXELENGINE] = new LogContainer("PE", "PixelEngine"); + m_Log[LogTypes::PROCESSORINTERFACE] = new LogContainer("PI", "ProcessorInt"); + m_Log[LogTypes::POWERPC] = new LogContainer("PowerPC", "IBM CPU"); + m_Log[LogTypes::SERIALINTERFACE] = new LogContainer("SI", "Serial Interface (SI)"); + m_Log[LogTypes::SP1] = new LogContainer("SP1", "Serial Port 1"); + m_Log[LogTypes::VIDEO] = new LogContainer("Video", "Video Backend"); + m_Log[LogTypes::VIDEOINTERFACE] = new LogContainer("VI", "Video Interface (VI)"); + m_Log[LogTypes::WIIMOTE] = new LogContainer("Wiimote", "Wiimote"); + m_Log[LogTypes::WII_IPC] = new LogContainer("WII_IPC", "WII IPC"); + m_Log[LogTypes::WII_IPC_DVD] = new LogContainer("WII_IPC_DVD", "WII IPC DVD"); + m_Log[LogTypes::WII_IPC_ES] = new LogContainer("WII_IPC_ES", "WII IPC ES"); + m_Log[LogTypes::WII_IPC_FILEIO] = new LogContainer("WII_IPC_FILEIO", "WII IPC FILEIO"); + m_Log[LogTypes::WII_IPC_HID] = new LogContainer("WII_IPC_HID", "WII IPC HID"); + m_Log[LogTypes::WII_IPC_HLE] = new LogContainer("WII_IPC_HLE", "WII IPC HLE"); + m_Log[LogTypes::WII_IPC_SD] = new LogContainer("WII_IPC_SD", "WII IPC SD"); + m_Log[LogTypes::WII_IPC_SSL] = new LogContainer("WII_IPC_SSL", "WII IPC SSL"); + m_Log[LogTypes::WII_IPC_STM] = new LogContainer("WII_IPC_STM", "WII IPC STM"); + m_Log[LogTypes::WII_IPC_NET] = new LogContainer("WII_IPC_NET", "WII IPC NET"); + m_Log[LogTypes::WII_IPC_WC24] = new LogContainer("WII_IPC_WC24", "WII IPC WC24"); + m_Log[LogTypes::WII_IPC_WIIMOTE] = new LogContainer("WII_IPC_WIIMOTE", "WII IPC WIIMOTE"); - RegisterListener(LogListener::FILE_LISTENER, new FileLogListener(File::GetUserPath(F_MAINLOG_IDX))); - RegisterListener(LogListener::CONSOLE_LISTENER, new ConsoleListener()); + RegisterListener(LogListener::FILE_LISTENER, + new FileLogListener(File::GetUserPath(F_MAINLOG_IDX))); + RegisterListener(LogListener::CONSOLE_LISTENER, new ConsoleListener()); - IniFile ini; - ini.Load(File::GetUserPath(F_LOGGERCONFIG_IDX)); - IniFile::Section* logs = ini.GetOrCreateSection("Logs"); - IniFile::Section* options = ini.GetOrCreateSection("Options"); - bool write_file; - bool write_console; - options->Get("WriteToFile", &write_file, false); - options->Get("WriteToConsole", &write_console, true); + IniFile ini; + ini.Load(File::GetUserPath(F_LOGGERCONFIG_IDX)); + IniFile::Section* logs = ini.GetOrCreateSection("Logs"); + IniFile::Section* options = ini.GetOrCreateSection("Options"); + bool write_file; + bool write_console; + options->Get("WriteToFile", &write_file, false); + options->Get("WriteToConsole", &write_console, true); - for (LogContainer* container : m_Log) - { - bool enable; - logs->Get(container->GetShortName(), &enable, false); - container->SetEnable(enable); - if (enable && write_file) - container->AddListener(LogListener::FILE_LISTENER); - if (enable && write_console) - container->AddListener(LogListener::CONSOLE_LISTENER); - } + for (LogContainer* container : m_Log) + { + bool enable; + logs->Get(container->GetShortName(), &enable, false); + container->SetEnable(enable); + if (enable && write_file) + container->AddListener(LogListener::FILE_LISTENER); + if (enable && write_console) + container->AddListener(LogListener::CONSOLE_LISTENER); + } } LogManager::~LogManager() { - for (LogContainer* container : m_Log) - delete container; + for (LogContainer* container : m_Log) + delete container; - // The log window listener pointer is owned by the GUI code. - delete m_listeners[LogListener::CONSOLE_LISTENER]; - delete m_listeners[LogListener::FILE_LISTENER]; + // The log window listener pointer is owned by the GUI code. + delete m_listeners[LogListener::CONSOLE_LISTENER]; + delete m_listeners[LogListener::FILE_LISTENER]; } -void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, - const char* file, int line, const char* format, va_list args) +void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, + int line, const char* format, va_list args) { - char temp[MAX_MSGLEN]; - LogContainer* log = m_Log[type]; + char temp[MAX_MSGLEN]; + LogContainer* log = m_Log[type]; - if (!log->IsEnabled() || level > log->GetLevel() || !log->HasListeners()) - return; + if (!log->IsEnabled() || level > log->GetLevel() || !log->HasListeners()) + return; - CharArrayFromFormatV(temp, MAX_MSGLEN, format, args); + CharArrayFromFormatV(temp, MAX_MSGLEN, format, args); - std::string msg = StringFromFormat("%s %s:%u %c[%s]: %s\n", - Common::Timer::GetTimeFormatted().c_str(), - file, line, - LogTypes::LOG_LEVEL_TO_CHAR[(int)level], - log->GetShortName().c_str(), temp); + std::string msg = StringFromFormat( + "%s %s:%u %c[%s]: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line, + LogTypes::LOG_LEVEL_TO_CHAR[(int)level], log->GetShortName().c_str(), temp); - for (auto listener_id : *log) - m_listeners[listener_id]->Log(level, msg.c_str()); + for (auto listener_id : *log) + m_listeners[listener_id]->Log(level, msg.c_str()); } void LogManager::Init() { - m_logManager = new LogManager(); + m_logManager = new LogManager(); } void LogManager::Shutdown() { - delete m_logManager; - m_logManager = nullptr; + delete m_logManager; + m_logManager = nullptr; } LogContainer::LogContainer(const std::string& shortName, const std::string& fullName, bool enable) - : m_fullName(fullName), - m_shortName(shortName), - m_enable(enable), - m_level(LogTypes::LWARNING) + : m_fullName(fullName), m_shortName(shortName), m_enable(enable), m_level(LogTypes::LWARNING) { } FileLogListener::FileLogListener(const std::string& filename) { - OpenFStream(m_logfile, filename, std::ios::app); - SetEnable(true); + OpenFStream(m_logfile, filename, std::ios::app); + SetEnable(true); } void FileLogListener::Log(LogTypes::LOG_LEVELS, const char* msg) { - if (!IsEnabled() || !IsValid()) - return; + if (!IsEnabled() || !IsValid()) + return; - std::lock_guard lk(m_log_lock); - m_logfile << msg << std::flush; + std::lock_guard lk(m_log_lock); + m_logfile << msg << std::flush; } diff --git a/Source/Core/Common/Logging/LogManager.h b/Source/Core/Common/Logging/LogManager.h index a81784bba1..1c5081cf60 100644 --- a/Source/Core/Common/Logging/LogManager.h +++ b/Source/Core/Common/Logging/LogManager.h @@ -13,80 +13,70 @@ #include "Common/BitSet.h" #include "Common/CommonTypes.h" -#include "Common/NonCopyable.h" #include "Common/Logging/Log.h" +#include "Common/NonCopyable.h" -#define MAX_MSGLEN 1024 +#define MAX_MSGLEN 1024 // pure virtual interface class LogListener { public: - virtual ~LogListener() {} + virtual ~LogListener() {} + virtual void Log(LogTypes::LOG_LEVELS, const char* msg) = 0; - virtual void Log(LogTypes::LOG_LEVELS, const char* msg) = 0; + enum LISTENER + { + FILE_LISTENER = 0, + CONSOLE_LISTENER, + LOG_WINDOW_LISTENER, - enum LISTENER - { - FILE_LISTENER = 0, - CONSOLE_LISTENER, - LOG_WINDOW_LISTENER, - - NUMBER_OF_LISTENERS // Must be last - }; + NUMBER_OF_LISTENERS // Must be last + }; }; class FileLogListener : public LogListener { public: - FileLogListener(const std::string& filename); + FileLogListener(const std::string& filename); - void Log(LogTypes::LOG_LEVELS, const char* msg) override; - - bool IsValid() const { return m_logfile.good(); } - bool IsEnabled() const { return m_enable; } - void SetEnable(bool enable) { m_enable = enable; } - - const char* GetName() const { return "file"; } + void Log(LogTypes::LOG_LEVELS, const char* msg) override; + bool IsValid() const { return m_logfile.good(); } + bool IsEnabled() const { return m_enable; } + void SetEnable(bool enable) { m_enable = enable; } + const char* GetName() const { return "file"; } private: - std::mutex m_log_lock; - std::ofstream m_logfile; - bool m_enable; + std::mutex m_log_lock; + std::ofstream m_logfile; + bool m_enable; }; class LogContainer { public: - LogContainer(const std::string& shortName, const std::string& fullName, bool enable = false); + LogContainer(const std::string& shortName, const std::string& fullName, bool enable = false); - std::string GetShortName() const { return m_shortName; } - std::string GetFullName() const { return m_fullName; } - - void AddListener(LogListener::LISTENER id) { m_listener_ids[id] = 1; } - void RemoveListener(LogListener::LISTENER id) { m_listener_ids[id] = 0; } - - void Trigger(LogTypes::LOG_LEVELS, const char* msg); - - bool IsEnabled() const { return m_enable; } - void SetEnable(bool enable) { m_enable = enable; } - - LogTypes::LOG_LEVELS GetLevel() const { return m_level; } - - void SetLevel(LogTypes::LOG_LEVELS level) { m_level = level; } - - bool HasListeners() const { return bool(m_listener_ids); } - - typedef class BitSet32::Iterator iterator; - iterator begin() const { return m_listener_ids.begin(); } - iterator end() const { return m_listener_ids.end(); } + std::string GetShortName() const { return m_shortName; } + std::string GetFullName() const { return m_fullName; } + void AddListener(LogListener::LISTENER id) { m_listener_ids[id] = 1; } + void RemoveListener(LogListener::LISTENER id) { m_listener_ids[id] = 0; } + void Trigger(LogTypes::LOG_LEVELS, const char* msg); + bool IsEnabled() const { return m_enable; } + void SetEnable(bool enable) { m_enable = enable; } + LogTypes::LOG_LEVELS GetLevel() const { return m_level; } + void SetLevel(LogTypes::LOG_LEVELS level) { m_level = level; } + bool HasListeners() const { return bool(m_listener_ids); } + typedef class BitSet32::Iterator iterator; + iterator begin() const { return m_listener_ids.begin(); } + iterator end() const { return m_listener_ids.end(); } private: - std::string m_fullName; - std::string m_shortName; - bool m_enable; - LogTypes::LOG_LEVELS m_level; - BitSet32 m_listener_ids; + std::string m_fullName; + std::string m_shortName; + bool m_enable; + LogTypes::LOG_LEVELS m_level; + BitSet32 m_listener_ids; }; class ConsoleListener; @@ -94,69 +84,48 @@ class ConsoleListener; class LogManager : NonCopyable { private: - LogContainer* m_Log[LogTypes::NUMBER_OF_LOGS]; - static LogManager* m_logManager; // Singleton. Ugh. - std::array m_listeners; + LogContainer* m_Log[LogTypes::NUMBER_OF_LOGS]; + static LogManager* m_logManager; // Singleton. Ugh. + std::array m_listeners; + + LogManager(); + ~LogManager(); - LogManager(); - ~LogManager(); public: + static u32 GetMaxLevel() { return MAX_LOGLEVEL; } + void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, + const char* fmt, va_list args); - static u32 GetMaxLevel() { return MAX_LOGLEVEL; } + void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) + { + m_Log[type]->SetLevel(level); + } - void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, - const char* file, int line, const char* fmt, va_list args); + void SetEnable(LogTypes::LOG_TYPE type, bool enable) { m_Log[type]->SetEnable(enable); } + bool IsEnabled(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level = LogTypes::LNOTICE) const + { + return m_Log[type]->IsEnabled() && m_Log[type]->GetLevel() >= level; + } - void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) - { - m_Log[type]->SetLevel(level); - } + std::string GetShortName(LogTypes::LOG_TYPE type) const { return m_Log[type]->GetShortName(); } + std::string GetFullName(LogTypes::LOG_TYPE type) const { return m_Log[type]->GetFullName(); } + void RegisterListener(LogListener::LISTENER id, LogListener* listener) + { + m_listeners[id] = listener; + } - void SetEnable(LogTypes::LOG_TYPE type, bool enable) - { - m_Log[type]->SetEnable(enable); - } + void AddListener(LogTypes::LOG_TYPE type, LogListener::LISTENER id) + { + m_Log[type]->AddListener(id); + } - bool IsEnabled(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level = LogTypes::LNOTICE) const - { - return m_Log[type]->IsEnabled() && m_Log[type]->GetLevel() >= level; - } + void RemoveListener(LogTypes::LOG_TYPE type, LogListener::LISTENER id) + { + m_Log[type]->RemoveListener(id); + } - std::string GetShortName(LogTypes::LOG_TYPE type) const - { - return m_Log[type]->GetShortName(); - } - - std::string GetFullName(LogTypes::LOG_TYPE type) const - { - return m_Log[type]->GetFullName(); - } - - void RegisterListener(LogListener::LISTENER id, LogListener* listener) - { - m_listeners[id] = listener; - } - - void AddListener(LogTypes::LOG_TYPE type, LogListener::LISTENER id) - { - m_Log[type]->AddListener(id); - } - - void RemoveListener(LogTypes::LOG_TYPE type, LogListener::LISTENER id) - { - m_Log[type]->RemoveListener(id); - } - - static LogManager* GetInstance() - { - return m_logManager; - } - - static void SetInstance(LogManager* logManager) - { - m_logManager = logManager; - } - - static void Init(); - static void Shutdown(); + static LogManager* GetInstance() { return m_logManager; } + static void SetInstance(LogManager* logManager) { m_logManager = logManager; } + static void Init(); + static void Shutdown(); }; diff --git a/Source/Core/Common/MathUtil.cpp b/Source/Core/Common/MathUtil.cpp index 8eb3899ce3..1f0983889c 100644 --- a/Source/Core/Common/MathUtil.cpp +++ b/Source/Core/Common/MathUtil.cpp @@ -12,360 +12,335 @@ namespace MathUtil { - u32 ClassifyDouble(double dvalue) { - // TODO: Optimize the below to be as fast as possible. - IntDouble value(dvalue); - u64 sign = value.i & DOUBLE_SIGN; - u64 exp = value.i & DOUBLE_EXP; - if (exp > DOUBLE_ZERO && exp < DOUBLE_EXP) - { - // Nice normalized number. - return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; - } - else - { - u64 mantissa = value.i & DOUBLE_FRAC; - if (mantissa) - { - if (exp) - { - return PPC_FPCLASS_QNAN; - } - else - { - // Denormalized number. - return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; - } - } - else if (exp) - { - //Infinite - return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF; - } - else - { - //Zero - return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ; - } - } + // TODO: Optimize the below to be as fast as possible. + IntDouble value(dvalue); + u64 sign = value.i & DOUBLE_SIGN; + u64 exp = value.i & DOUBLE_EXP; + if (exp > DOUBLE_ZERO && exp < DOUBLE_EXP) + { + // Nice normalized number. + return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; + } + else + { + u64 mantissa = value.i & DOUBLE_FRAC; + if (mantissa) + { + if (exp) + { + return PPC_FPCLASS_QNAN; + } + else + { + // Denormalized number. + return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; + } + } + else if (exp) + { + // Infinite + return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF; + } + else + { + // Zero + return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ; + } + } } u32 ClassifyFloat(float fvalue) { - // TODO: Optimize the below to be as fast as possible. - IntFloat value(fvalue); - u32 sign = value.i & FLOAT_SIGN; - u32 exp = value.i & FLOAT_EXP; - if (exp > FLOAT_ZERO && exp < FLOAT_EXP) - { - // Nice normalized number. - return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; - } - else - { - u32 mantissa = value.i & FLOAT_FRAC; - if (mantissa) - { - if (exp) - { - return PPC_FPCLASS_QNAN; // Quiet NAN - } - else - { - // Denormalized number. - return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; - } - } - else if (exp) - { - // Infinite - return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF; - } - else - { - //Zero - return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ; - } - } + // TODO: Optimize the below to be as fast as possible. + IntFloat value(fvalue); + u32 sign = value.i & FLOAT_SIGN; + u32 exp = value.i & FLOAT_EXP; + if (exp > FLOAT_ZERO && exp < FLOAT_EXP) + { + // Nice normalized number. + return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; + } + else + { + u32 mantissa = value.i & FLOAT_FRAC; + if (mantissa) + { + if (exp) + { + return PPC_FPCLASS_QNAN; // Quiet NAN + } + else + { + // Denormalized number. + return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; + } + } + else if (exp) + { + // Infinite + return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF; + } + else + { + // Zero + return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ; + } + } } -const int frsqrte_expected_base[] = -{ - 0x3ffa000, 0x3c29000, 0x38aa000, 0x3572000, - 0x3279000, 0x2fb7000, 0x2d26000, 0x2ac0000, - 0x2881000, 0x2665000, 0x2468000, 0x2287000, - 0x20c1000, 0x1f12000, 0x1d79000, 0x1bf4000, - 0x1a7e800, 0x17cb800, 0x1552800, 0x130c000, - 0x10f2000, 0x0eff000, 0x0d2e000, 0x0b7c000, - 0x09e5000, 0x0867000, 0x06ff000, 0x05ab800, - 0x046a000, 0x0339800, 0x0218800, 0x0105800, +const int frsqrte_expected_base[] = { + 0x3ffa000, 0x3c29000, 0x38aa000, 0x3572000, 0x3279000, 0x2fb7000, 0x2d26000, 0x2ac0000, + 0x2881000, 0x2665000, 0x2468000, 0x2287000, 0x20c1000, 0x1f12000, 0x1d79000, 0x1bf4000, + 0x1a7e800, 0x17cb800, 0x1552800, 0x130c000, 0x10f2000, 0x0eff000, 0x0d2e000, 0x0b7c000, + 0x09e5000, 0x0867000, 0x06ff000, 0x05ab800, 0x046a000, 0x0339800, 0x0218800, 0x0105800, }; -const int frsqrte_expected_dec[] = -{ - 0x7a4, 0x700, 0x670, 0x5f2, - 0x584, 0x524, 0x4cc, 0x47e, - 0x43a, 0x3fa, 0x3c2, 0x38e, - 0x35e, 0x332, 0x30a, 0x2e6, - 0x568, 0x4f3, 0x48d, 0x435, - 0x3e7, 0x3a2, 0x365, 0x32e, - 0x2fc, 0x2d0, 0x2a8, 0x283, - 0x261, 0x243, 0x226, 0x20b, +const int frsqrte_expected_dec[] = { + 0x7a4, 0x700, 0x670, 0x5f2, 0x584, 0x524, 0x4cc, 0x47e, 0x43a, 0x3fa, 0x3c2, + 0x38e, 0x35e, 0x332, 0x30a, 0x2e6, 0x568, 0x4f3, 0x48d, 0x435, 0x3e7, 0x3a2, + 0x365, 0x32e, 0x2fc, 0x2d0, 0x2a8, 0x283, 0x261, 0x243, 0x226, 0x20b, }; double ApproximateReciprocalSquareRoot(double val) { - union - { - double valf; - s64 vali; - }; - valf = val; - s64 mantissa = vali & ((1LL << 52) - 1); - s64 sign = vali & (1ULL << 63); - s64 exponent = vali & (0x7FFLL << 52); + union { + double valf; + s64 vali; + }; + valf = val; + s64 mantissa = vali & ((1LL << 52) - 1); + s64 sign = vali & (1ULL << 63); + s64 exponent = vali & (0x7FFLL << 52); - // Special case 0 - if (mantissa == 0 && exponent == 0) - return sign ? -std::numeric_limits::infinity() : - std::numeric_limits::infinity(); - // Special case NaN-ish numbers - if (exponent == (0x7FFLL << 52)) - { - if (mantissa == 0) - { - if (sign) - return std::numeric_limits::quiet_NaN(); + // Special case 0 + if (mantissa == 0 && exponent == 0) + return sign ? -std::numeric_limits::infinity() : + std::numeric_limits::infinity(); + // Special case NaN-ish numbers + if (exponent == (0x7FFLL << 52)) + { + if (mantissa == 0) + { + if (sign) + return std::numeric_limits::quiet_NaN(); - return 0.0; - } + return 0.0; + } - return 0.0 + valf; - } + return 0.0 + valf; + } - // Negative numbers return NaN - if (sign) - return std::numeric_limits::quiet_NaN(); + // Negative numbers return NaN + if (sign) + return std::numeric_limits::quiet_NaN(); - if (!exponent) - { - // "Normalize" denormal values - do - { - exponent -= 1LL << 52; - mantissa <<= 1; - } while (!(mantissa & (1LL << 52))); - mantissa &= (1LL << 52) - 1; - exponent += 1LL << 52; - } + if (!exponent) + { + // "Normalize" denormal values + do + { + exponent -= 1LL << 52; + mantissa <<= 1; + } while (!(mantissa & (1LL << 52))); + mantissa &= (1LL << 52) - 1; + exponent += 1LL << 52; + } - bool odd_exponent = !(exponent & (1LL << 52)); - exponent = ((0x3FFLL << 52) - ((exponent - (0x3FELL << 52)) / 2)) & (0x7FFLL << 52); + bool odd_exponent = !(exponent & (1LL << 52)); + exponent = ((0x3FFLL << 52) - ((exponent - (0x3FELL << 52)) / 2)) & (0x7FFLL << 52); - int i = (int)(mantissa >> 37); - vali = sign | exponent; - int index = i / 2048 + (odd_exponent ? 16 : 0); - vali |= (s64)(frsqrte_expected_base[index] - frsqrte_expected_dec[index] * (i % 2048)) << 26; - return valf; + int i = (int)(mantissa >> 37); + vali = sign | exponent; + int index = i / 2048 + (odd_exponent ? 16 : 0); + vali |= (s64)(frsqrte_expected_base[index] - frsqrte_expected_dec[index] * (i % 2048)) << 26; + return valf; } -const int fres_expected_base[] = -{ - 0x7ff800, 0x783800, 0x70ea00, 0x6a0800, - 0x638800, 0x5d6200, 0x579000, 0x520800, - 0x4cc800, 0x47ca00, 0x430800, 0x3e8000, - 0x3a2c00, 0x360800, 0x321400, 0x2e4a00, - 0x2aa800, 0x272c00, 0x23d600, 0x209e00, - 0x1d8800, 0x1a9000, 0x17ae00, 0x14f800, - 0x124400, 0x0fbe00, 0x0d3800, 0x0ade00, - 0x088400, 0x065000, 0x041c00, 0x020c00, +const int fres_expected_base[] = { + 0x7ff800, 0x783800, 0x70ea00, 0x6a0800, 0x638800, 0x5d6200, 0x579000, 0x520800, + 0x4cc800, 0x47ca00, 0x430800, 0x3e8000, 0x3a2c00, 0x360800, 0x321400, 0x2e4a00, + 0x2aa800, 0x272c00, 0x23d600, 0x209e00, 0x1d8800, 0x1a9000, 0x17ae00, 0x14f800, + 0x124400, 0x0fbe00, 0x0d3800, 0x0ade00, 0x088400, 0x065000, 0x041c00, 0x020c00, }; -const int fres_expected_dec[] = -{ - 0x3e1, 0x3a7, 0x371, 0x340, - 0x313, 0x2ea, 0x2c4, 0x2a0, - 0x27f, 0x261, 0x245, 0x22a, - 0x212, 0x1fb, 0x1e5, 0x1d1, - 0x1be, 0x1ac, 0x19b, 0x18b, - 0x17c, 0x16e, 0x15b, 0x15b, - 0x143, 0x143, 0x12d, 0x12d, - 0x11a, 0x11a, 0x108, 0x106, +const int fres_expected_dec[] = { + 0x3e1, 0x3a7, 0x371, 0x340, 0x313, 0x2ea, 0x2c4, 0x2a0, 0x27f, 0x261, 0x245, + 0x22a, 0x212, 0x1fb, 0x1e5, 0x1d1, 0x1be, 0x1ac, 0x19b, 0x18b, 0x17c, 0x16e, + 0x15b, 0x15b, 0x143, 0x143, 0x12d, 0x12d, 0x11a, 0x11a, 0x108, 0x106, }; // Used by fres and ps_res. double ApproximateReciprocal(double val) { - // We are using namespace std scoped here because the Android NDK is complete trash as usual - // For 32bit targets(mips, ARMv7, x86) it doesn't provide an implementation of std::copysign - // but instead provides just global namespace copysign implementations. - // The workaround for this is to just use namespace std within this function's scope - // That way on real toolchains it will use the std:: variant like normal. - using namespace std; - union - { - double valf; - s64 vali; - }; + // We are using namespace std scoped here because the Android NDK is complete trash as usual + // For 32bit targets(mips, ARMv7, x86) it doesn't provide an implementation of std::copysign + // but instead provides just global namespace copysign implementations. + // The workaround for this is to just use namespace std within this function's scope + // That way on real toolchains it will use the std:: variant like normal. + using namespace std; + union { + double valf; + s64 vali; + }; - valf = val; - s64 mantissa = vali & ((1LL << 52) - 1); - s64 sign = vali & (1ULL << 63); - s64 exponent = vali & (0x7FFLL << 52); + valf = val; + s64 mantissa = vali & ((1LL << 52) - 1); + s64 sign = vali & (1ULL << 63); + s64 exponent = vali & (0x7FFLL << 52); - // Special case 0 - if (mantissa == 0 && exponent == 0) - return copysign(std::numeric_limits::infinity(), valf); + // Special case 0 + if (mantissa == 0 && exponent == 0) + return copysign(std::numeric_limits::infinity(), valf); - // Special case NaN-ish numbers - if (exponent == (0x7FFLL << 52)) - { - if (mantissa == 0) - return copysign(0.0, valf); - return 0.0 + valf; - } + // Special case NaN-ish numbers + if (exponent == (0x7FFLL << 52)) + { + if (mantissa == 0) + return copysign(0.0, valf); + return 0.0 + valf; + } - // Special case small inputs - if (exponent < (895LL << 52)) - return copysign(std::numeric_limits::max(), valf); + // Special case small inputs + if (exponent < (895LL << 52)) + return copysign(std::numeric_limits::max(), valf); - // Special case large inputs - if (exponent >= (1149LL << 52)) - return copysign(0.0, valf); + // Special case large inputs + if (exponent >= (1149LL << 52)) + return copysign(0.0, valf); - exponent = (0x7FDLL << 52) - exponent; + exponent = (0x7FDLL << 52) - exponent; - int i = (int)(mantissa >> 37); - vali = sign | exponent; - vali |= (s64)(fres_expected_base[i / 1024] - (fres_expected_dec[i / 1024] * (i % 1024) + 1) / 2) << 29; - return valf; + int i = (int)(mantissa >> 37); + vali = sign | exponent; + vali |= (s64)(fres_expected_base[i / 1024] - (fres_expected_dec[i / 1024] * (i % 1024) + 1) / 2) + << 29; + return valf; } } // namespace inline void MatrixMul(int n, const float* a, const float* b, float* result) { - for (int i = 0; i < n; ++i) - { - for (int j = 0; j < n; ++j) - { - float temp = 0; - for (int k = 0; k < n; ++k) - { - temp += a[i * n + k] * b[k * n + j]; - } - result[i * n + j] = temp; - } - } + for (int i = 0; i < n; ++i) + { + for (int j = 0; j < n; ++j) + { + float temp = 0; + for (int k = 0; k < n; ++k) + { + temp += a[i * n + k] * b[k * n + j]; + } + result[i * n + j] = temp; + } + } } // Calculate sum of a float list float MathFloatVectorSum(const std::vector& Vec) { - return std::accumulate(Vec.begin(), Vec.end(), 0.0f); + return std::accumulate(Vec.begin(), Vec.end(), 0.0f); } void Matrix33::LoadIdentity(Matrix33& mtx) { - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = 1.0f; - mtx.data[4] = 1.0f; - mtx.data[8] = 1.0f; + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = 1.0f; + mtx.data[4] = 1.0f; + mtx.data[8] = 1.0f; } void Matrix33::RotateX(Matrix33& mtx, float rad) { - float s = sin(rad); - float c = cos(rad); - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = 1; - mtx.data[4] = c; - mtx.data[5] = -s; - mtx.data[7] = s; - mtx.data[8] = c; + float s = sin(rad); + float c = cos(rad); + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = 1; + mtx.data[4] = c; + mtx.data[5] = -s; + mtx.data[7] = s; + mtx.data[8] = c; } void Matrix33::RotateY(Matrix33& mtx, float rad) { - float s = sin(rad); - float c = cos(rad); - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = c; - mtx.data[2] = s; - mtx.data[4] = 1; - mtx.data[6] = -s; - mtx.data[8] = c; + float s = sin(rad); + float c = cos(rad); + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = c; + mtx.data[2] = s; + mtx.data[4] = 1; + mtx.data[6] = -s; + mtx.data[8] = c; } void Matrix33::Multiply(const Matrix33& a, const Matrix33& b, Matrix33& result) { - MatrixMul(3, a.data, b.data, result.data); + MatrixMul(3, a.data, b.data, result.data); } void Matrix33::Multiply(const Matrix33& a, const float vec[3], float result[3]) { - for (int i = 0; i < 3; ++i) - { - result[i] = 0; + for (int i = 0; i < 3; ++i) + { + result[i] = 0; - for (int k = 0; k < 3; ++k) - { - result[i] += a.data[i * 3 + k] * vec[k]; - } - } + for (int k = 0; k < 3; ++k) + { + result[i] += a.data[i * 3 + k] * vec[k]; + } + } } void Matrix44::LoadIdentity(Matrix44& mtx) { - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = 1.0f; - mtx.data[5] = 1.0f; - mtx.data[10] = 1.0f; - mtx.data[15] = 1.0f; + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = 1.0f; + mtx.data[5] = 1.0f; + mtx.data[10] = 1.0f; + mtx.data[15] = 1.0f; } void Matrix44::LoadMatrix33(Matrix44& mtx, const Matrix33& m33) { - for (int i = 0; i < 3; ++i) - { - for (int j = 0; j < 3; ++j) - { - mtx.data[i * 4 + j] = m33.data[i * 3 + j]; - } - } + for (int i = 0; i < 3; ++i) + { + for (int j = 0; j < 3; ++j) + { + mtx.data[i * 4 + j] = m33.data[i * 3 + j]; + } + } - for (int i = 0; i < 3; ++i) - { - mtx.data[i * 4 + 3] = 0; - mtx.data[i + 12] = 0; - } - mtx.data[15] = 1.0f; + for (int i = 0; i < 3; ++i) + { + mtx.data[i * 4 + 3] = 0; + mtx.data[i + 12] = 0; + } + mtx.data[15] = 1.0f; } void Matrix44::Set(Matrix44& mtx, const float mtxArray[16]) { - for (int i = 0; i < 16; ++i) - { - mtx.data[i] = mtxArray[i]; - } + for (int i = 0; i < 16; ++i) + { + mtx.data[i] = mtxArray[i]; + } } void Matrix44::Translate(Matrix44& mtx, const float vec[3]) { - LoadIdentity(mtx); - mtx.data[3] = vec[0]; - mtx.data[7] = vec[1]; - mtx.data[11] = vec[2]; + LoadIdentity(mtx); + mtx.data[3] = vec[0]; + mtx.data[7] = vec[1]; + mtx.data[11] = vec[2]; } void Matrix44::Shear(Matrix44& mtx, const float a, const float b) { - LoadIdentity(mtx); - mtx.data[2] = a; - mtx.data[6] = b; + LoadIdentity(mtx); + mtx.data[2] = a; + mtx.data[6] = b; } void Matrix44::Multiply(const Matrix44& a, const Matrix44& b, Matrix44& result) { - MatrixMul(4, a.data, b.data, result.data); + MatrixMul(4, a.data, b.data, result.data); } - diff --git a/Source/Core/Common/MathUtil.h b/Source/Core/Common/MathUtil.h index 236c554437..a38e49bf6d 100644 --- a/Source/Core/Common/MathUtil.h +++ b/Source/Core/Common/MathUtil.h @@ -12,11 +12,10 @@ namespace MathUtil { - template constexpr T SNANConstant() { - return std::numeric_limits::signaling_NaN(); + return std::numeric_limits::signaling_NaN(); } #ifdef _MSC_VER @@ -28,101 +27,95 @@ constexpr T SNANConstant() template <> constexpr double SNANConstant() { - return (_CSTD _Snan._Double); + return (_CSTD _Snan._Double); } template <> constexpr float SNANConstant() { - return (_CSTD _Snan._Float); + return (_CSTD _Snan._Float); } #endif -template +template constexpr T Clamp(const T val, const T& min, const T& max) { - return std::max(min, std::min(max, val)); + return std::max(min, std::min(max, val)); } constexpr bool IsPow2(u32 imm) { - return (imm & (imm - 1)) == 0; + return (imm & (imm - 1)) == 0; } // The most significant bit of the fraction is an is-quiet bit on all architectures we care about. -static const u64 DOUBLE_SIGN = 0x8000000000000000ULL, - DOUBLE_EXP = 0x7FF0000000000000ULL, - DOUBLE_FRAC = 0x000FFFFFFFFFFFFFULL, - DOUBLE_ZERO = 0x0000000000000000ULL, +static const u64 DOUBLE_SIGN = 0x8000000000000000ULL, DOUBLE_EXP = 0x7FF0000000000000ULL, + DOUBLE_FRAC = 0x000FFFFFFFFFFFFFULL, DOUBLE_ZERO = 0x0000000000000000ULL, DOUBLE_QBIT = 0x0008000000000000ULL; -static const u32 FLOAT_SIGN = 0x80000000, - FLOAT_EXP = 0x7F800000, - FLOAT_FRAC = 0x007FFFFF, +static const u32 FLOAT_SIGN = 0x80000000, FLOAT_EXP = 0x7F800000, FLOAT_FRAC = 0x007FFFFF, FLOAT_ZERO = 0x00000000; union IntDouble { - double d; - u64 i; + double d; + u64 i; - explicit IntDouble(u64 _i) : i(_i) {} - explicit IntDouble(double _d) : d(_d) {} + explicit IntDouble(u64 _i) : i(_i) {} + explicit IntDouble(double _d) : d(_d) {} }; union IntFloat { - float f; - u32 i; + float f; + u32 i; - explicit IntFloat(u32 _i) : i(_i) {} - explicit IntFloat(float _f) : f(_f) {} + explicit IntFloat(u32 _i) : i(_i) {} + explicit IntFloat(float _f) : f(_f) {} }; inline bool IsQNAN(double d) { - IntDouble x(d); - return ((x.i & DOUBLE_EXP) == DOUBLE_EXP) && - ((x.i & DOUBLE_QBIT) == DOUBLE_QBIT); + IntDouble x(d); + return ((x.i & DOUBLE_EXP) == DOUBLE_EXP) && ((x.i & DOUBLE_QBIT) == DOUBLE_QBIT); } inline bool IsSNAN(double d) { - IntDouble x(d); - return ((x.i & DOUBLE_EXP) == DOUBLE_EXP) && - ((x.i & DOUBLE_FRAC) != DOUBLE_ZERO) && - ((x.i & DOUBLE_QBIT) == DOUBLE_ZERO); + IntDouble x(d); + return ((x.i & DOUBLE_EXP) == DOUBLE_EXP) && ((x.i & DOUBLE_FRAC) != DOUBLE_ZERO) && + ((x.i & DOUBLE_QBIT) == DOUBLE_ZERO); } inline float FlushToZero(float f) { - IntFloat x(f); - if ((x.i & FLOAT_EXP) == 0) - { - x.i &= FLOAT_SIGN; // turn into signed zero - } - return x.f; + IntFloat x(f); + if ((x.i & FLOAT_EXP) == 0) + { + x.i &= FLOAT_SIGN; // turn into signed zero + } + return x.f; } inline double FlushToZero(double d) { - IntDouble x(d); - if ((x.i & DOUBLE_EXP) == 0) - { - x.i &= DOUBLE_SIGN; // turn into signed zero - } - return x.d; + IntDouble x(d); + if ((x.i & DOUBLE_EXP) == 0) + { + x.i &= DOUBLE_SIGN; // turn into signed zero + } + return x.d; } enum PPCFpClass { - PPC_FPCLASS_QNAN = 0x11, - PPC_FPCLASS_NINF = 0x9, - PPC_FPCLASS_NN = 0x8, - PPC_FPCLASS_ND = 0x18, - PPC_FPCLASS_NZ = 0x12, - PPC_FPCLASS_PZ = 0x2, - PPC_FPCLASS_PD = 0x14, - PPC_FPCLASS_PN = 0x4, - PPC_FPCLASS_PINF = 0x5, + PPC_FPCLASS_QNAN = 0x11, + PPC_FPCLASS_NINF = 0x9, + PPC_FPCLASS_NN = 0x8, + PPC_FPCLASS_ND = 0x18, + PPC_FPCLASS_NZ = 0x12, + PPC_FPCLASS_PZ = 0x2, + PPC_FPCLASS_PD = 0x14, + PPC_FPCLASS_PN = 0x4, + PPC_FPCLASS_PINF = 0x5, }; // Uses PowerPC conventions for the return value, so it can be easily @@ -140,75 +133,75 @@ extern const int fres_expected_dec[]; double ApproximateReciprocalSquareRoot(double val); double ApproximateReciprocal(double val); -template +template struct Rectangle { - T left{}; - T top{}; - T right{}; - T bottom{}; + T left{}; + T top{}; + T right{}; + T bottom{}; - constexpr Rectangle() = default; + constexpr Rectangle() = default; - constexpr Rectangle(T theLeft, T theTop, T theRight, T theBottom) - : left(theLeft), top(theTop), right(theRight), bottom(theBottom) - {} + constexpr Rectangle(T theLeft, T theTop, T theRight, T theBottom) + : left(theLeft), top(theTop), right(theRight), bottom(theBottom) + { + } - constexpr bool operator==(const Rectangle& r) const - { - return left == r.left && top == r.top && right == r.right && bottom == r.bottom; - } + constexpr bool operator==(const Rectangle& r) const + { + return left == r.left && top == r.top && right == r.right && bottom == r.bottom; + } - T GetWidth() const { return abs(right - left); } - T GetHeight() const { return abs(bottom - top); } + T GetWidth() const { return abs(right - left); } + T GetHeight() const { return abs(bottom - top); } + // If the rectangle is in a coordinate system with a lower-left origin, use + // this Clamp. + void ClampLL(T x1, T y1, T x2, T y2) + { + left = Clamp(left, x1, x2); + right = Clamp(right, x1, x2); + top = Clamp(top, y2, y1); + bottom = Clamp(bottom, y2, y1); + } - // If the rectangle is in a coordinate system with a lower-left origin, use - // this Clamp. - void ClampLL(T x1, T y1, T x2, T y2) - { - left = Clamp(left, x1, x2); - right = Clamp(right, x1, x2); - top = Clamp(top, y2, y1); - bottom = Clamp(bottom, y2, y1); - } - - // If the rectangle is in a coordinate system with an upper-left origin, - // use this Clamp. - void ClampUL(T x1, T y1, T x2, T y2) - { - left = Clamp(left, x1, x2); - right = Clamp(right, x1, x2); - top = Clamp(top, y1, y2); - bottom = Clamp(bottom, y1, y2); - } + // If the rectangle is in a coordinate system with an upper-left origin, + // use this Clamp. + void ClampUL(T x1, T y1, T x2, T y2) + { + left = Clamp(left, x1, x2); + right = Clamp(right, x1, x2); + top = Clamp(top, y1, y2); + bottom = Clamp(bottom, y1, y2); + } }; } // namespace MathUtil float MathFloatVectorSum(const std::vector&); -#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define ROUND_DOWN(x, a) ((x) & ~((a) - 1)) +#define ROUND_UP(x, a) (((x) + (a)-1) & ~((a)-1)) +#define ROUND_DOWN(x, a) ((x) & ~((a)-1)) // Rounds down. 0 -> undefined inline int IntLog2(u64 val) { #if defined(__GNUC__) - return 63 - __builtin_clzll(val); + return 63 - __builtin_clzll(val); #elif defined(_MSC_VER) - unsigned long result = -1; - _BitScanReverse64(&result, val); - return result; + unsigned long result = -1; + _BitScanReverse64(&result, val); + return result; #else - int result = -1; - while (val != 0) - { - val >>= 1; - ++result; - } - return result; + int result = -1; + while (val != 0) + { + val >>= 1; + ++result; + } + return result; #endif } @@ -218,31 +211,31 @@ inline int IntLog2(u64 val) class Matrix33 { public: - static void LoadIdentity(Matrix33& mtx); + static void LoadIdentity(Matrix33& mtx); - // set mtx to be a rotation matrix around the x axis - static void RotateX(Matrix33& mtx, float rad); - // set mtx to be a rotation matrix around the y axis - static void RotateY(Matrix33& mtx, float rad); + // set mtx to be a rotation matrix around the x axis + static void RotateX(Matrix33& mtx, float rad); + // set mtx to be a rotation matrix around the y axis + static void RotateY(Matrix33& mtx, float rad); - // set result = a x b - static void Multiply(const Matrix33& a, const Matrix33& b, Matrix33& result); - static void Multiply(const Matrix33& a, const float vec[3], float result[3]); + // set result = a x b + static void Multiply(const Matrix33& a, const Matrix33& b, Matrix33& result); + static void Multiply(const Matrix33& a, const float vec[3], float result[3]); - float data[9]; + float data[9]; }; class Matrix44 { public: - static void LoadIdentity(Matrix44& mtx); - static void LoadMatrix33(Matrix44& mtx, const Matrix33& m33); - static void Set(Matrix44& mtx, const float mtxArray[16]); + static void LoadIdentity(Matrix44& mtx); + static void LoadMatrix33(Matrix44& mtx, const Matrix33& m33); + static void Set(Matrix44& mtx, const float mtxArray[16]); - static void Translate(Matrix44& mtx, const float vec[3]); - static void Shear(Matrix44& mtx, const float a, const float b = 0); + static void Translate(Matrix44& mtx, const float vec[3]); + static void Shear(Matrix44& mtx, const float a, const float b = 0); - static void Multiply(const Matrix44& a, const Matrix44& b, Matrix44& result); + static void Multiply(const Matrix44& a, const Matrix44& b, Matrix44& result); - float data[16]; + float data[16]; }; diff --git a/Source/Core/Common/MemArena.cpp b/Source/Core/Common/MemArena.cpp index 008b49de0c..8112dbef8e 100644 --- a/Source/Core/Common/MemArena.cpp +++ b/Source/Core/Common/MemArena.cpp @@ -8,10 +8,10 @@ #include #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/MemArena.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #ifdef _WIN32 #include @@ -19,11 +19,11 @@ #include #include #include -#include #include +#include #ifdef ANDROID -#include #include +#include #endif #endif @@ -32,250 +32,243 @@ static int AshmemCreateFileMapping(const char* name, size_t size) { - int fd, ret; - fd = open(ASHMEM_DEVICE, O_RDWR); - if (fd < 0) - return fd; + int fd, ret; + fd = open(ASHMEM_DEVICE, O_RDWR); + if (fd < 0) + return fd; - // We don't really care if we can't set the name, it is optional - ioctl(fd, ASHMEM_SET_NAME, name); + // We don't really care if we can't set the name, it is optional + ioctl(fd, ASHMEM_SET_NAME, name); - ret = ioctl(fd, ASHMEM_SET_SIZE, size); - if (ret < 0) - { - close(fd); - NOTICE_LOG(MEMMAP, "Ashmem returned error: 0x%08x", ret); - return ret; - } - return fd; + ret = ioctl(fd, ASHMEM_SET_SIZE, size); + if (ret < 0) + { + close(fd); + NOTICE_LOG(MEMMAP, "Ashmem returned error: 0x%08x", ret); + return ret; + } + return fd; } #endif void MemArena::GrabSHMSegment(size_t size) { #ifdef _WIN32 - hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, (DWORD)(size), nullptr); + hMemoryMapping = + CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, (DWORD)(size), nullptr); #elif defined(ANDROID) - fd = AshmemCreateFileMapping("Dolphin-emu", size); - if (fd < 0) - { - NOTICE_LOG(MEMMAP, "Ashmem allocation failed"); - return; - } + fd = AshmemCreateFileMapping("Dolphin-emu", size); + if (fd < 0) + { + NOTICE_LOG(MEMMAP, "Ashmem allocation failed"); + return; + } #else - for (int i = 0; i < 10000; i++) - { - std::string file_name = StringFromFormat("/dolphinmem.%d", i); - fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); - if (fd != -1) - { - shm_unlink(file_name.c_str()); - break; - } - else if (errno != EEXIST) - { - ERROR_LOG(MEMMAP, "shm_open failed: %s", strerror(errno)); - return; - } - } - if (ftruncate(fd, size) < 0) - ERROR_LOG(MEMMAP, "Failed to allocate low memory space"); + for (int i = 0; i < 10000; i++) + { + std::string file_name = StringFromFormat("/dolphinmem.%d", i); + fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd != -1) + { + shm_unlink(file_name.c_str()); + break; + } + else if (errno != EEXIST) + { + ERROR_LOG(MEMMAP, "shm_open failed: %s", strerror(errno)); + return; + } + } + if (ftruncate(fd, size) < 0) + ERROR_LOG(MEMMAP, "Failed to allocate low memory space"); #endif } - void MemArena::ReleaseSHMSegment() { #ifdef _WIN32 - CloseHandle(hMemoryMapping); - hMemoryMapping = 0; + CloseHandle(hMemoryMapping); + hMemoryMapping = 0; #else - close(fd); + close(fd); #endif } - void* MemArena::CreateView(s64 offset, size_t size, void* base) { #ifdef _WIN32 - return MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base); + return MapViewOfFileEx(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size, base); #else - void* retval = mmap( - base, size, - PROT_READ | PROT_WRITE, - MAP_SHARED | ((base == nullptr) ? 0 : MAP_FIXED), - fd, offset); + void* retval = mmap(base, size, PROT_READ | PROT_WRITE, + MAP_SHARED | ((base == nullptr) ? 0 : MAP_FIXED), fd, offset); - if (retval == MAP_FAILED) - { - NOTICE_LOG(MEMMAP, "mmap failed"); - return nullptr; - } - else - { - return retval; - } + if (retval == MAP_FAILED) + { + NOTICE_LOG(MEMMAP, "mmap failed"); + return nullptr; + } + else + { + return retval; + } #endif } - void MemArena::ReleaseView(void* view, size_t size) { #ifdef _WIN32 - UnmapViewOfFile(view); + UnmapViewOfFile(view); #else - munmap(view, size); + munmap(view, size); #endif } - u8* MemArena::FindMemoryBase() { #if _ARCH_64 #ifdef _WIN32 - // 64 bit - u8* base = (u8*)VirtualAlloc(0, 0x400000000, MEM_RESERVE, PAGE_READWRITE); - VirtualFree(base, 0, MEM_RELEASE); - return base; + // 64 bit + u8* base = (u8*)VirtualAlloc(0, 0x400000000, MEM_RESERVE, PAGE_READWRITE); + VirtualFree(base, 0, MEM_RELEASE); + return base; #else - // Very precarious - mmap cannot return an error when trying to map already used pages. - // This makes the Windows approach above unusable on Linux, so we will simply pray... - return reinterpret_cast(0x2300000000ULL); + // Very precarious - mmap cannot return an error when trying to map already used pages. + // This makes the Windows approach above unusable on Linux, so we will simply pray... + return reinterpret_cast(0x2300000000ULL); #endif -#else // 32 bit +#else // 32 bit #ifdef ANDROID - // Android 4.3 changed how mmap works. - // if we map it private and then munmap it, we can't use the base returned. - // This may be due to changes in them support a full SELinux implementation. - const int flags = MAP_ANON | MAP_SHARED; + // Android 4.3 changed how mmap works. + // if we map it private and then munmap it, we can't use the base returned. + // This may be due to changes in them support a full SELinux implementation. + const int flags = MAP_ANON | MAP_SHARED; #else - const int flags = MAP_ANON | MAP_PRIVATE; + const int flags = MAP_ANON | MAP_PRIVATE; #endif - const u32 MemSize = 0x31000000; - void* base = mmap(0, MemSize, PROT_NONE, flags, -1, 0); - if (base == MAP_FAILED) - { - PanicAlert("Failed to map 1 GB of memory space: %s", strerror(errno)); - return 0; - } - munmap(base, MemSize); - return static_cast(base); + const u32 MemSize = 0x31000000; + void* base = mmap(0, MemSize, PROT_NONE, flags, -1, 0); + if (base == MAP_FAILED) + { + PanicAlert("Failed to map 1 GB of memory space: %s", strerror(errno)); + return 0; + } + munmap(base, MemSize); + return static_cast(base); #endif } - // yeah, this could also be done in like two bitwise ops... -#define SKIP(a_flags, b_flags) \ - if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY)) \ - continue; \ - if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM)) \ - continue; \ +#define SKIP(a_flags, b_flags) \ + if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY)) \ + continue; \ + if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM)) \ + continue; static bool Memory_TryBase(u8* base, MemoryView* views, int num_views, u32 flags, MemArena* arena) { - // OK, we know where to find free space. Now grab it! - // We just mimic the popular BAT setup. + // OK, we know where to find free space. Now grab it! + // We just mimic the popular BAT setup. - int i; - for (i = 0; i < num_views; i++) - { - MemoryView* view = &views[i]; - void* view_base; - bool use_sw_mirror; + int i; + for (i = 0; i < num_views; i++) + { + MemoryView* view = &views[i]; + void* view_base; + bool use_sw_mirror; - SKIP(flags, view->flags); + SKIP(flags, view->flags); #if _ARCH_64 - // On 64-bit, we map the same file position multiple times, so we - // don't need the software fallback for the mirrors. - view_base = base + view->virtual_address; - use_sw_mirror = false; + // On 64-bit, we map the same file position multiple times, so we + // don't need the software fallback for the mirrors. + view_base = base + view->virtual_address; + use_sw_mirror = false; #else - // On 32-bit, we don't have the actual address space to store all - // the mirrors, so we just map the fallbacks somewhere in our address - // space and use the software fallbacks for mirroring. - view_base = base + (view->virtual_address & 0x3FFFFFFF); - use_sw_mirror = true; + // On 32-bit, we don't have the actual address space to store all + // the mirrors, so we just map the fallbacks somewhere in our address + // space and use the software fallbacks for mirroring. + view_base = base + (view->virtual_address & 0x3FFFFFFF); + use_sw_mirror = true; #endif - if (use_sw_mirror && (view->flags & MV_MIRROR_PREVIOUS)) - { - view->view_ptr = views[i - 1].view_ptr; - } - else - { - view->mapped_ptr = arena->CreateView(view->shm_position, view->size, view_base); - view->view_ptr = view->mapped_ptr; - } + if (use_sw_mirror && (view->flags & MV_MIRROR_PREVIOUS)) + { + view->view_ptr = views[i - 1].view_ptr; + } + else + { + view->mapped_ptr = arena->CreateView(view->shm_position, view->size, view_base); + view->view_ptr = view->mapped_ptr; + } - if (!view->view_ptr) - { - // Argh! ERROR! Free what we grabbed so far so we can try again. - MemoryMap_Shutdown(views, i+1, flags, arena); - return false; - } + if (!view->view_ptr) + { + // Argh! ERROR! Free what we grabbed so far so we can try again. + MemoryMap_Shutdown(views, i + 1, flags, arena); + return false; + } - if (view->out_ptr) - *(view->out_ptr) = (u8*) view->view_ptr; - } + if (view->out_ptr) + *(view->out_ptr) = (u8*)view->view_ptr; + } - return true; + return true; } static u32 MemoryMap_InitializeViews(MemoryView* views, int num_views, u32 flags) { - u32 shm_position = 0; - u32 last_position = 0; + u32 shm_position = 0; + u32 last_position = 0; - for (int i = 0; i < num_views; i++) - { - // Zero all the pointers to be sure. - views[i].mapped_ptr = nullptr; + for (int i = 0; i < num_views; i++) + { + // Zero all the pointers to be sure. + views[i].mapped_ptr = nullptr; - SKIP(flags, views[i].flags); + SKIP(flags, views[i].flags); - if (views[i].flags & MV_MIRROR_PREVIOUS) - shm_position = last_position; - views[i].shm_position = shm_position; - last_position = shm_position; - shm_position += views[i].size; - } + if (views[i].flags & MV_MIRROR_PREVIOUS) + shm_position = last_position; + views[i].shm_position = shm_position; + last_position = shm_position; + shm_position += views[i].size; + } - return shm_position; + return shm_position; } u8* MemoryMap_Setup(MemoryView* views, int num_views, u32 flags, MemArena* arena) { - u32 total_mem = MemoryMap_InitializeViews(views, num_views, flags); + u32 total_mem = MemoryMap_InitializeViews(views, num_views, flags); - arena->GrabSHMSegment(total_mem); + arena->GrabSHMSegment(total_mem); - // Now, create views in high memory where there's plenty of space. - u8* base = MemArena::FindMemoryBase(); - // This really shouldn't fail - in 64-bit, there will always be enough - // address space. - if (!Memory_TryBase(base, views, num_views, flags, arena)) - { - PanicAlert("MemoryMap_Setup: Failed finding a memory base."); - exit(0); - return nullptr; - } + // Now, create views in high memory where there's plenty of space. + u8* base = MemArena::FindMemoryBase(); + // This really shouldn't fail - in 64-bit, there will always be enough + // address space. + if (!Memory_TryBase(base, views, num_views, flags, arena)) + { + PanicAlert("MemoryMap_Setup: Failed finding a memory base."); + exit(0); + return nullptr; + } - return base; + return base; } void MemoryMap_Shutdown(MemoryView* views, int num_views, u32 flags, MemArena* arena) { - std::set freeset; - for (int i = 0; i < num_views; i++) - { - MemoryView* view = &views[i]; - if (view->mapped_ptr && !freeset.count(view->mapped_ptr)) - { - arena->ReleaseView(view->mapped_ptr, view->size); - freeset.insert(view->mapped_ptr); - view->mapped_ptr = nullptr; - } - } + std::set freeset; + for (int i = 0; i < num_views; i++) + { + MemoryView* view = &views[i]; + if (view->mapped_ptr && !freeset.count(view->mapped_ptr)) + { + arena->ReleaseView(view->mapped_ptr, view->size); + freeset.insert(view->mapped_ptr); + view->mapped_ptr = nullptr; + } + } } diff --git a/Source/Core/Common/MemArena.h b/Source/Core/Common/MemArena.h index 2b1ecc7c29..025e0d9a50 100644 --- a/Source/Core/Common/MemArena.h +++ b/Source/Core/Common/MemArena.h @@ -13,43 +13,45 @@ #include "Common/CommonTypes.h" // This class lets you create a block of anonymous RAM, and then arbitrarily map views into it. -// Multiple views can mirror the same section of the block, which makes it very convenient for emulating +// Multiple views can mirror the same section of the block, which makes it very convenient for +// emulating // memory mirrors. class MemArena { public: - void GrabSHMSegment(size_t size); - void ReleaseSHMSegment(); - void* CreateView(s64 offset, size_t size, void* base = nullptr); - void ReleaseView(void* view, size_t size); + void GrabSHMSegment(size_t size); + void ReleaseSHMSegment(); + void* CreateView(s64 offset, size_t size, void* base = nullptr); + void ReleaseView(void* view, size_t size); + + // This finds 1 GB in 32-bit, 16 GB in 64-bit. + static u8* FindMemoryBase(); - // This finds 1 GB in 32-bit, 16 GB in 64-bit. - static u8* FindMemoryBase(); private: - #ifdef _WIN32 - HANDLE hMemoryMapping; + HANDLE hMemoryMapping; #else - int fd; + int fd; #endif }; -enum { - MV_MIRROR_PREVIOUS = 1, - MV_FAKE_VMEM = 2, - MV_WII_ONLY = 4, +enum +{ + MV_MIRROR_PREVIOUS = 1, + MV_FAKE_VMEM = 2, + MV_WII_ONLY = 4, }; struct MemoryView { - u8** out_ptr; - u64 virtual_address; - u32 size; - u32 flags; - void* mapped_ptr; - void* view_ptr; - u32 shm_position; + u8** out_ptr; + u64 virtual_address; + u32 size; + u32 flags; + void* mapped_ptr; + void* view_ptr; + u32 shm_position; }; // Uses a memory arena to set up an emulator-friendly memory map according to diff --git a/Source/Core/Common/MemoryUtil.cpp b/Source/Core/Common/MemoryUtil.cpp index 946fcfaf4f..61b1ee303c 100644 --- a/Source/Core/Common/MemoryUtil.cpp +++ b/Source/Core/Common/MemoryUtil.cpp @@ -8,13 +8,13 @@ #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/MemoryUtil.h" #include "Common/MsgHandler.h" -#include "Common/Logging/Log.h" #ifdef _WIN32 -#include #include +#include #include "Common/StringUtil.h" #else #include @@ -33,7 +33,7 @@ #if !defined(_WIN32) && defined(_M_X86_64) && !defined(MAP_32BIT) #include -#define PAGE_MASK (getpagesize() - 1) +#define PAGE_MASK (getpagesize() - 1) #define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) #endif @@ -43,227 +43,228 @@ void* AllocateExecutableMemory(size_t size, bool low) { #if defined(_WIN32) - void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); #else - static char* map_hint = nullptr; + static char* map_hint = nullptr; #if defined(_M_X86_64) && !defined(MAP_32BIT) - // This OS has no flag to enforce allocation below the 4 GB boundary, - // but if we hint that we want a low address it is very likely we will - // get one. - // An older version of this code used MAP_FIXED, but that has the side - // effect of discarding already mapped pages that happen to be in the - // requested virtual memory range (such as the emulated RAM, sometimes). - if (low && (!map_hint)) - map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */ + // This OS has no flag to enforce allocation below the 4 GB boundary, + // but if we hint that we want a low address it is very likely we will + // get one. + // An older version of this code used MAP_FIXED, but that has the side + // effect of discarding already mapped pages that happen to be in the + // requested virtual memory range (such as the emulated RAM, sometimes). + if (low && (!map_hint)) + map_hint = (char*)round_page(512 * 1024 * 1024); /* 0.5 GB rounded up to the next page */ #endif - void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANON | MAP_PRIVATE + void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE #if defined(_M_X86_64) && defined(MAP_32BIT) - | (low ? MAP_32BIT : 0) + | (low ? MAP_32BIT : 0) #endif - , -1, 0); + , + -1, 0); #endif /* defined(_WIN32) */ #ifdef _WIN32 - if (ptr == nullptr) - { + if (ptr == nullptr) + { #else - if (ptr == MAP_FAILED) - { - ptr = nullptr; + if (ptr == MAP_FAILED) + { + ptr = nullptr; #endif - PanicAlert("Failed to allocate executable memory. If you are running Dolphin in Valgrind, try '#undef MAP_32BIT'."); - } + PanicAlert("Failed to allocate executable memory. If you are running Dolphin in Valgrind, try " + "'#undef MAP_32BIT'."); + } #if !defined(_WIN32) && defined(_M_X86_64) && !defined(MAP_32BIT) - else - { - if (low) - { - map_hint += size; - map_hint = (char*)round_page(map_hint); /* round up to the next page */ - } - } + else + { + if (low) + { + map_hint += size; + map_hint = (char*)round_page(map_hint); /* round up to the next page */ + } + } #endif #if _M_X86_64 - if ((u64)ptr >= 0x80000000 && low == true) - PanicAlert("Executable memory ended up above 2GB!"); + if ((u64)ptr >= 0x80000000 && low == true) + PanicAlert("Executable memory ended up above 2GB!"); #endif - return ptr; + return ptr; } void* AllocateMemoryPages(size_t size) { #ifdef _WIN32 - void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); + void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); #else - void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, -1, 0); + void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - if (ptr == MAP_FAILED) - ptr = nullptr; + if (ptr == MAP_FAILED) + ptr = nullptr; #endif - if (ptr == nullptr) - PanicAlert("Failed to allocate raw memory"); + if (ptr == nullptr) + PanicAlert("Failed to allocate raw memory"); - return ptr; + return ptr; } void* AllocateAlignedMemory(size_t size, size_t alignment) { #ifdef _WIN32 - void* ptr = _aligned_malloc(size, alignment); + void* ptr = _aligned_malloc(size, alignment); #else - void* ptr = nullptr; - if (posix_memalign(&ptr, alignment, size) != 0) - ERROR_LOG(MEMMAP, "Failed to allocate aligned memory"); + void* ptr = nullptr; + if (posix_memalign(&ptr, alignment, size) != 0) + ERROR_LOG(MEMMAP, "Failed to allocate aligned memory"); #endif - if (ptr == nullptr) - PanicAlert("Failed to allocate aligned memory"); + if (ptr == nullptr) + PanicAlert("Failed to allocate aligned memory"); - return ptr; + return ptr; } void FreeMemoryPages(void* ptr, size_t size) { - if (ptr) - { - bool error_occurred = false; + if (ptr) + { + bool error_occurred = false; #ifdef _WIN32 - if (!VirtualFree(ptr, 0, MEM_RELEASE)) - error_occurred = true; + if (!VirtualFree(ptr, 0, MEM_RELEASE)) + error_occurred = true; #else - int retval = munmap(ptr, size); + int retval = munmap(ptr, size); - if (retval != 0) - error_occurred = true; + if (retval != 0) + error_occurred = true; #endif - if (error_occurred) - PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg().c_str()); - } + if (error_occurred) + PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg().c_str()); + } } void FreeAlignedMemory(void* ptr) { - if (ptr) - { + if (ptr) + { #ifdef _WIN32 - _aligned_free(ptr); + _aligned_free(ptr); #else - free(ptr); + free(ptr); #endif - } + } } void ReadProtectMemory(void* ptr, size_t size) { - bool error_occurred = false; + bool error_occurred = false; #ifdef _WIN32 - DWORD oldValue; - if (!VirtualProtect(ptr, size, PAGE_NOACCESS, &oldValue)) - error_occurred = true; + DWORD oldValue; + if (!VirtualProtect(ptr, size, PAGE_NOACCESS, &oldValue)) + error_occurred = true; #else - int retval = mprotect(ptr, size, PROT_NONE); + int retval = mprotect(ptr, size, PROT_NONE); - if (retval != 0) - error_occurred = true; + if (retval != 0) + error_occurred = true; #endif - if (error_occurred) - PanicAlert("ReadProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); + if (error_occurred) + PanicAlert("ReadProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); } void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) { - bool error_occurred = false; + bool error_occurred = false; #ifdef _WIN32 - DWORD oldValue; - if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) - error_occurred = true; + DWORD oldValue; + if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) + error_occurred = true; #else - int retval = mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ); + int retval = mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ); - if (retval != 0) - error_occurred = true; + if (retval != 0) + error_occurred = true; #endif - if (error_occurred) - PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); + if (error_occurred) + PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); } void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) { - bool error_occurred = false; + bool error_occurred = false; #ifdef _WIN32 - DWORD oldValue; - if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue)) - error_occurred = true; + DWORD oldValue; + if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue)) + error_occurred = true; #else - int retval = mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); + int retval = mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : + PROT_WRITE | PROT_READ); - if (retval != 0) - error_occurred = true; + if (retval != 0) + error_occurred = true; #endif - if (error_occurred) - PanicAlert("UnWriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); + if (error_occurred) + PanicAlert("UnWriteProtectMemory failed!\n%s", GetLastErrorMsg().c_str()); } std::string MemUsage() { #ifdef _WIN32 #pragma comment(lib, "psapi") - DWORD processID = GetCurrentProcessId(); - HANDLE hProcess; - PROCESS_MEMORY_COUNTERS pmc; - std::string Ret; + DWORD processID = GetCurrentProcessId(); + HANDLE hProcess; + PROCESS_MEMORY_COUNTERS pmc; + std::string Ret; - // Print information about the memory usage of the process. + // Print information about the memory usage of the process. - hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); - if (nullptr == hProcess) return "MemUsage Error"; + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); + if (nullptr == hProcess) + return "MemUsage Error"; - if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) - Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); + if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) + Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); - CloseHandle(hProcess); - return Ret; + CloseHandle(hProcess); + return Ret; #else - return ""; + return ""; #endif } - size_t MemPhysical() { #ifdef _WIN32 - MEMORYSTATUSEX memInfo; - memInfo.dwLength = sizeof(MEMORYSTATUSEX); - GlobalMemoryStatusEx(&memInfo); - return memInfo.ullTotalPhys; + MEMORYSTATUSEX memInfo; + memInfo.dwLength = sizeof(MEMORYSTATUSEX); + GlobalMemoryStatusEx(&memInfo); + return memInfo.ullTotalPhys; #elif defined __APPLE__ || defined __FreeBSD__ - int mib[2]; - size_t physical_memory; - mib[0] = CTL_HW; + int mib[2]; + size_t physical_memory; + mib[0] = CTL_HW; #ifdef __APPLE__ - mib[1] = HW_MEMSIZE; + mib[1] = HW_MEMSIZE; #elif defined __FreeBSD__ - mib[1] = HW_REALMEM; + mib[1] = HW_REALMEM; #endif - size_t length = sizeof(size_t); - sysctl(mib, 2, &physical_memory, &length, NULL, 0); - return physical_memory; + size_t length = sizeof(size_t); + sysctl(mib, 2, &physical_memory, &length, NULL, 0); + return physical_memory; #else - struct sysinfo memInfo; - sysinfo (&memInfo); - return (size_t)memInfo.totalram * memInfo.mem_unit; + struct sysinfo memInfo; + sysinfo(&memInfo); + return (size_t)memInfo.totalram * memInfo.mem_unit; #endif } diff --git a/Source/Core/Common/MemoryUtil.h b/Source/Core/Common/MemoryUtil.h index e986069d24..2224324fa2 100644 --- a/Source/Core/Common/MemoryUtil.h +++ b/Source/Core/Common/MemoryUtil.h @@ -10,7 +10,7 @@ void* AllocateExecutableMemory(size_t size, bool low = true); void* AllocateMemoryPages(size_t size); void FreeMemoryPages(void* ptr, size_t size); -void* AllocateAlignedMemory(size_t size,size_t alignment); +void* AllocateAlignedMemory(size_t size, size_t alignment); void FreeAlignedMemory(void* ptr); void ReadProtectMemory(void* ptr, size_t size); void WriteProtectMemory(void* ptr, size_t size, bool executable = false); @@ -21,4 +21,7 @@ size_t MemPhysical(); void GuardMemoryMake(void* ptr, size_t size); void GuardMemoryUnmake(void* ptr, size_t size); -inline int GetPageSize() { return 4096; } +inline int GetPageSize() +{ + return 4096; +} diff --git a/Source/Core/Common/Misc.cpp b/Source/Core/Common/Misc.cpp index 849fa78c75..870294092c 100644 --- a/Source/Core/Common/Misc.cpp +++ b/Source/Core/Common/Misc.cpp @@ -13,18 +13,17 @@ // This function might change the error code. std::string GetLastErrorMsg() { - const size_t buff_size = 256; - char err_str[buff_size]; + const size_t buff_size = 256; + char err_str[buff_size]; #ifdef _WIN32 - FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - err_str, buff_size, nullptr); + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr); #else - // Thread safe (XSI-compliant) - if (strerror_r(errno, err_str, buff_size)) - return ""; + // Thread safe (XSI-compliant) + if (strerror_r(errno, err_str, buff_size)) + return ""; #endif - return std::string(err_str); + return std::string(err_str); } diff --git a/Source/Core/Common/MsgHandler.cpp b/Source/Core/Common/MsgHandler.cpp index e73efe9020..caf8d99f15 100644 --- a/Source/Core/Common/MsgHandler.cpp +++ b/Source/Core/Common/MsgHandler.cpp @@ -8,9 +8,9 @@ #include "Common/Common.h" #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style); static MsgAlertHandler msg_handler = DefaultMsgHandler; @@ -23,97 +23,99 @@ static StringTranslator str_translator = DefaultStringTranslator; // wxWidgets is enabled we will use wxMsgAlert() that is defined in Main.cpp void RegisterMsgAlertHandler(MsgAlertHandler handler) { - msg_handler = handler; + msg_handler = handler; } // Select translation function. For wxWidgets use wxStringTranslator in Main.cpp void RegisterStringTranslator(StringTranslator translator) { - str_translator = translator; + str_translator = translator; } // enable/disable the alert handler void SetEnableAlert(bool enable) { - AlertEnabled = enable; + AlertEnabled = enable; } std::string GetTranslation(const char* string) { - return str_translator(string); + return str_translator(string); } // This is the first stop for gui alerts where the log is updated and the // correct window is shown bool MsgAlert(bool yes_no, int Style, const char* format, ...) { - // Read message and write it to the log - std::string caption; - char buffer[2048]; + // Read message and write it to the log + std::string caption; + char buffer[2048]; - static std::string info_caption; - static std::string warn_caption; - static std::string ques_caption; - static std::string crit_caption; + static std::string info_caption; + static std::string warn_caption; + static std::string ques_caption; + static std::string crit_caption; - if (!info_caption.length()) - { - info_caption = str_translator(_trans("Information")); - ques_caption = str_translator(_trans("Question")); - warn_caption = str_translator(_trans("Warning")); - crit_caption = str_translator(_trans("Critical")); - } + if (!info_caption.length()) + { + info_caption = str_translator(_trans("Information")); + ques_caption = str_translator(_trans("Question")); + warn_caption = str_translator(_trans("Warning")); + crit_caption = str_translator(_trans("Critical")); + } - switch (Style) - { - case INFORMATION: - caption = info_caption; - break; - case QUESTION: - caption = ques_caption; - break; - case WARNING: - caption = warn_caption; - break; - case CRITICAL: - caption = crit_caption; - break; - } + switch (Style) + { + case INFORMATION: + caption = info_caption; + break; + case QUESTION: + caption = ques_caption; + break; + case WARNING: + caption = warn_caption; + break; + case CRITICAL: + caption = crit_caption; + break; + } - va_list args; - va_start(args, format); - CharArrayFromFormatV(buffer, sizeof(buffer) - 1, str_translator(format).c_str(), args); - va_end(args); + va_list args; + va_start(args, format); + CharArrayFromFormatV(buffer, sizeof(buffer) - 1, str_translator(format).c_str(), args); + va_end(args); - ERROR_LOG(MASTER_LOG, "%s: %s", caption.c_str(), buffer); + ERROR_LOG(MASTER_LOG, "%s: %s", caption.c_str(), buffer); - // Don't ignore questions, especially AskYesNo, PanicYesNo could be ignored - if (msg_handler && (AlertEnabled || Style == QUESTION || Style == CRITICAL)) - return msg_handler(caption.c_str(), buffer, yes_no, Style); + // Don't ignore questions, especially AskYesNo, PanicYesNo could be ignored + if (msg_handler && (AlertEnabled || Style == QUESTION || Style == CRITICAL)) + return msg_handler(caption.c_str(), buffer, yes_no, Style); - return true; + return true; } // Default non library dependent panic alert bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style) { #ifdef _WIN32 - int STYLE = MB_ICONINFORMATION; - if (Style == QUESTION) STYLE = MB_ICONQUESTION; - if (Style == WARNING) STYLE = MB_ICONWARNING; + int STYLE = MB_ICONINFORMATION; + if (Style == QUESTION) + STYLE = MB_ICONQUESTION; + if (Style == WARNING) + STYLE = MB_ICONWARNING; - return IDYES == MessageBox(0, UTF8ToTStr(text).c_str(), UTF8ToTStr(caption).c_str(), STYLE | (yes_no ? MB_YESNO : MB_OK)); + return IDYES == MessageBox(0, UTF8ToTStr(text).c_str(), UTF8ToTStr(caption).c_str(), + STYLE | (yes_no ? MB_YESNO : MB_OK)); #else - fprintf(stderr, "%s\n", text); + fprintf(stderr, "%s\n", text); - // Return no to any question (which will in general crash the emulator) - return false; + // Return no to any question (which will in general crash the emulator) + return false; #endif } // Default (non) translator std::string DefaultStringTranslator(const char* text) { - return text; + return text; } - diff --git a/Source/Core/Common/MsgHandler.h b/Source/Core/Common/MsgHandler.h index f289486c02..b6fc9c32b3 100644 --- a/Source/Core/Common/MsgHandler.h +++ b/Source/Core/Common/MsgHandler.h @@ -9,14 +9,13 @@ // Message alerts enum MSG_TYPE { - INFORMATION, - QUESTION, - WARNING, - CRITICAL + INFORMATION, + QUESTION, + WARNING, + CRITICAL }; -typedef bool (*MsgAlertHandler)(const char* caption, const char* text, - bool yes_no, int Style); +typedef bool (*MsgAlertHandler)(const char* caption, const char* text, bool yes_no, int Style); typedef std::string (*StringTranslator)(const char* text); void RegisterMsgAlertHandler(MsgAlertHandler handler); @@ -25,37 +24,37 @@ void RegisterStringTranslator(StringTranslator translator); std::string GetTranslation(const char* string); bool MsgAlert(bool yes_no, int Style, const char* format, ...) #ifdef __GNUC__ - __attribute__((format(printf, 3, 4))) + __attribute__((format(printf, 3, 4))) #endif - ; + ; void SetEnableAlert(bool enable); #ifdef _WIN32 - #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) - #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) - #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) - #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) - #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) - // Use these macros (that do the same thing) if the message should be translated. - #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) - #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) - #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) - #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) - #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) +#define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) +#define PanicAlert(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) +#define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) +#define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) +#define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) +// Use these macros (that do the same thing) if the message should be translated. +#define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) +#define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) +#define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) +#define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) +#define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) - #define GetStringT(string) GetTranslation(string) +#define GetStringT(string) GetTranslation(string) #else - #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) - #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) - #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) - #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) - #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) - // Use these macros (that do the same thing) if the message should be translated. - #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) - #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) - #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) - #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) - #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) +#define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) +#define PanicAlert(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) +#define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) +#define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) +#define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) +// Use these macros (that do the same thing) if the message should be translated. +#define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) +#define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) +#define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) +#define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) +#define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) - #define GetStringT(string) GetTranslation(string) +#define GetStringT(string) GetTranslation(string) #endif diff --git a/Source/Core/Common/NandPaths.cpp b/Source/Core/Common/NandPaths.cpp index 9c00448a6a..3dc554dce9 100644 --- a/Source/Core/Common/NandPaths.cpp +++ b/Source/Core/Common/NandPaths.cpp @@ -12,143 +12,141 @@ #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" +#include "Common/Logging/Log.h" #include "Common/NandPaths.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" namespace Common { - static std::string s_temp_wii_root; void InitializeWiiRoot(bool use_dummy) { - ShutdownWiiRoot(); - if (use_dummy) - { - s_temp_wii_root = File::CreateTempDir(); - if (s_temp_wii_root.empty()) - { - ERROR_LOG(WII_IPC_FILEIO, "Could not create temporary directory"); - return; - } - File::CopyDir(File::GetSysDirectory() + WII_USER_DIR, s_temp_wii_root); - WARN_LOG(WII_IPC_FILEIO, "Using temporary directory %s for minimal Wii FS", s_temp_wii_root.c_str()); - static bool s_registered; - if (!s_registered) - { - s_registered = true; - atexit(ShutdownWiiRoot); - } - File::SetUserPath(D_SESSION_WIIROOT_IDX, s_temp_wii_root); - } - else - { - File::SetUserPath(D_SESSION_WIIROOT_IDX, File::GetUserPath(D_WIIROOT_IDX)); - } + ShutdownWiiRoot(); + if (use_dummy) + { + s_temp_wii_root = File::CreateTempDir(); + if (s_temp_wii_root.empty()) + { + ERROR_LOG(WII_IPC_FILEIO, "Could not create temporary directory"); + return; + } + File::CopyDir(File::GetSysDirectory() + WII_USER_DIR, s_temp_wii_root); + WARN_LOG(WII_IPC_FILEIO, "Using temporary directory %s for minimal Wii FS", + s_temp_wii_root.c_str()); + static bool s_registered; + if (!s_registered) + { + s_registered = true; + atexit(ShutdownWiiRoot); + } + File::SetUserPath(D_SESSION_WIIROOT_IDX, s_temp_wii_root); + } + else + { + File::SetUserPath(D_SESSION_WIIROOT_IDX, File::GetUserPath(D_WIIROOT_IDX)); + } } void ShutdownWiiRoot() { - if (!s_temp_wii_root.empty()) - { - File::DeleteDirRecursively(s_temp_wii_root); - s_temp_wii_root.clear(); - } + if (!s_temp_wii_root.empty()) + { + File::DeleteDirRecursively(s_temp_wii_root); + s_temp_wii_root.clear(); + } } static std::string RootUserPath(FromWhichRoot from) { - int idx = from == FROM_CONFIGURED_ROOT ? D_WIIROOT_IDX : D_SESSION_WIIROOT_IDX; - return File::GetUserPath(idx); + int idx = from == FROM_CONFIGURED_ROOT ? D_WIIROOT_IDX : D_SESSION_WIIROOT_IDX; + return File::GetUserPath(idx); } std::string GetTicketFileName(u64 _titleID, FromWhichRoot from) { - return StringFromFormat("%s/ticket/%08x/%08x.tik", - RootUserPath(from).c_str(), - (u32)(_titleID >> 32), (u32)_titleID); + return StringFromFormat("%s/ticket/%08x/%08x.tik", RootUserPath(from).c_str(), + (u32)(_titleID >> 32), (u32)_titleID); } std::string GetTitleDataPath(u64 _titleID, FromWhichRoot from) { - return StringFromFormat("%s/title/%08x/%08x/data/", - RootUserPath(from).c_str(), - (u32)(_titleID >> 32), (u32)_titleID); + return StringFromFormat("%s/title/%08x/%08x/data/", RootUserPath(from).c_str(), + (u32)(_titleID >> 32), (u32)_titleID); } std::string GetTMDFileName(u64 _titleID, FromWhichRoot from) { - return GetTitleContentPath(_titleID, from) + "title.tmd"; + return GetTitleContentPath(_titleID, from) + "title.tmd"; } std::string GetTitleContentPath(u64 _titleID, FromWhichRoot from) { - return StringFromFormat("%s/title/%08x/%08x/content/", - RootUserPath(from).c_str(), - (u32)(_titleID >> 32), (u32)_titleID); + return StringFromFormat("%s/title/%08x/%08x/content/", RootUserPath(from).c_str(), + (u32)(_titleID >> 32), (u32)_titleID); } bool CheckTitleTMD(u64 _titleID, FromWhichRoot from) { - const std::string TitlePath = GetTMDFileName(_titleID, from); - if (File::Exists(TitlePath)) - { - File::IOFile pTMDFile(TitlePath, "rb"); - u64 TitleID = 0; - pTMDFile.Seek(0x18C, SEEK_SET); - if (pTMDFile.ReadArray(&TitleID, 1) && _titleID == Common::swap64(TitleID)) - return true; - } - INFO_LOG(DISCIO, "Invalid or no tmd for title %08x %08x", (u32)(_titleID >> 32), (u32)(_titleID & 0xFFFFFFFF)); - return false; + const std::string TitlePath = GetTMDFileName(_titleID, from); + if (File::Exists(TitlePath)) + { + File::IOFile pTMDFile(TitlePath, "rb"); + u64 TitleID = 0; + pTMDFile.Seek(0x18C, SEEK_SET); + if (pTMDFile.ReadArray(&TitleID, 1) && _titleID == Common::swap64(TitleID)) + return true; + } + INFO_LOG(DISCIO, "Invalid or no tmd for title %08x %08x", (u32)(_titleID >> 32), + (u32)(_titleID & 0xFFFFFFFF)); + return false; } bool CheckTitleTIK(u64 _titleID, FromWhichRoot from) { - const std::string ticketFileName = Common::GetTicketFileName(_titleID, from); - if (File::Exists(ticketFileName)) - { - File::IOFile pTIKFile(ticketFileName, "rb"); - u64 TitleID = 0; - pTIKFile.Seek(0x1dC, SEEK_SET); - if (pTIKFile.ReadArray(&TitleID, 1) && _titleID == Common::swap64(TitleID)) - return true; - } - INFO_LOG(DISCIO, "Invalid or no tik for title %08x %08x", (u32)(_titleID >> 32), (u32)(_titleID & 0xFFFFFFFF)); - return false; + const std::string ticketFileName = Common::GetTicketFileName(_titleID, from); + if (File::Exists(ticketFileName)) + { + File::IOFile pTIKFile(ticketFileName, "rb"); + u64 TitleID = 0; + pTIKFile.Seek(0x1dC, SEEK_SET); + if (pTIKFile.ReadArray(&TitleID, 1) && _titleID == Common::swap64(TitleID)) + return true; + } + INFO_LOG(DISCIO, "Invalid or no tik for title %08x %08x", (u32)(_titleID >> 32), + (u32)(_titleID & 0xFFFFFFFF)); + return false; } static void CreateReplacementFile(std::string& filename) { - std::ofstream replace; - OpenFStream(replace, filename, std::ios_base::out); - replace <<"\" __22__\n"; - replace << "* __2a__\n"; - //replace << "/ __2f__\n"; - replace << ": __3a__\n"; - replace << "< __3c__\n"; - replace << "> __3e__\n"; - replace << "? __3f__\n"; - //replace <<"\\ __5c__\n"; - replace << "| __7c__\n"; + std::ofstream replace; + OpenFStream(replace, filename, std::ios_base::out); + replace << "\" __22__\n"; + replace << "* __2a__\n"; + // replace << "/ __2f__\n"; + replace << ": __3a__\n"; + replace << "< __3c__\n"; + replace << "> __3e__\n"; + replace << "? __3f__\n"; + // replace <<"\\ __5c__\n"; + replace << "| __7c__\n"; } void ReadReplacements(replace_v& replacements) { - replacements.clear(); - const std::string replace_fname = "/sys/replace"; - std::string filename = File::GetUserPath(D_SESSION_WIIROOT_IDX) + replace_fname; + replacements.clear(); + const std::string replace_fname = "/sys/replace"; + std::string filename = File::GetUserPath(D_SESSION_WIIROOT_IDX) + replace_fname; - if (!File::Exists(filename)) - CreateReplacementFile(filename); + if (!File::Exists(filename)) + CreateReplacementFile(filename); - std::ifstream f; - OpenFStream(f, filename, std::ios_base::in); - char letter; - std::string replacement; + std::ifstream f; + OpenFStream(f, filename, std::ios_base::in); + char letter; + std::string replacement; - while (f >> letter >> replacement && replacement.size()) - replacements.emplace_back(letter, replacement); + while (f >> letter >> replacement && replacement.size()) + replacements.emplace_back(letter, replacement); } - } diff --git a/Source/Core/Common/NandPaths.h b/Source/Core/Common/NandPaths.h index 7d33477d76..b2dc143963 100644 --- a/Source/Core/Common/NandPaths.h +++ b/Source/Core/Common/NandPaths.h @@ -15,23 +15,23 @@ static const std::string TITLEID_SYSMENU_STRING = "0000000100000002"; namespace Common { - typedef std::pair replace_t; - typedef std::vector replace_v; +typedef std::pair replace_t; +typedef std::vector replace_v; - void InitializeWiiRoot(bool use_temporary); - void ShutdownWiiRoot(); +void InitializeWiiRoot(bool use_temporary); +void ShutdownWiiRoot(); - enum FromWhichRoot - { - FROM_CONFIGURED_ROOT, // not related to currently running game - use D_WIIROOT_IDX - FROM_SESSION_ROOT, // request from currently running game - use D_SESSION_WIIROOT_IDX - }; +enum FromWhichRoot +{ + FROM_CONFIGURED_ROOT, // not related to currently running game - use D_WIIROOT_IDX + FROM_SESSION_ROOT, // request from currently running game - use D_SESSION_WIIROOT_IDX +}; - std::string GetTicketFileName(u64 _titleID, FromWhichRoot from); - std::string GetTMDFileName(u64 _titleID, FromWhichRoot from); - std::string GetTitleDataPath(u64 _titleID, FromWhichRoot from); - std::string GetTitleContentPath(u64 _titleID, FromWhichRoot from); - bool CheckTitleTMD(u64 _titleID, FromWhichRoot from); - bool CheckTitleTIK(u64 _titleID, FromWhichRoot from); - void ReadReplacements(replace_v& replacements); +std::string GetTicketFileName(u64 _titleID, FromWhichRoot from); +std::string GetTMDFileName(u64 _titleID, FromWhichRoot from); +std::string GetTitleDataPath(u64 _titleID, FromWhichRoot from); +std::string GetTitleContentPath(u64 _titleID, FromWhichRoot from); +bool CheckTitleTMD(u64 _titleID, FromWhichRoot from); +bool CheckTitleTIK(u64 _titleID, FromWhichRoot from); +void ReadReplacements(replace_v& replacements); } diff --git a/Source/Core/Common/Network.cpp b/Source/Core/Common/Network.cpp index c03ed0fc76..ce61cefc59 100644 --- a/Source/Core/Common/Network.cpp +++ b/Source/Core/Common/Network.cpp @@ -13,57 +13,58 @@ void GenerateMacAddress(const MACConsumer type, u8* mac) { - memset(mac, 0, MAC_ADDRESS_SIZE); + memset(mac, 0, MAC_ADDRESS_SIZE); - u8 const oui_bba[] = { 0x00, 0x09, 0xbf }; - u8 const oui_ios[] = { 0x00, 0x17, 0xab }; + u8 const oui_bba[] = {0x00, 0x09, 0xbf}; + u8 const oui_ios[] = {0x00, 0x17, 0xab}; - switch (type) - { - case BBA: - memcpy(mac, oui_bba, 3); - break; - case IOS: - memcpy(mac, oui_ios, 3); - break; - } + switch (type) + { + case BBA: + memcpy(mac, oui_bba, 3); + break; + case IOS: + memcpy(mac, oui_ios, 3); + break; + } - // Generate the 24-bit NIC-specific portion of the MAC address. - std::default_random_engine generator(Common::Timer::GetTimeMs()); - std::uniform_int_distribution distribution(0x00, 0xFF); - mac[3] = static_cast(distribution(generator)); - mac[4] = static_cast(distribution(generator)); - mac[5] = static_cast(distribution(generator)); + // Generate the 24-bit NIC-specific portion of the MAC address. + std::default_random_engine generator(Common::Timer::GetTimeMs()); + std::uniform_int_distribution distribution(0x00, 0xFF); + mac[3] = static_cast(distribution(generator)); + mac[4] = static_cast(distribution(generator)); + mac[5] = static_cast(distribution(generator)); } std::string MacAddressToString(const u8* mac) { - return StringFromFormat("%02x:%02x:%02x:%02x:%02x:%02x", - mac[0], mac[1], mac[2], - mac[3], mac[4], mac[5]); + return StringFromFormat("%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], + mac[5]); } bool StringToMacAddress(const std::string& mac_string, u8* mac) { - bool success = false; - if (!mac_string.empty()) - { - int x = 0; - memset(mac, 0, MAC_ADDRESS_SIZE); + bool success = false; + if (!mac_string.empty()) + { + int x = 0; + memset(mac, 0, MAC_ADDRESS_SIZE); - for (size_t i = 0; i < mac_string.size() && x < (MAC_ADDRESS_SIZE*2); ++i) - { - char c = tolower(mac_string.at(i)); - if (c >= '0' && c <= '9') - { - mac[x / 2] |= (c - '0') << ((x & 1) ? 0 : 4); ++x; - } - else if (c >= 'a' && c <= 'f') - { - mac[x / 2] |= (c - 'a' + 10) << ((x & 1) ? 0 : 4); ++x; - } - } - success = x / 2 == MAC_ADDRESS_SIZE; - } - return success; + for (size_t i = 0; i < mac_string.size() && x < (MAC_ADDRESS_SIZE * 2); ++i) + { + char c = tolower(mac_string.at(i)); + if (c >= '0' && c <= '9') + { + mac[x / 2] |= (c - '0') << ((x & 1) ? 0 : 4); + ++x; + } + else if (c >= 'a' && c <= 'f') + { + mac[x / 2] |= (c - 'a' + 10) << ((x & 1) ? 0 : 4); + ++x; + } + } + success = x / 2 == MAC_ADDRESS_SIZE; + } + return success; } diff --git a/Source/Core/Common/Network.h b/Source/Core/Common/Network.h index aea8e729cd..f353374d37 100644 --- a/Source/Core/Common/Network.h +++ b/Source/Core/Common/Network.h @@ -10,13 +10,13 @@ enum MACConsumer { - BBA = 0, - IOS = 1 + BBA = 0, + IOS = 1 }; enum { - MAC_ADDRESS_SIZE = 6 + MAC_ADDRESS_SIZE = 6 }; void GenerateMacAddress(const MACConsumer type, u8* mac); diff --git a/Source/Core/Common/NonCopyable.h b/Source/Core/Common/NonCopyable.h index f0f14bad09..77233b108e 100644 --- a/Source/Core/Common/NonCopyable.h +++ b/Source/Core/Common/NonCopyable.h @@ -8,9 +8,9 @@ class NonCopyable { protected: - constexpr NonCopyable() = default; - ~NonCopyable() = default; + constexpr NonCopyable() = default; + ~NonCopyable() = default; - NonCopyable(const NonCopyable&) = delete; - NonCopyable& operator=(const NonCopyable&) = delete; + NonCopyable(const NonCopyable&) = delete; + NonCopyable& operator=(const NonCopyable&) = delete; }; diff --git a/Source/Core/Common/PcapFile.cpp b/Source/Core/Common/PcapFile.cpp index 0b34ce2daf..e7be008c68 100644 --- a/Source/Core/Common/PcapFile.cpp +++ b/Source/Core/Common/PcapFile.cpp @@ -8,8 +8,8 @@ #include "Common/FileUtil.h" #include "Common/PcapFile.h" -namespace { - +namespace +{ const u32 PCAP_MAGIC = 0xa1b2c3d4; const u16 PCAP_VERSION_MAJOR = 2; const u16 PCAP_VERSION_MINOR = 4; @@ -23,21 +23,21 @@ const u32 PCAP_DATA_LINK_TYPE = 147; // Reserved for internal use. #pragma pack(push, 1) struct PCAPHeader { - u32 magic_number; - u16 version_major; - u16 version_minor; - s32 tz_offset; // Offset in seconds from the GMT timezone. - u32 ts_accuracy; // In practice, 0. - u32 capture_length; // Size at which we truncate packets. - u32 data_link_type; + u32 magic_number; + u16 version_major; + u16 version_minor; + s32 tz_offset; // Offset in seconds from the GMT timezone. + u32 ts_accuracy; // In practice, 0. + u32 capture_length; // Size at which we truncate packets. + u32 data_link_type; }; struct PCAPRecordHeader { - u32 ts_sec; - u32 ts_usec; - u32 size_in_file; // Size after eventual truncation. - u32 real_size; // Size before eventual truncation. + u32 ts_sec; + u32 ts_usec; + u32 size_in_file; // Size after eventual truncation. + u32 real_size; // Size before eventual truncation. }; #pragma pack(pop) @@ -45,22 +45,19 @@ struct PCAPRecordHeader void PCAP::AddHeader() { - PCAPHeader hdr = { - PCAP_MAGIC, PCAP_VERSION_MAJOR, PCAP_VERSION_MINOR, - 0, 0, PCAP_CAPTURE_LENGTH, PCAP_DATA_LINK_TYPE - }; - m_fp->WriteBytes(&hdr, sizeof (hdr)); + PCAPHeader hdr = {PCAP_MAGIC, PCAP_VERSION_MAJOR, PCAP_VERSION_MINOR, 0, + 0, PCAP_CAPTURE_LENGTH, PCAP_DATA_LINK_TYPE}; + m_fp->WriteBytes(&hdr, sizeof(hdr)); } void PCAP::AddPacket(const u8* bytes, size_t size) { - std::chrono::system_clock::time_point now(std::chrono::system_clock::now()); - auto ts = now.time_since_epoch(); - PCAPRecordHeader rec_hdr = { - (u32)std::chrono::duration_cast(ts).count(), - (u32)(std::chrono::duration_cast(ts).count() % 1000000), - (u32)size, (u32)size - }; - m_fp->WriteBytes(&rec_hdr, sizeof (rec_hdr)); - m_fp->WriteBytes(bytes, size); + std::chrono::system_clock::time_point now(std::chrono::system_clock::now()); + auto ts = now.time_since_epoch(); + PCAPRecordHeader rec_hdr = { + (u32)std::chrono::duration_cast(ts).count(), + (u32)(std::chrono::duration_cast(ts).count() % 1000000), (u32)size, + (u32)size}; + m_fp->WriteBytes(&rec_hdr, sizeof(rec_hdr)); + m_fp->WriteBytes(bytes, size); } diff --git a/Source/Core/Common/PcapFile.h b/Source/Core/Common/PcapFile.h index 39d2abcc44..823a974946 100644 --- a/Source/Core/Common/PcapFile.h +++ b/Source/Core/Common/PcapFile.h @@ -23,23 +23,19 @@ class PCAP final : public NonCopyable { public: - // Takes ownership of the file object. Assumes the file object is already - // opened in write mode. - explicit PCAP(File::IOFile* fp) : m_fp(fp) - { - AddHeader(); - } + // Takes ownership of the file object. Assumes the file object is already + // opened in write mode. + explicit PCAP(File::IOFile* fp) : m_fp(fp) { AddHeader(); } + template + void AddPacket(const T& obj) + { + AddPacket(reinterpret_cast(&obj), sizeof(obj)); + } - template - void AddPacket(const T& obj) - { - AddPacket(reinterpret_cast(&obj), sizeof (obj)); - } - - void AddPacket(const u8* bytes, size_t size); + void AddPacket(const u8* bytes, size_t size); private: - void AddHeader(); + void AddHeader(); - std::unique_ptr m_fp; + std::unique_ptr m_fp; }; diff --git a/Source/Core/Common/PerformanceCounter.cpp b/Source/Core/Common/PerformanceCounter.cpp index a1b8c64e8c..cd58983099 100644 --- a/Source/Core/Common/PerformanceCounter.cpp +++ b/Source/Core/Common/PerformanceCounter.cpp @@ -13,7 +13,7 @@ #include "Common/PerformanceCounter.h" #if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 -#if defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK>0 +#if defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK > 0 #define DOLPHIN_CLOCK CLOCK_MONOTONIC #else #define DOLPHIN_CLOCK CLOCK_REALTIME @@ -23,25 +23,25 @@ bool QueryPerformanceCounter(u64* out) { #if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 - timespec tp; - if (clock_gettime(DOLPHIN_CLOCK, &tp)) - return false; - *out = (u64) tp.tv_nsec + (u64) 1000000000 * (u64) tp.tv_sec; - return true; + timespec tp; + if (clock_gettime(DOLPHIN_CLOCK, &tp)) + return false; + *out = (u64)tp.tv_nsec + (u64)1000000000 * (u64)tp.tv_sec; + return true; #else - *out = 0; - return false; + *out = 0; + return false; #endif } bool QueryPerformanceFrequency(u64* out) { #if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 - *out = 1000000000; - return true; + *out = 1000000000; + return true; #else - *out = 1; - return false; + *out = 1; + return false; #endif } diff --git a/Source/Core/Common/Profiler.cpp b/Source/Core/Common/Profiler.cpp index 7a195dd02d..0c7807a532 100644 --- a/Source/Core/Common/Profiler.cpp +++ b/Source/Core/Common/Profiler.cpp @@ -14,10 +14,9 @@ namespace Common { - static const u32 PROFILER_FIELD_LENGTH = 8; static const u32 PROFILER_FIELD_LENGTH_FP = PROFILER_FIELD_LENGTH + 3; -static const int PROFILER_LAZY_DELAY = 60; // in frames +static const int PROFILER_LAZY_DELAY = 60; // in frames std::list Profiler::s_all_profilers; std::mutex Profiler::s_mutex; @@ -29,126 +28,136 @@ std::string Profiler::s_lazy_result = ""; int Profiler::s_lazy_delay = 0; Profiler::Profiler(const std::string& name) -: m_name(name), m_usecs(0), m_usecs_min(-1), m_usecs_max(0), m_usecs_quad(0), m_calls(0), m_depth(0) + : m_name(name), m_usecs(0), m_usecs_min(-1), m_usecs_max(0), m_usecs_quad(0), m_calls(0), + m_depth(0) { - m_time = Common::Timer::GetTimeUs(); - s_max_length = std::max(s_max_length, u32(m_name.length())); + m_time = Common::Timer::GetTimeUs(); + s_max_length = std::max(s_max_length, u32(m_name.length())); - std::lock_guard lk(s_mutex); - s_all_profilers.push_back(this); + std::lock_guard lk(s_mutex); + s_all_profilers.push_back(this); } Profiler::~Profiler() { - std::lock_guard lk(s_mutex); - s_all_profilers.remove(this); + std::lock_guard lk(s_mutex); + s_all_profilers.remove(this); } bool Profiler::operator<(const Profiler& b) const { - return m_usecs < b.m_usecs; + return m_usecs < b.m_usecs; } std::string Profiler::ToString() { - if (s_lazy_delay > 0) - { - s_lazy_delay--; - return s_lazy_result; - } - s_lazy_delay = PROFILER_LAZY_DELAY - 1; + if (s_lazy_delay > 0) + { + s_lazy_delay--; + return s_lazy_result; + } + s_lazy_delay = PROFILER_LAZY_DELAY - 1; - // don't write anything if no profilation is enabled - std::lock_guard lk(s_mutex); - if (s_all_profilers.empty()) - return ""; + // don't write anything if no profilation is enabled + std::lock_guard lk(s_mutex); + if (s_all_profilers.empty()) + return ""; - u64 end = Common::Timer::GetTimeUs(); - s_usecs_frame = end - s_frame_time; - s_frame_time = end; + u64 end = Common::Timer::GetTimeUs(); + s_usecs_frame = end - s_frame_time; + s_frame_time = end; - std::ostringstream buffer; - buffer << std::setw(s_max_length) << std::left << "" << " "; - buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << "calls" << " "; - buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << "sum" << " "; - buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << "rel" << " "; - buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << "min" << " "; - buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << "avg" << " "; - buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << "stdev" << " "; - buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << "max" << " "; - buffer << "/ usec" << std::endl; + std::ostringstream buffer; + buffer << std::setw(s_max_length) << std::left << "" + << " "; + buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << "calls" + << " "; + buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << "sum" + << " "; + buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << "rel" + << " "; + buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << "min" + << " "; + buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << "avg" + << " "; + buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << "stdev" + << " "; + buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << "max" + << " "; + buffer << "/ usec" << std::endl; - s_all_profilers.sort([](Profiler* a, Profiler* b) { return *b < *a; }); + s_all_profilers.sort([](Profiler* a, Profiler* b) { return *b < *a; }); - for (auto profiler : s_all_profilers) - { - buffer << profiler->Read() << std::endl; - } - s_lazy_result = buffer.str(); - return s_lazy_result; + for (auto profiler : s_all_profilers) + { + buffer << profiler->Read() << std::endl; + } + s_lazy_result = buffer.str(); + return s_lazy_result; } void Profiler::Start() { - if (!m_depth++) - { - m_time = Common::Timer::GetTimeUs(); - } + if (!m_depth++) + { + m_time = Common::Timer::GetTimeUs(); + } } void Profiler::Stop() { - if (!--m_depth) - { - u64 end = Common::Timer::GetTimeUs(); + if (!--m_depth) + { + u64 end = Common::Timer::GetTimeUs(); - u64 diff = end - m_time; + u64 diff = end - m_time; - m_usecs += diff; - m_usecs_min = std::min(m_usecs_min, diff); - m_usecs_max = std::max(m_usecs_max, diff); - m_usecs_quad += diff * diff; - m_calls++; - } + m_usecs += diff; + m_usecs_min = std::min(m_usecs_min, diff); + m_usecs_max = std::max(m_usecs_max, diff); + m_usecs_quad += diff * diff; + m_calls++; + } } std::string Profiler::Read() { - double avg = 0; - double stdev = 0; - double time_rel = 0; - if(m_calls) - { - avg = double(m_usecs)/m_calls; - stdev = std::sqrt(double(m_usecs_quad)/m_calls - avg*avg); - } - else - { - m_usecs_min = 0; - } - if(s_usecs_frame) - { - time_rel = double(m_usecs)*100/s_usecs_frame; - } + double avg = 0; + double stdev = 0; + double time_rel = 0; + if (m_calls) + { + avg = double(m_usecs) / m_calls; + stdev = std::sqrt(double(m_usecs_quad) / m_calls - avg * avg); + } + else + { + m_usecs_min = 0; + } + if (s_usecs_frame) + { + time_rel = double(m_usecs) * 100 / s_usecs_frame; + } - std::ostringstream buffer; + std::ostringstream buffer; - buffer << std::setw(s_max_length) << std::left << m_name << " "; - buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << m_calls << " "; - buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << m_usecs << " "; - buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << time_rel << " "; - buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << m_usecs_min << " "; - buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << std::fixed << std::setprecision(2) << avg << " "; - buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << std::fixed << std::setprecision(2) << stdev << " "; - buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << m_usecs_max; + buffer << std::setw(s_max_length) << std::left << m_name << " "; + buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << m_calls << " "; + buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << m_usecs << " "; + buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << time_rel << " "; + buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << m_usecs_min << " "; + buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << std::fixed << std::setprecision(2) + << avg << " "; + buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << std::fixed << std::setprecision(2) + << stdev << " "; + buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << m_usecs_max; - m_usecs = 0; - m_usecs_min = -1; - m_usecs_max = 0; - m_usecs_quad = 0; - m_calls = 0; + m_usecs = 0; + m_usecs_min = -1; + m_usecs_max = 0; + m_usecs_quad = 0; + m_calls = 0; - return buffer.str(); + return buffer.str(); } - } diff --git a/Source/Core/Common/Profiler.h b/Source/Core/Common/Profiler.h index c3643d4945..bbf4af7f9e 100644 --- a/Source/Core/Common/Profiler.h +++ b/Source/Core/Common/Profiler.h @@ -12,57 +12,51 @@ namespace Common { - class Profiler { public: - Profiler(const std::string& name); - ~Profiler(); + Profiler(const std::string& name); + ~Profiler(); - static std::string ToString(); + static std::string ToString(); - void Start(); - void Stop(); - std::string Read(); + void Start(); + void Stop(); + std::string Read(); - bool operator<(const Profiler& b) const; + bool operator<(const Profiler& b) const; private: - static std::list s_all_profilers; - static std::mutex s_mutex; - static u32 s_max_length; - static u64 s_frame_time; - static u64 s_usecs_frame; + static std::list s_all_profilers; + static std::mutex s_mutex; + static u32 s_max_length; + static u64 s_frame_time; + static u64 s_usecs_frame; - static std::string s_lazy_result; - static int s_lazy_delay; + static std::string s_lazy_result; + static int s_lazy_delay; - std::string m_name; - u64 m_usecs; - u64 m_usecs_min; - u64 m_usecs_max; - u64 m_usecs_quad; - u64 m_calls; - u64 m_time; - int m_depth; + std::string m_name; + u64 m_usecs; + u64 m_usecs_min; + u64 m_usecs_max; + u64 m_usecs_quad; + u64 m_calls; + u64 m_time; + int m_depth; }; class ProfilerExecuter { public: - ProfilerExecuter(Profiler* _p) : m_p(_p) - { - m_p->Start(); - } - ~ProfilerExecuter() - { - m_p->Stop(); - } + ProfilerExecuter(Profiler* _p) : m_p(_p) { m_p->Start(); } + ~ProfilerExecuter() { m_p->Stop(); } private: - Profiler* m_p; + Profiler* m_p; }; - }; // Warning: This profiler isn't thread safe. Only profile functions which doesn't run simultaneously -#define PROFILE(name) static Common::Profiler prof_gen(name); Common::ProfilerExecuter prof_e(&prof_gen); +#define PROFILE(name) \ + static Common::Profiler prof_gen(name); \ + Common::ProfilerExecuter prof_e(&prof_gen); diff --git a/Source/Core/Common/SDCardUtil.cpp b/Source/Core/Common/SDCardUtil.cpp index 84083ece2f..ba4c1c4209 100644 --- a/Source/Core/Common/SDCardUtil.cpp +++ b/Source/Core/Common/SDCardUtil.cpp @@ -42,246 +42,250 @@ #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/SDCardUtil.h" #include "Common/Logging/Log.h" +#include "Common/SDCardUtil.h" #ifndef _WIN32 -#include // for unlink() +#include // for unlink() #endif /* Believe me, you *don't* want to change these constants !! */ -#define BYTES_PER_SECTOR 512 -#define RESERVED_SECTORS 32 -#define BACKUP_BOOT_SECTOR 6 -#define NUM_FATS 2 +#define BYTES_PER_SECTOR 512 +#define RESERVED_SECTORS 32 +#define BACKUP_BOOT_SECTOR 6 +#define NUM_FATS 2 -#define BYTE_(p,i) (((u8*)(p))[(i)]) +#define BYTE_(p, i) (((u8*)(p))[(i)]) -#define POKEB(p,v) BYTE_(p,0) = (u8)(v) -#define POKES(p,v) ( BYTE_(p,0) = (u8)(v), BYTE_(p,1) = (u8)((v) >> 8) ) -#define POKEW(p,v) ( BYTE_(p,0) = (u8)(v), BYTE_(p,1) = (u8)((v) >> 8), BYTE_(p,2) = (u8)((v) >> 16), BYTE_(p,3) = (u8)((v) >> 24) ) +#define POKEB(p, v) BYTE_(p, 0) = (u8)(v) +#define POKES(p, v) (BYTE_(p, 0) = (u8)(v), BYTE_(p, 1) = (u8)((v) >> 8)) +#define POKEW(p, v) \ + (BYTE_(p, 0) = (u8)(v), BYTE_(p, 1) = (u8)((v) >> 8), BYTE_(p, 2) = (u8)((v) >> 16), \ + BYTE_(p, 3) = (u8)((v) >> 24)) -static u8 s_boot_sector [ BYTES_PER_SECTOR ]; /* Boot sector */ -static u8 s_fsinfo_sector [ BYTES_PER_SECTOR ]; /* FS Info sector */ -static u8 s_fat_head [ BYTES_PER_SECTOR ]; /* First FAT sector */ +static u8 s_boot_sector[BYTES_PER_SECTOR]; /* Boot sector */ +static u8 s_fsinfo_sector[BYTES_PER_SECTOR]; /* FS Info sector */ +static u8 s_fat_head[BYTES_PER_SECTOR]; /* First FAT sector */ /* This is the date and time when creating the disk */ static unsigned int get_serial_id() { - u16 lo, hi; - time_t now = time(nullptr); - struct tm tm = gmtime( &now )[0]; + u16 lo, hi; + time_t now = time(nullptr); + struct tm tm = gmtime(&now)[0]; - lo = (u16)(tm.tm_mday + ((tm.tm_mon+1) << 8) + (tm.tm_sec << 8)); - hi = (u16)(tm.tm_min + (tm.tm_hour << 8) + (tm.tm_year + 1900)); + lo = (u16)(tm.tm_mday + ((tm.tm_mon + 1) << 8) + (tm.tm_sec << 8)); + hi = (u16)(tm.tm_min + (tm.tm_hour << 8) + (tm.tm_year + 1900)); - return lo + (hi << 16); + return lo + (hi << 16); } static unsigned int get_sectors_per_cluster(u64 disk_size) { - u64 disk_MB = disk_size/(1024*1024); + u64 disk_MB = disk_size / (1024 * 1024); - if (disk_MB < 260) - return 1; + if (disk_MB < 260) + return 1; - if (disk_MB < 8192) - return 4; + if (disk_MB < 8192) + return 4; - if (disk_MB < 16384) - return 8; + if (disk_MB < 16384) + return 8; - if (disk_MB < 32768) - return 16; + if (disk_MB < 32768) + return 16; - return 32; + return 32; } static unsigned int get_sectors_per_fat(u64 disk_size, u32 sectors_per_cluster) { - u64 divider; + u64 divider; - /* Weird computation from MS - see fatgen103.doc for details */ - disk_size -= RESERVED_SECTORS * BYTES_PER_SECTOR; /* Don't count 32 reserved sectors */ - disk_size /= BYTES_PER_SECTOR; /* Disk size in sectors */ - divider = ((256 * sectors_per_cluster) + NUM_FATS) / 2; + /* Weird computation from MS - see fatgen103.doc for details */ + disk_size -= RESERVED_SECTORS * BYTES_PER_SECTOR; /* Don't count 32 reserved sectors */ + disk_size /= BYTES_PER_SECTOR; /* Disk size in sectors */ + divider = ((256 * sectors_per_cluster) + NUM_FATS) / 2; - return (u32)( (disk_size + (divider-1)) / divider ); + return (u32)((disk_size + (divider - 1)) / divider); } static void boot_sector_init(u8* boot, u8* info, u64 disk_size, const char* label) { - u32 sectors_per_cluster = get_sectors_per_cluster(disk_size); - u32 sectors_per_fat = get_sectors_per_fat(disk_size, sectors_per_cluster); - u32 sectors_per_disk = (u32)(disk_size / BYTES_PER_SECTOR); - u32 serial_id = get_serial_id(); - u32 free_count; + u32 sectors_per_cluster = get_sectors_per_cluster(disk_size); + u32 sectors_per_fat = get_sectors_per_fat(disk_size, sectors_per_cluster); + u32 sectors_per_disk = (u32)(disk_size / BYTES_PER_SECTOR); + u32 serial_id = get_serial_id(); + u32 free_count; - if (label == nullptr) - label = "DOLPHINSD"; + if (label == nullptr) + label = "DOLPHINSD"; - POKEB(boot, 0xeb); - POKEB(boot+1, 0x5a); - POKEB(boot+2, 0x90); - strcpy( (char*)boot + 3, "MSWIN4.1" ); - POKES( boot + 0x0b, BYTES_PER_SECTOR ); /* Sector size */ - POKEB( boot + 0xd, sectors_per_cluster ); /* Sectors per cluster */ - POKES( boot + 0xe, RESERVED_SECTORS ); /* Reserved sectors before first FAT */ - POKEB( boot + 0x10, NUM_FATS ); /* Number of FATs */ - POKES( boot + 0x11, 0 ); /* Max root directory entries for FAT12/FAT16, 0 for FAT32 */ - POKES( boot + 0x13, 0 ); /* Total sectors, 0 to use 32-bit value at offset 0x20 */ - POKEB( boot + 0x15, 0xF8 ); /* Media descriptor, 0xF8 == hard disk */ - POKES( boot + 0x16, 0 ); /* Sectors per FAT for FAT12/16, 0 for FAT32 */ - POKES( boot + 0x18, 9 ); /* Sectors per track (whatever) */ - POKES( boot + 0x1a, 2 ); /* Number of heads (whatever) */ - POKEW( boot + 0x1c, 0 ); /* Hidden sectors */ - POKEW( boot + 0x20, sectors_per_disk ); /* Total sectors */ + POKEB(boot, 0xeb); + POKEB(boot + 1, 0x5a); + POKEB(boot + 2, 0x90); + strcpy((char*)boot + 3, "MSWIN4.1"); + POKES(boot + 0x0b, BYTES_PER_SECTOR); /* Sector size */ + POKEB(boot + 0xd, sectors_per_cluster); /* Sectors per cluster */ + POKES(boot + 0xe, RESERVED_SECTORS); /* Reserved sectors before first FAT */ + POKEB(boot + 0x10, NUM_FATS); /* Number of FATs */ + POKES(boot + 0x11, 0); /* Max root directory entries for FAT12/FAT16, 0 for FAT32 */ + POKES(boot + 0x13, 0); /* Total sectors, 0 to use 32-bit value at offset 0x20 */ + POKEB(boot + 0x15, 0xF8); /* Media descriptor, 0xF8 == hard disk */ + POKES(boot + 0x16, 0); /* Sectors per FAT for FAT12/16, 0 for FAT32 */ + POKES(boot + 0x18, 9); /* Sectors per track (whatever) */ + POKES(boot + 0x1a, 2); /* Number of heads (whatever) */ + POKEW(boot + 0x1c, 0); /* Hidden sectors */ + POKEW(boot + 0x20, sectors_per_disk); /* Total sectors */ - /* Extension */ - POKEW( boot + 0x24, sectors_per_fat ); /* Sectors per FAT */ - POKES( boot + 0x28, 0 ); /* FAT flags */ - POKES( boot + 0x2a, 0 ); /* Version */ - POKEW( boot + 0x2c, 2 ); /* Cluster number of root directory start */ - POKES( boot + 0x30, 1 ); /* Sector number of FS information sector */ - POKES( boot + 0x32, BACKUP_BOOT_SECTOR ); /* Sector number of a copy of this boot sector */ - POKEB( boot + 0x40, 0x80 ); /* Physical drive number */ - POKEB( boot + 0x42, 0x29 ); /* Extended boot signature ?? */ - POKEW( boot + 0x43, serial_id ); /* Serial ID */ - strncpy( (char*)boot + 0x47, label, 11 ); /* Volume Label */ - memcpy( boot + 0x52, "FAT32 ", 8 ); /* FAT system type, padded with 0x20 */ + /* Extension */ + POKEW(boot + 0x24, sectors_per_fat); /* Sectors per FAT */ + POKES(boot + 0x28, 0); /* FAT flags */ + POKES(boot + 0x2a, 0); /* Version */ + POKEW(boot + 0x2c, 2); /* Cluster number of root directory start */ + POKES(boot + 0x30, 1); /* Sector number of FS information sector */ + POKES(boot + 0x32, BACKUP_BOOT_SECTOR); /* Sector number of a copy of this boot sector */ + POKEB(boot + 0x40, 0x80); /* Physical drive number */ + POKEB(boot + 0x42, 0x29); /* Extended boot signature ?? */ + POKEW(boot + 0x43, serial_id); /* Serial ID */ + strncpy((char*)boot + 0x47, label, 11); /* Volume Label */ + memcpy(boot + 0x52, "FAT32 ", 8); /* FAT system type, padded with 0x20 */ - POKEB( boot + BYTES_PER_SECTOR-2, 0x55 ); /* Boot sector signature */ - POKEB( boot + BYTES_PER_SECTOR-1, 0xAA ); + POKEB(boot + BYTES_PER_SECTOR - 2, 0x55); /* Boot sector signature */ + POKEB(boot + BYTES_PER_SECTOR - 1, 0xAA); - /* FSInfo sector */ - free_count = sectors_per_disk - 32 - 2*sectors_per_fat; + /* FSInfo sector */ + free_count = sectors_per_disk - 32 - 2 * sectors_per_fat; - POKEW( info + 0, 0x41615252 ); - POKEW( info + 484, 0x61417272 ); - POKEW( info + 488, free_count ); /* Number of free clusters */ - POKEW( info + 492, 3 ); /* Next free clusters, 0-1 reserved, 2 is used for the root dir */ - POKEW( info + 508, 0xAA550000 ); + POKEW(info + 0, 0x41615252); + POKEW(info + 484, 0x61417272); + POKEW(info + 488, free_count); /* Number of free clusters */ + POKEW(info + 492, 3); /* Next free clusters, 0-1 reserved, 2 is used for the root dir */ + POKEW(info + 508, 0xAA550000); } static void fat_init(u8* fat) { - POKEW( fat, 0x0ffffff8 ); /* Reserve cluster 1, media id in low byte */ - POKEW( fat + 4, 0x0fffffff ); /* Reserve cluster 2 */ - POKEW( fat + 8, 0x0fffffff ); /* End of cluster chain for root dir */ + POKEW(fat, 0x0ffffff8); /* Reserve cluster 1, media id in low byte */ + POKEW(fat + 4, 0x0fffffff); /* Reserve cluster 2 */ + POKEW(fat + 8, 0x0fffffff); /* End of cluster chain for root dir */ } - static unsigned int write_sector(FILE* file, u8* sector) { - return fwrite(sector, 1, 512, file) != 512; + return fwrite(sector, 1, 512, file) != 512; } static unsigned int write_empty(FILE* file, u64 count) { - static u8 empty[64*1024]; + static u8 empty[64 * 1024]; - count *= 512; - while (count > 0) - { - u64 len = sizeof(empty); - if (len > count) - len = count; + count *= 512; + while (count > 0) + { + u64 len = sizeof(empty); + if (len > count) + len = count; - if ( fwrite(empty, 1, (size_t)len, file) != (size_t)len ) - return 1; + if (fwrite(empty, 1, (size_t)len, file) != (size_t)len) + return 1; - count -= len; - } - return 0; + count -= len; + } + return 0; } bool SDCardCreate(u64 disk_size /*in MB*/, const std::string& filename) { - u32 sectors_per_fat; - u32 sectors_per_disk; + u32 sectors_per_fat; + u32 sectors_per_disk; - // Convert MB to bytes - disk_size *= 1024 * 1024; + // Convert MB to bytes + disk_size *= 1024 * 1024; - if (disk_size < 0x800000 || disk_size > 0x800000000ULL) - { - ERROR_LOG(COMMON, "Trying to create SD Card image of size %" PRIu64 "MB is out of range (8MB-32GB)", disk_size/(1024*1024)); - return false; - } + if (disk_size < 0x800000 || disk_size > 0x800000000ULL) + { + ERROR_LOG(COMMON, + "Trying to create SD Card image of size %" PRIu64 "MB is out of range (8MB-32GB)", + disk_size / (1024 * 1024)); + return false; + } - // Pretty unlikely to overflow. - sectors_per_disk = (u32)(disk_size / 512); - sectors_per_fat = get_sectors_per_fat(disk_size, get_sectors_per_cluster(disk_size)); + // Pretty unlikely to overflow. + sectors_per_disk = (u32)(disk_size / 512); + sectors_per_fat = get_sectors_per_fat(disk_size, get_sectors_per_cluster(disk_size)); - boot_sector_init(s_boot_sector, s_fsinfo_sector, disk_size, nullptr); - fat_init(s_fat_head); + boot_sector_init(s_boot_sector, s_fsinfo_sector, disk_size, nullptr); + fat_init(s_fat_head); - File::IOFile file(filename, "wb"); - FILE* const f = file.GetHandle(); - if (!f) - { - ERROR_LOG(COMMON, "Could not create file '%s', aborting...\n", filename.c_str()); - return false; - } + File::IOFile file(filename, "wb"); + FILE* const f = file.GetHandle(); + if (!f) + { + ERROR_LOG(COMMON, "Could not create file '%s', aborting...\n", filename.c_str()); + return false; + } - /* Here's the layout: - * - * boot_sector - * fsinfo_sector - * empty - * backup boot sector - * backup fsinfo sector - * RESERVED_SECTORS - 4 empty sectors (if backup sectors), or RESERVED_SECTORS - 2 (if no backup) - * first fat - * second fat - * zero sectors - */ + /* Here's the layout: + * + * boot_sector + * fsinfo_sector + * empty + * backup boot sector + * backup fsinfo sector + * RESERVED_SECTORS - 4 empty sectors (if backup sectors), or RESERVED_SECTORS - 2 (if no backup) + * first fat + * second fat + * zero sectors + */ - if (write_sector(f, s_boot_sector)) - goto FailWrite; + if (write_sector(f, s_boot_sector)) + goto FailWrite; - if (write_sector(f, s_fsinfo_sector)) - goto FailWrite; + if (write_sector(f, s_fsinfo_sector)) + goto FailWrite; - if (BACKUP_BOOT_SECTOR > 0) - { - if (write_empty(f, BACKUP_BOOT_SECTOR - 2)) - goto FailWrite; + if (BACKUP_BOOT_SECTOR > 0) + { + if (write_empty(f, BACKUP_BOOT_SECTOR - 2)) + goto FailWrite; - if (write_sector(f, s_boot_sector)) - goto FailWrite; + if (write_sector(f, s_boot_sector)) + goto FailWrite; - if (write_sector(f, s_fsinfo_sector)) - goto FailWrite; + if (write_sector(f, s_fsinfo_sector)) + goto FailWrite; - if (write_empty(f, RESERVED_SECTORS - 2 - BACKUP_BOOT_SECTOR)) - goto FailWrite; - } - else - { - if (write_empty(f, RESERVED_SECTORS - 2)) goto FailWrite; - } + if (write_empty(f, RESERVED_SECTORS - 2 - BACKUP_BOOT_SECTOR)) + goto FailWrite; + } + else + { + if (write_empty(f, RESERVED_SECTORS - 2)) + goto FailWrite; + } - if (write_sector(f, s_fat_head)) - goto FailWrite; + if (write_sector(f, s_fat_head)) + goto FailWrite; - if (write_empty(f, sectors_per_fat - 1)) - goto FailWrite; + if (write_empty(f, sectors_per_fat - 1)) + goto FailWrite; - if (write_sector(f, s_fat_head)) - goto FailWrite; + if (write_sector(f, s_fat_head)) + goto FailWrite; - if (write_empty(f, sectors_per_fat - 1)) - goto FailWrite; + if (write_empty(f, sectors_per_fat - 1)) + goto FailWrite; - if (write_empty(f, sectors_per_disk - RESERVED_SECTORS - 2*sectors_per_fat)) - goto FailWrite; + if (write_empty(f, sectors_per_disk - RESERVED_SECTORS - 2 * sectors_per_fat)) + goto FailWrite; - return true; + return true; FailWrite: - ERROR_LOG(COMMON, "Could not write to '%s', aborting...\n", filename.c_str()); - if (unlink(filename.c_str()) < 0) - ERROR_LOG(COMMON, "unlink(%s) failed\n%s", filename.c_str(), GetLastErrorMsg().c_str()); - return false; + ERROR_LOG(COMMON, "Could not write to '%s', aborting...\n", filename.c_str()); + if (unlink(filename.c_str()) < 0) + ERROR_LOG(COMMON, "unlink(%s) failed\n%s", filename.c_str(), GetLastErrorMsg().c_str()); + return false; } diff --git a/Source/Core/Common/ScopeGuard.h b/Source/Core/Common/ScopeGuard.h index ab021a178c..d95ef8e4ae 100644 --- a/Source/Core/Common/ScopeGuard.h +++ b/Source/Core/Common/ScopeGuard.h @@ -8,43 +8,36 @@ namespace Common { - class ScopeGuard final { public: - template - ScopeGuard(Callable&& finalizer) : m_finalizer(std::forward(finalizer)) {} + template + ScopeGuard(Callable&& finalizer) : m_finalizer(std::forward(finalizer)) + { + } - ScopeGuard(ScopeGuard&& other) : m_finalizer(std::move(other.m_finalizer)) - { - other.m_finalizer = nullptr; - } + ScopeGuard(ScopeGuard&& other) : m_finalizer(std::move(other.m_finalizer)) + { + other.m_finalizer = nullptr; + } - ~ScopeGuard() - { - Exit(); - } + ~ScopeGuard() { Exit(); } + void Dismiss() { m_finalizer = nullptr; } + void Exit() + { + if (m_finalizer) + { + m_finalizer(); // must not throw + m_finalizer = nullptr; + } + } - void Dismiss() - { - m_finalizer = nullptr; - } + ScopeGuard(const ScopeGuard&) = delete; - void Exit() - { - if (m_finalizer) - { - m_finalizer(); // must not throw - m_finalizer = nullptr; - } - } - - ScopeGuard(const ScopeGuard&) = delete; - - void operator=(const ScopeGuard&) = delete; + void operator=(const ScopeGuard&) = delete; private: - std::function m_finalizer; + std::function m_finalizer; }; } // Namespace Common diff --git a/Source/Core/Common/SettingsHandler.cpp b/Source/Core/Common/SettingsHandler.cpp index 342ab9e03a..a87fc478f5 100644 --- a/Source/Core/Common/SettingsHandler.cpp +++ b/Source/Core/Common/SettingsHandler.cpp @@ -14,7 +14,7 @@ #include #include #include -#include "Common/CommonFuncs.h" // snprintf +#include "Common/CommonFuncs.h" // snprintf #endif #include "Common/CommonTypes.h" @@ -23,105 +23,105 @@ SettingsHandler::SettingsHandler() { - Reset(); + Reset(); } const u8* SettingsHandler::GetData() const { - return m_buffer; + return m_buffer; } const std::string SettingsHandler::GetValue(const std::string& key) { - std::string delim = std::string("\r\n"); - std::string toFind = delim + key + "="; - size_t found = decoded.find(toFind); + std::string delim = std::string("\r\n"); + std::string toFind = delim + key + "="; + size_t found = decoded.find(toFind); - if (found != decoded.npos) - { - size_t delimFound = decoded.find(delim, found + toFind.length()); - if (delimFound == decoded.npos) - delimFound = decoded.length() - 1; - return decoded.substr(found + toFind.length(), delimFound - (found + toFind.length())); - } - else - { - toFind = key + "="; - found = decoded.find(toFind); - if (found == 0) - { - size_t delimFound = decoded.find(delim, found + toFind.length()); - if (delimFound == decoded.npos) - delimFound = decoded.length() - 1; - return decoded.substr(found + toFind.length(), delimFound - (found + toFind.length())); - } - } + if (found != decoded.npos) + { + size_t delimFound = decoded.find(delim, found + toFind.length()); + if (delimFound == decoded.npos) + delimFound = decoded.length() - 1; + return decoded.substr(found + toFind.length(), delimFound - (found + toFind.length())); + } + else + { + toFind = key + "="; + found = decoded.find(toFind); + if (found == 0) + { + size_t delimFound = decoded.find(delim, found + toFind.length()); + if (delimFound == decoded.npos) + delimFound = decoded.length() - 1; + return decoded.substr(found + toFind.length(), delimFound - (found + toFind.length())); + } + } - return ""; + return ""; } void SettingsHandler::Decrypt() { - const u8* str = m_buffer; - while (*str != 0) - { - if (m_position >= SETTINGS_SIZE) - return; - decoded.push_back((u8)(m_buffer[m_position] ^ m_key)); - m_position++; - str++; - m_key = (m_key >> 31) | (m_key << 1); - } + const u8* str = m_buffer; + while (*str != 0) + { + if (m_position >= SETTINGS_SIZE) + return; + decoded.push_back((u8)(m_buffer[m_position] ^ m_key)); + m_position++; + str++; + m_key = (m_key >> 31) | (m_key << 1); + } } void SettingsHandler::Reset() { - decoded = ""; - m_position = 0; - m_key = INITIAL_SEED; - memset(m_buffer, 0, SETTINGS_SIZE); + decoded = ""; + m_position = 0; + m_key = INITIAL_SEED; + memset(m_buffer, 0, SETTINGS_SIZE); } void SettingsHandler::AddSetting(const std::string& key, const std::string& value) { - for (const char& c : key) - { - WriteByte(c); - } + for (const char& c : key) + { + WriteByte(c); + } - WriteByte('='); + WriteByte('='); - for (const char& c : value) - { - WriteByte(c); - } + for (const char& c : value) + { + WriteByte(c); + } - WriteByte(13); - WriteByte(10); + WriteByte(13); + WriteByte(10); } void SettingsHandler::WriteByte(u8 b) { - if (m_position >= SETTINGS_SIZE) - return; + if (m_position >= SETTINGS_SIZE) + return; - m_buffer[m_position] = b ^ m_key; - m_position++; - m_key = (m_key >> 31) | (m_key << 1); + m_buffer[m_position] = b ^ m_key; + m_position++; + m_key = (m_key >> 31) | (m_key << 1); } const std::string SettingsHandler::generateSerialNumber() { - time_t rawtime; - tm* timeinfo; - char buffer[12]; - char serialNumber[12]; + time_t rawtime; + tm* timeinfo; + char buffer[12]; + char serialNumber[12]; - time(&rawtime); - timeinfo = localtime(&rawtime); - strftime(buffer, 11, "%j%H%M%S", timeinfo); + time(&rawtime); + timeinfo = localtime(&rawtime); + strftime(buffer, 11, "%j%H%M%S", timeinfo); - snprintf(serialNumber, 11, "%s%i", buffer, (Common::Timer::GetTimeMs() >> 1) & 0xF); - serialNumber[10] = 0; - return std::string(serialNumber); + snprintf(serialNumber, 11, "%s%i", buffer, (Common::Timer::GetTimeMs() >> 1) & 0xF); + serialNumber[10] = 0; + return std::string(serialNumber); } diff --git a/Source/Core/Common/SettingsHandler.h b/Source/Core/Common/SettingsHandler.h index 5c485d8828..563909d118 100644 --- a/Source/Core/Common/SettingsHandler.h +++ b/Source/Core/Common/SettingsHandler.h @@ -13,28 +13,28 @@ class SettingsHandler { public: - SettingsHandler(); + SettingsHandler(); - enum - { - SETTINGS_SIZE = 0x100, - // Key used to encrypt/decrypt setting.txt contents - INITIAL_SEED = 0x73B5DBFA - }; + enum + { + SETTINGS_SIZE = 0x100, + // Key used to encrypt/decrypt setting.txt contents + INITIAL_SEED = 0x73B5DBFA + }; - void AddSetting(const std::string& key, const std::string& value); + void AddSetting(const std::string& key, const std::string& value); - const u8* GetData() const; - const std::string GetValue(const std::string& key); + const u8* GetData() const; + const std::string GetValue(const std::string& key); - void Decrypt(); - void Reset(); - const std::string generateSerialNumber(); + void Decrypt(); + void Reset(); + const std::string generateSerialNumber(); private: - void WriteByte(u8 b); + void WriteByte(u8 b); - u8 m_buffer[SETTINGS_SIZE]; - u32 m_position, m_key; - std::string decoded; + u8 m_buffer[SETTINGS_SIZE]; + u32 m_position, m_key; + std::string decoded; }; diff --git a/Source/Core/Common/StringUtil.cpp b/Source/Core/Common/StringUtil.cpp index 007da2685a..1e3eab1c4b 100644 --- a/Source/Core/Common/StringUtil.cpp +++ b/Source/Core/Common/StringUtil.cpp @@ -17,197 +17,197 @@ #include "Common/CommonFuncs.h" #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" -#include "Common/StringUtil.h" #include "Common/Logging/Log.h" +#include "Common/StringUtil.h" #ifdef _WIN32 - #include +#include #else - #include - #include - #include +#include +#include +#include #endif #if !defined(_WIN32) && !defined(ANDROID) static locale_t GetCLocale() { - static locale_t c_locale = newlocale(LC_ALL_MASK, "C", nullptr); - return c_locale; + static locale_t c_locale = newlocale(LC_ALL_MASK, "C", nullptr); + return c_locale; } #endif std::string HexDump(const u8* data, size_t size) { - constexpr size_t BYTES_PER_LINE = 16; + constexpr size_t BYTES_PER_LINE = 16; - std::string out; - for (size_t row_start = 0; row_start < size; row_start += BYTES_PER_LINE) - { - out += StringFromFormat("%06zx: ", row_start); - for (size_t i = 0; i < BYTES_PER_LINE; ++i) - { - if (row_start + i < size) - { - out += StringFromFormat("%02hhx ", data[row_start + i]); - } - else - { - out += " "; - } - } - out += " "; - for (size_t i = 0; i < BYTES_PER_LINE; ++i) - { - if (row_start + i < size) - { - char c = static_cast(data[row_start + i]); - out += StringFromFormat("%c", isprint(c) ? c : '.'); - } - } - out += "\n"; - } - return out; + std::string out; + for (size_t row_start = 0; row_start < size; row_start += BYTES_PER_LINE) + { + out += StringFromFormat("%06zx: ", row_start); + for (size_t i = 0; i < BYTES_PER_LINE; ++i) + { + if (row_start + i < size) + { + out += StringFromFormat("%02hhx ", data[row_start + i]); + } + else + { + out += " "; + } + } + out += " "; + for (size_t i = 0; i < BYTES_PER_LINE; ++i) + { + if (row_start + i < size) + { + char c = static_cast(data[row_start + i]); + out += StringFromFormat("%c", isprint(c) ? c : '.'); + } + } + out += "\n"; + } + return out; } // faster than sscanf bool AsciiToHex(const std::string& _szValue, u32& result) { - // Set errno to a good state. - errno = 0; + // Set errno to a good state. + errno = 0; - char* endptr = nullptr; - const u32 value = strtoul(_szValue.c_str(), &endptr, 16); + char* endptr = nullptr; + const u32 value = strtoul(_szValue.c_str(), &endptr, 16); - if (!endptr || *endptr) - return false; + if (!endptr || *endptr) + return false; - if (errno == ERANGE) - return false; + if (errno == ERANGE) + return false; - result = value; - return true; + result = value; + return true; } bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) { - int writtenCount; + int writtenCount; #ifdef _WIN32 - // You would think *printf are simple, right? Iterate on each character, - // if it's a format specifier handle it properly, etc. - // - // Nooooo. Not according to the C standard. - // - // According to the C99 standard (7.19.6.1 "The fprintf function") - // The format shall be a multibyte character sequence - // - // Because some character encodings might have '%' signs in the middle of - // a multibyte sequence (SJIS for example only specifies that the first - // byte of a 2 byte sequence is "high", the second byte can be anything), - // printf functions have to decode the multibyte sequences and try their - // best to not screw up. - // - // Unfortunately, on Windows, the locale for most languages is not UTF-8 - // as we would need. Notably, for zh_TW, Windows chooses EUC-CN as the - // locale, and completely fails when trying to decode UTF-8 as EUC-CN. - // - // On the other hand, the fix is simple: because we use UTF-8, no such - // multibyte handling is required as we can simply assume that no '%' char - // will be present in the middle of a multibyte sequence. - // - // This is why we look up the default C locale here and use _vsnprintf_l. - static _locale_t c_locale = nullptr; - if (!c_locale) - c_locale = _create_locale(LC_ALL, "C"); - writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args); + // You would think *printf are simple, right? Iterate on each character, + // if it's a format specifier handle it properly, etc. + // + // Nooooo. Not according to the C standard. + // + // According to the C99 standard (7.19.6.1 "The fprintf function") + // The format shall be a multibyte character sequence + // + // Because some character encodings might have '%' signs in the middle of + // a multibyte sequence (SJIS for example only specifies that the first + // byte of a 2 byte sequence is "high", the second byte can be anything), + // printf functions have to decode the multibyte sequences and try their + // best to not screw up. + // + // Unfortunately, on Windows, the locale for most languages is not UTF-8 + // as we would need. Notably, for zh_TW, Windows chooses EUC-CN as the + // locale, and completely fails when trying to decode UTF-8 as EUC-CN. + // + // On the other hand, the fix is simple: because we use UTF-8, no such + // multibyte handling is required as we can simply assume that no '%' char + // will be present in the middle of a multibyte sequence. + // + // This is why we look up the default C locale here and use _vsnprintf_l. + static _locale_t c_locale = nullptr; + if (!c_locale) + c_locale = _create_locale(LC_ALL, "C"); + writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args); #else - #if !defined(ANDROID) - locale_t previousLocale = uselocale(GetCLocale()); - #endif - writtenCount = vsnprintf(out, outsize, format, args); - #if !defined(ANDROID) - uselocale(previousLocale); - #endif +#if !defined(ANDROID) + locale_t previousLocale = uselocale(GetCLocale()); +#endif + writtenCount = vsnprintf(out, outsize, format, args); +#if !defined(ANDROID) + uselocale(previousLocale); +#endif #endif - if (writtenCount > 0 && writtenCount < outsize) - { - out[writtenCount] = '\0'; - return true; - } - else - { - out[outsize - 1] = '\0'; - return false; - } + if (writtenCount > 0 && writtenCount < outsize) + { + out[writtenCount] = '\0'; + return true; + } + else + { + out[outsize - 1] = '\0'; + return false; + } } std::string StringFromFormat(const char* format, ...) { - va_list args; - va_start(args, format); - std::string res = StringFromFormatV(format, args); - va_end(args); - return res; + va_list args; + va_start(args, format); + std::string res = StringFromFormatV(format, args); + va_end(args); + return res; } std::string StringFromFormatV(const char* format, va_list args) { - char* buf = nullptr; + char* buf = nullptr; #ifdef _WIN32 - int required = _vscprintf(format, args); - buf = new char[required + 1]; - CharArrayFromFormatV(buf, required + 1, format, args); + int required = _vscprintf(format, args); + buf = new char[required + 1]; + CharArrayFromFormatV(buf, required + 1, format, args); - std::string temp = buf; - delete[] buf; + std::string temp = buf; + delete[] buf; #else - #if !defined(ANDROID) - locale_t previousLocale = uselocale(GetCLocale()); - #endif - if (vasprintf(&buf, format, args) < 0) - ERROR_LOG(COMMON, "Unable to allocate memory for string"); - #if !defined(ANDROID) - uselocale(previousLocale); - #endif - - std::string temp = buf; - free(buf); +#if !defined(ANDROID) + locale_t previousLocale = uselocale(GetCLocale()); #endif - return temp; + if (vasprintf(&buf, format, args) < 0) + ERROR_LOG(COMMON, "Unable to allocate memory for string"); +#if !defined(ANDROID) + uselocale(previousLocale); +#endif + + std::string temp = buf; + free(buf); +#endif + return temp; } // For Debugging. Read out an u8 array. std::string ArrayToString(const u8* data, u32 size, int line_len, bool spaces) { - std::ostringstream oss; - oss << std::setfill('0') << std::hex; + std::ostringstream oss; + oss << std::setfill('0') << std::hex; - for (int line = 0; size; ++data, --size) - { - oss << std::setw(2) << (int)*data; + for (int line = 0; size; ++data, --size) + { + oss << std::setw(2) << (int)*data; - if (line_len == ++line) - { - oss << '\n'; - line = 0; - } - else if (spaces) - oss << ' '; - } + if (line_len == ++line) + { + oss << '\n'; + line = 0; + } + else if (spaces) + oss << ' '; + } - return oss.str(); + return oss.str(); } // Turns " hej " into "hej". Also handles tabs. std::string StripSpaces(const std::string& str) { - const size_t s = str.find_first_not_of(" \t\r\n"); + const size_t s = str.find_first_not_of(" \t\r\n"); - if (str.npos != s) - return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1); - else - return ""; + if (str.npos != s) + return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1); + else + return ""; } // "\"hello\"" is turned to "hello" @@ -215,189 +215,195 @@ std::string StripSpaces(const std::string& str) // ends, as done by StripSpaces above, for example. std::string StripQuotes(const std::string& s) { - if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) - return s.substr(1, s.size() - 2); - else - return s; + if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) + return s.substr(1, s.size() - 2); + else + return s; } bool TryParse(const std::string& str, u32* const output) { - char* endptr = nullptr; + char* endptr = nullptr; - // Reset errno to a value other than ERANGE - errno = 0; + // Reset errno to a value other than ERANGE + errno = 0; - unsigned long value = strtoul(str.c_str(), &endptr, 0); + unsigned long value = strtoul(str.c_str(), &endptr, 0); - if (!endptr || *endptr) - return false; + if (!endptr || *endptr) + return false; - if (errno == ERANGE) - return false; + if (errno == ERANGE) + return false; #if ULONG_MAX > UINT_MAX - if (value >= 0x100000000ull && - value <= 0xFFFFFFFF00000000ull) - return false; + if (value >= 0x100000000ull && value <= 0xFFFFFFFF00000000ull) + return false; #endif - *output = static_cast(value); - return true; + *output = static_cast(value); + return true; } bool TryParse(const std::string& str, bool* const output) { - if ("1" == str || !strcasecmp("true", str.c_str())) - *output = true; - else if ("0" == str || !strcasecmp("false", str.c_str())) - *output = false; - else - return false; + if ("1" == str || !strcasecmp("true", str.c_str())) + *output = true; + else if ("0" == str || !strcasecmp("false", str.c_str())) + *output = false; + else + return false; - return true; + return true; } std::string StringFromInt(int value) { - char temp[16]; - sprintf(temp, "%i", value); - return temp; + char temp[16]; + sprintf(temp, "%i", value); + return temp; } std::string StringFromBool(bool value) { - return value ? "True" : "False"; + return value ? "True" : "False"; } -bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension) +bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, + std::string* _pExtension) { - if (full_path.empty()) - return false; + if (full_path.empty()) + return false; - size_t dir_end = full_path.find_last_of("/" - // Windows needs the : included for something like just "C:" to be considered a directory + size_t dir_end = full_path.find_last_of("/" +// Windows needs the : included for something like just "C:" to be considered a directory #ifdef _WIN32 - ":" + ":" #endif - ); - if (std::string::npos == dir_end) - dir_end = 0; - else - dir_end += 1; + ); + if (std::string::npos == dir_end) + dir_end = 0; + else + dir_end += 1; - size_t fname_end = full_path.rfind('.'); - if (fname_end < dir_end || std::string::npos == fname_end) - fname_end = full_path.size(); + size_t fname_end = full_path.rfind('.'); + if (fname_end < dir_end || std::string::npos == fname_end) + fname_end = full_path.size(); - if (_pPath) - *_pPath = full_path.substr(0, dir_end); + if (_pPath) + *_pPath = full_path.substr(0, dir_end); - if (_pFilename) - *_pFilename = full_path.substr(dir_end, fname_end - dir_end); + if (_pFilename) + *_pFilename = full_path.substr(dir_end, fname_end - dir_end); - if (_pExtension) - *_pExtension = full_path.substr(fname_end); + if (_pExtension) + *_pExtension = full_path.substr(fname_end); - return true; + return true; } -void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename) +void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, + const std::string& _Filename) { - _CompleteFilename = _Path; + _CompleteFilename = _Path; - // check for seperator - if (DIR_SEP_CHR != *_CompleteFilename.rbegin()) - _CompleteFilename += DIR_SEP_CHR; + // check for seperator + if (DIR_SEP_CHR != *_CompleteFilename.rbegin()) + _CompleteFilename += DIR_SEP_CHR; - // add the filename - _CompleteFilename += _Filename; + // add the filename + _CompleteFilename += _Filename; } void SplitString(const std::string& str, const char delim, std::vector& output) { - std::istringstream iss(str); - output.resize(1); + std::istringstream iss(str); + output.resize(1); - while (std::getline(iss, *output.rbegin(), delim)) - output.push_back(""); + while (std::getline(iss, *output.rbegin(), delim)) + output.push_back(""); - output.pop_back(); + output.pop_back(); } std::string TabsToSpaces(int tab_size, const std::string& in) { - const std::string spaces(tab_size, ' '); - std::string out(in); + const std::string spaces(tab_size, ' '); + std::string out(in); - size_t i = 0; - while (out.npos != (i = out.find('\t'))) - out.replace(i, 1, spaces); + size_t i = 0; + while (out.npos != (i = out.find('\t'))) + out.replace(i, 1, spaces); - return out; + return out; } std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) { - size_t pos = 0; + size_t pos = 0; - if (src == dest) - return result; + if (src == dest) + return result; - while ((pos = result.find(src, pos)) != std::string::npos) - { - result.replace(pos, src.size(), dest); - pos += dest.length(); - } + while ((pos = result.find(src, pos)) != std::string::npos) + { + result.replace(pos, src.size(), dest); + pos += dest.length(); + } - return result; + return result; } #ifdef _WIN32 std::string UTF16ToUTF8(const std::wstring& input) { - auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), (int)input.size(), nullptr, 0, nullptr, nullptr); + auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), (int)input.size(), nullptr, 0, + nullptr, nullptr); - std::string output; - output.resize(size); + std::string output; + output.resize(size); - if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), (int)input.size(), &output[0], (int)output.size(), nullptr, nullptr)) - { - output.clear(); - } + if (size == 0 || + size != WideCharToMultiByte(CP_UTF8, 0, input.data(), (int)input.size(), &output[0], + (int)output.size(), nullptr, nullptr)) + { + output.clear(); + } - return output; + return output; } std::wstring CPToUTF16(u32 code_page, const std::string& input) { - auto const size = MultiByteToWideChar(code_page, 0, input.data(), (int)input.size(), nullptr, 0); + auto const size = MultiByteToWideChar(code_page, 0, input.data(), (int)input.size(), nullptr, 0); - std::wstring output; - output.resize(size); + std::wstring output; + output.resize(size); - if (size == 0 || size != MultiByteToWideChar(code_page, 0, input.data(), (int)input.size(), &output[0], (int)output.size())) - { - output.clear(); - } + if (size == 0 || + size != MultiByteToWideChar(code_page, 0, input.data(), (int)input.size(), &output[0], + (int)output.size())) + { + output.clear(); + } - return output; + return output; } std::wstring UTF8ToUTF16(const std::string& input) { - return CPToUTF16(CP_UTF8, input); + return CPToUTF16(CP_UTF8, input); } std::string SHIFTJISToUTF8(const std::string& input) { - return UTF16ToUTF8(CPToUTF16(932, input)); + return UTF16ToUTF8(CPToUTF16(932, input)); } std::string CP1252ToUTF8(const std::string& input) { - return UTF16ToUTF8(CPToUTF16(1252, input)); + return UTF16ToUTF8(CPToUTF16(1252, input)); } #else @@ -405,79 +411,79 @@ std::string CP1252ToUTF8(const std::string& input) template std::string CodeToUTF8(const char* fromcode, const std::basic_string& input) { - std::string result; + std::string result; - iconv_t const conv_desc = iconv_open("UTF-8", fromcode); - if ((iconv_t)-1 == conv_desc) - { - ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); - } - else - { - size_t const in_bytes = sizeof(T) * input.size(); - size_t const out_buffer_size = 4 * in_bytes; + iconv_t const conv_desc = iconv_open("UTF-8", fromcode); + if ((iconv_t)-1 == conv_desc) + { + ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); + } + else + { + size_t const in_bytes = sizeof(T) * input.size(); + size_t const out_buffer_size = 4 * in_bytes; - std::string out_buffer; - out_buffer.resize(out_buffer_size); + std::string out_buffer; + out_buffer.resize(out_buffer_size); - auto src_buffer = &input[0]; - size_t src_bytes = in_bytes; - auto dst_buffer = &out_buffer[0]; - size_t dst_bytes = out_buffer.size(); + auto src_buffer = &input[0]; + size_t src_bytes = in_bytes; + auto dst_buffer = &out_buffer[0]; + size_t dst_bytes = out_buffer.size(); - while (src_bytes != 0) - { - size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes, - &dst_buffer, &dst_bytes); + while (src_bytes != 0) + { + size_t const iconv_result = + iconv(conv_desc, (char**)(&src_buffer), &src_bytes, &dst_buffer, &dst_bytes); - if ((size_t)-1 == iconv_result) - { - if (EILSEQ == errno || EINVAL == errno) - { - // Try to skip the bad character - if (src_bytes != 0) - { - --src_bytes; - ++src_buffer; - } - } - else - { - ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno)); - break; - } - } - } + if ((size_t)-1 == iconv_result) + { + if (EILSEQ == errno || EINVAL == errno) + { + // Try to skip the bad character + if (src_bytes != 0) + { + --src_bytes; + ++src_buffer; + } + } + else + { + ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno)); + break; + } + } + } - out_buffer.resize(out_buffer_size - dst_bytes); - out_buffer.swap(result); + out_buffer.resize(out_buffer_size - dst_bytes); + out_buffer.swap(result); - iconv_close(conv_desc); - } + iconv_close(conv_desc); + } - return result; + return result; } std::string CP1252ToUTF8(const std::string& input) { - //return CodeToUTF8("CP1252//TRANSLIT", input); - //return CodeToUTF8("CP1252//IGNORE", input); - return CodeToUTF8("CP1252", input); + // return CodeToUTF8("CP1252//TRANSLIT", input); + // return CodeToUTF8("CP1252//IGNORE", input); + return CodeToUTF8("CP1252", input); } std::string SHIFTJISToUTF8(const std::string& input) { - //return CodeToUTF8("CP932", input); - return CodeToUTF8("SJIS", input); + // return CodeToUTF8("CP932", input); + return CodeToUTF8("SJIS", input); } std::string UTF16ToUTF8(const std::wstring& input) { - std::string result = CodeToUTF8("UTF-16LE", input); + std::string result = CodeToUTF8("UTF-16LE", input); - // TODO: why is this needed? - result.erase(std::remove(result.begin(), result.end(), 0x00), result.end()); - return result; + // TODO: why is this needed? + result.erase(std::remove(result.begin(), result.end(), 0x00), result.end()); + return result; } #endif diff --git a/Source/Core/Common/StringUtil.h b/Source/Core/Common/StringUtil.h index 2c91a9a252..7e4c598d0d 100644 --- a/Source/Core/Common/StringUtil.h +++ b/Source/Core/Common/StringUtil.h @@ -17,22 +17,22 @@ std::string StringFromFormatV(const char* format, va_list args); std::string StringFromFormat(const char* format, ...) #if !defined _WIN32 -// On compilers that support function attributes, this gives StringFromFormat -// the same errors and warnings that printf would give. - __attribute__ ((__format__(printf, 1, 2))) + // On compilers that support function attributes, this gives StringFromFormat + // the same errors and warnings that printf would give. + __attribute__((__format__(printf, 1, 2))) #endif -; + ; // Cheap! bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args); -template -inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...) +template +inline void CharArrayFromFormat(char (&out)[Count], const char* format, ...) { - va_list args; - va_start(args, format); - CharArrayFromFormatV(out, Count, format, args); - va_end(args); + va_list args; + va_start(args, format); + CharArrayFromFormatV(out, Count, format, args); + va_end(args); } // Good @@ -45,15 +45,15 @@ std::string StripQuotes(const std::string& s); template std::string ThousandSeparate(I value, int spaces = 0) { - std::ostringstream oss; + std::ostringstream oss; // std::locale("") seems to be broken on many platforms #if defined _WIN32 || (defined __linux__ && !defined __clang__) - oss.imbue(std::locale("")); + oss.imbue(std::locale("")); #endif - oss << std::setw(spaces) << value; + oss << std::setw(spaces) << value; - return oss.str(); + return oss.str(); } std::string StringFromInt(int value); @@ -65,35 +65,36 @@ bool TryParse(const std::string& str, u32* output); template static bool TryParse(const std::string& str, N* const output) { - std::istringstream iss(str); - // is this right? not doing this breaks reading floats on locales that use different decimal separators - iss.imbue(std::locale("C")); + std::istringstream iss(str); + // is this right? not doing this breaks reading floats on locales that use different decimal + // separators + iss.imbue(std::locale("C")); - N tmp = 0; - if (iss >> tmp) - { - *output = tmp; - return true; - } - else - return false; + N tmp = 0; + if (iss >> tmp) + { + *output = tmp; + return true; + } + else + return false; } template bool TryParseVector(const std::string& str, std::vector* output, const char delimiter = ',') { - output->clear(); - std::istringstream buffer(str); - std::string variable; + output->clear(); + std::istringstream buffer(str); + std::string variable; - while (std::getline(buffer, variable, delimiter)) - { - N tmp = 0; - if (!TryParse(variable, &tmp)) - return false; - output->push_back(tmp); - } - return true; + while (std::getline(buffer, variable, delimiter)) + { + N tmp = 0; + if (!TryParse(variable, &tmp)) + return false; + output->push_back(tmp); + } + return true; } // Generates an hexdump-like representation of a binary data blob. @@ -107,9 +108,11 @@ std::string TabsToSpaces(int tab_size, const std::string& in); void SplitString(const std::string& str, char delim, std::vector& output); // "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe" -bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension); +bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, + std::string* _pExtension); -void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename); +void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, + const std::string& _Filename); std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest); std::string CP1252ToUTF8(const std::string& str); @@ -122,16 +125,24 @@ std::wstring UTF8ToUTF16(const std::string& str); #ifdef _UNICODE inline std::string TStrToUTF8(const std::wstring& str) -{ return UTF16ToUTF8(str); } +{ + return UTF16ToUTF8(str); +} inline std::wstring UTF8ToTStr(const std::string& str) -{ return UTF8ToUTF16(str); } +{ + return UTF8ToUTF16(str); +} #else inline std::string TStrToUTF8(const std::string& str) -{ return str; } +{ + return str; +} inline std::string UTF8ToTStr(const std::string& str) -{ return str; } +{ + return str; +} #endif #endif diff --git a/Source/Core/Common/SymbolDB.cpp b/Source/Core/Common/SymbolDB.cpp index c4abe0bd26..6b6f72d33e 100644 --- a/Source/Core/Common/SymbolDB.cpp +++ b/Source/Core/Common/SymbolDB.cpp @@ -8,49 +8,47 @@ #include #include "Common/CommonTypes.h" -#include "Common/SymbolDB.h" #include "Common/Logging/Log.h" +#include "Common/SymbolDB.h" void SymbolDB::List() { - for (const auto& func : functions) - { - DEBUG_LOG(OSHLE, "%s @ %08x: %i bytes (hash %08x) : %i calls", - func.second.name.c_str(), func.second.address, - func.second.size, func.second.hash, - func.second.numCalls); - } - INFO_LOG(OSHLE, "%zu functions known in this program above.", functions.size()); + for (const auto& func : functions) + { + DEBUG_LOG(OSHLE, "%s @ %08x: %i bytes (hash %08x) : %i calls", func.second.name.c_str(), + func.second.address, func.second.size, func.second.hash, func.second.numCalls); + } + INFO_LOG(OSHLE, "%zu functions known in this program above.", functions.size()); } void SymbolDB::Clear(const char* prefix) { - // TODO: honor prefix - functions.clear(); - checksumToFunction.clear(); + // TODO: honor prefix + functions.clear(); + checksumToFunction.clear(); } void SymbolDB::Index() { - int i = 0; - for (auto& func : functions) - { - func.second.index = i++; - } + int i = 0; + for (auto& func : functions) + { + func.second.index = i++; + } } Symbol* SymbolDB::GetSymbolFromName(const std::string& name) { - for (auto& func : functions) - { - if (func.second.name == name) - return &func.second; - } + for (auto& func : functions) + { + if (func.second.name == name) + return &func.second; + } - return nullptr; + return nullptr; } void SymbolDB::AddCompleteSymbol(const Symbol& symbol) { - functions.emplace(symbol.address, symbol); + functions.emplace(symbol.address, symbol); } diff --git a/Source/Core/Common/SymbolDB.h b/Source/Core/Common/SymbolDB.h index 8d8f323fdb..c80dfcd7a9 100644 --- a/Source/Core/Common/SymbolDB.h +++ b/Source/Core/Common/SymbolDB.h @@ -16,88 +16,76 @@ struct SCall { - SCall(u32 a, u32 b) : - function(a), - callAddress(b) - {} - u32 function; - u32 callAddress; + SCall(u32 a, u32 b) : function(a), callAddress(b) {} + u32 function; + u32 callAddress; }; struct Symbol { - enum { - SYMBOL_FUNCTION = 0, - SYMBOL_DATA = 1, - }; + enum + { + SYMBOL_FUNCTION = 0, + SYMBOL_DATA = 1, + }; - Symbol() : - hash(0), - address(0), - flags(0), - size(0), - numCalls(0), - type(SYMBOL_FUNCTION), - analyzed(0) - {} + Symbol() : hash(0), address(0), flags(0), size(0), numCalls(0), type(SYMBOL_FUNCTION), analyzed(0) + { + } - std::string name; - std::vector callers; //addresses of functions that call this function - std::vector calls; //addresses of functions that are called by this function - u32 hash; //use for HLE function finding - u32 address; - u32 flags; - int size; - int numCalls; - int type; - int index; // only used for coloring the disasm view - int analyzed; + std::string name; + std::vector callers; // addresses of functions that call this function + std::vector calls; // addresses of functions that are called by this function + u32 hash; // use for HLE function finding + u32 address; + u32 flags; + int size; + int numCalls; + int type; + int index; // only used for coloring the disasm view + int analyzed; }; enum { - FFLAG_TIMERINSTRUCTIONS = (1<<0), - FFLAG_LEAF = (1<<1), - FFLAG_ONLYCALLSNICELEAFS = (1<<2), - FFLAG_EVIL = (1<<3), - FFLAG_RFI = (1<<4), - FFLAG_STRAIGHT = (1<<5) + FFLAG_TIMERINSTRUCTIONS = (1 << 0), + FFLAG_LEAF = (1 << 1), + FFLAG_ONLYCALLSNICELEAFS = (1 << 2), + FFLAG_EVIL = (1 << 3), + FFLAG_RFI = (1 << 4), + FFLAG_STRAIGHT = (1 << 5) }; - - class SymbolDB { public: - typedef std::map XFuncMap; - typedef std::map XFuncPtrMap; + typedef std::map XFuncMap; + typedef std::map XFuncPtrMap; protected: - XFuncMap functions; - XFuncPtrMap checksumToFunction; + XFuncMap functions; + XFuncPtrMap checksumToFunction; public: - SymbolDB() {} - virtual ~SymbolDB() {} - virtual Symbol* GetSymbolFromAddr(u32 addr) { return nullptr; } - virtual Symbol* AddFunction(u32 startAddr) { return nullptr; } + SymbolDB() {} + virtual ~SymbolDB() {} + virtual Symbol* GetSymbolFromAddr(u32 addr) { return nullptr; } + virtual Symbol* AddFunction(u32 startAddr) { return nullptr; } + void AddCompleteSymbol(const Symbol& symbol); - void AddCompleteSymbol(const Symbol& symbol); + Symbol* GetSymbolFromName(const std::string& name); + Symbol* GetSymbolFromHash(u32 hash) + { + XFuncPtrMap::iterator iter = checksumToFunction.find(hash); + if (iter != checksumToFunction.end()) + return iter->second; + else + return nullptr; + } - Symbol* GetSymbolFromName(const std::string& name); - Symbol* GetSymbolFromHash(u32 hash) - { - XFuncPtrMap::iterator iter = checksumToFunction.find(hash); - if (iter != checksumToFunction.end()) - return iter->second; - else - return nullptr; - } - - const XFuncMap& Symbols() const { return functions; } - XFuncMap& AccessSymbols() { return functions; } - - void Clear(const char* prefix = ""); - void List(); - void Index(); + const XFuncMap& Symbols() const { return functions; } + XFuncMap& AccessSymbols() { return functions; } + void Clear(const char* prefix = ""); + void List(); + void Index(); }; diff --git a/Source/Core/Common/SysConf.cpp b/Source/Core/Common/SysConf.cpp index a50efeb71b..9ad5894eba 100644 --- a/Source/Core/Common/SysConf.cpp +++ b/Source/Core/Common/SysConf.cpp @@ -12,432 +12,435 @@ #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/SysConf.h" #include "Common/Logging/Log.h" +#include "Common/SysConf.h" #include "Core/Movie.h" -SysConf::SysConf() - : m_IsValid(false) +SysConf::SysConf() : m_IsValid(false) { - UpdateLocation(); + UpdateLocation(); } SysConf::~SysConf() { - if (!m_IsValid) - return; + if (!m_IsValid) + return; - Save(); - Clear(); + Save(); + Clear(); } void SysConf::Clear() { - for (auto i = m_Entries.begin(); i < m_Entries.end() - 1; ++i) - delete [] i->data; + for (auto i = m_Entries.begin(); i < m_Entries.end() - 1; ++i) + delete[] i->data; - m_Entries.clear(); + m_Entries.clear(); } bool SysConf::LoadFromFile(const std::string& filename) { - if (m_IsValid) - Clear(); - m_IsValid = false; + if (m_IsValid) + Clear(); + m_IsValid = false; - // Basic check - if (!File::Exists(filename)) - { - File::CreateFullPath(filename); - GenerateSysConf(); - return true; - } + // Basic check + if (!File::Exists(filename)) + { + File::CreateFullPath(filename); + GenerateSysConf(); + return true; + } - u64 size = File::GetSize(filename); - if (size != SYSCONF_SIZE) - { - if (AskYesNoT("Your SYSCONF file is the wrong size.\nIt should be 0x%04x (but is 0x%04" PRIx64 ")\nDo you want to generate a new one?", - SYSCONF_SIZE, size)) - { - GenerateSysConf(); - return true; - } - else - { - return false; - } - } + u64 size = File::GetSize(filename); + if (size != SYSCONF_SIZE) + { + if (AskYesNoT("Your SYSCONF file is the wrong size.\nIt should be 0x%04x (but is 0x%04" PRIx64 + ")\nDo you want to generate a new one?", + SYSCONF_SIZE, size)) + { + GenerateSysConf(); + return true; + } + else + { + return false; + } + } - File::IOFile f(filename, "rb"); - if (f.IsOpen()) - { - if (LoadFromFileInternal(f.ReleaseHandle())) - { - m_Filename = filename; - m_IsValid = true; - // Apply Wii settings from normal SYSCONF on Movie recording/playback - if (Movie::IsRecordingInput() || Movie::IsPlayingInput()) - { - SetData("IPL.LNG", Movie::GetLanguage()); - SetData("IPL.E60", Movie::IsPAL60()); - SetData("IPL.PGS", Movie::IsProgressive()); - } - return true; - } - } + File::IOFile f(filename, "rb"); + if (f.IsOpen()) + { + if (LoadFromFileInternal(f.ReleaseHandle())) + { + m_Filename = filename; + m_IsValid = true; + // Apply Wii settings from normal SYSCONF on Movie recording/playback + if (Movie::IsRecordingInput() || Movie::IsPlayingInput()) + { + SetData("IPL.LNG", Movie::GetLanguage()); + SetData("IPL.E60", Movie::IsPAL60()); + SetData("IPL.PGS", Movie::IsProgressive()); + } + return true; + } + } - return false; + return false; } bool SysConf::LoadFromFileInternal(FILE* fh) { - File::IOFile f(fh); - // Fill in infos - SSysConfHeader s_Header; - f.ReadArray(s_Header.version, 4); - f.ReadArray(&s_Header.numEntries, 1); - s_Header.numEntries = Common::swap16(s_Header.numEntries) + 1; + File::IOFile f(fh); + // Fill in infos + SSysConfHeader s_Header; + f.ReadArray(s_Header.version, 4); + f.ReadArray(&s_Header.numEntries, 1); + s_Header.numEntries = Common::swap16(s_Header.numEntries) + 1; - for (u16 index = 0; index < s_Header.numEntries; index++) - { - SSysConfEntry tmpEntry; - f.ReadArray(&tmpEntry.offset, 1); - tmpEntry.offset = Common::swap16(tmpEntry.offset); - m_Entries.push_back(tmpEntry); - } + for (u16 index = 0; index < s_Header.numEntries; index++) + { + SSysConfEntry tmpEntry; + f.ReadArray(&tmpEntry.offset, 1); + tmpEntry.offset = Common::swap16(tmpEntry.offset); + m_Entries.push_back(tmpEntry); + } - // Last offset is an invalid entry. We ignore it throughout this class - for (auto i = m_Entries.begin(); i < m_Entries.end() - 1; ++i) - { - SSysConfEntry& curEntry = *i; - f.Seek(curEntry.offset, SEEK_SET); + // Last offset is an invalid entry. We ignore it throughout this class + for (auto i = m_Entries.begin(); i < m_Entries.end() - 1; ++i) + { + SSysConfEntry& curEntry = *i; + f.Seek(curEntry.offset, SEEK_SET); - u8 description = 0; - f.ReadArray(&description, 1); - // Data type - curEntry.type = (SysconfType)((description & 0xe0) >> 5); - // Length of name in bytes - 1 - curEntry.nameLength = (description & 0x1f) + 1; - // Name - f.ReadArray(curEntry.name, curEntry.nameLength); - curEntry.name[curEntry.nameLength] = '\0'; - // Get length of data - curEntry.data = nullptr; - curEntry.dataLength = 0; - switch (curEntry.type) - { - case Type_BigArray: - f.ReadArray(&curEntry.dataLength, 1); - curEntry.dataLength = Common::swap16(curEntry.dataLength); - break; + u8 description = 0; + f.ReadArray(&description, 1); + // Data type + curEntry.type = (SysconfType)((description & 0xe0) >> 5); + // Length of name in bytes - 1 + curEntry.nameLength = (description & 0x1f) + 1; + // Name + f.ReadArray(curEntry.name, curEntry.nameLength); + curEntry.name[curEntry.nameLength] = '\0'; + // Get length of data + curEntry.data = nullptr; + curEntry.dataLength = 0; + switch (curEntry.type) + { + case Type_BigArray: + f.ReadArray(&curEntry.dataLength, 1); + curEntry.dataLength = Common::swap16(curEntry.dataLength); + break; - case Type_SmallArray: - { - u8 dlength = 0; - f.ReadBytes(&dlength, 1); - curEntry.dataLength = dlength; - break; - } + case Type_SmallArray: + { + u8 dlength = 0; + f.ReadBytes(&dlength, 1); + curEntry.dataLength = dlength; + break; + } - case Type_Byte: - case Type_Bool: - curEntry.dataLength = 1; - break; + case Type_Byte: + case Type_Bool: + curEntry.dataLength = 1; + break; - case Type_Short: - curEntry.dataLength = 2; - break; + case Type_Short: + curEntry.dataLength = 2; + break; - case Type_Long: - curEntry.dataLength = 4; - break; + case Type_Long: + curEntry.dataLength = 4; + break; - default: - PanicAlertT("Unknown entry type %i in SYSCONF (%s@%x)!", - curEntry.type, curEntry.name, curEntry.offset); - return false; - break; - } - // Fill in the actual data - if (curEntry.dataLength) - { - curEntry.data = new u8[curEntry.dataLength]; - f.ReadArray(curEntry.data, curEntry.dataLength); - } - } + default: + PanicAlertT("Unknown entry type %i in SYSCONF (%s@%x)!", curEntry.type, curEntry.name, + curEntry.offset); + return false; + break; + } + // Fill in the actual data + if (curEntry.dataLength) + { + curEntry.data = new u8[curEntry.dataLength]; + f.ReadArray(curEntry.data, curEntry.dataLength); + } + } - return f.IsGood(); + return f.IsGood(); } // Returns the size of the item in file static unsigned int create_item(SSysConfEntry& item, SysconfType type, const std::string& name, - const int data_length, unsigned int offset) + const int data_length, unsigned int offset) { - item.offset = offset; - item.type = type; - item.nameLength = (u8)(name.length()); - strncpy(item.name, name.c_str(), 32); - item.dataLength = data_length; - item.data = new u8[data_length]; - memset(item.data, 0, data_length); - switch (type) - { - case Type_BigArray: - // size of description + name length + size of dataLength + data length + null - return 1 + item.nameLength + 2 + item.dataLength + 1; - case Type_SmallArray: - // size of description + name length + size of dataLength + data length + null - return 1 + item.nameLength + 1 + item.dataLength + 1; - case Type_Byte: - case Type_Bool: - case Type_Short: - case Type_Long: - // size of description + name length + data length - return 1 + item.nameLength + item.dataLength; - default: - return 0; - } + item.offset = offset; + item.type = type; + item.nameLength = (u8)(name.length()); + strncpy(item.name, name.c_str(), 32); + item.dataLength = data_length; + item.data = new u8[data_length]; + memset(item.data, 0, data_length); + switch (type) + { + case Type_BigArray: + // size of description + name length + size of dataLength + data length + null + return 1 + item.nameLength + 2 + item.dataLength + 1; + case Type_SmallArray: + // size of description + name length + size of dataLength + data length + null + return 1 + item.nameLength + 1 + item.dataLength + 1; + case Type_Byte: + case Type_Bool: + case Type_Short: + case Type_Long: + // size of description + name length + data length + return 1 + item.nameLength + item.dataLength; + default: + return 0; + } } void SysConf::GenerateSysConf() { - SSysConfHeader s_Header; - strncpy(s_Header.version, "SCv0", 4); - s_Header.numEntries = Common::swap16(28 - 1); + SSysConfHeader s_Header; + strncpy(s_Header.version, "SCv0", 4); + s_Header.numEntries = Common::swap16(28 - 1); - SSysConfEntry items[27]; - memset(items, 0, sizeof(SSysConfEntry) * 27); + SSysConfEntry items[27]; + memset(items, 0, sizeof(SSysConfEntry) * 27); - // version length + size of numEntries + 28 * size of offset - unsigned int current_offset = 4 + 2 + 28 * 2; + // version length + size of numEntries + 28 * size of offset + unsigned int current_offset = 4 + 2 + 28 * 2; - // BT.DINF - current_offset += create_item(items[0], Type_BigArray, "BT.DINF", 0x460, current_offset); - items[0].data[0] = 4; - for (u8 i = 0; i < 4; ++i) - { - const u8 bt_addr[6] = {i, 0x00, 0x79, 0x19, 0x02, 0x11}; - memcpy(&items[0].data[1 + 70 * i], bt_addr, sizeof(bt_addr)); - memcpy(&items[0].data[7 + 70 * i], "Nintendo RVL-CNT-01", 19); - } + // BT.DINF + current_offset += create_item(items[0], Type_BigArray, "BT.DINF", 0x460, current_offset); + items[0].data[0] = 4; + for (u8 i = 0; i < 4; ++i) + { + const u8 bt_addr[6] = {i, 0x00, 0x79, 0x19, 0x02, 0x11}; + memcpy(&items[0].data[1 + 70 * i], bt_addr, sizeof(bt_addr)); + memcpy(&items[0].data[7 + 70 * i], "Nintendo RVL-CNT-01", 19); + } - // BT.SENS - current_offset += create_item(items[1], Type_Long, "BT.SENS", 4, current_offset); - items[1].data[3] = 0x03; + // BT.SENS + current_offset += create_item(items[1], Type_Long, "BT.SENS", 4, current_offset); + items[1].data[3] = 0x03; - // IPL.NIK - current_offset += create_item(items[2], Type_SmallArray, "IPL.NIK", 0x15, current_offset); - const u8 console_nick[14] = {0, 'd', 0, 'o', 0, 'l', 0, 'p', 0, 'h', 0, 'i', 0, 'n'}; - memcpy(items[2].data, console_nick, 14); + // IPL.NIK + current_offset += create_item(items[2], Type_SmallArray, "IPL.NIK", 0x15, current_offset); + const u8 console_nick[14] = {0, 'd', 0, 'o', 0, 'l', 0, 'p', 0, 'h', 0, 'i', 0, 'n'}; + memcpy(items[2].data, console_nick, 14); - // IPL.AR - current_offset += create_item(items[3], Type_Byte, "IPL.AR", 1, current_offset); - items[3].data[0] = 0x01; + // IPL.AR + current_offset += create_item(items[3], Type_Byte, "IPL.AR", 1, current_offset); + items[3].data[0] = 0x01; - // BT.BAR - current_offset += create_item(items[4], Type_Byte, "BT.BAR", 1, current_offset); - items[4].data[0] = 0x01; + // BT.BAR + current_offset += create_item(items[4], Type_Byte, "BT.BAR", 1, current_offset); + items[4].data[0] = 0x01; - // IPL.SSV - current_offset += create_item(items[5], Type_Byte, "IPL.SSV", 1, current_offset); + // IPL.SSV + current_offset += create_item(items[5], Type_Byte, "IPL.SSV", 1, current_offset); - // IPL.LNG - current_offset += create_item(items[6], Type_Byte, "IPL.LNG", 1, current_offset); - items[6].data[0] = 0x01; + // IPL.LNG + current_offset += create_item(items[6], Type_Byte, "IPL.LNG", 1, current_offset); + items[6].data[0] = 0x01; - // IPL.SADR - current_offset += create_item(items[7], Type_BigArray, "IPL.SADR", 0x1007, current_offset); - items[7].data[0] = 0x6c; //(Switzerland) TODO should this default be changed? + // IPL.SADR + current_offset += create_item(items[7], Type_BigArray, "IPL.SADR", 0x1007, current_offset); + items[7].data[0] = 0x6c; //(Switzerland) TODO should this default be changed? - // IPL.CB - current_offset += create_item(items[8], Type_Long, "IPL.CB", 4, current_offset); - items[8].data[0] = 0x0f; items[8].data[1] = 0x11; - items[8].data[2] = 0x14; items[8].data[3] = 0xa6; + // IPL.CB + current_offset += create_item(items[8], Type_Long, "IPL.CB", 4, current_offset); + items[8].data[0] = 0x0f; + items[8].data[1] = 0x11; + items[8].data[2] = 0x14; + items[8].data[3] = 0xa6; - // BT.SPKV - current_offset += create_item(items[9], Type_Byte, "BT.SPKV", 1, current_offset); - items[9].data[0] = 0x58; + // BT.SPKV + current_offset += create_item(items[9], Type_Byte, "BT.SPKV", 1, current_offset); + items[9].data[0] = 0x58; - // IPL.PC - current_offset += create_item(items[10], Type_SmallArray, "IPL.PC", 0x49, current_offset); - items[10].data[1] = 0x04; items[10].data[2] = 0x14; + // IPL.PC + current_offset += create_item(items[10], Type_SmallArray, "IPL.PC", 0x49, current_offset); + items[10].data[1] = 0x04; + items[10].data[2] = 0x14; - // NET.CTPC - current_offset += create_item(items[11], Type_Long, "NET.CTPC", 4, current_offset); + // NET.CTPC + current_offset += create_item(items[11], Type_Long, "NET.CTPC", 4, current_offset); - // WWW.RST - current_offset += create_item(items[12], Type_Bool, "WWW.RST", 1, current_offset); + // WWW.RST + current_offset += create_item(items[12], Type_Bool, "WWW.RST", 1, current_offset); - // BT.CDIF - current_offset += create_item(items[13], Type_BigArray, "BT.CDIF", 0x204, current_offset); + // BT.CDIF + current_offset += create_item(items[13], Type_BigArray, "BT.CDIF", 0x204, current_offset); - // IPL.INC - current_offset += create_item(items[14], Type_Long, "IPL.INC", 4, current_offset); - items[14].data[3] = 0x08; + // IPL.INC + current_offset += create_item(items[14], Type_Long, "IPL.INC", 4, current_offset); + items[14].data[3] = 0x08; - // IPL.FRC - current_offset += create_item(items[15], Type_Long, "IPL.FRC", 4, current_offset); - items[15].data[3] = 0x28; + // IPL.FRC + current_offset += create_item(items[15], Type_Long, "IPL.FRC", 4, current_offset); + items[15].data[3] = 0x28; - // IPL.CD - current_offset += create_item(items[16], Type_Bool, "IPL.CD", 1, current_offset); - items[16].data[0] = 0x01; + // IPL.CD + current_offset += create_item(items[16], Type_Bool, "IPL.CD", 1, current_offset); + items[16].data[0] = 0x01; - // IPL.CD2 - current_offset += create_item(items[17], Type_Bool, "IPL.CD2", 1, current_offset); - items[17].data[0] = 0x01; + // IPL.CD2 + current_offset += create_item(items[17], Type_Bool, "IPL.CD2", 1, current_offset); + items[17].data[0] = 0x01; - // IPL.UPT - current_offset += create_item(items[18], Type_Byte, "IPL.UPT", 1, current_offset); - items[18].data[0] = 0x02; + // IPL.UPT + current_offset += create_item(items[18], Type_Byte, "IPL.UPT", 1, current_offset); + items[18].data[0] = 0x02; - // IPL.PGS - current_offset += create_item(items[19], Type_Byte, "IPL.PGS", 1, current_offset); + // IPL.PGS + current_offset += create_item(items[19], Type_Byte, "IPL.PGS", 1, current_offset); - // IPL.E60 - current_offset += create_item(items[20], Type_Byte, "IPL.E60", 1, current_offset); - items[20].data[0] = 0x01; + // IPL.E60 + current_offset += create_item(items[20], Type_Byte, "IPL.E60", 1, current_offset); + items[20].data[0] = 0x01; - // IPL.DH - current_offset += create_item(items[21], Type_Byte, "IPL.DH", 1, current_offset); + // IPL.DH + current_offset += create_item(items[21], Type_Byte, "IPL.DH", 1, current_offset); - // NET.WCFG - current_offset += create_item(items[22], Type_Long, "NET.WCFG", 4, current_offset); - items[22].data[3] = 0x01; + // NET.WCFG + current_offset += create_item(items[22], Type_Long, "NET.WCFG", 4, current_offset); + items[22].data[3] = 0x01; - // IPL.IDL - current_offset += create_item(items[23], Type_SmallArray, "IPL.IDL", 1, current_offset); - items[23].data[0] = 0x01; + // IPL.IDL + current_offset += create_item(items[23], Type_SmallArray, "IPL.IDL", 1, current_offset); + items[23].data[0] = 0x01; - // IPL.EULA - current_offset += create_item(items[24], Type_Bool, "IPL.EULA", 1, current_offset); - items[24].data[0] = 0x01; + // IPL.EULA + current_offset += create_item(items[24], Type_Bool, "IPL.EULA", 1, current_offset); + items[24].data[0] = 0x01; - // BT.MOT - current_offset += create_item(items[25], Type_Byte, "BT.MOT", 1, current_offset); - items[25].data[0] = 0x01; + // BT.MOT + current_offset += create_item(items[25], Type_Byte, "BT.MOT", 1, current_offset); + items[25].data[0] = 0x01; - // MPLS.MOVIE - current_offset += create_item(items[26], Type_Bool, "MPLS.MOVIE", 1, current_offset); - items[26].data[0] = 0x01; + // MPLS.MOVIE + current_offset += create_item(items[26], Type_Bool, "MPLS.MOVIE", 1, current_offset); + items[26].data[0] = 0x01; + for (const SSysConfEntry& item : items) + m_Entries.push_back(item); - for (const SSysConfEntry& item : items) - m_Entries.push_back(item); + File::CreateFullPath(m_FilenameDefault); + File::IOFile g(m_FilenameDefault, "wb"); - File::CreateFullPath(m_FilenameDefault); - File::IOFile g(m_FilenameDefault, "wb"); + // Write the header and item offsets + g.WriteBytes(&s_Header.version, sizeof(s_Header.version)); + g.WriteBytes(&s_Header.numEntries, sizeof(u16)); + for (int i = 0; i != 27; ++i) + { + const u16 tmp_offset = Common::swap16(items[i].offset); + g.WriteBytes(&tmp_offset, 2); + } + const u16 end_data_offset = Common::swap16(current_offset); + g.WriteBytes(&end_data_offset, 2); - // Write the header and item offsets - g.WriteBytes(&s_Header.version, sizeof(s_Header.version)); - g.WriteBytes(&s_Header.numEntries, sizeof(u16)); - for (int i = 0; i != 27; ++i) - { - const u16 tmp_offset = Common::swap16(items[i].offset); - g.WriteBytes(&tmp_offset, 2); - } - const u16 end_data_offset = Common::swap16(current_offset); - g.WriteBytes(&end_data_offset, 2); + // Write the items + const u8 null_byte = 0; + for (int i = 0; i != 27; ++i) + { + u8 description = (items[i].type << 5) | (items[i].nameLength - 1); + g.WriteBytes(&description, sizeof(description)); + g.WriteBytes(&items[i].name, items[i].nameLength); + switch (items[i].type) + { + case Type_BigArray: + { + const u16 tmpDataLength = Common::swap16(items[i].dataLength); + g.WriteBytes(&tmpDataLength, 2); + g.WriteBytes(items[i].data, items[i].dataLength); + g.WriteBytes(&null_byte, 1); + } + break; - // Write the items - const u8 null_byte = 0; - for (int i = 0; i != 27; ++i) - { - u8 description = (items[i].type << 5) | (items[i].nameLength - 1); - g.WriteBytes(&description, sizeof(description)); - g.WriteBytes(&items[i].name, items[i].nameLength); - switch (items[i].type) - { - case Type_BigArray: - { - const u16 tmpDataLength = Common::swap16(items[i].dataLength); - g.WriteBytes(&tmpDataLength, 2); - g.WriteBytes(items[i].data, items[i].dataLength); - g.WriteBytes(&null_byte, 1); - } - break; + case Type_SmallArray: + g.WriteBytes(&items[i].dataLength, 1); + g.WriteBytes(items[i].data, items[i].dataLength); + g.WriteBytes(&null_byte, 1); + break; - case Type_SmallArray: - g.WriteBytes(&items[i].dataLength, 1); - g.WriteBytes(items[i].data, items[i].dataLength); - g.WriteBytes(&null_byte, 1); - break; + default: + g.WriteBytes(items[i].data, items[i].dataLength); + break; + } + } - default: - g.WriteBytes(items[i].data, items[i].dataLength); - break; - } - } + // Pad file to the correct size + const u64 cur_size = g.GetSize(); + for (unsigned int i = 0; i != 16380 - cur_size; ++i) + g.WriteBytes(&null_byte, 1); - // Pad file to the correct size - const u64 cur_size = g.GetSize(); - for (unsigned int i = 0; i != 16380 - cur_size; ++i) - g.WriteBytes(&null_byte, 1); + // Write the footer + g.WriteBytes("SCed", 4); - // Write the footer - g.WriteBytes("SCed", 4); - - m_Filename = m_FilenameDefault; - m_IsValid = true; + m_Filename = m_FilenameDefault; + m_IsValid = true; } bool SysConf::SaveToFile(const std::string& filename) { - File::IOFile f(filename, "r+b"); + File::IOFile f(filename, "r+b"); - for (auto i = m_Entries.begin(); i < m_Entries.end() - 1; ++i) - { - // Seek to after the name of this entry - f.Seek(i->offset + i->nameLength + 1, SEEK_SET); + for (auto i = m_Entries.begin(); i < m_Entries.end() - 1; ++i) + { + // Seek to after the name of this entry + f.Seek(i->offset + i->nameLength + 1, SEEK_SET); - // We may have to write array length value... - if (i->type == Type_BigArray) - { - const u16 tmpDataLength = Common::swap16(i->dataLength); - f.WriteArray(&tmpDataLength, 1); - } - else if (i->type == Type_SmallArray) - { - const u8 len = (u8)(i->dataLength); - f.WriteArray(&len, 1); - } + // We may have to write array length value... + if (i->type == Type_BigArray) + { + const u16 tmpDataLength = Common::swap16(i->dataLength); + f.WriteArray(&tmpDataLength, 1); + } + else if (i->type == Type_SmallArray) + { + const u8 len = (u8)(i->dataLength); + f.WriteArray(&len, 1); + } - // Now write the actual data - f.WriteBytes(i->data, i->dataLength); - } + // Now write the actual data + f.WriteBytes(i->data, i->dataLength); + } - return f.IsGood(); + return f.IsGood(); } bool SysConf::Save() { - if (!m_IsValid) - return false; + if (!m_IsValid) + return false; - return SaveToFile(m_Filename); + return SaveToFile(m_Filename); } void SysConf::UpdateLocation() { - // if the old Wii User dir had a sysconf file save any settings that have been changed to it - if (m_IsValid) - Save(); + // if the old Wii User dir had a sysconf file save any settings that have been changed to it + if (m_IsValid) + Save(); - // Clear the old filename and set the default filename to the new user path - // So that it can be generated if the file does not exist in the new location - m_Filename.clear(); - // Note: We don't use the dummy Wii root here (if in use) because this is - // all tied up with the configuration code. In the future this should - // probably just be synced with the other settings. - m_FilenameDefault = File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP WII_SYSCONF_DIR DIR_SEP WII_SYSCONF; - Reload(); + // Clear the old filename and set the default filename to the new user path + // So that it can be generated if the file does not exist in the new location + m_Filename.clear(); + // Note: We don't use the dummy Wii root here (if in use) because this is + // all tied up with the configuration code. In the future this should + // probably just be synced with the other settings. + m_FilenameDefault = + File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP WII_SYSCONF_DIR DIR_SEP WII_SYSCONF; + Reload(); } bool SysConf::Reload() { - std::string& filename = m_Filename.empty() ? m_FilenameDefault : m_Filename; + std::string& filename = m_Filename.empty() ? m_FilenameDefault : m_Filename; - LoadFromFile(filename); - return m_IsValid; + LoadFromFile(filename); + return m_IsValid; } diff --git a/Source/Core/Common/SysConf.h b/Source/Core/Common/SysConf.h index aae706f79d..83bed95a4f 100644 --- a/Source/Core/Common/SysConf.h +++ b/Source/Core/Common/SysConf.h @@ -11,8 +11,8 @@ #include #include "Common/CommonTypes.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" // This class is meant to edit the values in a given Wii SYSCONF file // It currently does not add/remove/rearrange sections, @@ -22,163 +22,165 @@ enum SysconfType { - Type_BigArray = 1, - Type_SmallArray, - Type_Byte, - Type_Short, - Type_Long, - Type_Unknown, - Type_Bool + Type_BigArray = 1, + Type_SmallArray, + Type_Byte, + Type_Short, + Type_Long, + Type_Unknown, + Type_Bool }; struct SSysConfHeader { - char version[4]; - u16 numEntries; + char version[4]; + u16 numEntries; }; struct SSysConfEntry { - u16 offset; - SysconfType type; - u8 nameLength; - char name[32]; - u16 dataLength; - u8* data; + u16 offset; + SysconfType type; + u8 nameLength; + char name[32]; + u16 dataLength; + u8* data; - template - T GetData() { return *(T*)data; } - bool GetArrayData(u8* dest, u16 destSize) - { - if (dest && destSize >= dataLength) - { - memcpy(dest, data, dataLength); - return true; - } - return false; - } - bool SetArrayData(u8* buffer, u16 bufferSize) - { - if (buffer) - { - memcpy(data, buffer, std::min(bufferSize, dataLength)); - return true; - } - return false; - } + template + T GetData() + { + return *(T*)data; + } + bool GetArrayData(u8* dest, u16 destSize) + { + if (dest && destSize >= dataLength) + { + memcpy(dest, data, dataLength); + return true; + } + return false; + } + bool SetArrayData(u8* buffer, u16 bufferSize) + { + if (buffer) + { + memcpy(data, buffer, std::min(bufferSize, dataLength)); + return true; + } + return false; + } }; class SysConf { public: - SysConf(); - ~SysConf(); + SysConf(); + ~SysConf(); - bool IsValid() { return m_IsValid; } + bool IsValid() { return m_IsValid; } + template + T GetData(const char* sectionName) + { + if (!m_IsValid) + { + PanicAlertT("Trying to read from invalid SYSCONF"); + return 0; + } - template - T GetData(const char* sectionName) - { - if (!m_IsValid) - { - PanicAlertT("Trying to read from invalid SYSCONF"); - return 0; - } + std::vector::iterator index = m_Entries.begin(); + for (; index < m_Entries.end() - 1; ++index) + { + if (strcmp(index->name, sectionName) == 0) + break; + } + if (index == m_Entries.end() - 1) + { + PanicAlertT("Section %s not found in SYSCONF", sectionName); + return 0; + } - std::vector::iterator index = m_Entries.begin(); - for (; index < m_Entries.end() - 1; ++index) - { - if (strcmp(index->name, sectionName) == 0) - break; - } - if (index == m_Entries.end() - 1) - { - PanicAlertT("Section %s not found in SYSCONF", sectionName); - return 0; - } + return index->GetData(); + } - return index->GetData(); - } + bool GetArrayData(const char* sectionName, u8* dest, u16 destSize) + { + if (!m_IsValid) + { + PanicAlertT("Trying to read from invalid SYSCONF"); + return 0; + } - bool GetArrayData(const char* sectionName, u8* dest, u16 destSize) - { - if (!m_IsValid) - { - PanicAlertT("Trying to read from invalid SYSCONF"); - return 0; - } + std::vector::iterator index = m_Entries.begin(); + for (; index < m_Entries.end() - 1; ++index) + { + if (strcmp(index->name, sectionName) == 0) + break; + } + if (index == m_Entries.end() - 1) + { + PanicAlertT("Section %s not found in SYSCONF", sectionName); + return 0; + } - std::vector::iterator index = m_Entries.begin(); - for (; index < m_Entries.end() - 1; ++index) - { - if (strcmp(index->name, sectionName) == 0) - break; - } - if (index == m_Entries.end() - 1) - { - PanicAlertT("Section %s not found in SYSCONF", sectionName); - return 0; - } + return index->GetArrayData(dest, destSize); + } - return index->GetArrayData(dest, destSize); - } + bool SetArrayData(const char* sectionName, u8* buffer, u16 bufferSize) + { + if (!m_IsValid) + return false; - bool SetArrayData(const char* sectionName, u8* buffer, u16 bufferSize) - { - if (!m_IsValid) - return false; + std::vector::iterator index = m_Entries.begin(); + for (; index < m_Entries.end() - 1; ++index) + { + if (strcmp(index->name, sectionName) == 0) + break; + } + if (index == m_Entries.end() - 1) + { + PanicAlertT("Section %s not found in SYSCONF", sectionName); + return false; + } - std::vector::iterator index = m_Entries.begin(); - for (; index < m_Entries.end() - 1; ++index) - { - if (strcmp(index->name, sectionName) == 0) - break; - } - if (index == m_Entries.end() - 1) - { - PanicAlertT("Section %s not found in SYSCONF", sectionName); - return false; - } + return index->SetArrayData(buffer, bufferSize); + } - return index->SetArrayData(buffer, bufferSize); - } + template + bool SetData(const char* sectionName, T newValue) + { + if (!m_IsValid) + return false; - template - bool SetData(const char* sectionName, T newValue) - { - if (!m_IsValid) - return false; + std::vector::iterator index = m_Entries.begin(); + for (; index < m_Entries.end() - 1; ++index) + { + if (strcmp(index->name, sectionName) == 0) + break; + } + if (index == m_Entries.end() - 1) + { + PanicAlertT("Section %s not found in SYSCONF", sectionName); + return false; + } - std::vector::iterator index = m_Entries.begin(); - for (; index < m_Entries.end() - 1; ++index) - { - if (strcmp(index->name, sectionName) == 0) - break; - } - if (index == m_Entries.end() - 1) - { - PanicAlertT("Section %s not found in SYSCONF", sectionName); - return false; - } + *(T*)index->data = newValue; + return true; + } - *(T*)index->data = newValue; - return true; - } - - bool Save(); - bool SaveToFile(const std::string& filename); - bool LoadFromFile(const std::string& filename); - bool Reload(); - // This function is used when the NAND root is changed - void UpdateLocation(); + bool Save(); + bool SaveToFile(const std::string& filename); + bool LoadFromFile(const std::string& filename); + bool Reload(); + // This function is used when the NAND root is changed + void UpdateLocation(); private: - bool LoadFromFileInternal(FILE* fh); - void GenerateSysConf(); - void Clear(); + bool LoadFromFileInternal(FILE* fh); + void GenerateSysConf(); + void Clear(); - std::string m_Filename; - std::string m_FilenameDefault; - std::vector m_Entries; - bool m_IsValid; + std::string m_Filename; + std::string m_FilenameDefault; + std::vector m_Entries; + bool m_IsValid; }; diff --git a/Source/Core/Common/Thread.cpp b/Source/Core/Common/Thread.cpp index 29420dd170..557cbfbef2 100644 --- a/Source/Core/Common/Thread.cpp +++ b/Source/Core/Common/Thread.cpp @@ -2,9 +2,9 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Common/Thread.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" -#include "Common/Thread.h" #ifndef _WIN32 #include @@ -23,15 +23,14 @@ namespace Common { - int CurrentThreadId() { #ifdef _WIN32 - return GetCurrentThreadId(); + return GetCurrentThreadId(); #elif defined __APPLE__ - return mach_thread_self(); + return mach_thread_self(); #else - return 0; + return 0; #endif } @@ -39,23 +38,23 @@ int CurrentThreadId() void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { - SetThreadAffinityMask(thread, mask); + SetThreadAffinityMask(thread, mask); } void SetCurrentThreadAffinity(u32 mask) { - SetThreadAffinityMask(GetCurrentThread(), mask); + SetThreadAffinityMask(GetCurrentThread(), mask); } // Supporting functions void SleepCurrentThread(int ms) { - Sleep(ms); + Sleep(ms); } void SwitchCurrentThread() { - SwitchToThread(); + SwitchToThread(); } // Sets the debugger-visible name of the current thread. @@ -66,85 +65,86 @@ void SwitchCurrentThread() // http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx void SetCurrentThreadName(const char* szThreadName) { - static const DWORD MS_VC_EXCEPTION = 0x406D1388; + static const DWORD MS_VC_EXCEPTION = 0x406D1388; - #pragma pack(push,8) - struct THREADNAME_INFO - { - DWORD dwType; // must be 0x1000 - LPCSTR szName; // pointer to name (in user addr space) - DWORD dwThreadID; // thread ID (-1=caller thread) - DWORD dwFlags; // reserved for future use, must be zero - } info; - #pragma pack(pop) +#pragma pack(push, 8) + struct THREADNAME_INFO + { + DWORD dwType; // must be 0x1000 + LPCSTR szName; // pointer to name (in user addr space) + DWORD dwThreadID; // thread ID (-1=caller thread) + DWORD dwFlags; // reserved for future use, must be zero + } info; +#pragma pack(pop) - info.dwType = 0x1000; - info.szName = szThreadName; - info.dwThreadID = -1; //dwThreadID; - info.dwFlags = 0; + info.dwType = 0x1000; + info.szName = szThreadName; + info.dwThreadID = -1; // dwThreadID; + info.dwFlags = 0; - __try - { - RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); - } - __except(EXCEPTION_CONTINUE_EXECUTION) - {} + __try + { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } + __except (EXCEPTION_CONTINUE_EXECUTION) + { + } } -#else // !WIN32, so must be POSIX threads +#else // !WIN32, so must be POSIX threads void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { #ifdef __APPLE__ - thread_policy_set(pthread_mach_thread_np(thread), - THREAD_AFFINITY_POLICY, (integer_t*)&mask, 1); + thread_policy_set(pthread_mach_thread_np(thread), THREAD_AFFINITY_POLICY, (integer_t*)&mask, 1); #elif (defined __linux__ || defined BSD4_4 || defined __FreeBSD__) && !(defined ANDROID) #ifdef __FreeBSD__ - cpuset_t cpu_set; + cpuset_t cpu_set; #else - cpu_set_t cpu_set; + cpu_set_t cpu_set; #endif - CPU_ZERO(&cpu_set); + CPU_ZERO(&cpu_set); - for (int i = 0; i != sizeof(mask) * 8; ++i) - if ((mask >> i) & 1) - CPU_SET(i, &cpu_set); + for (int i = 0; i != sizeof(mask) * 8; ++i) + if ((mask >> i) & 1) + CPU_SET(i, &cpu_set); - pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set); + pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set); #endif } void SetCurrentThreadAffinity(u32 mask) { - SetThreadAffinity(pthread_self(), mask); + SetThreadAffinity(pthread_self(), mask); } void SleepCurrentThread(int ms) { - usleep(1000 * ms); + usleep(1000 * ms); } void SwitchCurrentThread() { - usleep(1000 * 1); + usleep(1000 * 1); } void SetCurrentThreadName(const char* szThreadName) { #ifdef __APPLE__ - pthread_setname_np(szThreadName); + pthread_setname_np(szThreadName); #elif defined __FreeBSD__ - pthread_set_name_np(pthread_self(), szThreadName); + pthread_set_name_np(pthread_self(), szThreadName); #else - // linux doesn't allow to set more than 16 bytes, including \0. - pthread_setname_np(pthread_self(), std::string(szThreadName).substr(0, 15).c_str()); + // linux doesn't allow to set more than 16 bytes, including \0. + pthread_setname_np(pthread_self(), std::string(szThreadName).substr(0, 15).c_str()); #endif #ifdef USE_VTUNE - // VTune uses OS thread names by default but probably supports longer names when set via its own API. - __itt_thread_set_name(szThreadName); + // VTune uses OS thread names by default but probably supports longer names when set via its own + // API. + __itt_thread_set_name(szThreadName); #endif } #endif -} // namespace Common +} // namespace Common diff --git a/Source/Core/Common/Thread.h b/Source/Core/Common/Thread.h index 567615e801..e249317de2 100644 --- a/Source/Core/Common/Thread.h +++ b/Source/Core/Common/Thread.h @@ -18,23 +18,22 @@ namespace Common { - int CurrentThreadId(); void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask); void SetCurrentThreadAffinity(u32 mask); void SleepCurrentThread(int ms); -void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms +void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms // Use this function during a spin-wait to make the current thread // relax while another thread is working. This may be more efficient // than using events because event functions use kernel calls. inline void YieldCPU() { - std::this_thread::yield(); + std::this_thread::yield(); } void SetCurrentThreadName(const char* name); -} // namespace Common +} // namespace Common diff --git a/Source/Core/Common/Timer.cpp b/Source/Core/Common/Timer.cpp index 4ad69fdc23..edd1d4b378 100644 --- a/Source/Core/Common/Timer.cpp +++ b/Source/Core/Common/Timer.cpp @@ -20,46 +20,45 @@ namespace Common { - u32 Timer::GetTimeMs() { #ifdef _WIN32 - return timeGetTime(); + return timeGetTime(); #elif defined __APPLE__ - struct timeval t; - (void)gettimeofday(&t, nullptr); - return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000)); + struct timeval t; + (void)gettimeofday(&t, nullptr); + return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000)); #else - struct timespec t; - (void)clock_gettime(CLOCK_MONOTONIC, &t); - return ((u32)(t.tv_sec * 1000 + t.tv_nsec / 1000000)); + struct timespec t; + (void)clock_gettime(CLOCK_MONOTONIC, &t); + return ((u32)(t.tv_sec * 1000 + t.tv_nsec / 1000000)); #endif } #ifdef _WIN32 double GetFreq() { - LARGE_INTEGER freq; - QueryPerformanceFrequency(&freq); - return 1000000.0 / double(freq.QuadPart); + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + return 1000000.0 / double(freq.QuadPart); } #endif u64 Timer::GetTimeUs() { #ifdef _WIN32 - LARGE_INTEGER time; - static double freq = GetFreq(); - QueryPerformanceCounter(&time); - return u64(double(time.QuadPart) * freq); + LARGE_INTEGER time; + static double freq = GetFreq(); + QueryPerformanceCounter(&time); + return u64(double(time.QuadPart) * freq); #elif defined __APPLE__ - struct timeval t; - (void)gettimeofday(&t, nullptr); - return ((u64)(t.tv_sec * 1000000 + t.tv_usec)); + struct timeval t; + (void)gettimeofday(&t, nullptr); + return ((u64)(t.tv_sec * 1000000 + t.tv_usec)); #else - struct timespec t; - (void)clock_gettime(CLOCK_MONOTONIC, &t); - return ((u64)(t.tv_sec * 1000000 + t.tv_nsec / 1000)); + struct timespec t; + (void)clock_gettime(CLOCK_MONOTONIC, &t); + return ((u64)(t.tv_sec * 1000000 + t.tv_nsec / 1000)); #endif } @@ -68,32 +67,31 @@ u64 Timer::GetTimeUs() // -------------------------------------------- // Set initial values for the class -Timer::Timer() - : m_LastTime(0), m_StartTime(0), m_Running(false) +Timer::Timer() : m_LastTime(0), m_StartTime(0), m_Running(false) { - Update(); + Update(); } // Write the starting time void Timer::Start() { - m_StartTime = GetTimeMs(); - m_Running = true; + m_StartTime = GetTimeMs(); + m_Running = true; } // Stop the timer void Timer::Stop() { - // Write the final time - m_LastTime = GetTimeMs(); - m_Running = false; + // Write the final time + m_LastTime = GetTimeMs(); + m_Running = false; } // Update the last time variable void Timer::Update() { - m_LastTime = GetTimeMs(); - //TODO(ector) - QPF + m_LastTime = GetTimeMs(); + // TODO(ector) - QPF } // ------------------------------------- @@ -103,124 +101,126 @@ void Timer::Update() // Get the number of milliseconds since the last Update() u64 Timer::GetTimeDifference() { - return GetTimeMs() - m_LastTime; + return GetTimeMs() - m_LastTime; } // Add the time difference since the last Update() to the starting time. // This is used to compensate for a paused game. void Timer::AddTimeDifference() { - m_StartTime += GetTimeDifference(); + m_StartTime += GetTimeDifference(); } // Get the time elapsed since the Start() u64 Timer::GetTimeElapsed() { - // If we have not started yet, return 1 (because then I don't - // have to change the FPS calculation in CoreRerecording.cpp . - if (m_StartTime == 0) return 1; + // If we have not started yet, return 1 (because then I don't + // have to change the FPS calculation in CoreRerecording.cpp . + if (m_StartTime == 0) + return 1; - // Return the final timer time if the timer is stopped - if (!m_Running) return (m_LastTime - m_StartTime); + // Return the final timer time if the timer is stopped + if (!m_Running) + return (m_LastTime - m_StartTime); - return (GetTimeMs() - m_StartTime); + return (GetTimeMs() - m_StartTime); } // Get the formatted time elapsed since the Start() std::string Timer::GetTimeElapsedFormatted() const { - // If we have not started yet, return zero - if (m_StartTime == 0) - return "00:00:00:000"; + // If we have not started yet, return zero + if (m_StartTime == 0) + return "00:00:00:000"; - // The number of milliseconds since the start. - // Use a different value if the timer is stopped. - u64 Milliseconds; - if (m_Running) - Milliseconds = GetTimeMs() - m_StartTime; - else - Milliseconds = m_LastTime - m_StartTime; - // Seconds - u32 Seconds = (u32)(Milliseconds / 1000); - // Minutes - u32 Minutes = Seconds / 60; - // Hours - u32 Hours = Minutes / 60; + // The number of milliseconds since the start. + // Use a different value if the timer is stopped. + u64 Milliseconds; + if (m_Running) + Milliseconds = GetTimeMs() - m_StartTime; + else + Milliseconds = m_LastTime - m_StartTime; + // Seconds + u32 Seconds = (u32)(Milliseconds / 1000); + // Minutes + u32 Minutes = Seconds / 60; + // Hours + u32 Hours = Minutes / 60; - std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03" PRIu64, - Hours, Minutes % 60, Seconds % 60, Milliseconds % 1000); - return TmpStr; + std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03" PRIu64, Hours, Minutes % 60, + Seconds % 60, Milliseconds % 1000); + return TmpStr; } // Get current time void Timer::IncreaseResolution() { #ifdef _WIN32 - timeBeginPeriod(1); + timeBeginPeriod(1); #endif } void Timer::RestoreResolution() { #ifdef _WIN32 - timeEndPeriod(1); + timeEndPeriod(1); #endif } // Get the number of seconds since January 1 1970 u64 Timer::GetTimeSinceJan1970() { - time_t ltime; - time(<ime); - return((u64)ltime); + time_t ltime; + time(<ime); + return ((u64)ltime); } u64 Timer::GetLocalTimeSinceJan1970() { - time_t sysTime, tzDiff, tzDST; - struct tm * gmTime; + time_t sysTime, tzDiff, tzDST; + struct tm* gmTime; - time(&sysTime); + time(&sysTime); - // Account for DST where needed - gmTime = localtime(&sysTime); - if (gmTime->tm_isdst == 1) - tzDST = 3600; - else - tzDST = 0; + // Account for DST where needed + gmTime = localtime(&sysTime); + if (gmTime->tm_isdst == 1) + tzDST = 3600; + else + tzDST = 0; - // Lazy way to get local time in sec - gmTime = gmtime(&sysTime); - tzDiff = sysTime - mktime(gmTime); + // Lazy way to get local time in sec + gmTime = gmtime(&sysTime); + tzDiff = sysTime - mktime(gmTime); - return (u64)(sysTime + tzDiff + tzDST); + return (u64)(sysTime + tzDiff + tzDST); } // Return the current time formatted as Minutes:Seconds:Milliseconds // in the form 00:00:000. std::string Timer::GetTimeFormatted() { - time_t sysTime; - time(&sysTime); + time_t sysTime; + time(&sysTime); - struct tm * gmTime = localtime(&sysTime); + struct tm* gmTime = localtime(&sysTime); - char tmp[13]; - strftime(tmp, 6, "%M:%S", gmTime); + char tmp[13]; + strftime(tmp, 6, "%M:%S", gmTime); - // Now tack on the milliseconds +// Now tack on the milliseconds #ifdef _WIN32 - struct timeb tp; - (void)::ftime(&tp); - return StringFromFormat("%s:%03i", tmp, tp.millitm); + struct timeb tp; + (void)::ftime(&tp); + return StringFromFormat("%s:%03i", tmp, tp.millitm); #elif defined __APPLE__ - struct timeval t; - (void)gettimeofday(&t, nullptr); - return StringFromFormat("%s:%03d", tmp, (int)(t.tv_usec / 1000)); + struct timeval t; + (void)gettimeofday(&t, nullptr); + return StringFromFormat("%s:%03d", tmp, (int)(t.tv_usec / 1000)); #else - struct timespec t; - (void)clock_gettime(CLOCK_MONOTONIC, &t); - return StringFromFormat("%s:%03d", tmp, (int)(t.tv_nsec / 1000000)); + struct timespec t; + (void)clock_gettime(CLOCK_MONOTONIC, &t); + return StringFromFormat("%s:%03d", tmp, (int)(t.tv_nsec / 1000000)); #endif } @@ -228,48 +228,48 @@ std::string Timer::GetTimeFormatted() double Timer::GetDoubleTime() { #ifdef _WIN32 - struct timeb tp; - (void)::ftime(&tp); + struct timeb tp; + (void)::ftime(&tp); #elif defined __APPLE__ - struct timeval t; - (void)gettimeofday(&t, nullptr); + struct timeval t; + (void)gettimeofday(&t, nullptr); #else - struct timespec t; - (void)clock_gettime(CLOCK_MONOTONIC, &t); + struct timespec t; + (void)clock_gettime(CLOCK_MONOTONIC, &t); #endif - // Get continuous timestamp - u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970(); + // Get continuous timestamp + u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970(); - // Remove a few years. We only really want enough seconds to make - // sure that we are detecting actual actions, perhaps 60 seconds is - // enough really, but I leave a year of seconds anyway, in case the - // user's clock is incorrect or something like that. - TmpSeconds = TmpSeconds - DOUBLE_TIME_OFFSET; + // Remove a few years. We only really want enough seconds to make + // sure that we are detecting actual actions, perhaps 60 seconds is + // enough really, but I leave a year of seconds anyway, in case the + // user's clock is incorrect or something like that. + TmpSeconds = TmpSeconds - DOUBLE_TIME_OFFSET; - // Make a smaller integer that fits in the double - u32 Seconds = (u32)TmpSeconds; + // Make a smaller integer that fits in the double + u32 Seconds = (u32)TmpSeconds; #ifdef _WIN32 - double ms = tp.millitm / 1000.0 / 1000.0; + double ms = tp.millitm / 1000.0 / 1000.0; #elif defined __APPLE__ - double ms = t.tv_usec / 1000000.0; + double ms = t.tv_usec / 1000000.0; #else - double ms = t.tv_nsec / 1000000000.0; + double ms = t.tv_nsec / 1000000000.0; #endif - double TmpTime = Seconds + ms; + double TmpTime = Seconds + ms; - return TmpTime; + return TmpTime; } // Formats a timestamp from GetDoubleTime() into a date and time string std::string Timer::GetDateTimeFormatted(double time) { - // revert adjustments from GetDoubleTime() to get a normal Unix timestamp again - time_t seconds = (time_t)time + DOUBLE_TIME_OFFSET; - tm* localTime = localtime(&seconds); + // revert adjustments from GetDoubleTime() to get a normal Unix timestamp again + time_t seconds = (time_t)time + DOUBLE_TIME_OFFSET; + tm* localTime = localtime(&seconds); - char tmp[32] = {}; - strftime(tmp, sizeof(tmp), "%x %X", localTime); - return tmp; + char tmp[32] = {}; + strftime(tmp, sizeof(tmp), "%x %X", localTime); + return tmp; } -} // Namespace Common +} // Namespace Common diff --git a/Source/Core/Common/Timer.h b/Source/Core/Common/Timer.h index cc6d6549c4..aa82ebf6b0 100644 --- a/Source/Core/Common/Timer.h +++ b/Source/Core/Common/Timer.h @@ -12,40 +12,41 @@ namespace Common class Timer { public: - Timer(); + Timer(); - void Start(); - void Stop(); - void Update(); + void Start(); + void Stop(); + void Update(); - // The time difference is always returned in milliseconds, regardless of alternative internal representation - u64 GetTimeDifference(); - void AddTimeDifference(); + // The time difference is always returned in milliseconds, regardless of alternative internal + // representation + u64 GetTimeDifference(); + void AddTimeDifference(); - static void IncreaseResolution(); - static void RestoreResolution(); - static u64 GetTimeSinceJan1970(); - static u64 GetLocalTimeSinceJan1970(); - // Returns a timestamp with decimals for precise time comparisons - static double GetDoubleTime(); + static void IncreaseResolution(); + static void RestoreResolution(); + static u64 GetTimeSinceJan1970(); + static u64 GetLocalTimeSinceJan1970(); + // Returns a timestamp with decimals for precise time comparisons + static double GetDoubleTime(); - static std::string GetTimeFormatted(); - // Formats a timestamp from GetDoubleTime() into a date and time string - static std::string GetDateTimeFormatted(double time); - std::string GetTimeElapsedFormatted() const; - u64 GetTimeElapsed(); + static std::string GetTimeFormatted(); + // Formats a timestamp from GetDoubleTime() into a date and time string + static std::string GetDateTimeFormatted(double time); + std::string GetTimeElapsedFormatted() const; + u64 GetTimeElapsed(); - static u32 GetTimeMs(); - static u64 GetTimeUs(); + static u32 GetTimeMs(); + static u64 GetTimeUs(); - // Arbitrarily chosen value (38 years) that is subtracted in GetDoubleTime() - // to increase sub-second precision of the resulting double timestamp - static const int DOUBLE_TIME_OFFSET = (38 * 365 * 24 * 60 * 60); + // Arbitrarily chosen value (38 years) that is subtracted in GetDoubleTime() + // to increase sub-second precision of the resulting double timestamp + static const int DOUBLE_TIME_OFFSET = (38 * 365 * 24 * 60 * 60); private: - u64 m_LastTime; - u64 m_StartTime; - bool m_Running; + u64 m_LastTime; + u64 m_StartTime; + bool m_Running; }; -} // Namespace Common +} // Namespace Common diff --git a/Source/Core/Common/TraversalClient.cpp b/Source/Core/Common/TraversalClient.cpp index bb453ed25b..81d592d4c3 100644 --- a/Source/Core/Common/TraversalClient.cpp +++ b/Source/Core/Common/TraversalClient.cpp @@ -1,35 +1,29 @@ // This file is public domain, in case it's useful to anyone. -comex -#include "Common/MsgHandler.h" -#include "Common/Timer.h" #include "Common/TraversalClient.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" +#include "Common/Timer.h" static void GetRandomishBytes(u8* buf, size_t size) { - // We don't need high quality random numbers (which might not be available), - // just non-repeating numbers! - static std::mt19937 prng(enet_time_get()); - static std::uniform_int_distribution u8_distribution(0, 255); - for (size_t i = 0; i < size; i++) - buf[i] = u8_distribution(prng); + // We don't need high quality random numbers (which might not be available), + // just non-repeating numbers! + static std::mt19937 prng(enet_time_get()); + static std::uniform_int_distribution u8_distribution(0, 255); + for (size_t i = 0; i < size; i++) + buf[i] = u8_distribution(prng); } TraversalClient::TraversalClient(ENetHost* netHost, const std::string& server, const u16 port) - : m_NetHost(netHost) - , m_Client(nullptr) - , m_FailureReason(0) - , m_ConnectRequestId(0) - , m_PendingConnect(false) - , m_Server(server) - , m_port(port) - , m_PingTime(0) + : m_NetHost(netHost), m_Client(nullptr), m_FailureReason(0), m_ConnectRequestId(0), + m_PendingConnect(false), m_Server(server), m_port(port), m_PingTime(0) { - netHost->intercept = TraversalClient::InterceptCallback; + netHost->intercept = TraversalClient::InterceptCallback; - Reset(); + Reset(); - ReconnectToServer(); + ReconnectToServer(); } TraversalClient::~TraversalClient() @@ -38,279 +32,279 @@ TraversalClient::~TraversalClient() void TraversalClient::ReconnectToServer() { - if (enet_address_set_host(&m_ServerAddress, m_Server.c_str())) - { - OnFailure(BadHost); - return; - } - m_ServerAddress.port = m_port; + if (enet_address_set_host(&m_ServerAddress, m_Server.c_str())) + { + OnFailure(BadHost); + return; + } + m_ServerAddress.port = m_port; - m_State = Connecting; + m_State = Connecting; - TraversalPacket hello = {}; - hello.type = TraversalPacketHelloFromClient; - hello.helloFromClient.protoVersion = TraversalProtoVersion; - SendTraversalPacket(hello); - if (m_Client) - m_Client->OnTraversalStateChanged(); + TraversalPacket hello = {}; + hello.type = TraversalPacketHelloFromClient; + hello.helloFromClient.protoVersion = TraversalProtoVersion; + SendTraversalPacket(hello); + if (m_Client) + m_Client->OnTraversalStateChanged(); } static ENetAddress MakeENetAddress(TraversalInetAddress* address) { - ENetAddress eaddr; - if (address->isIPV6) - { - eaddr.port = 0; // no support yet :( - } - else - { - eaddr.host = address->address[0]; - eaddr.port = ntohs(address->port); - } - return eaddr; + ENetAddress eaddr; + if (address->isIPV6) + { + eaddr.port = 0; // no support yet :( + } + else + { + eaddr.host = address->address[0]; + eaddr.port = ntohs(address->port); + } + return eaddr; } void TraversalClient::ConnectToClient(const std::string& host) { - if (host.size() > sizeof(TraversalHostId)) - { - PanicAlert("host too long"); - return; - } - TraversalPacket packet = {}; - packet.type = TraversalPacketConnectPlease; - memcpy(packet.connectPlease.hostId.data(), host.c_str(), host.size()); - m_ConnectRequestId = SendTraversalPacket(packet); - m_PendingConnect = true; + if (host.size() > sizeof(TraversalHostId)) + { + PanicAlert("host too long"); + return; + } + TraversalPacket packet = {}; + packet.type = TraversalPacketConnectPlease; + memcpy(packet.connectPlease.hostId.data(), host.c_str(), host.size()); + m_ConnectRequestId = SendTraversalPacket(packet); + m_PendingConnect = true; } bool TraversalClient::TestPacket(u8* data, size_t size, ENetAddress* from) { - if (from->host == m_ServerAddress.host && - from->port == m_ServerAddress.port) - { - if (size < sizeof(TraversalPacket)) - { - ERROR_LOG(NETPLAY, "Received too-short traversal packet."); - } - else - { - HandleServerPacket((TraversalPacket*) data); - return true; - } - } - return false; + if (from->host == m_ServerAddress.host && from->port == m_ServerAddress.port) + { + if (size < sizeof(TraversalPacket)) + { + ERROR_LOG(NETPLAY, "Received too-short traversal packet."); + } + else + { + HandleServerPacket((TraversalPacket*)data); + return true; + } + } + return false; } //--Temporary until more of the old netplay branch is moved over void TraversalClient::Update() { - ENetEvent netEvent; - if (enet_host_service(m_NetHost, &netEvent, 4) > 0) - { - switch (netEvent.type) - { - case ENET_EVENT_TYPE_RECEIVE: - TestPacket(netEvent.packet->data, netEvent.packet->dataLength, &netEvent.peer->address); + ENetEvent netEvent; + if (enet_host_service(m_NetHost, &netEvent, 4) > 0) + { + switch (netEvent.type) + { + case ENET_EVENT_TYPE_RECEIVE: + TestPacket(netEvent.packet->data, netEvent.packet->dataLength, &netEvent.peer->address); - enet_packet_destroy(netEvent.packet); - break; - default: - break; - } - } - HandleResends(); + enet_packet_destroy(netEvent.packet); + break; + default: + break; + } + } + HandleResends(); } void TraversalClient::HandleServerPacket(TraversalPacket* packet) { - u8 ok = 1; - switch (packet->type) - { - case TraversalPacketAck: - if (!packet->ack.ok) - { - OnFailure(ServerForgotAboutUs); - break; - } - for (auto it = m_OutgoingTraversalPackets.begin(); it != m_OutgoingTraversalPackets.end(); ++it) - { - if (it->packet.requestId == packet->requestId) - { - m_OutgoingTraversalPackets.erase(it); - break; - } - } - break; - case TraversalPacketHelloFromServer: - if (m_State != Connecting) - break; - if (!packet->helloFromServer.ok) - { - OnFailure(VersionTooOld); - break; - } - m_HostId = packet->helloFromServer.yourHostId; - m_State = Connected; - if (m_Client) - m_Client->OnTraversalStateChanged(); - break; - case TraversalPacketPleaseSendPacket: - { - // security is overrated. - ENetAddress addr = MakeENetAddress(&packet->pleaseSendPacket.address); - if (addr.port != 0) - { - char message[] = "Hello from Dolphin Netplay..."; - ENetBuffer buf; - buf.data = message; - buf.dataLength = sizeof(message) - 1; - enet_socket_send(m_NetHost->socket, &addr, &buf, 1); - } - else - { - // invalid IPV6 - ok = 0; - } - break; - } - case TraversalPacketConnectReady: - case TraversalPacketConnectFailed: - { - if (!m_PendingConnect || packet->connectReady.requestId != m_ConnectRequestId) - break; + u8 ok = 1; + switch (packet->type) + { + case TraversalPacketAck: + if (!packet->ack.ok) + { + OnFailure(ServerForgotAboutUs); + break; + } + for (auto it = m_OutgoingTraversalPackets.begin(); it != m_OutgoingTraversalPackets.end(); ++it) + { + if (it->packet.requestId == packet->requestId) + { + m_OutgoingTraversalPackets.erase(it); + break; + } + } + break; + case TraversalPacketHelloFromServer: + if (m_State != Connecting) + break; + if (!packet->helloFromServer.ok) + { + OnFailure(VersionTooOld); + break; + } + m_HostId = packet->helloFromServer.yourHostId; + m_State = Connected; + if (m_Client) + m_Client->OnTraversalStateChanged(); + break; + case TraversalPacketPleaseSendPacket: + { + // security is overrated. + ENetAddress addr = MakeENetAddress(&packet->pleaseSendPacket.address); + if (addr.port != 0) + { + char message[] = "Hello from Dolphin Netplay..."; + ENetBuffer buf; + buf.data = message; + buf.dataLength = sizeof(message) - 1; + enet_socket_send(m_NetHost->socket, &addr, &buf, 1); + } + else + { + // invalid IPV6 + ok = 0; + } + break; + } + case TraversalPacketConnectReady: + case TraversalPacketConnectFailed: + { + if (!m_PendingConnect || packet->connectReady.requestId != m_ConnectRequestId) + break; - m_PendingConnect = false; + m_PendingConnect = false; - if (!m_Client) - break; + if (!m_Client) + break; - if (packet->type == TraversalPacketConnectReady) - m_Client->OnConnectReady(MakeENetAddress(&packet->connectReady.address)); - else - m_Client->OnConnectFailed(packet->connectFailed.reason); - break; - } - default: - WARN_LOG(NETPLAY, "Received unknown packet with type %d", packet->type); - break; - } - if (packet->type != TraversalPacketAck) - { - TraversalPacket ack = {}; - ack.type = TraversalPacketAck; - ack.requestId = packet->requestId; - ack.ack.ok = ok; + if (packet->type == TraversalPacketConnectReady) + m_Client->OnConnectReady(MakeENetAddress(&packet->connectReady.address)); + else + m_Client->OnConnectFailed(packet->connectFailed.reason); + break; + } + default: + WARN_LOG(NETPLAY, "Received unknown packet with type %d", packet->type); + break; + } + if (packet->type != TraversalPacketAck) + { + TraversalPacket ack = {}; + ack.type = TraversalPacketAck; + ack.requestId = packet->requestId; + ack.ack.ok = ok; - ENetBuffer buf; - buf.data = &ack; - buf.dataLength = sizeof(ack); - if (enet_socket_send(m_NetHost->socket, &m_ServerAddress, &buf, 1) == -1) - OnFailure(SocketSendError); - } + ENetBuffer buf; + buf.data = &ack; + buf.dataLength = sizeof(ack); + if (enet_socket_send(m_NetHost->socket, &m_ServerAddress, &buf, 1) == -1) + OnFailure(SocketSendError); + } } void TraversalClient::OnFailure(FailureReason reason) { - m_State = Failure; - m_FailureReason = reason; + m_State = Failure; + m_FailureReason = reason; - switch (reason) - { - case TraversalClient::BadHost: - PanicAlertT("Couldn't look up central server %s", m_Server.c_str()); - break; - case TraversalClient::VersionTooOld: - PanicAlertT("Dolphin too old for traversal server"); - break; - case TraversalClient::ServerForgotAboutUs: - PanicAlertT("Disconnected from traversal server"); - break; - case TraversalClient::SocketSendError: - PanicAlertT("Socket error sending to traversal server"); - break; - case TraversalClient::ResendTimeout: - PanicAlertT("Timeout connecting to traversal server"); - break; - } + switch (reason) + { + case TraversalClient::BadHost: + PanicAlertT("Couldn't look up central server %s", m_Server.c_str()); + break; + case TraversalClient::VersionTooOld: + PanicAlertT("Dolphin too old for traversal server"); + break; + case TraversalClient::ServerForgotAboutUs: + PanicAlertT("Disconnected from traversal server"); + break; + case TraversalClient::SocketSendError: + PanicAlertT("Socket error sending to traversal server"); + break; + case TraversalClient::ResendTimeout: + PanicAlertT("Timeout connecting to traversal server"); + break; + } - if (m_Client) - m_Client->OnTraversalStateChanged(); + if (m_Client) + m_Client->OnTraversalStateChanged(); } void TraversalClient::ResendPacket(OutgoingTraversalPacketInfo* info) { - info->sendTime = enet_time_get(); - info->tries++; - ENetBuffer buf; - buf.data = &info->packet; - buf.dataLength = sizeof(info->packet); - if (enet_socket_send(m_NetHost->socket, &m_ServerAddress, &buf, 1) == -1) - OnFailure(SocketSendError); + info->sendTime = enet_time_get(); + info->tries++; + ENetBuffer buf; + buf.data = &info->packet; + buf.dataLength = sizeof(info->packet); + if (enet_socket_send(m_NetHost->socket, &m_ServerAddress, &buf, 1) == -1) + OnFailure(SocketSendError); } void TraversalClient::HandleResends() { - enet_uint32 now = enet_time_get(); - for (auto& tpi : m_OutgoingTraversalPackets) - { - if (now - tpi.sendTime >= (u32) (300 * tpi.tries)) - { - if (tpi.tries >= 5) - { - OnFailure(ResendTimeout); - m_OutgoingTraversalPackets.clear(); - break; - } - else - { - ResendPacket(&tpi); - } - } - } - HandlePing(); + enet_uint32 now = enet_time_get(); + for (auto& tpi : m_OutgoingTraversalPackets) + { + if (now - tpi.sendTime >= (u32)(300 * tpi.tries)) + { + if (tpi.tries >= 5) + { + OnFailure(ResendTimeout); + m_OutgoingTraversalPackets.clear(); + break; + } + else + { + ResendPacket(&tpi); + } + } + } + HandlePing(); } void TraversalClient::HandlePing() { - enet_uint32 now = enet_time_get(); - if (m_State == Connected && now - m_PingTime >= 500) - { - TraversalPacket ping = {}; - ping.type = TraversalPacketPing; - ping.ping.hostId = m_HostId; - SendTraversalPacket(ping); - m_PingTime = now; - } + enet_uint32 now = enet_time_get(); + if (m_State == Connected && now - m_PingTime >= 500) + { + TraversalPacket ping = {}; + ping.type = TraversalPacketPing; + ping.ping.hostId = m_HostId; + SendTraversalPacket(ping); + m_PingTime = now; + } } TraversalRequestId TraversalClient::SendTraversalPacket(const TraversalPacket& packet) { - OutgoingTraversalPacketInfo info; - info.packet = packet; - GetRandomishBytes((u8*) &info.packet.requestId, sizeof(info.packet.requestId)); - info.tries = 0; - m_OutgoingTraversalPackets.push_back(info); - ResendPacket(&m_OutgoingTraversalPackets.back()); - return info.packet.requestId; + OutgoingTraversalPacketInfo info; + info.packet = packet; + GetRandomishBytes((u8*)&info.packet.requestId, sizeof(info.packet.requestId)); + info.tries = 0; + m_OutgoingTraversalPackets.push_back(info); + ResendPacket(&m_OutgoingTraversalPackets.back()); + return info.packet.requestId; } void TraversalClient::Reset() { - m_PendingConnect = false; - m_Client = nullptr; + m_PendingConnect = false; + m_Client = nullptr; } int ENET_CALLBACK TraversalClient::InterceptCallback(ENetHost* host, ENetEvent* event) { - auto traversalClient = g_TraversalClient.get(); - if (traversalClient->TestPacket(host->receivedData, host->receivedDataLength, &host->receivedAddress) - || (host->receivedDataLength == 1 && host->receivedData[0] == 0)) - { - event->type = (ENetEventType)42; - return 1; - } - return 0; + auto traversalClient = g_TraversalClient.get(); + if (traversalClient->TestPacket(host->receivedData, host->receivedDataLength, + &host->receivedAddress) || + (host->receivedDataLength == 1 && host->receivedData[0] == 0)) + { + event->type = (ENetEventType)42; + return 1; + } + return 0; } std::unique_ptr g_TraversalClient; @@ -325,36 +319,35 @@ static u16 g_OldListenPort; bool EnsureTraversalClient(const std::string& server, u16 server_port, u16 listen_port) { + if (!g_MainNetHost || !g_TraversalClient || server != g_OldServer || + server_port != g_OldServerPort || listen_port != g_OldListenPort) + { + g_OldServer = server; + g_OldServerPort = server_port; + g_OldListenPort = listen_port; - if (!g_MainNetHost || !g_TraversalClient || server != g_OldServer || server_port != g_OldServerPort || listen_port != g_OldListenPort) - { - g_OldServer = server; - g_OldServerPort = server_port; - g_OldListenPort = listen_port; - - ENetAddress addr = { ENET_HOST_ANY, listen_port }; - ENetHost* host = enet_host_create( - &addr, // address - 50, // peerCount - 1, // channelLimit - 0, // incomingBandwidth - 0); // outgoingBandwidth - if (!host) - { - g_MainNetHost.reset(); - return false; - } - g_MainNetHost.reset(host); - g_TraversalClient.reset(new TraversalClient(g_MainNetHost.get(), server, server_port)); - } - return true; + ENetAddress addr = {ENET_HOST_ANY, listen_port}; + ENetHost* host = enet_host_create(&addr, // address + 50, // peerCount + 1, // channelLimit + 0, // incomingBandwidth + 0); // outgoingBandwidth + if (!host) + { + g_MainNetHost.reset(); + return false; + } + g_MainNetHost.reset(host); + g_TraversalClient.reset(new TraversalClient(g_MainNetHost.get(), server, server_port)); + } + return true; } void ReleaseTraversalClient() { - if (!g_TraversalClient) - return; + if (!g_TraversalClient) + return; - g_TraversalClient.release(); - g_MainNetHost.release(); + g_TraversalClient.release(); + g_MainNetHost.release(); } diff --git a/Source/Core/Common/TraversalClient.h b/Source/Core/Common/TraversalClient.h index f02f6fe008..6316705889 100644 --- a/Source/Core/Common/TraversalClient.h +++ b/Source/Core/Common/TraversalClient.h @@ -1,11 +1,11 @@ // This file is public domain, in case it's useful to anyone. -comex #pragma once +#include #include #include #include #include -#include #include "Common/Common.h" #include "Common/Thread.h" #include "Common/TraversalProto.h" @@ -13,65 +13,65 @@ class TraversalClientClient { public: - virtual ~TraversalClientClient(){}; - virtual void OnTraversalStateChanged()=0; - virtual void OnConnectReady(ENetAddress addr)=0; - virtual void OnConnectFailed(u8 reason)=0; + virtual ~TraversalClientClient(){}; + virtual void OnTraversalStateChanged() = 0; + virtual void OnConnectReady(ENetAddress addr) = 0; + virtual void OnConnectFailed(u8 reason) = 0; }; class TraversalClient { public: - enum State - { - Connecting, - Connected, - Failure - }; - enum FailureReason - { - BadHost = 0x300, - VersionTooOld, - ServerForgotAboutUs, - SocketSendError, - ResendTimeout, - }; - TraversalClient(ENetHost* netHost, const std::string& server, const u16 port); - ~TraversalClient(); - void Reset(); - void ConnectToClient(const std::string& host); - void ReconnectToServer(); - void Update(); - // called from NetHost - bool TestPacket(u8* data, size_t size, ENetAddress* from); - void HandleResends(); + enum State + { + Connecting, + Connected, + Failure + }; + enum FailureReason + { + BadHost = 0x300, + VersionTooOld, + ServerForgotAboutUs, + SocketSendError, + ResendTimeout, + }; + TraversalClient(ENetHost* netHost, const std::string& server, const u16 port); + ~TraversalClient(); + void Reset(); + void ConnectToClient(const std::string& host); + void ReconnectToServer(); + void Update(); + // called from NetHost + bool TestPacket(u8* data, size_t size, ENetAddress* from); + void HandleResends(); - ENetHost* m_NetHost; - TraversalClientClient* m_Client; - TraversalHostId m_HostId; - State m_State; - int m_FailureReason; + ENetHost* m_NetHost; + TraversalClientClient* m_Client; + TraversalHostId m_HostId; + State m_State; + int m_FailureReason; private: - struct OutgoingTraversalPacketInfo - { - TraversalPacket packet; - int tries; - enet_uint32 sendTime; - }; - void HandleServerPacket(TraversalPacket* packet); - void ResendPacket(OutgoingTraversalPacketInfo* info); - TraversalRequestId SendTraversalPacket(const TraversalPacket& packet); - void OnFailure(FailureReason reason); - void HandlePing(); - static int ENET_CALLBACK InterceptCallback(ENetHost* host, ENetEvent* event); - TraversalRequestId m_ConnectRequestId; - bool m_PendingConnect; - std::list m_OutgoingTraversalPackets; - ENetAddress m_ServerAddress; - std::string m_Server; - u16 m_port; - enet_uint32 m_PingTime; + struct OutgoingTraversalPacketInfo + { + TraversalPacket packet; + int tries; + enet_uint32 sendTime; + }; + void HandleServerPacket(TraversalPacket* packet); + void ResendPacket(OutgoingTraversalPacketInfo* info); + TraversalRequestId SendTraversalPacket(const TraversalPacket& packet); + void OnFailure(FailureReason reason); + void HandlePing(); + static int ENET_CALLBACK InterceptCallback(ENetHost* host, ENetEvent* event); + TraversalRequestId m_ConnectRequestId; + bool m_PendingConnect; + std::list m_OutgoingTraversalPackets; + ENetAddress m_ServerAddress; + std::string m_Server; + u16 m_port; + enet_uint32 m_PingTime; }; extern std::unique_ptr g_TraversalClient; // the NetHost connected to the TraversalClient. diff --git a/Source/Core/Common/TraversalProto.h b/Source/Core/Common/TraversalProto.h index 5036c3dbcc..d0c2a96cde 100644 --- a/Source/Core/Common/TraversalProto.h +++ b/Source/Core/Common/TraversalProto.h @@ -10,87 +10,85 @@ typedef u64 TraversalRequestId; enum TraversalPacketType { - // [*->*] - TraversalPacketAck = 0, - // [c->s] - TraversalPacketPing = 1, - // [c->s] - TraversalPacketHelloFromClient = 2, - // [s->c] - TraversalPacketHelloFromServer = 3, - // [c->s] When connecting, first the client asks the central server... - TraversalPacketConnectPlease = 4, - // [s->c] ...who asks the game host to send a UDP packet to the - // client... (an ack implies success) - TraversalPacketPleaseSendPacket = 5, - // [s->c] ...which the central server relays back to the client. - TraversalPacketConnectReady = 6, - // [s->c] Alternately, the server might not have heard of this host. - TraversalPacketConnectFailed = 7 + // [*->*] + TraversalPacketAck = 0, + // [c->s] + TraversalPacketPing = 1, + // [c->s] + TraversalPacketHelloFromClient = 2, + // [s->c] + TraversalPacketHelloFromServer = 3, + // [c->s] When connecting, first the client asks the central server... + TraversalPacketConnectPlease = 4, + // [s->c] ...who asks the game host to send a UDP packet to the + // client... (an ack implies success) + TraversalPacketPleaseSendPacket = 5, + // [s->c] ...which the central server relays back to the client. + TraversalPacketConnectReady = 6, + // [s->c] Alternately, the server might not have heard of this host. + TraversalPacketConnectFailed = 7 }; enum { - TraversalProtoVersion = 0 + TraversalProtoVersion = 0 }; enum TraversalConnectFailedReason { - TraversalConnectFailedClientDidntRespond = 0, - TraversalConnectFailedClientFailure, - TraversalConnectFailedNoSuchClient + TraversalConnectFailedClientDidntRespond = 0, + TraversalConnectFailedClientFailure, + TraversalConnectFailedNoSuchClient }; #pragma pack(push, 1) struct TraversalInetAddress { - u8 isIPV6; - u32 address[4]; - u16 port; + u8 isIPV6; + u32 address[4]; + u16 port; }; struct TraversalPacket { - u8 type; - TraversalRequestId requestId; - union - { - struct - { - u8 ok; - } ack; - struct - { - TraversalHostId hostId; - } ping; - struct - { - u8 protoVersion; - } helloFromClient; - struct - { - u8 ok; - TraversalHostId yourHostId; - TraversalInetAddress yourAddress; // currently unused - } helloFromServer; - struct - { - TraversalHostId hostId; - } connectPlease; - struct - { - TraversalInetAddress address; - } pleaseSendPacket; - struct - { - TraversalRequestId requestId; - TraversalInetAddress address; - } connectReady; - struct - { - TraversalRequestId requestId; - u8 reason; - } connectFailed; - }; + u8 type; + TraversalRequestId requestId; + union { + struct + { + u8 ok; + } ack; + struct + { + TraversalHostId hostId; + } ping; + struct + { + u8 protoVersion; + } helloFromClient; + struct + { + u8 ok; + TraversalHostId yourHostId; + TraversalInetAddress yourAddress; // currently unused + } helloFromServer; + struct + { + TraversalHostId hostId; + } connectPlease; + struct + { + TraversalInetAddress address; + } pleaseSendPacket; + struct + { + TraversalRequestId requestId; + TraversalInetAddress address; + } connectReady; + struct + { + TraversalRequestId requestId; + u8 reason; + } connectFailed; + }; }; #pragma pack(pop) - diff --git a/Source/Core/Common/TraversalServer.cpp b/Source/Core/Common/TraversalServer.cpp index db6cfb294a..d62e647ad6 100644 --- a/Source/Core/Common/TraversalServer.cpp +++ b/Source/Core/Common/TraversalServer.cpp @@ -1,20 +1,20 @@ // This file is public domain, in case it's useful to anyone. -comex // The central server implementation. +#include #include #include #include #include #include -#include -#include -#include -#include -#include #include #include #include #include +#include +#include +#include +#include #include "Common/TraversalProto.h" #define DEBUG 1 @@ -24,436 +24,431 @@ static u64 currentTime; struct OutgoingPacketInfo { - TraversalPacket packet; - TraversalRequestId misc; - sockaddr_in6 dest; - int tries; - u64 sendTime; + TraversalPacket packet; + TraversalRequestId misc; + sockaddr_in6 dest; + int tries; + u64 sendTime; }; template struct EvictEntry { - u64 updateTime; - T value; + u64 updateTime; + T value; }; template struct EvictFindResult { - bool found; - V* value; + bool found; + V* value; }; template -EvictFindResult EvictFind(std::unordered_map>& map, const K& key, bool refresh = false) +EvictFindResult EvictFind(std::unordered_map>& map, const K& key, + bool refresh = false) { - retry: - const u64 expiryTime = 30 * 1000000; // 30s - EvictFindResult result; - if (map.bucket_count()) - { - auto bucket = map.bucket(key); - auto it = map.begin(bucket); - for (; it != map.end(bucket); ++it) - { - if (currentTime - it->second.updateTime > expiryTime) - { - map.erase(it->first); - goto retry; - } - if (it->first == key) - { - if (refresh) - it->second.updateTime = currentTime; - result.found = true; - result.value = &it->second.value; - return result; - } - } - } +retry: + const u64 expiryTime = 30 * 1000000; // 30s + EvictFindResult result; + if (map.bucket_count()) + { + auto bucket = map.bucket(key); + auto it = map.begin(bucket); + for (; it != map.end(bucket); ++it) + { + if (currentTime - it->second.updateTime > expiryTime) + { + map.erase(it->first); + goto retry; + } + if (it->first == key) + { + if (refresh) + it->second.updateTime = currentTime; + result.found = true; + result.value = &it->second.value; + return result; + } + } + } #if DEBUG - printf("failed to find key '"); - for (size_t i = 0; i < sizeof(key); i++) { - printf("%02x", ((u8*) &key)[i]); - } - printf("'\n"); + printf("failed to find key '"); + for (size_t i = 0; i < sizeof(key); i++) + { + printf("%02x", ((u8*)&key)[i]); + } + printf("'\n"); #endif - result.found = false; - return result; + result.found = false; + return result; } template V* EvictSet(std::unordered_map>& map, const K& key) { - // can't use a local_iterator to emplace... - auto& result = map[key]; - result.updateTime = currentTime; - return &result.value; + // can't use a local_iterator to emplace... + auto& result = map[key]; + result.updateTime = currentTime; + return &result.value; } namespace std { - template <> - struct hash - { - size_t operator()(const TraversalHostId& id) const - { - auto p = (u32*) id.data(); - return p[0] ^ ((p[1] << 13) | (p[1] >> 19)); - } - }; +template <> +struct hash +{ + size_t operator()(const TraversalHostId& id) const + { + auto p = (u32*)id.data(); + return p[0] ^ ((p[1] << 13) | (p[1] >> 19)); + } +}; } static int sock; static int urandomFd; -static std::unordered_map< - TraversalRequestId, - OutgoingPacketInfo -> outgoingPackets; -static std::unordered_map< - TraversalHostId, - EvictEntry -> connectedClients; +static std::unordered_map outgoingPackets; +static std::unordered_map> connectedClients; static TraversalInetAddress MakeInetAddress(const sockaddr_in6& addr) { - if (addr.sin6_family != AF_INET6) - { - fprintf(stderr, "bad sockaddr_in6\n"); - exit(1); - } - u32* words = (u32*) addr.sin6_addr.s6_addr; - TraversalInetAddress result = {0}; - if (words[0] == 0 && words[1] == 0 && words[2] == 0xffff0000) - { - result.isIPV6 = false; - result.address[0] = words[3]; - } - else - { - result.isIPV6 = true; - memcpy(result.address, words, sizeof(result.address)); - } - result.port = addr.sin6_port; - return result; + if (addr.sin6_family != AF_INET6) + { + fprintf(stderr, "bad sockaddr_in6\n"); + exit(1); + } + u32* words = (u32*)addr.sin6_addr.s6_addr; + TraversalInetAddress result = {0}; + if (words[0] == 0 && words[1] == 0 && words[2] == 0xffff0000) + { + result.isIPV6 = false; + result.address[0] = words[3]; + } + else + { + result.isIPV6 = true; + memcpy(result.address, words, sizeof(result.address)); + } + result.port = addr.sin6_port; + return result; } static sockaddr_in6 MakeSinAddr(const TraversalInetAddress& addr) { - sockaddr_in6 result; + sockaddr_in6 result; #ifdef SIN6_LEN - result.sin6_len = sizeof(result); + result.sin6_len = sizeof(result); #endif - result.sin6_family = AF_INET6; - result.sin6_port = addr.port; - result.sin6_flowinfo = 0; - if (addr.isIPV6) - { - memcpy(&result.sin6_addr, addr.address, 16); - } - else - { - u32* words = (u32*) result.sin6_addr.s6_addr; - words[0] = 0; - words[1] = 0; - words[2] = 0xffff0000; - words[3] = addr.address[0]; - } - result.sin6_scope_id = 0; - return result; + result.sin6_family = AF_INET6; + result.sin6_port = addr.port; + result.sin6_flowinfo = 0; + if (addr.isIPV6) + { + memcpy(&result.sin6_addr, addr.address, 16); + } + else + { + u32* words = (u32*)result.sin6_addr.s6_addr; + words[0] = 0; + words[1] = 0; + words[2] = 0xffff0000; + words[3] = addr.address[0]; + } + result.sin6_scope_id = 0; + return result; } static void GetRandomBytes(void* output, size_t size) { - static u8 bytes[8192]; - static size_t bytesLeft = 0; - if (bytesLeft < size) - { - ssize_t rv = read(urandomFd, bytes, sizeof(bytes)); - if (rv != sizeof(bytes)) - { - perror("read from /dev/urandom"); - exit(1); - } - bytesLeft = sizeof(bytes); - } - memcpy(output, bytes + (bytesLeft -= size), size); + static u8 bytes[8192]; + static size_t bytesLeft = 0; + if (bytesLeft < size) + { + ssize_t rv = read(urandomFd, bytes, sizeof(bytes)); + if (rv != sizeof(bytes)) + { + perror("read from /dev/urandom"); + exit(1); + } + bytesLeft = sizeof(bytes); + } + memcpy(output, bytes + (bytesLeft -= size), size); } static void GetRandomHostId(TraversalHostId* hostId) { - char buf[9]; - u32 num; - GetRandomBytes(&num, sizeof(num)); - sprintf(buf, "%08x", num); - memcpy(hostId->data(), buf, 8); + char buf[9]; + u32 num; + GetRandomBytes(&num, sizeof(num)); + sprintf(buf, "%08x", num); + memcpy(hostId->data(), buf, 8); } static const char* SenderName(sockaddr_in6* addr) { - static char buf[INET6_ADDRSTRLEN + 10]; - inet_ntop(PF_INET6, &addr->sin6_addr, buf, sizeof(buf)); - sprintf(buf + strlen(buf), ":%d", ntohs(addr->sin6_port)); - return buf; + static char buf[INET6_ADDRSTRLEN + 10]; + inet_ntop(PF_INET6, &addr->sin6_addr, buf, sizeof(buf)); + sprintf(buf + strlen(buf), ":%d", ntohs(addr->sin6_port)); + return buf; } static void TrySend(const void* buffer, size_t size, sockaddr_in6* addr) { #if DEBUG - printf("-> %d %llu %s\n", ((TraversalPacket*) buffer)->type, - (long long)((TraversalPacket*) buffer)->requestId, SenderName(addr)); + printf("-> %d %llu %s\n", ((TraversalPacket*)buffer)->type, + (long long)((TraversalPacket*)buffer)->requestId, SenderName(addr)); #endif - if ((size_t) sendto(sock, buffer, size, 0, (sockaddr*) addr, sizeof(*addr)) != size) - { - perror("sendto"); - } + if ((size_t)sendto(sock, buffer, size, 0, (sockaddr*)addr, sizeof(*addr)) != size) + { + perror("sendto"); + } } static TraversalPacket* AllocPacket(const sockaddr_in6& dest, TraversalRequestId misc = 0) { - TraversalRequestId requestId; - GetRandomBytes(&requestId, sizeof(requestId)); - OutgoingPacketInfo* info = &outgoingPackets[requestId]; - info->dest = dest; - info->misc = misc; - info->tries = 0; - info->sendTime = currentTime; - TraversalPacket* result = &info->packet; - memset(result, 0, sizeof(*result)); - result->requestId = requestId; - return result; + TraversalRequestId requestId; + GetRandomBytes(&requestId, sizeof(requestId)); + OutgoingPacketInfo* info = &outgoingPackets[requestId]; + info->dest = dest; + info->misc = misc; + info->tries = 0; + info->sendTime = currentTime; + TraversalPacket* result = &info->packet; + memset(result, 0, sizeof(*result)); + result->requestId = requestId; + return result; } static void SendPacket(OutgoingPacketInfo* info) { - info->tries++; - info->sendTime = currentTime; - TrySend(&info->packet, sizeof(info->packet), &info->dest); + info->tries++; + info->sendTime = currentTime; + TrySend(&info->packet, sizeof(info->packet), &info->dest); } - static void ResendPackets() { - std::vector> todoFailures; - todoFailures.clear(); - for (auto it = outgoingPackets.begin(); it != outgoingPackets.end();) - { - OutgoingPacketInfo* info = &it->second; - if (currentTime - info->sendTime >= (u64) (300000 * info->tries)) - { - if (info->tries >= NUMBER_OF_TRIES) - { - if (info->packet.type == TraversalPacketPleaseSendPacket) - { - todoFailures.push_back(std::make_pair(info->packet.pleaseSendPacket.address, info->misc)); - } - it = outgoingPackets.erase(it); - continue; - } - else - { - SendPacket(info); - } - } - ++it; - } + std::vector> todoFailures; + todoFailures.clear(); + for (auto it = outgoingPackets.begin(); it != outgoingPackets.end();) + { + OutgoingPacketInfo* info = &it->second; + if (currentTime - info->sendTime >= (u64)(300000 * info->tries)) + { + if (info->tries >= NUMBER_OF_TRIES) + { + if (info->packet.type == TraversalPacketPleaseSendPacket) + { + todoFailures.push_back(std::make_pair(info->packet.pleaseSendPacket.address, info->misc)); + } + it = outgoingPackets.erase(it); + continue; + } + else + { + SendPacket(info); + } + } + ++it; + } - for (const auto& p : todoFailures) - { - TraversalPacket* fail = AllocPacket(MakeSinAddr(p.first)); - fail->type = TraversalPacketConnectFailed; - fail->connectFailed.requestId = p.second; - fail->connectFailed.reason = TraversalConnectFailedClientDidntRespond; - } + for (const auto& p : todoFailures) + { + TraversalPacket* fail = AllocPacket(MakeSinAddr(p.first)); + fail->type = TraversalPacketConnectFailed; + fail->connectFailed.requestId = p.second; + fail->connectFailed.reason = TraversalConnectFailedClientDidntRespond; + } } static void HandlePacket(TraversalPacket* packet, sockaddr_in6* addr) { #if DEBUG - printf("<- %d %llu %s\n", packet->type, (long long)packet->requestId, SenderName(addr)); + printf("<- %d %llu %s\n", packet->type, (long long)packet->requestId, SenderName(addr)); #endif - bool packetOk = true; - switch (packet->type) - { - case TraversalPacketAck: - { - auto it = outgoingPackets.find(packet->requestId); - if (it == outgoingPackets.end()) - break; + bool packetOk = true; + switch (packet->type) + { + case TraversalPacketAck: + { + auto it = outgoingPackets.find(packet->requestId); + if (it == outgoingPackets.end()) + break; - OutgoingPacketInfo* info = &it->second; + OutgoingPacketInfo* info = &it->second; - if (info->packet.type == TraversalPacketPleaseSendPacket) - { - TraversalPacket* ready = AllocPacket(MakeSinAddr(info->packet.pleaseSendPacket.address)); - if (packet->ack.ok) - { - ready->type = TraversalPacketConnectReady; - ready->connectReady.requestId = info->misc; - ready->connectReady.address = MakeInetAddress(info->dest); - } - else - { - ready->type = TraversalPacketConnectFailed; - ready->connectFailed.requestId = info->misc; - ready->connectFailed.reason = TraversalConnectFailedClientFailure; - } - } + if (info->packet.type == TraversalPacketPleaseSendPacket) + { + TraversalPacket* ready = AllocPacket(MakeSinAddr(info->packet.pleaseSendPacket.address)); + if (packet->ack.ok) + { + ready->type = TraversalPacketConnectReady; + ready->connectReady.requestId = info->misc; + ready->connectReady.address = MakeInetAddress(info->dest); + } + else + { + ready->type = TraversalPacketConnectFailed; + ready->connectFailed.requestId = info->misc; + ready->connectFailed.reason = TraversalConnectFailedClientFailure; + } + } - outgoingPackets.erase(it); - break; - } - case TraversalPacketPing: - { - auto r = EvictFind(connectedClients, packet->ping.hostId, true); - packetOk = r.found; - break; - } - case TraversalPacketHelloFromClient: - { - u8 ok = packet->helloFromClient.protoVersion <= TraversalProtoVersion; - TraversalPacket* reply = AllocPacket(*addr); - reply->type = TraversalPacketHelloFromServer; - reply->helloFromServer.ok = ok; - if (ok) - { - TraversalHostId hostId; - TraversalInetAddress* iaddr; - // not that there is any significant change of - // duplication, but... - GetRandomHostId(&hostId); - while (true) - { - auto r = EvictFind(connectedClients, hostId); - if (!r.found) - { - iaddr = EvictSet(connectedClients, hostId); - break; - } - } + outgoingPackets.erase(it); + break; + } + case TraversalPacketPing: + { + auto r = EvictFind(connectedClients, packet->ping.hostId, true); + packetOk = r.found; + break; + } + case TraversalPacketHelloFromClient: + { + u8 ok = packet->helloFromClient.protoVersion <= TraversalProtoVersion; + TraversalPacket* reply = AllocPacket(*addr); + reply->type = TraversalPacketHelloFromServer; + reply->helloFromServer.ok = ok; + if (ok) + { + TraversalHostId hostId; + TraversalInetAddress* iaddr; + // not that there is any significant change of + // duplication, but... + GetRandomHostId(&hostId); + while (true) + { + auto r = EvictFind(connectedClients, hostId); + if (!r.found) + { + iaddr = EvictSet(connectedClients, hostId); + break; + } + } - *iaddr = MakeInetAddress(*addr); + *iaddr = MakeInetAddress(*addr); - reply->helloFromServer.yourAddress = *iaddr; - reply->helloFromServer.yourHostId = hostId; - } - break; - } - case TraversalPacketConnectPlease: - { - TraversalHostId& hostId = packet->connectPlease.hostId; - auto r = EvictFind(connectedClients, hostId); - if (!r.found) - { - TraversalPacket* reply = AllocPacket(*addr); - reply->type = TraversalPacketConnectFailed; - reply->connectFailed.requestId = packet->requestId; - reply->connectFailed.reason = TraversalConnectFailedNoSuchClient; - } - else - { - TraversalPacket* please = AllocPacket(MakeSinAddr(*r.value), packet->requestId); - please->type = TraversalPacketPleaseSendPacket; - please->pleaseSendPacket.address = MakeInetAddress(*addr); - } - break; - } - default: - fprintf(stderr, "received unknown packet type %d from %s\n", packet->type, SenderName(addr)); - } - if (packet->type != TraversalPacketAck) - { - TraversalPacket ack = {}; - ack.type = TraversalPacketAck; - ack.requestId = packet->requestId; - ack.ack.ok = packetOk; - TrySend(&ack, sizeof(ack), addr); - } + reply->helloFromServer.yourAddress = *iaddr; + reply->helloFromServer.yourHostId = hostId; + } + break; + } + case TraversalPacketConnectPlease: + { + TraversalHostId& hostId = packet->connectPlease.hostId; + auto r = EvictFind(connectedClients, hostId); + if (!r.found) + { + TraversalPacket* reply = AllocPacket(*addr); + reply->type = TraversalPacketConnectFailed; + reply->connectFailed.requestId = packet->requestId; + reply->connectFailed.reason = TraversalConnectFailedNoSuchClient; + } + else + { + TraversalPacket* please = AllocPacket(MakeSinAddr(*r.value), packet->requestId); + please->type = TraversalPacketPleaseSendPacket; + please->pleaseSendPacket.address = MakeInetAddress(*addr); + } + break; + } + default: + fprintf(stderr, "received unknown packet type %d from %s\n", packet->type, SenderName(addr)); + } + if (packet->type != TraversalPacketAck) + { + TraversalPacket ack = {}; + ack.type = TraversalPacketAck; + ack.requestId = packet->requestId; + ack.ack.ok = packetOk; + TrySend(&ack, sizeof(ack), addr); + } } int main() { - int rv; + int rv; - urandomFd = open("/dev/urandom", O_RDONLY); - if (urandomFd < 0) - { - perror("open /dev/urandom"); - return 1; - } + urandomFd = open("/dev/urandom", O_RDONLY); + if (urandomFd < 0) + { + perror("open /dev/urandom"); + return 1; + } - sock = socket(PF_INET6, SOCK_DGRAM, 0); - if (sock == -1) - { - perror("socket"); - return 1; - } - int no = 0; - rv = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)); - if (rv < 0) - { - perror("setsockopt IPV6_V6ONLY"); - return 1; - } - in6_addr any = IN6ADDR_ANY_INIT; - sockaddr_in6 addr; + sock = socket(PF_INET6, SOCK_DGRAM, 0); + if (sock == -1) + { + perror("socket"); + return 1; + } + int no = 0; + rv = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)); + if (rv < 0) + { + perror("setsockopt IPV6_V6ONLY"); + return 1; + } + in6_addr any = IN6ADDR_ANY_INIT; + sockaddr_in6 addr; #ifdef SIN6_LEN - addr.sin6_len = sizeof(addr); + addr.sin6_len = sizeof(addr); #endif - addr.sin6_family = AF_INET6; - addr.sin6_port = htons(6262); - addr.sin6_flowinfo = 0; - addr.sin6_addr = any; - addr.sin6_scope_id = 0; + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(6262); + addr.sin6_flowinfo = 0; + addr.sin6_addr = any; + addr.sin6_scope_id = 0; - rv = bind(sock, (sockaddr*) &addr, sizeof(addr)); - if (rv < 0) - { - perror("bind"); - return 1; - } + rv = bind(sock, (sockaddr*)&addr, sizeof(addr)); + if (rv < 0) + { + perror("bind"); + return 1; + } - timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 300000; - rv = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); - if (rv < 0) - { - perror("setsockopt SO_RCVTIMEO"); - return 1; - } + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 300000; + rv = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + if (rv < 0) + { + perror("setsockopt SO_RCVTIMEO"); + return 1; + } - while (true) - { - sockaddr_in6 raddr; - socklen_t addrLen = sizeof(raddr); - TraversalPacket packet; - // note: switch to recvmmsg (yes, mmsg) if this becomes - // expensive - rv = recvfrom(sock, &packet, sizeof(packet), 0, (sockaddr*) &raddr, &addrLen); - if (gettimeofday(&tv, nullptr) < 0) - { - perror("gettimeofday"); - exit(1); - } - currentTime = (u64) tv.tv_sec * 1000000 + tv.tv_usec; - if (rv < 0) - { - if (errno != EINTR && errno != EAGAIN) - { - perror("recvfrom"); - return 1; - } - } - else if ((size_t) rv < sizeof(packet)) - { - fprintf(stderr, "received short packet from %s\n", SenderName(&raddr)); - } - else - { - HandlePacket(&packet, &raddr); - } - ResendPackets(); - } + while (true) + { + sockaddr_in6 raddr; + socklen_t addrLen = sizeof(raddr); + TraversalPacket packet; + // note: switch to recvmmsg (yes, mmsg) if this becomes + // expensive + rv = recvfrom(sock, &packet, sizeof(packet), 0, (sockaddr*)&raddr, &addrLen); + if (gettimeofday(&tv, nullptr) < 0) + { + perror("gettimeofday"); + exit(1); + } + currentTime = (u64)tv.tv_sec * 1000000 + tv.tv_usec; + if (rv < 0) + { + if (errno != EINTR && errno != EAGAIN) + { + perror("recvfrom"); + return 1; + } + } + else if ((size_t)rv < sizeof(packet)) + { + fprintf(stderr, "received short packet from %s\n", SenderName(&raddr)); + } + else + { + HandlePacket(&packet, &raddr); + } + ResendPackets(); + } } diff --git a/Source/Core/Common/Version.cpp b/Source/Core/Common/Version.cpp index c02a83a21c..c21896afdc 100644 --- a/Source/Core/Common/Version.cpp +++ b/Source/Core/Common/Version.cpp @@ -2,26 +2,26 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "scmrev.h" #include "Common/Common.h" +#include "scmrev.h" #ifdef _DEBUG - #define BUILD_TYPE_STR "Debug " +#define BUILD_TYPE_STR "Debug " #elif defined DEBUGFAST - #define BUILD_TYPE_STR "DebugFast " +#define BUILD_TYPE_STR "DebugFast " #else - #define BUILD_TYPE_STR "" +#define BUILD_TYPE_STR "" #endif const std::string scm_rev_str = "Dolphin " #if !SCM_IS_MASTER - "[" SCM_BRANCH_STR "] " + "[" SCM_BRANCH_STR "] " #endif #ifdef __INTEL_COMPILER - BUILD_TYPE_STR SCM_DESC_STR "-ICC"; + BUILD_TYPE_STR SCM_DESC_STR "-ICC"; #else - BUILD_TYPE_STR SCM_DESC_STR; + BUILD_TYPE_STR SCM_DESC_STR; #endif #ifdef _WIN32 @@ -29,7 +29,7 @@ const std::string netplay_dolphin_ver = SCM_DESC_STR " Win"; #elif __APPLE__ const std::string netplay_dolphin_ver = SCM_DESC_STR " Mac"; #else -const std::string netplay_dolphin_ver = SCM_DESC_STR " Lin"; + const std::string netplay_dolphin_ver = SCM_DESC_STR " Lin"; #endif const std::string scm_rev_git_str = SCM_REV_STR; diff --git a/Source/Core/Common/ucrtFreadWorkaround.cpp b/Source/Core/Common/ucrtFreadWorkaround.cpp index 549c2d9ac5..80ad855fec 100644 --- a/Source/Core/Common/ucrtFreadWorkaround.cpp +++ b/Source/Core/Common/ucrtFreadWorkaround.cpp @@ -4,74 +4,79 @@ #if defined(_WIN32) -#include "CommonTypes.h" #include +#include "CommonTypes.h" -struct PatchInfo { - const wchar_t* module_name; - u32 checksum; - u32 rva; - u32 length; +struct PatchInfo +{ + const wchar_t* module_name; + u32 checksum; + u32 rva; + u32 length; } static const s_patches[] = { - // 10.0.10240.16384 (th1.150709-1700) - { L"ucrtbase.dll", 0xF61ED, 0x6AE7B, 5 }, - // 10.0.10240.16390 (th1_st1.150714-1601) - { L"ucrtbase.dll", 0xF5ED9, 0x6AE7B, 5 }, - // 10.0.10137.0 (th1.150602-2238) - { L"ucrtbase.dll", 0xF8B5E, 0x63ED6, 2 }, - // 10.0.10150.0 (th1.150616-1659) - { L"ucrtbased.dll", 0x1C1915 , 0x91905, 5 }, + // 10.0.10240.16384 (th1.150709-1700) + {L"ucrtbase.dll", 0xF61ED, 0x6AE7B, 5}, + // 10.0.10240.16390 (th1_st1.150714-1601) + {L"ucrtbase.dll", 0xF5ED9, 0x6AE7B, 5}, + // 10.0.10137.0 (th1.150602-2238) + {L"ucrtbase.dll", 0xF8B5E, 0x63ED6, 2}, + // 10.0.10150.0 (th1.150616-1659) + {L"ucrtbased.dll", 0x1C1915, 0x91905, 5}, }; -bool ApplyPatch(const PatchInfo& patch) { - auto module = GetModuleHandleW(patch.module_name); - if (module == nullptr) - { - return false; - } +bool ApplyPatch(const PatchInfo& patch) +{ + auto module = GetModuleHandleW(patch.module_name); + if (module == nullptr) + { + return false; + } - auto ucrtbase_pe = (PIMAGE_NT_HEADERS)((uintptr_t)module + ((PIMAGE_DOS_HEADER)module)->e_lfanew); - if (ucrtbase_pe->OptionalHeader.CheckSum != patch.checksum) { - return false; - } + auto ucrtbase_pe = (PIMAGE_NT_HEADERS)((uintptr_t)module + ((PIMAGE_DOS_HEADER)module)->e_lfanew); + if (ucrtbase_pe->OptionalHeader.CheckSum != patch.checksum) + { + return false; + } - void* patch_addr = (void*)((uintptr_t)module + patch.rva); - size_t patch_size = patch.length; + void* patch_addr = (void*)((uintptr_t)module + patch.rva); + size_t patch_size = patch.length; - DWORD old_protect; - if (!VirtualProtect(patch_addr, patch_size, PAGE_EXECUTE_READWRITE, &old_protect)) - { - return false; - } + DWORD old_protect; + if (!VirtualProtect(patch_addr, patch_size, PAGE_EXECUTE_READWRITE, &old_protect)) + { + return false; + } - memset(patch_addr, 0x90, patch_size); + memset(patch_addr, 0x90, patch_size); - VirtualProtect(patch_addr, patch_size, old_protect, &old_protect); + VirtualProtect(patch_addr, patch_size, old_protect, &old_protect); - FlushInstructionCache(GetCurrentProcess(), patch_addr, patch_size); + FlushInstructionCache(GetCurrentProcess(), patch_addr, patch_size); - return true; + return true; } int __cdecl EnableucrtFreadWorkaround() { - // This patches ucrtbase such that fseek will always - // synchronize the file object's internal buffer. + // This patches ucrtbase such that fseek will always + // synchronize the file object's internal buffer. - bool applied_at_least_one = false; - for (const auto &patch : s_patches) { - if (ApplyPatch(patch)) { - applied_at_least_one = true; - } - } + bool applied_at_least_one = false; + for (const auto& patch : s_patches) + { + if (ApplyPatch(patch)) + { + applied_at_least_one = true; + } + } - /* For forward compat, do not fail if patches don't apply (e.g. version mismatch) - if (!applied_at_least_one) { - std::abort(); - } - //*/ + /* For forward compat, do not fail if patches don't apply (e.g. version mismatch) + if (!applied_at_least_one) { + std::abort(); + } + //*/ - return 0; + return 0; } // Create a segment which is recognized by the linker to be part of the CRT @@ -84,8 +89,8 @@ int __cdecl EnableucrtFreadWorkaround() // referencing it doesn't require ugly decorated names. // Use /include:EnableucrtFreadWorkaround linker flag to enable this. extern "C" { - __declspec(allocate(".CRT$XIB")) - decltype(&EnableucrtFreadWorkaround) ucrtFreadWorkaround = EnableucrtFreadWorkaround; +__declspec(allocate(".CRT$XIB")) decltype(&EnableucrtFreadWorkaround) + ucrtFreadWorkaround = EnableucrtFreadWorkaround; }; #endif diff --git a/Source/Core/Common/x64ABI.cpp b/Source/Core/Common/x64ABI.cpp index d13d612b43..2a19934e29 100644 --- a/Source/Core/Common/x64ABI.cpp +++ b/Source/Core/Common/x64ABI.cpp @@ -2,233 +2,238 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Common/CommonTypes.h" #include "Common/x64ABI.h" +#include "Common/CommonTypes.h" #include "Common/x64Emitter.h" using namespace Gen; // Shared code between Win64 and Unix64 -void XEmitter::ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size, size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp) +void XEmitter::ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size, + size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp) { - size_t shadow = 0; + size_t shadow = 0; #if defined(_WIN32) - shadow = 0x20; + shadow = 0x20; #endif - int count = (mask & ABI_ALL_GPRS).Count(); - rsp_alignment -= count * 8; - size_t subtraction = 0; - int fpr_count = (mask & ABI_ALL_FPRS).Count(); - if (fpr_count) - { - // If we have any XMMs to save, we must align the stack here. - subtraction = rsp_alignment & 0xf; - } - subtraction += 16 * fpr_count; - size_t xmm_base_subtraction = subtraction; - subtraction += needed_frame_size; - subtraction += shadow; - // Final alignment. - rsp_alignment -= subtraction; - subtraction += rsp_alignment & 0xf; + int count = (mask & ABI_ALL_GPRS).Count(); + rsp_alignment -= count * 8; + size_t subtraction = 0; + int fpr_count = (mask & ABI_ALL_FPRS).Count(); + if (fpr_count) + { + // If we have any XMMs to save, we must align the stack here. + subtraction = rsp_alignment & 0xf; + } + subtraction += 16 * fpr_count; + size_t xmm_base_subtraction = subtraction; + subtraction += needed_frame_size; + subtraction += shadow; + // Final alignment. + rsp_alignment -= subtraction; + subtraction += rsp_alignment & 0xf; - *shadowp = shadow; - *subtractionp = subtraction; - *xmm_offsetp = subtraction - xmm_base_subtraction; + *shadowp = shadow; + *subtractionp = subtraction; + *xmm_offsetp = subtraction - xmm_base_subtraction; } -size_t XEmitter::ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size) +size_t XEmitter::ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, + size_t needed_frame_size) { - size_t shadow, subtraction, xmm_offset; - ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction, &xmm_offset); + size_t shadow, subtraction, xmm_offset; + ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction, + &xmm_offset); - for (int r : mask & ABI_ALL_GPRS) - PUSH((X64Reg)r); + for (int r : mask& ABI_ALL_GPRS) + PUSH((X64Reg)r); - if (subtraction) - SUB(64, R(RSP), subtraction >= 0x80 ? Imm32((u32)subtraction) : Imm8((u8)subtraction)); + if (subtraction) + SUB(64, R(RSP), subtraction >= 0x80 ? Imm32((u32)subtraction) : Imm8((u8)subtraction)); - for (int x : mask & ABI_ALL_FPRS) - { - MOVAPD(MDisp(RSP, (int)xmm_offset), (X64Reg)(x - 16)); - xmm_offset += 16; - } + for (int x : mask& ABI_ALL_FPRS) + { + MOVAPD(MDisp(RSP, (int)xmm_offset), (X64Reg)(x - 16)); + xmm_offset += 16; + } - return shadow; + return shadow; } -void XEmitter::ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size) +void XEmitter::ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, + size_t needed_frame_size) { - size_t shadow, subtraction, xmm_offset; - ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction, &xmm_offset); + size_t shadow, subtraction, xmm_offset; + ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction, + &xmm_offset); - for (int x : mask & ABI_ALL_FPRS) - { - MOVAPD((X64Reg) (x - 16), MDisp(RSP, (int)xmm_offset)); - xmm_offset += 16; - } + for (int x : mask& ABI_ALL_FPRS) + { + MOVAPD((X64Reg)(x - 16), MDisp(RSP, (int)xmm_offset)); + xmm_offset += 16; + } - if (subtraction) - ADD(64, R(RSP), subtraction >= 0x80 ? Imm32((u32)subtraction) : Imm8((u8)subtraction)); + if (subtraction) + ADD(64, R(RSP), subtraction >= 0x80 ? Imm32((u32)subtraction) : Imm8((u8)subtraction)); - for (int r = 15; r >= 0; r--) - { - if (mask[r]) - POP((X64Reg)r); - } + for (int r = 15; r >= 0; r--) + { + if (mask[r]) + POP((X64Reg)r); + } } // Common functions void XEmitter::ABI_CallFunction(const void* func) { - u64 distance = u64(func) - (u64(code) + 5); - if (distance >= 0x0000000080000000ULL && - distance < 0xFFFFFFFF80000000ULL) - { - // Far call - MOV(64, R(RAX), Imm64((u64)func)); - CALLptr(R(RAX)); - } - else - { - CALL(func); - } + u64 distance = u64(func) - (u64(code) + 5); + if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) + { + // Far call + MOV(64, R(RAX), Imm64((u64)func)); + CALLptr(R(RAX)); + } + else + { + CALL(func); + } } void XEmitter::ABI_CallFunctionC16(const void* func, u16 param1) { - MOV(32, R(ABI_PARAM1), Imm32((u32)param1)); - ABI_CallFunction(func); + MOV(32, R(ABI_PARAM1), Imm32((u32)param1)); + ABI_CallFunction(func); } void XEmitter::ABI_CallFunctionCC16(const void* func, u32 param1, u16 param2) { - MOV(32, R(ABI_PARAM1), Imm32(param1)); - MOV(32, R(ABI_PARAM2), Imm32((u32)param2)); - ABI_CallFunction(func); + MOV(32, R(ABI_PARAM1), Imm32(param1)); + MOV(32, R(ABI_PARAM2), Imm32((u32)param2)); + ABI_CallFunction(func); } void XEmitter::ABI_CallFunctionC(const void* func, u32 param1) { - MOV(32, R(ABI_PARAM1), Imm32(param1)); - ABI_CallFunction(func); + MOV(32, R(ABI_PARAM1), Imm32(param1)); + ABI_CallFunction(func); } void XEmitter::ABI_CallFunctionCC(const void* func, u32 param1, u32 param2) { - MOV(32, R(ABI_PARAM1), Imm32(param1)); - MOV(32, R(ABI_PARAM2), Imm32(param2)); - ABI_CallFunction(func); + MOV(32, R(ABI_PARAM1), Imm32(param1)); + MOV(32, R(ABI_PARAM2), Imm32(param2)); + ABI_CallFunction(func); } void XEmitter::ABI_CallFunctionCP(const void* func, u32 param1, void* param2) { - MOV(32, R(ABI_PARAM1), Imm32(param1)); - MOV(64, R(ABI_PARAM2), Imm64((u64)param2)); - ABI_CallFunction(func); + MOV(32, R(ABI_PARAM1), Imm32(param1)); + MOV(64, R(ABI_PARAM2), Imm64((u64)param2)); + ABI_CallFunction(func); } void XEmitter::ABI_CallFunctionCCC(const void* func, u32 param1, u32 param2, u32 param3) { - MOV(32, R(ABI_PARAM1), Imm32(param1)); - MOV(32, R(ABI_PARAM2), Imm32(param2)); - MOV(32, R(ABI_PARAM3), Imm32(param3)); - ABI_CallFunction(func); + MOV(32, R(ABI_PARAM1), Imm32(param1)); + MOV(32, R(ABI_PARAM2), Imm32(param2)); + MOV(32, R(ABI_PARAM3), Imm32(param3)); + ABI_CallFunction(func); } void XEmitter::ABI_CallFunctionCCP(const void* func, u32 param1, u32 param2, void* param3) { - MOV(32, R(ABI_PARAM1), Imm32(param1)); - MOV(32, R(ABI_PARAM2), Imm32(param2)); - MOV(64, R(ABI_PARAM3), Imm64((u64)param3)); - ABI_CallFunction(func); + MOV(32, R(ABI_PARAM1), Imm32(param1)); + MOV(32, R(ABI_PARAM2), Imm32(param2)); + MOV(64, R(ABI_PARAM3), Imm64((u64)param3)); + ABI_CallFunction(func); } -void XEmitter::ABI_CallFunctionCCCP(const void* func, u32 param1, u32 param2, u32 param3, void* param4) +void XEmitter::ABI_CallFunctionCCCP(const void* func, u32 param1, u32 param2, u32 param3, + void* param4) { - MOV(32, R(ABI_PARAM1), Imm32(param1)); - MOV(32, R(ABI_PARAM2), Imm32(param2)); - MOV(32, R(ABI_PARAM3), Imm32(param3)); - MOV(64, R(ABI_PARAM4), Imm64((u64)param4)); - ABI_CallFunction(func); + MOV(32, R(ABI_PARAM1), Imm32(param1)); + MOV(32, R(ABI_PARAM2), Imm32(param2)); + MOV(32, R(ABI_PARAM3), Imm32(param3)); + MOV(64, R(ABI_PARAM4), Imm64((u64)param4)); + ABI_CallFunction(func); } void XEmitter::ABI_CallFunctionPC(const void* func, void* param1, u32 param2) { - MOV(64, R(ABI_PARAM1), Imm64((u64)param1)); - MOV(32, R(ABI_PARAM2), Imm32(param2)); - ABI_CallFunction(func); + MOV(64, R(ABI_PARAM1), Imm64((u64)param1)); + MOV(32, R(ABI_PARAM2), Imm32(param2)); + ABI_CallFunction(func); } void XEmitter::ABI_CallFunctionPPC(const void* func, void* param1, void* param2, u32 param3) { - MOV(64, R(ABI_PARAM1), Imm64((u64)param1)); - MOV(64, R(ABI_PARAM2), Imm64((u64)param2)); - MOV(32, R(ABI_PARAM3), Imm32(param3)); - ABI_CallFunction(func); + MOV(64, R(ABI_PARAM1), Imm64((u64)param1)); + MOV(64, R(ABI_PARAM2), Imm64((u64)param2)); + MOV(32, R(ABI_PARAM3), Imm32(param3)); + ABI_CallFunction(func); } // Pass a register as a parameter. void XEmitter::ABI_CallFunctionR(const void* func, X64Reg reg1) { - if (reg1 != ABI_PARAM1) - MOV(32, R(ABI_PARAM1), R(reg1)); - ABI_CallFunction(func); + if (reg1 != ABI_PARAM1) + MOV(32, R(ABI_PARAM1), R(reg1)); + ABI_CallFunction(func); } // Pass two registers as parameters. void XEmitter::ABI_CallFunctionRR(const void* func, X64Reg reg1, X64Reg reg2) { - MOVTwo(64, ABI_PARAM1, reg1, 0, ABI_PARAM2, reg2); - ABI_CallFunction(func); + MOVTwo(64, ABI_PARAM1, reg1, 0, ABI_PARAM2, reg2); + ABI_CallFunction(func); } -void XEmitter::MOVTwo(int bits, Gen::X64Reg dst1, Gen::X64Reg src1, s32 offset1, Gen::X64Reg dst2, Gen::X64Reg src2) +void XEmitter::MOVTwo(int bits, Gen::X64Reg dst1, Gen::X64Reg src1, s32 offset1, Gen::X64Reg dst2, + Gen::X64Reg src2) { - if (dst1 == src2 && dst2 == src1) - { - XCHG(bits, R(src1), R(src2)); - if (offset1) - ADD(bits, R(dst1), Imm32(offset1)); - } - else if (src2 != dst1) - { - if (dst1 != src1 && offset1) - LEA(bits, dst1, MDisp(src1, offset1)); - else if (dst1 != src1) - MOV(bits, R(dst1), R(src1)); - else if (offset1) - ADD(bits, R(dst1), Imm32(offset1)); - if (dst2 != src2) - MOV(bits, R(dst2), R(src2)); - } - else - { - if (dst2 != src2) - MOV(bits, R(dst2), R(src2)); - if (dst1 != src1 && offset1) - LEA(bits, dst1, MDisp(src1, offset1)); - else if (dst1 != src1) - MOV(bits, R(dst1), R(src1)); - else if (offset1) - ADD(bits, R(dst1), Imm32(offset1)); - } + if (dst1 == src2 && dst2 == src1) + { + XCHG(bits, R(src1), R(src2)); + if (offset1) + ADD(bits, R(dst1), Imm32(offset1)); + } + else if (src2 != dst1) + { + if (dst1 != src1 && offset1) + LEA(bits, dst1, MDisp(src1, offset1)); + else if (dst1 != src1) + MOV(bits, R(dst1), R(src1)); + else if (offset1) + ADD(bits, R(dst1), Imm32(offset1)); + if (dst2 != src2) + MOV(bits, R(dst2), R(src2)); + } + else + { + if (dst2 != src2) + MOV(bits, R(dst2), R(src2)); + if (dst1 != src1 && offset1) + LEA(bits, dst1, MDisp(src1, offset1)); + else if (dst1 != src1) + MOV(bits, R(dst1), R(src1)); + else if (offset1) + ADD(bits, R(dst1), Imm32(offset1)); + } } void XEmitter::ABI_CallFunctionAC(int bits, const void* func, const Gen::OpArg& arg1, u32 param2) { - if (!arg1.IsSimpleReg(ABI_PARAM1)) - MOV(bits, R(ABI_PARAM1), arg1); - MOV(32, R(ABI_PARAM2), Imm32(param2)); - ABI_CallFunction(func); + if (!arg1.IsSimpleReg(ABI_PARAM1)) + MOV(bits, R(ABI_PARAM1), arg1); + MOV(32, R(ABI_PARAM2), Imm32(param2)); + ABI_CallFunction(func); } void XEmitter::ABI_CallFunctionA(int bits, const void* func, const Gen::OpArg& arg1) { - if (!arg1.IsSimpleReg(ABI_PARAM1)) - MOV(bits, R(ABI_PARAM1), arg1); - ABI_CallFunction(func); + if (!arg1.IsSimpleReg(ABI_PARAM1)) + MOV(bits, R(ABI_PARAM1), arg1); + ABI_CallFunction(func); } - diff --git a/Source/Core/Common/x64ABI.h b/Source/Core/Common/x64ABI.h index 2f0b0111f0..99459dd2c8 100644 --- a/Source/Core/Common/x64ABI.h +++ b/Source/Core/Common/x64ABI.h @@ -12,7 +12,8 @@ // Windows 64-bit // * 4-reg "fastcall" variant, very new-skool stack handling -// * Callee moves stack pointer, to make room for shadow regs for the biggest function _it itself calls_ +// * Callee moves stack pointer, to make room for shadow regs for the biggest function _it itself +// calls_ // * Parameters passed in RCX, RDX, ... further parameters are MOVed into the allocated stack space. // Scratch: RAX RCX RDX R8 R9 R10 R11 // Callee-save: RBX RSI RDI RBP R12 R13 R14 R15 @@ -27,7 +28,7 @@ #define ABI_ALL_FPRS BitSet32(0xffff0000) #define ABI_ALL_GPRS BitSet32(0x0000ffff) -#ifdef _WIN32 // 64-bit Windows - the really exotic calling convention +#ifdef _WIN32 // 64-bit Windows - the really exotic calling convention #define ABI_PARAM1 RCX #define ABI_PARAM2 RDX @@ -35,10 +36,10 @@ #define ABI_PARAM4 R9 // xmm0-xmm15 use the upper 16 bits in the functions that push/pop registers. -#define ABI_ALL_CALLER_SAVED \ - (BitSet32 { RAX, RCX, RDX, R8, R9, R10, R11, \ - XMM0+16, XMM1+16, XMM2+16, XMM3+16, XMM4+16, XMM5+16 }) -#else //64-bit Unix / OS X +#define ABI_ALL_CALLER_SAVED \ + (BitSet32{RAX, RCX, RDX, R8, R9, R10, R11, XMM0 + 16, XMM1 + 16, XMM2 + 16, XMM3 + 16, \ + XMM4 + 16, XMM5 + 16}) +#else // 64-bit Unix / OS X #define ABI_PARAM1 RDI #define ABI_PARAM2 RSI @@ -49,12 +50,9 @@ // FIXME: avoid pushing all 16 XMM registers when possible? most functions we call probably // don't actually clobber them. -#define ABI_ALL_CALLER_SAVED \ - (BitSet32 { RAX, RCX, RDX, RDI, RSI, R8, R9, R10, R11 } | \ - ABI_ALL_FPRS) -#endif // WIN32 +#define ABI_ALL_CALLER_SAVED (BitSet32{RAX, RCX, RDX, RDI, RSI, R8, R9, R10, R11} | ABI_ALL_FPRS) +#endif // WIN32 #define ABI_ALL_CALLEE_SAVED (~ABI_ALL_CALLER_SAVED) #define ABI_RETURN RAX - diff --git a/Source/Core/Common/x64Analyzer.cpp b/Source/Core/Common/x64Analyzer.cpp index 501db27cbe..773f6ebdbc 100644 --- a/Source/Core/Common/x64Analyzer.cpp +++ b/Source/Core/Common/x64Analyzer.cpp @@ -6,236 +6,228 @@ bool DisassembleMov(const unsigned char* codePtr, InstructionInfo* info) { - unsigned const char* startCodePtr = codePtr; - u8 rex = 0; - u32 opcode; - int opcode_length; + unsigned const char* startCodePtr = codePtr; + u8 rex = 0; + u32 opcode; + int opcode_length; - //Check for regular prefix - info->operandSize = 4; - info->zeroExtend = false; - info->signExtend = false; - info->hasImmediate = false; - info->isMemoryWrite = false; - info->byteSwap = false; + // Check for regular prefix + info->operandSize = 4; + info->zeroExtend = false; + info->signExtend = false; + info->hasImmediate = false; + info->isMemoryWrite = false; + info->byteSwap = false; - u8 modRMbyte = 0; - u8 sibByte = 0; - bool hasModRM = false; + u8 modRMbyte = 0; + u8 sibByte = 0; + bool hasModRM = false; - int displacementSize = 0; + int displacementSize = 0; - if (*codePtr == 0x66) - { - info->operandSize = 2; - codePtr++; - } - else if (*codePtr == 0x67) - { - codePtr++; - } + if (*codePtr == 0x66) + { + info->operandSize = 2; + codePtr++; + } + else if (*codePtr == 0x67) + { + codePtr++; + } - //Check for REX prefix - if ((*codePtr & 0xF0) == 0x40) - { - rex = *codePtr; - if (rex & 8) //REX.W - { - info->operandSize = 8; - } - codePtr++; - } + // Check for REX prefix + if ((*codePtr & 0xF0) == 0x40) + { + rex = *codePtr; + if (rex & 8) // REX.W + { + info->operandSize = 8; + } + codePtr++; + } - opcode = *codePtr++; - opcode_length = 1; - if (opcode == 0x0F) - { - opcode = (opcode << 8) | *codePtr++; - opcode_length = 2; - if ((opcode & 0xFB) == 0x38) - { - opcode = (opcode << 8) | *codePtr++; - opcode_length = 3; - } - } + opcode = *codePtr++; + opcode_length = 1; + if (opcode == 0x0F) + { + opcode = (opcode << 8) | *codePtr++; + opcode_length = 2; + if ((opcode & 0xFB) == 0x38) + { + opcode = (opcode << 8) | *codePtr++; + opcode_length = 3; + } + } - switch (opcode_length) - { - case 1: - if ((opcode & 0xF0) == 0x80 || - ((opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02)) - { - modRMbyte = *codePtr++; - hasModRM = true; - } - break; - case 2: - if (((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D) || - ((opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02) || - (opcode & 0xF0) == 0x30 || - (opcode & 0xFF) == 0x77 || - (opcode & 0xF0) == 0x80 || - (opcode & 0xF8) == 0xC8) - { - // No mod R/M byte - } - else - { - modRMbyte = *codePtr++; - hasModRM = true; - } - break; - case 3: - // TODO: support more 3-byte opcode instructions - if ((opcode & 0xFE) == 0xF0) - { - modRMbyte = *codePtr++; - hasModRM = true; - } - break; - } + switch (opcode_length) + { + case 1: + if ((opcode & 0xF0) == 0x80 || ((opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02)) + { + modRMbyte = *codePtr++; + hasModRM = true; + } + break; + case 2: + if (((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D) || + ((opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02) || (opcode & 0xF0) == 0x30 || + (opcode & 0xFF) == 0x77 || (opcode & 0xF0) == 0x80 || (opcode & 0xF8) == 0xC8) + { + // No mod R/M byte + } + else + { + modRMbyte = *codePtr++; + hasModRM = true; + } + break; + case 3: + // TODO: support more 3-byte opcode instructions + if ((opcode & 0xFE) == 0xF0) + { + modRMbyte = *codePtr++; + hasModRM = true; + } + break; + } - if (hasModRM) - { - ModRM mrm(modRMbyte, rex); - info->regOperandReg = mrm.reg; - if (mrm.mod < 3) - { - if (mrm.rm == 4) - { - //SIB byte - sibByte = *codePtr++; - info->scaledReg = (sibByte >> 3) & 7; - info->otherReg = (sibByte & 7); - if (rex & 2) info->scaledReg += 8; - if (rex & 1) info->otherReg += 8; - } - else - { - //info->scaledReg = - } - } - if (mrm.mod == 1 || mrm.mod == 2) - { - if (mrm.mod == 1) - displacementSize = 1; - else - displacementSize = 4; - } - } + if (hasModRM) + { + ModRM mrm(modRMbyte, rex); + info->regOperandReg = mrm.reg; + if (mrm.mod < 3) + { + if (mrm.rm == 4) + { + // SIB byte + sibByte = *codePtr++; + info->scaledReg = (sibByte >> 3) & 7; + info->otherReg = (sibByte & 7); + if (rex & 2) + info->scaledReg += 8; + if (rex & 1) + info->otherReg += 8; + } + else + { + // info->scaledReg = + } + } + if (mrm.mod == 1 || mrm.mod == 2) + { + if (mrm.mod == 1) + displacementSize = 1; + else + displacementSize = 4; + } + } - if (displacementSize == 1) - info->displacement = (s32)(s8)*codePtr; - else - info->displacement = *((s32*)codePtr); - codePtr += displacementSize; + if (displacementSize == 1) + info->displacement = (s32)(s8)*codePtr; + else + info->displacement = *((s32*)codePtr); + codePtr += displacementSize; - switch (opcode) - { - case 0xC6: // mem <- imm8 - info->isMemoryWrite = true; - info->hasImmediate = true; - info->immediate = *codePtr; - info->operandSize = 1; - codePtr++; - break; + switch (opcode) + { + case 0xC6: // mem <- imm8 + info->isMemoryWrite = true; + info->hasImmediate = true; + info->immediate = *codePtr; + info->operandSize = 1; + codePtr++; + break; - case 0xC7: // mem <- imm16/32 - info->isMemoryWrite = true; - switch (info->operandSize) - { - case 2: - info->hasImmediate = true; - info->immediate = *(u16*)codePtr; - codePtr += 2; - break; + case 0xC7: // mem <- imm16/32 + info->isMemoryWrite = true; + switch (info->operandSize) + { + case 2: + info->hasImmediate = true; + info->immediate = *(u16*)codePtr; + codePtr += 2; + break; - case 4: - info->hasImmediate = true; - info->immediate = *(u32*)codePtr; - codePtr += 4; - break; + case 4: + info->hasImmediate = true; + info->immediate = *(u32*)codePtr; + codePtr += 4; + break; - case 8: - info->zeroExtend = true; - info->immediate = *(u32*)codePtr; - codePtr += 4; - break; - } - break; + case 8: + info->zeroExtend = true; + info->immediate = *(u32*)codePtr; + codePtr += 4; + break; + } + break; - case 0x88: // mem <- r8 - info->isMemoryWrite = true; - if (info->operandSize != 4) - { - return false; - } - info->operandSize = 1; - break; + case 0x88: // mem <- r8 + info->isMemoryWrite = true; + if (info->operandSize != 4) + { + return false; + } + info->operandSize = 1; + break; - case 0x89: // mem <- r16/32/64 - info->isMemoryWrite = true; - break; + case 0x89: // mem <- r16/32/64 + info->isMemoryWrite = true; + break; - case 0x8A: // r8 <- mem - if (info->operandSize != 4) - { - return false; - } - info->operandSize = 1; - break; + case 0x8A: // r8 <- mem + if (info->operandSize != 4) + { + return false; + } + info->operandSize = 1; + break; - case 0x8B: // r16/32/64 <- mem - break; + case 0x8B: // r16/32/64 <- mem + break; - case 0x0FB6: // movzx on byte - info->zeroExtend = true; - info->operandSize = 1; - break; + case 0x0FB6: // movzx on byte + info->zeroExtend = true; + info->operandSize = 1; + break; - case 0x0FB7: // movzx on short - info->zeroExtend = true; - info->operandSize = 2; - break; + case 0x0FB7: // movzx on short + info->zeroExtend = true; + info->operandSize = 2; + break; - case 0x0FBE: // movsx on byte - info->signExtend = true; - info->operandSize = 1; - break; + case 0x0FBE: // movsx on byte + info->signExtend = true; + info->operandSize = 1; + break; - case 0x0FBF: // movsx on short - info->signExtend = true; - info->operandSize = 2; - break; + case 0x0FBF: // movsx on short + info->signExtend = true; + info->operandSize = 2; + break; - case 0x0F38F0: // movbe read - info->byteSwap = true; - break; + case 0x0F38F0: // movbe read + info->byteSwap = true; + break; - case 0x0F38F1: // movbe write - info->byteSwap = true; - info->isMemoryWrite = true; - break; + case 0x0F38F1: // movbe write + info->byteSwap = true; + info->isMemoryWrite = true; + break; - default: - return false; - } - info->instructionSize = (int)(codePtr - startCodePtr); - return true; + default: + return false; + } + info->instructionSize = (int)(codePtr - startCodePtr); + return true; } bool InstructionInfo::operator==(const InstructionInfo& other) const { - return operandSize == other.operandSize && - instructionSize == other.instructionSize && - regOperandReg == other.regOperandReg && - otherReg == other.otherReg && - scaledReg == other.scaledReg && - zeroExtend == other.zeroExtend && - signExtend == other.signExtend && - hasImmediate == other.hasImmediate && - isMemoryWrite == other.isMemoryWrite && - byteSwap == other.byteSwap && - immediate == other.immediate && - displacement == other.displacement; + return operandSize == other.operandSize && instructionSize == other.instructionSize && + regOperandReg == other.regOperandReg && otherReg == other.otherReg && + scaledReg == other.scaledReg && zeroExtend == other.zeroExtend && + signExtend == other.signExtend && hasImmediate == other.hasImmediate && + isMemoryWrite == other.isMemoryWrite && byteSwap == other.byteSwap && + immediate == other.immediate && displacement == other.displacement; } diff --git a/Source/Core/Common/x64Analyzer.h b/Source/Core/Common/x64Analyzer.h index 1bcf9f569f..de21f6ff8f 100644 --- a/Source/Core/Common/x64Analyzer.h +++ b/Source/Core/Common/x64Analyzer.h @@ -8,37 +8,37 @@ struct InstructionInfo { - int operandSize; //8, 16, 32, 64 - int instructionSize; - int regOperandReg; - int otherReg; - int scaledReg; - bool zeroExtend; - bool signExtend; - bool hasImmediate; - bool isMemoryWrite; - bool byteSwap; - u64 immediate; - s32 displacement; + int operandSize; // 8, 16, 32, 64 + int instructionSize; + int regOperandReg; + int otherReg; + int scaledReg; + bool zeroExtend; + bool signExtend; + bool hasImmediate; + bool isMemoryWrite; + bool byteSwap; + u64 immediate; + s32 displacement; - bool operator==(const InstructionInfo& other) const; + bool operator==(const InstructionInfo& other) const; }; struct ModRM { - int mod, reg, rm; - ModRM(u8 modRM, u8 rex) - { - mod = modRM >> 6; - reg = ((modRM >> 3) & 7) | ((rex & 4) ? 8 : 0); - rm = modRM & 7; - } + int mod, reg, rm; + ModRM(u8 modRM, u8 rex) + { + mod = modRM >> 6; + reg = ((modRM >> 3) & 7) | ((rex & 4) ? 8 : 0); + rm = modRM & 7; + } }; enum AccessType { - OP_ACCESS_READ = 0, - OP_ACCESS_WRITE = 1 + OP_ACCESS_READ = 0, + OP_ACCESS_WRITE = 1 }; bool DisassembleMov(const unsigned char* codePtr, InstructionInfo* info); diff --git a/Source/Core/Common/x64CPUDetect.cpp b/Source/Core/Common/x64CPUDetect.cpp index 23b279dbb8..b35a91b50e 100644 --- a/Source/Core/Common/x64CPUDetect.cpp +++ b/Source/Core/Common/x64CPUDetect.cpp @@ -5,237 +5,257 @@ #include #include -#include "Common/CommonTypes.h" #include "Common/CPUDetect.h" +#include "Common/CommonTypes.h" #include "Common/Intrinsics.h" #ifndef _WIN32 #ifdef __FreeBSD__ -#include #include +#include #endif static inline void __cpuidex(int info[4], int function_id, int subfunction_id) { #ifdef __FreeBSD__ - // Despite the name, this is just do_cpuid() with ECX as second input. - cpuid_count((u_int)function_id, (u_int)subfunction_id, (u_int*)info); + // Despite the name, this is just do_cpuid() with ECX as second input. + cpuid_count((u_int)function_id, (u_int)subfunction_id, (u_int*)info); #else - info[0] = function_id; // eax - info[2] = subfunction_id; // ecx - __asm__( - "cpuid" - : "=a" (info[0]), - "=b" (info[1]), - "=c" (info[2]), - "=d" (info[3]) - : "a" (function_id), - "c" (subfunction_id) - ); + info[0] = function_id; // eax + info[2] = subfunction_id; // ecx + __asm__("cpuid" + : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) + : "a"(function_id), "c"(subfunction_id)); #endif } static inline void __cpuid(int info[4], int function_id) { - return __cpuidex(info, function_id, 0); + return __cpuidex(info, function_id, 0); } #define _XCR_XFEATURE_ENABLED_MASK 0 static u64 _xgetbv(u32 index) { - u32 eax, edx; - __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); - return ((u64)edx << 32) | eax; + u32 eax, edx; + __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); + return ((u64)edx << 32) | eax; } -#endif // ifndef _WIN32 +#endif // ifndef _WIN32 CPUInfo cpu_info; CPUInfo::CPUInfo() { - Detect(); + Detect(); } // Detects the various CPU features void CPUInfo::Detect() { #ifdef _M_X86_64 - Mode64bit = true; - OS64bit = true; + Mode64bit = true; + OS64bit = true; #endif - num_cores = 1; + num_cores = 1; - // Set obvious defaults, for extra safety - if (Mode64bit) - { - bSSE = true; - bSSE2 = true; - bLongMode = true; - } + // Set obvious defaults, for extra safety + if (Mode64bit) + { + bSSE = true; + bSSE2 = true; + bLongMode = true; + } - // Assume CPU supports the CPUID instruction. Those that don't can barely - // boot modern OS:es anyway. - int cpu_id[4]; + // Assume CPU supports the CPUID instruction. Those that don't can barely + // boot modern OS:es anyway. + int cpu_id[4]; - // Detect CPU's CPUID capabilities, and grab CPU string - __cpuid(cpu_id, 0x00000000); - u32 max_std_fn = cpu_id[0]; // EAX - std::memcpy(&brand_string[0], &cpu_id[1], sizeof(int)); - std::memcpy(&brand_string[4], &cpu_id[3], sizeof(int)); - std::memcpy(&brand_string[8], &cpu_id[2], sizeof(int)); - __cpuid(cpu_id, 0x80000000); - u32 max_ex_fn = cpu_id[0]; - if (!strcmp(brand_string, "GenuineIntel")) - vendor = VENDOR_INTEL; - else if (!strcmp(brand_string, "AuthenticAMD")) - vendor = VENDOR_AMD; - else - vendor = VENDOR_OTHER; + // Detect CPU's CPUID capabilities, and grab CPU string + __cpuid(cpu_id, 0x00000000); + u32 max_std_fn = cpu_id[0]; // EAX + std::memcpy(&brand_string[0], &cpu_id[1], sizeof(int)); + std::memcpy(&brand_string[4], &cpu_id[3], sizeof(int)); + std::memcpy(&brand_string[8], &cpu_id[2], sizeof(int)); + __cpuid(cpu_id, 0x80000000); + u32 max_ex_fn = cpu_id[0]; + if (!strcmp(brand_string, "GenuineIntel")) + vendor = VENDOR_INTEL; + else if (!strcmp(brand_string, "AuthenticAMD")) + vendor = VENDOR_AMD; + else + vendor = VENDOR_OTHER; - // Set reasonable default brand string even if brand string not available. - strcpy(cpu_string, brand_string); + // Set reasonable default brand string even if brand string not available. + strcpy(cpu_string, brand_string); - // Detect family and other misc stuff. - bool ht = false; - HTT = ht; - logical_cpu_count = 1; - if (max_std_fn >= 1) - { - __cpuid(cpu_id, 0x00000001); - int family = ((cpu_id[0] >> 8) & 0xf) + ((cpu_id[0] >> 20) & 0xff); - int model = ((cpu_id[0] >> 4) & 0xf) + ((cpu_id[0] >> 12) & 0xf0); - // Detect people unfortunate enough to be running Dolphin on an Atom - if (family == 6 && (model == 0x1C || model == 0x26 ||model == 0x27 || model == 0x35 || model == 0x36 || - model == 0x37 || model == 0x4A || model == 0x4D || model == 0x5A || model == 0x5D)) - bAtom = true; - logical_cpu_count = (cpu_id[1] >> 16) & 0xFF; - ht = (cpu_id[3] >> 28) & 1; + // Detect family and other misc stuff. + bool ht = false; + HTT = ht; + logical_cpu_count = 1; + if (max_std_fn >= 1) + { + __cpuid(cpu_id, 0x00000001); + int family = ((cpu_id[0] >> 8) & 0xf) + ((cpu_id[0] >> 20) & 0xff); + int model = ((cpu_id[0] >> 4) & 0xf) + ((cpu_id[0] >> 12) & 0xf0); + // Detect people unfortunate enough to be running Dolphin on an Atom + if (family == 6 && + (model == 0x1C || model == 0x26 || model == 0x27 || model == 0x35 || model == 0x36 || + model == 0x37 || model == 0x4A || model == 0x4D || model == 0x5A || model == 0x5D)) + bAtom = true; + logical_cpu_count = (cpu_id[1] >> 16) & 0xFF; + ht = (cpu_id[3] >> 28) & 1; - if ((cpu_id[3] >> 25) & 1) bSSE = true; - if ((cpu_id[3] >> 26) & 1) bSSE2 = true; - if ((cpu_id[2]) & 1) bSSE3 = true; - if ((cpu_id[2] >> 9) & 1) bSSSE3 = true; - if ((cpu_id[2] >> 19) & 1) bSSE4_1 = true; - if ((cpu_id[2] >> 20) & 1) bSSE4_2 = true; - if ((cpu_id[2] >> 22) & 1) bMOVBE = true; - if ((cpu_id[2] >> 25) & 1) bAES = true; + if ((cpu_id[3] >> 25) & 1) + bSSE = true; + if ((cpu_id[3] >> 26) & 1) + bSSE2 = true; + if ((cpu_id[2]) & 1) + bSSE3 = true; + if ((cpu_id[2] >> 9) & 1) + bSSSE3 = true; + if ((cpu_id[2] >> 19) & 1) + bSSE4_1 = true; + if ((cpu_id[2] >> 20) & 1) + bSSE4_2 = true; + if ((cpu_id[2] >> 22) & 1) + bMOVBE = true; + if ((cpu_id[2] >> 25) & 1) + bAES = true; - if ((cpu_id[3] >> 24) & 1) - { - // We can use FXSAVE. - bFXSR = true; - } + if ((cpu_id[3] >> 24) & 1) + { + // We can use FXSAVE. + bFXSR = true; + } - // AVX support requires 3 separate checks: - // - Is the AVX bit set in CPUID? - // - Is the XSAVE bit set in CPUID? - // - XGETBV result has the XCR bit set. - if (((cpu_id[2] >> 28) & 1) && ((cpu_id[2] >> 27) & 1)) - { - if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) - { - bAVX = true; - if ((cpu_id[2] >> 12) & 1) - bFMA = true; - } - } + // AVX support requires 3 separate checks: + // - Is the AVX bit set in CPUID? + // - Is the XSAVE bit set in CPUID? + // - XGETBV result has the XCR bit set. + if (((cpu_id[2] >> 28) & 1) && ((cpu_id[2] >> 27) & 1)) + { + if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) + { + bAVX = true; + if ((cpu_id[2] >> 12) & 1) + bFMA = true; + } + } - if (max_std_fn >= 7) - { - __cpuidex(cpu_id, 0x00000007, 0x00000000); - // careful; we can't enable AVX2 unless the XSAVE/XGETBV checks above passed - if ((cpu_id[1] >> 5) & 1) - bAVX2 = bAVX; - if ((cpu_id[1] >> 3) & 1) - bBMI1 = true; - if ((cpu_id[1] >> 8) & 1) - bBMI2 = true; - } - } + if (max_std_fn >= 7) + { + __cpuidex(cpu_id, 0x00000007, 0x00000000); + // careful; we can't enable AVX2 unless the XSAVE/XGETBV checks above passed + if ((cpu_id[1] >> 5) & 1) + bAVX2 = bAVX; + if ((cpu_id[1] >> 3) & 1) + bBMI1 = true; + if ((cpu_id[1] >> 8) & 1) + bBMI2 = true; + } + } - bFlushToZero = bSSE; + bFlushToZero = bSSE; - if (max_ex_fn >= 0x80000004) - { - // Extract CPU model string - __cpuid(cpu_id, 0x80000002); - memcpy(cpu_string, cpu_id, sizeof(cpu_id)); - __cpuid(cpu_id, 0x80000003); - memcpy(cpu_string + 16, cpu_id, sizeof(cpu_id)); - __cpuid(cpu_id, 0x80000004); - memcpy(cpu_string + 32, cpu_id, sizeof(cpu_id)); - } - if (max_ex_fn >= 0x80000001) - { - // Check for more features. - __cpuid(cpu_id, 0x80000001); - if (cpu_id[2] & 1) bLAHFSAHF64 = true; - if ((cpu_id[2] >> 5) & 1) bLZCNT = true; - if ((cpu_id[2] >> 16) & 1) bFMA4 = true; - if ((cpu_id[3] >> 29) & 1) bLongMode = true; - } + if (max_ex_fn >= 0x80000004) + { + // Extract CPU model string + __cpuid(cpu_id, 0x80000002); + memcpy(cpu_string, cpu_id, sizeof(cpu_id)); + __cpuid(cpu_id, 0x80000003); + memcpy(cpu_string + 16, cpu_id, sizeof(cpu_id)); + __cpuid(cpu_id, 0x80000004); + memcpy(cpu_string + 32, cpu_id, sizeof(cpu_id)); + } + if (max_ex_fn >= 0x80000001) + { + // Check for more features. + __cpuid(cpu_id, 0x80000001); + if (cpu_id[2] & 1) + bLAHFSAHF64 = true; + if ((cpu_id[2] >> 5) & 1) + bLZCNT = true; + if ((cpu_id[2] >> 16) & 1) + bFMA4 = true; + if ((cpu_id[3] >> 29) & 1) + bLongMode = true; + } - num_cores = (logical_cpu_count == 0) ? 1 : logical_cpu_count; + num_cores = (logical_cpu_count == 0) ? 1 : logical_cpu_count; - if (max_ex_fn >= 0x80000008) - { - // Get number of cores. This is a bit complicated. Following AMD manual here. - __cpuid(cpu_id, 0x80000008); - int apic_id_core_id_size = (cpu_id[2] >> 12) & 0xF; - if (apic_id_core_id_size == 0) - { - if (ht) - { - // New mechanism for modern Intel CPUs. - if (vendor == VENDOR_INTEL) - { - __cpuidex(cpu_id, 0x00000004, 0x00000000); - int cores_x_package = ((cpu_id[0] >> 26) & 0x3F) + 1; - HTT = (cores_x_package < logical_cpu_count); - cores_x_package = ((logical_cpu_count % cores_x_package) == 0) ? cores_x_package : 1; - num_cores = (cores_x_package > 1) ? cores_x_package : num_cores; - logical_cpu_count /= cores_x_package; - } - } - } - else - { - // Use AMD's new method. - num_cores = (cpu_id[2] & 0xFF) + 1; - } - } + if (max_ex_fn >= 0x80000008) + { + // Get number of cores. This is a bit complicated. Following AMD manual here. + __cpuid(cpu_id, 0x80000008); + int apic_id_core_id_size = (cpu_id[2] >> 12) & 0xF; + if (apic_id_core_id_size == 0) + { + if (ht) + { + // New mechanism for modern Intel CPUs. + if (vendor == VENDOR_INTEL) + { + __cpuidex(cpu_id, 0x00000004, 0x00000000); + int cores_x_package = ((cpu_id[0] >> 26) & 0x3F) + 1; + HTT = (cores_x_package < logical_cpu_count); + cores_x_package = ((logical_cpu_count % cores_x_package) == 0) ? cores_x_package : 1; + num_cores = (cores_x_package > 1) ? cores_x_package : num_cores; + logical_cpu_count /= cores_x_package; + } + } + } + else + { + // Use AMD's new method. + num_cores = (cpu_id[2] & 0xFF) + 1; + } + } } // Turn the CPU info into a string we can show std::string CPUInfo::Summarize() { - std::string sum(cpu_string); - sum += " ("; - sum += brand_string; - sum += ")"; + std::string sum(cpu_string); + sum += " ("; + sum += brand_string; + sum += ")"; - if (bSSE) sum += ", SSE"; - if (bSSE2) - { - sum += ", SSE2"; - if (!bFlushToZero) - sum += " (but not DAZ!)"; - } - if (bSSE3) sum += ", SSE3"; - if (bSSSE3) sum += ", SSSE3"; - if (bSSE4_1) sum += ", SSE4.1"; - if (bSSE4_2) sum += ", SSE4.2"; - if (HTT) sum += ", HTT"; - if (bAVX) sum += ", AVX"; - if (bAVX2) sum += ", AVX2"; - if (bBMI1) sum += ", BMI1"; - if (bBMI2) sum += ", BMI2"; - if (bFMA) sum += ", FMA"; - if (bAES) sum += ", AES"; - if (bMOVBE) sum += ", MOVBE"; - if (bLongMode) sum += ", 64-bit support"; - return sum; + if (bSSE) + sum += ", SSE"; + if (bSSE2) + { + sum += ", SSE2"; + if (!bFlushToZero) + sum += " (but not DAZ!)"; + } + if (bSSE3) + sum += ", SSE3"; + if (bSSSE3) + sum += ", SSSE3"; + if (bSSE4_1) + sum += ", SSE4.1"; + if (bSSE4_2) + sum += ", SSE4.2"; + if (HTT) + sum += ", HTT"; + if (bAVX) + sum += ", AVX"; + if (bAVX2) + sum += ", AVX2"; + if (bBMI1) + sum += ", BMI1"; + if (bBMI2) + sum += ", BMI2"; + if (bFMA) + sum += ", FMA"; + if (bAES) + sum += ", AES"; + if (bMOVBE) + sum += ", MOVBE"; + if (bLongMode) + sum += ", 64-bit support"; + return sum; } - diff --git a/Source/Core/Common/x64Emitter.cpp b/Source/Core/Common/x64Emitter.cpp index 6cc779b80a..841d90a431 100644 --- a/Source/Core/Common/x64Emitter.cpp +++ b/Source/Core/Common/x64Emitter.cpp @@ -5,145 +5,142 @@ #include #include -#include "Common/CommonTypes.h" #include "Common/CPUDetect.h" -#include "Common/x64Emitter.h" +#include "Common/CommonTypes.h" #include "Common/Logging/Log.h" +#include "Common/x64Emitter.h" namespace Gen { - // TODO(ector): Add EAX special casing, for ever so slightly smaller code. struct NormalOpDef { - u8 toRm8, toRm32, fromRm8, fromRm32, imm8, imm32, simm8, eaximm8, eaximm32, ext; + u8 toRm8, toRm32, fromRm8, fromRm32, imm8, imm32, simm8, eaximm8, eaximm32, ext; }; // 0xCC is code for invalid combination of immediates -static const NormalOpDef normalops[11] = -{ - {0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x83, 0x04, 0x05, 0}, //ADD - {0x10, 0x11, 0x12, 0x13, 0x80, 0x81, 0x83, 0x14, 0x15, 2}, //ADC +static const NormalOpDef normalops[11] = { + {0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x83, 0x04, 0x05, 0}, // ADD + {0x10, 0x11, 0x12, 0x13, 0x80, 0x81, 0x83, 0x14, 0x15, 2}, // ADC - {0x28, 0x29, 0x2A, 0x2B, 0x80, 0x81, 0x83, 0x2C, 0x2D, 5}, //SUB - {0x18, 0x19, 0x1A, 0x1B, 0x80, 0x81, 0x83, 0x1C, 0x1D, 3}, //SBB + {0x28, 0x29, 0x2A, 0x2B, 0x80, 0x81, 0x83, 0x2C, 0x2D, 5}, // SUB + {0x18, 0x19, 0x1A, 0x1B, 0x80, 0x81, 0x83, 0x1C, 0x1D, 3}, // SBB - {0x20, 0x21, 0x22, 0x23, 0x80, 0x81, 0x83, 0x24, 0x25, 4}, //AND - {0x08, 0x09, 0x0A, 0x0B, 0x80, 0x81, 0x83, 0x0C, 0x0D, 1}, //OR + {0x20, 0x21, 0x22, 0x23, 0x80, 0x81, 0x83, 0x24, 0x25, 4}, // AND + {0x08, 0x09, 0x0A, 0x0B, 0x80, 0x81, 0x83, 0x0C, 0x0D, 1}, // OR - {0x30, 0x31, 0x32, 0x33, 0x80, 0x81, 0x83, 0x34, 0x35, 6}, //XOR - {0x88, 0x89, 0x8A, 0x8B, 0xC6, 0xC7, 0xCC, 0xCC, 0xCC, 0}, //MOV + {0x30, 0x31, 0x32, 0x33, 0x80, 0x81, 0x83, 0x34, 0x35, 6}, // XOR + {0x88, 0x89, 0x8A, 0x8B, 0xC6, 0xC7, 0xCC, 0xCC, 0xCC, 0}, // MOV - {0x84, 0x85, 0x84, 0x85, 0xF6, 0xF7, 0xCC, 0xA8, 0xA9, 0}, //TEST (to == from) - {0x38, 0x39, 0x3A, 0x3B, 0x80, 0x81, 0x83, 0x3C, 0x3D, 7}, //CMP + {0x84, 0x85, 0x84, 0x85, 0xF6, 0xF7, 0xCC, 0xA8, 0xA9, 0}, // TEST (to == from) + {0x38, 0x39, 0x3A, 0x3B, 0x80, 0x81, 0x83, 0x3C, 0x3D, 7}, // CMP - {0x86, 0x87, 0x86, 0x87, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 7}, //XCHG + {0x86, 0x87, 0x86, 0x87, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 7}, // XCHG }; enum NormalSSEOps { - sseCMP = 0xC2, - sseADD = 0x58, //ADD - sseSUB = 0x5C, //SUB - sseAND = 0x54, //AND - sseANDN = 0x55, //ANDN - sseOR = 0x56, - sseXOR = 0x57, - sseMUL = 0x59, //MUL - sseDIV = 0x5E, //DIV - sseMIN = 0x5D, //MIN - sseMAX = 0x5F, //MAX - sseCOMIS = 0x2F, //COMIS - sseUCOMIS = 0x2E, //UCOMIS - sseSQRT = 0x51, //SQRT - sseRCP = 0x53, //RCP - sseRSQRT = 0x52, //RSQRT (NO DOUBLE PRECISION!!!) - sseMOVAPfromRM = 0x28, //MOVAP from RM - sseMOVAPtoRM = 0x29, //MOVAP to RM - sseMOVUPfromRM = 0x10, //MOVUP from RM - sseMOVUPtoRM = 0x11, //MOVUP to RM - sseMOVLPfromRM = 0x12, - sseMOVLPtoRM = 0x13, - sseMOVHPfromRM = 0x16, - sseMOVHPtoRM = 0x17, - sseMOVHLPS = 0x12, - sseMOVLHPS = 0x16, - sseMOVDQfromRM = 0x6F, - sseMOVDQtoRM = 0x7F, - sseMASKMOVDQU = 0xF7, - sseLDDQU = 0xF0, - sseSHUF = 0xC6, - sseMOVNTDQ = 0xE7, - sseMOVNTP = 0x2B, + sseCMP = 0xC2, + sseADD = 0x58, // ADD + sseSUB = 0x5C, // SUB + sseAND = 0x54, // AND + sseANDN = 0x55, // ANDN + sseOR = 0x56, + sseXOR = 0x57, + sseMUL = 0x59, // MUL + sseDIV = 0x5E, // DIV + sseMIN = 0x5D, // MIN + sseMAX = 0x5F, // MAX + sseCOMIS = 0x2F, // COMIS + sseUCOMIS = 0x2E, // UCOMIS + sseSQRT = 0x51, // SQRT + sseRCP = 0x53, // RCP + sseRSQRT = 0x52, // RSQRT (NO DOUBLE PRECISION!!!) + sseMOVAPfromRM = 0x28, // MOVAP from RM + sseMOVAPtoRM = 0x29, // MOVAP to RM + sseMOVUPfromRM = 0x10, // MOVUP from RM + sseMOVUPtoRM = 0x11, // MOVUP to RM + sseMOVLPfromRM = 0x12, + sseMOVLPtoRM = 0x13, + sseMOVHPfromRM = 0x16, + sseMOVHPtoRM = 0x17, + sseMOVHLPS = 0x12, + sseMOVLHPS = 0x16, + sseMOVDQfromRM = 0x6F, + sseMOVDQtoRM = 0x7F, + sseMASKMOVDQU = 0xF7, + sseLDDQU = 0xF0, + sseSHUF = 0xC6, + sseMOVNTDQ = 0xE7, + sseMOVNTP = 0x2B, }; - void XEmitter::SetCodePtr(u8* ptr) { - code = ptr; + code = ptr; } const u8* XEmitter::GetCodePtr() const { - return code; + return code; } u8* XEmitter::GetWritableCodePtr() { - return code; + return code; } void XEmitter::Write8(u8 value) { - *code++ = value; + *code++ = value; } void XEmitter::Write16(u16 value) { - std::memcpy(code, &value, sizeof(u16)); - code += sizeof(u16); + std::memcpy(code, &value, sizeof(u16)); + code += sizeof(u16); } void XEmitter::Write32(u32 value) { - std::memcpy(code, &value, sizeof(u32)); - code += sizeof(u32); + std::memcpy(code, &value, sizeof(u32)); + code += sizeof(u32); } void XEmitter::Write64(u64 value) { - std::memcpy(code, &value, sizeof(u64)); - code += sizeof(u64); + std::memcpy(code, &value, sizeof(u64)); + code += sizeof(u64); } void XEmitter::ReserveCodeSpace(int bytes) { - for (int i = 0; i < bytes; i++) - *code++ = 0xCC; + for (int i = 0; i < bytes; i++) + *code++ = 0xCC; } const u8* XEmitter::AlignCode4() { - int c = int((u64)code & 3); - if (c) - ReserveCodeSpace(4-c); - return code; + int c = int((u64)code & 3); + if (c) + ReserveCodeSpace(4 - c); + return code; } const u8* XEmitter::AlignCode16() { - int c = int((u64)code & 15); - if (c) - ReserveCodeSpace(16-c); - return code; + int c = int((u64)code & 15); + if (c) + ReserveCodeSpace(16 - c); + return code; } const u8* XEmitter::AlignCodePage() { - int c = int((u64)code & 4095); - if (c) - ReserveCodeSpace(4096-c); - return code; + int c = int((u64)code & 4095); + if (c) + ReserveCodeSpace(4096 - c); + return code; } // This operation modifies flags; check to see the flags are locked. @@ -151,198 +148,222 @@ const u8* XEmitter::AlignCodePage() // causing a subtle JIT bug. void XEmitter::CheckFlags() { - _assert_msg_(DYNA_REC, !flags_locked, "Attempt to modify flags while flags locked!"); + _assert_msg_(DYNA_REC, !flags_locked, "Attempt to modify flags while flags locked!"); } void XEmitter::WriteModRM(int mod, int reg, int rm) { - Write8((u8)((mod << 6) | ((reg & 7) << 3) | (rm & 7))); + Write8((u8)((mod << 6) | ((reg & 7) << 3) | (rm & 7))); } void XEmitter::WriteSIB(int scale, int index, int base) { - Write8((u8)((scale << 6) | ((index & 7) << 3) | (base & 7))); + Write8((u8)((scale << 6) | ((index & 7) << 3) | (base & 7))); } void OpArg::WriteREX(XEmitter* emit, int opBits, int bits, int customOp) const { - if (customOp == -1) customOp = operandReg; - u8 op = 0x40; - // REX.W (whether operation is a 64-bit operation) - if (opBits == 64) op |= 8; - // REX.R (whether ModR/M reg field refers to R8-R15. - if (customOp & 8) op |= 4; - // REX.X (whether ModR/M SIB index field refers to R8-R15) - if (indexReg & 8) op |= 2; - // REX.B (whether ModR/M rm or SIB base or opcode reg field refers to R8-R15) - if (offsetOrBaseReg & 8) op |= 1; - // Write REX if wr have REX bits to write, or if the operation accesses - // SIL, DIL, BPL, or SPL. - if (op != 0x40 || - (scale == SCALE_NONE && bits == 8 && (offsetOrBaseReg & 0x10c) == 4) || - (opBits == 8 && (customOp & 0x10c) == 4)) - { - emit->Write8(op); - // Check the operation doesn't access AH, BH, CH, or DH. - _dbg_assert_(DYNA_REC, (offsetOrBaseReg & 0x100) == 0); - _dbg_assert_(DYNA_REC, (customOp & 0x100) == 0); - } + if (customOp == -1) + customOp = operandReg; + u8 op = 0x40; + // REX.W (whether operation is a 64-bit operation) + if (opBits == 64) + op |= 8; + // REX.R (whether ModR/M reg field refers to R8-R15. + if (customOp & 8) + op |= 4; + // REX.X (whether ModR/M SIB index field refers to R8-R15) + if (indexReg & 8) + op |= 2; + // REX.B (whether ModR/M rm or SIB base or opcode reg field refers to R8-R15) + if (offsetOrBaseReg & 8) + op |= 1; + // Write REX if wr have REX bits to write, or if the operation accesses + // SIL, DIL, BPL, or SPL. + if (op != 0x40 || (scale == SCALE_NONE && bits == 8 && (offsetOrBaseReg & 0x10c) == 4) || + (opBits == 8 && (customOp & 0x10c) == 4)) + { + emit->Write8(op); + // Check the operation doesn't access AH, BH, CH, or DH. + _dbg_assert_(DYNA_REC, (offsetOrBaseReg & 0x100) == 0); + _dbg_assert_(DYNA_REC, (customOp & 0x100) == 0); + } } -void OpArg::WriteVEX(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, int W) const +void OpArg::WriteVEX(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, + int W) const { - int R = !(regOp1 & 8); - int X = !(indexReg & 8); - int B = !(offsetOrBaseReg & 8); + int R = !(regOp1 & 8); + int X = !(indexReg & 8); + int B = !(offsetOrBaseReg & 8); - int vvvv = (regOp2 == X64Reg::INVALID_REG) ? 0xf : (regOp2 ^ 0xf); + int vvvv = (regOp2 == X64Reg::INVALID_REG) ? 0xf : (regOp2 ^ 0xf); - // do we need any VEX fields that only appear in the three-byte form? - if (X == 1 && B == 1 && W == 0 && mmmmm == 1) - { - u8 RvvvvLpp = (R << 7) | (vvvv << 3) | (L << 2) | pp; - emit->Write8(0xC5); - emit->Write8(RvvvvLpp); - } - else - { - u8 RXBmmmmm = (R << 7) | (X << 6) | (B << 5) | mmmmm; - u8 WvvvvLpp = (W << 7) | (vvvv << 3) | (L << 2) | pp; - emit->Write8(0xC4); - emit->Write8(RXBmmmmm); - emit->Write8(WvvvvLpp); - } + // do we need any VEX fields that only appear in the three-byte form? + if (X == 1 && B == 1 && W == 0 && mmmmm == 1) + { + u8 RvvvvLpp = (R << 7) | (vvvv << 3) | (L << 2) | pp; + emit->Write8(0xC5); + emit->Write8(RvvvvLpp); + } + else + { + u8 RXBmmmmm = (R << 7) | (X << 6) | (B << 5) | mmmmm; + u8 WvvvvLpp = (W << 7) | (vvvv << 3) | (L << 2) | pp; + emit->Write8(0xC4); + emit->Write8(RXBmmmmm); + emit->Write8(WvvvvLpp); + } } void OpArg::WriteRest(XEmitter* emit, int extraBytes, X64Reg _operandReg, - bool warn_64bit_offset) const + bool warn_64bit_offset) const { - if (_operandReg == INVALID_REG) - _operandReg = (X64Reg)this->operandReg; - int mod = 0; - int ireg = indexReg; - bool SIB = false; - int _offsetOrBaseReg = this->offsetOrBaseReg; + if (_operandReg == INVALID_REG) + _operandReg = (X64Reg) this->operandReg; + int mod = 0; + int ireg = indexReg; + bool SIB = false; + int _offsetOrBaseReg = this->offsetOrBaseReg; - if (scale == SCALE_RIP) //Also, on 32-bit, just an immediate address - { - // Oh, RIP addressing. - _offsetOrBaseReg = 5; - emit->WriteModRM(0, _operandReg, _offsetOrBaseReg); - //TODO : add some checks - u64 ripAddr = (u64)emit->GetCodePtr() + 4 + extraBytes; - s64 distance = (s64)offset - (s64)ripAddr; - _assert_msg_(DYNA_REC, - (distance < 0x80000000LL && - distance >= -0x80000000LL) || - !warn_64bit_offset, - "WriteRest: op out of range (0x%" PRIx64 " uses 0x%" PRIx64 ")", - ripAddr, offset); - s32 offs = (s32)distance; - emit->Write32((u32)offs); - return; - } + if (scale == SCALE_RIP) // Also, on 32-bit, just an immediate address + { + // Oh, RIP addressing. + _offsetOrBaseReg = 5; + emit->WriteModRM(0, _operandReg, _offsetOrBaseReg); + // TODO : add some checks + u64 ripAddr = (u64)emit->GetCodePtr() + 4 + extraBytes; + s64 distance = (s64)offset - (s64)ripAddr; + _assert_msg_(DYNA_REC, + (distance < 0x80000000LL && distance >= -0x80000000LL) || !warn_64bit_offset, + "WriteRest: op out of range (0x%" PRIx64 " uses 0x%" PRIx64 ")", ripAddr, offset); + s32 offs = (s32)distance; + emit->Write32((u32)offs); + return; + } - if (scale == 0) - { - // Oh, no memory, Just a reg. - mod = 3; //11 - } - else - { - //Ah good, no scaling. - if (scale == SCALE_ATREG && !((_offsetOrBaseReg & 7) == 4 || (_offsetOrBaseReg & 7) == 5)) - { - //Okay, we're good. No SIB necessary. - int ioff = (int)offset; - if (ioff == 0) - { - mod = 0; - } - else if (ioff<-128 || ioff>127) - { - mod = 2; //32-bit displacement - } - else - { - mod = 1; //8-bit displacement - } - } - else if (scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8) - { - SIB = true; - mod = 0; - _offsetOrBaseReg = 5; - } - else - { - if ((_offsetOrBaseReg & 7) == 4) //this would occupy the SIB encoding :( - { - //So we have to fake it with SIB encoding :( - SIB = true; - } + if (scale == 0) + { + // Oh, no memory, Just a reg. + mod = 3; // 11 + } + else + { + // Ah good, no scaling. + if (scale == SCALE_ATREG && !((_offsetOrBaseReg & 7) == 4 || (_offsetOrBaseReg & 7) == 5)) + { + // Okay, we're good. No SIB necessary. + int ioff = (int)offset; + if (ioff == 0) + { + mod = 0; + } + else if (ioff < -128 || ioff > 127) + { + mod = 2; // 32-bit displacement + } + else + { + mod = 1; // 8-bit displacement + } + } + else if (scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8) + { + SIB = true; + mod = 0; + _offsetOrBaseReg = 5; + } + else + { + if ((_offsetOrBaseReg & 7) == 4) // this would occupy the SIB encoding :( + { + // So we have to fake it with SIB encoding :( + SIB = true; + } - if (scale >= SCALE_1 && scale < SCALE_ATREG) - { - SIB = true; - } + if (scale >= SCALE_1 && scale < SCALE_ATREG) + { + SIB = true; + } - if (scale == SCALE_ATREG && ((_offsetOrBaseReg & 7) == 4)) - { - SIB = true; - ireg = _offsetOrBaseReg; - } + if (scale == SCALE_ATREG && ((_offsetOrBaseReg & 7) == 4)) + { + SIB = true; + ireg = _offsetOrBaseReg; + } - //Okay, we're fine. Just disp encoding. - //We need displacement. Which size? - int ioff = (int)(s64)offset; - if (ioff < -128 || ioff > 127) - { - mod = 2; //32-bit displacement - } - else - { - mod = 1; //8-bit displacement - } - } - } + // Okay, we're fine. Just disp encoding. + // We need displacement. Which size? + int ioff = (int)(s64)offset; + if (ioff < -128 || ioff > 127) + { + mod = 2; // 32-bit displacement + } + else + { + mod = 1; // 8-bit displacement + } + } + } - // Okay. Time to do the actual writing - // ModRM byte: - int oreg = _offsetOrBaseReg; - if (SIB) - oreg = 4; + // Okay. Time to do the actual writing + // ModRM byte: + int oreg = _offsetOrBaseReg; + if (SIB) + oreg = 4; - emit->WriteModRM(mod, _operandReg&7, oreg&7); + emit->WriteModRM(mod, _operandReg & 7, oreg & 7); - if (SIB) - { - //SIB byte - int ss; - switch (scale) - { - case SCALE_NONE: _offsetOrBaseReg = 4; ss = 0; break; //RSP - case SCALE_1: ss = 0; break; - case SCALE_2: ss = 1; break; - case SCALE_4: ss = 2; break; - case SCALE_8: ss = 3; break; - case SCALE_NOBASE_2: ss = 1; break; - case SCALE_NOBASE_4: ss = 2; break; - case SCALE_NOBASE_8: ss = 3; break; - case SCALE_ATREG: ss = 0; break; - default: _assert_msg_(DYNA_REC, 0, "Invalid scale for SIB byte"); ss = 0; break; - } - emit->Write8((u8)((ss << 6) | ((ireg&7)<<3) | (_offsetOrBaseReg&7))); - } + if (SIB) + { + // SIB byte + int ss; + switch (scale) + { + case SCALE_NONE: + _offsetOrBaseReg = 4; + ss = 0; + break; // RSP + case SCALE_1: + ss = 0; + break; + case SCALE_2: + ss = 1; + break; + case SCALE_4: + ss = 2; + break; + case SCALE_8: + ss = 3; + break; + case SCALE_NOBASE_2: + ss = 1; + break; + case SCALE_NOBASE_4: + ss = 2; + break; + case SCALE_NOBASE_8: + ss = 3; + break; + case SCALE_ATREG: + ss = 0; + break; + default: + _assert_msg_(DYNA_REC, 0, "Invalid scale for SIB byte"); + ss = 0; + break; + } + emit->Write8((u8)((ss << 6) | ((ireg & 7) << 3) | (_offsetOrBaseReg & 7))); + } - if (mod == 1) //8-bit disp - { - emit->Write8((u8)(s8)(s32)offset); - } - else if (mod == 2 || (scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8)) //32-bit disp - { - emit->Write32((u32)offset); - } + if (mod == 1) // 8-bit disp + { + emit->Write8((u8)(s8)(s32)offset); + } + else if (mod == 2 || (scale >= SCALE_NOBASE_2 && scale <= SCALE_NOBASE_8)) // 32-bit disp + { + emit->Write32((u32)offset); + } } // W = operand extended width (1 if 64-bit) @@ -351,1646 +372,2676 @@ void OpArg::WriteRest(XEmitter* emit, int extraBytes, X64Reg _operandReg, // B = base register# upper bit void XEmitter::Rex(int w, int r, int x, int b) { - w = w ? 1 : 0; - r = r ? 1 : 0; - x = x ? 1 : 0; - b = b ? 1 : 0; - u8 rx = (u8)(0x40 | (w << 3) | (r << 2) | (x << 1) | (b)); - if (rx != 0x40) - Write8(rx); + w = w ? 1 : 0; + r = r ? 1 : 0; + x = x ? 1 : 0; + b = b ? 1 : 0; + u8 rx = (u8)(0x40 | (w << 3) | (r << 2) | (x << 1) | (b)); + if (rx != 0x40) + Write8(rx); } void XEmitter::JMP(const u8* addr, bool force5Bytes) { - u64 fn = (u64)addr; - if (!force5Bytes) - { - s64 distance = (s64)(fn - ((u64)code + 2)); - _assert_msg_(DYNA_REC, distance >= -0x80 && distance < 0x80, - "Jump target too far away, needs force5Bytes = true"); - //8 bits will do - Write8(0xEB); - Write8((u8)(s8)distance); - } - else - { - s64 distance = (s64)(fn - ((u64)code + 5)); + u64 fn = (u64)addr; + if (!force5Bytes) + { + s64 distance = (s64)(fn - ((u64)code + 2)); + _assert_msg_(DYNA_REC, distance >= -0x80 && distance < 0x80, + "Jump target too far away, needs force5Bytes = true"); + // 8 bits will do + Write8(0xEB); + Write8((u8)(s8)distance); + } + else + { + s64 distance = (s64)(fn - ((u64)code + 5)); - _assert_msg_(DYNA_REC, - distance >= -0x80000000LL && distance < 0x80000000LL, - "Jump target too far away, needs indirect register"); - Write8(0xE9); - Write32((u32)(s32)distance); - } + _assert_msg_(DYNA_REC, distance >= -0x80000000LL && distance < 0x80000000LL, + "Jump target too far away, needs indirect register"); + Write8(0xE9); + Write32((u32)(s32)distance); + } } void XEmitter::JMPptr(const OpArg& arg2) { - OpArg arg = arg2; - if (arg.IsImm()) _assert_msg_(DYNA_REC, 0, "JMPptr - Imm argument"); - arg.operandReg = 4; - arg.WriteREX(this, 0, 0); - Write8(0xFF); - arg.WriteRest(this); + OpArg arg = arg2; + if (arg.IsImm()) + _assert_msg_(DYNA_REC, 0, "JMPptr - Imm argument"); + arg.operandReg = 4; + arg.WriteREX(this, 0, 0); + Write8(0xFF); + arg.WriteRest(this); } -//Can be used to trap other processors, before overwriting their code +// Can be used to trap other processors, before overwriting their code // not used in Dolphin void XEmitter::JMPself() { - Write8(0xEB); - Write8(0xFE); + Write8(0xEB); + Write8(0xFE); } void XEmitter::CALLptr(OpArg arg) { - if (arg.IsImm()) _assert_msg_(DYNA_REC, 0, "CALLptr - Imm argument"); - arg.operandReg = 2; - arg.WriteREX(this, 0, 0); - Write8(0xFF); - arg.WriteRest(this); + if (arg.IsImm()) + _assert_msg_(DYNA_REC, 0, "CALLptr - Imm argument"); + arg.operandReg = 2; + arg.WriteREX(this, 0, 0); + Write8(0xFF); + arg.WriteRest(this); } void XEmitter::CALL(const void* fnptr) { - u64 distance = u64(fnptr) - (u64(code) + 5); - _assert_msg_(DYNA_REC, - distance < 0x0000000080000000ULL || - distance >= 0xFFFFFFFF80000000ULL, - "CALL out of range (%p calls %p)", code, fnptr); - Write8(0xE8); - Write32(u32(distance)); + u64 distance = u64(fnptr) - (u64(code) + 5); + _assert_msg_(DYNA_REC, distance < 0x0000000080000000ULL || distance >= 0xFFFFFFFF80000000ULL, + "CALL out of range (%p calls %p)", code, fnptr); + Write8(0xE8); + Write32(u32(distance)); } FixupBranch XEmitter::J(bool force5bytes) { - FixupBranch branch; - branch.type = force5bytes ? 1 : 0; - branch.ptr = code + (force5bytes ? 5 : 2); - if (!force5bytes) - { - //8 bits will do - Write8(0xEB); - Write8(0); - } - else - { - Write8(0xE9); - Write32(0); - } - return branch; + FixupBranch branch; + branch.type = force5bytes ? 1 : 0; + branch.ptr = code + (force5bytes ? 5 : 2); + if (!force5bytes) + { + // 8 bits will do + Write8(0xEB); + Write8(0); + } + else + { + Write8(0xE9); + Write32(0); + } + return branch; } FixupBranch XEmitter::J_CC(CCFlags conditionCode, bool force5bytes) { - FixupBranch branch; - branch.type = force5bytes ? 1 : 0; - branch.ptr = code + (force5bytes ? 6 : 2); - if (!force5bytes) - { - //8 bits will do - Write8(0x70 + conditionCode); - Write8(0); - } - else - { - Write8(0x0F); - Write8(0x80 + conditionCode); - Write32(0); - } - return branch; + FixupBranch branch; + branch.type = force5bytes ? 1 : 0; + branch.ptr = code + (force5bytes ? 6 : 2); + if (!force5bytes) + { + // 8 bits will do + Write8(0x70 + conditionCode); + Write8(0); + } + else + { + Write8(0x0F); + Write8(0x80 + conditionCode); + Write32(0); + } + return branch; } void XEmitter::J_CC(CCFlags conditionCode, const u8* addr) { - u64 fn = (u64)addr; - s64 distance = (s64)(fn - ((u64)code + 2)); - if (distance < -0x80 || distance >= 0x80) - { - distance = (s64)(fn - ((u64)code + 6)); - _assert_msg_(DYNA_REC, - distance >= -0x80000000LL && distance < 0x80000000LL, - "Jump target too far away, needs indirect register"); - Write8(0x0F); - Write8(0x80 + conditionCode); - Write32((u32)(s32)distance); - } - else - { - Write8(0x70 + conditionCode); - Write8((u8)(s8)distance); - } + u64 fn = (u64)addr; + s64 distance = (s64)(fn - ((u64)code + 2)); + if (distance < -0x80 || distance >= 0x80) + { + distance = (s64)(fn - ((u64)code + 6)); + _assert_msg_(DYNA_REC, distance >= -0x80000000LL && distance < 0x80000000LL, + "Jump target too far away, needs indirect register"); + Write8(0x0F); + Write8(0x80 + conditionCode); + Write32((u32)(s32)distance); + } + else + { + Write8(0x70 + conditionCode); + Write8((u8)(s8)distance); + } } void XEmitter::SetJumpTarget(const FixupBranch& branch) { - if (branch.type == 0) - { - s64 distance = (s64)(code - branch.ptr); - _assert_msg_(DYNA_REC, distance >= -0x80 && distance < 0x80, "Jump target too far away, needs force5Bytes = true"); - branch.ptr[-1] = (u8)(s8)distance; - } - else if (branch.type == 1) - { - s64 distance = (s64)(code - branch.ptr); - _assert_msg_(DYNA_REC, distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target too far away, needs indirect register"); + if (branch.type == 0) + { + s64 distance = (s64)(code - branch.ptr); + _assert_msg_(DYNA_REC, distance >= -0x80 && distance < 0x80, + "Jump target too far away, needs force5Bytes = true"); + branch.ptr[-1] = (u8)(s8)distance; + } + else if (branch.type == 1) + { + s64 distance = (s64)(code - branch.ptr); + _assert_msg_(DYNA_REC, distance >= -0x80000000LL && distance < 0x80000000LL, + "Jump target too far away, needs indirect register"); - s32 valid_distance = static_cast(distance); - std::memcpy(&branch.ptr[-4], &valid_distance, sizeof(s32)); - } + s32 valid_distance = static_cast(distance); + std::memcpy(&branch.ptr[-4], &valid_distance, sizeof(s32)); + } } -//Single byte opcodes -//There is no PUSHAD/POPAD in 64-bit mode. -void XEmitter::INT3() {Write8(0xCC);} -void XEmitter::RET() {Write8(0xC3);} -void XEmitter::RET_FAST() {Write8(0xF3); Write8(0xC3);} //two-byte return (rep ret) - recommended by AMD optimization manual for the case of jumping to a ret +// Single byte opcodes +// There is no PUSHAD/POPAD in 64-bit mode. +void XEmitter::INT3() +{ + Write8(0xCC); +} +void XEmitter::RET() +{ + Write8(0xC3); +} +void XEmitter::RET_FAST() +{ + Write8(0xF3); + Write8(0xC3); +} // two-byte return (rep ret) - recommended by AMD optimization manual for the case of jumping to + // a ret // The first sign of decadence: optimized NOPs. void XEmitter::NOP(size_t size) { - _dbg_assert_(DYNA_REC, (int)size > 0); - while (true) - { - switch (size) - { - case 0: - return; - case 1: - Write8(0x90); - return; - case 2: - Write8(0x66); Write8(0x90); - return; - case 3: - Write8(0x0F); Write8(0x1F); Write8(0x00); - return; - case 4: - Write8(0x0F); Write8(0x1F); Write8(0x40); Write8(0x00); - return; - case 5: - Write8(0x0F); Write8(0x1F); Write8(0x44); Write8(0x00); - Write8(0x00); - return; - case 6: - Write8(0x66); Write8(0x0F); Write8(0x1F); Write8(0x44); - Write8(0x00); Write8(0x00); - return; - case 7: - Write8(0x0F); Write8(0x1F); Write8(0x80); Write8(0x00); - Write8(0x00); Write8(0x00); Write8(0x00); - return; - case 8: - Write8(0x0F); Write8(0x1F); Write8(0x84); Write8(0x00); - Write8(0x00); Write8(0x00); Write8(0x00); Write8(0x00); - return; - case 9: - Write8(0x66); Write8(0x0F); Write8(0x1F); Write8(0x84); - Write8(0x00); Write8(0x00); Write8(0x00); Write8(0x00); - Write8(0x00); - return; - case 10: - Write8(0x66); Write8(0x66); Write8(0x0F); Write8(0x1F); - Write8(0x84); Write8(0x00); Write8(0x00); Write8(0x00); - Write8(0x00); Write8(0x00); - return; - default: - // Even though x86 instructions are allowed to be up to 15 bytes long, - // AMD advises against using NOPs longer than 11 bytes because they - // carry a performance penalty on CPUs older than AMD family 16h. - Write8(0x66); Write8(0x66); Write8(0x66); Write8(0x0F); - Write8(0x1F); Write8(0x84); Write8(0x00); Write8(0x00); - Write8(0x00); Write8(0x00); Write8(0x00); - size -= 11; - continue; - } - } + _dbg_assert_(DYNA_REC, (int)size > 0); + while (true) + { + switch (size) + { + case 0: + return; + case 1: + Write8(0x90); + return; + case 2: + Write8(0x66); + Write8(0x90); + return; + case 3: + Write8(0x0F); + Write8(0x1F); + Write8(0x00); + return; + case 4: + Write8(0x0F); + Write8(0x1F); + Write8(0x40); + Write8(0x00); + return; + case 5: + Write8(0x0F); + Write8(0x1F); + Write8(0x44); + Write8(0x00); + Write8(0x00); + return; + case 6: + Write8(0x66); + Write8(0x0F); + Write8(0x1F); + Write8(0x44); + Write8(0x00); + Write8(0x00); + return; + case 7: + Write8(0x0F); + Write8(0x1F); + Write8(0x80); + Write8(0x00); + Write8(0x00); + Write8(0x00); + Write8(0x00); + return; + case 8: + Write8(0x0F); + Write8(0x1F); + Write8(0x84); + Write8(0x00); + Write8(0x00); + Write8(0x00); + Write8(0x00); + Write8(0x00); + return; + case 9: + Write8(0x66); + Write8(0x0F); + Write8(0x1F); + Write8(0x84); + Write8(0x00); + Write8(0x00); + Write8(0x00); + Write8(0x00); + Write8(0x00); + return; + case 10: + Write8(0x66); + Write8(0x66); + Write8(0x0F); + Write8(0x1F); + Write8(0x84); + Write8(0x00); + Write8(0x00); + Write8(0x00); + Write8(0x00); + Write8(0x00); + return; + default: + // Even though x86 instructions are allowed to be up to 15 bytes long, + // AMD advises against using NOPs longer than 11 bytes because they + // carry a performance penalty on CPUs older than AMD family 16h. + Write8(0x66); + Write8(0x66); + Write8(0x66); + Write8(0x0F); + Write8(0x1F); + Write8(0x84); + Write8(0x00); + Write8(0x00); + Write8(0x00); + Write8(0x00); + Write8(0x00); + size -= 11; + continue; + } + } } -void XEmitter::PAUSE() {Write8(0xF3); NOP();} //use in tight spinloops for energy saving on some CPU -void XEmitter::CLC() {CheckFlags(); Write8(0xF8);} //clear carry -void XEmitter::CMC() {CheckFlags(); Write8(0xF5);} //flip carry -void XEmitter::STC() {CheckFlags(); Write8(0xF9);} //set carry +void XEmitter::PAUSE() +{ + Write8(0xF3); + NOP(); +} // use in tight spinloops for energy saving on some CPU +void XEmitter::CLC() +{ + CheckFlags(); + Write8(0xF8); +} // clear carry +void XEmitter::CMC() +{ + CheckFlags(); + Write8(0xF5); +} // flip carry +void XEmitter::STC() +{ + CheckFlags(); + Write8(0xF9); +} // set carry -//TODO: xchg ah, al ??? +// TODO: xchg ah, al ??? void XEmitter::XCHG_AHAL() { - Write8(0x86); - Write8(0xe0); - // alt. 86 c4 + Write8(0x86); + Write8(0xe0); + // alt. 86 c4 } -//These two can not be executed on early Intel 64-bit CPU:s, only on AMD! -void XEmitter::LAHF() {Write8(0x9F);} -void XEmitter::SAHF() {CheckFlags(); Write8(0x9E);} +// These two can not be executed on early Intel 64-bit CPU:s, only on AMD! +void XEmitter::LAHF() +{ + Write8(0x9F); +} +void XEmitter::SAHF() +{ + CheckFlags(); + Write8(0x9E); +} -void XEmitter::PUSHF() {Write8(0x9C);} -void XEmitter::POPF() {CheckFlags(); Write8(0x9D);} +void XEmitter::PUSHF() +{ + Write8(0x9C); +} +void XEmitter::POPF() +{ + CheckFlags(); + Write8(0x9D); +} -void XEmitter::LFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xE8);} -void XEmitter::MFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xF0);} -void XEmitter::SFENCE() {Write8(0x0F); Write8(0xAE); Write8(0xF8);} +void XEmitter::LFENCE() +{ + Write8(0x0F); + Write8(0xAE); + Write8(0xE8); +} +void XEmitter::MFENCE() +{ + Write8(0x0F); + Write8(0xAE); + Write8(0xF0); +} +void XEmitter::SFENCE() +{ + Write8(0x0F); + Write8(0xAE); + Write8(0xF8); +} void XEmitter::WriteSimple1Byte(int bits, u8 byte, X64Reg reg) { - if (bits == 16) - Write8(0x66); - Rex(bits == 64, 0, 0, (int)reg >> 3); - Write8(byte + ((int)reg & 7)); + if (bits == 16) + Write8(0x66); + Rex(bits == 64, 0, 0, (int)reg >> 3); + Write8(byte + ((int)reg & 7)); } void XEmitter::WriteSimple2Byte(int bits, u8 byte1, u8 byte2, X64Reg reg) { - if (bits == 16) - Write8(0x66); - Rex(bits==64, 0, 0, (int)reg >> 3); - Write8(byte1); - Write8(byte2 + ((int)reg & 7)); + if (bits == 16) + Write8(0x66); + Rex(bits == 64, 0, 0, (int)reg >> 3); + Write8(byte1); + Write8(byte2 + ((int)reg & 7)); } void XEmitter::CWD(int bits) { - if (bits == 16) - Write8(0x66); - Rex(bits == 64, 0, 0, 0); - Write8(0x99); + if (bits == 16) + Write8(0x66); + Rex(bits == 64, 0, 0, 0); + Write8(0x99); } void XEmitter::CBW(int bits) { - if (bits == 8) - Write8(0x66); - Rex(bits == 32, 0, 0, 0); - Write8(0x98); + if (bits == 8) + Write8(0x66); + Rex(bits == 32, 0, 0, 0); + Write8(0x98); } -//Simple opcodes +// Simple opcodes - -//push/pop do not need wide to be 64-bit -void XEmitter::PUSH(X64Reg reg) {WriteSimple1Byte(32, 0x50, reg);} -void XEmitter::POP(X64Reg reg) {WriteSimple1Byte(32, 0x58, reg);} +// push/pop do not need wide to be 64-bit +void XEmitter::PUSH(X64Reg reg) +{ + WriteSimple1Byte(32, 0x50, reg); +} +void XEmitter::POP(X64Reg reg) +{ + WriteSimple1Byte(32, 0x58, reg); +} void XEmitter::PUSH(int bits, const OpArg& reg) { - if (reg.IsSimpleReg()) - PUSH(reg.GetSimpleReg()); - else if (reg.IsImm()) - { - switch (reg.GetImmBits()) - { - case 8: - Write8(0x6A); - Write8((u8)(s8)reg.offset); - break; - case 16: - Write8(0x66); - Write8(0x68); - Write16((u16)(s16)(s32)reg.offset); - break; - case 32: - Write8(0x68); - Write32((u32)reg.offset); - break; - default: - _assert_msg_(DYNA_REC, 0, "PUSH - Bad imm bits"); - break; - } - } - else - { - if (bits == 16) - Write8(0x66); - reg.WriteREX(this, bits, bits); - Write8(0xFF); - reg.WriteRest(this, 0, (X64Reg)6); - } + if (reg.IsSimpleReg()) + PUSH(reg.GetSimpleReg()); + else if (reg.IsImm()) + { + switch (reg.GetImmBits()) + { + case 8: + Write8(0x6A); + Write8((u8)(s8)reg.offset); + break; + case 16: + Write8(0x66); + Write8(0x68); + Write16((u16)(s16)(s32)reg.offset); + break; + case 32: + Write8(0x68); + Write32((u32)reg.offset); + break; + default: + _assert_msg_(DYNA_REC, 0, "PUSH - Bad imm bits"); + break; + } + } + else + { + if (bits == 16) + Write8(0x66); + reg.WriteREX(this, bits, bits); + Write8(0xFF); + reg.WriteRest(this, 0, (X64Reg)6); + } } void XEmitter::POP(int /*bits*/, const OpArg& reg) { - if (reg.IsSimpleReg()) - POP(reg.GetSimpleReg()); - else - _assert_msg_(DYNA_REC, 0, "POP - Unsupported encoding"); + if (reg.IsSimpleReg()) + POP(reg.GetSimpleReg()); + else + _assert_msg_(DYNA_REC, 0, "POP - Unsupported encoding"); } void XEmitter::BSWAP(int bits, X64Reg reg) { - if (bits >= 32) - { - WriteSimple2Byte(bits, 0x0F, 0xC8, reg); - } - else if (bits == 16) - { - ROL(16, R(reg), Imm8(8)); - } - else if (bits == 8) - { - // Do nothing - can't bswap a single byte... - } - else - { - _assert_msg_(DYNA_REC, 0, "BSWAP - Wrong number of bits"); - } + if (bits >= 32) + { + WriteSimple2Byte(bits, 0x0F, 0xC8, reg); + } + else if (bits == 16) + { + ROL(16, R(reg), Imm8(8)); + } + else if (bits == 8) + { + // Do nothing - can't bswap a single byte... + } + else + { + _assert_msg_(DYNA_REC, 0, "BSWAP - Wrong number of bits"); + } } // Undefined opcode - reserved // If we ever need a way to always cause a non-breakpoint hard exception... void XEmitter::UD2() { - Write8(0x0F); - Write8(0x0B); + Write8(0x0F); + Write8(0x0B); } void XEmitter::PREFETCH(PrefetchLevel level, OpArg arg) { - _assert_msg_(DYNA_REC, !arg.IsImm(), "PREFETCH - Imm argument"); - arg.operandReg = (u8)level; - arg.WriteREX(this, 0, 0); - Write8(0x0F); - Write8(0x18); - arg.WriteRest(this); + _assert_msg_(DYNA_REC, !arg.IsImm(), "PREFETCH - Imm argument"); + arg.operandReg = (u8)level; + arg.WriteREX(this, 0, 0); + Write8(0x0F); + Write8(0x18); + arg.WriteRest(this); } void XEmitter::SETcc(CCFlags flag, OpArg dest) { - _assert_msg_(DYNA_REC, !dest.IsImm(), "SETcc - Imm argument"); - dest.operandReg = 0; - dest.WriteREX(this, 0, 8); - Write8(0x0F); - Write8(0x90 + (u8)flag); - dest.WriteRest(this); + _assert_msg_(DYNA_REC, !dest.IsImm(), "SETcc - Imm argument"); + dest.operandReg = 0; + dest.WriteREX(this, 0, 8); + Write8(0x0F); + Write8(0x90 + (u8)flag); + dest.WriteRest(this); } void XEmitter::CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag) { - _assert_msg_(DYNA_REC, !src.IsImm(), "CMOVcc - Imm argument"); - _assert_msg_(DYNA_REC, bits != 8, "CMOVcc - 8 bits unsupported"); - if (bits == 16) - Write8(0x66); - src.operandReg = dest; - src.WriteREX(this, bits, bits); - Write8(0x0F); - Write8(0x40 + (u8)flag); - src.WriteRest(this); + _assert_msg_(DYNA_REC, !src.IsImm(), "CMOVcc - Imm argument"); + _assert_msg_(DYNA_REC, bits != 8, "CMOVcc - 8 bits unsupported"); + if (bits == 16) + Write8(0x66); + src.operandReg = dest; + src.WriteREX(this, bits, bits); + Write8(0x0F); + Write8(0x40 + (u8)flag); + src.WriteRest(this); } void XEmitter::WriteMulDivType(int bits, OpArg src, int ext) { - _assert_msg_(DYNA_REC, !src.IsImm(), "WriteMulDivType - Imm argument"); - CheckFlags(); - src.operandReg = ext; - if (bits == 16) - Write8(0x66); - src.WriteREX(this, bits, bits, 0); - if (bits == 8) - { - Write8(0xF6); - } - else - { - Write8(0xF7); - } - src.WriteRest(this); + _assert_msg_(DYNA_REC, !src.IsImm(), "WriteMulDivType - Imm argument"); + CheckFlags(); + src.operandReg = ext; + if (bits == 16) + Write8(0x66); + src.WriteREX(this, bits, bits, 0); + if (bits == 8) + { + Write8(0xF6); + } + else + { + Write8(0xF7); + } + src.WriteRest(this); } -void XEmitter::MUL(int bits, const OpArg& src) {WriteMulDivType(bits, src, 4);} -void XEmitter::DIV(int bits, const OpArg& src) {WriteMulDivType(bits, src, 6);} -void XEmitter::IMUL(int bits, const OpArg& src) {WriteMulDivType(bits, src, 5);} -void XEmitter::IDIV(int bits, const OpArg& src) {WriteMulDivType(bits, src, 7);} -void XEmitter::NEG(int bits, const OpArg& src) {WriteMulDivType(bits, src, 3);} -void XEmitter::NOT(int bits, const OpArg& src) {WriteMulDivType(bits, src, 2);} +void XEmitter::MUL(int bits, const OpArg& src) +{ + WriteMulDivType(bits, src, 4); +} +void XEmitter::DIV(int bits, const OpArg& src) +{ + WriteMulDivType(bits, src, 6); +} +void XEmitter::IMUL(int bits, const OpArg& src) +{ + WriteMulDivType(bits, src, 5); +} +void XEmitter::IDIV(int bits, const OpArg& src) +{ + WriteMulDivType(bits, src, 7); +} +void XEmitter::NEG(int bits, const OpArg& src) +{ + WriteMulDivType(bits, src, 3); +} +void XEmitter::NOT(int bits, const OpArg& src) +{ + WriteMulDivType(bits, src, 2); +} void XEmitter::WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2, bool rep) { - _assert_msg_(DYNA_REC, !src.IsImm(), "WriteBitSearchType - Imm argument"); - CheckFlags(); - src.operandReg = (u8)dest; - if (bits == 16) - Write8(0x66); - if (rep) - Write8(0xF3); - src.WriteREX(this, bits, bits); - Write8(0x0F); - Write8(byte2); - src.WriteRest(this); + _assert_msg_(DYNA_REC, !src.IsImm(), "WriteBitSearchType - Imm argument"); + CheckFlags(); + src.operandReg = (u8)dest; + if (bits == 16) + Write8(0x66); + if (rep) + Write8(0xF3); + src.WriteREX(this, bits, bits); + Write8(0x0F); + Write8(byte2); + src.WriteRest(this); } void XEmitter::MOVNTI(int bits, const OpArg& dest, X64Reg src) { - if (bits <= 16) - _assert_msg_(DYNA_REC, 0, "MOVNTI - bits<=16"); - WriteBitSearchType(bits, src, dest, 0xC3); + if (bits <= 16) + _assert_msg_(DYNA_REC, 0, "MOVNTI - bits<=16"); + WriteBitSearchType(bits, src, dest, 0xC3); } -void XEmitter::BSF(int bits, X64Reg dest, const OpArg& src) {WriteBitSearchType(bits,dest,src,0xBC);} // Bottom bit to top bit -void XEmitter::BSR(int bits, X64Reg dest, const OpArg& src) {WriteBitSearchType(bits,dest,src,0xBD);} // Top bit to bottom bit +void XEmitter::BSF(int bits, X64Reg dest, const OpArg& src) +{ + WriteBitSearchType(bits, dest, src, 0xBC); +} // Bottom bit to top bit +void XEmitter::BSR(int bits, X64Reg dest, const OpArg& src) +{ + WriteBitSearchType(bits, dest, src, 0xBD); +} // Top bit to bottom bit void XEmitter::TZCNT(int bits, X64Reg dest, const OpArg& src) { - CheckFlags(); - if (!cpu_info.bBMI1) - PanicAlert("Trying to use BMI1 on a system that doesn't support it. Bad programmer."); - WriteBitSearchType(bits, dest, src, 0xBC, true); + CheckFlags(); + if (!cpu_info.bBMI1) + PanicAlert("Trying to use BMI1 on a system that doesn't support it. Bad programmer."); + WriteBitSearchType(bits, dest, src, 0xBC, true); } void XEmitter::LZCNT(int bits, X64Reg dest, const OpArg& src) { - CheckFlags(); - if (!cpu_info.bLZCNT) - PanicAlert("Trying to use LZCNT on a system that doesn't support it. Bad programmer."); - WriteBitSearchType(bits, dest, src, 0xBD, true); + CheckFlags(); + if (!cpu_info.bLZCNT) + PanicAlert("Trying to use LZCNT on a system that doesn't support it. Bad programmer."); + WriteBitSearchType(bits, dest, src, 0xBD, true); } void XEmitter::MOVSX(int dbits, int sbits, X64Reg dest, OpArg src) { - _assert_msg_(DYNA_REC, !src.IsImm(), "MOVSX - Imm argument"); - if (dbits == sbits) - { - MOV(dbits, R(dest), src); - return; - } - src.operandReg = (u8)dest; - if (dbits == 16) - Write8(0x66); - src.WriteREX(this, dbits, sbits); - if (sbits == 8) - { - Write8(0x0F); - Write8(0xBE); - } - else if (sbits == 16) - { - Write8(0x0F); - Write8(0xBF); - } - else if (sbits == 32 && dbits == 64) - { - Write8(0x63); - } - else - { - Crash(); - } - src.WriteRest(this); + _assert_msg_(DYNA_REC, !src.IsImm(), "MOVSX - Imm argument"); + if (dbits == sbits) + { + MOV(dbits, R(dest), src); + return; + } + src.operandReg = (u8)dest; + if (dbits == 16) + Write8(0x66); + src.WriteREX(this, dbits, sbits); + if (sbits == 8) + { + Write8(0x0F); + Write8(0xBE); + } + else if (sbits == 16) + { + Write8(0x0F); + Write8(0xBF); + } + else if (sbits == 32 && dbits == 64) + { + Write8(0x63); + } + else + { + Crash(); + } + src.WriteRest(this); } void XEmitter::MOVZX(int dbits, int sbits, X64Reg dest, OpArg src) { - _assert_msg_(DYNA_REC, !src.IsImm(), "MOVZX - Imm argument"); - if (dbits == sbits) - { - MOV(dbits, R(dest), src); - return; - } - src.operandReg = (u8)dest; - if (dbits == 16) - Write8(0x66); - //the 32bit result is automatically zero extended to 64bit - src.WriteREX(this, dbits == 64 ? 32 : dbits, sbits); - if (sbits == 8) - { - Write8(0x0F); - Write8(0xB6); - } - else if (sbits == 16) - { - Write8(0x0F); - Write8(0xB7); - } - else if (sbits == 32 && dbits == 64) - { - Write8(0x8B); - } - else - { - _assert_msg_(DYNA_REC, 0, "MOVZX - Invalid size"); - } - src.WriteRest(this); + _assert_msg_(DYNA_REC, !src.IsImm(), "MOVZX - Imm argument"); + if (dbits == sbits) + { + MOV(dbits, R(dest), src); + return; + } + src.operandReg = (u8)dest; + if (dbits == 16) + Write8(0x66); + // the 32bit result is automatically zero extended to 64bit + src.WriteREX(this, dbits == 64 ? 32 : dbits, sbits); + if (sbits == 8) + { + Write8(0x0F); + Write8(0xB6); + } + else if (sbits == 16) + { + Write8(0x0F); + Write8(0xB7); + } + else if (sbits == 32 && dbits == 64) + { + Write8(0x8B); + } + else + { + _assert_msg_(DYNA_REC, 0, "MOVZX - Invalid size"); + } + src.WriteRest(this); } void XEmitter::WriteMOVBE(int bits, u8 op, X64Reg reg, const OpArg& arg) { - _assert_msg_(DYNA_REC, cpu_info.bMOVBE, "Generating MOVBE on a system that does not support it."); - if (bits == 8) - { - MOV(8, op & 1 ? arg : R(reg), op & 1 ? R(reg) : arg); - return; - } - if (bits == 16) - Write8(0x66); - _assert_msg_(DYNA_REC, !arg.IsSimpleReg() && !arg.IsImm(), "MOVBE: need r<-m or m<-r!"); - arg.WriteREX(this, bits, bits, reg); - Write8(0x0F); - Write8(0x38); - Write8(op); - arg.WriteRest(this, 0, reg); + _assert_msg_(DYNA_REC, cpu_info.bMOVBE, "Generating MOVBE on a system that does not support it."); + if (bits == 8) + { + MOV(8, op & 1 ? arg : R(reg), op & 1 ? R(reg) : arg); + return; + } + if (bits == 16) + Write8(0x66); + _assert_msg_(DYNA_REC, !arg.IsSimpleReg() && !arg.IsImm(), "MOVBE: need r<-m or m<-r!"); + arg.WriteREX(this, bits, bits, reg); + Write8(0x0F); + Write8(0x38); + Write8(op); + arg.WriteRest(this, 0, reg); +} +void XEmitter::MOVBE(int bits, X64Reg dest, const OpArg& src) +{ + WriteMOVBE(bits, 0xF0, dest, src); +} +void XEmitter::MOVBE(int bits, const OpArg& dest, X64Reg src) +{ + WriteMOVBE(bits, 0xF1, src, dest); } -void XEmitter::MOVBE(int bits, X64Reg dest, const OpArg& src) {WriteMOVBE(bits, 0xF0, dest, src);} -void XEmitter::MOVBE(int bits, const OpArg& dest, X64Reg src) {WriteMOVBE(bits, 0xF1, src, dest);} void XEmitter::LoadAndSwap(int size, X64Reg dst, const OpArg& src, bool sign_extend) { - switch (size) - { - case 8: - if (sign_extend) - MOVSX(32, 8, dst, src); - else - MOVZX(32, 8, dst, src); - break; - case 16: - MOVZX(32, 16, dst, src); - if (sign_extend) - { - BSWAP(32, dst); - SAR(32, R(dst), Imm8(16)); - } - else - { - ROL(16, R(dst), Imm8(8)); - } - break; - case 32: - case 64: - if (cpu_info.bMOVBE) - { - MOVBE(size, dst, src); - } - else - { - MOV(size, R(dst), src); - BSWAP(size, dst); - } - break; - } + switch (size) + { + case 8: + if (sign_extend) + MOVSX(32, 8, dst, src); + else + MOVZX(32, 8, dst, src); + break; + case 16: + MOVZX(32, 16, dst, src); + if (sign_extend) + { + BSWAP(32, dst); + SAR(32, R(dst), Imm8(16)); + } + else + { + ROL(16, R(dst), Imm8(8)); + } + break; + case 32: + case 64: + if (cpu_info.bMOVBE) + { + MOVBE(size, dst, src); + } + else + { + MOV(size, R(dst), src); + BSWAP(size, dst); + } + break; + } } u8* XEmitter::SwapAndStore(int size, const OpArg& dst, X64Reg src) { - u8* mov_location = GetWritableCodePtr(); - if (cpu_info.bMOVBE) - { - MOVBE(size, dst, src); - } - else - { - BSWAP(size, src); - mov_location = GetWritableCodePtr(); - MOV(size, dst, R(src)); - } - return mov_location; + u8* mov_location = GetWritableCodePtr(); + if (cpu_info.bMOVBE) + { + MOVBE(size, dst, src); + } + else + { + BSWAP(size, src); + mov_location = GetWritableCodePtr(); + MOV(size, dst, R(src)); + } + return mov_location; } - void XEmitter::LEA(int bits, X64Reg dest, OpArg src) { - _assert_msg_(DYNA_REC, !src.IsImm(), "LEA - Imm argument"); - src.operandReg = (u8)dest; - if (bits == 16) - Write8(0x66); //TODO: performance warning - src.WriteREX(this, bits, bits); - Write8(0x8D); - src.WriteRest(this, 0, INVALID_REG, bits == 64); + _assert_msg_(DYNA_REC, !src.IsImm(), "LEA - Imm argument"); + src.operandReg = (u8)dest; + if (bits == 16) + Write8(0x66); // TODO: performance warning + src.WriteREX(this, bits, bits); + Write8(0x8D); + src.WriteRest(this, 0, INVALID_REG, bits == 64); } -//shift can be either imm8 or cl +// shift can be either imm8 or cl void XEmitter::WriteShift(int bits, OpArg dest, const OpArg& shift, int ext) { - CheckFlags(); - bool writeImm = false; - if (dest.IsImm()) - { - _assert_msg_(DYNA_REC, 0, "WriteShift - can't shift imms"); - } - if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8)) - { - _assert_msg_(DYNA_REC, 0, "WriteShift - illegal argument"); - } - dest.operandReg = ext; - if (bits == 16) - Write8(0x66); - dest.WriteREX(this, bits, bits, 0); - if (shift.GetImmBits() == 8) - { - //ok an imm - u8 imm = (u8)shift.offset; - if (imm == 1) - { - Write8(bits == 8 ? 0xD0 : 0xD1); - } - else - { - writeImm = true; - Write8(bits == 8 ? 0xC0 : 0xC1); - } - } - else - { - Write8(bits == 8 ? 0xD2 : 0xD3); - } - dest.WriteRest(this, writeImm ? 1 : 0); - if (writeImm) - Write8((u8)shift.offset); + CheckFlags(); + bool writeImm = false; + if (dest.IsImm()) + { + _assert_msg_(DYNA_REC, 0, "WriteShift - can't shift imms"); + } + if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || + (shift.IsImm() && shift.GetImmBits() != 8)) + { + _assert_msg_(DYNA_REC, 0, "WriteShift - illegal argument"); + } + dest.operandReg = ext; + if (bits == 16) + Write8(0x66); + dest.WriteREX(this, bits, bits, 0); + if (shift.GetImmBits() == 8) + { + // ok an imm + u8 imm = (u8)shift.offset; + if (imm == 1) + { + Write8(bits == 8 ? 0xD0 : 0xD1); + } + else + { + writeImm = true; + Write8(bits == 8 ? 0xC0 : 0xC1); + } + } + else + { + Write8(bits == 8 ? 0xD2 : 0xD3); + } + dest.WriteRest(this, writeImm ? 1 : 0); + if (writeImm) + Write8((u8)shift.offset); } // large rotates and shift are slower on Intel than AMD // Intel likes to rotate by 1, and the op is smaller too -void XEmitter::ROL(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 0);} -void XEmitter::ROR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 1);} -void XEmitter::RCL(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 2);} -void XEmitter::RCR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 3);} -void XEmitter::SHL(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 4);} -void XEmitter::SHR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 5);} -void XEmitter::SAR(int bits, const OpArg& dest, const OpArg& shift) {WriteShift(bits, dest, shift, 7);} +void XEmitter::ROL(int bits, const OpArg& dest, const OpArg& shift) +{ + WriteShift(bits, dest, shift, 0); +} +void XEmitter::ROR(int bits, const OpArg& dest, const OpArg& shift) +{ + WriteShift(bits, dest, shift, 1); +} +void XEmitter::RCL(int bits, const OpArg& dest, const OpArg& shift) +{ + WriteShift(bits, dest, shift, 2); +} +void XEmitter::RCR(int bits, const OpArg& dest, const OpArg& shift) +{ + WriteShift(bits, dest, shift, 3); +} +void XEmitter::SHL(int bits, const OpArg& dest, const OpArg& shift) +{ + WriteShift(bits, dest, shift, 4); +} +void XEmitter::SHR(int bits, const OpArg& dest, const OpArg& shift) +{ + WriteShift(bits, dest, shift, 5); +} +void XEmitter::SAR(int bits, const OpArg& dest, const OpArg& shift) +{ + WriteShift(bits, dest, shift, 7); +} // index can be either imm8 or register, don't use memory destination because it's slow void XEmitter::WriteBitTest(int bits, const OpArg& dest, const OpArg& index, int ext) { - CheckFlags(); - if (dest.IsImm()) - { - _assert_msg_(DYNA_REC, 0, "WriteBitTest - can't test imms"); - } - if ((index.IsImm() && index.GetImmBits() != 8)) - { - _assert_msg_(DYNA_REC, 0, "WriteBitTest - illegal argument"); - } - if (bits == 16) - Write8(0x66); - if (index.IsImm()) - { - dest.WriteREX(this, bits, bits); - Write8(0x0F); Write8(0xBA); - dest.WriteRest(this, 1, (X64Reg)ext); - Write8((u8)index.offset); - } - else - { - X64Reg operand = index.GetSimpleReg(); - dest.WriteREX(this, bits, bits, operand); - Write8(0x0F); Write8(0x83 + 8*ext); - dest.WriteRest(this, 1, operand); - } + CheckFlags(); + if (dest.IsImm()) + { + _assert_msg_(DYNA_REC, 0, "WriteBitTest - can't test imms"); + } + if ((index.IsImm() && index.GetImmBits() != 8)) + { + _assert_msg_(DYNA_REC, 0, "WriteBitTest - illegal argument"); + } + if (bits == 16) + Write8(0x66); + if (index.IsImm()) + { + dest.WriteREX(this, bits, bits); + Write8(0x0F); + Write8(0xBA); + dest.WriteRest(this, 1, (X64Reg)ext); + Write8((u8)index.offset); + } + else + { + X64Reg operand = index.GetSimpleReg(); + dest.WriteREX(this, bits, bits, operand); + Write8(0x0F); + Write8(0x83 + 8 * ext); + dest.WriteRest(this, 1, operand); + } } -void XEmitter::BT(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 4);} -void XEmitter::BTS(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 5);} -void XEmitter::BTR(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 6);} -void XEmitter::BTC(int bits, const OpArg& dest, const OpArg& index) {WriteBitTest(bits, dest, index, 7);} +void XEmitter::BT(int bits, const OpArg& dest, const OpArg& index) +{ + WriteBitTest(bits, dest, index, 4); +} +void XEmitter::BTS(int bits, const OpArg& dest, const OpArg& index) +{ + WriteBitTest(bits, dest, index, 5); +} +void XEmitter::BTR(int bits, const OpArg& dest, const OpArg& index) +{ + WriteBitTest(bits, dest, index, 6); +} +void XEmitter::BTC(int bits, const OpArg& dest, const OpArg& index) +{ + WriteBitTest(bits, dest, index, 7); +} -//shift can be either imm8 or cl +// shift can be either imm8 or cl void XEmitter::SHRD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) { - CheckFlags(); - if (dest.IsImm()) - { - _assert_msg_(DYNA_REC, 0, "SHRD - can't use imms as destination"); - } - if (!src.IsSimpleReg()) - { - _assert_msg_(DYNA_REC, 0, "SHRD - must use simple register as source"); - } - if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8)) - { - _assert_msg_(DYNA_REC, 0, "SHRD - illegal shift"); - } - if (bits == 16) - Write8(0x66); - X64Reg operand = src.GetSimpleReg(); - dest.WriteREX(this, bits, bits, operand); - if (shift.GetImmBits() == 8) - { - Write8(0x0F); Write8(0xAC); - dest.WriteRest(this, 1, operand); - Write8((u8)shift.offset); - } - else - { - Write8(0x0F); Write8(0xAD); - dest.WriteRest(this, 0, operand); - } + CheckFlags(); + if (dest.IsImm()) + { + _assert_msg_(DYNA_REC, 0, "SHRD - can't use imms as destination"); + } + if (!src.IsSimpleReg()) + { + _assert_msg_(DYNA_REC, 0, "SHRD - must use simple register as source"); + } + if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || + (shift.IsImm() && shift.GetImmBits() != 8)) + { + _assert_msg_(DYNA_REC, 0, "SHRD - illegal shift"); + } + if (bits == 16) + Write8(0x66); + X64Reg operand = src.GetSimpleReg(); + dest.WriteREX(this, bits, bits, operand); + if (shift.GetImmBits() == 8) + { + Write8(0x0F); + Write8(0xAC); + dest.WriteRest(this, 1, operand); + Write8((u8)shift.offset); + } + else + { + Write8(0x0F); + Write8(0xAD); + dest.WriteRest(this, 0, operand); + } } void XEmitter::SHLD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift) { - CheckFlags(); - if (dest.IsImm()) - { - _assert_msg_(DYNA_REC, 0, "SHLD - can't use imms as destination"); - } - if (!src.IsSimpleReg()) - { - _assert_msg_(DYNA_REC, 0, "SHLD - must use simple register as source"); - } - if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8)) - { - _assert_msg_(DYNA_REC, 0, "SHLD - illegal shift"); - } - if (bits == 16) - Write8(0x66); - X64Reg operand = src.GetSimpleReg(); - dest.WriteREX(this, bits, bits, operand); - if (shift.GetImmBits() == 8) - { - Write8(0x0F); Write8(0xA4); - dest.WriteRest(this, 1, operand); - Write8((u8)shift.offset); - } - else - { - Write8(0x0F); Write8(0xA5); - dest.WriteRest(this, 0, operand); - } + CheckFlags(); + if (dest.IsImm()) + { + _assert_msg_(DYNA_REC, 0, "SHLD - can't use imms as destination"); + } + if (!src.IsSimpleReg()) + { + _assert_msg_(DYNA_REC, 0, "SHLD - must use simple register as source"); + } + if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || + (shift.IsImm() && shift.GetImmBits() != 8)) + { + _assert_msg_(DYNA_REC, 0, "SHLD - illegal shift"); + } + if (bits == 16) + Write8(0x66); + X64Reg operand = src.GetSimpleReg(); + dest.WriteREX(this, bits, bits, operand); + if (shift.GetImmBits() == 8) + { + Write8(0x0F); + Write8(0xA4); + dest.WriteRest(this, 1, operand); + Write8((u8)shift.offset); + } + else + { + Write8(0x0F); + Write8(0xA5); + dest.WriteRest(this, 0, operand); + } } void OpArg::WriteSingleByteOp(XEmitter* emit, u8 op, X64Reg _operandReg, int bits) { - if (bits == 16) - emit->Write8(0x66); + if (bits == 16) + emit->Write8(0x66); - this->operandReg = (u8)_operandReg; - WriteREX(emit, bits, bits); - emit->Write8(op); - WriteRest(emit); + this->operandReg = (u8)_operandReg; + WriteREX(emit, bits, bits); + emit->Write8(op); + WriteRest(emit); } -//operand can either be immediate or register -void OpArg::WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& operand, int bits) const +// operand can either be immediate or register +void OpArg::WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& operand, + int bits) const { - X64Reg _operandReg; - if (IsImm()) - { - _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Imm argument, wrong order"); - } + X64Reg _operandReg; + if (IsImm()) + { + _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Imm argument, wrong order"); + } - if (bits == 16) - emit->Write8(0x66); + if (bits == 16) + emit->Write8(0x66); - int immToWrite = 0; + int immToWrite = 0; - if (operand.IsImm()) - { - WriteREX(emit, bits, bits); + if (operand.IsImm()) + { + WriteREX(emit, bits, bits); - if (!toRM) - { - _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Writing to Imm (!toRM)"); - } + if (!toRM) + { + _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Writing to Imm (!toRM)"); + } - if (operand.scale == SCALE_IMM8 && bits == 8) - { - // op al, imm8 - if (!scale && offsetOrBaseReg == AL && normalops[op].eaximm8 != 0xCC) - { - emit->Write8(normalops[op].eaximm8); - emit->Write8((u8)operand.offset); - return; - } - // mov reg, imm8 - if (!scale && op == nrmMOV) - { - emit->Write8(0xB0 + (offsetOrBaseReg & 7)); - emit->Write8((u8)operand.offset); - return; - } - // op r/m8, imm8 - emit->Write8(normalops[op].imm8); - immToWrite = 8; - } - else if ((operand.scale == SCALE_IMM16 && bits == 16) || - (operand.scale == SCALE_IMM32 && bits == 32) || - (operand.scale == SCALE_IMM32 && bits == 64)) - { - // Try to save immediate size if we can, but first check to see - // if the instruction supports simm8. - // op r/m, imm8 - if (normalops[op].simm8 != 0xCC && - ((operand.scale == SCALE_IMM16 && (s16)operand.offset == (s8)operand.offset) || - (operand.scale == SCALE_IMM32 && (s32)operand.offset == (s8)operand.offset))) - { - emit->Write8(normalops[op].simm8); - immToWrite = 8; - } - else - { - // mov reg, imm - if (!scale && op == nrmMOV && bits != 64) - { - emit->Write8(0xB8 + (offsetOrBaseReg & 7)); - if (bits == 16) - emit->Write16((u16)operand.offset); - else - emit->Write32((u32)operand.offset); - return; - } - // op eax, imm - if (!scale && offsetOrBaseReg == EAX && normalops[op].eaximm32 != 0xCC) - { - emit->Write8(normalops[op].eaximm32); - if (bits == 16) - emit->Write16((u16)operand.offset); - else - emit->Write32((u32)operand.offset); - return; - } - // op r/m, imm - emit->Write8(normalops[op].imm32); - immToWrite = bits == 16 ? 16 : 32; - } - } - else if ((operand.scale == SCALE_IMM8 && bits == 16) || - (operand.scale == SCALE_IMM8 && bits == 32) || - (operand.scale == SCALE_IMM8 && bits == 64)) - { - // op r/m, imm8 - emit->Write8(normalops[op].simm8); - immToWrite = 8; - } - else if (operand.scale == SCALE_IMM64 && bits == 64) - { - if (scale) - { - _assert_msg_(DYNA_REC, 0, "WriteNormalOp - MOV with 64-bit imm requres register destination"); - } - // mov reg64, imm64 - else if (op == nrmMOV) - { - emit->Write8(0xB8 + (offsetOrBaseReg & 7)); - emit->Write64((u64)operand.offset); - return; - } - _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Only MOV can take 64-bit imm"); - } - else - { - _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Unhandled case %d %d", operand.scale, bits); - } - _operandReg = (X64Reg)normalops[op].ext; //pass extension in REG of ModRM - } - else - { - _operandReg = (X64Reg)operand.offsetOrBaseReg; - WriteREX(emit, bits, bits, _operandReg); - // op r/m, reg - if (toRM) - { - emit->Write8(bits == 8 ? normalops[op].toRm8 : normalops[op].toRm32); - } - // op reg, r/m - else - { - emit->Write8(bits == 8 ? normalops[op].fromRm8 : normalops[op].fromRm32); - } - } - WriteRest(emit, immToWrite >> 3, _operandReg); - switch (immToWrite) - { - case 0: - break; - case 8: - emit->Write8((u8)operand.offset); - break; - case 16: - emit->Write16((u16)operand.offset); - break; - case 32: - emit->Write32((u32)operand.offset); - break; - default: - _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Unhandled case"); - } + if (operand.scale == SCALE_IMM8 && bits == 8) + { + // op al, imm8 + if (!scale && offsetOrBaseReg == AL && normalops[op].eaximm8 != 0xCC) + { + emit->Write8(normalops[op].eaximm8); + emit->Write8((u8)operand.offset); + return; + } + // mov reg, imm8 + if (!scale && op == nrmMOV) + { + emit->Write8(0xB0 + (offsetOrBaseReg & 7)); + emit->Write8((u8)operand.offset); + return; + } + // op r/m8, imm8 + emit->Write8(normalops[op].imm8); + immToWrite = 8; + } + else if ((operand.scale == SCALE_IMM16 && bits == 16) || + (operand.scale == SCALE_IMM32 && bits == 32) || + (operand.scale == SCALE_IMM32 && bits == 64)) + { + // Try to save immediate size if we can, but first check to see + // if the instruction supports simm8. + // op r/m, imm8 + if (normalops[op].simm8 != 0xCC && + ((operand.scale == SCALE_IMM16 && (s16)operand.offset == (s8)operand.offset) || + (operand.scale == SCALE_IMM32 && (s32)operand.offset == (s8)operand.offset))) + { + emit->Write8(normalops[op].simm8); + immToWrite = 8; + } + else + { + // mov reg, imm + if (!scale && op == nrmMOV && bits != 64) + { + emit->Write8(0xB8 + (offsetOrBaseReg & 7)); + if (bits == 16) + emit->Write16((u16)operand.offset); + else + emit->Write32((u32)operand.offset); + return; + } + // op eax, imm + if (!scale && offsetOrBaseReg == EAX && normalops[op].eaximm32 != 0xCC) + { + emit->Write8(normalops[op].eaximm32); + if (bits == 16) + emit->Write16((u16)operand.offset); + else + emit->Write32((u32)operand.offset); + return; + } + // op r/m, imm + emit->Write8(normalops[op].imm32); + immToWrite = bits == 16 ? 16 : 32; + } + } + else if ((operand.scale == SCALE_IMM8 && bits == 16) || + (operand.scale == SCALE_IMM8 && bits == 32) || + (operand.scale == SCALE_IMM8 && bits == 64)) + { + // op r/m, imm8 + emit->Write8(normalops[op].simm8); + immToWrite = 8; + } + else if (operand.scale == SCALE_IMM64 && bits == 64) + { + if (scale) + { + _assert_msg_(DYNA_REC, 0, + "WriteNormalOp - MOV with 64-bit imm requres register destination"); + } + // mov reg64, imm64 + else if (op == nrmMOV) + { + emit->Write8(0xB8 + (offsetOrBaseReg & 7)); + emit->Write64((u64)operand.offset); + return; + } + _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Only MOV can take 64-bit imm"); + } + else + { + _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Unhandled case %d %d", operand.scale, bits); + } + _operandReg = (X64Reg)normalops[op].ext; // pass extension in REG of ModRM + } + else + { + _operandReg = (X64Reg)operand.offsetOrBaseReg; + WriteREX(emit, bits, bits, _operandReg); + // op r/m, reg + if (toRM) + { + emit->Write8(bits == 8 ? normalops[op].toRm8 : normalops[op].toRm32); + } + // op reg, r/m + else + { + emit->Write8(bits == 8 ? normalops[op].fromRm8 : normalops[op].fromRm32); + } + } + WriteRest(emit, immToWrite >> 3, _operandReg); + switch (immToWrite) + { + case 0: + break; + case 8: + emit->Write8((u8)operand.offset); + break; + case 16: + emit->Write16((u16)operand.offset); + break; + case 32: + emit->Write32((u32)operand.offset); + break; + default: + _assert_msg_(DYNA_REC, 0, "WriteNormalOp - Unhandled case"); + } } void XEmitter::WriteNormalOp(int bits, NormalOp op, const OpArg& a1, const OpArg& a2) { - if (a1.IsImm()) - { - //Booh! Can't write to an imm - _assert_msg_(DYNA_REC, 0, "WriteNormalOp - a1 cannot be imm"); - return; - } - if (a2.IsImm()) - { - a1.WriteNormalOp(this, true, op, a2, bits); - } - else - { - if (a1.IsSimpleReg()) - { - a2.WriteNormalOp(this, false, op, a1, bits); - } - else - { - _assert_msg_(DYNA_REC, a2.IsSimpleReg() || a2.IsImm(), "WriteNormalOp - a1 and a2 cannot both be memory"); - a1.WriteNormalOp(this, true, op, a2, bits); - } - } + if (a1.IsImm()) + { + // Booh! Can't write to an imm + _assert_msg_(DYNA_REC, 0, "WriteNormalOp - a1 cannot be imm"); + return; + } + if (a2.IsImm()) + { + a1.WriteNormalOp(this, true, op, a2, bits); + } + else + { + if (a1.IsSimpleReg()) + { + a2.WriteNormalOp(this, false, op, a1, bits); + } + else + { + _assert_msg_(DYNA_REC, a2.IsSimpleReg() || a2.IsImm(), + "WriteNormalOp - a1 and a2 cannot both be memory"); + a1.WriteNormalOp(this, true, op, a2, bits); + } + } } -void XEmitter::ADD (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(bits, nrmADD, a1, a2);} -void XEmitter::ADC (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(bits, nrmADC, a1, a2);} -void XEmitter::SUB (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(bits, nrmSUB, a1, a2);} -void XEmitter::SBB (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(bits, nrmSBB, a1, a2);} -void XEmitter::AND (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(bits, nrmAND, a1, a2);} -void XEmitter::OR (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(bits, nrmOR , a1, a2);} -void XEmitter::XOR (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(bits, nrmXOR, a1, a2);} -void XEmitter::MOV (int bits, const OpArg& a1, const OpArg& a2) +void XEmitter::ADD(int bits, const OpArg& a1, const OpArg& a2) { - if (a1.IsSimpleReg() && a2.IsSimpleReg() && a1.GetSimpleReg() == a2.GetSimpleReg()) - ERROR_LOG(DYNA_REC, "Redundant MOV @ %p - bug in JIT?", code); - WriteNormalOp(bits, nrmMOV, a1, a2); + CheckFlags(); + WriteNormalOp(bits, nrmADD, a1, a2); +} +void XEmitter::ADC(int bits, const OpArg& a1, const OpArg& a2) +{ + CheckFlags(); + WriteNormalOp(bits, nrmADC, a1, a2); +} +void XEmitter::SUB(int bits, const OpArg& a1, const OpArg& a2) +{ + CheckFlags(); + WriteNormalOp(bits, nrmSUB, a1, a2); +} +void XEmitter::SBB(int bits, const OpArg& a1, const OpArg& a2) +{ + CheckFlags(); + WriteNormalOp(bits, nrmSBB, a1, a2); +} +void XEmitter::AND(int bits, const OpArg& a1, const OpArg& a2) +{ + CheckFlags(); + WriteNormalOp(bits, nrmAND, a1, a2); +} +void XEmitter::OR(int bits, const OpArg& a1, const OpArg& a2) +{ + CheckFlags(); + WriteNormalOp(bits, nrmOR, a1, a2); +} +void XEmitter::XOR(int bits, const OpArg& a1, const OpArg& a2) +{ + CheckFlags(); + WriteNormalOp(bits, nrmXOR, a1, a2); +} +void XEmitter::MOV(int bits, const OpArg& a1, const OpArg& a2) +{ + if (a1.IsSimpleReg() && a2.IsSimpleReg() && a1.GetSimpleReg() == a2.GetSimpleReg()) + ERROR_LOG(DYNA_REC, "Redundant MOV @ %p - bug in JIT?", code); + WriteNormalOp(bits, nrmMOV, a1, a2); +} +void XEmitter::TEST(int bits, const OpArg& a1, const OpArg& a2) +{ + CheckFlags(); + WriteNormalOp(bits, nrmTEST, a1, a2); +} +void XEmitter::CMP(int bits, const OpArg& a1, const OpArg& a2) +{ + CheckFlags(); + WriteNormalOp(bits, nrmCMP, a1, a2); +} +void XEmitter::XCHG(int bits, const OpArg& a1, const OpArg& a2) +{ + WriteNormalOp(bits, nrmXCHG, a1, a2); } -void XEmitter::TEST(int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(bits, nrmTEST, a1, a2);} -void XEmitter::CMP (int bits, const OpArg& a1, const OpArg& a2) {CheckFlags(); WriteNormalOp(bits, nrmCMP, a1, a2);} -void XEmitter::XCHG(int bits, const OpArg& a1, const OpArg& a2) {WriteNormalOp(bits, nrmXCHG, a1, a2);} void XEmitter::CMP_or_TEST(int bits, const OpArg& a1, const OpArg& a2) { - CheckFlags(); - if (a1.IsSimpleReg() && a2.IsImm() && a2.offset == 0) // turn 'CMP reg, 0' into shorter 'TEST reg, reg' - { - WriteNormalOp(bits, nrmTEST, a1, a1); - } - else - { - WriteNormalOp(bits, nrmCMP, a1, a2); - } + CheckFlags(); + if (a1.IsSimpleReg() && a2.IsImm() && + a2.offset == 0) // turn 'CMP reg, 0' into shorter 'TEST reg, reg' + { + WriteNormalOp(bits, nrmTEST, a1, a1); + } + else + { + WriteNormalOp(bits, nrmCMP, a1, a2); + } } void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a1, const OpArg& a2) { - CheckFlags(); - if (bits == 8) - { - _assert_msg_(DYNA_REC, 0, "IMUL - illegal bit size!"); - return; - } + CheckFlags(); + if (bits == 8) + { + _assert_msg_(DYNA_REC, 0, "IMUL - illegal bit size!"); + return; + } - if (a1.IsImm()) - { - _assert_msg_(DYNA_REC, 0, "IMUL - second arg cannot be imm!"); - return; - } + if (a1.IsImm()) + { + _assert_msg_(DYNA_REC, 0, "IMUL - second arg cannot be imm!"); + return; + } - if (!a2.IsImm()) - { - _assert_msg_(DYNA_REC, 0, "IMUL - third arg must be imm!"); - return; - } + if (!a2.IsImm()) + { + _assert_msg_(DYNA_REC, 0, "IMUL - third arg must be imm!"); + return; + } - if (bits == 16) - Write8(0x66); - a1.WriteREX(this, bits, bits, regOp); + if (bits == 16) + Write8(0x66); + a1.WriteREX(this, bits, bits, regOp); - if (a2.GetImmBits() == 8 || - (a2.GetImmBits() == 16 && (s8)a2.offset == (s16)a2.offset) || - (a2.GetImmBits() == 32 && (s8)a2.offset == (s32)a2.offset)) - { - Write8(0x6B); - a1.WriteRest(this, 1, regOp); - Write8((u8)a2.offset); - } - else - { - Write8(0x69); - if (a2.GetImmBits() == 16 && bits == 16) - { - a1.WriteRest(this, 2, regOp); - Write16((u16)a2.offset); - } - else if (a2.GetImmBits() == 32 && (bits == 32 || bits == 64)) - { - a1.WriteRest(this, 4, regOp); - Write32((u32)a2.offset); - } - else - { - _assert_msg_(DYNA_REC, 0, "IMUL - unhandled case!"); - } - } + if (a2.GetImmBits() == 8 || (a2.GetImmBits() == 16 && (s8)a2.offset == (s16)a2.offset) || + (a2.GetImmBits() == 32 && (s8)a2.offset == (s32)a2.offset)) + { + Write8(0x6B); + a1.WriteRest(this, 1, regOp); + Write8((u8)a2.offset); + } + else + { + Write8(0x69); + if (a2.GetImmBits() == 16 && bits == 16) + { + a1.WriteRest(this, 2, regOp); + Write16((u16)a2.offset); + } + else if (a2.GetImmBits() == 32 && (bits == 32 || bits == 64)) + { + a1.WriteRest(this, 4, regOp); + Write32((u32)a2.offset); + } + else + { + _assert_msg_(DYNA_REC, 0, "IMUL - unhandled case!"); + } + } } void XEmitter::IMUL(int bits, X64Reg regOp, const OpArg& a) { - CheckFlags(); - if (bits == 8) - { - _assert_msg_(DYNA_REC, 0, "IMUL - illegal bit size!"); - return; - } + CheckFlags(); + if (bits == 8) + { + _assert_msg_(DYNA_REC, 0, "IMUL - illegal bit size!"); + return; + } - if (a.IsImm()) - { - IMUL(bits, regOp, R(regOp), a) ; - return; - } + if (a.IsImm()) + { + IMUL(bits, regOp, R(regOp), a); + return; + } - if (bits == 16) - Write8(0x66); - a.WriteREX(this, bits, bits, regOp); - Write8(0x0F); - Write8(0xAF); - a.WriteRest(this, 0, regOp); + if (bits == 16) + Write8(0x66); + a.WriteREX(this, bits, bits, regOp); + Write8(0x0F); + Write8(0xAF); + a.WriteRest(this, 0, regOp); } - void XEmitter::WriteSSEOp(u8 opPrefix, u16 op, X64Reg regOp, OpArg arg, int extrabytes) { - if (opPrefix) - Write8(opPrefix); - arg.operandReg = regOp; - arg.WriteREX(this, 0, 0); - Write8(0x0F); - if (op > 0xFF) - Write8((op >> 8) & 0xFF); - Write8(op & 0xFF); - arg.WriteRest(this, extrabytes); + if (opPrefix) + Write8(opPrefix); + arg.operandReg = regOp; + arg.WriteREX(this, 0, 0); + Write8(0x0F); + if (op > 0xFF) + Write8((op >> 8) & 0xFF); + Write8(op & 0xFF); + arg.WriteRest(this, extrabytes); } static int GetVEXmmmmm(u16 op) { - // Currently, only 0x38 and 0x3A are used as secondary escape byte. - if ((op >> 8) == 0x3A) - return 3; - else if ((op >> 8) == 0x38) - return 2; - else - return 1; + // Currently, only 0x38 and 0x3A are used as secondary escape byte. + if ((op >> 8) == 0x3A) + return 3; + else if ((op >> 8) == 0x38) + return 2; + else + return 1; } static int GetVEXpp(u8 opPrefix) { - if (opPrefix == 0x66) - return 1; - else if (opPrefix == 0xF3) - return 2; - else if (opPrefix == 0xF2) - return 3; - else - return 0; + if (opPrefix == 0x66) + return 1; + else if (opPrefix == 0xF3) + return 2; + else if (opPrefix == 0xF2) + return 3; + else + return 0; } -void XEmitter::WriteVEXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int W, int extrabytes) +void XEmitter::WriteVEXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, + int W, int extrabytes) { - int mmmmm = GetVEXmmmmm(op); - int pp = GetVEXpp(opPrefix); - // FIXME: we currently don't support 256-bit instructions, and "size" is not the vector size here - arg.WriteVEX(this, regOp1, regOp2, 0, pp, mmmmm, W); - Write8(op & 0xFF); - arg.WriteRest(this, extrabytes, regOp1); + int mmmmm = GetVEXmmmmm(op); + int pp = GetVEXpp(opPrefix); + // FIXME: we currently don't support 256-bit instructions, and "size" is not the vector size here + arg.WriteVEX(this, regOp1, regOp2, 0, pp, mmmmm, W); + Write8(op & 0xFF); + arg.WriteRest(this, extrabytes, regOp1); } -void XEmitter::WriteVEXOp4(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, X64Reg regOp3, int W) +void XEmitter::WriteVEXOp4(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, + X64Reg regOp3, int W) { - WriteVEXOp(opPrefix, op, regOp1, regOp2, arg, W, 1); - Write8((u8)regOp3 << 4); + WriteVEXOp(opPrefix, op, regOp1, regOp2, arg, W, 1); + Write8((u8)regOp3 << 4); } -void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int W, int extrabytes) +void XEmitter::WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, + int W, int extrabytes) { - if (!cpu_info.bAVX) - PanicAlert("Trying to use AVX on a system that doesn't support it. Bad programmer."); - WriteVEXOp(opPrefix, op, regOp1, regOp2, arg, W, extrabytes); + if (!cpu_info.bAVX) + PanicAlert("Trying to use AVX on a system that doesn't support it. Bad programmer."); + WriteVEXOp(opPrefix, op, regOp1, regOp2, arg, W, extrabytes); } -void XEmitter::WriteAVXOp4(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, X64Reg regOp3, int W) +void XEmitter::WriteAVXOp4(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, + X64Reg regOp3, int W) { - if (!cpu_info.bAVX) - PanicAlert("Trying to use AVX on a system that doesn't support it. Bad programmer."); - WriteVEXOp4(opPrefix, op, regOp1, regOp2, arg, regOp3, W); + if (!cpu_info.bAVX) + PanicAlert("Trying to use AVX on a system that doesn't support it. Bad programmer."); + WriteVEXOp4(opPrefix, op, regOp1, regOp2, arg, regOp3, W); } void XEmitter::WriteFMA3Op(u8 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int W) { - if (!cpu_info.bFMA) - PanicAlert("Trying to use FMA3 on a system that doesn't support it. Computer is v. f'n madd."); - WriteVEXOp(0x66, 0x3800 | op, regOp1, regOp2, arg, W); + if (!cpu_info.bFMA) + PanicAlert("Trying to use FMA3 on a system that doesn't support it. Computer is v. f'n madd."); + WriteVEXOp(0x66, 0x3800 | op, regOp1, regOp2, arg, W); } -void XEmitter::WriteFMA4Op(u8 op, X64Reg dest, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int W) +void XEmitter::WriteFMA4Op(u8 op, X64Reg dest, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, + int W) { - if (!cpu_info.bFMA4) - PanicAlert("Trying to use FMA4 on a system that doesn't support it. Computer is v. f'n madd."); - WriteVEXOp4(0x66, 0x3A00 | op, dest, regOp1, arg, regOp2, W); + if (!cpu_info.bFMA4) + PanicAlert("Trying to use FMA4 on a system that doesn't support it. Computer is v. f'n madd."); + WriteVEXOp4(0x66, 0x3A00 | op, dest, regOp1, arg, regOp2, W); } -void XEmitter::WriteBMIOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) +void XEmitter::WriteBMIOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, + const OpArg& arg, int extrabytes) { - if (arg.IsImm()) - PanicAlert("BMI1/2 instructions don't support immediate operands."); - if (size != 32 && size != 64) - PanicAlert("BMI1/2 instructions only support 32-bit and 64-bit modes!"); - int W = size == 64; - WriteVEXOp(opPrefix, op, regOp1, regOp2, arg, W, extrabytes); + if (arg.IsImm()) + PanicAlert("BMI1/2 instructions don't support immediate operands."); + if (size != 32 && size != 64) + PanicAlert("BMI1/2 instructions only support 32-bit and 64-bit modes!"); + int W = size == 64; + WriteVEXOp(opPrefix, op, regOp1, regOp2, arg, W, extrabytes); } -void XEmitter::WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) +void XEmitter::WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, + const OpArg& arg, int extrabytes) { - CheckFlags(); - if (!cpu_info.bBMI1) - PanicAlert("Trying to use BMI1 on a system that doesn't support it. Bad programmer."); - WriteBMIOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes); + CheckFlags(); + if (!cpu_info.bBMI1) + PanicAlert("Trying to use BMI1 on a system that doesn't support it. Bad programmer."); + WriteBMIOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes); } -void XEmitter::WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes) +void XEmitter::WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, + const OpArg& arg, int extrabytes) { - if (!cpu_info.bBMI2) - PanicAlert("Trying to use BMI2 on a system that doesn't support it. Bad programmer."); - WriteBMIOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes); + if (!cpu_info.bBMI2) + PanicAlert("Trying to use BMI2 on a system that doesn't support it. Bad programmer."); + WriteBMIOp(size, opPrefix, op, regOp1, regOp2, arg, extrabytes); } -void XEmitter::MOVD_xmm(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x6E, dest, arg, 0);} -void XEmitter::MOVD_xmm(const OpArg& arg, X64Reg src) {WriteSSEOp(0x66, 0x7E, src, arg, 0);} +void XEmitter::MOVD_xmm(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x6E, dest, arg, 0); +} +void XEmitter::MOVD_xmm(const OpArg& arg, X64Reg src) +{ + WriteSSEOp(0x66, 0x7E, src, arg, 0); +} void XEmitter::MOVQ_xmm(X64Reg dest, OpArg arg) { - // Alternate encoding - // This does not display correctly in MSVC's debugger, it thinks it's a MOVD - arg.operandReg = dest; - Write8(0x66); - arg.WriteREX(this, 64, 0); - Write8(0x0f); - Write8(0x6E); - arg.WriteRest(this, 0); + // Alternate encoding + // This does not display correctly in MSVC's debugger, it thinks it's a MOVD + arg.operandReg = dest; + Write8(0x66); + arg.WriteREX(this, 64, 0); + Write8(0x0f); + Write8(0x6E); + arg.WriteRest(this, 0); } void XEmitter::MOVQ_xmm(OpArg arg, X64Reg src) { - if (src > 7 || arg.IsSimpleReg()) - { - // Alternate encoding - // This does not display correctly in MSVC's debugger, it thinks it's a MOVD - arg.operandReg = src; - Write8(0x66); - arg.WriteREX(this, 64, 0); - Write8(0x0f); - Write8(0x7E); - arg.WriteRest(this, 0); - } - else - { - arg.operandReg = src; - arg.WriteREX(this, 0, 0); - Write8(0x66); - Write8(0x0f); - Write8(0xD6); - arg.WriteRest(this, 0); - } + if (src > 7 || arg.IsSimpleReg()) + { + // Alternate encoding + // This does not display correctly in MSVC's debugger, it thinks it's a MOVD + arg.operandReg = src; + Write8(0x66); + arg.WriteREX(this, 64, 0); + Write8(0x0f); + Write8(0x7E); + arg.WriteRest(this, 0); + } + else + { + arg.operandReg = src; + arg.WriteREX(this, 0, 0); + Write8(0x66); + Write8(0x0f); + Write8(0xD6); + arg.WriteRest(this, 0); + } } void XEmitter::WriteMXCSR(OpArg arg, int ext) { - if (arg.IsImm() || arg.IsSimpleReg()) - _assert_msg_(DYNA_REC, 0, "MXCSR - invalid operand"); + if (arg.IsImm() || arg.IsSimpleReg()) + _assert_msg_(DYNA_REC, 0, "MXCSR - invalid operand"); - arg.operandReg = ext; - arg.WriteREX(this, 0, 0); - Write8(0x0F); - Write8(0xAE); - arg.WriteRest(this); + arg.operandReg = ext; + arg.WriteREX(this, 0, 0); + Write8(0x0F); + Write8(0xAE); + arg.WriteRest(this); } -void XEmitter::STMXCSR(const OpArg& memloc) {WriteMXCSR(memloc, 3);} -void XEmitter::LDMXCSR(const OpArg& memloc) {WriteMXCSR(memloc, 2);} +void XEmitter::STMXCSR(const OpArg& memloc) +{ + WriteMXCSR(memloc, 3); +} +void XEmitter::LDMXCSR(const OpArg& memloc) +{ + WriteMXCSR(memloc, 2); +} -void XEmitter::MOVNTDQ(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVNTDQ, regOp, arg);} -void XEmitter::MOVNTPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVNTP, regOp, arg);} -void XEmitter::MOVNTPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVNTP, regOp, arg);} +void XEmitter::MOVNTDQ(const OpArg& arg, X64Reg regOp) +{ + WriteSSEOp(0x66, sseMOVNTDQ, regOp, arg); +} +void XEmitter::MOVNTPS(const OpArg& arg, X64Reg regOp) +{ + WriteSSEOp(0x00, sseMOVNTP, regOp, arg); +} +void XEmitter::MOVNTPD(const OpArg& arg, X64Reg regOp) +{ + WriteSSEOp(0x66, sseMOVNTP, regOp, arg); +} -void XEmitter::ADDSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseADD, regOp, arg);} -void XEmitter::ADDSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseADD, regOp, arg);} -void XEmitter::SUBSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseSUB, regOp, arg);} -void XEmitter::SUBSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseSUB, regOp, arg);} -void XEmitter::CMPSS(X64Reg regOp, const OpArg& arg, u8 compare) {WriteSSEOp(0xF3, sseCMP, regOp, arg, 1); Write8(compare);} -void XEmitter::CMPSD(X64Reg regOp, const OpArg& arg, u8 compare) {WriteSSEOp(0xF2, sseCMP, regOp, arg, 1); Write8(compare);} -void XEmitter::MULSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMUL, regOp, arg);} -void XEmitter::MULSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMUL, regOp, arg);} -void XEmitter::DIVSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseDIV, regOp, arg);} -void XEmitter::DIVSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseDIV, regOp, arg);} -void XEmitter::MINSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMIN, regOp, arg);} -void XEmitter::MINSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMIN, regOp, arg);} -void XEmitter::MAXSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMAX, regOp, arg);} -void XEmitter::MAXSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMAX, regOp, arg);} -void XEmitter::SQRTSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseSQRT, regOp, arg);} -void XEmitter::SQRTSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseSQRT, regOp, arg);} -void XEmitter::RCPSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseRCP, regOp, arg);} -void XEmitter::RSQRTSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseRSQRT, regOp, arg);} +void XEmitter::ADDSS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, sseADD, regOp, arg); +} +void XEmitter::ADDSD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF2, sseADD, regOp, arg); +} +void XEmitter::SUBSS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, sseSUB, regOp, arg); +} +void XEmitter::SUBSD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF2, sseSUB, regOp, arg); +} +void XEmitter::CMPSS(X64Reg regOp, const OpArg& arg, u8 compare) +{ + WriteSSEOp(0xF3, sseCMP, regOp, arg, 1); + Write8(compare); +} +void XEmitter::CMPSD(X64Reg regOp, const OpArg& arg, u8 compare) +{ + WriteSSEOp(0xF2, sseCMP, regOp, arg, 1); + Write8(compare); +} +void XEmitter::MULSS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, sseMUL, regOp, arg); +} +void XEmitter::MULSD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF2, sseMUL, regOp, arg); +} +void XEmitter::DIVSS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, sseDIV, regOp, arg); +} +void XEmitter::DIVSD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF2, sseDIV, regOp, arg); +} +void XEmitter::MINSS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, sseMIN, regOp, arg); +} +void XEmitter::MINSD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF2, sseMIN, regOp, arg); +} +void XEmitter::MAXSS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, sseMAX, regOp, arg); +} +void XEmitter::MAXSD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF2, sseMAX, regOp, arg); +} +void XEmitter::SQRTSS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, sseSQRT, regOp, arg); +} +void XEmitter::SQRTSD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF2, sseSQRT, regOp, arg); +} +void XEmitter::RCPSS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, sseRCP, regOp, arg); +} +void XEmitter::RSQRTSS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, sseRSQRT, regOp, arg); +} -void XEmitter::ADDPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseADD, regOp, arg);} -void XEmitter::ADDPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseADD, regOp, arg);} -void XEmitter::SUBPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseSUB, regOp, arg);} -void XEmitter::SUBPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseSUB, regOp, arg);} -void XEmitter::CMPPS(X64Reg regOp, const OpArg& arg, u8 compare) {WriteSSEOp(0x00, sseCMP, regOp, arg, 1); Write8(compare);} -void XEmitter::CMPPD(X64Reg regOp, const OpArg& arg, u8 compare) {WriteSSEOp(0x66, sseCMP, regOp, arg, 1); Write8(compare);} -void XEmitter::ANDPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseAND, regOp, arg);} -void XEmitter::ANDPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseAND, regOp, arg);} -void XEmitter::ANDNPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseANDN, regOp, arg);} -void XEmitter::ANDNPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseANDN, regOp, arg);} -void XEmitter::ORPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseOR, regOp, arg);} -void XEmitter::ORPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseOR, regOp, arg);} -void XEmitter::XORPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseXOR, regOp, arg);} -void XEmitter::XORPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseXOR, regOp, arg);} -void XEmitter::MULPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMUL, regOp, arg);} -void XEmitter::MULPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMUL, regOp, arg);} -void XEmitter::DIVPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseDIV, regOp, arg);} -void XEmitter::DIVPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseDIV, regOp, arg);} -void XEmitter::MINPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMIN, regOp, arg);} -void XEmitter::MINPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMIN, regOp, arg);} -void XEmitter::MAXPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMAX, regOp, arg);} -void XEmitter::MAXPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMAX, regOp, arg);} -void XEmitter::SQRTPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseSQRT, regOp, arg);} -void XEmitter::SQRTPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseSQRT, regOp, arg);} -void XEmitter::RCPPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseRCP, regOp, arg);} -void XEmitter::RSQRTPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseRSQRT, regOp, arg);} -void XEmitter::SHUFPS(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0x00, sseSHUF, regOp, arg,1); Write8(shuffle);} -void XEmitter::SHUFPD(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0x66, sseSHUF, regOp, arg,1); Write8(shuffle);} +void XEmitter::ADDPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseADD, regOp, arg); +} +void XEmitter::ADDPD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseADD, regOp, arg); +} +void XEmitter::SUBPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseSUB, regOp, arg); +} +void XEmitter::SUBPD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseSUB, regOp, arg); +} +void XEmitter::CMPPS(X64Reg regOp, const OpArg& arg, u8 compare) +{ + WriteSSEOp(0x00, sseCMP, regOp, arg, 1); + Write8(compare); +} +void XEmitter::CMPPD(X64Reg regOp, const OpArg& arg, u8 compare) +{ + WriteSSEOp(0x66, sseCMP, regOp, arg, 1); + Write8(compare); +} +void XEmitter::ANDPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseAND, regOp, arg); +} +void XEmitter::ANDPD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseAND, regOp, arg); +} +void XEmitter::ANDNPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseANDN, regOp, arg); +} +void XEmitter::ANDNPD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseANDN, regOp, arg); +} +void XEmitter::ORPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseOR, regOp, arg); +} +void XEmitter::ORPD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseOR, regOp, arg); +} +void XEmitter::XORPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseXOR, regOp, arg); +} +void XEmitter::XORPD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseXOR, regOp, arg); +} +void XEmitter::MULPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseMUL, regOp, arg); +} +void XEmitter::MULPD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseMUL, regOp, arg); +} +void XEmitter::DIVPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseDIV, regOp, arg); +} +void XEmitter::DIVPD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseDIV, regOp, arg); +} +void XEmitter::MINPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseMIN, regOp, arg); +} +void XEmitter::MINPD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseMIN, regOp, arg); +} +void XEmitter::MAXPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseMAX, regOp, arg); +} +void XEmitter::MAXPD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseMAX, regOp, arg); +} +void XEmitter::SQRTPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseSQRT, regOp, arg); +} +void XEmitter::SQRTPD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseSQRT, regOp, arg); +} +void XEmitter::RCPPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseRCP, regOp, arg); +} +void XEmitter::RSQRTPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseRSQRT, regOp, arg); +} +void XEmitter::SHUFPS(X64Reg regOp, const OpArg& arg, u8 shuffle) +{ + WriteSSEOp(0x00, sseSHUF, regOp, arg, 1); + Write8(shuffle); +} +void XEmitter::SHUFPD(X64Reg regOp, const OpArg& arg, u8 shuffle) +{ + WriteSSEOp(0x66, sseSHUF, regOp, arg, 1); + Write8(shuffle); +} -void XEmitter::COMISS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseCOMIS, regOp, arg);} //weird that these should be packed -void XEmitter::COMISD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseCOMIS, regOp, arg);} //ordered -void XEmitter::UCOMISS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseUCOMIS, regOp, arg);} //unordered -void XEmitter::UCOMISD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseUCOMIS, regOp, arg);} +void XEmitter::COMISS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseCOMIS, regOp, arg); +} // weird that these should be packed +void XEmitter::COMISD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseCOMIS, regOp, arg); +} // ordered +void XEmitter::UCOMISS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseUCOMIS, regOp, arg); +} // unordered +void XEmitter::UCOMISD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseUCOMIS, regOp, arg); +} -void XEmitter::MOVAPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMOVAPfromRM, regOp, arg);} -void XEmitter::MOVAPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVAPfromRM, regOp, arg);} -void XEmitter::MOVAPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVAPtoRM, regOp, arg);} -void XEmitter::MOVAPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVAPtoRM, regOp, arg);} +void XEmitter::MOVAPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseMOVAPfromRM, regOp, arg); +} +void XEmitter::MOVAPD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseMOVAPfromRM, regOp, arg); +} +void XEmitter::MOVAPS(const OpArg& arg, X64Reg regOp) +{ + WriteSSEOp(0x00, sseMOVAPtoRM, regOp, arg); +} +void XEmitter::MOVAPD(const OpArg& arg, X64Reg regOp) +{ + WriteSSEOp(0x66, sseMOVAPtoRM, regOp, arg); +} -void XEmitter::MOVUPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMOVUPfromRM, regOp, arg);} -void XEmitter::MOVUPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVUPfromRM, regOp, arg);} -void XEmitter::MOVUPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVUPtoRM, regOp, arg);} -void XEmitter::MOVUPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVUPtoRM, regOp, arg);} +void XEmitter::MOVUPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseMOVUPfromRM, regOp, arg); +} +void XEmitter::MOVUPD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseMOVUPfromRM, regOp, arg); +} +void XEmitter::MOVUPS(const OpArg& arg, X64Reg regOp) +{ + WriteSSEOp(0x00, sseMOVUPtoRM, regOp, arg); +} +void XEmitter::MOVUPD(const OpArg& arg, X64Reg regOp) +{ + WriteSSEOp(0x66, sseMOVUPtoRM, regOp, arg); +} -void XEmitter::MOVDQA(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVDQfromRM, regOp, arg);} -void XEmitter::MOVDQA(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVDQtoRM, regOp, arg);} -void XEmitter::MOVDQU(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMOVDQfromRM, regOp, arg);} -void XEmitter::MOVDQU(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0xF3, sseMOVDQtoRM, regOp, arg);} +void XEmitter::MOVDQA(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseMOVDQfromRM, regOp, arg); +} +void XEmitter::MOVDQA(const OpArg& arg, X64Reg regOp) +{ + WriteSSEOp(0x66, sseMOVDQtoRM, regOp, arg); +} +void XEmitter::MOVDQU(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, sseMOVDQfromRM, regOp, arg); +} +void XEmitter::MOVDQU(const OpArg& arg, X64Reg regOp) +{ + WriteSSEOp(0xF3, sseMOVDQtoRM, regOp, arg); +} -void XEmitter::MOVSS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, sseMOVUPfromRM, regOp, arg);} -void XEmitter::MOVSD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, sseMOVUPfromRM, regOp, arg);} -void XEmitter::MOVSS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0xF3, sseMOVUPtoRM, regOp, arg);} -void XEmitter::MOVSD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0xF2, sseMOVUPtoRM, regOp, arg);} +void XEmitter::MOVSS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, sseMOVUPfromRM, regOp, arg); +} +void XEmitter::MOVSD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF2, sseMOVUPfromRM, regOp, arg); +} +void XEmitter::MOVSS(const OpArg& arg, X64Reg regOp) +{ + WriteSSEOp(0xF3, sseMOVUPtoRM, regOp, arg); +} +void XEmitter::MOVSD(const OpArg& arg, X64Reg regOp) +{ + WriteSSEOp(0xF2, sseMOVUPtoRM, regOp, arg); +} -void XEmitter::MOVLPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMOVLPfromRM, regOp, arg);} -void XEmitter::MOVLPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVLPfromRM, regOp, arg);} -void XEmitter::MOVLPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVLPtoRM, regOp, arg);} -void XEmitter::MOVLPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVLPtoRM, regOp, arg);} +void XEmitter::MOVLPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseMOVLPfromRM, regOp, arg); +} +void XEmitter::MOVLPD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseMOVLPfromRM, regOp, arg); +} +void XEmitter::MOVLPS(const OpArg& arg, X64Reg regOp) +{ + WriteSSEOp(0x00, sseMOVLPtoRM, regOp, arg); +} +void XEmitter::MOVLPD(const OpArg& arg, X64Reg regOp) +{ + WriteSSEOp(0x66, sseMOVLPtoRM, regOp, arg); +} -void XEmitter::MOVHPS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, sseMOVHPfromRM, regOp, arg);} -void XEmitter::MOVHPD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, sseMOVHPfromRM, regOp, arg);} -void XEmitter::MOVHPS(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x00, sseMOVHPtoRM, regOp, arg);} -void XEmitter::MOVHPD(const OpArg& arg, X64Reg regOp) {WriteSSEOp(0x66, sseMOVHPtoRM, regOp, arg);} +void XEmitter::MOVHPS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, sseMOVHPfromRM, regOp, arg); +} +void XEmitter::MOVHPD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, sseMOVHPfromRM, regOp, arg); +} +void XEmitter::MOVHPS(const OpArg& arg, X64Reg regOp) +{ + WriteSSEOp(0x00, sseMOVHPtoRM, regOp, arg); +} +void XEmitter::MOVHPD(const OpArg& arg, X64Reg regOp) +{ + WriteSSEOp(0x66, sseMOVHPtoRM, regOp, arg); +} -void XEmitter::MOVHLPS(X64Reg regOp1, X64Reg regOp2) {WriteSSEOp(0x00, sseMOVHLPS, regOp1, R(regOp2));} -void XEmitter::MOVLHPS(X64Reg regOp1, X64Reg regOp2) {WriteSSEOp(0x00, sseMOVLHPS, regOp1, R(regOp2));} +void XEmitter::MOVHLPS(X64Reg regOp1, X64Reg regOp2) +{ + WriteSSEOp(0x00, sseMOVHLPS, regOp1, R(regOp2)); +} +void XEmitter::MOVLHPS(X64Reg regOp1, X64Reg regOp2) +{ + WriteSSEOp(0x00, sseMOVLHPS, regOp1, R(regOp2)); +} -void XEmitter::CVTPS2PD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, 0x5A, regOp, arg);} -void XEmitter::CVTPD2PS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, 0x5A, regOp, arg);} +void XEmitter::CVTPS2PD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, 0x5A, regOp, arg); +} +void XEmitter::CVTPD2PS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x5A, regOp, arg); +} -void XEmitter::CVTSD2SS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x5A, regOp, arg);} -void XEmitter::CVTSS2SD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x5A, regOp, arg);} -void XEmitter::CVTSD2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x2D, regOp, arg);} -void XEmitter::CVTSS2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x2D, regOp, arg);} -void XEmitter::CVTSI2SD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x2A, regOp, arg);} -void XEmitter::CVTSI2SS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x2A, regOp, arg);} +void XEmitter::CVTSD2SS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF2, 0x5A, regOp, arg); +} +void XEmitter::CVTSS2SD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, 0x5A, regOp, arg); +} +void XEmitter::CVTSD2SI(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF2, 0x2D, regOp, arg); +} +void XEmitter::CVTSS2SI(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, 0x2D, regOp, arg); +} +void XEmitter::CVTSI2SD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF2, 0x2A, regOp, arg); +} +void XEmitter::CVTSI2SS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, 0x2A, regOp, arg); +} -void XEmitter::CVTDQ2PD(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0xE6, regOp, arg);} -void XEmitter::CVTDQ2PS(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x00, 0x5B, regOp, arg);} -void XEmitter::CVTPD2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0xE6, regOp, arg);} -void XEmitter::CVTPS2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, 0x5B, regOp, arg);} +void XEmitter::CVTDQ2PD(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, 0xE6, regOp, arg); +} +void XEmitter::CVTDQ2PS(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x00, 0x5B, regOp, arg); +} +void XEmitter::CVTPD2DQ(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF2, 0xE6, regOp, arg); +} +void XEmitter::CVTPS2DQ(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x5B, regOp, arg); +} -void XEmitter::CVTTSD2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF2, 0x2C, regOp, arg);} -void XEmitter::CVTTSS2SI(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x2C, regOp, arg);} -void XEmitter::CVTTPS2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0xF3, 0x5B, regOp, arg);} -void XEmitter::CVTTPD2DQ(X64Reg regOp, const OpArg& arg) {WriteSSEOp(0x66, 0xE6, regOp, arg);} +void XEmitter::CVTTSD2SI(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF2, 0x2C, regOp, arg); +} +void XEmitter::CVTTSS2SI(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, 0x2C, regOp, arg); +} +void XEmitter::CVTTPS2DQ(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0xF3, 0x5B, regOp, arg); +} +void XEmitter::CVTTPD2DQ(X64Reg regOp, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xE6, regOp, arg); +} -void XEmitter::MASKMOVDQU(X64Reg dest, X64Reg src) {WriteSSEOp(0x66, sseMASKMOVDQU, dest, R(src));} +void XEmitter::MASKMOVDQU(X64Reg dest, X64Reg src) +{ + WriteSSEOp(0x66, sseMASKMOVDQU, dest, R(src)); +} -void XEmitter::MOVMSKPS(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x00, 0x50, dest, arg);} -void XEmitter::MOVMSKPD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x50, dest, arg);} +void XEmitter::MOVMSKPS(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x00, 0x50, dest, arg); +} +void XEmitter::MOVMSKPD(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x50, dest, arg); +} -void XEmitter::LDDQU(X64Reg dest, const OpArg& arg) {WriteSSEOp(0xF2, sseLDDQU, dest, arg);} // For integer data only +void XEmitter::LDDQU(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0xF2, sseLDDQU, dest, arg); +} // For integer data only -void XEmitter::UNPCKLPS(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x00, 0x14, dest, arg);} -void XEmitter::UNPCKHPS(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x00, 0x15, dest, arg);} -void XEmitter::UNPCKLPD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x14, dest, arg);} -void XEmitter::UNPCKHPD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x15, dest, arg);} +void XEmitter::UNPCKLPS(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x00, 0x14, dest, arg); +} +void XEmitter::UNPCKHPS(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x00, 0x15, dest, arg); +} +void XEmitter::UNPCKLPD(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x14, dest, arg); +} +void XEmitter::UNPCKHPD(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x15, dest, arg); +} // Pretty much every x86 CPU nowadays supports SSE3, // but the SSE2 fallbacks are easy. void XEmitter::MOVSLDUP(X64Reg regOp, const OpArg& arg) { - if (cpu_info.bSSE3) - { - WriteSSEOp(0xF3, 0x12, regOp, arg); - } - else - { - if (!arg.IsSimpleReg(regOp)) - MOVAPD(regOp, arg); - UNPCKLPS(regOp, R(regOp)); - } + if (cpu_info.bSSE3) + { + WriteSSEOp(0xF3, 0x12, regOp, arg); + } + else + { + if (!arg.IsSimpleReg(regOp)) + MOVAPD(regOp, arg); + UNPCKLPS(regOp, R(regOp)); + } } void XEmitter::MOVSHDUP(X64Reg regOp, const OpArg& arg) { - if (cpu_info.bSSE3) - { - WriteSSEOp(0xF3, 0x16, regOp, arg); - } - else - { - if (!arg.IsSimpleReg(regOp)) - MOVAPD(regOp, arg); - UNPCKHPS(regOp, R(regOp)); - } + if (cpu_info.bSSE3) + { + WriteSSEOp(0xF3, 0x16, regOp, arg); + } + else + { + if (!arg.IsSimpleReg(regOp)) + MOVAPD(regOp, arg); + UNPCKHPS(regOp, R(regOp)); + } } void XEmitter::MOVDDUP(X64Reg regOp, const OpArg& arg) { - if (cpu_info.bSSE3) - { - WriteSSEOp(0xF2, 0x12, regOp, arg); - } - else - { - if (!arg.IsSimpleReg(regOp)) - MOVSD(regOp, arg); - UNPCKLPD(regOp, R(regOp)); - } + if (cpu_info.bSSE3) + { + WriteSSEOp(0xF2, 0x12, regOp, arg); + } + else + { + if (!arg.IsSimpleReg(regOp)) + MOVSD(regOp, arg); + UNPCKLPD(regOp, R(regOp)); + } } -//There are a few more left +// There are a few more left // Also some integer instructions are missing -void XEmitter::PACKSSDW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x6B, dest, arg);} -void XEmitter::PACKSSWB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x63, dest, arg);} -void XEmitter::PACKUSWB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x67, dest, arg);} +void XEmitter::PACKSSDW(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x6B, dest, arg); +} +void XEmitter::PACKSSWB(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x63, dest, arg); +} +void XEmitter::PACKUSWB(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x67, dest, arg); +} -void XEmitter::PUNPCKLBW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x60, dest, arg);} -void XEmitter::PUNPCKLWD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x61, dest, arg);} -void XEmitter::PUNPCKLDQ(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x62, dest, arg);} -void XEmitter::PUNPCKLQDQ(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x6C, dest, arg);} +void XEmitter::PUNPCKLBW(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x60, dest, arg); +} +void XEmitter::PUNPCKLWD(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x61, dest, arg); +} +void XEmitter::PUNPCKLDQ(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x62, dest, arg); +} +void XEmitter::PUNPCKLQDQ(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x6C, dest, arg); +} void XEmitter::PSRLW(X64Reg reg, int shift) { - WriteSSEOp(0x66, 0x71, (X64Reg)2, R(reg)); - Write8(shift); + WriteSSEOp(0x66, 0x71, (X64Reg)2, R(reg)); + Write8(shift); } void XEmitter::PSRLD(X64Reg reg, int shift) { - WriteSSEOp(0x66, 0x72, (X64Reg)2, R(reg)); - Write8(shift); + WriteSSEOp(0x66, 0x72, (X64Reg)2, R(reg)); + Write8(shift); } void XEmitter::PSRLQ(X64Reg reg, int shift) { - WriteSSEOp(0x66, 0x73, (X64Reg)2, R(reg)); - Write8(shift); + WriteSSEOp(0x66, 0x73, (X64Reg)2, R(reg)); + Write8(shift); } void XEmitter::PSRLQ(X64Reg reg, const OpArg& arg) { - WriteSSEOp(0x66, 0xd3, reg, arg); + WriteSSEOp(0x66, 0xd3, reg, arg); } void XEmitter::PSRLDQ(X64Reg reg, int shift) { - WriteSSEOp(0x66, 0x73, (X64Reg)3, R(reg)); - Write8(shift); + WriteSSEOp(0x66, 0x73, (X64Reg)3, R(reg)); + Write8(shift); } void XEmitter::PSLLW(X64Reg reg, int shift) { - WriteSSEOp(0x66, 0x71, (X64Reg)6, R(reg)); - Write8(shift); + WriteSSEOp(0x66, 0x71, (X64Reg)6, R(reg)); + Write8(shift); } void XEmitter::PSLLD(X64Reg reg, int shift) { - WriteSSEOp(0x66, 0x72, (X64Reg)6, R(reg)); - Write8(shift); + WriteSSEOp(0x66, 0x72, (X64Reg)6, R(reg)); + Write8(shift); } void XEmitter::PSLLQ(X64Reg reg, int shift) { - WriteSSEOp(0x66, 0x73, (X64Reg)6, R(reg)); - Write8(shift); + WriteSSEOp(0x66, 0x73, (X64Reg)6, R(reg)); + Write8(shift); } void XEmitter::PSLLDQ(X64Reg reg, int shift) { - WriteSSEOp(0x66, 0x73, (X64Reg)7, R(reg)); - Write8(shift); + WriteSSEOp(0x66, 0x73, (X64Reg)7, R(reg)); + Write8(shift); } - // WARNING not REX compatible void XEmitter::PSRAW(X64Reg reg, int shift) { - if (reg > 7) - PanicAlert("The PSRAW-emitter does not support regs above 7"); - Write8(0x66); - Write8(0x0f); - Write8(0x71); - Write8(0xE0 | reg); - Write8(shift); + if (reg > 7) + PanicAlert("The PSRAW-emitter does not support regs above 7"); + Write8(0x66); + Write8(0x0f); + Write8(0x71); + Write8(0xE0 | reg); + Write8(shift); } // WARNING not REX compatible void XEmitter::PSRAD(X64Reg reg, int shift) { - if (reg > 7) - PanicAlert("The PSRAD-emitter does not support regs above 7"); - Write8(0x66); - Write8(0x0f); - Write8(0x72); - Write8(0xE0 | reg); - Write8(shift); + if (reg > 7) + PanicAlert("The PSRAD-emitter does not support regs above 7"); + Write8(0x66); + Write8(0x0f); + Write8(0x72); + Write8(0xE0 | reg); + Write8(shift); } void XEmitter::WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) { - if (!cpu_info.bSSSE3) - PanicAlert("Trying to use SSSE3 on a system that doesn't support it. Bad programmer."); - WriteSSEOp(opPrefix, op, regOp, arg, extrabytes); + if (!cpu_info.bSSSE3) + PanicAlert("Trying to use SSSE3 on a system that doesn't support it. Bad programmer."); + WriteSSEOp(opPrefix, op, regOp, arg, extrabytes); } void XEmitter::WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes) { - if (!cpu_info.bSSE4_1) - PanicAlert("Trying to use SSE4.1 on a system that doesn't support it. Bad programmer."); - WriteSSEOp(opPrefix, op, regOp, arg, extrabytes); + if (!cpu_info.bSSE4_1) + PanicAlert("Trying to use SSE4.1 on a system that doesn't support it. Bad programmer."); + WriteSSEOp(opPrefix, op, regOp, arg, extrabytes); } -void XEmitter::PSHUFB(X64Reg dest, const OpArg& arg) {WriteSSSE3Op(0x66, 0x3800, dest, arg);} -void XEmitter::PTEST(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3817, dest, arg);} -void XEmitter::PACKUSDW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x382b, dest, arg);} +void XEmitter::PSHUFB(X64Reg dest, const OpArg& arg) +{ + WriteSSSE3Op(0x66, 0x3800, dest, arg); +} +void XEmitter::PTEST(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3817, dest, arg); +} +void XEmitter::PACKUSDW(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x382b, dest, arg); +} -void XEmitter::PMOVSXBW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3820, dest, arg);} -void XEmitter::PMOVSXBD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3821, dest, arg);} -void XEmitter::PMOVSXBQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3822, dest, arg);} -void XEmitter::PMOVSXWD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3823, dest, arg);} -void XEmitter::PMOVSXWQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3824, dest, arg);} -void XEmitter::PMOVSXDQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3825, dest, arg);} -void XEmitter::PMOVZXBW(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3830, dest, arg);} -void XEmitter::PMOVZXBD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3831, dest, arg);} -void XEmitter::PMOVZXBQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3832, dest, arg);} -void XEmitter::PMOVZXWD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3833, dest, arg);} -void XEmitter::PMOVZXWQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3834, dest, arg);} -void XEmitter::PMOVZXDQ(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3835, dest, arg);} +void XEmitter::PMOVSXBW(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3820, dest, arg); +} +void XEmitter::PMOVSXBD(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3821, dest, arg); +} +void XEmitter::PMOVSXBQ(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3822, dest, arg); +} +void XEmitter::PMOVSXWD(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3823, dest, arg); +} +void XEmitter::PMOVSXWQ(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3824, dest, arg); +} +void XEmitter::PMOVSXDQ(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3825, dest, arg); +} +void XEmitter::PMOVZXBW(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3830, dest, arg); +} +void XEmitter::PMOVZXBD(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3831, dest, arg); +} +void XEmitter::PMOVZXBQ(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3832, dest, arg); +} +void XEmitter::PMOVZXWD(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3833, dest, arg); +} +void XEmitter::PMOVZXWQ(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3834, dest, arg); +} +void XEmitter::PMOVZXDQ(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3835, dest, arg); +} -void XEmitter::PBLENDVB(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3810, dest, arg);} -void XEmitter::BLENDVPS(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3814, dest, arg);} -void XEmitter::BLENDVPD(X64Reg dest, const OpArg& arg) {WriteSSE41Op(0x66, 0x3815, dest, arg);} -void XEmitter::BLENDPS(X64Reg dest, const OpArg& arg, u8 blend) {WriteSSE41Op(0x66, 0x3A0C, dest, arg, 1); Write8(blend);} -void XEmitter::BLENDPD(X64Reg dest, const OpArg& arg, u8 blend) {WriteSSE41Op(0x66, 0x3A0D, dest, arg, 1); Write8(blend);} +void XEmitter::PBLENDVB(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3810, dest, arg); +} +void XEmitter::BLENDVPS(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3814, dest, arg); +} +void XEmitter::BLENDVPD(X64Reg dest, const OpArg& arg) +{ + WriteSSE41Op(0x66, 0x3815, dest, arg); +} +void XEmitter::BLENDPS(X64Reg dest, const OpArg& arg, u8 blend) +{ + WriteSSE41Op(0x66, 0x3A0C, dest, arg, 1); + Write8(blend); +} +void XEmitter::BLENDPD(X64Reg dest, const OpArg& arg, u8 blend) +{ + WriteSSE41Op(0x66, 0x3A0D, dest, arg, 1); + Write8(blend); +} -void XEmitter::PAND(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDB, dest, arg);} -void XEmitter::PANDN(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDF, dest, arg);} -void XEmitter::PXOR(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEF, dest, arg);} -void XEmitter::POR(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEB, dest, arg);} +void XEmitter::PAND(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xDB, dest, arg); +} +void XEmitter::PANDN(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xDF, dest, arg); +} +void XEmitter::PXOR(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xEF, dest, arg); +} +void XEmitter::POR(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xEB, dest, arg); +} -void XEmitter::PADDB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFC, dest, arg);} -void XEmitter::PADDW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFD, dest, arg);} -void XEmitter::PADDD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFE, dest, arg);} -void XEmitter::PADDQ(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD4, dest, arg);} +void XEmitter::PADDB(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xFC, dest, arg); +} +void XEmitter::PADDW(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xFD, dest, arg); +} +void XEmitter::PADDD(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xFE, dest, arg); +} +void XEmitter::PADDQ(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xD4, dest, arg); +} -void XEmitter::PADDSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEC, dest, arg);} -void XEmitter::PADDSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xED, dest, arg);} -void XEmitter::PADDUSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDC, dest, arg);} -void XEmitter::PADDUSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDD, dest, arg);} +void XEmitter::PADDSB(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xEC, dest, arg); +} +void XEmitter::PADDSW(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xED, dest, arg); +} +void XEmitter::PADDUSB(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xDC, dest, arg); +} +void XEmitter::PADDUSW(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xDD, dest, arg); +} -void XEmitter::PSUBB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF8, dest, arg);} -void XEmitter::PSUBW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF9, dest, arg);} -void XEmitter::PSUBD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFA, dest, arg);} -void XEmitter::PSUBQ(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xFB, dest, arg);} +void XEmitter::PSUBB(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xF8, dest, arg); +} +void XEmitter::PSUBW(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xF9, dest, arg); +} +void XEmitter::PSUBD(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xFA, dest, arg); +} +void XEmitter::PSUBQ(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xFB, dest, arg); +} -void XEmitter::PSUBSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE8, dest, arg);} -void XEmitter::PSUBSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE9, dest, arg);} -void XEmitter::PSUBUSB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD8, dest, arg);} -void XEmitter::PSUBUSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD9, dest, arg);} +void XEmitter::PSUBSB(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xE8, dest, arg); +} +void XEmitter::PSUBSW(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xE9, dest, arg); +} +void XEmitter::PSUBUSB(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xD8, dest, arg); +} +void XEmitter::PSUBUSW(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xD9, dest, arg); +} -void XEmitter::PAVGB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE0, dest, arg);} -void XEmitter::PAVGW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xE3, dest, arg);} +void XEmitter::PAVGB(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xE0, dest, arg); +} +void XEmitter::PAVGW(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xE3, dest, arg); +} -void XEmitter::PCMPEQB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x74, dest, arg);} -void XEmitter::PCMPEQW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x75, dest, arg);} -void XEmitter::PCMPEQD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x76, dest, arg);} +void XEmitter::PCMPEQB(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x74, dest, arg); +} +void XEmitter::PCMPEQW(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x75, dest, arg); +} +void XEmitter::PCMPEQD(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x76, dest, arg); +} -void XEmitter::PCMPGTB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x64, dest, arg);} -void XEmitter::PCMPGTW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x65, dest, arg);} -void XEmitter::PCMPGTD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0x66, dest, arg);} +void XEmitter::PCMPGTB(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x64, dest, arg); +} +void XEmitter::PCMPGTW(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x65, dest, arg); +} +void XEmitter::PCMPGTD(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0x66, dest, arg); +} -void XEmitter::PEXTRW(X64Reg dest, const OpArg& arg, u8 subreg) {WriteSSEOp(0x66, 0xC5, dest, arg); Write8(subreg);} -void XEmitter::PINSRW(X64Reg dest, const OpArg& arg, u8 subreg) {WriteSSEOp(0x66, 0xC4, dest, arg); Write8(subreg);} -void XEmitter::PINSRD(X64Reg dest, const OpArg& arg, u8 subreg) {WriteSSE41Op(0x66, 0x3A22, dest, arg); Write8(subreg);} +void XEmitter::PEXTRW(X64Reg dest, const OpArg& arg, u8 subreg) +{ + WriteSSEOp(0x66, 0xC5, dest, arg); + Write8(subreg); +} +void XEmitter::PINSRW(X64Reg dest, const OpArg& arg, u8 subreg) +{ + WriteSSEOp(0x66, 0xC4, dest, arg); + Write8(subreg); +} +void XEmitter::PINSRD(X64Reg dest, const OpArg& arg, u8 subreg) +{ + WriteSSE41Op(0x66, 0x3A22, dest, arg); + Write8(subreg); +} -void XEmitter::PMADDWD(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF5, dest, arg); } -void XEmitter::PSADBW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xF6, dest, arg);} +void XEmitter::PMADDWD(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xF5, dest, arg); +} +void XEmitter::PSADBW(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xF6, dest, arg); +} -void XEmitter::PMAXSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEE, dest, arg); } -void XEmitter::PMAXUB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDE, dest, arg); } -void XEmitter::PMINSW(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xEA, dest, arg); } -void XEmitter::PMINUB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xDA, dest, arg); } +void XEmitter::PMAXSW(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xEE, dest, arg); +} +void XEmitter::PMAXUB(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xDE, dest, arg); +} +void XEmitter::PMINSW(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xEA, dest, arg); +} +void XEmitter::PMINUB(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xDA, dest, arg); +} -void XEmitter::PMOVMSKB(X64Reg dest, const OpArg& arg) {WriteSSEOp(0x66, 0xD7, dest, arg); } -void XEmitter::PSHUFD(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0x66, 0x70, regOp, arg, 1); Write8(shuffle);} -void XEmitter::PSHUFLW(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0xF2, 0x70, regOp, arg, 1); Write8(shuffle);} -void XEmitter::PSHUFHW(X64Reg regOp, const OpArg& arg, u8 shuffle) {WriteSSEOp(0xF3, 0x70, regOp, arg, 1); Write8(shuffle);} +void XEmitter::PMOVMSKB(X64Reg dest, const OpArg& arg) +{ + WriteSSEOp(0x66, 0xD7, dest, arg); +} +void XEmitter::PSHUFD(X64Reg regOp, const OpArg& arg, u8 shuffle) +{ + WriteSSEOp(0x66, 0x70, regOp, arg, 1); + Write8(shuffle); +} +void XEmitter::PSHUFLW(X64Reg regOp, const OpArg& arg, u8 shuffle) +{ + WriteSSEOp(0xF2, 0x70, regOp, arg, 1); + Write8(shuffle); +} +void XEmitter::PSHUFHW(X64Reg regOp, const OpArg& arg, u8 shuffle) +{ + WriteSSEOp(0xF3, 0x70, regOp, arg, 1); + Write8(shuffle); +} // VEX -void XEmitter::VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseADD, regOp1, regOp2, arg);} -void XEmitter::VSUBSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseSUB, regOp1, regOp2, arg);} -void XEmitter::VMULSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseMUL, regOp1, regOp2, arg);} -void XEmitter::VDIVSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseDIV, regOp1, regOp2, arg);} -void XEmitter::VADDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseADD, regOp1, regOp2, arg);} -void XEmitter::VSUBPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseSUB, regOp1, regOp2, arg);} -void XEmitter::VMULPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseMUL, regOp1, regOp2, arg);} -void XEmitter::VDIVPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseDIV, regOp1, regOp2, arg);} -void XEmitter::VSQRTSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0xF2, sseSQRT, regOp1, regOp2, arg);} -void XEmitter::VCMPPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, u8 compare) {WriteAVXOp(0x66, sseCMP, regOp1, regOp2, arg, 0, 1); Write8(compare);} -void XEmitter::VSHUFPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, u8 shuffle) {WriteAVXOp(0x66, sseSHUF, regOp1, regOp2, arg, 0, 1); Write8(shuffle);} -void XEmitter::VUNPCKLPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg){WriteAVXOp(0x66, 0x14, regOp1, regOp2, arg);} -void XEmitter::VUNPCKHPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg){WriteAVXOp(0x66, 0x15, regOp1, regOp2, arg);} -void XEmitter::VBLENDVPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, X64Reg regOp3) {WriteAVXOp4(0x66, 0x3A4B, regOp1, regOp2, arg, regOp3);} +void XEmitter::VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0xF2, sseADD, regOp1, regOp2, arg); +} +void XEmitter::VSUBSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0xF2, sseSUB, regOp1, regOp2, arg); +} +void XEmitter::VMULSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0xF2, sseMUL, regOp1, regOp2, arg); +} +void XEmitter::VDIVSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0xF2, sseDIV, regOp1, regOp2, arg); +} +void XEmitter::VADDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x66, sseADD, regOp1, regOp2, arg); +} +void XEmitter::VSUBPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x66, sseSUB, regOp1, regOp2, arg); +} +void XEmitter::VMULPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x66, sseMUL, regOp1, regOp2, arg); +} +void XEmitter::VDIVPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x66, sseDIV, regOp1, regOp2, arg); +} +void XEmitter::VSQRTSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0xF2, sseSQRT, regOp1, regOp2, arg); +} +void XEmitter::VCMPPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, u8 compare) +{ + WriteAVXOp(0x66, sseCMP, regOp1, regOp2, arg, 0, 1); + Write8(compare); +} +void XEmitter::VSHUFPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, u8 shuffle) +{ + WriteAVXOp(0x66, sseSHUF, regOp1, regOp2, arg, 0, 1); + Write8(shuffle); +} +void XEmitter::VUNPCKLPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x66, 0x14, regOp1, regOp2, arg); +} +void XEmitter::VUNPCKHPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x66, 0x15, regOp1, regOp2, arg); +} +void XEmitter::VBLENDVPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, X64Reg regOp3) +{ + WriteAVXOp4(0x66, 0x3A4B, regOp1, regOp2, arg, regOp3); +} -void XEmitter::VANDPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x00, sseAND, regOp1, regOp2, arg);} -void XEmitter::VANDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseAND, regOp1, regOp2, arg);} -void XEmitter::VANDNPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x00, sseANDN, regOp1, regOp2, arg);} -void XEmitter::VANDNPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseANDN, regOp1, regOp2, arg);} -void XEmitter::VORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x00, sseOR, regOp1, regOp2, arg);} -void XEmitter::VORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseOR, regOp1, regOp2, arg);} -void XEmitter::VXORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x00, sseXOR, regOp1, regOp2, arg);} -void XEmitter::VXORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, sseXOR, regOp1, regOp2, arg);} +void XEmitter::VANDPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x00, sseAND, regOp1, regOp2, arg); +} +void XEmitter::VANDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x66, sseAND, regOp1, regOp2, arg); +} +void XEmitter::VANDNPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x00, sseANDN, regOp1, regOp2, arg); +} +void XEmitter::VANDNPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x66, sseANDN, regOp1, regOp2, arg); +} +void XEmitter::VORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x00, sseOR, regOp1, regOp2, arg); +} +void XEmitter::VORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x66, sseOR, regOp1, regOp2, arg); +} +void XEmitter::VXORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x00, sseXOR, regOp1, regOp2, arg); +} +void XEmitter::VXORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x66, sseXOR, regOp1, regOp2, arg); +} -void XEmitter::VPAND(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, 0xDB, regOp1, regOp2, arg);} -void XEmitter::VPANDN(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, 0xDF, regOp1, regOp2, arg);} -void XEmitter::VPOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, 0xEB, regOp1, regOp2, arg);} -void XEmitter::VPXOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteAVXOp(0x66, 0xEF, regOp1, regOp2, arg);} +void XEmitter::VPAND(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x66, 0xDB, regOp1, regOp2, arg); +} +void XEmitter::VPANDN(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x66, 0xDF, regOp1, regOp2, arg); +} +void XEmitter::VPOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x66, 0xEB, regOp1, regOp2, arg); +} +void XEmitter::VPXOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteAVXOp(0x66, 0xEF, regOp1, regOp2, arg); +} -void XEmitter::VFMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x98, regOp1, regOp2, arg);} -void XEmitter::VFMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xA8, regOp1, regOp2, arg);} -void XEmitter::VFMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xB8, regOp1, regOp2, arg);} -void XEmitter::VFMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x98, regOp1, regOp2, arg, 1);} -void XEmitter::VFMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xA8, regOp1, regOp2, arg, 1);} -void XEmitter::VFMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xB8, regOp1, regOp2, arg, 1);} -void XEmitter::VFMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x99, regOp1, regOp2, arg);} -void XEmitter::VFMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xA9, regOp1, regOp2, arg);} -void XEmitter::VFMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xB9, regOp1, regOp2, arg);} -void XEmitter::VFMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x99, regOp1, regOp2, arg, 1);} -void XEmitter::VFMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xA9, regOp1, regOp2, arg, 1);} -void XEmitter::VFMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xB9, regOp1, regOp2, arg, 1);} -void XEmitter::VFMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x9A, regOp1, regOp2, arg);} -void XEmitter::VFMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xAA, regOp1, regOp2, arg);} -void XEmitter::VFMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xBA, regOp1, regOp2, arg);} -void XEmitter::VFMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x9A, regOp1, regOp2, arg, 1);} -void XEmitter::VFMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xAA, regOp1, regOp2, arg, 1);} -void XEmitter::VFMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xBA, regOp1, regOp2, arg, 1);} -void XEmitter::VFMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x9B, regOp1, regOp2, arg);} -void XEmitter::VFMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xAB, regOp1, regOp2, arg);} -void XEmitter::VFMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xBB, regOp1, regOp2, arg);} -void XEmitter::VFMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x9B, regOp1, regOp2, arg, 1);} -void XEmitter::VFMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xAB, regOp1, regOp2, arg, 1);} -void XEmitter::VFMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xBB, regOp1, regOp2, arg, 1);} -void XEmitter::VFNMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x9C, regOp1, regOp2, arg);} -void XEmitter::VFNMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xAC, regOp1, regOp2, arg);} -void XEmitter::VFNMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xBC, regOp1, regOp2, arg);} -void XEmitter::VFNMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x9C, regOp1, regOp2, arg, 1);} -void XEmitter::VFNMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xAC, regOp1, regOp2, arg, 1);} -void XEmitter::VFNMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xBC, regOp1, regOp2, arg, 1);} -void XEmitter::VFNMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x9D, regOp1, regOp2, arg);} -void XEmitter::VFNMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xAD, regOp1, regOp2, arg);} -void XEmitter::VFNMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xBD, regOp1, regOp2, arg);} -void XEmitter::VFNMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x9D, regOp1, regOp2, arg, 1);} -void XEmitter::VFNMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xAD, regOp1, regOp2, arg, 1);} -void XEmitter::VFNMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xBD, regOp1, regOp2, arg, 1);} -void XEmitter::VFNMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x9E, regOp1, regOp2, arg);} -void XEmitter::VFNMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xAE, regOp1, regOp2, arg);} -void XEmitter::VFNMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xBE, regOp1, regOp2, arg);} -void XEmitter::VFNMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x9E, regOp1, regOp2, arg, 1);} -void XEmitter::VFNMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xAE, regOp1, regOp2, arg, 1);} -void XEmitter::VFNMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xBE, regOp1, regOp2, arg, 1);} -void XEmitter::VFNMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x9F, regOp1, regOp2, arg);} -void XEmitter::VFNMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xAF, regOp1, regOp2, arg);} -void XEmitter::VFNMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xBF, regOp1, regOp2, arg);} -void XEmitter::VFNMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x9F, regOp1, regOp2, arg, 1);} -void XEmitter::VFNMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xAF, regOp1, regOp2, arg, 1);} -void XEmitter::VFNMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xBF, regOp1, regOp2, arg, 1);} -void XEmitter::VFMADDSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x96, regOp1, regOp2, arg);} -void XEmitter::VFMADDSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xA6, regOp1, regOp2, arg);} -void XEmitter::VFMADDSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xB6, regOp1, regOp2, arg);} -void XEmitter::VFMADDSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x96, regOp1, regOp2, arg, 1);} -void XEmitter::VFMADDSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xA6, regOp1, regOp2, arg, 1);} -void XEmitter::VFMADDSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xB6, regOp1, regOp2, arg, 1);} -void XEmitter::VFMSUBADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x97, regOp1, regOp2, arg);} -void XEmitter::VFMSUBADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xA7, regOp1, regOp2, arg);} -void XEmitter::VFMSUBADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xB7, regOp1, regOp2, arg);} -void XEmitter::VFMSUBADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0x97, regOp1, regOp2, arg, 1);} -void XEmitter::VFMSUBADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xA7, regOp1, regOp2, arg, 1);} -void XEmitter::VFMSUBADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA3Op(0xB7, regOp1, regOp2, arg, 1);} +void XEmitter::VFMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x98, regOp1, regOp2, arg); +} +void XEmitter::VFMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xA8, regOp1, regOp2, arg); +} +void XEmitter::VFMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xB8, regOp1, regOp2, arg); +} +void XEmitter::VFMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x98, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xA8, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xB8, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x99, regOp1, regOp2, arg); +} +void XEmitter::VFMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xA9, regOp1, regOp2, arg); +} +void XEmitter::VFMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xB9, regOp1, regOp2, arg); +} +void XEmitter::VFMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x99, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xA9, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xB9, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x9A, regOp1, regOp2, arg); +} +void XEmitter::VFMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xAA, regOp1, regOp2, arg); +} +void XEmitter::VFMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xBA, regOp1, regOp2, arg); +} +void XEmitter::VFMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x9A, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xAA, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xBA, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x9B, regOp1, regOp2, arg); +} +void XEmitter::VFMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xAB, regOp1, regOp2, arg); +} +void XEmitter::VFMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xBB, regOp1, regOp2, arg); +} +void XEmitter::VFMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x9B, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xAB, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xBB, regOp1, regOp2, arg, 1); +} +void XEmitter::VFNMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x9C, regOp1, regOp2, arg); +} +void XEmitter::VFNMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xAC, regOp1, regOp2, arg); +} +void XEmitter::VFNMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xBC, regOp1, regOp2, arg); +} +void XEmitter::VFNMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x9C, regOp1, regOp2, arg, 1); +} +void XEmitter::VFNMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xAC, regOp1, regOp2, arg, 1); +} +void XEmitter::VFNMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xBC, regOp1, regOp2, arg, 1); +} +void XEmitter::VFNMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x9D, regOp1, regOp2, arg); +} +void XEmitter::VFNMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xAD, regOp1, regOp2, arg); +} +void XEmitter::VFNMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xBD, regOp1, regOp2, arg); +} +void XEmitter::VFNMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x9D, regOp1, regOp2, arg, 1); +} +void XEmitter::VFNMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xAD, regOp1, regOp2, arg, 1); +} +void XEmitter::VFNMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xBD, regOp1, regOp2, arg, 1); +} +void XEmitter::VFNMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x9E, regOp1, regOp2, arg); +} +void XEmitter::VFNMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xAE, regOp1, regOp2, arg); +} +void XEmitter::VFNMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xBE, regOp1, regOp2, arg); +} +void XEmitter::VFNMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x9E, regOp1, regOp2, arg, 1); +} +void XEmitter::VFNMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xAE, regOp1, regOp2, arg, 1); +} +void XEmitter::VFNMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xBE, regOp1, regOp2, arg, 1); +} +void XEmitter::VFNMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x9F, regOp1, regOp2, arg); +} +void XEmitter::VFNMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xAF, regOp1, regOp2, arg); +} +void XEmitter::VFNMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xBF, regOp1, regOp2, arg); +} +void XEmitter::VFNMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x9F, regOp1, regOp2, arg, 1); +} +void XEmitter::VFNMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xAF, regOp1, regOp2, arg, 1); +} +void XEmitter::VFNMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xBF, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMADDSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x96, regOp1, regOp2, arg); +} +void XEmitter::VFMADDSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xA6, regOp1, regOp2, arg); +} +void XEmitter::VFMADDSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xB6, regOp1, regOp2, arg); +} +void XEmitter::VFMADDSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x96, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMADDSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xA6, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMADDSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xB6, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMSUBADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x97, regOp1, regOp2, arg); +} +void XEmitter::VFMSUBADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xA7, regOp1, regOp2, arg); +} +void XEmitter::VFMSUBADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xB7, regOp1, regOp2, arg); +} +void XEmitter::VFMSUBADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0x97, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMSUBADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xA7, regOp1, regOp2, arg, 1); +} +void XEmitter::VFMSUBADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteFMA3Op(0xB7, regOp1, regOp2, arg, 1); +} -#define FMA4(name, op) \ -void XEmitter::name(X64Reg dest, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteFMA4Op(op, dest, regOp1, regOp2, arg, 1);} \ -void XEmitter::name(X64Reg dest, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {WriteFMA4Op(op, dest, regOp1, regOp2, arg, 0);} +#define FMA4(name, op) \ + void XEmitter::name(X64Reg dest, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) \ + { \ + WriteFMA4Op(op, dest, regOp1, regOp2, arg, 1); \ + } \ + void XEmitter::name(X64Reg dest, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) \ + { \ + WriteFMA4Op(op, dest, regOp1, regOp2, arg, 0); \ + } FMA4(VFMADDSUBPS, 0x5C) FMA4(VFMADDSUBPD, 0x5D) @@ -2014,57 +3065,137 @@ FMA4(VFNMSUBSS, 0x7E) FMA4(VFNMSUBSD, 0x7F) #undef FMA4 -void XEmitter::SARX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {WriteBMI2Op(bits, 0xF3, 0x38F7, regOp1, regOp2, arg);} -void XEmitter::SHLX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {WriteBMI2Op(bits, 0x66, 0x38F7, regOp1, regOp2, arg);} -void XEmitter::SHRX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {WriteBMI2Op(bits, 0xF2, 0x38F7, regOp1, regOp2, arg);} -void XEmitter::RORX(int bits, X64Reg regOp, const OpArg& arg, u8 rotate) {WriteBMI2Op(bits, 0xF2, 0x3AF0, regOp, INVALID_REG, arg, 1); Write8(rotate);} -void XEmitter::PEXT(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteBMI2Op(bits, 0xF3, 0x38F5, regOp1, regOp2, arg);} -void XEmitter::PDEP(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteBMI2Op(bits, 0xF2, 0x38F5, regOp1, regOp2, arg);} -void XEmitter::MULX(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteBMI2Op(bits, 0xF2, 0x38F6, regOp2, regOp1, arg);} -void XEmitter::BZHI(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) {CheckFlags(); WriteBMI2Op(bits, 0x00, 0x38F5, regOp1, regOp2, arg);} -void XEmitter::BLSR(int bits, X64Reg regOp, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x1, regOp, arg);} -void XEmitter::BLSMSK(int bits, X64Reg regOp, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x2, regOp, arg);} -void XEmitter::BLSI(int bits, X64Reg regOp, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x3, regOp, arg);} -void XEmitter::BEXTR(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2){WriteBMI1Op(bits, 0x00, 0x38F7, regOp1, regOp2, arg);} -void XEmitter::ANDN(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) {WriteBMI1Op(bits, 0x00, 0x38F2, regOp1, regOp2, arg);} +void XEmitter::SARX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) +{ + WriteBMI2Op(bits, 0xF3, 0x38F7, regOp1, regOp2, arg); +} +void XEmitter::SHLX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) +{ + WriteBMI2Op(bits, 0x66, 0x38F7, regOp1, regOp2, arg); +} +void XEmitter::SHRX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) +{ + WriteBMI2Op(bits, 0xF2, 0x38F7, regOp1, regOp2, arg); +} +void XEmitter::RORX(int bits, X64Reg regOp, const OpArg& arg, u8 rotate) +{ + WriteBMI2Op(bits, 0xF2, 0x3AF0, regOp, INVALID_REG, arg, 1); + Write8(rotate); +} +void XEmitter::PEXT(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteBMI2Op(bits, 0xF3, 0x38F5, regOp1, regOp2, arg); +} +void XEmitter::PDEP(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteBMI2Op(bits, 0xF2, 0x38F5, regOp1, regOp2, arg); +} +void XEmitter::MULX(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteBMI2Op(bits, 0xF2, 0x38F6, regOp2, regOp1, arg); +} +void XEmitter::BZHI(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) +{ + CheckFlags(); + WriteBMI2Op(bits, 0x00, 0x38F5, regOp1, regOp2, arg); +} +void XEmitter::BLSR(int bits, X64Reg regOp, const OpArg& arg) +{ + WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x1, regOp, arg); +} +void XEmitter::BLSMSK(int bits, X64Reg regOp, const OpArg& arg) +{ + WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x2, regOp, arg); +} +void XEmitter::BLSI(int bits, X64Reg regOp, const OpArg& arg) +{ + WriteBMI1Op(bits, 0x00, 0x38F3, (X64Reg)0x3, regOp, arg); +} +void XEmitter::BEXTR(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2) +{ + WriteBMI1Op(bits, 0x00, 0x38F7, regOp1, regOp2, arg); +} +void XEmitter::ANDN(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg) +{ + WriteBMI1Op(bits, 0x00, 0x38F2, regOp1, regOp2, arg); +} // Prefixes -void XEmitter::LOCK() { Write8(0xF0); } -void XEmitter::REP() { Write8(0xF3); } -void XEmitter::REPNE() { Write8(0xF2); } -void XEmitter::FSOverride() { Write8(0x64); } -void XEmitter::GSOverride() { Write8(0x65); } +void XEmitter::LOCK() +{ + Write8(0xF0); +} +void XEmitter::REP() +{ + Write8(0xF3); +} +void XEmitter::REPNE() +{ + Write8(0xF2); +} +void XEmitter::FSOverride() +{ + Write8(0x64); +} +void XEmitter::GSOverride() +{ + Write8(0x65); +} void XEmitter::FWAIT() { - Write8(0x9B); + Write8(0x9B); } // TODO: make this more generic void XEmitter::WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg) { - int mf = 0; - _assert_msg_(DYNA_REC, !(bits == 80 && op_80b == floatINVALID), "WriteFloatLoadStore: 80 bits not supported for this instruction"); - switch (bits) - { - case 32: mf = 0; break; - case 64: mf = 4; break; - case 80: mf = 2; break; - default: _assert_msg_(DYNA_REC, 0, "WriteFloatLoadStore: invalid bits (should be 32/64/80)"); - } - Write8(0xd9 | mf); - // x87 instructions use the reg field of the ModR/M byte as opcode: - if (bits == 80) - op = op_80b; - arg.WriteRest(this, 0, (X64Reg) op); + int mf = 0; + _assert_msg_(DYNA_REC, !(bits == 80 && op_80b == floatINVALID), + "WriteFloatLoadStore: 80 bits not supported for this instruction"); + switch (bits) + { + case 32: + mf = 0; + break; + case 64: + mf = 4; + break; + case 80: + mf = 2; + break; + default: + _assert_msg_(DYNA_REC, 0, "WriteFloatLoadStore: invalid bits (should be 32/64/80)"); + } + Write8(0xd9 | mf); + // x87 instructions use the reg field of the ModR/M byte as opcode: + if (bits == 80) + op = op_80b; + arg.WriteRest(this, 0, (X64Reg)op); } -void XEmitter::FLD(int bits, const OpArg& src) { WriteFloatLoadStore(bits, floatLD, floatLD80, src); } -void XEmitter::FST(int bits, const OpArg& dest) { WriteFloatLoadStore(bits, floatST, floatINVALID, dest); } -void XEmitter::FSTP(int bits, const OpArg& dest) { WriteFloatLoadStore(bits, floatSTP, floatSTP80, dest); } -void XEmitter::FNSTSW_AX() { Write8(0xDF); Write8(0xE0); } - -void XEmitter::RDTSC() { Write8(0x0F); Write8(0x31); } - +void XEmitter::FLD(int bits, const OpArg& src) +{ + WriteFloatLoadStore(bits, floatLD, floatLD80, src); +} +void XEmitter::FST(int bits, const OpArg& dest) +{ + WriteFloatLoadStore(bits, floatST, floatINVALID, dest); +} +void XEmitter::FSTP(int bits, const OpArg& dest) +{ + WriteFloatLoadStore(bits, floatSTP, floatSTP80, dest); +} +void XEmitter::FNSTSW_AX() +{ + Write8(0xDF); + Write8(0xE0); +} + +void XEmitter::RDTSC() +{ + Write8(0x0F); + Write8(0x31); +} } diff --git a/Source/Core/Common/x64Emitter.h b/Source/Core/Common/x64Emitter.h index 928478af49..b939e79cd5 100644 --- a/Source/Core/Common/x64Emitter.h +++ b/Source/Core/Common/x64Emitter.h @@ -17,111 +17,188 @@ namespace Gen { - enum X64Reg { - EAX = 0, EBX = 3, ECX = 1, EDX = 2, - ESI = 6, EDI = 7, EBP = 5, ESP = 4, + EAX = 0, + EBX = 3, + ECX = 1, + EDX = 2, + ESI = 6, + EDI = 7, + EBP = 5, + ESP = 4, - RAX = 0, RBX = 3, RCX = 1, RDX = 2, - RSI = 6, RDI = 7, RBP = 5, RSP = 4, - R8 = 8, R9 = 9, R10 = 10,R11 = 11, - R12 = 12,R13 = 13,R14 = 14,R15 = 15, + RAX = 0, + RBX = 3, + RCX = 1, + RDX = 2, + RSI = 6, + RDI = 7, + RBP = 5, + RSP = 4, + R8 = 8, + R9 = 9, + R10 = 10, + R11 = 11, + R12 = 12, + R13 = 13, + R14 = 14, + R15 = 15, - AL = 0, BL = 3, CL = 1, DL = 2, - SIL = 6, DIL = 7, BPL = 5, SPL = 4, - AH = 0x104, BH = 0x107, CH = 0x105, DH = 0x106, + AL = 0, + BL = 3, + CL = 1, + DL = 2, + SIL = 6, + DIL = 7, + BPL = 5, + SPL = 4, + AH = 0x104, + BH = 0x107, + CH = 0x105, + DH = 0x106, - AX = 0, BX = 3, CX = 1, DX = 2, - SI = 6, DI = 7, BP = 5, SP = 4, + AX = 0, + BX = 3, + CX = 1, + DX = 2, + SI = 6, + DI = 7, + BP = 5, + SP = 4, - XMM0=0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, - XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, + XMM0 = 0, + XMM1, + XMM2, + XMM3, + XMM4, + XMM5, + XMM6, + XMM7, + XMM8, + XMM9, + XMM10, + XMM11, + XMM12, + XMM13, + XMM14, + XMM15, - YMM0=0, YMM1, YMM2, YMM3, YMM4, YMM5, YMM6, YMM7, - YMM8, YMM9, YMM10, YMM11, YMM12, YMM13, YMM14, YMM15, + YMM0 = 0, + YMM1, + YMM2, + YMM3, + YMM4, + YMM5, + YMM6, + YMM7, + YMM8, + YMM9, + YMM10, + YMM11, + YMM12, + YMM13, + YMM14, + YMM15, - INVALID_REG = 0xFFFFFFFF + INVALID_REG = 0xFFFFFFFF }; enum CCFlags { - CC_O = 0, - CC_NO = 1, - CC_B = 2, CC_C = 2, CC_NAE = 2, - CC_NB = 3, CC_NC = 3, CC_AE = 3, - CC_Z = 4, CC_E = 4, - CC_NZ = 5, CC_NE = 5, - CC_BE = 6, CC_NA = 6, - CC_NBE = 7, CC_A = 7, - CC_S = 8, - CC_NS = 9, - CC_P = 0xA, CC_PE = 0xA, - CC_NP = 0xB, CC_PO = 0xB, - CC_L = 0xC, CC_NGE = 0xC, - CC_NL = 0xD, CC_GE = 0xD, - CC_LE = 0xE, CC_NG = 0xE, - CC_NLE = 0xF, CC_G = 0xF + CC_O = 0, + CC_NO = 1, + CC_B = 2, + CC_C = 2, + CC_NAE = 2, + CC_NB = 3, + CC_NC = 3, + CC_AE = 3, + CC_Z = 4, + CC_E = 4, + CC_NZ = 5, + CC_NE = 5, + CC_BE = 6, + CC_NA = 6, + CC_NBE = 7, + CC_A = 7, + CC_S = 8, + CC_NS = 9, + CC_P = 0xA, + CC_PE = 0xA, + CC_NP = 0xB, + CC_PO = 0xB, + CC_L = 0xC, + CC_NGE = 0xC, + CC_NL = 0xD, + CC_GE = 0xD, + CC_LE = 0xE, + CC_NG = 0xE, + CC_NLE = 0xF, + CC_G = 0xF }; enum { - NUMGPRs = 16, - NUMXMMs = 16, + NUMGPRs = 16, + NUMXMMs = 16, }; enum { - SCALE_NONE = 0, - SCALE_1 = 1, - SCALE_2 = 2, - SCALE_4 = 4, - SCALE_8 = 8, - SCALE_ATREG = 16, - //SCALE_NOBASE_1 is not supported and can be replaced with SCALE_ATREG - SCALE_NOBASE_2 = 34, - SCALE_NOBASE_4 = 36, - SCALE_NOBASE_8 = 40, - SCALE_RIP = 0xFF, - SCALE_IMM8 = 0xF0, - SCALE_IMM16 = 0xF1, - SCALE_IMM32 = 0xF2, - SCALE_IMM64 = 0xF3, + SCALE_NONE = 0, + SCALE_1 = 1, + SCALE_2 = 2, + SCALE_4 = 4, + SCALE_8 = 8, + SCALE_ATREG = 16, + // SCALE_NOBASE_1 is not supported and can be replaced with SCALE_ATREG + SCALE_NOBASE_2 = 34, + SCALE_NOBASE_4 = 36, + SCALE_NOBASE_8 = 40, + SCALE_RIP = 0xFF, + SCALE_IMM8 = 0xF0, + SCALE_IMM16 = 0xF1, + SCALE_IMM32 = 0xF2, + SCALE_IMM64 = 0xF3, }; -enum NormalOp { - nrmADD, - nrmADC, - nrmSUB, - nrmSBB, - nrmAND, - nrmOR , - nrmXOR, - nrmMOV, - nrmTEST, - nrmCMP, - nrmXCHG, +enum NormalOp +{ + nrmADD, + nrmADC, + nrmSUB, + nrmSBB, + nrmAND, + nrmOR, + nrmXOR, + nrmMOV, + nrmTEST, + nrmCMP, + nrmXCHG, }; -enum SSECompare { - CMP_EQ = 0, - CMP_LT = 1, - CMP_LE = 2, - CMP_UNORD = 3, - CMP_NEQ = 4, - CMP_NLT = 5, - CMP_NLE = 6, - CMP_ORD = 7, +enum SSECompare +{ + CMP_EQ = 0, + CMP_LT = 1, + CMP_LE = 2, + CMP_UNORD = 3, + CMP_NEQ = 4, + CMP_NLT = 5, + CMP_NLE = 6, + CMP_ORD = 7, }; -enum FloatOp { - floatLD = 0, - floatST = 2, - floatSTP = 3, - floatLD80 = 5, - floatSTP80 = 7, +enum FloatOp +{ + floatLD = 0, + floatST = 2, + floatSTP = 3, + floatLD80 = 5, + floatSTP80 = 7, - floatINVALID = -1, + floatINVALID = -1, }; class XEmitter; @@ -129,835 +206,917 @@ class XEmitter; // RIP addressing does not benefit from micro op fusion on Core arch struct OpArg { - friend class XEmitter; // For accessing offset and operandReg + friend class XEmitter; // For accessing offset and operandReg - OpArg() {} // dummy op arg, used for storage - OpArg(u64 _offset, int _scale, X64Reg rmReg = RAX, X64Reg scaledReg = RAX) - { - operandReg = 0; - scale = (u8)_scale; - offsetOrBaseReg = (u16)rmReg; - indexReg = (u16)scaledReg; - //if scale == 0 never mind offsetting - offset = _offset; - } - bool operator==(const OpArg& b) const - { - return operandReg == b.operandReg && scale == b.scale && offsetOrBaseReg == b.offsetOrBaseReg && - indexReg == b.indexReg && offset == b.offset; - } - void WriteREX(XEmitter* emit, int opBits, int bits, int customOp = -1) const; - void WriteVEX(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, int W = 0) const; - void WriteRest(XEmitter* emit, int extraBytes=0, X64Reg operandReg=INVALID_REG, bool warn_64bit_offset = true) const; - void WriteSingleByteOp(XEmitter* emit, u8 op, X64Reg operandReg, int bits); + OpArg() {} // dummy op arg, used for storage + OpArg(u64 _offset, int _scale, X64Reg rmReg = RAX, X64Reg scaledReg = RAX) + { + operandReg = 0; + scale = (u8)_scale; + offsetOrBaseReg = (u16)rmReg; + indexReg = (u16)scaledReg; + // if scale == 0 never mind offsetting + offset = _offset; + } + bool operator==(const OpArg& b) const + { + return operandReg == b.operandReg && scale == b.scale && offsetOrBaseReg == b.offsetOrBaseReg && + indexReg == b.indexReg && offset == b.offset; + } + void WriteREX(XEmitter* emit, int opBits, int bits, int customOp = -1) const; + void WriteVEX(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, + int W = 0) const; + void WriteRest(XEmitter* emit, int extraBytes = 0, X64Reg operandReg = INVALID_REG, + bool warn_64bit_offset = true) const; + void WriteSingleByteOp(XEmitter* emit, u8 op, X64Reg operandReg, int bits); - u64 Imm64() const { _dbg_assert_(DYNA_REC, scale == SCALE_IMM64); return (u64)offset; } - u32 Imm32() const { _dbg_assert_(DYNA_REC, scale == SCALE_IMM32); return (u32)offset; } - u16 Imm16() const { _dbg_assert_(DYNA_REC, scale == SCALE_IMM16); return (u16)offset; } - u8 Imm8() const { _dbg_assert_(DYNA_REC, scale == SCALE_IMM8); return (u8)offset; } + u64 Imm64() const + { + _dbg_assert_(DYNA_REC, scale == SCALE_IMM64); + return (u64)offset; + } + u32 Imm32() const + { + _dbg_assert_(DYNA_REC, scale == SCALE_IMM32); + return (u32)offset; + } + u16 Imm16() const + { + _dbg_assert_(DYNA_REC, scale == SCALE_IMM16); + return (u16)offset; + } + u8 Imm8() const + { + _dbg_assert_(DYNA_REC, scale == SCALE_IMM8); + return (u8)offset; + } - s64 SImm64() const { _dbg_assert_(DYNA_REC, scale == SCALE_IMM64); return (s64)offset; } - s32 SImm32() const { _dbg_assert_(DYNA_REC, scale == SCALE_IMM32); return (s32)offset; } - s16 SImm16() const { _dbg_assert_(DYNA_REC, scale == SCALE_IMM16); return (s16)offset; } - s8 SImm8() const { _dbg_assert_(DYNA_REC, scale == SCALE_IMM8); return (s8)offset; } + s64 SImm64() const + { + _dbg_assert_(DYNA_REC, scale == SCALE_IMM64); + return (s64)offset; + } + s32 SImm32() const + { + _dbg_assert_(DYNA_REC, scale == SCALE_IMM32); + return (s32)offset; + } + s16 SImm16() const + { + _dbg_assert_(DYNA_REC, scale == SCALE_IMM16); + return (s16)offset; + } + s8 SImm8() const + { + _dbg_assert_(DYNA_REC, scale == SCALE_IMM8); + return (s8)offset; + } - void WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& operand, int bits) const; - bool IsImm() const {return scale == SCALE_IMM8 || scale == SCALE_IMM16 || scale == SCALE_IMM32 || scale == SCALE_IMM64;} - bool IsSimpleReg() const {return scale == SCALE_NONE;} - bool IsSimpleReg(X64Reg reg) const - { - return IsSimpleReg() && GetSimpleReg() == reg; - } + void WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& operand, int bits) const; + bool IsImm() const + { + return scale == SCALE_IMM8 || scale == SCALE_IMM16 || scale == SCALE_IMM32 || + scale == SCALE_IMM64; + } + bool IsSimpleReg() const { return scale == SCALE_NONE; } + bool IsSimpleReg(X64Reg reg) const { return IsSimpleReg() && GetSimpleReg() == reg; } + int GetImmBits() const + { + switch (scale) + { + case SCALE_IMM8: + return 8; + case SCALE_IMM16: + return 16; + case SCALE_IMM32: + return 32; + case SCALE_IMM64: + return 64; + default: + return -1; + } + } - int GetImmBits() const - { - switch (scale) - { - case SCALE_IMM8: return 8; - case SCALE_IMM16: return 16; - case SCALE_IMM32: return 32; - case SCALE_IMM64: return 64; - default: return -1; - } - } + X64Reg GetSimpleReg() const + { + if (scale == SCALE_NONE) + return (X64Reg)offsetOrBaseReg; + else + return INVALID_REG; + } - X64Reg GetSimpleReg() const - { - if (scale == SCALE_NONE) - return (X64Reg)offsetOrBaseReg; - else - return INVALID_REG; - } - - void AddMemOffset(int val) - { - _dbg_assert_msg_(DYNA_REC, scale == SCALE_RIP || (scale <= SCALE_ATREG && scale > SCALE_NONE), - "Tried to increment an OpArg which doesn't have an offset"); - offset += val; - } + void AddMemOffset(int val) + { + _dbg_assert_msg_(DYNA_REC, scale == SCALE_RIP || (scale <= SCALE_ATREG && scale > SCALE_NONE), + "Tried to increment an OpArg which doesn't have an offset"); + offset += val; + } private: - u8 scale; - u16 offsetOrBaseReg; - u16 indexReg; - u64 offset; // Also used to store immediates. - u16 operandReg; + u8 scale; + u16 offsetOrBaseReg; + u16 indexReg; + u64 offset; // Also used to store immediates. + u16 operandReg; }; template -inline OpArg M(const T* ptr) {return OpArg((u64)(const void*)ptr, (int)SCALE_RIP);} -inline OpArg R(X64Reg value) {return OpArg(0, SCALE_NONE, value);} -inline OpArg MatR(X64Reg value) {return OpArg(0, SCALE_ATREG, value);} +inline OpArg M(const T* ptr) +{ + return OpArg((u64)(const void*)ptr, (int)SCALE_RIP); +} +inline OpArg R(X64Reg value) +{ + return OpArg(0, SCALE_NONE, value); +} +inline OpArg MatR(X64Reg value) +{ + return OpArg(0, SCALE_ATREG, value); +} inline OpArg MDisp(X64Reg value, int offset) { - return OpArg((u32)offset, SCALE_ATREG, value); + return OpArg((u32)offset, SCALE_ATREG, value); } inline OpArg MComplex(X64Reg base, X64Reg scaled, int scale, int offset) { - return OpArg(offset, scale, base, scaled); + return OpArg(offset, scale, base, scaled); } inline OpArg MScaled(X64Reg scaled, int scale, int offset) { - if (scale == SCALE_1) - return OpArg(offset, SCALE_ATREG, scaled); - else - return OpArg(offset, scale | 0x20, RAX, scaled); + if (scale == SCALE_1) + return OpArg(offset, SCALE_ATREG, scaled); + else + return OpArg(offset, scale | 0x20, RAX, scaled); } inline OpArg MRegSum(X64Reg base, X64Reg offset) { - return MComplex(base, offset, 1, 0); + return MComplex(base, offset, 1, 0); } -inline OpArg Imm8 (u8 imm) {return OpArg(imm, SCALE_IMM8);} -inline OpArg Imm16(u16 imm) {return OpArg(imm, SCALE_IMM16);} //rarely used -inline OpArg Imm32(u32 imm) {return OpArg(imm, SCALE_IMM32);} -inline OpArg Imm64(u64 imm) {return OpArg(imm, SCALE_IMM64);} -inline OpArg ImmPtr(const void* imm) {return Imm64((u64)imm);} +inline OpArg Imm8(u8 imm) +{ + return OpArg(imm, SCALE_IMM8); +} +inline OpArg Imm16(u16 imm) +{ + return OpArg(imm, SCALE_IMM16); +} // rarely used +inline OpArg Imm32(u32 imm) +{ + return OpArg(imm, SCALE_IMM32); +} +inline OpArg Imm64(u64 imm) +{ + return OpArg(imm, SCALE_IMM64); +} +inline OpArg ImmPtr(const void* imm) +{ + return Imm64((u64)imm); +} inline u32 PtrOffset(const void* ptr, const void* base) { - s64 distance = (s64)ptr-(s64)base; - if (distance >= 0x80000000LL || - distance < -0x80000000LL) - { - _assert_msg_(DYNA_REC, 0, "pointer offset out of range"); - return 0; - } + s64 distance = (s64)ptr - (s64)base; + if (distance >= 0x80000000LL || distance < -0x80000000LL) + { + _assert_msg_(DYNA_REC, 0, "pointer offset out of range"); + return 0; + } - return (u32)distance; + return (u32)distance; } -//usage: int a[]; ARRAY_OFFSET(a,10) -#define ARRAY_OFFSET(array,index) ((u32)((u64)&(array)[index]-(u64)&(array)[0])) -//usage: struct {int e;} s; STRUCT_OFFSET(s,e) -#define STRUCT_OFFSET(str,elem) ((u32)((u64)&(str).elem-(u64)&(str))) +// usage: int a[]; ARRAY_OFFSET(a,10) +#define ARRAY_OFFSET(array, index) ((u32)((u64) & (array)[index] - (u64) & (array)[0])) +// usage: struct {int e;} s; STRUCT_OFFSET(s,e) +#define STRUCT_OFFSET(str, elem) ((u32)((u64) & (str).elem - (u64) & (str))) struct FixupBranch { - u8* ptr; - int type; //0 = 8bit 1 = 32bit + u8* ptr; + int type; // 0 = 8bit 1 = 32bit }; class XEmitter { - friend struct OpArg; // for Write8 etc + friend struct OpArg; // for Write8 etc private: - u8* code; - bool flags_locked; + u8* code; + bool flags_locked; - void CheckFlags(); + void CheckFlags(); - void Rex(int w, int r, int x, int b); - void WriteModRM(int mod, int rm, int reg); - void WriteSIB(int scale, int index, int base); - void WriteSimple1Byte(int bits, u8 byte, X64Reg reg); - void WriteSimple2Byte(int bits, u8 byte1, u8 byte2, X64Reg reg); - void WriteMulDivType(int bits, OpArg src, int ext); - void WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2, bool rep = false); - void WriteShift(int bits, OpArg dest, const OpArg& shift, int ext); - void WriteBitTest(int bits, const OpArg& dest, const OpArg& index, int ext); - void WriteMXCSR(OpArg arg, int ext); - void WriteSSEOp(u8 opPrefix, u16 op, X64Reg regOp, OpArg arg, int extrabytes = 0); - void WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0); - void WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0); - void WriteVEXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int W = 0, int extrabytes = 0); - void WriteVEXOp4(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, X64Reg regOp3, int W = 0); - void WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int W = 0, int extrabytes = 0); - void WriteAVXOp4(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, X64Reg regOp3, int W = 0); - void WriteFMA3Op(u8 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int W = 0); - void WriteFMA4Op(u8 op, X64Reg dest, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int W = 0); - void WriteBMIOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0); - void WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0); - void WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0); - void WriteMOVBE(int bits, u8 op, X64Reg regOp, const OpArg& arg); - void WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg); - void WriteNormalOp(int bits, NormalOp op, const OpArg& a1, const OpArg& a2); + void Rex(int w, int r, int x, int b); + void WriteModRM(int mod, int rm, int reg); + void WriteSIB(int scale, int index, int base); + void WriteSimple1Byte(int bits, u8 byte, X64Reg reg); + void WriteSimple2Byte(int bits, u8 byte1, u8 byte2, X64Reg reg); + void WriteMulDivType(int bits, OpArg src, int ext); + void WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2, bool rep = false); + void WriteShift(int bits, OpArg dest, const OpArg& shift, int ext); + void WriteBitTest(int bits, const OpArg& dest, const OpArg& index, int ext); + void WriteMXCSR(OpArg arg, int ext); + void WriteSSEOp(u8 opPrefix, u16 op, X64Reg regOp, OpArg arg, int extrabytes = 0); + void WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0); + void WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0); + void WriteVEXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int W = 0, + int extrabytes = 0); + void WriteVEXOp4(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, + X64Reg regOp3, int W = 0); + void WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int W = 0, + int extrabytes = 0); + void WriteAVXOp4(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, + X64Reg regOp3, int W = 0); + void WriteFMA3Op(u8 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int W = 0); + void WriteFMA4Op(u8 op, X64Reg dest, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int W = 0); + void WriteBMIOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, + int extrabytes = 0); + void WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, + int extrabytes = 0); + void WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, + int extrabytes = 0); + void WriteMOVBE(int bits, u8 op, X64Reg regOp, const OpArg& arg); + void WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg); + void WriteNormalOp(int bits, NormalOp op, const OpArg& a1, const OpArg& a2); - void ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size, size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp); + void ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size, + size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp); protected: - void Write8(u8 value); - void Write16(u16 value); - void Write32(u32 value); - void Write64(u64 value); + void Write8(u8 value); + void Write16(u16 value); + void Write32(u32 value); + void Write64(u64 value); public: - XEmitter() { code = nullptr; flags_locked = false; } - explicit XEmitter(u8* code_ptr) { code = code_ptr; flags_locked = false; } - virtual ~XEmitter() {} + XEmitter() + { + code = nullptr; + flags_locked = false; + } + explicit XEmitter(u8* code_ptr) + { + code = code_ptr; + flags_locked = false; + } + virtual ~XEmitter() {} + void SetCodePtr(u8* ptr); + void ReserveCodeSpace(int bytes); + const u8* AlignCode4(); + const u8* AlignCode16(); + const u8* AlignCodePage(); + const u8* GetCodePtr() const; + u8* GetWritableCodePtr(); - void SetCodePtr(u8* ptr); - void ReserveCodeSpace(int bytes); - const u8* AlignCode4(); - const u8* AlignCode16(); - const u8* AlignCodePage(); - const u8* GetCodePtr() const; - u8* GetWritableCodePtr(); + void LockFlags() { flags_locked = true; } + void UnlockFlags() { flags_locked = false; } + // Looking for one of these? It's BANNED!! Some instructions are slow on modern CPU + // INC, DEC, LOOP, LOOPNE, LOOPE, ENTER, LEAVE, XCHG, XLAT, REP MOVSB/MOVSD, REP SCASD + other + // string instr., + // INC and DEC are slow on Intel Core, but not on AMD. They create a + // false flag dependency because they only update a subset of the flags. + // XCHG is SLOW and should be avoided. - void LockFlags() { flags_locked = true; } - void UnlockFlags() { flags_locked = false; } + // Debug breakpoint + void INT3(); - // Looking for one of these? It's BANNED!! Some instructions are slow on modern CPU - // INC, DEC, LOOP, LOOPNE, LOOPE, ENTER, LEAVE, XCHG, XLAT, REP MOVSB/MOVSD, REP SCASD + other string instr., - // INC and DEC are slow on Intel Core, but not on AMD. They create a - // false flag dependency because they only update a subset of the flags. - // XCHG is SLOW and should be avoided. + // Do nothing + void NOP(size_t count = 1); - // Debug breakpoint - void INT3(); + // Save energy in wait-loops on P4 only. Probably not too useful. + void PAUSE(); - // Do nothing - void NOP(size_t count = 1); + // Flag control + void STC(); + void CLC(); + void CMC(); - // Save energy in wait-loops on P4 only. Probably not too useful. - void PAUSE(); + // These two can not be executed in 64-bit mode on early Intel 64-bit CPU:s, only on Core2 and + // AMD! + void LAHF(); // 3 cycle vector path + void SAHF(); // direct path fast - // Flag control - void STC(); - void CLC(); - void CMC(); + // Stack control + void PUSH(X64Reg reg); + void POP(X64Reg reg); + void PUSH(int bits, const OpArg& reg); + void POP(int bits, const OpArg& reg); + void PUSHF(); + void POPF(); - // These two can not be executed in 64-bit mode on early Intel 64-bit CPU:s, only on Core2 and AMD! - void LAHF(); // 3 cycle vector path - void SAHF(); // direct path fast + // Flow control + void RET(); + void RET_FAST(); + void UD2(); + FixupBranch J(bool force5bytes = false); - - // Stack control - void PUSH(X64Reg reg); - void POP(X64Reg reg); - void PUSH(int bits, const OpArg& reg); - void POP(int bits, const OpArg& reg); - void PUSHF(); - void POPF(); - - // Flow control - void RET(); - void RET_FAST(); - void UD2(); - FixupBranch J(bool force5bytes = false); - - void JMP(const u8* addr, bool force5Bytes = false); - void JMPptr(const OpArg& arg); - void JMPself(); //infinite loop! + void JMP(const u8* addr, bool force5Bytes = false); + void JMPptr(const OpArg& arg); + void JMPself(); // infinite loop! #ifdef CALL #undef CALL #endif - void CALL(const void* fnptr); - void CALLptr(OpArg arg); - - FixupBranch J_CC(CCFlags conditionCode, bool force5bytes = false); - void J_CC(CCFlags conditionCode, const u8* addr); - - void SetJumpTarget(const FixupBranch& branch); - - void SETcc(CCFlags flag, OpArg dest); - // Note: CMOV brings small if any benefit on current CPUs. - void CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag); - - // Fences - void LFENCE(); - void MFENCE(); - void SFENCE(); - - // Bit scan - void BSF(int bits, X64Reg dest, const OpArg& src); // Bottom bit to top bit - void BSR(int bits, X64Reg dest, const OpArg& src); // Top bit to bottom bit - - // Cache control - enum PrefetchLevel - { - PF_NTA, //Non-temporal (data used once and only once) - PF_T0, //All cache levels - PF_T1, //Levels 2+ (aliased to T0 on AMD) - PF_T2, //Levels 3+ (aliased to T0 on AMD) - }; - void PREFETCH(PrefetchLevel level, OpArg arg); - void MOVNTI(int bits, const OpArg& dest, X64Reg src); - void MOVNTDQ(const OpArg& arg, X64Reg regOp); - void MOVNTPS(const OpArg& arg, X64Reg regOp); - void MOVNTPD(const OpArg& arg, X64Reg regOp); - - // Multiplication / division - void MUL(int bits, const OpArg& src); // UNSIGNED - void IMUL(int bits, const OpArg& src); // SIGNED - void IMUL(int bits, X64Reg regOp, const OpArg& src); - void IMUL(int bits, X64Reg regOp, const OpArg& src, const OpArg& imm); - void DIV(int bits, const OpArg& src); - void IDIV(int bits, const OpArg& src); - - // Shift - void ROL(int bits, const OpArg& dest, const OpArg& shift); - void ROR(int bits, const OpArg& dest, const OpArg& shift); - void RCL(int bits, const OpArg& dest, const OpArg& shift); - void RCR(int bits, const OpArg& dest, const OpArg& shift); - void SHL(int bits, const OpArg& dest, const OpArg& shift); - void SHR(int bits, const OpArg& dest, const OpArg& shift); - void SAR(int bits, const OpArg& dest, const OpArg& shift); - - // Bit Test - void BT(int bits, const OpArg& dest, const OpArg& index); - void BTS(int bits, const OpArg& dest, const OpArg& index); - void BTR(int bits, const OpArg& dest, const OpArg& index); - void BTC(int bits, const OpArg& dest, const OpArg& index); - - // Double-Precision Shift - void SHRD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift); - void SHLD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift); - - // Extend EAX into EDX in various ways - void CWD(int bits = 16); - inline void CDQ() {CWD(32);} - inline void CQO() {CWD(64);} - void CBW(int bits = 8); - inline void CWDE() {CBW(16);} - inline void CDQE() {CBW(32);} - - // Load effective address - void LEA(int bits, X64Reg dest, OpArg src); - - // Integer arithmetic - void NEG (int bits, const OpArg& src); - void ADD (int bits, const OpArg& a1, const OpArg& a2); - void ADC (int bits, const OpArg& a1, const OpArg& a2); - void SUB (int bits, const OpArg& a1, const OpArg& a2); - void SBB (int bits, const OpArg& a1, const OpArg& a2); - void AND (int bits, const OpArg& a1, const OpArg& a2); - void CMP (int bits, const OpArg& a1, const OpArg& a2); - - // Bit operations - void NOT (int bits, const OpArg& src); - void OR (int bits, const OpArg& a1, const OpArg& a2); - void XOR (int bits, const OpArg& a1, const OpArg& a2); - void MOV (int bits, const OpArg& a1, const OpArg& a2); - void TEST(int bits, const OpArg& a1, const OpArg& a2); - - void CMP_or_TEST(int bits, const OpArg& a1, const OpArg& a2); - - // Are these useful at all? Consider removing. - void XCHG(int bits, const OpArg& a1, const OpArg& a2); - void XCHG_AHAL(); - - // Byte swapping (32 and 64-bit only). - void BSWAP(int bits, X64Reg reg); - - // Sign/zero extension - void MOVSX(int dbits, int sbits, X64Reg dest, OpArg src); //automatically uses MOVSXD if necessary - void MOVZX(int dbits, int sbits, X64Reg dest, OpArg src); - - // Available only on Atom or >= Haswell so far. Test with cpu_info.bMOVBE. - void MOVBE(int bits, X64Reg dest, const OpArg& src); - void MOVBE(int bits, const OpArg& dest, X64Reg src); - void LoadAndSwap(int size, X64Reg dst, const OpArg& src, bool sign_extend = false); - u8* SwapAndStore(int size, const OpArg& dst, X64Reg src); - - // Available only on AMD >= Phenom or Intel >= Haswell - void LZCNT(int bits, X64Reg dest, const OpArg& src); - // Note: this one is actually part of BMI1 - void TZCNT(int bits, X64Reg dest, const OpArg& src); - - // WARNING - These two take 11-13 cycles and are VectorPath! (AMD64) - void STMXCSR(const OpArg& memloc); - void LDMXCSR(const OpArg& memloc); - - // Prefixes - void LOCK(); - void REP(); - void REPNE(); - void FSOverride(); - void GSOverride(); - - // x87 - enum x87StatusWordBits { - x87_InvalidOperation = 0x1, - x87_DenormalizedOperand = 0x2, - x87_DivisionByZero = 0x4, - x87_Overflow = 0x8, - x87_Underflow = 0x10, - x87_Precision = 0x20, - x87_StackFault = 0x40, - x87_ErrorSummary = 0x80, - x87_C0 = 0x100, - x87_C1 = 0x200, - x87_C2 = 0x400, - x87_TopOfStack = 0x2000 | 0x1000 | 0x800, - x87_C3 = 0x4000, - x87_FPUBusy = 0x8000, - }; - - void FLD(int bits, const OpArg& src); - void FST(int bits, const OpArg& dest); - void FSTP(int bits, const OpArg& dest); - void FNSTSW_AX(); - void FWAIT(); - - // SSE/SSE2: Floating point arithmetic - void ADDSS(X64Reg regOp, const OpArg& arg); - void ADDSD(X64Reg regOp, const OpArg& arg); - void SUBSS(X64Reg regOp, const OpArg& arg); - void SUBSD(X64Reg regOp, const OpArg& arg); - void MULSS(X64Reg regOp, const OpArg& arg); - void MULSD(X64Reg regOp, const OpArg& arg); - void DIVSS(X64Reg regOp, const OpArg& arg); - void DIVSD(X64Reg regOp, const OpArg& arg); - void MINSS(X64Reg regOp, const OpArg& arg); - void MINSD(X64Reg regOp, const OpArg& arg); - void MAXSS(X64Reg regOp, const OpArg& arg); - void MAXSD(X64Reg regOp, const OpArg& arg); - void SQRTSS(X64Reg regOp, const OpArg& arg); - void SQRTSD(X64Reg regOp, const OpArg& arg); - void RCPSS(X64Reg regOp, const OpArg& arg); - void RSQRTSS(X64Reg regOp, const OpArg& arg); - - // SSE/SSE2: Floating point bitwise (yes) - void CMPSS(X64Reg regOp, const OpArg& arg, u8 compare); - void CMPSD(X64Reg regOp, const OpArg& arg, u8 compare); - - // SSE/SSE2: Floating point packed arithmetic (x4 for float, x2 for double) - void ADDPS(X64Reg regOp, const OpArg& arg); - void ADDPD(X64Reg regOp, const OpArg& arg); - void SUBPS(X64Reg regOp, const OpArg& arg); - void SUBPD(X64Reg regOp, const OpArg& arg); - void CMPPS(X64Reg regOp, const OpArg& arg, u8 compare); - void CMPPD(X64Reg regOp, const OpArg& arg, u8 compare); - void MULPS(X64Reg regOp, const OpArg& arg); - void MULPD(X64Reg regOp, const OpArg& arg); - void DIVPS(X64Reg regOp, const OpArg& arg); - void DIVPD(X64Reg regOp, const OpArg& arg); - void MINPS(X64Reg regOp, const OpArg& arg); - void MINPD(X64Reg regOp, const OpArg& arg); - void MAXPS(X64Reg regOp, const OpArg& arg); - void MAXPD(X64Reg regOp, const OpArg& arg); - void SQRTPS(X64Reg regOp, const OpArg& arg); - void SQRTPD(X64Reg regOp, const OpArg& arg); - void RCPPS(X64Reg regOp, const OpArg& arg); - void RSQRTPS(X64Reg regOp, const OpArg& arg); - - // SSE/SSE2: Floating point packed bitwise (x4 for float, x2 for double) - void ANDPS(X64Reg regOp, const OpArg& arg); - void ANDPD(X64Reg regOp, const OpArg& arg); - void ANDNPS(X64Reg regOp, const OpArg& arg); - void ANDNPD(X64Reg regOp, const OpArg& arg); - void ORPS(X64Reg regOp, const OpArg& arg); - void ORPD(X64Reg regOp, const OpArg& arg); - void XORPS(X64Reg regOp, const OpArg& arg); - void XORPD(X64Reg regOp, const OpArg& arg); - - // SSE/SSE2: Shuffle components. These are tricky - see Intel documentation. - void SHUFPS(X64Reg regOp, const OpArg& arg, u8 shuffle); - void SHUFPD(X64Reg regOp, const OpArg& arg, u8 shuffle); - - // SSE3 - void MOVSLDUP(X64Reg regOp, const OpArg& arg); - void MOVSHDUP(X64Reg regOp, const OpArg& arg); - void MOVDDUP(X64Reg regOp, const OpArg& arg); - - // SSE/SSE2: Useful alternative to shuffle in some cases. - void UNPCKLPS(X64Reg dest, const OpArg& src); - void UNPCKHPS(X64Reg dest, const OpArg& src); - void UNPCKLPD(X64Reg dest, const OpArg& src); - void UNPCKHPD(X64Reg dest, const OpArg& src); - - // SSE/SSE2: Compares. - void COMISS(X64Reg regOp, const OpArg& arg); - void COMISD(X64Reg regOp, const OpArg& arg); - void UCOMISS(X64Reg regOp, const OpArg& arg); - void UCOMISD(X64Reg regOp, const OpArg& arg); - - // SSE/SSE2: Moves. Use the right data type for your data, in most cases. - void MOVAPS(X64Reg regOp, const OpArg& arg); - void MOVAPD(X64Reg regOp, const OpArg& arg); - void MOVAPS(const OpArg& arg, X64Reg regOp); - void MOVAPD(const OpArg& arg, X64Reg regOp); - - void MOVUPS(X64Reg regOp, const OpArg& arg); - void MOVUPD(X64Reg regOp, const OpArg& arg); - void MOVUPS(const OpArg& arg, X64Reg regOp); - void MOVUPD(const OpArg& arg, X64Reg regOp); - - void MOVDQA(X64Reg regOp, const OpArg& arg); - void MOVDQA(const OpArg& arg, X64Reg regOp); - void MOVDQU(X64Reg regOp, const OpArg& arg); - void MOVDQU(const OpArg& arg, X64Reg regOp); - - void MOVSS(X64Reg regOp, const OpArg& arg); - void MOVSD(X64Reg regOp, const OpArg& arg); - void MOVSS(const OpArg& arg, X64Reg regOp); - void MOVSD(const OpArg& arg, X64Reg regOp); - - void MOVLPS(X64Reg regOp, const OpArg& arg); - void MOVLPD(X64Reg regOp, const OpArg& arg); - void MOVLPS(const OpArg& arg, X64Reg regOp); - void MOVLPD(const OpArg& arg, X64Reg regOp); - - void MOVHPS(X64Reg regOp, const OpArg& arg); - void MOVHPD(X64Reg regOp, const OpArg& arg); - void MOVHPS(const OpArg& arg, X64Reg regOp); - void MOVHPD(const OpArg& arg, X64Reg regOp); - - void MOVHLPS(X64Reg regOp1, X64Reg regOp2); - void MOVLHPS(X64Reg regOp1, X64Reg regOp2); - - // Be careful when using these overloads for reg <--> xmm moves. - // The one you cast to OpArg with R(reg) is the x86 reg, the other - // one is the xmm reg. - // ie: "MOVD_xmm(eax, R(xmm1))" generates incorrect code (movd xmm0, rcx) - // use "MOVD_xmm(R(eax), xmm1)" instead. - void MOVD_xmm(X64Reg dest, const OpArg& arg); - void MOVQ_xmm(X64Reg dest, OpArg arg); - void MOVD_xmm(const OpArg& arg, X64Reg src); - void MOVQ_xmm(OpArg arg, X64Reg src); - - // SSE/SSE2: Generates a mask from the high bits of the components of the packed register in question. - void MOVMSKPS(X64Reg dest, const OpArg& arg); - void MOVMSKPD(X64Reg dest, const OpArg& arg); - - // SSE2: Selective byte store, mask in src register. EDI/RDI specifies store address. This is a weird one. - void MASKMOVDQU(X64Reg dest, X64Reg src); - void LDDQU(X64Reg dest, const OpArg& src); - - // SSE/SSE2: Data type conversions. - void CVTPS2PD(X64Reg dest, const OpArg& src); - void CVTPD2PS(X64Reg dest, const OpArg& src); - void CVTSS2SD(X64Reg dest, const OpArg& src); - void CVTSI2SS(X64Reg dest, const OpArg& src); - void CVTSD2SS(X64Reg dest, const OpArg& src); - void CVTSI2SD(X64Reg dest, const OpArg& src); - void CVTDQ2PD(X64Reg regOp, const OpArg& arg); - void CVTPD2DQ(X64Reg regOp, const OpArg& arg); - void CVTDQ2PS(X64Reg regOp, const OpArg& arg); - void CVTPS2DQ(X64Reg regOp, const OpArg& arg); - - void CVTTPS2DQ(X64Reg regOp, const OpArg& arg); - void CVTTPD2DQ(X64Reg regOp, const OpArg& arg); - - // Destinations are X64 regs (rax, rbx, ...) for these instructions. - void CVTSS2SI(X64Reg xregdest, const OpArg& src); - void CVTSD2SI(X64Reg xregdest, const OpArg& src); - void CVTTSS2SI(X64Reg xregdest, const OpArg& arg); - void CVTTSD2SI(X64Reg xregdest, const OpArg& arg); - - // SSE2: Packed integer instructions - void PACKSSDW(X64Reg dest, const OpArg& arg); - void PACKSSWB(X64Reg dest, const OpArg& arg); - void PACKUSDW(X64Reg dest, const OpArg& arg); - void PACKUSWB(X64Reg dest, const OpArg& arg); - - void PUNPCKLBW(X64Reg dest, const OpArg& arg); - void PUNPCKLWD(X64Reg dest, const OpArg& arg); - void PUNPCKLDQ(X64Reg dest, const OpArg& arg); - void PUNPCKLQDQ(X64Reg dest, const OpArg& arg); - - void PTEST(X64Reg dest, const OpArg& arg); - void PAND(X64Reg dest, const OpArg& arg); - void PANDN(X64Reg dest, const OpArg& arg); - void PXOR(X64Reg dest, const OpArg& arg); - void POR(X64Reg dest, const OpArg& arg); - - void PADDB(X64Reg dest, const OpArg& arg); - void PADDW(X64Reg dest, const OpArg& arg); - void PADDD(X64Reg dest, const OpArg& arg); - void PADDQ(X64Reg dest, const OpArg& arg); - - void PADDSB(X64Reg dest, const OpArg& arg); - void PADDSW(X64Reg dest, const OpArg& arg); - void PADDUSB(X64Reg dest, const OpArg& arg); - void PADDUSW(X64Reg dest, const OpArg& arg); - - void PSUBB(X64Reg dest, const OpArg& arg); - void PSUBW(X64Reg dest, const OpArg& arg); - void PSUBD(X64Reg dest, const OpArg& arg); - void PSUBQ(X64Reg dest, const OpArg& arg); - - void PSUBSB(X64Reg dest, const OpArg& arg); - void PSUBSW(X64Reg dest, const OpArg& arg); - void PSUBUSB(X64Reg dest, const OpArg& arg); - void PSUBUSW(X64Reg dest, const OpArg& arg); - - void PAVGB(X64Reg dest, const OpArg& arg); - void PAVGW(X64Reg dest, const OpArg& arg); - - void PCMPEQB(X64Reg dest, const OpArg& arg); - void PCMPEQW(X64Reg dest, const OpArg& arg); - void PCMPEQD(X64Reg dest, const OpArg& arg); - - void PCMPGTB(X64Reg dest, const OpArg& arg); - void PCMPGTW(X64Reg dest, const OpArg& arg); - void PCMPGTD(X64Reg dest, const OpArg& arg); - - void PEXTRW(X64Reg dest, const OpArg& arg, u8 subreg); - void PINSRW(X64Reg dest, const OpArg& arg, u8 subreg); - void PINSRD(X64Reg dest, const OpArg& arg, u8 subreg); - - void PMADDWD(X64Reg dest, const OpArg& arg); - void PSADBW(X64Reg dest, const OpArg& arg); - - void PMAXSW(X64Reg dest, const OpArg& arg); - void PMAXUB(X64Reg dest, const OpArg& arg); - void PMINSW(X64Reg dest, const OpArg& arg); - void PMINUB(X64Reg dest, const OpArg& arg); - - void PMOVMSKB(X64Reg dest, const OpArg& arg); - void PSHUFD(X64Reg dest, const OpArg& arg, u8 shuffle); - void PSHUFB(X64Reg dest, const OpArg& arg); - - void PSHUFLW(X64Reg dest, const OpArg& arg, u8 shuffle); - void PSHUFHW(X64Reg dest, const OpArg& arg, u8 shuffle); - - void PSRLW(X64Reg reg, int shift); - void PSRLD(X64Reg reg, int shift); - void PSRLQ(X64Reg reg, int shift); - void PSRLQ(X64Reg reg, const OpArg& arg); - void PSRLDQ(X64Reg reg, int shift); - - void PSLLW(X64Reg reg, int shift); - void PSLLD(X64Reg reg, int shift); - void PSLLQ(X64Reg reg, int shift); - void PSLLDQ(X64Reg reg, int shift); - - void PSRAW(X64Reg reg, int shift); - void PSRAD(X64Reg reg, int shift); - - // SSE4: data type conversions - void PMOVSXBW(X64Reg dest, const OpArg& arg); - void PMOVSXBD(X64Reg dest, const OpArg& arg); - void PMOVSXBQ(X64Reg dest, const OpArg& arg); - void PMOVSXWD(X64Reg dest, const OpArg& arg); - void PMOVSXWQ(X64Reg dest, const OpArg& arg); - void PMOVSXDQ(X64Reg dest, const OpArg& arg); - void PMOVZXBW(X64Reg dest, const OpArg& arg); - void PMOVZXBD(X64Reg dest, const OpArg& arg); - void PMOVZXBQ(X64Reg dest, const OpArg& arg); - void PMOVZXWD(X64Reg dest, const OpArg& arg); - void PMOVZXWQ(X64Reg dest, const OpArg& arg); - void PMOVZXDQ(X64Reg dest, const OpArg& arg); - - // SSE4: blend instructions - void PBLENDVB(X64Reg dest, const OpArg& arg); - void BLENDVPS(X64Reg dest, const OpArg& arg); - void BLENDVPD(X64Reg dest, const OpArg& arg); - void BLENDPS(X64Reg dest, const OpArg& arg, u8 blend); - void BLENDPD(X64Reg dest, const OpArg& arg, u8 blend); - - // AVX - void VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VSUBSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VMULSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VDIVSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VADDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VSUBPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VMULPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VDIVPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VSQRTSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VCMPPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, u8 compare); - void VSHUFPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, u8 shuffle); - void VUNPCKLPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VUNPCKHPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VBLENDVPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, X64Reg mask); - - void VANDPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VANDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VANDNPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VANDNPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VXORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VXORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - - void VPAND(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VPANDN(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VPOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VPXOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - - // FMA3 - void VFMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFNMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADDSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADDSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADDSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADDSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADDSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMADDSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUBADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUBADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUBADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUBADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUBADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void VFMSUBADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - - #define FMA4(name) \ - void name(X64Reg dest, X64Reg regOp1, X64Reg regOp2, const OpArg& arg); \ - void name(X64Reg dest, X64Reg regOp1, const OpArg& arg, X64Reg regOp2); - - FMA4(VFMADDSUBPS) - FMA4(VFMADDSUBPD) - FMA4(VFMSUBADDPS) - FMA4(VFMSUBADDPD) - FMA4(VFMADDPS) - FMA4(VFMADDPD) - FMA4(VFMADDSS) - FMA4(VFMADDSD) - FMA4(VFMSUBPS) - FMA4(VFMSUBPD) - FMA4(VFMSUBSS) - FMA4(VFMSUBSD) - FMA4(VFNMADDPS) - FMA4(VFNMADDPD) - FMA4(VFNMADDSS) - FMA4(VFNMADDSD) - FMA4(VFNMSUBPS) - FMA4(VFNMSUBPD) - FMA4(VFNMSUBSS) - FMA4(VFNMSUBSD) - #undef FMA4 - - // VEX GPR instructions - void SARX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2); - void SHLX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2); - void SHRX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2); - void RORX(int bits, X64Reg regOp, const OpArg& arg, u8 rotate); - void PEXT(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void PDEP(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void MULX(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - void BZHI(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2); - void BLSR(int bits, X64Reg regOp, const OpArg& arg); - void BLSMSK(int bits, X64Reg regOp, const OpArg& arg); - void BLSI(int bits, X64Reg regOp, const OpArg& arg); - void BEXTR(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2); - void ANDN(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg); - - void RDTSC(); - - // Utility functions - // The difference between this and CALL is that this aligns the stack - // where appropriate. - void ABI_CallFunction(const void* func); - - void ABI_CallFunctionC16(const void* func, u16 param1); - void ABI_CallFunctionCC16(const void* func, u32 param1, u16 param2); - - // These only support u32 parameters, but that's enough for a lot of uses. - // These will destroy the 1 or 2 first "parameter regs". - void ABI_CallFunctionC(const void* func, u32 param1); - void ABI_CallFunctionCC(const void* func, u32 param1, u32 param2); - void ABI_CallFunctionCP(const void* func, u32 param1, void* param2); - void ABI_CallFunctionCCC(const void* func, u32 param1, u32 param2, u32 param3); - void ABI_CallFunctionCCP(const void* func, u32 param1, u32 param2, void* param3); - void ABI_CallFunctionCCCP(const void* func, u32 param1, u32 param2,u32 param3, void* param4); - void ABI_CallFunctionPC(const void* func, void* param1, u32 param2); - void ABI_CallFunctionPPC(const void* func, void* param1, void* param2, u32 param3); - void ABI_CallFunctionAC(int bits, const void* func, const OpArg& arg1, u32 param2); - void ABI_CallFunctionA(int bits, const void* func, const OpArg& arg1); - - // Pass a register as a parameter. - void ABI_CallFunctionR(const void* func, X64Reg reg1); - void ABI_CallFunctionRR(const void* func, X64Reg reg1, X64Reg reg2); - - // Helper method for the above, or can be used separately. - void MOVTwo(int bits, X64Reg dst1, X64Reg src1, s32 offset, X64Reg dst2,X64Reg src2); - - // Saves/restores the registers and adjusts the stack to be aligned as - // required by the ABI, where the previous alignment was as specified. - // Push returns the size of the shadow space, i.e. the offset of the frame. - size_t ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size = 0); - void ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size = 0); - - // Utility to generate a call to a std::function object. - // - // Unfortunately, calling operator() directly is undefined behavior in C++ - // (this method might be a thunk in the case of multi-inheritance) so we - // have to go through a trampoline function. - template - static T CallLambdaTrampoline(const std::function* f, Args... args) - { - return (*f)(args...); - } - - template - void ABI_CallLambdaC(const std::function* f, u32 p1) - { - auto trampoline = &XEmitter::CallLambdaTrampoline; - ABI_CallFunctionPC((void*)trampoline, const_cast((const void*)f), p1); - } + void CALL(const void* fnptr); + void CALLptr(OpArg arg); + + FixupBranch J_CC(CCFlags conditionCode, bool force5bytes = false); + void J_CC(CCFlags conditionCode, const u8* addr); + + void SetJumpTarget(const FixupBranch& branch); + + void SETcc(CCFlags flag, OpArg dest); + // Note: CMOV brings small if any benefit on current CPUs. + void CMOVcc(int bits, X64Reg dest, OpArg src, CCFlags flag); + + // Fences + void LFENCE(); + void MFENCE(); + void SFENCE(); + + // Bit scan + void BSF(int bits, X64Reg dest, const OpArg& src); // Bottom bit to top bit + void BSR(int bits, X64Reg dest, const OpArg& src); // Top bit to bottom bit + + // Cache control + enum PrefetchLevel + { + PF_NTA, // Non-temporal (data used once and only once) + PF_T0, // All cache levels + PF_T1, // Levels 2+ (aliased to T0 on AMD) + PF_T2, // Levels 3+ (aliased to T0 on AMD) + }; + void PREFETCH(PrefetchLevel level, OpArg arg); + void MOVNTI(int bits, const OpArg& dest, X64Reg src); + void MOVNTDQ(const OpArg& arg, X64Reg regOp); + void MOVNTPS(const OpArg& arg, X64Reg regOp); + void MOVNTPD(const OpArg& arg, X64Reg regOp); + + // Multiplication / division + void MUL(int bits, const OpArg& src); // UNSIGNED + void IMUL(int bits, const OpArg& src); // SIGNED + void IMUL(int bits, X64Reg regOp, const OpArg& src); + void IMUL(int bits, X64Reg regOp, const OpArg& src, const OpArg& imm); + void DIV(int bits, const OpArg& src); + void IDIV(int bits, const OpArg& src); + + // Shift + void ROL(int bits, const OpArg& dest, const OpArg& shift); + void ROR(int bits, const OpArg& dest, const OpArg& shift); + void RCL(int bits, const OpArg& dest, const OpArg& shift); + void RCR(int bits, const OpArg& dest, const OpArg& shift); + void SHL(int bits, const OpArg& dest, const OpArg& shift); + void SHR(int bits, const OpArg& dest, const OpArg& shift); + void SAR(int bits, const OpArg& dest, const OpArg& shift); + + // Bit Test + void BT(int bits, const OpArg& dest, const OpArg& index); + void BTS(int bits, const OpArg& dest, const OpArg& index); + void BTR(int bits, const OpArg& dest, const OpArg& index); + void BTC(int bits, const OpArg& dest, const OpArg& index); + + // Double-Precision Shift + void SHRD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift); + void SHLD(int bits, const OpArg& dest, const OpArg& src, const OpArg& shift); + + // Extend EAX into EDX in various ways + void CWD(int bits = 16); + inline void CDQ() { CWD(32); } + inline void CQO() { CWD(64); } + void CBW(int bits = 8); + inline void CWDE() { CBW(16); } + inline void CDQE() { CBW(32); } + // Load effective address + void LEA(int bits, X64Reg dest, OpArg src); + + // Integer arithmetic + void NEG(int bits, const OpArg& src); + void ADD(int bits, const OpArg& a1, const OpArg& a2); + void ADC(int bits, const OpArg& a1, const OpArg& a2); + void SUB(int bits, const OpArg& a1, const OpArg& a2); + void SBB(int bits, const OpArg& a1, const OpArg& a2); + void AND(int bits, const OpArg& a1, const OpArg& a2); + void CMP(int bits, const OpArg& a1, const OpArg& a2); + + // Bit operations + void NOT(int bits, const OpArg& src); + void OR(int bits, const OpArg& a1, const OpArg& a2); + void XOR(int bits, const OpArg& a1, const OpArg& a2); + void MOV(int bits, const OpArg& a1, const OpArg& a2); + void TEST(int bits, const OpArg& a1, const OpArg& a2); + + void CMP_or_TEST(int bits, const OpArg& a1, const OpArg& a2); + + // Are these useful at all? Consider removing. + void XCHG(int bits, const OpArg& a1, const OpArg& a2); + void XCHG_AHAL(); + + // Byte swapping (32 and 64-bit only). + void BSWAP(int bits, X64Reg reg); + + // Sign/zero extension + void MOVSX(int dbits, int sbits, X64Reg dest, + OpArg src); // automatically uses MOVSXD if necessary + void MOVZX(int dbits, int sbits, X64Reg dest, OpArg src); + + // Available only on Atom or >= Haswell so far. Test with cpu_info.bMOVBE. + void MOVBE(int bits, X64Reg dest, const OpArg& src); + void MOVBE(int bits, const OpArg& dest, X64Reg src); + void LoadAndSwap(int size, X64Reg dst, const OpArg& src, bool sign_extend = false); + u8* SwapAndStore(int size, const OpArg& dst, X64Reg src); + + // Available only on AMD >= Phenom or Intel >= Haswell + void LZCNT(int bits, X64Reg dest, const OpArg& src); + // Note: this one is actually part of BMI1 + void TZCNT(int bits, X64Reg dest, const OpArg& src); + + // WARNING - These two take 11-13 cycles and are VectorPath! (AMD64) + void STMXCSR(const OpArg& memloc); + void LDMXCSR(const OpArg& memloc); + + // Prefixes + void LOCK(); + void REP(); + void REPNE(); + void FSOverride(); + void GSOverride(); + + // x87 + enum x87StatusWordBits + { + x87_InvalidOperation = 0x1, + x87_DenormalizedOperand = 0x2, + x87_DivisionByZero = 0x4, + x87_Overflow = 0x8, + x87_Underflow = 0x10, + x87_Precision = 0x20, + x87_StackFault = 0x40, + x87_ErrorSummary = 0x80, + x87_C0 = 0x100, + x87_C1 = 0x200, + x87_C2 = 0x400, + x87_TopOfStack = 0x2000 | 0x1000 | 0x800, + x87_C3 = 0x4000, + x87_FPUBusy = 0x8000, + }; + + void FLD(int bits, const OpArg& src); + void FST(int bits, const OpArg& dest); + void FSTP(int bits, const OpArg& dest); + void FNSTSW_AX(); + void FWAIT(); + + // SSE/SSE2: Floating point arithmetic + void ADDSS(X64Reg regOp, const OpArg& arg); + void ADDSD(X64Reg regOp, const OpArg& arg); + void SUBSS(X64Reg regOp, const OpArg& arg); + void SUBSD(X64Reg regOp, const OpArg& arg); + void MULSS(X64Reg regOp, const OpArg& arg); + void MULSD(X64Reg regOp, const OpArg& arg); + void DIVSS(X64Reg regOp, const OpArg& arg); + void DIVSD(X64Reg regOp, const OpArg& arg); + void MINSS(X64Reg regOp, const OpArg& arg); + void MINSD(X64Reg regOp, const OpArg& arg); + void MAXSS(X64Reg regOp, const OpArg& arg); + void MAXSD(X64Reg regOp, const OpArg& arg); + void SQRTSS(X64Reg regOp, const OpArg& arg); + void SQRTSD(X64Reg regOp, const OpArg& arg); + void RCPSS(X64Reg regOp, const OpArg& arg); + void RSQRTSS(X64Reg regOp, const OpArg& arg); + + // SSE/SSE2: Floating point bitwise (yes) + void CMPSS(X64Reg regOp, const OpArg& arg, u8 compare); + void CMPSD(X64Reg regOp, const OpArg& arg, u8 compare); + + // SSE/SSE2: Floating point packed arithmetic (x4 for float, x2 for double) + void ADDPS(X64Reg regOp, const OpArg& arg); + void ADDPD(X64Reg regOp, const OpArg& arg); + void SUBPS(X64Reg regOp, const OpArg& arg); + void SUBPD(X64Reg regOp, const OpArg& arg); + void CMPPS(X64Reg regOp, const OpArg& arg, u8 compare); + void CMPPD(X64Reg regOp, const OpArg& arg, u8 compare); + void MULPS(X64Reg regOp, const OpArg& arg); + void MULPD(X64Reg regOp, const OpArg& arg); + void DIVPS(X64Reg regOp, const OpArg& arg); + void DIVPD(X64Reg regOp, const OpArg& arg); + void MINPS(X64Reg regOp, const OpArg& arg); + void MINPD(X64Reg regOp, const OpArg& arg); + void MAXPS(X64Reg regOp, const OpArg& arg); + void MAXPD(X64Reg regOp, const OpArg& arg); + void SQRTPS(X64Reg regOp, const OpArg& arg); + void SQRTPD(X64Reg regOp, const OpArg& arg); + void RCPPS(X64Reg regOp, const OpArg& arg); + void RSQRTPS(X64Reg regOp, const OpArg& arg); + + // SSE/SSE2: Floating point packed bitwise (x4 for float, x2 for double) + void ANDPS(X64Reg regOp, const OpArg& arg); + void ANDPD(X64Reg regOp, const OpArg& arg); + void ANDNPS(X64Reg regOp, const OpArg& arg); + void ANDNPD(X64Reg regOp, const OpArg& arg); + void ORPS(X64Reg regOp, const OpArg& arg); + void ORPD(X64Reg regOp, const OpArg& arg); + void XORPS(X64Reg regOp, const OpArg& arg); + void XORPD(X64Reg regOp, const OpArg& arg); + + // SSE/SSE2: Shuffle components. These are tricky - see Intel documentation. + void SHUFPS(X64Reg regOp, const OpArg& arg, u8 shuffle); + void SHUFPD(X64Reg regOp, const OpArg& arg, u8 shuffle); + + // SSE3 + void MOVSLDUP(X64Reg regOp, const OpArg& arg); + void MOVSHDUP(X64Reg regOp, const OpArg& arg); + void MOVDDUP(X64Reg regOp, const OpArg& arg); + + // SSE/SSE2: Useful alternative to shuffle in some cases. + void UNPCKLPS(X64Reg dest, const OpArg& src); + void UNPCKHPS(X64Reg dest, const OpArg& src); + void UNPCKLPD(X64Reg dest, const OpArg& src); + void UNPCKHPD(X64Reg dest, const OpArg& src); + + // SSE/SSE2: Compares. + void COMISS(X64Reg regOp, const OpArg& arg); + void COMISD(X64Reg regOp, const OpArg& arg); + void UCOMISS(X64Reg regOp, const OpArg& arg); + void UCOMISD(X64Reg regOp, const OpArg& arg); + + // SSE/SSE2: Moves. Use the right data type for your data, in most cases. + void MOVAPS(X64Reg regOp, const OpArg& arg); + void MOVAPD(X64Reg regOp, const OpArg& arg); + void MOVAPS(const OpArg& arg, X64Reg regOp); + void MOVAPD(const OpArg& arg, X64Reg regOp); + + void MOVUPS(X64Reg regOp, const OpArg& arg); + void MOVUPD(X64Reg regOp, const OpArg& arg); + void MOVUPS(const OpArg& arg, X64Reg regOp); + void MOVUPD(const OpArg& arg, X64Reg regOp); + + void MOVDQA(X64Reg regOp, const OpArg& arg); + void MOVDQA(const OpArg& arg, X64Reg regOp); + void MOVDQU(X64Reg regOp, const OpArg& arg); + void MOVDQU(const OpArg& arg, X64Reg regOp); + + void MOVSS(X64Reg regOp, const OpArg& arg); + void MOVSD(X64Reg regOp, const OpArg& arg); + void MOVSS(const OpArg& arg, X64Reg regOp); + void MOVSD(const OpArg& arg, X64Reg regOp); + + void MOVLPS(X64Reg regOp, const OpArg& arg); + void MOVLPD(X64Reg regOp, const OpArg& arg); + void MOVLPS(const OpArg& arg, X64Reg regOp); + void MOVLPD(const OpArg& arg, X64Reg regOp); + + void MOVHPS(X64Reg regOp, const OpArg& arg); + void MOVHPD(X64Reg regOp, const OpArg& arg); + void MOVHPS(const OpArg& arg, X64Reg regOp); + void MOVHPD(const OpArg& arg, X64Reg regOp); + + void MOVHLPS(X64Reg regOp1, X64Reg regOp2); + void MOVLHPS(X64Reg regOp1, X64Reg regOp2); + + // Be careful when using these overloads for reg <--> xmm moves. + // The one you cast to OpArg with R(reg) is the x86 reg, the other + // one is the xmm reg. + // ie: "MOVD_xmm(eax, R(xmm1))" generates incorrect code (movd xmm0, rcx) + // use "MOVD_xmm(R(eax), xmm1)" instead. + void MOVD_xmm(X64Reg dest, const OpArg& arg); + void MOVQ_xmm(X64Reg dest, OpArg arg); + void MOVD_xmm(const OpArg& arg, X64Reg src); + void MOVQ_xmm(OpArg arg, X64Reg src); + + // SSE/SSE2: Generates a mask from the high bits of the components of the packed register in + // question. + void MOVMSKPS(X64Reg dest, const OpArg& arg); + void MOVMSKPD(X64Reg dest, const OpArg& arg); + + // SSE2: Selective byte store, mask in src register. EDI/RDI specifies store address. This is a + // weird one. + void MASKMOVDQU(X64Reg dest, X64Reg src); + void LDDQU(X64Reg dest, const OpArg& src); + + // SSE/SSE2: Data type conversions. + void CVTPS2PD(X64Reg dest, const OpArg& src); + void CVTPD2PS(X64Reg dest, const OpArg& src); + void CVTSS2SD(X64Reg dest, const OpArg& src); + void CVTSI2SS(X64Reg dest, const OpArg& src); + void CVTSD2SS(X64Reg dest, const OpArg& src); + void CVTSI2SD(X64Reg dest, const OpArg& src); + void CVTDQ2PD(X64Reg regOp, const OpArg& arg); + void CVTPD2DQ(X64Reg regOp, const OpArg& arg); + void CVTDQ2PS(X64Reg regOp, const OpArg& arg); + void CVTPS2DQ(X64Reg regOp, const OpArg& arg); + + void CVTTPS2DQ(X64Reg regOp, const OpArg& arg); + void CVTTPD2DQ(X64Reg regOp, const OpArg& arg); + + // Destinations are X64 regs (rax, rbx, ...) for these instructions. + void CVTSS2SI(X64Reg xregdest, const OpArg& src); + void CVTSD2SI(X64Reg xregdest, const OpArg& src); + void CVTTSS2SI(X64Reg xregdest, const OpArg& arg); + void CVTTSD2SI(X64Reg xregdest, const OpArg& arg); + + // SSE2: Packed integer instructions + void PACKSSDW(X64Reg dest, const OpArg& arg); + void PACKSSWB(X64Reg dest, const OpArg& arg); + void PACKUSDW(X64Reg dest, const OpArg& arg); + void PACKUSWB(X64Reg dest, const OpArg& arg); + + void PUNPCKLBW(X64Reg dest, const OpArg& arg); + void PUNPCKLWD(X64Reg dest, const OpArg& arg); + void PUNPCKLDQ(X64Reg dest, const OpArg& arg); + void PUNPCKLQDQ(X64Reg dest, const OpArg& arg); + + void PTEST(X64Reg dest, const OpArg& arg); + void PAND(X64Reg dest, const OpArg& arg); + void PANDN(X64Reg dest, const OpArg& arg); + void PXOR(X64Reg dest, const OpArg& arg); + void POR(X64Reg dest, const OpArg& arg); + + void PADDB(X64Reg dest, const OpArg& arg); + void PADDW(X64Reg dest, const OpArg& arg); + void PADDD(X64Reg dest, const OpArg& arg); + void PADDQ(X64Reg dest, const OpArg& arg); + + void PADDSB(X64Reg dest, const OpArg& arg); + void PADDSW(X64Reg dest, const OpArg& arg); + void PADDUSB(X64Reg dest, const OpArg& arg); + void PADDUSW(X64Reg dest, const OpArg& arg); + + void PSUBB(X64Reg dest, const OpArg& arg); + void PSUBW(X64Reg dest, const OpArg& arg); + void PSUBD(X64Reg dest, const OpArg& arg); + void PSUBQ(X64Reg dest, const OpArg& arg); + + void PSUBSB(X64Reg dest, const OpArg& arg); + void PSUBSW(X64Reg dest, const OpArg& arg); + void PSUBUSB(X64Reg dest, const OpArg& arg); + void PSUBUSW(X64Reg dest, const OpArg& arg); + + void PAVGB(X64Reg dest, const OpArg& arg); + void PAVGW(X64Reg dest, const OpArg& arg); + + void PCMPEQB(X64Reg dest, const OpArg& arg); + void PCMPEQW(X64Reg dest, const OpArg& arg); + void PCMPEQD(X64Reg dest, const OpArg& arg); + + void PCMPGTB(X64Reg dest, const OpArg& arg); + void PCMPGTW(X64Reg dest, const OpArg& arg); + void PCMPGTD(X64Reg dest, const OpArg& arg); + + void PEXTRW(X64Reg dest, const OpArg& arg, u8 subreg); + void PINSRW(X64Reg dest, const OpArg& arg, u8 subreg); + void PINSRD(X64Reg dest, const OpArg& arg, u8 subreg); + + void PMADDWD(X64Reg dest, const OpArg& arg); + void PSADBW(X64Reg dest, const OpArg& arg); + + void PMAXSW(X64Reg dest, const OpArg& arg); + void PMAXUB(X64Reg dest, const OpArg& arg); + void PMINSW(X64Reg dest, const OpArg& arg); + void PMINUB(X64Reg dest, const OpArg& arg); + + void PMOVMSKB(X64Reg dest, const OpArg& arg); + void PSHUFD(X64Reg dest, const OpArg& arg, u8 shuffle); + void PSHUFB(X64Reg dest, const OpArg& arg); + + void PSHUFLW(X64Reg dest, const OpArg& arg, u8 shuffle); + void PSHUFHW(X64Reg dest, const OpArg& arg, u8 shuffle); + + void PSRLW(X64Reg reg, int shift); + void PSRLD(X64Reg reg, int shift); + void PSRLQ(X64Reg reg, int shift); + void PSRLQ(X64Reg reg, const OpArg& arg); + void PSRLDQ(X64Reg reg, int shift); + + void PSLLW(X64Reg reg, int shift); + void PSLLD(X64Reg reg, int shift); + void PSLLQ(X64Reg reg, int shift); + void PSLLDQ(X64Reg reg, int shift); + + void PSRAW(X64Reg reg, int shift); + void PSRAD(X64Reg reg, int shift); + + // SSE4: data type conversions + void PMOVSXBW(X64Reg dest, const OpArg& arg); + void PMOVSXBD(X64Reg dest, const OpArg& arg); + void PMOVSXBQ(X64Reg dest, const OpArg& arg); + void PMOVSXWD(X64Reg dest, const OpArg& arg); + void PMOVSXWQ(X64Reg dest, const OpArg& arg); + void PMOVSXDQ(X64Reg dest, const OpArg& arg); + void PMOVZXBW(X64Reg dest, const OpArg& arg); + void PMOVZXBD(X64Reg dest, const OpArg& arg); + void PMOVZXBQ(X64Reg dest, const OpArg& arg); + void PMOVZXWD(X64Reg dest, const OpArg& arg); + void PMOVZXWQ(X64Reg dest, const OpArg& arg); + void PMOVZXDQ(X64Reg dest, const OpArg& arg); + + // SSE4: blend instructions + void PBLENDVB(X64Reg dest, const OpArg& arg); + void BLENDVPS(X64Reg dest, const OpArg& arg); + void BLENDVPD(X64Reg dest, const OpArg& arg); + void BLENDPS(X64Reg dest, const OpArg& arg, u8 blend); + void BLENDPD(X64Reg dest, const OpArg& arg, u8 blend); + + // AVX + void VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VSUBSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VMULSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VDIVSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VADDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VSUBPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VMULPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VDIVPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VSQRTSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VCMPPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, u8 compare); + void VSHUFPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, u8 shuffle); + void VUNPCKLPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VUNPCKHPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VBLENDVPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg, X64Reg mask); + + void VANDPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VANDPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VANDNPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VANDNPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VXORPS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VXORPD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + + void VPAND(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VPANDN(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VPOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VPXOR(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + + // FMA3 + void VFMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMADD132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMADD213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMADD231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMADD132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMADD213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMADD231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMSUB132SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMSUB213SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMSUB231SS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMSUB132SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMSUB213SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFNMSUB231SD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADDSUB132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADDSUB213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADDSUB231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADDSUB132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADDSUB213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMADDSUB231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUBADD132PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUBADD213PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUBADD231PS(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUBADD132PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUBADD213PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void VFMSUBADD231PD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + +#define FMA4(name) \ + void name(X64Reg dest, X64Reg regOp1, X64Reg regOp2, const OpArg& arg); \ + void name(X64Reg dest, X64Reg regOp1, const OpArg& arg, X64Reg regOp2); + + FMA4(VFMADDSUBPS) + FMA4(VFMADDSUBPD) + FMA4(VFMSUBADDPS) + FMA4(VFMSUBADDPD) + FMA4(VFMADDPS) + FMA4(VFMADDPD) + FMA4(VFMADDSS) + FMA4(VFMADDSD) + FMA4(VFMSUBPS) + FMA4(VFMSUBPD) + FMA4(VFMSUBSS) + FMA4(VFMSUBSD) + FMA4(VFNMADDPS) + FMA4(VFNMADDPD) + FMA4(VFNMADDSS) + FMA4(VFNMADDSD) + FMA4(VFNMSUBPS) + FMA4(VFNMSUBPD) + FMA4(VFNMSUBSS) + FMA4(VFNMSUBSD) +#undef FMA4 + + // VEX GPR instructions + void SARX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2); + void SHLX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2); + void SHRX(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2); + void RORX(int bits, X64Reg regOp, const OpArg& arg, u8 rotate); + void PEXT(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void PDEP(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void MULX(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + void BZHI(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2); + void BLSR(int bits, X64Reg regOp, const OpArg& arg); + void BLSMSK(int bits, X64Reg regOp, const OpArg& arg); + void BLSI(int bits, X64Reg regOp, const OpArg& arg); + void BEXTR(int bits, X64Reg regOp1, const OpArg& arg, X64Reg regOp2); + void ANDN(int bits, X64Reg regOp1, X64Reg regOp2, const OpArg& arg); + + void RDTSC(); + + // Utility functions + // The difference between this and CALL is that this aligns the stack + // where appropriate. + void ABI_CallFunction(const void* func); + + void ABI_CallFunctionC16(const void* func, u16 param1); + void ABI_CallFunctionCC16(const void* func, u32 param1, u16 param2); + + // These only support u32 parameters, but that's enough for a lot of uses. + // These will destroy the 1 or 2 first "parameter regs". + void ABI_CallFunctionC(const void* func, u32 param1); + void ABI_CallFunctionCC(const void* func, u32 param1, u32 param2); + void ABI_CallFunctionCP(const void* func, u32 param1, void* param2); + void ABI_CallFunctionCCC(const void* func, u32 param1, u32 param2, u32 param3); + void ABI_CallFunctionCCP(const void* func, u32 param1, u32 param2, void* param3); + void ABI_CallFunctionCCCP(const void* func, u32 param1, u32 param2, u32 param3, void* param4); + void ABI_CallFunctionPC(const void* func, void* param1, u32 param2); + void ABI_CallFunctionPPC(const void* func, void* param1, void* param2, u32 param3); + void ABI_CallFunctionAC(int bits, const void* func, const OpArg& arg1, u32 param2); + void ABI_CallFunctionA(int bits, const void* func, const OpArg& arg1); + + // Pass a register as a parameter. + void ABI_CallFunctionR(const void* func, X64Reg reg1); + void ABI_CallFunctionRR(const void* func, X64Reg reg1, X64Reg reg2); + + // Helper method for the above, or can be used separately. + void MOVTwo(int bits, X64Reg dst1, X64Reg src1, s32 offset, X64Reg dst2, X64Reg src2); + + // Saves/restores the registers and adjusts the stack to be aligned as + // required by the ABI, where the previous alignment was as specified. + // Push returns the size of the shadow space, i.e. the offset of the frame. + size_t ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, + size_t needed_frame_size = 0); + void ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, + size_t needed_frame_size = 0); + + // Utility to generate a call to a std::function object. + // + // Unfortunately, calling operator() directly is undefined behavior in C++ + // (this method might be a thunk in the case of multi-inheritance) so we + // have to go through a trampoline function. + template + static T CallLambdaTrampoline(const std::function* f, Args... args) + { + return (*f)(args...); + } + + template + void ABI_CallLambdaC(const std::function* f, u32 p1) + { + auto trampoline = &XEmitter::CallLambdaTrampoline; + ABI_CallFunctionPC((void*)trampoline, const_cast((const void*)f), p1); + } }; // class XEmitter class X64CodeBlock : public CodeBlock { private: - void PoisonMemory() override - { - // x86/64: 0xCC = breakpoint - memset(region, 0xCC, region_size); - } + void PoisonMemory() override + { + // x86/64: 0xCC = breakpoint + memset(region, 0xCC, region_size); + } }; } // namespace diff --git a/Source/Core/Common/x64FPURoundMode.cpp b/Source/Core/Common/x64FPURoundMode.cpp index d96c1bfa08..66fe60a0d8 100644 --- a/Source/Core/Common/x64FPURoundMode.cpp +++ b/Source/Core/Common/x64FPURoundMode.cpp @@ -4,67 +4,61 @@ #include -#include "Common/CommonTypes.h" #include "Common/CPUDetect.h" +#include "Common/CommonTypes.h" #include "Common/FPURoundMode.h" #include "Common/Intrinsics.h" namespace FPURoundMode { - // Get the default SSE states here. - static u32 saved_sse_state = _mm_getcsr(); - static const u32 default_sse_state = _mm_getcsr(); +// Get the default SSE states here. +static u32 saved_sse_state = _mm_getcsr(); +static const u32 default_sse_state = _mm_getcsr(); - void SetRoundMode(int mode) - { - // Convert PowerPC to native rounding mode. - static const int rounding_mode_lut[] = { - FE_TONEAREST, - FE_TOWARDZERO, - FE_UPWARD, - FE_DOWNWARD - }; - fesetround(rounding_mode_lut[mode]); - } - - void SetPrecisionMode(PrecisionMode /* mode */) - { - //x64 doesn't need this - fpu is done with SSE - } - - void SetSIMDMode(int rounding_mode, bool non_ieee_mode) - { - // OR-mask for disabling FPU exceptions (bits 7-12 in the MXCSR register) - const u32 EXCEPTION_MASK = 0x1F80; - // Flush-To-Zero (non-IEEE mode: denormal outputs are set to +/- 0) - const u32 FTZ = 0x8000; - // lookup table for FPSCR.RN-to-MXCSR.RC translation - static const u32 simd_rounding_table[] = - { - (0 << 13) | EXCEPTION_MASK, // nearest - (3 << 13) | EXCEPTION_MASK, // zero - (2 << 13) | EXCEPTION_MASK, // +inf - (1 << 13) | EXCEPTION_MASK, // -inf - }; - u32 csr = simd_rounding_table[rounding_mode]; - - if (non_ieee_mode) - { - csr |= FTZ; - } - _mm_setcsr(csr); - } - - void SaveSIMDState() - { - saved_sse_state = _mm_getcsr(); - } - void LoadSIMDState() - { - _mm_setcsr(saved_sse_state); - } - void LoadDefaultSIMDState() - { - _mm_setcsr(default_sse_state); - } +void SetRoundMode(int mode) +{ + // Convert PowerPC to native rounding mode. + static const int rounding_mode_lut[] = {FE_TONEAREST, FE_TOWARDZERO, FE_UPWARD, FE_DOWNWARD}; + fesetround(rounding_mode_lut[mode]); +} + +void SetPrecisionMode(PrecisionMode /* mode */) +{ + // x64 doesn't need this - fpu is done with SSE +} + +void SetSIMDMode(int rounding_mode, bool non_ieee_mode) +{ + // OR-mask for disabling FPU exceptions (bits 7-12 in the MXCSR register) + const u32 EXCEPTION_MASK = 0x1F80; + // Flush-To-Zero (non-IEEE mode: denormal outputs are set to +/- 0) + const u32 FTZ = 0x8000; + // lookup table for FPSCR.RN-to-MXCSR.RC translation + static const u32 simd_rounding_table[] = { + (0 << 13) | EXCEPTION_MASK, // nearest + (3 << 13) | EXCEPTION_MASK, // zero + (2 << 13) | EXCEPTION_MASK, // +inf + (1 << 13) | EXCEPTION_MASK, // -inf + }; + u32 csr = simd_rounding_table[rounding_mode]; + + if (non_ieee_mode) + { + csr |= FTZ; + } + _mm_setcsr(csr); +} + +void SaveSIMDState() +{ + saved_sse_state = _mm_getcsr(); +} +void LoadSIMDState() +{ + _mm_setcsr(saved_sse_state); +} +void LoadDefaultSIMDState() +{ + _mm_setcsr(default_sse_state); +} } diff --git a/Source/Core/Core/ARDecrypt.cpp b/Source/Core/Core/ARDecrypt.cpp index b9bb235850..d336ddd276 100644 --- a/Source/Core/Core/ARDecrypt.cpp +++ b/Source/Core/Core/ARDecrypt.cpp @@ -20,491 +20,487 @@ namespace ActionReplay { - // Alphanumeric filter for text<->bin conversion -static const char *filter = "0123456789ABCDEFGHJKMNPQRTUVWXYZILOS"; +static const char* filter = "0123456789ABCDEFGHJKMNPQRTUVWXYZILOS"; static u32 genseeds[0x20]; static const u8 gentable0[0x38] = { - 0x39, 0x31, 0x29, 0x21, 0x19, 0x11, 0x09, 0x01, - 0x3A, 0x32, 0x2A, 0x22, 0x1A, 0x12, 0x0A, 0x02, - 0x3B, 0x33, 0x2B, 0x23, 0x1B, 0x13, 0x0B, 0x03, - 0x3C, 0x34, 0x2C, 0x24, 0x3F, 0x37, 0x2F, 0x27, - 0x1F, 0x17, 0x0F, 0x07, 0x3E, 0x36, 0x2E, 0x26, - 0x1E, 0x16, 0x0E, 0x06, 0x3D, 0x35, 0x2D, 0x25, - 0x1D, 0x15, 0x0D, 0x05, 0x1C, 0x14, 0x0C, 0x04, + 0x39, 0x31, 0x29, 0x21, 0x19, 0x11, 0x09, 0x01, 0x3A, 0x32, 0x2A, 0x22, 0x1A, 0x12, + 0x0A, 0x02, 0x3B, 0x33, 0x2B, 0x23, 0x1B, 0x13, 0x0B, 0x03, 0x3C, 0x34, 0x2C, 0x24, + 0x3F, 0x37, 0x2F, 0x27, 0x1F, 0x17, 0x0F, 0x07, 0x3E, 0x36, 0x2E, 0x26, 0x1E, 0x16, + 0x0E, 0x06, 0x3D, 0x35, 0x2D, 0x25, 0x1D, 0x15, 0x0D, 0x05, 0x1C, 0x14, 0x0C, 0x04, }; static const u8 gentable1[0x08] = { - 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, + 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, }; static const u8 gentable2[0x10] = { - 0x01, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, - 0x0F, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1C, + 0x01, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x0F, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1C, }; static const u8 gentable3[0x30] = { - 0x0E, 0x11, 0x0B, 0x18, 0x01, 0x05, 0x03, 0x1C, - 0x0F, 0x06, 0x15, 0x0A, 0x17, 0x13, 0x0C, 0x04, - 0x1A, 0x08, 0x10, 0x07, 0x1B, 0x14, 0x0D, 0x02, - 0x29, 0x34, 0x1F, 0x25, 0x2F, 0x37, 0x1E, 0x28, - 0x33, 0x2D, 0x21, 0x30, 0x2C, 0x31, 0x27, 0x38, - 0x22, 0x35, 0x2E, 0x2A, 0x32, 0x24, 0x1D, 0x20, + 0x0E, 0x11, 0x0B, 0x18, 0x01, 0x05, 0x03, 0x1C, 0x0F, 0x06, 0x15, 0x0A, 0x17, 0x13, 0x0C, 0x04, + 0x1A, 0x08, 0x10, 0x07, 0x1B, 0x14, 0x0D, 0x02, 0x29, 0x34, 0x1F, 0x25, 0x2F, 0x37, 0x1E, 0x28, + 0x33, 0x2D, 0x21, 0x30, 0x2C, 0x31, 0x27, 0x38, 0x22, 0x35, 0x2E, 0x2A, 0x32, 0x24, 0x1D, 0x20, }; static const u16 crctable0[0x10] = { - 0x0000, 0x1081, 0x2102, 0x3183, 0x4204, 0x5285, 0x6306, 0x7387, - 0x8408, 0x9489, 0xA50A, 0xB58B, 0xC60C, 0xD68D, 0xE70E, 0xF78F, + 0x0000, 0x1081, 0x2102, 0x3183, 0x4204, 0x5285, 0x6306, 0x7387, + 0x8408, 0x9489, 0xA50A, 0xB58B, 0xC60C, 0xD68D, 0xE70E, 0xF78F, }; static const u16 crctable1[0x10] = { - 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, - 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, + 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, + 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, }; static const u8 gensubtable[0x08] = { - 0x34, 0x1C, 0x84, 0x9E, 0xFD, 0xA4, 0xB6, 0x7B, + 0x34, 0x1C, 0x84, 0x9E, 0xFD, 0xA4, 0xB6, 0x7B, }; - static const u32 table0[0x40] = { - 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, - 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, - 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, - 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, - 0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, - 0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, - 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400, - 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004, + 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004, }; static const u32 table1[0x40] = { - 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020, - 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, - 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, - 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, - 0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, - 0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, - 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020, - 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000, + 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000, }; static const u32 table2[0x40] = { - 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200, - 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208, - 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, - 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, - 0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, - 0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, - 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008, - 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200, + 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200, }; static const u32 table3[0x40] = { - 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001, - 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, - 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, - 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, - 0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, - 0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, - 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081, - 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080, }; static const u32 table4[0x40] = { - 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000, - 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, - 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, - 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, - 0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, - 0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, - 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000, - 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100, + 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100, }; static const u32 table5[0x40] = { - 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000, - 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, - 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, - 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, - 0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, - 0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, - 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010, - 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010, + 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010, }; static const u32 table6[0x40] = { - 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800, - 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, - 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, - 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, - 0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, - 0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, - 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802, - 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002, + 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002, }; static const u32 table7[0x40] = { - 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000, - 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, - 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, - 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, - 0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, - 0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, - 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000, - 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000, + 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000, }; - -static void generateseeds(u32 *seeds, const u8 *seedtable, u8 doreverse) +static void generateseeds(u32* seeds, const u8* seedtable, u8 doreverse) { - u32 tmp3; - u8 array0[0x38],array1[0x38],array2[0x08]; - u8 tmp,tmp2; + u32 tmp3; + u8 array0[0x38], array1[0x38], array2[0x08]; + u8 tmp, tmp2; - for (int i = 0; i < 0x38; ++i) - { - tmp = (gentable0[i] - 1); - array0[i] = ((u32)(0-(seedtable[tmp>>3] & gentable1[tmp&7])) >> 31); - } + for (int i = 0; i < 0x38; ++i) + { + tmp = (gentable0[i] - 1); + array0[i] = ((u32)(0 - (seedtable[tmp >> 3] & gentable1[tmp & 7])) >> 31); + } - for (int i = 0; i < 0x10; ++i) - { - memset(array2,0,8); - tmp2 = gentable2[i]; + for (int i = 0; i < 0x10; ++i) + { + memset(array2, 0, 8); + tmp2 = gentable2[i]; - for (int j = 0; j < 0x38; j++) - { - tmp = (tmp2+j); + for (int j = 0; j < 0x38; j++) + { + tmp = (tmp2 + j); - if (j > 0x1B) - { - if (tmp > 0x37) - { - tmp-=0x1C; - } - } - else if (tmp > 0x1B) - { - tmp-=0x1C; - } + if (j > 0x1B) + { + if (tmp > 0x37) + { + tmp -= 0x1C; + } + } + else if (tmp > 0x1B) + { + tmp -= 0x1C; + } - array1[j] = array0[tmp]; - } - for (int j = 0; j < 0x30; j++) - { - if (!array1[gentable3[j]-1]) - { - continue; - } - tmp = (((j*0x2AAB)>>16) - (j>>0x1F)); - array2[tmp] |= (gentable1[j-(tmp*6)]>>2); - } - seeds[i<<1] = ((array2[0]<<24)|(array2[2]<<16)|(array2[4]<<8)|array2[6]); - seeds[(i<<1)+1] = ((array2[1]<<24)|(array2[3]<<16)|(array2[5]<<8)|array2[7]); - } + array1[j] = array0[tmp]; + } + for (int j = 0; j < 0x30; j++) + { + if (!array1[gentable3[j] - 1]) + { + continue; + } + tmp = (((j * 0x2AAB) >> 16) - (j >> 0x1F)); + array2[tmp] |= (gentable1[j - (tmp * 6)] >> 2); + } + seeds[i << 1] = ((array2[0] << 24) | (array2[2] << 16) | (array2[4] << 8) | array2[6]); + seeds[(i << 1) + 1] = ((array2[1] << 24) | (array2[3] << 16) | (array2[5] << 8) | array2[7]); + } - if (!doreverse) - { - int j = 0x1F; - for (int i = 0; i < 16; i+=2) - { - tmp3 = seeds[i]; - seeds[i] = seeds[j-1]; - seeds[j-1] = tmp3; + if (!doreverse) + { + int j = 0x1F; + for (int i = 0; i < 16; i += 2) + { + tmp3 = seeds[i]; + seeds[i] = seeds[j - 1]; + seeds[j - 1] = tmp3; - tmp3 = seeds[i+1]; - seeds[i+1] = seeds[j]; - seeds[j] = tmp3; - j-=2; - } - } + tmp3 = seeds[i + 1]; + seeds[i + 1] = seeds[j]; + seeds[j] = tmp3; + j -= 2; + } + } } static void buildseeds() { - generateseeds(genseeds,gensubtable,0); + generateseeds(genseeds, gensubtable, 0); } -static void getcode(u32 *src, u32 *addr, u32 *val) +static void getcode(u32* src, u32* addr, u32* val) { - *addr = Common::swap32(src[0]); - *val = Common::swap32(src[1]); + *addr = Common::swap32(src[0]); + *val = Common::swap32(src[1]); } -static void setcode(u32 *dst, u32 addr, u32 val) +static void setcode(u32* dst, u32 addr, u32 val) { - dst[0] = Common::swap32(addr); - dst[1] = Common::swap32(val); + dst[0] = Common::swap32(addr); + dst[1] = Common::swap32(val); } -static u16 gencrc16(u32 *codes, u16 size) +static u16 gencrc16(u32* codes, u16 size) { - u16 ret = 0; + u16 ret = 0; - if (size > 0) - { - for (u8 tmp = 0; tmp < size; ++tmp) - { - for (int i = 0; i < 4; ++i) - { - u8 tmp2 = ((codes[tmp] >> (i<<3))^ret); - ret = ((crctable0[(tmp2>>4)&0x0F]^crctable1[tmp2&0x0F])^(ret>>8)); - } - } - } - return ret; + if (size > 0) + { + for (u8 tmp = 0; tmp < size; ++tmp) + { + for (int i = 0; i < 4; ++i) + { + u8 tmp2 = ((codes[tmp] >> (i << 3)) ^ ret); + ret = ((crctable0[(tmp2 >> 4) & 0x0F] ^ crctable1[tmp2 & 0x0F]) ^ (ret >> 8)); + } + } + } + return ret; } -static u8 verifycode(u32 *codes, u16 size) +static u8 verifycode(u32* codes, u16 size) { - u16 tmp = gencrc16(codes,size); - return (((tmp>>12)^(tmp>>8)^(tmp>>4)^tmp)&0x0F); + u16 tmp = gencrc16(codes, size); + return (((tmp >> 12) ^ (tmp >> 8) ^ (tmp >> 4) ^ tmp) & 0x0F); } -static void unscramble1(u32 *addr, u32 *val) +static void unscramble1(u32* addr, u32* val) { - u32 tmp; + u32 tmp; - *val = _rotl(*val,4); + *val = _rotl(*val, 4); - tmp = ((*addr^*val)&0xF0F0F0F0); - *addr ^= tmp; - *val = _rotr((*val^tmp),0x14); + tmp = ((*addr ^ *val) & 0xF0F0F0F0); + *addr ^= tmp; + *val = _rotr((*val ^ tmp), 0x14); - tmp = ((*addr^*val)&0xFFFF0000); - *addr ^= tmp; - *val = _rotr((*val^tmp),0x12); + tmp = ((*addr ^ *val) & 0xFFFF0000); + *addr ^= tmp; + *val = _rotr((*val ^ tmp), 0x12); - tmp = ((*addr^*val)&0x33333333); - *addr ^= tmp; - *val = _rotr((*val^tmp),6); + tmp = ((*addr ^ *val) & 0x33333333); + *addr ^= tmp; + *val = _rotr((*val ^ tmp), 6); - tmp = ((*addr^*val)&0x00FF00FF); - *addr ^= tmp; - *val = _rotl((*val^tmp),9); + tmp = ((*addr ^ *val) & 0x00FF00FF); + *addr ^= tmp; + *val = _rotl((*val ^ tmp), 9); - tmp = ((*addr^*val)&0xAAAAAAAA); - *addr = _rotl((*addr^tmp),1); - *val ^= tmp; + tmp = ((*addr ^ *val) & 0xAAAAAAAA); + *addr = _rotl((*addr ^ tmp), 1); + *val ^= tmp; } -static void unscramble2(u32 *addr, u32 *val) +static void unscramble2(u32* addr, u32* val) { - u32 tmp; + u32 tmp; - *val = _rotr(*val,1); + *val = _rotr(*val, 1); - tmp = ((*addr^*val)&0xAAAAAAAA); - *val ^= tmp; - *addr = _rotr((*addr^tmp),9); + tmp = ((*addr ^ *val) & 0xAAAAAAAA); + *val ^= tmp; + *addr = _rotr((*addr ^ tmp), 9); - tmp = ((*addr^*val)&0x00FF00FF); - *val ^= tmp; - *addr = _rotl((*addr^tmp),6); + tmp = ((*addr ^ *val) & 0x00FF00FF); + *val ^= tmp; + *addr = _rotl((*addr ^ tmp), 6); - tmp = ((*addr^*val)&0x33333333); - *val ^= tmp; - *addr = _rotl((*addr^tmp),0x12); + tmp = ((*addr ^ *val) & 0x33333333); + *val ^= tmp; + *addr = _rotl((*addr ^ tmp), 0x12); - tmp = ((*addr^*val)&0xFFFF0000); - *val ^= tmp; - *addr = _rotl((*addr^tmp),0x14); + tmp = ((*addr ^ *val) & 0xFFFF0000); + *val ^= tmp; + *addr = _rotl((*addr ^ tmp), 0x14); - tmp = ((*addr^*val)&0xF0F0F0F0); - *val ^= tmp; - *addr = _rotr((*addr^tmp),4); + tmp = ((*addr ^ *val) & 0xF0F0F0F0); + *val ^= tmp; + *addr = _rotr((*addr ^ tmp), 4); } -static void decryptcode(u32 *seeds, u32 *code) +static void decryptcode(u32* seeds, u32* code) { - u32 addr,val; - u32 tmp,tmp2; - int i=0; + u32 addr, val; + u32 tmp, tmp2; + int i = 0; - getcode(code,&addr,&val); - unscramble1(&addr,&val); - while (i < 32) - { - tmp = (_rotr(val,4)^seeds[i++]); - tmp2 = (val^seeds[i++]); - addr ^= (table6[tmp&0x3F]^table4[(tmp>>8)&0x3F]^table2[(tmp>>16)&0x3F]^table0[(tmp>>24)&0x3F]^table7[tmp2&0x3F]^table5[(tmp2>>8)&0x3F]^table3[(tmp2>>16)&0x3F]^table1[(tmp2>>24)&0x3F]); + getcode(code, &addr, &val); + unscramble1(&addr, &val); + while (i < 32) + { + tmp = (_rotr(val, 4) ^ seeds[i++]); + tmp2 = (val ^ seeds[i++]); + addr ^= (table6[tmp & 0x3F] ^ table4[(tmp >> 8) & 0x3F] ^ table2[(tmp >> 16) & 0x3F] ^ + table0[(tmp >> 24) & 0x3F] ^ table7[tmp2 & 0x3F] ^ table5[(tmp2 >> 8) & 0x3F] ^ + table3[(tmp2 >> 16) & 0x3F] ^ table1[(tmp2 >> 24) & 0x3F]); - tmp = (_rotr(addr,4)^seeds[i++]); - tmp2 = (addr^seeds[i++]); - val ^= (table6[tmp&0x3F]^table4[(tmp>>8)&0x3F]^table2[(tmp>>16)&0x3F]^table0[(tmp>>24)&0x3F]^table7[tmp2&0x3F]^table5[(tmp2>>8)&0x3F]^table3[(tmp2>>16)&0x3F]^table1[(tmp2>>24)&0x3F]); - } - unscramble2(&addr,&val); - setcode(code,val,addr); + tmp = (_rotr(addr, 4) ^ seeds[i++]); + tmp2 = (addr ^ seeds[i++]); + val ^= (table6[tmp & 0x3F] ^ table4[(tmp >> 8) & 0x3F] ^ table2[(tmp >> 16) & 0x3F] ^ + table0[(tmp >> 24) & 0x3F] ^ table7[tmp2 & 0x3F] ^ table5[(tmp2 >> 8) & 0x3F] ^ + table3[(tmp2 >> 16) & 0x3F] ^ table1[(tmp2 >> 24) & 0x3F]); + } + unscramble2(&addr, &val); + setcode(code, val, addr); } -static bool getbitstring(u32 *ctrl, u32 *out, u8 len) +static bool getbitstring(u32* ctrl, u32* out, u8 len) { - u32 tmp=(ctrl[0]+(ctrl[1]<<2)); + u32 tmp = (ctrl[0] + (ctrl[1] << 2)); - *out = 0; - while (len--) - { - if (ctrl[2] > 0x1F) - { - ctrl[2] = 0; - ctrl[1]++; - tmp = (ctrl[0]+(ctrl[1]<<2)); - } - if (ctrl[1] >= ctrl[3]) - { - return false; - } - *out = ((*out<<1) | ((tmp >> (0x1F-ctrl[2])) & 1)); - ctrl[2]++; - } - return true; + *out = 0; + while (len--) + { + if (ctrl[2] > 0x1F) + { + ctrl[2] = 0; + ctrl[1]++; + tmp = (ctrl[0] + (ctrl[1] << 2)); + } + if (ctrl[1] >= ctrl[3]) + { + return false; + } + *out = ((*out << 1) | ((tmp >> (0x1F - ctrl[2])) & 1)); + ctrl[2]++; + } + return true; } -static bool batchdecrypt(u32 *codes, u16 size) +static bool batchdecrypt(u32* codes, u16 size) { - u32 tmp,*ptr=codes; - u32 tmparray[4] = { 0 },tmparray2[8] = { 0 }; + u32 tmp, *ptr = codes; + u32 tmparray[4] = {0}, tmparray2[8] = {0}; - // Not required - //if (size & 1) return 0; - //if (!size) return 0; + // Not required + // if (size & 1) return 0; + // if (!size) return 0; - tmp = (size >> 1); - while (tmp--) - { - decryptcode(genseeds,ptr); - ptr+=2; - } + tmp = (size >> 1); + while (tmp--) + { + decryptcode(genseeds, ptr); + ptr += 2; + } - tmparray[0] = *codes; - tmparray[1] = 0; - tmparray[2] = 4; // Skip crc - tmparray[3] = size; - getbitstring(tmparray,tmparray2+1,11); // Game id - getbitstring(tmparray,tmparray2+2,17); // Code id - getbitstring(tmparray,tmparray2+3,1); // Master code - getbitstring(tmparray,tmparray2+4,1); // Unknown - getbitstring(tmparray,tmparray2+5,2); // Region + tmparray[0] = *codes; + tmparray[1] = 0; + tmparray[2] = 4; // Skip crc + tmparray[3] = size; + getbitstring(tmparray, tmparray2 + 1, 11); // Game id + getbitstring(tmparray, tmparray2 + 2, 17); // Code id + getbitstring(tmparray, tmparray2 + 3, 1); // Master code + getbitstring(tmparray, tmparray2 + 4, 1); // Unknown + getbitstring(tmparray, tmparray2 + 5, 2); // Region - // Grab gameid and region from the last decrypted code - // TODO: Maybe check this against Dolphin's GameID? - "code is for wrong game" type msg - //gameid = tmparray2[1]; - //region = tmparray2[5]; + // Grab gameid and region from the last decrypted code + // TODO: Maybe check this against Dolphin's GameID? - "code is for wrong game" type msg + // gameid = tmparray2[1]; + // region = tmparray2[5]; - tmp = codes[0]; - codes[0] &= 0x0FFFFFFF; - if ((tmp>>28) != verifycode(codes,size)) - { - return false; - } + tmp = codes[0]; + codes[0] &= 0x0FFFFFFF; + if ((tmp >> 28) != verifycode(codes, size)) + { + return false; + } - return true; + return true; - // Unfinished (so says Parasyte :p ) + // Unfinished (so says Parasyte :p ) } -static int GetVal(const char *flt, char chr) +static int GetVal(const char* flt, char chr) { - int ret = (int)(strchr(flt,chr) - flt); - switch (ret) - { - case 32: // 'I' - case 33: // 'L' - ret = 1; - break; - case 34: // 'O' - ret = 0; - break; - case 35: // 'S' - ret = 5; - break; - } - return ret; + int ret = (int)(strchr(flt, chr) - flt); + switch (ret) + { + case 32: // 'I' + case 33: // 'L' + ret = 1; + break; + case 34: // 'O' + ret = 0; + break; + case 35: // 'S' + ret = 5; + break; + } + return ret; } -static int alphatobin(u32 *dst, const std::vector& alpha, int size) +static int alphatobin(u32* dst, const std::vector& alpha, int size) { - int j = 0; - int ret = 0; - int org = size + 1; - u32 bin[2]; - u8 parity; + int j = 0; + int ret = 0; + int org = size + 1; + u32 bin[2]; + u8 parity; - for (; size; --size) - { - bin[0] = 0; - for (int i = 0; i < 6; i++) - { - bin[0] |= (GetVal(filter,alpha[j>>1][i]) << (((5-i)*5)+2)); - } - bin[0] |= (GetVal(filter,alpha[j>>1][6]) >> 3); - dst[j++] = bin[0]; + for (; size; --size) + { + bin[0] = 0; + for (int i = 0; i < 6; i++) + { + bin[0] |= (GetVal(filter, alpha[j >> 1][i]) << (((5 - i) * 5) + 2)); + } + bin[0] |= (GetVal(filter, alpha[j >> 1][6]) >> 3); + dst[j++] = bin[0]; - bin[1] = 0; - for (int i = 0; i < 6; i++) - { - bin[1] |= (GetVal(filter,alpha[j>>1][i+6]) << (((5-i)*5)+4)); - } - bin[1] |= (GetVal(filter,alpha[j>>1][12]) >> 1); - dst[j++] = bin[1]; + bin[1] = 0; + for (int i = 0; i < 6; i++) + { + bin[1] |= (GetVal(filter, alpha[j >> 1][i + 6]) << (((5 - i) * 5) + 4)); + } + bin[1] |= (GetVal(filter, alpha[j >> 1][12]) >> 1); + dst[j++] = bin[1]; - //verify parity bit - int k = 0; - parity = 0; - for (int i = 0; i < 64; i++) - { - if (i == 32) - { - k++; - } - parity ^= (bin[k] >> (i-(k<<5))); - } - if ((parity&1) != (GetVal(filter,alpha[(j-2)>>1][12])&1)) - { - ret=(org-size); - } - } + // verify parity bit + int k = 0; + parity = 0; + for (int i = 0; i < 64; i++) + { + if (i == 32) + { + k++; + } + parity ^= (bin[k] >> (i - (k << 5))); + } + if ((parity & 1) != (GetVal(filter, alpha[(j - 2) >> 1][12]) & 1)) + { + ret = (org - size); + } + } - return ret; + return ret; } -void DecryptARCode(std::vector vCodes, std::vector &ops) +void DecryptARCode(std::vector vCodes, std::vector& ops) { - // The almighty buildseeds() function!! without this, the crypto routines are useless - buildseeds(); + // The almighty buildseeds() function!! without this, the crypto routines are useless + buildseeds(); - u32 uCodes[1200]; - u32 ret; + u32 uCodes[1200]; + u32 ret; - for (std::string& s : vCodes) - { - std::transform(s.begin(), s.end(), s.begin(), toupper); - } + for (std::string& s : vCodes) + { + std::transform(s.begin(), s.end(), s.begin(), toupper); + } - if ((ret=alphatobin(uCodes, vCodes, (int)vCodes.size()))) - { - PanicAlertT("Action Replay Code Decryption Error:\nParity Check Failed\n\nCulprit Code:\n%s", vCodes[ret].c_str()); - batchdecrypt(uCodes, (u16)vCodes.size()<<1); - } - else if (!batchdecrypt(uCodes, (u16)vCodes.size()<<1)) - { - // Commented out since we just send the code anyways and hope for the best XD - //PanicAlert("Action Replay Code Decryption Error:\nCRC Check Failed\n\n" - // "First Code in Block(should be verification code):\n%s", vCodes[0].c_str()); + if ((ret = alphatobin(uCodes, vCodes, (int)vCodes.size()))) + { + PanicAlertT("Action Replay Code Decryption Error:\nParity Check Failed\n\nCulprit Code:\n%s", + vCodes[ret].c_str()); + batchdecrypt(uCodes, (u16)vCodes.size() << 1); + } + else if (!batchdecrypt(uCodes, (u16)vCodes.size() << 1)) + { + // Commented out since we just send the code anyways and hope for the best XD + // PanicAlert("Action Replay Code Decryption Error:\nCRC Check Failed\n\n" + // "First Code in Block(should be verification code):\n%s", vCodes[0].c_str()); - for (size_t i = 0; i < (vCodes.size()<<1); i+=2) - { - AREntry op; - op.cmd_addr = uCodes[i]; - op.value = uCodes[i+1]; - ops.push_back(op); - //PanicAlert("Decrypted AR Code without verification code:\n%08X %08X", uCodes[i], uCodes[i+1]); - } - } - else - { - // Skip passing the verification code back - for (size_t i = 2; i < (vCodes.size()<<1); i+=2) - { - AREntry op; - op.cmd_addr = uCodes[i]; - op.value = uCodes[i+1]; - ops.push_back(op); - //PanicAlert("Decrypted AR Code:\n%08X %08X", uCodes[i], uCodes[i+1]); - } - } + for (size_t i = 0; i < (vCodes.size() << 1); i += 2) + { + AREntry op; + op.cmd_addr = uCodes[i]; + op.value = uCodes[i + 1]; + ops.push_back(op); + // PanicAlert("Decrypted AR Code without verification code:\n%08X %08X", uCodes[i], + // uCodes[i+1]); + } + } + else + { + // Skip passing the verification code back + for (size_t i = 2; i < (vCodes.size() << 1); i += 2) + { + AREntry op; + op.cmd_addr = uCodes[i]; + op.value = uCodes[i + 1]; + ops.push_back(op); + // PanicAlert("Decrypted AR Code:\n%08X %08X", uCodes[i], uCodes[i+1]); + } + } } -} //namespace ActionReplay +} // namespace ActionReplay diff --git a/Source/Core/Core/ARDecrypt.h b/Source/Core/Core/ARDecrypt.h index 084c0c6d03..897ecb19c8 100644 --- a/Source/Core/Core/ARDecrypt.h +++ b/Source/Core/Core/ARDecrypt.h @@ -11,7 +11,6 @@ namespace ActionReplay { +void DecryptARCode(std::vector vCodes, std::vector& ops); -void DecryptARCode(std::vector vCodes, std::vector &ops); - -} //namespace +} // namespace diff --git a/Source/Core/Core/ActionReplay.cpp b/Source/Core/Core/ActionReplay.cpp index 2f34a49699..c0055d771b 100644 --- a/Source/Core/Core/ActionReplay.cpp +++ b/Source/Core/Core/ActionReplay.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // ----------------------------------------------------------------------------------------- // Partial Action Replay code system implementation. // Will never be able to support some AR codes - specifically those that patch the running @@ -16,7 +15,8 @@ // Code Types: // (Unconditional) Normal Codes (0): this one has subtypes inside // (Conditional) Normal Codes (1 - 7): these just compare values and set the line skip info -// Zero Codes: any code with no address. These codes are used to do special operations like memory copy, etc +// Zero Codes: any code with no address. These codes are used to do special operations like memory +// copy, etc // ------------------------------------------------------------------------------------------------------------- #include @@ -30,920 +30,923 @@ #include "Common/CommonTypes.h" #include "Common/IniFile.h" -#include "Common/StringUtil.h" #include "Common/Logging/LogManager.h" +#include "Common/StringUtil.h" -#include "Core/ActionReplay.h" #include "Core/ARDecrypt.h" +#include "Core/ActionReplay.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/PowerPC/PowerPC.h" namespace ActionReplay { - enum { - // Zero Code Types - ZCODE_END = 0x00, - ZCODE_NORM = 0x02, - ZCODE_ROW = 0x03, - ZCODE_04 = 0x04, + // Zero Code Types + ZCODE_END = 0x00, + ZCODE_NORM = 0x02, + ZCODE_ROW = 0x03, + ZCODE_04 = 0x04, - // Conditional Codes - CONDTIONAL_EQUAL = 0x01, - CONDTIONAL_NOT_EQUAL = 0x02, - CONDTIONAL_LESS_THAN_SIGNED = 0x03, - CONDTIONAL_GREATER_THAN_SIGNED = 0x04, - CONDTIONAL_LESS_THAN_UNSIGNED = 0x05, - CONDTIONAL_GREATER_THAN_UNSIGNED = 0x06, - CONDTIONAL_AND = 0x07, // bitwise AND + // Conditional Codes + CONDTIONAL_EQUAL = 0x01, + CONDTIONAL_NOT_EQUAL = 0x02, + CONDTIONAL_LESS_THAN_SIGNED = 0x03, + CONDTIONAL_GREATER_THAN_SIGNED = 0x04, + CONDTIONAL_LESS_THAN_UNSIGNED = 0x05, + CONDTIONAL_GREATER_THAN_UNSIGNED = 0x06, + CONDTIONAL_AND = 0x07, // bitwise AND - // Conditional Line Counts - CONDTIONAL_ONE_LINE = 0x00, - CONDTIONAL_TWO_LINES = 0x01, - CONDTIONAL_ALL_LINES_UNTIL = 0x02, - CONDTIONAL_ALL_LINES = 0x03, + // Conditional Line Counts + CONDTIONAL_ONE_LINE = 0x00, + CONDTIONAL_TWO_LINES = 0x01, + CONDTIONAL_ALL_LINES_UNTIL = 0x02, + CONDTIONAL_ALL_LINES = 0x03, - // Data Types - DATATYPE_8BIT = 0x00, - DATATYPE_16BIT = 0x01, - DATATYPE_32BIT = 0x02, - DATATYPE_32BIT_FLOAT = 0x03, + // Data Types + DATATYPE_8BIT = 0x00, + DATATYPE_16BIT = 0x01, + DATATYPE_32BIT = 0x02, + DATATYPE_32BIT_FLOAT = 0x03, - // Normal Code 0 Subtypes - SUB_RAM_WRITE = 0x00, - SUB_WRITE_POINTER = 0x01, - SUB_ADD_CODE = 0x02, - SUB_MASTER_CODE = 0x03, + // Normal Code 0 Subtypes + SUB_RAM_WRITE = 0x00, + SUB_WRITE_POINTER = 0x01, + SUB_ADD_CODE = 0x02, + SUB_MASTER_CODE = 0x03, }; // General lock. Protects codes list and internal log. static std::mutex s_lock; static std::vector s_active_codes; static std::vector s_internal_log; -static std::atomic s_use_internal_log{ false }; +static std::atomic s_use_internal_log{false}; // pointer to the code currently being run, (used by log messages that include the code name) static const ARCode* s_current_code = nullptr; static bool s_disable_logging = false; struct ARAddr { - union - { - u32 address; - struct - { - u32 gcaddr : 25; - u32 size : 2; - u32 type : 3; - u32 subtype : 2; - }; - }; + union { + u32 address; + struct + { + u32 gcaddr : 25; + u32 size : 2; + u32 type : 3; + u32 subtype : 2; + }; + }; - ARAddr(const u32 addr) : address(addr) {} - u32 GCAddress() const { return gcaddr | 0x80000000; } - operator u32() const { return address; } + ARAddr(const u32 addr) : address(addr) {} + u32 GCAddress() const { return gcaddr | 0x80000000; } + operator u32() const { return address; } }; // ---------------------- // AR Remote Functions void ApplyCodes(const std::vector& codes) { - if (!SConfig::GetInstance().bEnableCheats) - return; + if (!SConfig::GetInstance().bEnableCheats) + return; - std::lock_guard guard(s_lock); - s_disable_logging = false; - s_active_codes.clear(); - std::copy_if(codes.begin(), codes.end(), std::back_inserter(s_active_codes), [](const ARCode& code) - { - return code.active; - }); - s_active_codes.shrink_to_fit(); + std::lock_guard guard(s_lock); + s_disable_logging = false; + s_active_codes.clear(); + std::copy_if(codes.begin(), codes.end(), std::back_inserter(s_active_codes), + [](const ARCode& code) { return code.active; }); + s_active_codes.shrink_to_fit(); } void AddCode(ARCode code) { - if (!SConfig::GetInstance().bEnableCheats) - return; + if (!SConfig::GetInstance().bEnableCheats) + return; - if (code.active) - { - std::lock_guard guard(s_lock); - s_disable_logging = false; - s_active_codes.emplace_back(std::move(code)); - } + if (code.active) + { + std::lock_guard guard(s_lock); + s_disable_logging = false; + s_active_codes.emplace_back(std::move(code)); + } } void LoadAndApplyCodes(const IniFile& global_ini, const IniFile& local_ini) { - ApplyCodes(LoadCodes(global_ini, local_ini)); + ApplyCodes(LoadCodes(global_ini, local_ini)); } // Parses the Action Replay section of a game ini file. std::vector LoadCodes(const IniFile& global_ini, const IniFile& local_ini) { - std::vector codes; + std::vector codes; - std::unordered_set enabled_names; - { - std::vector enabled_lines; - local_ini.GetLines("ActionReplay_Enabled", &enabled_lines); - for (const std::string& line : enabled_lines) - { - if (line.size() != 0 && line[0] == '$') - { - std::string name = line.substr(1, line.size() - 1); - enabled_names.insert(name); - } - } - } + std::unordered_set enabled_names; + { + std::vector enabled_lines; + local_ini.GetLines("ActionReplay_Enabled", &enabled_lines); + for (const std::string& line : enabled_lines) + { + if (line.size() != 0 && line[0] == '$') + { + std::string name = line.substr(1, line.size() - 1); + enabled_names.insert(name); + } + } + } - const IniFile* inis[2] = {&global_ini, &local_ini}; - for (const IniFile* ini : inis) - { - std::vector lines; - std::vector encrypted_lines; - ARCode current_code; + const IniFile* inis[2] = {&global_ini, &local_ini}; + for (const IniFile* ini : inis) + { + std::vector lines; + std::vector encrypted_lines; + ARCode current_code; - ini->GetLines("ActionReplay", &lines); + ini->GetLines("ActionReplay", &lines); - for (const std::string& line : lines) - { - if (line.empty()) - { - continue; - } + for (const std::string& line : lines) + { + if (line.empty()) + { + continue; + } - std::vector pieces; + std::vector pieces; - // Check if the line is a name of the code - if (line[0] == '$') - { - if (current_code.ops.size()) - { - codes.push_back(current_code); - current_code.ops.clear(); - } - if (encrypted_lines.size()) - { - DecryptARCode(encrypted_lines, current_code.ops); - codes.push_back(current_code); - current_code.ops.clear(); - encrypted_lines.clear(); - } + // Check if the line is a name of the code + if (line[0] == '$') + { + if (current_code.ops.size()) + { + codes.push_back(current_code); + current_code.ops.clear(); + } + if (encrypted_lines.size()) + { + DecryptARCode(encrypted_lines, current_code.ops); + codes.push_back(current_code); + current_code.ops.clear(); + encrypted_lines.clear(); + } - current_code.name = line.substr(1, line.size() - 1); - current_code.active = enabled_names.find(current_code.name) != enabled_names.end(); - current_code.user_defined = (ini == &local_ini); - } - else - { - SplitString(line, ' ', pieces); + current_code.name = line.substr(1, line.size() - 1); + current_code.active = enabled_names.find(current_code.name) != enabled_names.end(); + current_code.user_defined = (ini == &local_ini); + } + else + { + SplitString(line, ' ', pieces); - // Check if the AR code is decrypted - if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8) - { - AREntry op; - bool success_addr = TryParse(std::string("0x") + pieces[0], &op.cmd_addr); - bool success_val = TryParse(std::string("0x") + pieces[1], &op.value); + // Check if the AR code is decrypted + if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8) + { + AREntry op; + bool success_addr = TryParse(std::string("0x") + pieces[0], &op.cmd_addr); + bool success_val = TryParse(std::string("0x") + pieces[1], &op.value); - if (success_addr && success_val) - { - current_code.ops.push_back(op); - } - else - { - PanicAlertT("Action Replay Error: invalid AR code line: %s", line.c_str()); + if (success_addr && success_val) + { + current_code.ops.push_back(op); + } + else + { + PanicAlertT("Action Replay Error: invalid AR code line: %s", line.c_str()); - if (!success_addr) - PanicAlertT("The address is invalid"); + if (!success_addr) + PanicAlertT("The address is invalid"); - if (!success_val) - PanicAlertT("The value is invalid"); - } - } - else - { - SplitString(line, '-', pieces); - if (pieces.size() == 3 && pieces[0].size() == 4 && pieces[1].size() == 4 && pieces[2].size() == 5) - { - // Encrypted AR code - // Decryption is done in "blocks", so we must push blocks into a vector, - // then send to decrypt when a new block is encountered, or if it's the last block. - encrypted_lines.emplace_back(pieces[0] + pieces[1] + pieces[2]); - } - } - } - } + if (!success_val) + PanicAlertT("The value is invalid"); + } + } + else + { + SplitString(line, '-', pieces); + if (pieces.size() == 3 && pieces[0].size() == 4 && pieces[1].size() == 4 && + pieces[2].size() == 5) + { + // Encrypted AR code + // Decryption is done in "blocks", so we must push blocks into a vector, + // then send to decrypt when a new block is encountered, or if it's the last block. + encrypted_lines.emplace_back(pieces[0] + pieces[1] + pieces[2]); + } + } + } + } - // Handle the last code correctly. - if (current_code.ops.size()) - { - codes.push_back(current_code); - } - if (encrypted_lines.size()) - { - DecryptARCode(encrypted_lines, current_code.ops); - codes.push_back(current_code); - } - } + // Handle the last code correctly. + if (current_code.ops.size()) + { + codes.push_back(current_code); + } + if (encrypted_lines.size()) + { + DecryptARCode(encrypted_lines, current_code.ops); + codes.push_back(current_code); + } + } - return codes; + return codes; } void SaveCodes(IniFile* local_ini, const std::vector& codes) { - std::vector lines; - std::vector enabled_lines; - for (const ActionReplay::ARCode& code : codes) - { - if (code.active) - enabled_lines.emplace_back("$" + code.name); + std::vector lines; + std::vector enabled_lines; + for (const ActionReplay::ARCode& code : codes) + { + if (code.active) + enabled_lines.emplace_back("$" + code.name); - if (code.user_defined) - { - lines.emplace_back("$" + code.name); - for (const ActionReplay::AREntry& op : code.ops) - { - lines.emplace_back(StringFromFormat("%08X %08X", op.cmd_addr, op.value)); - } - } - } - local_ini->SetLines("ActionReplay_Enabled", enabled_lines); - local_ini->SetLines("ActionReplay", lines); + if (code.user_defined) + { + lines.emplace_back("$" + code.name); + for (const ActionReplay::AREntry& op : code.ops) + { + lines.emplace_back(StringFromFormat("%08X %08X", op.cmd_addr, op.value)); + } + } + } + local_ini->SetLines("ActionReplay_Enabled", enabled_lines); + local_ini->SetLines("ActionReplay", lines); } - static void LogInfo(const char* format, ...) { - if (s_disable_logging) - return; - bool use_internal_log = s_use_internal_log.load(std::memory_order_relaxed); - if (LogManager::GetMaxLevel() < LogTypes::LINFO && !use_internal_log) - return; + if (s_disable_logging) + return; + bool use_internal_log = s_use_internal_log.load(std::memory_order_relaxed); + if (LogManager::GetMaxLevel() < LogTypes::LINFO && !use_internal_log) + return; - va_list args; - va_start(args, format); - std::string text = StringFromFormatV(format, args); - va_end(args); - INFO_LOG(ACTIONREPLAY, "%s", text.c_str()); + va_list args; + va_start(args, format); + std::string text = StringFromFormatV(format, args); + va_end(args); + INFO_LOG(ACTIONREPLAY, "%s", text.c_str()); - if (use_internal_log) - { - text += '\n'; - s_internal_log.emplace_back(std::move(text)); - } + if (use_internal_log) + { + text += '\n'; + s_internal_log.emplace_back(std::move(text)); + } } void EnableSelfLogging(bool enable) { - s_use_internal_log.store(enable, std::memory_order_relaxed); + s_use_internal_log.store(enable, std::memory_order_relaxed); } std::vector GetSelfLog() { - std::lock_guard guard(s_lock); - return s_internal_log; + std::lock_guard guard(s_lock); + return s_internal_log; } void ClearSelfLog() { - std::lock_guard guard(s_lock); - s_internal_log.clear(); + std::lock_guard guard(s_lock); + s_internal_log.clear(); } bool IsSelfLogging() { - return s_use_internal_log.load(std::memory_order_relaxed); + return s_use_internal_log.load(std::memory_order_relaxed); } // ---------------------- // Code Functions static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data) { - const u32 new_addr = addr.GCAddress(); + const u32 new_addr = addr.GCAddress(); - LogInfo("Hardware Address: %08x", new_addr); - LogInfo("Size: %08x", addr.size); + LogInfo("Hardware Address: %08x", new_addr); + LogInfo("Size: %08x", addr.size); - switch (addr.size) - { - case DATATYPE_8BIT: - { - LogInfo("8-bit Write"); - LogInfo("--------"); - u32 repeat = data >> 8; - for (u32 i = 0; i <= repeat; ++i) - { - PowerPC::HostWrite_U8(data & 0xFF, new_addr + i); - LogInfo("Wrote %08x to address %08x", data & 0xFF, new_addr + i); - } - LogInfo("--------"); - break; - } + switch (addr.size) + { + case DATATYPE_8BIT: + { + LogInfo("8-bit Write"); + LogInfo("--------"); + u32 repeat = data >> 8; + for (u32 i = 0; i <= repeat; ++i) + { + PowerPC::HostWrite_U8(data & 0xFF, new_addr + i); + LogInfo("Wrote %08x to address %08x", data & 0xFF, new_addr + i); + } + LogInfo("--------"); + break; + } - case DATATYPE_16BIT: - { - LogInfo("16-bit Write"); - LogInfo("--------"); - u32 repeat = data >> 16; - for (u32 i = 0; i <= repeat; ++i) - { - PowerPC::HostWrite_U16(data & 0xFFFF, new_addr + i * 2); - LogInfo("Wrote %08x to address %08x", data & 0xFFFF, new_addr + i * 2); - } - LogInfo("--------"); - break; - } + case DATATYPE_16BIT: + { + LogInfo("16-bit Write"); + LogInfo("--------"); + u32 repeat = data >> 16; + for (u32 i = 0; i <= repeat; ++i) + { + PowerPC::HostWrite_U16(data & 0xFFFF, new_addr + i * 2); + LogInfo("Wrote %08x to address %08x", data & 0xFFFF, new_addr + i * 2); + } + LogInfo("--------"); + break; + } - case DATATYPE_32BIT_FLOAT: - case DATATYPE_32BIT: // Dword write - LogInfo("32-bit Write"); - LogInfo("--------"); - PowerPC::HostWrite_U32(data, new_addr); - LogInfo("Wrote %08x to address %08x", data, new_addr); - LogInfo("--------"); - break; + case DATATYPE_32BIT_FLOAT: + case DATATYPE_32BIT: // Dword write + LogInfo("32-bit Write"); + LogInfo("--------"); + PowerPC::HostWrite_U32(data, new_addr); + LogInfo("Wrote %08x to address %08x", data, new_addr); + LogInfo("--------"); + break; - default: - LogInfo("Bad Size"); - PanicAlertT("Action Replay Error: Invalid size " - "(%08x : address = %08x) in Ram Write And Fill (%s)", - addr.size, addr.gcaddr, s_current_code->name.c_str()); - return false; - } + default: + LogInfo("Bad Size"); + PanicAlertT("Action Replay Error: Invalid size " + "(%08x : address = %08x) in Ram Write And Fill (%s)", + addr.size, addr.gcaddr, s_current_code->name.c_str()); + return false; + } - return true; + return true; } static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data) { - const u32 new_addr = addr.GCAddress(); - const u32 ptr = PowerPC::HostRead_U32(new_addr); + const u32 new_addr = addr.GCAddress(); + const u32 ptr = PowerPC::HostRead_U32(new_addr); - LogInfo("Hardware Address: %08x", new_addr); - LogInfo("Size: %08x", addr.size); + LogInfo("Hardware Address: %08x", new_addr); + LogInfo("Size: %08x", addr.size); - switch (addr.size) - { - case DATATYPE_8BIT: - { - LogInfo("Write 8-bit to pointer"); - LogInfo("--------"); - const u8 thebyte = data & 0xFF; - const u32 offset = data >> 8; - LogInfo("Pointer: %08x", ptr); - LogInfo("Byte: %08x", thebyte); - LogInfo("Offset: %08x", offset); - PowerPC::HostWrite_U8(thebyte, ptr + offset); - LogInfo("Wrote %08x to address %08x", thebyte, ptr + offset); - LogInfo("--------"); - break; - } + switch (addr.size) + { + case DATATYPE_8BIT: + { + LogInfo("Write 8-bit to pointer"); + LogInfo("--------"); + const u8 thebyte = data & 0xFF; + const u32 offset = data >> 8; + LogInfo("Pointer: %08x", ptr); + LogInfo("Byte: %08x", thebyte); + LogInfo("Offset: %08x", offset); + PowerPC::HostWrite_U8(thebyte, ptr + offset); + LogInfo("Wrote %08x to address %08x", thebyte, ptr + offset); + LogInfo("--------"); + break; + } - case DATATYPE_16BIT: - { - LogInfo("Write 16-bit to pointer"); - LogInfo("--------"); - const u16 theshort = data & 0xFFFF; - const u32 offset = (data >> 16) << 1; - LogInfo("Pointer: %08x", ptr); - LogInfo("Byte: %08x", theshort); - LogInfo("Offset: %08x", offset); - PowerPC::HostWrite_U16(theshort, ptr + offset); - LogInfo("Wrote %08x to address %08x", theshort, ptr + offset); - LogInfo("--------"); - break; - } + case DATATYPE_16BIT: + { + LogInfo("Write 16-bit to pointer"); + LogInfo("--------"); + const u16 theshort = data & 0xFFFF; + const u32 offset = (data >> 16) << 1; + LogInfo("Pointer: %08x", ptr); + LogInfo("Byte: %08x", theshort); + LogInfo("Offset: %08x", offset); + PowerPC::HostWrite_U16(theshort, ptr + offset); + LogInfo("Wrote %08x to address %08x", theshort, ptr + offset); + LogInfo("--------"); + break; + } - case DATATYPE_32BIT_FLOAT: - case DATATYPE_32BIT: - LogInfo("Write 32-bit to pointer"); - LogInfo("--------"); - PowerPC::HostWrite_U32(data, ptr); - LogInfo("Wrote %08x to address %08x", data, ptr); - LogInfo("--------"); - break; + case DATATYPE_32BIT_FLOAT: + case DATATYPE_32BIT: + LogInfo("Write 32-bit to pointer"); + LogInfo("--------"); + PowerPC::HostWrite_U32(data, ptr); + LogInfo("Wrote %08x to address %08x", data, ptr); + LogInfo("--------"); + break; - default: - LogInfo("Bad Size"); - PanicAlertT("Action Replay Error: Invalid size " - "(%08x : address = %08x) in Write To Pointer (%s)", - addr.size, addr.gcaddr, s_current_code->name.c_str()); - return false; - } - return true; + default: + LogInfo("Bad Size"); + PanicAlertT("Action Replay Error: Invalid size " + "(%08x : address = %08x) in Write To Pointer (%s)", + addr.size, addr.gcaddr, s_current_code->name.c_str()); + return false; + } + return true; } static bool Subtype_AddCode(const ARAddr& addr, const u32 data) { - // Used to increment/decrement a value in memory - const u32 new_addr = addr.GCAddress(); + // Used to increment/decrement a value in memory + const u32 new_addr = addr.GCAddress(); - LogInfo("Hardware Address: %08x", new_addr); - LogInfo("Size: %08x", addr.size); + LogInfo("Hardware Address: %08x", new_addr); + LogInfo("Size: %08x", addr.size); - switch (addr.size) - { - case DATATYPE_8BIT: - LogInfo("8-bit Add"); - LogInfo("--------"); - PowerPC::HostWrite_U8(PowerPC::HostRead_U8(new_addr) + data, new_addr); - LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U8(new_addr) + (data & 0xFF), new_addr); - LogInfo("--------"); - break; + switch (addr.size) + { + case DATATYPE_8BIT: + LogInfo("8-bit Add"); + LogInfo("--------"); + PowerPC::HostWrite_U8(PowerPC::HostRead_U8(new_addr) + data, new_addr); + LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U8(new_addr) + (data & 0xFF), new_addr); + LogInfo("--------"); + break; - case DATATYPE_16BIT: - LogInfo("16-bit Add"); - LogInfo("--------"); - PowerPC::HostWrite_U16(PowerPC::HostRead_U16(new_addr) + data, new_addr); - LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U16(new_addr) + (data & 0xFFFF), new_addr); - LogInfo("--------"); - break; + case DATATYPE_16BIT: + LogInfo("16-bit Add"); + LogInfo("--------"); + PowerPC::HostWrite_U16(PowerPC::HostRead_U16(new_addr) + data, new_addr); + LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U16(new_addr) + (data & 0xFFFF), + new_addr); + LogInfo("--------"); + break; - case DATATYPE_32BIT: - LogInfo("32-bit Add"); - LogInfo("--------"); - PowerPC::HostWrite_U32(PowerPC::HostRead_U32(new_addr) + data, new_addr); - LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U32(new_addr) + data, new_addr); - LogInfo("--------"); - break; + case DATATYPE_32BIT: + LogInfo("32-bit Add"); + LogInfo("--------"); + PowerPC::HostWrite_U32(PowerPC::HostRead_U32(new_addr) + data, new_addr); + LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U32(new_addr) + data, new_addr); + LogInfo("--------"); + break; - case DATATYPE_32BIT_FLOAT: - { - LogInfo("32-bit floating Add"); - LogInfo("--------"); + case DATATYPE_32BIT_FLOAT: + { + LogInfo("32-bit floating Add"); + LogInfo("--------"); - const u32 read = PowerPC::HostRead_U32(new_addr); - const float read_float = reinterpret_cast(read); - // data contains an (unsigned?) integer value - const float fread = read_float + static_cast(data); - const u32 newval = reinterpret_cast(fread); - PowerPC::HostWrite_U32(newval, new_addr); - LogInfo("Old Value %08x", read); - LogInfo("Increment %08x", data); - LogInfo("New value %08x", newval); - LogInfo("--------"); - break; - } + const u32 read = PowerPC::HostRead_U32(new_addr); + const float read_float = reinterpret_cast(read); + // data contains an (unsigned?) integer value + const float fread = read_float + static_cast(data); + const u32 newval = reinterpret_cast(fread); + PowerPC::HostWrite_U32(newval, new_addr); + LogInfo("Old Value %08x", read); + LogInfo("Increment %08x", data); + LogInfo("New value %08x", newval); + LogInfo("--------"); + break; + } - default: - LogInfo("Bad Size"); - PanicAlertT("Action Replay Error: Invalid size " - "(%08x : address = %08x) in Add Code (%s)", - addr.size, addr.gcaddr, s_current_code->name.c_str()); - return false; - } - return true; + default: + LogInfo("Bad Size"); + PanicAlertT("Action Replay Error: Invalid size " + "(%08x : address = %08x) in Add Code (%s)", + addr.size, addr.gcaddr, s_current_code->name.c_str()); + return false; + } + return true; } static bool Subtype_MasterCodeAndWriteToCCXXXXXX(const ARAddr& addr, const u32 data) { - // code not yet implemented - TODO - // u32 new_addr = (addr & 0x01FFFFFF) | 0x80000000; - // u8 mcode_type = (data & 0xFF0000) >> 16; - // u8 mcode_count = (data & 0xFF00) >> 8; - // u8 mcode_number = data & 0xFF; - PanicAlertT("Action Replay Error: Master Code and Write To CCXXXXXX not implemented (%s)\n" - "Master codes are not needed. Do not use master codes.", - s_current_code->name.c_str()); - return false; + // code not yet implemented - TODO + // u32 new_addr = (addr & 0x01FFFFFF) | 0x80000000; + // u8 mcode_type = (data & 0xFF0000) >> 16; + // u8 mcode_count = (data & 0xFF00) >> 8; + // u8 mcode_number = data & 0xFF; + PanicAlertT("Action Replay Error: Master Code and Write To CCXXXXXX not implemented (%s)\n" + "Master codes are not needed. Do not use master codes.", + s_current_code->name.c_str()); + return false; } // This needs more testing static bool ZeroCode_FillAndSlide(const u32 val_last, const ARAddr& addr, const u32 data) { - const u32 new_addr = ARAddr(val_last).GCAddress(); - const u8 size = ARAddr(val_last).size; + const u32 new_addr = ARAddr(val_last).GCAddress(); + const u8 size = ARAddr(val_last).size; - const s16 addr_incr = static_cast(data & 0xFFFF); - const s8 val_incr = static_cast(data >> 24); - const u8 write_num = static_cast((data & 0xFF0000) >> 16); + const s16 addr_incr = static_cast(data & 0xFFFF); + const s8 val_incr = static_cast(data >> 24); + const u8 write_num = static_cast((data & 0xFF0000) >> 16); - u32 val = addr; - u32 curr_addr = new_addr; + u32 val = addr; + u32 curr_addr = new_addr; - LogInfo("Current Hardware Address: %08x", new_addr); - LogInfo("Size: %08x", addr.size); - LogInfo("Write Num: %08x", write_num); - LogInfo("Address Increment: %i", addr_incr); - LogInfo("Value Increment: %i", val_incr); + LogInfo("Current Hardware Address: %08x", new_addr); + LogInfo("Size: %08x", addr.size); + LogInfo("Write Num: %08x", write_num); + LogInfo("Address Increment: %i", addr_incr); + LogInfo("Value Increment: %i", val_incr); - switch (size) - { - case DATATYPE_8BIT: - LogInfo("8-bit Write"); - LogInfo("--------"); - for (int i = 0; i < write_num; ++i) - { - PowerPC::HostWrite_U8(val & 0xFF, curr_addr); - curr_addr += addr_incr; - val += val_incr; - LogInfo("Write %08x to address %08x", val & 0xFF, curr_addr); + switch (size) + { + case DATATYPE_8BIT: + LogInfo("8-bit Write"); + LogInfo("--------"); + for (int i = 0; i < write_num; ++i) + { + PowerPC::HostWrite_U8(val & 0xFF, curr_addr); + curr_addr += addr_incr; + val += val_incr; + LogInfo("Write %08x to address %08x", val & 0xFF, curr_addr); - LogInfo("Value Update: %08x", val); - LogInfo("Current Hardware Address Update: %08x", curr_addr); - } - LogInfo("--------"); - break; + LogInfo("Value Update: %08x", val); + LogInfo("Current Hardware Address Update: %08x", curr_addr); + } + LogInfo("--------"); + break; - case DATATYPE_16BIT: - LogInfo("16-bit Write"); - LogInfo("--------"); - for (int i=0; i < write_num; ++i) - { - PowerPC::HostWrite_U16(val & 0xFFFF, curr_addr); - LogInfo("Write %08x to address %08x", val & 0xFFFF, curr_addr); - curr_addr += addr_incr * 2; - val += val_incr; - LogInfo("Value Update: %08x", val); - LogInfo("Current Hardware Address Update: %08x", curr_addr); - } - LogInfo("--------"); - break; + case DATATYPE_16BIT: + LogInfo("16-bit Write"); + LogInfo("--------"); + for (int i = 0; i < write_num; ++i) + { + PowerPC::HostWrite_U16(val & 0xFFFF, curr_addr); + LogInfo("Write %08x to address %08x", val & 0xFFFF, curr_addr); + curr_addr += addr_incr * 2; + val += val_incr; + LogInfo("Value Update: %08x", val); + LogInfo("Current Hardware Address Update: %08x", curr_addr); + } + LogInfo("--------"); + break; - case DATATYPE_32BIT: - LogInfo("32-bit Write"); - LogInfo("--------"); - for (int i = 0; i < write_num; ++i) - { - PowerPC::HostWrite_U32(val, curr_addr); - LogInfo("Write %08x to address %08x", val, curr_addr); - curr_addr += addr_incr * 4; - val += val_incr; - LogInfo("Value Update: %08x", val); - LogInfo("Current Hardware Address Update: %08x", curr_addr); - } - LogInfo("--------"); - break; + case DATATYPE_32BIT: + LogInfo("32-bit Write"); + LogInfo("--------"); + for (int i = 0; i < write_num; ++i) + { + PowerPC::HostWrite_U32(val, curr_addr); + LogInfo("Write %08x to address %08x", val, curr_addr); + curr_addr += addr_incr * 4; + val += val_incr; + LogInfo("Value Update: %08x", val); + LogInfo("Current Hardware Address Update: %08x", curr_addr); + } + LogInfo("--------"); + break; - default: - LogInfo("Bad Size"); - PanicAlertT("Action Replay Error: Invalid size (%08x : address = %08x) in Fill and Slide (%s)", - size, new_addr, s_current_code->name.c_str()); - return false; - } - return true; + default: + LogInfo("Bad Size"); + PanicAlertT("Action Replay Error: Invalid size (%08x : address = %08x) in Fill and Slide (%s)", + size, new_addr, s_current_code->name.c_str()); + return false; + } + return true; } // Looks like this is new?? - untested static bool ZeroCode_MemoryCopy(const u32 val_last, const ARAddr& addr, const u32 data) { - const u32 addr_dest = val_last | 0x06000000; - const u32 addr_src = addr.GCAddress(); + const u32 addr_dest = val_last | 0x06000000; + const u32 addr_src = addr.GCAddress(); - const u8 num_bytes = data & 0x7FFF; + const u8 num_bytes = data & 0x7FFF; - LogInfo("Dest Address: %08x", addr_dest); - LogInfo("Src Address: %08x", addr_src); - LogInfo("Size: %08x", num_bytes); + LogInfo("Dest Address: %08x", addr_dest); + LogInfo("Src Address: %08x", addr_src); + LogInfo("Size: %08x", num_bytes); - if ((data & ~0x7FFF) == 0x0000) - { - if ((data >> 24) != 0x0) - { // Memory Copy With Pointers Support - LogInfo("Memory Copy With Pointers Support"); - LogInfo("--------"); - for (int i = 0; i < 138; ++i) - { - PowerPC::HostWrite_U8(PowerPC::HostRead_U8(addr_src + i), addr_dest + i); - LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U8(addr_src + i), addr_dest + i); - } - LogInfo("--------"); - } - else - { // Memory Copy Without Pointer Support - LogInfo("Memory Copy Without Pointers Support"); - LogInfo("--------"); - for (int i=0; i < num_bytes; ++i) - { - PowerPC::HostWrite_U8(PowerPC::HostRead_U8(addr_src + i), addr_dest + i); - LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U8(addr_src + i), addr_dest + i); - } - LogInfo("--------"); - return true; - } - } - else - { - LogInfo("Bad Value"); - PanicAlertT("Action Replay Error: Invalid value (%08x) in Memory Copy (%s)", - (data & ~0x7FFF), s_current_code->name.c_str()); - return false; - } - return true; + if ((data & ~0x7FFF) == 0x0000) + { + if ((data >> 24) != 0x0) + { // Memory Copy With Pointers Support + LogInfo("Memory Copy With Pointers Support"); + LogInfo("--------"); + for (int i = 0; i < 138; ++i) + { + PowerPC::HostWrite_U8(PowerPC::HostRead_U8(addr_src + i), addr_dest + i); + LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U8(addr_src + i), addr_dest + i); + } + LogInfo("--------"); + } + else + { // Memory Copy Without Pointer Support + LogInfo("Memory Copy Without Pointers Support"); + LogInfo("--------"); + for (int i = 0; i < num_bytes; ++i) + { + PowerPC::HostWrite_U8(PowerPC::HostRead_U8(addr_src + i), addr_dest + i); + LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U8(addr_src + i), addr_dest + i); + } + LogInfo("--------"); + return true; + } + } + else + { + LogInfo("Bad Value"); + PanicAlertT("Action Replay Error: Invalid value (%08x) in Memory Copy (%s)", (data & ~0x7FFF), + s_current_code->name.c_str()); + return false; + } + return true; } static bool NormalCode(const ARAddr& addr, const u32 data) { - switch (addr.subtype) - { - case SUB_RAM_WRITE: // Ram write (and fill) - LogInfo("Doing Ram Write And Fill"); - if (!Subtype_RamWriteAndFill(addr, data)) - return false; - break; + switch (addr.subtype) + { + case SUB_RAM_WRITE: // Ram write (and fill) + LogInfo("Doing Ram Write And Fill"); + if (!Subtype_RamWriteAndFill(addr, data)) + return false; + break; - case SUB_WRITE_POINTER: // Write to pointer - LogInfo("Doing Write To Pointer"); - if (!Subtype_WriteToPointer(addr, data)) - return false; - break; + case SUB_WRITE_POINTER: // Write to pointer + LogInfo("Doing Write To Pointer"); + if (!Subtype_WriteToPointer(addr, data)) + return false; + break; - case SUB_ADD_CODE: // Increment Value - LogInfo("Doing Add Code"); - if (!Subtype_AddCode(addr, data)) - return false; - break; + case SUB_ADD_CODE: // Increment Value + LogInfo("Doing Add Code"); + if (!Subtype_AddCode(addr, data)) + return false; + break; - case SUB_MASTER_CODE: // Master Code & Write to CCXXXXXX - LogInfo("Doing Master Code And Write to CCXXXXXX (ncode not supported)"); - if (!Subtype_MasterCodeAndWriteToCCXXXXXX(addr, data)) - return false; - break; + case SUB_MASTER_CODE: // Master Code & Write to CCXXXXXX + LogInfo("Doing Master Code And Write to CCXXXXXX (ncode not supported)"); + if (!Subtype_MasterCodeAndWriteToCCXXXXXX(addr, data)) + return false; + break; - default: - LogInfo("Bad Subtype"); - PanicAlertT("Action Replay: Normal Code 0: Invalid Subtype %08x (%s)", addr.subtype, - s_current_code->name.c_str()); - return false; - } + default: + LogInfo("Bad Subtype"); + PanicAlertT("Action Replay: Normal Code 0: Invalid Subtype %08x (%s)", addr.subtype, + s_current_code->name.c_str()); + return false; + } - return true; + return true; } static bool CompareValues(const u32 val1, const u32 val2, const int type) { - switch (type) - { - case CONDTIONAL_EQUAL: - LogInfo("Type 1: If Equal"); - return val1 == val2; + switch (type) + { + case CONDTIONAL_EQUAL: + LogInfo("Type 1: If Equal"); + return val1 == val2; - case CONDTIONAL_NOT_EQUAL: - LogInfo("Type 2: If Not Equal"); - return val1 != val2; + case CONDTIONAL_NOT_EQUAL: + LogInfo("Type 2: If Not Equal"); + return val1 != val2; - case CONDTIONAL_LESS_THAN_SIGNED: - LogInfo("Type 3: If Less Than (Signed)"); - return static_cast(val1) < static_cast(val2); + case CONDTIONAL_LESS_THAN_SIGNED: + LogInfo("Type 3: If Less Than (Signed)"); + return static_cast(val1) < static_cast(val2); - case CONDTIONAL_GREATER_THAN_SIGNED: - LogInfo("Type 4: If Greater Than (Signed)"); - return static_cast(val1) > static_cast(val2); + case CONDTIONAL_GREATER_THAN_SIGNED: + LogInfo("Type 4: If Greater Than (Signed)"); + return static_cast(val1) > static_cast(val2); - case CONDTIONAL_LESS_THAN_UNSIGNED: - LogInfo("Type 5: If Less Than (Unsigned)"); - return val1 < val2; + case CONDTIONAL_LESS_THAN_UNSIGNED: + LogInfo("Type 5: If Less Than (Unsigned)"); + return val1 < val2; - case CONDTIONAL_GREATER_THAN_UNSIGNED: - LogInfo("Type 6: If Greater Than (Unsigned)"); - return val1 > val2; + case CONDTIONAL_GREATER_THAN_UNSIGNED: + LogInfo("Type 6: If Greater Than (Unsigned)"); + return val1 > val2; - case CONDTIONAL_AND: - LogInfo("Type 7: If And"); - return !!(val1 & val2); // bitwise AND + case CONDTIONAL_AND: + LogInfo("Type 7: If And"); + return !!(val1 & val2); // bitwise AND - default: LogInfo("Unknown Compare type"); - PanicAlertT("Action Replay: Invalid Normal Code Type %08x (%s)", - type, s_current_code->name.c_str()); - return false; - } + default: + LogInfo("Unknown Compare type"); + PanicAlertT("Action Replay: Invalid Normal Code Type %08x (%s)", type, + s_current_code->name.c_str()); + return false; + } } static bool ConditionalCode(const ARAddr& addr, const u32 data, int* const pSkipCount) { - const u32 new_addr = addr.GCAddress(); + const u32 new_addr = addr.GCAddress(); - LogInfo("Size: %08x", addr.size); - LogInfo("Hardware Address: %08x", new_addr); + LogInfo("Size: %08x", addr.size); + LogInfo("Hardware Address: %08x", new_addr); - bool result = true; + bool result = true; - switch (addr.size) - { - case DATATYPE_8BIT: - result = CompareValues(PowerPC::HostRead_U8(new_addr), (data & 0xFF), addr.type); - break; + switch (addr.size) + { + case DATATYPE_8BIT: + result = CompareValues(PowerPC::HostRead_U8(new_addr), (data & 0xFF), addr.type); + break; - case DATATYPE_16BIT: - result = CompareValues(PowerPC::HostRead_U16(new_addr), (data & 0xFFFF), addr.type); - break; + case DATATYPE_16BIT: + result = CompareValues(PowerPC::HostRead_U16(new_addr), (data & 0xFFFF), addr.type); + break; - case DATATYPE_32BIT_FLOAT: - case DATATYPE_32BIT: - result = CompareValues(PowerPC::HostRead_U32(new_addr), data, addr.type); - break; + case DATATYPE_32BIT_FLOAT: + case DATATYPE_32BIT: + result = CompareValues(PowerPC::HostRead_U32(new_addr), data, addr.type); + break; - default: - LogInfo("Bad Size"); - PanicAlertT("Action Replay: Conditional Code: Invalid Size %08x (%s)", addr.size, - s_current_code->name.c_str()); - return false; - } + default: + LogInfo("Bad Size"); + PanicAlertT("Action Replay: Conditional Code: Invalid Size %08x (%s)", addr.size, + s_current_code->name.c_str()); + return false; + } - // if the comparison failed we need to skip some lines - if (false == result) - { - switch (addr.subtype) - { - case CONDTIONAL_ONE_LINE: - case CONDTIONAL_TWO_LINES: - *pSkipCount = addr.subtype + 1; // Skip 1 or 2 lines - break; + // if the comparison failed we need to skip some lines + if (false == result) + { + switch (addr.subtype) + { + case CONDTIONAL_ONE_LINE: + case CONDTIONAL_TWO_LINES: + *pSkipCount = addr.subtype + 1; // Skip 1 or 2 lines + break; - // Skip all lines, - // Skip lines until a "00000000 40000000" line is reached - case CONDTIONAL_ALL_LINES: - case CONDTIONAL_ALL_LINES_UNTIL: - *pSkipCount = -static_cast(addr.subtype); - break; + // Skip all lines, + // Skip lines until a "00000000 40000000" line is reached + case CONDTIONAL_ALL_LINES: + case CONDTIONAL_ALL_LINES_UNTIL: + *pSkipCount = -static_cast(addr.subtype); + break; - default: - LogInfo("Bad Subtype"); - PanicAlertT("Action Replay: Normal Code %i: Invalid subtype %08x (%s)", - 1, addr.subtype, s_current_code->name.c_str()); - return false; - } - } + default: + LogInfo("Bad Subtype"); + PanicAlertT("Action Replay: Normal Code %i: Invalid subtype %08x (%s)", 1, addr.subtype, + s_current_code->name.c_str()); + return false; + } + } - return true; + return true; } // NOTE: Lock needed to give mutual exclusion to s_current_code and LogInfo static bool RunCodeLocked(const ARCode& arcode) { - // The mechanism is different than what the real AR uses, so there may be compatibility problems. + // The mechanism is different than what the real AR uses, so there may be compatibility problems. - bool do_fill_and_slide = false; - bool do_memory_copy = false; + bool do_fill_and_slide = false; + bool do_memory_copy = false; - // used for conditional codes - int skip_count = 0; + // used for conditional codes + int skip_count = 0; - u32 val_last = 0; + u32 val_last = 0; - s_current_code = &arcode; + s_current_code = &arcode; - LogInfo("Code Name: %s", arcode.name.c_str()); - LogInfo("Number of codes: %zu", arcode.ops.size()); + LogInfo("Code Name: %s", arcode.name.c_str()); + LogInfo("Number of codes: %zu", arcode.ops.size()); - for (const AREntry& entry : arcode.ops) - { - const ARAddr addr(entry.cmd_addr); - const u32 data = entry.value; + for (const AREntry& entry : arcode.ops) + { + const ARAddr addr(entry.cmd_addr); + const u32 data = entry.value; - // after a conditional code, skip lines if needed - if (skip_count) - { - if (skip_count > 0) // skip x lines - { - LogInfo("Line skipped"); - --skip_count; - } - else if (-CONDTIONAL_ALL_LINES == skip_count) - { - // skip all lines - LogInfo("All Lines skipped"); - return true; // don't need to iterate through the rest of the ops - } - else if (-CONDTIONAL_ALL_LINES_UNTIL == skip_count) - { - // skip until a "00000000 40000000" line is reached - LogInfo("Line skipped"); - if (addr == 0 && 0x40000000 == data) // check for an endif line - skip_count = 0; - } + // after a conditional code, skip lines if needed + if (skip_count) + { + if (skip_count > 0) // skip x lines + { + LogInfo("Line skipped"); + --skip_count; + } + else if (-CONDTIONAL_ALL_LINES == skip_count) + { + // skip all lines + LogInfo("All Lines skipped"); + return true; // don't need to iterate through the rest of the ops + } + else if (-CONDTIONAL_ALL_LINES_UNTIL == skip_count) + { + // skip until a "00000000 40000000" line is reached + LogInfo("Line skipped"); + if (addr == 0 && 0x40000000 == data) // check for an endif line + skip_count = 0; + } - continue; - } + continue; + } - LogInfo("--- Running Code: %08x %08x ---", addr.address, data); - //LogInfo("Command: %08x", cmd); + LogInfo("--- Running Code: %08x %08x ---", addr.address, data); + // LogInfo("Command: %08x", cmd); - // Do Fill & Slide - if (do_fill_and_slide) - { - do_fill_and_slide = false; - LogInfo("Doing Fill And Slide"); - if (false == ZeroCode_FillAndSlide(val_last, addr, data)) - return false; - continue; - } + // Do Fill & Slide + if (do_fill_and_slide) + { + do_fill_and_slide = false; + LogInfo("Doing Fill And Slide"); + if (false == ZeroCode_FillAndSlide(val_last, addr, data)) + return false; + continue; + } - // Memory Copy - if (do_memory_copy) - { - do_memory_copy = false; - LogInfo("Doing Memory Copy"); - if (false == ZeroCode_MemoryCopy(val_last, addr, data)) - return false; - continue; - } + // Memory Copy + if (do_memory_copy) + { + do_memory_copy = false; + LogInfo("Doing Memory Copy"); + if (false == ZeroCode_MemoryCopy(val_last, addr, data)) + return false; + continue; + } - // ActionReplay program self modification codes - if (addr >= 0x00002000 && addr < 0x00003000) - { - LogInfo("This action replay simulator does not support codes that modify Action Replay itself."); - PanicAlertT("This action replay simulator does not support codes that modify Action Replay itself."); - return false; - } + // ActionReplay program self modification codes + if (addr >= 0x00002000 && addr < 0x00003000) + { + LogInfo( + "This action replay simulator does not support codes that modify Action Replay itself."); + PanicAlertT( + "This action replay simulator does not support codes that modify Action Replay itself."); + return false; + } - // skip these weird init lines - // TODO: Where are the "weird init lines"? - //if (iter == code.ops.begin() && cmd == 1) - //continue; + // skip these weird init lines + // TODO: Where are the "weird init lines"? + // if (iter == code.ops.begin() && cmd == 1) + // continue; - // Zero codes - if (0x0 == addr) // Check if the code is a zero code - { - const u8 zcode = data >> 29; + // Zero codes + if (0x0 == addr) // Check if the code is a zero code + { + const u8 zcode = data >> 29; - LogInfo("Doing Zero Code %08x", zcode); + LogInfo("Doing Zero Code %08x", zcode); - switch (zcode) - { - case ZCODE_END: // END OF CODES - LogInfo("ZCode: End Of Codes"); - return true; + switch (zcode) + { + case ZCODE_END: // END OF CODES + LogInfo("ZCode: End Of Codes"); + return true; - // TODO: the "00000000 40000000"(end if) codes fall into this case, I don't think that is correct - case ZCODE_NORM: // Normal execution of codes - // Todo: Set register 1BB4 to 0 - LogInfo("ZCode: Normal execution of codes, set register 1BB4 to 0 (zcode not supported)"); - break; + // TODO: the "00000000 40000000"(end if) codes fall into this case, I don't think that is + // correct + case ZCODE_NORM: // Normal execution of codes + // Todo: Set register 1BB4 to 0 + LogInfo("ZCode: Normal execution of codes, set register 1BB4 to 0 (zcode not supported)"); + break; - case ZCODE_ROW: // Executes all codes in the same row - // Todo: Set register 1BB4 to 1 - LogInfo("ZCode: Executes all codes in the same row, Set register 1BB4 to 1 (zcode not supported)"); - PanicAlertT("Zero 3 code not supported"); - return false; + case ZCODE_ROW: // Executes all codes in the same row + // Todo: Set register 1BB4 to 1 + LogInfo("ZCode: Executes all codes in the same row, Set register 1BB4 to 1 (zcode not " + "supported)"); + PanicAlertT("Zero 3 code not supported"); + return false; - case ZCODE_04: // Fill & Slide or Memory Copy - if (0x3 == ((data >> 25) & 0x03)) - { - LogInfo("ZCode: Memory Copy"); - do_memory_copy = true; - val_last = data; - } - else - { - LogInfo("ZCode: Fill And Slide"); - do_fill_and_slide = true; - val_last = data; - } - break; + case ZCODE_04: // Fill & Slide or Memory Copy + if (0x3 == ((data >> 25) & 0x03)) + { + LogInfo("ZCode: Memory Copy"); + do_memory_copy = true; + val_last = data; + } + else + { + LogInfo("ZCode: Fill And Slide"); + do_fill_and_slide = true; + val_last = data; + } + break; - default: - LogInfo("ZCode: Unknown"); - PanicAlertT("Zero code unknown to Dolphin: %08x", zcode); - return false; - } + default: + LogInfo("ZCode: Unknown"); + PanicAlertT("Zero code unknown to Dolphin: %08x", zcode); + return false; + } - // done handling zero codes - continue; - } + // done handling zero codes + continue; + } - // Normal codes - LogInfo("Doing Normal Code %08x", addr.type); - LogInfo("Subtype: %08x", addr.subtype); + // Normal codes + LogInfo("Doing Normal Code %08x", addr.type); + LogInfo("Subtype: %08x", addr.subtype); - switch (addr.type) - { - case 0x00: - if (false == NormalCode(addr, data)) - return false; - break; + switch (addr.type) + { + case 0x00: + if (false == NormalCode(addr, data)) + return false; + break; - default: - LogInfo("This Normal Code is a Conditional Code"); - if (false == ConditionalCode(addr, data, &skip_count)) - return false; - break; - } - } + default: + LogInfo("This Normal Code is a Conditional Code"); + if (false == ConditionalCode(addr, data, &skip_count)) + return false; + break; + } + } - return true; + return true; } void RunAllActive() { - if (!SConfig::GetInstance().bEnableCheats) - return; + if (!SConfig::GetInstance().bEnableCheats) + return; - // If the mutex is idle then acquiring it should be cheap, fast mutexes - // are only atomic ops unless contested. It should be rare for this to - // be contested. - std::lock_guard guard(s_lock); - s_active_codes.erase(std::remove_if(s_active_codes.begin(), s_active_codes.end(), [](const ARCode& code) - { - bool success = RunCodeLocked(code); - LogInfo("\n"); - return !success; - }), s_active_codes.end()); - s_disable_logging = true; + // If the mutex is idle then acquiring it should be cheap, fast mutexes + // are only atomic ops unless contested. It should be rare for this to + // be contested. + std::lock_guard guard(s_lock); + s_active_codes.erase(std::remove_if(s_active_codes.begin(), s_active_codes.end(), + [](const ARCode& code) { + bool success = RunCodeLocked(code); + LogInfo("\n"); + return !success; + }), + s_active_codes.end()); + s_disable_logging = true; } -} // namespace ActionReplay +} // namespace ActionReplay diff --git a/Source/Core/Core/ActionReplay.h b/Source/Core/Core/ActionReplay.h index 49f4746181..d6f617cd12 100644 --- a/Source/Core/Core/ActionReplay.h +++ b/Source/Core/Core/ActionReplay.h @@ -12,21 +12,20 @@ class IniFile; namespace ActionReplay { - struct AREntry { - AREntry() {} - AREntry(u32 _addr, u32 _value) : cmd_addr(_addr), value(_value) {} - u32 cmd_addr; - u32 value; + AREntry() {} + AREntry(u32 _addr, u32 _value) : cmd_addr(_addr), value(_value) {} + u32 cmd_addr; + u32 value; }; struct ARCode { - std::string name; - std::vector ops; - bool active; - bool user_defined; + std::string name; + std::vector ops; + bool active; + bool user_defined; }; void RunAllActive(); diff --git a/Source/Core/Core/Analytics.cpp b/Source/Core/Core/Analytics.cpp index 7bbe40303a..0c0bb813b1 100644 --- a/Source/Core/Core/Analytics.cpp +++ b/Source/Core/Core/Analytics.cpp @@ -1,9 +1,9 @@ #include +#include #include #include #include #include -#include #if defined(_WIN32) #include @@ -12,15 +12,15 @@ #endif #include "Common/Analytics.h" +#include "Common/CPUDetect.h" #include "Common/Common.h" #include "Common/CommonTypes.h" -#include "Common/CPUDetect.h" #include "Common/StringUtil.h" #include "Core/Analytics.h" #include "Core/ConfigManager.h" +#include "Core/HW/GCPad.h" #include "Core/Movie.h" #include "Core/NetPlayProto.h" -#include "Core/HW/GCPad.h" #include "InputCommon/ControllerEmu.h" #include "InputCommon/GCAdapter.h" #include "InputCommon/InputConfig.h" @@ -37,220 +37,222 @@ std::shared_ptr DolphinAnalytics::s_instance; DolphinAnalytics::DolphinAnalytics() { - ReloadConfig(); - MakeBaseBuilder(); + ReloadConfig(); + MakeBaseBuilder(); } std::shared_ptr DolphinAnalytics::Instance() { - std::lock_guard lk(s_instance_mutex); - if (!s_instance) - { - s_instance.reset(new DolphinAnalytics()); - } - return s_instance; + std::lock_guard lk(s_instance_mutex); + if (!s_instance) + { + s_instance.reset(new DolphinAnalytics()); + } + return s_instance; } void DolphinAnalytics::ReloadConfig() { - std::lock_guard lk(m_reporter_mutex); + std::lock_guard lk(m_reporter_mutex); - // Install the HTTP backend if analytics support is enabled. - std::unique_ptr new_backend; - if (SConfig::GetInstance().m_analytics_enabled) - { - new_backend = std::make_unique(ANALYTICS_ENDPOINT); - } - m_reporter.SetBackend(std::move(new_backend)); + // Install the HTTP backend if analytics support is enabled. + std::unique_ptr new_backend; + if (SConfig::GetInstance().m_analytics_enabled) + { + new_backend = std::make_unique(ANALYTICS_ENDPOINT); + } + m_reporter.SetBackend(std::move(new_backend)); - // Load the unique ID or generate it if needed. - m_unique_id = SConfig::GetInstance().m_analytics_id; - if (m_unique_id.empty()) - { - GenerateNewIdentity(); - } + // Load the unique ID or generate it if needed. + m_unique_id = SConfig::GetInstance().m_analytics_id; + if (m_unique_id.empty()) + { + GenerateNewIdentity(); + } } void DolphinAnalytics::GenerateNewIdentity() { - std::random_device rd; - u64 id_high = (static_cast(rd()) << 32) | rd(); - u64 id_low = (static_cast(rd()) << 32) | rd(); - m_unique_id = StringFromFormat("%016" PRIx64 "%016" PRIx64, id_high, id_low); + std::random_device rd; + u64 id_high = (static_cast(rd()) << 32) | rd(); + u64 id_low = (static_cast(rd()) << 32) | rd(); + m_unique_id = StringFromFormat("%016" PRIx64 "%016" PRIx64, id_high, id_low); - // Save the new id in the configuration. - SConfig::GetInstance().m_analytics_id = m_unique_id; - SConfig::GetInstance().SaveSettings(); + // Save the new id in the configuration. + SConfig::GetInstance().m_analytics_id = m_unique_id; + SConfig::GetInstance().SaveSettings(); } std::string DolphinAnalytics::MakeUniqueId(const std::string& data) { - u8 digest[20]; - std::string input = m_unique_id + data; - mbedtls_sha1(reinterpret_cast(input.c_str()), input.size(), - digest); + u8 digest[20]; + std::string input = m_unique_id + data; + mbedtls_sha1(reinterpret_cast(input.c_str()), input.size(), digest); - // Convert to hex string and truncate to 64 bits. - std::string out; - for (int i = 0; i < 8; ++i) - { - out += StringFromFormat("%02hhx", digest[i]); - } - return out; + // Convert to hex string and truncate to 64 bits. + std::string out; + for (int i = 0; i < 8; ++i) + { + out += StringFromFormat("%02hhx", digest[i]); + } + return out; } void DolphinAnalytics::ReportDolphinStart(const std::string& ui_type) { - Common::AnalyticsReportBuilder builder(m_base_builder); - builder.AddData("type", "dolphin-start"); - builder.AddData("ui-type", ui_type); - builder.AddData("id", MakeUniqueId("dolphin-start")); - Send(builder); + Common::AnalyticsReportBuilder builder(m_base_builder); + builder.AddData("type", "dolphin-start"); + builder.AddData("ui-type", ui_type); + builder.AddData("id", MakeUniqueId("dolphin-start")); + Send(builder); } void DolphinAnalytics::ReportGameStart() { - MakePerGameBuilder(); + MakePerGameBuilder(); - Common::AnalyticsReportBuilder builder(m_per_game_builder); - builder.AddData("type", "game-start"); - Send(builder); + Common::AnalyticsReportBuilder builder(m_per_game_builder); + builder.AddData("type", "game-start"); + Send(builder); } void DolphinAnalytics::MakeBaseBuilder() { - Common::AnalyticsReportBuilder builder; + Common::AnalyticsReportBuilder builder; - // Version information. - builder.AddData("version-desc", scm_desc_str); - builder.AddData("version-hash", scm_rev_git_str); - builder.AddData("version-branch", scm_branch_str); - builder.AddData("version-dist", scm_distributor_str); + // Version information. + builder.AddData("version-desc", scm_desc_str); + builder.AddData("version-hash", scm_rev_git_str); + builder.AddData("version-branch", scm_branch_str); + builder.AddData("version-dist", scm_distributor_str); - // CPU information. - builder.AddData("cpu-summary", cpu_info.Summarize()); + // CPU information. + builder.AddData("cpu-summary", cpu_info.Summarize()); - // OS information. +// OS information. #if defined(_WIN32) - builder.AddData("os-type", "windows"); + builder.AddData("os-type", "windows"); - // Windows 8 removes support for GetVersionEx and such. Stupid. - DWORD (WINAPI *RtlGetVersion)(LPOSVERSIONINFOEXW); - *(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandle(TEXT("ntdll")), "RtlGetVersion"); + // Windows 8 removes support for GetVersionEx and such. Stupid. + DWORD(WINAPI * RtlGetVersion)(LPOSVERSIONINFOEXW); + *(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandle(TEXT("ntdll")), "RtlGetVersion"); - OSVERSIONINFOEXW winver; - winver.dwOSVersionInfoSize = sizeof(winver); - if (RtlGetVersion != nullptr) - { - RtlGetVersion(&winver); - builder.AddData("win-ver-major", static_cast(winver.dwMajorVersion)); - builder.AddData("win-ver-minor", static_cast(winver.dwMinorVersion)); - builder.AddData("win-ver-build", static_cast(winver.dwBuildNumber)); - builder.AddData("win-ver-spmajor", static_cast(winver.wServicePackMajor)); - builder.AddData("win-ver-spminor", static_cast(winver.wServicePackMinor)); - } + OSVERSIONINFOEXW winver; + winver.dwOSVersionInfoSize = sizeof(winver); + if (RtlGetVersion != nullptr) + { + RtlGetVersion(&winver); + builder.AddData("win-ver-major", static_cast(winver.dwMajorVersion)); + builder.AddData("win-ver-minor", static_cast(winver.dwMinorVersion)); + builder.AddData("win-ver-build", static_cast(winver.dwBuildNumber)); + builder.AddData("win-ver-spmajor", static_cast(winver.wServicePackMajor)); + builder.AddData("win-ver-spminor", static_cast(winver.wServicePackMinor)); + } #elif defined(ANDROID) - builder.AddData("os-type", "android"); + builder.AddData("os-type", "android"); #elif defined(__APPLE__) - builder.AddData("os-type", "osx"); + builder.AddData("os-type", "osx"); - SInt32 osxmajor, osxminor, osxbugfix; - Gestalt(gestaltSystemVersionMajor, &osxmajor); - Gestalt(gestaltSystemVersionMinor, &osxminor); - Gestalt(gestaltSystemVersionBugFix, &osxbugfix); + SInt32 osxmajor, osxminor, osxbugfix; + Gestalt(gestaltSystemVersionMajor, &osxmajor); + Gestalt(gestaltSystemVersionMinor, &osxminor); + Gestalt(gestaltSystemVersionBugFix, &osxbugfix); - builder.AddData("osx-ver-major", osxmajor); - builder.AddData("osx-ver-minor", osxminor); - builder.AddData("osx-ver-bugfix", osxbugfix); + builder.AddData("osx-ver-major", osxmajor); + builder.AddData("osx-ver-minor", osxminor); + builder.AddData("osx-ver-bugfix", osxbugfix); #elif defined(__linux__) - builder.AddData("os-type", "linux"); + builder.AddData("os-type", "linux"); #elif defined(__FreeBSD__) - builder.AddData("os-type", "freebsd"); + builder.AddData("os-type", "freebsd"); #else - builder.AddData("os-type", "unknown"); + builder.AddData("os-type", "unknown"); #endif - m_base_builder = builder; + m_base_builder = builder; } void DolphinAnalytics::MakePerGameBuilder() { - Common::AnalyticsReportBuilder builder(m_base_builder); + Common::AnalyticsReportBuilder builder(m_base_builder); - // Gameid. - builder.AddData("gameid", SConfig::GetInstance().GetUniqueID()); + // Gameid. + builder.AddData("gameid", SConfig::GetInstance().GetUniqueID()); - // Unique id bound to the gameid. - builder.AddData("id", MakeUniqueId(SConfig::GetInstance().GetUniqueID())); + // Unique id bound to the gameid. + builder.AddData("id", MakeUniqueId(SConfig::GetInstance().GetUniqueID())); - // Configuration. - builder.AddData("cfg-dsp-hle", SConfig::GetInstance().bDSPHLE); - builder.AddData("cfg-dsp-jit", SConfig::GetInstance().m_DSPEnableJIT); - builder.AddData("cfg-dsp-thread", SConfig::GetInstance().bDSPThread); - builder.AddData("cfg-cpu-thread", SConfig::GetInstance().bCPUThread); - builder.AddData("cfg-idle-skip", SConfig::GetInstance().bSkipIdle); - builder.AddData("cfg-fastmem", SConfig::GetInstance().bFastmem); - builder.AddData("cfg-syncgpu", SConfig::GetInstance().bSyncGPU); - builder.AddData("cfg-audio-backend", SConfig::GetInstance().sBackend); - builder.AddData("cfg-oc-enable", SConfig::GetInstance().m_OCEnable); - builder.AddData("cfg-oc-factor", SConfig::GetInstance().m_OCFactor); - builder.AddData("cfg-render-to-main", SConfig::GetInstance().bRenderToMain); - if (g_video_backend) - { - builder.AddData("cfg-video-backend", g_video_backend->GetName()); - } + // Configuration. + builder.AddData("cfg-dsp-hle", SConfig::GetInstance().bDSPHLE); + builder.AddData("cfg-dsp-jit", SConfig::GetInstance().m_DSPEnableJIT); + builder.AddData("cfg-dsp-thread", SConfig::GetInstance().bDSPThread); + builder.AddData("cfg-cpu-thread", SConfig::GetInstance().bCPUThread); + builder.AddData("cfg-idle-skip", SConfig::GetInstance().bSkipIdle); + builder.AddData("cfg-fastmem", SConfig::GetInstance().bFastmem); + builder.AddData("cfg-syncgpu", SConfig::GetInstance().bSyncGPU); + builder.AddData("cfg-audio-backend", SConfig::GetInstance().sBackend); + builder.AddData("cfg-oc-enable", SConfig::GetInstance().m_OCEnable); + builder.AddData("cfg-oc-factor", SConfig::GetInstance().m_OCFactor); + builder.AddData("cfg-render-to-main", SConfig::GetInstance().bRenderToMain); + if (g_video_backend) + { + builder.AddData("cfg-video-backend", g_video_backend->GetName()); + } - // Video configuration. - builder.AddData("cfg-gfx-multisamples", g_Config.iMultisamples); - builder.AddData("cfg-gfx-ssaa", g_Config.bSSAA); - builder.AddData("cfg-gfx-anisotropy", g_Config.iMaxAnisotropy); - builder.AddData("cfg-gfx-realxfb", g_Config.RealXFBEnabled()); - builder.AddData("cfg-gfx-virtualxfb", g_Config.VirtualXFBEnabled()); - builder.AddData("cfg-gfx-vsync", g_Config.bVSync); - builder.AddData("cfg-gfx-fullscreen", g_Config.bFullscreen); - builder.AddData("cfg-gfx-exclusive-mode", g_Config.bExclusiveMode); - builder.AddData("cfg-gfx-aspect-ratio", g_Config.iAspectRatio); - builder.AddData("cfg-gfx-efb-access", g_Config.bEFBAccessEnable); - builder.AddData("cfg-gfx-efb-scale", g_Config.iEFBScale); - builder.AddData("cfg-gfx-efb-copy-format-changes", g_Config.bEFBEmulateFormatChanges); - builder.AddData("cfg-gfx-efb-copy-ram", !g_Config.bSkipEFBCopyToRam); - builder.AddData("cfg-gfx-efb-copy-scaled", g_Config.bCopyEFBScaled); - builder.AddData("cfg-gfx-tc-samples", g_Config.iSafeTextureCache_ColorSamples); - builder.AddData("cfg-gfx-stereo-mode", g_Config.iStereoMode); + // Video configuration. + builder.AddData("cfg-gfx-multisamples", g_Config.iMultisamples); + builder.AddData("cfg-gfx-ssaa", g_Config.bSSAA); + builder.AddData("cfg-gfx-anisotropy", g_Config.iMaxAnisotropy); + builder.AddData("cfg-gfx-realxfb", g_Config.RealXFBEnabled()); + builder.AddData("cfg-gfx-virtualxfb", g_Config.VirtualXFBEnabled()); + builder.AddData("cfg-gfx-vsync", g_Config.bVSync); + builder.AddData("cfg-gfx-fullscreen", g_Config.bFullscreen); + builder.AddData("cfg-gfx-exclusive-mode", g_Config.bExclusiveMode); + builder.AddData("cfg-gfx-aspect-ratio", g_Config.iAspectRatio); + builder.AddData("cfg-gfx-efb-access", g_Config.bEFBAccessEnable); + builder.AddData("cfg-gfx-efb-scale", g_Config.iEFBScale); + builder.AddData("cfg-gfx-efb-copy-format-changes", g_Config.bEFBEmulateFormatChanges); + builder.AddData("cfg-gfx-efb-copy-ram", !g_Config.bSkipEFBCopyToRam); + builder.AddData("cfg-gfx-efb-copy-scaled", g_Config.bCopyEFBScaled); + builder.AddData("cfg-gfx-tc-samples", g_Config.iSafeTextureCache_ColorSamples); + builder.AddData("cfg-gfx-stereo-mode", g_Config.iStereoMode); - // GPU features. - if (g_Config.iAdapter < static_cast(g_Config.backend_info.Adapters.size())) - { - builder.AddData("gpu-adapter", g_Config.backend_info.Adapters[g_Config.iAdapter]); - } - else if (!g_Config.backend_info.AdapterName.empty()) - { - builder.AddData("gpu-adapter", g_Config.backend_info.AdapterName); - } - builder.AddData("gpu-has-exclusive-fullscreen", g_Config.backend_info.bSupportsExclusiveFullscreen); - builder.AddData("gpu-has-dual-source-blend", g_Config.backend_info.bSupportsDualSourceBlend); - builder.AddData("gpu-has-primitive-restart", g_Config.backend_info.bSupportsPrimitiveRestart); - builder.AddData("gpu-has-oversized-viewports", g_Config.backend_info.bSupportsOversizedViewports); - builder.AddData("gpu-has-geometry-shaders", g_Config.backend_info.bSupportsGeometryShaders); - builder.AddData("gpu-has-3d-vision", g_Config.backend_info.bSupports3DVision); - builder.AddData("gpu-has-early-z", g_Config.backend_info.bSupportsEarlyZ); - builder.AddData("gpu-has-binding-layout", g_Config.backend_info.bSupportsBindingLayout); - builder.AddData("gpu-has-bbox", g_Config.backend_info.bSupportsBBox); - builder.AddData("gpu-has-gs-instancing", g_Config.backend_info.bSupportsGSInstancing); - builder.AddData("gpu-has-post-processing", g_Config.backend_info.bSupportsPostProcessing); - builder.AddData("gpu-has-palette-conversion", g_Config.backend_info.bSupportsPaletteConversion); - builder.AddData("gpu-has-clip-control", g_Config.backend_info.bSupportsClipControl); - builder.AddData("gpu-has-ssaa", g_Config.backend_info.bSupportsSSAA); + // GPU features. + if (g_Config.iAdapter < static_cast(g_Config.backend_info.Adapters.size())) + { + builder.AddData("gpu-adapter", g_Config.backend_info.Adapters[g_Config.iAdapter]); + } + else if (!g_Config.backend_info.AdapterName.empty()) + { + builder.AddData("gpu-adapter", g_Config.backend_info.AdapterName); + } + builder.AddData("gpu-has-exclusive-fullscreen", + g_Config.backend_info.bSupportsExclusiveFullscreen); + builder.AddData("gpu-has-dual-source-blend", g_Config.backend_info.bSupportsDualSourceBlend); + builder.AddData("gpu-has-primitive-restart", g_Config.backend_info.bSupportsPrimitiveRestart); + builder.AddData("gpu-has-oversized-viewports", g_Config.backend_info.bSupportsOversizedViewports); + builder.AddData("gpu-has-geometry-shaders", g_Config.backend_info.bSupportsGeometryShaders); + builder.AddData("gpu-has-3d-vision", g_Config.backend_info.bSupports3DVision); + builder.AddData("gpu-has-early-z", g_Config.backend_info.bSupportsEarlyZ); + builder.AddData("gpu-has-binding-layout", g_Config.backend_info.bSupportsBindingLayout); + builder.AddData("gpu-has-bbox", g_Config.backend_info.bSupportsBBox); + builder.AddData("gpu-has-gs-instancing", g_Config.backend_info.bSupportsGSInstancing); + builder.AddData("gpu-has-post-processing", g_Config.backend_info.bSupportsPostProcessing); + builder.AddData("gpu-has-palette-conversion", g_Config.backend_info.bSupportsPaletteConversion); + builder.AddData("gpu-has-clip-control", g_Config.backend_info.bSupportsClipControl); + builder.AddData("gpu-has-ssaa", g_Config.backend_info.bSupportsSSAA); - // NetPlay / recording. - builder.AddData("netplay", NetPlay::IsNetPlayRunning()); - builder.AddData("movie", Movie::IsMovieActive()); + // NetPlay / recording. + builder.AddData("netplay", NetPlay::IsNetPlayRunning()); + builder.AddData("movie", Movie::IsMovieActive()); - // Controller information - // We grab enough to tell what percentage of our users are playing with keyboard/mouse, some kind of gamepad - // or the official gamecube adapter. - builder.AddData("gcadapter-detected", GCAdapter::IsDetected()); - builder.AddData("has-controller", Pad::GetConfig()->IsControllerControlledByGamepadDevice(0) || GCAdapter::IsDetected()); + // Controller information + // We grab enough to tell what percentage of our users are playing with keyboard/mouse, some kind + // of gamepad + // or the official gamecube adapter. + builder.AddData("gcadapter-detected", GCAdapter::IsDetected()); + builder.AddData("has-controller", Pad::GetConfig()->IsControllerControlledByGamepadDevice(0) || + GCAdapter::IsDetected()); - m_per_game_builder = builder; + m_per_game_builder = builder; } diff --git a/Source/Core/Core/Analytics.h b/Source/Core/Core/Analytics.h index bf21224c4f..11a555136f 100644 --- a/Source/Core/Core/Analytics.h +++ b/Source/Core/Core/Analytics.h @@ -15,60 +15,60 @@ class DolphinAnalytics { public: - // Performs lazy-initialization of a singleton and returns the instance. - static std::shared_ptr Instance(); + // Performs lazy-initialization of a singleton and returns the instance. + static std::shared_ptr Instance(); - // Resets and recreates the analytics system in order to reload - // configuration. - void ReloadConfig(); + // Resets and recreates the analytics system in order to reload + // configuration. + void ReloadConfig(); - // Rotates the unique identifier used for this instance of Dolphin and saves - // it into the configuration. - void GenerateNewIdentity(); + // Rotates the unique identifier used for this instance of Dolphin and saves + // it into the configuration. + void GenerateNewIdentity(); - // Reports a Dolphin start event. - void ReportDolphinStart(const std::string& ui_type); + // Reports a Dolphin start event. + void ReportDolphinStart(const std::string& ui_type); - // Generates a base report for a "Game start" event. Also preseeds the - // per-game base data. - void ReportGameStart(); + // Generates a base report for a "Game start" event. Also preseeds the + // per-game base data. + void ReportGameStart(); - // Forward Send method calls to the reporter. - template - void Send(T report) - { - std::lock_guard lk(m_reporter_mutex); - m_reporter.Send(report); - } + // Forward Send method calls to the reporter. + template + void Send(T report) + { + std::lock_guard lk(m_reporter_mutex); + m_reporter.Send(report); + } private: - DolphinAnalytics(); + DolphinAnalytics(); - void MakeBaseBuilder(); - void MakePerGameBuilder(); + void MakeBaseBuilder(); + void MakePerGameBuilder(); - // Returns a unique ID derived on the global unique ID, hashed with some - // report-specific data. This avoid correlation between different types of - // events. - std::string MakeUniqueId(const std::string& data); + // Returns a unique ID derived on the global unique ID, hashed with some + // report-specific data. This avoid correlation between different types of + // events. + std::string MakeUniqueId(const std::string& data); - // Unique ID. This should never leave the application. Only used derived - // values created by MakeUniqueId. - std::string m_unique_id; + // Unique ID. This should never leave the application. Only used derived + // values created by MakeUniqueId. + std::string m_unique_id; - // Builder that contains all non variable data that should be sent with all - // reports. - Common::AnalyticsReportBuilder m_base_builder; + // Builder that contains all non variable data that should be sent with all + // reports. + Common::AnalyticsReportBuilder m_base_builder; - // Builder that contains per game data and is initialized when a game start - // report is sent. - Common::AnalyticsReportBuilder m_per_game_builder; + // Builder that contains per game data and is initialized when a game start + // report is sent. + Common::AnalyticsReportBuilder m_per_game_builder; - std::mutex m_reporter_mutex; - Common::AnalyticsReporter m_reporter; + std::mutex m_reporter_mutex; + Common::AnalyticsReporter m_reporter; - // Shared pointer in order to allow for multithreaded use of the instance and - // avoid races at reinitialization time. - static std::mutex s_instance_mutex; - static std::shared_ptr s_instance; + // Shared pointer in order to allow for multithreaded use of the instance and + // avoid races at reinitialization time. + static std::mutex s_instance_mutex; + static std::shared_ptr s_instance; }; diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 7a355062af..0e98dabd6c 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -12,12 +12,10 @@ #include "Common/MathUtil.h" #include "Common/StringUtil.h" -#include "Core/ConfigManager.h" -#include "Core/Core.h" -#include "Core/Host.h" -#include "Core/PatchEngine.h" #include "Core/Boot/Boot.h" #include "Core/Boot/Boot_DOL.h" +#include "Core/ConfigManager.h" +#include "Core/Core.h" #include "Core/Debugger/Debugger_SymbolMap.h" #include "Core/HLE/HLE.h" #include "Core/HW/DVDInterface.h" @@ -25,10 +23,12 @@ #include "Core/HW/Memmap.h" #include "Core/HW/ProcessorInterface.h" #include "Core/HW/VideoInterface.h" +#include "Core/Host.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" -#include "Core/PowerPC/PowerPC.h" +#include "Core/PatchEngine.h" #include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/PPCSymbolDB.h" +#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/SignatureDB.h" #include "DiscIO/NANDContentLoader.h" @@ -36,129 +36,125 @@ bool CBoot::DVDRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt) { - std::vector buffer(length); - if (!DVDInterface::GetVolume().Read(dvd_offset, length, buffer.data(), decrypt)) - return false; - Memory::CopyToEmu(output_address, buffer.data(), length); - return true; + std::vector buffer(length); + if (!DVDInterface::GetVolume().Read(dvd_offset, length, buffer.data(), decrypt)) + return false; + Memory::CopyToEmu(output_address, buffer.data(), length); + return true; } void CBoot::Load_FST(bool _bIsWii) { - if (!DVDInterface::VolumeIsValid()) - return; + if (!DVDInterface::VolumeIsValid()) + return; - const DiscIO::IVolume& volume = DVDInterface::GetVolume(); + const DiscIO::IVolume& volume = DVDInterface::GetVolume(); - // copy first 20 bytes of disc to start of Mem 1 - DVDRead(/*offset*/0, /*address*/0, /*length*/0x20, false); + // copy first 20 bytes of disc to start of Mem 1 + DVDRead(/*offset*/ 0, /*address*/ 0, /*length*/ 0x20, false); - // copy of game id - Memory::Write_U32(Memory::Read_U32(0x0000), 0x3180); + // copy of game id + Memory::Write_U32(Memory::Read_U32(0x0000), 0x3180); - u32 shift = 0; - if (_bIsWii) - shift = 2; + u32 shift = 0; + if (_bIsWii) + shift = 2; - u32 fst_offset = 0; - u32 fst_size = 0; - u32 max_fst_size = 0; + u32 fst_offset = 0; + u32 fst_size = 0; + u32 max_fst_size = 0; - volume.ReadSwapped(0x0424, &fst_offset, _bIsWii); - volume.ReadSwapped(0x0428, &fst_size, _bIsWii); - volume.ReadSwapped(0x042c, &max_fst_size, _bIsWii); + volume.ReadSwapped(0x0424, &fst_offset, _bIsWii); + volume.ReadSwapped(0x0428, &fst_size, _bIsWii); + volume.ReadSwapped(0x042c, &max_fst_size, _bIsWii); - u32 arena_high = ROUND_DOWN(0x817FFFFF - (max_fst_size << shift), 0x20); - Memory::Write_U32(arena_high, 0x00000034); + u32 arena_high = ROUND_DOWN(0x817FFFFF - (max_fst_size << shift), 0x20); + Memory::Write_U32(arena_high, 0x00000034); - // load FST - DVDRead(fst_offset << shift, arena_high, fst_size << shift, _bIsWii); - Memory::Write_U32(arena_high, 0x00000038); - Memory::Write_U32(max_fst_size << shift, 0x0000003c); + // load FST + DVDRead(fst_offset << shift, arena_high, fst_size << shift, _bIsWii); + Memory::Write_U32(arena_high, 0x00000038); + Memory::Write_U32(max_fst_size << shift, 0x0000003c); } void CBoot::UpdateDebugger_MapLoaded() { - Host_NotifyMapLoaded(); + Host_NotifyMapLoaded(); } -bool CBoot::FindMapFile(std::string* existing_map_file, - std::string* writable_map_file, +bool CBoot::FindMapFile(std::string* existing_map_file, std::string* writable_map_file, std::string* title_id) { - std::string title_id_str; - size_t name_begin_index; + std::string title_id_str; + size_t name_begin_index; - SConfig& _StartupPara = SConfig::GetInstance(); - switch (_StartupPara.m_BootType) - { - case SConfig::BOOT_WII_NAND: - { - const DiscIO::CNANDContentLoader& Loader = - DiscIO::CNANDContentManager::Access().GetNANDLoader(_StartupPara.m_strFilename); - if (Loader.IsValid()) - { - u64 TitleID = Loader.GetTitleID(); - title_id_str = StringFromFormat("%08X_%08X", - (u32)(TitleID >> 32) & 0xFFFFFFFF, - (u32)TitleID & 0xFFFFFFFF); - } - break; - } + SConfig& _StartupPara = SConfig::GetInstance(); + switch (_StartupPara.m_BootType) + { + case SConfig::BOOT_WII_NAND: + { + const DiscIO::CNANDContentLoader& Loader = + DiscIO::CNANDContentManager::Access().GetNANDLoader(_StartupPara.m_strFilename); + if (Loader.IsValid()) + { + u64 TitleID = Loader.GetTitleID(); + title_id_str = StringFromFormat("%08X_%08X", (u32)(TitleID >> 32) & 0xFFFFFFFF, + (u32)TitleID & 0xFFFFFFFF); + } + break; + } - case SConfig::BOOT_ELF: - case SConfig::BOOT_DOL: - // Strip the .elf/.dol file extension and directories before the name - name_begin_index = _StartupPara.m_strFilename.find_last_of("/") + 1; - if ((_StartupPara.m_strFilename.find_last_of("\\") + 1) > name_begin_index) - { - name_begin_index = _StartupPara.m_strFilename.find_last_of("\\") + 1; - } - title_id_str = _StartupPara.m_strFilename.substr( - name_begin_index, _StartupPara.m_strFilename.size() - 4 - name_begin_index); - break; + case SConfig::BOOT_ELF: + case SConfig::BOOT_DOL: + // Strip the .elf/.dol file extension and directories before the name + name_begin_index = _StartupPara.m_strFilename.find_last_of("/") + 1; + if ((_StartupPara.m_strFilename.find_last_of("\\") + 1) > name_begin_index) + { + name_begin_index = _StartupPara.m_strFilename.find_last_of("\\") + 1; + } + title_id_str = _StartupPara.m_strFilename.substr( + name_begin_index, _StartupPara.m_strFilename.size() - 4 - name_begin_index); + break; - default: - title_id_str = _StartupPara.GetUniqueID(); - break; - } + default: + title_id_str = _StartupPara.GetUniqueID(); + break; + } - if (writable_map_file) - *writable_map_file = File::GetUserPath(D_MAPS_IDX) + title_id_str + ".map"; + if (writable_map_file) + *writable_map_file = File::GetUserPath(D_MAPS_IDX) + title_id_str + ".map"; - if (title_id) - *title_id = title_id_str; + if (title_id) + *title_id = title_id_str; - bool found = false; - static const std::string maps_directories[] = { - File::GetUserPath(D_MAPS_IDX), - File::GetSysDirectory() + MAPS_DIR DIR_SEP - }; - for (size_t i = 0; !found && i < ArraySize(maps_directories); ++i) - { - std::string path = maps_directories[i] + title_id_str + ".map"; - if (File::Exists(path)) - { - found = true; - if (existing_map_file) - *existing_map_file = path; - } - } + bool found = false; + static const std::string maps_directories[] = {File::GetUserPath(D_MAPS_IDX), + File::GetSysDirectory() + MAPS_DIR DIR_SEP}; + for (size_t i = 0; !found && i < ArraySize(maps_directories); ++i) + { + std::string path = maps_directories[i] + title_id_str + ".map"; + if (File::Exists(path)) + { + found = true; + if (existing_map_file) + *existing_map_file = path; + } + } - return found; + return found; } bool CBoot::LoadMapFromFilename() { - std::string strMapFilename; - bool found = FindMapFile(&strMapFilename, nullptr); - if (found && g_symbolDB.LoadMap(strMapFilename)) - { - UpdateDebugger_MapLoaded(); - return true; - } + std::string strMapFilename; + bool found = FindMapFile(&strMapFilename, nullptr); + if (found && g_symbolDB.LoadMap(strMapFilename)) + { + UpdateDebugger_MapLoaded(); + return true; + } - return false; + return false; } // If ipl.bin is not found, this function does *some* of what BS1 does: @@ -166,314 +162,319 @@ bool CBoot::LoadMapFromFilename() // It does not initialize the hardware or anything else like BS1 does. bool CBoot::Load_BS2(const std::string& _rBootROMFilename) { - // CRC32 - const u32 USA_v1_0 = 0x6D740AE7; // https://forums.dolphin-emu.org/Thread-unknown-hash-on-ipl-bin?pid=385344#pid385344 - const u32 USA_v1_1 = 0xD5E6FEEA; // https://forums.dolphin-emu.org/Thread-unknown-hash-on-ipl-bin?pid=385334#pid385334 - const u32 USA_v1_2 = 0x86573808; // https://forums.dolphin-emu.org/Thread-unknown-hash-on-ipl-bin?pid=385399#pid385399 - const u32 BRA_v1_0 = 0x667D0B64; // GameCubes sold in Brazil have this IPL. Same as USA v1.2 but localized - const u32 JAP_v1_0 = 0x6DAC1F2A; // Redump - const u32 JAP_v1_1 = 0xD235E3F9; // https://bugs.dolphin-emu.org/issues/8936 - const u32 PAL_v1_0 = 0x4F319F43; // Redump - const u32 PAL_v1_2 = 0xAD1B7F16; // Redump + // CRC32 + const u32 USA_v1_0 = + 0x6D740AE7; // https://forums.dolphin-emu.org/Thread-unknown-hash-on-ipl-bin?pid=385344#pid385344 + const u32 USA_v1_1 = + 0xD5E6FEEA; // https://forums.dolphin-emu.org/Thread-unknown-hash-on-ipl-bin?pid=385334#pid385334 + const u32 USA_v1_2 = + 0x86573808; // https://forums.dolphin-emu.org/Thread-unknown-hash-on-ipl-bin?pid=385399#pid385399 + const u32 BRA_v1_0 = + 0x667D0B64; // GameCubes sold in Brazil have this IPL. Same as USA v1.2 but localized + const u32 JAP_v1_0 = 0x6DAC1F2A; // Redump + const u32 JAP_v1_1 = 0xD235E3F9; // https://bugs.dolphin-emu.org/issues/8936 + const u32 PAL_v1_0 = 0x4F319F43; // Redump + const u32 PAL_v1_2 = 0xAD1B7F16; // Redump - // Load the whole ROM dump - std::string data; - if (!File::ReadFileToString(_rBootROMFilename, data)) - return false; + // Load the whole ROM dump + std::string data; + if (!File::ReadFileToString(_rBootROMFilename, data)) + return false; - // Use zlibs crc32 implementation to compute the hash - u32 ipl_hash = crc32(0L, Z_NULL, 0); - ipl_hash = crc32(ipl_hash, (const Bytef*)data.data(), (u32)data.size()); - std::string ipl_region; - switch (ipl_hash) - { - case USA_v1_0: - case USA_v1_1: - case USA_v1_2: - case BRA_v1_0: - ipl_region = USA_DIR; - break; - case JAP_v1_0: - case JAP_v1_1: - ipl_region = JAP_DIR; - break; - case PAL_v1_0: - case PAL_v1_2: - ipl_region = EUR_DIR; - break; - default: - PanicAlertT("IPL with unknown hash %x", ipl_hash); - break; - } + // Use zlibs crc32 implementation to compute the hash + u32 ipl_hash = crc32(0L, Z_NULL, 0); + ipl_hash = crc32(ipl_hash, (const Bytef*)data.data(), (u32)data.size()); + std::string ipl_region; + switch (ipl_hash) + { + case USA_v1_0: + case USA_v1_1: + case USA_v1_2: + case BRA_v1_0: + ipl_region = USA_DIR; + break; + case JAP_v1_0: + case JAP_v1_1: + ipl_region = JAP_DIR; + break; + case PAL_v1_0: + case PAL_v1_2: + ipl_region = EUR_DIR; + break; + default: + PanicAlertT("IPL with unknown hash %x", ipl_hash); + break; + } - std::string BootRegion = _rBootROMFilename.substr(_rBootROMFilename.find_last_of(DIR_SEP) - 3, 3); - if (BootRegion != ipl_region) - PanicAlertT("%s IPL found in %s directory. The disc might not be recognized", - ipl_region.c_str(), BootRegion.c_str()); + std::string BootRegion = _rBootROMFilename.substr(_rBootROMFilename.find_last_of(DIR_SEP) - 3, 3); + if (BootRegion != ipl_region) + PanicAlertT("%s IPL found in %s directory. The disc might not be recognized", + ipl_region.c_str(), BootRegion.c_str()); - // Run the descrambler over the encrypted section containing BS1/BS2 - CEXIIPL::Descrambler((u8*)data.data() + 0x100, 0x1AFE00); + // Run the descrambler over the encrypted section containing BS1/BS2 + CEXIIPL::Descrambler((u8*)data.data() + 0x100, 0x1AFE00); - // TODO: Execution is supposed to start at 0xFFF00000, not 0x81200000; - // copying the initial boot code to 0x81200000 is a hack. - // For now, HLE the first few instructions and start at 0x81200150 - // to work around this. - Memory::CopyToEmu(0x01200000, data.data() + 0x100, 0x700); - Memory::CopyToEmu(0x01300000, data.data() + 0x820, 0x1AFE00); - PowerPC::ppcState.gpr[3] = 0xfff0001f; - PowerPC::ppcState.gpr[4] = 0x00002030; - PowerPC::ppcState.gpr[5] = 0x0000009c; - PowerPC::ppcState.msr = 0x00002030; - PowerPC::ppcState.spr[SPR_HID0] = 0x0011c464; - PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff; - PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; - PowerPC::ppcState.spr[SPR_IBAT3U] = 0xfff0001f; - PowerPC::ppcState.spr[SPR_IBAT3L] = 0xfff00001; - PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; - PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; - PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; - PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; - PowerPC::ppcState.spr[SPR_DBAT3U] = 0xfff0001f; - PowerPC::ppcState.spr[SPR_DBAT3L] = 0xfff00001; - PC = 0x81200150; - return true; + // TODO: Execution is supposed to start at 0xFFF00000, not 0x81200000; + // copying the initial boot code to 0x81200000 is a hack. + // For now, HLE the first few instructions and start at 0x81200150 + // to work around this. + Memory::CopyToEmu(0x01200000, data.data() + 0x100, 0x700); + Memory::CopyToEmu(0x01300000, data.data() + 0x820, 0x1AFE00); + PowerPC::ppcState.gpr[3] = 0xfff0001f; + PowerPC::ppcState.gpr[4] = 0x00002030; + PowerPC::ppcState.gpr[5] = 0x0000009c; + PowerPC::ppcState.msr = 0x00002030; + PowerPC::ppcState.spr[SPR_HID0] = 0x0011c464; + PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff; + PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; + PowerPC::ppcState.spr[SPR_IBAT3U] = 0xfff0001f; + PowerPC::ppcState.spr[SPR_IBAT3L] = 0xfff00001; + PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; + PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; + PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; + PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; + PowerPC::ppcState.spr[SPR_DBAT3U] = 0xfff0001f; + PowerPC::ppcState.spr[SPR_DBAT3L] = 0xfff00001; + PC = 0x81200150; + return true; } - // Third boot step after BootManager and Core. See Call schedule in BootManager.cpp bool CBoot::BootUp() { - SConfig& _StartupPara = SConfig::GetInstance(); + SConfig& _StartupPara = SConfig::GetInstance(); - NOTICE_LOG(BOOT, "Booting %s", _StartupPara.m_strFilename.c_str()); + NOTICE_LOG(BOOT, "Booting %s", _StartupPara.m_strFilename.c_str()); - g_symbolDB.Clear(); + g_symbolDB.Clear(); - // PAL Wii uses NTSC framerate and linecount in 60Hz modes - VideoInterface::Preset(_StartupPara.bNTSC || (_StartupPara.bWii && _StartupPara.bPAL60)); + // PAL Wii uses NTSC framerate and linecount in 60Hz modes + VideoInterface::Preset(_StartupPara.bNTSC || (_StartupPara.bWii && _StartupPara.bPAL60)); - switch (_StartupPara.m_BootType) - { - // GCM and Wii - case SConfig::BOOT_ISO: - { - DVDInterface::SetVolumeName(_StartupPara.m_strFilename); - DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid()); - if (!DVDInterface::VolumeIsValid()) - return false; + switch (_StartupPara.m_BootType) + { + // GCM and Wii + case SConfig::BOOT_ISO: + { + DVDInterface::SetVolumeName(_StartupPara.m_strFilename); + DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid()); + if (!DVDInterface::VolumeIsValid()) + return false; - const DiscIO::IVolume& pVolume = DVDInterface::GetVolume(); + const DiscIO::IVolume& pVolume = DVDInterface::GetVolume(); - if ((pVolume.GetVolumeType() == DiscIO::IVolume::WII_DISC) != _StartupPara.bWii) - { - PanicAlertT("Warning - starting ISO in wrong console mode!"); - } + if ((pVolume.GetVolumeType() == DiscIO::IVolume::WII_DISC) != _StartupPara.bWii) + { + PanicAlertT("Warning - starting ISO in wrong console mode!"); + } - std::string unique_id = DVDInterface::GetVolume().GetUniqueID(); - if (unique_id.size() >= 4) - VideoInterface::SetRegionReg(unique_id.at(3)); + std::string unique_id = DVDInterface::GetVolume().GetUniqueID(); + if (unique_id.size() >= 4) + VideoInterface::SetRegionReg(unique_id.at(3)); - std::vector tmd_buffer = pVolume.GetTMD(); - if (!tmd_buffer.empty()) - { - WII_IPC_HLE_Interface::ES_DIVerify(tmd_buffer); - } + std::vector tmd_buffer = pVolume.GetTMD(); + if (!tmd_buffer.empty()) + { + WII_IPC_HLE_Interface::ES_DIVerify(tmd_buffer); + } - _StartupPara.bWii = pVolume.GetVolumeType() == DiscIO::IVolume::WII_DISC; + _StartupPara.bWii = pVolume.GetVolumeType() == DiscIO::IVolume::WII_DISC; - // HLE BS2 or not - if (_StartupPara.bHLE_BS2) - { - EmulatedBS2(_StartupPara.bWii); - } - else if (!Load_BS2(_StartupPara.m_strBootROM)) - { - // If we can't load the bootrom file we HLE it instead - EmulatedBS2(_StartupPara.bWii); - } - else - { - // Load patches if they weren't already - PatchEngine::LoadPatches(); - } + // HLE BS2 or not + if (_StartupPara.bHLE_BS2) + { + EmulatedBS2(_StartupPara.bWii); + } + else if (!Load_BS2(_StartupPara.m_strBootROM)) + { + // If we can't load the bootrom file we HLE it instead + EmulatedBS2(_StartupPara.bWii); + } + else + { + // Load patches if they weren't already + PatchEngine::LoadPatches(); + } - // Scan for common HLE functions - if (_StartupPara.bSkipIdle && _StartupPara.bHLE_BS2 && !_StartupPara.bEnableDebugging) - { - PPCAnalyst::FindFunctions(0x80004000, 0x811fffff, &g_symbolDB); - SignatureDB db; - if (db.Load(File::GetSysDirectory() + TOTALDB)) - { - db.Apply(&g_symbolDB); - HLE::PatchFunctions(); - db.Clear(); - } - } + // Scan for common HLE functions + if (_StartupPara.bSkipIdle && _StartupPara.bHLE_BS2 && !_StartupPara.bEnableDebugging) + { + PPCAnalyst::FindFunctions(0x80004000, 0x811fffff, &g_symbolDB); + SignatureDB db; + if (db.Load(File::GetSysDirectory() + TOTALDB)) + { + db.Apply(&g_symbolDB); + HLE::PatchFunctions(); + db.Clear(); + } + } - // Try to load the symbol map if there is one, and then scan it for - // and eventually replace code - if (LoadMapFromFilename()) - HLE::PatchFunctions(); + // Try to load the symbol map if there is one, and then scan it for + // and eventually replace code + if (LoadMapFromFilename()) + HLE::PatchFunctions(); - break; - } + break; + } - // DOL - case SConfig::BOOT_DOL: - { - CDolLoader dolLoader(_StartupPara.m_strFilename); - if (!dolLoader.IsValid()) - return false; + // DOL + case SConfig::BOOT_DOL: + { + CDolLoader dolLoader(_StartupPara.m_strFilename); + if (!dolLoader.IsValid()) + return false; - // Check if we have gotten a Wii file or not - bool dolWii = dolLoader.IsWii(); - if (dolWii != _StartupPara.bWii) - { - PanicAlertT("Warning - starting DOL in wrong console mode!"); - } + // Check if we have gotten a Wii file or not + bool dolWii = dolLoader.IsWii(); + if (dolWii != _StartupPara.bWii) + { + PanicAlertT("Warning - starting DOL in wrong console mode!"); + } - bool BS2Success = false; + bool BS2Success = false; - if (dolWii) - { - BS2Success = EmulatedBS2(dolWii); - } - else if ((!DVDInterface::VolumeIsValid() || DVDInterface::GetVolume().GetVolumeType() != DiscIO::IVolume::WII_DISC) && - !_StartupPara.m_strDefaultISO.empty()) - { - DVDInterface::SetVolumeName(_StartupPara.m_strDefaultISO); - BS2Success = EmulatedBS2(dolWii); - } + if (dolWii) + { + BS2Success = EmulatedBS2(dolWii); + } + else if ((!DVDInterface::VolumeIsValid() || + DVDInterface::GetVolume().GetVolumeType() != DiscIO::IVolume::WII_DISC) && + !_StartupPara.m_strDefaultISO.empty()) + { + DVDInterface::SetVolumeName(_StartupPara.m_strDefaultISO); + BS2Success = EmulatedBS2(dolWii); + } - if (!_StartupPara.m_strDVDRoot.empty()) - { - NOTICE_LOG(BOOT, "Setting DVDRoot %s", _StartupPara.m_strDVDRoot.c_str()); - DVDInterface::SetVolumeDirectory(_StartupPara.m_strDVDRoot, dolWii, _StartupPara.m_strApploader, _StartupPara.m_strFilename); - BS2Success = EmulatedBS2(dolWii); - } + if (!_StartupPara.m_strDVDRoot.empty()) + { + NOTICE_LOG(BOOT, "Setting DVDRoot %s", _StartupPara.m_strDVDRoot.c_str()); + DVDInterface::SetVolumeDirectory(_StartupPara.m_strDVDRoot, dolWii, + _StartupPara.m_strApploader, _StartupPara.m_strFilename); + BS2Success = EmulatedBS2(dolWii); + } - DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid()); + DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid()); - if (!BS2Success) - { - // Set up MSR and the BAT SPR registers. - UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr); - m_MSR.FP = 1; - m_MSR.DR = 1; - m_MSR.IR = 1; - m_MSR.EE = 1; - PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff; - PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; - PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff; - PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002; - PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; - PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; - PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; - PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; - PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff; - PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002; - PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff; - PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a; + if (!BS2Success) + { + // Set up MSR and the BAT SPR registers. + UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr); + m_MSR.FP = 1; + m_MSR.DR = 1; + m_MSR.IR = 1; + m_MSR.EE = 1; + PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff; + PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; + PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff; + PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002; + PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; + PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; + PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; + PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; + PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff; + PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002; + PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff; + PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a; - dolLoader.Load(); - PC = dolLoader.GetEntryPoint(); - } + dolLoader.Load(); + PC = dolLoader.GetEntryPoint(); + } - if (LoadMapFromFilename()) - HLE::PatchFunctions(); + if (LoadMapFromFilename()) + HLE::PatchFunctions(); - break; - } + break; + } - // ELF - case SConfig::BOOT_ELF: - { - // load image or create virtual drive from directory - if (!_StartupPara.m_strDVDRoot.empty()) - { - NOTICE_LOG(BOOT, "Setting DVDRoot %s", _StartupPara.m_strDVDRoot.c_str()); - DVDInterface::SetVolumeDirectory(_StartupPara.m_strDVDRoot, _StartupPara.bWii); - } - else if (!_StartupPara.m_strDefaultISO.empty()) - { - NOTICE_LOG(BOOT, "Loading default ISO %s", _StartupPara.m_strDefaultISO.c_str()); - DVDInterface::SetVolumeName(_StartupPara.m_strDefaultISO); - } - else - { - DVDInterface::SetVolumeDirectory(_StartupPara.m_strFilename, _StartupPara.bWii); - } + // ELF + case SConfig::BOOT_ELF: + { + // load image or create virtual drive from directory + if (!_StartupPara.m_strDVDRoot.empty()) + { + NOTICE_LOG(BOOT, "Setting DVDRoot %s", _StartupPara.m_strDVDRoot.c_str()); + DVDInterface::SetVolumeDirectory(_StartupPara.m_strDVDRoot, _StartupPara.bWii); + } + else if (!_StartupPara.m_strDefaultISO.empty()) + { + NOTICE_LOG(BOOT, "Loading default ISO %s", _StartupPara.m_strDefaultISO.c_str()); + DVDInterface::SetVolumeName(_StartupPara.m_strDefaultISO); + } + else + { + DVDInterface::SetVolumeDirectory(_StartupPara.m_strFilename, _StartupPara.bWii); + } - DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid()); + DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid()); - // Poor man's bootup - if(_StartupPara.bWii) - SetupWiiMemory(DiscIO::IVolume::COUNTRY_UNKNOWN); - else - EmulatedBS2_GC(true); + // Poor man's bootup + if (_StartupPara.bWii) + SetupWiiMemory(DiscIO::IVolume::COUNTRY_UNKNOWN); + else + EmulatedBS2_GC(true); - Load_FST(_StartupPara.bWii); - if(!Boot_ELF(_StartupPara.m_strFilename)) - return false; + Load_FST(_StartupPara.bWii); + if (!Boot_ELF(_StartupPara.m_strFilename)) + return false; - UpdateDebugger_MapLoaded(); - Dolphin_Debugger::AddAutoBreakpoints(); - break; - } + UpdateDebugger_MapLoaded(); + Dolphin_Debugger::AddAutoBreakpoints(); + break; + } - // Wii WAD - case SConfig::BOOT_WII_NAND: - Boot_WiiWAD(_StartupPara.m_strFilename); + // Wii WAD + case SConfig::BOOT_WII_NAND: + Boot_WiiWAD(_StartupPara.m_strFilename); - if (LoadMapFromFilename()) - HLE::PatchFunctions(); + if (LoadMapFromFilename()) + HLE::PatchFunctions(); - // load default image or create virtual drive from directory - if (!_StartupPara.m_strDVDRoot.empty()) - DVDInterface::SetVolumeDirectory(_StartupPara.m_strDVDRoot, true); - else if (!_StartupPara.m_strDefaultISO.empty()) - DVDInterface::SetVolumeName(_StartupPara.m_strDefaultISO); + // load default image or create virtual drive from directory + if (!_StartupPara.m_strDVDRoot.empty()) + DVDInterface::SetVolumeDirectory(_StartupPara.m_strDVDRoot, true); + else if (!_StartupPara.m_strDefaultISO.empty()) + DVDInterface::SetVolumeName(_StartupPara.m_strDefaultISO); - DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid()); - break; + DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid()); + break; + // Bootstrap 2 (AKA: Initial Program Loader, "BIOS") + case SConfig::BOOT_BS2: + { + DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid()); + if (Load_BS2(_StartupPara.m_strBootROM)) + { + if (LoadMapFromFilename()) + HLE::PatchFunctions(); + } + else + { + return false; + } + break; + } - // Bootstrap 2 (AKA: Initial Program Loader, "BIOS") - case SConfig::BOOT_BS2: - { - DVDInterface::SetDiscInside(DVDInterface::VolumeIsValid()); - if (Load_BS2(_StartupPara.m_strBootROM)) - { - if (LoadMapFromFilename()) - HLE::PatchFunctions(); - } - else - { - return false; - } - break; - } + case SConfig::BOOT_DFF: + // do nothing + break; - case SConfig::BOOT_DFF: - // do nothing - break; + default: + { + PanicAlertT("Tried to load an unknown file type."); + return false; + } + } - default: - { - PanicAlertT("Tried to load an unknown file type."); - return false; - } - } + // HLE jump to loader (homebrew). Disabled when Gecko is active as it interferes with the code + // handler + if (!SConfig::GetInstance().bEnableCheats) + { + HLE::Patch(0x80001800, "HBReload"); + Memory::CopyToEmu(0x00001804, "STUBHAXX", 8); + } - // HLE jump to loader (homebrew). Disabled when Gecko is active as it interferes with the code handler - if (!SConfig::GetInstance().bEnableCheats) - { - HLE::Patch(0x80001800, "HBReload"); - Memory::CopyToEmu(0x00001804, "STUBHAXX", 8); - } - - // Not part of the binary itself, but either we or Gecko OS might insert - // this, and it doesn't clear the icache properly. - HLE::Patch(0x800018a8, "GeckoCodehandler"); - return true; + // Not part of the binary itself, but either we or Gecko OS might insert + // this, and it doesn't clear the icache properly. + HLE::Patch(0x800018a8, "GeckoCodehandler"); + return true; } diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index 41815c00f4..268ed2f653 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -11,50 +11,48 @@ struct CountrySetting { - const std::string area; - const std::string video; - const std::string game; - const std::string code; + const std::string area; + const std::string video; + const std::string game; + const std::string code; }; class CBoot { public: + static bool BootUp(); + static bool IsElfWii(const std::string& filename); - static bool BootUp(); - static bool IsElfWii(const std::string& filename); - - // Tries to find a map file for the current game by looking first in the - // local user directory, then in the shared user directory. - // - // If existing_map_file is not nullptr and a map file exists, it is set to the - // path to the existing map file. - // - // If writable_map_file is not nullptr, it is set to the path to where a map - // file should be saved. - // - // If title_id is not nullptr, it is set to the title id - // - // Returns true if a map file exists, false if none could be found. - static bool FindMapFile(std::string* existing_map_file, - std::string* writable_map_file, - std::string* title_id = nullptr); + // Tries to find a map file for the current game by looking first in the + // local user directory, then in the shared user directory. + // + // If existing_map_file is not nullptr and a map file exists, it is set to the + // path to the existing map file. + // + // If writable_map_file is not nullptr, it is set to the path to where a map + // file should be saved. + // + // If title_id is not nullptr, it is set to the title id + // + // Returns true if a map file exists, false if none could be found. + static bool FindMapFile(std::string* existing_map_file, std::string* writable_map_file, + std::string* title_id = nullptr); private: - static bool DVDRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt); - static void RunFunction(u32 _iAddr); + static bool DVDRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt); + static void RunFunction(u32 _iAddr); - static void UpdateDebugger_MapLoaded(); + static void UpdateDebugger_MapLoaded(); - static bool LoadMapFromFilename(); - static bool Boot_ELF(const std::string& filename); - static bool Boot_WiiWAD(const std::string& filename); + static bool LoadMapFromFilename(); + static bool Boot_ELF(const std::string& filename); + static bool Boot_WiiWAD(const std::string& filename); - static bool EmulatedBS2_GC(bool skipAppLoader = false); - static bool EmulatedBS2_Wii(); - static bool EmulatedBS2(bool _bIsWii); - static bool Load_BS2(const std::string& _rBootROMFilename); - static void Load_FST(bool _bIsWii); + static bool EmulatedBS2_GC(bool skipAppLoader = false); + static bool EmulatedBS2_Wii(); + static bool EmulatedBS2(bool _bIsWii); + static bool Load_BS2(const std::string& _rBootROMFilename); + static void Load_FST(bool _bIsWii); - static bool SetupWiiMemory(DiscIO::IVolume::ECountry country); + static bool SetupWiiMemory(DiscIO::IVolume::ECountry country); }; diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index 35ac4d69e6..69236d9e21 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -8,25 +8,25 @@ #include "Common/NandPaths.h" #include "Common/SettingsHandler.h" +#include "Core/Boot/Boot.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/MemTools.h" -#include "Core/PatchEngine.h" -#include "Core/Boot/Boot.h" #include "Core/HLE/HLE.h" #include "Core/HW/CPU.h" #include "Core/HW/DVDInterface.h" #include "Core/HW/EXI_DeviceIPL.h" #include "Core/HW/Memmap.h" +#include "Core/MemTools.h" +#include "Core/PatchEngine.h" #include "Core/PowerPC/PowerPC.h" void CBoot::RunFunction(u32 _iAddr) { - PC = _iAddr; - LR = 0x00; + PC = _iAddr; + LR = 0x00; - while (PC != 0x00) - PowerPC::SingleStep(); + while (PC != 0x00) + PowerPC::SingleStep(); } // __________________________________________________________________________________________________ @@ -35,282 +35,293 @@ void CBoot::RunFunction(u32 _iAddr) // execute the apploader, function by function, using the above utility. bool CBoot::EmulatedBS2_GC(bool skipAppLoader) { - INFO_LOG(BOOT, "Faking GC BS2..."); + INFO_LOG(BOOT, "Faking GC BS2..."); - // Set up MSR and the BAT SPR registers. - UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr); - m_MSR.FP = 1; - m_MSR.DR = 1; - m_MSR.IR = 1; - m_MSR.EE = 1; - PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff; - PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; - PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; - PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; - PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; - PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; + // Set up MSR and the BAT SPR registers. + UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr); + m_MSR.FP = 1; + m_MSR.DR = 1; + m_MSR.IR = 1; + m_MSR.EE = 1; + PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff; + PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; + PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; + PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; + PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; + PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; - // Write necessary values - // Here we write values to memory that the apploader does not take care of. Game info goes - // to 0x80000000 according to YAGCD 4.2. + // Write necessary values + // Here we write values to memory that the apploader does not take care of. Game info goes + // to 0x80000000 according to YAGCD 4.2. - // It's possible to boot DOL and ELF files without a disc inserted - if (DVDInterface::VolumeIsValid()) - DVDRead(/*offset*/0x00000000, /*address*/0x00000000, 0x20, false); // write disc info + // It's possible to boot DOL and ELF files without a disc inserted + if (DVDInterface::VolumeIsValid()) + DVDRead(/*offset*/ 0x00000000, /*address*/ 0x00000000, 0x20, false); // write disc info - PowerPC::HostWrite_U32(0x0D15EA5E, 0x80000020); // Booted from bootrom. 0xE5207C22 = booted from jtag - PowerPC::HostWrite_U32(Memory::REALRAM_SIZE, 0x80000028); // Physical Memory Size (24MB on retail) - // TODO determine why some games fail when using a retail ID. (Seem to take different EXI paths, see Ikaruga for example) - PowerPC::HostWrite_U32(0x10000006, 0x8000002C); // Console type - DevKit (retail ID == 0x00000003) see YAGCD 4.2.1.1.2 + PowerPC::HostWrite_U32(0x0D15EA5E, + 0x80000020); // Booted from bootrom. 0xE5207C22 = booted from jtag + PowerPC::HostWrite_U32(Memory::REALRAM_SIZE, + 0x80000028); // Physical Memory Size (24MB on retail) + // TODO determine why some games fail when using a retail ID. (Seem to take different EXI paths, + // see Ikaruga for example) + PowerPC::HostWrite_U32( + 0x10000006, + 0x8000002C); // Console type - DevKit (retail ID == 0x00000003) see YAGCD 4.2.1.1.2 - PowerPC::HostWrite_U32(SConfig::GetInstance().bNTSC - ? 0 : 1, 0x800000CC); // Fake the VI Init of the IPL (YAGCD 4.2.1.4) + PowerPC::HostWrite_U32(SConfig::GetInstance().bNTSC ? 0 : 1, + 0x800000CC); // Fake the VI Init of the IPL (YAGCD 4.2.1.4) - PowerPC::HostWrite_U32(0x01000000, 0x800000d0); // ARAM Size. 16MB main + 4/16/32MB external (retail consoles have no external ARAM) + PowerPC::HostWrite_U32(0x01000000, 0x800000d0); // ARAM Size. 16MB main + 4/16/32MB external + // (retail consoles have no external ARAM) - PowerPC::HostWrite_U32(0x09a7ec80, 0x800000F8); // Bus Clock Speed - PowerPC::HostWrite_U32(0x1cf7c580, 0x800000FC); // CPU Clock Speed + PowerPC::HostWrite_U32(0x09a7ec80, 0x800000F8); // Bus Clock Speed + PowerPC::HostWrite_U32(0x1cf7c580, 0x800000FC); // CPU Clock Speed - PowerPC::HostWrite_U32(0x4c000064, 0x80000300); // Write default DFI Handler: rfi - PowerPC::HostWrite_U32(0x4c000064, 0x80000800); // Write default FPU Handler: rfi - PowerPC::HostWrite_U32(0x4c000064, 0x80000C00); // Write default Syscall Handler: rfi + PowerPC::HostWrite_U32(0x4c000064, 0x80000300); // Write default DFI Handler: rfi + PowerPC::HostWrite_U32(0x4c000064, 0x80000800); // Write default FPU Handler: rfi + PowerPC::HostWrite_U32(0x4c000064, 0x80000C00); // Write default Syscall Handler: rfi - PowerPC::HostWrite_U64((u64)CEXIIPL::GetGCTime() * (u64)40500000, 0x800030D8); // Preset time base ticks - // HIO checks this - //PowerPC::HostWrite_U16(0x8200, 0x000030e6); // Console type + PowerPC::HostWrite_U64((u64)CEXIIPL::GetGCTime() * (u64)40500000, + 0x800030D8); // Preset time base ticks + // HIO checks this + // PowerPC::HostWrite_U16(0x8200, 0x000030e6); // Console type - HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader + HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader - if (!DVDInterface::VolumeIsValid()) - return false; + if (!DVDInterface::VolumeIsValid()) + return false; - // Load Apploader to Memory - The apploader is hardcoded to begin at 0x2440 on the disc, - // but the size can differ between discs. Compare with YAGCD chap 13. - const DiscIO::IVolume& volume = DVDInterface::GetVolume(); - const u32 apploader_offset = 0x2440; - u32 apploader_entry, apploader_size, apploader_trailer; - if (skipAppLoader || - !volume.ReadSwapped(apploader_offset + 0x10, &apploader_entry, false) || - !volume.ReadSwapped(apploader_offset + 0x14, &apploader_size, false) || - !volume.ReadSwapped(apploader_offset + 0x18, &apploader_trailer, false) || - apploader_entry == (u32)-1 || apploader_size + apploader_trailer == (u32)-1) - { - INFO_LOG(BOOT, "GC BS2: Not running apploader!"); - return false; - } - DVDRead(apploader_offset + 0x20, 0x01200000, apploader_size + apploader_trailer, false); + // Load Apploader to Memory - The apploader is hardcoded to begin at 0x2440 on the disc, + // but the size can differ between discs. Compare with YAGCD chap 13. + const DiscIO::IVolume& volume = DVDInterface::GetVolume(); + const u32 apploader_offset = 0x2440; + u32 apploader_entry, apploader_size, apploader_trailer; + if (skipAppLoader || !volume.ReadSwapped(apploader_offset + 0x10, &apploader_entry, false) || + !volume.ReadSwapped(apploader_offset + 0x14, &apploader_size, false) || + !volume.ReadSwapped(apploader_offset + 0x18, &apploader_trailer, false) || + apploader_entry == (u32)-1 || apploader_size + apploader_trailer == (u32)-1) + { + INFO_LOG(BOOT, "GC BS2: Not running apploader!"); + return false; + } + DVDRead(apploader_offset + 0x20, 0x01200000, apploader_size + apploader_trailer, false); - // Setup pointers like real BS2 does - if (SConfig::GetInstance().bNTSC) - { - PowerPC::ppcState.gpr[1] = 0x81566550; // StackPointer, used to be set to 0x816ffff0 - PowerPC::ppcState.gpr[2] = 0x81465cc0; // Global pointer to Small Data Area 2 Base (haven't seen anything use it...meh) - PowerPC::ppcState.gpr[13] = 0x81465320; // Global pointer to Small Data Area Base (Luigi's Mansion's apploader uses it) - } - else - { - PowerPC::ppcState.gpr[1] = 0x815edca8; - PowerPC::ppcState.gpr[2] = 0x814b5b20; - PowerPC::ppcState.gpr[13] = 0x814b4fc0; - } + // Setup pointers like real BS2 does + if (SConfig::GetInstance().bNTSC) + { + PowerPC::ppcState.gpr[1] = 0x81566550; // StackPointer, used to be set to 0x816ffff0 + PowerPC::ppcState.gpr[2] = 0x81465cc0; // Global pointer to Small Data Area 2 Base (haven't + // seen anything use it...meh) + PowerPC::ppcState.gpr[13] = + 0x81465320; // Global pointer to Small Data Area Base (Luigi's Mansion's apploader uses it) + } + else + { + PowerPC::ppcState.gpr[1] = 0x815edca8; + PowerPC::ppcState.gpr[2] = 0x814b5b20; + PowerPC::ppcState.gpr[13] = 0x814b4fc0; + } - // TODO - Make Apploader(or just RunFunction()) debuggable!!! + // TODO - Make Apploader(or just RunFunction()) debuggable!!! - // Call iAppLoaderEntry. - DEBUG_LOG(MASTER_LOG, "Call iAppLoaderEntry"); - u32 iAppLoaderFuncAddr = 0x80003100; - PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0; - PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4; - PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8; - RunFunction(apploader_entry); - u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0); - u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4); - u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8); + // Call iAppLoaderEntry. + DEBUG_LOG(MASTER_LOG, "Call iAppLoaderEntry"); + u32 iAppLoaderFuncAddr = 0x80003100; + PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0; + PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4; + PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8; + RunFunction(apploader_entry); + u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0); + u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4); + u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8); - // iAppLoaderInit - DEBUG_LOG(MASTER_LOG, "Call iAppLoaderInit"); - PowerPC::ppcState.gpr[3] = 0x81300000; - RunFunction(iAppLoaderInit); + // iAppLoaderInit + DEBUG_LOG(MASTER_LOG, "Call iAppLoaderInit"); + PowerPC::ppcState.gpr[3] = 0x81300000; + RunFunction(iAppLoaderInit); - // iAppLoaderMain - Here we load the apploader, the DOL (the exe) and the FST (filesystem). - // To give you an idea about where the stuff is located on the disc take a look at yagcd - // ch 13. - DEBUG_LOG(MASTER_LOG, "Call iAppLoaderMain"); - do - { - PowerPC::ppcState.gpr[3] = 0x81300004; - PowerPC::ppcState.gpr[4] = 0x81300008; - PowerPC::ppcState.gpr[5] = 0x8130000c; + // iAppLoaderMain - Here we load the apploader, the DOL (the exe) and the FST (filesystem). + // To give you an idea about where the stuff is located on the disc take a look at yagcd + // ch 13. + DEBUG_LOG(MASTER_LOG, "Call iAppLoaderMain"); + do + { + PowerPC::ppcState.gpr[3] = 0x81300004; + PowerPC::ppcState.gpr[4] = 0x81300008; + PowerPC::ppcState.gpr[5] = 0x8130000c; - RunFunction(iAppLoaderMain); + RunFunction(iAppLoaderMain); - u32 iRamAddress = PowerPC::Read_U32(0x81300004); - u32 iLength = PowerPC::Read_U32(0x81300008); - u32 iDVDOffset = PowerPC::Read_U32(0x8130000c); + u32 iRamAddress = PowerPC::Read_U32(0x81300004); + u32 iLength = PowerPC::Read_U32(0x81300008); + u32 iDVDOffset = PowerPC::Read_U32(0x8130000c); - INFO_LOG(MASTER_LOG, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength); - DVDRead(iDVDOffset, iRamAddress, iLength, false); + INFO_LOG(MASTER_LOG, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, + iRamAddress, iLength); + DVDRead(iDVDOffset, iRamAddress, iLength, false); - } while (PowerPC::ppcState.gpr[3] != 0x00); + } while (PowerPC::ppcState.gpr[3] != 0x00); - // iAppLoaderClose - DEBUG_LOG(MASTER_LOG, "call iAppLoaderClose"); - RunFunction(iAppLoaderClose); + // iAppLoaderClose + DEBUG_LOG(MASTER_LOG, "call iAppLoaderClose"); + RunFunction(iAppLoaderClose); - // return - PC = PowerPC::ppcState.gpr[3]; + // return + PC = PowerPC::ppcState.gpr[3]; - // Load patches - PatchEngine::LoadPatches(); + // Load patches + PatchEngine::LoadPatches(); - // If we have any patches that need to be applied very early, here's a good place - PatchEngine::ApplyFramePatches(); + // If we have any patches that need to be applied very early, here's a good place + PatchEngine::ApplyFramePatches(); - return true; + return true; } bool CBoot::SetupWiiMemory(DiscIO::IVolume::ECountry country) { - static const CountrySetting SETTING_EUROPE = {"EUR", "PAL", "EU", "LE"}; - static const CountrySetting SETTING_USA = {"USA", "NTSC", "US", "LU"}; - static const CountrySetting SETTING_JAPAN = {"JPN", "NTSC", "JP", "LJ"}; - static const CountrySetting SETTING_KOREA = {"KOR", "NTSC", "KR", "LKH"}; - static const std::map country_settings = { - {DiscIO::IVolume::COUNTRY_EUROPE, SETTING_EUROPE}, - {DiscIO::IVolume::COUNTRY_USA, SETTING_USA}, - {DiscIO::IVolume::COUNTRY_JAPAN, SETTING_JAPAN}, - {DiscIO::IVolume::COUNTRY_KOREA, SETTING_KOREA}, - //TODO: Determine if Taiwan have their own specific settings. - // Also determine if there are other specific settings - // for other countries. - {DiscIO::IVolume::COUNTRY_TAIWAN, SETTING_JAPAN} - }; - auto entryPos = country_settings.find(country); - const CountrySetting& country_setting = - (entryPos != country_settings.end()) ? - entryPos->second : - (SConfig::GetInstance().bNTSC ? SETTING_USA : SETTING_EUROPE); // default to USA or EUR depending on game's video mode + static const CountrySetting SETTING_EUROPE = {"EUR", "PAL", "EU", "LE"}; + static const CountrySetting SETTING_USA = {"USA", "NTSC", "US", "LU"}; + static const CountrySetting SETTING_JAPAN = {"JPN", "NTSC", "JP", "LJ"}; + static const CountrySetting SETTING_KOREA = {"KOR", "NTSC", "KR", "LKH"}; + static const std::map country_settings = { + {DiscIO::IVolume::COUNTRY_EUROPE, SETTING_EUROPE}, + {DiscIO::IVolume::COUNTRY_USA, SETTING_USA}, + {DiscIO::IVolume::COUNTRY_JAPAN, SETTING_JAPAN}, + {DiscIO::IVolume::COUNTRY_KOREA, SETTING_KOREA}, + // TODO: Determine if Taiwan have their own specific settings. + // Also determine if there are other specific settings + // for other countries. + {DiscIO::IVolume::COUNTRY_TAIWAN, SETTING_JAPAN}}; + auto entryPos = country_settings.find(country); + const CountrySetting& country_setting = + (entryPos != country_settings.end()) ? + entryPos->second : + (SConfig::GetInstance().bNTSC ? + SETTING_USA : + SETTING_EUROPE); // default to USA or EUR depending on game's video mode - SettingsHandler gen; - std::string serno; - std::string settings_Filename(Common::GetTitleDataPath(TITLEID_SYSMENU, Common::FROM_SESSION_ROOT) + WII_SETTING); - if (File::Exists(settings_Filename)) - { - File::IOFile settingsFileHandle(settings_Filename, "rb"); - if (settingsFileHandle.ReadBytes((void*)gen.GetData(), SettingsHandler::SETTINGS_SIZE)) - { - gen.Decrypt(); - serno = gen.GetValue("SERNO"); - gen.Reset(); - } - File::Delete(settings_Filename); - } + SettingsHandler gen; + std::string serno; + std::string settings_Filename( + Common::GetTitleDataPath(TITLEID_SYSMENU, Common::FROM_SESSION_ROOT) + WII_SETTING); + if (File::Exists(settings_Filename)) + { + File::IOFile settingsFileHandle(settings_Filename, "rb"); + if (settingsFileHandle.ReadBytes((void*)gen.GetData(), SettingsHandler::SETTINGS_SIZE)) + { + gen.Decrypt(); + serno = gen.GetValue("SERNO"); + gen.Reset(); + } + File::Delete(settings_Filename); + } - if (serno.empty() || serno == "000000000") - { - if (Core::g_want_determinism) - serno = "123456789"; - else - serno = gen.generateSerialNumber(); - INFO_LOG(BOOT, "No previous serial number found, generated one instead: %s", serno.c_str()); - } - else - { - INFO_LOG(BOOT, "Using serial number: %s", serno.c_str()); - } + if (serno.empty() || serno == "000000000") + { + if (Core::g_want_determinism) + serno = "123456789"; + else + serno = gen.generateSerialNumber(); + INFO_LOG(BOOT, "No previous serial number found, generated one instead: %s", serno.c_str()); + } + else + { + INFO_LOG(BOOT, "Using serial number: %s", serno.c_str()); + } - std::string model = "RVL-001(" + country_setting.area + ")"; - gen.AddSetting("AREA", country_setting.area); - gen.AddSetting("MODEL", model); - gen.AddSetting("DVD", "0"); - gen.AddSetting("MPCH", "0x7FFE"); - gen.AddSetting("CODE", country_setting.code); - gen.AddSetting("SERNO", serno); - gen.AddSetting("VIDEO", country_setting.video); - gen.AddSetting("GAME", country_setting.game); + std::string model = "RVL-001(" + country_setting.area + ")"; + gen.AddSetting("AREA", country_setting.area); + gen.AddSetting("MODEL", model); + gen.AddSetting("DVD", "0"); + gen.AddSetting("MPCH", "0x7FFE"); + gen.AddSetting("CODE", country_setting.code); + gen.AddSetting("SERNO", serno); + gen.AddSetting("VIDEO", country_setting.video); + gen.AddSetting("GAME", country_setting.game); - File::CreateFullPath(settings_Filename); - { - File::IOFile settingsFileHandle(settings_Filename, "wb"); + File::CreateFullPath(settings_Filename); + { + File::IOFile settingsFileHandle(settings_Filename, "wb"); - if (!settingsFileHandle.WriteBytes(gen.GetData(), SettingsHandler::SETTINGS_SIZE)) - { - PanicAlertT("SetupWiiMemory: Can't create setting.txt file"); - return false; - } - // Write the 256 byte setting.txt to memory. - Memory::CopyToEmu(0x3800, gen.GetData(), SettingsHandler::SETTINGS_SIZE); - } + if (!settingsFileHandle.WriteBytes(gen.GetData(), SettingsHandler::SETTINGS_SIZE)) + { + PanicAlertT("SetupWiiMemory: Can't create setting.txt file"); + return false; + } + // Write the 256 byte setting.txt to memory. + Memory::CopyToEmu(0x3800, gen.GetData(), SettingsHandler::SETTINGS_SIZE); + } - INFO_LOG(BOOT, "Setup Wii Memory..."); + INFO_LOG(BOOT, "Setup Wii Memory..."); - /* - Set hardcoded global variables to Wii memory. These are partly collected from - WiiBrew. These values are needed for the games to function correctly. A few - values in this region will also be placed here by the game as it boots. - They are: - 0x80000038 Start of FST - 0x8000003c Size of FST Size - 0x80000060 Copyright code - */ + /* + Set hardcoded global variables to Wii memory. These are partly collected from + WiiBrew. These values are needed for the games to function correctly. A few + values in this region will also be placed here by the game as it boots. + They are: + 0x80000038 Start of FST + 0x8000003c Size of FST Size + 0x80000060 Copyright code + */ - // When booting a WAD or the system menu, there will probably not be a disc inserted - if (DVDInterface::VolumeIsValid()) - DVDRead(0x00000000, 0x00000000, 0x20, false); // Game Code + // When booting a WAD or the system menu, there will probably not be a disc inserted + if (DVDInterface::VolumeIsValid()) + DVDRead(0x00000000, 0x00000000, 0x20, false); // Game Code - Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word - Memory::Write_U32(0x00000001, 0x00000024); // Unknown - Memory::Write_U32(Memory::REALRAM_SIZE, 0x00000028); // MEM1 size 24MB - Memory::Write_U32(0x00000023, 0x0000002c); // Production Board Model - Memory::Write_U32(0x00000000, 0x00000030); // Init - Memory::Write_U32(0x817FEC60, 0x00000034); // Init - // 38, 3C should get start, size of FST through apploader - Memory::Write_U32(0x38a00040, 0x00000060); // Exception init - Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init - Memory::Write_U32(Memory::REALRAM_SIZE, 0x000000f0); // "Simulated memory size" (debug mode?) - Memory::Write_U32(0x8179b500, 0x000000f4); // __start - Memory::Write_U32(0x0e7be2c0, 0x000000f8); // Bus speed - Memory::Write_U32(0x2B73A840, 0x000000fc); // CPU speed - Memory::Write_U16(0x0000, 0x000030e6); // Console type - Memory::Write_U32(0x00000000, 0x000030c0); // EXI - Memory::Write_U32(0x00000000, 0x000030c4); // EXI - Memory::Write_U32(0x00000000, 0x000030dc); // Time - Memory::Write_U32(0x00000000, 0x000030d8); // Time - Memory::Write_U16(0x8201, 0x000030e6); // Dev console / debug capable - Memory::Write_U32(0x00000000, 0x000030f0); // Apploader - Memory::Write_U32(0x01800000, 0x00003100); // BAT - Memory::Write_U32(0x01800000, 0x00003104); // BAT - Memory::Write_U32(0x00000000, 0x0000310c); // Init - Memory::Write_U32(0x8179d500, 0x00003110); // Init - Memory::Write_U32(0x04000000, 0x00003118); // Unknown - Memory::Write_U32(0x04000000, 0x0000311c); // BAT - Memory::Write_U32(0x93400000, 0x00003120); // BAT - Memory::Write_U32(0x90000800, 0x00003124); // Init - MEM2 low - Memory::Write_U32(0x93ae0000, 0x00003128); // Init - MEM2 high - Memory::Write_U32(0x93ae0000, 0x00003130); // IOS MEM2 low - Memory::Write_U32(0x93b00000, 0x00003134); // IOS MEM2 high - Memory::Write_U32(0x00000012, 0x00003138); // Console type - // 40 is copied from 88 after running apploader - Memory::Write_U32(0x00090204, 0x00003140); // IOS revision (IOS9, v2.4) - Memory::Write_U32(0x00062507, 0x00003144); // IOS date in USA format (June 25, 2007) - Memory::Write_U16(0x0113, 0x0000315e); // Apploader - Memory::Write_U32(0x0000FF16, 0x00003158); // DDR ram vendor code - Memory::Write_U32(0x00000000, 0x00003160); // Init semaphore (sysmenu waits for this to clear) - Memory::Write_U32(0x00090204, 0x00003188); // Expected IOS revision + Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word + Memory::Write_U32(0x00000001, 0x00000024); // Unknown + Memory::Write_U32(Memory::REALRAM_SIZE, 0x00000028); // MEM1 size 24MB + Memory::Write_U32(0x00000023, 0x0000002c); // Production Board Model + Memory::Write_U32(0x00000000, 0x00000030); // Init + Memory::Write_U32(0x817FEC60, 0x00000034); // Init + // 38, 3C should get start, size of FST through apploader + Memory::Write_U32(0x38a00040, 0x00000060); // Exception init + Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init + Memory::Write_U32(Memory::REALRAM_SIZE, 0x000000f0); // "Simulated memory size" (debug mode?) + Memory::Write_U32(0x8179b500, 0x000000f4); // __start + Memory::Write_U32(0x0e7be2c0, 0x000000f8); // Bus speed + Memory::Write_U32(0x2B73A840, 0x000000fc); // CPU speed + Memory::Write_U16(0x0000, 0x000030e6); // Console type + Memory::Write_U32(0x00000000, 0x000030c0); // EXI + Memory::Write_U32(0x00000000, 0x000030c4); // EXI + Memory::Write_U32(0x00000000, 0x000030dc); // Time + Memory::Write_U32(0x00000000, 0x000030d8); // Time + Memory::Write_U16(0x8201, 0x000030e6); // Dev console / debug capable + Memory::Write_U32(0x00000000, 0x000030f0); // Apploader + Memory::Write_U32(0x01800000, 0x00003100); // BAT + Memory::Write_U32(0x01800000, 0x00003104); // BAT + Memory::Write_U32(0x00000000, 0x0000310c); // Init + Memory::Write_U32(0x8179d500, 0x00003110); // Init + Memory::Write_U32(0x04000000, 0x00003118); // Unknown + Memory::Write_U32(0x04000000, 0x0000311c); // BAT + Memory::Write_U32(0x93400000, 0x00003120); // BAT + Memory::Write_U32(0x90000800, 0x00003124); // Init - MEM2 low + Memory::Write_U32(0x93ae0000, 0x00003128); // Init - MEM2 high + Memory::Write_U32(0x93ae0000, 0x00003130); // IOS MEM2 low + Memory::Write_U32(0x93b00000, 0x00003134); // IOS MEM2 high + Memory::Write_U32(0x00000012, 0x00003138); // Console type + // 40 is copied from 88 after running apploader + Memory::Write_U32(0x00090204, 0x00003140); // IOS revision (IOS9, v2.4) + Memory::Write_U32(0x00062507, 0x00003144); // IOS date in USA format (June 25, 2007) + Memory::Write_U16(0x0113, 0x0000315e); // Apploader + Memory::Write_U32(0x0000FF16, 0x00003158); // DDR ram vendor code + Memory::Write_U32(0x00000000, 0x00003160); // Init semaphore (sysmenu waits for this to clear) + Memory::Write_U32(0x00090204, 0x00003188); // Expected IOS revision - Memory::Write_U8(0x80, 0x0000315c); // OSInit - Memory::Write_U16(0x0000, 0x000030e0); // PADInit - Memory::Write_U32(0x80000000, 0x00003184); // GameID Address + Memory::Write_U8(0x80, 0x0000315c); // OSInit + Memory::Write_U16(0x0000, 0x000030e0); // PADInit + Memory::Write_U32(0x80000000, 0x00003184); // GameID Address - // Fake the VI Init of the IPL - Memory::Write_U32(SConfig::GetInstance().bNTSC ? 0 : 1, 0x000000CC); + // Fake the VI Init of the IPL + Memory::Write_U32(SConfig::GetInstance().bNTSC ? 0 : 1, 0x000000CC); - // Clear exception handler. Why? Don't we begin with only zeros? - for (int i = 0x3000; i <= 0x3038; i += 4) - { - Memory::Write_U32(0x00000000, i); - } - return true; + // Clear exception handler. Why? Don't we begin with only zeros? + for (int i = 0x3000; i <= 0x3038; i += 4) + { + Memory::Write_U32(0x00000000, i); + } + return true; } // __________________________________________________________________________________________________ @@ -319,129 +330,131 @@ bool CBoot::SetupWiiMemory(DiscIO::IVolume::ECountry country) // execute the apploader bool CBoot::EmulatedBS2_Wii() { - INFO_LOG(BOOT, "Faking Wii BS2..."); + INFO_LOG(BOOT, "Faking Wii BS2..."); - // Setup Wii memory - DiscIO::IVolume::ECountry country_code = DiscIO::IVolume::COUNTRY_UNKNOWN; - if (DVDInterface::VolumeIsValid()) - country_code = DVDInterface::GetVolume().GetCountry(); - if (SetupWiiMemory(country_code) == false) - return false; + // Setup Wii memory + DiscIO::IVolume::ECountry country_code = DiscIO::IVolume::COUNTRY_UNKNOWN; + if (DVDInterface::VolumeIsValid()) + country_code = DVDInterface::GetVolume().GetCountry(); + if (SetupWiiMemory(country_code) == false) + return false; - // Execute the apploader - bool apploaderRan = false; - if (DVDInterface::VolumeIsValid() && DVDInterface::GetVolume().GetVolumeType() == DiscIO::IVolume::WII_DISC) - { - // This is some kind of consistency check that is compared to the 0x00 - // values as the game boots. This location keeps the 4 byte ID for as long - // as the game is running. The 6 byte ID at 0x00 is overwritten sometime - // after this check during booting. - DVDRead(0, 0x3180, 4, true); + // Execute the apploader + bool apploaderRan = false; + if (DVDInterface::VolumeIsValid() && + DVDInterface::GetVolume().GetVolumeType() == DiscIO::IVolume::WII_DISC) + { + // This is some kind of consistency check that is compared to the 0x00 + // values as the game boots. This location keeps the 4 byte ID for as long + // as the game is running. The 6 byte ID at 0x00 is overwritten sometime + // after this check during booting. + DVDRead(0, 0x3180, 4, true); - // Set up MSR and the BAT SPR registers. - UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr); - m_MSR.FP = 1; - m_MSR.DR = 1; - m_MSR.IR = 1; - m_MSR.EE = 1; - PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff; - PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; - PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff; - PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002; - PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; - PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; - PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; - PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; - PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff; - PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002; - PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff; - PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a; + // Set up MSR and the BAT SPR registers. + UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr); + m_MSR.FP = 1; + m_MSR.DR = 1; + m_MSR.IR = 1; + m_MSR.EE = 1; + PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff; + PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; + PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff; + PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002; + PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; + PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; + PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; + PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; + PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff; + PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002; + PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff; + PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a; - Memory::Write_U32(0x4c000064, 0x00000300); // Write default DSI Handler: rfi - Memory::Write_U32(0x4c000064, 0x00000800); // Write default FPU Handler: rfi - Memory::Write_U32(0x4c000064, 0x00000C00); // Write default Syscall Handler: rfi + Memory::Write_U32(0x4c000064, 0x00000300); // Write default DSI Handler: rfi + Memory::Write_U32(0x4c000064, 0x00000800); // Write default FPU Handler: rfi + Memory::Write_U32(0x4c000064, 0x00000C00); // Write default Syscall Handler: rfi - HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader + HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader - PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer + PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer - const u32 apploader_offset = 0x2440; // 0x1c40; + const u32 apploader_offset = 0x2440; // 0x1c40; - // Load Apploader to Memory - const DiscIO::IVolume& volume = DVDInterface::GetVolume(); - u32 apploader_entry, apploader_size; - if (!volume.ReadSwapped(apploader_offset + 0x10, &apploader_entry, true) || - !volume.ReadSwapped(apploader_offset + 0x14, &apploader_size, true) || - apploader_entry == (u32)-1 || apploader_size == (u32)-1) - { - ERROR_LOG(BOOT, "Invalid apploader. Probably your image is corrupted."); - return false; - } - DVDRead(apploader_offset + 0x20, 0x01200000, apploader_size, true); + // Load Apploader to Memory + const DiscIO::IVolume& volume = DVDInterface::GetVolume(); + u32 apploader_entry, apploader_size; + if (!volume.ReadSwapped(apploader_offset + 0x10, &apploader_entry, true) || + !volume.ReadSwapped(apploader_offset + 0x14, &apploader_size, true) || + apploader_entry == (u32)-1 || apploader_size == (u32)-1) + { + ERROR_LOG(BOOT, "Invalid apploader. Probably your image is corrupted."); + return false; + } + DVDRead(apploader_offset + 0x20, 0x01200000, apploader_size, true); - //call iAppLoaderEntry - DEBUG_LOG(BOOT, "Call iAppLoaderEntry"); + // call iAppLoaderEntry + DEBUG_LOG(BOOT, "Call iAppLoaderEntry"); - u32 iAppLoaderFuncAddr = 0x80004000; - PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0; - PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4; - PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8; - RunFunction(apploader_entry); - u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0); - u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4); - u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8); + u32 iAppLoaderFuncAddr = 0x80004000; + PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0; + PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4; + PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8; + RunFunction(apploader_entry); + u32 iAppLoaderInit = PowerPC::Read_U32(iAppLoaderFuncAddr + 0); + u32 iAppLoaderMain = PowerPC::Read_U32(iAppLoaderFuncAddr + 4); + u32 iAppLoaderClose = PowerPC::Read_U32(iAppLoaderFuncAddr + 8); - // iAppLoaderInit - DEBUG_LOG(BOOT, "Run iAppLoaderInit"); - PowerPC::ppcState.gpr[3] = 0x81300000; - RunFunction(iAppLoaderInit); + // iAppLoaderInit + DEBUG_LOG(BOOT, "Run iAppLoaderInit"); + PowerPC::ppcState.gpr[3] = 0x81300000; + RunFunction(iAppLoaderInit); - // Let the apploader load the exe to memory. At this point I get an unknown IPC command - // (command zero) when I load Wii Sports or other games a second time. I don't notice - // any side effects however. It's a little disconcerting however that Start after Stop - // behaves differently than the first Start after starting Dolphin. It means something - // was not reset correctly. - DEBUG_LOG(BOOT, "Run iAppLoaderMain"); - do - { - PowerPC::ppcState.gpr[3] = 0x81300004; - PowerPC::ppcState.gpr[4] = 0x81300008; - PowerPC::ppcState.gpr[5] = 0x8130000c; + // Let the apploader load the exe to memory. At this point I get an unknown IPC command + // (command zero) when I load Wii Sports or other games a second time. I don't notice + // any side effects however. It's a little disconcerting however that Start after Stop + // behaves differently than the first Start after starting Dolphin. It means something + // was not reset correctly. + DEBUG_LOG(BOOT, "Run iAppLoaderMain"); + do + { + PowerPC::ppcState.gpr[3] = 0x81300004; + PowerPC::ppcState.gpr[4] = 0x81300008; + PowerPC::ppcState.gpr[5] = 0x8130000c; - RunFunction(iAppLoaderMain); + RunFunction(iAppLoaderMain); - u32 iRamAddress = PowerPC::Read_U32(0x81300004); - u32 iLength = PowerPC::Read_U32(0x81300008); - u32 iDVDOffset = PowerPC::Read_U32(0x8130000c) << 2; + u32 iRamAddress = PowerPC::Read_U32(0x81300004); + u32 iLength = PowerPC::Read_U32(0x81300008); + u32 iDVDOffset = PowerPC::Read_U32(0x8130000c) << 2; - INFO_LOG(BOOT, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength); - DVDRead(iDVDOffset, iRamAddress, iLength, true); - } while (PowerPC::ppcState.gpr[3] != 0x00); + INFO_LOG(BOOT, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, + iRamAddress, iLength); + DVDRead(iDVDOffset, iRamAddress, iLength, true); + } while (PowerPC::ppcState.gpr[3] != 0x00); - // iAppLoaderClose - DEBUG_LOG(BOOT, "Run iAppLoaderClose"); - RunFunction(iAppLoaderClose); + // iAppLoaderClose + DEBUG_LOG(BOOT, "Run iAppLoaderClose"); + RunFunction(iAppLoaderClose); - apploaderRan = true; + apploaderRan = true; - // Pass the "#002 check" - // Apploader writes the IOS version and revision here, we copy it - // Fake IOSv9 r2.4 if no version is found (elf loading) - u32 firmwareVer = PowerPC::Read_U32(0x80003188); - PowerPC::Write_U32(firmwareVer ? firmwareVer : 0x00090204, 0x80003140); + // Pass the "#002 check" + // Apploader writes the IOS version and revision here, we copy it + // Fake IOSv9 r2.4 if no version is found (elf loading) + u32 firmwareVer = PowerPC::Read_U32(0x80003188); + PowerPC::Write_U32(firmwareVer ? firmwareVer : 0x00090204, 0x80003140); - // Load patches and run startup patches - PatchEngine::LoadPatches(); + // Load patches and run startup patches + PatchEngine::LoadPatches(); - // return - PC = PowerPC::ppcState.gpr[3]; - } + // return + PC = PowerPC::ppcState.gpr[3]; + } - return apploaderRan; + return apploaderRan; } // Returns true if apploader has run successfully bool CBoot::EmulatedBS2(bool _bIsWii) { - return _bIsWii ? EmulatedBS2_Wii() : EmulatedBS2_GC(); + return _bIsWii ? EmulatedBS2_Wii() : EmulatedBS2_GC(); } diff --git a/Source/Core/Core/Boot/Boot_DOL.cpp b/Source/Core/Core/Boot/Boot_DOL.cpp index 87dcb1b5f5..cd2660e645 100644 --- a/Source/Core/Core/Boot/Boot_DOL.cpp +++ b/Source/Core/Core/Boot/Boot_DOL.cpp @@ -14,20 +14,20 @@ CDolLoader::CDolLoader(const std::vector& buffer) { - m_is_valid = Initialize(buffer); + m_is_valid = Initialize(buffer); } CDolLoader::CDolLoader(const std::string& filename) { - const u64 size = File::GetSize(filename); - std::vector temp_buffer(size); + const u64 size = File::GetSize(filename); + std::vector temp_buffer(size); - { - File::IOFile pStream(filename, "rb"); - pStream.ReadBytes(temp_buffer.data(), temp_buffer.size()); - } + { + File::IOFile pStream(filename, "rb"); + pStream.ReadBytes(temp_buffer.data(), temp_buffer.size()); + } - m_is_valid = Initialize(temp_buffer); + m_is_valid = Initialize(temp_buffer); } CDolLoader::~CDolLoader() @@ -36,76 +36,78 @@ CDolLoader::~CDolLoader() bool CDolLoader::Initialize(const std::vector& buffer) { - if (buffer.size() < sizeof(SDolHeader)) - return false; + if (buffer.size() < sizeof(SDolHeader)) + return false; - memcpy(&m_dolheader, buffer.data(), sizeof(SDolHeader)); + memcpy(&m_dolheader, buffer.data(), sizeof(SDolHeader)); - // swap memory - u32* p = (u32*)&m_dolheader; - for (size_t i = 0; i < (sizeof(SDolHeader) / sizeof(u32)); i++) - p[i] = Common::swap32(p[i]); + // swap memory + u32* p = (u32*)&m_dolheader; + for (size_t i = 0; i < (sizeof(SDolHeader) / sizeof(u32)); i++) + p[i] = Common::swap32(p[i]); - const u32 HID4_pattern = Common::swap32(0x7c13fba6); - const u32 HID4_mask = Common::swap32(0xfc1fffff); + const u32 HID4_pattern = Common::swap32(0x7c13fba6); + const u32 HID4_mask = Common::swap32(0xfc1fffff); - m_is_wii = false; + m_is_wii = false; - m_text_sections.reserve(DOL_NUM_TEXT); - for (int i = 0; i < DOL_NUM_TEXT; ++i) - { - if (m_dolheader.textSize[i] != 0) - { - if (buffer.size() < m_dolheader.textOffset[i] + m_dolheader.textSize[i]) - return false; + m_text_sections.reserve(DOL_NUM_TEXT); + for (int i = 0; i < DOL_NUM_TEXT; ++i) + { + if (m_dolheader.textSize[i] != 0) + { + if (buffer.size() < m_dolheader.textOffset[i] + m_dolheader.textSize[i]) + return false; - const u8* text_start = &buffer[m_dolheader.textOffset[i]]; - m_text_sections.emplace_back(text_start, &text_start[m_dolheader.textSize[i]]); + const u8* text_start = &buffer[m_dolheader.textOffset[i]]; + m_text_sections.emplace_back(text_start, &text_start[m_dolheader.textSize[i]]); - for (unsigned int j = 0; !m_is_wii && j < (m_dolheader.textSize[i] / sizeof(u32)); ++j) - { - u32 word = ((u32*)text_start)[j]; - if ((word & HID4_mask) == HID4_pattern) - m_is_wii = true; - } - } - else - { - // Make sure that m_text_sections indexes match header indexes - m_text_sections.emplace_back(); - } - } + for (unsigned int j = 0; !m_is_wii && j < (m_dolheader.textSize[i] / sizeof(u32)); ++j) + { + u32 word = ((u32*)text_start)[j]; + if ((word & HID4_mask) == HID4_pattern) + m_is_wii = true; + } + } + else + { + // Make sure that m_text_sections indexes match header indexes + m_text_sections.emplace_back(); + } + } - m_data_sections.reserve(DOL_NUM_DATA); - for (int i = 0; i < DOL_NUM_DATA; ++i) - { - if (m_dolheader.dataSize[i] != 0) - { - if (buffer.size() < m_dolheader.dataOffset[i] + m_dolheader.dataSize[i]) - return false; + m_data_sections.reserve(DOL_NUM_DATA); + for (int i = 0; i < DOL_NUM_DATA; ++i) + { + if (m_dolheader.dataSize[i] != 0) + { + if (buffer.size() < m_dolheader.dataOffset[i] + m_dolheader.dataSize[i]) + return false; - const u8* data_start = &buffer[m_dolheader.dataOffset[i]]; - m_data_sections.emplace_back(data_start, &data_start[m_dolheader.dataSize[i]]); - } - else - { - // Make sure that m_data_sections indexes match header indexes - m_data_sections.emplace_back(); - } - } + const u8* data_start = &buffer[m_dolheader.dataOffset[i]]; + m_data_sections.emplace_back(data_start, &data_start[m_dolheader.dataSize[i]]); + } + else + { + // Make sure that m_data_sections indexes match header indexes + m_data_sections.emplace_back(); + } + } - return true; + return true; } void CDolLoader::Load() const { - // load all text (code) sections - for (size_t i = 0; i < m_text_sections.size(); ++i) - if (!m_text_sections[i].empty()) - Memory::CopyToEmu(m_dolheader.textAddress[i], m_text_sections[i].data(), m_text_sections[i].size()); + // load all text (code) sections + for (size_t i = 0; i < m_text_sections.size(); ++i) + if (!m_text_sections[i].empty()) + Memory::CopyToEmu(m_dolheader.textAddress[i], m_text_sections[i].data(), + m_text_sections[i].size()); - // load all data sections - for (size_t i = 0; i < m_data_sections.size(); ++i) - if (!m_data_sections[i].empty()) - Memory::CopyToEmu(m_dolheader.dataAddress[i], m_data_sections[i].data(), m_data_sections[i].size()); + // load all data sections + for (size_t i = 0; i < m_data_sections.size(); ++i) + if (!m_data_sections[i].empty()) + Memory::CopyToEmu(m_dolheader.dataAddress[i], m_data_sections[i].data(), + m_data_sections[i].size()); } diff --git a/Source/Core/Core/Boot/Boot_DOL.h b/Source/Core/Core/Boot/Boot_DOL.h index 7b055d3850..f415e35705 100644 --- a/Source/Core/Core/Boot/Boot_DOL.h +++ b/Source/Core/Core/Boot/Boot_DOL.h @@ -12,47 +12,46 @@ class CDolLoader { public: - CDolLoader(const std::string& filename); - CDolLoader(const std::vector& buffer); - ~CDolLoader(); + CDolLoader(const std::string& filename); + CDolLoader(const std::vector& buffer); + ~CDolLoader(); - bool IsValid() const { return m_is_valid; } - bool IsWii() const { return m_is_wii; } - u32 GetEntryPoint() const { return m_dolheader.entryPoint; } - - // Load into emulated memory - void Load() const; + bool IsValid() const { return m_is_valid; } + bool IsWii() const { return m_is_wii; } + u32 GetEntryPoint() const { return m_dolheader.entryPoint; } + // Load into emulated memory + void Load() const; private: - enum - { - DOL_NUM_TEXT = 7, - DOL_NUM_DATA = 11 - }; + enum + { + DOL_NUM_TEXT = 7, + DOL_NUM_DATA = 11 + }; - struct SDolHeader - { - u32 textOffset[DOL_NUM_TEXT]; - u32 dataOffset[DOL_NUM_DATA]; + struct SDolHeader + { + u32 textOffset[DOL_NUM_TEXT]; + u32 dataOffset[DOL_NUM_DATA]; - u32 textAddress[DOL_NUM_TEXT]; - u32 dataAddress[DOL_NUM_DATA]; + u32 textAddress[DOL_NUM_TEXT]; + u32 dataAddress[DOL_NUM_DATA]; - u32 textSize[DOL_NUM_TEXT]; - u32 dataSize[DOL_NUM_DATA]; + u32 textSize[DOL_NUM_TEXT]; + u32 dataSize[DOL_NUM_DATA]; - u32 bssAddress; - u32 bssSize; - u32 entryPoint; - }; - SDolHeader m_dolheader; + u32 bssAddress; + u32 bssSize; + u32 entryPoint; + }; + SDolHeader m_dolheader; - std::vector> m_data_sections; - std::vector> m_text_sections; + std::vector> m_data_sections; + std::vector> m_text_sections; - bool m_is_valid; - bool m_is_wii; + bool m_is_valid; + bool m_is_wii; - // Copy sections to internal buffers - bool Initialize(const std::vector& buffer); + // Copy sections to internal buffers + bool Initialize(const std::vector& buffer); }; diff --git a/Source/Core/Core/Boot/Boot_ELF.cpp b/Source/Core/Core/Boot/Boot_ELF.cpp index 447e6f6f7b..6a41359f9b 100644 --- a/Source/Core/Core/Boot/Boot_ELF.cpp +++ b/Source/Core/Core/Boot/Boot_ELF.cpp @@ -12,91 +12,90 @@ bool CBoot::IsElfWii(const std::string& filename) { - /* We already check if filename existed before we called this function, so - there is no need for another check, just read the file right away */ + /* We already check if filename existed before we called this function, so + there is no need for another check, just read the file right away */ - size_t filesize = File::GetSize(filename); - auto elf = std::make_unique(filesize); + size_t filesize = File::GetSize(filename); + auto elf = std::make_unique(filesize); - { - File::IOFile f(filename, "rb"); - f.ReadBytes(elf.get(), filesize); - } + { + File::IOFile f(filename, "rb"); + f.ReadBytes(elf.get(), filesize); + } - // Use the same method as the DOL loader uses: search for mfspr from HID4, - // which should only be used in Wii ELFs. - // - // Likely to have some false positives/negatives, patches implementing a - // better heuristic are welcome. + // Use the same method as the DOL loader uses: search for mfspr from HID4, + // which should only be used in Wii ELFs. + // + // Likely to have some false positives/negatives, patches implementing a + // better heuristic are welcome. - // Swap these once, instead of swapping every word in the file. - u32 HID4_pattern = Common::swap32(0x7c13fba6); - u32 HID4_mask = Common::swap32(0xfc1fffff); - ElfReader reader(elf.get()); + // Swap these once, instead of swapping every word in the file. + u32 HID4_pattern = Common::swap32(0x7c13fba6); + u32 HID4_mask = Common::swap32(0xfc1fffff); + ElfReader reader(elf.get()); - for (int i = 0; i < reader.GetNumSections(); ++i) - { - if (reader.IsCodeSection(i)) - { - u32* code = (u32*)reader.GetSectionDataPtr(i); - for (u32 j = 0; j < reader.GetSectionSize(i) / sizeof(u32); ++j) - { - if ((code[j] & HID4_mask) == HID4_pattern) - return true; - } - } - } + for (int i = 0; i < reader.GetNumSections(); ++i) + { + if (reader.IsCodeSection(i)) + { + u32* code = (u32*)reader.GetSectionDataPtr(i); + for (u32 j = 0; j < reader.GetSectionSize(i) / sizeof(u32); ++j) + { + if ((code[j] & HID4_mask) == HID4_pattern) + return true; + } + } + } - return false; + return false; } - bool CBoot::Boot_ELF(const std::string& filename) { - // Read ELF from file - size_t filesize = File::GetSize(filename); - auto elf = std::make_unique(filesize); + // Read ELF from file + size_t filesize = File::GetSize(filename); + auto elf = std::make_unique(filesize); - { - File::IOFile f(filename, "rb"); - f.ReadBytes(elf.get(), filesize); - } + { + File::IOFile f(filename, "rb"); + f.ReadBytes(elf.get(), filesize); + } - // Load ELF into GameCube Memory - ElfReader reader(elf.get()); - if (!reader.LoadIntoMemory()) - return false; + // Load ELF into GameCube Memory + ElfReader reader(elf.get()); + if (!reader.LoadIntoMemory()) + return false; - // Set up MSR and the BAT SPR registers. - UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr); - m_MSR.FP = 1; - m_MSR.DR = 1; - m_MSR.IR = 1; - m_MSR.EE = 1; - PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff; - PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; - PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff; - PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002; - PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; - PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; - PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; - PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; - PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff; - PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002; - PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff; - PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a; + // Set up MSR and the BAT SPR registers. + UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr); + m_MSR.FP = 1; + m_MSR.DR = 1; + m_MSR.IR = 1; + m_MSR.EE = 1; + PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff; + PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; + PowerPC::ppcState.spr[SPR_IBAT4U] = 0x90001fff; + PowerPC::ppcState.spr[SPR_IBAT4L] = 0x10000002; + PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; + PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; + PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; + PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; + PowerPC::ppcState.spr[SPR_DBAT4U] = 0x90001fff; + PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002; + PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff; + PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a; - if (!reader.LoadSymbols()) - { - if (LoadMapFromFilename()) - HLE::PatchFunctions(); - } - else - { - HLE::PatchFunctions(); - } + if (!reader.LoadSymbols()) + { + if (LoadMapFromFilename()) + HLE::PatchFunctions(); + } + else + { + HLE::PatchFunctions(); + } - PC = reader.GetEntryPoint(); + PC = reader.GetEntryPoint(); - return true; + return true; } diff --git a/Source/Core/Core/Boot/Boot_WiiWAD.cpp b/Source/Core/Core/Boot/Boot_WiiWAD.cpp index 2d27231426..6586f5084a 100644 --- a/Source/Core/Core/Boot/Boot_WiiWAD.cpp +++ b/Source/Core/Core/Boot/Boot_WiiWAD.cpp @@ -9,15 +9,15 @@ #include "Common/FileUtil.h" #include "Common/NandPaths.h" -#include "Core/ConfigManager.h" -#include "Core/PatchEngine.h" #include "Core/Boot/Boot.h" #include "Core/Boot/Boot_DOL.h" +#include "Core/ConfigManager.h" #include "Core/HLE/HLE.h" #include "Core/HW/Memmap.h" #include "Core/HW/VideoInterface.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h" +#include "Core/PatchEngine.h" #include "Core/PowerPC/PowerPC.h" #include "DiscIO/NANDContentLoader.h" @@ -25,104 +25,106 @@ #include "DiscIO/VolumeCreator.h" #include "DiscIO/WiiWad.h" -static u32 state_checksum(u32 *buf, int len) +static u32 state_checksum(u32* buf, int len) { - u32 checksum = 0; - len = len >> 2; + u32 checksum = 0; + len = len >> 2; - for (int i = 0; i < len; i++) - { - checksum += buf[i]; - } + for (int i = 0; i < len; i++) + { + checksum += buf[i]; + } - return checksum; + return checksum; } struct StateFlags { - u32 checksum; - u8 flags; - u8 type; - u8 discstate; - u8 returnto; - u32 unknown[6]; + u32 checksum; + u8 flags; + u8 type; + u8 discstate; + u8 returnto; + u32 unknown[6]; }; bool CBoot::Boot_WiiWAD(const std::string& _pFilename) { - std::string state_filename(Common::GetTitleDataPath(TITLEID_SYSMENU, Common::FROM_SESSION_ROOT) + WII_STATE); + std::string state_filename(Common::GetTitleDataPath(TITLEID_SYSMENU, Common::FROM_SESSION_ROOT) + + WII_STATE); - if (File::Exists(state_filename)) - { - File::IOFile state_file(state_filename, "r+b"); - StateFlags state; - state_file.ReadBytes(&state, sizeof(StateFlags)); + if (File::Exists(state_filename)) + { + File::IOFile state_file(state_filename, "r+b"); + StateFlags state; + state_file.ReadBytes(&state, sizeof(StateFlags)); - state.type = 0x03; // TYPE_RETURN - state.checksum = state_checksum((u32*)&state.flags, sizeof(StateFlags) - 4); + state.type = 0x03; // TYPE_RETURN + state.checksum = state_checksum((u32*)&state.flags, sizeof(StateFlags) - 4); - state_file.Seek(0, SEEK_SET); - state_file.WriteBytes(&state, sizeof(StateFlags)); - } - else - { - File::CreateFullPath(state_filename); - File::IOFile state_file(state_filename, "a+b"); - StateFlags state; - memset(&state, 0, sizeof(StateFlags)); - state.type = 0x03; // TYPE_RETURN - state.discstate = 0x01; // DISCSTATE_WII - state.checksum = state_checksum((u32*)&state.flags, sizeof(StateFlags) - 4); - state_file.WriteBytes(&state, sizeof(StateFlags)); - } + state_file.Seek(0, SEEK_SET); + state_file.WriteBytes(&state, sizeof(StateFlags)); + } + else + { + File::CreateFullPath(state_filename); + File::IOFile state_file(state_filename, "a+b"); + StateFlags state; + memset(&state, 0, sizeof(StateFlags)); + state.type = 0x03; // TYPE_RETURN + state.discstate = 0x01; // DISCSTATE_WII + state.checksum = state_checksum((u32*)&state.flags, sizeof(StateFlags) - 4); + state_file.WriteBytes(&state, sizeof(StateFlags)); + } - const DiscIO::CNANDContentLoader& ContentLoader = DiscIO::CNANDContentManager::Access().GetNANDLoader(_pFilename); - if (!ContentLoader.IsValid()) - return false; + const DiscIO::CNANDContentLoader& ContentLoader = + DiscIO::CNANDContentManager::Access().GetNANDLoader(_pFilename); + if (!ContentLoader.IsValid()) + return false; - u64 titleID = ContentLoader.GetTitleID(); - // create data directory - File::CreateFullPath(Common::GetTitleDataPath(titleID, Common::FROM_SESSION_ROOT)); + u64 titleID = ContentLoader.GetTitleID(); + // create data directory + File::CreateFullPath(Common::GetTitleDataPath(titleID, Common::FROM_SESSION_ROOT)); - if (titleID == TITLEID_SYSMENU) - HLE_IPC_CreateVirtualFATFilesystem(); - // setup Wii memory - if (!SetupWiiMemory(ContentLoader.GetCountry())) - return false; - // this sets a bit that is used to detect NTSC-J - if (ContentLoader.GetCountry() == DiscIO::IVolume::COUNTRY_JAPAN) - { - VideoInterface::SetRegionReg('J'); - } - // DOL - const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(ContentLoader.GetBootIndex()); - if (pContent == nullptr) - return false; + if (titleID == TITLEID_SYSMENU) + HLE_IPC_CreateVirtualFATFilesystem(); + // setup Wii memory + if (!SetupWiiMemory(ContentLoader.GetCountry())) + return false; + // this sets a bit that is used to detect NTSC-J + if (ContentLoader.GetCountry() == DiscIO::IVolume::COUNTRY_JAPAN) + { + VideoInterface::SetRegionReg('J'); + } + // DOL + const DiscIO::SNANDContent* pContent = + ContentLoader.GetContentByIndex(ContentLoader.GetBootIndex()); + if (pContent == nullptr) + return false; - WII_IPC_HLE_Interface::SetDefaultContentFile(_pFilename); + WII_IPC_HLE_Interface::SetDefaultContentFile(_pFilename); - std::unique_ptr pDolLoader = std::make_unique(pContent->m_Data->Get()); - if (!pDolLoader->IsValid()) - return false; + std::unique_ptr pDolLoader = std::make_unique(pContent->m_Data->Get()); + if (!pDolLoader->IsValid()) + return false; - pDolLoader->Load(); - PC = pDolLoader->GetEntryPoint(); + pDolLoader->Load(); + PC = pDolLoader->GetEntryPoint(); - // Pass the "#002 check" - // Apploader should write the IOS version and revision to 0x3140, and compare it - // to 0x3188 to pass the check, but we don't do it, and i don't know where to read the IOS rev... - // Currently we just write 0xFFFF for the revision, copy manually and it works fine :p + // Pass the "#002 check" + // Apploader should write the IOS version and revision to 0x3140, and compare it + // to 0x3188 to pass the check, but we don't do it, and i don't know where to read the IOS rev... + // Currently we just write 0xFFFF for the revision, copy manually and it works fine :p - // TODO : figure it correctly : where should we read the IOS rev that the wad "needs" ? - Memory::Write_U16(ContentLoader.GetIosVersion(), 0x00003140); - Memory::Write_U16(0xFFFF, 0x00003142); - Memory::Write_U32(Memory::Read_U32(0x00003140), 0x00003188); + // TODO : figure it correctly : where should we read the IOS rev that the wad "needs" ? + Memory::Write_U16(ContentLoader.GetIosVersion(), 0x00003140); + Memory::Write_U16(0xFFFF, 0x00003142); + Memory::Write_U32(Memory::Read_U32(0x00003140), 0x00003188); - // Load patches and run startup patches - const std::unique_ptr pVolume(DiscIO::CreateVolumeFromFilename(_pFilename)); - if (pVolume != nullptr) - PatchEngine::LoadPatches(); + // Load patches and run startup patches + const std::unique_ptr pVolume(DiscIO::CreateVolumeFromFilename(_pFilename)); + if (pVolume != nullptr) + PatchEngine::LoadPatches(); - return true; + return true; } - diff --git a/Source/Core/Core/Boot/ElfReader.cpp b/Source/Core/Core/Boot/ElfReader.cpp index dbf911123b..6f86130de9 100644 --- a/Source/Core/Core/Boot/ElfReader.cpp +++ b/Source/Core/Core/Boot/ElfReader.cpp @@ -13,183 +13,191 @@ #include "Core/HW/Memmap.h" #include "Core/PowerPC/PPCSymbolDB.h" -static void bswap(u32 &w) {w = Common::swap32(w);} -static void bswap(u16 &w) {w = Common::swap16(w);} - -static void byteswapHeader(Elf32_Ehdr &ELF_H) +static void bswap(u32& w) { - bswap(ELF_H.e_type); - bswap(ELF_H.e_machine); - bswap(ELF_H.e_ehsize); - bswap(ELF_H.e_phentsize); - bswap(ELF_H.e_phnum); - bswap(ELF_H.e_shentsize); - bswap(ELF_H.e_shnum); - bswap(ELF_H.e_shstrndx); - bswap(ELF_H.e_version); - bswap(ELF_H.e_entry); - bswap(ELF_H.e_phoff); - bswap(ELF_H.e_shoff); - bswap(ELF_H.e_flags); + w = Common::swap32(w); +} +static void bswap(u16& w) +{ + w = Common::swap16(w); } -static void byteswapSegment(Elf32_Phdr &sec) +static void byteswapHeader(Elf32_Ehdr& ELF_H) { - bswap(sec.p_align); - bswap(sec.p_filesz); - bswap(sec.p_flags); - bswap(sec.p_memsz); - bswap(sec.p_offset); - bswap(sec.p_paddr); - bswap(sec.p_vaddr); - bswap(sec.p_type); + bswap(ELF_H.e_type); + bswap(ELF_H.e_machine); + bswap(ELF_H.e_ehsize); + bswap(ELF_H.e_phentsize); + bswap(ELF_H.e_phnum); + bswap(ELF_H.e_shentsize); + bswap(ELF_H.e_shnum); + bswap(ELF_H.e_shstrndx); + bswap(ELF_H.e_version); + bswap(ELF_H.e_entry); + bswap(ELF_H.e_phoff); + bswap(ELF_H.e_shoff); + bswap(ELF_H.e_flags); } -static void byteswapSection(Elf32_Shdr &sec) +static void byteswapSegment(Elf32_Phdr& sec) { - bswap(sec.sh_addr); - bswap(sec.sh_addralign); - bswap(sec.sh_entsize); - bswap(sec.sh_flags); - bswap(sec.sh_info); - bswap(sec.sh_link); - bswap(sec.sh_name); - bswap(sec.sh_offset); - bswap(sec.sh_size); - bswap(sec.sh_type); + bswap(sec.p_align); + bswap(sec.p_filesz); + bswap(sec.p_flags); + bswap(sec.p_memsz); + bswap(sec.p_offset); + bswap(sec.p_paddr); + bswap(sec.p_vaddr); + bswap(sec.p_type); } -ElfReader::ElfReader(void *ptr) +static void byteswapSection(Elf32_Shdr& sec) { - base = (char*)ptr; - base32 = (u32*)ptr; - header = (Elf32_Ehdr*)ptr; - byteswapHeader(*header); + bswap(sec.sh_addr); + bswap(sec.sh_addralign); + bswap(sec.sh_entsize); + bswap(sec.sh_flags); + bswap(sec.sh_info); + bswap(sec.sh_link); + bswap(sec.sh_name); + bswap(sec.sh_offset); + bswap(sec.sh_size); + bswap(sec.sh_type); +} - segments = (Elf32_Phdr *)(base + header->e_phoff); - sections = (Elf32_Shdr *)(base + header->e_shoff); +ElfReader::ElfReader(void* ptr) +{ + base = (char*)ptr; + base32 = (u32*)ptr; + header = (Elf32_Ehdr*)ptr; + byteswapHeader(*header); - for (int i = 0; i < GetNumSegments(); i++) - { - byteswapSegment(segments[i]); - } + segments = (Elf32_Phdr*)(base + header->e_phoff); + sections = (Elf32_Shdr*)(base + header->e_shoff); - for (int i = 0; i < GetNumSections(); i++) - { - byteswapSection(sections[i]); - } - entryPoint = header->e_entry; + for (int i = 0; i < GetNumSegments(); i++) + { + byteswapSegment(segments[i]); + } + + for (int i = 0; i < GetNumSections(); i++) + { + byteswapSection(sections[i]); + } + entryPoint = header->e_entry; } const char* ElfReader::GetSectionName(int section) const { - if (sections[section].sh_type == SHT_NULL) - return nullptr; + if (sections[section].sh_type == SHT_NULL) + return nullptr; - int nameOffset = sections[section].sh_name; - char* ptr = (char*)GetSectionDataPtr(header->e_shstrndx); + int nameOffset = sections[section].sh_name; + char* ptr = (char*)GetSectionDataPtr(header->e_shstrndx); - if (ptr) - return ptr + nameOffset; - else - return nullptr; + if (ptr) + return ptr + nameOffset; + else + return nullptr; } // This is just a simple elf loader, good enough to load elfs generated by devkitPPC bool ElfReader::LoadIntoMemory() { - DEBUG_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx); + DEBUG_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx); - // Should we relocate? - bRelocate = (header->e_type != ET_EXEC); + // Should we relocate? + bRelocate = (header->e_type != ET_EXEC); - if (bRelocate) - { - PanicAlert("Error: Dolphin doesn't know how to load a relocatable elf."); - return false; - } + if (bRelocate) + { + PanicAlert("Error: Dolphin doesn't know how to load a relocatable elf."); + return false; + } - INFO_LOG(MASTER_LOG, "%i segments:", header->e_phnum); + INFO_LOG(MASTER_LOG, "%i segments:", header->e_phnum); - // Copy segments into ram. - for (int i = 0; i < header->e_phnum; i++) - { - Elf32_Phdr* p = segments + i; + // Copy segments into ram. + for (int i = 0; i < header->e_phnum; i++) + { + Elf32_Phdr* p = segments + i; - INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", - p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz); + INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, + p->p_filesz, p->p_memsz); - if (p->p_type == PT_LOAD) - { - u32 writeAddr = p->p_vaddr; - const u8* src = GetSegmentPtr(i); - u32 srcSize = p->p_filesz; - u32 dstSize = p->p_memsz; + if (p->p_type == PT_LOAD) + { + u32 writeAddr = p->p_vaddr; + const u8* src = GetSegmentPtr(i); + u32 srcSize = p->p_filesz; + u32 dstSize = p->p_memsz; - Memory::CopyToEmu(writeAddr, src, srcSize); - if (srcSize < dstSize) - Memory::Memset(writeAddr + srcSize, 0, dstSize - srcSize); //zero out bss + Memory::CopyToEmu(writeAddr, src, srcSize); + if (srcSize < dstSize) + Memory::Memset(writeAddr + srcSize, 0, dstSize - srcSize); // zero out bss - INFO_LOG(MASTER_LOG, "Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz); - } - } + INFO_LOG(MASTER_LOG, "Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz); + } + } - INFO_LOG(MASTER_LOG, "Done loading."); - return true; + INFO_LOG(MASTER_LOG, "Done loading."); + return true; } -SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const +SectionID ElfReader::GetSectionByName(const char* name, int firstSection) const { - for (int i = firstSection; i < header->e_shnum; i++) - { - const char* secname = GetSectionName(i); + for (int i = firstSection; i < header->e_shnum; i++) + { + const char* secname = GetSectionName(i); - if (secname != nullptr && strcmp(name, secname) == 0) - return i; - } - return -1; + if (secname != nullptr && strcmp(name, secname) == 0) + return i; + } + return -1; } bool ElfReader::LoadSymbols() { - bool hasSymbols = false; - SectionID sec = GetSectionByName(".symtab"); - if (sec != -1) - { - int stringSection = sections[sec].sh_link; - const char* stringBase = (const char *)GetSectionDataPtr(stringSection); + bool hasSymbols = false; + SectionID sec = GetSectionByName(".symtab"); + if (sec != -1) + { + int stringSection = sections[sec].sh_link; + const char* stringBase = (const char*)GetSectionDataPtr(stringSection); - //We have a symbol table! - Elf32_Sym* symtab = (Elf32_Sym *)(GetSectionDataPtr(sec)); - int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); - for (int sym = 0; sym < numSymbols; sym++) - { - int size = Common::swap32(symtab[sym].st_size); - if (size == 0) - continue; + // We have a symbol table! + Elf32_Sym* symtab = (Elf32_Sym*)(GetSectionDataPtr(sec)); + int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); + for (int sym = 0; sym < numSymbols; sym++) + { + int size = Common::swap32(symtab[sym].st_size); + if (size == 0) + continue; - // int bind = symtab[sym].st_info >> 4; - int type = symtab[sym].st_info & 0xF; - int sectionIndex = Common::swap16(symtab[sym].st_shndx); - int value = Common::swap32(symtab[sym].st_value); - const char* name = stringBase + Common::swap32(symtab[sym].st_name); - if (bRelocate) - value += sectionAddrs[sectionIndex]; + // int bind = symtab[sym].st_info >> 4; + int type = symtab[sym].st_info & 0xF; + int sectionIndex = Common::swap16(symtab[sym].st_shndx); + int value = Common::swap32(symtab[sym].st_value); + const char* name = stringBase + Common::swap32(symtab[sym].st_name); + if (bRelocate) + value += sectionAddrs[sectionIndex]; - int symtype = Symbol::SYMBOL_DATA; - switch (type) - { - case STT_OBJECT: - symtype = Symbol::SYMBOL_DATA; break; - case STT_FUNC: - symtype = Symbol::SYMBOL_FUNCTION; break; - default: - continue; - } - g_symbolDB.AddKnownSymbol(value, size, name, symtype); - hasSymbols = true; - } - } - g_symbolDB.Index(); - return hasSymbols; + int symtype = Symbol::SYMBOL_DATA; + switch (type) + { + case STT_OBJECT: + symtype = Symbol::SYMBOL_DATA; + break; + case STT_FUNC: + symtype = Symbol::SYMBOL_FUNCTION; + break; + default: + continue; + } + g_symbolDB.AddKnownSymbol(value, size, name, symtype); + hasSymbols = true; + } + } + g_symbolDB.Index(); + return hasSymbols; } diff --git a/Source/Core/Core/Boot/ElfReader.h b/Source/Core/Core/Boot/ElfReader.h index 28822e8a45..b1d57d6aed 100644 --- a/Source/Core/Core/Boot/ElfReader.h +++ b/Source/Core/Core/Boot/ElfReader.h @@ -8,10 +8,10 @@ enum KnownElfTypes { - KNOWNELF_PSP = 0, - KNOWNELF_DS = 1, - KNOWNELF_GBA = 2, - KNOWNELF_GC = 3, + KNOWNELF_PSP = 0, + KNOWNELF_DS = 1, + KNOWNELF_GBA = 2, + KNOWNELF_GC = 3, }; typedef int SectionID; @@ -19,58 +19,47 @@ typedef int SectionID; class ElfReader { private: - char* base; - u32* base32; + char* base; + u32* base32; - Elf32_Ehdr* header; - Elf32_Phdr* segments; - Elf32_Shdr* sections; + Elf32_Ehdr* header; + Elf32_Phdr* segments; + Elf32_Shdr* sections; - u32 *sectionAddrs; - bool bRelocate; - u32 entryPoint; + u32* sectionAddrs; + bool bRelocate; + u32 entryPoint; public: - ElfReader(void* ptr); - ~ElfReader() { } + ElfReader(void* ptr); + ~ElfReader() {} + u32 Read32(int off) const { return base32[off >> 2]; } + // Quick accessors + ElfType GetType() const { return (ElfType)(header->e_type); } + ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } + u32 GetEntryPoint() const { return entryPoint; } + u32 GetFlags() const { return (u32)(header->e_flags); } + bool LoadIntoMemory(); + bool LoadSymbols(); - u32 Read32(int off) const { return base32[off>>2]; } + int GetNumSegments() const { return (int)(header->e_phnum); } + int GetNumSections() const { return (int)(header->e_shnum); } + const u8* GetPtr(int offset) const { return (u8*)base + offset; } + const char* GetSectionName(int section) const; + const u8* GetSectionDataPtr(int section) const + { + if (section < 0 || section >= header->e_shnum) + return nullptr; + if (sections[section].sh_type != SHT_NOBITS) + return GetPtr(sections[section].sh_offset); + else + return nullptr; + } + bool IsCodeSection(int section) const { return sections[section].sh_type == SHT_PROGBITS; } + const u8* GetSegmentPtr(int segment) { return GetPtr(segments[segment].p_offset); } + u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; } + int GetSectionSize(SectionID section) const { return sections[section].sh_size; } + SectionID GetSectionByName(const char* name, int firstSection = 0) const; //-1 for not found - // Quick accessors - ElfType GetType() const { return (ElfType)(header->e_type); } - ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } - u32 GetEntryPoint() const { return entryPoint; } - u32 GetFlags() const { return (u32)(header->e_flags); } - bool LoadIntoMemory(); - bool LoadSymbols(); - - int GetNumSegments() const { return (int)(header->e_phnum); } - int GetNumSections() const { return (int)(header->e_shnum); } - const u8* GetPtr(int offset) const { return (u8*)base + offset; } - const char* GetSectionName(int section) const; - const u8 *GetSectionDataPtr(int section) const - { - if (section < 0 || section >= header->e_shnum) - return nullptr; - if (sections[section].sh_type != SHT_NOBITS) - return GetPtr(sections[section].sh_offset); - else - return nullptr; - } - bool IsCodeSection(int section) const - { - return sections[section].sh_type == SHT_PROGBITS; - } - const u8* GetSegmentPtr(int segment) - { - return GetPtr(segments[segment].p_offset); - } - u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; } - int GetSectionSize(SectionID section) const { return sections[section].sh_size; } - SectionID GetSectionByName(const char* name, int firstSection = 0) const; //-1 for not found - - bool DidRelocate() const - { - return bRelocate; - } + bool DidRelocate() const { return bRelocate; } }; diff --git a/Source/Core/Core/Boot/ElfTypes.h b/Source/Core/Core/Boot/ElfTypes.h index 3728d82f6d..1b5c6d020d 100644 --- a/Source/Core/Core/Boot/ElfTypes.h +++ b/Source/Core/Core/Boot/ElfTypes.h @@ -11,85 +11,83 @@ // File type enum ElfType { - ET_NONE = 0, - ET_REL = 1, - ET_EXEC = 2, - ET_DYN = 3, - ET_CORE = 4, - ET_LOPROC = 0xFF00, - ET_HIPROC = 0xFFFF, + ET_NONE = 0, + ET_REL = 1, + ET_EXEC = 2, + ET_DYN = 3, + ET_CORE = 4, + ET_LOPROC = 0xFF00, + ET_HIPROC = 0xFFFF, }; // Machine/Architecture enum ElfMachine { - EM_NONE = 0, - EM_M32 = 1, - EM_SPARC = 2, - EM_386 = 3, - EM_68K = 4, - EM_88K = 5, - EM_860 = 7, - EM_MIPS = 8 + EM_NONE = 0, + EM_M32 = 1, + EM_SPARC = 2, + EM_386 = 3, + EM_68K = 4, + EM_88K = 5, + EM_860 = 7, + EM_MIPS = 8 }; // File version -#define EV_NONE 0 +#define EV_NONE 0 #define EV_CURRENT 1 // Identification index -#define EI_MAG0 0 -#define EI_MAG1 1 -#define EI_MAG2 2 -#define EI_MAG3 3 -#define EI_CLASS 4 -#define EI_DATA 5 +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 #define EI_VERSION 6 -#define EI_PAD 7 +#define EI_PAD 7 #define EI_NIDENT 16 // Magic number #define ELFMAG0 0x7F -#define ELFMAG1 'E' -#define ELFMAG2 'L' -#define ELFMAG3 'F' +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' // File class #define ELFCLASSNONE 0 -#define ELFCLASS32 1 -#define ELFCLASS64 2 +#define ELFCLASS32 1 +#define ELFCLASS64 2 // Encoding #define ELFDATANONE 0 #define ELFDATA2LSB 1 #define ELFDATA2MSB 2 - - // Sections constants // Section indexes -#define SHN_UNDEF 0 +#define SHN_UNDEF 0 #define SHN_LORESERVE 0xFF00 -#define SHN_LOPROC 0xFF00 -#define SHN_HIPROC 0xFF1F -#define SHN_ABS 0xFFF1 -#define SHN_COMMON 0xFFF2 +#define SHN_LOPROC 0xFF00 +#define SHN_HIPROC 0xFF1F +#define SHN_ABS 0xFFF1 +#define SHN_COMMON 0xFFF2 #define SHN_HIRESERVE 0xFFFF // Section types -#define SHT_NULL 0 -#define SHT_PROGBITS 1 -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_RELA 4 -#define SHT_HASH 5 -#define SHT_DYNAMIC 6 -#define SHT_NOTE 7 -#define SHT_NOBITS 8 -#define SHT_REL 9 -#define SHT_SHLIB 10 -#define SHT_DYNSYM 11 +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 #define SHT_LOPROC 0x70000000 #define SHT_HIPROC 0x7FFFFFFF #define SHT_LOUSER 0x80000000 @@ -98,58 +96,57 @@ enum ElfMachine // Custom section types #define SHT_PSPREL 0x700000a0 - // Section flags enum ElfSectionFlags { - SHF_WRITE = 0x1, - SHF_ALLOC = 0x2, - SHF_EXECINSTR = 0x4, - SHF_MASKPROC = 0xF0000000, + SHF_WRITE = 0x1, + SHF_ALLOC = 0x2, + SHF_EXECINSTR = 0x4, + SHF_MASKPROC = 0xF0000000, }; // Symbol binding -#define STB_LOCAL 0 -#define STB_GLOBAL 1 -#define STB_WEAK 2 +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 #define STB_LOPROC 13 #define STB_HIPROC 15 // Symbol types -#define STT_NOTYPE 0 -#define STT_OBJECT 1 -#define STT_FUNC 2 -#define STT_SECTION 3 -#define STT_FILE 4 -#define STT_LOPROC 13 -#define STT_HIPROC 15 +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_LOPROC 13 +#define STT_HIPROC 15 // Undefined name #define STN_UNDEF 0 // Relocation types -#define R_386_NONE 0 -#define R_386_32 1 -#define R_386_PC32 2 -#define R_386_GOT32 3 -#define R_386_PLT32 4 -#define R_386_COPY 5 -#define R_386_GLOB_DAT 6 -#define R_386_JMP_SLOT 7 -#define R_386_RELATIVE 8 -#define R_386_GOTOFF 9 -#define R_386_GOTPC 10 +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 // Segment types -#define PT_NULL 0 -#define PT_LOAD 1 -#define PT_DYNAMIC 2 -#define PT_INTERP 3 -#define PT_NOTE 4 -#define PT_SHLIB 5 -#define PT_PHDR 6 -#define PT_LOPROC 0x70000000 -#define PT_HIPROC 0x7FFFFFFF +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7FFFFFFF // Segment flags #define PF_X 1 @@ -157,120 +154,118 @@ enum ElfSectionFlags #define PF_R 4 // Dynamic Array Tags -#define DT_NULL 0 -#define DT_NEEDED 1 -#define DT_PLTRELSZ 2 -#define DT_PLTGOT 3 -#define DT_HASH 4 -#define DT_STRTAB 5 -#define DT_SYMTAB 6 -#define DT_RELA 7 -#define DT_RELASZ 8 -#define DT_RELAENT 9 -#define DT_STRSZ 10 -#define DT_SYMENT 11 -#define DT_INIT 12 -#define DT_FINI 13 -#define DT_SONAME 14 -#define DT_RPATH 15 -#define DT_SYMBOLIC 16 -#define DT_REL 17 -#define DT_RELSZ 18 -#define DT_RELENT 19 -#define DT_PLTREL 20 -#define DT_DEBUG 21 -#define DT_TEXTREL 22 -#define DT_JMPREL 23 -#define DT_LOPROC 0x70000000 -#define DT_HIPROC 0x7FFFFFFF +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7FFFFFFF // ELF file header struct Elf32_Ehdr { - u8 e_ident[EI_NIDENT]; - u16 e_type; - u16 e_machine; - u32 e_version; - u32 e_entry; - u32 e_phoff; - u32 e_shoff; - u32 e_flags; - u16 e_ehsize; - u16 e_phentsize; - u16 e_phnum; - u16 e_shentsize; - u16 e_shnum; - u16 e_shstrndx; + u8 e_ident[EI_NIDENT]; + u16 e_type; + u16 e_machine; + u32 e_version; + u32 e_entry; + u32 e_phoff; + u32 e_shoff; + u32 e_flags; + u16 e_ehsize; + u16 e_phentsize; + u16 e_phnum; + u16 e_shentsize; + u16 e_shnum; + u16 e_shstrndx; }; // Section header struct Elf32_Shdr { - u32 sh_name; - u32 sh_type; - u32 sh_flags; - u32 sh_addr; - u32 sh_offset; - u32 sh_size; - u32 sh_link; - u32 sh_info; - u32 sh_addralign; - u32 sh_entsize; + u32 sh_name; + u32 sh_type; + u32 sh_flags; + u32 sh_addr; + u32 sh_offset; + u32 sh_size; + u32 sh_link; + u32 sh_info; + u32 sh_addralign; + u32 sh_entsize; }; // Segment header struct Elf32_Phdr { - u32 p_type; - u32 p_offset; - u32 p_vaddr; - u32 p_paddr; - u32 p_filesz; - u32 p_memsz; - u32 p_flags; - u32 p_align; + u32 p_type; + u32 p_offset; + u32 p_vaddr; + u32 p_paddr; + u32 p_filesz; + u32 p_memsz; + u32 p_flags; + u32 p_align; }; // Symbol table entry struct Elf32_Sym { - u32 st_name; - u32 st_value; - u32 st_size; - u8 st_info; - u8 st_other; - u16 st_shndx; + u32 st_name; + u32 st_value; + u32 st_size; + u8 st_info; + u8 st_other; + u16 st_shndx; }; -#define ELF32_ST_BIND(i) ((i)>>4) -#define ELF32_ST_TYPE(i) ((i)&0xf) -#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) +#define ELF32_ST_BIND(i) ((i) >> 4) +#define ELF32_ST_TYPE(i) ((i)&0xf) +#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t)&0xf)) // Relocation entries struct Elf32_Rel { - u32 r_offset; - u32 r_info; + u32 r_offset; + u32 r_info; }; struct Elf32_Rela { - u32 r_offset; - u32 r_info; - s32 r_addend; + u32 r_offset; + u32 r_info; + s32 r_addend; }; -#define ELF32_R_SYM(i) ((i)>>8) +#define ELF32_R_SYM(i) ((i) >> 8) #define ELF32_R_TYPE(i) ((u8)(i)) -#define ELF32_R_INFO(s,t) (((s)<<8 )+(u8)(t)) - +#define ELF32_R_INFO(s, t) (((s) << 8) + (u8)(t)) struct Elf32_Dyn { - s32 d_tag; - union - { - u32 d_val; - u32 d_ptr; - } d_un; + s32 d_tag; + union { + u32 d_val; + u32 d_ptr; + } d_un; }; diff --git a/Source/Core/Core/BootManager.cpp b/Source/Core/Core/BootManager.cpp index a4b8426798..912d056bea 100644 --- a/Source/Core/Core/BootManager.cpp +++ b/Source/Core/Core/BootManager.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // File description // ------------- // Purpose of this file: Collect boot settings for Core::Init() @@ -17,7 +16,6 @@ // Boot.cpp CBoot::BootUp() // CBoot::EmulatedBS2_Wii() / GC() or Load_BS2() - // Includes // ---------------- #include @@ -32,367 +30,379 @@ #include "Core/BootManager.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/Host.h" -#include "Core/Movie.h" -#include "Core/NetPlayProto.h" #include "Core/HW/EXI.h" #include "Core/HW/SI.h" #include "Core/HW/Sram.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" +#include "Core/Host.h" +#include "Core/Movie.h" +#include "Core/NetPlayProto.h" #include "VideoCommon/VideoBackendBase.h" namespace BootManager { - // TODO this is an ugly hack which allows us to restore values trampled by per-game settings // Apply fire liberally struct ConfigCache { public: - // fill the cache with values from the configuration - void SaveConfig(const SConfig& config); - // restore values to the configuration from the cache - void RestoreConfig(SConfig* config); + // fill the cache with values from the configuration + void SaveConfig(const SConfig& config); + // restore values to the configuration from the cache + void RestoreConfig(SConfig* config); - // These store if the relevant setting should be reset back later (true) or if it should be left alone on restore (false) - bool bSetEmulationSpeed; - bool bSetVolume; - bool bSetFrameSkip; - std::array bSetWiimoteSource; - std::array bSetPads; - std::array bSetEXIDevice; + // These store if the relevant setting should be reset back later (true) or if it should be left + // alone on restore (false) + bool bSetEmulationSpeed; + bool bSetVolume; + bool bSetFrameSkip; + std::array bSetWiimoteSource; + std::array bSetPads; + std::array bSetEXIDevice; private: - bool valid; - bool bCPUThread; - bool bSkipIdle; - bool bSyncGPUOnSkipIdleHack; - bool bFPRF; - bool bAccurateNaNs; - bool bMMU; - bool bDCBZOFF; - bool m_EnableJIT; - bool bSyncGPU; - bool bFastDiscSpeed; - bool bDSPHLE; - bool bHLE_BS2; - bool bProgressive; - bool bPAL60; - int iSelectedLanguage; - int iCPUCore; - int Volume; - unsigned int frameSkip; - float m_EmulationSpeed; - std::string strBackend; - std::string sBackend; - std::string m_strGPUDeterminismMode; - std::array iWiimoteSource; - std::array Pads; - std::array m_EXIDevice; + bool valid; + bool bCPUThread; + bool bSkipIdle; + bool bSyncGPUOnSkipIdleHack; + bool bFPRF; + bool bAccurateNaNs; + bool bMMU; + bool bDCBZOFF; + bool m_EnableJIT; + bool bSyncGPU; + bool bFastDiscSpeed; + bool bDSPHLE; + bool bHLE_BS2; + bool bProgressive; + bool bPAL60; + int iSelectedLanguage; + int iCPUCore; + int Volume; + unsigned int frameSkip; + float m_EmulationSpeed; + std::string strBackend; + std::string sBackend; + std::string m_strGPUDeterminismMode; + std::array iWiimoteSource; + std::array Pads; + std::array m_EXIDevice; }; void ConfigCache::SaveConfig(const SConfig& config) { - valid = true; + valid = true; - bCPUThread = config.bCPUThread; - bSkipIdle = config.bSkipIdle; - bSyncGPUOnSkipIdleHack = config.bSyncGPUOnSkipIdleHack; - bFPRF = config.bFPRF; - bAccurateNaNs = config.bAccurateNaNs; - bMMU = config.bMMU; - bDCBZOFF = config.bDCBZOFF; - m_EnableJIT = config.m_DSPEnableJIT; - bSyncGPU = config.bSyncGPU; - bFastDiscSpeed = config.bFastDiscSpeed; - bDSPHLE = config.bDSPHLE; - bHLE_BS2 = config.bHLE_BS2; - bProgressive = config.bProgressive; - bPAL60 = config.bPAL60; - iSelectedLanguage = config.SelectedLanguage; - iCPUCore = config.iCPUCore; - Volume = config.m_Volume; - m_EmulationSpeed = config.m_EmulationSpeed; - frameSkip = config.m_FrameSkip; - strBackend = config.m_strVideoBackend; - sBackend = config.sBackend; - m_strGPUDeterminismMode = config.m_strGPUDeterminismMode; + bCPUThread = config.bCPUThread; + bSkipIdle = config.bSkipIdle; + bSyncGPUOnSkipIdleHack = config.bSyncGPUOnSkipIdleHack; + bFPRF = config.bFPRF; + bAccurateNaNs = config.bAccurateNaNs; + bMMU = config.bMMU; + bDCBZOFF = config.bDCBZOFF; + m_EnableJIT = config.m_DSPEnableJIT; + bSyncGPU = config.bSyncGPU; + bFastDiscSpeed = config.bFastDiscSpeed; + bDSPHLE = config.bDSPHLE; + bHLE_BS2 = config.bHLE_BS2; + bProgressive = config.bProgressive; + bPAL60 = config.bPAL60; + iSelectedLanguage = config.SelectedLanguage; + iCPUCore = config.iCPUCore; + Volume = config.m_Volume; + m_EmulationSpeed = config.m_EmulationSpeed; + frameSkip = config.m_FrameSkip; + strBackend = config.m_strVideoBackend; + sBackend = config.sBackend; + m_strGPUDeterminismMode = config.m_strGPUDeterminismMode; - std::copy(std::begin(g_wiimote_sources), std::end(g_wiimote_sources), std::begin(iWiimoteSource)); - std::copy(std::begin(config.m_SIDevice), std::end(config.m_SIDevice), std::begin(Pads)); - std::copy(std::begin(config.m_EXIDevice), std::end(config.m_EXIDevice), std::begin(m_EXIDevice)); + std::copy(std::begin(g_wiimote_sources), std::end(g_wiimote_sources), std::begin(iWiimoteSource)); + std::copy(std::begin(config.m_SIDevice), std::end(config.m_SIDevice), std::begin(Pads)); + std::copy(std::begin(config.m_EXIDevice), std::end(config.m_EXIDevice), std::begin(m_EXIDevice)); - bSetEmulationSpeed = false; - bSetVolume = false; - bSetFrameSkip = false; - bSetWiimoteSource.fill(false); - bSetPads.fill(false); - bSetEXIDevice.fill(false); + bSetEmulationSpeed = false; + bSetVolume = false; + bSetFrameSkip = false; + bSetWiimoteSource.fill(false); + bSetPads.fill(false); + bSetEXIDevice.fill(false); } void ConfigCache::RestoreConfig(SConfig* config) { - if (!valid) - return; + if (!valid) + return; - valid = false; + valid = false; - config->bCPUThread = bCPUThread; - config->bSkipIdle = bSkipIdle; - config->bSyncGPUOnSkipIdleHack = bSyncGPUOnSkipIdleHack; - config->bFPRF = bFPRF; - config->bAccurateNaNs = bAccurateNaNs; - config->bMMU = bMMU; - config->bDCBZOFF = bDCBZOFF; - config->m_DSPEnableJIT = m_EnableJIT; - config->bSyncGPU = bSyncGPU; - config->bFastDiscSpeed = bFastDiscSpeed; - config->bDSPHLE = bDSPHLE; - config->bHLE_BS2 = bHLE_BS2; - config->bProgressive = bProgressive; - config->bPAL60 = bPAL60; - config->SelectedLanguage = iSelectedLanguage; - config->iCPUCore = iCPUCore; + config->bCPUThread = bCPUThread; + config->bSkipIdle = bSkipIdle; + config->bSyncGPUOnSkipIdleHack = bSyncGPUOnSkipIdleHack; + config->bFPRF = bFPRF; + config->bAccurateNaNs = bAccurateNaNs; + config->bMMU = bMMU; + config->bDCBZOFF = bDCBZOFF; + config->m_DSPEnableJIT = m_EnableJIT; + config->bSyncGPU = bSyncGPU; + config->bFastDiscSpeed = bFastDiscSpeed; + config->bDSPHLE = bDSPHLE; + config->bHLE_BS2 = bHLE_BS2; + config->bProgressive = bProgressive; + config->bPAL60 = bPAL60; + config->SelectedLanguage = iSelectedLanguage; + config->iCPUCore = iCPUCore; - config->m_SYSCONF->SetData("IPL.PGS", bProgressive); - config->m_SYSCONF->SetData("IPL.E60", bPAL60); + config->m_SYSCONF->SetData("IPL.PGS", bProgressive); + config->m_SYSCONF->SetData("IPL.E60", bPAL60); - // Only change these back if they were actually set by game ini, since they can be changed while a game is running. - if (bSetVolume) - config->m_Volume = Volume; + // Only change these back if they were actually set by game ini, since they can be changed while a + // game is running. + if (bSetVolume) + config->m_Volume = Volume; - if (config->bWii) - { - for (unsigned int i = 0; i < MAX_BBMOTES; ++i) - { - if (bSetWiimoteSource[i]) - { - g_wiimote_sources[i] = iWiimoteSource[i]; - WiimoteReal::ChangeWiimoteSource(i, iWiimoteSource[i]); - } - } - } + if (config->bWii) + { + for (unsigned int i = 0; i < MAX_BBMOTES; ++i) + { + if (bSetWiimoteSource[i]) + { + g_wiimote_sources[i] = iWiimoteSource[i]; + WiimoteReal::ChangeWiimoteSource(i, iWiimoteSource[i]); + } + } + } - for (unsigned int i = 0; i < MAX_SI_CHANNELS; ++i) - { - if (bSetPads[i]) - config->m_SIDevice[i] = Pads[i]; - } + for (unsigned int i = 0; i < MAX_SI_CHANNELS; ++i) + { + if (bSetPads[i]) + config->m_SIDevice[i] = Pads[i]; + } - if (bSetEmulationSpeed) - config->m_EmulationSpeed = m_EmulationSpeed; + if (bSetEmulationSpeed) + config->m_EmulationSpeed = m_EmulationSpeed; - if (bSetFrameSkip) - { - config->m_FrameSkip = frameSkip; - Movie::SetFrameSkipping(frameSkip); - } + if (bSetFrameSkip) + { + config->m_FrameSkip = frameSkip; + Movie::SetFrameSkipping(frameSkip); + } - for (unsigned int i = 0; i < MAX_EXI_CHANNELS; ++i) - { - if (bSetEXIDevice[i]) - config->m_EXIDevice[i] = m_EXIDevice[i]; - } + for (unsigned int i = 0; i < MAX_EXI_CHANNELS; ++i) + { + if (bSetEXIDevice[i]) + config->m_EXIDevice[i] = m_EXIDevice[i]; + } - config->m_strVideoBackend = strBackend; - config->sBackend = sBackend; - config->m_strGPUDeterminismMode = m_strGPUDeterminismMode; - VideoBackendBase::ActivateBackend(config->m_strVideoBackend); + config->m_strVideoBackend = strBackend; + config->sBackend = sBackend; + config->m_strGPUDeterminismMode = m_strGPUDeterminismMode; + VideoBackendBase::ActivateBackend(config->m_strVideoBackend); } static ConfigCache config_cache; static GPUDeterminismMode ParseGPUDeterminismMode(const std::string& mode) { - if (mode == "auto") - return GPU_DETERMINISM_AUTO; - if (mode == "none") - return GPU_DETERMINISM_NONE; - if (mode == "fake-completion") - return GPU_DETERMINISM_FAKE_COMPLETION; + if (mode == "auto") + return GPU_DETERMINISM_AUTO; + if (mode == "none") + return GPU_DETERMINISM_NONE; + if (mode == "fake-completion") + return GPU_DETERMINISM_FAKE_COMPLETION; - NOTICE_LOG(BOOT, "Unknown GPU determinism mode %s", mode.c_str()); - return GPU_DETERMINISM_AUTO; + NOTICE_LOG(BOOT, "Unknown GPU determinism mode %s", mode.c_str()); + return GPU_DETERMINISM_AUTO; } // Boot the ISO or file bool BootCore(const std::string& _rFilename) { - SConfig& StartUp = SConfig::GetInstance(); + SConfig& StartUp = SConfig::GetInstance(); - // Use custom settings for debugging mode - Host_SetStartupDebuggingParameters(); + // Use custom settings for debugging mode + Host_SetStartupDebuggingParameters(); - StartUp.m_BootType = SConfig::BOOT_ISO; - StartUp.m_strFilename = _rFilename; - SConfig::GetInstance().m_LastFilename = _rFilename; - SConfig::GetInstance().SaveSettings(); - StartUp.bRunCompareClient = false; - StartUp.bRunCompareServer = false; + StartUp.m_BootType = SConfig::BOOT_ISO; + StartUp.m_strFilename = _rFilename; + SConfig::GetInstance().m_LastFilename = _rFilename; + SConfig::GetInstance().SaveSettings(); + StartUp.bRunCompareClient = false; + StartUp.bRunCompareServer = false; - config_cache.SaveConfig(StartUp); + config_cache.SaveConfig(StartUp); - // If for example the ISO file is bad we return here - if (!StartUp.AutoSetup(SConfig::BOOT_DEFAULT)) - return false; + // If for example the ISO file is bad we return here + if (!StartUp.AutoSetup(SConfig::BOOT_DEFAULT)) + return false; - // Load game specific settings - { - IniFile game_ini = StartUp.LoadGameIni(); + // Load game specific settings + { + IniFile game_ini = StartUp.LoadGameIni(); - // General settings - IniFile::Section* core_section = game_ini.GetOrCreateSection("Core"); - IniFile::Section* dsp_section = game_ini.GetOrCreateSection("DSP"); - IniFile::Section* controls_section = game_ini.GetOrCreateSection("Controls"); + // General settings + IniFile::Section* core_section = game_ini.GetOrCreateSection("Core"); + IniFile::Section* dsp_section = game_ini.GetOrCreateSection("DSP"); + IniFile::Section* controls_section = game_ini.GetOrCreateSection("Controls"); - core_section->Get("CPUThread", &StartUp.bCPUThread, StartUp.bCPUThread); - core_section->Get("SkipIdle", &StartUp.bSkipIdle, StartUp.bSkipIdle); - core_section->Get("SyncOnSkipIdle", &StartUp.bSyncGPUOnSkipIdleHack, StartUp.bSyncGPUOnSkipIdleHack); - core_section->Get("FPRF", &StartUp.bFPRF, StartUp.bFPRF); - core_section->Get("AccurateNaNs", &StartUp.bAccurateNaNs, StartUp.bAccurateNaNs); - core_section->Get("MMU", &StartUp.bMMU, StartUp.bMMU); - core_section->Get("DCBZ", &StartUp.bDCBZOFF, StartUp.bDCBZOFF); - core_section->Get("SyncGPU", &StartUp.bSyncGPU, StartUp.bSyncGPU); - core_section->Get("FastDiscSpeed", &StartUp.bFastDiscSpeed, StartUp.bFastDiscSpeed); - core_section->Get("DSPHLE", &StartUp.bDSPHLE, StartUp.bDSPHLE); - core_section->Get("GFXBackend", &StartUp.m_strVideoBackend, StartUp.m_strVideoBackend); - core_section->Get("CPUCore", &StartUp.iCPUCore, StartUp.iCPUCore); - core_section->Get("HLE_BS2", &StartUp.bHLE_BS2, StartUp.bHLE_BS2); - core_section->Get("ProgressiveScan", &StartUp.bProgressive, StartUp.bProgressive); - core_section->Get("PAL60", &StartUp.bPAL60, StartUp.bPAL60); - if (core_section->Get("EmulationSpeed", &SConfig::GetInstance().m_EmulationSpeed, SConfig::GetInstance().m_EmulationSpeed)) - config_cache.bSetEmulationSpeed = true; - if (core_section->Get("FrameSkip", &SConfig::GetInstance().m_FrameSkip)) - { - config_cache.bSetFrameSkip = true; - Movie::SetFrameSkipping(SConfig::GetInstance().m_FrameSkip); - } + core_section->Get("CPUThread", &StartUp.bCPUThread, StartUp.bCPUThread); + core_section->Get("SkipIdle", &StartUp.bSkipIdle, StartUp.bSkipIdle); + core_section->Get("SyncOnSkipIdle", &StartUp.bSyncGPUOnSkipIdleHack, + StartUp.bSyncGPUOnSkipIdleHack); + core_section->Get("FPRF", &StartUp.bFPRF, StartUp.bFPRF); + core_section->Get("AccurateNaNs", &StartUp.bAccurateNaNs, StartUp.bAccurateNaNs); + core_section->Get("MMU", &StartUp.bMMU, StartUp.bMMU); + core_section->Get("DCBZ", &StartUp.bDCBZOFF, StartUp.bDCBZOFF); + core_section->Get("SyncGPU", &StartUp.bSyncGPU, StartUp.bSyncGPU); + core_section->Get("FastDiscSpeed", &StartUp.bFastDiscSpeed, StartUp.bFastDiscSpeed); + core_section->Get("DSPHLE", &StartUp.bDSPHLE, StartUp.bDSPHLE); + core_section->Get("GFXBackend", &StartUp.m_strVideoBackend, StartUp.m_strVideoBackend); + core_section->Get("CPUCore", &StartUp.iCPUCore, StartUp.iCPUCore); + core_section->Get("HLE_BS2", &StartUp.bHLE_BS2, StartUp.bHLE_BS2); + core_section->Get("ProgressiveScan", &StartUp.bProgressive, StartUp.bProgressive); + core_section->Get("PAL60", &StartUp.bPAL60, StartUp.bPAL60); + if (core_section->Get("EmulationSpeed", &SConfig::GetInstance().m_EmulationSpeed, + SConfig::GetInstance().m_EmulationSpeed)) + config_cache.bSetEmulationSpeed = true; + if (core_section->Get("FrameSkip", &SConfig::GetInstance().m_FrameSkip)) + { + config_cache.bSetFrameSkip = true; + Movie::SetFrameSkipping(SConfig::GetInstance().m_FrameSkip); + } - if (dsp_section->Get("Volume", &SConfig::GetInstance().m_Volume, SConfig::GetInstance().m_Volume)) - config_cache.bSetVolume = true; - dsp_section->Get("EnableJIT", &SConfig::GetInstance().m_DSPEnableJIT, SConfig::GetInstance().m_DSPEnableJIT); - dsp_section->Get("Backend", &SConfig::GetInstance().sBackend, SConfig::GetInstance().sBackend); - VideoBackendBase::ActivateBackend(StartUp.m_strVideoBackend); - core_section->Get("GPUDeterminismMode", &StartUp.m_strGPUDeterminismMode, StartUp.m_strGPUDeterminismMode); + if (dsp_section->Get("Volume", &SConfig::GetInstance().m_Volume, + SConfig::GetInstance().m_Volume)) + config_cache.bSetVolume = true; + dsp_section->Get("EnableJIT", &SConfig::GetInstance().m_DSPEnableJIT, + SConfig::GetInstance().m_DSPEnableJIT); + dsp_section->Get("Backend", &SConfig::GetInstance().sBackend, SConfig::GetInstance().sBackend); + VideoBackendBase::ActivateBackend(StartUp.m_strVideoBackend); + core_section->Get("GPUDeterminismMode", &StartUp.m_strGPUDeterminismMode, + StartUp.m_strGPUDeterminismMode); - for (unsigned int i = 0; i < MAX_SI_CHANNELS; ++i) - { - int source; - controls_section->Get(StringFromFormat("PadType%u", i), &source, -1); - if (source >= (int) SIDEVICE_NONE && source <= (int) SIDEVICE_WIIU_ADAPTER) - { - SConfig::GetInstance().m_SIDevice[i] = (SIDevices) source; - config_cache.bSetPads[i] = true; - } - } + for (unsigned int i = 0; i < MAX_SI_CHANNELS; ++i) + { + int source; + controls_section->Get(StringFromFormat("PadType%u", i), &source, -1); + if (source >= (int)SIDEVICE_NONE && source <= (int)SIDEVICE_WIIU_ADAPTER) + { + SConfig::GetInstance().m_SIDevice[i] = (SIDevices)source; + config_cache.bSetPads[i] = true; + } + } - // Wii settings - if (StartUp.bWii) - { - // Flush possible changes to SYSCONF to file - SConfig::GetInstance().m_SYSCONF->Save(); + // Wii settings + if (StartUp.bWii) + { + // Flush possible changes to SYSCONF to file + SConfig::GetInstance().m_SYSCONF->Save(); - int source; - for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) - { - controls_section->Get(StringFromFormat("WiimoteSource%u", i), &source, -1); - if (source != -1 && g_wiimote_sources[i] != (unsigned) source && source >= WIIMOTE_SRC_NONE && source <= WIIMOTE_SRC_HYBRID) - { - config_cache.bSetWiimoteSource[i] = true; - g_wiimote_sources[i] = source; - WiimoteReal::ChangeWiimoteSource(i, source); - } - } - controls_section->Get("WiimoteSourceBB", &source, -1); - if (source != -1 && g_wiimote_sources[WIIMOTE_BALANCE_BOARD] != (unsigned) source && (source == WIIMOTE_SRC_NONE || source == WIIMOTE_SRC_REAL)) - { - config_cache.bSetWiimoteSource[WIIMOTE_BALANCE_BOARD] = true; - g_wiimote_sources[WIIMOTE_BALANCE_BOARD] = source; - WiimoteReal::ChangeWiimoteSource(WIIMOTE_BALANCE_BOARD, source); - } - } - } + int source; + for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) + { + controls_section->Get(StringFromFormat("WiimoteSource%u", i), &source, -1); + if (source != -1 && g_wiimote_sources[i] != (unsigned)source && + source >= WIIMOTE_SRC_NONE && source <= WIIMOTE_SRC_HYBRID) + { + config_cache.bSetWiimoteSource[i] = true; + g_wiimote_sources[i] = source; + WiimoteReal::ChangeWiimoteSource(i, source); + } + } + controls_section->Get("WiimoteSourceBB", &source, -1); + if (source != -1 && g_wiimote_sources[WIIMOTE_BALANCE_BOARD] != (unsigned)source && + (source == WIIMOTE_SRC_NONE || source == WIIMOTE_SRC_REAL)) + { + config_cache.bSetWiimoteSource[WIIMOTE_BALANCE_BOARD] = true; + g_wiimote_sources[WIIMOTE_BALANCE_BOARD] = source; + WiimoteReal::ChangeWiimoteSource(WIIMOTE_BALANCE_BOARD, source); + } + } + } - StartUp.m_GPUDeterminismMode = ParseGPUDeterminismMode(StartUp.m_strGPUDeterminismMode); + StartUp.m_GPUDeterminismMode = ParseGPUDeterminismMode(StartUp.m_strGPUDeterminismMode); - // Movie settings - if (Movie::IsPlayingInput() && Movie::IsConfigSaved()) - { - StartUp.bCPUThread = Movie::IsDualCore(); - StartUp.bSkipIdle = Movie::IsSkipIdle(); - StartUp.bDSPHLE = Movie::IsDSPHLE(); - StartUp.bProgressive = Movie::IsProgressive(); - StartUp.bPAL60 = Movie::IsPAL60(); - StartUp.bFastDiscSpeed = Movie::IsFastDiscSpeed(); - StartUp.iCPUCore = Movie::GetCPUMode(); - StartUp.bSyncGPU = Movie::IsSyncGPU(); - for (int i = 0; i < 2; ++i) - { - if (Movie::IsUsingMemcard(i) && Movie::IsStartingFromClearSave() && !StartUp.bWii) - { - if (File::Exists(File::GetUserPath(D_GCUSER_IDX) + StringFromFormat("Movie%s.raw", (i == 0) ? "A" : "B"))) - File::Delete(File::GetUserPath(D_GCUSER_IDX) + StringFromFormat("Movie%s.raw", (i == 0) ? "A" : "B")); - } - } - } + // Movie settings + if (Movie::IsPlayingInput() && Movie::IsConfigSaved()) + { + StartUp.bCPUThread = Movie::IsDualCore(); + StartUp.bSkipIdle = Movie::IsSkipIdle(); + StartUp.bDSPHLE = Movie::IsDSPHLE(); + StartUp.bProgressive = Movie::IsProgressive(); + StartUp.bPAL60 = Movie::IsPAL60(); + StartUp.bFastDiscSpeed = Movie::IsFastDiscSpeed(); + StartUp.iCPUCore = Movie::GetCPUMode(); + StartUp.bSyncGPU = Movie::IsSyncGPU(); + for (int i = 0; i < 2; ++i) + { + if (Movie::IsUsingMemcard(i) && Movie::IsStartingFromClearSave() && !StartUp.bWii) + { + if (File::Exists(File::GetUserPath(D_GCUSER_IDX) + + StringFromFormat("Movie%s.raw", (i == 0) ? "A" : "B"))) + File::Delete(File::GetUserPath(D_GCUSER_IDX) + + StringFromFormat("Movie%s.raw", (i == 0) ? "A" : "B")); + } + } + } - if (NetPlay::IsNetPlayRunning()) - { - StartUp.bCPUThread = g_NetPlaySettings.m_CPUthread; - StartUp.bDSPHLE = g_NetPlaySettings.m_DSPHLE; - StartUp.bEnableMemcardSdWriting = g_NetPlaySettings.m_WriteToMemcard; - StartUp.iCPUCore = g_NetPlaySettings.m_CPUcore; - StartUp.SelectedLanguage = g_NetPlaySettings.m_SelectedLanguage; - StartUp.bOverrideGCLanguage = g_NetPlaySettings.m_OverrideGCLanguage; - StartUp.bProgressive = g_NetPlaySettings.m_ProgressiveScan; - StartUp.bPAL60 = g_NetPlaySettings.m_PAL60; - SConfig::GetInstance().m_DSPEnableJIT = g_NetPlaySettings.m_DSPEnableJIT; - SConfig::GetInstance().m_OCEnable = g_NetPlaySettings.m_OCEnable; - SConfig::GetInstance().m_OCFactor = g_NetPlaySettings.m_OCFactor; - SConfig::GetInstance().m_EXIDevice[0] = g_NetPlaySettings.m_EXIDevice[0]; - SConfig::GetInstance().m_EXIDevice[1] = g_NetPlaySettings.m_EXIDevice[1]; - config_cache.bSetEXIDevice[0] = true; - config_cache.bSetEXIDevice[1] = true; - } - else - { - g_SRAM_netplay_initialized = false; - } + if (NetPlay::IsNetPlayRunning()) + { + StartUp.bCPUThread = g_NetPlaySettings.m_CPUthread; + StartUp.bDSPHLE = g_NetPlaySettings.m_DSPHLE; + StartUp.bEnableMemcardSdWriting = g_NetPlaySettings.m_WriteToMemcard; + StartUp.iCPUCore = g_NetPlaySettings.m_CPUcore; + StartUp.SelectedLanguage = g_NetPlaySettings.m_SelectedLanguage; + StartUp.bOverrideGCLanguage = g_NetPlaySettings.m_OverrideGCLanguage; + StartUp.bProgressive = g_NetPlaySettings.m_ProgressiveScan; + StartUp.bPAL60 = g_NetPlaySettings.m_PAL60; + SConfig::GetInstance().m_DSPEnableJIT = g_NetPlaySettings.m_DSPEnableJIT; + SConfig::GetInstance().m_OCEnable = g_NetPlaySettings.m_OCEnable; + SConfig::GetInstance().m_OCFactor = g_NetPlaySettings.m_OCFactor; + SConfig::GetInstance().m_EXIDevice[0] = g_NetPlaySettings.m_EXIDevice[0]; + SConfig::GetInstance().m_EXIDevice[1] = g_NetPlaySettings.m_EXIDevice[1]; + config_cache.bSetEXIDevice[0] = true; + config_cache.bSetEXIDevice[1] = true; + } + else + { + g_SRAM_netplay_initialized = false; + } - // Apply overrides - // Some NTSC GameCube games such as Baten Kaitos react strangely to language settings that would be invalid on an NTSC system - if (!StartUp.bOverrideGCLanguage && StartUp.bNTSC) - { - StartUp.SelectedLanguage = 0; - } + // Apply overrides + // Some NTSC GameCube games such as Baten Kaitos react strangely to language settings that would + // be invalid on an NTSC system + if (!StartUp.bOverrideGCLanguage && StartUp.bNTSC) + { + StartUp.SelectedLanguage = 0; + } - // Some NTSC Wii games such as Doc Louis's Punch-Out!! and 1942 (Virtual Console) crash if the PAL60 option is enabled - if (StartUp.bWii && StartUp.bNTSC) - { - StartUp.bPAL60 = false; - } + // Some NTSC Wii games such as Doc Louis's Punch-Out!! and 1942 (Virtual Console) crash if the + // PAL60 option is enabled + if (StartUp.bWii && StartUp.bNTSC) + { + StartUp.bPAL60 = false; + } - SConfig::GetInstance().m_SYSCONF->SetData("IPL.PGS", StartUp.bProgressive); - SConfig::GetInstance().m_SYSCONF->SetData("IPL.E60", StartUp.bPAL60); + SConfig::GetInstance().m_SYSCONF->SetData("IPL.PGS", StartUp.bProgressive); + SConfig::GetInstance().m_SYSCONF->SetData("IPL.E60", StartUp.bPAL60); - // Run the game - // Init the core - if (!Core::Init()) - { - PanicAlertT("Couldn't init the core.\nCheck your configuration."); - return false; - } + // Run the game + // Init the core + if (!Core::Init()) + { + PanicAlertT("Couldn't init the core.\nCheck your configuration."); + return false; + } - return true; + return true; } void Stop() { - Core::Stop(); + Core::Stop(); - SConfig& StartUp = SConfig::GetInstance(); - StartUp.m_strUniqueID = "00000000"; - config_cache.RestoreConfig(&StartUp); + SConfig& StartUp = SConfig::GetInstance(); + StartUp.m_strUniqueID = "00000000"; + config_cache.RestoreConfig(&StartUp); } -} // namespace +} // namespace diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index cfa9e4b0b9..fa2ade2cef 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -11,10 +11,10 @@ #include "Common/FileUtil.h" #include "Common/StringUtil.h" -#include "Core/ConfigManager.h" -#include "Core/Core.h" // for bWii #include "Core/Boot/Boot.h" #include "Core/Boot/Boot_DOL.h" +#include "Core/ConfigManager.h" +#include "Core/Core.h" // for bWii #include "Core/FifoPlayer/FifoDataFile.h" #include "Core/HW/SI.h" #include "Core/PowerPC/PowerPC.h" @@ -25,994 +25,984 @@ SConfig* SConfig::m_Instance; SConfig::SConfig() -: bEnableDebugging(false), bAutomaticStart(false), bBootToPause(false), - bJITNoBlockCache(false), bJITNoBlockLinking(false), - bJITOff(false), - bJITLoadStoreOff(false), bJITLoadStorelXzOff(false), - bJITLoadStorelwzOff(false), bJITLoadStorelbzxOff(false), - bJITLoadStoreFloatingOff(false), bJITLoadStorePairedOff(false), - bJITFloatingPointOff(false), bJITIntegerOff(false), - bJITPairedOff(false), bJITSystemRegistersOff(false), - bJITBranchOff(false), - bJITILTimeProfiling(false), bJITILOutputIR(false), - bFPRF(false), bAccurateNaNs(false), iTimingVariance(40), - bCPUThread(true), bDSPThread(false), bDSPHLE(true), - bSkipIdle(true), bSyncGPUOnSkipIdleHack(true), bNTSC(false), bForceNTSCJ(false), - bHLE_BS2(true), bEnableCheats(false), - bEnableMemcardSdWriting(true), - bDPL2Decoder(false), iLatency(14), - bRunCompareServer(false), bRunCompareClient(false), - bMMU(false), bDCBZOFF(false), - iBBDumpPort(0), - bFastDiscSpeed(false), bSyncGPU(false), - SelectedLanguage(0), bOverrideGCLanguage(false), bWii(false), - bConfirmStop(false), bHideCursor(false), - bAutoHideCursor(false), bUsePanicHandlers(true), bOnScreenDisplayMessages(true), - iRenderWindowXPos(-1), iRenderWindowYPos(-1), - iRenderWindowWidth(640), iRenderWindowHeight(480), - bRenderWindowAutoSize(false), bKeepWindowOnTop(false), - bFullscreen(false), bRenderToMain(false), - bProgressive(false), bPAL60(false), - bDisableScreenSaver(false), - iPosX(100), iPosY(100), iWidth(800), iHeight(600), - m_analytics_enabled(false), m_analytics_permission_asked(false), - bLoopFifoReplay(true) + : bEnableDebugging(false), bAutomaticStart(false), bBootToPause(false), bJITNoBlockCache(false), + bJITNoBlockLinking(false), bJITOff(false), bJITLoadStoreOff(false), + bJITLoadStorelXzOff(false), bJITLoadStorelwzOff(false), bJITLoadStorelbzxOff(false), + bJITLoadStoreFloatingOff(false), bJITLoadStorePairedOff(false), bJITFloatingPointOff(false), + bJITIntegerOff(false), bJITPairedOff(false), bJITSystemRegistersOff(false), + bJITBranchOff(false), bJITILTimeProfiling(false), bJITILOutputIR(false), bFPRF(false), + bAccurateNaNs(false), iTimingVariance(40), bCPUThread(true), bDSPThread(false), bDSPHLE(true), + bSkipIdle(true), bSyncGPUOnSkipIdleHack(true), bNTSC(false), bForceNTSCJ(false), + bHLE_BS2(true), bEnableCheats(false), bEnableMemcardSdWriting(true), bDPL2Decoder(false), + iLatency(14), bRunCompareServer(false), bRunCompareClient(false), bMMU(false), + bDCBZOFF(false), iBBDumpPort(0), bFastDiscSpeed(false), bSyncGPU(false), SelectedLanguage(0), + bOverrideGCLanguage(false), bWii(false), bConfirmStop(false), bHideCursor(false), + bAutoHideCursor(false), bUsePanicHandlers(true), bOnScreenDisplayMessages(true), + iRenderWindowXPos(-1), iRenderWindowYPos(-1), iRenderWindowWidth(640), + iRenderWindowHeight(480), bRenderWindowAutoSize(false), bKeepWindowOnTop(false), + bFullscreen(false), bRenderToMain(false), bProgressive(false), bPAL60(false), + bDisableScreenSaver(false), iPosX(100), iPosY(100), iWidth(800), iHeight(600), + m_analytics_enabled(false), m_analytics_permission_asked(false), bLoopFifoReplay(true) { - LoadDefaults(); - // Make sure we have log manager - LoadSettings(); + LoadDefaults(); + // Make sure we have log manager + LoadSettings(); } void SConfig::Init() { - m_Instance = new SConfig; + m_Instance = new SConfig; } void SConfig::Shutdown() { - delete m_Instance; - m_Instance = nullptr; + delete m_Instance; + m_Instance = nullptr; } SConfig::~SConfig() { - SaveSettings(); - delete m_SYSCONF; + SaveSettings(); + delete m_SYSCONF; } - void SConfig::SaveSettings() { - NOTICE_LOG(BOOT, "Saving settings to %s", File::GetUserPath(F_DOLPHINCONFIG_IDX).c_str()); - IniFile ini; - ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); // load first to not kill unknown stuff + NOTICE_LOG(BOOT, "Saving settings to %s", File::GetUserPath(F_DOLPHINCONFIG_IDX).c_str()); + IniFile ini; + ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); // load first to not kill unknown stuff - SaveGeneralSettings(ini); - SaveInterfaceSettings(ini); - SaveDisplaySettings(ini); - SaveGameListSettings(ini); - SaveCoreSettings(ini); - SaveMovieSettings(ini); - SaveDSPSettings(ini); - SaveInputSettings(ini); - SaveFifoPlayerSettings(ini); - SaveAnalyticsSettings(ini); + SaveGeneralSettings(ini); + SaveInterfaceSettings(ini); + SaveDisplaySettings(ini); + SaveGameListSettings(ini); + SaveCoreSettings(ini); + SaveMovieSettings(ini); + SaveDSPSettings(ini); + SaveInputSettings(ini); + SaveFifoPlayerSettings(ini); + SaveAnalyticsSettings(ini); - ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX)); - m_SYSCONF->Save(); + ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX)); + m_SYSCONF->Save(); } void SConfig::SaveGeneralSettings(IniFile& ini) { - IniFile::Section* general = ini.GetOrCreateSection("General"); + IniFile::Section* general = ini.GetOrCreateSection("General"); - // General - general->Set("LastFilename", m_LastFilename); - general->Set("ShowLag", m_ShowLag); - general->Set("ShowFrameCount", m_ShowFrameCount); + // General + general->Set("LastFilename", m_LastFilename); + general->Set("ShowLag", m_ShowLag); + general->Set("ShowFrameCount", m_ShowFrameCount); - // ISO folders - // Clear removed folders - int oldPaths; - int numPaths = (int)m_ISOFolder.size(); - general->Get("ISOPaths", &oldPaths, 0); - for (int i = numPaths; i < oldPaths; i++) - { - ini.DeleteKey("General", StringFromFormat("ISOPath%i", i)); - } + // ISO folders + // Clear removed folders + int oldPaths; + int numPaths = (int)m_ISOFolder.size(); + general->Get("ISOPaths", &oldPaths, 0); + for (int i = numPaths; i < oldPaths; i++) + { + ini.DeleteKey("General", StringFromFormat("ISOPath%i", i)); + } - general->Set("ISOPaths", numPaths); - for (int i = 0; i < numPaths; i++) - { - general->Set(StringFromFormat("ISOPath%i", i), m_ISOFolder[i]); - } + general->Set("ISOPaths", numPaths); + for (int i = 0; i < numPaths; i++) + { + general->Set(StringFromFormat("ISOPath%i", i), m_ISOFolder[i]); + } - general->Set("RecursiveISOPaths", m_RecursiveISOFolder); - general->Set("NANDRootPath", m_NANDPath); - general->Set("WirelessMac", m_WirelessMac); + general->Set("RecursiveISOPaths", m_RecursiveISOFolder); + general->Set("NANDRootPath", m_NANDPath); + general->Set("WirelessMac", m_WirelessMac); #ifdef USE_GDBSTUB #ifndef _WIN32 - general->Set("GDBSocket", gdb_socket); + general->Set("GDBSocket", gdb_socket); #endif - general->Set("GDBPort", iGDBPort); + general->Set("GDBPort", iGDBPort); #endif } void SConfig::SaveInterfaceSettings(IniFile& ini) { - IniFile::Section* interface = ini.GetOrCreateSection("Interface"); + IniFile::Section* interface = ini.GetOrCreateSection("Interface"); - interface->Set("ConfirmStop", bConfirmStop); - interface->Set("UsePanicHandlers", bUsePanicHandlers); - interface->Set("OnScreenDisplayMessages", bOnScreenDisplayMessages); - interface->Set("HideCursor", bHideCursor); - interface->Set("AutoHideCursor", bAutoHideCursor); - interface->Set("MainWindowPosX", (iPosX == -32000) ? 0 : iPosX); // TODO - HAX - interface->Set("MainWindowPosY", (iPosY == -32000) ? 0 : iPosY); // TODO - HAX - interface->Set("MainWindowWidth", iWidth); - interface->Set("MainWindowHeight", iHeight); - interface->Set("Language", m_InterfaceLanguage); - interface->Set("ShowToolbar", m_InterfaceToolbar); - interface->Set("ShowStatusbar", m_InterfaceStatusbar); - interface->Set("ShowLogWindow", m_InterfaceLogWindow); - interface->Set("ShowLogConfigWindow", m_InterfaceLogConfigWindow); - interface->Set("ExtendedFPSInfo", m_InterfaceExtendedFPSInfo); - interface->Set("ThemeName40", theme_name); - interface->Set("PauseOnFocusLost", m_PauseOnFocusLost); + interface->Set("ConfirmStop", bConfirmStop); + interface->Set("UsePanicHandlers", bUsePanicHandlers); + interface->Set("OnScreenDisplayMessages", bOnScreenDisplayMessages); + interface->Set("HideCursor", bHideCursor); + interface->Set("AutoHideCursor", bAutoHideCursor); + interface->Set("MainWindowPosX", (iPosX == -32000) ? 0 : iPosX); // TODO - HAX + interface->Set("MainWindowPosY", (iPosY == -32000) ? 0 : iPosY); // TODO - HAX + interface->Set("MainWindowWidth", iWidth); + interface->Set("MainWindowHeight", iHeight); + interface->Set("Language", m_InterfaceLanguage); + interface->Set("ShowToolbar", m_InterfaceToolbar); + interface->Set("ShowStatusbar", m_InterfaceStatusbar); + interface->Set("ShowLogWindow", m_InterfaceLogWindow); + interface->Set("ShowLogConfigWindow", m_InterfaceLogConfigWindow); + interface->Set("ExtendedFPSInfo", m_InterfaceExtendedFPSInfo); + interface->Set("ThemeName40", theme_name); + interface->Set("PauseOnFocusLost", m_PauseOnFocusLost); } void SConfig::SaveDisplaySettings(IniFile& ini) { - IniFile::Section* display = ini.GetOrCreateSection("Display"); + IniFile::Section* display = ini.GetOrCreateSection("Display"); - display->Set("FullscreenResolution", strFullscreenResolution); - display->Set("Fullscreen", bFullscreen); - display->Set("RenderToMain", bRenderToMain); - display->Set("RenderWindowXPos", iRenderWindowXPos); - display->Set("RenderWindowYPos", iRenderWindowYPos); - display->Set("RenderWindowWidth", iRenderWindowWidth); - display->Set("RenderWindowHeight", iRenderWindowHeight); - display->Set("RenderWindowAutoSize", bRenderWindowAutoSize); - display->Set("KeepWindowOnTop", bKeepWindowOnTop); - display->Set("ProgressiveScan", bProgressive); - display->Set("PAL60", bPAL60); - display->Set("DisableScreenSaver", bDisableScreenSaver); - display->Set("ForceNTSCJ", bForceNTSCJ); + display->Set("FullscreenResolution", strFullscreenResolution); + display->Set("Fullscreen", bFullscreen); + display->Set("RenderToMain", bRenderToMain); + display->Set("RenderWindowXPos", iRenderWindowXPos); + display->Set("RenderWindowYPos", iRenderWindowYPos); + display->Set("RenderWindowWidth", iRenderWindowWidth); + display->Set("RenderWindowHeight", iRenderWindowHeight); + display->Set("RenderWindowAutoSize", bRenderWindowAutoSize); + display->Set("KeepWindowOnTop", bKeepWindowOnTop); + display->Set("ProgressiveScan", bProgressive); + display->Set("PAL60", bPAL60); + display->Set("DisableScreenSaver", bDisableScreenSaver); + display->Set("ForceNTSCJ", bForceNTSCJ); } void SConfig::SaveGameListSettings(IniFile& ini) { - IniFile::Section* gamelist = ini.GetOrCreateSection("GameList"); + IniFile::Section* gamelist = ini.GetOrCreateSection("GameList"); - gamelist->Set("ListDrives", m_ListDrives); - gamelist->Set("ListWad", m_ListWad); - gamelist->Set("ListElfDol", m_ListElfDol); - gamelist->Set("ListWii", m_ListWii); - gamelist->Set("ListGC", m_ListGC); - gamelist->Set("ListJap", m_ListJap); - gamelist->Set("ListPal", m_ListPal); - gamelist->Set("ListUsa", m_ListUsa); - gamelist->Set("ListAustralia", m_ListAustralia); - gamelist->Set("ListFrance", m_ListFrance); - gamelist->Set("ListGermany", m_ListGermany); - gamelist->Set("ListItaly", m_ListItaly); - gamelist->Set("ListKorea", m_ListKorea); - gamelist->Set("ListNetherlands", m_ListNetherlands); - gamelist->Set("ListRussia", m_ListRussia); - gamelist->Set("ListSpain", m_ListSpain); - gamelist->Set("ListTaiwan", m_ListTaiwan); - gamelist->Set("ListWorld", m_ListWorld); - gamelist->Set("ListUnknown", m_ListUnknown); - gamelist->Set("ListSort", m_ListSort); - gamelist->Set("ListSortSecondary", m_ListSort2); + gamelist->Set("ListDrives", m_ListDrives); + gamelist->Set("ListWad", m_ListWad); + gamelist->Set("ListElfDol", m_ListElfDol); + gamelist->Set("ListWii", m_ListWii); + gamelist->Set("ListGC", m_ListGC); + gamelist->Set("ListJap", m_ListJap); + gamelist->Set("ListPal", m_ListPal); + gamelist->Set("ListUsa", m_ListUsa); + gamelist->Set("ListAustralia", m_ListAustralia); + gamelist->Set("ListFrance", m_ListFrance); + gamelist->Set("ListGermany", m_ListGermany); + gamelist->Set("ListItaly", m_ListItaly); + gamelist->Set("ListKorea", m_ListKorea); + gamelist->Set("ListNetherlands", m_ListNetherlands); + gamelist->Set("ListRussia", m_ListRussia); + gamelist->Set("ListSpain", m_ListSpain); + gamelist->Set("ListTaiwan", m_ListTaiwan); + gamelist->Set("ListWorld", m_ListWorld); + gamelist->Set("ListUnknown", m_ListUnknown); + gamelist->Set("ListSort", m_ListSort); + gamelist->Set("ListSortSecondary", m_ListSort2); - gamelist->Set("ColorCompressed", m_ColorCompressed); + gamelist->Set("ColorCompressed", m_ColorCompressed); - gamelist->Set("ColumnPlatform", m_showSystemColumn); - gamelist->Set("ColumnBanner", m_showBannerColumn); - gamelist->Set("ColumnNotes", m_showMakerColumn); - gamelist->Set("ColumnFileName", m_showFileNameColumn); - gamelist->Set("ColumnID", m_showIDColumn); - gamelist->Set("ColumnRegion", m_showRegionColumn); - gamelist->Set("ColumnSize", m_showSizeColumn); - gamelist->Set("ColumnState", m_showStateColumn); + gamelist->Set("ColumnPlatform", m_showSystemColumn); + gamelist->Set("ColumnBanner", m_showBannerColumn); + gamelist->Set("ColumnNotes", m_showMakerColumn); + gamelist->Set("ColumnFileName", m_showFileNameColumn); + gamelist->Set("ColumnID", m_showIDColumn); + gamelist->Set("ColumnRegion", m_showRegionColumn); + gamelist->Set("ColumnSize", m_showSizeColumn); + gamelist->Set("ColumnState", m_showStateColumn); } void SConfig::SaveCoreSettings(IniFile& ini) { - IniFile::Section* core = ini.GetOrCreateSection("Core"); + IniFile::Section* core = ini.GetOrCreateSection("Core"); - core->Set("HLE_BS2", bHLE_BS2); - core->Set("TimingVariance", iTimingVariance); - core->Set("CPUCore", iCPUCore); - core->Set("Fastmem", bFastmem); - core->Set("CPUThread", bCPUThread); - core->Set("DSPHLE", bDSPHLE); - core->Set("SkipIdle", bSkipIdle); - core->Set("SyncOnSkipIdle", bSyncGPUOnSkipIdleHack); - core->Set("SyncGPU", bSyncGPU); - core->Set("SyncGpuMaxDistance", iSyncGpuMaxDistance); - core->Set("SyncGpuMinDistance", iSyncGpuMinDistance); - core->Set("SyncGpuOverclock", fSyncGpuOverclock); - core->Set("FPRF", bFPRF); - core->Set("AccurateNaNs", bAccurateNaNs); - core->Set("DefaultISO", m_strDefaultISO); - core->Set("DVDRoot", m_strDVDRoot); - core->Set("Apploader", m_strApploader); - core->Set("EnableCheats", bEnableCheats); - core->Set("SelectedLanguage", SelectedLanguage); - core->Set("OverrideGCLang", bOverrideGCLanguage); - core->Set("DPL2Decoder", bDPL2Decoder); - core->Set("Latency", iLatency); - core->Set("MemcardAPath", m_strMemoryCardA); - core->Set("MemcardBPath", m_strMemoryCardB); - core->Set("AgpCartAPath", m_strGbaCartA); - core->Set("AgpCartBPath", m_strGbaCartB); - core->Set("SlotA", m_EXIDevice[0]); - core->Set("SlotB", m_EXIDevice[1]); - core->Set("SerialPort1", m_EXIDevice[2]); - core->Set("BBA_MAC", m_bba_mac); - for (int i = 0; i < MAX_SI_CHANNELS; ++i) - { - core->Set(StringFromFormat("SIDevice%i", i), m_SIDevice[i]); - core->Set(StringFromFormat("AdapterRumble%i", i), m_AdapterRumble[i]); - core->Set(StringFromFormat("SimulateKonga%i", i), m_AdapterKonga[i]); - } - core->Set("WiiSDCard", m_WiiSDCard); - core->Set("WiiKeyboard", m_WiiKeyboard); - core->Set("WiimoteContinuousScanning", m_WiimoteContinuousScanning); - core->Set("WiimoteEnableSpeaker", m_WiimoteEnableSpeaker); - core->Set("RunCompareServer", bRunCompareServer); - core->Set("RunCompareClient", bRunCompareClient); - core->Set("EmulationSpeed", m_EmulationSpeed); - core->Set("FrameSkip", m_FrameSkip); - core->Set("Overclock", m_OCFactor); - core->Set("OverclockEnable", m_OCEnable); - core->Set("GFXBackend", m_strVideoBackend); - core->Set("GPUDeterminismMode", m_strGPUDeterminismMode); - core->Set("PerfMapDir", m_perfDir); + core->Set("HLE_BS2", bHLE_BS2); + core->Set("TimingVariance", iTimingVariance); + core->Set("CPUCore", iCPUCore); + core->Set("Fastmem", bFastmem); + core->Set("CPUThread", bCPUThread); + core->Set("DSPHLE", bDSPHLE); + core->Set("SkipIdle", bSkipIdle); + core->Set("SyncOnSkipIdle", bSyncGPUOnSkipIdleHack); + core->Set("SyncGPU", bSyncGPU); + core->Set("SyncGpuMaxDistance", iSyncGpuMaxDistance); + core->Set("SyncGpuMinDistance", iSyncGpuMinDistance); + core->Set("SyncGpuOverclock", fSyncGpuOverclock); + core->Set("FPRF", bFPRF); + core->Set("AccurateNaNs", bAccurateNaNs); + core->Set("DefaultISO", m_strDefaultISO); + core->Set("DVDRoot", m_strDVDRoot); + core->Set("Apploader", m_strApploader); + core->Set("EnableCheats", bEnableCheats); + core->Set("SelectedLanguage", SelectedLanguage); + core->Set("OverrideGCLang", bOverrideGCLanguage); + core->Set("DPL2Decoder", bDPL2Decoder); + core->Set("Latency", iLatency); + core->Set("MemcardAPath", m_strMemoryCardA); + core->Set("MemcardBPath", m_strMemoryCardB); + core->Set("AgpCartAPath", m_strGbaCartA); + core->Set("AgpCartBPath", m_strGbaCartB); + core->Set("SlotA", m_EXIDevice[0]); + core->Set("SlotB", m_EXIDevice[1]); + core->Set("SerialPort1", m_EXIDevice[2]); + core->Set("BBA_MAC", m_bba_mac); + for (int i = 0; i < MAX_SI_CHANNELS; ++i) + { + core->Set(StringFromFormat("SIDevice%i", i), m_SIDevice[i]); + core->Set(StringFromFormat("AdapterRumble%i", i), m_AdapterRumble[i]); + core->Set(StringFromFormat("SimulateKonga%i", i), m_AdapterKonga[i]); + } + core->Set("WiiSDCard", m_WiiSDCard); + core->Set("WiiKeyboard", m_WiiKeyboard); + core->Set("WiimoteContinuousScanning", m_WiimoteContinuousScanning); + core->Set("WiimoteEnableSpeaker", m_WiimoteEnableSpeaker); + core->Set("RunCompareServer", bRunCompareServer); + core->Set("RunCompareClient", bRunCompareClient); + core->Set("EmulationSpeed", m_EmulationSpeed); + core->Set("FrameSkip", m_FrameSkip); + core->Set("Overclock", m_OCFactor); + core->Set("OverclockEnable", m_OCEnable); + core->Set("GFXBackend", m_strVideoBackend); + core->Set("GPUDeterminismMode", m_strGPUDeterminismMode); + core->Set("PerfMapDir", m_perfDir); } void SConfig::SaveMovieSettings(IniFile& ini) { - IniFile::Section* movie = ini.GetOrCreateSection("Movie"); + IniFile::Section* movie = ini.GetOrCreateSection("Movie"); - movie->Set("PauseMovie", m_PauseMovie); - movie->Set("Author", m_strMovieAuthor); - movie->Set("DumpFrames", m_DumpFrames); - movie->Set("DumpFramesSilent", m_DumpFramesSilent); - movie->Set("ShowInputDisplay", m_ShowInputDisplay); + movie->Set("PauseMovie", m_PauseMovie); + movie->Set("Author", m_strMovieAuthor); + movie->Set("DumpFrames", m_DumpFrames); + movie->Set("DumpFramesSilent", m_DumpFramesSilent); + movie->Set("ShowInputDisplay", m_ShowInputDisplay); } void SConfig::SaveDSPSettings(IniFile& ini) { - IniFile::Section* dsp = ini.GetOrCreateSection("DSP"); + IniFile::Section* dsp = ini.GetOrCreateSection("DSP"); - dsp->Set("EnableJIT", m_DSPEnableJIT); - dsp->Set("DumpAudio", m_DumpAudio); - dsp->Set("DumpUCode", m_DumpUCode); - dsp->Set("Backend", sBackend); - dsp->Set("Volume", m_Volume); - dsp->Set("CaptureLog", m_DSPCaptureLog); + dsp->Set("EnableJIT", m_DSPEnableJIT); + dsp->Set("DumpAudio", m_DumpAudio); + dsp->Set("DumpUCode", m_DumpUCode); + dsp->Set("Backend", sBackend); + dsp->Set("Volume", m_Volume); + dsp->Set("CaptureLog", m_DSPCaptureLog); } void SConfig::SaveInputSettings(IniFile& ini) { - IniFile::Section* input = ini.GetOrCreateSection("Input"); + IniFile::Section* input = ini.GetOrCreateSection("Input"); - input->Set("BackgroundInput", m_BackgroundInput); + input->Set("BackgroundInput", m_BackgroundInput); } void SConfig::SaveFifoPlayerSettings(IniFile& ini) { - IniFile::Section* fifoplayer = ini.GetOrCreateSection("FifoPlayer"); + IniFile::Section* fifoplayer = ini.GetOrCreateSection("FifoPlayer"); - fifoplayer->Set("LoopReplay", bLoopFifoReplay); + fifoplayer->Set("LoopReplay", bLoopFifoReplay); } void SConfig::SaveAnalyticsSettings(IniFile& ini) { - IniFile::Section* analytics = ini.GetOrCreateSection("Analytics"); + IniFile::Section* analytics = ini.GetOrCreateSection("Analytics"); - analytics->Set("ID", m_analytics_id); - analytics->Set("Enabled", m_analytics_enabled); - analytics->Set("PermissionAsked", m_analytics_permission_asked); + analytics->Set("ID", m_analytics_id); + analytics->Set("Enabled", m_analytics_enabled); + analytics->Set("PermissionAsked", m_analytics_permission_asked); } void SConfig::LoadSettings() { - INFO_LOG(BOOT, "Loading Settings from %s", File::GetUserPath(F_DOLPHINCONFIG_IDX).c_str()); - IniFile ini; - ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); + INFO_LOG(BOOT, "Loading Settings from %s", File::GetUserPath(F_DOLPHINCONFIG_IDX).c_str()); + IniFile ini; + ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); - LoadGeneralSettings(ini); - LoadInterfaceSettings(ini); - LoadDisplaySettings(ini); - LoadGameListSettings(ini); - LoadCoreSettings(ini); - LoadMovieSettings(ini); - LoadDSPSettings(ini); - LoadInputSettings(ini); - LoadFifoPlayerSettings(ini); - LoadAnalyticsSettings(ini); + LoadGeneralSettings(ini); + LoadInterfaceSettings(ini); + LoadDisplaySettings(ini); + LoadGameListSettings(ini); + LoadCoreSettings(ini); + LoadMovieSettings(ini); + LoadDSPSettings(ini); + LoadInputSettings(ini); + LoadFifoPlayerSettings(ini); + LoadAnalyticsSettings(ini); - m_SYSCONF = new SysConf(); + m_SYSCONF = new SysConf(); } void SConfig::LoadGeneralSettings(IniFile& ini) { - IniFile::Section* general = ini.GetOrCreateSection("General"); + IniFile::Section* general = ini.GetOrCreateSection("General"); - general->Get("LastFilename", &m_LastFilename); - general->Get("ShowLag", &m_ShowLag, false); - general->Get("ShowFrameCount", &m_ShowFrameCount, false); + general->Get("LastFilename", &m_LastFilename); + general->Get("ShowLag", &m_ShowLag, false); + general->Get("ShowFrameCount", &m_ShowFrameCount, false); #ifdef USE_GDBSTUB #ifndef _WIN32 - general->Get("GDBSocket", &gdb_socket, ""); + general->Get("GDBSocket", &gdb_socket, ""); #endif - general->Get("GDBPort", &(iGDBPort), -1); + general->Get("GDBPort", &(iGDBPort), -1); #endif - m_ISOFolder.clear(); - int numISOPaths; + m_ISOFolder.clear(); + int numISOPaths; - if (general->Get("ISOPaths", &numISOPaths, 0)) - { - for (int i = 0; i < numISOPaths; i++) - { - std::string tmpPath; - general->Get(StringFromFormat("ISOPath%i", i), &tmpPath, ""); - m_ISOFolder.push_back(std::move(tmpPath)); - } - } - // Check for old file path (Changed in 4.0-4003) - // This can probably be removed after 5.0 stable is launched - else if (general->Get("GCMPathes", &numISOPaths, 0)) - { - for (int i = 0; i < numISOPaths; i++) - { - std::string tmpPath; - general->Get(StringFromFormat("GCMPath%i", i), &tmpPath, ""); - bool found = false; - for (size_t j = 0; j < m_ISOFolder.size(); ++j) - { - if (m_ISOFolder[j] == tmpPath) - { - found = true; - break; - } - } - if (!found) - m_ISOFolder.push_back(std::move(tmpPath)); - } - } + if (general->Get("ISOPaths", &numISOPaths, 0)) + { + for (int i = 0; i < numISOPaths; i++) + { + std::string tmpPath; + general->Get(StringFromFormat("ISOPath%i", i), &tmpPath, ""); + m_ISOFolder.push_back(std::move(tmpPath)); + } + } + // Check for old file path (Changed in 4.0-4003) + // This can probably be removed after 5.0 stable is launched + else if (general->Get("GCMPathes", &numISOPaths, 0)) + { + for (int i = 0; i < numISOPaths; i++) + { + std::string tmpPath; + general->Get(StringFromFormat("GCMPath%i", i), &tmpPath, ""); + bool found = false; + for (size_t j = 0; j < m_ISOFolder.size(); ++j) + { + if (m_ISOFolder[j] == tmpPath) + { + found = true; + break; + } + } + if (!found) + m_ISOFolder.push_back(std::move(tmpPath)); + } + } - if (!general->Get("RecursiveISOPaths", &m_RecursiveISOFolder, false)) - { - // Check for old name - general->Get("RecursiveGCMPaths", &m_RecursiveISOFolder, false); - } + if (!general->Get("RecursiveISOPaths", &m_RecursiveISOFolder, false)) + { + // Check for old name + general->Get("RecursiveGCMPaths", &m_RecursiveISOFolder, false); + } - general->Get("NANDRootPath", &m_NANDPath); - File::SetUserPath(D_WIIROOT_IDX, m_NANDPath); - general->Get("WirelessMac", &m_WirelessMac); + general->Get("NANDRootPath", &m_NANDPath); + File::SetUserPath(D_WIIROOT_IDX, m_NANDPath); + general->Get("WirelessMac", &m_WirelessMac); } void SConfig::LoadInterfaceSettings(IniFile& ini) { - IniFile::Section* interface = ini.GetOrCreateSection("Interface"); + IniFile::Section* interface = ini.GetOrCreateSection("Interface"); - interface->Get("ConfirmStop", &bConfirmStop, true); - interface->Get("UsePanicHandlers", &bUsePanicHandlers, true); - interface->Get("OnScreenDisplayMessages", &bOnScreenDisplayMessages, true); - interface->Get("HideCursor", &bHideCursor, false); - interface->Get("AutoHideCursor", &bAutoHideCursor, false); - interface->Get("MainWindowPosX", &iPosX, 100); - interface->Get("MainWindowPosY", &iPosY, 100); - interface->Get("MainWindowWidth", &iWidth, 800); - interface->Get("MainWindowHeight", &iHeight, 600); - interface->Get("Language", &m_InterfaceLanguage, 0); - interface->Get("ShowToolbar", &m_InterfaceToolbar, true); - interface->Get("ShowStatusbar", &m_InterfaceStatusbar, true); - interface->Get("ShowLogWindow", &m_InterfaceLogWindow, false); - interface->Get("ShowLogConfigWindow", &m_InterfaceLogConfigWindow, false); - interface->Get("ExtendedFPSInfo", &m_InterfaceExtendedFPSInfo, false); - interface->Get("ThemeName40", &theme_name, "Clean"); - interface->Get("PauseOnFocusLost", &m_PauseOnFocusLost, false); + interface->Get("ConfirmStop", &bConfirmStop, true); + interface->Get("UsePanicHandlers", &bUsePanicHandlers, true); + interface->Get("OnScreenDisplayMessages", &bOnScreenDisplayMessages, true); + interface->Get("HideCursor", &bHideCursor, false); + interface->Get("AutoHideCursor", &bAutoHideCursor, false); + interface->Get("MainWindowPosX", &iPosX, 100); + interface->Get("MainWindowPosY", &iPosY, 100); + interface->Get("MainWindowWidth", &iWidth, 800); + interface->Get("MainWindowHeight", &iHeight, 600); + interface->Get("Language", &m_InterfaceLanguage, 0); + interface->Get("ShowToolbar", &m_InterfaceToolbar, true); + interface->Get("ShowStatusbar", &m_InterfaceStatusbar, true); + interface->Get("ShowLogWindow", &m_InterfaceLogWindow, false); + interface->Get("ShowLogConfigWindow", &m_InterfaceLogConfigWindow, false); + interface->Get("ExtendedFPSInfo", &m_InterfaceExtendedFPSInfo, false); + interface->Get("ThemeName40", &theme_name, "Clean"); + interface->Get("PauseOnFocusLost", &m_PauseOnFocusLost, false); } void SConfig::LoadDisplaySettings(IniFile& ini) { - IniFile::Section* display = ini.GetOrCreateSection("Display"); + IniFile::Section* display = ini.GetOrCreateSection("Display"); - display->Get("Fullscreen", &bFullscreen, false); - display->Get("FullscreenResolution", &strFullscreenResolution, "Auto"); - display->Get("RenderToMain", &bRenderToMain, false); - display->Get("RenderWindowXPos", &iRenderWindowXPos, -1); - display->Get("RenderWindowYPos", &iRenderWindowYPos, -1); - display->Get("RenderWindowWidth", &iRenderWindowWidth, 640); - display->Get("RenderWindowHeight", &iRenderWindowHeight, 480); - display->Get("RenderWindowAutoSize", &bRenderWindowAutoSize, false); - display->Get("KeepWindowOnTop", &bKeepWindowOnTop, false); - display->Get("ProgressiveScan", &bProgressive, false); - display->Get("PAL60", &bPAL60, true); - display->Get("DisableScreenSaver", &bDisableScreenSaver, true); - display->Get("ForceNTSCJ", &bForceNTSCJ, false); + display->Get("Fullscreen", &bFullscreen, false); + display->Get("FullscreenResolution", &strFullscreenResolution, "Auto"); + display->Get("RenderToMain", &bRenderToMain, false); + display->Get("RenderWindowXPos", &iRenderWindowXPos, -1); + display->Get("RenderWindowYPos", &iRenderWindowYPos, -1); + display->Get("RenderWindowWidth", &iRenderWindowWidth, 640); + display->Get("RenderWindowHeight", &iRenderWindowHeight, 480); + display->Get("RenderWindowAutoSize", &bRenderWindowAutoSize, false); + display->Get("KeepWindowOnTop", &bKeepWindowOnTop, false); + display->Get("ProgressiveScan", &bProgressive, false); + display->Get("PAL60", &bPAL60, true); + display->Get("DisableScreenSaver", &bDisableScreenSaver, true); + display->Get("ForceNTSCJ", &bForceNTSCJ, false); } void SConfig::LoadGameListSettings(IniFile& ini) { - IniFile::Section* gamelist = ini.GetOrCreateSection("GameList"); + IniFile::Section* gamelist = ini.GetOrCreateSection("GameList"); - gamelist->Get("ListDrives", &m_ListDrives, false); - gamelist->Get("ListWad", &m_ListWad, true); - gamelist->Get("ListElfDol", &m_ListElfDol, true); - gamelist->Get("ListWii", &m_ListWii, true); - gamelist->Get("ListGC", &m_ListGC, true); - gamelist->Get("ListJap", &m_ListJap, true); - gamelist->Get("ListPal", &m_ListPal, true); - gamelist->Get("ListUsa", &m_ListUsa, true); + gamelist->Get("ListDrives", &m_ListDrives, false); + gamelist->Get("ListWad", &m_ListWad, true); + gamelist->Get("ListElfDol", &m_ListElfDol, true); + gamelist->Get("ListWii", &m_ListWii, true); + gamelist->Get("ListGC", &m_ListGC, true); + gamelist->Get("ListJap", &m_ListJap, true); + gamelist->Get("ListPal", &m_ListPal, true); + gamelist->Get("ListUsa", &m_ListUsa, true); - gamelist->Get("ListAustralia", &m_ListAustralia, true); - gamelist->Get("ListFrance", &m_ListFrance, true); - gamelist->Get("ListGermany", &m_ListGermany, true); - gamelist->Get("ListItaly", &m_ListItaly, true); - gamelist->Get("ListKorea", &m_ListKorea, true); - gamelist->Get("ListNetherlands", &m_ListNetherlands, true); - gamelist->Get("ListRussia", &m_ListRussia, true); - gamelist->Get("ListSpain", &m_ListSpain, true); - gamelist->Get("ListTaiwan", &m_ListTaiwan, true); - gamelist->Get("ListWorld", &m_ListWorld, true); - gamelist->Get("ListUnknown", &m_ListUnknown, true); - gamelist->Get("ListSort", &m_ListSort, 3); - gamelist->Get("ListSortSecondary", &m_ListSort2, 0); + gamelist->Get("ListAustralia", &m_ListAustralia, true); + gamelist->Get("ListFrance", &m_ListFrance, true); + gamelist->Get("ListGermany", &m_ListGermany, true); + gamelist->Get("ListItaly", &m_ListItaly, true); + gamelist->Get("ListKorea", &m_ListKorea, true); + gamelist->Get("ListNetherlands", &m_ListNetherlands, true); + gamelist->Get("ListRussia", &m_ListRussia, true); + gamelist->Get("ListSpain", &m_ListSpain, true); + gamelist->Get("ListTaiwan", &m_ListTaiwan, true); + gamelist->Get("ListWorld", &m_ListWorld, true); + gamelist->Get("ListUnknown", &m_ListUnknown, true); + gamelist->Get("ListSort", &m_ListSort, 3); + gamelist->Get("ListSortSecondary", &m_ListSort2, 0); - // Determines if compressed games display in blue - gamelist->Get("ColorCompressed", &m_ColorCompressed, true); + // Determines if compressed games display in blue + gamelist->Get("ColorCompressed", &m_ColorCompressed, true); - // Gamelist columns toggles - gamelist->Get("ColumnPlatform", &m_showSystemColumn, true); - gamelist->Get("ColumnBanner", &m_showBannerColumn, true); - gamelist->Get("ColumnNotes", &m_showMakerColumn, true); - gamelist->Get("ColumnFileName", &m_showFileNameColumn, false); - gamelist->Get("ColumnID", &m_showIDColumn, false); - gamelist->Get("ColumnRegion", &m_showRegionColumn, true); - gamelist->Get("ColumnSize", &m_showSizeColumn, true); - gamelist->Get("ColumnState", &m_showStateColumn, true); + // Gamelist columns toggles + gamelist->Get("ColumnPlatform", &m_showSystemColumn, true); + gamelist->Get("ColumnBanner", &m_showBannerColumn, true); + gamelist->Get("ColumnNotes", &m_showMakerColumn, true); + gamelist->Get("ColumnFileName", &m_showFileNameColumn, false); + gamelist->Get("ColumnID", &m_showIDColumn, false); + gamelist->Get("ColumnRegion", &m_showRegionColumn, true); + gamelist->Get("ColumnSize", &m_showSizeColumn, true); + gamelist->Get("ColumnState", &m_showStateColumn, true); } void SConfig::LoadCoreSettings(IniFile& ini) { - IniFile::Section* core = ini.GetOrCreateSection("Core"); + IniFile::Section* core = ini.GetOrCreateSection("Core"); - core->Get("HLE_BS2", &bHLE_BS2, false); + core->Get("HLE_BS2", &bHLE_BS2, false); #ifdef _M_X86 - core->Get("CPUCore", &iCPUCore, PowerPC::CORE_JIT64); + core->Get("CPUCore", &iCPUCore, PowerPC::CORE_JIT64); #elif _M_ARM_64 - core->Get("CPUCore", &iCPUCore, PowerPC::CORE_JITARM64); + core->Get("CPUCore", &iCPUCore, PowerPC::CORE_JITARM64); #else - core->Get("CPUCore", &iCPUCore, PowerPC::CORE_INTERPRETER); + core->Get("CPUCore", &iCPUCore, PowerPC::CORE_INTERPRETER); #endif - core->Get("Fastmem", &bFastmem, true); - core->Get("DSPHLE", &bDSPHLE, true); - core->Get("TimingVariance", &iTimingVariance, 40); - core->Get("CPUThread", &bCPUThread, true); - core->Get("SkipIdle", &bSkipIdle, true); - core->Get("SyncOnSkipIdle", &bSyncGPUOnSkipIdleHack, true); - core->Get("DefaultISO", &m_strDefaultISO); - core->Get("DVDRoot", &m_strDVDRoot); - core->Get("Apploader", &m_strApploader); - core->Get("EnableCheats", &bEnableCheats, false); - core->Get("SelectedLanguage", &SelectedLanguage, 0); - core->Get("OverrideGCLang", &bOverrideGCLanguage, false); - core->Get("DPL2Decoder", &bDPL2Decoder, false); - core->Get("Latency", &iLatency, 2); - core->Get("MemcardAPath", &m_strMemoryCardA); - core->Get("MemcardBPath", &m_strMemoryCardB); - core->Get("AgpCartAPath", &m_strGbaCartA); - core->Get("AgpCartBPath", &m_strGbaCartB); - core->Get("SlotA", (int*)&m_EXIDevice[0], EXIDEVICE_MEMORYCARD); - core->Get("SlotB", (int*)&m_EXIDevice[1], EXIDEVICE_NONE); - core->Get("SerialPort1", (int*)&m_EXIDevice[2], EXIDEVICE_NONE); - core->Get("BBA_MAC", &m_bba_mac); - core->Get("TimeProfiling", &bJITILTimeProfiling, false); - core->Get("OutputIR", &bJITILOutputIR, false); - for (int i = 0; i < MAX_SI_CHANNELS; ++i) - { - core->Get(StringFromFormat("SIDevice%i", i), (u32*)&m_SIDevice[i], (i == 0) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE); - core->Get(StringFromFormat("AdapterRumble%i", i), &m_AdapterRumble[i], true); - core->Get(StringFromFormat("SimulateKonga%i", i), &m_AdapterKonga[i], false); - } - core->Get("WiiSDCard", &m_WiiSDCard, false); - core->Get("WiiKeyboard", &m_WiiKeyboard, false); - core->Get("WiimoteContinuousScanning", &m_WiimoteContinuousScanning, false); - core->Get("WiimoteEnableSpeaker", &m_WiimoteEnableSpeaker, false); - core->Get("RunCompareServer", &bRunCompareServer, false); - core->Get("RunCompareClient", &bRunCompareClient, false); - core->Get("MMU", &bMMU, false); - core->Get("BBDumpPort", &iBBDumpPort, -1); - core->Get("SyncGPU", &bSyncGPU, false); - core->Get("SyncGpuMaxDistance", &iSyncGpuMaxDistance, 200000); - core->Get("SyncGpuMinDistance", &iSyncGpuMinDistance, -200000); - core->Get("SyncGpuOverclock", &fSyncGpuOverclock, 1.0); - core->Get("FastDiscSpeed", &bFastDiscSpeed, false); - core->Get("DCBZ", &bDCBZOFF, false); - core->Get("FPRF", &bFPRF, false); - core->Get("AccurateNaNs", &bAccurateNaNs, false); - core->Get("EmulationSpeed", &m_EmulationSpeed, 1.0f); - core->Get("Overclock", &m_OCFactor, 1.0f); - core->Get("OverclockEnable", &m_OCEnable, false); - core->Get("FrameSkip", &m_FrameSkip, 0); - core->Get("GFXBackend", &m_strVideoBackend, ""); - core->Get("GPUDeterminismMode", &m_strGPUDeterminismMode, "auto"); - core->Get("PerfMapDir", &m_perfDir, ""); + core->Get("Fastmem", &bFastmem, true); + core->Get("DSPHLE", &bDSPHLE, true); + core->Get("TimingVariance", &iTimingVariance, 40); + core->Get("CPUThread", &bCPUThread, true); + core->Get("SkipIdle", &bSkipIdle, true); + core->Get("SyncOnSkipIdle", &bSyncGPUOnSkipIdleHack, true); + core->Get("DefaultISO", &m_strDefaultISO); + core->Get("DVDRoot", &m_strDVDRoot); + core->Get("Apploader", &m_strApploader); + core->Get("EnableCheats", &bEnableCheats, false); + core->Get("SelectedLanguage", &SelectedLanguage, 0); + core->Get("OverrideGCLang", &bOverrideGCLanguage, false); + core->Get("DPL2Decoder", &bDPL2Decoder, false); + core->Get("Latency", &iLatency, 2); + core->Get("MemcardAPath", &m_strMemoryCardA); + core->Get("MemcardBPath", &m_strMemoryCardB); + core->Get("AgpCartAPath", &m_strGbaCartA); + core->Get("AgpCartBPath", &m_strGbaCartB); + core->Get("SlotA", (int*)&m_EXIDevice[0], EXIDEVICE_MEMORYCARD); + core->Get("SlotB", (int*)&m_EXIDevice[1], EXIDEVICE_NONE); + core->Get("SerialPort1", (int*)&m_EXIDevice[2], EXIDEVICE_NONE); + core->Get("BBA_MAC", &m_bba_mac); + core->Get("TimeProfiling", &bJITILTimeProfiling, false); + core->Get("OutputIR", &bJITILOutputIR, false); + for (int i = 0; i < MAX_SI_CHANNELS; ++i) + { + core->Get(StringFromFormat("SIDevice%i", i), (u32*)&m_SIDevice[i], + (i == 0) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE); + core->Get(StringFromFormat("AdapterRumble%i", i), &m_AdapterRumble[i], true); + core->Get(StringFromFormat("SimulateKonga%i", i), &m_AdapterKonga[i], false); + } + core->Get("WiiSDCard", &m_WiiSDCard, false); + core->Get("WiiKeyboard", &m_WiiKeyboard, false); + core->Get("WiimoteContinuousScanning", &m_WiimoteContinuousScanning, false); + core->Get("WiimoteEnableSpeaker", &m_WiimoteEnableSpeaker, false); + core->Get("RunCompareServer", &bRunCompareServer, false); + core->Get("RunCompareClient", &bRunCompareClient, false); + core->Get("MMU", &bMMU, false); + core->Get("BBDumpPort", &iBBDumpPort, -1); + core->Get("SyncGPU", &bSyncGPU, false); + core->Get("SyncGpuMaxDistance", &iSyncGpuMaxDistance, 200000); + core->Get("SyncGpuMinDistance", &iSyncGpuMinDistance, -200000); + core->Get("SyncGpuOverclock", &fSyncGpuOverclock, 1.0); + core->Get("FastDiscSpeed", &bFastDiscSpeed, false); + core->Get("DCBZ", &bDCBZOFF, false); + core->Get("FPRF", &bFPRF, false); + core->Get("AccurateNaNs", &bAccurateNaNs, false); + core->Get("EmulationSpeed", &m_EmulationSpeed, 1.0f); + core->Get("Overclock", &m_OCFactor, 1.0f); + core->Get("OverclockEnable", &m_OCEnable, false); + core->Get("FrameSkip", &m_FrameSkip, 0); + core->Get("GFXBackend", &m_strVideoBackend, ""); + core->Get("GPUDeterminismMode", &m_strGPUDeterminismMode, "auto"); + core->Get("PerfMapDir", &m_perfDir, ""); } void SConfig::LoadMovieSettings(IniFile& ini) { - IniFile::Section* movie = ini.GetOrCreateSection("Movie"); + IniFile::Section* movie = ini.GetOrCreateSection("Movie"); - movie->Get("PauseMovie", &m_PauseMovie, false); - movie->Get("Author", &m_strMovieAuthor, ""); - movie->Get("DumpFrames", &m_DumpFrames, false); - movie->Get("DumpFramesSilent", &m_DumpFramesSilent, false); - movie->Get("ShowInputDisplay", &m_ShowInputDisplay, false); + movie->Get("PauseMovie", &m_PauseMovie, false); + movie->Get("Author", &m_strMovieAuthor, ""); + movie->Get("DumpFrames", &m_DumpFrames, false); + movie->Get("DumpFramesSilent", &m_DumpFramesSilent, false); + movie->Get("ShowInputDisplay", &m_ShowInputDisplay, false); } void SConfig::LoadDSPSettings(IniFile& ini) { - IniFile::Section* dsp = ini.GetOrCreateSection("DSP"); + IniFile::Section* dsp = ini.GetOrCreateSection("DSP"); - dsp->Get("EnableJIT", &m_DSPEnableJIT, true); - dsp->Get("DumpAudio", &m_DumpAudio, false); - dsp->Get("DumpUCode", &m_DumpUCode, false); + dsp->Get("EnableJIT", &m_DSPEnableJIT, true); + dsp->Get("DumpAudio", &m_DumpAudio, false); + dsp->Get("DumpUCode", &m_DumpUCode, false); #if defined __linux__ && HAVE_ALSA - dsp->Get("Backend", &sBackend, BACKEND_ALSA); + dsp->Get("Backend", &sBackend, BACKEND_ALSA); #elif defined __APPLE__ - dsp->Get("Backend", &sBackend, BACKEND_COREAUDIO); + dsp->Get("Backend", &sBackend, BACKEND_COREAUDIO); #elif defined _WIN32 - dsp->Get("Backend", &sBackend, BACKEND_XAUDIO2); + dsp->Get("Backend", &sBackend, BACKEND_XAUDIO2); #elif defined ANDROID - dsp->Get("Backend", &sBackend, BACKEND_OPENSLES); + dsp->Get("Backend", &sBackend, BACKEND_OPENSLES); #else - dsp->Get("Backend", &sBackend, BACKEND_NULLSOUND); + dsp->Get("Backend", &sBackend, BACKEND_NULLSOUND); #endif - dsp->Get("Volume", &m_Volume, 100); - dsp->Get("CaptureLog", &m_DSPCaptureLog, false); + dsp->Get("Volume", &m_Volume, 100); + dsp->Get("CaptureLog", &m_DSPCaptureLog, false); - m_IsMuted = false; + m_IsMuted = false; } void SConfig::LoadInputSettings(IniFile& ini) { - IniFile::Section* input = ini.GetOrCreateSection("Input"); + IniFile::Section* input = ini.GetOrCreateSection("Input"); - input->Get("BackgroundInput", &m_BackgroundInput, false); + input->Get("BackgroundInput", &m_BackgroundInput, false); } void SConfig::LoadFifoPlayerSettings(IniFile& ini) { - IniFile::Section* fifoplayer = ini.GetOrCreateSection("FifoPlayer"); + IniFile::Section* fifoplayer = ini.GetOrCreateSection("FifoPlayer"); - fifoplayer->Get("LoopReplay", &bLoopFifoReplay, true); + fifoplayer->Get("LoopReplay", &bLoopFifoReplay, true); } void SConfig::LoadAnalyticsSettings(IniFile& ini) { - IniFile::Section* analytics = ini.GetOrCreateSection("Analytics"); + IniFile::Section* analytics = ini.GetOrCreateSection("Analytics"); - analytics->Get("ID", &m_analytics_id, ""); - analytics->Get("Enabled", &m_analytics_enabled, false); - analytics->Get("PermissionAsked", &m_analytics_permission_asked, false); + analytics->Get("ID", &m_analytics_id, ""); + analytics->Get("Enabled", &m_analytics_enabled, false); + analytics->Get("PermissionAsked", &m_analytics_permission_asked, false); } void SConfig::LoadDefaults() { - bEnableDebugging = false; - bAutomaticStart = false; - bBootToPause = false; + bEnableDebugging = false; + bAutomaticStart = false; + bBootToPause = false; - #ifdef USE_GDBSTUB - iGDBPort = -1; - #ifndef _WIN32 - gdb_socket = ""; - #endif - #endif +#ifdef USE_GDBSTUB + iGDBPort = -1; +#ifndef _WIN32 + gdb_socket = ""; +#endif +#endif - iCPUCore = PowerPC::CORE_JIT64; - iTimingVariance = 40; - bCPUThread = false; - bSkipIdle = false; - bSyncGPUOnSkipIdleHack = true; - bRunCompareServer = false; - bDSPHLE = true; - bFastmem = true; - bFPRF = false; - bAccurateNaNs = false; - bMMU = false; - bDCBZOFF = false; - iBBDumpPort = -1; - bSyncGPU = false; - bFastDiscSpeed = false; - bEnableMemcardSdWriting = true; - SelectedLanguage = 0; - bOverrideGCLanguage = false; - bWii = false; - bDPL2Decoder = false; - iLatency = 14; + iCPUCore = PowerPC::CORE_JIT64; + iTimingVariance = 40; + bCPUThread = false; + bSkipIdle = false; + bSyncGPUOnSkipIdleHack = true; + bRunCompareServer = false; + bDSPHLE = true; + bFastmem = true; + bFPRF = false; + bAccurateNaNs = false; + bMMU = false; + bDCBZOFF = false; + iBBDumpPort = -1; + bSyncGPU = false; + bFastDiscSpeed = false; + bEnableMemcardSdWriting = true; + SelectedLanguage = 0; + bOverrideGCLanguage = false; + bWii = false; + bDPL2Decoder = false; + iLatency = 14; - iPosX = 100; - iPosY = 100; - iWidth = 800; - iHeight = 600; + iPosX = 100; + iPosY = 100; + iWidth = 800; + iHeight = 600; - m_analytics_id = ""; - m_analytics_enabled = false; - m_analytics_permission_asked = false; + m_analytics_id = ""; + m_analytics_enabled = false; + m_analytics_permission_asked = false; - bLoopFifoReplay = true; + bLoopFifoReplay = true; - bJITOff = false; // debugger only settings - bJITLoadStoreOff = false; - bJITLoadStoreFloatingOff = false; - bJITLoadStorePairedOff = false; - bJITFloatingPointOff = false; - bJITIntegerOff = false; - bJITPairedOff = false; - bJITSystemRegistersOff = false; - bJITBranchOff = false; + bJITOff = false; // debugger only settings + bJITLoadStoreOff = false; + bJITLoadStoreFloatingOff = false; + bJITLoadStorePairedOff = false; + bJITFloatingPointOff = false; + bJITIntegerOff = false; + bJITPairedOff = false; + bJITSystemRegistersOff = false; + bJITBranchOff = false; - m_strName = "NONE"; - m_strUniqueID = "00000000"; - m_revision = 0; + m_strName = "NONE"; + m_strUniqueID = "00000000"; + m_revision = 0; } static const char* GetRegionOfCountry(DiscIO::IVolume::ECountry country) { - switch (country) - { - case DiscIO::IVolume::COUNTRY_USA: - return USA_DIR; + switch (country) + { + case DiscIO::IVolume::COUNTRY_USA: + return USA_DIR; - case DiscIO::IVolume::COUNTRY_TAIWAN: - case DiscIO::IVolume::COUNTRY_KOREA: - // TODO: Should these have their own Region Dir? - case DiscIO::IVolume::COUNTRY_JAPAN: - return JAP_DIR; + case DiscIO::IVolume::COUNTRY_TAIWAN: + case DiscIO::IVolume::COUNTRY_KOREA: + // TODO: Should these have their own Region Dir? + case DiscIO::IVolume::COUNTRY_JAPAN: + return JAP_DIR; - case DiscIO::IVolume::COUNTRY_AUSTRALIA: - case DiscIO::IVolume::COUNTRY_EUROPE: - case DiscIO::IVolume::COUNTRY_FRANCE: - case DiscIO::IVolume::COUNTRY_GERMANY: - case DiscIO::IVolume::COUNTRY_ITALY: - case DiscIO::IVolume::COUNTRY_NETHERLANDS: - case DiscIO::IVolume::COUNTRY_RUSSIA: - case DiscIO::IVolume::COUNTRY_SPAIN: - case DiscIO::IVolume::COUNTRY_WORLD: - return EUR_DIR; + case DiscIO::IVolume::COUNTRY_AUSTRALIA: + case DiscIO::IVolume::COUNTRY_EUROPE: + case DiscIO::IVolume::COUNTRY_FRANCE: + case DiscIO::IVolume::COUNTRY_GERMANY: + case DiscIO::IVolume::COUNTRY_ITALY: + case DiscIO::IVolume::COUNTRY_NETHERLANDS: + case DiscIO::IVolume::COUNTRY_RUSSIA: + case DiscIO::IVolume::COUNTRY_SPAIN: + case DiscIO::IVolume::COUNTRY_WORLD: + return EUR_DIR; - case DiscIO::IVolume::COUNTRY_UNKNOWN: - default: - return nullptr; - } + case DiscIO::IVolume::COUNTRY_UNKNOWN: + default: + return nullptr; + } } bool SConfig::AutoSetup(EBootBS2 _BootBS2) { - std::string set_region_dir(EUR_DIR); + std::string set_region_dir(EUR_DIR); - switch (_BootBS2) - { - case BOOT_DEFAULT: - { - bool bootDrive = cdio_is_cdrom(m_strFilename); - // Check if the file exist, we may have gotten it from a --elf command line - // that gave an incorrect file name - if (!bootDrive && !File::Exists(m_strFilename)) - { - PanicAlertT("The specified file \"%s\" does not exist", m_strFilename.c_str()); - return false; - } + switch (_BootBS2) + { + case BOOT_DEFAULT: + { + bool bootDrive = cdio_is_cdrom(m_strFilename); + // Check if the file exist, we may have gotten it from a --elf command line + // that gave an incorrect file name + if (!bootDrive && !File::Exists(m_strFilename)) + { + PanicAlertT("The specified file \"%s\" does not exist", m_strFilename.c_str()); + return false; + } - std::string Extension; - SplitPath(m_strFilename, nullptr, nullptr, &Extension); - if (!strcasecmp(Extension.c_str(), ".gcm") || - !strcasecmp(Extension.c_str(), ".iso") || - !strcasecmp(Extension.c_str(), ".wbfs") || - !strcasecmp(Extension.c_str(), ".ciso") || - !strcasecmp(Extension.c_str(), ".gcz") || - bootDrive) - { - m_BootType = BOOT_ISO; - std::unique_ptr pVolume(DiscIO::CreateVolumeFromFilename(m_strFilename)); - if (pVolume == nullptr) - { - if (bootDrive) - PanicAlertT("Could not read \"%s\". " - "There is no disc in the drive, or it is not a GC/Wii backup. " - "Please note that original GameCube and Wii discs cannot be read " - "by most PC DVD drives.", m_strFilename.c_str()); - else - PanicAlertT("\"%s\" is an invalid GCM/ISO file, or is not a GC/Wii ISO.", - m_strFilename.c_str()); - return false; - } - m_strName = pVolume->GetInternalName(); - m_strUniqueID = pVolume->GetUniqueID(); - m_revision = pVolume->GetRevision(); + std::string Extension; + SplitPath(m_strFilename, nullptr, nullptr, &Extension); + if (!strcasecmp(Extension.c_str(), ".gcm") || !strcasecmp(Extension.c_str(), ".iso") || + !strcasecmp(Extension.c_str(), ".wbfs") || !strcasecmp(Extension.c_str(), ".ciso") || + !strcasecmp(Extension.c_str(), ".gcz") || bootDrive) + { + m_BootType = BOOT_ISO; + std::unique_ptr pVolume(DiscIO::CreateVolumeFromFilename(m_strFilename)); + if (pVolume == nullptr) + { + if (bootDrive) + PanicAlertT("Could not read \"%s\". " + "There is no disc in the drive, or it is not a GC/Wii backup. " + "Please note that original GameCube and Wii discs cannot be read " + "by most PC DVD drives.", + m_strFilename.c_str()); + else + PanicAlertT("\"%s\" is an invalid GCM/ISO file, or is not a GC/Wii ISO.", + m_strFilename.c_str()); + return false; + } + m_strName = pVolume->GetInternalName(); + m_strUniqueID = pVolume->GetUniqueID(); + m_revision = pVolume->GetRevision(); - // Check if we have a Wii disc - bWii = pVolume->GetVolumeType() == DiscIO::IVolume::WII_DISC; + // Check if we have a Wii disc + bWii = pVolume->GetVolumeType() == DiscIO::IVolume::WII_DISC; - const char* retrieved_region_dir = GetRegionOfCountry(pVolume->GetCountry()); - if (!retrieved_region_dir) - { - if (!PanicYesNoT("Your GCM/ISO file seems to be invalid (invalid country)." - "\nContinue with PAL region?")) - return false; - retrieved_region_dir = EUR_DIR; - } + const char* retrieved_region_dir = GetRegionOfCountry(pVolume->GetCountry()); + if (!retrieved_region_dir) + { + if (!PanicYesNoT("Your GCM/ISO file seems to be invalid (invalid country)." + "\nContinue with PAL region?")) + return false; + retrieved_region_dir = EUR_DIR; + } - set_region_dir = retrieved_region_dir; - bNTSC = set_region_dir == USA_DIR || set_region_dir == JAP_DIR; - } - else if (!strcasecmp(Extension.c_str(), ".elf")) - { - bWii = CBoot::IsElfWii(m_strFilename); - // TODO: Right now GC homebrew boots in NTSC and Wii homebrew in PAL. - // This is intentional so that Wii homebrew can boot in both 50Hz and 60Hz, without forcing all GC homebrew to 50Hz. - // In the future, it probably makes sense to add a Region setting for homebrew somewhere in the emulator config. - bNTSC = bWii ? false : true; - set_region_dir = bNTSC ? USA_DIR : EUR_DIR; - m_BootType = BOOT_ELF; - } - else if (!strcasecmp(Extension.c_str(), ".dol")) - { - CDolLoader dolfile(m_strFilename); - bWii = dolfile.IsWii(); - // TODO: See the ELF code above. - bNTSC = bWii ? false : true; - set_region_dir = bNTSC ? USA_DIR : EUR_DIR; - m_BootType = BOOT_DOL; - } - else if (!strcasecmp(Extension.c_str(), ".dff")) - { - bWii = true; - set_region_dir = USA_DIR; - bNTSC = true; - m_BootType = BOOT_DFF; + set_region_dir = retrieved_region_dir; + bNTSC = set_region_dir == USA_DIR || set_region_dir == JAP_DIR; + } + else if (!strcasecmp(Extension.c_str(), ".elf")) + { + bWii = CBoot::IsElfWii(m_strFilename); + // TODO: Right now GC homebrew boots in NTSC and Wii homebrew in PAL. + // This is intentional so that Wii homebrew can boot in both 50Hz and 60Hz, without forcing + // all GC homebrew to 50Hz. + // In the future, it probably makes sense to add a Region setting for homebrew somewhere in + // the emulator config. + bNTSC = bWii ? false : true; + set_region_dir = bNTSC ? USA_DIR : EUR_DIR; + m_BootType = BOOT_ELF; + } + else if (!strcasecmp(Extension.c_str(), ".dol")) + { + CDolLoader dolfile(m_strFilename); + bWii = dolfile.IsWii(); + // TODO: See the ELF code above. + bNTSC = bWii ? false : true; + set_region_dir = bNTSC ? USA_DIR : EUR_DIR; + m_BootType = BOOT_DOL; + } + else if (!strcasecmp(Extension.c_str(), ".dff")) + { + bWii = true; + set_region_dir = USA_DIR; + bNTSC = true; + m_BootType = BOOT_DFF; - std::unique_ptr ddfFile(FifoDataFile::Load(m_strFilename, true)); + std::unique_ptr ddfFile(FifoDataFile::Load(m_strFilename, true)); - if (ddfFile) - { - bWii = ddfFile->GetIsWii(); - } - } - else if (DiscIO::CNANDContentManager::Access().GetNANDLoader(m_strFilename).IsValid()) - { - std::unique_ptr pVolume(DiscIO::CreateVolumeFromFilename(m_strFilename)); - const DiscIO::CNANDContentLoader& ContentLoader = DiscIO::CNANDContentManager::Access().GetNANDLoader(m_strFilename); + if (ddfFile) + { + bWii = ddfFile->GetIsWii(); + } + } + else if (DiscIO::CNANDContentManager::Access().GetNANDLoader(m_strFilename).IsValid()) + { + std::unique_ptr pVolume(DiscIO::CreateVolumeFromFilename(m_strFilename)); + const DiscIO::CNANDContentLoader& ContentLoader = + DiscIO::CNANDContentManager::Access().GetNANDLoader(m_strFilename); - if (ContentLoader.GetContentByIndex(ContentLoader.GetBootIndex()) == nullptr) - { - //WAD is valid yet cannot be booted. Install instead. - u64 installed = DiscIO::CNANDContentManager::Access().Install_WiiWAD(m_strFilename); - if (installed) - SuccessAlertT("The WAD has been installed successfully"); - return false; //do not boot - } + if (ContentLoader.GetContentByIndex(ContentLoader.GetBootIndex()) == nullptr) + { + // WAD is valid yet cannot be booted. Install instead. + u64 installed = DiscIO::CNANDContentManager::Access().Install_WiiWAD(m_strFilename); + if (installed) + SuccessAlertT("The WAD has been installed successfully"); + return false; // do not boot + } - const char* retrieved_region_dir = GetRegionOfCountry(ContentLoader.GetCountry()); - set_region_dir = retrieved_region_dir ? retrieved_region_dir : EUR_DIR; - bNTSC = set_region_dir == USA_DIR || set_region_dir == JAP_DIR; + const char* retrieved_region_dir = GetRegionOfCountry(ContentLoader.GetCountry()); + set_region_dir = retrieved_region_dir ? retrieved_region_dir : EUR_DIR; + bNTSC = set_region_dir == USA_DIR || set_region_dir == JAP_DIR; - bWii = true; - m_BootType = BOOT_WII_NAND; + bWii = true; + m_BootType = BOOT_WII_NAND; - if (pVolume) - { - m_strName = pVolume->GetInternalName(); - m_strUniqueID = pVolume->GetUniqueID(); - } - else - { - // null pVolume means that we are loading from nand folder (Most Likely Wii Menu) - // if this is the second boot we would be using the Name and id of the last title - m_strName.clear(); - m_strUniqueID.clear(); - } + if (pVolume) + { + m_strName = pVolume->GetInternalName(); + m_strUniqueID = pVolume->GetUniqueID(); + } + else + { + // null pVolume means that we are loading from nand folder (Most Likely Wii Menu) + // if this is the second boot we would be using the Name and id of the last title + m_strName.clear(); + m_strUniqueID.clear(); + } - // Use the TitleIDhex for name and/or unique ID if launching from nand folder - // or if it is not ascii characters (specifically sysmenu could potentially apply to other things) - std::string titleidstr = StringFromFormat("%016" PRIx64, ContentLoader.GetTitleID()); + // Use the TitleIDhex for name and/or unique ID if launching from nand folder + // or if it is not ascii characters (specifically sysmenu could potentially apply to other + // things) + std::string titleidstr = StringFromFormat("%016" PRIx64, ContentLoader.GetTitleID()); - if (m_strName.empty()) - { - m_strName = titleidstr; - } - if (m_strUniqueID.empty()) - { - m_strUniqueID = titleidstr; - } - } - else - { - PanicAlertT("Could not recognize ISO file %s", m_strFilename.c_str()); - return false; - } - } - break; + if (m_strName.empty()) + { + m_strName = titleidstr; + } + if (m_strUniqueID.empty()) + { + m_strUniqueID = titleidstr; + } + } + else + { + PanicAlertT("Could not recognize ISO file %s", m_strFilename.c_str()); + return false; + } + } + break; - case BOOT_BS2_USA: - set_region_dir = USA_DIR; - m_strFilename.clear(); - bNTSC = true; - break; + case BOOT_BS2_USA: + set_region_dir = USA_DIR; + m_strFilename.clear(); + bNTSC = true; + break; - case BOOT_BS2_JAP: - set_region_dir = JAP_DIR; - m_strFilename.clear(); - bNTSC = true; - break; + case BOOT_BS2_JAP: + set_region_dir = JAP_DIR; + m_strFilename.clear(); + bNTSC = true; + break; - case BOOT_BS2_EUR: - set_region_dir = EUR_DIR; - m_strFilename.clear(); - bNTSC = false; - break; - } + case BOOT_BS2_EUR: + set_region_dir = EUR_DIR; + m_strFilename.clear(); + bNTSC = false; + break; + } - // Setup paths - CheckMemcardPath(SConfig::GetInstance().m_strMemoryCardA, set_region_dir, true); - CheckMemcardPath(SConfig::GetInstance().m_strMemoryCardB, set_region_dir, false); - m_strSRAM = File::GetUserPath(F_GCSRAM_IDX); - if (!bWii) - { - if (!bHLE_BS2) - { - m_strBootROM = File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + set_region_dir + DIR_SEP GC_IPL; - if (!File::Exists(m_strBootROM)) - m_strBootROM = File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + set_region_dir + DIR_SEP GC_IPL; + // Setup paths + CheckMemcardPath(SConfig::GetInstance().m_strMemoryCardA, set_region_dir, true); + CheckMemcardPath(SConfig::GetInstance().m_strMemoryCardB, set_region_dir, false); + m_strSRAM = File::GetUserPath(F_GCSRAM_IDX); + if (!bWii) + { + if (!bHLE_BS2) + { + m_strBootROM = File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + set_region_dir + DIR_SEP GC_IPL; + if (!File::Exists(m_strBootROM)) + m_strBootROM = + File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + set_region_dir + DIR_SEP GC_IPL; - if (!File::Exists(m_strBootROM)) - { - WARN_LOG(BOOT, "Bootrom file %s not found - using HLE.", m_strBootROM.c_str()); - bHLE_BS2 = true; - } - } - } - else if (bWii && !bHLE_BS2) - { - WARN_LOG(BOOT, "GC bootrom file will not be loaded for Wii mode."); - bHLE_BS2 = true; - } + if (!File::Exists(m_strBootROM)) + { + WARN_LOG(BOOT, "Bootrom file %s not found - using HLE.", m_strBootROM.c_str()); + bHLE_BS2 = true; + } + } + } + else if (bWii && !bHLE_BS2) + { + WARN_LOG(BOOT, "GC bootrom file will not be loaded for Wii mode."); + bHLE_BS2 = true; + } - return true; + return true; } -void SConfig::CheckMemcardPath(std::string& memcardPath, const std::string& gameRegion, bool isSlotA) +void SConfig::CheckMemcardPath(std::string& memcardPath, const std::string& gameRegion, + bool isSlotA) { - std::string ext("." + gameRegion + ".raw"); - if (memcardPath.empty()) - { - // Use default memcard path if there is no user defined name - std::string defaultFilename = isSlotA ? GC_MEMCARDA : GC_MEMCARDB; - memcardPath = File::GetUserPath(D_GCUSER_IDX) + defaultFilename + ext; - } - else - { - std::string filename = memcardPath; - std::string region = filename.substr(filename.size()-7, 3); - bool hasregion = false; - hasregion |= region.compare(USA_DIR) == 0; - hasregion |= region.compare(JAP_DIR) == 0; - hasregion |= region.compare(EUR_DIR) == 0; - if (!hasregion) - { - // filename doesn't have region in the extension - if (File::Exists(filename)) - { - // If the old file exists we are polite and ask if we should copy it - std::string oldFilename = filename; - filename.replace(filename.size()-4, 4, ext); - if (PanicYesNoT("Memory Card filename in Slot %c is incorrect\n" - "Region not specified\n\n" - "Slot %c path was changed to\n" - "%s\n" - "Would you like to copy the old file to this new location?\n", - isSlotA ? 'A':'B', isSlotA ? 'A':'B', filename.c_str())) - { - if (!File::Copy(oldFilename, filename)) - PanicAlertT("Copy failed"); - } - } - memcardPath = filename; // Always correct the path! - } - else if (region.compare(gameRegion) != 0) - { - // filename has region, but it's not == gameRegion - // Just set the correct filename, the EXI Device will create it if it doesn't exist - memcardPath = filename.replace(filename.size()-ext.size(), ext.size(), ext); - } - } + std::string ext("." + gameRegion + ".raw"); + if (memcardPath.empty()) + { + // Use default memcard path if there is no user defined name + std::string defaultFilename = isSlotA ? GC_MEMCARDA : GC_MEMCARDB; + memcardPath = File::GetUserPath(D_GCUSER_IDX) + defaultFilename + ext; + } + else + { + std::string filename = memcardPath; + std::string region = filename.substr(filename.size() - 7, 3); + bool hasregion = false; + hasregion |= region.compare(USA_DIR) == 0; + hasregion |= region.compare(JAP_DIR) == 0; + hasregion |= region.compare(EUR_DIR) == 0; + if (!hasregion) + { + // filename doesn't have region in the extension + if (File::Exists(filename)) + { + // If the old file exists we are polite and ask if we should copy it + std::string oldFilename = filename; + filename.replace(filename.size() - 4, 4, ext); + if (PanicYesNoT("Memory Card filename in Slot %c is incorrect\n" + "Region not specified\n\n" + "Slot %c path was changed to\n" + "%s\n" + "Would you like to copy the old file to this new location?\n", + isSlotA ? 'A' : 'B', isSlotA ? 'A' : 'B', filename.c_str())) + { + if (!File::Copy(oldFilename, filename)) + PanicAlertT("Copy failed"); + } + } + memcardPath = filename; // Always correct the path! + } + else if (region.compare(gameRegion) != 0) + { + // filename has region, but it's not == gameRegion + // Just set the correct filename, the EXI Device will create it if it doesn't exist + memcardPath = filename.replace(filename.size() - ext.size(), ext.size(), ext); + } + } } DiscIO::IVolume::ELanguage SConfig::GetCurrentLanguage(bool wii) const { - DiscIO::IVolume::ELanguage language; - if (wii) - language = (DiscIO::IVolume::ELanguage)SConfig::GetInstance().m_SYSCONF->GetData("IPL.LNG"); - else - language = (DiscIO::IVolume::ELanguage)(SConfig::GetInstance().SelectedLanguage + 1); + DiscIO::IVolume::ELanguage language; + if (wii) + language = (DiscIO::IVolume::ELanguage)SConfig::GetInstance().m_SYSCONF->GetData("IPL.LNG"); + else + language = (DiscIO::IVolume::ELanguage)(SConfig::GetInstance().SelectedLanguage + 1); - // Get rid of invalid values (probably doesn't matter, but might as well do it) - if (language > DiscIO::IVolume::ELanguage::LANGUAGE_UNKNOWN || language < 0) - language = DiscIO::IVolume::ELanguage::LANGUAGE_UNKNOWN; - return language; + // Get rid of invalid values (probably doesn't matter, but might as well do it) + if (language > DiscIO::IVolume::ELanguage::LANGUAGE_UNKNOWN || language < 0) + language = DiscIO::IVolume::ELanguage::LANGUAGE_UNKNOWN; + return language; } IniFile SConfig::LoadDefaultGameIni() const { - return LoadDefaultGameIni(GetUniqueID(), m_revision); + return LoadDefaultGameIni(GetUniqueID(), m_revision); } IniFile SConfig::LoadLocalGameIni() const { - return LoadLocalGameIni(GetUniqueID(), m_revision); + return LoadLocalGameIni(GetUniqueID(), m_revision); } IniFile SConfig::LoadGameIni() const { - return LoadGameIni(GetUniqueID(), m_revision); + return LoadGameIni(GetUniqueID(), m_revision); } IniFile SConfig::LoadDefaultGameIni(const std::string& id, u16 revision) { - IniFile game_ini; - for (const std::string& filename : GetGameIniFilenames(id, revision)) - game_ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true); - return game_ini; + IniFile game_ini; + for (const std::string& filename : GetGameIniFilenames(id, revision)) + game_ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true); + return game_ini; } IniFile SConfig::LoadLocalGameIni(const std::string& id, u16 revision) { - IniFile game_ini; - for (const std::string& filename : GetGameIniFilenames(id, revision)) - game_ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true); - return game_ini; + IniFile game_ini; + for (const std::string& filename : GetGameIniFilenames(id, revision)) + game_ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true); + return game_ini; } IniFile SConfig::LoadGameIni(const std::string& id, u16 revision) { - IniFile game_ini; - for (const std::string& filename : GetGameIniFilenames(id, revision)) - game_ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true); - for (const std::string& filename : GetGameIniFilenames(id, revision)) - game_ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true); - return game_ini; + IniFile game_ini; + for (const std::string& filename : GetGameIniFilenames(id, revision)) + game_ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true); + for (const std::string& filename : GetGameIniFilenames(id, revision)) + game_ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true); + return game_ini; } // Returns all possible filenames in ascending order of priority std::vector SConfig::GetGameIniFilenames(const std::string& id, u16 revision) { - std::vector filenames; + std::vector filenames; - if (id.empty()) - return filenames; + if (id.empty()) + return filenames; - // INIs that match the system code (unique for each Virtual Console system) - filenames.push_back(id.substr(0, 1) + ".ini"); + // INIs that match the system code (unique for each Virtual Console system) + filenames.push_back(id.substr(0, 1) + ".ini"); - // INIs that match all regions - if (id.size() >= 4) - filenames.push_back(id.substr(0, 3) + ".ini"); + // INIs that match all regions + if (id.size() >= 4) + filenames.push_back(id.substr(0, 3) + ".ini"); - // Regular INIs - filenames.push_back(id + ".ini"); + // Regular INIs + filenames.push_back(id + ".ini"); - // INIs with specific revisions - filenames.push_back(id + StringFromFormat("r%d", revision) + ".ini"); + // INIs with specific revisions + filenames.push_back(id + StringFromFormat("r%d", revision) + ".ini"); - return filenames; + return filenames; } diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index a2cc3c507d..94dd2a388c 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -15,302 +15,301 @@ #include "DiscIO/Volume.h" // DSP Backend Types -#define BACKEND_NULLSOUND _trans("No audio output") -#define BACKEND_ALSA "ALSA" -#define BACKEND_AOSOUND "AOSound" -#define BACKEND_COREAUDIO "CoreAudio" -#define BACKEND_OPENAL "OpenAL" -#define BACKEND_PULSEAUDIO "Pulse" -#define BACKEND_XAUDIO2 "XAudio2" -#define BACKEND_OPENSLES "OpenSLES" +#define BACKEND_NULLSOUND _trans("No audio output") +#define BACKEND_ALSA "ALSA" +#define BACKEND_AOSOUND "AOSound" +#define BACKEND_COREAUDIO "CoreAudio" +#define BACKEND_OPENAL "OpenAL" +#define BACKEND_PULSEAUDIO "Pulse" +#define BACKEND_XAUDIO2 "XAudio2" +#define BACKEND_OPENSLES "OpenSLES" enum GPUDeterminismMode { - GPU_DETERMINISM_AUTO, - GPU_DETERMINISM_NONE, - // This is currently the only mode. There will probably be at least - // one more at some point. - GPU_DETERMINISM_FAKE_COMPLETION, + GPU_DETERMINISM_AUTO, + GPU_DETERMINISM_NONE, + // This is currently the only mode. There will probably be at least + // one more at some point. + GPU_DETERMINISM_FAKE_COMPLETION, }; struct SConfig : NonCopyable { - // Wii Devices - bool m_WiiSDCard; - bool m_WiiKeyboard; - bool m_WiimoteContinuousScanning; - bool m_WiimoteEnableSpeaker; + // Wii Devices + bool m_WiiSDCard; + bool m_WiiKeyboard; + bool m_WiimoteContinuousScanning; + bool m_WiimoteEnableSpeaker; - // name of the last used filename - std::string m_LastFilename; + // name of the last used filename + std::string m_LastFilename; - // ISO folder - std::vector m_ISOFolder; - bool m_RecursiveISOFolder; + // ISO folder + std::vector m_ISOFolder; + bool m_RecursiveISOFolder; - // Settings - bool bEnableDebugging; - #ifdef USE_GDBSTUB - int iGDBPort; - #ifndef _WIN32 - std::string gdb_socket; - #endif - #endif - bool bAutomaticStart; - bool bBootToPause; + // Settings + bool bEnableDebugging; +#ifdef USE_GDBSTUB + int iGDBPort; +#ifndef _WIN32 + std::string gdb_socket; +#endif +#endif + bool bAutomaticStart; + bool bBootToPause; - int iCPUCore; + int iCPUCore; - // JIT (shared between JIT and JITIL) - bool bJITNoBlockCache, bJITNoBlockLinking; - bool bJITOff; - bool bJITLoadStoreOff, bJITLoadStorelXzOff, bJITLoadStorelwzOff, bJITLoadStorelbzxOff; - bool bJITLoadStoreFloatingOff; - bool bJITLoadStorePairedOff; - bool bJITFloatingPointOff; - bool bJITIntegerOff; - bool bJITPairedOff; - bool bJITSystemRegistersOff; - bool bJITBranchOff; - bool bJITILTimeProfiling; - bool bJITILOutputIR; + // JIT (shared between JIT and JITIL) + bool bJITNoBlockCache, bJITNoBlockLinking; + bool bJITOff; + bool bJITLoadStoreOff, bJITLoadStorelXzOff, bJITLoadStorelwzOff, bJITLoadStorelbzxOff; + bool bJITLoadStoreFloatingOff; + bool bJITLoadStorePairedOff; + bool bJITFloatingPointOff; + bool bJITIntegerOff; + bool bJITPairedOff; + bool bJITSystemRegistersOff; + bool bJITBranchOff; + bool bJITILTimeProfiling; + bool bJITILOutputIR; - bool bFastmem; - bool bFPRF; - bool bAccurateNaNs; + bool bFastmem; + bool bFPRF; + bool bAccurateNaNs; - int iTimingVariance; // in milli secounds - bool bCPUThread; - bool bDSPThread; - bool bDSPHLE; - bool bSkipIdle; - bool bSyncGPUOnSkipIdleHack; - bool bNTSC; - bool bForceNTSCJ; - bool bHLE_BS2; - bool bEnableCheats; - bool bEnableMemcardSdWriting; + int iTimingVariance; // in milli secounds + bool bCPUThread; + bool bDSPThread; + bool bDSPHLE; + bool bSkipIdle; + bool bSyncGPUOnSkipIdleHack; + bool bNTSC; + bool bForceNTSCJ; + bool bHLE_BS2; + bool bEnableCheats; + bool bEnableMemcardSdWriting; - bool bDPL2Decoder; - int iLatency; + bool bDPL2Decoder; + int iLatency; - bool bRunCompareServer; - bool bRunCompareClient; + bool bRunCompareServer; + bool bRunCompareClient; - bool bMMU; - bool bDCBZOFF; - int iBBDumpPort; - bool bFastDiscSpeed; + bool bMMU; + bool bDCBZOFF; + int iBBDumpPort; + bool bFastDiscSpeed; - bool bSyncGPU; - int iSyncGpuMaxDistance; - int iSyncGpuMinDistance; - float fSyncGpuOverclock; + bool bSyncGPU; + int iSyncGpuMaxDistance; + int iSyncGpuMinDistance; + float fSyncGpuOverclock; - int SelectedLanguage; - bool bOverrideGCLanguage; + int SelectedLanguage; + bool bOverrideGCLanguage; - bool bWii; + bool bWii; - // Interface settings - bool bConfirmStop, bHideCursor, bAutoHideCursor, bUsePanicHandlers, bOnScreenDisplayMessages; - std::string theme_name; + // Interface settings + bool bConfirmStop, bHideCursor, bAutoHideCursor, bUsePanicHandlers, bOnScreenDisplayMessages; + std::string theme_name; - // Display settings - std::string strFullscreenResolution; - int iRenderWindowXPos, iRenderWindowYPos; - int iRenderWindowWidth, iRenderWindowHeight; - bool bRenderWindowAutoSize, bKeepWindowOnTop; - bool bFullscreen, bRenderToMain; - bool bProgressive, bPAL60; - bool bDisableScreenSaver; + // Display settings + std::string strFullscreenResolution; + int iRenderWindowXPos, iRenderWindowYPos; + int iRenderWindowWidth, iRenderWindowHeight; + bool bRenderWindowAutoSize, bKeepWindowOnTop; + bool bFullscreen, bRenderToMain; + bool bProgressive, bPAL60; + bool bDisableScreenSaver; - int iPosX, iPosY, iWidth, iHeight; + int iPosX, iPosY, iWidth, iHeight; - // Analytics settings. - std::string m_analytics_id; - bool m_analytics_enabled; - bool m_analytics_permission_asked; + // Analytics settings. + std::string m_analytics_id; + bool m_analytics_enabled; + bool m_analytics_permission_asked; - // Fifo Player related settings - bool bLoopFifoReplay; + // Fifo Player related settings + bool bLoopFifoReplay; - enum EBootBS2 - { - BOOT_DEFAULT, - BOOT_BS2_JAP, - BOOT_BS2_USA, - BOOT_BS2_EUR, - }; + enum EBootBS2 + { + BOOT_DEFAULT, + BOOT_BS2_JAP, + BOOT_BS2_USA, + BOOT_BS2_EUR, + }; - enum EBootType - { - BOOT_ISO, - BOOT_ELF, - BOOT_DOL, - BOOT_WII_NAND, - BOOT_BS2, - BOOT_DFF - }; - EBootType m_BootType; + enum EBootType + { + BOOT_ISO, + BOOT_ELF, + BOOT_DOL, + BOOT_WII_NAND, + BOOT_BS2, + BOOT_DFF + }; + EBootType m_BootType; - std::string m_strVideoBackend; - std::string m_strGPUDeterminismMode; + std::string m_strVideoBackend; + std::string m_strGPUDeterminismMode; - // set based on the string version - GPUDeterminismMode m_GPUDeterminismMode; + // set based on the string version + GPUDeterminismMode m_GPUDeterminismMode; - // files - std::string m_strFilename; - std::string m_strBootROM; - std::string m_strSRAM; - std::string m_strDefaultISO; - std::string m_strDVDRoot; - std::string m_strApploader; - std::string m_strUniqueID; - std::string m_strName; - u16 m_revision; + // files + std::string m_strFilename; + std::string m_strBootROM; + std::string m_strSRAM; + std::string m_strDefaultISO; + std::string m_strDVDRoot; + std::string m_strApploader; + std::string m_strUniqueID; + std::string m_strName; + u16 m_revision; - std::string m_perfDir; + std::string m_perfDir; - void LoadDefaults(); - bool AutoSetup(EBootBS2 _BootBS2); - const std::string &GetUniqueID() const { return m_strUniqueID; } - void CheckMemcardPath(std::string& memcardPath, const std::string& gameRegion, bool isSlotA); - DiscIO::IVolume::ELanguage GetCurrentLanguage(bool wii) const; + void LoadDefaults(); + bool AutoSetup(EBootBS2 _BootBS2); + const std::string& GetUniqueID() const { return m_strUniqueID; } + void CheckMemcardPath(std::string& memcardPath, const std::string& gameRegion, bool isSlotA); + DiscIO::IVolume::ELanguage GetCurrentLanguage(bool wii) const; - IniFile LoadDefaultGameIni() const; - IniFile LoadLocalGameIni() const; - IniFile LoadGameIni() const; + IniFile LoadDefaultGameIni() const; + IniFile LoadLocalGameIni() const; + IniFile LoadGameIni() const; - static IniFile LoadDefaultGameIni(const std::string& id, u16 revision); - static IniFile LoadLocalGameIni(const std::string& id, u16 revision); - static IniFile LoadGameIni(const std::string& id, u16 revision); + static IniFile LoadDefaultGameIni(const std::string& id, u16 revision); + static IniFile LoadLocalGameIni(const std::string& id, u16 revision); + static IniFile LoadGameIni(const std::string& id, u16 revision); - static std::vector GetGameIniFilenames(const std::string& id, u16 revision); + static std::vector GetGameIniFilenames(const std::string& id, u16 revision); - std::string m_NANDPath; + std::string m_NANDPath; - std::string m_strMemoryCardA; - std::string m_strMemoryCardB; - std::string m_strGbaCartA; - std::string m_strGbaCartB; - TEXIDevices m_EXIDevice[3]; - SIDevices m_SIDevice[4]; - std::string m_bba_mac; + std::string m_strMemoryCardA; + std::string m_strMemoryCardB; + std::string m_strGbaCartA; + std::string m_strGbaCartB; + TEXIDevices m_EXIDevice[3]; + SIDevices m_SIDevice[4]; + std::string m_bba_mac; - // interface language - int m_InterfaceLanguage; - float m_EmulationSpeed; - bool m_OCEnable; - float m_OCFactor; - // other interface settings - bool m_InterfaceToolbar; - bool m_InterfaceStatusbar; - bool m_InterfaceLogWindow; - bool m_InterfaceLogConfigWindow; - bool m_InterfaceExtendedFPSInfo; + // interface language + int m_InterfaceLanguage; + float m_EmulationSpeed; + bool m_OCEnable; + float m_OCFactor; + // other interface settings + bool m_InterfaceToolbar; + bool m_InterfaceStatusbar; + bool m_InterfaceLogWindow; + bool m_InterfaceLogConfigWindow; + bool m_InterfaceExtendedFPSInfo; - bool m_ListDrives; - bool m_ListWad; - bool m_ListElfDol; - bool m_ListWii; - bool m_ListGC; - bool m_ListPal; - bool m_ListUsa; - bool m_ListJap; - bool m_ListAustralia; - bool m_ListFrance; - bool m_ListGermany; - bool m_ListItaly; - bool m_ListKorea; - bool m_ListNetherlands; - bool m_ListRussia; - bool m_ListSpain; - bool m_ListTaiwan; - bool m_ListWorld; - bool m_ListUnknown; - int m_ListSort; - int m_ListSort2; + bool m_ListDrives; + bool m_ListWad; + bool m_ListElfDol; + bool m_ListWii; + bool m_ListGC; + bool m_ListPal; + bool m_ListUsa; + bool m_ListJap; + bool m_ListAustralia; + bool m_ListFrance; + bool m_ListGermany; + bool m_ListItaly; + bool m_ListKorea; + bool m_ListNetherlands; + bool m_ListRussia; + bool m_ListSpain; + bool m_ListTaiwan; + bool m_ListWorld; + bool m_ListUnknown; + int m_ListSort; + int m_ListSort2; - // Game list column toggles - bool m_showSystemColumn; - bool m_showBannerColumn; - bool m_showMakerColumn; - bool m_showFileNameColumn; - bool m_showIDColumn; - bool m_showRegionColumn; - bool m_showSizeColumn; - bool m_showStateColumn; + // Game list column toggles + bool m_showSystemColumn; + bool m_showBannerColumn; + bool m_showMakerColumn; + bool m_showFileNameColumn; + bool m_showIDColumn; + bool m_showRegionColumn; + bool m_showSizeColumn; + bool m_showStateColumn; - // Toggles whether compressed titles show up in blue in the game list - bool m_ColorCompressed; + // Toggles whether compressed titles show up in blue in the game list + bool m_ColorCompressed; - std::string m_WirelessMac; - bool m_PauseMovie; - bool m_ShowLag; - bool m_ShowFrameCount; - std::string m_strMovieAuthor; - unsigned int m_FrameSkip; - bool m_DumpFrames; - bool m_DumpFramesSilent; - bool m_ShowInputDisplay; + std::string m_WirelessMac; + bool m_PauseMovie; + bool m_ShowLag; + bool m_ShowFrameCount; + std::string m_strMovieAuthor; + unsigned int m_FrameSkip; + bool m_DumpFrames; + bool m_DumpFramesSilent; + bool m_ShowInputDisplay; - bool m_PauseOnFocusLost; + bool m_PauseOnFocusLost; - // DSP settings - bool m_DSPEnableJIT; - bool m_DSPCaptureLog; - bool m_DumpAudio; - bool m_IsMuted; - bool m_DumpUCode; - int m_Volume; - std::string sBackend; + // DSP settings + bool m_DSPEnableJIT; + bool m_DSPCaptureLog; + bool m_DumpAudio; + bool m_IsMuted; + bool m_DumpUCode; + int m_Volume; + std::string sBackend; - // Input settings - bool m_BackgroundInput; - bool m_AdapterRumble[4]; - bool m_AdapterKonga[4]; + // Input settings + bool m_BackgroundInput; + bool m_AdapterRumble[4]; + bool m_AdapterKonga[4]; - SysConf* m_SYSCONF; + SysConf* m_SYSCONF; - // Save settings - void SaveSettings(); + // Save settings + void SaveSettings(); - // Load settings - void LoadSettings(); + // Load settings + void LoadSettings(); - // Return the permanent and somewhat globally used instance of this struct - static SConfig& GetInstance() { return(*m_Instance); } - - static void Init(); - static void Shutdown(); + // Return the permanent and somewhat globally used instance of this struct + static SConfig& GetInstance() { return (*m_Instance); } + static void Init(); + static void Shutdown(); private: - SConfig(); - ~SConfig(); + SConfig(); + ~SConfig(); - void SaveGeneralSettings(IniFile& ini); - void SaveInterfaceSettings(IniFile& ini); - void SaveDisplaySettings(IniFile& ini); - void SaveGameListSettings(IniFile& ini); - void SaveCoreSettings(IniFile& ini); - void SaveDSPSettings(IniFile& ini); - void SaveInputSettings(IniFile& ini); - void SaveMovieSettings(IniFile& ini); - void SaveFifoPlayerSettings(IniFile& ini); - void SaveAnalyticsSettings(IniFile& ini); + void SaveGeneralSettings(IniFile& ini); + void SaveInterfaceSettings(IniFile& ini); + void SaveDisplaySettings(IniFile& ini); + void SaveGameListSettings(IniFile& ini); + void SaveCoreSettings(IniFile& ini); + void SaveDSPSettings(IniFile& ini); + void SaveInputSettings(IniFile& ini); + void SaveMovieSettings(IniFile& ini); + void SaveFifoPlayerSettings(IniFile& ini); + void SaveAnalyticsSettings(IniFile& ini); - void LoadGeneralSettings(IniFile& ini); - void LoadInterfaceSettings(IniFile& ini); - void LoadDisplaySettings(IniFile& ini); - void LoadGameListSettings(IniFile& ini); - void LoadCoreSettings(IniFile& ini); - void LoadDSPSettings(IniFile& ini); - void LoadInputSettings(IniFile& ini); - void LoadMovieSettings(IniFile& ini); - void LoadFifoPlayerSettings(IniFile& ini); - void LoadAnalyticsSettings(IniFile& ini); + void LoadGeneralSettings(IniFile& ini); + void LoadInterfaceSettings(IniFile& ini); + void LoadDisplaySettings(IniFile& ini); + void LoadGameListSettings(IniFile& ini); + void LoadCoreSettings(IniFile& ini); + void LoadDSPSettings(IniFile& ini); + void LoadInputSettings(IniFile& ini); + void LoadMovieSettings(IniFile& ini); + void LoadFifoPlayerSettings(IniFile& ini); + void LoadAnalyticsSettings(IniFile& ini); - static SConfig* m_Instance; + static SConfig* m_Instance; }; diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index ab108c77d2..f01b17beae 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -15,15 +15,15 @@ #include "AudioCommon/AudioCommon.h" +#include "Common/CPUDetect.h" #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" -#include "Common/CPUDetect.h" +#include "Common/Logging/LogManager.h" #include "Common/MathUtil.h" #include "Common/MemoryUtil.h" #include "Common/StringUtil.h" #include "Common/Thread.h" #include "Common/Timer.h" -#include "Common/Logging/LogManager.h" #include "Core/Analytics.h" #include "Core/ConfigManager.h" @@ -35,11 +35,6 @@ #ifdef USE_MEMORYWATCHER #include "Core/MemoryWatcher.h" #endif -#include "Core/Movie.h" -#include "Core/NetPlayClient.h" -#include "Core/NetPlayProto.h" -#include "Core/PatchEngine.h" -#include "Core/State.h" #include "Core/Boot/Boot.h" #include "Core/FifoPlayer/FifoPlayer.h" #include "Core/HW/AudioInterface.h" @@ -58,16 +53,21 @@ #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" #include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h" #include "Core/IPC_HLE/WII_Socket.h" +#include "Core/Movie.h" +#include "Core/NetPlayClient.h" +#include "Core/NetPlayProto.h" +#include "Core/PatchEngine.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/State.h" #ifdef USE_GDBSTUB #include "Core/PowerPC/GDBStub.h" #endif #include "DiscIO/FileMonitor.h" -#include "InputCommon/GCAdapter.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" +#include "InputCommon/GCAdapter.h" #include "VideoCommon/Fifo.h" #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/RenderBase.h" @@ -80,13 +80,12 @@ #elif defined __ANDROID__ || defined __APPLE__ // This will most likely have to stay, to support android #include -#else // Everything besides VS and Android +#else // Everything besides VS and Android #define ThreadLocalStorage __thread #endif namespace Core { - // TODO: ugly, remove bool g_aspect_wide; @@ -106,7 +105,7 @@ void EmuThread(); static bool s_is_stopping = false; static bool s_hardware_initialized = false; static bool s_is_started = false; -static std::atomic s_is_booting{ false }; +static std::atomic s_is_booting{false}; static void* s_window_handle = nullptr; static std::string s_state_filename; static std::thread s_emu_thread; @@ -119,10 +118,10 @@ static bool s_is_throttler_temp_disabled = false; struct HostJob { - std::function job; - bool run_after_stop; + std::function job; + bool run_after_stop; }; -static std::mutex s_host_jobs_lock; +static std::mutex s_host_jobs_lock; static std::queue s_host_jobs_queue; #ifdef ThreadLocalStorage @@ -132,27 +131,33 @@ static pthread_key_t s_tls_is_cpu_key; static pthread_once_t s_cpu_key_is_init = PTHREAD_ONCE_INIT; static void InitIsCPUKey() { - pthread_key_create(&s_tls_is_cpu_key, nullptr); + pthread_key_create(&s_tls_is_cpu_key, nullptr); } #endif bool GetIsThrottlerTempDisabled() { - return s_is_throttler_temp_disabled; + return s_is_throttler_temp_disabled; } void SetIsThrottlerTempDisabled(bool disable) { - s_is_throttler_temp_disabled = disable; + s_is_throttler_temp_disabled = disable; } -std::string GetStateFileName() { return s_state_filename; } -void SetStateFileName(const std::string& val) { s_state_filename = val; } +std::string GetStateFileName() +{ + return s_state_filename; +} +void SetStateFileName(const std::string& val) +{ + s_state_filename = val; +} void FrameUpdateOnCPUThread() { - if (NetPlay::IsNetPlayRunning()) - NetPlayClient::SendTimeBase(); + if (NetPlay::IsNetPlayRunning()) + NetPlayClient::SendTimeBase(); } // Display messages and return values @@ -160,310 +165,306 @@ void FrameUpdateOnCPUThread() // Formatted stop message std::string StopMessage(bool main_thread, const std::string& message) { - return StringFromFormat("Stop [%s %i]\t%s\t%s", - main_thread ? "Main Thread" : "Video Thread", Common::CurrentThreadId(), MemUsage().c_str(), message.c_str()); + return StringFromFormat("Stop [%s %i]\t%s\t%s", main_thread ? "Main Thread" : "Video Thread", + Common::CurrentThreadId(), MemUsage().c_str(), message.c_str()); } void DisplayMessage(const std::string& message, int time_in_ms) { - if (!IsRunning()) - return; + if (!IsRunning()) + return; - // Actually displaying non-ASCII could cause things to go pear-shaped - for (const char& c : message) - { - if (!std::isprint(c)) - return; - } + // Actually displaying non-ASCII could cause things to go pear-shaped + for (const char& c : message) + { + if (!std::isprint(c)) + return; + } - OSD::AddMessage(message, time_in_ms); - Host_UpdateTitle(message); + OSD::AddMessage(message, time_in_ms); + Host_UpdateTitle(message); } bool IsRunning() { - return (GetState() != CORE_UNINITIALIZED || s_hardware_initialized) && !s_is_stopping; + return (GetState() != CORE_UNINITIALIZED || s_hardware_initialized) && !s_is_stopping; } bool IsRunningAndStarted() { - return s_is_started && !s_is_stopping; + return s_is_started && !s_is_stopping; } bool IsRunningInCurrentThread() { - return IsRunning() && IsCPUThread(); + return IsRunning() && IsCPUThread(); } bool IsCPUThread() { #ifdef ThreadLocalStorage - return tls_is_cpu_thread; + return tls_is_cpu_thread; #else - // Use pthread implementation for Android and Mac - // Make sure that s_tls_is_cpu_key is initialized - pthread_once(&s_cpu_key_is_init, InitIsCPUKey); - return pthread_getspecific(s_tls_is_cpu_key); + // Use pthread implementation for Android and Mac + // Make sure that s_tls_is_cpu_key is initialized + pthread_once(&s_cpu_key_is_init, InitIsCPUKey); + return pthread_getspecific(s_tls_is_cpu_key); #endif } bool IsGPUThread() { - const SConfig& _CoreParameter = SConfig::GetInstance(); - if (_CoreParameter.bCPUThread) - { - return (s_emu_thread.joinable() && (s_emu_thread.get_id() == std::this_thread::get_id())); - } - else - { - return IsCPUThread(); - } + const SConfig& _CoreParameter = SConfig::GetInstance(); + if (_CoreParameter.bCPUThread) + { + return (s_emu_thread.joinable() && (s_emu_thread.get_id() == std::this_thread::get_id())); + } + else + { + return IsCPUThread(); + } } // This is called from the GUI thread. See the booting call schedule in // BootManager.cpp bool Init() { - const SConfig& _CoreParameter = SConfig::GetInstance(); + const SConfig& _CoreParameter = SConfig::GetInstance(); - if (s_emu_thread.joinable()) - { - if (IsRunning()) - { - PanicAlertT("Emu Thread already running"); - return false; - } + if (s_emu_thread.joinable()) + { + if (IsRunning()) + { + PanicAlertT("Emu Thread already running"); + return false; + } - // The Emu Thread was stopped, synchronize with it. - s_emu_thread.join(); - } + // The Emu Thread was stopped, synchronize with it. + s_emu_thread.join(); + } - // Drain any left over jobs - HostDispatchJobs(); + // Drain any left over jobs + HostDispatchJobs(); - Core::UpdateWantDeterminism(/*initial*/ true); + Core::UpdateWantDeterminism(/*initial*/ true); - INFO_LOG(OSREPORT, "Starting core = %s mode", - _CoreParameter.bWii ? "Wii" : "GameCube"); - INFO_LOG(OSREPORT, "CPU Thread separate = %s", - _CoreParameter.bCPUThread ? "Yes" : "No"); + INFO_LOG(OSREPORT, "Starting core = %s mode", _CoreParameter.bWii ? "Wii" : "GameCube"); + INFO_LOG(OSREPORT, "CPU Thread separate = %s", _CoreParameter.bCPUThread ? "Yes" : "No"); - Host_UpdateMainFrame(); // Disable any menus or buttons at boot + Host_UpdateMainFrame(); // Disable any menus or buttons at boot - g_aspect_wide = _CoreParameter.bWii; - if (g_aspect_wide) - { - IniFile gameIni = _CoreParameter.LoadGameIni(); - gameIni.GetOrCreateSection("Wii")->Get("Widescreen", &g_aspect_wide, - !!SConfig::GetInstance().m_SYSCONF->GetData("IPL.AR")); - } + g_aspect_wide = _CoreParameter.bWii; + if (g_aspect_wide) + { + IniFile gameIni = _CoreParameter.LoadGameIni(); + gameIni.GetOrCreateSection("Wii")->Get( + "Widescreen", &g_aspect_wide, !!SConfig::GetInstance().m_SYSCONF->GetData("IPL.AR")); + } - s_window_handle = Host_GetRenderHandle(); + s_window_handle = Host_GetRenderHandle(); - // Start the emu thread - s_emu_thread = std::thread(EmuThread); + // Start the emu thread + s_emu_thread = std::thread(EmuThread); - return true; + return true; } // Called from GUI thread void Stop() // - Hammertime! { - if (GetState() == CORE_STOPPING) - return; + if (GetState() == CORE_STOPPING) + return; - const SConfig& _CoreParameter = SConfig::GetInstance(); + const SConfig& _CoreParameter = SConfig::GetInstance(); - s_is_stopping = true; + s_is_stopping = true; - // Dump left over jobs - HostDispatchJobs(); + // Dump left over jobs + HostDispatchJobs(); - Fifo::EmulatorState(false); + Fifo::EmulatorState(false); - INFO_LOG(CONSOLE, "Stop [Main Thread]\t\t---- Shutting down ----"); + INFO_LOG(CONSOLE, "Stop [Main Thread]\t\t---- Shutting down ----"); - // Stop the CPU - INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stop CPU").c_str()); - CPU::Stop(); + // Stop the CPU + INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stop CPU").c_str()); + CPU::Stop(); - if (_CoreParameter.bCPUThread) - { - // Video_EnterLoop() should now exit so that EmuThread() - // will continue concurrently with the rest of the commands - // in this function. We no longer rely on Postmessage. - INFO_LOG(CONSOLE, "%s", StopMessage(true, "Wait for Video Loop to exit ...").c_str()); + if (_CoreParameter.bCPUThread) + { + // Video_EnterLoop() should now exit so that EmuThread() + // will continue concurrently with the rest of the commands + // in this function. We no longer rely on Postmessage. + INFO_LOG(CONSOLE, "%s", StopMessage(true, "Wait for Video Loop to exit ...").c_str()); - g_video_backend->Video_ExitLoop(); - } + g_video_backend->Video_ExitLoop(); + } #if defined(__LIBUSB__) || defined(_WIN32) - GCAdapter::ResetRumble(); + GCAdapter::ResetRumble(); #endif #ifdef USE_MEMORYWATCHER - MemoryWatcher::Shutdown(); + MemoryWatcher::Shutdown(); #endif } void DeclareAsCPUThread() { #ifdef ThreadLocalStorage - tls_is_cpu_thread = true; + tls_is_cpu_thread = true; #else - // Use pthread implementation for Android and Mac - // Make sure that s_tls_is_cpu_key is initialized - pthread_once(&s_cpu_key_is_init, InitIsCPUKey); - pthread_setspecific(s_tls_is_cpu_key, (void*)true); + // Use pthread implementation for Android and Mac + // Make sure that s_tls_is_cpu_key is initialized + pthread_once(&s_cpu_key_is_init, InitIsCPUKey); + pthread_setspecific(s_tls_is_cpu_key, (void*)true); #endif } void UndeclareAsCPUThread() { #ifdef ThreadLocalStorage - tls_is_cpu_thread = false; + tls_is_cpu_thread = false; #else - // Use pthread implementation for Android and Mac - // Make sure that s_tls_is_cpu_key is initialized - pthread_once(&s_cpu_key_is_init, InitIsCPUKey); - pthread_setspecific(s_tls_is_cpu_key, (void*)false); + // Use pthread implementation for Android and Mac + // Make sure that s_tls_is_cpu_key is initialized + pthread_once(&s_cpu_key_is_init, InitIsCPUKey); + pthread_setspecific(s_tls_is_cpu_key, (void*)false); #endif } // For the CPU Thread only. static void CPUSetInitialExecutionState() { - QueueHostJob([] - { - SetState(SConfig::GetInstance().bBootToPause ? CORE_PAUSE : CORE_RUN); - Host_UpdateMainFrame(); - }); + QueueHostJob([] { + SetState(SConfig::GetInstance().bBootToPause ? CORE_PAUSE : CORE_RUN); + Host_UpdateMainFrame(); + }); } // Create the CPU thread, which is a CPU + Video thread in Single Core mode. static void CpuThread() { - DeclareAsCPUThread(); + DeclareAsCPUThread(); - const SConfig& _CoreParameter = SConfig::GetInstance(); + const SConfig& _CoreParameter = SConfig::GetInstance(); - if (_CoreParameter.bCPUThread) - { - Common::SetCurrentThreadName("CPU thread"); - } - else - { - Common::SetCurrentThreadName("CPU-GPU thread"); - g_video_backend->Video_Prepare(); - } + if (_CoreParameter.bCPUThread) + { + Common::SetCurrentThreadName("CPU thread"); + } + else + { + Common::SetCurrentThreadName("CPU-GPU thread"); + g_video_backend->Video_Prepare(); + } // This needs to be delayed until after the video backend is ready. - DolphinAnalytics::Instance()->ReportGameStart(); + DolphinAnalytics::Instance()->ReportGameStart(); - if (_CoreParameter.bFastmem) - EMM::InstallExceptionHandler(); // Let's run under memory watch + if (_CoreParameter.bFastmem) + EMM::InstallExceptionHandler(); // Let's run under memory watch - if (!s_state_filename.empty()) - { - // Needs to PauseAndLock the Core - // NOTE: EmuThread should have left us in CPU_STEPPING so nothing will happen - // until after the job is serviced. - QueueHostJob([] - { - // Recheck in case Movie cleared it since. - if (!s_state_filename.empty()) - State::LoadAs(s_state_filename); - }); - } + if (!s_state_filename.empty()) + { + // Needs to PauseAndLock the Core + // NOTE: EmuThread should have left us in CPU_STEPPING so nothing will happen + // until after the job is serviced. + QueueHostJob([] { + // Recheck in case Movie cleared it since. + if (!s_state_filename.empty()) + State::LoadAs(s_state_filename); + }); + } - s_is_started = true; - CPUSetInitialExecutionState(); + s_is_started = true; + CPUSetInitialExecutionState(); - #ifdef USE_GDBSTUB - #ifndef _WIN32 - if (!_CoreParameter.gdb_socket.empty()) - { - gdb_init_local(_CoreParameter.gdb_socket.data()); - gdb_break(); - } - else - #endif - if (_CoreParameter.iGDBPort > 0) - { - gdb_init(_CoreParameter.iGDBPort); - // break at next instruction (the first instruction) - gdb_break(); - } - #endif - -#ifdef USE_MEMORYWATCHER - MemoryWatcher::Init(); +#ifdef USE_GDBSTUB +#ifndef _WIN32 + if (!_CoreParameter.gdb_socket.empty()) + { + gdb_init_local(_CoreParameter.gdb_socket.data()); + gdb_break(); + } + else +#endif + if (_CoreParameter.iGDBPort > 0) + { + gdb_init(_CoreParameter.iGDBPort); + // break at next instruction (the first instruction) + gdb_break(); + } #endif - // Enter CPU run loop. When we leave it - we are done. - CPU::Run(); +#ifdef USE_MEMORYWATCHER + MemoryWatcher::Init(); +#endif - s_is_started = false; + // Enter CPU run loop. When we leave it - we are done. + CPU::Run(); - if (!_CoreParameter.bCPUThread) - g_video_backend->Video_Cleanup(); + s_is_started = false; - if (_CoreParameter.bFastmem) - EMM::UninstallExceptionHandler(); + if (!_CoreParameter.bCPUThread) + g_video_backend->Video_Cleanup(); - return; + if (_CoreParameter.bFastmem) + EMM::UninstallExceptionHandler(); + + return; } static void FifoPlayerThread() { - DeclareAsCPUThread(); - const SConfig& _CoreParameter = SConfig::GetInstance(); + DeclareAsCPUThread(); + const SConfig& _CoreParameter = SConfig::GetInstance(); - if (_CoreParameter.bCPUThread) - { - Common::SetCurrentThreadName("FIFO player thread"); - } - else - { - g_video_backend->Video_Prepare(); - Common::SetCurrentThreadName("FIFO-GPU thread"); - } + if (_CoreParameter.bCPUThread) + { + Common::SetCurrentThreadName("FIFO player thread"); + } + else + { + g_video_backend->Video_Prepare(); + Common::SetCurrentThreadName("FIFO-GPU thread"); + } - // Enter CPU run loop. When we leave it - we are done. - if (FifoPlayer::GetInstance().Open(_CoreParameter.m_strFilename)) - { - if (auto cpu_core = FifoPlayer::GetInstance().GetCPUCore()) - { - PowerPC::InjectExternalCPUCore(cpu_core.get()); - s_is_started = true; + // Enter CPU run loop. When we leave it - we are done. + if (FifoPlayer::GetInstance().Open(_CoreParameter.m_strFilename)) + { + if (auto cpu_core = FifoPlayer::GetInstance().GetCPUCore()) + { + PowerPC::InjectExternalCPUCore(cpu_core.get()); + s_is_started = true; - CPUSetInitialExecutionState(); - CPU::Run(); + CPUSetInitialExecutionState(); + CPU::Run(); - s_is_started = false; - PowerPC::InjectExternalCPUCore(nullptr); - } - FifoPlayer::GetInstance().Close(); - } + s_is_started = false; + PowerPC::InjectExternalCPUCore(nullptr); + } + FifoPlayer::GetInstance().Close(); + } - // If we did not enter the CPU Run Loop above then run a fake one instead. - // We need to be IsRunningAndStarted() for DolphinWX to stop us. - if (CPU::GetState() != CPU::CPU_POWERDOWN) - { - s_is_started = true; - Host_Message(WM_USER_STOP); - while (CPU::GetState() != CPU::CPU_POWERDOWN) - { - if (!_CoreParameter.bCPUThread) - g_video_backend->PeekMessages(); - std::this_thread::sleep_for(std::chrono::milliseconds(20)); - } - s_is_started = false; - } + // If we did not enter the CPU Run Loop above then run a fake one instead. + // We need to be IsRunningAndStarted() for DolphinWX to stop us. + if (CPU::GetState() != CPU::CPU_POWERDOWN) + { + s_is_started = true; + Host_Message(WM_USER_STOP); + while (CPU::GetState() != CPU::CPU_POWERDOWN) + { + if (!_CoreParameter.bCPUThread) + g_video_backend->PeekMessages(); + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + } + s_is_started = false; + } - if (!_CoreParameter.bCPUThread) - g_video_backend->Video_Cleanup(); + if (!_CoreParameter.bCPUThread) + g_video_backend->Video_Cleanup(); - return; + return; } // Initialize and create emulation thread @@ -471,386 +472,386 @@ static void FifoPlayerThread() // See the BootManager.cpp file description for a complete call schedule. void EmuThread() { - const SConfig& core_parameter = SConfig::GetInstance(); - s_is_booting.store(true); + const SConfig& core_parameter = SConfig::GetInstance(); + s_is_booting.store(true); - Common::SetCurrentThreadName("Emuthread - Starting"); + Common::SetCurrentThreadName("Emuthread - Starting"); - if (SConfig::GetInstance().m_OCEnable) - DisplayMessage("WARNING: running at non-native CPU clock! Game may not be stable.", 8000); - DisplayMessage(cpu_info.brand_string, 8000); - DisplayMessage(cpu_info.Summarize(), 8000); - DisplayMessage(core_parameter.m_strFilename, 3000); + if (SConfig::GetInstance().m_OCEnable) + DisplayMessage("WARNING: running at non-native CPU clock! Game may not be stable.", 8000); + DisplayMessage(cpu_info.brand_string, 8000); + DisplayMessage(cpu_info.Summarize(), 8000); + DisplayMessage(core_parameter.m_strFilename, 3000); - // For a time this acts as the CPU thread... - DeclareAsCPUThread(); + // For a time this acts as the CPU thread... + DeclareAsCPUThread(); - Movie::Init(); + Movie::Init(); - HW::Init(); + HW::Init(); - if (!g_video_backend->Initialize(s_window_handle)) - { - s_is_booting.store(false); - PanicAlert("Failed to initialize video backend!"); - Host_Message(WM_USER_STOP); - return; - } + if (!g_video_backend->Initialize(s_window_handle)) + { + s_is_booting.store(false); + PanicAlert("Failed to initialize video backend!"); + Host_Message(WM_USER_STOP); + return; + } - OSD::AddMessage("Dolphin " + g_video_backend->GetName() + " Video Backend.", 5000); + OSD::AddMessage("Dolphin " + g_video_backend->GetName() + " Video Backend.", 5000); - if (cpu_info.HTT) - SConfig::GetInstance().bDSPThread = cpu_info.num_cores > 4; - else - SConfig::GetInstance().bDSPThread = cpu_info.num_cores > 2; + if (cpu_info.HTT) + SConfig::GetInstance().bDSPThread = cpu_info.num_cores > 4; + else + SConfig::GetInstance().bDSPThread = cpu_info.num_cores > 2; - if (!DSP::GetDSPEmulator()->Initialize(core_parameter.bWii, core_parameter.bDSPThread)) - { - s_is_booting.store(false); - HW::Shutdown(); - g_video_backend->Shutdown(); - PanicAlert("Failed to initialize DSP emulation!"); - Host_Message(WM_USER_STOP); - return; - } + if (!DSP::GetDSPEmulator()->Initialize(core_parameter.bWii, core_parameter.bDSPThread)) + { + s_is_booting.store(false); + HW::Shutdown(); + g_video_backend->Shutdown(); + PanicAlert("Failed to initialize DSP emulation!"); + Host_Message(WM_USER_STOP); + return; + } - bool init_controllers = false; - if (!g_controller_interface.IsInit()) - { - Pad::Initialize(s_window_handle); - Keyboard::Initialize(s_window_handle); - init_controllers = true; - } - else - { - // Update references in case controllers were refreshed - Pad::LoadConfig(); - Keyboard::LoadConfig(); - } + bool init_controllers = false; + if (!g_controller_interface.IsInit()) + { + Pad::Initialize(s_window_handle); + Keyboard::Initialize(s_window_handle); + init_controllers = true; + } + else + { + // Update references in case controllers were refreshed + Pad::LoadConfig(); + Keyboard::LoadConfig(); + } - // Load and Init Wiimotes - only if we are booting in Wii mode - if (core_parameter.bWii) - { - if (init_controllers) - Wiimote::Initialize(s_window_handle, !s_state_filename.empty()); - else - Wiimote::LoadConfig(); + // Load and Init Wiimotes - only if we are booting in Wii mode + if (core_parameter.bWii) + { + if (init_controllers) + Wiimote::Initialize(s_window_handle, !s_state_filename.empty()); + else + Wiimote::LoadConfig(); - // Activate Wiimotes which don't have source set to "None" - for (unsigned int i = 0; i != MAX_BBMOTES; ++i) - if (g_wiimote_sources[i]) - GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(true); + // Activate Wiimotes which don't have source set to "None" + for (unsigned int i = 0; i != MAX_BBMOTES; ++i) + if (g_wiimote_sources[i]) + GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(true); + } - } + AudioCommon::InitSoundStream(); - AudioCommon::InitSoundStream(); + // The hardware is initialized. + s_hardware_initialized = true; + s_is_booting.store(false); - // The hardware is initialized. - s_hardware_initialized = true; - s_is_booting.store(false); + // Set execution state to known values (CPU/FIFO/Audio Paused) + CPU::Break(); - // Set execution state to known values (CPU/FIFO/Audio Paused) - CPU::Break(); + // Load GCM/DOL/ELF whatever ... we boot with the interpreter core + PowerPC::SetMode(PowerPC::MODE_INTERPRETER); - // Load GCM/DOL/ELF whatever ... we boot with the interpreter core - PowerPC::SetMode(PowerPC::MODE_INTERPRETER); + CBoot::BootUp(); - CBoot::BootUp(); + // This adds the SyncGPU handler to CoreTiming, so now CoreTiming::Advance might block. + Fifo::Prepare(); - // This adds the SyncGPU handler to CoreTiming, so now CoreTiming::Advance might block. - Fifo::Prepare(); + // Thread is no longer acting as CPU Thread + UndeclareAsCPUThread(); - // Thread is no longer acting as CPU Thread - UndeclareAsCPUThread(); + // Setup our core, but can't use dynarec if we are compare server + if (core_parameter.iCPUCore != PowerPC::CORE_INTERPRETER && + (!core_parameter.bRunCompareServer || core_parameter.bRunCompareClient)) + { + PowerPC::SetMode(PowerPC::MODE_JIT); + } + else + { + PowerPC::SetMode(PowerPC::MODE_INTERPRETER); + } - // Setup our core, but can't use dynarec if we are compare server - if (core_parameter.iCPUCore != PowerPC::CORE_INTERPRETER - && (!core_parameter.bRunCompareServer || core_parameter.bRunCompareClient)) - { - PowerPC::SetMode(PowerPC::MODE_JIT); - } - else - { - PowerPC::SetMode(PowerPC::MODE_INTERPRETER); - } + // Update the window again because all stuff is initialized + Host_UpdateDisasmDialog(); + Host_UpdateMainFrame(); - // Update the window again because all stuff is initialized - Host_UpdateDisasmDialog(); - Host_UpdateMainFrame(); + // Determine the CPU thread function + void (*cpuThreadFunc)(void); + if (core_parameter.m_BootType == SConfig::BOOT_DFF) + cpuThreadFunc = FifoPlayerThread; + else + cpuThreadFunc = CpuThread; - // Determine the CPU thread function - void (*cpuThreadFunc)(void); - if (core_parameter.m_BootType == SConfig::BOOT_DFF) - cpuThreadFunc = FifoPlayerThread; - else - cpuThreadFunc = CpuThread; + // ENTER THE VIDEO THREAD LOOP + if (core_parameter.bCPUThread) + { + // This thread, after creating the EmuWindow, spawns a CPU + // thread, and then takes over and becomes the video thread + Common::SetCurrentThreadName("Video thread"); - // ENTER THE VIDEO THREAD LOOP - if (core_parameter.bCPUThread) - { - // This thread, after creating the EmuWindow, spawns a CPU - // thread, and then takes over and becomes the video thread - Common::SetCurrentThreadName("Video thread"); + g_video_backend->Video_Prepare(); - g_video_backend->Video_Prepare(); + // Spawn the CPU thread + s_cpu_thread = std::thread(cpuThreadFunc); - // Spawn the CPU thread - s_cpu_thread = std::thread(cpuThreadFunc); + // become the GPU thread + Fifo::RunGpuLoop(); - // become the GPU thread - Fifo::RunGpuLoop(); + // We have now exited the Video Loop + INFO_LOG(CONSOLE, "%s", StopMessage(false, "Video Loop Ended").c_str()); + } + else // SingleCore mode + { + // The spawned CPU Thread also does the graphics. + // The EmuThread is thus an idle thread, which sleeps while + // waiting for the program to terminate. Without this extra + // thread, the video backend window hangs in single core mode + // because no one is pumping messages. + Common::SetCurrentThreadName("Emuthread - Idle"); - // We have now exited the Video Loop - INFO_LOG(CONSOLE, "%s", StopMessage(false, "Video Loop Ended").c_str()); - } - else // SingleCore mode - { - // The spawned CPU Thread also does the graphics. - // The EmuThread is thus an idle thread, which sleeps while - // waiting for the program to terminate. Without this extra - // thread, the video backend window hangs in single core mode - // because no one is pumping messages. - Common::SetCurrentThreadName("Emuthread - Idle"); + // Spawn the CPU+GPU thread + s_cpu_thread = std::thread(cpuThreadFunc); - // Spawn the CPU+GPU thread - s_cpu_thread = std::thread(cpuThreadFunc); + while (CPU::GetState() != CPU::CPU_POWERDOWN) + { + g_video_backend->PeekMessages(); + Common::SleepCurrentThread(20); + } + } - while (CPU::GetState() != CPU::CPU_POWERDOWN) - { - g_video_backend->PeekMessages(); - Common::SleepCurrentThread(20); - } - } + INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping Emu thread ...").c_str()); - INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping Emu thread ...").c_str()); + // Wait for s_cpu_thread to exit + INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping CPU-GPU thread ...").c_str()); - // Wait for s_cpu_thread to exit - INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping CPU-GPU thread ...").c_str()); +#ifdef USE_GDBSTUB + INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping GDB ...").c_str()); + gdb_deinit(); + INFO_LOG(CONSOLE, "%s", StopMessage(true, "GDB stopped.").c_str()); +#endif - #ifdef USE_GDBSTUB - INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping GDB ...").c_str()); - gdb_deinit(); - INFO_LOG(CONSOLE, "%s", StopMessage(true, "GDB stopped.").c_str()); - #endif + s_cpu_thread.join(); - s_cpu_thread.join(); + INFO_LOG(CONSOLE, "%s", StopMessage(true, "CPU thread stopped.").c_str()); - INFO_LOG(CONSOLE, "%s", StopMessage(true, "CPU thread stopped.").c_str()); + if (core_parameter.bCPUThread) + g_video_backend->Video_Cleanup(); - if (core_parameter.bCPUThread) - g_video_backend->Video_Cleanup(); + FileMon::Close(); - FileMon::Close(); + // Stop audio thread - Actually this does nothing when using HLE + // emulation, but stops the DSP Interpreter when using LLE emulation. + DSP::GetDSPEmulator()->DSP_StopSoundStream(); - // Stop audio thread - Actually this does nothing when using HLE - // emulation, but stops the DSP Interpreter when using LLE emulation. - DSP::GetDSPEmulator()->DSP_StopSoundStream(); + // We must set up this flag before executing HW::Shutdown() + s_hardware_initialized = false; + INFO_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down HW").c_str()); + HW::Shutdown(); + INFO_LOG(CONSOLE, "%s", StopMessage(false, "HW shutdown").c_str()); - // We must set up this flag before executing HW::Shutdown() - s_hardware_initialized = false; - INFO_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down HW").c_str()); - HW::Shutdown(); - INFO_LOG(CONSOLE, "%s", StopMessage(false, "HW shutdown").c_str()); + if (init_controllers) + { + Wiimote::Shutdown(); + Keyboard::Shutdown(); + Pad::Shutdown(); + init_controllers = false; + } - if (init_controllers) - { - Wiimote::Shutdown(); - Keyboard::Shutdown(); - Pad::Shutdown(); - init_controllers = false; - } + g_video_backend->Shutdown(); + AudioCommon::ShutdownSoundStream(); - g_video_backend->Shutdown(); - AudioCommon::ShutdownSoundStream(); + INFO_LOG(CONSOLE, "%s", StopMessage(true, "Main Emu thread stopped").c_str()); - INFO_LOG(CONSOLE, "%s", StopMessage(true, "Main Emu thread stopped").c_str()); + // Clear on screen messages that haven't expired + OSD::ClearMessages(); - // Clear on screen messages that haven't expired - OSD::ClearMessages(); + // Reload sysconf file in order to see changes committed during emulation + if (core_parameter.bWii) + SConfig::GetInstance().m_SYSCONF->Reload(); - // Reload sysconf file in order to see changes committed during emulation - if (core_parameter.bWii) - SConfig::GetInstance().m_SYSCONF->Reload(); + INFO_LOG(CONSOLE, "Stop [Video Thread]\t\t---- Shutdown complete ----"); + Movie::Shutdown(); + PatchEngine::Shutdown(); - INFO_LOG(CONSOLE, "Stop [Video Thread]\t\t---- Shutdown complete ----"); - Movie::Shutdown(); - PatchEngine::Shutdown(); + s_is_stopping = false; - s_is_stopping = false; - - if (s_on_stopped_callback) - s_on_stopped_callback(); + if (s_on_stopped_callback) + s_on_stopped_callback(); } // Set or get the running state void SetState(EState state) { - // State cannot be controlled until the CPU Thread is operational - if (!IsRunningAndStarted()) - return; + // State cannot be controlled until the CPU Thread is operational + if (!IsRunningAndStarted()) + return; - switch (state) - { - case CORE_PAUSE: - // NOTE: GetState() will return CORE_PAUSE immediately, even before anything has - // stopped (including the CPU). - CPU::EnableStepping(true); // Break - Wiimote::Pause(); + switch (state) + { + case CORE_PAUSE: + // NOTE: GetState() will return CORE_PAUSE immediately, even before anything has + // stopped (including the CPU). + CPU::EnableStepping(true); // Break + Wiimote::Pause(); #if defined(__LIBUSB__) || defined(_WIN32) - GCAdapter::ResetRumble(); + GCAdapter::ResetRumble(); #endif - break; - case CORE_RUN: - CPU::EnableStepping(false); - Wiimote::Resume(); - break; - default: - PanicAlert("Invalid state"); - break; - } + break; + case CORE_RUN: + CPU::EnableStepping(false); + Wiimote::Resume(); + break; + default: + PanicAlert("Invalid state"); + break; + } } EState GetState() { - if (s_is_stopping) - return CORE_STOPPING; + if (s_is_stopping) + return CORE_STOPPING; - if (s_hardware_initialized) - { - if (CPU::IsStepping()) - return CORE_PAUSE; + if (s_hardware_initialized) + { + if (CPU::IsStepping()) + return CORE_PAUSE; - return CORE_RUN; - } + return CORE_RUN; + } - return CORE_UNINITIALIZED; + return CORE_UNINITIALIZED; } static std::string GenerateScreenshotFolderPath() { - const std::string& gameId = SConfig::GetInstance().GetUniqueID(); - std::string path = File::GetUserPath(D_SCREENSHOTS_IDX) + gameId + DIR_SEP_CHR; + const std::string& gameId = SConfig::GetInstance().GetUniqueID(); + std::string path = File::GetUserPath(D_SCREENSHOTS_IDX) + gameId + DIR_SEP_CHR; - if (!File::CreateFullPath(path)) - { - // fallback to old-style screenshots, without folder. - path = File::GetUserPath(D_SCREENSHOTS_IDX); - } + if (!File::CreateFullPath(path)) + { + // fallback to old-style screenshots, without folder. + path = File::GetUserPath(D_SCREENSHOTS_IDX); + } - return path; + return path; } static std::string GenerateScreenshotName() { - std::string path = GenerateScreenshotFolderPath(); + std::string path = GenerateScreenshotFolderPath(); - //append gameId, path only contains the folder here. - path += SConfig::GetInstance().GetUniqueID(); + // append gameId, path only contains the folder here. + path += SConfig::GetInstance().GetUniqueID(); - std::string name; - for (int i = 1; File::Exists(name = StringFromFormat("%s-%d.png", path.c_str(), i)); ++i) - { - // TODO? - } + std::string name; + for (int i = 1; File::Exists(name = StringFromFormat("%s-%d.png", path.c_str(), i)); ++i) + { + // TODO? + } - return name; + return name; } void SaveScreenShot() { - const bool bPaused = (GetState() == CORE_PAUSE); + const bool bPaused = (GetState() == CORE_PAUSE); - SetState(CORE_PAUSE); + SetState(CORE_PAUSE); - Renderer::SetScreenshot(GenerateScreenshotName()); + Renderer::SetScreenshot(GenerateScreenshotName()); - if (!bPaused) - SetState(CORE_RUN); + if (!bPaused) + SetState(CORE_RUN); } void SaveScreenShot(const std::string& name) { - const bool bPaused = (GetState() == CORE_PAUSE); + const bool bPaused = (GetState() == CORE_PAUSE); - SetState(CORE_PAUSE); + SetState(CORE_PAUSE); - std::string filePath = GenerateScreenshotFolderPath() + name + ".png"; + std::string filePath = GenerateScreenshotFolderPath() + name + ".png"; - Renderer::SetScreenshot(filePath); + Renderer::SetScreenshot(filePath); - if (!bPaused) - SetState(CORE_RUN); + if (!bPaused) + SetState(CORE_RUN); } void RequestRefreshInfo() { - s_request_refresh_info = true; + s_request_refresh_info = true; } bool PauseAndLock(bool do_lock, bool unpause_on_unlock) { - // WARNING: PauseAndLock is not fully threadsafe so is only valid on the Host Thread - if (!IsRunning()) - return true; + // WARNING: PauseAndLock is not fully threadsafe so is only valid on the Host Thread + if (!IsRunning()) + return true; - // let's support recursive locking to simplify things on the caller's side, - // and let's do it at this outer level in case the individual systems don't support it. - if (do_lock ? s_pause_and_lock_depth++ : --s_pause_and_lock_depth) - return true; + // let's support recursive locking to simplify things on the caller's side, + // and let's do it at this outer level in case the individual systems don't support it. + if (do_lock ? s_pause_and_lock_depth++ : --s_pause_and_lock_depth) + return true; - bool was_unpaused = true; - if (do_lock) - { - // first pause the CPU - // This acquires a wrapper mutex and converts the current thread into - // a temporary replacement CPU Thread. - was_unpaused = CPU::PauseAndLock(true); - } + bool was_unpaused = true; + if (do_lock) + { + // first pause the CPU + // This acquires a wrapper mutex and converts the current thread into + // a temporary replacement CPU Thread. + was_unpaused = CPU::PauseAndLock(true); + } - ExpansionInterface::PauseAndLock(do_lock, false); + ExpansionInterface::PauseAndLock(do_lock, false); - // audio has to come after CPU, because CPU thread can wait for audio thread (m_throttle). - DSP::GetDSPEmulator()->PauseAndLock(do_lock, false); + // audio has to come after CPU, because CPU thread can wait for audio thread (m_throttle). + DSP::GetDSPEmulator()->PauseAndLock(do_lock, false); - // video has to come after CPU, because CPU thread can wait for video thread (s_efbAccessRequested). - Fifo::PauseAndLock(do_lock, false); + // video has to come after CPU, because CPU thread can wait for video thread + // (s_efbAccessRequested). + Fifo::PauseAndLock(do_lock, false); #if defined(__LIBUSB__) || defined(_WIN32) - GCAdapter::ResetRumble(); + GCAdapter::ResetRumble(); #endif - // CPU is unlocked last because CPU::PauseAndLock contains the synchronization - // mechanism that prevents CPU::Break from racing. - if (!do_lock) - { - // The CPU is responsible for managing the Audio and FIFO state so we use its - // mechanism to unpause them. If we unpaused the systems above when releasing - // the locks then they could call CPU::Break which would require detecting it - // and re-pausing with CPU::EnableStepping. - was_unpaused = CPU::PauseAndLock(false, unpause_on_unlock, true); - } + // CPU is unlocked last because CPU::PauseAndLock contains the synchronization + // mechanism that prevents CPU::Break from racing. + if (!do_lock) + { + // The CPU is responsible for managing the Audio and FIFO state so we use its + // mechanism to unpause them. If we unpaused the systems above when releasing + // the locks then they could call CPU::Break which would require detecting it + // and re-pausing with CPU::EnableStepping. + was_unpaused = CPU::PauseAndLock(false, unpause_on_unlock, true); + } - return was_unpaused; + return was_unpaused; } // Display FPS info // This should only be called from VI void VideoThrottle() { - // Update info per second - u32 ElapseTime = (u32)s_timer.GetTimeDifference(); - if ((ElapseTime >= 1000 && s_drawn_video.load() > 0) || s_request_refresh_info) - { - UpdateTitle(); + // Update info per second + u32 ElapseTime = (u32)s_timer.GetTimeDifference(); + if ((ElapseTime >= 1000 && s_drawn_video.load() > 0) || s_request_refresh_info) + { + UpdateTitle(); - // Reset counter - s_timer.Update(); - s_drawn_frame.store(0); - s_drawn_video.store(0); - } + // Reset counter + s_timer.Update(); + s_drawn_frame.store(0); + s_drawn_video.store(0); + } - s_drawn_video++; + s_drawn_video++; } // Executed from GPU thread @@ -858,13 +859,13 @@ void VideoThrottle() // depending on the emulation speed set bool ShouldSkipFrame(int skipped) { - u32 TargetFPS = VideoInterface::GetTargetRefreshRate(); - if (SConfig::GetInstance().m_EmulationSpeed > 0.0f) - TargetFPS = u32(TargetFPS * SConfig::GetInstance().m_EmulationSpeed); - const u32 frames = s_drawn_frame.load(); - const bool fps_slow = !(s_timer.GetTimeDifference() < (frames + skipped) * 1000 / TargetFPS); + u32 TargetFPS = VideoInterface::GetTargetRefreshRate(); + if (SConfig::GetInstance().m_EmulationSpeed > 0.0f) + TargetFPS = u32(TargetFPS * SConfig::GetInstance().m_EmulationSpeed); + const u32 frames = s_drawn_frame.load(); + const bool fps_slow = !(s_timer.GetTimeDifference() < (frames + skipped) * 1000 / TargetFPS); - return fps_slow; + return fps_slow; } // --- Callbacks for backends / engine --- @@ -872,163 +873,168 @@ bool ShouldSkipFrame(int skipped) // Should be called from GPU thread when a frame is drawn void Callback_VideoCopiedToXFB(bool video_update) { - if (video_update) - s_drawn_frame++; + if (video_update) + s_drawn_frame++; - Movie::FrameUpdate(); + Movie::FrameUpdate(); } void UpdateTitle() { - u32 ElapseTime = (u32)s_timer.GetTimeDifference(); - s_request_refresh_info = false; - SConfig& _CoreParameter = SConfig::GetInstance(); + u32 ElapseTime = (u32)s_timer.GetTimeDifference(); + s_request_refresh_info = false; + SConfig& _CoreParameter = SConfig::GetInstance(); - if (ElapseTime == 0) - ElapseTime = 1; + if (ElapseTime == 0) + ElapseTime = 1; - float FPS = (float)(s_drawn_frame.load() * 1000.0 / ElapseTime); - float VPS = (float)(s_drawn_video.load() * 1000.0 / ElapseTime); - float Speed = (float)(s_drawn_video.load() * (100 * 1000.0) / (VideoInterface::GetTargetRefreshRate() * ElapseTime)); + float FPS = (float)(s_drawn_frame.load() * 1000.0 / ElapseTime); + float VPS = (float)(s_drawn_video.load() * 1000.0 / ElapseTime); + float Speed = (float)(s_drawn_video.load() * (100 * 1000.0) / + (VideoInterface::GetTargetRefreshRate() * ElapseTime)); - // Settings are shown the same for both extended and summary info - std::string SSettings = StringFromFormat("%s %s | %s | %s", PowerPC::GetCPUName(), _CoreParameter.bCPUThread ? "DC" : "SC", - g_video_backend->GetDisplayName().c_str(), _CoreParameter.bDSPHLE ? "HLE" : "LLE"); + // Settings are shown the same for both extended and summary info + std::string SSettings = StringFromFormat( + "%s %s | %s | %s", PowerPC::GetCPUName(), _CoreParameter.bCPUThread ? "DC" : "SC", + g_video_backend->GetDisplayName().c_str(), _CoreParameter.bDSPHLE ? "HLE" : "LLE"); - std::string SFPS; + std::string SFPS; - if (Movie::IsPlayingInput()) - SFPS = StringFromFormat("VI: %u/%u - Input: %u/%u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed); - else if (Movie::IsRecordingInput()) - SFPS = StringFromFormat("VI: %u - Input: %u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed); - else - { - SFPS = StringFromFormat("FPS: %.0f - VPS: %.0f - %.0f%%", FPS, VPS, Speed); - if (SConfig::GetInstance().m_InterfaceExtendedFPSInfo) - { - // Use extended or summary information. The summary information does not print the ticks data, - // that's more of a debugging interest, it can always be optional of course if someone is interested. - static u64 ticks = 0; - static u64 idleTicks = 0; - u64 newTicks = CoreTiming::GetTicks(); - u64 newIdleTicks = CoreTiming::GetIdleTicks(); + if (Movie::IsPlayingInput()) + SFPS = StringFromFormat("VI: %u/%u - Input: %u/%u - FPS: %.0f - VPS: %.0f - %.0f%%", + (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, + (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, + VPS, Speed); + else if (Movie::IsRecordingInput()) + SFPS = StringFromFormat("VI: %u - Input: %u - FPS: %.0f - VPS: %.0f - %.0f%%", + (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, + Speed); + else + { + SFPS = StringFromFormat("FPS: %.0f - VPS: %.0f - %.0f%%", FPS, VPS, Speed); + if (SConfig::GetInstance().m_InterfaceExtendedFPSInfo) + { + // Use extended or summary information. The summary information does not print the ticks data, + // that's more of a debugging interest, it can always be optional of course if someone is + // interested. + static u64 ticks = 0; + static u64 idleTicks = 0; + u64 newTicks = CoreTiming::GetTicks(); + u64 newIdleTicks = CoreTiming::GetIdleTicks(); - u64 diff = (newTicks - ticks) / 1000000; - u64 idleDiff = (newIdleTicks - idleTicks) / 1000000; + u64 diff = (newTicks - ticks) / 1000000; + u64 idleDiff = (newIdleTicks - idleTicks) / 1000000; - ticks = newTicks; - idleTicks = newIdleTicks; + ticks = newTicks; + idleTicks = newIdleTicks; - float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100; + float TicksPercentage = + (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100; - SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)", - _CoreParameter.bSkipIdle ? "~" : "", - (int)(diff), - (int)(diff - idleDiff), - (int)(idleDiff), - SystemTimers::GetTicksPerSecond() / 1000000, - _CoreParameter.bSkipIdle ? "~" : "", - TicksPercentage); - } - } - // This is our final "frame counter" string - std::string SMessage = StringFromFormat("%s | %s", SSettings.c_str(), SFPS.c_str()); + SFPS += + StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)", + _CoreParameter.bSkipIdle ? "~" : "", (int)(diff), (int)(diff - idleDiff), + (int)(idleDiff), SystemTimers::GetTicksPerSecond() / 1000000, + _CoreParameter.bSkipIdle ? "~" : "", TicksPercentage); + } + } + // This is our final "frame counter" string + std::string SMessage = StringFromFormat("%s | %s", SSettings.c_str(), SFPS.c_str()); - // Update the audio timestretcher with the current speed - if (g_sound_stream) - { - CMixer* pMixer = g_sound_stream->GetMixer(); - pMixer->UpdateSpeed((float)Speed / 100); - } + // Update the audio timestretcher with the current speed + if (g_sound_stream) + { + CMixer* pMixer = g_sound_stream->GetMixer(); + pMixer->UpdateSpeed((float)Speed / 100); + } - Host_UpdateTitle(SMessage); + Host_UpdateTitle(SMessage); } void Shutdown() { - // During shutdown DXGI expects us to handle some messages on the UI thread. - // Therefore we can't immediately block and wait for the emu thread to shut - // down, so we join the emu thread as late as possible when the UI has already - // shut down. - // For more info read "DirectX Graphics Infrastructure (DXGI): Best Practices" - // on MSDN. - if (s_emu_thread.joinable()) - s_emu_thread.join(); + // During shutdown DXGI expects us to handle some messages on the UI thread. + // Therefore we can't immediately block and wait for the emu thread to shut + // down, so we join the emu thread as late as possible when the UI has already + // shut down. + // For more info read "DirectX Graphics Infrastructure (DXGI): Best Practices" + // on MSDN. + if (s_emu_thread.joinable()) + s_emu_thread.join(); - // Make sure there's nothing left over in case we're about to exit. - HostDispatchJobs(); + // Make sure there's nothing left over in case we're about to exit. + HostDispatchJobs(); } void SetOnStoppedCallback(StoppedCallbackFunc callback) { - s_on_stopped_callback = callback; + s_on_stopped_callback = callback; } void UpdateWantDeterminism(bool initial) { - // For now, this value is not itself configurable. Instead, individual - // settings that depend on it, such as GPU determinism mode. should have - // override options for testing, - bool new_want_determinism = - Movie::IsPlayingInput() || - Movie::IsRecordingInput() || - NetPlay::IsNetPlayRunning(); - if (new_want_determinism != g_want_determinism || initial) - { - WARN_LOG(COMMON, "Want determinism <- %s", new_want_determinism ? "true" : "false"); + // For now, this value is not itself configurable. Instead, individual + // settings that depend on it, such as GPU determinism mode. should have + // override options for testing, + bool new_want_determinism = + Movie::IsPlayingInput() || Movie::IsRecordingInput() || NetPlay::IsNetPlayRunning(); + if (new_want_determinism != g_want_determinism || initial) + { + WARN_LOG(COMMON, "Want determinism <- %s", new_want_determinism ? "true" : "false"); - bool was_unpaused = Core::PauseAndLock(true); + bool was_unpaused = Core::PauseAndLock(true); - g_want_determinism = new_want_determinism; - WiiSockMan::GetInstance().UpdateWantDeterminism(new_want_determinism); - Fifo::UpdateWantDeterminism(new_want_determinism); - // We need to clear the cache because some parts of the JIT depend on want_determinism, e.g. use of FMA. - JitInterface::ClearCache(); - Common::InitializeWiiRoot(g_want_determinism); + g_want_determinism = new_want_determinism; + WiiSockMan::GetInstance().UpdateWantDeterminism(new_want_determinism); + Fifo::UpdateWantDeterminism(new_want_determinism); + // We need to clear the cache because some parts of the JIT depend on want_determinism, e.g. use + // of FMA. + JitInterface::ClearCache(); + Common::InitializeWiiRoot(g_want_determinism); - Core::PauseAndLock(false, was_unpaused); - } + Core::PauseAndLock(false, was_unpaused); + } } void QueueHostJob(std::function job, bool run_during_stop) { - if (!job) - return; + if (!job) + return; - bool send_message = false; - { - std::lock_guard guard(s_host_jobs_lock); - send_message = s_host_jobs_queue.empty(); - s_host_jobs_queue.emplace(HostJob{ std::move(job), run_during_stop }); - } - // If the the queue was empty then kick the Host to come and get this job. - if (send_message) - Host_Message(WM_USER_JOB_DISPATCH); + bool send_message = false; + { + std::lock_guard guard(s_host_jobs_lock); + send_message = s_host_jobs_queue.empty(); + s_host_jobs_queue.emplace(HostJob{std::move(job), run_during_stop}); + } + // If the the queue was empty then kick the Host to come and get this job. + if (send_message) + Host_Message(WM_USER_JOB_DISPATCH); } void HostDispatchJobs() { - // WARNING: This should only run on the Host Thread. - // NOTE: This function is potentially re-entrant. If a job calls - // Core::Stop for instance then we'll enter this a second time. - std::unique_lock guard(s_host_jobs_lock); - while (!s_host_jobs_queue.empty()) - { - HostJob job = std::move(s_host_jobs_queue.front()); - s_host_jobs_queue.pop(); + // WARNING: This should only run on the Host Thread. + // NOTE: This function is potentially re-entrant. If a job calls + // Core::Stop for instance then we'll enter this a second time. + std::unique_lock guard(s_host_jobs_lock); + while (!s_host_jobs_queue.empty()) + { + HostJob job = std::move(s_host_jobs_queue.front()); + s_host_jobs_queue.pop(); - // NOTE: Memory ordering is important. The booting flag needs to be - // checked first because the state transition is: - // CORE_UNINITIALIZED: s_is_booting -> s_hardware_initialized - // We need to check variables in the same order as the state - // transition, otherwise we race and get transient failures. - if (!job.run_after_stop && !s_is_booting.load() && !IsRunning()) - continue; + // NOTE: Memory ordering is important. The booting flag needs to be + // checked first because the state transition is: + // CORE_UNINITIALIZED: s_is_booting -> s_hardware_initialized + // We need to check variables in the same order as the state + // transition, otherwise we race and get transient failures. + if (!job.run_after_stop && !s_is_booting.load() && !IsRunning()) + continue; - guard.unlock(); - job.job(); - guard.lock(); - } + guard.unlock(); + job.job(); + guard.lock(); + } } -} // Core +} // Core diff --git a/Source/Core/Core/Core.h b/Source/Core/Core/Core.h index f09f89bce2..7471e860b8 100644 --- a/Source/Core/Core/Core.h +++ b/Source/Core/Core/Core.h @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // Core // The external interface to the emulator core. Plus some extras. @@ -19,7 +18,6 @@ namespace Core { - // TODO: ugly, remove extern bool g_aspect_wide; @@ -32,10 +30,10 @@ void Callback_VideoCopiedToXFB(bool video_update); enum EState { - CORE_UNINITIALIZED, - CORE_PAUSE, - CORE_RUN, - CORE_STOPPING + CORE_UNINITIALIZED, + CORE_PAUSE, + CORE_RUN, + CORE_STOPPING }; bool Init(); @@ -48,9 +46,9 @@ void UndeclareAsCPUThread(); std::string StopMessage(bool, const std::string&); bool IsRunning(); -bool IsRunningAndStarted(); // is running and the CPU loop has been entered -bool IsRunningInCurrentThread(); // this tells us whether we are running in the CPU thread. -bool IsCPUThread(); // this tells us whether we are the CPU thread. +bool IsRunningAndStarted(); // is running and the CPU loop has been entered +bool IsRunningInCurrentThread(); // this tells us whether we are running in the CPU thread. +bool IsCPUThread(); // this tells us whether we are the CPU thread. bool IsGPUThread(); // [NOT THREADSAFE] For use by Host only @@ -86,7 +84,7 @@ void UpdateTitle(); bool PauseAndLock(bool doLock, bool unpauseOnUnlock = true); // for calling back into UI code without introducing a dependency on it in core -typedef void(*StoppedCallbackFunc)(void); +typedef void (*StoppedCallbackFunc)(void); void SetOnStoppedCallback(StoppedCallbackFunc callback); // Run on the Host thread when the factors change. [NOT THREADSAFE] diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp index b879161262..6852f46cee 100644 --- a/Source/Core/Core/CoreTiming.cpp +++ b/Source/Core/Core/CoreTiming.cpp @@ -24,31 +24,30 @@ namespace CoreTiming { - struct EventType { - TimedCallback callback; - std::string name; + TimedCallback callback; + std::string name; }; static std::vector event_types; struct BaseEvent { - s64 time; - u64 userdata; - int type; + s64 time; + u64 userdata; + int type; }; typedef LinkedListItem Event; // STATE_TO_SAVE -static Event *first; +static Event* first; static std::mutex tsWriteLock; static Common::FifoQueue tsQueue; // event pools -static Event *eventPool = nullptr; +static Event* eventPool = nullptr; static float s_lastOCFactor; float g_lastOCFactor_inverted; @@ -70,21 +69,23 @@ static int ev_lost; static Event* GetNewEvent() { - if (!eventPool) - return new Event; + if (!eventPool) + return new Event; - Event* ev = eventPool; - eventPool = ev->next; - return ev; + Event* ev = eventPool; + eventPool = ev->next; + return ev; } static void FreeEvent(Event* ev) { - ev->next = eventPool; - eventPool = ev; + ev->next = eventPool; + eventPool = ev; } -static void EmptyTimedCallback(u64 userdata, s64 cyclesLate) {} +static void EmptyTimedCallback(u64 userdata, s64 cyclesLate) +{ +} // Changing the CPU speed in Dolphin isn't actually done by changing the physical clock rate, // but by changing the amount of work done in a particular amount of time. This tends to be more @@ -95,221 +96,229 @@ static void EmptyTimedCallback(u64 userdata, s64 cyclesLate) {} // but the effect is largely the same. static int DowncountToCycles(int downcount) { - return (int)(downcount * g_lastOCFactor_inverted); + return (int)(downcount * g_lastOCFactor_inverted); } static int CyclesToDowncount(int cycles) { - return (int)(cycles * s_lastOCFactor); + return (int)(cycles * s_lastOCFactor); } int RegisterEvent(const std::string& name, TimedCallback callback) { - EventType type; - type.name = name; - type.callback = callback; + EventType type; + type.name = name; + type.callback = callback; - // check for existing type with same name. - // we want event type names to remain unique so that we can use them for serialization. - for (auto& event_type : event_types) - { - if (name == event_type.name) - { - WARN_LOG(POWERPC, "Discarded old event type \"%s\" because a new type with the same name was registered.", name.c_str()); - // we don't know if someone might be holding on to the type index, - // so we gut the old event type instead of actually removing it. - event_type.name = "_discarded_event"; - event_type.callback = &EmptyTimedCallback; - } - } + // check for existing type with same name. + // we want event type names to remain unique so that we can use them for serialization. + for (auto& event_type : event_types) + { + if (name == event_type.name) + { + WARN_LOG( + POWERPC, + "Discarded old event type \"%s\" because a new type with the same name was registered.", + name.c_str()); + // we don't know if someone might be holding on to the type index, + // so we gut the old event type instead of actually removing it. + event_type.name = "_discarded_event"; + event_type.callback = &EmptyTimedCallback; + } + } - event_types.push_back(type); - return (int)event_types.size() - 1; + event_types.push_back(type); + return (int)event_types.size() - 1; } void UnregisterAllEvents() { - if (first) - PanicAlert("Cannot unregister events with events pending"); - event_types.clear(); + if (first) + PanicAlert("Cannot unregister events with events pending"); + event_types.clear(); } void Init() { - s_lastOCFactor = SConfig::GetInstance().m_OCEnable ? SConfig::GetInstance().m_OCFactor : 1.0f; - g_lastOCFactor_inverted = 1.0f / s_lastOCFactor; - PowerPC::ppcState.downcount = CyclesToDowncount(maxslicelength); - g_slicelength = maxslicelength; - g_globalTimer = 0; - idledCycles = 0; - globalTimerIsSane = true; + s_lastOCFactor = SConfig::GetInstance().m_OCEnable ? SConfig::GetInstance().m_OCFactor : 1.0f; + g_lastOCFactor_inverted = 1.0f / s_lastOCFactor; + PowerPC::ppcState.downcount = CyclesToDowncount(maxslicelength); + g_slicelength = maxslicelength; + g_globalTimer = 0; + idledCycles = 0; + globalTimerIsSane = true; - ev_lost = RegisterEvent("_lost_event", &EmptyTimedCallback); + ev_lost = RegisterEvent("_lost_event", &EmptyTimedCallback); } void Shutdown() { - std::lock_guard lk(tsWriteLock); - MoveEvents(); - ClearPendingEvents(); - UnregisterAllEvents(); + std::lock_guard lk(tsWriteLock); + MoveEvents(); + ClearPendingEvents(); + UnregisterAllEvents(); - while (eventPool) - { - Event *ev = eventPool; - eventPool = ev->next; - delete ev; - } + while (eventPool) + { + Event* ev = eventPool; + eventPool = ev->next; + delete ev; + } } -static void EventDoState(PointerWrap &p, BaseEvent* ev) +static void EventDoState(PointerWrap& p, BaseEvent* ev) { - p.Do(ev->time); + p.Do(ev->time); - // this is why we can't have (nice things) pointers as userdata - p.Do(ev->userdata); + // this is why we can't have (nice things) pointers as userdata + p.Do(ev->userdata); - // we can't savestate ev->type directly because events might not get registered in the same order (or at all) every time. - // so, we savestate the event's type's name, and derive ev->type from that when loading. - std::string name; - if (p.GetMode() != PointerWrap::MODE_READ) - name = event_types[ev->type].name; + // we can't savestate ev->type directly because events might not get registered in the same order + // (or at all) every time. + // so, we savestate the event's type's name, and derive ev->type from that when loading. + std::string name; + if (p.GetMode() != PointerWrap::MODE_READ) + name = event_types[ev->type].name; - p.Do(name); - if (p.GetMode() == PointerWrap::MODE_READ) - { - bool foundMatch = false; - for (unsigned int i = 0; i < event_types.size(); ++i) - { - if (name == event_types[i].name) - { - ev->type = i; - foundMatch = true; - break; - } - } - if (!foundMatch) - { - WARN_LOG(POWERPC, "Lost event from savestate because its type, \"%s\", has not been registered.", name.c_str()); - ev->type = ev_lost; - } - } + p.Do(name); + if (p.GetMode() == PointerWrap::MODE_READ) + { + bool foundMatch = false; + for (unsigned int i = 0; i < event_types.size(); ++i) + { + if (name == event_types[i].name) + { + ev->type = i; + foundMatch = true; + break; + } + } + if (!foundMatch) + { + WARN_LOG(POWERPC, + "Lost event from savestate because its type, \"%s\", has not been registered.", + name.c_str()); + ev->type = ev_lost; + } + } } -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - std::lock_guard lk(tsWriteLock); - p.Do(g_slicelength); - p.Do(g_globalTimer); - p.Do(idledCycles); - p.Do(fakeDecStartValue); - p.Do(fakeDecStartTicks); - p.Do(g_fakeTBStartValue); - p.Do(g_fakeTBStartTicks); - p.Do(s_lastOCFactor); - if (p.GetMode() == PointerWrap::MODE_READ) - g_lastOCFactor_inverted = 1.0f / s_lastOCFactor; + std::lock_guard lk(tsWriteLock); + p.Do(g_slicelength); + p.Do(g_globalTimer); + p.Do(idledCycles); + p.Do(fakeDecStartValue); + p.Do(fakeDecStartTicks); + p.Do(g_fakeTBStartValue); + p.Do(g_fakeTBStartTicks); + p.Do(s_lastOCFactor); + if (p.GetMode() == PointerWrap::MODE_READ) + g_lastOCFactor_inverted = 1.0f / s_lastOCFactor; - p.DoMarker("CoreTimingData"); + p.DoMarker("CoreTimingData"); - MoveEvents(); + MoveEvents(); - p.DoLinkedList(first); - p.DoMarker("CoreTimingEvents"); + p.DoLinkedList(first); + p.DoMarker("CoreTimingEvents"); } -// This should only be called from the CPU thread, if you are calling it any other thread, you are doing something evil +// This should only be called from the CPU thread, if you are calling it any other thread, you are +// doing something evil u64 GetTicks() { - u64 ticks = (u64)g_globalTimer; - if (!globalTimerIsSane) - { - int downcount = DowncountToCycles(PowerPC::ppcState.downcount); - ticks += g_slicelength - downcount; - } - return ticks; + u64 ticks = (u64)g_globalTimer; + if (!globalTimerIsSane) + { + int downcount = DowncountToCycles(PowerPC::ppcState.downcount); + ticks += g_slicelength - downcount; + } + return ticks; } u64 GetIdleTicks() { - return (u64)idledCycles; + return (u64)idledCycles; } // This is to be called when outside threads, such as the graphics thread, wants to // schedule things to be executed on the main thread. void ScheduleEvent_Threadsafe(s64 cyclesIntoFuture, int event_type, u64 userdata) { - _assert_msg_(POWERPC, !Core::IsCPUThread(), "ScheduleEvent_Threadsafe from wrong thread"); - if (Core::g_want_determinism) - { - ERROR_LOG(POWERPC, "Someone scheduled an off-thread \"%s\" event while netplay or movie play/record " - "was active. This is likely to cause a desync.", - event_types[event_type].name.c_str()); - } - std::lock_guard lk(tsWriteLock); - Event ne; - ne.time = g_globalTimer + cyclesIntoFuture; - ne.type = event_type; - ne.userdata = userdata; - tsQueue.Push(ne); + _assert_msg_(POWERPC, !Core::IsCPUThread(), "ScheduleEvent_Threadsafe from wrong thread"); + if (Core::g_want_determinism) + { + ERROR_LOG(POWERPC, + "Someone scheduled an off-thread \"%s\" event while netplay or movie play/record " + "was active. This is likely to cause a desync.", + event_types[event_type].name.c_str()); + } + std::lock_guard lk(tsWriteLock); + Event ne; + ne.time = g_globalTimer + cyclesIntoFuture; + ne.type = event_type; + ne.userdata = userdata; + tsQueue.Push(ne); } // Executes an event immediately, then returns. void ScheduleEvent_Immediate(int event_type, u64 userdata) { - _assert_msg_(POWERPC, Core::IsCPUThread(), "ScheduleEvent_Immediate from wrong thread"); - event_types[event_type].callback(userdata, 0); + _assert_msg_(POWERPC, Core::IsCPUThread(), "ScheduleEvent_Immediate from wrong thread"); + event_types[event_type].callback(userdata, 0); } // Same as ScheduleEvent_Threadsafe(0, ...) EXCEPT if we are already on the CPU thread // in which case this is the same as ScheduleEvent_Immediate. void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata) { - if (Core::IsCPUThread()) - { - event_types[event_type].callback(userdata, 0); - } - else - { - ScheduleEvent_Threadsafe(0, event_type, userdata); - } + if (Core::IsCPUThread()) + { + event_types[event_type].callback(userdata, 0); + } + else + { + ScheduleEvent_Threadsafe(0, event_type, userdata); + } } // To be used from any thread, including the CPU thread void ScheduleEvent_AnyThread(s64 cyclesIntoFuture, int event_type, u64 userdata) { - if (Core::IsCPUThread()) - ScheduleEvent(cyclesIntoFuture, event_type, userdata); - else - ScheduleEvent_Threadsafe(cyclesIntoFuture, event_type, userdata); + if (Core::IsCPUThread()) + ScheduleEvent(cyclesIntoFuture, event_type, userdata); + else + ScheduleEvent_Threadsafe(cyclesIntoFuture, event_type, userdata); } void ClearPendingEvents() { - while (first) - { - Event *e = first->next; - FreeEvent(first); - first = e; - } + while (first) + { + Event* e = first->next; + FreeEvent(first); + first = e; + } } static void AddEventToQueue(Event* ne) { - Event* prev = nullptr; - Event** pNext = &first; - for (;;) - { - Event*& next = *pNext; - if (!next || ne->time < next->time) - { - ne->next = next; - next = ne; - break; - } - prev = next; - pNext = &prev->next; - } + Event* prev = nullptr; + Event** pNext = &first; + for (;;) + { + Event*& next = *pNext; + if (!next || ne->time < next->time) + { + ne->next = next; + next = ne; + break; + } + prev = next; + pNext = &prev->next; + } } // This must be run ONLY from within the CPU thread @@ -317,231 +326,233 @@ static void AddEventToQueue(Event* ne) // than Advance void ScheduleEvent(s64 cyclesIntoFuture, int event_type, u64 userdata) { - _assert_msg_(POWERPC, Core::IsCPUThread() || Core::GetState() == Core::CORE_PAUSE, - "ScheduleEvent from wrong thread"); + _assert_msg_(POWERPC, Core::IsCPUThread() || Core::GetState() == Core::CORE_PAUSE, + "ScheduleEvent from wrong thread"); - Event *ne = GetNewEvent(); - ne->userdata = userdata; - ne->type = event_type; - ne->time = GetTicks() + cyclesIntoFuture; + Event* ne = GetNewEvent(); + ne->userdata = userdata; + ne->type = event_type; + ne->time = GetTicks() + cyclesIntoFuture; - // If this event needs to be scheduled before the next advance(), force one early - if (!globalTimerIsSane) - ForceExceptionCheck(cyclesIntoFuture); + // If this event needs to be scheduled before the next advance(), force one early + if (!globalTimerIsSane) + ForceExceptionCheck(cyclesIntoFuture); - - AddEventToQueue(ne); + AddEventToQueue(ne); } void RemoveEvent(int event_type) { - while (first && first->type == event_type) - { - Event* next = first->next; - FreeEvent(first); - first = next; - } + while (first && first->type == event_type) + { + Event* next = first->next; + FreeEvent(first); + first = next; + } - if (!first) - return; + if (!first) + return; - Event *prev = first; - Event *ptr = prev->next; - while (ptr) - { - if (ptr->type == event_type) - { - prev->next = ptr->next; - FreeEvent(ptr); - ptr = prev->next; - } - else - { - prev = ptr; - ptr = ptr->next; - } - } + Event* prev = first; + Event* ptr = prev->next; + while (ptr) + { + if (ptr->type == event_type) + { + prev->next = ptr->next; + FreeEvent(ptr); + ptr = prev->next; + } + else + { + prev = ptr; + ptr = ptr->next; + } + } } void RemoveAllEvents(int event_type) { - MoveEvents(); - RemoveEvent(event_type); + MoveEvents(); + RemoveEvent(event_type); } void ForceExceptionCheck(s64 cycles) { - if (s64(DowncountToCycles(PowerPC::ppcState.downcount)) > cycles) - { - // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int here. - g_slicelength -= (DowncountToCycles(PowerPC::ppcState.downcount) - (int)cycles); // Account for cycles already executed by adjusting the g_slicelength - PowerPC::ppcState.downcount = CyclesToDowncount((int)cycles); - } + if (s64(DowncountToCycles(PowerPC::ppcState.downcount)) > cycles) + { + // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int here. + g_slicelength -= + (DowncountToCycles(PowerPC::ppcState.downcount) - + (int)cycles); // Account for cycles already executed by adjusting the g_slicelength + PowerPC::ppcState.downcount = CyclesToDowncount((int)cycles); + } } - -//This raise only the events required while the fifo is processing data +// This raise only the events required while the fifo is processing data void ProcessFifoWaitEvents() { - MoveEvents(); + MoveEvents(); - if (!first) - return; + if (!first) + return; - while (first) - { - if (first->time <= g_globalTimer) - { - Event* evt = first; - first = first->next; - event_types[evt->type].callback(evt->userdata, (int)(g_globalTimer - evt->time)); - FreeEvent(evt); - } - else - { - break; - } - } + while (first) + { + if (first->time <= g_globalTimer) + { + Event* evt = first; + first = first->next; + event_types[evt->type].callback(evt->userdata, (int)(g_globalTimer - evt->time)); + FreeEvent(evt); + } + else + { + break; + } + } } void MoveEvents() { - BaseEvent sevt; - while (tsQueue.Pop(sevt)) - { - Event *evt = GetNewEvent(); - evt->time = sevt.time; - evt->userdata = sevt.userdata; - evt->type = sevt.type; - AddEventToQueue(evt); - } + BaseEvent sevt; + while (tsQueue.Pop(sevt)) + { + Event* evt = GetNewEvent(); + evt->time = sevt.time; + evt->userdata = sevt.userdata; + evt->type = sevt.type; + AddEventToQueue(evt); + } } void Advance() { - MoveEvents(); + MoveEvents(); - int cyclesExecuted = g_slicelength - DowncountToCycles(PowerPC::ppcState.downcount); - g_globalTimer += cyclesExecuted; - s_lastOCFactor = SConfig::GetInstance().m_OCEnable ? SConfig::GetInstance().m_OCFactor : 1.0f; - g_lastOCFactor_inverted = 1.0f / s_lastOCFactor; - g_slicelength = maxslicelength; + int cyclesExecuted = g_slicelength - DowncountToCycles(PowerPC::ppcState.downcount); + g_globalTimer += cyclesExecuted; + s_lastOCFactor = SConfig::GetInstance().m_OCEnable ? SConfig::GetInstance().m_OCFactor : 1.0f; + g_lastOCFactor_inverted = 1.0f / s_lastOCFactor; + g_slicelength = maxslicelength; - globalTimerIsSane = true; + globalTimerIsSane = true; - while (first && first->time <= g_globalTimer) - { - //LOG(POWERPC, "[Scheduler] %s (%lld, %lld) ", - // event_types[first->type].name ? event_types[first->type].name : "?", (u64)g_globalTimer, (u64)first->time); - Event* evt = first; - first = first->next; - event_types[evt->type].callback(evt->userdata, (int)(g_globalTimer - evt->time)); - FreeEvent(evt); - } + while (first && first->time <= g_globalTimer) + { + // LOG(POWERPC, "[Scheduler] %s (%lld, %lld) ", + // event_types[first->type].name ? event_types[first->type].name : "?", + // (u64)g_globalTimer, (u64)first->time); + Event* evt = first; + first = first->next; + event_types[evt->type].callback(evt->userdata, (int)(g_globalTimer - evt->time)); + FreeEvent(evt); + } - globalTimerIsSane = false; + globalTimerIsSane = false; - if (first) - { - g_slicelength = (int)(first->time - g_globalTimer); - if (g_slicelength > maxslicelength) - g_slicelength = maxslicelength; - } + if (first) + { + g_slicelength = (int)(first->time - g_globalTimer); + if (g_slicelength > maxslicelength) + g_slicelength = maxslicelength; + } - PowerPC::ppcState.downcount = CyclesToDowncount(g_slicelength); - - // Check for any external exceptions. - // It's important to do this after processing events otherwise any exceptions will be delayed until the next slice: - // Pokemon Box refuses to boot if the first exception from the audio DMA is received late - PowerPC::CheckExternalExceptions(); + PowerPC::ppcState.downcount = CyclesToDowncount(g_slicelength); + // Check for any external exceptions. + // It's important to do this after processing events otherwise any exceptions will be delayed + // until the next slice: + // Pokemon Box refuses to boot if the first exception from the audio DMA is received late + PowerPC::CheckExternalExceptions(); } void LogPendingEvents() { - Event *ptr = first; - while (ptr) - { - INFO_LOG(POWERPC, "PENDING: Now: %" PRId64 " Pending: %" PRId64 " Type: %d", g_globalTimer, ptr->time, ptr->type); - ptr = ptr->next; - } + Event* ptr = first; + while (ptr) + { + INFO_LOG(POWERPC, "PENDING: Now: %" PRId64 " Pending: %" PRId64 " Type: %d", g_globalTimer, + ptr->time, ptr->type); + ptr = ptr->next; + } } void Idle() { - //DEBUG_LOG(POWERPC, "Idle"); + // DEBUG_LOG(POWERPC, "Idle"); - if (SConfig::GetInstance().bSyncGPUOnSkipIdleHack) - { - //When the FIFO is processing data we must not advance because in this way - //the VI will be desynchronized. So, We are waiting until the FIFO finish and - //while we process only the events required by the FIFO. - ProcessFifoWaitEvents(); - Fifo::FlushGpu(); - } + if (SConfig::GetInstance().bSyncGPUOnSkipIdleHack) + { + // When the FIFO is processing data we must not advance because in this way + // the VI will be desynchronized. So, We are waiting until the FIFO finish and + // while we process only the events required by the FIFO. + ProcessFifoWaitEvents(); + Fifo::FlushGpu(); + } - idledCycles += DowncountToCycles(PowerPC::ppcState.downcount); - PowerPC::ppcState.downcount = 0; + idledCycles += DowncountToCycles(PowerPC::ppcState.downcount); + PowerPC::ppcState.downcount = 0; } std::string GetScheduledEventsSummary() { - Event *ptr = first; - std::string text = "Scheduled events\n"; - text.reserve(1000); - while (ptr) - { - unsigned int t = ptr->type; - if (t >= event_types.size()) - PanicAlertT("Invalid event type %i", t); + Event* ptr = first; + std::string text = "Scheduled events\n"; + text.reserve(1000); + while (ptr) + { + unsigned int t = ptr->type; + if (t >= event_types.size()) + PanicAlertT("Invalid event type %i", t); - const std::string& name = event_types[ptr->type].name; + const std::string& name = event_types[ptr->type].name; - text += StringFromFormat("%s : %" PRIi64 " %016" PRIx64 "\n", name.c_str(), ptr->time, ptr->userdata); - ptr = ptr->next; - } - return text; + text += StringFromFormat("%s : %" PRIi64 " %016" PRIx64 "\n", name.c_str(), ptr->time, + ptr->userdata); + ptr = ptr->next; + } + return text; } u32 GetFakeDecStartValue() { - return fakeDecStartValue; + return fakeDecStartValue; } void SetFakeDecStartValue(u32 val) { - fakeDecStartValue = val; + fakeDecStartValue = val; } u64 GetFakeDecStartTicks() { - return fakeDecStartTicks; + return fakeDecStartTicks; } void SetFakeDecStartTicks(u64 val) { - fakeDecStartTicks = val; + fakeDecStartTicks = val; } u64 GetFakeTBStartValue() { - return g_fakeTBStartValue; + return g_fakeTBStartValue; } void SetFakeTBStartValue(u64 val) { - g_fakeTBStartValue = val; + g_fakeTBStartValue = val; } u64 GetFakeTBStartTicks() { - return g_fakeTBStartTicks; + return g_fakeTBStartTicks; } void SetFakeTBStartTicks(u64 val) { - g_fakeTBStartTicks = val; + g_fakeTBStartTicks = val; } } // namespace - diff --git a/Source/Core/Core/CoreTiming.h b/Source/Core/Core/CoreTiming.h index 9be212a7df..df07a4d345 100644 --- a/Source/Core/Core/CoreTiming.h +++ b/Source/Core/Core/CoreTiming.h @@ -24,7 +24,6 @@ class PointerWrap; namespace CoreTiming { - // These really shouldn't be global, but jit64 accesses them directly extern s64 g_globalTimer; extern u64 g_fakeTBStartValue; @@ -37,13 +36,15 @@ void Shutdown(); typedef void (*TimedCallback)(u64 userdata, s64 cyclesLate); -// This should only be called from the CPU thread, if you are calling it any other thread, you are doing something evil +// This should only be called from the CPU thread, if you are calling it any other thread, you are +// doing something evil u64 GetTicks(); u64 GetIdleTicks(); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); -// Returns the event_type identifier. if name is not unique, an existing event_type will be discarded. +// Returns the event_type identifier. if name is not unique, an existing event_type will be +// discarded. int RegisterEvent(const std::string& name, TimedCallback callback); void UnregisterAllEvents(); @@ -82,6 +83,4 @@ void SetFakeTBStartTicks(u64 val); void ForceExceptionCheck(s64 cycles); - - -} // end of namespace +} // end of namespace diff --git a/Source/Core/Core/DSP/DSPAccelerator.cpp b/Source/Core/Core/DSP/DSPAccelerator.cpp index b750d60ff9..1252cf928a 100644 --- a/Source/Core/Core/DSP/DSPAccelerator.cpp +++ b/Source/Core/Core/DSP/DSPAccelerator.cpp @@ -7,173 +7,174 @@ #include "Core/DSP/DSPAccelerator.h" #include "Core/DSP/DSPCore.h" -#include "Core/DSP/DSPHost.h" #include "Core/DSP/DSPHWInterface.h" +#include "Core/DSP/DSPHost.h" #include "Core/DSP/DSPInterpreter.h" // The hardware adpcm decoder :) static s16 ADPCM_Step(u32& _rSamplePos) { - const s16 *pCoefTable = (const s16 *)&g_dsp.ifx_regs[DSP_COEF_A1_0]; + const s16* pCoefTable = (const s16*)&g_dsp.ifx_regs[DSP_COEF_A1_0]; - if ((_rSamplePos & 15) == 0) - { - g_dsp.ifx_regs[DSP_PRED_SCALE] = DSPHost::ReadHostMemory((_rSamplePos & ~15) >> 1); - _rSamplePos += 2; - } + if ((_rSamplePos & 15) == 0) + { + g_dsp.ifx_regs[DSP_PRED_SCALE] = DSPHost::ReadHostMemory((_rSamplePos & ~15) >> 1); + _rSamplePos += 2; + } - int scale = 1 << (g_dsp.ifx_regs[DSP_PRED_SCALE] & 0xF); - int coef_idx = (g_dsp.ifx_regs[DSP_PRED_SCALE] >> 4) & 0x7; + int scale = 1 << (g_dsp.ifx_regs[DSP_PRED_SCALE] & 0xF); + int coef_idx = (g_dsp.ifx_regs[DSP_PRED_SCALE] >> 4) & 0x7; - s32 coef1 = pCoefTable[coef_idx * 2 + 0]; - s32 coef2 = pCoefTable[coef_idx * 2 + 1]; + s32 coef1 = pCoefTable[coef_idx * 2 + 0]; + s32 coef2 = pCoefTable[coef_idx * 2 + 1]; - int temp = (_rSamplePos & 1) ? - (DSPHost::ReadHostMemory(_rSamplePos >> 1) & 0xF) : - (DSPHost::ReadHostMemory(_rSamplePos >> 1) >> 4); + int temp = (_rSamplePos & 1) ? (DSPHost::ReadHostMemory(_rSamplePos >> 1) & 0xF) : + (DSPHost::ReadHostMemory(_rSamplePos >> 1) >> 4); - if (temp >= 8) - temp -= 16; + if (temp >= 8) + temp -= 16; - // 0x400 = 0.5 in 11-bit fixed point - int val = (scale * temp) + ((0x400 + coef1 * (s16)g_dsp.ifx_regs[DSP_YN1] + coef2 * (s16)g_dsp.ifx_regs[DSP_YN2]) >> 11); - val = MathUtil::Clamp(val, -0x7FFF, 0x7FFF); + // 0x400 = 0.5 in 11-bit fixed point + int val = + (scale * temp) + + ((0x400 + coef1 * (s16)g_dsp.ifx_regs[DSP_YN1] + coef2 * (s16)g_dsp.ifx_regs[DSP_YN2]) >> 11); + val = MathUtil::Clamp(val, -0x7FFF, 0x7FFF); - g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1]; - g_dsp.ifx_regs[DSP_YN1] = val; + g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1]; + g_dsp.ifx_regs[DSP_YN1] = val; - _rSamplePos++; + _rSamplePos++; - // The advanced interpolation (linear, polyphase,...) is done by the ucode, - // so we don't need to bother with it here. - return val; + // The advanced interpolation (linear, polyphase,...) is done by the ucode, + // so we don't need to bother with it here. + return val; } u16 dsp_read_aram_d3() { - // Zelda ucode reads ARAM through 0xffd3. - const u32 EndAddress = (g_dsp.ifx_regs[DSP_ACEAH] << 16) | g_dsp.ifx_regs[DSP_ACEAL]; - u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL]; - u16 val = 0; + // Zelda ucode reads ARAM through 0xffd3. + const u32 EndAddress = (g_dsp.ifx_regs[DSP_ACEAH] << 16) | g_dsp.ifx_regs[DSP_ACEAL]; + u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL]; + u16 val = 0; - switch (g_dsp.ifx_regs[DSP_FORMAT]) - { - case 0x5: // u8 reads - val = DSPHost::ReadHostMemory(Address); - Address++; - break; - case 0x6: // u16 reads - val = (DSPHost::ReadHostMemory(Address * 2) << 8) | DSPHost::ReadHostMemory(Address * 2 + 1); - Address++; - break; - default: - ERROR_LOG(DSPLLE, "dsp_read_aram_d3() - unknown format 0x%x", g_dsp.ifx_regs[DSP_FORMAT]); - break; - } + switch (g_dsp.ifx_regs[DSP_FORMAT]) + { + case 0x5: // u8 reads + val = DSPHost::ReadHostMemory(Address); + Address++; + break; + case 0x6: // u16 reads + val = (DSPHost::ReadHostMemory(Address * 2) << 8) | DSPHost::ReadHostMemory(Address * 2 + 1); + Address++; + break; + default: + ERROR_LOG(DSPLLE, "dsp_read_aram_d3() - unknown format 0x%x", g_dsp.ifx_regs[DSP_FORMAT]); + break; + } - if (Address >= EndAddress) - { - // Set address back to start address. (never seen this here!) - Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL]; - } + if (Address >= EndAddress) + { + // Set address back to start address. (never seen this here!) + Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL]; + } - g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16; - g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff; - return val; + g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16; + g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff; + return val; } void dsp_write_aram_d3(u16 value) { - // Zelda ucode writes a bunch of zeros to ARAM through d3 during - // initialization. Don't know if it ever does it later, too. - // Pikmin 2 Wii writes non-stop to 0x10008000-0x1000801f (non-zero values too) - // Zelda TP Wii writes non-stop to 0x10000000-0x1000001f (non-zero values too) - u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL]; + // Zelda ucode writes a bunch of zeros to ARAM through d3 during + // initialization. Don't know if it ever does it later, too. + // Pikmin 2 Wii writes non-stop to 0x10008000-0x1000801f (non-zero values too) + // Zelda TP Wii writes non-stop to 0x10000000-0x1000001f (non-zero values too) + u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL]; - switch (g_dsp.ifx_regs[DSP_FORMAT]) - { - case 0xA: // u16 writes - DSPHost::WriteHostMemory(value >> 8, Address * 2); - DSPHost::WriteHostMemory(value & 0xFF, Address * 2 + 1); - Address++; - break; - default: - ERROR_LOG(DSPLLE, "dsp_write_aram_d3() - unknown format 0x%x", g_dsp.ifx_regs[DSP_FORMAT]); - break; - } + switch (g_dsp.ifx_regs[DSP_FORMAT]) + { + case 0xA: // u16 writes + DSPHost::WriteHostMemory(value >> 8, Address * 2); + DSPHost::WriteHostMemory(value & 0xFF, Address * 2 + 1); + Address++; + break; + default: + ERROR_LOG(DSPLLE, "dsp_write_aram_d3() - unknown format 0x%x", g_dsp.ifx_regs[DSP_FORMAT]); + break; + } - g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16; - g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff; + g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16; + g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff; } u16 dsp_read_accelerator() { - const u32 EndAddress = (g_dsp.ifx_regs[DSP_ACEAH] << 16) | g_dsp.ifx_regs[DSP_ACEAL]; - u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL]; - u16 val; - u8 step_size_bytes = 0; + const u32 EndAddress = (g_dsp.ifx_regs[DSP_ACEAH] << 16) | g_dsp.ifx_regs[DSP_ACEAL]; + u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL]; + u16 val; + u8 step_size_bytes = 0; - // let's do the "hardware" decode DSP_FORMAT is interesting - the Zelda - // ucode seems to indicate that the bottom two bits specify the "read size" - // and the address multiplier. The bits above that may be things like sign - // extension and do/do not use ADPCM. It also remains to be figured out - // whether there's a difference between the usual accelerator "read - // address" and 0xd3. - switch (g_dsp.ifx_regs[DSP_FORMAT]) - { - case 0x00: // ADPCM audio - switch (EndAddress & 15) - { - case 0: // Tom and Jerry - step_size_bytes = 1; - break; - case 1: // Blazing Angels - step_size_bytes = 0; - break; - default: - step_size_bytes = 2; - break; - } - val = ADPCM_Step(Address); - break; - case 0x0A: // 16-bit PCM audio - val = (DSPHost::ReadHostMemory(Address * 2) << 8) | DSPHost::ReadHostMemory(Address * 2 + 1); - g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1]; - g_dsp.ifx_regs[DSP_YN1] = val; - step_size_bytes = 2; - Address++; - break; - case 0x19: // 8-bit PCM audio - val = DSPHost::ReadHostMemory(Address) << 8; - g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1]; - g_dsp.ifx_regs[DSP_YN1] = val; - step_size_bytes = 2; - Address++; - break; - default: - ERROR_LOG(DSPLLE, "dsp_read_accelerator() - unknown format 0x%x", g_dsp.ifx_regs[DSP_FORMAT]); - step_size_bytes = 2; - Address++; - val = 0; - break; - } + // let's do the "hardware" decode DSP_FORMAT is interesting - the Zelda + // ucode seems to indicate that the bottom two bits specify the "read size" + // and the address multiplier. The bits above that may be things like sign + // extension and do/do not use ADPCM. It also remains to be figured out + // whether there's a difference between the usual accelerator "read + // address" and 0xd3. + switch (g_dsp.ifx_regs[DSP_FORMAT]) + { + case 0x00: // ADPCM audio + switch (EndAddress & 15) + { + case 0: // Tom and Jerry + step_size_bytes = 1; + break; + case 1: // Blazing Angels + step_size_bytes = 0; + break; + default: + step_size_bytes = 2; + break; + } + val = ADPCM_Step(Address); + break; + case 0x0A: // 16-bit PCM audio + val = (DSPHost::ReadHostMemory(Address * 2) << 8) | DSPHost::ReadHostMemory(Address * 2 + 1); + g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1]; + g_dsp.ifx_regs[DSP_YN1] = val; + step_size_bytes = 2; + Address++; + break; + case 0x19: // 8-bit PCM audio + val = DSPHost::ReadHostMemory(Address) << 8; + g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1]; + g_dsp.ifx_regs[DSP_YN1] = val; + step_size_bytes = 2; + Address++; + break; + default: + ERROR_LOG(DSPLLE, "dsp_read_accelerator() - unknown format 0x%x", g_dsp.ifx_regs[DSP_FORMAT]); + step_size_bytes = 2; + Address++; + val = 0; + break; + } - // TODO: Take GAIN into account - // adpcm = 0, pcm8 = 0x100, pcm16 = 0x800 - // games using pcm8 : Phoenix Wright Ace Attorney (WiiWare), Megaman 9-10 (WiiWare) - // games using pcm16: GC Sega games, ... + // TODO: Take GAIN into account + // adpcm = 0, pcm8 = 0x100, pcm16 = 0x800 + // games using pcm8 : Phoenix Wright Ace Attorney (WiiWare), Megaman 9-10 (WiiWare) + // games using pcm16: GC Sega games, ... - // Check for loop. - // Somehow, YN1 and YN2 must be initialized with their "loop" values, - // so yeah, it seems likely that we should raise an exception to let - // the DSP program do that, at least if DSP_FORMAT == 0x0A. - if (Address == (EndAddress + step_size_bytes - 1)) - { - // Set address back to start address. - Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL]; - DSPCore_SetException(EXP_ACCOV); - } + // Check for loop. + // Somehow, YN1 and YN2 must be initialized with their "loop" values, + // so yeah, it seems likely that we should raise an exception to let + // the DSP program do that, at least if DSP_FORMAT == 0x0A. + if (Address == (EndAddress + step_size_bytes - 1)) + { + // Set address back to start address. + Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL]; + DSPCore_SetException(EXP_ACCOV); + } - g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16; - g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff; - return val; + g_dsp.ifx_regs[DSP_ACCAH] = Address >> 16; + g_dsp.ifx_regs[DSP_ACCAL] = Address & 0xffff; + return val; } diff --git a/Source/Core/Core/DSP/DSPAnalyzer.cpp b/Source/Core/Core/DSP/DSPAnalyzer.cpp index 1fb98d2ca1..ed25152d52 100644 --- a/Source/Core/Core/DSP/DSPAnalyzer.cpp +++ b/Source/Core/Core/DSP/DSPAnalyzer.cpp @@ -9,8 +9,8 @@ #include "Core/DSP/DSPMemoryMap.h" #include "Core/DSP/DSPTables.h" -namespace DSPAnalyzer { - +namespace DSPAnalyzer +{ // Holds data about all instructions in RAM. std::array code_flags; @@ -23,140 +23,133 @@ std::array code_flags; #define MAX_IDLE_SIG_SIZE 6 // 0xFFFF means ignore. -const u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] = -{ - // From AX: - { 0x26fc, // LRS $30, @DMBH - 0x02c0, 0x8000, // ANDCF $30, #0x8000 - 0x029d, 0xFFFF, // JLZ 0x027a - 0, 0 }, // RET - { 0x27fc, // LRS $31, @DMBH - 0x03c0, 0x8000, // ANDCF $31, #0x8000 - 0x029d, 0xFFFF, // JLZ 0x027a - 0, 0 }, // RET - { 0x26fe, // LRS $30, @CMBH - 0x02c0, 0x8000, // ANDCF $30, #0x8000 - 0x029c, 0xFFFF, // JLNZ 0x0280 - 0, 0 }, // RET - { 0x27fe, // LRS $31, @CMBH - 0x03c0, 0x8000, // ANDCF $31, #0x8000 - 0x029c, 0xFFFF, // JLNZ 0x0280 - 0, 0 }, // RET - { 0x26fc, // LRS $AC0.M, @DMBH - 0x02a0, 0x8000, // ANDF $AC0.M, #0x8000 - 0x029c, 0xFFFF, // JLNZ 0x???? - 0, 0 }, - { 0x27fc, // LRS $AC1.M, @DMBH - 0x03a0, 0x8000, // ANDF $AC1.M, #0x8000 - 0x029c, 0xFFFF, // JLNZ 0x???? - 0, 0 }, - // From Zelda: - { 0x00de, 0xFFFE, // LR $AC0.M, @CMBH - 0x02c0, 0x8000, // ANDCF $AC0.M, #0x8000 - 0x029c, 0xFFFF, // JLNZ 0x05cf - 0 }, - // From Zelda - experimental - { 0x00da, 0x0352, // LR $AX0.H, @0x0352 - 0x8600, // TSTAXH $AX0.H - 0x0295, 0xFFFF, // JZ 0x???? - 0, 0 } -}; +const u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] = { + // From AX: + {0x26fc, // LRS $30, @DMBH + 0x02c0, 0x8000, // ANDCF $30, #0x8000 + 0x029d, 0xFFFF, // JLZ 0x027a + 0, 0}, // RET + {0x27fc, // LRS $31, @DMBH + 0x03c0, 0x8000, // ANDCF $31, #0x8000 + 0x029d, 0xFFFF, // JLZ 0x027a + 0, 0}, // RET + {0x26fe, // LRS $30, @CMBH + 0x02c0, 0x8000, // ANDCF $30, #0x8000 + 0x029c, 0xFFFF, // JLNZ 0x0280 + 0, 0}, // RET + {0x27fe, // LRS $31, @CMBH + 0x03c0, 0x8000, // ANDCF $31, #0x8000 + 0x029c, 0xFFFF, // JLNZ 0x0280 + 0, 0}, // RET + {0x26fc, // LRS $AC0.M, @DMBH + 0x02a0, 0x8000, // ANDF $AC0.M, #0x8000 + 0x029c, 0xFFFF, // JLNZ 0x???? + 0, 0}, + {0x27fc, // LRS $AC1.M, @DMBH + 0x03a0, 0x8000, // ANDF $AC1.M, #0x8000 + 0x029c, 0xFFFF, // JLNZ 0x???? + 0, 0}, + // From Zelda: + {0x00de, 0xFFFE, // LR $AC0.M, @CMBH + 0x02c0, 0x8000, // ANDCF $AC0.M, #0x8000 + 0x029c, 0xFFFF, // JLNZ 0x05cf + 0}, + // From Zelda - experimental + {0x00da, 0x0352, // LR $AX0.H, @0x0352 + 0x8600, // TSTAXH $AX0.H + 0x0295, 0xFFFF, // JZ 0x???? + 0, 0}}; static void Reset() { - code_flags.fill(0); + code_flags.fill(0); } static void AnalyzeRange(u16 start_addr, u16 end_addr) { - // First we run an extremely simplified version of a disassembler to find - // where all instructions start. + // First we run an extremely simplified version of a disassembler to find + // where all instructions start. - // This may not be 100% accurate in case of jump tables! - // It could get desynced, which would be bad. We'll see if that's an issue. - u16 last_arithmetic = 0; - for (u16 addr = start_addr; addr < end_addr;) - { - UDSPInstruction inst = dsp_imem_read(addr); - const DSPOPCTemplate *opcode = GetOpTemplate(inst); - if (!opcode) - { - addr++; - continue; - } - code_flags[addr] |= CODE_START_OF_INST; - // Look for loops. - if ((inst & 0xffe0) == 0x0060 || (inst & 0xff00) == 0x1100) - { - // BLOOP, BLOOPI - u16 loop_end = dsp_imem_read(addr + 1); - code_flags[addr] |= CODE_LOOP_START; - code_flags[loop_end] |= CODE_LOOP_END; - } - else if ((inst & 0xffe0) == 0x0040 || (inst & 0xff00) == 0x1000) - { - // LOOP, LOOPI - code_flags[addr] |= CODE_LOOP_START; - code_flags[static_cast(addr + 1u)] |= CODE_LOOP_END; - } + // This may not be 100% accurate in case of jump tables! + // It could get desynced, which would be bad. We'll see if that's an issue. + u16 last_arithmetic = 0; + for (u16 addr = start_addr; addr < end_addr;) + { + UDSPInstruction inst = dsp_imem_read(addr); + const DSPOPCTemplate* opcode = GetOpTemplate(inst); + if (!opcode) + { + addr++; + continue; + } + code_flags[addr] |= CODE_START_OF_INST; + // Look for loops. + if ((inst & 0xffe0) == 0x0060 || (inst & 0xff00) == 0x1100) + { + // BLOOP, BLOOPI + u16 loop_end = dsp_imem_read(addr + 1); + code_flags[addr] |= CODE_LOOP_START; + code_flags[loop_end] |= CODE_LOOP_END; + } + else if ((inst & 0xffe0) == 0x0040 || (inst & 0xff00) == 0x1000) + { + // LOOP, LOOPI + code_flags[addr] |= CODE_LOOP_START; + code_flags[static_cast(addr + 1u)] |= CODE_LOOP_END; + } - // Mark the last arithmetic/multiplier instruction before a branch. - // We must update the SR reg at these instructions - if (opcode->updates_sr) - { - last_arithmetic = addr; - } + // Mark the last arithmetic/multiplier instruction before a branch. + // We must update the SR reg at these instructions + if (opcode->updates_sr) + { + last_arithmetic = addr; + } - if (opcode->branch && !opcode->uncond_branch) - { - code_flags[last_arithmetic] |= CODE_UPDATE_SR; - } + if (opcode->branch && !opcode->uncond_branch) + { + code_flags[last_arithmetic] |= CODE_UPDATE_SR; + } - // If an instruction potentially raises exceptions, mark the following - // instruction as needing to check for exceptions - if (opcode->opcode == 0x00c0 || - opcode->opcode == 0x1800 || - opcode->opcode == 0x1880 || - opcode->opcode == 0x1900 || - opcode->opcode == 0x1980 || - opcode->opcode == 0x2000 || - opcode->extended - ) - code_flags[static_cast(addr + opcode->size)] |= CODE_CHECK_INT; + // If an instruction potentially raises exceptions, mark the following + // instruction as needing to check for exceptions + if (opcode->opcode == 0x00c0 || opcode->opcode == 0x1800 || opcode->opcode == 0x1880 || + opcode->opcode == 0x1900 || opcode->opcode == 0x1980 || opcode->opcode == 0x2000 || + opcode->extended) + code_flags[static_cast(addr + opcode->size)] |= CODE_CHECK_INT; - addr += opcode->size; - } + addr += opcode->size; + } - // Next, we'll scan for potential idle skips. - for (int s = 0; s < NUM_IDLE_SIGS; s++) - { - for (u16 addr = start_addr; addr < end_addr; addr++) - { - bool found = false; - for (int i = 0; i < MAX_IDLE_SIG_SIZE + 1; i++) - { - if (idle_skip_sigs[s][i] == 0) - found = true; - if (idle_skip_sigs[s][i] == 0xFFFF) - continue; - if (idle_skip_sigs[s][i] != dsp_imem_read(addr + i)) - break; - } - if (found) - { - INFO_LOG(DSPLLE, "Idle skip location found at %02x (sigNum:%d)", addr, s+1); - code_flags[addr] |= CODE_IDLE_SKIP; - } - } - } - INFO_LOG(DSPLLE, "Finished analysis."); + // Next, we'll scan for potential idle skips. + for (int s = 0; s < NUM_IDLE_SIGS; s++) + { + for (u16 addr = start_addr; addr < end_addr; addr++) + { + bool found = false; + for (int i = 0; i < MAX_IDLE_SIG_SIZE + 1; i++) + { + if (idle_skip_sigs[s][i] == 0) + found = true; + if (idle_skip_sigs[s][i] == 0xFFFF) + continue; + if (idle_skip_sigs[s][i] != dsp_imem_read(addr + i)) + break; + } + if (found) + { + INFO_LOG(DSPLLE, "Idle skip location found at %02x (sigNum:%d)", addr, s + 1); + code_flags[addr] |= CODE_IDLE_SKIP; + } + } + } + INFO_LOG(DSPLLE, "Finished analysis."); } void Analyze() { - Reset(); - AnalyzeRange(0x0000, 0x1000); // IRAM - AnalyzeRange(0x8000, 0x9000); // IROM + Reset(); + AnalyzeRange(0x0000, 0x1000); // IRAM + AnalyzeRange(0x8000, 0x9000); // IROM } } // namespace diff --git a/Source/Core/Core/DSP/DSPAnalyzer.h b/Source/Core/Core/DSP/DSPAnalyzer.h index b55cccc21a..1eea140400 100644 --- a/Source/Core/Core/DSP/DSPAnalyzer.h +++ b/Source/Core/Core/DSP/DSPAnalyzer.h @@ -17,12 +17,12 @@ namespace DSPAnalyzer enum { - CODE_START_OF_INST = 1, - CODE_IDLE_SKIP = 2, - CODE_LOOP_START = 4, - CODE_LOOP_END = 8, - CODE_UPDATE_SR = 16, - CODE_CHECK_INT = 32, + CODE_START_OF_INST = 1, + CODE_IDLE_SKIP = 2, + CODE_LOOP_START = 4, + CODE_LOOP_END = 8, + CODE_UPDATE_SR = 16, + CODE_CHECK_INT = 32, }; // Easy to query array covering the whole of instruction memory. diff --git a/Source/Core/Core/DSP/DSPAssembler.cpp b/Source/Core/Core/DSP/DSPAssembler.cpp index 895d4bc579..7a1ad94605 100644 --- a/Source/Core/Core/DSP/DSPAssembler.cpp +++ b/Source/Core/Core/DSP/DSPAssembler.cpp @@ -18,213 +18,208 @@ #include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPTables.h" -static const char *err_string[] = -{ - "", - "Unknown Error", - "Unknown opcode", - "Not enough parameters", - "Too many parameters", - "Wrong parameter", - "Expected parameter of type 'string'", - "Expected parameter of type 'value'", - "Expected parameter of type 'register'", - "Expected parameter of type 'memory pointer'", - "Expected parameter of type 'immediate'", - "Incorrect binary value", - "Incorrect hexadecimal value", - "Incorrect decimal value", - "Label already exists", - "Label not defined", - "No matching brackets", - "This opcode cannot be extended", - "Given extending params for non extensible opcode", - "Wrong parameter: must be accumulator register", - "Wrong parameter: must be mid accumulator register", - "Invalid register", - "Number out of range" -}; +static const char* err_string[] = {"", + "Unknown Error", + "Unknown opcode", + "Not enough parameters", + "Too many parameters", + "Wrong parameter", + "Expected parameter of type 'string'", + "Expected parameter of type 'value'", + "Expected parameter of type 'register'", + "Expected parameter of type 'memory pointer'", + "Expected parameter of type 'immediate'", + "Incorrect binary value", + "Incorrect hexadecimal value", + "Incorrect decimal value", + "Label already exists", + "Label not defined", + "No matching brackets", + "This opcode cannot be extended", + "Given extending params for non extensible opcode", + "Wrong parameter: must be accumulator register", + "Wrong parameter: must be mid accumulator register", + "Invalid register", + "Number out of range"}; -DSPAssembler::DSPAssembler(const AssemblerSettings &settings) : - gdg_buffer(nullptr), - m_cur_addr(0), - m_cur_pass(0), - m_current_param(0), - settings_(settings) +DSPAssembler::DSPAssembler(const AssemblerSettings& settings) + : gdg_buffer(nullptr), m_cur_addr(0), m_cur_pass(0), m_current_param(0), settings_(settings) { } DSPAssembler::~DSPAssembler() { - if (gdg_buffer) - free(gdg_buffer); + if (gdg_buffer) + free(gdg_buffer); } -bool DSPAssembler::Assemble(const std::string& text, std::vector &code, std::vector *line_numbers) +bool DSPAssembler::Assemble(const std::string& text, std::vector& code, + std::vector* line_numbers) { - if (line_numbers) - line_numbers->clear(); - const char *fname = "tmp.asm"; - if (!File::WriteStringToFile(text, fname)) - return false; - InitPass(1); - if (!AssembleFile(fname, 1)) - return false; + if (line_numbers) + line_numbers->clear(); + const char* fname = "tmp.asm"; + if (!File::WriteStringToFile(text, fname)) + return false; + InitPass(1); + if (!AssembleFile(fname, 1)) + return false; - // We now have the size of the output buffer - if (m_totalSize > 0) - { - gdg_buffer = (char *)malloc(m_totalSize * sizeof(u16) + 4); - if (!gdg_buffer) - return false; + // We now have the size of the output buffer + if (m_totalSize > 0) + { + gdg_buffer = (char*)malloc(m_totalSize * sizeof(u16) + 4); + if (!gdg_buffer) + return false; - memset(gdg_buffer, 0, m_totalSize * sizeof(u16)); - } else - return false; + memset(gdg_buffer, 0, m_totalSize * sizeof(u16)); + } + else + return false; - InitPass(2); - if (!AssembleFile(fname, 2)) - return false; + InitPass(2); + if (!AssembleFile(fname, 2)) + return false; - code.resize(m_totalSize); - for (int i = 0; i < m_totalSize; i++) - { - code[i] = *(u16 *)(gdg_buffer + i * 2); - } + code.resize(m_totalSize); + for (int i = 0; i < m_totalSize; i++) + { + code[i] = *(u16*)(gdg_buffer + i * 2); + } - if (gdg_buffer) - { - free(gdg_buffer); - gdg_buffer = nullptr; - } + if (gdg_buffer) + { + free(gdg_buffer); + gdg_buffer = nullptr; + } - last_error_str = "(no errors)"; - last_error = ERR_OK; + last_error_str = "(no errors)"; + last_error = ERR_OK; - return true; + return true; } -void DSPAssembler::ShowError(err_t err_code, const char *extra_info) +void DSPAssembler::ShowError(err_t err_code, const char* extra_info) { + if (!settings_.force) + failed = true; - if (!settings_.force) - failed = true; + char error_buffer[1024]; + char* buf_ptr = error_buffer; + buf_ptr += sprintf(buf_ptr, "%i : %s ", code_line, cur_line.c_str()); + if (!extra_info) + extra_info = "-"; - char error_buffer[1024]; - char *buf_ptr = error_buffer; - buf_ptr += sprintf(buf_ptr, "%i : %s ", code_line, cur_line.c_str()); - if (!extra_info) - extra_info = "-"; - - if (m_current_param == 0) - buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d : %s\n", err_string[err_code], code_line, extra_info); - else - buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d Param: %d : %s\n", - err_string[err_code], code_line, m_current_param, extra_info); - last_error_str = error_buffer; - last_error = err_code; + if (m_current_param == 0) + buf_ptr += + sprintf(buf_ptr, "ERROR: %s Line: %d : %s\n", err_string[err_code], code_line, extra_info); + else + buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d Param: %d : %s\n", err_string[err_code], + code_line, m_current_param, extra_info); + last_error_str = error_buffer; + last_error = err_code; } -static char *skip_spaces(char *ptr) +static char* skip_spaces(char* ptr) { - while (*ptr == ' ') - ptr++; - return ptr; + while (*ptr == ' ') + ptr++; + return ptr; } // Parse a standalone value - it can be a number in one of several formats or a label. -s32 DSPAssembler::ParseValue(const char *str) +s32 DSPAssembler::ParseValue(const char* str) { - bool negative = false; - s32 val = 0; - const char *ptr = str; + bool negative = false; + s32 val = 0; + const char* ptr = str; - if (ptr[0] == '#') - { - ptr++; - negative = true; // Wow! Double # (needed one to get in here) negates??? - } - if (ptr[0] == '-') - { - ptr++; - negative = true; - } - if (ptr[0] == '0') - { - if (ptr[1] >= '0' && ptr[1] <= '9') - { - for (int i = 0; ptr[i] != 0; i++) - { - val *= 10; - if (ptr[i] >= '0' && ptr[i] <= '9') - val += ptr[i] - '0'; - else - ShowError(ERR_INCORRECT_DEC, str); - } - } - else - { - switch (ptr[1]) - { - case 'X': // hex - for (int i = 2 ; ptr[i] != 0 ; i++) - { - val <<= 4; - if (ptr[i] >= 'a' && ptr[i] <= 'f') - val += (ptr[i]-'a'+10); - else if (ptr[i] >= 'A' && ptr[i] <= 'F') - val += (ptr[i]-'A'+10); - else if (ptr[i] >= '0' && ptr[i] <= '9') - val += (ptr[i] - '0'); - else - ShowError(ERR_INCORRECT_HEX, str); - } - break; - case '\'': // binary - for (int i = 2; ptr[i] != 0; i++) - { - val *=2; - if (ptr[i] >= '0' && ptr[i] <= '1') - val += ptr[i] - '0'; - else - ShowError(ERR_INCORRECT_BIN, str); - } - break; - default: - // value is 0 or error - val = 0; - break; - } - } - } - else - { - // Symbol starts with a digit - it's a dec number. - if (ptr[0] >= '0' && ptr[0] <= '9') - { - for (int i = 0; ptr[i] != 0; i++) - { - val *= 10; - if (ptr[i] >= '0' && ptr[i] <= '9') - val += ptr[i] - '0'; - else - ShowError(ERR_INCORRECT_DEC, str); - } - } - else // Everything else is a label. - { - // Lookup label - u16 value; - if (labels.GetLabelValue(ptr, &value)) - return value; - if (m_cur_pass == 2) - ShowError(ERR_UNKNOWN_LABEL, str); - } - } - if (negative) - return -val; - return val; + if (ptr[0] == '#') + { + ptr++; + negative = true; // Wow! Double # (needed one to get in here) negates??? + } + if (ptr[0] == '-') + { + ptr++; + negative = true; + } + if (ptr[0] == '0') + { + if (ptr[1] >= '0' && ptr[1] <= '9') + { + for (int i = 0; ptr[i] != 0; i++) + { + val *= 10; + if (ptr[i] >= '0' && ptr[i] <= '9') + val += ptr[i] - '0'; + else + ShowError(ERR_INCORRECT_DEC, str); + } + } + else + { + switch (ptr[1]) + { + case 'X': // hex + for (int i = 2; ptr[i] != 0; i++) + { + val <<= 4; + if (ptr[i] >= 'a' && ptr[i] <= 'f') + val += (ptr[i] - 'a' + 10); + else if (ptr[i] >= 'A' && ptr[i] <= 'F') + val += (ptr[i] - 'A' + 10); + else if (ptr[i] >= '0' && ptr[i] <= '9') + val += (ptr[i] - '0'); + else + ShowError(ERR_INCORRECT_HEX, str); + } + break; + case '\'': // binary + for (int i = 2; ptr[i] != 0; i++) + { + val *= 2; + if (ptr[i] >= '0' && ptr[i] <= '1') + val += ptr[i] - '0'; + else + ShowError(ERR_INCORRECT_BIN, str); + } + break; + default: + // value is 0 or error + val = 0; + break; + } + } + } + else + { + // Symbol starts with a digit - it's a dec number. + if (ptr[0] >= '0' && ptr[0] <= '9') + { + for (int i = 0; ptr[i] != 0; i++) + { + val *= 10; + if (ptr[i] >= '0' && ptr[i] <= '9') + val += ptr[i] - '0'; + else + ShowError(ERR_INCORRECT_DEC, str); + } + } + else // Everything else is a label. + { + // Lookup label + u16 value; + if (labels.GetLabelValue(ptr, &value)) + return value; + if (m_cur_pass == 2) + ShowError(ERR_UNKNOWN_LABEL, str); + } + } + if (negative) + return -val; + return val; } // This function splits the given src string into three parts: @@ -232,784 +227,806 @@ s32 DSPAssembler::ParseValue(const char *str) // - Text within the first and last opening ('(') and closing (')') parentheses. // - If text follows after these parentheses, then this is what is returned from the function. // -// Note that the first opening parenthesis and the last closing parenthesis are discarded from the string. +// Note that the first opening parenthesis and the last closing parenthesis are discarded from the +// string. // For example: Say "Test (string) 1234" is the string passed in as src. // // - src will become "Test " // - dst will become "string" // - Returned string from the function will be " 1234" // -char *DSPAssembler::FindBrackets(char *src, char *dst) +char* DSPAssembler::FindBrackets(char* src, char* dst) { - s32 len = (s32) strlen(src); - s32 first = -1; - s32 count = 0; - s32 i, j; - j = 0; - for (i = 0 ; i < len ; i++) - { - if (src[i] == '(') - { - if (first < 0) - { - count = 1; - src[i] = 0x0; - first = i; - } - else - { - count++; - dst[j++] = src[i]; - } - } - else if (src[i] == ')') - { - if (--count == 0) - { - dst[j] = 0; - return &src[i+1]; - } - else - { - dst[j++] = src[i]; - } - } - else - { - if (first >= 0) - dst[j++] = src[i]; - } - } - if (count) - ShowError(ERR_NO_MATCHING_BRACKETS); - return nullptr; + s32 len = (s32)strlen(src); + s32 first = -1; + s32 count = 0; + s32 i, j; + j = 0; + for (i = 0; i < len; i++) + { + if (src[i] == '(') + { + if (first < 0) + { + count = 1; + src[i] = 0x0; + first = i; + } + else + { + count++; + dst[j++] = src[i]; + } + } + else if (src[i] == ')') + { + if (--count == 0) + { + dst[j] = 0; + return &src[i + 1]; + } + else + { + dst[j++] = src[i]; + } + } + else + { + if (first >= 0) + dst[j++] = src[i]; + } + } + if (count) + ShowError(ERR_NO_MATCHING_BRACKETS); + return nullptr; } // Bizarre in-place expression evaluator. -u32 DSPAssembler::ParseExpression(const char *ptr) +u32 DSPAssembler::ParseExpression(const char* ptr) { - char *pbuf; - s32 val = 0; + char* pbuf; + s32 val = 0; - char *d_buffer = (char *)malloc(1024); - char *s_buffer = (char *)malloc(1024); - strcpy(s_buffer, ptr); + char* d_buffer = (char*)malloc(1024); + char* s_buffer = (char*)malloc(1024); + strcpy(s_buffer, ptr); - while ((pbuf = FindBrackets(s_buffer, d_buffer)) != nullptr) - { - val = ParseExpression(d_buffer); - sprintf(d_buffer, "%s%d%s", s_buffer, val, pbuf); - strcpy(s_buffer, d_buffer); - } + while ((pbuf = FindBrackets(s_buffer, d_buffer)) != nullptr) + { + val = ParseExpression(d_buffer); + sprintf(d_buffer, "%s%d%s", s_buffer, val, pbuf); + strcpy(s_buffer, d_buffer); + } - int j = 0; - for (int i = 0; i < ((s32)strlen(s_buffer) + 1) ; i++) - { - char c = s_buffer[i]; - if (c != ' ') - d_buffer[j++] = c; - } + int j = 0; + for (int i = 0; i < ((s32)strlen(s_buffer) + 1); i++) + { + char c = s_buffer[i]; + if (c != ' ') + d_buffer[j++] = c; + } - for (int i = 0; i < ((s32)strlen(d_buffer) + 1) ; i++) - { - char c = d_buffer[i]; - if (c == '-') - { - if (i == 0) - c = '#'; - else - { - switch (d_buffer[i - 1]) - { - case '/': - case '%': - case '*': - c = '#'; - } - } - } - d_buffer[i] = c; - } + for (int i = 0; i < ((s32)strlen(d_buffer) + 1); i++) + { + char c = d_buffer[i]; + if (c == '-') + { + if (i == 0) + c = '#'; + else + { + switch (d_buffer[i - 1]) + { + case '/': + case '%': + case '*': + c = '#'; + } + } + } + d_buffer[i] = c; + } - while ((pbuf = strstr(d_buffer, "+")) != nullptr) - { - *pbuf = 0x0; - val = ParseExpression(d_buffer) + ParseExpression(pbuf+1); - sprintf(d_buffer, "%d", val); - } + while ((pbuf = strstr(d_buffer, "+")) != nullptr) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) + ParseExpression(pbuf + 1); + sprintf(d_buffer, "%d", val); + } - while ((pbuf = strstr(d_buffer, "-")) != nullptr) - { - *pbuf = 0x0; - val = ParseExpression(d_buffer) - ParseExpression(pbuf+1); - if (val < 0) - { - val = 0x10000 + (val & 0xffff); // ATTENTION: avoid a terrible bug!!! number cannot write with '-' in sprintf - fprintf(stderr, "WARNING: Number Underflow at Line: %d \n", code_line); - } - sprintf(d_buffer, "%d", val); - } + while ((pbuf = strstr(d_buffer, "-")) != nullptr) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) - ParseExpression(pbuf + 1); + if (val < 0) + { + val = 0x10000 + + (val & + 0xffff); // ATTENTION: avoid a terrible bug!!! number cannot write with '-' in sprintf + fprintf(stderr, "WARNING: Number Underflow at Line: %d \n", code_line); + } + sprintf(d_buffer, "%d", val); + } - while ((pbuf = strstr(d_buffer, "*")) != nullptr) - { - *pbuf = 0x0; - val = ParseExpression(d_buffer) * ParseExpression(pbuf+1); - sprintf(d_buffer, "%d", val); - } + while ((pbuf = strstr(d_buffer, "*")) != nullptr) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) * ParseExpression(pbuf + 1); + sprintf(d_buffer, "%d", val); + } - while ((pbuf = strstr(d_buffer, "/")) != nullptr) - { - *pbuf = 0x0; - val = ParseExpression(d_buffer) / ParseExpression(pbuf+1); - sprintf(d_buffer, "%d", val); - } + while ((pbuf = strstr(d_buffer, "/")) != nullptr) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) / ParseExpression(pbuf + 1); + sprintf(d_buffer, "%d", val); + } - while ((pbuf = strstr(d_buffer, "|")) != nullptr) - { - *pbuf = 0x0; - val = ParseExpression(d_buffer) | ParseExpression(pbuf+1); - sprintf(d_buffer, "%d", val); - } + while ((pbuf = strstr(d_buffer, "|")) != nullptr) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) | ParseExpression(pbuf + 1); + sprintf(d_buffer, "%d", val); + } - while ((pbuf = strstr(d_buffer, "&")) != nullptr) - { - *pbuf = 0x0; - val = ParseExpression(d_buffer) & ParseExpression(pbuf+1); - sprintf(d_buffer, "%d", val); - } + while ((pbuf = strstr(d_buffer, "&")) != nullptr) + { + *pbuf = 0x0; + val = ParseExpression(d_buffer) & ParseExpression(pbuf + 1); + sprintf(d_buffer, "%d", val); + } - val = ParseValue(d_buffer); - free(d_buffer); - free(s_buffer); - return val; + val = ParseValue(d_buffer); + free(d_buffer); + free(s_buffer); + return val; } // Destroys parstr -u32 DSPAssembler::GetParams(char *parstr, param_t *par) +u32 DSPAssembler::GetParams(char* parstr, param_t* par) { - u32 count = 0; - char *tmpstr = skip_spaces(parstr); - tmpstr = strtok(tmpstr, ",\x00"); - for (int i = 0; i < 10; i++) - { - if (tmpstr == nullptr) - break; - tmpstr = skip_spaces(tmpstr); - if (strlen(tmpstr) == 0) - break; - if (tmpstr) - count++; - else - break; + u32 count = 0; + char* tmpstr = skip_spaces(parstr); + tmpstr = strtok(tmpstr, ",\x00"); + for (int i = 0; i < 10; i++) + { + if (tmpstr == nullptr) + break; + tmpstr = skip_spaces(tmpstr); + if (strlen(tmpstr) == 0) + break; + if (tmpstr) + count++; + else + break; - par[i].type = P_NONE; - switch (tmpstr[0]) - { - case '"': - par[i].str = strtok(tmpstr, "\""); - par[i].type = P_STR; - break; - case '#': - par[i].val = ParseExpression(tmpstr + 1); - par[i].type = P_IMM; - break; - case '@': - if (tmpstr[1] == '$') - { - par[i].val = ParseExpression(tmpstr + 2); - par[i].type = P_PRG; - } - else - { - par[i].val = ParseExpression(tmpstr + 1); - par[i].type = P_MEM; - } - break; - case '$': - par[i].val = ParseExpression(tmpstr + 1); - par[i].type = P_REG; - break; + par[i].type = P_NONE; + switch (tmpstr[0]) + { + case '"': + par[i].str = strtok(tmpstr, "\""); + par[i].type = P_STR; + break; + case '#': + par[i].val = ParseExpression(tmpstr + 1); + par[i].type = P_IMM; + break; + case '@': + if (tmpstr[1] == '$') + { + par[i].val = ParseExpression(tmpstr + 2); + par[i].type = P_PRG; + } + else + { + par[i].val = ParseExpression(tmpstr + 1); + par[i].type = P_MEM; + } + break; + case '$': + par[i].val = ParseExpression(tmpstr + 1); + par[i].type = P_REG; + break; - default: - par[i].val = ParseExpression(tmpstr); - par[i].type = P_VAL; - break; - } - tmpstr = strtok(nullptr, ",\x00"); - } - return count; + default: + par[i].val = ParseExpression(tmpstr); + par[i].type = P_VAL; + break; + } + tmpstr = strtok(nullptr, ",\x00"); + } + return count; } -const opc_t *DSPAssembler::FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size) +const opc_t* DSPAssembler::FindOpcode(const char* opcode, u32 par_count, const opc_t* const opcod, + int opcod_size) { - if (opcode[0] == 'C' && opcode[1] == 'W') - return &cw; + if (opcode[0] == 'C' && opcode[1] == 'W') + return &cw; - AliasMap::const_iterator alias_iter = aliases.find(opcode); - if (alias_iter != aliases.end()) - opcode = alias_iter->second.c_str(); - for (int i = 0; i < opcod_size; i++) - { - const opc_t *opc = &opcod[i]; - if (strcmp(opc->name, opcode) == 0) - { - if (par_count < opc->param_count) - { - ShowError(ERR_NOT_ENOUGH_PARAMETERS); - } - if (par_count > opc->param_count) - { - ShowError(ERR_TOO_MANY_PARAMETERS); - } - return opc; - } - } - ShowError(ERR_UNKNOWN_OPCODE); - return nullptr; + AliasMap::const_iterator alias_iter = aliases.find(opcode); + if (alias_iter != aliases.end()) + opcode = alias_iter->second.c_str(); + for (int i = 0; i < opcod_size; i++) + { + const opc_t* opc = &opcod[i]; + if (strcmp(opc->name, opcode) == 0) + { + if (par_count < opc->param_count) + { + ShowError(ERR_NOT_ENOUGH_PARAMETERS); + } + if (par_count > opc->param_count) + { + ShowError(ERR_TOO_MANY_PARAMETERS); + } + return opc; + } + } + ShowError(ERR_UNKNOWN_OPCODE); + return nullptr; } // weird... static u16 get_mask_shifted_down(u16 mask) { - while (!(mask & 1)) - mask >>= 1; - return mask; + while (!(mask & 1)) + mask >>= 1; + return mask; } -bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool ext) +bool DSPAssembler::VerifyParams(const opc_t* opc, param_t* par, int count, bool ext) { - for (int i = 0; i < count; i++) - { - const int current_param = i + 1; // just for display. - if (opc->params[i].type != par[i].type || (par[i].type & P_REG)) - { - if (par[i].type == P_VAL && - (opc->params[i].type == P_ADDR_I || opc->params[i].type == P_ADDR_D)) - { - // Data and instruction addresses are valid as VAL values. - continue; - } + for (int i = 0; i < count; i++) + { + const int current_param = i + 1; // just for display. + if (opc->params[i].type != par[i].type || (par[i].type & P_REG)) + { + if (par[i].type == P_VAL && + (opc->params[i].type == P_ADDR_I || opc->params[i].type == P_ADDR_D)) + { + // Data and instruction addresses are valid as VAL values. + continue; + } - if ((opc->params[i].type & P_REG) && (par[i].type & P_REG)) - { - // Just a temp. Should be replaced with more purposeful vars. - int value; + if ((opc->params[i].type & P_REG) && (par[i].type & P_REG)) + { + // Just a temp. Should be replaced with more purposeful vars. + int value; - // modified by Hermes: test the register range - switch ((unsigned)opc->params[i].type) - { - case P_REG18: - case P_REG19: - case P_REG1A: - value = (opc->params[i].type >> 8) & 31; - if ((int)par[i].val < value || - (int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask)) - { - if (ext) - fprintf(stderr, "(ext) "); + // modified by Hermes: test the register range + switch ((unsigned)opc->params[i].type) + { + case P_REG18: + case P_REG19: + case P_REG1A: + value = (opc->params[i].type >> 8) & 31; + if ((int)par[i].val < value || + (int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask)) + { + if (ext) + fprintf(stderr, "(ext) "); - fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); - ShowError(ERR_INVALID_REGISTER); - } - break; - case P_PRG: - if ((int)par[i].val < 0 || (int)par[i].val > 0x3) - { - if (ext) - fprintf(stderr, "(ext) "); + fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); + ShowError(ERR_INVALID_REGISTER); + } + break; + case P_PRG: + if ((int)par[i].val < 0 || (int)par[i].val > 0x3) + { + if (ext) + fprintf(stderr, "(ext) "); - fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); - ShowError(ERR_INVALID_REGISTER); - } - break; - case P_ACC: - if ((int)par[i].val < 0x20 || (int)par[i].val > 0x21) - { - if (ext) - fprintf(stderr, "(ext) "); + fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); + ShowError(ERR_INVALID_REGISTER); + } + break; + case P_ACC: + if ((int)par[i].val < 0x20 || (int)par[i].val > 0x21) + { + if (ext) + fprintf(stderr, "(ext) "); - if (par[i].val >= 0x1e && par[i].val <= 0x1f) - { - fprintf(stderr, "%i : %s ", code_line, cur_line.c_str()); - fprintf(stderr, "WARNING: $ACM%d register used instead of $ACC%d register Line: %d Param: %d Ext: %d\n", - (par[i].val & 1), (par[i].val & 1), code_line, current_param, ext); - } - else if (par[i].val >= 0x1c && par[i].val <= 0x1d) - { - fprintf(stderr, "WARNING: $ACL%d register used instead of $ACC%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), code_line, current_param); - } - else - { - ShowError(ERR_WRONG_PARAMETER_ACC); - } - } - break; - case P_ACCM: - if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) - { - if (ext) - fprintf(stderr, "(ext) "); + if (par[i].val >= 0x1e && par[i].val <= 0x1f) + { + fprintf(stderr, "%i : %s ", code_line, cur_line.c_str()); + fprintf(stderr, "WARNING: $ACM%d register used instead of $ACC%d register Line: %d " + "Param: %d Ext: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param, ext); + } + else if (par[i].val >= 0x1c && par[i].val <= 0x1d) + { + fprintf( + stderr, + "WARNING: $ACL%d register used instead of $ACC%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } + else + { + ShowError(ERR_WRONG_PARAMETER_ACC); + } + } + break; + case P_ACCM: + if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) + { + if (ext) + fprintf(stderr, "(ext) "); - if (par[i].val >= 0x1c && par[i].val <= 0x1d) - { - fprintf(stderr, "WARNING: $ACL%d register used instead of $ACM%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), code_line, current_param); - } - else if (par[i].val >= 0x20 && par[i].val <= 0x21) - { - fprintf(stderr, "WARNING: $ACC%d register used instead of $ACM%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), code_line, current_param); - } - else - { - ShowError(ERR_WRONG_PARAMETER_ACC); - } - } - break; + if (par[i].val >= 0x1c && par[i].val <= 0x1d) + { + fprintf( + stderr, + "WARNING: $ACL%d register used instead of $ACM%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } + else if (par[i].val >= 0x20 && par[i].val <= 0x21) + { + fprintf( + stderr, + "WARNING: $ACC%d register used instead of $ACM%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } + else + { + ShowError(ERR_WRONG_PARAMETER_ACC); + } + } + break; - case P_ACCL: - if ((int)par[i].val < 0x1c || (int)par[i].val > 0x1d) - { - if (ext) - fprintf(stderr, "(ext) "); + case P_ACCL: + if ((int)par[i].val < 0x1c || (int)par[i].val > 0x1d) + { + if (ext) + fprintf(stderr, "(ext) "); - if (par[i].val >= 0x1e && par[i].val <= 0x1f) - { - fprintf(stderr, "%s ", cur_line.c_str()); - fprintf(stderr, "WARNING: $ACM%d register used instead of $ACL%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), code_line, current_param); - } - else if (par[i].val >= 0x20 && par[i].val <= 0x21) - { - fprintf(stderr, "%s ", cur_line.c_str()); - fprintf(stderr, "WARNING: $ACC%d register used instead of $ACL%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), code_line, current_param); - } - else - { - ShowError(ERR_WRONG_PARAMETER_ACC); - } - } - break; -/* case P_ACCM_D: //P_ACC_MID: - if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) - { - ShowError(ERR_WRONG_PARAMETER_MID_ACC); - } - break;*/ - } - continue; - } + if (par[i].val >= 0x1e && par[i].val <= 0x1f) + { + fprintf(stderr, "%s ", cur_line.c_str()); + fprintf( + stderr, + "WARNING: $ACM%d register used instead of $ACL%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } + else if (par[i].val >= 0x20 && par[i].val <= 0x21) + { + fprintf(stderr, "%s ", cur_line.c_str()); + fprintf( + stderr, + "WARNING: $ACC%d register used instead of $ACL%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } + else + { + ShowError(ERR_WRONG_PARAMETER_ACC); + } + } + break; + /* case P_ACCM_D: //P_ACC_MID: + if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) + { + ShowError(ERR_WRONG_PARAMETER_MID_ACC); + } + break;*/ + } + continue; + } - switch (par[i].type & (P_REG | 7)) - { - case P_REG: - if (ext) fprintf(stderr, "(ext) "); - ShowError(ERR_EXPECTED_PARAM_REG); - break; - case P_MEM: - if (ext) fprintf(stderr, "(ext) "); - ShowError(ERR_EXPECTED_PARAM_MEM); - break; - case P_VAL: - if (ext) fprintf(stderr, "(ext) "); - ShowError(ERR_EXPECTED_PARAM_VAL); - break; - case P_IMM: - if (ext) fprintf(stderr, "(ext) "); - ShowError(ERR_EXPECTED_PARAM_IMM); - break; - } - ShowError(ERR_WRONG_PARAMETER); - break; - } - else if ((opc->params[i].type & 3) != 0 && (par[i].type & 3) != 0) - { - // modified by Hermes: test NUMBER range - int value = get_mask_shifted_down(opc->params[i].mask); - unsigned int valueu = 0xffff & ~(value >> 1); - if ((int)par[i].val < 0) - { - if (value == 7) // value 7 por sbclr/sbset - { - fprintf(stderr,"Value must be from 0x0 to 0x%x\n", value); - ShowError(ERR_OUT_RANGE_NUMBER); - } - else if (opc->params[i].type == P_MEM) - { - if (value < 256) - fprintf(stderr, "Address value must be from 0x%x to 0x%x\n",valueu, (value>>1)); - else - fprintf(stderr, "Address value must be from 0x0 to 0x%x\n", value); + switch (par[i].type & (P_REG | 7)) + { + case P_REG: + if (ext) + fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_REG); + break; + case P_MEM: + if (ext) + fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_MEM); + break; + case P_VAL: + if (ext) + fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_VAL); + break; + case P_IMM: + if (ext) + fprintf(stderr, "(ext) "); + ShowError(ERR_EXPECTED_PARAM_IMM); + break; + } + ShowError(ERR_WRONG_PARAMETER); + break; + } + else if ((opc->params[i].type & 3) != 0 && (par[i].type & 3) != 0) + { + // modified by Hermes: test NUMBER range + int value = get_mask_shifted_down(opc->params[i].mask); + unsigned int valueu = 0xffff & ~(value >> 1); + if ((int)par[i].val < 0) + { + if (value == 7) // value 7 por sbclr/sbset + { + fprintf(stderr, "Value must be from 0x0 to 0x%x\n", value); + ShowError(ERR_OUT_RANGE_NUMBER); + } + else if (opc->params[i].type == P_MEM) + { + if (value < 256) + fprintf(stderr, "Address value must be from 0x%x to 0x%x\n", valueu, (value >> 1)); + else + fprintf(stderr, "Address value must be from 0x0 to 0x%x\n", value); - ShowError(ERR_OUT_RANGE_NUMBER); - } - else if ((int)par[i].val < -((value >> 1) + 1)) - { - if (value < 128) - fprintf(stderr, "Value must be from -0x%x to 0x%x, is %i\n", - (value >> 1) + 1, value >> 1, par[i].val); - else - fprintf(stderr, "Value must be from -0x%x to 0x%x or 0x0 to 0x%x, is %i\n", - (value >> 1) + 1, value >> 1, value, par[i].val); + ShowError(ERR_OUT_RANGE_NUMBER); + } + else if ((int)par[i].val < -((value >> 1) + 1)) + { + if (value < 128) + fprintf(stderr, "Value must be from -0x%x to 0x%x, is %i\n", (value >> 1) + 1, + value >> 1, par[i].val); + else + fprintf(stderr, "Value must be from -0x%x to 0x%x or 0x0 to 0x%x, is %i\n", + (value >> 1) + 1, value >> 1, value, par[i].val); - ShowError(ERR_OUT_RANGE_NUMBER); - } - } - else - { - if (value == 7) // value 7 por sbclr/sbset - { - if (par[i].val > (unsigned)value) - { - fprintf(stderr,"Value must be from 0x%x to 0x%x, is %i\n",valueu, value, par[i].val); - ShowError(ERR_OUT_RANGE_NUMBER); - } - } - else if (opc->params[i].type == P_MEM) - { - if (value < 256) - value >>= 1; // addressing 8 bit with sign - if (par[i].val > (unsigned)value && - (par[i].val < valueu || par[i].val > (unsigned)0xffff)) - { - if (value < 256) - fprintf(stderr,"Address value must be from 0x%x to 0x%x, is %04x\n", valueu, value, par[i].val); - else - fprintf(stderr,"Address value must be minor of 0x%x\n", value+1); - ShowError(ERR_OUT_RANGE_NUMBER); - } - } - else - { - if (value < 128) - value >>= 1; // special case ASL/ASR/LSL/LSR - if (par[i].val > (unsigned)value) - { - if (value < 64) - fprintf(stderr,"Value must be from -0x%x to 0x%x, is %i\n", (value + 1), value, par[i].val); - else - fprintf(stderr,"Value must be minor of 0x%x, is %i\n", value + 1, par[i].val); - ShowError(ERR_OUT_RANGE_NUMBER); - } - } - } - continue; - } - } - m_current_param = 0; - return true; + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + else + { + if (value == 7) // value 7 por sbclr/sbset + { + if (par[i].val > (unsigned)value) + { + fprintf(stderr, "Value must be from 0x%x to 0x%x, is %i\n", valueu, value, par[i].val); + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + else if (opc->params[i].type == P_MEM) + { + if (value < 256) + value >>= 1; // addressing 8 bit with sign + if (par[i].val > (unsigned)value && + (par[i].val < valueu || par[i].val > (unsigned)0xffff)) + { + if (value < 256) + fprintf(stderr, "Address value must be from 0x%x to 0x%x, is %04x\n", valueu, value, + par[i].val); + else + fprintf(stderr, "Address value must be minor of 0x%x\n", value + 1); + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + else + { + if (value < 128) + value >>= 1; // special case ASL/ASR/LSL/LSR + if (par[i].val > (unsigned)value) + { + if (value < 64) + fprintf(stderr, "Value must be from -0x%x to 0x%x, is %i\n", (value + 1), value, + par[i].val); + else + fprintf(stderr, "Value must be minor of 0x%x, is %i\n", value + 1, par[i].val); + ShowError(ERR_OUT_RANGE_NUMBER); + } + } + } + continue; + } + } + m_current_param = 0; + return true; } - // Merge opcode with params. -void DSPAssembler::BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf) +void DSPAssembler::BuildCode(const opc_t* opc, param_t* par, u32 par_count, u16* outbuf) { - outbuf[m_cur_addr] |= opc->opcode; - for (u32 i = 0; i < par_count; i++) - { - // Ignore the "reverse" parameters since they are implicit. - if (opc->params[i].type != P_ACC_D && opc->params[i].type != P_ACCM_D) - { - u16 t16 = outbuf[m_cur_addr + opc->params[i].loc]; - u16 v16 = par[i].val; - if (opc->params[i].lshift > 0) - v16 <<= opc->params[i].lshift; - else - v16 >>= -opc->params[i].lshift; - v16 &= opc->params[i].mask; - outbuf[m_cur_addr + opc->params[i].loc] = t16 | v16; - } - } + outbuf[m_cur_addr] |= opc->opcode; + for (u32 i = 0; i < par_count; i++) + { + // Ignore the "reverse" parameters since they are implicit. + if (opc->params[i].type != P_ACC_D && opc->params[i].type != P_ACCM_D) + { + u16 t16 = outbuf[m_cur_addr + opc->params[i].loc]; + u16 v16 = par[i].val; + if (opc->params[i].lshift > 0) + v16 <<= opc->params[i].lshift; + else + v16 >>= -opc->params[i].lshift; + v16 &= opc->params[i].mask; + outbuf[m_cur_addr + opc->params[i].loc] = t16 | v16; + } + } } void DSPAssembler::InitPass(int pass) { - failed = false; - if (pass == 1) - { - // Reset label table. Pre-populate with hw addresses and registers. - labels.Clear(); - labels.RegisterDefaults(); - aliases.clear(); - aliases["S15"] = "SET15"; - aliases["S16"] = "SET16"; - aliases["S40"] = "SET40"; - } - m_cur_addr = 0; - m_totalSize = 0; - cur_segment = SEGMENT_CODE; - segment_addr[SEGMENT_CODE] = 0; - segment_addr[SEGMENT_DATA] = 0; - segment_addr[SEGMENT_OVERLAY] = 0; + failed = false; + if (pass == 1) + { + // Reset label table. Pre-populate with hw addresses and registers. + labels.Clear(); + labels.RegisterDefaults(); + aliases.clear(); + aliases["S15"] = "SET15"; + aliases["S16"] = "SET16"; + aliases["S40"] = "SET40"; + } + m_cur_addr = 0; + m_totalSize = 0; + cur_segment = SEGMENT_CODE; + segment_addr[SEGMENT_CODE] = 0; + segment_addr[SEGMENT_DATA] = 0; + segment_addr[SEGMENT_OVERLAY] = 0; } -bool DSPAssembler::AssembleFile(const char *fname, int pass) +bool DSPAssembler::AssembleFile(const char* fname, int pass) { - int disable_text = 0; // modified by Hermes + int disable_text = 0; // modified by Hermes - std::ifstream fsrc; - OpenFStream(fsrc, fname, std::ios_base::in); + std::ifstream fsrc; + OpenFStream(fsrc, fname, std::ios_base::in); - if (fsrc.fail()) - { - std::cerr << "Cannot open file " << fname << std::endl; - return false; - } + if (fsrc.fail()) + { + std::cerr << "Cannot open file " << fname << std::endl; + return false; + } - //printf("%s: Pass %d\n", fname, pass); - code_line = 0; - m_cur_pass = pass; + // printf("%s: Pass %d\n", fname, pass); + code_line = 0; + m_cur_pass = pass; #define LINEBUF_SIZE 1024 - char line[LINEBUF_SIZE] = {0}; - while (!failed && !fsrc.fail() && !fsrc.eof()) - { - int opcode_size = 0; - fsrc.getline(line, LINEBUF_SIZE); - if (fsrc.fail()) - break; + char line[LINEBUF_SIZE] = {0}; + while (!failed && !fsrc.fail() && !fsrc.eof()) + { + int opcode_size = 0; + fsrc.getline(line, LINEBUF_SIZE); + if (fsrc.fail()) + break; - cur_line = line; - //printf("A: %s\n", line); - code_line++; + cur_line = line; + // printf("A: %s\n", line); + code_line++; - param_t params[10] = {{0, P_NONE, nullptr}}; - param_t params_ext[10] = {{0, P_NONE, nullptr}}; + param_t params[10] = {{0, P_NONE, nullptr}}; + param_t params_ext[10] = {{0, P_NONE, nullptr}}; - bool upper = true; - for (int i = 0; i < LINEBUF_SIZE; i++) - { - char c = line[i]; - // This stuff handles /**/ and // comments. - // modified by Hermes : added // and /* */ for long commentaries - if (c == '/') - { - if (i < 1023) - { - if (line[i+1] == '/') - c = 0x00; - else if (line[i+1] == '*') - { - // toggle comment mode. - disable_text = !disable_text; - } - } - } - else if (c == '*') - { - if (i < 1023 && line[i+1] == '/' && disable_text) - { - disable_text = 0; - c = 32; - line[i + 1] = 32; - } - } + bool upper = true; + for (int i = 0; i < LINEBUF_SIZE; i++) + { + char c = line[i]; + // This stuff handles /**/ and // comments. + // modified by Hermes : added // and /* */ for long commentaries + if (c == '/') + { + if (i < 1023) + { + if (line[i + 1] == '/') + c = 0x00; + else if (line[i + 1] == '*') + { + // toggle comment mode. + disable_text = !disable_text; + } + } + } + else if (c == '*') + { + if (i < 1023 && line[i + 1] == '/' && disable_text) + { + disable_text = 0; + c = 32; + line[i + 1] = 32; + } + } - // turn text into spaces if disable_text is on (in a comment). - if (disable_text && ((unsigned char)c) > 32) c = 32; + // turn text into spaces if disable_text is on (in a comment). + if (disable_text && ((unsigned char)c) > 32) + c = 32; - if (c == 0x0a || c == 0x0d || c == ';') - c = 0x00; - if (c == 0x09) // tabs to spaces - c = ' '; - if (c == '"') - upper = !upper; - if (upper && c >= 'a' && c <= 'z') // convert to uppercase - c = c - 'a' + 'A'; - line[i] = c; - if (c == 0) - break; // modified by Hermes - } - char *ptr = line; + if (c == 0x0a || c == 0x0d || c == ';') + c = 0x00; + if (c == 0x09) // tabs to spaces + c = ' '; + if (c == '"') + upper = !upper; + if (upper && c >= 'a' && c <= 'z') // convert to uppercase + c = c - 'a' + 'A'; + line[i] = c; + if (c == 0) + break; // modified by Hermes + } + char* ptr = line; - std::string label; + std::string label; - size_t col_pos = std::string(line).find(":"); - if (col_pos != std::string::npos) - { - bool valid = true; + size_t col_pos = std::string(line).find(":"); + if (col_pos != std::string::npos) + { + bool valid = true; - for (int j = 0; j < (int)col_pos; j++) - { - if (j == 0) - if (!((ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_'))) - valid = false; - if (!((ptr[j] >= '0' && ptr[j] <= '9') || (ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_'))) - valid = false; - } - if (valid) - { - label = std::string(line).substr(0, col_pos); - ptr += col_pos + 1; - } - } + for (int j = 0; j < (int)col_pos; j++) + { + if (j == 0) + if (!((ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_'))) + valid = false; + if (!((ptr[j] >= '0' && ptr[j] <= '9') || (ptr[j] >= 'A' && ptr[j] <= 'Z') || + (ptr[j] == '_'))) + valid = false; + } + if (valid) + { + label = std::string(line).substr(0, col_pos); + ptr += col_pos + 1; + } + } - char* opcode = strtok(ptr, " "); - char* opcode_ext = nullptr; + char* opcode = strtok(ptr, " "); + char* opcode_ext = nullptr; - u32 params_count = 0; - u32 params_count_ext = 0; - if (opcode) - { - if ((opcode_ext = strstr(opcode, "'")) != nullptr) - { - opcode_ext[0] = '\0'; - opcode_ext++; - if (strlen(opcode_ext) == 0) - opcode_ext = nullptr; - } - // now we have opcode and label + u32 params_count = 0; + u32 params_count_ext = 0; + if (opcode) + { + if ((opcode_ext = strstr(opcode, "'")) != nullptr) + { + opcode_ext[0] = '\0'; + opcode_ext++; + if (strlen(opcode_ext) == 0) + opcode_ext = nullptr; + } + // now we have opcode and label - params_count = 0; - params_count_ext = 0; + params_count = 0; + params_count_ext = 0; - char *paramstr = strtok(nullptr, "\0"); - char *paramstr_ext = nullptr; - // there is valid opcode so probably we have parameters + char* paramstr = strtok(nullptr, "\0"); + char* paramstr_ext = nullptr; + // there is valid opcode so probably we have parameters - if (paramstr) - { - if ((paramstr_ext = strstr(paramstr, ":")) != nullptr) - { - paramstr_ext[0] = '\0'; - paramstr_ext++; - } - } + if (paramstr) + { + if ((paramstr_ext = strstr(paramstr, ":")) != nullptr) + { + paramstr_ext[0] = '\0'; + paramstr_ext++; + } + } - if (paramstr) - params_count = GetParams(paramstr, params); - if (paramstr_ext) - params_count_ext = GetParams(paramstr_ext, params_ext); - } + if (paramstr) + params_count = GetParams(paramstr, params); + if (paramstr_ext) + params_count_ext = GetParams(paramstr_ext, params_ext); + } - if (!label.empty()) - { - // there is a valid label so lets store it in labels table - u32 lval = m_cur_addr; - if (opcode) - { - if (strcmp(opcode, "EQU") == 0) - { - lval = params[0].val; - opcode = nullptr; - } - } - if (pass == 1) - labels.RegisterLabel(label, lval); - } + if (!label.empty()) + { + // there is a valid label so lets store it in labels table + u32 lval = m_cur_addr; + if (opcode) + { + if (strcmp(opcode, "EQU") == 0) + { + lval = params[0].val; + opcode = nullptr; + } + } + if (pass == 1) + labels.RegisterLabel(label, lval); + } - if (opcode == nullptr) - continue; + if (opcode == nullptr) + continue; - // check if opcode is reserved compiler word - if (strcmp("INCLUDE", opcode) == 0) - { - if (params[0].type == P_STR) - { - char *tmpstr; - u32 thisCodeline = code_line; + // check if opcode is reserved compiler word + if (strcmp("INCLUDE", opcode) == 0) + { + if (params[0].type == P_STR) + { + char* tmpstr; + u32 thisCodeline = code_line; - if (include_dir.size()) - { - tmpstr = (char *)malloc(include_dir.size() + strlen(params[0].str) + 2); - sprintf(tmpstr, "%s/%s", include_dir.c_str(), params[0].str); - } - else - { - tmpstr = (char *)malloc(strlen(params[0].str) + 1); - strcpy(tmpstr, params[0].str); - } + if (include_dir.size()) + { + tmpstr = (char*)malloc(include_dir.size() + strlen(params[0].str) + 2); + sprintf(tmpstr, "%s/%s", include_dir.c_str(), params[0].str); + } + else + { + tmpstr = (char*)malloc(strlen(params[0].str) + 1); + strcpy(tmpstr, params[0].str); + } - AssembleFile(tmpstr, pass); + AssembleFile(tmpstr, pass); - code_line = thisCodeline; + code_line = thisCodeline; - free(tmpstr); - } - else - ShowError(ERR_EXPECTED_PARAM_STR); - continue; - } + free(tmpstr); + } + else + ShowError(ERR_EXPECTED_PARAM_STR); + continue; + } - if (strcmp("INCDIR", opcode) == 0) - { - if (params[0].type == P_STR) - include_dir = params[0].str; - else - ShowError(ERR_EXPECTED_PARAM_STR); - continue; - } + if (strcmp("INCDIR", opcode) == 0) + { + if (params[0].type == P_STR) + include_dir = params[0].str; + else + ShowError(ERR_EXPECTED_PARAM_STR); + continue; + } - if (strcmp("ORG", opcode) == 0) - { - if (params[0].type == P_VAL) - m_cur_addr = params[0].val; - else - ShowError(ERR_EXPECTED_PARAM_VAL); - continue; - } + if (strcmp("ORG", opcode) == 0) + { + if (params[0].type == P_VAL) + m_cur_addr = params[0].val; + else + ShowError(ERR_EXPECTED_PARAM_VAL); + continue; + } - if (strcmp("SEGMENT", opcode) == 0) - { - if (params[0].type == P_STR) - { - segment_addr[cur_segment] = m_cur_addr; - if (strcmp("DATA", params[0].str) == 0) - cur_segment = SEGMENT_DATA; - if (strcmp("CODE", params[0].str) == 0) - cur_segment = SEGMENT_CODE; - m_cur_addr = segment_addr[cur_segment]; - } - else - ShowError(ERR_EXPECTED_PARAM_STR); - continue; - } + if (strcmp("SEGMENT", opcode) == 0) + { + if (params[0].type == P_STR) + { + segment_addr[cur_segment] = m_cur_addr; + if (strcmp("DATA", params[0].str) == 0) + cur_segment = SEGMENT_DATA; + if (strcmp("CODE", params[0].str) == 0) + cur_segment = SEGMENT_CODE; + m_cur_addr = segment_addr[cur_segment]; + } + else + ShowError(ERR_EXPECTED_PARAM_STR); + continue; + } - const opc_t *opc = FindOpcode(opcode, params_count, opcodes, opcodes_size); - if (!opc) - opc = &cw; + const opc_t* opc = FindOpcode(opcode, params_count, opcodes, opcodes_size); + if (!opc) + opc = &cw; - opcode_size = opc->size; + opcode_size = opc->size; - VerifyParams(opc, params, params_count); + VerifyParams(opc, params, params_count); - const opc_t *opc_ext = nullptr; - // Check for opcode extensions. - if (opc->extended) - { - if (opcode_ext) - { - opc_ext = FindOpcode(opcode_ext, params_count_ext, opcodes_ext, opcodes_ext_size); - VerifyParams(opc_ext, params_ext, params_count_ext, true); - } - else if (params_count_ext) - ShowError(ERR_EXT_PAR_NOT_EXT); - } - else - { - if (opcode_ext) - ShowError(ERR_EXT_CANT_EXTEND_OPCODE); - if (params_count_ext) - ShowError(ERR_EXT_PAR_NOT_EXT); - } + const opc_t* opc_ext = nullptr; + // Check for opcode extensions. + if (opc->extended) + { + if (opcode_ext) + { + opc_ext = FindOpcode(opcode_ext, params_count_ext, opcodes_ext, opcodes_ext_size); + VerifyParams(opc_ext, params_ext, params_count_ext, true); + } + else if (params_count_ext) + ShowError(ERR_EXT_PAR_NOT_EXT); + } + else + { + if (opcode_ext) + ShowError(ERR_EXT_CANT_EXTEND_OPCODE); + if (params_count_ext) + ShowError(ERR_EXT_PAR_NOT_EXT); + } - if (pass == 2) - { - // generate binary - ((u16 *)gdg_buffer)[m_cur_addr] = 0x0000; - BuildCode(opc, params, params_count, (u16 *)gdg_buffer); - if (opc_ext) - BuildCode(opc_ext, params_ext, params_count_ext, (u16 *)gdg_buffer); - } + if (pass == 2) + { + // generate binary + ((u16*)gdg_buffer)[m_cur_addr] = 0x0000; + BuildCode(opc, params, params_count, (u16*)gdg_buffer); + if (opc_ext) + BuildCode(opc_ext, params_ext, params_count_ext, (u16*)gdg_buffer); + } - m_cur_addr += opcode_size; - m_totalSize += opcode_size; - }; + m_cur_addr += opcode_size; + m_totalSize += opcode_size; + }; - if (!failed) - fsrc.close(); + if (!failed) + fsrc.close(); - return !failed; + return !failed; } diff --git a/Source/Core/Core/DSP/DSPAssembler.h b/Source/Core/Core/DSP/DSPAssembler.h index ba1df0018b..9983e9c90a 100644 --- a/Source/Core/Core/DSP/DSPAssembler.h +++ b/Source/Core/Core/DSP/DSPAssembler.h @@ -16,103 +16,103 @@ enum err_t { - ERR_OK = 0, - ERR_UNKNOWN, - ERR_UNKNOWN_OPCODE, - ERR_NOT_ENOUGH_PARAMETERS, - ERR_TOO_MANY_PARAMETERS, - ERR_WRONG_PARAMETER, - ERR_EXPECTED_PARAM_STR, - ERR_EXPECTED_PARAM_VAL, - ERR_EXPECTED_PARAM_REG, - ERR_EXPECTED_PARAM_MEM, - ERR_EXPECTED_PARAM_IMM, - ERR_INCORRECT_BIN, - ERR_INCORRECT_HEX, - ERR_INCORRECT_DEC, - ERR_LABEL_EXISTS, - ERR_UNKNOWN_LABEL, - ERR_NO_MATCHING_BRACKETS, - ERR_EXT_CANT_EXTEND_OPCODE, - ERR_EXT_PAR_NOT_EXT, - ERR_WRONG_PARAMETER_ACC, - ERR_WRONG_PARAMETER_MID_ACC, - ERR_INVALID_REGISTER, - ERR_OUT_RANGE_NUMBER + ERR_OK = 0, + ERR_UNKNOWN, + ERR_UNKNOWN_OPCODE, + ERR_NOT_ENOUGH_PARAMETERS, + ERR_TOO_MANY_PARAMETERS, + ERR_WRONG_PARAMETER, + ERR_EXPECTED_PARAM_STR, + ERR_EXPECTED_PARAM_VAL, + ERR_EXPECTED_PARAM_REG, + ERR_EXPECTED_PARAM_MEM, + ERR_EXPECTED_PARAM_IMM, + ERR_INCORRECT_BIN, + ERR_INCORRECT_HEX, + ERR_INCORRECT_DEC, + ERR_LABEL_EXISTS, + ERR_UNKNOWN_LABEL, + ERR_NO_MATCHING_BRACKETS, + ERR_EXT_CANT_EXTEND_OPCODE, + ERR_EXT_PAR_NOT_EXT, + ERR_WRONG_PARAMETER_ACC, + ERR_WRONG_PARAMETER_MID_ACC, + ERR_INVALID_REGISTER, + ERR_OUT_RANGE_NUMBER }; - // Unless you want labels to carry over between files, you probably // want to create a new DSPAssembler for every file you assemble. class DSPAssembler { public: - DSPAssembler(const AssemblerSettings &settings); - ~DSPAssembler(); + DSPAssembler(const AssemblerSettings& settings); + ~DSPAssembler(); - // line_numbers is optional (and not yet implemented). It'll receieve a list of ints, - // one for each word of code, indicating the source assembler code line number it came from. + // line_numbers is optional (and not yet implemented). It'll receieve a list of ints, + // one for each word of code, indicating the source assembler code line number it came from. - // If returns false, call GetErrorString to get some text to present to the user. - bool Assemble(const std::string& text, std::vector &code, std::vector *line_numbers = nullptr); - - std::string GetErrorString() const { return last_error_str; } - err_t GetError() const { return last_error; } + // If returns false, call GetErrorString to get some text to present to the user. + bool Assemble(const std::string& text, std::vector& code, + std::vector* line_numbers = nullptr); + std::string GetErrorString() const { return last_error_str; } + err_t GetError() const { return last_error; } private: - struct param_t - { - u32 val; - partype_t type; - char *str; - }; + struct param_t + { + u32 val; + partype_t type; + char* str; + }; - enum segment_t - { - SEGMENT_CODE = 0, - SEGMENT_DATA, - SEGMENT_OVERLAY, - SEGMENT_MAX - }; + enum segment_t + { + SEGMENT_CODE = 0, + SEGMENT_DATA, + SEGMENT_OVERLAY, + SEGMENT_MAX + }; - // Utility functions - s32 ParseValue(const char *str); - u32 ParseExpression(const char *ptr); + // Utility functions + s32 ParseValue(const char* str); + u32 ParseExpression(const char* ptr); - u32 GetParams(char *parstr, param_t *par); + u32 GetParams(char* parstr, param_t* par); - void InitPass(int pass); - bool AssembleFile(const char *fname, int pass); + void InitPass(int pass); + bool AssembleFile(const char* fname, int pass); - void ShowError(err_t err_code, const char *extra_info = nullptr); - // void ShowWarning(err_t err_code, const char *extra_info = nullptr); + void ShowError(err_t err_code, const char* extra_info = nullptr); + // void ShowWarning(err_t err_code, const char *extra_info = nullptr); - char *FindBrackets(char *src, char *dst); - const opc_t *FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size); - bool VerifyParams(const opc_t *opc, param_t *par, int count, bool ext = false); - void BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf); + char* FindBrackets(char* src, char* dst); + const opc_t* FindOpcode(const char* opcode, u32 par_count, const opc_t* const opcod, + int opcod_size); + bool VerifyParams(const opc_t* opc, param_t* par, int count, bool ext = false); + void BuildCode(const opc_t* opc, param_t* par, u32 par_count, u16* outbuf); - char *gdg_buffer; + char* gdg_buffer; - std::string include_dir; - std::string cur_line; + std::string include_dir; + std::string cur_line; - u32 m_cur_addr; - int m_totalSize; - u8 m_cur_pass; + u32 m_cur_addr; + int m_totalSize; + u8 m_cur_pass; - LabelMap labels; + LabelMap labels; - u32 code_line; - bool failed; - std::string last_error_str; - err_t last_error; + u32 code_line; + bool failed; + std::string last_error_str; + err_t last_error; - typedef std::map AliasMap; - AliasMap aliases; + typedef std::map AliasMap; + AliasMap aliases; - segment_t cur_segment; - u32 segment_addr[SEGMENT_MAX]; - int m_current_param; - const AssemblerSettings settings_; + segment_t cur_segment; + u32 segment_addr[SEGMENT_MAX]; + int m_current_param; + const AssemblerSettings settings_; }; diff --git a/Source/Core/Core/DSP/DSPBreakpoints.h b/Source/Core/Core/DSP/DSPBreakpoints.h index ebaa0f53b3..5315861f5b 100644 --- a/Source/Core/Core/DSP/DSPBreakpoints.h +++ b/Source/Core/Core/DSP/DSPBreakpoints.h @@ -12,51 +12,35 @@ class DSPBreakpoints { public: - DSPBreakpoints() - { - Clear(); - } + DSPBreakpoints() { Clear(); } + // is address breakpoint + bool IsAddressBreakPoint(u32 addr) { return b[addr] != 0; } + // AddBreakPoint + bool Add(u32 addr, bool temp = false) + { + bool was_one = b[addr] != 0; - // is address breakpoint - bool IsAddressBreakPoint(u32 addr) - { - return b[addr] != 0; - } + if (!was_one) + { + b[addr] = temp ? 2 : 1; + return true; + } + else + { + return false; + } + } - // AddBreakPoint - bool Add(u32 addr, bool temp=false) - { - bool was_one = b[addr] != 0; - - if (!was_one) - { - b[addr] = temp ? 2 : 1; - return true; - } - else - { - return false; - } - } - - // Remove Breakpoint - bool Remove(u32 addr) - { - bool was_one = b[addr] != 0; - b[addr] = 0; - return was_one; - } - - void Clear() - { - memset(b, 0, sizeof(b)); - } - - void DeleteByAddress(u32 addr) - { - b[addr] = 0; - } + // Remove Breakpoint + bool Remove(u32 addr) + { + bool was_one = b[addr] != 0; + b[addr] = 0; + return was_one; + } + void Clear() { memset(b, 0, sizeof(b)); } + void DeleteByAddress(u32 addr) { b[addr] = 0; } private: - u8 b[65536]; + u8 b[65536]; }; diff --git a/Source/Core/Core/DSP/DSPCaptureLogger.cpp b/Source/Core/Core/DSP/DSPCaptureLogger.cpp index 66c3c6d09b..97710d54f8 100644 --- a/Source/Core/Core/DSP/DSPCaptureLogger.cpp +++ b/Source/Core/Core/DSP/DSPCaptureLogger.cpp @@ -19,25 +19,25 @@ const u8 DMA_PACKET_MAGIC = 1; #pragma pack(push, 1) struct IFXAccessPacket { - u8 magic; // IFX_ACCESS_PACKET_MAGIC - u8 is_read; // 0 for writes, 1 for reads. - u16 address; - u16 value; + u8 magic; // IFX_ACCESS_PACKET_MAGIC + u8 is_read; // 0 for writes, 1 for reads. + u16 address; + u16 value; }; // Followed by the bytes of the DMA. struct DMAPacket { - u8 magic; // DMA_PACKET_MAGIC - u16 dma_control; // Value of the DMA control register. - u32 gc_address; // Address in the GC RAM. - u16 dsp_address; // Address in the DSP RAM. - u16 length; // Length in bytes. + u8 magic; // DMA_PACKET_MAGIC + u16 dma_control; // Value of the DMA control register. + u32 gc_address; // Address in the GC RAM. + u16 dsp_address; // Address in the DSP RAM. + u16 length; // Length in bytes. }; #pragma pack(pop) PCAPDSPCaptureLogger::PCAPDSPCaptureLogger(const std::string& pcap_filename) - : m_pcap(new PCAP(new File::IOFile(pcap_filename, "wb"))) + : m_pcap(new PCAP(new File::IOFile(pcap_filename, "wb"))) { } @@ -45,36 +45,35 @@ PCAPDSPCaptureLogger::PCAPDSPCaptureLogger(PCAP* pcap) : m_pcap(pcap) { } -PCAPDSPCaptureLogger::PCAPDSPCaptureLogger(std::unique_ptr&& pcap) - : m_pcap(std::move(pcap)) +PCAPDSPCaptureLogger::PCAPDSPCaptureLogger(std::unique_ptr&& pcap) : m_pcap(std::move(pcap)) { } void PCAPDSPCaptureLogger::LogIFXAccess(bool read, u16 address, u16 value) { - IFXAccessPacket pkt; - pkt.magic = IFX_ACCESS_PACKET_MAGIC; - pkt.is_read = !!read; // Make sure we actually have 0/1. - pkt.address = address; - pkt.value = value; + IFXAccessPacket pkt; + pkt.magic = IFX_ACCESS_PACKET_MAGIC; + pkt.is_read = !!read; // Make sure we actually have 0/1. + pkt.address = address; + pkt.value = value; - m_pcap->AddPacket(pkt); + m_pcap->AddPacket(pkt); } -void PCAPDSPCaptureLogger::LogDMA(u16 control, u32 gc_address, u16 dsp_address, - u16 length, const u8* data) +void PCAPDSPCaptureLogger::LogDMA(u16 control, u32 gc_address, u16 dsp_address, u16 length, + const u8* data) { - // The length of a DMA cannot be above 64K, so we use a static buffer for - // the construction of the packet. - static u8 buffer[0x10000]; + // The length of a DMA cannot be above 64K, so we use a static buffer for + // the construction of the packet. + static u8 buffer[0x10000]; - DMAPacket* pkt = reinterpret_cast(&buffer[0]); - pkt->magic = DMA_PACKET_MAGIC; - pkt->dma_control = control; - pkt->gc_address = gc_address; - pkt->dsp_address = dsp_address; - pkt->length = length; - memcpy(&buffer[sizeof (DMAPacket)], data, length); + DMAPacket* pkt = reinterpret_cast(&buffer[0]); + pkt->magic = DMA_PACKET_MAGIC; + pkt->dma_control = control; + pkt->gc_address = gc_address; + pkt->dsp_address = dsp_address; + pkt->length = length; + memcpy(&buffer[sizeof(DMAPacket)], data, length); - m_pcap->AddPacket(buffer, sizeof (DMAPacket) + length); + m_pcap->AddPacket(buffer, sizeof(DMAPacket) + length); } diff --git a/Source/Core/Core/DSP/DSPCaptureLogger.h b/Source/Core/Core/DSP/DSPCaptureLogger.h index 79e97cf8a8..c5bcbbb81f 100644 --- a/Source/Core/Core/DSP/DSPCaptureLogger.h +++ b/Source/Core/Core/DSP/DSPCaptureLogger.h @@ -20,21 +20,19 @@ class PCAP; class DSPCaptureLogger { public: - virtual ~DSPCaptureLogger() {} + virtual ~DSPCaptureLogger() {} + // Accesses (reads or writes) to memory mapped registers (external + // interface, also known as IFX). These are always 16 bits accesses. + virtual void LogIFXRead(u16 address, u16 read_value) = 0; + virtual void LogIFXWrite(u16 address, u16 written_value) = 0; - // Accesses (reads or writes) to memory mapped registers (external - // interface, also known as IFX). These are always 16 bits accesses. - virtual void LogIFXRead(u16 address, u16 read_value) = 0; - virtual void LogIFXWrite(u16 address, u16 written_value) = 0; - - // DMAs to/from main memory from/to DSP memory. We let the interpretation - // of the "control" field to the layer that analyze the logs and do not - // perform our own interpretation of it. Thus there is only one call which - // is used for DRAM/IRAM in any direction (to/from DSP). - // - // Length is expressed in bytes, not DSP words. - virtual void LogDMA(u16 control, u32 gc_address, u16 dsp_address, - u16 length, const u8* data) = 0; + // DMAs to/from main memory from/to DSP memory. We let the interpretation + // of the "control" field to the layer that analyze the logs and do not + // perform our own interpretation of it. Thus there is only one call which + // is used for DRAM/IRAM in any direction (to/from DSP). + // + // Length is expressed in bytes, not DSP words. + virtual void LogDMA(u16 control, u32 gc_address, u16 dsp_address, u16 length, const u8* data) = 0; }; // A dummy implementation of a capture logger that does nothing. This is the @@ -44,10 +42,9 @@ public: class DefaultDSPCaptureLogger : public DSPCaptureLogger { public: - void LogIFXRead(u16 address, u16 read_value) override {} - void LogIFXWrite(u16 address, u16 written_value) override {} - void LogDMA(u16 control, u32 gc_address, u16 dsp_address, - u16 length, const u8* data) override {} + void LogIFXRead(u16 address, u16 read_value) override {} + void LogIFXWrite(u16 address, u16 written_value) override {} + void LogDMA(u16 control, u32 gc_address, u16 dsp_address, u16 length, const u8* data) override {} }; // A capture logger implementation that logs to PCAP files in a custom @@ -55,25 +52,21 @@ public: class PCAPDSPCaptureLogger final : public DSPCaptureLogger, NonCopyable { public: - // Automatically creates a writeable file (truncate existing file). - PCAPDSPCaptureLogger(const std::string& pcap_filename); - // Takes ownership of pcap. - PCAPDSPCaptureLogger(PCAP* pcap); - PCAPDSPCaptureLogger(std::unique_ptr&& pcap); + // Automatically creates a writeable file (truncate existing file). + PCAPDSPCaptureLogger(const std::string& pcap_filename); + // Takes ownership of pcap. + PCAPDSPCaptureLogger(PCAP* pcap); + PCAPDSPCaptureLogger(std::unique_ptr&& pcap); - void LogIFXRead(u16 address, u16 read_value) override - { - LogIFXAccess(true, address, read_value); - } - void LogIFXWrite(u16 address, u16 written_value) override - { - LogIFXAccess(false, address, written_value); - } - void LogDMA(u16 control, u32 gc_address, u16 dsp_address, - u16 length, const u8* data) override; + void LogIFXRead(u16 address, u16 read_value) override { LogIFXAccess(true, address, read_value); } + void LogIFXWrite(u16 address, u16 written_value) override + { + LogIFXAccess(false, address, written_value); + } + void LogDMA(u16 control, u32 gc_address, u16 dsp_address, u16 length, const u8* data) override; private: - void LogIFXAccess(bool read, u16 address, u16 value); + void LogIFXAccess(bool read, u16 address, u16 value); - std::unique_ptr m_pcap; + std::unique_ptr m_pcap; }; diff --git a/Source/Core/Core/DSP/DSPCodeUtil.cpp b/Source/Core/Core/DSP/DSPCodeUtil.cpp index 3078948be7..9136b46ec4 100644 --- a/Source/Core/Core/DSP/DSPCodeUtil.cpp +++ b/Source/Core/Core/DSP/DSPCodeUtil.cpp @@ -15,202 +15,204 @@ #include "Core/DSP/DSPCodeUtil.h" #include "Core/DSP/DSPDisassembler.h" -bool Assemble(const std::string& text, std::vector &code, bool force) +bool Assemble(const std::string& text, std::vector& code, bool force) { - AssemblerSettings settings; - // settings.pc = 0; - // settings.decode_registers = false; - // settings.decode_names = false; - settings.force = force; - // settings.print_tabs = false; - // settings.ext_separator = '\''; + AssemblerSettings settings; + // settings.pc = 0; + // settings.decode_registers = false; + // settings.decode_names = false; + settings.force = force; + // settings.print_tabs = false; + // settings.ext_separator = '\''; - // TODO: fix the terrible api of the assembler. - DSPAssembler assembler(settings); - if (!assembler.Assemble(text, code)) - { - std::cerr << assembler.GetErrorString() << std::endl; - return false; - } + // TODO: fix the terrible api of the assembler. + DSPAssembler assembler(settings); + if (!assembler.Assemble(text, code)) + { + std::cerr << assembler.GetErrorString() << std::endl; + return false; + } - return true; + return true; } -bool Disassemble(const std::vector &code, bool line_numbers, std::string &text) +bool Disassemble(const std::vector& code, bool line_numbers, std::string& text) { - if (code.empty()) - return false; + if (code.empty()) + return false; - AssemblerSettings settings; + AssemblerSettings settings; - // These two prevent roundtripping. - settings.show_hex = true; - settings.show_pc = line_numbers; - settings.ext_separator = '\''; - settings.decode_names = true; - settings.decode_registers = true; + // These two prevent roundtripping. + settings.show_hex = true; + settings.show_pc = line_numbers; + settings.ext_separator = '\''; + settings.decode_names = true; + settings.decode_registers = true; - DSPDisassembler disasm(settings); - bool success = disasm.Disassemble(0, code, 0x0000, text); - return success; + DSPDisassembler disasm(settings); + bool success = disasm.Disassemble(0, code, 0x0000, text); + return success; } -bool Compare(const std::vector &code1, const std::vector &code2) +bool Compare(const std::vector& code1, const std::vector& code2) { - if (code1.size() != code2.size()) - printf("Size difference! 1=%zu 2=%zu\n", code1.size(), code2.size()); - u32 count_equal = 0; - const int min_size = std::min((int)code1.size(), (int)code2.size()); + if (code1.size() != code2.size()) + printf("Size difference! 1=%zu 2=%zu\n", code1.size(), code2.size()); + u32 count_equal = 0; + const int min_size = std::min((int)code1.size(), (int)code2.size()); - AssemblerSettings settings; - DSPDisassembler disassembler(settings); - for (int i = 0; i < min_size; i++) - { - if (code1[i] == code2[i]) - { - count_equal++; - } - else - { - std::string line1, line2; - u16 pc = i; - disassembler.DisassembleOpcode(&code1[0], 0x0000, 2, &pc, line1); - pc = i; - disassembler.DisassembleOpcode(&code2[0], 0x0000, 2, &pc, line2); - printf("!! %04x : %04x vs %04x - %s vs %s\n", i, code1[i], code2[i], line1.c_str(), line2.c_str()); - } - } - if (code2.size() != code1.size()) - { - printf("Extra code words:\n"); - const std::vector &longest = code1.size() > code2.size() ? code1 : code2; - for (int i = min_size; i < (int)longest.size(); i++) - { - u16 pc = i; - std::string line; - disassembler.DisassembleOpcode(&longest[0], 0x0000, 2, &pc, line); - printf("!! %s\n", line.c_str()); - } - } - printf("Equal instruction words: %i / %i\n", count_equal, min_size); - return code1.size() == code2.size() && code1.size() == count_equal; + AssemblerSettings settings; + DSPDisassembler disassembler(settings); + for (int i = 0; i < min_size; i++) + { + if (code1[i] == code2[i]) + { + count_equal++; + } + else + { + std::string line1, line2; + u16 pc = i; + disassembler.DisassembleOpcode(&code1[0], 0x0000, 2, &pc, line1); + pc = i; + disassembler.DisassembleOpcode(&code2[0], 0x0000, 2, &pc, line2); + printf("!! %04x : %04x vs %04x - %s vs %s\n", i, code1[i], code2[i], line1.c_str(), + line2.c_str()); + } + } + if (code2.size() != code1.size()) + { + printf("Extra code words:\n"); + const std::vector& longest = code1.size() > code2.size() ? code1 : code2; + for (int i = min_size; i < (int)longest.size(); i++) + { + u16 pc = i; + std::string line; + disassembler.DisassembleOpcode(&longest[0], 0x0000, 2, &pc, line); + printf("!! %s\n", line.c_str()); + } + } + printf("Equal instruction words: %i / %i\n", count_equal, min_size); + return code1.size() == code2.size() && code1.size() == count_equal; } -void GenRandomCode(u32 size, std::vector &code) +void GenRandomCode(u32 size, std::vector& code) { - code.resize(size); - for (u32 i = 0; i < size; i++) - { - code[i] = rand() ^ (rand() << 8); - } + code.resize(size); + for (u32 i = 0; i < size; i++) + { + code[i] = rand() ^ (rand() << 8); + } } -void CodeToHeader(const std::vector &code, std::string _filename, - const char *name, std::string &header) +void CodeToHeader(const std::vector& code, std::string _filename, const char* name, + std::string& header) { - std::vector code_padded = code; - // Pad with nops to 32byte boundary - while (code_padded.size() & 0x7f) - code_padded.push_back(0); - header.clear(); - header.reserve(code_padded.size() * 4); - header.append("#define NUM_UCODES 1\n\n"); - std::string filename; - SplitPath(_filename, nullptr, &filename, nullptr); - header.append(StringFromFormat("const char* UCODE_NAMES[NUM_UCODES] = {\"%s\"};\n\n", filename.c_str())); - header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] = {\n"); + std::vector code_padded = code; + // Pad with nops to 32byte boundary + while (code_padded.size() & 0x7f) + code_padded.push_back(0); + header.clear(); + header.reserve(code_padded.size() * 4); + header.append("#define NUM_UCODES 1\n\n"); + std::string filename; + SplitPath(_filename, nullptr, &filename, nullptr); + header.append( + StringFromFormat("const char* UCODE_NAMES[NUM_UCODES] = {\"%s\"};\n\n", filename.c_str())); + header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] = {\n"); - header.append("\t{\n\t\t"); - for (u32 j = 0; j < code_padded.size(); j++) - { - if (j && ((j & 15) == 0)) - header.append("\n\t\t"); - header.append(StringFromFormat("0x%04x, ", code_padded[j])); - } - header.append("\n\t},\n"); + header.append("\t{\n\t\t"); + for (u32 j = 0; j < code_padded.size(); j++) + { + if (j && ((j & 15) == 0)) + header.append("\n\t\t"); + header.append(StringFromFormat("0x%04x, ", code_padded[j])); + } + header.append("\n\t},\n"); - header.append("};\n"); + header.append("};\n"); } -void CodesToHeader(const std::vector *codes, const std::vector* filenames, - u32 numCodes, const char *name, std::string &header) +void CodesToHeader(const std::vector* codes, const std::vector* filenames, + u32 numCodes, const char* name, std::string& header) { - std::vector > codes_padded; - u32 reserveSize = 0; - for (u32 i = 0; i < numCodes; i++) - { - codes_padded.push_back(codes[i]); - // Pad with nops to 32byte boundary - while (codes_padded.at(i).size() & 0x7f) - codes_padded.at(i).push_back(0); + std::vector> codes_padded; + u32 reserveSize = 0; + for (u32 i = 0; i < numCodes; i++) + { + codes_padded.push_back(codes[i]); + // Pad with nops to 32byte boundary + while (codes_padded.at(i).size() & 0x7f) + codes_padded.at(i).push_back(0); - reserveSize += (u32)codes_padded.at(i).size(); - } - header.clear(); - header.reserve(reserveSize * 4); - header.append(StringFromFormat("#define NUM_UCODES %u\n\n", numCodes)); - header.append("const char* UCODE_NAMES[NUM_UCODES] = {\n"); - for (u32 i = 0; i < numCodes; i++) - { - std::string filename; - if (! SplitPath(filenames->at(i), nullptr, &filename, nullptr)) - filename = filenames->at(i); - header.append(StringFromFormat("\t\"%s\",\n", filename.c_str())); - } - header.append("};\n\n"); - header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] = {\n"); + reserveSize += (u32)codes_padded.at(i).size(); + } + header.clear(); + header.reserve(reserveSize * 4); + header.append(StringFromFormat("#define NUM_UCODES %u\n\n", numCodes)); + header.append("const char* UCODE_NAMES[NUM_UCODES] = {\n"); + for (u32 i = 0; i < numCodes; i++) + { + std::string filename; + if (!SplitPath(filenames->at(i), nullptr, &filename, nullptr)) + filename = filenames->at(i); + header.append(StringFromFormat("\t\"%s\",\n", filename.c_str())); + } + header.append("};\n\n"); + header.append("const unsigned short dsp_code[NUM_UCODES][0x1000] = {\n"); - for (u32 i = 0; i < numCodes; i++) - { - if (codes[i].size() == 0) - continue; + for (u32 i = 0; i < numCodes; i++) + { + if (codes[i].size() == 0) + continue; - header.append("\t{\n\t\t"); - for (u32 j = 0; j < codes_padded.at(i).size(); j++) - { - if (j && ((j & 15) == 0)) - header.append("\n\t\t"); - header.append(StringFromFormat("0x%04x, ", codes_padded.at(i).at(j))); - } - header.append("\n\t},\n"); - } - header.append("};\n"); + header.append("\t{\n\t\t"); + for (u32 j = 0; j < codes_padded.at(i).size(); j++) + { + if (j && ((j & 15) == 0)) + header.append("\n\t\t"); + header.append(StringFromFormat("0x%04x, ", codes_padded.at(i).at(j))); + } + header.append("\n\t},\n"); + } + header.append("};\n"); } -void CodeToBinaryStringBE(const std::vector &code, std::string &str) +void CodeToBinaryStringBE(const std::vector& code, std::string& str) { - str.resize(code.size() * 2); - for (size_t i = 0; i < code.size(); i++) - { - str[i * 2 + 0] = code[i] >> 8; - str[i * 2 + 1] = code[i] & 0xff; - } + str.resize(code.size() * 2); + for (size_t i = 0; i < code.size(); i++) + { + str[i * 2 + 0] = code[i] >> 8; + str[i * 2 + 1] = code[i] & 0xff; + } } -void BinaryStringBEToCode(const std::string &str, std::vector &code) +void BinaryStringBEToCode(const std::string& str, std::vector& code) { - code.resize(str.size() / 2); - for (size_t i = 0; i < code.size(); i++) - { - code[i] = ((u16)(u8)str[i * 2 + 0] << 8) | ((u16)(u8)str[i * 2 + 1]); - } + code.resize(str.size() / 2); + for (size_t i = 0; i < code.size(); i++) + { + code[i] = ((u16)(u8)str[i * 2 + 0] << 8) | ((u16)(u8)str[i * 2 + 1]); + } } -bool LoadBinary(const std::string& filename, std::vector &code) +bool LoadBinary(const std::string& filename, std::vector& code) { - std::string buffer; - if (!File::ReadFileToString(filename, buffer)) - return false; + std::string buffer; + if (!File::ReadFileToString(filename, buffer)) + return false; - BinaryStringBEToCode(buffer, code); - return true; + BinaryStringBEToCode(buffer, code); + return true; } -bool SaveBinary(const std::vector &code, const std::string& filename) +bool SaveBinary(const std::vector& code, const std::string& filename) { - std::string buffer; - CodeToBinaryStringBE(code, buffer); - if (!File::WriteStringToFile(buffer, filename)) - return false; - return true; + std::string buffer; + CodeToBinaryStringBE(code, buffer); + if (!File::WriteStringToFile(buffer, filename)) + return false; + return true; } diff --git a/Source/Core/Core/DSP/DSPCodeUtil.h b/Source/Core/Core/DSP/DSPCodeUtil.h index 4117f814f4..cab0d73ce0 100644 --- a/Source/Core/Core/DSP/DSPCodeUtil.h +++ b/Source/Core/Core/DSP/DSPCodeUtil.h @@ -9,19 +9,19 @@ #include "Common/CommonTypes.h" -bool Assemble(const std::string& text, std::vector &code, bool force = false); -bool Disassemble(const std::vector &code, bool line_numbers, std::string &text); -bool Compare(const std::vector &code1, const std::vector &code2); -void GenRandomCode(u32 size, std::vector &code); -void CodeToHeader(const std::vector &code, std::string _filename, - const char *name, std::string &header); -void CodesToHeader(const std::vector *codes, const std::vector *filenames, - u32 numCodes, const char *name, std::string &header); +bool Assemble(const std::string& text, std::vector& code, bool force = false); +bool Disassemble(const std::vector& code, bool line_numbers, std::string& text); +bool Compare(const std::vector& code1, const std::vector& code2); +void GenRandomCode(u32 size, std::vector& code); +void CodeToHeader(const std::vector& code, std::string _filename, const char* name, + std::string& header); +void CodesToHeader(const std::vector* codes, const std::vector* filenames, + u32 numCodes, const char* name, std::string& header); // Big-endian, for writing straight to file using File::WriteStringToFile. -void CodeToBinaryStringBE(const std::vector &code, std::string &str); -void BinaryStringBEToCode(const std::string &str, std::vector &code); +void CodeToBinaryStringBE(const std::vector& code, std::string& str); +void BinaryStringBEToCode(const std::string& str, std::vector& code); // Load code (big endian binary). -bool LoadBinary(const std::string& filename, std::vector &code); -bool SaveBinary(const std::vector &code, const std::string& filename); +bool LoadBinary(const std::string& filename, std::vector& code); +bool SaveBinary(const std::vector& code, const std::string& filename); diff --git a/Source/Core/Core/DSP/DSPCore.cpp b/Source/Core/Core/DSP/DSPCore.cpp index ea2ad8e471..8c69e4e82d 100644 --- a/Source/Core/Core/DSP/DSPCore.cpp +++ b/Source/Core/Core/DSP/DSPCore.cpp @@ -17,10 +17,10 @@ #include "Core/DSP/DSPAnalyzer.h" #include "Core/DSP/DSPCore.h" #include "Core/DSP/DSPEmitter.h" -#include "Core/DSP/DSPHost.h" #include "Core/DSP/DSPHWInterface.h" -#include "Core/DSP/DSPInterpreter.h" +#include "Core/DSP/DSPHost.h" #include "Core/DSP/DSPIntUtil.h" +#include "Core/DSP/DSPInterpreter.h" SDSP g_dsp; DSPBreakpoints g_dsp_breakpoints; @@ -34,409 +34,425 @@ static Common::Event step_event; // Returns false if the hash fails and the user hits "Yes" static bool VerifyRoms() { - struct DspRomHashes - { - u32 hash_irom; // dsp_rom.bin - u32 hash_drom; // dsp_coef.bin - }; + struct DspRomHashes + { + u32 hash_irom; // dsp_rom.bin + u32 hash_drom; // dsp_coef.bin + }; - static const std::array known_roms = {{ - // Official Nintendo ROM - { 0x66f334fe, 0xf3b93527 }, + static const std::array known_roms = { + {// Official Nintendo ROM + {0x66f334fe, 0xf3b93527}, - // LM1234 replacement ROM (Zelda UCode only) - { 0x9c8f593c, 0x10000001 }, + // LM1234 replacement ROM (Zelda UCode only) + {0x9c8f593c, 0x10000001}, - // delroth's improvement on LM1234 replacement ROM (Zelda and AX only, - // IPL/Card/GBA still broken) - { 0xd9907f71, 0xb019c2fb }, + // delroth's improvement on LM1234 replacement ROM (Zelda and AX only, + // IPL/Card/GBA still broken) + {0xd9907f71, 0xb019c2fb}, - // above with improved resampling coefficients - { 0xd9907f71, 0xdb6880c1 } - }}; + // above with improved resampling coefficients + {0xd9907f71, 0xdb6880c1}}}; - u32 hash_irom = HashAdler32((u8*)g_dsp.irom, DSP_IROM_BYTE_SIZE); - u32 hash_drom = HashAdler32((u8*)g_dsp.coef, DSP_COEF_BYTE_SIZE); - int rom_idx = -1; + u32 hash_irom = HashAdler32((u8*)g_dsp.irom, DSP_IROM_BYTE_SIZE); + u32 hash_drom = HashAdler32((u8*)g_dsp.coef, DSP_COEF_BYTE_SIZE); + int rom_idx = -1; - for (size_t i = 0; i < known_roms.size(); ++i) - { - const DspRomHashes& rom = known_roms[i]; - if (hash_irom == rom.hash_irom && hash_drom == rom.hash_drom) - rom_idx = static_cast(i); - } + for (size_t i = 0; i < known_roms.size(); ++i) + { + const DspRomHashes& rom = known_roms[i]; + if (hash_irom == rom.hash_irom && hash_drom == rom.hash_drom) + rom_idx = static_cast(i); + } - if (rom_idx < 0) - { - if (AskYesNoT("Your DSP ROMs have incorrect hashes.\n" - "Would you like to stop now to fix the problem?\n" - "If you select \"No\", audio might be garbled.")) - return false; - } + if (rom_idx < 0) + { + if (AskYesNoT("Your DSP ROMs have incorrect hashes.\n" + "Would you like to stop now to fix the problem?\n" + "If you select \"No\", audio might be garbled.")) + return false; + } - if (rom_idx == 1) - { - DSPHost::OSD_AddMessage("You are using an old free DSP ROM made by the Dolphin Team.", 6000); - DSPHost::OSD_AddMessage("Only games using the Zelda UCode will work correctly.", 6000); - } - else if (rom_idx == 2 || rom_idx == 3) - { - DSPHost::OSD_AddMessage("You are using a free DSP ROM made by the Dolphin Team.", 8000); - DSPHost::OSD_AddMessage("All Wii games will work correctly, and most GC games should ", 8000); - DSPHost::OSD_AddMessage("also work fine, but the GBA/IPL/CARD UCodes will not work.\n", 8000); - } + if (rom_idx == 1) + { + DSPHost::OSD_AddMessage("You are using an old free DSP ROM made by the Dolphin Team.", 6000); + DSPHost::OSD_AddMessage("Only games using the Zelda UCode will work correctly.", 6000); + } + else if (rom_idx == 2 || rom_idx == 3) + { + DSPHost::OSD_AddMessage("You are using a free DSP ROM made by the Dolphin Team.", 8000); + DSPHost::OSD_AddMessage("All Wii games will work correctly, and most GC games should ", 8000); + DSPHost::OSD_AddMessage("also work fine, but the GBA/IPL/CARD UCodes will not work.\n", 8000); + } - return true; + return true; } static void DSPCore_FreeMemoryPages() { - FreeMemoryPages(g_dsp.irom, DSP_IROM_BYTE_SIZE); - FreeMemoryPages(g_dsp.iram, DSP_IRAM_BYTE_SIZE); - FreeMemoryPages(g_dsp.dram, DSP_DRAM_BYTE_SIZE); - FreeMemoryPages(g_dsp.coef, DSP_COEF_BYTE_SIZE); - g_dsp.irom = g_dsp.iram = g_dsp.dram = g_dsp.coef = nullptr; + FreeMemoryPages(g_dsp.irom, DSP_IROM_BYTE_SIZE); + FreeMemoryPages(g_dsp.iram, DSP_IRAM_BYTE_SIZE); + FreeMemoryPages(g_dsp.dram, DSP_DRAM_BYTE_SIZE); + FreeMemoryPages(g_dsp.coef, DSP_COEF_BYTE_SIZE); + g_dsp.irom = g_dsp.iram = g_dsp.dram = g_dsp.coef = nullptr; } bool DSPCore_Init(const DSPInitOptions& opts) { - g_dsp.step_counter = 0; - g_cycles_left = 0; - g_init_hax = false; + g_dsp.step_counter = 0; + g_cycles_left = 0; + g_init_hax = false; - g_dsp.irom = (u16*)AllocateMemoryPages(DSP_IROM_BYTE_SIZE); - g_dsp.iram = (u16*)AllocateMemoryPages(DSP_IRAM_BYTE_SIZE); - g_dsp.dram = (u16*)AllocateMemoryPages(DSP_DRAM_BYTE_SIZE); - g_dsp.coef = (u16*)AllocateMemoryPages(DSP_COEF_BYTE_SIZE); + g_dsp.irom = (u16*)AllocateMemoryPages(DSP_IROM_BYTE_SIZE); + g_dsp.iram = (u16*)AllocateMemoryPages(DSP_IRAM_BYTE_SIZE); + g_dsp.dram = (u16*)AllocateMemoryPages(DSP_DRAM_BYTE_SIZE); + g_dsp.coef = (u16*)AllocateMemoryPages(DSP_COEF_BYTE_SIZE); - memcpy(g_dsp.irom, opts.irom_contents.data(), DSP_IROM_BYTE_SIZE); - memcpy(g_dsp.coef, opts.coef_contents.data(), DSP_COEF_BYTE_SIZE); + memcpy(g_dsp.irom, opts.irom_contents.data(), DSP_IROM_BYTE_SIZE); + memcpy(g_dsp.coef, opts.coef_contents.data(), DSP_COEF_BYTE_SIZE); - // Try to load real ROM contents. - if (!VerifyRoms()) - { - DSPCore_FreeMemoryPages(); - return false; - } + // Try to load real ROM contents. + if (!VerifyRoms()) + { + DSPCore_FreeMemoryPages(); + return false; + } - memset(&g_dsp.r,0,sizeof(g_dsp.r)); + memset(&g_dsp.r, 0, sizeof(g_dsp.r)); - std::fill(std::begin(g_dsp.reg_stack_ptr), std::end(g_dsp.reg_stack_ptr), 0); + std::fill(std::begin(g_dsp.reg_stack_ptr), std::end(g_dsp.reg_stack_ptr), 0); - for (size_t i = 0; i < ArraySize(g_dsp.reg_stack); i++) - std::fill(std::begin(g_dsp.reg_stack[i]), std::end(g_dsp.reg_stack[i]), 0); + for (size_t i = 0; i < ArraySize(g_dsp.reg_stack); i++) + std::fill(std::begin(g_dsp.reg_stack[i]), std::end(g_dsp.reg_stack[i]), 0); - // Fill IRAM with HALT opcodes. - std::fill(g_dsp.iram, g_dsp.iram + DSP_IRAM_SIZE, 0x0021); + // Fill IRAM with HALT opcodes. + std::fill(g_dsp.iram, g_dsp.iram + DSP_IRAM_SIZE, 0x0021); - // Just zero out DRAM. - std::fill(g_dsp.dram, g_dsp.dram + DSP_DRAM_SIZE, 0); + // Just zero out DRAM. + std::fill(g_dsp.dram, g_dsp.dram + DSP_DRAM_SIZE, 0); - // Copied from a real console after the custom UCode has been loaded. - // These are the indexing wrapping registers. - std::fill(std::begin(g_dsp.r.wr), std::end(g_dsp.r.wr), 0xffff); + // Copied from a real console after the custom UCode has been loaded. + // These are the indexing wrapping registers. + std::fill(std::begin(g_dsp.r.wr), std::end(g_dsp.r.wr), 0xffff); - g_dsp.r.sr |= SR_INT_ENABLE; - g_dsp.r.sr |= SR_EXT_INT_ENABLE; + g_dsp.r.sr |= SR_INT_ENABLE; + g_dsp.r.sr |= SR_EXT_INT_ENABLE; - g_dsp.cr = 0x804; - gdsp_ifx_init(); - // Mostly keep IRAM write protected. We unprotect only when DMA-ing - // in new ucodes. - WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); + g_dsp.cr = 0x804; + gdsp_ifx_init(); + // Mostly keep IRAM write protected. We unprotect only when DMA-ing + // in new ucodes. + WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); - // Initialize JIT, if necessary - if (opts.core_type == DSPInitOptions::CORE_JIT) - g_dsp_jit = std::make_unique(); + // Initialize JIT, if necessary + if (opts.core_type == DSPInitOptions::CORE_JIT) + g_dsp_jit = std::make_unique(); - g_dsp_cap.reset(opts.capture_logger); + g_dsp_cap.reset(opts.capture_logger); - core_state = DSPCORE_RUNNING; - return true; + core_state = DSPCORE_RUNNING; + return true; } void DSPCore_Shutdown() { - if (core_state == DSPCORE_STOP) - return; + if (core_state == DSPCORE_STOP) + return; - core_state = DSPCORE_STOP; + core_state = DSPCORE_STOP; - g_dsp_jit.reset(); + g_dsp_jit.reset(); - DSPCore_FreeMemoryPages(); + DSPCore_FreeMemoryPages(); - g_dsp_cap.reset(); + g_dsp_cap.reset(); } void DSPCore_Reset() { - g_dsp.pc = DSP_RESET_VECTOR; + g_dsp.pc = DSP_RESET_VECTOR; - std::fill(std::begin(g_dsp.r.wr), std::end(g_dsp.r.wr), 0xffff); + std::fill(std::begin(g_dsp.r.wr), std::end(g_dsp.r.wr), 0xffff); - DSPAnalyzer::Analyze(); + DSPAnalyzer::Analyze(); } void DSPCore_SetException(u8 level) { - g_dsp.exceptions |= 1 << level; + g_dsp.exceptions |= 1 << level; } // Notify that an external interrupt is pending (used by thread mode) void DSPCore_SetExternalInterrupt(bool val) { - g_dsp.external_interrupt_waiting = val; + g_dsp.external_interrupt_waiting = val; } // Coming from the CPU void DSPCore_CheckExternalInterrupt() { - if (! dsp_SR_is_flag_set(SR_EXT_INT_ENABLE)) - return; + if (!dsp_SR_is_flag_set(SR_EXT_INT_ENABLE)) + return; - // Signal the SPU about new mail - DSPCore_SetException(EXP_INT); + // Signal the SPU about new mail + DSPCore_SetException(EXP_INT); - g_dsp.cr &= ~CR_EXTERNAL_INT; + g_dsp.cr &= ~CR_EXTERNAL_INT; } - void DSPCore_CheckExceptions() { - // Early out to skip the loop in the common case. - if (g_dsp.exceptions == 0) - return; + // Early out to skip the loop in the common case. + if (g_dsp.exceptions == 0) + return; - for (int i = 7; i > 0; i--) - { - // Seems exp int are not masked by sr_int_enable - if (g_dsp.exceptions & (1 << i)) - { - if (dsp_SR_is_flag_set(SR_INT_ENABLE) || (i == EXP_INT)) - { - // store pc and sr until RTI - dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); - dsp_reg_store_stack(DSP_STACK_D, g_dsp.r.sr); + for (int i = 7; i > 0; i--) + { + // Seems exp int are not masked by sr_int_enable + if (g_dsp.exceptions & (1 << i)) + { + if (dsp_SR_is_flag_set(SR_INT_ENABLE) || (i == EXP_INT)) + { + // store pc and sr until RTI + dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); + dsp_reg_store_stack(DSP_STACK_D, g_dsp.r.sr); - g_dsp.pc = i * 2; - g_dsp.exceptions &= ~(1 << i); - if (i == 7) - g_dsp.r.sr &= ~SR_EXT_INT_ENABLE; - else - g_dsp.r.sr &= ~SR_INT_ENABLE; - break; - } - else - { + g_dsp.pc = i * 2; + g_dsp.exceptions &= ~(1 << i); + if (i == 7) + g_dsp.r.sr &= ~SR_EXT_INT_ENABLE; + else + g_dsp.r.sr &= ~SR_INT_ENABLE; + break; + } + else + { #if defined(_DEBUG) || defined(DEBUGFAST) - ERROR_LOG(DSPLLE, "Firing exception %d failed", i); + ERROR_LOG(DSPLLE, "Firing exception %d failed", i); #endif - } - } - } + } + } + } } // Delegate to JIT or interpreter as appropriate. // Handle state changes and stepping. int DSPCore_RunCycles(int cycles) { - if (g_dsp_jit) - { - if (g_dsp.external_interrupt_waiting) - { - DSPCore_CheckExternalInterrupt(); - DSPCore_CheckExceptions(); - DSPCore_SetExternalInterrupt(false); - } + if (g_dsp_jit) + { + if (g_dsp.external_interrupt_waiting) + { + DSPCore_CheckExternalInterrupt(); + DSPCore_CheckExceptions(); + DSPCore_SetExternalInterrupt(false); + } - g_cycles_left = cycles; - DSPCompiledCode pExecAddr = (DSPCompiledCode)g_dsp_jit->enterDispatcher; - pExecAddr(); + g_cycles_left = cycles; + DSPCompiledCode pExecAddr = (DSPCompiledCode)g_dsp_jit->enterDispatcher; + pExecAddr(); - if (g_dsp.reset_dspjit_codespace) - g_dsp_jit->ClearIRAMandDSPJITCodespaceReset(); + if (g_dsp.reset_dspjit_codespace) + g_dsp_jit->ClearIRAMandDSPJITCodespaceReset(); - return g_cycles_left; - } + return g_cycles_left; + } - while (cycles > 0) - { - switch (core_state) - { - case DSPCORE_RUNNING: - // Seems to slow things down + while (cycles > 0) + { + switch (core_state) + { + case DSPCORE_RUNNING: +// Seems to slow things down #if defined(_DEBUG) || defined(DEBUGFAST) - cycles = DSPInterpreter::RunCyclesDebug(cycles); + cycles = DSPInterpreter::RunCyclesDebug(cycles); #else - cycles = DSPInterpreter::RunCycles(cycles); + cycles = DSPInterpreter::RunCycles(cycles); #endif - break; + break; - case DSPCORE_STEPPING: - step_event.Wait(); - if (core_state != DSPCORE_STEPPING) - continue; + case DSPCORE_STEPPING: + step_event.Wait(); + if (core_state != DSPCORE_STEPPING) + continue; - DSPInterpreter::Step(); - cycles--; + DSPInterpreter::Step(); + cycles--; - DSPHost::UpdateDebugger(); - break; - case DSPCORE_STOP: - break; - } - } - return cycles; + DSPHost::UpdateDebugger(); + break; + case DSPCORE_STOP: + break; + } + } + return cycles; } void DSPCore_SetState(DSPCoreState new_state) { - core_state = new_state; - // kick the event, in case we are waiting - if (new_state == DSPCORE_RUNNING) - step_event.Set(); - // Sleep(10); - DSPHost::UpdateDebugger(); + core_state = new_state; + // kick the event, in case we are waiting + if (new_state == DSPCORE_RUNNING) + step_event.Set(); + // Sleep(10); + DSPHost::UpdateDebugger(); } DSPCoreState DSPCore_GetState() { - return core_state; + return core_state; } void DSPCore_Step() { - if (core_state == DSPCORE_STEPPING) - step_event.Set(); + if (core_state == DSPCORE_STEPPING) + step_event.Set(); } void CompileCurrent() { - g_dsp_jit->Compile(g_dsp.pc); + g_dsp_jit->Compile(g_dsp.pc); - bool retry = true; + bool retry = true; - while (retry) - { - retry = false; - for (u16 i = 0x0000; i < 0xffff; ++i) - { - if (!g_dsp_jit->unresolvedJumps[i].empty()) - { - u16 addrToCompile = g_dsp_jit->unresolvedJumps[i].front(); - g_dsp_jit->Compile(addrToCompile); - if (!g_dsp_jit->unresolvedJumps[i].empty()) - retry = true; - } - } - } + while (retry) + { + retry = false; + for (u16 i = 0x0000; i < 0xffff; ++i) + { + if (!g_dsp_jit->unresolvedJumps[i].empty()) + { + u16 addrToCompile = g_dsp_jit->unresolvedJumps[i].front(); + g_dsp_jit->Compile(addrToCompile); + if (!g_dsp_jit->unresolvedJumps[i].empty()) + retry = true; + } + } + } } u16 DSPCore_ReadRegister(int reg) { - switch (reg) - { - case DSP_REG_AR0: - case DSP_REG_AR1: - case DSP_REG_AR2: - case DSP_REG_AR3: - return g_dsp.r.ar[reg - DSP_REG_AR0]; - case DSP_REG_IX0: - case DSP_REG_IX1: - case DSP_REG_IX2: - case DSP_REG_IX3: - return g_dsp.r.ix[reg - DSP_REG_IX0]; - case DSP_REG_WR0: - case DSP_REG_WR1: - case DSP_REG_WR2: - case DSP_REG_WR3: - return g_dsp.r.wr[reg - DSP_REG_WR0]; - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - return g_dsp.r.st[reg - DSP_REG_ST0]; - case DSP_REG_ACH0: - case DSP_REG_ACH1: - return g_dsp.r.ac[reg - DSP_REG_ACH0].h; - case DSP_REG_CR: return g_dsp.r.cr; - case DSP_REG_SR: return g_dsp.r.sr; - case DSP_REG_PRODL: return g_dsp.r.prod.l; - case DSP_REG_PRODM: return g_dsp.r.prod.m; - case DSP_REG_PRODH: return g_dsp.r.prod.h; - case DSP_REG_PRODM2: return g_dsp.r.prod.m2; - case DSP_REG_AXL0: - case DSP_REG_AXL1: - return g_dsp.r.ax[reg - DSP_REG_AXL0].l; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - return g_dsp.r.ax[reg - DSP_REG_AXH0].h; - case DSP_REG_ACL0: - case DSP_REG_ACL1: - return g_dsp.r.ac[reg - DSP_REG_ACL0].l; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - return g_dsp.r.ac[reg - DSP_REG_ACM0].m; - default: - _assert_msg_(DSP_CORE, 0, "cannot happen"); - return 0; - } + switch (reg) + { + case DSP_REG_AR0: + case DSP_REG_AR1: + case DSP_REG_AR2: + case DSP_REG_AR3: + return g_dsp.r.ar[reg - DSP_REG_AR0]; + case DSP_REG_IX0: + case DSP_REG_IX1: + case DSP_REG_IX2: + case DSP_REG_IX3: + return g_dsp.r.ix[reg - DSP_REG_IX0]; + case DSP_REG_WR0: + case DSP_REG_WR1: + case DSP_REG_WR2: + case DSP_REG_WR3: + return g_dsp.r.wr[reg - DSP_REG_WR0]; + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + return g_dsp.r.st[reg - DSP_REG_ST0]; + case DSP_REG_ACH0: + case DSP_REG_ACH1: + return g_dsp.r.ac[reg - DSP_REG_ACH0].h; + case DSP_REG_CR: + return g_dsp.r.cr; + case DSP_REG_SR: + return g_dsp.r.sr; + case DSP_REG_PRODL: + return g_dsp.r.prod.l; + case DSP_REG_PRODM: + return g_dsp.r.prod.m; + case DSP_REG_PRODH: + return g_dsp.r.prod.h; + case DSP_REG_PRODM2: + return g_dsp.r.prod.m2; + case DSP_REG_AXL0: + case DSP_REG_AXL1: + return g_dsp.r.ax[reg - DSP_REG_AXL0].l; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + return g_dsp.r.ax[reg - DSP_REG_AXH0].h; + case DSP_REG_ACL0: + case DSP_REG_ACL1: + return g_dsp.r.ac[reg - DSP_REG_ACL0].l; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + return g_dsp.r.ac[reg - DSP_REG_ACM0].m; + default: + _assert_msg_(DSP_CORE, 0, "cannot happen"); + return 0; + } } void DSPCore_WriteRegister(int reg, u16 val) { - switch (reg) - { - case DSP_REG_AR0: - case DSP_REG_AR1: - case DSP_REG_AR2: - case DSP_REG_AR3: - g_dsp.r.ar[reg - DSP_REG_AR0] = val; - break; - case DSP_REG_IX0: - case DSP_REG_IX1: - case DSP_REG_IX2: - case DSP_REG_IX3: - g_dsp.r.ix[reg - DSP_REG_IX0] = val; - break; - case DSP_REG_WR0: - case DSP_REG_WR1: - case DSP_REG_WR2: - case DSP_REG_WR3: - g_dsp.r.wr[reg - DSP_REG_WR0] = val; - break; - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - g_dsp.r.st[reg - DSP_REG_ST0] = val; - break; - case DSP_REG_ACH0: - case DSP_REG_ACH1: - g_dsp.r.ac[reg - DSP_REG_ACH0].h = val; - break; - case DSP_REG_CR: g_dsp.r.cr = val; break; - case DSP_REG_SR: g_dsp.r.sr = val; break; - case DSP_REG_PRODL: g_dsp.r.prod.l = val; break; - case DSP_REG_PRODM: g_dsp.r.prod.m = val; break; - case DSP_REG_PRODH: g_dsp.r.prod.h = val; break; - case DSP_REG_PRODM2: g_dsp.r.prod.m2 = val; break; - case DSP_REG_AXL0: - case DSP_REG_AXL1: - g_dsp.r.ax[reg - DSP_REG_AXL0].l = val; - break; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - g_dsp.r.ax[reg - DSP_REG_AXH0].h = val; - break; - case DSP_REG_ACL0: - case DSP_REG_ACL1: - g_dsp.r.ac[reg - DSP_REG_ACL0].l = val; - break; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - g_dsp.r.ac[reg - DSP_REG_ACM0].m = val; - break; - } + switch (reg) + { + case DSP_REG_AR0: + case DSP_REG_AR1: + case DSP_REG_AR2: + case DSP_REG_AR3: + g_dsp.r.ar[reg - DSP_REG_AR0] = val; + break; + case DSP_REG_IX0: + case DSP_REG_IX1: + case DSP_REG_IX2: + case DSP_REG_IX3: + g_dsp.r.ix[reg - DSP_REG_IX0] = val; + break; + case DSP_REG_WR0: + case DSP_REG_WR1: + case DSP_REG_WR2: + case DSP_REG_WR3: + g_dsp.r.wr[reg - DSP_REG_WR0] = val; + break; + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + g_dsp.r.st[reg - DSP_REG_ST0] = val; + break; + case DSP_REG_ACH0: + case DSP_REG_ACH1: + g_dsp.r.ac[reg - DSP_REG_ACH0].h = val; + break; + case DSP_REG_CR: + g_dsp.r.cr = val; + break; + case DSP_REG_SR: + g_dsp.r.sr = val; + break; + case DSP_REG_PRODL: + g_dsp.r.prod.l = val; + break; + case DSP_REG_PRODM: + g_dsp.r.prod.m = val; + break; + case DSP_REG_PRODH: + g_dsp.r.prod.h = val; + break; + case DSP_REG_PRODM2: + g_dsp.r.prod.m2 = val; + break; + case DSP_REG_AXL0: + case DSP_REG_AXL1: + g_dsp.r.ax[reg - DSP_REG_AXL0].l = val; + break; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + g_dsp.r.ax[reg - DSP_REG_AXH0].h = val; + break; + case DSP_REG_ACL0: + case DSP_REG_ACL1: + g_dsp.r.ac[reg - DSP_REG_ACL0].l = val; + break; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + g_dsp.r.ac[reg - DSP_REG_ACM0].m = val; + break; + } } diff --git a/Source/Core/Core/DSP/DSPCore.h b/Source/Core/Core/DSP/DSPCore.h index f673774b35..b270b0117a 100644 --- a/Source/Core/Core/DSP/DSPCore.h +++ b/Source/Core/Core/DSP/DSPCore.h @@ -16,283 +16,284 @@ enum : u32 { - DSP_IRAM_BYTE_SIZE = 0x2000, - DSP_IRAM_SIZE = 0x1000, - DSP_IRAM_MASK = 0x0fff + DSP_IRAM_BYTE_SIZE = 0x2000, + DSP_IRAM_SIZE = 0x1000, + DSP_IRAM_MASK = 0x0fff }; enum : u32 { - DSP_IROM_BYTE_SIZE = 0x2000, - DSP_IROM_SIZE = 0x1000, - DSP_IROM_MASK = 0x0fff + DSP_IROM_BYTE_SIZE = 0x2000, + DSP_IROM_SIZE = 0x1000, + DSP_IROM_MASK = 0x0fff }; enum : u32 { - DSP_DRAM_BYTE_SIZE = 0x2000, - DSP_DRAM_SIZE = 0x1000, - DSP_DRAM_MASK = 0x0fff + DSP_DRAM_BYTE_SIZE = 0x2000, + DSP_DRAM_SIZE = 0x1000, + DSP_DRAM_MASK = 0x0fff }; enum : u32 { - DSP_COEF_BYTE_SIZE = 0x1000, - DSP_COEF_SIZE = 0x800, - DSP_COEF_MASK = 0x7ff + DSP_COEF_BYTE_SIZE = 0x1000, + DSP_COEF_SIZE = 0x800, + DSP_COEF_MASK = 0x7ff }; enum : u16 { - DSP_RESET_VECTOR = 0x8000 + DSP_RESET_VECTOR = 0x8000 }; enum : u8 { - DSP_STACK_DEPTH = 0x20, - DSP_STACK_MASK = 0x1f + DSP_STACK_DEPTH = 0x20, + DSP_STACK_MASK = 0x1f }; enum : u32 { - DSP_CR_IMEM = 2, - DSP_CR_DMEM = 0, - DSP_CR_TO_CPU = 1, - DSP_CR_FROM_CPU = 0 + DSP_CR_IMEM = 2, + DSP_CR_DMEM = 0, + DSP_CR_TO_CPU = 1, + DSP_CR_FROM_CPU = 0 }; // Register table taken from libasnd enum : int { - // Address registers - DSP_REG_AR0 = 0x00, - DSP_REG_AR1 = 0x01, - DSP_REG_AR2 = 0x02, - DSP_REG_AR3 = 0x03, + // Address registers + DSP_REG_AR0 = 0x00, + DSP_REG_AR1 = 0x01, + DSP_REG_AR2 = 0x02, + DSP_REG_AR3 = 0x03, - // Indexing registers (actually, mostly used as increments) - DSP_REG_IX0 = 0x04, - DSP_REG_IX1 = 0x05, - DSP_REG_IX2 = 0x06, - DSP_REG_IX3 = 0x07, + // Indexing registers (actually, mostly used as increments) + DSP_REG_IX0 = 0x04, + DSP_REG_IX1 = 0x05, + DSP_REG_IX2 = 0x06, + DSP_REG_IX3 = 0x07, - // Address wrapping registers. should be initialized to 0xFFFF if not used. - DSP_REG_WR0 = 0x08, - DSP_REG_WR1 = 0x09, - DSP_REG_WR2 = 0x0a, - DSP_REG_WR3 = 0x0b, + // Address wrapping registers. should be initialized to 0xFFFF if not used. + DSP_REG_WR0 = 0x08, + DSP_REG_WR1 = 0x09, + DSP_REG_WR2 = 0x0a, + DSP_REG_WR3 = 0x0b, - // Stacks - DSP_REG_ST0 = 0x0c, - DSP_REG_ST1 = 0x0d, - DSP_REG_ST2 = 0x0e, - DSP_REG_ST3 = 0x0f, + // Stacks + DSP_REG_ST0 = 0x0c, + DSP_REG_ST1 = 0x0d, + DSP_REG_ST2 = 0x0e, + DSP_REG_ST3 = 0x0f, - // Seems to be the top 8 bits of LRS/SRS. - DSP_REG_CR = 0x12, - DSP_REG_SR = 0x13, + // Seems to be the top 8 bits of LRS/SRS. + DSP_REG_CR = 0x12, + DSP_REG_SR = 0x13, - // Product - DSP_REG_PRODL = 0x14, - DSP_REG_PRODM = 0x15, - DSP_REG_PRODH = 0x16, - DSP_REG_PRODM2 = 0x17, + // Product + DSP_REG_PRODL = 0x14, + DSP_REG_PRODM = 0x15, + DSP_REG_PRODH = 0x16, + DSP_REG_PRODM2 = 0x17, - DSP_REG_AXL0 = 0x18, - DSP_REG_AXL1 = 0x19, - DSP_REG_AXH0 = 0x1a, - DSP_REG_AXH1 = 0x1b, + DSP_REG_AXL0 = 0x18, + DSP_REG_AXL1 = 0x19, + DSP_REG_AXH0 = 0x1a, + DSP_REG_AXH1 = 0x1b, - // Accumulator (global) - DSP_REG_ACC0 = 0x1c, - DSP_REG_ACC1 = 0x1d, + // Accumulator (global) + DSP_REG_ACC0 = 0x1c, + DSP_REG_ACC1 = 0x1d, - DSP_REG_ACL0 = 0x1c, // Low accumulator - DSP_REG_ACL1 = 0x1d, - DSP_REG_ACM0 = 0x1e, // Mid accumulator - DSP_REG_ACM1 = 0x1f, - DSP_REG_ACH0 = 0x10, // Sign extended 8 bit register 0 - DSP_REG_ACH1 = 0x11 // Sign extended 8 bit register 1 + DSP_REG_ACL0 = 0x1c, // Low accumulator + DSP_REG_ACL1 = 0x1d, + DSP_REG_ACM0 = 0x1e, // Mid accumulator + DSP_REG_ACM1 = 0x1f, + DSP_REG_ACH0 = 0x10, // Sign extended 8 bit register 0 + DSP_REG_ACH1 = 0x11 // Sign extended 8 bit register 1 }; // Hardware registers address enum : u32 { - DSP_COEF_A1_0 = 0xa0, + DSP_COEF_A1_0 = 0xa0, - DSP_DSCR = 0xc9, // DSP DMA Control Reg - DSP_DSPA = 0xcd, // DSP DMA Address (DSP) - DSP_DSBL = 0xcb, // DSP DMA Block Length - DSP_DSMAH = 0xce, // DSP DMA Address High (External) - DSP_DSMAL = 0xcf, // DSP DMA Address Low (External) + DSP_DSCR = 0xc9, // DSP DMA Control Reg + DSP_DSPA = 0xcd, // DSP DMA Address (DSP) + DSP_DSBL = 0xcb, // DSP DMA Block Length + DSP_DSMAH = 0xce, // DSP DMA Address High (External) + DSP_DSMAL = 0xcf, // DSP DMA Address Low (External) - DSP_FORMAT = 0xd1, // Sample format - DSP_ACUNK = 0xd2, // Set to 3 on my dumps - DSP_ACDATA1 = 0xd3, // Used only by Zelda ucodes - DSP_ACSAH = 0xd4, // Start of loop - DSP_ACSAL = 0xd5, - DSP_ACEAH = 0xd6, // End of sample (and loop) - DSP_ACEAL = 0xd7, - DSP_ACCAH = 0xd8, // Current playback position - DSP_ACCAL = 0xd9, - DSP_PRED_SCALE = 0xda, // ADPCM predictor and scale - DSP_YN1 = 0xdb, - DSP_YN2 = 0xdc, - DSP_ACCELERATOR = 0xdd, // ADPCM accelerator read. Used by AX. - DSP_GAIN = 0xde, - DSP_ACUNK2 = 0xdf, // Set to 0xc on my dumps + DSP_FORMAT = 0xd1, // Sample format + DSP_ACUNK = 0xd2, // Set to 3 on my dumps + DSP_ACDATA1 = 0xd3, // Used only by Zelda ucodes + DSP_ACSAH = 0xd4, // Start of loop + DSP_ACSAL = 0xd5, + DSP_ACEAH = 0xd6, // End of sample (and loop) + DSP_ACEAL = 0xd7, + DSP_ACCAH = 0xd8, // Current playback position + DSP_ACCAL = 0xd9, + DSP_PRED_SCALE = 0xda, // ADPCM predictor and scale + DSP_YN1 = 0xdb, + DSP_YN2 = 0xdc, + DSP_ACCELERATOR = 0xdd, // ADPCM accelerator read. Used by AX. + DSP_GAIN = 0xde, + DSP_ACUNK2 = 0xdf, // Set to 0xc on my dumps - DSP_AMDM = 0xef, // ARAM DMA Request Mask 0: DMA with ARAM unmasked 1: masked + DSP_AMDM = 0xef, // ARAM DMA Request Mask 0: DMA with ARAM unmasked 1: masked - DSP_DIRQ = 0xfb, // DSP Irq Rest - DSP_DMBH = 0xfc, // DSP Mailbox H - DSP_DMBL = 0xfd, // DSP Mailbox L - DSP_CMBH = 0xfe, // CPU Mailbox H - DSP_CMBL = 0xff // CPU Mailbox L + DSP_DIRQ = 0xfb, // DSP Irq Rest + DSP_DMBH = 0xfc, // DSP Mailbox H + DSP_DMBL = 0xfd, // DSP Mailbox L + DSP_CMBH = 0xfe, // CPU Mailbox H + DSP_CMBL = 0xff // CPU Mailbox L }; // Stacks enum : int { - DSP_STACK_C, - DSP_STACK_D + DSP_STACK_C, + DSP_STACK_D }; // cr (Not g_dsp.r[CR]) bits // See HW/DSP.cpp. enum : u32 { - CR_EXTERNAL_INT = 0x0002, - CR_HALT = 0x0004, - CR_INIT = 0x0400 + CR_EXTERNAL_INT = 0x0002, + CR_HALT = 0x0004, + CR_INIT = 0x0400 }; // SR bits enum : u16 { - SR_CARRY = 0x0001, - SR_OVERFLOW = 0x0002, - SR_ARITH_ZERO = 0x0004, - SR_SIGN = 0x0008, - SR_OVER_S32 = 0x0010, // Set when there was mod/tst/cmp on accu and result is over s32 - SR_TOP2BITS = 0x0020, // If the upper (ac?.m/ax?.h) 2 bits are equal - SR_LOGIC_ZERO = 0x0040, - SR_OVERFLOW_STICKY = 0x0080, // Set at the same time as 0x2 (under same conditions) - but not cleared the same - SR_100 = 0x0100, // Unknown - SR_INT_ENABLE = 0x0200, // Not 100% sure but duddie says so. This should replace the hack, if so. - SR_400 = 0x0400, // Unknown - SR_EXT_INT_ENABLE = 0x0800, // Appears in zelda - seems to disable external interrupts - SR_1000 = 0x1000, // Unknown - SR_MUL_MODIFY = 0x2000, // 1 = normal. 0 = x2 (M0, M2) (Free mul by 2) - SR_40_MODE_BIT = 0x4000, // 0 = "16", 1 = "40" (SET16, SET40) Controls sign extension when loading mid accums and data saturation for stores from mid accums. - SR_MUL_UNSIGNED = 0x8000, // 0 = normal. 1 = unsigned (CLR15, SET15) If set, treats ax?.l as unsigned (MULX family only). + SR_CARRY = 0x0001, + SR_OVERFLOW = 0x0002, + SR_ARITH_ZERO = 0x0004, + SR_SIGN = 0x0008, + SR_OVER_S32 = 0x0010, // Set when there was mod/tst/cmp on accu and result is over s32 + SR_TOP2BITS = 0x0020, // If the upper (ac?.m/ax?.h) 2 bits are equal + SR_LOGIC_ZERO = 0x0040, + SR_OVERFLOW_STICKY = + 0x0080, // Set at the same time as 0x2 (under same conditions) - but not cleared the same + SR_100 = 0x0100, // Unknown + SR_INT_ENABLE = 0x0200, // Not 100% sure but duddie says so. This should replace the hack, if so. + SR_400 = 0x0400, // Unknown + SR_EXT_INT_ENABLE = 0x0800, // Appears in zelda - seems to disable external interrupts + SR_1000 = 0x1000, // Unknown + SR_MUL_MODIFY = 0x2000, // 1 = normal. 0 = x2 (M0, M2) (Free mul by 2) + SR_40_MODE_BIT = 0x4000, // 0 = "16", 1 = "40" (SET16, SET40) Controls sign extension when + // loading mid accums and data saturation for stores from mid accums. + SR_MUL_UNSIGNED = 0x8000, // 0 = normal. 1 = unsigned (CLR15, SET15) If set, treats ax?.l as + // unsigned (MULX family only). - // This should be the bits affected by CMP. Does not include logic zero. - SR_CMP_MASK = 0x3f + // This should be the bits affected by CMP. Does not include logic zero. + SR_CMP_MASK = 0x3f }; // Exception vectors enum : int { - EXP_STOVF = 1, // 0x0002 stack under/over flow - EXP_2 = 2, // 0x0004 - EXP_3 = 3, // 0x0006 - EXP_4 = 4, // 0x0008 - EXP_ACCOV = 5, // 0x000a accelerator address overflow - EXP_6 = 6, // 0x000c - EXP_INT = 7 // 0x000e external int (message from CPU) + EXP_STOVF = 1, // 0x0002 stack under/over flow + EXP_2 = 2, // 0x0004 + EXP_3 = 3, // 0x0006 + EXP_4 = 4, // 0x0008 + EXP_ACCOV = 5, // 0x000a accelerator address overflow + EXP_6 = 6, // 0x000c + EXP_INT = 7 // 0x000e external int (message from CPU) }; struct DSP_Regs { - u16 ar[4]; - u16 ix[4]; - u16 wr[4]; - u16 st[4]; - u16 cr; - u16 sr; + u16 ar[4]; + u16 ix[4]; + u16 wr[4]; + u16 st[4]; + u16 cr; + u16 sr; - union - { - u64 val; - struct - { - u16 l; - u16 m; - u16 h; - u16 m2;//if this gets in the way, drop it. - }; - } prod; + union { + u64 val; + struct + { + u16 l; + u16 m; + u16 h; + u16 m2; // if this gets in the way, drop it. + }; + } prod; - union - { - u32 val; - struct { - u16 l; - u16 h; - }; - } ax[2]; + union { + u32 val; + struct + { + u16 l; + u16 h; + }; + } ax[2]; - union - { - u64 val; - struct - { - u16 l; - u16 m; - u16 h; - }; - } ac[2]; + union { + u64 val; + struct + { + u16 l; + u16 m; + u16 h; + }; + } ac[2]; }; // All the state of the DSP should be in this struct. Any DSP state that is not filled on init // should be moved here. struct SDSP { - DSP_Regs r; - u16 pc; + DSP_Regs r; + u16 pc; #if PROFILE - u16 err_pc; + u16 err_pc; #endif - // This is NOT the same cr as r.cr. - // This register is shared with the main emulation, see DSP.cpp - // The engine has control over 0x0C07 of this reg. - // Bits are defined in a struct in DSP.cpp. - u16 cr; + // This is NOT the same cr as r.cr. + // This register is shared with the main emulation, see DSP.cpp + // The engine has control over 0x0C07 of this reg. + // Bits are defined in a struct in DSP.cpp. + u16 cr; - u8 reg_stack_ptr[4]; - u8 exceptions; // pending exceptions - volatile bool external_interrupt_waiting; - bool reset_dspjit_codespace; + u8 reg_stack_ptr[4]; + u8 exceptions; // pending exceptions + volatile bool external_interrupt_waiting; + bool reset_dspjit_codespace; - // DSP hardware stacks. They're mapped to a bunch of registers, such that writes - // to them push and reads pop. - // Let's make stack depth 32 for now, which is way more than what's needed. - // The real DSP has different depths for the different stacks, but it would - // be strange if any ucode relied on stack overflows since on the DSP, when - // the stack overflows, you're screwed. - u16 reg_stack[4][DSP_STACK_DEPTH]; + // DSP hardware stacks. They're mapped to a bunch of registers, such that writes + // to them push and reads pop. + // Let's make stack depth 32 for now, which is way more than what's needed. + // The real DSP has different depths for the different stacks, but it would + // be strange if any ucode relied on stack overflows since on the DSP, when + // the stack overflows, you're screwed. + u16 reg_stack[4][DSP_STACK_DEPTH]; - // For debugging. - u32 iram_crc; - u64 step_counter; + // For debugging. + u32 iram_crc; + u64 step_counter; - // Mailbox. - std::atomic mbox[2]; + // Mailbox. + std::atomic mbox[2]; - // Accelerator / DMA / other hardware registers. Not GPRs. - std::array ifx_regs; + // Accelerator / DMA / other hardware registers. Not GPRs. + std::array ifx_regs; - // When state saving, all of the above can just be memcpy'd into the save state. - // The below needs special handling. - u16 *iram; - u16 *dram; - u16 *irom; - u16 *coef; + // When state saving, all of the above can just be memcpy'd into the save state. + // The below needs special handling. + u16* iram; + u16* dram; + u16* irom; + u16* coef; - // This one doesn't really belong here. - u8 *cpu_ram; + // This one doesn't really belong here. + u8* cpu_ram; }; extern SDSP g_dsp; @@ -304,30 +305,26 @@ extern std::unique_ptr g_dsp_cap; struct DSPInitOptions { - // DSP IROM blob, which is where the DSP boots from. Embedded into the DSP. - std::array irom_contents; + // DSP IROM blob, which is where the DSP boots from. Embedded into the DSP. + std::array irom_contents; - // DSP DROM blob, which contains resampling coefficients. - std::array coef_contents; + // DSP DROM blob, which contains resampling coefficients. + std::array coef_contents; - // Core used to emulate the DSP. - // Default: CORE_JIT. - enum CoreType - { - CORE_INTERPRETER, - CORE_JIT, - }; - CoreType core_type; + // Core used to emulate the DSP. + // Default: CORE_JIT. + enum CoreType + { + CORE_INTERPRETER, + CORE_JIT, + }; + CoreType core_type; - // Optional capture logger used to log internal DSP data transfers. - // Default: dummy implementation, does nothing. - DSPCaptureLogger* capture_logger; + // Optional capture logger used to log internal DSP data transfers. + // Default: dummy implementation, does nothing. + DSPCaptureLogger* capture_logger; - DSPInitOptions() - : core_type(CORE_JIT), - capture_logger(new DefaultDSPCaptureLogger()) - { - } + DSPInitOptions() : core_type(CORE_JIT), capture_logger(new DefaultDSPCaptureLogger()) {} }; // Initializes the DSP emulator using the provided options. Takes ownership of @@ -335,7 +332,7 @@ struct DSPInitOptions bool DSPCore_Init(const DSPInitOptions& opts); void DSPCore_Reset(); -void DSPCore_Shutdown(); // Frees all allocated memory. +void DSPCore_Shutdown(); // Frees all allocated memory. void DSPCore_CheckExternalInterrupt(); void DSPCore_CheckExceptions(); @@ -348,9 +345,9 @@ void CompileCurrent(); enum DSPCoreState { - DSPCORE_STOP = 0, - DSPCORE_RUNNING, - DSPCORE_STEPPING, + DSPCORE_STOP = 0, + DSPCORE_RUNNING, + DSPCORE_STEPPING, }; int DSPCore_RunCycles(int cycles); diff --git a/Source/Core/Core/DSP/DSPDisassembler.cpp b/Source/Core/Core/DSP/DSPDisassembler.cpp index f84f61aea3..a58a273ec4 100644 --- a/Source/Core/Core/DSP/DSPDisassembler.cpp +++ b/Source/Core/Core/DSP/DSPDisassembler.cpp @@ -15,315 +15,320 @@ #include "Core/DSP/DSPDisassembler.h" #include "Core/DSP/DSPTables.h" -DSPDisassembler::DSPDisassembler(const AssemblerSettings &settings) - : settings_(settings) +DSPDisassembler::DSPDisassembler(const AssemblerSettings& settings) : settings_(settings) { } DSPDisassembler::~DSPDisassembler() { - // Some old code for logging unknown ops. - std::string filename = File::GetUserPath(D_DUMPDSP_IDX) + "UnkOps.txt"; - std::ofstream uo(filename); - if (!uo) - return; + // Some old code for logging unknown ops. + std::string filename = File::GetUserPath(D_DUMPDSP_IDX) + "UnkOps.txt"; + std::ofstream uo(filename); + if (!uo) + return; - int count = 0; - for (const auto& entry : unk_opcodes) - { - if (entry.second > 0) - { - count++; - uo << StringFromFormat("OP%04x\t%d", entry.first, entry.second); - for (int j = 15; j >= 0; j--) // print op bits - { - if ((j & 0x3) == 3) - uo << "\tb"; + int count = 0; + for (const auto& entry : unk_opcodes) + { + if (entry.second > 0) + { + count++; + uo << StringFromFormat("OP%04x\t%d", entry.first, entry.second); + for (int j = 15; j >= 0; j--) // print op bits + { + if ((j & 0x3) == 3) + uo << "\tb"; - uo << StringFromFormat("%d", (entry.first >> j) & 0x1); - } + uo << StringFromFormat("%d", (entry.first >> j) & 0x1); + } - uo << "\n"; - } - } + uo << "\n"; + } + } - uo << StringFromFormat("Unknown opcodes count: %d\n", count); + uo << StringFromFormat("Unknown opcodes count: %d\n", count); } -bool DSPDisassembler::Disassemble(int start_pc, const std::vector &code, int base_addr, std::string &text) +bool DSPDisassembler::Disassemble(int start_pc, const std::vector& code, int base_addr, + std::string& text) { - const char *tmp1 = "tmp1.bin"; + const char* tmp1 = "tmp1.bin"; - // First we have to dump the code to a bin file. - { - File::IOFile f(tmp1, "wb"); - f.WriteArray(&code[0], code.size()); - } + // First we have to dump the code to a bin file. + { + File::IOFile f(tmp1, "wb"); + f.WriteArray(&code[0], code.size()); + } - // Run the two passes. - return DisassembleFile(tmp1, base_addr, 1, text) && DisassembleFile(tmp1, base_addr, 2, text); + // Run the two passes. + return DisassembleFile(tmp1, base_addr, 1, text) && DisassembleFile(tmp1, base_addr, 2, text); } std::string DSPDisassembler::DisassembleParameters(const DSPOPCTemplate& opc, u16 op1, u16 op2) { - std::string buf; + std::string buf; - for (int j = 0; j < opc.param_count; j++) - { - if (j > 0) - buf += ", "; + for (int j = 0; j < opc.param_count; j++) + { + if (j > 0) + buf += ", "; - u32 val = (opc.params[j].loc >= 1) ? op2 : op1; - val &= opc.params[j].mask; - if (opc.params[j].lshift < 0) - val = val << (-opc.params[j].lshift); - else - val = val >> opc.params[j].lshift; + u32 val = (opc.params[j].loc >= 1) ? op2 : op1; + val &= opc.params[j].mask; + if (opc.params[j].lshift < 0) + val = val << (-opc.params[j].lshift); + else + val = val >> opc.params[j].lshift; - u32 type = opc.params[j].type; - if ((type & 0xff) == 0x10) - type &= 0xff00; + u32 type = opc.params[j].type; + if ((type & 0xff) == 0x10) + type &= 0xff00; - if (type & P_REG) - { - // Check for _D parameter - if so flip. - if ((type == P_ACC_D) || (type == P_ACCM_D)) // Used to be P_ACCM_D TODO verify - val = (~val & 0x1) | ((type & P_REGS_MASK) >> 8); - else - val |= (type & P_REGS_MASK) >> 8; - type &= ~P_REGS_MASK; - } + if (type & P_REG) + { + // Check for _D parameter - if so flip. + if ((type == P_ACC_D) || (type == P_ACCM_D)) // Used to be P_ACCM_D TODO verify + val = (~val & 0x1) | ((type & P_REGS_MASK) >> 8); + else + val |= (type & P_REGS_MASK) >> 8; + type &= ~P_REGS_MASK; + } - switch (type) - { - case P_REG: - if (settings_.decode_registers) - buf += StringFromFormat("$%s", pdregname(val)); - else - buf += StringFromFormat("$%d", val); - break; + switch (type) + { + case P_REG: + if (settings_.decode_registers) + buf += StringFromFormat("$%s", pdregname(val)); + else + buf += StringFromFormat("$%d", val); + break; - case P_PRG: - if (settings_.decode_registers) - buf += StringFromFormat("@$%s", pdregname(val)); - else - buf += StringFromFormat("@$%d", val); - break; + case P_PRG: + if (settings_.decode_registers) + buf += StringFromFormat("@$%s", pdregname(val)); + else + buf += StringFromFormat("@$%d", val); + break; - case P_VAL: - case P_ADDR_I: - case P_ADDR_D: - if (settings_.decode_names) - { - buf += pdname(val); - } - else - { - buf += StringFromFormat("0x%04x", val); - } - break; + case P_VAL: + case P_ADDR_I: + case P_ADDR_D: + if (settings_.decode_names) + { + buf += pdname(val); + } + else + { + buf += StringFromFormat("0x%04x", val); + } + break; - case P_IMM: - if (opc.params[j].size != 2) - { - if (opc.params[j].mask == 0x003f) // LSL, LSR, ASL, ASR - buf += StringFromFormat("#%d", (val & 0x20) ? (val | 0xFFFFFFC0) : val); // 6-bit sign extension - else - buf += StringFromFormat("#0x%02x", val); - } - else - { - buf += StringFromFormat("#0x%04x", val); - } - break; + case P_IMM: + if (opc.params[j].size != 2) + { + if (opc.params[j].mask == 0x003f) // LSL, LSR, ASL, ASR + buf += StringFromFormat("#%d", + (val & 0x20) ? (val | 0xFFFFFFC0) : val); // 6-bit sign extension + else + buf += StringFromFormat("#0x%02x", val); + } + else + { + buf += StringFromFormat("#0x%04x", val); + } + break; - case P_MEM: - if (opc.params[j].size != 2) - val = (u16)(s16)(s8)val; + case P_MEM: + if (opc.params[j].size != 2) + val = (u16)(s16)(s8)val; - if (settings_.decode_names) - buf += StringFromFormat("@%s", pdname(val)); - else - buf += StringFromFormat("@0x%04x", val); - break; + if (settings_.decode_names) + buf += StringFromFormat("@%s", pdname(val)); + else + buf += StringFromFormat("@0x%04x", val); + break; - default: - ERROR_LOG(DSPLLE, "Unknown parameter type: %x", opc.params[j].type); - break; - } - } + default: + ERROR_LOG(DSPLLE, "Unknown parameter type: %x", opc.params[j].type); + break; + } + } - return buf; + return buf; } static std::string MakeLowerCase(std::string in) { - std::transform(in.begin(), in.end(), in.begin(), ::tolower); + std::transform(in.begin(), in.end(), in.begin(), ::tolower); - return in; + return in; } -bool DSPDisassembler::DisassembleOpcode(const u16 *binbuf, int base_addr, int pass, u16 *pc, std::string &dest) +bool DSPDisassembler::DisassembleOpcode(const u16* binbuf, int base_addr, int pass, u16* pc, + std::string& dest) { - std::string buf(" "); + std::string buf(" "); - if ((*pc & 0x7fff) >= 0x1000) - { - ++pc; - dest.append("; outside memory"); - return false; - } + if ((*pc & 0x7fff) >= 0x1000) + { + ++pc; + dest.append("; outside memory"); + return false; + } - const u32 op1 = binbuf[*pc & 0x0fff]; + const u32 op1 = binbuf[*pc & 0x0fff]; - const DSPOPCTemplate *opc = nullptr; - const DSPOPCTemplate *opc_ext = nullptr; + const DSPOPCTemplate* opc = nullptr; + const DSPOPCTemplate* opc_ext = nullptr; - // find opcode - for (int j = 0; j < opcodes_size; j++) - { - u16 mask = opcodes[j].opcode_mask; + // find opcode + for (int j = 0; j < opcodes_size; j++) + { + u16 mask = opcodes[j].opcode_mask; - if ((op1 & mask) == opcodes[j].opcode) - { - opc = &opcodes[j]; - break; - } - } - const DSPOPCTemplate fake_op = {"CW", 0x0000, 0x0000, nop, nullptr, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, false, false, false, false, false}; - if (!opc) - opc = &fake_op; + if ((op1 & mask) == opcodes[j].opcode) + { + opc = &opcodes[j]; + break; + } + } + const DSPOPCTemplate fake_op = { + "CW", 0x0000, 0x0000, nop, nullptr, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, + false, false, false, false, false}; + if (!opc) + opc = &fake_op; - bool extended = false; - bool only7bitext = false; + bool extended = false; + bool only7bitext = false; - if (((opc->opcode >> 12) == 0x3) && (op1 & 0x007f)) - { - extended = true; - only7bitext = true; - } - else if (((opc->opcode >> 12) > 0x3) && (op1 & 0x00ff)) - { - extended = true; - } + if (((opc->opcode >> 12) == 0x3) && (op1 & 0x007f)) + { + extended = true; + only7bitext = true; + } + else if (((opc->opcode >> 12) > 0x3) && (op1 & 0x00ff)) + { + extended = true; + } - if (extended) - { - // opcode has an extension - // find opcode - for (int j = 0; j < opcodes_ext_size; j++) - { - if (only7bitext) - { - if (((op1 & 0x7f) & opcodes_ext[j].opcode_mask) == opcodes_ext[j].opcode) - { - opc_ext = &opcodes_ext[j]; - break; - } - } - else - { - if ((op1 & opcodes_ext[j].opcode_mask) == opcodes_ext[j].opcode) - { - opc_ext = &opcodes_ext[j]; - break; - } - } - } - } + if (extended) + { + // opcode has an extension + // find opcode + for (int j = 0; j < opcodes_ext_size; j++) + { + if (only7bitext) + { + if (((op1 & 0x7f) & opcodes_ext[j].opcode_mask) == opcodes_ext[j].opcode) + { + opc_ext = &opcodes_ext[j]; + break; + } + } + else + { + if ((op1 & opcodes_ext[j].opcode_mask) == opcodes_ext[j].opcode) + { + opc_ext = &opcodes_ext[j]; + break; + } + } + } + } - // printing + // printing - if (settings_.show_pc) - buf += StringFromFormat("%04x ", *pc); + if (settings_.show_pc) + buf += StringFromFormat("%04x ", *pc); - u32 op2; + u32 op2; - // Size 2 - the op has a large immediate. - if (opc->size == 2) - { - op2 = binbuf[(*pc + 1) & 0x0fff]; - if (settings_.show_hex) - buf += StringFromFormat("%04x %04x ", op1, op2); - } - else - { - op2 = 0; - if (settings_.show_hex) - buf += StringFromFormat("%04x ", op1); - } + // Size 2 - the op has a large immediate. + if (opc->size == 2) + { + op2 = binbuf[(*pc + 1) & 0x0fff]; + if (settings_.show_hex) + buf += StringFromFormat("%04x %04x ", op1, op2); + } + else + { + op2 = 0; + if (settings_.show_hex) + buf += StringFromFormat("%04x ", op1); + } - std::string opname = opc->name; - if (settings_.lower_case_ops) - opname = MakeLowerCase(opname); + std::string opname = opc->name; + if (settings_.lower_case_ops) + opname = MakeLowerCase(opname); - std::string ext_buf; - if (extended) - ext_buf = StringFromFormat("%s%c%s", opname.c_str(), settings_.ext_separator, opc_ext->name); - else - ext_buf = opname; - if (settings_.lower_case_ops) - ext_buf = MakeLowerCase(ext_buf); + std::string ext_buf; + if (extended) + ext_buf = StringFromFormat("%s%c%s", opname.c_str(), settings_.ext_separator, opc_ext->name); + else + ext_buf = opname; + if (settings_.lower_case_ops) + ext_buf = MakeLowerCase(ext_buf); - if (settings_.print_tabs) - buf += StringFromFormat("%s\t", ext_buf.c_str()); - else - buf += StringFromFormat("%-12s", ext_buf.c_str()); + if (settings_.print_tabs) + buf += StringFromFormat("%s\t", ext_buf.c_str()); + else + buf += StringFromFormat("%-12s", ext_buf.c_str()); - if (opc->param_count > 0) - buf += DisassembleParameters(*opc, op1, op2); + if (opc->param_count > 0) + buf += DisassembleParameters(*opc, op1, op2); - // Handle opcode extension. - if (extended) - { - if (opc->param_count > 0) - buf += " "; + // Handle opcode extension. + if (extended) + { + if (opc->param_count > 0) + buf += " "; - buf += ": "; + buf += ": "; - if (opc_ext->param_count > 0) - buf += DisassembleParameters(*opc_ext, op1, op2); - } + if (opc_ext->param_count > 0) + buf += DisassembleParameters(*opc_ext, op1, op2); + } - if (opc->opcode_mask == 0) - { - // unknown opcode - unk_opcodes[op1]++; - buf += "\t\t; *** UNKNOWN OPCODE ***"; - } + if (opc->opcode_mask == 0) + { + // unknown opcode + unk_opcodes[op1]++; + buf += "\t\t; *** UNKNOWN OPCODE ***"; + } - if (extended) - *pc += opc_ext->size; - else - *pc += opc->size; + if (extended) + *pc += opc_ext->size; + else + *pc += opc->size; - if (pass == 2) - dest.append(buf); + if (pass == 2) + dest.append(buf); - return true; + return true; } -bool DSPDisassembler::DisassembleFile(const std::string& name, int base_addr, int pass, std::string &output) +bool DSPDisassembler::DisassembleFile(const std::string& name, int base_addr, int pass, + std::string& output) { - File::IOFile in(name, "rb"); - if (!in) - { - printf("gd_dis_file: No input\n"); - return false; - } + File::IOFile in(name, "rb"); + if (!in) + { + printf("gd_dis_file: No input\n"); + return false; + } - const int size = ((int)in.GetSize() & ~1) / 2; - std::vector binbuf(size); - in.ReadArray(binbuf.data(), size); - in.Close(); + const int size = ((int)in.GetSize() & ~1) / 2; + std::vector binbuf(size); + in.ReadArray(binbuf.data(), size); + in.Close(); - // Actually do the disassembly. - for (u16 pc = 0; pc < size;) - { - DisassembleOpcode(binbuf.data(), base_addr, pass, &pc, output); - if (pass == 2) - output.append("\n"); - } + // Actually do the disassembly. + for (u16 pc = 0; pc < size;) + { + DisassembleOpcode(binbuf.data(), base_addr, pass, &pc, output); + if (pass == 2) + output.append("\n"); + } - return true; + return true; } diff --git a/Source/Core/Core/DSP/DSPDisassembler.h b/Source/Core/Core/DSP/DSPDisassembler.h index dd90314b68..96f2aefeb0 100644 --- a/Source/Core/Core/DSP/DSPDisassembler.h +++ b/Source/Core/Core/DSP/DSPDisassembler.h @@ -16,51 +16,44 @@ struct AssemblerSettings { - AssemblerSettings() - : print_tabs(false), - show_hex(false), - show_pc(false), - force(false), - decode_names(true), - decode_registers(true), - ext_separator('\''), - lower_case_ops(true), - pc(0) - { - } + AssemblerSettings() + : print_tabs(false), show_hex(false), show_pc(false), force(false), decode_names(true), + decode_registers(true), ext_separator('\''), lower_case_ops(true), pc(0) + { + } - bool print_tabs; - bool show_hex; - bool show_pc; - bool force; - bool decode_names; - bool decode_registers; - char ext_separator; - bool lower_case_ops; + bool print_tabs; + bool show_hex; + bool show_pc; + bool force; + bool decode_names; + bool decode_registers; + char ext_separator; + bool lower_case_ops; - u16 pc; + u16 pc; }; class DSPDisassembler { public: - DSPDisassembler(const AssemblerSettings &settings); - ~DSPDisassembler(); + DSPDisassembler(const AssemblerSettings& settings); + ~DSPDisassembler(); - bool Disassemble(int start_pc, const std::vector &code, int base_addr, std::string &text); + bool Disassemble(int start_pc, const std::vector& code, int base_addr, std::string& text); - // Warning - this one is trickier to use right. - // Use pass == 2 if you're just using it by itself. - bool DisassembleOpcode(const u16 *binbuf, int base_addr, int pass, u16 *pc, std::string &dest); + // Warning - this one is trickier to use right. + // Use pass == 2 if you're just using it by itself. + bool DisassembleOpcode(const u16* binbuf, int base_addr, int pass, u16* pc, std::string& dest); private: - // Moves PC forward and writes the result to dest. - bool DisassembleFile(const std::string& name, int base_addr, int pass, std::string &output); + // Moves PC forward and writes the result to dest. + bool DisassembleFile(const std::string& name, int base_addr, int pass, std::string& output); - std::string DisassembleParameters(const DSPOPCTemplate& opc, u16 op1, u16 op2); - std::map unk_opcodes; + std::string DisassembleParameters(const DSPOPCTemplate& opc, u16 op1, u16 op2); + std::map unk_opcodes; - const AssemblerSettings settings_; + const AssemblerSettings settings_; - LabelMap labels; + LabelMap labels; }; diff --git a/Source/Core/Core/DSP/DSPEmitter.cpp b/Source/Core/Core/DSP/DSPEmitter.cpp index e082317d85..6c3913ee75 100644 --- a/Source/Core/Core/DSP/DSPEmitter.cpp +++ b/Source/Core/Core/DSP/DSPEmitter.cpp @@ -18,409 +18,409 @@ using namespace Gen; DSPEmitter::DSPEmitter() : gpr(*this), storeIndex(-1), storeIndex2(-1) { - m_compiledCode = nullptr; + m_compiledCode = nullptr; - AllocCodeSpace(COMPILED_CODE_SIZE); + AllocCodeSpace(COMPILED_CODE_SIZE); - blocks = new DSPCompiledCode[MAX_BLOCKS]; - blockLinks = new Block[MAX_BLOCKS]; - blockSize = new u16[MAX_BLOCKS]; + blocks = new DSPCompiledCode[MAX_BLOCKS]; + blockLinks = new Block[MAX_BLOCKS]; + blockSize = new u16[MAX_BLOCKS]; - compileSR = 0; - compileSR |= SR_INT_ENABLE; - compileSR |= SR_EXT_INT_ENABLE; + compileSR = 0; + compileSR |= SR_INT_ENABLE; + compileSR |= SR_EXT_INT_ENABLE; - CompileDispatcher(); - stubEntryPoint = CompileStub(); + CompileDispatcher(); + stubEntryPoint = CompileStub(); - //clear all of the block references - for (int i = 0x0000; i < MAX_BLOCKS; i++) - { - blocks[i] = (DSPCompiledCode)stubEntryPoint; - blockLinks[i] = nullptr; - blockSize[i] = 0; - } + // clear all of the block references + for (int i = 0x0000; i < MAX_BLOCKS; i++) + { + blocks[i] = (DSPCompiledCode)stubEntryPoint; + blockLinks[i] = nullptr; + blockSize[i] = 0; + } } DSPEmitter::~DSPEmitter() { - delete[] blocks; - delete[] blockLinks; - delete[] blockSize; - FreeCodeSpace(); + delete[] blocks; + delete[] blockLinks; + delete[] blockSize; + FreeCodeSpace(); } void DSPEmitter::ClearIRAM() { - for (int i = 0x0000; i < 0x1000; i++) - { - blocks[i] = (DSPCompiledCode)stubEntryPoint; - blockLinks[i] = nullptr; - blockSize[i] = 0; - unresolvedJumps[i].clear(); - } - g_dsp.reset_dspjit_codespace = true; + for (int i = 0x0000; i < 0x1000; i++) + { + blocks[i] = (DSPCompiledCode)stubEntryPoint; + blockLinks[i] = nullptr; + blockSize[i] = 0; + unresolvedJumps[i].clear(); + } + g_dsp.reset_dspjit_codespace = true; } void DSPEmitter::ClearIRAMandDSPJITCodespaceReset() { - ClearCodeSpace(); - CompileDispatcher(); - stubEntryPoint = CompileStub(); + ClearCodeSpace(); + CompileDispatcher(); + stubEntryPoint = CompileStub(); - for (int i = 0x0000; i < 0x10000; i++) - { - blocks[i] = (DSPCompiledCode)stubEntryPoint; - blockLinks[i] = nullptr; - blockSize[i] = 0; - unresolvedJumps[i].clear(); - } - g_dsp.reset_dspjit_codespace = false; + for (int i = 0x0000; i < 0x10000; i++) + { + blocks[i] = (DSPCompiledCode)stubEntryPoint; + blockLinks[i] = nullptr; + blockSize[i] = 0; + unresolvedJumps[i].clear(); + } + g_dsp.reset_dspjit_codespace = false; } - // Must go out of block if exception is detected void DSPEmitter::checkExceptions(u32 retval) { - // Check for interrupts and exceptions - TEST(8, M(&g_dsp.exceptions), Imm8(0xff)); - FixupBranch skipCheck = J_CC(CC_Z, true); + // Check for interrupts and exceptions + TEST(8, M(&g_dsp.exceptions), Imm8(0xff)); + FixupBranch skipCheck = J_CC(CC_Z, true); - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC)); + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC)); - DSPJitRegCache c(gpr); - gpr.SaveRegs(); - ABI_CallFunction((void *)&DSPCore_CheckExceptions); - MOV(32, R(EAX), Imm32(retval)); - JMP(returnDispatcher, true); - gpr.LoadRegs(false); - gpr.FlushRegs(c,false); + DSPJitRegCache c(gpr); + gpr.SaveRegs(); + ABI_CallFunction((void*)&DSPCore_CheckExceptions); + MOV(32, R(EAX), Imm32(retval)); + JMP(returnDispatcher, true); + gpr.LoadRegs(false); + gpr.FlushRegs(c, false); - SetJumpTarget(skipCheck); + SetJumpTarget(skipCheck); } bool DSPEmitter::FlagsNeeded() { - if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || - (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) - return true; - else - return false; + if (!(DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_START_OF_INST) || + (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_UPDATE_SR)) + return true; + else + return false; } void DSPEmitter::FallBackToInterpreter(UDSPInstruction inst) { - if (opTable[inst]->reads_pc) - { - // Increment PC - we shouldn't need to do this for every instruction. only for branches and end of block. - // Fallbacks to interpreter need this for fetching immediate values + if (opTable[inst]->reads_pc) + { + // Increment PC - we shouldn't need to do this for every instruction. only for branches and end + // of block. + // Fallbacks to interpreter need this for fetching immediate values - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1)); - } + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1)); + } - // Fall back to interpreter - gpr.PushRegs(); - _assert_msg_(DSPLLE, opTable[inst]->intFunc, "No function for %04x",inst); - ABI_CallFunctionC16((void*)opTable[inst]->intFunc, inst); - gpr.PopRegs(); + // Fall back to interpreter + gpr.PushRegs(); + _assert_msg_(DSPLLE, opTable[inst]->intFunc, "No function for %04x", inst); + ABI_CallFunctionC16((void*)opTable[inst]->intFunc, inst); + gpr.PopRegs(); } void DSPEmitter::EmitInstruction(UDSPInstruction inst) { - const DSPOPCTemplate *tinst = GetOpTemplate(inst); - bool ext_is_jit = false; + const DSPOPCTemplate* tinst = GetOpTemplate(inst); + bool ext_is_jit = false; - // Call extended - if (tinst->extended) - { - if ((inst >> 12) == 0x3) - { - if (! extOpTable[inst & 0x7F]->jitFunc) - { - // Fall back to interpreter - gpr.PushRegs(); - ABI_CallFunctionC16((void*)extOpTable[inst & 0x7F]->intFunc, inst); - gpr.PopRegs(); - INFO_LOG(DSPLLE, "Instruction not JITed(ext part): %04x\n", inst); - ext_is_jit = false; - } - else - { - (this->*extOpTable[inst & 0x7F]->jitFunc)(inst); - ext_is_jit = true; - } - } - else - { - if (!extOpTable[inst & 0xFF]->jitFunc) - { - // Fall back to interpreter - gpr.PushRegs(); - ABI_CallFunctionC16((void*)extOpTable[inst & 0xFF]->intFunc, inst); - gpr.PopRegs(); - INFO_LOG(DSPLLE, "Instruction not JITed(ext part): %04x\n", inst); - ext_is_jit = false; - } - else - { - (this->*extOpTable[inst & 0xFF]->jitFunc)(inst); - ext_is_jit = true; - } - } - } + // Call extended + if (tinst->extended) + { + if ((inst >> 12) == 0x3) + { + if (!extOpTable[inst & 0x7F]->jitFunc) + { + // Fall back to interpreter + gpr.PushRegs(); + ABI_CallFunctionC16((void*)extOpTable[inst & 0x7F]->intFunc, inst); + gpr.PopRegs(); + INFO_LOG(DSPLLE, "Instruction not JITed(ext part): %04x\n", inst); + ext_is_jit = false; + } + else + { + (this->*extOpTable[inst & 0x7F]->jitFunc)(inst); + ext_is_jit = true; + } + } + else + { + if (!extOpTable[inst & 0xFF]->jitFunc) + { + // Fall back to interpreter + gpr.PushRegs(); + ABI_CallFunctionC16((void*)extOpTable[inst & 0xFF]->intFunc, inst); + gpr.PopRegs(); + INFO_LOG(DSPLLE, "Instruction not JITed(ext part): %04x\n", inst); + ext_is_jit = false; + } + else + { + (this->*extOpTable[inst & 0xFF]->jitFunc)(inst); + ext_is_jit = true; + } + } + } - // Main instruction - if (!opTable[inst]->jitFunc) - { - FallBackToInterpreter(inst); - INFO_LOG(DSPLLE, "Instruction not JITed(main part): %04x\n", inst); - } - else - { - (this->*opTable[inst]->jitFunc)(inst); - } + // Main instruction + if (!opTable[inst]->jitFunc) + { + FallBackToInterpreter(inst); + INFO_LOG(DSPLLE, "Instruction not JITed(main part): %04x\n", inst); + } + else + { + (this->*opTable[inst]->jitFunc)(inst); + } - // Backlog - if (tinst->extended) - { - if (!ext_is_jit) - { - //need to call the online cleanup function because - //the writeBackLog gets populated at runtime - gpr.PushRegs(); - ABI_CallFunction((void*)::applyWriteBackLog); - gpr.PopRegs(); - } - else - { - popExtValueToReg(); - } - } + // Backlog + if (tinst->extended) + { + if (!ext_is_jit) + { + // need to call the online cleanup function because + // the writeBackLog gets populated at runtime + gpr.PushRegs(); + ABI_CallFunction((void*)::applyWriteBackLog); + gpr.PopRegs(); + } + else + { + popExtValueToReg(); + } + } } void DSPEmitter::Compile(u16 start_addr) { - // Remember the current block address for later - startAddr = start_addr; - unresolvedJumps[start_addr].clear(); + // Remember the current block address for later + startAddr = start_addr; + unresolvedJumps[start_addr].clear(); - const u8 *entryPoint = AlignCode16(); + const u8* entryPoint = AlignCode16(); - /* - // Check for other exceptions - if (dsp_SR_is_flag_set(SR_INT_ENABLE)) - return; + /* + // Check for other exceptions + if (dsp_SR_is_flag_set(SR_INT_ENABLE)) + return; - if (g_dsp.exceptions == 0) - return; - */ + if (g_dsp.exceptions == 0) + return; + */ - gpr.LoadRegs(); + gpr.LoadRegs(); - blockLinkEntry = GetCodePtr(); + blockLinkEntry = GetCodePtr(); - compilePC = start_addr; - bool fixup_pc = false; - blockSize[start_addr] = 0; + compilePC = start_addr; + bool fixup_pc = false; + blockSize[start_addr] = 0; - while (compilePC < start_addr + MAX_BLOCK_SIZE) - { - if (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_CHECK_INT) - checkExceptions(blockSize[start_addr]); + while (compilePC < start_addr + MAX_BLOCK_SIZE) + { + if (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_CHECK_INT) + checkExceptions(blockSize[start_addr]); - UDSPInstruction inst = dsp_imem_read(compilePC); - const DSPOPCTemplate *opcode = GetOpTemplate(inst); + UDSPInstruction inst = dsp_imem_read(compilePC); + const DSPOPCTemplate* opcode = GetOpTemplate(inst); - EmitInstruction(inst); + EmitInstruction(inst); - blockSize[start_addr]++; - compilePC += opcode->size; + blockSize[start_addr]++; + compilePC += opcode->size; - // If the block was trying to link into itself, remove the link - unresolvedJumps[start_addr].remove(compilePC); + // If the block was trying to link into itself, remove the link + unresolvedJumps[start_addr].remove(compilePC); - fixup_pc = true; + fixup_pc = true; - // Handle loop condition, only if current instruction was flagged as a loop destination - // by the analyzer. - if (DSPAnalyzer::code_flags[static_cast(compilePC - 1u)] & DSPAnalyzer::CODE_LOOP_END) - { - MOVZX(32, 16, EAX, M(&(g_dsp.r.st[2]))); - TEST(32, R(EAX), R(EAX)); - FixupBranch rLoopAddressExit = J_CC(CC_LE, true); + // Handle loop condition, only if current instruction was flagged as a loop destination + // by the analyzer. + if (DSPAnalyzer::code_flags[static_cast(compilePC - 1u)] & DSPAnalyzer::CODE_LOOP_END) + { + MOVZX(32, 16, EAX, M(&(g_dsp.r.st[2]))); + TEST(32, R(EAX), R(EAX)); + FixupBranch rLoopAddressExit = J_CC(CC_LE, true); - MOVZX(32, 16, EAX, M(&g_dsp.r.st[3])); - TEST(32, R(EAX), R(EAX)); - FixupBranch rLoopCounterExit = J_CC(CC_LE, true); + MOVZX(32, 16, EAX, M(&g_dsp.r.st[3])); + TEST(32, R(EAX), R(EAX)); + FixupBranch rLoopCounterExit = J_CC(CC_LE, true); - if (!opcode->branch) - { - //branch insns update the g_dsp.pc - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC)); - } + if (!opcode->branch) + { + // branch insns update the g_dsp.pc + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC)); + } - // These functions branch and therefore only need to be called in the - // end of each block and in this order - DSPJitRegCache c(gpr); - HandleLoop(); - gpr.SaveRegs(); - if (!DSPHost::OnThread() && DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) - { - MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); - } - else - { - MOV(16, R(EAX), Imm16(blockSize[start_addr])); - } - JMP(returnDispatcher, true); - gpr.LoadRegs(false); - gpr.FlushRegs(c,false); + // These functions branch and therefore only need to be called in the + // end of each block and in this order + DSPJitRegCache c(gpr); + HandleLoop(); + gpr.SaveRegs(); + if (!DSPHost::OnThread() && DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) + { + MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); + } + else + { + MOV(16, R(EAX), Imm16(blockSize[start_addr])); + } + JMP(returnDispatcher, true); + gpr.LoadRegs(false); + gpr.FlushRegs(c, false); - SetJumpTarget(rLoopAddressExit); - SetJumpTarget(rLoopCounterExit); - } + SetJumpTarget(rLoopAddressExit); + SetJumpTarget(rLoopCounterExit); + } - if (opcode->branch) - { - //don't update g_dsp.pc -- the branch insn already did - fixup_pc = false; - if (opcode->uncond_branch) - { - break; - } - else if (!opcode->jitFunc) - { - //look at g_dsp.pc if we actually branched - MOV(16, R(AX), M(&g_dsp.pc)); - CMP(16, R(AX), Imm16(compilePC)); - FixupBranch rNoBranch = J_CC(CC_Z, true); + if (opcode->branch) + { + // don't update g_dsp.pc -- the branch insn already did + fixup_pc = false; + if (opcode->uncond_branch) + { + break; + } + else if (!opcode->jitFunc) + { + // look at g_dsp.pc if we actually branched + MOV(16, R(AX), M(&g_dsp.pc)); + CMP(16, R(AX), Imm16(compilePC)); + FixupBranch rNoBranch = J_CC(CC_Z, true); - DSPJitRegCache c(gpr); - //don't update g_dsp.pc -- the branch insn already did - gpr.SaveRegs(); - if (!DSPHost::OnThread() && DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) - { - MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); - } - else - { - MOV(16, R(EAX), Imm16(blockSize[start_addr])); - } - JMP(returnDispatcher, true); - gpr.LoadRegs(false); - gpr.FlushRegs(c,false); + DSPJitRegCache c(gpr); + // don't update g_dsp.pc -- the branch insn already did + gpr.SaveRegs(); + if (!DSPHost::OnThread() && + DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) + { + MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); + } + else + { + MOV(16, R(EAX), Imm16(blockSize[start_addr])); + } + JMP(returnDispatcher, true); + gpr.LoadRegs(false); + gpr.FlushRegs(c, false); - SetJumpTarget(rNoBranch); - } - } + SetJumpTarget(rNoBranch); + } + } - // End the block if we're before an idle skip address - if (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_IDLE_SKIP) - { - break; - } - } + // End the block if we're before an idle skip address + if (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_IDLE_SKIP) + { + break; + } + } - if (fixup_pc) - { - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC)); - } + if (fixup_pc) + { + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC)); + } - blocks[start_addr] = (DSPCompiledCode)entryPoint; + blocks[start_addr] = (DSPCompiledCode)entryPoint; - // Mark this block as a linkable destination if it does not contain - // any unresolved CALL's - if (unresolvedJumps[start_addr].empty()) - { - blockLinks[start_addr] = blockLinkEntry; + // Mark this block as a linkable destination if it does not contain + // any unresolved CALL's + if (unresolvedJumps[start_addr].empty()) + { + blockLinks[start_addr] = blockLinkEntry; - for (u16 i = 0x0000; i < 0xffff; ++i) - { - if (!unresolvedJumps[i].empty()) - { - // Check if there were any blocks waiting for this block to be linkable - size_t size = unresolvedJumps[i].size(); - unresolvedJumps[i].remove(start_addr); - if (unresolvedJumps[i].size() < size) - { - // Mark the block to be recompiled again - blocks[i] = (DSPCompiledCode)stubEntryPoint; - blockLinks[i] = nullptr; - blockSize[i] = 0; - } - } - } - } + for (u16 i = 0x0000; i < 0xffff; ++i) + { + if (!unresolvedJumps[i].empty()) + { + // Check if there were any blocks waiting for this block to be linkable + size_t size = unresolvedJumps[i].size(); + unresolvedJumps[i].remove(start_addr); + if (unresolvedJumps[i].size() < size) + { + // Mark the block to be recompiled again + blocks[i] = (DSPCompiledCode)stubEntryPoint; + blockLinks[i] = nullptr; + blockSize[i] = 0; + } + } + } + } - if (blockSize[start_addr] == 0) - { - // just a safeguard, should never happen anymore. - // if it does we might get stuck over in RunForCycles. - ERROR_LOG(DSPLLE, "Block at 0x%04x has zero size", start_addr); - blockSize[start_addr] = 1; - } + if (blockSize[start_addr] == 0) + { + // just a safeguard, should never happen anymore. + // if it does we might get stuck over in RunForCycles. + ERROR_LOG(DSPLLE, "Block at 0x%04x has zero size", start_addr); + blockSize[start_addr] = 1; + } - gpr.SaveRegs(); - if (!DSPHost::OnThread() && DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) - { - MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); - } - else - { - MOV(16, R(EAX), Imm16(blockSize[start_addr])); - } - JMP(returnDispatcher, true); + gpr.SaveRegs(); + if (!DSPHost::OnThread() && DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) + { + MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); + } + else + { + MOV(16, R(EAX), Imm16(blockSize[start_addr])); + } + JMP(returnDispatcher, true); } -const u8 *DSPEmitter::CompileStub() +const u8* DSPEmitter::CompileStub() { - const u8 *entryPoint = AlignCode16(); - ABI_CallFunction((void *)&CompileCurrent); - XOR(32, R(EAX), R(EAX)); // Return 0 cycles executed - JMP(returnDispatcher); - return entryPoint; + const u8* entryPoint = AlignCode16(); + ABI_CallFunction((void*)&CompileCurrent); + XOR(32, R(EAX), R(EAX)); // Return 0 cycles executed + JMP(returnDispatcher); + return entryPoint; } void DSPEmitter::CompileDispatcher() { - enterDispatcher = AlignCode16(); - // We don't use floating point (high 16 bits). - BitSet32 registers_used = ABI_ALL_CALLEE_SAVED & BitSet32(0xffff); - ABI_PushRegistersAndAdjustStack(registers_used, 8); + enterDispatcher = AlignCode16(); + // We don't use floating point (high 16 bits). + BitSet32 registers_used = ABI_ALL_CALLEE_SAVED & BitSet32(0xffff); + ABI_PushRegistersAndAdjustStack(registers_used, 8); - const u8 *dispatcherLoop = GetCodePtr(); + const u8* dispatcherLoop = GetCodePtr(); - FixupBranch exceptionExit; - if (DSPHost::OnThread()) - { - CMP(8, M(const_cast(&g_dsp.external_interrupt_waiting)), Imm8(0)); - exceptionExit = J_CC(CC_NE); - } + FixupBranch exceptionExit; + if (DSPHost::OnThread()) + { + CMP(8, M(const_cast(&g_dsp.external_interrupt_waiting)), Imm8(0)); + exceptionExit = J_CC(CC_NE); + } - // Check for DSP halt - TEST(8, M(&g_dsp.cr), Imm8(CR_HALT)); - FixupBranch _halt = J_CC(CC_NE); + // Check for DSP halt + TEST(8, M(&g_dsp.cr), Imm8(CR_HALT)); + FixupBranch _halt = J_CC(CC_NE); + // Execute block. Cycles executed returned in EAX. + MOVZX(64, 16, ECX, M(&g_dsp.pc)); + MOV(64, R(RBX), ImmPtr(blocks)); + JMPptr(MComplex(RBX, RCX, SCALE_8, 0)); - // Execute block. Cycles executed returned in EAX. - MOVZX(64, 16, ECX, M(&g_dsp.pc)); - MOV(64, R(RBX), ImmPtr(blocks)); - JMPptr(MComplex(RBX, RCX, SCALE_8, 0)); + returnDispatcher = GetCodePtr(); - returnDispatcher = GetCodePtr(); + // Decrement cyclesLeft + SUB(16, M(&g_cycles_left), R(EAX)); - // Decrement cyclesLeft - SUB(16, M(&g_cycles_left), R(EAX)); + J_CC(CC_A, dispatcherLoop); - J_CC(CC_A, dispatcherLoop); - - // DSP gave up the remaining cycles. - SetJumpTarget(_halt); - if (DSPHost::OnThread()) - { - SetJumpTarget(exceptionExit); - } - //MOV(32, M(&cyclesLeft), Imm32(0)); - ABI_PopRegistersAndAdjustStack(registers_used, 8); - RET(); + // DSP gave up the remaining cycles. + SetJumpTarget(_halt); + if (DSPHost::OnThread()) + { + SetJumpTarget(exceptionExit); + } + // MOV(32, M(&cyclesLeft), Imm32(0)); + ABI_PopRegistersAndAdjustStack(registers_used, 8); + RET(); } diff --git a/Source/Core/Core/DSP/DSPEmitter.h b/Source/Core/Core/DSP/DSPEmitter.h index dc5600c668..094827141c 100644 --- a/Source/Core/Core/DSP/DSPEmitter.h +++ b/Source/Core/Core/DSP/DSPEmitter.h @@ -13,270 +13,271 @@ #include "Core/DSP/Jit/DSPJitRegCache.h" #define COMPILED_CODE_SIZE 2097152 -#define MAX_BLOCKS 0x10000 +#define MAX_BLOCKS 0x10000 typedef u32 (*DSPCompiledCode)(); -typedef const u8 *Block; +typedef const u8* Block; class DSPEmitter : public Gen::X64CodeBlock { public: - DSPEmitter(); - ~DSPEmitter(); + DSPEmitter(); + ~DSPEmitter(); - Block m_compiledCode; + Block m_compiledCode; - void EmitInstruction(UDSPInstruction inst); - void ClearIRAM(); - void ClearIRAMandDSPJITCodespaceReset(); + void EmitInstruction(UDSPInstruction inst); + void ClearIRAM(); + void ClearIRAMandDSPJITCodespaceReset(); - void CompileDispatcher(); - Block CompileStub(); - void Compile(u16 start_addr); + void CompileDispatcher(); + Block CompileStub(); + void Compile(u16 start_addr); - bool FlagsNeeded(); + bool FlagsNeeded(); - void FallBackToInterpreter(UDSPInstruction inst); + void FallBackToInterpreter(UDSPInstruction inst); - // CC Util - void Update_SR_Register64(Gen::X64Reg val = Gen::EAX); - void Update_SR_Register64_Carry(Gen::X64Reg val, Gen::X64Reg carry_ovfl, bool carry_eq = false); - void Update_SR_Register16(Gen::X64Reg val = Gen::EAX); - void Update_SR_Register16_OverS32(Gen::X64Reg val = Gen::EAX); + // CC Util + void Update_SR_Register64(Gen::X64Reg val = Gen::EAX); + void Update_SR_Register64_Carry(Gen::X64Reg val, Gen::X64Reg carry_ovfl, bool carry_eq = false); + void Update_SR_Register16(Gen::X64Reg val = Gen::EAX); + void Update_SR_Register16_OverS32(Gen::X64Reg val = Gen::EAX); - // Register helpers - void setCompileSR(u16 bit); - void clrCompileSR(u16 bit); - void checkExceptions(u32 retval); + // Register helpers + void setCompileSR(u16 bit); + void clrCompileSR(u16 bit); + void checkExceptions(u32 retval); - // Memory helper functions - void increment_addr_reg(int reg); - void decrement_addr_reg(int reg); - void increase_addr_reg(int reg, int ix_reg); - void decrease_addr_reg(int reg); - void imem_read(Gen::X64Reg address); - void dmem_read(Gen::X64Reg address); - void dmem_read_imm(u16 addr); - void dmem_write(Gen::X64Reg value); - void dmem_write_imm(u16 addr, Gen::X64Reg value); + // Memory helper functions + void increment_addr_reg(int reg); + void decrement_addr_reg(int reg); + void increase_addr_reg(int reg, int ix_reg); + void decrease_addr_reg(int reg); + void imem_read(Gen::X64Reg address); + void dmem_read(Gen::X64Reg address); + void dmem_read_imm(u16 addr); + void dmem_write(Gen::X64Reg value); + void dmem_write_imm(u16 addr, Gen::X64Reg value); - // Ext command helpers - void popExtValueToReg(); - void pushExtValueFromMem(u16 dreg, u16 sreg); - void pushExtValueFromMem2(u16 dreg, u16 sreg); + // Ext command helpers + void popExtValueToReg(); + void pushExtValueFromMem(u16 dreg, u16 sreg); + void pushExtValueFromMem2(u16 dreg, u16 sreg); - // Ext commands - void l(const UDSPInstruction opc); - void ln(const UDSPInstruction opc); - void ls(const UDSPInstruction opc); - void lsn(const UDSPInstruction opc); - void lsm(const UDSPInstruction opc); - void lsnm(const UDSPInstruction opc); - void sl(const UDSPInstruction opc); - void sln(const UDSPInstruction opc); - void slm(const UDSPInstruction opc); - void slnm(const UDSPInstruction opc); - void s(const UDSPInstruction opc); - void sn(const UDSPInstruction opc); - void ld(const UDSPInstruction opc); - void ldax(const UDSPInstruction opc); - void ldn(const UDSPInstruction opc); - void ldaxn(const UDSPInstruction opc); - void ldm(const UDSPInstruction opc); - void ldaxm(const UDSPInstruction opc); - void ldnm(const UDSPInstruction opc); - void ldaxnm(const UDSPInstruction opc); - void mv(const UDSPInstruction opc); - void dr(const UDSPInstruction opc); - void ir(const UDSPInstruction opc); - void nr(const UDSPInstruction opc); - void nop(const UDSPInstruction opc) {} + // Ext commands + void l(const UDSPInstruction opc); + void ln(const UDSPInstruction opc); + void ls(const UDSPInstruction opc); + void lsn(const UDSPInstruction opc); + void lsm(const UDSPInstruction opc); + void lsnm(const UDSPInstruction opc); + void sl(const UDSPInstruction opc); + void sln(const UDSPInstruction opc); + void slm(const UDSPInstruction opc); + void slnm(const UDSPInstruction opc); + void s(const UDSPInstruction opc); + void sn(const UDSPInstruction opc); + void ld(const UDSPInstruction opc); + void ldax(const UDSPInstruction opc); + void ldn(const UDSPInstruction opc); + void ldaxn(const UDSPInstruction opc); + void ldm(const UDSPInstruction opc); + void ldaxm(const UDSPInstruction opc); + void ldnm(const UDSPInstruction opc); + void ldaxnm(const UDSPInstruction opc); + void mv(const UDSPInstruction opc); + void dr(const UDSPInstruction opc); + void ir(const UDSPInstruction opc); + void nr(const UDSPInstruction opc); + void nop(const UDSPInstruction opc) {} + // Command helpers + void dsp_reg_stack_push(int stack_reg); + void dsp_reg_stack_pop(int stack_reg); + void dsp_reg_store_stack(int stack_reg, Gen::X64Reg host_sreg = Gen::EDX); + void dsp_reg_load_stack(int stack_reg, Gen::X64Reg host_dreg = Gen::EDX); + void dsp_reg_store_stack_imm(int stack_reg, u16 val); + void dsp_op_write_reg(int reg, Gen::X64Reg host_sreg); + void dsp_op_write_reg_imm(int reg, u16 val); + void dsp_conditional_extend_accum(int reg); + void dsp_conditional_extend_accum_imm(int reg, u16 val); + void dsp_op_read_reg_dont_saturate(int reg, Gen::X64Reg host_dreg, + DSPJitSignExtend extend = NONE); + void dsp_op_read_reg(int reg, Gen::X64Reg host_dreg, DSPJitSignExtend extend = NONE); - // Command helpers - void dsp_reg_stack_push(int stack_reg); - void dsp_reg_stack_pop(int stack_reg); - void dsp_reg_store_stack(int stack_reg, Gen::X64Reg host_sreg = Gen::EDX); - void dsp_reg_load_stack(int stack_reg, Gen::X64Reg host_dreg = Gen::EDX); - void dsp_reg_store_stack_imm(int stack_reg, u16 val); - void dsp_op_write_reg(int reg, Gen::X64Reg host_sreg); - void dsp_op_write_reg_imm(int reg, u16 val); - void dsp_conditional_extend_accum(int reg); - void dsp_conditional_extend_accum_imm(int reg, u16 val); - void dsp_op_read_reg_dont_saturate(int reg, Gen::X64Reg host_dreg, DSPJitSignExtend extend = NONE); - void dsp_op_read_reg(int reg, Gen::X64Reg host_dreg, DSPJitSignExtend extend = NONE); + // Commands + void dar(const UDSPInstruction opc); + void iar(const UDSPInstruction opc); + void subarn(const UDSPInstruction opc); + void addarn(const UDSPInstruction opc); + void sbclr(const UDSPInstruction opc); + void sbset(const UDSPInstruction opc); + void srbith(const UDSPInstruction opc); + void lri(const UDSPInstruction opc); + void lris(const UDSPInstruction opc); + void mrr(const UDSPInstruction opc); + void nx(const UDSPInstruction opc); - // Commands - void dar(const UDSPInstruction opc); - void iar(const UDSPInstruction opc); - void subarn(const UDSPInstruction opc); - void addarn(const UDSPInstruction opc); - void sbclr(const UDSPInstruction opc); - void sbset(const UDSPInstruction opc); - void srbith(const UDSPInstruction opc); - void lri(const UDSPInstruction opc); - void lris(const UDSPInstruction opc); - void mrr(const UDSPInstruction opc); - void nx(const UDSPInstruction opc); + // Branch + void HandleLoop(); + void jcc(const UDSPInstruction opc); + void jmprcc(const UDSPInstruction opc); + void call(const UDSPInstruction opc); + void callr(const UDSPInstruction opc); + void ifcc(const UDSPInstruction opc); + void ret(const UDSPInstruction opc); + void rti(const UDSPInstruction opc); + void halt(const UDSPInstruction opc); + void loop(const UDSPInstruction opc); + void loopi(const UDSPInstruction opc); + void bloop(const UDSPInstruction opc); + void bloopi(const UDSPInstruction opc); - // Branch - void HandleLoop(); - void jcc(const UDSPInstruction opc); - void jmprcc(const UDSPInstruction opc); - void call(const UDSPInstruction opc); - void callr(const UDSPInstruction opc); - void ifcc(const UDSPInstruction opc); - void ret(const UDSPInstruction opc); - void rti(const UDSPInstruction opc); - void halt(const UDSPInstruction opc); - void loop(const UDSPInstruction opc); - void loopi(const UDSPInstruction opc); - void bloop(const UDSPInstruction opc); - void bloopi(const UDSPInstruction opc); + // Load/Store + void srs(const UDSPInstruction opc); + void lrs(const UDSPInstruction opc); + void lr(const UDSPInstruction opc); + void sr(const UDSPInstruction opc); + void si(const UDSPInstruction opc); + void lrr(const UDSPInstruction opc); + void lrrd(const UDSPInstruction opc); + void lrri(const UDSPInstruction opc); + void lrrn(const UDSPInstruction opc); + void srr(const UDSPInstruction opc); + void srrd(const UDSPInstruction opc); + void srri(const UDSPInstruction opc); + void srrn(const UDSPInstruction opc); + void ilrr(const UDSPInstruction opc); + void ilrrd(const UDSPInstruction opc); + void ilrri(const UDSPInstruction opc); + void ilrrn(const UDSPInstruction opc); - // Load/Store - void srs(const UDSPInstruction opc); - void lrs(const UDSPInstruction opc); - void lr(const UDSPInstruction opc); - void sr(const UDSPInstruction opc); - void si(const UDSPInstruction opc); - void lrr(const UDSPInstruction opc); - void lrrd(const UDSPInstruction opc); - void lrri(const UDSPInstruction opc); - void lrrn(const UDSPInstruction opc); - void srr(const UDSPInstruction opc); - void srrd(const UDSPInstruction opc); - void srri(const UDSPInstruction opc); - void srrn(const UDSPInstruction opc); - void ilrr(const UDSPInstruction opc); - void ilrrd(const UDSPInstruction opc); - void ilrri(const UDSPInstruction opc); - void ilrrn(const UDSPInstruction opc); + // Arithmetic + void clr(const UDSPInstruction opc); + void clrl(const UDSPInstruction opc); + void andcf(const UDSPInstruction opc); + void andf(const UDSPInstruction opc); + void tst(const UDSPInstruction opc); + void tstaxh(const UDSPInstruction opc); + void cmp(const UDSPInstruction opc); + void cmpar(const UDSPInstruction opc); + void cmpi(const UDSPInstruction opc); + void cmpis(const UDSPInstruction opc); + void xorr(const UDSPInstruction opc); + void andr(const UDSPInstruction opc); + void orr(const UDSPInstruction opc); + void andc(const UDSPInstruction opc); + void orc(const UDSPInstruction opc); + void xorc(const UDSPInstruction opc); + void notc(const UDSPInstruction opc); + void xori(const UDSPInstruction opc); + void andi(const UDSPInstruction opc); + void ori(const UDSPInstruction opc); + void addr(const UDSPInstruction opc); + void addax(const UDSPInstruction opc); + void add(const UDSPInstruction opc); + void addp(const UDSPInstruction opc); + void addaxl(const UDSPInstruction opc); + void addi(const UDSPInstruction opc); + void addis(const UDSPInstruction opc); + void incm(const UDSPInstruction opc); + void inc(const UDSPInstruction opc); + void subr(const UDSPInstruction opc); + void subax(const UDSPInstruction opc); + void sub(const UDSPInstruction opc); + void subp(const UDSPInstruction opc); + void decm(const UDSPInstruction opc); + void dec(const UDSPInstruction opc); + void neg(const UDSPInstruction opc); + void abs(const UDSPInstruction opc); + void movr(const UDSPInstruction opc); + void movax(const UDSPInstruction opc); + void mov(const UDSPInstruction opc); + void lsl16(const UDSPInstruction opc); + void lsr16(const UDSPInstruction opc); + void asr16(const UDSPInstruction opc); + void lsl(const UDSPInstruction opc); + void lsr(const UDSPInstruction opc); + void asl(const UDSPInstruction opc); + void asr(const UDSPInstruction opc); + void lsrn(const UDSPInstruction opc); + void asrn(const UDSPInstruction opc); + void lsrnrx(const UDSPInstruction opc); + void asrnrx(const UDSPInstruction opc); + void lsrnr(const UDSPInstruction opc); + void asrnr(const UDSPInstruction opc); - // Arithmetic - void clr(const UDSPInstruction opc); - void clrl(const UDSPInstruction opc); - void andcf(const UDSPInstruction opc); - void andf(const UDSPInstruction opc); - void tst(const UDSPInstruction opc); - void tstaxh(const UDSPInstruction opc); - void cmp(const UDSPInstruction opc); - void cmpar(const UDSPInstruction opc); - void cmpi(const UDSPInstruction opc); - void cmpis(const UDSPInstruction opc); - void xorr(const UDSPInstruction opc); - void andr(const UDSPInstruction opc); - void orr(const UDSPInstruction opc); - void andc(const UDSPInstruction opc); - void orc(const UDSPInstruction opc); - void xorc(const UDSPInstruction opc); - void notc(const UDSPInstruction opc); - void xori(const UDSPInstruction opc); - void andi(const UDSPInstruction opc); - void ori(const UDSPInstruction opc); - void addr(const UDSPInstruction opc); - void addax(const UDSPInstruction opc); - void add(const UDSPInstruction opc); - void addp(const UDSPInstruction opc); - void addaxl(const UDSPInstruction opc); - void addi(const UDSPInstruction opc); - void addis(const UDSPInstruction opc); - void incm(const UDSPInstruction opc); - void inc(const UDSPInstruction opc); - void subr(const UDSPInstruction opc); - void subax(const UDSPInstruction opc); - void sub(const UDSPInstruction opc); - void subp(const UDSPInstruction opc); - void decm(const UDSPInstruction opc); - void dec(const UDSPInstruction opc); - void neg(const UDSPInstruction opc); - void abs(const UDSPInstruction opc); - void movr(const UDSPInstruction opc); - void movax(const UDSPInstruction opc); - void mov(const UDSPInstruction opc); - void lsl16(const UDSPInstruction opc); - void lsr16(const UDSPInstruction opc); - void asr16(const UDSPInstruction opc); - void lsl(const UDSPInstruction opc); - void lsr(const UDSPInstruction opc); - void asl(const UDSPInstruction opc); - void asr(const UDSPInstruction opc); - void lsrn(const UDSPInstruction opc); - void asrn(const UDSPInstruction opc); - void lsrnrx(const UDSPInstruction opc); - void asrnrx(const UDSPInstruction opc); - void lsrnr(const UDSPInstruction opc); - void asrnr(const UDSPInstruction opc); + // Multipliers + void multiply(); + void multiply_add(); + void multiply_sub(); + void multiply_mulx(u8 axh0, u8 axh1); + void clrp(const UDSPInstruction opc); + void tstprod(const UDSPInstruction opc); + void movp(const UDSPInstruction opc); + void movnp(const UDSPInstruction opc); + void movpz(const UDSPInstruction opc); + void addpaxz(const UDSPInstruction opc); + void mulaxh(const UDSPInstruction opc); + void mul(const UDSPInstruction opc); + void mulac(const UDSPInstruction opc); + void mulmv(const UDSPInstruction opc); + void mulmvz(const UDSPInstruction opc); + void mulx(const UDSPInstruction opc); + void mulxac(const UDSPInstruction opc); + void mulxmv(const UDSPInstruction opc); + void mulxmvz(const UDSPInstruction opc); + void mulc(const UDSPInstruction opc); + void mulcac(const UDSPInstruction opc); + void mulcmv(const UDSPInstruction opc); + void mulcmvz(const UDSPInstruction opc); + void maddx(const UDSPInstruction opc); + void msubx(const UDSPInstruction opc); + void maddc(const UDSPInstruction opc); + void msubc(const UDSPInstruction opc); + void madd(const UDSPInstruction opc); + void msub(const UDSPInstruction opc); - // Multipliers - void multiply(); - void multiply_add(); - void multiply_sub(); - void multiply_mulx(u8 axh0, u8 axh1); - void clrp(const UDSPInstruction opc); - void tstprod(const UDSPInstruction opc); - void movp(const UDSPInstruction opc); - void movnp(const UDSPInstruction opc); - void movpz(const UDSPInstruction opc); - void addpaxz(const UDSPInstruction opc); - void mulaxh(const UDSPInstruction opc); - void mul(const UDSPInstruction opc); - void mulac(const UDSPInstruction opc); - void mulmv(const UDSPInstruction opc); - void mulmvz(const UDSPInstruction opc); - void mulx(const UDSPInstruction opc); - void mulxac(const UDSPInstruction opc); - void mulxmv(const UDSPInstruction opc); - void mulxmvz(const UDSPInstruction opc); - void mulc(const UDSPInstruction opc); - void mulcac(const UDSPInstruction opc); - void mulcmv(const UDSPInstruction opc); - void mulcmvz(const UDSPInstruction opc); - void maddx(const UDSPInstruction opc); - void msubx(const UDSPInstruction opc); - void maddc(const UDSPInstruction opc); - void msubc(const UDSPInstruction opc); - void madd(const UDSPInstruction opc); - void msub(const UDSPInstruction opc); + // CALL this to start the dispatcher + const u8* enterDispatcher; + const u8* reenterDispatcher; + const u8* stubEntryPoint; + const u8* returnDispatcher; + u16 compilePC; + u16 startAddr; + Block* blockLinks; + u16* blockSize; + std::list unresolvedJumps[MAX_BLOCKS]; - // CALL this to start the dispatcher - const u8 *enterDispatcher; - const u8 *reenterDispatcher; - const u8 *stubEntryPoint; - const u8 *returnDispatcher; - u16 compilePC; - u16 startAddr; - Block *blockLinks; - u16 *blockSize; - std::list unresolvedJumps[MAX_BLOCKS]; + DSPJitRegCache gpr; - DSPJitRegCache gpr; private: - DSPCompiledCode *blocks; - Block blockLinkEntry; - u16 compileSR; + DSPCompiledCode* blocks; + Block blockLinkEntry; + u16 compileSR; - // The index of the last stored ext value (compile time). - int storeIndex; - int storeIndex2; + // The index of the last stored ext value (compile time). + int storeIndex; + int storeIndex2; - // Counts down. - // int cycles; + // Counts down. + // int cycles; - void Update_SR_Register(Gen::X64Reg val = Gen::EAX); + void Update_SR_Register(Gen::X64Reg val = Gen::EAX); - void get_long_prod(Gen::X64Reg long_prod = Gen::RAX); - void get_long_prod_round_prodl(Gen::X64Reg long_prod = Gen::RAX); - void set_long_prod(); - void round_long_acc(Gen::X64Reg long_acc = Gen::EAX); - void set_long_acc(int _reg, Gen::X64Reg acc = Gen::EAX); - void get_acc_h(int _reg, Gen::X64Reg acc = Gen::EAX, bool sign = true); - void set_acc_h(int _reg, const Gen::OpArg& arg = R(Gen::EAX)); - void get_acc_m(int _reg, Gen::X64Reg acc = Gen::EAX, bool sign = true); - void set_acc_m(int _reg, const Gen::OpArg& arg = R(Gen::EAX)); - void get_acc_l(int _reg, Gen::X64Reg acc = Gen::EAX, bool sign = true); - void set_acc_l(int _reg, const Gen::OpArg& arg = R(Gen::EAX)); - void get_long_acx(int _reg, Gen::X64Reg acx = Gen::EAX); - void get_ax_l(int _reg, Gen::X64Reg acx = Gen::EAX); - void get_ax_h(int _reg, Gen::X64Reg acc = Gen::EAX); - void get_long_acc(int _reg, Gen::X64Reg acc = Gen::EAX); + void get_long_prod(Gen::X64Reg long_prod = Gen::RAX); + void get_long_prod_round_prodl(Gen::X64Reg long_prod = Gen::RAX); + void set_long_prod(); + void round_long_acc(Gen::X64Reg long_acc = Gen::EAX); + void set_long_acc(int _reg, Gen::X64Reg acc = Gen::EAX); + void get_acc_h(int _reg, Gen::X64Reg acc = Gen::EAX, bool sign = true); + void set_acc_h(int _reg, const Gen::OpArg& arg = R(Gen::EAX)); + void get_acc_m(int _reg, Gen::X64Reg acc = Gen::EAX, bool sign = true); + void set_acc_m(int _reg, const Gen::OpArg& arg = R(Gen::EAX)); + void get_acc_l(int _reg, Gen::X64Reg acc = Gen::EAX, bool sign = true); + void set_acc_l(int _reg, const Gen::OpArg& arg = R(Gen::EAX)); + void get_long_acx(int _reg, Gen::X64Reg acx = Gen::EAX); + void get_ax_l(int _reg, Gen::X64Reg acx = Gen::EAX); + void get_ax_h(int _reg, Gen::X64Reg acc = Gen::EAX); + void get_long_acc(int _reg, Gen::X64Reg acc = Gen::EAX); }; diff --git a/Source/Core/Core/DSP/DSPHWInterface.cpp b/Source/Core/Core/DSP/DSPHWInterface.cpp index 905975cb8d..b1bf47f3d7 100644 --- a/Source/Core/Core/DSP/DSPHWInterface.cpp +++ b/Source/Core/Core/DSP/DSPHWInterface.cpp @@ -3,8 +3,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Common/CommonFuncs.h" #include "Common/CPUDetect.h" +#include "Common/CommonFuncs.h" #include "Common/Intrinsics.h" #include "Common/MemoryUtil.h" #include "Common/Thread.h" @@ -12,8 +12,8 @@ #include "Core/DSP/DSPAccelerator.h" #include "Core/DSP/DSPAnalyzer.h" #include "Core/DSP/DSPCore.h" -#include "Core/DSP/DSPHost.h" #include "Core/DSP/DSPHWInterface.h" +#include "Core/DSP/DSPHost.h" #include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPTables.h" @@ -21,226 +21,234 @@ static void gdsp_do_dma(); void gdsp_ifx_init() { - g_dsp.ifx_regs.fill(0); + g_dsp.ifx_regs.fill(0); - g_dsp.mbox[MAILBOX_CPU].store(0); - g_dsp.mbox[MAILBOX_DSP].store(0); + g_dsp.mbox[MAILBOX_CPU].store(0); + g_dsp.mbox[MAILBOX_DSP].store(0); } u32 gdsp_mbox_peek(Mailbox mbx) { - return g_dsp.mbox[mbx].load(); + return g_dsp.mbox[mbx].load(); } void gdsp_mbox_write_h(Mailbox mbx, u16 val) { - const u32 old_value = g_dsp.mbox[mbx].load(std::memory_order_acquire); - const u32 new_value = (old_value & 0xffff) | (val << 16); + const u32 old_value = g_dsp.mbox[mbx].load(std::memory_order_acquire); + const u32 new_value = (old_value & 0xffff) | (val << 16); - g_dsp.mbox[mbx].store(new_value & ~0x80000000, std::memory_order_release); + g_dsp.mbox[mbx].store(new_value & ~0x80000000, std::memory_order_release); } void gdsp_mbox_write_l(Mailbox mbx, u16 val) { - const u32 old_value = g_dsp.mbox[mbx].load(std::memory_order_acquire); - const u32 new_value = (old_value & ~0xffff) | val; + const u32 old_value = g_dsp.mbox[mbx].load(std::memory_order_acquire); + const u32 new_value = (old_value & ~0xffff) | val; - g_dsp.mbox[mbx].store(new_value | 0x80000000, std::memory_order_release); + g_dsp.mbox[mbx].store(new_value | 0x80000000, std::memory_order_release); #if defined(_DEBUG) || defined(DEBUGFAST) - if (mbx == MAILBOX_DSP) - INFO_LOG(DSP_MAIL, "DSP(WM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(MAILBOX_DSP), g_dsp.pc); - else - INFO_LOG(DSP_MAIL, "CPU(WM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(MAILBOX_CPU), g_dsp.pc); + if (mbx == MAILBOX_DSP) + INFO_LOG(DSP_MAIL, "DSP(WM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(MAILBOX_DSP), + g_dsp.pc); + else + INFO_LOG(DSP_MAIL, "CPU(WM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(MAILBOX_CPU), + g_dsp.pc); #endif } u16 gdsp_mbox_read_h(Mailbox mbx) { - if (g_init_hax && mbx == MAILBOX_DSP) - { - return 0x8054; - } + if (g_init_hax && mbx == MAILBOX_DSP) + { + return 0x8054; + } - return (u16)(g_dsp.mbox[mbx].load() >> 16); // TODO: mask away the top bit? + return (u16)(g_dsp.mbox[mbx].load() >> 16); // TODO: mask away the top bit? } u16 gdsp_mbox_read_l(Mailbox mbx) { - const u32 value = g_dsp.mbox[mbx].load(std::memory_order_acquire); - g_dsp.mbox[mbx].store(value & ~0x80000000, std::memory_order_release); + const u32 value = g_dsp.mbox[mbx].load(std::memory_order_acquire); + g_dsp.mbox[mbx].store(value & ~0x80000000, std::memory_order_release); - if (g_init_hax && mbx == MAILBOX_DSP) - { - g_init_hax = false; - DSPCore_Reset(); - return 0x4348; - } + if (g_init_hax && mbx == MAILBOX_DSP) + { + g_init_hax = false; + DSPCore_Reset(); + return 0x4348; + } #if defined(_DEBUG) || defined(DEBUGFAST) - if (mbx == MAILBOX_DSP) - INFO_LOG(DSP_MAIL, "DSP(RM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(MAILBOX_DSP), g_dsp.pc); - else - INFO_LOG(DSP_MAIL, "CPU(RM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(MAILBOX_CPU), g_dsp.pc); + if (mbx == MAILBOX_DSP) + INFO_LOG(DSP_MAIL, "DSP(RM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(MAILBOX_DSP), + g_dsp.pc); + else + INFO_LOG(DSP_MAIL, "CPU(RM) B:%i M:0x%08x (pc=0x%04x)", mbx, gdsp_mbox_peek(MAILBOX_CPU), + g_dsp.pc); #endif - return (u16)value; + return (u16)value; } void gdsp_ifx_write(u32 addr, u32 val) { - g_dsp_cap->LogIFXWrite(addr, val); + g_dsp_cap->LogIFXWrite(addr, val); - switch (addr & 0xff) - { - case DSP_DIRQ: - if (val & 0x1) - DSPHost::InterruptRequest(); - else - INFO_LOG(DSPLLE, "Unknown Interrupt Request pc=%04x (%04x)", g_dsp.pc, val); - break; + switch (addr & 0xff) + { + case DSP_DIRQ: + if (val & 0x1) + DSPHost::InterruptRequest(); + else + INFO_LOG(DSPLLE, "Unknown Interrupt Request pc=%04x (%04x)", g_dsp.pc, val); + break; - case DSP_DMBH: - gdsp_mbox_write_h(MAILBOX_DSP, val); - break; + case DSP_DMBH: + gdsp_mbox_write_h(MAILBOX_DSP, val); + break; - case DSP_DMBL: - gdsp_mbox_write_l(MAILBOX_DSP, val); - break; + case DSP_DMBL: + gdsp_mbox_write_l(MAILBOX_DSP, val); + break; - case DSP_CMBH: - return gdsp_mbox_write_h(MAILBOX_CPU, val); + case DSP_CMBH: + return gdsp_mbox_write_h(MAILBOX_CPU, val); - case DSP_CMBL: - return gdsp_mbox_write_l(MAILBOX_CPU, val); + case DSP_CMBL: + return gdsp_mbox_write_l(MAILBOX_CPU, val); - case DSP_DSBL: - g_dsp.ifx_regs[DSP_DSBL] = val; - g_dsp.ifx_regs[DSP_DSCR] |= 4; // Doesn't really matter since we do DMA instantly - if (!g_dsp.ifx_regs[DSP_AMDM]) - gdsp_do_dma(); - else - NOTICE_LOG(DSPLLE, "Masked DMA skipped"); - g_dsp.ifx_regs[DSP_DSCR] &= ~4; - g_dsp.ifx_regs[DSP_DSBL] = 0; - break; + case DSP_DSBL: + g_dsp.ifx_regs[DSP_DSBL] = val; + g_dsp.ifx_regs[DSP_DSCR] |= 4; // Doesn't really matter since we do DMA instantly + if (!g_dsp.ifx_regs[DSP_AMDM]) + gdsp_do_dma(); + else + NOTICE_LOG(DSPLLE, "Masked DMA skipped"); + g_dsp.ifx_regs[DSP_DSCR] &= ~4; + g_dsp.ifx_regs[DSP_DSBL] = 0; + break; - case DSP_ACDATA1: // Accelerator write (Zelda type) - "UnkZelda" - dsp_write_aram_d3(val); - break; + case DSP_ACDATA1: // Accelerator write (Zelda type) - "UnkZelda" + dsp_write_aram_d3(val); + break; - case DSP_GAIN: - if (val) - { - INFO_LOG(DSPLLE,"Gain Written: 0x%04x", val); - } - case DSP_DSPA: - case DSP_DSMAH: - case DSP_DSMAL: - case DSP_DSCR: - g_dsp.ifx_regs[addr & 0xFF] = val; - break; -/* - case DSP_ACCAL: - dsp_step_accelerator(); - break; -*/ - default: - if ((addr & 0xff) >= 0xa0) - { - if (pdlabels[(addr & 0xFF) - 0xa0].name && pdlabels[(addr & 0xFF) - 0xa0].description) - { - INFO_LOG(DSPLLE, "%04x MW %s (%04x)", g_dsp.pc, pdlabels[(addr & 0xFF) - 0xa0].name, val); - } - else - { - ERROR_LOG(DSPLLE, "%04x MW %04x (%04x)", g_dsp.pc, addr, val); - } - } - else - { - ERROR_LOG(DSPLLE, "%04x MW %04x (%04x)", g_dsp.pc, addr, val); - } - g_dsp.ifx_regs[addr & 0xFF] = val; - break; - } + case DSP_GAIN: + if (val) + { + INFO_LOG(DSPLLE, "Gain Written: 0x%04x", val); + } + case DSP_DSPA: + case DSP_DSMAH: + case DSP_DSMAL: + case DSP_DSCR: + g_dsp.ifx_regs[addr & 0xFF] = val; + break; + /* + case DSP_ACCAL: + dsp_step_accelerator(); + break; + */ + default: + if ((addr & 0xff) >= 0xa0) + { + if (pdlabels[(addr & 0xFF) - 0xa0].name && pdlabels[(addr & 0xFF) - 0xa0].description) + { + INFO_LOG(DSPLLE, "%04x MW %s (%04x)", g_dsp.pc, pdlabels[(addr & 0xFF) - 0xa0].name, val); + } + else + { + ERROR_LOG(DSPLLE, "%04x MW %04x (%04x)", g_dsp.pc, addr, val); + } + } + else + { + ERROR_LOG(DSPLLE, "%04x MW %04x (%04x)", g_dsp.pc, addr, val); + } + g_dsp.ifx_regs[addr & 0xFF] = val; + break; + } } static u16 _gdsp_ifx_read(u16 addr) { - switch (addr & 0xff) - { - case DSP_DMBH: - return gdsp_mbox_read_h(MAILBOX_DSP); + switch (addr & 0xff) + { + case DSP_DMBH: + return gdsp_mbox_read_h(MAILBOX_DSP); - case DSP_DMBL: - return gdsp_mbox_read_l(MAILBOX_DSP); + case DSP_DMBL: + return gdsp_mbox_read_l(MAILBOX_DSP); - case DSP_CMBH: - return gdsp_mbox_read_h(MAILBOX_CPU); + case DSP_CMBH: + return gdsp_mbox_read_h(MAILBOX_CPU); - case DSP_CMBL: - return gdsp_mbox_read_l(MAILBOX_CPU); + case DSP_CMBL: + return gdsp_mbox_read_l(MAILBOX_CPU); - case DSP_DSCR: - return g_dsp.ifx_regs[addr & 0xFF]; + case DSP_DSCR: + return g_dsp.ifx_regs[addr & 0xFF]; - case DSP_ACCELERATOR: // ADPCM Accelerator reads - return dsp_read_accelerator(); + case DSP_ACCELERATOR: // ADPCM Accelerator reads + return dsp_read_accelerator(); - case DSP_ACDATA1: // Accelerator reads (Zelda type) - "UnkZelda" - return dsp_read_aram_d3(); + case DSP_ACDATA1: // Accelerator reads (Zelda type) - "UnkZelda" + return dsp_read_aram_d3(); - default: - if ((addr & 0xff) >= 0xa0) - { - if (pdlabels[(addr & 0xFF) - 0xa0].name && pdlabels[(addr & 0xFF) - 0xa0].description) - { - INFO_LOG(DSPLLE, "%04x MR %s (%04x)", g_dsp.pc, pdlabels[(addr & 0xFF) - 0xa0].name, g_dsp.ifx_regs[addr & 0xFF]); - } - else - { - ERROR_LOG(DSPLLE, "%04x MR %04x (%04x)", g_dsp.pc, addr, g_dsp.ifx_regs[addr & 0xFF]); - } - } - else - { - ERROR_LOG(DSPLLE, "%04x MR %04x (%04x)", g_dsp.pc, addr, g_dsp.ifx_regs[addr & 0xFF]); - } - return g_dsp.ifx_regs[addr & 0xFF]; - } + default: + if ((addr & 0xff) >= 0xa0) + { + if (pdlabels[(addr & 0xFF) - 0xa0].name && pdlabels[(addr & 0xFF) - 0xa0].description) + { + INFO_LOG(DSPLLE, "%04x MR %s (%04x)", g_dsp.pc, pdlabels[(addr & 0xFF) - 0xa0].name, + g_dsp.ifx_regs[addr & 0xFF]); + } + else + { + ERROR_LOG(DSPLLE, "%04x MR %04x (%04x)", g_dsp.pc, addr, g_dsp.ifx_regs[addr & 0xFF]); + } + } + else + { + ERROR_LOG(DSPLLE, "%04x MR %04x (%04x)", g_dsp.pc, addr, g_dsp.ifx_regs[addr & 0xFF]); + } + return g_dsp.ifx_regs[addr & 0xFF]; + } } u16 gdsp_ifx_read(u16 addr) { - u16 retval = _gdsp_ifx_read(addr); - g_dsp_cap->LogIFXRead(addr, retval); - return retval; + u16 retval = _gdsp_ifx_read(addr); + g_dsp_cap->LogIFXRead(addr, retval); + return retval; } static const u8* gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size) { - UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); + UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); - u8* dst = ((u8*)g_dsp.iram); - for (u32 i = 0; i < size; i += 2) - { - *(u16*)&dst[dsp_addr + i] = Common::swap16(*(const u16*)&g_dsp.cpu_ram[(addr + i) & 0x0fffffff]); - } - WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); + u8* dst = ((u8*)g_dsp.iram); + for (u32 i = 0; i < size; i += 2) + { + *(u16*)&dst[dsp_addr + i] = + Common::swap16(*(const u16*)&g_dsp.cpu_ram[(addr + i) & 0x0fffffff]); + } + WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); - DSPHost::CodeLoaded((const u8*)g_dsp.iram + dsp_addr, size); + DSPHost::CodeLoaded((const u8*)g_dsp.iram + dsp_addr, size); - NOTICE_LOG(DSPLLE, "*** Copy new UCode from 0x%08x to 0x%04x (crc: %8x)", addr, dsp_addr, g_dsp.iram_crc); + NOTICE_LOG(DSPLLE, "*** Copy new UCode from 0x%08x to 0x%04x (crc: %8x)", addr, dsp_addr, + g_dsp.iram_crc); - return dst + dsp_addr; + return dst + dsp_addr; } static const u8* gdsp_idma_out(u16 dsp_addr, u32 addr, u32 size) { - ERROR_LOG(DSPLLE, "*** idma_out IRAM_DSP (0x%04x) -> RAM (0x%08x) : size (0x%08x)", dsp_addr / 2, addr, size); + ERROR_LOG(DSPLLE, "*** idma_out IRAM_DSP (0x%04x) -> RAM (0x%08x) : size (0x%08x)", dsp_addr / 2, + addr, size); - return nullptr; + return nullptr; } #if _M_SSE >= 0x301 @@ -250,92 +258,102 @@ static const __m128i s_mask = _mm_set_epi32(0x0E0F0C0DL, 0x0A0B0809L, 0x06070405 // TODO: These should eat clock cycles. static const u8* gdsp_ddma_in(u16 dsp_addr, u32 addr, u32 size) { - u8* dst = ((u8*)g_dsp.dram); + u8* dst = ((u8*)g_dsp.dram); #if _M_SSE >= 0x301 - if (cpu_info.bSSSE3 && !(size % 16)) - { - for (u32 i = 0; i < size; i += 16) - { - _mm_storeu_si128((__m128i *)&dst[dsp_addr + i], _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF]), s_mask)); - } - } - else + if (cpu_info.bSSSE3 && !(size % 16)) + { + for (u32 i = 0; i < size; i += 16) + { + _mm_storeu_si128( + (__m128i*)&dst[dsp_addr + i], + _mm_shuffle_epi8(_mm_loadu_si128((__m128i*)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF]), + s_mask)); + } + } + else #endif - { - for (u32 i = 0; i < size; i += 2) - { - *(u16*)&dst[dsp_addr + i] = Common::swap16(*(const u16*)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF]); - } - } - INFO_LOG(DSPLLE, "*** ddma_in RAM (0x%08x) -> DRAM_DSP (0x%04x) : size (0x%08x)", addr, dsp_addr / 2, size); + { + for (u32 i = 0; i < size; i += 2) + { + *(u16*)&dst[dsp_addr + i] = + Common::swap16(*(const u16*)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF]); + } + } + INFO_LOG(DSPLLE, "*** ddma_in RAM (0x%08x) -> DRAM_DSP (0x%04x) : size (0x%08x)", addr, + dsp_addr / 2, size); - return dst + dsp_addr; + return dst + dsp_addr; } static const u8* gdsp_ddma_out(u16 dsp_addr, u32 addr, u32 size) { - const u8* src = ((const u8*)g_dsp.dram); + const u8* src = ((const u8*)g_dsp.dram); #if _M_SSE >= 0x301 - if (cpu_info.bSSSE3 && !(size % 16)) - { - for (u32 i = 0; i < size; i += 16) - { - _mm_storeu_si128((__m128i *)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF], _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)&src[dsp_addr + i]), s_mask)); - } - } - else + if (cpu_info.bSSSE3 && !(size % 16)) + { + for (u32 i = 0; i < size; i += 16) + { + _mm_storeu_si128((__m128i*)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF], + _mm_shuffle_epi8(_mm_loadu_si128((__m128i*)&src[dsp_addr + i]), s_mask)); + } + } + else #endif - { - for (u32 i = 0; i < size; i += 2) - { - *(u16*)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF] = Common::swap16(*(const u16*)&src[dsp_addr + i]); - } - } + { + for (u32 i = 0; i < size; i += 2) + { + *(u16*)&g_dsp.cpu_ram[(addr + i) & 0x7FFFFFFF] = + Common::swap16(*(const u16*)&src[dsp_addr + i]); + } + } - INFO_LOG(DSPLLE, "*** ddma_out DRAM_DSP (0x%04x) -> RAM (0x%08x) : size (0x%08x)", dsp_addr / 2, addr, size); + INFO_LOG(DSPLLE, "*** ddma_out DRAM_DSP (0x%04x) -> RAM (0x%08x) : size (0x%08x)", dsp_addr / 2, + addr, size); - return src + dsp_addr; + return src + dsp_addr; } static void gdsp_do_dma() { - u32 addr = (g_dsp.ifx_regs[DSP_DSMAH] << 16) | g_dsp.ifx_regs[DSP_DSMAL]; - u16 ctl = g_dsp.ifx_regs[DSP_DSCR]; - u16 dsp_addr = g_dsp.ifx_regs[DSP_DSPA] * 2; - u16 len = g_dsp.ifx_regs[DSP_DSBL]; + u32 addr = (g_dsp.ifx_regs[DSP_DSMAH] << 16) | g_dsp.ifx_regs[DSP_DSMAL]; + u16 ctl = g_dsp.ifx_regs[DSP_DSCR]; + u16 dsp_addr = g_dsp.ifx_regs[DSP_DSPA] * 2; + u16 len = g_dsp.ifx_regs[DSP_DSBL]; - if (len > 0x4000) - { - ERROR_LOG(DSPLLE, "DMA ERROR: PC: %04x, Control: %04x, Address: %08x, DSP Address: %04x, Size: %04x", g_dsp.pc, ctl, addr, dsp_addr, len); - exit(0); - } + if (len > 0x4000) + { + ERROR_LOG(DSPLLE, + "DMA ERROR: PC: %04x, Control: %04x, Address: %08x, DSP Address: %04x, Size: %04x", + g_dsp.pc, ctl, addr, dsp_addr, len); + exit(0); + } #if defined(_DEBUG) || defined(DEBUGFAST) - DEBUG_LOG(DSPLLE, "DMA pc: %04x, Control: %04x, Address: %08x, DSP Address: %04x, Size: %04x", g_dsp.pc, ctl, addr, dsp_addr, len); + DEBUG_LOG(DSPLLE, "DMA pc: %04x, Control: %04x, Address: %08x, DSP Address: %04x, Size: %04x", + g_dsp.pc, ctl, addr, dsp_addr, len); #endif - const u8* copied_data_ptr = nullptr; - switch (ctl & 0x3) - { - case (DSP_CR_DMEM | DSP_CR_TO_CPU): - copied_data_ptr = gdsp_ddma_out(dsp_addr, addr, len); - break; + const u8* copied_data_ptr = nullptr; + switch (ctl & 0x3) + { + case (DSP_CR_DMEM | DSP_CR_TO_CPU): + copied_data_ptr = gdsp_ddma_out(dsp_addr, addr, len); + break; - case (DSP_CR_DMEM | DSP_CR_FROM_CPU): - copied_data_ptr = gdsp_ddma_in(dsp_addr, addr, len); - break; + case (DSP_CR_DMEM | DSP_CR_FROM_CPU): + copied_data_ptr = gdsp_ddma_in(dsp_addr, addr, len); + break; - case (DSP_CR_IMEM | DSP_CR_TO_CPU): - copied_data_ptr = gdsp_idma_out(dsp_addr, addr, len); - break; + case (DSP_CR_IMEM | DSP_CR_TO_CPU): + copied_data_ptr = gdsp_idma_out(dsp_addr, addr, len); + break; - case (DSP_CR_IMEM | DSP_CR_FROM_CPU): - copied_data_ptr = gdsp_idma_in(dsp_addr, addr, len); - break; - } - - if (copied_data_ptr) - g_dsp_cap->LogDMA(ctl, addr, dsp_addr, len, copied_data_ptr); + case (DSP_CR_IMEM | DSP_CR_FROM_CPU): + copied_data_ptr = gdsp_idma_in(dsp_addr, addr, len); + break; + } + if (copied_data_ptr) + g_dsp_cap->LogDMA(ctl, addr, dsp_addr, len, copied_data_ptr); } diff --git a/Source/Core/Core/DSP/DSPHWInterface.h b/Source/Core/Core/DSP/DSPHWInterface.h index cb491397b0..6038255665 100644 --- a/Source/Core/Core/DSP/DSPHWInterface.h +++ b/Source/Core/Core/DSP/DSPHWInterface.h @@ -9,16 +9,16 @@ enum Mailbox { - MAILBOX_CPU, - MAILBOX_DSP + MAILBOX_CPU, + MAILBOX_DSP }; -u32 gdsp_mbox_peek(Mailbox mbx); +u32 gdsp_mbox_peek(Mailbox mbx); void gdsp_mbox_write_h(Mailbox mbx, u16 val); void gdsp_mbox_write_l(Mailbox mbx, u16 val); -u16 gdsp_mbox_read_h(Mailbox mbx); -u16 gdsp_mbox_read_l(Mailbox mbx); +u16 gdsp_mbox_read_h(Mailbox mbx); +u16 gdsp_mbox_read_l(Mailbox mbx); void gdsp_ifx_init(); void gdsp_ifx_write(u32 addr, u32 val); -u16 gdsp_ifx_read(u16 addr); +u16 gdsp_ifx_read(u16 addr); diff --git a/Source/Core/Core/DSP/DSPHost.h b/Source/Core/Core/DSP/DSPHost.h index b3af7db2ca..687ca5bb84 100644 --- a/Source/Core/Core/DSP/DSPHost.h +++ b/Source/Core/Core/DSP/DSPHost.h @@ -21,6 +21,6 @@ void OSD_AddMessage(const std::string& str, u32 ms); bool OnThread(); bool IsWiiHost(); void InterruptRequest(); -void CodeLoaded(const u8 *ptr, int size); +void CodeLoaded(const u8* ptr, int size); void UpdateDebugger(); } diff --git a/Source/Core/Core/DSP/DSPIntArithmetic.cpp b/Source/Core/Core/DSP/DSPIntArithmetic.cpp index 4bd924939e..1a30c63857 100644 --- a/Source/Core/Core/DSP/DSPIntArithmetic.cpp +++ b/Source/Core/Core/DSP/DSPIntArithmetic.cpp @@ -5,15 +5,15 @@ // Additional copyrights go to Duddie and Tratax (c) 2004 #include "Core/DSP/DSPIntCCUtil.h" -#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPIntUtil.h" +#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPMemoryMap.h" #include "Core/DSP/DSPTables.h" // Arithmetic and accumulator control. -namespace DSPInterpreter { - +namespace DSPInterpreter +{ // CLR $acR // 1000 r001 xxxx xxxx // Clears accumulator $acR @@ -21,11 +21,11 @@ namespace DSPInterpreter { // flags out: --10 0100 void clr(const UDSPInstruction opc) { - u8 reg = (opc >> 11) & 0x1; + u8 reg = (opc >> 11) & 0x1; - dsp_set_long_acc(reg, 0); - Update_SR_Register64(0); - zeroWriteBackLog(); + dsp_set_long_acc(reg, 0); + Update_SR_Register64(0); + zeroWriteBackLog(); } // CLRL $acR.l @@ -35,13 +35,13 @@ void clr(const UDSPInstruction opc) // flags out: --xx xx00 void clrl(const UDSPInstruction opc) { - u8 reg = (opc >> 8) & 0x1; - s64 acc = dsp_round_long_acc(dsp_get_long_acc(reg)); + u8 reg = (opc >> 8) & 0x1; + s64 acc = dsp_round_long_acc(dsp_get_long_acc(reg)); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(reg, acc); - Update_SR_Register64(acc); + dsp_set_long_acc(reg, acc); + Update_SR_Register64(acc); } //---- @@ -55,11 +55,11 @@ void clrl(const UDSPInstruction opc) // flags out: -x-- ---- void andcf(const UDSPInstruction opc) { - u8 reg = (opc >> 8) & 0x1; + u8 reg = (opc >> 8) & 0x1; - u16 imm = dsp_fetch_code(); - u16 val = dsp_get_acc_m(reg); - Update_SR_LZ(((val & imm) == imm) ? true : false); + u16 imm = dsp_fetch_code(); + u16 val = dsp_get_acc_m(reg); + Update_SR_LZ(((val & imm) == imm) ? true : false); } // ANDF $acD.m, #I @@ -72,11 +72,11 @@ void andcf(const UDSPInstruction opc) // flags out: -x-- ---- void andf(const UDSPInstruction opc) { - u8 reg = (opc >> 8) & 0x1; + u8 reg = (opc >> 8) & 0x1; - u16 imm = dsp_fetch_code(); - u16 val = dsp_get_acc_m(reg); - Update_SR_LZ(((val & imm) == 0) ? true : false); + u16 imm = dsp_fetch_code(); + u16 val = dsp_get_acc_m(reg); + Update_SR_LZ(((val & imm) == 0) ? true : false); } //---- @@ -88,11 +88,11 @@ void andf(const UDSPInstruction opc) // flags out: --xx xx00 void tst(const UDSPInstruction opc) { - u8 reg = (opc >> 11) & 0x1; + u8 reg = (opc >> 11) & 0x1; - s64 acc = dsp_get_long_acc(reg); - Update_SR_Register64(acc); - zeroWriteBackLog(); + s64 acc = dsp_get_long_acc(reg); + Update_SR_Register64(acc); + zeroWriteBackLog(); } // TSTAXH $axR.h @@ -102,11 +102,11 @@ void tst(const UDSPInstruction opc) // flags out: --x0 xx00 void tstaxh(const UDSPInstruction opc) { - u8 reg = (opc >> 8) & 0x1; + u8 reg = (opc >> 8) & 0x1; - s16 val = dsp_get_ax_h(reg); - Update_SR_Register16(val); - zeroWriteBackLog(); + s16 val = dsp_get_ax_h(reg); + Update_SR_Register16(val); + zeroWriteBackLog(); } //---- @@ -118,12 +118,13 @@ void tstaxh(const UDSPInstruction opc) // flags out: x-xx xxxx void cmp(const UDSPInstruction opc) { - s64 acc0 = dsp_get_long_acc(0); - s64 acc1 = dsp_get_long_acc(1); - s64 res = dsp_convert_long_acc(acc0 - acc1); + s64 acc0 = dsp_get_long_acc(0); + s64 acc1 = dsp_get_long_acc(1); + s64 res = dsp_convert_long_acc(acc0 - acc1); - Update_SR_Register64(res, isCarry2(acc0, res), isOverflow(acc0, -acc1, res)); // CF -> influence on ABS/0xa100 - zeroWriteBackLog(); + Update_SR_Register64(res, isCarry2(acc0, res), + isOverflow(acc0, -acc1, res)); // CF -> influence on ABS/0xa100 + zeroWriteBackLog(); } // CMPAR $acS axR.h @@ -134,16 +135,16 @@ void cmp(const UDSPInstruction opc) // flags out: x-xx xxxx void cmpar(const UDSPInstruction opc) { - u8 rreg = (opc >> 12) & 0x1; - u8 sreg = (opc >> 11) & 0x1; + u8 rreg = (opc >> 12) & 0x1; + u8 sreg = (opc >> 11) & 0x1; - s64 sr = dsp_get_long_acc(sreg); - s64 rr = (s16)g_dsp.r.ax[rreg].h; - rr <<= 16; - s64 res = dsp_convert_long_acc(sr - rr); + s64 sr = dsp_get_long_acc(sreg); + s64 rr = (s16)g_dsp.r.ax[rreg].h; + rr <<= 16; + s64 res = dsp_convert_long_acc(sr - rr); - Update_SR_Register64(res, isCarry2(sr, res), isOverflow(sr, -rr, res)); - zeroWriteBackLog(); + Update_SR_Register64(res, isCarry2(sr, res), isOverflow(sr, -rr, res)); + zeroWriteBackLog(); } // CMPI $amD, #I @@ -155,13 +156,14 @@ void cmpar(const UDSPInstruction opc) // flags out: x-xx xxxx void cmpi(const UDSPInstruction opc) { - u8 reg = (opc >> 8) & 0x1; + u8 reg = (opc >> 8) & 0x1; - s64 val = dsp_get_long_acc(reg); - s64 imm = (s64)(s16)dsp_fetch_code() << 16; // Immediate is considered to be at M level in the 40-bit accumulator. - s64 res = dsp_convert_long_acc(val - imm); + s64 val = dsp_get_long_acc(reg); + s64 imm = (s64)(s16)dsp_fetch_code() + << 16; // Immediate is considered to be at M level in the 40-bit accumulator. + s64 res = dsp_convert_long_acc(val - imm); - Update_SR_Register64(res, isCarry2(val, res), isOverflow(val, -imm, res)); + Update_SR_Register64(res, isCarry2(val, res), isOverflow(val, -imm, res)); } // CMPIS $acD, #I @@ -173,14 +175,14 @@ void cmpi(const UDSPInstruction opc) // flags out: x-xx xxxx void cmpis(const UDSPInstruction opc) { - u8 areg = (opc >> 8) & 0x1; + u8 areg = (opc >> 8) & 0x1; - s64 acc = dsp_get_long_acc(areg); - s64 val = (s8)opc; - val <<= 16; - s64 res = dsp_convert_long_acc(acc - val); + s64 acc = dsp_get_long_acc(areg); + s64 val = (s8)opc; + val <<= 16; + s64 res = dsp_convert_long_acc(acc - val); - Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -val, res)); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -val, res)); } //---- @@ -194,14 +196,14 @@ void cmpis(const UDSPInstruction opc) // flags out: --xx xx00 void xorr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - u16 accm = g_dsp.r.ac[dreg].m ^ g_dsp.r.ax[sreg].h; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + u16 accm = g_dsp.r.ac[dreg].m ^ g_dsp.r.ax[sreg].h; - zeroWriteBackLogPreserveAcc(dreg); + zeroWriteBackLogPreserveAcc(dreg); - g_dsp.r.ac[dreg].m = accm; - Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + g_dsp.r.ac[dreg].m = accm; + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); } // ANDR $acD.m, $axS.h @@ -213,14 +215,14 @@ void xorr(const UDSPInstruction opc) // flags out: --xx xx00 void andr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - u16 accm = g_dsp.r.ac[dreg].m & g_dsp.r.ax[sreg].h; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + u16 accm = g_dsp.r.ac[dreg].m & g_dsp.r.ax[sreg].h; - zeroWriteBackLogPreserveAcc(dreg); + zeroWriteBackLogPreserveAcc(dreg); - g_dsp.r.ac[dreg].m = accm; - Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + g_dsp.r.ac[dreg].m = accm; + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); } // ORR $acD.m, $axS.h @@ -232,14 +234,14 @@ void andr(const UDSPInstruction opc) // flags out: --xx xx00 void orr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - u16 accm = g_dsp.r.ac[dreg].m | g_dsp.r.ax[sreg].h; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + u16 accm = g_dsp.r.ac[dreg].m | g_dsp.r.ax[sreg].h; - zeroWriteBackLogPreserveAcc(dreg); + zeroWriteBackLogPreserveAcc(dreg); - g_dsp.r.ac[dreg].m = accm; - Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + g_dsp.r.ac[dreg].m = accm; + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); } // ANDC $acD.m, $ac(1-D).m @@ -251,13 +253,13 @@ void orr(const UDSPInstruction opc) // flags out: --xx xx00 void andc(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u16 accm = g_dsp.r.ac[dreg].m & g_dsp.r.ac[1 - dreg].m; + u8 dreg = (opc >> 8) & 0x1; + u16 accm = g_dsp.r.ac[dreg].m & g_dsp.r.ac[1 - dreg].m; - zeroWriteBackLogPreserveAcc(dreg); + zeroWriteBackLogPreserveAcc(dreg); - g_dsp.r.ac[dreg].m = accm; - Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + g_dsp.r.ac[dreg].m = accm; + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); } // ORC $acD.m, $ac(1-D).m @@ -269,13 +271,13 @@ void andc(const UDSPInstruction opc) // flags out: --xx xx00 void orc(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u16 accm = g_dsp.r.ac[dreg].m | g_dsp.r.ac[1 - dreg].m; + u8 dreg = (opc >> 8) & 0x1; + u16 accm = g_dsp.r.ac[dreg].m | g_dsp.r.ac[1 - dreg].m; - zeroWriteBackLogPreserveAcc(dreg); + zeroWriteBackLogPreserveAcc(dreg); - g_dsp.r.ac[dreg].m = accm; - Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + g_dsp.r.ac[dreg].m = accm; + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); } // XORC $acD.m @@ -286,13 +288,13 @@ void orc(const UDSPInstruction opc) // flags out: --xx xx00 void xorc(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u16 accm = g_dsp.r.ac[dreg].m ^ g_dsp.r.ac[1 - dreg].m; + u8 dreg = (opc >> 8) & 0x1; + u16 accm = g_dsp.r.ac[dreg].m ^ g_dsp.r.ac[1 - dreg].m; - zeroWriteBackLogPreserveAcc(dreg); + zeroWriteBackLogPreserveAcc(dreg); - g_dsp.r.ac[dreg].m = accm; - Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + g_dsp.r.ac[dreg].m = accm; + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); } // NOT $acD.m @@ -303,13 +305,13 @@ void xorc(const UDSPInstruction opc) // flags out: --xx xx00 void notc(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u16 accm = g_dsp.r.ac[dreg].m ^ 0xffff; + u8 dreg = (opc >> 8) & 0x1; + u16 accm = g_dsp.r.ac[dreg].m ^ 0xffff; - zeroWriteBackLogPreserveAcc(dreg); + zeroWriteBackLogPreserveAcc(dreg); - g_dsp.r.ac[dreg].m = accm; - Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + g_dsp.r.ac[dreg].m = accm; + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); } // XORI $acD.m, #I @@ -321,11 +323,11 @@ void notc(const UDSPInstruction opc) // flags out: --xx xx00 void xori(const UDSPInstruction opc) { - u8 reg = (opc >> 8) & 0x1; - u16 imm = dsp_fetch_code(); - g_dsp.r.ac[reg].m ^= imm; + u8 reg = (opc >> 8) & 0x1; + u16 imm = dsp_fetch_code(); + g_dsp.r.ac[reg].m ^= imm; - Update_SR_Register16((s16)g_dsp.r.ac[reg].m, false, false, isOverS32(dsp_get_long_acc(reg))); + Update_SR_Register16((s16)g_dsp.r.ac[reg].m, false, false, isOverS32(dsp_get_long_acc(reg))); } // ANDI $acD.m, #I @@ -336,11 +338,11 @@ void xori(const UDSPInstruction opc) // flags out: --xx xx00 void andi(const UDSPInstruction opc) { - u8 reg = (opc >> 8) & 0x1; - u16 imm = dsp_fetch_code(); - g_dsp.r.ac[reg].m &= imm; + u8 reg = (opc >> 8) & 0x1; + u16 imm = dsp_fetch_code(); + g_dsp.r.ac[reg].m &= imm; - Update_SR_Register16((s16)g_dsp.r.ac[reg].m, false, false, isOverS32(dsp_get_long_acc(reg))); + Update_SR_Register16((s16)g_dsp.r.ac[reg].m, false, false, isOverS32(dsp_get_long_acc(reg))); } // ORI $acD.m, #I @@ -351,11 +353,11 @@ void andi(const UDSPInstruction opc) // flags out: --xx xx00 void ori(const UDSPInstruction opc) { - u8 reg = (opc >> 8) & 0x1; - u16 imm = dsp_fetch_code(); - g_dsp.r.ac[reg].m |= imm; + u8 reg = (opc >> 8) & 0x1; + u16 imm = dsp_fetch_code(); + g_dsp.r.ac[reg].m |= imm; - Update_SR_Register16((s16)g_dsp.r.ac[reg].m, false, false, isOverS32(dsp_get_long_acc(reg))); + Update_SR_Register16((s16)g_dsp.r.ac[reg].m, false, false, isOverS32(dsp_get_long_acc(reg))); } //---- @@ -367,35 +369,35 @@ void ori(const UDSPInstruction opc) // flags out: x-xx xxxx void addr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; - s64 acc = dsp_get_long_acc(dreg); - s64 ax = 0; + s64 acc = dsp_get_long_acc(dreg); + s64 ax = 0; - switch (sreg) - { - case DSP_REG_AXL0: - case DSP_REG_AXL1: - ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXL0].l; - break; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXH0].h; - break; - default: - ax = 0; - break; - } + switch (sreg) + { + case DSP_REG_AXL0: + case DSP_REG_AXL1: + ax = (s16)g_dsp.r.ax[sreg - DSP_REG_AXL0].l; + break; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + ax = (s16)g_dsp.r.ax[sreg - DSP_REG_AXH0].h; + break; + default: + ax = 0; + break; + } - ax <<= 16; - s64 res = acc + ax; + ax <<= 16; + s64 res = acc + ax; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); } // ADDAX $acD, $axS @@ -405,18 +407,18 @@ void addr(const UDSPInstruction opc) // flags out: x-xx xxxx void addax(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; - s64 acc = dsp_get_long_acc(dreg); - s64 ax = dsp_get_long_acx(sreg); - s64 res = acc + ax; + s64 acc = dsp_get_long_acc(dreg); + s64 ax = dsp_get_long_acx(sreg); + s64 res = acc + ax; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); } // ADD $acD, $ac(1-D) @@ -426,17 +428,17 @@ void addax(const UDSPInstruction opc) // flags out: x-xx xxxx void add(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - s64 acc0 = dsp_get_long_acc(dreg); - s64 acc1 = dsp_get_long_acc(1 - dreg); - s64 res = acc0 + acc1; + s64 acc0 = dsp_get_long_acc(dreg); + s64 acc1 = dsp_get_long_acc(1 - dreg); + s64 res = acc0 + acc1; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry(acc0, res), isOverflow(acc0, acc1, res)); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc0, res), isOverflow(acc0, acc1, res)); } // ADDP $acD @@ -446,17 +448,17 @@ void add(const UDSPInstruction opc) // flags out: x-xx xxxx void addp(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - s64 acc = dsp_get_long_acc(dreg); - s64 prod = dsp_get_long_prod(); - s64 res = acc + prod; + s64 acc = dsp_get_long_acc(dreg); + s64 prod = dsp_get_long_prod(); + s64 res = acc + prod; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, prod, res)); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, prod, res)); } // ADDAXL $acD, $axS.l @@ -467,19 +469,19 @@ void addp(const UDSPInstruction opc) // flags out: x-xx xxxx void addaxl(const UDSPInstruction opc) { - u8 sreg = (opc >> 9) & 0x1; - u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - u64 acc = dsp_get_long_acc(dreg); - u16 acx = (u16)dsp_get_ax_l(sreg); + u64 acc = dsp_get_long_acc(dreg); + u16 acx = (u16)dsp_get_ax_l(sreg); - u64 res = acc + acx; + u64 res = acc + acx; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, (s64)res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64((s64)res, isCarry(acc, res), isOverflow((s64)acc, (s64)acx, (s64)res)); + dsp_set_long_acc(dreg, (s64)res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64((s64)res, isCarry(acc, res), isOverflow((s64)acc, (s64)acx, (s64)res)); } // ADDI $amR, #I @@ -490,16 +492,16 @@ void addaxl(const UDSPInstruction opc) // flags out: x-xx xxxx void addi(const UDSPInstruction opc) { - u8 areg = (opc >> 8) & 0x1; + u8 areg = (opc >> 8) & 0x1; - s64 acc = dsp_get_long_acc(areg); - s64 imm = (s16)dsp_fetch_code(); - imm <<= 16; - s64 res = acc + imm; + s64 acc = dsp_get_long_acc(areg); + s64 imm = (s16)dsp_fetch_code(); + imm <<= 16; + s64 res = acc + imm; - dsp_set_long_acc(areg, res); - res = dsp_get_long_acc(areg); - Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); + dsp_set_long_acc(areg, res); + res = dsp_get_long_acc(areg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); } // ADDIS $acD, #I @@ -509,16 +511,16 @@ void addi(const UDSPInstruction opc) // flags out: x-xx xxxx void addis(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - s64 acc = dsp_get_long_acc(dreg); - s64 imm = (s8)(u8)opc; - imm <<= 16; - s64 res = acc + imm; + s64 acc = dsp_get_long_acc(dreg); + s64 imm = (s8)(u8)opc; + imm <<= 16; + s64 res = acc + imm; - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); } // INCM $acsD @@ -528,17 +530,17 @@ void addis(const UDSPInstruction opc) // flags out: x-xx xxxx void incm(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - s64 sub = 0x10000; - s64 acc = dsp_get_long_acc(dreg); - s64 res = acc + sub; + s64 sub = 0x10000; + s64 acc = dsp_get_long_acc(dreg); + s64 res = acc + sub; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, sub, res)); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, sub, res)); } // INC $acD @@ -548,16 +550,16 @@ void incm(const UDSPInstruction opc) // flags out: x-xx xxxx void inc(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - s64 acc = dsp_get_long_acc(dreg); - s64 res = acc + 1; + s64 acc = dsp_get_long_acc(dreg); + s64 res = acc + 1; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, 1, res)); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, 1, res)); } //---- @@ -569,35 +571,35 @@ void inc(const UDSPInstruction opc) // flags out: x-xx xxxx void subr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; - s64 acc = dsp_get_long_acc(dreg); - s64 ax = 0; + s64 acc = dsp_get_long_acc(dreg); + s64 ax = 0; - switch (sreg) - { - case DSP_REG_AXL0: - case DSP_REG_AXL1: - ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXL0].l; - break; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXH0].h; - break; - default: - ax = 0; - break; - } + switch (sreg) + { + case DSP_REG_AXL0: + case DSP_REG_AXL1: + ax = (s16)g_dsp.r.ax[sreg - DSP_REG_AXL0].l; + break; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + ax = (s16)g_dsp.r.ax[sreg - DSP_REG_AXH0].h; + break; + default: + ax = 0; + break; + } - ax <<= 16; - s64 res = acc - ax; + ax <<= 16; + s64 res = acc - ax; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -ax, res)); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -ax, res)); } // SUBAX $acD, $axS @@ -607,18 +609,18 @@ void subr(const UDSPInstruction opc) // flags out: x-xx xxxx void subax(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; - s64 acc = dsp_get_long_acc(dreg); - s64 acx = dsp_get_long_acx(sreg); - s64 res = acc - acx; + s64 acc = dsp_get_long_acc(dreg); + s64 acx = dsp_get_long_acx(sreg); + s64 res = acc - acx; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -acx, res)); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -acx, res)); } // SUB $acD, $ac(1-D) @@ -628,17 +630,17 @@ void subax(const UDSPInstruction opc) // flags out: x-xx xxxx void sub(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - s64 acc1 = dsp_get_long_acc(dreg); - s64 acc2 = dsp_get_long_acc(1 - dreg); - s64 res = acc1 - acc2; + s64 acc1 = dsp_get_long_acc(dreg); + s64 acc2 = dsp_get_long_acc(1 - dreg); + s64 res = acc1 - acc2; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry2(acc1, res), isOverflow(acc1, -acc2, res)); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc1, res), isOverflow(acc1, -acc2, res)); } // SUBP $acD @@ -648,17 +650,17 @@ void sub(const UDSPInstruction opc) // flags out: x-xx xxxx void subp(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - s64 acc = dsp_get_long_acc(dreg); - s64 prod = dsp_get_long_prod(); - s64 res = acc - prod; + s64 acc = dsp_get_long_acc(dreg); + s64 prod = dsp_get_long_prod(); + s64 res = acc - prod; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -prod, res)); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -prod, res)); } // DECM $acsD @@ -668,17 +670,17 @@ void subp(const UDSPInstruction opc) // flags out: x-xx xxxx void decm(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x01; + u8 dreg = (opc >> 8) & 0x01; - s64 sub = 0x10000; - s64 acc = dsp_get_long_acc(dreg); - s64 res = acc - sub; + s64 sub = 0x10000; + s64 acc = dsp_get_long_acc(dreg); + s64 res = acc - sub; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -sub, res)); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -sub, res)); } // DEC $acD @@ -688,16 +690,16 @@ void decm(const UDSPInstruction opc) // flags out: x-xx xxxx void dec(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x01; + u8 dreg = (opc >> 8) & 0x01; - s64 acc = dsp_get_long_acc(dreg); - s64 res = acc - 1; + s64 acc = dsp_get_long_acc(dreg); + s64 res = acc - 1; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -1, res)); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -1, res)); } //---- @@ -709,15 +711,15 @@ void dec(const UDSPInstruction opc) // flags out: --xx xx00 void neg(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - s64 acc = dsp_get_long_acc(dreg); - acc = 0 - acc; + s64 acc = dsp_get_long_acc(dreg); + acc = 0 - acc; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(dsp_get_long_acc(dreg)); + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(dsp_get_long_acc(dreg)); } // ABS $acD @@ -727,17 +729,17 @@ void neg(const UDSPInstruction opc) // flags out: --xx xx00 void abs(const UDSPInstruction opc) { - u8 dreg = (opc >> 11) & 0x1; + u8 dreg = (opc >> 11) & 0x1; - s64 acc = dsp_get_long_acc(dreg); + s64 acc = dsp_get_long_acc(dreg); - if (acc < 0) - acc = 0 - acc; + if (acc < 0) + acc = 0 - acc; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(dsp_get_long_acc(dreg)); + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(dsp_get_long_acc(dreg)); } //---- @@ -749,31 +751,31 @@ void abs(const UDSPInstruction opc) // flags out: --xx xx00 void movr(const UDSPInstruction opc) { - u8 areg = (opc >> 8) & 0x1; - u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; + u8 areg = (opc >> 8) & 0x1; + u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; - s64 ax = 0; - switch (sreg) - { - case DSP_REG_AXL0: - case DSP_REG_AXL1: - ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXL0].l; - break; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - ax = (s16)g_dsp.r.ax[sreg-DSP_REG_AXH0].h; - break; - default: - ax = 0; - break; - } - ax <<= 16; - ax &= ~0xffff; + s64 ax = 0; + switch (sreg) + { + case DSP_REG_AXL0: + case DSP_REG_AXL1: + ax = (s16)g_dsp.r.ax[sreg - DSP_REG_AXL0].l; + break; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + ax = (s16)g_dsp.r.ax[sreg - DSP_REG_AXH0].h; + break; + default: + ax = 0; + break; + } + ax <<= 16; + ax &= ~0xffff; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(areg, ax); - Update_SR_Register64(ax); + dsp_set_long_acc(areg, ax); + Update_SR_Register64(ax); } // MOVAX $acD, $axS @@ -783,15 +785,15 @@ void movr(const UDSPInstruction opc) // flags out: --xx xx00 void movax(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; - s64 acx = dsp_get_long_acx(sreg); + s64 acx = dsp_get_long_acx(sreg); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, acx); - Update_SR_Register64(acx); + dsp_set_long_acc(dreg, acx); + Update_SR_Register64(acx); } // MOV $acD, $ac(1-D) @@ -801,13 +803,13 @@ void movax(const UDSPInstruction opc) // flags out: --x0 xx00 void mov(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u64 acc = dsp_get_long_acc(1 - dreg); + u8 dreg = (opc >> 8) & 0x1; + u64 acc = dsp_get_long_acc(1 - dreg); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(acc); + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(acc); } //---- @@ -819,15 +821,15 @@ void mov(const UDSPInstruction opc) // flags out: --xx xx00 void lsl16(const UDSPInstruction opc) { - u8 areg = (opc >> 8) & 0x1; + u8 areg = (opc >> 8) & 0x1; - s64 acc = dsp_get_long_acc(areg); - acc <<= 16; + s64 acc = dsp_get_long_acc(areg); + acc <<= 16; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(areg, acc); - Update_SR_Register64(dsp_get_long_acc(areg)); + dsp_set_long_acc(areg, acc); + Update_SR_Register64(dsp_get_long_acc(areg)); } // LSR16 $acR @@ -837,16 +839,17 @@ void lsl16(const UDSPInstruction opc) // flags out: --xx xx00 void lsr16(const UDSPInstruction opc) { - u8 areg = (opc >> 8) & 0x1; + u8 areg = (opc >> 8) & 0x1; - u64 acc = dsp_get_long_acc(areg); - acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes - acc >>= 16; + u64 acc = dsp_get_long_acc(areg); + acc &= + 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes + acc >>= 16; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(areg, (s64)acc); - Update_SR_Register64(dsp_get_long_acc(areg)); + dsp_set_long_acc(areg, (s64)acc); + Update_SR_Register64(dsp_get_long_acc(areg)); } // ASR16 $acR @@ -856,15 +859,15 @@ void lsr16(const UDSPInstruction opc) // flags out: --xx xx00 void asr16(const UDSPInstruction opc) { - u8 areg = (opc >> 11) & 0x1; + u8 areg = (opc >> 11) & 0x1; - s64 acc = dsp_get_long_acc(areg); - acc >>= 16; + s64 acc = dsp_get_long_acc(areg); + acc >>= 16; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(areg, acc); - Update_SR_Register64(dsp_get_long_acc(areg)); + dsp_set_long_acc(areg, acc); + Update_SR_Register64(dsp_get_long_acc(areg)); } // LSL $acR, #I @@ -874,14 +877,14 @@ void asr16(const UDSPInstruction opc) // flags out: --xx xx00 void lsl(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x01; - u16 shift = opc & 0x3f; - u64 acc = dsp_get_long_acc(rreg); + u8 rreg = (opc >> 8) & 0x01; + u16 shift = opc & 0x3f; + u64 acc = dsp_get_long_acc(rreg); - acc <<= shift; + acc <<= shift; - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); } // LSR $acR, #I @@ -892,20 +895,21 @@ void lsl(const UDSPInstruction opc) // flags out: --xx xx00 void lsr(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x01; - u16 shift; - u64 acc = dsp_get_long_acc(rreg); - acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes + u8 rreg = (opc >> 8) & 0x01; + u16 shift; + u64 acc = dsp_get_long_acc(rreg); + acc &= + 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes - if ((opc & 0x3f) == 0) - shift = 0; - else - shift = 0x40 - (opc & 0x3f); + if ((opc & 0x3f) == 0) + shift = 0; + else + shift = 0x40 - (opc & 0x3f); - acc >>= shift; + acc >>= shift; - dsp_set_long_acc(rreg, (s64)acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); + dsp_set_long_acc(rreg, (s64)acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); } // ASL $acR, #I @@ -915,14 +919,14 @@ void lsr(const UDSPInstruction opc) // flags out: --xx xx00 void asl(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x01; - u16 shift = opc & 0x3f; - u64 acc = dsp_get_long_acc(rreg); + u8 rreg = (opc >> 8) & 0x01; + u16 shift = opc & 0x3f; + u64 acc = dsp_get_long_acc(rreg); - acc <<= shift; + acc <<= shift; - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); } // ASR $acR, #I @@ -933,20 +937,20 @@ void asl(const UDSPInstruction opc) // flags out: --xx xx00 void asr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x01; - u16 shift; + u8 dreg = (opc >> 8) & 0x01; + u16 shift; - if ((opc & 0x3f) == 0) - shift = 0; - else - shift = 0x40 - (opc & 0x3f); + if ((opc & 0x3f) == 0) + shift = 0; + else + shift = 0x40 - (opc & 0x3f); - // arithmetic shift - s64 acc = dsp_get_long_acc(dreg); - acc >>= shift; + // arithmetic shift + s64 acc = dsp_get_long_acc(dreg); + acc >>= shift; - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(dsp_get_long_acc(dreg)); + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(dsp_get_long_acc(dreg)); } // LSRN (fixed parameters) @@ -957,29 +961,29 @@ void asr(const UDSPInstruction opc) // flags out: --xx xx00 void lsrn(const UDSPInstruction opc) { - s16 shift; - u16 accm = (u16)dsp_get_acc_m(1); - u64 acc = dsp_get_long_acc(0); - acc &= 0x000000FFFFFFFFFFULL; + s16 shift; + u16 accm = (u16)dsp_get_acc_m(1); + u64 acc = dsp_get_long_acc(0); + acc &= 0x000000FFFFFFFFFFULL; - if ((accm & 0x3f) == 0) - shift = 0; - else if (accm & 0x40) - shift = -0x40 + (accm & 0x3f); - else - shift = accm & 0x3f; + if ((accm & 0x3f) == 0) + shift = 0; + else if (accm & 0x40) + shift = -0x40 + (accm & 0x3f); + else + shift = accm & 0x3f; - if (shift > 0) - { - acc >>= shift; - } - else if (shift < 0) - { - acc <<= -shift; - } + if (shift > 0) + { + acc >>= shift; + } + else if (shift < 0) + { + acc <<= -shift; + } - dsp_set_long_acc(0, (s64)acc); - Update_SR_Register64(dsp_get_long_acc(0)); + dsp_set_long_acc(0, (s64)acc); + Update_SR_Register64(dsp_get_long_acc(0)); } // ASRN (fixed parameters) @@ -990,28 +994,28 @@ void lsrn(const UDSPInstruction opc) // flags out: --xx xx00 void asrn(const UDSPInstruction opc) { - s16 shift; - u16 accm = (u16)dsp_get_acc_m(1); - s64 acc = dsp_get_long_acc(0); + s16 shift; + u16 accm = (u16)dsp_get_acc_m(1); + s64 acc = dsp_get_long_acc(0); - if ((accm & 0x3f) == 0) - shift = 0; - else if (accm & 0x40) - shift = -0x40 + (accm & 0x3f); - else - shift = accm & 0x3f; + if ((accm & 0x3f) == 0) + shift = 0; + else if (accm & 0x40) + shift = -0x40 + (accm & 0x3f); + else + shift = accm & 0x3f; - if (shift > 0) - { - acc >>= shift; - } - else if (shift < 0) - { - acc <<= -shift; - } + if (shift > 0) + { + acc >>= shift; + } + else if (shift < 0) + { + acc <<= -shift; + } - dsp_set_long_acc(0, acc); - Update_SR_Register64(dsp_get_long_acc(0)); + dsp_set_long_acc(0, acc); + Update_SR_Register64(dsp_get_long_acc(0)); } // LSRNRX $acD, $axS.h @@ -1022,34 +1026,34 @@ void asrn(const UDSPInstruction opc) // flags out: --xx xx00 void lsrnrx(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; - s16 shift; - u16 axh = g_dsp.r.ax[sreg].h; - u64 acc = dsp_get_long_acc(dreg); - acc &= 0x000000FFFFFFFFFFULL; + s16 shift; + u16 axh = g_dsp.r.ax[sreg].h; + u64 acc = dsp_get_long_acc(dreg); + acc &= 0x000000FFFFFFFFFFULL; - if ((axh & 0x3f) == 0) - shift = 0; - else if (axh & 0x40) - shift = -0x40 + (axh & 0x3f); - else - shift = axh & 0x3f; + if ((axh & 0x3f) == 0) + shift = 0; + else if (axh & 0x40) + shift = -0x40 + (axh & 0x3f); + else + shift = axh & 0x3f; - if (shift > 0) - { - acc <<= shift; - } - else if (shift < 0) - { - acc >>= -shift; - } + if (shift > 0) + { + acc <<= shift; + } + else if (shift < 0) + { + acc >>= -shift; + } - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, (s64)acc); - Update_SR_Register64(dsp_get_long_acc(dreg)); + dsp_set_long_acc(dreg, (s64)acc); + Update_SR_Register64(dsp_get_long_acc(dreg)); } // ASRNRX $acD, $axS.h @@ -1060,33 +1064,33 @@ void lsrnrx(const UDSPInstruction opc) // flags out: --xx xx00 void asrnrx(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; - s16 shift; - u16 axh = g_dsp.r.ax[sreg].h; - s64 acc = dsp_get_long_acc(dreg); + s16 shift; + u16 axh = g_dsp.r.ax[sreg].h; + s64 acc = dsp_get_long_acc(dreg); - if ((axh & 0x3f) == 0) - shift = 0; - else if (axh & 0x40) - shift = -0x40 + (axh & 0x3f); - else - shift = axh & 0x3f; + if ((axh & 0x3f) == 0) + shift = 0; + else if (axh & 0x40) + shift = -0x40 + (axh & 0x3f); + else + shift = axh & 0x3f; - if (shift > 0) - { - acc <<= shift; - } - else if (shift < 0) - { - acc >>= -shift; - } + if (shift > 0) + { + acc <<= shift; + } + else if (shift < 0) + { + acc >>= -shift; + } - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(dsp_get_long_acc(dreg)); + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(dsp_get_long_acc(dreg)); } // LSRNR $acD @@ -1097,29 +1101,29 @@ void asrnrx(const UDSPInstruction opc) // flags out: --xx xx00 void lsrnr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - s16 shift; - u16 accm = (u16)dsp_get_acc_m(1 - dreg); - u64 acc = dsp_get_long_acc(dreg); - acc &= 0x000000FFFFFFFFFFULL; + s16 shift; + u16 accm = (u16)dsp_get_acc_m(1 - dreg); + u64 acc = dsp_get_long_acc(dreg); + acc &= 0x000000FFFFFFFFFFULL; - if ((accm & 0x3f) == 0) - shift = 0; - else if (accm & 0x40) - shift = -0x40 + (accm & 0x3f); - else - shift = accm & 0x3f; + if ((accm & 0x3f) == 0) + shift = 0; + else if (accm & 0x40) + shift = -0x40 + (accm & 0x3f); + else + shift = accm & 0x3f; - if (shift > 0) - acc <<= shift; - else if (shift < 0) - acc >>= -shift; + if (shift > 0) + acc <<= shift; + else if (shift < 0) + acc >>= -shift; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, (s64)acc); - Update_SR_Register64(dsp_get_long_acc(dreg)); + dsp_set_long_acc(dreg, (s64)acc); + Update_SR_Register64(dsp_get_long_acc(dreg)); } // ASRNR $acD @@ -1130,30 +1134,28 @@ void lsrnr(const UDSPInstruction opc) // flags out: --xx xx00 void asrnr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - s16 shift; - u16 accm = (u16)dsp_get_acc_m(1 - dreg); - s64 acc = dsp_get_long_acc(dreg); + s16 shift; + u16 accm = (u16)dsp_get_acc_m(1 - dreg); + s64 acc = dsp_get_long_acc(dreg); - if ((accm & 0x3f) == 0) - shift = 0; - else if (accm & 0x40) - shift = -0x40 + (accm & 0x3f); - else - shift = accm & 0x3f; + if ((accm & 0x3f) == 0) + shift = 0; + else if (accm & 0x40) + shift = -0x40 + (accm & 0x3f); + else + shift = accm & 0x3f; - if (shift > 0) - acc <<= shift; - else if (shift < 0) - acc >>= -shift; + if (shift > 0) + acc <<= shift; + else if (shift < 0) + acc >>= -shift; - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(dsp_get_long_acc(dreg)); + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(dsp_get_long_acc(dreg)); } - } // namespace - diff --git a/Source/Core/Core/DSP/DSPIntBranch.cpp b/Source/Core/Core/DSP/DSPIntBranch.cpp index 318196d520..875d9584b9 100644 --- a/Source/Core/Core/DSP/DSPIntBranch.cpp +++ b/Source/Core/Core/DSP/DSPIntBranch.cpp @@ -6,13 +6,13 @@ #include "Core/DSP/DSPCore.h" #include "Core/DSP/DSPIntCCUtil.h" -#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPIntUtil.h" +#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPMemoryMap.h" #include "Core/DSP/DSPStacks.h" -namespace DSPInterpreter { - +namespace DSPInterpreter +{ // Generic call implementation // CALLcc addressA // 0000 0010 1011 cccc @@ -22,13 +22,13 @@ namespace DSPInterpreter { // represented by value that follows this "call" instruction. void call(const UDSPInstruction opc) { - // must be outside the if. - u16 dest = dsp_fetch_code(); - if (CheckCondition(opc & 0xf)) - { - dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); - g_dsp.pc = dest; - } + // must be outside the if. + u16 dest = dsp_fetch_code(); + if (CheckCondition(opc & 0xf)) + { + dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); + g_dsp.pc = dest; + } } // Generic callr implementation @@ -39,13 +39,13 @@ void call(const UDSPInstruction opc) // register $R. void callr(const UDSPInstruction opc) { - if (CheckCondition(opc & 0xf)) - { - u8 reg = (opc >> 5) & 0x7; - u16 addr = dsp_op_read_reg(reg); - dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); - g_dsp.pc = addr; - } + if (CheckCondition(opc & 0xf)) + { + u8 reg = (opc >> 5) & 0x7; + u16 addr = dsp_op_read_reg(reg); + dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); + g_dsp.pc = addr; + } } // Generic if implementation @@ -54,11 +54,11 @@ void callr(const UDSPInstruction opc) // Execute following opcode if the condition has been met. void ifcc(const UDSPInstruction opc) { - if (!CheckCondition(opc & 0xf)) - { - // skip the next opcode - we have to lookup its size. - dsp_skip_inst(); - } + if (!CheckCondition(opc & 0xf)) + { + // skip the next opcode - we have to lookup its size. + dsp_skip_inst(); + } } // Generic jmp implementation @@ -69,11 +69,11 @@ void ifcc(const UDSPInstruction opc) // address represented by value that follows this "jmp" instruction. void jcc(const UDSPInstruction opc) { - u16 dest = dsp_fetch_code(); - if (CheckCondition(opc & 0xf)) - { - g_dsp.pc = dest; - } + u16 dest = dsp_fetch_code(); + if (CheckCondition(opc & 0xf)) + { + g_dsp.pc = dest; + } } // Generic jmpr implementation @@ -82,11 +82,11 @@ void jcc(const UDSPInstruction opc) // Jump to address; set program counter to a value from register $R. void jmprcc(const UDSPInstruction opc) { - if (CheckCondition(opc & 0xf)) - { - u8 reg = (opc >> 5) & 0x7; - g_dsp.pc = dsp_op_read_reg(reg); - } + if (CheckCondition(opc & 0xf)) + { + u8 reg = (opc >> 5) & 0x7; + g_dsp.pc = dsp_op_read_reg(reg); + } } // Generic ret implementation @@ -96,10 +96,10 @@ void jmprcc(const UDSPInstruction opc) // from call stack $st0 and sets $pc to this location. void ret(const UDSPInstruction opc) { - if (CheckCondition(opc & 0xf)) - { - g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); - } + if (CheckCondition(opc & 0xf)) + { + g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); + } } // RTI @@ -109,9 +109,8 @@ void ret(const UDSPInstruction opc) // location. void rti(const UDSPInstruction opc) { - g_dsp.r.sr = dsp_reg_load_stack(DSP_STACK_D); - g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); - + g_dsp.r.sr = dsp_reg_load_stack(DSP_STACK_D); + g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); } // HALT @@ -119,11 +118,10 @@ void rti(const UDSPInstruction opc) // Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR. void halt(const UDSPInstruction opc) { - g_dsp.cr |= 0x4; - g_dsp.pc--; + g_dsp.cr |= 0x4; + g_dsp.pc--; } - // LOOP handling: Loop stack is used to control execution of repeated blocks of // instructions. Whenever there is value on stack $st2 and current PC is equal // value at $st2, then value at stack $st3 is decremented. If value is not zero @@ -132,33 +130,32 @@ void halt(const UDSPInstruction opc) // continues at next opcode. void HandleLoop() { - // Handle looping hardware. - const u16 rCallAddress = g_dsp.r.st[0]; - const u16 rLoopAddress = g_dsp.r.st[2]; - u16& rLoopCounter = g_dsp.r.st[3]; + // Handle looping hardware. + const u16 rCallAddress = g_dsp.r.st[0]; + const u16 rLoopAddress = g_dsp.r.st[2]; + u16& rLoopCounter = g_dsp.r.st[3]; - if (rLoopAddress > 0 && rLoopCounter > 0) - { - // FIXME: why -1? because we just read past it. - if (g_dsp.pc - 1 == rLoopAddress) - { - rLoopCounter--; - if (rLoopCounter > 0) - { - g_dsp.pc = rCallAddress; - } - else - { - // end of loop - dsp_reg_load_stack(0); - dsp_reg_load_stack(2); - dsp_reg_load_stack(3); - } - } - } + if (rLoopAddress > 0 && rLoopCounter > 0) + { + // FIXME: why -1? because we just read past it. + if (g_dsp.pc - 1 == rLoopAddress) + { + rLoopCounter--; + if (rLoopCounter > 0) + { + g_dsp.pc = rCallAddress; + } + else + { + // end of loop + dsp_reg_load_stack(0); + dsp_reg_load_stack(2); + dsp_reg_load_stack(3); + } + } + } } - // LOOP $R // 0000 0000 010r rrrr // Repeatedly execute following opcode until counter specified by value @@ -169,20 +166,20 @@ void HandleLoop() // The looping hardware takes care of the rest. void loop(const UDSPInstruction opc) { - u16 reg = opc & 0x1f; - u16 cnt = dsp_op_read_reg(reg); - u16 loop_pc = g_dsp.pc; + u16 reg = opc & 0x1f; + u16 cnt = dsp_op_read_reg(reg); + u16 loop_pc = g_dsp.pc; - if (cnt) - { - dsp_reg_store_stack(0, g_dsp.pc); - dsp_reg_store_stack(2, loop_pc); - dsp_reg_store_stack(3, cnt); - } - else - { - dsp_skip_inst(); - } + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } + else + { + dsp_skip_inst(); + } } // LOOPI #I @@ -195,22 +192,21 @@ void loop(const UDSPInstruction opc) // The looping hardware takes care of the rest. void loopi(const UDSPInstruction opc) { - u16 cnt = opc & 0xff; - u16 loop_pc = g_dsp.pc; + u16 cnt = opc & 0xff; + u16 loop_pc = g_dsp.pc; - if (cnt) - { - dsp_reg_store_stack(0, g_dsp.pc); - dsp_reg_store_stack(2, loop_pc); - dsp_reg_store_stack(3, cnt); - } - else - { - dsp_skip_inst(); - } + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } + else + { + dsp_skip_inst(); + } } - // BLOOP $R, addrA // 0000 0000 011r rrrr // aaaa aaaa aaaa aaaa @@ -222,21 +218,21 @@ void loopi(const UDSPInstruction opc) // Up to 4 nested loops are allowed. void bloop(const UDSPInstruction opc) { - u16 reg = opc & 0x1f; - u16 cnt = dsp_op_read_reg(reg); - u16 loop_pc = dsp_fetch_code(); + u16 reg = opc & 0x1f; + u16 cnt = dsp_op_read_reg(reg); + u16 loop_pc = dsp_fetch_code(); - if (cnt) - { - dsp_reg_store_stack(0, g_dsp.pc); - dsp_reg_store_stack(2, loop_pc); - dsp_reg_store_stack(3, cnt); - } - else - { - g_dsp.pc = loop_pc; - dsp_skip_inst(); - } + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } + else + { + g_dsp.pc = loop_pc; + dsp_skip_inst(); + } } // BLOOPI #I, addrA @@ -250,20 +246,20 @@ void bloop(const UDSPInstruction opc) // nested loops are allowed. void bloopi(const UDSPInstruction opc) { - u16 cnt = opc & 0xff; - u16 loop_pc = dsp_fetch_code(); + u16 cnt = opc & 0xff; + u16 loop_pc = dsp_fetch_code(); - if (cnt) - { - dsp_reg_store_stack(0, g_dsp.pc); - dsp_reg_store_stack(2, loop_pc); - dsp_reg_store_stack(3, cnt); - } - else - { - g_dsp.pc = loop_pc; - dsp_skip_inst(); - } + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } + else + { + g_dsp.pc = loop_pc; + dsp_skip_inst(); + } } } // namespace diff --git a/Source/Core/Core/DSP/DSPIntCCUtil.cpp b/Source/Core/Core/DSP/DSPIntCCUtil.cpp index 4bcb164f0e..df51a9b665 100644 --- a/Source/Core/Core/DSP/DSPIntCCUtil.cpp +++ b/Source/Core/Core/DSP/DSPIntCCUtil.cpp @@ -4,183 +4,182 @@ // // Additional copyrights go to Duddie and Tratax (c) 2004 - // HELPER FUNCTIONS -#include "Core/DSP/DSPCore.h" #include "Core/DSP/DSPIntCCUtil.h" +#include "Core/DSP/DSPCore.h" #include "Core/DSP/DSPInterpreter.h" -namespace DSPInterpreter { - +namespace DSPInterpreter +{ void Update_SR_Register64(s64 _Value, bool carry, bool overflow) { - g_dsp.r.sr &= ~SR_CMP_MASK; + g_dsp.r.sr &= ~SR_CMP_MASK; - // 0x01 - if (carry) - { - g_dsp.r.sr |= SR_CARRY; - } + // 0x01 + if (carry) + { + g_dsp.r.sr |= SR_CARRY; + } - // 0x02 and 0x80 - if (overflow) - { - g_dsp.r.sr |= SR_OVERFLOW; - g_dsp.r.sr |= SR_OVERFLOW_STICKY; - } + // 0x02 and 0x80 + if (overflow) + { + g_dsp.r.sr |= SR_OVERFLOW; + g_dsp.r.sr |= SR_OVERFLOW_STICKY; + } - // 0x04 - if (_Value == 0) - { - g_dsp.r.sr |= SR_ARITH_ZERO; - } + // 0x04 + if (_Value == 0) + { + g_dsp.r.sr |= SR_ARITH_ZERO; + } - // 0x08 - if (_Value < 0) - { - g_dsp.r.sr |= SR_SIGN; - } + // 0x08 + if (_Value < 0) + { + g_dsp.r.sr |= SR_SIGN; + } - // 0x10 - if (_Value != (s32)_Value) - { - g_dsp.r.sr |= SR_OVER_S32; - } + // 0x10 + if (_Value != (s32)_Value) + { + g_dsp.r.sr |= SR_OVER_S32; + } - // 0x20 - Checks if top bits of m are equal - if (((_Value & 0xc0000000) == 0) || ((_Value & 0xc0000000) == 0xc0000000)) - { - g_dsp.r.sr |= SR_TOP2BITS; - } + // 0x20 - Checks if top bits of m are equal + if (((_Value & 0xc0000000) == 0) || ((_Value & 0xc0000000) == 0xc0000000)) + { + g_dsp.r.sr |= SR_TOP2BITS; + } } - void Update_SR_Register16(s16 _Value, bool carry, bool overflow, bool overS32) { - g_dsp.r.sr &= ~SR_CMP_MASK; + g_dsp.r.sr &= ~SR_CMP_MASK; - // 0x01 - if (carry) - { - g_dsp.r.sr |= SR_CARRY; - } + // 0x01 + if (carry) + { + g_dsp.r.sr |= SR_CARRY; + } - // 0x02 and 0x80 - if (overflow) - { - g_dsp.r.sr |= SR_OVERFLOW; - g_dsp.r.sr |= SR_OVERFLOW_STICKY; - } + // 0x02 and 0x80 + if (overflow) + { + g_dsp.r.sr |= SR_OVERFLOW; + g_dsp.r.sr |= SR_OVERFLOW_STICKY; + } - // 0x04 - if (_Value == 0) - { - g_dsp.r.sr |= SR_ARITH_ZERO; - } + // 0x04 + if (_Value == 0) + { + g_dsp.r.sr |= SR_ARITH_ZERO; + } - // 0x08 - if (_Value < 0) - { - g_dsp.r.sr |= SR_SIGN; - } + // 0x08 + if (_Value < 0) + { + g_dsp.r.sr |= SR_SIGN; + } - // 0x10 - if (overS32) - { - g_dsp.r.sr |= SR_OVER_S32; - } + // 0x10 + if (overS32) + { + g_dsp.r.sr |= SR_OVER_S32; + } - // 0x20 - Checks if top bits of m are equal - if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) - { - g_dsp.r.sr |= SR_TOP2BITS; - } + // 0x20 - Checks if top bits of m are equal + if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) + { + g_dsp.r.sr |= SR_TOP2BITS; + } } void Update_SR_LZ(bool value) { - if (value == true) - g_dsp.r.sr |= SR_LOGIC_ZERO; - else - g_dsp.r.sr &= ~SR_LOGIC_ZERO; + if (value == true) + g_dsp.r.sr |= SR_LOGIC_ZERO; + else + g_dsp.r.sr &= ~SR_LOGIC_ZERO; } static bool IsCarry() { - return (g_dsp.r.sr & SR_CARRY) != 0; + return (g_dsp.r.sr & SR_CARRY) != 0; } static bool IsOverflow() { - return (g_dsp.r.sr & SR_OVERFLOW) != 0; + return (g_dsp.r.sr & SR_OVERFLOW) != 0; } static bool IsOverS32() { - return (g_dsp.r.sr & SR_OVER_S32) != 0; + return (g_dsp.r.sr & SR_OVER_S32) != 0; } static bool IsLess() { - return (!(g_dsp.r.sr & SR_OVERFLOW) != !(g_dsp.r.sr & SR_SIGN)); + return (!(g_dsp.r.sr & SR_OVERFLOW) != !(g_dsp.r.sr & SR_SIGN)); } static bool IsZero() { - return (g_dsp.r.sr & SR_ARITH_ZERO) != 0; + return (g_dsp.r.sr & SR_ARITH_ZERO) != 0; } static bool IsLogicZero() { - return (g_dsp.r.sr & SR_LOGIC_ZERO) != 0; + return (g_dsp.r.sr & SR_LOGIC_ZERO) != 0; } static bool IsConditionA() { - return (((g_dsp.r.sr & SR_OVER_S32) || (g_dsp.r.sr & SR_TOP2BITS)) && !(g_dsp.r.sr & SR_ARITH_ZERO)) != 0; + return (((g_dsp.r.sr & SR_OVER_S32) || (g_dsp.r.sr & SR_TOP2BITS)) && + !(g_dsp.r.sr & SR_ARITH_ZERO)) != 0; } -//see DSPCore.h for flags +// see DSPCore.h for flags bool CheckCondition(u8 _Condition) { - switch (_Condition & 0xf) - { - case 0xf: // Always true. - return true; - case 0x0: // GE - Greater Equal - return !IsLess(); - case 0x1: // L - Less - return IsLess(); - case 0x2: // G - Greater - return !IsLess() && !IsZero(); - case 0x3: // LE - Less Equal - return IsLess() || IsZero(); - case 0x4: // NZ - Not Zero - return !IsZero(); - case 0x5: // Z - Zero - return IsZero(); - case 0x6: // NC - Not carry - return !IsCarry(); - case 0x7: // C - Carry - return IsCarry(); - case 0x8: // ? - Not over s32 - return !IsOverS32(); - case 0x9: // ? - Over s32 - return IsOverS32(); - case 0xa: // ? - return IsConditionA(); - case 0xb: // ? - return !IsConditionA(); - case 0xc: // LNZ - Logic Not Zero - return !IsLogicZero(); - case 0xd: // LZ - Logic Zero - return IsLogicZero(); - case 0xe: // 0 - Overflow - return IsOverflow(); - default: - return true; - } + switch (_Condition & 0xf) + { + case 0xf: // Always true. + return true; + case 0x0: // GE - Greater Equal + return !IsLess(); + case 0x1: // L - Less + return IsLess(); + case 0x2: // G - Greater + return !IsLess() && !IsZero(); + case 0x3: // LE - Less Equal + return IsLess() || IsZero(); + case 0x4: // NZ - Not Zero + return !IsZero(); + case 0x5: // Z - Zero + return IsZero(); + case 0x6: // NC - Not carry + return !IsCarry(); + case 0x7: // C - Carry + return IsCarry(); + case 0x8: // ? - Not over s32 + return !IsOverS32(); + case 0x9: // ? - Over s32 + return IsOverS32(); + case 0xa: // ? + return IsConditionA(); + case 0xb: // ? + return !IsConditionA(); + case 0xc: // LNZ - Logic Not Zero + return !IsLogicZero(); + case 0xd: // LZ - Logic Zero + return IsLogicZero(); + case 0xe: // 0 - Overflow + return IsOverflow(); + default: + return true; + } } } // namespace diff --git a/Source/Core/Core/DSP/DSPIntCCUtil.h b/Source/Core/Core/DSP/DSPIntCCUtil.h index a39e9512f6..c0098afa98 100644 --- a/Source/Core/Core/DSP/DSPIntCCUtil.h +++ b/Source/Core/Core/DSP/DSPIntCCUtil.h @@ -12,31 +12,31 @@ namespace DSPInterpreter { - bool CheckCondition(u8 _Condition); -void Update_SR_Register16(s16 _Value, bool carry = false, bool overflow = false, bool overS32 = false); +void Update_SR_Register16(s16 _Value, bool carry = false, bool overflow = false, + bool overS32 = false); void Update_SR_Register64(s64 _Value, bool carry = false, bool overflow = false); void Update_SR_LZ(bool value); inline bool isCarry(u64 val, u64 result) { - return (val > result); + return (val > result); } inline bool isCarry2(u64 val, u64 result) { - return (val >= result); + return (val >= result); } inline bool isOverflow(s64 val1, s64 val2, s64 res) { - return ((val1 ^ res) & (val2 ^ res)) < 0; + return ((val1 ^ res) & (val2 ^ res)) < 0; } inline bool isOverS32(s64 acc) { - return (acc != (s32)acc) ? true : false; + return (acc != (s32)acc) ? true : false; } } // namespace diff --git a/Source/Core/Core/DSP/DSPIntExtOps.cpp b/Source/Core/Core/DSP/DSPIntExtOps.cpp index 189874db7c..4d4b140556 100644 --- a/Source/Core/Core/DSP/DSPIntExtOps.cpp +++ b/Source/Core/Core/DSP/DSPIntExtOps.cpp @@ -6,7 +6,8 @@ #include "Core/DSP/DSPIntUtil.h" #include "Core/DSP/DSPMemoryMap.h" -//not needed for game ucodes (it slows down interpreter/dspjit32 + easier to compare int VS dspjit64 without it) +// not needed for game ucodes (it slows down interpreter/dspjit32 + easier to compare int VS +// dspjit64 without it) //#define PRECISE_BACKLOG // Extended opcodes do not exist on their own. These opcodes can only be @@ -22,23 +23,21 @@ // Needs comments. inline static void writeToBackLog(int i, int idx, u16 value) { - writeBackLog[i] = value; - writeBackLogIdx[i] = idx; + writeBackLog[i] = value; + writeBackLogIdx[i] = idx; } namespace DSPInterpreter { - namespace Ext { - inline bool IsSameMemArea(u16 a, u16 b) { - // LM: tested on Wii - if ((a>>10)==(b>>10)) - return true; - else - return false; + // LM: tested on Wii + if ((a >> 10) == (b >> 10)) + return true; + else + return false; } // DR $arR @@ -46,7 +45,7 @@ inline bool IsSameMemArea(u16 a, u16 b) // Decrement addressing register $arR. void dr(const UDSPInstruction opc) { - writeToBackLog(0, opc & 0x3, dsp_decrement_addr_reg(opc & 0x3)); + writeToBackLog(0, opc & 0x3, dsp_decrement_addr_reg(opc & 0x3)); } // IR $arR @@ -54,7 +53,7 @@ void dr(const UDSPInstruction opc) // Increment addressing register $arR. void ir(const UDSPInstruction opc) { - writeToBackLog(0, opc & 0x3, dsp_increment_addr_reg(opc & 0x3)); + writeToBackLog(0, opc & 0x3, dsp_increment_addr_reg(opc & 0x3)); } // NR $arR @@ -62,9 +61,9 @@ void ir(const UDSPInstruction opc) // Add corresponding indexing register $ixR to addressing register $arR. void nr(const UDSPInstruction opc) { - u8 reg = opc & 0x3; + u8 reg = opc & 0x3; - writeToBackLog(0, reg, dsp_increase_addr_reg(reg, (s16)g_dsp.r.ix[reg])); + writeToBackLog(0, reg, dsp_increase_addr_reg(reg, (s16)g_dsp.r.ix[reg])); } // MV $axD.D, $acS.S @@ -72,20 +71,20 @@ void nr(const UDSPInstruction opc) // Move value of $acS.S to the $axD.D. void mv(const UDSPInstruction opc) { - u8 sreg = (opc & 0x3) + DSP_REG_ACL0; - u8 dreg = ((opc >> 2) & 0x3); + u8 sreg = (opc & 0x3) + DSP_REG_ACL0; + u8 dreg = ((opc >> 2) & 0x3); - switch (sreg) - { - case DSP_REG_ACL0: - case DSP_REG_ACL1: - writeToBackLog(0, dreg + DSP_REG_AXL0, g_dsp.r.ac[sreg-DSP_REG_ACL0].l); - break; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - writeToBackLog(0, dreg + DSP_REG_AXL0, dsp_op_read_reg_and_saturate(sreg-DSP_REG_ACM0)); - break; - } + switch (sreg) + { + case DSP_REG_ACL0: + case DSP_REG_ACL1: + writeToBackLog(0, dreg + DSP_REG_AXL0, g_dsp.r.ac[sreg - DSP_REG_ACL0].l); + break; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + writeToBackLog(0, dreg + DSP_REG_AXL0, dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0)); + break; + } } // S @$arD, $acS.S @@ -94,21 +93,21 @@ void mv(const UDSPInstruction opc) // Post increment register $arD. void s(const UDSPInstruction opc) { - u8 dreg = opc & 0x3; - u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; + u8 dreg = opc & 0x3; + u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; - switch (sreg) - { - case DSP_REG_ACL0: - case DSP_REG_ACL1: - dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg-DSP_REG_ACL0].l); - break; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg-DSP_REG_ACM0)); - break; - } - writeToBackLog(0, dreg, dsp_increment_addr_reg(dreg)); + switch (sreg) + { + case DSP_REG_ACL0: + case DSP_REG_ACL1: + dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg - DSP_REG_ACL0].l); + break; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0)); + break; + } + writeToBackLog(0, dreg, dsp_increment_addr_reg(dreg)); } // SN @$arD, $acS.S @@ -117,21 +116,21 @@ void s(const UDSPInstruction opc) // Add indexing register $ixD to register $arD. void sn(const UDSPInstruction opc) { - u8 dreg = opc & 0x3; - u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; + u8 dreg = opc & 0x3; + u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; - switch (sreg) - { - case DSP_REG_ACL0: - case DSP_REG_ACL1: - dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg-DSP_REG_ACL0].l); - break; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg-DSP_REG_ACM0)); - break; - } - writeToBackLog(0, dreg, dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg])); + switch (sreg) + { + case DSP_REG_ACL0: + case DSP_REG_ACL1: + dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg - DSP_REG_ACL0].l); + break; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0)); + break; + } + writeToBackLog(0, dreg, dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg])); } // L $axD.D, @$arS @@ -140,22 +139,22 @@ void sn(const UDSPInstruction opc) // Post increment register $arS. void l(const UDSPInstruction opc) { - u8 sreg = opc & 0x3; - u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; + u8 sreg = opc & 0x3; + u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; - if ((dreg >= DSP_REG_ACM0) && (g_dsp.r.sr & SR_40_MODE_BIT)) - { - u16 val = dsp_dmem_read(g_dsp.r.ar[sreg]); - writeToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) ? 0xFFFF : 0x0000); - writeToBackLog(1, dreg, val); - writeToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0); - writeToBackLog(3, sreg, dsp_increment_addr_reg(sreg)); - } - else - { - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[sreg])); - writeToBackLog(1, sreg, dsp_increment_addr_reg(sreg)); - } + if ((dreg >= DSP_REG_ACM0) && (g_dsp.r.sr & SR_40_MODE_BIT)) + { + u16 val = dsp_dmem_read(g_dsp.r.ar[sreg]); + writeToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) ? 0xFFFF : 0x0000); + writeToBackLog(1, dreg, val); + writeToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0); + writeToBackLog(3, sreg, dsp_increment_addr_reg(sreg)); + } + else + { + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[sreg])); + writeToBackLog(1, sreg, dsp_increment_addr_reg(sreg)); + } } // LN $axD.D, @$arS @@ -164,22 +163,22 @@ void l(const UDSPInstruction opc) // Add indexing register $ixS to register $arS. void ln(const UDSPInstruction opc) { - u8 sreg = opc & 0x3; - u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; + u8 sreg = opc & 0x3; + u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; - if ((dreg >= DSP_REG_ACM0) && (g_dsp.r.sr & SR_40_MODE_BIT)) - { - u16 val = dsp_dmem_read(g_dsp.r.ar[sreg]); - writeToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) ? 0xFFFF : 0x0000); - writeToBackLog(1, dreg, val); - writeToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0); - writeToBackLog(3, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); - } - else - { - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[sreg])); - writeToBackLog(1, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); - } + if ((dreg >= DSP_REG_ACM0) && (g_dsp.r.sr & SR_40_MODE_BIT)) + { + u16 val = dsp_dmem_read(g_dsp.r.ar[sreg]); + writeToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) ? 0xFFFF : 0x0000); + writeToBackLog(1, dreg, val); + writeToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0); + writeToBackLog(3, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); + } + else + { + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[sreg])); + writeToBackLog(1, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); + } } // LS $axD.D, $acS.m108 @@ -189,17 +188,16 @@ void ln(const UDSPInstruction opc) // register $ar3. Increment both $ar0 and $ar3. void ls(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg)); + dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg)); - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); - writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); - writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); + writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); + writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); } - // LSN $axD.D, $acS.m // xxxx xxxx 10dd 010s // Load register $axD.D with value from memory pointed by register @@ -208,14 +206,14 @@ void ls(const UDSPInstruction opc) // register $ar0 and increment $ar3. void lsn(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg)); + dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg)); - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); - writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); - writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); + writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); + writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); } // LSM $axD.D, $acS.m @@ -226,14 +224,14 @@ void lsn(const UDSPInstruction opc) // register $ar3 and increment $ar0. void lsm(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg)); + dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg)); - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); - writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); - writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); + writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); + writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); } // LSMN $axD.D, $acS.m @@ -245,14 +243,14 @@ void lsm(const UDSPInstruction opc) // register $ar3. void lsnm(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg)); + dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg)); - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); - writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); - writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0])); + writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); + writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); } // SL $acS.m, $axD.D @@ -262,14 +260,14 @@ void lsnm(const UDSPInstruction opc) // $ar3. Increment both $ar0 and $ar3. void sl(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg)); + dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg)); - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); - writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); + writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); + writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); } // SLN $acS.m, $axD.D @@ -280,14 +278,14 @@ void sl(const UDSPInstruction opc) // and increment $ar3. void sln(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg)); + dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg)); - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); - writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); + writeToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); + writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); } // SLM $acS.m, $axD.D @@ -298,14 +296,14 @@ void sln(const UDSPInstruction opc) // and increment $ar0. void slm(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg)); + dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg)); - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); - writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); + writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); + writeToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0)); } // SLMN $acS.m, $axD.D @@ -316,14 +314,14 @@ void slm(const UDSPInstruction opc) // and add corresponding indexing register $ix3 to addressing register $ar3. void slnm(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg)); + dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg)); - writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); - writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); + writeToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3])); + writeToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); + writeToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0])); } // LD $ax0.d, $ax1.r, @$arS @@ -331,176 +329,173 @@ void slnm(const UDSPInstruction opc) // example for "nx'ld $AX0.L, $AX1.L, @$AR3" // Loads the word pointed by AR0 to AX0.H, then loads the word pointed by AR3 to AX0.L. // Increments AR0 and AR3. -// If AR0 and AR3 point into the same memory page (upper 6 bits of addr are the same -> games are not doing that!) +// If AR0 and AR3 point into the same memory page (upper 6 bits of addr are the same -> games are +// not doing that!) // then the value pointed by AR0 is loaded to BOTH AX0.H and AX0.L. -// If AR0 points into an invalid memory page (ie 0x2000), then AX0.H keeps its old value. (not implemented yet) -// If AR3 points into an invalid memory page, then AX0.L gets the same value as AX0.H. (not implemented yet) +// If AR0 points into an invalid memory page (ie 0x2000), then AX0.H keeps its old value. (not +// implemented yet) +// If AR3 points into an invalid memory page, then AX0.L gets the same value as AX0.H. (not +// implemented yet) void ld(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; - writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); + writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); - if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); - else - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); + if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); + else + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg)); + writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg)); - writeToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); + writeToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); } // LDAX $axR, @$arS // xxxx xxxx 11sr 0011 void ldax(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; + u8 sreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; - writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg])); + writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg])); - if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); - else - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); + if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); + else + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg)); + writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg)); - writeToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); + writeToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); } // LDN $ax0.d, $ax1.r, @$arS // xxxx xxxx 11dr 01ss void ldn(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; - writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); + writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); - if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); - else - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); + if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); + else + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); + writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); - writeToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); + writeToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); } // LDAXN $axR, @$arS // xxxx xxxx 11sr 0111 void ldaxn(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; + u8 sreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; - writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg])); + writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg])); - if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); - else - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); + if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); + else + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); + writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); - writeToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); + writeToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3)); } // LDM $ax0.d, $ax1.r, @$arS // xxxx xxxx 11dr 10ss void ldm(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; - writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); + writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); - if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); - else - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); + if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); + else + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg)); + writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg)); - writeToBackLog(3, DSP_REG_AR3, - dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); + writeToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); } // LDAXM $axR, @$arS // xxxx xxxx 11sr 1011 void ldaxm(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; + u8 sreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; - writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg])); + writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg])); - if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); - else - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); + if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); + else + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg)); + writeToBackLog(2, sreg, dsp_increment_addr_reg(sreg)); - writeToBackLog(3, DSP_REG_AR3, - dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); + writeToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); } // LDNM $ax0.d, $ax1.r, @$arS // xxxx xxxx 11dr 11ss void ldnm(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; - writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); + writeToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); - if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); - else - writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); + if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg])); + else + writeToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); + writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); - writeToBackLog(3, DSP_REG_AR3, - dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); + writeToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); } // LDAXNM $axR, @$arS // xxxx xxxx 11dr 1111 void ldaxnm(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; + u8 sreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; - writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg])); + writeToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg])); - if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); - else - writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); + if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3])) + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg])); + else + writeToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3])); - writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); + writeToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg])); - writeToBackLog(3, DSP_REG_AR3, - dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); + writeToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3])); } - void nop(const UDSPInstruction opc) { } -} // end namespace ext -} // end namespace DSPInterpeter - +} // end namespace ext +} // end namespace DSPInterpeter // The ext ops are calculated in parallel with the actual op. That means that // both the main op and the ext op see the same register state as input. The @@ -512,18 +507,18 @@ void nop(const UDSPInstruction opc) // being applied to the real registers after the main op was executed void applyWriteBackLog() { - // always make sure to have an extra entry at the end w/ -1 to avoid - // infinitive loops - for (int i = 0; writeBackLogIdx[i] != -1; i++) - { + // always make sure to have an extra entry at the end w/ -1 to avoid + // infinitive loops + for (int i = 0; writeBackLogIdx[i] != -1; i++) + { #ifdef PRECISE_BACKLOG - dsp_op_write_reg(writeBackLogIdx[i], dsp_op_read_reg(writeBackLogIdx[i]) | writeBackLog[i]); + dsp_op_write_reg(writeBackLogIdx[i], dsp_op_read_reg(writeBackLogIdx[i]) | writeBackLog[i]); #else - dsp_op_write_reg(writeBackLogIdx[i], writeBackLog[i]); + dsp_op_write_reg(writeBackLogIdx[i], writeBackLog[i]); #endif - // Clear back log - writeBackLogIdx[i] = -1; - } + // Clear back log + writeBackLogIdx[i] = -1; + } } // This function is being called in the main op after all input regs were read @@ -536,31 +531,33 @@ void applyWriteBackLog() void zeroWriteBackLog() { #ifdef PRECISE_BACKLOG - // always make sure to have an extra entry at the end w/ -1 to avoid - // infinitive loops - for (int i = 0; writeBackLogIdx[i] != -1; i++) - { - dsp_op_write_reg(writeBackLogIdx[i], 0); - } + // always make sure to have an extra entry at the end w/ -1 to avoid + // infinitive loops + for (int i = 0; writeBackLogIdx[i] != -1; i++) + { + dsp_op_write_reg(writeBackLogIdx[i], 0); + } #endif } void zeroWriteBackLogPreserveAcc(u8 acc) { #ifdef PRECISE_BACKLOG - for (int i = 0; writeBackLogIdx[i] != -1; i++) - { - // acc0 - if ((acc == 0) && - ((writeBackLogIdx[i] == DSP_REG_ACL0) || (writeBackLogIdx[i] == DSP_REG_ACM0) || (writeBackLogIdx[i] == DSP_REG_ACH0))) - continue; + for (int i = 0; writeBackLogIdx[i] != -1; i++) + { + // acc0 + if ((acc == 0) && + ((writeBackLogIdx[i] == DSP_REG_ACL0) || (writeBackLogIdx[i] == DSP_REG_ACM0) || + (writeBackLogIdx[i] == DSP_REG_ACH0))) + continue; - // acc1 - if ((acc == 1) && - ((writeBackLogIdx[i] == DSP_REG_ACL1) || (writeBackLogIdx[i] == DSP_REG_ACM1) || (writeBackLogIdx[i] == DSP_REG_ACH1))) - continue; + // acc1 + if ((acc == 1) && + ((writeBackLogIdx[i] == DSP_REG_ACL1) || (writeBackLogIdx[i] == DSP_REG_ACM1) || + (writeBackLogIdx[i] == DSP_REG_ACH1))) + continue; - dsp_op_write_reg(writeBackLogIdx[i], 0); - } + dsp_op_write_reg(writeBackLogIdx[i], 0); + } #endif } diff --git a/Source/Core/Core/DSP/DSPIntExtOps.h b/Source/Core/Core/DSP/DSPIntExtOps.h index 8aa18b830d..b492590e2f 100644 --- a/Source/Core/Core/DSP/DSPIntExtOps.h +++ b/Source/Core/Core/DSP/DSPIntExtOps.h @@ -41,5 +41,5 @@ void ir(const UDSPInstruction opc); void nr(const UDSPInstruction opc); void nop(const UDSPInstruction opc); -} // end namespace Ext -} // end namespace DSPinterpeter +} // end namespace Ext +} // end namespace DSPinterpeter diff --git a/Source/Core/Core/DSP/DSPIntLoadStore.cpp b/Source/Core/Core/DSP/DSPIntLoadStore.cpp index 7ea1efe64d..e2305f304e 100644 --- a/Source/Core/Core/DSP/DSPIntLoadStore.cpp +++ b/Source/Core/Core/DSP/DSPIntLoadStore.cpp @@ -4,12 +4,12 @@ // // Additional copyrights go to Duddie and Tratax (c) 2004 -#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPIntUtil.h" +#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPMemoryMap.h" -namespace DSPInterpreter { - +namespace DSPInterpreter +{ // SRS @M, $(0x18+S) // 0010 1sss mmmm mmmm // Move value from register $(0x18+D) to data memory pointed by address @@ -18,13 +18,13 @@ namespace DSPInterpreter { // Note: pc+=2 in duddie's doc seems wrong void srs(const UDSPInstruction opc) { - u8 reg = ((opc >> 8) & 0x7) + 0x18; - u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF); + u8 reg = ((opc >> 8) & 0x7) + 0x18; + u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF); - if (reg >= DSP_REG_ACM0) - dsp_dmem_write(addr, dsp_op_read_reg_and_saturate(reg-DSP_REG_ACM0)); - else - dsp_dmem_write(addr, dsp_op_read_reg(reg)); + if (reg >= DSP_REG_ACM0) + dsp_dmem_write(addr, dsp_op_read_reg_and_saturate(reg - DSP_REG_ACM0)); + else + dsp_dmem_write(addr, dsp_op_read_reg(reg)); } // LRS $(0x18+D), @M @@ -34,10 +34,10 @@ void srs(const UDSPInstruction opc) // from CR, and the lower 8 bits are from the 8-bit immediate. void lrs(const UDSPInstruction opc) { - u8 reg = ((opc >> 8) & 0x7) + 0x18; - u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF); - dsp_op_write_reg(reg, dsp_dmem_read(addr)); - dsp_conditional_extend_accum(reg); + u8 reg = ((opc >> 8) & 0x7) + 0x18; + u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF); + dsp_op_write_reg(reg, dsp_dmem_read(addr)); + dsp_conditional_extend_accum(reg); } // LR $D, @M @@ -46,11 +46,11 @@ void lrs(const UDSPInstruction opc) // Move value from data memory pointed by address M to register $D. void lr(const UDSPInstruction opc) { - u8 reg = opc & DSP_REG_MASK; - u16 addr = dsp_fetch_code(); - u16 val = dsp_dmem_read(addr); - dsp_op_write_reg(reg, val); - dsp_conditional_extend_accum(reg); + u8 reg = opc & DSP_REG_MASK; + u16 addr = dsp_fetch_code(); + u16 val = dsp_dmem_read(addr); + dsp_op_write_reg(reg, val); + dsp_conditional_extend_accum(reg); } // SR @M, $S @@ -59,13 +59,13 @@ void lr(const UDSPInstruction opc) // Store value from register $S to a memory pointed by address M. void sr(const UDSPInstruction opc) { - u8 reg = opc & DSP_REG_MASK; - u16 addr = dsp_fetch_code(); + u8 reg = opc & DSP_REG_MASK; + u16 addr = dsp_fetch_code(); - if (reg >= DSP_REG_ACM0) - dsp_dmem_write(addr, dsp_op_read_reg_and_saturate(reg-DSP_REG_ACM0)); - else - dsp_dmem_write(addr, dsp_op_read_reg(reg)); + if (reg >= DSP_REG_ACM0) + dsp_dmem_write(addr, dsp_op_read_reg_and_saturate(reg - DSP_REG_ACM0)); + else + dsp_dmem_write(addr, dsp_op_read_reg(reg)); } // SI @M, #I @@ -75,9 +75,9 @@ void sr(const UDSPInstruction opc) // M (M is 8-bit value sign extended). void si(const UDSPInstruction opc) { - u16 addr = (s8)opc; - u16 imm = dsp_fetch_code(); - dsp_dmem_write(addr, imm); + u16 addr = (s8)opc; + u16 imm = dsp_fetch_code(); + dsp_dmem_write(addr, imm); } // LRR $D, @$S @@ -85,12 +85,12 @@ void si(const UDSPInstruction opc) // Move value from data memory pointed by addressing register $S to register $D. void lrr(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; - u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); - dsp_op_write_reg(dreg, val); - dsp_conditional_extend_accum(dreg); + u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); + dsp_op_write_reg(dreg, val); + dsp_conditional_extend_accum(dreg); } // LRRD $D, @$S @@ -99,13 +99,13 @@ void lrr(const UDSPInstruction opc) // Decrement register $S. void lrrd(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; - u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); - dsp_op_write_reg(dreg, val); - dsp_conditional_extend_accum(dreg); - g_dsp.r.ar[sreg] = dsp_decrement_addr_reg(sreg); + u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); + dsp_op_write_reg(dreg, val); + dsp_conditional_extend_accum(dreg); + g_dsp.r.ar[sreg] = dsp_decrement_addr_reg(sreg); } // LRRI $D, @$S @@ -114,13 +114,13 @@ void lrrd(const UDSPInstruction opc) // Increment register $S. void lrri(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; - u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); - dsp_op_write_reg(dreg, val); - dsp_conditional_extend_accum(dreg); - g_dsp.r.ar[sreg] = dsp_increment_addr_reg(sreg); + u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); + dsp_op_write_reg(dreg, val); + dsp_conditional_extend_accum(dreg); + g_dsp.r.ar[sreg] = dsp_increment_addr_reg(sreg); } // LRRN $D, @$S @@ -129,13 +129,13 @@ void lrri(const UDSPInstruction opc) // Add indexing register $(0x4+S) to register $S. void lrrn(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; - u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); - dsp_op_write_reg(dreg, val); - dsp_conditional_extend_accum(dreg); - g_dsp.r.ar[sreg] = dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]); + u16 val = dsp_dmem_read(dsp_op_read_reg(sreg)); + dsp_op_write_reg(dreg, val); + dsp_conditional_extend_accum(dreg); + g_dsp.r.ar[sreg] = dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]); } // SRR @$D, $S @@ -144,13 +144,13 @@ void lrrn(const UDSPInstruction opc) // addressing register $D. void srr(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; - if (sreg >= DSP_REG_ACM0) - dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg-DSP_REG_ACM0)); - else - dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg)); + if (sreg >= DSP_REG_ACM0) + dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0)); + else + dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg)); } // SRRD @$D, $S @@ -159,15 +159,15 @@ void srr(const UDSPInstruction opc) // addressing register $D. Decrement register $D. void srrd(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; - if (sreg >= DSP_REG_ACM0) - dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg-DSP_REG_ACM0)); - else - dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg)); + if (sreg >= DSP_REG_ACM0) + dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0)); + else + dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg)); - g_dsp.r.ar[dreg] = dsp_decrement_addr_reg(dreg); + g_dsp.r.ar[dreg] = dsp_decrement_addr_reg(dreg); } // SRRI @$D, $S @@ -176,15 +176,15 @@ void srrd(const UDSPInstruction opc) // addressing register $D. Increment register $D. void srri(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; - if (sreg >= DSP_REG_ACM0) - dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg-DSP_REG_ACM0)); - else - dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg)); + if (sreg >= DSP_REG_ACM0) + dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0)); + else + dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg)); - g_dsp.r.ar[dreg] = dsp_increment_addr_reg(dreg); + g_dsp.r.ar[dreg] = dsp_increment_addr_reg(dreg); } // SRRN @$D, $S @@ -193,15 +193,15 @@ void srri(const UDSPInstruction opc) // addressing register $D. Add DSP_REG_IX0 register to register $D. void srrn(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; - if (sreg >= DSP_REG_ACM0) - dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg-DSP_REG_ACM0)); - else - dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg)); + if (sreg >= DSP_REG_ACM0) + dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0)); + else + dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg)); - g_dsp.r.ar[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]); + g_dsp.r.ar[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]); } // ILRR $acD.m, @$arS @@ -210,11 +210,11 @@ void srrn(const UDSPInstruction opc) // $arS to mid accumulator register $acD.m. void ilrr(const UDSPInstruction opc) { - u16 reg = opc & 0x3; - u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); + u16 reg = opc & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); - g_dsp.r.ac[dreg-DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); - dsp_conditional_extend_accum(dreg); + g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); + dsp_conditional_extend_accum(dreg); } // ILRRD $acD.m, @$arS @@ -223,12 +223,12 @@ void ilrr(const UDSPInstruction opc) // $arS to mid accumulator register $acD.m. Decrement addressing register $arS. void ilrrd(const UDSPInstruction opc) { - u16 reg = opc & 0x3; - u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); + u16 reg = opc & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); - g_dsp.r.ac[dreg-DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); - dsp_conditional_extend_accum(dreg); - g_dsp.r.ar[reg] = dsp_decrement_addr_reg(reg); + g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); + dsp_conditional_extend_accum(dreg); + g_dsp.r.ar[reg] = dsp_decrement_addr_reg(reg); } // ILRRI $acD.m, @$S @@ -237,12 +237,12 @@ void ilrrd(const UDSPInstruction opc) // $arS to mid accumulator register $acD.m. Increment addressing register $arS. void ilrri(const UDSPInstruction opc) { - u16 reg = opc & 0x3; - u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); + u16 reg = opc & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); - g_dsp.r.ac[dreg-DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); - dsp_conditional_extend_accum(dreg); - g_dsp.r.ar[reg] = dsp_increment_addr_reg(reg); + g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); + dsp_conditional_extend_accum(dreg); + g_dsp.r.ar[reg] = dsp_increment_addr_reg(reg); } // ILRRN $acD.m, @$arS @@ -252,12 +252,12 @@ void ilrri(const UDSPInstruction opc) // register $ixS to addressing register $arS. void ilrrn(const UDSPInstruction opc) { - u16 reg = opc & 0x3; - u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); + u16 reg = opc & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1); - g_dsp.r.ac[dreg-DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); - dsp_conditional_extend_accum(dreg); - g_dsp.r.ar[reg] = dsp_increase_addr_reg(reg, (s16)g_dsp.r.ix[reg]); + g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]); + dsp_conditional_extend_accum(dreg); + g_dsp.r.ar[reg] = dsp_increase_addr_reg(reg, (s16)g_dsp.r.ix[reg]); } } // namespace diff --git a/Source/Core/Core/DSP/DSPIntMisc.cpp b/Source/Core/Core/DSP/DSPIntMisc.cpp index 241dd96b6e..1883b7d741 100644 --- a/Source/Core/Core/DSP/DSPIntMisc.cpp +++ b/Source/Core/Core/DSP/DSPIntMisc.cpp @@ -5,27 +5,27 @@ // Additional copyrights go to Duddie and Tratax (c) 2004 #include "Core/DSP/DSPCore.h" -#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPIntUtil.h" +#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPMemoryMap.h" #include "Core/DSP/DSPTables.h" -namespace DSPInterpreter { - +namespace DSPInterpreter +{ // MRR $D, $S // 0001 11dd ddds ssss // Move value from register $S to register $D. void mrr(const UDSPInstruction opc) { - u8 sreg = opc & 0x1f; - u8 dreg = (opc >> 5) & 0x1f; + u8 sreg = opc & 0x1f; + u8 dreg = (opc >> 5) & 0x1f; - if (sreg >= DSP_REG_ACM0) - dsp_op_write_reg(dreg, dsp_op_read_reg_and_saturate(sreg-DSP_REG_ACM0)); - else - dsp_op_write_reg(dreg, dsp_op_read_reg(sreg)); + if (sreg >= DSP_REG_ACM0) + dsp_op_write_reg(dreg, dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0)); + else + dsp_op_write_reg(dreg, dsp_op_read_reg(sreg)); - dsp_conditional_extend_accum(dreg); + dsp_conditional_extend_accum(dreg); } // LRI $D, #I @@ -39,10 +39,10 @@ void mrr(const UDSPInstruction opc) // S16 mode. void lri(const UDSPInstruction opc) { - u8 reg = opc & DSP_REG_MASK; - u16 imm = dsp_fetch_code(); - dsp_op_write_reg(reg, imm); - dsp_conditional_extend_accum(reg); + u8 reg = opc & DSP_REG_MASK; + u16 imm = dsp_fetch_code(); + dsp_op_write_reg(reg, imm); + dsp_conditional_extend_accum(reg); } // LRIS $(0x18+D), #I @@ -50,10 +50,10 @@ void lri(const UDSPInstruction opc) // Load immediate value I (8-bit sign extended) to accumulator register. void lris(const UDSPInstruction opc) { - u8 reg = ((opc >> 8) & 0x7) + DSP_REG_AXL0; - u16 imm = (s8)opc; - dsp_op_write_reg(reg, imm); - dsp_conditional_extend_accum(reg); + u8 reg = ((opc >> 8) & 0x7) + DSP_REG_AXL0; + u16 imm = (s8)opc; + dsp_op_write_reg(reg, imm); + dsp_conditional_extend_accum(reg); } //---- @@ -65,7 +65,7 @@ void lris(const UDSPInstruction opc) // an opcode extension but not do anything. At least according to duddie. void nx(const UDSPInstruction opc) { - zeroWriteBackLog(); + zeroWriteBackLog(); } //---- @@ -75,7 +75,7 @@ void nx(const UDSPInstruction opc) // Decrement address register $arD. void dar(const UDSPInstruction opc) { - g_dsp.r.ar[opc & 0x3] = dsp_decrement_addr_reg(opc & 0x3); + g_dsp.r.ar[opc & 0x3] = dsp_decrement_addr_reg(opc & 0x3); } // IAR $arD @@ -83,7 +83,7 @@ void dar(const UDSPInstruction opc) // Increment address register $arD. void iar(const UDSPInstruction opc) { - g_dsp.r.ar[opc & 0x3] = dsp_increment_addr_reg(opc & 0x3); + g_dsp.r.ar[opc & 0x3] = dsp_increment_addr_reg(opc & 0x3); } // SUBARN $arD @@ -92,8 +92,8 @@ void iar(const UDSPInstruction opc) // used only in IPL-NTSC ucode void subarn(const UDSPInstruction opc) { - u8 dreg = opc & 0x3; - g_dsp.r.ar[dreg] = dsp_decrease_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]); + u8 dreg = opc & 0x3; + g_dsp.r.ar[dreg] = dsp_decrease_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]); } // ADDARN $arD, $ixS @@ -102,9 +102,9 @@ void subarn(const UDSPInstruction opc) // It is critical for the Zelda ucode that this one wraps correctly. void addarn(const UDSPInstruction opc) { - u8 dreg = opc & 0x3; - u8 sreg = (opc >> 2) & 0x3; - g_dsp.r.ar[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[sreg]); + u8 dreg = opc & 0x3; + u8 sreg = (opc >> 2) & 0x3; + g_dsp.r.ar[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[sreg]); } //---- @@ -115,8 +115,8 @@ void addarn(const UDSPInstruction opc) // immediate value I. void sbclr(const UDSPInstruction opc) { - u8 bit = (opc & 0x7) + 6; - g_dsp.r.sr &= ~(1 << bit); + u8 bit = (opc & 0x7) + 6; + g_dsp.r.sr &= ~(1 << bit); } // SBSET #I @@ -125,37 +125,37 @@ void sbclr(const UDSPInstruction opc) // immediate value I. void sbset(const UDSPInstruction opc) { - u8 bit = (opc & 0x7) + 6; - g_dsp.r.sr |= (1 << bit); + u8 bit = (opc & 0x7) + 6; + g_dsp.r.sr |= (1 << bit); } // This is a bunch of flag setters, flipping bits in SR. void srbith(const UDSPInstruction opc) { - zeroWriteBackLog(); - switch ((opc >> 8) & 0xf) - { - case 0xa: // M2 - g_dsp.r.sr &= ~SR_MUL_MODIFY; - break; - case 0xb: // M0 - g_dsp.r.sr |= SR_MUL_MODIFY; - break; - case 0xc: // CLR15 - g_dsp.r.sr &= ~SR_MUL_UNSIGNED; - break; - case 0xd: // SET15 - g_dsp.r.sr |= SR_MUL_UNSIGNED; - break; - case 0xe: // SET16 (CLR40) - g_dsp.r.sr &= ~SR_40_MODE_BIT; - break; - case 0xf: // SET40 - g_dsp.r.sr |= SR_40_MODE_BIT; - break; - default: - break; - } + zeroWriteBackLog(); + switch ((opc >> 8) & 0xf) + { + case 0xa: // M2 + g_dsp.r.sr &= ~SR_MUL_MODIFY; + break; + case 0xb: // M0 + g_dsp.r.sr |= SR_MUL_MODIFY; + break; + case 0xc: // CLR15 + g_dsp.r.sr &= ~SR_MUL_UNSIGNED; + break; + case 0xd: // SET15 + g_dsp.r.sr |= SR_MUL_UNSIGNED; + break; + case 0xe: // SET16 (CLR40) + g_dsp.r.sr &= ~SR_40_MODE_BIT; + break; + case 0xf: // SET40 + g_dsp.r.sr |= SR_40_MODE_BIT; + break; + default: + break; + } } } // namespace diff --git a/Source/Core/Core/DSP/DSPIntMultiplier.cpp b/Source/Core/Core/DSP/DSPIntMultiplier.cpp index 6644f61448..82b1819c65 100644 --- a/Source/Core/Core/DSP/DSPIntMultiplier.cpp +++ b/Source/Core/Core/DSP/DSPIntMultiplier.cpp @@ -4,67 +4,66 @@ // // Additional copyrights go to Duddie and Tratax (c) 2004 - // Multiplier and product register control #include "Core/DSP/DSPIntCCUtil.h" -#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPIntUtil.h" +#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPTables.h" -namespace DSPInterpreter { - +namespace DSPInterpreter +{ // Only MULX family instructions have unsigned/mixed support. inline s64 dsp_get_multiply_prod(u16 a, u16 b, u8 sign) { - s64 prod; + s64 prod; - if ((sign == 1) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) //unsigned - prod = (u32)(a * b); - else if ((sign == 2) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) //mixed - prod = a * (s16)b; - else - prod = (s16)a * (s16)b; //signed + if ((sign == 1) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) // unsigned + prod = (u32)(a * b); + else if ((sign == 2) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) // mixed + prod = a * (s16)b; + else + prod = (s16)a * (s16)b; // signed - // Conditionally multiply by 2. - if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0) - prod <<= 1; + // Conditionally multiply by 2. + if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0) + prod <<= 1; - return prod; + return prod; } inline s64 dsp_multiply(u16 a, u16 b, u8 sign = 0) { - s64 prod = dsp_get_multiply_prod(a, b, sign); - return prod; + s64 prod = dsp_get_multiply_prod(a, b, sign); + return prod; } inline s64 dsp_multiply_add(u16 a, u16 b, u8 sign = 0) { - s64 prod = dsp_get_long_prod() + dsp_get_multiply_prod(a, b, sign); - return prod; + s64 prod = dsp_get_long_prod() + dsp_get_multiply_prod(a, b, sign); + return prod; } inline s64 dsp_multiply_sub(u16 a, u16 b, u8 sign = 0) { - s64 prod = dsp_get_long_prod() - dsp_get_multiply_prod(a, b, sign); - return prod; + s64 prod = dsp_get_long_prod() - dsp_get_multiply_prod(a, b, sign); + return prod; } inline s64 dsp_multiply_mulx(u8 axh0, u8 axh1, u16 val1, u16 val2) { - s64 result; + s64 result; - if ((axh0==0) && (axh1==0)) - result = dsp_multiply(val1, val2, 1); // unsigned support ON if both ax?.l regs are used - else if ((axh0==0) && (axh1==1)) - result = dsp_multiply(val1, val2, 2); // mixed support ON (u16)axl.0 * (s16)axh.1 - else if ((axh0==1) && (axh1==0)) - result = dsp_multiply(val2, val1, 2); // mixed support ON (u16)axl.1 * (s16)axh.0 - else - result = dsp_multiply(val1, val2, 0); // unsigned support OFF if both ax?.h regs are used + if ((axh0 == 0) && (axh1 == 0)) + result = dsp_multiply(val1, val2, 1); // unsigned support ON if both ax?.l regs are used + else if ((axh0 == 0) && (axh1 == 1)) + result = dsp_multiply(val1, val2, 2); // mixed support ON (u16)axl.0 * (s16)axh.1 + else if ((axh0 == 1) && (axh1 == 0)) + result = dsp_multiply(val2, val1, 2); // mixed support ON (u16)axl.1 * (s16)axh.0 + else + result = dsp_multiply(val1, val2, 0); // unsigned support OFF if both ax?.h regs are used - return result; + return result; } //---- @@ -80,12 +79,12 @@ inline s64 dsp_multiply_mulx(u8 axh0, u8 axh1, u16 val1, u16 val2) // direct use of prod regs by AX/AXWII (look @that part of ucode). void clrp(const UDSPInstruction opc) { - zeroWriteBackLog(); + zeroWriteBackLog(); - g_dsp.r.prod.l = 0x0000; - g_dsp.r.prod.m = 0xfff0; - g_dsp.r.prod.h = 0x00ff; - g_dsp.r.prod.m2 = 0x0010; + g_dsp.r.prod.l = 0x0000; + g_dsp.r.prod.m = 0xfff0; + g_dsp.r.prod.h = 0x00ff; + g_dsp.r.prod.m2 = 0x0010; } // TSTPROD @@ -95,9 +94,9 @@ void clrp(const UDSPInstruction opc) // flags out: --xx xx0x void tstprod(const UDSPInstruction opc) { - s64 prod = dsp_get_long_prod(); - Update_SR_Register64(prod); - zeroWriteBackLog(); + s64 prod = dsp_get_long_prod(); + Update_SR_Register64(prod); + zeroWriteBackLog(); } //---- @@ -109,14 +108,14 @@ void tstprod(const UDSPInstruction opc) // flags out: --xx xx0x void movp(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - s64 acc = dsp_get_long_prod(); + s64 acc = dsp_get_long_prod(); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(acc); + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(acc); } // MOVNP $acD @@ -127,14 +126,14 @@ void movp(const UDSPInstruction opc) // flags out: --xx xx0x void movnp(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - s64 acc = -dsp_get_long_prod(); + s64 acc = -dsp_get_long_prod(); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(acc); + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(acc); } // MOVPZ $acD @@ -145,14 +144,14 @@ void movnp(const UDSPInstruction opc) // flags out: --xx xx0x void movpz(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x01; + u8 dreg = (opc >> 8) & 0x01; - s64 acc = dsp_get_long_prod_round_prodl(); + s64 acc = dsp_get_long_prod_round_prodl(); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(acc); + dsp_set_long_acc(dreg, acc); + Update_SR_Register64(acc); } // ADDPAXZ $acD, $axS @@ -164,19 +163,19 @@ void movpz(const UDSPInstruction opc) // flags out: --xx xx0x void addpaxz(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; - s64 oldprod = dsp_get_long_prod(); - s64 prod = dsp_get_long_prod_round_prodl(); - s64 ax = dsp_get_long_acx(sreg); - s64 res = prod + (ax & ~0xffff); + s64 oldprod = dsp_get_long_prod(); + s64 prod = dsp_get_long_prod_round_prodl(); + s64 ax = dsp_get_long_acx(sreg); + s64 res = prod + (ax & ~0xffff); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - Update_SR_Register64(res, isCarry(oldprod, res), false); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(oldprod, res), false); } //---- @@ -186,11 +185,11 @@ void addpaxz(const UDSPInstruction opc) // Multiply $ax0.h by $ax0.h void mulaxh(const UDSPInstruction opc) { - s64 prod = dsp_multiply(dsp_get_ax_h(0), dsp_get_ax_h(0)); + s64 prod = dsp_multiply(dsp_get_ax_h(0), dsp_get_ax_h(0)); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); + dsp_set_long_prod(prod); } //---- @@ -201,15 +200,15 @@ void mulaxh(const UDSPInstruction opc) // $axS.h of secondary accumulator $axS (treat them both as signed). void mul(const UDSPInstruction opc) { - u8 sreg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 11) & 0x1; - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply(axh, axl); + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply(axh, axl); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); + dsp_set_long_prod(prod); } // MULAC $axS.l, $axS.h, $acR @@ -221,19 +220,19 @@ void mul(const UDSPInstruction opc) // flags out: --xx xx0x void mulac(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 11) & 0x1; + u8 rreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 11) & 0x1; - s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply(axl, axh); + s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply(axl, axh); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); } // MULMV $axS.l, $axS.h, $acR @@ -245,19 +244,19 @@ void mulac(const UDSPInstruction opc) // flags out: --xx xx0x void mulmv(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; - u8 sreg = ((opc >> 11) & 0x1); + u8 rreg = (opc >> 8) & 0x1; + u8 sreg = ((opc >> 11) & 0x1); - s64 acc = dsp_get_long_prod(); - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply(axl, axh); + s64 acc = dsp_get_long_prod(); + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply(axl, axh); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); } // MULMVZ $axS.l, $axS.h, $acR @@ -270,19 +269,19 @@ void mulmv(const UDSPInstruction opc) // flags out: --xx xx0x void mulmvz(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 11) & 0x1; + u8 rreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 11) & 0x1; - s64 acc = dsp_get_long_prod_round_prodl(); - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply(axl, axh); + s64 acc = dsp_get_long_prod_round_prodl(); + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply(axl, axh); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); } //---- @@ -293,16 +292,16 @@ void mulmvz(const UDSPInstruction opc) // Part is selected by S and T bits. Zero selects low part, one selects high part. void mulx(const UDSPInstruction opc) { - u8 treg = ((opc >> 11) & 0x1); - u8 sreg = ((opc >> 12) & 0x1); + u8 treg = ((opc >> 11) & 0x1); + u8 sreg = ((opc >> 12) & 0x1); - u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); + dsp_set_long_prod(prod); } // MULXAC $ax0.S, $ax1.T, $acR @@ -314,20 +313,20 @@ void mulx(const UDSPInstruction opc) // flags out: --xx xx0x void mulxac(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; - s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); } // MULXMV $ax0.S, $ax1.T, $acR @@ -339,20 +338,20 @@ void mulxac(const UDSPInstruction opc) // flags out: --xx xx0x void mulxmv(const UDSPInstruction opc) { - u8 rreg = ((opc >> 8) & 0x1); - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; + u8 rreg = ((opc >> 8) & 0x1); + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; - s64 acc = dsp_get_long_prod(); - u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + s64 acc = dsp_get_long_prod(); + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); } // MULXMVZ $ax0.S, $ax1.T, $acR @@ -365,20 +364,20 @@ void mulxmv(const UDSPInstruction opc) // flags out: --xx xx0x void mulxmvz(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; - s64 acc = dsp_get_long_prod_round_prodl(); - u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + s64 acc = dsp_get_long_prod_round_prodl(); + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); } //---- @@ -389,16 +388,16 @@ void mulxmvz(const UDSPInstruction opc) // secondary accumulator $axS (treat them both as signed). void mulc(const UDSPInstruction opc) { - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; - u16 accm = dsp_get_acc_m(sreg); - u16 axh = dsp_get_ax_h(treg); - s64 prod = dsp_multiply(accm, axh); + u16 accm = dsp_get_acc_m(sreg); + u16 axh = dsp_get_ax_h(treg); + s64 prod = dsp_multiply(accm, axh); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); + dsp_set_long_prod(prod); } // MULCAC $acS.m, $axT.h, $acR @@ -410,20 +409,20 @@ void mulc(const UDSPInstruction opc) // flags out: --xx xx0x void mulcac(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; - s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - u16 accm = dsp_get_acc_m(sreg); - u16 axh = dsp_get_ax_h(treg); - s64 prod = dsp_multiply(accm, axh); + s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + u16 accm = dsp_get_acc_m(sreg); + u16 axh = dsp_get_ax_h(treg); + s64 prod = dsp_multiply(accm, axh); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); } // MULCMV $acS.m, $axT.h, $acR @@ -436,20 +435,20 @@ void mulcac(const UDSPInstruction opc) // flags out: --xx xx0x void mulcmv(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; - s64 acc = dsp_get_long_prod(); - u16 accm = dsp_get_acc_m(sreg); - u16 axh = dsp_get_ax_h(treg); - s64 prod = dsp_multiply(accm, axh); + s64 acc = dsp_get_long_prod(); + u16 accm = dsp_get_acc_m(sreg); + u16 axh = dsp_get_ax_h(treg); + s64 prod = dsp_multiply(accm, axh); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); } // MULCMVZ $acS.m, $axT.h, $acR @@ -463,20 +462,20 @@ void mulcmv(const UDSPInstruction opc) // flags out: --xx xx0x void mulcmvz(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; - s64 acc = dsp_get_long_prod_round_prodl(); - u16 accm = dsp_get_acc_m(sreg); - u16 axh = dsp_get_ax_h(treg); - s64 prod = dsp_multiply(accm, axh); + s64 acc = dsp_get_long_prod_round_prodl(); + u16 accm = dsp_get_acc_m(sreg); + u16 axh = dsp_get_ax_h(treg); + s64 prod = dsp_multiply(accm, axh); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(dsp_get_long_acc(rreg)); + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); + Update_SR_Register64(dsp_get_long_acc(rreg)); } //---- @@ -488,16 +487,16 @@ void mulcmvz(const UDSPInstruction opc) // signed) and add result to product register. void maddx(const UDSPInstruction opc) { - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; - u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply_add(val1, val2); + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + s64 prod = dsp_multiply_add(val1, val2); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); + dsp_set_long_prod(prod); } // MSUBX $(0x18+S*2), $(0x19+T*2) @@ -507,16 +506,16 @@ void maddx(const UDSPInstruction opc) // signed) and subtract result from product register. void msubx(const UDSPInstruction opc) { - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; - u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply_sub(val1, val2); + u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + s64 prod = dsp_multiply_sub(val1, val2); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); + dsp_set_long_prod(prod); } // MADDC $acS.m, $axT.h @@ -526,16 +525,16 @@ void msubx(const UDSPInstruction opc) // register. void maddc(const UDSPInstruction opc) { - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; - u16 accm = dsp_get_acc_m(sreg); - u16 axh = dsp_get_ax_h(treg); - s64 prod = dsp_multiply_add(accm, axh); + u16 accm = dsp_get_acc_m(sreg); + u16 axh = dsp_get_ax_h(treg); + s64 prod = dsp_multiply_add(accm, axh); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); + dsp_set_long_prod(prod); } // MSUBC $acS.m, $axT.h @@ -545,16 +544,16 @@ void maddc(const UDSPInstruction opc) // product register. void msubc(const UDSPInstruction opc) { - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; - u16 accm = dsp_get_acc_m(sreg); - u16 axh = dsp_get_ax_h(treg); - s64 prod = dsp_multiply_sub(accm, axh); + u16 accm = dsp_get_acc_m(sreg); + u16 axh = dsp_get_ax_h(treg); + s64 prod = dsp_multiply_sub(accm, axh); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); + dsp_set_long_prod(prod); } // MADD $axS.l, $axS.h @@ -564,15 +563,15 @@ void msubc(const UDSPInstruction opc) // result to product register. void madd(const UDSPInstruction opc) { - u8 sreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 8) & 0x1; - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply_add(axl, axh); + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply_add(axl, axh); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); + dsp_set_long_prod(prod); } // MSUB $axS.l, $axS.h @@ -582,15 +581,15 @@ void madd(const UDSPInstruction opc) // subtract result from product register. void msub(const UDSPInstruction opc) { - u8 sreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 8) & 0x1; - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply_sub(axl, axh); + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply_sub(axl, axh); - zeroWriteBackLog(); + zeroWriteBackLog(); - dsp_set_long_prod(prod); + dsp_set_long_prod(prod); } } // namespace diff --git a/Source/Core/Core/DSP/DSPIntUtil.h b/Source/Core/Core/DSP/DSPIntUtil.h index 6e245e9a28..9c540400e1 100644 --- a/Source/Core/Core/DSP/DSPIntUtil.h +++ b/Source/Core/Core/DSP/DSPIntUtil.h @@ -10,19 +10,18 @@ #include "Core/DSP/DSPCore.h" #include "Core/DSP/DSPStacks.h" - // --------------------------------------------------------------------------------------- // --- SR // --------------------------------------------------------------------------------------- static inline void dsp_SR_set_flag(int flag) { - g_dsp.r.sr |= flag; + g_dsp.r.sr |= flag; } static inline bool dsp_SR_is_flag_set(int flag) { - return (g_dsp.r.sr & flag) != 0; + return (g_dsp.r.sr & flag) != 0; } // --------------------------------------------------------------------------------------- @@ -31,210 +30,227 @@ static inline bool dsp_SR_is_flag_set(int flag) static inline u16 dsp_increase_addr_reg(u16 reg, s16 _ix) { - u32 ar = g_dsp.r.ar[reg]; - u32 wr = g_dsp.r.wr[reg]; - s32 ix = _ix; + u32 ar = g_dsp.r.ar[reg]; + u32 wr = g_dsp.r.wr[reg]; + s32 ix = _ix; - u32 mx = (wr | 1) << 1; - u32 nar = ar + ix; - u32 dar = (nar ^ ar ^ ix) & mx; + u32 mx = (wr | 1) << 1; + u32 nar = ar + ix; + u32 dar = (nar ^ ar ^ ix) & mx; - if (ix >= 0) - { - if (dar > wr) //overflow - nar -= wr + 1; - } - else - { - if ((((nar + wr + 1) ^ nar) & dar) <= wr) //underflow or below min for mask - nar += wr + 1; - } - return nar; + if (ix >= 0) + { + if (dar > wr) // overflow + nar -= wr + 1; + } + else + { + if ((((nar + wr + 1) ^ nar) & dar) <= wr) // underflow or below min for mask + nar += wr + 1; + } + return nar; } static inline u16 dsp_decrease_addr_reg(u16 reg, s16 _ix) { - u32 ar = g_dsp.r.ar[reg]; - u32 wr = g_dsp.r.wr[reg]; - s32 ix = _ix; + u32 ar = g_dsp.r.ar[reg]; + u32 wr = g_dsp.r.wr[reg]; + s32 ix = _ix; - u32 mx = (wr | 1) << 1; - u32 nar = ar - ix; - u32 dar = (nar ^ ar ^ ~ix) & mx; + u32 mx = (wr | 1) << 1; + u32 nar = ar - ix; + u32 dar = (nar ^ ar ^ ~ix) & mx; - if ((u32)ix > 0xFFFF8000) //(ix < 0 && ix != -0x8000) - { - if (dar > wr) //overflow - nar -= wr + 1; - } - else - { - if ((((nar + wr + 1) ^ nar) & dar) <= wr) //underflow or below min for mask - nar += wr + 1; - } - return nar; + if ((u32)ix > 0xFFFF8000) //(ix < 0 && ix != -0x8000) + { + if (dar > wr) // overflow + nar -= wr + 1; + } + else + { + if ((((nar + wr + 1) ^ nar) & dar) <= wr) // underflow or below min for mask + nar += wr + 1; + } + return nar; } static inline u16 dsp_increment_addr_reg(u16 reg) { - u32 ar = g_dsp.r.ar[reg]; - u32 wr = g_dsp.r.wr[reg]; + u32 ar = g_dsp.r.ar[reg]; + u32 wr = g_dsp.r.wr[reg]; - u32 nar = ar + 1; + u32 nar = ar + 1; - if ((nar ^ ar) > ((wr | 1) << 1)) - nar -= wr + 1; - return nar; + if ((nar ^ ar) > ((wr | 1) << 1)) + nar -= wr + 1; + return nar; } static inline u16 dsp_decrement_addr_reg(u16 reg) { - u32 ar = g_dsp.r.ar[reg]; - u32 wr = g_dsp.r.wr[reg]; + u32 ar = g_dsp.r.ar[reg]; + u32 wr = g_dsp.r.wr[reg]; - u32 nar = ar + wr; + u32 nar = ar + wr; - if (((nar ^ ar) & ((wr | 1) << 1)) > wr) - nar -= wr + 1; - return nar; + if (((nar ^ ar) & ((wr | 1) << 1)) > wr) + nar -= wr + 1; + return nar; } - // --------------------------------------------------------------------------------------- // --- reg // --------------------------------------------------------------------------------------- static inline u16 dsp_op_read_reg(int _reg) { - int reg = _reg & 0x1f; + int reg = _reg & 0x1f; - switch (reg) - { - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - return dsp_reg_load_stack(reg - DSP_REG_ST0); - case DSP_REG_AR0: - case DSP_REG_AR1: - case DSP_REG_AR2: - case DSP_REG_AR3: - return g_dsp.r.ar[reg - DSP_REG_AR0]; - case DSP_REG_IX0: - case DSP_REG_IX1: - case DSP_REG_IX2: - case DSP_REG_IX3: - return g_dsp.r.ix[reg - DSP_REG_IX0]; - case DSP_REG_WR0: - case DSP_REG_WR1: - case DSP_REG_WR2: - case DSP_REG_WR3: - return g_dsp.r.wr[reg - DSP_REG_WR0]; - case DSP_REG_ACH0: - case DSP_REG_ACH1: - return g_dsp.r.ac[reg - DSP_REG_ACH0].h; - case DSP_REG_CR: return g_dsp.r.cr; - case DSP_REG_SR: return g_dsp.r.sr; - case DSP_REG_PRODL: return g_dsp.r.prod.l; - case DSP_REG_PRODM: return g_dsp.r.prod.m; - case DSP_REG_PRODH: return g_dsp.r.prod.h; - case DSP_REG_PRODM2: return g_dsp.r.prod.m2; - case DSP_REG_AXL0: - case DSP_REG_AXL1: - return g_dsp.r.ax[reg - DSP_REG_AXL0].l; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - return g_dsp.r.ax[reg - DSP_REG_AXH0].h; - case DSP_REG_ACL0: - case DSP_REG_ACL1: - return g_dsp.r.ac[reg - DSP_REG_ACL0].l; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - return g_dsp.r.ac[reg - DSP_REG_ACM0].m; - default: - _assert_msg_(DSP_INT, 0, "cannot happen"); - return 0; - } + switch (reg) + { + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + return dsp_reg_load_stack(reg - DSP_REG_ST0); + case DSP_REG_AR0: + case DSP_REG_AR1: + case DSP_REG_AR2: + case DSP_REG_AR3: + return g_dsp.r.ar[reg - DSP_REG_AR0]; + case DSP_REG_IX0: + case DSP_REG_IX1: + case DSP_REG_IX2: + case DSP_REG_IX3: + return g_dsp.r.ix[reg - DSP_REG_IX0]; + case DSP_REG_WR0: + case DSP_REG_WR1: + case DSP_REG_WR2: + case DSP_REG_WR3: + return g_dsp.r.wr[reg - DSP_REG_WR0]; + case DSP_REG_ACH0: + case DSP_REG_ACH1: + return g_dsp.r.ac[reg - DSP_REG_ACH0].h; + case DSP_REG_CR: + return g_dsp.r.cr; + case DSP_REG_SR: + return g_dsp.r.sr; + case DSP_REG_PRODL: + return g_dsp.r.prod.l; + case DSP_REG_PRODM: + return g_dsp.r.prod.m; + case DSP_REG_PRODH: + return g_dsp.r.prod.h; + case DSP_REG_PRODM2: + return g_dsp.r.prod.m2; + case DSP_REG_AXL0: + case DSP_REG_AXL1: + return g_dsp.r.ax[reg - DSP_REG_AXL0].l; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + return g_dsp.r.ax[reg - DSP_REG_AXH0].h; + case DSP_REG_ACL0: + case DSP_REG_ACL1: + return g_dsp.r.ac[reg - DSP_REG_ACL0].l; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + return g_dsp.r.ac[reg - DSP_REG_ACM0].m; + default: + _assert_msg_(DSP_INT, 0, "cannot happen"); + return 0; + } } static inline void dsp_op_write_reg(int _reg, u16 val) { - int reg = _reg & 0x1f; + int reg = _reg & 0x1f; - switch (reg) - { - // 8-bit sign extended registers. Should look at prod.h too... - case DSP_REG_ACH0: - case DSP_REG_ACH1: - // sign extend from the bottom 8 bits. - g_dsp.r.ac[reg-DSP_REG_ACH0].h = (u16)(s16)(s8)(u8)val; - break; + switch (reg) + { + // 8-bit sign extended registers. Should look at prod.h too... + case DSP_REG_ACH0: + case DSP_REG_ACH1: + // sign extend from the bottom 8 bits. + g_dsp.r.ac[reg - DSP_REG_ACH0].h = (u16)(s16)(s8)(u8)val; + break; - // Stack registers. - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - dsp_reg_store_stack(reg - DSP_REG_ST0, val); - break; + // Stack registers. + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + dsp_reg_store_stack(reg - DSP_REG_ST0, val); + break; - case DSP_REG_AR0: - case DSP_REG_AR1: - case DSP_REG_AR2: - case DSP_REG_AR3: - g_dsp.r.ar[reg - DSP_REG_AR0] = val; - break; - case DSP_REG_IX0: - case DSP_REG_IX1: - case DSP_REG_IX2: - case DSP_REG_IX3: - g_dsp.r.ix[reg - DSP_REG_IX0] = val; - break; - case DSP_REG_WR0: - case DSP_REG_WR1: - case DSP_REG_WR2: - case DSP_REG_WR3: - g_dsp.r.wr[reg - DSP_REG_WR0] = val; - break; - case DSP_REG_CR: g_dsp.r.cr = val; break; - case DSP_REG_SR: g_dsp.r.sr = val; break; - case DSP_REG_PRODL: g_dsp.r.prod.l = val; break; - case DSP_REG_PRODM: g_dsp.r.prod.m = val; break; - case DSP_REG_PRODH: g_dsp.r.prod.h = val; break; - case DSP_REG_PRODM2: g_dsp.r.prod.m2 = val; break; - case DSP_REG_AXL0: - case DSP_REG_AXL1: - g_dsp.r.ax[reg - DSP_REG_AXL0].l = val; - break; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - g_dsp.r.ax[reg - DSP_REG_AXH0].h = val; - break; - case DSP_REG_ACL0: - case DSP_REG_ACL1: - g_dsp.r.ac[reg - DSP_REG_ACL0].l = val; - break; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - g_dsp.r.ac[reg - DSP_REG_ACM0].m = val; - break; - } + case DSP_REG_AR0: + case DSP_REG_AR1: + case DSP_REG_AR2: + case DSP_REG_AR3: + g_dsp.r.ar[reg - DSP_REG_AR0] = val; + break; + case DSP_REG_IX0: + case DSP_REG_IX1: + case DSP_REG_IX2: + case DSP_REG_IX3: + g_dsp.r.ix[reg - DSP_REG_IX0] = val; + break; + case DSP_REG_WR0: + case DSP_REG_WR1: + case DSP_REG_WR2: + case DSP_REG_WR3: + g_dsp.r.wr[reg - DSP_REG_WR0] = val; + break; + case DSP_REG_CR: + g_dsp.r.cr = val; + break; + case DSP_REG_SR: + g_dsp.r.sr = val; + break; + case DSP_REG_PRODL: + g_dsp.r.prod.l = val; + break; + case DSP_REG_PRODM: + g_dsp.r.prod.m = val; + break; + case DSP_REG_PRODH: + g_dsp.r.prod.h = val; + break; + case DSP_REG_PRODM2: + g_dsp.r.prod.m2 = val; + break; + case DSP_REG_AXL0: + case DSP_REG_AXL1: + g_dsp.r.ax[reg - DSP_REG_AXL0].l = val; + break; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + g_dsp.r.ax[reg - DSP_REG_AXH0].h = val; + break; + case DSP_REG_ACL0: + case DSP_REG_ACL1: + g_dsp.r.ac[reg - DSP_REG_ACL0].l = val; + break; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + g_dsp.r.ac[reg - DSP_REG_ACM0].m = val; + break; + } } static inline void dsp_conditional_extend_accum(int reg) { - switch (reg) - { - case DSP_REG_ACM0: - case DSP_REG_ACM1: - if (g_dsp.r.sr & SR_40_MODE_BIT) - { - // Sign extend into whole accum. - u16 val = g_dsp.r.ac[reg-DSP_REG_ACM0].m; - g_dsp.r.ac[reg - DSP_REG_ACM0].h = (val & 0x8000) ? 0xFFFF : 0x0000; - g_dsp.r.ac[reg - DSP_REG_ACM0].l = 0; - } - } + switch (reg) + { + case DSP_REG_ACM0: + case DSP_REG_ACM1: + if (g_dsp.r.sr & SR_40_MODE_BIT) + { + // Sign extend into whole accum. + u16 val = g_dsp.r.ac[reg - DSP_REG_ACM0].m; + g_dsp.r.ac[reg - DSP_REG_ACM0].h = (val & 0x8000) ? 0xFFFF : 0x0000; + g_dsp.r.ac[reg - DSP_REG_ACM0].l = 0; + } + } } // --------------------------------------------------------------------------------------- @@ -243,33 +259,33 @@ static inline void dsp_conditional_extend_accum(int reg) static inline s64 dsp_get_long_prod() { - s64 val = (s8)(u8)g_dsp.r.prod.h; - val <<= 32; - s64 low_prod = g_dsp.r.prod.m; - low_prod += g_dsp.r.prod.m2; - low_prod <<= 16; - low_prod |= g_dsp.r.prod.l; - val += low_prod; - return val; + s64 val = (s8)(u8)g_dsp.r.prod.h; + val <<= 32; + s64 low_prod = g_dsp.r.prod.m; + low_prod += g_dsp.r.prod.m2; + low_prod <<= 16; + low_prod |= g_dsp.r.prod.l; + val += low_prod; + return val; } static inline s64 dsp_get_long_prod_round_prodl() { - s64 prod = dsp_get_long_prod(); + s64 prod = dsp_get_long_prod(); - if (prod & 0x10000) - prod = (prod + 0x8000) & ~0xffff; - else - prod = (prod + 0x7fff) & ~0xffff; + if (prod & 0x10000) + prod = (prod + 0x8000) & ~0xffff; + else + prod = (prod + 0x7fff) & ~0xffff; - return prod; + return prod; } // For accurate emulation, this is wrong - but the real prod registers behave // in completely bizarre ways. Not needed to emulate them correctly for game ucodes. inline void dsp_set_long_prod(s64 val) { - g_dsp.r.prod.val = val & 0x000000FFFFFFFFFFULL; + g_dsp.r.prod.val = val & 0x000000FFFFFFFFFFULL; } // --------------------------------------------------------------------------------------- @@ -278,66 +294,66 @@ inline void dsp_set_long_prod(s64 val) inline s64 dsp_get_long_acc(int reg) { - return ((s64)(g_dsp.r.ac[reg].val << 24) >> 24); + return ((s64)(g_dsp.r.ac[reg].val << 24) >> 24); } inline void dsp_set_long_acc(int _reg, s64 val) { - g_dsp.r.ac[_reg].val = (u64)val; + g_dsp.r.ac[_reg].val = (u64)val; } -inline s64 dsp_convert_long_acc(s64 val) // s64 -> s40 +inline s64 dsp_convert_long_acc(s64 val) // s64 -> s40 { - return ((val << 24) >> 24); + return ((val << 24) >> 24); } inline s64 dsp_round_long_acc(s64 val) { - if (val & 0x10000) - val = (val + 0x8000) & ~0xffff; - else - val = (val + 0x7fff) & ~0xffff; + if (val & 0x10000) + val = (val + 0x8000) & ~0xffff; + else + val = (val + 0x7fff) & ~0xffff; - return val; + return val; } inline s16 dsp_get_acc_l(int _reg) { - return (s16)g_dsp.r.ac[_reg].l; + return (s16)g_dsp.r.ac[_reg].l; } inline s16 dsp_get_acc_m(int _reg) { - return (s16)g_dsp.r.ac[_reg].m; + return (s16)g_dsp.r.ac[_reg].m; } inline s16 dsp_get_acc_h(int _reg) { - return (s16)g_dsp.r.ac[_reg].h; + return (s16)g_dsp.r.ac[_reg].h; } inline u16 dsp_op_read_reg_and_saturate(u8 _reg) { - if (g_dsp.r.sr & SR_40_MODE_BIT) - { - s64 acc = dsp_get_long_acc(_reg); + if (g_dsp.r.sr & SR_40_MODE_BIT) + { + s64 acc = dsp_get_long_acc(_reg); - if (acc != (s32)acc) - { - if (acc > 0) - return 0x7fff; - else - return 0x8000; - } - else - { - return g_dsp.r.ac[_reg].m; - } - } - else - { - return g_dsp.r.ac[_reg].m; - } + if (acc != (s32)acc) + { + if (acc > 0) + return 0x7fff; + else + return 0x8000; + } + else + { + return g_dsp.r.ac[_reg].m; + } + } + else + { + return g_dsp.r.ac[_reg].m; + } } // --------------------------------------------------------------------------------------- @@ -346,15 +362,15 @@ inline u16 dsp_op_read_reg_and_saturate(u8 _reg) inline s32 dsp_get_long_acx(int _reg) { - return (s32)(((u32)g_dsp.r.ax[_reg].h << 16) | g_dsp.r.ax[_reg].l); + return (s32)(((u32)g_dsp.r.ax[_reg].h << 16) | g_dsp.r.ax[_reg].l); } inline s16 dsp_get_ax_l(int _reg) { - return (s16)g_dsp.r.ax[_reg].l; + return (s16)g_dsp.r.ax[_reg].l; } inline s16 dsp_get_ax_h(int _reg) { - return (s16)g_dsp.r.ax[_reg].h; + return (s16)g_dsp.r.ax[_reg].h; } diff --git a/Source/Core/Core/DSP/DSPInterpreter.cpp b/Source/Core/Core/DSP/DSPInterpreter.cpp index d3575df686..852007570e 100644 --- a/Source/Core/Core/DSP/DSPInterpreter.cpp +++ b/Source/Core/Core/DSP/DSPInterpreter.cpp @@ -3,206 +3,206 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPAnalyzer.h" #include "Core/DSP/DSPCore.h" #include "Core/DSP/DSPHWInterface.h" -#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPIntUtil.h" #include "Core/DSP/DSPMemoryMap.h" #include "Core/DSP/DSPTables.h" -namespace DSPInterpreter { - +namespace DSPInterpreter +{ // NOTE: These have nothing to do with g_dsp.r.cr ! void WriteCR(u16 val) { - // reset - if (val & 1) - { - INFO_LOG(DSPLLE,"DSP_CONTROL RESET"); - DSPCore_Reset(); - val &= ~1; - } - // init - else if (val == 4) - { - // HAX! - // OSInitAudioSystem ucode should send this mail - not DSP core itself - INFO_LOG(DSPLLE,"DSP_CONTROL INIT"); - g_init_hax = true; - val |= 0x800; - } + // reset + if (val & 1) + { + INFO_LOG(DSPLLE, "DSP_CONTROL RESET"); + DSPCore_Reset(); + val &= ~1; + } + // init + else if (val == 4) + { + // HAX! + // OSInitAudioSystem ucode should send this mail - not DSP core itself + INFO_LOG(DSPLLE, "DSP_CONTROL INIT"); + g_init_hax = true; + val |= 0x800; + } - // update cr - g_dsp.cr = val; + // update cr + g_dsp.cr = val; } u16 ReadCR() { - if (g_dsp.pc & 0x8000) - { - g_dsp.cr |= 0x800; - } - else - { - g_dsp.cr &= ~0x800; - } + if (g_dsp.pc & 0x8000) + { + g_dsp.cr |= 0x800; + } + else + { + g_dsp.cr &= ~0x800; + } - return g_dsp.cr; + return g_dsp.cr; } void Step() { - DSPCore_CheckExceptions(); + DSPCore_CheckExceptions(); - g_dsp.step_counter++; + g_dsp.step_counter++; #if PROFILE - g_dsp.err_pc = g_dsp.pc; + g_dsp.err_pc = g_dsp.pc; - ProfilerAddDelta(g_dsp.err_pc, 1); - if (g_dsp.step_counter == 1) - { - ProfilerInit(); - } + ProfilerAddDelta(g_dsp.err_pc, 1); + if (g_dsp.step_counter == 1) + { + ProfilerInit(); + } - if ((g_dsp.step_counter & 0xFFFFF) == 0) - { - ProfilerDump(g_dsp.step_counter); - } + if ((g_dsp.step_counter & 0xFFFFF) == 0) + { + ProfilerDump(g_dsp.step_counter); + } #endif - u16 opc = dsp_fetch_code(); - ExecuteInstruction(UDSPInstruction(opc)); + u16 opc = dsp_fetch_code(); + ExecuteInstruction(UDSPInstruction(opc)); - if (DSPAnalyzer::code_flags[static_cast(g_dsp.pc - 1u)] & DSPAnalyzer::CODE_LOOP_END) - HandleLoop(); + if (DSPAnalyzer::code_flags[static_cast(g_dsp.pc - 1u)] & DSPAnalyzer::CODE_LOOP_END) + HandleLoop(); } // Used by thread mode. int RunCyclesThread(int cycles) { - while (true) - { - if (g_dsp.cr & CR_HALT) - return 0; + while (true) + { + if (g_dsp.cr & CR_HALT) + return 0; - if (g_dsp.external_interrupt_waiting) - { - DSPCore_CheckExternalInterrupt(); - DSPCore_SetExternalInterrupt(false); - } + if (g_dsp.external_interrupt_waiting) + { + DSPCore_CheckExternalInterrupt(); + DSPCore_SetExternalInterrupt(false); + } - Step(); - cycles--; - if (cycles < 0) - return 0; - } + Step(); + cycles--; + if (cycles < 0) + return 0; + } } // This one has basic idle skipping, and checks breakpoints. int RunCyclesDebug(int cycles) { - // First, let's run a few cycles with no idle skipping so that things can progress a bit. - for (int i = 0; i < 8; i++) - { - if (g_dsp.cr & CR_HALT) - return 0; - if (g_dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc)) - { - DSPCore_SetState(DSPCORE_STEPPING); - return cycles; - } - Step(); - cycles--; - if (cycles < 0) - return 0; - } + // First, let's run a few cycles with no idle skipping so that things can progress a bit. + for (int i = 0; i < 8; i++) + { + if (g_dsp.cr & CR_HALT) + return 0; + if (g_dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc)) + { + DSPCore_SetState(DSPCORE_STEPPING); + return cycles; + } + Step(); + cycles--; + if (cycles < 0) + return 0; + } - while (true) - { - // Next, let's run a few cycles with idle skipping, so that we can skip - // idle loops. - for (int i = 0; i < 8; i++) - { - if (g_dsp.cr & CR_HALT) - return 0; - if (g_dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc)) - { - DSPCore_SetState(DSPCORE_STEPPING); - return cycles; - } - // Idle skipping. - if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP) - return 0; - Step(); - cycles--; - if (cycles < 0) - return 0; - } + while (true) + { + // Next, let's run a few cycles with idle skipping, so that we can skip + // idle loops. + for (int i = 0; i < 8; i++) + { + if (g_dsp.cr & CR_HALT) + return 0; + if (g_dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc)) + { + DSPCore_SetState(DSPCORE_STEPPING); + return cycles; + } + // Idle skipping. + if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP) + return 0; + Step(); + cycles--; + if (cycles < 0) + return 0; + } - // Now, lets run some more without idle skipping. - for (int i = 0; i < 200; i++) - { - if (g_dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc)) - { - DSPCore_SetState(DSPCORE_STEPPING); - return cycles; - } - Step(); - cycles--; - if (cycles < 0) - return 0; - // We don't bother directly supporting pause - if the main emu pauses, - // it just won't call this function anymore. - } - } + // Now, lets run some more without idle skipping. + for (int i = 0; i < 200; i++) + { + if (g_dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc)) + { + DSPCore_SetState(DSPCORE_STEPPING); + return cycles; + } + Step(); + cycles--; + if (cycles < 0) + return 0; + // We don't bother directly supporting pause - if the main emu pauses, + // it just won't call this function anymore. + } + } } // Used by non-thread mode. Meant to be efficient. int RunCycles(int cycles) { - // First, let's run a few cycles with no idle skipping so that things can - // progress a bit. - for (int i = 0; i < 8; i++) - { - if (g_dsp.cr & CR_HALT) - return 0; - Step(); - cycles--; - if (cycles < 0) - return 0; - } + // First, let's run a few cycles with no idle skipping so that things can + // progress a bit. + for (int i = 0; i < 8; i++) + { + if (g_dsp.cr & CR_HALT) + return 0; + Step(); + cycles--; + if (cycles < 0) + return 0; + } - while (true) - { - // Next, let's run a few cycles with idle skipping, so that we can skip - // idle loops. - for (int i = 0; i < 8; i++) - { - if (g_dsp.cr & CR_HALT) - return 0; - // Idle skipping. - if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP) - return 0; - Step(); - cycles--; - if (cycles < 0) - return 0; - } + while (true) + { + // Next, let's run a few cycles with idle skipping, so that we can skip + // idle loops. + for (int i = 0; i < 8; i++) + { + if (g_dsp.cr & CR_HALT) + return 0; + // Idle skipping. + if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP) + return 0; + Step(); + cycles--; + if (cycles < 0) + return 0; + } - // Now, lets run some more without idle skipping. - for (int i = 0; i < 200; i++) - { - Step(); - cycles--; - if (cycles < 0) - return 0; - // We don't bother directly supporting pause - if the main emu pauses, - // it just won't call this function anymore. - } - } + // Now, lets run some more without idle skipping. + for (int i = 0; i < 200; i++) + { + Step(); + cycles--; + if (cycles < 0) + return 0; + // We don't bother directly supporting pause - if the main emu pauses, + // it just won't call this function anymore. + } + } } } // namespace diff --git a/Source/Core/Core/DSP/DSPInterpreter.h b/Source/Core/Core/DSP/DSPInterpreter.h index a584dc43c2..541b07b04f 100644 --- a/Source/Core/Core/DSP/DSPInterpreter.h +++ b/Source/Core/Core/DSP/DSPInterpreter.h @@ -6,7 +6,7 @@ #include "Core/DSP/DSPCommon.h" -#define DSP_REG_MASK 0x1f +#define DSP_REG_MASK 0x1f namespace DSPInterpreter { @@ -23,7 +23,7 @@ int RunCycles(int cycles); int RunCyclesDebug(int cycles); void WriteCR(u16 val); -u16 ReadCR(); +u16 ReadCR(); // All the opcode functions. void call(const UDSPInstruction opc); diff --git a/Source/Core/Core/DSP/DSPMemoryMap.cpp b/Source/Core/Core/DSP/DSPMemoryMap.cpp index 8a3deb1506..68904e4650 100644 --- a/Source/Core/Core/DSP/DSPMemoryMap.cpp +++ b/Source/Core/Core/DSP/DSPMemoryMap.cpp @@ -3,61 +3,61 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/DSP/DSPMemoryMap.h" #include "Core/DSP/DSPCore.h" #include "Core/DSP/DSPHWInterface.h" #include "Core/DSP/DSPInterpreter.h" -#include "Core/DSP/DSPMemoryMap.h" u16 dsp_imem_read(u16 addr) { - switch (addr >> 12) - { - case 0: // 0xxx IRAM - return g_dsp.iram[addr & DSP_IRAM_MASK]; + switch (addr >> 12) + { + case 0: // 0xxx IRAM + return g_dsp.iram[addr & DSP_IRAM_MASK]; - case 8: // 8xxx IROM - contains code to receive code for IRAM, and a bunch of mixing loops. - return g_dsp.irom[addr & DSP_IROM_MASK]; + case 8: // 8xxx IROM - contains code to receive code for IRAM, and a bunch of mixing loops. + return g_dsp.irom[addr & DSP_IROM_MASK]; - default: // Unmapped/non-existing memory - ERROR_LOG(DSPLLE, "%04x DSP ERROR: Executing from invalid (%04x) memory", g_dsp.pc, addr); - return 0; - } + default: // Unmapped/non-existing memory + ERROR_LOG(DSPLLE, "%04x DSP ERROR: Executing from invalid (%04x) memory", g_dsp.pc, addr); + return 0; + } } u16 dsp_dmem_read(u16 addr) { - switch (addr >> 12) - { - case 0x0: // 0xxx DRAM - return g_dsp.dram[addr & DSP_DRAM_MASK]; + switch (addr >> 12) + { + case 0x0: // 0xxx DRAM + return g_dsp.dram[addr & DSP_DRAM_MASK]; - case 0x1: // 1xxx COEF - DEBUG_LOG(DSPLLE, "%04x : Coefficient Read @ %04x", g_dsp.pc, addr); - return g_dsp.coef[addr & DSP_COEF_MASK]; + case 0x1: // 1xxx COEF + DEBUG_LOG(DSPLLE, "%04x : Coefficient Read @ %04x", g_dsp.pc, addr); + return g_dsp.coef[addr & DSP_COEF_MASK]; - case 0xf: // Fxxx HW regs - return gdsp_ifx_read(addr); + case 0xf: // Fxxx HW regs + return gdsp_ifx_read(addr); - default: // Unmapped/non-existing memory - ERROR_LOG(DSPLLE, "%04x DSP ERROR: Read from UNKNOWN (%04x) memory", g_dsp.pc, addr); - return 0; - } + default: // Unmapped/non-existing memory + ERROR_LOG(DSPLLE, "%04x DSP ERROR: Read from UNKNOWN (%04x) memory", g_dsp.pc, addr); + return 0; + } } void dsp_dmem_write(u16 addr, u16 val) { - switch (addr >> 12) - { - case 0x0: // 0xxx DRAM - g_dsp.dram[addr & DSP_DRAM_MASK] = val; - break; + switch (addr >> 12) + { + case 0x0: // 0xxx DRAM + g_dsp.dram[addr & DSP_DRAM_MASK] = val; + break; - case 0xf: // Fxxx HW regs - gdsp_ifx_write(addr, val); - break; + case 0xf: // Fxxx HW regs + gdsp_ifx_write(addr, val); + break; - default: // Unmapped/non-existing memory - ERROR_LOG(DSPLLE, "%04x DSP ERROR: Write to UNKNOWN (%04x) memory", g_dsp.pc, addr); - break; - } + default: // Unmapped/non-existing memory + ERROR_LOG(DSPLLE, "%04x DSP ERROR: Write to UNKNOWN (%04x) memory", g_dsp.pc, addr); + break; + } } diff --git a/Source/Core/Core/DSP/DSPMemoryMap.h b/Source/Core/Core/DSP/DSPMemoryMap.h index c9f7476862..d9ebcef9fb 100644 --- a/Source/Core/Core/DSP/DSPMemoryMap.h +++ b/Source/Core/Core/DSP/DSPMemoryMap.h @@ -10,24 +10,24 @@ #include "Core/DSP/DSPCore.h" #include "Core/DSP/DSPTables.h" -u16 dsp_imem_read(u16 addr); +u16 dsp_imem_read(u16 addr); void dsp_dmem_write(u16 addr, u16 val); -u16 dsp_dmem_read(u16 addr); +u16 dsp_dmem_read(u16 addr); inline u16 dsp_fetch_code() { - u16 opc = dsp_imem_read(g_dsp.pc); + u16 opc = dsp_imem_read(g_dsp.pc); - g_dsp.pc++; - return opc; + g_dsp.pc++; + return opc; } inline u16 dsp_peek_code() { - return dsp_imem_read(g_dsp.pc); + return dsp_imem_read(g_dsp.pc); } inline void dsp_skip_inst() { - g_dsp.pc += opTable[dsp_peek_code()]->size; + g_dsp.pc += opTable[dsp_peek_code()]->size; } diff --git a/Source/Core/Core/DSP/DSPStacks.cpp b/Source/Core/Core/DSP/DSPStacks.cpp index becafff966..9cfdf3873e 100644 --- a/Source/Core/Core/DSP/DSPStacks.cpp +++ b/Source/Core/Core/DSP/DSPStacks.cpp @@ -12,27 +12,27 @@ static void dsp_reg_stack_push(int stack_reg) { - g_dsp.reg_stack_ptr[stack_reg]++; - g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; - g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]] = g_dsp.r.st[stack_reg]; + g_dsp.reg_stack_ptr[stack_reg]++; + g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; + g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]] = g_dsp.r.st[stack_reg]; } static void dsp_reg_stack_pop(int stack_reg) { - g_dsp.r.st[stack_reg] = g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]]; - g_dsp.reg_stack_ptr[stack_reg]--; - g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; + g_dsp.r.st[stack_reg] = g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]]; + g_dsp.reg_stack_ptr[stack_reg]--; + g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; } void dsp_reg_store_stack(int stack_reg, u16 val) { - dsp_reg_stack_push(stack_reg); - g_dsp.r.st[stack_reg] = val; + dsp_reg_stack_push(stack_reg); + g_dsp.r.st[stack_reg] = val; } u16 dsp_reg_load_stack(int stack_reg) { - u16 val = g_dsp.r.st[stack_reg]; - dsp_reg_stack_pop(stack_reg); - return val; + u16 val = g_dsp.r.st[stack_reg]; + dsp_reg_stack_pop(stack_reg); + return val; } diff --git a/Source/Core/Core/DSP/DSPTables.cpp b/Source/Core/Core/DSP/DSPTables.cpp index 757ae6f2c1..e3054f97da 100644 --- a/Source/Core/Core/DSP/DSPTables.cpp +++ b/Source/Core/Core/DSP/DSPTables.cpp @@ -7,571 +7,3704 @@ #include "Common/CommonTypes.h" #include "Core/DSP/DSPEmitter.h" -#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPIntExtOps.h" +#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPTables.h" void nop(const UDSPInstruction opc) { - // The real nop is 0. Anything else is bad. - if (opc) - { - ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x", opc); - } + // The real nop is 0. Anything else is bad. + if (opc) + { + ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x", opc); + } } -const DSPOPCTemplate opcodes[] = -{ - // # of parameters----+ {type, size, loc, lshift, mask} branch reads PC // instruction approximation - // name opcode mask interpreter function JIT function size-V V param 1 param 2 param 3 extendable uncond. updates SR - {"NOP", 0x0000, 0xfffc, nop, &DSPEmitter::nop, 1, 0, {}, false, false, false, false, false}, // no operation +const DSPOPCTemplate opcodes[] = { + // # of parameters----+ {type, size, + // loc, lshift, mask} + // branch reads PC // + // instruction approximation + // name opcode mask interpreter function JIT function size-V V param 1 + // param 2 param 3 extendable uncond. updates + // SR + {"NOP", + 0x0000, + 0xfffc, + nop, + &DSPEmitter::nop, + 1, + 0, + {}, + false, + false, + false, + false, + false}, // no operation - {"DAR", 0x0004, 0xfffc, DSPInterpreter::dar, &DSPEmitter::dar, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $arD-- - {"IAR", 0x0008, 0xfffc, DSPInterpreter::iar, &DSPEmitter::iar, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $arD++ - {"SUBARN", 0x000c, 0xfffc, DSPInterpreter::subarn, &DSPEmitter::subarn, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $arD -= $ixS - {"ADDARN", 0x0010, 0xfff0, DSPInterpreter::addarn, &DSPEmitter::addarn, 1, 2, {{P_REG, 1, 0, 0, 0x0003}, {P_REG04, 1, 0, 2, 0x000c}}, false, false, false, false, false}, // $arD += $ixS + {"DAR", + 0x0004, + 0xfffc, + DSPInterpreter::dar, + &DSPEmitter::dar, + 1, + 1, + {{P_REG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $arD-- + {"IAR", + 0x0008, + 0xfffc, + DSPInterpreter::iar, + &DSPEmitter::iar, + 1, + 1, + {{P_REG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $arD++ + {"SUBARN", + 0x000c, + 0xfffc, + DSPInterpreter::subarn, + &DSPEmitter::subarn, + 1, + 1, + {{P_REG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $arD -= $ixS + {"ADDARN", + 0x0010, + 0xfff0, + DSPInterpreter::addarn, + &DSPEmitter::addarn, + 1, + 2, + {{P_REG, 1, 0, 0, 0x0003}, {P_REG04, 1, 0, 2, 0x000c}}, + false, + false, + false, + false, + false}, // $arD += $ixS - {"HALT", 0x0021, 0xffff, DSPInterpreter::halt, &DSPEmitter::halt, 1, 0, {}, false, true, true, false, false}, // halt until reset + {"HALT", + 0x0021, + 0xffff, + DSPInterpreter::halt, + &DSPEmitter::halt, + 1, + 0, + {}, + false, + true, + true, + false, + false}, // halt until reset - {"RETGE", 0x02d0, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, // return if greater or equal - {"RETL", 0x02d1, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, // return if less - {"RETG", 0x02d2, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, // return if greater - {"RETLE", 0x02d3, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, // return if less or equal - {"RETNZ", 0x02d4, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, // return if not zero - {"RETZ", 0x02d5, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, // return if zero - {"RETNC", 0x02d6, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, // return if not carry - {"RETC", 0x02d7, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, // return if carry - {"RETx8", 0x02d8, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, // return if TODO - {"RETx9", 0x02d9, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, // return if TODO - {"RETxA", 0x02da, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, // return if TODO - {"RETxB", 0x02db, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, // return if TODO - {"RETLNZ", 0x02dc, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, // return if logic not zero - {"RETLZ", 0x02dd, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, // return if logic zero - {"RETO", 0x02de, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, false, true, false}, // return if overflow - {"RET", 0x02df, 0xffff, DSPInterpreter::ret, &DSPEmitter::ret, 1, 0, {}, false, true, true, false, false}, // unconditional return + {"RETGE", + 0x02d0, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // return if greater or equal + {"RETL", + 0x02d1, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // return if less + {"RETG", + 0x02d2, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // return if greater + {"RETLE", + 0x02d3, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // return if less or equal + {"RETNZ", + 0x02d4, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // return if not zero + {"RETZ", + 0x02d5, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // return if zero + {"RETNC", + 0x02d6, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // return if not carry + {"RETC", + 0x02d7, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // return if carry + {"RETx8", + 0x02d8, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // return if TODO + {"RETx9", + 0x02d9, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // return if TODO + {"RETxA", + 0x02da, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // return if TODO + {"RETxB", + 0x02db, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // return if TODO + {"RETLNZ", + 0x02dc, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // return if logic not zero + {"RETLZ", + 0x02dd, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // return if logic zero + {"RETO", + 0x02de, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // return if overflow + {"RET", + 0x02df, + 0xffff, + DSPInterpreter::ret, + &DSPEmitter::ret, + 1, + 0, + {}, + false, + true, + true, + false, + false}, // unconditional return - {"RTI", 0x02ff, 0xffff, DSPInterpreter::rti, &DSPEmitter::rti, 1, 0, {}, false, true, true, false, false}, // return from interrupt + {"RTI", + 0x02ff, + 0xffff, + DSPInterpreter::rti, + &DSPEmitter::rti, + 1, + 0, + {}, + false, + true, + true, + false, + false}, // return from interrupt - {"CALLGE", 0x02b0, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if greater or equal - {"CALLL", 0x02b1, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if less - {"CALLG", 0x02b2, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if greater - {"CALLLE", 0x02b3, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if less or equal - {"CALLNZ", 0x02b4, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if not zero - {"CALLZ", 0x02b5, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if zero - {"CALLNC", 0x02b6, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if not carry - {"CALLC", 0x02b7, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if carry - {"CALLx8", 0x02b8, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if TODO - {"CALLx9", 0x02b9, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if TODO - {"CALLxA", 0x02ba, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if TODO - {"CALLxB", 0x02bb, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if TODO - {"CALLLNZ", 0x02bc, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if logic not zero - {"CALLLZ", 0x02bd, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if logic zero - {"CALLO", 0x02be, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if overflow - {"CALL", 0x02bf, 0xffff, DSPInterpreter::call, &DSPEmitter::call, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, true, true, false}, // unconditional call + {"CALLGE", + 0x02b0, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // call if greater or equal + {"CALLL", + 0x02b1, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // call if less + {"CALLG", + 0x02b2, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // call if greater + {"CALLLE", + 0x02b3, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // call if less or equal + {"CALLNZ", + 0x02b4, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // call if not zero + {"CALLZ", + 0x02b5, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // call if zero + {"CALLNC", + 0x02b6, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // call if not carry + {"CALLC", + 0x02b7, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // call if carry + {"CALLx8", + 0x02b8, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // call if TODO + {"CALLx9", + 0x02b9, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // call if TODO + {"CALLxA", + 0x02ba, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // call if TODO + {"CALLxB", + 0x02bb, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // call if TODO + {"CALLLNZ", + 0x02bc, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // call if logic not zero + {"CALLLZ", + 0x02bd, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // call if logic zero + {"CALLO", + 0x02be, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // call if overflow + {"CALL", + 0x02bf, + 0xffff, + DSPInterpreter::call, + &DSPEmitter::call, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + true, + true, + false}, // unconditional call - {"IFGE", 0x0270, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, // if greater or equal - {"IFL", 0x0271, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, // if less - {"IFG", 0x0272, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, // if greater - {"IFLE", 0x0273, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, // if less or equal - {"IFNZ", 0x0274, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, // if not zero - {"IFZ", 0x0275, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, // if zero - {"IFNC", 0x0276, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, // if not carry - {"IFC", 0x0277, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, // if carry - {"IFx8", 0x0278, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, // if TODO - {"IFx9", 0x0279, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, // if TODO - {"IFxA", 0x027a, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, // if TODO - {"IFxB", 0x027b, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, // if TODO - {"IFLNZ", 0x027c, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, // if logic not zero - {"IFLZ", 0x027d, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, // if logic zero - {"IFO", 0x027e, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, false, true, false}, // if overflow - {"IF", 0x027f, 0xffff, DSPInterpreter::ifcc, &DSPEmitter::ifcc, 1, 0, {}, false, true, true, true, false}, // what is this, I don't even... + {"IFGE", + 0x0270, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // if greater or equal + {"IFL", + 0x0271, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // if less + {"IFG", + 0x0272, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // if greater + {"IFLE", + 0x0273, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // if less or equal + {"IFNZ", + 0x0274, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // if not zero + {"IFZ", + 0x0275, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // if zero + {"IFNC", + 0x0276, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // if not carry + {"IFC", + 0x0277, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // if carry + {"IFx8", + 0x0278, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // if TODO + {"IFx9", + 0x0279, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // if TODO + {"IFxA", + 0x027a, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // if TODO + {"IFxB", + 0x027b, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // if TODO + {"IFLNZ", + 0x027c, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // if logic not zero + {"IFLZ", + 0x027d, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // if logic zero + {"IFO", + 0x027e, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + false, + true, + false}, // if overflow + {"IF", + 0x027f, + 0xffff, + DSPInterpreter::ifcc, + &DSPEmitter::ifcc, + 1, + 0, + {}, + false, + true, + true, + true, + false}, // what is this, I don't even... - {"JGE", 0x0290, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // jump if greater or equal - {"JL", 0x0291, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // jump if less - {"JG", 0x0292, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // jump if greater - {"JLE", 0x0293, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // jump if less or equal - {"JNZ", 0x0294, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // jump if not zero - {"JZ", 0x0295, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // jump if zero - {"JNC", 0x0296, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // jump if not carry - {"JC", 0x0297, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // jump if carry - {"JMPx8", 0x0298, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // jump if TODO - {"JMPx9", 0x0299, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // jump if TODO - {"JMPxA", 0x029a, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // jump if TODO - {"JMPxB", 0x029b, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // jump if TODO - {"JLNZ", 0x029c, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // jump if logic not zero - {"JLZ", 0x029d, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // jump if logic zero - {"JO", 0x029e, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // jump if overflow - {"JMP", 0x029f, 0xffff, DSPInterpreter::jcc, &DSPEmitter::jcc, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, true, true, false}, // unconditional jump + {"JGE", + 0x0290, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // jump if greater or equal + {"JL", + 0x0291, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // jump if less + {"JG", + 0x0292, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // jump if greater + {"JLE", + 0x0293, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // jump if less or equal + {"JNZ", + 0x0294, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // jump if not zero + {"JZ", + 0x0295, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // jump if zero + {"JNC", + 0x0296, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // jump if not carry + {"JC", + 0x0297, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // jump if carry + {"JMPx8", + 0x0298, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // jump if TODO + {"JMPx9", + 0x0299, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // jump if TODO + {"JMPxA", + 0x029a, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // jump if TODO + {"JMPxB", + 0x029b, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // jump if TODO + {"JLNZ", + 0x029c, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // jump if logic not zero + {"JLZ", + 0x029d, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // jump if logic zero + {"JO", + 0x029e, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + false, + true, + false}, // jump if overflow + {"JMP", + 0x029f, + 0xffff, + DSPInterpreter::jcc, + &DSPEmitter::jcc, + 2, + 1, + {{P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + true, + true, + false}, // unconditional jump - {"JRGE", 0x1700, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, // jump to $R if greater or equal - {"JRL", 0x1701, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, // jump to $R if less - {"JRG", 0x1702, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, // jump to $R if greater - {"JRLE", 0x1703, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, // jump to $R if less or equal - {"JRNZ", 0x1704, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, // jump to $R if not zero - {"JRZ", 0x1705, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, // jump to $R if zero - {"JRNC", 0x1706, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, // jump to $R if not carry - {"JRC", 0x1707, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, // jump to $R if carry - {"JMPRx8", 0x1708, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, // jump to $R if TODO - {"JMPRx9", 0x1709, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, // jump to $R if TODO - {"JMPRxA", 0x170a, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, // jump to $R if TODO - {"JMPRxB", 0x170b, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, // jump to $R if TODO - {"JRLNZ", 0x170c, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, // jump to $R if logic not zero - {"JRLZ", 0x170d, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, // jump to $R if logic zero - {"JRO", 0x170e, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, false, false}, // jump to $R if overflow - {"JMPR", 0x170f, 0xff1f, DSPInterpreter::jmprcc, &DSPEmitter::jmprcc, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, true, false, false}, // jump to $R + {"JRGE", + 0x1700, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + false, + false}, // jump to $R if greater or equal + {"JRL", + 0x1701, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + false, + false}, // jump to $R if less + {"JRG", + 0x1702, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + false, + false}, // jump to $R if greater + {"JRLE", + 0x1703, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + false, + false}, // jump to $R if less or equal + {"JRNZ", + 0x1704, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + false, + false}, // jump to $R if not zero + {"JRZ", + 0x1705, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + false, + false}, // jump to $R if zero + {"JRNC", + 0x1706, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + false, + false}, // jump to $R if not carry + {"JRC", + 0x1707, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + false, + false}, // jump to $R if carry + {"JMPRx8", + 0x1708, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + false, + false}, // jump to $R if TODO + {"JMPRx9", + 0x1709, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + false, + false}, // jump to $R if TODO + {"JMPRxA", + 0x170a, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + false, + false}, // jump to $R if TODO + {"JMPRxB", + 0x170b, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + false, + false}, // jump to $R if TODO + {"JRLNZ", + 0x170c, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + false, + false}, // jump to $R if logic not zero + {"JRLZ", + 0x170d, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + false, + false}, // jump to $R if logic zero + {"JRO", + 0x170e, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + false, + false}, // jump to $R if overflow + {"JMPR", + 0x170f, + 0xff1f, + DSPInterpreter::jmprcc, + &DSPEmitter::jmprcc, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + true, + false, + false}, // jump to $R - {"CALLRGE", 0x1710, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, // call $R if greater or equal - {"CALLRL", 0x1711, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, // call $R if less - {"CALLRG", 0x1712, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, // call $R if greater - {"CALLRLE", 0x1713, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, // call $R if less or equal - {"CALLRNZ", 0x1714, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, // call $R if not zero - {"CALLRZ", 0x1715, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, // call $R if zero - {"CALLRNC", 0x1716, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, // call $R if not carry - {"CALLRC", 0x1717, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, // call $R if carry - {"CALLRx8", 0x1718, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, // call $R if TODO - {"CALLRx9", 0x1719, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, // call $R if TODO - {"CALLRxA", 0x171a, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, // call $R if TODO - {"CALLRxB", 0x171b, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, // call $R if TODO - {"CALLRLNZ", 0x171c, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, // call $R if logic not zero - {"CALLRLZ", 0x171d, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, // call $R if logic zero - {"CALLRO", 0x171e, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, false, true, false}, // call $R if overflow - {"CALLR", 0x171f, 0xff1f, DSPInterpreter::callr, &DSPEmitter::callr, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false, true, true, true, false}, // call $R + {"CALLRGE", + 0x1710, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + true, + false}, // call $R if greater or equal + {"CALLRL", + 0x1711, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + true, + false}, // call $R if less + {"CALLRG", + 0x1712, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + true, + false}, // call $R if greater + {"CALLRLE", + 0x1713, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + true, + false}, // call $R if less or equal + {"CALLRNZ", + 0x1714, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + true, + false}, // call $R if not zero + {"CALLRZ", + 0x1715, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + true, + false}, // call $R if zero + {"CALLRNC", + 0x1716, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + true, + false}, // call $R if not carry + {"CALLRC", + 0x1717, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + true, + false}, // call $R if carry + {"CALLRx8", + 0x1718, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + true, + false}, // call $R if TODO + {"CALLRx9", + 0x1719, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + true, + false}, // call $R if TODO + {"CALLRxA", + 0x171a, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + true, + false}, // call $R if TODO + {"CALLRxB", + 0x171b, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + true, + false}, // call $R if TODO + {"CALLRLNZ", + 0x171c, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + true, + false}, // call $R if logic not zero + {"CALLRLZ", + 0x171d, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + true, + false}, // call $R if logic zero + {"CALLRO", + 0x171e, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + false, + true, + false}, // call $R if overflow + {"CALLR", + 0x171f, + 0xff1f, + DSPInterpreter::callr, + &DSPEmitter::callr, + 1, + 1, + {{P_REG, 1, 0, 5, 0x00e0}}, + false, + true, + true, + true, + false}, // call $R - {"SBCLR", 0x1200, 0xff00, DSPInterpreter::sbclr, &DSPEmitter::sbclr, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, false, false, false, false, false}, // $sr &= ~(I + 6) - {"SBSET", 0x1300, 0xff00, DSPInterpreter::sbset, &DSPEmitter::sbset, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, false, false, false, false, false}, // $sr |= (I + 6) + {"SBCLR", + 0x1200, + 0xff00, + DSPInterpreter::sbclr, + &DSPEmitter::sbclr, + 1, + 1, + {{P_IMM, 1, 0, 0, 0x0007}}, + false, + false, + false, + false, + false}, // $sr &= ~(I + 6) + {"SBSET", + 0x1300, + 0xff00, + DSPInterpreter::sbset, + &DSPEmitter::sbset, + 1, + 1, + {{P_IMM, 1, 0, 0, 0x0007}}, + false, + false, + false, + false, + false}, // $sr |= (I + 6) - {"LSL", 0x1400, 0xfec0, DSPInterpreter::lsl, &DSPEmitter::lsl, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false, false, true}, // $acR <<= I - {"LSR", 0x1440, 0xfec0, DSPInterpreter::lsr, &DSPEmitter::lsr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false, false, true}, // $acR >>= I (shifting in zeros) - {"ASL", 0x1480, 0xfec0, DSPInterpreter::asl, &DSPEmitter::asl, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false, false, true}, // $acR <<= I - {"ASR", 0x14c0, 0xfec0, DSPInterpreter::asr, &DSPEmitter::asr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false, false, true}, // $acR >>= I (shifting in sign bits) + {"LSL", + 0x1400, + 0xfec0, + DSPInterpreter::lsl, + &DSPEmitter::lsl, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, + false, + false, + false, + false, + true}, // $acR <<= I + {"LSR", + 0x1440, + 0xfec0, + DSPInterpreter::lsr, + &DSPEmitter::lsr, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, + false, + false, + false, + false, + true}, // $acR >>= I (shifting in zeros) + {"ASL", + 0x1480, + 0xfec0, + DSPInterpreter::asl, + &DSPEmitter::asl, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, + false, + false, + false, + false, + true}, // $acR <<= I + {"ASR", + 0x14c0, + 0xfec0, + DSPInterpreter::asr, + &DSPEmitter::asr, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, + false, + false, + false, + false, + true}, // $acR >>= I (shifting in sign bits) - // these two were discovered by ector - {"LSRN", 0x02ca, 0xffff, DSPInterpreter::lsrn, &DSPEmitter::lsrn, 1, 0, {}, false, false, false, false, true}, // $ac0 >>=/<<= $ac1.m[0-6] - {"ASRN", 0x02cb, 0xffff, DSPInterpreter::asrn, &DSPEmitter::asrn, 1, 0, {}, false, false, false, false, true}, // $ac0 >>=/<<= $ac1.m[0-6] (arithmetic) + // these two were discovered by ector + {"LSRN", + 0x02ca, + 0xffff, + DSPInterpreter::lsrn, + &DSPEmitter::lsrn, + 1, + 0, + {}, + false, + false, + false, + false, + true}, // $ac0 >>=/<<= $ac1.m[0-6] + {"ASRN", + 0x02cb, + 0xffff, + DSPInterpreter::asrn, + &DSPEmitter::asrn, + 1, + 0, + {}, + false, + false, + false, + false, + true}, // $ac0 >>=/<<= $ac1.m[0-6] (arithmetic) - {"LRI", 0x0080, 0xffe0, DSPInterpreter::lri, &DSPEmitter::lri, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, false}, // $D = I - {"LR", 0x00c0, 0xffe0, DSPInterpreter::lr, &DSPEmitter::lr, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_MEM, 2, 1, 0, 0xffff}}, false, false, false, true, false}, // $D = MEM[M] - {"SR", 0x00e0, 0xffe0, DSPInterpreter::sr, &DSPEmitter::sr, 2, 2, {{P_MEM, 2, 1, 0, 0xffff}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, true, false}, // MEM[M] = $S + {"LRI", + 0x0080, + 0xffe0, + DSPInterpreter::lri, + &DSPEmitter::lri, + 2, + 2, + {{P_REG, 1, 0, 0, 0x001f}, {P_IMM, 2, 1, 0, 0xffff}}, + false, + false, + false, + true, + false}, // $D = I + {"LR", + 0x00c0, + 0xffe0, + DSPInterpreter::lr, + &DSPEmitter::lr, + 2, + 2, + {{P_REG, 1, 0, 0, 0x001f}, {P_MEM, 2, 1, 0, 0xffff}}, + false, + false, + false, + true, + false}, // $D = MEM[M] + {"SR", + 0x00e0, + 0xffe0, + DSPInterpreter::sr, + &DSPEmitter::sr, + 2, + 2, + {{P_MEM, 2, 1, 0, 0xffff}, {P_REG, 1, 0, 0, 0x001f}}, + false, + false, + false, + true, + false}, // MEM[M] = $S - {"MRR", 0x1c00, 0xfc00, DSPInterpreter::mrr, &DSPEmitter::mrr, 1, 2, {{P_REG, 1, 0, 5, 0x03e0}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, false, false}, // $D = $S + {"MRR", + 0x1c00, + 0xfc00, + DSPInterpreter::mrr, + &DSPEmitter::mrr, + 1, + 2, + {{P_REG, 1, 0, 5, 0x03e0}, {P_REG, 1, 0, 0, 0x001f}}, + false, + false, + false, + false, + false}, // $D = $S - {"SI", 0x1600, 0xff00, DSPInterpreter::si, &DSPEmitter::si, 2, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, false}, // MEM[M] = I + {"SI", + 0x1600, + 0xff00, + DSPInterpreter::si, + &DSPEmitter::si, + 2, + 2, + {{P_MEM, 1, 0, 0, 0x00ff}, {P_IMM, 2, 1, 0, 0xffff}}, + false, + false, + false, + true, + false}, // MEM[M] = I - {"ADDIS", 0x0400, 0xfe00, DSPInterpreter::addis, &DSPEmitter::addis, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, false, false, false, false, true}, // $acD.hm += I - {"CMPIS", 0x0600, 0xfe00, DSPInterpreter::cmpis, &DSPEmitter::cmpis, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, false, false, false, false, true}, // FLAGS($acD - I) - {"LRIS", 0x0800, 0xf800, DSPInterpreter::lris, &DSPEmitter::lris, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_IMM, 1, 0, 0, 0x00ff}}, false, false, false, false, true}, // $(D+24) = I + {"ADDIS", + 0x0400, + 0xfe00, + DSPInterpreter::addis, + &DSPEmitter::addis, + 1, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, + false, + false, + false, + false, + true}, // $acD.hm += I + {"CMPIS", + 0x0600, + 0xfe00, + DSPInterpreter::cmpis, + &DSPEmitter::cmpis, + 1, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x00ff}}, + false, + false, + false, + false, + true}, // FLAGS($acD - I) + {"LRIS", + 0x0800, + 0xf800, + DSPInterpreter::lris, + &DSPEmitter::lris, + 1, + 2, + {{P_REG18, 1, 0, 8, 0x0700}, {P_IMM, 1, 0, 0, 0x00ff}}, + false, + false, + false, + false, + true}, // $(D+24) = I - {"ADDI", 0x0200, 0xfeff, DSPInterpreter::addi, &DSPEmitter::addi, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, // $acD.hm += I - {"XORI", 0x0220, 0xfeff, DSPInterpreter::xori, &DSPEmitter::xori, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, // $acD.m ^= I - {"ANDI", 0x0240, 0xfeff, DSPInterpreter::andi, &DSPEmitter::andi, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, // $acD.m &= I - {"ORI", 0x0260, 0xfeff, DSPInterpreter::ori, &DSPEmitter::ori, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, // $acD.m |= I - {"CMPI", 0x0280, 0xfeff, DSPInterpreter::cmpi, &DSPEmitter::cmpi, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, // FLAGS(($acD.hm - I) | $acD.l) + {"ADDI", + 0x0200, + 0xfeff, + DSPInterpreter::addi, + &DSPEmitter::addi, + 2, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, + false, + false, + false, + true, + true}, // $acD.hm += I + {"XORI", + 0x0220, + 0xfeff, + DSPInterpreter::xori, + &DSPEmitter::xori, + 2, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, + false, + false, + false, + true, + true}, // $acD.m ^= I + {"ANDI", + 0x0240, + 0xfeff, + DSPInterpreter::andi, + &DSPEmitter::andi, + 2, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, + false, + false, + false, + true, + true}, // $acD.m &= I + {"ORI", + 0x0260, + 0xfeff, + DSPInterpreter::ori, + &DSPEmitter::ori, + 2, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, + false, + false, + false, + true, + true}, // $acD.m |= I + {"CMPI", + 0x0280, + 0xfeff, + DSPInterpreter::cmpi, + &DSPEmitter::cmpi, + 2, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, + false, + false, + false, + true, + true}, // FLAGS(($acD.hm - I) | $acD.l) - {"ANDF", 0x02a0, 0xfeff, DSPInterpreter::andf, &DSPEmitter::andf, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, // $sr.LZ = ($acD.m & I) == 0 ? 1 : 0 - {"ANDCF", 0x02c0, 0xfeff, DSPInterpreter::andcf, &DSPEmitter::andcf, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false, false, false, true, true}, // $sr.LZ = ($acD.m & I) == I ? 1 : 0 + {"ANDF", + 0x02a0, + 0xfeff, + DSPInterpreter::andf, + &DSPEmitter::andf, + 2, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, + false, + false, + false, + true, + true}, // $sr.LZ = ($acD.m & I) == 0 ? 1 : 0 + {"ANDCF", + 0x02c0, + 0xfeff, + DSPInterpreter::andcf, + &DSPEmitter::andcf, + 2, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, + false, + false, + false, + true, + true}, // $sr.LZ = ($acD.m & I) == I ? 1 : 0 - {"ILRR", 0x0210, 0xfefc, DSPInterpreter::ilrr, &DSPEmitter::ilrr, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $acD.m = IMEM[$arS] - {"ILRRD", 0x0214, 0xfefc, DSPInterpreter::ilrrd, &DSPEmitter::ilrrd, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $acD.m = IMEM[$arS--] - {"ILRRI", 0x0218, 0xfefc, DSPInterpreter::ilrri, &DSPEmitter::ilrri, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $acD.m = IMEM[$arS++] - {"ILRRN", 0x021c, 0xfefc, DSPInterpreter::ilrrn, &DSPEmitter::ilrrn, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $acD.m = IMEM[$arS]; $arS += $ixS + {"ILRR", + 0x0210, + 0xfefc, + DSPInterpreter::ilrr, + &DSPEmitter::ilrr, + 1, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $acD.m = IMEM[$arS] + {"ILRRD", + 0x0214, + 0xfefc, + DSPInterpreter::ilrrd, + &DSPEmitter::ilrrd, + 1, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $acD.m = IMEM[$arS--] + {"ILRRI", + 0x0218, + 0xfefc, + DSPInterpreter::ilrri, + &DSPEmitter::ilrri, + 1, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $acD.m = IMEM[$arS++] + {"ILRRN", + 0x021c, + 0xfefc, + DSPInterpreter::ilrrn, + &DSPEmitter::ilrrn, + 1, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $acD.m = IMEM[$arS]; $arS += $ixS - // LOOPS - {"LOOP", 0x0040, 0xffe0, DSPInterpreter::loop, &DSPEmitter::loop, 1, 1, {{P_REG, 1, 0, 0, 0x001f}}, false, true, true, true, false}, // run next instruction $R times - {"BLOOP", 0x0060, 0xffe0, DSPInterpreter::bloop, &DSPEmitter::bloop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, true, true, false}, // COMEFROM addr $R times - {"LOOPI", 0x1000, 0xff00, DSPInterpreter::loopi, &DSPEmitter::loopi, 1, 1, {{P_IMM, 1, 0, 0, 0x00ff}}, false, true, true, true, false}, // run next instruction I times - {"BLOOPI", 0x1100, 0xff00, DSPInterpreter::bloopi, &DSPEmitter::bloopi, 2, 2, {{P_IMM, 1, 0, 0, 0x00ff}, {P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, true, true, false}, // COMEFROM addr I times + // LOOPS + {"LOOP", + 0x0040, + 0xffe0, + DSPInterpreter::loop, + &DSPEmitter::loop, + 1, + 1, + {{P_REG, 1, 0, 0, 0x001f}}, + false, + true, + true, + true, + false}, // run next instruction $R times + {"BLOOP", + 0x0060, + 0xffe0, + DSPInterpreter::bloop, + &DSPEmitter::bloop, + 2, + 2, + {{P_REG, 1, 0, 0, 0x001f}, {P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + true, + true, + false}, // COMEFROM addr $R times + {"LOOPI", + 0x1000, + 0xff00, + DSPInterpreter::loopi, + &DSPEmitter::loopi, + 1, + 1, + {{P_IMM, 1, 0, 0, 0x00ff}}, + false, + true, + true, + true, + false}, // run next instruction I times + {"BLOOPI", + 0x1100, + 0xff00, + DSPInterpreter::bloopi, + &DSPEmitter::bloopi, + 2, + 2, + {{P_IMM, 1, 0, 0, 0x00ff}, {P_ADDR_I, 2, 1, 0, 0xffff}}, + false, + true, + true, + true, + false}, // COMEFROM addr I times - // load and store value pointed by indexing reg and increment; LRR/SRR variants - {"LRR", 0x1800, 0xff80, DSPInterpreter::lrr, &DSPEmitter::lrr, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, false, false, false, false, false}, // $D = MEM[$arS] - {"LRRD", 0x1880, 0xff80, DSPInterpreter::lrrd, &DSPEmitter::lrrd, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, false, false, false, false, false}, // $D = MEM[$arS--] - {"LRRI", 0x1900, 0xff80, DSPInterpreter::lrri, &DSPEmitter::lrri, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, false, false, false, false, false}, // $D = MEM[$arS++] - {"LRRN", 0x1980, 0xff80, DSPInterpreter::lrrn, &DSPEmitter::lrrn, 1, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, false, false, false, false, false}, // $D = MEM[$arS]; $arS += $ixS + // load and store value pointed by indexing reg and increment; LRR/SRR variants + {"LRR", + 0x1800, + 0xff80, + DSPInterpreter::lrr, + &DSPEmitter::lrr, + 1, + 2, + {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, + false, + false, + false, + false, + false}, // $D = MEM[$arS] + {"LRRD", + 0x1880, + 0xff80, + DSPInterpreter::lrrd, + &DSPEmitter::lrrd, + 1, + 2, + {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, + false, + false, + false, + false, + false}, // $D = MEM[$arS--] + {"LRRI", + 0x1900, + 0xff80, + DSPInterpreter::lrri, + &DSPEmitter::lrri, + 1, + 2, + {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, + false, + false, + false, + false, + false}, // $D = MEM[$arS++] + {"LRRN", + 0x1980, + 0xff80, + DSPInterpreter::lrrn, + &DSPEmitter::lrrn, + 1, + 2, + {{P_REG, 1, 0, 0, 0x001f}, {P_PRG, 1, 0, 5, 0x0060}}, + false, + false, + false, + false, + false}, // $D = MEM[$arS]; $arS += $ixS - {"SRR", 0x1a00, 0xff80, DSPInterpreter::srr, &DSPEmitter::srr, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, false, false}, // MEM[$arD] = $S - {"SRRD", 0x1a80, 0xff80, DSPInterpreter::srrd, &DSPEmitter::srrd, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, false, false}, // MEM[$arD--] = $S - {"SRRI", 0x1b00, 0xff80, DSPInterpreter::srri, &DSPEmitter::srri, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, false, false}, // MEM[$arD++] = $S - {"SRRN", 0x1b80, 0xff80, DSPInterpreter::srrn, &DSPEmitter::srrn, 1, 2, {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, false, false, false, false, false}, // MEM[$arD] = $S; $arD += $ixD + {"SRR", + 0x1a00, + 0xff80, + DSPInterpreter::srr, + &DSPEmitter::srr, + 1, + 2, + {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, + false, + false, + false, + false, + false}, // MEM[$arD] = $S + {"SRRD", + 0x1a80, + 0xff80, + DSPInterpreter::srrd, + &DSPEmitter::srrd, + 1, + 2, + {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, + false, + false, + false, + false, + false}, // MEM[$arD--] = $S + {"SRRI", + 0x1b00, + 0xff80, + DSPInterpreter::srri, + &DSPEmitter::srri, + 1, + 2, + {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, + false, + false, + false, + false, + false}, // MEM[$arD++] = $S + {"SRRN", + 0x1b80, + 0xff80, + DSPInterpreter::srrn, + &DSPEmitter::srrn, + 1, + 2, + {{P_PRG, 1, 0, 5, 0x0060}, {P_REG, 1, 0, 0, 0x001f}}, + false, + false, + false, + false, + false}, // MEM[$arD] = $S; $arD += $ixD - //2 - {"LRS", 0x2000, 0xf800, DSPInterpreter::lrs, &DSPEmitter::lrs, 1, 2, {{P_REG18, 1, 0, 8, 0x0700}, {P_MEM, 1, 0, 0, 0x00ff}}, false, false, false, false, false}, // $(D+24) = MEM[($cr[0-7] << 8) | I] - {"SRS", 0x2800, 0xf800, DSPInterpreter::srs, &DSPEmitter::srs, 1, 2, {{P_MEM, 1, 0, 0, 0x00ff}, {P_REG18, 1, 0, 8, 0x0700}}, false, false, false, false, false}, // MEM[($cr[0-7] << 8) | I] = $(S+24) + // 2 + {"LRS", + 0x2000, + 0xf800, + DSPInterpreter::lrs, + &DSPEmitter::lrs, + 1, + 2, + {{P_REG18, 1, 0, 8, 0x0700}, {P_MEM, 1, 0, 0, 0x00ff}}, + false, + false, + false, + false, + false}, // $(D+24) = MEM[($cr[0-7] << 8) | I] + {"SRS", + 0x2800, + 0xf800, + DSPInterpreter::srs, + &DSPEmitter::srs, + 1, + 2, + {{P_MEM, 1, 0, 0, 0x00ff}, {P_REG18, 1, 0, 8, 0x0700}}, + false, + false, + false, + false, + false}, // MEM[($cr[0-7] << 8) | I] = $(S+24) -// opcodes that can be extended + // opcodes that can be extended - //3 - main opcode defined by 9 bits, extension defined by last 7 bits!! - {"XORR", 0x3000, 0xfc80, DSPInterpreter::xorr, &DSPEmitter::xorr, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, true, false, false, false, true}, // $acD.m ^= $axS.h - {"ANDR", 0x3400, 0xfc80, DSPInterpreter::andr, &DSPEmitter::andr, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, true, false, false, false, true}, // $acD.m &= $axS.h - {"ORR", 0x3800, 0xfc80, DSPInterpreter::orr, &DSPEmitter::orr, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, true, false, false, false, true}, // $acD.m |= $axS.h - {"ANDC", 0x3c00, 0xfe80, DSPInterpreter::andc, &DSPEmitter::andc, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD.m &= $ac(1-D).m - {"ORC", 0x3e00, 0xfe80, DSPInterpreter::orc, &DSPEmitter::orc, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD.m |= $ac(1-D).m - {"XORC", 0x3080, 0xfe80, DSPInterpreter::xorc, &DSPEmitter::xorc, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD.m ^= $ac(1-D).m - {"NOT", 0x3280, 0xfe80, DSPInterpreter::notc, &DSPEmitter::notc, 1, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD.m = ~$acD.m - {"LSRNRX", 0x3480, 0xfc80, DSPInterpreter::lsrnrx, &DSPEmitter::lsrnrx, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, true, false, false, false, true}, // $acD >>=/<<= $axS.h[0-6] - {"ASRNRX", 0x3880, 0xfc80, DSPInterpreter::asrnrx, &DSPEmitter::asrnrx, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, true, false, false, false, true}, // $acD >>=/<<= $axS.h[0-6] (arithmetic) - {"LSRNR", 0x3c80, 0xfe80, DSPInterpreter::lsrnr, &DSPEmitter::lsrnr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD >>=/<<= $ac(1-D).m[0-6] - {"ASRNR", 0x3e80, 0xfe80, DSPInterpreter::asrnr, &DSPEmitter::asrnr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD >>=/<<= $ac(1-D).m[0-6] (arithmetic) + // 3 - main opcode defined by 9 bits, extension defined by last 7 bits!! + {"XORR", + 0x3000, + 0xfc80, + DSPInterpreter::xorr, + &DSPEmitter::xorr, + 1, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, + true, + false, + false, + false, + true}, // $acD.m ^= $axS.h + {"ANDR", + 0x3400, + 0xfc80, + DSPInterpreter::andr, + &DSPEmitter::andr, + 1, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, + true, + false, + false, + false, + true}, // $acD.m &= $axS.h + {"ORR", + 0x3800, + 0xfc80, + DSPInterpreter::orr, + &DSPEmitter::orr, + 1, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, + true, + false, + false, + false, + true}, // $acD.m |= $axS.h + {"ANDC", + 0x3c00, + 0xfe80, + DSPInterpreter::andc, + &DSPEmitter::andc, + 1, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD.m &= $ac(1-D).m + {"ORC", + 0x3e00, + 0xfe80, + DSPInterpreter::orc, + &DSPEmitter::orc, + 1, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD.m |= $ac(1-D).m + {"XORC", + 0x3080, + 0xfe80, + DSPInterpreter::xorc, + &DSPEmitter::xorc, + 1, + 2, + {{P_ACCM, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD.m ^= $ac(1-D).m + {"NOT", + 0x3280, + 0xfe80, + DSPInterpreter::notc, + &DSPEmitter::notc, + 1, + 1, + {{P_ACCM, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD.m = ~$acD.m + {"LSRNRX", + 0x3480, + 0xfc80, + DSPInterpreter::lsrnrx, + &DSPEmitter::lsrnrx, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, + true, + false, + false, + false, + true}, // $acD >>=/<<= $axS.h[0-6] + {"ASRNRX", + 0x3880, + 0xfc80, + DSPInterpreter::asrnrx, + &DSPEmitter::asrnrx, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 9, 0x0200}}, + true, + false, + false, + false, + true}, // $acD >>=/<<= $axS.h[0-6] (arithmetic) + {"LSRNR", + 0x3c80, + 0xfe80, + DSPInterpreter::lsrnr, + &DSPEmitter::lsrnr, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD >>=/<<= $ac(1-D).m[0-6] + {"ASRNR", + 0x3e80, + 0xfe80, + DSPInterpreter::asrnr, + &DSPEmitter::asrnr, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD >>=/<<= $ac(1-D).m[0-6] (arithmetic) - //4 - {"ADDR", 0x4000, 0xf800, DSPInterpreter::addr, &DSPEmitter::addr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, true, false, false, false, true}, // $acD += $(S+24) - {"ADDAX", 0x4800, 0xfc00, DSPInterpreter::addax, &DSPEmitter::addax, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_AX, 1, 0, 9, 0x0200}}, true, false, false, false, true}, // $acD += $axS - {"ADD", 0x4c00, 0xfe00, DSPInterpreter::add, &DSPEmitter::add, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD += $ac(1-D) - {"ADDP", 0x4e00, 0xfe00, DSPInterpreter::addp, &DSPEmitter::addp, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD += $prod + // 4 + {"ADDR", + 0x4000, + 0xf800, + DSPInterpreter::addr, + &DSPEmitter::addr, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, + true, + false, + false, + false, + true}, // $acD += $(S+24) + {"ADDAX", + 0x4800, + 0xfc00, + DSPInterpreter::addax, + &DSPEmitter::addax, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_AX, 1, 0, 9, 0x0200}}, + true, + false, + false, + false, + true}, // $acD += $axS + {"ADD", + 0x4c00, + 0xfe00, + DSPInterpreter::add, + &DSPEmitter::add, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD += $ac(1-D) + {"ADDP", + 0x4e00, + 0xfe00, + DSPInterpreter::addp, + &DSPEmitter::addp, + 1, + 1, + {{P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD += $prod - //5 - {"SUBR", 0x5000, 0xf800, DSPInterpreter::subr, &DSPEmitter::subr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, true, false, false, false, true}, // $acD -= $(S+24) - {"SUBAX", 0x5800, 0xfc00, DSPInterpreter::subax, &DSPEmitter::subax, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_AX, 1, 0, 9, 0x0200}}, true, false, false, false, true}, // $acD -= $axS - {"SUB", 0x5c00, 0xfe00, DSPInterpreter::sub, &DSPEmitter::sub, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD -= $ac(1-D) - {"SUBP", 0x5e00, 0xfe00, DSPInterpreter::subp, &DSPEmitter::subp, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD -= $prod + // 5 + {"SUBR", + 0x5000, + 0xf800, + DSPInterpreter::subr, + &DSPEmitter::subr, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, + true, + false, + false, + false, + true}, // $acD -= $(S+24) + {"SUBAX", + 0x5800, + 0xfc00, + DSPInterpreter::subax, + &DSPEmitter::subax, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_AX, 1, 0, 9, 0x0200}}, + true, + false, + false, + false, + true}, // $acD -= $axS + {"SUB", + 0x5c00, + 0xfe00, + DSPInterpreter::sub, + &DSPEmitter::sub, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD -= $ac(1-D) + {"SUBP", + 0x5e00, + 0xfe00, + DSPInterpreter::subp, + &DSPEmitter::subp, + 1, + 1, + {{P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD -= $prod - //6 - {"MOVR", 0x6000, 0xf800, DSPInterpreter::movr, &DSPEmitter::movr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, true, false, false, false, true}, // $acD.hm = $(S+24); $acD.l = 0 - {"MOVAX", 0x6800, 0xfc00, DSPInterpreter::movax, &DSPEmitter::movax, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_AX, 1, 0, 9, 0x0200}}, true, false, false, false, true}, // $acD = $axS - {"MOV", 0x6c00, 0xfe00, DSPInterpreter::mov, &DSPEmitter::mov, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD = $ax(1-D) - {"MOVP", 0x6e00, 0xfe00, DSPInterpreter::movp, &DSPEmitter::movp, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD = $prod + // 6 + {"MOVR", + 0x6000, + 0xf800, + DSPInterpreter::movr, + &DSPEmitter::movr, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, + true, + false, + false, + false, + true}, // $acD.hm = $(S+24); $acD.l = 0 + {"MOVAX", + 0x6800, + 0xfc00, + DSPInterpreter::movax, + &DSPEmitter::movax, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_AX, 1, 0, 9, 0x0200}}, + true, + false, + false, + false, + true}, // $acD = $axS + {"MOV", + 0x6c00, + 0xfe00, + DSPInterpreter::mov, + &DSPEmitter::mov, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD = $ax(1-D) + {"MOVP", + 0x6e00, + 0xfe00, + DSPInterpreter::movp, + &DSPEmitter::movp, + 1, + 1, + {{P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD = $prod - //7 - {"ADDAXL", 0x7000, 0xfc00, DSPInterpreter::addaxl, &DSPEmitter::addaxl, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, true, false, false, false, true}, // $acD += $axS.l - {"INCM", 0x7400, 0xfe00, DSPInterpreter::incm, &DSPEmitter::incm, 1, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acsD++ - {"INC", 0x7600, 0xfe00, DSPInterpreter::inc, &DSPEmitter::inc, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD++ - {"DECM", 0x7800, 0xfe00, DSPInterpreter::decm, &DSPEmitter::decm, 1, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acsD-- - {"DEC", 0x7a00, 0xfe00, DSPInterpreter::dec, &DSPEmitter::dec, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD-- - {"NEG", 0x7c00, 0xfe00, DSPInterpreter::neg, &DSPEmitter::neg, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD = -$acD - {"MOVNP", 0x7e00, 0xfe00, DSPInterpreter::movnp, &DSPEmitter::movnp, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD = -$prod + // 7 + {"ADDAXL", + 0x7000, + 0xfc00, + DSPInterpreter::addaxl, + &DSPEmitter::addaxl, + 1, + 2, + {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, + true, + false, + false, + false, + true}, // $acD += $axS.l + {"INCM", + 0x7400, + 0xfe00, + DSPInterpreter::incm, + &DSPEmitter::incm, + 1, + 1, + {{P_ACCM, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acsD++ + {"INC", + 0x7600, + 0xfe00, + DSPInterpreter::inc, + &DSPEmitter::inc, + 1, + 1, + {{P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD++ + {"DECM", + 0x7800, + 0xfe00, + DSPInterpreter::decm, + &DSPEmitter::decm, + 1, + 1, + {{P_ACCM, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acsD-- + {"DEC", + 0x7a00, + 0xfe00, + DSPInterpreter::dec, + &DSPEmitter::dec, + 1, + 1, + {{P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD-- + {"NEG", + 0x7c00, + 0xfe00, + DSPInterpreter::neg, + &DSPEmitter::neg, + 1, + 1, + {{P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD = -$acD + {"MOVNP", + 0x7e00, + 0xfe00, + DSPInterpreter::movnp, + &DSPEmitter::movnp, + 1, + 1, + {{P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD = -$prod - //8 - {"NX", 0x8000, 0xf700, DSPInterpreter::nx, &DSPEmitter::nx, 1, 0, {}, true, false, false, false, false}, // extendable nop - {"CLR", 0x8100, 0xf700, DSPInterpreter::clr, &DSPEmitter::clr, 1, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true, false, false, false, true}, // $acD = 0 - {"CMP", 0x8200, 0xff00, DSPInterpreter::cmp, &DSPEmitter::cmp, 1, 0, {}, true, false, false, false, true}, // FLAGS($ac0 - $ac1) - {"MULAXH", 0x8300, 0xff00, DSPInterpreter::mulaxh, &DSPEmitter::mulaxh, 1, 0, {}, true, false, false, false, true}, // $prod = $ax0.h * $ax0.h - {"CLRP", 0x8400, 0xff00, DSPInterpreter::clrp, &DSPEmitter::clrp, 1, 0, {}, true, false, false, false, true}, // $prod = 0 - {"TSTPROD", 0x8500, 0xff00, DSPInterpreter::tstprod, &DSPEmitter::tstprod,1, 0, {}, true, false, false, false, true}, // FLAGS($prod) - {"TSTAXH", 0x8600, 0xfe00, DSPInterpreter::tstaxh, &DSPEmitter::tstaxh, 1, 1, {{P_REG1A, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // FLAGS($axR.h) - {"M2", 0x8a00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, // enable "$prod *= 2" after every multiplication - {"M0", 0x8b00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, // disable "$prod *= 2" after every multiplication - {"CLR15", 0x8c00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, // set normal multiplication - {"SET15", 0x8d00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, // set unsigned multiplication in MUL - {"SET16", 0x8e00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, // set 16 bit sign extension width - {"SET40", 0x8f00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false, false, false}, // set 40 bit sign extension width + // 8 + {"NX", + 0x8000, + 0xf700, + DSPInterpreter::nx, + &DSPEmitter::nx, + 1, + 0, + {}, + true, + false, + false, + false, + false}, // extendable nop + {"CLR", + 0x8100, + 0xf700, + DSPInterpreter::clr, + &DSPEmitter::clr, + 1, + 1, + {{P_ACC, 1, 0, 11, 0x0800}}, + true, + false, + false, + false, + true}, // $acD = 0 + {"CMP", + 0x8200, + 0xff00, + DSPInterpreter::cmp, + &DSPEmitter::cmp, + 1, + 0, + {}, + true, + false, + false, + false, + true}, // FLAGS($ac0 - $ac1) + {"MULAXH", + 0x8300, + 0xff00, + DSPInterpreter::mulaxh, + &DSPEmitter::mulaxh, + 1, + 0, + {}, + true, + false, + false, + false, + true}, // $prod = $ax0.h * $ax0.h + {"CLRP", + 0x8400, + 0xff00, + DSPInterpreter::clrp, + &DSPEmitter::clrp, + 1, + 0, + {}, + true, + false, + false, + false, + true}, // $prod = 0 + {"TSTPROD", + 0x8500, + 0xff00, + DSPInterpreter::tstprod, + &DSPEmitter::tstprod, + 1, + 0, + {}, + true, + false, + false, + false, + true}, // FLAGS($prod) + {"TSTAXH", + 0x8600, + 0xfe00, + DSPInterpreter::tstaxh, + &DSPEmitter::tstaxh, + 1, + 1, + {{P_REG1A, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // FLAGS($axR.h) + {"M2", + 0x8a00, + 0xff00, + DSPInterpreter::srbith, + &DSPEmitter::srbith, + 1, + 0, + {}, + true, + false, + false, + false, + false}, // enable "$prod *= 2" after every multiplication + {"M0", + 0x8b00, + 0xff00, + DSPInterpreter::srbith, + &DSPEmitter::srbith, + 1, + 0, + {}, + true, + false, + false, + false, + false}, // disable "$prod *= 2" after every multiplication + {"CLR15", + 0x8c00, + 0xff00, + DSPInterpreter::srbith, + &DSPEmitter::srbith, + 1, + 0, + {}, + true, + false, + false, + false, + false}, // set normal multiplication + {"SET15", + 0x8d00, + 0xff00, + DSPInterpreter::srbith, + &DSPEmitter::srbith, + 1, + 0, + {}, + true, + false, + false, + false, + false}, // set unsigned multiplication in MUL + {"SET16", + 0x8e00, + 0xff00, + DSPInterpreter::srbith, + &DSPEmitter::srbith, + 1, + 0, + {}, + true, + false, + false, + false, + false}, // set 16 bit sign extension width + {"SET40", + 0x8f00, + 0xff00, + DSPInterpreter::srbith, + &DSPEmitter::srbith, + 1, + 0, + {}, + true, + false, + false, + false, + false}, // set 40 bit sign extension width - //9 - {"MUL", 0x9000, 0xf700, DSPInterpreter::mul, &DSPEmitter::mul, 1, 2, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}}, true, false, false, false, true}, // $prod = $axS.l * $axS.h - {"ASR16", 0x9100, 0xf700, DSPInterpreter::asr16, &DSPEmitter::asr16, 1, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true, false, false, false, true}, // $acD >>= 16 (shifting in sign bits) - {"MULMVZ", 0x9200, 0xf600, DSPInterpreter::mulmvz, &DSPEmitter::mulmvz, 1, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acR.hm = $prod.hm; $acR.l = 0; $prod = $axS.l * $axS.h - {"MULAC", 0x9400, 0xf600, DSPInterpreter::mulac, &DSPEmitter::mulac, 1, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acR += $prod; $prod = $axS.l * $axS.h - {"MULMV", 0x9600, 0xf600, DSPInterpreter::mulmv, &DSPEmitter::mulmv, 1, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acR = $prod; $prod = $axS.l * $axS.h + // 9 + {"MUL", + 0x9000, + 0xf700, + DSPInterpreter::mul, + &DSPEmitter::mul, + 1, + 2, + {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}}, + true, + false, + false, + false, + true}, // $prod = $axS.l * $axS.h + {"ASR16", + 0x9100, + 0xf700, + DSPInterpreter::asr16, + &DSPEmitter::asr16, + 1, + 1, + {{P_ACC, 1, 0, 11, 0x0800}}, + true, + false, + false, + false, + true}, // $acD >>= 16 (shifting in sign bits) + {"MULMVZ", + 0x9200, + 0xf600, + DSPInterpreter::mulmvz, + &DSPEmitter::mulmvz, + 1, + 3, + {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acR.hm = $prod.hm; $acR.l = 0; $prod = $axS.l * $axS.h + {"MULAC", + 0x9400, + 0xf600, + DSPInterpreter::mulac, + &DSPEmitter::mulac, + 1, + 3, + {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acR += $prod; $prod = $axS.l * $axS.h + {"MULMV", + 0x9600, + 0xf600, + DSPInterpreter::mulmv, + &DSPEmitter::mulmv, + 1, + 3, + {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acR = $prod; $prod = $axS.l * $axS.h - //a-b - {"MULX", 0xa000, 0xe700, DSPInterpreter::mulx, &DSPEmitter::mulx, 1, 2, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}}, true, false, false, false, true}, // $prod = $ax0.S * $ax1.T - {"ABS", 0xa100, 0xf700, DSPInterpreter::abs, &DSPEmitter::abs, 1, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true, false, false, false, true}, // $acD = abs($acD) - {"MULXMVZ", 0xa200, 0xe600, DSPInterpreter::mulxmvz, &DSPEmitter::mulxmvz,1, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acR.hm = $prod.hm; $acR.l = 0; $prod = $ax0.S * $ax1.T - {"MULXAC", 0xa400, 0xe600, DSPInterpreter::mulxac, &DSPEmitter::mulxac, 1, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acR += $prod; $prod = $ax0.S * $ax1.T - {"MULXMV", 0xa600, 0xe600, DSPInterpreter::mulxmv, &DSPEmitter::mulxmv, 1, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acR = $prod; $prod = $ax0.S * $ax1.T - {"TST", 0xb100, 0xf700, DSPInterpreter::tst, &DSPEmitter::tst, 1, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true, false, false, false, true}, // FLAGS($acR) + // a-b + {"MULX", + 0xa000, + 0xe700, + DSPInterpreter::mulx, + &DSPEmitter::mulx, + 1, + 2, + {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}}, + true, + false, + false, + false, + true}, // $prod = $ax0.S * $ax1.T + {"ABS", + 0xa100, + 0xf700, + DSPInterpreter::abs, + &DSPEmitter::abs, + 1, + 1, + {{P_ACC, 1, 0, 11, 0x0800}}, + true, + false, + false, + false, + true}, // $acD = abs($acD) + {"MULXMVZ", + 0xa200, + 0xe600, + DSPInterpreter::mulxmvz, + &DSPEmitter::mulxmvz, + 1, + 3, + {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acR.hm = $prod.hm; $acR.l = 0; $prod = $ax0.S * $ax1.T + {"MULXAC", + 0xa400, + 0xe600, + DSPInterpreter::mulxac, + &DSPEmitter::mulxac, + 1, + 3, + {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acR += $prod; $prod = $ax0.S * $ax1.T + {"MULXMV", + 0xa600, + 0xe600, + DSPInterpreter::mulxmv, + &DSPEmitter::mulxmv, + 1, + 3, + {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acR = $prod; $prod = $ax0.S * $ax1.T + {"TST", + 0xb100, + 0xf700, + DSPInterpreter::tst, + &DSPEmitter::tst, + 1, + 1, + {{P_ACC, 1, 0, 11, 0x0800}}, + true, + false, + false, + false, + true}, // FLAGS($acR) - //c-d - {"MULC", 0xc000, 0xe700, DSPInterpreter::mulc, &DSPEmitter::mulc, 1, 2, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, true, false, false, false, true}, // $prod = $acS.m * $axS.h - {"CMPAR", 0xc100, 0xe700, DSPInterpreter::cmpar, &DSPEmitter::cmpar, 1, 2, {{P_ACC, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 12, 0x1000}}, true, false, false, false, true}, // FLAGS($acS - axR.h) - {"MULCMVZ", 0xc200, 0xe600, DSPInterpreter::mulcmvz, &DSPEmitter::mulcmvz,1, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acR.hm, $acR.l, $prod = $prod.hm, 0, $acS.m * $axS.h - {"MULCAC", 0xc400, 0xe600, DSPInterpreter::mulcac, &DSPEmitter::mulcac, 1, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acR, $prod = $acR + $prod, $acS.m * $axS.h - {"MULCMV", 0xc600, 0xe600, DSPInterpreter::mulcmv, &DSPEmitter::mulcmv, 1, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acR, $prod = $prod, $acS.m * $axS.h + // c-d + {"MULC", + 0xc000, + 0xe700, + DSPInterpreter::mulc, + &DSPEmitter::mulc, + 1, + 2, + {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, + true, + false, + false, + false, + true}, // $prod = $acS.m * $axS.h + {"CMPAR", + 0xc100, + 0xe700, + DSPInterpreter::cmpar, + &DSPEmitter::cmpar, + 1, + 2, + {{P_ACC, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 12, 0x1000}}, + true, + false, + false, + false, + true}, // FLAGS($acS - axR.h) + {"MULCMVZ", + 0xc200, + 0xe600, + DSPInterpreter::mulcmvz, + &DSPEmitter::mulcmvz, + 1, + 3, + {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acR.hm, $acR.l, $prod = $prod.hm, 0, $acS.m * $axS.h + {"MULCAC", + 0xc400, + 0xe600, + DSPInterpreter::mulcac, + &DSPEmitter::mulcac, + 1, + 3, + {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acR, $prod = $acR + $prod, $acS.m * $axS.h + {"MULCMV", + 0xc600, + 0xe600, + DSPInterpreter::mulcmv, + &DSPEmitter::mulcmv, + 1, + 3, + {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acR, $prod = $prod, $acS.m * $axS.h - //e - {"MADDX", 0xe000, 0xfc00, DSPInterpreter::maddx, &DSPEmitter::maddx, 1, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, true, false, false, false, true}, // $prod += $ax0.S * $ax1.T - {"MSUBX", 0xe400, 0xfc00, DSPInterpreter::msubx, &DSPEmitter::msubx, 1, 2, {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, true, false, false, false, true}, // $prod -= $ax0.S * $ax1.T - {"MADDC", 0xe800, 0xfc00, DSPInterpreter::maddc, &DSPEmitter::maddc, 1, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, true, false, false, false, true}, // $prod += $acS.m * $axT.h - {"MSUBC", 0xec00, 0xfc00, DSPInterpreter::msubc, &DSPEmitter::msubc, 1, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, true, false, false, false, true}, // $prod -= $acS.m * $axT.h + // e + {"MADDX", + 0xe000, + 0xfc00, + DSPInterpreter::maddx, + &DSPEmitter::maddx, + 1, + 2, + {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, + true, + false, + false, + false, + true}, // $prod += $ax0.S * $ax1.T + {"MSUBX", + 0xe400, + 0xfc00, + DSPInterpreter::msubx, + &DSPEmitter::msubx, + 1, + 2, + {{P_REGM18, 1, 0, 8, 0x0200}, {P_REGM19, 1, 0, 7, 0x0100}}, + true, + false, + false, + false, + true}, // $prod -= $ax0.S * $ax1.T + {"MADDC", + 0xe800, + 0xfc00, + DSPInterpreter::maddc, + &DSPEmitter::maddc, + 1, + 2, + {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, + true, + false, + false, + false, + true}, // $prod += $acS.m * $axT.h + {"MSUBC", + 0xec00, + 0xfc00, + DSPInterpreter::msubc, + &DSPEmitter::msubc, + 1, + 2, + {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, + true, + false, + false, + false, + true}, // $prod -= $acS.m * $axT.h - //f - {"LSL16", 0xf000, 0xfe00, DSPInterpreter::lsl16, &DSPEmitter::lsl16, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acR <<= 16 - {"MADD", 0xf200, 0xfe00, DSPInterpreter::madd, &DSPEmitter::madd, 1, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $prod += $axS.l * $axS.h - {"LSR16", 0xf400, 0xfe00, DSPInterpreter::lsr16, &DSPEmitter::lsr16, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acR >>= 16 - {"MSUB", 0xf600, 0xfe00, DSPInterpreter::msub, &DSPEmitter::msub, 1, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $prod -= $axS.l * $axS.h - {"ADDPAXZ", 0xf800, 0xfc00, DSPInterpreter::addpaxz, &DSPEmitter::addpaxz,1, 2, {{P_ACC, 1, 0, 9, 0x0200}, {P_AX, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD.hm = $prod.hm + $ax.h; $acD.l = 0 - {"CLRL", 0xfc00, 0xfe00, DSPInterpreter::clrl, &DSPEmitter::clrl, 1, 1, {{P_ACCL, 1, 0, 11, 0x0800}}, true, false, false, false, true}, // $acR.l = 0 - {"MOVPZ", 0xfe00, 0xfe00, DSPInterpreter::movpz, &DSPEmitter::movpz, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false, false, true}, // $acD.hm = $prod.hm; $acD.l = 0 + // f + {"LSL16", + 0xf000, + 0xfe00, + DSPInterpreter::lsl16, + &DSPEmitter::lsl16, + 1, + 1, + {{P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acR <<= 16 + {"MADD", + 0xf200, + 0xfe00, + DSPInterpreter::madd, + &DSPEmitter::madd, + 1, + 2, + {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $prod += $axS.l * $axS.h + {"LSR16", + 0xf400, + 0xfe00, + DSPInterpreter::lsr16, + &DSPEmitter::lsr16, + 1, + 1, + {{P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acR >>= 16 + {"MSUB", + 0xf600, + 0xfe00, + DSPInterpreter::msub, + &DSPEmitter::msub, + 1, + 2, + {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $prod -= $axS.l * $axS.h + {"ADDPAXZ", + 0xf800, + 0xfc00, + DSPInterpreter::addpaxz, + &DSPEmitter::addpaxz, + 1, + 2, + {{P_ACC, 1, 0, 9, 0x0200}, {P_AX, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD.hm = $prod.hm + $ax.h; $acD.l = 0 + {"CLRL", + 0xfc00, + 0xfe00, + DSPInterpreter::clrl, + &DSPEmitter::clrl, + 1, + 1, + {{P_ACCL, 1, 0, 11, 0x0800}}, + true, + false, + false, + false, + true}, // $acR.l = 0 + {"MOVPZ", + 0xfe00, + 0xfe00, + DSPInterpreter::movpz, + &DSPEmitter::movpz, + 1, + 1, + {{P_ACC, 1, 0, 8, 0x0100}}, + true, + false, + false, + false, + true}, // $acD.hm = $prod.hm; $acD.l = 0 }; -const DSPOPCTemplate cw = - {"CW", 0x0000, 0x0000, nop, nullptr, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, false, false, false, false, false}; +const DSPOPCTemplate cw = {"CW", 0x0000, 0x0000, nop, nullptr, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, + false, false, false, false, false}; // extended opcodes -const DSPOPCTemplate opcodes_ext[] = -{ - {"XXX", 0x0000, 0x00fc, DSPInterpreter::Ext::nop, &DSPEmitter::nop, 1, 1, {{P_VAL, 1, 0, 0, 0x00ff}}, false, false, false, false, false}, // no operation +const DSPOPCTemplate opcodes_ext[] = { + {"XXX", + 0x0000, + 0x00fc, + DSPInterpreter::Ext::nop, + &DSPEmitter::nop, + 1, + 1, + {{P_VAL, 1, 0, 0, 0x00ff}}, + false, + false, + false, + false, + false}, // no operation - {"DR", 0x0004, 0x00fc, DSPInterpreter::Ext::dr, &DSPEmitter::dr, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $arR-- - {"IR", 0x0008, 0x00fc, DSPInterpreter::Ext::ir, &DSPEmitter::ir, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $arR++ - {"NR", 0x000c, 0x00fc, DSPInterpreter::Ext::nr, &DSPEmitter::nr, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $arR += $ixR - {"MV", 0x0010, 0x00f0, DSPInterpreter::Ext::mv, &DSPEmitter::mv, 1, 2, {{P_REG18, 1, 0, 2, 0x000c}, {P_REG1C, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $(D+24) = $(S+28) + {"DR", + 0x0004, + 0x00fc, + DSPInterpreter::Ext::dr, + &DSPEmitter::dr, + 1, + 1, + {{P_REG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $arR-- + {"IR", + 0x0008, + 0x00fc, + DSPInterpreter::Ext::ir, + &DSPEmitter::ir, + 1, + 1, + {{P_REG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $arR++ + {"NR", + 0x000c, + 0x00fc, + DSPInterpreter::Ext::nr, + &DSPEmitter::nr, + 1, + 1, + {{P_REG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $arR += $ixR + {"MV", + 0x0010, + 0x00f0, + DSPInterpreter::Ext::mv, + &DSPEmitter::mv, + 1, + 2, + {{P_REG18, 1, 0, 2, 0x000c}, {P_REG1C, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $(D+24) = $(S+28) - {"S", 0x0020, 0x00e4, DSPInterpreter::Ext::s, &DSPEmitter::s, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, false, false, false, false, false}, // MEM[$D++] = $(S+28) - {"SN", 0x0024, 0x00e4, DSPInterpreter::Ext::sn, &DSPEmitter::sn, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, false, false, false, false, false}, // MEM[$D] = $(D+28); $D += $(D+4) + {"S", + 0x0020, + 0x00e4, + DSPInterpreter::Ext::s, + &DSPEmitter::s, + 1, + 2, + {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, + false, + false, + false, + false, + false}, // MEM[$D++] = $(S+28) + {"SN", + 0x0024, + 0x00e4, + DSPInterpreter::Ext::sn, + &DSPEmitter::sn, + 1, + 2, + {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, + false, + false, + false, + false, + false}, // MEM[$D] = $(D+28); $D += $(D+4) - {"L", 0x0040, 0x00c4, DSPInterpreter::Ext::l, &DSPEmitter::l, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $(D+24) = MEM[$S++] - {"LN", 0x0044, 0x00c4, DSPInterpreter::Ext::ln, &DSPEmitter::ln, 1, 2, {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $(D+24) = MEM[$S]; $S += $(S+4) + {"L", + 0x0040, + 0x00c4, + DSPInterpreter::Ext::l, + &DSPEmitter::l, + 1, + 2, + {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $(D+24) = MEM[$S++] + {"LN", + 0x0044, + 0x00c4, + DSPInterpreter::Ext::ln, + &DSPEmitter::ln, + 1, + 2, + {{P_REG18, 1, 0, 3, 0x0038}, {P_PRG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $(D+24) = MEM[$S]; $S += $(S+4) - {"LS", 0x0080, 0x00ce, DSPInterpreter::Ext::ls, &DSPEmitter::ls, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, false, false, false, false, false}, // $(D+24) = MEM[$ar0++]; MEM[$ar3++] = $acS.m - {"SL", 0x0082, 0x00ce, DSPInterpreter::Ext::sl, &DSPEmitter::sl, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, false, false, false, false, false}, // MEM[$ar0++] = $acS.m; $(D+24) = MEM[$ar3++] - {"LSN", 0x0084, 0x00ce, DSPInterpreter::Ext::lsn, &DSPEmitter::lsn, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, false, false, false, false, false}, // $(D+24) = MEM[$ar0]; MEM[$ar3++] = $acS.m; $ar0 += $ix0 - {"SLN", 0x0086, 0x00ce, DSPInterpreter::Ext::sln, &DSPEmitter::sln, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, false, false, false, false, false}, // MEM[$ar0] = $acS.m; $(D+24) = MEM[$ar3++]; $ar0 += $ix0 - {"LSM", 0x0088, 0x00ce, DSPInterpreter::Ext::lsm, &DSPEmitter::lsm, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, false, false, false, false, false}, // $(D+24) = MEM[$ar0++]; MEM[$ar3] = $acS.m; $ar3 += $ix3 - {"SLM", 0x008a, 0x00ce, DSPInterpreter::Ext::slm, &DSPEmitter::slm, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, false, false, false, false, false}, // MEM[$ar0++] = $acS.m; $(D+24) = MEM[$ar3]; $ar3 += $ix3 - {"LSNM", 0x008c, 0x00ce, DSPInterpreter::Ext::lsnm, &DSPEmitter::lsnm, 1, 2, {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, false, false, false, false, false}, // $(D+24) = MEM[$ar0]; MEM[$ar3] = $acS.m; $ar0 += $ix0; $ar3 += $ix3 - {"SLNM", 0x008e, 0x00ce, DSPInterpreter::Ext::slnm, &DSPEmitter::slnm, 1, 2, {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, false, false, false, false, false}, // MEM[$ar0] = $acS.m; $(D+24) = MEM[$ar3]; $ar0 += $ix0; $ar3 += $ix3 + {"LS", + 0x0080, + 0x00ce, + DSPInterpreter::Ext::ls, + &DSPEmitter::ls, + 1, + 2, + {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, + false, + false, + false, + false, + false}, // $(D+24) = MEM[$ar0++]; MEM[$ar3++] = $acS.m + {"SL", + 0x0082, + 0x00ce, + DSPInterpreter::Ext::sl, + &DSPEmitter::sl, + 1, + 2, + {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, + false, + false, + false, + false, + false}, // MEM[$ar0++] = $acS.m; $(D+24) = MEM[$ar3++] + {"LSN", + 0x0084, + 0x00ce, + DSPInterpreter::Ext::lsn, + &DSPEmitter::lsn, + 1, + 2, + {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, + false, + false, + false, + false, + false}, // $(D+24) = MEM[$ar0]; MEM[$ar3++] = $acS.m; $ar0 += $ix0 + {"SLN", + 0x0086, + 0x00ce, + DSPInterpreter::Ext::sln, + &DSPEmitter::sln, + 1, + 2, + {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, + false, + false, + false, + false, + false}, // MEM[$ar0] = $acS.m; $(D+24) = MEM[$ar3++]; $ar0 += $ix0 + {"LSM", + 0x0088, + 0x00ce, + DSPInterpreter::Ext::lsm, + &DSPEmitter::lsm, + 1, + 2, + {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, + false, + false, + false, + false, + false}, // $(D+24) = MEM[$ar0++]; MEM[$ar3] = $acS.m; $ar3 += $ix3 + {"SLM", + 0x008a, + 0x00ce, + DSPInterpreter::Ext::slm, + &DSPEmitter::slm, + 1, + 2, + {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, + false, + false, + false, + false, + false}, // MEM[$ar0++] = $acS.m; $(D+24) = MEM[$ar3]; $ar3 += $ix3 + {"LSNM", + 0x008c, + 0x00ce, + DSPInterpreter::Ext::lsnm, + &DSPEmitter::lsnm, + 1, + 2, + {{P_REG18, 1, 0, 4, 0x0030}, {P_ACCM, 1, 0, 0, 0x0001}}, + false, + false, + false, + false, + false}, // $(D+24) = MEM[$ar0]; MEM[$ar3] = $acS.m; $ar0 += $ix0; $ar3 += $ix3 + {"SLNM", + 0x008e, + 0x00ce, + DSPInterpreter::Ext::slnm, + &DSPEmitter::slnm, + 1, + 2, + {{P_ACCM, 1, 0, 0, 0x0001}, {P_REG18, 1, 0, 4, 0x0030}}, + false, + false, + false, + false, + false}, // MEM[$ar0] = $acS.m; $(D+24) = MEM[$ar3]; $ar0 += $ix0; $ar3 += $ix3 - {"LDAX", 0x00c3, 0x00cf, DSPInterpreter::Ext::ldax, &DSPEmitter::ldax, 1, 2, {{P_AX, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, false, false, false, false, false}, // $axR.h = MEM[$arS++]; $axR.l = MEM[$ar3++] - {"LDAXN", 0x00c7, 0x00cf, DSPInterpreter::Ext::ldaxn, &DSPEmitter::ldaxn, 1, 2, {{P_AX, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, false, false, false, false, false}, // $axR.h = MEM[$arS]; $axR.l = MEM[$ar3++]; $arS += $ixS - {"LDAXM", 0x00cb, 0x00cf, DSPInterpreter::Ext::ldaxm, &DSPEmitter::ldaxm, 1, 2, {{P_AX, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, false, false, false, false, false}, // $axR.h = MEM[$arS++]; $axR.l = MEM[$ar3]; $ar3 += $ix3 - {"LDAXNM", 0x00cf, 0x00cf, DSPInterpreter::Ext::ldaxnm, &DSPEmitter::ldaxnm, 1, 2, {{P_AX, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, false, false, false, false, false}, // $axR.h = MEM[$arS]; $axR.l = MEM[$ar3]; $arS += $ixS; $ar3 += $ix3 + {"LDAX", + 0x00c3, + 0x00cf, + DSPInterpreter::Ext::ldax, + &DSPEmitter::ldax, + 1, + 2, + {{P_AX, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, + false, + false, + false, + false, + false}, // $axR.h = MEM[$arS++]; $axR.l = MEM[$ar3++] + {"LDAXN", + 0x00c7, + 0x00cf, + DSPInterpreter::Ext::ldaxn, + &DSPEmitter::ldaxn, + 1, + 2, + {{P_AX, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, + false, + false, + false, + false, + false}, // $axR.h = MEM[$arS]; $axR.l = MEM[$ar3++]; $arS += $ixS + {"LDAXM", + 0x00cb, + 0x00cf, + DSPInterpreter::Ext::ldaxm, + &DSPEmitter::ldaxm, + 1, + 2, + {{P_AX, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, + false, + false, + false, + false, + false}, // $axR.h = MEM[$arS++]; $axR.l = MEM[$ar3]; $ar3 += $ix3 + {"LDAXNM", + 0x00cf, + 0x00cf, + DSPInterpreter::Ext::ldaxnm, + &DSPEmitter::ldaxnm, + 1, + 2, + {{P_AX, 1, 0, 4, 0x0010}, {P_PRG, 1, 0, 5, 0x0020}}, + false, + false, + false, + false, + false}, // $axR.h = MEM[$arS]; $axR.l = MEM[$ar3]; $arS += $ixS; $ar3 += $ix3 - {"LD", 0x00c0, 0x00cc, DSPInterpreter::Ext::ld, &DSPEmitter::ld, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $ax0.D = MEM[$arS++]; $ax1.R = MEM[$ar3++] - {"LDN", 0x00c4, 0x00cc, DSPInterpreter::Ext::ldn, &DSPEmitter::ldn, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $ax0.D = MEM[$arS]; $ax1.R = MEM[$ar3++]; $arS += $ixS - {"LDM", 0x00c8, 0x00cc, DSPInterpreter::Ext::ldm, &DSPEmitter::ldm, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $ax0.D = MEM[$arS++]; $ax1.R = MEM[$ar3]; $ar3 += $ix3 - {"LDNM", 0x00cc, 0x00cc, DSPInterpreter::Ext::ldnm, &DSPEmitter::ldnm, 1, 3, {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, false, false, false, false, false}, // $ax0.D = MEM[$arS]; $ax1.R = MEM[$ar3]; $arS += $ixS; $ar3 += $ix3 + {"LD", + 0x00c0, + 0x00cc, + DSPInterpreter::Ext::ld, + &DSPEmitter::ld, + 1, + 3, + {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $ax0.D = MEM[$arS++]; $ax1.R = MEM[$ar3++] + {"LDN", + 0x00c4, + 0x00cc, + DSPInterpreter::Ext::ldn, + &DSPEmitter::ldn, + 1, + 3, + {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $ax0.D = MEM[$arS]; $ax1.R = MEM[$ar3++]; $arS += $ixS + {"LDM", + 0x00c8, + 0x00cc, + DSPInterpreter::Ext::ldm, + &DSPEmitter::ldm, + 1, + 3, + {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $ax0.D = MEM[$arS++]; $ax1.R = MEM[$ar3]; $ar3 += $ix3 + {"LDNM", + 0x00cc, + 0x00cc, + DSPInterpreter::Ext::ldnm, + &DSPEmitter::ldnm, + 1, + 3, + {{P_REGM18, 1, 0, 4, 0x0020}, {P_REGM19, 1, 0, 3, 0x0010}, {P_PRG, 1, 0, 0, 0x0003}}, + false, + false, + false, + false, + false}, // $ax0.D = MEM[$arS]; $ax1.R = MEM[$ar3]; $arS += $ixS; $ar3 += $ix3 }; const int opcodes_size = sizeof(opcodes) / sizeof(DSPOPCTemplate); const int opcodes_ext_size = sizeof(opcodes_ext) / sizeof(DSPOPCTemplate); -const pdlabel_t pdlabels[] = -{ - {0xffa0, "COEF_A1_0", "COEF_A1_0",}, - {0xffa1, "COEF_A2_0", "COEF_A2_0",}, - {0xffa2, "COEF_A1_1", "COEF_A1_1",}, - {0xffa3, "COEF_A2_1", "COEF_A2_1",}, - {0xffa4, "COEF_A1_2", "COEF_A1_2",}, - {0xffa5, "COEF_A2_2", "COEF_A2_2",}, - {0xffa6, "COEF_A1_3", "COEF_A1_3",}, - {0xffa7, "COEF_A2_3", "COEF_A2_3",}, - {0xffa8, "COEF_A1_4", "COEF_A1_4",}, - {0xffa9, "COEF_A2_4", "COEF_A2_4",}, - {0xffaa, "COEF_A1_5", "COEF_A1_5",}, - {0xffab, "COEF_A2_5", "COEF_A2_5",}, - {0xffac, "COEF_A1_6", "COEF_A1_6",}, - {0xffad, "COEF_A2_6", "COEF_A2_6",}, - {0xffae, "COEF_A1_7", "COEF_A1_7",}, - {0xffaf, "COEF_A2_7", "COEF_A2_7",}, +const pdlabel_t pdlabels[] = { + { + 0xffa0, "COEF_A1_0", "COEF_A1_0", + }, + { + 0xffa1, "COEF_A2_0", "COEF_A2_0", + }, + { + 0xffa2, "COEF_A1_1", "COEF_A1_1", + }, + { + 0xffa3, "COEF_A2_1", "COEF_A2_1", + }, + { + 0xffa4, "COEF_A1_2", "COEF_A1_2", + }, + { + 0xffa5, "COEF_A2_2", "COEF_A2_2", + }, + { + 0xffa6, "COEF_A1_3", "COEF_A1_3", + }, + { + 0xffa7, "COEF_A2_3", "COEF_A2_3", + }, + { + 0xffa8, "COEF_A1_4", "COEF_A1_4", + }, + { + 0xffa9, "COEF_A2_4", "COEF_A2_4", + }, + { + 0xffaa, "COEF_A1_5", "COEF_A1_5", + }, + { + 0xffab, "COEF_A2_5", "COEF_A2_5", + }, + { + 0xffac, "COEF_A1_6", "COEF_A1_6", + }, + { + 0xffad, "COEF_A2_6", "COEF_A2_6", + }, + { + 0xffae, "COEF_A1_7", "COEF_A1_7", + }, + { + 0xffaf, "COEF_A2_7", "COEF_A2_7", + }, - {0xffb0, "0xffb0", nullptr,}, - {0xffb1, "0xffb1", nullptr,}, - {0xffb2, "0xffb2", nullptr,}, - {0xffb3, "0xffb3", nullptr,}, - {0xffb4, "0xffb4", nullptr,}, - {0xffb5, "0xffb5", nullptr,}, - {0xffb6, "0xffb6", nullptr,}, - {0xffb7, "0xffb7", nullptr,}, - {0xffb8, "0xffb8", nullptr,}, - {0xffb9, "0xffb9", nullptr,}, - {0xffba, "0xffba", nullptr,}, - {0xffbb, "0xffbb", nullptr,}, - {0xffbc, "0xffbc", nullptr,}, - {0xffbd, "0xffbd", nullptr,}, - {0xffbe, "0xffbe", nullptr,}, - {0xffbf, "0xffbf", nullptr,}, + { + 0xffb0, "0xffb0", nullptr, + }, + { + 0xffb1, "0xffb1", nullptr, + }, + { + 0xffb2, "0xffb2", nullptr, + }, + { + 0xffb3, "0xffb3", nullptr, + }, + { + 0xffb4, "0xffb4", nullptr, + }, + { + 0xffb5, "0xffb5", nullptr, + }, + { + 0xffb6, "0xffb6", nullptr, + }, + { + 0xffb7, "0xffb7", nullptr, + }, + { + 0xffb8, "0xffb8", nullptr, + }, + { + 0xffb9, "0xffb9", nullptr, + }, + { + 0xffba, "0xffba", nullptr, + }, + { + 0xffbb, "0xffbb", nullptr, + }, + { + 0xffbc, "0xffbc", nullptr, + }, + { + 0xffbd, "0xffbd", nullptr, + }, + { + 0xffbe, "0xffbe", nullptr, + }, + { + 0xffbf, "0xffbf", nullptr, + }, - {0xffc0, "0xffc0", nullptr,}, - {0xffc1, "0xffc1", nullptr,}, - {0xffc2, "0xffc2", nullptr,}, - {0xffc3, "0xffc3", nullptr,}, - {0xffc4, "0xffc4", nullptr,}, - {0xffc5, "0xffc5", nullptr,}, - {0xffc6, "0xffc6", nullptr,}, - {0xffc7, "0xffc7", nullptr,}, - {0xffc8, "0xffc8", nullptr,}, - {0xffc9, "DSCR", "DSP DMA Control Reg",}, - {0xffca, "0xffca", nullptr,}, - {0xffcb, "DSBL", "DSP DMA Block Length",}, - {0xffcc, "0xffcc", nullptr,}, - {0xffcd, "DSPA", "DSP DMA DMEM Address",}, - {0xffce, "DSMAH", "DSP DMA Mem Address H",}, - {0xffcf, "DSMAL", "DSP DMA Mem Address L",}, + { + 0xffc0, "0xffc0", nullptr, + }, + { + 0xffc1, "0xffc1", nullptr, + }, + { + 0xffc2, "0xffc2", nullptr, + }, + { + 0xffc3, "0xffc3", nullptr, + }, + { + 0xffc4, "0xffc4", nullptr, + }, + { + 0xffc5, "0xffc5", nullptr, + }, + { + 0xffc6, "0xffc6", nullptr, + }, + { + 0xffc7, "0xffc7", nullptr, + }, + { + 0xffc8, "0xffc8", nullptr, + }, + { + 0xffc9, "DSCR", "DSP DMA Control Reg", + }, + { + 0xffca, "0xffca", nullptr, + }, + { + 0xffcb, "DSBL", "DSP DMA Block Length", + }, + { + 0xffcc, "0xffcc", nullptr, + }, + { + 0xffcd, "DSPA", "DSP DMA DMEM Address", + }, + { + 0xffce, "DSMAH", "DSP DMA Mem Address H", + }, + { + 0xffcf, "DSMAL", "DSP DMA Mem Address L", + }, - {0xffd0, "0xffd0",nullptr,}, - {0xffd1, "SampleFormat", "SampleFormat",}, - {0xffd2, "0xffd2",nullptr,}, - {0xffd3, "UnkZelda", "Unk Zelda reads/writes from/to it",}, - {0xffd4, "ACSAH", "Accelerator start address H",}, - {0xffd5, "ACSAL", "Accelerator start address L",}, - {0xffd6, "ACEAH", "Accelerator end address H",}, - {0xffd7, "ACEAL", "Accelerator end address L",}, - {0xffd8, "ACCAH", "Accelerator current address H",}, - {0xffd9, "ACCAL", "Accelerator current address L",}, - {0xffda, "pred_scale", "pred_scale",}, - {0xffdb, "yn1", "yn1",}, - {0xffdc, "yn2", "yn2",}, - {0xffdd, "ARAM", "Direct Read from ARAM (uses ADPCM)",}, - {0xffde, "GAIN", "Gain",}, - {0xffdf, "0xffdf", nullptr,}, + { + 0xffd0, "0xffd0", nullptr, + }, + { + 0xffd1, "SampleFormat", "SampleFormat", + }, + { + 0xffd2, "0xffd2", nullptr, + }, + { + 0xffd3, "UnkZelda", "Unk Zelda reads/writes from/to it", + }, + { + 0xffd4, "ACSAH", "Accelerator start address H", + }, + { + 0xffd5, "ACSAL", "Accelerator start address L", + }, + { + 0xffd6, "ACEAH", "Accelerator end address H", + }, + { + 0xffd7, "ACEAL", "Accelerator end address L", + }, + { + 0xffd8, "ACCAH", "Accelerator current address H", + }, + { + 0xffd9, "ACCAL", "Accelerator current address L", + }, + { + 0xffda, "pred_scale", "pred_scale", + }, + { + 0xffdb, "yn1", "yn1", + }, + { + 0xffdc, "yn2", "yn2", + }, + { + 0xffdd, "ARAM", "Direct Read from ARAM (uses ADPCM)", + }, + { + 0xffde, "GAIN", "Gain", + }, + { + 0xffdf, "0xffdf", nullptr, + }, - {0xffe0, "0xffe0",nullptr,}, - {0xffe1, "0xffe1",nullptr,}, - {0xffe2, "0xffe2",nullptr,}, - {0xffe3, "0xffe3",nullptr,}, - {0xffe4, "0xffe4",nullptr,}, - {0xffe5, "0xffe5",nullptr,}, - {0xffe6, "0xffe6",nullptr,}, - {0xffe7, "0xffe7",nullptr,}, - {0xffe8, "0xffe8",nullptr,}, - {0xffe9, "0xffe9",nullptr,}, - {0xffea, "0xffea",nullptr,}, - {0xffeb, "0xffeb",nullptr,}, - {0xffec, "0xffec",nullptr,}, - {0xffed, "0xffed",nullptr,}, - {0xffee, "0xffee",nullptr,}, - {0xffef, "AMDM", "ARAM DMA Request Mask",}, + { + 0xffe0, "0xffe0", nullptr, + }, + { + 0xffe1, "0xffe1", nullptr, + }, + { + 0xffe2, "0xffe2", nullptr, + }, + { + 0xffe3, "0xffe3", nullptr, + }, + { + 0xffe4, "0xffe4", nullptr, + }, + { + 0xffe5, "0xffe5", nullptr, + }, + { + 0xffe6, "0xffe6", nullptr, + }, + { + 0xffe7, "0xffe7", nullptr, + }, + { + 0xffe8, "0xffe8", nullptr, + }, + { + 0xffe9, "0xffe9", nullptr, + }, + { + 0xffea, "0xffea", nullptr, + }, + { + 0xffeb, "0xffeb", nullptr, + }, + { + 0xffec, "0xffec", nullptr, + }, + { + 0xffed, "0xffed", nullptr, + }, + { + 0xffee, "0xffee", nullptr, + }, + { + 0xffef, "AMDM", "ARAM DMA Request Mask", + }, - {0xfff0, "0xfff0",nullptr,}, - {0xfff1, "0xfff1",nullptr,}, - {0xfff2, "0xfff2",nullptr,}, - {0xfff3, "0xfff3",nullptr,}, - {0xfff4, "0xfff4",nullptr,}, - {0xfff5, "0xfff5",nullptr,}, - {0xfff6, "0xfff6",nullptr,}, - {0xfff7, "0xfff7",nullptr,}, - {0xfff8, "0xfff8",nullptr,}, - {0xfff9, "0xfff9",nullptr,}, - {0xfffa, "0xfffa",nullptr,}, - {0xfffb, "DIRQ", "DSP IRQ Request",}, - {0xfffc, "DMBH", "DSP Mailbox H",}, - {0xfffd, "DMBL", "DSP Mailbox L",}, - {0xfffe, "CMBH", "CPU Mailbox H",}, - {0xffff, "CMBL", "CPU Mailbox L",}, + { + 0xfff0, "0xfff0", nullptr, + }, + { + 0xfff1, "0xfff1", nullptr, + }, + { + 0xfff2, "0xfff2", nullptr, + }, + { + 0xfff3, "0xfff3", nullptr, + }, + { + 0xfff4, "0xfff4", nullptr, + }, + { + 0xfff5, "0xfff5", nullptr, + }, + { + 0xfff6, "0xfff6", nullptr, + }, + { + 0xfff7, "0xfff7", nullptr, + }, + { + 0xfff8, "0xfff8", nullptr, + }, + { + 0xfff9, "0xfff9", nullptr, + }, + { + 0xfffa, "0xfffa", nullptr, + }, + { + 0xfffb, "DIRQ", "DSP IRQ Request", + }, + { + 0xfffc, "DMBH", "DSP Mailbox H", + }, + { + 0xfffd, "DMBL", "DSP Mailbox L", + }, + { + 0xfffe, "CMBH", "CPU Mailbox H", + }, + { + 0xffff, "CMBL", "CPU Mailbox L", + }, }; const u32 pdlabels_size = sizeof(pdlabels) / sizeof(pdlabel_t); -const pdlabel_t regnames[] = -{ - {0x00, "AR0", "Addr Reg 00",}, - {0x01, "AR1", "Addr Reg 01",}, - {0x02, "AR2", "Addr Reg 02",}, - {0x03, "AR3", "Addr Reg 03",}, - {0x04, "IX0", "Index Reg 0",}, - {0x05, "IX1", "Index Reg 1",}, - {0x06, "IX2", "Index Reg 2",}, - {0x07, "IX3", "Index Reg 3",}, - {0x08, "WR0", "Wrapping Register 0",}, - {0x09, "WR1", "Wrapping Register 1",}, - {0x0a, "WR2", "Wrapping Register 2",}, - {0x0b, "WR3", "Wrapping Register 3",}, - {0x0c, "ST0", "Call stack",}, - {0x0d, "ST1", "Data stack",}, - {0x0e, "ST2", "Loop addr stack",}, - {0x0f, "ST3", "Loop counter",}, - {0x10, "AC0.H", "Accu High 0",}, - {0x11, "AC1.H", "Accu High 1",}, - {0x12, "CR", "Config Register",}, - {0x13, "SR", "Special Register",}, - {0x14, "PROD.L", "Prod L",}, - {0x15, "PROD.M1", "Prod M1",}, - {0x16, "PROD.H", "Prod H",}, - {0x17, "PROD.M2", "Prod M2",}, - {0x18, "AX0.L", "Extra Accu L 0",}, - {0x19, "AX1.L", "Extra Accu L 1",}, - {0x1a, "AX0.H", "Extra Accu H 0",}, - {0x1b, "AX1.H", "Extra Accu H 1",}, - {0x1c, "AC0.L", "Accu Low 0",}, - {0x1d, "AC1.L", "Accu Low 1",}, - {0x1e, "AC0.M", "Accu Mid 0",}, - {0x1f, "AC1.M", "Accu Mid 1",}, +const pdlabel_t regnames[] = { + { + 0x00, "AR0", "Addr Reg 00", + }, + { + 0x01, "AR1", "Addr Reg 01", + }, + { + 0x02, "AR2", "Addr Reg 02", + }, + { + 0x03, "AR3", "Addr Reg 03", + }, + { + 0x04, "IX0", "Index Reg 0", + }, + { + 0x05, "IX1", "Index Reg 1", + }, + { + 0x06, "IX2", "Index Reg 2", + }, + { + 0x07, "IX3", "Index Reg 3", + }, + { + 0x08, "WR0", "Wrapping Register 0", + }, + { + 0x09, "WR1", "Wrapping Register 1", + }, + { + 0x0a, "WR2", "Wrapping Register 2", + }, + { + 0x0b, "WR3", "Wrapping Register 3", + }, + { + 0x0c, "ST0", "Call stack", + }, + { + 0x0d, "ST1", "Data stack", + }, + { + 0x0e, "ST2", "Loop addr stack", + }, + { + 0x0f, "ST3", "Loop counter", + }, + { + 0x10, "AC0.H", "Accu High 0", + }, + { + 0x11, "AC1.H", "Accu High 1", + }, + { + 0x12, "CR", "Config Register", + }, + { + 0x13, "SR", "Special Register", + }, + { + 0x14, "PROD.L", "Prod L", + }, + { + 0x15, "PROD.M1", "Prod M1", + }, + { + 0x16, "PROD.H", "Prod H", + }, + { + 0x17, "PROD.M2", "Prod M2", + }, + { + 0x18, "AX0.L", "Extra Accu L 0", + }, + { + 0x19, "AX1.L", "Extra Accu L 1", + }, + { + 0x1a, "AX0.H", "Extra Accu H 0", + }, + { + 0x1b, "AX1.H", "Extra Accu H 1", + }, + { + 0x1c, "AC0.L", "Accu Low 0", + }, + { + 0x1d, "AC1.L", "Accu Low 1", + }, + { + 0x1e, "AC0.M", "Accu Mid 0", + }, + { + 0x1f, "AC1.M", "Accu Mid 1", + }, - // To resolve combined register names. - {0x20, "ACC0", "Accu Full 0",}, - {0x21, "ACC1", "Accu Full 1",}, - {0x22, "AX0", "Extra Accu 0",}, - {0x23, "AX1", "Extra Accu 1",}, + // To resolve combined register names. + { + 0x20, "ACC0", "Accu Full 0", + }, + { + 0x21, "ACC1", "Accu Full 1", + }, + { + 0x22, "AX0", "Extra Accu 0", + }, + { + 0x23, "AX1", "Extra Accu 1", + }, }; -const DSPOPCTemplate *opTable[OPTABLE_SIZE]; -const DSPOPCTemplate *extOpTable[EXT_OPTABLE_SIZE]; +const DSPOPCTemplate* opTable[OPTABLE_SIZE]; +const DSPOPCTemplate* extOpTable[EXT_OPTABLE_SIZE]; u16 writeBackLog[WRITEBACKLOGSIZE]; int writeBackLogIdx[WRITEBACKLOGSIZE]; const char* pdname(u16 val) { - static char tmpstr[12]; // nasty + static char tmpstr[12]; // nasty - for (const pdlabel_t& pdlabel : pdlabels) - { - if (pdlabel.addr == val) - return pdlabel.name; - } + for (const pdlabel_t& pdlabel : pdlabels) + { + if (pdlabel.addr == val) + return pdlabel.name; + } - sprintf(tmpstr, "0x%04x", val); - return tmpstr; + sprintf(tmpstr, "0x%04x", val); + return tmpstr; } -const char *pdregname(int val) +const char* pdregname(int val) { - return regnames[val].name; + return regnames[val].name; } -const char *pdregnamelong(int val) +const char* pdregnamelong(int val) { - return regnames[val].description; + return regnames[val].description; } -const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst) +const DSPOPCTemplate* GetOpTemplate(const UDSPInstruction& inst) { - return opTable[inst]; + return opTable[inst]; } - // This function could use the above GetOpTemplate, but then we'd lose the // nice property that it catches colliding op masks. void InitInstructionTable() { - // ext op table - for (int i = 0; i < EXT_OPTABLE_SIZE; i++) - { - extOpTable[i] = &cw; + // ext op table + for (int i = 0; i < EXT_OPTABLE_SIZE; i++) + { + extOpTable[i] = &cw; - for (const DSPOPCTemplate& ext : opcodes_ext) - { - u16 mask = ext.opcode_mask; - if ((mask & i) == ext.opcode) - { - if (extOpTable[i] == &cw) - { - extOpTable[i] = &ext; - } - else - { - //if the entry already in the table - //is a strict subset, allow it - if ((extOpTable[i]->opcode_mask | ext.opcode_mask) != extOpTable[i]->opcode_mask) - { - ERROR_LOG(DSPLLE, "opcode ext table place %d already in use by %s when inserting %s", i, extOpTable[i]->name, ext.name); - } - } - } - } - } + for (const DSPOPCTemplate& ext : opcodes_ext) + { + u16 mask = ext.opcode_mask; + if ((mask & i) == ext.opcode) + { + if (extOpTable[i] == &cw) + { + extOpTable[i] = &ext; + } + else + { + // if the entry already in the table + // is a strict subset, allow it + if ((extOpTable[i]->opcode_mask | ext.opcode_mask) != extOpTable[i]->opcode_mask) + { + ERROR_LOG(DSPLLE, "opcode ext table place %d already in use by %s when inserting %s", i, + extOpTable[i]->name, ext.name); + } + } + } + } + } - // op table - for (const DSPOPCTemplate*& opcode : opTable) - { - opcode = &cw; - } + // op table + for (const DSPOPCTemplate*& opcode : opTable) + { + opcode = &cw; + } - for (int i = 0; i < OPTABLE_SIZE; i++) - { - for (const DSPOPCTemplate& opcode : opcodes) - { - u16 mask = opcode.opcode_mask; - if ((mask & i) == opcode.opcode) - { - if (opTable[i] == &cw) - opTable[i] = &opcode; - else - ERROR_LOG(DSPLLE, "opcode table place %d already in use for %s", i, opcode.name); - } - } - } + for (int i = 0; i < OPTABLE_SIZE; i++) + { + for (const DSPOPCTemplate& opcode : opcodes) + { + u16 mask = opcode.opcode_mask; + if ((mask & i) == opcode.opcode) + { + if (opTable[i] == &cw) + opTable[i] = &opcode; + else + ERROR_LOG(DSPLLE, "opcode table place %d already in use for %s", i, opcode.name); + } + } + } - for (int& elem : writeBackLogIdx) - { - elem = -1; - } + for (int& elem : writeBackLogIdx) + { + elem = -1; + } } diff --git a/Source/Core/Core/DSP/DSPTables.h b/Source/Core/Core/DSP/DSPTables.h index 97b920a1a9..9413a125c0 100644 --- a/Source/Core/Core/DSP/DSPTables.h +++ b/Source/Core/Core/DSP/DSPTables.h @@ -18,37 +18,37 @@ enum partype_t { - P_NONE = 0x0000, - P_VAL = 0x0001, - P_IMM = 0x0002, - P_MEM = 0x0003, - P_STR = 0x0004, - P_ADDR_I = 0x0005, - P_ADDR_D = 0x0006, - P_REG = 0x8000, - P_REG04 = P_REG | 0x0400, // IX - P_REG08 = P_REG | 0x0800, - P_REG18 = P_REG | 0x1800, - P_REGM18 = P_REG | 0x1810, // used in multiply instructions - P_REG19 = P_REG | 0x1900, - P_REGM19 = P_REG | 0x1910, // used in multiply instructions - P_REG1A = P_REG | 0x1a80, - P_REG1C = P_REG | 0x1c00, - // P_ACC = P_REG | 0x1c10, // used for global accum (gcdsptool's value) - P_ACCL = P_REG | 0x1c00, // used for low part of accum - P_ACCM = P_REG | 0x1e00, // used for mid part of accum - // The following are not in gcdsptool - P_ACCM_D = P_REG | 0x1e80, - P_ACC = P_REG | 0x2000, // used for full accum. - P_ACC_D = P_REG | 0x2080, - P_AX = P_REG | 0x2200, - P_REGS_MASK = 0x03f80, // gcdsptool's value = 0x01f80 - P_REF = P_REG | 0x4000, - P_PRG = P_REF | P_REG, + P_NONE = 0x0000, + P_VAL = 0x0001, + P_IMM = 0x0002, + P_MEM = 0x0003, + P_STR = 0x0004, + P_ADDR_I = 0x0005, + P_ADDR_D = 0x0006, + P_REG = 0x8000, + P_REG04 = P_REG | 0x0400, // IX + P_REG08 = P_REG | 0x0800, + P_REG18 = P_REG | 0x1800, + P_REGM18 = P_REG | 0x1810, // used in multiply instructions + P_REG19 = P_REG | 0x1900, + P_REGM19 = P_REG | 0x1910, // used in multiply instructions + P_REG1A = P_REG | 0x1a80, + P_REG1C = P_REG | 0x1c00, + // P_ACC = P_REG | 0x1c10, // used for global accum (gcdsptool's value) + P_ACCL = P_REG | 0x1c00, // used for low part of accum + P_ACCM = P_REG | 0x1e00, // used for mid part of accum + // The following are not in gcdsptool + P_ACCM_D = P_REG | 0x1e80, + P_ACC = P_REG | 0x2000, // used for full accum. + P_ACC_D = P_REG | 0x2080, + P_AX = P_REG | 0x2200, + P_REGS_MASK = 0x03f80, // gcdsptool's value = 0x01f80 + P_REF = P_REG | 0x4000, + P_PRG = P_REF | P_REG, - // The following seem like junk: - // P_REG10 = P_REG | 0x1000, - // P_AX_D = P_REG | 0x2280, + // The following seem like junk: + // P_REG10 = P_REG | 0x1000, + // P_AX_D = P_REG | 0x2280, }; #define OPTABLE_SIZE 0xffff + 1 @@ -61,30 +61,30 @@ typedef void (DSPEmitter::*dspJitFunc)(const UDSPInstruction); struct param2_t { - partype_t type; - u8 size; - u8 loc; - s8 lshift; - u16 mask; + partype_t type; + u8 size; + u8 loc; + s8 lshift; + u16 mask; }; struct DSPOPCTemplate { - const char *name; - u16 opcode; - u16 opcode_mask; + const char* name; + u16 opcode; + u16 opcode_mask; - dspIntFunc intFunc; - dspJitFunc jitFunc; + dspIntFunc intFunc; + dspJitFunc jitFunc; - u8 size; - u8 param_count; - param2_t params[8]; - bool extended; - bool branch; - bool uncond_branch; - bool reads_pc; - bool updates_sr; + u8 size; + u8 param_count; + param2_t params[8]; + bool extended; + bool branch; + bool uncond_branch; + bool reads_pc; + bool updates_sr; }; typedef DSPOPCTemplate opc_t; @@ -98,50 +98,50 @@ extern const DSPOPCTemplate cw; #define WRITEBACKLOGSIZE 5 -extern const DSPOPCTemplate *opTable[OPTABLE_SIZE]; -extern const DSPOPCTemplate *extOpTable[EXT_OPTABLE_SIZE]; +extern const DSPOPCTemplate* opTable[OPTABLE_SIZE]; +extern const DSPOPCTemplate* extOpTable[EXT_OPTABLE_SIZE]; extern u16 writeBackLog[WRITEBACKLOGSIZE]; extern int writeBackLogIdx[WRITEBACKLOGSIZE]; // Predefined labels struct pdlabel_t { - u16 addr; - const char* name; - const char* description; + u16 addr; + const char* name; + const char* description; }; extern const pdlabel_t regnames[]; extern const pdlabel_t pdlabels[]; extern const u32 pdlabels_size; -const char *pdname(u16 val); -const char *pdregname(int val); -const char *pdregnamelong(int val); +const char* pdname(u16 val); +const char* pdregname(int val); +const char* pdregnamelong(int val); void InitInstructionTable(); void applyWriteBackLog(); void zeroWriteBackLog(); void zeroWriteBackLogPreserveAcc(u8 acc); -const DSPOPCTemplate *GetOpTemplate(const UDSPInstruction &inst); +const DSPOPCTemplate* GetOpTemplate(const UDSPInstruction& inst); inline void ExecuteInstruction(const UDSPInstruction inst) { - const DSPOPCTemplate *tinst = GetOpTemplate(inst); + const DSPOPCTemplate* tinst = GetOpTemplate(inst); - if (tinst->extended) - { - if ((inst >> 12) == 0x3) - extOpTable[inst & 0x7F]->intFunc(inst); - else - extOpTable[inst & 0xFF]->intFunc(inst); - } + if (tinst->extended) + { + if ((inst >> 12) == 0x3) + extOpTable[inst & 0x7F]->intFunc(inst); + else + extOpTable[inst & 0xFF]->intFunc(inst); + } - tinst->intFunc(inst); + tinst->intFunc(inst); - if (tinst->extended) - { - applyWriteBackLog(); - } + if (tinst->extended) + { + applyWriteBackLog(); + } } diff --git a/Source/Core/Core/DSP/Jit/DSPJitArithmetic.cpp b/Source/Core/Core/DSP/Jit/DSPJitArithmetic.cpp index 0e2e8d667a..6fc39fdc24 100644 --- a/Source/Core/Core/DSP/Jit/DSPJitArithmetic.cpp +++ b/Source/Core/Core/DSP/Jit/DSPJitArithmetic.cpp @@ -19,15 +19,15 @@ using namespace Gen; // flags out: --10 0100 void DSPEmitter::clr(const UDSPInstruction opc) { - u8 reg = (opc >> 11) & 0x1; -// dsp_set_long_acc(reg, 0); - MOV(64, R(RAX), Imm64(0)); - set_long_acc(reg); -// Update_SR_Register64(0); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + u8 reg = (opc >> 11) & 0x1; + // dsp_set_long_acc(reg, 0); + MOV(64, R(RAX), Imm64(0)); + set_long_acc(reg); + // Update_SR_Register64(0); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // CLRL $acR.l @@ -37,17 +37,17 @@ void DSPEmitter::clr(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::clrl(const UDSPInstruction opc) { - u8 reg = (opc >> 8) & 0x1; -// s64 acc = dsp_round_long_acc(dsp_get_long_acc(reg)); - get_long_acc(reg); - round_long_acc(); -// dsp_set_long_acc(reg, acc); - set_long_acc(reg); -// Update_SR_Register64(acc); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + u8 reg = (opc >> 8) & 0x1; + // s64 acc = dsp_round_long_acc(dsp_get_long_acc(reg)); + get_long_acc(reg); + round_long_acc(); + // dsp_set_long_acc(reg, acc); + set_long_acc(reg); + // Update_SR_Register64(acc); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } //---- @@ -61,30 +61,30 @@ void DSPEmitter::clrl(const UDSPInstruction opc) // flags out: -x-- ---- void DSPEmitter::andcf(const UDSPInstruction opc) { - if (FlagsNeeded()) - { - u8 reg = (opc >> 8) & 0x1; -// u16 imm = dsp_fetch_code(); - u16 imm = dsp_imem_read(compilePC+1); -// u16 val = dsp_get_acc_m(reg); - get_acc_m(reg); -// Update_SR_LZ(((val & imm) == imm) ? true : false); -// if ((val & imm) == imm) -// g_dsp.r.sr |= SR_LOGIC_ZERO; -// else -// g_dsp.r.sr &= ~SR_LOGIC_ZERO; - OpArg sr_reg; - gpr.GetReg(DSP_REG_SR,sr_reg); - AND(16, R(RAX), Imm16(imm)); - CMP(16, R(RAX), Imm16(imm)); - FixupBranch notLogicZero = J_CC(CC_NE); - OR(16, sr_reg, Imm16(SR_LOGIC_ZERO)); - FixupBranch exit = J(); - SetJumpTarget(notLogicZero); - AND(16, sr_reg, Imm16(~SR_LOGIC_ZERO)); - SetJumpTarget(exit); - gpr.PutReg(DSP_REG_SR); - } + if (FlagsNeeded()) + { + u8 reg = (opc >> 8) & 0x1; + // u16 imm = dsp_fetch_code(); + u16 imm = dsp_imem_read(compilePC + 1); + // u16 val = dsp_get_acc_m(reg); + get_acc_m(reg); + // Update_SR_LZ(((val & imm) == imm) ? true : false); + // if ((val & imm) == imm) + // g_dsp.r.sr |= SR_LOGIC_ZERO; + // else + // g_dsp.r.sr &= ~SR_LOGIC_ZERO; + OpArg sr_reg; + gpr.GetReg(DSP_REG_SR, sr_reg); + AND(16, R(RAX), Imm16(imm)); + CMP(16, R(RAX), Imm16(imm)); + FixupBranch notLogicZero = J_CC(CC_NE); + OR(16, sr_reg, Imm16(SR_LOGIC_ZERO)); + FixupBranch exit = J(); + SetJumpTarget(notLogicZero); + AND(16, sr_reg, Imm16(~SR_LOGIC_ZERO)); + SetJumpTarget(exit); + gpr.PutReg(DSP_REG_SR); + } } // ANDF $acD.m, #I @@ -97,29 +97,29 @@ void DSPEmitter::andcf(const UDSPInstruction opc) // flags out: -x-- ---- void DSPEmitter::andf(const UDSPInstruction opc) { - if (FlagsNeeded()) - { - u8 reg = (opc >> 8) & 0x1; -// u16 imm = dsp_fetch_code(); - u16 imm = dsp_imem_read(compilePC+1); -// u16 val = dsp_get_acc_m(reg); - get_acc_m(reg); -// Update_SR_LZ(((val & imm) == 0) ? true : false); -// if ((val & imm) == 0) -// g_dsp.r.sr |= SR_LOGIC_ZERO; -// else -// g_dsp.r.sr &= ~SR_LOGIC_ZERO; - OpArg sr_reg; - gpr.GetReg(DSP_REG_SR,sr_reg); - TEST(16, R(RAX), Imm16(imm)); - FixupBranch notLogicZero = J_CC(CC_NE); - OR(16, sr_reg, Imm16(SR_LOGIC_ZERO)); - FixupBranch exit = J(); - SetJumpTarget(notLogicZero); - AND(16, sr_reg, Imm16(~SR_LOGIC_ZERO)); - SetJumpTarget(exit); - gpr.PutReg(DSP_REG_SR); - } + if (FlagsNeeded()) + { + u8 reg = (opc >> 8) & 0x1; + // u16 imm = dsp_fetch_code(); + u16 imm = dsp_imem_read(compilePC + 1); + // u16 val = dsp_get_acc_m(reg); + get_acc_m(reg); + // Update_SR_LZ(((val & imm) == 0) ? true : false); + // if ((val & imm) == 0) + // g_dsp.r.sr |= SR_LOGIC_ZERO; + // else + // g_dsp.r.sr &= ~SR_LOGIC_ZERO; + OpArg sr_reg; + gpr.GetReg(DSP_REG_SR, sr_reg); + TEST(16, R(RAX), Imm16(imm)); + FixupBranch notLogicZero = J_CC(CC_NE); + OR(16, sr_reg, Imm16(SR_LOGIC_ZERO)); + FixupBranch exit = J(); + SetJumpTarget(notLogicZero); + AND(16, sr_reg, Imm16(~SR_LOGIC_ZERO)); + SetJumpTarget(exit); + gpr.PutReg(DSP_REG_SR); + } } //---- @@ -131,14 +131,14 @@ void DSPEmitter::andf(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::tst(const UDSPInstruction opc) { - if (FlagsNeeded()) - { - u8 reg = (opc >> 11) & 0x1; -// s64 acc = dsp_get_long_acc(reg); - get_long_acc(reg); -// Update_SR_Register64(acc); - Update_SR_Register64(); - } + if (FlagsNeeded()) + { + u8 reg = (opc >> 11) & 0x1; + // s64 acc = dsp_get_long_acc(reg); + get_long_acc(reg); + // Update_SR_Register64(acc); + Update_SR_Register64(); + } } // TSTAXH $axR.h @@ -148,14 +148,14 @@ void DSPEmitter::tst(const UDSPInstruction opc) // flags out: --x0 xx00 void DSPEmitter::tstaxh(const UDSPInstruction opc) { - if (FlagsNeeded()) - { - u8 reg = (opc >> 8) & 0x1; -// s16 val = dsp_get_ax_h(reg); - get_ax_h(reg); -// Update_SR_Register16(val); - Update_SR_Register16(); - } + if (FlagsNeeded()) + { + u8 reg = (opc >> 8) & 0x1; + // s16 val = dsp_get_ax_h(reg); + get_ax_h(reg); + // Update_SR_Register16(val); + Update_SR_Register16(); + } } //---- @@ -167,21 +167,22 @@ void DSPEmitter::tstaxh(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::cmp(const UDSPInstruction opc) { - if (FlagsNeeded()) - { - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 acc0 = dsp_get_long_acc(0); - get_long_acc(0, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 acc1 = dsp_get_long_acc(1); - get_long_acc(1, RDX); -// s64 res = dsp_convert_long_acc(acc0 - acc1); - SUB(64, R(RAX), R(RDX)); -// Update_SR_Register64(res, isCarry2(acc0, res), isOverflow(acc0, -acc1, res)); // CF -> influence on ABS/0xa100 - NEG(64, R(RDX)); - Update_SR_Register64_Carry(EAX, tmp1, true); - gpr.PutXReg(tmp1); - } + if (FlagsNeeded()) + { + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 acc0 = dsp_get_long_acc(0); + get_long_acc(0, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 acc1 = dsp_get_long_acc(1); + get_long_acc(1, RDX); + // s64 res = dsp_convert_long_acc(acc0 - acc1); + SUB(64, R(RAX), R(RDX)); + // Update_SR_Register64(res, isCarry2(acc0, res), isOverflow(acc0, -acc1, res)); // CF -> + //influence on ABS/0xa100 + NEG(64, R(RDX)); + Update_SR_Register64_Carry(EAX, tmp1, true); + gpr.PutXReg(tmp1); + } } // CMPAR $acS axR.h @@ -192,26 +193,26 @@ void DSPEmitter::cmp(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::cmpar(const UDSPInstruction opc) { - if (FlagsNeeded()) - { - u8 rreg = ((opc >> 12) & 0x1); - u8 sreg = (opc >> 11) & 0x1; + if (FlagsNeeded()) + { + u8 rreg = ((opc >> 12) & 0x1); + u8 sreg = (opc >> 11) & 0x1; - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 sr = dsp_get_long_acc(sreg); - get_long_acc(sreg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 rr = (s16)g_dsp.r.axh[rreg]; - get_ax_h(rreg, RDX); -// rr <<= 16; - SHL(64, R(RDX), Imm8(16)); -// s64 res = dsp_convert_long_acc(sr - rr); - SUB(64, R(RAX), R(RDX)); -// Update_SR_Register64(res, isCarry2(sr, res), isOverflow(sr, -rr, res)); - NEG(64, R(RDX)); - Update_SR_Register64_Carry(EAX, tmp1, true); - gpr.PutXReg(tmp1); - } + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 sr = dsp_get_long_acc(sreg); + get_long_acc(sreg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 rr = (s16)g_dsp.r.axh[rreg]; + get_ax_h(rreg, RDX); + // rr <<= 16; + SHL(64, R(RDX), Imm8(16)); + // s64 res = dsp_convert_long_acc(sr - rr); + SUB(64, R(RAX), R(RDX)); + // Update_SR_Register64(res, isCarry2(sr, res), isOverflow(sr, -rr, res)); + NEG(64, R(RDX)); + Update_SR_Register64_Carry(EAX, tmp1, true); + gpr.PutXReg(tmp1); + } } // CMPI $amD, #I @@ -223,23 +224,24 @@ void DSPEmitter::cmpar(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::cmpi(const UDSPInstruction opc) { - if (FlagsNeeded()) - { - u8 reg = (opc >> 8) & 0x1; - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 val = dsp_get_long_acc(reg); - get_long_acc(reg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 imm = (s64)(s16)dsp_fetch_code() << 16; // Immediate is considered to be at M level in the 40-bit accumulator. - u16 imm = dsp_imem_read(compilePC+1); - MOV(64, R(RDX), Imm64((s64)(s16)imm << 16)); -// s64 res = dsp_convert_long_acc(val - imm); - SUB(64, R(RAX), R(RDX)); -// Update_SR_Register64(res, isCarry2(val, res), isOverflow(val, -imm, res)); - NEG(64, R(RDX)); - Update_SR_Register64_Carry(EAX, tmp1, true); - gpr.PutXReg(tmp1); - } + if (FlagsNeeded()) + { + u8 reg = (opc >> 8) & 0x1; + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 val = dsp_get_long_acc(reg); + get_long_acc(reg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 imm = (s64)(s16)dsp_fetch_code() << 16; // Immediate is considered to be at M level in + //the 40-bit accumulator. + u16 imm = dsp_imem_read(compilePC + 1); + MOV(64, R(RDX), Imm64((s64)(s16)imm << 16)); + // s64 res = dsp_convert_long_acc(val - imm); + SUB(64, R(RAX), R(RDX)); + // Update_SR_Register64(res, isCarry2(val, res), isOverflow(val, -imm, res)); + NEG(64, R(RDX)); + Update_SR_Register64_Carry(EAX, tmp1, true); + gpr.PutXReg(tmp1); + } } // CMPIS $acD, #I @@ -251,23 +253,23 @@ void DSPEmitter::cmpi(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::cmpis(const UDSPInstruction opc) { - if (FlagsNeeded()) - { - u8 areg = (opc >> 8) & 0x1; -// s64 acc = dsp_get_long_acc(areg); - X64Reg tmp1 = gpr.GetFreeXReg(); - get_long_acc(areg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 val = (s8)opc; -// val <<= 16; - MOV(64, R(RDX), Imm64((s64)(s8)opc << 16)); -// s64 res = dsp_convert_long_acc(acc - val); - SUB(64, R(RAX), R(RDX)); -// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -val, res)); - NEG(64, R(RDX)); - Update_SR_Register64_Carry(EAX, tmp1, true); - gpr.PutXReg(tmp1); - } + if (FlagsNeeded()) + { + u8 areg = (opc >> 8) & 0x1; + // s64 acc = dsp_get_long_acc(areg); + X64Reg tmp1 = gpr.GetFreeXReg(); + get_long_acc(areg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 val = (s8)opc; + // val <<= 16; + MOV(64, R(RDX), Imm64((s64)(s8)opc << 16)); + // s64 res = dsp_convert_long_acc(acc - val); + SUB(64, R(RAX), R(RDX)); + // Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -val, res)); + NEG(64, R(RDX)); + Update_SR_Register64_Carry(EAX, tmp1, true); + gpr.PutXReg(tmp1); + } } //---- @@ -281,20 +283,20 @@ void DSPEmitter::cmpis(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::xorr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; -// u16 accm = g_dsp.r.acm[dreg] ^ g_dsp.r.axh[sreg]; - get_acc_m(dreg, RAX); - get_ax_h(sreg, RDX); - XOR(64, R(RAX), R(RDX)); -// g_dsp.r.acm[dreg] = accm; - set_acc_m(dreg); -// Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); - if (FlagsNeeded()) - { - get_long_acc(dreg, RCX); - Update_SR_Register16_OverS32(); - } + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + // u16 accm = g_dsp.r.acm[dreg] ^ g_dsp.r.axh[sreg]; + get_acc_m(dreg, RAX); + get_ax_h(sreg, RDX); + XOR(64, R(RAX), R(RDX)); + // g_dsp.r.acm[dreg] = accm; + set_acc_m(dreg); + // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + if (FlagsNeeded()) + { + get_long_acc(dreg, RCX); + Update_SR_Register16_OverS32(); + } } // ANDR $acD.m, $axS.h @@ -306,20 +308,20 @@ void DSPEmitter::xorr(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::andr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - // u16 accm = g_dsp.r.acm[dreg] & g_dsp.r.axh[sreg]; - get_acc_m(dreg, RAX); - get_ax_h(sreg, RDX); - AND(64, R(RAX), R(RDX)); - // g_dsp.r.acm[dreg] = accm; - set_acc_m(dreg); - // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); - if (FlagsNeeded()) - { - get_long_acc(dreg, RCX); - Update_SR_Register16_OverS32(); - } + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + // u16 accm = g_dsp.r.acm[dreg] & g_dsp.r.axh[sreg]; + get_acc_m(dreg, RAX); + get_ax_h(sreg, RDX); + AND(64, R(RAX), R(RDX)); + // g_dsp.r.acm[dreg] = accm; + set_acc_m(dreg); + // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + if (FlagsNeeded()) + { + get_long_acc(dreg, RCX); + Update_SR_Register16_OverS32(); + } } // ORR $acD.m, $axS.h @@ -331,20 +333,20 @@ void DSPEmitter::andr(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::orr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; - // u16 accm = g_dsp.r.acm[dreg] | g_dsp.r.axh[sreg]; - get_acc_m(dreg, RAX); - get_ax_h(sreg, RDX); - OR(64, R(RAX), R(RDX)); - // g_dsp.r.acm[dreg] = accm; - set_acc_m(dreg); - // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); - if (FlagsNeeded()) - { - get_long_acc(dreg, RCX); - Update_SR_Register16_OverS32(); - } + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + // u16 accm = g_dsp.r.acm[dreg] | g_dsp.r.axh[sreg]; + get_acc_m(dreg, RAX); + get_ax_h(sreg, RDX); + OR(64, R(RAX), R(RDX)); + // g_dsp.r.acm[dreg] = accm; + set_acc_m(dreg); + // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + if (FlagsNeeded()) + { + get_long_acc(dreg, RCX); + Update_SR_Register16_OverS32(); + } } // ANDC $acD.m, $ac(1-D).m @@ -356,19 +358,19 @@ void DSPEmitter::orr(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::andc(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; -// u16 accm = g_dsp.r.acm[dreg] & g_dsp.r.acm[1 - dreg]; - get_acc_m(dreg, RAX); - get_acc_m(1 - dreg, RDX); - AND(64, R(RAX), R(RDX)); - // g_dsp.r.acm[dreg] = accm; - set_acc_m(dreg); - // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); - if (FlagsNeeded()) - { - get_long_acc(dreg, RCX); - Update_SR_Register16_OverS32(); - } + u8 dreg = (opc >> 8) & 0x1; + // u16 accm = g_dsp.r.acm[dreg] & g_dsp.r.acm[1 - dreg]; + get_acc_m(dreg, RAX); + get_acc_m(1 - dreg, RDX); + AND(64, R(RAX), R(RDX)); + // g_dsp.r.acm[dreg] = accm; + set_acc_m(dreg); + // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + if (FlagsNeeded()) + { + get_long_acc(dreg, RCX); + Update_SR_Register16_OverS32(); + } } // ORC $acD.m, $ac(1-D).m @@ -380,19 +382,19 @@ void DSPEmitter::andc(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::orc(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - // u16 accm = g_dsp.r.acm[dreg] | g_dsp.r.acm[1 - dreg]; - get_acc_m(dreg, RAX); - get_acc_m(1 - dreg, RDX); - OR(64, R(RAX), R(RDX)); - // g_dsp.r.acm[dreg] = accm; - set_acc_m(dreg); - // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); - if (FlagsNeeded()) - { - get_long_acc(dreg, RCX); - Update_SR_Register16_OverS32(); - } + u8 dreg = (opc >> 8) & 0x1; + // u16 accm = g_dsp.r.acm[dreg] | g_dsp.r.acm[1 - dreg]; + get_acc_m(dreg, RAX); + get_acc_m(1 - dreg, RDX); + OR(64, R(RAX), R(RDX)); + // g_dsp.r.acm[dreg] = accm; + set_acc_m(dreg); + // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + if (FlagsNeeded()) + { + get_long_acc(dreg, RCX); + Update_SR_Register16_OverS32(); + } } // XORC $acD.m @@ -403,19 +405,19 @@ void DSPEmitter::orc(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::xorc(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - // u16 accm = g_dsp.r.acm[dreg] ^ g_dsp.r.acm[1 - dreg]; - get_acc_m(dreg, RAX); - get_acc_m(1 - dreg, RDX); - XOR(64, R(RAX), R(RDX)); - // g_dsp.r.acm[dreg] = accm; - set_acc_m(dreg); - // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); - if (FlagsNeeded()) - { - get_long_acc(dreg, RCX); - Update_SR_Register16_OverS32(); - } + u8 dreg = (opc >> 8) & 0x1; + // u16 accm = g_dsp.r.acm[dreg] ^ g_dsp.r.acm[1 - dreg]; + get_acc_m(dreg, RAX); + get_acc_m(1 - dreg, RDX); + XOR(64, R(RAX), R(RDX)); + // g_dsp.r.acm[dreg] = accm; + set_acc_m(dreg); + // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + if (FlagsNeeded()) + { + get_long_acc(dreg, RCX); + Update_SR_Register16_OverS32(); + } } // NOT $acD.m @@ -426,18 +428,18 @@ void DSPEmitter::xorc(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::notc(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; -// u16 accm = g_dsp.r.acm[dreg] ^ 0xffff; - get_acc_m(dreg, RAX); - XOR(16, R(RAX), Imm16(0xffff)); -// g_dsp.r.acm[dreg] = accm; - set_acc_m(dreg); -// Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); - if (FlagsNeeded()) - { - get_long_acc(dreg, RCX); - Update_SR_Register16_OverS32(); - } + u8 dreg = (opc >> 8) & 0x1; + // u16 accm = g_dsp.r.acm[dreg] ^ 0xffff; + get_acc_m(dreg, RAX); + XOR(16, R(RAX), Imm16(0xffff)); + // g_dsp.r.acm[dreg] = accm; + set_acc_m(dreg); + // Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); + if (FlagsNeeded()) + { + get_long_acc(dreg, RCX); + Update_SR_Register16_OverS32(); + } } // XORI $acD.m, #I @@ -449,19 +451,19 @@ void DSPEmitter::notc(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::xori(const UDSPInstruction opc) { - u8 reg = (opc >> 8) & 0x1; -// u16 imm = dsp_fetch_code(); - u16 imm = dsp_imem_read(compilePC+1); -// g_dsp.r.acm[reg] ^= imm; - get_acc_m(reg, RAX); - XOR(16, R(RAX), Imm16(imm)); - set_acc_m(reg); -// Update_SR_Register16((s16)g_dsp.r.acm[reg], false, false, isOverS32(dsp_get_long_acc(reg))); - if (FlagsNeeded()) - { - get_long_acc(reg, RCX); - Update_SR_Register16_OverS32(); - } + u8 reg = (opc >> 8) & 0x1; + // u16 imm = dsp_fetch_code(); + u16 imm = dsp_imem_read(compilePC + 1); + // g_dsp.r.acm[reg] ^= imm; + get_acc_m(reg, RAX); + XOR(16, R(RAX), Imm16(imm)); + set_acc_m(reg); + // Update_SR_Register16((s16)g_dsp.r.acm[reg], false, false, isOverS32(dsp_get_long_acc(reg))); + if (FlagsNeeded()) + { + get_long_acc(reg, RCX); + Update_SR_Register16_OverS32(); + } } // ANDI $acD.m, #I @@ -472,19 +474,19 @@ void DSPEmitter::xori(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::andi(const UDSPInstruction opc) { - u8 reg = (opc >> 8) & 0x1; -// u16 imm = dsp_fetch_code(); - u16 imm = dsp_imem_read(compilePC+1); -// g_dsp.r.acm[reg] &= imm; - get_acc_m(reg, RAX); - AND(16, R(RAX), Imm16(imm)); - set_acc_m(reg); -// Update_SR_Register16((s16)g_dsp.r.acm[reg], false, false, isOverS32(dsp_get_long_acc(reg))); - if (FlagsNeeded()) - { - get_long_acc(reg, RCX); - Update_SR_Register16_OverS32(); - } + u8 reg = (opc >> 8) & 0x1; + // u16 imm = dsp_fetch_code(); + u16 imm = dsp_imem_read(compilePC + 1); + // g_dsp.r.acm[reg] &= imm; + get_acc_m(reg, RAX); + AND(16, R(RAX), Imm16(imm)); + set_acc_m(reg); + // Update_SR_Register16((s16)g_dsp.r.acm[reg], false, false, isOverS32(dsp_get_long_acc(reg))); + if (FlagsNeeded()) + { + get_long_acc(reg, RCX); + Update_SR_Register16_OverS32(); + } } // ORI $acD.m, #I @@ -495,19 +497,19 @@ void DSPEmitter::andi(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::ori(const UDSPInstruction opc) { - u8 reg = (opc >> 8) & 0x1; - // u16 imm = dsp_fetch_code(); - u16 imm = dsp_imem_read(compilePC+1); - // g_dsp.r.acm[reg] |= imm; - get_acc_m(reg, RAX); - OR(16, R(RAX), Imm16(imm)); - set_acc_m(reg); - // Update_SR_Register16((s16)g_dsp.r.acm[reg], false, false, isOverS32(dsp_get_long_acc(reg))); - if (FlagsNeeded()) - { - get_long_acc(reg, RCX); - Update_SR_Register16_OverS32(); - } + u8 reg = (opc >> 8) & 0x1; + // u16 imm = dsp_fetch_code(); + u16 imm = dsp_imem_read(compilePC + 1); + // g_dsp.r.acm[reg] |= imm; + get_acc_m(reg, RAX); + OR(16, R(RAX), Imm16(imm)); + set_acc_m(reg); + // Update_SR_Register16((s16)g_dsp.r.acm[reg], false, false, isOverS32(dsp_get_long_acc(reg))); + if (FlagsNeeded()) + { + get_long_acc(reg, RCX); + Update_SR_Register16_OverS32(); + } } //---- @@ -519,32 +521,32 @@ void DSPEmitter::ori(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::addr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; -// s64 acc = dsp_get_long_acc(dreg); - X64Reg tmp1 = gpr.GetFreeXReg(); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 ax = (s16)g_dsp.r[sreg]; - dsp_op_read_reg(sreg, RDX, SIGN); -// ax <<= 16; - SHL(64, R(RDX), Imm8(16)); -// s64 res = acc + ax; - ADD(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); - if (FlagsNeeded()) - { - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); - } - else - { - set_long_acc(dreg, RAX); - } - gpr.PutXReg(tmp1); + // s64 acc = dsp_get_long_acc(dreg); + X64Reg tmp1 = gpr.GetFreeXReg(); + get_long_acc(dreg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 ax = (s16)g_dsp.r[sreg]; + dsp_op_read_reg(sreg, RDX, SIGN); + // ax <<= 16; + SHL(64, R(RDX), Imm8(16)); + // s64 res = acc + ax; + ADD(64, R(RAX), R(RDX)); + // dsp_set_long_acc(dreg, res); + // Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); + if (FlagsNeeded()) + { + MOV(64, R(RCX), R(RAX)); + set_long_acc(dreg, RCX); + Update_SR_Register64_Carry(EAX, tmp1); + } + else + { + set_long_acc(dreg, RAX); + } + gpr.PutXReg(tmp1); } // ADDAX $acD, $axS @@ -554,31 +556,31 @@ void DSPEmitter::addr(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::addax(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 ax = dsp_get_long_acx(sreg); - get_long_acx(sreg, RDX); -// s64 res = acc + ax; - ADD(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); - if (FlagsNeeded()) - { - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); - } - else - { - set_long_acc(dreg, RAX); - } - gpr.PutXReg(tmp1); + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 ax = dsp_get_long_acx(sreg); + get_long_acx(sreg, RDX); + // s64 res = acc + ax; + ADD(64, R(RAX), R(RDX)); + // dsp_set_long_acc(dreg, res); + // res = dsp_get_long_acc(dreg); + // Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); + if (FlagsNeeded()) + { + MOV(64, R(RCX), R(RAX)); + set_long_acc(dreg, RCX); + Update_SR_Register64_Carry(EAX, tmp1); + } + else + { + set_long_acc(dreg, RAX); + } + gpr.PutXReg(tmp1); } // ADD $acD, $ac(1-D) @@ -588,30 +590,30 @@ void DSPEmitter::addax(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::add(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 acc0 = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 acc1 = dsp_get_long_acc(1 - dreg); - get_long_acc(1 - dreg, RDX); -// s64 res = acc0 + acc1; - ADD(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry(acc0, res), isOverflow(acc0, acc1, res)); - if (FlagsNeeded()) - { - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); - } - else - { - set_long_acc(dreg, RAX); - } - gpr.PutXReg(tmp1); + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 acc0 = dsp_get_long_acc(dreg); + get_long_acc(dreg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 acc1 = dsp_get_long_acc(1 - dreg); + get_long_acc(1 - dreg, RDX); + // s64 res = acc0 + acc1; + ADD(64, R(RAX), R(RDX)); + // dsp_set_long_acc(dreg, res); + // res = dsp_get_long_acc(dreg); + // Update_SR_Register64(res, isCarry(acc0, res), isOverflow(acc0, acc1, res)); + if (FlagsNeeded()) + { + MOV(64, R(RCX), R(RAX)); + set_long_acc(dreg, RCX); + Update_SR_Register64_Carry(EAX, tmp1); + } + else + { + set_long_acc(dreg, RAX); + } + gpr.PutXReg(tmp1); } // ADDP $acD @@ -621,30 +623,30 @@ void DSPEmitter::add(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::addp(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 prod = dsp_get_long_prod(); - get_long_prod(RDX); -// s64 res = acc + prod; - ADD(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, prod, res)); - if (FlagsNeeded()) - { - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); - } - else - { - set_long_acc(dreg, RAX); - } - gpr.PutXReg(tmp1); + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 prod = dsp_get_long_prod(); + get_long_prod(RDX); + // s64 res = acc + prod; + ADD(64, R(RAX), R(RDX)); + // dsp_set_long_acc(dreg, res); + // res = dsp_get_long_acc(dreg); + // Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, prod, res)); + if (FlagsNeeded()) + { + MOV(64, R(RCX), R(RAX)); + set_long_acc(dreg, RCX); + Update_SR_Register64_Carry(EAX, tmp1); + } + else + { + set_long_acc(dreg, RAX); + } + gpr.PutXReg(tmp1); } // ADDAXL $acD, $axS.l @@ -655,32 +657,32 @@ void DSPEmitter::addp(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::addaxl(const UDSPInstruction opc) { - u8 sreg = (opc >> 9) & 0x1; - u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - X64Reg tmp1 = gpr.GetFreeXReg(); -// u64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// u16 acx = (u16)dsp_get_ax_l(sreg); - get_ax_l(sreg, RDX); - MOVZX(64, 16, RDX, R(RDX)); -// u64 res = acc + acx; - ADD(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, (s64)res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64((s64)res, isCarry(acc, res), isOverflow((s64)acc, (s64)acx, (s64)res)); - if (FlagsNeeded()) - { - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); - } - else - { - set_long_acc(dreg, RAX); - } - gpr.PutXReg(tmp1); + X64Reg tmp1 = gpr.GetFreeXReg(); + // u64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // u16 acx = (u16)dsp_get_ax_l(sreg); + get_ax_l(sreg, RDX); + MOVZX(64, 16, RDX, R(RDX)); + // u64 res = acc + acx; + ADD(64, R(RAX), R(RDX)); + // dsp_set_long_acc(dreg, (s64)res); + // res = dsp_get_long_acc(dreg); + // Update_SR_Register64((s64)res, isCarry(acc, res), isOverflow((s64)acc, (s64)acx, (s64)res)); + if (FlagsNeeded()) + { + MOV(64, R(RCX), R(RAX)); + set_long_acc(dreg, RCX); + Update_SR_Register64_Carry(EAX, tmp1); + } + else + { + set_long_acc(dreg, RAX); + } + gpr.PutXReg(tmp1); } // ADDI $amR, #I @@ -691,33 +693,33 @@ void DSPEmitter::addaxl(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::addi(const UDSPInstruction opc) { - u8 areg = (opc >> 8) & 0x1; - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 acc = dsp_get_long_acc(areg); - get_long_acc(areg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 imm = (s16)dsp_fetch_code(); - s16 imm = dsp_imem_read(compilePC+1); - //imm <<= 16; - MOV(16, R(RDX), Imm16(imm)); - MOVSX(64, 16, RDX, R(RDX)); - SHL(64, R(RDX), Imm8(16)); -// s64 res = acc + imm; - ADD(64, R(RAX), R(RDX)); -// dsp_set_long_acc(areg, res); -// res = dsp_get_long_acc(areg); -// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); - if (FlagsNeeded()) - { - MOV(64, R(RCX), R(RAX)); - set_long_acc(areg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); - } - else - { - set_long_acc(areg, RAX); - } - gpr.PutXReg(tmp1); + u8 areg = (opc >> 8) & 0x1; + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 acc = dsp_get_long_acc(areg); + get_long_acc(areg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 imm = (s16)dsp_fetch_code(); + s16 imm = dsp_imem_read(compilePC + 1); + // imm <<= 16; + MOV(16, R(RDX), Imm16(imm)); + MOVSX(64, 16, RDX, R(RDX)); + SHL(64, R(RDX), Imm8(16)); + // s64 res = acc + imm; + ADD(64, R(RAX), R(RDX)); + // dsp_set_long_acc(areg, res); + // res = dsp_get_long_acc(areg); + // Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); + if (FlagsNeeded()) + { + MOV(64, R(RCX), R(RAX)); + set_long_acc(areg, RCX); + Update_SR_Register64_Carry(EAX, tmp1); + } + else + { + set_long_acc(areg, RAX); + } + gpr.PutXReg(tmp1); } // ADDIS $acD, #I @@ -727,33 +729,33 @@ void DSPEmitter::addi(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::addis(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 imm = (s8)(u8)opc; -// imm <<= 16; - MOV(8, R(RDX), Imm8((u8)opc)); - MOVSX(64, 8, RDX, R(RDX)); - SHL(64, R(RDX), Imm8(16)); -// s64 res = acc + imm; - ADD(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); - if (FlagsNeeded()) - { - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); - } - else - { - set_long_acc(dreg, RAX); - } - gpr.PutXReg(tmp1); + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 imm = (s8)(u8)opc; + // imm <<= 16; + MOV(8, R(RDX), Imm8((u8)opc)); + MOVSX(64, 8, RDX, R(RDX)); + SHL(64, R(RDX), Imm8(16)); + // s64 res = acc + imm; + ADD(64, R(RAX), R(RDX)); + // dsp_set_long_acc(dreg, res); + // res = dsp_get_long_acc(dreg); + // Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); + if (FlagsNeeded()) + { + MOV(64, R(RCX), R(RAX)); + set_long_acc(dreg, RCX); + Update_SR_Register64_Carry(EAX, tmp1); + } + else + { + set_long_acc(dreg, RAX); + } + gpr.PutXReg(tmp1); } // INCM $acsD @@ -763,29 +765,29 @@ void DSPEmitter::addis(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::incm(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - s64 subtract = 0x10000; - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 res = acc + sub; - ADD(64, R(RAX), Imm32((u32)subtract)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, subtract, res)); - if (FlagsNeeded()) - { - MOV(64, R(RDX), Imm32((u32)subtract)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); - } - else - { - set_long_acc(dreg); - } - gpr.PutXReg(tmp1); + u8 dreg = (opc >> 8) & 0x1; + s64 subtract = 0x10000; + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 res = acc + sub; + ADD(64, R(RAX), Imm32((u32)subtract)); + // dsp_set_long_acc(dreg, res); + // res = dsp_get_long_acc(dreg); + // Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, subtract, res)); + if (FlagsNeeded()) + { + MOV(64, R(RDX), Imm32((u32)subtract)); + MOV(64, R(RCX), R(RAX)); + set_long_acc(dreg, RCX); + Update_SR_Register64_Carry(EAX, tmp1); + } + else + { + set_long_acc(dreg); + } + gpr.PutXReg(tmp1); } // INC $acD @@ -795,28 +797,28 @@ void DSPEmitter::incm(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::inc(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 res = acc + 1; - ADD(64, R(RAX), Imm8(1)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, 1, res)); - if (FlagsNeeded()) - { - MOV(64, R(RDX), Imm64(1)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); - } - else - { - set_long_acc(dreg); - } - gpr.PutXReg(tmp1); + u8 dreg = (opc >> 8) & 0x1; + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 res = acc + 1; + ADD(64, R(RAX), Imm8(1)); + // dsp_set_long_acc(dreg, res); + // res = dsp_get_long_acc(dreg); + // Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, 1, res)); + if (FlagsNeeded()) + { + MOV(64, R(RDX), Imm64(1)); + MOV(64, R(RCX), R(RAX)); + set_long_acc(dreg, RCX); + Update_SR_Register64_Carry(EAX, tmp1); + } + else + { + set_long_acc(dreg); + } + gpr.PutXReg(tmp1); } //---- @@ -828,34 +830,34 @@ void DSPEmitter::inc(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::subr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 ax = (s16)g_dsp.r[sreg]; - dsp_op_read_reg(sreg, RDX, SIGN); -// ax <<= 16; - SHL(64, R(RDX), Imm8(16)); -// s64 res = acc - ax; - SUB(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -ax, res)); - if (FlagsNeeded()) - { - NEG(64, R(RDX)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1, true); - } - else - { - set_long_acc(dreg, RAX); - } - gpr.PutXReg(tmp1); + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 ax = (s16)g_dsp.r[sreg]; + dsp_op_read_reg(sreg, RDX, SIGN); + // ax <<= 16; + SHL(64, R(RDX), Imm8(16)); + // s64 res = acc - ax; + SUB(64, R(RAX), R(RDX)); + // dsp_set_long_acc(dreg, res); + // res = dsp_get_long_acc(dreg); + // Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -ax, res)); + if (FlagsNeeded()) + { + NEG(64, R(RDX)); + MOV(64, R(RCX), R(RAX)); + set_long_acc(dreg, RCX); + Update_SR_Register64_Carry(EAX, tmp1, true); + } + else + { + set_long_acc(dreg, RAX); + } + gpr.PutXReg(tmp1); } // SUBAX $acD, $axS @@ -865,32 +867,32 @@ void DSPEmitter::subr(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::subax(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 acx = dsp_get_long_acx(sreg); - get_long_acx(sreg, RDX); -// s64 res = acc - acx; - SUB(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -acx, res)); - if (FlagsNeeded()) - { - NEG(64, R(RDX)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1, true); - } - else - { - set_long_acc(dreg, RAX); - } - gpr.PutXReg(tmp1); + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 acx = dsp_get_long_acx(sreg); + get_long_acx(sreg, RDX); + // s64 res = acc - acx; + SUB(64, R(RAX), R(RDX)); + // dsp_set_long_acc(dreg, res); + // res = dsp_get_long_acc(dreg); + // Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -acx, res)); + if (FlagsNeeded()) + { + NEG(64, R(RDX)); + MOV(64, R(RCX), R(RAX)); + set_long_acc(dreg, RCX); + Update_SR_Register64_Carry(EAX, tmp1, true); + } + else + { + set_long_acc(dreg, RAX); + } + gpr.PutXReg(tmp1); } // SUB $acD, $ac(1-D) @@ -900,30 +902,30 @@ void DSPEmitter::subax(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::sub(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 acc1 = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 acc2 = dsp_get_long_acc(1 - dreg); - get_long_acc(1 - dreg, RDX); -// s64 res = acc1 - acc2; - SUB(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry2(acc1, res), isOverflow(acc1, -acc2, res)); - if (FlagsNeeded()) - { - NEG(64, R(RDX)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1, true); - } - else - { - set_long_acc(dreg, RAX); - } - gpr.PutXReg(tmp1); + u8 dreg = (opc >> 8) & 0x1; + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 acc1 = dsp_get_long_acc(dreg); + get_long_acc(dreg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 acc2 = dsp_get_long_acc(1 - dreg); + get_long_acc(1 - dreg, RDX); + // s64 res = acc1 - acc2; + SUB(64, R(RAX), R(RDX)); + // dsp_set_long_acc(dreg, res); + // res = dsp_get_long_acc(dreg); + // Update_SR_Register64(res, isCarry2(acc1, res), isOverflow(acc1, -acc2, res)); + if (FlagsNeeded()) + { + NEG(64, R(RDX)); + MOV(64, R(RCX), R(RAX)); + set_long_acc(dreg, RCX); + Update_SR_Register64_Carry(EAX, tmp1, true); + } + else + { + set_long_acc(dreg, RAX); + } + gpr.PutXReg(tmp1); } // SUBP $acD @@ -933,30 +935,30 @@ void DSPEmitter::sub(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::subp(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 prod = dsp_get_long_prod(); - get_long_prod(RDX); -// s64 res = acc - prod; - SUB(64, R(RAX), R(RDX)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -prod, res)); - if (FlagsNeeded()) - { - NEG(64, R(RDX)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1, true); - } - else - { - set_long_acc(dreg, RAX); - } - gpr.PutXReg(tmp1); + u8 dreg = (opc >> 8) & 0x1; + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 prod = dsp_get_long_prod(); + get_long_prod(RDX); + // s64 res = acc - prod; + SUB(64, R(RAX), R(RDX)); + // dsp_set_long_acc(dreg, res); + // res = dsp_get_long_acc(dreg); + // Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -prod, res)); + if (FlagsNeeded()) + { + NEG(64, R(RDX)); + MOV(64, R(RCX), R(RAX)); + set_long_acc(dreg, RCX); + Update_SR_Register64_Carry(EAX, tmp1, true); + } + else + { + set_long_acc(dreg, RAX); + } + gpr.PutXReg(tmp1); } // DECM $acsD @@ -966,29 +968,29 @@ void DSPEmitter::subp(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::decm(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x01; - s64 subtract = 0x10000; - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 res = acc - sub; - SUB(64, R(RAX), Imm32((u32)subtract)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -subtract, res)); - if (FlagsNeeded()) - { - MOV(64, R(RDX), Imm64(-subtract)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1, true); - } - else - { - set_long_acc(dreg, RAX); - } - gpr.PutXReg(tmp1); + u8 dreg = (opc >> 8) & 0x01; + s64 subtract = 0x10000; + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 res = acc - sub; + SUB(64, R(RAX), Imm32((u32)subtract)); + // dsp_set_long_acc(dreg, res); + // res = dsp_get_long_acc(dreg); + // Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -subtract, res)); + if (FlagsNeeded()) + { + MOV(64, R(RDX), Imm64(-subtract)); + MOV(64, R(RCX), R(RAX)); + set_long_acc(dreg, RCX); + Update_SR_Register64_Carry(EAX, tmp1, true); + } + else + { + set_long_acc(dreg, RAX); + } + gpr.PutXReg(tmp1); } // DEC $acD @@ -998,28 +1000,28 @@ void DSPEmitter::decm(const UDSPInstruction opc) // flags out: x-xx xxxx void DSPEmitter::dec(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x01; - X64Reg tmp1 = gpr.GetFreeXReg(); -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); -// s64 res = acc - 1; - SUB(64, R(RAX), Imm32(1)); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -1, res)); - if (FlagsNeeded()) - { - MOV(64, R(RDX), Imm64(-1)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1, true); - } - else - { - set_long_acc(dreg); - } - gpr.PutXReg(tmp1); + u8 dreg = (opc >> 8) & 0x01; + X64Reg tmp1 = gpr.GetFreeXReg(); + // s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, tmp1); + MOV(64, R(RAX), R(tmp1)); + // s64 res = acc - 1; + SUB(64, R(RAX), Imm32(1)); + // dsp_set_long_acc(dreg, res); + // res = dsp_get_long_acc(dreg); + // Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -1, res)); + if (FlagsNeeded()) + { + MOV(64, R(RDX), Imm64(-1)); + MOV(64, R(RCX), R(RAX)); + set_long_acc(dreg, RCX); + Update_SR_Register64_Carry(EAX, tmp1, true); + } + else + { + set_long_acc(dreg); + } + gpr.PutXReg(tmp1); } //---- @@ -1031,18 +1033,18 @@ void DSPEmitter::dec(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::neg(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg); -// acc = 0 - acc; - NEG(64, R(RAX)); -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg); -// Update_SR_Register64(dsp_get_long_acc(dreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + u8 dreg = (opc >> 8) & 0x1; + // s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg); + // acc = 0 - acc; + NEG(64, R(RAX)); + // dsp_set_long_acc(dreg, acc); + set_long_acc(dreg); + // Update_SR_Register64(dsp_get_long_acc(dreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // ABS $acD @@ -1052,21 +1054,21 @@ void DSPEmitter::neg(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::abs(const UDSPInstruction opc) { - u8 dreg = (opc >> 11) & 0x1; + u8 dreg = (opc >> 11) & 0x1; -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg); -// if (acc < 0) acc = 0 - acc; - TEST(64, R(RAX), R(RAX)); - FixupBranch GreaterThanOrEqual = J_CC(CC_GE); - NEG(64, R(RAX)); - set_long_acc(dreg); - SetJumpTarget(GreaterThanOrEqual); -// Update_SR_Register64(dsp_get_long_acc(dreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg); + // if (acc < 0) acc = 0 - acc; + TEST(64, R(RAX), R(RAX)); + FixupBranch GreaterThanOrEqual = J_CC(CC_GE); + NEG(64, R(RAX)); + set_long_acc(dreg); + SetJumpTarget(GreaterThanOrEqual); + // Update_SR_Register64(dsp_get_long_acc(dreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } //---- @@ -1079,20 +1081,20 @@ void DSPEmitter::abs(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::movr(const UDSPInstruction opc) { - u8 areg = (opc >> 8) & 0x1; - u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; + u8 areg = (opc >> 8) & 0x1; + u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; -// s64 acc = (s16)g_dsp.r[sreg]; - dsp_op_read_reg(sreg, RAX, SIGN); -// acc <<= 16; - SHL(64, R(RAX), Imm8(16)); -// acc &= ~0xffff; -// dsp_set_long_acc(areg, acc); - set_long_acc(areg); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // s64 acc = (s16)g_dsp.r[sreg]; + dsp_op_read_reg(sreg, RAX, SIGN); + // acc <<= 16; + SHL(64, R(RAX), Imm8(16)); + // acc &= ~0xffff; + // dsp_set_long_acc(areg, acc); + set_long_acc(areg); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // MOVAX $acD, $axS @@ -1102,18 +1104,18 @@ void DSPEmitter::movr(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::movax(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; -// s64 acx = dsp_get_long_acx(sreg); - get_long_acx(sreg); -// dsp_set_long_acc(dreg, acx); - set_long_acc(dreg); -// Update_SR_Register64(acx); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // s64 acx = dsp_get_long_acx(sreg); + get_long_acx(sreg); + // dsp_set_long_acc(dreg, acx); + set_long_acc(dreg); + // Update_SR_Register64(acx); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // MOV $acD, $ac(1-D) @@ -1123,16 +1125,16 @@ void DSPEmitter::movax(const UDSPInstruction opc) // flags out: --x0 xx00 void DSPEmitter::mov(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; -// u64 acc = dsp_get_long_acc(1 - dreg); - get_long_acc(1 - dreg); -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg); -// Update_SR_Register64(acc); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + u8 dreg = (opc >> 8) & 0x1; + // u64 acc = dsp_get_long_acc(1 - dreg); + get_long_acc(1 - dreg); + // dsp_set_long_acc(dreg, acc); + set_long_acc(dreg); + // Update_SR_Register64(acc); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } //---- @@ -1144,18 +1146,18 @@ void DSPEmitter::mov(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::lsl16(const UDSPInstruction opc) { - u8 areg = (opc >> 8) & 0x1; -// s64 acc = dsp_get_long_acc(areg); - get_long_acc(areg); -// acc <<= 16; - SHL(64, R(RAX), Imm8(16)); -// dsp_set_long_acc(areg, acc); - set_long_acc(areg); -// Update_SR_Register64(dsp_get_long_acc(areg)); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + u8 areg = (opc >> 8) & 0x1; + // s64 acc = dsp_get_long_acc(areg); + get_long_acc(areg); + // acc <<= 16; + SHL(64, R(RAX), Imm8(16)); + // dsp_set_long_acc(areg, acc); + set_long_acc(areg); + // Update_SR_Register64(dsp_get_long_acc(areg)); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // LSR16 $acR @@ -1165,21 +1167,22 @@ void DSPEmitter::lsl16(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::lsr16(const UDSPInstruction opc) { - u8 areg = (opc >> 8) & 0x1; + u8 areg = (opc >> 8) & 0x1; -// u64 acc = dsp_get_long_acc(areg); - get_long_acc(areg); -// acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes -// acc >>= 16; - SHR(64, R(RAX), Imm8(16)); - AND(64, R(RAX), Imm32(0xffffff)); -// dsp_set_long_acc(areg, (s64)acc); - set_long_acc(areg); -// Update_SR_Register64(dsp_get_long_acc(areg)); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // u64 acc = dsp_get_long_acc(areg); + get_long_acc(areg); + // acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum + //causes + // acc >>= 16; + SHR(64, R(RAX), Imm8(16)); + AND(64, R(RAX), Imm32(0xffffff)); + // dsp_set_long_acc(areg, (s64)acc); + set_long_acc(areg); + // Update_SR_Register64(dsp_get_long_acc(areg)); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // ASR16 $acR @@ -1189,19 +1192,19 @@ void DSPEmitter::lsr16(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::asr16(const UDSPInstruction opc) { - u8 areg = (opc >> 11) & 0x1; + u8 areg = (opc >> 11) & 0x1; -// s64 acc = dsp_get_long_acc(areg); - get_long_acc(areg); -// acc >>= 16; - SAR(64, R(RAX), Imm8(16)); -// dsp_set_long_acc(areg, acc); - set_long_acc(areg); -// Update_SR_Register64(dsp_get_long_acc(areg)); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // s64 acc = dsp_get_long_acc(areg); + get_long_acc(areg); + // acc >>= 16; + SAR(64, R(RAX), Imm8(16)); + // dsp_set_long_acc(areg, acc); + set_long_acc(areg); + // Update_SR_Register64(dsp_get_long_acc(areg)); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // LSL $acR, #I @@ -1211,21 +1214,21 @@ void DSPEmitter::asr16(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::lsl(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x01; - u16 shift = opc & 0x3f; -// u64 acc = dsp_get_long_acc(rreg); - get_long_acc(rreg); + u8 rreg = (opc >> 8) & 0x01; + u16 shift = opc & 0x3f; + // u64 acc = dsp_get_long_acc(rreg); + get_long_acc(rreg); -// acc <<= shift; - SHL(64, R(RAX), Imm8((u8)shift)); + // acc <<= shift; + SHL(64, R(RAX), Imm8((u8)shift)); -// dsp_set_long_acc(rreg, acc); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // dsp_set_long_acc(rreg, acc); + set_long_acc(rreg); + // Update_SR_Register64(dsp_get_long_acc(rreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // LSR $acR, #I @@ -1236,31 +1239,32 @@ void DSPEmitter::lsl(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::lsr(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x01; - u16 shift; -// u64 acc = dsp_get_long_acc(rreg); - get_long_acc(rreg); + u8 rreg = (opc >> 8) & 0x01; + u16 shift; + // u64 acc = dsp_get_long_acc(rreg); + get_long_acc(rreg); - if ((opc & 0x3f) == 0) - shift = 0; - else - shift = 0x40 - (opc & 0x3f); + if ((opc & 0x3f) == 0) + shift = 0; + else + shift = 0x40 - (opc & 0x3f); - if (shift) - { - // acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes - SHL(64, R(RAX), Imm8(24)); - // acc >>= shift; - SHR(64, R(RAX), Imm8(shift + 24)); - } + if (shift) + { + // acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake + //accum causes + SHL(64, R(RAX), Imm8(24)); + // acc >>= shift; + SHR(64, R(RAX), Imm8(shift + 24)); + } -// dsp_set_long_acc(rreg, (s64)acc); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // dsp_set_long_acc(rreg, (s64)acc); + set_long_acc(rreg); + // Update_SR_Register64(dsp_get_long_acc(rreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // ASL $acR, #I @@ -1270,19 +1274,19 @@ void DSPEmitter::lsr(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::asl(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x01; - u16 shift = opc & 0x3f; -// u64 acc = dsp_get_long_acc(rreg); - get_long_acc(rreg); -// acc <<= shift; - SHL(64, R(RAX), Imm8((u8)shift)); -// dsp_set_long_acc(rreg, acc); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + u8 rreg = (opc >> 8) & 0x01; + u16 shift = opc & 0x3f; + // u64 acc = dsp_get_long_acc(rreg); + get_long_acc(rreg); + // acc <<= shift; + SHL(64, R(RAX), Imm8((u8)shift)); + // dsp_set_long_acc(rreg, acc); + set_long_acc(rreg); + // Update_SR_Register64(dsp_get_long_acc(rreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // ASR $acR, #I @@ -1293,27 +1297,27 @@ void DSPEmitter::asl(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::asr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x01; - u16 shift; + u8 dreg = (opc >> 8) & 0x01; + u16 shift; - if ((opc & 0x3f) == 0) - shift = 0; - else - shift = 0x40 - (opc & 0x3f); + if ((opc & 0x3f) == 0) + shift = 0; + else + shift = 0x40 - (opc & 0x3f); - // arithmetic shift -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg); -// acc >>= shift; - SAR(64, R(RAX), Imm8((u8)shift)); + // arithmetic shift + // s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg); + // acc >>= shift; + SAR(64, R(RAX), Imm8((u8)shift)); -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg); -// Update_SR_Register64(dsp_get_long_acc(dreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // dsp_set_long_acc(dreg, acc); + set_long_acc(dreg); + // Update_SR_Register64(dsp_get_long_acc(dreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // LSRN (fixed parameters) @@ -1324,58 +1328,58 @@ void DSPEmitter::asr(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::lsrn(const UDSPInstruction opc) { -// s16 shift; -// u16 accm = (u16)dsp_get_acc_m(1); - get_acc_m(1); -// u64 acc = dsp_get_long_acc(0); - get_long_acc(0, RDX); -// acc &= 0x000000FFFFFFFFFFULL; - SHL(64, R(RDX), Imm8(24)); - SHR(64, R(RDX), Imm8(24)); + // s16 shift; + // u16 accm = (u16)dsp_get_acc_m(1); + get_acc_m(1); + // u64 acc = dsp_get_long_acc(0); + get_long_acc(0, RDX); + // acc &= 0x000000FFFFFFFFFFULL; + SHL(64, R(RDX), Imm8(24)); + SHR(64, R(RDX), Imm8(24)); - // if ((accm & 0x3f) == 0) - // shift = 0; - // else if (accm & 0x40) - // shift = -0x40 + (accm & 0x3f); - // else - // shift = accm & 0x3f; + // if ((accm & 0x3f) == 0) + // shift = 0; + // else if (accm & 0x40) + // shift = -0x40 + (accm & 0x3f); + // else + // shift = accm & 0x3f; - // if (shift > 0) - // { - // acc >>= shift; - // } - // else if (shift < 0) - // { - // acc <<= -shift; - // } + // if (shift > 0) + // { + // acc >>= shift; + // } + // else if (shift < 0) + // { + // acc <<= -shift; + // } - TEST(64, R(RDX), R(RDX));//is this actually worth the branch cost? - FixupBranch zero = J_CC(CC_E); - TEST(16, R(RAX), Imm16(0x3f));//is this actually worth the branch cost? - FixupBranch noShift = J_CC(CC_Z); -//CL gets automatically masked with 0x3f on IA32/AMD64 - //MOVZX(64, 16, RCX, R(RAX)); - MOV(64, R(RCX), R(RAX)); - //AND(16, R(RCX), Imm16(0x3f)); - TEST(16, R(RAX), Imm16(0x40)); - FixupBranch shiftLeft = J_CC(CC_Z); - NEG(16, R(RCX)); - //ADD(16, R(RCX), Imm16(0x40)); - SHL(64, R(RDX), R(RCX)); - FixupBranch exit = J(); - SetJumpTarget(shiftLeft); - SHR(64, R(RDX), R(RCX)); - SetJumpTarget(noShift); - SetJumpTarget(exit); + TEST(64, R(RDX), R(RDX)); // is this actually worth the branch cost? + FixupBranch zero = J_CC(CC_E); + TEST(16, R(RAX), Imm16(0x3f)); // is this actually worth the branch cost? + FixupBranch noShift = J_CC(CC_Z); + // CL gets automatically masked with 0x3f on IA32/AMD64 + // MOVZX(64, 16, RCX, R(RAX)); + MOV(64, R(RCX), R(RAX)); + // AND(16, R(RCX), Imm16(0x3f)); + TEST(16, R(RAX), Imm16(0x40)); + FixupBranch shiftLeft = J_CC(CC_Z); + NEG(16, R(RCX)); + // ADD(16, R(RCX), Imm16(0x40)); + SHL(64, R(RDX), R(RCX)); + FixupBranch exit = J(); + SetJumpTarget(shiftLeft); + SHR(64, R(RDX), R(RCX)); + SetJumpTarget(noShift); + SetJumpTarget(exit); -// dsp_set_long_acc(0, (s64)acc); - set_long_acc(0, RDX); - SetJumpTarget(zero); -// Update_SR_Register64(dsp_get_long_acc(0)); - if (FlagsNeeded()) - { - Update_SR_Register64(RDX); - } + // dsp_set_long_acc(0, (s64)acc); + set_long_acc(0, RDX); + SetJumpTarget(zero); + // Update_SR_Register64(dsp_get_long_acc(0)); + if (FlagsNeeded()) + { + Update_SR_Register64(RDX); + } } // ASRN (fixed parameters) @@ -1386,53 +1390,53 @@ void DSPEmitter::lsrn(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::asrn(const UDSPInstruction opc) { -// s16 shift; -// u16 accm = (u16)dsp_get_acc_m(1); - get_acc_m(1); -// s64 acc = dsp_get_long_acc(0); - get_long_acc(0, RDX); + // s16 shift; + // u16 accm = (u16)dsp_get_acc_m(1); + get_acc_m(1); + // s64 acc = dsp_get_long_acc(0); + get_long_acc(0, RDX); -// if ((accm & 0x3f) == 0) -// shift = 0; -// else if (accm & 0x40) -// shift = -0x40 + (accm & 0x3f); -// else -// shift = accm & 0x3f; + // if ((accm & 0x3f) == 0) + // shift = 0; + // else if (accm & 0x40) + // shift = -0x40 + (accm & 0x3f); + // else + // shift = accm & 0x3f; -// if (shift > 0) -// { -// acc >>= shift; -// } -// else if (shift < 0) -// { -// acc <<= -shift; -// } + // if (shift > 0) + // { + // acc >>= shift; + // } + // else if (shift < 0) + // { + // acc <<= -shift; + // } - TEST(64, R(RDX), R(RDX)); - FixupBranch zero = J_CC(CC_E); - TEST(16, R(RAX), Imm16(0x3f)); - FixupBranch noShift = J_CC(CC_Z); - MOVZX(64, 16, RCX, R(RAX)); - AND(16, R(RCX), Imm16(0x3f)); - TEST(16, R(RAX), Imm16(0x40)); - FixupBranch shiftLeft = J_CC(CC_Z); - NEG(16, R(RCX)); - ADD(16, R(RCX), Imm16(0x40)); - SHL(64, R(RDX), R(RCX)); - FixupBranch exit = J(); - SetJumpTarget(shiftLeft); - SAR(64, R(RDX), R(RCX)); - SetJumpTarget(noShift); - SetJumpTarget(exit); + TEST(64, R(RDX), R(RDX)); + FixupBranch zero = J_CC(CC_E); + TEST(16, R(RAX), Imm16(0x3f)); + FixupBranch noShift = J_CC(CC_Z); + MOVZX(64, 16, RCX, R(RAX)); + AND(16, R(RCX), Imm16(0x3f)); + TEST(16, R(RAX), Imm16(0x40)); + FixupBranch shiftLeft = J_CC(CC_Z); + NEG(16, R(RCX)); + ADD(16, R(RCX), Imm16(0x40)); + SHL(64, R(RDX), R(RCX)); + FixupBranch exit = J(); + SetJumpTarget(shiftLeft); + SAR(64, R(RDX), R(RCX)); + SetJumpTarget(noShift); + SetJumpTarget(exit); -// dsp_set_long_acc(0, acc); -// Update_SR_Register64(dsp_get_long_acc(0)); - set_long_acc(0, RDX); - SetJumpTarget(zero); - if (FlagsNeeded()) - { - Update_SR_Register64(RDX); - } + // dsp_set_long_acc(0, acc); + // Update_SR_Register64(dsp_get_long_acc(0)); + set_long_acc(0, RDX); + SetJumpTarget(zero); + if (FlagsNeeded()) + { + Update_SR_Register64(RDX); + } } // LSRNRX $acD, $axS.h @@ -1443,59 +1447,59 @@ void DSPEmitter::asrn(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::lsrnrx(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; -// s16 shift; -// u16 axh = g_dsp.r.axh[sreg]; - get_ax_h(sreg); -// u64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RDX); -// acc &= 0x000000FFFFFFFFFFULL; - SHL(64, R(RDX), Imm8(24)); - SHR(64, R(RDX), Imm8(24)); + // s16 shift; + // u16 axh = g_dsp.r.axh[sreg]; + get_ax_h(sreg); + // u64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RDX); + // acc &= 0x000000FFFFFFFFFFULL; + SHL(64, R(RDX), Imm8(24)); + SHR(64, R(RDX), Imm8(24)); -// if ((axh & 0x3f) == 0) -// shift = 0; -// else if (axh & 0x40) -// shift = -0x40 + (axh & 0x3f); -// else -// shift = axh & 0x3f; + // if ((axh & 0x3f) == 0) + // shift = 0; + // else if (axh & 0x40) + // shift = -0x40 + (axh & 0x3f); + // else + // shift = axh & 0x3f; -// if (shift > 0) -// { -// acc <<= shift; -// } -// else if (shift < 0) -// { -// acc >>= -shift; -// } + // if (shift > 0) + // { + // acc <<= shift; + // } + // else if (shift < 0) + // { + // acc >>= -shift; + // } - TEST(64, R(RDX), R(RDX)); - FixupBranch zero = J_CC(CC_E); - TEST(16, R(RAX), Imm16(0x3f)); - FixupBranch noShift = J_CC(CC_Z); - MOVZX(64, 16, RCX, R(RAX)); - AND(16, R(RCX), Imm16(0x3f)); - TEST(16, R(RAX), Imm16(0x40)); - FixupBranch shiftLeft = J_CC(CC_Z); - NEG(16, R(RCX)); - ADD(16, R(RCX), Imm16(0x40)); - SHR(64, R(RDX), R(RCX)); - FixupBranch exit = J(); - SetJumpTarget(shiftLeft); - SHL(64, R(RDX), R(RCX)); - SetJumpTarget(noShift); - SetJumpTarget(exit); + TEST(64, R(RDX), R(RDX)); + FixupBranch zero = J_CC(CC_E); + TEST(16, R(RAX), Imm16(0x3f)); + FixupBranch noShift = J_CC(CC_Z); + MOVZX(64, 16, RCX, R(RAX)); + AND(16, R(RCX), Imm16(0x3f)); + TEST(16, R(RAX), Imm16(0x40)); + FixupBranch shiftLeft = J_CC(CC_Z); + NEG(16, R(RCX)); + ADD(16, R(RCX), Imm16(0x40)); + SHR(64, R(RDX), R(RCX)); + FixupBranch exit = J(); + SetJumpTarget(shiftLeft); + SHL(64, R(RDX), R(RCX)); + SetJumpTarget(noShift); + SetJumpTarget(exit); -// dsp_set_long_acc(dreg, (s64)acc); -// Update_SR_Register64(dsp_get_long_acc(dreg)); - set_long_acc(dreg, RDX); - SetJumpTarget(zero); - if (FlagsNeeded()) - { - Update_SR_Register64(RDX); - } + // dsp_set_long_acc(dreg, (s64)acc); + // Update_SR_Register64(dsp_get_long_acc(dreg)); + set_long_acc(dreg, RDX); + SetJumpTarget(zero); + if (FlagsNeeded()) + { + Update_SR_Register64(RDX); + } } // ASRNRX $acD, $axS.h @@ -1506,53 +1510,53 @@ void DSPEmitter::lsrnrx(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::asrnrx(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; -// s16 shift; -// u16 axh = g_dsp.r.axh[sreg]; - get_ax_h(sreg); -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RDX); + // s16 shift; + // u16 axh = g_dsp.r.axh[sreg]; + get_ax_h(sreg); + // s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RDX); -// if ((axh & 0x3f) == 0) -// shift = 0; -// else if (axh & 0x40) -// shift = -0x40 + (axh & 0x3f); -// else -// shift = axh & 0x3f; + // if ((axh & 0x3f) == 0) + // shift = 0; + // else if (axh & 0x40) + // shift = -0x40 + (axh & 0x3f); + // else + // shift = axh & 0x3f; -// if (shift > 0) { -// acc <<= shift; -// } else if (shift < 0) { -// acc >>= -shift; -// } + // if (shift > 0) { + // acc <<= shift; + // } else if (shift < 0) { + // acc >>= -shift; + // } - TEST(64, R(RDX), R(RDX)); - FixupBranch zero = J_CC(CC_E); - TEST(16, R(RAX), Imm16(0x3f)); - FixupBranch noShift = J_CC(CC_Z); - MOVZX(64, 16, RCX, R(RAX)); - AND(16, R(RCX), Imm16(0x3f)); - TEST(16, R(RAX), Imm16(0x40)); - FixupBranch shiftLeft = J_CC(CC_Z); - NEG(16, R(RCX)); - ADD(16, R(RCX), Imm16(0x40)); - SAR(64, R(RDX), R(RCX)); - FixupBranch exit = J(); - SetJumpTarget(shiftLeft); - SHL(64, R(RDX), R(RCX)); - SetJumpTarget(noShift); - SetJumpTarget(exit); + TEST(64, R(RDX), R(RDX)); + FixupBranch zero = J_CC(CC_E); + TEST(16, R(RAX), Imm16(0x3f)); + FixupBranch noShift = J_CC(CC_Z); + MOVZX(64, 16, RCX, R(RAX)); + AND(16, R(RCX), Imm16(0x3f)); + TEST(16, R(RAX), Imm16(0x40)); + FixupBranch shiftLeft = J_CC(CC_Z); + NEG(16, R(RCX)); + ADD(16, R(RCX), Imm16(0x40)); + SAR(64, R(RDX), R(RCX)); + FixupBranch exit = J(); + SetJumpTarget(shiftLeft); + SHL(64, R(RDX), R(RCX)); + SetJumpTarget(noShift); + SetJumpTarget(exit); -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg, RDX); - SetJumpTarget(zero); -// Update_SR_Register64(dsp_get_long_acc(dreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(RDX); - } + // dsp_set_long_acc(dreg, acc); + set_long_acc(dreg, RDX); + SetJumpTarget(zero); + // Update_SR_Register64(dsp_get_long_acc(dreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(RDX); + } } // LSRNR $acD @@ -1563,54 +1567,54 @@ void DSPEmitter::asrnrx(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::lsrnr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; -// s16 shift; -// u16 accm = (u16)dsp_get_acc_m(1 - dreg); - get_acc_m(1 - dreg); -// u64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RDX); -// acc &= 0x000000FFFFFFFFFFULL; - SHL(64, R(RDX), Imm8(24)); - SHR(64, R(RDX), Imm8(24)); + // s16 shift; + // u16 accm = (u16)dsp_get_acc_m(1 - dreg); + get_acc_m(1 - dreg); + // u64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RDX); + // acc &= 0x000000FFFFFFFFFFULL; + SHL(64, R(RDX), Imm8(24)); + SHR(64, R(RDX), Imm8(24)); -// if ((accm & 0x3f) == 0) -// shift = 0; -// else if (accm & 0x40) -// shift = -0x40 + (accm & 0x3f); -// else -// shift = accm & 0x3f; + // if ((accm & 0x3f) == 0) + // shift = 0; + // else if (accm & 0x40) + // shift = -0x40 + (accm & 0x3f); + // else + // shift = accm & 0x3f; -// if (shift > 0) -// acc <<= shift; -// else if (shift < 0) -// acc >>= -shift; + // if (shift > 0) + // acc <<= shift; + // else if (shift < 0) + // acc >>= -shift; - TEST(64, R(RDX), R(RDX)); - FixupBranch zero = J_CC(CC_E); - TEST(16, R(RAX), Imm16(0x3f)); - FixupBranch noShift = J_CC(CC_Z); - MOVZX(64, 16, RCX, R(RAX)); - AND(16, R(RCX), Imm16(0x3f)); - TEST(16, R(RAX), Imm16(0x40)); - FixupBranch shiftLeft = J_CC(CC_Z); - NEG(16, R(RCX)); - ADD(16, R(RCX), Imm16(0x40)); - SHR(64, R(RDX), R(RCX)); - FixupBranch exit = J(); - SetJumpTarget(shiftLeft); - SHL(64, R(RDX), R(RCX)); - SetJumpTarget(noShift); - SetJumpTarget(exit); + TEST(64, R(RDX), R(RDX)); + FixupBranch zero = J_CC(CC_E); + TEST(16, R(RAX), Imm16(0x3f)); + FixupBranch noShift = J_CC(CC_Z); + MOVZX(64, 16, RCX, R(RAX)); + AND(16, R(RCX), Imm16(0x3f)); + TEST(16, R(RAX), Imm16(0x40)); + FixupBranch shiftLeft = J_CC(CC_Z); + NEG(16, R(RCX)); + ADD(16, R(RCX), Imm16(0x40)); + SHR(64, R(RDX), R(RCX)); + FixupBranch exit = J(); + SetJumpTarget(shiftLeft); + SHL(64, R(RDX), R(RCX)); + SetJumpTarget(noShift); + SetJumpTarget(exit); -// dsp_set_long_acc(dreg, (s64)acc); - set_long_acc(dreg, RDX); - SetJumpTarget(zero); -// Update_SR_Register64(dsp_get_long_acc(dreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(RDX); - } + // dsp_set_long_acc(dreg, (s64)acc); + set_long_acc(dreg, RDX); + SetJumpTarget(zero); + // Update_SR_Register64(dsp_get_long_acc(dreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(RDX); + } } // ASRNR $acD @@ -1621,54 +1625,53 @@ void DSPEmitter::lsrnr(const UDSPInstruction opc) // flags out: --xx xx00 void DSPEmitter::asrnr(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; -// s16 shift; -// u16 accm = (u16)dsp_get_acc_m(1 - dreg); - get_acc_m(1 - dreg); -// s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, RDX); + // s16 shift; + // u16 accm = (u16)dsp_get_acc_m(1 - dreg); + get_acc_m(1 - dreg); + // s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg, RDX); -// if ((accm & 0x3f) == 0) -// shift = 0; -// else if (accm & 0x40) -// shift = -0x40 + (accm & 0x3f); -// else -// shift = accm & 0x3f; + // if ((accm & 0x3f) == 0) + // shift = 0; + // else if (accm & 0x40) + // shift = -0x40 + (accm & 0x3f); + // else + // shift = accm & 0x3f; -// if (shift > 0) -// acc <<= shift; -// else if (shift < 0) -// acc >>= -shift; + // if (shift > 0) + // acc <<= shift; + // else if (shift < 0) + // acc >>= -shift; - TEST(64, R(RDX), R(RDX)); - FixupBranch zero = J_CC(CC_E); - TEST(16, R(RAX), Imm16(0x3f)); - FixupBranch noShift = J_CC(CC_Z); - MOVZX(64, 16, RCX, R(RAX)); - AND(16, R(RCX), Imm16(0x3f)); - TEST(16, R(RAX), Imm16(0x40)); - FixupBranch shiftLeft = J_CC(CC_Z); - NEG(16, R(RCX)); - ADD(16, R(RCX), Imm16(0x40)); - SAR(64, R(RDX), R(RCX)); - FixupBranch exit = J(); - SetJumpTarget(shiftLeft); - SHL(64, R(RDX), R(RCX)); - SetJumpTarget(noShift); - SetJumpTarget(exit); + TEST(64, R(RDX), R(RDX)); + FixupBranch zero = J_CC(CC_E); + TEST(16, R(RAX), Imm16(0x3f)); + FixupBranch noShift = J_CC(CC_Z); + MOVZX(64, 16, RCX, R(RAX)); + AND(16, R(RCX), Imm16(0x3f)); + TEST(16, R(RAX), Imm16(0x40)); + FixupBranch shiftLeft = J_CC(CC_Z); + NEG(16, R(RCX)); + ADD(16, R(RCX), Imm16(0x40)); + SAR(64, R(RDX), R(RCX)); + FixupBranch exit = J(); + SetJumpTarget(shiftLeft); + SHL(64, R(RDX), R(RCX)); + SetJumpTarget(noShift); + SetJumpTarget(exit); -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg, RDX); - SetJumpTarget(zero); -// Update_SR_Register64(dsp_get_long_acc(dreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(RDX); - } + // dsp_set_long_acc(dreg, acc); + set_long_acc(dreg, RDX); + SetJumpTarget(zero); + // Update_SR_Register64(dsp_get_long_acc(dreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(RDX); + } } - //} // namespace // diff --git a/Source/Core/Core/DSP/Jit/DSPJitBranch.cpp b/Source/Core/Core/DSP/Jit/DSPJitBranch.cpp index b84fc840d3..1f89e06698 100644 --- a/Source/Core/Core/DSP/Jit/DSPJitBranch.cpp +++ b/Source/Core/Core/DSP/Jit/DSPJitBranch.cpp @@ -9,124 +9,126 @@ using namespace Gen; -template +template static void ReJitConditional(const UDSPInstruction opc, DSPEmitter& emitter) { - u8 cond = opc & 0xf; - if (cond == 0xf) // Always true. - { - jitCode(opc,emitter); - return; - } + u8 cond = opc & 0xf; + if (cond == 0xf) // Always true. + { + jitCode(opc, emitter); + return; + } - emitter.dsp_op_read_reg(DSP_REG_SR, EAX); + emitter.dsp_op_read_reg(DSP_REG_SR, EAX); - switch (cond) - { - case 0x0: // GE - Greater Equal - case 0x1: // L - Less - emitter.LEA(16, EDX, MScaled(EAX, SCALE_4, 0)); - emitter.XOR(16, R(EAX), R(EDX)); - emitter.TEST(16, R(EAX), Imm16(8)); - break; - case 0x2: // G - Greater - case 0x3: // LE - Less Equal - emitter.LEA(16, EDX, MScaled(EAX, SCALE_4, 0)); - emitter.XOR(16, R(EAX), R(EDX)); - emitter.LEA(16, EAX, MScaled(EAX, SCALE_2, 0)); - emitter.OR(16, R(EAX), R(EDX)); - emitter.TEST(16, R(EAX), Imm16(0x10)); - break; - case 0x4: // NZ - Not Zero - case 0x5: // Z - Zero - emitter.TEST(16, R(EAX), Imm16(SR_ARITH_ZERO)); - break; - case 0x6: // NC - Not carry - case 0x7: // C - Carry - emitter.TEST(16, R(EAX), Imm16(SR_CARRY)); - break; - case 0x8: // ? - Not over s32 - case 0x9: // ? - Over s32 - emitter.TEST(16, R(EAX), Imm16(SR_OVER_S32)); - break; - case 0xa: // ? - case 0xb: // ? - emitter.LEA(16, EDX, MScaled(EAX, SCALE_2, 0)); - emitter.OR(16, R(EAX), R(EDX)); - emitter.LEA(16, EDX, MScaled(EDX, SCALE_8, 0)); - emitter.NOT(16, R(EAX)); - emitter.OR(16, R(EAX), R(EDX)); - emitter.TEST(16, R(EAX), Imm16(0x20)); - break; - case 0xc: // LNZ - Logic Not Zero - case 0xd: // LZ - Logic Zero - emitter.TEST(16, R(EAX), Imm16(SR_LOGIC_ZERO)); - break; - case 0xe: // 0 - Overflow - emitter.TEST(16, R(EAX), Imm16(SR_OVERFLOW)); - break; - } - DSPJitRegCache c1(emitter.gpr); - FixupBranch skipCode = cond == 0xe ? emitter.J_CC(CC_E,true) : emitter.J_CC((CCFlags)(CC_NE - (cond & 1)),true); - jitCode(opc,emitter); - emitter.gpr.FlushRegs(c1); - emitter.SetJumpTarget(skipCode); + switch (cond) + { + case 0x0: // GE - Greater Equal + case 0x1: // L - Less + emitter.LEA(16, EDX, MScaled(EAX, SCALE_4, 0)); + emitter.XOR(16, R(EAX), R(EDX)); + emitter.TEST(16, R(EAX), Imm16(8)); + break; + case 0x2: // G - Greater + case 0x3: // LE - Less Equal + emitter.LEA(16, EDX, MScaled(EAX, SCALE_4, 0)); + emitter.XOR(16, R(EAX), R(EDX)); + emitter.LEA(16, EAX, MScaled(EAX, SCALE_2, 0)); + emitter.OR(16, R(EAX), R(EDX)); + emitter.TEST(16, R(EAX), Imm16(0x10)); + break; + case 0x4: // NZ - Not Zero + case 0x5: // Z - Zero + emitter.TEST(16, R(EAX), Imm16(SR_ARITH_ZERO)); + break; + case 0x6: // NC - Not carry + case 0x7: // C - Carry + emitter.TEST(16, R(EAX), Imm16(SR_CARRY)); + break; + case 0x8: // ? - Not over s32 + case 0x9: // ? - Over s32 + emitter.TEST(16, R(EAX), Imm16(SR_OVER_S32)); + break; + case 0xa: // ? + case 0xb: // ? + emitter.LEA(16, EDX, MScaled(EAX, SCALE_2, 0)); + emitter.OR(16, R(EAX), R(EDX)); + emitter.LEA(16, EDX, MScaled(EDX, SCALE_8, 0)); + emitter.NOT(16, R(EAX)); + emitter.OR(16, R(EAX), R(EDX)); + emitter.TEST(16, R(EAX), Imm16(0x20)); + break; + case 0xc: // LNZ - Logic Not Zero + case 0xd: // LZ - Logic Zero + emitter.TEST(16, R(EAX), Imm16(SR_LOGIC_ZERO)); + break; + case 0xe: // 0 - Overflow + emitter.TEST(16, R(EAX), Imm16(SR_OVERFLOW)); + break; + } + DSPJitRegCache c1(emitter.gpr); + FixupBranch skipCode = + cond == 0xe ? emitter.J_CC(CC_E, true) : emitter.J_CC((CCFlags)(CC_NE - (cond & 1)), true); + jitCode(opc, emitter); + emitter.gpr.FlushRegs(c1); + emitter.SetJumpTarget(skipCode); } static void WriteBranchExit(DSPEmitter& emitter) { - DSPJitRegCache c(emitter.gpr); - emitter.gpr.SaveRegs(); - if (DSPAnalyzer::code_flags[emitter.startAddr] & DSPAnalyzer::CODE_IDLE_SKIP) - { - emitter.MOV(16, R(EAX), Imm16(0x1000)); - } - else - { - emitter.MOV(16, R(EAX), Imm16(emitter.blockSize[emitter.startAddr])); - } - emitter.JMP(emitter.returnDispatcher, true); - emitter.gpr.LoadRegs(false); - emitter.gpr.FlushRegs(c,false); + DSPJitRegCache c(emitter.gpr); + emitter.gpr.SaveRegs(); + if (DSPAnalyzer::code_flags[emitter.startAddr] & DSPAnalyzer::CODE_IDLE_SKIP) + { + emitter.MOV(16, R(EAX), Imm16(0x1000)); + } + else + { + emitter.MOV(16, R(EAX), Imm16(emitter.blockSize[emitter.startAddr])); + } + emitter.JMP(emitter.returnDispatcher, true); + emitter.gpr.LoadRegs(false); + emitter.gpr.FlushRegs(c, false); } static void WriteBlockLink(DSPEmitter& emitter, u16 dest) { - // Jump directly to the called block if it has already been compiled. - if (!(dest >= emitter.startAddr && dest <= emitter.compilePC)) - { - if (emitter.blockLinks[dest] != nullptr ) - { - emitter.gpr.FlushRegs(); - // Check if we have enough cycles to execute the next block - emitter.MOV(16, R(ECX), M(&g_cycles_left)); - emitter.CMP(16, R(ECX), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); - FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); + // Jump directly to the called block if it has already been compiled. + if (!(dest >= emitter.startAddr && dest <= emitter.compilePC)) + { + if (emitter.blockLinks[dest] != nullptr) + { + emitter.gpr.FlushRegs(); + // Check if we have enough cycles to execute the next block + emitter.MOV(16, R(ECX), M(&g_cycles_left)); + emitter.CMP(16, R(ECX), + Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); + FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); - emitter.SUB(16, R(ECX), Imm16(emitter.blockSize[emitter.startAddr])); - emitter.MOV(16, M(&g_cycles_left), R(ECX)); - emitter.JMP(emitter.blockLinks[dest], true); - emitter.SetJumpTarget(notEnoughCycles); - } - else - { - // The destination has not been compiled yet. Add it to the list - // of blocks that this block is waiting on. - emitter.unresolvedJumps[emitter.startAddr].push_back(dest); - } - } + emitter.SUB(16, R(ECX), Imm16(emitter.blockSize[emitter.startAddr])); + emitter.MOV(16, M(&g_cycles_left), R(ECX)); + emitter.JMP(emitter.blockLinks[dest], true); + emitter.SetJumpTarget(notEnoughCycles); + } + else + { + // The destination has not been compiled yet. Add it to the list + // of blocks that this block is waiting on. + emitter.unresolvedJumps[emitter.startAddr].push_back(dest); + } + } } static void r_jcc(const UDSPInstruction opc, DSPEmitter& emitter) { - u16 dest = dsp_imem_read(emitter.compilePC + 1); - const DSPOPCTemplate *opcode = GetOpTemplate(opc); + u16 dest = dsp_imem_read(emitter.compilePC + 1); + const DSPOPCTemplate* opcode = GetOpTemplate(opc); - // If the block is unconditional, attempt to link block - if (opcode->uncond_branch) - WriteBlockLink(emitter, dest); - emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest)); - WriteBranchExit(emitter); + // If the block is unconditional, attempt to link block + if (opcode->uncond_branch) + WriteBlockLink(emitter, dest); + emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest)); + WriteBranchExit(emitter); } // Generic jmp implementation // Jcc addressA @@ -137,18 +139,18 @@ static void r_jcc(const UDSPInstruction opc, DSPEmitter& emitter) // NOTE: Cannot use FallBackToInterpreter(opc) here because of the need to write branch exit void DSPEmitter::jcc(const UDSPInstruction opc) { - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); - ReJitConditional(opc, *this); + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); + ReJitConditional(opc, *this); } static void r_jmprcc(const UDSPInstruction opc, DSPEmitter& emitter) { - u8 reg = (opc >> 5) & 0x7; - //reg can only be DSP_REG_ARx and DSP_REG_IXx now, - //no need to handle DSP_REG_STx. - emitter.dsp_op_read_reg(reg, RAX, NONE); - emitter.MOV(16, M(&g_dsp.pc), R(EAX)); - WriteBranchExit(emitter); + u8 reg = (opc >> 5) & 0x7; + // reg can only be DSP_REG_ARx and DSP_REG_IXx now, + // no need to handle DSP_REG_STx. + emitter.dsp_op_read_reg(reg, RAX, NONE); + emitter.MOV(16, M(&g_dsp.pc), R(EAX)); + WriteBranchExit(emitter); } // Generic jmpr implementation // JMPcc $R @@ -157,22 +159,22 @@ static void r_jmprcc(const UDSPInstruction opc, DSPEmitter& emitter) // NOTE: Cannot use FallBackToInterpreter(opc) here because of the need to write branch exit void DSPEmitter::jmprcc(const UDSPInstruction opc) { - MOV(16, M(&g_dsp.pc), Imm16(compilePC + 1)); - ReJitConditional(opc, *this); + MOV(16, M(&g_dsp.pc), Imm16(compilePC + 1)); + ReJitConditional(opc, *this); } static void r_call(const UDSPInstruction opc, DSPEmitter& emitter) { - emitter.MOV(16, R(DX), Imm16(emitter.compilePC + 2)); - emitter.dsp_reg_store_stack(DSP_STACK_C); - u16 dest = dsp_imem_read(emitter.compilePC + 1); - const DSPOPCTemplate *opcode = GetOpTemplate(opc); + emitter.MOV(16, R(DX), Imm16(emitter.compilePC + 2)); + emitter.dsp_reg_store_stack(DSP_STACK_C); + u16 dest = dsp_imem_read(emitter.compilePC + 1); + const DSPOPCTemplate* opcode = GetOpTemplate(opc); - // If the block is unconditional, attempt to link block - if (opcode->uncond_branch) - WriteBlockLink(emitter, dest); - emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest)); - WriteBranchExit(emitter); + // If the block is unconditional, attempt to link block + if (opcode->uncond_branch) + WriteBlockLink(emitter, dest); + emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest)); + WriteBranchExit(emitter); } // Generic call implementation // CALLcc addressA @@ -184,18 +186,18 @@ static void r_call(const UDSPInstruction opc, DSPEmitter& emitter) // NOTE: Cannot use FallBackToInterpreter(opc) here because of the need to write branch exit void DSPEmitter::call(const UDSPInstruction opc) { - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); - ReJitConditional(opc, *this); + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); + ReJitConditional(opc, *this); } static void r_callr(const UDSPInstruction opc, DSPEmitter& emitter) { - u8 reg = (opc >> 5) & 0x7; - emitter.MOV(16, R(DX), Imm16(emitter.compilePC + 1)); - emitter.dsp_reg_store_stack(DSP_STACK_C); - emitter.dsp_op_read_reg(reg, RAX, NONE); - emitter.MOV(16, M(&g_dsp.pc), R(EAX)); - WriteBranchExit(emitter); + u8 reg = (opc >> 5) & 0x7; + emitter.MOV(16, R(DX), Imm16(emitter.compilePC + 1)); + emitter.dsp_reg_store_stack(DSP_STACK_C); + emitter.dsp_op_read_reg(reg, RAX, NONE); + emitter.MOV(16, M(&g_dsp.pc), R(EAX)); + WriteBranchExit(emitter); } // Generic callr implementation // CALLRcc $R @@ -206,13 +208,13 @@ static void r_callr(const UDSPInstruction opc, DSPEmitter& emitter) // NOTE: Cannot use FallBackToInterpreter(opc) here because of the need to write branch exit void DSPEmitter::callr(const UDSPInstruction opc) { - MOV(16, M(&g_dsp.pc), Imm16(compilePC + 1)); - ReJitConditional(opc, *this); + MOV(16, M(&g_dsp.pc), Imm16(compilePC + 1)); + ReJitConditional(opc, *this); } static void r_ifcc(const UDSPInstruction opc, DSPEmitter& emitter) { - emitter.MOV(16, M(&g_dsp.pc), Imm16(emitter.compilePC + 1)); + emitter.MOV(16, M(&g_dsp.pc), Imm16(emitter.compilePC + 1)); } // Generic if implementation // IFcc @@ -221,16 +223,16 @@ static void r_ifcc(const UDSPInstruction opc, DSPEmitter& emitter) // NOTE: Cannot use FallBackToInterpreter(opc) here because of the need to write branch exit void DSPEmitter::ifcc(const UDSPInstruction opc) { - MOV(16, M(&g_dsp.pc), Imm16((compilePC + 1) + opTable[dsp_imem_read(compilePC + 1)]->size)); - ReJitConditional(opc, *this); - WriteBranchExit(*this); + MOV(16, M(&g_dsp.pc), Imm16((compilePC + 1) + opTable[dsp_imem_read(compilePC + 1)]->size)); + ReJitConditional(opc, *this); + WriteBranchExit(*this); } static void r_ret(const UDSPInstruction opc, DSPEmitter& emitter) { - emitter.dsp_reg_load_stack(DSP_STACK_C); - emitter.MOV(16, M(&g_dsp.pc), R(DX)); - WriteBranchExit(emitter); + emitter.dsp_reg_load_stack(DSP_STACK_C); + emitter.MOV(16, M(&g_dsp.pc), R(DX)); + WriteBranchExit(emitter); } // Generic ret implementation @@ -241,8 +243,8 @@ static void r_ret(const UDSPInstruction opc, DSPEmitter& emitter) // NOTE: Cannot use FallBackToInterpreter(opc) here because of the need to write branch exit void DSPEmitter::ret(const UDSPInstruction opc) { - MOV(16, M(&g_dsp.pc), Imm16(compilePC + 1)); - ReJitConditional(opc, *this); + MOV(16, M(&g_dsp.pc), Imm16(compilePC + 1)); + ReJitConditional(opc, *this); } // RTI @@ -252,12 +254,12 @@ void DSPEmitter::ret(const UDSPInstruction opc) // location. void DSPEmitter::rti(const UDSPInstruction opc) { -// g_dsp.r[DSP_REG_SR] = dsp_reg_load_stack(DSP_STACK_D); - dsp_reg_load_stack(DSP_STACK_D); - dsp_op_write_reg(DSP_REG_SR, RDX); -// g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); - dsp_reg_load_stack(DSP_STACK_C); - MOV(16, M(&g_dsp.pc), R(DX)); + // g_dsp.r[DSP_REG_SR] = dsp_reg_load_stack(DSP_STACK_D); + dsp_reg_load_stack(DSP_STACK_D); + dsp_op_write_reg(DSP_REG_SR, RDX); + // g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); + dsp_reg_load_stack(DSP_STACK_C); + MOV(16, M(&g_dsp.pc), R(DX)); } // HALT @@ -265,10 +267,10 @@ void DSPEmitter::rti(const UDSPInstruction opc) // Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR. void DSPEmitter::halt(const UDSPInstruction opc) { - OR(16, M(&g_dsp.cr), Imm16(4)); - // g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); - dsp_reg_load_stack(DSP_STACK_C); - MOV(16, M(&g_dsp.pc), R(DX)); + OR(16, M(&g_dsp.cr), Imm16(4)); + // g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); + dsp_reg_load_stack(DSP_STACK_C); + MOV(16, M(&g_dsp.pc), R(DX)); } // LOOP handling: Loop stack is used to control execution of repeated blocks of @@ -279,32 +281,32 @@ void DSPEmitter::halt(const UDSPInstruction opc) // continues at next opcode. void DSPEmitter::HandleLoop() { - MOVZX(32, 16, EAX, M(&g_dsp.r.st[2])); - MOVZX(32, 16, ECX, M(&g_dsp.r.st[3])); + MOVZX(32, 16, EAX, M(&g_dsp.r.st[2])); + MOVZX(32, 16, ECX, M(&g_dsp.r.st[3])); - TEST(32, R(RCX), R(RCX)); - FixupBranch rLoopCntG = J_CC(CC_LE, true); - CMP(16, R(RAX), Imm16(compilePC - 1)); - FixupBranch rLoopAddrG = J_CC(CC_NE, true); + TEST(32, R(RCX), R(RCX)); + FixupBranch rLoopCntG = J_CC(CC_LE, true); + CMP(16, R(RAX), Imm16(compilePC - 1)); + FixupBranch rLoopAddrG = J_CC(CC_NE, true); - SUB(16, M(&(g_dsp.r.st[3])), Imm16(1)); - CMP(16, M(&(g_dsp.r.st[3])), Imm16(0)); + SUB(16, M(&(g_dsp.r.st[3])), Imm16(1)); + CMP(16, M(&(g_dsp.r.st[3])), Imm16(0)); - FixupBranch loadStack = J_CC(CC_LE, true); - MOVZX(32, 16, ECX, M(&(g_dsp.r.st[0]))); - MOV(16, M(&g_dsp.pc), R(RCX)); - FixupBranch loopUpdated = J(true); + FixupBranch loadStack = J_CC(CC_LE, true); + MOVZX(32, 16, ECX, M(&(g_dsp.r.st[0]))); + MOV(16, M(&g_dsp.pc), R(RCX)); + FixupBranch loopUpdated = J(true); - SetJumpTarget(loadStack); - DSPJitRegCache c(gpr); - dsp_reg_load_stack(0); - dsp_reg_load_stack(2); - dsp_reg_load_stack(3); - gpr.FlushRegs(c); + SetJumpTarget(loadStack); + DSPJitRegCache c(gpr); + dsp_reg_load_stack(0); + dsp_reg_load_stack(2); + dsp_reg_load_stack(3); + gpr.FlushRegs(c); - SetJumpTarget(loopUpdated); - SetJumpTarget(rLoopAddrG); - SetJumpTarget(rLoopCntG); + SetJumpTarget(loopUpdated); + SetJumpTarget(rLoopAddrG); + SetJumpTarget(rLoopCntG); } // LOOP $R @@ -317,30 +319,30 @@ void DSPEmitter::HandleLoop() // The looping hardware takes care of the rest. void DSPEmitter::loop(const UDSPInstruction opc) { - u16 reg = opc & 0x1f; -// u16 cnt = g_dsp.r[reg]; -//todo: check if we can use normal variant here - dsp_op_read_reg_dont_saturate(reg, RDX, ZERO); - u16 loop_pc = compilePC + 1; + u16 reg = opc & 0x1f; + // u16 cnt = g_dsp.r[reg]; + // todo: check if we can use normal variant here + dsp_op_read_reg_dont_saturate(reg, RDX, ZERO); + u16 loop_pc = compilePC + 1; - TEST(16, R(EDX), R(EDX)); - DSPJitRegCache c(gpr); - FixupBranch cnt = J_CC(CC_Z, true); - dsp_reg_store_stack(3); - MOV(16, R(RDX), Imm16(compilePC + 1)); - dsp_reg_store_stack(0); - MOV(16, R(RDX), Imm16(loop_pc)); - dsp_reg_store_stack(2); - gpr.FlushRegs(c); - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1)); - FixupBranch exit = J(true); + TEST(16, R(EDX), R(EDX)); + DSPJitRegCache c(gpr); + FixupBranch cnt = J_CC(CC_Z, true); + dsp_reg_store_stack(3); + MOV(16, R(RDX), Imm16(compilePC + 1)); + dsp_reg_store_stack(0); + MOV(16, R(RDX), Imm16(loop_pc)); + dsp_reg_store_stack(2); + gpr.FlushRegs(c); + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1)); + FixupBranch exit = J(true); - SetJumpTarget(cnt); - // dsp_skip_inst(); - MOV(16, M(&g_dsp.pc), Imm16(loop_pc + opTable[dsp_imem_read(loop_pc)]->size)); - WriteBranchExit(*this); - gpr.FlushRegs(c,false); - SetJumpTarget(exit); + SetJumpTarget(cnt); + // dsp_skip_inst(); + MOV(16, M(&g_dsp.pc), Imm16(loop_pc + opTable[dsp_imem_read(loop_pc)]->size)); + WriteBranchExit(*this); + gpr.FlushRegs(c, false); + SetJumpTarget(exit); } // LOOPI #I @@ -353,29 +355,28 @@ void DSPEmitter::loop(const UDSPInstruction opc) // The looping hardware takes care of the rest. void DSPEmitter::loopi(const UDSPInstruction opc) { - u16 cnt = opc & 0xff; - u16 loop_pc = compilePC + 1; + u16 cnt = opc & 0xff; + u16 loop_pc = compilePC + 1; - if (cnt) - { - MOV(16, R(RDX), Imm16(compilePC + 1)); - dsp_reg_store_stack(0); - MOV(16, R(RDX), Imm16(loop_pc)); - dsp_reg_store_stack(2); - MOV(16, R(RDX), Imm16(cnt)); - dsp_reg_store_stack(3); + if (cnt) + { + MOV(16, R(RDX), Imm16(compilePC + 1)); + dsp_reg_store_stack(0); + MOV(16, R(RDX), Imm16(loop_pc)); + dsp_reg_store_stack(2); + MOV(16, R(RDX), Imm16(cnt)); + dsp_reg_store_stack(3); - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1)); - } - else - { -// dsp_skip_inst(); - MOV(16, M(&g_dsp.pc), Imm16(loop_pc + opTable[dsp_imem_read(loop_pc)]->size)); - WriteBranchExit(*this); - } + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1)); + } + else + { + // dsp_skip_inst(); + MOV(16, M(&g_dsp.pc), Imm16(loop_pc + opTable[dsp_imem_read(loop_pc)]->size)); + WriteBranchExit(*this); + } } - // BLOOP $R, addrA // 0000 0000 011r rrrr // aaaa aaaa aaaa aaaa @@ -387,31 +388,31 @@ void DSPEmitter::loopi(const UDSPInstruction opc) // Up to 4 nested loops are allowed. void DSPEmitter::bloop(const UDSPInstruction opc) { - u16 reg = opc & 0x1f; -// u16 cnt = g_dsp.r[reg]; -//todo: check if we can use normal variant here - dsp_op_read_reg_dont_saturate(reg, RDX, ZERO); - u16 loop_pc = dsp_imem_read(compilePC + 1); + u16 reg = opc & 0x1f; + // u16 cnt = g_dsp.r[reg]; + // todo: check if we can use normal variant here + dsp_op_read_reg_dont_saturate(reg, RDX, ZERO); + u16 loop_pc = dsp_imem_read(compilePC + 1); - TEST(16, R(EDX), R(EDX)); - DSPJitRegCache c(gpr); - FixupBranch cnt = J_CC(CC_Z, true); - dsp_reg_store_stack(3); - MOV(16, R(RDX), Imm16(compilePC + 2)); - dsp_reg_store_stack(0); - MOV(16, R(RDX), Imm16(loop_pc)); - dsp_reg_store_stack(2); - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); - gpr.FlushRegs(c,true); - FixupBranch exit = J(true); + TEST(16, R(EDX), R(EDX)); + DSPJitRegCache c(gpr); + FixupBranch cnt = J_CC(CC_Z, true); + dsp_reg_store_stack(3); + MOV(16, R(RDX), Imm16(compilePC + 2)); + dsp_reg_store_stack(0); + MOV(16, R(RDX), Imm16(loop_pc)); + dsp_reg_store_stack(2); + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); + gpr.FlushRegs(c, true); + FixupBranch exit = J(true); - SetJumpTarget(cnt); - // g_dsp.pc = loop_pc; - // dsp_skip_inst(); - MOV(16, M(&g_dsp.pc), Imm16(loop_pc + opTable[dsp_imem_read(loop_pc)]->size)); - WriteBranchExit(*this); - gpr.FlushRegs(c,false); - SetJumpTarget(exit); + SetJumpTarget(cnt); + // g_dsp.pc = loop_pc; + // dsp_skip_inst(); + MOV(16, M(&g_dsp.pc), Imm16(loop_pc + opTable[dsp_imem_read(loop_pc)]->size)); + WriteBranchExit(*this); + gpr.FlushRegs(c, false); + SetJumpTarget(exit); } // BLOOPI #I, addrA @@ -425,26 +426,26 @@ void DSPEmitter::bloop(const UDSPInstruction opc) // nested loops are allowed. void DSPEmitter::bloopi(const UDSPInstruction opc) { - u16 cnt = opc & 0xff; -// u16 loop_pc = dsp_fetch_code(); - u16 loop_pc = dsp_imem_read(compilePC + 1); + u16 cnt = opc & 0xff; + // u16 loop_pc = dsp_fetch_code(); + u16 loop_pc = dsp_imem_read(compilePC + 1); - if (cnt) - { - MOV(16, R(RDX), Imm16(compilePC + 2)); - dsp_reg_store_stack(0); - MOV(16, R(RDX), Imm16(loop_pc)); - dsp_reg_store_stack(2); - MOV(16, R(RDX), Imm16(cnt)); - dsp_reg_store_stack(3); + if (cnt) + { + MOV(16, R(RDX), Imm16(compilePC + 2)); + dsp_reg_store_stack(0); + MOV(16, R(RDX), Imm16(loop_pc)); + dsp_reg_store_stack(2); + MOV(16, R(RDX), Imm16(cnt)); + dsp_reg_store_stack(3); - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); - } - else - { -// g_dsp.pc = loop_pc; -// dsp_skip_inst(); - MOV(16, M(&g_dsp.pc), Imm16(loop_pc + opTable[dsp_imem_read(loop_pc)]->size)); - WriteBranchExit(*this); - } + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); + } + else + { + // g_dsp.pc = loop_pc; + // dsp_skip_inst(); + MOV(16, M(&g_dsp.pc), Imm16(loop_pc + opTable[dsp_imem_read(loop_pc)]->size)); + WriteBranchExit(*this); + } } diff --git a/Source/Core/Core/DSP/Jit/DSPJitCCUtil.cpp b/Source/Core/Core/DSP/Jit/DSPJitCCUtil.cpp index d702fdbbd2..876ffd638e 100644 --- a/Source/Core/Core/DSP/Jit/DSPJitCCUtil.cpp +++ b/Source/Core/Core/DSP/Jit/DSPJitCCUtil.cpp @@ -5,7 +5,7 @@ // Additional copyrights go to Duddie and Tratax (c) 2004 #include "Core/DSP/DSPEmitter.h" -#include "Core/DSP/DSPIntUtil.h" // Helper functions +#include "Core/DSP/DSPIntUtil.h" // Helper functions using namespace Gen; @@ -13,55 +13,55 @@ using namespace Gen; // Clobbers RDX void DSPEmitter::Update_SR_Register(Gen::X64Reg val) { - OpArg sr_reg; - gpr.GetReg(DSP_REG_SR,sr_reg); - // // 0x04 - // if (_Value == 0) g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO; - TEST(64, R(val), R(val)); - FixupBranch notZero = J_CC(CC_NZ); - OR(16, sr_reg, Imm16(SR_ARITH_ZERO | SR_TOP2BITS)); - FixupBranch end = J(); - SetJumpTarget(notZero); + OpArg sr_reg; + gpr.GetReg(DSP_REG_SR, sr_reg); + // // 0x04 + // if (_Value == 0) g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO; + TEST(64, R(val), R(val)); + FixupBranch notZero = J_CC(CC_NZ); + OR(16, sr_reg, Imm16(SR_ARITH_ZERO | SR_TOP2BITS)); + FixupBranch end = J(); + SetJumpTarget(notZero); - // // 0x08 - // if (_Value < 0) g_dsp.r[DSP_REG_SR] |= SR_SIGN; - FixupBranch greaterThanEqual = J_CC(CC_GE); - OR(16, sr_reg, Imm16(SR_SIGN)); - SetJumpTarget(greaterThanEqual); + // // 0x08 + // if (_Value < 0) g_dsp.r[DSP_REG_SR] |= SR_SIGN; + FixupBranch greaterThanEqual = J_CC(CC_GE); + OR(16, sr_reg, Imm16(SR_SIGN)); + SetJumpTarget(greaterThanEqual); - // // 0x10 - // if (_Value != (s32)_Value) g_dsp.r[DSP_REG_SR] |= SR_OVER_S32; - MOVSX(64, 32, RDX, R(val)); - CMP(64, R(RDX), R(val)); - FixupBranch noOverS32 = J_CC(CC_E); - OR(16, sr_reg, Imm16(SR_OVER_S32)); - SetJumpTarget(noOverS32); + // // 0x10 + // if (_Value != (s32)_Value) g_dsp.r[DSP_REG_SR] |= SR_OVER_S32; + MOVSX(64, 32, RDX, R(val)); + CMP(64, R(RDX), R(val)); + FixupBranch noOverS32 = J_CC(CC_E); + OR(16, sr_reg, Imm16(SR_OVER_S32)); + SetJumpTarget(noOverS32); - // // 0x20 - Checks if top bits of m are equal - // if (((_Value & 0xc0000000) == 0) || ((_Value & 0xc0000000) == 0xc0000000)) - MOV(32, R(RDX), Imm32(0xc0000000)); - AND(32, R(val), R(RDX)); - FixupBranch zeroC = J_CC(CC_Z); - CMP(32, R(val), R(RDX)); - FixupBranch cC = J_CC(CC_NE); - SetJumpTarget(zeroC); - // g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS; - OR(16, sr_reg, Imm16(SR_TOP2BITS)); - SetJumpTarget(cC); - SetJumpTarget(end); - gpr.PutReg(DSP_REG_SR); + // // 0x20 - Checks if top bits of m are equal + // if (((_Value & 0xc0000000) == 0) || ((_Value & 0xc0000000) == 0xc0000000)) + MOV(32, R(RDX), Imm32(0xc0000000)); + AND(32, R(val), R(RDX)); + FixupBranch zeroC = J_CC(CC_Z); + CMP(32, R(val), R(RDX)); + FixupBranch cC = J_CC(CC_NE); + SetJumpTarget(zeroC); + // g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS; + OR(16, sr_reg, Imm16(SR_TOP2BITS)); + SetJumpTarget(cC); + SetJumpTarget(end); + gpr.PutReg(DSP_REG_SR); } // In: RAX: s64 _Value // Clobbers RDX void DSPEmitter::Update_SR_Register64(Gen::X64Reg val) { -// g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; - OpArg sr_reg; - gpr.GetReg(DSP_REG_SR,sr_reg); - AND(16, sr_reg, Imm16(~SR_CMP_MASK)); - gpr.PutReg(DSP_REG_SR); - Update_SR_Register(val); + // g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; + OpArg sr_reg; + gpr.GetReg(DSP_REG_SR, sr_reg); + AND(16, sr_reg, Imm16(~SR_CMP_MASK)); + gpr.PutReg(DSP_REG_SR); + Update_SR_Register(val); } // In: (val): s64 _Value @@ -69,98 +69,98 @@ void DSPEmitter::Update_SR_Register64(Gen::X64Reg val) // Clobbers RDX void DSPEmitter::Update_SR_Register64_Carry(X64Reg val, X64Reg carry_ovfl, bool carry_eq) { - OpArg sr_reg; - gpr.GetReg(DSP_REG_SR,sr_reg); - // g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; - AND(16, sr_reg, Imm16(~SR_CMP_MASK)); + OpArg sr_reg; + gpr.GetReg(DSP_REG_SR, sr_reg); + // g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; + AND(16, sr_reg, Imm16(~SR_CMP_MASK)); - CMP(64, R(carry_ovfl), R(val)); + CMP(64, R(carry_ovfl), R(val)); - // 0x01 - // g_dsp.r[DSP_REG_SR] |= SR_CARRY; - // Carry = (acc>res) - // Carry2 = (acc>=res) - FixupBranch noCarry = J_CC(carry_eq ? CC_B : CC_BE); - OR(16, sr_reg, Imm16(SR_CARRY)); - SetJumpTarget(noCarry); + // 0x01 + // g_dsp.r[DSP_REG_SR] |= SR_CARRY; + // Carry = (acc>res) + // Carry2 = (acc>=res) + FixupBranch noCarry = J_CC(carry_eq ? CC_B : CC_BE); + OR(16, sr_reg, Imm16(SR_CARRY)); + SetJumpTarget(noCarry); - // 0x02 and 0x80 - // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW; - // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_STICKY; - // Overflow = ((acc ^ res) & (ax ^ res)) < 0 - XOR(64, R(carry_ovfl), R(val)); - XOR(64, R(RDX), R(val)); - TEST(64, R(carry_ovfl), R(RDX)); - FixupBranch noOverflow = J_CC(CC_GE); - OR(16, sr_reg, Imm16(SR_OVERFLOW | SR_OVERFLOW_STICKY)); - SetJumpTarget(noOverflow); + // 0x02 and 0x80 + // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW; + // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_STICKY; + // Overflow = ((acc ^ res) & (ax ^ res)) < 0 + XOR(64, R(carry_ovfl), R(val)); + XOR(64, R(RDX), R(val)); + TEST(64, R(carry_ovfl), R(RDX)); + FixupBranch noOverflow = J_CC(CC_GE); + OR(16, sr_reg, Imm16(SR_OVERFLOW | SR_OVERFLOW_STICKY)); + SetJumpTarget(noOverflow); - gpr.PutReg(DSP_REG_SR); - if (carry_eq) - { - Update_SR_Register(); - } - else - { - Update_SR_Register(val); - } + gpr.PutReg(DSP_REG_SR); + if (carry_eq) + { + Update_SR_Register(); + } + else + { + Update_SR_Register(val); + } } // In: RAX: s64 _Value void DSPEmitter::Update_SR_Register16(X64Reg val) { - OpArg sr_reg; - gpr.GetReg(DSP_REG_SR,sr_reg); - AND(16, sr_reg, Imm16(~SR_CMP_MASK)); + OpArg sr_reg; + gpr.GetReg(DSP_REG_SR, sr_reg); + AND(16, sr_reg, Imm16(~SR_CMP_MASK)); - // // 0x04 - // if (_Value == 0) g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO; - TEST(64, R(val), R(val)); - FixupBranch notZero = J_CC(CC_NZ); - OR(16, sr_reg, Imm16(SR_ARITH_ZERO | SR_TOP2BITS)); - FixupBranch end = J(); - SetJumpTarget(notZero); + // // 0x04 + // if (_Value == 0) g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO; + TEST(64, R(val), R(val)); + FixupBranch notZero = J_CC(CC_NZ); + OR(16, sr_reg, Imm16(SR_ARITH_ZERO | SR_TOP2BITS)); + FixupBranch end = J(); + SetJumpTarget(notZero); - // // 0x08 - // if (_Value < 0) g_dsp.r[DSP_REG_SR] |= SR_SIGN; - FixupBranch greaterThanEqual = J_CC(CC_GE); - OR(16, sr_reg, Imm16(SR_SIGN)); - SetJumpTarget(greaterThanEqual); + // // 0x08 + // if (_Value < 0) g_dsp.r[DSP_REG_SR] |= SR_SIGN; + FixupBranch greaterThanEqual = J_CC(CC_GE); + OR(16, sr_reg, Imm16(SR_SIGN)); + SetJumpTarget(greaterThanEqual); - // // 0x20 - Checks if top bits of m are equal - // if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) - SHR(16, R(val), Imm8(14)); - TEST(16, R(val), R(val)); - FixupBranch isZero = J_CC(CC_Z); - CMP(16, R(val), Imm16(3)); - FixupBranch notThree = J_CC(CC_NE); - SetJumpTarget(isZero); - // g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS; - OR(16, sr_reg, Imm16(SR_TOP2BITS)); - SetJumpTarget(notThree); - SetJumpTarget(end); - gpr.PutReg(DSP_REG_SR); + // // 0x20 - Checks if top bits of m are equal + // if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) + SHR(16, R(val), Imm8(14)); + TEST(16, R(val), R(val)); + FixupBranch isZero = J_CC(CC_Z); + CMP(16, R(val), Imm16(3)); + FixupBranch notThree = J_CC(CC_NE); + SetJumpTarget(isZero); + // g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS; + OR(16, sr_reg, Imm16(SR_TOP2BITS)); + SetJumpTarget(notThree); + SetJumpTarget(end); + gpr.PutReg(DSP_REG_SR); } // In: RAX: s64 _Value // Clobbers RCX void DSPEmitter::Update_SR_Register16_OverS32(Gen::X64Reg val) { - OpArg sr_reg; - gpr.GetReg(DSP_REG_SR,sr_reg); - AND(16, sr_reg, Imm16(~SR_CMP_MASK)); + OpArg sr_reg; + gpr.GetReg(DSP_REG_SR, sr_reg); + AND(16, sr_reg, Imm16(~SR_CMP_MASK)); - // // 0x10 - // if (_Value != (s32)_Value) g_dsp.r[DSP_REG_SR] |= SR_OVER_S32; - MOVSX(64, 32, RCX, R(val)); - CMP(64, R(RCX), R(val)); - FixupBranch noOverS32 = J_CC(CC_E); - OR(16, sr_reg, Imm16(SR_OVER_S32)); - SetJumpTarget(noOverS32); + // // 0x10 + // if (_Value != (s32)_Value) g_dsp.r[DSP_REG_SR] |= SR_OVER_S32; + MOVSX(64, 32, RCX, R(val)); + CMP(64, R(RCX), R(val)); + FixupBranch noOverS32 = J_CC(CC_E); + OR(16, sr_reg, Imm16(SR_OVER_S32)); + SetJumpTarget(noOverS32); - gpr.PutReg(DSP_REG_SR); - // // 0x20 - Checks if top bits of m are equal - // if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) - //AND(32, R(val), Imm32(0xc0000000)); - Update_SR_Register16(val); + gpr.PutReg(DSP_REG_SR); + // // 0x20 - Checks if top bits of m are equal + // if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) + // AND(32, R(val), Imm32(0xc0000000)); + Update_SR_Register16(val); } diff --git a/Source/Core/Core/DSP/Jit/DSPJitExtOps.cpp b/Source/Core/Core/DSP/Jit/DSPJitExtOps.cpp index 7d40b7847e..690960685c 100644 --- a/Source/Core/Core/DSP/Jit/DSPJitExtOps.cpp +++ b/Source/Core/Core/DSP/Jit/DSPJitExtOps.cpp @@ -28,7 +28,7 @@ using namespace Gen; // Decrement addressing register $arR. void DSPEmitter::dr(const UDSPInstruction opc) { - decrement_addr_reg(opc & 0x3); + decrement_addr_reg(opc & 0x3); } // IR $arR @@ -36,7 +36,7 @@ void DSPEmitter::dr(const UDSPInstruction opc) // Increment addressing register $arR. void DSPEmitter::ir(const UDSPInstruction opc) { - increment_addr_reg(opc & 0x3); + increment_addr_reg(opc & 0x3); } // NR $arR @@ -44,9 +44,9 @@ void DSPEmitter::ir(const UDSPInstruction opc) // Add corresponding indexing register $ixR to addressing register $arR. void DSPEmitter::nr(const UDSPInstruction opc) { - u8 reg = opc & 0x3; + u8 reg = opc & 0x3; - increase_addr_reg(reg, reg); + increase_addr_reg(reg, reg); } // MV $axD.D, $acS.S @@ -54,10 +54,10 @@ void DSPEmitter::nr(const UDSPInstruction opc) // Move value of $acS.S to the $axD.D. void DSPEmitter::mv(const UDSPInstruction opc) { - u8 sreg = (opc & 0x3) + DSP_REG_ACL0; - u8 dreg = ((opc >> 2) & 0x3); - dsp_op_read_reg(sreg, RBX, ZERO); - storeIndex = dreg + DSP_REG_AXL0; + u8 sreg = (opc & 0x3) + DSP_REG_ACL0; + u8 dreg = ((opc >> 2) & 0x3); + dsp_op_read_reg(sreg, RBX, ZERO); + storeIndex = dreg + DSP_REG_AXL0; } // S @$arD, $acS.S @@ -66,20 +66,20 @@ void DSPEmitter::mv(const UDSPInstruction opc) // Post increment register $arD. void DSPEmitter::s(const UDSPInstruction opc) { - u8 dreg = opc & 0x3; - u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; - // u16 addr = g_dsp.r[dest]; - dsp_op_read_reg(dreg, RAX, ZERO); + u8 dreg = opc & 0x3; + u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; + // u16 addr = g_dsp.r[dest]; + dsp_op_read_reg(dreg, RAX, ZERO); - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg, tmp1, ZERO); - // u16 val = g_dsp.r[src]; - dmem_write(tmp1); + dsp_op_read_reg(sreg, tmp1, ZERO); + // u16 val = g_dsp.r[src]; + dmem_write(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - increment_addr_reg(dreg); + increment_addr_reg(dreg); } // SN @$arD, $acS.S @@ -88,18 +88,18 @@ void DSPEmitter::s(const UDSPInstruction opc) // Add indexing register $ixD to register $arD. void DSPEmitter::sn(const UDSPInstruction opc) { - u8 dreg = opc & 0x3; - u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; - dsp_op_read_reg(dreg, RAX, ZERO); + u8 dreg = opc & 0x3; + u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0; + dsp_op_read_reg(dreg, RAX, ZERO); - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg, tmp1, ZERO); - dmem_write(tmp1); + dsp_op_read_reg(sreg, tmp1, ZERO); + dmem_write(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - increase_addr_reg(dreg, dreg); + increase_addr_reg(dreg, dreg); } // L $axD.D, @$arS @@ -108,23 +108,23 @@ void DSPEmitter::sn(const UDSPInstruction opc) // Post increment register $arS. void DSPEmitter::l(const UDSPInstruction opc) { - u8 sreg = opc & 0x3; - u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; //AX?.?, AC?.[LM] + u8 sreg = opc & 0x3; + u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; // AX?.?, AC?.[LM] - pushExtValueFromMem(dreg, sreg); + pushExtValueFromMem(dreg, sreg); - if (dreg >= DSP_REG_ACM0) - { - //save SR too, so we can decide later. - //even if only for one bit, can only - //store (up to) two registers in EBX, - //so store all of SR - dsp_op_read_reg(DSP_REG_SR, RAX); - SHL(32, R(EAX), Imm8(16)); - OR(32, R(EBX), R(EAX)); - } + if (dreg >= DSP_REG_ACM0) + { + // save SR too, so we can decide later. + // even if only for one bit, can only + // store (up to) two registers in EBX, + // so store all of SR + dsp_op_read_reg(DSP_REG_SR, RAX); + SHL(32, R(EAX), Imm8(16)); + OR(32, R(EBX), R(EAX)); + } - increment_addr_reg(sreg); + increment_addr_reg(sreg); } // LN $axD.D, @$arS @@ -133,23 +133,23 @@ void DSPEmitter::l(const UDSPInstruction opc) // Add indexing register $ixS to register $arS. void DSPEmitter::ln(const UDSPInstruction opc) { - u8 sreg = opc & 0x3; - u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; + u8 sreg = opc & 0x3; + u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0; - pushExtValueFromMem(dreg, sreg); + pushExtValueFromMem(dreg, sreg); - if (dreg >= DSP_REG_ACM0) - { - //save SR too, so we can decide later. - //even if only for one bit, can only - //store (up to) two registers in EBX, - //so store all of SR - dsp_op_read_reg(DSP_REG_SR, RAX); - SHL(32, R(EAX), Imm8(16)); - OR(32, R(EBX), R(EAX)); - } + if (dreg >= DSP_REG_ACM0) + { + // save SR too, so we can decide later. + // even if only for one bit, can only + // store (up to) two registers in EBX, + // so store all of SR + dsp_op_read_reg(DSP_REG_SR, RAX); + SHL(32, R(EAX), Imm8(16)); + OR(32, R(EBX), R(EAX)); + } - increase_addr_reg(sreg, sreg); + increase_addr_reg(sreg, sreg); } // LS $axD.D, $acS.m @@ -159,24 +159,23 @@ void DSPEmitter::ln(const UDSPInstruction opc) // register $ar3. Increment both $ar0 and $ar3. void DSPEmitter::ls(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); - dmem_write(tmp1); + dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); + dmem_write(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - pushExtValueFromMem(dreg, DSP_REG_AR0); + pushExtValueFromMem(dreg, DSP_REG_AR0); - increment_addr_reg(DSP_REG_AR3); - increment_addr_reg(DSP_REG_AR0); + increment_addr_reg(DSP_REG_AR3); + increment_addr_reg(DSP_REG_AR0); } - // LSN $axD.D, $acS.m // xxxx xxxx 10dd 010s // Load register $axD.D with value from memory pointed by register @@ -185,21 +184,21 @@ void DSPEmitter::ls(const UDSPInstruction opc) // register $ar0 and increment $ar3. void DSPEmitter::lsn(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); - dmem_write(tmp1); + dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); + dmem_write(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - pushExtValueFromMem(dreg, DSP_REG_AR0); + pushExtValueFromMem(dreg, DSP_REG_AR0); - increment_addr_reg(DSP_REG_AR3); - increase_addr_reg(DSP_REG_AR0, DSP_REG_AR0); + increment_addr_reg(DSP_REG_AR3); + increase_addr_reg(DSP_REG_AR0, DSP_REG_AR0); } // LSM $axD.D, $acS.m @@ -210,21 +209,21 @@ void DSPEmitter::lsn(const UDSPInstruction opc) // register $ar3 and increment $ar0. void DSPEmitter::lsm(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); - dmem_write(tmp1); + dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); + dmem_write(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - pushExtValueFromMem(dreg, DSP_REG_AR0); + pushExtValueFromMem(dreg, DSP_REG_AR0); - increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); - increment_addr_reg(DSP_REG_AR0); + increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); + increment_addr_reg(DSP_REG_AR0); } // LSMN $axD.D, $acS.m @@ -236,21 +235,21 @@ void DSPEmitter::lsm(const UDSPInstruction opc) // register $ar3. void DSPEmitter::lsnm(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR3, RAX, ZERO); - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); - dmem_write(tmp1); + dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); + dmem_write(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - pushExtValueFromMem(dreg, DSP_REG_AR0); + pushExtValueFromMem(dreg, DSP_REG_AR0); - increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); - increase_addr_reg(DSP_REG_AR0, DSP_REG_AR0); + increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); + increase_addr_reg(DSP_REG_AR0, DSP_REG_AR0); } // SL $acS.m, $axD.D @@ -260,21 +259,21 @@ void DSPEmitter::lsnm(const UDSPInstruction opc) // $ar3. Increment both $ar0 and $ar3. void DSPEmitter::sl(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); - dmem_write(tmp1); + dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); + dmem_write(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - pushExtValueFromMem(dreg, DSP_REG_AR3); + pushExtValueFromMem(dreg, DSP_REG_AR3); - increment_addr_reg(DSP_REG_AR3); - increment_addr_reg(DSP_REG_AR0); + increment_addr_reg(DSP_REG_AR3); + increment_addr_reg(DSP_REG_AR0); } // SLN $acS.m, $axD.D @@ -285,21 +284,21 @@ void DSPEmitter::sl(const UDSPInstruction opc) // and increment $ar3. void DSPEmitter::sln(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); - dmem_write(tmp1); + dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); + dmem_write(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - pushExtValueFromMem(dreg, DSP_REG_AR3); + pushExtValueFromMem(dreg, DSP_REG_AR3); - increment_addr_reg(DSP_REG_AR3); - increase_addr_reg(DSP_REG_AR0, DSP_REG_AR0); + increment_addr_reg(DSP_REG_AR3); + increase_addr_reg(DSP_REG_AR0, DSP_REG_AR0); } // SLM $acS.m, $axD.D @@ -310,21 +309,21 @@ void DSPEmitter::sln(const UDSPInstruction opc) // and increment $ar0. void DSPEmitter::slm(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); - dmem_write(tmp1); + dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); + dmem_write(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - pushExtValueFromMem(dreg, DSP_REG_AR3); + pushExtValueFromMem(dreg, DSP_REG_AR3); - increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); - increment_addr_reg(DSP_REG_AR0); + increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); + increment_addr_reg(DSP_REG_AR0); } // SLMN $acS.m, $axD.D @@ -335,21 +334,21 @@ void DSPEmitter::slm(const UDSPInstruction opc) // and add corresponding indexing register $ix3 to addressing register $ar3. void DSPEmitter::slnm(const UDSPInstruction opc) { - u8 sreg = opc & 0x1; - u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; - dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); + u8 sreg = opc & 0x1; + u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0; + dsp_op_read_reg(DSP_REG_AR0, RAX, ZERO); - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); - dmem_write(tmp1); + dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO); + dmem_write(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - pushExtValueFromMem(dreg, DSP_REG_AR3); + pushExtValueFromMem(dreg, DSP_REG_AR3); - increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); - increase_addr_reg(DSP_REG_AR0, DSP_REG_AR0); + increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); + increase_addr_reg(DSP_REG_AR0, DSP_REG_AR0); } // LD $ax0.d, $ax1.r, @$arS @@ -364,329 +363,329 @@ void DSPEmitter::slnm(const UDSPInstruction opc) // AX0.L gets the same value as AX0.H. (not implemented yet) void DSPEmitter::ld(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; - pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); + pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); - // if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { - X64Reg tmp = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg, RCX, NONE); - dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); - XOR(16, R(ECX), R(tmp)); - gpr.PutXReg(tmp); - DSPJitRegCache c(gpr); - TEST(16, R(ECX), Imm16(0xfc00)); - FixupBranch not_equal = J_CC(CC_NE,true); - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); - gpr.FlushRegs(c); - FixupBranch after = J(true); - SetJumpTarget(not_equal); // else - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); - gpr.FlushRegs(c); - SetJumpTarget(after); + // if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { + X64Reg tmp = gpr.GetFreeXReg(); + dsp_op_read_reg(sreg, RCX, NONE); + dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); + XOR(16, R(ECX), R(tmp)); + gpr.PutXReg(tmp); + DSPJitRegCache c(gpr); + TEST(16, R(ECX), Imm16(0xfc00)); + FixupBranch not_equal = J_CC(CC_NE, true); + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); + gpr.FlushRegs(c); + FixupBranch after = J(true); + SetJumpTarget(not_equal); // else + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); + gpr.FlushRegs(c); + SetJumpTarget(after); - increment_addr_reg(sreg); + increment_addr_reg(sreg); - increment_addr_reg(DSP_REG_AR3); + increment_addr_reg(DSP_REG_AR3); } // LDAX $axR, @$arS // xxxx xxxx 11sr 0011 void DSPEmitter::ldax(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; + u8 sreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; - pushExtValueFromMem(rreg + DSP_REG_AXH0, sreg); + pushExtValueFromMem(rreg + DSP_REG_AXH0, sreg); - X64Reg tmp = gpr.GetFreeXReg(); - //if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { - dsp_op_read_reg(sreg, RCX, NONE); - dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); - XOR(16, R(ECX), R(tmp)); - gpr.PutXReg(tmp); - DSPJitRegCache c(gpr); - TEST(16, R(ECX), Imm16(0xfc00)); - FixupBranch not_equal = J_CC(CC_NE, true); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, sreg); - gpr.FlushRegs(c); - FixupBranch after = J(true); // else - SetJumpTarget(not_equal); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); - gpr.FlushRegs(c); - SetJumpTarget(after); + X64Reg tmp = gpr.GetFreeXReg(); + // if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { + dsp_op_read_reg(sreg, RCX, NONE); + dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); + XOR(16, R(ECX), R(tmp)); + gpr.PutXReg(tmp); + DSPJitRegCache c(gpr); + TEST(16, R(ECX), Imm16(0xfc00)); + FixupBranch not_equal = J_CC(CC_NE, true); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, sreg); + gpr.FlushRegs(c); + FixupBranch after = J(true); // else + SetJumpTarget(not_equal); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); + gpr.FlushRegs(c); + SetJumpTarget(after); - increment_addr_reg(sreg); + increment_addr_reg(sreg); - increment_addr_reg(DSP_REG_AR3); + increment_addr_reg(DSP_REG_AR3); } // LDN $ax0.d, $ax1.r, @$arS // xxxx xxxx 11dr 01ss void DSPEmitter::ldn(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; - pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); + pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); - X64Reg tmp = gpr.GetFreeXReg(); - //if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { - dsp_op_read_reg(sreg, RCX, NONE); - dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); - XOR(16, R(ECX), R(tmp)); - gpr.PutXReg(tmp); - DSPJitRegCache c(gpr); - TEST(16, R(ECX), Imm16(0xfc00)); - FixupBranch not_equal = J_CC(CC_NE,true); - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); - gpr.FlushRegs(c); - FixupBranch after = J(true); - SetJumpTarget(not_equal); // else - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); - gpr.FlushRegs(c); - SetJumpTarget(after); + X64Reg tmp = gpr.GetFreeXReg(); + // if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { + dsp_op_read_reg(sreg, RCX, NONE); + dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); + XOR(16, R(ECX), R(tmp)); + gpr.PutXReg(tmp); + DSPJitRegCache c(gpr); + TEST(16, R(ECX), Imm16(0xfc00)); + FixupBranch not_equal = J_CC(CC_NE, true); + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); + gpr.FlushRegs(c); + FixupBranch after = J(true); + SetJumpTarget(not_equal); // else + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); + gpr.FlushRegs(c); + SetJumpTarget(after); - increase_addr_reg(sreg, sreg); + increase_addr_reg(sreg, sreg); - increment_addr_reg(DSP_REG_AR3); + increment_addr_reg(DSP_REG_AR3); } // LDAXN $axR, @$arS // xxxx xxxx 11sr 0111 void DSPEmitter::ldaxn(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; + u8 sreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; - pushExtValueFromMem(rreg + DSP_REG_AXH0, sreg); + pushExtValueFromMem(rreg + DSP_REG_AXH0, sreg); - X64Reg tmp = gpr.GetFreeXReg(); - //if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { - dsp_op_read_reg(sreg, RCX, NONE); - dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); - XOR(16, R(ECX), R(tmp)); - gpr.PutXReg(tmp); - DSPJitRegCache c(gpr); - TEST(16, R(ECX), Imm16(0xfc00)); - FixupBranch not_equal = J_CC(CC_NE,true); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, sreg); - gpr.FlushRegs(c); - FixupBranch after = J(true); // else - SetJumpTarget(not_equal); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); - gpr.FlushRegs(c); - SetJumpTarget(after); + X64Reg tmp = gpr.GetFreeXReg(); + // if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { + dsp_op_read_reg(sreg, RCX, NONE); + dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); + XOR(16, R(ECX), R(tmp)); + gpr.PutXReg(tmp); + DSPJitRegCache c(gpr); + TEST(16, R(ECX), Imm16(0xfc00)); + FixupBranch not_equal = J_CC(CC_NE, true); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, sreg); + gpr.FlushRegs(c); + FixupBranch after = J(true); // else + SetJumpTarget(not_equal); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); + gpr.FlushRegs(c); + SetJumpTarget(after); - increase_addr_reg(sreg, sreg); + increase_addr_reg(sreg, sreg); - increment_addr_reg(DSP_REG_AR3); + increment_addr_reg(DSP_REG_AR3); } // LDM $ax0.d, $ax1.r, @$arS // xxxx xxxx 11dr 10ss void DSPEmitter::ldm(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; - pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); + pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); - X64Reg tmp = gpr.GetFreeXReg(); - //if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { - dsp_op_read_reg(sreg, RCX, NONE); - dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); - XOR(16, R(ECX), R(tmp)); - gpr.PutXReg(tmp); - DSPJitRegCache c(gpr); - TEST(16, R(ECX), Imm16(0xfc00)); - FixupBranch not_equal = J_CC(CC_NE,true); - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); - gpr.FlushRegs(c); - FixupBranch after = J(true); - SetJumpTarget(not_equal); // else - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); - gpr.FlushRegs(c); - SetJumpTarget(after); + X64Reg tmp = gpr.GetFreeXReg(); + // if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { + dsp_op_read_reg(sreg, RCX, NONE); + dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); + XOR(16, R(ECX), R(tmp)); + gpr.PutXReg(tmp); + DSPJitRegCache c(gpr); + TEST(16, R(ECX), Imm16(0xfc00)); + FixupBranch not_equal = J_CC(CC_NE, true); + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); + gpr.FlushRegs(c); + FixupBranch after = J(true); + SetJumpTarget(not_equal); // else + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); + gpr.FlushRegs(c); + SetJumpTarget(after); - increment_addr_reg(sreg); + increment_addr_reg(sreg); - increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); + increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); } // LDAXM $axR, @$arS // xxxx xxxx 11sr 1011 void DSPEmitter::ldaxm(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; + u8 sreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; - pushExtValueFromMem(rreg + DSP_REG_AXH0, sreg); + pushExtValueFromMem(rreg + DSP_REG_AXH0, sreg); - X64Reg tmp = gpr.GetFreeXReg(); - //if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { - dsp_op_read_reg(sreg, RCX, NONE); - dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); - XOR(16, R(ECX), R(tmp)); - gpr.PutXReg(tmp); - DSPJitRegCache c(gpr); - TEST(16, R(ECX), Imm16(0xfc00)); - FixupBranch not_equal = J_CC(CC_NE,true); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, sreg); - gpr.FlushRegs(c); - FixupBranch after = J(true); // else - SetJumpTarget(not_equal); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); - gpr.FlushRegs(c); - SetJumpTarget(after); + X64Reg tmp = gpr.GetFreeXReg(); + // if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { + dsp_op_read_reg(sreg, RCX, NONE); + dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); + XOR(16, R(ECX), R(tmp)); + gpr.PutXReg(tmp); + DSPJitRegCache c(gpr); + TEST(16, R(ECX), Imm16(0xfc00)); + FixupBranch not_equal = J_CC(CC_NE, true); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, sreg); + gpr.FlushRegs(c); + FixupBranch after = J(true); // else + SetJumpTarget(not_equal); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); + gpr.FlushRegs(c); + SetJumpTarget(after); - increment_addr_reg(sreg); + increment_addr_reg(sreg); - increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); + increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); } // LDNM $ax0.d, $ax1.r, @$arS // xxxx xxxx 11dr 11ss void DSPEmitter::ldnm(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; - u8 sreg = opc & 0x3; + u8 dreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; + u8 sreg = opc & 0x3; - pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); + pushExtValueFromMem((dreg << 1) + DSP_REG_AXL0, sreg); - X64Reg tmp = gpr.GetFreeXReg(); - //if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { - dsp_op_read_reg(sreg, RCX, NONE); - dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); - XOR(16, R(ECX), R(tmp)); - gpr.PutXReg(tmp); - DSPJitRegCache c(gpr); - TEST(16, R(ECX), Imm16(0xfc00)); - FixupBranch not_equal = J_CC(CC_NE,true); - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); - gpr.FlushRegs(c); - FixupBranch after = J(true); - SetJumpTarget(not_equal); // else - pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); - gpr.FlushRegs(c); - SetJumpTarget(after); + X64Reg tmp = gpr.GetFreeXReg(); + // if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { + dsp_op_read_reg(sreg, RCX, NONE); + dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); + XOR(16, R(ECX), R(tmp)); + gpr.PutXReg(tmp); + DSPJitRegCache c(gpr); + TEST(16, R(ECX), Imm16(0xfc00)); + FixupBranch not_equal = J_CC(CC_NE, true); + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, sreg); + gpr.FlushRegs(c); + FixupBranch after = J(true); + SetJumpTarget(not_equal); // else + pushExtValueFromMem2((rreg << 1) + DSP_REG_AXL1, DSP_REG_AR3); + gpr.FlushRegs(c); + SetJumpTarget(after); - increase_addr_reg(sreg, sreg); + increase_addr_reg(sreg, sreg); - increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); + increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); } // LDAXNM $axR, @$arS // xxxx xxxx 11sr 1111 void DSPEmitter::ldaxnm(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x1; - u8 rreg = (opc >> 4) & 0x1; + u8 sreg = (opc >> 5) & 0x1; + u8 rreg = (opc >> 4) & 0x1; - pushExtValueFromMem(rreg + DSP_REG_AXH0, sreg); + pushExtValueFromMem(rreg + DSP_REG_AXH0, sreg); - X64Reg tmp = gpr.GetFreeXReg(); - //if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { - dsp_op_read_reg(sreg, RCX, NONE); - dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); - XOR(16, R(ECX), R(tmp)); - gpr.PutXReg(tmp); - DSPJitRegCache c(gpr); - TEST(16, R(ECX), Imm16(0xfc00)); - FixupBranch not_equal = J_CC(CC_NE,true); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, sreg); - gpr.FlushRegs(c); - FixupBranch after = J(true); // else - SetJumpTarget(not_equal); - pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); - gpr.FlushRegs(c); - SetJumpTarget(after); + X64Reg tmp = gpr.GetFreeXReg(); + // if (IsSameMemArea(g_dsp.r[sreg], g_dsp.r[DSP_REG_AR3])) { + dsp_op_read_reg(sreg, RCX, NONE); + dsp_op_read_reg(DSP_REG_AR3, tmp, NONE); + XOR(16, R(ECX), R(tmp)); + gpr.PutXReg(tmp); + DSPJitRegCache c(gpr); + TEST(16, R(ECX), Imm16(0xfc00)); + FixupBranch not_equal = J_CC(CC_NE, true); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, sreg); + gpr.FlushRegs(c); + FixupBranch after = J(true); // else + SetJumpTarget(not_equal); + pushExtValueFromMem2(rreg + DSP_REG_AXL0, DSP_REG_AR3); + gpr.FlushRegs(c); + SetJumpTarget(after); - increase_addr_reg(sreg, sreg); + increase_addr_reg(sreg, sreg); - increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); + increase_addr_reg(DSP_REG_AR3, DSP_REG_AR3); } // Push value from address in g_dsp.r[sreg] into EBX and stores the // destinationindex in storeIndex void DSPEmitter::pushExtValueFromMem(u16 dreg, u16 sreg) { - // u16 addr = g_dsp.r[addr]; + // u16 addr = g_dsp.r[addr]; - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg, tmp1, ZERO); - dmem_read(tmp1); + dsp_op_read_reg(sreg, tmp1, ZERO); + dmem_read(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - MOVZX(32, 16, EBX, R(EAX)); + MOVZX(32, 16, EBX, R(EAX)); - storeIndex = dreg; + storeIndex = dreg; } void DSPEmitter::pushExtValueFromMem2(u16 dreg, u16 sreg) { - // u16 addr = g_dsp.r[addr]; + // u16 addr = g_dsp.r[addr]; - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg, tmp1, ZERO); - dmem_read(tmp1); + dsp_op_read_reg(sreg, tmp1, ZERO); + dmem_read(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - SHL(32, R(EAX), Imm8(16)); - OR(32, R(EBX), R(EAX)); + SHL(32, R(EAX), Imm8(16)); + OR(32, R(EBX), R(EAX)); - storeIndex2 = dreg; + storeIndex2 = dreg; } void DSPEmitter::popExtValueToReg() { - // in practice, we rarely ever have a non-NX main op - // with an extended op, so the OR here is either - // not run (storeIndex == -1) or ends up OR'ing - // EBX with 0 (becoming the MOV we have here) - // nakee wants to keep it clean, so lets do that. - // [nakeee] the or case never happens in real - // [nakeee] it's just how the hardware works so we added it - if (storeIndex != -1) - { - dsp_op_write_reg(storeIndex, RBX); - if (storeIndex >= DSP_REG_ACM0 && storeIndex2 == -1) - { - TEST(32, R(EBX), Imm32(SR_40_MODE_BIT << 16)); - FixupBranch not_40bit = J_CC(CC_Z, true); - DSPJitRegCache c(gpr); - //if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT) - //{ - // Sign extend into whole accum. - //u16 val = g_dsp.r[reg]; - MOVSX(32, 16, EAX, R(EBX)); - SHR(32, R(EAX), Imm8(16)); - //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = (val & 0x8000) ? 0xFFFF : 0x0000; - //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0; - set_acc_h(storeIndex - DSP_REG_ACM0, R(RAX)); - set_acc_l(storeIndex - DSP_REG_ACM0, Imm16(0)); - //} - gpr.FlushRegs(c); - SetJumpTarget(not_40bit); - } - } + // in practice, we rarely ever have a non-NX main op + // with an extended op, so the OR here is either + // not run (storeIndex == -1) or ends up OR'ing + // EBX with 0 (becoming the MOV we have here) + // nakee wants to keep it clean, so lets do that. + // [nakeee] the or case never happens in real + // [nakeee] it's just how the hardware works so we added it + if (storeIndex != -1) + { + dsp_op_write_reg(storeIndex, RBX); + if (storeIndex >= DSP_REG_ACM0 && storeIndex2 == -1) + { + TEST(32, R(EBX), Imm32(SR_40_MODE_BIT << 16)); + FixupBranch not_40bit = J_CC(CC_Z, true); + DSPJitRegCache c(gpr); + // if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT) + //{ + // Sign extend into whole accum. + // u16 val = g_dsp.r[reg]; + MOVSX(32, 16, EAX, R(EBX)); + SHR(32, R(EAX), Imm8(16)); + // g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = (val & 0x8000) ? 0xFFFF : 0x0000; + // g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0; + set_acc_h(storeIndex - DSP_REG_ACM0, R(RAX)); + set_acc_l(storeIndex - DSP_REG_ACM0, Imm16(0)); + //} + gpr.FlushRegs(c); + SetJumpTarget(not_40bit); + } + } - storeIndex = -1; + storeIndex = -1; - if (storeIndex2 != -1) - { - SHR(32, R(EBX), Imm8(16)); - dsp_op_write_reg(storeIndex2, RBX); - } + if (storeIndex2 != -1) + { + SHR(32, R(EBX), Imm8(16)); + dsp_op_write_reg(storeIndex2, RBX); + } - storeIndex2 = -1; + storeIndex2 = -1; } diff --git a/Source/Core/Core/DSP/Jit/DSPJitLoadStore.cpp b/Source/Core/Core/DSP/Jit/DSPJitLoadStore.cpp index f1de0043ce..8cf503ef5d 100644 --- a/Source/Core/Core/DSP/Jit/DSPJitLoadStore.cpp +++ b/Source/Core/Core/DSP/Jit/DSPJitLoadStore.cpp @@ -6,8 +6,8 @@ #include "Core/DSP/DSPEmitter.h" #include "Core/DSP/DSPIntCCUtil.h" -#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPIntUtil.h" +#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPMemoryMap.h" using namespace Gen; @@ -20,18 +20,18 @@ using namespace Gen; // Note: pc+=2 in duddie's doc seems wrong void DSPEmitter::srs(const UDSPInstruction opc) { - u8 reg = ((opc >> 8) & 0x7) + 0x18; - //u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF); + u8 reg = ((opc >> 8) & 0x7) + 0x18; + // u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF); - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(reg, tmp1, ZERO); - dsp_op_read_reg(DSP_REG_CR, RAX, ZERO); - SHL(16, R(EAX), Imm8(8)); - OR(16, R(EAX), Imm16(opc & 0xFF)); - dmem_write(tmp1); + dsp_op_read_reg(reg, tmp1, ZERO); + dsp_op_read_reg(DSP_REG_CR, RAX, ZERO); + SHL(16, R(EAX), Imm8(8)); + OR(16, R(EAX), Imm16(opc & 0xFF)); + dmem_write(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); } // LRS $(0x18+D), @M @@ -41,20 +41,20 @@ void DSPEmitter::srs(const UDSPInstruction opc) // from CR, and the lower 8 bits are from the 8-bit immediate. void DSPEmitter::lrs(const UDSPInstruction opc) { - u8 reg = ((opc >> 8) & 0x7) + 0x18; + u8 reg = ((opc >> 8) & 0x7) + 0x18; - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - //u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc & 0xFF); - dsp_op_read_reg(DSP_REG_CR, tmp1, ZERO); - SHL(16, R(tmp1), Imm8(8)); - OR(16, R(tmp1), Imm16(opc & 0xFF)); - dmem_read(tmp1); + // u16 addr = (g_dsp.r[DSP_REG_CR] << 8) | (opc & 0xFF); + dsp_op_read_reg(DSP_REG_CR, tmp1, ZERO); + SHL(16, R(tmp1), Imm8(8)); + OR(16, R(tmp1), Imm16(opc & 0xFF)); + dmem_read(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - dsp_op_write_reg(reg, RAX); - dsp_conditional_extend_accum(reg); + dsp_op_write_reg(reg, RAX); + dsp_conditional_extend_accum(reg); } // LR $D, @M @@ -63,11 +63,11 @@ void DSPEmitter::lrs(const UDSPInstruction opc) // Move value from data memory pointed by address M to register $D. void DSPEmitter::lr(const UDSPInstruction opc) { - int reg = opc & DSP_REG_MASK; - u16 address = dsp_imem_read(compilePC + 1); - dmem_read_imm(address); - dsp_op_write_reg(reg, EAX); - dsp_conditional_extend_accum(reg); + int reg = opc & DSP_REG_MASK; + u16 address = dsp_imem_read(compilePC + 1); + dmem_read_imm(address); + dsp_op_write_reg(reg, EAX); + dsp_conditional_extend_accum(reg); } // SR @M, $S @@ -76,15 +76,15 @@ void DSPEmitter::lr(const UDSPInstruction opc) // Store value from register $S to a memory pointed by address M. void DSPEmitter::sr(const UDSPInstruction opc) { - u8 reg = opc & DSP_REG_MASK; - u16 address = dsp_imem_read(compilePC + 1); + u8 reg = opc & DSP_REG_MASK; + u16 address = dsp_imem_read(compilePC + 1); - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(reg, tmp1); - dmem_write_imm(address, tmp1); + dsp_op_read_reg(reg, tmp1); + dmem_write_imm(address, tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); } // SI @M, #I @@ -94,15 +94,15 @@ void DSPEmitter::sr(const UDSPInstruction opc) // M (M is 8-bit value sign extended). void DSPEmitter::si(const UDSPInstruction opc) { - u16 address = (s8)opc; - u16 imm = dsp_imem_read(compilePC + 1); + u16 address = (s8)opc; + u16 imm = dsp_imem_read(compilePC + 1); - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - MOV(32, R(tmp1), Imm32((u32)imm)); - dmem_write_imm(address, tmp1); + MOV(32, R(tmp1), Imm32((u32)imm)); + dmem_write_imm(address, tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); } // LRR $D, @$S @@ -110,18 +110,18 @@ void DSPEmitter::si(const UDSPInstruction opc) // Move value from data memory pointed by addressing register $S to register $D. void DSPEmitter::lrr(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg, tmp1); - dmem_read(tmp1); + dsp_op_read_reg(sreg, tmp1); + dmem_read(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - dsp_op_write_reg(dreg, EAX); - dsp_conditional_extend_accum(dreg); + dsp_op_write_reg(dreg, EAX); + dsp_conditional_extend_accum(dreg); } // LRRD $D, @$S @@ -130,19 +130,19 @@ void DSPEmitter::lrr(const UDSPInstruction opc) // Decrement register $S. void DSPEmitter::lrrd(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg, tmp1); - dmem_read(tmp1); + dsp_op_read_reg(sreg, tmp1); + dmem_read(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - dsp_op_write_reg(dreg, EAX); - dsp_conditional_extend_accum(dreg); - decrement_addr_reg(sreg); + dsp_op_write_reg(dreg, EAX); + dsp_conditional_extend_accum(dreg); + decrement_addr_reg(sreg); } // LRRI $D, @$S @@ -151,19 +151,19 @@ void DSPEmitter::lrrd(const UDSPInstruction opc) // Increment register $S. void DSPEmitter::lrri(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg, tmp1); - dmem_read(tmp1); + dsp_op_read_reg(sreg, tmp1); + dmem_read(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - dsp_op_write_reg(dreg, EAX); - dsp_conditional_extend_accum(dreg); - increment_addr_reg(sreg); + dsp_op_write_reg(dreg, EAX); + dsp_conditional_extend_accum(dreg); + increment_addr_reg(sreg); } // LRRN $D, @$S @@ -172,19 +172,19 @@ void DSPEmitter::lrri(const UDSPInstruction opc) // Add indexing register $(0x4+S) to register $S. void DSPEmitter::lrrn(const UDSPInstruction opc) { - u8 sreg = (opc >> 5) & 0x3; - u8 dreg = opc & 0x1f; + u8 sreg = (opc >> 5) & 0x3; + u8 dreg = opc & 0x1f; - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg, tmp1); - dmem_read(tmp1); + dsp_op_read_reg(sreg, tmp1); + dmem_read(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - dsp_op_write_reg(dreg, EAX); - dsp_conditional_extend_accum(dreg); - increase_addr_reg(sreg, sreg); + dsp_op_write_reg(dreg, EAX); + dsp_conditional_extend_accum(dreg); + increase_addr_reg(sreg, sreg); } // SRR @$D, $S @@ -193,16 +193,16 @@ void DSPEmitter::lrrn(const UDSPInstruction opc) // addressing register $D. void DSPEmitter::srr(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg, tmp1); - dsp_op_read_reg(dreg, RAX, ZERO); - dmem_write(tmp1); + dsp_op_read_reg(sreg, tmp1); + dsp_op_read_reg(dreg, RAX, ZERO); + dmem_write(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); } // SRRD @$D, $S @@ -211,18 +211,18 @@ void DSPEmitter::srr(const UDSPInstruction opc) // addressing register $D. Decrement register $D. void DSPEmitter::srrd(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg, tmp1); - dsp_op_read_reg(dreg, RAX, ZERO); - dmem_write(tmp1); + dsp_op_read_reg(sreg, tmp1); + dsp_op_read_reg(dreg, RAX, ZERO); + dmem_write(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - decrement_addr_reg(dreg); + decrement_addr_reg(dreg); } // SRRI @$D, $S @@ -231,18 +231,18 @@ void DSPEmitter::srrd(const UDSPInstruction opc) // addressing register $D. Increment register $D. void DSPEmitter::srri(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg, tmp1); - dsp_op_read_reg(dreg, RAX, ZERO); - dmem_write(tmp1); + dsp_op_read_reg(sreg, tmp1); + dsp_op_read_reg(dreg, RAX, ZERO); + dmem_write(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - increment_addr_reg(dreg); + increment_addr_reg(dreg); } // SRRN @$D, $S @@ -251,18 +251,18 @@ void DSPEmitter::srri(const UDSPInstruction opc) // addressing register $D. Add DSP_REG_IX0 register to register $D. void DSPEmitter::srrn(const UDSPInstruction opc) { - u8 dreg = (opc >> 5) & 0x3; - u8 sreg = opc & 0x1f; + u8 dreg = (opc >> 5) & 0x3; + u8 sreg = opc & 0x1f; - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(sreg, tmp1); - dsp_op_read_reg(dreg, RAX, ZERO); - dmem_write(tmp1); + dsp_op_read_reg(sreg, tmp1); + dsp_op_read_reg(dreg, RAX, ZERO); + dmem_write(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - increase_addr_reg(dreg, dreg); + increase_addr_reg(dreg, dreg); } // ILRR $acD.m, @$arS @@ -271,18 +271,18 @@ void DSPEmitter::srrn(const UDSPInstruction opc) // $arS to mid accumulator register $acD.m. void DSPEmitter::ilrr(const UDSPInstruction opc) { - u16 reg = opc & 0x3; - u16 dreg = (opc >> 8) & 1; + u16 reg = opc & 0x3; + u16 dreg = (opc >> 8) & 1; - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(reg, tmp1, ZERO); - imem_read(tmp1); + dsp_op_read_reg(reg, tmp1, ZERO); + imem_read(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - set_acc_m(dreg, R(RAX)); - dsp_conditional_extend_accum(dreg + DSP_REG_ACM0); + set_acc_m(dreg, R(RAX)); + dsp_conditional_extend_accum(dreg + DSP_REG_ACM0); } // ILRRD $acD.m, @$arS @@ -291,19 +291,19 @@ void DSPEmitter::ilrr(const UDSPInstruction opc) // $arS to mid accumulator register $acD.m. Decrement addressing register $arS. void DSPEmitter::ilrrd(const UDSPInstruction opc) { - u16 reg = opc & 0x3; - u16 dreg = (opc >> 8) & 1; + u16 reg = opc & 0x3; + u16 dreg = (opc >> 8) & 1; - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(reg, tmp1, ZERO); - imem_read(tmp1); + dsp_op_read_reg(reg, tmp1, ZERO); + imem_read(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - set_acc_m(dreg, R(RAX)); - dsp_conditional_extend_accum(dreg + DSP_REG_ACM0); - decrement_addr_reg(reg); + set_acc_m(dreg, R(RAX)); + dsp_conditional_extend_accum(dreg + DSP_REG_ACM0); + decrement_addr_reg(reg); } // ILRRI $acD.m, @$S @@ -312,19 +312,19 @@ void DSPEmitter::ilrrd(const UDSPInstruction opc) // $arS to mid accumulator register $acD.m. Increment addressing register $arS. void DSPEmitter::ilrri(const UDSPInstruction opc) { - u16 reg = opc & 0x3; - u16 dreg = (opc >> 8) & 1; + u16 reg = opc & 0x3; + u16 dreg = (opc >> 8) & 1; - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(reg, tmp1, ZERO); - imem_read(tmp1); + dsp_op_read_reg(reg, tmp1, ZERO); + imem_read(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - set_acc_m(dreg, R(RAX)); - dsp_conditional_extend_accum(dreg + DSP_REG_ACM0); - increment_addr_reg(reg); + set_acc_m(dreg, R(RAX)); + dsp_conditional_extend_accum(dreg + DSP_REG_ACM0); + increment_addr_reg(reg); } // ILRRN $acD.m, @$arS @@ -334,18 +334,17 @@ void DSPEmitter::ilrri(const UDSPInstruction opc) // register $ixS to addressing register $arS. void DSPEmitter::ilrrn(const UDSPInstruction opc) { - u16 reg = opc & 0x3; - u16 dreg = (opc >> 8) & 1; + u16 reg = opc & 0x3; + u16 dreg = (opc >> 8) & 1; - X64Reg tmp1 = gpr.GetFreeXReg(); + X64Reg tmp1 = gpr.GetFreeXReg(); - dsp_op_read_reg(reg, tmp1, ZERO); - imem_read(tmp1); + dsp_op_read_reg(reg, tmp1, ZERO); + imem_read(tmp1); - gpr.PutXReg(tmp1); + gpr.PutXReg(tmp1); - set_acc_m(dreg, R(RAX)); - dsp_conditional_extend_accum(dreg + DSP_REG_ACM0); - increase_addr_reg(reg, reg); + set_acc_m(dreg, R(RAX)); + dsp_conditional_extend_accum(dreg + DSP_REG_ACM0); + increase_addr_reg(reg, reg); } - diff --git a/Source/Core/Core/DSP/Jit/DSPJitMisc.cpp b/Source/Core/Core/DSP/Jit/DSPJitMisc.cpp index 4c8b854107..3a18d7cca6 100644 --- a/Source/Core/Core/DSP/Jit/DSPJitMisc.cpp +++ b/Source/Core/Core/DSP/Jit/DSPJitMisc.cpp @@ -3,8 +3,8 @@ // Refer to the license.txt file included. #include "Core/DSP/DSPEmitter.h" -#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPIntUtil.h" +#include "Core/DSP/DSPInterpreter.h" #include "Core/DSP/DSPMemoryMap.h" using namespace Gen; @@ -14,12 +14,12 @@ using namespace Gen; // Move value from register $S to register $D. void DSPEmitter::mrr(const UDSPInstruction opc) { - u8 sreg = opc & 0x1f; - u8 dreg = (opc >> 5) & 0x1f; + u8 sreg = opc & 0x1f; + u8 dreg = (opc >> 5) & 0x1f; - dsp_op_read_reg(sreg, EDX); - dsp_op_write_reg(dreg, EDX); - dsp_conditional_extend_accum(dreg); + dsp_op_read_reg(sreg, EDX); + dsp_op_write_reg(dreg, EDX); + dsp_conditional_extend_accum(dreg); } // LRI $D, #I @@ -33,10 +33,10 @@ void DSPEmitter::mrr(const UDSPInstruction opc) // S16 mode. void DSPEmitter::lri(const UDSPInstruction opc) { - u8 reg = opc & DSP_REG_MASK; - u16 imm = dsp_imem_read(compilePC+1); - dsp_op_write_reg_imm(reg, imm); - dsp_conditional_extend_accum_imm(reg, imm); + u8 reg = opc & DSP_REG_MASK; + u16 imm = dsp_imem_read(compilePC + 1); + dsp_op_write_reg_imm(reg, imm); + dsp_conditional_extend_accum_imm(reg, imm); } // LRIS $(0x18+D), #I @@ -44,10 +44,10 @@ void DSPEmitter::lri(const UDSPInstruction opc) // Load immediate value I (8-bit sign extended) to accumulator register. void DSPEmitter::lris(const UDSPInstruction opc) { - u8 reg = ((opc >> 8) & 0x7) + DSP_REG_AXL0; - u16 imm = (s8)opc; - dsp_op_write_reg_imm(reg, imm); - dsp_conditional_extend_accum_imm(reg, imm); + u8 reg = ((opc >> 8) & 0x7) + DSP_REG_AXL0; + u16 imm = (s8)opc; + dsp_op_write_reg_imm(reg, imm); + dsp_conditional_extend_accum_imm(reg, imm); } //---- @@ -68,9 +68,8 @@ void DSPEmitter::nx(const UDSPInstruction opc) // Decrement address register $arD. void DSPEmitter::dar(const UDSPInstruction opc) { - // g_dsp.r[opc & 0x3] = dsp_decrement_addr_reg(opc & 0x3); - decrement_addr_reg(opc & 0x3); - + // g_dsp.r[opc & 0x3] = dsp_decrement_addr_reg(opc & 0x3); + decrement_addr_reg(opc & 0x3); } // IAR $arD @@ -78,8 +77,8 @@ void DSPEmitter::dar(const UDSPInstruction opc) // Increment address register $arD. void DSPEmitter::iar(const UDSPInstruction opc) { - // g_dsp.r[opc & 0x3] = dsp_increment_addr_reg(opc & 0x3); - increment_addr_reg(opc & 0x3); + // g_dsp.r[opc & 0x3] = dsp_increment_addr_reg(opc & 0x3); + increment_addr_reg(opc & 0x3); } // SUBARN $arD @@ -88,9 +87,9 @@ void DSPEmitter::iar(const UDSPInstruction opc) // used only in IPL-NTSC ucode void DSPEmitter::subarn(const UDSPInstruction opc) { - // u8 dreg = opc & 0x3; - // g_dsp.r[dreg] = dsp_decrease_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg]); - decrease_addr_reg(opc & 0x3); + // u8 dreg = opc & 0x3; + // g_dsp.r[dreg] = dsp_decrease_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg]); + decrease_addr_reg(opc & 0x3); } // ADDARN $arD, $ixS @@ -99,39 +98,36 @@ void DSPEmitter::subarn(const UDSPInstruction opc) // It is critical for the Zelda ucode that this one wraps correctly. void DSPEmitter::addarn(const UDSPInstruction opc) { - // u8 dreg = opc & 0x3; - // u8 sreg = (opc >> 2) & 0x3; - // g_dsp.r[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]); + // u8 dreg = opc & 0x3; + // u8 sreg = (opc >> 2) & 0x3; + // g_dsp.r[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]); - // From looking around it is always called with the matching index register - increase_addr_reg(opc & 0x3, (opc >> 2) & 0x3); + // From looking around it is always called with the matching index register + increase_addr_reg(opc & 0x3, (opc >> 2) & 0x3); } //---- - void DSPEmitter::setCompileSR(u16 bit) { + // g_dsp.r[DSP_REG_SR] |= bit + OpArg sr_reg; + gpr.GetReg(DSP_REG_SR, sr_reg); + OR(16, sr_reg, Imm16(bit)); + gpr.PutReg(DSP_REG_SR); - // g_dsp.r[DSP_REG_SR] |= bit - OpArg sr_reg; - gpr.GetReg(DSP_REG_SR,sr_reg); - OR(16, sr_reg, Imm16(bit)); - gpr.PutReg(DSP_REG_SR); - - compileSR |= bit; + compileSR |= bit; } void DSPEmitter::clrCompileSR(u16 bit) { + // g_dsp.r[DSP_REG_SR] &= bit + OpArg sr_reg; + gpr.GetReg(DSP_REG_SR, sr_reg); + AND(16, sr_reg, Imm16(~bit)); + gpr.PutReg(DSP_REG_SR); - // g_dsp.r[DSP_REG_SR] &= bit - OpArg sr_reg; - gpr.GetReg(DSP_REG_SR,sr_reg); - AND(16, sr_reg, Imm16(~bit)); - gpr.PutReg(DSP_REG_SR); - - compileSR &= ~bit; + compileSR &= ~bit; } // SBCLR #I // 0001 0011 aaaa aiii @@ -139,9 +135,9 @@ void DSPEmitter::clrCompileSR(u16 bit) // immediate value I. void DSPEmitter::sbclr(const UDSPInstruction opc) { - u8 bit = (opc & 0x7) + 6; + u8 bit = (opc & 0x7) + 6; - clrCompileSR(1 << bit); + clrCompileSR(1 << bit); } // SBSET #I @@ -150,9 +146,9 @@ void DSPEmitter::sbclr(const UDSPInstruction opc) // immediate value I. void DSPEmitter::sbset(const UDSPInstruction opc) { - u8 bit = (opc & 0x7) + 6; + u8 bit = (opc & 0x7) + 6; - setCompileSR(1 << bit); + setCompileSR(1 << bit); } // 1000 1bbb xxxx xxxx, bbb >= 010 @@ -160,37 +156,36 @@ void DSPEmitter::sbset(const UDSPInstruction opc) // but it's harder to know exactly what effect they have. void DSPEmitter::srbith(const UDSPInstruction opc) { - switch ((opc >> 8) & 0xf) - { - // M0/M2 change the multiplier mode (it can multiply by 2 for free). - case 0xa: // M2 - clrCompileSR(SR_MUL_MODIFY); - break; - case 0xb: // M0 - setCompileSR(SR_MUL_MODIFY); - break; + switch ((opc >> 8) & 0xf) + { + // M0/M2 change the multiplier mode (it can multiply by 2 for free). + case 0xa: // M2 + clrCompileSR(SR_MUL_MODIFY); + break; + case 0xb: // M0 + setCompileSR(SR_MUL_MODIFY); + break; - // If set, treat multiplicands as unsigned. - // If clear, treat them as signed. - case 0xc: // CLR15 - clrCompileSR(SR_MUL_UNSIGNED); - break; - case 0xd: // SET15 - setCompileSR(SR_MUL_UNSIGNED); - break; + // If set, treat multiplicands as unsigned. + // If clear, treat them as signed. + case 0xc: // CLR15 + clrCompileSR(SR_MUL_UNSIGNED); + break; + case 0xd: // SET15 + setCompileSR(SR_MUL_UNSIGNED); + break; - // Automatic 40-bit sign extension when loading ACx.M. - // SET40 changes something very important: see the LRI instruction above. - case 0xe: // SET16 (CLR40) - clrCompileSR(SR_40_MODE_BIT); - break; + // Automatic 40-bit sign extension when loading ACx.M. + // SET40 changes something very important: see the LRI instruction above. + case 0xe: // SET16 (CLR40) + clrCompileSR(SR_40_MODE_BIT); + break; - case 0xf: // SET40 - setCompileSR(SR_40_MODE_BIT); - break; + case 0xf: // SET40 + setCompileSR(SR_40_MODE_BIT); + break; - default: - break; - } + default: + break; + } } - diff --git a/Source/Core/Core/DSP/Jit/DSPJitMultiplier.cpp b/Source/Core/Core/DSP/Jit/DSPJitMultiplier.cpp index fd988ae3ab..7edb90e54d 100644 --- a/Source/Core/Core/DSP/Jit/DSPJitMultiplier.cpp +++ b/Source/Core/Core/DSP/Jit/DSPJitMultiplier.cpp @@ -4,7 +4,6 @@ // Additional copyrights go to Duddie and Tratax (c) 2004 - // Multiplier and product register control #include "Core/DSP/DSPAnalyzer.h" @@ -17,44 +16,44 @@ using namespace Gen; // In: RCX = s16 a, RAX = s16 b void DSPEmitter::multiply() { -// prod = (s16)a * (s16)b; //signed - IMUL(64, R(ECX)); + // prod = (s16)a * (s16)b; //signed + IMUL(64, R(ECX)); -// Conditionally multiply by 2. -// if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0) - OpArg sr_reg; - gpr.GetReg(DSP_REG_SR,sr_reg); - TEST(16, sr_reg, Imm16(SR_MUL_MODIFY)); - FixupBranch noMult2 = J_CC(CC_NZ); -// prod <<= 1; - LEA(64, RAX, MRegSum(RAX,RAX)); - SetJumpTarget(noMult2); - gpr.PutReg(DSP_REG_SR, false); -// return prod; + // Conditionally multiply by 2. + // if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0) + OpArg sr_reg; + gpr.GetReg(DSP_REG_SR, sr_reg); + TEST(16, sr_reg, Imm16(SR_MUL_MODIFY)); + FixupBranch noMult2 = J_CC(CC_NZ); + // prod <<= 1; + LEA(64, RAX, MRegSum(RAX, RAX)); + SetJumpTarget(noMult2); + gpr.PutReg(DSP_REG_SR, false); + // return prod; } // Returns s64 in RAX // Clobbers RDX void DSPEmitter::multiply_add() { -// s64 prod = dsp_get_long_prod() + dsp_get_multiply_prod(a, b, sign); - multiply(); - MOV(64, R(RDX), R(RAX)); - get_long_prod(); - ADD(64, R(RAX), R(RDX)); -// return prod; + // s64 prod = dsp_get_long_prod() + dsp_get_multiply_prod(a, b, sign); + multiply(); + MOV(64, R(RDX), R(RAX)); + get_long_prod(); + ADD(64, R(RAX), R(RDX)); + // return prod; } // Returns s64 in RAX // Clobbers RDX void DSPEmitter::multiply_sub() { -// s64 prod = dsp_get_long_prod() - dsp_get_multiply_prod(a, b, sign); - multiply(); - MOV(64, R(RDX), R(RAX)); - get_long_prod(); - SUB(64, R(RAX), R(RDX)); -// return prod; + // s64 prod = dsp_get_long_prod() - dsp_get_multiply_prod(a, b, sign); + multiply(); + MOV(64, R(RDX), R(RAX)); + get_long_prod(); + SUB(64, R(RAX), R(RDX)); + // return prod; } // Only MULX family instructions have unsigned/mixed support. @@ -63,76 +62,75 @@ void DSPEmitter::multiply_sub() // Returns s64 in RAX void DSPEmitter::multiply_mulx(u8 axh0, u8 axh1) { -// s64 result; + // s64 result; -// if ((axh0==0) && (axh1==0)) -// result = dsp_multiply(val1, val2, 1); // unsigned support ON if both ax?.l regs are used -// else if ((axh0==0) && (axh1==1)) -// result = dsp_multiply(val1, val2, 2); // mixed support ON (u16)axl.0 * (s16)axh.1 -// else if ((axh0==1) && (axh1==0)) -// result = dsp_multiply(val2, val1, 2); // mixed support ON (u16)axl.1 * (s16)axh.0 -// else -// result = dsp_multiply(val1, val2, 0); // unsigned support OFF if both ax?.h regs are used + // if ((axh0==0) && (axh1==0)) + // result = dsp_multiply(val1, val2, 1); // unsigned support ON if both ax?.l regs are used + // else if ((axh0==0) && (axh1==1)) + // result = dsp_multiply(val1, val2, 2); // mixed support ON (u16)axl.0 * (s16)axh.1 + // else if ((axh0==1) && (axh1==0)) + // result = dsp_multiply(val2, val1, 2); // mixed support ON (u16)axl.1 * (s16)axh.0 + // else + // result = dsp_multiply(val1, val2, 0); // unsigned support OFF if both ax?.h regs are used + // if ((sign == 1) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) //unsigned + OpArg sr_reg; + gpr.GetReg(DSP_REG_SR, sr_reg); + TEST(16, sr_reg, Imm16(SR_MUL_UNSIGNED)); + FixupBranch unsignedMul = J_CC(CC_NZ); + // prod = (s16)a * (s16)b; //signed + MOVSX(64, 16, RAX, R(RAX)); + IMUL(64, R(RCX)); + FixupBranch signedMul = J(true); -// if ((sign == 1) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) //unsigned - OpArg sr_reg; - gpr.GetReg(DSP_REG_SR,sr_reg); - TEST(16, sr_reg, Imm16(SR_MUL_UNSIGNED)); - FixupBranch unsignedMul = J_CC(CC_NZ); - // prod = (s16)a * (s16)b; //signed - MOVSX(64, 16, RAX, R(RAX)); - IMUL(64, R(RCX)); - FixupBranch signedMul = J(true); + SetJumpTarget(unsignedMul); + DSPJitRegCache c(gpr); + gpr.PutReg(DSP_REG_SR, false); + if ((axh0 == 0) && (axh1 == 0)) + { + // unsigned support ON if both ax?.l regs are used + // prod = (u32)(a * b); + MOVZX(64, 16, RCX, R(RCX)); + MOVZX(64, 16, RAX, R(RAX)); + MUL(64, R(RCX)); + } + else if ((axh0 == 0) && (axh1 == 1)) + { + // mixed support ON (u16)axl.0 * (s16)axh.1 + // prod = a * (s16)b; + X64Reg tmp = gpr.GetFreeXReg(); + MOV(64, R(tmp), R(RAX)); + MOVZX(64, 16, RAX, R(RCX)); + IMUL(64, R(tmp)); + gpr.PutXReg(tmp); + } + else if ((axh0 == 1) && (axh1 == 0)) + { + // mixed support ON (u16)axl.1 * (s16)axh.0 + // prod = (s16)a * b; + MOVZX(64, 16, RAX, R(RAX)); + IMUL(64, R(RCX)); + } + else + { + // unsigned support OFF if both ax?.h regs are used + // prod = (s16)a * (s16)b; //signed + MOVSX(64, 16, RAX, R(RAX)); + IMUL(64, R(RCX)); + } - SetJumpTarget(unsignedMul); - DSPJitRegCache c(gpr); - gpr.PutReg(DSP_REG_SR, false); - if ((axh0==0) && (axh1==0)) - { - // unsigned support ON if both ax?.l regs are used -// prod = (u32)(a * b); - MOVZX(64, 16, RCX, R(RCX)); - MOVZX(64, 16, RAX, R(RAX)); - MUL(64, R(RCX)); - } - else if ((axh0==0) && (axh1==1)) - { - // mixed support ON (u16)axl.0 * (s16)axh.1 -// prod = a * (s16)b; - X64Reg tmp = gpr.GetFreeXReg(); - MOV(64, R(tmp), R(RAX)); - MOVZX(64, 16, RAX, R(RCX)); - IMUL(64, R(tmp)); - gpr.PutXReg(tmp); - } - else if ((axh0==1) && (axh1==0)) - { - // mixed support ON (u16)axl.1 * (s16)axh.0 -// prod = (s16)a * b; - MOVZX(64, 16, RAX, R(RAX)); - IMUL(64, R(RCX)); - } - else - { - // unsigned support OFF if both ax?.h regs are used -// prod = (s16)a * (s16)b; //signed - MOVSX(64, 16, RAX, R(RAX)); - IMUL(64, R(RCX)); - } + gpr.FlushRegs(c); + SetJumpTarget(signedMul); - gpr.FlushRegs(c); - SetJumpTarget(signedMul); - - // Conditionally multiply by 2. -// if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0) - TEST(16, sr_reg, Imm16(SR_MUL_MODIFY)); - FixupBranch noMult2 = J_CC(CC_NZ); -// prod <<= 1; - LEA(64, RAX, MRegSum(RAX,RAX)); - SetJumpTarget(noMult2); - gpr.PutReg(DSP_REG_SR, false); -// return prod; + // Conditionally multiply by 2. + // if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0) + TEST(16, sr_reg, Imm16(SR_MUL_MODIFY)); + FixupBranch noMult2 = J_CC(CC_NZ); + // prod <<= 1; + LEA(64, RAX, MRegSum(RAX, RAX)); + SetJumpTarget(noMult2); + gpr.PutReg(DSP_REG_SR, false); + // return prod; } //---- @@ -148,9 +146,9 @@ void DSPEmitter::multiply_mulx(u8 axh0, u8 axh1) // direct use of prod regs by AX/AXWII (look @that part of ucode). void DSPEmitter::clrp(const UDSPInstruction opc) { - //64bit move to memory does not work. use 2 32bits - MOV(32, M(((u32*)&g_dsp.r.prod.val)+0), Imm32(0xfff00000U)); - MOV(32, M(((u32*)&g_dsp.r.prod.val)+1), Imm32(0x001000ffU)); + // 64bit move to memory does not work. use 2 32bits + MOV(32, M(((u32*)&g_dsp.r.prod.val) + 0), Imm32(0xfff00000U)); + MOV(32, M(((u32*)&g_dsp.r.prod.val) + 1), Imm32(0x001000ffU)); } // TSTPROD @@ -160,13 +158,13 @@ void DSPEmitter::clrp(const UDSPInstruction opc) // flags out: --xx xx0x void DSPEmitter::tstprod(const UDSPInstruction opc) { - if (FlagsNeeded()) - { -// s64 prod = dsp_get_long_prod(); - get_long_prod(); -// Update_SR_Register64(prod); - Update_SR_Register64(); - } + if (FlagsNeeded()) + { + // s64 prod = dsp_get_long_prod(); + get_long_prod(); + // Update_SR_Register64(prod); + Update_SR_Register64(); + } } //---- @@ -178,17 +176,17 @@ void DSPEmitter::tstprod(const UDSPInstruction opc) // flags out: --xx xx0x void DSPEmitter::movp(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; -// s64 acc = dsp_get_long_prod(); - get_long_prod(); -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg); -// Update_SR_Register64(acc); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // s64 acc = dsp_get_long_prod(); + get_long_prod(); + // dsp_set_long_acc(dreg, acc); + set_long_acc(dreg); + // Update_SR_Register64(acc); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // MOVNP $acD @@ -199,18 +197,18 @@ void DSPEmitter::movp(const UDSPInstruction opc) // flags out: --xx xx0x void DSPEmitter::movnp(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; + u8 dreg = (opc >> 8) & 0x1; -// s64 acc = -dsp_get_long_prod(); - get_long_prod(); - NEG(64, R(EAX)); -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg); -// Update_SR_Register64(acc); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // s64 acc = -dsp_get_long_prod(); + get_long_prod(); + NEG(64, R(EAX)); + // dsp_set_long_acc(dreg, acc); + set_long_acc(dreg); + // Update_SR_Register64(acc); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // MOVPZ $acD @@ -221,17 +219,17 @@ void DSPEmitter::movnp(const UDSPInstruction opc) // flags out: --xx xx0x void DSPEmitter::movpz(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x01; + u8 dreg = (opc >> 8) & 0x01; -// s64 acc = dsp_get_long_prod_round_prodl(); - get_long_prod_round_prodl(); -// dsp_set_long_acc(dreg, acc); - set_long_acc(dreg); -// Update_SR_Register64(acc); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // s64 acc = dsp_get_long_prod_round_prodl(); + get_long_prod_round_prodl(); + // dsp_set_long_acc(dreg, acc); + set_long_acc(dreg); + // Update_SR_Register64(acc); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // ADDPAXZ $acD, $axS @@ -242,36 +240,36 @@ void DSPEmitter::movpz(const UDSPInstruction opc) // flags out: --xx xx0x void DSPEmitter::addpaxz(const UDSPInstruction opc) { - u8 dreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; -// s64 ax = dsp_get_long_acx(sreg); - X64Reg tmp1 = gpr.GetFreeXReg(); - get_long_acx(sreg, tmp1); - MOV(64, R(RDX), R(tmp1)); -// s64 res = prod + (ax & ~0xffff); - MOV(64, R(RAX), Imm64(~0xffff)); - AND(64, R(RDX), R(RAX)); -// s64 prod = dsp_get_long_prod_round_prodl(); - get_long_prod_round_prodl(); - ADD(64, R(RAX), R(RDX)); + // s64 ax = dsp_get_long_acx(sreg); + X64Reg tmp1 = gpr.GetFreeXReg(); + get_long_acx(sreg, tmp1); + MOV(64, R(RDX), R(tmp1)); + // s64 res = prod + (ax & ~0xffff); + MOV(64, R(RAX), Imm64(~0xffff)); + AND(64, R(RDX), R(RAX)); + // s64 prod = dsp_get_long_prod_round_prodl(); + get_long_prod_round_prodl(); + ADD(64, R(RAX), R(RDX)); -// s64 oldprod = dsp_get_long_prod(); -// dsp_set_long_acc(dreg, res); -// res = dsp_get_long_acc(dreg); -// Update_SR_Register64(res, isCarry(oldprod, res), false); - if (FlagsNeeded()) - { - get_long_prod(RDX); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); - } - else - { - set_long_acc(dreg, RAX); - } - gpr.PutXReg(tmp1); + // s64 oldprod = dsp_get_long_prod(); + // dsp_set_long_acc(dreg, res); + // res = dsp_get_long_acc(dreg); + // Update_SR_Register64(res, isCarry(oldprod, res), false); + if (FlagsNeeded()) + { + get_long_prod(RDX); + MOV(64, R(RCX), R(RAX)); + set_long_acc(dreg, RCX); + Update_SR_Register64_Carry(EAX, tmp1); + } + else + { + set_long_acc(dreg, RAX); + } + gpr.PutXReg(tmp1); } //---- @@ -281,12 +279,12 @@ void DSPEmitter::addpaxz(const UDSPInstruction opc) // Multiply $ax0.h by $ax0.h void DSPEmitter::mulaxh(const UDSPInstruction opc) { -// s64 prod = dsp_multiply(dsp_get_ax_h(0), dsp_get_ax_h(0)); - dsp_op_read_reg(DSP_REG_AXH0, RCX, SIGN); - MOV(64, R(RAX), R(RCX)); - multiply(); -// dsp_set_long_prod(prod); - set_long_prod(); + // s64 prod = dsp_multiply(dsp_get_ax_h(0), dsp_get_ax_h(0)); + dsp_op_read_reg(DSP_REG_AXH0, RCX, SIGN); + MOV(64, R(RAX), R(RCX)); + multiply(); + // dsp_set_long_prod(prod); + set_long_prod(); } //---- @@ -297,16 +295,16 @@ void DSPEmitter::mulaxh(const UDSPInstruction opc) // $axS.h of secondary accumulator $axS (treat them both as signed). void DSPEmitter::mul(const UDSPInstruction opc) { - u8 sreg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 11) & 0x1; -// u16 axl = dsp_get_ax_l(sreg); - dsp_op_read_reg(DSP_REG_AXL0+sreg, RCX, SIGN); -// u16 axh = dsp_get_ax_h(sreg); - dsp_op_read_reg(DSP_REG_AXH0+sreg, RAX, SIGN); -// s64 prod = dsp_multiply(axh, axl); - multiply(); -// dsp_set_long_prod(prod); - set_long_prod(); + // u16 axl = dsp_get_ax_l(sreg); + dsp_op_read_reg(DSP_REG_AXL0 + sreg, RCX, SIGN); + // u16 axh = dsp_get_ax_h(sreg); + dsp_op_read_reg(DSP_REG_AXH0 + sreg, RAX, SIGN); + // s64 prod = dsp_multiply(axh, axl); + multiply(); + // dsp_set_long_prod(prod); + set_long_prod(); } // MULAC $axS.l, $axS.h, $acR @@ -318,31 +316,31 @@ void DSPEmitter::mul(const UDSPInstruction opc) // flags out: --xx xx0x void DSPEmitter::mulac(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 11) & 0x1; + u8 rreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 11) & 0x1; -// s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - get_long_acc(rreg); - MOV(64, R(RDX), R(RAX)); - get_long_prod(); - ADD(64, R(RAX), R(RDX)); - PUSH(64, R(RAX)); -// u16 axl = dsp_get_ax_l(sreg); - dsp_op_read_reg(DSP_REG_AXL0+sreg, RCX, SIGN); -// u16 axh = dsp_get_ax_h(sreg); - dsp_op_read_reg(DSP_REG_AXH0+sreg, RAX, SIGN); -// s64 prod = dsp_multiply(axl, axh); - multiply(); -// dsp_set_long_prod(prod); - set_long_prod(); -// dsp_set_long_acc(rreg, acc); - POP(64, R(RAX)); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + get_long_acc(rreg); + MOV(64, R(RDX), R(RAX)); + get_long_prod(); + ADD(64, R(RAX), R(RDX)); + PUSH(64, R(RAX)); + // u16 axl = dsp_get_ax_l(sreg); + dsp_op_read_reg(DSP_REG_AXL0 + sreg, RCX, SIGN); + // u16 axh = dsp_get_ax_h(sreg); + dsp_op_read_reg(DSP_REG_AXH0 + sreg, RAX, SIGN); + // s64 prod = dsp_multiply(axl, axh); + multiply(); + // dsp_set_long_prod(prod); + set_long_prod(); + // dsp_set_long_acc(rreg, acc); + POP(64, R(RAX)); + set_long_acc(rreg); + // Update_SR_Register64(dsp_get_long_acc(rreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // MULMV $axS.l, $axS.h, $acR @@ -354,20 +352,20 @@ void DSPEmitter::mulac(const UDSPInstruction opc) // flags out: --xx xx0x void DSPEmitter::mulmv(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; + u8 rreg = (opc >> 8) & 0x1; -// s64 acc = dsp_get_long_prod(); - get_long_prod(); - PUSH(64, R(RAX)); - mul(opc); -// dsp_set_long_acc(rreg, acc); - POP(64, R(RAX)); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // s64 acc = dsp_get_long_prod(); + get_long_prod(); + PUSH(64, R(RAX)); + mul(opc); + // dsp_set_long_acc(rreg, acc); + POP(64, R(RAX)); + set_long_acc(rreg); + // Update_SR_Register64(dsp_get_long_acc(rreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // MULMVZ $axS.l, $axS.h, $acR @@ -380,18 +378,18 @@ void DSPEmitter::mulmv(const UDSPInstruction opc) // flags out: --xx xx0x void DSPEmitter::mulmvz(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; + u8 rreg = (opc >> 8) & 0x1; -// s64 acc = dsp_get_long_prod_round_prodl(); - get_long_prod_round_prodl(RDX); -// dsp_set_long_acc(rreg, acc); - set_long_acc(rreg, RDX); - mul(opc); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(RDX); - } + // s64 acc = dsp_get_long_prod_round_prodl(); + get_long_prod_round_prodl(RDX); + // dsp_set_long_acc(rreg, acc); + set_long_acc(rreg, RDX); + mul(opc); + // Update_SR_Register64(dsp_get_long_acc(rreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(RDX); + } } //---- @@ -402,17 +400,17 @@ void DSPEmitter::mulmvz(const UDSPInstruction opc) // Part is selected by S and T bits. Zero selects low part, one selects high part. void DSPEmitter::mulx(const UDSPInstruction opc) { - u8 treg = ((opc >> 11) & 0x1); - u8 sreg = ((opc >> 12) & 0x1); + u8 treg = ((opc >> 11) & 0x1); + u8 sreg = ((opc >> 12) & 0x1); -// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RCX, SIGN); -// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RAX, SIGN); -// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - multiply_mulx(sreg, treg); -// dsp_set_long_prod(prod); - set_long_prod(); + // u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + dsp_op_read_reg(DSP_REG_AXL0 + sreg * 2, RCX, SIGN); + // u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + dsp_op_read_reg(DSP_REG_AXL1 + treg * 2, RAX, SIGN); + // s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + multiply_mulx(sreg, treg); + // dsp_set_long_prod(prod); + set_long_prod(); } // MULXAC $ax0.S, $ax1.T, $acR @@ -424,32 +422,32 @@ void DSPEmitter::mulx(const UDSPInstruction opc) // flags out: --xx xx0x void DSPEmitter::mulxac(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; -// s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - X64Reg tmp1 = gpr.GetFreeXReg(); - get_long_acc(rreg, tmp1); - get_long_prod(); - ADD(64, R(tmp1), R(RAX)); -// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RCX, SIGN); -// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RAX, SIGN); -// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - multiply_mulx(sreg, treg); + // s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + X64Reg tmp1 = gpr.GetFreeXReg(); + get_long_acc(rreg, tmp1); + get_long_prod(); + ADD(64, R(tmp1), R(RAX)); + // u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + dsp_op_read_reg(DSP_REG_AXL0 + sreg * 2, RCX, SIGN); + // u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + dsp_op_read_reg(DSP_REG_AXL1 + treg * 2, RAX, SIGN); + // s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + multiply_mulx(sreg, treg); -// dsp_set_long_prod(prod); - set_long_prod(); -// dsp_set_long_acc(rreg, acc); - set_long_acc(rreg, tmp1); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(tmp1); - } - gpr.PutXReg(tmp1); + // dsp_set_long_prod(prod); + set_long_prod(); + // dsp_set_long_acc(rreg, acc); + set_long_acc(rreg, tmp1); + // Update_SR_Register64(dsp_get_long_acc(rreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(tmp1); + } + gpr.PutXReg(tmp1); } // MULXMV $ax0.S, $ax1.T, $acR @@ -461,30 +459,30 @@ void DSPEmitter::mulxac(const UDSPInstruction opc) // flags out: --xx xx0x void DSPEmitter::mulxmv(const UDSPInstruction opc) { - u8 rreg = ((opc >> 8) & 0x1); - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; + u8 rreg = ((opc >> 8) & 0x1); + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; -// s64 acc = dsp_get_long_prod(); - X64Reg tmp1 = gpr.GetFreeXReg(); - get_long_prod(tmp1); -// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RCX, SIGN); -// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RAX, SIGN); -// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - multiply_mulx(sreg, treg); + // s64 acc = dsp_get_long_prod(); + X64Reg tmp1 = gpr.GetFreeXReg(); + get_long_prod(tmp1); + // u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + dsp_op_read_reg(DSP_REG_AXL0 + sreg * 2, RCX, SIGN); + // u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + dsp_op_read_reg(DSP_REG_AXL1 + treg * 2, RAX, SIGN); + // s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + multiply_mulx(sreg, treg); -// dsp_set_long_prod(prod); - set_long_prod(); -// dsp_set_long_acc(rreg, acc); - set_long_acc(rreg, tmp1); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(tmp1); - } - gpr.PutXReg(tmp1); + // dsp_set_long_prod(prod); + set_long_prod(); + // dsp_set_long_acc(rreg, acc); + set_long_acc(rreg, tmp1); + // Update_SR_Register64(dsp_get_long_acc(rreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(tmp1); + } + gpr.PutXReg(tmp1); } // MULXMV $ax0.S, $ax1.T, $acR @@ -497,30 +495,30 @@ void DSPEmitter::mulxmv(const UDSPInstruction opc) // flags out: --xx xx0x void DSPEmitter::mulxmvz(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; -// s64 acc = dsp_get_long_prod_round_prodl(); - X64Reg tmp1 = gpr.GetFreeXReg(); - get_long_prod_round_prodl(tmp1); -// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RCX, SIGN); -// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RAX, SIGN); -// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); - multiply_mulx(sreg, treg); + // s64 acc = dsp_get_long_prod_round_prodl(); + X64Reg tmp1 = gpr.GetFreeXReg(); + get_long_prod_round_prodl(tmp1); + // u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + dsp_op_read_reg(DSP_REG_AXL0 + sreg * 2, RCX, SIGN); + // u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + dsp_op_read_reg(DSP_REG_AXL1 + treg * 2, RAX, SIGN); + // s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2); + multiply_mulx(sreg, treg); -// dsp_set_long_prod(prod); - set_long_prod(); -// dsp_set_long_acc(rreg, acc); - set_long_acc(rreg, tmp1); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(tmp1); - } - gpr.PutXReg(tmp1); + // dsp_set_long_prod(prod); + set_long_prod(); + // dsp_set_long_acc(rreg, acc); + set_long_acc(rreg, tmp1); + // Update_SR_Register64(dsp_get_long_acc(rreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(tmp1); + } + gpr.PutXReg(tmp1); } //---- @@ -531,17 +529,17 @@ void DSPEmitter::mulxmvz(const UDSPInstruction opc) // secondary accumulator $axS (treat them both as signed). void DSPEmitter::mulc(const UDSPInstruction opc) { - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; -// u16 accm = dsp_get_acc_m(sreg); - get_acc_m(sreg, ECX); -// u16 axh = dsp_get_ax_h(treg); - dsp_op_read_reg(DSP_REG_AXH0+treg, RAX, SIGN); -// s64 prod = dsp_multiply(accm, axh); - multiply(); -// dsp_set_long_prod(prod); - set_long_prod(); + // u16 accm = dsp_get_acc_m(sreg); + get_acc_m(sreg, ECX); + // u16 axh = dsp_get_ax_h(treg); + dsp_op_read_reg(DSP_REG_AXH0 + treg, RAX, SIGN); + // s64 prod = dsp_multiply(accm, axh); + multiply(); + // dsp_set_long_prod(prod); + set_long_prod(); } // MULCAC $acS.m, $axT.h, $acR @@ -553,32 +551,32 @@ void DSPEmitter::mulc(const UDSPInstruction opc) // flags out: --xx xx0x void DSPEmitter::mulcac(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; -// s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - get_long_acc(rreg); - MOV(64, R(RDX), R(RAX)); - get_long_prod(); - ADD(64, R(RAX), R(RDX)); - PUSH(64, R(RAX)); -// u16 accm = dsp_get_acc_m(sreg); - get_acc_m(sreg, ECX); -// u16 axh = dsp_get_ax_h(treg); - dsp_op_read_reg(DSP_REG_AXH0+treg, RAX, SIGN); -// s64 prod = dsp_multiply(accm, axh); - multiply(); -// dsp_set_long_prod(prod); - set_long_prod(); -// dsp_set_long_acc(rreg, acc); - POP(64, R(RAX)); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + get_long_acc(rreg); + MOV(64, R(RDX), R(RAX)); + get_long_prod(); + ADD(64, R(RAX), R(RDX)); + PUSH(64, R(RAX)); + // u16 accm = dsp_get_acc_m(sreg); + get_acc_m(sreg, ECX); + // u16 axh = dsp_get_ax_h(treg); + dsp_op_read_reg(DSP_REG_AXH0 + treg, RAX, SIGN); + // s64 prod = dsp_multiply(accm, axh); + multiply(); + // dsp_set_long_prod(prod); + set_long_prod(); + // dsp_set_long_acc(rreg, acc); + POP(64, R(RAX)); + set_long_acc(rreg); + // Update_SR_Register64(dsp_get_long_acc(rreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // MULCMV $acS.m, $axT.h, $acR @@ -591,29 +589,29 @@ void DSPEmitter::mulcac(const UDSPInstruction opc) // flags out: --xx xx0x void DSPEmitter::mulcmv(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; -// s64 acc = dsp_get_long_prod(); - get_long_prod(); - PUSH(64, R(RAX)); -// u16 accm = dsp_get_acc_m(sreg); - get_acc_m(sreg, ECX); -// u16 axh = dsp_get_ax_h(treg); - dsp_op_read_reg(DSP_REG_AXH0+treg, RAX, SIGN); -// s64 prod = dsp_multiply(accm, axh); - multiply(); -// dsp_set_long_prod(prod); - set_long_prod(); -// dsp_set_long_acc(rreg, acc); - POP(64, R(RAX)); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // s64 acc = dsp_get_long_prod(); + get_long_prod(); + PUSH(64, R(RAX)); + // u16 accm = dsp_get_acc_m(sreg); + get_acc_m(sreg, ECX); + // u16 axh = dsp_get_ax_h(treg); + dsp_op_read_reg(DSP_REG_AXH0 + treg, RAX, SIGN); + // s64 prod = dsp_multiply(accm, axh); + multiply(); + // dsp_set_long_prod(prod); + set_long_prod(); + // dsp_set_long_acc(rreg, acc); + POP(64, R(RAX)); + set_long_acc(rreg); + // Update_SR_Register64(dsp_get_long_acc(rreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } // MULCMVZ $acS.m, $axT.h, $acR @@ -627,29 +625,29 @@ void DSPEmitter::mulcmv(const UDSPInstruction opc) // flags out: --xx xx0x void DSPEmitter::mulcmvz(const UDSPInstruction opc) { - u8 rreg = (opc >> 8) & 0x1; - u8 treg = (opc >> 11) & 0x1; - u8 sreg = (opc >> 12) & 0x1; + u8 rreg = (opc >> 8) & 0x1; + u8 treg = (opc >> 11) & 0x1; + u8 sreg = (opc >> 12) & 0x1; -// s64 acc = dsp_get_long_prod_round_prodl(); - get_long_prod_round_prodl(); - PUSH(64, R(RAX)); -// u16 accm = dsp_get_acc_m(sreg); - get_acc_m(sreg, ECX); -// u16 axh = dsp_get_ax_h(treg); - dsp_op_read_reg(DSP_REG_AXH0+treg, RAX, SIGN); -// s64 prod = dsp_multiply(accm, axh); - multiply(); -// dsp_set_long_prod(prod); - set_long_prod(); -// dsp_set_long_acc(rreg, acc); - POP(64, R(RAX)); - set_long_acc(rreg); -// Update_SR_Register64(dsp_get_long_acc(rreg)); - if (FlagsNeeded()) - { - Update_SR_Register64(); - } + // s64 acc = dsp_get_long_prod_round_prodl(); + get_long_prod_round_prodl(); + PUSH(64, R(RAX)); + // u16 accm = dsp_get_acc_m(sreg); + get_acc_m(sreg, ECX); + // u16 axh = dsp_get_ax_h(treg); + dsp_op_read_reg(DSP_REG_AXH0 + treg, RAX, SIGN); + // s64 prod = dsp_multiply(accm, axh); + multiply(); + // dsp_set_long_prod(prod); + set_long_prod(); + // dsp_set_long_acc(rreg, acc); + POP(64, R(RAX)); + set_long_acc(rreg); + // Update_SR_Register64(dsp_get_long_acc(rreg)); + if (FlagsNeeded()) + { + Update_SR_Register64(); + } } //---- @@ -661,17 +659,17 @@ void DSPEmitter::mulcmvz(const UDSPInstruction opc) // signed) and add result to product register. void DSPEmitter::maddx(const UDSPInstruction opc) { - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; - // u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RCX, SIGN); - // u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RAX, SIGN); - // s64 prod = dsp_multiply_add(val1, val2); - multiply_add(); - // dsp_set_long_prod(prod); - set_long_prod(); + // u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + dsp_op_read_reg(DSP_REG_AXL0 + sreg * 2, RCX, SIGN); + // u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + dsp_op_read_reg(DSP_REG_AXL1 + treg * 2, RAX, SIGN); + // s64 prod = dsp_multiply_add(val1, val2); + multiply_add(); + // dsp_set_long_prod(prod); + set_long_prod(); } // MSUBX $(0x18+S*2), $(0x19+T*2) @@ -681,17 +679,17 @@ void DSPEmitter::maddx(const UDSPInstruction opc) // signed) and subtract result from product register. void DSPEmitter::msubx(const UDSPInstruction opc) { - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; - // u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - dsp_op_read_reg(DSP_REG_AXL0 + sreg*2, RCX, SIGN); - // u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - dsp_op_read_reg(DSP_REG_AXL1 + treg*2, RAX, SIGN); - // s64 prod = dsp_multiply_sub(val1, val2); - multiply_sub(); - // dsp_set_long_prod(prod); - set_long_prod(); + // u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + dsp_op_read_reg(DSP_REG_AXL0 + sreg * 2, RCX, SIGN); + // u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + dsp_op_read_reg(DSP_REG_AXL1 + treg * 2, RAX, SIGN); + // s64 prod = dsp_multiply_sub(val1, val2); + multiply_sub(); + // dsp_set_long_prod(prod); + set_long_prod(); } // MADDC $acS.m, $axT.h @@ -701,17 +699,17 @@ void DSPEmitter::msubx(const UDSPInstruction opc) // register. void DSPEmitter::maddc(const UDSPInstruction opc) { - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; -// u16 accm = dsp_get_acc_m(sreg); - get_acc_m(sreg, ECX); -// u16 axh = dsp_get_ax_h(treg); - dsp_op_read_reg(DSP_REG_AXH0+treg, RAX, SIGN); -// s64 prod = dsp_multiply_add(accm, axh); - multiply_add(); -// dsp_set_long_prod(prod); - set_long_prod(); + // u16 accm = dsp_get_acc_m(sreg); + get_acc_m(sreg, ECX); + // u16 axh = dsp_get_ax_h(treg); + dsp_op_read_reg(DSP_REG_AXH0 + treg, RAX, SIGN); + // s64 prod = dsp_multiply_add(accm, axh); + multiply_add(); + // dsp_set_long_prod(prod); + set_long_prod(); } // MSUBC $acS.m, $axT.h @@ -721,17 +719,17 @@ void DSPEmitter::maddc(const UDSPInstruction opc) // product register. void DSPEmitter::msubc(const UDSPInstruction opc) { - u8 treg = (opc >> 8) & 0x1; - u8 sreg = (opc >> 9) & 0x1; + u8 treg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 9) & 0x1; -// u16 accm = dsp_get_acc_m(sreg); - get_acc_m(sreg, ECX); -// u16 axh = dsp_get_ax_h(treg); - dsp_op_read_reg(DSP_REG_AXH0+treg, RAX, SIGN); -// s64 prod = dsp_multiply_sub(accm, axh); - multiply_sub(); -// dsp_set_long_prod(prod); - set_long_prod(); + // u16 accm = dsp_get_acc_m(sreg); + get_acc_m(sreg, ECX); + // u16 axh = dsp_get_ax_h(treg); + dsp_op_read_reg(DSP_REG_AXH0 + treg, RAX, SIGN); + // s64 prod = dsp_multiply_sub(accm, axh); + multiply_sub(); + // dsp_set_long_prod(prod); + set_long_prod(); } // MADD $axS.l, $axS.h @@ -741,16 +739,16 @@ void DSPEmitter::msubc(const UDSPInstruction opc) // result to product register. void DSPEmitter::madd(const UDSPInstruction opc) { - u8 sreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 8) & 0x1; -// u16 axl = dsp_get_ax_l(sreg); - dsp_op_read_reg(DSP_REG_AXL0+sreg, RCX, SIGN); -// u16 axh = dsp_get_ax_h(sreg); - dsp_op_read_reg(DSP_REG_AXH0+sreg, RAX, SIGN); -// s64 prod = dsp_multiply_add(axl, axh); - multiply_add(); -// dsp_set_long_prod(prod); - set_long_prod(); + // u16 axl = dsp_get_ax_l(sreg); + dsp_op_read_reg(DSP_REG_AXL0 + sreg, RCX, SIGN); + // u16 axh = dsp_get_ax_h(sreg); + dsp_op_read_reg(DSP_REG_AXH0 + sreg, RAX, SIGN); + // s64 prod = dsp_multiply_add(axl, axh); + multiply_add(); + // dsp_set_long_prod(prod); + set_long_prod(); } // MSUB $axS.l, $axS.h @@ -760,14 +758,14 @@ void DSPEmitter::madd(const UDSPInstruction opc) // subtract result from product register. void DSPEmitter::msub(const UDSPInstruction opc) { - u8 sreg = (opc >> 8) & 0x1; + u8 sreg = (opc >> 8) & 0x1; -// u16 axl = dsp_get_ax_l(sreg); - dsp_op_read_reg(DSP_REG_AXL0+sreg, RCX, SIGN); -// u16 axh = dsp_get_ax_h(sreg); - dsp_op_read_reg(DSP_REG_AXH0+sreg, RAX, SIGN); -// s64 prod = dsp_multiply_sub(axl, axh); - multiply_sub(); -// dsp_set_long_prod(prod); - set_long_prod(); + // u16 axl = dsp_get_ax_l(sreg); + dsp_op_read_reg(DSP_REG_AXL0 + sreg, RCX, SIGN); + // u16 axh = dsp_get_ax_h(sreg); + dsp_op_read_reg(DSP_REG_AXH0 + sreg, RAX, SIGN); + // s64 prod = dsp_multiply_sub(axl, axh); + multiply_sub(); + // dsp_set_long_prod(prod); + set_long_prod(); } diff --git a/Source/Core/Core/DSP/Jit/DSPJitRegCache.cpp b/Source/Core/Core/DSP/Jit/DSPJitRegCache.cpp index 869fbffbb8..f7f6ea1603 100644 --- a/Source/Core/Core/DSP/Jit/DSPJitRegCache.cpp +++ b/Source/Core/Core/DSP/Jit/DSPJitRegCache.cpp @@ -12,1062 +12,994 @@ using namespace Gen; // Ordered in order of prefered use. // Not all of these are actually available -const std::array DSPJitRegCache::m_allocation_order = {{ - R8, R9, R10, R11, R12, R13, R14, R15, RSI, RDI, RBX, RCX, RDX, RAX, RBP -}}; +const std::array DSPJitRegCache::m_allocation_order = { + {R8, R9, R10, R11, R12, R13, R14, R15, RSI, RDI, RBX, RCX, RDX, RAX, RBP}}; static void* GetRegisterPointer(size_t reg) { - switch (reg) - { - case DSP_REG_AR0: - case DSP_REG_AR1: - case DSP_REG_AR2: - case DSP_REG_AR3: - return &g_dsp.r.ar[reg - DSP_REG_AR0]; - case DSP_REG_IX0: - case DSP_REG_IX1: - case DSP_REG_IX2: - case DSP_REG_IX3: - return &g_dsp.r.ix[reg - DSP_REG_IX0]; - case DSP_REG_WR0: - case DSP_REG_WR1: - case DSP_REG_WR2: - case DSP_REG_WR3: - return &g_dsp.r.wr[reg - DSP_REG_WR0]; - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - return &g_dsp.r.st[reg - DSP_REG_ST0]; - case DSP_REG_ACH0: - case DSP_REG_ACH1: - return &g_dsp.r.ac[reg - DSP_REG_ACH0].h; - case DSP_REG_CR: - return &g_dsp.r.cr; - case DSP_REG_SR: - return &g_dsp.r.sr; - case DSP_REG_PRODL: - return &g_dsp.r.prod.l; - case DSP_REG_PRODM: - return &g_dsp.r.prod.m; - case DSP_REG_PRODH: - return &g_dsp.r.prod.h; - case DSP_REG_PRODM2: - return &g_dsp.r.prod.m2; - case DSP_REG_AXL0: - case DSP_REG_AXL1: - return &g_dsp.r.ax[reg - DSP_REG_AXL0].l; - case DSP_REG_AXH0: - case DSP_REG_AXH1: - return &g_dsp.r.ax[reg - DSP_REG_AXH0].h; - case DSP_REG_ACL0: - case DSP_REG_ACL1: - return &g_dsp.r.ac[reg - DSP_REG_ACL0].l; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - return &g_dsp.r.ac[reg - DSP_REG_ACM0].m; - case DSP_REG_AX0_32: - case DSP_REG_AX1_32: - return &g_dsp.r.ax[reg - DSP_REG_AX0_32].val; - case DSP_REG_ACC0_64: - case DSP_REG_ACC1_64: - return &g_dsp.r.ac[reg - DSP_REG_ACC0_64].val; - case DSP_REG_PROD_64: - return &g_dsp.r.prod.val; - default: - _assert_msg_(DSPLLE, 0, "cannot happen"); - return nullptr; - } + switch (reg) + { + case DSP_REG_AR0: + case DSP_REG_AR1: + case DSP_REG_AR2: + case DSP_REG_AR3: + return &g_dsp.r.ar[reg - DSP_REG_AR0]; + case DSP_REG_IX0: + case DSP_REG_IX1: + case DSP_REG_IX2: + case DSP_REG_IX3: + return &g_dsp.r.ix[reg - DSP_REG_IX0]; + case DSP_REG_WR0: + case DSP_REG_WR1: + case DSP_REG_WR2: + case DSP_REG_WR3: + return &g_dsp.r.wr[reg - DSP_REG_WR0]; + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + return &g_dsp.r.st[reg - DSP_REG_ST0]; + case DSP_REG_ACH0: + case DSP_REG_ACH1: + return &g_dsp.r.ac[reg - DSP_REG_ACH0].h; + case DSP_REG_CR: + return &g_dsp.r.cr; + case DSP_REG_SR: + return &g_dsp.r.sr; + case DSP_REG_PRODL: + return &g_dsp.r.prod.l; + case DSP_REG_PRODM: + return &g_dsp.r.prod.m; + case DSP_REG_PRODH: + return &g_dsp.r.prod.h; + case DSP_REG_PRODM2: + return &g_dsp.r.prod.m2; + case DSP_REG_AXL0: + case DSP_REG_AXL1: + return &g_dsp.r.ax[reg - DSP_REG_AXL0].l; + case DSP_REG_AXH0: + case DSP_REG_AXH1: + return &g_dsp.r.ax[reg - DSP_REG_AXH0].h; + case DSP_REG_ACL0: + case DSP_REG_ACL1: + return &g_dsp.r.ac[reg - DSP_REG_ACL0].l; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + return &g_dsp.r.ac[reg - DSP_REG_ACM0].m; + case DSP_REG_AX0_32: + case DSP_REG_AX1_32: + return &g_dsp.r.ax[reg - DSP_REG_AX0_32].val; + case DSP_REG_ACC0_64: + case DSP_REG_ACC1_64: + return &g_dsp.r.ac[reg - DSP_REG_ACC0_64].val; + case DSP_REG_PROD_64: + return &g_dsp.r.prod.val; + default: + _assert_msg_(DSPLLE, 0, "cannot happen"); + return nullptr; + } } #define STATIC_REG_ACCS //#undef STATIC_REG_ACCS -DSPJitRegCache::DSPJitRegCache(DSPEmitter &_emitter) - : emitter(_emitter), temporary(false), merged(false) +DSPJitRegCache::DSPJitRegCache(DSPEmitter& _emitter) + : emitter(_emitter), temporary(false), merged(false) { - for (X64CachedReg& xreg : xregs) - { - xreg.guest_reg = DSP_REG_STATIC; - xreg.pushed = false; - } + for (X64CachedReg& xreg : xregs) + { + xreg.guest_reg = DSP_REG_STATIC; + xreg.pushed = false; + } - xregs[RAX].guest_reg = DSP_REG_STATIC; // reserved for MUL/DIV - xregs[RDX].guest_reg = DSP_REG_STATIC; // reserved for MUL/DIV - xregs[RCX].guest_reg = DSP_REG_STATIC; // reserved for shifts + xregs[RAX].guest_reg = DSP_REG_STATIC; // reserved for MUL/DIV + xregs[RDX].guest_reg = DSP_REG_STATIC; // reserved for MUL/DIV + xregs[RCX].guest_reg = DSP_REG_STATIC; // reserved for shifts - xregs[RBX].guest_reg = DSP_REG_STATIC; // extended op backing store + xregs[RBX].guest_reg = DSP_REG_STATIC; // extended op backing store - xregs[RSP].guest_reg = DSP_REG_STATIC; // stack pointer + xregs[RSP].guest_reg = DSP_REG_STATIC; // stack pointer - xregs[RBP].guest_reg = DSP_REG_NONE; // definitely usable in dsplle because - // all external calls are protected + xregs[RBP].guest_reg = DSP_REG_NONE; // definitely usable in dsplle because + // all external calls are protected - xregs[RSI].guest_reg = DSP_REG_NONE; - xregs[RDI].guest_reg = DSP_REG_NONE; + xregs[RSI].guest_reg = DSP_REG_NONE; + xregs[RDI].guest_reg = DSP_REG_NONE; #ifdef STATIC_REG_ACCS - xregs[R8].guest_reg = DSP_REG_STATIC; //acc0 - xregs[R9].guest_reg = DSP_REG_STATIC; //acc1 + xregs[R8].guest_reg = DSP_REG_STATIC; // acc0 + xregs[R9].guest_reg = DSP_REG_STATIC; // acc1 #else - xregs[R8].guest_reg = DSP_REG_NONE; - xregs[R9].guest_reg = DSP_REG_NONE; + xregs[R8].guest_reg = DSP_REG_NONE; + xregs[R9].guest_reg = DSP_REG_NONE; #endif - xregs[R10].guest_reg = DSP_REG_NONE; - xregs[R11].guest_reg = DSP_REG_NONE; - xregs[R12].guest_reg = DSP_REG_NONE; - xregs[R13].guest_reg = DSP_REG_NONE; - xregs[R14].guest_reg = DSP_REG_NONE; - xregs[R15].guest_reg = DSP_REG_NONE; + xregs[R10].guest_reg = DSP_REG_NONE; + xregs[R11].guest_reg = DSP_REG_NONE; + xregs[R12].guest_reg = DSP_REG_NONE; + xregs[R13].guest_reg = DSP_REG_NONE; + xregs[R14].guest_reg = DSP_REG_NONE; + xregs[R15].guest_reg = DSP_REG_NONE; - for (size_t i = 0; i < regs.size(); i++) - { - regs[i].mem = GetRegisterPointer(i); - regs[i].size = 0; - regs[i].dirty = false; - regs[i].used = false; - regs[i].last_use_ctr = -1; - regs[i].parentReg = DSP_REG_NONE; - regs[i].shift = 0; - regs[i].host_reg = INVALID_REG; - regs[i].loc = M(regs[i].mem); - } + for (size_t i = 0; i < regs.size(); i++) + { + regs[i].mem = GetRegisterPointer(i); + regs[i].size = 0; + regs[i].dirty = false; + regs[i].used = false; + regs[i].last_use_ctr = -1; + regs[i].parentReg = DSP_REG_NONE; + regs[i].shift = 0; + regs[i].host_reg = INVALID_REG; + regs[i].loc = M(regs[i].mem); + } - for (unsigned int i = 0; i < 32; i++) - { - regs[i].size = 2; - } - //special composite registers + for (unsigned int i = 0; i < 32; i++) + { + regs[i].size = 2; + } +// special composite registers #ifdef STATIC_REG_ACCS - regs[DSP_REG_ACC0_64].host_reg = R8; - regs[DSP_REG_ACC1_64].host_reg = R9; + regs[DSP_REG_ACC0_64].host_reg = R8; + regs[DSP_REG_ACC1_64].host_reg = R9; #endif - for (unsigned int i = 0; i < 2; i++) - { - regs[i+DSP_REG_ACC0_64].size = 8; - regs[i+DSP_REG_ACL0].parentReg = i+DSP_REG_ACC0_64; - regs[i+DSP_REG_ACM0].parentReg = i+DSP_REG_ACC0_64; - regs[i+DSP_REG_ACH0].parentReg = i+DSP_REG_ACC0_64; - regs[i+DSP_REG_ACL0].shift = 0; - regs[i+DSP_REG_ACM0].shift = 16; - regs[i+DSP_REG_ACH0].shift = 32; - } + for (unsigned int i = 0; i < 2; i++) + { + regs[i + DSP_REG_ACC0_64].size = 8; + regs[i + DSP_REG_ACL0].parentReg = i + DSP_REG_ACC0_64; + regs[i + DSP_REG_ACM0].parentReg = i + DSP_REG_ACC0_64; + regs[i + DSP_REG_ACH0].parentReg = i + DSP_REG_ACC0_64; + regs[i + DSP_REG_ACL0].shift = 0; + regs[i + DSP_REG_ACM0].shift = 16; + regs[i + DSP_REG_ACH0].shift = 32; + } - regs[DSP_REG_PROD_64].size = 8; - regs[DSP_REG_PRODL].parentReg = DSP_REG_PROD_64; - regs[DSP_REG_PRODM].parentReg = DSP_REG_PROD_64; - regs[DSP_REG_PRODH].parentReg = DSP_REG_PROD_64; - regs[DSP_REG_PRODM2].parentReg = DSP_REG_PROD_64; - regs[DSP_REG_PRODL].shift = 0; - regs[DSP_REG_PRODM].shift = 16; - regs[DSP_REG_PRODH].shift = 32; - regs[DSP_REG_PRODM2].shift = 48; + regs[DSP_REG_PROD_64].size = 8; + regs[DSP_REG_PRODL].parentReg = DSP_REG_PROD_64; + regs[DSP_REG_PRODM].parentReg = DSP_REG_PROD_64; + regs[DSP_REG_PRODH].parentReg = DSP_REG_PROD_64; + regs[DSP_REG_PRODM2].parentReg = DSP_REG_PROD_64; + regs[DSP_REG_PRODL].shift = 0; + regs[DSP_REG_PRODM].shift = 16; + regs[DSP_REG_PRODH].shift = 32; + regs[DSP_REG_PRODM2].shift = 48; - for (unsigned int i = 0; i < 2; i++) - { - regs[i+DSP_REG_AX0_32].size = 4; - regs[i+DSP_REG_AXL0].parentReg = i+DSP_REG_AX0_32; - regs[i+DSP_REG_AXH0].parentReg = i+DSP_REG_AX0_32; - regs[i+DSP_REG_AXL0].shift = 0; - regs[i+DSP_REG_AXH0].shift = 16; - } + for (unsigned int i = 0; i < 2; i++) + { + regs[i + DSP_REG_AX0_32].size = 4; + regs[i + DSP_REG_AXL0].parentReg = i + DSP_REG_AX0_32; + regs[i + DSP_REG_AXH0].parentReg = i + DSP_REG_AX0_32; + regs[i + DSP_REG_AXL0].shift = 0; + regs[i + DSP_REG_AXH0].shift = 16; + } - use_ctr = 0; + use_ctr = 0; } -DSPJitRegCache::DSPJitRegCache(const DSPJitRegCache &cache) - : regs(cache.regs), xregs(cache.xregs), emitter(cache.emitter), temporary(true), merged(false) +DSPJitRegCache::DSPJitRegCache(const DSPJitRegCache& cache) + : regs(cache.regs), xregs(cache.xregs), emitter(cache.emitter), temporary(true), merged(false) { } -DSPJitRegCache& DSPJitRegCache::operator=(const DSPJitRegCache &cache) +DSPJitRegCache& DSPJitRegCache::operator=(const DSPJitRegCache& cache) { - _assert_msg_(DSPLLE, &emitter == &cache.emitter, "emitter does not match"); - _assert_msg_(DSPLLE, temporary, "register cache not temporary??"); - merged = false; + _assert_msg_(DSPLLE, &emitter == &cache.emitter, "emitter does not match"); + _assert_msg_(DSPLLE, temporary, "register cache not temporary??"); + merged = false; - xregs = cache.xregs; - regs = cache.regs; + xregs = cache.xregs; + regs = cache.regs; - return *this; + return *this; } DSPJitRegCache::~DSPJitRegCache() { - _assert_msg_(DSPLLE, !temporary || merged, "temporary cache not merged"); + _assert_msg_(DSPLLE, !temporary || merged, "temporary cache not merged"); } void DSPJitRegCache::Drop() { - merged = true; + merged = true; } -void DSPJitRegCache::FlushRegs(DSPJitRegCache &cache, bool emit) +void DSPJitRegCache::FlushRegs(DSPJitRegCache& cache, bool emit) { - cache.merged = true; + cache.merged = true; - // drop all guest register not used by cache - for (size_t i = 0; i < regs.size(); i++) - { - regs[i].used = false; //used is restored later - if (regs[i].loc.IsSimpleReg() && - !cache.regs[i].loc.IsSimpleReg()) - { - MovToMemory(i); - } - } + // drop all guest register not used by cache + for (size_t i = 0; i < regs.size(); i++) + { + regs[i].used = false; // used is restored later + if (regs[i].loc.IsSimpleReg() && !cache.regs[i].loc.IsSimpleReg()) + { + MovToMemory(i); + } + } - // try to move guest regs in the wrong host reg to the correct one - int movcnt; - do - { - movcnt = 0; - for (size_t i = 0; i < regs.size(); i++) - { - X64Reg simple = regs[i].loc.GetSimpleReg(); - X64Reg simple_cache = cache.regs[i].loc.GetSimpleReg(); + // try to move guest regs in the wrong host reg to the correct one + int movcnt; + do + { + movcnt = 0; + for (size_t i = 0; i < regs.size(); i++) + { + X64Reg simple = regs[i].loc.GetSimpleReg(); + X64Reg simple_cache = cache.regs[i].loc.GetSimpleReg(); - if (simple_cache != simple && xregs[simple_cache].guest_reg == DSP_REG_NONE) - { - MovToHostReg(i, simple_cache, true); - movcnt++; - } - } - } while (movcnt != 0); + if (simple_cache != simple && xregs[simple_cache].guest_reg == DSP_REG_NONE) + { + MovToHostReg(i, simple_cache, true); + movcnt++; + } + } + } while (movcnt != 0); - // free all host regs that are not used for the same guest reg - for (size_t i = 0; i < regs.size(); i++) - { - if (cache.regs[i].loc.GetSimpleReg() != - regs[i].loc.GetSimpleReg() && - regs[i].loc.IsSimpleReg()) - { - MovToMemory(i); - } - } + // free all host regs that are not used for the same guest reg + for (size_t i = 0; i < regs.size(); i++) + { + if (cache.regs[i].loc.GetSimpleReg() != regs[i].loc.GetSimpleReg() && regs[i].loc.IsSimpleReg()) + { + MovToMemory(i); + } + } - // load all guest regs that are in memory and should be in host reg - for (size_t i = 0; i < regs.size(); i++) - { - if (cache.regs[i].loc.IsSimpleReg()) - { - MovToHostReg(i, cache.regs[i].loc.GetSimpleReg(), true); - RotateHostReg(i, cache.regs[i].shift, true); - } - else if (cache.regs[i].loc.IsImm()) - { - // TODO: Immediates? - } + // load all guest regs that are in memory and should be in host reg + for (size_t i = 0; i < regs.size(); i++) + { + if (cache.regs[i].loc.IsSimpleReg()) + { + MovToHostReg(i, cache.regs[i].loc.GetSimpleReg(), true); + RotateHostReg(i, cache.regs[i].shift, true); + } + else if (cache.regs[i].loc.IsImm()) + { + // TODO: Immediates? + } - regs[i].used = cache.regs[i].used; - regs[i].dirty |= cache.regs[i].dirty; - regs[i].last_use_ctr = cache.regs[i].last_use_ctr; - } + regs[i].used = cache.regs[i].used; + regs[i].dirty |= cache.regs[i].dirty; + regs[i].last_use_ctr = cache.regs[i].last_use_ctr; + } - // sync the freely used xregs - if (!emit) - { - for (size_t i = 0; i < xregs.size(); i++) - { - if (cache.xregs[i].guest_reg == DSP_REG_USED && - xregs[i].guest_reg == DSP_REG_NONE) - { - xregs[i].guest_reg = DSP_REG_USED; - } - if (cache.xregs[i].guest_reg == DSP_REG_NONE && - xregs[i].guest_reg == DSP_REG_USED) - { - xregs[i].guest_reg = DSP_REG_NONE; - } - } - } + // sync the freely used xregs + if (!emit) + { + for (size_t i = 0; i < xregs.size(); i++) + { + if (cache.xregs[i].guest_reg == DSP_REG_USED && xregs[i].guest_reg == DSP_REG_NONE) + { + xregs[i].guest_reg = DSP_REG_USED; + } + if (cache.xregs[i].guest_reg == DSP_REG_NONE && xregs[i].guest_reg == DSP_REG_USED) + { + xregs[i].guest_reg = DSP_REG_NONE; + } + } + } - // consistency checks - for (size_t i = 0; i < xregs.size(); i++) - { - _assert_msg_(DSPLLE, - xregs[i].guest_reg == cache.xregs[i].guest_reg, - "cache and current xreg guest_reg mismatch for %u", static_cast(i)); - } + // consistency checks + for (size_t i = 0; i < xregs.size(); i++) + { + _assert_msg_(DSPLLE, xregs[i].guest_reg == cache.xregs[i].guest_reg, + "cache and current xreg guest_reg mismatch for %u", static_cast(i)); + } - for (size_t i = 0; i < regs.size(); i++) - { - _assert_msg_(DSPLLE, - regs[i].loc.IsImm() == cache.regs[i].loc.IsImm(), - "cache and current reg loc mismatch for %i", static_cast(i)); - _assert_msg_(DSPLLE, - regs[i].loc.GetSimpleReg() == cache.regs[i].loc.GetSimpleReg(), - "cache and current reg loc mismatch for %i", static_cast(i)); - _assert_msg_(DSPLLE, - regs[i].dirty || !cache.regs[i].dirty, - "cache and current reg dirty mismatch for %i", static_cast(i)); - _assert_msg_(DSPLLE, - regs[i].used == cache.regs[i].used, - "cache and current reg used mismatch for %i", static_cast(i)); - _assert_msg_(DSPLLE, - regs[i].shift == cache.regs[i].shift, - "cache and current reg shift mismatch for %i", static_cast(i)); - } + for (size_t i = 0; i < regs.size(); i++) + { + _assert_msg_(DSPLLE, regs[i].loc.IsImm() == cache.regs[i].loc.IsImm(), + "cache and current reg loc mismatch for %i", static_cast(i)); + _assert_msg_(DSPLLE, regs[i].loc.GetSimpleReg() == cache.regs[i].loc.GetSimpleReg(), + "cache and current reg loc mismatch for %i", static_cast(i)); + _assert_msg_(DSPLLE, regs[i].dirty || !cache.regs[i].dirty, + "cache and current reg dirty mismatch for %i", static_cast(i)); + _assert_msg_(DSPLLE, regs[i].used == cache.regs[i].used, + "cache and current reg used mismatch for %i", static_cast(i)); + _assert_msg_(DSPLLE, regs[i].shift == cache.regs[i].shift, + "cache and current reg shift mismatch for %i", static_cast(i)); + } - use_ctr = cache.use_ctr; + use_ctr = cache.use_ctr; } void DSPJitRegCache::FlushMemBackedRegs() { - // also needs to undo any dynamic changes to static allocated regs - // this should have the same effect as - // merge(DSPJitRegCache(emitter)); + // also needs to undo any dynamic changes to static allocated regs + // this should have the same effect as + // merge(DSPJitRegCache(emitter)); - for (size_t i = 0; i < regs.size(); i++) - { - _assert_msg_(DSPLLE, !regs[i].used, - "register %u still in use", static_cast(i)); + for (size_t i = 0; i < regs.size(); i++) + { + _assert_msg_(DSPLLE, !regs[i].used, "register %u still in use", static_cast(i)); - if (regs[i].used) - { - emitter.INT3(); - } + if (regs[i].used) + { + emitter.INT3(); + } - if (regs[i].host_reg != INVALID_REG) - { - MovToHostReg(i, regs[i].host_reg, true); - RotateHostReg(i, 0, true); - } - else if (regs[i].parentReg == DSP_REG_NONE) - { - MovToMemory(i); - } - } + if (regs[i].host_reg != INVALID_REG) + { + MovToHostReg(i, regs[i].host_reg, true); + RotateHostReg(i, 0, true); + } + else if (regs[i].parentReg == DSP_REG_NONE) + { + MovToMemory(i); + } + } } void DSPJitRegCache::FlushRegs() { - FlushMemBackedRegs(); + FlushMemBackedRegs(); - for (size_t i = 0; i < regs.size(); i++) - { - if (regs[i].host_reg != INVALID_REG) - { - MovToMemory(i); - } + for (size_t i = 0; i < regs.size(); i++) + { + if (regs[i].host_reg != INVALID_REG) + { + MovToMemory(i); + } - _assert_msg_(DSPLLE, - !regs[i].loc.IsSimpleReg(), - "register %zu is still a simple reg", i); - } + _assert_msg_(DSPLLE, !regs[i].loc.IsSimpleReg(), "register %zu is still a simple reg", i); + } - _assert_msg_(DSPLLE, - xregs[RSP].guest_reg == DSP_REG_STATIC, - "wrong xreg state for %d", RSP); - _assert_msg_(DSPLLE, - xregs[RBX].guest_reg == DSP_REG_STATIC, - "wrong xreg state for %d", RBX); - _assert_msg_(DSPLLE, - xregs[RBP].guest_reg == DSP_REG_NONE, - "wrong xreg state for %d", RBP); - _assert_msg_(DSPLLE, - xregs[RSI].guest_reg == DSP_REG_NONE, - "wrong xreg state for %d", RSI); - _assert_msg_(DSPLLE, - xregs[RDI].guest_reg == DSP_REG_NONE, - "wrong xreg state for %d", RDI); + _assert_msg_(DSPLLE, xregs[RSP].guest_reg == DSP_REG_STATIC, "wrong xreg state for %d", RSP); + _assert_msg_(DSPLLE, xregs[RBX].guest_reg == DSP_REG_STATIC, "wrong xreg state for %d", RBX); + _assert_msg_(DSPLLE, xregs[RBP].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", RBP); + _assert_msg_(DSPLLE, xregs[RSI].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", RSI); + _assert_msg_(DSPLLE, xregs[RDI].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", RDI); #ifdef STATIC_REG_ACCS - _assert_msg_(DSPLLE, - xregs[R8].guest_reg == DSP_REG_STATIC, - "wrong xreg state for %d", R8); - _assert_msg_(DSPLLE, - xregs[R9].guest_reg == DSP_REG_STATIC, - "wrong xreg state for %d", R9); + _assert_msg_(DSPLLE, xregs[R8].guest_reg == DSP_REG_STATIC, "wrong xreg state for %d", R8); + _assert_msg_(DSPLLE, xregs[R9].guest_reg == DSP_REG_STATIC, "wrong xreg state for %d", R9); #else - _assert_msg_(DSPLLE, - xregs[R8].guest_reg == DSP_REG_NONE, - "wrong xreg state for %d", R8); - _assert_msg_(DSPLLE, - xregs[R9].guest_reg == DSP_REG_NONE, - "wrong xreg state for %d", R9); + _assert_msg_(DSPLLE, xregs[R8].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R8); + _assert_msg_(DSPLLE, xregs[R9].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R9); #endif - _assert_msg_(DSPLLE, - xregs[R10].guest_reg == DSP_REG_NONE, - "wrong xreg state for %d", R10); - _assert_msg_(DSPLLE, - xregs[R11].guest_reg == DSP_REG_NONE, - "wrong xreg state for %d", R11); - _assert_msg_(DSPLLE, - xregs[R12].guest_reg == DSP_REG_NONE, - "wrong xreg state for %d", R12); - _assert_msg_(DSPLLE, - xregs[R13].guest_reg == DSP_REG_NONE, - "wrong xreg state for %d", R13); - _assert_msg_(DSPLLE, - xregs[R14].guest_reg == DSP_REG_NONE, - "wrong xreg state for %d", R14); - _assert_msg_(DSPLLE, - xregs[R15].guest_reg == DSP_REG_NONE, - "wrong xreg state for %d", R15); + _assert_msg_(DSPLLE, xregs[R10].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R10); + _assert_msg_(DSPLLE, xregs[R11].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R11); + _assert_msg_(DSPLLE, xregs[R12].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R12); + _assert_msg_(DSPLLE, xregs[R13].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R13); + _assert_msg_(DSPLLE, xregs[R14].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R14); + _assert_msg_(DSPLLE, xregs[R15].guest_reg == DSP_REG_NONE, "wrong xreg state for %d", R15); - use_ctr = 0; + use_ctr = 0; } static u64 ebp_store; void DSPJitRegCache::LoadRegs(bool emit) { - for (size_t i = 0; i < regs.size(); i++) - { - if (regs[i].host_reg != INVALID_REG) - { - MovToHostReg(i, regs[i].host_reg, emit); - } - } + for (size_t i = 0; i < regs.size(); i++) + { + if (regs[i].host_reg != INVALID_REG) + { + MovToHostReg(i, regs[i].host_reg, emit); + } + } - if (emit) - { - emitter.MOV(64, M(&ebp_store), R(RBP)); - } + if (emit) + { + emitter.MOV(64, M(&ebp_store), R(RBP)); + } } void DSPJitRegCache::SaveRegs() { - FlushRegs(); + FlushRegs(); - for (size_t i = 0; i < regs.size(); i++) - { - if (regs[i].host_reg != INVALID_REG) - { - MovToMemory(i); - } + for (size_t i = 0; i < regs.size(); i++) + { + if (regs[i].host_reg != INVALID_REG) + { + MovToMemory(i); + } - _assert_msg_(DSPLLE, - !regs[i].loc.IsSimpleReg(), - "register %zu is still a simple reg", i); - } + _assert_msg_(DSPLLE, !regs[i].loc.IsSimpleReg(), "register %zu is still a simple reg", i); + } - emitter.MOV(64, R(RBP), M(&ebp_store)); + emitter.MOV(64, R(RBP), M(&ebp_store)); } void DSPJitRegCache::PushRegs() { - FlushMemBackedRegs(); + FlushMemBackedRegs(); - for (size_t i = 0; i < regs.size(); i++) - { - if (regs[i].host_reg != INVALID_REG) - { - MovToMemory(i); - } + for (size_t i = 0; i < regs.size(); i++) + { + if (regs[i].host_reg != INVALID_REG) + { + MovToMemory(i); + } - _assert_msg_(DSPLLE, - !regs[i].loc.IsSimpleReg(), - "register %zu is still a simple reg", i); - } + _assert_msg_(DSPLLE, !regs[i].loc.IsSimpleReg(), "register %zu is still a simple reg", i); + } - int push_count = 0; - for (X64CachedReg& xreg : xregs) - { - if (xreg.guest_reg == DSP_REG_USED) - push_count++; - } + int push_count = 0; + for (X64CachedReg& xreg : xregs) + { + if (xreg.guest_reg == DSP_REG_USED) + push_count++; + } - // hardcoding alignment to 16 bytes - if (push_count & 1) - { - emitter.SUB(64, R(RSP), Imm32(8)); - } + // hardcoding alignment to 16 bytes + if (push_count & 1) + { + emitter.SUB(64, R(RSP), Imm32(8)); + } - for (size_t i = 0; i < xregs.size(); i++) - { - if (xregs[i].guest_reg == DSP_REG_USED) - { - emitter.PUSH(static_cast(i)); - xregs[i].pushed = true; - xregs[i].guest_reg = DSP_REG_NONE; - } + for (size_t i = 0; i < xregs.size(); i++) + { + if (xregs[i].guest_reg == DSP_REG_USED) + { + emitter.PUSH(static_cast(i)); + xregs[i].pushed = true; + xregs[i].guest_reg = DSP_REG_NONE; + } - _assert_msg_(DSPLLE, - xregs[i].guest_reg == DSP_REG_NONE || - xregs[i].guest_reg == DSP_REG_STATIC, - "register %zu is still used", i); - } + _assert_msg_(DSPLLE, xregs[i].guest_reg == DSP_REG_NONE || xregs[i].guest_reg == DSP_REG_STATIC, + "register %zu is still used", i); + } - emitter.MOV(64, R(RBP), M(&ebp_store)); + emitter.MOV(64, R(RBP), M(&ebp_store)); } void DSPJitRegCache::PopRegs() { - emitter.MOV(64, M(&ebp_store), R(RBP)); + emitter.MOV(64, M(&ebp_store), R(RBP)); - int push_count = 0; - for (int i = static_cast(xregs.size() - 1); i >= 0; i--) - { - if (xregs[i].pushed) - { - push_count++; + int push_count = 0; + for (int i = static_cast(xregs.size() - 1); i >= 0; i--) + { + if (xregs[i].pushed) + { + push_count++; - emitter.POP(static_cast(i)); - xregs[i].pushed = false; - xregs[i].guest_reg = DSP_REG_USED; - } - } + emitter.POP(static_cast(i)); + xregs[i].pushed = false; + xregs[i].guest_reg = DSP_REG_USED; + } + } - // hardcoding alignment to 16 bytes - if (push_count & 1) - { - emitter.ADD(64, R(RSP), Imm32(8)); - } + // hardcoding alignment to 16 bytes + if (push_count & 1) + { + emitter.ADD(64, R(RSP), Imm32(8)); + } - for (size_t i = 0; i < regs.size(); i++) - { - if (regs[i].host_reg != INVALID_REG) - { - MovToHostReg(i, regs[i].host_reg, true); - } - } + for (size_t i = 0; i < regs.size(); i++) + { + if (regs[i].host_reg != INVALID_REG) + { + MovToHostReg(i, regs[i].host_reg, true); + } + } } X64Reg DSPJitRegCache::MakeABICallSafe(X64Reg reg) { - if (reg != RBP) - { - return reg; - } + if (reg != RBP) + { + return reg; + } - size_t rbp_guest = xregs[RBP].guest_reg; - xregs[RBP].guest_reg = DSP_REG_USED; - X64Reg safe = FindSpillFreeXReg(); - _assert_msg_(DSPLLE, safe != INVALID_REG, "could not find register"); - if (safe == INVALID_REG) - { - emitter.INT3(); - } - xregs[RBP].guest_reg = rbp_guest; - emitter.MOV(64,R(safe),R(reg)); - return safe; + size_t rbp_guest = xregs[RBP].guest_reg; + xregs[RBP].guest_reg = DSP_REG_USED; + X64Reg safe = FindSpillFreeXReg(); + _assert_msg_(DSPLLE, safe != INVALID_REG, "could not find register"); + if (safe == INVALID_REG) + { + emitter.INT3(); + } + xregs[RBP].guest_reg = rbp_guest; + emitter.MOV(64, R(safe), R(reg)); + return safe; } void DSPJitRegCache::MovToHostReg(size_t reg, X64Reg host_reg, bool load) { - _assert_msg_(DSPLLE, reg < regs.size(), - "bad register name %zu", reg); - _assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE, - "register %zu is proxy for %d", reg, regs[reg].parentReg); - _assert_msg_(DSPLLE, !regs[reg].used, - "moving to host reg in use guest reg %zu", reg); - X64Reg old_reg = regs[reg].loc.GetSimpleReg(); - if (old_reg == host_reg) - { - return; - } + _assert_msg_(DSPLLE, reg < regs.size(), "bad register name %zu", reg); + _assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE, "register %zu is proxy for %d", reg, + regs[reg].parentReg); + _assert_msg_(DSPLLE, !regs[reg].used, "moving to host reg in use guest reg %zu", reg); + X64Reg old_reg = regs[reg].loc.GetSimpleReg(); + if (old_reg == host_reg) + { + return; + } - if (xregs[host_reg].guest_reg != DSP_REG_STATIC) - { - xregs[host_reg].guest_reg = reg; - } + if (xregs[host_reg].guest_reg != DSP_REG_STATIC) + { + xregs[host_reg].guest_reg = reg; + } - if (load) - { - switch (regs[reg].size) - { - case 2: - emitter.MOV(16, R(host_reg), regs[reg].loc); - break; - case 4: - emitter.MOV(32, R(host_reg), regs[reg].loc); - break; - case 8: - emitter.MOV(64, R(host_reg), regs[reg].loc); - break; - default: - _assert_msg_(DSPLLE, 0, "unsupported memory size"); - break; - } - } + if (load) + { + switch (regs[reg].size) + { + case 2: + emitter.MOV(16, R(host_reg), regs[reg].loc); + break; + case 4: + emitter.MOV(32, R(host_reg), regs[reg].loc); + break; + case 8: + emitter.MOV(64, R(host_reg), regs[reg].loc); + break; + default: + _assert_msg_(DSPLLE, 0, "unsupported memory size"); + break; + } + } - regs[reg].loc = R(host_reg); - if (old_reg != INVALID_REG && - xregs[old_reg].guest_reg != DSP_REG_STATIC) - { - xregs[old_reg].guest_reg = DSP_REG_NONE; - } + regs[reg].loc = R(host_reg); + if (old_reg != INVALID_REG && xregs[old_reg].guest_reg != DSP_REG_STATIC) + { + xregs[old_reg].guest_reg = DSP_REG_NONE; + } } void DSPJitRegCache::MovToHostReg(size_t reg, bool load) { - _assert_msg_(DSPLLE, reg < regs.size(), - "bad register name %zu", reg); - _assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE, - "register %zu is proxy for %d", reg, regs[reg].parentReg); - _assert_msg_(DSPLLE, !regs[reg].used, - "moving to host reg in use guest reg %zu", reg); + _assert_msg_(DSPLLE, reg < regs.size(), "bad register name %zu", reg); + _assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE, "register %zu is proxy for %d", reg, + regs[reg].parentReg); + _assert_msg_(DSPLLE, !regs[reg].used, "moving to host reg in use guest reg %zu", reg); - if (regs[reg].loc.IsSimpleReg()) - { - return; - } + if (regs[reg].loc.IsSimpleReg()) + { + return; + } - X64Reg tmp; - if (regs[reg].host_reg != INVALID_REG) - { - tmp = regs[reg].host_reg; - } - else - { - tmp = FindSpillFreeXReg(); - } + X64Reg tmp; + if (regs[reg].host_reg != INVALID_REG) + { + tmp = regs[reg].host_reg; + } + else + { + tmp = FindSpillFreeXReg(); + } - if (tmp == INVALID_REG) - { - return; - } + if (tmp == INVALID_REG) + { + return; + } - MovToHostReg(reg, tmp, load); + MovToHostReg(reg, tmp, load); } void DSPJitRegCache::RotateHostReg(size_t reg, int shift, bool emit) { - _assert_msg_(DSPLLE, reg < regs.size(), - "bad register name %zu", reg); - _assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE, - "register %zu is proxy for %d", reg, regs[reg].parentReg); - _assert_msg_(DSPLLE, regs[reg].loc.IsSimpleReg(), - "register %zu is not a simple reg", reg); - _assert_msg_(DSPLLE, !regs[reg].used, - "rotating in use guest reg %zu", reg); + _assert_msg_(DSPLLE, reg < regs.size(), "bad register name %zu", reg); + _assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE, "register %zu is proxy for %d", reg, + regs[reg].parentReg); + _assert_msg_(DSPLLE, regs[reg].loc.IsSimpleReg(), "register %zu is not a simple reg", reg); + _assert_msg_(DSPLLE, !regs[reg].used, "rotating in use guest reg %zu", reg); - if (shift > regs[reg].shift && emit) - { - switch (regs[reg].size) - { - case 2: - emitter.ROR(16, regs[reg].loc, Imm8(shift - regs[reg].shift)); - break; - case 4: - emitter.ROR(32, regs[reg].loc, Imm8(shift - regs[reg].shift)); - break; - case 8: - emitter.ROR(64, regs[reg].loc, Imm8(shift - regs[reg].shift)); - break; - } - } - else if (shift < regs[reg].shift && emit) - { - switch (regs[reg].size) - { - case 2: - emitter.ROL(16, regs[reg].loc, Imm8(regs[reg].shift - shift)); - break; - case 4: - emitter.ROL(32, regs[reg].loc, Imm8(regs[reg].shift - shift)); - break; - case 8: - emitter.ROL(64, regs[reg].loc, Imm8(regs[reg].shift - shift)); - break; - } - } - regs[reg].shift = shift; + if (shift > regs[reg].shift && emit) + { + switch (regs[reg].size) + { + case 2: + emitter.ROR(16, regs[reg].loc, Imm8(shift - regs[reg].shift)); + break; + case 4: + emitter.ROR(32, regs[reg].loc, Imm8(shift - regs[reg].shift)); + break; + case 8: + emitter.ROR(64, regs[reg].loc, Imm8(shift - regs[reg].shift)); + break; + } + } + else if (shift < regs[reg].shift && emit) + { + switch (regs[reg].size) + { + case 2: + emitter.ROL(16, regs[reg].loc, Imm8(regs[reg].shift - shift)); + break; + case 4: + emitter.ROL(32, regs[reg].loc, Imm8(regs[reg].shift - shift)); + break; + case 8: + emitter.ROL(64, regs[reg].loc, Imm8(regs[reg].shift - shift)); + break; + } + } + regs[reg].shift = shift; } void DSPJitRegCache::MovToMemory(size_t reg) { - _assert_msg_(DSPLLE, reg < regs.size(), - "bad register name %zu", reg); - _assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE, - "register %zu is proxy for %d", reg, regs[reg].parentReg); - _assert_msg_(DSPLLE, !regs[reg].used, - "moving to memory in use guest reg %zu", reg); + _assert_msg_(DSPLLE, reg < regs.size(), "bad register name %zu", reg); + _assert_msg_(DSPLLE, regs[reg].parentReg == DSP_REG_NONE, "register %zu is proxy for %d", reg, + regs[reg].parentReg); + _assert_msg_(DSPLLE, !regs[reg].used, "moving to memory in use guest reg %zu", reg); - if (regs[reg].used) - { - emitter.INT3(); - } + if (regs[reg].used) + { + emitter.INT3(); + } - if (!regs[reg].loc.IsSimpleReg() && - !regs[reg].loc.IsImm()) - { - return; - } + if (!regs[reg].loc.IsSimpleReg() && !regs[reg].loc.IsImm()) + { + return; + } - //but first, check for any needed rotations - if (regs[reg].loc.IsSimpleReg()) - { - RotateHostReg(reg, 0, true); - } - else - { - // TODO: Immediates? - } + // but first, check for any needed rotations + if (regs[reg].loc.IsSimpleReg()) + { + RotateHostReg(reg, 0, true); + } + else + { + // TODO: Immediates? + } - _assert_msg_(DSPLLE, regs[reg].shift == 0, "still shifted??"); + _assert_msg_(DSPLLE, regs[reg].shift == 0, "still shifted??"); - //move to mem - OpArg tmp = M(regs[reg].mem); + // move to mem + OpArg tmp = M(regs[reg].mem); - if (regs[reg].dirty) - { - switch (regs[reg].size) - { - case 2: - emitter.MOV(16, tmp, regs[reg].loc); - break; - case 4: - emitter.MOV(32, tmp, regs[reg].loc); - break; - case 8: - emitter.MOV(64, tmp, regs[reg].loc); - break; - default: - _assert_msg_(DSPLLE, 0, "unsupported memory size"); - break; - } - regs[reg].dirty = false; - } + if (regs[reg].dirty) + { + switch (regs[reg].size) + { + case 2: + emitter.MOV(16, tmp, regs[reg].loc); + break; + case 4: + emitter.MOV(32, tmp, regs[reg].loc); + break; + case 8: + emitter.MOV(64, tmp, regs[reg].loc); + break; + default: + _assert_msg_(DSPLLE, 0, "unsupported memory size"); + break; + } + regs[reg].dirty = false; + } - if (regs[reg].loc.IsSimpleReg()) - { - X64Reg hostreg = regs[reg].loc.GetSimpleReg(); - if (xregs[hostreg].guest_reg != DSP_REG_STATIC) - { - xregs[hostreg].guest_reg = DSP_REG_NONE; - } - } + if (regs[reg].loc.IsSimpleReg()) + { + X64Reg hostreg = regs[reg].loc.GetSimpleReg(); + if (xregs[hostreg].guest_reg != DSP_REG_STATIC) + { + xregs[hostreg].guest_reg = DSP_REG_NONE; + } + } - regs[reg].last_use_ctr = -1; - regs[reg].loc = tmp; + regs[reg].last_use_ctr = -1; + regs[reg].loc = tmp; } -void DSPJitRegCache::GetReg(int reg, OpArg &oparg, bool load) +void DSPJitRegCache::GetReg(int reg, OpArg& oparg, bool load) { - int real_reg; - int shift; - if (regs[reg].parentReg != DSP_REG_NONE) - { - real_reg = regs[reg].parentReg; + int real_reg; + int shift; + if (regs[reg].parentReg != DSP_REG_NONE) + { + real_reg = regs[reg].parentReg; - // always load and rotate since we need the other - // parts of the register - load = true; + // always load and rotate since we need the other + // parts of the register + load = true; - shift = regs[reg].shift; - } - else - { - real_reg = reg; - shift = 0; - } + shift = regs[reg].shift; + } + else + { + real_reg = reg; + shift = 0; + } - _assert_msg_(DSPLLE, !regs[real_reg].used, - "register %d already in use", real_reg); + _assert_msg_(DSPLLE, !regs[real_reg].used, "register %d already in use", real_reg); - if (regs[real_reg].used) - { - emitter.INT3(); - } - // no need to actually emit code for load or rotate if caller doesn't - // use the contents, but see above for a reason to force the load - MovToHostReg(real_reg, load); + if (regs[real_reg].used) + { + emitter.INT3(); + } + // no need to actually emit code for load or rotate if caller doesn't + // use the contents, but see above for a reason to force the load + MovToHostReg(real_reg, load); - // TODO: actually handle INVALID_REG - _assert_msg_(DSPLLE, regs[real_reg].loc.IsSimpleReg(), - "did not get host reg for %d", reg); + // TODO: actually handle INVALID_REG + _assert_msg_(DSPLLE, regs[real_reg].loc.IsSimpleReg(), "did not get host reg for %d", reg); - RotateHostReg(real_reg, shift, load); - oparg = regs[real_reg].loc; - regs[real_reg].used = true; + RotateHostReg(real_reg, shift, load); + oparg = regs[real_reg].loc; + regs[real_reg].used = true; - //do some register specific fixup - switch (reg) - { - case DSP_REG_ACC0_64: - case DSP_REG_ACC1_64: - if (load) - { - // need to do this because interpreter only does 48 bits - // (and PutReg does the same) - emitter.SHL(64, oparg, Imm8(64-40)); // sign extend - emitter.SAR(64, oparg, Imm8(64-40)); - } - break; - default: - break; - } + // do some register specific fixup + switch (reg) + { + case DSP_REG_ACC0_64: + case DSP_REG_ACC1_64: + if (load) + { + // need to do this because interpreter only does 48 bits + // (and PutReg does the same) + emitter.SHL(64, oparg, Imm8(64 - 40)); // sign extend + emitter.SAR(64, oparg, Imm8(64 - 40)); + } + break; + default: + break; + } } void DSPJitRegCache::PutReg(int reg, bool dirty) { - int real_reg = reg; - if (regs[reg].parentReg != DSP_REG_NONE) - real_reg = regs[reg].parentReg; + int real_reg = reg; + if (regs[reg].parentReg != DSP_REG_NONE) + real_reg = regs[reg].parentReg; - OpArg oparg = regs[real_reg].loc; + OpArg oparg = regs[real_reg].loc; - switch (reg) - { - case DSP_REG_ACH0: - case DSP_REG_ACH1: - if (dirty) - { - // no need to extend to full 64bit here until interpreter - // uses that - if (oparg.IsSimpleReg()) - { - // register is already shifted correctly - // (if at all) + switch (reg) + { + case DSP_REG_ACH0: + case DSP_REG_ACH1: + if (dirty) + { + // no need to extend to full 64bit here until interpreter + // uses that + if (oparg.IsSimpleReg()) + { + // register is already shifted correctly + // (if at all) - // sign extend from the bottom 8 bits. - emitter.MOVSX(16, 8, oparg.GetSimpleReg(), oparg); - } - else if (oparg.IsImm()) - { - // TODO: Immediates? - } - else - { - // This works on the memory, so use reg instead - // of real_reg, since it has the right loc - X64Reg tmp = GetFreeXReg(); - // Sign extend from the bottom 8 bits. - emitter.MOVSX(16, 8, tmp, regs[reg].loc); - emitter.MOV(16, regs[reg].loc, R(tmp)); - PutXReg(tmp); - } - } - break; - case DSP_REG_ACC0_64: - case DSP_REG_ACC1_64: - if (dirty) - { - emitter.SHL(64, oparg, Imm8(64-40)); // sign extend - emitter.SAR(64, oparg, Imm8(64-40)); - } - break; - default: - break; - } + // sign extend from the bottom 8 bits. + emitter.MOVSX(16, 8, oparg.GetSimpleReg(), oparg); + } + else if (oparg.IsImm()) + { + // TODO: Immediates? + } + else + { + // This works on the memory, so use reg instead + // of real_reg, since it has the right loc + X64Reg tmp = GetFreeXReg(); + // Sign extend from the bottom 8 bits. + emitter.MOVSX(16, 8, tmp, regs[reg].loc); + emitter.MOV(16, regs[reg].loc, R(tmp)); + PutXReg(tmp); + } + } + break; + case DSP_REG_ACC0_64: + case DSP_REG_ACC1_64: + if (dirty) + { + emitter.SHL(64, oparg, Imm8(64 - 40)); // sign extend + emitter.SAR(64, oparg, Imm8(64 - 40)); + } + break; + default: + break; + } - regs[real_reg].used = false; + regs[real_reg].used = false; - if (regs[real_reg].loc.IsSimpleReg()) - { - regs[real_reg].dirty |= dirty; - regs[real_reg].last_use_ctr = use_ctr; - use_ctr++; - } + if (regs[real_reg].loc.IsSimpleReg()) + { + regs[real_reg].dirty |= dirty; + regs[real_reg].last_use_ctr = use_ctr; + use_ctr++; + } } void DSPJitRegCache::ReadReg(int sreg, X64Reg host_dreg, DSPJitSignExtend extend) { - OpArg reg; - GetReg(sreg, reg); + OpArg reg; + GetReg(sreg, reg); - switch (regs[sreg].size) - { - case 2: - switch (extend) - { - case SIGN: - emitter.MOVSX(64, 16, host_dreg, reg); - break; - case ZERO: - emitter.MOVZX(64, 16, host_dreg, reg); - break; - case NONE: - emitter.MOV(16, R(host_dreg), reg); - break; - } - break; - case 4: - switch (extend) - { - case SIGN: - emitter.MOVSX(64, 32, host_dreg, reg); - break; - case ZERO: - emitter.MOVZX(64, 32, host_dreg, reg); - break; - case NONE: - emitter.MOV(32, R(host_dreg), reg); - break; - } - break; - case 8: - emitter.MOV(64, R(host_dreg), reg); - break; - default: - _assert_msg_(DSPLLE, 0, "unsupported memory size"); - break; - } - PutReg(sreg, false); + switch (regs[sreg].size) + { + case 2: + switch (extend) + { + case SIGN: + emitter.MOVSX(64, 16, host_dreg, reg); + break; + case ZERO: + emitter.MOVZX(64, 16, host_dreg, reg); + break; + case NONE: + emitter.MOV(16, R(host_dreg), reg); + break; + } + break; + case 4: + switch (extend) + { + case SIGN: + emitter.MOVSX(64, 32, host_dreg, reg); + break; + case ZERO: + emitter.MOVZX(64, 32, host_dreg, reg); + break; + case NONE: + emitter.MOV(32, R(host_dreg), reg); + break; + } + break; + case 8: + emitter.MOV(64, R(host_dreg), reg); + break; + default: + _assert_msg_(DSPLLE, 0, "unsupported memory size"); + break; + } + PutReg(sreg, false); } void DSPJitRegCache::WriteReg(int dreg, OpArg arg) { - OpArg reg; - GetReg(dreg, reg, false); - if (arg.IsImm()) - { - switch (regs[dreg].size) - { - case 2: - emitter.MOV(16, reg, Imm16(arg.Imm16())); - break; - case 4: - emitter.MOV(32, reg, Imm32(arg.Imm32())); - break; - case 8: - if ((u32)arg.Imm64() == arg.Imm64()) - { - emitter.MOV(64, reg, Imm32((u32) arg.Imm64())); - } - else - { - emitter.MOV(64, reg, Imm64(arg.Imm64())); - } - break; - default: - _assert_msg_(DSPLLE, 0, "unsupported memory size"); - break; - } - } - else - { - switch (regs[dreg].size) - { - case 2: - emitter.MOV(16, reg, arg); - break; - case 4: - emitter.MOV(32, reg, arg); - break; - case 8: - emitter.MOV(64, reg, arg); - break; - default: - _assert_msg_(DSPLLE, 0, "unsupported memory size"); - break; - } - } - PutReg(dreg, true); + OpArg reg; + GetReg(dreg, reg, false); + if (arg.IsImm()) + { + switch (regs[dreg].size) + { + case 2: + emitter.MOV(16, reg, Imm16(arg.Imm16())); + break; + case 4: + emitter.MOV(32, reg, Imm32(arg.Imm32())); + break; + case 8: + if ((u32)arg.Imm64() == arg.Imm64()) + { + emitter.MOV(64, reg, Imm32((u32)arg.Imm64())); + } + else + { + emitter.MOV(64, reg, Imm64(arg.Imm64())); + } + break; + default: + _assert_msg_(DSPLLE, 0, "unsupported memory size"); + break; + } + } + else + { + switch (regs[dreg].size) + { + case 2: + emitter.MOV(16, reg, arg); + break; + case 4: + emitter.MOV(32, reg, arg); + break; + case 8: + emitter.MOV(64, reg, arg); + break; + default: + _assert_msg_(DSPLLE, 0, "unsupported memory size"); + break; + } + } + PutReg(dreg, true); } X64Reg DSPJitRegCache::SpillXReg() { - int max_use_ctr_diff = 0; - X64Reg least_recent_use_reg = INVALID_REG; - for (X64Reg reg : m_allocation_order) - { - if (xregs[reg].guest_reg <= DSP_REG_MAX_MEM_BACKED && - !regs[xregs[reg].guest_reg].used) - { - int use_ctr_diff = use_ctr - regs[xregs[reg].guest_reg].last_use_ctr; - if (use_ctr_diff >= max_use_ctr_diff) - { - max_use_ctr_diff = use_ctr_diff; - least_recent_use_reg = reg; - } - } - } + int max_use_ctr_diff = 0; + X64Reg least_recent_use_reg = INVALID_REG; + for (X64Reg reg : m_allocation_order) + { + if (xregs[reg].guest_reg <= DSP_REG_MAX_MEM_BACKED && !regs[xregs[reg].guest_reg].used) + { + int use_ctr_diff = use_ctr - regs[xregs[reg].guest_reg].last_use_ctr; + if (use_ctr_diff >= max_use_ctr_diff) + { + max_use_ctr_diff = use_ctr_diff; + least_recent_use_reg = reg; + } + } + } - if (least_recent_use_reg != INVALID_REG) - { - MovToMemory(xregs[least_recent_use_reg].guest_reg); - return least_recent_use_reg; - } + if (least_recent_use_reg != INVALID_REG) + { + MovToMemory(xregs[least_recent_use_reg].guest_reg); + return least_recent_use_reg; + } - //just choose one. - for (X64Reg reg : m_allocation_order) - { - if (xregs[reg].guest_reg <= DSP_REG_MAX_MEM_BACKED && - !regs[xregs[reg].guest_reg].used) - { - MovToMemory(xregs[reg].guest_reg); - return reg; - } - } + // just choose one. + for (X64Reg reg : m_allocation_order) + { + if (xregs[reg].guest_reg <= DSP_REG_MAX_MEM_BACKED && !regs[xregs[reg].guest_reg].used) + { + MovToMemory(xregs[reg].guest_reg); + return reg; + } + } - return INVALID_REG; + return INVALID_REG; } void DSPJitRegCache::SpillXReg(X64Reg reg) { - if (xregs[reg].guest_reg <= DSP_REG_MAX_MEM_BACKED) - { - _assert_msg_(DSPLLE, !regs[xregs[reg].guest_reg].used, - "to be spilled host reg %x(guest reg %zx) still in use!", - reg, xregs[reg].guest_reg); + if (xregs[reg].guest_reg <= DSP_REG_MAX_MEM_BACKED) + { + _assert_msg_(DSPLLE, !regs[xregs[reg].guest_reg].used, + "to be spilled host reg %x(guest reg %zx) still in use!", reg, + xregs[reg].guest_reg); - MovToMemory(xregs[reg].guest_reg); - } - else - { - _assert_msg_(DSPLLE, xregs[reg].guest_reg == DSP_REG_NONE, - "to be spilled host reg %x still in use!", - reg); - } + MovToMemory(xregs[reg].guest_reg); + } + else + { + _assert_msg_(DSPLLE, xregs[reg].guest_reg == DSP_REG_NONE, + "to be spilled host reg %x still in use!", reg); + } } X64Reg DSPJitRegCache::FindFreeXReg() { - for (X64Reg x : m_allocation_order) - { - if (xregs[x].guest_reg == DSP_REG_NONE) - { - return x; - } - } + for (X64Reg x : m_allocation_order) + { + if (xregs[x].guest_reg == DSP_REG_NONE) + { + return x; + } + } - return INVALID_REG; + return INVALID_REG; } X64Reg DSPJitRegCache::FindSpillFreeXReg() { - X64Reg reg = FindFreeXReg(); - if (reg == INVALID_REG) - { - reg = SpillXReg(); - } - return reg; + X64Reg reg = FindFreeXReg(); + if (reg == INVALID_REG) + { + reg = SpillXReg(); + } + return reg; } X64Reg DSPJitRegCache::GetFreeXReg() { - X64Reg reg = FindSpillFreeXReg(); + X64Reg reg = FindSpillFreeXReg(); - _assert_msg_(DSPLLE, reg != INVALID_REG, "could not find register"); - if (reg == INVALID_REG) - { - emitter.INT3(); - } + _assert_msg_(DSPLLE, reg != INVALID_REG, "could not find register"); + if (reg == INVALID_REG) + { + emitter.INT3(); + } - xregs[reg].guest_reg = DSP_REG_USED; - return reg; + xregs[reg].guest_reg = DSP_REG_USED; + return reg; } void DSPJitRegCache::GetXReg(X64Reg reg) { - if (xregs[reg].guest_reg == DSP_REG_STATIC) - { - ERROR_LOG(DSPLLE, "Trying to get statically used XReg %d", reg); - return; - } + if (xregs[reg].guest_reg == DSP_REG_STATIC) + { + ERROR_LOG(DSPLLE, "Trying to get statically used XReg %d", reg); + return; + } - if (xregs[reg].guest_reg != DSP_REG_NONE) - { - SpillXReg(reg); - } - _assert_msg_(DSPLLE, xregs[reg].guest_reg == DSP_REG_NONE, "register already in use"); - xregs[reg].guest_reg = DSP_REG_USED; + if (xregs[reg].guest_reg != DSP_REG_NONE) + { + SpillXReg(reg); + } + _assert_msg_(DSPLLE, xregs[reg].guest_reg == DSP_REG_NONE, "register already in use"); + xregs[reg].guest_reg = DSP_REG_USED; } void DSPJitRegCache::PutXReg(X64Reg reg) { - if (xregs[reg].guest_reg == DSP_REG_STATIC) - { - ERROR_LOG(DSPLLE, "Trying to put statically used XReg %d", reg); - return; - } + if (xregs[reg].guest_reg == DSP_REG_STATIC) + { + ERROR_LOG(DSPLLE, "Trying to put statically used XReg %d", reg); + return; + } - _assert_msg_(DSPLLE, xregs[reg].guest_reg == DSP_REG_USED, - "PutXReg without get(Free)XReg"); + _assert_msg_(DSPLLE, xregs[reg].guest_reg == DSP_REG_USED, "PutXReg without get(Free)XReg"); - xregs[reg].guest_reg = DSP_REG_NONE; + xregs[reg].guest_reg = DSP_REG_NONE; } diff --git a/Source/Core/Core/DSP/Jit/DSPJitRegCache.h b/Source/Core/Core/DSP/Jit/DSPJitRegCache.h index 462fbe3dfe..8f6e33e146 100644 --- a/Source/Core/Core/DSP/Jit/DSPJitRegCache.h +++ b/Source/Core/Core/DSP/Jit/DSPJitRegCache.h @@ -11,171 +11,171 @@ class DSPEmitter; enum DSPJitRegSpecial { - DSP_REG_AX0_32 =32, - DSP_REG_AX1_32 =33, - DSP_REG_ACC0_64 =34, - DSP_REG_ACC1_64 =35, - DSP_REG_PROD_64 =36, - DSP_REG_MAX_MEM_BACKED = 36, + DSP_REG_AX0_32 = 32, + DSP_REG_AX1_32 = 33, + DSP_REG_ACC0_64 = 34, + DSP_REG_ACC1_64 = 35, + DSP_REG_PROD_64 = 36, + DSP_REG_MAX_MEM_BACKED = 36, - DSP_REG_USED =253, - DSP_REG_STATIC =254, - DSP_REG_NONE =255 + DSP_REG_USED = 253, + DSP_REG_STATIC = 254, + DSP_REG_NONE = 255 }; enum DSPJitSignExtend { - SIGN, - ZERO, - NONE + SIGN, + ZERO, + NONE }; class DSPJitRegCache { public: - DSPJitRegCache(DSPEmitter &_emitter); + DSPJitRegCache(DSPEmitter& _emitter); - // For branching into multiple control flows - DSPJitRegCache(const DSPJitRegCache &cache); - DSPJitRegCache& operator=(const DSPJitRegCache &cache); + // For branching into multiple control flows + DSPJitRegCache(const DSPJitRegCache& cache); + DSPJitRegCache& operator=(const DSPJitRegCache& cache); - ~DSPJitRegCache(); + ~DSPJitRegCache(); - // Merge must be done _before_ leaving the code branch, so we can fix - // up any differences in state - void FlushRegs(DSPJitRegCache &cache, bool emit = true); - /* since some use cases are non-trivial, some examples: + // Merge must be done _before_ leaving the code branch, so we can fix + // up any differences in state + void FlushRegs(DSPJitRegCache& cache, bool emit = true); + /* since some use cases are non-trivial, some examples: - //this does not modify the final state of gpr - - FixupBranch b = JCC(); - DSPJitRegCache c = gpr; - - gpr.FlushRegs(c); - SetBranchTarget(b); - + //this does not modify the final state of gpr + + FixupBranch b = JCC(); + DSPJitRegCache c = gpr; + + gpr.FlushRegs(c); + SetBranchTarget(b); + - //this does not modify the final state of gpr - - DSPJitRegCache c = gpr; - FixupBranch b1 = JCC(); - - gpr.FlushRegs(c); - FixupBranch b2 = JMP(); - SetBranchTarget(b1); - - gpr.FlushRegs(c); - SetBranchTarget(b2); - + //this does not modify the final state of gpr + + DSPJitRegCache c = gpr; + FixupBranch b1 = JCC(); + + gpr.FlushRegs(c); + FixupBranch b2 = JMP(); + SetBranchTarget(b1); + + gpr.FlushRegs(c); + SetBranchTarget(b2); + - //this allows gpr to be modified in the second branch - //and fixes gpr according to the results form in the first branch - - DSPJitRegCache c = gpr; - FixupBranch b1 = JCC(); - - FixupBranch b2 = JMP(); - SetBranchTarget(b1); - - gpr.FlushRegs(c); - SetBranchTarget(b2); - + //this allows gpr to be modified in the second branch + //and fixes gpr according to the results form in the first branch + + DSPJitRegCache c = gpr; + FixupBranch b1 = JCC(); + + FixupBranch b2 = JMP(); + SetBranchTarget(b1); + + gpr.FlushRegs(c); + SetBranchTarget(b2); + - //this does not modify the final state of gpr - - u8* b = GetCodePtr(); - DSPJitRegCache c = gpr; - - gpr.FlushRegs(c); - JCC(b); - + //this does not modify the final state of gpr + + u8* b = GetCodePtr(); + DSPJitRegCache c = gpr; + + gpr.FlushRegs(c); + JCC(b); + - this all is not needed when gpr would not be used at all in the - conditional branch - */ + this all is not needed when gpr would not be used at all in the + conditional branch + */ - // Drop this copy without warning - void Drop(); + // Drop this copy without warning + void Drop(); - // Prepare state so that another flushed DSPJitRegCache can take over - void FlushRegs(); + // Prepare state so that another flushed DSPJitRegCache can take over + void FlushRegs(); - void LoadRegs(bool emit = true);// Load statically allocated regs from memory - void SaveRegs(); // Save statically allocated regs to memory + void LoadRegs(bool emit = true); // Load statically allocated regs from memory + void SaveRegs(); // Save statically allocated regs to memory - void PushRegs();// Save registers before ABI call - void PopRegs(); // Restore registers after ABI call + void PushRegs(); // Save registers before ABI call + void PopRegs(); // Restore registers after ABI call - // Returns a register with the same contents as reg that is safe - // to use through saveStaticRegs and for ABI-calls - Gen::X64Reg MakeABICallSafe(Gen::X64Reg reg); + // Returns a register with the same contents as reg that is safe + // to use through saveStaticRegs and for ABI-calls + Gen::X64Reg MakeABICallSafe(Gen::X64Reg reg); - // Gives no SCALE_RIP with abs(offset) >= 0x80000000 - // 32/64 bit writes allowed when the register has a _64 or _32 suffix - // only 16 bit writes allowed without any suffix. - void GetReg(int reg, Gen::OpArg &oparg, bool load = true); - // Done with all usages of OpArg above - void PutReg(int reg, bool dirty = true); + // Gives no SCALE_RIP with abs(offset) >= 0x80000000 + // 32/64 bit writes allowed when the register has a _64 or _32 suffix + // only 16 bit writes allowed without any suffix. + void GetReg(int reg, Gen::OpArg& oparg, bool load = true); + // Done with all usages of OpArg above + void PutReg(int reg, bool dirty = true); - void ReadReg(int sreg, Gen::X64Reg host_dreg, DSPJitSignExtend extend); - void WriteReg(int dreg, Gen::OpArg arg); + void ReadReg(int sreg, Gen::X64Reg host_dreg, DSPJitSignExtend extend); + void WriteReg(int dreg, Gen::OpArg arg); - // Find a free host reg, spill if used, reserve - Gen::X64Reg GetFreeXReg(); - // Spill a specific host reg if used, reserve - void GetXReg(Gen::X64Reg reg); - // Unreserve the given host reg - void PutXReg(Gen::X64Reg reg); + // Find a free host reg, spill if used, reserve + Gen::X64Reg GetFreeXReg(); + // Spill a specific host reg if used, reserve + void GetXReg(Gen::X64Reg reg); + // Unreserve the given host reg + void PutXReg(Gen::X64Reg reg); private: - struct X64CachedReg - { - size_t guest_reg; // Including DSPJitRegSpecial - bool pushed; - }; + struct X64CachedReg + { + size_t guest_reg; // Including DSPJitRegSpecial + bool pushed; + }; - struct DynamicReg - { - Gen::OpArg loc; - void *mem; - size_t size; - bool dirty; - bool used; - int last_use_ctr; - int parentReg; - int shift; // Current shift if parentReg == DSP_REG_NONE - // otherwise the shift this part can be found at - Gen::X64Reg host_reg; + struct DynamicReg + { + Gen::OpArg loc; + void* mem; + size_t size; + bool dirty; + bool used; + int last_use_ctr; + int parentReg; + int shift; // Current shift if parentReg == DSP_REG_NONE + // otherwise the shift this part can be found at + Gen::X64Reg host_reg; - // TODO: - // + drop sameReg - // + add parentReg - // + add shift: - // - if parentReg != DSP_REG_NONE, this is the shift where this - // register is found in the parentReg - // - if parentReg == DSP_REG_NONE, this is the current shift _state_ - }; + // TODO: + // + drop sameReg + // + add parentReg + // + add shift: + // - if parentReg != DSP_REG_NONE, this is the shift where this + // register is found in the parentReg + // - if parentReg == DSP_REG_NONE, this is the current shift _state_ + }; - // Find a free host reg - Gen::X64Reg FindFreeXReg(); - Gen::X64Reg SpillXReg(); - Gen::X64Reg FindSpillFreeXReg(); - void SpillXReg(Gen::X64Reg reg); + // Find a free host reg + Gen::X64Reg FindFreeXReg(); + Gen::X64Reg SpillXReg(); + Gen::X64Reg FindSpillFreeXReg(); + void SpillXReg(Gen::X64Reg reg); - void MovToHostReg(size_t reg, Gen::X64Reg host_reg, bool load); - void MovToHostReg(size_t reg, bool load); - void RotateHostReg(size_t reg, int shift, bool emit); - void MovToMemory(size_t reg); - void FlushMemBackedRegs(); + void MovToHostReg(size_t reg, Gen::X64Reg host_reg, bool load); + void MovToHostReg(size_t reg, bool load); + void RotateHostReg(size_t reg, int shift, bool emit); + void MovToMemory(size_t reg); + void FlushMemBackedRegs(); - static const std::array m_allocation_order; + static const std::array m_allocation_order; - std::array regs; - std::array xregs; + std::array regs; + std::array xregs; - DSPEmitter& emitter; - bool temporary; - bool merged; + DSPEmitter& emitter; + bool temporary; + bool merged; - int use_ctr; + int use_ctr; }; diff --git a/Source/Core/Core/DSP/Jit/DSPJitUtil.cpp b/Source/Core/Core/DSP/Jit/DSPJitUtil.cpp index 9da3d990fe..bb59f74b34 100644 --- a/Source/Core/Core/DSP/Jit/DSPJitUtil.cpp +++ b/Source/Core/Core/DSP/Jit/DSPJitUtil.cpp @@ -8,282 +8,280 @@ using namespace Gen; -//clobbers: -//EAX = (s8)g_dsp.reg_stack_ptr[stack_reg] -//expects: +// clobbers: +// EAX = (s8)g_dsp.reg_stack_ptr[stack_reg] +// expects: void DSPEmitter::dsp_reg_stack_push(int stack_reg) { - //g_dsp.reg_stack_ptr[stack_reg]++; - //g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; - MOV(8, R(AL), M(&g_dsp.reg_stack_ptr[stack_reg])); - ADD(8, R(AL), Imm8(1)); - AND(8, R(AL), Imm8(DSP_STACK_MASK)); - MOV(8, M(&g_dsp.reg_stack_ptr[stack_reg]), R(AL)); + // g_dsp.reg_stack_ptr[stack_reg]++; + // g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; + MOV(8, R(AL), M(&g_dsp.reg_stack_ptr[stack_reg])); + ADD(8, R(AL), Imm8(1)); + AND(8, R(AL), Imm8(DSP_STACK_MASK)); + MOV(8, M(&g_dsp.reg_stack_ptr[stack_reg]), R(AL)); - X64Reg tmp1 = gpr.GetFreeXReg(); - //g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]] = g_dsp.r[DSP_REG_ST0 + stack_reg]; - MOV(16, R(tmp1), M(&g_dsp.r.st[stack_reg])); - MOVZX(64, 8, RAX, R(AL)); - MOV(16, MComplex(EAX, EAX, SCALE_1, - PtrOffset(&g_dsp.reg_stack[stack_reg][0],nullptr)), R(tmp1)); - gpr.PutXReg(tmp1); + X64Reg tmp1 = gpr.GetFreeXReg(); + // g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]] = g_dsp.r[DSP_REG_ST0 + stack_reg]; + MOV(16, R(tmp1), M(&g_dsp.r.st[stack_reg])); + MOVZX(64, 8, RAX, R(AL)); + MOV(16, MComplex(EAX, EAX, SCALE_1, PtrOffset(&g_dsp.reg_stack[stack_reg][0], nullptr)), R(tmp1)); + gpr.PutXReg(tmp1); } -//clobbers: -//EAX = (s8)g_dsp.reg_stack_ptr[stack_reg] -//expects: +// clobbers: +// EAX = (s8)g_dsp.reg_stack_ptr[stack_reg] +// expects: void DSPEmitter::dsp_reg_stack_pop(int stack_reg) { - //g_dsp.r[DSP_REG_ST0 + stack_reg] = g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]]; - MOV(8, R(AL), M(&g_dsp.reg_stack_ptr[stack_reg])); - X64Reg tmp1 = gpr.GetFreeXReg(); - MOVZX(64, 8, RAX, R(AL)); - MOV(16, R(tmp1), MComplex(EAX, EAX, SCALE_1, - PtrOffset(&g_dsp.reg_stack[stack_reg][0],nullptr))); - MOV(16, M(&g_dsp.r.st[stack_reg]), R(tmp1)); - gpr.PutXReg(tmp1); + // g_dsp.r[DSP_REG_ST0 + stack_reg] = g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]]; + MOV(8, R(AL), M(&g_dsp.reg_stack_ptr[stack_reg])); + X64Reg tmp1 = gpr.GetFreeXReg(); + MOVZX(64, 8, RAX, R(AL)); + MOV(16, R(tmp1), MComplex(EAX, EAX, SCALE_1, PtrOffset(&g_dsp.reg_stack[stack_reg][0], nullptr))); + MOV(16, M(&g_dsp.r.st[stack_reg]), R(tmp1)); + gpr.PutXReg(tmp1); - //g_dsp.reg_stack_ptr[stack_reg]--; - //g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; - SUB(8, R(AL), Imm8(1)); - AND(8, R(AL), Imm8(DSP_STACK_MASK)); - MOV(8, M(&g_dsp.reg_stack_ptr[stack_reg]), R(AL)); + // g_dsp.reg_stack_ptr[stack_reg]--; + // g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK; + SUB(8, R(AL), Imm8(1)); + AND(8, R(AL), Imm8(DSP_STACK_MASK)); + MOV(8, M(&g_dsp.reg_stack_ptr[stack_reg]), R(AL)); } - void DSPEmitter::dsp_reg_store_stack(int stack_reg, Gen::X64Reg host_sreg) { - if (host_sreg != EDX) - { - MOV(16, R(EDX), R(host_sreg)); - } - dsp_reg_stack_push(stack_reg); - //g_dsp.r[DSP_REG_ST0 + stack_reg] = val; - MOV(16, M(&g_dsp.r.st[stack_reg]), R(EDX)); + if (host_sreg != EDX) + { + MOV(16, R(EDX), R(host_sreg)); + } + dsp_reg_stack_push(stack_reg); + // g_dsp.r[DSP_REG_ST0 + stack_reg] = val; + MOV(16, M(&g_dsp.r.st[stack_reg]), R(EDX)); } void DSPEmitter::dsp_reg_load_stack(int stack_reg, Gen::X64Reg host_dreg) { - //u16 val = g_dsp.r[DSP_REG_ST0 + stack_reg]; - MOV(16, R(EDX), M(&g_dsp.r.st[stack_reg])); - dsp_reg_stack_pop(stack_reg); - if (host_dreg != EDX) - { - MOV(16, R(host_dreg), R(EDX)); - } + // u16 val = g_dsp.r[DSP_REG_ST0 + stack_reg]; + MOV(16, R(EDX), M(&g_dsp.r.st[stack_reg])); + dsp_reg_stack_pop(stack_reg); + if (host_dreg != EDX) + { + MOV(16, R(host_dreg), R(EDX)); + } } void DSPEmitter::dsp_reg_store_stack_imm(int stack_reg, u16 val) { - dsp_reg_stack_push(stack_reg); - //g_dsp.r[DSP_REG_ST0 + stack_reg] = val; - MOV(16, M(&g_dsp.r.st[stack_reg]), Imm16(val)); + dsp_reg_stack_push(stack_reg); + // g_dsp.r[DSP_REG_ST0 + stack_reg] = val; + MOV(16, M(&g_dsp.r.st[stack_reg]), Imm16(val)); } void DSPEmitter::dsp_op_write_reg(int reg, Gen::X64Reg host_sreg) { - switch (reg & 0x1f) - { - // 8-bit sign extended registers. - case DSP_REG_ACH0: - case DSP_REG_ACH1: - gpr.WriteReg(reg, R(host_sreg)); - break; + switch (reg & 0x1f) + { + // 8-bit sign extended registers. + case DSP_REG_ACH0: + case DSP_REG_ACH1: + gpr.WriteReg(reg, R(host_sreg)); + break; - // Stack registers. - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - dsp_reg_store_stack(reg - DSP_REG_ST0, host_sreg); - break; + // Stack registers. + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + dsp_reg_store_stack(reg - DSP_REG_ST0, host_sreg); + break; - default: - gpr.WriteReg(reg, R(host_sreg)); - break; - } + default: + gpr.WriteReg(reg, R(host_sreg)); + break; + } } void DSPEmitter::dsp_op_write_reg_imm(int reg, u16 val) { - switch (reg & 0x1f) - { - // 8-bit sign extended registers. Should look at prod.h too... - case DSP_REG_ACH0: - case DSP_REG_ACH1: - gpr.WriteReg(reg, Imm16((u16)(s16)(s8)(u8)val)); - break; - // Stack registers. - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - dsp_reg_store_stack_imm(reg - DSP_REG_ST0, val); - break; + switch (reg & 0x1f) + { + // 8-bit sign extended registers. Should look at prod.h too... + case DSP_REG_ACH0: + case DSP_REG_ACH1: + gpr.WriteReg(reg, Imm16((u16)(s16)(s8)(u8)val)); + break; + // Stack registers. + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + dsp_reg_store_stack_imm(reg - DSP_REG_ST0, val); + break; - default: - gpr.WriteReg(reg, Imm16(val)); - break; - } + default: + gpr.WriteReg(reg, Imm16(val)); + break; + } } void DSPEmitter::dsp_conditional_extend_accum(int reg) { - switch (reg) - { - case DSP_REG_ACM0: - case DSP_REG_ACM1: - { - OpArg sr_reg; - gpr.GetReg(DSP_REG_SR,sr_reg); - DSPJitRegCache c(gpr); - TEST(16, sr_reg, Imm16(SR_40_MODE_BIT)); - FixupBranch not_40bit = J_CC(CC_Z,true); - //if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT) - //{ - // Sign extend into whole accum. - //u16 val = g_dsp.r[reg]; - get_acc_m(reg - DSP_REG_ACM0, EAX); - SHR(32, R(EAX), Imm8(16)); - //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = (val & 0x8000) ? 0xFFFF : 0x0000; - //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0; - set_acc_h(reg - DSP_REG_ACM0, R(RAX)); - set_acc_l(reg - DSP_REG_ACM0, Imm16(0)); - //} - gpr.FlushRegs(c); - SetJumpTarget(not_40bit); - gpr.PutReg(DSP_REG_SR, false); - } - } + switch (reg) + { + case DSP_REG_ACM0: + case DSP_REG_ACM1: + { + OpArg sr_reg; + gpr.GetReg(DSP_REG_SR, sr_reg); + DSPJitRegCache c(gpr); + TEST(16, sr_reg, Imm16(SR_40_MODE_BIT)); + FixupBranch not_40bit = J_CC(CC_Z, true); + // if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT) + //{ + // Sign extend into whole accum. + // u16 val = g_dsp.r[reg]; + get_acc_m(reg - DSP_REG_ACM0, EAX); + SHR(32, R(EAX), Imm8(16)); + // g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = (val & 0x8000) ? 0xFFFF : 0x0000; + // g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0; + set_acc_h(reg - DSP_REG_ACM0, R(RAX)); + set_acc_l(reg - DSP_REG_ACM0, Imm16(0)); + //} + gpr.FlushRegs(c); + SetJumpTarget(not_40bit); + gpr.PutReg(DSP_REG_SR, false); + } + } } void DSPEmitter::dsp_conditional_extend_accum_imm(int reg, u16 val) { - switch (reg) - { - case DSP_REG_ACM0: - case DSP_REG_ACM1: - { - OpArg sr_reg; - gpr.GetReg(DSP_REG_SR,sr_reg); - DSPJitRegCache c(gpr); - TEST(16, sr_reg, Imm16(SR_40_MODE_BIT)); - FixupBranch not_40bit = J_CC(CC_Z, true); - //if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT) - //{ - // Sign extend into whole accum. - //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = (val & 0x8000) ? 0xFFFF : 0x0000; - //g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0; - set_acc_h(reg - DSP_REG_ACM0, Imm16((val & 0x8000)?0xffff:0x0000)); - set_acc_l(reg - DSP_REG_ACM0, Imm16(0)); - //} - gpr.FlushRegs(c); - SetJumpTarget(not_40bit); - gpr.PutReg(DSP_REG_SR, false); - } - } + switch (reg) + { + case DSP_REG_ACM0: + case DSP_REG_ACM1: + { + OpArg sr_reg; + gpr.GetReg(DSP_REG_SR, sr_reg); + DSPJitRegCache c(gpr); + TEST(16, sr_reg, Imm16(SR_40_MODE_BIT)); + FixupBranch not_40bit = J_CC(CC_Z, true); + // if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT) + //{ + // Sign extend into whole accum. + // g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = (val & 0x8000) ? 0xFFFF : 0x0000; + // g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0; + set_acc_h(reg - DSP_REG_ACM0, Imm16((val & 0x8000) ? 0xffff : 0x0000)); + set_acc_l(reg - DSP_REG_ACM0, Imm16(0)); + //} + gpr.FlushRegs(c); + SetJumpTarget(not_40bit); + gpr.PutReg(DSP_REG_SR, false); + } + } } -void DSPEmitter::dsp_op_read_reg_dont_saturate(int reg, Gen::X64Reg host_dreg, DSPJitSignExtend extend) +void DSPEmitter::dsp_op_read_reg_dont_saturate(int reg, Gen::X64Reg host_dreg, + DSPJitSignExtend extend) { - switch (reg & 0x1f) - { - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - dsp_reg_load_stack(reg - DSP_REG_ST0, host_dreg); - switch (extend) - { - case SIGN: - MOVSX(64, 16, host_dreg, R(host_dreg)); - break; - case ZERO: - MOVZX(64, 16, host_dreg, R(host_dreg)); - break; - case NONE: - default: - break; - } - return; - default: - gpr.ReadReg(reg, host_dreg, extend); - return; - } + switch (reg & 0x1f) + { + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + dsp_reg_load_stack(reg - DSP_REG_ST0, host_dreg); + switch (extend) + { + case SIGN: + MOVSX(64, 16, host_dreg, R(host_dreg)); + break; + case ZERO: + MOVZX(64, 16, host_dreg, R(host_dreg)); + break; + case NONE: + default: + break; + } + return; + default: + gpr.ReadReg(reg, host_dreg, extend); + return; + } } void DSPEmitter::dsp_op_read_reg(int reg, Gen::X64Reg host_dreg, DSPJitSignExtend extend) { - switch (reg & 0x1f) - { - case DSP_REG_ST0: - case DSP_REG_ST1: - case DSP_REG_ST2: - case DSP_REG_ST3: - dsp_reg_load_stack(reg - DSP_REG_ST0, host_dreg); - switch (extend) - { - case SIGN: - MOVSX(64, 16, host_dreg, R(host_dreg)); - break; - case ZERO: - MOVZX(64, 16, host_dreg, R(host_dreg)); - break; - case NONE: - default: - break; - } - return; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - { - //we already know this is ACCM0 or ACCM1 - OpArg acc_reg; - gpr.GetReg(reg-DSP_REG_ACM0+DSP_REG_ACC0_64, acc_reg); - OpArg sr_reg; - gpr.GetReg(DSP_REG_SR,sr_reg); + switch (reg & 0x1f) + { + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: + dsp_reg_load_stack(reg - DSP_REG_ST0, host_dreg); + switch (extend) + { + case SIGN: + MOVSX(64, 16, host_dreg, R(host_dreg)); + break; + case ZERO: + MOVZX(64, 16, host_dreg, R(host_dreg)); + break; + case NONE: + default: + break; + } + return; + case DSP_REG_ACM0: + case DSP_REG_ACM1: + { + // we already know this is ACCM0 or ACCM1 + OpArg acc_reg; + gpr.GetReg(reg - DSP_REG_ACM0 + DSP_REG_ACC0_64, acc_reg); + OpArg sr_reg; + gpr.GetReg(DSP_REG_SR, sr_reg); - DSPJitRegCache c(gpr); - TEST(16, sr_reg, Imm16(SR_40_MODE_BIT)); - FixupBranch not_40bit = J_CC(CC_Z, true); + DSPJitRegCache c(gpr); + TEST(16, sr_reg, Imm16(SR_40_MODE_BIT)); + FixupBranch not_40bit = J_CC(CC_Z, true); - MOVSX(64,32,host_dreg,acc_reg); - CMP(64,R(host_dreg),acc_reg); - FixupBranch no_saturate = J_CC(CC_Z); + MOVSX(64, 32, host_dreg, acc_reg); + CMP(64, R(host_dreg), acc_reg); + FixupBranch no_saturate = J_CC(CC_Z); - CMP(64,acc_reg,Imm32(0)); - FixupBranch negative = J_CC(CC_LE); + CMP(64, acc_reg, Imm32(0)); + FixupBranch negative = J_CC(CC_LE); - MOV(64,R(host_dreg),Imm32(0x7fff));//this works for all extend modes - FixupBranch done_positive = J(); + MOV(64, R(host_dreg), Imm32(0x7fff)); // this works for all extend modes + FixupBranch done_positive = J(); - SetJumpTarget(negative); - if (extend == NONE || extend == ZERO) - MOV(64,R(host_dreg),Imm32(0x00008000)); - else - MOV(64,R(host_dreg),Imm32(0xffff8000)); - FixupBranch done_negative = J(); + SetJumpTarget(negative); + if (extend == NONE || extend == ZERO) + MOV(64, R(host_dreg), Imm32(0x00008000)); + else + MOV(64, R(host_dreg), Imm32(0xffff8000)); + FixupBranch done_negative = J(); - SetJumpTarget(no_saturate); - SetJumpTarget(not_40bit); + SetJumpTarget(no_saturate); + SetJumpTarget(not_40bit); - MOV(64, R(host_dreg), acc_reg); - if (extend == NONE || extend == ZERO) - SHR(64, R(host_dreg), Imm8(16)); - else - SAR(64, R(host_dreg), Imm8(16)); - SetJumpTarget(done_positive); - SetJumpTarget(done_negative); - gpr.FlushRegs(c); - gpr.PutReg(reg-DSP_REG_ACM0+DSP_REG_ACC0_64, false); + MOV(64, R(host_dreg), acc_reg); + if (extend == NONE || extend == ZERO) + SHR(64, R(host_dreg), Imm8(16)); + else + SAR(64, R(host_dreg), Imm8(16)); + SetJumpTarget(done_positive); + SetJumpTarget(done_negative); + gpr.FlushRegs(c); + gpr.PutReg(reg - DSP_REG_ACM0 + DSP_REG_ACC0_64, false); - gpr.PutReg(DSP_REG_SR, false); - } - return; - default: - gpr.ReadReg(reg, host_dreg, extend); - return; - } + gpr.PutReg(DSP_REG_SR, false); + } + return; + default: + gpr.ReadReg(reg, host_dreg, extend); + return; + } } // addr math @@ -295,73 +293,72 @@ void DSPEmitter::dsp_op_read_reg(int reg, Gen::X64Reg host_dreg, DSPJitSignExten // Both are done while ignoring changes due to values/holes in IX // above the mask. - // EAX = g_dsp.r.ar[reg] // EDX = g_dsp.r.wr[reg] void DSPEmitter::increment_addr_reg(int reg) { - OpArg ar_reg; - OpArg wr_reg; - gpr.GetReg(DSP_REG_WR0+reg,wr_reg); - MOVZX(32, 16, EDX, wr_reg); - gpr.PutReg(DSP_REG_WR0+reg, false); - gpr.GetReg(DSP_REG_AR0+reg,ar_reg); - MOVZX(32, 16, EAX, ar_reg); - X64Reg tmp1 = gpr.GetFreeXReg(); - //u32 nar = ar + 1; - MOV(32, R(tmp1), R(EAX)); - ADD(32, R(EAX), Imm8(1)); + OpArg ar_reg; + OpArg wr_reg; + gpr.GetReg(DSP_REG_WR0 + reg, wr_reg); + MOVZX(32, 16, EDX, wr_reg); + gpr.PutReg(DSP_REG_WR0 + reg, false); + gpr.GetReg(DSP_REG_AR0 + reg, ar_reg); + MOVZX(32, 16, EAX, ar_reg); + X64Reg tmp1 = gpr.GetFreeXReg(); + // u32 nar = ar + 1; + MOV(32, R(tmp1), R(EAX)); + ADD(32, R(EAX), Imm8(1)); - // if ((nar ^ ar) > ((wr | 1) << 1)) - // nar -= wr + 1; - XOR(32, R(tmp1), R(EAX)); - LEA(32, ECX, MRegSum(EDX, EDX)); - OR(32, R(ECX), Imm8(2)); - CMP(32, R(tmp1), R(ECX)); - FixupBranch nowrap = J_CC(CC_BE); - SUB(16, R(AX), R(DX)); - SUB(16, R(AX), Imm8(1)); - SetJumpTarget(nowrap); - gpr.PutXReg(tmp1); - // g_dsp.r.ar[reg] = nar; + // if ((nar ^ ar) > ((wr | 1) << 1)) + // nar -= wr + 1; + XOR(32, R(tmp1), R(EAX)); + LEA(32, ECX, MRegSum(EDX, EDX)); + OR(32, R(ECX), Imm8(2)); + CMP(32, R(tmp1), R(ECX)); + FixupBranch nowrap = J_CC(CC_BE); + SUB(16, R(AX), R(DX)); + SUB(16, R(AX), Imm8(1)); + SetJumpTarget(nowrap); + gpr.PutXReg(tmp1); + // g_dsp.r.ar[reg] = nar; - MOV(16, ar_reg, R(AX)); - gpr.PutReg(DSP_REG_AR0+reg); + MOV(16, ar_reg, R(AX)); + gpr.PutReg(DSP_REG_AR0 + reg); } // EAX = g_dsp.r.ar[reg] // EDX = g_dsp.r.wr[reg] void DSPEmitter::decrement_addr_reg(int reg) { - OpArg ar_reg; - OpArg wr_reg; - gpr.GetReg(DSP_REG_WR0+reg,wr_reg); - MOVZX(32, 16, EDX, wr_reg); - gpr.PutReg(DSP_REG_WR0+reg, false); - gpr.GetReg(DSP_REG_AR0+reg,ar_reg); - MOVZX(32, 16, EAX, ar_reg); + OpArg ar_reg; + OpArg wr_reg; + gpr.GetReg(DSP_REG_WR0 + reg, wr_reg); + MOVZX(32, 16, EDX, wr_reg); + gpr.PutReg(DSP_REG_WR0 + reg, false); + gpr.GetReg(DSP_REG_AR0 + reg, ar_reg); + MOVZX(32, 16, EAX, ar_reg); - X64Reg tmp1 = gpr.GetFreeXReg(); - // u32 nar = ar + wr; - // edi = nar - LEA(32, tmp1, MRegSum(EAX, EDX)); + X64Reg tmp1 = gpr.GetFreeXReg(); + // u32 nar = ar + wr; + // edi = nar + LEA(32, tmp1, MRegSum(EAX, EDX)); - // if (((nar ^ ar) & ((wr | 1) << 1)) > wr) - // nar -= wr + 1; - XOR(32, R(EAX), R(tmp1)); - LEA(32, ECX, MRegSum(EDX, EDX)); - OR(32, R(ECX), Imm8(2)); - AND(32, R(EAX), R(ECX)); - CMP(32, R(EAX), R(EDX)); - FixupBranch nowrap = J_CC(CC_BE); - SUB(16, R(tmp1), R(DX)); - SUB(16, R(tmp1), Imm8(1)); - SetJumpTarget(nowrap); - // g_dsp.r.ar[reg] = nar; + // if (((nar ^ ar) & ((wr | 1) << 1)) > wr) + // nar -= wr + 1; + XOR(32, R(EAX), R(tmp1)); + LEA(32, ECX, MRegSum(EDX, EDX)); + OR(32, R(ECX), Imm8(2)); + AND(32, R(EAX), R(ECX)); + CMP(32, R(EAX), R(EDX)); + FixupBranch nowrap = J_CC(CC_BE); + SUB(16, R(tmp1), R(DX)); + SUB(16, R(tmp1), Imm8(1)); + SetJumpTarget(nowrap); + // g_dsp.r.ar[reg] = nar; - MOV(16, ar_reg, R(tmp1)); - gpr.PutReg(DSP_REG_AR0+reg); - gpr.PutXReg(tmp1); + MOV(16, ar_reg, R(tmp1)); + gpr.PutReg(DSP_REG_AR0 + reg); + gpr.PutXReg(tmp1); } // Increase addr register according to the correspond ix register @@ -370,66 +367,66 @@ void DSPEmitter::decrement_addr_reg(int reg) // ECX = g_dsp.r.ix[reg] void DSPEmitter::increase_addr_reg(int reg, int _ix_reg) { - OpArg ar_reg; - OpArg wr_reg; - OpArg ix_reg; - gpr.GetReg(DSP_REG_WR0+reg,wr_reg); - MOVZX(32, 16, EDX, wr_reg); - gpr.PutReg(DSP_REG_WR0+reg, false); - gpr.GetReg(DSP_REG_IX0+_ix_reg,ix_reg); - MOVSX(32, 16, ECX, ix_reg); - gpr.PutReg(DSP_REG_IX0+_ix_reg, false); - gpr.GetReg(DSP_REG_AR0+reg,ar_reg); - MOVZX(32, 16, EAX, ar_reg); + OpArg ar_reg; + OpArg wr_reg; + OpArg ix_reg; + gpr.GetReg(DSP_REG_WR0 + reg, wr_reg); + MOVZX(32, 16, EDX, wr_reg); + gpr.PutReg(DSP_REG_WR0 + reg, false); + gpr.GetReg(DSP_REG_IX0 + _ix_reg, ix_reg); + MOVSX(32, 16, ECX, ix_reg); + gpr.PutReg(DSP_REG_IX0 + _ix_reg, false); + gpr.GetReg(DSP_REG_AR0 + reg, ar_reg); + MOVZX(32, 16, EAX, ar_reg); - X64Reg tmp1 = gpr.GetFreeXReg(); - //u32 nar = ar + ix; - //edi = nar - LEA(32, tmp1, MRegSum(EAX, ECX)); + X64Reg tmp1 = gpr.GetFreeXReg(); + // u32 nar = ar + ix; + // edi = nar + LEA(32, tmp1, MRegSum(EAX, ECX)); - //u32 dar = (nar ^ ar ^ ix) & ((wr | 1) << 1); - //eax = dar - XOR(32, R(EAX), R(ECX)); - XOR(32, R(EAX), R(tmp1)); + // u32 dar = (nar ^ ar ^ ix) & ((wr | 1) << 1); + // eax = dar + XOR(32, R(EAX), R(ECX)); + XOR(32, R(EAX), R(tmp1)); - //if (ix >= 0) - TEST(32, R(ECX), R(ECX)); - FixupBranch negative = J_CC(CC_S); - LEA(32, ECX, MRegSum(EDX, EDX)); - OR(32, R(ECX), Imm8(2)); - AND(32, R(EAX), R(ECX)); + // if (ix >= 0) + TEST(32, R(ECX), R(ECX)); + FixupBranch negative = J_CC(CC_S); + LEA(32, ECX, MRegSum(EDX, EDX)); + OR(32, R(ECX), Imm8(2)); + AND(32, R(EAX), R(ECX)); - //if (dar > wr) - CMP(32, R(EAX), R(EDX)); - FixupBranch done = J_CC(CC_BE); - //nar -= wr + 1; - SUB(16, R(tmp1), R(DX)); - SUB(16, R(tmp1), Imm8(1)); - FixupBranch done2 = J(); + // if (dar > wr) + CMP(32, R(EAX), R(EDX)); + FixupBranch done = J_CC(CC_BE); + // nar -= wr + 1; + SUB(16, R(tmp1), R(DX)); + SUB(16, R(tmp1), Imm8(1)); + FixupBranch done2 = J(); - //else - SetJumpTarget(negative); - LEA(32, ECX, MRegSum(EDX, EDX)); - OR(32, R(ECX), Imm8(2)); - AND(32, R(EAX), R(ECX)); + // else + SetJumpTarget(negative); + LEA(32, ECX, MRegSum(EDX, EDX)); + OR(32, R(ECX), Imm8(2)); + AND(32, R(EAX), R(ECX)); - //if ((((nar + wr + 1) ^ nar) & dar) <= wr) - LEA(32, ECX, MComplex(tmp1, EDX, SCALE_1, 1)); - XOR(32, R(ECX), R(tmp1)); - AND(32, R(ECX), R(EAX)); - CMP(32, R(ECX), R(EDX)); - FixupBranch done3 = J_CC(CC_A); - //nar += wr + 1; - LEA(32, tmp1, MComplex(tmp1, EDX, SCALE_1, 1)); + // if ((((nar + wr + 1) ^ nar) & dar) <= wr) + LEA(32, ECX, MComplex(tmp1, EDX, SCALE_1, 1)); + XOR(32, R(ECX), R(tmp1)); + AND(32, R(ECX), R(EAX)); + CMP(32, R(ECX), R(EDX)); + FixupBranch done3 = J_CC(CC_A); + // nar += wr + 1; + LEA(32, tmp1, MComplex(tmp1, EDX, SCALE_1, 1)); - SetJumpTarget(done); - SetJumpTarget(done2); - SetJumpTarget(done3); - // g_dsp.r.ar[reg] = nar; + SetJumpTarget(done); + SetJumpTarget(done2); + SetJumpTarget(done3); + // g_dsp.r.ar[reg] = nar; - MOV(16, ar_reg, R(tmp1)); - gpr.PutReg(DSP_REG_AR0+reg); - gpr.PutXReg(tmp1); + MOV(16, ar_reg, R(tmp1)); + gpr.PutReg(DSP_REG_AR0 + reg); + gpr.PutXReg(tmp1); } // Decrease addr register according to the correspond ix register @@ -438,119 +435,117 @@ void DSPEmitter::increase_addr_reg(int reg, int _ix_reg) // ECX = g_dsp.r.ix[reg] void DSPEmitter::decrease_addr_reg(int reg) { - OpArg ar_reg; - OpArg wr_reg; - OpArg ix_reg; - gpr.GetReg(DSP_REG_WR0+reg,wr_reg); - MOVZX(32, 16, EDX, wr_reg); - gpr.PutReg(DSP_REG_WR0+reg, false); - gpr.GetReg(DSP_REG_IX0+reg,ix_reg); - MOVSX(32, 16, ECX, ix_reg); - gpr.PutReg(DSP_REG_IX0+reg, false); - gpr.GetReg(DSP_REG_AR0+reg,ar_reg); - MOVZX(32, 16, EAX, ar_reg); + OpArg ar_reg; + OpArg wr_reg; + OpArg ix_reg; + gpr.GetReg(DSP_REG_WR0 + reg, wr_reg); + MOVZX(32, 16, EDX, wr_reg); + gpr.PutReg(DSP_REG_WR0 + reg, false); + gpr.GetReg(DSP_REG_IX0 + reg, ix_reg); + MOVSX(32, 16, ECX, ix_reg); + gpr.PutReg(DSP_REG_IX0 + reg, false); + gpr.GetReg(DSP_REG_AR0 + reg, ar_reg); + MOVZX(32, 16, EAX, ar_reg); - NOT(32, R(ECX)); //esi = ~ix + NOT(32, R(ECX)); // esi = ~ix - X64Reg tmp1 = gpr.GetFreeXReg(); - //u32 nar = ar - ix; (ar + ~ix + 1) - LEA(32, tmp1, MComplex(EAX, ECX, SCALE_1, 1)); + X64Reg tmp1 = gpr.GetFreeXReg(); + // u32 nar = ar - ix; (ar + ~ix + 1) + LEA(32, tmp1, MComplex(EAX, ECX, SCALE_1, 1)); - //u32 dar = (nar ^ ar ^ ~ix) & ((wr | 1) << 1); - //eax = dar - XOR(32, R(EAX), R(ECX)); - XOR(32, R(EAX), R(tmp1)); + // u32 dar = (nar ^ ar ^ ~ix) & ((wr | 1) << 1); + // eax = dar + XOR(32, R(EAX), R(ECX)); + XOR(32, R(EAX), R(tmp1)); - //if ((u32)ix > 0xFFFF8000) ==> (~ix < 0x00007FFF) - CMP(32, R(ECX), Imm32(0x00007FFF)); - FixupBranch positive = J_CC(CC_AE); - LEA(32, ECX, MRegSum(EDX, EDX)); - OR(32, R(ECX), Imm8(2)); - AND(32, R(EAX), R(ECX)); + // if ((u32)ix > 0xFFFF8000) ==> (~ix < 0x00007FFF) + CMP(32, R(ECX), Imm32(0x00007FFF)); + FixupBranch positive = J_CC(CC_AE); + LEA(32, ECX, MRegSum(EDX, EDX)); + OR(32, R(ECX), Imm8(2)); + AND(32, R(EAX), R(ECX)); - //if (dar > wr) - CMP(32, R(EAX), R(EDX)); - FixupBranch done = J_CC(CC_BE); - //nar -= wr + 1; - SUB(16, R(tmp1), R(DX)); - SUB(16, R(tmp1), Imm8(1)); - FixupBranch done2 = J(); + // if (dar > wr) + CMP(32, R(EAX), R(EDX)); + FixupBranch done = J_CC(CC_BE); + // nar -= wr + 1; + SUB(16, R(tmp1), R(DX)); + SUB(16, R(tmp1), Imm8(1)); + FixupBranch done2 = J(); - //else - SetJumpTarget(positive); - LEA(32, ECX, MRegSum(EDX, EDX)); - OR(32, R(ECX), Imm8(2)); - AND(32, R(EAX), R(ECX)); + // else + SetJumpTarget(positive); + LEA(32, ECX, MRegSum(EDX, EDX)); + OR(32, R(ECX), Imm8(2)); + AND(32, R(EAX), R(ECX)); - //if ((((nar + wr + 1) ^ nar) & dar) <= wr) - LEA(32, ECX, MComplex(tmp1, EDX, SCALE_1, 1)); - XOR(32, R(ECX), R(tmp1)); - AND(32, R(ECX), R(EAX)); - CMP(32, R(ECX), R(EDX)); - FixupBranch done3 = J_CC(CC_A); - //nar += wr + 1; - LEA(32, tmp1, MComplex(tmp1, EDX, SCALE_1, 1)); + // if ((((nar + wr + 1) ^ nar) & dar) <= wr) + LEA(32, ECX, MComplex(tmp1, EDX, SCALE_1, 1)); + XOR(32, R(ECX), R(tmp1)); + AND(32, R(ECX), R(EAX)); + CMP(32, R(ECX), R(EDX)); + FixupBranch done3 = J_CC(CC_A); + // nar += wr + 1; + LEA(32, tmp1, MComplex(tmp1, EDX, SCALE_1, 1)); - SetJumpTarget(done); - SetJumpTarget(done2); - SetJumpTarget(done3); - //return nar + SetJumpTarget(done); + SetJumpTarget(done2); + SetJumpTarget(done3); + // return nar - MOV(16, ar_reg, R(tmp1)); - gpr.PutReg(DSP_REG_AR0+reg); - gpr.PutXReg(tmp1); + MOV(16, ar_reg, R(tmp1)); + gpr.PutReg(DSP_REG_AR0 + reg); + gpr.PutXReg(tmp1); } - // EAX - destination address // ECX - Base of DRAM void DSPEmitter::dmem_write(X64Reg value) { - // if (saddr == 0) - CMP(16, R(EAX), Imm16(0x0fff)); - FixupBranch ifx = J_CC(CC_A); + // if (saddr == 0) + CMP(16, R(EAX), Imm16(0x0fff)); + FixupBranch ifx = J_CC(CC_A); - // g_dsp.dram[addr & DSP_DRAM_MASK] = val; - AND(16, R(EAX), Imm16(DSP_DRAM_MASK)); - MOV(64, R(ECX), ImmPtr(g_dsp.dram)); - MOV(16, MComplex(ECX, EAX, SCALE_2, 0), R(value)); + // g_dsp.dram[addr & DSP_DRAM_MASK] = val; + AND(16, R(EAX), Imm16(DSP_DRAM_MASK)); + MOV(64, R(ECX), ImmPtr(g_dsp.dram)); + MOV(16, MComplex(ECX, EAX, SCALE_2, 0), R(value)); - FixupBranch end = J(true); - // else if (saddr == 0xf) - SetJumpTarget(ifx); - // Does it mean gdsp_ifx_write needs u32 rather than u16? - DSPJitRegCache c(gpr); - X64Reg abisafereg = gpr.MakeABICallSafe(value); - gpr.PushRegs(); - ABI_CallFunctionRR((void *)gdsp_ifx_write, EAX, abisafereg); - gpr.PopRegs(); - gpr.FlushRegs(c); - SetJumpTarget(end); + FixupBranch end = J(true); + // else if (saddr == 0xf) + SetJumpTarget(ifx); + // Does it mean gdsp_ifx_write needs u32 rather than u16? + DSPJitRegCache c(gpr); + X64Reg abisafereg = gpr.MakeABICallSafe(value); + gpr.PushRegs(); + ABI_CallFunctionRR((void*)gdsp_ifx_write, EAX, abisafereg); + gpr.PopRegs(); + gpr.FlushRegs(c); + SetJumpTarget(end); } void DSPEmitter::dmem_write_imm(u16 address, X64Reg value) { - switch (address >> 12) - { - case 0x0: // 0xxx DRAM - MOV(64, R(RDX), ImmPtr(g_dsp.dram)); - MOV(16, MDisp(RDX, (address & DSP_DRAM_MASK)*2), R(value)); - break; + switch (address >> 12) + { + case 0x0: // 0xxx DRAM + MOV(64, R(RDX), ImmPtr(g_dsp.dram)); + MOV(16, MDisp(RDX, (address & DSP_DRAM_MASK) * 2), R(value)); + break; - case 0xf: // Fxxx HW regs - { - MOV(16, R(EAX), Imm16(address)); - X64Reg abisafereg = gpr.MakeABICallSafe(value); - gpr.PushRegs(); - ABI_CallFunctionRR((void *)gdsp_ifx_write, EAX, abisafereg); - gpr.PopRegs(); - break; - } - default: // Unmapped/non-existing memory - ERROR_LOG(DSPLLE, "%04x DSP ERROR: Write to UNKNOWN (%04x) memory", - g_dsp.pc, address); - break; - } + case 0xf: // Fxxx HW regs + { + MOV(16, R(EAX), Imm16(address)); + X64Reg abisafereg = gpr.MakeABICallSafe(value); + gpr.PushRegs(); + ABI_CallFunctionRR((void*)gdsp_ifx_write, EAX, abisafereg); + gpr.PopRegs(); + break; + } + default: // Unmapped/non-existing memory + ERROR_LOG(DSPLLE, "%04x DSP ERROR: Write to UNKNOWN (%04x) memory", g_dsp.pc, address); + break; + } } // In: (address) - the address to read @@ -558,23 +553,23 @@ void DSPEmitter::dmem_write_imm(u16 address, X64Reg value) // ECX - Base void DSPEmitter::imem_read(X64Reg address) { - // if (addr == 0) - CMP(16, R(address), Imm16(0x0fff)); - FixupBranch irom = J_CC(CC_A); - // return g_dsp.iram[addr & DSP_IRAM_MASK]; - AND(16, R(address), Imm16(DSP_IRAM_MASK)); - MOV(64, R(ECX), ImmPtr(g_dsp.iram)); - MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0)); + // if (addr == 0) + CMP(16, R(address), Imm16(0x0fff)); + FixupBranch irom = J_CC(CC_A); + // return g_dsp.iram[addr & DSP_IRAM_MASK]; + AND(16, R(address), Imm16(DSP_IRAM_MASK)); + MOV(64, R(ECX), ImmPtr(g_dsp.iram)); + MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0)); - FixupBranch end = J(); - SetJumpTarget(irom); - // else if (addr == 0x8) - // return g_dsp.irom[addr & DSP_IROM_MASK]; - AND(16, R(address), Imm16(DSP_IROM_MASK)); - MOV(64, R(ECX), ImmPtr(g_dsp.irom)); - MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0)); + FixupBranch end = J(); + SetJumpTarget(irom); + // else if (addr == 0x8) + // return g_dsp.irom[addr & DSP_IROM_MASK]; + AND(16, R(address), Imm16(DSP_IROM_MASK)); + MOV(64, R(ECX), ImmPtr(g_dsp.irom)); + MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0)); - SetJumpTarget(end); + SetJumpTarget(end); } // In: (address) - the address to read @@ -582,109 +577,108 @@ void DSPEmitter::imem_read(X64Reg address) // ECX - Base void DSPEmitter::dmem_read(X64Reg address) { - // if (saddr == 0) - CMP(16, R(address), Imm16(0x0fff)); - FixupBranch dram = J_CC(CC_A); - // return g_dsp.dram[addr & DSP_DRAM_MASK]; - AND(32, R(address), Imm32(DSP_DRAM_MASK)); - MOVZX(64, 16, address, R(address)); - MOV(64, R(ECX), ImmPtr(g_dsp.dram)); - MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0)); + // if (saddr == 0) + CMP(16, R(address), Imm16(0x0fff)); + FixupBranch dram = J_CC(CC_A); + // return g_dsp.dram[addr & DSP_DRAM_MASK]; + AND(32, R(address), Imm32(DSP_DRAM_MASK)); + MOVZX(64, 16, address, R(address)); + MOV(64, R(ECX), ImmPtr(g_dsp.dram)); + MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0)); - FixupBranch end = J(true); - SetJumpTarget(dram); - // else if (saddr == 0x1) - CMP(16, R(address), Imm16(0x1fff)); - FixupBranch ifx = J_CC(CC_A); - // return g_dsp.coef[addr & DSP_COEF_MASK]; - AND(32, R(address), Imm32(DSP_COEF_MASK)); - MOVZX(64, 16, address, R(address)); - MOV(64, R(ECX), ImmPtr(g_dsp.coef)); - MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0)); + FixupBranch end = J(true); + SetJumpTarget(dram); + // else if (saddr == 0x1) + CMP(16, R(address), Imm16(0x1fff)); + FixupBranch ifx = J_CC(CC_A); + // return g_dsp.coef[addr & DSP_COEF_MASK]; + AND(32, R(address), Imm32(DSP_COEF_MASK)); + MOVZX(64, 16, address, R(address)); + MOV(64, R(ECX), ImmPtr(g_dsp.coef)); + MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0)); - FixupBranch end2 = J(true); - SetJumpTarget(ifx); - // else if (saddr == 0xf) - // return gdsp_ifx_read(addr); - DSPJitRegCache c(gpr); - X64Reg abisafereg = gpr.MakeABICallSafe(address); - gpr.PushRegs(); - ABI_CallFunctionR((void *)gdsp_ifx_read, abisafereg); - gpr.PopRegs(); - gpr.FlushRegs(c); - SetJumpTarget(end); - SetJumpTarget(end2); + FixupBranch end2 = J(true); + SetJumpTarget(ifx); + // else if (saddr == 0xf) + // return gdsp_ifx_read(addr); + DSPJitRegCache c(gpr); + X64Reg abisafereg = gpr.MakeABICallSafe(address); + gpr.PushRegs(); + ABI_CallFunctionR((void*)gdsp_ifx_read, abisafereg); + gpr.PopRegs(); + gpr.FlushRegs(c); + SetJumpTarget(end); + SetJumpTarget(end2); } void DSPEmitter::dmem_read_imm(u16 address) { - switch (address >> 12) - { - case 0x0: // 0xxx DRAM - MOV(64, R(RDX), ImmPtr(g_dsp.dram)); - MOV(16, R(EAX), MDisp(RDX, (address & DSP_DRAM_MASK)*2)); - break; + switch (address >> 12) + { + case 0x0: // 0xxx DRAM + MOV(64, R(RDX), ImmPtr(g_dsp.dram)); + MOV(16, R(EAX), MDisp(RDX, (address & DSP_DRAM_MASK) * 2)); + break; - case 0x1: // 1xxx COEF - MOV(64, R(RDX), ImmPtr(g_dsp.coef)); - MOV(16, R(EAX), MDisp(RDX, (address & DSP_COEF_MASK)*2)); - break; + case 0x1: // 1xxx COEF + MOV(64, R(RDX), ImmPtr(g_dsp.coef)); + MOV(16, R(EAX), MDisp(RDX, (address & DSP_COEF_MASK) * 2)); + break; - case 0xf: // Fxxx HW regs - { - gpr.PushRegs(); - ABI_CallFunctionC16((void *)gdsp_ifx_read, address); - gpr.PopRegs(); - break; - } - default: // Unmapped/non-existing memory - ERROR_LOG(DSPLLE, "%04x DSP ERROR: Read from UNKNOWN (%04x) memory", - g_dsp.pc, address); - } + case 0xf: // Fxxx HW regs + { + gpr.PushRegs(); + ABI_CallFunctionC16((void*)gdsp_ifx_read, address); + gpr.PopRegs(); + break; + } + default: // Unmapped/non-existing memory + ERROR_LOG(DSPLLE, "%04x DSP ERROR: Read from UNKNOWN (%04x) memory", g_dsp.pc, address); + } } // Returns s64 in RAX void DSPEmitter::get_long_prod(X64Reg long_prod) { - //s64 val = (s8)(u8)g_dsp.r[DSP_REG_PRODH]; - OpArg prod_reg; - gpr.GetReg(DSP_REG_PROD_64, prod_reg); - MOV(64, R(long_prod), prod_reg); - gpr.PutReg(DSP_REG_PROD_64, false); - //no use in keeping prod_reg any longer. - X64Reg tmp = gpr.GetFreeXReg(); - MOV(64, R(tmp), R(long_prod)); - SHL(64, R(long_prod), Imm8(64-40));//sign extend - SAR(64, R(long_prod), Imm8(64-40)); - SHR(64, R(tmp), Imm8(48)); - SHL(64, R(tmp), Imm8(16)); - ADD(64, R(long_prod), R(tmp)); - gpr.PutXReg(tmp); + // s64 val = (s8)(u8)g_dsp.r[DSP_REG_PRODH]; + OpArg prod_reg; + gpr.GetReg(DSP_REG_PROD_64, prod_reg); + MOV(64, R(long_prod), prod_reg); + gpr.PutReg(DSP_REG_PROD_64, false); + // no use in keeping prod_reg any longer. + X64Reg tmp = gpr.GetFreeXReg(); + MOV(64, R(tmp), R(long_prod)); + SHL(64, R(long_prod), Imm8(64 - 40)); // sign extend + SAR(64, R(long_prod), Imm8(64 - 40)); + SHR(64, R(tmp), Imm8(48)); + SHL(64, R(tmp), Imm8(16)); + ADD(64, R(long_prod), R(tmp)); + gpr.PutXReg(tmp); } // Returns s64 in RAX // Clobbers RCX void DSPEmitter::get_long_prod_round_prodl(X64Reg long_prod) { - //s64 prod = dsp_get_long_prod(); - get_long_prod(long_prod); + // s64 prod = dsp_get_long_prod(); + get_long_prod(long_prod); - X64Reg tmp = gpr.GetFreeXReg(); - //if (prod & 0x10000) prod = (prod + 0x8000) & ~0xffff; - TEST(32, R(long_prod), Imm32(0x10000)); - FixupBranch jump = J_CC(CC_Z); - ADD(64, R(long_prod), Imm32(0x8000)); - MOV(64, R(tmp), Imm64(~0xffff)); - AND(64, R(long_prod), R(tmp)); - FixupBranch _ret = J(); - //else prod = (prod + 0x7fff) & ~0xffff; - SetJumpTarget(jump); - ADD(64, R(long_prod), Imm32(0x7fff)); - MOV(64, R(tmp), Imm64(~0xffff)); - AND(64, R(long_prod), R(tmp)); - SetJumpTarget(_ret); - //return prod; - gpr.PutXReg(tmp); + X64Reg tmp = gpr.GetFreeXReg(); + // if (prod & 0x10000) prod = (prod + 0x8000) & ~0xffff; + TEST(32, R(long_prod), Imm32(0x10000)); + FixupBranch jump = J_CC(CC_Z); + ADD(64, R(long_prod), Imm32(0x8000)); + MOV(64, R(tmp), Imm64(~0xffff)); + AND(64, R(long_prod), R(tmp)); + FixupBranch _ret = J(); + // else prod = (prod + 0x7fff) & ~0xffff; + SetJumpTarget(jump); + ADD(64, R(long_prod), Imm32(0x7fff)); + MOV(64, R(tmp), Imm64(~0xffff)); + AND(64, R(long_prod), R(tmp)); + SetJumpTarget(_ret); + // return prod; + gpr.PutXReg(tmp); } // For accurate emulation, this is wrong - but the real prod registers behave @@ -692,118 +686,115 @@ void DSPEmitter::get_long_prod_round_prodl(X64Reg long_prod) // In: RAX = s64 val void DSPEmitter::set_long_prod() { - X64Reg tmp = gpr.GetFreeXReg(); + X64Reg tmp = gpr.GetFreeXReg(); - MOV(64, R(tmp), Imm64(0x000000ffffffffffULL)); - AND(64, R(RAX), R(tmp)); - gpr.PutXReg(tmp); - OpArg prod_reg; - gpr.GetReg(DSP_REG_PROD_64, prod_reg, false); - // g_dsp.r[DSP_REG_PRODL] = (u16)val; - MOV(64, prod_reg, R(RAX)); + MOV(64, R(tmp), Imm64(0x000000ffffffffffULL)); + AND(64, R(RAX), R(tmp)); + gpr.PutXReg(tmp); + OpArg prod_reg; + gpr.GetReg(DSP_REG_PROD_64, prod_reg, false); + // g_dsp.r[DSP_REG_PRODL] = (u16)val; + MOV(64, prod_reg, R(RAX)); - gpr.PutReg(DSP_REG_PROD_64, true); + gpr.PutReg(DSP_REG_PROD_64, true); } // Returns s64 in RAX // Clobbers RCX void DSPEmitter::round_long_acc(X64Reg long_acc) { - //if (prod & 0x10000) prod = (prod + 0x8000) & ~0xffff; - TEST(32, R(long_acc), Imm32(0x10000)); - FixupBranch jump = J_CC(CC_Z); - ADD(64, R(long_acc), Imm32(0x8000)); - MOV(64, R(ECX), Imm64(~0xffff)); - AND(64, R(long_acc), R(RCX)); - FixupBranch _ret = J(); - //else prod = (prod + 0x7fff) & ~0xffff; - SetJumpTarget(jump); - ADD(64, R(long_acc), Imm32(0x7fff)); - MOV(64, R(RCX), Imm64(~0xffff)); - AND(64, R(long_acc), R(RCX)); - SetJumpTarget(_ret); - //return prod; + // if (prod & 0x10000) prod = (prod + 0x8000) & ~0xffff; + TEST(32, R(long_acc), Imm32(0x10000)); + FixupBranch jump = J_CC(CC_Z); + ADD(64, R(long_acc), Imm32(0x8000)); + MOV(64, R(ECX), Imm64(~0xffff)); + AND(64, R(long_acc), R(RCX)); + FixupBranch _ret = J(); + // else prod = (prod + 0x7fff) & ~0xffff; + SetJumpTarget(jump); + ADD(64, R(long_acc), Imm32(0x7fff)); + MOV(64, R(RCX), Imm64(~0xffff)); + AND(64, R(long_acc), R(RCX)); + SetJumpTarget(_ret); + // return prod; } // Returns s64 in acc void DSPEmitter::get_long_acc(int _reg, X64Reg acc) { - OpArg reg; - gpr.GetReg(DSP_REG_ACC0_64+_reg, reg); - MOV(64, R(acc), reg); - gpr.PutReg(DSP_REG_ACC0_64+_reg, false); + OpArg reg; + gpr.GetReg(DSP_REG_ACC0_64 + _reg, reg); + MOV(64, R(acc), reg); + gpr.PutReg(DSP_REG_ACC0_64 + _reg, false); } // In: acc = s64 val void DSPEmitter::set_long_acc(int _reg, X64Reg acc) { - OpArg reg; - gpr.GetReg(DSP_REG_ACC0_64+_reg, reg, false); - MOV(64, reg, R(acc)); - gpr.PutReg(DSP_REG_ACC0_64+_reg); + OpArg reg; + gpr.GetReg(DSP_REG_ACC0_64 + _reg, reg, false); + MOV(64, reg, R(acc)); + gpr.PutReg(DSP_REG_ACC0_64 + _reg); } // Returns s16 in AX void DSPEmitter::get_acc_l(int _reg, X64Reg acl, bool sign) { - // return g_dsp.r[DSP_REG_ACM0 + _reg]; - gpr.ReadReg(_reg+DSP_REG_ACL0, acl, sign?SIGN:ZERO); + // return g_dsp.r[DSP_REG_ACM0 + _reg]; + gpr.ReadReg(_reg + DSP_REG_ACL0, acl, sign ? SIGN : ZERO); } void DSPEmitter::set_acc_l(int _reg, const OpArg& arg) { - // return g_dsp.r[DSP_REG_ACM0 + _reg]; - gpr.WriteReg(_reg+DSP_REG_ACL0,arg); + // return g_dsp.r[DSP_REG_ACM0 + _reg]; + gpr.WriteReg(_reg + DSP_REG_ACL0, arg); } // Returns s16 in AX void DSPEmitter::get_acc_m(int _reg, X64Reg acm, bool sign) { -// return g_dsp.r[DSP_REG_ACM0 + _reg]; - gpr.ReadReg(_reg+DSP_REG_ACM0, acm, sign?SIGN:ZERO); + // return g_dsp.r[DSP_REG_ACM0 + _reg]; + gpr.ReadReg(_reg + DSP_REG_ACM0, acm, sign ? SIGN : ZERO); } // In: s16 in AX void DSPEmitter::set_acc_m(int _reg, const OpArg& arg) { - // return g_dsp.r.ac[_reg].m; - gpr.WriteReg(_reg+DSP_REG_ACM0,arg); + // return g_dsp.r.ac[_reg].m; + gpr.WriteReg(_reg + DSP_REG_ACM0, arg); } // Returns s16 in AX void DSPEmitter::get_acc_h(int _reg, X64Reg ach, bool sign) { -// return g_dsp.r.ac[_reg].h; - gpr.ReadReg(_reg+DSP_REG_ACH0, ach, sign?SIGN:ZERO); + // return g_dsp.r.ac[_reg].h; + gpr.ReadReg(_reg + DSP_REG_ACH0, ach, sign ? SIGN : ZERO); } // In: s16 in AX void DSPEmitter::set_acc_h(int _reg, const OpArg& arg) { - // return g_dsp.r[DSP_REG_ACM0 + _reg]; - gpr.WriteReg(_reg+DSP_REG_ACH0,arg); + // return g_dsp.r[DSP_REG_ACM0 + _reg]; + gpr.WriteReg(_reg + DSP_REG_ACH0, arg); } // Returns u32 in EAX void DSPEmitter::get_long_acx(int _reg, X64Reg acx) { -// return ((u32)g_dsp.r[DSP_REG_AXH0 + _reg] << 16) | g_dsp.r[DSP_REG_AXL0 + _reg]; - gpr.ReadReg(_reg+DSP_REG_AX0_32, acx, SIGN); + // return ((u32)g_dsp.r[DSP_REG_AXH0 + _reg] << 16) | g_dsp.r[DSP_REG_AXL0 + _reg]; + gpr.ReadReg(_reg + DSP_REG_AX0_32, acx, SIGN); } // Returns s16 in EAX void DSPEmitter::get_ax_l(int _reg, X64Reg axl) { -// return (s16)g_dsp.r[DSP_REG_AXL0 + _reg]; - gpr.ReadReg(_reg+DSP_REG_AXL0, axl, SIGN); + // return (s16)g_dsp.r[DSP_REG_AXL0 + _reg]; + gpr.ReadReg(_reg + DSP_REG_AXL0, axl, SIGN); } // Returns s16 in EAX void DSPEmitter::get_ax_h(int _reg, X64Reg axh) { -// return (s16)g_dsp.r[DSP_REG_AXH0 + _reg]; - gpr.ReadReg(_reg+DSP_REG_AXH0, axh, SIGN); + // return (s16)g_dsp.r[DSP_REG_AXH0 + _reg]; + gpr.ReadReg(_reg + DSP_REG_AXH0, axh, SIGN); } - - - diff --git a/Source/Core/Core/DSP/LabelMap.cpp b/Source/Core/Core/DSP/LabelMap.cpp index 31ca4b614c..a9460952e7 100644 --- a/Source/Core/Core/DSP/LabelMap.cpp +++ b/Source/Core/Core/DSP/LabelMap.cpp @@ -2,74 +2,72 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Core/DSP/DSPTables.h" #include "Core/DSP/LabelMap.h" +#include "Core/DSP/DSPTables.h" LabelMap::LabelMap() { - } void LabelMap::RegisterDefaults() { - for (int i = 0; i < 0x24; i++) - { - if (regnames[i].name) - RegisterLabel(regnames[i].name, regnames[i].addr); - } - for (int i = 0; i < (int)pdlabels_size; i++) - { - if (pdlabels[i].name) - RegisterLabel(pdlabels[i].name, pdlabels[i].addr); - } + for (int i = 0; i < 0x24; i++) + { + if (regnames[i].name) + RegisterLabel(regnames[i].name, regnames[i].addr); + } + for (int i = 0; i < (int)pdlabels_size; i++) + { + if (pdlabels[i].name) + RegisterLabel(pdlabels[i].name, pdlabels[i].addr); + } } -void LabelMap::RegisterLabel(const std::string &label, u16 lval, LabelType type) +void LabelMap::RegisterLabel(const std::string& label, u16 lval, LabelType type) { - u16 old_value; - if (GetLabelValue(label, &old_value) && old_value != lval) - { - printf("WARNING: Redefined label %s to %04x - old value %04x\n", - label.c_str(), lval, old_value); - DeleteLabel(label); - } - labels.emplace_back(label, lval, type); + u16 old_value; + if (GetLabelValue(label, &old_value) && old_value != lval) + { + printf("WARNING: Redefined label %s to %04x - old value %04x\n", label.c_str(), lval, + old_value); + DeleteLabel(label); + } + labels.emplace_back(label, lval, type); } -void LabelMap::DeleteLabel(const std::string &label) +void LabelMap::DeleteLabel(const std::string& label) { - for (std::vector::iterator iter = labels.begin(); - iter != labels.end(); ++iter) - { - if (!label.compare(iter->name)) - { - labels.erase(iter); - return; - } - } + for (std::vector::iterator iter = labels.begin(); iter != labels.end(); ++iter) + { + if (!label.compare(iter->name)) + { + labels.erase(iter); + return; + } + } } -bool LabelMap::GetLabelValue(const std::string &name, u16 *value, LabelType type) const +bool LabelMap::GetLabelValue(const std::string& name, u16* value, LabelType type) const { - for (auto& label : labels) - { - if (!name.compare(label.name)) - { - if (type & label.type) - { - *value = label.addr; - return true; - } - else - { - printf("WARNING: Wrong label type requested. %s\n", name.c_str()); - } - } - } - return false; + for (auto& label : labels) + { + if (!name.compare(label.name)) + { + if (type & label.type) + { + *value = label.addr; + return true; + } + else + { + printf("WARNING: Wrong label type requested. %s\n", name.c_str()); + } + } + } + return false; } void LabelMap::Clear() { - labels.clear(); + labels.clear(); } diff --git a/Source/Core/Core/DSP/LabelMap.h b/Source/Core/Core/DSP/LabelMap.h index 6938379fd4..d6e7d3cc13 100644 --- a/Source/Core/Core/DSP/LabelMap.h +++ b/Source/Core/Core/DSP/LabelMap.h @@ -11,29 +11,32 @@ enum LabelType { - LABEL_IADDR = 1, // Jump addresses, etc - LABEL_DADDR = 2, // Data addresses, etc - LABEL_VALUE = 4, - LABEL_ANY = 0xFF, + LABEL_IADDR = 1, // Jump addresses, etc + LABEL_DADDR = 2, // Data addresses, etc + LABEL_VALUE = 4, + LABEL_ANY = 0xFF, }; class LabelMap { - struct label_t - { - label_t(const std::string &lbl, s32 address, LabelType ltype) : name(lbl), addr(address), type(ltype) {} - std::string name; - s32 addr; - LabelType type; - }; - std::vector labels; + struct label_t + { + label_t(const std::string& lbl, s32 address, LabelType ltype) + : name(lbl), addr(address), type(ltype) + { + } + std::string name; + s32 addr; + LabelType type; + }; + std::vector labels; public: - LabelMap(); - ~LabelMap() { } - void RegisterDefaults(); - void RegisterLabel(const std::string &label, u16 lval, LabelType type = LABEL_VALUE); - void DeleteLabel(const std::string &label); - bool GetLabelValue(const std::string &label, u16 *value, LabelType type = LABEL_ANY) const; - void Clear(); + LabelMap(); + ~LabelMap() {} + void RegisterDefaults(); + void RegisterLabel(const std::string& label, u16 lval, LabelType type = LABEL_VALUE); + void DeleteLabel(const std::string& label); + bool GetLabelValue(const std::string& label, u16* value, LabelType type = LABEL_ANY) const; + void Clear(); }; diff --git a/Source/Core/Core/DSPEmulator.cpp b/Source/Core/Core/DSPEmulator.cpp index 9a5cd62a95..10cc8f7617 100644 --- a/Source/Core/Core/DSPEmulator.cpp +++ b/Source/Core/Core/DSPEmulator.cpp @@ -10,8 +10,8 @@ std::unique_ptr CreateDSPEmulator(bool hle) { - if (hle) - return std::make_unique(); + if (hle) + return std::make_unique(); - return std::make_unique(); + return std::make_unique(); } diff --git a/Source/Core/Core/DSPEmulator.h b/Source/Core/Core/DSPEmulator.h index e07f6dd6e3..b8cc8085d5 100644 --- a/Source/Core/Core/DSPEmulator.h +++ b/Source/Core/Core/DSPEmulator.h @@ -12,25 +12,24 @@ class PointerWrap; class DSPEmulator { public: - virtual ~DSPEmulator() {} + virtual ~DSPEmulator() {} + virtual bool IsLLE() = 0; - virtual bool IsLLE() = 0; + virtual bool Initialize(bool bWii, bool bDSPThread) = 0; + virtual void Shutdown() = 0; - virtual bool Initialize(bool bWii, bool bDSPThread) = 0; - virtual void Shutdown() = 0; + virtual void DoState(PointerWrap& p) = 0; + virtual void PauseAndLock(bool doLock, bool unpauseOnUnlock = true) = 0; - virtual void DoState(PointerWrap &p) = 0; - virtual void PauseAndLock(bool doLock, bool unpauseOnUnlock=true) = 0; - - virtual void DSP_WriteMailBoxHigh(bool _CPUMailbox, unsigned short) = 0; - virtual void DSP_WriteMailBoxLow(bool _CPUMailbox, unsigned short) = 0; - virtual unsigned short DSP_ReadMailBoxHigh(bool _CPUMailbox) = 0; - virtual unsigned short DSP_ReadMailBoxLow(bool _CPUMailbox) = 0; - virtual unsigned short DSP_ReadControlRegister() = 0; - virtual unsigned short DSP_WriteControlRegister(unsigned short) = 0; - virtual void DSP_Update(int cycles) = 0; - virtual void DSP_StopSoundStream() = 0; - virtual u32 DSP_UpdateRate() = 0; + virtual void DSP_WriteMailBoxHigh(bool _CPUMailbox, unsigned short) = 0; + virtual void DSP_WriteMailBoxLow(bool _CPUMailbox, unsigned short) = 0; + virtual unsigned short DSP_ReadMailBoxHigh(bool _CPUMailbox) = 0; + virtual unsigned short DSP_ReadMailBoxLow(bool _CPUMailbox) = 0; + virtual unsigned short DSP_ReadControlRegister() = 0; + virtual unsigned short DSP_WriteControlRegister(unsigned short) = 0; + virtual void DSP_Update(int cycles) = 0; + virtual void DSP_StopSoundStream() = 0; + virtual u32 DSP_UpdateRate() = 0; }; std::unique_ptr CreateDSPEmulator(bool hle); diff --git a/Source/Core/Core/Debugger/Debugger_SymbolMap.cpp b/Source/Core/Core/Debugger/Debugger_SymbolMap.cpp index 1044a647c8..f431390991 100644 --- a/Source/Core/Core/Debugger/Debugger_SymbolMap.cpp +++ b/Source/Core/Core/Debugger/Debugger_SymbolMap.cpp @@ -11,27 +11,26 @@ #include "Core/Core.h" #include "Core/Debugger/Debugger_SymbolMap.h" #include "Core/HW/Memmap.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/PPCSymbolDB.h" +#include "Core/PowerPC/PowerPC.h" namespace Dolphin_Debugger { - void AddAutoBreakpoints() { #if defined(_DEBUG) || defined(DEBUGFAST) #if 1 - const char *bps[] = { - "PPCHalt", - }; + const char* bps[] = { + "PPCHalt", + }; - for (const char* bp : bps) - { - Symbol *symbol = g_symbolDB.GetSymbolFromName(bp); - if (symbol) - PowerPC::breakpoints.Add(symbol->address, false); - } + for (const char* bp : bps) + { + Symbol* symbol = g_symbolDB.GetSymbolFromName(bp); + if (symbol) + PowerPC::breakpoints.Add(symbol->address, false); + } #endif #endif } @@ -39,127 +38,123 @@ void AddAutoBreakpoints() // Returns true if the address is not a valid RAM address or NULL. static bool IsStackBottom(u32 addr) { - return !addr || !PowerPC::HostIsRAMAddress(addr); + return !addr || !PowerPC::HostIsRAMAddress(addr); } static void WalkTheStack(const std::function& stack_step) { - if (!IsStackBottom(PowerPC::ppcState.gpr[1])) - { - u32 addr = PowerPC::HostRead_U32(PowerPC::ppcState.gpr[1]); // SP + if (!IsStackBottom(PowerPC::ppcState.gpr[1])) + { + u32 addr = PowerPC::HostRead_U32(PowerPC::ppcState.gpr[1]); // SP - // Walk the stack chain - for (int count = 0; - !IsStackBottom(addr + 4) && (count++ < 20); - ++count) - { - u32 func_addr = PowerPC::HostRead_U32(addr + 4); - stack_step(func_addr); + // Walk the stack chain + for (int count = 0; !IsStackBottom(addr + 4) && (count++ < 20); ++count) + { + u32 func_addr = PowerPC::HostRead_U32(addr + 4); + stack_step(func_addr); - if (IsStackBottom(addr)) - break; + if (IsStackBottom(addr)) + break; - addr = PowerPC::HostRead_U32(addr); - } - } + addr = PowerPC::HostRead_U32(addr); + } + } } // Returns callstack "formatted for debugging" - meaning that it // includes LR as the last item, and all items are the last step, // instead of "pointing ahead" -bool GetCallstack(std::vector &output) +bool GetCallstack(std::vector& output) { - if (!Core::IsRunning() || !PowerPC::HostIsRAMAddress(PowerPC::ppcState.gpr[1])) - return false; + if (!Core::IsRunning() || !PowerPC::HostIsRAMAddress(PowerPC::ppcState.gpr[1])) + return false; - if (LR == 0) - { - CallstackEntry entry; - entry.Name = "(error: LR=0)"; - entry.vAddress = 0x0; - output.push_back(entry); - return false; - } + if (LR == 0) + { + CallstackEntry entry; + entry.Name = "(error: LR=0)"; + entry.vAddress = 0x0; + output.push_back(entry); + return false; + } - CallstackEntry entry; - entry.Name = StringFromFormat(" * %s [ LR = %08x ]\n", g_symbolDB.GetDescription(LR).c_str(), LR - 4); - entry.vAddress = LR - 4; - output.push_back(entry); + CallstackEntry entry; + entry.Name = + StringFromFormat(" * %s [ LR = %08x ]\n", g_symbolDB.GetDescription(LR).c_str(), LR - 4); + entry.vAddress = LR - 4; + output.push_back(entry); - WalkTheStack([&entry, &output](u32 func_addr) { - std::string func_desc = g_symbolDB.GetDescription(func_addr); - if (func_desc.empty() || func_desc == "Invalid") - func_desc = "(unknown)"; - entry.Name = StringFromFormat(" * %s [ addr = %08x ]\n", - func_desc.c_str(), func_addr - 4); - entry.vAddress = func_addr - 4; - output.push_back(entry); - }); + WalkTheStack([&entry, &output](u32 func_addr) { + std::string func_desc = g_symbolDB.GetDescription(func_addr); + if (func_desc.empty() || func_desc == "Invalid") + func_desc = "(unknown)"; + entry.Name = StringFromFormat(" * %s [ addr = %08x ]\n", func_desc.c_str(), func_addr - 4); + entry.vAddress = func_addr - 4; + output.push_back(entry); + }); - return true; + return true; } void PrintCallstack() { - printf("== STACK TRACE - SP = %08x ==", PowerPC::ppcState.gpr[1]); + printf("== STACK TRACE - SP = %08x ==", PowerPC::ppcState.gpr[1]); - if (LR == 0) - { - printf(" LR = 0 - this is bad"); - } + if (LR == 0) + { + printf(" LR = 0 - this is bad"); + } - if (g_symbolDB.GetDescription(PC) != g_symbolDB.GetDescription(LR)) - { - printf(" * %s [ LR = %08x ]", g_symbolDB.GetDescription(LR).c_str(), LR); - } + if (g_symbolDB.GetDescription(PC) != g_symbolDB.GetDescription(LR)) + { + printf(" * %s [ LR = %08x ]", g_symbolDB.GetDescription(LR).c_str(), LR); + } - WalkTheStack([](u32 func_addr) { - std::string func_desc = g_symbolDB.GetDescription(func_addr); - if (func_desc.empty() || func_desc == "Invalid") - func_desc = "(unknown)"; - printf(" * %s [ addr = %08x ]", func_desc.c_str(), func_addr); - }); + WalkTheStack([](u32 func_addr) { + std::string func_desc = g_symbolDB.GetDescription(func_addr); + if (func_desc.empty() || func_desc == "Invalid") + func_desc = "(unknown)"; + printf(" * %s [ addr = %08x ]", func_desc.c_str(), func_addr); + }); } void PrintCallstack(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) { - GENERIC_LOG(type, level, "== STACK TRACE - SP = %08x ==", - PowerPC::ppcState.gpr[1]); + GENERIC_LOG(type, level, "== STACK TRACE - SP = %08x ==", PowerPC::ppcState.gpr[1]); - if (LR == 0) - { - GENERIC_LOG(type, level, " LR = 0 - this is bad"); - } + if (LR == 0) + { + GENERIC_LOG(type, level, " LR = 0 - this is bad"); + } - if (g_symbolDB.GetDescription(PC) != g_symbolDB.GetDescription(LR)) - { - GENERIC_LOG(type, level, " * %s [ LR = %08x ]", - g_symbolDB.GetDescription(LR).c_str(), LR); - } + if (g_symbolDB.GetDescription(PC) != g_symbolDB.GetDescription(LR)) + { + GENERIC_LOG(type, level, " * %s [ LR = %08x ]", g_symbolDB.GetDescription(LR).c_str(), LR); + } - WalkTheStack([type, level](u32 func_addr) { - std::string func_desc = g_symbolDB.GetDescription(func_addr); - if (func_desc.empty() || func_desc == "Invalid") - func_desc = "(unknown)"; - GENERIC_LOG(type, level, " * %s [ addr = %08x ]", func_desc.c_str(), func_addr); - }); + WalkTheStack([type, level](u32 func_addr) { + std::string func_desc = g_symbolDB.GetDescription(func_addr); + if (func_desc.empty() || func_desc == "Invalid") + func_desc = "(unknown)"; + GENERIC_LOG(type, level, " * %s [ addr = %08x ]", func_desc.c_str(), func_addr); + }); } void PrintDataBuffer(LogTypes::LOG_TYPE type, const u8* data, size_t size, const std::string& title) { - GENERIC_LOG(type, LogTypes::LDEBUG, "%s", title.c_str()); - for (u32 j = 0; j < size;) - { - std::string hex_line = ""; - for (int i = 0; i < 16; i++) - { - hex_line += StringFromFormat("%02x ", data[j++]); + GENERIC_LOG(type, LogTypes::LDEBUG, "%s", title.c_str()); + for (u32 j = 0; j < size;) + { + std::string hex_line = ""; + for (int i = 0; i < 16; i++) + { + hex_line += StringFromFormat("%02x ", data[j++]); - if (j >= size) - break; - } - GENERIC_LOG(type, LogTypes::LDEBUG, " Data: %s", hex_line.c_str()); - } + if (j >= size) + break; + } + GENERIC_LOG(type, LogTypes::LDEBUG, " Data: %s", hex_line.c_str()); + } } } // end of namespace Debugger diff --git a/Source/Core/Core/Debugger/Debugger_SymbolMap.h b/Source/Core/Core/Debugger/Debugger_SymbolMap.h index bb74112183..aa1f3e7452 100644 --- a/Source/Core/Core/Debugger/Debugger_SymbolMap.h +++ b/Source/Core/Core/Debugger/Debugger_SymbolMap.h @@ -12,18 +12,17 @@ namespace Dolphin_Debugger { - struct CallstackEntry { - std::string Name; - u32 vAddress; + std::string Name; + u32 vAddress; }; -bool GetCallstack(std::vector &output); +bool GetCallstack(std::vector& output); void PrintCallstack(); void PrintCallstack(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level); -void PrintDataBuffer(LogTypes::LOG_TYPE type, const u8* data, size_t size, const std::string& title); +void PrintDataBuffer(LogTypes::LOG_TYPE type, const u8* data, size_t size, + const std::string& title); void AddAutoBreakpoints(); - -} // end of namespace Debugger +} // end of namespace Debugger diff --git a/Source/Core/Core/Debugger/Dump.cpp b/Source/Core/Core/Debugger/Dump.cpp index 89d593e7fa..45f8fde926 100644 --- a/Source/Core/Core/Debugger/Dump.cpp +++ b/Source/Core/Core/Debugger/Dump.cpp @@ -10,60 +10,57 @@ #include "Core/Debugger/Dump.h" -CDump::CDump(const std::string& filename) : - m_pData(nullptr) +CDump::CDump(const std::string& filename) : m_pData(nullptr) { - File::IOFile pStream(filename, "rb"); - if (pStream) - { - m_size = (size_t)pStream.GetSize(); + File::IOFile pStream(filename, "rb"); + if (pStream) + { + m_size = (size_t)pStream.GetSize(); - m_pData = new u8[m_size]; + m_pData = new u8[m_size]; - pStream.ReadArray(m_pData, m_size); - } + pStream.ReadArray(m_pData, m_size); + } } CDump::~CDump() { - if (m_pData != nullptr) - { - delete[] m_pData; - m_pData = nullptr; - } + if (m_pData != nullptr) + { + delete[] m_pData; + m_pData = nullptr; + } } int CDump::GetNumberOfSteps() { - return (int)(m_size / STRUCTUR_SIZE); + return (int)(m_size / STRUCTUR_SIZE); } u32 CDump::GetGPR(int _step, int _gpr) { - u32 offset = _step * STRUCTUR_SIZE; + u32 offset = _step * STRUCTUR_SIZE; - if (offset >= m_size) - return -1; + if (offset >= m_size) + return -1; - return Read32(offset + OFFSET_GPR + (_gpr * 4)); + return Read32(offset + OFFSET_GPR + (_gpr * 4)); } u32 CDump::GetPC(int _step) { - u32 offset = _step * STRUCTUR_SIZE; + u32 offset = _step * STRUCTUR_SIZE; - if (offset >= m_size) - return -1; + if (offset >= m_size) + return -1; - return Read32(offset + OFFSET_PC); + return Read32(offset + OFFSET_PC); } u32 CDump::Read32(u32 _pos) { - u32 result = (m_pData[_pos+0] << 24) | - (m_pData[_pos+1] << 16) | - (m_pData[_pos+2] << 8) | - (m_pData[_pos+3] << 0); + u32 result = (m_pData[_pos + 0] << 24) | (m_pData[_pos + 1] << 16) | (m_pData[_pos + 2] << 8) | + (m_pData[_pos + 3] << 0); - return result; + return result; } diff --git a/Source/Core/Core/Debugger/Dump.h b/Source/Core/Core/Debugger/Dump.h index 9a86ccb6dd..5cdc696475 100644 --- a/Source/Core/Core/Debugger/Dump.h +++ b/Source/Core/Core/Debugger/Dump.h @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // Purpose: uncompress the dumps from costis GC-Debugger tool // // @@ -14,25 +13,24 @@ class CDump { public: + CDump(const std::string& filename); + ~CDump(); - CDump(const std::string& filename); - ~CDump(); - - int GetNumberOfSteps(); - u32 GetGPR(int _step, int _gpr); - u32 GetPC(int _step); + int GetNumberOfSteps(); + u32 GetGPR(int _step, int _gpr); + u32 GetPC(int _step); private: - enum - { - OFFSET_GPR = 0x4, - OFFSET_PC = 0x194, - STRUCTUR_SIZE = 0x2BC - }; + enum + { + OFFSET_GPR = 0x4, + OFFSET_PC = 0x194, + STRUCTUR_SIZE = 0x2BC + }; - u8 *m_pData; + u8* m_pData; - size_t m_size; + size_t m_size; - u32 Read32(u32 _pos); + u32 Read32(u32 _pos); }; diff --git a/Source/Core/Core/Debugger/GCELF.h b/Source/Core/Core/Debugger/GCELF.h index 10ff582757..8c3dd401a8 100644 --- a/Source/Core/Core/Debugger/GCELF.h +++ b/Source/Core/Core/Debugger/GCELF.h @@ -5,108 +5,107 @@ #pragma once // ELF File Types -#define ET_NONE 0 // No file type -#define ET_REL 1 // Relocatable file -#define ET_EXEC 2 // Executable file -#define ET_DYN 3 // Shared object file -#define ET_CORE 4 // Core file -#define ET_LOPROC 0xFF00 // Processor specific -#define ET_HIPROC 0xFFFF // Processor specific +#define ET_NONE 0 // No file type +#define ET_REL 1 // Relocatable file +#define ET_EXEC 2 // Executable file +#define ET_DYN 3 // Shared object file +#define ET_CORE 4 // Core file +#define ET_LOPROC 0xFF00 // Processor specific +#define ET_HIPROC 0xFFFF // Processor specific // ELF Machine Types -#define EM_NONE 0 // No machine -#define EM_M32 1 // AT&T WE 32100 -#define EM_SPARC 2 // SPARC -#define EM_386 3 // Intel Architecture -#define EM_68K 4 // Motorola 68000 -#define EM_88K 5 // Motorola 88000 -#define EM_860 6 // Intel 80860 -#define EM_MIPS 7 // MIPS RS3000 Big-Endian -#define EM_MIPS_RS4_BE 8 // MIPS RS4000 Big-Endian -#define EM_ARM 40 // ARM/Thumb Architecture +#define EM_NONE 0 // No machine +#define EM_M32 1 // AT&T WE 32100 +#define EM_SPARC 2 // SPARC +#define EM_386 3 // Intel Architecture +#define EM_68K 4 // Motorola 68000 +#define EM_88K 5 // Motorola 88000 +#define EM_860 6 // Intel 80860 +#define EM_MIPS 7 // MIPS RS3000 Big-Endian +#define EM_MIPS_RS4_BE 8 // MIPS RS4000 Big-Endian +#define EM_ARM 40 // ARM/Thumb Architecture // ELF Version Types -#define EV_NONE 0 // Invalid version -#define EV_CURRENT 1 // Current version +#define EV_NONE 0 // Invalid version +#define EV_CURRENT 1 // Current version // ELF Section Header Types -#define SHT_NULL 0 -#define SHT_PROGBITS 1 -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_RELA 4 -#define SHT_HASH 5 -#define SHT_DYNAMIC 6 -#define SHT_NOTE 7 -#define SHT_NOBITS 8 -#define SHT_REL 9 -#define SHT_SHLIB 10 -#define SHT_DYNSYM 11 - +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 struct ELF_Header { - unsigned char ID[4]; - unsigned char clazz; - unsigned char data; - unsigned char version; - unsigned char pad[9]; - unsigned short e_type; // ELF file type - unsigned short e_machine; // ELF target machine - unsigned int e_version; // ELF file version number - unsigned int e_entry; - unsigned int e_phoff; - unsigned int e_shoff; - unsigned int e_flags; - unsigned short e_ehsize; - unsigned short e_phentsize; - unsigned short e_phnum; - unsigned short e_shentsize; - unsigned short e_shnum; - unsigned short e_shtrndx; + unsigned char ID[4]; + unsigned char clazz; + unsigned char data; + unsigned char version; + unsigned char pad[9]; + unsigned short e_type; // ELF file type + unsigned short e_machine; // ELF target machine + unsigned int e_version; // ELF file version number + unsigned int e_entry; + unsigned int e_phoff; + unsigned int e_shoff; + unsigned int e_flags; + unsigned short e_ehsize; + unsigned short e_phentsize; + unsigned short e_phnum; + unsigned short e_shentsize; + unsigned short e_shnum; + unsigned short e_shtrndx; }; struct Program_Header { - unsigned int type; - unsigned int offset; - unsigned int vaddr; - unsigned int paddr; - unsigned int filesz; - unsigned int memsz; - unsigned int flags; - unsigned int align; + unsigned int type; + unsigned int offset; + unsigned int vaddr; + unsigned int paddr; + unsigned int filesz; + unsigned int memsz; + unsigned int flags; + unsigned int align; }; struct Section_Header { - unsigned int name; - unsigned int type; - unsigned int flags; - unsigned int addr; - unsigned int offset; - unsigned int size; - unsigned int link; - unsigned int info; - unsigned int addralign; - unsigned int entsize; + unsigned int name; + unsigned int type; + unsigned int flags; + unsigned int addr; + unsigned int offset; + unsigned int size; + unsigned int link; + unsigned int info; + unsigned int addralign; + unsigned int entsize; }; struct Symbol_Header { - unsigned int name; - unsigned int value; - unsigned int size; - unsigned char info; - unsigned char other; - unsigned short shndx; + unsigned int name; + unsigned int value; + unsigned int size; + unsigned char info; + unsigned char other; + unsigned short shndx; }; struct Rela_Header { - unsigned int offset; - unsigned int info; - signed int addend; + unsigned int offset; + unsigned int info; + signed int addend; }; const char ELFID[4] = {0x7F, 'E', 'L', 'F'}; diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.cpp b/Source/Core/Core/Debugger/PPCDebugInterface.cpp index 9d6eacef8e..4356c27d9f 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.cpp +++ b/Source/Core/Core/Debugger/PPCDebugInterface.cpp @@ -7,212 +7,205 @@ #include "Common/GekkoDisassembler.h" #include "Core/Core.h" -#include "Core/Host.h" #include "Core/Debugger/Debugger_SymbolMap.h" #include "Core/Debugger/PPCDebugInterface.h" #include "Core/HW/DSP.h" #include "Core/HW/Memmap.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCSymbolDB.h" +#include "Core/Host.h" #include "Core/PowerPC/JitCommon/JitBase.h" +#include "Core/PowerPC/PPCSymbolDB.h" +#include "Core/PowerPC/PowerPC.h" std::string PPCDebugInterface::Disassemble(unsigned int address) { - // PowerPC::HostRead_U32 seemed to crash on shutdown - if (!IsAlive()) - return ""; + // PowerPC::HostRead_U32 seemed to crash on shutdown + if (!IsAlive()) + return ""; - if (Core::GetState() == Core::CORE_PAUSE) - { - if (!PowerPC::HostIsRAMAddress(address)) - { - return "(No RAM here)"; - } + if (Core::GetState() == Core::CORE_PAUSE) + { + if (!PowerPC::HostIsRAMAddress(address)) + { + return "(No RAM here)"; + } - u32 op = PowerPC::HostRead_Instruction(address); - std::string disasm = GekkoDisassembler::Disassemble(op, address); + u32 op = PowerPC::HostRead_Instruction(address); + std::string disasm = GekkoDisassembler::Disassemble(op, address); - UGeckoInstruction inst; - inst.hex = PowerPC::HostRead_U32(address); + UGeckoInstruction inst; + inst.hex = PowerPC::HostRead_U32(address); - if (inst.OPCD == 1) - { - disasm += " (hle)"; - } + if (inst.OPCD == 1) + { + disasm += " (hle)"; + } - return disasm; - } - else - { - return ""; - } + return disasm; + } + else + { + return ""; + } } -void PPCDebugInterface::GetRawMemoryString(int memory, unsigned int address, char *dest, int max_size) +void PPCDebugInterface::GetRawMemoryString(int memory, unsigned int address, char* dest, + int max_size) { - if (IsAlive()) - { - if (memory || PowerPC::HostIsRAMAddress(address)) - { - snprintf(dest, max_size, "%08X%s", ReadExtraMemory(memory, address), memory ? " (ARAM)" : ""); - } - else - { - strcpy(dest, memory ? "--ARAM--" : "--------"); - } - } - else - { - strcpy(dest, ""); // bad spelling - 8 chars - } + if (IsAlive()) + { + if (memory || PowerPC::HostIsRAMAddress(address)) + { + snprintf(dest, max_size, "%08X%s", ReadExtraMemory(memory, address), memory ? " (ARAM)" : ""); + } + else + { + strcpy(dest, memory ? "--ARAM--" : "--------"); + } + } + else + { + strcpy(dest, ""); // bad spelling - 8 chars + } } unsigned int PPCDebugInterface::ReadMemory(unsigned int address) { - return PowerPC::HostRead_U32(address); + return PowerPC::HostRead_U32(address); } unsigned int PPCDebugInterface::ReadExtraMemory(int memory, unsigned int address) { - switch (memory) - { - case 0: - return PowerPC::HostRead_U32(address); - case 1: - return (DSP::ReadARAM(address) << 24) | - (DSP::ReadARAM(address + 1) << 16) | - (DSP::ReadARAM(address + 2) << 8) | - (DSP::ReadARAM(address + 3)); - default: - return 0; - } + switch (memory) + { + case 0: + return PowerPC::HostRead_U32(address); + case 1: + return (DSP::ReadARAM(address) << 24) | (DSP::ReadARAM(address + 1) << 16) | + (DSP::ReadARAM(address + 2) << 8) | (DSP::ReadARAM(address + 3)); + default: + return 0; + } } unsigned int PPCDebugInterface::ReadInstruction(unsigned int address) { - return PowerPC::HostRead_Instruction(address); + return PowerPC::HostRead_Instruction(address); } bool PPCDebugInterface::IsAlive() { - return Core::IsRunning(); + return Core::IsRunning(); } bool PPCDebugInterface::IsBreakpoint(unsigned int address) { - return PowerPC::breakpoints.IsAddressBreakPoint(address); + return PowerPC::breakpoints.IsAddressBreakPoint(address); } void PPCDebugInterface::SetBreakpoint(unsigned int address) { - PowerPC::breakpoints.Add(address); + PowerPC::breakpoints.Add(address); } void PPCDebugInterface::ClearBreakpoint(unsigned int address) { - PowerPC::breakpoints.Remove(address); + PowerPC::breakpoints.Remove(address); } void PPCDebugInterface::ClearAllBreakpoints() { - PowerPC::breakpoints.Clear(); + PowerPC::breakpoints.Clear(); } void PPCDebugInterface::ToggleBreakpoint(unsigned int address) { - if (PowerPC::breakpoints.IsAddressBreakPoint(address)) - PowerPC::breakpoints.Remove(address); - else - PowerPC::breakpoints.Add(address); + if (PowerPC::breakpoints.IsAddressBreakPoint(address)) + PowerPC::breakpoints.Remove(address); + else + PowerPC::breakpoints.Add(address); } void PPCDebugInterface::AddWatch(unsigned int address) { - PowerPC::watches.Add(address); + PowerPC::watches.Add(address); } void PPCDebugInterface::ClearAllMemChecks() { - PowerPC::memchecks.Clear(); + PowerPC::memchecks.Clear(); } bool PPCDebugInterface::IsMemCheck(unsigned int address) { - return (Memory::AreMemoryBreakpointsActivated() && - PowerPC::memchecks.GetMemCheck(address)); + return (Memory::AreMemoryBreakpointsActivated() && PowerPC::memchecks.GetMemCheck(address)); } void PPCDebugInterface::ToggleMemCheck(unsigned int address) { - if (Memory::AreMemoryBreakpointsActivated() && - !PowerPC::memchecks.GetMemCheck(address)) - { - // Add Memory Check - TMemCheck MemCheck; - MemCheck.StartAddress = address; - MemCheck.EndAddress = address; - MemCheck.OnRead = true; - MemCheck.OnWrite = true; + if (Memory::AreMemoryBreakpointsActivated() && !PowerPC::memchecks.GetMemCheck(address)) + { + // Add Memory Check + TMemCheck MemCheck; + MemCheck.StartAddress = address; + MemCheck.EndAddress = address; + MemCheck.OnRead = true; + MemCheck.OnWrite = true; - MemCheck.Log = true; - MemCheck.Break = true; + MemCheck.Log = true; + MemCheck.Break = true; - PowerPC::memchecks.Add(MemCheck); - } - else - PowerPC::memchecks.Remove(address); + PowerPC::memchecks.Add(MemCheck); + } + else + PowerPC::memchecks.Remove(address); } void PPCDebugInterface::InsertBLR(unsigned int address, unsigned int value) { - PowerPC::HostWrite_U32(value, address); + PowerPC::HostWrite_U32(value, address); } - // ======================================================= // Separate the blocks with colors. // ------------- int PPCDebugInterface::GetColor(unsigned int address) { - if (!IsAlive()) - return 0xFFFFFF; - if (!PowerPC::HostIsRAMAddress(address)) - return 0xeeeeee; - static const int colors[6] = - { - 0xd0FFFF, // light cyan - 0xFFd0d0, // light red - 0xd8d8FF, // light blue - 0xFFd0FF, // light purple - 0xd0FFd0, // light green - 0xFFFFd0, // light yellow - }; - Symbol *symbol = g_symbolDB.GetSymbolFromAddr(address); - if (!symbol) - return 0xFFFFFF; - if (symbol->type != Symbol::SYMBOL_FUNCTION) - return 0xEEEEFF; - return colors[symbol->index % 6]; + if (!IsAlive()) + return 0xFFFFFF; + if (!PowerPC::HostIsRAMAddress(address)) + return 0xeeeeee; + static const int colors[6] = { + 0xd0FFFF, // light cyan + 0xFFd0d0, // light red + 0xd8d8FF, // light blue + 0xFFd0FF, // light purple + 0xd0FFd0, // light green + 0xFFFFd0, // light yellow + }; + Symbol* symbol = g_symbolDB.GetSymbolFromAddr(address); + if (!symbol) + return 0xFFFFFF; + if (symbol->type != Symbol::SYMBOL_FUNCTION) + return 0xEEEEFF; + return colors[symbol->index % 6]; } // ============= - std::string PPCDebugInterface::GetDescription(unsigned int address) { - return g_symbolDB.GetDescription(address); + return g_symbolDB.GetDescription(address); } unsigned int PPCDebugInterface::GetPC() { - return PowerPC::ppcState.pc; + return PowerPC::ppcState.pc; } void PPCDebugInterface::SetPC(unsigned int address) { - PowerPC::ppcState.pc = address; + PowerPC::ppcState.pc = address; } void PPCDebugInterface::RunToBreakpoint() { - } diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.h b/Source/Core/Core/Debugger/PPCDebugInterface.h index 4b24c6488c..be4a7a1502 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.h +++ b/Source/Core/Core/Debugger/PPCDebugInterface.h @@ -8,39 +8,39 @@ #include "Common/DebugInterface.h" -//wrapper between disasm control and Dolphin debugger +// wrapper between disasm control and Dolphin debugger class PPCDebugInterface final : public DebugInterface { public: - PPCDebugInterface(){} - std::string Disassemble(unsigned int address) override; - void GetRawMemoryString(int memory, unsigned int address, char *dest, int max_size) override; - int GetInstructionSize(int /*instruction*/) override {return 4;} - bool IsAlive() override; - bool IsBreakpoint(unsigned int address) override; - void SetBreakpoint(unsigned int address) override; - void ClearBreakpoint(unsigned int address) override; - void ClearAllBreakpoints() override; - void AddWatch(unsigned int address) override; - void ToggleBreakpoint(unsigned int address) override; - void ClearAllMemChecks() override; - bool IsMemCheck(unsigned int address) override; - void ToggleMemCheck(unsigned int address) override; - unsigned int ReadMemory(unsigned int address) override; + PPCDebugInterface() {} + std::string Disassemble(unsigned int address) override; + void GetRawMemoryString(int memory, unsigned int address, char* dest, int max_size) override; + int GetInstructionSize(int /*instruction*/) override { return 4; } + bool IsAlive() override; + bool IsBreakpoint(unsigned int address) override; + void SetBreakpoint(unsigned int address) override; + void ClearBreakpoint(unsigned int address) override; + void ClearAllBreakpoints() override; + void AddWatch(unsigned int address) override; + void ToggleBreakpoint(unsigned int address) override; + void ClearAllMemChecks() override; + bool IsMemCheck(unsigned int address) override; + void ToggleMemCheck(unsigned int address) override; + unsigned int ReadMemory(unsigned int address) override; - enum - { - EXTRAMEM_ARAM = 1, - }; + enum + { + EXTRAMEM_ARAM = 1, + }; - unsigned int ReadExtraMemory(int memory, unsigned int address) override; - unsigned int ReadInstruction(unsigned int address) override; - unsigned int GetPC() override; - void SetPC(unsigned int address) override; - void Step() override {} - void RunToBreakpoint() override; - void InsertBLR(unsigned int address, unsigned int value) override; - int GetColor(unsigned int address) override; - std::string GetDescription(unsigned int address) override; + unsigned int ReadExtraMemory(int memory, unsigned int address) override; + unsigned int ReadInstruction(unsigned int address) override; + unsigned int GetPC() override; + void SetPC(unsigned int address) override; + void Step() override {} + void RunToBreakpoint() override; + void InsertBLR(unsigned int address, unsigned int value) override; + int GetColor(unsigned int address) override; + std::string GetDescription(unsigned int address) override; }; diff --git a/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp b/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp index ac970bb9e6..22358fb501 100644 --- a/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoAnalyzer.cpp @@ -19,263 +19,274 @@ namespace FifoAnalyzer { - bool s_DrawingObject; FifoAnalyzer::CPMemory s_CpMem; void Init() { - VertexLoader_Normal::Init(); + VertexLoader_Normal::Init(); } u8 ReadFifo8(u8*& data) { - u8 value = data[0]; - data += 1; - return value; + u8 value = data[0]; + data += 1; + return value; } u16 ReadFifo16(u8*& data) { - u16 value = Common::swap16(data); - data += 2; - return value; + u16 value = Common::swap16(data); + data += 2; + return value; } u32 ReadFifo32(u8*& data) { - u32 value = Common::swap32(data); - data += 4; - return value; + u32 value = Common::swap32(data); + data += 4; + return value; } u32 AnalyzeCommand(u8* data, DecodeMode mode) { - u8* dataStart = data; + u8* dataStart = data; - int cmd = ReadFifo8(data); + int cmd = ReadFifo8(data); - switch (cmd) - { - case GX_NOP: - case 0x44: - case GX_CMD_INVL_VC: - break; + switch (cmd) + { + case GX_NOP: + case 0x44: + case GX_CMD_INVL_VC: + break; - case GX_LOAD_CP_REG: - { - s_DrawingObject = false; + case GX_LOAD_CP_REG: + { + s_DrawingObject = false; - u32 cmd2 = ReadFifo8(data); - u32 value = ReadFifo32(data); - LoadCPReg(cmd2, value, s_CpMem); - break; - } + u32 cmd2 = ReadFifo8(data); + u32 value = ReadFifo32(data); + LoadCPReg(cmd2, value, s_CpMem); + break; + } - case GX_LOAD_XF_REG: - { - s_DrawingObject = false; + case GX_LOAD_XF_REG: + { + s_DrawingObject = false; - u32 cmd2 = ReadFifo32(data); - u8 streamSize = ((cmd2 >> 16) & 15) + 1; + u32 cmd2 = ReadFifo32(data); + u8 streamSize = ((cmd2 >> 16) & 15) + 1; - data += streamSize * 4; - break; - } + data += streamSize * 4; + break; + } - case GX_LOAD_INDX_A: - case GX_LOAD_INDX_B: - case GX_LOAD_INDX_C: - case GX_LOAD_INDX_D: - { - s_DrawingObject = false; + case GX_LOAD_INDX_A: + case GX_LOAD_INDX_B: + case GX_LOAD_INDX_C: + case GX_LOAD_INDX_D: + { + s_DrawingObject = false; - int array = 0xc + (cmd - GX_LOAD_INDX_A) / 8; - u32 value = ReadFifo32(data); + int array = 0xc + (cmd - GX_LOAD_INDX_A) / 8; + u32 value = ReadFifo32(data); - if (mode == DECODE_RECORD) - FifoRecordAnalyzer::ProcessLoadIndexedXf(value, array); - break; - } + if (mode == DECODE_RECORD) + FifoRecordAnalyzer::ProcessLoadIndexedXf(value, array); + break; + } - case GX_CMD_CALL_DL: - // The recorder should have expanded display lists into the fifo stream and skipped the call to start them - // That is done to make it easier to track where memory is updated - _assert_(false); - data += 8; - break; + case GX_CMD_CALL_DL: + // The recorder should have expanded display lists into the fifo stream and skipped the call to + // start them + // That is done to make it easier to track where memory is updated + _assert_(false); + data += 8; + break; - case GX_LOAD_BP_REG: - { - s_DrawingObject = false; - ReadFifo32(data); - break; - } + case GX_LOAD_BP_REG: + { + s_DrawingObject = false; + ReadFifo32(data); + break; + } - default: - if (cmd & 0x80) - { - s_DrawingObject = true; + default: + if (cmd & 0x80) + { + s_DrawingObject = true; - int sizes[21]; - FifoAnalyzer::CalculateVertexElementSizes(sizes, cmd & GX_VAT_MASK, s_CpMem); + int sizes[21]; + FifoAnalyzer::CalculateVertexElementSizes(sizes, cmd & GX_VAT_MASK, s_CpMem); - // Determine offset of each element that might be a vertex array - // The first 9 elements are never vertex arrays so we just accumulate their sizes. - int offsets[12]; - int offset = std::accumulate(&sizes[0], &sizes[9], 0u); - for (int i = 0; i < 12; ++i) - { - offsets[i] = offset; - offset += sizes[i + 9]; - } + // Determine offset of each element that might be a vertex array + // The first 9 elements are never vertex arrays so we just accumulate their sizes. + int offsets[12]; + int offset = std::accumulate(&sizes[0], &sizes[9], 0u); + for (int i = 0; i < 12; ++i) + { + offsets[i] = offset; + offset += sizes[i + 9]; + } - int vertexSize = offset; - int numVertices = ReadFifo16(data); + int vertexSize = offset; + int numVertices = ReadFifo16(data); - if (mode == DECODE_RECORD && numVertices > 0) - { - for (int i = 0; i < 12; ++i) - { - FifoRecordAnalyzer::WriteVertexArray(i, data + offsets[i], vertexSize, numVertices); - } - } + if (mode == DECODE_RECORD && numVertices > 0) + { + for (int i = 0; i < 12; ++i) + { + FifoRecordAnalyzer::WriteVertexArray(i, data + offsets[i], vertexSize, numVertices); + } + } - data += numVertices * vertexSize; - } - else - { - PanicAlert("FifoPlayer: Unknown Opcode (0x%x).\n", cmd); - return 0; - } - break; - } + data += numVertices * vertexSize; + } + else + { + PanicAlert("FifoPlayer: Unknown Opcode (0x%x).\n", cmd); + return 0; + } + break; + } - return (u32)(data - dataStart); + return (u32)(data - dataStart); } void LoadCPReg(u32 subCmd, u32 value, CPMemory& cpMem) { - switch (subCmd & 0xF0) - { - case 0x50: - cpMem.vtxDesc.Hex &= ~0x1FFFF; // keep the Upper bits - cpMem.vtxDesc.Hex |= value; - break; + switch (subCmd & 0xF0) + { + case 0x50: + cpMem.vtxDesc.Hex &= ~0x1FFFF; // keep the Upper bits + cpMem.vtxDesc.Hex |= value; + break; - case 0x60: - cpMem.vtxDesc.Hex &= 0x1FFFF; // keep the lower 17Bits - cpMem.vtxDesc.Hex |= (u64)value << 17; - break; + case 0x60: + cpMem.vtxDesc.Hex &= 0x1FFFF; // keep the lower 17Bits + cpMem.vtxDesc.Hex |= (u64)value << 17; + break; - case 0x70: - _assert_((subCmd & 0x0F) < 8); - cpMem.vtxAttr[subCmd & 7].g0.Hex = value; - break; + case 0x70: + _assert_((subCmd & 0x0F) < 8); + cpMem.vtxAttr[subCmd & 7].g0.Hex = value; + break; - case 0x80: - _assert_((subCmd & 0x0F) < 8); - cpMem.vtxAttr[subCmd & 7].g1.Hex = value; - break; + case 0x80: + _assert_((subCmd & 0x0F) < 8); + cpMem.vtxAttr[subCmd & 7].g1.Hex = value; + break; - case 0x90: - _assert_((subCmd & 0x0F) < 8); - cpMem.vtxAttr[subCmd & 7].g2.Hex = value; - break; + case 0x90: + _assert_((subCmd & 0x0F) < 8); + cpMem.vtxAttr[subCmd & 7].g2.Hex = value; + break; - case 0xA0: - cpMem.arrayBases[subCmd & 0xF] = value; - break; + case 0xA0: + cpMem.arrayBases[subCmd & 0xF] = value; + break; - case 0xB0: - cpMem.arrayStrides[subCmd & 0xF] = value & 0xFF; - break; - } + case 0xB0: + cpMem.arrayStrides[subCmd & 0xF] = value & 0xFF; + break; + } } void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory& cpMem) { - const TVtxDesc &vtxDesc = cpMem.vtxDesc; - const VAT &vtxAttr = cpMem.vtxAttr[vatIndex]; + const TVtxDesc& vtxDesc = cpMem.vtxDesc; + const VAT& vtxAttr = cpMem.vtxAttr[vatIndex]; - // Colors - const u64 colDesc[2] = {vtxDesc.Color0, vtxDesc.Color1}; - const u32 colComp[2] = {vtxAttr.g0.Color0Comp, vtxAttr.g0.Color1Comp}; + // Colors + const u64 colDesc[2] = {vtxDesc.Color0, vtxDesc.Color1}; + const u32 colComp[2] = {vtxAttr.g0.Color0Comp, vtxAttr.g0.Color1Comp}; - const u32 tcElements[8] = - { - vtxAttr.g0.Tex0CoordElements, vtxAttr.g1.Tex1CoordElements, vtxAttr.g1.Tex2CoordElements, - vtxAttr.g1.Tex3CoordElements, vtxAttr.g1.Tex4CoordElements, vtxAttr.g2.Tex5CoordElements, - vtxAttr.g2.Tex6CoordElements, vtxAttr.g2.Tex7CoordElements - }; + const u32 tcElements[8] = {vtxAttr.g0.Tex0CoordElements, vtxAttr.g1.Tex1CoordElements, + vtxAttr.g1.Tex2CoordElements, vtxAttr.g1.Tex3CoordElements, + vtxAttr.g1.Tex4CoordElements, vtxAttr.g2.Tex5CoordElements, + vtxAttr.g2.Tex6CoordElements, vtxAttr.g2.Tex7CoordElements}; - const u32 tcFormat[8] = - { - vtxAttr.g0.Tex0CoordFormat, vtxAttr.g1.Tex1CoordFormat, vtxAttr.g1.Tex2CoordFormat, - vtxAttr.g1.Tex3CoordFormat, vtxAttr.g1.Tex4CoordFormat, vtxAttr.g2.Tex5CoordFormat, - vtxAttr.g2.Tex6CoordFormat, vtxAttr.g2.Tex7CoordFormat - }; + const u32 tcFormat[8] = {vtxAttr.g0.Tex0CoordFormat, vtxAttr.g1.Tex1CoordFormat, + vtxAttr.g1.Tex2CoordFormat, vtxAttr.g1.Tex3CoordFormat, + vtxAttr.g1.Tex4CoordFormat, vtxAttr.g2.Tex5CoordFormat, + vtxAttr.g2.Tex6CoordFormat, vtxAttr.g2.Tex7CoordFormat}; - // Add position and texture matrix indices - u64 vtxDescHex = cpMem.vtxDesc.Hex; - for (int i = 0; i < 9; ++i) - { - sizes[i] = vtxDescHex & 1; - vtxDescHex >>= 1; - } + // Add position and texture matrix indices + u64 vtxDescHex = cpMem.vtxDesc.Hex; + for (int i = 0; i < 9; ++i) + { + sizes[i] = vtxDescHex & 1; + vtxDescHex >>= 1; + } - // Position - sizes[9] = VertexLoader_Position::GetSize(vtxDesc.Position, vtxAttr.g0.PosFormat, vtxAttr.g0.PosElements); + // Position + sizes[9] = VertexLoader_Position::GetSize(vtxDesc.Position, vtxAttr.g0.PosFormat, + vtxAttr.g0.PosElements); - // Normals - if (vtxDesc.Normal != NOT_PRESENT) - { - sizes[10] = VertexLoader_Normal::GetSize(vtxDesc.Normal, vtxAttr.g0.NormalFormat, vtxAttr.g0.NormalElements, vtxAttr.g0.NormalIndex3); - } - else - { - sizes[10] = 0; - } + // Normals + if (vtxDesc.Normal != NOT_PRESENT) + { + sizes[10] = VertexLoader_Normal::GetSize(vtxDesc.Normal, vtxAttr.g0.NormalFormat, + vtxAttr.g0.NormalElements, vtxAttr.g0.NormalIndex3); + } + else + { + sizes[10] = 0; + } - // Colors - for (int i = 0; i < 2; i++) - { - int size = 0; + // Colors + for (int i = 0; i < 2; i++) + { + int size = 0; - switch (colDesc[i]) - { - case NOT_PRESENT: - break; - case DIRECT: - switch (colComp[i]) - { - case FORMAT_16B_565: size = 2; break; - case FORMAT_24B_888: size = 3; break; - case FORMAT_32B_888x: size = 4; break; - case FORMAT_16B_4444: size = 2; break; - case FORMAT_24B_6666: size = 3; break; - case FORMAT_32B_8888: size = 4; break; - default: _assert_(0); break; - } - break; - case INDEX8: - size = 1; - break; - case INDEX16: - size = 2; - break; - } + switch (colDesc[i]) + { + case NOT_PRESENT: + break; + case DIRECT: + switch (colComp[i]) + { + case FORMAT_16B_565: + size = 2; + break; + case FORMAT_24B_888: + size = 3; + break; + case FORMAT_32B_888x: + size = 4; + break; + case FORMAT_16B_4444: + size = 2; + break; + case FORMAT_24B_6666: + size = 3; + break; + case FORMAT_32B_8888: + size = 4; + break; + default: + _assert_(0); + break; + } + break; + case INDEX8: + size = 1; + break; + case INDEX16: + size = 2; + break; + } - sizes[11 + i] = size; - } + sizes[11 + i] = size; + } - // Texture coordinates - vtxDescHex = vtxDesc.Hex >> 17; - for (int i = 0; i < 8; i++) - { - sizes[13 + i] = VertexLoader_TextCoord::GetSize(vtxDescHex & 3, tcFormat[i], tcElements[i]); - vtxDescHex >>= 2; - } + // Texture coordinates + vtxDescHex = vtxDesc.Hex >> 17; + for (int i = 0; i < 8; i++) + { + sizes[13 + i] = VertexLoader_TextCoord::GetSize(vtxDescHex & 3, tcFormat[i], tcElements[i]); + vtxDescHex >>= 2; + } } - } diff --git a/Source/Core/Core/FifoPlayer/FifoAnalyzer.h b/Source/Core/Core/FifoPlayer/FifoAnalyzer.h index 328b035a9a..162d1b0b74 100644 --- a/Source/Core/Core/FifoPlayer/FifoAnalyzer.h +++ b/Source/Core/Core/FifoPlayer/FifoAnalyzer.h @@ -11,32 +11,32 @@ namespace FifoAnalyzer { - void Init(); +void Init(); - u8 ReadFifo8(u8*& data); - u16 ReadFifo16(u8*& data); - u32 ReadFifo32(u8*& data); +u8 ReadFifo8(u8*& data); +u16 ReadFifo16(u8*& data); +u32 ReadFifo32(u8*& data); - enum DecodeMode - { - DECODE_RECORD, - DECODE_PLAYBACK, - }; +enum DecodeMode +{ + DECODE_RECORD, + DECODE_PLAYBACK, +}; - u32 AnalyzeCommand(u8* data, DecodeMode mode); +u32 AnalyzeCommand(u8* data, DecodeMode mode); - struct CPMemory - { - TVtxDesc vtxDesc; - VAT vtxAttr[8]; - u32 arrayBases[16]; - u32 arrayStrides[16]; - }; +struct CPMemory +{ + TVtxDesc vtxDesc; + VAT vtxAttr[8]; + u32 arrayBases[16]; + u32 arrayStrides[16]; +}; - void LoadCPReg(u32 subCmd, u32 value, CPMemory& cpMem); +void LoadCPReg(u32 subCmd, u32 value, CPMemory& cpMem); - void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory& cpMem); +void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory& cpMem); - extern bool s_DrawingObject; - extern FifoAnalyzer::CPMemory s_CpMem; +extern bool s_DrawingObject; +extern FifoAnalyzer::CPMemory s_CpMem; } diff --git a/Source/Core/Core/FifoPlayer/FifoDataFile.cpp b/Source/Core/Core/FifoPlayer/FifoDataFile.cpp index 9bc09f10e2..cab3816480 100644 --- a/Source/Core/Core/FifoPlayer/FifoDataFile.cpp +++ b/Source/Core/Core/FifoPlayer/FifoDataFile.cpp @@ -12,263 +12,265 @@ using namespace FifoFileStruct; -FifoDataFile::FifoDataFile() : - m_Flags(0) +FifoDataFile::FifoDataFile() : m_Flags(0) { } FifoDataFile::~FifoDataFile() { - for (auto& frame : m_Frames) - { - for (auto& update : frame.memoryUpdates) - delete []update.data; + for (auto& frame : m_Frames) + { + for (auto& update : frame.memoryUpdates) + delete[] update.data; - delete []frame.fifoData; - } + delete[] frame.fifoData; + } } bool FifoDataFile::HasBrokenEFBCopies() const { - return m_Version < 2; + return m_Version < 2; } void FifoDataFile::SetIsWii(bool isWii) { - SetFlag(FLAG_IS_WII, isWii); + SetFlag(FLAG_IS_WII, isWii); } bool FifoDataFile::GetIsWii() const { - return GetFlag(FLAG_IS_WII); + return GetFlag(FLAG_IS_WII); } void FifoDataFile::AddFrame(const FifoFrameInfo& frameInfo) { - m_Frames.push_back(frameInfo); + m_Frames.push_back(frameInfo); } bool FifoDataFile::Save(const std::string& filename) { - File::IOFile file; - if (!file.Open(filename, "wb")) - return false; + File::IOFile file; + if (!file.Open(filename, "wb")) + return false; - // Add space for header - PadFile(sizeof(FileHeader), file); + // Add space for header + PadFile(sizeof(FileHeader), file); - // Add space for frame list - u64 frameListOffset = file.Tell(); - PadFile(m_Frames.size() * sizeof(FileFrameInfo), file); + // Add space for frame list + u64 frameListOffset = file.Tell(); + PadFile(m_Frames.size() * sizeof(FileFrameInfo), file); - u64 bpMemOffset = file.Tell(); - file.WriteArray(m_BPMem, BP_MEM_SIZE); + u64 bpMemOffset = file.Tell(); + file.WriteArray(m_BPMem, BP_MEM_SIZE); - u64 cpMemOffset = file.Tell(); - file.WriteArray(m_CPMem, CP_MEM_SIZE); + u64 cpMemOffset = file.Tell(); + file.WriteArray(m_CPMem, CP_MEM_SIZE); - u64 xfMemOffset = file.Tell(); - file.WriteArray(m_XFMem, XF_MEM_SIZE); + u64 xfMemOffset = file.Tell(); + file.WriteArray(m_XFMem, XF_MEM_SIZE); - u64 xfRegsOffset = file.Tell(); - file.WriteArray(m_XFRegs, XF_REGS_SIZE); + u64 xfRegsOffset = file.Tell(); + file.WriteArray(m_XFRegs, XF_REGS_SIZE); - // Write header - FileHeader header; - header.fileId = FILE_ID; - header.file_version = VERSION_NUMBER; - header.min_loader_version = MIN_LOADER_VERSION; + // Write header + FileHeader header; + header.fileId = FILE_ID; + header.file_version = VERSION_NUMBER; + header.min_loader_version = MIN_LOADER_VERSION; - header.bpMemOffset = bpMemOffset; - header.bpMemSize = BP_MEM_SIZE; + header.bpMemOffset = bpMemOffset; + header.bpMemSize = BP_MEM_SIZE; - header.cpMemOffset = cpMemOffset; - header.cpMemSize = CP_MEM_SIZE; + header.cpMemOffset = cpMemOffset; + header.cpMemSize = CP_MEM_SIZE; - header.xfMemOffset = xfMemOffset; - header.xfMemSize = XF_MEM_SIZE; + header.xfMemOffset = xfMemOffset; + header.xfMemSize = XF_MEM_SIZE; - header.xfRegsOffset = xfRegsOffset; - header.xfRegsSize = XF_REGS_SIZE; + header.xfRegsOffset = xfRegsOffset; + header.xfRegsSize = XF_REGS_SIZE; - header.frameListOffset = frameListOffset; - header.frameCount = (u32)m_Frames.size(); + header.frameListOffset = frameListOffset; + header.frameCount = (u32)m_Frames.size(); - header.flags = m_Flags; + header.flags = m_Flags; - file.Seek(0, SEEK_SET); - file.WriteBytes(&header, sizeof(FileHeader)); + file.Seek(0, SEEK_SET); + file.WriteBytes(&header, sizeof(FileHeader)); - // Write frames list - for (unsigned int i = 0; i < m_Frames.size(); ++i) - { - const FifoFrameInfo &srcFrame = m_Frames[i]; + // Write frames list + for (unsigned int i = 0; i < m_Frames.size(); ++i) + { + const FifoFrameInfo& srcFrame = m_Frames[i]; - // Write FIFO data - file.Seek(0, SEEK_END); - u64 dataOffset = file.Tell(); - file.WriteBytes(srcFrame.fifoData, srcFrame.fifoDataSize); + // Write FIFO data + file.Seek(0, SEEK_END); + u64 dataOffset = file.Tell(); + file.WriteBytes(srcFrame.fifoData, srcFrame.fifoDataSize); - u64 memoryUpdatesOffset = WriteMemoryUpdates(srcFrame.memoryUpdates, file); + u64 memoryUpdatesOffset = WriteMemoryUpdates(srcFrame.memoryUpdates, file); - FileFrameInfo dstFrame; - dstFrame.fifoDataSize = srcFrame.fifoDataSize; - dstFrame.fifoDataOffset = dataOffset; - dstFrame.fifoStart = srcFrame.fifoStart; - dstFrame.fifoEnd = srcFrame.fifoEnd; - dstFrame.memoryUpdatesOffset = memoryUpdatesOffset; - dstFrame.numMemoryUpdates = (u32)srcFrame.memoryUpdates.size(); + FileFrameInfo dstFrame; + dstFrame.fifoDataSize = srcFrame.fifoDataSize; + dstFrame.fifoDataOffset = dataOffset; + dstFrame.fifoStart = srcFrame.fifoStart; + dstFrame.fifoEnd = srcFrame.fifoEnd; + dstFrame.memoryUpdatesOffset = memoryUpdatesOffset; + dstFrame.numMemoryUpdates = (u32)srcFrame.memoryUpdates.size(); - // Write frame info - u64 frameOffset = frameListOffset + (i * sizeof(FileFrameInfo)); - file.Seek(frameOffset, SEEK_SET); - file.WriteBytes(&dstFrame, sizeof(FileFrameInfo)); - } + // Write frame info + u64 frameOffset = frameListOffset + (i * sizeof(FileFrameInfo)); + file.Seek(frameOffset, SEEK_SET); + file.WriteBytes(&dstFrame, sizeof(FileFrameInfo)); + } - if (!file.Close()) - return false; + if (!file.Close()) + return false; - return true; + return true; } -FifoDataFile* FifoDataFile::Load(const std::string &filename, bool flagsOnly) +FifoDataFile* FifoDataFile::Load(const std::string& filename, bool flagsOnly) { - File::IOFile file; - file.Open(filename, "rb"); - if (!file) - return nullptr; + File::IOFile file; + file.Open(filename, "rb"); + if (!file) + return nullptr; - FileHeader header; - file.ReadBytes(&header, sizeof(header)); + FileHeader header; + file.ReadBytes(&header, sizeof(header)); - if (header.fileId != FILE_ID || header.min_loader_version > VERSION_NUMBER) - { - file.Close(); - return nullptr; - } + if (header.fileId != FILE_ID || header.min_loader_version > VERSION_NUMBER) + { + file.Close(); + return nullptr; + } - FifoDataFile* dataFile = new FifoDataFile; + FifoDataFile* dataFile = new FifoDataFile; - dataFile->m_Flags = header.flags; - dataFile->m_Version = header.file_version; + dataFile->m_Flags = header.flags; + dataFile->m_Version = header.file_version; - if (flagsOnly) - { - file.Close(); - return dataFile; - } + if (flagsOnly) + { + file.Close(); + return dataFile; + } - u32 size = std::min((u32)BP_MEM_SIZE, header.bpMemSize); - file.Seek(header.bpMemOffset, SEEK_SET); - file.ReadArray(dataFile->m_BPMem, size); + u32 size = std::min((u32)BP_MEM_SIZE, header.bpMemSize); + file.Seek(header.bpMemOffset, SEEK_SET); + file.ReadArray(dataFile->m_BPMem, size); - size = std::min((u32)CP_MEM_SIZE, header.cpMemSize); - file.Seek(header.cpMemOffset, SEEK_SET); - file.ReadArray(dataFile->m_CPMem, size); + size = std::min((u32)CP_MEM_SIZE, header.cpMemSize); + file.Seek(header.cpMemOffset, SEEK_SET); + file.ReadArray(dataFile->m_CPMem, size); - size = std::min((u32)XF_MEM_SIZE, header.xfMemSize); - file.Seek(header.xfMemOffset, SEEK_SET); - file.ReadArray(dataFile->m_XFMem, size); + size = std::min((u32)XF_MEM_SIZE, header.xfMemSize); + file.Seek(header.xfMemOffset, SEEK_SET); + file.ReadArray(dataFile->m_XFMem, size); - size = std::min((u32)XF_REGS_SIZE, header.xfRegsSize); - file.Seek(header.xfRegsOffset, SEEK_SET); - file.ReadArray(dataFile->m_XFRegs, size); + size = std::min((u32)XF_REGS_SIZE, header.xfRegsSize); + file.Seek(header.xfRegsOffset, SEEK_SET); + file.ReadArray(dataFile->m_XFRegs, size); - // Read frames - for (u32 i = 0; i < header.frameCount; ++i) - { - u64 frameOffset = header.frameListOffset + (i * sizeof(FileFrameInfo)); - file.Seek(frameOffset, SEEK_SET); - FileFrameInfo srcFrame; - file.ReadBytes(&srcFrame, sizeof(FileFrameInfo)); + // Read frames + for (u32 i = 0; i < header.frameCount; ++i) + { + u64 frameOffset = header.frameListOffset + (i * sizeof(FileFrameInfo)); + file.Seek(frameOffset, SEEK_SET); + FileFrameInfo srcFrame; + file.ReadBytes(&srcFrame, sizeof(FileFrameInfo)); - FifoFrameInfo dstFrame; - dstFrame.fifoData = new u8[srcFrame.fifoDataSize]; - dstFrame.fifoDataSize = srcFrame.fifoDataSize; - dstFrame.fifoStart = srcFrame.fifoStart; - dstFrame.fifoEnd = srcFrame.fifoEnd; + FifoFrameInfo dstFrame; + dstFrame.fifoData = new u8[srcFrame.fifoDataSize]; + dstFrame.fifoDataSize = srcFrame.fifoDataSize; + dstFrame.fifoStart = srcFrame.fifoStart; + dstFrame.fifoEnd = srcFrame.fifoEnd; - file.Seek(srcFrame.fifoDataOffset, SEEK_SET); - file.ReadBytes(dstFrame.fifoData, srcFrame.fifoDataSize); + file.Seek(srcFrame.fifoDataOffset, SEEK_SET); + file.ReadBytes(dstFrame.fifoData, srcFrame.fifoDataSize); - ReadMemoryUpdates(srcFrame.memoryUpdatesOffset, srcFrame.numMemoryUpdates, dstFrame.memoryUpdates, file); + ReadMemoryUpdates(srcFrame.memoryUpdatesOffset, srcFrame.numMemoryUpdates, + dstFrame.memoryUpdates, file); - dataFile->AddFrame(dstFrame); - } + dataFile->AddFrame(dstFrame); + } - file.Close(); + file.Close(); - return dataFile; + return dataFile; } void FifoDataFile::PadFile(size_t numBytes, File::IOFile& file) { - for (size_t i = 0; i < numBytes; ++i) - fputc(0, file.GetHandle()); + for (size_t i = 0; i < numBytes; ++i) + fputc(0, file.GetHandle()); } void FifoDataFile::SetFlag(u32 flag, bool set) { - if (set) - m_Flags |= flag; - else - m_Flags &= ~flag; + if (set) + m_Flags |= flag; + else + m_Flags &= ~flag; } bool FifoDataFile::GetFlag(u32 flag) const { - return !!(m_Flags & flag); + return !!(m_Flags & flag); } -u64 FifoDataFile::WriteMemoryUpdates(const std::vector& memUpdates, File::IOFile& file) +u64 FifoDataFile::WriteMemoryUpdates(const std::vector& memUpdates, + File::IOFile& file) { - // Add space for memory update list - u64 updateListOffset = file.Tell(); - PadFile(memUpdates.size() * sizeof(FileMemoryUpdate), file); + // Add space for memory update list + u64 updateListOffset = file.Tell(); + PadFile(memUpdates.size() * sizeof(FileMemoryUpdate), file); - for (unsigned int i = 0; i < memUpdates.size(); ++i) - { - const MemoryUpdate &srcUpdate = memUpdates[i]; + for (unsigned int i = 0; i < memUpdates.size(); ++i) + { + const MemoryUpdate& srcUpdate = memUpdates[i]; - // Write memory - file.Seek(0, SEEK_END); - u64 dataOffset = file.Tell(); - file.WriteBytes(srcUpdate.data, srcUpdate.size); + // Write memory + file.Seek(0, SEEK_END); + u64 dataOffset = file.Tell(); + file.WriteBytes(srcUpdate.data, srcUpdate.size); - FileMemoryUpdate dstUpdate; - dstUpdate.address = srcUpdate.address; - dstUpdate.dataOffset = dataOffset; - dstUpdate.dataSize = srcUpdate.size; - dstUpdate.fifoPosition = srcUpdate.fifoPosition; - dstUpdate.type = srcUpdate.type; + FileMemoryUpdate dstUpdate; + dstUpdate.address = srcUpdate.address; + dstUpdate.dataOffset = dataOffset; + dstUpdate.dataSize = srcUpdate.size; + dstUpdate.fifoPosition = srcUpdate.fifoPosition; + dstUpdate.type = srcUpdate.type; - u64 updateOffset = updateListOffset + (i * sizeof(FileMemoryUpdate)); - file.Seek(updateOffset, SEEK_SET); - file.WriteBytes(&dstUpdate, sizeof(FileMemoryUpdate)); - } + u64 updateOffset = updateListOffset + (i * sizeof(FileMemoryUpdate)); + file.Seek(updateOffset, SEEK_SET); + file.WriteBytes(&dstUpdate, sizeof(FileMemoryUpdate)); + } - return updateListOffset; + return updateListOffset; } -void FifoDataFile::ReadMemoryUpdates(u64 fileOffset, u32 numUpdates, std::vector& memUpdates, File::IOFile& file) +void FifoDataFile::ReadMemoryUpdates(u64 fileOffset, u32 numUpdates, + std::vector& memUpdates, File::IOFile& file) { - memUpdates.resize(numUpdates); + memUpdates.resize(numUpdates); - for (u32 i = 0; i < numUpdates; ++i) - { - u64 updateOffset = fileOffset + (i * sizeof(FileMemoryUpdate)); - file.Seek(updateOffset, SEEK_SET); - FileMemoryUpdate srcUpdate; - file.ReadBytes(&srcUpdate, sizeof(FileMemoryUpdate)); + for (u32 i = 0; i < numUpdates; ++i) + { + u64 updateOffset = fileOffset + (i * sizeof(FileMemoryUpdate)); + file.Seek(updateOffset, SEEK_SET); + FileMemoryUpdate srcUpdate; + file.ReadBytes(&srcUpdate, sizeof(FileMemoryUpdate)); - MemoryUpdate& dstUpdate = memUpdates[i]; - dstUpdate.address = srcUpdate.address; - dstUpdate.fifoPosition = srcUpdate.fifoPosition; - dstUpdate.size = srcUpdate.dataSize; - dstUpdate.data = new u8[srcUpdate.dataSize]; - dstUpdate.type = (MemoryUpdate::Type)srcUpdate.type; + MemoryUpdate& dstUpdate = memUpdates[i]; + dstUpdate.address = srcUpdate.address; + dstUpdate.fifoPosition = srcUpdate.fifoPosition; + dstUpdate.size = srcUpdate.dataSize; + dstUpdate.data = new u8[srcUpdate.dataSize]; + dstUpdate.type = (MemoryUpdate::Type)srcUpdate.type; - file.Seek(srcUpdate.dataOffset, SEEK_SET); - file.ReadBytes(dstUpdate.data, srcUpdate.dataSize); - } + file.Seek(srcUpdate.dataOffset, SEEK_SET); + file.ReadBytes(dstUpdate.data, srcUpdate.dataSize); + } } diff --git a/Source/Core/Core/FifoPlayer/FifoDataFile.h b/Source/Core/Core/FifoPlayer/FifoDataFile.h index 8db380033e..5d21ddcbf7 100644 --- a/Source/Core/Core/FifoPlayer/FifoDataFile.h +++ b/Source/Core/Core/FifoPlayer/FifoDataFile.h @@ -11,90 +11,89 @@ namespace File { - class IOFile; +class IOFile; } struct MemoryUpdate { - enum Type - { - TEXTURE_MAP = 0x01, - XF_DATA = 0x02, - VERTEX_STREAM = 0x04, - TMEM = 0x08, - }; + enum Type + { + TEXTURE_MAP = 0x01, + XF_DATA = 0x02, + VERTEX_STREAM = 0x04, + TMEM = 0x08, + }; - u32 fifoPosition; - u32 address; - u32 size; - u8* data; - Type type; + u32 fifoPosition; + u32 address; + u32 size; + u8* data; + Type type; }; struct FifoFrameInfo { - u8* fifoData; - u32 fifoDataSize; + u8* fifoData; + u32 fifoDataSize; - u32 fifoStart; - u32 fifoEnd; + u32 fifoStart; + u32 fifoEnd; - // Must be sorted by fifoPosition - std::vector memoryUpdates; + // Must be sorted by fifoPosition + std::vector memoryUpdates; }; class FifoDataFile { public: - enum - { - BP_MEM_SIZE = 256, - CP_MEM_SIZE = 256, - XF_MEM_SIZE = 4096, - XF_REGS_SIZE = 96, - }; + enum + { + BP_MEM_SIZE = 256, + CP_MEM_SIZE = 256, + XF_MEM_SIZE = 4096, + XF_REGS_SIZE = 96, + }; - FifoDataFile(); - ~FifoDataFile(); + FifoDataFile(); + ~FifoDataFile(); - void SetIsWii(bool isWii); - bool GetIsWii() const; - bool HasBrokenEFBCopies() const; + void SetIsWii(bool isWii); + bool GetIsWii() const; + bool HasBrokenEFBCopies() const; - u32 *GetBPMem() { return m_BPMem; } - u32 *GetCPMem() { return m_CPMem; } - u32 *GetXFMem() { return m_XFMem; } - u32 *GetXFRegs() { return m_XFRegs; } + u32* GetBPMem() { return m_BPMem; } + u32* GetCPMem() { return m_CPMem; } + u32* GetXFMem() { return m_XFMem; } + u32* GetXFRegs() { return m_XFRegs; } + void AddFrame(const FifoFrameInfo& frameInfo); + const FifoFrameInfo& GetFrame(u32 frame) const { return m_Frames[frame]; } + u32 GetFrameCount() const { return static_cast(m_Frames.size()); } + bool Save(const std::string& filename); - void AddFrame(const FifoFrameInfo &frameInfo); - const FifoFrameInfo &GetFrame(u32 frame) const { return m_Frames[frame]; } - u32 GetFrameCount() const { return static_cast(m_Frames.size()); } - - bool Save(const std::string& filename); - - static FifoDataFile* Load(const std::string &filename, bool flagsOnly); + static FifoDataFile* Load(const std::string& filename, bool flagsOnly); private: - enum - { - FLAG_IS_WII = 1 - }; + enum + { + FLAG_IS_WII = 1 + }; - void PadFile(size_t numBytes, File::IOFile &file); + void PadFile(size_t numBytes, File::IOFile& file); - void SetFlag(u32 flag, bool set); - bool GetFlag(u32 flag) const; + void SetFlag(u32 flag, bool set); + bool GetFlag(u32 flag) const; - u64 WriteMemoryUpdates(const std::vector& memUpdates, File::IOFile &file); - static void ReadMemoryUpdates(u64 fileOffset, u32 numUpdates, std::vector& memUpdates, File::IOFile& file); + u64 WriteMemoryUpdates(const std::vector& memUpdates, File::IOFile& file); + static void ReadMemoryUpdates(u64 fileOffset, u32 numUpdates, + std::vector& memUpdates, File::IOFile& file); - u32 m_BPMem[BP_MEM_SIZE]; - u32 m_CPMem[CP_MEM_SIZE]; - u32 m_XFMem[XF_MEM_SIZE]; - u32 m_XFRegs[XF_REGS_SIZE]; + u32 m_BPMem[BP_MEM_SIZE]; + u32 m_CPMem[CP_MEM_SIZE]; + u32 m_XFMem[XF_MEM_SIZE]; + u32 m_XFRegs[XF_REGS_SIZE]; - u32 m_Flags; - u32 m_Version; + u32 m_Flags; + u32 m_Version; - std::vector m_Frames; + std::vector m_Frames; }; diff --git a/Source/Core/Core/FifoPlayer/FifoFileStruct.h b/Source/Core/Core/FifoPlayer/FifoFileStruct.h index 1a2f129a23..5dd2329ee5 100644 --- a/Source/Core/Core/FifoPlayer/FifoFileStruct.h +++ b/Source/Core/Core/FifoPlayer/FifoFileStruct.h @@ -8,62 +8,57 @@ namespace FifoFileStruct { - enum { - FILE_ID = 0x0d01f1f0, - VERSION_NUMBER = 3, - MIN_LOADER_VERSION = 1, + FILE_ID = 0x0d01f1f0, + VERSION_NUMBER = 3, + MIN_LOADER_VERSION = 1, }; #pragma pack(push, 4) -union FileHeader -{ - struct - { - u32 fileId; - u32 file_version; - u32 min_loader_version; - u64 bpMemOffset; - u32 bpMemSize; - u64 cpMemOffset; - u32 cpMemSize; - u64 xfMemOffset; - u32 xfMemSize; - u64 xfRegsOffset; - u32 xfRegsSize; - u64 frameListOffset; - u32 frameCount; - u32 flags; - }; - u32 rawData[32]; +union FileHeader { + struct + { + u32 fileId; + u32 file_version; + u32 min_loader_version; + u64 bpMemOffset; + u32 bpMemSize; + u64 cpMemOffset; + u32 cpMemSize; + u64 xfMemOffset; + u32 xfMemSize; + u64 xfRegsOffset; + u32 xfRegsSize; + u64 frameListOffset; + u32 frameCount; + u32 flags; + }; + u32 rawData[32]; }; -union FileFrameInfo -{ - struct - { - u64 fifoDataOffset; - u32 fifoDataSize; - u32 fifoStart; - u32 fifoEnd; - u64 memoryUpdatesOffset; - u32 numMemoryUpdates; - }; - u32 rawData[16]; +union FileFrameInfo { + struct + { + u64 fifoDataOffset; + u32 fifoDataSize; + u32 fifoStart; + u32 fifoEnd; + u64 memoryUpdatesOffset; + u32 numMemoryUpdates; + }; + u32 rawData[16]; }; - struct FileMemoryUpdate { - u32 fifoPosition; - u32 address; - u64 dataOffset; - u32 dataSize; - u8 type; + u32 fifoPosition; + u32 address; + u64 dataOffset; + u32 dataSize; + u8 type; }; #pragma pack(pop) - } diff --git a/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp b/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp index 9f54b6a095..6d4e56ccb5 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.cpp @@ -2,11 +2,11 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/FifoPlayer/FifoPlaybackAnalyzer.h" #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Core/FifoPlayer/FifoAnalyzer.h" #include "Core/FifoPlayer/FifoDataFile.h" -#include "Core/FifoPlayer/FifoPlaybackAnalyzer.h" #include "VideoCommon/OpcodeDecoding.h" #include "VideoCommon/TextureDecoder.h" #include "VideoCommon/VertexLoader.h" @@ -17,85 +17,87 @@ using namespace FifoAnalyzer; #define LOG_FIFO_CMDS 0 struct CmdData { - u32 size; - u32 offset; - u8* ptr; + u32 size; + u32 offset; + u8* ptr; }; -void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file, std::vector& frameInfo) +void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file, + std::vector& frameInfo) { - u32* cpMem = file->GetCPMem(); - FifoAnalyzer::LoadCPReg(0x50, cpMem[0x50], s_CpMem); - FifoAnalyzer::LoadCPReg(0x60, cpMem[0x60], s_CpMem); + u32* cpMem = file->GetCPMem(); + FifoAnalyzer::LoadCPReg(0x50, cpMem[0x50], s_CpMem); + FifoAnalyzer::LoadCPReg(0x60, cpMem[0x60], s_CpMem); - for (int i = 0; i < 8; ++i) - { - FifoAnalyzer::LoadCPReg(0x70 + i, cpMem[0x70 + i], s_CpMem); - FifoAnalyzer::LoadCPReg(0x80 + i, cpMem[0x80 + i], s_CpMem); - FifoAnalyzer::LoadCPReg(0x90 + i, cpMem[0x90 + i], s_CpMem); - } + for (int i = 0; i < 8; ++i) + { + FifoAnalyzer::LoadCPReg(0x70 + i, cpMem[0x70 + i], s_CpMem); + FifoAnalyzer::LoadCPReg(0x80 + i, cpMem[0x80 + i], s_CpMem); + FifoAnalyzer::LoadCPReg(0x90 + i, cpMem[0x90 + i], s_CpMem); + } - frameInfo.clear(); - frameInfo.resize(file->GetFrameCount()); + frameInfo.clear(); + frameInfo.resize(file->GetFrameCount()); - for (u32 frameIdx = 0; frameIdx < file->GetFrameCount(); ++frameIdx) - { - const FifoFrameInfo& frame = file->GetFrame(frameIdx); - AnalyzedFrameInfo& analyzed = frameInfo[frameIdx]; + for (u32 frameIdx = 0; frameIdx < file->GetFrameCount(); ++frameIdx) + { + const FifoFrameInfo& frame = file->GetFrame(frameIdx); + AnalyzedFrameInfo& analyzed = frameInfo[frameIdx]; - s_DrawingObject = false; + s_DrawingObject = false; - u32 cmdStart = 0; - u32 nextMemUpdate = 0; + u32 cmdStart = 0; + u32 nextMemUpdate = 0; #if LOG_FIFO_CMDS - // Debugging - vector prevCmds; + // Debugging + vector prevCmds; #endif - while (cmdStart < frame.fifoDataSize) - { - // Add memory updates that have occurred before this point in the frame - while (nextMemUpdate < frame.memoryUpdates.size() && frame.memoryUpdates[nextMemUpdate].fifoPosition <= cmdStart) - { - analyzed.memoryUpdates.push_back(frame.memoryUpdates[nextMemUpdate]); - ++nextMemUpdate; - } + while (cmdStart < frame.fifoDataSize) + { + // Add memory updates that have occurred before this point in the frame + while (nextMemUpdate < frame.memoryUpdates.size() && + frame.memoryUpdates[nextMemUpdate].fifoPosition <= cmdStart) + { + analyzed.memoryUpdates.push_back(frame.memoryUpdates[nextMemUpdate]); + ++nextMemUpdate; + } - bool wasDrawing = s_DrawingObject; + bool wasDrawing = s_DrawingObject; - u32 cmdSize = FifoAnalyzer::AnalyzeCommand(&frame.fifoData[cmdStart], DECODE_PLAYBACK); + u32 cmdSize = FifoAnalyzer::AnalyzeCommand(&frame.fifoData[cmdStart], DECODE_PLAYBACK); #if LOG_FIFO_CMDS - CmdData cmdData; - cmdData.offset = cmdStart; - cmdData.ptr = &frame.fifoData[cmdStart]; - cmdData.size = cmdSize; - prevCmds.push_back(cmdData); + CmdData cmdData; + cmdData.offset = cmdStart; + cmdData.ptr = &frame.fifoData[cmdStart]; + cmdData.size = cmdSize; + prevCmds.push_back(cmdData); #endif - // Check for error - if (cmdSize == 0) - { - // Clean up frame analysis - analyzed.objectStarts.clear(); - analyzed.objectEnds.clear(); + // Check for error + if (cmdSize == 0) + { + // Clean up frame analysis + analyzed.objectStarts.clear(); + analyzed.objectEnds.clear(); - return; - } + return; + } - if (wasDrawing != s_DrawingObject) - { - if (s_DrawingObject) - analyzed.objectStarts.push_back(cmdStart); - else - analyzed.objectEnds.push_back(cmdStart); - } + if (wasDrawing != s_DrawingObject) + { + if (s_DrawingObject) + analyzed.objectStarts.push_back(cmdStart); + else + analyzed.objectEnds.push_back(cmdStart); + } - cmdStart += cmdSize; - } + cmdStart += cmdSize; + } - if (analyzed.objectEnds.size() < analyzed.objectStarts.size()) - analyzed.objectEnds.push_back(cmdStart); - } + if (analyzed.objectEnds.size() < analyzed.objectStarts.size()) + analyzed.objectEnds.push_back(cmdStart); + } } diff --git a/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.h b/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.h index bd558b9d8a..b594e6f4f2 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.h +++ b/Source/Core/Core/FifoPlayer/FifoPlaybackAnalyzer.h @@ -12,12 +12,12 @@ struct AnalyzedFrameInfo { - std::vector objectStarts; - std::vector objectEnds; - std::vector memoryUpdates; + std::vector objectStarts; + std::vector objectEnds; + std::vector memoryUpdates; }; namespace FifoPlaybackAnalyzer { - void AnalyzeFrames(FifoDataFile* file, std::vector& frameInfo); +void AnalyzeFrames(FifoDataFile* file, std::vector& frameInfo); }; diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp index 2d8eada9d4..3078326b1b 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp @@ -11,7 +11,6 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" -#include "Core/Host.h" #include "Core/FifoPlayer/FifoDataFile.h" #include "Core/FifoPlayer/FifoPlayer.h" #include "Core/HW/CPU.h" @@ -20,6 +19,7 @@ #include "Core/HW/ProcessorInterface.h" #include "Core/HW/SystemTimers.h" #include "Core/HW/VideoInterface.h" +#include "Core/Host.h" #include "Core/PowerPC/PowerPC.h" #include "VideoCommon/BPMemory.h" #include "VideoCommon/CommandProcessor.h" @@ -28,524 +28,508 @@ bool IsPlayingBackFifologWithBrokenEFBCopies = false; FifoPlayer::~FifoPlayer() { - delete m_File; + delete m_File; } bool FifoPlayer::Open(const std::string& filename) { - Close(); + Close(); - m_File = FifoDataFile::Load(filename, false); + m_File = FifoDataFile::Load(filename, false); - if (m_File) - { - FifoAnalyzer::Init(); - FifoPlaybackAnalyzer::AnalyzeFrames(m_File, m_FrameInfo); + if (m_File) + { + FifoAnalyzer::Init(); + FifoPlaybackAnalyzer::AnalyzeFrames(m_File, m_FrameInfo); - m_FrameRangeEnd = m_File->GetFrameCount(); - } + m_FrameRangeEnd = m_File->GetFrameCount(); + } - if (m_FileLoadedCb) - m_FileLoadedCb(); + if (m_FileLoadedCb) + m_FileLoadedCb(); - return (m_File != nullptr); + return (m_File != nullptr); } void FifoPlayer::Close() { - delete m_File; - m_File = nullptr; + delete m_File; + m_File = nullptr; - m_FrameRangeStart = 0; - m_FrameRangeEnd = 0; + m_FrameRangeStart = 0; + m_FrameRangeEnd = 0; } class FifoPlayer::CPUCore final : public CPUCoreBase { public: - explicit CPUCore(FifoPlayer* parent) - : m_parent(parent) - { - } - CPUCore(const CPUCore&) = delete; - ~CPUCore() - { - } - CPUCore& operator=(const CPUCore&) = delete; + explicit CPUCore(FifoPlayer* parent) : m_parent(parent) {} + CPUCore(const CPUCore&) = delete; + ~CPUCore() {} + CPUCore& operator=(const CPUCore&) = delete; - void Init() override - { - IsPlayingBackFifologWithBrokenEFBCopies = m_parent->m_File->HasBrokenEFBCopies(); + void Init() override + { + IsPlayingBackFifologWithBrokenEFBCopies = m_parent->m_File->HasBrokenEFBCopies(); - m_parent->m_CurrentFrame = m_parent->m_FrameRangeStart; - m_parent->LoadMemory(); - } + m_parent->m_CurrentFrame = m_parent->m_FrameRangeStart; + m_parent->LoadMemory(); + } - void Shutdown() override - { - IsPlayingBackFifologWithBrokenEFBCopies = false; - } + void Shutdown() override { IsPlayingBackFifologWithBrokenEFBCopies = false; } + void ClearCache() override + { + // Nothing to clear. + } - void ClearCache() override - { - // Nothing to clear. - } + void SingleStep() override + { + // NOTE: AdvanceFrame() will get stuck forever in Dual Core because the FIFO + // is disabled by CPU::EnableStepping(true) so the frame never gets displayed. + PanicAlert("Cannot SingleStep the FIFO. Use Frame Advance instead."); + } - void SingleStep() override - { - // NOTE: AdvanceFrame() will get stuck forever in Dual Core because the FIFO - // is disabled by CPU::EnableStepping(true) so the frame never gets displayed. - PanicAlert("Cannot SingleStep the FIFO. Use Frame Advance instead."); - } + const char* GetName() override { return "FifoPlayer"; } + void Run() override + { + while (CPU::GetState() == CPU::CPU_RUNNING) + { + switch (m_parent->AdvanceFrame()) + { + case CPU::CPU_POWERDOWN: + CPU::Break(); + Host_Message(WM_USER_STOP); + break; - const char* GetName() override - { - return "FifoPlayer"; - } - - void Run() override - { - while (CPU::GetState() == CPU::CPU_RUNNING) - { - switch (m_parent->AdvanceFrame()) - { - case CPU::CPU_POWERDOWN: - CPU::Break(); - Host_Message(WM_USER_STOP); - break; - - case CPU::CPU_STEPPING: - CPU::Break(); - Host_UpdateMainFrame(); - break; - } - } - } + case CPU::CPU_STEPPING: + CPU::Break(); + Host_UpdateMainFrame(); + break; + } + } + } private: - FifoPlayer* m_parent; + FifoPlayer* m_parent; }; int FifoPlayer::AdvanceFrame() { - if (m_CurrentFrame >= m_FrameRangeEnd) - { - if (!m_Loop) - return CPU::CPU_POWERDOWN; - // If there are zero frames in the range then sleep instead of busy spinning - if (m_FrameRangeStart >= m_FrameRangeEnd) - return CPU::CPU_STEPPING; + if (m_CurrentFrame >= m_FrameRangeEnd) + { + if (!m_Loop) + return CPU::CPU_POWERDOWN; + // If there are zero frames in the range then sleep instead of busy spinning + if (m_FrameRangeStart >= m_FrameRangeEnd) + return CPU::CPU_STEPPING; - m_CurrentFrame = m_FrameRangeStart; - } + m_CurrentFrame = m_FrameRangeStart; + } - if (m_FrameWrittenCb) - m_FrameWrittenCb(); + if (m_FrameWrittenCb) + m_FrameWrittenCb(); - if (m_EarlyMemoryUpdates && m_CurrentFrame == m_FrameRangeStart) - WriteAllMemoryUpdates(); + if (m_EarlyMemoryUpdates && m_CurrentFrame == m_FrameRangeStart) + WriteAllMemoryUpdates(); - WriteFrame(m_File->GetFrame(m_CurrentFrame), m_FrameInfo[m_CurrentFrame]); + WriteFrame(m_File->GetFrame(m_CurrentFrame), m_FrameInfo[m_CurrentFrame]); - ++m_CurrentFrame; - return CPU::CPU_RUNNING; + ++m_CurrentFrame; + return CPU::CPU_RUNNING; } std::unique_ptr FifoPlayer::GetCPUCore() { - if (!m_File || m_File->GetFrameCount() == 0) - return nullptr; + if (!m_File || m_File->GetFrameCount() == 0) + return nullptr; - return std::make_unique(this); + return std::make_unique(this); } u32 FifoPlayer::GetFrameObjectCount() { - if (m_CurrentFrame < m_FrameInfo.size()) - { - return (u32)(m_FrameInfo[m_CurrentFrame].objectStarts.size()); - } + if (m_CurrentFrame < m_FrameInfo.size()) + { + return (u32)(m_FrameInfo[m_CurrentFrame].objectStarts.size()); + } - return 0; + return 0; } void FifoPlayer::SetFrameRangeStart(u32 start) { - if (m_File) - { - u32 frameCount = m_File->GetFrameCount(); - if (start > frameCount) - start = frameCount; + if (m_File) + { + u32 frameCount = m_File->GetFrameCount(); + if (start > frameCount) + start = frameCount; - m_FrameRangeStart = start; - if (m_FrameRangeEnd < start) - m_FrameRangeEnd = start; + m_FrameRangeStart = start; + if (m_FrameRangeEnd < start) + m_FrameRangeEnd = start; - if (m_CurrentFrame < m_FrameRangeStart) - m_CurrentFrame = m_FrameRangeStart; - } + if (m_CurrentFrame < m_FrameRangeStart) + m_CurrentFrame = m_FrameRangeStart; + } } void FifoPlayer::SetFrameRangeEnd(u32 end) { - if (m_File) - { - u32 frameCount = m_File->GetFrameCount(); - if (end > frameCount) - end = frameCount; + if (m_File) + { + u32 frameCount = m_File->GetFrameCount(); + if (end > frameCount) + end = frameCount; - m_FrameRangeEnd = end; - if (m_FrameRangeStart > end) - m_FrameRangeStart = end; + m_FrameRangeEnd = end; + if (m_FrameRangeStart > end) + m_FrameRangeStart = end; - if (m_CurrentFrame >= m_FrameRangeEnd) - m_CurrentFrame = m_FrameRangeStart; - } + if (m_CurrentFrame >= m_FrameRangeEnd) + m_CurrentFrame = m_FrameRangeStart; + } } FifoPlayer& FifoPlayer::GetInstance() { - static FifoPlayer instance; - return instance; + static FifoPlayer instance; + return instance; } -FifoPlayer::FifoPlayer() : - m_CurrentFrame(0), - m_FrameRangeStart(0), - m_FrameRangeEnd(0), - m_ObjectRangeStart(0), - m_ObjectRangeEnd(10000), - m_EarlyMemoryUpdates(false), - m_FileLoadedCb(nullptr), - m_FrameWrittenCb(nullptr), - m_File(nullptr) +FifoPlayer::FifoPlayer() + : m_CurrentFrame(0), m_FrameRangeStart(0), m_FrameRangeEnd(0), m_ObjectRangeStart(0), + m_ObjectRangeEnd(10000), m_EarlyMemoryUpdates(false), m_FileLoadedCb(nullptr), + m_FrameWrittenCb(nullptr), m_File(nullptr) { - m_Loop = SConfig::GetInstance().bLoopFifoReplay; + m_Loop = SConfig::GetInstance().bLoopFifoReplay; } void FifoPlayer::WriteFrame(const FifoFrameInfo& frame, const AnalyzedFrameInfo& info) { - // Core timing information - m_CyclesPerFrame = SystemTimers::GetTicksPerSecond() / VideoInterface::GetTargetRefreshRate(); - m_ElapsedCycles = 0; - m_FrameFifoSize = frame.fifoDataSize; + // Core timing information + m_CyclesPerFrame = SystemTimers::GetTicksPerSecond() / VideoInterface::GetTargetRefreshRate(); + m_ElapsedCycles = 0; + m_FrameFifoSize = frame.fifoDataSize; - // Determine start and end objects - u32 numObjects = (u32)(info.objectStarts.size()); - u32 drawStart = std::min(numObjects, m_ObjectRangeStart); - u32 drawEnd = std::min(numObjects - 1, m_ObjectRangeEnd); + // Determine start and end objects + u32 numObjects = (u32)(info.objectStarts.size()); + u32 drawStart = std::min(numObjects, m_ObjectRangeStart); + u32 drawEnd = std::min(numObjects - 1, m_ObjectRangeEnd); - u32 position = 0; - u32 memoryUpdate = 0; + u32 position = 0; + u32 memoryUpdate = 0; - // Skip memory updates during frame if true - if (m_EarlyMemoryUpdates) - { - memoryUpdate = (u32)(frame.memoryUpdates.size()); - } + // Skip memory updates during frame if true + if (m_EarlyMemoryUpdates) + { + memoryUpdate = (u32)(frame.memoryUpdates.size()); + } - if (numObjects > 0) - { - u32 objectNum = 0; + if (numObjects > 0) + { + u32 objectNum = 0; - // Write fifo data skipping objects before the draw range - while (objectNum < drawStart) - { - WriteFramePart(position, info.objectStarts[objectNum], memoryUpdate, frame, info); + // Write fifo data skipping objects before the draw range + while (objectNum < drawStart) + { + WriteFramePart(position, info.objectStarts[objectNum], memoryUpdate, frame, info); - position = info.objectEnds[objectNum]; - ++objectNum; - } + position = info.objectEnds[objectNum]; + ++objectNum; + } - // Write objects in draw range - if (objectNum < numObjects && drawStart <= drawEnd) - { - objectNum = drawEnd; - WriteFramePart(position, info.objectEnds[objectNum], memoryUpdate, frame, info); - position = info.objectEnds[objectNum]; - ++objectNum; - } + // Write objects in draw range + if (objectNum < numObjects && drawStart <= drawEnd) + { + objectNum = drawEnd; + WriteFramePart(position, info.objectEnds[objectNum], memoryUpdate, frame, info); + position = info.objectEnds[objectNum]; + ++objectNum; + } - // Write fifo data skipping objects after the draw range - while (objectNum < numObjects) - { - WriteFramePart(position, info.objectStarts[objectNum], memoryUpdate, frame, info); + // Write fifo data skipping objects after the draw range + while (objectNum < numObjects) + { + WriteFramePart(position, info.objectStarts[objectNum], memoryUpdate, frame, info); - position = info.objectEnds[objectNum]; - ++objectNum; - } - } + position = info.objectEnds[objectNum]; + ++objectNum; + } + } - // Write data after the last object - WriteFramePart(position, frame.fifoDataSize, memoryUpdate, frame, info); + // Write data after the last object + WriteFramePart(position, frame.fifoDataSize, memoryUpdate, frame, info); - FlushWGP(); + FlushWGP(); - // Sleep while the GPU is active - while (!IsIdleSet()) - { - CoreTiming::Idle(); - CoreTiming::Advance(); - } + // Sleep while the GPU is active + while (!IsIdleSet()) + { + CoreTiming::Idle(); + CoreTiming::Advance(); + } } -void FifoPlayer::WriteFramePart(u32 dataStart, u32 dataEnd, u32& nextMemUpdate, const FifoFrameInfo& frame, const AnalyzedFrameInfo& info) +void FifoPlayer::WriteFramePart(u32 dataStart, u32 dataEnd, u32& nextMemUpdate, + const FifoFrameInfo& frame, const AnalyzedFrameInfo& info) { - u8* data = frame.fifoData; + u8* data = frame.fifoData; - while (nextMemUpdate < frame.memoryUpdates.size() && dataStart < dataEnd) - { - const MemoryUpdate &memUpdate = info.memoryUpdates[nextMemUpdate]; + while (nextMemUpdate < frame.memoryUpdates.size() && dataStart < dataEnd) + { + const MemoryUpdate& memUpdate = info.memoryUpdates[nextMemUpdate]; - if (memUpdate.fifoPosition < dataEnd) - { - if (dataStart < memUpdate.fifoPosition) - { - WriteFifo(data, dataStart, memUpdate.fifoPosition); - dataStart = memUpdate.fifoPosition; - } + if (memUpdate.fifoPosition < dataEnd) + { + if (dataStart < memUpdate.fifoPosition) + { + WriteFifo(data, dataStart, memUpdate.fifoPosition); + dataStart = memUpdate.fifoPosition; + } - WriteMemory(memUpdate); + WriteMemory(memUpdate); - ++nextMemUpdate; - } - else - { - WriteFifo(data, dataStart, dataEnd); - dataStart = dataEnd; - } - } + ++nextMemUpdate; + } + else + { + WriteFifo(data, dataStart, dataEnd); + dataStart = dataEnd; + } + } - if (dataStart < dataEnd) - WriteFifo(data, dataStart, dataEnd); + if (dataStart < dataEnd) + WriteFifo(data, dataStart, dataEnd); } void FifoPlayer::WriteAllMemoryUpdates() { - _assert_(m_File); + _assert_(m_File); - for (u32 frameNum = 0; frameNum < m_File->GetFrameCount(); ++frameNum) - { - const FifoFrameInfo &frame = m_File->GetFrame(frameNum); - for (auto& update : frame.memoryUpdates) - { - WriteMemory(update); - } - } + for (u32 frameNum = 0; frameNum < m_File->GetFrameCount(); ++frameNum) + { + const FifoFrameInfo& frame = m_File->GetFrame(frameNum); + for (auto& update : frame.memoryUpdates) + { + WriteMemory(update); + } + } } void FifoPlayer::WriteMemory(const MemoryUpdate& memUpdate) { - u8 *mem = nullptr; + u8* mem = nullptr; - if (memUpdate.address & 0x10000000) - mem = &Memory::m_pEXRAM[memUpdate.address & Memory::EXRAM_MASK]; - else - mem = &Memory::m_pRAM[memUpdate.address & Memory::RAM_MASK]; + if (memUpdate.address & 0x10000000) + mem = &Memory::m_pEXRAM[memUpdate.address & Memory::EXRAM_MASK]; + else + mem = &Memory::m_pRAM[memUpdate.address & Memory::RAM_MASK]; - memcpy(mem, memUpdate.data, memUpdate.size); + memcpy(mem, memUpdate.data, memUpdate.size); } void FifoPlayer::WriteFifo(u8* data, u32 start, u32 end) { - u32 written = start; - u32 lastBurstEnd = end - 1; + u32 written = start; + u32 lastBurstEnd = end - 1; - // Write up to 256 bytes at a time - while (written < end) - { - while (IsHighWatermarkSet()) - { - CoreTiming::Idle(); - CoreTiming::Advance(); - } + // Write up to 256 bytes at a time + while (written < end) + { + while (IsHighWatermarkSet()) + { + CoreTiming::Idle(); + CoreTiming::Advance(); + } - u32 burstEnd = std::min(written + 255, lastBurstEnd); + u32 burstEnd = std::min(written + 255, lastBurstEnd); - while (written < burstEnd) - GPFifo::FastWrite8(data[written++]); + while (written < burstEnd) + GPFifo::FastWrite8(data[written++]); - GPFifo::Write8(data[written++]); + GPFifo::Write8(data[written++]); - // Advance core timing - u32 elapsedCycles = u32(((u64)written * m_CyclesPerFrame) / m_FrameFifoSize); - u32 cyclesUsed = elapsedCycles - m_ElapsedCycles; - m_ElapsedCycles = elapsedCycles; + // Advance core timing + u32 elapsedCycles = u32(((u64)written * m_CyclesPerFrame) / m_FrameFifoSize); + u32 cyclesUsed = elapsedCycles - m_ElapsedCycles; + m_ElapsedCycles = elapsedCycles; - PowerPC::ppcState.downcount -= cyclesUsed; - CoreTiming::Advance(); - } + PowerPC::ppcState.downcount -= cyclesUsed; + CoreTiming::Advance(); + } } void FifoPlayer::SetupFifo() { - WriteCP(CommandProcessor::CTRL_REGISTER, 0); // disable read, BP, interrupts - WriteCP(CommandProcessor::CLEAR_REGISTER, 7); // clear overflow, underflow, metrics + WriteCP(CommandProcessor::CTRL_REGISTER, 0); // disable read, BP, interrupts + WriteCP(CommandProcessor::CLEAR_REGISTER, 7); // clear overflow, underflow, metrics - const FifoFrameInfo& frame = m_File->GetFrame(m_CurrentFrame); + const FifoFrameInfo& frame = m_File->GetFrame(m_CurrentFrame); - // Set fifo bounds - WriteCP(CommandProcessor::FIFO_BASE_LO, frame.fifoStart); - WriteCP(CommandProcessor::FIFO_BASE_HI, frame.fifoStart >> 16); - WriteCP(CommandProcessor::FIFO_END_LO, frame.fifoEnd); - WriteCP(CommandProcessor::FIFO_END_HI, frame.fifoEnd >> 16); + // Set fifo bounds + WriteCP(CommandProcessor::FIFO_BASE_LO, frame.fifoStart); + WriteCP(CommandProcessor::FIFO_BASE_HI, frame.fifoStart >> 16); + WriteCP(CommandProcessor::FIFO_END_LO, frame.fifoEnd); + WriteCP(CommandProcessor::FIFO_END_HI, frame.fifoEnd >> 16); - // Set watermarks, high at 75%, low at 0% - u32 hi_watermark = (frame.fifoEnd - frame.fifoStart) * 3 / 4; - WriteCP(CommandProcessor::FIFO_HI_WATERMARK_LO, hi_watermark); - WriteCP(CommandProcessor::FIFO_HI_WATERMARK_HI, hi_watermark >> 16); - WriteCP(CommandProcessor::FIFO_LO_WATERMARK_LO, 0); - WriteCP(CommandProcessor::FIFO_LO_WATERMARK_HI, 0); + // Set watermarks, high at 75%, low at 0% + u32 hi_watermark = (frame.fifoEnd - frame.fifoStart) * 3 / 4; + WriteCP(CommandProcessor::FIFO_HI_WATERMARK_LO, hi_watermark); + WriteCP(CommandProcessor::FIFO_HI_WATERMARK_HI, hi_watermark >> 16); + WriteCP(CommandProcessor::FIFO_LO_WATERMARK_LO, 0); + WriteCP(CommandProcessor::FIFO_LO_WATERMARK_HI, 0); - // Set R/W pointers to fifo start - WriteCP(CommandProcessor::FIFO_RW_DISTANCE_LO, 0); - WriteCP(CommandProcessor::FIFO_RW_DISTANCE_HI, 0); - WriteCP(CommandProcessor::FIFO_WRITE_POINTER_LO, frame.fifoStart); - WriteCP(CommandProcessor::FIFO_WRITE_POINTER_HI, frame.fifoStart >> 16); - WriteCP(CommandProcessor::FIFO_READ_POINTER_LO, frame.fifoStart); - WriteCP(CommandProcessor::FIFO_READ_POINTER_HI, frame.fifoStart >> 16); + // Set R/W pointers to fifo start + WriteCP(CommandProcessor::FIFO_RW_DISTANCE_LO, 0); + WriteCP(CommandProcessor::FIFO_RW_DISTANCE_HI, 0); + WriteCP(CommandProcessor::FIFO_WRITE_POINTER_LO, frame.fifoStart); + WriteCP(CommandProcessor::FIFO_WRITE_POINTER_HI, frame.fifoStart >> 16); + WriteCP(CommandProcessor::FIFO_READ_POINTER_LO, frame.fifoStart); + WriteCP(CommandProcessor::FIFO_READ_POINTER_HI, frame.fifoStart >> 16); - // Set fifo bounds - WritePI(ProcessorInterface::PI_FIFO_BASE, frame.fifoStart); - WritePI(ProcessorInterface::PI_FIFO_END, frame.fifoEnd); + // Set fifo bounds + WritePI(ProcessorInterface::PI_FIFO_BASE, frame.fifoStart); + WritePI(ProcessorInterface::PI_FIFO_END, frame.fifoEnd); - // Set write pointer - WritePI(ProcessorInterface::PI_FIFO_WPTR, frame.fifoStart); - FlushWGP(); - WritePI(ProcessorInterface::PI_FIFO_WPTR, frame.fifoStart); + // Set write pointer + WritePI(ProcessorInterface::PI_FIFO_WPTR, frame.fifoStart); + FlushWGP(); + WritePI(ProcessorInterface::PI_FIFO_WPTR, frame.fifoStart); - WriteCP(CommandProcessor::CTRL_REGISTER, 17); // enable read & GP link + WriteCP(CommandProcessor::CTRL_REGISTER, 17); // enable read & GP link } void FifoPlayer::LoadMemory() { - UReg_MSR newMSR; - newMSR.DR = 1; - newMSR.IR = 1; - MSR = newMSR.Hex; - PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff; - PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; - PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; - PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; - PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; - PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; + UReg_MSR newMSR; + newMSR.DR = 1; + newMSR.IR = 1; + MSR = newMSR.Hex; + PowerPC::ppcState.spr[SPR_IBAT0U] = 0x80001fff; + PowerPC::ppcState.spr[SPR_IBAT0L] = 0x00000002; + PowerPC::ppcState.spr[SPR_DBAT0U] = 0x80001fff; + PowerPC::ppcState.spr[SPR_DBAT0L] = 0x00000002; + PowerPC::ppcState.spr[SPR_DBAT1U] = 0xc0001fff; + PowerPC::ppcState.spr[SPR_DBAT1L] = 0x0000002a; - SetupFifo(); + SetupFifo(); - u32 *regs = m_File->GetBPMem(); - for (int i = 0; i < FifoDataFile::BP_MEM_SIZE; ++i) - { - if (ShouldLoadBP(i)) - LoadBPReg(i, regs[i]); - } + u32* regs = m_File->GetBPMem(); + for (int i = 0; i < FifoDataFile::BP_MEM_SIZE; ++i) + { + if (ShouldLoadBP(i)) + LoadBPReg(i, regs[i]); + } - regs = m_File->GetCPMem(); - LoadCPReg(0x30, regs[0x30]); - LoadCPReg(0x40, regs[0x40]); - LoadCPReg(0x50, regs[0x50]); - LoadCPReg(0x60, regs[0x60]); + regs = m_File->GetCPMem(); + LoadCPReg(0x30, regs[0x30]); + LoadCPReg(0x40, regs[0x40]); + LoadCPReg(0x50, regs[0x50]); + LoadCPReg(0x60, regs[0x60]); - for (int i = 0; i < 8; ++i) - { - LoadCPReg(0x70 + i, regs[0x70 + i]); - LoadCPReg(0x80 + i, regs[0x80 + i]); - LoadCPReg(0x90 + i, regs[0x90 + i]); - } + for (int i = 0; i < 8; ++i) + { + LoadCPReg(0x70 + i, regs[0x70 + i]); + LoadCPReg(0x80 + i, regs[0x80 + i]); + LoadCPReg(0x90 + i, regs[0x90 + i]); + } - for (int i = 0; i < 16; ++i) - { - LoadCPReg(0xa0 + i, regs[0xa0 + i]); - LoadCPReg(0xb0 + i, regs[0xb0 + i]); - } + for (int i = 0; i < 16; ++i) + { + LoadCPReg(0xa0 + i, regs[0xa0 + i]); + LoadCPReg(0xb0 + i, regs[0xb0 + i]); + } - regs = m_File->GetXFMem(); - for (int i = 0; i < FifoDataFile::XF_MEM_SIZE; i += 16) - LoadXFMem16(i, ®s[i]); + regs = m_File->GetXFMem(); + for (int i = 0; i < FifoDataFile::XF_MEM_SIZE; i += 16) + LoadXFMem16(i, ®s[i]); - regs = m_File->GetXFRegs(); - for (int i = 0; i < FifoDataFile::XF_REGS_SIZE; ++i) - LoadXFReg(i, regs[i]); + regs = m_File->GetXFRegs(); + for (int i = 0; i < FifoDataFile::XF_REGS_SIZE; ++i) + LoadXFReg(i, regs[i]); - FlushWGP(); + FlushWGP(); } void FifoPlayer::WriteCP(u32 address, u16 value) { - PowerPC::Write_U16(value, 0xCC000000 | address); + PowerPC::Write_U16(value, 0xCC000000 | address); } void FifoPlayer::WritePI(u32 address, u32 value) { - PowerPC::Write_U32(value, 0xCC003000 | address); + PowerPC::Write_U32(value, 0xCC003000 | address); } void FifoPlayer::FlushWGP() { - // Send 31 0s through the WGP - for (int i = 0; i < 7; ++i) - GPFifo::Write32(0); - GPFifo::Write16(0); - GPFifo::Write8(0); + // Send 31 0s through the WGP + for (int i = 0; i < 7; ++i) + GPFifo::Write32(0); + GPFifo::Write16(0); + GPFifo::Write8(0); - GPFifo::ResetGatherPipe(); + GPFifo::ResetGatherPipe(); } void FifoPlayer::LoadBPReg(u8 reg, u32 value) { - GPFifo::Write8(0x61); // load BP reg + GPFifo::Write8(0x61); // load BP reg - u32 cmd = (reg << 24) & 0xff000000; - cmd |= (value & 0x00ffffff); - GPFifo::Write32(cmd); + u32 cmd = (reg << 24) & 0xff000000; + cmd |= (value & 0x00ffffff); + GPFifo::Write32(cmd); } void FifoPlayer::LoadCPReg(u8 reg, u32 value) { - GPFifo::Write8(0x08); // load CP reg - GPFifo::Write8(reg); - GPFifo::Write32(value); + GPFifo::Write8(0x08); // load CP reg + GPFifo::Write8(reg); + GPFifo::Write32(value); } void FifoPlayer::LoadXFReg(u16 reg, u32 value) { - GPFifo::Write8(0x10); // load XF reg - GPFifo::Write32((reg & 0x0fff) | 0x1000); // load 4 bytes into reg - GPFifo::Write32(value); + GPFifo::Write8(0x10); // load XF reg + GPFifo::Write32((reg & 0x0fff) | 0x1000); // load 4 bytes into reg + GPFifo::Write32(value); } void FifoPlayer::LoadXFMem16(u16 address, u32* data) { - // Loads 16 * 4 bytes in xf memory starting at address - GPFifo::Write8(0x10); // load XF reg - GPFifo::Write32(0x000f0000 | (address & 0xffff)); // load 16 * 4 bytes into address - for (int i = 0; i < 16; ++i) - GPFifo::Write32(data[i]); + // Loads 16 * 4 bytes in xf memory starting at address + GPFifo::Write8(0x10); // load XF reg + GPFifo::Write32(0x000f0000 | (address & 0xffff)); // load 16 * 4 bytes into address + for (int i = 0; i < 16; ++i) + GPFifo::Write32(data[i]); } bool FifoPlayer::ShouldLoadBP(u8 address) { - switch (address) - { - case BPMEM_SETDRAWDONE: - case BPMEM_PE_TOKEN_ID: - case BPMEM_PE_TOKEN_INT_ID: - case BPMEM_TRIGGER_EFB_COPY: - case BPMEM_LOADTLUT1: - case BPMEM_PERF1: - return false; - default: - return true; - } + switch (address) + { + case BPMEM_SETDRAWDONE: + case BPMEM_PE_TOKEN_ID: + case BPMEM_PE_TOKEN_INT_ID: + case BPMEM_TRIGGER_EFB_COPY: + case BPMEM_LOADTLUT1: + case BPMEM_PERF1: + return false; + default: + return true; + } } bool FifoPlayer::IsIdleSet() { - CommandProcessor::UCPStatusReg status = PowerPC::Read_U16(0xCC000000 | CommandProcessor::STATUS_REGISTER); - return status.CommandIdle; + CommandProcessor::UCPStatusReg status = + PowerPC::Read_U16(0xCC000000 | CommandProcessor::STATUS_REGISTER); + return status.CommandIdle; } bool FifoPlayer::IsHighWatermarkSet() { - CommandProcessor::UCPStatusReg status = PowerPC::Read_U16(0xCC000000 | CommandProcessor::STATUS_REGISTER); - return status.OverflowHiWatermark; + CommandProcessor::UCPStatusReg status = + PowerPC::Read_U16(0xCC000000 | CommandProcessor::STATUS_REGISTER); + return status.OverflowHiWatermark; } diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.h b/Source/Core/Core/FifoPlayer/FifoPlayer.h index 78f40ac777..46d1f69b7c 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.h +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.h @@ -22,22 +22,27 @@ struct AnalyzedFrameInfo; // baked into the fifo log. If you recorded with efb2ram on, the result of efb2ram would be baked // into the fifo. If you recorded with efb2tex or efb off, random data would be included in the fifo // log. -// Later the behaviour of efb2tex was changed to zero the underlying memory and check the hash of that. +// Later the behaviour of efb2tex was changed to zero the underlying memory and check the hash of +// that. // But this broke a whole lot of fifologs due to the following sequence of events: // 1. fifoplayer would trigger the efb copy // 2. Texture cache would zero the memory backing the texture and hash it. // 3. Time passes. // 4. fifoplayer would encounter the drawcall using the efb copy -// 5. fifoplayer would overwrite the memory backing the efb copy back to it's state when recording. +// 5. fifoplayer would overwrite the memory backing the efb copy back to it's state when +// recording. // 6. Texture cache would hash the memory and see that the hash no-longer matches // 7. Texture cache would load whatever data was now in memory as a texture either a baked in // efb2ram copy from recording time or just random data. // 8. The output of fifoplayer would be wrong. -// To keep compatibility with old fifologs, we have this flag which signals texture cache to not bother +// To keep compatibility with old fifologs, we have this flag which signals texture cache to not +// bother // hashing the memory and just assume the hash matched. -// At a later point proper efb copy support should be added to fiforecorder and this flag will change -// based on the version of the .dff file, but until then it will always be true when a fifolog is playing. +// At a later point proper efb copy support should be added to fiforecorder and this flag will +// change +// based on the version of the .dff file, but until then it will always be true when a fifolog is +// playing. // Shitty global to fix a shitty problem extern bool IsPlayingBackFifologWithBrokenEFBCopies; @@ -45,106 +50,100 @@ extern bool IsPlayingBackFifologWithBrokenEFBCopies; class FifoPlayer { public: - typedef void(*CallbackFunc)(void); + typedef void (*CallbackFunc)(void); - ~FifoPlayer(); + ~FifoPlayer(); - bool Open(const std::string& filename); - void Close(); + bool Open(const std::string& filename); + void Close(); - // Returns a CPUCoreBase instance that can be injected into PowerPC as a - // pseudo-CPU. The instance is only valid while the FifoPlayer is Open(). - // Returns nullptr if the FifoPlayer is not initialized correctly. - // Play/Pause/Stop of the FifoLog can be controlled normally via the - // PowerPC state. - std::unique_ptr GetCPUCore(); + // Returns a CPUCoreBase instance that can be injected into PowerPC as a + // pseudo-CPU. The instance is only valid while the FifoPlayer is Open(). + // Returns nullptr if the FifoPlayer is not initialized correctly. + // Play/Pause/Stop of the FifoLog can be controlled normally via the + // PowerPC state. + std::unique_ptr GetCPUCore(); - FifoDataFile *GetFile() { return m_File; } + FifoDataFile* GetFile() { return m_File; } + u32 GetFrameObjectCount(); + u32 GetCurrentFrameNum() const { return m_CurrentFrame; } + const AnalyzedFrameInfo& GetAnalyzedFrameInfo(u32 frame) const { return m_FrameInfo[frame]; } + // Frame range + u32 GetFrameRangeStart() const { return m_FrameRangeStart; } + void SetFrameRangeStart(u32 start); - u32 GetFrameObjectCount(); - u32 GetCurrentFrameNum() const { return m_CurrentFrame; } + u32 GetFrameRangeEnd() const { return m_FrameRangeEnd; } + void SetFrameRangeEnd(u32 end); - const AnalyzedFrameInfo& GetAnalyzedFrameInfo(u32 frame) const { return m_FrameInfo[frame]; } - - // Frame range - u32 GetFrameRangeStart() const { return m_FrameRangeStart; } - void SetFrameRangeStart(u32 start); - - u32 GetFrameRangeEnd() const { return m_FrameRangeEnd; } - void SetFrameRangeEnd(u32 end); - - // Object range - u32 GetObjectRangeStart() const { return m_ObjectRangeStart; } - void SetObjectRangeStart(u32 start) { m_ObjectRangeStart = start; } - - u32 GetObjectRangeEnd() const { return m_ObjectRangeEnd; } - void SetObjectRangeEnd(u32 end) { m_ObjectRangeEnd = end; } - - // If enabled then all memory updates happen at once before the first frame - // Default is disabled - void SetEarlyMemoryUpdates(bool enabled) { m_EarlyMemoryUpdates = enabled; } - - // Callbacks - void SetFileLoadedCallback(CallbackFunc callback) { m_FileLoadedCb = callback; } - void SetFrameWrittenCallback(CallbackFunc callback) { m_FrameWrittenCb = callback; } - - static FifoPlayer &GetInstance(); + // Object range + u32 GetObjectRangeStart() const { return m_ObjectRangeStart; } + void SetObjectRangeStart(u32 start) { m_ObjectRangeStart = start; } + u32 GetObjectRangeEnd() const { return m_ObjectRangeEnd; } + void SetObjectRangeEnd(u32 end) { m_ObjectRangeEnd = end; } + // If enabled then all memory updates happen at once before the first frame + // Default is disabled + void SetEarlyMemoryUpdates(bool enabled) { m_EarlyMemoryUpdates = enabled; } + // Callbacks + void SetFileLoadedCallback(CallbackFunc callback) { m_FileLoadedCb = callback; } + void SetFrameWrittenCallback(CallbackFunc callback) { m_FrameWrittenCb = callback; } + static FifoPlayer& GetInstance(); private: - class CPUCore; + class CPUCore; - FifoPlayer(); + FifoPlayer(); - int AdvanceFrame(); + int AdvanceFrame(); - void WriteFrame(const FifoFrameInfo& frame, const AnalyzedFrameInfo &info); - void WriteFramePart(u32 dataStart, u32 dataEnd, u32 &nextMemUpdate, const FifoFrameInfo& frame, const AnalyzedFrameInfo& info); + void WriteFrame(const FifoFrameInfo& frame, const AnalyzedFrameInfo& info); + void WriteFramePart(u32 dataStart, u32 dataEnd, u32& nextMemUpdate, const FifoFrameInfo& frame, + const AnalyzedFrameInfo& info); - void WriteAllMemoryUpdates(); - void WriteMemory(const MemoryUpdate &memUpdate); + void WriteAllMemoryUpdates(); + void WriteMemory(const MemoryUpdate& memUpdate); - // writes a range of data to the fifo - // start and end must be relative to frame's fifo data so elapsed cycles are figured correctly - void WriteFifo(u8* data, u32 start, u32 end); + // writes a range of data to the fifo + // start and end must be relative to frame's fifo data so elapsed cycles are figured correctly + void WriteFifo(u8* data, u32 start, u32 end); - void SetupFifo(); + void SetupFifo(); - void LoadMemory(); + void LoadMemory(); - void WriteCP(u32 address, u16 value); - void WritePI(u32 address, u32 value); + void WriteCP(u32 address, u16 value); + void WritePI(u32 address, u32 value); - void FlushWGP(); + void FlushWGP(); - void LoadBPReg(u8 reg, u32 value); - void LoadCPReg(u8 reg, u32 value); - void LoadXFReg(u16 reg, u32 value); - void LoadXFMem16(u16 address, u32 *data); + void LoadBPReg(u8 reg, u32 value); + void LoadCPReg(u8 reg, u32 value); + void LoadXFReg(u16 reg, u32 value); + void LoadXFMem16(u16 address, u32* data); - bool ShouldLoadBP(u8 address); + bool ShouldLoadBP(u8 address); - static bool IsIdleSet(); - static bool IsHighWatermarkSet(); + static bool IsIdleSet(); + static bool IsHighWatermarkSet(); - bool m_Loop; + bool m_Loop; - u32 m_CurrentFrame; - u32 m_FrameRangeStart; - u32 m_FrameRangeEnd; + u32 m_CurrentFrame; + u32 m_FrameRangeStart; + u32 m_FrameRangeEnd; - u32 m_ObjectRangeStart; - u32 m_ObjectRangeEnd; + u32 m_ObjectRangeStart; + u32 m_ObjectRangeEnd; - bool m_EarlyMemoryUpdates; + bool m_EarlyMemoryUpdates; - u64 m_CyclesPerFrame; - u32 m_ElapsedCycles; - u32 m_FrameFifoSize; + u64 m_CyclesPerFrame; + u32 m_ElapsedCycles; + u32 m_FrameFifoSize; - CallbackFunc m_FileLoadedCb; - CallbackFunc m_FrameWrittenCb; + CallbackFunc m_FileLoadedCb; + CallbackFunc m_FrameWrittenCb; - FifoDataFile* m_File; + FifoDataFile* m_File; - std::vector m_FrameInfo; + std::vector m_FrameInfo; }; diff --git a/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp b/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp index e21556e088..e0e13d4419 100644 --- a/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.cpp @@ -17,70 +17,71 @@ using namespace FifoAnalyzer; void FifoRecordAnalyzer::Initialize(u32* cpMem) { - s_DrawingObject = false; + s_DrawingObject = false; - FifoAnalyzer::LoadCPReg(0x50, *(cpMem + 0x50), s_CpMem); - FifoAnalyzer::LoadCPReg(0x60, *(cpMem + 0x60), s_CpMem); - for (int i = 0; i < 8; ++i) - FifoAnalyzer::LoadCPReg(0x70 + i, *(cpMem + 0x70 + i), s_CpMem); + FifoAnalyzer::LoadCPReg(0x50, *(cpMem + 0x50), s_CpMem); + FifoAnalyzer::LoadCPReg(0x60, *(cpMem + 0x60), s_CpMem); + for (int i = 0; i < 8; ++i) + FifoAnalyzer::LoadCPReg(0x70 + i, *(cpMem + 0x70 + i), s_CpMem); - memcpy(s_CpMem.arrayBases, cpMem + 0xA0, 16 * 4); - memcpy(s_CpMem.arrayStrides, cpMem + 0xB0, 16 * 4); + memcpy(s_CpMem.arrayBases, cpMem + 0xA0, 16 * 4); + memcpy(s_CpMem.arrayStrides, cpMem + 0xB0, 16 * 4); } void FifoRecordAnalyzer::ProcessLoadIndexedXf(u32 val, int array) { - int index = val >> 16; - int size = ((val >> 12) & 0xF) + 1; + int index = val >> 16; + int size = ((val >> 12) & 0xF) + 1; - u32 address = s_CpMem.arrayBases[array] + s_CpMem.arrayStrides[array] * index; + u32 address = s_CpMem.arrayBases[array] + s_CpMem.arrayStrides[array] * index; - FifoRecorder::GetInstance().UseMemory(address, size * 4, MemoryUpdate::XF_DATA); + FifoRecorder::GetInstance().UseMemory(address, size * 4, MemoryUpdate::XF_DATA); } -void FifoRecordAnalyzer::WriteVertexArray(int arrayIndex, u8* vertexData, int vertexSize, int numVertices) +void FifoRecordAnalyzer::WriteVertexArray(int arrayIndex, u8* vertexData, int vertexSize, + int numVertices) { - // Skip if not indexed array - int arrayType = (s_CpMem.vtxDesc.Hex >> (9 + (arrayIndex * 2))) & 3; - if (arrayType < 2) - return; + // Skip if not indexed array + int arrayType = (s_CpMem.vtxDesc.Hex >> (9 + (arrayIndex * 2))) & 3; + if (arrayType < 2) + return; - int maxIndex = 0; + int maxIndex = 0; - // Determine min and max indices - if (arrayType == INDEX8) - { - for (int i = 0; i < numVertices; ++i) - { - int index = *vertexData; - vertexData += vertexSize; + // Determine min and max indices + if (arrayType == INDEX8) + { + for (int i = 0; i < numVertices; ++i) + { + int index = *vertexData; + vertexData += vertexSize; - // 0xff skips the vertex - if (index != 0xff) - { - if (index > maxIndex) - maxIndex = index; - } - } - } - else - { - for (int i = 0; i < numVertices; ++i) - { - int index = Common::swap16(vertexData); - vertexData += vertexSize; + // 0xff skips the vertex + if (index != 0xff) + { + if (index > maxIndex) + maxIndex = index; + } + } + } + else + { + for (int i = 0; i < numVertices; ++i) + { + int index = Common::swap16(vertexData); + vertexData += vertexSize; - // 0xffff skips the vertex - if (index != 0xffff) - { - if (index > maxIndex) - maxIndex = index; - } - } - } + // 0xffff skips the vertex + if (index != 0xffff) + { + if (index > maxIndex) + maxIndex = index; + } + } + } - u32 arrayStart = s_CpMem.arrayBases[arrayIndex]; - u32 arraySize = s_CpMem.arrayStrides[arrayIndex] * (maxIndex + 1); + u32 arrayStart = s_CpMem.arrayBases[arrayIndex]; + u32 arraySize = s_CpMem.arrayStrides[arrayIndex] * (maxIndex + 1); - FifoRecorder::GetInstance().UseMemory(arrayStart, arraySize, MemoryUpdate::VERTEX_STREAM); + FifoRecorder::GetInstance().UseMemory(arrayStart, arraySize, MemoryUpdate::VERTEX_STREAM); } diff --git a/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.h b/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.h index 7bf9052a4f..b0ca59ce97 100644 --- a/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.h +++ b/Source/Core/Core/FifoPlayer/FifoRecordAnalyzer.h @@ -12,9 +12,9 @@ namespace FifoRecordAnalyzer { - // Must call this before analyzing Fifo commands with FifoAnalyzer::AnalyzeCommand() - void Initialize(u32* cpMem); +// Must call this before analyzing Fifo commands with FifoAnalyzer::AnalyzeCommand() +void Initialize(u32* cpMem); - void ProcessLoadIndexedXf(u32 val, int array); - void WriteVertexArray(int arrayIndex, u8* vertexData, int vertexSize, int numVertices); +void ProcessLoadIndexedXf(u32 val, int array); +void WriteVertexArray(int arrayIndex, u8* vertexData, int vertexSize, int numVertices); }; diff --git a/Source/Core/Core/FifoPlayer/FifoRecorder.cpp b/Source/Core/Core/FifoPlayer/FifoRecorder.cpp index 7c6ba461af..54831d094f 100644 --- a/Source/Core/Core/FifoPlayer/FifoRecorder.cpp +++ b/Source/Core/Core/FifoPlayer/FifoRecorder.cpp @@ -14,206 +14,200 @@ static FifoRecorder instance; static std::recursive_mutex sMutex; -FifoRecorder::FifoRecorder() : - m_IsRecording(false), - m_WasRecording(false), - m_RequestedRecordingEnd(false), - m_RecordFramesRemaining(0), - m_FinishedCb(nullptr), - m_File(nullptr), - m_SkipNextData(true), - m_SkipFutureData(true), - m_FrameEnded(false), - m_Ram(Memory::RAM_SIZE), - m_ExRam(Memory::EXRAM_SIZE) +FifoRecorder::FifoRecorder() + : m_IsRecording(false), m_WasRecording(false), m_RequestedRecordingEnd(false), + m_RecordFramesRemaining(0), m_FinishedCb(nullptr), m_File(nullptr), m_SkipNextData(true), + m_SkipFutureData(true), m_FrameEnded(false), m_Ram(Memory::RAM_SIZE), + m_ExRam(Memory::EXRAM_SIZE) { } FifoRecorder::~FifoRecorder() { - m_IsRecording = false; + m_IsRecording = false; } void FifoRecorder::StartRecording(s32 numFrames, CallbackFunc finishedCb) { - sMutex.lock(); + sMutex.lock(); - delete m_File; + delete m_File; - FifoAnalyzer::Init(); + FifoAnalyzer::Init(); - m_File = new FifoDataFile; - std::fill(m_Ram.begin(), m_Ram.end(), 0); - std::fill(m_ExRam.begin(), m_ExRam.end(), 0); + m_File = new FifoDataFile; + std::fill(m_Ram.begin(), m_Ram.end(), 0); + std::fill(m_ExRam.begin(), m_ExRam.end(), 0); - m_File->SetIsWii(SConfig::GetInstance().bWii); + m_File->SetIsWii(SConfig::GetInstance().bWii); - if (!m_IsRecording) - { - m_WasRecording = false; - m_IsRecording = true; - m_RecordFramesRemaining = numFrames; - } + if (!m_IsRecording) + { + m_WasRecording = false; + m_IsRecording = true; + m_RecordFramesRemaining = numFrames; + } - m_RequestedRecordingEnd = false; - m_FinishedCb = finishedCb; + m_RequestedRecordingEnd = false; + m_FinishedCb = finishedCb; - sMutex.unlock(); + sMutex.unlock(); } void FifoRecorder::StopRecording() { - m_RequestedRecordingEnd = true; + m_RequestedRecordingEnd = true; } void FifoRecorder::WriteGPCommand(u8* data, u32 size) { - if (!m_SkipNextData) - { - // Assumes data contains all information for the command - // Calls FifoRecorder::UseMemory - u32 analyzed_size = FifoAnalyzer::AnalyzeCommand(data, FifoAnalyzer::DECODE_RECORD); + if (!m_SkipNextData) + { + // Assumes data contains all information for the command + // Calls FifoRecorder::UseMemory + u32 analyzed_size = FifoAnalyzer::AnalyzeCommand(data, FifoAnalyzer::DECODE_RECORD); - // Make sure FifoPlayer's command analyzer agrees about the size of the command. - if (analyzed_size != size) - PanicAlert("FifoRecorder: Expected command to be %i bytes long, we were given %i bytes", analyzed_size, size); + // Make sure FifoPlayer's command analyzer agrees about the size of the command. + if (analyzed_size != size) + PanicAlert("FifoRecorder: Expected command to be %i bytes long, we were given %i bytes", + analyzed_size, size); - // Copy data to buffer - size_t currentSize = m_FifoData.size(); - m_FifoData.resize(currentSize + size); - memcpy(&m_FifoData[currentSize], data, size); - } + // Copy data to buffer + size_t currentSize = m_FifoData.size(); + m_FifoData.resize(currentSize + size); + memcpy(&m_FifoData[currentSize], data, size); + } - if (m_FrameEnded && m_FifoData.size() > 0) - { - size_t dataSize = m_FifoData.size(); - m_CurrentFrame.fifoDataSize = (u32)dataSize; - m_CurrentFrame.fifoData = new u8[dataSize]; - memcpy(m_CurrentFrame.fifoData, m_FifoData.data(), dataSize); + if (m_FrameEnded && m_FifoData.size() > 0) + { + size_t dataSize = m_FifoData.size(); + m_CurrentFrame.fifoDataSize = (u32)dataSize; + m_CurrentFrame.fifoData = new u8[dataSize]; + memcpy(m_CurrentFrame.fifoData, m_FifoData.data(), dataSize); - sMutex.lock(); + sMutex.lock(); - // Copy frame to file - // The file will be responsible for freeing the memory allocated for each frame's fifoData - m_File->AddFrame(m_CurrentFrame); + // Copy frame to file + // The file will be responsible for freeing the memory allocated for each frame's fifoData + m_File->AddFrame(m_CurrentFrame); - if (m_FinishedCb && m_RequestedRecordingEnd) - m_FinishedCb(); + if (m_FinishedCb && m_RequestedRecordingEnd) + m_FinishedCb(); - sMutex.unlock(); + sMutex.unlock(); - m_CurrentFrame.memoryUpdates.clear(); - m_FifoData.clear(); - m_FrameEnded = false; - } + m_CurrentFrame.memoryUpdates.clear(); + m_FifoData.clear(); + m_FrameEnded = false; + } - m_SkipNextData = m_SkipFutureData; + m_SkipNextData = m_SkipFutureData; } void FifoRecorder::UseMemory(u32 address, u32 size, MemoryUpdate::Type type, bool dynamicUpdate) { - u8* curData; - u8* newData; - if (address & 0x10000000) - { - curData = &m_ExRam[address & Memory::EXRAM_MASK]; - newData = &Memory::m_pEXRAM[address & Memory::EXRAM_MASK]; - } - else - { - curData = &m_Ram[address & Memory::RAM_MASK]; - newData = &Memory::m_pRAM[address & Memory::RAM_MASK]; - } + u8* curData; + u8* newData; + if (address & 0x10000000) + { + curData = &m_ExRam[address & Memory::EXRAM_MASK]; + newData = &Memory::m_pEXRAM[address & Memory::EXRAM_MASK]; + } + else + { + curData = &m_Ram[address & Memory::RAM_MASK]; + newData = &Memory::m_pRAM[address & Memory::RAM_MASK]; + } - if (!dynamicUpdate && memcmp(curData, newData, size) != 0) - { - // Update current memory - memcpy(curData, newData, size); + if (!dynamicUpdate && memcmp(curData, newData, size) != 0) + { + // Update current memory + memcpy(curData, newData, size); - // Record memory update - MemoryUpdate memUpdate; - memUpdate.address = address; - memUpdate.fifoPosition = (u32)(m_FifoData.size()); - memUpdate.size = size; - memUpdate.type = type; - memUpdate.data = new u8[size]; - memcpy(memUpdate.data, newData, size); + // Record memory update + MemoryUpdate memUpdate; + memUpdate.address = address; + memUpdate.fifoPosition = (u32)(m_FifoData.size()); + memUpdate.size = size; + memUpdate.type = type; + memUpdate.data = new u8[size]; + memcpy(memUpdate.data, newData, size); - m_CurrentFrame.memoryUpdates.push_back(memUpdate); - } - else if (dynamicUpdate) - { - // Shadow the data so it won't be recorded as changed by a future UseMemory - memcpy(curData, newData, size); - } + m_CurrentFrame.memoryUpdates.push_back(memUpdate); + } + else if (dynamicUpdate) + { + // Shadow the data so it won't be recorded as changed by a future UseMemory + memcpy(curData, newData, size); + } } void FifoRecorder::EndFrame(u32 fifoStart, u32 fifoEnd) { - // m_IsRecording is assumed to be true at this point, otherwise this function would not be called + // m_IsRecording is assumed to be true at this point, otherwise this function would not be called - sMutex.lock(); + sMutex.lock(); - m_FrameEnded = true; + m_FrameEnded = true; - m_CurrentFrame.fifoStart = fifoStart; - m_CurrentFrame.fifoEnd = fifoEnd; + m_CurrentFrame.fifoStart = fifoStart; + m_CurrentFrame.fifoEnd = fifoEnd; - if (m_WasRecording) - { - // If recording a fixed number of frames then check if the end of the recording was reached - if (m_RecordFramesRemaining > 0) - { - --m_RecordFramesRemaining; - if (m_RecordFramesRemaining == 0) - m_RequestedRecordingEnd = true; - } - } - else - { - m_WasRecording = true; + if (m_WasRecording) + { + // If recording a fixed number of frames then check if the end of the recording was reached + if (m_RecordFramesRemaining > 0) + { + --m_RecordFramesRemaining; + if (m_RecordFramesRemaining == 0) + m_RequestedRecordingEnd = true; + } + } + else + { + m_WasRecording = true; - // Skip the first data which will be the frame copy command - m_SkipNextData = true; - m_SkipFutureData = false; + // Skip the first data which will be the frame copy command + m_SkipNextData = true; + m_SkipFutureData = false; - m_FrameEnded = false; + m_FrameEnded = false; - m_FifoData.reserve(1024 * 1024 * 4); - m_FifoData.clear(); - } + m_FifoData.reserve(1024 * 1024 * 4); + m_FifoData.clear(); + } - if (m_RequestedRecordingEnd) - { - // Skip data after the next time WriteFifoData is called - m_SkipFutureData = true; - // Signal video backend that it should not call this function when the next frame ends - m_IsRecording = false; - } + if (m_RequestedRecordingEnd) + { + // Skip data after the next time WriteFifoData is called + m_SkipFutureData = true; + // Signal video backend that it should not call this function when the next frame ends + m_IsRecording = false; + } - sMutex.unlock(); + sMutex.unlock(); } -void FifoRecorder::SetVideoMemory(u32 *bpMem, u32 *cpMem, u32 *xfMem, u32 *xfRegs, u32 xfRegsSize) +void FifoRecorder::SetVideoMemory(u32* bpMem, u32* cpMem, u32* xfMem, u32* xfRegs, u32 xfRegsSize) { - sMutex.lock(); + sMutex.lock(); - if (m_File) - { - memcpy(m_File->GetBPMem(), bpMem, FifoDataFile::BP_MEM_SIZE * 4); - memcpy(m_File->GetCPMem(), cpMem, FifoDataFile::CP_MEM_SIZE * 4); - memcpy(m_File->GetXFMem(), xfMem, FifoDataFile::XF_MEM_SIZE * 4); + if (m_File) + { + memcpy(m_File->GetBPMem(), bpMem, FifoDataFile::BP_MEM_SIZE * 4); + memcpy(m_File->GetCPMem(), cpMem, FifoDataFile::CP_MEM_SIZE * 4); + memcpy(m_File->GetXFMem(), xfMem, FifoDataFile::XF_MEM_SIZE * 4); - u32 xfRegsCopySize = std::min((u32)FifoDataFile::XF_REGS_SIZE, xfRegsSize); - memcpy(m_File->GetXFRegs(), xfRegs, xfRegsCopySize * 4); - } + u32 xfRegsCopySize = std::min((u32)FifoDataFile::XF_REGS_SIZE, xfRegsSize); + memcpy(m_File->GetXFRegs(), xfRegs, xfRegsCopySize * 4); + } - FifoRecordAnalyzer::Initialize(cpMem); + FifoRecordAnalyzer::Initialize(cpMem); - sMutex.unlock(); + sMutex.unlock(); } FifoRecorder& FifoRecorder::GetInstance() { - return instance; + return instance; } diff --git a/Source/Core/Core/FifoPlayer/FifoRecorder.h b/Source/Core/Core/FifoPlayer/FifoRecorder.h index 91573f508b..ca2e335141 100644 --- a/Source/Core/Core/FifoPlayer/FifoRecorder.h +++ b/Source/Core/Core/FifoPlayer/FifoRecorder.h @@ -12,57 +12,57 @@ class FifoRecorder { public: - typedef void(*CallbackFunc)(void); + typedef void (*CallbackFunc)(void); - FifoRecorder(); - ~FifoRecorder(); + FifoRecorder(); + ~FifoRecorder(); - void StartRecording(s32 numFrames, CallbackFunc finishedCb); - void StopRecording(); + void StartRecording(s32 numFrames, CallbackFunc finishedCb); + void StopRecording(); - FifoDataFile* GetRecordedFile() { return m_File; } + FifoDataFile* GetRecordedFile() { return m_File; } + // Called from video thread - // Called from video thread + // Must write one full GP command at a time + void WriteGPCommand(u8* data, u32 size); - // Must write one full GP command at a time - void WriteGPCommand(u8* data, u32 size); + // Track memory that has been used and write it to the fifolog if it has changed. + // If memory is updated by the video backend (dynamicUpdate == true) take special care to make + // sure the data + // isn't baked into the fifolog. + void UseMemory(u32 address, u32 size, MemoryUpdate::Type type, bool dynamicUpdate = false); - // Track memory that has been used and write it to the fifolog if it has changed. - // If memory is updated by the video backend (dynamicUpdate == true) take special care to make sure the data - // isn't baked into the fifolog. - void UseMemory(u32 address, u32 size, MemoryUpdate::Type type, bool dynamicUpdate = false); + void EndFrame(u32 fifoStart, u32 fifoEnd); - void EndFrame(u32 fifoStart, u32 fifoEnd); + // This function must be called before writing GP commands + // bpMem must point to the actual bp mem array used by the plugin because it will be read as fifo + // data is recorded + void SetVideoMemory(u32* bpMem, u32* cpMem, u32* xfMem, u32* xfRegs, u32 xfRegsSize); - // This function must be called before writing GP commands - // bpMem must point to the actual bp mem array used by the plugin because it will be read as fifo data is recorded - void SetVideoMemory(u32* bpMem, u32* cpMem, u32* xfMem, u32* xfRegs, u32 xfRegsSize); - - // Checked once per frame prior to callng EndFrame() - bool IsRecording() const { return m_IsRecording; } - - static FifoRecorder& GetInstance(); + // Checked once per frame prior to callng EndFrame() + bool IsRecording() const { return m_IsRecording; } + static FifoRecorder& GetInstance(); private: - // Accessed from both GUI and video threads + // Accessed from both GUI and video threads - // True if video thread should send data - volatile bool m_IsRecording; - // True if m_IsRecording was true during last frame - volatile bool m_WasRecording; - volatile bool m_RequestedRecordingEnd; - volatile s32 m_RecordFramesRemaining; - volatile CallbackFunc m_FinishedCb; + // True if video thread should send data + volatile bool m_IsRecording; + // True if m_IsRecording was true during last frame + volatile bool m_WasRecording; + volatile bool m_RequestedRecordingEnd; + volatile s32 m_RecordFramesRemaining; + volatile CallbackFunc m_FinishedCb; - FifoDataFile* volatile m_File; + FifoDataFile* volatile m_File; - // Accessed only from video thread + // Accessed only from video thread - bool m_SkipNextData; - bool m_SkipFutureData; - bool m_FrameEnded; - FifoFrameInfo m_CurrentFrame; - std::vector m_FifoData; - std::vector m_Ram; - std::vector m_ExRam; + bool m_SkipNextData; + bool m_SkipFutureData; + bool m_FrameEnded; + FifoFrameInfo m_CurrentFrame; + std::vector m_FifoData; + std::vector m_Ram; + std::vector m_ExRam; }; diff --git a/Source/Core/Core/GeckoCode.cpp b/Source/Core/Core/GeckoCode.cpp index 117f5c1a39..f3472c38d7 100644 --- a/Source/Core/Core/GeckoCode.cpp +++ b/Source/Core/Core/GeckoCode.cpp @@ -16,37 +16,36 @@ namespace Gecko { - static const u32 INSTALLER_BASE_ADDRESS = 0x80001800; static const u32 INSTALLER_END_ADDRESS = 0x80003000; // return true if a code exists bool GeckoCode::Exist(u32 address, u32 data) const { - for (const GeckoCode::Code& code : codes) - { - if (code.address == address && code.data == data) - return true; - } + for (const GeckoCode::Code& code : codes) + { + if (code.address == address && code.data == data) + return true; + } - return false; + return false; } // return true if the code is identical bool GeckoCode::Compare(const GeckoCode& compare) const { - if (codes.size() != compare.codes.size()) - return false; + if (codes.size() != compare.codes.size()) + return false; - unsigned int exist = 0; + unsigned int exist = 0; - for (const GeckoCode::Code& code : codes) - { - if (compare.Exist(code.address, code.data)) - exist++; - } + for (const GeckoCode::Code& code : codes) + { + if (compare.Exist(code.address, code.data)) + exist++; + } - return exist == codes.size(); + return exist == codes.size(); } static bool code_handler_installed = false; @@ -56,136 +55,136 @@ static std::mutex active_codes_lock; void SetActiveCodes(const std::vector& gcodes) { - std::lock_guard lk(active_codes_lock); + std::lock_guard lk(active_codes_lock); - active_codes.clear(); + active_codes.clear(); - // add enabled codes - for (const GeckoCode& gecko_code : gcodes) - { - if (gecko_code.enabled) - { - // TODO: apply modifiers - // TODO: don't need description or creator string, just takin up memory - active_codes.push_back(gecko_code); - } - } + // add enabled codes + for (const GeckoCode& gecko_code : gcodes) + { + if (gecko_code.enabled) + { + // TODO: apply modifiers + // TODO: don't need description or creator string, just takin up memory + active_codes.push_back(gecko_code); + } + } - code_handler_installed = false; + code_handler_installed = false; } static bool InstallCodeHandler() { - std::string data; - std::string _rCodeHandlerFilename = File::GetSysDirectory() + GECKO_CODE_HANDLER; - if (!File::ReadFileToString(_rCodeHandlerFilename, data)) - { - NOTICE_LOG(ACTIONREPLAY, "Could not enable cheats because codehandler.bin was missing."); - return false; - } + std::string data; + std::string _rCodeHandlerFilename = File::GetSysDirectory() + GECKO_CODE_HANDLER; + if (!File::ReadFileToString(_rCodeHandlerFilename, data)) + { + NOTICE_LOG(ACTIONREPLAY, "Could not enable cheats because codehandler.bin was missing."); + return false; + } - u8 mmioAddr = 0xCC; + u8 mmioAddr = 0xCC; - if (SConfig::GetInstance().bWii) - { - mmioAddr = 0xCD; - } + if (SConfig::GetInstance().bWii) + { + mmioAddr = 0xCD; + } - // Install code handler - for (size_t i = 0, e = data.length(); i < e; ++i) - PowerPC::HostWrite_U8(data[i], (u32)(INSTALLER_BASE_ADDRESS + i)); + // Install code handler + for (size_t i = 0, e = data.length(); i < e; ++i) + PowerPC::HostWrite_U8(data[i], (u32)(INSTALLER_BASE_ADDRESS + i)); - // Patch the code handler to the system starting up - for (unsigned int h = 0; h < data.length(); h += 4) - { - // Patch MMIO address - if (PowerPC::HostRead_U32(INSTALLER_BASE_ADDRESS + h) == (0x3f000000u | ((mmioAddr ^ 1) << 8))) - { - NOTICE_LOG(ACTIONREPLAY, "Patching MMIO access at %08x", INSTALLER_BASE_ADDRESS + h); - PowerPC::HostWrite_U32(0x3f000000u | mmioAddr << 8, INSTALLER_BASE_ADDRESS + h); - } - } + // Patch the code handler to the system starting up + for (unsigned int h = 0; h < data.length(); h += 4) + { + // Patch MMIO address + if (PowerPC::HostRead_U32(INSTALLER_BASE_ADDRESS + h) == (0x3f000000u | ((mmioAddr ^ 1) << 8))) + { + NOTICE_LOG(ACTIONREPLAY, "Patching MMIO access at %08x", INSTALLER_BASE_ADDRESS + h); + PowerPC::HostWrite_U32(0x3f000000u | mmioAddr << 8, INSTALLER_BASE_ADDRESS + h); + } + } - u32 codelist_base_address = INSTALLER_BASE_ADDRESS + (u32)data.length() - 8; - u32 codelist_end_address = INSTALLER_END_ADDRESS; + u32 codelist_base_address = INSTALLER_BASE_ADDRESS + (u32)data.length() - 8; + u32 codelist_end_address = INSTALLER_END_ADDRESS; - // Write a magic value to 'gameid' (codehandleronly does not actually read this). - PowerPC::HostWrite_U32(0xd01f1bad, INSTALLER_BASE_ADDRESS); + // Write a magic value to 'gameid' (codehandleronly does not actually read this). + PowerPC::HostWrite_U32(0xd01f1bad, INSTALLER_BASE_ADDRESS); - // Create GCT in memory - PowerPC::HostWrite_U32(0x00d0c0de, codelist_base_address); - PowerPC::HostWrite_U32(0x00d0c0de, codelist_base_address + 4); + // Create GCT in memory + PowerPC::HostWrite_U32(0x00d0c0de, codelist_base_address); + PowerPC::HostWrite_U32(0x00d0c0de, codelist_base_address + 4); - std::lock_guard lk(active_codes_lock); + std::lock_guard lk(active_codes_lock); - int i = 0; + int i = 0; - for (const GeckoCode& active_code : active_codes) - { - if (active_code.enabled) - { - for (const GeckoCode::Code& code : active_code.codes) - { - // Make sure we have enough memory to hold the code list - if ((codelist_base_address + 24 + i) < codelist_end_address) - { - PowerPC::HostWrite_U32(code.address, codelist_base_address + 8 + i); - PowerPC::HostWrite_U32(code.data, codelist_base_address + 12 + i); - i += 8; - } - } - } - } + for (const GeckoCode& active_code : active_codes) + { + if (active_code.enabled) + { + for (const GeckoCode::Code& code : active_code.codes) + { + // Make sure we have enough memory to hold the code list + if ((codelist_base_address + 24 + i) < codelist_end_address) + { + PowerPC::HostWrite_U32(code.address, codelist_base_address + 8 + i); + PowerPC::HostWrite_U32(code.data, codelist_base_address + 12 + i); + i += 8; + } + } + } + } - PowerPC::HostWrite_U32(0xff000000, codelist_base_address + 8 + i); - PowerPC::HostWrite_U32(0x00000000, codelist_base_address + 12 + i); + PowerPC::HostWrite_U32(0xff000000, codelist_base_address + 8 + i); + PowerPC::HostWrite_U32(0x00000000, codelist_base_address + 12 + i); - // Turn on codes - PowerPC::HostWrite_U8(1, INSTALLER_BASE_ADDRESS + 7); + // Turn on codes + PowerPC::HostWrite_U8(1, INSTALLER_BASE_ADDRESS + 7); - // Invalidate the icache and any asm codes - for (unsigned int j = 0; j < (INSTALLER_END_ADDRESS - INSTALLER_BASE_ADDRESS); j += 32) - { - PowerPC::ppcState.iCache.Invalidate(INSTALLER_BASE_ADDRESS + j); - } - for (unsigned int k = codelist_base_address; k < codelist_end_address; k += 32) - { - PowerPC::ppcState.iCache.Invalidate(k); - } - return true; + // Invalidate the icache and any asm codes + for (unsigned int j = 0; j < (INSTALLER_END_ADDRESS - INSTALLER_BASE_ADDRESS); j += 32) + { + PowerPC::ppcState.iCache.Invalidate(INSTALLER_BASE_ADDRESS + j); + } + for (unsigned int k = codelist_base_address; k < codelist_end_address; k += 32) + { + PowerPC::ppcState.iCache.Invalidate(k); + } + return true; } void RunCodeHandler() { - if (SConfig::GetInstance().bEnableCheats && active_codes.size() > 0) - { - if (!code_handler_installed || PowerPC::HostRead_U32(INSTALLER_BASE_ADDRESS) - 0xd01f1bad > 5) - code_handler_installed = InstallCodeHandler(); + if (SConfig::GetInstance().bEnableCheats && active_codes.size() > 0) + { + if (!code_handler_installed || PowerPC::HostRead_U32(INSTALLER_BASE_ADDRESS) - 0xd01f1bad > 5) + code_handler_installed = InstallCodeHandler(); - if (!code_handler_installed) - { - // A warning was already issued. - return; - } + if (!code_handler_installed) + { + // A warning was already issued. + return; + } - if (PC == LR) - { - u32 oldLR = LR; - PowerPC::CoreMode oldMode = PowerPC::GetMode(); + if (PC == LR) + { + u32 oldLR = LR; + PowerPC::CoreMode oldMode = PowerPC::GetMode(); - PC = INSTALLER_BASE_ADDRESS + 0xA8; - LR = 0; + PC = INSTALLER_BASE_ADDRESS + 0xA8; + LR = 0; - // Execute the code handler in interpreter mode to track when it exits - PowerPC::SetMode(PowerPC::MODE_INTERPRETER); + // Execute the code handler in interpreter mode to track when it exits + PowerPC::SetMode(PowerPC::MODE_INTERPRETER); - while (PC != 0) - PowerPC::SingleStep(); + while (PC != 0) + PowerPC::SingleStep(); - PowerPC::SetMode(oldMode); - PC = LR = oldLR; - } - } + PowerPC::SetMode(oldMode); + PC = LR = oldLR; + } + } } -} // namespace Gecko +} // namespace Gecko diff --git a/Source/Core/Core/GeckoCode.h b/Source/Core/Core/GeckoCode.h index 23f3569090..37cc05f768 100644 --- a/Source/Core/Core/GeckoCode.h +++ b/Source/Core/Core/GeckoCode.h @@ -11,33 +11,30 @@ namespace Gecko { +class GeckoCode +{ +public: + GeckoCode() : enabled(false) {} + struct Code + { + u32 address = 0; + u32 data = 0; + std::string original_line; + }; - class GeckoCode - { - public: + std::vector codes; + std::string name, creator; + std::vector notes; - GeckoCode() : enabled(false) {} + bool enabled; + bool user_defined; - struct Code - { - u32 address = 0; - u32 data = 0; - std::string original_line; - }; + bool Compare(const GeckoCode& compare) const; + bool Exist(u32 address, u32 data) const; +}; - std::vector codes; - std::string name, creator; - std::vector notes; +void SetActiveCodes(const std::vector& gcodes); +bool RunActiveCodes(); +void RunCodeHandler(); - bool enabled; - bool user_defined; - - bool Compare(const GeckoCode& compare) const; - bool Exist(u32 address, u32 data) const; - }; - - void SetActiveCodes(const std::vector& gcodes); - bool RunActiveCodes(); - void RunCodeHandler(); - -} // namespace Gecko +} // namespace Gecko diff --git a/Source/Core/Core/GeckoCodeConfig.cpp b/Source/Core/Core/GeckoCodeConfig.cpp index 6ea75cf64d..a877297331 100644 --- a/Source/Core/Core/GeckoCodeConfig.cpp +++ b/Source/Core/Core/GeckoCodeConfig.cpp @@ -12,141 +12,138 @@ namespace Gecko { - void LoadCodes(const IniFile& globalIni, const IniFile& localIni, std::vector& gcodes) { - const IniFile* inis[2] = { &globalIni, &localIni }; + const IniFile* inis[2] = {&globalIni, &localIni}; - for (const IniFile* ini : inis) - { - std::vector lines; - ini->GetLines("Gecko", &lines, false); + for (const IniFile* ini : inis) + { + std::vector lines; + ini->GetLines("Gecko", &lines, false); - GeckoCode gcode; + GeckoCode gcode; - for (auto& line : lines) - { - if (line.empty()) - continue; + for (auto& line : lines) + { + if (line.empty()) + continue; - std::istringstream ss(line); + std::istringstream ss(line); - switch ((line)[0]) - { + switch ((line)[0]) + { + // enabled or disabled code + case '+': + ss.seekg(1); + case '$': + if (gcode.name.size()) + gcodes.push_back(gcode); + gcode = GeckoCode(); + gcode.enabled = (1 == ss.tellg()); // silly + gcode.user_defined = (ini == &localIni); + ss.seekg(1, std::ios_base::cur); + // read the code name + std::getline(ss, gcode.name, '['); // stop at [ character (beginning of contributor name) + gcode.name = StripSpaces(gcode.name); + // read the code creator name + std::getline(ss, gcode.creator, ']'); + break; - // enabled or disabled code - case '+' : - ss.seekg(1); - case '$' : - if (gcode.name.size()) - gcodes.push_back(gcode); - gcode = GeckoCode(); - gcode.enabled = (1 == ss.tellg()); // silly - gcode.user_defined = (ini == &localIni); - ss.seekg(1, std::ios_base::cur); - // read the code name - std::getline(ss, gcode.name, '['); // stop at [ character (beginning of contributor name) - gcode.name = StripSpaces(gcode.name); - // read the code creator name - std::getline(ss, gcode.creator, ']'); - break; + // notes + case '*': + gcode.notes.push_back(std::string(++line.begin(), line.end())); + break; - // notes - case '*': - gcode.notes.push_back(std::string(++line.begin(), line.end())); - break; + // either part of the code, or an option choice + default: + { + GeckoCode::Code new_code; + // TODO: support options + new_code.original_line = line; + ss >> std::hex >> new_code.address >> new_code.data; + gcode.codes.push_back(new_code); + } + break; + } + } - // either part of the code, or an option choice - default : - { - GeckoCode::Code new_code; - // TODO: support options - new_code.original_line = line; - ss >> std::hex >> new_code.address >> new_code.data; - gcode.codes.push_back(new_code); - } - break; - } + // add the last code + if (gcode.name.size()) + { + gcodes.push_back(gcode); + } - } + ini->GetLines("Gecko_Enabled", &lines, false); - // add the last code - if (gcode.name.size()) - { - gcodes.push_back(gcode); - } - - ini->GetLines("Gecko_Enabled", &lines, false); - - for (const std::string& line : lines) - { - if (line.size() == 0 || line[0] != '$') - { - continue; - } - std::string name = line.substr(1); - for (GeckoCode& ogcode : gcodes) - { - if (ogcode.name == name) - { - ogcode.enabled = true; - } - } - } - } + for (const std::string& line : lines) + { + if (line.size() == 0 || line[0] != '$') + { + continue; + } + std::string name = line.substr(1); + for (GeckoCode& ogcode : gcodes) + { + if (ogcode.name == name) + { + ogcode.enabled = true; + } + } + } + } } // used by the SaveGeckoCodes function -static void SaveGeckoCode(std::vector& lines, std::vector& enabledLines, const GeckoCode& gcode) +static void SaveGeckoCode(std::vector& lines, std::vector& enabledLines, + const GeckoCode& gcode) { - if (gcode.enabled) - enabledLines.push_back("$" + gcode.name); + if (gcode.enabled) + enabledLines.push_back("$" + gcode.name); - if (!gcode.user_defined) - return; + if (!gcode.user_defined) + return; - std::string name; + std::string name; - // save the name - name += '$'; - name += gcode.name; + // save the name + name += '$'; + name += gcode.name; - // save the creator name - if (gcode.creator.size()) - { - name += " ["; - name += gcode.creator; - name += ']'; - } + // save the creator name + if (gcode.creator.size()) + { + name += " ["; + name += gcode.creator; + name += ']'; + } - lines.push_back(name); + lines.push_back(name); - // save all the code lines - for (const GeckoCode::Code& code : gcode.codes) - { - //ss << std::hex << codes_iter->address << ' ' << codes_iter->data; - //lines.push_back(StringFromFormat("%08X %08X", codes_iter->address, codes_iter->data)); - lines.push_back(code.original_line); - //ss.clear(); - } + // save all the code lines + for (const GeckoCode::Code& code : gcode.codes) + { + // ss << std::hex << codes_iter->address << ' ' << codes_iter->data; + // lines.push_back(StringFromFormat("%08X %08X", codes_iter->address, codes_iter->data)); + lines.push_back(code.original_line); + // ss.clear(); + } - // save the notes - for (const std::string& note : gcode.notes) - lines.push_back(std::string("*") + note); + // save the notes + for (const std::string& note : gcode.notes) + lines.push_back(std::string("*") + note); } void SaveCodes(IniFile& inifile, const std::vector& gcodes) { - std::vector lines; - std::vector enabledLines; + std::vector lines; + std::vector enabledLines; - for (const GeckoCode& geckoCode : gcodes) - { - SaveGeckoCode(lines, enabledLines, geckoCode); - } + for (const GeckoCode& geckoCode : gcodes) + { + SaveGeckoCode(lines, enabledLines, geckoCode); + } - inifile.SetLines("Gecko", lines); - inifile.SetLines("Gecko_Enabled", enabledLines); + inifile.SetLines("Gecko", lines); + inifile.SetLines("Gecko_Enabled", enabledLines); } - } diff --git a/Source/Core/Core/GeckoCodeConfig.h b/Source/Core/Core/GeckoCodeConfig.h index 52ebbd8413..ce0427633b 100644 --- a/Source/Core/Core/GeckoCodeConfig.h +++ b/Source/Core/Core/GeckoCodeConfig.h @@ -11,8 +11,6 @@ class IniFile; namespace Gecko { - void LoadCodes(const IniFile& globalIni, const IniFile& localIni, std::vector& gcodes); void SaveCodes(IniFile& inifile, const std::vector& gcodes); - } diff --git a/Source/Core/Core/HLE/HLE.cpp b/Source/Core/Core/HLE/HLE.cpp index b91e23c4fc..2c60f7d2e6 100644 --- a/Source/Core/Core/HLE/HLE.cpp +++ b/Source/Core/Core/HLE/HLE.cpp @@ -12,13 +12,11 @@ #include "Core/HLE/HLE_OS.h" #include "Core/HW/Memmap.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_es.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PPCSymbolDB.h" - +#include "Core/PowerPC/PowerPC.h" namespace HLE { - using namespace PowerPC; typedef void (*TPatchFunction)(); @@ -27,145 +25,148 @@ static std::map s_original_instructions; enum { - HLE_RETURNTYPE_BLR = 0, - HLE_RETURNTYPE_RFI = 1, + HLE_RETURNTYPE_BLR = 0, + HLE_RETURNTYPE_RFI = 1, }; struct SPatch { - char m_szPatchName[128]; - TPatchFunction PatchFunction; - int type; - int flags; + char m_szPatchName[128]; + TPatchFunction PatchFunction; + int type; + int flags; }; -static const SPatch OSPatches[] = -{ - { "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC }, +static const SPatch OSPatches[] = { + {"FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC}, - { "PanicAlert", HLE_Misc::HLEPanicAlert, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, + {"PanicAlert", HLE_Misc::HLEPanicAlert, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG}, - // Name doesn't matter, installed in CBoot::BootUp() - { "HBReload", HLE_Misc::HBReload, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC }, + // Name doesn't matter, installed in CBoot::BootUp() + {"HBReload", HLE_Misc::HBReload, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC}, - // Debug/OS Support - { "OSPanic", HLE_OS::HLE_OSPanic, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, + // Debug/OS Support + {"OSPanic", HLE_OS::HLE_OSPanic, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG}, - { "OSReport", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, - { "DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, - { "WUD_DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, - { "vprintf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, - { "printf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, - { "puts", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, // gcc-optimized printf? - { "___blank(char *,...)", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, // used for early init things (normally) - { "___blank", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, - { "__write_console", HLE_OS::HLE_write_console, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, // used by sysmenu (+more?) - { "GeckoCodehandler", HLE_Misc::HLEGeckoCodehandler, HLE_HOOK_START, HLE_TYPE_GENERIC }, + {"OSReport", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG}, + {"DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG}, + {"WUD_DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG}, + {"vprintf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG}, + {"printf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG}, + {"puts", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, + HLE_TYPE_DEBUG}, // gcc-optimized printf? + {"___blank(char *,...)", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, + HLE_TYPE_DEBUG}, // used for early init things (normally) + {"___blank", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG}, + {"__write_console", HLE_OS::HLE_write_console, HLE_HOOK_REPLACE, + HLE_TYPE_DEBUG}, // used by sysmenu (+more?) + {"GeckoCodehandler", HLE_Misc::HLEGeckoCodehandler, HLE_HOOK_START, HLE_TYPE_GENERIC}, }; -static const SPatch OSBreakPoints[] = -{ - { "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction }, +static const SPatch OSBreakPoints[] = { + {"FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction}, }; -void Patch(u32 addr, const char *hle_func_name) +void Patch(u32 addr, const char* hle_func_name) { - for (u32 i = 0; i < sizeof(OSPatches) / sizeof(SPatch); i++) - { - if (!strcmp(OSPatches[i].m_szPatchName, hle_func_name)) - { - s_original_instructions[addr] = i; - return; - } - } + for (u32 i = 0; i < sizeof(OSPatches) / sizeof(SPatch); i++) + { + if (!strcmp(OSPatches[i].m_szPatchName, hle_func_name)) + { + s_original_instructions[addr] = i; + return; + } + } } void PatchFunctions() { - s_original_instructions.clear(); - for (u32 i = 0; i < sizeof(OSPatches) / sizeof(SPatch); i++) - { - Symbol *symbol = g_symbolDB.GetSymbolFromName(OSPatches[i].m_szPatchName); - if (symbol) - { - for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4) - { - s_original_instructions[addr] = i; - } - INFO_LOG(OSHLE, "Patching %s %08x", OSPatches[i].m_szPatchName, symbol->address); - } - } + s_original_instructions.clear(); + for (u32 i = 0; i < sizeof(OSPatches) / sizeof(SPatch); i++) + { + Symbol* symbol = g_symbolDB.GetSymbolFromName(OSPatches[i].m_szPatchName); + if (symbol) + { + for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4) + { + s_original_instructions[addr] = i; + } + INFO_LOG(OSHLE, "Patching %s %08x", OSPatches[i].m_szPatchName, symbol->address); + } + } - if (SConfig::GetInstance().bEnableDebugging) - { - for (size_t i = 1; i < sizeof(OSBreakPoints) / sizeof(SPatch); i++) - { - Symbol *symbol = g_symbolDB.GetSymbolFromName(OSPatches[i].m_szPatchName); - if (symbol) - { - PowerPC::breakpoints.Add(symbol->address, false); - INFO_LOG(OSHLE, "Adding BP to %s %08x", OSBreakPoints[i].m_szPatchName, symbol->address); - } - } - } + if (SConfig::GetInstance().bEnableDebugging) + { + for (size_t i = 1; i < sizeof(OSBreakPoints) / sizeof(SPatch); i++) + { + Symbol* symbol = g_symbolDB.GetSymbolFromName(OSPatches[i].m_szPatchName); + if (symbol) + { + PowerPC::breakpoints.Add(symbol->address, false); + INFO_LOG(OSHLE, "Adding BP to %s %08x", OSBreakPoints[i].m_szPatchName, symbol->address); + } + } + } - // CBreakPoints::AddBreakPoint(0x8000D3D0, false); + // CBreakPoints::AddBreakPoint(0x8000D3D0, false); } void Execute(u32 _CurrentPC, u32 _Instruction) { - unsigned int FunctionIndex = _Instruction & 0xFFFFF; - if ((FunctionIndex > 0) && (FunctionIndex < (sizeof(OSPatches) / sizeof(SPatch)))) - { - OSPatches[FunctionIndex].PatchFunction(); - } - else - { - PanicAlert("HLE system tried to call an undefined HLE function %i.", FunctionIndex); - } + unsigned int FunctionIndex = _Instruction & 0xFFFFF; + if ((FunctionIndex > 0) && (FunctionIndex < (sizeof(OSPatches) / sizeof(SPatch)))) + { + OSPatches[FunctionIndex].PatchFunction(); + } + else + { + PanicAlert("HLE system tried to call an undefined HLE function %i.", FunctionIndex); + } - // _dbg_assert_msg_(HLE,NPC == LR, "Broken HLE function (doesn't set NPC)", OSPatches[pos].m_szPatchName); + // _dbg_assert_msg_(HLE,NPC == LR, "Broken HLE function (doesn't set NPC)", + // OSPatches[pos].m_szPatchName); } u32 GetFunctionIndex(u32 addr) { - auto iter = s_original_instructions.find(addr); - return (iter != s_original_instructions.end()) ? iter->second : 0; + auto iter = s_original_instructions.find(addr); + return (iter != s_original_instructions.end()) ? iter->second : 0; } int GetFunctionTypeByIndex(u32 index) { - return OSPatches[index].type; + return OSPatches[index].type; } int GetFunctionFlagsByIndex(u32 index) { - return OSPatches[index].flags; + return OSPatches[index].flags; } bool IsEnabled(int flags) { - if (flags == HLE::HLE_TYPE_DEBUG && !SConfig::GetInstance().bEnableDebugging && PowerPC::GetMode() != MODE_INTERPRETER) - return false; + if (flags == HLE::HLE_TYPE_DEBUG && !SConfig::GetInstance().bEnableDebugging && + PowerPC::GetMode() != MODE_INTERPRETER) + return false; - return true; + return true; } u32 UnPatch(const std::string& patchName) { - Symbol* symbol = g_symbolDB.GetSymbolFromName(patchName); + Symbol* symbol = g_symbolDB.GetSymbolFromName(patchName); - if (symbol) - { - for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4) - { - s_original_instructions[addr] = 0; - PowerPC::ppcState.iCache.Invalidate(addr); - } - return symbol->address; - } + if (symbol) + { + for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4) + { + s_original_instructions[addr] = 0; + PowerPC::ppcState.iCache.Invalidate(addr); + } + return symbol->address; + } - return 0; + return 0; } } // end of namespace HLE diff --git a/Source/Core/Core/HLE/HLE.h b/Source/Core/Core/HLE/HLE.h index d45d000e3e..42f3be0bcb 100644 --- a/Source/Core/Core/HLE/HLE.h +++ b/Source/Core/Core/HLE/HLE.h @@ -10,28 +10,28 @@ namespace HLE { - enum - { - HLE_HOOK_START = 0, // Hook the beginning of the function and execute the function afterwards - HLE_HOOK_REPLACE = 1, // Replace the function with the HLE version - HLE_HOOK_NONE = 2, // Do not hook the function - }; +enum +{ + HLE_HOOK_START = 0, // Hook the beginning of the function and execute the function afterwards + HLE_HOOK_REPLACE = 1, // Replace the function with the HLE version + HLE_HOOK_NONE = 2, // Do not hook the function +}; - enum - { - HLE_TYPE_GENERIC = 0, // Miscellaneous function - HLE_TYPE_DEBUG = 1, // Debug output function - }; +enum +{ + HLE_TYPE_GENERIC = 0, // Miscellaneous function + HLE_TYPE_DEBUG = 1, // Debug output function +}; - void PatchFunctions(); +void PatchFunctions(); - void Patch(u32 pc, const char *func_name); - u32 UnPatch(const std::string& patchName); - void Execute(u32 _CurrentPC, u32 _Instruction); +void Patch(u32 pc, const char* func_name); +u32 UnPatch(const std::string& patchName); +void Execute(u32 _CurrentPC, u32 _Instruction); - u32 GetFunctionIndex(u32 em_address); - int GetFunctionTypeByIndex(u32 index); - int GetFunctionFlagsByIndex(u32 index); +u32 GetFunctionIndex(u32 em_address); +int GetFunctionTypeByIndex(u32 index); +int GetFunctionFlagsByIndex(u32 index); - bool IsEnabled(int flags); +bool IsEnabled(int flags); } diff --git a/Source/Core/Core/HLE/HLE_Misc.cpp b/Source/Core/Core/HLE/HLE_Misc.cpp index 26ce8c884f..a59b474916 100644 --- a/Source/Core/Core/HLE/HLE_Misc.cpp +++ b/Source/Core/Core/HLE/HLE_Misc.cpp @@ -7,59 +7,57 @@ #include "Common/CommonTypes.h" #include "Core/ConfigManager.h" -#include "Core/Host.h" #include "Core/HLE/HLE_Misc.h" #include "Core/HW/CPU.h" -#include "Core/PowerPC/PowerPC.h" +#include "Core/Host.h" #include "Core/PowerPC/PPCCache.h" +#include "Core/PowerPC/PowerPC.h" namespace HLE_Misc { - static std::string args; // If you just want to kill a function, one of the three following are usually appropriate. // According to the PPC ABI, the return value is always in r3. void UnimplementedFunction() { - NPC = LR; + NPC = LR; } // If you want a function to panic, you can rename it PanicAlert :p // Don't know if this is worth keeping. void HLEPanicAlert() { - ::PanicAlert("HLE: PanicAlert %08x", LR); - NPC = LR; + ::PanicAlert("HLE: PanicAlert %08x", LR); + NPC = LR; } void HBReload() { - // There isn't much we can do. Just stop cleanly. - CPU::Break(); - Host_Message(WM_USER_STOP); + // There isn't much we can do. Just stop cleanly. + CPU::Break(); + Host_Message(WM_USER_STOP); } void HLEGeckoCodehandler() { - // Work around the codehandler not properly invalidating the icache, but - // only the first few frames. - // (Project M uses a conditional to only apply patches after something has - // been read into memory, or such, so we do the first 5 frames. More - // robust alternative would be to actually detect memory writes, but that - // would be even uglier.) - u32 magic = 0xd01f1bad; - u32 existing = PowerPC::HostRead_U32(0x80001800); - if (existing - magic == 5) - { - return; - } - else if (existing - magic > 5) - { - existing = magic; - } - PowerPC::HostWrite_U32(existing + 1, 0x80001800); - PowerPC::ppcState.iCache.Reset(); + // Work around the codehandler not properly invalidating the icache, but + // only the first few frames. + // (Project M uses a conditional to only apply patches after something has + // been read into memory, or such, so we do the first 5 frames. More + // robust alternative would be to actually detect memory writes, but that + // would be even uglier.) + u32 magic = 0xd01f1bad; + u32 existing = PowerPC::HostRead_U32(0x80001800); + if (existing - magic == 5) + { + return; + } + else if (existing - magic > 5) + { + existing = magic; + } + PowerPC::HostWrite_U32(existing + 1, 0x80001800); + PowerPC::ppcState.iCache.Reset(); } - } diff --git a/Source/Core/Core/HLE/HLE_Misc.h b/Source/Core/Core/HLE/HLE_Misc.h index 70565c2324..2ba9bb367c 100644 --- a/Source/Core/Core/HLE/HLE_Misc.h +++ b/Source/Core/Core/HLE/HLE_Misc.h @@ -6,8 +6,8 @@ namespace HLE_Misc { - void HLEPanicAlert(); - void UnimplementedFunction(); - void HBReload(); - void HLEGeckoCodehandler(); +void HLEPanicAlert(); +void UnimplementedFunction(); +void HBReload(); +void HLEGeckoCodehandler(); } diff --git a/Source/Core/Core/HLE/HLE_OS.cpp b/Source/Core/Core/HLE/HLE_OS.cpp index 8ab2478b4b..34de681267 100644 --- a/Source/Core/Core/HLE/HLE_OS.cpp +++ b/Source/Core/Core/HLE/HLE_OS.cpp @@ -5,139 +5,139 @@ #include #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "Core/HLE/HLE_OS.h" #include "Core/HW/Memmap.h" #include "Core/PowerPC/PowerPC.h" namespace HLE_OS { - void GetStringVA(std::string& _rOutBuffer, u32 strReg = 3); void HLE_OSPanic() { - std::string Error, Msg; - GetStringVA(Error); - GetStringVA(Msg, 5); + std::string Error, Msg; + GetStringVA(Error); + GetStringVA(Msg, 5); - PanicAlert("OSPanic: %s: %s", Error.c_str(), Msg.c_str()); - ERROR_LOG(OSREPORT, "%08x->%08x| OSPanic: %s: %s", LR, PC, Error.c_str(), Msg.c_str()); + PanicAlert("OSPanic: %s: %s", Error.c_str(), Msg.c_str()); + ERROR_LOG(OSREPORT, "%08x->%08x| OSPanic: %s: %s", LR, PC, Error.c_str(), Msg.c_str()); - NPC = LR; + NPC = LR; } // Generalized func for just printing string pointed to by r3. void HLE_GeneralDebugPrint() { - std::string ReportMessage; - if (PowerPC::HostRead_U32(GPR(3)) > 0x80000000) - { - GetStringVA(ReportMessage, 4); - } - else - { - GetStringVA(ReportMessage); - } - NPC = LR; + std::string ReportMessage; + if (PowerPC::HostRead_U32(GPR(3)) > 0x80000000) + { + GetStringVA(ReportMessage, 4); + } + else + { + GetStringVA(ReportMessage); + } + NPC = LR; - //PanicAlert("(%08x->%08x) %s", LR, PC, ReportMessage.c_str()); - NOTICE_LOG(OSREPORT, "%08x->%08x| %s", LR, PC, ReportMessage.c_str()); + // PanicAlert("(%08x->%08x) %s", LR, PC, ReportMessage.c_str()); + NOTICE_LOG(OSREPORT, "%08x->%08x| %s", LR, PC, ReportMessage.c_str()); } // __write_console is slightly abnormal void HLE_write_console() { - std::string ReportMessage; - GetStringVA(ReportMessage, 4); - NPC = LR; + std::string ReportMessage; + GetStringVA(ReportMessage, 4); + NPC = LR; - //PanicAlert("(%08x->%08x) %s", LR, PC, ReportMessage.c_str()); - NOTICE_LOG(OSREPORT, "%08x->%08x| %s", LR, PC, ReportMessage.c_str()); + // PanicAlert("(%08x->%08x) %s", LR, PC, ReportMessage.c_str()); + NOTICE_LOG(OSREPORT, "%08x->%08x| %s", LR, PC, ReportMessage.c_str()); } void GetStringVA(std::string& _rOutBuffer, u32 strReg) { - _rOutBuffer = ""; - std::string ArgumentBuffer = ""; - u32 ParameterCounter = strReg+1; - u32 FloatingParameterCounter = 1; - std::string string = PowerPC::HostGetString(GPR(strReg)); + _rOutBuffer = ""; + std::string ArgumentBuffer = ""; + u32 ParameterCounter = strReg + 1; + u32 FloatingParameterCounter = 1; + std::string string = PowerPC::HostGetString(GPR(strReg)); - for(u32 i = 0; i < string.size(); i++) - { - if (string[i] == '%') - { - ArgumentBuffer = "%"; - i++; - if (string[i] == '%') - { - _rOutBuffer += "%"; - continue; - } - while (string[i] < 'A' || string[i] > 'z' || string[i] == 'l' || string[i] == '-') - ArgumentBuffer += string[i++]; + for (u32 i = 0; i < string.size(); i++) + { + if (string[i] == '%') + { + ArgumentBuffer = "%"; + i++; + if (string[i] == '%') + { + _rOutBuffer += "%"; + continue; + } + while (string[i] < 'A' || string[i] > 'z' || string[i] == 'l' || string[i] == '-') + ArgumentBuffer += string[i++]; - ArgumentBuffer += string[i]; + ArgumentBuffer += string[i]; - u64 Parameter; - if (ParameterCounter > 10) - { - Parameter = PowerPC::HostRead_U32(GPR(1) + 0x8 + ((ParameterCounter - 11) * 4)); - } - else - { - if (string[i-1] == 'l' && string[i-2] == 'l') // hax, just seen this on sysmenu osreport - { - Parameter = GPR(++ParameterCounter); - Parameter = (Parameter<<32)|GPR(++ParameterCounter); - } - else // normal, 32bit - Parameter = GPR(ParameterCounter); - } - ParameterCounter++; + u64 Parameter; + if (ParameterCounter > 10) + { + Parameter = PowerPC::HostRead_U32(GPR(1) + 0x8 + ((ParameterCounter - 11) * 4)); + } + else + { + if (string[i - 1] == 'l' && + string[i - 2] == 'l') // hax, just seen this on sysmenu osreport + { + Parameter = GPR(++ParameterCounter); + Parameter = (Parameter << 32) | GPR(++ParameterCounter); + } + else // normal, 32bit + Parameter = GPR(ParameterCounter); + } + ParameterCounter++; - switch (string[i]) - { - case 's': - _rOutBuffer += StringFromFormat(ArgumentBuffer.c_str(), PowerPC::HostGetString((u32)Parameter).c_str()); - break; + switch (string[i]) + { + case 's': + _rOutBuffer += StringFromFormat(ArgumentBuffer.c_str(), + PowerPC::HostGetString((u32)Parameter).c_str()); + break; - case 'd': - case 'i': - { - _rOutBuffer += StringFromFormat(ArgumentBuffer.c_str(), Parameter); - break; - } + case 'd': + case 'i': + { + _rOutBuffer += StringFromFormat(ArgumentBuffer.c_str(), Parameter); + break; + } - case 'f': - { - _rOutBuffer += StringFromFormat(ArgumentBuffer.c_str(), - rPS0(FloatingParameterCounter)); - FloatingParameterCounter++; - ParameterCounter--; - break; - } + case 'f': + { + _rOutBuffer += StringFromFormat(ArgumentBuffer.c_str(), rPS0(FloatingParameterCounter)); + FloatingParameterCounter++; + ParameterCounter--; + break; + } - case 'p': - // Override, so 64bit Dolphin prints 32bit pointers, since the ppc is 32bit :) - _rOutBuffer += StringFromFormat("%x", (u32)Parameter); - break; + case 'p': + // Override, so 64bit Dolphin prints 32bit pointers, since the ppc is 32bit :) + _rOutBuffer += StringFromFormat("%x", (u32)Parameter); + break; - default: - _rOutBuffer += StringFromFormat(ArgumentBuffer.c_str(), Parameter); - break; - } - } - else - { - _rOutBuffer += string[i]; - } - } - if (!_rOutBuffer.empty() && _rOutBuffer[_rOutBuffer.length() - 1] == '\n') - _rOutBuffer.resize(_rOutBuffer.length() - 1); + default: + _rOutBuffer += StringFromFormat(ArgumentBuffer.c_str(), Parameter); + break; + } + } + else + { + _rOutBuffer += string[i]; + } + } + if (!_rOutBuffer.empty() && _rOutBuffer[_rOutBuffer.length() - 1] == '\n') + _rOutBuffer.resize(_rOutBuffer.length() - 1); } } // end of namespace HLE_OS diff --git a/Source/Core/Core/HLE/HLE_OS.h b/Source/Core/Core/HLE/HLE_OS.h index 0bf4f5c2ea..d729a8842f 100644 --- a/Source/Core/Core/HLE/HLE_OS.h +++ b/Source/Core/Core/HLE/HLE_OS.h @@ -6,7 +6,7 @@ namespace HLE_OS { - void HLE_GeneralDebugPrint(); - void HLE_write_console(); - void HLE_OSPanic(); +void HLE_GeneralDebugPrint(); +void HLE_write_console(); +void HLE_OSPanic(); } diff --git a/Source/Core/Core/HW/AudioInterface.cpp b/Source/Core/Core/HW/AudioInterface.cpp index f88ebd0326..de062df4aa 100644 --- a/Source/Core/Core/HW/AudioInterface.cpp +++ b/Source/Core/Core/HW/AudioInterface.cpp @@ -51,56 +51,54 @@ This file mainly deals with the [Drive I/F], however [AIDFR] controls namespace AudioInterface { - // Internal hardware addresses enum { - AI_CONTROL_REGISTER = 0x6C00, - AI_VOLUME_REGISTER = 0x6C04, - AI_SAMPLE_COUNTER = 0x6C08, - AI_INTERRUPT_TIMING = 0x6C0C, + AI_CONTROL_REGISTER = 0x6C00, + AI_VOLUME_REGISTER = 0x6C04, + AI_SAMPLE_COUNTER = 0x6C08, + AI_INTERRUPT_TIMING = 0x6C0C, }; enum { - AIS_32KHz = 0, - AIS_48KHz = 1, + AIS_32KHz = 0, + AIS_48KHz = 1, - AID_32KHz = 1, - AID_48KHz = 0 + AID_32KHz = 1, + AID_48KHz = 0 }; // AI Control Register -union AICR -{ - AICR() { hex = 0;} - AICR(u32 _hex) { hex = _hex;} - struct - { - u32 PSTAT : 1; // sample counter/playback enable - u32 AISFR : 1; // AIS Frequency (0=32khz 1=48khz) - u32 AIINTMSK : 1; // 0=interrupt masked 1=interrupt enabled - u32 AIINT : 1; // audio interrupt status - u32 AIINTVLD : 1; // This bit controls whether AIINT is affected by the Interrupt Timing register - // matching the sample counter. Once set, AIINT will hold its last value - u32 SCRESET : 1; // write to reset counter - u32 AIDFR : 1; // AID Frequency (0=48khz 1=32khz) - u32 :25; - }; - u32 hex; +union AICR { + AICR() { hex = 0; } + AICR(u32 _hex) { hex = _hex; } + struct + { + u32 PSTAT : 1; // sample counter/playback enable + u32 AISFR : 1; // AIS Frequency (0=32khz 1=48khz) + u32 AIINTMSK : 1; // 0=interrupt masked 1=interrupt enabled + u32 AIINT : 1; // audio interrupt status + u32 AIINTVLD : 1; // This bit controls whether AIINT is affected by the Interrupt Timing + // register + // matching the sample counter. Once set, AIINT will hold its last value + u32 SCRESET : 1; // write to reset counter + u32 AIDFR : 1; // AID Frequency (0=48khz 1=32khz) + u32 : 25; + }; + u32 hex; }; // AI Volume Register -union AIVR -{ - AIVR() { hex = 0;} - struct - { - u32 left : 8; - u32 right : 8; - u32 :16; - }; - u32 hex; +union AIVR { + AIVR() { hex = 0; } + struct + { + u32 left : 8; + u32 right : 8; + u32 : 16; + }; + u32 hex; }; // STATE_TO_SAVE @@ -116,16 +114,16 @@ static u64 g_CPUCyclesPerSample = 0xFFFFFFFFFFFULL; static unsigned int g_AISSampleRate = 48000; static unsigned int g_AIDSampleRate = 32000; -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - p.DoPOD(m_Control); - p.DoPOD(m_Volume); - p.Do(m_SampleCounter); - p.Do(m_InterruptTiming); - p.Do(g_LastCPUTime); - p.Do(g_AISSampleRate); - p.Do(g_AIDSampleRate); - p.Do(g_CPUCyclesPerSample); + p.DoPOD(m_Control); + p.DoPOD(m_Volume); + p.Do(m_SampleCounter); + p.Do(m_InterruptTiming); + p.Do(g_LastCPUTime); + p.Do(g_AISSampleRate); + p.Do(g_AIDSampleRate); + p.Do(g_CPUCyclesPerSample); } static void GenerateAudioInterrupt(); @@ -137,19 +135,19 @@ static void Update(u64 userdata, s64 cyclesLate); void Init() { - m_Control.hex = 0; - m_Control.AISFR = AIS_48KHz; - m_Volume.hex = 0; - m_SampleCounter = 0; - m_InterruptTiming = 0; + m_Control.hex = 0; + m_Control.AISFR = AIS_48KHz; + m_Volume.hex = 0; + m_SampleCounter = 0; + m_InterruptTiming = 0; - g_LastCPUTime = 0; - g_CPUCyclesPerSample = 0xFFFFFFFFFFFULL; + g_LastCPUTime = 0; + g_CPUCyclesPerSample = 0xFFFFFFFFFFFULL; - g_AISSampleRate = 48000; - g_AIDSampleRate = 32000; + g_AISSampleRate = 48000; + g_AIDSampleRate = 32000; - et_AI = CoreTiming::RegisterEvent("AICallback", Update); + et_AI = CoreTiming::RegisterEvent("AICallback", Update); } void Shutdown() @@ -158,170 +156,165 @@ void Shutdown() void RegisterMMIO(MMIO::Mapping* mmio, u32 base) { - mmio->Register(base | AI_CONTROL_REGISTER, - MMIO::DirectRead(&m_Control.hex), - MMIO::ComplexWrite([](u32, u32 val) { - AICR tmpAICtrl(val); + mmio->Register( + base | AI_CONTROL_REGISTER, MMIO::DirectRead(&m_Control.hex), + MMIO::ComplexWrite([](u32, u32 val) { + AICR tmpAICtrl(val); + if (m_Control.AIINTMSK != tmpAICtrl.AIINTMSK) + { + DEBUG_LOG(AUDIO_INTERFACE, "Change AIINTMSK to %d", tmpAICtrl.AIINTMSK); + m_Control.AIINTMSK = tmpAICtrl.AIINTMSK; + } - if (m_Control.AIINTMSK != tmpAICtrl.AIINTMSK) - { - DEBUG_LOG(AUDIO_INTERFACE, "Change AIINTMSK to %d", tmpAICtrl.AIINTMSK); - m_Control.AIINTMSK = tmpAICtrl.AIINTMSK; - } + if (m_Control.AIINTVLD != tmpAICtrl.AIINTVLD) + { + DEBUG_LOG(AUDIO_INTERFACE, "Change AIINTVLD to %d", tmpAICtrl.AIINTVLD); + m_Control.AIINTVLD = tmpAICtrl.AIINTVLD; + } - if (m_Control.AIINTVLD != tmpAICtrl.AIINTVLD) - { - DEBUG_LOG(AUDIO_INTERFACE, "Change AIINTVLD to %d", tmpAICtrl.AIINTVLD); - m_Control.AIINTVLD = tmpAICtrl.AIINTVLD; - } + // Set frequency of streaming audio + if (tmpAICtrl.AISFR != m_Control.AISFR) + { + // AISFR rates below are intentionally inverted wrt yagcd + DEBUG_LOG(AUDIO_INTERFACE, "Change AISFR to %s", tmpAICtrl.AISFR ? "48khz" : "32khz"); + m_Control.AISFR = tmpAICtrl.AISFR; + g_AISSampleRate = tmpAICtrl.AISFR ? 48000 : 32000; + g_sound_stream->GetMixer()->SetStreamInputSampleRate(g_AISSampleRate); + g_CPUCyclesPerSample = SystemTimers::GetTicksPerSecond() / g_AISSampleRate; + } + // Set frequency of DMA + if (tmpAICtrl.AIDFR != m_Control.AIDFR) + { + DEBUG_LOG(AUDIO_INTERFACE, "Change AIDFR to %s", tmpAICtrl.AIDFR ? "32khz" : "48khz"); + m_Control.AIDFR = tmpAICtrl.AIDFR; + g_AIDSampleRate = tmpAICtrl.AIDFR ? 32000 : 48000; + g_sound_stream->GetMixer()->SetDMAInputSampleRate(g_AIDSampleRate); + } - // Set frequency of streaming audio - if (tmpAICtrl.AISFR != m_Control.AISFR) - { - // AISFR rates below are intentionally inverted wrt yagcd - DEBUG_LOG(AUDIO_INTERFACE, "Change AISFR to %s", tmpAICtrl.AISFR ? "48khz":"32khz"); - m_Control.AISFR = tmpAICtrl.AISFR; - g_AISSampleRate = tmpAICtrl.AISFR ? 48000 : 32000; - g_sound_stream->GetMixer()->SetStreamInputSampleRate(g_AISSampleRate); - g_CPUCyclesPerSample = SystemTimers::GetTicksPerSecond() / g_AISSampleRate; - } - // Set frequency of DMA - if (tmpAICtrl.AIDFR != m_Control.AIDFR) - { - DEBUG_LOG(AUDIO_INTERFACE, "Change AIDFR to %s", tmpAICtrl.AIDFR ? "32khz":"48khz"); - m_Control.AIDFR = tmpAICtrl.AIDFR; - g_AIDSampleRate = tmpAICtrl.AIDFR ? 32000 : 48000; - g_sound_stream->GetMixer()->SetDMAInputSampleRate(g_AIDSampleRate); - } + // Streaming counter + if (tmpAICtrl.PSTAT != m_Control.PSTAT) + { + DEBUG_LOG(AUDIO_INTERFACE, "%s streaming audio", tmpAICtrl.PSTAT ? "start" : "stop"); + m_Control.PSTAT = tmpAICtrl.PSTAT; + g_LastCPUTime = CoreTiming::GetTicks(); + CoreTiming::RemoveEvent(et_AI); + CoreTiming::ScheduleEvent(GetAIPeriod(), et_AI); + } - // Streaming counter - if (tmpAICtrl.PSTAT != m_Control.PSTAT) - { - DEBUG_LOG(AUDIO_INTERFACE, "%s streaming audio", tmpAICtrl.PSTAT ? "start":"stop"); - m_Control.PSTAT = tmpAICtrl.PSTAT; - g_LastCPUTime = CoreTiming::GetTicks(); + // AI Interrupt + if (tmpAICtrl.AIINT) + { + DEBUG_LOG(AUDIO_INTERFACE, "Clear AIS Interrupt"); + m_Control.AIINT = 0; + } - CoreTiming::RemoveEvent(et_AI); - CoreTiming::ScheduleEvent(GetAIPeriod(), et_AI); - } + // Sample Count Reset + if (tmpAICtrl.SCRESET) + { + DEBUG_LOG(AUDIO_INTERFACE, "Reset AIS sample counter"); + m_SampleCounter = 0; - // AI Interrupt - if (tmpAICtrl.AIINT) - { - DEBUG_LOG(AUDIO_INTERFACE, "Clear AIS Interrupt"); - m_Control.AIINT = 0; - } + g_LastCPUTime = CoreTiming::GetTicks(); + } - // Sample Count Reset - if (tmpAICtrl.SCRESET) - { - DEBUG_LOG(AUDIO_INTERFACE, "Reset AIS sample counter"); - m_SampleCounter = 0; + UpdateInterrupts(); + })); - g_LastCPUTime = CoreTiming::GetTicks(); - } + mmio->Register(base | AI_VOLUME_REGISTER, MMIO::DirectRead(&m_Volume.hex), + MMIO::ComplexWrite([](u32, u32 val) { + m_Volume.hex = val; + g_sound_stream->GetMixer()->SetStreamingVolume(m_Volume.left, m_Volume.right); + })); - UpdateInterrupts(); - }) - ); + mmio->Register(base | AI_SAMPLE_COUNTER, MMIO::ComplexRead([](u32) { + return m_SampleCounter + + static_cast((CoreTiming::GetTicks() - g_LastCPUTime) / + g_CPUCyclesPerSample); + }), + MMIO::ComplexWrite([](u32, u32 val) { + m_SampleCounter = val; + g_LastCPUTime = CoreTiming::GetTicks(); + CoreTiming::RemoveEvent(et_AI); + CoreTiming::ScheduleEvent(GetAIPeriod(), et_AI); + })); - mmio->Register(base | AI_VOLUME_REGISTER, - MMIO::DirectRead(&m_Volume.hex), - MMIO::ComplexWrite([](u32, u32 val) { - m_Volume.hex = val; - g_sound_stream->GetMixer()->SetStreamingVolume(m_Volume.left, m_Volume.right); - }) - ); - - mmio->Register(base | AI_SAMPLE_COUNTER, - MMIO::ComplexRead([](u32) { - return m_SampleCounter + static_cast((CoreTiming::GetTicks() - g_LastCPUTime) / g_CPUCyclesPerSample); - }), - MMIO::ComplexWrite([](u32, u32 val) { - m_SampleCounter = val; - g_LastCPUTime = CoreTiming::GetTicks(); - CoreTiming::RemoveEvent(et_AI); - CoreTiming::ScheduleEvent(GetAIPeriod(), et_AI); - }) - ); - - mmio->Register(base | AI_INTERRUPT_TIMING, - MMIO::DirectRead(&m_InterruptTiming), - MMIO::ComplexWrite([](u32, u32 val) { - DEBUG_LOG(AUDIO_INTERFACE, "AI_INTERRUPT_TIMING=%08x@%08x", val, PowerPC::ppcState.pc); - m_InterruptTiming = val; - CoreTiming::RemoveEvent(et_AI); - CoreTiming::ScheduleEvent(GetAIPeriod(), et_AI); - }) - ); + mmio->Register(base | AI_INTERRUPT_TIMING, MMIO::DirectRead(&m_InterruptTiming), + MMIO::ComplexWrite([](u32, u32 val) { + DEBUG_LOG(AUDIO_INTERFACE, "AI_INTERRUPT_TIMING=%08x@%08x", val, + PowerPC::ppcState.pc); + m_InterruptTiming = val; + CoreTiming::RemoveEvent(et_AI); + CoreTiming::ScheduleEvent(GetAIPeriod(), et_AI); + })); } static void UpdateInterrupts() { - ProcessorInterface::SetInterrupt( - ProcessorInterface::INT_CAUSE_AI, m_Control.AIINT & m_Control.AIINTMSK); + ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_AI, + m_Control.AIINT & m_Control.AIINTMSK); } static void GenerateAudioInterrupt() { - m_Control.AIINT = 1; - UpdateInterrupts(); + m_Control.AIINT = 1; + UpdateInterrupts(); } void GenerateAISInterrupt() { - GenerateAudioInterrupt(); + GenerateAudioInterrupt(); } static void IncreaseSampleCount(const u32 _iAmount) { - if (m_Control.PSTAT) - { - u32 old_SampleCounter = m_SampleCounter + 1; - m_SampleCounter += _iAmount; + if (m_Control.PSTAT) + { + u32 old_SampleCounter = m_SampleCounter + 1; + m_SampleCounter += _iAmount; - if ((m_InterruptTiming - old_SampleCounter) <= (m_SampleCounter - old_SampleCounter)) - { - DEBUG_LOG(AUDIO_INTERFACE, "GenerateAudioInterrupt %08x:%08x @ %08x m_Control.AIINTVLD=%d", m_SampleCounter, m_InterruptTiming, PowerPC::ppcState.pc, m_Control.AIINTVLD); - GenerateAudioInterrupt(); - } - } + if ((m_InterruptTiming - old_SampleCounter) <= (m_SampleCounter - old_SampleCounter)) + { + DEBUG_LOG(AUDIO_INTERFACE, "GenerateAudioInterrupt %08x:%08x @ %08x m_Control.AIINTVLD=%d", + m_SampleCounter, m_InterruptTiming, PowerPC::ppcState.pc, m_Control.AIINTVLD); + GenerateAudioInterrupt(); + } + } } bool IsPlaying() { - return (m_Control.PSTAT == 1); + return (m_Control.PSTAT == 1); } unsigned int GetAIDSampleRate() { - return g_AIDSampleRate; + return g_AIDSampleRate; } static void Update(u64 userdata, s64 cyclesLate) { - if (m_Control.PSTAT) - { - const u64 Diff = CoreTiming::GetTicks() - g_LastCPUTime; - if (Diff > g_CPUCyclesPerSample) - { - const u32 Samples = static_cast(Diff / g_CPUCyclesPerSample); - g_LastCPUTime += Samples * g_CPUCyclesPerSample; - IncreaseSampleCount(Samples); - } - CoreTiming::ScheduleEvent(GetAIPeriod() - cyclesLate, et_AI); - } + if (m_Control.PSTAT) + { + const u64 Diff = CoreTiming::GetTicks() - g_LastCPUTime; + if (Diff > g_CPUCyclesPerSample) + { + const u32 Samples = static_cast(Diff / g_CPUCyclesPerSample); + g_LastCPUTime += Samples * g_CPUCyclesPerSample; + IncreaseSampleCount(Samples); + } + CoreTiming::ScheduleEvent(GetAIPeriod() - cyclesLate, et_AI); + } } int GetAIPeriod() { - u64 period = g_CPUCyclesPerSample * (m_InterruptTiming-m_SampleCounter); - u64 s_period = g_CPUCyclesPerSample * g_AISSampleRate; - if (period == 0) - return static_cast(s_period); - return static_cast(std::min(period, s_period)); + u64 period = g_CPUCyclesPerSample * (m_InterruptTiming - m_SampleCounter); + u64 s_period = g_CPUCyclesPerSample * g_AISSampleRate; + if (period == 0) + return static_cast(s_period); + return static_cast(std::min(period, s_period)); } -} // end of namespace AudioInterface +} // end of namespace AudioInterface diff --git a/Source/Core/Core/HW/AudioInterface.h b/Source/Core/Core/HW/AudioInterface.h index fde7a7ffae..7be8c5e4fd 100644 --- a/Source/Core/Core/HW/AudioInterface.h +++ b/Source/Core/Core/HW/AudioInterface.h @@ -9,14 +9,16 @@ #include "Common/CommonTypes.h" class PointerWrap; -namespace MMIO { class Mapping; } +namespace MMIO +{ +class Mapping; +} namespace AudioInterface { - void Init(); void Shutdown(); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); bool IsPlaying(); void RegisterMMIO(MMIO::Mapping* mmio, u32 base); diff --git a/Source/Core/Core/HW/BBA-TAP/TAP_Apple.cpp b/Source/Core/Core/HW/BBA-TAP/TAP_Apple.cpp index bd0e3e9860..5681f0b507 100644 --- a/Source/Core/Core/HW/BBA-TAP/TAP_Apple.cpp +++ b/Source/Core/Core/HW/BBA-TAP/TAP_Apple.cpp @@ -4,103 +4,103 @@ #include -#include "Common/StringUtil.h" #include "Common/Logging/Log.h" +#include "Common/StringUtil.h" #include "Core/HW/EXI_Device.h" #include "Core/HW/EXI_DeviceEthernet.h" bool CEXIETHERNET::Activate() { - if (IsActivated()) - return true; + if (IsActivated()) + return true; - // Assumes TunTap OS X is installed, and /dev/tun0 is not in use - // and readable / writable by the logged-in user + // Assumes TunTap OS X is installed, and /dev/tun0 is not in use + // and readable / writable by the logged-in user - if ((fd = open("/dev/tap0", O_RDWR)) < 0) - { - ERROR_LOG(SP1, "Couldn't open /dev/tap0, unable to init BBA"); - return false; - } + if ((fd = open("/dev/tap0", O_RDWR)) < 0) + { + ERROR_LOG(SP1, "Couldn't open /dev/tap0, unable to init BBA"); + return false; + } - INFO_LOG(SP1, "BBA initialized."); - return RecvInit(); + INFO_LOG(SP1, "BBA initialized."); + return RecvInit(); } void CEXIETHERNET::Deactivate() { - close(fd); - fd = -1; + close(fd); + fd = -1; - readEnabled.Clear(); - readThreadShutdown.Set(); - if (readThread.joinable()) - readThread.join(); + readEnabled.Clear(); + readThreadShutdown.Set(); + if (readThread.joinable()) + readThread.join(); } bool CEXIETHERNET::IsActivated() { - return fd != -1; + return fd != -1; } bool CEXIETHERNET::SendFrame(u8* frame, u32 size) { - INFO_LOG(SP1, "SendFrame %x\n%s", size, ArrayToString(frame, size, 0x10).c_str()); + INFO_LOG(SP1, "SendFrame %x\n%s", size, ArrayToString(frame, size, 0x10).c_str()); - int writtenBytes = write(fd, frame, size); - if ((u32)writtenBytes != size) - { - ERROR_LOG(SP1, "SendFrame(): expected to write %d bytes, instead wrote %d", - size, writtenBytes); - return false; - } - else - { - SendComplete(); - return true; - } + int writtenBytes = write(fd, frame, size); + if ((u32)writtenBytes != size) + { + ERROR_LOG(SP1, "SendFrame(): expected to write %d bytes, instead wrote %d", size, writtenBytes); + return false; + } + else + { + SendComplete(); + return true; + } } static void ReadThreadHandler(CEXIETHERNET* self) { - while (!self->readThreadShutdown.IsSet()) - { - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(self->fd, &rfds); + while (!self->readThreadShutdown.IsSet()) + { + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(self->fd, &rfds); - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 50000; - if (select(self->fd + 1, &rfds, nullptr, nullptr, &timeout) <= 0) - continue; + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 50000; + if (select(self->fd + 1, &rfds, nullptr, nullptr, &timeout) <= 0) + continue; - int readBytes = read(self->fd, self->mRecvBuffer.get(), BBA_RECV_SIZE); - if (readBytes < 0) - { - ERROR_LOG(SP1, "Failed to read from BBA, err=%d", readBytes); - } - else if (self->readEnabled.IsSet()) - { - INFO_LOG(SP1, "Read data: %s", ArrayToString(self->mRecvBuffer.get(), readBytes, 0x10).c_str()); - self->mRecvBufferLength = readBytes; - self->RecvHandlePacket(); - } - } + int readBytes = read(self->fd, self->mRecvBuffer.get(), BBA_RECV_SIZE); + if (readBytes < 0) + { + ERROR_LOG(SP1, "Failed to read from BBA, err=%d", readBytes); + } + else if (self->readEnabled.IsSet()) + { + INFO_LOG(SP1, "Read data: %s", + ArrayToString(self->mRecvBuffer.get(), readBytes, 0x10).c_str()); + self->mRecvBufferLength = readBytes; + self->RecvHandlePacket(); + } + } } bool CEXIETHERNET::RecvInit() { - readThread = std::thread(ReadThreadHandler, this); - return true; + readThread = std::thread(ReadThreadHandler, this); + return true; } void CEXIETHERNET::RecvStart() { - readEnabled.Set(); + readEnabled.Set(); } void CEXIETHERNET::RecvStop() { - readEnabled.Clear(); + readEnabled.Clear(); } diff --git a/Source/Core/Core/HW/BBA-TAP/TAP_Unix.cpp b/Source/Core/Core/HW/BBA-TAP/TAP_Unix.cpp index a44a8968f7..ad2f67cda0 100644 --- a/Source/Core/Core/HW/BBA-TAP/TAP_Unix.cpp +++ b/Source/Core/Core/HW/BBA-TAP/TAP_Unix.cpp @@ -8,8 +8,8 @@ #include #endif -#include "Common/StringUtil.h" #include "Common/Logging/Log.h" +#include "Common/StringUtil.h" #include "Core/HW/EXI_Device.h" #include "Core/HW/EXI_DeviceEthernet.h" @@ -23,159 +23,159 @@ #include #endif -#define NOTIMPLEMENTED(Name) \ - NOTICE_LOG(SP1, "CEXIETHERNET::%s not implemented for your UNIX", Name); +#define NOTIMPLEMENTED(Name) \ + NOTICE_LOG(SP1, "CEXIETHERNET::%s not implemented for your UNIX", Name); bool CEXIETHERNET::Activate() { #ifdef __linux__ - if (IsActivated()) - return true; + if (IsActivated()) + return true; - // Assumes that there is a TAP device named "Dolphin" preconfigured for - // bridge/NAT/whatever the user wants it configured. + // Assumes that there is a TAP device named "Dolphin" preconfigured for + // bridge/NAT/whatever the user wants it configured. - if ((fd = open("/dev/net/tun", O_RDWR)) < 0) - { - ERROR_LOG(SP1, "Couldn't open /dev/net/tun, unable to init BBA"); - return false; - } + if ((fd = open("/dev/net/tun", O_RDWR)) < 0) + { + ERROR_LOG(SP1, "Couldn't open /dev/net/tun, unable to init BBA"); + return false; + } - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE; + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE; - const int MAX_INTERFACES = 32; - for (int i = 0; i < MAX_INTERFACES; ++i) - { - strncpy(ifr.ifr_name, StringFromFormat("Dolphin%d", i).c_str(), IFNAMSIZ); + const int MAX_INTERFACES = 32; + for (int i = 0; i < MAX_INTERFACES; ++i) + { + strncpy(ifr.ifr_name, StringFromFormat("Dolphin%d", i).c_str(), IFNAMSIZ); - int err; - if ((err = ioctl(fd, TUNSETIFF, (void*)&ifr)) < 0) - { - if (i == (MAX_INTERFACES - 1)) - { - close(fd); - fd = -1; - ERROR_LOG(SP1, "TUNSETIFF failed: Interface=%s err=%d", ifr.ifr_name, err); - return false; - } - } - else - { - break; - } - } - ioctl(fd, TUNSETNOCSUM, 1); + int err; + if ((err = ioctl(fd, TUNSETIFF, (void*)&ifr)) < 0) + { + if (i == (MAX_INTERFACES - 1)) + { + close(fd); + fd = -1; + ERROR_LOG(SP1, "TUNSETIFF failed: Interface=%s err=%d", ifr.ifr_name, err); + return false; + } + } + else + { + break; + } + } + ioctl(fd, TUNSETNOCSUM, 1); - INFO_LOG(SP1, "BBA initialized with associated tap %s", ifr.ifr_name); - return RecvInit(); + INFO_LOG(SP1, "BBA initialized with associated tap %s", ifr.ifr_name); + return RecvInit(); #else - NOTIMPLEMENTED("Activate"); - return false; + NOTIMPLEMENTED("Activate"); + return false; #endif } void CEXIETHERNET::Deactivate() { #ifdef __linux__ - close(fd); - fd = -1; + close(fd); + fd = -1; - readEnabled.Clear(); - readThreadShutdown.Set(); - if (readThread.joinable()) - readThread.join(); + readEnabled.Clear(); + readThreadShutdown.Set(); + if (readThread.joinable()) + readThread.join(); #else - NOTIMPLEMENTED("Deactivate"); + NOTIMPLEMENTED("Deactivate"); #endif } bool CEXIETHERNET::IsActivated() { #ifdef __linux__ - return fd != -1 ? true : false; + return fd != -1 ? true : false; #else - return false; + return false; #endif } bool CEXIETHERNET::SendFrame(u8* frame, u32 size) { #ifdef __linux__ - INFO_LOG(SP1, "SendFrame %x\n%s", size, ArrayToString(frame, size, 0x10).c_str()); + INFO_LOG(SP1, "SendFrame %x\n%s", size, ArrayToString(frame, size, 0x10).c_str()); - int writtenBytes = write(fd, frame, size); - if ((u32)writtenBytes != size) - { - ERROR_LOG(SP1, "SendFrame(): expected to write %d bytes, instead wrote %d", - size, writtenBytes); - return false; - } - else - { - SendComplete(); - return true; - } + int writtenBytes = write(fd, frame, size); + if ((u32)writtenBytes != size) + { + ERROR_LOG(SP1, "SendFrame(): expected to write %d bytes, instead wrote %d", size, writtenBytes); + return false; + } + else + { + SendComplete(); + return true; + } #else - NOTIMPLEMENTED("SendFrame"); - return false; + NOTIMPLEMENTED("SendFrame"); + return false; #endif } static void ReadThreadHandler(CEXIETHERNET* self) { - while (!self->readThreadShutdown.IsSet()) - { - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(self->fd, &rfds); + while (!self->readThreadShutdown.IsSet()) + { + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(self->fd, &rfds); - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 50000; - if (select(self->fd + 1, &rfds, nullptr, nullptr, &timeout) <= 0) - continue; + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 50000; + if (select(self->fd + 1, &rfds, nullptr, nullptr, &timeout) <= 0) + continue; - int readBytes = read(self->fd, self->mRecvBuffer.get(), BBA_RECV_SIZE); - if (readBytes < 0) - { - ERROR_LOG(SP1, "Failed to read from BBA, err=%d", readBytes); - } - else if (self->readEnabled.IsSet()) - { - INFO_LOG(SP1, "Read data: %s", ArrayToString(self->mRecvBuffer.get(), readBytes, 0x10).c_str()); - self->mRecvBufferLength = readBytes; - self->RecvHandlePacket(); - } - } + int readBytes = read(self->fd, self->mRecvBuffer.get(), BBA_RECV_SIZE); + if (readBytes < 0) + { + ERROR_LOG(SP1, "Failed to read from BBA, err=%d", readBytes); + } + else if (self->readEnabled.IsSet()) + { + INFO_LOG(SP1, "Read data: %s", + ArrayToString(self->mRecvBuffer.get(), readBytes, 0x10).c_str()); + self->mRecvBufferLength = readBytes; + self->RecvHandlePacket(); + } + } } bool CEXIETHERNET::RecvInit() { #ifdef __linux__ - readThread = std::thread(ReadThreadHandler, this); - return true; + readThread = std::thread(ReadThreadHandler, this); + return true; #else - NOTIMPLEMENTED("RecvInit"); - return false; + NOTIMPLEMENTED("RecvInit"); + return false; #endif } void CEXIETHERNET::RecvStart() { #ifdef __linux__ - readEnabled.Set(); + readEnabled.Set(); #else - NOTIMPLEMENTED("RecvStart"); + NOTIMPLEMENTED("RecvStart"); #endif } void CEXIETHERNET::RecvStop() { #ifdef __linux__ - readEnabled.Clear(); + readEnabled.Clear(); #else - NOTIMPLEMENTED("RecvStop"); + NOTIMPLEMENTED("RecvStop"); #endif } diff --git a/Source/Core/Core/HW/BBA-TAP/TAP_Win32.cpp b/Source/Core/Core/HW/BBA-TAP/TAP_Win32.cpp index 37b55c212a..a3e16047ab 100644 --- a/Source/Core/Core/HW/BBA-TAP/TAP_Win32.cpp +++ b/Source/Core/Core/HW/BBA-TAP/TAP_Win32.cpp @@ -2,364 +2,364 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/BBA-TAP/TAP_Win32.h" #include "Common/Assert.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "Core/HW/EXI_Device.h" #include "Core/HW/EXI_DeviceEthernet.h" -#include "Core/HW/BBA-TAP/TAP_Win32.h" namespace Win32TAPHelper { - -bool IsTAPDevice(const TCHAR *guid) +bool IsTAPDevice(const TCHAR* guid) { - HKEY netcard_key; - LONG status; - DWORD len; - int i = 0; + HKEY netcard_key; + LONG status; + DWORD len; + int i = 0; - status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADAPTER_KEY, 0, KEY_READ, &netcard_key); + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADAPTER_KEY, 0, KEY_READ, &netcard_key); - if (status != ERROR_SUCCESS) - return false; + if (status != ERROR_SUCCESS) + return false; - for (;;) - { - TCHAR enum_name[256]; - TCHAR unit_string[256]; - HKEY unit_key; - TCHAR component_id_string[] = _T("ComponentId"); - TCHAR component_id[256]; - TCHAR net_cfg_instance_id_string[] = _T("NetCfgInstanceId"); - TCHAR net_cfg_instance_id[256]; - DWORD data_type; + for (;;) + { + TCHAR enum_name[256]; + TCHAR unit_string[256]; + HKEY unit_key; + TCHAR component_id_string[] = _T("ComponentId"); + TCHAR component_id[256]; + TCHAR net_cfg_instance_id_string[] = _T("NetCfgInstanceId"); + TCHAR net_cfg_instance_id[256]; + DWORD data_type; - len = sizeof(enum_name); - status = RegEnumKeyEx(netcard_key, i, enum_name, &len, nullptr, nullptr, nullptr, nullptr); + len = sizeof(enum_name); + status = RegEnumKeyEx(netcard_key, i, enum_name, &len, nullptr, nullptr, nullptr, nullptr); - if (status == ERROR_NO_MORE_ITEMS) - break; - else if (status != ERROR_SUCCESS) - return false; + if (status == ERROR_NO_MORE_ITEMS) + break; + else if (status != ERROR_SUCCESS) + return false; - _sntprintf(unit_string, sizeof(unit_string), _T("%s\\%s"), ADAPTER_KEY, enum_name); + _sntprintf(unit_string, sizeof(unit_string), _T("%s\\%s"), ADAPTER_KEY, enum_name); - status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, unit_string, 0, KEY_READ, &unit_key); + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, unit_string, 0, KEY_READ, &unit_key); - if (status != ERROR_SUCCESS) - { - return false; - } - else - { - len = sizeof(component_id); - status = RegQueryValueEx(unit_key, component_id_string, nullptr, - &data_type, (LPBYTE)component_id, &len); + if (status != ERROR_SUCCESS) + { + return false; + } + else + { + len = sizeof(component_id); + status = RegQueryValueEx(unit_key, component_id_string, nullptr, &data_type, + (LPBYTE)component_id, &len); - if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) - { - len = sizeof(net_cfg_instance_id); - status = RegQueryValueEx(unit_key, net_cfg_instance_id_string, nullptr, - &data_type, (LPBYTE)net_cfg_instance_id, &len); + if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) + { + len = sizeof(net_cfg_instance_id); + status = RegQueryValueEx(unit_key, net_cfg_instance_id_string, nullptr, &data_type, + (LPBYTE)net_cfg_instance_id, &len); - if (status == ERROR_SUCCESS && data_type == REG_SZ) - { - if (!_tcscmp(component_id, TAP_COMPONENT_ID) && - !_tcscmp(net_cfg_instance_id, guid)) - { - RegCloseKey(unit_key); - RegCloseKey(netcard_key); - return true; - } - } - } - RegCloseKey(unit_key); - } - ++i; - } + if (status == ERROR_SUCCESS && data_type == REG_SZ) + { + if (!_tcscmp(component_id, TAP_COMPONENT_ID) && !_tcscmp(net_cfg_instance_id, guid)) + { + RegCloseKey(unit_key); + RegCloseKey(netcard_key); + return true; + } + } + } + RegCloseKey(unit_key); + } + ++i; + } - RegCloseKey(netcard_key); - return false; + RegCloseKey(netcard_key); + return false; } bool GetGUIDs(std::vector>& guids) { - LONG status; - HKEY control_net_key; - DWORD len; - DWORD cSubKeys = 0; + LONG status; + HKEY control_net_key; + DWORD len; + DWORD cSubKeys = 0; - status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ | KEY_QUERY_VALUE, &control_net_key); + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ | KEY_QUERY_VALUE, + &control_net_key); - if (status != ERROR_SUCCESS) - return false; + if (status != ERROR_SUCCESS) + return false; - status = RegQueryInfoKey(control_net_key, nullptr, nullptr, nullptr, &cSubKeys, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + status = RegQueryInfoKey(control_net_key, nullptr, nullptr, nullptr, &cSubKeys, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr); - if (status != ERROR_SUCCESS) - return false; + if (status != ERROR_SUCCESS) + return false; - for (DWORD i = 0; i < cSubKeys; i++) - { - TCHAR enum_name[256]; - TCHAR connection_string[256]; - HKEY connection_key; - TCHAR name_data[256]; - DWORD name_type; - const TCHAR name_string[] = _T("Name"); + for (DWORD i = 0; i < cSubKeys; i++) + { + TCHAR enum_name[256]; + TCHAR connection_string[256]; + HKEY connection_key; + TCHAR name_data[256]; + DWORD name_type; + const TCHAR name_string[] = _T("Name"); - len = sizeof(enum_name); - status = RegEnumKeyEx(control_net_key, i, enum_name, - &len, nullptr, nullptr, nullptr, nullptr); + len = sizeof(enum_name); + status = RegEnumKeyEx(control_net_key, i, enum_name, &len, nullptr, nullptr, nullptr, nullptr); - if (status != ERROR_SUCCESS) - continue; + if (status != ERROR_SUCCESS) + continue; - _sntprintf(connection_string, sizeof(connection_string), - _T("%s\\%s\\Connection"), NETWORK_CONNECTIONS_KEY, enum_name); + _sntprintf(connection_string, sizeof(connection_string), _T("%s\\%s\\Connection"), + NETWORK_CONNECTIONS_KEY, enum_name); - status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, connection_string, - 0, KEY_READ, &connection_key); + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, connection_string, 0, KEY_READ, &connection_key); - if (status == ERROR_SUCCESS) - { - len = sizeof(name_data); - status = RegQueryValueEx(connection_key, name_string, nullptr, - &name_type, (LPBYTE)name_data, &len); + if (status == ERROR_SUCCESS) + { + len = sizeof(name_data); + status = RegQueryValueEx(connection_key, name_string, nullptr, &name_type, (LPBYTE)name_data, + &len); - if (status != ERROR_SUCCESS || name_type != REG_SZ) - { - continue; - } - else - { - if (IsTAPDevice(enum_name)) - { - guids.push_back(enum_name); - } - } + if (status != ERROR_SUCCESS || name_type != REG_SZ) + { + continue; + } + else + { + if (IsTAPDevice(enum_name)) + { + guids.push_back(enum_name); + } + } - RegCloseKey(connection_key); - } - } + RegCloseKey(connection_key); + } + } - RegCloseKey(control_net_key); + RegCloseKey(control_net_key); - return !guids.empty(); + return !guids.empty(); } bool OpenTAP(HANDLE& adapter, const std::basic_string& device_guid) { - auto const device_path = USERMODEDEVICEDIR + device_guid + TAPSUFFIX; + auto const device_path = USERMODEDEVICEDIR + device_guid + TAPSUFFIX; - adapter = CreateFile(device_path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, nullptr); + adapter = CreateFile(device_path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, + FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, nullptr); - if (adapter == INVALID_HANDLE_VALUE) - { - INFO_LOG(SP1, "Failed to open TAP at %s", device_path); - return false; - } - return true; + if (adapter == INVALID_HANDLE_VALUE) + { + INFO_LOG(SP1, "Failed to open TAP at %s", device_path); + return false; + } + return true; } -} // namespace Win32TAPHelper +} // namespace Win32TAPHelper bool CEXIETHERNET::Activate() { - if (IsActivated()) - return true; + if (IsActivated()) + return true; - DWORD len; - std::vector> device_guids; + DWORD len; + std::vector> device_guids; - if (!Win32TAPHelper::GetGUIDs(device_guids)) - { - ERROR_LOG(SP1, "Failed to find a TAP GUID"); - return false; - } + if (!Win32TAPHelper::GetGUIDs(device_guids)) + { + ERROR_LOG(SP1, "Failed to find a TAP GUID"); + return false; + } - for (size_t i = 0; i < device_guids.size(); i++) - { - if (Win32TAPHelper::OpenTAP(mHAdapter, device_guids.at(i))) - { - INFO_LOG(SP1, "OPENED %s", device_guids.at(i).c_str()); - break; - } - } - if (mHAdapter == INVALID_HANDLE_VALUE) - { - PanicAlert("Failed to open any TAP"); - return false; - } + for (size_t i = 0; i < device_guids.size(); i++) + { + if (Win32TAPHelper::OpenTAP(mHAdapter, device_guids.at(i))) + { + INFO_LOG(SP1, "OPENED %s", device_guids.at(i).c_str()); + break; + } + } + if (mHAdapter == INVALID_HANDLE_VALUE) + { + PanicAlert("Failed to open any TAP"); + return false; + } - /* get driver version info */ - ULONG info[3]; - if (DeviceIoControl(mHAdapter, TAP_IOCTL_GET_VERSION, - &info, sizeof(info), &info, sizeof(info), &len, nullptr)) - { - INFO_LOG(SP1, "TAP-Win32 Driver Version %d.%d %s", - info[0], info[1], info[2] ? "(DEBUG)" : ""); - } - if (!(info[0] > TAP_WIN32_MIN_MAJOR || (info[0] == TAP_WIN32_MIN_MAJOR && info[1] >= TAP_WIN32_MIN_MINOR))) - { - PanicAlertT("ERROR: This version of Dolphin requires a TAP-Win32 driver" - " that is at least version %d.%d -- If you recently upgraded your Dolphin" - " distribution, a reboot is probably required at this point to get" - " Windows to see the new driver.", - TAP_WIN32_MIN_MAJOR, TAP_WIN32_MIN_MINOR); - return false; - } + /* get driver version info */ + ULONG info[3]; + if (DeviceIoControl(mHAdapter, TAP_IOCTL_GET_VERSION, &info, sizeof(info), &info, sizeof(info), + &len, nullptr)) + { + INFO_LOG(SP1, "TAP-Win32 Driver Version %d.%d %s", info[0], info[1], info[2] ? "(DEBUG)" : ""); + } + if (!(info[0] > TAP_WIN32_MIN_MAJOR || + (info[0] == TAP_WIN32_MIN_MAJOR && info[1] >= TAP_WIN32_MIN_MINOR))) + { + PanicAlertT("ERROR: This version of Dolphin requires a TAP-Win32 driver" + " that is at least version %d.%d -- If you recently upgraded your Dolphin" + " distribution, a reboot is probably required at this point to get" + " Windows to see the new driver.", + TAP_WIN32_MIN_MAJOR, TAP_WIN32_MIN_MINOR); + return false; + } - /* set driver media status to 'connected' */ - ULONG status = TRUE; - if (!DeviceIoControl(mHAdapter, TAP_IOCTL_SET_MEDIA_STATUS, - &status, sizeof(status), &status, sizeof(status), &len, nullptr)) - { - ERROR_LOG(SP1, "WARNING: The TAP-Win32 driver rejected a" - "TAP_IOCTL_SET_MEDIA_STATUS DeviceIoControl call."); - return false; - } + /* set driver media status to 'connected' */ + ULONG status = TRUE; + if (!DeviceIoControl(mHAdapter, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, + sizeof(status), &len, nullptr)) + { + ERROR_LOG(SP1, "WARNING: The TAP-Win32 driver rejected a" + "TAP_IOCTL_SET_MEDIA_STATUS DeviceIoControl call."); + return false; + } - /* initialize read/write events */ - mReadOverlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); - mWriteOverlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); - if (mReadOverlapped.hEvent == nullptr || mWriteOverlapped.hEvent == nullptr) - return false; + /* initialize read/write events */ + mReadOverlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); + mWriteOverlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); + if (mReadOverlapped.hEvent == nullptr || mWriteOverlapped.hEvent == nullptr) + return false; - mWriteBuffer.reserve(1518); - return RecvInit(); + mWriteBuffer.reserve(1518); + return RecvInit(); } void CEXIETHERNET::Deactivate() { - if (!IsActivated()) - return; + if (!IsActivated()) + return; - // Signal read thread to exit. - readEnabled.Clear(); - readThreadShutdown.Set(); + // Signal read thread to exit. + readEnabled.Clear(); + readThreadShutdown.Set(); - // Cancel any outstanding requests from both this thread (writes), and the read thread. - CancelIoEx(mHAdapter, nullptr); + // Cancel any outstanding requests from both this thread (writes), and the read thread. + CancelIoEx(mHAdapter, nullptr); - // Wait for read thread to exit. - if (readThread.joinable()) - readThread.join(); + // Wait for read thread to exit. + if (readThread.joinable()) + readThread.join(); - // Clean-up handles - CloseHandle(mReadOverlapped.hEvent); - CloseHandle(mWriteOverlapped.hEvent); - CloseHandle(mHAdapter); - mHAdapter = INVALID_HANDLE_VALUE; - memset(&mReadOverlapped, 0, sizeof(mReadOverlapped)); - memset(&mWriteOverlapped, 0, sizeof(mWriteOverlapped)); + // Clean-up handles + CloseHandle(mReadOverlapped.hEvent); + CloseHandle(mWriteOverlapped.hEvent); + CloseHandle(mHAdapter); + mHAdapter = INVALID_HANDLE_VALUE; + memset(&mReadOverlapped, 0, sizeof(mReadOverlapped)); + memset(&mWriteOverlapped, 0, sizeof(mWriteOverlapped)); } bool CEXIETHERNET::IsActivated() { - return mHAdapter != INVALID_HANDLE_VALUE; + return mHAdapter != INVALID_HANDLE_VALUE; } static void ReadThreadHandler(CEXIETHERNET* self) { - while (!self->readThreadShutdown.IsSet()) - { - DWORD transferred; + while (!self->readThreadShutdown.IsSet()) + { + DWORD transferred; - // Read from TAP into internal buffer. - if (ReadFile(self->mHAdapter, self->mRecvBuffer.get(), BBA_RECV_SIZE, &transferred, &self->mReadOverlapped)) - { - // Returning immediately is not likely to happen, but if so, reset the event state manually. - ResetEvent(self->mReadOverlapped.hEvent); - } - else - { - // IO should be pending. - if (GetLastError() != ERROR_IO_PENDING) - { - ERROR_LOG(SP1, "ReadFile failed (err=0x%X)", GetLastError()); - continue; - } + // Read from TAP into internal buffer. + if (ReadFile(self->mHAdapter, self->mRecvBuffer.get(), BBA_RECV_SIZE, &transferred, + &self->mReadOverlapped)) + { + // Returning immediately is not likely to happen, but if so, reset the event state manually. + ResetEvent(self->mReadOverlapped.hEvent); + } + else + { + // IO should be pending. + if (GetLastError() != ERROR_IO_PENDING) + { + ERROR_LOG(SP1, "ReadFile failed (err=0x%X)", GetLastError()); + continue; + } - // Block until the read completes. - if (!GetOverlappedResult(self->mHAdapter, &self->mReadOverlapped, &transferred, TRUE)) - { - // If CancelIO was called, we should exit (the flag will be set). - if (GetLastError() == ERROR_OPERATION_ABORTED) - continue; + // Block until the read completes. + if (!GetOverlappedResult(self->mHAdapter, &self->mReadOverlapped, &transferred, TRUE)) + { + // If CancelIO was called, we should exit (the flag will be set). + if (GetLastError() == ERROR_OPERATION_ABORTED) + continue; - // Something else went wrong. - ERROR_LOG(SP1, "GetOverlappedResult failed (err=0x%X)", GetLastError()); - continue; - } - } + // Something else went wrong. + ERROR_LOG(SP1, "GetOverlappedResult failed (err=0x%X)", GetLastError()); + continue; + } + } - // Copy to BBA buffer, and fire interrupt if enabled. - DEBUG_LOG(SP1, "Received %u bytes\n: %s", transferred, ArrayToString(self->mRecvBuffer.get(), transferred, 0x10).c_str()); - if (self->readEnabled.IsSet()) - { - self->mRecvBufferLength = transferred; - self->RecvHandlePacket(); - } - } + // Copy to BBA buffer, and fire interrupt if enabled. + DEBUG_LOG(SP1, "Received %u bytes\n: %s", transferred, + ArrayToString(self->mRecvBuffer.get(), transferred, 0x10).c_str()); + if (self->readEnabled.IsSet()) + { + self->mRecvBufferLength = transferred; + self->RecvHandlePacket(); + } + } } bool CEXIETHERNET::SendFrame(u8* frame, u32 size) { - DEBUG_LOG(SP1, "SendFrame %u bytes:\n%s", size, ArrayToString(frame, size, 0x10).c_str()); + DEBUG_LOG(SP1, "SendFrame %u bytes:\n%s", size, ArrayToString(frame, size, 0x10).c_str()); - // Check for a background write. We can't issue another one until this one has completed. - DWORD transferred; - if (mWritePending) - { - // Wait for previous write to complete. - if (!GetOverlappedResult(mHAdapter, &mWriteOverlapped, &transferred, TRUE)) - ERROR_LOG(SP1, "GetOverlappedResult failed (err=0x%X)", GetLastError()); - } + // Check for a background write. We can't issue another one until this one has completed. + DWORD transferred; + if (mWritePending) + { + // Wait for previous write to complete. + if (!GetOverlappedResult(mHAdapter, &mWriteOverlapped, &transferred, TRUE)) + ERROR_LOG(SP1, "GetOverlappedResult failed (err=0x%X)", GetLastError()); + } - // Copy to write buffer. - mWriteBuffer.resize(size); - memcpy(mWriteBuffer.data(), frame, size); - mWritePending = true; + // Copy to write buffer. + mWriteBuffer.resize(size); + memcpy(mWriteBuffer.data(), frame, size); + mWritePending = true; - // Queue async write. - if (WriteFile(mHAdapter, mWriteBuffer.data(), size, &transferred, &mWriteOverlapped)) - { - // Returning immediately is not likely to happen, but if so, reset the event state manually. - ResetEvent(mWriteOverlapped.hEvent); - } - else - { - // IO should be pending. - if (GetLastError() != ERROR_IO_PENDING) - { - ERROR_LOG(SP1, "WriteFile failed (err=0x%X)", GetLastError()); - ResetEvent(mWriteOverlapped.hEvent); - mWritePending = false; - return false; - } - } + // Queue async write. + if (WriteFile(mHAdapter, mWriteBuffer.data(), size, &transferred, &mWriteOverlapped)) + { + // Returning immediately is not likely to happen, but if so, reset the event state manually. + ResetEvent(mWriteOverlapped.hEvent); + } + else + { + // IO should be pending. + if (GetLastError() != ERROR_IO_PENDING) + { + ERROR_LOG(SP1, "WriteFile failed (err=0x%X)", GetLastError()); + ResetEvent(mWriteOverlapped.hEvent); + mWritePending = false; + return false; + } + } - // Always report the packet as being sent successfully, even though it might be a lie - SendComplete(); - return true; + // Always report the packet as being sent successfully, even though it might be a lie + SendComplete(); + return true; } bool CEXIETHERNET::RecvInit() { - readThread = std::thread(ReadThreadHandler, this); - return true; + readThread = std::thread(ReadThreadHandler, this); + return true; } void CEXIETHERNET::RecvStart() { - readEnabled.Set(); + readEnabled.Set(); } void CEXIETHERNET::RecvStop() { - readEnabled.Clear(); + readEnabled.Clear(); } diff --git a/Source/Core/Core/HW/BBA-TAP/TAP_Win32.h b/Source/Core/Core/HW/BBA-TAP/TAP_Win32.h index 21cfcc71b8..6cabb27f7a 100644 --- a/Source/Core/Core/HW/BBA-TAP/TAP_Win32.h +++ b/Source/Core/Core/HW/BBA-TAP/TAP_Win32.h @@ -41,42 +41,44 @@ // TAP IOCTLs //============= -#define TAP_CONTROL_CODE(request,method) \ - CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) +#define TAP_CONTROL_CODE(request, method) \ + CTL_CODE(FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) // Present in 8.1 -#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED) -#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED) -#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED) -#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED) -#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED) -#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED) -#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED) -#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED) -#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED) +#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE(1, METHOD_BUFFERED) +#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE(2, METHOD_BUFFERED) +#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE(3, METHOD_BUFFERED) +#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE(4, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE(5, METHOD_BUFFERED) +#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE(6, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE(7, METHOD_BUFFERED) +#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE(8, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE(9, METHOD_BUFFERED) // Added in 8.2 /* obsoletes TAP_IOCTL_CONFIG_POINT_TO_POINT */ -#define TAP_IOCTL_CONFIG_TUN TAP_CONTROL_CODE (10, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_TUN TAP_CONTROL_CODE(10, METHOD_BUFFERED) //================= // Registry keys //================= -#define ADAPTER_KEY _T("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}") +#define ADAPTER_KEY \ + _T("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}") -#define NETWORK_CONNECTIONS_KEY _T("SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}") +#define NETWORK_CONNECTIONS_KEY \ + _T("SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}") //====================== // Filesystem prefixes //====================== #define USERMODEDEVICEDIR _T("\\\\.\\Global\\") -#define SYSDEVICEDIR _T("\\Device\\") -#define USERDEVICEDIR _T("\\DosDevices\\Global\\") -#define TAPSUFFIX _T(".tap") +#define SYSDEVICEDIR _T("\\Device\\") +#define USERDEVICEDIR _T("\\DosDevices\\Global\\") +#define TAPSUFFIX _T(".tap") //========================================================= // TAP_COMPONENT_ID -- This string defines the TAP driver diff --git a/Source/Core/Core/HW/CPU.cpp b/Source/Core/Core/HW/CPU.cpp index e436b90d1b..5a17e5b01e 100644 --- a/Source/Core/Core/HW/CPU.cpp +++ b/Source/Core/Core/HW/CPU.cpp @@ -10,15 +10,14 @@ #include "Common/Event.h" #include "Common/Logging/Log.h" #include "Core/Core.h" -#include "Core/Host.h" #include "Core/HW/CPU.h" #include "Core/HW/Memmap.h" +#include "Core/Host.h" #include "Core/PowerPC/PowerPC.h" #include "VideoCommon/Fifo.h" namespace CPU { - // CPU Thread execution state. // Requires s_state_change_lock to modify the value. // Read access is unsynchronized. @@ -36,157 +35,152 @@ static std::mutex s_stepping_lock; // Primary lock. Protects changing s_state, requesting instruction stepping and // pause-and-locking. -static std::mutex s_state_change_lock; +static std::mutex s_state_change_lock; // When s_state_cpu_thread_active changes to false static std::condition_variable s_state_cpu_idle_cvar; // When s_state changes / s_state_paused_and_locked becomes false (for CPU Thread only) static std::condition_variable s_state_cpu_cvar; -static bool s_state_cpu_thread_active = false; -static bool s_state_paused_and_locked = false; -static bool s_state_system_request_stepping = false; -static bool s_state_cpu_step_instruction = false; -static Common::Event* s_state_cpu_step_instruction_sync = nullptr; +static bool s_state_cpu_thread_active = false; +static bool s_state_paused_and_locked = false; +static bool s_state_system_request_stepping = false; +static bool s_state_cpu_step_instruction = false; +static Common::Event* s_state_cpu_step_instruction_sync = nullptr; void Init(int cpu_core) { - PowerPC::Init(cpu_core); - s_state = CPU_STEPPING; + PowerPC::Init(cpu_core); + s_state = CPU_STEPPING; } void Shutdown() { - Stop(); - PowerPC::Shutdown(); + Stop(); + PowerPC::Shutdown(); } // Requires holding s_state_change_lock static void FlushStepSyncEventLocked() { - if (s_state_cpu_step_instruction_sync) - { - s_state_cpu_step_instruction_sync->Set(); - s_state_cpu_step_instruction_sync = nullptr; - } - s_state_cpu_step_instruction = false; + if (s_state_cpu_step_instruction_sync) + { + s_state_cpu_step_instruction_sync->Set(); + s_state_cpu_step_instruction_sync = nullptr; + } + s_state_cpu_step_instruction = false; } void Run() { - std::unique_lock state_lock(s_state_change_lock); - while (s_state != CPU_POWERDOWN) - { - s_state_cpu_cvar.wait(state_lock, [] { return !s_state_paused_and_locked; }); + std::unique_lock state_lock(s_state_change_lock); + while (s_state != CPU_POWERDOWN) + { + s_state_cpu_cvar.wait(state_lock, [] { return !s_state_paused_and_locked; }); - switch (s_state) - { - case CPU_RUNNING: - s_state_cpu_thread_active = true; - state_lock.unlock(); + switch (s_state) + { + case CPU_RUNNING: + s_state_cpu_thread_active = true; + state_lock.unlock(); - // Adjust PC for JIT when debugging - // SingleStep so that the "continue", "step over" and "step out" debugger functions - // work when the PC is at a breakpoint at the beginning of the block - // If watchpoints are enabled, any instruction could be a breakpoint. - if (PowerPC::GetMode() != PowerPC::MODE_INTERPRETER) - { + // Adjust PC for JIT when debugging + // SingleStep so that the "continue", "step over" and "step out" debugger functions + // work when the PC is at a breakpoint at the beginning of the block + // If watchpoints are enabled, any instruction could be a breakpoint. + if (PowerPC::GetMode() != PowerPC::MODE_INTERPRETER) + { #ifndef ENABLE_MEM_CHECK - if (PowerPC::breakpoints.IsAddressBreakPoint(PC)) + if (PowerPC::breakpoints.IsAddressBreakPoint(PC)) #endif - { - PowerPC::CoreMode old_mode = PowerPC::GetMode(); - PowerPC::SetMode(PowerPC::MODE_INTERPRETER); - PowerPC::SingleStep(); - PowerPC::SetMode(old_mode); - } - } + { + PowerPC::CoreMode old_mode = PowerPC::GetMode(); + PowerPC::SetMode(PowerPC::MODE_INTERPRETER); + PowerPC::SingleStep(); + PowerPC::SetMode(old_mode); + } + } - // Enter a fast runloop - PowerPC::RunLoop(); + // Enter a fast runloop + PowerPC::RunLoop(); - state_lock.lock(); - s_state_cpu_thread_active = false; - s_state_cpu_idle_cvar.notify_all(); - break; + state_lock.lock(); + s_state_cpu_thread_active = false; + s_state_cpu_idle_cvar.notify_all(); + break; - case CPU_STEPPING: - // Wait for step command. - s_state_cpu_cvar.wait(state_lock, [] - { - return s_state_cpu_step_instruction || - s_state != CPU_STEPPING; - }); - if (s_state != CPU_STEPPING) - { - // Signal event if the mode changes. - FlushStepSyncEventLocked(); - continue; - } - if (s_state_paused_and_locked) - continue; + case CPU_STEPPING: + // Wait for step command. + s_state_cpu_cvar.wait(state_lock, + [] { return s_state_cpu_step_instruction || s_state != CPU_STEPPING; }); + if (s_state != CPU_STEPPING) + { + // Signal event if the mode changes. + FlushStepSyncEventLocked(); + continue; + } + if (s_state_paused_and_locked) + continue; - // Do step - s_state_cpu_thread_active = true; - state_lock.unlock(); + // Do step + s_state_cpu_thread_active = true; + state_lock.unlock(); - PowerPC::SingleStep(); + PowerPC::SingleStep(); - state_lock.lock(); - s_state_cpu_thread_active = false; - s_state_cpu_idle_cvar.notify_all(); + state_lock.lock(); + s_state_cpu_thread_active = false; + s_state_cpu_idle_cvar.notify_all(); - // Update disasm dialog - FlushStepSyncEventLocked(); - Host_UpdateDisasmDialog(); - break; + // Update disasm dialog + FlushStepSyncEventLocked(); + Host_UpdateDisasmDialog(); + break; - case CPU_POWERDOWN: - break; - } - } - state_lock.unlock(); - Host_UpdateDisasmDialog(); + case CPU_POWERDOWN: + break; + } + } + state_lock.unlock(); + Host_UpdateDisasmDialog(); } // Requires holding s_state_change_lock static void RunAdjacentSystems(bool running) { - // NOTE: We're assuming these will not try to call Break or EnableStepping. - Fifo::EmulatorState(running); - AudioCommon::ClearAudioBuffer(!running); + // NOTE: We're assuming these will not try to call Break or EnableStepping. + Fifo::EmulatorState(running); + AudioCommon::ClearAudioBuffer(!running); } void Stop() { - // Change state and wait for it to be acknowledged. - // We don't need the stepping lock because CPU_POWERDOWN is a priority state which - // will stick permanently. - std::unique_lock state_lock(s_state_change_lock); - s_state = CPU_POWERDOWN; - s_state_cpu_cvar.notify_one(); - // FIXME: MsgHandler can cause this to deadlock the GUI Thread. Remove the timeout. - bool success = s_state_cpu_idle_cvar.wait_for(state_lock, std::chrono::seconds(5), [] - { - return !s_state_cpu_thread_active; - }); - if (!success) - ERROR_LOG(POWERPC, "CPU Thread failed to acknowledge CPU_POWERDOWN. It may be deadlocked."); - RunAdjacentSystems(false); - FlushStepSyncEventLocked(); + // Change state and wait for it to be acknowledged. + // We don't need the stepping lock because CPU_POWERDOWN is a priority state which + // will stick permanently. + std::unique_lock state_lock(s_state_change_lock); + s_state = CPU_POWERDOWN; + s_state_cpu_cvar.notify_one(); + // FIXME: MsgHandler can cause this to deadlock the GUI Thread. Remove the timeout. + bool success = s_state_cpu_idle_cvar.wait_for(state_lock, std::chrono::seconds(5), + [] { return !s_state_cpu_thread_active; }); + if (!success) + ERROR_LOG(POWERPC, "CPU Thread failed to acknowledge CPU_POWERDOWN. It may be deadlocked."); + RunAdjacentSystems(false); + FlushStepSyncEventLocked(); } bool IsStepping() { - return s_state == CPU_STEPPING; + return s_state == CPU_STEPPING; } State GetState() { - return s_state; + return s_state; } const volatile State* GetStatePtr() { - return &s_state; + return &s_state; } void Reset() @@ -195,142 +189,139 @@ void Reset() void StepOpcode(Common::Event* event) { - std::lock_guard state_lock(s_state_change_lock); - // If we're not stepping then this is pointless - if (!IsStepping()) - { - if (event) - event->Set(); - return; - } + std::lock_guard state_lock(s_state_change_lock); + // If we're not stepping then this is pointless + if (!IsStepping()) + { + if (event) + event->Set(); + return; + } - // Potential race where the previous step has not been serviced yet. - if (s_state_cpu_step_instruction_sync && s_state_cpu_step_instruction_sync != event) - s_state_cpu_step_instruction_sync->Set(); + // Potential race where the previous step has not been serviced yet. + if (s_state_cpu_step_instruction_sync && s_state_cpu_step_instruction_sync != event) + s_state_cpu_step_instruction_sync->Set(); - s_state_cpu_step_instruction = true; - s_state_cpu_step_instruction_sync = event; - s_state_cpu_cvar.notify_one(); + s_state_cpu_step_instruction = true; + s_state_cpu_step_instruction_sync = event; + s_state_cpu_cvar.notify_one(); } // Requires s_state_change_lock static bool SetStateLocked(State s) { - if (s_state == CPU_POWERDOWN) - return false; - s_state = s; - return true; + if (s_state == CPU_POWERDOWN) + return false; + s_state = s; + return true; } void EnableStepping(bool stepping) { - std::lock_guard stepping_lock(s_stepping_lock); - std::unique_lock state_lock(s_state_change_lock); + std::lock_guard stepping_lock(s_stepping_lock); + std::unique_lock state_lock(s_state_change_lock); - if (stepping) - { - SetStateLocked(CPU_STEPPING); + if (stepping) + { + SetStateLocked(CPU_STEPPING); - // Wait for the CPU Thread to leave the run loop - // FIXME: MsgHandler can cause this to deadlock the GUI Thread. Remove the timeout. - bool success = s_state_cpu_idle_cvar.wait_for(state_lock, std::chrono::seconds(5), [] - { - return !s_state_cpu_thread_active; - }); - if (!success) - ERROR_LOG(POWERPC, "Abandoned waiting for CPU Thread! The Core may be deadlocked."); + // Wait for the CPU Thread to leave the run loop + // FIXME: MsgHandler can cause this to deadlock the GUI Thread. Remove the timeout. + bool success = s_state_cpu_idle_cvar.wait_for(state_lock, std::chrono::seconds(5), + [] { return !s_state_cpu_thread_active; }); + if (!success) + ERROR_LOG(POWERPC, "Abandoned waiting for CPU Thread! The Core may be deadlocked."); - RunAdjacentSystems(false); - } - else if (SetStateLocked(CPU_RUNNING)) - { - s_state_cpu_cvar.notify_one(); - RunAdjacentSystems(true); - } + RunAdjacentSystems(false); + } + else if (SetStateLocked(CPU_RUNNING)) + { + s_state_cpu_cvar.notify_one(); + RunAdjacentSystems(true); + } } void Break() { - std::lock_guard state_lock(s_state_change_lock); + std::lock_guard state_lock(s_state_change_lock); - // If another thread is trying to PauseAndLock then we need to remember this - // for later to ignore the unpause_on_unlock. - if (s_state_paused_and_locked) - { - s_state_system_request_stepping = true; - return; - } + // If another thread is trying to PauseAndLock then we need to remember this + // for later to ignore the unpause_on_unlock. + if (s_state_paused_and_locked) + { + s_state_system_request_stepping = true; + return; + } - // We'll deadlock if we synchronize, the CPU may block waiting for our caller to - // finish resulting in the CPU loop never terminating. - SetStateLocked(CPU_STEPPING); - RunAdjacentSystems(false); + // We'll deadlock if we synchronize, the CPU may block waiting for our caller to + // finish resulting in the CPU loop never terminating. + SetStateLocked(CPU_STEPPING); + RunAdjacentSystems(false); } bool PauseAndLock(bool do_lock, bool unpause_on_unlock, bool control_adjacent) { - // NOTE: This is protected by s_stepping_lock. - static bool s_have_fake_cpu_thread = false; - bool was_unpaused = false; + // NOTE: This is protected by s_stepping_lock. + static bool s_have_fake_cpu_thread = false; + bool was_unpaused = false; - if (do_lock) - { - s_stepping_lock.lock(); + if (do_lock) + { + s_stepping_lock.lock(); - std::unique_lock state_lock(s_state_change_lock); - s_state_paused_and_locked = true; + std::unique_lock state_lock(s_state_change_lock); + s_state_paused_and_locked = true; - was_unpaused = s_state == CPU_RUNNING; - SetStateLocked(CPU_STEPPING); + was_unpaused = s_state == CPU_RUNNING; + SetStateLocked(CPU_STEPPING); - // FIXME: MsgHandler can cause this to deadlock the GUI Thread. Remove the timeout. - bool success = s_state_cpu_idle_cvar.wait_for(state_lock, std::chrono::seconds(10), [] - { - return !s_state_cpu_thread_active; - }); - if (!success) - NOTICE_LOG(POWERPC, "Abandoned CPU Thread synchronization in CPU::PauseAndLock! We'll probably crash now."); + // FIXME: MsgHandler can cause this to deadlock the GUI Thread. Remove the timeout. + bool success = s_state_cpu_idle_cvar.wait_for(state_lock, std::chrono::seconds(10), + [] { return !s_state_cpu_thread_active; }); + if (!success) + NOTICE_LOG( + POWERPC, + "Abandoned CPU Thread synchronization in CPU::PauseAndLock! We'll probably crash now."); - if (control_adjacent) - RunAdjacentSystems(false); - state_lock.unlock(); + if (control_adjacent) + RunAdjacentSystems(false); + state_lock.unlock(); - // NOTE: It would make more sense for Core::DeclareAsCPUThread() to keep a - // depth counter instead of being a boolean. - if (!Core::IsCPUThread()) - { - s_have_fake_cpu_thread = true; - Core::DeclareAsCPUThread(); - } - } - else - { - // Only need the stepping lock for this - if (s_have_fake_cpu_thread) - { - s_have_fake_cpu_thread = false; - Core::UndeclareAsCPUThread(); - } + // NOTE: It would make more sense for Core::DeclareAsCPUThread() to keep a + // depth counter instead of being a boolean. + if (!Core::IsCPUThread()) + { + s_have_fake_cpu_thread = true; + Core::DeclareAsCPUThread(); + } + } + else + { + // Only need the stepping lock for this + if (s_have_fake_cpu_thread) + { + s_have_fake_cpu_thread = false; + Core::UndeclareAsCPUThread(); + } - { - std::lock_guard state_lock(s_state_change_lock); - if (s_state_system_request_stepping) - { - s_state_system_request_stepping = false; - } - else if (unpause_on_unlock && SetStateLocked(CPU_RUNNING)) - { - was_unpaused = true; - } - s_state_paused_and_locked = false; - s_state_cpu_cvar.notify_one(); + { + std::lock_guard state_lock(s_state_change_lock); + if (s_state_system_request_stepping) + { + s_state_system_request_stepping = false; + } + else if (unpause_on_unlock && SetStateLocked(CPU_RUNNING)) + { + was_unpaused = true; + } + s_state_paused_and_locked = false; + s_state_cpu_cvar.notify_one(); - if (control_adjacent) - RunAdjacentSystems(s_state == CPU_RUNNING); - } - s_stepping_lock.unlock(); - } - return was_unpaused; + if (control_adjacent) + RunAdjacentSystems(s_state == CPU_RUNNING); + } + s_stepping_lock.unlock(); + } + return was_unpaused; } - } diff --git a/Source/Core/Core/HW/CPU.h b/Source/Core/Core/HW/CPU.h index f9fc6aaca9..390f12f58a 100644 --- a/Source/Core/Core/HW/CPU.h +++ b/Source/Core/Core/HW/CPU.h @@ -4,18 +4,18 @@ #pragma once -namespace Common { - class Event; +namespace Common +{ +class Event; } namespace CPU { - enum State { - CPU_RUNNING = 0, - CPU_STEPPING = 2, - CPU_POWERDOWN = 3 + CPU_RUNNING = 0, + CPU_STEPPING = 2, + CPU_POWERDOWN = 3 }; // Init @@ -69,5 +69,4 @@ const volatile State* GetStatePtr(); // "control_adjacent" causes PauseAndLock to behave like EnableStepping by modifying the // state of the Audio and FIFO subsystems as well. bool PauseAndLock(bool do_lock, bool unpause_on_unlock = true, bool control_adjacent = false); - } diff --git a/Source/Core/Core/HW/DSP.cpp b/Source/Core/Core/HW/DSP.cpp index 7a92c94636..fe37eb3cd2 100644 --- a/Source/Core/Core/HW/DSP.cpp +++ b/Source/Core/Core/HW/DSP.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // AID / AUDIO_DMA controls pushing audio out to the SRC and then the speakers. // The audio DMA pushes audio through a small FIFO 32 bytes at a time, as // needed. @@ -32,113 +31,106 @@ #include "Core/CoreTiming.h" #include "Core/DSPEmulator.h" #include "Core/HW/DSP.h" -#include "Core/HW/Memmap.h" #include "Core/HW/MMIO.h" +#include "Core/HW/Memmap.h" #include "Core/HW/ProcessorInterface.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/PowerPC.h" namespace DSP { - // register offsets enum { - DSP_MAIL_TO_DSP_HI = 0x5000, - DSP_MAIL_TO_DSP_LO = 0x5002, - DSP_MAIL_FROM_DSP_HI = 0x5004, - DSP_MAIL_FROM_DSP_LO = 0x5006, - DSP_CONTROL = 0x500A, - DSP_INTERRUPT_CONTROL = 0x5010, - AR_INFO = 0x5012, // These names are a good guess at best - AR_MODE = 0x5016, // - AR_REFRESH = 0x501a, - AR_DMA_MMADDR_H = 0x5020, - AR_DMA_MMADDR_L = 0x5022, - AR_DMA_ARADDR_H = 0x5024, - AR_DMA_ARADDR_L = 0x5026, - AR_DMA_CNT_H = 0x5028, - AR_DMA_CNT_L = 0x502A, - AUDIO_DMA_START_HI = 0x5030, - AUDIO_DMA_START_LO = 0x5032, - AUDIO_DMA_BLOCKS_LENGTH = 0x5034, // Ever used? - AUDIO_DMA_CONTROL_LEN = 0x5036, - AUDIO_DMA_BLOCKS_LEFT = 0x503A, + DSP_MAIL_TO_DSP_HI = 0x5000, + DSP_MAIL_TO_DSP_LO = 0x5002, + DSP_MAIL_FROM_DSP_HI = 0x5004, + DSP_MAIL_FROM_DSP_LO = 0x5006, + DSP_CONTROL = 0x500A, + DSP_INTERRUPT_CONTROL = 0x5010, + AR_INFO = 0x5012, // These names are a good guess at best + AR_MODE = 0x5016, // + AR_REFRESH = 0x501a, + AR_DMA_MMADDR_H = 0x5020, + AR_DMA_MMADDR_L = 0x5022, + AR_DMA_ARADDR_H = 0x5024, + AR_DMA_ARADDR_L = 0x5026, + AR_DMA_CNT_H = 0x5028, + AR_DMA_CNT_L = 0x502A, + AUDIO_DMA_START_HI = 0x5030, + AUDIO_DMA_START_LO = 0x5032, + AUDIO_DMA_BLOCKS_LENGTH = 0x5034, // Ever used? + AUDIO_DMA_CONTROL_LEN = 0x5036, + AUDIO_DMA_BLOCKS_LEFT = 0x503A, }; // UARAMCount -union UARAMCount -{ - u32 Hex; - struct - { - u32 count : 31; - u32 dir : 1; // 0: MRAM -> ARAM 1: ARAM -> MRAM - }; +union UARAMCount { + u32 Hex; + struct + { + u32 count : 31; + u32 dir : 1; // 0: MRAM -> ARAM 1: ARAM -> MRAM + }; }; // Blocks are 32 bytes. -union UAudioDMAControl -{ - u16 Hex; - struct - { - u16 NumBlocks : 15; - u16 Enable : 1; - }; +union UAudioDMAControl { + u16 Hex; + struct + { + u16 NumBlocks : 15; + u16 Enable : 1; + }; - UAudioDMAControl(u16 _Hex = 0) : Hex(_Hex) - {} + UAudioDMAControl(u16 _Hex = 0) : Hex(_Hex) {} }; // AudioDMA struct AudioDMA { - u32 current_source_address; - u16 remaining_blocks_count; - u32 SourceAddress; - UAudioDMAControl AudioDMAControl; + u32 current_source_address; + u16 remaining_blocks_count; + u32 SourceAddress; + UAudioDMAControl AudioDMAControl; - AudioDMA(): - current_source_address(0), - remaining_blocks_count(0), - SourceAddress(0), - AudioDMAControl(0) - { - } + AudioDMA() + : current_source_address(0), remaining_blocks_count(0), SourceAddress(0), AudioDMAControl(0) + { + } }; // ARAM_DMA struct ARAM_DMA { - u32 MMAddr; - u32 ARAddr; - UARAMCount Cnt; + u32 MMAddr; + u32 ARAddr; + UARAMCount Cnt; - ARAM_DMA() - { - MMAddr = 0; - ARAddr = 0; - Cnt.Hex = 0; - } + ARAM_DMA() + { + MMAddr = 0; + ARAddr = 0; + Cnt.Hex = 0; + } }; // So we may abstract GC/Wii differences a little struct ARAMInfo { - bool wii_mode; // Wii EXRAM is managed in Memory:: so we need to skip statesaving, etc - u32 size; - u32 mask; - u8* ptr; // aka audio ram, auxiliary ram, MEM2, EXRAM, etc... + bool wii_mode; // Wii EXRAM is managed in Memory:: so we need to skip statesaving, etc + u32 size; + u32 mask; + u8* ptr; // aka audio ram, auxiliary ram, MEM2, EXRAM, etc... - // Default to GC mode - ARAMInfo() - { - wii_mode = false; - size = ARAM_SIZE; - mask = ARAM_MASK; - ptr = nullptr; - } + // Default to GC mode + ARAMInfo() + { + wii_mode = false; + size = ARAM_SIZE; + mask = ARAM_MASK; + ptr = nullptr; + } }; // STATE_TO_SAVE @@ -150,15 +142,14 @@ static u32 last_aram_dma_count; static bool instant_dma; UDSPControl g_dspState; -union ARAM_Info -{ - u16 Hex; - struct - { - u16 size : 6; - u16 unk : 1; - u16 : 9; - }; +union ARAM_Info { + u16 Hex; + struct + { + u16 size : 6; + u16 unk : 1; + u16 : 9; + }; }; static ARAM_Info g_ARAM_Info; // Contains bitfields for some stuff we don't care about (and nothing ever reads): @@ -173,27 +164,26 @@ static int dsp_slice = 0; static bool dsp_is_lle = false; // time given to LLE DSP on every read of the high bits in a mailbox -static const int DSP_MAIL_SLICE=72; +static const int DSP_MAIL_SLICE = 72; -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - if (!g_ARAM.wii_mode) - p.DoArray(g_ARAM.ptr, g_ARAM.size); - p.DoPOD(g_dspState); - p.DoPOD(g_audioDMA); - p.DoPOD(g_arDMA); - p.Do(g_ARAM_Info); - p.Do(g_AR_MODE); - p.Do(g_AR_REFRESH); - p.Do(dsp_slice); - p.Do(last_mmaddr); - p.Do(last_aram_dma_count); - p.Do(instant_dma); + if (!g_ARAM.wii_mode) + p.DoArray(g_ARAM.ptr, g_ARAM.size); + p.DoPOD(g_dspState); + p.DoPOD(g_audioDMA); + p.DoPOD(g_arDMA); + p.Do(g_ARAM_Info); + p.Do(g_AR_MODE); + p.Do(g_AR_REFRESH); + p.Do(dsp_slice); + p.Do(last_mmaddr); + p.Do(last_aram_dma_count); + p.Do(instant_dma); - dsp_emulator->DoState(p); + dsp_emulator->DoState(p); } - static void UpdateInterrupts(); static void Do_ARAM_DMA(); static void GenerateDSPInterrupt(u64 DSPIntType, s64 cyclesLate = 0); @@ -203,455 +193,447 @@ static int et_CompleteARAM; static void CompleteARAM(u64 userdata, s64 cyclesLate) { - g_dspState.DMAState = 0; - GenerateDSPInterrupt(INT_ARAM); + g_dspState.DMAState = 0; + GenerateDSPInterrupt(INT_ARAM); } void EnableInstantDMA() { - CoreTiming::RemoveEvent(et_CompleteARAM); - CompleteARAM(0, 0); - instant_dma = true; - ERROR_LOG(DSPINTERFACE, "Enabling Instant ARAM DMA hack"); + CoreTiming::RemoveEvent(et_CompleteARAM); + CompleteARAM(0, 0); + instant_dma = true; + ERROR_LOG(DSPINTERFACE, "Enabling Instant ARAM DMA hack"); } void FlushInstantDMA(u32 address) { - u64 dma_in_progress = DSP::DMAInProgress(); - if (dma_in_progress != 0) - { - u32 start_addr = (dma_in_progress >> 32) & Memory::RAM_MASK; - u32 end_addr = (dma_in_progress & Memory::RAM_MASK) & 0xffffffff; - u32 invalidated_addr = (address & Memory::RAM_MASK) & ~0x1f; + u64 dma_in_progress = DSP::DMAInProgress(); + if (dma_in_progress != 0) + { + u32 start_addr = (dma_in_progress >> 32) & Memory::RAM_MASK; + u32 end_addr = (dma_in_progress & Memory::RAM_MASK) & 0xffffffff; + u32 invalidated_addr = (address & Memory::RAM_MASK) & ~0x1f; - if (invalidated_addr >= start_addr && invalidated_addr <= end_addr) - { - DSP::EnableInstantDMA(); - } - } + if (invalidated_addr >= start_addr && invalidated_addr <= end_addr) + { + DSP::EnableInstantDMA(); + } + } } DSPEmulator* GetDSPEmulator() { - return dsp_emulator.get(); + return dsp_emulator.get(); } void Init(bool hle) { - dsp_emulator = CreateDSPEmulator(hle); - dsp_is_lle = dsp_emulator->IsLLE(); + dsp_emulator = CreateDSPEmulator(hle); + dsp_is_lle = dsp_emulator->IsLLE(); - if (SConfig::GetInstance().bWii) - { - g_ARAM.wii_mode = true; - g_ARAM.size = Memory::EXRAM_SIZE; - g_ARAM.mask = Memory::EXRAM_MASK; - g_ARAM.ptr = Memory::m_pEXRAM; - } - else - { - // On the GameCube, ARAM is accessible only through this interface. - g_ARAM.wii_mode = false; - g_ARAM.size = ARAM_SIZE; - g_ARAM.mask = ARAM_MASK; - g_ARAM.ptr = (u8 *)AllocateMemoryPages(g_ARAM.size); - } + if (SConfig::GetInstance().bWii) + { + g_ARAM.wii_mode = true; + g_ARAM.size = Memory::EXRAM_SIZE; + g_ARAM.mask = Memory::EXRAM_MASK; + g_ARAM.ptr = Memory::m_pEXRAM; + } + else + { + // On the GameCube, ARAM is accessible only through this interface. + g_ARAM.wii_mode = false; + g_ARAM.size = ARAM_SIZE; + g_ARAM.mask = ARAM_MASK; + g_ARAM.ptr = (u8*)AllocateMemoryPages(g_ARAM.size); + } - memset(&g_audioDMA, 0, sizeof(g_audioDMA)); - memset(&g_arDMA, 0, sizeof(g_arDMA)); + memset(&g_audioDMA, 0, sizeof(g_audioDMA)); + memset(&g_arDMA, 0, sizeof(g_arDMA)); - g_dspState.Hex = 0; - g_dspState.DSPHalt = 1; + g_dspState.Hex = 0; + g_dspState.DSPHalt = 1; - g_ARAM_Info.Hex = 0; - g_AR_MODE = 1; // ARAM Controller has init'd - g_AR_REFRESH = 156; // 156MHz + g_ARAM_Info.Hex = 0; + g_AR_MODE = 1; // ARAM Controller has init'd + g_AR_REFRESH = 156; // 156MHz - instant_dma = false; + instant_dma = false; - last_aram_dma_count = 0; - last_mmaddr = 0; + last_aram_dma_count = 0; + last_mmaddr = 0; - et_GenerateDSPInterrupt = CoreTiming::RegisterEvent("DSPint", GenerateDSPInterrupt); - et_CompleteARAM = CoreTiming::RegisterEvent("ARAMint", CompleteARAM); + et_GenerateDSPInterrupt = CoreTiming::RegisterEvent("DSPint", GenerateDSPInterrupt); + et_CompleteARAM = CoreTiming::RegisterEvent("ARAMint", CompleteARAM); } void Shutdown() { - if (!g_ARAM.wii_mode) - { - FreeMemoryPages(g_ARAM.ptr, g_ARAM.size); - g_ARAM.ptr = nullptr; - } + if (!g_ARAM.wii_mode) + { + FreeMemoryPages(g_ARAM.ptr, g_ARAM.size); + g_ARAM.ptr = nullptr; + } - dsp_emulator->Shutdown(); - dsp_emulator.reset(); + dsp_emulator->Shutdown(); + dsp_emulator.reset(); } void RegisterMMIO(MMIO::Mapping* mmio, u32 base) { - // Declare all the boilerplate direct MMIOs. - struct - { - u32 addr; - u16* ptr; - bool align_writes_on_32_bytes; - } directly_mapped_vars[] = { - { AR_INFO, &g_ARAM_Info.Hex }, - { AR_MODE, &g_AR_MODE }, - { AR_REFRESH, &g_AR_REFRESH }, - { AR_DMA_MMADDR_H, MMIO::Utils::HighPart(&g_arDMA.MMAddr) }, - { AR_DMA_MMADDR_L, MMIO::Utils::LowPart(&g_arDMA.MMAddr), true }, - { AR_DMA_ARADDR_H, MMIO::Utils::HighPart(&g_arDMA.ARAddr) }, - { AR_DMA_ARADDR_L, MMIO::Utils::LowPart(&g_arDMA.ARAddr), true }, - { AR_DMA_CNT_H, MMIO::Utils::HighPart(&g_arDMA.Cnt.Hex) }, - // AR_DMA_CNT_L triggers DMA - { AUDIO_DMA_START_HI, MMIO::Utils::HighPart(&g_audioDMA.SourceAddress) }, - { AUDIO_DMA_START_LO, MMIO::Utils::LowPart(&g_audioDMA.SourceAddress) }, - }; - for (auto& mapped_var : directly_mapped_vars) - { - u16 write_mask = mapped_var.align_writes_on_32_bytes ? 0xFFE0 : 0xFFFF; - mmio->Register(base | mapped_var.addr, - MMIO::DirectRead(mapped_var.ptr), - MMIO::DirectWrite(mapped_var.ptr, write_mask) - ); - } + // Declare all the boilerplate direct MMIOs. + struct + { + u32 addr; + u16* ptr; + bool align_writes_on_32_bytes; + } directly_mapped_vars[] = { + {AR_INFO, &g_ARAM_Info.Hex}, + {AR_MODE, &g_AR_MODE}, + {AR_REFRESH, &g_AR_REFRESH}, + {AR_DMA_MMADDR_H, MMIO::Utils::HighPart(&g_arDMA.MMAddr)}, + {AR_DMA_MMADDR_L, MMIO::Utils::LowPart(&g_arDMA.MMAddr), true}, + {AR_DMA_ARADDR_H, MMIO::Utils::HighPart(&g_arDMA.ARAddr)}, + {AR_DMA_ARADDR_L, MMIO::Utils::LowPart(&g_arDMA.ARAddr), true}, + {AR_DMA_CNT_H, MMIO::Utils::HighPart(&g_arDMA.Cnt.Hex)}, + // AR_DMA_CNT_L triggers DMA + {AUDIO_DMA_START_HI, MMIO::Utils::HighPart(&g_audioDMA.SourceAddress)}, + {AUDIO_DMA_START_LO, MMIO::Utils::LowPart(&g_audioDMA.SourceAddress)}, + }; + for (auto& mapped_var : directly_mapped_vars) + { + u16 write_mask = mapped_var.align_writes_on_32_bytes ? 0xFFE0 : 0xFFFF; + mmio->Register(base | mapped_var.addr, MMIO::DirectRead(mapped_var.ptr), + MMIO::DirectWrite(mapped_var.ptr, write_mask)); + } - // DSP mail MMIOs call DSP emulator functions to get results or write data. - mmio->Register(base | DSP_MAIL_TO_DSP_HI, - MMIO::ComplexRead([](u32) { - if (dsp_slice > DSP_MAIL_SLICE && dsp_is_lle) - { - dsp_emulator->DSP_Update(DSP_MAIL_SLICE); - dsp_slice -= DSP_MAIL_SLICE; - } - return dsp_emulator->DSP_ReadMailBoxHigh(true); - }), - MMIO::ComplexWrite([](u32, u16 val) { - dsp_emulator->DSP_WriteMailBoxHigh(true, val); - }) - ); - mmio->Register(base | DSP_MAIL_TO_DSP_LO, - MMIO::ComplexRead([](u32) { - return dsp_emulator->DSP_ReadMailBoxLow(true); - }), - MMIO::ComplexWrite([](u32, u16 val) { - dsp_emulator->DSP_WriteMailBoxLow(true, val); - }) - ); - mmio->Register(base | DSP_MAIL_FROM_DSP_HI, - MMIO::ComplexRead([](u32) { - if (dsp_slice > DSP_MAIL_SLICE && dsp_is_lle) - { - dsp_emulator->DSP_Update(DSP_MAIL_SLICE); - dsp_slice -= DSP_MAIL_SLICE; - } - return dsp_emulator->DSP_ReadMailBoxHigh(false); - }), - MMIO::InvalidWrite() - ); - mmio->Register(base | DSP_MAIL_FROM_DSP_LO, - MMIO::ComplexRead([](u32) { - return dsp_emulator->DSP_ReadMailBoxLow(false); - }), - MMIO::InvalidWrite() - ); + // DSP mail MMIOs call DSP emulator functions to get results or write data. + mmio->Register( + base | DSP_MAIL_TO_DSP_HI, MMIO::ComplexRead([](u32) { + if (dsp_slice > DSP_MAIL_SLICE && dsp_is_lle) + { + dsp_emulator->DSP_Update(DSP_MAIL_SLICE); + dsp_slice -= DSP_MAIL_SLICE; + } + return dsp_emulator->DSP_ReadMailBoxHigh(true); + }), + MMIO::ComplexWrite([](u32, u16 val) { dsp_emulator->DSP_WriteMailBoxHigh(true, val); })); + mmio->Register( + base | DSP_MAIL_TO_DSP_LO, + MMIO::ComplexRead([](u32) { return dsp_emulator->DSP_ReadMailBoxLow(true); }), + MMIO::ComplexWrite([](u32, u16 val) { dsp_emulator->DSP_WriteMailBoxLow(true, val); })); + mmio->Register(base | DSP_MAIL_FROM_DSP_HI, MMIO::ComplexRead([](u32) { + if (dsp_slice > DSP_MAIL_SLICE && dsp_is_lle) + { + dsp_emulator->DSP_Update(DSP_MAIL_SLICE); + dsp_slice -= DSP_MAIL_SLICE; + } + return dsp_emulator->DSP_ReadMailBoxHigh(false); + }), + MMIO::InvalidWrite()); + mmio->Register(base | DSP_MAIL_FROM_DSP_LO, MMIO::ComplexRead([](u32) { + return dsp_emulator->DSP_ReadMailBoxLow(false); + }), + MMIO::InvalidWrite()); - mmio->Register(base | DSP_CONTROL, - MMIO::ComplexRead([](u32) { - return (g_dspState.Hex & ~DSP_CONTROL_MASK) | - (dsp_emulator->DSP_ReadControlRegister() & DSP_CONTROL_MASK); - }), - MMIO::ComplexWrite([](u32, u16 val) { - UDSPControl tmpControl; - tmpControl.Hex = (val & ~DSP_CONTROL_MASK) | - (dsp_emulator->DSP_WriteControlRegister(val) & DSP_CONTROL_MASK); + mmio->Register( + base | DSP_CONTROL, MMIO::ComplexRead([](u32) { + return (g_dspState.Hex & ~DSP_CONTROL_MASK) | + (dsp_emulator->DSP_ReadControlRegister() & DSP_CONTROL_MASK); + }), + MMIO::ComplexWrite([](u32, u16 val) { + UDSPControl tmpControl; + tmpControl.Hex = (val & ~DSP_CONTROL_MASK) | + (dsp_emulator->DSP_WriteControlRegister(val) & DSP_CONTROL_MASK); - // Not really sure if this is correct, but it works... - // Kind of a hack because DSP_CONTROL_MASK should make this bit - // only viewable to DSP emulator - if (val & 1 /*DSPReset*/) - { - g_audioDMA.AudioDMAControl.Hex = 0; - } + // Not really sure if this is correct, but it works... + // Kind of a hack because DSP_CONTROL_MASK should make this bit + // only viewable to DSP emulator + if (val & 1 /*DSPReset*/) + { + g_audioDMA.AudioDMAControl.Hex = 0; + } - // Update DSP related flags - g_dspState.DSPReset = tmpControl.DSPReset; - g_dspState.DSPAssertInt = tmpControl.DSPAssertInt; - g_dspState.DSPHalt = tmpControl.DSPHalt; - g_dspState.DSPInit = tmpControl.DSPInit; + // Update DSP related flags + g_dspState.DSPReset = tmpControl.DSPReset; + g_dspState.DSPAssertInt = tmpControl.DSPAssertInt; + g_dspState.DSPHalt = tmpControl.DSPHalt; + g_dspState.DSPInit = tmpControl.DSPInit; - // Interrupt (mask) - g_dspState.AID_mask = tmpControl.AID_mask; - g_dspState.ARAM_mask = tmpControl.ARAM_mask; - g_dspState.DSP_mask = tmpControl.DSP_mask; + // Interrupt (mask) + g_dspState.AID_mask = tmpControl.AID_mask; + g_dspState.ARAM_mask = tmpControl.ARAM_mask; + g_dspState.DSP_mask = tmpControl.DSP_mask; - // Interrupt - if (tmpControl.AID) g_dspState.AID = 0; - if (tmpControl.ARAM) g_dspState.ARAM = 0; - if (tmpControl.DSP) g_dspState.DSP = 0; + // Interrupt + if (tmpControl.AID) + g_dspState.AID = 0; + if (tmpControl.ARAM) + g_dspState.ARAM = 0; + if (tmpControl.DSP) + g_dspState.DSP = 0; - // unknown - g_dspState.DSPInitCode = tmpControl.DSPInitCode; - g_dspState.pad = tmpControl.pad; - if (g_dspState.pad != 0) - { - PanicAlert("DSPInterface (w) g_dspState (CC00500A) gets a value with junk in the padding %08x", val); - } + // unknown + g_dspState.DSPInitCode = tmpControl.DSPInitCode; + g_dspState.pad = tmpControl.pad; + if (g_dspState.pad != 0) + { + PanicAlert( + "DSPInterface (w) g_dspState (CC00500A) gets a value with junk in the padding %08x", + val); + } - UpdateInterrupts(); - }) - ); + UpdateInterrupts(); + })); - // ARAM MMIO controlling the DMA start. - mmio->Register(base | AR_DMA_CNT_L, - MMIO::DirectRead(MMIO::Utils::LowPart(&g_arDMA.Cnt.Hex)), - MMIO::ComplexWrite([](u32, u16 val) { - g_arDMA.Cnt.Hex = (g_arDMA.Cnt.Hex & 0xFFFF0000) | (val & ~31); - Do_ARAM_DMA(); - }) - ); + // ARAM MMIO controlling the DMA start. + mmio->Register(base | AR_DMA_CNT_L, MMIO::DirectRead(MMIO::Utils::LowPart(&g_arDMA.Cnt.Hex)), + MMIO::ComplexWrite([](u32, u16 val) { + g_arDMA.Cnt.Hex = (g_arDMA.Cnt.Hex & 0xFFFF0000) | (val & ~31); + Do_ARAM_DMA(); + })); - // Audio DMA MMIO controlling the DMA start. - mmio->Register(base | AUDIO_DMA_CONTROL_LEN, - MMIO::DirectRead(&g_audioDMA.AudioDMAControl.Hex), - MMIO::ComplexWrite([](u32, u16 val) { - bool already_enabled = g_audioDMA.AudioDMAControl.Enable; - g_audioDMA.AudioDMAControl.Hex = val; + // Audio DMA MMIO controlling the DMA start. + mmio->Register( + base | AUDIO_DMA_CONTROL_LEN, MMIO::DirectRead(&g_audioDMA.AudioDMAControl.Hex), + MMIO::ComplexWrite([](u32, u16 val) { + bool already_enabled = g_audioDMA.AudioDMAControl.Enable; + g_audioDMA.AudioDMAControl.Hex = val; - // Only load new values if were not already doing a DMA transfer, - // otherwise just let the new values be autoloaded in when the - // current transfer ends. - if (!already_enabled && g_audioDMA.AudioDMAControl.Enable) - { - g_audioDMA.current_source_address = g_audioDMA.SourceAddress; - g_audioDMA.remaining_blocks_count = g_audioDMA.AudioDMAControl.NumBlocks; + // Only load new values if were not already doing a DMA transfer, + // otherwise just let the new values be autoloaded in when the + // current transfer ends. + if (!already_enabled && g_audioDMA.AudioDMAControl.Enable) + { + g_audioDMA.current_source_address = g_audioDMA.SourceAddress; + g_audioDMA.remaining_blocks_count = g_audioDMA.AudioDMAControl.NumBlocks; - INFO_LOG(AUDIO_INTERFACE, "Audio DMA configured: %i blocks from 0x%08x", - g_audioDMA.AudioDMAControl.NumBlocks, g_audioDMA.SourceAddress); + INFO_LOG(AUDIO_INTERFACE, "Audio DMA configured: %i blocks from 0x%08x", + g_audioDMA.AudioDMAControl.NumBlocks, g_audioDMA.SourceAddress); - // We make the samples ready as soon as possible - void *address = Memory::GetPointer(g_audioDMA.SourceAddress); - AudioCommon::SendAIBuffer((short*)address, g_audioDMA.AudioDMAControl.NumBlocks * 8); + // We make the samples ready as soon as possible + void* address = Memory::GetPointer(g_audioDMA.SourceAddress); + AudioCommon::SendAIBuffer((short*)address, g_audioDMA.AudioDMAControl.NumBlocks * 8); - // TODO: need hardware tests for the timing of this interrupt. - // Sky Crawlers crashes at boot if this is scheduled less than 87 cycles in the future. - // Other Namco games crash too, see issue 9509. For now we will just push it to 200 cycles - CoreTiming::ScheduleEvent(200, et_GenerateDSPInterrupt, INT_AID); - } - }) - ); + // TODO: need hardware tests for the timing of this interrupt. + // Sky Crawlers crashes at boot if this is scheduled less than 87 cycles in the future. + // Other Namco games crash too, see issue 9509. For now we will just push it to 200 cycles + CoreTiming::ScheduleEvent(200, et_GenerateDSPInterrupt, INT_AID); + } + })); - // Audio DMA blocks remaining is invalid to write to, and requires logic on - // the read side. - mmio->Register(base | AUDIO_DMA_BLOCKS_LEFT, - MMIO::ComplexRead([](u32) { - // remaining_blocks_count is zero-based. DreamMix World Fighters will hang if it never reaches zero. - return (g_audioDMA.remaining_blocks_count > 0 ? g_audioDMA.remaining_blocks_count - 1 : 0); - }), - MMIO::InvalidWrite() - ); + // Audio DMA blocks remaining is invalid to write to, and requires logic on + // the read side. + mmio->Register( + base | AUDIO_DMA_BLOCKS_LEFT, MMIO::ComplexRead([](u32) { + // remaining_blocks_count is zero-based. DreamMix World Fighters will hang if it never + // reaches zero. + return (g_audioDMA.remaining_blocks_count > 0 ? g_audioDMA.remaining_blocks_count - 1 : 0); + }), + MMIO::InvalidWrite()); - // 32 bit reads/writes are a combination of two 16 bit accesses. - for (int i = 0; i < 0x1000; i += 4) - { - mmio->Register(base | i, - MMIO::ReadToSmaller(mmio, base | i, base | (i + 2)), - MMIO::WriteToSmaller(mmio, base | i, base | (i + 2)) - ); - } + // 32 bit reads/writes are a combination of two 16 bit accesses. + for (int i = 0; i < 0x1000; i += 4) + { + mmio->Register(base | i, MMIO::ReadToSmaller(mmio, base | i, base | (i + 2)), + MMIO::WriteToSmaller(mmio, base | i, base | (i + 2))); + } } // UpdateInterrupts static void UpdateInterrupts() { - // For each interrupt bit in DSP_CONTROL, the interrupt enablemask is the bit directly - // to the left of it. By doing: - // (DSP_CONTROL>>1) & DSP_CONTROL & MASK_OF_ALL_INTERRUPT_BITS - // We can check if any of the interrupts are enabled and active, all at once. - bool ints_set = (((g_dspState.Hex >> 1) & g_dspState.Hex & (INT_DSP | INT_ARAM | INT_AID)) != 0); + // For each interrupt bit in DSP_CONTROL, the interrupt enablemask is the bit directly + // to the left of it. By doing: + // (DSP_CONTROL>>1) & DSP_CONTROL & MASK_OF_ALL_INTERRUPT_BITS + // We can check if any of the interrupts are enabled and active, all at once. + bool ints_set = (((g_dspState.Hex >> 1) & g_dspState.Hex & (INT_DSP | INT_ARAM | INT_AID)) != 0); - ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_DSP, ints_set); + ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_DSP, ints_set); } static void GenerateDSPInterrupt(u64 DSPIntType, s64 cyclesLate) { - // The INT_* enumeration members have values that reflect their bit positions in - // DSP_CONTROL - we mask by (INT_DSP | INT_ARAM | INT_AID) just to ensure people - // don't call this with bogus values. - g_dspState.Hex |= (DSPIntType & (INT_DSP | INT_ARAM | INT_AID)); + // The INT_* enumeration members have values that reflect their bit positions in + // DSP_CONTROL - we mask by (INT_DSP | INT_ARAM | INT_AID) just to ensure people + // don't call this with bogus values. + g_dspState.Hex |= (DSPIntType & (INT_DSP | INT_ARAM | INT_AID)); - UpdateInterrupts(); + UpdateInterrupts(); } // CALLED FROM DSP EMULATOR, POSSIBLY THREADED void GenerateDSPInterruptFromDSPEmu(DSPInterruptType type) { - // TODO: Maybe rethink this? ScheduleEvent_Threadsafe_Immediate has unpredictable timing. - CoreTiming::ScheduleEvent_Threadsafe_Immediate(et_GenerateDSPInterrupt, type); + // TODO: Maybe rethink this? ScheduleEvent_Threadsafe_Immediate has unpredictable timing. + CoreTiming::ScheduleEvent_Threadsafe_Immediate(et_GenerateDSPInterrupt, type); } // called whenever SystemTimers thinks the DSP deserves a few more cycles void UpdateDSPSlice(int cycles) { - if (dsp_is_lle) - { - // use up the rest of the slice(if any) - dsp_emulator->DSP_Update(dsp_slice); - dsp_slice %= 6; - // note the new budget - dsp_slice += cycles; - } - else - { - dsp_emulator->DSP_Update(cycles); - } + if (dsp_is_lle) + { + // use up the rest of the slice(if any) + dsp_emulator->DSP_Update(dsp_slice); + dsp_slice %= 6; + // note the new budget + dsp_slice += cycles; + } + else + { + dsp_emulator->DSP_Update(cycles); + } } // This happens at 4 khz, since 32 bytes at 4khz = 4 bytes at 32 khz (16bit stereo pcm) void UpdateAudioDMA() { - static short zero_samples[8*2] = { 0 }; - if (g_audioDMA.AudioDMAControl.Enable) - { - // Read audio at g_audioDMA.current_source_address in RAM and push onto an - // external audio fifo in the emulator, to be mixed with the disc - // streaming output. + static short zero_samples[8 * 2] = {0}; + if (g_audioDMA.AudioDMAControl.Enable) + { + // Read audio at g_audioDMA.current_source_address in RAM and push onto an + // external audio fifo in the emulator, to be mixed with the disc + // streaming output. - if (g_audioDMA.remaining_blocks_count != 0) - { - g_audioDMA.remaining_blocks_count--; - g_audioDMA.current_source_address += 32; - } + if (g_audioDMA.remaining_blocks_count != 0) + { + g_audioDMA.remaining_blocks_count--; + g_audioDMA.current_source_address += 32; + } - if (g_audioDMA.remaining_blocks_count == 0) - { - g_audioDMA.current_source_address = g_audioDMA.SourceAddress; - g_audioDMA.remaining_blocks_count = g_audioDMA.AudioDMAControl.NumBlocks; + if (g_audioDMA.remaining_blocks_count == 0) + { + g_audioDMA.current_source_address = g_audioDMA.SourceAddress; + g_audioDMA.remaining_blocks_count = g_audioDMA.AudioDMAControl.NumBlocks; - if (g_audioDMA.remaining_blocks_count != 0) - { - // We make the samples ready as soon as possible - void *address = Memory::GetPointer(g_audioDMA.SourceAddress); - AudioCommon::SendAIBuffer((short*)address, g_audioDMA.AudioDMAControl.NumBlocks * 8); - } - GenerateDSPInterrupt(DSP::INT_AID); - } - } - else - { - AudioCommon::SendAIBuffer(&zero_samples[0], 8); - } + if (g_audioDMA.remaining_blocks_count != 0) + { + // We make the samples ready as soon as possible + void* address = Memory::GetPointer(g_audioDMA.SourceAddress); + AudioCommon::SendAIBuffer((short*)address, g_audioDMA.AudioDMAControl.NumBlocks * 8); + } + GenerateDSPInterrupt(DSP::INT_AID); + } + } + else + { + AudioCommon::SendAIBuffer(&zero_samples[0], 8); + } } static void Do_ARAM_DMA() { - g_dspState.DMAState = 1; + g_dspState.DMAState = 1; - // ARAM DMA transfer rate has been measured on real hw - int ticksToTransfer = (g_arDMA.Cnt.count / 32) * 246; + // ARAM DMA transfer rate has been measured on real hw + int ticksToTransfer = (g_arDMA.Cnt.count / 32) * 246; - // This is a huge hack that appears to be here only to fix Resident Evil 2/3 - if (instant_dma) - ticksToTransfer = std::min(ticksToTransfer, 100); + // This is a huge hack that appears to be here only to fix Resident Evil 2/3 + if (instant_dma) + ticksToTransfer = std::min(ticksToTransfer, 100); - CoreTiming::ScheduleEvent(ticksToTransfer, et_CompleteARAM); + CoreTiming::ScheduleEvent(ticksToTransfer, et_CompleteARAM); - last_mmaddr = g_arDMA.MMAddr; - last_aram_dma_count = g_arDMA.Cnt.count; + last_mmaddr = g_arDMA.MMAddr; + last_aram_dma_count = g_arDMA.Cnt.count; - // Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks - if (g_arDMA.Cnt.dir) - { - // ARAM -> MRAM - INFO_LOG(DSPINTERFACE, "DMA %08x bytes from ARAM %08x to MRAM %08x PC: %08x", - g_arDMA.Cnt.count, g_arDMA.ARAddr, g_arDMA.MMAddr, PC); + // Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks + if (g_arDMA.Cnt.dir) + { + // ARAM -> MRAM + INFO_LOG(DSPINTERFACE, "DMA %08x bytes from ARAM %08x to MRAM %08x PC: %08x", g_arDMA.Cnt.count, + g_arDMA.ARAddr, g_arDMA.MMAddr, PC); - // Outgoing data from ARAM is mirrored every 64MB (verified on real HW) - g_arDMA.ARAddr &= 0x3ffffff; - g_arDMA.MMAddr &= 0x3ffffff; + // Outgoing data from ARAM is mirrored every 64MB (verified on real HW) + g_arDMA.ARAddr &= 0x3ffffff; + g_arDMA.MMAddr &= 0x3ffffff; - if (g_arDMA.ARAddr < g_ARAM.size) - { - while (g_arDMA.Cnt.count) - { - // These are logically separated in code to show that a memory map has been set up - // See below in the write section for more information - if ((g_ARAM_Info.Hex & 0xf) == 3) - { - Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr); - } - else if ((g_ARAM_Info.Hex & 0xf) == 4) - { - Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr); - } - else - { - Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr); - } + if (g_arDMA.ARAddr < g_ARAM.size) + { + while (g_arDMA.Cnt.count) + { + // These are logically separated in code to show that a memory map has been set up + // See below in the write section for more information + if ((g_ARAM_Info.Hex & 0xf) == 3) + { + Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr); + } + else if ((g_ARAM_Info.Hex & 0xf) == 4) + { + Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr); + } + else + { + Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr); + } - g_arDMA.MMAddr += 8; - g_arDMA.ARAddr += 8; - g_arDMA.Cnt.count -= 8; - } - } - else - { - // Assuming no external ARAM installed; returns zeros on out of bounds reads (verified on real HW) - while (g_arDMA.Cnt.count) - { - Memory::Write_U64(0, g_arDMA.MMAddr); - g_arDMA.MMAddr += 8; - g_arDMA.ARAddr += 8; - g_arDMA.Cnt.count -= 8; - } - } - } - else - { - // MRAM -> ARAM - INFO_LOG(DSPINTERFACE, "DMA %08x bytes from MRAM %08x to ARAM %08x PC: %08x", - g_arDMA.Cnt.count, g_arDMA.MMAddr, g_arDMA.ARAddr, PC); + g_arDMA.MMAddr += 8; + g_arDMA.ARAddr += 8; + g_arDMA.Cnt.count -= 8; + } + } + else + { + // Assuming no external ARAM installed; returns zeros on out of bounds reads (verified on real + // HW) + while (g_arDMA.Cnt.count) + { + Memory::Write_U64(0, g_arDMA.MMAddr); + g_arDMA.MMAddr += 8; + g_arDMA.ARAddr += 8; + g_arDMA.Cnt.count -= 8; + } + } + } + else + { + // MRAM -> ARAM + INFO_LOG(DSPINTERFACE, "DMA %08x bytes from MRAM %08x to ARAM %08x PC: %08x", g_arDMA.Cnt.count, + g_arDMA.MMAddr, g_arDMA.ARAddr, PC); - // Incoming data into ARAM is mirrored every 64MB (verified on real HW) - g_arDMA.ARAddr &= 0x3ffffff; - g_arDMA.MMAddr &= 0x3ffffff; + // Incoming data into ARAM is mirrored every 64MB (verified on real HW) + g_arDMA.ARAddr &= 0x3ffffff; + g_arDMA.MMAddr &= 0x3ffffff; - if (g_arDMA.ARAddr < g_ARAM.size) - { - while (g_arDMA.Cnt.count) - { - if ((g_ARAM_Info.Hex & 0xf) == 3) - { - *(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); - } - else if ((g_ARAM_Info.Hex & 0xf) == 4) - { - if (g_arDMA.ARAddr < 0x400000) - { - *(u64*)&g_ARAM.ptr[(g_arDMA.ARAddr + 0x400000) & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); - } - *(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); - } - else - { - *(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); - } + if (g_arDMA.ARAddr < g_ARAM.size) + { + while (g_arDMA.Cnt.count) + { + if ((g_ARAM_Info.Hex & 0xf) == 3) + { + *(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = + Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); + } + else if ((g_ARAM_Info.Hex & 0xf) == 4) + { + if (g_arDMA.ARAddr < 0x400000) + { + *(u64*)&g_ARAM.ptr[(g_arDMA.ARAddr + 0x400000) & g_ARAM.mask] = + Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); + } + *(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = + Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); + } + else + { + *(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = + Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); + } - g_arDMA.MMAddr += 8; - g_arDMA.ARAddr += 8; - g_arDMA.Cnt.count -= 8; - } - } - else - { - // Assuming no external ARAM installed; writes nothing to ARAM when out of bounds (verified on real HW) - g_arDMA.MMAddr += g_arDMA.Cnt.count; - g_arDMA.ARAddr += g_arDMA.Cnt.count; - g_arDMA.Cnt.count = 0; - } - } + g_arDMA.MMAddr += 8; + g_arDMA.ARAddr += 8; + g_arDMA.Cnt.count -= 8; + } + } + else + { + // Assuming no external ARAM installed; writes nothing to ARAM when out of bounds (verified on + // real HW) + g_arDMA.MMAddr += g_arDMA.Cnt.count; + g_arDMA.ARAddr += g_arDMA.Cnt.count; + g_arDMA.Cnt.count = 0; + } + } } // (shuffle2) I still don't believe that this hack is actually needed... :( @@ -659,40 +641,39 @@ static void Do_ARAM_DMA() // (LM) It just means that DSP reads via '0xffdd' on Wii can end up in EXRAM or main RAM u8 ReadARAM(u32 _iAddress) { - //NOTICE_LOG(DSPINTERFACE, "ReadARAM 0x%08x", _iAddress); - if (g_ARAM.wii_mode) - { - if (_iAddress & 0x10000000) - return g_ARAM.ptr[_iAddress & g_ARAM.mask]; - else - return Memory::Read_U8(_iAddress & Memory::RAM_MASK); - } - else - { - return g_ARAM.ptr[_iAddress & g_ARAM.mask]; - } + // NOTICE_LOG(DSPINTERFACE, "ReadARAM 0x%08x", _iAddress); + if (g_ARAM.wii_mode) + { + if (_iAddress & 0x10000000) + return g_ARAM.ptr[_iAddress & g_ARAM.mask]; + else + return Memory::Read_U8(_iAddress & Memory::RAM_MASK); + } + else + { + return g_ARAM.ptr[_iAddress & g_ARAM.mask]; + } } void WriteARAM(u8 value, u32 _uAddress) { - // NOTICE_LOG(DSPINTERFACE, "WriteARAM 0x%08x", _uAddress); - // TODO: verify this on Wii - g_ARAM.ptr[_uAddress & g_ARAM.mask] = value; + // NOTICE_LOG(DSPINTERFACE, "WriteARAM 0x%08x", _uAddress); + // TODO: verify this on Wii + g_ARAM.ptr[_uAddress & g_ARAM.mask] = value; } -u8 *GetARAMPtr() +u8* GetARAMPtr() { - return g_ARAM.ptr; + return g_ARAM.ptr; } u64 DMAInProgress() { - if (g_dspState.DMAState == 1) - { - return ((u64)last_mmaddr << 32 | (last_mmaddr + last_aram_dma_count)); - } - return 0; + if (g_dspState.DMAState == 1) + { + return ((u64)last_mmaddr << 32 | (last_mmaddr + last_aram_dma_count)); + } + return 0; } -} // end of namespace DSP - +} // end of namespace DSP diff --git a/Source/Core/Core/HW/DSP.h b/Source/Core/Core/HW/DSP.h index 2152cb41c6..4eceaa8706 100644 --- a/Source/Core/Core/HW/DSP.h +++ b/Source/Core/Core/HW/DSP.h @@ -8,52 +8,54 @@ class PointerWrap; class DSPEmulator; -namespace MMIO { class Mapping; } +namespace MMIO +{ +class Mapping; +} namespace DSP { - enum DSPInterruptType { - INT_DSP = 0x80, - INT_ARAM = 0x20, - INT_AID = 0x08, + INT_DSP = 0x80, + INT_ARAM = 0x20, + INT_AID = 0x08, }; // aram size and mask enum { - ARAM_SIZE = 0x01000000, // 16 MB - ARAM_MASK = 0x00FFFFFF, + ARAM_SIZE = 0x01000000, // 16 MB + ARAM_MASK = 0x00FFFFFF, }; // UDSPControl #define DSP_CONTROL_MASK 0x0C07 -union UDSPControl -{ - u16 Hex; - struct - { - // DSP Control - u16 DSPReset : 1; // Write 1 to reset and waits for 0 - u16 DSPAssertInt : 1; - u16 DSPHalt : 1; - // Interrupt for DMA to the AI/speakers - u16 AID : 1; - u16 AID_mask : 1; - // ARAM DMA interrupt - u16 ARAM : 1; - u16 ARAM_mask : 1; - // DSP DMA interrupt - u16 DSP : 1; - u16 DSP_mask : 1; - // Other ??? - u16 DMAState : 1; // DSPGetDMAStatus() uses this flag. __ARWaitForDMA() uses it too...maybe it's just general DMA flag - u16 DSPInitCode : 1; // Indicator that the DSP was initialized? - u16 DSPInit : 1; // DSPInit() writes to this flag - u16 pad : 4; - }; - UDSPControl(u16 _Hex = 0) : Hex(_Hex) {} +union UDSPControl { + u16 Hex; + struct + { + // DSP Control + u16 DSPReset : 1; // Write 1 to reset and waits for 0 + u16 DSPAssertInt : 1; + u16 DSPHalt : 1; + // Interrupt for DMA to the AI/speakers + u16 AID : 1; + u16 AID_mask : 1; + // ARAM DMA interrupt + u16 ARAM : 1; + u16 ARAM_mask : 1; + // DSP DMA interrupt + u16 DSP : 1; + u16 DSP_mask : 1; + // Other ??? + u16 DMAState : 1; // DSPGetDMAStatus() uses this flag. __ARWaitForDMA() uses it too...maybe + // it's just general DMA flag + u16 DSPInitCode : 1; // Indicator that the DSP was initialized? + u16 DSPInit : 1; // DSPInit() writes to this flag + u16 pad : 4; + }; + UDSPControl(u16 _Hex = 0) : Hex(_Hex) {} }; extern UDSPControl g_dspState; @@ -65,7 +67,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base); DSPEmulator* GetDSPEmulator(); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); void GenerateDSPInterruptFromDSPEmu(DSPInterruptType _DSPInterruptType); @@ -82,4 +84,4 @@ u64 DMAInProgress(); void EnableInstantDMA(); void FlushInstantDMA(u32 address); -}// end of namespace DSP +} // end of namespace DSP diff --git a/Source/Core/Core/HW/DSPHLE/DSPHLE.cpp b/Source/Core/Core/HW/DSPHLE/DSPHLE.cpp index 510b76b5da..66254954b8 100644 --- a/Source/Core/Core/HW/DSPHLE/DSPHLE.cpp +++ b/Source/Core/Core/HW/DSPHLE/DSPHLE.cpp @@ -8,9 +8,9 @@ #include "Common/CommonTypes.h" #include "Common/MsgHandler.h" #include "Core/Core.h" -#include "Core/HW/SystemTimers.h" #include "Core/HW/DSPHLE/DSPHLE.h" #include "Core/HW/DSPHLE/UCodes/UCodes.h" +#include "Core/HW/SystemTimers.h" DSPHLE::DSPHLE() { @@ -18,19 +18,19 @@ DSPHLE::DSPHLE() bool DSPHLE::Initialize(bool bWii, bool bDSPThread) { - m_bWii = bWii; - m_pUCode = nullptr; - m_lastUCode = nullptr; - m_bHalt = false; - m_bAssertInt = false; + m_bWii = bWii; + m_pUCode = nullptr; + m_lastUCode = nullptr; + m_bHalt = false; + m_bAssertInt = false; - SetUCode(UCODE_ROM); - m_DSPControl.DSPHalt = 1; - m_DSPControl.DSPInit = 1; + SetUCode(UCODE_ROM); + m_DSPControl.DSPHalt = 1; + m_DSPControl.DSPInit = 1; - m_dspState.Reset(); + m_dspState.Reset(); - return true; + return true; } void DSPHLE::DSP_StopSoundStream() @@ -39,44 +39,44 @@ void DSPHLE::DSP_StopSoundStream() void DSPHLE::Shutdown() { - delete m_pUCode; - m_pUCode = nullptr; + delete m_pUCode; + m_pUCode = nullptr; } void DSPHLE::DSP_Update(int cycles) { - if (m_pUCode != nullptr) - m_pUCode->Update(); + if (m_pUCode != nullptr) + m_pUCode->Update(); } u32 DSPHLE::DSP_UpdateRate() { - // AX HLE uses 3ms (Wii) or 5ms (GC) timing period - // But to be sure, just update the HLE every ms. - return SystemTimers::GetTicksPerSecond() / 1000; + // AX HLE uses 3ms (Wii) or 5ms (GC) timing period + // But to be sure, just update the HLE every ms. + return SystemTimers::GetTicksPerSecond() / 1000; } void DSPHLE::SendMailToDSP(u32 _uMail) { - if (m_pUCode != nullptr) - { - DEBUG_LOG(DSP_MAIL, "CPU writes 0x%08x", _uMail); - m_pUCode->HandleMail(_uMail); - } + if (m_pUCode != nullptr) + { + DEBUG_LOG(DSP_MAIL, "CPU writes 0x%08x", _uMail); + m_pUCode->HandleMail(_uMail); + } } UCodeInterface* DSPHLE::GetUCode() { - return m_pUCode; + return m_pUCode; } void DSPHLE::SetUCode(u32 _crc) { - delete m_pUCode; + delete m_pUCode; - m_pUCode = nullptr; - m_MailHandler.Clear(); - m_pUCode = UCodeFactory(_crc, this, m_bWii); + m_pUCode = nullptr; + m_MailHandler.Clear(); + m_pUCode = UCodeFactory(_crc, this, m_bWii); } // TODO do it better? @@ -84,159 +84,163 @@ void DSPHLE::SetUCode(u32 _crc) // Even callers are deleted. void DSPHLE::SwapUCode(u32 _crc) { - m_MailHandler.Clear(); + m_MailHandler.Clear(); - if (m_lastUCode == nullptr) - { - m_lastUCode = m_pUCode; - m_pUCode = UCodeFactory(_crc, this, m_bWii); - } - else - { - delete m_pUCode; - m_pUCode = m_lastUCode; - m_lastUCode = nullptr; - } + if (m_lastUCode == nullptr) + { + m_lastUCode = m_pUCode; + m_pUCode = UCodeFactory(_crc, this, m_bWii); + } + else + { + delete m_pUCode; + m_pUCode = m_lastUCode; + m_lastUCode = nullptr; + } } -void DSPHLE::DoState(PointerWrap &p) +void DSPHLE::DoState(PointerWrap& p) { - bool isHLE = true; - p.Do(isHLE); - if (isHLE != true && p.GetMode() == PointerWrap::MODE_READ) - { - Core::DisplayMessage("State is incompatible with current DSP engine. Aborting load state.", 3000); - p.SetMode(PointerWrap::MODE_VERIFY); - return; - } + bool isHLE = true; + p.Do(isHLE); + if (isHLE != true && p.GetMode() == PointerWrap::MODE_READ) + { + Core::DisplayMessage("State is incompatible with current DSP engine. Aborting load state.", + 3000); + p.SetMode(PointerWrap::MODE_VERIFY); + return; + } - p.DoPOD(m_DSPControl); - p.DoPOD(m_dspState); + p.DoPOD(m_DSPControl); + p.DoPOD(m_dspState); - int ucode_crc = UCodeInterface::GetCRC(m_pUCode); - int ucode_crc_beforeLoad = ucode_crc; - int lastucode_crc = UCodeInterface::GetCRC(m_lastUCode); - int lastucode_crc_beforeLoad = lastucode_crc; + int ucode_crc = UCodeInterface::GetCRC(m_pUCode); + int ucode_crc_beforeLoad = ucode_crc; + int lastucode_crc = UCodeInterface::GetCRC(m_lastUCode); + int lastucode_crc_beforeLoad = lastucode_crc; - p.Do(ucode_crc); - p.Do(lastucode_crc); + p.Do(ucode_crc); + p.Do(lastucode_crc); - // if a different type of ucode was being used when the savestate was created, - // we have to reconstruct the old type of ucode so that we have a valid thing to call DoState on. - UCodeInterface* ucode = (ucode_crc == ucode_crc_beforeLoad) ? m_pUCode : UCodeFactory( ucode_crc, this, m_bWii); - UCodeInterface* lastucode = (lastucode_crc != lastucode_crc_beforeLoad) ? m_lastUCode : UCodeFactory(lastucode_crc, this, m_bWii); + // if a different type of ucode was being used when the savestate was created, + // we have to reconstruct the old type of ucode so that we have a valid thing to call DoState on. + UCodeInterface* ucode = + (ucode_crc == ucode_crc_beforeLoad) ? m_pUCode : UCodeFactory(ucode_crc, this, m_bWii); + UCodeInterface* lastucode = (lastucode_crc != lastucode_crc_beforeLoad) ? + m_lastUCode : + UCodeFactory(lastucode_crc, this, m_bWii); - if (ucode) - ucode->DoState(p); - if (lastucode) - lastucode->DoState(p); + if (ucode) + ucode->DoState(p); + if (lastucode) + lastucode->DoState(p); - // if a different type of ucode was being used when the savestate was created, - // discard it if we're not loading, otherwise discard the old one and keep the new one. - if (ucode != m_pUCode) - { - if (p.GetMode() != PointerWrap::MODE_READ) - { - delete ucode; - } - else - { - delete m_pUCode; - m_pUCode = ucode; - } - } - if (lastucode != m_lastUCode) - { - if (p.GetMode() != PointerWrap::MODE_READ) - { - delete lastucode; - } - else - { - delete m_lastUCode; - m_lastUCode = lastucode; - } - } + // if a different type of ucode was being used when the savestate was created, + // discard it if we're not loading, otherwise discard the old one and keep the new one. + if (ucode != m_pUCode) + { + if (p.GetMode() != PointerWrap::MODE_READ) + { + delete ucode; + } + else + { + delete m_pUCode; + m_pUCode = ucode; + } + } + if (lastucode != m_lastUCode) + { + if (p.GetMode() != PointerWrap::MODE_READ) + { + delete lastucode; + } + else + { + delete m_lastUCode; + m_lastUCode = lastucode; + } + } - m_MailHandler.DoState(p); + m_MailHandler.DoState(p); } // Mailbox functions unsigned short DSPHLE::DSP_ReadMailBoxHigh(bool _CPUMailbox) { - if (_CPUMailbox) - { - return (m_dspState.CPUMailbox >> 16) & 0xFFFF; - } - else - { - return AccessMailHandler().ReadDSPMailboxHigh(); - } + if (_CPUMailbox) + { + return (m_dspState.CPUMailbox >> 16) & 0xFFFF; + } + else + { + return AccessMailHandler().ReadDSPMailboxHigh(); + } } unsigned short DSPHLE::DSP_ReadMailBoxLow(bool _CPUMailbox) { - if (_CPUMailbox) - { - return m_dspState.CPUMailbox & 0xFFFF; - } - else - { - return AccessMailHandler().ReadDSPMailboxLow(); - } + if (_CPUMailbox) + { + return m_dspState.CPUMailbox & 0xFFFF; + } + else + { + return AccessMailHandler().ReadDSPMailboxLow(); + } } void DSPHLE::DSP_WriteMailBoxHigh(bool _CPUMailbox, unsigned short _Value) { - if (_CPUMailbox) - { - m_dspState.CPUMailbox = (m_dspState.CPUMailbox & 0xFFFF) | (_Value << 16); - } - else - { - PanicAlert("CPU can't write %08x to DSP mailbox", _Value); - } + if (_CPUMailbox) + { + m_dspState.CPUMailbox = (m_dspState.CPUMailbox & 0xFFFF) | (_Value << 16); + } + else + { + PanicAlert("CPU can't write %08x to DSP mailbox", _Value); + } } void DSPHLE::DSP_WriteMailBoxLow(bool _CPUMailbox, unsigned short _Value) { - if (_CPUMailbox) - { - m_dspState.CPUMailbox = (m_dspState.CPUMailbox & 0xFFFF0000) | _Value; - SendMailToDSP(m_dspState.CPUMailbox); - // Mail sent so clear MSB to show that it is progressed - m_dspState.CPUMailbox &= 0x7FFFFFFF; - } - else - { - PanicAlert("CPU can't write %08x to DSP mailbox", _Value); - } + if (_CPUMailbox) + { + m_dspState.CPUMailbox = (m_dspState.CPUMailbox & 0xFFFF0000) | _Value; + SendMailToDSP(m_dspState.CPUMailbox); + // Mail sent so clear MSB to show that it is progressed + m_dspState.CPUMailbox &= 0x7FFFFFFF; + } + else + { + PanicAlert("CPU can't write %08x to DSP mailbox", _Value); + } } // Other DSP functions u16 DSPHLE::DSP_WriteControlRegister(unsigned short _Value) { - DSP::UDSPControl Temp(_Value); + DSP::UDSPControl Temp(_Value); - if (Temp.DSPReset) - { - SetUCode(UCODE_ROM); - Temp.DSPReset = 0; - } - if (Temp.DSPInit == 0) - { - // copy 128 byte from ARAM 0x000000 to IMEM - SetUCode(UCODE_INIT_AUDIO_SYSTEM); - Temp.DSPInitCode = 0; - } + if (Temp.DSPReset) + { + SetUCode(UCODE_ROM); + Temp.DSPReset = 0; + } + if (Temp.DSPInit == 0) + { + // copy 128 byte from ARAM 0x000000 to IMEM + SetUCode(UCODE_INIT_AUDIO_SYSTEM); + Temp.DSPInitCode = 0; + } - m_DSPControl.Hex = Temp.Hex; - return m_DSPControl.Hex; + m_DSPControl.Hex = Temp.Hex; + return m_DSPControl.Hex; } u16 DSPHLE::DSP_ReadControlRegister() { - return m_DSPControl.Hex; + return m_DSPControl.Hex; } void DSPHLE::PauseAndLock(bool doLock, bool unpauseOnUnlock) diff --git a/Source/Core/Core/HW/DSPHLE/DSPHLE.h b/Source/Core/Core/HW/DSPHLE/DSPHLE.h index 08371c3898..411440da7e 100644 --- a/Source/Core/Core/HW/DSPHLE/DSPHLE.h +++ b/Source/Core/Core/HW/DSPHLE/DSPHLE.h @@ -12,65 +12,61 @@ class PointerWrap; class UCodeInterface; -class DSPHLE : public DSPEmulator { +class DSPHLE : public DSPEmulator +{ public: - DSPHLE(); + DSPHLE(); - bool Initialize(bool bWii, bool bDSPThread) override; - void Shutdown() override; - bool IsLLE() override { return false ; } + bool Initialize(bool bWii, bool bDSPThread) override; + void Shutdown() override; + bool IsLLE() override { return false; } + void DoState(PointerWrap& p) override; + void PauseAndLock(bool doLock, bool unpauseOnUnlock = true) override; - void DoState(PointerWrap &p) override; - void PauseAndLock(bool doLock, bool unpauseOnUnlock=true) override; + void DSP_WriteMailBoxHigh(bool _CPUMailbox, unsigned short) override; + void DSP_WriteMailBoxLow(bool _CPUMailbox, unsigned short) override; + unsigned short DSP_ReadMailBoxHigh(bool _CPUMailbox) override; + unsigned short DSP_ReadMailBoxLow(bool _CPUMailbox) override; + unsigned short DSP_ReadControlRegister() override; + unsigned short DSP_WriteControlRegister(unsigned short) override; + void DSP_Update(int cycles) override; + void DSP_StopSoundStream() override; + u32 DSP_UpdateRate() override; - void DSP_WriteMailBoxHigh(bool _CPUMailbox, unsigned short) override; - void DSP_WriteMailBoxLow(bool _CPUMailbox, unsigned short) override; - unsigned short DSP_ReadMailBoxHigh(bool _CPUMailbox) override; - unsigned short DSP_ReadMailBoxLow(bool _CPUMailbox) override; - unsigned short DSP_ReadControlRegister() override; - unsigned short DSP_WriteControlRegister(unsigned short) override; - void DSP_Update(int cycles) override; - void DSP_StopSoundStream() override; - u32 DSP_UpdateRate() override; - - CMailHandler& AccessMailHandler() { return m_MailHandler; } - - // Formerly DSPHandler - UCodeInterface *GetUCode(); - void SetUCode(u32 _crc); - void SwapUCode(u32 _crc); + CMailHandler& AccessMailHandler() { return m_MailHandler; } + // Formerly DSPHandler + UCodeInterface* GetUCode(); + void SetUCode(u32 _crc); + void SwapUCode(u32 _crc); private: - void SendMailToDSP(u32 _uMail); + void SendMailToDSP(u32 _uMail); - // Declarations and definitions - bool m_bWii; + // Declarations and definitions + bool m_bWii; - // Fake mailbox utility - struct DSPState - { - u32 CPUMailbox; - u32 DSPMailbox; + // Fake mailbox utility + struct DSPState + { + u32 CPUMailbox; + u32 DSPMailbox; - void Reset() - { - CPUMailbox = 0x00000000; - DSPMailbox = 0x00000000; - } + void Reset() + { + CPUMailbox = 0x00000000; + DSPMailbox = 0x00000000; + } - DSPState() - { - Reset(); - } - }; - DSPState m_dspState; + DSPState() { Reset(); } + }; + DSPState m_dspState; - UCodeInterface* m_pUCode; - UCodeInterface* m_lastUCode; + UCodeInterface* m_pUCode; + UCodeInterface* m_lastUCode; - DSP::UDSPControl m_DSPControl; - CMailHandler m_MailHandler; + DSP::UDSPControl m_DSPControl; + CMailHandler m_MailHandler; - bool m_bHalt; - bool m_bAssertInt; + bool m_bHalt; + bool m_bAssertInt; }; diff --git a/Source/Core/Core/HW/DSPHLE/MailHandler.cpp b/Source/Core/Core/HW/DSPHLE/MailHandler.cpp index fffb1653f1..8ced968319 100644 --- a/Source/Core/Core/HW/DSPHLE/MailHandler.cpp +++ b/Source/Core/Core/HW/DSPHLE/MailHandler.cpp @@ -2,12 +2,12 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/DSPHLE/MailHandler.h" #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "Core/HW/DSP.h" -#include "Core/HW/DSPHLE/MailHandler.h" CMailHandler::CMailHandler() { @@ -15,116 +15,116 @@ CMailHandler::CMailHandler() CMailHandler::~CMailHandler() { - Clear(); + Clear(); } void CMailHandler::PushMail(u32 _Mail, bool interrupt) { - if (interrupt) - { - if (m_Mails.empty()) - { - DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); - } - else - { - m_Mails.front().second = true; - } - } - m_Mails.emplace(_Mail, false); - DEBUG_LOG(DSP_MAIL, "DSP writes 0x%08x", _Mail); + if (interrupt) + { + if (m_Mails.empty()) + { + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + } + else + { + m_Mails.front().second = true; + } + } + m_Mails.emplace(_Mail, false); + DEBUG_LOG(DSP_MAIL, "DSP writes 0x%08x", _Mail); } u16 CMailHandler::ReadDSPMailboxHigh() { - // check if we have a mail for the core - if (!m_Mails.empty()) - { - u16 result = (m_Mails.front().first >> 16) & 0xFFFF; - return result; - } - return 0x00; + // check if we have a mail for the core + if (!m_Mails.empty()) + { + u16 result = (m_Mails.front().first >> 16) & 0xFFFF; + return result; + } + return 0x00; } u16 CMailHandler::ReadDSPMailboxLow() { - // check if we have a mail for the core - if (!m_Mails.empty()) - { - u16 result = m_Mails.front().first & 0xFFFF; - bool generate_interrupt = m_Mails.front().second; - m_Mails.pop(); + // check if we have a mail for the core + if (!m_Mails.empty()) + { + u16 result = m_Mails.front().first & 0xFFFF; + bool generate_interrupt = m_Mails.front().second; + m_Mails.pop(); - if (generate_interrupt) - { - DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); - } + if (generate_interrupt) + { + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + } - return result; - } - return 0x00; + return result; + } + return 0x00; } void CMailHandler::Clear() { - while (!m_Mails.empty()) - m_Mails.pop(); + while (!m_Mails.empty()) + m_Mails.pop(); } bool CMailHandler::IsEmpty() const { - return m_Mails.empty(); + return m_Mails.empty(); } void CMailHandler::Halt(bool _Halt) { - if (_Halt) - { - Clear(); - PushMail(0x80544348); - } + if (_Halt) + { + Clear(); + PushMail(0x80544348); + } } -void CMailHandler::DoState(PointerWrap &p) +void CMailHandler::DoState(PointerWrap& p) { - if (p.GetMode() == PointerWrap::MODE_READ) - { - Clear(); - int sz = 0; - p.Do(sz); - for (int i = 0; i < sz; i++) - { - u32 mail = 0; - bool interrupt = false; - p.Do(mail); - p.Do(interrupt); - m_Mails.emplace(mail, interrupt); - } - } - else // WRITE and MEASURE - { - std::queue> temp; - int sz = (int)m_Mails.size(); - p.Do(sz); - for (int i = 0; i < sz; i++) - { - u32 value = m_Mails.front().first; - bool interrupt = m_Mails.front().second; - m_Mails.pop(); - p.Do(value); - p.Do(interrupt); - temp.emplace(value, interrupt); - } - if (!m_Mails.empty()) - PanicAlert("CMailHandler::DoState - WTF?"); + if (p.GetMode() == PointerWrap::MODE_READ) + { + Clear(); + int sz = 0; + p.Do(sz); + for (int i = 0; i < sz; i++) + { + u32 mail = 0; + bool interrupt = false; + p.Do(mail); + p.Do(interrupt); + m_Mails.emplace(mail, interrupt); + } + } + else // WRITE and MEASURE + { + std::queue> temp; + int sz = (int)m_Mails.size(); + p.Do(sz); + for (int i = 0; i < sz; i++) + { + u32 value = m_Mails.front().first; + bool interrupt = m_Mails.front().second; + m_Mails.pop(); + p.Do(value); + p.Do(interrupt); + temp.emplace(value, interrupt); + } + if (!m_Mails.empty()) + PanicAlert("CMailHandler::DoState - WTF?"); - // Restore queue. - for (int i = 0; i < sz; i++) - { - u32 value = temp.front().first; - bool interrupt = temp.front().second; - temp.pop(); - m_Mails.emplace(value, interrupt); - } - } + // Restore queue. + for (int i = 0; i < sz; i++) + { + u32 value = temp.front().first; + bool interrupt = temp.front().second; + temp.pop(); + m_Mails.emplace(value, interrupt); + } + } } diff --git a/Source/Core/Core/HW/DSPHLE/MailHandler.h b/Source/Core/Core/HW/DSPHLE/MailHandler.h index 41d5f77c89..12c2c9f3ba 100644 --- a/Source/Core/Core/HW/DSPHLE/MailHandler.h +++ b/Source/Core/Core/HW/DSPHLE/MailHandler.h @@ -14,19 +14,19 @@ class PointerWrap; class CMailHandler { public: - CMailHandler(); - ~CMailHandler(); + CMailHandler(); + ~CMailHandler(); - void PushMail(u32 _Mail, bool interrupt = false); - void Clear(); - void Halt(bool _Halt); - void DoState(PointerWrap &p); - bool IsEmpty() const; + void PushMail(u32 _Mail, bool interrupt = false); + void Clear(); + void Halt(bool _Halt); + void DoState(PointerWrap& p); + bool IsEmpty() const; - u16 ReadDSPMailboxHigh(); - u16 ReadDSPMailboxLow(); + u16 ReadDSPMailboxHigh(); + u16 ReadDSPMailboxLow(); private: - // mail handler - std::queue> m_Mails; + // mail handler + std::queue> m_Mails; }; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp index 76969027d5..4c84267a29 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp @@ -2,88 +2,84 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/DSPHLE/UCodes/AX.h" #include "Common/ChunkFile.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/MathUtil.h" #include "Common/Logging/Log.h" +#include "Common/MathUtil.h" #include "Core/ConfigManager.h" #include "Core/HW/DSP.h" -#include "Core/HW/DSPHLE/UCodes/AX.h" #include "Core/HW/DSPHLE/UCodes/AXStructs.h" #define AX_GC #include "Core/HW/DSPHLE/UCodes/AXVoice.h" -AXUCode::AXUCode(DSPHLE* dsphle, u32 crc) - : UCodeInterface(dsphle, crc) - , m_cmdlist_size(0) +AXUCode::AXUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc), m_cmdlist_size(0) { - WARN_LOG(DSPHLE, "Instantiating AXUCode: crc=%08x", crc); - m_mail_handler.PushMail(DSP_INIT); - DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + WARN_LOG(DSPHLE, "Instantiating AXUCode: crc=%08x", crc); + m_mail_handler.PushMail(DSP_INIT); + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); - LoadResamplingCoefficients(); + LoadResamplingCoefficients(); } AXUCode::~AXUCode() { - m_mail_handler.Clear(); + m_mail_handler.Clear(); } void AXUCode::LoadResamplingCoefficients() { - m_coeffs_available = false; + m_coeffs_available = false; - std::string filenames[] = { - File::GetUserPath(D_GCUSER_IDX) + "dsp_coef.bin", - File::GetSysDirectory() + "/GC/dsp_coef.bin" - }; + std::string filenames[] = {File::GetUserPath(D_GCUSER_IDX) + "dsp_coef.bin", + File::GetSysDirectory() + "/GC/dsp_coef.bin"}; - size_t fidx; - std::string filename; - for (fidx = 0; fidx < ArraySize(filenames); ++fidx) - { - filename = filenames[fidx]; - if (!File::Exists(filename)) - continue; + size_t fidx; + std::string filename; + for (fidx = 0; fidx < ArraySize(filenames); ++fidx) + { + filename = filenames[fidx]; + if (!File::Exists(filename)) + continue; - if (File::GetSize(filename) != 0x1000) - continue; + if (File::GetSize(filename) != 0x1000) + continue; - break; - } + break; + } - if (fidx >= ArraySize(filenames)) - return; + if (fidx >= ArraySize(filenames)) + return; - WARN_LOG(DSPHLE, "Loading polyphase resampling coeffs from %s", filename.c_str()); + WARN_LOG(DSPHLE, "Loading polyphase resampling coeffs from %s", filename.c_str()); - File::IOFile fp(filename, "rb"); - fp.ReadBytes(m_coeffs, 0x1000); + File::IOFile fp(filename, "rb"); + fp.ReadBytes(m_coeffs, 0x1000); - for (auto& coef : m_coeffs) - coef = Common::swap16(coef); + for (auto& coef : m_coeffs) + coef = Common::swap16(coef); - m_coeffs_available = true; + m_coeffs_available = true; } void AXUCode::SignalWorkEnd() { - // Signal end of processing - m_mail_handler.PushMail(DSP_YIELD); - DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + // Signal end of processing + m_mail_handler.PushMail(DSP_YIELD); + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); } void AXUCode::HandleCommandList() { - // Temp variables for addresses computation - u16 addr_hi, addr_lo; - u16 addr2_hi, addr2_lo; - u16 size; + // Temp variables for addresses computation + u16 addr_hi, addr_lo; + u16 addr2_hi, addr2_lo; + u16 size; - u32 pb_addr = 0; + u32 pb_addr = 0; #if 0 WARN_LOG(DSPHLE, "Command list:"); @@ -92,604 +88,602 @@ void AXUCode::HandleCommandList() WARN_LOG(DSPHLE, "-------------"); #endif - u32 curr_idx = 0; - bool end = false; - while (!end) - { - u16 cmd = m_cmdlist[curr_idx++]; + u32 curr_idx = 0; + bool end = false; + while (!end) + { + u16 cmd = m_cmdlist[curr_idx++]; - switch (cmd) - { - // Some of these commands are unknown, or unused in this AX HLE. - // We still need to skip their arguments using "curr_idx += N". + switch (cmd) + { + // Some of these commands are unknown, or unused in this AX HLE. + // We still need to skip their arguments using "curr_idx += N". - case CMD_SETUP: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - SetupProcessing(HILO_TO_32(addr)); - break; + case CMD_SETUP: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + SetupProcessing(HILO_TO_32(addr)); + break; - case CMD_DL_AND_VOL_MIX: - { - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - u16 vol_main = m_cmdlist[curr_idx++]; - u16 vol_auxa = m_cmdlist[curr_idx++]; - u16 vol_auxb = m_cmdlist[curr_idx++]; - DownloadAndMixWithVolume(HILO_TO_32(addr), vol_main, vol_auxa, vol_auxb); - break; - } + case CMD_DL_AND_VOL_MIX: + { + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + u16 vol_main = m_cmdlist[curr_idx++]; + u16 vol_auxa = m_cmdlist[curr_idx++]; + u16 vol_auxb = m_cmdlist[curr_idx++]; + DownloadAndMixWithVolume(HILO_TO_32(addr), vol_main, vol_auxa, vol_auxb); + break; + } - case CMD_PB_ADDR: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - pb_addr = HILO_TO_32(addr); - break; + case CMD_PB_ADDR: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + pb_addr = HILO_TO_32(addr); + break; - case CMD_PROCESS: - ProcessPBList(pb_addr); - break; + case CMD_PROCESS: + ProcessPBList(pb_addr); + break; - case CMD_MIX_AUXA: - case CMD_MIX_AUXB: - // These two commands are handled almost the same internally. - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - addr2_hi = m_cmdlist[curr_idx++]; - addr2_lo = m_cmdlist[curr_idx++]; - MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2)); - break; + case CMD_MIX_AUXA: + case CMD_MIX_AUXB: + // These two commands are handled almost the same internally. + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + addr2_hi = m_cmdlist[curr_idx++]; + addr2_lo = m_cmdlist[curr_idx++]; + MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2)); + break; - case CMD_UPLOAD_LRS: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - UploadLRS(HILO_TO_32(addr)); - break; + case CMD_UPLOAD_LRS: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + UploadLRS(HILO_TO_32(addr)); + break; - case CMD_SET_LR: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - SetMainLR(HILO_TO_32(addr)); - break; + case CMD_SET_LR: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + SetMainLR(HILO_TO_32(addr)); + break; - case CMD_UNK_08: curr_idx += 10; break; // TODO: check + case CMD_UNK_08: + curr_idx += 10; + break; // TODO: check - case CMD_MIX_AUXB_NOWRITE: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - MixAUXSamples(1, 0, HILO_TO_32(addr)); - break; + case CMD_MIX_AUXB_NOWRITE: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + MixAUXSamples(1, 0, HILO_TO_32(addr)); + break; - case CMD_COMPRESSOR_TABLE_ADDR: curr_idx += 2; break; - case CMD_UNK_0B: break; // TODO: check other versions - case CMD_UNK_0C: break; // TODO: check other versions + case CMD_COMPRESSOR_TABLE_ADDR: + curr_idx += 2; + break; + case CMD_UNK_0B: + break; // TODO: check other versions + case CMD_UNK_0C: + break; // TODO: check other versions - case CMD_MORE: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - size = m_cmdlist[curr_idx++]; + case CMD_MORE: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + size = m_cmdlist[curr_idx++]; - CopyCmdList(HILO_TO_32(addr), size); - curr_idx = 0; - break; + CopyCmdList(HILO_TO_32(addr), size); + curr_idx = 0; + break; - case CMD_OUTPUT: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - addr2_hi = m_cmdlist[curr_idx++]; - addr2_lo = m_cmdlist[curr_idx++]; - OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr)); - break; + case CMD_OUTPUT: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + addr2_hi = m_cmdlist[curr_idx++]; + addr2_lo = m_cmdlist[curr_idx++]; + OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr)); + break; - case CMD_END: - end = true; - break; + case CMD_END: + end = true; + break; - case CMD_MIX_AUXB_LR: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - addr2_hi = m_cmdlist[curr_idx++]; - addr2_lo = m_cmdlist[curr_idx++]; - MixAUXBLR(HILO_TO_32(addr), HILO_TO_32(addr2)); - break; + case CMD_MIX_AUXB_LR: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + addr2_hi = m_cmdlist[curr_idx++]; + addr2_lo = m_cmdlist[curr_idx++]; + MixAUXBLR(HILO_TO_32(addr), HILO_TO_32(addr2)); + break; - case CMD_SET_OPPOSITE_LR: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - SetOppositeLR(HILO_TO_32(addr)); - break; + case CMD_SET_OPPOSITE_LR: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + SetOppositeLR(HILO_TO_32(addr)); + break; - case CMD_UNK_12: - { - u16 samp_val = m_cmdlist[curr_idx++]; - u16 idx = m_cmdlist[curr_idx++]; - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - // TODO - // suppress warnings: - (void)samp_val; (void)idx; - break; - } + case CMD_UNK_12: + { + u16 samp_val = m_cmdlist[curr_idx++]; + u16 idx = m_cmdlist[curr_idx++]; + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + // TODO + // suppress warnings: + (void)samp_val; + (void)idx; + break; + } - // Send the contents of MAIN LRS, AUXA LRS and AUXB S to RAM, and - // mix data to MAIN LR and AUXB LR. - case CMD_SEND_AUX_AND_MIX: - { - // Address for Main + AUXA LRS upload - u16 main_auxa_up_hi = m_cmdlist[curr_idx++]; - u16 main_auxa_up_lo = m_cmdlist[curr_idx++]; + // Send the contents of MAIN LRS, AUXA LRS and AUXB S to RAM, and + // mix data to MAIN LR and AUXB LR. + case CMD_SEND_AUX_AND_MIX: + { + // Address for Main + AUXA LRS upload + u16 main_auxa_up_hi = m_cmdlist[curr_idx++]; + u16 main_auxa_up_lo = m_cmdlist[curr_idx++]; - // Address for AUXB S upload - u16 auxb_s_up_hi = m_cmdlist[curr_idx++]; - u16 auxb_s_up_lo = m_cmdlist[curr_idx++]; + // Address for AUXB S upload + u16 auxb_s_up_hi = m_cmdlist[curr_idx++]; + u16 auxb_s_up_lo = m_cmdlist[curr_idx++]; - // Address to read data for Main L - u16 main_l_dl_hi = m_cmdlist[curr_idx++]; - u16 main_l_dl_lo = m_cmdlist[curr_idx++]; + // Address to read data for Main L + u16 main_l_dl_hi = m_cmdlist[curr_idx++]; + u16 main_l_dl_lo = m_cmdlist[curr_idx++]; - // Address to read data for Main R - u16 main_r_dl_hi = m_cmdlist[curr_idx++]; - u16 main_r_dl_lo = m_cmdlist[curr_idx++]; + // Address to read data for Main R + u16 main_r_dl_hi = m_cmdlist[curr_idx++]; + u16 main_r_dl_lo = m_cmdlist[curr_idx++]; - // Address to read data for AUXB L - u16 auxb_l_dl_hi = m_cmdlist[curr_idx++]; - u16 auxb_l_dl_lo = m_cmdlist[curr_idx++]; + // Address to read data for AUXB L + u16 auxb_l_dl_hi = m_cmdlist[curr_idx++]; + u16 auxb_l_dl_lo = m_cmdlist[curr_idx++]; - // Address to read data for AUXB R - u16 auxb_r_dl_hi = m_cmdlist[curr_idx++]; - u16 auxb_r_dl_lo = m_cmdlist[curr_idx++]; + // Address to read data for AUXB R + u16 auxb_r_dl_hi = m_cmdlist[curr_idx++]; + u16 auxb_r_dl_lo = m_cmdlist[curr_idx++]; - SendAUXAndMix(HILO_TO_32(main_auxa_up), HILO_TO_32(auxb_s_up), - HILO_TO_32(main_l_dl), HILO_TO_32(main_r_dl), - HILO_TO_32(auxb_l_dl), HILO_TO_32(auxb_r_dl)); - break; - } + SendAUXAndMix(HILO_TO_32(main_auxa_up), HILO_TO_32(auxb_s_up), HILO_TO_32(main_l_dl), + HILO_TO_32(main_r_dl), HILO_TO_32(auxb_l_dl), HILO_TO_32(auxb_r_dl)); + break; + } - default: - ERROR_LOG(DSPHLE, "Unknown command in AX command list: %04x", cmd); - end = true; - break; - } - } + default: + ERROR_LOG(DSPHLE, "Unknown command in AX command list: %04x", cmd); + end = true; + break; + } + } } void AXUCode::ApplyUpdatesForMs(int curr_ms, u16* pb, u16* num_updates, u16* updates) { - u32 start_idx = 0; - for (int i = 0; i < curr_ms; ++i) - start_idx += num_updates[i]; + u32 start_idx = 0; + for (int i = 0; i < curr_ms; ++i) + start_idx += num_updates[i]; - for (u32 i = start_idx; i < start_idx + num_updates[curr_ms]; ++i) - { - u16 update_off = Common::swap16(updates[2 * i]); - u16 update_val = Common::swap16(updates[2 * i + 1]); + for (u32 i = start_idx; i < start_idx + num_updates[curr_ms]; ++i) + { + u16 update_off = Common::swap16(updates[2 * i]); + u16 update_val = Common::swap16(updates[2 * i + 1]); - pb[update_off] = update_val; - } + pb[update_off] = update_val; + } } AXMixControl AXUCode::ConvertMixerControl(u32 mixer_control) { - u32 ret = 0; + u32 ret = 0; - // TODO: find other UCode versions with different mixer_control values - if (m_crc == 0x4e8a8b21) - { - ret |= MIX_L | MIX_R; - if (mixer_control & 0x0001) ret |= MIX_AUXA_L | MIX_AUXA_R; - if (mixer_control & 0x0002) ret |= MIX_AUXB_L | MIX_AUXB_R; - if (mixer_control & 0x0004) - { - ret |= MIX_S; - if (ret & MIX_AUXA_L) ret |= MIX_AUXA_S; - if (ret & MIX_AUXB_L) ret |= MIX_AUXB_S; - } - if (mixer_control & 0x0008) - { - ret |= MIX_L_RAMP | MIX_R_RAMP; - if (ret & MIX_AUXA_L) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP; - if (ret & MIX_AUXB_L) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP; - if (ret & MIX_AUXA_S) ret |= MIX_AUXA_S_RAMP; - if (ret & MIX_AUXB_S) ret |= MIX_AUXB_S_RAMP; - } - } - else - { - if (mixer_control & 0x0001) ret |= MIX_L; - if (mixer_control & 0x0002) ret |= MIX_R; - if (mixer_control & 0x0004) ret |= MIX_S; - if (mixer_control & 0x0008) ret |= MIX_L_RAMP | MIX_R_RAMP | MIX_S_RAMP; - if (mixer_control & 0x0010) ret |= MIX_AUXA_L; - if (mixer_control & 0x0020) ret |= MIX_AUXA_R; - if (mixer_control & 0x0040) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP; - if (mixer_control & 0x0080) ret |= MIX_AUXA_S; - if (mixer_control & 0x0100) ret |= MIX_AUXA_S_RAMP; - if (mixer_control & 0x0200) ret |= MIX_AUXB_L; - if (mixer_control & 0x0400) ret |= MIX_AUXB_R; - if (mixer_control & 0x0800) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP; - if (mixer_control & 0x1000) ret |= MIX_AUXB_S; - if (mixer_control & 0x2000) ret |= MIX_AUXB_S_RAMP; + // TODO: find other UCode versions with different mixer_control values + if (m_crc == 0x4e8a8b21) + { + ret |= MIX_L | MIX_R; + if (mixer_control & 0x0001) + ret |= MIX_AUXA_L | MIX_AUXA_R; + if (mixer_control & 0x0002) + ret |= MIX_AUXB_L | MIX_AUXB_R; + if (mixer_control & 0x0004) + { + ret |= MIX_S; + if (ret & MIX_AUXA_L) + ret |= MIX_AUXA_S; + if (ret & MIX_AUXB_L) + ret |= MIX_AUXB_S; + } + if (mixer_control & 0x0008) + { + ret |= MIX_L_RAMP | MIX_R_RAMP; + if (ret & MIX_AUXA_L) + ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP; + if (ret & MIX_AUXB_L) + ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP; + if (ret & MIX_AUXA_S) + ret |= MIX_AUXA_S_RAMP; + if (ret & MIX_AUXB_S) + ret |= MIX_AUXB_S_RAMP; + } + } + else + { + if (mixer_control & 0x0001) + ret |= MIX_L; + if (mixer_control & 0x0002) + ret |= MIX_R; + if (mixer_control & 0x0004) + ret |= MIX_S; + if (mixer_control & 0x0008) + ret |= MIX_L_RAMP | MIX_R_RAMP | MIX_S_RAMP; + if (mixer_control & 0x0010) + ret |= MIX_AUXA_L; + if (mixer_control & 0x0020) + ret |= MIX_AUXA_R; + if (mixer_control & 0x0040) + ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP; + if (mixer_control & 0x0080) + ret |= MIX_AUXA_S; + if (mixer_control & 0x0100) + ret |= MIX_AUXA_S_RAMP; + if (mixer_control & 0x0200) + ret |= MIX_AUXB_L; + if (mixer_control & 0x0400) + ret |= MIX_AUXB_R; + if (mixer_control & 0x0800) + ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP; + if (mixer_control & 0x1000) + ret |= MIX_AUXB_S; + if (mixer_control & 0x2000) + ret |= MIX_AUXB_S_RAMP; - // TODO: 0x4000 is used for Dolby Pro 2 sound mixing - } + // TODO: 0x4000 is used for Dolby Pro 2 sound mixing + } - return (AXMixControl)ret; + return (AXMixControl)ret; } void AXUCode::SetupProcessing(u32 init_addr) { - u16 init_data[0x20]; + u16 init_data[0x20]; - for (u32 i = 0; i < 0x20; ++i) - init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i); + for (u32 i = 0; i < 0x20; ++i) + init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i); - // List of all buffers we have to initialize - int* buffers[] = { - m_samples_left, - m_samples_right, - m_samples_surround, - m_samples_auxA_left, - m_samples_auxA_right, - m_samples_auxA_surround, - m_samples_auxB_left, - m_samples_auxB_right, - m_samples_auxB_surround - }; + // List of all buffers we have to initialize + int* buffers[] = {m_samples_left, m_samples_right, m_samples_surround, + m_samples_auxA_left, m_samples_auxA_right, m_samples_auxA_surround, + m_samples_auxB_left, m_samples_auxB_right, m_samples_auxB_surround}; - u32 init_idx = 0; - for (auto& buffer : buffers) - { - s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]); - s16 delta = (s16)init_data[init_idx + 2]; + u32 init_idx = 0; + for (auto& buffer : buffers) + { + s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]); + s16 delta = (s16)init_data[init_idx + 2]; - init_idx += 3; + init_idx += 3; - if (!init_val) - { - memset(buffer, 0, 5 * 32 * sizeof (int)); - } - else - { - for (u32 j = 0; j < 32 * 5; ++j) - { - buffer[j] = init_val; - init_val += delta; - } - } - } + if (!init_val) + { + memset(buffer, 0, 5 * 32 * sizeof(int)); + } + else + { + for (u32 j = 0; j < 32 * 5; ++j) + { + buffer[j] = init_val; + init_val += delta; + } + } + } } void AXUCode::DownloadAndMixWithVolume(u32 addr, u16 vol_main, u16 vol_auxa, u16 vol_auxb) { - int* buffers_main[3] = { m_samples_left, m_samples_right, m_samples_surround }; - int* buffers_auxa[3] = { m_samples_auxA_left, m_samples_auxA_right, m_samples_auxA_surround }; - int* buffers_auxb[3] = { m_samples_auxB_left, m_samples_auxB_right, m_samples_auxB_surround }; - int** buffers[3] = { buffers_main, buffers_auxa, buffers_auxb }; - u16 volumes[3] = { vol_main, vol_auxa, vol_auxb }; + int* buffers_main[3] = {m_samples_left, m_samples_right, m_samples_surround}; + int* buffers_auxa[3] = {m_samples_auxA_left, m_samples_auxA_right, m_samples_auxA_surround}; + int* buffers_auxb[3] = {m_samples_auxB_left, m_samples_auxB_right, m_samples_auxB_surround}; + int** buffers[3] = {buffers_main, buffers_auxa, buffers_auxb}; + u16 volumes[3] = {vol_main, vol_auxa, vol_auxb}; - for (u32 i = 0; i < 3; ++i) - { - int* ptr = (int*)HLEMemory_Get_Pointer(addr); - u16 volume = volumes[i]; - for (u32 j = 0; j < 3; ++j) - { - int* buffer = buffers[i][j]; - for (u32 k = 0; k < 5 * 32; ++k) - { - s64 sample = (s64)(s32)Common::swap32(*ptr++); - sample *= volume; - buffer[k] += (s32)(sample >> 15); - } - } - } + for (u32 i = 0; i < 3; ++i) + { + int* ptr = (int*)HLEMemory_Get_Pointer(addr); + u16 volume = volumes[i]; + for (u32 j = 0; j < 3; ++j) + { + int* buffer = buffers[i][j]; + for (u32 k = 0; k < 5 * 32; ++k) + { + s64 sample = (s64)(s32)Common::swap32(*ptr++); + sample *= volume; + buffer[k] += (s32)(sample >> 15); + } + } + } } void AXUCode::ProcessPBList(u32 pb_addr) { - // Samples per millisecond. In theory DSP sampling rate can be changed from - // 32KHz to 48KHz, but AX always process at 32KHz. - const u32 spms = 32; + // Samples per millisecond. In theory DSP sampling rate can be changed from + // 32KHz to 48KHz, but AX always process at 32KHz. + const u32 spms = 32; - AXPB pb; + AXPB pb; - while (pb_addr) - { - AXBuffers buffers = {{ - m_samples_left, - m_samples_right, - m_samples_surround, - m_samples_auxA_left, - m_samples_auxA_right, - m_samples_auxA_surround, - m_samples_auxB_left, - m_samples_auxB_right, - m_samples_auxB_surround - }}; + while (pb_addr) + { + AXBuffers buffers = {{m_samples_left, m_samples_right, m_samples_surround, m_samples_auxA_left, + m_samples_auxA_right, m_samples_auxA_surround, m_samples_auxB_left, + m_samples_auxB_right, m_samples_auxB_surround}}; - ReadPB(pb_addr, pb); + ReadPB(pb_addr, pb); - u32 updates_addr = HILO_TO_32(pb.updates.data); - u16* updates = (u16*)HLEMemory_Get_Pointer(updates_addr); + u32 updates_addr = HILO_TO_32(pb.updates.data); + u16* updates = (u16*)HLEMemory_Get_Pointer(updates_addr); - for (int curr_ms = 0; curr_ms < 5; ++curr_ms) - { - ApplyUpdatesForMs(curr_ms, (u16*)&pb, pb.updates.num_updates, updates); + for (int curr_ms = 0; curr_ms < 5; ++curr_ms) + { + ApplyUpdatesForMs(curr_ms, (u16*)&pb, pb.updates.num_updates, updates); - ProcessVoice(pb, buffers, spms, ConvertMixerControl(pb.mixer_control), - m_coeffs_available ? m_coeffs : nullptr); + ProcessVoice(pb, buffers, spms, ConvertMixerControl(pb.mixer_control), + m_coeffs_available ? m_coeffs : nullptr); - // Forward the buffers - for (size_t i = 0; i < ArraySize(buffers.ptrs); ++i) - buffers.ptrs[i] += spms; - } + // Forward the buffers + for (size_t i = 0; i < ArraySize(buffers.ptrs); ++i) + buffers.ptrs[i] += spms; + } - WritePB(pb_addr, pb); - pb_addr = HILO_TO_32(pb.next_pb); - } + WritePB(pb_addr, pb); + pb_addr = HILO_TO_32(pb.next_pb); + } } void AXUCode::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr) { - int* buffers[3] = { nullptr }; + int* buffers[3] = {nullptr}; - switch (aux_id) - { - case 0: - buffers[0] = m_samples_auxA_left; - buffers[1] = m_samples_auxA_right; - buffers[2] = m_samples_auxA_surround; - break; + switch (aux_id) + { + case 0: + buffers[0] = m_samples_auxA_left; + buffers[1] = m_samples_auxA_right; + buffers[2] = m_samples_auxA_surround; + break; - case 1: - buffers[0] = m_samples_auxB_left; - buffers[1] = m_samples_auxB_right; - buffers[2] = m_samples_auxB_surround; - break; - } + case 1: + buffers[0] = m_samples_auxB_left; + buffers[1] = m_samples_auxB_right; + buffers[2] = m_samples_auxB_surround; + break; + } - // First, we need to send the contents of our AUX buffers to the CPU. - if (write_addr) - { - int* ptr = (int*)HLEMemory_Get_Pointer(write_addr); - for (auto& buffer : buffers) - for (u32 j = 0; j < 5 * 32; ++j) - *ptr++ = Common::swap32(buffer[j]); - } + // First, we need to send the contents of our AUX buffers to the CPU. + if (write_addr) + { + int* ptr = (int*)HLEMemory_Get_Pointer(write_addr); + for (auto& buffer : buffers) + for (u32 j = 0; j < 5 * 32; ++j) + *ptr++ = Common::swap32(buffer[j]); + } - // Then, we read the new temp from the CPU and add to our current - // temp. - int* ptr = (int*)HLEMemory_Get_Pointer(read_addr); - for (auto& sample : m_samples_left) - sample += (int)Common::swap32(*ptr++); - for (auto& sample : m_samples_right) - sample += (int)Common::swap32(*ptr++); - for (auto& sample : m_samples_surround) - sample += (int)Common::swap32(*ptr++); + // Then, we read the new temp from the CPU and add to our current + // temp. + int* ptr = (int*)HLEMemory_Get_Pointer(read_addr); + for (auto& sample : m_samples_left) + sample += (int)Common::swap32(*ptr++); + for (auto& sample : m_samples_right) + sample += (int)Common::swap32(*ptr++); + for (auto& sample : m_samples_surround) + sample += (int)Common::swap32(*ptr++); } void AXUCode::UploadLRS(u32 dst_addr) { - int buffers[3][5 * 32]; + int buffers[3][5 * 32]; - for (u32 i = 0; i < 5 * 32; ++i) - { - buffers[0][i] = Common::swap32(m_samples_left[i]); - buffers[1][i] = Common::swap32(m_samples_right[i]); - buffers[2][i] = Common::swap32(m_samples_surround[i]); - } - memcpy(HLEMemory_Get_Pointer(dst_addr), buffers, sizeof (buffers)); + for (u32 i = 0; i < 5 * 32; ++i) + { + buffers[0][i] = Common::swap32(m_samples_left[i]); + buffers[1][i] = Common::swap32(m_samples_right[i]); + buffers[2][i] = Common::swap32(m_samples_surround[i]); + } + memcpy(HLEMemory_Get_Pointer(dst_addr), buffers, sizeof(buffers)); } void AXUCode::SetMainLR(u32 src_addr) { - int* ptr = (int*)HLEMemory_Get_Pointer(src_addr); - for (u32 i = 0; i < 5 * 32; ++i) - { - int samp = (int)Common::swap32(*ptr++); - m_samples_left[i] = samp; - m_samples_right[i] = samp; - m_samples_surround[i] = 0; - } + int* ptr = (int*)HLEMemory_Get_Pointer(src_addr); + for (u32 i = 0; i < 5 * 32; ++i) + { + int samp = (int)Common::swap32(*ptr++); + m_samples_left[i] = samp; + m_samples_right[i] = samp; + m_samples_surround[i] = 0; + } } void AXUCode::OutputSamples(u32 lr_addr, u32 surround_addr) { - int surround_buffer[5 * 32]; + int surround_buffer[5 * 32]; - for (u32 i = 0; i < 5 * 32; ++i) - surround_buffer[i] = Common::swap32(m_samples_surround[i]); - memcpy(HLEMemory_Get_Pointer(surround_addr), surround_buffer, sizeof (surround_buffer)); + for (u32 i = 0; i < 5 * 32; ++i) + surround_buffer[i] = Common::swap32(m_samples_surround[i]); + memcpy(HLEMemory_Get_Pointer(surround_addr), surround_buffer, sizeof(surround_buffer)); - // 32 samples per ms, 5 ms, 2 channels - short buffer[5 * 32 * 2]; + // 32 samples per ms, 5 ms, 2 channels + short buffer[5 * 32 * 2]; - // Output samples clamped to 16 bits and interlaced RLRLRLRLRL... - for (u32 i = 0; i < 5 * 32; ++i) - { - int left = MathUtil::Clamp(m_samples_left[i], -32767, 32767); - int right = MathUtil::Clamp(m_samples_right[i], -32767, 32767); + // Output samples clamped to 16 bits and interlaced RLRLRLRLRL... + for (u32 i = 0; i < 5 * 32; ++i) + { + int left = MathUtil::Clamp(m_samples_left[i], -32767, 32767); + int right = MathUtil::Clamp(m_samples_right[i], -32767, 32767); - buffer[2 * i + 0] = Common::swap16(right); - buffer[2 * i + 1] = Common::swap16(left); - } + buffer[2 * i + 0] = Common::swap16(right); + buffer[2 * i + 1] = Common::swap16(left); + } - memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer)); + memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof(buffer)); } void AXUCode::MixAUXBLR(u32 ul_addr, u32 dl_addr) { - // Upload AUXB L/R - int* ptr = (int*)HLEMemory_Get_Pointer(ul_addr); - for (auto& sample : m_samples_auxB_left) - *ptr++ = Common::swap32(sample); - for (auto& sample : m_samples_auxB_right) - *ptr++ = Common::swap32(sample); + // Upload AUXB L/R + int* ptr = (int*)HLEMemory_Get_Pointer(ul_addr); + for (auto& sample : m_samples_auxB_left) + *ptr++ = Common::swap32(sample); + for (auto& sample : m_samples_auxB_right) + *ptr++ = Common::swap32(sample); - // Mix AUXB L/R to MAIN L/R, and replace AUXB L/R - ptr = (int*)HLEMemory_Get_Pointer(dl_addr); - for (u32 i = 0; i < 5 * 32; ++i) - { - int samp = Common::swap32(*ptr++); - m_samples_auxB_left[i] = samp; - m_samples_left[i] += samp; - } - for (u32 i = 0; i < 5 * 32; ++i) - { - int samp = Common::swap32(*ptr++); - m_samples_auxB_right[i] = samp; - m_samples_right[i] += samp; - } + // Mix AUXB L/R to MAIN L/R, and replace AUXB L/R + ptr = (int*)HLEMemory_Get_Pointer(dl_addr); + for (u32 i = 0; i < 5 * 32; ++i) + { + int samp = Common::swap32(*ptr++); + m_samples_auxB_left[i] = samp; + m_samples_left[i] += samp; + } + for (u32 i = 0; i < 5 * 32; ++i) + { + int samp = Common::swap32(*ptr++); + m_samples_auxB_right[i] = samp; + m_samples_right[i] += samp; + } } void AXUCode::SetOppositeLR(u32 src_addr) { - int* ptr = (int*)HLEMemory_Get_Pointer(src_addr); - for (u32 i = 0; i < 5 * 32; ++i) - { - int inp = Common::swap32(*ptr++); - m_samples_left[i] = -inp; - m_samples_right[i] = inp; - m_samples_surround[i] = 0; - } + int* ptr = (int*)HLEMemory_Get_Pointer(src_addr); + for (u32 i = 0; i < 5 * 32; ++i) + { + int inp = Common::swap32(*ptr++); + m_samples_left[i] = -inp; + m_samples_right[i] = inp; + m_samples_surround[i] = 0; + } } -void AXUCode::SendAUXAndMix(u32 main_auxa_up, u32 auxb_s_up, u32 main_l_dl, - u32 main_r_dl, u32 auxb_l_dl, u32 auxb_r_dl) +void AXUCode::SendAUXAndMix(u32 main_auxa_up, u32 auxb_s_up, u32 main_l_dl, u32 main_r_dl, + u32 auxb_l_dl, u32 auxb_r_dl) { - // Buffers to upload first - int* up_buffers[] = { - m_samples_auxA_left, - m_samples_auxA_right, - m_samples_auxA_surround - }; + // Buffers to upload first + int* up_buffers[] = {m_samples_auxA_left, m_samples_auxA_right, m_samples_auxA_surround}; - // Upload AUXA LRS - int* ptr = (int*)HLEMemory_Get_Pointer(main_auxa_up); - for (auto& up_buffer : up_buffers) - for (u32 j = 0; j < 32 * 5; ++j) - *ptr++ = Common::swap32(up_buffer[j]); + // Upload AUXA LRS + int* ptr = (int*)HLEMemory_Get_Pointer(main_auxa_up); + for (auto& up_buffer : up_buffers) + for (u32 j = 0; j < 32 * 5; ++j) + *ptr++ = Common::swap32(up_buffer[j]); - // Upload AUXB S - ptr = (int*)HLEMemory_Get_Pointer(auxb_s_up); - for (auto& sample : m_samples_auxB_surround) - *ptr++ = Common::swap32(sample); + // Upload AUXB S + ptr = (int*)HLEMemory_Get_Pointer(auxb_s_up); + for (auto& sample : m_samples_auxB_surround) + *ptr++ = Common::swap32(sample); - // Download buffers and addresses - int* dl_buffers[] = { - m_samples_left, - m_samples_right, - m_samples_auxB_left, - m_samples_auxB_right - }; - u32 dl_addrs[] = { - main_l_dl, - main_r_dl, - auxb_l_dl, - auxb_r_dl - }; + // Download buffers and addresses + int* dl_buffers[] = {m_samples_left, m_samples_right, m_samples_auxB_left, m_samples_auxB_right}; + u32 dl_addrs[] = {main_l_dl, main_r_dl, auxb_l_dl, auxb_r_dl}; - // Download and mix - for (size_t i = 0; i < ArraySize(dl_buffers); ++i) - { - int* dl_src = (int*)HLEMemory_Get_Pointer(dl_addrs[i]); - for (size_t j = 0; j < 32 * 5; ++j) - dl_buffers[i][j] += (int)Common::swap32(*dl_src++); - } + // Download and mix + for (size_t i = 0; i < ArraySize(dl_buffers); ++i) + { + int* dl_src = (int*)HLEMemory_Get_Pointer(dl_addrs[i]); + for (size_t j = 0; j < 32 * 5; ++j) + dl_buffers[i][j] += (int)Common::swap32(*dl_src++); + } } void AXUCode::HandleMail(u32 mail) { - // Indicates if the next message is a command list address. - static bool next_is_cmdlist = false; - static u16 cmdlist_size = 0; + // Indicates if the next message is a command list address. + static bool next_is_cmdlist = false; + static u16 cmdlist_size = 0; - bool set_next_is_cmdlist = false; + bool set_next_is_cmdlist = false; - if (next_is_cmdlist) - { - CopyCmdList(mail, cmdlist_size); - HandleCommandList(); - m_cmdlist_size = 0; - SignalWorkEnd(); - } - else if (m_upload_setup_in_progress) - { - PrepareBootUCode(mail); - } - else if (mail == MAIL_RESUME) - { - // Acknowledge the resume request - m_mail_handler.PushMail(DSP_RESUME); - DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); - } - else if (mail == MAIL_NEW_UCODE) - { - m_upload_setup_in_progress = true; - } - else if (mail == MAIL_RESET) - { - m_dsphle->SetUCode(UCODE_ROM); - } - else if (mail == MAIL_CONTINUE) - { - // We don't have to do anything here - the CPU does not wait for a ACK - // and sends a cmdlist mail just after. - } - else if ((mail & MAIL_CMDLIST_MASK) == MAIL_CMDLIST) - { - // A command list address is going to be sent next. - set_next_is_cmdlist = true; - cmdlist_size = (u16)(mail & ~MAIL_CMDLIST_MASK); - } - else - { - ERROR_LOG(DSPHLE, "Unknown mail sent to AX::HandleMail: %08x", mail); - } + if (next_is_cmdlist) + { + CopyCmdList(mail, cmdlist_size); + HandleCommandList(); + m_cmdlist_size = 0; + SignalWorkEnd(); + } + else if (m_upload_setup_in_progress) + { + PrepareBootUCode(mail); + } + else if (mail == MAIL_RESUME) + { + // Acknowledge the resume request + m_mail_handler.PushMail(DSP_RESUME); + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + } + else if (mail == MAIL_NEW_UCODE) + { + m_upload_setup_in_progress = true; + } + else if (mail == MAIL_RESET) + { + m_dsphle->SetUCode(UCODE_ROM); + } + else if (mail == MAIL_CONTINUE) + { + // We don't have to do anything here - the CPU does not wait for a ACK + // and sends a cmdlist mail just after. + } + else if ((mail & MAIL_CMDLIST_MASK) == MAIL_CMDLIST) + { + // A command list address is going to be sent next. + set_next_is_cmdlist = true; + cmdlist_size = (u16)(mail & ~MAIL_CMDLIST_MASK); + } + else + { + ERROR_LOG(DSPHLE, "Unknown mail sent to AX::HandleMail: %08x", mail); + } - next_is_cmdlist = set_next_is_cmdlist; + next_is_cmdlist = set_next_is_cmdlist; } void AXUCode::CopyCmdList(u32 addr, u16 size) { - if (size >= ArraySize(m_cmdlist)) - { - ERROR_LOG(DSPHLE, "Command list at %08x is too large: size=%d", addr, size); - return; - } + if (size >= ArraySize(m_cmdlist)) + { + ERROR_LOG(DSPHLE, "Command list at %08x is too large: size=%d", addr, size); + return; + } - for (u32 i = 0; i < size; ++i, addr += 2) - m_cmdlist[i] = HLEMemory_Read_U16(addr); - m_cmdlist_size = size; + for (u32 i = 0; i < size; ++i, addr += 2) + m_cmdlist[i] = HLEMemory_Read_U16(addr); + m_cmdlist_size = size; } void AXUCode::Update() { - // Used for UCode switching. - if (NeedsResumeMail()) - { - m_mail_handler.PushMail(DSP_RESUME); - DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); - } + // Used for UCode switching. + if (NeedsResumeMail()) + { + m_mail_handler.PushMail(DSP_RESUME); + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + } } void AXUCode::DoAXState(PointerWrap& p) { - p.Do(m_cmdlist); - p.Do(m_cmdlist_size); + p.Do(m_cmdlist); + p.Do(m_cmdlist_size); - p.Do(m_samples_left); - p.Do(m_samples_right); - p.Do(m_samples_surround); - p.Do(m_samples_auxA_left); - p.Do(m_samples_auxA_right); - p.Do(m_samples_auxA_surround); - p.Do(m_samples_auxB_left); - p.Do(m_samples_auxB_right); - p.Do(m_samples_auxB_surround); + p.Do(m_samples_left); + p.Do(m_samples_right); + p.Do(m_samples_surround); + p.Do(m_samples_auxA_left); + p.Do(m_samples_auxA_right); + p.Do(m_samples_auxA_surround); + p.Do(m_samples_auxB_left); + p.Do(m_samples_auxB_right); + p.Do(m_samples_auxB_surround); } void AXUCode::DoState(PointerWrap& p) { - DoStateShared(p); - DoAXState(p); + DoStateShared(p); + DoAXState(p); } diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AX.h b/Source/Core/Core/HW/DSPHLE/UCodes/AX.h index 962857cdbc..0f00fc9328 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AX.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AX.h @@ -20,131 +20,131 @@ // mixer_control value to an AXMixControl bitfield. enum AXMixControl { - MIX_L = 0x000001, - MIX_L_RAMP = 0x000002, - MIX_R = 0x000004, - MIX_R_RAMP = 0x000008, - MIX_S = 0x000010, - MIX_S_RAMP = 0x000020, + MIX_L = 0x000001, + MIX_L_RAMP = 0x000002, + MIX_R = 0x000004, + MIX_R_RAMP = 0x000008, + MIX_S = 0x000010, + MIX_S_RAMP = 0x000020, - MIX_AUXA_L = 0x000040, - MIX_AUXA_L_RAMP = 0x000080, - MIX_AUXA_R = 0x000100, - MIX_AUXA_R_RAMP = 0x000200, - MIX_AUXA_S = 0x000400, - MIX_AUXA_S_RAMP = 0x000800, + MIX_AUXA_L = 0x000040, + MIX_AUXA_L_RAMP = 0x000080, + MIX_AUXA_R = 0x000100, + MIX_AUXA_R_RAMP = 0x000200, + MIX_AUXA_S = 0x000400, + MIX_AUXA_S_RAMP = 0x000800, - MIX_AUXB_L = 0x001000, - MIX_AUXB_L_RAMP = 0x002000, - MIX_AUXB_R = 0x004000, - MIX_AUXB_R_RAMP = 0x008000, - MIX_AUXB_S = 0x010000, - MIX_AUXB_S_RAMP = 0x020000, + MIX_AUXB_L = 0x001000, + MIX_AUXB_L_RAMP = 0x002000, + MIX_AUXB_R = 0x004000, + MIX_AUXB_R_RAMP = 0x008000, + MIX_AUXB_S = 0x010000, + MIX_AUXB_S_RAMP = 0x020000, - MIX_AUXC_L = 0x040000, - MIX_AUXC_L_RAMP = 0x080000, - MIX_AUXC_R = 0x100000, - MIX_AUXC_R_RAMP = 0x200000, - MIX_AUXC_S = 0x400000, - MIX_AUXC_S_RAMP = 0x800000 + MIX_AUXC_L = 0x040000, + MIX_AUXC_L_RAMP = 0x080000, + MIX_AUXC_R = 0x100000, + MIX_AUXC_R_RAMP = 0x200000, + MIX_AUXC_S = 0x400000, + MIX_AUXC_S_RAMP = 0x800000 }; class AXUCode : public UCodeInterface { public: - AXUCode(DSPHLE* dsphle, u32 crc); - virtual ~AXUCode(); + AXUCode(DSPHLE* dsphle, u32 crc); + virtual ~AXUCode(); - void HandleMail(u32 mail) override; - void Update() override; - void DoState(PointerWrap& p) override; + void HandleMail(u32 mail) override; + void Update() override; + void DoState(PointerWrap& p) override; protected: - enum MailType - { - MAIL_RESUME = 0xCDD10000, - MAIL_NEW_UCODE = 0xCDD10001, - MAIL_RESET = 0xCDD10002, - MAIL_CONTINUE = 0xCDD10003, + enum MailType + { + MAIL_RESUME = 0xCDD10000, + MAIL_NEW_UCODE = 0xCDD10001, + MAIL_RESET = 0xCDD10002, + MAIL_CONTINUE = 0xCDD10003, - // CPU sends 0xBABE0000 | cmdlist_size to the DSP - MAIL_CMDLIST = 0xBABE0000, - MAIL_CMDLIST_MASK = 0xFFFF0000 - }; + // CPU sends 0xBABE0000 | cmdlist_size to the DSP + MAIL_CMDLIST = 0xBABE0000, + MAIL_CMDLIST_MASK = 0xFFFF0000 + }; - // 32 * 5 because 32 samples per millisecond, for max 5 milliseconds. - int m_samples_left[32 * 5]; - int m_samples_right[32 * 5]; - int m_samples_surround[32 * 5]; - int m_samples_auxA_left[32 * 5]; - int m_samples_auxA_right[32 * 5]; - int m_samples_auxA_surround[32 * 5]; - int m_samples_auxB_left[32 * 5]; - int m_samples_auxB_right[32 * 5]; - int m_samples_auxB_surround[32 * 5]; + // 32 * 5 because 32 samples per millisecond, for max 5 milliseconds. + int m_samples_left[32 * 5]; + int m_samples_right[32 * 5]; + int m_samples_surround[32 * 5]; + int m_samples_auxA_left[32 * 5]; + int m_samples_auxA_right[32 * 5]; + int m_samples_auxA_surround[32 * 5]; + int m_samples_auxB_left[32 * 5]; + int m_samples_auxB_right[32 * 5]; + int m_samples_auxB_surround[32 * 5]; - u16 m_cmdlist[512]; - u32 m_cmdlist_size; + u16 m_cmdlist[512]; + u32 m_cmdlist_size; - // Table of coefficients for polyphase sample rate conversion. - // The coefficients aren't always available (they are part of the DSP DROM) - // so we also need to know if they are valid or not. - bool m_coeffs_available; - s16 m_coeffs[0x800]; + // Table of coefficients for polyphase sample rate conversion. + // The coefficients aren't always available (they are part of the DSP DROM) + // so we also need to know if they are valid or not. + bool m_coeffs_available; + s16 m_coeffs[0x800]; - void LoadResamplingCoefficients(); + void LoadResamplingCoefficients(); - // Copy a command list from memory to our temp buffer - void CopyCmdList(u32 addr, u16 size); + // Copy a command list from memory to our temp buffer + void CopyCmdList(u32 addr, u16 size); - // Convert a mixer_control bitfield to our internal representation for that - // value. Required because that bitfield has a different meaning in some - // versions of AX. - AXMixControl ConvertMixerControl(u32 mixer_control); + // Convert a mixer_control bitfield to our internal representation for that + // value. Required because that bitfield has a different meaning in some + // versions of AX. + AXMixControl ConvertMixerControl(u32 mixer_control); - // Apply updates to a PB. Generic, used in AX GC and AX Wii. - void ApplyUpdatesForMs(int curr_ms, u16* pb, u16* num_updates, u16* updates); + // Apply updates to a PB. Generic, used in AX GC and AX Wii. + void ApplyUpdatesForMs(int curr_ms, u16* pb, u16* num_updates, u16* updates); - virtual void HandleCommandList(); - void SignalWorkEnd(); + virtual void HandleCommandList(); + void SignalWorkEnd(); - void SetupProcessing(u32 init_addr); - void DownloadAndMixWithVolume(u32 addr, u16 vol_main, u16 vol_auxa, u16 vol_auxb); - void ProcessPBList(u32 pb_addr); - void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr); - void UploadLRS(u32 dst_addr); - void SetMainLR(u32 src_addr); - void OutputSamples(u32 out_addr, u32 surround_addr); - void MixAUXBLR(u32 ul_addr, u32 dl_addr); - void SetOppositeLR(u32 src_addr); - void SendAUXAndMix(u32 main_auxa_up, u32 auxb_s_up, u32 main_l_dl, - u32 main_r_dl, u32 auxb_l_dl, u32 auxb_r_dl); + void SetupProcessing(u32 init_addr); + void DownloadAndMixWithVolume(u32 addr, u16 vol_main, u16 vol_auxa, u16 vol_auxb); + void ProcessPBList(u32 pb_addr); + void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr); + void UploadLRS(u32 dst_addr); + void SetMainLR(u32 src_addr); + void OutputSamples(u32 out_addr, u32 surround_addr); + void MixAUXBLR(u32 ul_addr, u32 dl_addr); + void SetOppositeLR(u32 src_addr); + void SendAUXAndMix(u32 main_auxa_up, u32 auxb_s_up, u32 main_l_dl, u32 main_r_dl, u32 auxb_l_dl, + u32 auxb_r_dl); - // Handle save states for main AX. - void DoAXState(PointerWrap& p); + // Handle save states for main AX. + void DoAXState(PointerWrap& p); private: - enum CmdType - { - CMD_SETUP = 0x00, - CMD_DL_AND_VOL_MIX = 0x01, - CMD_PB_ADDR = 0x02, - CMD_PROCESS = 0x03, - CMD_MIX_AUXA = 0x04, - CMD_MIX_AUXB = 0x05, - CMD_UPLOAD_LRS = 0x06, - CMD_SET_LR = 0x07, - CMD_UNK_08 = 0x08, - CMD_MIX_AUXB_NOWRITE = 0x09, - CMD_COMPRESSOR_TABLE_ADDR = 0x0A, - CMD_UNK_0B = 0x0B, - CMD_UNK_0C = 0x0C, - CMD_MORE = 0x0D, - CMD_OUTPUT = 0x0E, - CMD_END = 0x0F, - CMD_MIX_AUXB_LR = 0x10, - CMD_SET_OPPOSITE_LR = 0x11, - CMD_UNK_12 = 0x12, - CMD_SEND_AUX_AND_MIX = 0x13, - }; + enum CmdType + { + CMD_SETUP = 0x00, + CMD_DL_AND_VOL_MIX = 0x01, + CMD_PB_ADDR = 0x02, + CMD_PROCESS = 0x03, + CMD_MIX_AUXA = 0x04, + CMD_MIX_AUXB = 0x05, + CMD_UPLOAD_LRS = 0x06, + CMD_SET_LR = 0x07, + CMD_UNK_08 = 0x08, + CMD_MIX_AUXB_NOWRITE = 0x09, + CMD_COMPRESSOR_TABLE_ADDR = 0x0A, + CMD_UNK_0B = 0x0B, + CMD_UNK_0C = 0x0C, + CMD_MORE = 0x0D, + CMD_OUTPUT = 0x0E, + CMD_END = 0x0F, + CMD_MIX_AUXB_LR = 0x10, + CMD_SET_OPPOSITE_LR = 0x11, + CMD_UNK_12 = 0x12, + CMD_SEND_AUX_AND_MIX = 0x13, + }; }; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AXStructs.h b/Source/Core/Core/HW/DSPHLE/UCodes/AXStructs.h index e6ab2c1d88..f13dee120f 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AXStructs.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AXStructs.h @@ -8,96 +8,96 @@ struct PBMixer { - u16 left; - u16 left_delta; - u16 right; - u16 right_delta; + u16 left; + u16 left_delta; + u16 right; + u16 right_delta; - u16 auxA_left; - u16 auxA_left_delta; - u16 auxA_right; - u16 auxA_right_delta; + u16 auxA_left; + u16 auxA_left_delta; + u16 auxA_right; + u16 auxA_right_delta; - u16 auxB_left; - u16 auxB_left_delta; - u16 auxB_right; - u16 auxB_right_delta; + u16 auxB_left; + u16 auxB_left_delta; + u16 auxB_right; + u16 auxB_right_delta; - u16 auxB_surround; - u16 auxB_surround_delta; - u16 surround; - u16 surround_delta; - u16 auxA_surround; - u16 auxA_surround_delta; + u16 auxB_surround; + u16 auxB_surround_delta; + u16 surround; + u16 surround_delta; + u16 auxA_surround; + u16 auxA_surround_delta; }; struct PBMixerWii { - // volume mixing values in .15, 0x8000 = ca. 1.0 - u16 left; - u16 left_delta; - u16 right; - u16 right_delta; + // volume mixing values in .15, 0x8000 = ca. 1.0 + u16 left; + u16 left_delta; + u16 right; + u16 right_delta; - u16 auxA_left; - u16 auxA_left_delta; - u16 auxA_right; - u16 auxA_right_delta; + u16 auxA_left; + u16 auxA_left_delta; + u16 auxA_right; + u16 auxA_right_delta; - u16 auxB_left; - u16 auxB_left_delta; - u16 auxB_right; - u16 auxB_right_delta; + u16 auxB_left; + u16 auxB_left_delta; + u16 auxB_right; + u16 auxB_right_delta; - // Note: the following elements usage changes a little in DPL2 mode - // TODO: implement and comment it in the mixer - u16 auxC_left; - u16 auxC_left_delta; - u16 auxC_right; - u16 auxC_right_delta; + // Note: the following elements usage changes a little in DPL2 mode + // TODO: implement and comment it in the mixer + u16 auxC_left; + u16 auxC_left_delta; + u16 auxC_right; + u16 auxC_right_delta; - u16 surround; - u16 surround_delta; - u16 auxA_surround; - u16 auxA_surround_delta; - u16 auxB_surround; - u16 auxB_surround_delta; - u16 auxC_surround; - u16 auxC_surround_delta; + u16 surround; + u16 surround_delta; + u16 auxA_surround; + u16 auxA_surround_delta; + u16 auxB_surround; + u16 auxB_surround_delta; + u16 auxC_surround; + u16 auxC_surround_delta; }; struct PBMixerWM { - u16 main0; - u16 main0_delta; - u16 aux0; - u16 aux0_delta; + u16 main0; + u16 main0_delta; + u16 aux0; + u16 aux0_delta; - u16 main1; - u16 main1_delta; - u16 aux1; - u16 aux1_delta; + u16 main1; + u16 main1_delta; + u16 aux1; + u16 aux1_delta; - u16 main2; - u16 main2_delta; - u16 aux2; - u16 aux2_delta; + u16 main2; + u16 main2_delta; + u16 aux2; + u16 aux2_delta; - u16 main3; - u16 main3_delta; - u16 aux3; - u16 aux3_delta; + u16 main3; + u16 main3_delta; + u16 aux3; + u16 aux3_delta; }; struct PBInitialTimeDelay { - u16 on; - u16 addrMemHigh; - u16 addrMemLow; - u16 offsetLeft; - u16 offsetRight; - u16 targetLeft; - u16 targetRight; + u16 on; + u16 addrMemHigh; + u16 addrMemLow; + u16 offsetLeft; + u16 offsetRight; + u16 targetLeft; + u16 targetRight; }; // Update data - read these each 1ms subframe and use them! @@ -106,9 +106,9 @@ struct PBInitialTimeDelay // Using this data should fix games that are missing MIDI notes. struct PBUpdates { - u16 num_updates[5]; - u16 data_hi; // These point to main RAM. Not sure about the structure of the data. - u16 data_lo; + u16 num_updates[5]; + u16 data_hi; // These point to main RAM. Not sure about the structure of the data. + u16 data_lo; }; // The DSP stores the final sample values for each voice after every frame of processing. @@ -116,220 +116,218 @@ struct PBUpdates // and ramped down on a per-sample basis to provide a gentle "roll off." struct PBDpop { - s16 left; - s16 auxA_left; - s16 auxB_left; + s16 left; + s16 auxA_left; + s16 auxB_left; - s16 right; - s16 auxA_right; - s16 auxB_right; + s16 right; + s16 auxA_right; + s16 auxB_right; - s16 surround; - s16 auxA_surround; - s16 auxB_surround; + s16 surround; + s16 auxA_surround; + s16 auxB_surround; }; struct PBDpopWii { - s16 left; - s16 auxA_left; - s16 auxB_left; - s16 auxC_left; + s16 left; + s16 auxA_left; + s16 auxB_left; + s16 auxC_left; - s16 right; - s16 auxA_right; - s16 auxB_right; - s16 auxC_right; + s16 right; + s16 auxA_right; + s16 auxB_right; + s16 auxC_right; - s16 surround; - s16 auxA_surround; - s16 auxB_surround; - s16 auxC_surround; + s16 surround; + s16 auxA_surround; + s16 auxB_surround; + s16 auxC_surround; }; struct PBDpopWM { - s16 main0; - s16 main1; - s16 main2; - s16 main3; + s16 main0; + s16 main1; + s16 main2; + s16 main3; - s16 aux0; - s16 aux1; - s16 aux2; - s16 aux3; + s16 aux0; + s16 aux1; + s16 aux2; + s16 aux3; }; struct PBVolumeEnvelope { - u16 cur_volume; // Volume at start of frame - s16 cur_volume_delta; // Signed per sample delta (96 samples per frame) + u16 cur_volume; // Volume at start of frame + s16 cur_volume_delta; // Signed per sample delta (96 samples per frame) }; struct PBUnknown2 { - u16 unknown_reserved[3]; + u16 unknown_reserved[3]; }; struct PBAudioAddr { - u16 looping; - u16 sample_format; - u16 loop_addr_hi; // Start of loop (this will point to a shared "zero" buffer if one-shot mode is active) - u16 loop_addr_lo; - u16 end_addr_hi; // End of sample (and loop), inclusive - u16 end_addr_lo; - u16 cur_addr_hi; - u16 cur_addr_lo; + u16 looping; + u16 sample_format; + u16 loop_addr_hi; // Start of loop (this will point to a shared "zero" buffer if one-shot mode is + // active) + u16 loop_addr_lo; + u16 end_addr_hi; // End of sample (and loop), inclusive + u16 end_addr_lo; + u16 cur_addr_hi; + u16 cur_addr_lo; }; struct PBADPCMInfo { - s16 coefs[16]; - u16 gain; - u16 pred_scale; - s16 yn1; - s16 yn2; + s16 coefs[16]; + u16 gain; + u16 pred_scale; + s16 yn1; + s16 yn2; }; struct PBSampleRateConverter { - // ratio = (f32)ratio * 0x10000; - // valid range is 1/512 to 4.0000 - u16 ratio_hi; // integer part of sampling ratio - u16 ratio_lo; // fraction part of sampling ratio - u16 cur_addr_frac; - s16 last_samples[4]; + // ratio = (f32)ratio * 0x10000; + // valid range is 1/512 to 4.0000 + u16 ratio_hi; // integer part of sampling ratio + u16 ratio_lo; // fraction part of sampling ratio + u16 cur_addr_frac; + s16 last_samples[4]; }; struct PBSampleRateConverterWM { - u16 cur_addr_frac; - s16 last_samples[4]; + u16 cur_addr_frac; + s16 last_samples[4]; }; struct PBADPCMLoopInfo { - u16 pred_scale; - u16 yn1; - u16 yn2; + u16 pred_scale; + u16 yn1; + u16 yn2; }; struct PBLowPassFilter { - u16 enabled; - s16 yn1; - u16 a0; - u16 b0; + u16 enabled; + s16 yn1; + u16 a0; + u16 b0; }; struct AXPB { - u16 next_pb_hi; - u16 next_pb_lo; - u16 this_pb_hi; - u16 this_pb_lo; + u16 next_pb_hi; + u16 next_pb_lo; + u16 this_pb_hi; + u16 this_pb_lo; - u16 src_type; // Type of sample rate converter (none, ?, linear) - u16 coef_select; - u16 mixer_control; + u16 src_type; // Type of sample rate converter (none, ?, linear) + u16 coef_select; + u16 mixer_control; - u16 running; // 1=RUN 0=STOP - u16 is_stream; // 1 = stream, 0 = one shot + u16 running; // 1=RUN 0=STOP + u16 is_stream; // 1 = stream, 0 = one shot - PBMixer mixer; - PBInitialTimeDelay initial_time_delay; - PBUpdates updates; - PBDpop dpop; - PBVolumeEnvelope vol_env; - PBUnknown2 unknown3; - PBAudioAddr audio_addr; - PBADPCMInfo adpcm; - PBSampleRateConverter src; - PBADPCMLoopInfo adpcm_loop_info; - PBLowPassFilter lpf; + PBMixer mixer; + PBInitialTimeDelay initial_time_delay; + PBUpdates updates; + PBDpop dpop; + PBVolumeEnvelope vol_env; + PBUnknown2 unknown3; + PBAudioAddr audio_addr; + PBADPCMInfo adpcm; + PBSampleRateConverter src; + PBADPCMLoopInfo adpcm_loop_info; + PBLowPassFilter lpf; - u16 padding[25]; + u16 padding[25]; }; struct PBBiquadFilter { - - u16 on; // on = 2, off = 0 - u16 xn1; // History data - u16 xn2; - u16 yn1; - u16 yn2; - u16 b0; // Filter coefficients - u16 b1; - u16 b2; - u16 a1; - u16 a2; - + u16 on; // on = 2, off = 0 + u16 xn1; // History data + u16 xn2; + u16 yn1; + u16 yn2; + u16 b0; // Filter coefficients + u16 b1; + u16 b2; + u16 a1; + u16 a2; }; -union PBInfImpulseResponseWM -{ - PBLowPassFilter lpf; - PBBiquadFilter biquad; +union PBInfImpulseResponseWM { + PBLowPassFilter lpf; + PBBiquadFilter biquad; }; struct AXPBWii { - u16 next_pb_hi; - u16 next_pb_lo; - u16 this_pb_hi; - u16 this_pb_lo; + u16 next_pb_hi; + u16 next_pb_lo; + u16 this_pb_hi; + u16 this_pb_lo; - u16 src_type; // Type of sample rate converter (none, 4-tap, linear) - u16 coef_select; // coef for the 4-tap src - u16 mixer_control_hi; - u16 mixer_control_lo; + u16 src_type; // Type of sample rate converter (none, 4-tap, linear) + u16 coef_select; // coef for the 4-tap src + u16 mixer_control_hi; + u16 mixer_control_lo; - u16 running; // 1=RUN 0=STOP - u16 is_stream; // 1 = stream, 0 = one shot + u16 running; // 1=RUN 0=STOP + u16 is_stream; // 1 = stream, 0 = one shot - PBMixerWii mixer; - PBInitialTimeDelay initial_time_delay; - PBDpopWii dpop; - PBVolumeEnvelope vol_env; - PBAudioAddr audio_addr; - PBADPCMInfo adpcm; - PBSampleRateConverter src; - PBADPCMLoopInfo adpcm_loop_info; - PBLowPassFilter lpf; - PBBiquadFilter biquad; + PBMixerWii mixer; + PBInitialTimeDelay initial_time_delay; + PBDpopWii dpop; + PBVolumeEnvelope vol_env; + PBAudioAddr audio_addr; + PBADPCMInfo adpcm; + PBSampleRateConverter src; + PBADPCMLoopInfo adpcm_loop_info; + PBLowPassFilter lpf; + PBBiquadFilter biquad; - // WIIMOTE :D - u16 remote; - u16 remote_mixer_control; + // WIIMOTE :D + u16 remote; + u16 remote_mixer_control; - PBMixerWM remote_mixer; - PBDpopWM remote_dpop; - PBSampleRateConverterWM remote_src; - PBInfImpulseResponseWM remote_iir; + PBMixerWM remote_mixer; + PBDpopWM remote_dpop; + PBSampleRateConverterWM remote_src; + PBInfImpulseResponseWM remote_iir; - u16 pad[12]; // align us, captain! (32B) + u16 pad[12]; // align us, captain! (32B) }; // TODO: All these enums have changed a lot for Wii enum { - AUDIOFORMAT_ADPCM = 0, - AUDIOFORMAT_PCM8 = 0x19, - AUDIOFORMAT_PCM16 = 0xA, + AUDIOFORMAT_ADPCM = 0, + AUDIOFORMAT_PCM8 = 0x19, + AUDIOFORMAT_PCM16 = 0xA, }; enum { - SRCTYPE_POLYPHASE = 0, - SRCTYPE_LINEAR = 1, - SRCTYPE_NEAREST = 2, + SRCTYPE_POLYPHASE = 0, + SRCTYPE_LINEAR = 1, + SRCTYPE_NEAREST = 2, }; // Both may be used at once enum { - FILTER_LOWPASS = 1, - FILTER_BIQUAD = 2, + FILTER_LOWPASS = 1, + FILTER_BIQUAD = 2, }; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AXVoice.h b/Source/Core/Core/HW/DSPHLE/UCodes/AXVoice.h index 684aa2c16e..4795cbf77a 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AXVoice.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AXVoice.h @@ -17,78 +17,76 @@ #include "Common/CommonTypes.h" #include "Common/MathUtil.h" #include "Core/HW/DSP.h" -#include "Core/HW/Memmap.h" #include "Core/HW/DSPHLE/UCodes/AX.h" #include "Core/HW/DSPHLE/UCodes/AXStructs.h" +#include "Core/HW/Memmap.h" #ifdef AX_GC -# define PB_TYPE AXPB -# define MAX_SAMPLES_PER_FRAME 32 +#define PB_TYPE AXPB +#define MAX_SAMPLES_PER_FRAME 32 #else -# define PB_TYPE AXPBWii -# define MAX_SAMPLES_PER_FRAME 96 +#define PB_TYPE AXPBWii +#define MAX_SAMPLES_PER_FRAME 96 #endif // Put all of that in an anonymous namespace to avoid stupid compilers merging // functions from AX GC and AX Wii. -namespace { - +namespace +{ // Useful macro to convert xxx_hi + xxx_lo to xxx for 32 bits. -#define HILO_TO_32(name) \ - ((name##_hi << 16) | name##_lo) +#define HILO_TO_32(name) ((name##_hi << 16) | name##_lo) // Used to pass a large amount of buffers to the mixing function. -union AXBuffers -{ - struct - { - int* left; - int* right; - int* surround; +union AXBuffers { + struct + { + int* left; + int* right; + int* surround; - int* auxA_left; - int* auxA_right; - int* auxA_surround; + int* auxA_left; + int* auxA_right; + int* auxA_surround; - int* auxB_left; - int* auxB_right; - int* auxB_surround; + int* auxB_left; + int* auxB_right; + int* auxB_surround; #ifdef AX_WII - int* auxC_left; - int* auxC_right; - int* auxC_surround; + int* auxC_left; + int* auxC_right; + int* auxC_surround; - int* wm_main0; - int* wm_aux0; - int* wm_main1; - int* wm_aux1; - int* wm_main2; - int* wm_aux2; - int* wm_main3; - int* wm_aux3; + int* wm_main0; + int* wm_aux0; + int* wm_main1; + int* wm_aux1; + int* wm_main2; + int* wm_aux2; + int* wm_main3; + int* wm_aux3; #endif - }; + }; #ifdef AX_GC - int* ptrs[9]; + int* ptrs[9]; #else - int* ptrs[20]; + int* ptrs[20]; #endif }; // Read a PB from MRAM/ARAM void ReadPB(u32 addr, PB_TYPE& pb) { - u16* dst = (u16*)&pb; - Memory::CopyFromEmuSwapped(dst, addr, sizeof(pb)); + u16* dst = (u16*)&pb; + Memory::CopyFromEmuSwapped(dst, addr, sizeof(pb)); } // Write a PB back to MRAM/ARAM void WritePB(u32 addr, const PB_TYPE& pb) { - const u16* src = (const u16*)&pb; - Memory::CopyToEmuSwapped(addr, src, sizeof(pb)); + const u16* src = (const u16*)&pb; + Memory::CopyToEmuSwapped(addr, src, sizeof(pb)); } #if 0 @@ -122,11 +120,11 @@ static bool acc_end_reached; // Sets up the simulated accelerator. void AcceleratorSetup(PB_TYPE* pb, u32* cur_addr) { - acc_pb = pb; - acc_loop_addr = HILO_TO_32(pb->audio_addr.loop_addr); - acc_end_addr = HILO_TO_32(pb->audio_addr.end_addr); - acc_cur_addr = cur_addr; - acc_end_reached = false; + acc_pb = pb; + acc_loop_addr = HILO_TO_32(pb->audio_addr.loop_addr); + acc_end_addr = HILO_TO_32(pb->audio_addr.end_addr); + acc_cur_addr = cur_addr; + acc_end_reached = false; } // Reads a sample from the simulated accelerator. Also handles looping and @@ -134,121 +132,121 @@ void AcceleratorSetup(PB_TYPE* pb, u32* cur_addr) // by the accelerator on real hardware). u16 AcceleratorGetSample() { - u16 ret; - u8 step_size_bytes = 0; + u16 ret; + u8 step_size_bytes = 0; - // See below for explanations about acc_end_reached. - if (acc_end_reached) - return 0; + // See below for explanations about acc_end_reached. + if (acc_end_reached) + return 0; - switch (acc_pb->audio_addr.sample_format) - { - case 0x00: // ADPCM - { - // ADPCM decoding, not much to explain here. - if ((*acc_cur_addr & 15) == 0) - { - acc_pb->adpcm.pred_scale = DSP::ReadARAM((*acc_cur_addr & ~15) >> 1); - *acc_cur_addr += 2; - } + switch (acc_pb->audio_addr.sample_format) + { + case 0x00: // ADPCM + { + // ADPCM decoding, not much to explain here. + if ((*acc_cur_addr & 15) == 0) + { + acc_pb->adpcm.pred_scale = DSP::ReadARAM((*acc_cur_addr & ~15) >> 1); + *acc_cur_addr += 2; + } - switch (acc_end_addr & 15) - { - case 0: // Tom and Jerry - step_size_bytes = 1; - break; - case 1: // Blazing Angels - step_size_bytes = 0; - break; - default: - step_size_bytes = 2; - break; - } + switch (acc_end_addr & 15) + { + case 0: // Tom and Jerry + step_size_bytes = 1; + break; + case 1: // Blazing Angels + step_size_bytes = 0; + break; + default: + step_size_bytes = 2; + break; + } - int scale = 1 << (acc_pb->adpcm.pred_scale & 0xF); - int coef_idx = (acc_pb->adpcm.pred_scale >> 4) & 0x7; + int scale = 1 << (acc_pb->adpcm.pred_scale & 0xF); + int coef_idx = (acc_pb->adpcm.pred_scale >> 4) & 0x7; - s32 coef1 = acc_pb->adpcm.coefs[coef_idx * 2 + 0]; - s32 coef2 = acc_pb->adpcm.coefs[coef_idx * 2 + 1]; + s32 coef1 = acc_pb->adpcm.coefs[coef_idx * 2 + 0]; + s32 coef2 = acc_pb->adpcm.coefs[coef_idx * 2 + 1]; - int temp = (*acc_cur_addr & 1) ? - (DSP::ReadARAM(*acc_cur_addr >> 1) & 0xF) : - (DSP::ReadARAM(*acc_cur_addr >> 1) >> 4); + int temp = (*acc_cur_addr & 1) ? (DSP::ReadARAM(*acc_cur_addr >> 1) & 0xF) : + (DSP::ReadARAM(*acc_cur_addr >> 1) >> 4); - if (temp >= 8) - temp -= 16; + if (temp >= 8) + temp -= 16; - int val = (scale * temp) + ((0x400 + coef1 * acc_pb->adpcm.yn1 + coef2 * acc_pb->adpcm.yn2) >> 11); - val = MathUtil::Clamp(val, -0x7FFF, 0x7FFF); + int val = + (scale * temp) + ((0x400 + coef1 * acc_pb->adpcm.yn1 + coef2 * acc_pb->adpcm.yn2) >> 11); + val = MathUtil::Clamp(val, -0x7FFF, 0x7FFF); - acc_pb->adpcm.yn2 = acc_pb->adpcm.yn1; - acc_pb->adpcm.yn1 = val; - *acc_cur_addr += 1; - ret = val; - break; - } + acc_pb->adpcm.yn2 = acc_pb->adpcm.yn1; + acc_pb->adpcm.yn1 = val; + *acc_cur_addr += 1; + ret = val; + break; + } - case 0x0A: // 16-bit PCM audio - ret = (DSP::ReadARAM(*acc_cur_addr * 2) << 8) | DSP::ReadARAM(*acc_cur_addr * 2 + 1); - acc_pb->adpcm.yn2 = acc_pb->adpcm.yn1; - acc_pb->adpcm.yn1 = ret; - step_size_bytes = 2; - *acc_cur_addr += 1; - break; + case 0x0A: // 16-bit PCM audio + ret = (DSP::ReadARAM(*acc_cur_addr * 2) << 8) | DSP::ReadARAM(*acc_cur_addr * 2 + 1); + acc_pb->adpcm.yn2 = acc_pb->adpcm.yn1; + acc_pb->adpcm.yn1 = ret; + step_size_bytes = 2; + *acc_cur_addr += 1; + break; - case 0x19: // 8-bit PCM audio - ret = DSP::ReadARAM(*acc_cur_addr) << 8; - acc_pb->adpcm.yn2 = acc_pb->adpcm.yn1; - acc_pb->adpcm.yn1 = ret; - step_size_bytes = 2; - *acc_cur_addr += 1; - break; + case 0x19: // 8-bit PCM audio + ret = DSP::ReadARAM(*acc_cur_addr) << 8; + acc_pb->adpcm.yn2 = acc_pb->adpcm.yn1; + acc_pb->adpcm.yn1 = ret; + step_size_bytes = 2; + *acc_cur_addr += 1; + break; - default: - ERROR_LOG(DSPHLE, "Unknown sample format: %d", acc_pb->audio_addr.sample_format); - return 0; - } + default: + ERROR_LOG(DSPHLE, "Unknown sample format: %d", acc_pb->audio_addr.sample_format); + return 0; + } - // Have we reached the end address? - // - // On real hardware, this would raise an interrupt that is handled by the - // UCode. We simulate what this interrupt does here. - if (*acc_cur_addr == (acc_end_addr + step_size_bytes - 1)) - { - // loop back to loop_addr. - *acc_cur_addr = acc_loop_addr; + // Have we reached the end address? + // + // On real hardware, this would raise an interrupt that is handled by the + // UCode. We simulate what this interrupt does here. + if (*acc_cur_addr == (acc_end_addr + step_size_bytes - 1)) + { + // loop back to loop_addr. + *acc_cur_addr = acc_loop_addr; - if (acc_pb->audio_addr.looping) - { - // Set the ADPCM infos to continue processing at loop_addr. - // - // For some reason, yn1 and yn2 aren't set if the voice is not of - // stream type. This is what the AX UCode does and I don't really - // know why. - acc_pb->adpcm.pred_scale = acc_pb->adpcm_loop_info.pred_scale; - if (!acc_pb->is_stream) - { - acc_pb->adpcm.yn1 = acc_pb->adpcm_loop_info.yn1; - acc_pb->adpcm.yn2 = acc_pb->adpcm_loop_info.yn2; - } - } - else - { - // Non looping voice reached the end -> running = 0. - acc_pb->running = 0; + if (acc_pb->audio_addr.looping) + { + // Set the ADPCM infos to continue processing at loop_addr. + // + // For some reason, yn1 and yn2 aren't set if the voice is not of + // stream type. This is what the AX UCode does and I don't really + // know why. + acc_pb->adpcm.pred_scale = acc_pb->adpcm_loop_info.pred_scale; + if (!acc_pb->is_stream) + { + acc_pb->adpcm.yn1 = acc_pb->adpcm_loop_info.yn1; + acc_pb->adpcm.yn2 = acc_pb->adpcm_loop_info.yn2; + } + } + else + { + // Non looping voice reached the end -> running = 0. + acc_pb->running = 0; #ifdef AX_WII - // One of the few meaningful differences between AXGC and AXWii: - // while AXGC handles non looping voices ending by having 0000 - // samples at the loop address, AXWii has the 0000 samples - // internally in DRAM and use an internal pointer to it (loop addr - // does not contain 0000 samples on AXWii!). - acc_end_reached = true; + // One of the few meaningful differences between AXGC and AXWii: + // while AXGC handles non looping voices ending by having 0000 + // samples at the loop address, AXWii has the 0000 samples + // internally in DRAM and use an internal pointer to it (loop addr + // does not contain 0000 samples on AXWii!). + acc_end_reached = true; #endif - } - } + } + } - return ret; + return ret; } // Reads samples from the input callback, resamples them to samples at @@ -271,291 +269,307 @@ u16 AcceleratorGetSample() // We start getting samples not from sample 0, but 0.. This // avoids discontinuities in the audio stream, especially with very low ratios // which interpolate a lot of values between two "real" samples. -u32 ResampleAudio(std::function input_callback, s16* output, u32 count, - s16* last_samples, u32 curr_pos, u32 ratio, int srctype, - const s16* coeffs) +u32 ResampleAudio(std::function input_callback, s16* output, u32 count, s16* last_samples, + u32 curr_pos, u32 ratio, int srctype, const s16* coeffs) { - int read_samples_count = 0; + int read_samples_count = 0; - // TODO(delroth): find out why the polyphase resampling algorithm causes - // audio glitches in Wii games with non integral ratios. + // TODO(delroth): find out why the polyphase resampling algorithm causes + // audio glitches in Wii games with non integral ratios. - // If DSP DROM coefficients are available, support polyphase resampling. - if (0) // if (coeffs && srctype == SRCTYPE_POLYPHASE) - { - s16 temp[4]; - u32 idx = 0; + // If DSP DROM coefficients are available, support polyphase resampling. + if (0) // if (coeffs && srctype == SRCTYPE_POLYPHASE) + { + s16 temp[4]; + u32 idx = 0; - temp[idx++ & 3] = last_samples[0]; - temp[idx++ & 3] = last_samples[1]; - temp[idx++ & 3] = last_samples[2]; - temp[idx++ & 3] = last_samples[3]; + temp[idx++ & 3] = last_samples[0]; + temp[idx++ & 3] = last_samples[1]; + temp[idx++ & 3] = last_samples[2]; + temp[idx++ & 3] = last_samples[3]; - for (u32 i = 0; i < count; ++i) - { - curr_pos += ratio; - while (curr_pos >= 0x10000) - { - temp[idx++ & 3] = input_callback(read_samples_count++); - curr_pos -= 0x10000; - } + for (u32 i = 0; i < count; ++i) + { + curr_pos += ratio; + while (curr_pos >= 0x10000) + { + temp[idx++ & 3] = input_callback(read_samples_count++); + curr_pos -= 0x10000; + } - u16 curr_pos_frac = ((curr_pos & 0xFFFF) >> 9) << 2; - const s16* c = &coeffs[curr_pos_frac]; + u16 curr_pos_frac = ((curr_pos & 0xFFFF) >> 9) << 2; + const s16* c = &coeffs[curr_pos_frac]; - s64 t0 = temp[idx++ & 3]; - s64 t1 = temp[idx++ & 3]; - s64 t2 = temp[idx++ & 3]; - s64 t3 = temp[idx++ & 3]; + s64 t0 = temp[idx++ & 3]; + s64 t1 = temp[idx++ & 3]; + s64 t2 = temp[idx++ & 3]; + s64 t3 = temp[idx++ & 3]; - s64 samp = (t0 * c[0] + t1 * c[1] + t2 * c[2] + t3 * c[3]) >> 15; + s64 samp = (t0 * c[0] + t1 * c[1] + t2 * c[2] + t3 * c[3]) >> 15; - output[i] = (s16)samp; - } + output[i] = (s16)samp; + } - last_samples[3] = temp[--idx & 3]; - last_samples[2] = temp[--idx & 3]; - last_samples[1] = temp[--idx & 3]; - last_samples[0] = temp[--idx & 3]; - } - else if (srctype == SRCTYPE_LINEAR || srctype == SRCTYPE_POLYPHASE) - { - // This is the circular buffer containing samples to use for the - // interpolation. It is initialized with the values from the PB, and it - // will be stored back to the PB at the end. - s16 temp[4]; - u32 idx = 0; + last_samples[3] = temp[--idx & 3]; + last_samples[2] = temp[--idx & 3]; + last_samples[1] = temp[--idx & 3]; + last_samples[0] = temp[--idx & 3]; + } + else if (srctype == SRCTYPE_LINEAR || srctype == SRCTYPE_POLYPHASE) + { + // This is the circular buffer containing samples to use for the + // interpolation. It is initialized with the values from the PB, and it + // will be stored back to the PB at the end. + s16 temp[4]; + u32 idx = 0; - temp[idx++ & 3] = last_samples[0]; - temp[idx++ & 3] = last_samples[1]; - temp[idx++ & 3] = last_samples[2]; - temp[idx++ & 3] = last_samples[3]; + temp[idx++ & 3] = last_samples[0]; + temp[idx++ & 3] = last_samples[1]; + temp[idx++ & 3] = last_samples[2]; + temp[idx++ & 3] = last_samples[3]; - for (u32 i = 0; i < count; ++i) - { - curr_pos += ratio; + for (u32 i = 0; i < count; ++i) + { + curr_pos += ratio; - // While our current position is >= 1.0, push new samples to the - // circular buffer. - while (curr_pos >= 0x10000) - { - temp[idx++ & 3] = input_callback(read_samples_count++); - curr_pos -= 0x10000; - } + // While our current position is >= 1.0, push new samples to the + // circular buffer. + while (curr_pos >= 0x10000) + { + temp[idx++ & 3] = input_callback(read_samples_count++); + curr_pos -= 0x10000; + } - // Get our current fractional position, used to know how much of - // curr0 and how much of curr1 the output sample should be. - u16 curr_frac = curr_pos & 0xFFFF; - u16 inv_curr_frac = -curr_frac; + // Get our current fractional position, used to know how much of + // curr0 and how much of curr1 the output sample should be. + u16 curr_frac = curr_pos & 0xFFFF; + u16 inv_curr_frac = -curr_frac; - // Interpolate! If curr_frac is 0, we can simply take the last - // sample without any multiplying. - s16 sample; - if (curr_frac) - { - s32 s0 = temp[idx++ & 3]; - s32 s1 = temp[idx++ & 3]; + // Interpolate! If curr_frac is 0, we can simply take the last + // sample without any multiplying. + s16 sample; + if (curr_frac) + { + s32 s0 = temp[idx++ & 3]; + s32 s1 = temp[idx++ & 3]; - sample = ((s0 * inv_curr_frac) + (s1 * curr_frac)) >> 16; - idx += 2; - } - else - { - sample = temp[idx++ & 3]; - idx += 3; - } + sample = ((s0 * inv_curr_frac) + (s1 * curr_frac)) >> 16; + idx += 2; + } + else + { + sample = temp[idx++ & 3]; + idx += 3; + } - output[i] = sample; - } + output[i] = sample; + } - // Update the four last_samples values. - last_samples[3] = temp[--idx & 3]; - last_samples[2] = temp[--idx & 3]; - last_samples[1] = temp[--idx & 3]; - last_samples[0] = temp[--idx & 3]; - } - else // SRCTYPE_NEAREST - { - // No sample rate conversion here: simply read samples from the - // accelerator to the output buffer. - for (u32 i = 0; i < count; ++i) - output[i] = input_callback(i); + // Update the four last_samples values. + last_samples[3] = temp[--idx & 3]; + last_samples[2] = temp[--idx & 3]; + last_samples[1] = temp[--idx & 3]; + last_samples[0] = temp[--idx & 3]; + } + else // SRCTYPE_NEAREST + { + // No sample rate conversion here: simply read samples from the + // accelerator to the output buffer. + for (u32 i = 0; i < count; ++i) + output[i] = input_callback(i); - memcpy(last_samples, output + count - 4, 4 * sizeof (u16)); - } + memcpy(last_samples, output + count - 4, 4 * sizeof(u16)); + } - return curr_pos; + return curr_pos; } // Read input samples from ARAM, decoding and converting rate // if required. void GetInputSamples(PB_TYPE& pb, s16* samples, u16 count, const s16* coeffs) { - u32 cur_addr = HILO_TO_32(pb.audio_addr.cur_addr); - AcceleratorSetup(&pb, &cur_addr); + u32 cur_addr = HILO_TO_32(pb.audio_addr.cur_addr); + AcceleratorSetup(&pb, &cur_addr); - if (coeffs) - coeffs += pb.coef_select * 0x200; - u32 curr_pos = ResampleAudio([](u32) { return AcceleratorGetSample(); }, - samples, count, pb.src.last_samples, - pb.src.cur_addr_frac, HILO_TO_32(pb.src.ratio), - pb.src_type, coeffs); - pb.src.cur_addr_frac = (curr_pos & 0xFFFF); + if (coeffs) + coeffs += pb.coef_select * 0x200; + u32 curr_pos = + ResampleAudio([](u32) { return AcceleratorGetSample(); }, samples, count, pb.src.last_samples, + pb.src.cur_addr_frac, HILO_TO_32(pb.src.ratio), pb.src_type, coeffs); + pb.src.cur_addr_frac = (curr_pos & 0xFFFF); - // Update current position in the PB. - pb.audio_addr.cur_addr_hi = (u16)(cur_addr >> 16); - pb.audio_addr.cur_addr_lo = (u16)(cur_addr & 0xFFFF); + // Update current position in the PB. + pb.audio_addr.cur_addr_hi = (u16)(cur_addr >> 16); + pb.audio_addr.cur_addr_lo = (u16)(cur_addr & 0xFFFF); } // Add samples to an output buffer, with optional volume ramping. void MixAdd(int* out, const s16* input, u32 count, u16* pvol, s16* dpop, bool ramp) { - u16& volume = pvol[0]; - u16 volume_delta = pvol[1]; + u16& volume = pvol[0]; + u16 volume_delta = pvol[1]; - // If volume ramping is disabled, set volume_delta to 0. That way, the - // mixing loop can avoid testing if volume ramping is enabled at each step, - // and just add volume_delta. - if (!ramp) - volume_delta = 0; + // If volume ramping is disabled, set volume_delta to 0. That way, the + // mixing loop can avoid testing if volume ramping is enabled at each step, + // and just add volume_delta. + if (!ramp) + volume_delta = 0; - for (u32 i = 0; i < count; ++i) - { - s64 sample = input[i]; - sample *= volume; - sample >>= 15; - sample = MathUtil::Clamp((s32)sample, -32767, 32767); // -32768 ? + for (u32 i = 0; i < count; ++i) + { + s64 sample = input[i]; + sample *= volume; + sample >>= 15; + sample = MathUtil::Clamp((s32)sample, -32767, 32767); // -32768 ? - out[i] += (s16)sample; - volume += volume_delta; + out[i] += (s16)sample; + volume += volume_delta; - *dpop = (s16)sample; - } + *dpop = (s16)sample; + } } // Execute a low pass filter on the samples using one history value. Returns // the new history value. s16 LowPassFilter(s16* samples, u32 count, s16 yn1, u16 a0, u16 b0) { - for (u32 i = 0; i < count; ++i) - yn1 = samples[i] = (a0 * (s32)samples[i] + b0 * (s32)yn1) >> 15; - return yn1; + for (u32 i = 0; i < count; ++i) + yn1 = samples[i] = (a0 * (s32)samples[i] + b0 * (s32)yn1) >> 15; + return yn1; } // Process 1ms of audio (for AX GC) or 3ms of audio (for AX Wii) from a PB and // mix it to the output buffers. -void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, u16 count, AXMixControl mctrl, const s16* coeffs) +void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, u16 count, AXMixControl mctrl, + const s16* coeffs) { - // If the voice is not running, nothing to do. - if (!pb.running) - return; + // If the voice is not running, nothing to do. + if (!pb.running) + return; - // Read input samples, performing sample rate conversion if needed. - s16 samples[MAX_SAMPLES_PER_FRAME]; - GetInputSamples(pb, samples, count, coeffs); + // Read input samples, performing sample rate conversion if needed. + s16 samples[MAX_SAMPLES_PER_FRAME]; + GetInputSamples(pb, samples, count, coeffs); - // Apply a global volume ramp using the volume envelope parameters. - for (u32 i = 0; i < count; ++i) - { - samples[i] = MathUtil::Clamp(((s32)samples[i] * pb.vol_env.cur_volume) >> 15, -32767, 32767); // -32768 ? - pb.vol_env.cur_volume += pb.vol_env.cur_volume_delta; - } + // Apply a global volume ramp using the volume envelope parameters. + for (u32 i = 0; i < count; ++i) + { + samples[i] = MathUtil::Clamp(((s32)samples[i] * pb.vol_env.cur_volume) >> 15, -32767, + 32767); // -32768 ? + pb.vol_env.cur_volume += pb.vol_env.cur_volume_delta; + } - // Optionally, execute a low pass filter - // TODO: LPF code is currently broken, causing Super Monkey Ball sound - // corruption. Disabled until someone figures out what is wrong with it. - if (0 && pb.lpf.enabled) - { - pb.lpf.yn1 = LowPassFilter(samples, count, pb.lpf.yn1, pb.lpf.a0, pb.lpf.b0); - } + // Optionally, execute a low pass filter + // TODO: LPF code is currently broken, causing Super Monkey Ball sound + // corruption. Disabled until someone figures out what is wrong with it. + if (0 && pb.lpf.enabled) + { + pb.lpf.yn1 = LowPassFilter(samples, count, pb.lpf.yn1, pb.lpf.a0, pb.lpf.b0); + } - // Mix LRS, AUXA and AUXB depending on mixer_control - // TODO: Handle DPL2 on AUXB. +// Mix LRS, AUXA and AUXB depending on mixer_control +// TODO: Handle DPL2 on AUXB. #define MIX_ON(C) (0 != (mctrl & MIX_##C)) #define RAMP_ON(C) (0 != (mctrl & MIX_##C##_RAMP)) - if (MIX_ON(L)) - MixAdd(buffers.left, samples, count, &pb.mixer.left, &pb.dpop.left, RAMP_ON(L)); - if (MIX_ON(R)) - MixAdd(buffers.right, samples, count, &pb.mixer.right, &pb.dpop.right, RAMP_ON(R)); - if (MIX_ON(S)) - MixAdd(buffers.surround, samples, count, &pb.mixer.surround, &pb.dpop.surround, RAMP_ON(S)); + if (MIX_ON(L)) + MixAdd(buffers.left, samples, count, &pb.mixer.left, &pb.dpop.left, RAMP_ON(L)); + if (MIX_ON(R)) + MixAdd(buffers.right, samples, count, &pb.mixer.right, &pb.dpop.right, RAMP_ON(R)); + if (MIX_ON(S)) + MixAdd(buffers.surround, samples, count, &pb.mixer.surround, &pb.dpop.surround, RAMP_ON(S)); - if (MIX_ON(AUXA_L)) - MixAdd(buffers.auxA_left, samples, count, &pb.mixer.auxA_left, &pb.dpop.auxA_left, RAMP_ON(AUXA_L)); - if (MIX_ON(AUXA_R)) - MixAdd(buffers.auxA_right, samples, count, &pb.mixer.auxA_right, &pb.dpop.auxA_right, RAMP_ON(AUXA_R)); - if (MIX_ON(AUXA_S)) - MixAdd(buffers.auxA_surround, samples, count, &pb.mixer.auxA_surround, &pb.dpop.auxA_surround, RAMP_ON(AUXA_S)); + if (MIX_ON(AUXA_L)) + MixAdd(buffers.auxA_left, samples, count, &pb.mixer.auxA_left, &pb.dpop.auxA_left, + RAMP_ON(AUXA_L)); + if (MIX_ON(AUXA_R)) + MixAdd(buffers.auxA_right, samples, count, &pb.mixer.auxA_right, &pb.dpop.auxA_right, + RAMP_ON(AUXA_R)); + if (MIX_ON(AUXA_S)) + MixAdd(buffers.auxA_surround, samples, count, &pb.mixer.auxA_surround, &pb.dpop.auxA_surround, + RAMP_ON(AUXA_S)); - if (MIX_ON(AUXB_L)) - MixAdd(buffers.auxB_left, samples, count, &pb.mixer.auxB_left, &pb.dpop.auxB_left, RAMP_ON(AUXB_L)); - if (MIX_ON(AUXB_R)) - MixAdd(buffers.auxB_right, samples, count, &pb.mixer.auxB_right, &pb.dpop.auxB_right, RAMP_ON(AUXB_R)); - if (MIX_ON(AUXB_S)) - MixAdd(buffers.auxB_surround, samples, count, &pb.mixer.auxB_surround, &pb.dpop.auxB_surround, RAMP_ON(AUXB_S)); + if (MIX_ON(AUXB_L)) + MixAdd(buffers.auxB_left, samples, count, &pb.mixer.auxB_left, &pb.dpop.auxB_left, + RAMP_ON(AUXB_L)); + if (MIX_ON(AUXB_R)) + MixAdd(buffers.auxB_right, samples, count, &pb.mixer.auxB_right, &pb.dpop.auxB_right, + RAMP_ON(AUXB_R)); + if (MIX_ON(AUXB_S)) + MixAdd(buffers.auxB_surround, samples, count, &pb.mixer.auxB_surround, &pb.dpop.auxB_surround, + RAMP_ON(AUXB_S)); #ifdef AX_WII - if (MIX_ON(AUXC_L)) - MixAdd(buffers.auxC_left, samples, count, &pb.mixer.auxC_left, &pb.dpop.auxC_left, RAMP_ON(AUXC_L)); - if (MIX_ON(AUXC_R)) - MixAdd(buffers.auxC_right, samples, count, &pb.mixer.auxC_right, &pb.dpop.auxC_right, RAMP_ON(AUXC_R)); - if (MIX_ON(AUXC_S)) - MixAdd(buffers.auxC_surround, samples, count, &pb.mixer.auxC_surround, &pb.dpop.auxC_surround, RAMP_ON(AUXC_S)); + if (MIX_ON(AUXC_L)) + MixAdd(buffers.auxC_left, samples, count, &pb.mixer.auxC_left, &pb.dpop.auxC_left, + RAMP_ON(AUXC_L)); + if (MIX_ON(AUXC_R)) + MixAdd(buffers.auxC_right, samples, count, &pb.mixer.auxC_right, &pb.dpop.auxC_right, + RAMP_ON(AUXC_R)); + if (MIX_ON(AUXC_S)) + MixAdd(buffers.auxC_surround, samples, count, &pb.mixer.auxC_surround, &pb.dpop.auxC_surround, + RAMP_ON(AUXC_S)); #endif #undef MIX_ON #undef RAMP_ON - // Optionally, phase shift left or right channel to simulate 3D sound. - if (pb.initial_time_delay.on) - { - // TODO - } + // Optionally, phase shift left or right channel to simulate 3D sound. + if (pb.initial_time_delay.on) + { + // TODO + } #ifdef AX_WII - // Wiimote mixing. - if (pb.remote) - { - // Old AXWii versions process ms per ms. - u16 wm_count = count == 96 ? 18 : 6; + // Wiimote mixing. + if (pb.remote) + { + // Old AXWii versions process ms per ms. + u16 wm_count = count == 96 ? 18 : 6; - // Interpolate at most 18 samples from the 96 samples we read before. - s16 wm_samples[18]; + // Interpolate at most 18 samples from the 96 samples we read before. + s16 wm_samples[18]; - // We use ratio 0x55555 == (5 * 65536 + 21845) / 65536 == 5.3333 which - // is the nearest we can get to 96/18 - u32 curr_pos = ResampleAudio([&samples](u32 i) { return samples[i]; }, - wm_samples, wm_count, pb.remote_src.last_samples, - pb.remote_src.cur_addr_frac, 0x55555, - SRCTYPE_POLYPHASE, coeffs); - pb.remote_src.cur_addr_frac = curr_pos & 0xFFFF; + // We use ratio 0x55555 == (5 * 65536 + 21845) / 65536 == 5.3333 which + // is the nearest we can get to 96/18 + u32 curr_pos = ResampleAudio([&samples](u32 i) { return samples[i]; }, wm_samples, wm_count, + pb.remote_src.last_samples, pb.remote_src.cur_addr_frac, 0x55555, + SRCTYPE_POLYPHASE, coeffs); + pb.remote_src.cur_addr_frac = curr_pos & 0xFFFF; - // Mix to main[0-3] and aux[0-3] +// Mix to main[0-3] and aux[0-3] #define WMCHAN_MIX_ON(n) (0 != ((pb.remote_mixer_control >> (2 * n)) & 3)) #define WMCHAN_MIX_RAMP(n) (0 != ((pb.remote_mixer_control >> (2 * n)) & 2)) - if (WMCHAN_MIX_ON(0)) - MixAdd(buffers.wm_main0, wm_samples, wm_count, &pb.remote_mixer.main0, &pb.remote_dpop.main0, WMCHAN_MIX_RAMP(0)); - if (WMCHAN_MIX_ON(1)) - MixAdd(buffers.wm_aux0, wm_samples, wm_count, &pb.remote_mixer.aux0, &pb.remote_dpop.aux0, WMCHAN_MIX_RAMP(1)); - if (WMCHAN_MIX_ON(2)) - MixAdd(buffers.wm_main1, wm_samples, wm_count, &pb.remote_mixer.main1, &pb.remote_dpop.main1, WMCHAN_MIX_RAMP(2)); - if (WMCHAN_MIX_ON(3)) - MixAdd(buffers.wm_aux1, wm_samples, wm_count, &pb.remote_mixer.aux1, &pb.remote_dpop.aux1, WMCHAN_MIX_RAMP(3)); - if (WMCHAN_MIX_ON(4)) - MixAdd(buffers.wm_main2, wm_samples, wm_count, &pb.remote_mixer.main2, &pb.remote_dpop.main2, WMCHAN_MIX_RAMP(4)); - if (WMCHAN_MIX_ON(5)) - MixAdd(buffers.wm_aux2, wm_samples, wm_count, &pb.remote_mixer.aux2, &pb.remote_dpop.aux2, WMCHAN_MIX_RAMP(5)); - if (WMCHAN_MIX_ON(6)) - MixAdd(buffers.wm_main3, wm_samples, wm_count, &pb.remote_mixer.main3, &pb.remote_dpop.main3, WMCHAN_MIX_RAMP(6)); - if (WMCHAN_MIX_ON(7)) - MixAdd(buffers.wm_aux3, wm_samples, wm_count, &pb.remote_mixer.aux3, &pb.remote_dpop.aux3, WMCHAN_MIX_RAMP(7)); - } + if (WMCHAN_MIX_ON(0)) + MixAdd(buffers.wm_main0, wm_samples, wm_count, &pb.remote_mixer.main0, &pb.remote_dpop.main0, + WMCHAN_MIX_RAMP(0)); + if (WMCHAN_MIX_ON(1)) + MixAdd(buffers.wm_aux0, wm_samples, wm_count, &pb.remote_mixer.aux0, &pb.remote_dpop.aux0, + WMCHAN_MIX_RAMP(1)); + if (WMCHAN_MIX_ON(2)) + MixAdd(buffers.wm_main1, wm_samples, wm_count, &pb.remote_mixer.main1, &pb.remote_dpop.main1, + WMCHAN_MIX_RAMP(2)); + if (WMCHAN_MIX_ON(3)) + MixAdd(buffers.wm_aux1, wm_samples, wm_count, &pb.remote_mixer.aux1, &pb.remote_dpop.aux1, + WMCHAN_MIX_RAMP(3)); + if (WMCHAN_MIX_ON(4)) + MixAdd(buffers.wm_main2, wm_samples, wm_count, &pb.remote_mixer.main2, &pb.remote_dpop.main2, + WMCHAN_MIX_RAMP(4)); + if (WMCHAN_MIX_ON(5)) + MixAdd(buffers.wm_aux2, wm_samples, wm_count, &pb.remote_mixer.aux2, &pb.remote_dpop.aux2, + WMCHAN_MIX_RAMP(5)); + if (WMCHAN_MIX_ON(6)) + MixAdd(buffers.wm_main3, wm_samples, wm_count, &pb.remote_mixer.main3, &pb.remote_dpop.main3, + WMCHAN_MIX_RAMP(6)); + if (WMCHAN_MIX_ON(7)) + MixAdd(buffers.wm_aux3, wm_samples, wm_count, &pb.remote_mixer.aux3, &pb.remote_dpop.aux3, + WMCHAN_MIX_RAMP(7)); + } #undef WMCHAN_MIX_RAMP #undef WMCHAN_MIX_ON #endif } -} // namespace +} // namespace diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.cpp index 78df3e56fd..5cbd94ff60 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.cpp @@ -2,30 +2,27 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. // -#define AX_WII // Used in AXVoice. +#define AX_WII // Used in AXVoice. +#include "Core/HW/DSPHLE/UCodes/AXWii.h" #include "Common/ChunkFile.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/MathUtil.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "Core/HW/DSPHLE/UCodes/AXStructs.h" #include "Core/HW/DSPHLE/UCodes/AXVoice.h" -#include "Core/HW/DSPHLE/UCodes/AXWii.h" #include "Core/HW/DSPHLE/UCodes/UCodes.h" - -AXWiiUCode::AXWiiUCode(DSPHLE *dsphle, u32 crc) - : AXUCode(dsphle, crc), - m_last_main_volume(0x8000) +AXWiiUCode::AXWiiUCode(DSPHLE* dsphle, u32 crc) : AXUCode(dsphle, crc), m_last_main_volume(0x8000) { - for (u16& volume : m_last_aux_volumes) - volume = 0x8000; + for (u16& volume : m_last_aux_volumes) + volume = 0x8000; - WARN_LOG(DSPHLE, "Instantiating AXWiiUCode"); + WARN_LOG(DSPHLE, "Instantiating AXWiiUCode"); - m_old_axwii = (crc == 0xfa450138); + m_old_axwii = (crc == 0xfa450138); } AXWiiUCode::~AXWiiUCode() @@ -34,647 +31,623 @@ AXWiiUCode::~AXWiiUCode() void AXWiiUCode::HandleCommandList() { - // Temp variables for addresses computation - u16 addr_hi, addr_lo; - u16 addr2_hi, addr2_lo; - u16 volume; + // Temp variables for addresses computation + u16 addr_hi, addr_lo; + u16 addr2_hi, addr2_lo; + u16 volume; - u32 pb_addr = 0; + u32 pb_addr = 0; - // WARN_LOG(DSPHLE, "Command list:"); - // for (u32 i = 0; m_cmdlist[i] != CMD_END; ++i) - // WARN_LOG(DSPHLE, "%04x", m_cmdlist[i]); - // WARN_LOG(DSPHLE, "-------------"); + // WARN_LOG(DSPHLE, "Command list:"); + // for (u32 i = 0; m_cmdlist[i] != CMD_END; ++i) + // WARN_LOG(DSPHLE, "%04x", m_cmdlist[i]); + // WARN_LOG(DSPHLE, "-------------"); - u32 curr_idx = 0; - bool end = false; - while (!end) - { - u16 cmd = m_cmdlist[curr_idx++]; + u32 curr_idx = 0; + bool end = false; + while (!end) + { + u16 cmd = m_cmdlist[curr_idx++]; - if (m_old_axwii) - { - switch (cmd) - { - // Some of these commands are unknown, or unused in this AX HLE. - // We still need to skip their arguments using "curr_idx += N". + if (m_old_axwii) + { + switch (cmd) + { + // Some of these commands are unknown, or unused in this AX HLE. + // We still need to skip their arguments using "curr_idx += N". - case CMD_SETUP_OLD: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - SetupProcessing(HILO_TO_32(addr)); - break; + case CMD_SETUP_OLD: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + SetupProcessing(HILO_TO_32(addr)); + break; - case CMD_ADD_TO_LR_OLD: - case CMD_SUB_TO_LR_OLD: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - AddToLR(HILO_TO_32(addr), cmd == CMD_SUB_TO_LR_OLD); - break; + case CMD_ADD_TO_LR_OLD: + case CMD_SUB_TO_LR_OLD: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + AddToLR(HILO_TO_32(addr), cmd == CMD_SUB_TO_LR_OLD); + break; - case CMD_ADD_SUB_TO_LR_OLD: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - AddSubToLR(HILO_TO_32(addr)); - break; + case CMD_ADD_SUB_TO_LR_OLD: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + AddSubToLR(HILO_TO_32(addr)); + break; - case CMD_PB_ADDR_OLD: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - pb_addr = HILO_TO_32(addr); - break; + case CMD_PB_ADDR_OLD: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + pb_addr = HILO_TO_32(addr); + break; - case CMD_PROCESS_OLD: - ProcessPBList(pb_addr); - break; + case CMD_PROCESS_OLD: + ProcessPBList(pb_addr); + break; - case CMD_MIX_AUXA_OLD: - case CMD_MIX_AUXB_OLD: - case CMD_MIX_AUXC_OLD: - volume = m_cmdlist[curr_idx++]; - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - addr2_hi = m_cmdlist[curr_idx++]; - addr2_lo = m_cmdlist[curr_idx++]; - MixAUXSamples(cmd - CMD_MIX_AUXA_OLD, HILO_TO_32(addr), HILO_TO_32(addr2), volume); - break; + case CMD_MIX_AUXA_OLD: + case CMD_MIX_AUXB_OLD: + case CMD_MIX_AUXC_OLD: + volume = m_cmdlist[curr_idx++]; + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + addr2_hi = m_cmdlist[curr_idx++]; + addr2_lo = m_cmdlist[curr_idx++]; + MixAUXSamples(cmd - CMD_MIX_AUXA_OLD, HILO_TO_32(addr), HILO_TO_32(addr2), volume); + break; - case CMD_UPL_AUXA_MIX_LRSC_OLD: - case CMD_UPL_AUXB_MIX_LRSC_OLD: - { - volume = m_cmdlist[curr_idx++]; - u32 addresses[6] = { - (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1], - (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3], - (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5], - (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7], - (u32)(m_cmdlist[curr_idx + 8] << 16) | m_cmdlist[curr_idx + 9], - (u32)(m_cmdlist[curr_idx + 10] << 16) | m_cmdlist[curr_idx + 11], - }; - curr_idx += 12; - UploadAUXMixLRSC(cmd == CMD_UPL_AUXB_MIX_LRSC_OLD, addresses, volume); - break; - } + case CMD_UPL_AUXA_MIX_LRSC_OLD: + case CMD_UPL_AUXB_MIX_LRSC_OLD: + { + volume = m_cmdlist[curr_idx++]; + u32 addresses[6] = { + (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1], + (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3], + (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5], + (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7], + (u32)(m_cmdlist[curr_idx + 8] << 16) | m_cmdlist[curr_idx + 9], + (u32)(m_cmdlist[curr_idx + 10] << 16) | m_cmdlist[curr_idx + 11], + }; + curr_idx += 12; + UploadAUXMixLRSC(cmd == CMD_UPL_AUXB_MIX_LRSC_OLD, addresses, volume); + break; + } - // TODO(delroth): figure this one out, it's used by almost every - // game I've tested so far. - case CMD_UNK_0B_OLD: curr_idx += 4; break; + // TODO(delroth): figure this one out, it's used by almost every + // game I've tested so far. + case CMD_UNK_0B_OLD: + curr_idx += 4; + break; - case CMD_OUTPUT_OLD: - case CMD_OUTPUT_DPL2_OLD: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - addr2_hi = m_cmdlist[curr_idx++]; - addr2_lo = m_cmdlist[curr_idx++]; - OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr), 0x8000, - cmd == CMD_OUTPUT_DPL2_OLD); - break; + case CMD_OUTPUT_OLD: + case CMD_OUTPUT_DPL2_OLD: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + addr2_hi = m_cmdlist[curr_idx++]; + addr2_lo = m_cmdlist[curr_idx++]; + OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr), 0x8000, cmd == CMD_OUTPUT_DPL2_OLD); + break; - case CMD_WM_OUTPUT_OLD: - { - u32 addresses[4] = { - (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1], - (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3], - (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5], - (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7], - }; - curr_idx += 8; - OutputWMSamples(addresses); - break; - } + case CMD_WM_OUTPUT_OLD: + { + u32 addresses[4] = { + (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1], + (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3], + (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5], + (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7], + }; + curr_idx += 8; + OutputWMSamples(addresses); + break; + } - case CMD_END_OLD: - end = true; - break; - } - } - else - { - switch (cmd) - { - // Some of these commands are unknown, or unused in this AX HLE. - // We still need to skip their arguments using "curr_idx += N". + case CMD_END_OLD: + end = true; + break; + } + } + else + { + switch (cmd) + { + // Some of these commands are unknown, or unused in this AX HLE. + // We still need to skip their arguments using "curr_idx += N". - case CMD_SETUP: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - SetupProcessing(HILO_TO_32(addr)); - break; + case CMD_SETUP: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + SetupProcessing(HILO_TO_32(addr)); + break; - case CMD_ADD_TO_LR: - case CMD_SUB_TO_LR: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - AddToLR(HILO_TO_32(addr), cmd == CMD_SUB_TO_LR); - break; + case CMD_ADD_TO_LR: + case CMD_SUB_TO_LR: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + AddToLR(HILO_TO_32(addr), cmd == CMD_SUB_TO_LR); + break; - case CMD_ADD_SUB_TO_LR: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - AddSubToLR(HILO_TO_32(addr)); - break; + case CMD_ADD_SUB_TO_LR: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + AddSubToLR(HILO_TO_32(addr)); + break; - case CMD_PROCESS: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - ProcessPBList(HILO_TO_32(addr)); - break; + case CMD_PROCESS: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + ProcessPBList(HILO_TO_32(addr)); + break; - case CMD_MIX_AUXA: - case CMD_MIX_AUXB: - case CMD_MIX_AUXC: - volume = m_cmdlist[curr_idx++]; - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - addr2_hi = m_cmdlist[curr_idx++]; - addr2_lo = m_cmdlist[curr_idx++]; - MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2), volume); - break; + case CMD_MIX_AUXA: + case CMD_MIX_AUXB: + case CMD_MIX_AUXC: + volume = m_cmdlist[curr_idx++]; + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + addr2_hi = m_cmdlist[curr_idx++]; + addr2_lo = m_cmdlist[curr_idx++]; + MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2), volume); + break; - case CMD_UPL_AUXA_MIX_LRSC: - case CMD_UPL_AUXB_MIX_LRSC: - { - volume = m_cmdlist[curr_idx++]; - u32 addresses[6] = { - (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1], - (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3], - (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5], - (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7], - (u32)(m_cmdlist[curr_idx + 8] << 16) | m_cmdlist[curr_idx + 9], - (u32)(m_cmdlist[curr_idx + 10] << 16) | m_cmdlist[curr_idx + 11], - }; - curr_idx += 12; - UploadAUXMixLRSC(cmd == CMD_UPL_AUXB_MIX_LRSC, addresses, volume); - break; - } + case CMD_UPL_AUXA_MIX_LRSC: + case CMD_UPL_AUXB_MIX_LRSC: + { + volume = m_cmdlist[curr_idx++]; + u32 addresses[6] = { + (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1], + (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3], + (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5], + (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7], + (u32)(m_cmdlist[curr_idx + 8] << 16) | m_cmdlist[curr_idx + 9], + (u32)(m_cmdlist[curr_idx + 10] << 16) | m_cmdlist[curr_idx + 11], + }; + curr_idx += 12; + UploadAUXMixLRSC(cmd == CMD_UPL_AUXB_MIX_LRSC, addresses, volume); + break; + } - // TODO(delroth): figure this one out, it's used by almost every - // game I've tested so far. - case CMD_UNK_0A: curr_idx += 4; break; + // TODO(delroth): figure this one out, it's used by almost every + // game I've tested so far. + case CMD_UNK_0A: + curr_idx += 4; + break; - case CMD_OUTPUT: - case CMD_OUTPUT_DPL2: - volume = m_cmdlist[curr_idx++]; - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - addr2_hi = m_cmdlist[curr_idx++]; - addr2_lo = m_cmdlist[curr_idx++]; - OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr), volume, - cmd == CMD_OUTPUT_DPL2); - break; + case CMD_OUTPUT: + case CMD_OUTPUT_DPL2: + volume = m_cmdlist[curr_idx++]; + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + addr2_hi = m_cmdlist[curr_idx++]; + addr2_lo = m_cmdlist[curr_idx++]; + OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr), volume, cmd == CMD_OUTPUT_DPL2); + break; - case CMD_WM_OUTPUT: - { - u32 addresses[4] = { - (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1], - (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3], - (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5], - (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7], - }; - curr_idx += 8; - OutputWMSamples(addresses); - break; - } + case CMD_WM_OUTPUT: + { + u32 addresses[4] = { + (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1], + (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3], + (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5], + (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7], + }; + curr_idx += 8; + OutputWMSamples(addresses); + break; + } - case CMD_END: - end = true; - break; - } - } - } + case CMD_END: + end = true; + break; + } + } + } } void AXWiiUCode::SetupProcessing(u32 init_addr) { - // TODO: should be easily factorizable with AX - s16 init_data[60]; + // TODO: should be easily factorizable with AX + s16 init_data[60]; - for (u32 i = 0; i < 60; ++i) - init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i); + for (u32 i = 0; i < 60; ++i) + init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i); - // List of all buffers we have to initialize - struct - { - int* ptr; - u32 samples; - } buffers[] = { - { m_samples_left, 32 }, - { m_samples_right, 32 }, - { m_samples_surround, 32 }, - { m_samples_auxA_left, 32 }, - { m_samples_auxA_right, 32 }, - { m_samples_auxA_surround, 32 }, - { m_samples_auxB_left, 32 }, - { m_samples_auxB_right, 32 }, - { m_samples_auxB_surround, 32 }, - { m_samples_auxC_left, 32 }, - { m_samples_auxC_right, 32 }, - { m_samples_auxC_surround, 32 }, + // List of all buffers we have to initialize + struct + { + int* ptr; + u32 samples; + } buffers[] = { + {m_samples_left, 32}, {m_samples_right, 32}, {m_samples_surround, 32}, + {m_samples_auxA_left, 32}, {m_samples_auxA_right, 32}, {m_samples_auxA_surround, 32}, + {m_samples_auxB_left, 32}, {m_samples_auxB_right, 32}, {m_samples_auxB_surround, 32}, + {m_samples_auxC_left, 32}, {m_samples_auxC_right, 32}, {m_samples_auxC_surround, 32}, - { m_samples_wm0, 6 }, - { m_samples_aux0, 6 }, - { m_samples_wm1, 6 }, - { m_samples_aux1, 6 }, - { m_samples_wm2, 6 }, - { m_samples_aux2, 6 }, - { m_samples_wm3, 6 }, - { m_samples_aux3, 6 } - }; + {m_samples_wm0, 6}, {m_samples_aux0, 6}, {m_samples_wm1, 6}, + {m_samples_aux1, 6}, {m_samples_wm2, 6}, {m_samples_aux2, 6}, + {m_samples_wm3, 6}, {m_samples_aux3, 6}}; - u32 init_idx = 0; - for (auto& buffer : buffers) - { - s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]); - s16 delta = (s16)init_data[init_idx + 2]; + u32 init_idx = 0; + for (auto& buffer : buffers) + { + s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]); + s16 delta = (s16)init_data[init_idx + 2]; - init_idx += 3; + init_idx += 3; - if (!init_val) - { - memset(buffer.ptr, 0, 3 * buffer.samples * sizeof (int)); - } - else - { - for (u32 j = 0; j < 3 * buffer.samples; ++j) - { - buffer.ptr[j] = init_val; - init_val += delta; - } - } - } + if (!init_val) + { + memset(buffer.ptr, 0, 3 * buffer.samples * sizeof(int)); + } + else + { + for (u32 j = 0; j < 3 * buffer.samples; ++j) + { + buffer.ptr[j] = init_val; + init_val += delta; + } + } + } } void AXWiiUCode::AddToLR(u32 val_addr, bool neg) { - int* ptr = (int*)HLEMemory_Get_Pointer(val_addr); - for (int i = 0; i < 32 * 3; ++i) - { - int val = (int)Common::swap32(*ptr++); - if (neg) - val = -val; + int* ptr = (int*)HLEMemory_Get_Pointer(val_addr); + for (int i = 0; i < 32 * 3; ++i) + { + int val = (int)Common::swap32(*ptr++); + if (neg) + val = -val; - m_samples_left[i] += val; - m_samples_right[i] += val; - } + m_samples_left[i] += val; + m_samples_right[i] += val; + } } void AXWiiUCode::AddSubToLR(u32 val_addr) { - int* ptr = (int*)HLEMemory_Get_Pointer(val_addr); - for (int i = 0; i < 32 * 3; ++i) - { - int val = (int)Common::swap32(*ptr++); - m_samples_left[i] += val; - } - for (int i = 0; i < 32 * 3; ++i) - { - int val = (int)Common::swap32(*ptr++); - m_samples_right[i] -= val; - } + int* ptr = (int*)HLEMemory_Get_Pointer(val_addr); + for (int i = 0; i < 32 * 3; ++i) + { + int val = (int)Common::swap32(*ptr++); + m_samples_left[i] += val; + } + for (int i = 0; i < 32 * 3; ++i) + { + int val = (int)Common::swap32(*ptr++); + m_samples_right[i] -= val; + } } AXMixControl AXWiiUCode::ConvertMixerControl(u32 mixer_control) { - u32 ret = 0; + u32 ret = 0; - if (mixer_control & 0x00000001) ret |= MIX_L; - if (mixer_control & 0x00000002) ret |= MIX_R; - if (mixer_control & 0x00000004) ret |= MIX_L_RAMP | MIX_R_RAMP; - if (mixer_control & 0x00000008) ret |= MIX_S; - if (mixer_control & 0x00000010) ret |= MIX_S_RAMP; - if (mixer_control & 0x00010000) ret |= MIX_AUXA_L; - if (mixer_control & 0x00020000) ret |= MIX_AUXA_R; - if (mixer_control & 0x00040000) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP; - if (mixer_control & 0x00080000) ret |= MIX_AUXA_S; - if (mixer_control & 0x00100000) ret |= MIX_AUXA_S_RAMP; - if (mixer_control & 0x00200000) ret |= MIX_AUXB_L; - if (mixer_control & 0x00400000) ret |= MIX_AUXB_R; - if (mixer_control & 0x00800000) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP; - if (mixer_control & 0x01000000) ret |= MIX_AUXB_S; - if (mixer_control & 0x02000000) ret |= MIX_AUXB_S_RAMP; - if (mixer_control & 0x04000000) ret |= MIX_AUXC_L; - if (mixer_control & 0x08000000) ret |= MIX_AUXC_R; - if (mixer_control & 0x10000000) ret |= MIX_AUXC_L_RAMP | MIX_AUXC_R_RAMP; - if (mixer_control & 0x20000000) ret |= MIX_AUXC_S; - if (mixer_control & 0x40000000) ret |= MIX_AUXC_S_RAMP; + if (mixer_control & 0x00000001) + ret |= MIX_L; + if (mixer_control & 0x00000002) + ret |= MIX_R; + if (mixer_control & 0x00000004) + ret |= MIX_L_RAMP | MIX_R_RAMP; + if (mixer_control & 0x00000008) + ret |= MIX_S; + if (mixer_control & 0x00000010) + ret |= MIX_S_RAMP; + if (mixer_control & 0x00010000) + ret |= MIX_AUXA_L; + if (mixer_control & 0x00020000) + ret |= MIX_AUXA_R; + if (mixer_control & 0x00040000) + ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP; + if (mixer_control & 0x00080000) + ret |= MIX_AUXA_S; + if (mixer_control & 0x00100000) + ret |= MIX_AUXA_S_RAMP; + if (mixer_control & 0x00200000) + ret |= MIX_AUXB_L; + if (mixer_control & 0x00400000) + ret |= MIX_AUXB_R; + if (mixer_control & 0x00800000) + ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP; + if (mixer_control & 0x01000000) + ret |= MIX_AUXB_S; + if (mixer_control & 0x02000000) + ret |= MIX_AUXB_S_RAMP; + if (mixer_control & 0x04000000) + ret |= MIX_AUXC_L; + if (mixer_control & 0x08000000) + ret |= MIX_AUXC_R; + if (mixer_control & 0x10000000) + ret |= MIX_AUXC_L_RAMP | MIX_AUXC_R_RAMP; + if (mixer_control & 0x20000000) + ret |= MIX_AUXC_S; + if (mixer_control & 0x40000000) + ret |= MIX_AUXC_S_RAMP; - return (AXMixControl)ret; + return (AXMixControl)ret; } void AXWiiUCode::GenerateVolumeRamp(u16* output, u16 vol1, u16 vol2, size_t nvals) { - float curr = vol1; - for (size_t i = 0; i < nvals; ++i) - { - curr += (vol2 - vol1) / (float)nvals; - output[i] = (u16) curr; - } + float curr = vol1; + for (size_t i = 0; i < nvals; ++i) + { + curr += (vol2 - vol1) / (float)nvals; + output[i] = (u16)curr; + } } bool AXWiiUCode::ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* updates, - u32* updates_addr) + u32* updates_addr) { - u16* pb_mem = (u16*)&pb; + u16* pb_mem = (u16*)&pb; - if (!m_old_axwii) - return false; + if (!m_old_axwii) + return false; - // Copy the num_updates field. - memcpy(num_updates, pb_mem + 41, 6); + // Copy the num_updates field. + memcpy(num_updates, pb_mem + 41, 6); - // Get the address of the updates data - u16 addr_hi = pb_mem[44]; - u16 addr_lo = pb_mem[45]; - u32 addr = HILO_TO_32(addr); - u16* ptr = (u16*)HLEMemory_Get_Pointer(addr); + // Get the address of the updates data + u16 addr_hi = pb_mem[44]; + u16 addr_lo = pb_mem[45]; + u32 addr = HILO_TO_32(addr); + u16* ptr = (u16*)HLEMemory_Get_Pointer(addr); - *updates_addr = addr; + *updates_addr = addr; - // Copy the updates data and change the offset to match a PB without - // updates data. - u32 updates_count = num_updates[0] + num_updates[1] + num_updates[2]; - for (u32 i = 0; i < updates_count; ++i) - { - u16 update_off = Common::swap16(ptr[2 * i]); - u16 update_val = Common::swap16(ptr[2 * i + 1]); + // Copy the updates data and change the offset to match a PB without + // updates data. + u32 updates_count = num_updates[0] + num_updates[1] + num_updates[2]; + for (u32 i = 0; i < updates_count; ++i) + { + u16 update_off = Common::swap16(ptr[2 * i]); + u16 update_val = Common::swap16(ptr[2 * i + 1]); - if (update_off > 45) - update_off -= 5; + if (update_off > 45) + update_off -= 5; - updates[2 * i] = update_off; - updates[2 * i + 1] = update_val; - } + updates[2 * i] = update_off; + updates[2 * i + 1] = update_val; + } - // Remove the updates data from the PB - memmove(pb_mem + 41, pb_mem + 46, sizeof (pb) - 2 * 46); + // Remove the updates data from the PB + memmove(pb_mem + 41, pb_mem + 46, sizeof(pb) - 2 * 46); - return true; + return true; } void AXWiiUCode::ReinjectUpdatesFields(AXPBWii& pb, u16* num_updates, u32 updates_addr) { - u16* pb_mem = (u16*)&pb; + u16* pb_mem = (u16*)&pb; - // Make some space - memmove(pb_mem + 46, pb_mem + 41, sizeof (pb) - 2 * 46); + // Make some space + memmove(pb_mem + 46, pb_mem + 41, sizeof(pb) - 2 * 46); - // Reinsert previous values - pb_mem[41] = num_updates[0]; - pb_mem[42] = num_updates[1]; - pb_mem[43] = num_updates[2]; - pb_mem[44] = updates_addr >> 16; - pb_mem[45] = updates_addr & 0xFFFF; + // Reinsert previous values + pb_mem[41] = num_updates[0]; + pb_mem[42] = num_updates[1]; + pb_mem[43] = num_updates[2]; + pb_mem[44] = updates_addr >> 16; + pb_mem[45] = updates_addr & 0xFFFF; } void AXWiiUCode::ProcessPBList(u32 pb_addr) { - AXPBWii pb; + AXPBWii pb; - while (pb_addr) - { - AXBuffers buffers = {{ - m_samples_left, - m_samples_right, - m_samples_surround, - m_samples_auxA_left, - m_samples_auxA_right, - m_samples_auxA_surround, - m_samples_auxB_left, - m_samples_auxB_right, - m_samples_auxB_surround, - m_samples_auxC_left, - m_samples_auxC_right, - m_samples_auxC_surround, - m_samples_wm0, - m_samples_aux0, - m_samples_wm1, - m_samples_aux1, - m_samples_wm2, - m_samples_aux2, - m_samples_wm3, - m_samples_aux3 - }}; + while (pb_addr) + { + AXBuffers buffers = {{m_samples_left, m_samples_right, m_samples_surround, + m_samples_auxA_left, m_samples_auxA_right, m_samples_auxA_surround, + m_samples_auxB_left, m_samples_auxB_right, m_samples_auxB_surround, + m_samples_auxC_left, m_samples_auxC_right, m_samples_auxC_surround, + m_samples_wm0, m_samples_aux0, m_samples_wm1, + m_samples_aux1, m_samples_wm2, m_samples_aux2, + m_samples_wm3, m_samples_aux3}}; - ReadPB(pb_addr, pb); + ReadPB(pb_addr, pb); - u16 num_updates[3]; - u16 updates[1024]; - u32 updates_addr; - if (ExtractUpdatesFields(pb, num_updates, updates, &updates_addr)) - { - for (int curr_ms = 0; curr_ms < 3; ++curr_ms) - { - ApplyUpdatesForMs(curr_ms, (u16*)&pb, num_updates, updates); - ProcessVoice(pb, buffers, 32, - ConvertMixerControl(HILO_TO_32(pb.mixer_control)), - m_coeffs_available ? m_coeffs : nullptr); + u16 num_updates[3]; + u16 updates[1024]; + u32 updates_addr; + if (ExtractUpdatesFields(pb, num_updates, updates, &updates_addr)) + { + for (int curr_ms = 0; curr_ms < 3; ++curr_ms) + { + ApplyUpdatesForMs(curr_ms, (u16*)&pb, num_updates, updates); + ProcessVoice(pb, buffers, 32, ConvertMixerControl(HILO_TO_32(pb.mixer_control)), + m_coeffs_available ? m_coeffs : nullptr); - // Forward the buffers - for (size_t i = 0; i < ArraySize(buffers.ptrs); ++i) - buffers.ptrs[i] += 32; - } - ReinjectUpdatesFields(pb, num_updates, updates_addr); - } - else - { - ProcessVoice(pb, buffers, 96, - ConvertMixerControl(HILO_TO_32(pb.mixer_control)), - m_coeffs_available ? m_coeffs : nullptr); - } + // Forward the buffers + for (size_t i = 0; i < ArraySize(buffers.ptrs); ++i) + buffers.ptrs[i] += 32; + } + ReinjectUpdatesFields(pb, num_updates, updates_addr); + } + else + { + ProcessVoice(pb, buffers, 96, ConvertMixerControl(HILO_TO_32(pb.mixer_control)), + m_coeffs_available ? m_coeffs : nullptr); + } - WritePB(pb_addr, pb); - pb_addr = HILO_TO_32(pb.next_pb); - } + WritePB(pb_addr, pb); + pb_addr = HILO_TO_32(pb.next_pb); + } } void AXWiiUCode::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume) { - u16 volume_ramp[96]; - GenerateVolumeRamp(volume_ramp, m_last_aux_volumes[aux_id], volume, ArraySize(volume_ramp)); - m_last_aux_volumes[aux_id] = volume; + u16 volume_ramp[96]; + GenerateVolumeRamp(volume_ramp, m_last_aux_volumes[aux_id], volume, ArraySize(volume_ramp)); + m_last_aux_volumes[aux_id] = volume; - int* buffers[3] = { nullptr }; - int* main_buffers[3] = { - m_samples_left, - m_samples_right, - m_samples_surround - }; + int* buffers[3] = {nullptr}; + int* main_buffers[3] = {m_samples_left, m_samples_right, m_samples_surround}; - switch (aux_id) - { - case 0: - buffers[0] = m_samples_auxA_left; - buffers[1] = m_samples_auxA_right; - buffers[2] = m_samples_auxA_surround; - break; + switch (aux_id) + { + case 0: + buffers[0] = m_samples_auxA_left; + buffers[1] = m_samples_auxA_right; + buffers[2] = m_samples_auxA_surround; + break; - case 1: - buffers[0] = m_samples_auxB_left; - buffers[1] = m_samples_auxB_right; - buffers[2] = m_samples_auxB_surround; - break; + case 1: + buffers[0] = m_samples_auxB_left; + buffers[1] = m_samples_auxB_right; + buffers[2] = m_samples_auxB_surround; + break; - case 2: - buffers[0] = m_samples_auxC_left; - buffers[1] = m_samples_auxC_right; - buffers[2] = m_samples_auxC_surround; - break; - } + case 2: + buffers[0] = m_samples_auxC_left; + buffers[1] = m_samples_auxC_right; + buffers[2] = m_samples_auxC_surround; + break; + } - // Send the content of AUX buffers to the CPU - if (write_addr) - { - int* ptr = (int*)HLEMemory_Get_Pointer(write_addr); - for (auto& buffer : buffers) - for (u32 j = 0; j < 3 * 32; ++j) - *ptr++ = Common::swap32(buffer[j]); - } + // Send the content of AUX buffers to the CPU + if (write_addr) + { + int* ptr = (int*)HLEMemory_Get_Pointer(write_addr); + for (auto& buffer : buffers) + for (u32 j = 0; j < 3 * 32; ++j) + *ptr++ = Common::swap32(buffer[j]); + } - // Then read the buffers from the CPU and add to our main buffers. - int* ptr = (int*)HLEMemory_Get_Pointer(read_addr); - for (auto& main_buffer : main_buffers) - for (u32 j = 0; j < 3 * 32; ++j) - { - s64 sample = (s64)(s32)Common::swap32(*ptr++); - sample *= volume_ramp[j]; - main_buffer[j] += (s32)(sample >> 15); - } + // Then read the buffers from the CPU and add to our main buffers. + int* ptr = (int*)HLEMemory_Get_Pointer(read_addr); + for (auto& main_buffer : main_buffers) + for (u32 j = 0; j < 3 * 32; ++j) + { + s64 sample = (s64)(s32)Common::swap32(*ptr++); + sample *= volume_ramp[j]; + main_buffer[j] += (s32)(sample >> 15); + } } void AXWiiUCode::UploadAUXMixLRSC(int aux_id, u32* addresses, u16 volume) { - int* aux_left = aux_id ? m_samples_auxB_left : m_samples_auxA_left; - int* aux_right = aux_id ? m_samples_auxB_right : m_samples_auxA_right; - int* aux_surround = aux_id ? m_samples_auxB_surround : m_samples_auxA_surround; - int* auxc_buffer = aux_id ? m_samples_auxC_surround : m_samples_auxC_right; + int* aux_left = aux_id ? m_samples_auxB_left : m_samples_auxA_left; + int* aux_right = aux_id ? m_samples_auxB_right : m_samples_auxA_right; + int* aux_surround = aux_id ? m_samples_auxB_surround : m_samples_auxA_surround; + int* auxc_buffer = aux_id ? m_samples_auxC_surround : m_samples_auxC_right; - int* upload_ptr = (int*)HLEMemory_Get_Pointer(addresses[0]); - for (u32 i = 0; i < 96; ++i) - *upload_ptr++ = Common::swap32(aux_left[i]); - for (u32 i = 0; i < 96; ++i) - *upload_ptr++ = Common::swap32(aux_right[i]); - for (u32 i = 0; i < 96; ++i) - *upload_ptr++ = Common::swap32(aux_surround[i]); + int* upload_ptr = (int*)HLEMemory_Get_Pointer(addresses[0]); + for (u32 i = 0; i < 96; ++i) + *upload_ptr++ = Common::swap32(aux_left[i]); + for (u32 i = 0; i < 96; ++i) + *upload_ptr++ = Common::swap32(aux_right[i]); + for (u32 i = 0; i < 96; ++i) + *upload_ptr++ = Common::swap32(aux_surround[i]); - upload_ptr = (int*)HLEMemory_Get_Pointer(addresses[1]); - for (u32 i = 0; i < 96; ++i) - *upload_ptr++ = Common::swap32(auxc_buffer[i]); + upload_ptr = (int*)HLEMemory_Get_Pointer(addresses[1]); + for (u32 i = 0; i < 96; ++i) + *upload_ptr++ = Common::swap32(auxc_buffer[i]); - u16 volume_ramp[96]; - GenerateVolumeRamp(volume_ramp, m_last_aux_volumes[aux_id], volume, 96); - m_last_aux_volumes[aux_id] = volume; + u16 volume_ramp[96]; + GenerateVolumeRamp(volume_ramp, m_last_aux_volumes[aux_id], volume, 96); + m_last_aux_volumes[aux_id] = volume; - int* mix_dest[4] = { - m_samples_left, - m_samples_right, - m_samples_surround, - m_samples_auxC_left - }; - for (u32 mix_i = 0; mix_i < 4; ++mix_i) - { - int* dl_ptr = (int*)HLEMemory_Get_Pointer(addresses[2 + mix_i]); - for (u32 i = 0; i < 96; ++i) - aux_left[i] = Common::swap32(dl_ptr[i]); + int* mix_dest[4] = {m_samples_left, m_samples_right, m_samples_surround, m_samples_auxC_left}; + for (u32 mix_i = 0; mix_i < 4; ++mix_i) + { + int* dl_ptr = (int*)HLEMemory_Get_Pointer(addresses[2 + mix_i]); + for (u32 i = 0; i < 96; ++i) + aux_left[i] = Common::swap32(dl_ptr[i]); - for (u32 i = 0; i < 96; ++i) - { - s64 sample = (s64)(s32)aux_left[i]; - sample *= volume_ramp[i]; - mix_dest[mix_i][i] += (s32)(sample >> 15); - } - } + for (u32 i = 0; i < 96; ++i) + { + s64 sample = (s64)(s32)aux_left[i]; + sample *= volume_ramp[i]; + mix_dest[mix_i][i] += (s32)(sample >> 15); + } + } } -void AXWiiUCode::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume, - bool upload_auxc) +void AXWiiUCode::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume, bool upload_auxc) { - u16 volume_ramp[96]; - GenerateVolumeRamp(volume_ramp, m_last_main_volume, volume, ArraySize(volume_ramp)); - m_last_main_volume = volume; + u16 volume_ramp[96]; + GenerateVolumeRamp(volume_ramp, m_last_main_volume, volume, ArraySize(volume_ramp)); + m_last_main_volume = volume; - int upload_buffer[3 * 32] = { 0 }; + int upload_buffer[3 * 32] = {0}; - for (u32 i = 0; i < 3 * 32; ++i) - upload_buffer[i] = Common::swap32(m_samples_surround[i]); - memcpy(HLEMemory_Get_Pointer(surround_addr), upload_buffer, sizeof (upload_buffer)); + for (u32 i = 0; i < 3 * 32; ++i) + upload_buffer[i] = Common::swap32(m_samples_surround[i]); + memcpy(HLEMemory_Get_Pointer(surround_addr), upload_buffer, sizeof(upload_buffer)); - if (upload_auxc) - { - surround_addr += sizeof (upload_buffer); - for (u32 i = 0; i < 3 * 32; ++i) - upload_buffer[i] = Common::swap32(m_samples_auxC_left[i]); - memcpy(HLEMemory_Get_Pointer(surround_addr), upload_buffer, sizeof (upload_buffer)); - } + if (upload_auxc) + { + surround_addr += sizeof(upload_buffer); + for (u32 i = 0; i < 3 * 32; ++i) + upload_buffer[i] = Common::swap32(m_samples_auxC_left[i]); + memcpy(HLEMemory_Get_Pointer(surround_addr), upload_buffer, sizeof(upload_buffer)); + } - short buffer[3 * 32 * 2]; + short buffer[3 * 32 * 2]; - // Clamp internal buffers to 16 bits. - for (u32 i = 0; i < 3 * 32; ++i) - { - int left = m_samples_left[i]; - int right = m_samples_right[i]; + // Clamp internal buffers to 16 bits. + for (u32 i = 0; i < 3 * 32; ++i) + { + int left = m_samples_left[i]; + int right = m_samples_right[i]; - // Apply global volume. Cast to s64 to avoid overflow. - left = ((s64)left * volume_ramp[i]) >> 15; - right = ((s64)right * volume_ramp[i]) >> 15; + // Apply global volume. Cast to s64 to avoid overflow. + left = ((s64)left * volume_ramp[i]) >> 15; + right = ((s64)right * volume_ramp[i]) >> 15; - m_samples_left[i] = MathUtil::Clamp(left, -32767, 32767); - m_samples_right[i] = MathUtil::Clamp(right, -32767, 32767); - } + m_samples_left[i] = MathUtil::Clamp(left, -32767, 32767); + m_samples_right[i] = MathUtil::Clamp(right, -32767, 32767); + } - for (u32 i = 0; i < 3 * 32; ++i) - { - buffer[2 * i] = Common::swap16(m_samples_right[i]); - buffer[2 * i + 1] = Common::swap16(m_samples_left[i]); - } + for (u32 i = 0; i < 3 * 32; ++i) + { + buffer[2 * i] = Common::swap16(m_samples_right[i]); + buffer[2 * i + 1] = Common::swap16(m_samples_left[i]); + } - memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer)); + memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof(buffer)); - // There should be a DSP_SYNC message sent here. However, it looks like not - // sending it does not cause any issue, and sending it actually causes some - // sounds to go at half speed. I have no idea why. + // There should be a DSP_SYNC message sent here. However, it looks like not + // sending it does not cause any issue, and sending it actually causes some + // sounds to go at half speed. I have no idea why. } void AXWiiUCode::OutputWMSamples(u32* addresses) { - int* buffers[] = { - m_samples_wm0, - m_samples_wm1, - m_samples_wm2, - m_samples_wm3 - }; + int* buffers[] = {m_samples_wm0, m_samples_wm1, m_samples_wm2, m_samples_wm3}; - for (u32 i = 0; i < 4; ++i) - { - int* in = buffers[i]; - u16* out = (u16*)HLEMemory_Get_Pointer(addresses[i]); - for (u32 j = 0; j < 3 * 6; ++j) - { - int sample = MathUtil::Clamp(in[j], -32767, 32767); - out[j] = Common::swap16((u16)sample); - } - } + for (u32 i = 0; i < 4; ++i) + { + int* in = buffers[i]; + u16* out = (u16*)HLEMemory_Get_Pointer(addresses[i]); + for (u32 j = 0; j < 3 * 6; ++j) + { + int sample = MathUtil::Clamp(in[j], -32767, 32767); + out[j] = Common::swap16((u16)sample); + } + } } -void AXWiiUCode::DoState(PointerWrap &p) +void AXWiiUCode::DoState(PointerWrap& p) { - DoStateShared(p); - DoAXState(p); + DoStateShared(p); + DoAXState(p); - p.Do(m_samples_auxC_left); - p.Do(m_samples_auxC_right); - p.Do(m_samples_auxC_surround); + p.Do(m_samples_auxC_left); + p.Do(m_samples_auxC_right); + p.Do(m_samples_auxC_surround); - p.Do(m_samples_wm0); - p.Do(m_samples_wm1); - p.Do(m_samples_wm2); - p.Do(m_samples_wm3); + p.Do(m_samples_wm0); + p.Do(m_samples_wm1); + p.Do(m_samples_wm2); + p.Do(m_samples_wm3); - p.Do(m_samples_aux0); - p.Do(m_samples_aux1); - p.Do(m_samples_aux2); - p.Do(m_samples_aux3); + p.Do(m_samples_aux0); + p.Do(m_samples_aux1); + p.Do(m_samples_aux2); + p.Do(m_samples_aux3); - p.Do(m_last_main_volume); - p.Do(m_last_aux_volumes); + p.Do(m_last_main_volume); + p.Do(m_last_aux_volumes); } diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.h b/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.h index f3cb27f8e7..3304cf59be 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.h @@ -11,103 +11,101 @@ struct AXPBWii; class AXWiiUCode : public AXUCode { public: - AXWiiUCode(DSPHLE *dsphle, u32 crc); - virtual ~AXWiiUCode(); + AXWiiUCode(DSPHLE* dsphle, u32 crc); + virtual ~AXWiiUCode(); - void DoState(PointerWrap &p) override; + void DoState(PointerWrap& p) override; protected: - // Additional AUX buffers - int m_samples_auxC_left[32 * 3]; - int m_samples_auxC_right[32 * 3]; - int m_samples_auxC_surround[32 * 3]; + // Additional AUX buffers + int m_samples_auxC_left[32 * 3]; + int m_samples_auxC_right[32 * 3]; + int m_samples_auxC_surround[32 * 3]; - // Wiimote buffers - int m_samples_wm0[6 * 3]; - int m_samples_aux0[6 * 3]; - int m_samples_wm1[6 * 3]; - int m_samples_aux1[6 * 3]; - int m_samples_wm2[6 * 3]; - int m_samples_aux2[6 * 3]; - int m_samples_wm3[6 * 3]; - int m_samples_aux3[6 * 3]; + // Wiimote buffers + int m_samples_wm0[6 * 3]; + int m_samples_aux0[6 * 3]; + int m_samples_wm1[6 * 3]; + int m_samples_aux1[6 * 3]; + int m_samples_wm2[6 * 3]; + int m_samples_aux2[6 * 3]; + int m_samples_wm3[6 * 3]; + int m_samples_aux3[6 * 3]; - // Are we implementing an old version of AXWii which still has updates? - bool m_old_axwii; + // Are we implementing an old version of AXWii which still has updates? + bool m_old_axwii; - // Last volume values for MAIN and AUX. Used to generate volume ramps to - // interpolate nicely between old and new volume values. - u16 m_last_main_volume; - u16 m_last_aux_volumes[3]; + // Last volume values for MAIN and AUX. Used to generate volume ramps to + // interpolate nicely between old and new volume values. + u16 m_last_main_volume; + u16 m_last_aux_volumes[3]; - // If needed, extract the updates related fields from a PB. We need to - // reinject them afterwards so that the correct PB typs is written to RAM. - bool ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* updates, - u32* updates_addr); - void ReinjectUpdatesFields(AXPBWii& pb, u16* num_updates, u32 updates_addr); + // If needed, extract the updates related fields from a PB. We need to + // reinject them afterwards so that the correct PB typs is written to RAM. + bool ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* updates, u32* updates_addr); + void ReinjectUpdatesFields(AXPBWii& pb, u16* num_updates, u32 updates_addr); - // Convert a mixer_control bitfield to our internal representation for that - // value. Required because that bitfield has a different meaning in some - // versions of AX. - AXMixControl ConvertMixerControl(u32 mixer_control); + // Convert a mixer_control bitfield to our internal representation for that + // value. Required because that bitfield has a different meaning in some + // versions of AX. + AXMixControl ConvertMixerControl(u32 mixer_control); - // Generate a volume ramp from vol1 to vol2, interpolating n volume values. - // Uses floating point arithmetic, which isn't exactly what the UCode does, - // but this gives better precision and nicer code. - void GenerateVolumeRamp(u16* output, u16 vol1, u16 vol2, size_t nvals); + // Generate a volume ramp from vol1 to vol2, interpolating n volume values. + // Uses floating point arithmetic, which isn't exactly what the UCode does, + // but this gives better precision and nicer code. + void GenerateVolumeRamp(u16* output, u16 vol1, u16 vol2, size_t nvals); - void HandleCommandList() override; + void HandleCommandList() override; - void SetupProcessing(u32 init_addr); - void AddToLR(u32 val_addr, bool neg); - void AddSubToLR(u32 val_addr); - void ProcessPBList(u32 pb_addr); - void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume); - void UploadAUXMixLRSC(int aux_id, u32* addresses, u16 volume); - void OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume, - bool upload_auxc); - void OutputWMSamples(u32* addresses); // 4 addresses + void SetupProcessing(u32 init_addr); + void AddToLR(u32 val_addr, bool neg); + void AddSubToLR(u32 val_addr); + void ProcessPBList(u32 pb_addr); + void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume); + void UploadAUXMixLRSC(int aux_id, u32* addresses, u16 volume); + void OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume, bool upload_auxc); + void OutputWMSamples(u32* addresses); // 4 addresses private: - enum CmdType - { - CMD_SETUP = 0x00, - CMD_ADD_TO_LR = 0x01, - CMD_SUB_TO_LR = 0x02, - CMD_ADD_SUB_TO_LR = 0x03, - CMD_PROCESS = 0x04, - CMD_MIX_AUXA = 0x05, - CMD_MIX_AUXB = 0x06, - CMD_MIX_AUXC = 0x07, - CMD_UPL_AUXA_MIX_LRSC = 0x08, - CMD_UPL_AUXB_MIX_LRSC = 0x09, - CMD_UNK_0A = 0x0A, - CMD_OUTPUT = 0x0B, - CMD_OUTPUT_DPL2 = 0x0C, - CMD_WM_OUTPUT = 0x0D, - CMD_END = 0x0E, - }; + enum CmdType + { + CMD_SETUP = 0x00, + CMD_ADD_TO_LR = 0x01, + CMD_SUB_TO_LR = 0x02, + CMD_ADD_SUB_TO_LR = 0x03, + CMD_PROCESS = 0x04, + CMD_MIX_AUXA = 0x05, + CMD_MIX_AUXB = 0x06, + CMD_MIX_AUXC = 0x07, + CMD_UPL_AUXA_MIX_LRSC = 0x08, + CMD_UPL_AUXB_MIX_LRSC = 0x09, + CMD_UNK_0A = 0x0A, + CMD_OUTPUT = 0x0B, + CMD_OUTPUT_DPL2 = 0x0C, + CMD_WM_OUTPUT = 0x0D, + CMD_END = 0x0E, + }; - // A lot of these are similar to the new version, but there is an offset in - // the command ids due to the PB_ADDR command (which was removed from the - // new AXWii). - enum CmdTypeOld - { - CMD_SETUP_OLD = 0x00, - CMD_ADD_TO_LR_OLD = 0x01, - CMD_SUB_TO_LR_OLD = 0x02, - CMD_ADD_SUB_TO_LR_OLD = 0x03, - CMD_PB_ADDR_OLD = 0x04, - CMD_PROCESS_OLD = 0x05, - CMD_MIX_AUXA_OLD = 0x06, - CMD_MIX_AUXB_OLD = 0x07, - CMD_MIX_AUXC_OLD = 0x08, - CMD_UPL_AUXA_MIX_LRSC_OLD = 0x09, - CMD_UPL_AUXB_MIX_LRSC_OLD = 0x0a, - CMD_UNK_0B_OLD = 0x0B, - CMD_OUTPUT_OLD = 0x0C, // no volume! - CMD_OUTPUT_DPL2_OLD = 0x0D, - CMD_WM_OUTPUT_OLD = 0x0E, - CMD_END_OLD = 0x0F - }; + // A lot of these are similar to the new version, but there is an offset in + // the command ids due to the PB_ADDR command (which was removed from the + // new AXWii). + enum CmdTypeOld + { + CMD_SETUP_OLD = 0x00, + CMD_ADD_TO_LR_OLD = 0x01, + CMD_SUB_TO_LR_OLD = 0x02, + CMD_ADD_SUB_TO_LR_OLD = 0x03, + CMD_PB_ADDR_OLD = 0x04, + CMD_PROCESS_OLD = 0x05, + CMD_MIX_AUXA_OLD = 0x06, + CMD_MIX_AUXB_OLD = 0x07, + CMD_MIX_AUXC_OLD = 0x08, + CMD_UPL_AUXA_MIX_LRSC_OLD = 0x09, + CMD_UPL_AUXB_MIX_LRSC_OLD = 0x0a, + CMD_UNK_0B_OLD = 0x0B, + CMD_OUTPUT_OLD = 0x0C, // no volume! + CMD_OUTPUT_DPL2_OLD = 0x0D, + CMD_WM_OUTPUT_OLD = 0x0E, + CMD_END_OLD = 0x0F + }; }; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/CARD.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/CARD.cpp index 5ec02707d7..1b25a4f21b 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/CARD.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/CARD.cpp @@ -2,50 +2,44 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/DSPHLE/UCodes/CARD.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Core/HW/DSP.h" #include "Core/HW/DSPHLE/DSPHLE.h" -#include "Core/HW/DSPHLE/UCodes/CARD.h" #include "Core/HW/DSPHLE/UCodes/UCodes.h" - -CARDUCode::CARDUCode(DSPHLE *dsphle, u32 crc) - : UCodeInterface(dsphle, crc) +CARDUCode::CARDUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc) { - DEBUG_LOG(DSPHLE, "CARDUCode - initialized"); - m_mail_handler.PushMail(DSP_INIT); + DEBUG_LOG(DSPHLE, "CARDUCode - initialized"); + m_mail_handler.PushMail(DSP_INIT); } - CARDUCode::~CARDUCode() { - m_mail_handler.Clear(); + m_mail_handler.Clear(); } - void CARDUCode::Update() { - // check if we have to sent something - if (!m_mail_handler.IsEmpty()) - { - DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); - } + // check if we have to sent something + if (!m_mail_handler.IsEmpty()) + { + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + } } void CARDUCode::HandleMail(u32 mail) { - if (mail == 0xFF000000) // unlock card - { - // m_Mails.push(0x00000001); // ACK (actually anything != 0) - } - else - { - DEBUG_LOG(DSPHLE, "CARDUCode - unknown command: %x", mail); - } + if (mail == 0xFF000000) // unlock card + { + // m_Mails.push(0x00000001); // ACK (actually anything != 0) + } + else + { + DEBUG_LOG(DSPHLE, "CARDUCode - unknown command: %x", mail); + } - m_mail_handler.PushMail(DSP_DONE); - m_dsphle->SetUCode(UCODE_ROM); + m_mail_handler.PushMail(DSP_DONE); + m_dsphle->SetUCode(UCODE_ROM); } - - diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/CARD.h b/Source/Core/Core/HW/DSPHLE/UCodes/CARD.h index a3978aeee0..7dcc9779a6 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/CARD.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/CARD.h @@ -9,10 +9,9 @@ class CARDUCode : public UCodeInterface { public: - CARDUCode(DSPHLE *dsphle, u32 crc); - virtual ~CARDUCode(); + CARDUCode(DSPHLE* dsphle, u32 crc); + virtual ~CARDUCode(); - void HandleMail(u32 mail) override; - void Update() override; + void HandleMail(u32 mail) override; + void Update() override; }; - diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp index df364b27a7..83e64d9556 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp @@ -2,147 +2,144 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/DSPHLE/UCodes/GBA.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Core/HW/DSP.h" -#include "Core/HW/DSPHLE/UCodes/GBA.h" #include "Core/HW/DSPHLE/UCodes/UCodes.h" void ProcessGBACrypto(u32 address) { - struct sec_params_t - { - u16 key[2]; - u16 unk1[2]; - u16 unk2[2]; - u32 length; - u32 dest_addr; - u32 pad[3]; - } sec_params; + struct sec_params_t + { + u16 key[2]; + u16 unk1[2]; + u16 unk2[2]; + u32 length; + u32 dest_addr; + u32 pad[3]; + } sec_params; - // 32 bytes from mram addr to DRAM @ 0 - for (int i = 0; i < 8; i++, address += 4) - ((u32*)&sec_params)[i] = HLEMemory_Read_U32(address); + // 32 bytes from mram addr to DRAM @ 0 + for (int i = 0; i < 8; i++, address += 4) + ((u32*)&sec_params)[i] = HLEMemory_Read_U32(address); - // This is the main decrypt routine - u16 x11 = 0, x12 = 0, - x20 = 0, x21 = 0, x22 = 0, x23 = 0; + // This is the main decrypt routine + u16 x11 = 0, x12 = 0, x20 = 0, x21 = 0, x22 = 0, x23 = 0; - x20 = Common::swap16(sec_params.key[0]) ^ 0x6f64; - x21 = Common::swap16(sec_params.key[1]) ^ 0x6573; + x20 = Common::swap16(sec_params.key[0]) ^ 0x6f64; + x21 = Common::swap16(sec_params.key[1]) ^ 0x6573; - s16 unk2 = (s8)sec_params.unk2[0]; - if (unk2 < 0) - { - x11 = ((~unk2 + 3) << 1) | (sec_params.unk1[0] << 4); - } - else if (unk2 == 0) - { - x11 = (sec_params.unk1[0] << 1) | 0x70; - } - else // unk2 > 0 - { - x11 = ((unk2 - 1) << 1) | (sec_params.unk1[0] << 4); - } + s16 unk2 = (s8)sec_params.unk2[0]; + if (unk2 < 0) + { + x11 = ((~unk2 + 3) << 1) | (sec_params.unk1[0] << 4); + } + else if (unk2 == 0) + { + x11 = (sec_params.unk1[0] << 1) | 0x70; + } + else // unk2 > 0 + { + x11 = ((unk2 - 1) << 1) | (sec_params.unk1[0] << 4); + } - s32 rounded_sub = ((sec_params.length + 7) & ~7) - 0x200; - u16 size = (rounded_sub < 0) ? 0 : rounded_sub >> 3; + s32 rounded_sub = ((sec_params.length + 7) & ~7) - 0x200; + u16 size = (rounded_sub < 0) ? 0 : rounded_sub >> 3; - u32 t = (((size << 16) | 0x3f80) & 0x3f80ffff) << 1; - s16 t_low = (s8)(t >> 8); - t += (t_low & size) << 16; - x12 = t >> 16; - x11 |= (size & 0x4000) >> 14; // this would be stored in ac0.h if we weren't constrained to 32bit :) - t = ((x11 & 0xff) << 16) + ((x12 & 0xff) << 16) + (x12 << 8); + u32 t = (((size << 16) | 0x3f80) & 0x3f80ffff) << 1; + s16 t_low = (s8)(t >> 8); + t += (t_low & size) << 16; + x12 = t >> 16; + x11 |= + (size & 0x4000) >> 14; // this would be stored in ac0.h if we weren't constrained to 32bit :) + t = ((x11 & 0xff) << 16) + ((x12 & 0xff) << 16) + (x12 << 8); - u16 final11 = 0, final12 = 0; - final11 = x11 | ((t >> 8) & 0xff00) | 0x8080; - final12 = x12 | 0x8080; + u16 final11 = 0, final12 = 0; + final11 = x11 | ((t >> 8) & 0xff00) | 0x8080; + final12 = x12 | 0x8080; - if ((final12 & 0x200) != 0) - { - x22 = final11 ^ 0x6f64; - x23 = final12 ^ 0x6573; - } - else - { - x22 = final11 ^ 0x6177; - x23 = final12 ^ 0x614b; - } + if ((final12 & 0x200) != 0) + { + x22 = final11 ^ 0x6f64; + x23 = final12 ^ 0x6573; + } + else + { + x22 = final11 ^ 0x6177; + x23 = final12 ^ 0x614b; + } - // Send the result back to mram - *(u32*)HLEMemory_Get_Pointer(sec_params.dest_addr) = Common::swap32((x20 << 16) | x21); - *(u32*)HLEMemory_Get_Pointer(sec_params.dest_addr+4) = Common::swap32((x22 << 16) | x23); + // Send the result back to mram + *(u32*)HLEMemory_Get_Pointer(sec_params.dest_addr) = Common::swap32((x20 << 16) | x21); + *(u32*)HLEMemory_Get_Pointer(sec_params.dest_addr + 4) = Common::swap32((x22 << 16) | x23); - // Done! - DEBUG_LOG(DSPHLE, "\n%08x -> key: %08x, len: %08x, dest_addr: %08x, unk1: %08x, unk2: %08x" - " 22: %04x, 23: %04x", - address, - *(u32*)sec_params.key, sec_params.length, sec_params.dest_addr, - *(u32*)sec_params.unk1, *(u32*)sec_params.unk2, - x22, x23); + // Done! + DEBUG_LOG(DSPHLE, "\n%08x -> key: %08x, len: %08x, dest_addr: %08x, unk1: %08x, unk2: %08x" + " 22: %04x, 23: %04x", + address, *(u32*)sec_params.key, sec_params.length, sec_params.dest_addr, + *(u32*)sec_params.unk1, *(u32*)sec_params.unk2, x22, x23); } -GBAUCode::GBAUCode(DSPHLE *dsphle, u32 crc) -: UCodeInterface(dsphle, crc) +GBAUCode::GBAUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc) { - m_mail_handler.PushMail(DSP_INIT); + m_mail_handler.PushMail(DSP_INIT); } GBAUCode::~GBAUCode() { - m_mail_handler.Clear(); + m_mail_handler.Clear(); } void GBAUCode::Update() { - // check if we have to send something - if (!m_mail_handler.IsEmpty()) - { - DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); - } + // check if we have to send something + if (!m_mail_handler.IsEmpty()) + { + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + } } void GBAUCode::HandleMail(u32 mail) { - static bool nextmail_is_mramaddr = false; - static bool calc_done = false; + static bool nextmail_is_mramaddr = false; + static bool calc_done = false; - if (m_upload_setup_in_progress) - { - PrepareBootUCode(mail); - } - else if ((mail >> 16 == 0xabba) && !nextmail_is_mramaddr) - { - nextmail_is_mramaddr = true; - } - else if (nextmail_is_mramaddr) - { - nextmail_is_mramaddr = false; + if (m_upload_setup_in_progress) + { + PrepareBootUCode(mail); + } + else if ((mail >> 16 == 0xabba) && !nextmail_is_mramaddr) + { + nextmail_is_mramaddr = true; + } + else if (nextmail_is_mramaddr) + { + nextmail_is_mramaddr = false; - ProcessGBACrypto(mail); + ProcessGBACrypto(mail); - calc_done = true; - m_mail_handler.PushMail(DSP_DONE); - } - else if ((mail >> 16 == 0xcdd1) && calc_done) - { - switch (mail & 0xffff) - { - case 1: - m_upload_setup_in_progress = true; - break; - case 2: - m_dsphle->SetUCode(UCODE_ROM); - break; - default: - DEBUG_LOG(DSPHLE, "GBAUCode - unknown 0xcdd1 command: %08x", mail); - break; - } - } - else - { - DEBUG_LOG(DSPHLE, "GBAUCode - unknown command: %08x", mail); - } + calc_done = true; + m_mail_handler.PushMail(DSP_DONE); + } + else if ((mail >> 16 == 0xcdd1) && calc_done) + { + switch (mail & 0xffff) + { + case 1: + m_upload_setup_in_progress = true; + break; + case 2: + m_dsphle->SetUCode(UCODE_ROM); + break; + default: + DEBUG_LOG(DSPHLE, "GBAUCode - unknown 0xcdd1 command: %08x", mail); + break; + } + } + else + { + DEBUG_LOG(DSPHLE, "GBAUCode - unknown command: %08x", mail); + } } diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/GBA.h b/Source/Core/Core/HW/DSPHLE/UCodes/GBA.h index f439a37b4f..ac99afe006 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/GBA.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/GBA.h @@ -13,9 +13,9 @@ void ProcessGBACrypto(u32 address); struct GBAUCode : public UCodeInterface { - GBAUCode(DSPHLE *dsphle, u32 crc); - virtual ~GBAUCode(); + GBAUCode(DSPHLE* dsphle, u32 crc); + virtual ~GBAUCode(); - void HandleMail(u32 mail) override; - void Update() override; + void HandleMail(u32 mail) override; + void Update() override; }; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/INIT.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/INIT.cpp index c96308eecb..dcfe8a6048 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/INIT.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/INIT.cpp @@ -2,16 +2,15 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/DSPHLE/UCodes/INIT.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" -#include "Core/HW/DSPHLE/UCodes/INIT.h" #include "Core/HW/DSPHLE/UCodes/UCodes.h" -INITUCode::INITUCode(DSPHLE *dsphle, u32 crc) - : UCodeInterface(dsphle, crc) +INITUCode::INITUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc) { - DEBUG_LOG(DSPHLE, "INITUCode - initialized"); - m_mail_handler.PushMail(0x80544348); + DEBUG_LOG(DSPHLE, "INITUCode - initialized"); + m_mail_handler.PushMail(0x80544348); } INITUCode::~INITUCode() @@ -29,5 +28,3 @@ void INITUCode::Update() void INITUCode::HandleMail(u32 mail) { } - - diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/INIT.h b/Source/Core/Core/HW/DSPHLE/UCodes/INIT.h index 716ba2cc54..2f53f91625 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/INIT.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/INIT.h @@ -9,10 +9,10 @@ class INITUCode : public UCodeInterface { public: - INITUCode(DSPHLE *dsphle, u32 crc); - virtual ~INITUCode(); + INITUCode(DSPHLE* dsphle, u32 crc); + virtual ~INITUCode(); - void HandleMail(u32 mail) override; - void Update() override; - void Init(); + void HandleMail(u32 mail) override; + void Update() override; + void Init(); }; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/ROM.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/ROM.cpp index a9f48d67d0..c70df0b4d8 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/ROM.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/ROM.cpp @@ -12,21 +12,18 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/Hash.h" -#include "Common/StringUtil.h" #include "Common/Logging/Log.h" +#include "Common/StringUtil.h" #include "Core/ConfigManager.h" #include "Core/HW/DSPHLE/UCodes/ROM.h" #include "Core/HW/DSPHLE/UCodes/UCodes.h" -ROMUCode::ROMUCode(DSPHLE *dsphle, u32 crc) - : UCodeInterface(dsphle, crc) - , m_current_ucode() - , m_boot_task_num_steps(0) - , m_next_parameter(0) +ROMUCode::ROMUCode(DSPHLE* dsphle, u32 crc) + : UCodeInterface(dsphle, crc), m_current_ucode(), m_boot_task_num_steps(0), m_next_parameter(0) { - DEBUG_LOG(DSPHLE, "UCode_Rom - initialized"); - m_mail_handler.Clear(); - m_mail_handler.PushMail(0x8071FEED); + DEBUG_LOG(DSPHLE, "UCode_Rom - initialized"); + m_mail_handler.Clear(); + m_mail_handler.PushMail(0x8071FEED); } ROMUCode::~ROMUCode() @@ -39,93 +36,93 @@ void ROMUCode::Update() void ROMUCode::HandleMail(u32 mail) { - if (m_next_parameter == 0) - { - // wait for beginning of UCode - if ((mail & 0xFFFF0000) != 0x80F30000) - { - u32 Message = 0xFEEE0000 | (mail & 0xFFFF); - m_mail_handler.PushMail(Message); - } - else - { - m_next_parameter = mail; - } - } - else - { - switch (m_next_parameter) - { - case 0x80F3A001: - m_current_ucode.m_ram_address = mail; - break; + if (m_next_parameter == 0) + { + // wait for beginning of UCode + if ((mail & 0xFFFF0000) != 0x80F30000) + { + u32 Message = 0xFEEE0000 | (mail & 0xFFFF); + m_mail_handler.PushMail(Message); + } + else + { + m_next_parameter = mail; + } + } + else + { + switch (m_next_parameter) + { + case 0x80F3A001: + m_current_ucode.m_ram_address = mail; + break; - case 0x80F3A002: - m_current_ucode.m_length = mail & 0xffff; - break; + case 0x80F3A002: + m_current_ucode.m_length = mail & 0xffff; + break; - case 0x80F3B002: - m_current_ucode.m_dmem_length = mail & 0xffff; - if (m_current_ucode.m_dmem_length) - { - NOTICE_LOG(DSPHLE, "m_current_ucode.m_dmem_length = 0x%04x.", m_current_ucode.m_dmem_length); - } - break; + case 0x80F3B002: + m_current_ucode.m_dmem_length = mail & 0xffff; + if (m_current_ucode.m_dmem_length) + { + NOTICE_LOG(DSPHLE, "m_current_ucode.m_dmem_length = 0x%04x.", + m_current_ucode.m_dmem_length); + } + break; - case 0x80F3C002: - m_current_ucode.m_imem_address = mail & 0xffff; - break; + case 0x80F3C002: + m_current_ucode.m_imem_address = mail & 0xffff; + break; - case 0x80F3D001: - m_current_ucode.m_start_pc = mail & 0xffff; - BootUCode(); - return; // Important! BootUCode indirectly does "delete this;". Must exit immediately. + case 0x80F3D001: + m_current_ucode.m_start_pc = mail & 0xffff; + BootUCode(); + return; // Important! BootUCode indirectly does "delete this;". Must exit immediately. - default: - break; - } + default: + break; + } - // THE GODDAMN OVERWRITE WAS HERE. Without the return above, since BootUCode may delete "this", well ... - m_next_parameter = 0; - } + // THE GODDAMN OVERWRITE WAS HERE. Without the return above, since BootUCode may delete "this", + // well ... + m_next_parameter = 0; + } } void ROMUCode::BootUCode() { - u32 ector_crc = HashEctor( - (u8*)HLEMemory_Get_Pointer(m_current_ucode.m_ram_address), - m_current_ucode.m_length); + u32 ector_crc = HashEctor((u8*)HLEMemory_Get_Pointer(m_current_ucode.m_ram_address), + m_current_ucode.m_length); - if (SConfig::GetInstance().m_DumpUCode) - { - std::string ucode_dump_path = StringFromFormat( - "%sDSP_UC_%08X.bin", File::GetUserPath(D_DUMPDSP_IDX).c_str(), ector_crc); + if (SConfig::GetInstance().m_DumpUCode) + { + std::string ucode_dump_path = + StringFromFormat("%sDSP_UC_%08X.bin", File::GetUserPath(D_DUMPDSP_IDX).c_str(), ector_crc); - File::IOFile fp(ucode_dump_path, "wb"); - if (fp) - { - fp.WriteArray((u8*)HLEMemory_Get_Pointer(m_current_ucode.m_ram_address), - m_current_ucode.m_length); - } - } + File::IOFile fp(ucode_dump_path, "wb"); + if (fp) + { + fp.WriteArray((u8*)HLEMemory_Get_Pointer(m_current_ucode.m_ram_address), + m_current_ucode.m_length); + } + } - DEBUG_LOG(DSPHLE, "CurrentUCode SOURCE Addr: 0x%08x", m_current_ucode.m_ram_address); - DEBUG_LOG(DSPHLE, "CurrentUCode Length: 0x%08x", m_current_ucode.m_length); - DEBUG_LOG(DSPHLE, "CurrentUCode DEST Addr: 0x%08x", m_current_ucode.m_imem_address); - DEBUG_LOG(DSPHLE, "CurrentUCode DMEM Length: 0x%08x", m_current_ucode.m_dmem_length); - DEBUG_LOG(DSPHLE, "CurrentUCode init_vector: 0x%08x", m_current_ucode.m_start_pc); - DEBUG_LOG(DSPHLE, "CurrentUCode CRC: 0x%08x", ector_crc); - DEBUG_LOG(DSPHLE, "BootTask - done"); + DEBUG_LOG(DSPHLE, "CurrentUCode SOURCE Addr: 0x%08x", m_current_ucode.m_ram_address); + DEBUG_LOG(DSPHLE, "CurrentUCode Length: 0x%08x", m_current_ucode.m_length); + DEBUG_LOG(DSPHLE, "CurrentUCode DEST Addr: 0x%08x", m_current_ucode.m_imem_address); + DEBUG_LOG(DSPHLE, "CurrentUCode DMEM Length: 0x%08x", m_current_ucode.m_dmem_length); + DEBUG_LOG(DSPHLE, "CurrentUCode init_vector: 0x%08x", m_current_ucode.m_start_pc); + DEBUG_LOG(DSPHLE, "CurrentUCode CRC: 0x%08x", ector_crc); + DEBUG_LOG(DSPHLE, "BootTask - done"); - m_dsphle->SetUCode(ector_crc); + m_dsphle->SetUCode(ector_crc); } -void ROMUCode::DoState(PointerWrap &p) +void ROMUCode::DoState(PointerWrap& p) { - p.Do(m_current_ucode); - p.Do(m_boot_task_num_steps); - p.Do(m_next_parameter); + p.Do(m_current_ucode); + p.Do(m_boot_task_num_steps); + p.Do(m_next_parameter); - DoStateShared(p); + DoStateShared(p); } - diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/ROM.h b/Source/Core/Core/HW/DSPHLE/UCodes/ROM.h index 41092b1dd0..9d1100f3aa 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/ROM.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/ROM.h @@ -9,27 +9,27 @@ class ROMUCode : public UCodeInterface { public: - ROMUCode(DSPHLE* dsphle, u32 crc); - virtual ~ROMUCode(); + ROMUCode(DSPHLE* dsphle, u32 crc); + virtual ~ROMUCode(); - void HandleMail(u32 mail) override; - void Update() override; + void HandleMail(u32 mail) override; + void Update() override; - void DoState(PointerWrap &p) override; + void DoState(PointerWrap& p) override; private: - struct UCodeBootInfo - { - u32 m_ram_address; - u32 m_length; - u32 m_imem_address; - u32 m_dmem_length; - u32 m_start_pc; - }; - UCodeBootInfo m_current_ucode; - int m_boot_task_num_steps; + struct UCodeBootInfo + { + u32 m_ram_address; + u32 m_length; + u32 m_imem_address; + u32 m_dmem_length; + u32 m_start_pc; + }; + UCodeBootInfo m_current_ucode; + int m_boot_task_num_steps; - u32 m_next_parameter; + u32 m_next_parameter; - void BootUCode(); + void BootUCode(); }; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp index a74d4db256..2997148bc3 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp @@ -12,8 +12,8 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/Hash.h" -#include "Common/StringUtil.h" #include "Common/Logging/Log.h" +#include "Common/StringUtil.h" #include "Core/ConfigManager.h" #include "Core/HW/DSPHLE/UCodes/AX.h" #include "Core/HW/DSPHLE/UCodes/AXWii.h" @@ -26,163 +26,183 @@ UCodeInterface* UCodeFactory(u32 crc, DSPHLE* dsphle, bool wii) { - switch (crc) - { - case UCODE_ROM: - INFO_LOG(DSPHLE, "Switching to ROM ucode"); - return new ROMUCode(dsphle, crc); + switch (crc) + { + case UCODE_ROM: + INFO_LOG(DSPHLE, "Switching to ROM ucode"); + return new ROMUCode(dsphle, crc); - case UCODE_INIT_AUDIO_SYSTEM: - INFO_LOG(DSPHLE, "Switching to INIT ucode"); - return new INITUCode(dsphle, crc); + case UCODE_INIT_AUDIO_SYSTEM: + INFO_LOG(DSPHLE, "Switching to INIT ucode"); + return new INITUCode(dsphle, crc); - case 0x65d6cc6f: // CARD - INFO_LOG(DSPHLE, "Switching to CARD ucode"); - return new CARDUCode(dsphle, crc); + case 0x65d6cc6f: // CARD + INFO_LOG(DSPHLE, "Switching to CARD ucode"); + return new CARDUCode(dsphle, crc); - case 0xdd7e72d5: - INFO_LOG(DSPHLE, "Switching to GBA ucode"); - return new GBAUCode(dsphle, crc); + case 0xdd7e72d5: + INFO_LOG(DSPHLE, "Switching to GBA ucode"); + return new GBAUCode(dsphle, crc); - case 0x3ad3b7ac: // Naruto 3, Paper Mario - The Thousand Year Door - case 0x3daf59b9: // Alien Hominid - case 0x4e8a8b21: // spdemo, Crazy Taxi, 18 Wheeler, Disney, Monkeyball 1/2, Cubivore, Nintendo Puzzle Collection, Wario, - // Capcom vs. SNK 2, Naruto 2, Lost Kingdoms, Star Fox, Mario Party 4, Mortal Kombat, - // Smugglers Run Warzone, Smash Brothers, Sonic Mega Collection, ZooCube - // nddemo, Star Fox - case 0x07f88145: // bustamove, Ikaruga, F-Zero GX, Robotech Battle Cry, Star Soldier, Soul Calibur 2, - // Zelda:OOT, Tony Hawk, Viewtiful Joe - case 0xe2136399: // Billy Hatcher, Dragon Ball Z, Mario Party 5, TMNT, 1080° Avalanche - case 0x3389a79e: // MP1/MP2 Wii (Metroid Prime Trilogy) - INFO_LOG(DSPHLE, "CRC %08x: AX ucode chosen", crc); - return new AXUCode(dsphle, crc); + case 0x3ad3b7ac: // Naruto 3, Paper Mario - The Thousand Year Door + case 0x3daf59b9: // Alien Hominid + case 0x4e8a8b21: // spdemo, Crazy Taxi, 18 Wheeler, Disney, Monkeyball 1/2, Cubivore, Nintendo + // Puzzle Collection, Wario, + // Capcom vs. SNK 2, Naruto 2, Lost Kingdoms, Star Fox, Mario Party 4, Mortal Kombat, + // Smugglers Run Warzone, Smash Brothers, Sonic Mega Collection, ZooCube + // nddemo, Star Fox + case 0x07f88145: // bustamove, Ikaruga, F-Zero GX, Robotech Battle Cry, Star Soldier, Soul + // Calibur 2, + // Zelda:OOT, Tony Hawk, Viewtiful Joe + case 0xe2136399: // Billy Hatcher, Dragon Ball Z, Mario Party 5, TMNT, 1080° Avalanche + case 0x3389a79e: // MP1/MP2 Wii (Metroid Prime Trilogy) + INFO_LOG(DSPHLE, "CRC %08x: AX ucode chosen", crc); + return new AXUCode(dsphle, crc); - case 0x86840740: // Zelda WW - US - case 0x6ca33a6d: // Zelda TP GC - US - case 0xd643001f: // Super Mario Galaxy - US - case 0x6ba3b3ea: // GC IPL - PAL - case 0x24b22038: // GC IPL - US - case 0x2fcdf1ec: // Zelda FSA - US - case 0x4be6a5cb: // Pikmin 1 GC - US - case 0x267fd05a: // Pikmin 1 GC - PAL - case 0x42f64ac4: // Luigi's Mansion - US - case 0x56d36052: // Super Mario Sunshine - US - case 0x6c3f6f94: // Zelda TP Wii - US - case 0xb7eb9a9c: // Pikmin 1 New Play Control Wii - US - case 0xeaeb38cc: // Pikmin 2 New Play Control Wii - US - return new ZeldaUCode(dsphle, crc); + case 0x86840740: // Zelda WW - US + case 0x6ca33a6d: // Zelda TP GC - US + case 0xd643001f: // Super Mario Galaxy - US + case 0x6ba3b3ea: // GC IPL - PAL + case 0x24b22038: // GC IPL - US + case 0x2fcdf1ec: // Zelda FSA - US + case 0x4be6a5cb: // Pikmin 1 GC - US + case 0x267fd05a: // Pikmin 1 GC - PAL + case 0x42f64ac4: // Luigi's Mansion - US + case 0x56d36052: // Super Mario Sunshine - US + case 0x6c3f6f94: // Zelda TP Wii - US + case 0xb7eb9a9c: // Pikmin 1 New Play Control Wii - US + case 0xeaeb38cc: // Pikmin 2 New Play Control Wii - US + return new ZeldaUCode(dsphle, crc); - case 0x2ea36ce6: // Some Wii demos - case 0x5ef56da3: // AX demo - case 0x347112ba: // Raving Rabbids - case 0xfa450138: // Wii Sports - PAL - case 0xadbc06bd: // Elebits - case 0x4cc52064: // Bleach: Versus Crusade - case 0xd9c4bf34: // WiiMenu - INFO_LOG(DSPHLE, "CRC %08x: Wii - AXWii chosen", crc); - return new AXWiiUCode(dsphle, crc); + case 0x2ea36ce6: // Some Wii demos + case 0x5ef56da3: // AX demo + case 0x347112ba: // Raving Rabbids + case 0xfa450138: // Wii Sports - PAL + case 0xadbc06bd: // Elebits + case 0x4cc52064: // Bleach: Versus Crusade + case 0xd9c4bf34: // WiiMenu + INFO_LOG(DSPHLE, "CRC %08x: Wii - AXWii chosen", crc); + return new AXWiiUCode(dsphle, crc); - default: - if (wii) - { - PanicAlertT("This title might be incompatible with DSP HLE emulation. Try using LLE if this is homebrew.\n\n" - "Unknown ucode (CRC = %08x) - forcing AXWii.", crc); - return new AXWiiUCode(dsphle, crc); - } - else - { - PanicAlertT("This title might be incompatible with DSP HLE emulation. Try using LLE if this is homebrew.\n\n" - "DSPHLE: Unknown ucode (CRC = %08x) - forcing AX.", crc); - return new AXUCode(dsphle, crc); - } + default: + if (wii) + { + PanicAlertT("This title might be incompatible with DSP HLE emulation. Try using LLE if this " + "is homebrew.\n\n" + "Unknown ucode (CRC = %08x) - forcing AXWii.", + crc); + return new AXWiiUCode(dsphle, crc); + } + else + { + PanicAlertT("This title might be incompatible with DSP HLE emulation. Try using LLE if this " + "is homebrew.\n\n" + "DSPHLE: Unknown ucode (CRC = %08x) - forcing AX.", + crc); + return new AXUCode(dsphle, crc); + } - case UCODE_NULL: - break; - } + case UCODE_NULL: + break; + } - return nullptr; + return nullptr; } bool UCodeInterface::NeedsResumeMail() { - if (m_needs_resume_mail) - { - m_needs_resume_mail = false; - return true; - } - return false; + if (m_needs_resume_mail) + { + m_needs_resume_mail = false; + return true; + } + return false; } void UCodeInterface::PrepareBootUCode(u32 mail) { - switch (m_next_ucode_steps) - { - case 0: m_next_ucode.mram_dest_addr = mail; break; - case 1: m_next_ucode.mram_size = mail & 0xffff; break; - case 2: m_next_ucode.mram_dram_addr = mail & 0xffff; break; - case 3: m_next_ucode.iram_mram_addr = mail; break; - case 4: m_next_ucode.iram_size = mail & 0xffff; break; - case 5: m_next_ucode.iram_dest = mail & 0xffff; break; - case 6: m_next_ucode.iram_startpc = mail & 0xffff; break; - case 7: m_next_ucode.dram_mram_addr = mail; break; - case 8: m_next_ucode.dram_size = mail & 0xffff; break; - case 9: m_next_ucode.dram_dest = mail & 0xffff; break; - } - m_next_ucode_steps++; + switch (m_next_ucode_steps) + { + case 0: + m_next_ucode.mram_dest_addr = mail; + break; + case 1: + m_next_ucode.mram_size = mail & 0xffff; + break; + case 2: + m_next_ucode.mram_dram_addr = mail & 0xffff; + break; + case 3: + m_next_ucode.iram_mram_addr = mail; + break; + case 4: + m_next_ucode.iram_size = mail & 0xffff; + break; + case 5: + m_next_ucode.iram_dest = mail & 0xffff; + break; + case 6: + m_next_ucode.iram_startpc = mail & 0xffff; + break; + case 7: + m_next_ucode.dram_mram_addr = mail; + break; + case 8: + m_next_ucode.dram_size = mail & 0xffff; + break; + case 9: + m_next_ucode.dram_dest = mail & 0xffff; + break; + } + m_next_ucode_steps++; - if (m_next_ucode_steps == 10) - { - m_next_ucode_steps = 0; - m_needs_resume_mail = true; - m_upload_setup_in_progress = false; + if (m_next_ucode_steps == 10) + { + m_next_ucode_steps = 0; + m_needs_resume_mail = true; + m_upload_setup_in_progress = false; - u32 ector_crc = HashEctor( - (u8*)HLEMemory_Get_Pointer(m_next_ucode.iram_mram_addr), - m_next_ucode.iram_size); + u32 ector_crc = + HashEctor((u8*)HLEMemory_Get_Pointer(m_next_ucode.iram_mram_addr), m_next_ucode.iram_size); - if (SConfig::GetInstance().m_DumpUCode) - { - std::string ucode_dump_path = StringFromFormat( - "%sDSP_UC_%08X.bin", File::GetUserPath(D_DUMPDSP_IDX).c_str(), ector_crc); + if (SConfig::GetInstance().m_DumpUCode) + { + std::string ucode_dump_path = StringFromFormat( + "%sDSP_UC_%08X.bin", File::GetUserPath(D_DUMPDSP_IDX).c_str(), ector_crc); - File::IOFile fp(ucode_dump_path, "wb"); - if (fp) - { - fp.WriteArray((u8*)Memory::GetPointer(m_next_ucode.iram_mram_addr), - m_next_ucode.iram_size); - } - } + File::IOFile fp(ucode_dump_path, "wb"); + if (fp) + { + fp.WriteArray((u8*)Memory::GetPointer(m_next_ucode.iram_mram_addr), m_next_ucode.iram_size); + } + } - DEBUG_LOG(DSPHLE, "PrepareBootUCode 0x%08x", ector_crc); - DEBUG_LOG(DSPHLE, "DRAM -> MRAM: src %04x dst %08x size %04x", - m_next_ucode.mram_dram_addr, m_next_ucode.mram_dest_addr, - m_next_ucode.mram_size); - DEBUG_LOG(DSPHLE, "MRAM -> IRAM: src %08x dst %04x size %04x startpc %04x", - m_next_ucode.iram_mram_addr, m_next_ucode.iram_dest, - m_next_ucode.iram_size, m_next_ucode.iram_startpc); - DEBUG_LOG(DSPHLE, "MRAM -> DRAM: src %08x dst %04x size %04x", - m_next_ucode.dram_mram_addr, m_next_ucode.dram_dest, - m_next_ucode.dram_size); + DEBUG_LOG(DSPHLE, "PrepareBootUCode 0x%08x", ector_crc); + DEBUG_LOG(DSPHLE, "DRAM -> MRAM: src %04x dst %08x size %04x", m_next_ucode.mram_dram_addr, + m_next_ucode.mram_dest_addr, m_next_ucode.mram_size); + DEBUG_LOG(DSPHLE, "MRAM -> IRAM: src %08x dst %04x size %04x startpc %04x", + m_next_ucode.iram_mram_addr, m_next_ucode.iram_dest, m_next_ucode.iram_size, + m_next_ucode.iram_startpc); + DEBUG_LOG(DSPHLE, "MRAM -> DRAM: src %08x dst %04x size %04x", m_next_ucode.dram_mram_addr, + m_next_ucode.dram_dest, m_next_ucode.dram_size); - if (m_next_ucode.mram_size) - { - WARN_LOG(DSPHLE, - "Trying to boot new ucode with DRAM download - not implemented"); - } - if (m_next_ucode.dram_size) - { - WARN_LOG(DSPHLE, - "Trying to boot new ucode with DRAM upload - not implemented"); - } + if (m_next_ucode.mram_size) + { + WARN_LOG(DSPHLE, "Trying to boot new ucode with DRAM download - not implemented"); + } + if (m_next_ucode.dram_size) + { + WARN_LOG(DSPHLE, "Trying to boot new ucode with DRAM upload - not implemented"); + } - m_dsphle->SwapUCode(ector_crc); - } + m_dsphle->SwapUCode(ector_crc); + } } -void UCodeInterface::DoStateShared(PointerWrap &p) +void UCodeInterface::DoStateShared(PointerWrap& p) { - p.Do(m_upload_setup_in_progress); - p.Do(m_next_ucode); - p.Do(m_next_ucode_steps); - p.Do(m_needs_resume_mail); + p.Do(m_upload_setup_in_progress); + p.Do(m_next_ucode); + p.Do(m_next_ucode_steps); + p.Do(m_needs_resume_mail); } diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.h b/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.h index 527ed767b2..0cec95498c 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.h @@ -7,143 +7,128 @@ #include #include "Common/CommonTypes.h" -#include "Core/HW/Memmap.h" #include "Core/HW/DSPHLE/DSPHLE.h" +#include "Core/HW/Memmap.h" -#define UCODE_ROM 0x00000000 -#define UCODE_INIT_AUDIO_SYSTEM 0x00000001 -#define UCODE_NULL 0xFFFFFFFF +#define UCODE_ROM 0x00000000 +#define UCODE_INIT_AUDIO_SYSTEM 0x00000001 +#define UCODE_NULL 0xFFFFFFFF class CMailHandler; class PointerWrap; constexpr bool ExramRead(u32 address) { - return (address & 0x10000000) != 0; + return (address & 0x10000000) != 0; } inline u8 HLEMemory_Read_U8(u32 address) { - if (ExramRead(address)) - return Memory::m_pEXRAM[address & Memory::EXRAM_MASK]; - else - return Memory::m_pRAM[address & Memory::RAM_MASK]; + if (ExramRead(address)) + return Memory::m_pEXRAM[address & Memory::EXRAM_MASK]; + else + return Memory::m_pRAM[address & Memory::RAM_MASK]; } inline u16 HLEMemory_Read_U16(u32 address) { - u16 value; + u16 value; - if (ExramRead(address)) - std::memcpy(&value, &Memory::m_pEXRAM[address & Memory::EXRAM_MASK], sizeof(u16)); - else - std::memcpy(&value, &Memory::m_pRAM[address & Memory::RAM_MASK], sizeof(u16)); + if (ExramRead(address)) + std::memcpy(&value, &Memory::m_pEXRAM[address & Memory::EXRAM_MASK], sizeof(u16)); + else + std::memcpy(&value, &Memory::m_pRAM[address & Memory::RAM_MASK], sizeof(u16)); - return Common::swap16(value); + return Common::swap16(value); } inline u32 HLEMemory_Read_U32(u32 address) { - u32 value; + u32 value; - if (ExramRead(address)) - std::memcpy(&value, &Memory::m_pEXRAM[address & Memory::EXRAM_MASK], sizeof(u32)); - else - std::memcpy(&value, &Memory::m_pRAM[address & Memory::RAM_MASK], sizeof(u32)); + if (ExramRead(address)) + std::memcpy(&value, &Memory::m_pEXRAM[address & Memory::EXRAM_MASK], sizeof(u32)); + else + std::memcpy(&value, &Memory::m_pRAM[address & Memory::RAM_MASK], sizeof(u32)); - return Common::swap32(value); + return Common::swap32(value); } inline void* HLEMemory_Get_Pointer(u32 address) { - if (ExramRead(address)) - return &Memory::m_pEXRAM[address & Memory::EXRAM_MASK]; - else - return &Memory::m_pRAM[address & Memory::RAM_MASK]; + if (ExramRead(address)) + return &Memory::m_pEXRAM[address & Memory::EXRAM_MASK]; + else + return &Memory::m_pRAM[address & Memory::RAM_MASK]; } class UCodeInterface { public: - UCodeInterface(DSPHLE *dsphle, u32 crc) - : m_mail_handler(dsphle->AccessMailHandler()) - , m_upload_setup_in_progress(false) - , m_dsphle(dsphle) - , m_crc(crc) - , m_next_ucode() - , m_next_ucode_steps(0) - , m_needs_resume_mail(false) - { - } + UCodeInterface(DSPHLE* dsphle, u32 crc) + : m_mail_handler(dsphle->AccessMailHandler()), m_upload_setup_in_progress(false), + m_dsphle(dsphle), m_crc(crc), m_next_ucode(), m_next_ucode_steps(0), + m_needs_resume_mail(false) + { + } - virtual ~UCodeInterface() - { - } - - virtual void HandleMail(u32 mail) = 0; - virtual void Update() = 0; - - virtual void DoState(PointerWrap &p) - { - DoStateShared(p); - } - - static u32 GetCRC(UCodeInterface* ucode) - { - return ucode ? ucode->m_crc : UCODE_NULL; - } + virtual ~UCodeInterface() {} + virtual void HandleMail(u32 mail) = 0; + virtual void Update() = 0; + virtual void DoState(PointerWrap& p) { DoStateShared(p); } + static u32 GetCRC(UCodeInterface* ucode) { return ucode ? ucode->m_crc : UCODE_NULL; } protected: - void PrepareBootUCode(u32 mail); + void PrepareBootUCode(u32 mail); - // Some ucodes (notably zelda) require a resume mail to be - // sent if they are be started via PrepareBootUCode. - // The HLE can use this to - bool NeedsResumeMail(); + // Some ucodes (notably zelda) require a resume mail to be + // sent if they are be started via PrepareBootUCode. + // The HLE can use this to + bool NeedsResumeMail(); - void DoStateShared(PointerWrap &p); + void DoStateShared(PointerWrap& p); - CMailHandler& m_mail_handler; + CMailHandler& m_mail_handler; - enum EDSP_Codes - { - DSP_INIT = 0xDCD10000, - DSP_RESUME = 0xDCD10001, - DSP_YIELD = 0xDCD10002, - DSP_DONE = 0xDCD10003, - DSP_SYNC = 0xDCD10004, - DSP_FRAME_END = 0xDCD10005, - }; + enum EDSP_Codes + { + DSP_INIT = 0xDCD10000, + DSP_RESUME = 0xDCD10001, + DSP_YIELD = 0xDCD10002, + DSP_DONE = 0xDCD10003, + DSP_SYNC = 0xDCD10004, + DSP_FRAME_END = 0xDCD10005, + }; - // UCode is forwarding mails to PrepareBootUCode - // UCode only needs to set this to true, UCodeInterface will set to false when done! - bool m_upload_setup_in_progress; + // UCode is forwarding mails to PrepareBootUCode + // UCode only needs to set this to true, UCodeInterface will set to false when done! + bool m_upload_setup_in_progress; - // Need a pointer back to DSPHLE to switch ucodes. - DSPHLE *m_dsphle; + // Need a pointer back to DSPHLE to switch ucodes. + DSPHLE* m_dsphle; - // used for reconstruction when loading saves, - // and for variations within certain ucodes. - u32 m_crc; + // used for reconstruction when loading saves, + // and for variations within certain ucodes. + u32 m_crc; private: - struct NextUCodeInfo - { - u32 mram_dest_addr; - u16 mram_size; - u16 mram_dram_addr; - u32 iram_mram_addr; - u16 iram_size; - u16 iram_dest; - u16 iram_startpc; - u32 dram_mram_addr; - u16 dram_size; - u16 dram_dest; - }; - NextUCodeInfo m_next_ucode; - int m_next_ucode_steps; + struct NextUCodeInfo + { + u32 mram_dest_addr; + u16 mram_size; + u16 mram_dram_addr; + u32 iram_mram_addr; + u16 iram_size; + u16 iram_dest; + u16 iram_startpc; + u32 dram_mram_addr; + u16 dram_size; + u16 dram_dest; + }; + NextUCodeInfo m_next_ucode; + int m_next_ucode_steps; - bool m_needs_resume_mail; + bool m_needs_resume_mail; }; -UCodeInterface* UCodeFactory(u32 crc, DSPHLE *dsphle, bool wii); +UCodeInterface* UCodeFactory(u32 crc, DSPHLE* dsphle, bool wii); diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp index 0d601efebf..dbc0655ab7 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp @@ -24,1784 +24,1783 @@ // UCode version. enum ZeldaUCodeFlag { - // UCode for Wii where no ARAM is present. Instead of using ARAM, DMAs from - // MRAM are used to transfer sound data. - NO_ARAM = 0x00000001, + // UCode for Wii where no ARAM is present. Instead of using ARAM, DMAs from + // MRAM are used to transfer sound data. + NO_ARAM = 0x00000001, - // Multiply by two the computed Dolby positional volumes. Some UCodes do - // not do that (Zelda TWW for example), others do (Zelda TP, SMG). - MAKE_DOLBY_LOUDER = 0x00000002, + // Multiply by two the computed Dolby positional volumes. Some UCodes do + // not do that (Zelda TWW for example), others do (Zelda TP, SMG). + MAKE_DOLBY_LOUDER = 0x00000002, - // Light version of the UCode: no Dolby mixing, different synchronization - // protocol, etc. - LIGHT_PROTOCOL = 0x00000004, + // Light version of the UCode: no Dolby mixing, different synchronization + // protocol, etc. + LIGHT_PROTOCOL = 0x00000004, - // If set, only consider 4 of the 6 non-Dolby mixing outputs. Early - // versions of the Zelda UCode only had 4. - FOUR_MIXING_DESTS = 0x00000008, + // If set, only consider 4 of the 6 non-Dolby mixing outputs. Early + // versions of the Zelda UCode only had 4. + FOUR_MIXING_DESTS = 0x00000008, - // Handle smaller VPBs that are missing their 0x40-0x80 area. Very early - // versions of the Zelda UCode used 0x80 sized VPBs. - TINY_VPB = 0x00000010, + // Handle smaller VPBs that are missing their 0x40-0x80 area. Very early + // versions of the Zelda UCode used 0x80 sized VPBs. + TINY_VPB = 0x00000010, - // If set, interpret non-Dolby mixing parameters as step/current volume - // instead of target/current volume. - VOLUME_EXPLICIT_STEP = 0x00000020, + // If set, interpret non-Dolby mixing parameters as step/current volume + // instead of target/current volume. + VOLUME_EXPLICIT_STEP = 0x00000020, - // If set, handle synchronization per-frame instead of per-16-voices. - SYNC_PER_FRAME = 0x00000040, + // If set, handle synchronization per-frame instead of per-16-voices. + SYNC_PER_FRAME = 0x00000040, - // If set, does not support command 0D. TODO: rename. - NO_CMD_0D = 0x00000080, + // If set, does not support command 0D. TODO: rename. + NO_CMD_0D = 0x00000080, - // If set, command 0C is used for GBA crypto. This was used before the GBA - // UCode and UCode switching was available. - SUPPORTS_GBA_CRYPTO = 0x00000100, + // If set, command 0C is used for GBA crypto. This was used before the GBA + // UCode and UCode switching was available. + SUPPORTS_GBA_CRYPTO = 0x00000100, - // If set, command 0C is used for an unknown purpose. TODO: rename. - WEIRD_CMD_0C = 0x00000200, + // If set, command 0C is used for an unknown purpose. TODO: rename. + WEIRD_CMD_0C = 0x00000200, - // If set, command 0D (unknown purpose) is combined with the render command, - // which as such takes two more command arguments. TODO: rename. - COMBINED_CMD_0D = 0x00000400, + // If set, command 0D (unknown purpose) is combined with the render command, + // which as such takes two more command arguments. TODO: rename. + COMBINED_CMD_0D = 0x00000400, }; static const std::map UCODE_FLAGS = { - // GameCube IPL/BIOS, NTSC. - { 0x24B22038, LIGHT_PROTOCOL | FOUR_MIXING_DESTS | TINY_VPB | - VOLUME_EXPLICIT_STEP | NO_CMD_0D | WEIRD_CMD_0C }, - // GameCube IPL/BIOS, PAL. - { 0x6BA3B3EA, LIGHT_PROTOCOL | FOUR_MIXING_DESTS | NO_CMD_0D | - WEIRD_CMD_0C }, - // Pikmin 1 GC NTSC. - // Animal Crossing. - { 0x4BE6A5CB, LIGHT_PROTOCOL | NO_CMD_0D | SUPPORTS_GBA_CRYPTO }, - // Luigi's Mansion. - { 0x42F64AC4, LIGHT_PROTOCOL | NO_CMD_0D | WEIRD_CMD_0C }, - // Pikmin 1 GC PAL. - { 0x267FD05A, SYNC_PER_FRAME | NO_CMD_0D }, - // Super Mario Sunshine. - { 0x56D36052, SYNC_PER_FRAME | NO_CMD_0D }, - // The Legend of Zelda: The Wind Waker. - { 0x86840740, 0 }, - // The Legend of Zelda: Four Swords Adventures. - // Mario Kart: Double Dash. - // Pikmin 2 GC NTSC. - { 0x2FCDF1EC, MAKE_DOLBY_LOUDER }, - // The Legend of Zelda: Twilight Princess / GC. - // Donkey Kong Jungle Beat. - // - // TODO: These do additional filtering at frame rendering time. We don't - // implement this yet. - { 0x6CA33A6D, MAKE_DOLBY_LOUDER }, - // The Legend of Zelda: Twilight Princess / Wii. - { 0x6C3F6F94, NO_ARAM | MAKE_DOLBY_LOUDER }, - // Super Mario Galaxy. - // Super Mario Galaxy 2. - { 0xD643001F, NO_ARAM | MAKE_DOLBY_LOUDER }, - // Pikmin 1 New Play Control. - { 0xB7EB9A9C, NO_ARAM | MAKE_DOLBY_LOUDER | COMBINED_CMD_0D }, - // Pikmin 2 New Play Control. - { 0xEAEB38CC, NO_ARAM | MAKE_DOLBY_LOUDER }, + // GameCube IPL/BIOS, NTSC. + {0x24B22038, LIGHT_PROTOCOL | FOUR_MIXING_DESTS | TINY_VPB | VOLUME_EXPLICIT_STEP | NO_CMD_0D | + WEIRD_CMD_0C}, + // GameCube IPL/BIOS, PAL. + {0x6BA3B3EA, LIGHT_PROTOCOL | FOUR_MIXING_DESTS | NO_CMD_0D | WEIRD_CMD_0C}, + // Pikmin 1 GC NTSC. + // Animal Crossing. + {0x4BE6A5CB, LIGHT_PROTOCOL | NO_CMD_0D | SUPPORTS_GBA_CRYPTO}, + // Luigi's Mansion. + {0x42F64AC4, LIGHT_PROTOCOL | NO_CMD_0D | WEIRD_CMD_0C}, + // Pikmin 1 GC PAL. + {0x267FD05A, SYNC_PER_FRAME | NO_CMD_0D}, + // Super Mario Sunshine. + {0x56D36052, SYNC_PER_FRAME | NO_CMD_0D}, + // The Legend of Zelda: The Wind Waker. + {0x86840740, 0}, + // The Legend of Zelda: Four Swords Adventures. + // Mario Kart: Double Dash. + // Pikmin 2 GC NTSC. + {0x2FCDF1EC, MAKE_DOLBY_LOUDER}, + // The Legend of Zelda: Twilight Princess / GC. + // Donkey Kong Jungle Beat. + // + // TODO: These do additional filtering at frame rendering time. We don't + // implement this yet. + {0x6CA33A6D, MAKE_DOLBY_LOUDER}, + // The Legend of Zelda: Twilight Princess / Wii. + {0x6C3F6F94, NO_ARAM | MAKE_DOLBY_LOUDER}, + // Super Mario Galaxy. + // Super Mario Galaxy 2. + {0xD643001F, NO_ARAM | MAKE_DOLBY_LOUDER}, + // Pikmin 1 New Play Control. + {0xB7EB9A9C, NO_ARAM | MAKE_DOLBY_LOUDER | COMBINED_CMD_0D}, + // Pikmin 2 New Play Control. + {0xEAEB38CC, NO_ARAM | MAKE_DOLBY_LOUDER}, - // TODO: Other games that use this UCode (exhaustive list): - // * Link's Crossbow Training - // * The Legend of Zelda: Collector's Edition - // * The Legend of Zelda: Twilight Princess / Wii (type ????, CRC ????) + // TODO: Other games that use this UCode (exhaustive list): + // * Link's Crossbow Training + // * The Legend of Zelda: Collector's Edition + // * The Legend of Zelda: Twilight Princess / Wii (type ????, CRC ????) }; -ZeldaUCode::ZeldaUCode(DSPHLE *dsphle, u32 crc) - : UCodeInterface(dsphle, crc) +ZeldaUCode::ZeldaUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc) { - auto it = UCODE_FLAGS.find(crc); - if (it == UCODE_FLAGS.end()) - PanicAlert("No flags definition found for Zelda CRC %08x", crc); + auto it = UCODE_FLAGS.find(crc); + if (it == UCODE_FLAGS.end()) + PanicAlert("No flags definition found for Zelda CRC %08x", crc); - m_flags = it->second; - m_renderer.SetFlags(m_flags); + m_flags = it->second; + m_renderer.SetFlags(m_flags); - WARN_LOG(DSPHLE, "Zelda UCode loaded, crc=%08x, flags=%08x", crc, m_flags); + WARN_LOG(DSPHLE, "Zelda UCode loaded, crc=%08x, flags=%08x", crc, m_flags); - if (m_flags & LIGHT_PROTOCOL) - { - m_mail_handler.PushMail(0x88881111); - } - else - { - m_mail_handler.PushMail(DSP_INIT, true); - m_mail_handler.PushMail(0xF3551111); // handshake - } + if (m_flags & LIGHT_PROTOCOL) + { + m_mail_handler.PushMail(0x88881111); + } + else + { + m_mail_handler.PushMail(DSP_INIT, true); + m_mail_handler.PushMail(0xF3551111); // handshake + } } ZeldaUCode::~ZeldaUCode() { - m_mail_handler.Clear(); + m_mail_handler.Clear(); } void ZeldaUCode::Update() { - if (NeedsResumeMail()) - { - m_mail_handler.PushMail(DSP_RESUME, true); - } + if (NeedsResumeMail()) + { + m_mail_handler.PushMail(DSP_RESUME, true); + } } -void ZeldaUCode::DoState(PointerWrap &p) +void ZeldaUCode::DoState(PointerWrap& p) { - p.Do(m_flags); - p.Do(m_mail_current_state); - p.Do(m_mail_expected_cmd_mails); + p.Do(m_flags); + p.Do(m_mail_current_state); + p.Do(m_mail_expected_cmd_mails); - p.Do(m_sync_max_voice_id); - p.Do(m_sync_voice_skip_flags); - p.Do(m_sync_flags_second_half); + p.Do(m_sync_max_voice_id); + p.Do(m_sync_voice_skip_flags); + p.Do(m_sync_flags_second_half); - p.Do(m_cmd_buffer); - p.Do(m_read_offset); - p.Do(m_write_offset); - p.Do(m_pending_commands_count); - p.Do(m_cmd_can_execute); + p.Do(m_cmd_buffer); + p.Do(m_read_offset); + p.Do(m_write_offset); + p.Do(m_pending_commands_count); + p.Do(m_cmd_can_execute); - p.Do(m_rendering_requested_frames); - p.Do(m_rendering_voices_per_frame); - p.Do(m_rendering_curr_frame); - p.Do(m_rendering_curr_voice); + p.Do(m_rendering_requested_frames); + p.Do(m_rendering_voices_per_frame); + p.Do(m_rendering_curr_frame); + p.Do(m_rendering_curr_voice); - m_renderer.DoState(p); + m_renderer.DoState(p); - DoStateShared(p); + DoStateShared(p); } void ZeldaUCode::HandleMail(u32 mail) { - if (m_upload_setup_in_progress) // evaluated first! - { - PrepareBootUCode(mail); - return; - } + if (m_upload_setup_in_progress) // evaluated first! + { + PrepareBootUCode(mail); + return; + } - if (m_flags & LIGHT_PROTOCOL) - HandleMailLight(mail); - else - HandleMailDefault(mail); + if (m_flags & LIGHT_PROTOCOL) + HandleMailLight(mail); + else + HandleMailDefault(mail); } void ZeldaUCode::HandleMailDefault(u32 mail) { - switch (m_mail_current_state) - { - case MailState::WAITING: - if (mail & 0x80000000) - { - if ((mail >> 16) != 0xCDD1) - { - PanicAlert("Rendering end mail without prefix CDD1: %08x", - mail); - } + switch (m_mail_current_state) + { + case MailState::WAITING: + if (mail & 0x80000000) + { + if ((mail >> 16) != 0xCDD1) + { + PanicAlert("Rendering end mail without prefix CDD1: %08x", mail); + } - switch (mail & 0xFFFF) - { - case 1: - NOTICE_LOG(DSPHLE, "UCode being replaced."); - m_upload_setup_in_progress = true; - SetMailState(MailState::HALTED); - break; + switch (mail & 0xFFFF) + { + case 1: + NOTICE_LOG(DSPHLE, "UCode being replaced."); + m_upload_setup_in_progress = true; + SetMailState(MailState::HALTED); + break; - case 2: - NOTICE_LOG(DSPHLE, "UCode being rebooted to ROM."); - SetMailState(MailState::HALTED); - m_dsphle->SetUCode(UCODE_ROM); - break; + case 2: + NOTICE_LOG(DSPHLE, "UCode being rebooted to ROM."); + SetMailState(MailState::HALTED); + m_dsphle->SetUCode(UCODE_ROM); + break; - case 3: - m_cmd_can_execute = true; - RunPendingCommands(); - break; + case 3: + m_cmd_can_execute = true; + RunPendingCommands(); + break; - default: - NOTICE_LOG(DSPHLE, "Unknown end rendering action. Halting."); - case 0: - NOTICE_LOG(DSPHLE, "UCode asked to halt. Stopping any processing."); - SetMailState(MailState::HALTED); - break; - } - } - else if (!(mail & 0xFFFF)) - { - if (RenderingInProgress()) - { - SetMailState(MailState::RENDERING); - } - else - { - NOTICE_LOG(DSPHLE, "Sync mail (%08x) received when rendering was not active. Halting.", - mail); - SetMailState(MailState::HALTED); - } - } - else - { - SetMailState(MailState::WRITING_CMD); - m_mail_expected_cmd_mails = mail & 0xFFFF; - } - break; + default: + NOTICE_LOG(DSPHLE, "Unknown end rendering action. Halting."); + case 0: + NOTICE_LOG(DSPHLE, "UCode asked to halt. Stopping any processing."); + SetMailState(MailState::HALTED); + break; + } + } + else if (!(mail & 0xFFFF)) + { + if (RenderingInProgress()) + { + SetMailState(MailState::RENDERING); + } + else + { + NOTICE_LOG(DSPHLE, "Sync mail (%08x) received when rendering was not active. Halting.", + mail); + SetMailState(MailState::HALTED); + } + } + else + { + SetMailState(MailState::WRITING_CMD); + m_mail_expected_cmd_mails = mail & 0xFFFF; + } + break; - case MailState::RENDERING: - if (m_flags & SYNC_PER_FRAME) - { - int base = m_sync_flags_second_half ? 2 : 0; - m_sync_voice_skip_flags[base] = mail >> 16; - m_sync_voice_skip_flags[base + 1] = mail & 0xFFFF; + case MailState::RENDERING: + if (m_flags & SYNC_PER_FRAME) + { + int base = m_sync_flags_second_half ? 2 : 0; + m_sync_voice_skip_flags[base] = mail >> 16; + m_sync_voice_skip_flags[base + 1] = mail & 0xFFFF; - if (m_sync_flags_second_half) - m_sync_max_voice_id = 0xFFFF; + if (m_sync_flags_second_half) + m_sync_max_voice_id = 0xFFFF; - RenderAudio(); - if (m_sync_flags_second_half) - SetMailState(MailState::WAITING); - m_sync_flags_second_half = !m_sync_flags_second_half; - } - else - { - m_sync_max_voice_id = (((mail >> 16) & 0xF) + 1) << 4; - m_sync_voice_skip_flags[(mail >> 16) & 0xFF] = mail & 0xFFFF; - RenderAudio(); - SetMailState(MailState::WAITING); - } - break; + RenderAudio(); + if (m_sync_flags_second_half) + SetMailState(MailState::WAITING); + m_sync_flags_second_half = !m_sync_flags_second_half; + } + else + { + m_sync_max_voice_id = (((mail >> 16) & 0xF) + 1) << 4; + m_sync_voice_skip_flags[(mail >> 16) & 0xFF] = mail & 0xFFFF; + RenderAudio(); + SetMailState(MailState::WAITING); + } + break; - case MailState::WRITING_CMD: - Write32(mail); + case MailState::WRITING_CMD: + Write32(mail); - if (--m_mail_expected_cmd_mails == 0) - { - m_pending_commands_count += 1; - SetMailState(MailState::WAITING); - RunPendingCommands(); - } - break; + if (--m_mail_expected_cmd_mails == 0) + { + m_pending_commands_count += 1; + SetMailState(MailState::WAITING); + RunPendingCommands(); + } + break; - case MailState::HALTED: - WARN_LOG(DSPHLE, "Received mail %08x while we're halted.", mail); - break; - } + case MailState::HALTED: + WARN_LOG(DSPHLE, "Received mail %08x while we're halted.", mail); + break; + } } void ZeldaUCode::HandleMailLight(u32 mail) { - bool add_command = true; + bool add_command = true; - switch (m_mail_current_state) - { - case MailState::WAITING: - if (!(mail & 0x80000000)) - PanicAlert("Mail received in waiting state has MSB=0: %08x", mail); + switch (m_mail_current_state) + { + case MailState::WAITING: + if (!(mail & 0x80000000)) + PanicAlert("Mail received in waiting state has MSB=0: %08x", mail); - // Start of a command. We have to hardcode the number of mails required - // for each command - the alternative is to rewrite command handling as - // an asynchronous procedure, and we wouldn't want that, would we? - Write32(mail); + // Start of a command. We have to hardcode the number of mails required + // for each command - the alternative is to rewrite command handling as + // an asynchronous procedure, and we wouldn't want that, would we? + Write32(mail); - switch ((mail >> 24) & 0x7F) - { - case 0x00: m_mail_expected_cmd_mails = 0; break; - case 0x01: m_mail_expected_cmd_mails = 4; break; - case 0x02: m_mail_expected_cmd_mails = 2; break; - // Doesn't even register as a command, just rejumps to the dispatcher. - // TODO: That's true on 0x4BE6A5CB and 0x42F64AC4, what about others? - case 0x03: add_command = false; break; - case 0x0C: - if (m_flags & SUPPORTS_GBA_CRYPTO) - m_mail_expected_cmd_mails = 1; - else if (m_flags & WEIRD_CMD_0C) - m_mail_expected_cmd_mails = 2; - else - m_mail_expected_cmd_mails = 0; - break; + switch ((mail >> 24) & 0x7F) + { + case 0x00: + m_mail_expected_cmd_mails = 0; + break; + case 0x01: + m_mail_expected_cmd_mails = 4; + break; + case 0x02: + m_mail_expected_cmd_mails = 2; + break; + // Doesn't even register as a command, just rejumps to the dispatcher. + // TODO: That's true on 0x4BE6A5CB and 0x42F64AC4, what about others? + case 0x03: + add_command = false; + break; + case 0x0C: + if (m_flags & SUPPORTS_GBA_CRYPTO) + m_mail_expected_cmd_mails = 1; + else if (m_flags & WEIRD_CMD_0C) + m_mail_expected_cmd_mails = 2; + else + m_mail_expected_cmd_mails = 0; + break; - default: - PanicAlert("Received unknown command in light protocol: %08x", mail); - break; - } - if (m_mail_expected_cmd_mails) - { - SetMailState(MailState::WRITING_CMD); - } - else if (add_command) - { - m_pending_commands_count += 1; - RunPendingCommands(); - } - break; + default: + PanicAlert("Received unknown command in light protocol: %08x", mail); + break; + } + if (m_mail_expected_cmd_mails) + { + SetMailState(MailState::WRITING_CMD); + } + else if (add_command) + { + m_pending_commands_count += 1; + RunPendingCommands(); + } + break; - case MailState::WRITING_CMD: - Write32(mail); - if (--m_mail_expected_cmd_mails == 0) - { - m_pending_commands_count += 1; - SetMailState(MailState::WAITING); - RunPendingCommands(); - } - break; + case MailState::WRITING_CMD: + Write32(mail); + if (--m_mail_expected_cmd_mails == 0) + { + m_pending_commands_count += 1; + SetMailState(MailState::WAITING); + RunPendingCommands(); + } + break; - case MailState::RENDERING: - if (mail != 0) - PanicAlert("Sync mail is not zero: %08x", mail); + case MailState::RENDERING: + if (mail != 0) + PanicAlert("Sync mail is not zero: %08x", mail); - // No per-voice syncing in the light protocol. - m_sync_max_voice_id = 0xFFFFFFFF; - m_sync_voice_skip_flags.fill(0xFFFF); - RenderAudio(); - DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); - break; + // No per-voice syncing in the light protocol. + m_sync_max_voice_id = 0xFFFFFFFF; + m_sync_voice_skip_flags.fill(0xFFFF); + RenderAudio(); + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + break; - case MailState::HALTED: - WARN_LOG(DSPHLE, "Received mail %08x while we're halted.", mail); - break; - } + case MailState::HALTED: + WARN_LOG(DSPHLE, "Received mail %08x while we're halted.", mail); + break; + } } void ZeldaUCode::RunPendingCommands() { - if (RenderingInProgress() || !m_cmd_can_execute) - { - // No commands can be ran while audio rendering is in progress or - // waiting for an ACK. - return; - } + if (RenderingInProgress() || !m_cmd_can_execute) + { + // No commands can be ran while audio rendering is in progress or + // waiting for an ACK. + return; + } - while (m_pending_commands_count) - { - u32 cmd_mail = Read32(); - if (!(cmd_mail & 0x80000000)) - continue; + while (m_pending_commands_count) + { + u32 cmd_mail = Read32(); + if (!(cmd_mail & 0x80000000)) + continue; - u32 command = (cmd_mail >> 24) & 0x7f; - u32 sync = cmd_mail >> 16; - u32 extra_data = cmd_mail & 0xFFFF; + u32 command = (cmd_mail >> 24) & 0x7f; + u32 sync = cmd_mail >> 16; + u32 extra_data = cmd_mail & 0xFFFF; - m_pending_commands_count--; + m_pending_commands_count--; - switch (command) - { - case 0x00: - case 0x0A: - case 0x0B: - case 0x0F: - // NOP commands. Log anyway in case we encounter a new version - // where these are not NOPs anymore. - NOTICE_LOG(DSPHLE, "Received a NOP command: %d", command); - SendCommandAck(CommandAck::STANDARD, sync); - break; + switch (command) + { + case 0x00: + case 0x0A: + case 0x0B: + case 0x0F: + // NOP commands. Log anyway in case we encounter a new version + // where these are not NOPs anymore. + NOTICE_LOG(DSPHLE, "Received a NOP command: %d", command); + SendCommandAck(CommandAck::STANDARD, sync); + break; - case 0x03: - // NOP on standard protocol but shouldn't ever happen on light protocol - // since it's going directly back to the dispatcher with no ack. - if (m_flags & LIGHT_PROTOCOL) - { - PanicAlert("Received a 03 command on light protocol."); - break; - } - SendCommandAck(CommandAck::STANDARD, sync); - break; + case 0x03: + // NOP on standard protocol but shouldn't ever happen on light protocol + // since it's going directly back to the dispatcher with no ack. + if (m_flags & LIGHT_PROTOCOL) + { + PanicAlert("Received a 03 command on light protocol."); + break; + } + SendCommandAck(CommandAck::STANDARD, sync); + break; - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - // Commands that crash the DAC UCode on non-light protocols. Log and - // enter HALTED mode. - // - // TODO: These are not crashes on light protocol, however I've never seen - // them used so far. - NOTICE_LOG(DSPHLE, "Received a crashy command: %d", command); - SetMailState(MailState::HALTED); - return; + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + // Commands that crash the DAC UCode on non-light protocols. Log and + // enter HALTED mode. + // + // TODO: These are not crashes on light protocol, however I've never seen + // them used so far. + NOTICE_LOG(DSPHLE, "Received a crashy command: %d", command); + SetMailState(MailState::HALTED); + return; - // Command 01: Setup/initialization command. Provides the address to - // voice parameter blocks (VPBs) as well as some array of coefficients - // used for mixing. - case 0x01: - { - m_rendering_voices_per_frame = extra_data; + // Command 01: Setup/initialization command. Provides the address to + // voice parameter blocks (VPBs) as well as some array of coefficients + // used for mixing. + case 0x01: + { + m_rendering_voices_per_frame = extra_data; - m_renderer.SetVPBBaseAddress(Read32()); + m_renderer.SetVPBBaseAddress(Read32()); - u16* data_ptr = (u16*)HLEMemory_Get_Pointer(Read32()); + u16* data_ptr = (u16*)HLEMemory_Get_Pointer(Read32()); - std::array resampling_coeffs; - for (size_t i = 0; i < 0x100; ++i) - resampling_coeffs[i] = Common::swap16(data_ptr[i]); - m_renderer.SetResamplingCoeffs(std::move(resampling_coeffs)); + std::array resampling_coeffs; + for (size_t i = 0; i < 0x100; ++i) + resampling_coeffs[i] = Common::swap16(data_ptr[i]); + m_renderer.SetResamplingCoeffs(std::move(resampling_coeffs)); - std::array const_patterns; - for (size_t i = 0; i < 0x100; ++i) - const_patterns[i] = Common::swap16(data_ptr[0x100 + i]); - m_renderer.SetConstPatterns(std::move(const_patterns)); + std::array const_patterns; + for (size_t i = 0; i < 0x100; ++i) + const_patterns[i] = Common::swap16(data_ptr[0x100 + i]); + m_renderer.SetConstPatterns(std::move(const_patterns)); - std::array sine_table; - for (size_t i = 0; i < 0x80; ++i) - sine_table[i] = Common::swap16(data_ptr[0x200 + i]); - m_renderer.SetSineTable(std::move(sine_table)); + std::array sine_table; + for (size_t i = 0; i < 0x80; ++i) + sine_table[i] = Common::swap16(data_ptr[0x200 + i]); + m_renderer.SetSineTable(std::move(sine_table)); - u16* afc_coeffs_ptr = (u16*)HLEMemory_Get_Pointer(Read32()); - std::array afc_coeffs; - for (size_t i = 0; i < 0x20; ++i) - afc_coeffs[i] = Common::swap16(afc_coeffs_ptr[i]); - m_renderer.SetAfcCoeffs(std::move(afc_coeffs)); + u16* afc_coeffs_ptr = (u16*)HLEMemory_Get_Pointer(Read32()); + std::array afc_coeffs; + for (size_t i = 0; i < 0x20; ++i) + afc_coeffs[i] = Common::swap16(afc_coeffs_ptr[i]); + m_renderer.SetAfcCoeffs(std::move(afc_coeffs)); - m_renderer.SetReverbPBBaseAddress(Read32()); + m_renderer.SetReverbPBBaseAddress(Read32()); - SendCommandAck(CommandAck::STANDARD, sync); - break; - } + SendCommandAck(CommandAck::STANDARD, sync); + break; + } - // Command 02: starts audio processing. NOTE: this handler uses return, - // not break. This is because it hijacks the mail control flow and - // stops processing of further commands until audio processing is done. - case 0x02: - m_rendering_requested_frames = (cmd_mail >> 16) & 0xFF; - m_renderer.SetOutputVolume(cmd_mail & 0xFFFF); - m_renderer.SetOutputLeftBufferAddr(Read32()); - m_renderer.SetOutputRightBufferAddr(Read32()); + // Command 02: starts audio processing. NOTE: this handler uses return, + // not break. This is because it hijacks the mail control flow and + // stops processing of further commands until audio processing is done. + case 0x02: + m_rendering_requested_frames = (cmd_mail >> 16) & 0xFF; + m_renderer.SetOutputVolume(cmd_mail & 0xFFFF); + m_renderer.SetOutputLeftBufferAddr(Read32()); + m_renderer.SetOutputRightBufferAddr(Read32()); - if (m_flags & COMBINED_CMD_0D) - { - // Ignore the two values which are equivalent to arguments passed to - // command 0D. - Read32(); - Read32(); - } + if (m_flags & COMBINED_CMD_0D) + { + // Ignore the two values which are equivalent to arguments passed to + // command 0D. + Read32(); + Read32(); + } - m_rendering_curr_frame = 0; - m_rendering_curr_voice = 0; + m_rendering_curr_frame = 0; + m_rendering_curr_voice = 0; - if (m_flags & LIGHT_PROTOCOL) - { - SendCommandAck(CommandAck::STANDARD, m_rendering_requested_frames); - SetMailState(MailState::RENDERING); - } - else - { - RenderAudio(); - } - return; + if (m_flags & LIGHT_PROTOCOL) + { + SendCommandAck(CommandAck::STANDARD, m_rendering_requested_frames); + SetMailState(MailState::RENDERING); + } + else + { + RenderAudio(); + } + return; - // Command 0C: used for multiple purpose depending on the UCode version: - // * IPL NTSC/PAL, Luigi's Mansion: TODO (unknown as of now). - // * Pikmin/AC: GBA crypto. - // * SMS and onwards: NOP. - case 0x0C: - if (m_flags & SUPPORTS_GBA_CRYPTO) - { - ProcessGBACrypto(Read32()); - } - else if (m_flags & WEIRD_CMD_0C) - { - // TODO - NOTICE_LOG(DSPHLE, "Received an unhandled 0C command, params: %08x %08x", Read32(), Read32()); - } - else - { - WARN_LOG(DSPHLE, "Received a NOP 0C command. Flags=%08x", m_flags); - } - SendCommandAck(CommandAck::STANDARD, sync); - break; + // Command 0C: used for multiple purpose depending on the UCode version: + // * IPL NTSC/PAL, Luigi's Mansion: TODO (unknown as of now). + // * Pikmin/AC: GBA crypto. + // * SMS and onwards: NOP. + case 0x0C: + if (m_flags & SUPPORTS_GBA_CRYPTO) + { + ProcessGBACrypto(Read32()); + } + else if (m_flags & WEIRD_CMD_0C) + { + // TODO + NOTICE_LOG(DSPHLE, "Received an unhandled 0C command, params: %08x %08x", Read32(), + Read32()); + } + else + { + WARN_LOG(DSPHLE, "Received a NOP 0C command. Flags=%08x", m_flags); + } + SendCommandAck(CommandAck::STANDARD, sync); + break; - // Command 0D: TODO: find a name and implement. - case 0x0D: - if (m_flags & NO_CMD_0D) - { - WARN_LOG(DSPHLE, "Received a 0D command which is NOP'd on this UCode."); - SendCommandAck(CommandAck::STANDARD, sync); - break; - } + // Command 0D: TODO: find a name and implement. + case 0x0D: + if (m_flags & NO_CMD_0D) + { + WARN_LOG(DSPHLE, "Received a 0D command which is NOP'd on this UCode."); + SendCommandAck(CommandAck::STANDARD, sync); + break; + } - WARN_LOG(DSPHLE, "CMD0D: %08x", Read32()); - SendCommandAck(CommandAck::STANDARD, sync); - break; + WARN_LOG(DSPHLE, "CMD0D: %08x", Read32()); + SendCommandAck(CommandAck::STANDARD, sync); + break; - // Command 0E: Sets the base address of the ARAM for Wii UCodes. Used - // because the Wii does not have an ARAM, so it simulates it with MRAM - // and DMAs. - case 0x0E: - if (!(m_flags & NO_ARAM)) - PanicAlert("Setting base ARAM addr on non Wii DAC."); - m_renderer.SetARAMBaseAddr(Read32()); - SendCommandAck(CommandAck::STANDARD, sync); - break; + // Command 0E: Sets the base address of the ARAM for Wii UCodes. Used + // because the Wii does not have an ARAM, so it simulates it with MRAM + // and DMAs. + case 0x0E: + if (!(m_flags & NO_ARAM)) + PanicAlert("Setting base ARAM addr on non Wii DAC."); + m_renderer.SetARAMBaseAddr(Read32()); + SendCommandAck(CommandAck::STANDARD, sync); + break; - default: - NOTICE_LOG(DSPHLE, "Received a non-existing command (%d), halting.", command); - SetMailState(MailState::HALTED); - return; - } - } + default: + NOTICE_LOG(DSPHLE, "Received a non-existing command (%d), halting.", command); + SetMailState(MailState::HALTED); + return; + } + } } void ZeldaUCode::SendCommandAck(CommandAck ack_type, u16 sync_value) { - if (m_flags & LIGHT_PROTOCOL) - { - // The light protocol uses the address of the command handler in the - // DSP code instead of the command id... go figure. - sync_value = 2 * ((sync_value >> 8) & 0x7F) + 0x62; - m_mail_handler.PushMail(0x80000000 | sync_value); - } - else - { - u32 ack_mail = 0; - switch (ack_type) - { - case CommandAck::STANDARD: ack_mail = DSP_SYNC; break; - case CommandAck::DONE_RENDERING: ack_mail = DSP_FRAME_END; break; - } - m_mail_handler.PushMail(ack_mail, true); + if (m_flags & LIGHT_PROTOCOL) + { + // The light protocol uses the address of the command handler in the + // DSP code instead of the command id... go figure. + sync_value = 2 * ((sync_value >> 8) & 0x7F) + 0x62; + m_mail_handler.PushMail(0x80000000 | sync_value); + } + else + { + u32 ack_mail = 0; + switch (ack_type) + { + case CommandAck::STANDARD: + ack_mail = DSP_SYNC; + break; + case CommandAck::DONE_RENDERING: + ack_mail = DSP_FRAME_END; + break; + } + m_mail_handler.PushMail(ack_mail, true); - if (ack_type == CommandAck::STANDARD) - m_mail_handler.PushMail(0xF3550000 | sync_value); - } + if (ack_type == CommandAck::STANDARD) + m_mail_handler.PushMail(0xF3550000 | sync_value); + } } void ZeldaUCode::RenderAudio() { - if (!RenderingInProgress()) - { - WARN_LOG(DSPHLE, "Trying to render audio while no rendering should be happening."); - return; - } + if (!RenderingInProgress()) + { + WARN_LOG(DSPHLE, "Trying to render audio while no rendering should be happening."); + return; + } - while (m_rendering_curr_frame < m_rendering_requested_frames) - { - if (m_rendering_curr_voice == 0) - m_renderer.PrepareFrame(); + while (m_rendering_curr_frame < m_rendering_requested_frames) + { + if (m_rendering_curr_voice == 0) + m_renderer.PrepareFrame(); - while (m_rendering_curr_voice < m_rendering_voices_per_frame) - { - // If we are not meant to render this voice yet, go back to message - // processing. - if (m_rendering_curr_voice >= m_sync_max_voice_id) - return; + while (m_rendering_curr_voice < m_rendering_voices_per_frame) + { + // If we are not meant to render this voice yet, go back to message + // processing. + if (m_rendering_curr_voice >= m_sync_max_voice_id) + return; - // Test the sync flag for this voice, skip it if not set. - u16 flags = m_sync_voice_skip_flags[m_rendering_curr_voice >> 4]; - u8 bit = 0xF - (m_rendering_curr_voice & 0xF); - if (flags & (1 << bit)) - m_renderer.AddVoice(m_rendering_curr_voice); + // Test the sync flag for this voice, skip it if not set. + u16 flags = m_sync_voice_skip_flags[m_rendering_curr_voice >> 4]; + u8 bit = 0xF - (m_rendering_curr_voice & 0xF); + if (flags & (1 << bit)) + m_renderer.AddVoice(m_rendering_curr_voice); - m_rendering_curr_voice++; - } + m_rendering_curr_voice++; + } - if (!(m_flags & LIGHT_PROTOCOL)) - SendCommandAck(CommandAck::STANDARD, 0xFF00 | m_rendering_curr_frame); + if (!(m_flags & LIGHT_PROTOCOL)) + SendCommandAck(CommandAck::STANDARD, 0xFF00 | m_rendering_curr_frame); - m_renderer.FinalizeFrame(); + m_renderer.FinalizeFrame(); - m_rendering_curr_voice = 0; - m_sync_max_voice_id = 0; - m_rendering_curr_frame++; - } + m_rendering_curr_voice = 0; + m_sync_max_voice_id = 0; + m_rendering_curr_frame++; + } - if (!(m_flags & LIGHT_PROTOCOL)) - { - SendCommandAck(CommandAck::DONE_RENDERING, 0); - m_cmd_can_execute = false; // Block command execution until ACK is received. - } - else - { - SetMailState(MailState::WAITING); - } + if (!(m_flags & LIGHT_PROTOCOL)) + { + SendCommandAck(CommandAck::DONE_RENDERING, 0); + m_cmd_can_execute = false; // Block command execution until ACK is received. + } + else + { + SetMailState(MailState::WAITING); + } } // Utility to define 32 bit accessors/modifiers methods based on two 16 bit // fields named _l and _h. -#define DEFINE_32BIT_ACCESSOR(field_name, name) \ - u32 Get##name() const { return (field_name##_h << 16) | field_name##_l; } \ - void Set##name(u32 v) \ - { \ - field_name##_h = v >> 16; \ - field_name##_l = v & 0xFFFF; \ - } +#define DEFINE_32BIT_ACCESSOR(field_name, name) \ + u32 Get##name() const { return (field_name##_h << 16) | field_name##_l; } \ + void Set##name(u32 v) \ + { \ + field_name##_h = v >> 16; \ + field_name##_l = v & 0xFFFF; \ + } #pragma pack(push, 1) struct ZeldaAudioRenderer::VPB { - // If zero, skip processing this voice. - u16 enabled; + // If zero, skip processing this voice. + u16 enabled; - // If non zero, skip processing this voice. - u16 done; + // If non zero, skip processing this voice. + u16 done; - // In 4.12 format. 1.0 (0x1000) means 0x50 raw samples from RAM/accelerator - // will be "resampled" to 0x50 input samples. 2.0 (0x2000) means 2 raw - // samples for one input samples. 0.5 (0x800) means one raw sample for 2 - // input samples. - u16 resampling_ratio; + // In 4.12 format. 1.0 (0x1000) means 0x50 raw samples from RAM/accelerator + // will be "resampled" to 0x50 input samples. 2.0 (0x2000) means 2 raw + // samples for one input samples. 0.5 (0x800) means one raw sample for 2 + // input samples. + u16 resampling_ratio; - u16 unk_03; + u16 unk_03; - // If non zero, reset some value in the VPB when processing it. - u16 reset_vpb; + // If non zero, reset some value in the VPB when processing it. + u16 reset_vpb; - // If non zero, tells PCM8/PCM16 sample sources that the end of the voice - // has been reached and looping should be considered if enabled. - u16 end_reached; + // If non zero, tells PCM8/PCM16 sample sources that the end of the voice + // has been reached and looping should be considered if enabled. + u16 end_reached; - // If non zero, input samples to this VPB will be the fixed value from - // VPB[33] (constant_sample_value). This is used when a voice is being - // terminated in order to force silence. - u16 use_constant_sample; + // If non zero, input samples to this VPB will be the fixed value from + // VPB[33] (constant_sample_value). This is used when a voice is being + // terminated in order to force silence. + u16 use_constant_sample; - // Number of samples that should be saved in the VPB for processing during - // future frames. Should be at most TODO. - u16 samples_to_keep_count; + // Number of samples that should be saved in the VPB for processing during + // future frames. Should be at most TODO. + u16 samples_to_keep_count; - // Channel mixing information. Each voice can be mixed to 6 different - // channels, with separate volume information. - // - // Used only if VPB[2C] (use_dolby_volume) is not set. Otherwise, the - // values from VPB[0x20:0x2C] are used to mix to all available channels. - struct Channel - { - // Can be treated as an ID, but in the real world this is actually the - // address in DRAM of a DSP buffer. The game passes that information to - // the DSP, which means the game must know the memory layout of the DSP - // UCode... that's terrible. - u16 id; + // Channel mixing information. Each voice can be mixed to 6 different + // channels, with separate volume information. + // + // Used only if VPB[2C] (use_dolby_volume) is not set. Otherwise, the + // values from VPB[0x20:0x2C] are used to mix to all available channels. + struct Channel + { + // Can be treated as an ID, but in the real world this is actually the + // address in DRAM of a DSP buffer. The game passes that information to + // the DSP, which means the game must know the memory layout of the DSP + // UCode... that's terrible. + u16 id; - s16 target_volume; - s16 current_volume; + s16 target_volume; + s16 current_volume; - u16 unk; - }; - Channel channels[6]; + u16 unk; + }; + Channel channels[6]; - u16 unk_20_28[0x8]; + u16 unk_20_28[0x8]; - // When using Dolby voice mixing (see VPB[2C] use_dolby_volume), the X - // (left/right) and Y (front/back) coordinates of the sound. 0x00 is all - // right/back, 0x7F is all left/front. Format is 0XXXXXXX0YYYYYYY. - u16 dolby_voice_position; - u8 GetDolbyVoiceX() const { return (dolby_voice_position >> 8) & 0x7F; } - u8 GetDolbyVoiceY() const { return dolby_voice_position & 0x7F; } + // When using Dolby voice mixing (see VPB[2C] use_dolby_volume), the X + // (left/right) and Y (front/back) coordinates of the sound. 0x00 is all + // right/back, 0x7F is all left/front. Format is 0XXXXXXX0YYYYYYY. + u16 dolby_voice_position; + u8 GetDolbyVoiceX() const { return (dolby_voice_position >> 8) & 0x7F; } + u8 GetDolbyVoiceY() const { return dolby_voice_position & 0x7F; } + // How much reverbation to apply to the Dolby mixed voice. 0 is none, + // 0x7FFF is the maximum value. + s16 dolby_reverb_factor; - // How much reverbation to apply to the Dolby mixed voice. 0 is none, - // 0x7FFF is the maximum value. - s16 dolby_reverb_factor; + // The volume for the 0x50 samples being mixed will ramp between current + // and target. After the ramping is done, the current value is updated (to + // match target, usually). + s16 dolby_volume_current; + s16 dolby_volume_target; - // The volume for the 0x50 samples being mixed will ramp between current - // and target. After the ramping is done, the current value is updated (to - // match target, usually). - s16 dolby_volume_current; - s16 dolby_volume_target; + // If non zero, use positional audio mixing. Instead of using the channels + // information, use the 4 Dolby related VPB fields defined above. + u16 use_dolby_volume; - // If non zero, use positional audio mixing. Instead of using the channels - // information, use the 4 Dolby related VPB fields defined above. - u16 use_dolby_volume; + u16 unk_2D; + u16 unk_2E; + u16 unk_2F; - u16 unk_2D; - u16 unk_2E; - u16 unk_2F; + // Fractional part of the current sample position, in 0.12 format (all + // decimal part, 0x0800 = 0.5). The 4 top bits are unused. + u16 current_pos_frac; - // Fractional part of the current sample position, in 0.12 format (all - // decimal part, 0x0800 = 0.5). The 4 top bits are unused. - u16 current_pos_frac; + u16 unk_31; - u16 unk_31; + // Number of remaining decoded AFC samples in the VPB internal buffer (see + // VPB[0x58]) that haven't been output yet. + u16 afc_remaining_decoded_samples; - // Number of remaining decoded AFC samples in the VPB internal buffer (see - // VPB[0x58]) that haven't been output yet. - u16 afc_remaining_decoded_samples; + // Value used as the constant sample value if VPB[6] (use_constant_sample) + // is set. Reset to the last sample value after each round of resampling. + s16 constant_sample; - // Value used as the constant sample value if VPB[6] (use_constant_sample) - // is set. Reset to the last sample value after each round of resampling. - s16 constant_sample; + // Current position in the voice. Not needed for accelerator based voice + // types since the accelerator exposes a streaming based interface, but DMA + // based voice types (PCM16_FROM_MRAM for example) require it to know where + // to seek in the MRAM buffer. + u16 current_position_h; + u16 current_position_l; + DEFINE_32BIT_ACCESSOR(current_position, CurrentPosition) - // Current position in the voice. Not needed for accelerator based voice - // types since the accelerator exposes a streaming based interface, but DMA - // based voice types (PCM16_FROM_MRAM for example) require it to know where - // to seek in the MRAM buffer. - u16 current_position_h; - u16 current_position_l; - DEFINE_32BIT_ACCESSOR(current_position, CurrentPosition) + // Number of samples that will be processed before the loop point of the + // voice is reached. Maintained by the UCode and used by the game to + // schedule some parameters updates. + u16 samples_before_loop; - // Number of samples that will be processed before the loop point of the - // voice is reached. Maintained by the UCode and used by the game to - // schedule some parameters updates. - u16 samples_before_loop; + u16 unk_37; - u16 unk_37; + // Current address used to stream samples for the ARAM sample source types. + u16 current_aram_addr_h; + u16 current_aram_addr_l; + DEFINE_32BIT_ACCESSOR(current_aram_addr, CurrentARAMAddr) - // Current address used to stream samples for the ARAM sample source types. - u16 current_aram_addr_h; - u16 current_aram_addr_l; - DEFINE_32BIT_ACCESSOR(current_aram_addr, CurrentARAMAddr) + // Remaining number of samples to load before considering the voice + // rendering complete and setting the done flag. Note that this is an + // absolute value that does not take into account loops. If a loop of 100 + // samples is played 4 times, remaining_length will have decreased by 400. + u16 remaining_length_h; + u16 remaining_length_l; + DEFINE_32BIT_ACCESSOR(remaining_length, RemainingLength) - // Remaining number of samples to load before considering the voice - // rendering complete and setting the done flag. Note that this is an - // absolute value that does not take into account loops. If a loop of 100 - // samples is played 4 times, remaining_length will have decreased by 400. - u16 remaining_length_h; - u16 remaining_length_l; - DEFINE_32BIT_ACCESSOR(remaining_length, RemainingLength) + // Stores the last 4 resampled input samples after each frame, so that they + // can be used for future linear interpolation. + s16 resample_buffer[4]; - // Stores the last 4 resampled input samples after each frame, so that they - // can be used for future linear interpolation. - s16 resample_buffer[4]; + // TODO: document and implement. + s16 prev_input_samples[0x18]; - // TODO: document and implement. - s16 prev_input_samples[0x18]; + // Values from the last decoded AFC block. The last two values are + // especially important since AFC decoding - as a variant of ADPCM - + // requires the two latest sample values to be able to decode future + // samples. + s16 afc_remaining_samples[0x10]; + s16* AFCYN2() { return &afc_remaining_samples[0xE]; } + s16* AFCYN1() { return &afc_remaining_samples[0xF]; } + u16 unk_68_80[0x80 - 0x68]; - // Values from the last decoded AFC block. The last two values are - // especially important since AFC decoding - as a variant of ADPCM - - // requires the two latest sample values to be able to decode future - // samples. - s16 afc_remaining_samples[0x10]; - s16* AFCYN2() { return &afc_remaining_samples[0xE]; } - s16* AFCYN1() { return &afc_remaining_samples[0xF]; } + enum SamplesSourceType + { + // Simple square wave at 50% amplitude and frequency controlled via the + // resampling ratio. + SRC_SQUARE_WAVE = 0, + // Simple saw wave at 100% amplitude and frequency controlled via the + // resampling ratio. + SRC_SAW_WAVE = 1, + // Same "square" wave as SRC_SQUARE_WAVE but using a 0.25 duty cycle + // instead of 0.5. + SRC_SQUARE_WAVE_25PCT = 3, + // Breaking the numerical ordering for these, but they are all related. + // Simple pattern stored in the data downloaded by command 01. Playback + // frequency is controlled by the resampling ratio. + SRC_CONST_PATTERN_0 = 7, + SRC_CONST_PATTERN_0_VARIABLE_STEP = 10, + SRC_CONST_PATTERN_1 = 4, + SRC_CONST_PATTERN_2 = 11, + SRC_CONST_PATTERN_3 = 12, + // Samples stored in ARAM at a rate of 16 samples/5 bytes, AFC encoded, + // at an arbitrary sample rate (resampling is applied). + SRC_AFC_LQ_FROM_ARAM = 5, + // Samples stored in ARAM in PCM8 format, at an arbitrary sampling rate + // (resampling is applied). + SRC_PCM8_FROM_ARAM = 8, + // Samples stored in ARAM at a rate of 16 samples/9 bytes, AFC encoded, + // at an arbitrary sample rate (resampling is applied). + SRC_AFC_HQ_FROM_ARAM = 9, + // Samples stored in ARAM in PCM16 format, at an arbitrary sampling + // rate (resampling is applied). + SRC_PCM16_FROM_ARAM = 16, + // Samples stored in MRAM at an arbitrary sample rate (resampling is + // applied, unlike PCM16_FROM_MRAM_RAW). + SRC_PCM16_FROM_MRAM = 33, + }; + u16 samples_source_type; - u16 unk_68_80[0x80 - 0x68]; + // If non zero, indicates that the sound should loop. + u16 is_looping; - enum SamplesSourceType - { - // Simple square wave at 50% amplitude and frequency controlled via the - // resampling ratio. - SRC_SQUARE_WAVE = 0, - // Simple saw wave at 100% amplitude and frequency controlled via the - // resampling ratio. - SRC_SAW_WAVE = 1, - // Same "square" wave as SRC_SQUARE_WAVE but using a 0.25 duty cycle - // instead of 0.5. - SRC_SQUARE_WAVE_25PCT = 3, - // Breaking the numerical ordering for these, but they are all related. - // Simple pattern stored in the data downloaded by command 01. Playback - // frequency is controlled by the resampling ratio. - SRC_CONST_PATTERN_0 = 7, - SRC_CONST_PATTERN_0_VARIABLE_STEP = 10, - SRC_CONST_PATTERN_1 = 4, - SRC_CONST_PATTERN_2 = 11, - SRC_CONST_PATTERN_3 = 12, - // Samples stored in ARAM at a rate of 16 samples/5 bytes, AFC encoded, - // at an arbitrary sample rate (resampling is applied). - SRC_AFC_LQ_FROM_ARAM = 5, - // Samples stored in ARAM in PCM8 format, at an arbitrary sampling rate - // (resampling is applied). - SRC_PCM8_FROM_ARAM = 8, - // Samples stored in ARAM at a rate of 16 samples/9 bytes, AFC encoded, - // at an arbitrary sample rate (resampling is applied). - SRC_AFC_HQ_FROM_ARAM = 9, - // Samples stored in ARAM in PCM16 format, at an arbitrary sampling - // rate (resampling is applied). - SRC_PCM16_FROM_ARAM = 16, - // Samples stored in MRAM at an arbitrary sample rate (resampling is - // applied, unlike PCM16_FROM_MRAM_RAW). - SRC_PCM16_FROM_MRAM = 33, - }; - u16 samples_source_type; + // For AFC looping voices, the values of the last 2 samples before the + // start of the loop, in order to be able to decode samples after looping. + s16 loop_yn1; + s16 loop_yn2; - // If non zero, indicates that the sound should loop. - u16 is_looping; + u16 unk_84; - // For AFC looping voices, the values of the last 2 samples before the - // start of the loop, in order to be able to decode samples after looping. - s16 loop_yn1; - s16 loop_yn2; + // If true, ramp down quickly to a volume of zero, and end the voice (by + // setting VPB[1] done) when it reaches zero. + u16 end_requested; - u16 unk_84; + u16 unk_86; + u16 unk_87; - // If true, ramp down quickly to a volume of zero, and end the voice (by - // setting VPB[1] done) when it reaches zero. - u16 end_requested; + // Base address used to download samples data after the loop point of the + // voice has been reached. + u16 loop_address_h; + u16 loop_address_l; + DEFINE_32BIT_ACCESSOR(loop_address, LoopAddress) - u16 unk_86; - u16 unk_87; + // Offset (in number of raw samples) of the start of the loop area in the + // voice. Note: some sample sources only use the _h part of this. + // + // TODO: rename to length? confusion with remaining_length... + u16 loop_start_position_h; + u16 loop_start_position_l; + DEFINE_32BIT_ACCESSOR(loop_start_position, LoopStartPosition) - // Base address used to download samples data after the loop point of the - // voice has been reached. - u16 loop_address_h; - u16 loop_address_l; - DEFINE_32BIT_ACCESSOR(loop_address, LoopAddress) + // Base address used to download samples data before the loop point of the + // voice has been reached. + u16 base_address_h; + u16 base_address_l; + DEFINE_32BIT_ACCESSOR(base_address, BaseAddress) - // Offset (in number of raw samples) of the start of the loop area in the - // voice. Note: some sample sources only use the _h part of this. - // - // TODO: rename to length? confusion with remaining_length... - u16 loop_start_position_h; - u16 loop_start_position_l; - DEFINE_32BIT_ACCESSOR(loop_start_position, LoopStartPosition) + u16 padding[0xC0]; - // Base address used to download samples data before the loop point of the - // voice has been reached. - u16 base_address_h; - u16 base_address_l; - DEFINE_32BIT_ACCESSOR(base_address, BaseAddress) + // These next two functions are terrible hacks used in order to support two + // different VPB sizes. - u16 padding[0xC0]; + // Transforms from an NTSC-IPL type 0x80-sized VPB to a full size VPB. + void Uncompress() + { + u16* words = (u16*)this; + // RO part of the VPB is from 0x40-0x80 instead of 0x80-0xC0. + for (int i = 0; i < 0x40; ++i) + { + words[0x80 + i] = words[0x40 + i]; + words[0x40 + i] = 0; + } + // AFC decoded samples are offset by 0x28. + for (int i = 0; i < 0x10; ++i) + { + words[0x58 + i] = words[0x30 + i]; + words[0x30 + i] = 0; + } + // Most things are offset by 0x18 because no Dolby mixing. + for (int i = 0; i < 0x18; ++i) + { + words[0x30 + i] = words[0x18 + i]; + words[0x18 + i] = 0; + } + } - // These next two functions are terrible hacks used in order to support two - // different VPB sizes. - - // Transforms from an NTSC-IPL type 0x80-sized VPB to a full size VPB. - void Uncompress() - { - u16* words = (u16*)this; - // RO part of the VPB is from 0x40-0x80 instead of 0x80-0xC0. - for (int i = 0; i < 0x40; ++i) - { - words[0x80 + i] = words[0x40 + i]; - words[0x40 + i] = 0; - } - // AFC decoded samples are offset by 0x28. - for (int i = 0; i < 0x10; ++i) - { - words[0x58 + i] = words[0x30 + i]; - words[0x30 + i] = 0; - } - // Most things are offset by 0x18 because no Dolby mixing. - for (int i = 0; i < 0x18; ++i) - { - words[0x30 + i] = words[0x18 + i]; - words[0x18 + i] = 0; - } - } - - // Transforms from a full size VPB to an NTSC-IPL 0x80-sized VPB. - void Compress() - { - u16* words = (u16*)this; - for (int i = 0; i < 0x18; ++i) - { - words[0x18 + i] = words[0x30 + i]; - words[0x30 + i] = 0; - } - for (int i = 0; i < 0x10; ++i) - { - words[0x30 + i] = words[0x58 + i]; - words[0x58 + i] = 0; - } - for (int i = 0; i < 0x40; ++i) - { - words[0x40 + i] = words[0x80 + i]; - words[0x80 + i] = 0; - } - } + // Transforms from a full size VPB to an NTSC-IPL 0x80-sized VPB. + void Compress() + { + u16* words = (u16*)this; + for (int i = 0; i < 0x18; ++i) + { + words[0x18 + i] = words[0x30 + i]; + words[0x30 + i] = 0; + } + for (int i = 0; i < 0x10; ++i) + { + words[0x30 + i] = words[0x58 + i]; + words[0x58 + i] = 0; + } + for (int i = 0; i < 0x40; ++i) + { + words[0x40 + i] = words[0x80 + i]; + words[0x80 + i] = 0; + } + } }; struct ReverbPB { - // If zero, skip this reverb PB. - u16 enabled; - // Size of the circular buffer in MRAM, expressed in number of 0x50 samples - // blocks (0xA0 bytes). - u16 circular_buffer_size; - // Base address of the circular buffer in MRAM. - u16 circular_buffer_base_h; - u16 circular_buffer_base_l; + // If zero, skip this reverb PB. + u16 enabled; + // Size of the circular buffer in MRAM, expressed in number of 0x50 samples + // blocks (0xA0 bytes). + u16 circular_buffer_size; + // Base address of the circular buffer in MRAM. + u16 circular_buffer_base_h; + u16 circular_buffer_base_l; - struct Destination - { - u16 buffer_id; // See VPB::Channel::id. - u16 volume; // 1.15 format. - }; - Destination dest[2]; + struct Destination + { + u16 buffer_id; // See VPB::Channel::id. + u16 volume; // 1.15 format. + }; + Destination dest[2]; - // Coefficients for an 8-tap filter applied to each reverb buffer before - // adding its data to the destination. - s16 filter_coeffs[8]; + // Coefficients for an 8-tap filter applied to each reverb buffer before + // adding its data to the destination. + s16 filter_coeffs[8]; }; #pragma pack(pop) void ZeldaAudioRenderer::PrepareFrame() { - if (m_prepared) - return; + if (m_prepared) + return; - m_buf_front_left.fill(0); - m_buf_front_right.fill(0); + m_buf_front_left.fill(0); + m_buf_front_right.fill(0); - ApplyVolumeInPlace_1_15(&m_buf_back_left, 0x6784); - ApplyVolumeInPlace_1_15(&m_buf_back_right, 0x6784); + ApplyVolumeInPlace_1_15(&m_buf_back_left, 0x6784); + ApplyVolumeInPlace_1_15(&m_buf_back_right, 0x6784); - // TODO: Back left and back right should have a filter applied to them, - // then get mixed into front left and front right. In practice, TWW never - // uses this AFAICT. PanicAlert to help me find places that use this. +// TODO: Back left and back right should have a filter applied to them, +// then get mixed into front left and front right. In practice, TWW never +// uses this AFAICT. PanicAlert to help me find places that use this. #ifdef STRICT_ZELDA_HLE - if (!(m_flags & LIGHT_PROTOCOL) && (m_buf_back_left[0] != 0 || m_buf_back_right[0] != 0)) - PanicAlert("Zelda HLE using back mixing buffers"); + if (!(m_flags & LIGHT_PROTOCOL) && (m_buf_back_left[0] != 0 || m_buf_back_right[0] != 0)) + PanicAlert("Zelda HLE using back mixing buffers"); #endif - // Add reverb data from previous frame. - ApplyReverb(false); - AddBuffersWithVolume(m_buf_front_left_reverb.data(), - m_buf_back_left_reverb.data(), - 0x50, 0x7FFF); - AddBuffersWithVolume(m_buf_front_right_reverb.data(), - m_buf_back_left_reverb.data(), - 0x50, 0xB820); - AddBuffersWithVolume(m_buf_front_left_reverb.data(), - m_buf_back_right_reverb.data() + 0x28, - 0x28, 0xB820); - AddBuffersWithVolume(m_buf_front_right_reverb.data(), - m_buf_back_left_reverb.data() + 0x28, - 0x28, 0x7FFF); - m_buf_back_left_reverb.fill(0); - m_buf_back_right_reverb.fill(0); + // Add reverb data from previous frame. + ApplyReverb(false); + AddBuffersWithVolume(m_buf_front_left_reverb.data(), m_buf_back_left_reverb.data(), 0x50, 0x7FFF); + AddBuffersWithVolume(m_buf_front_right_reverb.data(), m_buf_back_left_reverb.data(), 0x50, + 0xB820); + AddBuffersWithVolume(m_buf_front_left_reverb.data(), m_buf_back_right_reverb.data() + 0x28, 0x28, + 0xB820); + AddBuffersWithVolume(m_buf_front_right_reverb.data(), m_buf_back_left_reverb.data() + 0x28, 0x28, + 0x7FFF); + m_buf_back_left_reverb.fill(0); + m_buf_back_right_reverb.fill(0); - // Prepare patterns 2/3 - they are not constant unlike 0/1. - s16* pattern2 = m_const_patterns.data() + 2 * 0x40; - s32 yn2 = pattern2[0x40 - 2], yn1 = pattern2[0x40 - 1], v; - for (int i = 0; i < 0x40; i += 2) - { - v = yn2 * yn1 - (pattern2[i] << 16); - yn2 = yn1; yn1 = pattern2[i]; pattern2[i] = v >> 16; + // Prepare patterns 2/3 - they are not constant unlike 0/1. + s16* pattern2 = m_const_patterns.data() + 2 * 0x40; + s32 yn2 = pattern2[0x40 - 2], yn1 = pattern2[0x40 - 1], v; + for (int i = 0; i < 0x40; i += 2) + { + v = yn2 * yn1 - (pattern2[i] << 16); + yn2 = yn1; + yn1 = pattern2[i]; + pattern2[i] = v >> 16; - v = 2 * (yn2 * yn1 + (pattern2[i + 1] << 16)); - yn2 = yn1; yn1 = pattern2[i + 1]; pattern2[i + 1] = v >> 16; - } - s16* pattern3 = m_const_patterns.data() + 3 * 0x40; - yn2 = pattern3[0x40 - 2]; yn1 = pattern3[0x40 - 1]; - s16 acc = yn1; - s16 step = pattern3[0] + ((yn1 * yn2 + ((yn2 << 16) + yn1)) >> 16); - step = (step & 0x1FF) | 0x2000; - for (s32 i = 0; i < 0x40; ++i) - pattern3[i] = acc + (i + 1) * step; + v = 2 * (yn2 * yn1 + (pattern2[i + 1] << 16)); + yn2 = yn1; + yn1 = pattern2[i + 1]; + pattern2[i + 1] = v >> 16; + } + s16* pattern3 = m_const_patterns.data() + 3 * 0x40; + yn2 = pattern3[0x40 - 2]; + yn1 = pattern3[0x40 - 1]; + s16 acc = yn1; + s16 step = pattern3[0] + ((yn1 * yn2 + ((yn2 << 16) + yn1)) >> 16); + step = (step & 0x1FF) | 0x2000; + for (s32 i = 0; i < 0x40; ++i) + pattern3[i] = acc + (i + 1) * step; - m_prepared = true; + m_prepared = true; } void ZeldaAudioRenderer::ApplyReverb(bool post_rendering) { - if (!m_reverb_pb_base_addr) - { + if (!m_reverb_pb_base_addr) + { #ifdef STRICT_ZELDA_HLE - PanicAlert("Trying to apply reverb without available parameters."); + PanicAlert("Trying to apply reverb without available parameters."); #endif - return; - } + return; + } - // Each of the 4 RPBs maps to one of these buffers. - MixingBuffer* reverb_buffers[4] = { - &m_buf_unk0_reverb, - &m_buf_unk1_reverb, - &m_buf_front_left_reverb, - &m_buf_front_right_reverb, - }; - std::array* last8_samples_buffers[4] = { - &m_buf_unk0_reverb_last8, - &m_buf_unk1_reverb_last8, - &m_buf_front_left_reverb_last8, - &m_buf_front_right_reverb_last8, - }; + // Each of the 4 RPBs maps to one of these buffers. + MixingBuffer* reverb_buffers[4] = { + &m_buf_unk0_reverb, &m_buf_unk1_reverb, &m_buf_front_left_reverb, &m_buf_front_right_reverb, + }; + std::array* last8_samples_buffers[4] = { + &m_buf_unk0_reverb_last8, &m_buf_unk1_reverb_last8, &m_buf_front_left_reverb_last8, + &m_buf_front_right_reverb_last8, + }; - u16* rpb_base_ptr = (u16*)HLEMemory_Get_Pointer(m_reverb_pb_base_addr); - for (u16 rpb_idx = 0; rpb_idx < 4; ++rpb_idx) - { - ReverbPB rpb; - u16* rpb_raw_ptr = reinterpret_cast(&rpb); - for (size_t i = 0; i < sizeof (ReverbPB) / 2; ++i) - rpb_raw_ptr[i] = Common::swap16(rpb_base_ptr[rpb_idx * sizeof (ReverbPB) / 2 + i]); + u16* rpb_base_ptr = (u16*)HLEMemory_Get_Pointer(m_reverb_pb_base_addr); + for (u16 rpb_idx = 0; rpb_idx < 4; ++rpb_idx) + { + ReverbPB rpb; + u16* rpb_raw_ptr = reinterpret_cast(&rpb); + for (size_t i = 0; i < sizeof(ReverbPB) / 2; ++i) + rpb_raw_ptr[i] = Common::swap16(rpb_base_ptr[rpb_idx * sizeof(ReverbPB) / 2 + i]); - if (!rpb.enabled) - continue; + if (!rpb.enabled) + continue; - u16 mram_buffer_idx = m_reverb_pb_frames_count[rpb_idx]; + u16 mram_buffer_idx = m_reverb_pb_frames_count[rpb_idx]; - u32 mram_addr = ((rpb.circular_buffer_base_h << 16) | - rpb.circular_buffer_base_l) + - mram_buffer_idx * 0x50 * sizeof (s16); - s16* mram_ptr = (s16*)HLEMemory_Get_Pointer(mram_addr); + u32 mram_addr = ((rpb.circular_buffer_base_h << 16) | rpb.circular_buffer_base_l) + + mram_buffer_idx * 0x50 * sizeof(s16); + s16* mram_ptr = (s16*)HLEMemory_Get_Pointer(mram_addr); - if (!post_rendering) - { - // 8 more samples because of the filter order. The first 8 samples - // are the last 8 samples of the previous frame. - std::array buffer; - for (u16 i = 0; i < 8; ++i) - buffer[i] = (*last8_samples_buffers[rpb_idx])[i]; + if (!post_rendering) + { + // 8 more samples because of the filter order. The first 8 samples + // are the last 8 samples of the previous frame. + std::array buffer; + for (u16 i = 0; i < 8; ++i) + buffer[i] = (*last8_samples_buffers[rpb_idx])[i]; - for (u16 i = 0; i < 0x50; ++i) - buffer[8 + i] = Common::swap16(mram_ptr[i]); + for (u16 i = 0; i < 0x50; ++i) + buffer[8 + i] = Common::swap16(mram_ptr[i]); - for (u16 i = 0; i < 8; ++i) - (*last8_samples_buffers[rpb_idx])[i] = buffer[0x50 + i]; + for (u16 i = 0; i < 8; ++i) + (*last8_samples_buffers[rpb_idx])[i] = buffer[0x50 + i]; - auto ApplyFilter = [&]() { - // Filter the buffer using provided coefficients. - for (u16 i = 0; i < 0x50; ++i) - { - s32 sample = 0; - for (u16 j = 0; j < 8; ++j) - sample += (s32)buffer[i + j] * rpb.filter_coeffs[j]; - sample >>= 15; - buffer[i] = MathUtil::Clamp(sample, -0x8000, 0x7FFF); - } - }; + auto ApplyFilter = [&]() { + // Filter the buffer using provided coefficients. + for (u16 i = 0; i < 0x50; ++i) + { + s32 sample = 0; + for (u16 j = 0; j < 8; ++j) + sample += (s32)buffer[i + j] * rpb.filter_coeffs[j]; + sample >>= 15; + buffer[i] = MathUtil::Clamp(sample, -0x8000, 0x7FFF); + } + }; - // LSB set -> pre-filtering. - if (rpb.enabled & 1) - ApplyFilter(); + // LSB set -> pre-filtering. + if (rpb.enabled & 1) + ApplyFilter(); - for (const auto& dest : rpb.dest) - { - if (dest.buffer_id == 0) - continue; + for (const auto& dest : rpb.dest) + { + if (dest.buffer_id == 0) + continue; - MixingBuffer* dest_buffer = BufferForID(dest.buffer_id); - if (!dest_buffer) - { + MixingBuffer* dest_buffer = BufferForID(dest.buffer_id); + if (!dest_buffer) + { #ifdef STRICT_ZELDA_HLE - PanicAlert("RPB mixing to an unknown buffer: %04x", dest.buffer_id); + PanicAlert("RPB mixing to an unknown buffer: %04x", dest.buffer_id); #endif - continue; - } - AddBuffersWithVolume(dest_buffer->data(), buffer.data(), - 0x50, dest.volume); - } + continue; + } + AddBuffersWithVolume(dest_buffer->data(), buffer.data(), 0x50, dest.volume); + } - // LSB not set, bit 1 set -> post-filtering. - if (rpb.enabled & 2) - ApplyFilter(); + // LSB not set, bit 1 set -> post-filtering. + if (rpb.enabled & 2) + ApplyFilter(); - for (u16 i = 0; i < 0x50; ++i) - (*reverb_buffers[rpb_idx])[i] = buffer[i]; - } - else - { - MixingBuffer* buffer = reverb_buffers[rpb_idx]; + for (u16 i = 0; i < 0x50; ++i) + (*reverb_buffers[rpb_idx])[i] = buffer[i]; + } + else + { + MixingBuffer* buffer = reverb_buffers[rpb_idx]; - // Upload the reverb data to RAM. - for (auto sample : *buffer) - *mram_ptr++ = Common::swap16(sample); + // Upload the reverb data to RAM. + for (auto sample : *buffer) + *mram_ptr++ = Common::swap16(sample); - mram_buffer_idx = (mram_buffer_idx + 1) % rpb.circular_buffer_size; - m_reverb_pb_frames_count[rpb_idx] = mram_buffer_idx; - } - } + mram_buffer_idx = (mram_buffer_idx + 1) % rpb.circular_buffer_size; + m_reverb_pb_frames_count[rpb_idx] = mram_buffer_idx; + } + } } ZeldaAudioRenderer::MixingBuffer* ZeldaAudioRenderer::BufferForID(u16 buffer_id) { - switch (buffer_id) - { - case 0x0D00: return &m_buf_front_left; - case 0x0D60: return &m_buf_front_right; - case 0x0F40: return &m_buf_back_left; - case 0x0CA0: return &m_buf_back_right; - case 0x0E80: return &m_buf_front_left_reverb; - case 0x0EE0: return &m_buf_front_right_reverb; - case 0x0C00: return &m_buf_back_left_reverb; - case 0x0C50: return &m_buf_back_right_reverb; - case 0x0DC0: return &m_buf_unk0_reverb; - case 0x0E20: return &m_buf_unk1_reverb; - case 0x09A0: return &m_buf_unk0; // Used by the GC IPL as a reverb dest. - case 0x0FA0: return &m_buf_unk1; // Used by the GC IPL as a mixing dest. - case 0x0B00: return &m_buf_unk2; // Used by Pikmin 1 as a mixing dest. - default: return nullptr; - } + switch (buffer_id) + { + case 0x0D00: + return &m_buf_front_left; + case 0x0D60: + return &m_buf_front_right; + case 0x0F40: + return &m_buf_back_left; + case 0x0CA0: + return &m_buf_back_right; + case 0x0E80: + return &m_buf_front_left_reverb; + case 0x0EE0: + return &m_buf_front_right_reverb; + case 0x0C00: + return &m_buf_back_left_reverb; + case 0x0C50: + return &m_buf_back_right_reverb; + case 0x0DC0: + return &m_buf_unk0_reverb; + case 0x0E20: + return &m_buf_unk1_reverb; + case 0x09A0: + return &m_buf_unk0; // Used by the GC IPL as a reverb dest. + case 0x0FA0: + return &m_buf_unk1; // Used by the GC IPL as a mixing dest. + case 0x0B00: + return &m_buf_unk2; // Used by Pikmin 1 as a mixing dest. + default: + return nullptr; + } } void ZeldaAudioRenderer::AddVoice(u16 voice_id) { - VPB vpb; - FetchVPB(voice_id, &vpb); + VPB vpb; + FetchVPB(voice_id, &vpb); - if (!vpb.enabled || vpb.done) - return; + if (!vpb.enabled || vpb.done) + return; - MixingBuffer input_samples; - LoadInputSamples(&input_samples, &vpb); + MixingBuffer input_samples; + LoadInputSamples(&input_samples, &vpb); - // TODO: In place effects. + // TODO: In place effects. - // TODO: IIR filter. + // TODO: IIR filter. - if (vpb.use_dolby_volume) - { - if (vpb.end_requested) - { - vpb.dolby_volume_target = vpb.dolby_volume_current / 2; - if (vpb.dolby_volume_target == 0) - vpb.done = true; - } + if (vpb.use_dolby_volume) + { + if (vpb.end_requested) + { + vpb.dolby_volume_target = vpb.dolby_volume_current / 2; + if (vpb.dolby_volume_target == 0) + vpb.done = true; + } - // Each of these volumes is in 1.15 fixed format. - s16 right_volume = m_sine_table[vpb.GetDolbyVoiceX()]; - s16 back_volume = m_sine_table[vpb.GetDolbyVoiceY()]; - s16 left_volume = m_sine_table[vpb.GetDolbyVoiceX() ^ 0x7F]; - s16 front_volume = m_sine_table[vpb.GetDolbyVoiceY() ^ 0x7F]; + // Each of these volumes is in 1.15 fixed format. + s16 right_volume = m_sine_table[vpb.GetDolbyVoiceX()]; + s16 back_volume = m_sine_table[vpb.GetDolbyVoiceY()]; + s16 left_volume = m_sine_table[vpb.GetDolbyVoiceX() ^ 0x7F]; + s16 front_volume = m_sine_table[vpb.GetDolbyVoiceY() ^ 0x7F]; - // Compute volume for each quadrant. - u16 shift_factor = (m_flags & MAKE_DOLBY_LOUDER) ? 15 : 16; - s16 quadrant_volumes[4] = { - (s16)((left_volume * front_volume) >> shift_factor), - (s16)((left_volume * back_volume) >> shift_factor), - (s16)((right_volume * front_volume) >> shift_factor), - (s16)((right_volume * back_volume) >> shift_factor), - }; + // Compute volume for each quadrant. + u16 shift_factor = (m_flags & MAKE_DOLBY_LOUDER) ? 15 : 16; + s16 quadrant_volumes[4] = { + (s16)((left_volume * front_volume) >> shift_factor), + (s16)((left_volume * back_volume) >> shift_factor), + (s16)((right_volume * front_volume) >> shift_factor), + (s16)((right_volume * back_volume) >> shift_factor), + }; - // Compute the volume delta for each sample to match the difference - // between current and target volume. - s16 delta = vpb.dolby_volume_target - vpb.dolby_volume_current; - s16 volume_deltas[4]; - for (size_t i = 0; i < 4; ++i) - volume_deltas[i] = ((u16)quadrant_volumes[i] * delta) >> shift_factor; + // Compute the volume delta for each sample to match the difference + // between current and target volume. + s16 delta = vpb.dolby_volume_target - vpb.dolby_volume_current; + s16 volume_deltas[4]; + for (size_t i = 0; i < 4; ++i) + volume_deltas[i] = ((u16)quadrant_volumes[i] * delta) >> shift_factor; - // Apply master volume to each quadrant. - for (size_t i = 0; i < 4; ++i) - quadrant_volumes[i] = (quadrant_volumes[i] * vpb.dolby_volume_current) >> shift_factor; + // Apply master volume to each quadrant. + for (size_t i = 0; i < 4; ++i) + quadrant_volumes[i] = (quadrant_volumes[i] * vpb.dolby_volume_current) >> shift_factor; - // Compute reverb volume and ramp deltas. - s16 reverb_volumes[4], reverb_volume_deltas[4]; - s16 reverb_volume_factor = (vpb.dolby_volume_current * vpb.dolby_reverb_factor) >> (shift_factor - 1); - for (size_t i = 0; i < 4; ++i) - { - reverb_volumes[i] = (quadrant_volumes[i] * reverb_volume_factor) >> shift_factor; - reverb_volume_deltas[i] = (volume_deltas[i] * vpb.dolby_reverb_factor) >> shift_factor; - } + // Compute reverb volume and ramp deltas. + s16 reverb_volumes[4], reverb_volume_deltas[4]; + s16 reverb_volume_factor = + (vpb.dolby_volume_current * vpb.dolby_reverb_factor) >> (shift_factor - 1); + for (size_t i = 0; i < 4; ++i) + { + reverb_volumes[i] = (quadrant_volumes[i] * reverb_volume_factor) >> shift_factor; + reverb_volume_deltas[i] = (volume_deltas[i] * vpb.dolby_reverb_factor) >> shift_factor; + } - struct { - MixingBuffer* buffer; - s16 volume; - s16 volume_delta; - } buffers[8] = { - { &m_buf_front_left, quadrant_volumes[0], volume_deltas[0] }, - { &m_buf_back_left, quadrant_volumes[1], volume_deltas[1] }, - { &m_buf_front_right, quadrant_volumes[2], volume_deltas[2] }, - { &m_buf_back_right, quadrant_volumes[3], volume_deltas[3] }, + struct + { + MixingBuffer* buffer; + s16 volume; + s16 volume_delta; + } buffers[8] = { + {&m_buf_front_left, quadrant_volumes[0], volume_deltas[0]}, + {&m_buf_back_left, quadrant_volumes[1], volume_deltas[1]}, + {&m_buf_front_right, quadrant_volumes[2], volume_deltas[2]}, + {&m_buf_back_right, quadrant_volumes[3], volume_deltas[3]}, - { &m_buf_front_left_reverb, reverb_volumes[0], reverb_volume_deltas[0] }, - { &m_buf_back_left_reverb, reverb_volumes[1], reverb_volume_deltas[1] }, - { &m_buf_front_right_reverb, reverb_volumes[2], reverb_volume_deltas[2] }, - { &m_buf_back_right_reverb, reverb_volumes[3], reverb_volume_deltas[3] }, - }; - for (const auto& buffer : buffers) - { - AddBuffersWithVolumeRamp(buffer.buffer, input_samples, buffer.volume << 16, - (buffer.volume_delta << 16) / (s32)buffer.buffer->size()); - } + {&m_buf_front_left_reverb, reverb_volumes[0], reverb_volume_deltas[0]}, + {&m_buf_back_left_reverb, reverb_volumes[1], reverb_volume_deltas[1]}, + {&m_buf_front_right_reverb, reverb_volumes[2], reverb_volume_deltas[2]}, + {&m_buf_back_right_reverb, reverb_volumes[3], reverb_volume_deltas[3]}, + }; + for (const auto& buffer : buffers) + { + AddBuffersWithVolumeRamp(buffer.buffer, input_samples, buffer.volume << 16, + (buffer.volume_delta << 16) / (s32)buffer.buffer->size()); + } - vpb.dolby_volume_current = vpb.dolby_volume_target; - } - else - { - // TODO: Store input samples if requested by the VPB. + vpb.dolby_volume_current = vpb.dolby_volume_target; + } + else + { + // TODO: Store input samples if requested by the VPB. - int num_channels = (m_flags & FOUR_MIXING_DESTS) ? 4 : 6; - if (vpb.end_requested) - { - bool all_mute = true; - for (int i = 0; i < num_channels; ++i) - { - vpb.channels[i].target_volume = vpb.channels[i].current_volume / 2; - all_mute &= (vpb.channels[i].target_volume == 0); - } - if (all_mute) - vpb.done = true; - } + int num_channels = (m_flags & FOUR_MIXING_DESTS) ? 4 : 6; + if (vpb.end_requested) + { + bool all_mute = true; + for (int i = 0; i < num_channels; ++i) + { + vpb.channels[i].target_volume = vpb.channels[i].current_volume / 2; + all_mute &= (vpb.channels[i].target_volume == 0); + } + if (all_mute) + vpb.done = true; + } - for (int i = 0; i < num_channels; ++i) - { - if (!vpb.channels[i].id) - continue; + for (int i = 0; i < num_channels; ++i) + { + if (!vpb.channels[i].id) + continue; - // Some UCode versions provide the delta directly instead of - // providing a target volume. - s16 volume_delta; - if (m_flags & VOLUME_EXPLICIT_STEP) - volume_delta = (vpb.channels[i].target_volume << 16); - else - volume_delta = vpb.channels[i].target_volume - vpb.channels[i].current_volume; + // Some UCode versions provide the delta directly instead of + // providing a target volume. + s16 volume_delta; + if (m_flags & VOLUME_EXPLICIT_STEP) + volume_delta = (vpb.channels[i].target_volume << 16); + else + volume_delta = vpb.channels[i].target_volume - vpb.channels[i].current_volume; - s32 volume_step = (volume_delta << 16) / (s32)input_samples.size(); // In 1.31 format. + s32 volume_step = (volume_delta << 16) / (s32)input_samples.size(); // In 1.31 format. - // TODO: The last value of each channel structure is used to - // determine whether a channel should be skipped or not. Not - // implemented yet. + // TODO: The last value of each channel structure is used to + // determine whether a channel should be skipped or not. Not + // implemented yet. - if (!vpb.channels[i].current_volume && !volume_step) - continue; + if (!vpb.channels[i].current_volume && !volume_step) + continue; - MixingBuffer* dst_buffer = BufferForID(vpb.channels[i].id); - if (!dst_buffer) - { + MixingBuffer* dst_buffer = BufferForID(vpb.channels[i].id); + if (!dst_buffer) + { #ifdef STRICT_ZELDA_HLE - PanicAlert("Mixing to an unmapped buffer: %04x", vpb.channels[i].id); + PanicAlert("Mixing to an unmapped buffer: %04x", vpb.channels[i].id); #endif - continue; - } + continue; + } - s32 new_volume = AddBuffersWithVolumeRamp( - dst_buffer, input_samples, vpb.channels[i].current_volume << 16, - volume_step); - vpb.channels[i].current_volume = new_volume >> 16; - } - } + s32 new_volume = AddBuffersWithVolumeRamp(dst_buffer, input_samples, + vpb.channels[i].current_volume << 16, volume_step); + vpb.channels[i].current_volume = new_volume >> 16; + } + } - // By then the VPB has been reset, unless we're in the "constant sample" / - // silence mode. - if (!vpb.use_constant_sample) - vpb.reset_vpb = false; + // By then the VPB has been reset, unless we're in the "constant sample" / + // silence mode. + if (!vpb.use_constant_sample) + vpb.reset_vpb = false; - StoreVPB(voice_id, &vpb); + StoreVPB(voice_id, &vpb); } void ZeldaAudioRenderer::FinalizeFrame() { - // TODO: Dolby mixing. + // TODO: Dolby mixing. - ApplyVolumeInPlace_4_12(&m_buf_front_left, m_output_volume); - ApplyVolumeInPlace_4_12(&m_buf_front_right, m_output_volume); + ApplyVolumeInPlace_4_12(&m_buf_front_left, m_output_volume); + ApplyVolumeInPlace_4_12(&m_buf_front_right, m_output_volume); - u16* ram_left_buffer = (u16*)HLEMemory_Get_Pointer(m_output_lbuf_addr); - u16* ram_right_buffer = (u16*)HLEMemory_Get_Pointer(m_output_rbuf_addr); - for (size_t i = 0; i < m_buf_front_left.size(); ++i) - { - ram_left_buffer[i] = Common::swap16(m_buf_front_left[i]); - ram_right_buffer[i] = Common::swap16(m_buf_front_right[i]); - } - m_output_lbuf_addr += sizeof (u16) * (u32)m_buf_front_left.size(); - m_output_rbuf_addr += sizeof (u16) * (u32)m_buf_front_right.size(); + u16* ram_left_buffer = (u16*)HLEMemory_Get_Pointer(m_output_lbuf_addr); + u16* ram_right_buffer = (u16*)HLEMemory_Get_Pointer(m_output_rbuf_addr); + for (size_t i = 0; i < m_buf_front_left.size(); ++i) + { + ram_left_buffer[i] = Common::swap16(m_buf_front_left[i]); + ram_right_buffer[i] = Common::swap16(m_buf_front_right[i]); + } + m_output_lbuf_addr += sizeof(u16) * (u32)m_buf_front_left.size(); + m_output_rbuf_addr += sizeof(u16) * (u32)m_buf_front_right.size(); - // TODO: Some more Dolby mixing. + // TODO: Some more Dolby mixing. - ApplyReverb(true); + ApplyReverb(true); - m_prepared = false; + m_prepared = false; } void ZeldaAudioRenderer::FetchVPB(u16 voice_id, VPB* vpb) { - u16* vpb_words = (u16*)vpb; - u16* ram_vpbs = (u16*)HLEMemory_Get_Pointer(m_vpb_base_addr); + u16* vpb_words = (u16*)vpb; + u16* ram_vpbs = (u16*)HLEMemory_Get_Pointer(m_vpb_base_addr); - // A few versions of the UCode have VPB of size 0x80 (vs. the standard - // 0xC0). The whole 0x40-0x80 part is gone. Handle that by moving things - // around. - size_t vpb_size = (m_flags & TINY_VPB) ? 0x80 : 0xC0; + // A few versions of the UCode have VPB of size 0x80 (vs. the standard + // 0xC0). The whole 0x40-0x80 part is gone. Handle that by moving things + // around. + size_t vpb_size = (m_flags & TINY_VPB) ? 0x80 : 0xC0; - size_t base_idx = voice_id * vpb_size; - for (size_t i = 0; i < vpb_size; ++i) - vpb_words[i] = Common::swap16(ram_vpbs[base_idx + i]); + size_t base_idx = voice_id * vpb_size; + for (size_t i = 0; i < vpb_size; ++i) + vpb_words[i] = Common::swap16(ram_vpbs[base_idx + i]); - if (m_flags & TINY_VPB) - vpb->Uncompress(); + if (m_flags & TINY_VPB) + vpb->Uncompress(); } void ZeldaAudioRenderer::StoreVPB(u16 voice_id, VPB* vpb) { - u16* vpb_words = (u16*)vpb; - u16* ram_vpbs = (u16*)HLEMemory_Get_Pointer(m_vpb_base_addr); + u16* vpb_words = (u16*)vpb; + u16* ram_vpbs = (u16*)HLEMemory_Get_Pointer(m_vpb_base_addr); - size_t vpb_size = (m_flags & TINY_VPB) ? 0x80 : 0xC0; - size_t base_idx = voice_id * vpb_size; + size_t vpb_size = (m_flags & TINY_VPB) ? 0x80 : 0xC0; + size_t base_idx = voice_id * vpb_size; - if (m_flags & TINY_VPB) - vpb->Compress(); + if (m_flags & TINY_VPB) + vpb->Compress(); - // Only the first 0x80 words are transferred back - the rest is read-only. - for (size_t i = 0; i < vpb_size - 0x40; ++i) - ram_vpbs[base_idx + i] = Common::swap16(vpb_words[i]); + // Only the first 0x80 words are transferred back - the rest is read-only. + for (size_t i = 0; i < vpb_size - 0x40; ++i) + ram_vpbs[base_idx + i] = Common::swap16(vpb_words[i]); } void ZeldaAudioRenderer::LoadInputSamples(MixingBuffer* buffer, VPB* vpb) { - // Input data pre-resampling. Resampled into the mixing buffer parameter at - // the end of processing, if needed. - // - // Maximum of 0x500 samples here - see NeededRawSamplesCount to understand - // this practical limit (resampling_ratio = 0xFFFF -> 0x500 samples). Add a - // margin of 4 that is needed for samples source that do resampling. - std::array raw_input_samples; - for (size_t i = 0; i < 4; ++i) - raw_input_samples[i] = vpb->resample_buffer[i]; + // Input data pre-resampling. Resampled into the mixing buffer parameter at + // the end of processing, if needed. + // + // Maximum of 0x500 samples here - see NeededRawSamplesCount to understand + // this practical limit (resampling_ratio = 0xFFFF -> 0x500 samples). Add a + // margin of 4 that is needed for samples source that do resampling. + std::array raw_input_samples; + for (size_t i = 0; i < 4; ++i) + raw_input_samples[i] = vpb->resample_buffer[i]; - if (vpb->use_constant_sample) - { - buffer->fill(vpb->constant_sample); - return; - } + if (vpb->use_constant_sample) + { + buffer->fill(vpb->constant_sample); + return; + } - switch (vpb->samples_source_type) - { - case VPB::SRC_SQUARE_WAVE: - case VPB::SRC_SQUARE_WAVE_25PCT: - { - u32 shift; - if (vpb->samples_source_type == VPB::SRC_SQUARE_WAVE) - shift = 1; - else - shift = 2; - u32 mask = (1 << shift) - 1; + switch (vpb->samples_source_type) + { + case VPB::SRC_SQUARE_WAVE: + case VPB::SRC_SQUARE_WAVE_25PCT: + { + u32 shift; + if (vpb->samples_source_type == VPB::SRC_SQUARE_WAVE) + shift = 1; + else + shift = 2; + u32 mask = (1 << shift) - 1; - u32 pos = vpb->current_pos_frac << shift; - for (size_t i = 0; i < buffer->size(); ++i) - { - (*buffer)[i] = ((pos >> 16) & mask) ? 0xC000 : 0x4000; - pos += vpb->resampling_ratio; - } - vpb->current_pos_frac = (pos >> shift) & 0xFFFF; - break; - } + u32 pos = vpb->current_pos_frac << shift; + for (size_t i = 0; i < buffer->size(); ++i) + { + (*buffer)[i] = ((pos >> 16) & mask) ? 0xC000 : 0x4000; + pos += vpb->resampling_ratio; + } + vpb->current_pos_frac = (pos >> shift) & 0xFFFF; + break; + } - case VPB::SRC_SAW_WAVE: - { - u32 pos = vpb->current_pos_frac; - for (size_t i = 0; i < buffer->size(); ++i) - { - (*buffer)[i] = pos & 0xFFFF; - pos += (vpb->resampling_ratio) >> 1; - } - vpb->current_pos_frac = pos & 0xFFFF; - break; - } + case VPB::SRC_SAW_WAVE: + { + u32 pos = vpb->current_pos_frac; + for (size_t i = 0; i < buffer->size(); ++i) + { + (*buffer)[i] = pos & 0xFFFF; + pos += (vpb->resampling_ratio) >> 1; + } + vpb->current_pos_frac = pos & 0xFFFF; + break; + } - case VPB::SRC_CONST_PATTERN_0: - case VPB::SRC_CONST_PATTERN_0_VARIABLE_STEP: - case VPB::SRC_CONST_PATTERN_1: - case VPB::SRC_CONST_PATTERN_2: - case VPB::SRC_CONST_PATTERN_3: - { - const u16 PATTERN_SIZE = 0x40; + case VPB::SRC_CONST_PATTERN_0: + case VPB::SRC_CONST_PATTERN_0_VARIABLE_STEP: + case VPB::SRC_CONST_PATTERN_1: + case VPB::SRC_CONST_PATTERN_2: + case VPB::SRC_CONST_PATTERN_3: + { + const u16 PATTERN_SIZE = 0x40; - struct PatternInfo { u16 idx; bool variable_step; }; - std::map samples_source_to_pattern = { - { VPB::SRC_CONST_PATTERN_0, {0, false} }, - { VPB::SRC_CONST_PATTERN_0_VARIABLE_STEP, {0, true} }, - { VPB::SRC_CONST_PATTERN_1, {1, false} }, - { VPB::SRC_CONST_PATTERN_2, {2, false} }, - { VPB::SRC_CONST_PATTERN_3, {3, false} }, - }; - auto& pattern_info = samples_source_to_pattern[vpb->samples_source_type]; - u16 pattern_offset = pattern_info.idx * PATTERN_SIZE; - s16* pattern = m_const_patterns.data() + pattern_offset; + struct PatternInfo + { + u16 idx; + bool variable_step; + }; + std::map samples_source_to_pattern = { + {VPB::SRC_CONST_PATTERN_0, {0, false}}, {VPB::SRC_CONST_PATTERN_0_VARIABLE_STEP, {0, true}}, + {VPB::SRC_CONST_PATTERN_1, {1, false}}, {VPB::SRC_CONST_PATTERN_2, {2, false}}, + {VPB::SRC_CONST_PATTERN_3, {3, false}}, + }; + auto& pattern_info = samples_source_to_pattern[vpb->samples_source_type]; + u16 pattern_offset = pattern_info.idx * PATTERN_SIZE; + s16* pattern = m_const_patterns.data() + pattern_offset; - u32 pos = vpb->current_pos_frac << 6; // log2(PATTERN_SIZE) - u32 step = vpb->resampling_ratio << 5; + u32 pos = vpb->current_pos_frac << 6; // log2(PATTERN_SIZE) + u32 step = vpb->resampling_ratio << 5; - for (size_t i = 0; i < buffer->size(); ++i) - { - (*buffer)[i] = pattern[pos >> 16]; - pos = (pos + step) % (PATTERN_SIZE << 16); - if (pattern_info.variable_step) - pos = ((pos << 10) + m_buf_back_right[i] * vpb->resampling_ratio) >> 10; - } + for (size_t i = 0; i < buffer->size(); ++i) + { + (*buffer)[i] = pattern[pos >> 16]; + pos = (pos + step) % (PATTERN_SIZE << 16); + if (pattern_info.variable_step) + pos = ((pos << 10) + m_buf_back_right[i] * vpb->resampling_ratio) >> 10; + } - vpb->current_pos_frac = pos >> 6; - break; - } + vpb->current_pos_frac = pos >> 6; + break; + } + case VPB::SRC_PCM8_FROM_ARAM: + DownloadPCMSamplesFromARAM(raw_input_samples.data() + 4, vpb, NeededRawSamplesCount(*vpb)); + Resample(vpb, raw_input_samples.data(), buffer); + break; + case VPB::SRC_AFC_HQ_FROM_ARAM: + case VPB::SRC_AFC_LQ_FROM_ARAM: + DownloadAFCSamplesFromARAM(raw_input_samples.data() + 4, vpb, NeededRawSamplesCount(*vpb)); + Resample(vpb, raw_input_samples.data(), buffer); + break; - case VPB::SRC_PCM8_FROM_ARAM: - DownloadPCMSamplesFromARAM(raw_input_samples.data() + 4, vpb, - NeededRawSamplesCount(*vpb)); - Resample(vpb, raw_input_samples.data(), buffer); - break; + case VPB::SRC_PCM16_FROM_ARAM: + DownloadPCMSamplesFromARAM(raw_input_samples.data() + 4, vpb, NeededRawSamplesCount(*vpb)); + Resample(vpb, raw_input_samples.data(), buffer); + break; - case VPB::SRC_AFC_HQ_FROM_ARAM: - case VPB::SRC_AFC_LQ_FROM_ARAM: - DownloadAFCSamplesFromARAM(raw_input_samples.data() + 4, vpb, - NeededRawSamplesCount(*vpb)); - Resample(vpb, raw_input_samples.data(), buffer); - break; + case VPB::SRC_PCM16_FROM_MRAM: + DownloadRawSamplesFromMRAM(raw_input_samples.data() + 4, vpb, NeededRawSamplesCount(*vpb)); + Resample(vpb, raw_input_samples.data(), buffer); + break; - case VPB::SRC_PCM16_FROM_ARAM: - DownloadPCMSamplesFromARAM(raw_input_samples.data() + 4, vpb, - NeededRawSamplesCount(*vpb)); - Resample(vpb, raw_input_samples.data(), buffer); - break; - - case VPB::SRC_PCM16_FROM_MRAM: - DownloadRawSamplesFromMRAM(raw_input_samples.data() + 4, vpb, - NeededRawSamplesCount(*vpb)); - Resample(vpb, raw_input_samples.data(), buffer); - break; - - default: - PanicAlert("Using an unknown/unimplemented sample source: %04x", vpb->samples_source_type); - buffer->fill(0); - return; - } + default: + PanicAlert("Using an unknown/unimplemented sample source: %04x", vpb->samples_source_type); + buffer->fill(0); + return; + } } u16 ZeldaAudioRenderer::NeededRawSamplesCount(const VPB& vpb) { - // Both of these are 4.12 fixed point, so shift by 12 to get the int part. - return (vpb.current_pos_frac + 0x50 * vpb.resampling_ratio) >> 12; + // Both of these are 4.12 fixed point, so shift by 12 to get the int part. + return (vpb.current_pos_frac + 0x50 * vpb.resampling_ratio) >> 12; } void ZeldaAudioRenderer::Resample(VPB* vpb, const s16* src, MixingBuffer* dst) { - // Both in 20.12 format. - u32 ratio = vpb->resampling_ratio; - u32 pos = vpb->current_pos_frac; + // Both in 20.12 format. + u32 ratio = vpb->resampling_ratio; + u32 pos = vpb->current_pos_frac; - // Check if we need to do some interpolation. If the resampling ratio is - // more than 4:1, it's not worth it. - if ((ratio >> 12) >= 4) - { - for (s16& dst_sample : *dst) - { - pos += ratio; - dst_sample = src[pos >> 12]; - } - } - else - { - for (auto& dst_sample : *dst) - { - // We have 0x40 * 4 coeffs that need to be selected based on the - // most significant bits of the fractional part of the position. 12 - // bits >> 6 = 6 bits = 0x40. Multiply by 4 since there are 4 - // consecutive coeffs. - u32 coeffs_idx = ((pos & 0xFFF) >> 6) * 4; - const s16* coeffs = &m_resampling_coeffs[coeffs_idx]; - const s16* input = &src[pos >> 12]; + // Check if we need to do some interpolation. If the resampling ratio is + // more than 4:1, it's not worth it. + if ((ratio >> 12) >= 4) + { + for (s16& dst_sample : *dst) + { + pos += ratio; + dst_sample = src[pos >> 12]; + } + } + else + { + for (auto& dst_sample : *dst) + { + // We have 0x40 * 4 coeffs that need to be selected based on the + // most significant bits of the fractional part of the position. 12 + // bits >> 6 = 6 bits = 0x40. Multiply by 4 since there are 4 + // consecutive coeffs. + u32 coeffs_idx = ((pos & 0xFFF) >> 6) * 4; + const s16* coeffs = &m_resampling_coeffs[coeffs_idx]; + const s16* input = &src[pos >> 12]; - s64 dst_sample_unclamped = 0; - for (size_t i = 0; i < 4; ++i) - dst_sample_unclamped += (s64)2 * coeffs[i] * input[i]; - dst_sample_unclamped >>= 16; + s64 dst_sample_unclamped = 0; + for (size_t i = 0; i < 4; ++i) + dst_sample_unclamped += (s64)2 * coeffs[i] * input[i]; + dst_sample_unclamped >>= 16; - dst_sample = (s16)MathUtil::Clamp(dst_sample_unclamped, -0x8000, 0x7FFF); + dst_sample = (s16)MathUtil::Clamp(dst_sample_unclamped, -0x8000, 0x7FFF); - pos += ratio; - } - } + pos += ratio; + } + } - for (u32 i = 0; i < 4; ++i) - vpb->resample_buffer[i] = src[(pos >> 12) + i]; - vpb->constant_sample = (*dst)[dst->size() - 1]; - vpb->current_pos_frac = pos & 0xFFF; + for (u32 i = 0; i < 4; ++i) + vpb->resample_buffer[i] = src[(pos >> 12) + i]; + vpb->constant_sample = (*dst)[dst->size() - 1]; + vpb->current_pos_frac = pos & 0xFFF; } void* ZeldaAudioRenderer::GetARAMPtr() const { - if (m_aram_base_addr) - return HLEMemory_Get_Pointer(m_aram_base_addr); - else - return DSP::GetARAMPtr(); + if (m_aram_base_addr) + return HLEMemory_Get_Pointer(m_aram_base_addr); + else + return DSP::GetARAMPtr(); } template void ZeldaAudioRenderer::DownloadPCMSamplesFromARAM(s16* dst, VPB* vpb, u16 requested_samples_count) { - if (vpb->done) - { - for (u16 i = 0; i < requested_samples_count; ++i) - dst[i] = 0; - return; - } + if (vpb->done) + { + for (u16 i = 0; i < requested_samples_count; ++i) + dst[i] = 0; + return; + } - if (vpb->reset_vpb) - { - vpb->SetRemainingLength( - vpb->GetLoopStartPosition() - vpb->GetCurrentPosition()); - vpb->SetCurrentARAMAddr( - vpb->GetBaseAddress() + vpb->GetCurrentPosition() * sizeof (T)); - } + if (vpb->reset_vpb) + { + vpb->SetRemainingLength(vpb->GetLoopStartPosition() - vpb->GetCurrentPosition()); + vpb->SetCurrentARAMAddr(vpb->GetBaseAddress() + vpb->GetCurrentPosition() * sizeof(T)); + } - vpb->end_reached = false; - while (requested_samples_count) - { - if (vpb->end_reached) - { - vpb->end_reached = false; - if (!vpb->is_looping) - { - for (u16 i = 0; i < requested_samples_count; ++i) - dst[i] = 0; - vpb->done = true; - break; - } - vpb->SetCurrentPosition(vpb->GetLoopAddress()); - vpb->SetRemainingLength( - vpb->GetLoopStartPosition() - vpb->GetCurrentPosition()); - vpb->SetCurrentARAMAddr( - vpb->GetBaseAddress() + vpb->GetCurrentPosition() * sizeof (T)); - } + vpb->end_reached = false; + while (requested_samples_count) + { + if (vpb->end_reached) + { + vpb->end_reached = false; + if (!vpb->is_looping) + { + for (u16 i = 0; i < requested_samples_count; ++i) + dst[i] = 0; + vpb->done = true; + break; + } + vpb->SetCurrentPosition(vpb->GetLoopAddress()); + vpb->SetRemainingLength(vpb->GetLoopStartPosition() - vpb->GetCurrentPosition()); + vpb->SetCurrentARAMAddr(vpb->GetBaseAddress() + vpb->GetCurrentPosition() * sizeof(T)); + } - T* src_ptr = (T*)((u8*)GetARAMPtr() + vpb->GetCurrentARAMAddr()); - u16 samples_to_download = std::min(vpb->GetRemainingLength(), - (u32)requested_samples_count); + T* src_ptr = (T*)((u8*)GetARAMPtr() + vpb->GetCurrentARAMAddr()); + u16 samples_to_download = std::min(vpb->GetRemainingLength(), (u32)requested_samples_count); - for (u16 i = 0; i < samples_to_download; ++i) - *dst++ = Common::FromBigEndian(*src_ptr++) << (16 - 8 * sizeof (T)); + for (u16 i = 0; i < samples_to_download; ++i) + *dst++ = Common::FromBigEndian(*src_ptr++) << (16 - 8 * sizeof(T)); - vpb->SetRemainingLength(vpb->GetRemainingLength() - samples_to_download); - vpb->SetCurrentARAMAddr(vpb->GetCurrentARAMAddr() + samples_to_download * sizeof (T)); - requested_samples_count -= samples_to_download; - if (!vpb->GetRemainingLength()) - vpb->end_reached = true; - } + vpb->SetRemainingLength(vpb->GetRemainingLength() - samples_to_download); + vpb->SetCurrentARAMAddr(vpb->GetCurrentARAMAddr() + samples_to_download * sizeof(T)); + requested_samples_count -= samples_to_download; + if (!vpb->GetRemainingLength()) + vpb->end_reached = true; + } } -void ZeldaAudioRenderer::DownloadAFCSamplesFromARAM( - s16* dst, VPB* vpb, u16 requested_samples_count) +void ZeldaAudioRenderer::DownloadAFCSamplesFromARAM(s16* dst, VPB* vpb, u16 requested_samples_count) { - if (vpb->reset_vpb) - { - *vpb->AFCYN1() = 0; - *vpb->AFCYN2() = 0; - vpb->afc_remaining_decoded_samples = 0; - vpb->SetRemainingLength(vpb->GetLoopStartPosition()); - vpb->SetCurrentARAMAddr(vpb->GetBaseAddress()); - } + if (vpb->reset_vpb) + { + *vpb->AFCYN1() = 0; + *vpb->AFCYN2() = 0; + vpb->afc_remaining_decoded_samples = 0; + vpb->SetRemainingLength(vpb->GetLoopStartPosition()); + vpb->SetCurrentARAMAddr(vpb->GetBaseAddress()); + } - if (vpb->done) - { - for (u16 i = 0; i < requested_samples_count; ++i) - dst[i] = 0; - return; - } + if (vpb->done) + { + for (u16 i = 0; i < requested_samples_count; ++i) + dst[i] = 0; + return; + } - // Try several things until we have output enough samples. - while (true) - { - // Try to push currently cached/already decoded samples. - u16 remaining_to_output = std::min(vpb->afc_remaining_decoded_samples, - requested_samples_count); - s16* base = &vpb->afc_remaining_samples[0x10 - vpb->afc_remaining_decoded_samples]; - for (size_t i = 0; i < remaining_to_output; ++i) - *dst++ = base[i]; + // Try several things until we have output enough samples. + while (true) + { + // Try to push currently cached/already decoded samples. + u16 remaining_to_output = std::min(vpb->afc_remaining_decoded_samples, requested_samples_count); + s16* base = &vpb->afc_remaining_samples[0x10 - vpb->afc_remaining_decoded_samples]; + for (size_t i = 0; i < remaining_to_output; ++i) + *dst++ = base[i]; - vpb->afc_remaining_decoded_samples -= remaining_to_output; - requested_samples_count -= remaining_to_output; + vpb->afc_remaining_decoded_samples -= remaining_to_output; + requested_samples_count -= remaining_to_output; - if (requested_samples_count == 0) - { - return; // We have output everything we needed. - } - else if (requested_samples_count <= vpb->GetRemainingLength()) - { - // Each AFC block is 16 samples. - u16 requested_blocks_count = (requested_samples_count + 0xF) >> 4; - u16 decoded_samples_count = requested_blocks_count << 4; + if (requested_samples_count == 0) + { + return; // We have output everything we needed. + } + else if (requested_samples_count <= vpb->GetRemainingLength()) + { + // Each AFC block is 16 samples. + u16 requested_blocks_count = (requested_samples_count + 0xF) >> 4; + u16 decoded_samples_count = requested_blocks_count << 4; - if (decoded_samples_count < vpb->GetRemainingLength()) - { - vpb->afc_remaining_decoded_samples = - decoded_samples_count - requested_samples_count; - vpb->SetRemainingLength(vpb->GetRemainingLength() - decoded_samples_count); - } - else - { - vpb->afc_remaining_decoded_samples = - vpb->GetRemainingLength() - requested_samples_count; - vpb->SetRemainingLength(0); - } + if (decoded_samples_count < vpb->GetRemainingLength()) + { + vpb->afc_remaining_decoded_samples = decoded_samples_count - requested_samples_count; + vpb->SetRemainingLength(vpb->GetRemainingLength() - decoded_samples_count); + } + else + { + vpb->afc_remaining_decoded_samples = vpb->GetRemainingLength() - requested_samples_count; + vpb->SetRemainingLength(0); + } - DecodeAFC(vpb, dst, requested_blocks_count); + DecodeAFC(vpb, dst, requested_blocks_count); - if (vpb->afc_remaining_decoded_samples) - { - for (size_t i = 0; i < 0x10; ++i) - vpb->afc_remaining_samples[i] = dst[decoded_samples_count - 0x10 + i]; + if (vpb->afc_remaining_decoded_samples) + { + for (size_t i = 0; i < 0x10; ++i) + vpb->afc_remaining_samples[i] = dst[decoded_samples_count - 0x10 + i]; - if (!vpb->GetRemainingLength() && vpb->GetLoopStartPosition()) - { - // Adjust remaining samples to account for the future loop iteration. - base = vpb->afc_remaining_samples + ((vpb->GetLoopStartPosition() + 0xF) & 0xF); - for (size_t i = 0; i < vpb->afc_remaining_decoded_samples; ++i) - vpb->afc_remaining_samples[0x10 - i - 1] = *base--; - } - } + if (!vpb->GetRemainingLength() && vpb->GetLoopStartPosition()) + { + // Adjust remaining samples to account for the future loop iteration. + base = vpb->afc_remaining_samples + ((vpb->GetLoopStartPosition() + 0xF) & 0xF); + for (size_t i = 0; i < vpb->afc_remaining_decoded_samples; ++i) + vpb->afc_remaining_samples[0x10 - i - 1] = *base--; + } + } - return; - } - else - { - // More samples asked than available. Either complete the sound, or - // start looping. - if (vpb->GetRemainingLength()) // Skip if we cannot load anything. - { - requested_samples_count -= vpb->GetRemainingLength(); - u16 requested_blocks_count = (vpb->GetRemainingLength() + 0xF) >> 4; - DecodeAFC(vpb, dst, requested_blocks_count); - dst += vpb->GetRemainingLength(); - } + return; + } + else + { + // More samples asked than available. Either complete the sound, or + // start looping. + if (vpb->GetRemainingLength()) // Skip if we cannot load anything. + { + requested_samples_count -= vpb->GetRemainingLength(); + u16 requested_blocks_count = (vpb->GetRemainingLength() + 0xF) >> 4; + DecodeAFC(vpb, dst, requested_blocks_count); + dst += vpb->GetRemainingLength(); + } - if (!vpb->is_looping) - { - vpb->done = true; - for (size_t i = 0; i < requested_samples_count; ++i) - *dst++ = 0; - return; - } - else - { - // We need to loop. Compute the new position, decode a block, - // and loop back to the beginning of the download logic. + if (!vpb->is_looping) + { + vpb->done = true; + for (size_t i = 0; i < requested_samples_count; ++i) + *dst++ = 0; + return; + } + else + { + // We need to loop. Compute the new position, decode a block, + // and loop back to the beginning of the download logic. - // Use the fact that the sample source number also represents - // the number of bytes per 16 samples. - u32 loop_off_in_bytes = - (vpb->GetLoopAddress() >> 4) * vpb->samples_source_type; - u32 loop_start_addr = vpb->GetBaseAddress() + loop_off_in_bytes; - vpb->SetCurrentARAMAddr(loop_start_addr); + // Use the fact that the sample source number also represents + // the number of bytes per 16 samples. + u32 loop_off_in_bytes = (vpb->GetLoopAddress() >> 4) * vpb->samples_source_type; + u32 loop_start_addr = vpb->GetBaseAddress() + loop_off_in_bytes; + vpb->SetCurrentARAMAddr(loop_start_addr); - *vpb->AFCYN2() = vpb->loop_yn2; - *vpb->AFCYN1() = vpb->loop_yn1; + *vpb->AFCYN2() = vpb->loop_yn2; + *vpb->AFCYN1() = vpb->loop_yn1; - DecodeAFC(vpb, vpb->afc_remaining_samples, 1); + DecodeAFC(vpb, vpb->afc_remaining_samples, 1); - // Realign and recompute the number of internally cached - // samples and the current position. - vpb->afc_remaining_decoded_samples = - 0x10 - (vpb->GetLoopAddress() & 0xF); + // Realign and recompute the number of internally cached + // samples and the current position. + vpb->afc_remaining_decoded_samples = 0x10 - (vpb->GetLoopAddress() & 0xF); - u32 remaining_length = vpb->GetLoopStartPosition(); - remaining_length -= vpb->afc_remaining_decoded_samples; - remaining_length -= vpb->GetLoopAddress(); - vpb->SetRemainingLength(remaining_length); - continue; - } - } - } + u32 remaining_length = vpb->GetLoopStartPosition(); + remaining_length -= vpb->afc_remaining_decoded_samples; + remaining_length -= vpb->GetLoopAddress(); + vpb->SetRemainingLength(remaining_length); + continue; + } + } + } } void ZeldaAudioRenderer::DecodeAFC(VPB* vpb, s16* dst, size_t block_count) { - u32 addr = vpb->GetCurrentARAMAddr(); - u8* src = (u8*)GetARAMPtr() + addr; - vpb->SetCurrentARAMAddr(addr + (u32)block_count * vpb->samples_source_type); + u32 addr = vpb->GetCurrentARAMAddr(); + u8* src = (u8*)GetARAMPtr() + addr; + vpb->SetCurrentARAMAddr(addr + (u32)block_count * vpb->samples_source_type); - for (size_t b = 0; b < block_count; ++b) - { - s16 nibbles[16]; - s16 delta = 1 << ((*src >> 4) & 0xF); - s16 idx = (*src & 0xF); - src++; + for (size_t b = 0; b < block_count; ++b) + { + s16 nibbles[16]; + s16 delta = 1 << ((*src >> 4) & 0xF); + s16 idx = (*src & 0xF); + src++; - if (vpb->samples_source_type == VPB::SRC_AFC_HQ_FROM_ARAM) - { - for (size_t i = 0; i < 16; i += 2) - { - nibbles[i + 0] = *src >> 4; - nibbles[i + 1] = *src & 0xF; - src++; - } - for (auto& nibble : nibbles) - { - if (nibble >= 8) - nibble -= 16; - nibble <<= 11; - } - } - else - { - for (size_t i = 0; i < 16; i += 4) - { - nibbles[i + 0] = (*src >> 6) & 3; - nibbles[i + 1] = (*src >> 4) & 3; - nibbles[i + 2] = (*src >> 2) & 3; - nibbles[i + 3] = (*src >> 0) & 3; - src++; - } - for (auto& nibble : nibbles) - { - if (nibble >= 2) - nibble -= 4; - nibble <<= 13; - } - } + if (vpb->samples_source_type == VPB::SRC_AFC_HQ_FROM_ARAM) + { + for (size_t i = 0; i < 16; i += 2) + { + nibbles[i + 0] = *src >> 4; + nibbles[i + 1] = *src & 0xF; + src++; + } + for (auto& nibble : nibbles) + { + if (nibble >= 8) + nibble -= 16; + nibble <<= 11; + } + } + else + { + for (size_t i = 0; i < 16; i += 4) + { + nibbles[i + 0] = (*src >> 6) & 3; + nibbles[i + 1] = (*src >> 4) & 3; + nibbles[i + 2] = (*src >> 2) & 3; + nibbles[i + 3] = (*src >> 0) & 3; + src++; + } + for (auto& nibble : nibbles) + { + if (nibble >= 2) + nibble -= 4; + nibble <<= 13; + } + } - s32 yn1 = *vpb->AFCYN1(), yn2 = *vpb->AFCYN2(); - for (size_t i = 0; i < 16; ++i) - { - s32 sample = delta * nibbles[i] + - yn1 * m_afc_coeffs[idx * 2] + - yn2 * m_afc_coeffs[idx * 2 + 1]; - sample >>= 11; - sample = MathUtil::Clamp(sample, -0x8000, 0x7fff); - *dst++ = (s16)sample; - yn2 = yn1; - yn1 = sample; - } + s32 yn1 = *vpb->AFCYN1(), yn2 = *vpb->AFCYN2(); + for (size_t i = 0; i < 16; ++i) + { + s32 sample = + delta * nibbles[i] + yn1 * m_afc_coeffs[idx * 2] + yn2 * m_afc_coeffs[idx * 2 + 1]; + sample >>= 11; + sample = MathUtil::Clamp(sample, -0x8000, 0x7fff); + *dst++ = (s16)sample; + yn2 = yn1; + yn1 = sample; + } - *vpb->AFCYN2() = yn2; - *vpb->AFCYN1() = yn1; - } + *vpb->AFCYN2() = yn2; + *vpb->AFCYN1() = yn1; + } } -void ZeldaAudioRenderer::DownloadRawSamplesFromMRAM( - s16* dst, VPB* vpb, u16 requested_samples_count) +void ZeldaAudioRenderer::DownloadRawSamplesFromMRAM(s16* dst, VPB* vpb, u16 requested_samples_count) { - u32 addr = vpb->GetBaseAddress() + vpb->current_position_h * sizeof (u16); - s16* src_ptr = (s16*)HLEMemory_Get_Pointer(addr); + u32 addr = vpb->GetBaseAddress() + vpb->current_position_h * sizeof(u16); + s16* src_ptr = (s16*)HLEMemory_Get_Pointer(addr); - if (requested_samples_count > vpb->GetRemainingLength()) - { - s16 last_sample = 0; - for (u16 i = 0; i < vpb->GetRemainingLength(); ++i) - *dst++ = last_sample = Common::swap16(*src_ptr++); - for (u16 i = vpb->GetRemainingLength(); i < requested_samples_count; ++i) - *dst++ = last_sample; + if (requested_samples_count > vpb->GetRemainingLength()) + { + s16 last_sample = 0; + for (u16 i = 0; i < vpb->GetRemainingLength(); ++i) + *dst++ = last_sample = Common::swap16(*src_ptr++); + for (u16 i = vpb->GetRemainingLength(); i < requested_samples_count; ++i) + *dst++ = last_sample; - vpb->current_position_h += vpb->GetRemainingLength(); - vpb->SetRemainingLength(0); - vpb->done = true; - } - else - { - vpb->SetRemainingLength(vpb->GetRemainingLength() - requested_samples_count); - vpb->samples_before_loop = vpb->loop_start_position_h - vpb->current_position_h; - if (requested_samples_count <= vpb->samples_before_loop) - { - for (u16 i = 0; i < requested_samples_count; ++i) - *dst++ = Common::swap16(*src_ptr++); - vpb->current_position_h += requested_samples_count; - } - else - { - for (u16 i = 0; i < vpb->samples_before_loop; ++i) - *dst++ = Common::swap16(*src_ptr++); - vpb->SetBaseAddress(vpb->GetLoopAddress()); - src_ptr = (s16*)HLEMemory_Get_Pointer(vpb->GetLoopAddress()); - for (u16 i = vpb->samples_before_loop; i < requested_samples_count; ++i) - *dst++ = Common::swap16(*src_ptr++); - vpb->current_position_h = requested_samples_count - vpb->samples_before_loop; - } - } + vpb->current_position_h += vpb->GetRemainingLength(); + vpb->SetRemainingLength(0); + vpb->done = true; + } + else + { + vpb->SetRemainingLength(vpb->GetRemainingLength() - requested_samples_count); + vpb->samples_before_loop = vpb->loop_start_position_h - vpb->current_position_h; + if (requested_samples_count <= vpb->samples_before_loop) + { + for (u16 i = 0; i < requested_samples_count; ++i) + *dst++ = Common::swap16(*src_ptr++); + vpb->current_position_h += requested_samples_count; + } + else + { + for (u16 i = 0; i < vpb->samples_before_loop; ++i) + *dst++ = Common::swap16(*src_ptr++); + vpb->SetBaseAddress(vpb->GetLoopAddress()); + src_ptr = (s16*)HLEMemory_Get_Pointer(vpb->GetLoopAddress()); + for (u16 i = vpb->samples_before_loop; i < requested_samples_count; ++i) + *dst++ = Common::swap16(*src_ptr++); + vpb->current_position_h = requested_samples_count - vpb->samples_before_loop; + } + } } void ZeldaAudioRenderer::DoState(PointerWrap& p) { - p.Do(m_flags); - p.Do(m_prepared); + p.Do(m_flags); + p.Do(m_prepared); - p.Do(m_output_lbuf_addr); - p.Do(m_output_rbuf_addr); - p.Do(m_output_volume); + p.Do(m_output_lbuf_addr); + p.Do(m_output_rbuf_addr); + p.Do(m_output_volume); - p.Do(m_buf_front_left); - p.Do(m_buf_front_right); - p.Do(m_buf_back_left); - p.Do(m_buf_back_right); - p.Do(m_buf_front_left_reverb); - p.Do(m_buf_front_right_reverb); - p.Do(m_buf_back_left_reverb); - p.Do(m_buf_back_right_reverb); - p.Do(m_buf_unk0_reverb); - p.Do(m_buf_unk1_reverb); - p.Do(m_buf_unk0); - p.Do(m_buf_unk1); - p.Do(m_buf_unk2); + p.Do(m_buf_front_left); + p.Do(m_buf_front_right); + p.Do(m_buf_back_left); + p.Do(m_buf_back_right); + p.Do(m_buf_front_left_reverb); + p.Do(m_buf_front_right_reverb); + p.Do(m_buf_back_left_reverb); + p.Do(m_buf_back_right_reverb); + p.Do(m_buf_unk0_reverb); + p.Do(m_buf_unk1_reverb); + p.Do(m_buf_unk0); + p.Do(m_buf_unk1); + p.Do(m_buf_unk2); - p.Do(m_resampling_coeffs); - p.Do(m_const_patterns); - p.Do(m_sine_table); - p.Do(m_afc_coeffs); + p.Do(m_resampling_coeffs); + p.Do(m_const_patterns); + p.Do(m_sine_table); + p.Do(m_afc_coeffs); - p.Do(m_aram_base_addr); - p.Do(m_vpb_base_addr); - p.Do(m_reverb_pb_base_addr); + p.Do(m_aram_base_addr); + p.Do(m_vpb_base_addr); + p.Do(m_reverb_pb_base_addr); - p.Do(m_reverb_pb_frames_count); - p.Do(m_buf_unk0_reverb_last8); - p.Do(m_buf_unk1_reverb_last8); - p.Do(m_buf_front_left_reverb_last8); - p.Do(m_buf_front_right_reverb_last8); + p.Do(m_reverb_pb_frames_count); + p.Do(m_buf_unk0_reverb_last8); + p.Do(m_buf_unk1_reverb_last8); + p.Do(m_buf_front_left_reverb_last8); + p.Do(m_buf_front_right_reverb_last8); } diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h index b3e6e7caf5..86a0962f44 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.h @@ -11,286 +11,288 @@ class ZeldaAudioRenderer { public: - void PrepareFrame(); - void AddVoice(u16 voice_id); - void FinalizeFrame(); + void PrepareFrame(); + void AddVoice(u16 voice_id); + void FinalizeFrame(); - void SetFlags(u32 flags) { m_flags = flags; } - void SetSineTable(std::array&& sine_table) { m_sine_table = sine_table; } - void SetConstPatterns(std::array&& patterns) { m_const_patterns = patterns; } - void SetResamplingCoeffs(std::array&& coeffs) { m_resampling_coeffs = coeffs; } - void SetAfcCoeffs(std::array&& coeffs) { m_afc_coeffs = coeffs; } - void SetVPBBaseAddress(u32 addr) { m_vpb_base_addr = addr; } - void SetReverbPBBaseAddress(u32 addr) { m_reverb_pb_base_addr = addr; } - void SetOutputVolume(u16 volume) { m_output_volume = volume; } - void SetOutputLeftBufferAddr(u32 addr) { m_output_lbuf_addr = addr; } - void SetOutputRightBufferAddr(u32 addr) { m_output_rbuf_addr = addr; } - void SetARAMBaseAddr(u32 addr) { m_aram_base_addr = addr; } - - void DoState(PointerWrap& p); + void SetFlags(u32 flags) { m_flags = flags; } + void SetSineTable(std::array&& sine_table) { m_sine_table = sine_table; } + void SetConstPatterns(std::array&& patterns) { m_const_patterns = patterns; } + void SetResamplingCoeffs(std::array&& coeffs) { m_resampling_coeffs = coeffs; } + void SetAfcCoeffs(std::array&& coeffs) { m_afc_coeffs = coeffs; } + void SetVPBBaseAddress(u32 addr) { m_vpb_base_addr = addr; } + void SetReverbPBBaseAddress(u32 addr) { m_reverb_pb_base_addr = addr; } + void SetOutputVolume(u16 volume) { m_output_volume = volume; } + void SetOutputLeftBufferAddr(u32 addr) { m_output_lbuf_addr = addr; } + void SetOutputRightBufferAddr(u32 addr) { m_output_rbuf_addr = addr; } + void SetARAMBaseAddr(u32 addr) { m_aram_base_addr = addr; } + void DoState(PointerWrap& p); private: - struct VPB; + struct VPB; - // See Zelda.cpp for the list of possible flags. - u32 m_flags; + // See Zelda.cpp for the list of possible flags. + u32 m_flags; - // Utility functions for audio operations. + // Utility functions for audio operations. - // Apply volume to a buffer. The volume is a fixed point integer, usually - // 1.15 or 4.12 in the DAC UCode. - template - void ApplyVolumeInPlace(std::array* buf, u16 vol) - { - for (size_t i = 0; i < N; ++i) - { - s32 tmp = (u32)(*buf)[i] * (u32)vol; - tmp >>= 16 - B; + // Apply volume to a buffer. The volume is a fixed point integer, usually + // 1.15 or 4.12 in the DAC UCode. + template + void ApplyVolumeInPlace(std::array* buf, u16 vol) + { + for (size_t i = 0; i < N; ++i) + { + s32 tmp = (u32)(*buf)[i] * (u32)vol; + tmp >>= 16 - B; - (*buf)[i] = (s16)MathUtil::Clamp(tmp, -0x8000, 0x7FFF); - } - } - template - void ApplyVolumeInPlace_1_15(std::array* buf, u16 vol) - { - ApplyVolumeInPlace(buf, vol); - } - template - void ApplyVolumeInPlace_4_12(std::array* buf, u16 vol) - { - ApplyVolumeInPlace(buf, vol); - } + (*buf)[i] = (s16)MathUtil::Clamp(tmp, -0x8000, 0x7FFF); + } + } + template + void ApplyVolumeInPlace_1_15(std::array* buf, u16 vol) + { + ApplyVolumeInPlace(buf, vol); + } + template + void ApplyVolumeInPlace_4_12(std::array* buf, u16 vol) + { + ApplyVolumeInPlace(buf, vol); + } - // Mixes two buffers together while applying a volume to one of them. The - // volume ramps up/down in N steps using the provided step delta value. - // - // Note: On a real GC, the stepping happens in 32 steps instead. But hey, - // we can do better here with very low risk. Why not? :) - template - s32 AddBuffersWithVolumeRamp(std::array* dst, - const std::array& src, - s32 vol, s32 step) - { - if (!vol && !step) - return vol; + // Mixes two buffers together while applying a volume to one of them. The + // volume ramps up/down in N steps using the provided step delta value. + // + // Note: On a real GC, the stepping happens in 32 steps instead. But hey, + // we can do better here with very low risk. Why not? :) + template + s32 AddBuffersWithVolumeRamp(std::array* dst, const std::array& src, s32 vol, + s32 step) + { + if (!vol && !step) + return vol; - for (size_t i = 0; i < N; ++i) - { - (*dst)[i] += ((vol >> 16) * src[i]) >> 16; - vol += step; - } + for (size_t i = 0; i < N; ++i) + { + (*dst)[i] += ((vol >> 16) * src[i]) >> 16; + vol += step; + } - return vol; - } + return vol; + } - // Does not use std::array because it needs to be able to process partial - // buffers. Volume is in 1.15 format. - void AddBuffersWithVolume(s16* dst, const s16* src, size_t count, u16 vol) - { - while (count--) - { - s32 vol_src = ((s32)*src++ * (s32)vol) >> 15; - *dst++ += MathUtil::Clamp(vol_src, -0x8000, 0x7FFF); - } - } + // Does not use std::array because it needs to be able to process partial + // buffers. Volume is in 1.15 format. + void AddBuffersWithVolume(s16* dst, const s16* src, size_t count, u16 vol) + { + while (count--) + { + s32 vol_src = ((s32)*src++ * (s32)vol) >> 15; + *dst++ += MathUtil::Clamp(vol_src, -0x8000, 0x7FFF); + } + } - // Whether the frame needs to be prepared or not. - bool m_prepared = false; + // Whether the frame needs to be prepared or not. + bool m_prepared = false; - // MRAM addresses where output samples should be copied. - u32 m_output_lbuf_addr = 0; - u32 m_output_rbuf_addr = 0; + // MRAM addresses where output samples should be copied. + u32 m_output_lbuf_addr = 0; + u32 m_output_rbuf_addr = 0; - // Output volume applied to buffers before being uploaded to RAM. - u16 m_output_volume = 0; + // Output volume applied to buffers before being uploaded to RAM. + u16 m_output_volume = 0; - // Mixing buffers. - typedef std::array MixingBuffer; - MixingBuffer m_buf_front_left{}; - MixingBuffer m_buf_front_right{}; - MixingBuffer m_buf_back_left{}; - MixingBuffer m_buf_back_right{}; - MixingBuffer m_buf_front_left_reverb{}; - MixingBuffer m_buf_front_right_reverb{}; - MixingBuffer m_buf_back_left_reverb{}; - MixingBuffer m_buf_back_right_reverb{}; - MixingBuffer m_buf_unk0_reverb{}; - MixingBuffer m_buf_unk1_reverb{}; - MixingBuffer m_buf_unk0{}; - MixingBuffer m_buf_unk1{}; - MixingBuffer m_buf_unk2{}; + // Mixing buffers. + typedef std::array MixingBuffer; + MixingBuffer m_buf_front_left{}; + MixingBuffer m_buf_front_right{}; + MixingBuffer m_buf_back_left{}; + MixingBuffer m_buf_back_right{}; + MixingBuffer m_buf_front_left_reverb{}; + MixingBuffer m_buf_front_right_reverb{}; + MixingBuffer m_buf_back_left_reverb{}; + MixingBuffer m_buf_back_right_reverb{}; + MixingBuffer m_buf_unk0_reverb{}; + MixingBuffer m_buf_unk1_reverb{}; + MixingBuffer m_buf_unk0{}; + MixingBuffer m_buf_unk1{}; + MixingBuffer m_buf_unk2{}; - // Maps a buffer "ID" (really, their address in the DSP DRAM...) to our - // buffers. Returns nullptr if no match is found. - MixingBuffer* BufferForID(u16 buffer_id); + // Maps a buffer "ID" (really, their address in the DSP DRAM...) to our + // buffers. Returns nullptr if no match is found. + MixingBuffer* BufferForID(u16 buffer_id); - // Base address where VPBs are stored linearly in RAM. - u32 m_vpb_base_addr; - void FetchVPB(u16 voice_id, VPB* vpb); - void StoreVPB(u16 voice_id, VPB* vpb); + // Base address where VPBs are stored linearly in RAM. + u32 m_vpb_base_addr; + void FetchVPB(u16 voice_id, VPB* vpb); + void StoreVPB(u16 voice_id, VPB* vpb); - // Sine table transferred from MRAM. Contains sin(x) values for x in - // [0.0;pi/4] (sin(x) in [1.0;0.0]), in 1.15 fixed format. - std::array m_sine_table{}; + // Sine table transferred from MRAM. Contains sin(x) values for x in + // [0.0;pi/4] (sin(x) in [1.0;0.0]), in 1.15 fixed format. + std::array m_sine_table{}; - // Const patterns used for some voice samples source. 4 x 0x40 samples. - std::array m_const_patterns{}; + // Const patterns used for some voice samples source. 4 x 0x40 samples. + std::array m_const_patterns{}; - // Fills up a buffer with the input samples for a voice, represented by its - // VPB. - void LoadInputSamples(MixingBuffer* buffer, VPB* vpb); + // Fills up a buffer with the input samples for a voice, represented by its + // VPB. + void LoadInputSamples(MixingBuffer* buffer, VPB* vpb); - // Raw samples (pre-resampling) that need to be generated to result in 0x50 - // post-resampling input samples. - u16 NeededRawSamplesCount(const VPB& vpb); + // Raw samples (pre-resampling) that need to be generated to result in 0x50 + // post-resampling input samples. + u16 NeededRawSamplesCount(const VPB& vpb); - // Resamples raw samples to 0x50 input samples, using the resampling ratio - // and current position information from the VPB. - void Resample(VPB* vpb, const s16* src, MixingBuffer* dst); + // Resamples raw samples to 0x50 input samples, using the resampling ratio + // and current position information from the VPB. + void Resample(VPB* vpb, const s16* src, MixingBuffer* dst); - // Coefficients used for resampling. - std::array m_resampling_coeffs{}; + // Coefficients used for resampling. + std::array m_resampling_coeffs{}; - // If non zero, base MRAM address for sound data transfers from ARAM. On - // the Wii, this points to some MRAM location since there is no ARAM to be - // used. If zero, use the top of ARAM. - u32 m_aram_base_addr = 0; - void* GetARAMPtr() const; + // If non zero, base MRAM address for sound data transfers from ARAM. On + // the Wii, this points to some MRAM location since there is no ARAM to be + // used. If zero, use the top of ARAM. + u32 m_aram_base_addr = 0; + void* GetARAMPtr() const; - // Downloads PCM encoded samples from ARAM. Handles looping and other - // parameters appropriately. - template void DownloadPCMSamplesFromARAM(s16* dst, VPB* vpb, u16 requested_samples_count); + // Downloads PCM encoded samples from ARAM. Handles looping and other + // parameters appropriately. + template + void DownloadPCMSamplesFromARAM(s16* dst, VPB* vpb, u16 requested_samples_count); - // Downloads AFC encoded samples from ARAM and decode them. Handles looping - // and other parameters appropriately. - void DownloadAFCSamplesFromARAM(s16* dst, VPB* vpb, u16 requested_samples_count); - void DecodeAFC(VPB* vpb, s16* dst, size_t block_count); - std::array m_afc_coeffs{}; + // Downloads AFC encoded samples from ARAM and decode them. Handles looping + // and other parameters appropriately. + void DownloadAFCSamplesFromARAM(s16* dst, VPB* vpb, u16 requested_samples_count); + void DecodeAFC(VPB* vpb, s16* dst, size_t block_count); + std::array m_afc_coeffs{}; - // Downloads samples from MRAM while handling appropriate length / looping - // behavior. - void DownloadRawSamplesFromMRAM(s16* dst, VPB* vpb, u16 requested_samples_count); + // Downloads samples from MRAM while handling appropriate length / looping + // behavior. + void DownloadRawSamplesFromMRAM(s16* dst, VPB* vpb, u16 requested_samples_count); - // Applies the reverb effect to Dolby mixed voices based on a set of - // per-buffer parameters. Is called twice: once before frame rendering and - // once after. - void ApplyReverb(bool post_rendering); - std::array m_reverb_pb_frames_count{}; - std::array m_buf_unk0_reverb_last8{}; - std::array m_buf_unk1_reverb_last8{}; - std::array m_buf_front_left_reverb_last8{}; - std::array m_buf_front_right_reverb_last8{}; - u32 m_reverb_pb_base_addr = 0; + // Applies the reverb effect to Dolby mixed voices based on a set of + // per-buffer parameters. Is called twice: once before frame rendering and + // once after. + void ApplyReverb(bool post_rendering); + std::array m_reverb_pb_frames_count{}; + std::array m_buf_unk0_reverb_last8{}; + std::array m_buf_unk1_reverb_last8{}; + std::array m_buf_front_left_reverb_last8{}; + std::array m_buf_front_right_reverb_last8{}; + u32 m_reverb_pb_base_addr = 0; }; class ZeldaUCode : public UCodeInterface { public: - ZeldaUCode(DSPHLE *dsphle, u32 crc); - virtual ~ZeldaUCode(); + ZeldaUCode(DSPHLE* dsphle, u32 crc); + virtual ~ZeldaUCode(); - void HandleMail(u32 mail) override; - void Update() override; + void HandleMail(u32 mail) override; + void Update() override; - void DoState(PointerWrap &p) override; + void DoState(PointerWrap& p) override; private: - // Flags that alter the behavior of the UCode. See Zelda.cpp for complete - // list and explanation. - u32 m_flags; + // Flags that alter the behavior of the UCode. See Zelda.cpp for complete + // list and explanation. + u32 m_flags; - // Different mail handlers for different protocols. - void HandleMailDefault(u32 mail); - void HandleMailLight(u32 mail); + // Different mail handlers for different protocols. + void HandleMailDefault(u32 mail); + void HandleMailLight(u32 mail); - // UCode state machine. The control flow in the Zelda UCode family is quite - // complex, using interrupt handlers heavily to handle incoming messages - // which, depending on the type, get handled immediately or are queued in a - // command buffer. In this implementation, the synchronous+interrupts flow - // of the original DSP implementation is rewritten in an asynchronous/coro - // + state machine style. It is less readable, but the best we can do given - // our constraints. - enum class MailState : u32 - { - WAITING, - RENDERING, - WRITING_CMD, - HALTED, - }; - MailState m_mail_current_state = MailState::WAITING; - u32 m_mail_expected_cmd_mails = 0; + // UCode state machine. The control flow in the Zelda UCode family is quite + // complex, using interrupt handlers heavily to handle incoming messages + // which, depending on the type, get handled immediately or are queued in a + // command buffer. In this implementation, the synchronous+interrupts flow + // of the original DSP implementation is rewritten in an asynchronous/coro + // + state machine style. It is less readable, but the best we can do given + // our constraints. + enum class MailState : u32 + { + WAITING, + RENDERING, + WRITING_CMD, + HALTED, + }; + MailState m_mail_current_state = MailState::WAITING; + u32 m_mail_expected_cmd_mails = 0; - // Utility function to set the current state. Useful for debugging and - // logging as a hook point. - void SetMailState(MailState new_state) - { - // WARN_LOG(DSPHLE, "MailState %d -> %d", m_mail_current_state, new_state); - m_mail_current_state = new_state; - } + // Utility function to set the current state. Useful for debugging and + // logging as a hook point. + void SetMailState(MailState new_state) + { + // WARN_LOG(DSPHLE, "MailState %d -> %d", m_mail_current_state, new_state); + m_mail_current_state = new_state; + } - // Voice synchronization / audio rendering flow control. When rendering an - // audio frame, only voices up to max_voice_id will be rendered until a - // sync mail arrives, increasing the value of max_voice_id. Additionally, - // these sync mails contain 16 bit values that are used as bitfields to - // control voice skipping on a voice per voice level. - u32 m_sync_max_voice_id = 0; - std::array m_sync_voice_skip_flags{}; - bool m_sync_flags_second_half = false; + // Voice synchronization / audio rendering flow control. When rendering an + // audio frame, only voices up to max_voice_id will be rendered until a + // sync mail arrives, increasing the value of max_voice_id. Additionally, + // these sync mails contain 16 bit values that are used as bitfields to + // control voice skipping on a voice per voice level. + u32 m_sync_max_voice_id = 0; + std::array m_sync_voice_skip_flags{}; + bool m_sync_flags_second_half = false; - // Command buffer (circular queue with r/w indices). Filled by HandleMail - // when the state machine is in WRITING_CMD state. Commands get executed - // when entering WAITING state and we are not rendering audio. - std::array m_cmd_buffer{}; - u32 m_read_offset = 0; - u32 m_write_offset = 0; - u32 m_pending_commands_count = 0; - bool m_cmd_can_execute = true; + // Command buffer (circular queue with r/w indices). Filled by HandleMail + // when the state machine is in WRITING_CMD state. Commands get executed + // when entering WAITING state and we are not rendering audio. + std::array m_cmd_buffer{}; + u32 m_read_offset = 0; + u32 m_write_offset = 0; + u32 m_pending_commands_count = 0; + bool m_cmd_can_execute = true; - // Reads a 32 bit value from the command buffer. Advances the read pointer. - u32 Read32() - { - if (m_read_offset == m_write_offset) - { - ERROR_LOG(DSPHLE, "Reading too many command params"); - return 0; - } + // Reads a 32 bit value from the command buffer. Advances the read pointer. + u32 Read32() + { + if (m_read_offset == m_write_offset) + { + ERROR_LOG(DSPHLE, "Reading too many command params"); + return 0; + } - u32 res = m_cmd_buffer[m_read_offset]; - m_read_offset = (m_read_offset + 1) % (sizeof (m_cmd_buffer) / sizeof (u32)); - return res; - } + u32 res = m_cmd_buffer[m_read_offset]; + m_read_offset = (m_read_offset + 1) % (sizeof(m_cmd_buffer) / sizeof(u32)); + return res; + } - // Writes a 32 bit value to the command buffer. Advances the write pointer. - void Write32(u32 val) - { - m_cmd_buffer[m_write_offset] = val; - m_write_offset = (m_write_offset + 1) % (sizeof (m_cmd_buffer) / sizeof (u32)); - } + // Writes a 32 bit value to the command buffer. Advances the write pointer. + void Write32(u32 val) + { + m_cmd_buffer[m_write_offset] = val; + m_write_offset = (m_write_offset + 1) % (sizeof(m_cmd_buffer) / sizeof(u32)); + } - // Tries to run as many commands as possible until either the command - // buffer is empty (pending_commands == 0) or we reached a long lived - // command that needs to hijack the mail control flow. - // - // Might change the current state to indicate crashy commands. - void RunPendingCommands(); + // Tries to run as many commands as possible until either the command + // buffer is empty (pending_commands == 0) or we reached a long lived + // command that needs to hijack the mail control flow. + // + // Might change the current state to indicate crashy commands. + void RunPendingCommands(); - // Sends the two mails from DSP to CPU to ack the command execution. - enum class CommandAck : u32 - { - STANDARD, - DONE_RENDERING, - }; - void SendCommandAck(CommandAck ack_type, u16 sync_value); + // Sends the two mails from DSP to CPU to ack the command execution. + enum class CommandAck : u32 + { + STANDARD, + DONE_RENDERING, + }; + void SendCommandAck(CommandAck ack_type, u16 sync_value); - // Audio rendering flow control state. - u32 m_rendering_requested_frames = 0; - u16 m_rendering_voices_per_frame = 0; - u32 m_rendering_curr_frame = 0; - u32 m_rendering_curr_voice = 0; + // Audio rendering flow control state. + u32 m_rendering_requested_frames = 0; + u16 m_rendering_voices_per_frame = 0; + u32 m_rendering_curr_frame = 0; + u32 m_rendering_curr_voice = 0; - bool RenderingInProgress() const { return m_rendering_curr_frame != m_rendering_requested_frames; } - void RenderAudio(); + bool RenderingInProgress() const + { + return m_rendering_curr_frame != m_rendering_requested_frames; + } + void RenderAudio(); - // Main object handling audio rendering logic and state. - ZeldaAudioRenderer m_renderer; + // Main object handling audio rendering logic and state. + ZeldaAudioRenderer m_renderer; }; diff --git a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp index 7fe5ed7d38..4165581a65 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp +++ b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.cpp @@ -12,135 +12,134 @@ std::string DSPDebugInterface::Disassemble(unsigned int address) { - // we'll treat addresses as line numbers. - return DSPSymbols::GetLineText(address); + // we'll treat addresses as line numbers. + return DSPSymbols::GetLineText(address); } -void DSPDebugInterface::GetRawMemoryString(int memory, unsigned int address, char *dest, int max_size) +void DSPDebugInterface::GetRawMemoryString(int memory, unsigned int address, char* dest, + int max_size) { - if (DSPCore_GetState() == DSPCORE_STOP) - { - dest[0] = 0; - return; - } + if (DSPCore_GetState() == DSPCORE_STOP) + { + dest[0] = 0; + return; + } - switch (memory) - { - case 0: // IMEM - switch (address >> 12) - { - case 0: - case 0x8: - sprintf(dest, "%04x", dsp_imem_read(address)); - break; - default: - sprintf(dest, "--IMEM--"); - break; - } - break; - case 1: // DMEM - switch (address >> 12) - { - case 0: - case 1: - sprintf(dest, "%04x (DMEM)", dsp_dmem_read(address)); - break; - case 0xf: - sprintf(dest, "%04x (MMIO)", g_dsp.ifx_regs[address & 0xFF]); - break; - default: - sprintf(dest, "--DMEM--"); - break; - } - break; - } + switch (memory) + { + case 0: // IMEM + switch (address >> 12) + { + case 0: + case 0x8: + sprintf(dest, "%04x", dsp_imem_read(address)); + break; + default: + sprintf(dest, "--IMEM--"); + break; + } + break; + case 1: // DMEM + switch (address >> 12) + { + case 0: + case 1: + sprintf(dest, "%04x (DMEM)", dsp_dmem_read(address)); + break; + case 0xf: + sprintf(dest, "%04x (MMIO)", g_dsp.ifx_regs[address & 0xFF]); + break; + default: + sprintf(dest, "--DMEM--"); + break; + } + break; + } } unsigned int DSPDebugInterface::ReadMemory(unsigned int address) { - return 0; + return 0; } unsigned int DSPDebugInterface::ReadInstruction(unsigned int address) { - return 0; + return 0; } bool DSPDebugInterface::IsAlive() { - return true; //Core::GetState() != Core::CORE_UNINITIALIZED; + return true; // Core::GetState() != Core::CORE_UNINITIALIZED; } bool DSPDebugInterface::IsBreakpoint(unsigned int address) { - int real_addr = DSPSymbols::Line2Addr(address); - if (real_addr >= 0) - return g_dsp_breakpoints.IsAddressBreakPoint(real_addr); + int real_addr = DSPSymbols::Line2Addr(address); + if (real_addr >= 0) + return g_dsp_breakpoints.IsAddressBreakPoint(real_addr); - return false; + return false; } void DSPDebugInterface::SetBreakpoint(unsigned int address) { - int real_addr = DSPSymbols::Line2Addr(address); + int real_addr = DSPSymbols::Line2Addr(address); - if (real_addr >= 0) - { - if (g_dsp_breakpoints.Add(real_addr)) - { - - } - } + if (real_addr >= 0) + { + if (g_dsp_breakpoints.Add(real_addr)) + { + } + } } void DSPDebugInterface::ClearBreakpoint(unsigned int address) { - int real_addr = DSPSymbols::Line2Addr(address); + int real_addr = DSPSymbols::Line2Addr(address); - if (real_addr >= 0) - { - if (g_dsp_breakpoints.Remove(real_addr)) - { - - } - } + if (real_addr >= 0) + { + if (g_dsp_breakpoints.Remove(real_addr)) + { + } + } } void DSPDebugInterface::ClearAllBreakpoints() { - g_dsp_breakpoints.Clear(); + g_dsp_breakpoints.Clear(); } void DSPDebugInterface::ToggleBreakpoint(unsigned int address) { - int real_addr = DSPSymbols::Line2Addr(address); - if (real_addr >= 0) - { - if (g_dsp_breakpoints.IsAddressBreakPoint(real_addr)) - g_dsp_breakpoints.Remove(real_addr); - else - g_dsp_breakpoints.Add(real_addr); - } + int real_addr = DSPSymbols::Line2Addr(address); + if (real_addr >= 0) + { + if (g_dsp_breakpoints.IsAddressBreakPoint(real_addr)) + g_dsp_breakpoints.Remove(real_addr); + else + g_dsp_breakpoints.Add(real_addr); + } } bool DSPDebugInterface::IsMemCheck(unsigned int address) { - return false; + return false; } void DSPDebugInterface::ClearAllMemChecks() { - PanicAlert("MemCheck functionality not supported in DSP module."); + PanicAlert("MemCheck functionality not supported in DSP module."); } void DSPDebugInterface::ToggleMemCheck(unsigned int address) { - PanicAlert("MemCheck functionality not supported in DSP module."); + PanicAlert("MemCheck functionality not supported in DSP module."); } void DSPDebugInterface::InsertBLR(unsigned int address, unsigned int value) { - PanicAlert("insertBLR functionality not supported in DSP module."); + PanicAlert("insertBLR functionality not supported in DSP module."); } // ======================================================= @@ -148,55 +147,52 @@ void DSPDebugInterface::InsertBLR(unsigned int address, unsigned int value) // ------------- int DSPDebugInterface::GetColor(unsigned int address) { - static const int colors[6] = - { - 0xd0FFFF, // light cyan - 0xFFd0d0, // light red - 0xd8d8FF, // light blue - 0xFFd0FF, // light purple - 0xd0FFd0, // light green - 0xFFFFd0, // light yellow - }; + static const int colors[6] = { + 0xd0FFFF, // light cyan + 0xFFd0d0, // light red + 0xd8d8FF, // light blue + 0xFFd0FF, // light purple + 0xd0FFd0, // light green + 0xFFFFd0, // light yellow + }; - // Scan backwards so we don't miss it. Hm, actually, let's not - it looks pretty good. - int addr = -1; - for (int i = 0; i < 1; i++) - { - addr = DSPSymbols::Line2Addr(address - i); - if (addr >= 0) - break; - } - if (addr == -1) - return 0xFFFFFF; + // Scan backwards so we don't miss it. Hm, actually, let's not - it looks pretty good. + int addr = -1; + for (int i = 0; i < 1; i++) + { + addr = DSPSymbols::Line2Addr(address - i); + if (addr >= 0) + break; + } + if (addr == -1) + return 0xFFFFFF; - Symbol *symbol = DSPSymbols::g_dsp_symbol_db.GetSymbolFromAddr(addr); - if (!symbol) - return 0xFFFFFF; - if (symbol->type != Symbol::SYMBOL_FUNCTION) - return 0xEEEEFF; - return colors[symbol->index % 6]; + Symbol* symbol = DSPSymbols::g_dsp_symbol_db.GetSymbolFromAddr(addr); + if (!symbol) + return 0xFFFFFF; + if (symbol->type != Symbol::SYMBOL_FUNCTION) + return 0xEEEEFF; + return colors[symbol->index % 6]; } // ============= - std::string DSPDebugInterface::GetDescription(unsigned int address) { - return ""; // g_symbolDB.GetDescription(address); + return ""; // g_symbolDB.GetDescription(address); } unsigned int DSPDebugInterface::GetPC() { - return DSPSymbols::Addr2Line(g_dsp.pc); + return DSPSymbols::Addr2Line(g_dsp.pc); } void DSPDebugInterface::SetPC(unsigned int address) { - int new_pc = DSPSymbols::Line2Addr(address); - if (new_pc > 0) - g_dsp.pc = new_pc; + int new_pc = DSPSymbols::Line2Addr(address); + if (new_pc > 0) + g_dsp.pc = new_pc; } void DSPDebugInterface::RunToBreakpoint() { - } diff --git a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h index b8bdd83e5c..cb71639617 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h +++ b/Source/Core/Core/HW/DSPLLE/DSPDebugInterface.h @@ -12,27 +12,26 @@ class DSPDebugInterface final : public DebugInterface { public: - DSPDebugInterface() {} - - std::string Disassemble(unsigned int address) override; - void GetRawMemoryString(int memory, unsigned int address, char *dest, int max_size) override; - int GetInstructionSize(int instruction) override { return 1; } - bool IsAlive() override; - bool IsBreakpoint(unsigned int address) override; - void SetBreakpoint(unsigned int address) override; - void ClearBreakpoint(unsigned int address) override; - void ClearAllBreakpoints() override; - void ToggleBreakpoint(unsigned int address) override; - void ClearAllMemChecks() override; - bool IsMemCheck(unsigned int address) override; - void ToggleMemCheck(unsigned int address) override; - unsigned int ReadMemory(unsigned int address) override; - unsigned int ReadInstruction(unsigned int address) override; - unsigned int GetPC() override; - void SetPC(unsigned int address) override; - void Step() override {} - void RunToBreakpoint() override; - void InsertBLR(unsigned int address, unsigned int value) override; - int GetColor(unsigned int address) override; - std::string GetDescription(unsigned int address) override; + DSPDebugInterface() {} + std::string Disassemble(unsigned int address) override; + void GetRawMemoryString(int memory, unsigned int address, char* dest, int max_size) override; + int GetInstructionSize(int instruction) override { return 1; } + bool IsAlive() override; + bool IsBreakpoint(unsigned int address) override; + void SetBreakpoint(unsigned int address) override; + void ClearBreakpoint(unsigned int address) override; + void ClearAllBreakpoints() override; + void ToggleBreakpoint(unsigned int address) override; + void ClearAllMemChecks() override; + bool IsMemCheck(unsigned int address) override; + void ToggleMemCheck(unsigned int address) override; + unsigned int ReadMemory(unsigned int address) override; + unsigned int ReadInstruction(unsigned int address) override; + unsigned int GetPC() override; + void SetPC(unsigned int address) override; + void Step() override {} + void RunToBreakpoint() override; + void InsertBLR(unsigned int address, unsigned int value) override; + int GetColor(unsigned int address) override; + std::string GetDescription(unsigned int address) override; }; diff --git a/Source/Core/Core/HW/DSPLLE/DSPHost.cpp b/Source/Core/Core/HW/DSPLLE/DSPHost.cpp index fc5ad5c1fe..83b50bc60a 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPHost.cpp +++ b/Source/Core/Core/HW/DSPLLE/DSPHost.cpp @@ -2,17 +2,17 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/DSP/DSPHost.h" #include "Common/CommonTypes.h" #include "Common/Hash.h" #include "Common/Logging/Log.h" #include "Core/ConfigManager.h" -#include "Core/Host.h" #include "Core/DSP/DSPAnalyzer.h" #include "Core/DSP/DSPCore.h" -#include "Core/DSP/DSPHost.h" #include "Core/HW/DSP.h" #include "Core/HW/DSPLLE/DSPLLETools.h" #include "Core/HW/DSPLLE/DSPSymbols.h" +#include "Core/Host.h" #include "VideoCommon/OnScreenDisplay.h" // The user of the DSPCore library must supply a few functions so that the @@ -22,88 +22,108 @@ namespace DSPHost { - u8 ReadHostMemory(u32 addr) { - return DSP::ReadARAM(addr); + return DSP::ReadARAM(addr); } void WriteHostMemory(u8 value, u32 addr) { - DSP::WriteARAM(value, addr); + DSP::WriteARAM(value, addr); } void OSD_AddMessage(const std::string& str, u32 ms) { - OSD::AddMessage(str, ms); + OSD::AddMessage(str, ms); } bool OnThread() { - return SConfig::GetInstance().bDSPThread; + return SConfig::GetInstance().bDSPThread; } bool IsWiiHost() { - return SConfig::GetInstance().bWii; + return SConfig::GetInstance().bWii; } void InterruptRequest() { - // Fire an interrupt on the PPC ASAP. - DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + // Fire an interrupt on the PPC ASAP. + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); } -void CodeLoaded(const u8 *ptr, int size) +void CodeLoaded(const u8* ptr, int size) { - g_dsp.iram_crc = HashEctor(ptr, size); + g_dsp.iram_crc = HashEctor(ptr, size); #if defined(_DEBUG) || defined(DEBUGFAST) - DumpDSPCode(ptr, size, g_dsp.iram_crc); + DumpDSPCode(ptr, size, g_dsp.iram_crc); #endif - DSPSymbols::Clear(); + DSPSymbols::Clear(); - // Auto load text file - if none just disassemble. + // Auto load text file - if none just disassemble. - NOTICE_LOG(DSPLLE, "g_dsp.iram_crc: %08x", g_dsp.iram_crc); + NOTICE_LOG(DSPLLE, "g_dsp.iram_crc: %08x", g_dsp.iram_crc); - DSPSymbols::Clear(); - bool success = false; - switch (g_dsp.iram_crc) - { - case 0x86840740: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_Zelda.txt"); break; - case 0x42f64ac4: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_Luigi.txt"); break; - case 0x07f88145: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AX_07F88145.txt"); break; - case 0x3ad3b7ac: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AX_3AD3B7AC.txt"); break; - case 0x3daf59b9: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AX_3DAF59B9.txt"); break; - case 0x4e8a8b21: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AX_4E8A8B21.txt"); break; - case 0xe2136399: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AX_E2136399.txt"); break; - case 0xdd7e72d5: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_GBA.txt"); break; - case 0x347112BA: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AXWii.txt"); break; - case 0xD643001F: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_SuperMarioGalaxy.txt"); break; - default: success = false; break; - } + DSPSymbols::Clear(); + bool success = false; + switch (g_dsp.iram_crc) + { + case 0x86840740: + success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_Zelda.txt"); + break; + case 0x42f64ac4: + success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_Luigi.txt"); + break; + case 0x07f88145: + success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AX_07F88145.txt"); + break; + case 0x3ad3b7ac: + success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AX_3AD3B7AC.txt"); + break; + case 0x3daf59b9: + success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AX_3DAF59B9.txt"); + break; + case 0x4e8a8b21: + success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AX_4E8A8B21.txt"); + break; + case 0xe2136399: + success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AX_E2136399.txt"); + break; + case 0xdd7e72d5: + success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_GBA.txt"); + break; + case 0x347112BA: + success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AXWii.txt"); + break; + case 0xD643001F: + success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_SuperMarioGalaxy.txt"); + break; + default: + success = false; + break; + } - if (!success) - { - DSPSymbols::AutoDisassembly(0x0, 0x1000); - } + if (!success) + { + DSPSymbols::AutoDisassembly(0x0, 0x1000); + } - // Always add the ROM. - DSPSymbols::AutoDisassembly(0x8000, 0x9000); + // Always add the ROM. + DSPSymbols::AutoDisassembly(0x8000, 0x9000); - UpdateDebugger(); + UpdateDebugger(); - if (g_dsp_jit) - g_dsp_jit->ClearIRAM(); + if (g_dsp_jit) + g_dsp_jit->ClearIRAM(); - DSPAnalyzer::Analyze(); + DSPAnalyzer::Analyze(); } void UpdateDebugger() { - Host_RefreshDSPDebuggerWindow(); + Host_RefreshDSPDebuggerWindow(); } - } diff --git a/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp b/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp index 32e3bbca50..70146c1eac 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp +++ b/Source/Core/Core/HW/DSPLLE/DSPLLE.cpp @@ -11,30 +11,26 @@ #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" #include "Common/Event.h" -#include "Common/Thread.h" #include "Common/Logging/Log.h" +#include "Common/Thread.h" #include "Core/ConfigManager.h" #include "Core/Core.h" +#include "Core/DSP/DSPCaptureLogger.h" +#include "Core/DSP/DSPCore.h" +#include "Core/DSP/DSPHWInterface.h" +#include "Core/DSP/DSPHost.h" +#include "Core/DSP/DSPInterpreter.h" +#include "Core/DSP/DSPTables.h" +#include "Core/HW/DSPLLE/DSPLLE.h" +#include "Core/HW/DSPLLE/DSPLLEGlobals.h" +#include "Core/HW/Memmap.h" #include "Core/Host.h" #include "Core/Movie.h" #include "Core/NetPlayProto.h" -#include "Core/DSP/DSPCaptureLogger.h" -#include "Core/DSP/DSPCore.h" -#include "Core/DSP/DSPHost.h" -#include "Core/DSP/DSPHWInterface.h" -#include "Core/DSP/DSPInterpreter.h" -#include "Core/DSP/DSPTables.h" -#include "Core/HW/Memmap.h" -#include "Core/HW/DSPLLE/DSPLLE.h" -#include "Core/HW/DSPLLE/DSPLLEGlobals.h" DSPLLE::DSPLLE() - : m_hDSPThread() - , m_csDSPThreadActive() - , m_bWii(false) - , m_bDSPThread(false) - , m_bIsRunning(false) - , m_cycle_count(0) + : m_hDSPThread(), m_csDSPThreadActive(), m_bWii(false), m_bDSPThread(false), + m_bIsRunning(false), m_cycle_count(0) { } @@ -42,310 +38,312 @@ static Common::Event dspEvent; static Common::Event ppcEvent; static bool requestDisableThread; -void DSPLLE::DoState(PointerWrap &p) +void DSPLLE::DoState(PointerWrap& p) { - bool is_hle = false; - p.Do(is_hle); - if (is_hle && p.GetMode() == PointerWrap::MODE_READ) - { - Core::DisplayMessage("State is incompatible with current DSP engine. Aborting load state.", 3000); - p.SetMode(PointerWrap::MODE_VERIFY); - return; - } - p.Do(g_dsp.r); - p.Do(g_dsp.pc); + bool is_hle = false; + p.Do(is_hle); + if (is_hle && p.GetMode() == PointerWrap::MODE_READ) + { + Core::DisplayMessage("State is incompatible with current DSP engine. Aborting load state.", + 3000); + p.SetMode(PointerWrap::MODE_VERIFY); + return; + } + p.Do(g_dsp.r); + p.Do(g_dsp.pc); #if PROFILE - p.Do(g_dsp.err_pc); + p.Do(g_dsp.err_pc); #endif - p.Do(g_dsp.cr); - p.Do(g_dsp.reg_stack_ptr); - p.Do(g_dsp.exceptions); - p.Do(g_dsp.external_interrupt_waiting); + p.Do(g_dsp.cr); + p.Do(g_dsp.reg_stack_ptr); + p.Do(g_dsp.exceptions); + p.Do(g_dsp.external_interrupt_waiting); - for (int i = 0; i < 4; i++) - { - p.Do(g_dsp.reg_stack[i]); - } + for (int i = 0; i < 4; i++) + { + p.Do(g_dsp.reg_stack[i]); + } - p.Do(g_dsp.step_counter); - p.DoArray(g_dsp.ifx_regs); - p.Do(g_dsp.mbox[0]); - p.Do(g_dsp.mbox[1]); - UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); - p.DoArray(g_dsp.iram, DSP_IRAM_SIZE); - WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); - if (p.GetMode() == PointerWrap::MODE_READ) - DSPHost::CodeLoaded((const u8*)g_dsp.iram, DSP_IRAM_BYTE_SIZE); - p.DoArray(g_dsp.dram, DSP_DRAM_SIZE); - p.Do(g_cycles_left); - p.Do(g_init_hax); - p.Do(m_cycle_count); + p.Do(g_dsp.step_counter); + p.DoArray(g_dsp.ifx_regs); + p.Do(g_dsp.mbox[0]); + p.Do(g_dsp.mbox[1]); + UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); + p.DoArray(g_dsp.iram, DSP_IRAM_SIZE); + WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); + if (p.GetMode() == PointerWrap::MODE_READ) + DSPHost::CodeLoaded((const u8*)g_dsp.iram, DSP_IRAM_BYTE_SIZE); + p.DoArray(g_dsp.dram, DSP_DRAM_SIZE); + p.Do(g_cycles_left); + p.Do(g_init_hax); + p.Do(m_cycle_count); } // Regular thread void DSPLLE::DSPThread(DSPLLE* dsp_lle) { - Common::SetCurrentThreadName("DSP thread"); + Common::SetCurrentThreadName("DSP thread"); - while (dsp_lle->m_bIsRunning.IsSet()) - { - const int cycles = static_cast(dsp_lle->m_cycle_count.load()); - if (cycles > 0) - { - std::lock_guard dsp_thread_lock(dsp_lle->m_csDSPThreadActive); - if (g_dsp_jit) - { - DSPCore_RunCycles(cycles); - } - else - { - DSPInterpreter::RunCyclesThread(cycles); - } - dsp_lle->m_cycle_count.store(0); - } - else - { - ppcEvent.Set(); - dspEvent.Wait(); - } - } + while (dsp_lle->m_bIsRunning.IsSet()) + { + const int cycles = static_cast(dsp_lle->m_cycle_count.load()); + if (cycles > 0) + { + std::lock_guard dsp_thread_lock(dsp_lle->m_csDSPThreadActive); + if (g_dsp_jit) + { + DSPCore_RunCycles(cycles); + } + else + { + DSPInterpreter::RunCyclesThread(cycles); + } + dsp_lle->m_cycle_count.store(0); + } + else + { + ppcEvent.Set(); + dspEvent.Wait(); + } + } } static bool LoadDSPRom(u16* rom, const std::string& filename, u32 size_in_bytes) { - std::string bytes; - if (!File::ReadFileToString(filename, bytes)) - return false; + std::string bytes; + if (!File::ReadFileToString(filename, bytes)) + return false; - if (bytes.size() != size_in_bytes) - { - ERROR_LOG(DSPLLE, "%s has a wrong size (%zu, expected %u)", - filename.c_str(), bytes.size(), size_in_bytes); - return false; - } + if (bytes.size() != size_in_bytes) + { + ERROR_LOG(DSPLLE, "%s has a wrong size (%zu, expected %u)", filename.c_str(), bytes.size(), + size_in_bytes); + return false; + } - const u16* words = reinterpret_cast(bytes.c_str()); - for (u32 i = 0; i < size_in_bytes / 2; ++i) - rom[i] = Common::swap16(words[i]); + const u16* words = reinterpret_cast(bytes.c_str()); + for (u32 i = 0; i < size_in_bytes / 2; ++i) + rom[i] = Common::swap16(words[i]); - return true; + return true; } static bool FillDSPInitOptions(DSPInitOptions* opts) { - std::string irom_file = File::GetUserPath(D_GCUSER_IDX) + DSP_IROM; - std::string coef_file = File::GetUserPath(D_GCUSER_IDX) + DSP_COEF; + std::string irom_file = File::GetUserPath(D_GCUSER_IDX) + DSP_IROM; + std::string coef_file = File::GetUserPath(D_GCUSER_IDX) + DSP_COEF; - if (!File::Exists(irom_file)) - irom_file = File::GetSysDirectory() + GC_SYS_DIR DIR_SEP DSP_IROM; - if (!File::Exists(coef_file)) - coef_file = File::GetSysDirectory() + GC_SYS_DIR DIR_SEP DSP_COEF; + if (!File::Exists(irom_file)) + irom_file = File::GetSysDirectory() + GC_SYS_DIR DIR_SEP DSP_IROM; + if (!File::Exists(coef_file)) + coef_file = File::GetSysDirectory() + GC_SYS_DIR DIR_SEP DSP_COEF; - if (!LoadDSPRom(opts->irom_contents.data(), irom_file, DSP_IROM_BYTE_SIZE)) - return false; - if (!LoadDSPRom(opts->coef_contents.data(), coef_file, DSP_COEF_BYTE_SIZE)) - return false; + if (!LoadDSPRom(opts->irom_contents.data(), irom_file, DSP_IROM_BYTE_SIZE)) + return false; + if (!LoadDSPRom(opts->coef_contents.data(), coef_file, DSP_COEF_BYTE_SIZE)) + return false; - opts->core_type = SConfig::GetInstance().m_DSPEnableJIT ? - DSPInitOptions::CORE_JIT : DSPInitOptions::CORE_INTERPRETER; + opts->core_type = SConfig::GetInstance().m_DSPEnableJIT ? DSPInitOptions::CORE_JIT : + DSPInitOptions::CORE_INTERPRETER; - if (SConfig::GetInstance().m_DSPCaptureLog) - { - const std::string pcap_path = File::GetUserPath(D_DUMPDSP_IDX) + "dsp.pcap"; - opts->capture_logger = new PCAPDSPCaptureLogger(pcap_path); - } + if (SConfig::GetInstance().m_DSPCaptureLog) + { + const std::string pcap_path = File::GetUserPath(D_DUMPDSP_IDX) + "dsp.pcap"; + opts->capture_logger = new PCAPDSPCaptureLogger(pcap_path); + } - return true; + return true; } bool DSPLLE::Initialize(bool bWii, bool bDSPThread) { - requestDisableThread = false; + requestDisableThread = false; - DSPInitOptions opts; - if (!FillDSPInitOptions(&opts)) - return false; - if (!DSPCore_Init(opts)) - return false; + DSPInitOptions opts; + if (!FillDSPInitOptions(&opts)) + return false; + if (!DSPCore_Init(opts)) + return false; - // needs to be after DSPCore_Init for the dspjit ptr - if (NetPlay::IsNetPlayRunning() || Movie::IsMovieActive() || - Core::g_want_determinism || !g_dsp_jit) - { - bDSPThread = false; - } - m_bWii = bWii; - m_bDSPThread = bDSPThread; + // needs to be after DSPCore_Init for the dspjit ptr + if (NetPlay::IsNetPlayRunning() || Movie::IsMovieActive() || Core::g_want_determinism || + !g_dsp_jit) + { + bDSPThread = false; + } + m_bWii = bWii; + m_bDSPThread = bDSPThread; - // DSPLLE directly accesses the fastmem arena. - // TODO: The fastmem arena is only supposed to be used by the JIT: - // among other issues, its size is only 1GB on 32-bit targets. - g_dsp.cpu_ram = Memory::physical_base; - DSPCore_Reset(); + // DSPLLE directly accesses the fastmem arena. + // TODO: The fastmem arena is only supposed to be used by the JIT: + // among other issues, its size is only 1GB on 32-bit targets. + g_dsp.cpu_ram = Memory::physical_base; + DSPCore_Reset(); - InitInstructionTable(); + InitInstructionTable(); - if (bDSPThread) - { - m_bIsRunning.Set(true); - m_hDSPThread = std::thread(DSPThread, this); - } + if (bDSPThread) + { + m_bIsRunning.Set(true); + m_hDSPThread = std::thread(DSPThread, this); + } - Host_RefreshDSPDebuggerWindow(); - return true; + Host_RefreshDSPDebuggerWindow(); + return true; } void DSPLLE::DSP_StopSoundStream() { - if (m_bDSPThread) - { - m_bIsRunning.Clear(); - ppcEvent.Set(); - dspEvent.Set(); - m_hDSPThread.join(); - } + if (m_bDSPThread) + { + m_bIsRunning.Clear(); + ppcEvent.Set(); + dspEvent.Set(); + m_hDSPThread.join(); + } } void DSPLLE::Shutdown() { - DSPCore_Shutdown(); + DSPCore_Shutdown(); } u16 DSPLLE::DSP_WriteControlRegister(u16 _uFlag) { - DSPInterpreter::WriteCR(_uFlag); + DSPInterpreter::WriteCR(_uFlag); - if (_uFlag & 2) - { - if (!m_bDSPThread) - { - DSPCore_CheckExternalInterrupt(); - DSPCore_CheckExceptions(); - } - else - { - // External interrupt pending: this is the zelda ucode. - // Disable the DSP thread because there is no performance gain. - requestDisableThread = true; + if (_uFlag & 2) + { + if (!m_bDSPThread) + { + DSPCore_CheckExternalInterrupt(); + DSPCore_CheckExceptions(); + } + else + { + // External interrupt pending: this is the zelda ucode. + // Disable the DSP thread because there is no performance gain. + requestDisableThread = true; - DSPCore_SetExternalInterrupt(true); - } + DSPCore_SetExternalInterrupt(true); + } + } - } - - return DSPInterpreter::ReadCR(); + return DSPInterpreter::ReadCR(); } u16 DSPLLE::DSP_ReadControlRegister() { - return DSPInterpreter::ReadCR(); + return DSPInterpreter::ReadCR(); } u16 DSPLLE::DSP_ReadMailBoxHigh(bool _CPUMailbox) { - return gdsp_mbox_read_h(_CPUMailbox ? MAILBOX_CPU : MAILBOX_DSP); + return gdsp_mbox_read_h(_CPUMailbox ? MAILBOX_CPU : MAILBOX_DSP); } u16 DSPLLE::DSP_ReadMailBoxLow(bool _CPUMailbox) { - return gdsp_mbox_read_l(_CPUMailbox ? MAILBOX_CPU : MAILBOX_DSP); + return gdsp_mbox_read_l(_CPUMailbox ? MAILBOX_CPU : MAILBOX_DSP); } void DSPLLE::DSP_WriteMailBoxHigh(bool _CPUMailbox, u16 _uHighMail) { - if (_CPUMailbox) - { - if (gdsp_mbox_peek(MAILBOX_CPU) & 0x80000000) - { - ERROR_LOG(DSPLLE, "Mailbox isn't empty ... strange"); - } + if (_CPUMailbox) + { + if (gdsp_mbox_peek(MAILBOX_CPU) & 0x80000000) + { + ERROR_LOG(DSPLLE, "Mailbox isn't empty ... strange"); + } #if PROFILE - if ((_uHighMail) == 0xBABE) - { - ProfilerStart(); - } + if ((_uHighMail) == 0xBABE) + { + ProfilerStart(); + } #endif - gdsp_mbox_write_h(MAILBOX_CPU, _uHighMail); - } - else - { - ERROR_LOG(DSPLLE, "CPU can't write to DSP mailbox"); - } + gdsp_mbox_write_h(MAILBOX_CPU, _uHighMail); + } + else + { + ERROR_LOG(DSPLLE, "CPU can't write to DSP mailbox"); + } } void DSPLLE::DSP_WriteMailBoxLow(bool _CPUMailbox, u16 _uLowMail) { - if (_CPUMailbox) - { - gdsp_mbox_write_l(MAILBOX_CPU, _uLowMail); - } - else - { - ERROR_LOG(DSPLLE, "CPU can't write to DSP mailbox"); - } + if (_CPUMailbox) + { + gdsp_mbox_write_l(MAILBOX_CPU, _uLowMail); + } + else + { + ERROR_LOG(DSPLLE, "CPU can't write to DSP mailbox"); + } } void DSPLLE::DSP_Update(int cycles) { - int dsp_cycles = cycles / 6; + int dsp_cycles = cycles / 6; - if (dsp_cycles <= 0) - return; -// Sound stream update job has been handled by AudioDMA routine, which is more efficient -/* - // This gets called VERY OFTEN. The soundstream update might be expensive so only do it 200 times per second or something. - int cycles_between_ss_update; + if (dsp_cycles <= 0) + return; + // Sound stream update job has been handled by AudioDMA routine, which is more efficient + /* + // This gets called VERY OFTEN. The soundstream update might be expensive so only do it 200 + times per second or something. + int cycles_between_ss_update; - if (g_dspInitialize.bWii) - cycles_between_ss_update = 121500000 / 200; - else - cycles_between_ss_update = 81000000 / 200; + if (g_dspInitialize.bWii) + cycles_between_ss_update = 121500000 / 200; + else + cycles_between_ss_update = 81000000 / 200; - m_cycle_count += cycles; - if (m_cycle_count > cycles_between_ss_update) - { - while (m_cycle_count > cycles_between_ss_update) - m_cycle_count -= cycles_between_ss_update; - soundStream->Update(); - } -*/ - if (m_bDSPThread) - { - if (requestDisableThread || NetPlay::IsNetPlayRunning() || Movie::IsMovieActive() || Core::g_want_determinism) - { - DSP_StopSoundStream(); - m_bDSPThread = false; - requestDisableThread = false; - SConfig::GetInstance().bDSPThread = false; - } - } + m_cycle_count += cycles; + if (m_cycle_count > cycles_between_ss_update) + { + while (m_cycle_count > cycles_between_ss_update) + m_cycle_count -= cycles_between_ss_update; + soundStream->Update(); + } + */ + if (m_bDSPThread) + { + if (requestDisableThread || NetPlay::IsNetPlayRunning() || Movie::IsMovieActive() || + Core::g_want_determinism) + { + DSP_StopSoundStream(); + m_bDSPThread = false; + requestDisableThread = false; + SConfig::GetInstance().bDSPThread = false; + } + } - // If we're not on a thread, run cycles here. - if (!m_bDSPThread) - { - // ~1/6th as many cycles as the period PPC-side. - DSPCore_RunCycles(dsp_cycles); - } - else - { - // Wait for DSP thread to complete its cycle. Note: this logic should be thought through. - ppcEvent.Wait(); - m_cycle_count.fetch_add(dsp_cycles); - dspEvent.Set(); - } + // If we're not on a thread, run cycles here. + if (!m_bDSPThread) + { + // ~1/6th as many cycles as the period PPC-side. + DSPCore_RunCycles(dsp_cycles); + } + else + { + // Wait for DSP thread to complete its cycle. Note: this logic should be thought through. + ppcEvent.Wait(); + m_cycle_count.fetch_add(dsp_cycles); + dspEvent.Set(); + } } u32 DSPLLE::DSP_UpdateRate() { - return 12600; // TO BE TWEAKED + return 12600; // TO BE TWEAKED } void DSPLLE::PauseAndLock(bool doLock, bool unpauseOnUnlock) { - if (doLock) - m_csDSPThreadActive.lock(); - else - m_csDSPThreadActive.unlock(); + if (doLock) + m_csDSPThreadActive.lock(); + else + m_csDSPThreadActive.unlock(); } diff --git a/Source/Core/Core/HW/DSPLLE/DSPLLE.h b/Source/Core/Core/HW/DSPLLE/DSPLLE.h index c40063bcae..95c36a84dd 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPLLE.h +++ b/Source/Core/Core/HW/DSPLLE/DSPLLE.h @@ -16,32 +16,31 @@ class PointerWrap; class DSPLLE : public DSPEmulator { public: - DSPLLE(); + DSPLLE(); - bool Initialize(bool bWii, bool bDSPThread) override; - void Shutdown() override; - bool IsLLE() override { return true; } + bool Initialize(bool bWii, bool bDSPThread) override; + void Shutdown() override; + bool IsLLE() override { return true; } + void DoState(PointerWrap& p) override; + void PauseAndLock(bool doLock, bool unpauseOnUnlock = true) override; - void DoState(PointerWrap &p) override; - void PauseAndLock(bool doLock, bool unpauseOnUnlock=true) override; - - void DSP_WriteMailBoxHigh(bool _CPUMailbox, unsigned short) override; - void DSP_WriteMailBoxLow(bool _CPUMailbox, unsigned short) override; - unsigned short DSP_ReadMailBoxHigh(bool _CPUMailbox) override; - unsigned short DSP_ReadMailBoxLow(bool _CPUMailbox) override; - unsigned short DSP_ReadControlRegister() override; - unsigned short DSP_WriteControlRegister(unsigned short) override; - void DSP_Update(int cycles) override; - void DSP_StopSoundStream() override; - u32 DSP_UpdateRate() override; + void DSP_WriteMailBoxHigh(bool _CPUMailbox, unsigned short) override; + void DSP_WriteMailBoxLow(bool _CPUMailbox, unsigned short) override; + unsigned short DSP_ReadMailBoxHigh(bool _CPUMailbox) override; + unsigned short DSP_ReadMailBoxLow(bool _CPUMailbox) override; + unsigned short DSP_ReadControlRegister() override; + unsigned short DSP_WriteControlRegister(unsigned short) override; + void DSP_Update(int cycles) override; + void DSP_StopSoundStream() override; + u32 DSP_UpdateRate() override; private: - static void DSPThread(DSPLLE* lpParameter); + static void DSPThread(DSPLLE* lpParameter); - std::thread m_hDSPThread; - std::mutex m_csDSPThreadActive; - bool m_bWii; - bool m_bDSPThread; - Common::Flag m_bIsRunning; - std::atomic m_cycle_count; + std::thread m_hDSPThread; + std::mutex m_csDSPThreadActive; + bool m_bWii; + bool m_bDSPThread; + Common::Flag m_bIsRunning; + std::atomic m_cycle_count; }; diff --git a/Source/Core/Core/HW/DSPLLE/DSPLLEGlobals.cpp b/Source/Core/Core/HW/DSPLLE/DSPLLEGlobals.cpp index 6fd28b45c5..77782a2455 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPLLEGlobals.cpp +++ b/Source/Core/Core/HW/DSPLLE/DSPLLEGlobals.cpp @@ -19,40 +19,43 @@ bool g_profile = false; void ProfilerStart() { - g_profile = true; + g_profile = true; } void ProfilerAddDelta(int _addr, int _delta) { - if (g_profile) - { - g_profileMap[_addr] += _delta; - } + if (g_profile) + { + g_profileMap[_addr] += _delta; + } } void ProfilerInit() { - memset(g_profileMap, 0, sizeof(g_profileMap)); + memset(g_profileMap, 0, sizeof(g_profileMap)); } void ProfilerDump(u64 count) { - File::IOFile pFile("DSP_Prof.txt", "wt"); - if (pFile) - { - fprintf(pFile.GetHandle(), "Number of DSP steps: %" PRIu64 "\n\n", count); - for (int i=0; i 0) - { - fprintf(pFile.GetHandle(), "0x%04X: %" PRIu64 "\n", i, g_profileMap[i]); - } - } - } + File::IOFile pFile("DSP_Prof.txt", "wt"); + if (pFile) + { + fprintf(pFile.GetHandle(), "Number of DSP steps: %" PRIu64 "\n\n", count); + for (int i = 0; i < PROFILE_MAP_SIZE; i++) + { + if (g_profileMap[i] > 0) + { + fprintf(pFile.GetHandle(), "0x%04X: %" PRIu64 "\n", i, g_profileMap[i]); + } + } + } } #elif defined(_MSC_VER) -namespace { char SilenceLNK4221; }; +namespace +{ +char SilenceLNK4221; +}; #endif diff --git a/Source/Core/Core/HW/DSPLLE/DSPLLEGlobals.h b/Source/Core/Core/HW/DSPLLE/DSPLLEGlobals.h index 1fd3e0aaad..1d7beba487 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPLLEGlobals.h +++ b/Source/Core/Core/HW/DSPLLE/DSPLLEGlobals.h @@ -8,11 +8,11 @@ // TODO: Get rid of this file. -#define PROFILE 0 +#define PROFILE 0 #if PROFILE - void ProfilerDump(u64 _count); - void ProfilerInit(); - void ProfilerAddDelta(int _addr, int _delta); - void ProfilerStart(); +void ProfilerDump(u64 _count); +void ProfilerInit(); +void ProfilerAddDelta(int _addr, int _delta); +void ProfilerStart(); #endif diff --git a/Source/Core/Core/HW/DSPLLE/DSPLLETools.cpp b/Source/Core/Core/HW/DSPLLE/DSPLLETools.cpp index a493fd7564..600df672f9 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPLLETools.cpp +++ b/Source/Core/Core/HW/DSPLLE/DSPLLETools.cpp @@ -19,58 +19,60 @@ #include "Core/DSP/DSPDisassembler.h" #include "Core/HW/DSPLLE/DSPLLETools.h" -bool DumpDSPCode(const u8 *code_be, int size_in_bytes, u32 crc) +bool DumpDSPCode(const u8* code_be, int size_in_bytes, u32 crc) { - const std::string binFile = StringFromFormat("%sDSP_UC_%08X.bin", File::GetUserPath(D_DUMPDSP_IDX).c_str(), crc); - const std::string txtFile = StringFromFormat("%sDSP_UC_%08X.txt", File::GetUserPath(D_DUMPDSP_IDX).c_str(), crc); + const std::string binFile = + StringFromFormat("%sDSP_UC_%08X.bin", File::GetUserPath(D_DUMPDSP_IDX).c_str(), crc); + const std::string txtFile = + StringFromFormat("%sDSP_UC_%08X.txt", File::GetUserPath(D_DUMPDSP_IDX).c_str(), crc); - File::IOFile pFile(binFile, "wb"); - if (pFile) - { - pFile.WriteBytes(code_be, size_in_bytes); - pFile.Close(); - } - else - { - PanicAlert("Can't open file (%s) to dump UCode!!", binFile.c_str()); - return false; - } + File::IOFile pFile(binFile, "wb"); + if (pFile) + { + pFile.WriteBytes(code_be, size_in_bytes); + pFile.Close(); + } + else + { + PanicAlert("Can't open file (%s) to dump UCode!!", binFile.c_str()); + return false; + } - // Load the binary back in. - std::vector code; - LoadBinary(binFile, code); + // Load the binary back in. + std::vector code; + LoadBinary(binFile, code); - AssemblerSettings settings; - settings.show_hex = true; - settings.show_pc = true; - settings.ext_separator = '\''; - settings.decode_names = true; - settings.decode_registers = true; + AssemblerSettings settings; + settings.show_hex = true; + settings.show_pc = true; + settings.ext_separator = '\''; + settings.decode_names = true; + settings.decode_registers = true; - std::string text; - DSPDisassembler disasm(settings); + std::string text; + DSPDisassembler disasm(settings); - if (!disasm.Disassemble(0, code, 0x0000, text)) - return false; + if (!disasm.Disassemble(0, code, 0x0000, text)) + return false; - return File::WriteStringToFile(text, txtFile); + return File::WriteStringToFile(text, txtFile); } // TODO make this useful :p bool DumpCWCode(u32 _Address, u32 _Length) { - std::string filename = File::GetUserPath(D_DUMPDSP_IDX) + "DSP_UCode.bin"; - File::IOFile pFile(filename, "wb"); + std::string filename = File::GetUserPath(D_DUMPDSP_IDX) + "DSP_UCode.bin"; + File::IOFile pFile(filename, "wb"); - if (pFile) - { - for (size_t i = _Address; i != _Address + _Length; ++i) - { - u16 val = g_dsp.iram[i]; - fprintf(pFile.GetHandle(), " cw 0x%04x \n", val); - } - return true; - } + if (pFile) + { + for (size_t i = _Address; i != _Address + _Length; ++i) + { + u16 val = g_dsp.iram[i]; + fprintf(pFile.GetHandle(), " cw 0x%04x \n", val); + } + return true; + } - return false; + return false; } diff --git a/Source/Core/Core/HW/DSPLLE/DSPLLETools.h b/Source/Core/Core/HW/DSPLLE/DSPLLETools.h index bdd688476d..6014f616f0 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPLLETools.h +++ b/Source/Core/Core/HW/DSPLLE/DSPLLETools.h @@ -6,5 +6,5 @@ #include "Common/CommonTypes.h" -bool DumpDSPCode(const u8 *code_be, int size_in_bytes, u32 crc); +bool DumpDSPCode(const u8* code_be, int size_in_bytes, u32 crc); bool DumpCWCode(u32 _Address, u32 _Length); diff --git a/Source/Core/Core/HW/DSPLLE/DSPSymbols.cpp b/Source/Core/Core/HW/DSPLLE/DSPSymbols.cpp index ab5ed8efef..e4438fa40a 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPSymbols.cpp +++ b/Source/Core/Core/HW/DSPLLE/DSPSymbols.cpp @@ -17,235 +17,233 @@ namespace DSPSymbols { - DSPSymbolDB g_dsp_symbol_db; static std::map addr_to_line; static std::map line_to_addr; -static std::map line_to_symbol; +static std::map line_to_symbol; static std::vector lines; static int line_counter = 0; int Addr2Line(u16 address) // -1 for not found { - std::map::iterator iter = addr_to_line.find(address); - if (iter != addr_to_line.end()) - return iter->second; - else - return -1; + std::map::iterator iter = addr_to_line.find(address); + if (iter != addr_to_line.end()) + return iter->second; + else + return -1; } -int Line2Addr(int line) // -1 for not found +int Line2Addr(int line) // -1 for not found { - std::map::iterator iter = line_to_addr.find(line); - if (iter != line_to_addr.end()) - return iter->second; - else - return -1; + std::map::iterator iter = line_to_addr.find(line); + if (iter != line_to_addr.end()) + return iter->second; + else + return -1; } -const char *GetLineText(int line) +const char* GetLineText(int line) { - if (line > 0 && line < (int)lines.size()) - { - return lines[line].c_str(); - } - else - { - return "----"; - } + if (line > 0 && line < (int)lines.size()) + { + return lines[line].c_str(); + } + else + { + return "----"; + } } -Symbol *DSPSymbolDB::GetSymbolFromAddr(u32 addr) +Symbol* DSPSymbolDB::GetSymbolFromAddr(u32 addr) { - XFuncMap::iterator it = functions.find(addr); + XFuncMap::iterator it = functions.find(addr); - if (it != functions.end()) - { - return &it->second; - } - else - { - for (auto& func : functions) - { - if (addr >= func.second.address && addr < func.second.address + func.second.size) - return &func.second; - } - } - return nullptr; + if (it != functions.end()) + { + return &it->second; + } + else + { + for (auto& func : functions) + { + if (addr >= func.second.address && addr < func.second.address + func.second.size) + return &func.second; + } + } + return nullptr; } bool ReadAnnotatedAssembly(const std::string& filename) { - File::IOFile f(filename, "r"); - if (!f) - { - ERROR_LOG(DSPLLE, "Bah! ReadAnnotatedAssembly couldn't find the file %s", filename.c_str()); - return false; - } - char line[512]; + File::IOFile f(filename, "r"); + if (!f) + { + ERROR_LOG(DSPLLE, "Bah! ReadAnnotatedAssembly couldn't find the file %s", filename.c_str()); + return false; + } + char line[512]; - int last_addr = 0; + int last_addr = 0; - lines.reserve(3000); + lines.reserve(3000); - // Symbol generation - int brace_count = 0; - bool symbol_in_progress = false; + // Symbol generation + int brace_count = 0; + bool symbol_in_progress = false; - int symbol_count = 0; - Symbol current_symbol; + int symbol_count = 0; + Symbol current_symbol; - while (fgets(line, 512, f.GetHandle())) - { - // Scan string for the first 4-digit hex string. - size_t len = strlen(line); - int first_hex = -1; - bool hex_found = false; - for (unsigned int i = 0; i < strlen(line); i++) - { - const char c = line[i]; - if (isxdigit(c)) - { - if (first_hex == -1) - { - first_hex = i; - } - else - { - // Remove hex notation - if ((int)i == first_hex + 3 && - (first_hex == 0 || line[first_hex - 1] != 'x') && - (i >= len - 1 || line[i + 1] == ' ')) - { - hex_found = true; - break; - } - } - } - else - { - if (i - first_hex < 3) - { - first_hex = -1; - } - if (isalpha(c)) - break; - } - } + while (fgets(line, 512, f.GetHandle())) + { + // Scan string for the first 4-digit hex string. + size_t len = strlen(line); + int first_hex = -1; + bool hex_found = false; + for (unsigned int i = 0; i < strlen(line); i++) + { + const char c = line[i]; + if (isxdigit(c)) + { + if (first_hex == -1) + { + first_hex = i; + } + else + { + // Remove hex notation + if ((int)i == first_hex + 3 && (first_hex == 0 || line[first_hex - 1] != 'x') && + (i >= len - 1 || line[i + 1] == ' ')) + { + hex_found = true; + break; + } + } + } + else + { + if (i - first_hex < 3) + { + first_hex = -1; + } + if (isalpha(c)) + break; + } + } - // Scan for function starts - if (!memcmp(line, "void", 4)) - { - char temp[256]; - for (size_t i = 6; i < len; i++) - { - if (line[i] == '(') - { - // Yep, got one. - memcpy(temp, line + 5, i - 5); - temp[i - 5] = 0; + // Scan for function starts + if (!memcmp(line, "void", 4)) + { + char temp[256]; + for (size_t i = 6; i < len; i++) + { + if (line[i] == '(') + { + // Yep, got one. + memcpy(temp, line + 5, i - 5); + temp[i - 5] = 0; - // Mark symbol so the next hex sets the address - current_symbol.name = temp; - current_symbol.address = 0xFFFF; - current_symbol.index = symbol_count++; - symbol_in_progress = true; + // Mark symbol so the next hex sets the address + current_symbol.name = temp; + current_symbol.address = 0xFFFF; + current_symbol.index = symbol_count++; + symbol_in_progress = true; - // Reset brace count. - brace_count = 0; - } - } - } + // Reset brace count. + brace_count = 0; + } + } + } - // Scan for braces - for (size_t i = 0; i < len; i++) - { - if (line[i] == '{') - brace_count++; - if (line[i] == '}') - { - brace_count--; - if (brace_count == 0 && symbol_in_progress) - { - // Commit this symbol. - current_symbol.size = last_addr - current_symbol.address + 1; - g_dsp_symbol_db.AddCompleteSymbol(current_symbol); - current_symbol.address = 0xFFFF; - symbol_in_progress = false; - } - } - } + // Scan for braces + for (size_t i = 0; i < len; i++) + { + if (line[i] == '{') + brace_count++; + if (line[i] == '}') + { + brace_count--; + if (brace_count == 0 && symbol_in_progress) + { + // Commit this symbol. + current_symbol.size = last_addr - current_symbol.address + 1; + g_dsp_symbol_db.AddCompleteSymbol(current_symbol); + current_symbol.address = 0xFFFF; + symbol_in_progress = false; + } + } + } - if (hex_found) - { - int hex = 0; - sscanf(line + first_hex, "%04x", &hex); + if (hex_found) + { + int hex = 0; + sscanf(line + first_hex, "%04x", &hex); - // Sanity check - if (hex > last_addr + 3 || hex < last_addr - 3) - { - static int errors = 0; - INFO_LOG(DSPLLE, "Got Insane Hex Digit %04x (%04x) from %s", hex, last_addr, line); - errors++; - if (errors > 10) - { - return false; - } - } - else - { - // if (line_counter >= 200 && line_counter <= 220) - // NOTICE_LOG(DSPLLE, "Got Hex Digit %04x from %s, line %i", hex, line, line_counter); - if (symbol_in_progress && current_symbol.address == 0xFFFF) - current_symbol.address = hex; + // Sanity check + if (hex > last_addr + 3 || hex < last_addr - 3) + { + static int errors = 0; + INFO_LOG(DSPLLE, "Got Insane Hex Digit %04x (%04x) from %s", hex, last_addr, line); + errors++; + if (errors > 10) + { + return false; + } + } + else + { + // if (line_counter >= 200 && line_counter <= 220) + // NOTICE_LOG(DSPLLE, "Got Hex Digit %04x from %s, line %i", hex, line, line_counter); + if (symbol_in_progress && current_symbol.address == 0xFFFF) + current_symbol.address = hex; - line_to_addr[line_counter] = hex; - addr_to_line[hex] = line_counter; - last_addr = hex; - } - } + line_to_addr[line_counter] = hex; + addr_to_line[hex] = line_counter; + last_addr = hex; + } + } - lines.push_back(TabsToSpaces(4, line)); - line_counter++; - } + lines.push_back(TabsToSpaces(4, line)); + line_counter++; + } - return true; + return true; } void AutoDisassembly(u16 start_addr, u16 end_addr) { - AssemblerSettings settings; - settings.show_pc = true; - settings.show_hex = true; - DSPDisassembler disasm(settings); + AssemblerSettings settings; + settings.show_pc = true; + settings.show_hex = true; + DSPDisassembler disasm(settings); - u16 addr = start_addr; - const u16 *ptr = (start_addr >> 15) ? g_dsp.irom : g_dsp.iram; - while (addr < end_addr) - { - line_to_addr[line_counter] = addr; - addr_to_line[addr] = line_counter; + u16 addr = start_addr; + const u16* ptr = (start_addr >> 15) ? g_dsp.irom : g_dsp.iram; + while (addr < end_addr) + { + line_to_addr[line_counter] = addr; + addr_to_line[addr] = line_counter; - std::string buf; - if (!disasm.DisassembleOpcode(ptr, 0, 2, &addr, buf)) - { - ERROR_LOG(DSPLLE, "disasm failed at %04x", addr); - break; - } + std::string buf; + if (!disasm.DisassembleOpcode(ptr, 0, 2, &addr, buf)) + { + ERROR_LOG(DSPLLE, "disasm failed at %04x", addr); + break; + } - //NOTICE_LOG(DSPLLE, "Added %04x %i %s", addr, line_counter, buf.c_str()); - lines.push_back(buf); - line_counter++; - } + // NOTICE_LOG(DSPLLE, "Added %04x %i %s", addr, line_counter, buf.c_str()); + lines.push_back(buf); + line_counter++; + } } void Clear() { - addr_to_line.clear(); - line_to_addr.clear(); - lines.clear(); - line_counter = 0; + addr_to_line.clear(); + line_to_addr.clear(); + lines.clear(); + line_counter = 0; } } // namespace DSPSymbols diff --git a/Source/Core/Core/HW/DSPLLE/DSPSymbols.h b/Source/Core/Core/HW/DSPLLE/DSPSymbols.h index ab64d8d3a9..9465ea817b 100644 --- a/Source/Core/Core/HW/DSPLLE/DSPSymbols.h +++ b/Source/Core/Core/HW/DSPLLE/DSPSymbols.h @@ -11,15 +11,12 @@ namespace DSPSymbols { - class DSPSymbolDB : public SymbolDB { public: - DSPSymbolDB() {} - ~DSPSymbolDB() {} - - Symbol *GetSymbolFromAddr(u32 addr) override; - + DSPSymbolDB() {} + ~DSPSymbolDB() {} + Symbol* GetSymbolFromAddr(u32 addr) override; }; extern DSPSymbolDB g_dsp_symbol_db; @@ -30,8 +27,8 @@ void AutoDisassembly(u16 start_addr, u16 end_addr); void Clear(); int Addr2Line(u16 address); -int Line2Addr(int line); // -1 for not found +int Line2Addr(int line); // -1 for not found -const char *GetLineText(int line); +const char* GetLineText(int line); } // namespace DSPSymbols diff --git a/Source/Core/Core/HW/DVDInterface.cpp b/Source/Core/Core/HW/DVDInterface.cpp index c3626cd428..ba5a730c1b 100644 --- a/Source/Core/Core/HW/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVDInterface.cpp @@ -16,17 +16,17 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" -#include "Core/Movie.h" #include "Core/HW/AudioInterface.h" #include "Core/HW/DVDInterface.h" #include "Core/HW/DVDThread.h" -#include "Core/HW/Memmap.h" #include "Core/HW/MMIO.h" +#include "Core/HW/Memmap.h" #include "Core/HW/ProcessorInterface.h" #include "Core/HW/StreamADPCM.h" #include "Core/HW/SystemTimers.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_DI.h" +#include "Core/Movie.h" #include "DiscIO/Volume.h" #include "DiscIO/VolumeCreator.h" @@ -49,14 +49,15 @@ static const u64 WII_DISC_LAYER_SIZE = 4699979776; // // These speeds are approximations of speeds measured on real Wiis. -static const u32 GC_DISC_LOCATION_1_OFFSET = 0; // The beginning of a GC disc - 48 mm +static const u32 GC_DISC_LOCATION_1_OFFSET = 0; // The beginning of a GC disc - 48 mm static const u32 GC_DISC_LOCATION_1_READ_SPEED = (u32)(1024 * 1024 * 2.1); -static const u32 GC_DISC_LOCATION_2_OFFSET = 1459978239; // The end of a GC disc - 76 mm +static const u32 GC_DISC_LOCATION_2_OFFSET = 1459978239; // The end of a GC disc - 76 mm static const u32 GC_DISC_LOCATION_2_READ_SPEED = (u32)(1024 * 1024 * 3.325); -static const u32 WII_DISC_LOCATION_1_OFFSET = 0; // The beginning of a Wii disc - 48 mm +static const u32 WII_DISC_LOCATION_1_OFFSET = 0; // The beginning of a Wii disc - 48 mm static const u32 WII_DISC_LOCATION_1_READ_SPEED = (u32)(1024 * 1024 * 3.5); -static const u64 WII_DISC_LOCATION_2_OFFSET = WII_DISC_LAYER_SIZE; // The end of a Wii disc - 116 mm +static const u64 WII_DISC_LOCATION_2_OFFSET = + WII_DISC_LAYER_SIZE; // The end of a Wii disc - 116 mm static const u32 WII_DISC_LOCATION_2_READ_SPEED = (u32)(1024 * 1024 * 8.45); // These values are used for disc read speed calculations. Calculations @@ -64,176 +65,167 @@ static const u32 WII_DISC_LOCATION_2_READ_SPEED = (u32)(1024 * 1024 * 8.45); // is the same as the read speed at that track in bytes per second. static const double GC_DISC_AREA_UP_TO_LOCATION_1 = - PI * GC_DISC_LOCATION_1_READ_SPEED * GC_DISC_LOCATION_1_READ_SPEED; + PI * GC_DISC_LOCATION_1_READ_SPEED * GC_DISC_LOCATION_1_READ_SPEED; static const double GC_DISC_AREA_UP_TO_LOCATION_2 = - PI * GC_DISC_LOCATION_2_READ_SPEED * GC_DISC_LOCATION_2_READ_SPEED; + PI * GC_DISC_LOCATION_2_READ_SPEED * GC_DISC_LOCATION_2_READ_SPEED; static const double GC_BYTES_PER_AREA_UNIT = - (GC_DISC_LOCATION_2_OFFSET - GC_DISC_LOCATION_1_OFFSET) / - (GC_DISC_AREA_UP_TO_LOCATION_2 - GC_DISC_AREA_UP_TO_LOCATION_1); + (GC_DISC_LOCATION_2_OFFSET - GC_DISC_LOCATION_1_OFFSET) / + (GC_DISC_AREA_UP_TO_LOCATION_2 - GC_DISC_AREA_UP_TO_LOCATION_1); static const double WII_DISC_AREA_UP_TO_LOCATION_1 = - PI * WII_DISC_LOCATION_1_READ_SPEED * WII_DISC_LOCATION_1_READ_SPEED; + PI * WII_DISC_LOCATION_1_READ_SPEED * WII_DISC_LOCATION_1_READ_SPEED; static const double WII_DISC_AREA_UP_TO_LOCATION_2 = - PI * WII_DISC_LOCATION_2_READ_SPEED * WII_DISC_LOCATION_2_READ_SPEED; + PI * WII_DISC_LOCATION_2_READ_SPEED * WII_DISC_LOCATION_2_READ_SPEED; static const double WII_BYTES_PER_AREA_UNIT = - (WII_DISC_LOCATION_2_OFFSET - WII_DISC_LOCATION_1_OFFSET) / - (WII_DISC_AREA_UP_TO_LOCATION_2 - WII_DISC_AREA_UP_TO_LOCATION_1); + (WII_DISC_LOCATION_2_OFFSET - WII_DISC_LOCATION_1_OFFSET) / + (WII_DISC_AREA_UP_TO_LOCATION_2 - WII_DISC_AREA_UP_TO_LOCATION_1); namespace DVDInterface { - // internal hardware addresses enum { - DI_STATUS_REGISTER = 0x00, - DI_COVER_REGISTER = 0x04, - DI_COMMAND_0 = 0x08, - DI_COMMAND_1 = 0x0C, - DI_COMMAND_2 = 0x10, - DI_DMA_ADDRESS_REGISTER = 0x14, - DI_DMA_LENGTH_REGISTER = 0x18, - DI_DMA_CONTROL_REGISTER = 0x1C, - DI_IMMEDIATE_DATA_BUFFER = 0x20, - DI_CONFIG_REGISTER = 0x24 + DI_STATUS_REGISTER = 0x00, + DI_COVER_REGISTER = 0x04, + DI_COMMAND_0 = 0x08, + DI_COMMAND_1 = 0x0C, + DI_COMMAND_2 = 0x10, + DI_DMA_ADDRESS_REGISTER = 0x14, + DI_DMA_LENGTH_REGISTER = 0x18, + DI_DMA_CONTROL_REGISTER = 0x1C, + DI_IMMEDIATE_DATA_BUFFER = 0x20, + DI_CONFIG_REGISTER = 0x24 }; // debug commands which may be ORd enum { - STOP_DRIVE = 0, - START_DRIVE = 0x100, - ACCEPT_COPY = 0x4000, - DISC_CHECK = 0x8000, + STOP_DRIVE = 0, + START_DRIVE = 0x100, + ACCEPT_COPY = 0x4000, + DISC_CHECK = 0x8000, }; // DI Status Register -union UDISR -{ - u32 Hex; - struct - { - u32 BREAK : 1; // Stop the Device + Interrupt - u32 DEINITMASK : 1; // Access Device Error Int Mask - u32 DEINT : 1; // Access Device Error Int - u32 TCINTMASK : 1; // Transfer Complete Int Mask - u32 TCINT : 1; // Transfer Complete Int - u32 BRKINTMASK : 1; - u32 BRKINT : 1; // w 1: clear brkint - u32 : 25; - }; - UDISR() {Hex = 0;} - UDISR(u32 _hex) {Hex = _hex;} +union UDISR { + u32 Hex; + struct + { + u32 BREAK : 1; // Stop the Device + Interrupt + u32 DEINITMASK : 1; // Access Device Error Int Mask + u32 DEINT : 1; // Access Device Error Int + u32 TCINTMASK : 1; // Transfer Complete Int Mask + u32 TCINT : 1; // Transfer Complete Int + u32 BRKINTMASK : 1; + u32 BRKINT : 1; // w 1: clear brkint + u32 : 25; + }; + UDISR() { Hex = 0; } + UDISR(u32 _hex) { Hex = _hex; } }; // DI Cover Register -union UDICVR -{ - u32 Hex; - struct - { - u32 CVR : 1; // 0: Cover closed 1: Cover open - u32 CVRINTMASK : 1; // 1: Interrupt enabled - u32 CVRINT : 1; // r 1: Interrupt requested w 1: Interrupt clear - u32 : 29; - }; - UDICVR() {Hex = 0;} - UDICVR(u32 _hex) {Hex = _hex;} +union UDICVR { + u32 Hex; + struct + { + u32 CVR : 1; // 0: Cover closed 1: Cover open + u32 CVRINTMASK : 1; // 1: Interrupt enabled + u32 CVRINT : 1; // r 1: Interrupt requested w 1: Interrupt clear + u32 : 29; + }; + UDICVR() { Hex = 0; } + UDICVR(u32 _hex) { Hex = _hex; } }; -union UDICMDBUF -{ - u32 Hex; - struct - { - u8 CMDBYTE3; - u8 CMDBYTE2; - u8 CMDBYTE1; - u8 CMDBYTE0; - }; +union UDICMDBUF { + u32 Hex; + struct + { + u8 CMDBYTE3; + u8 CMDBYTE2; + u8 CMDBYTE1; + u8 CMDBYTE0; + }; }; // DI DMA Address Register -union UDIMAR -{ - u32 Hex; - struct - { - u32 Zerobits : 5; // Must be zero (32byte aligned) - u32 : 27; - }; - struct - { - u32 Address : 26; - u32 : 6; - }; +union UDIMAR { + u32 Hex; + struct + { + u32 Zerobits : 5; // Must be zero (32byte aligned) + u32 : 27; + }; + struct + { + u32 Address : 26; + u32 : 6; + }; }; // DI DMA Address Length Register -union UDILENGTH -{ - u32 Hex; - struct - { - u32 Zerobits : 5; // Must be zero (32byte aligned) - u32 : 27; - }; - struct - { - u32 Length : 26; - u32 : 6; - }; +union UDILENGTH { + u32 Hex; + struct + { + u32 Zerobits : 5; // Must be zero (32byte aligned) + u32 : 27; + }; + struct + { + u32 Length : 26; + u32 : 6; + }; }; // DI DMA Control Register -union UDICR -{ - u32 Hex; - struct - { - u32 TSTART : 1; // w:1 start r:0 ready - u32 DMA : 1; // 1: DMA Mode 0: Immediate Mode (can only do Access Register Command) - u32 RW : 1; // 0: Read Command (DVD to Memory) 1: Write Command (Memory to DVD) - u32 : 29; - }; +union UDICR { + u32 Hex; + struct + { + u32 TSTART : 1; // w:1 start r:0 ready + u32 DMA : 1; // 1: DMA Mode 0: Immediate Mode (can only do Access Register Command) + u32 RW : 1; // 0: Read Command (DVD to Memory) 1: Write Command (Memory to DVD) + u32 : 29; + }; }; -union UDIIMMBUF -{ - u32 Hex; - struct - { - u8 REGVAL3; - u8 REGVAL2; - u8 REGVAL1; - u8 REGVAL0; - }; +union UDIIMMBUF { + u32 Hex; + struct + { + u8 REGVAL3; + u8 REGVAL2; + u8 REGVAL1; + u8 REGVAL0; + }; }; // DI Config Register -union UDICFG -{ - u32 Hex; - struct - { - u32 CONFIG : 8; - u32 : 24; - }; - UDICFG() {Hex = 0;} - UDICFG(u32 _hex) {Hex = _hex;} +union UDICFG { + u32 Hex; + struct + { + u32 CONFIG : 8; + u32 : 24; + }; + UDICFG() { Hex = 0; } + UDICFG(u32 _hex) { Hex = _hex; } }; static std::unique_ptr s_inserted_volume; // STATE_TO_SAVE // hardware registers -static UDISR s_DISR; -static UDICVR s_DICVR; +static UDISR s_DISR; +static UDICVR s_DICVR; static UDICMDBUF s_DICMDBUF[3]; -static UDIMAR s_DIMAR; +static UDIMAR s_DIMAR; static UDILENGTH s_DILENGTH; -static UDICR s_DICR; +static UDICR s_DICR; static UDIIMMBUF s_DIIMMBUF; -static UDICFG s_DICFG; +static UDICFG s_DICFG; static u32 s_audio_position; static u32 s_current_start; @@ -241,13 +233,12 @@ static u32 s_current_length; static u32 s_next_start; static u32 s_next_length; - -static u32 s_error_code = 0; +static u32 s_error_code = 0; static bool s_disc_inside = false; static bool s_stream = false; static bool s_stop_at_track_end = false; -static int s_finish_executing_command = 0; -static int s_dtk = 0; +static int s_finish_executing_command = 0; +static int s_dtk = 0; static u64 s_last_read_offset; static u64 s_last_read_time; @@ -268,186 +259,191 @@ void UpdateInterrupts(); void GenerateDIInterrupt(DIInterruptType _DVDInterrupt); void WriteImmediate(u32 value, u32 output_address, bool reply_to_ios); -bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length, bool decrypt, - bool reply_to_ios, DIInterruptType* interrupt_type, u64* ticks_until_completion); +bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length, + bool decrypt, bool reply_to_ios, DIInterruptType* interrupt_type, + u64* ticks_until_completion); u64 SimulateDiscReadTime(u64 offset, u32 length); s64 CalculateRawDiscReadTime(u64 offset, s64 length); -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - p.DoPOD(s_DISR); - p.DoPOD(s_DICVR); - p.DoArray(s_DICMDBUF); - p.Do(s_DIMAR); - p.Do(s_DILENGTH); - p.Do(s_DICR); - p.Do(s_DIIMMBUF); - p.DoPOD(s_DICFG); + p.DoPOD(s_DISR); + p.DoPOD(s_DICVR); + p.DoArray(s_DICMDBUF); + p.Do(s_DIMAR); + p.Do(s_DILENGTH); + p.Do(s_DICR); + p.Do(s_DIIMMBUF); + p.DoPOD(s_DICFG); - p.Do(s_next_start); - p.Do(s_audio_position); - p.Do(s_next_length); + p.Do(s_next_start); + p.Do(s_audio_position); + p.Do(s_next_length); - p.Do(s_error_code); - p.Do(s_disc_inside); - p.Do(s_stream); + p.Do(s_error_code); + p.Do(s_disc_inside); + p.Do(s_stream); - p.Do(s_current_start); - p.Do(s_current_length); + p.Do(s_current_start); + p.Do(s_current_length); - p.Do(s_last_read_offset); - p.Do(s_last_read_time); + p.Do(s_last_read_offset); + p.Do(s_last_read_time); - p.Do(s_stop_at_track_end); + p.Do(s_stop_at_track_end); - DVDThread::DoState(p); + DVDThread::DoState(p); } -static u32 ProcessDTKSamples(short *tempPCM, u32 num_samples) +static u32 ProcessDTKSamples(short* tempPCM, u32 num_samples) { - // TODO: Read audio data using the DVD thread instead of blocking on it? - DVDThread::WaitUntilIdle(); + // TODO: Read audio data using the DVD thread instead of blocking on it? + DVDThread::WaitUntilIdle(); - u32 samples_processed = 0; - do - { - if (s_audio_position >= s_current_start + s_current_length) - { - DEBUG_LOG(DVDINTERFACE, - "ProcessDTKSamples: NextStart=%08x,NextLength=%08x,CurrentStart=%08x,CurrentLength=%08x,AudioPos=%08x", - s_next_start, s_next_length, s_current_start, s_current_length, s_audio_position); + u32 samples_processed = 0; + do + { + if (s_audio_position >= s_current_start + s_current_length) + { + DEBUG_LOG(DVDINTERFACE, "ProcessDTKSamples: " + "NextStart=%08x,NextLength=%08x,CurrentStart=%08x,CurrentLength=%08x," + "AudioPos=%08x", + s_next_start, s_next_length, s_current_start, s_current_length, s_audio_position); - s_audio_position = s_next_start; - s_current_start = s_next_start; - s_current_length = s_next_length; + s_audio_position = s_next_start; + s_current_start = s_next_start; + s_current_length = s_next_length; - if (s_stop_at_track_end) - { - s_stop_at_track_end = false; - s_stream = false; - break; - } + if (s_stop_at_track_end) + { + s_stop_at_track_end = false; + s_stream = false; + break; + } - StreamADPCM::InitFilter(); - } + StreamADPCM::InitFilter(); + } - u8 tempADPCM[StreamADPCM::ONE_BLOCK_SIZE]; - // TODO: What if we can't read from s_audio_position? - s_inserted_volume->Read(s_audio_position, sizeof(tempADPCM), tempADPCM, false); - s_audio_position += sizeof(tempADPCM); - StreamADPCM::DecodeBlock(tempPCM + samples_processed * 2, tempADPCM); - samples_processed += StreamADPCM::SAMPLES_PER_BLOCK; - } while (samples_processed < num_samples); - for (unsigned i = 0; i < samples_processed * 2; ++i) - { - // TODO: Fix the mixer so it can accept non-byte-swapped samples. - tempPCM[i] = Common::swap16(tempPCM[i]); - } - return samples_processed; + u8 tempADPCM[StreamADPCM::ONE_BLOCK_SIZE]; + // TODO: What if we can't read from s_audio_position? + s_inserted_volume->Read(s_audio_position, sizeof(tempADPCM), tempADPCM, false); + s_audio_position += sizeof(tempADPCM); + StreamADPCM::DecodeBlock(tempPCM + samples_processed * 2, tempADPCM); + samples_processed += StreamADPCM::SAMPLES_PER_BLOCK; + } while (samples_processed < num_samples); + for (unsigned i = 0; i < samples_processed * 2; ++i) + { + // TODO: Fix the mixer so it can accept non-byte-swapped samples. + tempPCM[i] = Common::swap16(tempPCM[i]); + } + return samples_processed; } static void DTKStreamingCallback(u64 userdata, s64 cyclesLate) { - // Send audio to the mixer. - static const int NUM_SAMPLES = 48000 / 2000 * 7; // 3.5ms of 48kHz samples - short tempPCM[NUM_SAMPLES * 2]; - unsigned samples_processed; - if (s_stream && AudioInterface::IsPlaying()) - { - samples_processed = ProcessDTKSamples(tempPCM, NUM_SAMPLES); - } - else - { - memset(tempPCM, 0, sizeof(tempPCM)); - samples_processed = NUM_SAMPLES; - } - g_sound_stream->GetMixer()->PushStreamingSamples(tempPCM, samples_processed); + // Send audio to the mixer. + static const int NUM_SAMPLES = 48000 / 2000 * 7; // 3.5ms of 48kHz samples + short tempPCM[NUM_SAMPLES * 2]; + unsigned samples_processed; + if (s_stream && AudioInterface::IsPlaying()) + { + samples_processed = ProcessDTKSamples(tempPCM, NUM_SAMPLES); + } + else + { + memset(tempPCM, 0, sizeof(tempPCM)); + samples_processed = NUM_SAMPLES; + } + g_sound_stream->GetMixer()->PushStreamingSamples(tempPCM, samples_processed); - int ticks_to_dtk = int(SystemTimers::GetTicksPerSecond() * u64(samples_processed) / 48000); - CoreTiming::ScheduleEvent(ticks_to_dtk - cyclesLate, s_dtk); + int ticks_to_dtk = int(SystemTimers::GetTicksPerSecond() * u64(samples_processed) / 48000); + CoreTiming::ScheduleEvent(ticks_to_dtk - cyclesLate, s_dtk); } void Init() { - DVDThread::Start(); + DVDThread::Start(); - s_DISR.Hex = 0; - s_DICVR.Hex = 1; // Disc Channel relies on cover being open when no disc is inserted - s_DICMDBUF[0].Hex = 0; - s_DICMDBUF[1].Hex = 0; - s_DICMDBUF[2].Hex = 0; - s_DIMAR.Hex = 0; - s_DILENGTH.Hex = 0; - s_DICR.Hex = 0; - s_DIIMMBUF.Hex = 0; - s_DICFG.Hex = 0; - s_DICFG.CONFIG = 1; // Disable bootrom descrambler + s_DISR.Hex = 0; + s_DICVR.Hex = 1; // Disc Channel relies on cover being open when no disc is inserted + s_DICMDBUF[0].Hex = 0; + s_DICMDBUF[1].Hex = 0; + s_DICMDBUF[2].Hex = 0; + s_DIMAR.Hex = 0; + s_DILENGTH.Hex = 0; + s_DICR.Hex = 0; + s_DIIMMBUF.Hex = 0; + s_DICFG.Hex = 0; + s_DICFG.CONFIG = 1; // Disable bootrom descrambler - s_audio_position = 0; - s_next_start = 0; - s_next_length = 0; - s_current_start = 0; - s_current_length = 0; + s_audio_position = 0; + s_next_start = 0; + s_next_length = 0; + s_current_start = 0; + s_current_length = 0; - s_error_code = 0; - s_disc_inside = false; - s_stream = false; - s_stop_at_track_end = false; + s_error_code = 0; + s_disc_inside = false; + s_stream = false; + s_stop_at_track_end = false; - s_last_read_offset = 0; - s_last_read_time = 0; + s_last_read_offset = 0; + s_last_read_time = 0; - s_eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback); - s_insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback); + s_eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback); + s_insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback); - s_finish_executing_command = CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback); - s_dtk = CoreTiming::RegisterEvent("StreamingTimer", DTKStreamingCallback); + s_finish_executing_command = + CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback); + s_dtk = CoreTiming::RegisterEvent("StreamingTimer", DTKStreamingCallback); - CoreTiming::ScheduleEvent(0, s_dtk); + CoreTiming::ScheduleEvent(0, s_dtk); } void Shutdown() { - DVDThread::Stop(); - s_inserted_volume.reset(); + DVDThread::Stop(); + s_inserted_volume.reset(); } const DiscIO::IVolume& GetVolume() { - return *s_inserted_volume; + return *s_inserted_volume; } bool SetVolumeName(const std::string& disc_path) { - DVDThread::WaitUntilIdle(); - s_inserted_volume = DiscIO::CreateVolumeFromFilename(disc_path); - return VolumeIsValid(); + DVDThread::WaitUntilIdle(); + s_inserted_volume = DiscIO::CreateVolumeFromFilename(disc_path); + return VolumeIsValid(); } -bool SetVolumeDirectory(const std::string& full_path, bool is_wii, const std::string& apploader_path, const std::string& DOL_path) +bool SetVolumeDirectory(const std::string& full_path, bool is_wii, + const std::string& apploader_path, const std::string& DOL_path) { - DVDThread::WaitUntilIdle(); - s_inserted_volume = DiscIO::CreateVolumeFromDirectory(full_path, is_wii, apploader_path, DOL_path); - return VolumeIsValid(); + DVDThread::WaitUntilIdle(); + s_inserted_volume = + DiscIO::CreateVolumeFromDirectory(full_path, is_wii, apploader_path, DOL_path); + return VolumeIsValid(); } bool VolumeIsValid() { - return s_inserted_volume != nullptr; + return s_inserted_volume != nullptr; } void SetDiscInside(bool disc_inside) { - if (s_disc_inside != disc_inside) - SetLidOpen(!disc_inside); + if (s_disc_inside != disc_inside) + SetLidOpen(!disc_inside); - s_disc_inside = disc_inside; + s_disc_inside = disc_inside; } bool IsDiscInside() { - return s_disc_inside; + return s_disc_inside; } // Take care of all logic of "swapping discs" @@ -456,219 +452,214 @@ bool IsDiscInside() // that the userdata string exists when called static void EjectDiscCallback(u64 userdata, s64 cyclesLate) { - DVDThread::WaitUntilIdle(); - s_inserted_volume.reset(); - SetDiscInside(false); + DVDThread::WaitUntilIdle(); + s_inserted_volume.reset(); + SetDiscInside(false); } static void InsertDiscCallback(u64 userdata, s64 cyclesLate) { - std::string& SavedFileName = SConfig::GetInstance().m_strFilename; - std::string *_FileName = (std::string *)userdata; + std::string& SavedFileName = SConfig::GetInstance().m_strFilename; + std::string* _FileName = (std::string*)userdata; - if (!SetVolumeName(*_FileName)) - { - // Put back the old one - SetVolumeName(SavedFileName); - PanicAlertT("Invalid file"); - } - SetDiscInside(VolumeIsValid()); - delete _FileName; + if (!SetVolumeName(*_FileName)) + { + // Put back the old one + SetVolumeName(SavedFileName); + PanicAlertT("Invalid file"); + } + SetDiscInside(VolumeIsValid()); + delete _FileName; } void ChangeDisc(const std::string& newFileName) { - // WARNING: Can only run on Host Thread - bool was_unpaused = Core::PauseAndLock(true); - std::string* _FileName = new std::string(newFileName); - CoreTiming::ScheduleEvent(0, s_eject_disc); - CoreTiming::ScheduleEvent(500000000, s_insert_disc, (u64)_FileName); - if (Movie::IsRecordingInput()) - { - Movie::g_bDiscChange = true; - std::string fileName = newFileName; - auto sizeofpath = fileName.find_last_of("/\\") + 1; - if (fileName.substr(sizeofpath).length() > 40) - { - PanicAlertT("The disc change to \"%s\" could not be saved in the .dtm file.\n" - "The filename of the disc image must not be longer than 40 characters.", newFileName.c_str()); - } - Movie::g_discChange = fileName.substr(sizeofpath); - } - Core::PauseAndLock(false, was_unpaused); + // WARNING: Can only run on Host Thread + bool was_unpaused = Core::PauseAndLock(true); + std::string* _FileName = new std::string(newFileName); + CoreTiming::ScheduleEvent(0, s_eject_disc); + CoreTiming::ScheduleEvent(500000000, s_insert_disc, (u64)_FileName); + if (Movie::IsRecordingInput()) + { + Movie::g_bDiscChange = true; + std::string fileName = newFileName; + auto sizeofpath = fileName.find_last_of("/\\") + 1; + if (fileName.substr(sizeofpath).length() > 40) + { + PanicAlertT("The disc change to \"%s\" could not be saved in the .dtm file.\n" + "The filename of the disc image must not be longer than 40 characters.", + newFileName.c_str()); + } + Movie::g_discChange = fileName.substr(sizeofpath); + } + Core::PauseAndLock(false, was_unpaused); } void SetLidOpen(bool open) { - s_DICVR.CVR = open ? 1 : 0; + s_DICVR.CVR = open ? 1 : 0; - GenerateDIInterrupt(INT_CVRINT); + GenerateDIInterrupt(INT_CVRINT); } bool ChangePartition(u64 offset) { - DVDThread::WaitUntilIdle(); - return s_inserted_volume->ChangePartition(offset); + DVDThread::WaitUntilIdle(); + return s_inserted_volume->ChangePartition(offset); } void RegisterMMIO(MMIO::Mapping* mmio, u32 base) { - mmio->Register(base | DI_STATUS_REGISTER, - MMIO::DirectRead(&s_DISR.Hex), - MMIO::ComplexWrite([](u32, u32 val) { - UDISR tmpStatusReg(val); + mmio->Register(base | DI_STATUS_REGISTER, MMIO::DirectRead(&s_DISR.Hex), + MMIO::ComplexWrite([](u32, u32 val) { + UDISR tmpStatusReg(val); - s_DISR.DEINITMASK = tmpStatusReg.DEINITMASK; - s_DISR.TCINTMASK = tmpStatusReg.TCINTMASK; - s_DISR.BRKINTMASK = tmpStatusReg.BRKINTMASK; - s_DISR.BREAK = tmpStatusReg.BREAK; + s_DISR.DEINITMASK = tmpStatusReg.DEINITMASK; + s_DISR.TCINTMASK = tmpStatusReg.TCINTMASK; + s_DISR.BRKINTMASK = tmpStatusReg.BRKINTMASK; + s_DISR.BREAK = tmpStatusReg.BREAK; - if (tmpStatusReg.DEINT) - s_DISR.DEINT = 0; + if (tmpStatusReg.DEINT) + s_DISR.DEINT = 0; - if (tmpStatusReg.TCINT) - s_DISR.TCINT = 0; + if (tmpStatusReg.TCINT) + s_DISR.TCINT = 0; - if (tmpStatusReg.BRKINT) - s_DISR.BRKINT = 0; + if (tmpStatusReg.BRKINT) + s_DISR.BRKINT = 0; - if (s_DISR.BREAK) - { - _dbg_assert_(DVDINTERFACE, 0); - } + if (s_DISR.BREAK) + { + _dbg_assert_(DVDINTERFACE, 0); + } - UpdateInterrupts(); - }) - ); + UpdateInterrupts(); + })); - mmio->Register(base | DI_COVER_REGISTER, - MMIO::DirectRead(&s_DICVR.Hex), - MMIO::ComplexWrite([](u32, u32 val) { - UDICVR tmpCoverReg(val); + mmio->Register(base | DI_COVER_REGISTER, MMIO::DirectRead(&s_DICVR.Hex), + MMIO::ComplexWrite([](u32, u32 val) { + UDICVR tmpCoverReg(val); - s_DICVR.CVRINTMASK = tmpCoverReg.CVRINTMASK; + s_DICVR.CVRINTMASK = tmpCoverReg.CVRINTMASK; - if (tmpCoverReg.CVRINT) - s_DICVR.CVRINT = 0; + if (tmpCoverReg.CVRINT) + s_DICVR.CVRINT = 0; - UpdateInterrupts(); - }) - ); + UpdateInterrupts(); + })); - // Command registers are very similar and we can register them with a - // simple loop. - for (int i = 0; i < 3; ++i) - mmio->Register(base | (DI_COMMAND_0 + 4 * i), - MMIO::DirectRead(&s_DICMDBUF[i].Hex), - MMIO::DirectWrite(&s_DICMDBUF[i].Hex) - ); + // Command registers are very similar and we can register them with a + // simple loop. + for (int i = 0; i < 3; ++i) + mmio->Register(base | (DI_COMMAND_0 + 4 * i), MMIO::DirectRead(&s_DICMDBUF[i].Hex), + MMIO::DirectWrite(&s_DICMDBUF[i].Hex)); - // DMA related registers. Mostly direct accesses (+ masking for writes to - // handle things like address alignment) and complex write on the DMA - // control register that will trigger the DMA. - mmio->Register(base | DI_DMA_ADDRESS_REGISTER, - MMIO::DirectRead(&s_DIMAR.Hex), - MMIO::DirectWrite(&s_DIMAR.Hex, ~0xFC00001F) - ); - mmio->Register(base | DI_DMA_LENGTH_REGISTER, - MMIO::DirectRead(&s_DILENGTH.Hex), - MMIO::DirectWrite(&s_DILENGTH.Hex, ~0x1F) - ); - mmio->Register(base | DI_DMA_CONTROL_REGISTER, - MMIO::DirectRead(&s_DICR.Hex), - MMIO::ComplexWrite([](u32, u32 val) { - s_DICR.Hex = val & 7; - if (s_DICR.TSTART) - { - ExecuteCommand(s_DICMDBUF[0].Hex, s_DICMDBUF[1].Hex, s_DICMDBUF[2].Hex, - s_DIMAR.Hex, s_DILENGTH.Hex, false); - } - }) - ); + // DMA related registers. Mostly direct accesses (+ masking for writes to + // handle things like address alignment) and complex write on the DMA + // control register that will trigger the DMA. + mmio->Register(base | DI_DMA_ADDRESS_REGISTER, MMIO::DirectRead(&s_DIMAR.Hex), + MMIO::DirectWrite(&s_DIMAR.Hex, ~0xFC00001F)); + mmio->Register(base | DI_DMA_LENGTH_REGISTER, MMIO::DirectRead(&s_DILENGTH.Hex), + MMIO::DirectWrite(&s_DILENGTH.Hex, ~0x1F)); + mmio->Register(base | DI_DMA_CONTROL_REGISTER, MMIO::DirectRead(&s_DICR.Hex), + MMIO::ComplexWrite([](u32, u32 val) { + s_DICR.Hex = val & 7; + if (s_DICR.TSTART) + { + ExecuteCommand(s_DICMDBUF[0].Hex, s_DICMDBUF[1].Hex, s_DICMDBUF[2].Hex, + s_DIMAR.Hex, s_DILENGTH.Hex, false); + } + })); - mmio->Register(base | DI_IMMEDIATE_DATA_BUFFER, - MMIO::DirectRead(&s_DIIMMBUF.Hex), - MMIO::DirectWrite(&s_DIIMMBUF.Hex) - ); + mmio->Register(base | DI_IMMEDIATE_DATA_BUFFER, MMIO::DirectRead(&s_DIIMMBUF.Hex), + MMIO::DirectWrite(&s_DIIMMBUF.Hex)); - // DI config register is read only. - mmio->Register(base | DI_CONFIG_REGISTER, - MMIO::DirectRead(&s_DICFG.Hex), - MMIO::InvalidWrite() - ); + // DI config register is read only. + mmio->Register(base | DI_CONFIG_REGISTER, MMIO::DirectRead(&s_DICFG.Hex), + MMIO::InvalidWrite()); } void UpdateInterrupts() { - if ((s_DISR.DEINT & s_DISR.DEINITMASK) || - (s_DISR.TCINT & s_DISR.TCINTMASK) || - (s_DISR.BRKINT & s_DISR.BRKINTMASK) || - (s_DICVR.CVRINT & s_DICVR.CVRINTMASK)) - { - ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_DI, true); - } - else - { - ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_DI, false); - } + if ((s_DISR.DEINT & s_DISR.DEINITMASK) || (s_DISR.TCINT & s_DISR.TCINTMASK) || + (s_DISR.BRKINT & s_DISR.BRKINTMASK) || (s_DICVR.CVRINT & s_DICVR.CVRINTMASK)) + { + ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_DI, true); + } + else + { + ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_DI, false); + } - // Required for Summoner: A Goddess Reborn - CoreTiming::ForceExceptionCheck(50); + // Required for Summoner: A Goddess Reborn + CoreTiming::ForceExceptionCheck(50); } void GenerateDIInterrupt(DIInterruptType dvd_interrupt) { - switch (dvd_interrupt) - { - case INT_DEINT: s_DISR.DEINT = 1; break; - case INT_TCINT: s_DISR.TCINT = 1; break; - case INT_BRKINT: s_DISR.BRKINT = 1; break; - case INT_CVRINT: s_DICVR.CVRINT = 1; break; - } + switch (dvd_interrupt) + { + case INT_DEINT: + s_DISR.DEINT = 1; + break; + case INT_TCINT: + s_DISR.TCINT = 1; + break; + case INT_BRKINT: + s_DISR.BRKINT = 1; + break; + case INT_CVRINT: + s_DICVR.CVRINT = 1; + break; + } - UpdateInterrupts(); + UpdateInterrupts(); } void WriteImmediate(u32 value, u32 output_address, bool reply_to_ios) { - if (reply_to_ios) - Memory::Write_U32(value, output_address); - else - s_DIIMMBUF.Hex = value; + if (reply_to_ios) + Memory::Write_U32(value, output_address); + else + s_DIIMMBUF.Hex = value; } // Iff false is returned, ScheduleEvent must be used to finish executing the command -bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length, bool decrypt, - bool reply_to_ios, DIInterruptType* interrupt_type, u64* ticks_until_completion) +bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length, + bool decrypt, bool reply_to_ios, DIInterruptType* interrupt_type, + u64* ticks_until_completion) { - if (!s_disc_inside) - { - // Disc read fails - s_error_code = ERROR_NO_DISK | ERROR_COVER_H; - *interrupt_type = INT_DEINT; - return false; - } - else - { - // Disc read succeeds - *interrupt_type = INT_TCINT; - } + if (!s_disc_inside) + { + // Disc read fails + s_error_code = ERROR_NO_DISK | ERROR_COVER_H; + *interrupt_type = INT_DEINT; + return false; + } + else + { + // Disc read succeeds + *interrupt_type = INT_TCINT; + } - if (DVD_length > output_length) - { - WARN_LOG(DVDINTERFACE, "Detected attempt to read more data from the DVD than fit inside the out buffer. Clamp."); - DVD_length = output_length; - } + if (DVD_length > output_length) + { + WARN_LOG( + DVDINTERFACE, + "Detected attempt to read more data from the DVD than fit inside the out buffer. Clamp."); + DVD_length = output_length; + } - if (SConfig::GetInstance().bFastDiscSpeed) - // An optional hack to speed up loading times - *ticks_until_completion = output_length * (SystemTimers::GetTicksPerSecond() / BUFFER_TRANSFER_RATE); - else - *ticks_until_completion = SimulateDiscReadTime(DVD_offset, DVD_length); + if (SConfig::GetInstance().bFastDiscSpeed) + // An optional hack to speed up loading times + *ticks_until_completion = + output_length * (SystemTimers::GetTicksPerSecond() / BUFFER_TRANSFER_RATE); + else + *ticks_until_completion = SimulateDiscReadTime(DVD_offset, DVD_length); - DVDThread::StartRead(DVD_offset, output_address, DVD_length, decrypt, - reply_to_ios, (int)*ticks_until_completion); - return true; + DVDThread::StartRead(DVD_offset, output_address, DVD_length, decrypt, reply_to_ios, + (int)*ticks_until_completion); + return true; } // When the command has finished executing, callback_event_type @@ -677,369 +668,381 @@ bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_address, u32 output_length, bool reply_to_ios) { - DIInterruptType interrupt_type = INT_TCINT; - u64 ticks_until_completion = SystemTimers::GetTicksPerSecond() / 15000; - bool command_handled_by_thread = false; + DIInterruptType interrupt_type = INT_TCINT; + u64 ticks_until_completion = SystemTimers::GetTicksPerSecond() / 15000; + bool command_handled_by_thread = false; - bool GCAM = (SConfig::GetInstance().m_SIDevice[0] == SIDEVICE_AM_BASEBOARD) && - (SConfig::GetInstance().m_EXIDevice[2] == EXIDEVICE_AM_BASEBOARD); + bool GCAM = (SConfig::GetInstance().m_SIDevice[0] == SIDEVICE_AM_BASEBOARD) && + (SConfig::GetInstance().m_EXIDevice[2] == EXIDEVICE_AM_BASEBOARD); - // DVDLowRequestError needs access to the error code set by the previous command - if (command_0 >> 24 != DVDLowRequestError) - s_error_code = 0; + // DVDLowRequestError needs access to the error code set by the previous command + if (command_0 >> 24 != DVDLowRequestError) + s_error_code = 0; - if (GCAM) - { - ERROR_LOG(DVDINTERFACE, "DVD: %08x, %08x, %08x, DMA=addr:%08x,len:%08x,ctrl:%08x", - command_0, command_1, command_2, output_address, output_length, s_DICR.Hex); - // decrypt command. But we have a zero key, that simplifies things a lot. - // If you get crazy dvd command errors, make sure 0x80000000 - 0x8000000c is zero'd - command_0 <<= 24; - } + if (GCAM) + { + ERROR_LOG(DVDINTERFACE, "DVD: %08x, %08x, %08x, DMA=addr:%08x,len:%08x,ctrl:%08x", command_0, + command_1, command_2, output_address, output_length, s_DICR.Hex); + // decrypt command. But we have a zero key, that simplifies things a lot. + // If you get crazy dvd command errors, make sure 0x80000000 - 0x8000000c is zero'd + command_0 <<= 24; + } - switch (command_0 >> 24) - { - // Seems to be used by both GC and Wii - case DVDLowInquiry: - if (GCAM) - { - // 0x29484100... - // was 21 i'm not entirely sure about this, but it works well. - WriteImmediate(0x21000000, output_address, reply_to_ios); - } - else - { - // (shuffle2) Taken from my Wii - Memory::Write_U32(0x00000002, output_address); - Memory::Write_U32(0x20060526, output_address + 4); - // This was in the oubuf even though this cmd is only supposed to reply with 64bits - // However, this and other tests strongly suggest that the buffer is static, and it's never - or rarely cleared. - Memory::Write_U32(0x41000000, output_address + 8); + switch (command_0 >> 24) + { + // Seems to be used by both GC and Wii + case DVDLowInquiry: + if (GCAM) + { + // 0x29484100... + // was 21 i'm not entirely sure about this, but it works well. + WriteImmediate(0x21000000, output_address, reply_to_ios); + } + else + { + // (shuffle2) Taken from my Wii + Memory::Write_U32(0x00000002, output_address); + Memory::Write_U32(0x20060526, output_address + 4); + // This was in the oubuf even though this cmd is only supposed to reply with 64bits + // However, this and other tests strongly suggest that the buffer is static, and it's never - + // or rarely cleared. + Memory::Write_U32(0x41000000, output_address + 8); - INFO_LOG(DVDINTERFACE, "DVDLowInquiry (Buffer 0x%08x, 0x%x)", - output_address, output_length); - } - break; + INFO_LOG(DVDINTERFACE, "DVDLowInquiry (Buffer 0x%08x, 0x%x)", output_address, output_length); + } + break; - // Only seems to be used from WII_IPC, not through direct access - case DVDLowReadDiskID: - INFO_LOG(DVDINTERFACE, "DVDLowReadDiskID"); - command_handled_by_thread = ExecuteReadCommand(0, output_address, 0x20, output_length, false, - reply_to_ios, &interrupt_type, &ticks_until_completion); - break; + // Only seems to be used from WII_IPC, not through direct access + case DVDLowReadDiskID: + INFO_LOG(DVDINTERFACE, "DVDLowReadDiskID"); + command_handled_by_thread = + ExecuteReadCommand(0, output_address, 0x20, output_length, false, reply_to_ios, + &interrupt_type, &ticks_until_completion); + break; - // Only used from WII_IPC. This is the only read command that decrypts data - case DVDLowRead: - INFO_LOG(DVDINTERFACE, "DVDLowRead: DVDAddr: 0x%09" PRIx64 ", Size: 0x%x", (u64)command_2 << 2, command_1); - command_handled_by_thread = ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, true, - reply_to_ios, &interrupt_type, &ticks_until_completion); - break; + // Only used from WII_IPC. This is the only read command that decrypts data + case DVDLowRead: + INFO_LOG(DVDINTERFACE, "DVDLowRead: DVDAddr: 0x%09" PRIx64 ", Size: 0x%x", (u64)command_2 << 2, + command_1); + command_handled_by_thread = + ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, true, + reply_to_ios, &interrupt_type, &ticks_until_completion); + break; - // Probably only used by Wii - case DVDLowWaitForCoverClose: - INFO_LOG(DVDINTERFACE, "DVDLowWaitForCoverClose"); - interrupt_type = (DIInterruptType)4; // ??? - break; + // Probably only used by Wii + case DVDLowWaitForCoverClose: + INFO_LOG(DVDINTERFACE, "DVDLowWaitForCoverClose"); + interrupt_type = (DIInterruptType)4; // ??? + break; - // "Set Extension"...not sure what it does. GC only? - case 0x55: - INFO_LOG(DVDINTERFACE, "SetExtension"); - break; + // "Set Extension"...not sure what it does. GC only? + case 0x55: + INFO_LOG(DVDINTERFACE, "SetExtension"); + break; - // Probably only used though WII_IPC - case DVDLowGetCoverReg: - WriteImmediate(s_DICVR.Hex, output_address, reply_to_ios); - INFO_LOG(DVDINTERFACE, "DVDLowGetCoverReg 0x%08x", s_DICVR.Hex); - break; + // Probably only used though WII_IPC + case DVDLowGetCoverReg: + WriteImmediate(s_DICVR.Hex, output_address, reply_to_ios); + INFO_LOG(DVDINTERFACE, "DVDLowGetCoverReg 0x%08x", s_DICVR.Hex); + break; - // Probably only used by Wii - case DVDLowNotifyReset: - ERROR_LOG(DVDINTERFACE, "DVDLowNotifyReset"); - PanicAlert("DVDLowNotifyReset"); - break; - // Probably only used by Wii - case DVDLowReadDvdPhysical: - ERROR_LOG(DVDINTERFACE, "DVDLowReadDvdPhysical"); - PanicAlert("DVDLowReadDvdPhysical"); - break; - // Probably only used by Wii - case DVDLowReadDvdCopyright: - ERROR_LOG(DVDINTERFACE, "DVDLowReadDvdCopyright"); - PanicAlert("DVDLowReadDvdCopyright"); - break; - // Probably only used by Wii - case DVDLowReadDvdDiscKey: - ERROR_LOG(DVDINTERFACE, "DVDLowReadDvdDiscKey"); - PanicAlert("DVDLowReadDvdDiscKey"); - break; + // Probably only used by Wii + case DVDLowNotifyReset: + ERROR_LOG(DVDINTERFACE, "DVDLowNotifyReset"); + PanicAlert("DVDLowNotifyReset"); + break; + // Probably only used by Wii + case DVDLowReadDvdPhysical: + ERROR_LOG(DVDINTERFACE, "DVDLowReadDvdPhysical"); + PanicAlert("DVDLowReadDvdPhysical"); + break; + // Probably only used by Wii + case DVDLowReadDvdCopyright: + ERROR_LOG(DVDINTERFACE, "DVDLowReadDvdCopyright"); + PanicAlert("DVDLowReadDvdCopyright"); + break; + // Probably only used by Wii + case DVDLowReadDvdDiscKey: + ERROR_LOG(DVDINTERFACE, "DVDLowReadDvdDiscKey"); + PanicAlert("DVDLowReadDvdDiscKey"); + break; - // Probably only used by Wii - case DVDLowClearCoverInterrupt: - INFO_LOG(DVDINTERFACE, "DVDLowClearCoverInterrupt"); - s_DICVR.CVRINT = 0; - break; + // Probably only used by Wii + case DVDLowClearCoverInterrupt: + INFO_LOG(DVDINTERFACE, "DVDLowClearCoverInterrupt"); + s_DICVR.CVRINT = 0; + break; - // Probably only used by Wii - case DVDLowGetCoverStatus: - WriteImmediate(s_disc_inside ? 2 : 1, output_address, reply_to_ios); - INFO_LOG(DVDINTERFACE, "DVDLowGetCoverStatus: Disc %sInserted", s_disc_inside ? "" : "Not "); - break; + // Probably only used by Wii + case DVDLowGetCoverStatus: + WriteImmediate(s_disc_inside ? 2 : 1, output_address, reply_to_ios); + INFO_LOG(DVDINTERFACE, "DVDLowGetCoverStatus: Disc %sInserted", s_disc_inside ? "" : "Not "); + break; - // Probably only used by Wii - case DVDLowReset: - INFO_LOG(DVDINTERFACE, "DVDLowReset"); - break; + // Probably only used by Wii + case DVDLowReset: + INFO_LOG(DVDINTERFACE, "DVDLowReset"); + break; - // Probably only used by Wii - case DVDLowClosePartition: - INFO_LOG(DVDINTERFACE, "DVDLowClosePartition"); - break; + // Probably only used by Wii + case DVDLowClosePartition: + INFO_LOG(DVDINTERFACE, "DVDLowClosePartition"); + break; - // Probably only used by Wii - case DVDLowUnencryptedRead: - INFO_LOG(DVDINTERFACE, "DVDLowUnencryptedRead: DVDAddr: 0x%09" PRIx64 ", Size: 0x%x", (u64)command_2 << 2, command_1); + // Probably only used by Wii + case DVDLowUnencryptedRead: + INFO_LOG(DVDINTERFACE, "DVDLowUnencryptedRead: DVDAddr: 0x%09" PRIx64 ", Size: 0x%x", + (u64)command_2 << 2, command_1); - // We must make sure it is in a valid area! (#001 check) - // Are these checks correct? They seem to mix 32-bit offsets and 8-bit lengths - // * 0x00000000 - 0x00014000 (limit of older IOS versions) - // * 0x460a0000 - 0x460a0008 - // * 0x7ed40000 - 0x7ed40008 - if (((command_2 > 0x00000000 && command_2 < 0x00014000) || - (((command_2 + command_1) > 0x00000000) && (command_2 + command_1) < 0x00014000) || - (command_2 > 0x460a0000 && command_2 < 0x460a0008) || - (((command_2 + command_1) > 0x460a0000) && (command_2 + command_1) < 0x460a0008) || - (command_2 > 0x7ed40000 && command_2 < 0x7ed40008) || - (((command_2 + command_1) > 0x7ed40000) && (command_2 + command_1) < 0x7ed40008))) - { - command_handled_by_thread = ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, false, - reply_to_ios, &interrupt_type, &ticks_until_completion); - } - else - { - WARN_LOG(DVDINTERFACE, "DVDLowUnencryptedRead: trying to read out of bounds @ %09" PRIx64, (u64)command_2 << 2); - s_error_code = ERROR_READY | ERROR_BLOCK_OOB; - // Should cause software to call DVDLowRequestError - interrupt_type = INT_BRKINT; - } + // We must make sure it is in a valid area! (#001 check) + // Are these checks correct? They seem to mix 32-bit offsets and 8-bit lengths + // * 0x00000000 - 0x00014000 (limit of older IOS versions) + // * 0x460a0000 - 0x460a0008 + // * 0x7ed40000 - 0x7ed40008 + if (((command_2 > 0x00000000 && command_2 < 0x00014000) || + (((command_2 + command_1) > 0x00000000) && (command_2 + command_1) < 0x00014000) || + (command_2 > 0x460a0000 && command_2 < 0x460a0008) || + (((command_2 + command_1) > 0x460a0000) && (command_2 + command_1) < 0x460a0008) || + (command_2 > 0x7ed40000 && command_2 < 0x7ed40008) || + (((command_2 + command_1) > 0x7ed40000) && (command_2 + command_1) < 0x7ed40008))) + { + command_handled_by_thread = + ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, false, + reply_to_ios, &interrupt_type, &ticks_until_completion); + } + else + { + WARN_LOG(DVDINTERFACE, "DVDLowUnencryptedRead: trying to read out of bounds @ %09" PRIx64, + (u64)command_2 << 2); + s_error_code = ERROR_READY | ERROR_BLOCK_OOB; + // Should cause software to call DVDLowRequestError + interrupt_type = INT_BRKINT; + } - break; + break; - // Probably only used by Wii - case DVDLowEnableDvdVideo: - ERROR_LOG(DVDINTERFACE, "DVDLowEnableDvdVideo"); - break; + // Probably only used by Wii + case DVDLowEnableDvdVideo: + ERROR_LOG(DVDINTERFACE, "DVDLowEnableDvdVideo"); + break; - // New Super Mario Bros. Wii sends these commands, - // but it seems we don't need to implement anything. - // Probably only used by Wii - case 0x95: - case 0x96: - ERROR_LOG(DVDINTERFACE, "Unimplemented BCA command 0x%08x (Buffer 0x%08x, 0x%x)", - command_0, output_address, output_length); - break; + // New Super Mario Bros. Wii sends these commands, + // but it seems we don't need to implement anything. + // Probably only used by Wii + case 0x95: + case 0x96: + ERROR_LOG(DVDINTERFACE, "Unimplemented BCA command 0x%08x (Buffer 0x%08x, 0x%x)", command_0, + output_address, output_length); + break; - // Probably only used by Wii - case DVDLowReportKey: - INFO_LOG(DVDINTERFACE, "DVDLowReportKey"); - // Does not work on retail discs/drives - // Retail games send this command to see if they are running on real retail hw - s_error_code = ERROR_READY | ERROR_INV_CMD; - interrupt_type = INT_BRKINT; - break; + // Probably only used by Wii + case DVDLowReportKey: + INFO_LOG(DVDINTERFACE, "DVDLowReportKey"); + // Does not work on retail discs/drives + // Retail games send this command to see if they are running on real retail hw + s_error_code = ERROR_READY | ERROR_INV_CMD; + interrupt_type = INT_BRKINT; + break; - // DMA Read from Disc. Only seems to be used through direct access, not WII_IPC - case 0xA8: - switch (command_0 & 0xFF) - { - case 0x00: // Read Sector - { - u64 iDVDOffset = (u64)command_1 << 2; + // DMA Read from Disc. Only seems to be used through direct access, not WII_IPC + case 0xA8: + switch (command_0 & 0xFF) + { + case 0x00: // Read Sector + { + u64 iDVDOffset = (u64)command_1 << 2; - INFO_LOG(DVDINTERFACE, "Read: DVDOffset=%08" PRIx64 ", DMABuffer = %08x, SrcLength = %08x, DMALength = %08x", - iDVDOffset, output_address, command_2, output_length); + INFO_LOG(DVDINTERFACE, "Read: DVDOffset=%08" PRIx64 + ", DMABuffer = %08x, SrcLength = %08x, DMALength = %08x", + iDVDOffset, output_address, command_2, output_length); - if (GCAM) - { - if (iDVDOffset & 0x80000000) // read request to hardware buffer - { - switch (iDVDOffset) - { - case 0x80000000: - ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (80000000)"); - for (u32 i = 0; i < output_length; i += 4) - Memory::Write_U32(0, output_address + i); - break; - case 0x80000040: - ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (2) (80000040)"); - for (u32 i = 0; i < output_length; i += 4) - Memory::Write_U32(~0, output_address + i); - Memory::Write_U32(0x00000020, output_address); // DIMM SIZE, LE - Memory::Write_U32(0x4743414D, output_address + 4); // GCAM signature - break; - case 0x80000120: - ERROR_LOG(DVDINTERFACE, "GC-AM: READ FIRMWARE STATUS (80000120)"); - for (u32 i = 0; i < output_length; i += 4) - Memory::Write_U32(0x01010101, output_address + i); - break; - case 0x80000140: - ERROR_LOG(DVDINTERFACE, "GC-AM: READ FIRMWARE STATUS (80000140)"); - for (u32 i = 0; i < output_length; i += 4) - Memory::Write_U32(0x01010101, output_address + i); - break; - case 0x84000020: - ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (1) (84000020)"); - for (u32 i = 0; i < output_length; i += 4) - Memory::Write_U32(0x00000000, output_address + i); - break; - default: - ERROR_LOG(DVDINTERFACE, "GC-AM: UNKNOWN MEDIA BOARD LOCATION %" PRIx64, iDVDOffset); - break; - } - break; - } - else if ((iDVDOffset == 0x1f900000) || (iDVDOffset == 0x1f900020)) - { - ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD COMM AREA (1f900020)"); - u8* source = s_media_buffer + iDVDOffset - 0x1f900000; - Memory::CopyToEmu(output_address, source, output_length); - for (u32 i = 0; i < output_length; i += 4) - ERROR_LOG(DVDINTERFACE, "GC-AM: %08x", Memory::Read_U32(output_address + i)); - break; - } - } + if (GCAM) + { + if (iDVDOffset & 0x80000000) // read request to hardware buffer + { + switch (iDVDOffset) + { + case 0x80000000: + ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (80000000)"); + for (u32 i = 0; i < output_length; i += 4) + Memory::Write_U32(0, output_address + i); + break; + case 0x80000040: + ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (2) (80000040)"); + for (u32 i = 0; i < output_length; i += 4) + Memory::Write_U32(~0, output_address + i); + Memory::Write_U32(0x00000020, output_address); // DIMM SIZE, LE + Memory::Write_U32(0x4743414D, output_address + 4); // GCAM signature + break; + case 0x80000120: + ERROR_LOG(DVDINTERFACE, "GC-AM: READ FIRMWARE STATUS (80000120)"); + for (u32 i = 0; i < output_length; i += 4) + Memory::Write_U32(0x01010101, output_address + i); + break; + case 0x80000140: + ERROR_LOG(DVDINTERFACE, "GC-AM: READ FIRMWARE STATUS (80000140)"); + for (u32 i = 0; i < output_length; i += 4) + Memory::Write_U32(0x01010101, output_address + i); + break; + case 0x84000020: + ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (1) (84000020)"); + for (u32 i = 0; i < output_length; i += 4) + Memory::Write_U32(0x00000000, output_address + i); + break; + default: + ERROR_LOG(DVDINTERFACE, "GC-AM: UNKNOWN MEDIA BOARD LOCATION %" PRIx64, iDVDOffset); + break; + } + break; + } + else if ((iDVDOffset == 0x1f900000) || (iDVDOffset == 0x1f900020)) + { + ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD COMM AREA (1f900020)"); + u8* source = s_media_buffer + iDVDOffset - 0x1f900000; + Memory::CopyToEmu(output_address, source, output_length); + for (u32 i = 0; i < output_length; i += 4) + ERROR_LOG(DVDINTERFACE, "GC-AM: %08x", Memory::Read_U32(output_address + i)); + break; + } + } - command_handled_by_thread = ExecuteReadCommand(iDVDOffset, output_address, command_2, output_length, false, - reply_to_ios, &interrupt_type, &ticks_until_completion); - } - break; + command_handled_by_thread = + ExecuteReadCommand(iDVDOffset, output_address, command_2, output_length, false, + reply_to_ios, &interrupt_type, &ticks_until_completion); + } + break; - case 0x40: // Read DiscID - INFO_LOG(DVDINTERFACE, "Read DiscID %08x", Memory::Read_U32(output_address)); - command_handled_by_thread = ExecuteReadCommand(0, output_address, 0x20, output_length, false, - reply_to_ios, &interrupt_type, &ticks_until_completion); - break; + case 0x40: // Read DiscID + INFO_LOG(DVDINTERFACE, "Read DiscID %08x", Memory::Read_U32(output_address)); + command_handled_by_thread = + ExecuteReadCommand(0, output_address, 0x20, output_length, false, reply_to_ios, + &interrupt_type, &ticks_until_completion); + break; - default: - ERROR_LOG(DVDINTERFACE, "Unknown read subcommand: %08x", command_0); - break; - } - break; + default: + ERROR_LOG(DVDINTERFACE, "Unknown read subcommand: %08x", command_0); + break; + } + break; - // GC-AM only - case 0xAA: - if (GCAM) - { - ERROR_LOG(DVDINTERFACE, "GC-AM: 0xAA, DMABuffer=%08x, DMALength=%08x", output_address, output_length); - u64 iDVDOffset = (u64)command_1 << 2; - u32 len = output_length; - s64 offset = iDVDOffset - 0x1F900000; - /* - if (iDVDOffset == 0x84800000) - { - ERROR_LOG(DVDINTERFACE, "Firmware upload"); - } - else*/ - if ((offset < 0) || ((offset + len) > 0x40) || len > 0x40) - { - u32 addr = output_address; - if (iDVDOffset == 0x84800000) - { - ERROR_LOG(DVDINTERFACE, "FIRMWARE UPLOAD"); - } - else - { - ERROR_LOG(DVDINTERFACE, "ILLEGAL MEDIA WRITE"); - } + // GC-AM only + case 0xAA: + if (GCAM) + { + ERROR_LOG(DVDINTERFACE, "GC-AM: 0xAA, DMABuffer=%08x, DMALength=%08x", output_address, + output_length); + u64 iDVDOffset = (u64)command_1 << 2; + u32 len = output_length; + s64 offset = iDVDOffset - 0x1F900000; + /* + if (iDVDOffset == 0x84800000) + { + ERROR_LOG(DVDINTERFACE, "Firmware upload"); + } + else*/ + if ((offset < 0) || ((offset + len) > 0x40) || len > 0x40) + { + u32 addr = output_address; + if (iDVDOffset == 0x84800000) + { + ERROR_LOG(DVDINTERFACE, "FIRMWARE UPLOAD"); + } + else + { + ERROR_LOG(DVDINTERFACE, "ILLEGAL MEDIA WRITE"); + } - while (len >= 4) - { - ERROR_LOG(DVDINTERFACE, "GC-AM Media Board WRITE (0xAA): %08" PRIx64 ": %08x", iDVDOffset, Memory::Read_U32(addr)); - addr += 4; - len -= 4; - iDVDOffset += 4; - } - } - else - { - u32 addr = s_DIMAR.Address; - Memory::CopyFromEmu(s_media_buffer + offset, addr, len); - while (len >= 4) - { - ERROR_LOG(DVDINTERFACE, "GC-AM Media Board WRITE (0xAA): %08" PRIx64 ": %08x", iDVDOffset, Memory::Read_U32(addr)); - addr += 4; - len -= 4; - iDVDOffset += 4; - } - } - } - break; + while (len >= 4) + { + ERROR_LOG(DVDINTERFACE, "GC-AM Media Board WRITE (0xAA): %08" PRIx64 ": %08x", iDVDOffset, + Memory::Read_U32(addr)); + addr += 4; + len -= 4; + iDVDOffset += 4; + } + } + else + { + u32 addr = s_DIMAR.Address; + Memory::CopyFromEmu(s_media_buffer + offset, addr, len); + while (len >= 4) + { + ERROR_LOG(DVDINTERFACE, "GC-AM Media Board WRITE (0xAA): %08" PRIx64 ": %08x", iDVDOffset, + Memory::Read_U32(addr)); + addr += 4; + len -= 4; + iDVDOffset += 4; + } + } + } + break; - // Seems to be used by both GC and Wii - case DVDLowSeek: - if (!GCAM) - { - // Currently unimplemented - INFO_LOG(DVDINTERFACE, "Seek: offset=%09" PRIx64 " (ignoring)", (u64)command_1 << 2); - } - else - { - memset(s_media_buffer, 0, 0x20); - s_media_buffer[0] = s_media_buffer[0x20]; // ID - s_media_buffer[2] = s_media_buffer[0x22]; - s_media_buffer[3] = s_media_buffer[0x23] | 0x80; - int cmd = (s_media_buffer[0x23]<<8)|s_media_buffer[0x22]; - ERROR_LOG(DVDINTERFACE, "GC-AM: execute buffer, cmd=%04x", cmd); - switch (cmd) - { - case 0x00: - s_media_buffer[4] = 1; - break; - case 0x1: - s_media_buffer[7] = 0x20; // DIMM Size - break; - case 0x100: - { - // urgh - static int percentage = 0; - static int status = 0; - percentage++; - if (percentage > 100) - { - status++; - percentage = 0; - } - s_media_buffer[4] = status; - /* status: - 0 - "Initializing media board. Please wait.." - 1 - "Checking network. Please wait..." - 2 - "Found a system disc. Insert a game disc" - 3 - "Testing a game program. %d%%" - 4 - "Loading a game program. %d%%" - 5 - go - 6 - error xx - */ - s_media_buffer[8] = percentage; - s_media_buffer[4] = 0x05; - s_media_buffer[8] = 0x64; - break; - } - case 0x101: - s_media_buffer[4] = 3; // version - s_media_buffer[5] = 3; - s_media_buffer[6] = 1; // xxx - s_media_buffer[8] = 1; - s_media_buffer[16] = 0xFF; - s_media_buffer[17] = 0xFF; - s_media_buffer[18] = 0xFF; - s_media_buffer[19] = 0xFF; - break; - case 0x102: // get error code - s_media_buffer[4] = 1; // 0: download incomplete (31), 1: corrupted, other error 1 - s_media_buffer[5] = 0; - break; - case 0x103: - memcpy(s_media_buffer + 4, "A89E27A50364511", 15); // serial - break; + // Seems to be used by both GC and Wii + case DVDLowSeek: + if (!GCAM) + { + // Currently unimplemented + INFO_LOG(DVDINTERFACE, "Seek: offset=%09" PRIx64 " (ignoring)", (u64)command_1 << 2); + } + else + { + memset(s_media_buffer, 0, 0x20); + s_media_buffer[0] = s_media_buffer[0x20]; // ID + s_media_buffer[2] = s_media_buffer[0x22]; + s_media_buffer[3] = s_media_buffer[0x23] | 0x80; + int cmd = (s_media_buffer[0x23] << 8) | s_media_buffer[0x22]; + ERROR_LOG(DVDINTERFACE, "GC-AM: execute buffer, cmd=%04x", cmd); + switch (cmd) + { + case 0x00: + s_media_buffer[4] = 1; + break; + case 0x1: + s_media_buffer[7] = 0x20; // DIMM Size + break; + case 0x100: + { + // urgh + static int percentage = 0; + static int status = 0; + percentage++; + if (percentage > 100) + { + status++; + percentage = 0; + } + s_media_buffer[4] = status; + /* status: + 0 - "Initializing media board. Please wait.." + 1 - "Checking network. Please wait..." + 2 - "Found a system disc. Insert a game disc" + 3 - "Testing a game program. %d%%" + 4 - "Loading a game program. %d%%" + 5 - go + 6 - error xx + */ + s_media_buffer[8] = percentage; + s_media_buffer[4] = 0x05; + s_media_buffer[8] = 0x64; + break; + } + case 0x101: + s_media_buffer[4] = 3; // version + s_media_buffer[5] = 3; + s_media_buffer[6] = 1; // xxx + s_media_buffer[8] = 1; + s_media_buffer[16] = 0xFF; + s_media_buffer[17] = 0xFF; + s_media_buffer[18] = 0xFF; + s_media_buffer[19] = 0xFF; + break; + case 0x102: // get error code + s_media_buffer[4] = 1; // 0: download incomplete (31), 1: corrupted, other error 1 + s_media_buffer[5] = 0; + break; + case 0x103: + memcpy(s_media_buffer + 4, "A89E27A50364511", 15); // serial + break; #if 0 case 0x301: // unknown memcpy(s_media_buffer + 4, s_media_buffer + 0x24, 0x1c); @@ -1047,243 +1050,245 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr case 0x302: break; #endif - default: - ERROR_LOG(DVDINTERFACE, "GC-AM: execute buffer (unknown)"); - break; - } - memset(s_media_buffer + 0x20, 0, 0x20); - WriteImmediate(0x66556677, output_address, reply_to_ios); // just a random value that works. - } - break; + default: + ERROR_LOG(DVDINTERFACE, "GC-AM: execute buffer (unknown)"); + break; + } + memset(s_media_buffer + 0x20, 0, 0x20); + WriteImmediate(0x66556677, output_address, reply_to_ios); // just a random value that works. + } + break; - // Probably only used by Wii - case DVDLowReadDvd: - ERROR_LOG(DVDINTERFACE, "DVDLowReadDvd"); - break; - // Probably only used by Wii - case DVDLowReadDvdConfig: - ERROR_LOG(DVDINTERFACE, "DVDLowReadDvdConfig"); - break; - // Probably only used by Wii - case DVDLowStopLaser: - ERROR_LOG(DVDINTERFACE, "DVDLowStopLaser"); - break; - // Probably only used by Wii - case DVDLowOffset: - ERROR_LOG(DVDINTERFACE, "DVDLowOffset"); - break; - // Probably only used by Wii - case DVDLowReadDiskBca: - WARN_LOG(DVDINTERFACE, "DVDLowReadDiskBca"); - Memory::Write_U32(1, output_address + 0x30); - break; - // Probably only used by Wii - case DVDLowRequestDiscStatus: - ERROR_LOG(DVDINTERFACE, "DVDLowRequestDiscStatus"); - break; - // Probably only used by Wii - case DVDLowRequestRetryNumber: - ERROR_LOG(DVDINTERFACE, "DVDLowRequestRetryNumber"); - break; - // Probably only used by Wii - case DVDLowSetMaximumRotation: - ERROR_LOG(DVDINTERFACE, "DVDLowSetMaximumRotation"); - break; - // Probably only used by Wii - case DVDLowSerMeasControl: - ERROR_LOG(DVDINTERFACE, "DVDLowSerMeasControl"); - break; + // Probably only used by Wii + case DVDLowReadDvd: + ERROR_LOG(DVDINTERFACE, "DVDLowReadDvd"); + break; + // Probably only used by Wii + case DVDLowReadDvdConfig: + ERROR_LOG(DVDINTERFACE, "DVDLowReadDvdConfig"); + break; + // Probably only used by Wii + case DVDLowStopLaser: + ERROR_LOG(DVDINTERFACE, "DVDLowStopLaser"); + break; + // Probably only used by Wii + case DVDLowOffset: + ERROR_LOG(DVDINTERFACE, "DVDLowOffset"); + break; + // Probably only used by Wii + case DVDLowReadDiskBca: + WARN_LOG(DVDINTERFACE, "DVDLowReadDiskBca"); + Memory::Write_U32(1, output_address + 0x30); + break; + // Probably only used by Wii + case DVDLowRequestDiscStatus: + ERROR_LOG(DVDINTERFACE, "DVDLowRequestDiscStatus"); + break; + // Probably only used by Wii + case DVDLowRequestRetryNumber: + ERROR_LOG(DVDINTERFACE, "DVDLowRequestRetryNumber"); + break; + // Probably only used by Wii + case DVDLowSetMaximumRotation: + ERROR_LOG(DVDINTERFACE, "DVDLowSetMaximumRotation"); + break; + // Probably only used by Wii + case DVDLowSerMeasControl: + ERROR_LOG(DVDINTERFACE, "DVDLowSerMeasControl"); + break; - // Used by both GC and Wii - case DVDLowRequestError: - INFO_LOG(DVDINTERFACE, "Requesting error... (0x%08x)", s_error_code); - WriteImmediate(s_error_code, output_address, reply_to_ios); - s_error_code = 0; - break; + // Used by both GC and Wii + case DVDLowRequestError: + INFO_LOG(DVDINTERFACE, "Requesting error... (0x%08x)", s_error_code); + WriteImmediate(s_error_code, output_address, reply_to_ios); + s_error_code = 0; + break; - // Audio Stream (Immediate). Only seems to be used by some GC games - // (command_0 >> 16) & 0xFF = Subcommand - // command_1 << 2 = Offset on disc - // command_2 = Length of the stream - case 0xE1: - { - u8 cancel_stream = (command_0 >> 16) & 0xFF; - if (cancel_stream) - { - s_stop_at_track_end = false; - s_stream = false; - s_audio_position = 0; - s_next_start = 0; - s_next_length = 0; - s_current_start = 0; - s_current_length = 0; - } - else - { - if ((command_1 == 0) && (command_2 == 0)) - { - s_stop_at_track_end = true; - } - else if (!s_stop_at_track_end) - { - // Setting s_next_start (a u32) like this discards two bits, - // but GC games can't be 4 GiB big, so it shouldn't matter - s_next_start = command_1 << 2; - s_next_length = command_2; - if (!s_stream) - { - s_current_start = s_next_start; - s_current_length = s_next_length; - s_audio_position = s_current_start; - StreamADPCM::InitFilter(); - s_stream = true; - } - } - } + // Audio Stream (Immediate). Only seems to be used by some GC games + // (command_0 >> 16) & 0xFF = Subcommand + // command_1 << 2 = Offset on disc + // command_2 = Length of the stream + case 0xE1: + { + u8 cancel_stream = (command_0 >> 16) & 0xFF; + if (cancel_stream) + { + s_stop_at_track_end = false; + s_stream = false; + s_audio_position = 0; + s_next_start = 0; + s_next_length = 0; + s_current_start = 0; + s_current_length = 0; + } + else + { + if ((command_1 == 0) && (command_2 == 0)) + { + s_stop_at_track_end = true; + } + else if (!s_stop_at_track_end) + { + // Setting s_next_start (a u32) like this discards two bits, + // but GC games can't be 4 GiB big, so it shouldn't matter + s_next_start = command_1 << 2; + s_next_length = command_2; + if (!s_stream) + { + s_current_start = s_next_start; + s_current_length = s_next_length; + s_audio_position = s_current_start; + StreamADPCM::InitFilter(); + s_stream = true; + } + } + } - INFO_LOG(DVDINTERFACE, "(Audio) Stream cmd: %08x offset: %08" PRIx64 " length: %08x", - command_0, (u64)command_1 << 2, command_2); - } - break; + INFO_LOG(DVDINTERFACE, "(Audio) Stream cmd: %08x offset: %08" PRIx64 " length: %08x", command_0, + (u64)command_1 << 2, command_2); + } + break; - // Request Audio Status (Immediate). Only seems to be used by some GC games - case 0xE2: - { - switch (command_0 >> 16 & 0xFF) - { - case 0x00: // Returns streaming status - INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status AudioPos:%08x/%08x CurrentStart:%08x CurrentLength:%08x", - s_audio_position, s_current_start + s_current_length, s_current_start, s_current_length); - WriteImmediate(s_stream ? 1 : 0, output_address, reply_to_ios); - break; - case 0x01: // Returns the current offset - INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status AudioPos:%08x", s_audio_position); - WriteImmediate(s_audio_position >> 2, output_address, reply_to_ios); - break; - case 0x02: // Returns the start offset - INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentStart:%08x", s_current_start); - WriteImmediate(s_current_start >> 2, output_address, reply_to_ios); - break; - case 0x03: // Returns the total length - INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentLength:%08x", s_current_length); - WriteImmediate(s_current_length >> 2, output_address, reply_to_ios); - break; - default: - WARN_LOG(DVDINTERFACE, "(Audio): Subcommand: %02x Request Audio status %s", command_0 >> 16 & 0xFF, s_stream ? "on" : "off"); - break; - } - } - break; + // Request Audio Status (Immediate). Only seems to be used by some GC games + case 0xE2: + { + switch (command_0 >> 16 & 0xFF) + { + case 0x00: // Returns streaming status + INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status AudioPos:%08x/%08x " + "CurrentStart:%08x CurrentLength:%08x", + s_audio_position, s_current_start + s_current_length, s_current_start, + s_current_length); + WriteImmediate(s_stream ? 1 : 0, output_address, reply_to_ios); + break; + case 0x01: // Returns the current offset + INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status AudioPos:%08x", + s_audio_position); + WriteImmediate(s_audio_position >> 2, output_address, reply_to_ios); + break; + case 0x02: // Returns the start offset + INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentStart:%08x", + s_current_start); + WriteImmediate(s_current_start >> 2, output_address, reply_to_ios); + break; + case 0x03: // Returns the total length + INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentLength:%08x", + s_current_length); + WriteImmediate(s_current_length >> 2, output_address, reply_to_ios); + break; + default: + WARN_LOG(DVDINTERFACE, "(Audio): Subcommand: %02x Request Audio status %s", + command_0 >> 16 & 0xFF, s_stream ? "on" : "off"); + break; + } + } + break; - case DVDLowStopMotor: - INFO_LOG(DVDINTERFACE, "DVDLowStopMotor %s %s", - command_1 ? "eject" : "", command_2 ? "kill!" : ""); + case DVDLowStopMotor: + INFO_LOG(DVDINTERFACE, "DVDLowStopMotor %s %s", command_1 ? "eject" : "", + command_2 ? "kill!" : ""); - if (command_1 && !command_2) - EjectDiscCallback(0, 0); - break; + if (command_1 && !command_2) + EjectDiscCallback(0, 0); + break; - // DVD Audio Enable/Disable (Immediate). GC uses this, and apparently Wii also does...? - case DVDLowAudioBufferConfig: - // For more information: http://www.crazynation.org/GC/GC_DD_TECH/GCTech.htm (dead link?) - // - // Upon Power up or reset , 2 commands must be issued for proper use of audio streaming: - // DVDReadDiskID A8000040,00000000,00000020 - // DVDLowAudioBufferConfig E4xx00yy,00000000,00000020 - // - // xx=byte 8 [0 or 1] from the disk header retrieved from DVDReadDiskID - // yy=0 (if xx=0) or 0xA (if xx=1) + // DVD Audio Enable/Disable (Immediate). GC uses this, and apparently Wii also does...? + case DVDLowAudioBufferConfig: + // For more information: http://www.crazynation.org/GC/GC_DD_TECH/GCTech.htm (dead link?) + // + // Upon Power up or reset , 2 commands must be issued for proper use of audio streaming: + // DVDReadDiskID A8000040,00000000,00000020 + // DVDLowAudioBufferConfig E4xx00yy,00000000,00000020 + // + // xx=byte 8 [0 or 1] from the disk header retrieved from DVDReadDiskID + // yy=0 (if xx=0) or 0xA (if xx=1) - if ((command_0 >> 16) & 0xFF) - { - // TODO: What is this actually supposed to do? - s_stream = true; - WARN_LOG(DVDINTERFACE, "(Audio): Audio enabled"); - } - else - { - // TODO: What is this actually supposed to do? - s_stream = false; - WARN_LOG(DVDINTERFACE, "(Audio): Audio disabled"); - } - break; + if ((command_0 >> 16) & 0xFF) + { + // TODO: What is this actually supposed to do? + s_stream = true; + WARN_LOG(DVDINTERFACE, "(Audio): Audio enabled"); + } + else + { + // TODO: What is this actually supposed to do? + s_stream = false; + WARN_LOG(DVDINTERFACE, "(Audio): Audio disabled"); + } + break; - // yet another (GC?) command we prolly don't care about - case 0xEE: - INFO_LOG(DVDINTERFACE, "SetStatus"); - break; + // yet another (GC?) command we prolly don't care about + case 0xEE: + INFO_LOG(DVDINTERFACE, "SetStatus"); + break; - // Debug commands; see yagcd. We don't really care - // NOTE: commands to stream data will send...a raw data stream - // This will appear as unknown commands, unless the check is re-instated to catch such data. - // Can probably only be used through direct access - case 0xFE: - ERROR_LOG(DVDINTERFACE, "Unsupported DVD Drive debug command 0x%08x", command_0); - break; + // Debug commands; see yagcd. We don't really care + // NOTE: commands to stream data will send...a raw data stream + // This will appear as unknown commands, unless the check is re-instated to catch such data. + // Can probably only be used through direct access + case 0xFE: + ERROR_LOG(DVDINTERFACE, "Unsupported DVD Drive debug command 0x%08x", command_0); + break; - // Unlock Commands. 1: "MATSHITA" 2: "DVD-GAME" - // Just for fun - // Can probably only be used through direct access - case 0xFF: - { - if (command_0 == 0xFF014D41 && - command_1 == 0x54534849 && - command_2 == 0x54410200) - { - INFO_LOG(DVDINTERFACE, "Unlock test 1 passed"); - } - else if (command_0 == 0xFF004456 && - command_1 == 0x442D4741 && - command_2 == 0x4D450300) - { - INFO_LOG(DVDINTERFACE, "Unlock test 2 passed"); - } - else - { - INFO_LOG(DVDINTERFACE, "Unlock test failed"); - } - } - break; + // Unlock Commands. 1: "MATSHITA" 2: "DVD-GAME" + // Just for fun + // Can probably only be used through direct access + case 0xFF: + { + if (command_0 == 0xFF014D41 && command_1 == 0x54534849 && command_2 == 0x54410200) + { + INFO_LOG(DVDINTERFACE, "Unlock test 1 passed"); + } + else if (command_0 == 0xFF004456 && command_1 == 0x442D4741 && command_2 == 0x4D450300) + { + INFO_LOG(DVDINTERFACE, "Unlock test 2 passed"); + } + else + { + INFO_LOG(DVDINTERFACE, "Unlock test failed"); + } + } + break; - default: - ERROR_LOG(DVDINTERFACE, "Unknown command 0x%08x (Buffer 0x%08x, 0x%x)", - command_0, output_address, output_length); - PanicAlertT("Unknown DVD command %08x - fatal error", command_0); - break; - } + default: + ERROR_LOG(DVDINTERFACE, "Unknown command 0x%08x (Buffer 0x%08x, 0x%x)", command_0, + output_address, output_length); + PanicAlertT("Unknown DVD command %08x - fatal error", command_0); + break; + } - // The command will finish executing after a delay - // to simulate the speed of a real disc drive - if (!command_handled_by_thread) - { - u64 userdata = (static_cast(reply_to_ios) << 32) + static_cast(interrupt_type); - CoreTiming::ScheduleEvent((int)ticks_until_completion, s_finish_executing_command, userdata); - } + // The command will finish executing after a delay + // to simulate the speed of a real disc drive + if (!command_handled_by_thread) + { + u64 userdata = (static_cast(reply_to_ios) << 32) + static_cast(interrupt_type); + CoreTiming::ScheduleEvent((int)ticks_until_completion, s_finish_executing_command, userdata); + } } void FinishExecutingCommandCallback(u64 userdata, s64 cycles_late) { - bool reply_to_ios = userdata >> 32 != 0; - DIInterruptType interrupt_type = static_cast(userdata & 0xFFFFFFFF); - FinishExecutingCommand(reply_to_ios, interrupt_type); + bool reply_to_ios = userdata >> 32 != 0; + DIInterruptType interrupt_type = static_cast(userdata & 0xFFFFFFFF); + FinishExecutingCommand(reply_to_ios, interrupt_type); } void FinishExecutingCommand(bool reply_to_ios, DIInterruptType interrupt_type) { - if (reply_to_ios) - { - std::shared_ptr di = WII_IPC_HLE_Interface::GetDeviceByName("/dev/di"); - if (di) - std::static_pointer_cast(di)->FinishIOCtl(interrupt_type); + if (reply_to_ios) + { + std::shared_ptr di = WII_IPC_HLE_Interface::GetDeviceByName("/dev/di"); + if (di) + std::static_pointer_cast(di)->FinishIOCtl(interrupt_type); - // If di == nullptr, IOS was probably shut down, so the command shouldn't be completed - } - else if (s_DICR.TSTART) - { - s_DICR.TSTART = 0; - s_DILENGTH.Length = 0; - GenerateDIInterrupt(interrupt_type); - } + // If di == nullptr, IOS was probably shut down, so the command shouldn't be completed + } + else if (s_DICR.TSTART) + { + s_DICR.TSTART = 0; + s_DILENGTH.Length = 0; + GenerateDIInterrupt(interrupt_type); + } } // Simulates the timing aspects of reading data from a disc. @@ -1291,87 +1296,84 @@ void FinishExecutingCommand(bool reply_to_ios, DIInterruptType interrupt_type) // and sets some state that is used the next time this function runs. u64 SimulateDiscReadTime(u64 offset, u32 length) { - // The drive buffers 1 MiB (?) of data after every read request; - // if a read request is covered by this buffer (or if it's - // faster to wait for the data to be buffered), the drive - // doesn't seek; it returns buffered data. Data can be - // transferred from the buffer at up to 16 MiB/s. - // - // If the drive has to seek, the time this takes varies a lot. - // A short seek is around 50 ms; a long seek is around 150 ms. - // However, the time isn't purely dependent on the distance; the - // pattern of previous seeks seems to matter in a way I'm - // not sure how to explain. - // - // Metroid Prime is a good example of a game that's sensitive to - // all of these details; if there isn't enough latency in the - // right places, doors open too quickly, and if there's too - // much latency in the wrong places, the video before the - // save-file select screen lags. - // - // For now, just use a very rough approximation: 50 ms seek - // for reads outside 1 MiB, accelerated reads within 1 MiB. - // We can refine this if someone comes up with a more complete - // model for seek times. + // The drive buffers 1 MiB (?) of data after every read request; + // if a read request is covered by this buffer (or if it's + // faster to wait for the data to be buffered), the drive + // doesn't seek; it returns buffered data. Data can be + // transferred from the buffer at up to 16 MiB/s. + // + // If the drive has to seek, the time this takes varies a lot. + // A short seek is around 50 ms; a long seek is around 150 ms. + // However, the time isn't purely dependent on the distance; the + // pattern of previous seeks seems to matter in a way I'm + // not sure how to explain. + // + // Metroid Prime is a good example of a game that's sensitive to + // all of these details; if there isn't enough latency in the + // right places, doors open too quickly, and if there's too + // much latency in the wrong places, the video before the + // save-file select screen lags. + // + // For now, just use a very rough approximation: 50 ms seek + // for reads outside 1 MiB, accelerated reads within 1 MiB. + // We can refine this if someone comes up with a more complete + // model for seek times. - u64 current_time = CoreTiming::GetTicks(); - u64 ticks_until_completion; + u64 current_time = CoreTiming::GetTicks(); + u64 ticks_until_completion; - // Number of ticks it takes to seek and read directly from the disk. - u64 disk_read_duration = CalculateRawDiscReadTime(offset, length) + - SystemTimers::GetTicksPerSecond() / 1000 * DISC_ACCESS_TIME_MS; + // Number of ticks it takes to seek and read directly from the disk. + u64 disk_read_duration = CalculateRawDiscReadTime(offset, length) + + SystemTimers::GetTicksPerSecond() / 1000 * DISC_ACCESS_TIME_MS; - // Assume unbuffered read if the read we are performing asks for data > - // 1MB past the end of the last read *or* asks for data before the last - // read. It assumes the buffer is only used when reading small amounts - // forward. - if (offset + length > s_last_read_offset + 1024 * 1024 || offset < s_last_read_offset) - { - // No buffer; just use the simple seek time + read time. - DEBUG_LOG(DVDINTERFACE, "Seeking %" PRId64 " bytes", - s64(offset) - s64(s_last_read_offset)); - ticks_until_completion = disk_read_duration; - s_last_read_time = current_time + ticks_until_completion; - } - else - { - // Possibly buffered; use the buffer if it saves time. - // It's not proven that the buffer actually behaves like this, but - // it appears to be a decent approximation. + // Assume unbuffered read if the read we are performing asks for data > + // 1MB past the end of the last read *or* asks for data before the last + // read. It assumes the buffer is only used when reading small amounts + // forward. + if (offset + length > s_last_read_offset + 1024 * 1024 || offset < s_last_read_offset) + { + // No buffer; just use the simple seek time + read time. + DEBUG_LOG(DVDINTERFACE, "Seeking %" PRId64 " bytes", s64(offset) - s64(s_last_read_offset)); + ticks_until_completion = disk_read_duration; + s_last_read_time = current_time + ticks_until_completion; + } + else + { + // Possibly buffered; use the buffer if it saves time. + // It's not proven that the buffer actually behaves like this, but + // it appears to be a decent approximation. - // Time at which the buffer will contain the data we need. - u64 buffer_fill_time = s_last_read_time + - CalculateRawDiscReadTime(s_last_read_offset, - offset + length - s_last_read_offset); - // Number of ticks it takes to transfer the data from the buffer to memory. - u64 buffer_read_duration = length * - (SystemTimers::GetTicksPerSecond() / BUFFER_TRANSFER_RATE); + // Time at which the buffer will contain the data we need. + u64 buffer_fill_time = + s_last_read_time + + CalculateRawDiscReadTime(s_last_read_offset, offset + length - s_last_read_offset); + // Number of ticks it takes to transfer the data from the buffer to memory. + u64 buffer_read_duration = length * (SystemTimers::GetTicksPerSecond() / BUFFER_TRANSFER_RATE); - if (current_time > buffer_fill_time) - { - DEBUG_LOG(DVDINTERFACE, "Fast buffer read at %" PRIx64, offset); - ticks_until_completion = buffer_read_duration; - s_last_read_time = buffer_fill_time; - } - else if (current_time + disk_read_duration > buffer_fill_time) - { - DEBUG_LOG(DVDINTERFACE, "Slow buffer read at %" PRIx64, offset); - ticks_until_completion = std::max(buffer_fill_time - current_time, - buffer_read_duration); - s_last_read_time = buffer_fill_time; - } - else - { - DEBUG_LOG(DVDINTERFACE, "Short seek %" PRId64 " bytes", - s64(offset) - s64(s_last_read_offset)); - ticks_until_completion = disk_read_duration; - s_last_read_time = current_time + ticks_until_completion; - } - } + if (current_time > buffer_fill_time) + { + DEBUG_LOG(DVDINTERFACE, "Fast buffer read at %" PRIx64, offset); + ticks_until_completion = buffer_read_duration; + s_last_read_time = buffer_fill_time; + } + else if (current_time + disk_read_duration > buffer_fill_time) + { + DEBUG_LOG(DVDINTERFACE, "Slow buffer read at %" PRIx64, offset); + ticks_until_completion = std::max(buffer_fill_time - current_time, buffer_read_duration); + s_last_read_time = buffer_fill_time; + } + else + { + DEBUG_LOG(DVDINTERFACE, "Short seek %" PRId64 " bytes", + s64(offset) - s64(s_last_read_offset)); + ticks_until_completion = disk_read_duration; + s_last_read_time = current_time + ticks_until_completion; + } + } - s_last_read_offset = ROUND_DOWN(offset + length - 2048, 2048); + s_last_read_offset = ROUND_DOWN(offset + length - 2048, 2048); - return ticks_until_completion; + return ticks_until_completion; } // Returns the number of ticks it takes to read an amount of @@ -1379,46 +1381,48 @@ u64 SimulateDiscReadTime(u64 offset, u32 length) // The result will be negative if the length is negative. s64 CalculateRawDiscReadTime(u64 offset, s64 length) { - // The speed will be calculated using the average offset. This is a bit - // inaccurate since the speed doesn't increase linearly with the offset, - // but since reads only span a small part of the disc, it's insignificant. - u64 average_offset = offset + (length / 2); + // The speed will be calculated using the average offset. This is a bit + // inaccurate since the speed doesn't increase linearly with the offset, + // but since reads only span a small part of the disc, it's insignificant. + u64 average_offset = offset + (length / 2); - // Here, addresses on the second layer of Wii discs are replaced with equivalent - // addresses on the first layer so that the speed calculation works correctly. - // This is wrong for reads spanning two layers, but those should be rare. - average_offset %= WII_DISC_LAYER_SIZE; + // Here, addresses on the second layer of Wii discs are replaced with equivalent + // addresses on the first layer so that the speed calculation works correctly. + // This is wrong for reads spanning two layers, but those should be rare. + average_offset %= WII_DISC_LAYER_SIZE; - // The area on the disc between position 1 and the arbitrary position X is: - // LOCATION_X_SPEED * LOCATION_X_SPEED * pi - AREA_UP_TO_LOCATION_1 - // - // The number of bytes between position 1 and position X is: - // LOCATION_X_OFFSET - LOCATION_1_OFFSET - // - // This means that the following equation is true: - // (LOCATION_X_SPEED * LOCATION_X_SPEED * pi - AREA_UP_TO_LOCATION_1) * - // BYTES_PER_AREA_UNIT = LOCATION_X_OFFSET - LOCATION_1_OFFSET - // - // Solving this equation for LOCATION_X_SPEED results in this: - // LOCATION_X_SPEED = sqrt(((LOCATION_X_OFFSET - LOCATION_1_OFFSET) / - // BYTES_PER_AREA_UNIT + AREA_UP_TO_LOCATION_1) / pi) - // - // Note that the speed at a track (in bytes per second) is the same as - // the radius of that track because of the length unit used. - double speed; - if (s_inserted_volume->GetVolumeType() == DiscIO::IVolume::WII_DISC) - { - speed = std::sqrt(((average_offset - WII_DISC_LOCATION_1_OFFSET) / - WII_BYTES_PER_AREA_UNIT + WII_DISC_AREA_UP_TO_LOCATION_1) / PI); - } - else - { - speed = std::sqrt(((average_offset - GC_DISC_LOCATION_1_OFFSET) / - GC_BYTES_PER_AREA_UNIT + GC_DISC_AREA_UP_TO_LOCATION_1) / PI); - } - DEBUG_LOG(DVDINTERFACE, "Disc speed: %f MiB/s", speed / 1024 / 1024); + // The area on the disc between position 1 and the arbitrary position X is: + // LOCATION_X_SPEED * LOCATION_X_SPEED * pi - AREA_UP_TO_LOCATION_1 + // + // The number of bytes between position 1 and position X is: + // LOCATION_X_OFFSET - LOCATION_1_OFFSET + // + // This means that the following equation is true: + // (LOCATION_X_SPEED * LOCATION_X_SPEED * pi - AREA_UP_TO_LOCATION_1) * + // BYTES_PER_AREA_UNIT = LOCATION_X_OFFSET - LOCATION_1_OFFSET + // + // Solving this equation for LOCATION_X_SPEED results in this: + // LOCATION_X_SPEED = sqrt(((LOCATION_X_OFFSET - LOCATION_1_OFFSET) / + // BYTES_PER_AREA_UNIT + AREA_UP_TO_LOCATION_1) / pi) + // + // Note that the speed at a track (in bytes per second) is the same as + // the radius of that track because of the length unit used. + double speed; + if (s_inserted_volume->GetVolumeType() == DiscIO::IVolume::WII_DISC) + { + speed = std::sqrt(((average_offset - WII_DISC_LOCATION_1_OFFSET) / WII_BYTES_PER_AREA_UNIT + + WII_DISC_AREA_UP_TO_LOCATION_1) / + PI); + } + else + { + speed = std::sqrt(((average_offset - GC_DISC_LOCATION_1_OFFSET) / GC_BYTES_PER_AREA_UNIT + + GC_DISC_AREA_UP_TO_LOCATION_1) / + PI); + } + DEBUG_LOG(DVDINTERFACE, "Disc speed: %f MiB/s", speed / 1024 / 1024); - return (s64)(SystemTimers::GetTicksPerSecond() / speed * length); + return (s64)(SystemTimers::GetTicksPerSecond() / speed * length); } } // namespace diff --git a/Source/Core/Core/HW/DVDInterface.h b/Source/Core/Core/HW/DVDInterface.h index 96b065132e..a67fd39baf 100644 --- a/Source/Core/Core/HW/DVDInterface.h +++ b/Source/Core/Core/HW/DVDInterface.h @@ -9,94 +9,100 @@ #include "Common/CommonTypes.h" class PointerWrap; -namespace DiscIO { class IVolume; } -namespace MMIO { class Mapping; } +namespace DiscIO +{ +class IVolume; +} +namespace MMIO +{ +class Mapping; +} namespace DVDInterface { - // Not sure about endianness here. I'll just name them like this... enum DIErrorLow { - ERROR_READY = 0x00000000, // Ready. - ERROR_COVER_L = 0x01000000, // Cover is opened. - ERROR_CHANGE_DISK = 0x02000000, // Disk change. - ERROR_NO_DISK = 0x03000000, // No disk. - ERROR_MOTOR_STOP_L = 0x04000000, // Motor stop. - ERROR_NO_DISKID_L = 0x05000000 // Disk ID not read. + ERROR_READY = 0x00000000, // Ready. + ERROR_COVER_L = 0x01000000, // Cover is opened. + ERROR_CHANGE_DISK = 0x02000000, // Disk change. + ERROR_NO_DISK = 0x03000000, // No disk. + ERROR_MOTOR_STOP_L = 0x04000000, // Motor stop. + ERROR_NO_DISKID_L = 0x05000000 // Disk ID not read. }; enum DIErrorHigh { - ERROR_NONE = 0x000000, // No error. - ERROR_MOTOR_STOP_H = 0x020400, // Motor stopped. - ERROR_NO_DISKID_H = 0x020401, // Disk ID not read. - ERROR_COVER_H = 0x023a00, // Medium not present / Cover opened. - ERROR_SEEK_NDONE = 0x030200, // No seek complete. - ERROR_READ = 0x031100, // Unrecovered read error. - ERROR_PROTOCOL = 0x040800, // Transfer protocol error. - ERROR_INV_CMD = 0x052000, // Invalid command operation code. - ERROR_AUDIO_BUF = 0x052001, // Audio Buffer not set. - ERROR_BLOCK_OOB = 0x052100, // Logical block address out of bounds. - ERROR_INV_FIELD = 0x052400, // Invalid field in command packet. - ERROR_INV_AUDIO = 0x052401, // Invalid audio command. - ERROR_INV_PERIOD = 0x052402, // Configuration out of permitted period. - ERROR_END_USR_AREA = 0x056300, // End of user area encountered on this track. - ERROR_MEDIUM = 0x062800, // Medium may have changed. - ERROR_MEDIUM_REQ = 0x0b5a01 // Operator medium removal request. + ERROR_NONE = 0x000000, // No error. + ERROR_MOTOR_STOP_H = 0x020400, // Motor stopped. + ERROR_NO_DISKID_H = 0x020401, // Disk ID not read. + ERROR_COVER_H = 0x023a00, // Medium not present / Cover opened. + ERROR_SEEK_NDONE = 0x030200, // No seek complete. + ERROR_READ = 0x031100, // Unrecovered read error. + ERROR_PROTOCOL = 0x040800, // Transfer protocol error. + ERROR_INV_CMD = 0x052000, // Invalid command operation code. + ERROR_AUDIO_BUF = 0x052001, // Audio Buffer not set. + ERROR_BLOCK_OOB = 0x052100, // Logical block address out of bounds. + ERROR_INV_FIELD = 0x052400, // Invalid field in command packet. + ERROR_INV_AUDIO = 0x052401, // Invalid audio command. + ERROR_INV_PERIOD = 0x052402, // Configuration out of permitted period. + ERROR_END_USR_AREA = 0x056300, // End of user area encountered on this track. + ERROR_MEDIUM = 0x062800, // Medium may have changed. + ERROR_MEDIUM_REQ = 0x0b5a01 // Operator medium removal request. }; enum DICommand { - DVDLowInquiry = 0x12, - DVDLowReadDiskID = 0x70, - DVDLowRead = 0x71, - DVDLowWaitForCoverClose = 0x79, - DVDLowGetCoverReg = 0x7a, // DVDLowPrepareCoverRegister? - DVDLowNotifyReset = 0x7e, - DVDLowReadDvdPhysical = 0x80, - DVDLowReadDvdCopyright = 0x81, - DVDLowReadDvdDiscKey = 0x82, - DVDLowClearCoverInterrupt = 0x86, - DVDLowGetCoverStatus = 0x88, - DVDLowReset = 0x8a, - DVDLowOpenPartition = 0x8b, - DVDLowClosePartition = 0x8c, - DVDLowUnencryptedRead = 0x8d, - DVDLowEnableDvdVideo = 0x8e, - DVDLowReportKey = 0xa4, - DVDLowSeek = 0xab, - DVDLowReadDvd = 0xd0, - DVDLowReadDvdConfig = 0xd1, - DVDLowStopLaser = 0xd2, - DVDLowOffset = 0xd9, - DVDLowReadDiskBca = 0xda, - DVDLowRequestDiscStatus = 0xdb, - DVDLowRequestRetryNumber = 0xdc, - DVDLowSetMaximumRotation = 0xdd, - DVDLowSerMeasControl = 0xdf, - DVDLowRequestError = 0xe0, - DVDLowStopMotor = 0xe3, - DVDLowAudioBufferConfig = 0xe4 + DVDLowInquiry = 0x12, + DVDLowReadDiskID = 0x70, + DVDLowRead = 0x71, + DVDLowWaitForCoverClose = 0x79, + DVDLowGetCoverReg = 0x7a, // DVDLowPrepareCoverRegister? + DVDLowNotifyReset = 0x7e, + DVDLowReadDvdPhysical = 0x80, + DVDLowReadDvdCopyright = 0x81, + DVDLowReadDvdDiscKey = 0x82, + DVDLowClearCoverInterrupt = 0x86, + DVDLowGetCoverStatus = 0x88, + DVDLowReset = 0x8a, + DVDLowOpenPartition = 0x8b, + DVDLowClosePartition = 0x8c, + DVDLowUnencryptedRead = 0x8d, + DVDLowEnableDvdVideo = 0x8e, + DVDLowReportKey = 0xa4, + DVDLowSeek = 0xab, + DVDLowReadDvd = 0xd0, + DVDLowReadDvdConfig = 0xd1, + DVDLowStopLaser = 0xd2, + DVDLowOffset = 0xd9, + DVDLowReadDiskBca = 0xda, + DVDLowRequestDiscStatus = 0xdb, + DVDLowRequestRetryNumber = 0xdc, + DVDLowSetMaximumRotation = 0xdd, + DVDLowSerMeasControl = 0xdf, + DVDLowRequestError = 0xe0, + DVDLowStopMotor = 0xe3, + DVDLowAudioBufferConfig = 0xe4 }; enum DIInterruptType : int { - INT_DEINT = 0, - INT_TCINT = 1, - INT_BRKINT = 2, - INT_CVRINT = 3, + INT_DEINT = 0, + INT_TCINT = 1, + INT_BRKINT = 2, + INT_CVRINT = 3, }; void Init(); void Shutdown(); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); void RegisterMMIO(MMIO::Mapping* mmio, u32 base); // Direct disc access const DiscIO::IVolume& GetVolume(); bool SetVolumeName(const std::string& disc_path); -bool SetVolumeDirectory(const std::string& disc_path, bool is_wii, const std::string& apploader_path = "", const std::string& DOL_path = ""); +bool SetVolumeDirectory(const std::string& disc_path, bool is_wii, + const std::string& apploader_path = "", const std::string& DOL_path = ""); bool VolumeIsValid(); // Disc detection and swapping @@ -110,4 +116,4 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr u32 output_length, bool reply_to_ios); void FinishExecutingCommand(bool reply_to_ios, DIInterruptType interrupt_type); -} // end of namespace DVDInterface +} // end of namespace DVDInterface diff --git a/Source/Core/Core/HW/DVDThread.cpp b/Source/Core/Core/HW/DVDThread.cpp index 1ef6642842..3601f5bafd 100644 --- a/Source/Core/Core/HW/DVDThread.cpp +++ b/Source/Core/Core/HW/DVDThread.cpp @@ -11,10 +11,10 @@ #include "Common/CommonTypes.h" #include "Common/Event.h" #include "Common/Flag.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/Thread.h" #include "Common/Timer.h" -#include "Common/Logging/Log.h" #include "Core/Core.h" #include "Core/CoreTiming.h" @@ -27,7 +27,6 @@ namespace DVDThread { - static void DVDThread(); static void FinishRead(u64 userdata, s64 cycles_late); @@ -57,122 +56,124 @@ static u64 s_realtime_done_us; void Start() { - s_finish_read = CoreTiming::RegisterEvent("FinishReadDVDThread", FinishRead); - _assert_(!s_dvd_thread.joinable()); - s_dvd_thread = std::thread(DVDThread); + s_finish_read = CoreTiming::RegisterEvent("FinishReadDVDThread", FinishRead); + _assert_(!s_dvd_thread.joinable()); + s_dvd_thread = std::thread(DVDThread); } void Stop() { - _assert_(s_dvd_thread.joinable()); + _assert_(s_dvd_thread.joinable()); - // The DVD thread will return if s_DVD_thread_exiting - // is set when it starts working - s_dvd_thread_exiting.Set(); - s_dvd_thread_start_working.Set(); + // The DVD thread will return if s_DVD_thread_exiting + // is set when it starts working + s_dvd_thread_exiting.Set(); + s_dvd_thread_start_working.Set(); - s_dvd_thread.join(); + s_dvd_thread.join(); - s_dvd_thread_exiting.Clear(); + s_dvd_thread_exiting.Clear(); } -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - WaitUntilIdle(); + WaitUntilIdle(); - // TODO: Savestates can be smaller if s_DVD_buffer is not saved - p.Do(s_dvd_buffer); - p.Do(s_time_read_started); - p.Do(s_dvd_success); + // TODO: Savestates can be smaller if s_DVD_buffer is not saved + p.Do(s_dvd_buffer); + p.Do(s_time_read_started); + p.Do(s_dvd_success); - p.Do(s_dvd_offset); - p.Do(s_output_address); - p.Do(s_length); - p.Do(s_decrypt); - p.Do(s_reply_to_ios); + p.Do(s_dvd_offset); + p.Do(s_output_address); + p.Do(s_length); + p.Do(s_decrypt); + p.Do(s_reply_to_ios); - // s_realtime_started_us and s_realtime_done_us aren't savestated - // because they rely on the current system's time. - // This means that loading a savestate might cause - // incorrect times to be logged once. + // s_realtime_started_us and s_realtime_done_us aren't savestated + // because they rely on the current system's time. + // This means that loading a savestate might cause + // incorrect times to be logged once. } void WaitUntilIdle() { - _assert_(Core::IsCPUThread()); + _assert_(Core::IsCPUThread()); - // Wait until DVD thread isn't working - s_dvd_thread_done_working.Wait(); + // Wait until DVD thread isn't working + s_dvd_thread_done_working.Wait(); - // Set the event again so that we still know that the DVD thread isn't working - s_dvd_thread_done_working.Set(); + // Set the event again so that we still know that the DVD thread isn't working + s_dvd_thread_done_working.Set(); } -void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt, - bool reply_to_ios, int ticks_until_completion) +void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt, bool reply_to_ios, + int ticks_until_completion) { - _assert_(Core::IsCPUThread()); + _assert_(Core::IsCPUThread()); - s_dvd_thread_done_working.Wait(); + s_dvd_thread_done_working.Wait(); - s_dvd_offset = dvd_offset; - s_output_address = output_address; - s_length = length; - s_decrypt = decrypt; - s_reply_to_ios = reply_to_ios; + s_dvd_offset = dvd_offset; + s_output_address = output_address; + s_length = length; + s_decrypt = decrypt; + s_reply_to_ios = reply_to_ios; - s_time_read_started = CoreTiming::GetTicks(); - s_realtime_started_us = Common::Timer::GetTimeUs(); + s_time_read_started = CoreTiming::GetTicks(); + s_realtime_started_us = Common::Timer::GetTimeUs(); - s_dvd_thread_start_working.Set(); + s_dvd_thread_start_working.Set(); - CoreTiming::ScheduleEvent(ticks_until_completion, s_finish_read); + CoreTiming::ScheduleEvent(ticks_until_completion, s_finish_read); } static void FinishRead(u64 userdata, s64 cycles_late) { - WaitUntilIdle(); + WaitUntilIdle(); - DEBUG_LOG(DVDINTERFACE, "Disc has been read. Real time: %" PRIu64 " us. " - "Real time including delay: %" PRIu64 " us. Emulated time including delay: %" PRIu64 " us.", - s_realtime_done_us - s_realtime_started_us, - Common::Timer::GetTimeUs() - s_realtime_started_us, - (CoreTiming::GetTicks() - s_time_read_started) / (SystemTimers::GetTicksPerSecond() / 1000 / 1000)); + DEBUG_LOG(DVDINTERFACE, "Disc has been read. Real time: %" PRIu64 " us. " + "Real time including delay: %" PRIu64 + " us. Emulated time including delay: %" PRIu64 " us.", + s_realtime_done_us - s_realtime_started_us, + Common::Timer::GetTimeUs() - s_realtime_started_us, + (CoreTiming::GetTicks() - s_time_read_started) / + (SystemTimers::GetTicksPerSecond() / 1000 / 1000)); - if (s_dvd_success) - Memory::CopyToEmu(s_output_address, s_dvd_buffer.data(), s_length); - else - PanicAlertT("The disc could not be read (at 0x%" PRIx64 " - 0x%" PRIx64 ").", - s_dvd_offset, s_dvd_offset + s_length); + if (s_dvd_success) + Memory::CopyToEmu(s_output_address, s_dvd_buffer.data(), s_length); + else + PanicAlertT("The disc could not be read (at 0x%" PRIx64 " - 0x%" PRIx64 ").", s_dvd_offset, + s_dvd_offset + s_length); - // This will make the buffer take less space in savestates. - // Reducing the size doesn't change the amount of reserved memory, - // so this doesn't lead to extra memory allocations. - s_dvd_buffer.resize(0); + // This will make the buffer take less space in savestates. + // Reducing the size doesn't change the amount of reserved memory, + // so this doesn't lead to extra memory allocations. + s_dvd_buffer.resize(0); - // Notify the emulated software that the command has been executed - DVDInterface::FinishExecutingCommand(s_reply_to_ios, DVDInterface::INT_TCINT); + // Notify the emulated software that the command has been executed + DVDInterface::FinishExecutingCommand(s_reply_to_ios, DVDInterface::INT_TCINT); } static void DVDThread() { - Common::SetCurrentThreadName("DVD thread"); + Common::SetCurrentThreadName("DVD thread"); - while (true) - { - s_dvd_thread_done_working.Set(); + while (true) + { + s_dvd_thread_done_working.Set(); - s_dvd_thread_start_working.Wait(); + s_dvd_thread_start_working.Wait(); - if (s_dvd_thread_exiting.IsSet()) - return; + if (s_dvd_thread_exiting.IsSet()) + return; - s_dvd_buffer.resize(s_length); + s_dvd_buffer.resize(s_length); - s_dvd_success = DVDInterface::GetVolume().Read(s_dvd_offset, s_length, s_dvd_buffer.data(), s_decrypt); + s_dvd_success = + DVDInterface::GetVolume().Read(s_dvd_offset, s_length, s_dvd_buffer.data(), s_decrypt); - s_realtime_done_us = Common::Timer::GetTimeUs(); - } + s_realtime_done_us = Common::Timer::GetTimeUs(); + } } - } diff --git a/Source/Core/Core/HW/DVDThread.h b/Source/Core/Core/HW/DVDThread.h index 795c7ad617..b657e29f4f 100644 --- a/Source/Core/Core/HW/DVDThread.h +++ b/Source/Core/Core/HW/DVDThread.h @@ -9,13 +9,11 @@ namespace DVDThread { - void Start(); void Stop(); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); void WaitUntilIdle(); -void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt, - bool reply_to_ios, int ticks_until_completion); - +void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt, bool reply_to_ios, + int ticks_until_completion); } diff --git a/Source/Core/Core/HW/EXI.cpp b/Source/Core/Core/HW/EXI.cpp index 0307aaa32c..75fe28eb38 100644 --- a/Source/Core/Core/HW/EXI.cpp +++ b/Source/Core/Core/HW/EXI.cpp @@ -10,19 +10,18 @@ #include "Core/ConfigManager.h" #include "Core/CoreTiming.h" -#include "Core/Movie.h" #include "Core/HW/EXI.h" #include "Core/HW/EXI_Channel.h" #include "Core/HW/MMIO.h" #include "Core/HW/ProcessorInterface.h" #include "Core/HW/Sram.h" +#include "Core/Movie.h" SRAM g_SRAM; bool g_SRAM_netplay_initialized = false; namespace ExpansionInterface { - static int changeDevice; static int updateInterrupts; @@ -33,125 +32,129 @@ static void UpdateInterruptsCallback(u64 userdata, s64 cycles_late); void Init() { - if (!g_SRAM_netplay_initialized) - { - InitSRAM(); - } + if (!g_SRAM_netplay_initialized) + { + InitSRAM(); + } - for (u32 i = 0; i < MAX_EXI_CHANNELS; i++) - g_Channels[i] = std::make_unique(i); + for (u32 i = 0; i < MAX_EXI_CHANNELS; i++) + g_Channels[i] = std::make_unique(i); - if (Movie::IsPlayingInput() && Movie::IsConfigSaved()) - { - g_Channels[0]->AddDevice(Movie::IsUsingMemcard(0) ? EXIDEVICE_MEMORYCARD : EXIDEVICE_NONE, 0); // SlotA - g_Channels[1]->AddDevice(Movie::IsUsingMemcard(1) ? EXIDEVICE_MEMORYCARD : EXIDEVICE_NONE, 0); // SlotB - } - else - { - g_Channels[0]->AddDevice(SConfig::GetInstance().m_EXIDevice[0], 0); // SlotA - g_Channels[1]->AddDevice(SConfig::GetInstance().m_EXIDevice[1], 0); // SlotB - } - g_Channels[0]->AddDevice(EXIDEVICE_MASKROM, 1); - g_Channels[0]->AddDevice(SConfig::GetInstance().m_EXIDevice[2], 2); // Serial Port 1 - g_Channels[2]->AddDevice(EXIDEVICE_AD16, 0); + if (Movie::IsPlayingInput() && Movie::IsConfigSaved()) + { + g_Channels[0]->AddDevice(Movie::IsUsingMemcard(0) ? EXIDEVICE_MEMORYCARD : EXIDEVICE_NONE, + 0); // SlotA + g_Channels[1]->AddDevice(Movie::IsUsingMemcard(1) ? EXIDEVICE_MEMORYCARD : EXIDEVICE_NONE, + 0); // SlotB + } + else + { + g_Channels[0]->AddDevice(SConfig::GetInstance().m_EXIDevice[0], 0); // SlotA + g_Channels[1]->AddDevice(SConfig::GetInstance().m_EXIDevice[1], 0); // SlotB + } + g_Channels[0]->AddDevice(EXIDEVICE_MASKROM, 1); + g_Channels[0]->AddDevice(SConfig::GetInstance().m_EXIDevice[2], 2); // Serial Port 1 + g_Channels[2]->AddDevice(EXIDEVICE_AD16, 0); - changeDevice = CoreTiming::RegisterEvent("ChangeEXIDevice", ChangeDeviceCallback); - updateInterrupts = CoreTiming::RegisterEvent("EXIUpdateInterrupts", UpdateInterruptsCallback); + changeDevice = CoreTiming::RegisterEvent("ChangeEXIDevice", ChangeDeviceCallback); + updateInterrupts = CoreTiming::RegisterEvent("EXIUpdateInterrupts", UpdateInterruptsCallback); } void Shutdown() { - for (auto& channel : g_Channels) - channel.reset(); + for (auto& channel : g_Channels) + channel.reset(); } -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - for (auto& channel : g_Channels) - channel->DoState(p); + for (auto& channel : g_Channels) + channel->DoState(p); } void PauseAndLock(bool doLock, bool unpauseOnUnlock) { - for (auto& channel : g_Channels) - channel->PauseAndLock(doLock, unpauseOnUnlock); + for (auto& channel : g_Channels) + channel->PauseAndLock(doLock, unpauseOnUnlock); } void RegisterMMIO(MMIO::Mapping* mmio, u32 base) { - for (int i = 0; i < MAX_EXI_CHANNELS; ++i) - { - _dbg_assert_(EXPANSIONINTERFACE, g_Channels[i] != nullptr); - // Each channel has 5 32 bit registers assigned to it. We offset the - // base that we give to each channel for registration. - // - // Be careful: this means the base is no longer aligned on a page - // boundary and using "base | FOO" is not valid! - g_Channels[i]->RegisterMMIO(mmio, base + 5 * 4 * i); - } + for (int i = 0; i < MAX_EXI_CHANNELS; ++i) + { + _dbg_assert_(EXPANSIONINTERFACE, g_Channels[i] != nullptr); + // Each channel has 5 32 bit registers assigned to it. We offset the + // base that we give to each channel for registration. + // + // Be careful: this means the base is no longer aligned on a page + // boundary and using "base | FOO" is not valid! + g_Channels[i]->RegisterMMIO(mmio, base + 5 * 4 * i); + } } static void ChangeDeviceCallback(u64 userdata, s64 cyclesLate) { - u8 channel = (u8)(userdata >> 32); - u8 type = (u8)(userdata >> 16); - u8 num = (u8)userdata; + u8 channel = (u8)(userdata >> 32); + u8 type = (u8)(userdata >> 16); + u8 num = (u8)userdata; - g_Channels.at(channel)->AddDevice((TEXIDevices)type, num); + g_Channels.at(channel)->AddDevice((TEXIDevices)type, num); } void ChangeDevice(const u8 channel, const TEXIDevices device_type, const u8 device_num) { - // Called from GUI, so we need to make it thread safe. - // Let the hardware see no device for .5b cycles - CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | ((u64)EXIDEVICE_NONE << 16) | device_num); - CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | ((u64)device_type << 16) | device_num); + // Called from GUI, so we need to make it thread safe. + // Let the hardware see no device for .5b cycles + CoreTiming::ScheduleEvent_Threadsafe( + 0, changeDevice, ((u64)channel << 32) | ((u64)EXIDEVICE_NONE << 16) | device_num); + CoreTiming::ScheduleEvent_Threadsafe( + 500000000, changeDevice, ((u64)channel << 32) | ((u64)device_type << 16) | device_num); } CEXIChannel* GetChannel(u32 index) { - return g_Channels.at(index).get(); + return g_Channels.at(index).get(); } IEXIDevice* FindDevice(TEXIDevices device_type, int customIndex) { - for (auto& channel : g_Channels) - { - IEXIDevice* device = channel->FindDevice(device_type, customIndex); - if (device) - return device; - } - return nullptr; + for (auto& channel : g_Channels) + { + IEXIDevice* device = channel->FindDevice(device_type, customIndex); + if (device) + return device; + } + return nullptr; } void UpdateInterrupts() { - // Interrupts are mapped a bit strangely: - // Channel 0 Device 0 generates interrupt on channel 0 - // Channel 0 Device 2 generates interrupt on channel 2 - // Channel 1 Device 0 generates interrupt on channel 1 - g_Channels[2]->SetEXIINT(g_Channels[0]->GetDevice(4)->IsInterruptSet()); + // Interrupts are mapped a bit strangely: + // Channel 0 Device 0 generates interrupt on channel 0 + // Channel 0 Device 2 generates interrupt on channel 2 + // Channel 1 Device 0 generates interrupt on channel 1 + g_Channels[2]->SetEXIINT(g_Channels[0]->GetDevice(4)->IsInterruptSet()); - bool causeInt = false; - for (auto& channel : g_Channels) - causeInt |= channel->IsCausingInterrupt(); + bool causeInt = false; + for (auto& channel : g_Channels) + causeInt |= channel->IsCausingInterrupt(); - ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_EXI, causeInt); + ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_EXI, causeInt); } static void UpdateInterruptsCallback(u64 userdata, s64 cycles_late) { - UpdateInterrupts(); + UpdateInterrupts(); } void ScheduleUpdateInterrupts_Threadsafe(int cycles_late) { - CoreTiming::ScheduleEvent_Threadsafe(cycles_late, updateInterrupts, 0); + CoreTiming::ScheduleEvent_Threadsafe(cycles_late, updateInterrupts, 0); } void ScheduleUpdateInterrupts(int cycles_late) { - CoreTiming::ScheduleEvent(cycles_late, updateInterrupts, 0); + CoreTiming::ScheduleEvent(cycles_late, updateInterrupts, 0); } -} // end of namespace ExpansionInterface +} // end of namespace ExpansionInterface diff --git a/Source/Core/Core/HW/EXI.h b/Source/Core/Core/HW/EXI.h index 9787930105..28629a09b4 100644 --- a/Source/Core/Core/HW/EXI.h +++ b/Source/Core/Core/HW/EXI.h @@ -10,19 +10,21 @@ class CEXIChannel; class IEXIDevice; class PointerWrap; enum TEXIDevices : int; -namespace MMIO { class Mapping; } +namespace MMIO +{ +class Mapping; +} enum { - MAX_EXI_CHANNELS = 3 + MAX_EXI_CHANNELS = 3 }; namespace ExpansionInterface { - void Init(); void Shutdown(); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); void PauseAndLock(bool doLock, bool unpauseOnUnlock); void RegisterMMIO(MMIO::Mapping* mmio, u32 base); @@ -35,6 +37,6 @@ void ChangeDevice(const u8 channel, const TEXIDevices device_type, const u8 devi CEXIChannel* GetChannel(u32 index); -IEXIDevice* FindDevice(TEXIDevices device_type, int customIndex=-1); +IEXIDevice* FindDevice(TEXIDevices device_type, int customIndex = -1); -} // end of namespace ExpansionInterface +} // end of namespace ExpansionInterface diff --git a/Source/Core/Core/HW/EXI_Channel.cpp b/Source/Core/Core/HW/EXI_Channel.cpp index a2b68d9adb..799c07bd22 100644 --- a/Source/Core/Core/HW/EXI_Channel.cpp +++ b/Source/Core/Core/HW/EXI_Channel.cpp @@ -14,250 +14,255 @@ enum { - EXI_READ, - EXI_WRITE, - EXI_READWRITE + EXI_READ, + EXI_WRITE, + EXI_READWRITE }; -CEXIChannel::CEXIChannel(u32 ChannelId) : - m_DMAMemoryAddress(0), - m_DMALength(0), - m_ImmData(0), - m_ChannelId(ChannelId) +CEXIChannel::CEXIChannel(u32 ChannelId) + : m_DMAMemoryAddress(0), m_DMALength(0), m_ImmData(0), m_ChannelId(ChannelId) { - m_Control.Hex = 0; - m_Status.Hex = 0; + m_Control.Hex = 0; + m_Status.Hex = 0; - if (m_ChannelId == 0 || m_ChannelId == 1) - m_Status.EXTINT = 1; - if (m_ChannelId == 1) - m_Status.CHIP_SELECT = 1; + if (m_ChannelId == 0 || m_ChannelId == 1) + m_Status.EXTINT = 1; + if (m_ChannelId == 1) + m_Status.CHIP_SELECT = 1; - for (auto& device : m_pDevices) - device = EXIDevice_Create(EXIDEVICE_NONE, m_ChannelId); + for (auto& device : m_pDevices) + device = EXIDevice_Create(EXIDEVICE_NONE, m_ChannelId); } CEXIChannel::~CEXIChannel() { - RemoveDevices(); + RemoveDevices(); } void CEXIChannel::RegisterMMIO(MMIO::Mapping* mmio, u32 base) { - // Warning: the base is not aligned on a page boundary here. We can't use | - // to select a register address, instead we need to use +. + // Warning: the base is not aligned on a page boundary here. We can't use | + // to select a register address, instead we need to use +. - mmio->Register(base + EXI_STATUS, - MMIO::ComplexRead([this](u32) { - // check if external device is present - // pretty sure it is memcard only, not entirely sure - if (m_ChannelId == 2) - { - m_Status.EXT = 0; - } - else - { - m_Status.EXT = GetDevice(1)->IsPresent() ? 1 : 0; - } + mmio->Register(base + EXI_STATUS, MMIO::ComplexRead([this](u32) { + // check if external device is present + // pretty sure it is memcard only, not entirely sure + if (m_ChannelId == 2) + { + m_Status.EXT = 0; + } + else + { + m_Status.EXT = GetDevice(1)->IsPresent() ? 1 : 0; + } - return m_Status.Hex; - }), - MMIO::ComplexWrite([this](u32, u32 val) { - UEXI_STATUS newStatus(val); + return m_Status.Hex; + }), + MMIO::ComplexWrite([this](u32, u32 val) { + UEXI_STATUS newStatus(val); - m_Status.EXIINTMASK = newStatus.EXIINTMASK; - if (newStatus.EXIINT) - m_Status.EXIINT = 0; + m_Status.EXIINTMASK = newStatus.EXIINTMASK; + if (newStatus.EXIINT) + m_Status.EXIINT = 0; - m_Status.TCINTMASK = newStatus.TCINTMASK; - if (newStatus.TCINT) - m_Status.TCINT = 0; + m_Status.TCINTMASK = newStatus.TCINTMASK; + if (newStatus.TCINT) + m_Status.TCINT = 0; - m_Status.CLK = newStatus.CLK; + m_Status.CLK = newStatus.CLK; - if (m_ChannelId == 0 || m_ChannelId == 1) - { - m_Status.EXTINTMASK = newStatus.EXTINTMASK; + if (m_ChannelId == 0 || m_ChannelId == 1) + { + m_Status.EXTINTMASK = newStatus.EXTINTMASK; - if (newStatus.EXTINT) - m_Status.EXTINT = 0; - } + if (newStatus.EXTINT) + m_Status.EXTINT = 0; + } - if (m_ChannelId == 0) - m_Status.ROMDIS = newStatus.ROMDIS; + if (m_ChannelId == 0) + m_Status.ROMDIS = newStatus.ROMDIS; - IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT ^ newStatus.CHIP_SELECT); - m_Status.CHIP_SELECT = newStatus.CHIP_SELECT; - if (pDevice != nullptr) - pDevice->SetCS(m_Status.CHIP_SELECT); + IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT ^ newStatus.CHIP_SELECT); + m_Status.CHIP_SELECT = newStatus.CHIP_SELECT; + if (pDevice != nullptr) + pDevice->SetCS(m_Status.CHIP_SELECT); - ExpansionInterface::UpdateInterrupts(); - }) - ); + ExpansionInterface::UpdateInterrupts(); + })); - mmio->Register(base + EXI_DMAADDR, - MMIO::DirectRead(&m_DMAMemoryAddress), - MMIO::DirectWrite(&m_DMAMemoryAddress) - ); - mmio->Register(base + EXI_DMALENGTH, - MMIO::DirectRead(&m_DMALength), - MMIO::DirectWrite(&m_DMALength) - ); - mmio->Register(base + EXI_DMACONTROL, - MMIO::DirectRead(&m_Control.Hex), - MMIO::ComplexWrite([this](u32, u32 val) { - m_Control.Hex = val; + mmio->Register(base + EXI_DMAADDR, MMIO::DirectRead(&m_DMAMemoryAddress), + MMIO::DirectWrite(&m_DMAMemoryAddress)); + mmio->Register(base + EXI_DMALENGTH, MMIO::DirectRead(&m_DMALength), + MMIO::DirectWrite(&m_DMALength)); + mmio->Register(base + EXI_DMACONTROL, MMIO::DirectRead(&m_Control.Hex), + MMIO::ComplexWrite([this](u32, u32 val) { + m_Control.Hex = val; - if (m_Control.TSTART) - { - IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT); - if (pDevice == nullptr) - return; + if (m_Control.TSTART) + { + IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT); + if (pDevice == nullptr) + return; - if (m_Control.DMA == 0) - { - // immediate data - switch (m_Control.RW) - { - case EXI_READ: m_ImmData = pDevice->ImmRead(m_Control.TLEN + 1); break; - case EXI_WRITE: pDevice->ImmWrite(m_ImmData, m_Control.TLEN + 1); break; - case EXI_READWRITE: pDevice->ImmReadWrite(m_ImmData, m_Control.TLEN + 1); break; - default: _dbg_assert_msg_(EXPANSIONINTERFACE,0,"EXI Imm: Unknown transfer type %i", m_Control.RW); - } - } - else - { - // DMA - switch (m_Control.RW) - { - case EXI_READ: pDevice->DMARead (m_DMAMemoryAddress, m_DMALength); break; - case EXI_WRITE: pDevice->DMAWrite(m_DMAMemoryAddress, m_DMALength); break; - default: _dbg_assert_msg_(EXPANSIONINTERFACE,0,"EXI DMA: Unknown transfer type %i", m_Control.RW); - } - } + if (m_Control.DMA == 0) + { + // immediate data + switch (m_Control.RW) + { + case EXI_READ: + m_ImmData = pDevice->ImmRead(m_Control.TLEN + 1); + break; + case EXI_WRITE: + pDevice->ImmWrite(m_ImmData, m_Control.TLEN + 1); + break; + case EXI_READWRITE: + pDevice->ImmReadWrite(m_ImmData, m_Control.TLEN + 1); + break; + default: + _dbg_assert_msg_(EXPANSIONINTERFACE, 0, + "EXI Imm: Unknown transfer type %i", m_Control.RW); + } + } + else + { + // DMA + switch (m_Control.RW) + { + case EXI_READ: + pDevice->DMARead(m_DMAMemoryAddress, m_DMALength); + break; + case EXI_WRITE: + pDevice->DMAWrite(m_DMAMemoryAddress, m_DMALength); + break; + default: + _dbg_assert_msg_(EXPANSIONINTERFACE, 0, + "EXI DMA: Unknown transfer type %i", m_Control.RW); + } + } - m_Control.TSTART = 0; + m_Control.TSTART = 0; - // Check if device needs specific timing, otherwise just complete transfer immediately - if (!pDevice->UseDelayedTransferCompletion()) - SendTransferComplete(); - } - }) - ); + // Check if device needs specific timing, otherwise just complete transfer + // immediately + if (!pDevice->UseDelayedTransferCompletion()) + SendTransferComplete(); + } + })); - mmio->Register(base + EXI_IMMDATA, - MMIO::DirectRead(&m_ImmData), - MMIO::DirectWrite(&m_ImmData) - ); + mmio->Register(base + EXI_IMMDATA, MMIO::DirectRead(&m_ImmData), + MMIO::DirectWrite(&m_ImmData)); } void CEXIChannel::SendTransferComplete() { - m_Status.TCINT = 1; - ExpansionInterface::UpdateInterrupts(); + m_Status.TCINT = 1; + ExpansionInterface::UpdateInterrupts(); } void CEXIChannel::RemoveDevices() { - for (auto& device : m_pDevices) - device.reset(nullptr); + for (auto& device : m_pDevices) + device.reset(nullptr); } void CEXIChannel::AddDevice(const TEXIDevices device_type, const int device_num) { - AddDevice(EXIDevice_Create(device_type, m_ChannelId), device_num); + AddDevice(EXIDevice_Create(device_type, m_ChannelId), device_num); } -void CEXIChannel::AddDevice(std::unique_ptr device, const int device_num, bool notify_presence_changed) +void CEXIChannel::AddDevice(std::unique_ptr device, const int device_num, + bool notify_presence_changed) { - _dbg_assert_(EXPANSIONINTERFACE, device_num < NUM_DEVICES); + _dbg_assert_(EXPANSIONINTERFACE, device_num < NUM_DEVICES); - // Replace it with the new one - m_pDevices[device_num] = std::move(device); + // Replace it with the new one + m_pDevices[device_num] = std::move(device); - if (notify_presence_changed) - { - // This means "device presence changed", software has to check - // m_Status.EXT to see if it is now present or not - if (m_ChannelId != 2) - { - m_Status.EXTINT = 1; - ExpansionInterface::UpdateInterrupts(); - } - } + if (notify_presence_changed) + { + // This means "device presence changed", software has to check + // m_Status.EXT to see if it is now present or not + if (m_ChannelId != 2) + { + m_Status.EXTINT = 1; + ExpansionInterface::UpdateInterrupts(); + } + } } bool CEXIChannel::IsCausingInterrupt() { - if (m_ChannelId != 2 && GetDevice(1)->IsInterruptSet()) - m_Status.EXIINT = 1; // Always check memcard slots - else if (GetDevice(m_Status.CHIP_SELECT)) - if (GetDevice(m_Status.CHIP_SELECT)->IsInterruptSet()) - m_Status.EXIINT = 1; + if (m_ChannelId != 2 && GetDevice(1)->IsInterruptSet()) + m_Status.EXIINT = 1; // Always check memcard slots + else if (GetDevice(m_Status.CHIP_SELECT)) + if (GetDevice(m_Status.CHIP_SELECT)->IsInterruptSet()) + m_Status.EXIINT = 1; - if ((m_Status.EXIINT & m_Status.EXIINTMASK) || - (m_Status.TCINT & m_Status.TCINTMASK) || - (m_Status.EXTINT & m_Status.EXTINTMASK)) - { - return true; - } - else - { - return false; - } + if ((m_Status.EXIINT & m_Status.EXIINTMASK) || (m_Status.TCINT & m_Status.TCINTMASK) || + (m_Status.EXTINT & m_Status.EXTINTMASK)) + { + return true; + } + else + { + return false; + } } IEXIDevice* CEXIChannel::GetDevice(const u8 chip_select) { - switch (chip_select) - { - case 1: return m_pDevices[0].get(); - case 2: return m_pDevices[1].get(); - case 4: return m_pDevices[2].get(); - } - return nullptr; + switch (chip_select) + { + case 1: + return m_pDevices[0].get(); + case 2: + return m_pDevices[1].get(); + case 4: + return m_pDevices[2].get(); + } + return nullptr; } -void CEXIChannel::DoState(PointerWrap &p) +void CEXIChannel::DoState(PointerWrap& p) { - p.DoPOD(m_Status); - p.Do(m_DMAMemoryAddress); - p.Do(m_DMALength); - p.Do(m_Control); - p.Do(m_ImmData); + p.DoPOD(m_Status); + p.Do(m_DMAMemoryAddress); + p.Do(m_DMALength); + p.Do(m_Control); + p.Do(m_ImmData); - for (int device_index = 0; device_index < NUM_DEVICES; ++device_index) - { - std::unique_ptr& device = m_pDevices[device_index]; - TEXIDevices type = device->m_deviceType; - p.Do(type); + for (int device_index = 0; device_index < NUM_DEVICES; ++device_index) + { + std::unique_ptr& device = m_pDevices[device_index]; + TEXIDevices type = device->m_deviceType; + p.Do(type); - if (type == device->m_deviceType) - { - device->DoState(p); - } - else - { - std::unique_ptr save_device = EXIDevice_Create(type, m_ChannelId); - save_device->DoState(p); - AddDevice(std::move(save_device), device_index, false); - } - } + if (type == device->m_deviceType) + { + device->DoState(p); + } + else + { + std::unique_ptr save_device = EXIDevice_Create(type, m_ChannelId); + save_device->DoState(p); + AddDevice(std::move(save_device), device_index, false); + } + } } void CEXIChannel::PauseAndLock(bool doLock, bool unpauseOnUnlock) { - for (auto& device : m_pDevices) - device->PauseAndLock(doLock, unpauseOnUnlock); + for (auto& device : m_pDevices) + device->PauseAndLock(doLock, unpauseOnUnlock); } IEXIDevice* CEXIChannel::FindDevice(TEXIDevices device_type, int customIndex) { - for (auto& sup : m_pDevices) - { - IEXIDevice* device = sup->FindDevice(device_type, customIndex); - if (device) - return device; - } - return nullptr; + for (auto& sup : m_pDevices) + { + IEXIDevice* device = sup->FindDevice(device_type, customIndex); + if (device) + return device; + } + return nullptr; } diff --git a/Source/Core/Core/HW/EXI_Channel.h b/Source/Core/Core/HW/EXI_Channel.h index 4a512852fe..9ae2c409f0 100644 --- a/Source/Core/Core/HW/EXI_Channel.h +++ b/Source/Core/Core/HW/EXI_Channel.h @@ -10,102 +10,103 @@ class IEXIDevice; class PointerWrap; enum TEXIDevices : int; -namespace MMIO { class Mapping; } +namespace MMIO +{ +class Mapping; +} class CEXIChannel { private: + enum + { + EXI_STATUS = 0x00, + EXI_DMAADDR = 0x04, + EXI_DMALENGTH = 0x08, + EXI_DMACONTROL = 0x0C, + EXI_IMMDATA = 0x10 + }; - enum - { - EXI_STATUS = 0x00, - EXI_DMAADDR = 0x04, - EXI_DMALENGTH = 0x08, - EXI_DMACONTROL = 0x0C, - EXI_IMMDATA = 0x10 - }; + // EXI Status Register - "Channel Parameter Register" + union UEXI_STATUS { + u32 Hex; + // DO NOT obey the warning and give this struct a name. Things will fail. + struct + { + // Indentation Meaning: + // Channels 0, 1, 2 + // Channels 0, 1 only + // Channel 0 only + u32 EXIINTMASK : 1; + u32 EXIINT : 1; + u32 TCINTMASK : 1; + u32 TCINT : 1; + u32 CLK : 3; + u32 CHIP_SELECT : 3; // CS1 and CS2 are Channel 0 only + u32 EXTINTMASK : 1; + u32 EXTINT : 1; + u32 EXT : 1; // External Insertion Status (1: External EXI device present) + u32 ROMDIS : 1; // ROM Disable + u32 : 18; + }; + UEXI_STATUS() { Hex = 0; } + UEXI_STATUS(u32 _hex) { Hex = _hex; } + }; - // EXI Status Register - "Channel Parameter Register" - union UEXI_STATUS - { - u32 Hex; - // DO NOT obey the warning and give this struct a name. Things will fail. - struct - { - // Indentation Meaning: - // Channels 0, 1, 2 - // Channels 0, 1 only - // Channel 0 only - u32 EXIINTMASK : 1; - u32 EXIINT : 1; - u32 TCINTMASK : 1; - u32 TCINT : 1; - u32 CLK : 3; - u32 CHIP_SELECT : 3; // CS1 and CS2 are Channel 0 only - u32 EXTINTMASK : 1; - u32 EXTINT : 1; - u32 EXT : 1; // External Insertion Status (1: External EXI device present) - u32 ROMDIS : 1; // ROM Disable - u32 :18; - }; - UEXI_STATUS() { Hex = 0; } - UEXI_STATUS(u32 _hex) { Hex = _hex; } - }; + // EXI Control Register + union UEXI_CONTROL { + u32 Hex; + struct + { + u32 TSTART : 1; + u32 DMA : 1; + u32 RW : 2; + u32 TLEN : 2; + u32 : 26; + }; + }; - // EXI Control Register - union UEXI_CONTROL - { - u32 Hex; - struct - { - u32 TSTART : 1; - u32 DMA : 1; - u32 RW : 2; - u32 TLEN : 2; - u32 :26; - }; - }; + // STATE_TO_SAVE + UEXI_STATUS m_Status; + u32 m_DMAMemoryAddress; + u32 m_DMALength; + UEXI_CONTROL m_Control; + u32 m_ImmData; - // STATE_TO_SAVE - UEXI_STATUS m_Status; - u32 m_DMAMemoryAddress; - u32 m_DMALength; - UEXI_CONTROL m_Control; - u32 m_ImmData; + // Devices + enum + { + NUM_DEVICES = 3 + }; - // Devices - enum - { - NUM_DEVICES = 3 - }; + std::unique_ptr m_pDevices[NUM_DEVICES]; - std::unique_ptr m_pDevices[NUM_DEVICES]; - - // Since channels operate a bit differently from each other - u32 m_ChannelId; + // Since channels operate a bit differently from each other + u32 m_ChannelId; public: - // get device - IEXIDevice* GetDevice(const u8 _CHIP_SELECT); - IEXIDevice* FindDevice(TEXIDevices device_type, int customIndex = -1); + // get device + IEXIDevice* GetDevice(const u8 _CHIP_SELECT); + IEXIDevice* FindDevice(TEXIDevices device_type, int customIndex = -1); - CEXIChannel(u32 ChannelId); - ~CEXIChannel(); + CEXIChannel(u32 ChannelId); + ~CEXIChannel(); - void RegisterMMIO(MMIO::Mapping* mmio, u32 base); + void RegisterMMIO(MMIO::Mapping* mmio, u32 base); - void SendTransferComplete(); + void SendTransferComplete(); - void AddDevice(const TEXIDevices device_type, const int device_num); - void AddDevice(std::unique_ptr device, const int device_num, bool notify_presence_changed = true); + void AddDevice(const TEXIDevices device_type, const int device_num); + void AddDevice(std::unique_ptr device, const int device_num, + bool notify_presence_changed = true); - // Remove all devices - void RemoveDevices(); + // Remove all devices + void RemoveDevices(); - bool IsCausingInterrupt(); - void DoState(PointerWrap &p); - void PauseAndLock(bool doLock, bool unpauseOnUnlock); + bool IsCausingInterrupt(); + void DoState(PointerWrap& p); + void PauseAndLock(bool doLock, bool unpauseOnUnlock); - // This should only be used to transition interrupts from SP1 to Channel 2 - void SetEXIINT(bool exiint) { m_Status.EXIINT = !!exiint; } + // This should only be used to transition interrupts from SP1 to Channel 2 + void SetEXIINT(bool exiint) { m_Status.EXIINT = !!exiint; } }; diff --git a/Source/Core/Core/HW/EXI_Device.cpp b/Source/Core/Core/HW/EXI_Device.cpp index f0fe8edb2b..bc2c4b84be 100644 --- a/Source/Core/Core/HW/EXI_Device.cpp +++ b/Source/Core/Core/HW/EXI_Device.cpp @@ -21,129 +21,136 @@ // --- interface IEXIDevice --- void IEXIDevice::ImmWrite(u32 _uData, u32 _uSize) { - while (_uSize--) - { - u8 uByte = _uData >> 24; - TransferByte(uByte); - _uData <<= 8; - } + while (_uSize--) + { + u8 uByte = _uData >> 24; + TransferByte(uByte); + _uData <<= 8; + } } u32 IEXIDevice::ImmRead(u32 _uSize) { - u32 uResult = 0; - u32 uPosition = 0; - while (_uSize--) - { - u8 uByte = 0; - TransferByte(uByte); - uResult |= uByte << (24 - (uPosition++ * 8)); - } - return uResult; + u32 uResult = 0; + u32 uPosition = 0; + while (_uSize--) + { + u8 uByte = 0; + TransferByte(uByte); + uResult |= uByte << (24 - (uPosition++ * 8)); + } + return uResult; } void IEXIDevice::DMAWrite(u32 _uAddr, u32 _uSize) { - // _dbg_assert_(EXPANSIONINTERFACE, 0); - while (_uSize--) - { - u8 uByte = Memory::Read_U8(_uAddr++); - TransferByte(uByte); - } + // _dbg_assert_(EXPANSIONINTERFACE, 0); + while (_uSize--) + { + u8 uByte = Memory::Read_U8(_uAddr++); + TransferByte(uByte); + } } void IEXIDevice::DMARead(u32 _uAddr, u32 _uSize) { - // _dbg_assert_(EXPANSIONINTERFACE, 0); - while (_uSize--) - { - u8 uByte = 0; - TransferByte(uByte); - Memory::Write_U8(uByte, _uAddr++); - } + // _dbg_assert_(EXPANSIONINTERFACE, 0); + while (_uSize--) + { + u8 uByte = 0; + TransferByte(uByte); + Memory::Write_U8(uByte, _uAddr++); + } } - // --- class CEXIDummy --- // Just a dummy that logs reads and writes // to be used for EXI devices we haven't emulated // DOES NOT FUNCTION AS "NO DEVICE INSERTED" -> Appears as unknown device class CEXIDummy : public IEXIDevice { - std::string m_strName; - - void TransferByte(u8& _byte) override {} + std::string m_strName; + void TransferByte(u8& _byte) override {} public: - CEXIDummy(const std::string& _strName) : - m_strName(_strName) - { - } - - virtual ~CEXIDummy(){} - - void ImmWrite(u32 data, u32 size) override {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmWrite: %08x", m_strName.c_str(), data);} - u32 ImmRead (u32 size) override {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmRead", m_strName.c_str()); return 0;} - void DMAWrite(u32 addr, u32 size) override {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMAWrite: %08x bytes, from %08x to device", m_strName.c_str(), size, addr);} - void DMARead (u32 addr, u32 size) override {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMARead: %08x bytes, from device to %08x", m_strName.c_str(), size, addr);} - bool IsPresent() const override { return true; } + CEXIDummy(const std::string& _strName) : m_strName(_strName) {} + virtual ~CEXIDummy() {} + void ImmWrite(u32 data, u32 size) override + { + INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmWrite: %08x", m_strName.c_str(), data); + } + u32 ImmRead(u32 size) override + { + INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmRead", m_strName.c_str()); + return 0; + } + void DMAWrite(u32 addr, u32 size) override + { + INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMAWrite: %08x bytes, from %08x to device", + m_strName.c_str(), size, addr); + } + void DMARead(u32 addr, u32 size) override + { + INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMARead: %08x bytes, from device to %08x", + m_strName.c_str(), size, addr); + } + bool IsPresent() const override { return true; } }; - // F A C T O R Y std::unique_ptr EXIDevice_Create(TEXIDevices device_type, const int channel_num) { - std::unique_ptr result; + std::unique_ptr result; - switch (device_type) - { - case EXIDEVICE_DUMMY: - result = std::make_unique("Dummy"); - break; + switch (device_type) + { + case EXIDEVICE_DUMMY: + result = std::make_unique("Dummy"); + break; - case EXIDEVICE_MEMORYCARD: - case EXIDEVICE_MEMORYCARDFOLDER: - { - bool gci_folder = (device_type == EXIDEVICE_MEMORYCARDFOLDER); - result = std::make_unique(channel_num, gci_folder); - break; - } - case EXIDEVICE_MASKROM: - result = std::make_unique(); - break; + case EXIDEVICE_MEMORYCARD: + case EXIDEVICE_MEMORYCARDFOLDER: + { + bool gci_folder = (device_type == EXIDEVICE_MEMORYCARDFOLDER); + result = std::make_unique(channel_num, gci_folder); + break; + } + case EXIDEVICE_MASKROM: + result = std::make_unique(); + break; - case EXIDEVICE_AD16: - result = std::make_unique(); - break; + case EXIDEVICE_AD16: + result = std::make_unique(); + break; - case EXIDEVICE_MIC: - result = std::make_unique(channel_num); - break; + case EXIDEVICE_MIC: + result = std::make_unique(channel_num); + break; - case EXIDEVICE_ETH: - result = std::make_unique(); - break; + case EXIDEVICE_ETH: + result = std::make_unique(); + break; - case EXIDEVICE_AM_BASEBOARD: - result = std::make_unique(); - break; + case EXIDEVICE_AM_BASEBOARD: + result = std::make_unique(); + break; - case EXIDEVICE_GECKO: - result = std::make_unique(); - break; + case EXIDEVICE_GECKO: + result = std::make_unique(); + break; - case EXIDEVICE_AGP: - result = std::make_unique(channel_num); - break; + case EXIDEVICE_AGP: + result = std::make_unique(channel_num); + break; - case EXIDEVICE_NONE: - default: - result = std::make_unique(); - break; - } + case EXIDEVICE_NONE: + default: + result = std::make_unique(); + break; + } - if (result != nullptr) - result->m_deviceType = device_type; + if (result != nullptr) + result->m_deviceType = device_type; - return result; + return result; } diff --git a/Source/Core/Core/HW/EXI_Device.h b/Source/Core/Core/HW/EXI_Device.h index 156f49edac..db93c3276b 100644 --- a/Source/Core/Core/HW/EXI_Device.h +++ b/Source/Core/Core/HW/EXI_Device.h @@ -11,51 +11,51 @@ class PointerWrap; enum TEXIDevices : int { - EXIDEVICE_DUMMY, - EXIDEVICE_MEMORYCARD, - EXIDEVICE_MASKROM, - EXIDEVICE_AD16, - EXIDEVICE_MIC, - EXIDEVICE_ETH, - EXIDEVICE_AM_BASEBOARD, - EXIDEVICE_GECKO, - EXIDEVICE_MEMORYCARDFOLDER, // Only used when creating a device by EXIDevice_Create - // Converted to EXIDEVICE_MEMORYCARD internally - EXIDEVICE_AGP, - EXIDEVICE_NONE = (u8)-1 + EXIDEVICE_DUMMY, + EXIDEVICE_MEMORYCARD, + EXIDEVICE_MASKROM, + EXIDEVICE_AD16, + EXIDEVICE_MIC, + EXIDEVICE_ETH, + EXIDEVICE_AM_BASEBOARD, + EXIDEVICE_GECKO, + EXIDEVICE_MEMORYCARDFOLDER, // Only used when creating a device by EXIDevice_Create + // Converted to EXIDEVICE_MEMORYCARD internally + EXIDEVICE_AGP, + EXIDEVICE_NONE = (u8)-1 }; class IEXIDevice { private: - // Byte transfer function for this device - virtual void TransferByte(u8&) {} - + // Byte transfer function for this device + virtual void TransferByte(u8&) {} public: - // Immediate copy functions - virtual void ImmWrite(u32 _uData, u32 _uSize); - virtual u32 ImmRead(u32 _uSize); - virtual void ImmReadWrite(u32 &/*_uData*/, u32 /*_uSize*/) {} + // Immediate copy functions + virtual void ImmWrite(u32 _uData, u32 _uSize); + virtual u32 ImmRead(u32 _uSize); + virtual void ImmReadWrite(u32& /*_uData*/, u32 /*_uSize*/) {} + // DMA copy functions + virtual void DMAWrite(u32 _uAddr, u32 _uSize); + virtual void DMARead(u32 _uAddr, u32 _uSize); - // DMA copy functions - virtual void DMAWrite(u32 _uAddr, u32 _uSize); - virtual void DMARead (u32 _uAddr, u32 _uSize); + virtual bool UseDelayedTransferCompletion() const { return false; } + virtual bool IsPresent() const { return false; } + virtual void SetCS(int) {} + virtual void DoState(PointerWrap&) {} + virtual void PauseAndLock(bool doLock, bool unpauseOnUnlock = true) {} + virtual IEXIDevice* FindDevice(TEXIDevices device_type, int customIndex = -1) + { + return (device_type == m_deviceType) ? this : nullptr; + } - virtual bool UseDelayedTransferCompletion() const { return false; } - - virtual bool IsPresent() const { return false; } - virtual void SetCS(int) {} - virtual void DoState(PointerWrap&) {} - virtual void PauseAndLock(bool doLock, bool unpauseOnUnlock=true) {} - virtual IEXIDevice* FindDevice(TEXIDevices device_type, int customIndex=-1) { return (device_type == m_deviceType) ? this : nullptr; } - - // Is generating interrupt ? - virtual bool IsInterruptSet() {return false;} - virtual ~IEXIDevice() {} - - // for savestates. storing it here seemed cleaner than requiring each implementation to report its type. - // I know this class is set up like an interface, but no code requires it to be strictly such. - TEXIDevices m_deviceType; + // Is generating interrupt ? + virtual bool IsInterruptSet() { return false; } + virtual ~IEXIDevice() {} + // for savestates. storing it here seemed cleaner than requiring each implementation to report its + // type. + // I know this class is set up like an interface, but no code requires it to be strictly such. + TEXIDevices m_deviceType; }; std::unique_ptr EXIDevice_Create(const TEXIDevices device_type, const int channel_num); diff --git a/Source/Core/Core/HW/EXI_DeviceAD16.cpp b/Source/Core/Core/HW/EXI_DeviceAD16.cpp index e4b676f36a..619b361682 100644 --- a/Source/Core/Core/HW/EXI_DeviceAD16.cpp +++ b/Source/Core/Core/HW/EXI_DeviceAD16.cpp @@ -2,85 +2,109 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/EXI_DeviceAD16.h" #include "Common/Assert.h" #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" -#include "Core/HW/EXI_DeviceAD16.h" -CEXIAD16::CEXIAD16() : - m_uPosition(0), - m_uCommand(0) +CEXIAD16::CEXIAD16() : m_uPosition(0), m_uCommand(0) { - m_uAD16Register.U32 = 0x00; + m_uAD16Register.U32 = 0x00; } void CEXIAD16::SetCS(int cs) { - if (cs) - m_uPosition = 0; + if (cs) + m_uPosition = 0; } bool CEXIAD16::IsPresent() const { - return true; + return true; } void CEXIAD16::TransferByte(u8& _byte) { - if (m_uPosition == 0) - { - m_uCommand = _byte; - } - else - { - switch (m_uCommand) - { - case init: - { - m_uAD16Register.U32 = 0x04120000; - switch (m_uPosition) - { - case 1: _dbg_assert_(EXPANSIONINTERFACE, (_byte == 0x00)); break; // just skip - case 2: _byte = m_uAD16Register.U8[0]; break; - case 3: _byte = m_uAD16Register.U8[1]; break; - case 4: _byte = m_uAD16Register.U8[2]; break; - case 5: _byte = m_uAD16Register.U8[3]; break; - } - } - break; + if (m_uPosition == 0) + { + m_uCommand = _byte; + } + else + { + switch (m_uCommand) + { + case init: + { + m_uAD16Register.U32 = 0x04120000; + switch (m_uPosition) + { + case 1: + _dbg_assert_(EXPANSIONINTERFACE, (_byte == 0x00)); + break; // just skip + case 2: + _byte = m_uAD16Register.U8[0]; + break; + case 3: + _byte = m_uAD16Register.U8[1]; + break; + case 4: + _byte = m_uAD16Register.U8[2]; + break; + case 5: + _byte = m_uAD16Register.U8[3]; + break; + } + } + break; - case write: - { - switch (m_uPosition) - { - case 1: m_uAD16Register.U8[0] = _byte; break; - case 2: m_uAD16Register.U8[1] = _byte; break; - case 3: m_uAD16Register.U8[2] = _byte; break; - case 4: m_uAD16Register.U8[3] = _byte; break; - } - } - break; + case write: + { + switch (m_uPosition) + { + case 1: + m_uAD16Register.U8[0] = _byte; + break; + case 2: + m_uAD16Register.U8[1] = _byte; + break; + case 3: + m_uAD16Register.U8[2] = _byte; + break; + case 4: + m_uAD16Register.U8[3] = _byte; + break; + } + } + break; - case read: - { - switch (m_uPosition) - { - case 1: _byte = m_uAD16Register.U8[0]; break; - case 2: _byte = m_uAD16Register.U8[1]; break; - case 3: _byte = m_uAD16Register.U8[2]; break; - case 4: _byte = m_uAD16Register.U8[3]; break; - } - } - break; - } - } + case read: + { + switch (m_uPosition) + { + case 1: + _byte = m_uAD16Register.U8[0]; + break; + case 2: + _byte = m_uAD16Register.U8[1]; + break; + case 3: + _byte = m_uAD16Register.U8[2]; + break; + case 4: + _byte = m_uAD16Register.U8[3]; + break; + } + } + break; + } + } - m_uPosition++; + m_uPosition++; } -void CEXIAD16::DoState(PointerWrap &p) +void CEXIAD16::DoState(PointerWrap& p) { - p.Do(m_uPosition); - p.Do(m_uCommand); - p.Do(m_uAD16Register); + p.Do(m_uPosition); + p.Do(m_uCommand); + p.Do(m_uAD16Register); } diff --git a/Source/Core/Core/HW/EXI_DeviceAD16.h b/Source/Core/Core/HW/EXI_DeviceAD16.h index c3bcf8a4a9..84c3ed56f4 100644 --- a/Source/Core/Core/HW/EXI_DeviceAD16.h +++ b/Source/Core/Core/HW/EXI_DeviceAD16.h @@ -11,29 +11,28 @@ class PointerWrap; class CEXIAD16 : public IEXIDevice { public: - CEXIAD16(); - void SetCS(int _iCS) override; - bool IsPresent() const override; - void DoState(PointerWrap &p) override; + CEXIAD16(); + void SetCS(int _iCS) override; + bool IsPresent() const override; + void DoState(PointerWrap& p) override; private: - enum - { - init = 0x00, - write = 0xa0, - read = 0xa2 - }; + enum + { + init = 0x00, + write = 0xa0, + read = 0xa2 + }; - union UAD16Reg - { - u32 U32; - u32 U8[4]; - }; + union UAD16Reg { + u32 U32; + u32 U8[4]; + }; - // STATE_TO_SAVE - u32 m_uPosition; - u32 m_uCommand; - UAD16Reg m_uAD16Register; + // STATE_TO_SAVE + u32 m_uPosition; + u32 m_uCommand; + UAD16Reg m_uAD16Register; - void TransferByte(u8& _uByte) override; + void TransferByte(u8& _uByte) override; }; diff --git a/Source/Core/Core/HW/EXI_DeviceAGP.cpp b/Source/Core/Core/HW/EXI_DeviceAGP.cpp index 54d5ea22b0..44bae38db1 100644 --- a/Source/Core/Core/HW/EXI_DeviceAGP.cpp +++ b/Source/Core/Core/HW/EXI_DeviceAGP.cpp @@ -14,351 +14,368 @@ CEXIAgp::CEXIAgp(int index) { - m_slot = index; + m_slot = index; - // Create the ROM - m_rom_size = 0; + // Create the ROM + m_rom_size = 0; - LoadRom(); + LoadRom(); - m_address = 0; + m_address = 0; } CEXIAgp::~CEXIAgp() { - std::string path; - std::string filename; - std::string ext; - std::string gbapath; - SplitPath(m_slot == 0 ? SConfig::GetInstance().m_strGbaCartA : SConfig::GetInstance().m_strGbaCartB, &path, &filename, &ext); - gbapath = path + filename; + std::string path; + std::string filename; + std::string ext; + std::string gbapath; + SplitPath(m_slot == 0 ? SConfig::GetInstance().m_strGbaCartA : + SConfig::GetInstance().m_strGbaCartB, + &path, &filename, &ext); + gbapath = path + filename; - SaveFileFromEEPROM(gbapath + ".sav"); + SaveFileFromEEPROM(gbapath + ".sav"); } void CEXIAgp::CRC8(u8* data, u32 size) { - for (u32 it = 0; it < size; it++) - { - u8 crc = 0; - m_hash = m_hash ^ data[it]; - if (m_hash & 1) crc ^= 0x5e; - if (m_hash & 2) crc ^= 0xbc; - if (m_hash & 4) crc ^= 0x61; - if (m_hash & 8) crc ^= 0xc2; - if (m_hash & 0x10) crc ^= 0x9d; - if (m_hash & 0x20) crc ^= 0x23; - if (m_hash & 0x40) crc ^= 0x46; - if (m_hash & 0x80) crc ^= 0x8c; - m_hash = crc; - } + for (u32 it = 0; it < size; it++) + { + u8 crc = 0; + m_hash = m_hash ^ data[it]; + if (m_hash & 1) + crc ^= 0x5e; + if (m_hash & 2) + crc ^= 0xbc; + if (m_hash & 4) + crc ^= 0x61; + if (m_hash & 8) + crc ^= 0xc2; + if (m_hash & 0x10) + crc ^= 0x9d; + if (m_hash & 0x20) + crc ^= 0x23; + if (m_hash & 0x40) + crc ^= 0x46; + if (m_hash & 0x80) + crc ^= 0x8c; + m_hash = crc; + } } void CEXIAgp::LoadRom() { - // Load whole ROM dump - std::string path; - std::string filename; - std::string ext; - std::string gbapath; - SplitPath(m_slot == 0 ? SConfig::GetInstance().m_strGbaCartA : SConfig::GetInstance().m_strGbaCartB, &path, &filename, &ext); - gbapath = path + filename; - LoadFileToROM(gbapath + ext); - INFO_LOG(EXPANSIONINTERFACE, "Loaded GBA rom: %s card: %d", gbapath.c_str(), m_slot); - LoadFileToEEPROM(gbapath + ".sav"); - INFO_LOG(EXPANSIONINTERFACE, "Loaded GBA sav: %s card: %d", gbapath.c_str(), m_slot); + // Load whole ROM dump + std::string path; + std::string filename; + std::string ext; + std::string gbapath; + SplitPath(m_slot == 0 ? SConfig::GetInstance().m_strGbaCartA : + SConfig::GetInstance().m_strGbaCartB, + &path, &filename, &ext); + gbapath = path + filename; + LoadFileToROM(gbapath + ext); + INFO_LOG(EXPANSIONINTERFACE, "Loaded GBA rom: %s card: %d", gbapath.c_str(), m_slot); + LoadFileToEEPROM(gbapath + ".sav"); + INFO_LOG(EXPANSIONINTERFACE, "Loaded GBA sav: %s card: %d", gbapath.c_str(), m_slot); } void CEXIAgp::LoadFileToROM(const std::string& filename) { - File::IOFile pStream(filename, "rb"); - if (pStream) - { - u64 filesize = pStream.GetSize(); - m_rom_size = filesize & 0xFFFFFFFF; - m_rom_mask = (m_rom_size - 1); + File::IOFile pStream(filename, "rb"); + if (pStream) + { + u64 filesize = pStream.GetSize(); + m_rom_size = filesize & 0xFFFFFFFF; + m_rom_mask = (m_rom_size - 1); - m_rom.resize(m_rom_size); + m_rom.resize(m_rom_size); - pStream.ReadBytes(m_rom.data(), filesize); - } - else - { - // dummy rom data - m_rom.resize(0x2000); - } + pStream.ReadBytes(m_rom.data(), filesize); + } + else + { + // dummy rom data + m_rom.resize(0x2000); + } } void CEXIAgp::LoadFileToEEPROM(const std::string& filename) { - // Technically one of EEPROM, Flash, SRAM, FRAM - File::IOFile pStream(filename, "rb"); - if (pStream) - { - u64 filesize = pStream.GetSize(); - m_eeprom_size = filesize & 0xFFFFFFFF; - m_eeprom_mask = (m_eeprom_size - 1); + // Technically one of EEPROM, Flash, SRAM, FRAM + File::IOFile pStream(filename, "rb"); + if (pStream) + { + u64 filesize = pStream.GetSize(); + m_eeprom_size = filesize & 0xFFFFFFFF; + m_eeprom_mask = (m_eeprom_size - 1); - m_eeprom.resize(m_eeprom_size); - pStream.ReadBytes(m_eeprom.data(), filesize); - if ((m_eeprom_size == 512) || (m_eeprom_size == 8192)) - { - // Handle endian read - could be done with byte access in 0xAE commands instead - for (u32 index = 0; index < (m_eeprom_size / 8); index++) - { - u64 NewVal = 0; - for (u32 indexb = 0; indexb < 8; indexb++) - NewVal = (NewVal << 0x8) | m_eeprom[index * 8 + indexb]; - ((u64*)(m_eeprom.data()))[index] = NewVal; - } - m_eeprom_add_end = (m_eeprom_size == 512 ? (2 + 6) : (2 + 14)); - m_eeprom_add_mask = (m_eeprom_size == 512 ? 0x3F : 0x3FF); - m_eeprom_read_mask = (m_eeprom_size == 512 ? 0x80 : 0x8000); - m_eeprom_status_mask = (m_rom_size == 0x2000000 ? 0x1FFFF00 : 0x1000000); - } - else - m_eeprom_status_mask = 0; - } - else - { - m_eeprom_size = 0; - m_eeprom.clear(); - } + m_eeprom.resize(m_eeprom_size); + pStream.ReadBytes(m_eeprom.data(), filesize); + if ((m_eeprom_size == 512) || (m_eeprom_size == 8192)) + { + // Handle endian read - could be done with byte access in 0xAE commands instead + for (u32 index = 0; index < (m_eeprom_size / 8); index++) + { + u64 NewVal = 0; + for (u32 indexb = 0; indexb < 8; indexb++) + NewVal = (NewVal << 0x8) | m_eeprom[index * 8 + indexb]; + ((u64*)(m_eeprom.data()))[index] = NewVal; + } + m_eeprom_add_end = (m_eeprom_size == 512 ? (2 + 6) : (2 + 14)); + m_eeprom_add_mask = (m_eeprom_size == 512 ? 0x3F : 0x3FF); + m_eeprom_read_mask = (m_eeprom_size == 512 ? 0x80 : 0x8000); + m_eeprom_status_mask = (m_rom_size == 0x2000000 ? 0x1FFFF00 : 0x1000000); + } + else + m_eeprom_status_mask = 0; + } + else + { + m_eeprom_size = 0; + m_eeprom.clear(); + } } void CEXIAgp::SaveFileFromEEPROM(const std::string& filename) { - File::IOFile pStream(filename, "wb"); - if (pStream) - { - if ((m_eeprom_size == 512) || (m_eeprom_size == 8192)) - { - // Handle endian write - could be done with byte access in 0xAE commands instead - std::vector temp_eeprom(m_eeprom_size); - for (u32 index = 0; index < (m_eeprom_size / 8); index++) - { - u64 NewVal = ((u64*)(m_eeprom.data()))[index]; - for (u32 indexb = 0; indexb < 8; indexb++) - temp_eeprom[index * 8 + (7 - indexb)] = (NewVal >> (indexb * 8)) & 0xFF; - } - pStream.WriteBytes(temp_eeprom.data(), m_eeprom_size); - } - else - { - pStream.WriteBytes(m_eeprom.data(), m_eeprom_size); - } - } + File::IOFile pStream(filename, "wb"); + if (pStream) + { + if ((m_eeprom_size == 512) || (m_eeprom_size == 8192)) + { + // Handle endian write - could be done with byte access in 0xAE commands instead + std::vector temp_eeprom(m_eeprom_size); + for (u32 index = 0; index < (m_eeprom_size / 8); index++) + { + u64 NewVal = ((u64*)(m_eeprom.data()))[index]; + for (u32 indexb = 0; indexb < 8; indexb++) + temp_eeprom[index * 8 + (7 - indexb)] = (NewVal >> (indexb * 8)) & 0xFF; + } + pStream.WriteBytes(temp_eeprom.data(), m_eeprom_size); + } + else + { + pStream.WriteBytes(m_eeprom.data(), m_eeprom_size); + } + } } u32 CEXIAgp::ImmRead(u32 _uSize) { - u32 uData = 0; - u8 RomVal1, RomVal2, RomVal3, RomVal4; + u32 uData = 0; + u8 RomVal1, RomVal2, RomVal3, RomVal4; - switch (m_current_cmd) - { - case 0xAE000000: // Clock handshake? - uData = 0x5AAA5517; // 17 is precalculated hash - m_current_cmd = 0; - break; - case 0xAE010000: // Init? - uData = (m_return_pos == 0) ? 0x01020304 : 0xF0020304; // F0 is precalculated hash, 020304 is left over - if (m_return_pos == 1) - m_current_cmd = 0; - else - m_return_pos = 1; - break; - case 0xAE020000: // Read 2 bytes with 24 bit address - if (m_eeprom_write_status && ((m_rw_offset & m_eeprom_status_mask) == m_eeprom_status_mask) && (m_eeprom_status_mask != 0)) - { - RomVal1 = 0x1; - RomVal2 = 0x0; - } - else - { - RomVal1 = m_rom[(m_rw_offset++) & m_rom_mask]; - RomVal2 = m_rom[(m_rw_offset++) & m_rom_mask]; - } - CRC8(&RomVal2, 1); - CRC8(&RomVal1, 1); - uData = (RomVal2 << 24) | (RomVal1 << 16) | (m_hash << 8); - m_current_cmd = 0; - break; - case 0xAE030000: // read the next 4 bytes out of 0x10000 group - if (_uSize == 1) - { - uData = 0xFF000000; - m_current_cmd = 0; - } - else - { - RomVal1 = m_rom[(m_rw_offset++) & m_rom_mask]; - RomVal2 = m_rom[(m_rw_offset++) & m_rom_mask]; - RomVal3 = m_rom[(m_rw_offset++) & m_rom_mask]; - RomVal4 = m_rom[(m_rw_offset++) & m_rom_mask]; - CRC8(&RomVal2, 1); - CRC8(&RomVal1, 1); - CRC8(&RomVal4, 1); - CRC8(&RomVal3, 1); - uData = (RomVal2 << 24) | (RomVal1 << 16) | (RomVal4 << 8) | (RomVal3); - } - break; - case 0xAE040000: // read 1 byte from 16 bit address - // ToDo: Flash special handling - if (m_eeprom_size == 0) - RomVal1 = 0xFF; - else - RomVal1 = (m_eeprom.data())[m_eeprom_pos]; - CRC8(&RomVal1, 1); - uData = (RomVal1 << 24) | (m_hash << 16); - m_current_cmd = 0; - break; - case 0xAE0B0000: // read 1 bit from DMA with 6 or 14 bit address - // Change to byte access instead of endian file access? - RomVal1 = EE_READ_FALSE; - if ((m_eeprom_size != 0) - && (m_eeprom_pos >= EE_IGNORE_BITS) - && ((((u64*)m_eeprom.data())[(m_eeprom_cmd >> 1) & m_eeprom_add_mask]) >> ((EE_DATA_BITS - 1) - (m_eeprom_pos - EE_IGNORE_BITS))) & 0x1) - { - RomVal1 = EE_READ_TRUE; - } - RomVal2 = 0; - CRC8(&RomVal2, 1); - CRC8(&RomVal1, 1); - uData = (RomVal2 << 24) | (RomVal1 << 16) | (m_hash << 8); - m_eeprom_pos++; - m_current_cmd = 0; - break; - case 0xAE070000: // complete write 1 byte from 16 bit address - case 0xAE0C0000: // complete write 1 bit from dma with 6 or 14 bit address - uData = m_hash << 24; - m_current_cmd = 0; - break; - default: - uData = 0x0; - m_current_cmd = 0; - break; - } - INFO_LOG(EXPANSIONINTERFACE, "AGP read %x", uData); - return uData; + switch (m_current_cmd) + { + case 0xAE000000: // Clock handshake? + uData = 0x5AAA5517; // 17 is precalculated hash + m_current_cmd = 0; + break; + case 0xAE010000: // Init? + uData = (m_return_pos == 0) ? 0x01020304 : + 0xF0020304; // F0 is precalculated hash, 020304 is left over + if (m_return_pos == 1) + m_current_cmd = 0; + else + m_return_pos = 1; + break; + case 0xAE020000: // Read 2 bytes with 24 bit address + if (m_eeprom_write_status && ((m_rw_offset & m_eeprom_status_mask) == m_eeprom_status_mask) && + (m_eeprom_status_mask != 0)) + { + RomVal1 = 0x1; + RomVal2 = 0x0; + } + else + { + RomVal1 = m_rom[(m_rw_offset++) & m_rom_mask]; + RomVal2 = m_rom[(m_rw_offset++) & m_rom_mask]; + } + CRC8(&RomVal2, 1); + CRC8(&RomVal1, 1); + uData = (RomVal2 << 24) | (RomVal1 << 16) | (m_hash << 8); + m_current_cmd = 0; + break; + case 0xAE030000: // read the next 4 bytes out of 0x10000 group + if (_uSize == 1) + { + uData = 0xFF000000; + m_current_cmd = 0; + } + else + { + RomVal1 = m_rom[(m_rw_offset++) & m_rom_mask]; + RomVal2 = m_rom[(m_rw_offset++) & m_rom_mask]; + RomVal3 = m_rom[(m_rw_offset++) & m_rom_mask]; + RomVal4 = m_rom[(m_rw_offset++) & m_rom_mask]; + CRC8(&RomVal2, 1); + CRC8(&RomVal1, 1); + CRC8(&RomVal4, 1); + CRC8(&RomVal3, 1); + uData = (RomVal2 << 24) | (RomVal1 << 16) | (RomVal4 << 8) | (RomVal3); + } + break; + case 0xAE040000: // read 1 byte from 16 bit address + // ToDo: Flash special handling + if (m_eeprom_size == 0) + RomVal1 = 0xFF; + else + RomVal1 = (m_eeprom.data())[m_eeprom_pos]; + CRC8(&RomVal1, 1); + uData = (RomVal1 << 24) | (m_hash << 16); + m_current_cmd = 0; + break; + case 0xAE0B0000: // read 1 bit from DMA with 6 or 14 bit address + // Change to byte access instead of endian file access? + RomVal1 = EE_READ_FALSE; + if ((m_eeprom_size != 0) && (m_eeprom_pos >= EE_IGNORE_BITS) && + ((((u64*)m_eeprom.data())[(m_eeprom_cmd >> 1) & m_eeprom_add_mask]) >> + ((EE_DATA_BITS - 1) - (m_eeprom_pos - EE_IGNORE_BITS))) & + 0x1) + { + RomVal1 = EE_READ_TRUE; + } + RomVal2 = 0; + CRC8(&RomVal2, 1); + CRC8(&RomVal1, 1); + uData = (RomVal2 << 24) | (RomVal1 << 16) | (m_hash << 8); + m_eeprom_pos++; + m_current_cmd = 0; + break; + case 0xAE070000: // complete write 1 byte from 16 bit address + case 0xAE0C0000: // complete write 1 bit from dma with 6 or 14 bit address + uData = m_hash << 24; + m_current_cmd = 0; + break; + default: + uData = 0x0; + m_current_cmd = 0; + break; + } + INFO_LOG(EXPANSIONINTERFACE, "AGP read %x", uData); + return uData; } void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize) { - // 0x00 = Execute current command? - if ((_uSize == 1) && ((_uData & 0xFF000000) == 0)) - return; + // 0x00 = Execute current command? + if ((_uSize == 1) && ((_uData & 0xFF000000) == 0)) + return; - u8 HashCmd; - u64 Mask; - INFO_LOG(EXPANSIONINTERFACE, "AGP command %x", _uData); - switch (m_current_cmd) - { - case 0xAE020000: // set up 24 bit address for read 2 bytes - case 0xAE030000: // set up 24 bit address for read (0x10000 byte group) - // 25 bit address shifted one bit right = 24 bits - m_rw_offset = ((_uData & 0xFFFFFF00) >> (8 - 1)); - m_return_pos = 0; - HashCmd = (_uData & 0xFF000000) >> 24; - CRC8(&HashCmd, 1); - HashCmd = (_uData & 0x00FF0000) >> 16; - CRC8(&HashCmd, 1); - HashCmd = (_uData & 0x0000FF00) >> 8; - CRC8(&HashCmd, 1); - break; - case 0xAE040000: // set up 16 bit address for read 1 byte - // ToDo: Flash special handling - m_eeprom_pos = ((_uData & 0xFFFF0000) >> 0x10) & m_eeprom_mask; - HashCmd = (_uData & 0xFF000000) >> 24; - CRC8(&HashCmd, 1); - HashCmd = (_uData & 0x00FF0000) >> 16; - CRC8(&HashCmd, 1); - break; - case 0xAE070000: // write 1 byte from 16 bit address - // ToDo: Flash special handling - m_eeprom_pos = ((_uData & 0xFFFF0000) >> 0x10) & m_eeprom_mask; - if (m_eeprom_size != 0) - ((m_eeprom.data()))[(m_eeprom_pos)] = (_uData & 0x0000FF00) >> 0x8; - HashCmd = (_uData & 0xFF000000) >> 24; - CRC8(&HashCmd, 1); - HashCmd = (_uData & 0x00FF0000) >> 16; - CRC8(&HashCmd, 1); - HashCmd = (_uData & 0x0000FF00) >> 8; - CRC8(&HashCmd, 1); - break; - case 0xAE0C0000: // write 1 bit from dma with 6 or 14 bit address - if ((m_eeprom_pos < m_eeprom_add_end) || (m_eeprom_pos == ((m_eeprom_cmd & m_eeprom_read_mask) ? m_eeprom_add_end : m_eeprom_add_end + EE_DATA_BITS))) - { - Mask = (1ULL << (m_eeprom_add_end - std::min(m_eeprom_pos, m_eeprom_add_end))); - if ((_uData >> 16) & 0x1) - m_eeprom_cmd |= Mask; - else - m_eeprom_cmd &= ~Mask; - if (m_eeprom_pos == m_eeprom_add_end + EE_DATA_BITS) - { - // Change to byte access instead of endian file access? - if (m_eeprom_size != 0) - ((u64*)(m_eeprom.data()))[(m_eeprom_cmd >> 1) & m_eeprom_add_mask] = m_eeprom_data; - m_eeprom_write_status = true; - } - } - else - { - Mask = (1ULL << (m_eeprom_add_end + EE_DATA_BITS - 1 - m_eeprom_pos)); - if ((_uData >> 16) & 0x1) - m_eeprom_data |= Mask; - else - m_eeprom_data &= ~Mask; - } - m_eeprom_pos++; - m_return_pos = 0; - HashCmd = (_uData & 0xFF000000) >> 24; - CRC8(&HashCmd, 1); - HashCmd = (_uData & 0x00FF0000) >> 16; - CRC8(&HashCmd, 1); - break; - case 0xAE0B0000: - m_eeprom_write_status = false; - break; - case 0xAE000000: - case 0xAE010000: - case 0xAE090000: // start DMA - m_eeprom_write_status = false; //ToDo: Verify with hardware which commands disable EEPROM CS - // Fall-through intentional - case 0xAE0A0000: // end DMA - m_eeprom_pos = 0; - // Fall-through intentional - default: - m_current_cmd = _uData; - m_return_pos = 0; - m_hash = 0xFF; - HashCmd = (_uData & 0x00FF0000) >> 16; - CRC8(&HashCmd, 1); - break; - } + u8 HashCmd; + u64 Mask; + INFO_LOG(EXPANSIONINTERFACE, "AGP command %x", _uData); + switch (m_current_cmd) + { + case 0xAE020000: // set up 24 bit address for read 2 bytes + case 0xAE030000: // set up 24 bit address for read (0x10000 byte group) + // 25 bit address shifted one bit right = 24 bits + m_rw_offset = ((_uData & 0xFFFFFF00) >> (8 - 1)); + m_return_pos = 0; + HashCmd = (_uData & 0xFF000000) >> 24; + CRC8(&HashCmd, 1); + HashCmd = (_uData & 0x00FF0000) >> 16; + CRC8(&HashCmd, 1); + HashCmd = (_uData & 0x0000FF00) >> 8; + CRC8(&HashCmd, 1); + break; + case 0xAE040000: // set up 16 bit address for read 1 byte + // ToDo: Flash special handling + m_eeprom_pos = ((_uData & 0xFFFF0000) >> 0x10) & m_eeprom_mask; + HashCmd = (_uData & 0xFF000000) >> 24; + CRC8(&HashCmd, 1); + HashCmd = (_uData & 0x00FF0000) >> 16; + CRC8(&HashCmd, 1); + break; + case 0xAE070000: // write 1 byte from 16 bit address + // ToDo: Flash special handling + m_eeprom_pos = ((_uData & 0xFFFF0000) >> 0x10) & m_eeprom_mask; + if (m_eeprom_size != 0) + ((m_eeprom.data()))[(m_eeprom_pos)] = (_uData & 0x0000FF00) >> 0x8; + HashCmd = (_uData & 0xFF000000) >> 24; + CRC8(&HashCmd, 1); + HashCmd = (_uData & 0x00FF0000) >> 16; + CRC8(&HashCmd, 1); + HashCmd = (_uData & 0x0000FF00) >> 8; + CRC8(&HashCmd, 1); + break; + case 0xAE0C0000: // write 1 bit from dma with 6 or 14 bit address + if ((m_eeprom_pos < m_eeprom_add_end) || + (m_eeprom_pos == ((m_eeprom_cmd & m_eeprom_read_mask) ? m_eeprom_add_end : + m_eeprom_add_end + EE_DATA_BITS))) + { + Mask = (1ULL << (m_eeprom_add_end - std::min(m_eeprom_pos, m_eeprom_add_end))); + if ((_uData >> 16) & 0x1) + m_eeprom_cmd |= Mask; + else + m_eeprom_cmd &= ~Mask; + if (m_eeprom_pos == m_eeprom_add_end + EE_DATA_BITS) + { + // Change to byte access instead of endian file access? + if (m_eeprom_size != 0) + ((u64*)(m_eeprom.data()))[(m_eeprom_cmd >> 1) & m_eeprom_add_mask] = m_eeprom_data; + m_eeprom_write_status = true; + } + } + else + { + Mask = (1ULL << (m_eeprom_add_end + EE_DATA_BITS - 1 - m_eeprom_pos)); + if ((_uData >> 16) & 0x1) + m_eeprom_data |= Mask; + else + m_eeprom_data &= ~Mask; + } + m_eeprom_pos++; + m_return_pos = 0; + HashCmd = (_uData & 0xFF000000) >> 24; + CRC8(&HashCmd, 1); + HashCmd = (_uData & 0x00FF0000) >> 16; + CRC8(&HashCmd, 1); + break; + case 0xAE0B0000: + m_eeprom_write_status = false; + break; + case 0xAE000000: + case 0xAE010000: + case 0xAE090000: // start DMA + m_eeprom_write_status = false; // ToDo: Verify with hardware which commands disable EEPROM CS + // Fall-through intentional + case 0xAE0A0000: // end DMA + m_eeprom_pos = 0; + // Fall-through intentional + default: + m_current_cmd = _uData; + m_return_pos = 0; + m_hash = 0xFF; + HashCmd = (_uData & 0x00FF0000) >> 16; + CRC8(&HashCmd, 1); + break; + } } -void CEXIAgp::DoState(PointerWrap &p) +void CEXIAgp::DoState(PointerWrap& p) { - p.Do(m_slot); - p.Do(m_address); - p.Do(m_current_cmd); - p.Do(m_eeprom); - p.Do(m_eeprom_cmd); - p.Do(m_eeprom_data); - p.Do(m_eeprom_mask); - p.Do(m_eeprom_pos); - p.Do(m_eeprom_size); - p.Do(m_eeprom_add_end); - p.Do(m_eeprom_add_mask); - p.Do(m_eeprom_read_mask); - p.Do(m_eeprom_status_mask); - p.Do(m_eeprom_write_status); - p.Do(m_hash); - p.Do(m_position); - p.Do(m_return_pos); - p.Do(m_rom); - p.Do(m_rom_mask); - p.Do(m_rom_size); - p.Do(m_rw_offset); + p.Do(m_slot); + p.Do(m_address); + p.Do(m_current_cmd); + p.Do(m_eeprom); + p.Do(m_eeprom_cmd); + p.Do(m_eeprom_data); + p.Do(m_eeprom_mask); + p.Do(m_eeprom_pos); + p.Do(m_eeprom_size); + p.Do(m_eeprom_add_end); + p.Do(m_eeprom_add_mask); + p.Do(m_eeprom_read_mask); + p.Do(m_eeprom_status_mask); + p.Do(m_eeprom_write_status); + p.Do(m_hash); + p.Do(m_position); + p.Do(m_return_pos); + p.Do(m_rom); + p.Do(m_rom_mask); + p.Do(m_rom_size); + p.Do(m_rw_offset); } diff --git a/Source/Core/Core/HW/EXI_DeviceAGP.h b/Source/Core/Core/HW/EXI_DeviceAGP.h index 45b1ec2560..49fc697572 100644 --- a/Source/Core/Core/HW/EXI_DeviceAGP.h +++ b/Source/Core/Core/HW/EXI_DeviceAGP.h @@ -11,56 +11,55 @@ class PointerWrap; -class CEXIAgp - : public IEXIDevice +class CEXIAgp : public IEXIDevice { public: - CEXIAgp(const int index); - virtual ~CEXIAgp() override; - bool IsPresent() const override { return true; } - void ImmWrite(u32 _uData, u32 _uSize) override; - u32 ImmRead(u32 _uSize) override; - void DoState(PointerWrap &p) override; + CEXIAgp(const int index); + virtual ~CEXIAgp() override; + bool IsPresent() const override { return true; } + void ImmWrite(u32 _uData, u32 _uSize) override; + u32 ImmRead(u32 _uSize) override; + void DoState(PointerWrap& p) override; private: - enum - { - EE_IGNORE_BITS = 0x4, - EE_DATA_BITS = 0x40, - EE_READ_FALSE = 0xA, - EE_READ_TRUE = 0xB, - }; + enum + { + EE_IGNORE_BITS = 0x4, + EE_DATA_BITS = 0x40, + EE_READ_FALSE = 0xA, + EE_READ_TRUE = 0xB, + }; - int m_slot; + int m_slot; - //! ROM - u32 m_rom_size = 0; - u32 m_rom_mask = 0; - u32 m_eeprom_size = 0; - u32 m_eeprom_mask = 0; - std::vector m_rom; - std::vector m_eeprom; + //! ROM + u32 m_rom_size = 0; + u32 m_rom_mask = 0; + u32 m_eeprom_size = 0; + u32 m_eeprom_mask = 0; + std::vector m_rom; + std::vector m_eeprom; - //! Helper - u32 m_position = 0; - u32 m_address = 0; - u32 m_rw_offset = 0; - u64 m_eeprom_data = 0; - u16 m_eeprom_pos = 0; - u32 m_eeprom_cmd = 0; - u16 m_eeprom_add_end = 0; - u16 m_eeprom_add_mask = 0; - u16 m_eeprom_read_mask = 0; - u32 m_eeprom_status_mask = 0; - bool m_eeprom_write_status = false; + //! Helper + u32 m_position = 0; + u32 m_address = 0; + u32 m_rw_offset = 0; + u64 m_eeprom_data = 0; + u16 m_eeprom_pos = 0; + u32 m_eeprom_cmd = 0; + u16 m_eeprom_add_end = 0; + u16 m_eeprom_add_mask = 0; + u16 m_eeprom_read_mask = 0; + u32 m_eeprom_status_mask = 0; + bool m_eeprom_write_status = false; - void LoadFileToROM(const std::string& filename); - void LoadFileToEEPROM(const std::string& filename); - void SaveFileFromEEPROM(const std::string& filename); - void LoadRom(); - void CRC8(u8* data, u32 size); + void LoadFileToROM(const std::string& filename); + void LoadFileToEEPROM(const std::string& filename); + void SaveFileFromEEPROM(const std::string& filename); + void LoadRom(); + void CRC8(u8* data, u32 size); - u8 m_hash = 0; - u32 m_current_cmd = 0; - u32 m_return_pos = 0; + u8 m_hash = 0; + u32 m_current_cmd = 0; + u32 m_return_pos = 0; }; diff --git a/Source/Core/Core/HW/EXI_DeviceAMBaseboard.cpp b/Source/Core/Core/HW/EXI_DeviceAMBaseboard.cpp index 7e2d0e61ca..9e1c99d45c 100644 --- a/Source/Core/Core/HW/EXI_DeviceAMBaseboard.cpp +++ b/Source/Core/Core/HW/EXI_DeviceAMBaseboard.cpp @@ -2,131 +2,129 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/EXI.h" #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" -#include "Core/HW/EXI.h" #include "Core/HW/EXI_DeviceAMBaseboard.h" -CEXIAMBaseboard::CEXIAMBaseboard() - : m_position(0) - , m_have_irq(false) +CEXIAMBaseboard::CEXIAMBaseboard() : m_position(0), m_have_irq(false) { } void CEXIAMBaseboard::SetCS(int cs) { - ERROR_LOG(SP1, "AM-BB ChipSelect=%d", cs); - if (cs) - m_position = 0; + ERROR_LOG(SP1, "AM-BB ChipSelect=%d", cs); + if (cs) + m_position = 0; } bool CEXIAMBaseboard::IsPresent() const { - return true; + return true; } void CEXIAMBaseboard::TransferByte(u8& _byte) { - /* - ID: - 00 00 xx xx xx xx - xx xx 06 04 10 00 - CMD: - 01 00 00 b3 xx - xx xx xx xx 04 - exi_lanctl_write: - ff 02 01 63 xx - xx xx xx xx 04 - exi_imr_read: - 86 00 00 f5 xx xx xx - xx xx xx xx 04 rr rr - exi_imr_write: - 87 80 5c 17 xx - xx xx xx xx 04 + /* + ID: + 00 00 xx xx xx xx + xx xx 06 04 10 00 + CMD: + 01 00 00 b3 xx + xx xx xx xx 04 + exi_lanctl_write: + ff 02 01 63 xx + xx xx xx xx 04 + exi_imr_read: + 86 00 00 f5 xx xx xx + xx xx xx xx 04 rr rr + exi_imr_write: + 87 80 5c 17 xx + xx xx xx xx 04 - exi_isr_read: - 82 .. .. .. xx xx xx - xx xx xx xx 04 rr rr - 3 byte command, 1 byte checksum - */ - DEBUG_LOG(SP1, "AM-BB > %02x", _byte); - if (m_position < 4) - { - m_command[m_position] = _byte; - _byte = 0xFF; - } + exi_isr_read: + 82 .. .. .. xx xx xx + xx xx xx xx 04 rr rr + 3 byte command, 1 byte checksum + */ + DEBUG_LOG(SP1, "AM-BB > %02x", _byte); + if (m_position < 4) + { + m_command[m_position] = _byte; + _byte = 0xFF; + } - if ((m_position >= 2) && (m_command[0] == 0 && m_command[1] == 0)) - { - _byte = "\x06\x04\x10\x00"[(m_position - 2) & 3]; - } - else if (m_position == 3) - { - unsigned int checksum = (m_command[0] << 24) | (m_command[1] << 16) | (m_command[2] << 8); - unsigned int bit = 0x80000000UL; - unsigned int check = 0x8D800000UL; - while (bit >= 0x100) - { - if (checksum & bit) - checksum ^= check; - check >>= 1; - bit >>= 1; - } + if ((m_position >= 2) && (m_command[0] == 0 && m_command[1] == 0)) + { + _byte = "\x06\x04\x10\x00"[(m_position - 2) & 3]; + } + else if (m_position == 3) + { + unsigned int checksum = (m_command[0] << 24) | (m_command[1] << 16) | (m_command[2] << 8); + unsigned int bit = 0x80000000UL; + unsigned int check = 0x8D800000UL; + while (bit >= 0x100) + { + if (checksum & bit) + checksum ^= check; + check >>= 1; + bit >>= 1; + } - if (m_command[3] != (checksum & 0xFF)) - ERROR_LOG(SP1, "AM-BB cs: %02x, w: %02x", m_command[3], checksum & 0xFF); - } - else - { - if (m_position == 4) - { - _byte = 4; - ERROR_LOG(SP1, "AM-BB COMMAND: %02x %02x %02x", m_command[0], m_command[1], m_command[2]); + if (m_command[3] != (checksum & 0xFF)) + ERROR_LOG(SP1, "AM-BB cs: %02x, w: %02x", m_command[3], checksum & 0xFF); + } + else + { + if (m_position == 4) + { + _byte = 4; + ERROR_LOG(SP1, "AM-BB COMMAND: %02x %02x %02x", m_command[0], m_command[1], m_command[2]); - if ((m_command[0] == 0xFF) && (m_command[1] == 0) && (m_command[2] == 0)) - m_have_irq = true; - else if (m_command[0] == 0x82) - m_have_irq = false; - ExpansionInterface::UpdateInterrupts(); - } - else if (m_position > 4) - { - switch (m_command[0]) - { - case 0xFF: // lan - _byte = 0xFF; - break; - case 0x86: // imr - _byte = 0x00; - break; - case 0x82: // isr - _byte = m_have_irq ? 0xFF : 0; - break; - default: - _dbg_assert_msg_(SP1, 0, "Unknown AM-BB command"); - break; - } - } - else - { - _byte = 0xFF; - } - } - DEBUG_LOG(SP1, "AM-BB < %02x", _byte); - m_position++; + if ((m_command[0] == 0xFF) && (m_command[1] == 0) && (m_command[2] == 0)) + m_have_irq = true; + else if (m_command[0] == 0x82) + m_have_irq = false; + ExpansionInterface::UpdateInterrupts(); + } + else if (m_position > 4) + { + switch (m_command[0]) + { + case 0xFF: // lan + _byte = 0xFF; + break; + case 0x86: // imr + _byte = 0x00; + break; + case 0x82: // isr + _byte = m_have_irq ? 0xFF : 0; + break; + default: + _dbg_assert_msg_(SP1, 0, "Unknown AM-BB command"); + break; + } + } + else + { + _byte = 0xFF; + } + } + DEBUG_LOG(SP1, "AM-BB < %02x", _byte); + m_position++; } bool CEXIAMBaseboard::IsInterruptSet() { - if (m_have_irq) - ERROR_LOG(SP1, "AM-BB IRQ"); - return m_have_irq; + if (m_have_irq) + ERROR_LOG(SP1, "AM-BB IRQ"); + return m_have_irq; } -void CEXIAMBaseboard::DoState(PointerWrap &p) +void CEXIAMBaseboard::DoState(PointerWrap& p) { - p.Do(m_position); - p.Do(m_have_irq); - p.Do(m_command); + p.Do(m_position); + p.Do(m_have_irq); + p.Do(m_command); } diff --git a/Source/Core/Core/HW/EXI_DeviceAMBaseboard.h b/Source/Core/Core/HW/EXI_DeviceAMBaseboard.h index 50b9d0354a..423a23be71 100644 --- a/Source/Core/Core/HW/EXI_DeviceAMBaseboard.h +++ b/Source/Core/Core/HW/EXI_DeviceAMBaseboard.h @@ -11,16 +11,16 @@ class PointerWrap; class CEXIAMBaseboard : public IEXIDevice { public: - CEXIAMBaseboard(); + CEXIAMBaseboard(); - void SetCS(int _iCS) override; - bool IsPresent() const override; - bool IsInterruptSet() override; - void DoState(PointerWrap &p) override; + void SetCS(int _iCS) override; + bool IsPresent() const override; + bool IsInterruptSet() override; + void DoState(PointerWrap& p) override; private: - void TransferByte(u8& _uByte) override; - int m_position; - bool m_have_irq; - unsigned char m_command[4]; + void TransferByte(u8& _uByte) override; + int m_position; + bool m_have_irq; + unsigned char m_command[4]; }; diff --git a/Source/Core/Core/HW/EXI_DeviceEthernet.cpp b/Source/Core/Core/HW/EXI_DeviceEthernet.cpp index 76cf3aea72..dd0aed4be9 100644 --- a/Source/Core/Core/HW/EXI_DeviceEthernet.cpp +++ b/Source/Core/Core/HW/EXI_DeviceEthernet.cpp @@ -6,8 +6,8 @@ #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" -#include "Common/Network.h" #include "Common/Logging/Log.h" +#include "Common/Network.h" #include "Core/ConfigManager.h" #include "Core/HW/EXI.h" #include "Core/HW/EXI_DeviceEthernet.h" @@ -17,580 +17,571 @@ // Multiple parts of this implementation depend on Dolphin // being compiled for a little endian host. - CEXIETHERNET::CEXIETHERNET() { - tx_fifo = std::make_unique(BBA_TXFIFO_SIZE); - mBbaMem = std::make_unique(BBA_MEM_SIZE); + tx_fifo = std::make_unique(BBA_TXFIFO_SIZE); + mBbaMem = std::make_unique(BBA_MEM_SIZE); - mRecvBuffer = std::make_unique(BBA_RECV_SIZE); - mRecvBufferLength = 0; + mRecvBuffer = std::make_unique(BBA_RECV_SIZE); + mRecvBufferLength = 0; - MXHardReset(); + MXHardReset(); - // Parse MAC address from config, and generate a new one if it doesn't - // exist or can't be parsed. - std::string &mac_addr_setting = SConfig::GetInstance().m_bba_mac; - u8 mac_addr[MAC_ADDRESS_SIZE] = { 0 }; + // Parse MAC address from config, and generate a new one if it doesn't + // exist or can't be parsed. + std::string& mac_addr_setting = SConfig::GetInstance().m_bba_mac; + u8 mac_addr[MAC_ADDRESS_SIZE] = {0}; - if (!StringToMacAddress(mac_addr_setting, mac_addr)) - { - GenerateMacAddress(BBA, mac_addr); - mac_addr_setting = MacAddressToString(mac_addr); - SConfig::GetInstance().SaveSettings(); - } + if (!StringToMacAddress(mac_addr_setting, mac_addr)) + { + GenerateMacAddress(BBA, mac_addr); + mac_addr_setting = MacAddressToString(mac_addr); + SConfig::GetInstance().SaveSettings(); + } - memcpy(&mBbaMem[BBA_NAFR_PAR0], mac_addr, MAC_ADDRESS_SIZE); + memcpy(&mBbaMem[BBA_NAFR_PAR0], mac_addr, MAC_ADDRESS_SIZE); - // HACK: .. fully established 100BASE-T link - mBbaMem[BBA_NWAYS] = NWAYS_LS100 | NWAYS_LPNWAY | NWAYS_100TXF | NWAYS_ANCLPT; + // HACK: .. fully established 100BASE-T link + mBbaMem[BBA_NWAYS] = NWAYS_LS100 | NWAYS_LPNWAY | NWAYS_100TXF | NWAYS_ANCLPT; #if defined(_WIN32) - mHAdapter = INVALID_HANDLE_VALUE; - memset(&mReadOverlapped, 0, sizeof(mReadOverlapped)); - memset(&mWriteOverlapped, 0, sizeof(mWriteOverlapped)); - mWritePending = false; + mHAdapter = INVALID_HANDLE_VALUE; + memset(&mReadOverlapped, 0, sizeof(mReadOverlapped)); + memset(&mWriteOverlapped, 0, sizeof(mWriteOverlapped)); + mWritePending = false; #elif defined(__linux__) || defined(__APPLE__) - fd = -1; + fd = -1; #endif } CEXIETHERNET::~CEXIETHERNET() { - Deactivate(); + Deactivate(); } void CEXIETHERNET::SetCS(int cs) { - if (cs) - { - // Invalidate the previous transfer - transfer.valid = false; - } + if (cs) + { + // Invalidate the previous transfer + transfer.valid = false; + } } bool CEXIETHERNET::IsPresent() const { - return true; + return true; } bool CEXIETHERNET::IsInterruptSet() { - return !!(exi_status.interrupt & exi_status.interrupt_mask); + return !!(exi_status.interrupt & exi_status.interrupt_mask); } void CEXIETHERNET::ImmWrite(u32 data, u32 size) { - data >>= (4 - size) * 8; + data >>= (4 - size) * 8; - if (!transfer.valid) - { - transfer.valid = true; - transfer.region = IsMXCommand(data) ? transfer.MX : transfer.EXI; - if (transfer.region == transfer.EXI) - transfer.address = ((data & ~0xc000) >> 8) & 0xff; - else - transfer.address = (data >> 8) & 0xffff; - transfer.direction = IsWriteCommand(data) ? transfer.WRITE : transfer.READ; + if (!transfer.valid) + { + transfer.valid = true; + transfer.region = IsMXCommand(data) ? transfer.MX : transfer.EXI; + if (transfer.region == transfer.EXI) + transfer.address = ((data & ~0xc000) >> 8) & 0xff; + else + transfer.address = (data >> 8) & 0xffff; + transfer.direction = IsWriteCommand(data) ? transfer.WRITE : transfer.READ; - DEBUG_LOG(SP1, "%s %s %s %x", - IsMXCommand(data) ? "mx " : "exi", - IsWriteCommand(data) ? "write" : "read ", - GetRegisterName(), - transfer.address); + DEBUG_LOG(SP1, "%s %s %s %x", IsMXCommand(data) ? "mx " : "exi", + IsWriteCommand(data) ? "write" : "read ", GetRegisterName(), transfer.address); - if (transfer.address == BBA_IOB && transfer.region == transfer.MX) - { - ERROR_LOG(SP1, "Usage of BBA_IOB indicates that the rx packet descriptor has been corrupted. Killing Dolphin..."); - exit(0); - } + if (transfer.address == BBA_IOB && transfer.region == transfer.MX) + { + ERROR_LOG(SP1, "Usage of BBA_IOB indicates that the rx packet descriptor has been corrupted. " + "Killing Dolphin..."); + exit(0); + } - // transfer has been setup - return; - } + // transfer has been setup + return; + } - // Reach here if we're actually writing data to the EXI or MX region. + // Reach here if we're actually writing data to the EXI or MX region. - DEBUG_LOG(SP1, "%s write %0*x", - transfer.region == transfer.MX ? "mx " : "exi", size * 2, data); + DEBUG_LOG(SP1, "%s write %0*x", transfer.region == transfer.MX ? "mx " : "exi", size * 2, data); - if (transfer.region == transfer.EXI) - { - switch (transfer.address) - { - case INTERRUPT: - exi_status.interrupt &= data ^ 0xff; - break; - case INTERRUPT_MASK: - exi_status.interrupt_mask = data; - break; - } - ExpansionInterface::UpdateInterrupts(); - } - else - { - MXCommandHandler(data, size); - } + if (transfer.region == transfer.EXI) + { + switch (transfer.address) + { + case INTERRUPT: + exi_status.interrupt &= data ^ 0xff; + break; + case INTERRUPT_MASK: + exi_status.interrupt_mask = data; + break; + } + ExpansionInterface::UpdateInterrupts(); + } + else + { + MXCommandHandler(data, size); + } } u32 CEXIETHERNET::ImmRead(u32 size) { - u32 ret = 0; + u32 ret = 0; - if (transfer.region == transfer.EXI) - { - switch (transfer.address) - { - case EXI_ID: - ret = EXI_DEVTYPE_ETHER; - break; - case REVISION_ID: - ret = exi_status.revision_id; - break; - case DEVICE_ID: - ret = exi_status.device_id; - break; - case ACSTART: - ret = exi_status.acstart; - break; - case INTERRUPT: - ret = exi_status.interrupt; - break; - } + if (transfer.region == transfer.EXI) + { + switch (transfer.address) + { + case EXI_ID: + ret = EXI_DEVTYPE_ETHER; + break; + case REVISION_ID: + ret = exi_status.revision_id; + break; + case DEVICE_ID: + ret = exi_status.device_id; + break; + case ACSTART: + ret = exi_status.acstart; + break; + case INTERRUPT: + ret = exi_status.interrupt; + break; + } - transfer.address += size; - } - else - { - for (int i = size - 1; i >= 0; i--) - ret |= mBbaMem[transfer.address++] << (i * 8); - } + transfer.address += size; + } + else + { + for (int i = size - 1; i >= 0; i--) + ret |= mBbaMem[transfer.address++] << (i * 8); + } - DEBUG_LOG(SP1, "imm r%i: %0*x", size, size * 2, ret); + DEBUG_LOG(SP1, "imm r%i: %0*x", size, size * 2, ret); - ret <<= (4 - size) * 8; + ret <<= (4 - size) * 8; - return ret; + return ret; } void CEXIETHERNET::DMAWrite(u32 addr, u32 size) { - DEBUG_LOG(SP1, "DMA write: %08x %x", addr, size); + DEBUG_LOG(SP1, "DMA write: %08x %x", addr, size); - if (transfer.region == transfer.MX && - transfer.direction == transfer.WRITE && - transfer.address == BBA_WRTXFIFOD) - { - DirectFIFOWrite(Memory::GetPointer(addr), size); - } - else - { - ERROR_LOG(SP1, "DMA write in %s %s mode - not implemented", - transfer.region == transfer.EXI ? "exi" : "mx", - transfer.direction == transfer.READ ? "read" : "write"); - } + if (transfer.region == transfer.MX && transfer.direction == transfer.WRITE && + transfer.address == BBA_WRTXFIFOD) + { + DirectFIFOWrite(Memory::GetPointer(addr), size); + } + else + { + ERROR_LOG(SP1, "DMA write in %s %s mode - not implemented", + transfer.region == transfer.EXI ? "exi" : "mx", + transfer.direction == transfer.READ ? "read" : "write"); + } } void CEXIETHERNET::DMARead(u32 addr, u32 size) { - DEBUG_LOG(SP1, "DMA read: %08x %x", addr, size); + DEBUG_LOG(SP1, "DMA read: %08x %x", addr, size); - Memory::CopyToEmu(addr, &mBbaMem[transfer.address], size); + Memory::CopyToEmu(addr, &mBbaMem[transfer.address], size); - transfer.address += size; + transfer.address += size; } -void CEXIETHERNET::DoState(PointerWrap &p) +void CEXIETHERNET::DoState(PointerWrap& p) { - p.DoArray(tx_fifo.get(), BBA_TXFIFO_SIZE); - p.DoArray(mBbaMem.get(), BBA_MEM_SIZE); + p.DoArray(tx_fifo.get(), BBA_TXFIFO_SIZE); + p.DoArray(mBbaMem.get(), BBA_MEM_SIZE); } bool CEXIETHERNET::IsMXCommand(u32 const data) { - return !!(data & (1 << 31)); + return !!(data & (1 << 31)); } bool CEXIETHERNET::IsWriteCommand(u32 const data) { - return IsMXCommand(data) ? !!(data & (1 << 30)) : !!(data & (1 << 14)); + return IsMXCommand(data) ? !!(data & (1 << 30)) : !!(data & (1 << 14)); } const char* CEXIETHERNET::GetRegisterName() const { -#define STR_RETURN(x) case x: return #x; +#define STR_RETURN(x) \ + case x: \ + return #x; - if (transfer.region == transfer.EXI) - { - switch (transfer.address) - { - STR_RETURN(EXI_ID) - STR_RETURN(REVISION_ID) - STR_RETURN(INTERRUPT) - STR_RETURN(INTERRUPT_MASK) - STR_RETURN(DEVICE_ID) - STR_RETURN(ACSTART) - STR_RETURN(HASH_READ) - STR_RETURN(HASH_WRITE) - STR_RETURN(HASH_STATUS) - STR_RETURN(RESET) - default: return "unknown"; - } - } - else - { - switch (transfer.address) - { - STR_RETURN(BBA_NCRA) - STR_RETURN(BBA_NCRB) - STR_RETURN(BBA_LTPS) - STR_RETURN(BBA_LRPS) - STR_RETURN(BBA_IMR) - STR_RETURN(BBA_IR) - STR_RETURN(BBA_BP) - STR_RETURN(BBA_TLBP) - STR_RETURN(BBA_TWP) - STR_RETURN(BBA_IOB) - STR_RETURN(BBA_TRP) - STR_RETURN(BBA_RWP) - STR_RETURN(BBA_RRP) - STR_RETURN(BBA_RHBP) - STR_RETURN(BBA_RXINTT) - STR_RETURN(BBA_NAFR_PAR0) - STR_RETURN(BBA_NAFR_PAR1) - STR_RETURN(BBA_NAFR_PAR2) - STR_RETURN(BBA_NAFR_PAR3) - STR_RETURN(BBA_NAFR_PAR4) - STR_RETURN(BBA_NAFR_PAR5) - STR_RETURN(BBA_NAFR_MAR0) - STR_RETURN(BBA_NAFR_MAR1) - STR_RETURN(BBA_NAFR_MAR2) - STR_RETURN(BBA_NAFR_MAR3) - STR_RETURN(BBA_NAFR_MAR4) - STR_RETURN(BBA_NAFR_MAR5) - STR_RETURN(BBA_NAFR_MAR6) - STR_RETURN(BBA_NAFR_MAR7) - STR_RETURN(BBA_NWAYC) - STR_RETURN(BBA_NWAYS) - STR_RETURN(BBA_GCA) - STR_RETURN(BBA_MISC) - STR_RETURN(BBA_TXFIFOCNT) - STR_RETURN(BBA_WRTXFIFOD) - STR_RETURN(BBA_MISC2) - STR_RETURN(BBA_SI_ACTRL) - STR_RETURN(BBA_SI_STATUS) - STR_RETURN(BBA_SI_ACTRL2) - default: - if (transfer.address >= 0x100 && - transfer.address <= 0xfff) - return "packet buffer"; - else - return "unknown"; - } - } + if (transfer.region == transfer.EXI) + { + switch (transfer.address) + { + STR_RETURN(EXI_ID) + STR_RETURN(REVISION_ID) + STR_RETURN(INTERRUPT) + STR_RETURN(INTERRUPT_MASK) + STR_RETURN(DEVICE_ID) + STR_RETURN(ACSTART) + STR_RETURN(HASH_READ) + STR_RETURN(HASH_WRITE) + STR_RETURN(HASH_STATUS) + STR_RETURN(RESET) + default: + return "unknown"; + } + } + else + { + switch (transfer.address) + { + STR_RETURN(BBA_NCRA) + STR_RETURN(BBA_NCRB) + STR_RETURN(BBA_LTPS) + STR_RETURN(BBA_LRPS) + STR_RETURN(BBA_IMR) + STR_RETURN(BBA_IR) + STR_RETURN(BBA_BP) + STR_RETURN(BBA_TLBP) + STR_RETURN(BBA_TWP) + STR_RETURN(BBA_IOB) + STR_RETURN(BBA_TRP) + STR_RETURN(BBA_RWP) + STR_RETURN(BBA_RRP) + STR_RETURN(BBA_RHBP) + STR_RETURN(BBA_RXINTT) + STR_RETURN(BBA_NAFR_PAR0) + STR_RETURN(BBA_NAFR_PAR1) + STR_RETURN(BBA_NAFR_PAR2) + STR_RETURN(BBA_NAFR_PAR3) + STR_RETURN(BBA_NAFR_PAR4) + STR_RETURN(BBA_NAFR_PAR5) + STR_RETURN(BBA_NAFR_MAR0) + STR_RETURN(BBA_NAFR_MAR1) + STR_RETURN(BBA_NAFR_MAR2) + STR_RETURN(BBA_NAFR_MAR3) + STR_RETURN(BBA_NAFR_MAR4) + STR_RETURN(BBA_NAFR_MAR5) + STR_RETURN(BBA_NAFR_MAR6) + STR_RETURN(BBA_NAFR_MAR7) + STR_RETURN(BBA_NWAYC) + STR_RETURN(BBA_NWAYS) + STR_RETURN(BBA_GCA) + STR_RETURN(BBA_MISC) + STR_RETURN(BBA_TXFIFOCNT) + STR_RETURN(BBA_WRTXFIFOD) + STR_RETURN(BBA_MISC2) + STR_RETURN(BBA_SI_ACTRL) + STR_RETURN(BBA_SI_STATUS) + STR_RETURN(BBA_SI_ACTRL2) + default: + if (transfer.address >= 0x100 && transfer.address <= 0xfff) + return "packet buffer"; + else + return "unknown"; + } + } #undef STR_RETURN } void CEXIETHERNET::MXHardReset() { - memset(mBbaMem.get(), 0, BBA_MEM_SIZE); + memset(mBbaMem.get(), 0, BBA_MEM_SIZE); - mBbaMem[BBA_NCRB] = NCRB_PR; - mBbaMem[BBA_NWAYC] = NWAYC_LTE | NWAYC_ANE; - mBbaMem[BBA_MISC] = MISC1_TPF | MISC1_TPH | MISC1_TXF | MISC1_TXH; + mBbaMem[BBA_NCRB] = NCRB_PR; + mBbaMem[BBA_NWAYC] = NWAYC_LTE | NWAYC_ANE; + mBbaMem[BBA_MISC] = MISC1_TPF | MISC1_TPH | MISC1_TXF | MISC1_TXH; } void CEXIETHERNET::MXCommandHandler(u32 data, u32 size) { - switch (transfer.address) - { - case BBA_NCRA: - if (data & NCRA_RESET) - { - DEBUG_LOG(SP1, "Software reset"); - //MXSoftReset(); - Activate(); - } + switch (transfer.address) + { + case BBA_NCRA: + if (data & NCRA_RESET) + { + DEBUG_LOG(SP1, "Software reset"); + // MXSoftReset(); + Activate(); + } - if ((mBbaMem[BBA_NCRA] & NCRA_SR) ^ (data & NCRA_SR)) - { - DEBUG_LOG(SP1, "%s rx", (data & NCRA_SR) ? "start" : "stop"); + if ((mBbaMem[BBA_NCRA] & NCRA_SR) ^ (data & NCRA_SR)) + { + DEBUG_LOG(SP1, "%s rx", (data & NCRA_SR) ? "start" : "stop"); - if (data & NCRA_SR) - RecvStart(); - else - RecvStop(); - } + if (data & NCRA_SR) + RecvStart(); + else + RecvStop(); + } - // Only start transfer if there isn't one currently running - if (!(mBbaMem[BBA_NCRA] & (NCRA_ST0 | NCRA_ST1))) - { - // Technically transfer DMA status is kept in TXDMA - not implemented + // Only start transfer if there isn't one currently running + if (!(mBbaMem[BBA_NCRA] & (NCRA_ST0 | NCRA_ST1))) + { + // Technically transfer DMA status is kept in TXDMA - not implemented - if (data & NCRA_ST0) - { - WARN_LOG(SP1, "start tx - local DMA"); - SendFromPacketBuffer(); - } - else if (data & NCRA_ST1) - { - DEBUG_LOG(SP1, "start tx - direct FIFO"); - SendFromDirectFIFO(); - // Kind of a hack: send completes instantly, so we don't - // actually write the "send in status" bit to the register - data &= ~NCRA_ST1; - } - } - goto write_to_register; + if (data & NCRA_ST0) + { + WARN_LOG(SP1, "start tx - local DMA"); + SendFromPacketBuffer(); + } + else if (data & NCRA_ST1) + { + DEBUG_LOG(SP1, "start tx - direct FIFO"); + SendFromDirectFIFO(); + // Kind of a hack: send completes instantly, so we don't + // actually write the "send in status" bit to the register + data &= ~NCRA_ST1; + } + } + goto write_to_register; - case BBA_WRTXFIFOD: - if (size == 2) - data = Common::swap16(data & 0xffff); - else if (size == 4) - data = Common::swap32(data); - DirectFIFOWrite((u8 *)&data, size); - // Do not increment address - return; + case BBA_WRTXFIFOD: + if (size == 2) + data = Common::swap16(data & 0xffff); + else if (size == 4) + data = Common::swap32(data); + DirectFIFOWrite((u8*)&data, size); + // Do not increment address + return; - case BBA_IR: - data &= (data & 0xff) ^ 0xff; - goto write_to_register; + case BBA_IR: + data &= (data & 0xff) ^ 0xff; + goto write_to_register; - case BBA_TXFIFOCNT: - case BBA_TXFIFOCNT+1: - // Ignore all writes to BBA_TXFIFOCNT - transfer.address += size; - return; + case BBA_TXFIFOCNT: + case BBA_TXFIFOCNT + 1: + // Ignore all writes to BBA_TXFIFOCNT + transfer.address += size; + return; -write_to_register: - default: - for (int i = size - 1; i >= 0; i--) - { - mBbaMem[transfer.address++] = (data >> (i * 8)) & 0xff; - } - return; - } + write_to_register: + default: + for (int i = size - 1; i >= 0; i--) + { + mBbaMem[transfer.address++] = (data >> (i * 8)) & 0xff; + } + return; + } } -void CEXIETHERNET::DirectFIFOWrite(u8 *data, u32 size) +void CEXIETHERNET::DirectFIFOWrite(u8* data, u32 size) { - // In direct mode, the hardware handles creating the state required by the - // GMAC instead of finagling with packet descriptors and such + // In direct mode, the hardware handles creating the state required by the + // GMAC instead of finagling with packet descriptors and such - u16 *tx_fifo_count = (u16 *)&mBbaMem[BBA_TXFIFOCNT]; + u16* tx_fifo_count = (u16*)&mBbaMem[BBA_TXFIFOCNT]; - memcpy(tx_fifo.get() + *tx_fifo_count, data, size); + memcpy(tx_fifo.get() + *tx_fifo_count, data, size); - *tx_fifo_count += size; - // TODO: not sure this mask is correct. - // However, BBA_TXFIFOCNT should never get even close to this amount, - // so it shouldn't matter - *tx_fifo_count &= (1 << 12) - 1; + *tx_fifo_count += size; + // TODO: not sure this mask is correct. + // However, BBA_TXFIFOCNT should never get even close to this amount, + // so it shouldn't matter + *tx_fifo_count &= (1 << 12) - 1; } void CEXIETHERNET::SendFromDirectFIFO() { - SendFrame(tx_fifo.get(), *(u16 *)&mBbaMem[BBA_TXFIFOCNT]); + SendFrame(tx_fifo.get(), *(u16*)&mBbaMem[BBA_TXFIFOCNT]); } void CEXIETHERNET::SendFromPacketBuffer() { - ERROR_LOG(SP1, "tx packet buffer not implemented."); + ERROR_LOG(SP1, "tx packet buffer not implemented."); } void CEXIETHERNET::SendComplete() { - mBbaMem[BBA_NCRA] &= ~(NCRA_ST0 | NCRA_ST1); - *(u16 *)&mBbaMem[BBA_TXFIFOCNT] = 0; + mBbaMem[BBA_NCRA] &= ~(NCRA_ST0 | NCRA_ST1); + *(u16*)&mBbaMem[BBA_TXFIFOCNT] = 0; - if (mBbaMem[BBA_IMR] & INT_T) - { - mBbaMem[BBA_IR] |= INT_T; + if (mBbaMem[BBA_IMR] & INT_T) + { + mBbaMem[BBA_IR] |= INT_T; - exi_status.interrupt |= exi_status.TRANSFER; - ExpansionInterface::ScheduleUpdateInterrupts(0); - } + exi_status.interrupt |= exi_status.TRANSFER; + ExpansionInterface::ScheduleUpdateInterrupts(0); + } - mBbaMem[BBA_LTPS] = 0; + mBbaMem[BBA_LTPS] = 0; } -inline u8 CEXIETHERNET::HashIndex(u8 *dest_eth_addr) +inline u8 CEXIETHERNET::HashIndex(u8* dest_eth_addr) { - // Calculate CRC - u32 crc = 0xffffffff; + // Calculate CRC + u32 crc = 0xffffffff; - for (size_t byte_num = 0; byte_num < 6; ++byte_num) - { - u8 cur_byte = dest_eth_addr[byte_num]; - for (size_t bit = 0; bit < 8; ++bit) - { - u8 carry = ((crc >> 31) & 1) ^ (cur_byte & 1); - crc <<= 1; - cur_byte >>= 1; - if (carry) - crc = (crc ^ 0x4c11db6) | carry; - } - } + for (size_t byte_num = 0; byte_num < 6; ++byte_num) + { + u8 cur_byte = dest_eth_addr[byte_num]; + for (size_t bit = 0; bit < 8; ++bit) + { + u8 carry = ((crc >> 31) & 1) ^ (cur_byte & 1); + crc <<= 1; + cur_byte >>= 1; + if (carry) + crc = (crc ^ 0x4c11db6) | carry; + } + } - // return bits used as index - return crc >> 26; + // return bits used as index + return crc >> 26; } inline bool CEXIETHERNET::RecvMACFilter() { - static u8 const broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + static u8 const broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - // Accept all destination addrs? - if (mBbaMem[BBA_NCRB] & NCRB_PR) - return true; + // Accept all destination addrs? + if (mBbaMem[BBA_NCRB] & NCRB_PR) + return true; - // Unicast? - if ((mRecvBuffer[0] & 0x01) == 0) - { - return memcmp(mRecvBuffer.get(), &mBbaMem[BBA_NAFR_PAR0], 6) == 0; - } - else if (memcmp(mRecvBuffer.get(), broadcast, 6) == 0) - { - // Accept broadcast? - return !!(mBbaMem[BBA_NCRB] & NCRB_AB); - } - else if (mBbaMem[BBA_NCRB] & NCRB_PM) - { - // Accept all multicast - return true; - } - else - { - // Lookup the dest eth address in the hashmap - u16 index = HashIndex(mRecvBuffer.get()); - return !!(mBbaMem[BBA_NAFR_MAR0 + index / 8] & (1 << (index % 8))); - } + // Unicast? + if ((mRecvBuffer[0] & 0x01) == 0) + { + return memcmp(mRecvBuffer.get(), &mBbaMem[BBA_NAFR_PAR0], 6) == 0; + } + else if (memcmp(mRecvBuffer.get(), broadcast, 6) == 0) + { + // Accept broadcast? + return !!(mBbaMem[BBA_NCRB] & NCRB_AB); + } + else if (mBbaMem[BBA_NCRB] & NCRB_PM) + { + // Accept all multicast + return true; + } + else + { + // Lookup the dest eth address in the hashmap + u16 index = HashIndex(mRecvBuffer.get()); + return !!(mBbaMem[BBA_NAFR_MAR0 + index / 8] & (1 << (index % 8))); + } } inline void CEXIETHERNET::inc_rwp() { - u16 *rwp = (u16 *)&mBbaMem[BBA_RWP]; + u16* rwp = (u16*)&mBbaMem[BBA_RWP]; - if (*rwp + 1 == page_ptr(BBA_RHBP)) - *rwp = page_ptr(BBA_BP); - else - (*rwp)++; + if (*rwp + 1 == page_ptr(BBA_RHBP)) + *rwp = page_ptr(BBA_BP); + else + (*rwp)++; } // This function is on the critical path for receiving data. // Be very careful about calling into the logger and other slow things bool CEXIETHERNET::RecvHandlePacket() { - u8 *write_ptr; - u8 *end_ptr; - u8 *read_ptr; - Descriptor *descriptor; - u32 status = 0; - u16 rwp_initial = page_ptr(BBA_RWP); + u8* write_ptr; + u8* end_ptr; + u8* read_ptr; + Descriptor* descriptor; + u32 status = 0; + u16 rwp_initial = page_ptr(BBA_RWP); - if (!RecvMACFilter()) - goto wait_for_next; + if (!RecvMACFilter()) + goto wait_for_next; #ifdef BBA_TRACK_PAGE_PTRS - WARN_LOG(SP1, "RecvHandlePacket %x\n%s", mRecvBufferLength, - ArrayToString(mRecvBuffer, mRecvBufferLength, 0x100).c_str()); + WARN_LOG(SP1, "RecvHandlePacket %x\n%s", mRecvBufferLength, + ArrayToString(mRecvBuffer, mRecvBufferLength, 0x100).c_str()); - WARN_LOG(SP1, "%x %x %x %x", - page_ptr(BBA_BP), - page_ptr(BBA_RRP), - page_ptr(BBA_RWP), - page_ptr(BBA_RHBP)); + WARN_LOG(SP1, "%x %x %x %x", page_ptr(BBA_BP), page_ptr(BBA_RRP), page_ptr(BBA_RWP), + page_ptr(BBA_RHBP)); #endif - write_ptr = ptr_from_page_ptr(BBA_RWP); - end_ptr = ptr_from_page_ptr(BBA_RHBP); - read_ptr = ptr_from_page_ptr(BBA_RRP); + write_ptr = ptr_from_page_ptr(BBA_RWP); + end_ptr = ptr_from_page_ptr(BBA_RHBP); + read_ptr = ptr_from_page_ptr(BBA_RRP); - descriptor = (Descriptor *)write_ptr; - write_ptr += 4; + descriptor = (Descriptor*)write_ptr; + write_ptr += 4; - for (u32 i = 0, off = 4; i < mRecvBufferLength; ++i, ++off) - { - *write_ptr++ = mRecvBuffer[i]; + for (u32 i = 0, off = 4; i < mRecvBufferLength; ++i, ++off) + { + *write_ptr++ = mRecvBuffer[i]; - if (off == 0xff) - { - off = 0; - inc_rwp(); - } + if (off == 0xff) + { + off = 0; + inc_rwp(); + } - if (write_ptr == end_ptr) - write_ptr = ptr_from_page_ptr(BBA_BP); + if (write_ptr == end_ptr) + write_ptr = ptr_from_page_ptr(BBA_BP); - if (write_ptr == read_ptr) - { - /* - halt copy - if (cur_packet_size >= PAGE_SIZE) - desc.status |= FO | BF - if (RBFIM) - raise RBFI - if (AUTORCVR) - discard bad packet - else - inc MPC instead of receiving packets - */ - status |= DESC_FO | DESC_BF; - mBbaMem[BBA_IR] |= mBbaMem[BBA_IMR] & INT_RBF; - break; - } - } + if (write_ptr == read_ptr) + { + /* + halt copy + if (cur_packet_size >= PAGE_SIZE) + desc.status |= FO | BF + if (RBFIM) + raise RBFI + if (AUTORCVR) + discard bad packet + else + inc MPC instead of receiving packets + */ + status |= DESC_FO | DESC_BF; + mBbaMem[BBA_IR] |= mBbaMem[BBA_IMR] & INT_RBF; + break; + } + } - // Align up to next page - if ((mRecvBufferLength + 4) % 256) - inc_rwp(); + // Align up to next page + if ((mRecvBufferLength + 4) % 256) + inc_rwp(); #ifdef BBA_TRACK_PAGE_PTRS - WARN_LOG(SP1, "%x %x %x %x", - page_ptr(BBA_BP), - page_ptr(BBA_RRP), - page_ptr(BBA_RWP), - page_ptr(BBA_RHBP)); + WARN_LOG(SP1, "%x %x %x %x", page_ptr(BBA_BP), page_ptr(BBA_RRP), page_ptr(BBA_RWP), + page_ptr(BBA_RHBP)); #endif - // Is the current frame multicast? - if (mRecvBuffer[0] & 0x01) - status |= DESC_MF; + // Is the current frame multicast? + if (mRecvBuffer[0] & 0x01) + status |= DESC_MF; - if (status & DESC_BF) - { - if (mBbaMem[BBA_MISC2] & MISC2_AUTORCVR) - { - *(u16 *)&mBbaMem[BBA_RWP] = rwp_initial; - } - else - { - ERROR_LOG(SP1, "RBF while AUTORCVR == 0!"); - } - } + if (status & DESC_BF) + { + if (mBbaMem[BBA_MISC2] & MISC2_AUTORCVR) + { + *(u16*)&mBbaMem[BBA_RWP] = rwp_initial; + } + else + { + ERROR_LOG(SP1, "RBF while AUTORCVR == 0!"); + } + } - descriptor->set(*(u16 *)&mBbaMem[BBA_RWP], 4 + mRecvBufferLength, status); + descriptor->set(*(u16*)&mBbaMem[BBA_RWP], 4 + mRecvBufferLength, status); - mBbaMem[BBA_LRPS] = status; + mBbaMem[BBA_LRPS] = status; - // Raise interrupt - if (mBbaMem[BBA_IMR] & INT_R) - { - mBbaMem[BBA_IR] |= INT_R; + // Raise interrupt + if (mBbaMem[BBA_IMR] & INT_R) + { + mBbaMem[BBA_IR] |= INT_R; - exi_status.interrupt |= exi_status.TRANSFER; - ExpansionInterface::ScheduleUpdateInterrupts_Threadsafe(0); - } - else - { - // This occurs if software is still processing the last raised recv interrupt - WARN_LOG(SP1, "NOT raising recv interrupt"); - } + exi_status.interrupt |= exi_status.TRANSFER; + ExpansionInterface::ScheduleUpdateInterrupts_Threadsafe(0); + } + else + { + // This occurs if software is still processing the last raised recv interrupt + WARN_LOG(SP1, "NOT raising recv interrupt"); + } wait_for_next: - if (mBbaMem[BBA_NCRA] & NCRA_SR) - RecvStart(); + if (mBbaMem[BBA_NCRA] & NCRA_SR) + RecvStart(); - return true; + return true; } diff --git a/Source/Core/Core/HW/EXI_DeviceEthernet.h b/Source/Core/Core/HW/EXI_DeviceEthernet.h index d5ea42ffaa..28b1aff389 100644 --- a/Source/Core/Core/HW/EXI_DeviceEthernet.h +++ b/Source/Core/Core/HW/EXI_DeviceEthernet.h @@ -20,176 +20,176 @@ class PointerWrap; // Network Control Register A enum NCRA { - NCRA_RESET = 0x01, // RESET - NCRA_ST0 = 0x02, // Start transmit command/status - NCRA_ST1 = 0x04, // " - NCRA_SR = 0x08 // Start Receive + NCRA_RESET = 0x01, // RESET + NCRA_ST0 = 0x02, // Start transmit command/status + NCRA_ST1 = 0x04, // " + NCRA_SR = 0x08 // Start Receive }; // Network Control Register B enum NCRB { - NCRB_PR = 0x01, // Promiscuous Mode - NCRB_CA = 0x02, // Capture Effect Mode - NCRB_PM = 0x04, // Pass Multicast - NCRB_PB = 0x08, // Pass Bad Frame - NCRB_AB = 0x10, // Accept Broadcast - NCRB_HBD = 0x20, // reserved - NCRB_RXINTC = 0xC0 // Receive Interrupt Counter (mask) + NCRB_PR = 0x01, // Promiscuous Mode + NCRB_CA = 0x02, // Capture Effect Mode + NCRB_PM = 0x04, // Pass Multicast + NCRB_PB = 0x08, // Pass Bad Frame + NCRB_AB = 0x10, // Accept Broadcast + NCRB_HBD = 0x20, // reserved + NCRB_RXINTC = 0xC0 // Receive Interrupt Counter (mask) }; // Interrupt Mask Register // Interrupt Register enum Interrupts { - INT_FRAG = 0x01, // Fragment Counter - INT_R = 0x02, // Receive - INT_T = 0x04, // Transmit - INT_R_ERR = 0x08, // Receive Error - INT_T_ERR = 0x10, // Transmit Error - INT_FIFO_ERR = 0x20, // FIFO Error - INT_BUS_ERR = 0x40, // BUS Error - INT_RBF = 0x80 // RX Buffer Full + INT_FRAG = 0x01, // Fragment Counter + INT_R = 0x02, // Receive + INT_T = 0x04, // Transmit + INT_R_ERR = 0x08, // Receive Error + INT_T_ERR = 0x10, // Transmit Error + INT_FIFO_ERR = 0x20, // FIFO Error + INT_BUS_ERR = 0x40, // BUS Error + INT_RBF = 0x80 // RX Buffer Full }; // NWAY Configuration Register enum NWAYC { - NWAYC_FD = 0x01, // Full Duplex Mode - NWAYC_PS100_10 = 0x02, // Port Select 100/10 - NWAYC_ANE = 0x04, // Autonegotiate enable + NWAYC_FD = 0x01, // Full Duplex Mode + NWAYC_PS100_10 = 0x02, // Port Select 100/10 + NWAYC_ANE = 0x04, // Autonegotiate enable - // Autonegotiation status bits... + // Autonegotiation status bits... - NWAYC_NTTEST = 0x40, // Reserved - NWAYC_LTE = 0x80 // Link Test Enable + NWAYC_NTTEST = 0x40, // Reserved + NWAYC_LTE = 0x80 // Link Test Enable }; enum NWAYS { - NWAYS_LS10 = 0x01, - NWAYS_LS100 = 0x02, - NWAYS_LPNWAY = 0x04, - NWAYS_ANCLPT = 0x08, - NWAYS_100TXF = 0x10, - NWAYS_100TXH = 0x20, - NWAYS_10TXF = 0x40, - NWAYS_10TXH = 0x80 + NWAYS_LS10 = 0x01, + NWAYS_LS100 = 0x02, + NWAYS_LPNWAY = 0x04, + NWAYS_ANCLPT = 0x08, + NWAYS_100TXF = 0x10, + NWAYS_100TXH = 0x20, + NWAYS_10TXF = 0x40, + NWAYS_10TXH = 0x80 }; enum MISC1 { - MISC1_BURSTDMA = 0x01, - MISC1_DISLDMA = 0x02, - MISC1_TPF = 0x04, - MISC1_TPH = 0x08, - MISC1_TXF = 0x10, - MISC1_TXH = 0x20, - MISC1_TXFIFORST = 0x40, - MISC1_RXFIFORST = 0x80 + MISC1_BURSTDMA = 0x01, + MISC1_DISLDMA = 0x02, + MISC1_TPF = 0x04, + MISC1_TPH = 0x08, + MISC1_TXF = 0x10, + MISC1_TXH = 0x20, + MISC1_TXFIFORST = 0x40, + MISC1_RXFIFORST = 0x80 }; enum MISC2 { - MISC2_HBRLEN0 = 0x01, - MISC2_HBRLEN1 = 0x02, - MISC2_RUNTSIZE = 0x04, - MISC2_DREQBCTRL = 0x08, - MISC2_RINTSEL = 0x10, - MISC2_ITPSEL = 0x20, - MISC2_A11A8EN = 0x40, - MISC2_AUTORCVR = 0x80 + MISC2_HBRLEN0 = 0x01, + MISC2_HBRLEN1 = 0x02, + MISC2_RUNTSIZE = 0x04, + MISC2_DREQBCTRL = 0x08, + MISC2_RINTSEL = 0x10, + MISC2_ITPSEL = 0x20, + MISC2_A11A8EN = 0x40, + MISC2_AUTORCVR = 0x80 }; enum { - BBA_NCRA = 0x00, - BBA_NCRB = 0x01, + BBA_NCRA = 0x00, + BBA_NCRB = 0x01, - BBA_LTPS = 0x04, - BBA_LRPS = 0x05, + BBA_LTPS = 0x04, + BBA_LRPS = 0x05, - BBA_IMR = 0x08, - BBA_IR = 0x09, + BBA_IMR = 0x08, + BBA_IR = 0x09, - BBA_BP = 0x0a, - BBA_TLBP = 0x0c, - BBA_TWP = 0x0e, - BBA_IOB = 0x10, - BBA_TRP = 0x12, - BBA_RWP = 0x16, - BBA_RRP = 0x18, - BBA_RHBP = 0x1a, + BBA_BP = 0x0a, + BBA_TLBP = 0x0c, + BBA_TWP = 0x0e, + BBA_IOB = 0x10, + BBA_TRP = 0x12, + BBA_RWP = 0x16, + BBA_RRP = 0x18, + BBA_RHBP = 0x1a, - BBA_RXINTT = 0x14, + BBA_RXINTT = 0x14, - BBA_NAFR_PAR0 = 0x20, - BBA_NAFR_PAR1 = 0x21, - BBA_NAFR_PAR2 = 0x22, - BBA_NAFR_PAR3 = 0x23, - BBA_NAFR_PAR4 = 0x24, - BBA_NAFR_PAR5 = 0x25, - BBA_NAFR_MAR0 = 0x26, - BBA_NAFR_MAR1 = 0x27, - BBA_NAFR_MAR2 = 0x28, - BBA_NAFR_MAR3 = 0x29, - BBA_NAFR_MAR4 = 0x2a, - BBA_NAFR_MAR5 = 0x2b, - BBA_NAFR_MAR6 = 0x2c, - BBA_NAFR_MAR7 = 0x2d, + BBA_NAFR_PAR0 = 0x20, + BBA_NAFR_PAR1 = 0x21, + BBA_NAFR_PAR2 = 0x22, + BBA_NAFR_PAR3 = 0x23, + BBA_NAFR_PAR4 = 0x24, + BBA_NAFR_PAR5 = 0x25, + BBA_NAFR_MAR0 = 0x26, + BBA_NAFR_MAR1 = 0x27, + BBA_NAFR_MAR2 = 0x28, + BBA_NAFR_MAR3 = 0x29, + BBA_NAFR_MAR4 = 0x2a, + BBA_NAFR_MAR5 = 0x2b, + BBA_NAFR_MAR6 = 0x2c, + BBA_NAFR_MAR7 = 0x2d, - BBA_NWAYC = 0x30, - BBA_NWAYS = 0x31, + BBA_NWAYC = 0x30, + BBA_NWAYS = 0x31, - BBA_GCA = 0x32, + BBA_GCA = 0x32, - BBA_MISC = 0x3d, + BBA_MISC = 0x3d, - BBA_TXFIFOCNT = 0x3e, - BBA_WRTXFIFOD = 0x48, + BBA_TXFIFOCNT = 0x3e, + BBA_WRTXFIFOD = 0x48, - BBA_MISC2 = 0x50, + BBA_MISC2 = 0x50, - BBA_SI_ACTRL = 0x5c, - BBA_SI_STATUS = 0x5d, - BBA_SI_ACTRL2 = 0x60 + BBA_SI_ACTRL = 0x5c, + BBA_SI_STATUS = 0x5d, + BBA_SI_ACTRL2 = 0x60 }; enum { - BBA_NUM_PAGES = 0x10, - BBA_PAGE_SIZE = 0x100, - BBA_MEM_SIZE = BBA_NUM_PAGES * BBA_PAGE_SIZE, - BBA_TXFIFO_SIZE = 1518 + BBA_NUM_PAGES = 0x10, + BBA_PAGE_SIZE = 0x100, + BBA_MEM_SIZE = BBA_NUM_PAGES * BBA_PAGE_SIZE, + BBA_TXFIFO_SIZE = 1518 }; enum { - EXI_DEVTYPE_ETHER = 0x04020200 + EXI_DEVTYPE_ETHER = 0x04020200 }; enum SendStatus { - DESC_CC0 = 0x01, - DESC_CC1 = 0x02, - DESC_CC2 = 0x04, - DESC_CC3 = 0x08, - DESC_CRSLOST = 0x10, - DESC_UF = 0x20, - DESC_OWC = 0x40, - DESC_OWN = 0x80 + DESC_CC0 = 0x01, + DESC_CC1 = 0x02, + DESC_CC2 = 0x04, + DESC_CC3 = 0x08, + DESC_CRSLOST = 0x10, + DESC_UF = 0x20, + DESC_OWC = 0x40, + DESC_OWN = 0x80 }; enum RecvStatus { - DESC_BF = 0x01, - DESC_CRC = 0x02, - DESC_FAE = 0x04, - DESC_FO = 0x08, - DESC_RW = 0x10, - DESC_MF = 0x20, - DESC_RF = 0x40, - DESC_RERR = 0x80 + DESC_BF = 0x01, + DESC_CRC = 0x02, + DESC_FAE = 0x04, + DESC_FO = 0x08, + DESC_RW = 0x10, + DESC_MF = 0x20, + DESC_RF = 0x40, + DESC_RERR = 0x80 }; #define BBA_RECV_SIZE 0x800 @@ -197,148 +197,143 @@ enum RecvStatus class CEXIETHERNET : public IEXIDevice { public: - CEXIETHERNET(); - virtual ~CEXIETHERNET(); - void SetCS(int cs) override; - bool IsPresent() const override; - bool IsInterruptSet() override; - void ImmWrite(u32 data, u32 size) override; - u32 ImmRead(u32 size) override; - void DMAWrite(u32 addr, u32 size) override; - void DMARead(u32 addr, u32 size) override; - void DoState(PointerWrap &p) override; + CEXIETHERNET(); + virtual ~CEXIETHERNET(); + void SetCS(int cs) override; + bool IsPresent() const override; + bool IsInterruptSet() override; + void ImmWrite(u32 data, u32 size) override; + u32 ImmRead(u32 size) override; + void DMAWrite(u32 addr, u32 size) override; + void DMARead(u32 addr, u32 size) override; + void DoState(PointerWrap& p) override; -//private: - struct - { - enum - { - READ, - WRITE - } direction; + // private: + struct + { + enum + { + READ, + WRITE + } direction; - enum - { - EXI, - MX - } region; + enum + { + EXI, + MX + } region; - u16 address; - bool valid; - } transfer; + u16 address; + bool valid; + } transfer; - enum - { - EXI_ID, - REVISION_ID, - INTERRUPT_MASK, - INTERRUPT, - DEVICE_ID, - ACSTART, - HASH_READ = 8, - HASH_WRITE, - HASH_STATUS = 0xb, - RESET = 0xf - }; + enum + { + EXI_ID, + REVISION_ID, + INTERRUPT_MASK, + INTERRUPT, + DEVICE_ID, + ACSTART, + HASH_READ = 8, + HASH_WRITE, + HASH_STATUS = 0xb, + RESET = 0xf + }; - // exi regs - struct EXIStatus - { - enum - { - TRANSFER = 0x80 - }; + // exi regs + struct EXIStatus + { + enum + { + TRANSFER = 0x80 + }; - u8 revision_id; - u8 interrupt_mask; - u8 interrupt; - u16 device_id; - u8 acstart; - u32 hash_challenge; - u32 hash_response; - u8 hash_status; + u8 revision_id; + u8 interrupt_mask; + u8 interrupt; + u16 device_id; + u8 acstart; + u32 hash_challenge; + u32 hash_response; + u8 hash_status; - EXIStatus() - { - device_id = 0xd107; - revision_id = 0;//0xf0; - acstart = 0x4e; + EXIStatus() + { + device_id = 0xd107; + revision_id = 0; // 0xf0; + acstart = 0x4e; - interrupt_mask = 0; - interrupt = 0; - hash_challenge = 0; - hash_response = 0; - hash_status = 0; - } + interrupt_mask = 0; + interrupt = 0; + hash_challenge = 0; + hash_response = 0; + hash_status = 0; + } - } exi_status; + } exi_status; - struct Descriptor - { - u32 word; + struct Descriptor + { + u32 word; - inline void set(u32 const next_page, u32 const packet_length, u32 const status) - { - word = 0; - word |= (status & 0xff) << 24; - word |= (packet_length & 0xfff) << 12; - word |= next_page & 0xfff; - } - }; + inline void set(u32 const next_page, u32 const packet_length, u32 const status) + { + word = 0; + word |= (status & 0xff) << 24; + word |= (packet_length & 0xfff) << 12; + word |= next_page & 0xfff; + } + }; - inline u16 page_ptr(int const index) const - { - return ((u16)mBbaMem[index + 1] << 8) | mBbaMem[index]; - } + inline u16 page_ptr(int const index) const + { + return ((u16)mBbaMem[index + 1] << 8) | mBbaMem[index]; + } - inline u8 *ptr_from_page_ptr(int const index) const - { - return &mBbaMem[page_ptr(index) << 8]; - } + inline u8* ptr_from_page_ptr(int const index) const { return &mBbaMem[page_ptr(index) << 8]; } + bool IsMXCommand(u32 const data); + bool IsWriteCommand(u32 const data); + const char* GetRegisterName() const; + void MXHardReset(); + void MXCommandHandler(u32 data, u32 size); + void DirectFIFOWrite(u8* data, u32 size); + void SendFromDirectFIFO(); + void SendFromPacketBuffer(); + void SendComplete(); + u8 HashIndex(u8* dest_eth_addr); + bool RecvMACFilter(); + void inc_rwp(); + bool RecvHandlePacket(); - bool IsMXCommand(u32 const data); - bool IsWriteCommand(u32 const data); - const char* GetRegisterName() const; - void MXHardReset(); - void MXCommandHandler(u32 data, u32 size); - void DirectFIFOWrite(u8 *data, u32 size); - void SendFromDirectFIFO(); - void SendFromPacketBuffer(); - void SendComplete(); - u8 HashIndex(u8 *dest_eth_addr); - bool RecvMACFilter(); - void inc_rwp(); - bool RecvHandlePacket(); + std::unique_ptr mBbaMem; + std::unique_ptr tx_fifo; - std::unique_ptr mBbaMem; - std::unique_ptr tx_fifo; + // TAP interface + bool Activate(); + void Deactivate(); + bool IsActivated(); + bool SendFrame(u8* frame, u32 size); + bool RecvInit(); + void RecvStart(); + void RecvStop(); - // TAP interface - bool Activate(); - void Deactivate(); - bool IsActivated(); - bool SendFrame(u8 *frame, u32 size); - bool RecvInit(); - void RecvStart(); - void RecvStop(); - - std::unique_ptr mRecvBuffer; - u32 mRecvBufferLength; + std::unique_ptr mRecvBuffer; + u32 mRecvBufferLength; #if defined(_WIN32) - HANDLE mHAdapter; - OVERLAPPED mReadOverlapped; - OVERLAPPED mWriteOverlapped; - std::vector mWriteBuffer; - bool mWritePending; + HANDLE mHAdapter; + OVERLAPPED mReadOverlapped; + OVERLAPPED mWriteOverlapped; + std::vector mWriteBuffer; + bool mWritePending; #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) - int fd; + int fd; #endif #if defined(WIN32) || defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) - std::thread readThread; - Common::Flag readEnabled; - Common::Flag readThreadShutdown; + std::thread readThread; + Common::Flag readEnabled; + Common::Flag readThreadShutdown; #endif - }; diff --git a/Source/Core/Core/HW/EXI_DeviceGecko.cpp b/Source/Core/Core/HW/EXI_DeviceGecko.cpp index c72f4d5b25..4bf93d5439 100644 --- a/Source/Core/Core/HW/EXI_DeviceGecko.cpp +++ b/Source/Core/Core/HW/EXI_DeviceGecko.cpp @@ -12,219 +12,213 @@ #include "Common/ChunkFile.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "Common/Thread.h" -#include "Common/Logging/Log.h" #include "Core/Core.h" #include "Core/HW/EXI_DeviceGecko.h" -u16 GeckoSockServer::server_port; -int GeckoSockServer::client_count; -std::thread GeckoSockServer::connectionThread; -std::atomic GeckoSockServer::server_running; -std::mutex GeckoSockServer::connection_lock; +u16 GeckoSockServer::server_port; +int GeckoSockServer::client_count; +std::thread GeckoSockServer::connectionThread; +std::atomic GeckoSockServer::server_running; +std::mutex GeckoSockServer::connection_lock; std::queue> GeckoSockServer::waiting_socks; -GeckoSockServer::GeckoSockServer() - : client_running(false) +GeckoSockServer::GeckoSockServer() : client_running(false) { - if (!connectionThread.joinable()) - connectionThread = std::thread(GeckoConnectionWaiter); + if (!connectionThread.joinable()) + connectionThread = std::thread(GeckoConnectionWaiter); } GeckoSockServer::~GeckoSockServer() { - if (clientThread.joinable()) - { - --client_count; + if (clientThread.joinable()) + { + --client_count; - client_running.store(false); - clientThread.join(); - } + client_running.store(false); + clientThread.join(); + } - if (client_count <= 0) - { - server_running.store(false); - connectionThread.join(); - } + if (client_count <= 0) + { + server_running.store(false); + connectionThread.join(); + } } void GeckoSockServer::GeckoConnectionWaiter() { - Common::SetCurrentThreadName("Gecko Connection Waiter"); + Common::SetCurrentThreadName("Gecko Connection Waiter"); - sf::TcpListener server; - server_port = 0xd6ec; // "dolphin gecko" - for (int bind_tries = 0; bind_tries <= 10 && !server_running.load(); bind_tries++) - { - server_running.store(server.listen(server_port) == sf::Socket::Done); - if (!server_running.load()) - server_port++; - } + sf::TcpListener server; + server_port = 0xd6ec; // "dolphin gecko" + for (int bind_tries = 0; bind_tries <= 10 && !server_running.load(); bind_tries++) + { + server_running.store(server.listen(server_port) == sf::Socket::Done); + if (!server_running.load()) + server_port++; + } - if (!server_running.load()) - return; + if (!server_running.load()) + return; - Core::DisplayMessage( - StringFromFormat("USBGecko: Listening on TCP port %u", server_port), - 5000); + Core::DisplayMessage(StringFromFormat("USBGecko: Listening on TCP port %u", server_port), 5000); - server.setBlocking(false); + server.setBlocking(false); - auto new_client = std::make_unique(); - while (server_running.load()) - { - if (server.accept(*new_client) == sf::Socket::Done) - { - std::lock_guard lk(connection_lock); - waiting_socks.push(std::move(new_client)); + auto new_client = std::make_unique(); + while (server_running.load()) + { + if (server.accept(*new_client) == sf::Socket::Done) + { + std::lock_guard lk(connection_lock); + waiting_socks.push(std::move(new_client)); - new_client = std::make_unique(); - } + new_client = std::make_unique(); + } - Common::SleepCurrentThread(1); - } + Common::SleepCurrentThread(1); + } } bool GeckoSockServer::GetAvailableSock() { - bool sock_filled = false; + bool sock_filled = false; - std::lock_guard lk(connection_lock); + std::lock_guard lk(connection_lock); - if (!waiting_socks.empty()) - { - client = std::move(waiting_socks.front()); - if (clientThread.joinable()) - { - client_running.store(false); - clientThread.join(); + if (!waiting_socks.empty()) + { + client = std::move(waiting_socks.front()); + if (clientThread.joinable()) + { + client_running.store(false); + clientThread.join(); - recv_fifo = std::deque(); - send_fifo = std::deque(); - } - clientThread = std::thread(&GeckoSockServer::ClientThread, this); - client_count++; - waiting_socks.pop(); - sock_filled = true; - } + recv_fifo = std::deque(); + send_fifo = std::deque(); + } + clientThread = std::thread(&GeckoSockServer::ClientThread, this); + client_count++; + waiting_socks.pop(); + sock_filled = true; + } - return sock_filled; + return sock_filled; } void GeckoSockServer::ClientThread() { - client_running.store(true); + client_running.store(true); - Common::SetCurrentThreadName("Gecko Client"); + Common::SetCurrentThreadName("Gecko Client"); - client->setBlocking(false); + client->setBlocking(false); - while (client_running.load()) - { - bool did_nothing = true; + while (client_running.load()) + { + bool did_nothing = true; - { - std::lock_guard lk(transfer_lock); + { + std::lock_guard lk(transfer_lock); - // what's an ideal buffer size? - char data[128]; - std::size_t got = 0; + // what's an ideal buffer size? + char data[128]; + std::size_t got = 0; - if (client->receive(&data[0], ArraySize(data), got) == sf::Socket::Disconnected) - client_running.store(false); + if (client->receive(&data[0], ArraySize(data), got) == sf::Socket::Disconnected) + client_running.store(false); - if (got != 0) - { - did_nothing = false; + if (got != 0) + { + did_nothing = false; - recv_fifo.insert(recv_fifo.end(), &data[0], &data[got]); - } + recv_fifo.insert(recv_fifo.end(), &data[0], &data[got]); + } - if (!send_fifo.empty()) - { - did_nothing = false; + if (!send_fifo.empty()) + { + did_nothing = false; - std::vector packet(send_fifo.begin(), send_fifo.end()); - send_fifo.clear(); + std::vector packet(send_fifo.begin(), send_fifo.end()); + send_fifo.clear(); - if (client->send(&packet[0], packet.size()) == sf::Socket::Disconnected) - client_running.store(false); - } - } // unlock transfer + if (client->send(&packet[0], packet.size()) == sf::Socket::Disconnected) + client_running.store(false); + } + } // unlock transfer - if (did_nothing) - Common::YieldCPU(); - } + if (did_nothing) + Common::YieldCPU(); + } - client->disconnect(); + client->disconnect(); } -void CEXIGecko::ImmReadWrite(u32 &_uData, u32 _uSize) +void CEXIGecko::ImmReadWrite(u32& _uData, u32 _uSize) { - // We don't really care about _uSize - (void)_uSize; + // We don't really care about _uSize + (void)_uSize; - if (!client || client->getLocalPort() == 0) - GetAvailableSock(); + if (!client || client->getLocalPort() == 0) + GetAvailableSock(); - switch (_uData >> 28) - { - case CMD_LED_OFF: - Core::DisplayMessage( - "USBGecko: No LEDs for you!", - 3000); - break; - case CMD_LED_ON: - Core::DisplayMessage( - "USBGecko: A piercing blue light is now shining in your general direction", - 3000); - break; + switch (_uData >> 28) + { + case CMD_LED_OFF: + Core::DisplayMessage("USBGecko: No LEDs for you!", 3000); + break; + case CMD_LED_ON: + Core::DisplayMessage("USBGecko: A piercing blue light is now shining in your general direction", + 3000); + break; - case CMD_INIT: - _uData = ident; - break; + case CMD_INIT: + _uData = ident; + break; - // PC -> Gecko - // |= 0x08000000 if successful - case CMD_RECV: - { - std::lock_guard lk(transfer_lock); - if (!recv_fifo.empty()) - { - _uData = 0x08000000 | (recv_fifo.front() << 16); - recv_fifo.pop_front(); - } - break; - } + // PC -> Gecko + // |= 0x08000000 if successful + case CMD_RECV: + { + std::lock_guard lk(transfer_lock); + if (!recv_fifo.empty()) + { + _uData = 0x08000000 | (recv_fifo.front() << 16); + recv_fifo.pop_front(); + } + break; + } - // Gecko -> PC - // |= 0x04000000 if successful - case CMD_SEND: - { - std::lock_guard lk(transfer_lock); - send_fifo.push_back(_uData >> 20); - _uData = 0x04000000; - break; - } + // Gecko -> PC + // |= 0x04000000 if successful + case CMD_SEND: + { + std::lock_guard lk(transfer_lock); + send_fifo.push_back(_uData >> 20); + _uData = 0x04000000; + break; + } - // Check if ok for Gecko -> PC, or FIFO full - // |= 0x04000000 if FIFO is not full - case CMD_CHK_TX: - _uData = 0x04000000; - break; + // Check if ok for Gecko -> PC, or FIFO full + // |= 0x04000000 if FIFO is not full + case CMD_CHK_TX: + _uData = 0x04000000; + break; - // Check if data in FIFO for PC -> Gecko, or FIFO empty - // |= 0x04000000 if data in recv FIFO - case CMD_CHK_RX: - { - std::lock_guard lk(transfer_lock); - _uData = recv_fifo.empty() ? 0 : 0x04000000; - break; - } + // Check if data in FIFO for PC -> Gecko, or FIFO empty + // |= 0x04000000 if data in recv FIFO + case CMD_CHK_RX: + { + std::lock_guard lk(transfer_lock); + _uData = recv_fifo.empty() ? 0 : 0x04000000; + break; + } - default: - ERROR_LOG(EXPANSIONINTERFACE, "Unknown USBGecko command %x", _uData); - break; - } + default: + ERROR_LOG(EXPANSIONINTERFACE, "Unknown USBGecko command %x", _uData); + break; + } } diff --git a/Source/Core/Core/HW/EXI_DeviceGecko.h b/Source/Core/Core/HW/EXI_DeviceGecko.h index 3b60406e82..b32ec69ce8 100644 --- a/Source/Core/Core/HW/EXI_DeviceGecko.h +++ b/Source/Core/Core/HW/EXI_DeviceGecko.h @@ -4,13 +4,13 @@ #pragma once +#include #include #include #include #include #include #include -#include #include "Common/CommonTypes.h" #include "Core/HW/EXI_Device.h" @@ -18,53 +18,51 @@ class GeckoSockServer { public: - GeckoSockServer(); - ~GeckoSockServer(); - bool GetAvailableSock(); + GeckoSockServer(); + ~GeckoSockServer(); + bool GetAvailableSock(); - // Client for this server object - std::unique_ptr client; - void ClientThread(); - std::thread clientThread; - std::mutex transfer_lock; + // Client for this server object + std::unique_ptr client; + void ClientThread(); + std::thread clientThread; + std::mutex transfer_lock; - std::deque send_fifo; - std::deque recv_fifo; + std::deque send_fifo; + std::deque recv_fifo; private: - static int client_count; - std::atomic client_running; + static int client_count; + std::atomic client_running; - // Only ever one server thread - static void GeckoConnectionWaiter(); + // Only ever one server thread + static void GeckoConnectionWaiter(); - static u16 server_port; - static std::atomic server_running; - static std::thread connectionThread; - static std::mutex connection_lock; - static std::queue> waiting_socks; + static u16 server_port; + static std::atomic server_running; + static std::thread connectionThread; + static std::mutex connection_lock; + static std::queue> waiting_socks; }; -class CEXIGecko - : public IEXIDevice - , private GeckoSockServer +class CEXIGecko : public IEXIDevice, private GeckoSockServer { public: - CEXIGecko() {} - bool IsPresent() const override { return true; } - void ImmReadWrite(u32 &_uData, u32 _uSize) override; + CEXIGecko() {} + bool IsPresent() const override { return true; } + void ImmReadWrite(u32& _uData, u32 _uSize) override; private: - enum - { - CMD_LED_OFF = 0x7, - CMD_LED_ON = 0x8, - CMD_INIT = 0x9, - CMD_RECV = 0xa, - CMD_SEND = 0xb, - CMD_CHK_TX = 0xc, - CMD_CHK_RX = 0xd, - }; + enum + { + CMD_LED_OFF = 0x7, + CMD_LED_ON = 0x8, + CMD_INIT = 0x9, + CMD_RECV = 0xa, + CMD_SEND = 0xb, + CMD_CHK_TX = 0xc, + CMD_CHK_RX = 0xd, + }; - static const u32 ident = 0x04700000; + static const u32 ident = 0x04700000; }; diff --git a/Source/Core/Core/HW/EXI_DeviceIPL.cpp b/Source/Core/Core/HW/EXI_DeviceIPL.cpp index acbc09f6a8..0938647c01 100644 --- a/Source/Core/Core/HW/EXI_DeviceIPL.cpp +++ b/Source/Core/Core/HW/EXI_DeviceIPL.cpp @@ -8,23 +8,24 @@ #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" +#include "Common/Logging/Log.h" #include "Common/MemoryUtil.h" #include "Common/Timer.h" -#include "Common/Logging/Log.h" #include "Core/ConfigManager.h" #include "Core/CoreTiming.h" -#include "Core/Movie.h" -#include "Core/NetPlayProto.h" #include "Core/HW/EXI_DeviceIPL.h" #include "Core/HW/Sram.h" #include "Core/HW/SystemTimers.h" +#include "Core/Movie.h" +#include "Core/NetPlayProto.h" -// We should provide an option to choose from the above, or figure out the checksum (the algo in yagcd seems wrong) +// We should provide an option to choose from the above, or figure out the checksum (the algo in +// yagcd seems wrong) // so that people can change default language. -static const char iplverPAL[0x100] = "(C) 1999-2001 Nintendo. All rights reserved." - "(C) 1999 ArtX Inc. All rights reserved." - "PAL Revision 1.0 "; +static const char iplverPAL[0x100] = "(C) 1999-2001 Nintendo. All rights reserved." + "(C) 1999 ArtX Inc. All rights reserved." + "PAL Revision 1.0 "; static const char iplverNTSC[0x100] = "(C) 1999-2001 Nintendo. All rights reserved." "(C) 1999 ArtX Inc. All rights reserved."; @@ -33,399 +34,397 @@ static const char iplverNTSC[0x100] = "(C) 1999-2001 Nintendo. All rights reser // Copyright 2008 Segher Boessenkool void CEXIIPL::Descrambler(u8* data, u32 size) { - u8 acc = 0; - u8 nacc = 0; + u8 acc = 0; + u8 nacc = 0; - u16 t = 0x2953; - u16 u = 0xd9c2; - u16 v = 0x3ff1; + u16 t = 0x2953; + u16 u = 0xd9c2; + u16 v = 0x3ff1; - u8 x = 1; + u8 x = 1; - for (u32 it = 0; it < size;) - { - int t0 = t & 1; - int t1 = (t >> 1) & 1; - int u0 = u & 1; - int u1 = (u >> 1) & 1; - int v0 = v & 1; + for (u32 it = 0; it < size;) + { + int t0 = t & 1; + int t1 = (t >> 1) & 1; + int u0 = u & 1; + int u1 = (u >> 1) & 1; + int v0 = v & 1; - x ^= t1 ^ v0; - x ^= (u0 | u1); - x ^= (t0 ^ u1 ^ v0) & (t0 ^ u0); + x ^= t1 ^ v0; + x ^= (u0 | u1); + x ^= (t0 ^ u1 ^ v0) & (t0 ^ u0); - if (t0 == u0) - { - v >>= 1; - if (v0) - v ^= 0xb3d0; - } + if (t0 == u0) + { + v >>= 1; + if (v0) + v ^= 0xb3d0; + } - if (t0 == 0) - { - u >>= 1; - if (u0) - u ^= 0xfb10; - } + if (t0 == 0) + { + u >>= 1; + if (u0) + u ^= 0xfb10; + } - t >>= 1; - if (t0) - t ^= 0xa740; + t >>= 1; + if (t0) + t ^= 0xa740; - nacc++; - acc = 2*acc + x; - if (nacc == 8) - { - data[it++] ^= acc; - nacc = 0; - } - } + nacc++; + acc = 2 * acc + x; + if (nacc == 8) + { + data[it++] ^= acc; + nacc = 0; + } + } } -CEXIIPL::CEXIIPL() : - m_uPosition(0), - m_uAddress(0), - m_uRWOffset(0), - m_FontsLoaded(false) +CEXIIPL::CEXIIPL() : m_uPosition(0), m_uAddress(0), m_uRWOffset(0), m_FontsLoaded(false) { - // Determine region - m_bNTSC = SConfig::GetInstance().bNTSC; + // Determine region + m_bNTSC = SConfig::GetInstance().bNTSC; - // Create the IPL - m_pIPL = (u8*)AllocateMemoryPages(ROM_SIZE); + // Create the IPL + m_pIPL = (u8*)AllocateMemoryPages(ROM_SIZE); - if (SConfig::GetInstance().bHLE_BS2) - { - // Copy header - memcpy(m_pIPL, m_bNTSC ? iplverNTSC : iplverPAL, m_bNTSC ? sizeof(iplverNTSC) : sizeof(iplverPAL)); + if (SConfig::GetInstance().bHLE_BS2) + { + // Copy header + memcpy(m_pIPL, m_bNTSC ? iplverNTSC : iplverPAL, + m_bNTSC ? sizeof(iplverNTSC) : sizeof(iplverPAL)); - // Load fonts - LoadFontFile((File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + FONT_SJIS), 0x1aff00); - LoadFontFile((File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + FONT_ANSI), 0x1fcf00); - } - else - { - // Load whole ROM dump - LoadFileToIPL(SConfig::GetInstance().m_strBootROM, 0); - // Descramble the encrypted section (contains BS1 and BS2) - Descrambler(m_pIPL + 0x100, 0x1afe00); - INFO_LOG(BOOT, "Loaded bootrom: %s", m_pIPL); // yay for null-terminated strings ;p - } + // Load fonts + LoadFontFile((File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + FONT_SJIS), 0x1aff00); + LoadFontFile((File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + FONT_ANSI), 0x1fcf00); + } + else + { + // Load whole ROM dump + LoadFileToIPL(SConfig::GetInstance().m_strBootROM, 0); + // Descramble the encrypted section (contains BS1 and BS2) + Descrambler(m_pIPL + 0x100, 0x1afe00); + INFO_LOG(BOOT, "Loaded bootrom: %s", m_pIPL); // yay for null-terminated strings ;p + } - // Clear RTC - memset(m_RTC, 0, sizeof(m_RTC)); + // Clear RTC + memset(m_RTC, 0, sizeof(m_RTC)); - // We Overwrite language selection here since it's possible on the GC to change the language as you please - g_SRAM.lang = SConfig::GetInstance().SelectedLanguage; - FixSRAMChecksums(); + // We Overwrite language selection here since it's possible on the GC to change the language as + // you please + g_SRAM.lang = SConfig::GetInstance().SelectedLanguage; + FixSRAMChecksums(); - WriteProtectMemory(m_pIPL, ROM_SIZE); - m_uAddress = 0; + WriteProtectMemory(m_pIPL, ROM_SIZE); + m_uAddress = 0; } CEXIIPL::~CEXIIPL() { - FreeMemoryPages(m_pIPL, ROM_SIZE); - m_pIPL = nullptr; + FreeMemoryPages(m_pIPL, ROM_SIZE); + m_pIPL = nullptr; - // SRAM - if (!g_SRAM_netplay_initialized) - { - File::IOFile file(SConfig::GetInstance().m_strSRAM, "wb"); - file.WriteArray(&g_SRAM, 1); - } - else - { - g_SRAM_netplay_initialized = false; - } + // SRAM + if (!g_SRAM_netplay_initialized) + { + File::IOFile file(SConfig::GetInstance().m_strSRAM, "wb"); + file.WriteArray(&g_SRAM, 1); + } + else + { + g_SRAM_netplay_initialized = false; + } } -void CEXIIPL::DoState(PointerWrap &p) +void CEXIIPL::DoState(PointerWrap& p) { - p.Do(m_RTC); - p.Do(m_uPosition); - p.Do(m_uAddress); - p.Do(m_uRWOffset); - p.Do(m_buffer); - p.Do(m_FontsLoaded); + p.Do(m_RTC); + p.Do(m_uPosition); + p.Do(m_uAddress); + p.Do(m_uRWOffset); + p.Do(m_buffer); + p.Do(m_FontsLoaded); } void CEXIIPL::LoadFileToIPL(const std::string& filename, u32 offset) { - File::IOFile stream(filename, "rb"); - if (!stream) - return; + File::IOFile stream(filename, "rb"); + if (!stream) + return; - u64 filesize = stream.GetSize(); + u64 filesize = stream.GetSize(); - stream.ReadBytes(m_pIPL + offset, filesize); + stream.ReadBytes(m_pIPL + offset, filesize); - m_FontsLoaded = true; + m_FontsLoaded = true; } std::string CEXIIPL::FindIPLDump(const std::string& path_prefix) { - std::string ipl_dump_path; + std::string ipl_dump_path; - if (File::Exists(path_prefix + DIR_SEP + USA_DIR + DIR_SEP + GC_IPL)) - ipl_dump_path = path_prefix + DIR_SEP + USA_DIR + DIR_SEP + GC_IPL; - else if (File::Exists(path_prefix + DIR_SEP + EUR_DIR + DIR_SEP + GC_IPL)) - ipl_dump_path = path_prefix + DIR_SEP + EUR_DIR + DIR_SEP + GC_IPL; - else if (File::Exists(path_prefix + DIR_SEP + JAP_DIR + DIR_SEP + GC_IPL)) - ipl_dump_path = path_prefix + DIR_SEP + JAP_DIR + DIR_SEP + GC_IPL; + if (File::Exists(path_prefix + DIR_SEP + USA_DIR + DIR_SEP + GC_IPL)) + ipl_dump_path = path_prefix + DIR_SEP + USA_DIR + DIR_SEP + GC_IPL; + else if (File::Exists(path_prefix + DIR_SEP + EUR_DIR + DIR_SEP + GC_IPL)) + ipl_dump_path = path_prefix + DIR_SEP + EUR_DIR + DIR_SEP + GC_IPL; + else if (File::Exists(path_prefix + DIR_SEP + JAP_DIR + DIR_SEP + GC_IPL)) + ipl_dump_path = path_prefix + DIR_SEP + JAP_DIR + DIR_SEP + GC_IPL; - return ipl_dump_path; + return ipl_dump_path; } void CEXIIPL::LoadFontFile(const std::string& filename, u32 offset) { - // Official IPL fonts are copyrighted. Dolphin ships with a set of free font alternatives but - // unfortunately the bundled fonts have different padding, causing issues with misplaced text - // in some titles. This function check if the user has IPL dumps available and load the fonts - // from those dumps instead of loading the bundled fonts + // Official IPL fonts are copyrighted. Dolphin ships with a set of free font alternatives but + // unfortunately the bundled fonts have different padding, causing issues with misplaced text + // in some titles. This function check if the user has IPL dumps available and load the fonts + // from those dumps instead of loading the bundled fonts - // Check for IPL dumps in User folder - std::string ipl_rom_path = FindIPLDump(File::GetUserPath(D_GCUSER_IDX)); + // Check for IPL dumps in User folder + std::string ipl_rom_path = FindIPLDump(File::GetUserPath(D_GCUSER_IDX)); - // If not found, check again in Sys folder - if (ipl_rom_path.empty()) - ipl_rom_path = FindIPLDump(File::GetSysDirectory() + GC_SYS_DIR); + // If not found, check again in Sys folder + if (ipl_rom_path.empty()) + ipl_rom_path = FindIPLDump(File::GetSysDirectory() + GC_SYS_DIR); - if (File::Exists(ipl_rom_path)) - { - // The user has an IPL dump, load the font from it - File::IOFile stream(ipl_rom_path, "rb"); - if (!stream) - return; + if (File::Exists(ipl_rom_path)) + { + // The user has an IPL dump, load the font from it + File::IOFile stream(ipl_rom_path, "rb"); + if (!stream) + return; - // Official Windows-1252 and SJIS fonts present on the IPL dumps are 0x2575 and 0x4a24d bytes - // long respectively, so, determine the size of the font being loaded based on the offset - u64 fontsize = (offset == 0x1aff00) ? 0x4a24d : 0x2575; + // Official Windows-1252 and SJIS fonts present on the IPL dumps are 0x2575 and 0x4a24d bytes + // long respectively, so, determine the size of the font being loaded based on the offset + u64 fontsize = (offset == 0x1aff00) ? 0x4a24d : 0x2575; - INFO_LOG(BOOT, "Found IPL dump, loading %s font from %s", ((offset == 0x1aff00) ? "SJIS" : "Windows-1252"), (ipl_rom_path).c_str()); + INFO_LOG(BOOT, "Found IPL dump, loading %s font from %s", + ((offset == 0x1aff00) ? "SJIS" : "Windows-1252"), (ipl_rom_path).c_str()); - stream.Seek(offset, 0); - stream.ReadBytes(m_pIPL + offset, fontsize); + stream.Seek(offset, 0); + stream.ReadBytes(m_pIPL + offset, fontsize); - m_FontsLoaded = true; - } - else - { - // No IPL dump available, load bundled font instead - LoadFileToIPL(filename, offset); - } + m_FontsLoaded = true; + } + else + { + // No IPL dump available, load bundled font instead + LoadFileToIPL(filename, offset); + } } void CEXIIPL::SetCS(int _iCS) { - if (_iCS) - { - // cs transition to high - m_uPosition = 0; - } + if (_iCS) + { + // cs transition to high + m_uPosition = 0; + } } void CEXIIPL::UpdateRTC() { - // Seconds between 1.1.2000 and 4.1.2008 16:00:38 - static constexpr u32 WII_BIAS = 0x0F1114A6; + // Seconds between 1.1.2000 and 4.1.2008 16:00:38 + static constexpr u32 WII_BIAS = 0x0F1114A6; - u32 rtc; + u32 rtc; - if (SConfig::GetInstance().bWii) - rtc = Common::swap32(GetGCTime() - WII_BIAS); - else - rtc = Common::swap32(GetGCTime()); + if (SConfig::GetInstance().bWii) + rtc = Common::swap32(GetGCTime() - WII_BIAS); + else + rtc = Common::swap32(GetGCTime()); - std::memcpy(m_RTC, &rtc, sizeof(u32)); + std::memcpy(m_RTC, &rtc, sizeof(u32)); } bool CEXIIPL::IsPresent() const { - return true; + return true; } void CEXIIPL::TransferByte(u8& _uByte) { - // The first 4 bytes must be the address - // If we haven't read it, do it now - if (m_uPosition <= 3) - { - m_uAddress <<= 8; - m_uAddress |= _uByte; - m_uRWOffset = 0; - _uByte = 0xFF; + // The first 4 bytes must be the address + // If we haven't read it, do it now + if (m_uPosition <= 3) + { + m_uAddress <<= 8; + m_uAddress |= _uByte; + m_uRWOffset = 0; + _uByte = 0xFF; - // Check if the command is complete - if (m_uPosition == 3) - { - // Get the time... - UpdateRTC(); + // Check if the command is complete + if (m_uPosition == 3) + { + // Get the time... + UpdateRTC(); - // Log the command - std::string device_name; + // Log the command + std::string device_name; - switch (CommandRegion()) - { - case REGION_RTC: - device_name = "RTC"; - break; - case REGION_SRAM: - device_name = "SRAM"; - break; - case REGION_UART: - device_name = "UART"; - break; - case REGION_EUART: - case REGION_EUART_UNK: - device_name = "EUART"; - break; - case REGION_UART_UNK: - device_name = "UART Other?"; - break; - case REGION_BARNACLE: - device_name = "UART Barnacle"; - break; - case REGION_WRTC0: - case REGION_WRTC1: - case REGION_WRTC2: - device_name = "Wii RTC flags - not implemented"; - break; - default: - if ((m_uAddress >> 6) < ROM_SIZE) - { - device_name = "ROM"; - } - else - { - device_name = "illegal address"; - _dbg_assert_msg_(EXPANSIONINTERFACE, 0, - "EXI IPL-DEV: %s %08x", device_name.c_str(), m_uAddress); - } - break; - } + switch (CommandRegion()) + { + case REGION_RTC: + device_name = "RTC"; + break; + case REGION_SRAM: + device_name = "SRAM"; + break; + case REGION_UART: + device_name = "UART"; + break; + case REGION_EUART: + case REGION_EUART_UNK: + device_name = "EUART"; + break; + case REGION_UART_UNK: + device_name = "UART Other?"; + break; + case REGION_BARNACLE: + device_name = "UART Barnacle"; + break; + case REGION_WRTC0: + case REGION_WRTC1: + case REGION_WRTC2: + device_name = "Wii RTC flags - not implemented"; + break; + default: + if ((m_uAddress >> 6) < ROM_SIZE) + { + device_name = "ROM"; + } + else + { + device_name = "illegal address"; + _dbg_assert_msg_(EXPANSIONINTERFACE, 0, "EXI IPL-DEV: %s %08x", device_name.c_str(), + m_uAddress); + } + break; + } - DEBUG_LOG(EXPANSIONINTERFACE, "%s %s %08x", device_name.c_str(), - IsWriteCommand() ? "write" : "read", m_uAddress); - } - } - else - { - // Actually read or write a byte - switch (CommandRegion()) - { - case REGION_RTC: - if (IsWriteCommand()) - m_RTC[(m_uAddress & 0x03) + m_uRWOffset] = _uByte; - else - _uByte = m_RTC[(m_uAddress & 0x03) + m_uRWOffset]; - break; + DEBUG_LOG(EXPANSIONINTERFACE, "%s %s %08x", device_name.c_str(), + IsWriteCommand() ? "write" : "read", m_uAddress); + } + } + else + { + // Actually read or write a byte + switch (CommandRegion()) + { + case REGION_RTC: + if (IsWriteCommand()) + m_RTC[(m_uAddress & 0x03) + m_uRWOffset] = _uByte; + else + _uByte = m_RTC[(m_uAddress & 0x03) + m_uRWOffset]; + break; - case REGION_SRAM: - if (IsWriteCommand()) - g_SRAM.p_SRAM[(m_uAddress & 0x3F) + m_uRWOffset] = _uByte; - else - _uByte = g_SRAM.p_SRAM[(m_uAddress & 0x3F) + m_uRWOffset]; - break; + case REGION_SRAM: + if (IsWriteCommand()) + g_SRAM.p_SRAM[(m_uAddress & 0x3F) + m_uRWOffset] = _uByte; + else + _uByte = g_SRAM.p_SRAM[(m_uAddress & 0x3F) + m_uRWOffset]; + break; - case REGION_UART: - case REGION_EUART: - if (IsWriteCommand()) - { - if (_uByte != '\0') - m_buffer += _uByte; + case REGION_UART: + case REGION_EUART: + if (IsWriteCommand()) + { + if (_uByte != '\0') + m_buffer += _uByte; - if (_uByte == '\r') - { - NOTICE_LOG(OSREPORT, "%s", m_buffer.c_str()); - m_buffer.clear(); - } - } - else - { - // "Queue Length"... return 0 cause we're instant - _uByte = 0; - } - break; + if (_uByte == '\r') + { + NOTICE_LOG(OSREPORT, "%s", m_buffer.c_str()); + m_buffer.clear(); + } + } + else + { + // "Queue Length"... return 0 cause we're instant + _uByte = 0; + } + break; - case REGION_EUART_UNK: - // Writes 0xf2 then 0xf3 on EUART init. Just need to return non-zero - // so we can leave the byte untouched. - break; + case REGION_EUART_UNK: + // Writes 0xf2 then 0xf3 on EUART init. Just need to return non-zero + // so we can leave the byte untouched. + break; - case REGION_UART_UNK: - DEBUG_LOG(OSREPORT, "UART? %x", _uByte); - _uByte = 0xff; - break; + case REGION_UART_UNK: + DEBUG_LOG(OSREPORT, "UART? %x", _uByte); + _uByte = 0xff; + break; - case REGION_BARNACLE: - DEBUG_LOG(OSREPORT, "UART Barnacle %x", _uByte); - break; + case REGION_BARNACLE: + DEBUG_LOG(OSREPORT, "UART Barnacle %x", _uByte); + break; - case REGION_WRTC0: - case REGION_WRTC1: - case REGION_WRTC2: - // Wii only RTC flags... afaik just the Wii Menu initialize it - default: - if ((m_uAddress >> 6) < ROM_SIZE) - { - if (!IsWriteCommand()) - { - u32 position = ((m_uAddress >> 6) & ROM_MASK) + m_uRWOffset; + case REGION_WRTC0: + case REGION_WRTC1: + case REGION_WRTC2: + // Wii only RTC flags... afaik just the Wii Menu initialize it + default: + if ((m_uAddress >> 6) < ROM_SIZE) + { + if (!IsWriteCommand()) + { + u32 position = ((m_uAddress >> 6) & ROM_MASK) + m_uRWOffset; - // Technically we should descramble here iff descrambling logic is enabled. - // At the moment, we pre-decrypt the whole thing and - // ignore the "enabled" bit - see CEXIIPL::CEXIIPL - _uByte = m_pIPL[position]; + // Technically we should descramble here iff descrambling logic is enabled. + // At the moment, we pre-decrypt the whole thing and + // ignore the "enabled" bit - see CEXIIPL::CEXIIPL + _uByte = m_pIPL[position]; - if ((position >= 0x001AFF00) && (position <= 0x001FF474) && !m_FontsLoaded) - { - PanicAlertT( - "Error: Trying to access %s fonts but they are not loaded. " - "Games may not show fonts correctly, or crash.", - (position >= 0x001FCF00) ? "ANSI" : "SJIS"); - m_FontsLoaded = true; // Don't be a nag :p - } - } - } - else - { - NOTICE_LOG(OSREPORT, "EXI IPL-DEV: %s %x at %08x", - IsWriteCommand() ? "write" : "read", _uByte, m_uAddress); - } - break; - } + if ((position >= 0x001AFF00) && (position <= 0x001FF474) && !m_FontsLoaded) + { + PanicAlertT("Error: Trying to access %s fonts but they are not loaded. " + "Games may not show fonts correctly, or crash.", + (position >= 0x001FCF00) ? "ANSI" : "SJIS"); + m_FontsLoaded = true; // Don't be a nag :p + } + } + } + else + { + NOTICE_LOG(OSREPORT, "EXI IPL-DEV: %s %x at %08x", IsWriteCommand() ? "write" : "read", + _uByte, m_uAddress); + } + break; + } - m_uRWOffset++; - } + m_uRWOffset++; + } - m_uPosition++; + m_uPosition++; } u32 CEXIIPL::GetGCTime() { - u64 ltime = 0; - static const u32 cJanuary2000 = 0x386D4380; // Seconds between 1.1.1970 and 1.1.2000 + u64 ltime = 0; + static const u32 cJanuary2000 = 0x386D4380; // Seconds between 1.1.1970 and 1.1.2000 - if (Movie::IsMovieActive()) - { - ltime = Movie::GetRecordingStartTime(); + if (Movie::IsMovieActive()) + { + ltime = Movie::GetRecordingStartTime(); - // let's keep time moving forward, regardless of what it starts at - ltime += CoreTiming::GetTicks() / SystemTimers::GetTicksPerSecond(); - } - else if (NetPlay::IsNetPlayRunning()) - { - ltime = NetPlay_GetGCTime(); + // let's keep time moving forward, regardless of what it starts at + ltime += CoreTiming::GetTicks() / SystemTimers::GetTicksPerSecond(); + } + else if (NetPlay::IsNetPlayRunning()) + { + ltime = NetPlay_GetGCTime(); - // let's keep time moving forward, regardless of what it starts at - ltime += CoreTiming::GetTicks() / SystemTimers::GetTicksPerSecond(); - } - else - { - ltime = Common::Timer::GetLocalTimeSinceJan1970(); - } + // let's keep time moving forward, regardless of what it starts at + ltime += CoreTiming::GetTicks() / SystemTimers::GetTicksPerSecond(); + } + else + { + ltime = Common::Timer::GetLocalTimeSinceJan1970(); + } - return ((u32)ltime - cJanuary2000); + return ((u32)ltime - cJanuary2000); #if 0 // (mb2): I think we can get rid of the IPL bias. diff --git a/Source/Core/Core/HW/EXI_DeviceIPL.h b/Source/Core/Core/HW/EXI_DeviceIPL.h index 06185be785..5fc20b8abc 100644 --- a/Source/Core/Core/HW/EXI_DeviceIPL.h +++ b/Source/Core/Core/HW/EXI_DeviceIPL.h @@ -13,64 +13,63 @@ class PointerWrap; class CEXIIPL : public IEXIDevice { public: - CEXIIPL(); - virtual ~CEXIIPL(); + CEXIIPL(); + virtual ~CEXIIPL(); - void SetCS(int _iCS) override; - bool IsPresent() const override; - void DoState(PointerWrap &p) override; + void SetCS(int _iCS) override; + bool IsPresent() const override; + void DoState(PointerWrap& p) override; - static u32 GetGCTime(); - static u64 NetPlay_GetGCTime(); + static u32 GetGCTime(); + static u64 NetPlay_GetGCTime(); - static void Descrambler(u8* data, u32 size); + static void Descrambler(u8* data, u32 size); private: - enum - { - ROM_SIZE = 1024*1024*2, - ROM_MASK = (ROM_SIZE - 1) - }; + enum + { + ROM_SIZE = 1024 * 1024 * 2, + ROM_MASK = (ROM_SIZE - 1) + }; - enum - { - REGION_RTC = 0x200000, - REGION_SRAM = 0x200001, - REGION_UART = 0x200100, - REGION_UART_UNK = 0x200103, - REGION_BARNACLE = 0x200113, - REGION_WRTC0 = 0x210000, - REGION_WRTC1 = 0x210001, - REGION_WRTC2 = 0x210008, - REGION_EUART_UNK = 0x300000, - REGION_EUART = 0x300001 - }; + enum + { + REGION_RTC = 0x200000, + REGION_SRAM = 0x200001, + REGION_UART = 0x200100, + REGION_UART_UNK = 0x200103, + REGION_BARNACLE = 0x200113, + REGION_WRTC0 = 0x210000, + REGION_WRTC1 = 0x210001, + REGION_WRTC2 = 0x210008, + REGION_EUART_UNK = 0x300000, + REGION_EUART = 0x300001 + }; - // Region - bool m_bNTSC; + // Region + bool m_bNTSC; - //! IPL - u8* m_pIPL; + //! IPL + u8* m_pIPL; - // STATE_TO_SAVE - //! RealTimeClock - u8 m_RTC[4]; + // STATE_TO_SAVE + //! RealTimeClock + u8 m_RTC[4]; - //! Helper - u32 m_uPosition; - u32 m_uAddress; - u32 m_uRWOffset; + //! Helper + u32 m_uPosition; + u32 m_uAddress; + u32 m_uRWOffset; - std::string m_buffer; - bool m_FontsLoaded; + std::string m_buffer; + bool m_FontsLoaded; - void UpdateRTC(); + void UpdateRTC(); - void TransferByte(u8& _uByte) override; - bool IsWriteCommand() const { return !!(m_uAddress & (1 << 31)); } - u32 CommandRegion() const { return (m_uAddress & ~(1 << 31)) >> 8; } - - void LoadFileToIPL(const std::string& filename, u32 offset); - void LoadFontFile(const std::string& filename, u32 offset); - std::string FindIPLDump(const std::string& path_prefix); + void TransferByte(u8& _uByte) override; + bool IsWriteCommand() const { return !!(m_uAddress & (1 << 31)); } + u32 CommandRegion() const { return (m_uAddress & ~(1 << 31)) >> 8; } + void LoadFileToIPL(const std::string& filename, u32 offset); + void LoadFontFile(const std::string& filename, u32 offset); + std::string FindIPLDump(const std::string& path_prefix); }; diff --git a/Source/Core/Core/HW/EXI_DeviceMemoryCard.cpp b/Source/Core/Core/HW/EXI_DeviceMemoryCard.cpp index 1cfdb7e210..763dba1dbe 100644 --- a/Source/Core/Core/HW/EXI_DeviceMemoryCard.cpp +++ b/Source/Core/Core/HW/EXI_DeviceMemoryCard.cpp @@ -11,12 +11,11 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/IniFile.h" +#include "Common/Logging/Log.h" #include "Common/NandPaths.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "Core/ConfigManager.h" #include "Core/CoreTiming.h" -#include "Core/Movie.h" #include "Core/HW/EXI.h" #include "Core/HW/EXI_Channel.h" #include "Core/HW/EXI_Device.h" @@ -27,14 +26,15 @@ #include "Core/HW/Memmap.h" #include "Core/HW/Sram.h" #include "Core/HW/SystemTimers.h" +#include "Core/Movie.h" #include "DiscIO/NANDContentLoader.h" -#define MC_STATUS_BUSY 0x80 -#define MC_STATUS_UNLOCKED 0x40 -#define MC_STATUS_SLEEP 0x20 -#define MC_STATUS_ERASEERROR 0x10 -#define MC_STATUS_PROGRAMEERROR 0x08 -#define MC_STATUS_READY 0x01 +#define MC_STATUS_BUSY 0x80 +#define MC_STATUS_UNLOCKED 0x40 +#define MC_STATUS_SLEEP 0x20 +#define MC_STATUS_ERASEERROR 0x10 +#define MC_STATUS_PROGRAMEERROR 0x08 +#define MC_STATUS_READY 0x01 #define SIZE_TO_Mb (1024 * 8 * 16) static const u32 MC_TRANSFER_RATE_READ = 512 * 1024; @@ -42,529 +42,525 @@ static const u32 MC_TRANSFER_RATE_WRITE = (u32)(96.125f * 1024.0f); // Takes care of the nasty recovery of the 'this' pointer from card_index, // stored in the userdata parameter of the CoreTiming event. -void CEXIMemoryCard::EventCompleteFindInstance(u64 userdata, std::function callback) +void CEXIMemoryCard::EventCompleteFindInstance(u64 userdata, + std::function callback) { - int card_index = (int)userdata; - CEXIMemoryCard* pThis = (CEXIMemoryCard*)ExpansionInterface::FindDevice( - EXIDEVICE_MEMORYCARD, card_index); - if (pThis == nullptr) - { - pThis = (CEXIMemoryCard*)ExpansionInterface::FindDevice( - EXIDEVICE_MEMORYCARDFOLDER, card_index); - } - if (pThis) - { - callback(pThis); - } + int card_index = (int)userdata; + CEXIMemoryCard* pThis = + (CEXIMemoryCard*)ExpansionInterface::FindDevice(EXIDEVICE_MEMORYCARD, card_index); + if (pThis == nullptr) + { + pThis = (CEXIMemoryCard*)ExpansionInterface::FindDevice(EXIDEVICE_MEMORYCARDFOLDER, card_index); + } + if (pThis) + { + callback(pThis); + } } void CEXIMemoryCard::CmdDoneCallback(u64 userdata, s64 cyclesLate) { - EventCompleteFindInstance(userdata, [](CEXIMemoryCard* instance) - { - instance->CmdDone(); - }); + EventCompleteFindInstance(userdata, [](CEXIMemoryCard* instance) { instance->CmdDone(); }); } void CEXIMemoryCard::TransferCompleteCallback(u64 userdata, s64 cyclesLate) { - EventCompleteFindInstance(userdata, [](CEXIMemoryCard* instance) - { - instance->TransferComplete(); - }); + EventCompleteFindInstance(userdata, + [](CEXIMemoryCard* instance) { instance->TransferComplete(); }); } -CEXIMemoryCard::CEXIMemoryCard(const int index, bool gciFolder) - : card_index(index) +CEXIMemoryCard::CEXIMemoryCard(const int index, bool gciFolder) : card_index(index) { - struct - { - const char *done; - const char *transfer_complete; - } const event_names[] = { - { "memcardDoneA", "memcardTransferCompleteA" }, - { "memcardDoneB", "memcardTransferCompleteB" }, - }; + struct + { + const char* done; + const char* transfer_complete; + } const event_names[] = { + {"memcardDoneA", "memcardTransferCompleteA"}, {"memcardDoneB", "memcardTransferCompleteB"}, + }; - if ((size_t)index >= ArraySize(event_names)) - { - PanicAlertT("Trying to create invalid memory card index."); - } - // we're potentially leaking events here, since there's no RemoveEvent - // until emu shutdown, but I guess it's inconsequential - et_cmd_done = CoreTiming::RegisterEvent(event_names[index].done, - CmdDoneCallback); - et_transfer_complete = CoreTiming::RegisterEvent( - event_names[index].transfer_complete, TransferCompleteCallback); + if ((size_t)index >= ArraySize(event_names)) + { + PanicAlertT("Trying to create invalid memory card index."); + } + // we're potentially leaking events here, since there's no RemoveEvent + // until emu shutdown, but I guess it's inconsequential + et_cmd_done = CoreTiming::RegisterEvent(event_names[index].done, CmdDoneCallback); + et_transfer_complete = + CoreTiming::RegisterEvent(event_names[index].transfer_complete, TransferCompleteCallback); - interruptSwitch = 0; - m_bInterruptSet = 0; - command = 0; - status = MC_STATUS_BUSY | MC_STATUS_UNLOCKED | MC_STATUS_READY; - m_uPosition = 0; - memset(programming_buffer, 0, sizeof(programming_buffer)); - //Nintendo Memory Card EXI IDs - //0x00000004 Memory Card 59 4Mbit - //0x00000008 Memory Card 123 8Mb - //0x00000010 Memory Card 251 16Mb - //0x00000020 Memory Card 507 32Mb - //0x00000040 Memory Card 1019 64Mb - //0x00000080 Memory Card 2043 128Mb + interruptSwitch = 0; + m_bInterruptSet = 0; + command = 0; + status = MC_STATUS_BUSY | MC_STATUS_UNLOCKED | MC_STATUS_READY; + m_uPosition = 0; + memset(programming_buffer, 0, sizeof(programming_buffer)); + // Nintendo Memory Card EXI IDs + // 0x00000004 Memory Card 59 4Mbit + // 0x00000008 Memory Card 123 8Mb + // 0x00000010 Memory Card 251 16Mb + // 0x00000020 Memory Card 507 32Mb + // 0x00000040 Memory Card 1019 64Mb + // 0x00000080 Memory Card 2043 128Mb - //0x00000510 16Mb "bigben" card - //card_id = 0xc243; - card_id = 0xc221; // It's a Nintendo brand memcard + // 0x00000510 16Mb "bigben" card + // card_id = 0xc243; + card_id = 0xc221; // It's a Nintendo brand memcard - // The following games have issues with memory cards bigger than 16Mb - // Darkened Skye GDQE6S GDQP6S - // WTA Tour Tennis GWTEA4 GWTJA4 GWTPA4 - // Disney Sports : Skate Boarding GDXEA4 GDXPA4 GDXJA4 - // Disney Sports : Soccer GDKEA4 - // Use a 16Mb (251 block) memory card for these games - bool useMC251; - IniFile gameIni = SConfig::GetInstance().LoadGameIni(); - gameIni.GetOrCreateSection("Core")->Get("MemoryCard251", &useMC251, false); - u16 sizeMb = useMC251 ? MemCard251Mb : MemCard2043Mb; + // The following games have issues with memory cards bigger than 16Mb + // Darkened Skye GDQE6S GDQP6S + // WTA Tour Tennis GWTEA4 GWTJA4 GWTPA4 + // Disney Sports : Skate Boarding GDXEA4 GDXPA4 GDXJA4 + // Disney Sports : Soccer GDKEA4 + // Use a 16Mb (251 block) memory card for these games + bool useMC251; + IniFile gameIni = SConfig::GetInstance().LoadGameIni(); + gameIni.GetOrCreateSection("Core")->Get("MemoryCard251", &useMC251, false); + u16 sizeMb = useMC251 ? MemCard251Mb : MemCard2043Mb; - if (gciFolder) - { - SetupGciFolder(sizeMb); - } - else - { - SetupRawMemcard(sizeMb); - } + if (gciFolder) + { + SetupGciFolder(sizeMb); + } + else + { + SetupRawMemcard(sizeMb); + } - memory_card_size = memorycard->GetCardId() * SIZE_TO_Mb; - u8 header[20] = {0}; - memorycard->Read(0, static_cast(ArraySize(header)), header); - SetCardFlashID(header, card_index); + memory_card_size = memorycard->GetCardId() * SIZE_TO_Mb; + u8 header[20] = {0}; + memorycard->Read(0, static_cast(ArraySize(header)), header); + SetCardFlashID(header, card_index); } void CEXIMemoryCard::SetupGciFolder(u16 sizeMb) { - DiscIO::IVolume::ECountry country_code = DiscIO::IVolume::COUNTRY_UNKNOWN; - auto strUniqueID = SConfig::GetInstance().m_strUniqueID; + DiscIO::IVolume::ECountry country_code = DiscIO::IVolume::COUNTRY_UNKNOWN; + auto strUniqueID = SConfig::GetInstance().m_strUniqueID; - u32 CurrentGameId = 0; - if (strUniqueID == TITLEID_SYSMENU_STRING) - { - const DiscIO::CNANDContentLoader & SysMenu_Loader = DiscIO::CNANDContentManager::Access().GetNANDLoader(TITLEID_SYSMENU, Common::FROM_SESSION_ROOT); - if (SysMenu_Loader.IsValid()) - { - country_code = DiscIO::CountrySwitch(SysMenu_Loader.GetCountryChar()); - } - } - else if (strUniqueID.length() >= 4) - { - country_code = DiscIO::CountrySwitch(strUniqueID.at(3)); - CurrentGameId = BE32((u8*)strUniqueID.c_str()); - } - bool ascii = true; - std::string strDirectoryName = File::GetUserPath(D_GCUSER_IDX); - switch (country_code) - { - case DiscIO::IVolume::COUNTRY_JAPAN: - ascii = false; - strDirectoryName += JAP_DIR DIR_SEP; - break; - case DiscIO::IVolume::COUNTRY_USA: - strDirectoryName += USA_DIR DIR_SEP; - break; - case DiscIO::IVolume::COUNTRY_UNKNOWN: - { - // The current game's region is not passed down to the EXI device level. - // Usually, we can retrieve the region from SConfig::GetInstance().m_strUniqueId. - // The Wii System Menu requires a lookup based on the version number. - // This is not possible in some cases ( e.g. FIFO logs, homebrew elf/dol files). - // Instead, we then lookup the region from the memory card name - // Earlier in the boot process the region is added to the memory card name (This is done by the function checkMemcardPath) - // For now take advantage of this. - // Future options: - // Set memory card directory path in the checkMemcardPath function. - // or Add region to SConfig::GetInstance(). - // or Pass region down to the EXI device creation. + u32 CurrentGameId = 0; + if (strUniqueID == TITLEID_SYSMENU_STRING) + { + const DiscIO::CNANDContentLoader& SysMenu_Loader = + DiscIO::CNANDContentManager::Access().GetNANDLoader(TITLEID_SYSMENU, + Common::FROM_SESSION_ROOT); + if (SysMenu_Loader.IsValid()) + { + country_code = DiscIO::CountrySwitch(SysMenu_Loader.GetCountryChar()); + } + } + else if (strUniqueID.length() >= 4) + { + country_code = DiscIO::CountrySwitch(strUniqueID.at(3)); + CurrentGameId = BE32((u8*)strUniqueID.c_str()); + } + bool ascii = true; + std::string strDirectoryName = File::GetUserPath(D_GCUSER_IDX); + switch (country_code) + { + case DiscIO::IVolume::COUNTRY_JAPAN: + ascii = false; + strDirectoryName += JAP_DIR DIR_SEP; + break; + case DiscIO::IVolume::COUNTRY_USA: + strDirectoryName += USA_DIR DIR_SEP; + break; + case DiscIO::IVolume::COUNTRY_UNKNOWN: + { + // The current game's region is not passed down to the EXI device level. + // Usually, we can retrieve the region from SConfig::GetInstance().m_strUniqueId. + // The Wii System Menu requires a lookup based on the version number. + // This is not possible in some cases ( e.g. FIFO logs, homebrew elf/dol files). + // Instead, we then lookup the region from the memory card name + // Earlier in the boot process the region is added to the memory card name (This is done by the + // function checkMemcardPath) + // For now take advantage of this. + // Future options: + // Set memory card directory path in the checkMemcardPath function. + // or Add region to SConfig::GetInstance(). + // or Pass region down to the EXI device creation. - std::string memcardFilename = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : SConfig::GetInstance().m_strMemoryCardB; - std::string region = memcardFilename.substr(memcardFilename.size() - 7, 3); - if (region == JAP_DIR) - { - country_code = DiscIO::IVolume::COUNTRY_JAPAN; - ascii = false; - strDirectoryName += JAP_DIR DIR_SEP; - break; - } - else if (region == USA_DIR) - { - country_code = DiscIO::IVolume::COUNTRY_USA; - strDirectoryName += USA_DIR DIR_SEP; - break; - } - } - default: - country_code = DiscIO::IVolume::COUNTRY_EUROPE; - strDirectoryName += EUR_DIR DIR_SEP; - } - strDirectoryName += StringFromFormat("Card %c", 'A' + card_index); + std::string memcardFilename = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : + SConfig::GetInstance().m_strMemoryCardB; + std::string region = memcardFilename.substr(memcardFilename.size() - 7, 3); + if (region == JAP_DIR) + { + country_code = DiscIO::IVolume::COUNTRY_JAPAN; + ascii = false; + strDirectoryName += JAP_DIR DIR_SEP; + break; + } + else if (region == USA_DIR) + { + country_code = DiscIO::IVolume::COUNTRY_USA; + strDirectoryName += USA_DIR DIR_SEP; + break; + } + } + default: + country_code = DiscIO::IVolume::COUNTRY_EUROPE; + strDirectoryName += EUR_DIR DIR_SEP; + } + strDirectoryName += StringFromFormat("Card %c", 'A' + card_index); - if (!File::Exists(strDirectoryName)) // first use of memcard folder, migrate automatically - { - MigrateFromMemcardFile(strDirectoryName + DIR_SEP, card_index); - } - else if (!File::IsDirectory(strDirectoryName)) - { - if (File::Rename(strDirectoryName, strDirectoryName + ".original")) - { - PanicAlertT("%s was not a directory, moved to *.original", strDirectoryName.c_str()); - MigrateFromMemcardFile(strDirectoryName + DIR_SEP, card_index); - } - else // we tried but the user wants to crash - { - // TODO more user friendly abort - PanicAlertT("%s is not a directory, failed to move to *.original.\n Verify your write permissions or move " - "the file outside of Dolphin", - strDirectoryName.c_str()); - exit(0); - } - } + if (!File::Exists(strDirectoryName)) // first use of memcard folder, migrate automatically + { + MigrateFromMemcardFile(strDirectoryName + DIR_SEP, card_index); + } + else if (!File::IsDirectory(strDirectoryName)) + { + if (File::Rename(strDirectoryName, strDirectoryName + ".original")) + { + PanicAlertT("%s was not a directory, moved to *.original", strDirectoryName.c_str()); + MigrateFromMemcardFile(strDirectoryName + DIR_SEP, card_index); + } + else // we tried but the user wants to crash + { + // TODO more user friendly abort + PanicAlertT("%s is not a directory, failed to move to *.original.\n Verify your write " + "permissions or move " + "the file outside of Dolphin", + strDirectoryName.c_str()); + exit(0); + } + } - memorycard = std::make_unique(strDirectoryName + DIR_SEP, card_index, sizeMb, ascii, - country_code, CurrentGameId); + memorycard = std::make_unique(strDirectoryName + DIR_SEP, card_index, sizeMb, + ascii, country_code, CurrentGameId); } void CEXIMemoryCard::SetupRawMemcard(u16 sizeMb) { - std::string filename = - (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : SConfig::GetInstance().m_strMemoryCardB; - if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsUsingMemcard(card_index) && - Movie::IsStartingFromClearSave()) - filename = File::GetUserPath(D_GCUSER_IDX) + StringFromFormat("Movie%s.raw", (card_index == 0) ? "A" : "B"); + std::string filename = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : + SConfig::GetInstance().m_strMemoryCardB; + if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsUsingMemcard(card_index) && + Movie::IsStartingFromClearSave()) + filename = File::GetUserPath(D_GCUSER_IDX) + + StringFromFormat("Movie%s.raw", (card_index == 0) ? "A" : "B"); - if (sizeMb == MemCard251Mb) - { - filename.insert(filename.find_last_of("."), ".251"); - } - memorycard = std::make_unique(filename, card_index, sizeMb); + if (sizeMb == MemCard251Mb) + { + filename.insert(filename.find_last_of("."), ".251"); + } + memorycard = std::make_unique(filename, card_index, sizeMb); } CEXIMemoryCard::~CEXIMemoryCard() { - CoreTiming::RemoveEvent(et_cmd_done); - CoreTiming::RemoveEvent(et_transfer_complete); + CoreTiming::RemoveEvent(et_cmd_done); + CoreTiming::RemoveEvent(et_transfer_complete); } bool CEXIMemoryCard::UseDelayedTransferCompletion() const { - return true; + return true; } bool CEXIMemoryCard::IsPresent() const { - return true; + return true; } void CEXIMemoryCard::CmdDone() { - status |= MC_STATUS_READY; - status &= ~MC_STATUS_BUSY; + status |= MC_STATUS_READY; + status &= ~MC_STATUS_BUSY; - m_bInterruptSet = 1; - ExpansionInterface::UpdateInterrupts(); + m_bInterruptSet = 1; + ExpansionInterface::UpdateInterrupts(); } void CEXIMemoryCard::TransferComplete() { - // Transfer complete, send interrupt - ExpansionInterface::GetChannel(card_index)->SendTransferComplete(); + // Transfer complete, send interrupt + ExpansionInterface::GetChannel(card_index)->SendTransferComplete(); } void CEXIMemoryCard::CmdDoneLater(u64 cycles) { - CoreTiming::RemoveEvent(et_cmd_done); - CoreTiming::ScheduleEvent((int)cycles, et_cmd_done, (u64)card_index); + CoreTiming::RemoveEvent(et_cmd_done); + CoreTiming::ScheduleEvent((int)cycles, et_cmd_done, (u64)card_index); } void CEXIMemoryCard::SetCS(int cs) { - if (cs) // not-selected to selected - { - m_uPosition = 0; - } - else - { - switch (command) - { - case cmdSectorErase: - if (m_uPosition > 2) - { - memorycard->ClearBlock(address & (memory_card_size - 1)); - status |= MC_STATUS_BUSY; - status &= ~MC_STATUS_READY; + if (cs) // not-selected to selected + { + m_uPosition = 0; + } + else + { + switch (command) + { + case cmdSectorErase: + if (m_uPosition > 2) + { + memorycard->ClearBlock(address & (memory_card_size - 1)); + status |= MC_STATUS_BUSY; + status &= ~MC_STATUS_READY; - //??? + //??? - CmdDoneLater(5000); - } - break; + CmdDoneLater(5000); + } + break; - case cmdChipErase: - if (m_uPosition > 2) - { - // TODO: Investigate on HW, I (LPFaint99) believe that this only - // erases the system area (Blocks 0-4) - memorycard->ClearAll(); - status &= ~MC_STATUS_BUSY; - } - break; + case cmdChipErase: + if (m_uPosition > 2) + { + // TODO: Investigate on HW, I (LPFaint99) believe that this only + // erases the system area (Blocks 0-4) + memorycard->ClearAll(); + status &= ~MC_STATUS_BUSY; + } + break; - case cmdPageProgram: - if (m_uPosition >= 5) - { - int count = m_uPosition - 5; - int i = 0; - status &= ~0x80; + case cmdPageProgram: + if (m_uPosition >= 5) + { + int count = m_uPosition - 5; + int i = 0; + status &= ~0x80; - while (count--) - { - memorycard->Write(address, 1, &(programming_buffer[i++])); - i &= 127; - address = (address & ~0x1FF) | ((address + 1) & 0x1FF); - } + while (count--) + { + memorycard->Write(address, 1, &(programming_buffer[i++])); + i &= 127; + address = (address & ~0x1FF) | ((address + 1) & 0x1FF); + } - CmdDoneLater(5000); - } - break; - } - } + CmdDoneLater(5000); + } + break; + } + } } bool CEXIMemoryCard::IsInterruptSet() { - if (interruptSwitch) - return m_bInterruptSet; - return false; + if (interruptSwitch) + return m_bInterruptSet; + return false; } -void CEXIMemoryCard::TransferByte(u8 &byte) +void CEXIMemoryCard::TransferByte(u8& byte) { - DEBUG_LOG(EXPANSIONINTERFACE, "EXI MEMCARD: > %02x", byte); - if (m_uPosition == 0) - { - command = byte; // first byte is command - byte = 0xFF; // would be tristate, but we don't care. + DEBUG_LOG(EXPANSIONINTERFACE, "EXI MEMCARD: > %02x", byte); + if (m_uPosition == 0) + { + command = byte; // first byte is command + byte = 0xFF; // would be tristate, but we don't care. - switch (command) // This seems silly, do we really need it? - { - case cmdNintendoID: - case cmdReadArray: - case cmdArrayToBuffer: - case cmdSetInterrupt: - case cmdWriteBuffer: - case cmdReadStatus: - case cmdReadID: - case cmdReadErrorBuffer: - case cmdWakeUp: - case cmdSleep: - case cmdClearStatus: - case cmdSectorErase: - case cmdPageProgram: - case cmdExtraByteProgram: - case cmdChipErase: - INFO_LOG(EXPANSIONINTERFACE, "EXI MEMCARD: command %02x at position 0. seems normal.", command); - break; - default: - WARN_LOG(EXPANSIONINTERFACE, "EXI MEMCARD: command %02x at position 0", command); - break; - } - if (command == cmdClearStatus) - { - status &= ~MC_STATUS_PROGRAMEERROR; - status &= ~MC_STATUS_ERASEERROR; + switch (command) // This seems silly, do we really need it? + { + case cmdNintendoID: + case cmdReadArray: + case cmdArrayToBuffer: + case cmdSetInterrupt: + case cmdWriteBuffer: + case cmdReadStatus: + case cmdReadID: + case cmdReadErrorBuffer: + case cmdWakeUp: + case cmdSleep: + case cmdClearStatus: + case cmdSectorErase: + case cmdPageProgram: + case cmdExtraByteProgram: + case cmdChipErase: + INFO_LOG(EXPANSIONINTERFACE, "EXI MEMCARD: command %02x at position 0. seems normal.", + command); + break; + default: + WARN_LOG(EXPANSIONINTERFACE, "EXI MEMCARD: command %02x at position 0", command); + break; + } + if (command == cmdClearStatus) + { + status &= ~MC_STATUS_PROGRAMEERROR; + status &= ~MC_STATUS_ERASEERROR; - status |= MC_STATUS_READY; + status |= MC_STATUS_READY; - m_bInterruptSet = 0; + m_bInterruptSet = 0; - byte = 0xFF; - m_uPosition = 0; - } - } - else - { - switch (command) - { - case cmdNintendoID: - // - // Nintendo card: - // 00 | 80 00 00 00 10 00 00 00 - // "bigben" card: - // 00 | ff 00 00 05 10 00 00 00 00 00 00 00 00 00 00 - // we do it the Nintendo way. - if (m_uPosition == 1) - byte = 0x80; // dummy cycle - else - byte = (u8)(memorycard->GetCardId() >> (24 - (((m_uPosition - 2) & 3) * 8))); - break; + byte = 0xFF; + m_uPosition = 0; + } + } + else + { + switch (command) + { + case cmdNintendoID: + // + // Nintendo card: + // 00 | 80 00 00 00 10 00 00 00 + // "bigben" card: + // 00 | ff 00 00 05 10 00 00 00 00 00 00 00 00 00 00 + // we do it the Nintendo way. + if (m_uPosition == 1) + byte = 0x80; // dummy cycle + else + byte = (u8)(memorycard->GetCardId() >> (24 - (((m_uPosition - 2) & 3) * 8))); + break; - case cmdReadArray: - switch (m_uPosition) - { - case 1: // AD1 - address = byte << 17; - byte = 0xFF; - break; - case 2: // AD2 - address |= byte << 9; - break; - case 3: // AD3 - address |= (byte & 3) << 7; - break; - case 4: // BA - address |= (byte & 0x7F); - break; - } - if (m_uPosition > 1) // not specified for 1..8, anyway - { - memorycard->Read(address & (memory_card_size - 1), 1, &byte); - // after 9 bytes, we start incrementing the address, - // but only the sector offset - the pointer wraps around - if (m_uPosition >= 9) - address = (address & ~0x1FF) | ((address + 1) & 0x1FF); - } - break; + case cmdReadArray: + switch (m_uPosition) + { + case 1: // AD1 + address = byte << 17; + byte = 0xFF; + break; + case 2: // AD2 + address |= byte << 9; + break; + case 3: // AD3 + address |= (byte & 3) << 7; + break; + case 4: // BA + address |= (byte & 0x7F); + break; + } + if (m_uPosition > 1) // not specified for 1..8, anyway + { + memorycard->Read(address & (memory_card_size - 1), 1, &byte); + // after 9 bytes, we start incrementing the address, + // but only the sector offset - the pointer wraps around + if (m_uPosition >= 9) + address = (address & ~0x1FF) | ((address + 1) & 0x1FF); + } + break; - case cmdReadStatus: - // (unspecified for byte 1) - byte = status; - break; + case cmdReadStatus: + // (unspecified for byte 1) + byte = status; + break; - case cmdReadID: - if (m_uPosition == 1) // (unspecified) - byte = (u8)(card_id >> 8); - else - byte = (u8)((m_uPosition & 1) ? (card_id) : (card_id >> 8)); - break; + case cmdReadID: + if (m_uPosition == 1) // (unspecified) + byte = (u8)(card_id >> 8); + else + byte = (u8)((m_uPosition & 1) ? (card_id) : (card_id >> 8)); + break; - case cmdSectorErase: - switch (m_uPosition) - { - case 1: // AD1 - address = byte << 17; - break; - case 2: // AD2 - address |= byte << 9; - break; - } - byte = 0xFF; - break; + case cmdSectorErase: + switch (m_uPosition) + { + case 1: // AD1 + address = byte << 17; + break; + case 2: // AD2 + address |= byte << 9; + break; + } + byte = 0xFF; + break; - case cmdSetInterrupt: - if (m_uPosition == 1) - { - interruptSwitch = byte; - } - byte = 0xFF; - break; + case cmdSetInterrupt: + if (m_uPosition == 1) + { + interruptSwitch = byte; + } + byte = 0xFF; + break; - case cmdChipErase: - byte = 0xFF; - break; + case cmdChipErase: + byte = 0xFF; + break; - case cmdPageProgram: - switch (m_uPosition) - { - case 1: // AD1 - address = byte << 17; - break; - case 2: // AD2 - address |= byte << 9; - break; - case 3: // AD3 - address |= (byte & 3) << 7; - break; - case 4: // BA - address |= (byte & 0x7F); - break; - } + case cmdPageProgram: + switch (m_uPosition) + { + case 1: // AD1 + address = byte << 17; + break; + case 2: // AD2 + address |= byte << 9; + break; + case 3: // AD3 + address |= (byte & 3) << 7; + break; + case 4: // BA + address |= (byte & 0x7F); + break; + } - if (m_uPosition >= 5) - programming_buffer[((m_uPosition - 5) & 0x7F)] = byte; // wrap around after 128 bytes + if (m_uPosition >= 5) + programming_buffer[((m_uPosition - 5) & 0x7F)] = byte; // wrap around after 128 bytes - byte = 0xFF; - break; + byte = 0xFF; + break; - default: - WARN_LOG(EXPANSIONINTERFACE, "EXI MEMCARD: unknown command byte %02x\n", byte); - byte = 0xFF; - } - } - m_uPosition++; - DEBUG_LOG(EXPANSIONINTERFACE, "EXI MEMCARD: < %02x", byte); + default: + WARN_LOG(EXPANSIONINTERFACE, "EXI MEMCARD: unknown command byte %02x\n", byte); + byte = 0xFF; + } + } + m_uPosition++; + DEBUG_LOG(EXPANSIONINTERFACE, "EXI MEMCARD: < %02x", byte); } -void CEXIMemoryCard::DoState(PointerWrap &p) +void CEXIMemoryCard::DoState(PointerWrap& p) { - // for movie sync, we need to save/load memory card contents (and other data) in savestates. - // otherwise, we'll assume the user wants to keep their memcards and saves separate, - // unless we're loading (in which case we let the savestate contents decide, in order to stay aligned with them). - bool storeContents = (Movie::IsMovieActive()); - p.Do(storeContents); + // for movie sync, we need to save/load memory card contents (and other data) in savestates. + // otherwise, we'll assume the user wants to keep their memcards and saves separate, + // unless we're loading (in which case we let the savestate contents decide, in order to stay + // aligned with them). + bool storeContents = (Movie::IsMovieActive()); + p.Do(storeContents); - if (storeContents) - { - p.Do(interruptSwitch); - p.Do(m_bInterruptSet); - p.Do(command); - p.Do(status); - p.Do(m_uPosition); - p.Do(programming_buffer); - p.Do(address); - memorycard->DoState(p); - p.Do(card_index); - } + if (storeContents) + { + p.Do(interruptSwitch); + p.Do(m_bInterruptSet); + p.Do(command); + p.Do(status); + p.Do(m_uPosition); + p.Do(programming_buffer); + p.Do(address); + memorycard->DoState(p); + p.Do(card_index); + } } IEXIDevice* CEXIMemoryCard::FindDevice(TEXIDevices device_type, int customIndex) { - if (device_type != m_deviceType) - return nullptr; - if (customIndex != card_index) - return nullptr; - return this; + if (device_type != m_deviceType) + return nullptr; + if (customIndex != card_index) + return nullptr; + return this; } // DMA reads are preceded by all of the necessary setup via IMMRead // read all at once instead of single byte at a time as done by IEXIDevice::DMARead void CEXIMemoryCard::DMARead(u32 _uAddr, u32 _uSize) { - memorycard->Read(address, _uSize, Memory::GetPointer(_uAddr)); + memorycard->Read(address, _uSize, Memory::GetPointer(_uAddr)); - if ((address + _uSize) % BLOCK_SIZE == 0) - { - DEBUG_LOG(EXPANSIONINTERFACE, "reading from block: %x", - address / BLOCK_SIZE); - } + if ((address + _uSize) % BLOCK_SIZE == 0) + { + DEBUG_LOG(EXPANSIONINTERFACE, "reading from block: %x", address / BLOCK_SIZE); + } - // Schedule transfer complete later based on read speed - CoreTiming::ScheduleEvent( - _uSize * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_READ), - et_transfer_complete, (u64)card_index); + // Schedule transfer complete later based on read speed + CoreTiming::ScheduleEvent(_uSize * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_READ), + et_transfer_complete, (u64)card_index); } // DMA write are preceded by all of the necessary setup via IMMWrite // write all at once instead of single byte at a time as done by IEXIDevice::DMAWrite void CEXIMemoryCard::DMAWrite(u32 _uAddr, u32 _uSize) { - memorycard->Write(address, _uSize, Memory::GetPointer(_uAddr)); + memorycard->Write(address, _uSize, Memory::GetPointer(_uAddr)); - if (((address + _uSize) % BLOCK_SIZE) == 0) - { - DEBUG_LOG(EXPANSIONINTERFACE, "writing to block: %x", - address / BLOCK_SIZE); - } + if (((address + _uSize) % BLOCK_SIZE) == 0) + { + DEBUG_LOG(EXPANSIONINTERFACE, "writing to block: %x", address / BLOCK_SIZE); + } - // Schedule transfer complete later based on write speed - CoreTiming::ScheduleEvent( - _uSize * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE), - et_transfer_complete, (u64)card_index); + // Schedule transfer complete later based on write speed + CoreTiming::ScheduleEvent(_uSize * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE), + et_transfer_complete, (u64)card_index); } diff --git a/Source/Core/Core/HW/EXI_DeviceMemoryCard.h b/Source/Core/Core/HW/EXI_DeviceMemoryCard.h index 87f75f7975..53763e7e5f 100644 --- a/Source/Core/Core/HW/EXI_DeviceMemoryCard.h +++ b/Source/Core/Core/HW/EXI_DeviceMemoryCard.h @@ -15,73 +15,74 @@ class PointerWrap; class CEXIMemoryCard : public IEXIDevice { public: - CEXIMemoryCard(const int index, bool gciFolder); - virtual ~CEXIMemoryCard(); - void SetCS(int cs) override; - bool IsInterruptSet() override; - bool UseDelayedTransferCompletion() const override; - bool IsPresent() const override; - void DoState(PointerWrap &p) override; - IEXIDevice* FindDevice(TEXIDevices device_type, int customIndex = -1) override; - void DMARead(u32 _uAddr, u32 _uSize) override; - void DMAWrite(u32 _uAddr, u32 _uSize) override; + CEXIMemoryCard(const int index, bool gciFolder); + virtual ~CEXIMemoryCard(); + void SetCS(int cs) override; + bool IsInterruptSet() override; + bool UseDelayedTransferCompletion() const override; + bool IsPresent() const override; + void DoState(PointerWrap& p) override; + IEXIDevice* FindDevice(TEXIDevices device_type, int customIndex = -1) override; + void DMARead(u32 _uAddr, u32 _uSize) override; + void DMAWrite(u32 _uAddr, u32 _uSize) override; private: - void SetupGciFolder(u16 sizeMb); - void SetupRawMemcard(u16 sizeMb); - static void EventCompleteFindInstance(u64 userdata, std::function callback); + void SetupGciFolder(u16 sizeMb); + void SetupRawMemcard(u16 sizeMb); + static void EventCompleteFindInstance(u64 userdata, + std::function callback); - // Scheduled when a command that required delayed end signaling is done. - static void CmdDoneCallback(u64 userdata, s64 cyclesLate); + // Scheduled when a command that required delayed end signaling is done. + static void CmdDoneCallback(u64 userdata, s64 cyclesLate); - // Scheduled when memory card is done transferring data - static void TransferCompleteCallback(u64 userdata, s64 cyclesLate); + // Scheduled when memory card is done transferring data + static void TransferCompleteCallback(u64 userdata, s64 cyclesLate); - // Signals that the command that was previously executed is now done. - void CmdDone(); + // Signals that the command that was previously executed is now done. + void CmdDone(); - // Signals that the transfer that was previously executed is now done. - void TransferComplete(); + // Signals that the transfer that was previously executed is now done. + void TransferComplete(); - // Variant of CmdDone which schedules an event later in the future to complete the command. - void CmdDoneLater(u64 cycles); + // Variant of CmdDone which schedules an event later in the future to complete the command. + void CmdDoneLater(u64 cycles); - enum - { - cmdNintendoID = 0x00, - cmdReadArray = 0x52, - cmdArrayToBuffer = 0x53, - cmdSetInterrupt = 0x81, - cmdWriteBuffer = 0x82, - cmdReadStatus = 0x83, - cmdReadID = 0x85, - cmdReadErrorBuffer = 0x86, - cmdWakeUp = 0x87, - cmdSleep = 0x88, - cmdClearStatus = 0x89, - cmdSectorErase = 0xF1, - cmdPageProgram = 0xF2, - cmdExtraByteProgram = 0xF3, - cmdChipErase = 0xF4, - }; + enum + { + cmdNintendoID = 0x00, + cmdReadArray = 0x52, + cmdArrayToBuffer = 0x53, + cmdSetInterrupt = 0x81, + cmdWriteBuffer = 0x82, + cmdReadStatus = 0x83, + cmdReadID = 0x85, + cmdReadErrorBuffer = 0x86, + cmdWakeUp = 0x87, + cmdSleep = 0x88, + cmdClearStatus = 0x89, + cmdSectorErase = 0xF1, + cmdPageProgram = 0xF2, + cmdExtraByteProgram = 0xF3, + cmdChipErase = 0xF4, + }; - int card_index; - int et_cmd_done, et_transfer_complete; - //! memory card state + int card_index; + int et_cmd_done, et_transfer_complete; + //! memory card state - // STATE_TO_SAVE - int interruptSwitch; - bool m_bInterruptSet; - int command; - int status; - u32 m_uPosition; - u8 programming_buffer[128]; - //! memory card parameters - unsigned int card_id; - unsigned int address; - u32 memory_card_size; - std::unique_ptr memorycard; + // STATE_TO_SAVE + int interruptSwitch; + bool m_bInterruptSet; + int command; + int status; + u32 m_uPosition; + u8 programming_buffer[128]; + //! memory card parameters + unsigned int card_id; + unsigned int address; + u32 memory_card_size; + std::unique_ptr memorycard; protected: - void TransferByte(u8& byte) override; + void TransferByte(u8& byte) override; }; diff --git a/Source/Core/Core/HW/EXI_DeviceMic.cpp b/Source/Core/Core/HW/EXI_DeviceMic.cpp index bc9d7ee4f2..4115fe6497 100644 --- a/Source/Core/Core/HW/EXI_DeviceMic.cpp +++ b/Source/Core/Core/HW/EXI_DeviceMic.cpp @@ -19,118 +19,115 @@ #include -void CEXIMic::StreamLog(const char *msg) +void CEXIMic::StreamLog(const char* msg) { - DEBUG_LOG(EXPANSIONINTERFACE, "%s: %s", - msg, Pa_GetErrorText(pa_error)); + DEBUG_LOG(EXPANSIONINTERFACE, "%s: %s", msg, Pa_GetErrorText(pa_error)); } void CEXIMic::StreamInit() { - // Setup the wonderful c-interfaced lib... - pa_stream = nullptr; + // Setup the wonderful c-interfaced lib... + pa_stream = nullptr; - if ((pa_error = Pa_Initialize()) != paNoError) - StreamLog("Pa_Initialize"); + if ((pa_error = Pa_Initialize()) != paNoError) + StreamLog("Pa_Initialize"); - stream_buffer = nullptr; - samples_avail = stream_wpos = stream_rpos = 0; + stream_buffer = nullptr; + samples_avail = stream_wpos = stream_rpos = 0; } void CEXIMic::StreamTerminate() { - StreamStop(); + StreamStop(); - if ((pa_error = Pa_Terminate()) != paNoError) - StreamLog("Pa_Terminate"); + if ((pa_error = Pa_Terminate()) != paNoError) + StreamLog("Pa_Terminate"); } -static int Pa_Callback(const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo *timeInfo, - PaStreamCallbackFlags statusFlags, - void *userData) +static int Pa_Callback(const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, + void* userData) { - (void)outputBuffer; - (void)timeInfo; - (void)statusFlags; + (void)outputBuffer; + (void)timeInfo; + (void)statusFlags; - CEXIMic *mic = (CEXIMic *)userData; + CEXIMic* mic = (CEXIMic*)userData; - std::lock_guard lk(mic->ring_lock); + std::lock_guard lk(mic->ring_lock); - if (mic->stream_wpos + mic->buff_size_samples > mic->stream_size) - mic->stream_wpos = 0; + if (mic->stream_wpos + mic->buff_size_samples > mic->stream_size) + mic->stream_wpos = 0; - s16 *buff_in = (s16 *)inputBuffer; - s16 *buff_out = &mic->stream_buffer[mic->stream_wpos]; + s16* buff_in = (s16*)inputBuffer; + s16* buff_out = &mic->stream_buffer[mic->stream_wpos]; - if (buff_in == nullptr) - { - for (int i = 0; i < mic->buff_size_samples; i++) - { - buff_out[i] = 0; - } - } - else - { - for (int i = 0; i < mic->buff_size_samples; i++) - { - buff_out[i] = buff_in[i]; - } - } + if (buff_in == nullptr) + { + for (int i = 0; i < mic->buff_size_samples; i++) + { + buff_out[i] = 0; + } + } + else + { + for (int i = 0; i < mic->buff_size_samples; i++) + { + buff_out[i] = buff_in[i]; + } + } - mic->samples_avail += mic->buff_size_samples; - if (mic->samples_avail > mic->stream_size) - { - mic->samples_avail = 0; - mic->status.buff_ovrflw = 1; - } + mic->samples_avail += mic->buff_size_samples; + if (mic->samples_avail > mic->stream_size) + { + mic->samples_avail = 0; + mic->status.buff_ovrflw = 1; + } - mic->stream_wpos += mic->buff_size_samples; - mic->stream_wpos %= mic->stream_size; + mic->stream_wpos += mic->buff_size_samples; + mic->stream_wpos %= mic->stream_size; - return paContinue; + return paContinue; } void CEXIMic::StreamStart() { - // Open stream with current parameters - stream_size = buff_size_samples * 500; - stream_buffer = new s16[stream_size]; + // Open stream with current parameters + stream_size = buff_size_samples * 500; + stream_buffer = new s16[stream_size]; - pa_error = Pa_OpenDefaultStream(&pa_stream, 1, 0, paInt16, - sample_rate, buff_size_samples, Pa_Callback, this); - StreamLog("Pa_OpenDefaultStream"); - pa_error = Pa_StartStream(pa_stream); - StreamLog("Pa_StartStream"); + pa_error = Pa_OpenDefaultStream(&pa_stream, 1, 0, paInt16, sample_rate, buff_size_samples, + Pa_Callback, this); + StreamLog("Pa_OpenDefaultStream"); + pa_error = Pa_StartStream(pa_stream); + StreamLog("Pa_StartStream"); } void CEXIMic::StreamStop() { - if (pa_stream != nullptr && Pa_IsStreamActive(pa_stream) >= paNoError) - Pa_AbortStream(pa_stream); + if (pa_stream != nullptr && Pa_IsStreamActive(pa_stream) >= paNoError) + Pa_AbortStream(pa_stream); - samples_avail = stream_wpos = stream_rpos = 0; + samples_avail = stream_wpos = stream_rpos = 0; - delete [] stream_buffer; - stream_buffer = nullptr; + delete[] stream_buffer; + stream_buffer = nullptr; } void CEXIMic::StreamReadOne() { - std::lock_guard lk(ring_lock); + std::lock_guard lk(ring_lock); - if (samples_avail >= buff_size_samples) - { - s16 *last_buffer = &stream_buffer[stream_rpos]; - std::memcpy(ring_buffer, last_buffer, buff_size); + if (samples_avail >= buff_size_samples) + { + s16* last_buffer = &stream_buffer[stream_rpos]; + std::memcpy(ring_buffer, last_buffer, buff_size); - samples_avail -= buff_size_samples; + samples_avail -= buff_size_samples; - stream_rpos += buff_size_samples; - stream_rpos %= stream_size; - } + stream_rpos += buff_size_samples; + stream_rpos %= stream_size; + } } // EXI Mic Device @@ -140,135 +137,134 @@ void CEXIMic::StreamReadOne() // cmdGetBuffer, which is when we actually read data from a buffer filled // in the background by Pa_Callback. -u8 const CEXIMic::exi_id[] = { 0, 0x0a, 0, 0, 0 }; +u8 const CEXIMic::exi_id[] = {0, 0x0a, 0, 0, 0}; -CEXIMic::CEXIMic(int index) - : slot(index) +CEXIMic::CEXIMic(int index) : slot(index) { - m_position = 0; - command = 0; - status.U16 = 0; + m_position = 0; + command = 0; + status.U16 = 0; - sample_rate = rate_base; - buff_size = ring_base; - buff_size_samples = buff_size / sample_size; + sample_rate = rate_base; + buff_size = ring_base; + buff_size_samples = buff_size / sample_size; - ring_pos = 0; - std::memset(ring_buffer, 0, sizeof(ring_buffer)); + ring_pos = 0; + std::memset(ring_buffer, 0, sizeof(ring_buffer)); - next_int_ticks = 0; + next_int_ticks = 0; - StreamInit(); + StreamInit(); } CEXIMic::~CEXIMic() { - StreamTerminate(); + StreamTerminate(); } bool CEXIMic::IsPresent() const { - return true; + return true; } void CEXIMic::SetCS(int cs) { - if (cs) // not-selected to selected - m_position = 0; - // Doesn't appear to do anything we care about - //else if (command == cmdReset) + if (cs) // not-selected to selected + m_position = 0; + // Doesn't appear to do anything we care about + // else if (command == cmdReset) } void CEXIMic::UpdateNextInterruptTicks() { - int diff = (SystemTimers::GetTicksPerSecond() / sample_rate) * buff_size_samples; - next_int_ticks = CoreTiming::GetTicks() + diff; - ExpansionInterface::ScheduleUpdateInterrupts(diff); + int diff = (SystemTimers::GetTicksPerSecond() / sample_rate) * buff_size_samples; + next_int_ticks = CoreTiming::GetTicks() + diff; + ExpansionInterface::ScheduleUpdateInterrupts(diff); } bool CEXIMic::IsInterruptSet() { - if (next_int_ticks && CoreTiming::GetTicks() >= next_int_ticks) - { - if (status.is_active) - UpdateNextInterruptTicks(); - else - next_int_ticks = 0; + if (next_int_ticks && CoreTiming::GetTicks() >= next_int_ticks) + { + if (status.is_active) + UpdateNextInterruptTicks(); + else + next_int_ticks = 0; - return true; - } - else - { - return false; - } + return true; + } + else + { + return false; + } } -void CEXIMic::TransferByte(u8 &byte) +void CEXIMic::TransferByte(u8& byte) { - if (m_position == 0) - { - command = byte; // first byte is command - byte = 0xFF; // would be tristate, but we don't care. - m_position++; - return; - } + if (m_position == 0) + { + command = byte; // first byte is command + byte = 0xFF; // would be tristate, but we don't care. + m_position++; + return; + } - int pos = m_position - 1; + int pos = m_position - 1; - switch (command) - { - case cmdID: - byte = exi_id[pos]; - break; + switch (command) + { + case cmdID: + byte = exi_id[pos]; + break; - case cmdGetStatus: - if (pos == 0) - status.button = Pad::GetMicButton(slot); + case cmdGetStatus: + if (pos == 0) + status.button = Pad::GetMicButton(slot); - byte = status.U8[pos ^ 1]; + byte = status.U8[pos ^ 1]; - if (pos == 1) - status.buff_ovrflw = 0; - break; + if (pos == 1) + status.buff_ovrflw = 0; + break; - case cmdSetStatus: - { - bool wasactive = status.is_active; - status.U8[pos ^ 1] = byte; + case cmdSetStatus: + { + bool wasactive = status.is_active; + status.U8[pos ^ 1] = byte; - // safe to do since these can only be entered if both bytes of status have been written - if (!wasactive && status.is_active) - { - sample_rate = rate_base << status.sample_rate; - buff_size = ring_base << status.buff_size; - buff_size_samples = buff_size / sample_size; + // safe to do since these can only be entered if both bytes of status have been written + if (!wasactive && status.is_active) + { + sample_rate = rate_base << status.sample_rate; + buff_size = ring_base << status.buff_size; + buff_size_samples = buff_size / sample_size; - UpdateNextInterruptTicks(); + UpdateNextInterruptTicks(); - StreamStart(); - } - else if (wasactive && !status.is_active) - { - StreamStop(); - } - } - break; + StreamStart(); + } + else if (wasactive && !status.is_active) + { + StreamStop(); + } + } + break; - case cmdGetBuffer: - { - if (ring_pos == 0) - StreamReadOne(); + case cmdGetBuffer: + { + if (ring_pos == 0) + StreamReadOne(); - byte = ring_buffer[ring_pos ^ 1]; - ring_pos = (ring_pos + 1) % buff_size; - } - break; + byte = ring_buffer[ring_pos ^ 1]; + ring_pos = (ring_pos + 1) % buff_size; + } + break; - default: - ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: unknown command byte %02x", command); - break; - } + default: + ERROR_LOG(EXPANSIONINTERFACE, "EXI MIC: unknown command byte %02x", command); + break; + } - m_position++; + m_position++; } #endif diff --git a/Source/Core/Core/HW/EXI_DeviceMic.h b/Source/Core/Core/HW/EXI_DeviceMic.h index e8adf97efb..2d6d94a926 100644 --- a/Source/Core/Core/HW/EXI_DeviceMic.h +++ b/Source/Core/Core/HW/EXI_DeviceMic.h @@ -13,97 +13,96 @@ class CEXIMic : public IEXIDevice { public: - CEXIMic(const int index); - virtual ~CEXIMic(); - void SetCS(int cs) override; - bool IsInterruptSet() override; - bool IsPresent() const override; + CEXIMic(const int index); + virtual ~CEXIMic(); + void SetCS(int cs) override; + bool IsInterruptSet() override; + bool IsPresent() const override; private: - static u8 const exi_id[]; - static int const sample_size = sizeof(s16); - static int const rate_base = 11025; - static int const ring_base = 32; + static u8 const exi_id[]; + static int const sample_size = sizeof(s16); + static int const rate_base = 11025; + static int const ring_base = 32; - enum - { - cmdID = 0x00, - cmdGetStatus = 0x40, - cmdSetStatus = 0x80, - cmdGetBuffer = 0x20, - cmdReset = 0xFF, - }; + enum + { + cmdID = 0x00, + cmdGetStatus = 0x40, + cmdSetStatus = 0x80, + cmdGetBuffer = 0x20, + cmdReset = 0xFF, + }; - int slot; + int slot; - u32 m_position; - int command; - union UStatus - { - u16 U16; - u8 U8[2]; - struct - { - u16 out : 4; // MICSet/GetOut...??? - u16 id : 1; // Used for MICGetDeviceID (always 0) - u16 button_unk : 3; // Button bits which appear unused - u16 button : 1; // The actual button on the mic - u16 buff_ovrflw : 1; // Ring buffer wrote over bytes which weren't read by console - u16 gain : 1; // Gain: 0dB or 15dB - u16 sample_rate : 2; // Sample rate, 00-11025, 01-22050, 10-44100, 11-?? - u16 buff_size : 2; // Ring buffer size in bytes, 00-32, 01-64, 10-128, 11-??? - u16 is_active : 1; // If we are sampling or not - }; - }; + u32 m_position; + int command; + union UStatus { + u16 U16; + u8 U8[2]; + struct + { + u16 out : 4; // MICSet/GetOut...??? + u16 id : 1; // Used for MICGetDeviceID (always 0) + u16 button_unk : 3; // Button bits which appear unused + u16 button : 1; // The actual button on the mic + u16 buff_ovrflw : 1; // Ring buffer wrote over bytes which weren't read by console + u16 gain : 1; // Gain: 0dB or 15dB + u16 sample_rate : 2; // Sample rate, 00-11025, 01-22050, 10-44100, 11-?? + u16 buff_size : 2; // Ring buffer size in bytes, 00-32, 01-64, 10-128, 11-??? + u16 is_active : 1; // If we are sampling or not + }; + }; - // 64 is the max size, can be 16 or 32 as well - int ring_pos; - u8 ring_buffer[64 * sample_size]; + // 64 is the max size, can be 16 or 32 as well + int ring_pos; + u8 ring_buffer[64 * sample_size]; - // 0 to disable interrupts, else it will be checked against current CPU ticks - // to determine if interrupt should be raised - u64 next_int_ticks; - void UpdateNextInterruptTicks(); + // 0 to disable interrupts, else it will be checked against current CPU ticks + // to determine if interrupt should be raised + u64 next_int_ticks; + void UpdateNextInterruptTicks(); - // Streaming input interface - int pa_error; // PaError - void *pa_stream; // PaStream + // Streaming input interface + int pa_error; // PaError + void* pa_stream; // PaStream - void StreamLog(const char *msg); - void StreamInit(); - void StreamTerminate(); - void StreamStart(); - void StreamStop(); - void StreamReadOne(); + void StreamLog(const char* msg); + void StreamInit(); + void StreamTerminate(); + void StreamStart(); + void StreamStop(); + void StreamReadOne(); public: - UStatus status; + UStatus status; - std::mutex ring_lock; + std::mutex ring_lock; - // status bits converted to nice numbers - int sample_rate; - int buff_size; - int buff_size_samples; + // status bits converted to nice numbers + int sample_rate; + int buff_size; + int buff_size_samples; - // Arbitrarily small ringbuffer used by audio input backend in order to - // keep delay tolerable - s16 *stream_buffer; - int stream_size; - int stream_wpos; - int stream_rpos; - int samples_avail; + // Arbitrarily small ringbuffer used by audio input backend in order to + // keep delay tolerable + s16* stream_buffer; + int stream_size; + int stream_wpos; + int stream_rpos; + int samples_avail; protected: - void TransferByte(u8& byte) override; + void TransferByte(u8& byte) override; }; -#else // HAVE_PORTAUDIO +#else // HAVE_PORTAUDIO class CEXIMic : public IEXIDevice { public: - CEXIMic(const int) {} + CEXIMic(const int) {} }; #endif diff --git a/Source/Core/Core/HW/GCKeyboard.cpp b/Source/Core/Core/HW/GCKeyboard.cpp index 2605c48610..a306dc06a0 100644 --- a/Source/Core/Core/HW/GCKeyboard.cpp +++ b/Source/Core/Core/HW/GCKeyboard.cpp @@ -8,52 +8,50 @@ #include "Common/CommonTypes.h" #include "Core/HW/GCKeyboard.h" #include "Core/HW/GCKeyboardEmu.h" +#include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/InputConfig.h" #include "InputCommon/KeyboardStatus.h" -#include "InputCommon/ControllerInterface/ControllerInterface.h" namespace Keyboard { - static InputConfig s_config("GCKeyNew", _trans("Keyboard"), "GCKey"); InputConfig* GetConfig() { - return &s_config; + return &s_config; } void Shutdown() { - s_config.ClearControllers(); + s_config.ClearControllers(); - g_controller_interface.Shutdown(); + g_controller_interface.Shutdown(); } void Initialize(void* const hwnd) { - if (s_config.ControllersNeedToBeCreated()) - { - for (unsigned int i = 0; i < 4; ++i) - s_config.CreateController(i); - } + if (s_config.ControllersNeedToBeCreated()) + { + for (unsigned int i = 0; i < 4; ++i) + s_config.CreateController(i); + } - g_controller_interface.Initialize(hwnd); + g_controller_interface.Initialize(hwnd); - // Load the saved controller config - s_config.LoadConfig(true); + // Load the saved controller config + s_config.LoadConfig(true); } void LoadConfig() { - s_config.LoadConfig(true); + s_config.LoadConfig(true); } void GetStatus(u8 port, KeyboardStatus* keyboard_status) { - memset(keyboard_status, 0, sizeof(*keyboard_status)); - keyboard_status->err = PAD_ERR_NONE; + memset(keyboard_status, 0, sizeof(*keyboard_status)); + keyboard_status->err = PAD_ERR_NONE; - // Get input - static_cast(s_config.GetController(port))->GetInput(keyboard_status); + // Get input + static_cast(s_config.GetController(port))->GetInput(keyboard_status); } - } diff --git a/Source/Core/Core/HW/GCKeyboard.h b/Source/Core/Core/HW/GCKeyboard.h index 8bf89fc1d4..56709a259e 100644 --- a/Source/Core/Core/HW/GCKeyboard.h +++ b/Source/Core/Core/HW/GCKeyboard.h @@ -11,7 +11,6 @@ struct KeyboardStatus; namespace Keyboard { - void Shutdown(); void Initialize(void* const hwnd); void LoadConfig(); @@ -19,5 +18,4 @@ void LoadConfig(); InputConfig* GetConfig(); void GetStatus(u8 port, KeyboardStatus* keyboard_status); - } diff --git a/Source/Core/Core/HW/GCKeyboardEmu.cpp b/Source/Core/Core/HW/GCKeyboardEmu.cpp index 7bff11e119..e910e907be 100644 --- a/Source/Core/Core/HW/GCKeyboardEmu.cpp +++ b/Source/Core/Core/HW/GCKeyboardEmu.cpp @@ -2,446 +2,275 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Common/Common.h" #include "Core/HW/GCKeyboardEmu.h" +#include "Common/Common.h" #include "InputCommon/KeyboardStatus.h" -static const u16 keys0_bitmasks[] = -{ - KEYMASK_HOME, - KEYMASK_END, - KEYMASK_PGUP, - KEYMASK_PGDN, - KEYMASK_SCROLLLOCK, - KEYMASK_A, - KEYMASK_B, - KEYMASK_C, - KEYMASK_D, - KEYMASK_E, - KEYMASK_F, - KEYMASK_G, - KEYMASK_H, - KEYMASK_I, - KEYMASK_J, - KEYMASK_K -}; -static const u16 keys1_bitmasks[] = -{ - KEYMASK_L, - KEYMASK_M, - KEYMASK_N, - KEYMASK_O, - KEYMASK_P, - KEYMASK_Q, - KEYMASK_R, - KEYMASK_S, - KEYMASK_T, - KEYMASK_U, - KEYMASK_V, - KEYMASK_W, - KEYMASK_X, - KEYMASK_Y, - KEYMASK_Z, - KEYMASK_1 -}; -static const u16 keys2_bitmasks[] = -{ - KEYMASK_2, - KEYMASK_3, - KEYMASK_4, - KEYMASK_5, - KEYMASK_6, - KEYMASK_7, - KEYMASK_8, - KEYMASK_9, - KEYMASK_0, - KEYMASK_MINUS, - KEYMASK_PLUS, - KEYMASK_PRINTSCR, - KEYMASK_BRACE_OPEN, - KEYMASK_BRACE_CLOSE, - KEYMASK_COLON, - KEYMASK_QUOTE -}; -static const u16 keys3_bitmasks[] = -{ - KEYMASK_HASH, - KEYMASK_COMMA, - KEYMASK_PERIOD, - KEYMASK_QUESTIONMARK, - KEYMASK_INTERNATIONAL1, - KEYMASK_F1, - KEYMASK_F2, - KEYMASK_F3, - KEYMASK_F4, - KEYMASK_F5, - KEYMASK_F6, - KEYMASK_F7, - KEYMASK_F8, - KEYMASK_F9, - KEYMASK_F10, - KEYMASK_F11 -}; -static const u16 keys4_bitmasks[] = -{ - KEYMASK_F12, - KEYMASK_ESC, - KEYMASK_INSERT, - KEYMASK_DELETE, - KEYMASK_TILDE, - KEYMASK_BACKSPACE, - KEYMASK_TAB, - KEYMASK_CAPSLOCK, - KEYMASK_LEFTSHIFT, - KEYMASK_RIGHTSHIFT, - KEYMASK_LEFTCONTROL, - KEYMASK_RIGHTALT, - KEYMASK_LEFTWINDOWS, - KEYMASK_SPACE, - KEYMASK_RIGHTWINDOWS, - KEYMASK_MENU -}; -static const u16 keys5_bitmasks[] = -{ - KEYMASK_LEFTARROW, - KEYMASK_DOWNARROW, - KEYMASK_UPARROW, - KEYMASK_RIGHTARROW, - KEYMASK_ENTER -}; +static const u16 keys0_bitmasks[] = {KEYMASK_HOME, KEYMASK_END, KEYMASK_PGUP, KEYMASK_PGDN, + KEYMASK_SCROLLLOCK, KEYMASK_A, KEYMASK_B, KEYMASK_C, + KEYMASK_D, KEYMASK_E, KEYMASK_F, KEYMASK_G, + KEYMASK_H, KEYMASK_I, KEYMASK_J, KEYMASK_K}; +static const u16 keys1_bitmasks[] = { + KEYMASK_L, KEYMASK_M, KEYMASK_N, KEYMASK_O, KEYMASK_P, KEYMASK_Q, KEYMASK_R, KEYMASK_S, + KEYMASK_T, KEYMASK_U, KEYMASK_V, KEYMASK_W, KEYMASK_X, KEYMASK_Y, KEYMASK_Z, KEYMASK_1}; +static const u16 keys2_bitmasks[] = { + KEYMASK_2, KEYMASK_3, KEYMASK_4, KEYMASK_5, + KEYMASK_6, KEYMASK_7, KEYMASK_8, KEYMASK_9, + KEYMASK_0, KEYMASK_MINUS, KEYMASK_PLUS, KEYMASK_PRINTSCR, + KEYMASK_BRACE_OPEN, KEYMASK_BRACE_CLOSE, KEYMASK_COLON, KEYMASK_QUOTE}; +static const u16 keys3_bitmasks[] = { + KEYMASK_HASH, KEYMASK_COMMA, KEYMASK_PERIOD, KEYMASK_QUESTIONMARK, KEYMASK_INTERNATIONAL1, + KEYMASK_F1, KEYMASK_F2, KEYMASK_F3, KEYMASK_F4, KEYMASK_F5, + KEYMASK_F6, KEYMASK_F7, KEYMASK_F8, KEYMASK_F9, KEYMASK_F10, + KEYMASK_F11}; +static const u16 keys4_bitmasks[] = { + KEYMASK_F12, KEYMASK_ESC, KEYMASK_INSERT, KEYMASK_DELETE, + KEYMASK_TILDE, KEYMASK_BACKSPACE, KEYMASK_TAB, KEYMASK_CAPSLOCK, + KEYMASK_LEFTSHIFT, KEYMASK_RIGHTSHIFT, KEYMASK_LEFTCONTROL, KEYMASK_RIGHTALT, + KEYMASK_LEFTWINDOWS, KEYMASK_SPACE, KEYMASK_RIGHTWINDOWS, KEYMASK_MENU}; +static const u16 keys5_bitmasks[] = {KEYMASK_LEFTARROW, KEYMASK_DOWNARROW, KEYMASK_UPARROW, + KEYMASK_RIGHTARROW, KEYMASK_ENTER}; -static const char* const named_keys0[] = -{ - "HOME", - "END", - "PGUP", - "PGDN", - "SCR LK", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K" -}; -static const char* const named_keys1[] = -{ - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "1" -}; -static const char* const named_keys2[] = -{ - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "0", - "-", - "`", - "PRT SC", - "'", - "[", - "EQUALS", - "*" -}; -static const char* const named_keys3[] = -{ - "]", - ",", - ".", - "/", - "\\", - "F1", - "F2", - "F3", - "F4", - "F5", - "F6", - "F7", - "F8", - "F9", - "F10", - "F11" -}; -static const char* const named_keys4[] = -{ - "F12", - "ESC", - "INSERT", - "DELETE", - ";", - "BACKSPACE", - "TAB", - "CAPS LOCK", - "L SHIFT", - "R SHIFT", - "L CTRL", - "R ALT", - "L WIN", - "SPACE", - "R WIN", - "MENU" -}; -static const char* const named_keys5[] = -{ - "LEFT", - "DOWN", - "UP", - "RIGHT", - "ENTER" -}; +static const char* const named_keys0[] = {"HOME", "END", "PGUP", "PGDN", "SCR LK", "A", "B", "C", + "D", "E", "F", "G", "H", "I", "J", "K"}; +static const char* const named_keys1[] = {"L", "M", "N", "O", "P", "Q", "R", "S", + "T", "U", "V", "W", "X", "Y", "Z", "1"}; +static const char* const named_keys2[] = {"2", "3", "4", "5", "6", "7", "8", "9", + "0", "-", "`", "PRT SC", "'", "[", "EQUALS", "*"}; +static const char* const named_keys3[] = {"]", ",", ".", "/", "\\", "F1", "F2", "F3", + "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11"}; +static const char* const named_keys4[] = { + "F12", "ESC", "INSERT", "DELETE", ";", "BACKSPACE", "TAB", "CAPS LOCK", + "L SHIFT", "R SHIFT", "L CTRL", "R ALT", "L WIN", "SPACE", "R WIN", "MENU"}; +static const char* const named_keys5[] = {"LEFT", "DOWN", "UP", "RIGHT", "ENTER"}; GCKeyboard::GCKeyboard(const unsigned int index) : m_index(index) { - // buttons - groups.emplace_back(m_keys0x = new Buttons(_trans("Keys"))); - for (const char* key : named_keys0) - m_keys0x->controls.emplace_back(new ControlGroup::Input(key)); + // buttons + groups.emplace_back(m_keys0x = new Buttons(_trans("Keys"))); + for (const char* key : named_keys0) + m_keys0x->controls.emplace_back(new ControlGroup::Input(key)); - groups.emplace_back(m_keys1x = new Buttons(_trans("Keys"))); - for (const char* key : named_keys1) - m_keys1x->controls.emplace_back(new ControlGroup::Input(key)); + groups.emplace_back(m_keys1x = new Buttons(_trans("Keys"))); + for (const char* key : named_keys1) + m_keys1x->controls.emplace_back(new ControlGroup::Input(key)); - groups.emplace_back(m_keys2x = new Buttons(_trans("Keys"))); - for (const char* key : named_keys2) - m_keys2x->controls.emplace_back(new ControlGroup::Input(key)); + groups.emplace_back(m_keys2x = new Buttons(_trans("Keys"))); + for (const char* key : named_keys2) + m_keys2x->controls.emplace_back(new ControlGroup::Input(key)); - groups.emplace_back(m_keys3x = new Buttons(_trans("Keys"))); - for (const char* key : named_keys3) - m_keys3x->controls.emplace_back(new ControlGroup::Input(key)); + groups.emplace_back(m_keys3x = new Buttons(_trans("Keys"))); + for (const char* key : named_keys3) + m_keys3x->controls.emplace_back(new ControlGroup::Input(key)); - groups.emplace_back(m_keys4x = new Buttons(_trans("Keys"))); - for (const char* key : named_keys4) - m_keys4x->controls.emplace_back(new ControlGroup::Input(key)); + groups.emplace_back(m_keys4x = new Buttons(_trans("Keys"))); + for (const char* key : named_keys4) + m_keys4x->controls.emplace_back(new ControlGroup::Input(key)); - groups.emplace_back(m_keys5x = new Buttons(_trans("Keys"))); - for (const char* key : named_keys5) - m_keys5x->controls.emplace_back(new ControlGroup::Input(key)); + groups.emplace_back(m_keys5x = new Buttons(_trans("Keys"))); + for (const char* key : named_keys5) + m_keys5x->controls.emplace_back(new ControlGroup::Input(key)); - - // options - groups.emplace_back(m_options = new ControlGroup(_trans("Options"))); - m_options->settings.emplace_back(new ControlGroup::BackgroundInputSetting(_trans("Background Input"))); - m_options->settings.emplace_back(new ControlGroup::IterateUI(_trans("Iterative Input"))); + // options + groups.emplace_back(m_options = new ControlGroup(_trans("Options"))); + m_options->settings.emplace_back( + new ControlGroup::BackgroundInputSetting(_trans("Background Input"))); + m_options->settings.emplace_back(new ControlGroup::IterateUI(_trans("Iterative Input"))); } std::string GCKeyboard::GetName() const { - return std::string("GCKeyboard") + char('1' + m_index); + return std::string("GCKeyboard") + char('1' + m_index); } void GCKeyboard::GetInput(KeyboardStatus* const kb) { - m_keys0x->GetState(&kb->key0x, keys0_bitmasks); - m_keys1x->GetState(&kb->key1x, keys1_bitmasks); - m_keys2x->GetState(&kb->key2x, keys2_bitmasks); - m_keys3x->GetState(&kb->key3x, keys3_bitmasks); - m_keys4x->GetState(&kb->key4x, keys4_bitmasks); - m_keys5x->GetState(&kb->key5x, keys5_bitmasks); + m_keys0x->GetState(&kb->key0x, keys0_bitmasks); + m_keys1x->GetState(&kb->key1x, keys1_bitmasks); + m_keys2x->GetState(&kb->key2x, keys2_bitmasks); + m_keys3x->GetState(&kb->key3x, keys3_bitmasks); + m_keys4x->GetState(&kb->key4x, keys4_bitmasks); + m_keys5x->GetState(&kb->key5x, keys5_bitmasks); } void GCKeyboard::LoadDefaults(const ControllerInterface& ciface) { - ControllerEmu::LoadDefaults(ciface); + ControllerEmu::LoadDefaults(ciface); - // Buttons - m_keys0x->SetControlExpression(5, "A"); - m_keys0x->SetControlExpression(6, "B"); - m_keys0x->SetControlExpression(7, "C"); - m_keys0x->SetControlExpression(8, "D"); - m_keys0x->SetControlExpression(9, "E"); - m_keys0x->SetControlExpression(10, "F"); - m_keys0x->SetControlExpression(11, "G"); - m_keys0x->SetControlExpression(12, "H"); - m_keys0x->SetControlExpression(13, "I"); - m_keys0x->SetControlExpression(14, "J"); - m_keys0x->SetControlExpression(15, "K"); - m_keys1x->SetControlExpression(0, "L"); - m_keys1x->SetControlExpression(1, "M"); - m_keys1x->SetControlExpression(2, "N"); - m_keys1x->SetControlExpression(3, "O"); - m_keys1x->SetControlExpression(4, "P"); - m_keys1x->SetControlExpression(5, "Q"); - m_keys1x->SetControlExpression(6, "R"); - m_keys1x->SetControlExpression(7, "S"); - m_keys1x->SetControlExpression(8, "T"); - m_keys1x->SetControlExpression(9, "U"); - m_keys1x->SetControlExpression(10, "V"); - m_keys1x->SetControlExpression(11, "W"); - m_keys1x->SetControlExpression(12, "X"); - m_keys1x->SetControlExpression(13, "Y"); - m_keys1x->SetControlExpression(14, "Z"); + // Buttons + m_keys0x->SetControlExpression(5, "A"); + m_keys0x->SetControlExpression(6, "B"); + m_keys0x->SetControlExpression(7, "C"); + m_keys0x->SetControlExpression(8, "D"); + m_keys0x->SetControlExpression(9, "E"); + m_keys0x->SetControlExpression(10, "F"); + m_keys0x->SetControlExpression(11, "G"); + m_keys0x->SetControlExpression(12, "H"); + m_keys0x->SetControlExpression(13, "I"); + m_keys0x->SetControlExpression(14, "J"); + m_keys0x->SetControlExpression(15, "K"); + m_keys1x->SetControlExpression(0, "L"); + m_keys1x->SetControlExpression(1, "M"); + m_keys1x->SetControlExpression(2, "N"); + m_keys1x->SetControlExpression(3, "O"); + m_keys1x->SetControlExpression(4, "P"); + m_keys1x->SetControlExpression(5, "Q"); + m_keys1x->SetControlExpression(6, "R"); + m_keys1x->SetControlExpression(7, "S"); + m_keys1x->SetControlExpression(8, "T"); + m_keys1x->SetControlExpression(9, "U"); + m_keys1x->SetControlExpression(10, "V"); + m_keys1x->SetControlExpression(11, "W"); + m_keys1x->SetControlExpression(12, "X"); + m_keys1x->SetControlExpression(13, "Y"); + m_keys1x->SetControlExpression(14, "Z"); - m_keys1x->SetControlExpression(15, "1"); - m_keys2x->SetControlExpression(0, "2"); - m_keys2x->SetControlExpression(1, "3"); - m_keys2x->SetControlExpression(2, "4"); - m_keys2x->SetControlExpression(3, "5"); - m_keys2x->SetControlExpression(4, "6"); - m_keys2x->SetControlExpression(5, "7"); - m_keys2x->SetControlExpression(6, "8"); - m_keys2x->SetControlExpression(7, "9"); - m_keys2x->SetControlExpression(8, "0"); + m_keys1x->SetControlExpression(15, "1"); + m_keys2x->SetControlExpression(0, "2"); + m_keys2x->SetControlExpression(1, "3"); + m_keys2x->SetControlExpression(2, "4"); + m_keys2x->SetControlExpression(3, "5"); + m_keys2x->SetControlExpression(4, "6"); + m_keys2x->SetControlExpression(5, "7"); + m_keys2x->SetControlExpression(6, "8"); + m_keys2x->SetControlExpression(7, "9"); + m_keys2x->SetControlExpression(8, "0"); - m_keys3x->SetControlExpression(5, "F1"); - m_keys3x->SetControlExpression(6, "F2"); - m_keys3x->SetControlExpression(7, "F3"); - m_keys3x->SetControlExpression(8, "F4"); - m_keys3x->SetControlExpression(9, "F5"); - m_keys3x->SetControlExpression(10, "F6"); - m_keys3x->SetControlExpression(11, "F7"); - m_keys3x->SetControlExpression(12, "F8"); - m_keys3x->SetControlExpression(13, "F9"); - m_keys3x->SetControlExpression(14, "F10"); - m_keys3x->SetControlExpression(15, "F11"); - m_keys4x->SetControlExpression(0, "F12"); + m_keys3x->SetControlExpression(5, "F1"); + m_keys3x->SetControlExpression(6, "F2"); + m_keys3x->SetControlExpression(7, "F3"); + m_keys3x->SetControlExpression(8, "F4"); + m_keys3x->SetControlExpression(9, "F5"); + m_keys3x->SetControlExpression(10, "F6"); + m_keys3x->SetControlExpression(11, "F7"); + m_keys3x->SetControlExpression(12, "F8"); + m_keys3x->SetControlExpression(13, "F9"); + m_keys3x->SetControlExpression(14, "F10"); + m_keys3x->SetControlExpression(15, "F11"); + m_keys4x->SetControlExpression(0, "F12"); #ifdef _WIN32 - m_keys0x->SetControlExpression(0, "HOME"); - m_keys0x->SetControlExpression(1, "END"); - m_keys0x->SetControlExpression(2, "PRIOR"); - m_keys0x->SetControlExpression(3, "NEXT"); - m_keys0x->SetControlExpression(4, "SCROLL"); + m_keys0x->SetControlExpression(0, "HOME"); + m_keys0x->SetControlExpression(1, "END"); + m_keys0x->SetControlExpression(2, "PRIOR"); + m_keys0x->SetControlExpression(3, "NEXT"); + m_keys0x->SetControlExpression(4, "SCROLL"); - m_keys2x->SetControlExpression(9, "MINUS"); - m_keys2x->SetControlExpression(10, "GRAVE"); - m_keys2x->SetControlExpression(11, "SYSRQ"); - m_keys2x->SetControlExpression(12, "APOSTROPHE"); - m_keys2x->SetControlExpression(13, "LBRACKET"); - m_keys2x->SetControlExpression(14, "EQUALS"); - m_keys2x->SetControlExpression(15, "MULTIPLY"); - m_keys3x->SetControlExpression(0, "RBRACKET"); - m_keys3x->SetControlExpression(1, "COMMA"); - m_keys3x->SetControlExpression(2, "PERIOD"); - m_keys3x->SetControlExpression(3, "SLASH"); - m_keys3x->SetControlExpression(4, "BACKSLASH"); + m_keys2x->SetControlExpression(9, "MINUS"); + m_keys2x->SetControlExpression(10, "GRAVE"); + m_keys2x->SetControlExpression(11, "SYSRQ"); + m_keys2x->SetControlExpression(12, "APOSTROPHE"); + m_keys2x->SetControlExpression(13, "LBRACKET"); + m_keys2x->SetControlExpression(14, "EQUALS"); + m_keys2x->SetControlExpression(15, "MULTIPLY"); + m_keys3x->SetControlExpression(0, "RBRACKET"); + m_keys3x->SetControlExpression(1, "COMMA"); + m_keys3x->SetControlExpression(2, "PERIOD"); + m_keys3x->SetControlExpression(3, "SLASH"); + m_keys3x->SetControlExpression(4, "BACKSLASH"); - m_keys4x->SetControlExpression(1, "ESCAPE"); - m_keys4x->SetControlExpression(2, "INSERT"); - m_keys4x->SetControlExpression(3, "DELETE"); - m_keys4x->SetControlExpression(4, "SEMICOLON"); - m_keys4x->SetControlExpression(5, "BACK"); - m_keys4x->SetControlExpression(6, "TAB"); - m_keys4x->SetControlExpression(7, "CAPITAL"); - m_keys4x->SetControlExpression(8, "LSHIFT"); - m_keys4x->SetControlExpression(9, "RSHIFT"); - m_keys4x->SetControlExpression(10, "LCONTROL"); - m_keys4x->SetControlExpression(11, "RMENU"); - m_keys4x->SetControlExpression(12, "LWIN"); - m_keys4x->SetControlExpression(13, "SPACE"); - m_keys4x->SetControlExpression(14, "RWIN"); - m_keys4x->SetControlExpression(15, "MENU"); + m_keys4x->SetControlExpression(1, "ESCAPE"); + m_keys4x->SetControlExpression(2, "INSERT"); + m_keys4x->SetControlExpression(3, "DELETE"); + m_keys4x->SetControlExpression(4, "SEMICOLON"); + m_keys4x->SetControlExpression(5, "BACK"); + m_keys4x->SetControlExpression(6, "TAB"); + m_keys4x->SetControlExpression(7, "CAPITAL"); + m_keys4x->SetControlExpression(8, "LSHIFT"); + m_keys4x->SetControlExpression(9, "RSHIFT"); + m_keys4x->SetControlExpression(10, "LCONTROL"); + m_keys4x->SetControlExpression(11, "RMENU"); + m_keys4x->SetControlExpression(12, "LWIN"); + m_keys4x->SetControlExpression(13, "SPACE"); + m_keys4x->SetControlExpression(14, "RWIN"); + m_keys4x->SetControlExpression(15, "MENU"); - m_keys5x->SetControlExpression(0, "LEFT"); - m_keys5x->SetControlExpression(1, "DOWN"); - m_keys5x->SetControlExpression(2, "UP"); - m_keys5x->SetControlExpression(3, "RIGHT"); - m_keys5x->SetControlExpression(4, "RETURN"); + m_keys5x->SetControlExpression(0, "LEFT"); + m_keys5x->SetControlExpression(1, "DOWN"); + m_keys5x->SetControlExpression(2, "UP"); + m_keys5x->SetControlExpression(3, "RIGHT"); + m_keys5x->SetControlExpression(4, "RETURN"); #elif __APPLE__ - m_keys0x->SetControlExpression(0, "Home"); - m_keys0x->SetControlExpression(1, "End"); - m_keys0x->SetControlExpression(2, "Page Up"); - m_keys0x->SetControlExpression(3, "Page Down"); - m_keys0x->SetControlExpression(4, ""); // Scroll lock + m_keys0x->SetControlExpression(0, "Home"); + m_keys0x->SetControlExpression(1, "End"); + m_keys0x->SetControlExpression(2, "Page Up"); + m_keys0x->SetControlExpression(3, "Page Down"); + m_keys0x->SetControlExpression(4, ""); // Scroll lock - m_keys2x->SetControlExpression(9, "-"); - m_keys2x->SetControlExpression(10, "Paragraph"); - m_keys2x->SetControlExpression(11, ""); // Print Scr - m_keys2x->SetControlExpression(12, "'"); - m_keys2x->SetControlExpression(13, "["); - m_keys2x->SetControlExpression(14, "="); - m_keys2x->SetControlExpression(15, "Keypad *"); - m_keys3x->SetControlExpression(0, "]"); - m_keys3x->SetControlExpression(1, ","); - m_keys3x->SetControlExpression(2, "."); - m_keys3x->SetControlExpression(3, "/"); - m_keys3x->SetControlExpression(4, "\\"); + m_keys2x->SetControlExpression(9, "-"); + m_keys2x->SetControlExpression(10, "Paragraph"); + m_keys2x->SetControlExpression(11, ""); // Print Scr + m_keys2x->SetControlExpression(12, "'"); + m_keys2x->SetControlExpression(13, "["); + m_keys2x->SetControlExpression(14, "="); + m_keys2x->SetControlExpression(15, "Keypad *"); + m_keys3x->SetControlExpression(0, "]"); + m_keys3x->SetControlExpression(1, ","); + m_keys3x->SetControlExpression(2, "."); + m_keys3x->SetControlExpression(3, "/"); + m_keys3x->SetControlExpression(4, "\\"); - m_keys4x->SetControlExpression(1, "Escape"); - m_keys4x->SetControlExpression(2, "Insert"); - m_keys4x->SetControlExpression(3, "Delete"); - m_keys4x->SetControlExpression(4, ";"); - m_keys4x->SetControlExpression(5, "Backspace"); - m_keys4x->SetControlExpression(6, "Tab"); - m_keys4x->SetControlExpression(7, "Caps Lock"); - m_keys4x->SetControlExpression(8, "Left Shift"); - m_keys4x->SetControlExpression(9, "Right Shift"); - m_keys4x->SetControlExpression(10, "Left Control"); - m_keys4x->SetControlExpression(11, "Right Alt"); - m_keys4x->SetControlExpression(12, "Left Command"); - m_keys4x->SetControlExpression(13, "Space"); - m_keys4x->SetControlExpression(14, "Right Command"); - m_keys4x->SetControlExpression(15, ""); // Menu + m_keys4x->SetControlExpression(1, "Escape"); + m_keys4x->SetControlExpression(2, "Insert"); + m_keys4x->SetControlExpression(3, "Delete"); + m_keys4x->SetControlExpression(4, ";"); + m_keys4x->SetControlExpression(5, "Backspace"); + m_keys4x->SetControlExpression(6, "Tab"); + m_keys4x->SetControlExpression(7, "Caps Lock"); + m_keys4x->SetControlExpression(8, "Left Shift"); + m_keys4x->SetControlExpression(9, "Right Shift"); + m_keys4x->SetControlExpression(10, "Left Control"); + m_keys4x->SetControlExpression(11, "Right Alt"); + m_keys4x->SetControlExpression(12, "Left Command"); + m_keys4x->SetControlExpression(13, "Space"); + m_keys4x->SetControlExpression(14, "Right Command"); + m_keys4x->SetControlExpression(15, ""); // Menu - m_keys5x->SetControlExpression(0, "Left Arrow"); - m_keys5x->SetControlExpression(1, "Down Arrow"); - m_keys5x->SetControlExpression(2, "Up Arrow"); - m_keys5x->SetControlExpression(3, "Right Arrow"); - m_keys5x->SetControlExpression(4, "Return"); -#else // linux - m_keys0x->SetControlExpression(0, "Home"); - m_keys0x->SetControlExpression(1, "End"); - m_keys0x->SetControlExpression(2, "Prior"); - m_keys0x->SetControlExpression(3, "Next"); - m_keys0x->SetControlExpression(4, "Scroll_Lock"); + m_keys5x->SetControlExpression(0, "Left Arrow"); + m_keys5x->SetControlExpression(1, "Down Arrow"); + m_keys5x->SetControlExpression(2, "Up Arrow"); + m_keys5x->SetControlExpression(3, "Right Arrow"); + m_keys5x->SetControlExpression(4, "Return"); +#else // linux + m_keys0x->SetControlExpression(0, "Home"); + m_keys0x->SetControlExpression(1, "End"); + m_keys0x->SetControlExpression(2, "Prior"); + m_keys0x->SetControlExpression(3, "Next"); + m_keys0x->SetControlExpression(4, "Scroll_Lock"); - m_keys2x->SetControlExpression(9, "minus"); - m_keys2x->SetControlExpression(10, "grave"); - m_keys2x->SetControlExpression(11, "Print"); - m_keys2x->SetControlExpression(12, "apostrophe"); - m_keys2x->SetControlExpression(13, "bracketleft"); - m_keys2x->SetControlExpression(14, "equal"); - m_keys2x->SetControlExpression(15, "KP_Multiply"); - m_keys3x->SetControlExpression(0, "bracketright"); - m_keys3x->SetControlExpression(1, "comma"); - m_keys3x->SetControlExpression(2, "period"); - m_keys3x->SetControlExpression(3, "slash"); - m_keys3x->SetControlExpression(4, "backslash"); + m_keys2x->SetControlExpression(9, "minus"); + m_keys2x->SetControlExpression(10, "grave"); + m_keys2x->SetControlExpression(11, "Print"); + m_keys2x->SetControlExpression(12, "apostrophe"); + m_keys2x->SetControlExpression(13, "bracketleft"); + m_keys2x->SetControlExpression(14, "equal"); + m_keys2x->SetControlExpression(15, "KP_Multiply"); + m_keys3x->SetControlExpression(0, "bracketright"); + m_keys3x->SetControlExpression(1, "comma"); + m_keys3x->SetControlExpression(2, "period"); + m_keys3x->SetControlExpression(3, "slash"); + m_keys3x->SetControlExpression(4, "backslash"); - m_keys4x->SetControlExpression(1, "Escape"); - m_keys4x->SetControlExpression(2, "Insert"); - m_keys4x->SetControlExpression(3, "Delete"); - m_keys4x->SetControlExpression(4, "semicolon"); - m_keys4x->SetControlExpression(5, "BackSpace"); - m_keys4x->SetControlExpression(6, "Tab"); - m_keys4x->SetControlExpression(7, "Caps_Lock"); - m_keys4x->SetControlExpression(8, "Shift_L"); - m_keys4x->SetControlExpression(9, "Shift_R"); - m_keys4x->SetControlExpression(10, "Control_L"); - m_keys4x->SetControlExpression(11, "Alt_R"); - m_keys4x->SetControlExpression(12, "Super_L"); - m_keys4x->SetControlExpression(13, "space"); - m_keys4x->SetControlExpression(14, "Super_R"); - m_keys4x->SetControlExpression(15, "Menu"); + m_keys4x->SetControlExpression(1, "Escape"); + m_keys4x->SetControlExpression(2, "Insert"); + m_keys4x->SetControlExpression(3, "Delete"); + m_keys4x->SetControlExpression(4, "semicolon"); + m_keys4x->SetControlExpression(5, "BackSpace"); + m_keys4x->SetControlExpression(6, "Tab"); + m_keys4x->SetControlExpression(7, "Caps_Lock"); + m_keys4x->SetControlExpression(8, "Shift_L"); + m_keys4x->SetControlExpression(9, "Shift_R"); + m_keys4x->SetControlExpression(10, "Control_L"); + m_keys4x->SetControlExpression(11, "Alt_R"); + m_keys4x->SetControlExpression(12, "Super_L"); + m_keys4x->SetControlExpression(13, "space"); + m_keys4x->SetControlExpression(14, "Super_R"); + m_keys4x->SetControlExpression(15, "Menu"); - m_keys5x->SetControlExpression(0, "Left"); - m_keys5x->SetControlExpression(1, "Down"); - m_keys5x->SetControlExpression(2, "Up"); - m_keys5x->SetControlExpression(3, "Right"); - m_keys5x->SetControlExpression(4, "Return"); + m_keys5x->SetControlExpression(0, "Left"); + m_keys5x->SetControlExpression(1, "Down"); + m_keys5x->SetControlExpression(2, "Up"); + m_keys5x->SetControlExpression(3, "Right"); + m_keys5x->SetControlExpression(4, "Return"); #endif - } diff --git a/Source/Core/Core/HW/GCKeyboardEmu.h b/Source/Core/Core/HW/GCKeyboardEmu.h index 4c8c85194b..3f41659a1f 100644 --- a/Source/Core/Core/HW/GCKeyboardEmu.h +++ b/Source/Core/Core/HW/GCKeyboardEmu.h @@ -13,21 +13,19 @@ struct KeyboardStatus; class GCKeyboard : public ControllerEmu { public: - - GCKeyboard(const unsigned int index); - void GetInput(KeyboardStatus* const pad); - std::string GetName() const override; - void LoadDefaults(const ControllerInterface& ciface) override; + GCKeyboard(const unsigned int index); + void GetInput(KeyboardStatus* const pad); + std::string GetName() const override; + void LoadDefaults(const ControllerInterface& ciface) override; private: + Buttons* m_keys0x; + Buttons* m_keys1x; + Buttons* m_keys2x; + Buttons* m_keys3x; + Buttons* m_keys4x; + Buttons* m_keys5x; + ControlGroup* m_options; - Buttons* m_keys0x; - Buttons* m_keys1x; - Buttons* m_keys2x; - Buttons* m_keys3x; - Buttons* m_keys4x; - Buttons* m_keys5x; - ControlGroup* m_options; - - const unsigned int m_index; + const unsigned int m_index; }; diff --git a/Source/Core/Core/HW/GCMemcard.cpp b/Source/Core/Core/HW/GCMemcard.cpp index 658aa82f05..4168e7285d 100644 --- a/Source/Core/Core/HW/GCMemcard.cpp +++ b/Source/Core/Core/HW/GCMemcard.cpp @@ -15,368 +15,372 @@ #include "Common/StringUtil.h" #include "Core/HW/GCMemcard.h" -static void ByteSwap(u8 *valueA, u8 *valueB) +static void ByteSwap(u8* valueA, u8* valueB) { - u8 tmp = *valueA; - *valueA = *valueB; - *valueB = tmp; + u8 tmp = *valueA; + *valueA = *valueB; + *valueB = tmp; } -GCMemcard::GCMemcard(const std::string &filename, bool forceCreation, bool ascii) - : m_valid(false) - , m_fileName(filename) +GCMemcard::GCMemcard(const std::string& filename, bool forceCreation, bool ascii) + : m_valid(false), m_fileName(filename) { - // Currently there is a string freeze. instead of adding a new message about needing r/w - // open file read only, if write is denied the error will be reported at that point - File::IOFile mcdFile(m_fileName, "rb"); - if (!mcdFile.IsOpen()) - { - if (!forceCreation) - { - if (!AskYesNoT("\"%s\" does not exist.\n Create a new 16MB Memcard?", filename.c_str())) - return; - ascii = AskYesNoT("Format as ASCII (NTSC\\PAL)?\nChoose no for Shift JIS (NTSC-J)"); - } - Format(ascii); - return; - } - else - { - //This function can be removed once more about hdr is known and we can check for a valid header - std::string fileType; - SplitPath(filename, nullptr, nullptr, &fileType); - if (strcasecmp(fileType.c_str(), ".raw") && strcasecmp(fileType.c_str(), ".gcp")) - { - PanicAlertT("File has the extension \"%s\".\nValid extensions are (.raw/.gcp)", fileType.c_str()); - return; - } - auto size = mcdFile.GetSize(); - if (size < MC_FST_BLOCKS*BLOCK_SIZE) - { - PanicAlertT("%s failed to load as a memory card.\nFile is not large enough to be a valid memory card file (0x%x bytes)", filename.c_str(), (unsigned) size); - return; - } - if (size % BLOCK_SIZE) - { - PanicAlertT("%s failed to load as a memory card.\nCard file size is invalid (0x%x bytes)", filename.c_str(), (unsigned) size); - return; - } + // Currently there is a string freeze. instead of adding a new message about needing r/w + // open file read only, if write is denied the error will be reported at that point + File::IOFile mcdFile(m_fileName, "rb"); + if (!mcdFile.IsOpen()) + { + if (!forceCreation) + { + if (!AskYesNoT("\"%s\" does not exist.\n Create a new 16MB Memcard?", filename.c_str())) + return; + ascii = AskYesNoT("Format as ASCII (NTSC\\PAL)?\nChoose no for Shift JIS (NTSC-J)"); + } + Format(ascii); + return; + } + else + { + // This function can be removed once more about hdr is known and we can check for a valid header + std::string fileType; + SplitPath(filename, nullptr, nullptr, &fileType); + if (strcasecmp(fileType.c_str(), ".raw") && strcasecmp(fileType.c_str(), ".gcp")) + { + PanicAlertT("File has the extension \"%s\".\nValid extensions are (.raw/.gcp)", + fileType.c_str()); + return; + } + auto size = mcdFile.GetSize(); + if (size < MC_FST_BLOCKS * BLOCK_SIZE) + { + PanicAlertT("%s failed to load as a memory card.\nFile is not large enough to be a valid " + "memory card file (0x%x bytes)", + filename.c_str(), (unsigned)size); + return; + } + if (size % BLOCK_SIZE) + { + PanicAlertT("%s failed to load as a memory card.\nCard file size is invalid (0x%x bytes)", + filename.c_str(), (unsigned)size); + return; + } - m_sizeMb = (u16)((size/BLOCK_SIZE) / MBIT_TO_BLOCKS); - switch (m_sizeMb) - { - case MemCard59Mb: - case MemCard123Mb: - case MemCard251Mb: - case Memcard507Mb: - case MemCard1019Mb: - case MemCard2043Mb: - break; - default: - PanicAlertT("%s failed to load as a memory card.\nCard size is invalid (0x%x bytes)", filename.c_str(), (unsigned) size); - return; - } - } + m_sizeMb = (u16)((size / BLOCK_SIZE) / MBIT_TO_BLOCKS); + switch (m_sizeMb) + { + case MemCard59Mb: + case MemCard123Mb: + case MemCard251Mb: + case Memcard507Mb: + case MemCard1019Mb: + case MemCard2043Mb: + break; + default: + PanicAlertT("%s failed to load as a memory card.\nCard size is invalid (0x%x bytes)", + filename.c_str(), (unsigned)size); + return; + } + } + mcdFile.Seek(0, SEEK_SET); + if (!mcdFile.ReadBytes(&hdr, BLOCK_SIZE)) + { + PanicAlertT("Failed to read header correctly\n(0x0000-0x1FFF)"); + return; + } + if (m_sizeMb != BE16(hdr.SizeMb)) + { + PanicAlertT("Memory card file size does not match the header size"); + return; + } - mcdFile.Seek(0, SEEK_SET); - if (!mcdFile.ReadBytes(&hdr, BLOCK_SIZE)) - { - PanicAlertT("Failed to read header correctly\n(0x0000-0x1FFF)"); - return; - } - if (m_sizeMb != BE16(hdr.SizeMb)) - { - PanicAlertT("Memory card file size does not match the header size"); - return; - } + if (!mcdFile.ReadBytes(&dir, BLOCK_SIZE)) + { + PanicAlertT("Failed to read directory correctly\n(0x2000-0x3FFF)"); + return; + } - if (!mcdFile.ReadBytes(&dir, BLOCK_SIZE)) - { - PanicAlertT("Failed to read directory correctly\n(0x2000-0x3FFF)"); - return; - } + if (!mcdFile.ReadBytes(&dir_backup, BLOCK_SIZE)) + { + PanicAlertT("Failed to read directory backup correctly\n(0x4000-0x5FFF)"); + return; + } - if (!mcdFile.ReadBytes(&dir_backup, BLOCK_SIZE)) - { - PanicAlertT("Failed to read directory backup correctly\n(0x4000-0x5FFF)"); - return; - } + if (!mcdFile.ReadBytes(&bat, BLOCK_SIZE)) + { + PanicAlertT("Failed to read block allocation table correctly\n(0x6000-0x7FFF)"); + return; + } - if (!mcdFile.ReadBytes(&bat, BLOCK_SIZE)) - { - PanicAlertT("Failed to read block allocation table correctly\n(0x6000-0x7FFF)"); - return; - } + if (!mcdFile.ReadBytes(&bat_backup, BLOCK_SIZE)) + { + PanicAlertT("Failed to read block allocation table backup correctly\n(0x8000-0x9FFF)"); + return; + } - if (!mcdFile.ReadBytes(&bat_backup, BLOCK_SIZE)) - { - PanicAlertT("Failed to read block allocation table backup correctly\n(0x8000-0x9FFF)"); - return; - } + u32 csums = TestChecksums(); - u32 csums = TestChecksums(); + if (csums & 0x1) + { + // header checksum error! + // invalid files do not always get here + PanicAlertT("Header checksum failed"); + return; + } - if (csums & 0x1) - { - // header checksum error! - // invalid files do not always get here - PanicAlertT("Header checksum failed"); - return; - } + if (csums & 0x2) // directory checksum error! + { + if (csums & 0x4) + { + // backup is also wrong! + PanicAlertT("Directory checksum and directory backup checksum failed"); + return; + } + else + { + // backup is correct, restore + dir = dir_backup; + bat = bat_backup; - if (csums & 0x2) // directory checksum error! - { - if (csums & 0x4) - { - // backup is also wrong! - PanicAlertT("Directory checksum and directory backup checksum failed"); - return; - } - else - { - // backup is correct, restore - dir = dir_backup; - bat = bat_backup; + // update checksums + csums = TestChecksums(); + } + } - // update checksums - csums = TestChecksums(); - } - } + if (csums & 0x8) // BAT checksum error! + { + if (csums & 0x10) + { + // backup is also wrong! + PanicAlertT("Block Allocation Table checksum failed"); + return; + } + else + { + // backup is correct, restore + dir = dir_backup; + bat = bat_backup; - if (csums & 0x8) // BAT checksum error! - { - if (csums & 0x10) - { - // backup is also wrong! - PanicAlertT("Block Allocation Table checksum failed"); - return; - } - else - { - // backup is correct, restore - dir = dir_backup; - bat = bat_backup; + // update checksums + csums = TestChecksums(); + } + // It seems that the backup having a larger counter doesn't necessarily mean + // the backup should be copied? + // } + // + // if (BE16(dir_backup.UpdateCounter) > BE16(dir.UpdateCounter)) //check if the backup is newer + // { + // dir = dir_backup; + // bat = bat_backup; // needed? + } - // update checksums - csums = TestChecksums(); - } -// It seems that the backup having a larger counter doesn't necessarily mean -// the backup should be copied? -// } -// -// if (BE16(dir_backup.UpdateCounter) > BE16(dir.UpdateCounter)) //check if the backup is newer -// { -// dir = dir_backup; -// bat = bat_backup; // needed? - } + mcdFile.Seek(0xa000, SEEK_SET); - mcdFile.Seek(0xa000, SEEK_SET); + maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS; + mc_data_blocks.reserve(maxBlock - MC_FST_BLOCKS); - maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS; - mc_data_blocks.reserve(maxBlock - MC_FST_BLOCKS); + m_valid = true; + for (u32 i = MC_FST_BLOCKS; i < maxBlock; ++i) + { + GCMBlock b; + if (mcdFile.ReadBytes(b.block, BLOCK_SIZE)) + { + mc_data_blocks.push_back(b); + } + else + { + PanicAlertT("Failed to read block %u of the save data\nMemcard may be truncated\nFile " + "position: 0x%" PRIx64, + i, mcdFile.Tell()); + m_valid = false; + break; + } + } - m_valid = true; - for (u32 i = MC_FST_BLOCKS; i < maxBlock; ++i) - { - GCMBlock b; - if (mcdFile.ReadBytes(b.block, BLOCK_SIZE)) - { - mc_data_blocks.push_back(b); - } - else - { - PanicAlertT("Failed to read block %u of the save data\nMemcard may be truncated\nFile position: 0x%" PRIx64, i, mcdFile.Tell()); - m_valid = false; - break; - } - } + mcdFile.Close(); - mcdFile.Close(); - - InitDirBatPointers(); + InitDirBatPointers(); } void GCMemcard::InitDirBatPointers() { - if (BE16(dir.UpdateCounter) > (BE16(dir_backup.UpdateCounter))) - { - CurrentDir = &dir; - PreviousDir = &dir_backup; - } - else - { - CurrentDir = &dir_backup; - PreviousDir = &dir; - } - if (BE16(bat.UpdateCounter) > BE16(bat_backup.UpdateCounter)) - { - CurrentBat = &bat; - PreviousBat = &bat_backup; - } - else - { - CurrentBat = &bat_backup; - PreviousBat = &bat; - } + if (BE16(dir.UpdateCounter) > (BE16(dir_backup.UpdateCounter))) + { + CurrentDir = &dir; + PreviousDir = &dir_backup; + } + else + { + CurrentDir = &dir_backup; + PreviousDir = &dir; + } + if (BE16(bat.UpdateCounter) > BE16(bat_backup.UpdateCounter)) + { + CurrentBat = &bat; + PreviousBat = &bat_backup; + } + else + { + CurrentBat = &bat_backup; + PreviousBat = &bat; + } } bool GCMemcard::IsAsciiEncoding() const { - return hdr.Encoding == 0; + return hdr.Encoding == 0; } bool GCMemcard::Save() { - File::IOFile mcdFile(m_fileName, "wb"); - mcdFile.Seek(0, SEEK_SET); + File::IOFile mcdFile(m_fileName, "wb"); + mcdFile.Seek(0, SEEK_SET); - mcdFile.WriteBytes(&hdr, BLOCK_SIZE); - mcdFile.WriteBytes(&dir, BLOCK_SIZE); - mcdFile.WriteBytes(&dir_backup, BLOCK_SIZE); - mcdFile.WriteBytes(&bat, BLOCK_SIZE); - mcdFile.WriteBytes(&bat_backup, BLOCK_SIZE); - for (unsigned int i = 0; i < maxBlock - MC_FST_BLOCKS; ++i) - { - mcdFile.WriteBytes(mc_data_blocks[i].block, BLOCK_SIZE); - } + mcdFile.WriteBytes(&hdr, BLOCK_SIZE); + mcdFile.WriteBytes(&dir, BLOCK_SIZE); + mcdFile.WriteBytes(&dir_backup, BLOCK_SIZE); + mcdFile.WriteBytes(&bat, BLOCK_SIZE); + mcdFile.WriteBytes(&bat_backup, BLOCK_SIZE); + for (unsigned int i = 0; i < maxBlock - MC_FST_BLOCKS; ++i) + { + mcdFile.WriteBytes(mc_data_blocks[i].block, BLOCK_SIZE); + } - return mcdFile.Close(); + return mcdFile.Close(); } -void calc_checksumsBE(u16 *buf, u32 length, u16 *csum, u16 *inv_csum) +void calc_checksumsBE(u16* buf, u32 length, u16* csum, u16* inv_csum) { - *csum = *inv_csum = 0; + *csum = *inv_csum = 0; - for (u32 i = 0; i < length; ++i) - { - //weird warnings here - *csum += BE16(buf[i]); - *inv_csum += BE16((u16)(buf[i] ^ 0xffff)); - } - *csum = BE16(*csum); - *inv_csum = BE16(*inv_csum); - if (*csum == 0xffff) - { - *csum = 0; - } - if (*inv_csum == 0xffff) - { - *inv_csum = 0; - } + for (u32 i = 0; i < length; ++i) + { + // weird warnings here + *csum += BE16(buf[i]); + *inv_csum += BE16((u16)(buf[i] ^ 0xffff)); + } + *csum = BE16(*csum); + *inv_csum = BE16(*inv_csum); + if (*csum == 0xffff) + { + *csum = 0; + } + if (*inv_csum == 0xffff) + { + *inv_csum = 0; + } } -u32 GCMemcard::TestChecksums() const +u32 GCMemcard::TestChecksums() const { - u16 csum=0, - csum_inv=0; + u16 csum = 0, csum_inv = 0; - u32 results = 0; + u32 results = 0; - calc_checksumsBE((u16*)&hdr, 0xFE , &csum, &csum_inv); - if ((hdr.Checksum != csum) || (hdr.Checksum_Inv != csum_inv)) - results |= 1; + calc_checksumsBE((u16*)&hdr, 0xFE, &csum, &csum_inv); + if ((hdr.Checksum != csum) || (hdr.Checksum_Inv != csum_inv)) + results |= 1; - calc_checksumsBE((u16*)&dir, 0xFFE, &csum, &csum_inv); - if ((dir.Checksum != csum) || (dir.Checksum_Inv != csum_inv)) - results |= 2; + calc_checksumsBE((u16*)&dir, 0xFFE, &csum, &csum_inv); + if ((dir.Checksum != csum) || (dir.Checksum_Inv != csum_inv)) + results |= 2; - calc_checksumsBE((u16*)&dir_backup, 0xFFE, &csum, &csum_inv); - if ((dir_backup.Checksum != csum) || (dir_backup.Checksum_Inv != csum_inv)) - results |= 4; + calc_checksumsBE((u16*)&dir_backup, 0xFFE, &csum, &csum_inv); + if ((dir_backup.Checksum != csum) || (dir_backup.Checksum_Inv != csum_inv)) + results |= 4; - calc_checksumsBE((u16*)(((u8*)&bat)+4), 0xFFE, &csum, &csum_inv); - if ((bat.Checksum != csum) || (bat.Checksum_Inv != csum_inv)) - results |= 8; + calc_checksumsBE((u16*)(((u8*)&bat) + 4), 0xFFE, &csum, &csum_inv); + if ((bat.Checksum != csum) || (bat.Checksum_Inv != csum_inv)) + results |= 8; - calc_checksumsBE((u16*)(((u8*)&bat_backup)+4), 0xFFE, &csum, &csum_inv); - if ((bat_backup.Checksum != csum) || (bat_backup.Checksum_Inv != csum_inv)) - results |= 16; + calc_checksumsBE((u16*)(((u8*)&bat_backup) + 4), 0xFFE, &csum, &csum_inv); + if ((bat_backup.Checksum != csum) || (bat_backup.Checksum_Inv != csum_inv)) + results |= 16; - return results; + return results; } bool GCMemcard::FixChecksums() { - if (!m_valid) - return false; + if (!m_valid) + return false; - calc_checksumsBE((u16*)&hdr, 0xFE, &hdr.Checksum, &hdr.Checksum_Inv); - calc_checksumsBE((u16*)&dir, 0xFFE, &dir.Checksum, &dir.Checksum_Inv); - calc_checksumsBE((u16*)&dir_backup, 0xFFE, &dir_backup.Checksum, &dir_backup.Checksum_Inv); - calc_checksumsBE((u16*)&bat+2, 0xFFE, &bat.Checksum, &bat.Checksum_Inv); - calc_checksumsBE((u16*)&bat_backup+2, 0xFFE, &bat_backup.Checksum, &bat_backup.Checksum_Inv); + calc_checksumsBE((u16*)&hdr, 0xFE, &hdr.Checksum, &hdr.Checksum_Inv); + calc_checksumsBE((u16*)&dir, 0xFFE, &dir.Checksum, &dir.Checksum_Inv); + calc_checksumsBE((u16*)&dir_backup, 0xFFE, &dir_backup.Checksum, &dir_backup.Checksum_Inv); + calc_checksumsBE((u16*)&bat + 2, 0xFFE, &bat.Checksum, &bat.Checksum_Inv); + calc_checksumsBE((u16*)&bat_backup + 2, 0xFFE, &bat_backup.Checksum, &bat_backup.Checksum_Inv); - return true; + return true; } u8 GCMemcard::GetNumFiles() const { - if (!m_valid) - return 0; + if (!m_valid) + return 0; - u8 j = 0; - for (int i = 0; i < DIRLEN; i++) - { - if (BE32(CurrentDir->Dir[i].Gamecode)!= 0xFFFFFFFF) - j++; - } - return j; + u8 j = 0; + for (int i = 0; i < DIRLEN; i++) + { + if (BE32(CurrentDir->Dir[i].Gamecode) != 0xFFFFFFFF) + j++; + } + return j; } u8 GCMemcard::GetFileIndex(u8 fileNumber) const { - if (m_valid) - { - u8 j = 0; - for (u8 i = 0; i < DIRLEN; i++) - { - if (BE32(CurrentDir->Dir[i].Gamecode)!= 0xFFFFFFFF) - { - if (j == fileNumber) - { - return i; - } - j++; - } - } - } - return 0xFF; + if (m_valid) + { + u8 j = 0; + for (u8 i = 0; i < DIRLEN; i++) + { + if (BE32(CurrentDir->Dir[i].Gamecode) != 0xFFFFFFFF) + { + if (j == fileNumber) + { + return i; + } + j++; + } + } + } + return 0xFF; } u16 GCMemcard::GetFreeBlocks() const { - if (!m_valid) - return 0; + if (!m_valid) + return 0; - return BE16(CurrentBat->FreeBlocks); + return BE16(CurrentBat->FreeBlocks); } u8 GCMemcard::TitlePresent(const DEntry& d) const { - if (!m_valid) - return DIRLEN; + if (!m_valid) + return DIRLEN; - u8 i = 0; - while (i < DIRLEN) - { - if ((BE32(CurrentDir->Dir[i].Gamecode) == BE32(d.Gamecode)) && - (!memcmp(CurrentDir->Dir[i].Filename, d.Filename, 32))) - { - break; - } - i++; - } - return i; + u8 i = 0; + while (i < DIRLEN) + { + if ((BE32(CurrentDir->Dir[i].Gamecode) == BE32(d.Gamecode)) && + (!memcmp(CurrentDir->Dir[i].Filename, d.Filename, 32))) + { + break; + } + i++; + } + return i; } -bool GCMemcard::GCI_FileName(u8 index, std::string &filename) const +bool GCMemcard::GCI_FileName(u8 index, std::string& filename) const { - if (!m_valid || index >= DIRLEN || (BE32(CurrentDir->Dir[index].Gamecode) == 0xFFFFFFFF)) - return false; + if (!m_valid || index >= DIRLEN || (BE32(CurrentDir->Dir[index].Gamecode) == 0xFFFFFFFF)) + return false; - filename = CurrentDir->Dir[index].GCI_FileName(); - return true; + filename = CurrentDir->Dir[index].GCI_FileName(); + return true; } // DEntry functions, all take u8 index < DIRLEN (127) @@ -384,870 +388,878 @@ bool GCMemcard::GCI_FileName(u8 index, std::string &filename) const std::string GCMemcard::DEntry_GameCode(u8 index) const { - if (!m_valid || index >= DIRLEN) - return ""; + if (!m_valid || index >= DIRLEN) + return ""; - return std::string((const char*)CurrentDir->Dir[index].Gamecode, 4); + return std::string((const char*)CurrentDir->Dir[index].Gamecode, 4); } std::string GCMemcard::DEntry_Makercode(u8 index) const { - if (!m_valid || index >= DIRLEN) - return ""; + if (!m_valid || index >= DIRLEN) + return ""; - return std::string((const char*)CurrentDir->Dir[index].Makercode, 2); + return std::string((const char*)CurrentDir->Dir[index].Makercode, 2); } std::string GCMemcard::DEntry_BIFlags(u8 index) const { - if (!m_valid || index >= DIRLEN) - return ""; + if (!m_valid || index >= DIRLEN) + return ""; - std::string flags; - int x = CurrentDir->Dir[index].BIFlags; - for (int i = 0; i < 8; i++) - { - flags.push_back((x & 0x80) ? '1' : '0'); - x = x << 1; - } - return flags; + std::string flags; + int x = CurrentDir->Dir[index].BIFlags; + for (int i = 0; i < 8; i++) + { + flags.push_back((x & 0x80) ? '1' : '0'); + x = x << 1; + } + return flags; } std::string GCMemcard::DEntry_FileName(u8 index) const { - if (!m_valid || index >= DIRLEN) - return ""; + if (!m_valid || index >= DIRLEN) + return ""; - return std::string((const char*)CurrentDir->Dir[index].Filename, DENTRY_STRLEN); + return std::string((const char*)CurrentDir->Dir[index].Filename, DENTRY_STRLEN); } u32 GCMemcard::DEntry_ModTime(u8 index) const { - if (!m_valid || index >= DIRLEN) - return 0xFFFFFFFF; + if (!m_valid || index >= DIRLEN) + return 0xFFFFFFFF; - return BE32(CurrentDir->Dir[index].ModTime); + return BE32(CurrentDir->Dir[index].ModTime); } u32 GCMemcard::DEntry_ImageOffset(u8 index) const { - if (!m_valid || index >= DIRLEN) - return 0xFFFFFFFF; + if (!m_valid || index >= DIRLEN) + return 0xFFFFFFFF; - return BE32(CurrentDir->Dir[index].ImageOffset); + return BE32(CurrentDir->Dir[index].ImageOffset); } std::string GCMemcard::DEntry_IconFmt(u8 index) const { - if (!m_valid || index >= DIRLEN) - return ""; + if (!m_valid || index >= DIRLEN) + return ""; - int x = CurrentDir->Dir[index].IconFmt[0]; - std::string format; - for (int i = 0; i < 16; i++) - { - if (i == 8) x = CurrentDir->Dir[index].IconFmt[1]; - format.push_back((x & 0x80) ? '1' : '0'); - x = x << 1; - } - return format; + int x = CurrentDir->Dir[index].IconFmt[0]; + std::string format; + for (int i = 0; i < 16; i++) + { + if (i == 8) + x = CurrentDir->Dir[index].IconFmt[1]; + format.push_back((x & 0x80) ? '1' : '0'); + x = x << 1; + } + return format; } std::string GCMemcard::DEntry_AnimSpeed(u8 index) const { - if (!m_valid || index >= DIRLEN) - return ""; + if (!m_valid || index >= DIRLEN) + return ""; - int x = CurrentDir->Dir[index].AnimSpeed[0]; - std::string speed; - for (int i = 0; i < 16; i++) - { - if (i == 8) x = CurrentDir->Dir[index].AnimSpeed[1]; - speed.push_back((x & 0x80) ? '1' : '0'); - x = x << 1; - } - return speed; + int x = CurrentDir->Dir[index].AnimSpeed[0]; + std::string speed; + for (int i = 0; i < 16; i++) + { + if (i == 8) + x = CurrentDir->Dir[index].AnimSpeed[1]; + speed.push_back((x & 0x80) ? '1' : '0'); + x = x << 1; + } + return speed; } std::string GCMemcard::DEntry_Permissions(u8 index) const { - if (!m_valid || index >= DIRLEN) - return ""; + if (!m_valid || index >= DIRLEN) + return ""; - u8 Permissions = CurrentDir->Dir[index].Permissions; - std::string permissionsString; - permissionsString.push_back((Permissions & 16) ? 'x' : 'M'); - permissionsString.push_back((Permissions & 8) ? 'x' : 'C'); - permissionsString.push_back((Permissions & 4) ? 'P' : 'x'); - return permissionsString; + u8 Permissions = CurrentDir->Dir[index].Permissions; + std::string permissionsString; + permissionsString.push_back((Permissions & 16) ? 'x' : 'M'); + permissionsString.push_back((Permissions & 8) ? 'x' : 'C'); + permissionsString.push_back((Permissions & 4) ? 'P' : 'x'); + return permissionsString; } u8 GCMemcard::DEntry_CopyCounter(u8 index) const { - if (!m_valid || index >= DIRLEN) - return 0xFF; + if (!m_valid || index >= DIRLEN) + return 0xFF; - return CurrentDir->Dir[index].CopyCounter; + return CurrentDir->Dir[index].CopyCounter; } u16 GCMemcard::DEntry_FirstBlock(u8 index) const { - if (!m_valid || index >= DIRLEN) - return 0xFFFF; + if (!m_valid || index >= DIRLEN) + return 0xFFFF; - u16 block = BE16(CurrentDir->Dir[index].FirstBlock); - if (block > (u16) maxBlock) return 0xFFFF; - return block; + u16 block = BE16(CurrentDir->Dir[index].FirstBlock); + if (block > (u16)maxBlock) + return 0xFFFF; + return block; } u16 GCMemcard::DEntry_BlockCount(u8 index) const { - if (!m_valid || index >= DIRLEN) - return 0xFFFF; + if (!m_valid || index >= DIRLEN) + return 0xFFFF; - u16 blocks = BE16(CurrentDir->Dir[index].BlockCount); - if (blocks > (u16) maxBlock) return 0xFFFF; - return blocks; + u16 blocks = BE16(CurrentDir->Dir[index].BlockCount); + if (blocks > (u16)maxBlock) + return 0xFFFF; + return blocks; } u32 GCMemcard::DEntry_CommentsAddress(u8 index) const { - if (!m_valid || index >= DIRLEN) - return 0xFFFF; + if (!m_valid || index >= DIRLEN) + return 0xFFFF; - return BE32(CurrentDir->Dir[index].CommentsAddr); + return BE32(CurrentDir->Dir[index].CommentsAddr); } std::string GCMemcard::GetSaveComment1(u8 index) const { - if (!m_valid || index >= DIRLEN) - return ""; + if (!m_valid || index >= DIRLEN) + return ""; - u32 Comment1 = BE32(CurrentDir->Dir[index].CommentsAddr); - u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; - if ((DataBlock > maxBlock) || (Comment1 == 0xFFFFFFFF)) - { - return ""; - } - return std::string((const char *)mc_data_blocks[DataBlock].block + Comment1, DENTRY_STRLEN); + u32 Comment1 = BE32(CurrentDir->Dir[index].CommentsAddr); + u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; + if ((DataBlock > maxBlock) || (Comment1 == 0xFFFFFFFF)) + { + return ""; + } + return std::string((const char*)mc_data_blocks[DataBlock].block + Comment1, DENTRY_STRLEN); } std::string GCMemcard::GetSaveComment2(u8 index) const { - if (!m_valid || index >= DIRLEN) - return ""; + if (!m_valid || index >= DIRLEN) + return ""; - u32 Comment1 = BE32(CurrentDir->Dir[index].CommentsAddr); - u32 Comment2 = Comment1 + DENTRY_STRLEN; - u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; - if ((DataBlock > maxBlock) || (Comment1 == 0xFFFFFFFF)) - { - return ""; - } - return std::string((const char *)mc_data_blocks[DataBlock].block + Comment2, DENTRY_STRLEN); + u32 Comment1 = BE32(CurrentDir->Dir[index].CommentsAddr); + u32 Comment2 = Comment1 + DENTRY_STRLEN; + u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; + if ((DataBlock > maxBlock) || (Comment1 == 0xFFFFFFFF)) + { + return ""; + } + return std::string((const char*)mc_data_blocks[DataBlock].block + Comment2, DENTRY_STRLEN); } -bool GCMemcard::GetDEntry(u8 index, DEntry &dest) const +bool GCMemcard::GetDEntry(u8 index, DEntry& dest) const { - if (!m_valid || index >= DIRLEN) - return false; + if (!m_valid || index >= DIRLEN) + return false; - dest = CurrentDir->Dir[index]; - return true; + dest = CurrentDir->Dir[index]; + return true; } u16 BlockAlloc::GetNextBlock(u16 Block) const { - if ((Block < MC_FST_BLOCKS) || (Block > 4091)) - return 0; + if ((Block < MC_FST_BLOCKS) || (Block > 4091)) + return 0; - return Common::swap16(Map[Block-MC_FST_BLOCKS]); + return Common::swap16(Map[Block - MC_FST_BLOCKS]); } u16 BlockAlloc::NextFreeBlock(u16 MaxBlock, u16 StartingBlock) const { - if (FreeBlocks) - { - MaxBlock = std::min(MaxBlock, BAT_SIZE); - for (u16 i = StartingBlock; i < MaxBlock; ++i) - if (Map[i-MC_FST_BLOCKS] == 0) - return i; + if (FreeBlocks) + { + MaxBlock = std::min(MaxBlock, BAT_SIZE); + for (u16 i = StartingBlock; i < MaxBlock; ++i) + if (Map[i - MC_FST_BLOCKS] == 0) + return i; - for (u16 i = MC_FST_BLOCKS; i < StartingBlock; ++i) - if (Map[i-MC_FST_BLOCKS] == 0) - return i; - } - return 0xFFFF; + for (u16 i = MC_FST_BLOCKS; i < StartingBlock; ++i) + if (Map[i - MC_FST_BLOCKS] == 0) + return i; + } + return 0xFFFF; } bool BlockAlloc::ClearBlocks(u16 FirstBlock, u16 BlockCount) { - std::vector blocks; - while (FirstBlock != 0xFFFF && FirstBlock != 0) - { - blocks.push_back(FirstBlock); - FirstBlock = GetNextBlock(FirstBlock); - } - if (FirstBlock > 0) - { - size_t length = blocks.size(); - if (length != BlockCount) - { - return false; - } - for (unsigned int i = 0; i < length; ++i) - Map[blocks.at(i)-MC_FST_BLOCKS] = 0; - FreeBlocks = BE16(BE16(FreeBlocks) + BlockCount); + std::vector blocks; + while (FirstBlock != 0xFFFF && FirstBlock != 0) + { + blocks.push_back(FirstBlock); + FirstBlock = GetNextBlock(FirstBlock); + } + if (FirstBlock > 0) + { + size_t length = blocks.size(); + if (length != BlockCount) + { + return false; + } + for (unsigned int i = 0; i < length; ++i) + Map[blocks.at(i) - MC_FST_BLOCKS] = 0; + FreeBlocks = BE16(BE16(FreeBlocks) + BlockCount); - return true; - } - return false; + return true; + } + return false; } -u32 GCMemcard::GetSaveData(u8 index, std::vector & Blocks) const +u32 GCMemcard::GetSaveData(u8 index, std::vector& Blocks) const { - if (!m_valid) - return NOMEMCARD; + if (!m_valid) + return NOMEMCARD; - u16 block = DEntry_FirstBlock(index); - u16 BlockCount = DEntry_BlockCount(index); - //u16 memcardSize = BE16(hdr.SizeMb) * MBIT_TO_BLOCKS; + u16 block = DEntry_FirstBlock(index); + u16 BlockCount = DEntry_BlockCount(index); + // u16 memcardSize = BE16(hdr.SizeMb) * MBIT_TO_BLOCKS; - if ((block == 0xFFFF) || (BlockCount == 0xFFFF)) - { - return FAIL; - } + if ((block == 0xFFFF) || (BlockCount == 0xFFFF)) + { + return FAIL; + } - u16 nextBlock = block; - for (int i = 0; i < BlockCount; ++i) - { - if ((!nextBlock) || (nextBlock == 0xFFFF)) - return FAIL; - Blocks.push_back(mc_data_blocks[nextBlock-MC_FST_BLOCKS]); - nextBlock = CurrentBat->GetNextBlock(nextBlock); - } - return SUCCESS; + u16 nextBlock = block; + for (int i = 0; i < BlockCount; ++i) + { + if ((!nextBlock) || (nextBlock == 0xFFFF)) + return FAIL; + Blocks.push_back(mc_data_blocks[nextBlock - MC_FST_BLOCKS]); + nextBlock = CurrentBat->GetNextBlock(nextBlock); + } + return SUCCESS; } // End DEntry functions -u32 GCMemcard::ImportFile(DEntry& direntry, std::vector &saveBlocks) +u32 GCMemcard::ImportFile(DEntry& direntry, std::vector& saveBlocks) { - if (!m_valid) - return NOMEMCARD; + if (!m_valid) + return NOMEMCARD; - if (GetNumFiles() >= DIRLEN) - { - return OUTOFDIRENTRIES; - } - if (BE16(CurrentBat->FreeBlocks) < BE16(direntry.BlockCount)) - { - return OUTOFBLOCKS; - } - if (TitlePresent(direntry) != DIRLEN) - { - return TITLEPRESENT; - } + if (GetNumFiles() >= DIRLEN) + { + return OUTOFDIRENTRIES; + } + if (BE16(CurrentBat->FreeBlocks) < BE16(direntry.BlockCount)) + { + return OUTOFBLOCKS; + } + if (TitlePresent(direntry) != DIRLEN) + { + return TITLEPRESENT; + } - // find first free data block - u16 firstBlock = CurrentBat->NextFreeBlock(maxBlock - MC_FST_BLOCKS, BE16(CurrentBat->LastAllocated)); - if (firstBlock == 0xFFFF) - return OUTOFBLOCKS; - Directory UpdatedDir = *CurrentDir; + // find first free data block + u16 firstBlock = + CurrentBat->NextFreeBlock(maxBlock - MC_FST_BLOCKS, BE16(CurrentBat->LastAllocated)); + if (firstBlock == 0xFFFF) + return OUTOFBLOCKS; + Directory UpdatedDir = *CurrentDir; - // find first free dir entry - for (int i=0; i < DIRLEN; i++) - { - if (BE32(UpdatedDir.Dir[i].Gamecode) == 0xFFFFFFFF) - { - UpdatedDir.Dir[i] = direntry; - *(u16*)&UpdatedDir.Dir[i].FirstBlock = BE16(firstBlock); - UpdatedDir.Dir[i].CopyCounter = UpdatedDir.Dir[i].CopyCounter+1; - break; - } - } - UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); - *PreviousDir = UpdatedDir; - if (PreviousDir == &dir ) - { - CurrentDir = &dir; - PreviousDir = &dir_backup; - } - else - { - CurrentDir = &dir_backup; - PreviousDir = &dir; - } + // find first free dir entry + for (int i = 0; i < DIRLEN; i++) + { + if (BE32(UpdatedDir.Dir[i].Gamecode) == 0xFFFFFFFF) + { + UpdatedDir.Dir[i] = direntry; + *(u16*)&UpdatedDir.Dir[i].FirstBlock = BE16(firstBlock); + UpdatedDir.Dir[i].CopyCounter = UpdatedDir.Dir[i].CopyCounter + 1; + break; + } + } + UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); + *PreviousDir = UpdatedDir; + if (PreviousDir == &dir) + { + CurrentDir = &dir; + PreviousDir = &dir_backup; + } + else + { + CurrentDir = &dir_backup; + PreviousDir = &dir; + } - int fileBlocks = BE16(direntry.BlockCount); + int fileBlocks = BE16(direntry.BlockCount); - FZEROGX_MakeSaveGameValid(hdr, direntry, saveBlocks); - PSO_MakeSaveGameValid(hdr, direntry, saveBlocks); + FZEROGX_MakeSaveGameValid(hdr, direntry, saveBlocks); + PSO_MakeSaveGameValid(hdr, direntry, saveBlocks); - BlockAlloc UpdatedBat = *CurrentBat; - u16 nextBlock; - // keep assuming no freespace fragmentation, and copy over all the data - for (int i = 0; i < fileBlocks; ++i) - { - if (firstBlock == 0xFFFF) - PanicAlert("Fatal Error"); - mc_data_blocks[firstBlock - MC_FST_BLOCKS] = saveBlocks[i]; - if (i == fileBlocks-1) - nextBlock = 0xFFFF; - else - nextBlock = UpdatedBat.NextFreeBlock(maxBlock - MC_FST_BLOCKS, firstBlock + 1); - UpdatedBat.Map[firstBlock - MC_FST_BLOCKS] = BE16(nextBlock); - UpdatedBat.LastAllocated = BE16(firstBlock); - firstBlock = nextBlock; - } + BlockAlloc UpdatedBat = *CurrentBat; + u16 nextBlock; + // keep assuming no freespace fragmentation, and copy over all the data + for (int i = 0; i < fileBlocks; ++i) + { + if (firstBlock == 0xFFFF) + PanicAlert("Fatal Error"); + mc_data_blocks[firstBlock - MC_FST_BLOCKS] = saveBlocks[i]; + if (i == fileBlocks - 1) + nextBlock = 0xFFFF; + else + nextBlock = UpdatedBat.NextFreeBlock(maxBlock - MC_FST_BLOCKS, firstBlock + 1); + UpdatedBat.Map[firstBlock - MC_FST_BLOCKS] = BE16(nextBlock); + UpdatedBat.LastAllocated = BE16(firstBlock); + firstBlock = nextBlock; + } - UpdatedBat.FreeBlocks = BE16(BE16(UpdatedBat.FreeBlocks) - fileBlocks); - UpdatedBat.UpdateCounter = BE16(BE16(UpdatedBat.UpdateCounter) + 1); - *PreviousBat = UpdatedBat; - if (PreviousBat == &bat ) - { - CurrentBat = &bat; - PreviousBat = &bat_backup; - } - else - { - CurrentBat = &bat_backup; - PreviousBat = &bat; - } + UpdatedBat.FreeBlocks = BE16(BE16(UpdatedBat.FreeBlocks) - fileBlocks); + UpdatedBat.UpdateCounter = BE16(BE16(UpdatedBat.UpdateCounter) + 1); + *PreviousBat = UpdatedBat; + if (PreviousBat == &bat) + { + CurrentBat = &bat; + PreviousBat = &bat_backup; + } + else + { + CurrentBat = &bat_backup; + PreviousBat = &bat; + } - return SUCCESS; + return SUCCESS; } -u32 GCMemcard::RemoveFile(u8 index) //index in the directory array +u32 GCMemcard::RemoveFile(u8 index) // index in the directory array { - if (!m_valid) - return NOMEMCARD; - if (index >= DIRLEN) - return DELETE_FAIL; + if (!m_valid) + return NOMEMCARD; + if (index >= DIRLEN) + return DELETE_FAIL; - u16 startingblock = BE16(dir.Dir[index].FirstBlock); - u16 numberofblocks = BE16(dir.Dir[index].BlockCount); + u16 startingblock = BE16(dir.Dir[index].FirstBlock); + u16 numberofblocks = BE16(dir.Dir[index].BlockCount); - BlockAlloc UpdatedBat = *CurrentBat; - if (!UpdatedBat.ClearBlocks(startingblock, numberofblocks)) - return DELETE_FAIL; - UpdatedBat.UpdateCounter = BE16(BE16(UpdatedBat.UpdateCounter) + 1); - *PreviousBat = UpdatedBat; - if (PreviousBat == &bat ) - { - CurrentBat = &bat; - PreviousBat = &bat_backup; - } - else - { - CurrentBat = &bat_backup; - PreviousBat = &bat; - } + BlockAlloc UpdatedBat = *CurrentBat; + if (!UpdatedBat.ClearBlocks(startingblock, numberofblocks)) + return DELETE_FAIL; + UpdatedBat.UpdateCounter = BE16(BE16(UpdatedBat.UpdateCounter) + 1); + *PreviousBat = UpdatedBat; + if (PreviousBat == &bat) + { + CurrentBat = &bat; + PreviousBat = &bat_backup; + } + else + { + CurrentBat = &bat_backup; + PreviousBat = &bat; + } - Directory UpdatedDir = *CurrentDir; - /* - // TODO: determine when this is used, even on the same memory card I have seen - // both update to broken file, and not updated - *(u32*)&UpdatedDir.Dir[index].Gamecode = 0; - *(u16*)&UpdatedDir.Dir[index].Makercode = 0; - memset(UpdatedDir.Dir[index].Filename, 0, 0x20); - strcpy((char*)UpdatedDir.Dir[index].Filename, "Broken File000"); - *(u16*)&UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); + Directory UpdatedDir = *CurrentDir; + /* + // TODO: determine when this is used, even on the same memory card I have seen + // both update to broken file, and not updated + *(u32*)&UpdatedDir.Dir[index].Gamecode = 0; + *(u16*)&UpdatedDir.Dir[index].Makercode = 0; + memset(UpdatedDir.Dir[index].Filename, 0, 0x20); + strcpy((char*)UpdatedDir.Dir[index].Filename, "Broken File000"); + *(u16*)&UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); - *PreviousDir = UpdatedDir; - if (PreviousDir == &dir ) - { - CurrentDir = &dir; - PreviousDir = &dir_backup; - } - else - { - CurrentDir = &dir_backup; - PreviousDir = &dir; - } - */ - memset(&(UpdatedDir.Dir[index]), 0xFF, DENTRY_SIZE); - UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); - *PreviousDir = UpdatedDir; - if (PreviousDir == &dir ) - { - CurrentDir = &dir; - PreviousDir = &dir_backup; - } - else - { - CurrentDir = &dir_backup; - PreviousDir = &dir; - } + *PreviousDir = UpdatedDir; + if (PreviousDir == &dir ) + { + CurrentDir = &dir; + PreviousDir = &dir_backup; + } + else + { + CurrentDir = &dir_backup; + PreviousDir = &dir; + } + */ + memset(&(UpdatedDir.Dir[index]), 0xFF, DENTRY_SIZE); + UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); + *PreviousDir = UpdatedDir; + if (PreviousDir == &dir) + { + CurrentDir = &dir; + PreviousDir = &dir_backup; + } + else + { + CurrentDir = &dir_backup; + PreviousDir = &dir; + } - return SUCCESS; + return SUCCESS; } u32 GCMemcard::CopyFrom(const GCMemcard& source, u8 index) { - if (!m_valid || !source.m_valid) - return NOMEMCARD; + if (!m_valid || !source.m_valid) + return NOMEMCARD; - DEntry tempDEntry; - if (!source.GetDEntry(index, tempDEntry)) - return NOMEMCARD; + DEntry tempDEntry; + if (!source.GetDEntry(index, tempDEntry)) + return NOMEMCARD; - u32 size = source.DEntry_BlockCount(index); - if (size == 0xFFFF) return INVALIDFILESIZE; + u32 size = source.DEntry_BlockCount(index); + if (size == 0xFFFF) + return INVALIDFILESIZE; - std::vector saveData; - saveData.reserve(size); - switch (source.GetSaveData(index, saveData)) - { - case FAIL: - return FAIL; - case NOMEMCARD: - return NOMEMCARD; - default: - return ImportFile(tempDEntry, saveData); - } + std::vector saveData; + saveData.reserve(size); + switch (source.GetSaveData(index, saveData)) + { + case FAIL: + return FAIL; + case NOMEMCARD: + return NOMEMCARD; + default: + return ImportFile(tempDEntry, saveData); + } } -u32 GCMemcard::ImportGci(const std::string& inputFile, const std::string &outputFile) +u32 GCMemcard::ImportGci(const std::string& inputFile, const std::string& outputFile) { - if (outputFile.empty() && !m_valid) - return OPENFAIL; + if (outputFile.empty() && !m_valid) + return OPENFAIL; - File::IOFile gci(inputFile, "rb"); - if (!gci) - return OPENFAIL; + File::IOFile gci(inputFile, "rb"); + if (!gci) + return OPENFAIL; - u32 result = ImportGciInternal(gci.ReleaseHandle(), inputFile, outputFile); + u32 result = ImportGciInternal(gci.ReleaseHandle(), inputFile, outputFile); - return result; + return result; } -u32 GCMemcard::ImportGciInternal(FILE* gcih, const std::string& inputFile, const std::string &outputFile) +u32 GCMemcard::ImportGciInternal(FILE* gcih, const std::string& inputFile, + const std::string& outputFile) { - File::IOFile gci(gcih); - unsigned int offset; - std::string fileType; - SplitPath(inputFile, nullptr, nullptr, &fileType); + File::IOFile gci(gcih); + unsigned int offset; + std::string fileType; + SplitPath(inputFile, nullptr, nullptr, &fileType); - if (!strcasecmp(fileType.c_str(), ".gci")) - offset = GCI; - else - { - char tmp[0xD]; - gci.ReadBytes(tmp, sizeof(tmp)); - if (!strcasecmp(fileType.c_str(), ".gcs")) - { - if (!memcmp(tmp, "GCSAVE", 6)) // Header must be uppercase - offset = GCS; - else - return GCSFAIL; - } - else if (!strcasecmp(fileType.c_str(), ".sav")) - { - if (!memcmp(tmp, "DATELGC_SAVE", 0xC)) // Header must be uppercase - offset = SAV; - else - return SAVFAIL; - } - else - return OPENFAIL; - } - gci.Seek(offset, SEEK_SET); + if (!strcasecmp(fileType.c_str(), ".gci")) + offset = GCI; + else + { + char tmp[0xD]; + gci.ReadBytes(tmp, sizeof(tmp)); + if (!strcasecmp(fileType.c_str(), ".gcs")) + { + if (!memcmp(tmp, "GCSAVE", 6)) // Header must be uppercase + offset = GCS; + else + return GCSFAIL; + } + else if (!strcasecmp(fileType.c_str(), ".sav")) + { + if (!memcmp(tmp, "DATELGC_SAVE", 0xC)) // Header must be uppercase + offset = SAV; + else + return SAVFAIL; + } + else + return OPENFAIL; + } + gci.Seek(offset, SEEK_SET); - DEntry tempDEntry; - gci.ReadBytes(&tempDEntry, DENTRY_SIZE); - const int fStart = (int)gci.Tell(); - gci.Seek(0, SEEK_END); - const int length = (int)gci.Tell() - fStart; - gci.Seek(offset + DENTRY_SIZE, SEEK_SET); + DEntry tempDEntry; + gci.ReadBytes(&tempDEntry, DENTRY_SIZE); + const int fStart = (int)gci.Tell(); + gci.Seek(0, SEEK_END); + const int length = (int)gci.Tell() - fStart; + gci.Seek(offset + DENTRY_SIZE, SEEK_SET); - Gcs_SavConvert(tempDEntry, offset, length); + Gcs_SavConvert(tempDEntry, offset, length); - if (length != BE16(tempDEntry.BlockCount) * BLOCK_SIZE) - return LENGTHFAIL; - if (gci.Tell() != offset + DENTRY_SIZE) // Verify correct file position - return OPENFAIL; + if (length != BE16(tempDEntry.BlockCount) * BLOCK_SIZE) + return LENGTHFAIL; + if (gci.Tell() != offset + DENTRY_SIZE) // Verify correct file position + return OPENFAIL; - u32 size = BE16((tempDEntry.BlockCount)); - std::vector saveData; - saveData.reserve(size); + u32 size = BE16((tempDEntry.BlockCount)); + std::vector saveData; + saveData.reserve(size); - for (unsigned int i = 0; i < size; ++i) - { - GCMBlock b; - gci.ReadBytes(b.block, BLOCK_SIZE); - saveData.push_back(b); - } - u32 ret; - if (!outputFile.empty()) - { - File::IOFile gci2(outputFile, "wb"); - bool completeWrite = true; - if (!gci2) - { - return OPENFAIL; - } - gci2.Seek(0, SEEK_SET); + for (unsigned int i = 0; i < size; ++i) + { + GCMBlock b; + gci.ReadBytes(b.block, BLOCK_SIZE); + saveData.push_back(b); + } + u32 ret; + if (!outputFile.empty()) + { + File::IOFile gci2(outputFile, "wb"); + bool completeWrite = true; + if (!gci2) + { + return OPENFAIL; + } + gci2.Seek(0, SEEK_SET); - if (!gci2.WriteBytes(&tempDEntry, DENTRY_SIZE)) - completeWrite = false; - int fileBlocks = BE16(tempDEntry.BlockCount); - gci2.Seek(DENTRY_SIZE, SEEK_SET); + if (!gci2.WriteBytes(&tempDEntry, DENTRY_SIZE)) + completeWrite = false; + int fileBlocks = BE16(tempDEntry.BlockCount); + gci2.Seek(DENTRY_SIZE, SEEK_SET); - for (int i = 0; i < fileBlocks; ++i) - { - if (!gci2.WriteBytes(saveData[i].block, BLOCK_SIZE)) - completeWrite = false; - } + for (int i = 0; i < fileBlocks; ++i) + { + if (!gci2.WriteBytes(saveData[i].block, BLOCK_SIZE)) + completeWrite = false; + } - if (completeWrite) - ret = GCS; - else - ret = WRITEFAIL; - } - else - ret = ImportFile(tempDEntry, saveData); + if (completeWrite) + ret = GCS; + else + ret = WRITEFAIL; + } + else + ret = ImportFile(tempDEntry, saveData); - return ret; + return ret; } -u32 GCMemcard::ExportGci(u8 index, const std::string& fileName, const std::string &directory) const +u32 GCMemcard::ExportGci(u8 index, const std::string& fileName, const std::string& directory) const { - File::IOFile gci; - int offset = GCI; + File::IOFile gci; + int offset = GCI; - if (!fileName.length()) - { - std::string gciFilename; - // GCI_FileName should only fail if the gamecode is 0xFFFFFFFF - if (!GCI_FileName(index, gciFilename)) return SUCCESS; - gci.Open(directory + DIR_SEP + gciFilename, "wb"); - } - else - { - std::string fileType; - gci.Open(fileName, "wb"); - SplitPath(fileName, nullptr, nullptr, &fileType); - if (!strcasecmp(fileType.c_str(), ".gcs")) - { - offset = GCS; - } - else if (!strcasecmp(fileType.c_str(), ".sav")) - { - offset = SAV; - } - } + if (!fileName.length()) + { + std::string gciFilename; + // GCI_FileName should only fail if the gamecode is 0xFFFFFFFF + if (!GCI_FileName(index, gciFilename)) + return SUCCESS; + gci.Open(directory + DIR_SEP + gciFilename, "wb"); + } + else + { + std::string fileType; + gci.Open(fileName, "wb"); + SplitPath(fileName, nullptr, nullptr, &fileType); + if (!strcasecmp(fileType.c_str(), ".gcs")) + { + offset = GCS; + } + else if (!strcasecmp(fileType.c_str(), ".sav")) + { + offset = SAV; + } + } - if (!gci) - return OPENFAIL; + if (!gci) + return OPENFAIL; - gci.Seek(0, SEEK_SET); + gci.Seek(0, SEEK_SET); - switch (offset) - { - case GCS: - u8 gcsHDR[GCS]; - memset(gcsHDR, 0, GCS); - memcpy(gcsHDR, "GCSAVE", 6); - gci.WriteArray(gcsHDR, GCS); - break; + switch (offset) + { + case GCS: + u8 gcsHDR[GCS]; + memset(gcsHDR, 0, GCS); + memcpy(gcsHDR, "GCSAVE", 6); + gci.WriteArray(gcsHDR, GCS); + break; - case SAV: - u8 savHDR[SAV]; - memset(savHDR, 0, SAV); - memcpy(savHDR, "DATELGC_SAVE", 0xC); - gci.WriteArray(savHDR, SAV); - break; - } + case SAV: + u8 savHDR[SAV]; + memset(savHDR, 0, SAV); + memcpy(savHDR, "DATELGC_SAVE", 0xC); + gci.WriteArray(savHDR, SAV); + break; + } - DEntry tempDEntry; - if (!GetDEntry(index, tempDEntry)) - { - return NOMEMCARD; - } + DEntry tempDEntry; + if (!GetDEntry(index, tempDEntry)) + { + return NOMEMCARD; + } - Gcs_SavConvert(tempDEntry, offset); - gci.WriteBytes(&tempDEntry, DENTRY_SIZE); + Gcs_SavConvert(tempDEntry, offset); + gci.WriteBytes(&tempDEntry, DENTRY_SIZE); - u32 size = DEntry_BlockCount(index); - if (size == 0xFFFF) - { - return FAIL; - } + u32 size = DEntry_BlockCount(index); + if (size == 0xFFFF) + { + return FAIL; + } - std::vector saveData; - saveData.reserve(size); + std::vector saveData; + saveData.reserve(size); - switch (GetSaveData(index, saveData)) - { - case FAIL: - return FAIL; - case NOMEMCARD: - return NOMEMCARD; - } - gci.Seek(DENTRY_SIZE + offset, SEEK_SET); - for (unsigned int i = 0; i < size; ++i) - { - gci.WriteBytes(saveData[i].block, BLOCK_SIZE); - } + switch (GetSaveData(index, saveData)) + { + case FAIL: + return FAIL; + case NOMEMCARD: + return NOMEMCARD; + } + gci.Seek(DENTRY_SIZE + offset, SEEK_SET); + for (unsigned int i = 0; i < size; ++i) + { + gci.WriteBytes(saveData[i].block, BLOCK_SIZE); + } - if (gci.IsGood()) - return SUCCESS; - else - return WRITEFAIL; + if (gci.IsGood()) + return SUCCESS; + else + return WRITEFAIL; } -void GCMemcard::Gcs_SavConvert(DEntry &tempDEntry, int saveType, int length) +void GCMemcard::Gcs_SavConvert(DEntry& tempDEntry, int saveType, int length) { - switch (saveType) - { - case GCS: - { - // field containing the Block count as displayed within - // the GameSaves software is not stored in the GCS file. - // It is stored only within the corresponding GSV file. - // If the GCS file is added without using the GameSaves software, - // the value stored is always "1" - *(u16*)&tempDEntry.BlockCount = BE16(length / BLOCK_SIZE); - } - break; - case SAV: - // swap byte pairs - // 0x2C and 0x2D, 0x2E and 0x2F, 0x30 and 0x31, 0x32 and 0x33, - // 0x34 and 0x35, 0x36 and 0x37, 0x38 and 0x39, 0x3A and 0x3B, - // 0x3C and 0x3D,0x3E and 0x3F. - // It seems that sav files also swap the BIFlags... - ByteSwap(&tempDEntry.Unused1, &tempDEntry.BIFlags); - ArrayByteSwap((tempDEntry.ImageOffset)); - ArrayByteSwap(&(tempDEntry.ImageOffset[2])); - ArrayByteSwap((tempDEntry.IconFmt)); - ArrayByteSwap((tempDEntry.AnimSpeed)); - ByteSwap(&tempDEntry.Permissions, &tempDEntry.CopyCounter); - ArrayByteSwap((tempDEntry.FirstBlock)); - ArrayByteSwap((tempDEntry.BlockCount)); - ArrayByteSwap((tempDEntry.Unused2)); - ArrayByteSwap((tempDEntry.CommentsAddr)); - ArrayByteSwap(&(tempDEntry.CommentsAddr[2])); - break; - default: - break; - } + switch (saveType) + { + case GCS: + { + // field containing the Block count as displayed within + // the GameSaves software is not stored in the GCS file. + // It is stored only within the corresponding GSV file. + // If the GCS file is added without using the GameSaves software, + // the value stored is always "1" + *(u16*)&tempDEntry.BlockCount = BE16(length / BLOCK_SIZE); + } + break; + case SAV: + // swap byte pairs + // 0x2C and 0x2D, 0x2E and 0x2F, 0x30 and 0x31, 0x32 and 0x33, + // 0x34 and 0x35, 0x36 and 0x37, 0x38 and 0x39, 0x3A and 0x3B, + // 0x3C and 0x3D,0x3E and 0x3F. + // It seems that sav files also swap the BIFlags... + ByteSwap(&tempDEntry.Unused1, &tempDEntry.BIFlags); + ArrayByteSwap((tempDEntry.ImageOffset)); + ArrayByteSwap(&(tempDEntry.ImageOffset[2])); + ArrayByteSwap((tempDEntry.IconFmt)); + ArrayByteSwap((tempDEntry.AnimSpeed)); + ByteSwap(&tempDEntry.Permissions, &tempDEntry.CopyCounter); + ArrayByteSwap((tempDEntry.FirstBlock)); + ArrayByteSwap((tempDEntry.BlockCount)); + ArrayByteSwap((tempDEntry.Unused2)); + ArrayByteSwap((tempDEntry.CommentsAddr)); + ArrayByteSwap(&(tempDEntry.CommentsAddr[2])); + break; + default: + break; + } } bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer) const { - if (!m_valid || index >= DIRLEN) - return false; + if (!m_valid || index >= DIRLEN) + return false; - int flags = CurrentDir->Dir[index].BIFlags; - // Timesplitters 2 is the only game that I see this in - // May be a hack - if (flags == 0xFB) flags = ~flags; + int flags = CurrentDir->Dir[index].BIFlags; + // Timesplitters 2 is the only game that I see this in + // May be a hack + if (flags == 0xFB) + flags = ~flags; - int bnrFormat = (flags&3); + int bnrFormat = (flags & 3); - if (bnrFormat == 0) - return false; + if (bnrFormat == 0) + return false; - u32 DataOffset = BE32(CurrentDir->Dir[index].ImageOffset); - u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; + u32 DataOffset = BE32(CurrentDir->Dir[index].ImageOffset); + u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; - if ((DataBlock > maxBlock) || (DataOffset == 0xFFFFFFFF)) - { - return false; - } + if ((DataBlock > maxBlock) || (DataOffset == 0xFFFFFFFF)) + { + return false; + } - const int pixels = 96*32; + const int pixels = 96 * 32; - if (bnrFormat&1) - { - u8 *pxdata = (u8* )(mc_data_blocks[DataBlock].block + DataOffset); - u16 *paldata = (u16*)(mc_data_blocks[DataBlock].block + DataOffset + pixels); + if (bnrFormat & 1) + { + u8* pxdata = (u8*)(mc_data_blocks[DataBlock].block + DataOffset); + u16* paldata = (u16*)(mc_data_blocks[DataBlock].block + DataOffset + pixels); - ColorUtil::decodeCI8image(buffer, pxdata, paldata, 96, 32); - } - else - { - u16 *pxdata = (u16*)(mc_data_blocks[DataBlock].block + DataOffset); + ColorUtil::decodeCI8image(buffer, pxdata, paldata, 96, 32); + } + else + { + u16* pxdata = (u16*)(mc_data_blocks[DataBlock].block + DataOffset); - ColorUtil::decode5A3image(buffer, pxdata, 96, 32); - } - return true; + ColorUtil::decode5A3image(buffer, pxdata, 96, 32); + } + return true; } -u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const +u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8* delays) const { - if (!m_valid || index >= DIRLEN) - return 0; + if (!m_valid || index >= DIRLEN) + return 0; - // To ensure only one type of icon is used - // Sonic Heroes it the only game I have seen that tries to use a CI8 and RGB5A3 icon - //int fmtCheck = 0; + // To ensure only one type of icon is used + // Sonic Heroes it the only game I have seen that tries to use a CI8 and RGB5A3 icon + // int fmtCheck = 0; - int formats = BE16(CurrentDir->Dir[index].IconFmt); - int fdelays = BE16(CurrentDir->Dir[index].AnimSpeed); + int formats = BE16(CurrentDir->Dir[index].IconFmt); + int fdelays = BE16(CurrentDir->Dir[index].AnimSpeed); - int flags = CurrentDir->Dir[index].BIFlags; - // Timesplitters 2 and 3 is the only game that I see this in - // May be a hack - //if (flags == 0xFB) flags = ~flags; - // Batten Kaitos has 0x65 as flag too. Everything but the first 3 bytes seems irrelevant. - // Something similar happens with Wario Ware Inc. AnimSpeed + int flags = CurrentDir->Dir[index].BIFlags; + // Timesplitters 2 and 3 is the only game that I see this in + // May be a hack + // if (flags == 0xFB) flags = ~flags; + // Batten Kaitos has 0x65 as flag too. Everything but the first 3 bytes seems irrelevant. + // Something similar happens with Wario Ware Inc. AnimSpeed - int bnrFormat = (flags&3); + int bnrFormat = (flags & 3); - u32 DataOffset = BE32(CurrentDir->Dir[index].ImageOffset); - u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; + u32 DataOffset = BE32(CurrentDir->Dir[index].ImageOffset); + u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; - if ((DataBlock > maxBlock) || (DataOffset == 0xFFFFFFFF)) - { - return 0; - } + if ((DataBlock > maxBlock) || (DataOffset == 0xFFFFFFFF)) + { + return 0; + } - u8* animData = (u8*)(mc_data_blocks[DataBlock].block + DataOffset); + u8* animData = (u8*)(mc_data_blocks[DataBlock].block + DataOffset); - switch (bnrFormat) - { - case 1: - animData += 96*32 + 2*256; // image+palette - break; - case 2: - animData += 96*32*2; - break; - } + switch (bnrFormat) + { + case 1: + animData += 96 * 32 + 2 * 256; // image+palette + break; + case 2: + animData += 96 * 32 * 2; + break; + } - int fmts[8]; - u8* data[8]; - int frames = 0; + int fmts[8]; + u8* data[8]; + int frames = 0; - for (int i = 0; i < 8; i++) - { - fmts[i] = (formats >> (2*i))&3; - delays[i] = ((fdelays >> (2*i))&3); - data[i] = animData; + for (int i = 0; i < 8; i++) + { + fmts[i] = (formats >> (2 * i)) & 3; + delays[i] = ((fdelays >> (2 * i)) & 3); + data[i] = animData; - if (!delays[i]) - { - //First icon_speed = 0 indicates there aren't any more icons - break; - } - //If speed is set there is an icon (it can be a "blank frame") - frames++; - if (fmts[i] != 0) - { - switch (fmts[i]) - { - case CI8SHARED: // CI8 with shared palette - animData += 32*32; - break; - case RGB5A3: // RGB5A3 - animData += 32*32*2; - break; - case CI8: // CI8 with own palette - animData += 32*32 + 2*256; - break; - } - } - } + if (!delays[i]) + { + // First icon_speed = 0 indicates there aren't any more icons + break; + } + // If speed is set there is an icon (it can be a "blank frame") + frames++; + if (fmts[i] != 0) + { + switch (fmts[i]) + { + case CI8SHARED: // CI8 with shared palette + animData += 32 * 32; + break; + case RGB5A3: // RGB5A3 + animData += 32 * 32 * 2; + break; + case CI8: // CI8 with own palette + animData += 32 * 32 + 2 * 256; + break; + } + } + } - u16* sharedPal = (u16*)(animData); - int j = 0; + u16* sharedPal = (u16*)(animData); + int j = 0; - for (int i = 0; i < 8; i++) - { + for (int i = 0; i < 8; i++) + { + if (!delays[i]) + { + // First icon_speed = 0 indicates there aren't any more icons + break; + } + if (fmts[i] != 0) + { + switch (fmts[i]) + { + case CI8SHARED: // CI8 with shared palette + ColorUtil::decodeCI8image(buffer, data[i], sharedPal, 32, 32); + buffer += 32 * 32; + break; + case RGB5A3: // RGB5A3 + ColorUtil::decode5A3image(buffer, (u16*)(data[i]), 32, 32); + buffer += 32 * 32; + break; + case CI8: // CI8 with own palette + u16* paldata = (u16*)(data[i] + 32 * 32); + ColorUtil::decodeCI8image(buffer, data[i], paldata, 32, 32); + buffer += 32 * 32; + break; + } + } + else + { + // Speed is set but there's no actual icon + // This is used to reduce animation speed in Pikmin and Luigi's Mansion for example + // These "blank frames" show the next icon + for (j = i; j < 8; ++j) + { + if (fmts[j] != 0) + { + switch (fmts[j]) + { + case CI8SHARED: // CI8 with shared palette + ColorUtil::decodeCI8image(buffer, data[j], sharedPal, 32, 32); + break; + case RGB5A3: // RGB5A3 + ColorUtil::decode5A3image(buffer, (u16*)(data[j]), 32, 32); + buffer += 32 * 32; + break; + case CI8: // CI8 with own palette + u16* paldata = (u16*)(data[j] + 32 * 32); + ColorUtil::decodeCI8image(buffer, data[j], paldata, 32, 32); + buffer += 32 * 32; + break; + } + } + } + } + } - if (!delays[i]) - { - //First icon_speed = 0 indicates there aren't any more icons - break; - } - if (fmts[i] != 0) - { - switch (fmts[i]) - { - case CI8SHARED: // CI8 with shared palette - ColorUtil::decodeCI8image(buffer,data[i],sharedPal,32,32); - buffer += 32*32; - break; - case RGB5A3: // RGB5A3 - ColorUtil::decode5A3image(buffer, (u16*)(data[i]), 32, 32); - buffer += 32*32; - break; - case CI8: // CI8 with own palette - u16 *paldata = (u16*)(data[i] + 32*32); - ColorUtil::decodeCI8image(buffer, data[i], paldata, 32, 32); - buffer += 32*32; - break; - } - } - else - { - //Speed is set but there's no actual icon - //This is used to reduce animation speed in Pikmin and Luigi's Mansion for example - //These "blank frames" show the next icon - for (j=i; j<8;++j) - { - if (fmts[j] != 0) - { - switch (fmts[j]) - { - case CI8SHARED: // CI8 with shared palette - ColorUtil::decodeCI8image(buffer,data[j],sharedPal,32,32); - break; - case RGB5A3: // RGB5A3 - ColorUtil::decode5A3image(buffer, (u16*)(data[j]), 32, 32); - buffer += 32*32; - break; - case CI8: // CI8 with own palette - u16 *paldata = (u16*)(data[j] + 32*32); - ColorUtil::decodeCI8image(buffer, data[j], paldata, 32, 32); - buffer += 32*32; - break; - } - } - } - } - } - - return frames; + return frames; } -bool GCMemcard::Format(u8 *card_data, bool ascii, u16 SizeMb) +bool GCMemcard::Format(u8* card_data, bool ascii, u16 SizeMb) { - if (!card_data) - return false; - memset(card_data, 0xFF, BLOCK_SIZE*3); - memset(card_data + BLOCK_SIZE*3, 0, BLOCK_SIZE*2); + if (!card_data) + return false; + memset(card_data, 0xFF, BLOCK_SIZE * 3); + memset(card_data + BLOCK_SIZE * 3, 0, BLOCK_SIZE * 2); - *((Header *)card_data) = Header(SLOT_A, SizeMb, ascii); + *((Header*)card_data) = Header(SLOT_A, SizeMb, ascii); - *((Directory *)(card_data + BLOCK_SIZE)) = Directory(); - *((Directory *)(card_data + BLOCK_SIZE * 2)) = Directory(); - *((BlockAlloc *)(card_data + BLOCK_SIZE * 3)) = BlockAlloc(SizeMb); - *((BlockAlloc *)(card_data + BLOCK_SIZE * 4)) = BlockAlloc(SizeMb); - return true; + *((Directory*)(card_data + BLOCK_SIZE)) = Directory(); + *((Directory*)(card_data + BLOCK_SIZE * 2)) = Directory(); + *((BlockAlloc*)(card_data + BLOCK_SIZE * 3)) = BlockAlloc(SizeMb); + *((BlockAlloc*)(card_data + BLOCK_SIZE * 4)) = BlockAlloc(SizeMb); + return true; } bool GCMemcard::Format(bool ascii, u16 SizeMb) { - memset(&hdr, 0xFF, BLOCK_SIZE); - memset(&dir, 0xFF, BLOCK_SIZE); - memset(&dir_backup, 0xFF, BLOCK_SIZE); - memset(&bat, 0, BLOCK_SIZE); - memset(&bat_backup, 0, BLOCK_SIZE); + memset(&hdr, 0xFF, BLOCK_SIZE); + memset(&dir, 0xFF, BLOCK_SIZE); + memset(&dir_backup, 0xFF, BLOCK_SIZE); + memset(&bat, 0, BLOCK_SIZE); + memset(&bat_backup, 0, BLOCK_SIZE); - hdr = Header(SLOT_A, SizeMb, ascii); - dir = dir_backup = Directory(); - bat = bat_backup = BlockAlloc(SizeMb); + hdr = Header(SLOT_A, SizeMb, ascii); + dir = dir_backup = Directory(); + bat = bat_backup = BlockAlloc(SizeMb); - m_sizeMb = SizeMb; - maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS; - mc_data_blocks.clear(); - mc_data_blocks.resize(maxBlock - MC_FST_BLOCKS); + m_sizeMb = SizeMb; + maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS; + mc_data_blocks.clear(); + mc_data_blocks.resize(maxBlock - MC_FST_BLOCKS); - InitDirBatPointers(); - m_valid = true; + InitDirBatPointers(); + m_valid = true; - return Save(); + return Save(); } /*************************************************************/ @@ -1261,41 +1273,46 @@ bool GCMemcard::Format(bool ascii, u16 SizeMb) /* Returns: Error code */ /*************************************************************/ -s32 GCMemcard::FZEROGX_MakeSaveGameValid(Header &cardheader, DEntry &direntry, std::vector &FileBuffer) +s32 GCMemcard::FZEROGX_MakeSaveGameValid(Header& cardheader, DEntry& direntry, + std::vector& FileBuffer) { - u32 i,j; - u32 serial1,serial2; - u16 chksum = 0xFFFF; - int block = 0; + u32 i, j; + u32 serial1, serial2; + u16 chksum = 0xFFFF; + int block = 0; - // check for F-Zero GX system file - if (strcmp((char*)direntry.Filename,"f_zero.dat")!=0) return 0; + // check for F-Zero GX system file + if (strcmp((char*)direntry.Filename, "f_zero.dat") != 0) + return 0; - // get encrypted destination memory card serial numbers - cardheader.CARD_GetSerialNo(&serial1, &serial2); + // get encrypted destination memory card serial numbers + cardheader.CARD_GetSerialNo(&serial1, &serial2); - // set new serial numbers - *(u16*)&FileBuffer[1].block[0x0066] = BE16(BE32(serial1) >> 16); - *(u16*)&FileBuffer[3].block[0x1580] = BE16(BE32(serial2) >> 16); - *(u16*)&FileBuffer[1].block[0x0060] = BE16(BE32(serial1) & 0xFFFF); - *(u16*)&FileBuffer[1].block[0x0200] = BE16(BE32(serial2) & 0xFFFF); + // set new serial numbers + *(u16*)&FileBuffer[1].block[0x0066] = BE16(BE32(serial1) >> 16); + *(u16*)&FileBuffer[3].block[0x1580] = BE16(BE32(serial2) >> 16); + *(u16*)&FileBuffer[1].block[0x0060] = BE16(BE32(serial1) & 0xFFFF); + *(u16*)&FileBuffer[1].block[0x0200] = BE16(BE32(serial2) & 0xFFFF); - // calc 16-bit checksum - for (i=0x02;i<0x8000;i++) - { - chksum ^= (FileBuffer[block].block[i-(block*0x2000)]&0xFF); - for (j=8; j > 0; j--) - { - if (chksum&1) chksum = (chksum>>1)^0x8408; - else chksum >>= 1; - } - if (!(i%0x2000)) block ++; - } + // calc 16-bit checksum + for (i = 0x02; i < 0x8000; i++) + { + chksum ^= (FileBuffer[block].block[i - (block * 0x2000)] & 0xFF); + for (j = 8; j > 0; j--) + { + if (chksum & 1) + chksum = (chksum >> 1) ^ 0x8408; + else + chksum >>= 1; + } + if (!(i % 0x2000)) + block++; + } - // set new checksum - *(u16*)&FileBuffer[0].block[0x00] = BE16(~chksum); + // set new checksum + *(u16*)&FileBuffer[0].block[0x00] = BE16(~chksum); - return 1; + return 1; } /***********************************************************/ @@ -1309,63 +1326,64 @@ s32 GCMemcard::FZEROGX_MakeSaveGameValid(Header &cardheader, DEntry &direntry, s /* Returns: Error code */ /***********************************************************/ -s32 GCMemcard::PSO_MakeSaveGameValid(Header &cardheader, DEntry &direntry, std::vector &FileBuffer) +s32 GCMemcard::PSO_MakeSaveGameValid(Header& cardheader, DEntry& direntry, + std::vector& FileBuffer) { - u32 i,j; - u32 chksum; - u32 crc32LUT[256]; - u32 serial1,serial2; - u32 pso3offset = 0x00; + u32 i, j; + u32 chksum; + u32 crc32LUT[256]; + u32 serial1, serial2; + u32 pso3offset = 0x00; - // check for PSO1&2 system file - if (strcmp((char*)direntry.Filename,"PSO_SYSTEM")!=0) - { - // check for PSO3 system file - if (strcmp((char*)direntry.Filename,"PSO3_SYSTEM")==0) - { - // PSO3 data block size adjustment - pso3offset = 0x10; - } - else - { - // nothing to do - return 0; - } - } + // check for PSO1&2 system file + if (strcmp((char*)direntry.Filename, "PSO_SYSTEM") != 0) + { + // check for PSO3 system file + if (strcmp((char*)direntry.Filename, "PSO3_SYSTEM") == 0) + { + // PSO3 data block size adjustment + pso3offset = 0x10; + } + else + { + // nothing to do + return 0; + } + } - // get encrypted destination memory card serial numbers - cardheader.CARD_GetSerialNo(&serial1, &serial2); + // get encrypted destination memory card serial numbers + cardheader.CARD_GetSerialNo(&serial1, &serial2); - // set new serial numbers - *(u32*)&FileBuffer[1].block[0x0158] = serial1; - *(u32*)&FileBuffer[1].block[0x015C] = serial2; + // set new serial numbers + *(u32*)&FileBuffer[1].block[0x0158] = serial1; + *(u32*)&FileBuffer[1].block[0x015C] = serial2; - // generate crc32 LUT - for (i=0; i < 256; i++) - { - chksum = i; - for (j=8; j > 0; j--) - { - if (chksum & 1) - chksum = (chksum>>1)^0xEDB88320; - else - chksum >>= 1; - } + // generate crc32 LUT + for (i = 0; i < 256; i++) + { + chksum = i; + for (j = 8; j > 0; j--) + { + if (chksum & 1) + chksum = (chksum >> 1) ^ 0xEDB88320; + else + chksum >>= 1; + } - crc32LUT[i] = chksum; - } + crc32LUT[i] = chksum; + } - // PSO initial crc32 value - chksum = 0xDEBB20E3; + // PSO initial crc32 value + chksum = 0xDEBB20E3; - // calc 32-bit checksum - for (i=0x004C; i < 0x0164+pso3offset; i++) - { - chksum = ((chksum>>8)&0xFFFFFF)^crc32LUT[(chksum^FileBuffer[1].block[i])&0xFF]; - } + // calc 32-bit checksum + for (i = 0x004C; i < 0x0164 + pso3offset; i++) + { + chksum = ((chksum >> 8) & 0xFFFFFF) ^ crc32LUT[(chksum ^ FileBuffer[1].block[i]) & 0xFF]; + } - // set new checksum - *(u32*)&FileBuffer[1].block[0x0048] = BE32(chksum^0xFFFFFFFF); + // set new checksum + *(u32*)&FileBuffer[1].block[0x0048] = BE32(chksum ^ 0xFFFFFFFF); - return 1; + return 1; } diff --git a/Source/Core/Core/HW/GCMemcard.h b/Source/Core/Core/HW/GCMemcard.h index f5c9cbe2c7..b729e307df 100644 --- a/Source/Core/Core/HW/GCMemcard.h +++ b/Source/Core/Core/HW/GCMemcard.h @@ -18,396 +18,383 @@ #define BE64(x) (Common::swap64(x)) #define BE32(x) (Common::swap32(x)) #define BE16(x) (Common::swap16(x)) -#define ArrayByteSwap(a) (ByteSwap(a, a+sizeof(u8))); +#define ArrayByteSwap(a) (ByteSwap(a, a + sizeof(u8))); enum { - SLOT_A = 0, - SLOT_B = 1, - GCI = 0, - SUCCESS, - NOMEMCARD, - OPENFAIL, - OUTOFBLOCKS, - OUTOFDIRENTRIES, - LENGTHFAIL, - INVALIDFILESIZE, - TITLEPRESENT, - DIRLEN = 0x7F, - SAV = 0x80, - SAVFAIL, - GCS = 0x110, - GCSFAIL, - FAIL, - WRITEFAIL, - DELETE_FAIL, + SLOT_A = 0, + SLOT_B = 1, + GCI = 0, + SUCCESS, + NOMEMCARD, + OPENFAIL, + OUTOFBLOCKS, + OUTOFDIRENTRIES, + LENGTHFAIL, + INVALIDFILESIZE, + TITLEPRESENT, + DIRLEN = 0x7F, + SAV = 0x80, + SAVFAIL, + GCS = 0x110, + GCSFAIL, + FAIL, + WRITEFAIL, + DELETE_FAIL, - MC_FST_BLOCKS = 0x05, - MBIT_TO_BLOCKS = 0x10, - DENTRY_STRLEN = 0x20, - DENTRY_SIZE = 0x40, - BLOCK_SIZE = 0x2000, - BAT_SIZE = 0xFFB, + MC_FST_BLOCKS = 0x05, + MBIT_TO_BLOCKS = 0x10, + DENTRY_STRLEN = 0x20, + DENTRY_SIZE = 0x40, + BLOCK_SIZE = 0x2000, + BAT_SIZE = 0xFFB, - MemCard59Mb = 0x04, - MemCard123Mb = 0x08, - MemCard251Mb = 0x10, - Memcard507Mb = 0x20, - MemCard1019Mb = 0x40, - MemCard2043Mb = 0x80, + MemCard59Mb = 0x04, + MemCard123Mb = 0x08, + MemCard251Mb = 0x10, + Memcard507Mb = 0x20, + MemCard1019Mb = 0x40, + MemCard2043Mb = 0x80, - CI8SHARED = 1, - RGB5A3, - CI8, + CI8SHARED = 1, + RGB5A3, + CI8, }; class MemoryCardBase { public: - MemoryCardBase(int _card_index = 0, int sizeMb = MemCard2043Mb) - : card_index(_card_index) - , nintendo_card_id(sizeMb) - { - } - virtual ~MemoryCardBase() {} - virtual s32 Read(u32 address, s32 length, u8 *destaddress) = 0; - virtual s32 Write(u32 destaddress, s32 length, u8 *srcaddress) = 0; - virtual void ClearBlock(u32 address) = 0; - virtual void ClearAll() = 0; - virtual void DoState(PointerWrap &p) = 0; - u32 GetCardId() const { return nintendo_card_id; } - bool IsAddressInBounds(u32 address) const - { - return address <= (memory_card_size - 1); - } - + MemoryCardBase(int _card_index = 0, int sizeMb = MemCard2043Mb) + : card_index(_card_index), nintendo_card_id(sizeMb) + { + } + virtual ~MemoryCardBase() {} + virtual s32 Read(u32 address, s32 length, u8* destaddress) = 0; + virtual s32 Write(u32 destaddress, s32 length, u8* srcaddress) = 0; + virtual void ClearBlock(u32 address) = 0; + virtual void ClearAll() = 0; + virtual void DoState(PointerWrap& p) = 0; + u32 GetCardId() const { return nintendo_card_id; } + bool IsAddressInBounds(u32 address) const { return address <= (memory_card_size - 1); } protected: - int card_index; - u16 nintendo_card_id; - u32 memory_card_size; + int card_index; + u16 nintendo_card_id; + u32 memory_card_size; }; struct GCMBlock { - GCMBlock() - { - Erase(); - } - - void Erase() - { - memset(block, 0xFF, BLOCK_SIZE); - } - - u8 block[BLOCK_SIZE]; + GCMBlock() { Erase(); } + void Erase() { memset(block, 0xFF, BLOCK_SIZE); } + u8 block[BLOCK_SIZE]; }; -void calc_checksumsBE(u16 *buf, u32 length, u16 *csum, u16 *inv_csum); +void calc_checksumsBE(u16* buf, u32 length, u16* csum, u16* inv_csum); -#pragma pack(push,1) -struct Header //Offset Size Description +#pragma pack(push, 1) +struct Header // Offset Size Description { - // Serial in libogc - u8 serial[12]; //0x0000 12 ? - u64 formatTime; //0x000c 8 Time of format (OSTime value) - u32 SramBias; //0x0014 4 SRAM bias at time of format - u32 SramLang; //0x0018 4 SRAM language - u8 Unk2[4]; //0x001c 4 ? almost always 0 - // end Serial in libogc - u8 deviceID[2]; //0x0020 2 0 if formated in slot A 1 if formated in slot B - u8 SizeMb[2]; //0x0022 2 Size of memcard in Mbits - u16 Encoding; //0x0024 2 Encoding (ASCII or Japanese) - u8 Unused1[468]; //0x0026 468 Unused (0xff) - u16 UpdateCounter; //0x01fa 2 Update Counter (?, probably unused) - u16 Checksum; //0x01fc 2 Additive Checksum - u16 Checksum_Inv; //0x01fe 2 Inverse Checksum - u8 Unused2[7680]; //0x0200 0x1e00 Unused (0xff) + // Serial in libogc + u8 serial[12]; // 0x0000 12 ? + u64 formatTime; // 0x000c 8 Time of format (OSTime value) + u32 SramBias; // 0x0014 4 SRAM bias at time of format + u32 SramLang; // 0x0018 4 SRAM language + u8 Unk2[4]; // 0x001c 4 ? almost always 0 + // end Serial in libogc + u8 deviceID[2]; // 0x0020 2 0 if formated in slot A 1 if formated in slot B + u8 SizeMb[2]; // 0x0022 2 Size of memcard in Mbits + u16 Encoding; // 0x0024 2 Encoding (ASCII or Japanese) + u8 Unused1[468]; // 0x0026 468 Unused (0xff) + u16 UpdateCounter; // 0x01fa 2 Update Counter (?, probably unused) + u16 Checksum; // 0x01fc 2 Additive Checksum + u16 Checksum_Inv; // 0x01fe 2 Inverse Checksum + u8 Unused2[7680]; // 0x0200 0x1e00 Unused (0xff) + void CARD_GetSerialNo(u32* serial1, u32* serial2) const + { + u32 _serial[8]; - void CARD_GetSerialNo(u32 *serial1, u32 *serial2) const - { - u32 _serial[8]; + for (int i = 0; i < 8; i++) + { + memcpy(&_serial[i], (u8*)this + (i * 4), 4); + } - for (int i = 0; i < 8; i++) - { - memcpy(&_serial[i], (u8 *)this + (i * 4), 4); - } + *serial1 = _serial[0] ^ _serial[2] ^ _serial[4] ^ _serial[6]; + *serial2 = _serial[1] ^ _serial[3] ^ _serial[5] ^ _serial[7]; + } - *serial1 = _serial[0] ^ _serial[2] ^ _serial[4] ^ _serial[6]; - *serial2 = _serial[1] ^ _serial[3] ^ _serial[5] ^ _serial[7]; - } - - // Nintendo format algorithm. - // Constants are fixed by the GC SDK - // Changing the constants will break memory card support - Header(int slot = 0, u16 sizeMb = MemCard2043Mb, bool ascii = true) - { - memset(this, 0xFF, BLOCK_SIZE); - *(u16 *)SizeMb = BE16(sizeMb); - Encoding = BE16(ascii ? 0 : 1); - u64 rand = CEXIIPL::GetGCTime(); - formatTime = Common::swap64(rand); - for (int i = 0; i < 12; i++) - { - rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); - serial[i] = (u8)(g_SRAM.flash_id[slot][i] + (u32)rand); - rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); - rand &= (u64)0x0000000000007fffULL; - } - SramBias = g_SRAM.counter_bias; - SramLang = BE32(g_SRAM.lang); - // TODO: determine the purpose of Unk2 1 works for slot A, 0 works for both slot A and slot B - *(u32 *)&Unk2 = 0; // = _viReg[55]; static vu16* const _viReg = (u16*)0xCC002000; - *(u16 *)&deviceID = 0; - calc_checksumsBE((u16 *)this, 0xFE, &Checksum, &Checksum_Inv); - } + // Nintendo format algorithm. + // Constants are fixed by the GC SDK + // Changing the constants will break memory card support + Header(int slot = 0, u16 sizeMb = MemCard2043Mb, bool ascii = true) + { + memset(this, 0xFF, BLOCK_SIZE); + *(u16*)SizeMb = BE16(sizeMb); + Encoding = BE16(ascii ? 0 : 1); + u64 rand = CEXIIPL::GetGCTime(); + formatTime = Common::swap64(rand); + for (int i = 0; i < 12; i++) + { + rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); + serial[i] = (u8)(g_SRAM.flash_id[slot][i] + (u32)rand); + rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); + rand &= (u64)0x0000000000007fffULL; + } + SramBias = g_SRAM.counter_bias; + SramLang = BE32(g_SRAM.lang); + // TODO: determine the purpose of Unk2 1 works for slot A, 0 works for both slot A and slot B + *(u32*)&Unk2 = 0; // = _viReg[55]; static vu16* const _viReg = (u16*)0xCC002000; + *(u16*)&deviceID = 0; + calc_checksumsBE((u16*)this, 0xFE, &Checksum, &Checksum_Inv); + } }; struct DEntry { - static const u8 DENTRY_SIZE = 0x40; - DEntry() { memset(this, 0xFF, DENTRY_SIZE); } - std::string GCI_FileName() const - { - std::string filename = std::string((char *)Makercode, 2) + '-' + std::string((char *)Gamecode, 4) + '-' + (char *)Filename + - ".gci"; - static Common::replace_v replacements; - if (replacements.size() == 0) - { - Common::ReadReplacements(replacements); - // Cannot add \r to replacements file due to it being a line ending char - // / might be ok, but we need to verify that this is only used on filenames - // as it is a dir_sep - replacements.push_back(std::make_pair('\r', std::string("__0d__"))); - replacements.push_back(std::make_pair('/', std::string("__2f__"))); + static const u8 DENTRY_SIZE = 0x40; + DEntry() { memset(this, 0xFF, DENTRY_SIZE); } + std::string GCI_FileName() const + { + std::string filename = std::string((char*)Makercode, 2) + '-' + + std::string((char*)Gamecode, 4) + '-' + (char*)Filename + ".gci"; + static Common::replace_v replacements; + if (replacements.size() == 0) + { + Common::ReadReplacements(replacements); + // Cannot add \r to replacements file due to it being a line ending char + // / might be ok, but we need to verify that this is only used on filenames + // as it is a dir_sep + replacements.push_back(std::make_pair('\r', std::string("__0d__"))); + replacements.push_back(std::make_pair('/', std::string("__2f__"))); + } - } + // Replaces chars that FAT32 can't support with strings defined in /sys/replace + for (auto& replacement : replacements) + { + for (size_t j = 0; (j = filename.find(replacement.first, j)) != filename.npos; ++j) + filename.replace(j, 1, replacement.second); + } + return filename; + } - // Replaces chars that FAT32 can't support with strings defined in /sys/replace - for (auto& replacement : replacements) - { - for (size_t j = 0; (j = filename.find(replacement.first, j)) != filename.npos; ++j) - filename.replace(j, 1, replacement.second); - } - return filename; - } - - u8 Gamecode[4]; //0x00 0x04 Gamecode - u8 Makercode[2]; //0x04 0x02 Makercode - u8 Unused1; //0x06 0x01 reserved/unused (always 0xff, has no effect) - u8 BIFlags; //0x07 0x01 banner gfx format and icon animation (Image Key) - // Bit(s) Description - // 2 Icon Animation 0: forward 1: ping-pong - // 1 [--0: No Banner 1: Banner present--] WRONG! YAGCD LIES! - // 0 [--Banner Color 0: RGB5A3 1: CI8--] WRONG! YAGCD LIES! - // bits 0 and 1: image format - // 00 no banner - // 01 CI8 banner - // 10 RGB5A3 banner - // 11 ? maybe ==00? Time Splitters 2 and 3 have it and don't have banner - // - u8 Filename[DENTRY_STRLEN]; //0x08 0x20 Filename - u8 ModTime[4]; //0x28 0x04 Time of file's last modification in seconds since 12am, January 1st, 2000 - u8 ImageOffset[4]; //0x2c 0x04 image data offset - u8 IconFmt[2]; //0x30 0x02 icon gfx format (2bits per icon) - // Bits Description - // 00 No icon - // 01 CI8 with a shared color palette after the last frame - // 10 RGB5A3 - // 11 CI8 with a unique color palette after itself - // - u8 AnimSpeed[2]; //0x32 0x02 Animation speed (2bits per icon) (*1) - // Bits Description - // 00 No icon - // 01 Icon lasts for 4 frames - // 10 Icon lasts for 8 frames - // 11 Icon lasts for 12 frames - // - u8 Permissions; //0x34 0x01 File-permissions - // Bit Permission Description - // 4 no move File cannot be moved by the IPL - // 3 no copy File cannot be copied by the IPL - // 2 public Can be read by any game - // - u8 CopyCounter; //0x35 0x01 Copy counter (*2) - u8 FirstBlock[2]; //0x36 0x02 Block no of first block of file (0 == offset 0) - u8 BlockCount[2]; //0x38 0x02 File-length (number of blocks in file) - u8 Unused2[2]; //0x3a 0x02 Reserved/unused (always 0xffff, has no effect) - u8 CommentsAddr[4]; //0x3c 0x04 Address of the two comments within the file data (*3) + u8 Gamecode[4]; // 0x00 0x04 Gamecode + u8 Makercode[2]; // 0x04 0x02 Makercode + u8 Unused1; // 0x06 0x01 reserved/unused (always 0xff, has no effect) + u8 BIFlags; // 0x07 0x01 banner gfx format and icon animation (Image Key) + // Bit(s) Description + // 2 Icon Animation 0: forward 1: ping-pong + // 1 [--0: No Banner 1: Banner present--] WRONG! YAGCD LIES! + // 0 [--Banner Color 0: RGB5A3 1: CI8--] WRONG! YAGCD LIES! + // bits 0 and 1: image format + // 00 no banner + // 01 CI8 banner + // 10 RGB5A3 banner + // 11 ? maybe ==00? Time Splitters 2 and 3 have it and don't have banner + // + u8 Filename[DENTRY_STRLEN]; // 0x08 0x20 Filename + u8 ModTime[4]; // 0x28 0x04 Time of file's last modification in seconds since 12am, + // January 1st, 2000 + u8 ImageOffset[4]; // 0x2c 0x04 image data offset + u8 IconFmt[2]; // 0x30 0x02 icon gfx format (2bits per icon) + // Bits Description + // 00 No icon + // 01 CI8 with a shared color palette after the last frame + // 10 RGB5A3 + // 11 CI8 with a unique color palette after itself + // + u8 AnimSpeed[2]; // 0x32 0x02 Animation speed (2bits per icon) (*1) + // Bits Description + // 00 No icon + // 01 Icon lasts for 4 frames + // 10 Icon lasts for 8 frames + // 11 Icon lasts for 12 frames + // + u8 Permissions; // 0x34 0x01 File-permissions + // Bit Permission Description + // 4 no move File cannot be moved by the IPL + // 3 no copy File cannot be copied by the IPL + // 2 public Can be read by any game + // + u8 CopyCounter; // 0x35 0x01 Copy counter (*2) + u8 FirstBlock[2]; // 0x36 0x02 Block no of first block of file (0 == offset 0) + u8 BlockCount[2]; // 0x38 0x02 File-length (number of blocks in file) + u8 Unused2[2]; // 0x3a 0x02 Reserved/unused (always 0xffff, has no effect) + u8 CommentsAddr[4]; // 0x3c 0x04 Address of the two comments within the file data (*3) }; struct Directory { - DEntry Dir[DIRLEN]; //0x0000 Directory Entries (max 127) - u8 Padding[0x3a]; - u16 UpdateCounter; //0x1ffa 2 Update Counter - u16 Checksum; //0x1ffc 2 Additive Checksum - u16 Checksum_Inv; //0x1ffe 2 Inverse Checksum - Directory() - { - memset(this, 0xFF, BLOCK_SIZE); - UpdateCounter = 0; - Checksum = BE16(0xF003); - Checksum_Inv = 0; - } - void Replace(DEntry d, int idx) - { - Dir[idx] = d; - fixChecksums(); - } - void fixChecksums() { calc_checksumsBE((u16 *)this, 0xFFE, &Checksum, &Checksum_Inv); } + DEntry Dir[DIRLEN]; // 0x0000 Directory Entries (max 127) + u8 Padding[0x3a]; + u16 UpdateCounter; // 0x1ffa 2 Update Counter + u16 Checksum; // 0x1ffc 2 Additive Checksum + u16 Checksum_Inv; // 0x1ffe 2 Inverse Checksum + Directory() + { + memset(this, 0xFF, BLOCK_SIZE); + UpdateCounter = 0; + Checksum = BE16(0xF003); + Checksum_Inv = 0; + } + void Replace(DEntry d, int idx) + { + Dir[idx] = d; + fixChecksums(); + } + void fixChecksums() { calc_checksumsBE((u16*)this, 0xFFE, &Checksum, &Checksum_Inv); } }; struct BlockAlloc { - u16 Checksum; //0x0000 2 Additive Checksum - u16 Checksum_Inv; //0x0002 2 Inverse Checksum - u16 UpdateCounter; //0x0004 2 Update Counter - u16 FreeBlocks; //0x0006 2 Free Blocks - u16 LastAllocated; //0x0008 2 Last allocated Block - u16 Map[BAT_SIZE]; //0x000a 0x1ff8 Map of allocated Blocks - u16 GetNextBlock(u16 Block) const; - u16 NextFreeBlock(u16 MaxBlock, u16 StartingBlock = MC_FST_BLOCKS) const; - bool ClearBlocks(u16 StartingBlock, u16 Length); - void fixChecksums() { calc_checksumsBE((u16 *)&UpdateCounter, 0xFFE, &Checksum, &Checksum_Inv); } - BlockAlloc(u16 sizeMb = MemCard2043Mb) - { - memset(this, 0, BLOCK_SIZE); - // UpdateCounter = 0; - FreeBlocks = BE16((sizeMb * MBIT_TO_BLOCKS) - MC_FST_BLOCKS); - LastAllocated = BE16(4); - fixChecksums(); - } - u16 AssignBlocksContiguous(u16 length) - { - u16 starting = BE16(LastAllocated) + 1; - if (length > BE16(FreeBlocks)) - return 0xFFFF; - u16 current = starting; - while ((current - starting + 1) < length) - { - Map[current - 5] = BE16(current + 1); - current++; - } - Map[current - 5] = 0xFFFF; - LastAllocated = BE16(current); - FreeBlocks = BE16(BE16(FreeBlocks) - length); - fixChecksums(); - return BE16(starting); - } + u16 Checksum; // 0x0000 2 Additive Checksum + u16 Checksum_Inv; // 0x0002 2 Inverse Checksum + u16 UpdateCounter; // 0x0004 2 Update Counter + u16 FreeBlocks; // 0x0006 2 Free Blocks + u16 LastAllocated; // 0x0008 2 Last allocated Block + u16 Map[BAT_SIZE]; // 0x000a 0x1ff8 Map of allocated Blocks + u16 GetNextBlock(u16 Block) const; + u16 NextFreeBlock(u16 MaxBlock, u16 StartingBlock = MC_FST_BLOCKS) const; + bool ClearBlocks(u16 StartingBlock, u16 Length); + void fixChecksums() { calc_checksumsBE((u16*)&UpdateCounter, 0xFFE, &Checksum, &Checksum_Inv); } + BlockAlloc(u16 sizeMb = MemCard2043Mb) + { + memset(this, 0, BLOCK_SIZE); + // UpdateCounter = 0; + FreeBlocks = BE16((sizeMb * MBIT_TO_BLOCKS) - MC_FST_BLOCKS); + LastAllocated = BE16(4); + fixChecksums(); + } + u16 AssignBlocksContiguous(u16 length) + { + u16 starting = BE16(LastAllocated) + 1; + if (length > BE16(FreeBlocks)) + return 0xFFFF; + u16 current = starting; + while ((current - starting + 1) < length) + { + Map[current - 5] = BE16(current + 1); + current++; + } + Map[current - 5] = 0xFFFF; + LastAllocated = BE16(current); + FreeBlocks = BE16(BE16(FreeBlocks) - length); + fixChecksums(); + return BE16(starting); + } }; #pragma pack(pop) class GCIFile { public: - bool LoadSaveBlocks(); - bool HasCopyProtection() const - { - if ((strcmp((char*)m_gci_header.Filename, "PSO_SYSTEM") == 0) || - (strcmp((char*)m_gci_header.Filename, "PSO3_SYSTEM") == 0) || - (strcmp((char*)m_gci_header.Filename, "f_zero.dat") == 0)) - return true; - return false; - } + bool LoadSaveBlocks(); + bool HasCopyProtection() const + { + if ((strcmp((char*)m_gci_header.Filename, "PSO_SYSTEM") == 0) || + (strcmp((char*)m_gci_header.Filename, "PSO3_SYSTEM") == 0) || + (strcmp((char*)m_gci_header.Filename, "f_zero.dat") == 0)) + return true; + return false; + } - void DoState(PointerWrap &p); - DEntry m_gci_header; - std::vector m_save_data; - std::vector m_used_blocks; - int UsesBlock(u16 blocknum); - bool m_dirty; - std::string m_filename; + void DoState(PointerWrap& p); + DEntry m_gci_header; + std::vector m_save_data; + std::vector m_used_blocks; + int UsesBlock(u16 blocknum); + bool m_dirty; + std::string m_filename; }; class GCMemcard : NonCopyable { private: - bool m_valid; - std::string m_fileName; + bool m_valid; + std::string m_fileName; - u32 maxBlock; - u16 m_sizeMb; + u32 maxBlock; + u16 m_sizeMb; - Header hdr; - Directory dir, dir_backup, *CurrentDir, *PreviousDir; - BlockAlloc bat, bat_backup, *CurrentBat, *PreviousBat; + Header hdr; + Directory dir, dir_backup, *CurrentDir, *PreviousDir; + BlockAlloc bat, bat_backup, *CurrentBat, *PreviousBat; - std::vector mc_data_blocks; + std::vector mc_data_blocks; - u32 ImportGciInternal(FILE* gcih, const std::string& inputFile, const std::string &outputFile); - void InitDirBatPointers(); + u32 ImportGciInternal(FILE* gcih, const std::string& inputFile, const std::string& outputFile); + void InitDirBatPointers(); public: + GCMemcard(const std::string& fileName, bool forceCreation = false, bool sjis = false); + bool IsValid() const { return m_valid; } + bool IsAsciiEncoding() const; + bool Save(); + bool Format(bool ascii = true, u16 SizeMb = MemCard2043Mb); + static bool Format(u8* card_data, bool ascii = true, u16 SizeMb = MemCard2043Mb); + static s32 FZEROGX_MakeSaveGameValid(Header& cardheader, DEntry& direntry, + std::vector& FileBuffer); + static s32 PSO_MakeSaveGameValid(Header& cardheader, DEntry& direntry, + std::vector& FileBuffer); - GCMemcard(const std::string& fileName, bool forceCreation=false, bool sjis=false); - bool IsValid() const { return m_valid; } - bool IsAsciiEncoding() const; - bool Save(); - bool Format(bool ascii = true, u16 SizeMb = MemCard2043Mb); - static bool Format(u8 *card_data, bool ascii = true, u16 SizeMb = MemCard2043Mb); - static s32 FZEROGX_MakeSaveGameValid(Header &cardheader, DEntry &direntry, std::vector &FileBuffer); - static s32 PSO_MakeSaveGameValid(Header &cardheader, DEntry &direntry, std::vector &FileBuffer); + u32 TestChecksums() const; + bool FixChecksums(); - u32 TestChecksums() const; - bool FixChecksums(); + // get number of file entries in the directory + u8 GetNumFiles() const; + u8 GetFileIndex(u8 fileNumber) const; - // get number of file entries in the directory - u8 GetNumFiles() const; - u8 GetFileIndex(u8 fileNumber) const; + // get the free blocks from bat + u16 GetFreeBlocks() const; - // get the free blocks from bat - u16 GetFreeBlocks() const; + // If title already on memcard returns index, otherwise returns -1 + u8 TitlePresent(const DEntry& d) const; - // If title already on memcard returns index, otherwise returns -1 - u8 TitlePresent(const DEntry& d) const; + bool GCI_FileName(u8 index, std::string& filename) const; + // DEntry functions, all take u8 index < DIRLEN (127) + std::string DEntry_GameCode(u8 index) const; + std::string DEntry_Makercode(u8 index) const; + std::string DEntry_BIFlags(u8 index) const; + std::string DEntry_FileName(u8 index) const; + u32 DEntry_ModTime(u8 index) const; + u32 DEntry_ImageOffset(u8 index) const; + std::string DEntry_IconFmt(u8 index) const; + std::string DEntry_AnimSpeed(u8 index) const; + std::string DEntry_Permissions(u8 index) const; + u8 DEntry_CopyCounter(u8 index) const; + // get first block for file + u16 DEntry_FirstBlock(u8 index) const; + // get file length in blocks + u16 DEntry_BlockCount(u8 index) const; + u32 DEntry_CommentsAddress(u8 index) const; + std::string GetSaveComment1(u8 index) const; + std::string GetSaveComment2(u8 index) const; + // Copies a DEntry from u8 index to DEntry& data + bool GetDEntry(u8 index, DEntry& dest) const; - bool GCI_FileName(u8 index, std::string &filename) const; - // DEntry functions, all take u8 index < DIRLEN (127) - std::string DEntry_GameCode(u8 index) const; - std::string DEntry_Makercode(u8 index) const; - std::string DEntry_BIFlags(u8 index) const; - std::string DEntry_FileName(u8 index) const; - u32 DEntry_ModTime(u8 index) const; - u32 DEntry_ImageOffset(u8 index) const; - std::string DEntry_IconFmt(u8 index) const; - std::string DEntry_AnimSpeed(u8 index) const; - std::string DEntry_Permissions(u8 index) const; - u8 DEntry_CopyCounter(u8 index) const; - // get first block for file - u16 DEntry_FirstBlock(u8 index) const; - // get file length in blocks - u16 DEntry_BlockCount(u8 index) const; - u32 DEntry_CommentsAddress(u8 index) const; - std::string GetSaveComment1(u8 index) const; - std::string GetSaveComment2(u8 index) const; - // Copies a DEntry from u8 index to DEntry& data - bool GetDEntry(u8 index, DEntry &dest) const; + u32 GetSaveData(u8 index, std::vector& saveBlocks) const; - u32 GetSaveData(u8 index, std::vector &saveBlocks) const; + // adds the file to the directory and copies its contents + u32 ImportFile(DEntry& direntry, std::vector& saveBlocks); - // adds the file to the directory and copies its contents - u32 ImportFile(DEntry& direntry, std::vector &saveBlocks); + // delete a file from the directory + u32 RemoveFile(u8 index); - // delete a file from the directory - u32 RemoveFile(u8 index); + // reads a save from another memcard, and imports the data into this memcard + u32 CopyFrom(const GCMemcard& source, u8 index); - // reads a save from another memcard, and imports the data into this memcard - u32 CopyFrom(const GCMemcard& source, u8 index); + // reads a .gci/.gcs/.sav file and calls ImportFile or saves out a gci file + u32 ImportGci(const std::string& inputFile, const std::string& outputFile); - // reads a .gci/.gcs/.sav file and calls ImportFile or saves out a gci file - u32 ImportGci(const std::string& inputFile,const std::string &outputFile); + // writes a .gci file to disk containing index + u32 ExportGci(u8 index, const std::string& fileName, const std::string& directory) const; - // writes a .gci file to disk containing index - u32 ExportGci(u8 index, const std::string& fileName, const std::string &directory) const; + // GCI files are untouched, SAV files are byteswapped + // GCS files have the block count set, default is 1 (For export as GCS) + static void Gcs_SavConvert(DEntry& tempDEntry, int saveType, int length = BLOCK_SIZE); - // GCI files are untouched, SAV files are byteswapped - // GCS files have the block count set, default is 1 (For export as GCS) - static void Gcs_SavConvert(DEntry &tempDEntry, int saveType, int length = BLOCK_SIZE); + // reads the banner image + bool ReadBannerRGBA8(u8 index, u32* buffer) const; - // reads the banner image - bool ReadBannerRGBA8(u8 index, u32* buffer) const; - - // reads the animation frames - u32 ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const; + // reads the animation frames + u32 ReadAnimRGBA8(u8 index, u32* buffer, u8* delays) const; }; diff --git a/Source/Core/Core/HW/GCMemcardDirectory.cpp b/Source/Core/Core/HW/GCMemcardDirectory.cpp index ddbf543080..029cdeaa68 100644 --- a/Source/Core/Core/HW/GCMemcardDirectory.cpp +++ b/Source/Core/Core/HW/GCMemcardDirectory.cpp @@ -13,715 +13,721 @@ #include "Common/CommonTypes.h" #include "Common/FileSearch.h" #include "Common/FileUtil.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/Thread.h" -#include "Common/Logging/Log.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/HW/GCMemcardDirectory.h" #include "DiscIO/Volume.h" const int NO_INDEX = -1; -static const char *MC_HDR = "MC_SYSTEM_AREA"; +static const char* MC_HDR = "MC_SYSTEM_AREA"; -int GCMemcardDirectory::LoadGCI(const std::string& fileName, DiscIO::IVolume::ECountry card_region, bool currentGameOnly) +int GCMemcardDirectory::LoadGCI(const std::string& fileName, DiscIO::IVolume::ECountry card_region, + bool currentGameOnly) { - File::IOFile gcifile(fileName, "rb"); - if (gcifile) - { - GCIFile gci; - gci.m_filename = fileName; - gci.m_dirty = false; - if (!gcifile.ReadBytes(&(gci.m_gci_header), DENTRY_SIZE)) - { - ERROR_LOG(EXPANSIONINTERFACE, "%s failed to read header", fileName.c_str()); - return NO_INDEX; - } + File::IOFile gcifile(fileName, "rb"); + if (gcifile) + { + GCIFile gci; + gci.m_filename = fileName; + gci.m_dirty = false; + if (!gcifile.ReadBytes(&(gci.m_gci_header), DENTRY_SIZE)) + { + ERROR_LOG(EXPANSIONINTERFACE, "%s failed to read header", fileName.c_str()); + return NO_INDEX; + } - DiscIO::IVolume::ECountry gci_region; - // check region - switch (gci.m_gci_header.Gamecode[3]) - { - case 'J': - gci_region = DiscIO::IVolume::COUNTRY_JAPAN; - break; - case 'E': - gci_region = DiscIO::IVolume::COUNTRY_USA; - break; - case 'C': - // Used by Datel Action Replay Save - // can be on any regions card - gci_region = card_region; - break; - default: - gci_region = DiscIO::IVolume::COUNTRY_EUROPE; - break; - } + DiscIO::IVolume::ECountry gci_region; + // check region + switch (gci.m_gci_header.Gamecode[3]) + { + case 'J': + gci_region = DiscIO::IVolume::COUNTRY_JAPAN; + break; + case 'E': + gci_region = DiscIO::IVolume::COUNTRY_USA; + break; + case 'C': + // Used by Datel Action Replay Save + // can be on any regions card + gci_region = card_region; + break; + default: + gci_region = DiscIO::IVolume::COUNTRY_EUROPE; + break; + } - if (gci_region != card_region) - { - PanicAlertT("GCI save file was not loaded because it is the wrong region for this memory card:\n%s", - fileName.c_str()); - return NO_INDEX; - } + if (gci_region != card_region) + { + PanicAlertT( + "GCI save file was not loaded because it is the wrong region for this memory card:\n%s", + fileName.c_str()); + return NO_INDEX; + } - std::string gci_filename = gci.m_gci_header.GCI_FileName(); - for (u16 i = 0; i < m_loaded_saves.size(); ++i) - { - if (m_loaded_saves[i] == gci_filename) - { - PanicAlertT( - "%s\nwas not loaded because it has the same internal filename as previously loaded save\n%s", - gci.m_filename.c_str(), m_saves[i].m_filename.c_str()); - return NO_INDEX; - } - } + std::string gci_filename = gci.m_gci_header.GCI_FileName(); + for (u16 i = 0; i < m_loaded_saves.size(); ++i) + { + if (m_loaded_saves[i] == gci_filename) + { + PanicAlertT("%s\nwas not loaded because it has the same internal filename as previously " + "loaded save\n%s", + gci.m_filename.c_str(), m_saves[i].m_filename.c_str()); + return NO_INDEX; + } + } - u16 numBlocks = BE16(gci.m_gci_header.BlockCount); - // largest number of free blocks on a memory card - // in reality, there are not likely any valid gci files > 251 blocks - if (numBlocks > 2043) - { - PanicAlertT("%s\nwas not loaded because it is an invalid GCI.\n Number of blocks claimed to be %u", - gci.m_filename.c_str(), numBlocks); - return NO_INDEX; - } + u16 numBlocks = BE16(gci.m_gci_header.BlockCount); + // largest number of free blocks on a memory card + // in reality, there are not likely any valid gci files > 251 blocks + if (numBlocks > 2043) + { + PanicAlertT( + "%s\nwas not loaded because it is an invalid GCI.\n Number of blocks claimed to be %u", + gci.m_filename.c_str(), numBlocks); + return NO_INDEX; + } - u32 size = numBlocks * BLOCK_SIZE; - u64 file_size = gcifile.GetSize(); - if (file_size != size + DENTRY_SIZE) - { - PanicAlertT("%s\nwas not loaded because it is an invalid GCI.\n File size (0x%" PRIx64 - ") does not match the size recorded in the header (0x%x)", - gci.m_filename.c_str(), file_size, size + DENTRY_SIZE); - return NO_INDEX; - } + u32 size = numBlocks * BLOCK_SIZE; + u64 file_size = gcifile.GetSize(); + if (file_size != size + DENTRY_SIZE) + { + PanicAlertT("%s\nwas not loaded because it is an invalid GCI.\n File size (0x%" PRIx64 + ") does not match the size recorded in the header (0x%x)", + gci.m_filename.c_str(), file_size, size + DENTRY_SIZE); + return NO_INDEX; + } - if (m_GameId == BE32(gci.m_gci_header.Gamecode)) - { - gci.LoadSaveBlocks(); - } - else - { - if (currentGameOnly) - { - return NO_INDEX; - } - int totalBlocks = BE16(m_hdr.SizeMb)*MBIT_TO_BLOCKS - MC_FST_BLOCKS; - int freeBlocks = BE16(m_bat1.FreeBlocks); - if (totalBlocks > freeBlocks * 10) - { + if (m_GameId == BE32(gci.m_gci_header.Gamecode)) + { + gci.LoadSaveBlocks(); + } + else + { + if (currentGameOnly) + { + return NO_INDEX; + } + int totalBlocks = BE16(m_hdr.SizeMb) * MBIT_TO_BLOCKS - MC_FST_BLOCKS; + int freeBlocks = BE16(m_bat1.FreeBlocks); + if (totalBlocks > freeBlocks * 10) + { + PanicAlertT("%s\nwas not loaded because there is less than 10%% free blocks available on " + "the memory card\n" + "Total Blocks: %d; Free Blocks: %d", + gci.m_filename.c_str(), totalBlocks, freeBlocks); + return NO_INDEX; + } + } + u16 first_block = m_bat1.AssignBlocksContiguous(numBlocks); + if (first_block == 0xFFFF) + { + PanicAlertT( + "%s\nwas not loaded because there are not enough free blocks on the virtual memory card", + fileName.c_str()); + return NO_INDEX; + } + *(u16*)&gci.m_gci_header.FirstBlock = first_block; + if (gci.HasCopyProtection() && gci.LoadSaveBlocks()) + { + GCMemcard::PSO_MakeSaveGameValid(m_hdr, gci.m_gci_header, gci.m_save_data); + GCMemcard::FZEROGX_MakeSaveGameValid(m_hdr, gci.m_gci_header, gci.m_save_data); + } + int idx = (int)m_saves.size(); + m_dir1.Replace(gci.m_gci_header, idx); + m_saves.push_back(std::move(gci)); + SetUsedBlocks(idx); - PanicAlertT("%s\nwas not loaded because there is less than 10%% free blocks available on the memory card\n"\ - "Total Blocks: %d; Free Blocks: %d", - gci.m_filename.c_str(), totalBlocks, freeBlocks); - return NO_INDEX; - } - } - u16 first_block = m_bat1.AssignBlocksContiguous(numBlocks); - if (first_block == 0xFFFF) - { - PanicAlertT("%s\nwas not loaded because there are not enough free blocks on the virtual memory card", - fileName.c_str()); - return NO_INDEX; - } - *(u16 *)&gci.m_gci_header.FirstBlock = first_block; - if (gci.HasCopyProtection() && gci.LoadSaveBlocks()) - { - - GCMemcard::PSO_MakeSaveGameValid(m_hdr, gci.m_gci_header, gci.m_save_data); - GCMemcard::FZEROGX_MakeSaveGameValid(m_hdr, gci.m_gci_header, gci.m_save_data); - } - int idx = (int)m_saves.size(); - m_dir1.Replace(gci.m_gci_header, idx); - m_saves.push_back(std::move(gci)); - SetUsedBlocks(idx); - - return idx; - } - return NO_INDEX; + return idx; + } + return NO_INDEX; } -GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot, u16 sizeMb, bool ascii, DiscIO::IVolume::ECountry card_region, int gameId) - : MemoryCardBase(slot, sizeMb) - , m_GameId(gameId) - , m_LastBlock(-1) - , m_hdr(slot, sizeMb, ascii) - , m_bat1(sizeMb) - , m_saves(0) - , m_SaveDirectory(directory) - , m_exiting(false) +GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot, u16 sizeMb, + bool ascii, DiscIO::IVolume::ECountry card_region, + int gameId) + : MemoryCardBase(slot, sizeMb), m_GameId(gameId), m_LastBlock(-1), m_hdr(slot, sizeMb, ascii), + m_bat1(sizeMb), m_saves(0), m_SaveDirectory(directory), m_exiting(false) { - // Use existing header data if available - if (File::Exists(m_SaveDirectory + MC_HDR)) - { - File::IOFile hdrfile((m_SaveDirectory + MC_HDR), "rb"); - hdrfile.ReadBytes(&m_hdr, BLOCK_SIZE); - } + // Use existing header data if available + if (File::Exists(m_SaveDirectory + MC_HDR)) + { + File::IOFile hdrfile((m_SaveDirectory + MC_HDR), "rb"); + hdrfile.ReadBytes(&m_hdr, BLOCK_SIZE); + } - std::vector rFilenames = DoFileSearch({".gci"}, {m_SaveDirectory}); + std::vector rFilenames = DoFileSearch({".gci"}, {m_SaveDirectory}); - if (rFilenames.size() > 112) - { - Core::DisplayMessage("Warning: There are more than 112 save files on this memory card.\n" - " Only loading the first 112 in the folder, unless the game ID is the same as the current game's ID", - 4000); - } + if (rFilenames.size() > 112) + { + Core::DisplayMessage("Warning: There are more than 112 save files on this memory card.\n" + " Only loading the first 112 in the folder, unless the game ID is the " + "same as the current game's ID", + 4000); + } - for (const std::string& gciFile : rFilenames) - { - if (m_saves.size() == DIRLEN) - { - PanicAlertT("There are too many GCI files in the folder\n%s.\nOnly the first 127 will be available", - m_SaveDirectory.c_str()); - break; - } - int index = LoadGCI(gciFile, card_region, m_saves.size() > 112 ); - if (index != NO_INDEX) - { - m_loaded_saves.push_back(m_saves.at(index).m_gci_header.GCI_FileName()); - } + for (const std::string& gciFile : rFilenames) + { + if (m_saves.size() == DIRLEN) + { + PanicAlertT( + "There are too many GCI files in the folder\n%s.\nOnly the first 127 will be available", + m_SaveDirectory.c_str()); + break; + } + int index = LoadGCI(gciFile, card_region, m_saves.size() > 112); + if (index != NO_INDEX) + { + m_loaded_saves.push_back(m_saves.at(index).m_gci_header.GCI_FileName()); + } + } - } + m_loaded_saves.clear(); + m_dir1.fixChecksums(); + m_dir2 = m_dir1; + m_bat2 = m_bat1; - m_loaded_saves.clear(); - m_dir1.fixChecksums(); - m_dir2 = m_dir1; - m_bat2 = m_bat1; - - m_flush_thread = std::thread(&GCMemcardDirectory::FlushThread, this); + m_flush_thread = std::thread(&GCMemcardDirectory::FlushThread, this); } void GCMemcardDirectory::FlushThread() { - if (!SConfig::GetInstance().bEnableMemcardSdWriting) - { - return; - } + if (!SConfig::GetInstance().bEnableMemcardSdWriting) + { + return; + } + Common::SetCurrentThreadName(StringFromFormat("Memcard %d flushing thread", card_index).c_str()); - Common::SetCurrentThreadName( - StringFromFormat("Memcard %d flushing thread", card_index).c_str()); + while (true) + { + // no-op until signalled + m_flush_trigger.Wait(); - while (true) - { - // no-op until signalled - m_flush_trigger.Wait(); + if (m_exiting) + { + m_exiting = false; + return; + } + // no-op as long as signalled within flush_interval + while (m_flush_trigger.WaitFor(flush_interval)) + { + if (m_exiting) + { + m_exiting = false; + return; + } + } - if (m_exiting) - { - m_exiting = false; - return; - } - // no-op as long as signalled within flush_interval - while (m_flush_trigger.WaitFor(flush_interval)) - { - if (m_exiting) - { - m_exiting = false; - return; - } - } - - FlushToFile(); - } + FlushToFile(); + } } GCMemcardDirectory::~GCMemcardDirectory() { - m_exiting = true; - m_flush_trigger.Set(); - m_flush_thread.join(); + m_exiting = true; + m_flush_trigger.Set(); + m_flush_thread.join(); - FlushToFile(); + FlushToFile(); } -s32 GCMemcardDirectory::Read(u32 address, s32 length, u8 *destaddress) +s32 GCMemcardDirectory::Read(u32 address, s32 length, u8* destaddress) { + s32 block = address / BLOCK_SIZE; + u32 offset = address % BLOCK_SIZE; + s32 extra = 0; // used for read calls that are across multiple blocks - s32 block = address / BLOCK_SIZE; - u32 offset = address % BLOCK_SIZE; - s32 extra = 0; // used for read calls that are across multiple blocks + if (offset + length > BLOCK_SIZE) + { + extra = length + offset - BLOCK_SIZE; + length -= extra; - if (offset + length > BLOCK_SIZE) - { - extra = length + offset - BLOCK_SIZE; - length -= extra; + // verify that we haven't calculated a length beyond BLOCK_SIZE + _dbg_assert_msg_(EXPANSIONINTERFACE, (address + length) % BLOCK_SIZE == 0, + "Memcard directory Read Logic Error"); + } - // verify that we haven't calculated a length beyond BLOCK_SIZE - _dbg_assert_msg_(EXPANSIONINTERFACE, (address + length) % BLOCK_SIZE == 0, - "Memcard directory Read Logic Error"); - } + if (m_LastBlock != block) + { + switch (block) + { + case 0: + m_LastBlock = block; + m_LastBlockAddress = (u8*)&m_hdr; + break; + case 1: + m_LastBlock = -1; + m_LastBlockAddress = (u8*)&m_dir1; + break; + case 2: + m_LastBlock = -1; + m_LastBlockAddress = (u8*)&m_dir2; + break; + case 3: + m_LastBlock = block; + m_LastBlockAddress = (u8*)&m_bat1; + break; + case 4: + m_LastBlock = block; + m_LastBlockAddress = (u8*)&m_bat2; + break; + default: + m_LastBlock = SaveAreaRW(block); - if (m_LastBlock != block) - { - switch (block) - { - case 0: - m_LastBlock = block; - m_LastBlockAddress = (u8 *)&m_hdr; - break; - case 1: - m_LastBlock = -1; - m_LastBlockAddress = (u8 *)&m_dir1; - break; - case 2: - m_LastBlock = -1; - m_LastBlockAddress = (u8 *)&m_dir2; - break; - case 3: - m_LastBlock = block; - m_LastBlockAddress = (u8 *)&m_bat1; - break; - case 4: - m_LastBlock = block; - m_LastBlockAddress = (u8 *)&m_bat2; - break; - default: - m_LastBlock = SaveAreaRW(block); + if (m_LastBlock == -1) + { + memset(destaddress, 0xFF, length); + return 0; + } + } + } - if (m_LastBlock == -1) - { - memset(destaddress, 0xFF, length); - return 0; - } - } - } - - memcpy(destaddress, m_LastBlockAddress + offset, length); - if (extra) - extra = Read(address + length, extra, destaddress + length); - return length + extra; + memcpy(destaddress, m_LastBlockAddress + offset, length); + if (extra) + extra = Read(address + length, extra, destaddress + length); + return length + extra; } -s32 GCMemcardDirectory::Write(u32 destaddress, s32 length, u8 *srcaddress) +s32 GCMemcardDirectory::Write(u32 destaddress, s32 length, u8* srcaddress) { - std::unique_lock l(m_write_mutex); - if (length != 0x80) - INFO_LOG(EXPANSIONINTERFACE, "Writing to 0x%x. Length: 0x%x", destaddress, length); - s32 block = destaddress / BLOCK_SIZE; - u32 offset = destaddress % BLOCK_SIZE; - s32 extra = 0; // used for write calls that are across multiple blocks + std::unique_lock l(m_write_mutex); + if (length != 0x80) + INFO_LOG(EXPANSIONINTERFACE, "Writing to 0x%x. Length: 0x%x", destaddress, length); + s32 block = destaddress / BLOCK_SIZE; + u32 offset = destaddress % BLOCK_SIZE; + s32 extra = 0; // used for write calls that are across multiple blocks - if (offset + length > BLOCK_SIZE) - { - extra = length + offset - BLOCK_SIZE; - length -= extra; + if (offset + length > BLOCK_SIZE) + { + extra = length + offset - BLOCK_SIZE; + length -= extra; - // verify that we haven't calculated a length beyond BLOCK_SIZE - _dbg_assert_msg_(EXPANSIONINTERFACE, (destaddress + length) % BLOCK_SIZE == 0, - "Memcard directory Write Logic Error"); - } - if (m_LastBlock != block) - { - switch (block) - { - case 0: - m_LastBlock = block; - m_LastBlockAddress = (u8 *)&m_hdr; - break; - case 1: - case 2: - { - m_LastBlock = -1; - s32 bytes_written = 0; - while (length > 0) - { - s32 to_write = std::min(DENTRY_SIZE, length); - bytes_written += DirectoryWrite(destaddress + bytes_written, to_write, srcaddress + bytes_written); - length -= to_write; - } - return bytes_written; - } - case 3: - m_LastBlock = block; - m_LastBlockAddress = (u8 *)&m_bat1; - break; - case 4: - m_LastBlock = block; - m_LastBlockAddress = (u8 *)&m_bat2; - break; - default: - m_LastBlock = SaveAreaRW(block, true); - if (m_LastBlock == -1) - { - PanicAlertT("Report: GCIFolder Writing to unallocated block 0x%x", block); - exit(0); - } - } - } + // verify that we haven't calculated a length beyond BLOCK_SIZE + _dbg_assert_msg_(EXPANSIONINTERFACE, (destaddress + length) % BLOCK_SIZE == 0, + "Memcard directory Write Logic Error"); + } + if (m_LastBlock != block) + { + switch (block) + { + case 0: + m_LastBlock = block; + m_LastBlockAddress = (u8*)&m_hdr; + break; + case 1: + case 2: + { + m_LastBlock = -1; + s32 bytes_written = 0; + while (length > 0) + { + s32 to_write = std::min(DENTRY_SIZE, length); + bytes_written += + DirectoryWrite(destaddress + bytes_written, to_write, srcaddress + bytes_written); + length -= to_write; + } + return bytes_written; + } + case 3: + m_LastBlock = block; + m_LastBlockAddress = (u8*)&m_bat1; + break; + case 4: + m_LastBlock = block; + m_LastBlockAddress = (u8*)&m_bat2; + break; + default: + m_LastBlock = SaveAreaRW(block, true); + if (m_LastBlock == -1) + { + PanicAlertT("Report: GCIFolder Writing to unallocated block 0x%x", block); + exit(0); + } + } + } - memcpy(m_LastBlockAddress + offset, srcaddress, length); + memcpy(m_LastBlockAddress + offset, srcaddress, length); - l.unlock(); - if (extra) - extra = Write(destaddress + length, extra, srcaddress + length); - if (offset + length == BLOCK_SIZE) - m_flush_trigger.Set(); - return length + extra; + l.unlock(); + if (extra) + extra = Write(destaddress + length, extra, srcaddress + length); + if (offset + length == BLOCK_SIZE) + m_flush_trigger.Set(); + return length + extra; } void GCMemcardDirectory::ClearBlock(u32 address) { - if (address % BLOCK_SIZE) - { - PanicAlertT("GCMemcardDirectory: ClearBlock called with invalid block address"); - return; - } + if (address % BLOCK_SIZE) + { + PanicAlertT("GCMemcardDirectory: ClearBlock called with invalid block address"); + return; + } - u32 block = address / BLOCK_SIZE; - INFO_LOG(EXPANSIONINTERFACE, "Clearing block %u", block); - switch (block) - { - case 0: - m_LastBlock = block; - m_LastBlockAddress = (u8 *)&m_hdr; - break; - case 1: - m_LastBlock = -1; - m_LastBlockAddress = (u8 *)&m_dir1; - break; - case 2: - m_LastBlock = -1; - m_LastBlockAddress = (u8 *)&m_dir2; - break; - case 3: - m_LastBlock = block; - m_LastBlockAddress = (u8 *)&m_bat1; - break; - case 4: - m_LastBlock = block; - m_LastBlockAddress = (u8 *)&m_bat2; - break; - default: - m_LastBlock = SaveAreaRW(block, true); - if (m_LastBlock == -1) - return; - } - ((GCMBlock *)m_LastBlockAddress)->Erase(); + u32 block = address / BLOCK_SIZE; + INFO_LOG(EXPANSIONINTERFACE, "Clearing block %u", block); + switch (block) + { + case 0: + m_LastBlock = block; + m_LastBlockAddress = (u8*)&m_hdr; + break; + case 1: + m_LastBlock = -1; + m_LastBlockAddress = (u8*)&m_dir1; + break; + case 2: + m_LastBlock = -1; + m_LastBlockAddress = (u8*)&m_dir2; + break; + case 3: + m_LastBlock = block; + m_LastBlockAddress = (u8*)&m_bat1; + break; + case 4: + m_LastBlock = block; + m_LastBlockAddress = (u8*)&m_bat2; + break; + default: + m_LastBlock = SaveAreaRW(block, true); + if (m_LastBlock == -1) + return; + } + ((GCMBlock*)m_LastBlockAddress)->Erase(); } inline void GCMemcardDirectory::SyncSaves() { - Directory *current = &m_dir2; + Directory* current = &m_dir2; - if (BE16(m_dir1.UpdateCounter) > BE16(m_dir2.UpdateCounter)) - { - current = &m_dir1; - } + if (BE16(m_dir1.UpdateCounter) > BE16(m_dir2.UpdateCounter)) + { + current = &m_dir1; + } - for (u32 i = 0; i < DIRLEN; ++i) - { - if (BE32(current->Dir[i].Gamecode) != 0xFFFFFFFF) - { - INFO_LOG(EXPANSIONINTERFACE, "Syncing save 0x%x", *(u32 *)&(current->Dir[i].Gamecode)); - bool added = false; - while (i >= m_saves.size()) - { - GCIFile temp; - m_saves.push_back(temp); - added = true; - } + for (u32 i = 0; i < DIRLEN; ++i) + { + if (BE32(current->Dir[i].Gamecode) != 0xFFFFFFFF) + { + INFO_LOG(EXPANSIONINTERFACE, "Syncing save 0x%x", *(u32*)&(current->Dir[i].Gamecode)); + bool added = false; + while (i >= m_saves.size()) + { + GCIFile temp; + m_saves.push_back(temp); + added = true; + } - if (added || memcmp((u8 *)&(m_saves[i].m_gci_header), (u8 *)&(current->Dir[i]), DENTRY_SIZE)) - { - m_saves[i].m_dirty = true; - u32 gamecode = BE32(m_saves[i].m_gci_header.Gamecode); - u32 newGameCode = BE32(current->Dir[i].Gamecode); - u32 old_start = BE16(m_saves[i].m_gci_header.FirstBlock); - u32 new_start = BE16(current->Dir[i].FirstBlock); + if (added || memcmp((u8*)&(m_saves[i].m_gci_header), (u8*)&(current->Dir[i]), DENTRY_SIZE)) + { + m_saves[i].m_dirty = true; + u32 gamecode = BE32(m_saves[i].m_gci_header.Gamecode); + u32 newGameCode = BE32(current->Dir[i].Gamecode); + u32 old_start = BE16(m_saves[i].m_gci_header.FirstBlock); + u32 new_start = BE16(current->Dir[i].FirstBlock); - if ((gamecode != 0xFFFFFFFF) - && (gamecode != newGameCode)) - { - PanicAlertT("Game overwrote with another games save. Data corruption ahead 0x%x, 0x%x", - BE32(m_saves[i].m_gci_header.Gamecode), BE32(current->Dir[i].Gamecode)); - } - memcpy((u8 *)&(m_saves[i].m_gci_header), (u8 *)&(current->Dir[i]), DENTRY_SIZE); - if (old_start != new_start) - { - INFO_LOG(EXPANSIONINTERFACE, "Save moved from 0x%x to 0x%x", old_start, new_start); - m_saves[i].m_used_blocks.clear(); - m_saves[i].m_save_data.clear(); - } - if (m_saves[i].m_used_blocks.size() == 0) - { - SetUsedBlocks(i); - } - } - } - else if ((i < m_saves.size()) && (*(u32 *)&(m_saves[i].m_gci_header) != 0xFFFFFFFF)) - { - INFO_LOG(EXPANSIONINTERFACE, "Clearing and/or deleting save 0x%x", BE32(m_saves[i].m_gci_header.Gamecode)); - *(u32 *)&(m_saves[i].m_gci_header.Gamecode) = 0xFFFFFFFF; - m_saves[i].m_save_data.clear(); - m_saves[i].m_used_blocks.clear(); - m_saves[i].m_dirty = true; - - } - } + if ((gamecode != 0xFFFFFFFF) && (gamecode != newGameCode)) + { + PanicAlertT("Game overwrote with another games save. Data corruption ahead 0x%x, 0x%x", + BE32(m_saves[i].m_gci_header.Gamecode), BE32(current->Dir[i].Gamecode)); + } + memcpy((u8*)&(m_saves[i].m_gci_header), (u8*)&(current->Dir[i]), DENTRY_SIZE); + if (old_start != new_start) + { + INFO_LOG(EXPANSIONINTERFACE, "Save moved from 0x%x to 0x%x", old_start, new_start); + m_saves[i].m_used_blocks.clear(); + m_saves[i].m_save_data.clear(); + } + if (m_saves[i].m_used_blocks.size() == 0) + { + SetUsedBlocks(i); + } + } + } + else if ((i < m_saves.size()) && (*(u32*)&(m_saves[i].m_gci_header) != 0xFFFFFFFF)) + { + INFO_LOG(EXPANSIONINTERFACE, "Clearing and/or deleting save 0x%x", + BE32(m_saves[i].m_gci_header.Gamecode)); + *(u32*)&(m_saves[i].m_gci_header.Gamecode) = 0xFFFFFFFF; + m_saves[i].m_save_data.clear(); + m_saves[i].m_used_blocks.clear(); + m_saves[i].m_dirty = true; + } + } } inline s32 GCMemcardDirectory::SaveAreaRW(u32 block, bool writing) { - for (u16 i = 0; i < m_saves.size(); ++i) - { - if (BE32(m_saves[i].m_gci_header.Gamecode) != 0xFFFFFFFF) - { - if (m_saves[i].m_used_blocks.size() == 0) - { - SetUsedBlocks(i); - } + for (u16 i = 0; i < m_saves.size(); ++i) + { + if (BE32(m_saves[i].m_gci_header.Gamecode) != 0xFFFFFFFF) + { + if (m_saves[i].m_used_blocks.size() == 0) + { + SetUsedBlocks(i); + } - int idx = m_saves[i].UsesBlock(block); - if (idx != -1) - { - if (!m_saves[i].LoadSaveBlocks()) - { - int num_blocks = BE16(m_saves[i].m_gci_header.BlockCount); - while (num_blocks) - { - m_saves[i].m_save_data.emplace_back(); - num_blocks--; - } - } + int idx = m_saves[i].UsesBlock(block); + if (idx != -1) + { + if (!m_saves[i].LoadSaveBlocks()) + { + int num_blocks = BE16(m_saves[i].m_gci_header.BlockCount); + while (num_blocks) + { + m_saves[i].m_save_data.emplace_back(); + num_blocks--; + } + } - if (writing) - { - m_saves[i].m_dirty = true; - } + if (writing) + { + m_saves[i].m_dirty = true; + } - m_LastBlock = block; - m_LastBlockAddress = m_saves[i].m_save_data[idx].block; - return m_LastBlock; - } - } - } - return -1; + m_LastBlock = block; + m_LastBlockAddress = m_saves[i].m_save_data[idx].block; + return m_LastBlock; + } + } + } + return -1; } -s32 GCMemcardDirectory::DirectoryWrite(u32 destaddress, u32 length, u8 *srcaddress) +s32 GCMemcardDirectory::DirectoryWrite(u32 destaddress, u32 length, u8* srcaddress) { - u32 block = destaddress / BLOCK_SIZE; - u32 offset = destaddress % BLOCK_SIZE; - Directory *dest = (block == 1) ? &m_dir1 : &m_dir2; - u16 Dnum = offset / DENTRY_SIZE; + u32 block = destaddress / BLOCK_SIZE; + u32 offset = destaddress % BLOCK_SIZE; + Directory* dest = (block == 1) ? &m_dir1 : &m_dir2; + u16 Dnum = offset / DENTRY_SIZE; - if (Dnum == DIRLEN) - { - // first 58 bytes should always be 0xff - // needed to update the update ctr, checksums - // could check for writes to the 6 important bytes but doubtful that it improves performance noticably - memcpy((u8 *)(dest)+offset, srcaddress, length); - SyncSaves(); - } - else - memcpy((u8 *)(dest)+offset, srcaddress, length); - return length; + if (Dnum == DIRLEN) + { + // first 58 bytes should always be 0xff + // needed to update the update ctr, checksums + // could check for writes to the 6 important bytes but doubtful that it improves performance + // noticably + memcpy((u8*)(dest) + offset, srcaddress, length); + SyncSaves(); + } + else + memcpy((u8*)(dest) + offset, srcaddress, length); + return length; } bool GCMemcardDirectory::SetUsedBlocks(int saveIndex) { - BlockAlloc *currentBat; - if (BE16(m_bat2.UpdateCounter) > BE16(m_bat1.UpdateCounter)) - currentBat = &m_bat2; - else - currentBat = &m_bat1; + BlockAlloc* currentBat; + if (BE16(m_bat2.UpdateCounter) > BE16(m_bat1.UpdateCounter)) + currentBat = &m_bat2; + else + currentBat = &m_bat1; - u16 block = BE16(m_saves[saveIndex].m_gci_header.FirstBlock); - while (block != 0xFFFF) - { - m_saves[saveIndex].m_used_blocks.push_back(block); - block = currentBat->GetNextBlock(block); - if (block == 0) - { - PanicAlertT("BAT incorrect. Dolphin will now exit"); - exit(0); - } - } + u16 block = BE16(m_saves[saveIndex].m_gci_header.FirstBlock); + while (block != 0xFFFF) + { + m_saves[saveIndex].m_used_blocks.push_back(block); + block = currentBat->GetNextBlock(block); + if (block == 0) + { + PanicAlertT("BAT incorrect. Dolphin will now exit"); + exit(0); + } + } - u16 num_blocks = BE16(m_saves[saveIndex].m_gci_header.BlockCount); - u16 blocksFromBat = (u16)m_saves[saveIndex].m_used_blocks.size(); - if (blocksFromBat != num_blocks) - { - PanicAlertT("Warning: Number of blocks indicated by the BAT (%u) does not match that of the loaded file header (%u)", - blocksFromBat, num_blocks); - return false; - } + u16 num_blocks = BE16(m_saves[saveIndex].m_gci_header.BlockCount); + u16 blocksFromBat = (u16)m_saves[saveIndex].m_used_blocks.size(); + if (blocksFromBat != num_blocks) + { + PanicAlertT("Warning: Number of blocks indicated by the BAT (%u) does not match that of the " + "loaded file header (%u)", + blocksFromBat, num_blocks); + return false; + } - return true; + return true; } void GCMemcardDirectory::FlushToFile() { - std::unique_lock l(m_write_mutex); - int errors = 0; - DEntry invalid; - for (u16 i = 0; i < m_saves.size(); ++i) - { - if (m_saves[i].m_dirty) - { - if (BE32(m_saves[i].m_gci_header.Gamecode) != 0xFFFFFFFF) - { - m_saves[i].m_dirty = false; - if (m_saves[i].m_save_data.size() == 0) - { - // The save's header has been changed but the actual save blocks haven't been read/written to - // skip flushing this file until actual save data is modified - ERROR_LOG(EXPANSIONINTERFACE, "GCI header modified without corresponding save data changes"); - continue; - } - if (m_saves[i].m_filename.empty()) - { - std::string defaultSaveName = m_SaveDirectory + m_saves[i].m_gci_header.GCI_FileName(); + std::unique_lock l(m_write_mutex); + int errors = 0; + DEntry invalid; + for (u16 i = 0; i < m_saves.size(); ++i) + { + if (m_saves[i].m_dirty) + { + if (BE32(m_saves[i].m_gci_header.Gamecode) != 0xFFFFFFFF) + { + m_saves[i].m_dirty = false; + if (m_saves[i].m_save_data.size() == 0) + { + // The save's header has been changed but the actual save blocks haven't been read/written + // to + // skip flushing this file until actual save data is modified + ERROR_LOG(EXPANSIONINTERFACE, + "GCI header modified without corresponding save data changes"); + continue; + } + if (m_saves[i].m_filename.empty()) + { + std::string defaultSaveName = m_SaveDirectory + m_saves[i].m_gci_header.GCI_FileName(); - // Check to see if another file is using the same name - // This seems unlikely except in the case of file corruption - // otherwise what user would name another file this way? - for (int j = 0; File::Exists(defaultSaveName) && j < 10; ++j) - { - defaultSaveName.insert(defaultSaveName.end() - 4, '0'); - } - if (File::Exists(defaultSaveName)) - PanicAlertT("Failed to find new filename.\n%s\n will be overwritten", defaultSaveName.c_str()); - m_saves[i].m_filename = defaultSaveName; - } - File::IOFile GCI(m_saves[i].m_filename, "wb"); - if (GCI) - { - GCI.WriteBytes(&m_saves[i].m_gci_header, DENTRY_SIZE); - GCI.WriteBytes(m_saves[i].m_save_data.data(), BLOCK_SIZE * m_saves[i].m_save_data.size()); + // Check to see if another file is using the same name + // This seems unlikely except in the case of file corruption + // otherwise what user would name another file this way? + for (int j = 0; File::Exists(defaultSaveName) && j < 10; ++j) + { + defaultSaveName.insert(defaultSaveName.end() - 4, '0'); + } + if (File::Exists(defaultSaveName)) + PanicAlertT("Failed to find new filename.\n%s\n will be overwritten", + defaultSaveName.c_str()); + m_saves[i].m_filename = defaultSaveName; + } + File::IOFile GCI(m_saves[i].m_filename, "wb"); + if (GCI) + { + GCI.WriteBytes(&m_saves[i].m_gci_header, DENTRY_SIZE); + GCI.WriteBytes(m_saves[i].m_save_data.data(), BLOCK_SIZE * m_saves[i].m_save_data.size()); - if (GCI.IsGood()) - { - Core::DisplayMessage( - StringFromFormat("Wrote save contents to %s", m_saves[i].m_filename.c_str()), 4000); - } - else - { - ++errors; - Core::DisplayMessage( - StringFromFormat("Failed to write save contents to %s", m_saves[i].m_filename.c_str()), - 4000); - ERROR_LOG(EXPANSIONINTERFACE, "Failed to save data to %s", m_saves[i].m_filename.c_str()); - } - } - } - else if (m_saves[i].m_filename.length() != 0) - { - m_saves[i].m_dirty = false; - std::string &oldname = m_saves[i].m_filename; - std::string deletedname = oldname + ".deleted"; - if (File::Exists(deletedname)) - File::Delete(deletedname); - File::Rename(oldname, deletedname); - m_saves[i].m_filename.clear(); - m_saves[i].m_save_data.clear(); - m_saves[i].m_used_blocks.clear(); - } - } + if (GCI.IsGood()) + { + Core::DisplayMessage( + StringFromFormat("Wrote save contents to %s", m_saves[i].m_filename.c_str()), 4000); + } + else + { + ++errors; + Core::DisplayMessage(StringFromFormat("Failed to write save contents to %s", + m_saves[i].m_filename.c_str()), + 4000); + ERROR_LOG(EXPANSIONINTERFACE, "Failed to save data to %s", + m_saves[i].m_filename.c_str()); + } + } + } + else if (m_saves[i].m_filename.length() != 0) + { + m_saves[i].m_dirty = false; + std::string& oldname = m_saves[i].m_filename; + std::string deletedname = oldname + ".deleted"; + if (File::Exists(deletedname)) + File::Delete(deletedname); + File::Rename(oldname, deletedname); + m_saves[i].m_filename.clear(); + m_saves[i].m_save_data.clear(); + m_saves[i].m_used_blocks.clear(); + } + } - // Unload the save data for any game that is not running - // we could use !m_dirty, but some games have multiple gci files and may not write to them simultaneously - // this ensures that the save data for all of the current games gci files are stored in the savestate - u32 gamecode = BE32(m_saves[i].m_gci_header.Gamecode); - if (gamecode != m_GameId && gamecode != 0xFFFFFFFF && m_saves[i].m_save_data.size()) - { - INFO_LOG(EXPANSIONINTERFACE, "Flushing savedata to disk for %s", m_saves[i].m_filename.c_str()); - m_saves[i].m_save_data.clear(); - } - } + // Unload the save data for any game that is not running + // we could use !m_dirty, but some games have multiple gci files and may not write to them + // simultaneously + // this ensures that the save data for all of the current games gci files are stored in the + // savestate + u32 gamecode = BE32(m_saves[i].m_gci_header.Gamecode); + if (gamecode != m_GameId && gamecode != 0xFFFFFFFF && m_saves[i].m_save_data.size()) + { + INFO_LOG(EXPANSIONINTERFACE, "Flushing savedata to disk for %s", + m_saves[i].m_filename.c_str()); + m_saves[i].m_save_data.clear(); + } + } #if _WRITE_MC_HEADER - u8 mc[BLOCK_SIZE * MC_FST_BLOCKS]; - Read(0, BLOCK_SIZE * MC_FST_BLOCKS, mc); - File::IOFile hdrfile(m_SaveDirectory + MC_HDR, "wb"); - hdrfile.WriteBytes(mc, BLOCK_SIZE * MC_FST_BLOCKS); + u8 mc[BLOCK_SIZE * MC_FST_BLOCKS]; + Read(0, BLOCK_SIZE * MC_FST_BLOCKS, mc); + File::IOFile hdrfile(m_SaveDirectory + MC_HDR, "wb"); + hdrfile.WriteBytes(mc, BLOCK_SIZE * MC_FST_BLOCKS); #endif } -void GCMemcardDirectory::DoState(PointerWrap &p) +void GCMemcardDirectory::DoState(PointerWrap& p) { - std::unique_lock l(m_write_mutex); - m_LastBlock = -1; - m_LastBlockAddress = nullptr; - p.Do(m_SaveDirectory); - p.DoPOD
(m_hdr); - p.DoPOD(m_dir1); - p.DoPOD(m_dir2); - p.DoPOD(m_bat1); - p.DoPOD(m_bat2); - int numSaves = (int)m_saves.size(); - p.Do(numSaves); - m_saves.resize(numSaves); - for (auto itr = m_saves.begin(); itr != m_saves.end(); ++itr) - { - itr->DoState(p); - } + std::unique_lock l(m_write_mutex); + m_LastBlock = -1; + m_LastBlockAddress = nullptr; + p.Do(m_SaveDirectory); + p.DoPOD
(m_hdr); + p.DoPOD(m_dir1); + p.DoPOD(m_dir2); + p.DoPOD(m_bat1); + p.DoPOD(m_bat2); + int numSaves = (int)m_saves.size(); + p.Do(numSaves); + m_saves.resize(numSaves); + for (auto itr = m_saves.begin(); itr != m_saves.end(); ++itr) + { + itr->DoState(p); + } } bool GCIFile::LoadSaveBlocks() { - if (m_save_data.size() == 0) - { - if (m_filename.empty()) - return false; + if (m_save_data.size() == 0) + { + if (m_filename.empty()) + return false; - File::IOFile savefile(m_filename, "rb"); - if (!savefile) - return false; + File::IOFile savefile(m_filename, "rb"); + if (!savefile) + return false; - INFO_LOG(EXPANSIONINTERFACE, "Reading savedata from disk for %s", m_filename.c_str()); - savefile.Seek(DENTRY_SIZE, SEEK_SET); - u16 num_blocks = BE16(m_gci_header.BlockCount); - m_save_data.resize(num_blocks); - if (!savefile.ReadBytes(m_save_data.data(), num_blocks * BLOCK_SIZE)) - { - PanicAlertT("Failed to read data from GCI file %s", m_filename.c_str()); - m_save_data.clear(); - return false; - } - } - return true; + INFO_LOG(EXPANSIONINTERFACE, "Reading savedata from disk for %s", m_filename.c_str()); + savefile.Seek(DENTRY_SIZE, SEEK_SET); + u16 num_blocks = BE16(m_gci_header.BlockCount); + m_save_data.resize(num_blocks); + if (!savefile.ReadBytes(m_save_data.data(), num_blocks * BLOCK_SIZE)) + { + PanicAlertT("Failed to read data from GCI file %s", m_filename.c_str()); + m_save_data.clear(); + return false; + } + } + return true; } int GCIFile::UsesBlock(u16 blocknum) { - for (u16 i = 0; i < m_used_blocks.size(); ++i) - { - if (m_used_blocks[i] == blocknum) - return i; - } - return -1; + for (u16 i = 0; i < m_used_blocks.size(); ++i) + { + if (m_used_blocks[i] == blocknum) + return i; + } + return -1; } -void GCIFile::DoState(PointerWrap &p) +void GCIFile::DoState(PointerWrap& p) { - p.DoPOD(m_gci_header); - p.Do(m_dirty); - p.Do(m_filename); - int numBlocks = (int)m_save_data.size(); - p.Do(numBlocks); - m_save_data.resize(numBlocks); - for (auto itr = m_save_data.begin(); itr != m_save_data.end(); ++itr) - { - p.DoPOD(*itr); - } - p.Do(m_used_blocks); + p.DoPOD(m_gci_header); + p.Do(m_dirty); + p.Do(m_filename); + int numBlocks = (int)m_save_data.size(); + p.Do(numBlocks); + m_save_data.resize(numBlocks); + for (auto itr = m_save_data.begin(); itr != m_save_data.end(); ++itr) + { + p.DoPOD(*itr); + } + p.Do(m_used_blocks); } void MigrateFromMemcardFile(const std::string& strDirectoryName, int card_index) { - File::CreateFullPath(strDirectoryName); - std::string ini_memcard = - (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : SConfig::GetInstance().m_strMemoryCardB; - if (File::Exists(ini_memcard)) - { - GCMemcard memcard(ini_memcard.c_str()); - if (memcard.IsValid()) - { - for (u8 i = 0; i < DIRLEN; i++) - { - memcard.ExportGci(i, "", strDirectoryName); - } - } - } + File::CreateFullPath(strDirectoryName); + std::string ini_memcard = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : + SConfig::GetInstance().m_strMemoryCardB; + if (File::Exists(ini_memcard)) + { + GCMemcard memcard(ini_memcard.c_str()); + if (memcard.IsValid()) + { + for (u8 i = 0; i < DIRLEN; i++) + { + memcard.ExportGci(i, "", strDirectoryName); + } + } + } } diff --git a/Source/Core/Core/HW/GCMemcardDirectory.h b/Source/Core/Core/HW/GCMemcardDirectory.h index 45aaa0628b..b17e590a45 100644 --- a/Source/Core/Core/HW/GCMemcardDirectory.h +++ b/Source/Core/Core/HW/GCMemcardDirectory.h @@ -23,39 +23,42 @@ void MigrateFromMemcardFile(const std::string& strDirectoryName, int card_index) class GCMemcardDirectory : public MemoryCardBase, NonCopyable { public: - GCMemcardDirectory(const std::string& directory, int slot = 0, u16 sizeMb = MemCard2043Mb, bool ascii = true, - DiscIO::IVolume::ECountry card_region = DiscIO::IVolume::COUNTRY_EUROPE, int gameId = 0); - ~GCMemcardDirectory(); - void FlushToFile(); - void FlushThread(); - s32 Read(u32 address, s32 length, u8 *destaddress) override; - s32 Write(u32 destaddress, s32 length, u8 *srcaddress) override; - void ClearBlock(u32 address) override; - void ClearAll() override {} - void DoState(PointerWrap &p) override; + GCMemcardDirectory(const std::string& directory, int slot = 0, u16 sizeMb = MemCard2043Mb, + bool ascii = true, + DiscIO::IVolume::ECountry card_region = DiscIO::IVolume::COUNTRY_EUROPE, + int gameId = 0); + ~GCMemcardDirectory(); + void FlushToFile(); + void FlushThread(); + s32 Read(u32 address, s32 length, u8* destaddress) override; + s32 Write(u32 destaddress, s32 length, u8* srcaddress) override; + void ClearBlock(u32 address) override; + void ClearAll() override {} + void DoState(PointerWrap& p) override; private: - int LoadGCI(const std::string& fileName, DiscIO::IVolume::ECountry card_region, bool currentGameOnly); - inline s32 SaveAreaRW(u32 block, bool writing = false); - // s32 DirectoryRead(u32 offset, u32 length, u8* destaddress); - s32 DirectoryWrite(u32 destaddress, u32 length, u8 *srcaddress); - inline void SyncSaves(); - bool SetUsedBlocks(int saveIndex); + int LoadGCI(const std::string& fileName, DiscIO::IVolume::ECountry card_region, + bool currentGameOnly); + inline s32 SaveAreaRW(u32 block, bool writing = false); + // s32 DirectoryRead(u32 offset, u32 length, u8* destaddress); + s32 DirectoryWrite(u32 destaddress, u32 length, u8* srcaddress); + inline void SyncSaves(); + bool SetUsedBlocks(int saveIndex); - u32 m_GameId; - s32 m_LastBlock; - u8 *m_LastBlockAddress; + u32 m_GameId; + s32 m_LastBlock; + u8* m_LastBlockAddress; - Header m_hdr; - Directory m_dir1, m_dir2; - BlockAlloc m_bat1, m_bat2; - std::vector m_saves; + Header m_hdr; + Directory m_dir1, m_dir2; + BlockAlloc m_bat1, m_bat2; + std::vector m_saves; - std::vector m_loaded_saves; - std::string m_SaveDirectory; - const std::chrono::seconds flush_interval = std::chrono::seconds(1); - Common::Event m_flush_trigger; - std::mutex m_write_mutex; - std::atomic m_exiting; - std::thread m_flush_thread; + std::vector m_loaded_saves; + std::string m_SaveDirectory; + const std::chrono::seconds flush_interval = std::chrono::seconds(1); + Common::Event m_flush_trigger; + std::mutex m_write_mutex; + std::atomic m_exiting; + std::thread m_flush_thread; }; diff --git a/Source/Core/Core/HW/GCMemcardRaw.cpp b/Source/Core/Core/HW/GCMemcardRaw.cpp index 1c1e82f957..24c72b7f6f 100644 --- a/Source/Core/Core/HW/GCMemcardRaw.cpp +++ b/Source/Core/Core/HW/GCMemcardRaw.cpp @@ -10,8 +10,8 @@ #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/Thread.h" #include "Common/Logging/Log.h" +#include "Common/Thread.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/HW/GCMemcard.h" @@ -21,190 +21,185 @@ #define MC_HDR_SIZE 0xA000 MemoryCard::MemoryCard(const std::string& filename, int _card_index, u16 sizeMb) - : MemoryCardBase(_card_index, sizeMb) - , m_filename(filename) + : MemoryCardBase(_card_index, sizeMb), m_filename(filename) { - File::IOFile pFile(m_filename, "rb"); - if (pFile) - { - // Measure size of the existing memcard file. - memory_card_size = (u32)pFile.GetSize(); - nintendo_card_id = memory_card_size / SIZE_TO_Mb; - m_memcard_data = std::make_unique(memory_card_size); - memset(&m_memcard_data[0], 0xFF, memory_card_size); + File::IOFile pFile(m_filename, "rb"); + if (pFile) + { + // Measure size of the existing memcard file. + memory_card_size = (u32)pFile.GetSize(); + nintendo_card_id = memory_card_size / SIZE_TO_Mb; + m_memcard_data = std::make_unique(memory_card_size); + memset(&m_memcard_data[0], 0xFF, memory_card_size); - INFO_LOG(EXPANSIONINTERFACE, "Reading memory card %s", m_filename.c_str()); - pFile.ReadBytes(&m_memcard_data[0], memory_card_size); - } - else - { - // Create a new 128Mb memcard - nintendo_card_id = sizeMb; - memory_card_size = sizeMb * SIZE_TO_Mb; + INFO_LOG(EXPANSIONINTERFACE, "Reading memory card %s", m_filename.c_str()); + pFile.ReadBytes(&m_memcard_data[0], memory_card_size); + } + else + { + // Create a new 128Mb memcard + nintendo_card_id = sizeMb; + memory_card_size = sizeMb * SIZE_TO_Mb; - m_memcard_data = std::make_unique(memory_card_size); - // Fills in MC_HDR_SIZE bytes - GCMemcard::Format(&m_memcard_data[0], m_filename.find(".JAP.raw") != std::string::npos, sizeMb); - memset(&m_memcard_data[MC_HDR_SIZE], 0xFF, memory_card_size - MC_HDR_SIZE); + m_memcard_data = std::make_unique(memory_card_size); + // Fills in MC_HDR_SIZE bytes + GCMemcard::Format(&m_memcard_data[0], m_filename.find(".JAP.raw") != std::string::npos, sizeMb); + memset(&m_memcard_data[MC_HDR_SIZE], 0xFF, memory_card_size - MC_HDR_SIZE); - INFO_LOG(EXPANSIONINTERFACE, "No memory card found. A new one was created instead."); - } + INFO_LOG(EXPANSIONINTERFACE, "No memory card found. A new one was created instead."); + } - // Class members (including inherited ones) have now been initialized, so - // it's safe to startup the flush thread (which reads them). - m_flush_buffer = std::make_unique(memory_card_size); - m_flush_thread = std::thread(&MemoryCard::FlushThread, this); + // Class members (including inherited ones) have now been initialized, so + // it's safe to startup the flush thread (which reads them). + m_flush_buffer = std::make_unique(memory_card_size); + m_flush_thread = std::thread(&MemoryCard::FlushThread, this); } MemoryCard::~MemoryCard() { - if (m_flush_thread.joinable()) - { - m_flush_trigger.Set(); + if (m_flush_thread.joinable()) + { + m_flush_trigger.Set(); - m_flush_thread.join(); - } + m_flush_thread.join(); + } } void MemoryCard::FlushThread() { - if (!SConfig::GetInstance().bEnableMemcardSdWriting) - { - return; - } + if (!SConfig::GetInstance().bEnableMemcardSdWriting) + { + return; + } - Common::SetCurrentThreadName( - StringFromFormat("Memcard %d flushing thread", card_index).c_str()); + Common::SetCurrentThreadName(StringFromFormat("Memcard %d flushing thread", card_index).c_str()); - const auto flush_interval = std::chrono::seconds(15); + const auto flush_interval = std::chrono::seconds(15); - while (true) - { - // If triggered, we're exiting. - // If timed out, check if we need to flush. - bool do_exit = m_flush_trigger.WaitFor(flush_interval); - if (!do_exit) - { - bool is_dirty = m_dirty.TestAndClear(); - if (!is_dirty) - { - continue; - } - } + while (true) + { + // If triggered, we're exiting. + // If timed out, check if we need to flush. + bool do_exit = m_flush_trigger.WaitFor(flush_interval); + if (!do_exit) + { + bool is_dirty = m_dirty.TestAndClear(); + if (!is_dirty) + { + continue; + } + } - // Opening the file is purposefully done each iteration to ensure the - // file doesn't disappear out from under us after the first check. - File::IOFile pFile(m_filename, "r+b"); + // Opening the file is purposefully done each iteration to ensure the + // file doesn't disappear out from under us after the first check. + File::IOFile pFile(m_filename, "r+b"); - if (!pFile) - { - std::string dir; - SplitPath(m_filename, &dir, nullptr, nullptr); - if (!File::IsDirectory(dir)) - { - File::CreateFullPath(dir); - } - pFile.Open(m_filename, "wb"); - } + if (!pFile) + { + std::string dir; + SplitPath(m_filename, &dir, nullptr, nullptr); + if (!File::IsDirectory(dir)) + { + File::CreateFullPath(dir); + } + pFile.Open(m_filename, "wb"); + } - // Note - pFile may have changed above, after ctor - if (!pFile) - { - PanicAlertT( - "Could not write memory card file %s.\n\n" - "Are you running Dolphin from a CD/DVD, or is the save file maybe write protected?\n\n" - "Are you receiving this after moving the emulator directory?\nIf so, then you may " - "need to re-specify your memory card location in the options.", - m_filename.c_str()); + // Note - pFile may have changed above, after ctor + if (!pFile) + { + PanicAlertT( + "Could not write memory card file %s.\n\n" + "Are you running Dolphin from a CD/DVD, or is the save file maybe write protected?\n\n" + "Are you receiving this after moving the emulator directory?\nIf so, then you may " + "need to re-specify your memory card location in the options.", + m_filename.c_str()); - // Exit the flushing thread - further flushes will be ignored unless - // the thread is recreated. - return; - } + // Exit the flushing thread - further flushes will be ignored unless + // the thread is recreated. + return; + } - { - std::unique_lock l(m_flush_mutex); - memcpy(&m_flush_buffer[0], &m_memcard_data[0], memory_card_size); - } - pFile.WriteBytes(&m_flush_buffer[0], memory_card_size); + { + std::unique_lock l(m_flush_mutex); + memcpy(&m_flush_buffer[0], &m_memcard_data[0], memory_card_size); + } + pFile.WriteBytes(&m_flush_buffer[0], memory_card_size); - if (!do_exit) - { - Core::DisplayMessage( - StringFromFormat("Wrote memory card %c contents to %s", - card_index ? 'B' : 'A', m_filename.c_str()).c_str(), - 4000); - } - else - { - return; - } - } + if (!do_exit) + { + Core::DisplayMessage(StringFromFormat("Wrote memory card %c contents to %s", + card_index ? 'B' : 'A', m_filename.c_str()) + .c_str(), + 4000); + } + else + { + return; + } + } } void MemoryCard::MakeDirty() { - m_dirty.Set(); + m_dirty.Set(); } -s32 MemoryCard::Read(u32 srcaddress, s32 length, u8 *destaddress) +s32 MemoryCard::Read(u32 srcaddress, s32 length, u8* destaddress) { - if (!IsAddressInBounds(srcaddress)) - { - PanicAlertT("MemoryCard: Read called with invalid source address (0x%x)", - srcaddress); - return -1; - } + if (!IsAddressInBounds(srcaddress)) + { + PanicAlertT("MemoryCard: Read called with invalid source address (0x%x)", srcaddress); + return -1; + } - memcpy(destaddress, &m_memcard_data[srcaddress], length); - return length; + memcpy(destaddress, &m_memcard_data[srcaddress], length); + return length; } -s32 MemoryCard::Write(u32 destaddress, s32 length, u8 *srcaddress) +s32 MemoryCard::Write(u32 destaddress, s32 length, u8* srcaddress) { - if (!IsAddressInBounds(destaddress)) - { - PanicAlertT("MemoryCard: Write called with invalid destination address (0x%x)", - destaddress); - return -1; - } + if (!IsAddressInBounds(destaddress)) + { + PanicAlertT("MemoryCard: Write called with invalid destination address (0x%x)", destaddress); + return -1; + } - { - std::unique_lock l(m_flush_mutex); - memcpy(&m_memcard_data[destaddress], srcaddress, length); - } - MakeDirty(); - return length; + { + std::unique_lock l(m_flush_mutex); + memcpy(&m_memcard_data[destaddress], srcaddress, length); + } + MakeDirty(); + return length; } void MemoryCard::ClearBlock(u32 address) { - if (address & (BLOCK_SIZE - 1) || !IsAddressInBounds(address)) - { - PanicAlertT("MemoryCard: ClearBlock called on invalid address (0x%x)", - address); - return; - } - else - { - std::unique_lock l(m_flush_mutex); - memset(&m_memcard_data[address], 0xFF, BLOCK_SIZE); - } - MakeDirty(); + if (address & (BLOCK_SIZE - 1) || !IsAddressInBounds(address)) + { + PanicAlertT("MemoryCard: ClearBlock called on invalid address (0x%x)", address); + return; + } + else + { + std::unique_lock l(m_flush_mutex); + memset(&m_memcard_data[address], 0xFF, BLOCK_SIZE); + } + MakeDirty(); } void MemoryCard::ClearAll() { - { - std::unique_lock l(m_flush_mutex); - memset(&m_memcard_data[0], 0xFF, memory_card_size); - } - MakeDirty(); + { + std::unique_lock l(m_flush_mutex); + memset(&m_memcard_data[0], 0xFF, memory_card_size); + } + MakeDirty(); } -void MemoryCard::DoState(PointerWrap &p) +void MemoryCard::DoState(PointerWrap& p) { - p.Do(card_index); - p.Do(memory_card_size); - p.DoArray(&m_memcard_data[0], memory_card_size); + p.Do(card_index); + p.Do(memory_card_size); + p.DoArray(&m_memcard_data[0], memory_card_size); } diff --git a/Source/Core/Core/HW/GCMemcardRaw.h b/Source/Core/Core/HW/GCMemcardRaw.h index 3fb90a8602..0b0e5cf637 100644 --- a/Source/Core/Core/HW/GCMemcardRaw.h +++ b/Source/Core/Core/HW/GCMemcardRaw.h @@ -17,23 +17,23 @@ class PointerWrap; class MemoryCard : public MemoryCardBase { public: - MemoryCard(const std::string& filename, int _card_index, u16 sizeMb = MemCard2043Mb); - ~MemoryCard(); - void FlushThread(); - void MakeDirty(); + MemoryCard(const std::string& filename, int _card_index, u16 sizeMb = MemCard2043Mb); + ~MemoryCard(); + void FlushThread(); + void MakeDirty(); - s32 Read(u32 address, s32 length, u8 *destaddress) override; - s32 Write(u32 destaddress, s32 length, u8 *srcaddress) override; - void ClearBlock(u32 address) override; - void ClearAll() override; - void DoState(PointerWrap &p) override; + s32 Read(u32 address, s32 length, u8* destaddress) override; + s32 Write(u32 destaddress, s32 length, u8* srcaddress) override; + void ClearBlock(u32 address) override; + void ClearAll() override; + void DoState(PointerWrap& p) override; private: - std::string m_filename; - std::unique_ptr m_memcard_data; - std::unique_ptr m_flush_buffer; - std::thread m_flush_thread; - std::mutex m_flush_mutex; - Common::Event m_flush_trigger; - Common::Flag m_dirty; + std::string m_filename; + std::unique_ptr m_memcard_data; + std::unique_ptr m_flush_buffer; + std::thread m_flush_thread; + std::mutex m_flush_mutex; + Common::Event m_flush_trigger; + Common::Flag m_dirty; }; diff --git a/Source/Core/Core/HW/GCPad.cpp b/Source/Core/Core/HW/GCPad.cpp index 356ca5f996..70af354560 100644 --- a/Source/Core/Core/HW/GCPad.cpp +++ b/Source/Core/Core/HW/GCPad.cpp @@ -13,57 +13,54 @@ namespace Pad { - static InputConfig s_config("GCPadNew", _trans("Pad"), "GCPad"); InputConfig* GetConfig() { - return &s_config; + return &s_config; } void Shutdown() { - s_config.ClearControllers(); + s_config.ClearControllers(); - g_controller_interface.Shutdown(); + g_controller_interface.Shutdown(); } void Initialize(void* const hwnd) { - if (s_config.ControllersNeedToBeCreated()) - { - for (unsigned int i = 0; i < 4; ++i) - s_config.CreateController(i); - } + if (s_config.ControllersNeedToBeCreated()) + { + for (unsigned int i = 0; i < 4; ++i) + s_config.CreateController(i); + } - g_controller_interface.Initialize(hwnd); + g_controller_interface.Initialize(hwnd); - // Load the saved controller config - s_config.LoadConfig(true); + // Load the saved controller config + s_config.LoadConfig(true); } void LoadConfig() { - s_config.LoadConfig(true); + s_config.LoadConfig(true); } - void GetStatus(u8 pad_num, GCPadStatus* pad_status) { - memset(pad_status, 0, sizeof(*pad_status)); - pad_status->err = PAD_ERR_NONE; + memset(pad_status, 0, sizeof(*pad_status)); + pad_status->err = PAD_ERR_NONE; - // Get input - static_cast(s_config.GetController(pad_num))->GetInput(pad_status); + // Get input + static_cast(s_config.GetController(pad_num))->GetInput(pad_status); } void Rumble(const u8 pad_num, const ControlState strength) { - static_cast(s_config.GetController(pad_num))->SetOutput(strength); + static_cast(s_config.GetController(pad_num))->SetOutput(strength); } bool GetMicButton(const u8 pad_num) { - return static_cast(s_config.GetController(pad_num))->GetMicButton(); + return static_cast(s_config.GetController(pad_num))->GetMicButton(); } - } diff --git a/Source/Core/Core/HW/GCPad.h b/Source/Core/Core/HW/GCPad.h index cb9021ac2a..aff6745b07 100644 --- a/Source/Core/Core/HW/GCPad.h +++ b/Source/Core/Core/HW/GCPad.h @@ -12,7 +12,6 @@ struct GCPadStatus; namespace Pad { - void Shutdown(); void Initialize(void* const hwnd); void LoadConfig(); diff --git a/Source/Core/Core/HW/GCPadEmu.cpp b/Source/Core/Core/HW/GCPadEmu.cpp index 20ad6f9186..2c8c54b46c 100644 --- a/Source/Core/Core/HW/GCPadEmu.cpp +++ b/Source/Core/Core/HW/GCPadEmu.cpp @@ -2,198 +2,192 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/GCPadEmu.h" #include "Common/Common.h" #include "Common/CommonTypes.h" #include "Core/Host.h" -#include "Core/HW/GCPadEmu.h" -static const u16 button_bitmasks[] = -{ - PAD_BUTTON_A, - PAD_BUTTON_B, - PAD_BUTTON_X, - PAD_BUTTON_Y, - PAD_TRIGGER_Z, - PAD_BUTTON_START, - 0 // MIC HAX +static const u16 button_bitmasks[] = { + PAD_BUTTON_A, + PAD_BUTTON_B, + PAD_BUTTON_X, + PAD_BUTTON_Y, + PAD_TRIGGER_Z, + PAD_BUTTON_START, + 0 // MIC HAX }; -static const u16 trigger_bitmasks[] = -{ - PAD_TRIGGER_L, - PAD_TRIGGER_R, +static const u16 trigger_bitmasks[] = { + PAD_TRIGGER_L, PAD_TRIGGER_R, }; -static const u16 dpad_bitmasks[] = -{ - PAD_BUTTON_UP, PAD_BUTTON_DOWN, PAD_BUTTON_LEFT, PAD_BUTTON_RIGHT -}; +static const u16 dpad_bitmasks[] = {PAD_BUTTON_UP, PAD_BUTTON_DOWN, PAD_BUTTON_LEFT, + PAD_BUTTON_RIGHT}; -static const char* const named_buttons[] = -{ - "A", - "B", - "X", - "Y", - "Z", - _trans("Start"), - _trans("Mic") -}; +static const char* const named_buttons[] = {"A", "B", "X", "Y", "Z", _trans("Start"), + _trans("Mic")}; -static const char* const named_triggers[] = -{ - // i18n: Left - _trans("L"), - // i18n: Right - _trans("R"), - // i18n: Left-Analog - _trans("L-Analog"), - // i18n: Right-Analog - _trans("R-Analog") -}; +static const char* const named_triggers[] = { + // i18n: Left + _trans("L"), + // i18n: Right + _trans("R"), + // i18n: Left-Analog + _trans("L-Analog"), + // i18n: Right-Analog + _trans("R-Analog")}; GCPad::GCPad(const unsigned int index) : m_index(index) { - int const mic_hax = index > 1; + int const mic_hax = index > 1; - // buttons - groups.emplace_back(m_buttons = new Buttons(_trans("Buttons"))); - for (unsigned int i=0; i < sizeof(named_buttons)/sizeof(*named_buttons) - mic_hax; ++i) - m_buttons->controls.emplace_back(new ControlGroup::Input(named_buttons[i])); + // buttons + groups.emplace_back(m_buttons = new Buttons(_trans("Buttons"))); + for (unsigned int i = 0; i < sizeof(named_buttons) / sizeof(*named_buttons) - mic_hax; ++i) + m_buttons->controls.emplace_back(new ControlGroup::Input(named_buttons[i])); - // sticks - groups.emplace_back(m_main_stick = new AnalogStick("Main Stick", _trans("Control Stick"), DEFAULT_PAD_STICK_RADIUS)); - groups.emplace_back(m_c_stick = new AnalogStick("C-Stick", _trans("C Stick"), DEFAULT_PAD_STICK_RADIUS)); + // sticks + groups.emplace_back(m_main_stick = new AnalogStick("Main Stick", _trans("Control Stick"), + DEFAULT_PAD_STICK_RADIUS)); + groups.emplace_back(m_c_stick = + new AnalogStick("C-Stick", _trans("C Stick"), DEFAULT_PAD_STICK_RADIUS)); - // triggers - groups.emplace_back(m_triggers = new MixedTriggers(_trans("Triggers"))); - for (auto& named_trigger : named_triggers) - m_triggers->controls.emplace_back(new ControlGroup::Input(named_trigger)); + // triggers + groups.emplace_back(m_triggers = new MixedTriggers(_trans("Triggers"))); + for (auto& named_trigger : named_triggers) + m_triggers->controls.emplace_back(new ControlGroup::Input(named_trigger)); - // rumble - groups.emplace_back(m_rumble = new ControlGroup(_trans("Rumble"))); - m_rumble->controls.emplace_back(new ControlGroup::Output(_trans("Motor"))); + // rumble + groups.emplace_back(m_rumble = new ControlGroup(_trans("Rumble"))); + m_rumble->controls.emplace_back(new ControlGroup::Output(_trans("Motor"))); - // dpad - groups.emplace_back(m_dpad = new Buttons(_trans("D-Pad"))); - for (auto& named_direction : named_directions) - m_dpad->controls.emplace_back(new ControlGroup::Input(named_direction)); + // dpad + groups.emplace_back(m_dpad = new Buttons(_trans("D-Pad"))); + for (auto& named_direction : named_directions) + m_dpad->controls.emplace_back(new ControlGroup::Input(named_direction)); - // options - groups.emplace_back(m_options = new ControlGroup(_trans("Options"))); - m_options->settings.emplace_back(new ControlGroup::BackgroundInputSetting(_trans("Background Input"))); - m_options->settings.emplace_back(new ControlGroup::IterateUI(_trans("Iterative Input"))); + // options + groups.emplace_back(m_options = new ControlGroup(_trans("Options"))); + m_options->settings.emplace_back( + new ControlGroup::BackgroundInputSetting(_trans("Background Input"))); + m_options->settings.emplace_back(new ControlGroup::IterateUI(_trans("Iterative Input"))); } std::string GCPad::GetName() const { - return std::string("GCPad") + char('1'+m_index); + return std::string("GCPad") + char('1' + m_index); } void GCPad::GetInput(GCPadStatus* const pad) { - ControlState x, y, triggers[2]; + ControlState x, y, triggers[2]; - // buttons - m_buttons->GetState(&pad->button, button_bitmasks); + // buttons + m_buttons->GetState(&pad->button, button_bitmasks); - // set analog A/B analog to full or w/e, prolly not needed - if (pad->button & PAD_BUTTON_A) pad->analogA = 0xFF; - if (pad->button & PAD_BUTTON_B) pad->analogB = 0xFF; + // set analog A/B analog to full or w/e, prolly not needed + if (pad->button & PAD_BUTTON_A) + pad->analogA = 0xFF; + if (pad->button & PAD_BUTTON_B) + pad->analogB = 0xFF; - // dpad - m_dpad->GetState(&pad->button, dpad_bitmasks); + // dpad + m_dpad->GetState(&pad->button, dpad_bitmasks); - // sticks - m_main_stick->GetState(&x, &y); - pad->stickX = static_cast(GCPadStatus::MAIN_STICK_CENTER_X + (x * GCPadStatus::MAIN_STICK_RADIUS)); - pad->stickY = static_cast(GCPadStatus::MAIN_STICK_CENTER_Y + (y * GCPadStatus::MAIN_STICK_RADIUS)); + // sticks + m_main_stick->GetState(&x, &y); + pad->stickX = + static_cast(GCPadStatus::MAIN_STICK_CENTER_X + (x * GCPadStatus::MAIN_STICK_RADIUS)); + pad->stickY = + static_cast(GCPadStatus::MAIN_STICK_CENTER_Y + (y * GCPadStatus::MAIN_STICK_RADIUS)); - m_c_stick->GetState(&x, &y); - pad->substickX = static_cast(GCPadStatus::C_STICK_CENTER_X + (x * GCPadStatus::C_STICK_RADIUS)); - pad->substickY = static_cast(GCPadStatus::C_STICK_CENTER_Y + (y * GCPadStatus::C_STICK_RADIUS)); + m_c_stick->GetState(&x, &y); + pad->substickX = + static_cast(GCPadStatus::C_STICK_CENTER_X + (x * GCPadStatus::C_STICK_RADIUS)); + pad->substickY = + static_cast(GCPadStatus::C_STICK_CENTER_Y + (y * GCPadStatus::C_STICK_RADIUS)); - // triggers - m_triggers->GetState(&pad->button, trigger_bitmasks, triggers); - pad->triggerLeft = static_cast(triggers[0] * 0xFF); - pad->triggerRight = static_cast(triggers[1] * 0xFF); + // triggers + m_triggers->GetState(&pad->button, trigger_bitmasks, triggers); + pad->triggerLeft = static_cast(triggers[0] * 0xFF); + pad->triggerRight = static_cast(triggers[1] * 0xFF); } void GCPad::SetOutput(const ControlState strength) { - m_rumble->controls[0]->control_ref->State(strength); + m_rumble->controls[0]->control_ref->State(strength); } void GCPad::LoadDefaults(const ControllerInterface& ciface) { - ControllerEmu::LoadDefaults(ciface); + ControllerEmu::LoadDefaults(ciface); - // Buttons - m_buttons->SetControlExpression(0, "X"); // A - m_buttons->SetControlExpression(1, "Z"); // B - m_buttons->SetControlExpression(2, "C"); // X - m_buttons->SetControlExpression(3, "S"); // Y - m_buttons->SetControlExpression(4, "D"); // Z + // Buttons + m_buttons->SetControlExpression(0, "X"); // A + m_buttons->SetControlExpression(1, "Z"); // B + m_buttons->SetControlExpression(2, "C"); // X + m_buttons->SetControlExpression(3, "S"); // Y + m_buttons->SetControlExpression(4, "D"); // Z #ifdef _WIN32 - m_buttons->SetControlExpression(5, "!LMENU & RETURN"); // Start + m_buttons->SetControlExpression(5, "!LMENU & RETURN"); // Start #else - // OS X/Linux - m_buttons->SetControlExpression(5, "!`Alt_L` & Return"); // Start + // OS X/Linux + m_buttons->SetControlExpression(5, "!`Alt_L` & Return"); // Start #endif - // stick modifiers to 50 % - m_main_stick->controls[4]->control_ref->range = 0.5f; - m_c_stick->controls[4]->control_ref->range = 0.5f; + // stick modifiers to 50 % + m_main_stick->controls[4]->control_ref->range = 0.5f; + m_c_stick->controls[4]->control_ref->range = 0.5f; - // D-Pad - m_dpad->SetControlExpression(0, "T"); // Up - m_dpad->SetControlExpression(1, "G"); // Down - m_dpad->SetControlExpression(2, "F"); // Left - m_dpad->SetControlExpression(3, "H"); // Right + // D-Pad + m_dpad->SetControlExpression(0, "T"); // Up + m_dpad->SetControlExpression(1, "G"); // Down + m_dpad->SetControlExpression(2, "F"); // Left + m_dpad->SetControlExpression(3, "H"); // Right - // C Stick - m_c_stick->SetControlExpression(0, "I"); // Up - m_c_stick->SetControlExpression(1, "K"); // Down - m_c_stick->SetControlExpression(2, "J"); // Left - m_c_stick->SetControlExpression(3, "L"); // Right + // C Stick + m_c_stick->SetControlExpression(0, "I"); // Up + m_c_stick->SetControlExpression(1, "K"); // Down + m_c_stick->SetControlExpression(2, "J"); // Left + m_c_stick->SetControlExpression(3, "L"); // Right #ifdef _WIN32 - m_c_stick->SetControlExpression(4, "LCONTROL"); // Modifier + m_c_stick->SetControlExpression(4, "LCONTROL"); // Modifier - // Control Stick - m_main_stick->SetControlExpression(0, "UP"); // Up - m_main_stick->SetControlExpression(1, "DOWN"); // Down - m_main_stick->SetControlExpression(2, "LEFT"); // Left - m_main_stick->SetControlExpression(3, "RIGHT"); // Right - m_main_stick->SetControlExpression(4, "LSHIFT"); // Modifier + // Control Stick + m_main_stick->SetControlExpression(0, "UP"); // Up + m_main_stick->SetControlExpression(1, "DOWN"); // Down + m_main_stick->SetControlExpression(2, "LEFT"); // Left + m_main_stick->SetControlExpression(3, "RIGHT"); // Right + m_main_stick->SetControlExpression(4, "LSHIFT"); // Modifier #elif __APPLE__ - m_c_stick->SetControlExpression(4, "Left Control"); // Modifier + m_c_stick->SetControlExpression(4, "Left Control"); // Modifier - // Control Stick - m_main_stick->SetControlExpression(0, "Up Arrow"); // Up - m_main_stick->SetControlExpression(1, "Down Arrow"); // Down - m_main_stick->SetControlExpression(2, "Left Arrow"); // Left - m_main_stick->SetControlExpression(3, "Right Arrow"); // Right - m_main_stick->SetControlExpression(4, "Left Shift"); // Modifier + // Control Stick + m_main_stick->SetControlExpression(0, "Up Arrow"); // Up + m_main_stick->SetControlExpression(1, "Down Arrow"); // Down + m_main_stick->SetControlExpression(2, "Left Arrow"); // Left + m_main_stick->SetControlExpression(3, "Right Arrow"); // Right + m_main_stick->SetControlExpression(4, "Left Shift"); // Modifier #else - // not sure if these are right + // not sure if these are right - m_c_stick->SetControlExpression(4, "Control_L"); // Modifier + m_c_stick->SetControlExpression(4, "Control_L"); // Modifier - // Control Stick - m_main_stick->SetControlExpression(0, "Up"); // Up - m_main_stick->SetControlExpression(1, "Down"); // Down - m_main_stick->SetControlExpression(2, "Left"); // Left - m_main_stick->SetControlExpression(3, "Right"); // Right - m_main_stick->SetControlExpression(4, "Shift_L"); // Modifier + // Control Stick + m_main_stick->SetControlExpression(0, "Up"); // Up + m_main_stick->SetControlExpression(1, "Down"); // Down + m_main_stick->SetControlExpression(2, "Left"); // Left + m_main_stick->SetControlExpression(3, "Right"); // Right + m_main_stick->SetControlExpression(4, "Shift_L"); // Modifier #endif - // Triggers - m_triggers->SetControlExpression(0, "Q"); // L - m_triggers->SetControlExpression(1, "W"); // R + // Triggers + m_triggers->SetControlExpression(0, "Q"); // L + m_triggers->SetControlExpression(1, "W"); // R } bool GCPad::GetMicButton() const { - return (0.0f != m_buttons->controls.back()->control_ref->State()); + return (0.0f != m_buttons->controls.back()->control_ref->State()); } diff --git a/Source/Core/Core/HW/GCPadEmu.h b/Source/Core/Core/HW/GCPadEmu.h index 9ec2aabc08..d7578a5780 100644 --- a/Source/Core/Core/HW/GCPadEmu.h +++ b/Source/Core/Core/HW/GCPadEmu.h @@ -11,29 +11,27 @@ class GCPad : public ControllerEmu { public: + GCPad(const unsigned int index); + void GetInput(GCPadStatus* const pad); + void SetOutput(const ControlState strength); - GCPad(const unsigned int index); - void GetInput(GCPadStatus* const pad); - void SetOutput(const ControlState strength); + bool GetMicButton() const; - bool GetMicButton() const; + std::string GetName() const override; - std::string GetName() const override; - - void LoadDefaults(const ControllerInterface& ciface) override; + void LoadDefaults(const ControllerInterface& ciface) override; private: + Buttons* m_buttons; + AnalogStick* m_main_stick; + AnalogStick* m_c_stick; + Buttons* m_dpad; + MixedTriggers* m_triggers; + ControlGroup* m_rumble; + ControlGroup* m_options; - Buttons* m_buttons; - AnalogStick* m_main_stick; - AnalogStick* m_c_stick; - Buttons* m_dpad; - MixedTriggers* m_triggers; - ControlGroup* m_rumble; - ControlGroup* m_options; + const unsigned int m_index; - const unsigned int m_index; - - // Default analog stick radius for GameCube controllers. - static constexpr ControlState DEFAULT_PAD_STICK_RADIUS = 1.0; + // Default analog stick radius for GameCube controllers. + static constexpr ControlState DEFAULT_PAD_STICK_RADIUS = 1.0; }; diff --git a/Source/Core/Core/HW/GPFifo.cpp b/Source/Core/Core/HW/GPFifo.cpp index 5d75061d77..f48786fc7f 100644 --- a/Source/Core/Core/HW/GPFifo.cpp +++ b/Source/Core/Core/HW/GPFifo.cpp @@ -15,7 +15,6 @@ namespace GPFifo { - // 32 Byte gather pipe with extra space // Overfilling is no problem (up to the real limit), CheckGatherPipe will blast the // contents in nicely sized chunks @@ -33,125 +32,125 @@ alignas(32) u8 m_gatherPipe[GATHER_PIPE_SIZE * 16]; // pipe counter u32 m_gatherPipeCount = 0; -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - p.Do(m_gatherPipe); - p.Do(m_gatherPipeCount); + p.Do(m_gatherPipe); + p.Do(m_gatherPipeCount); } void Init() { - ResetGatherPipe(); - memset(m_gatherPipe, 0, sizeof(m_gatherPipe)); + ResetGatherPipe(); + memset(m_gatherPipe, 0, sizeof(m_gatherPipe)); } bool IsEmpty() { - return m_gatherPipeCount == 0; + return m_gatherPipeCount == 0; } void ResetGatherPipe() { - m_gatherPipeCount = 0; + m_gatherPipeCount = 0; } static void UpdateGatherPipe() { - u32 cnt; - u8* curMem = Memory::GetPointer(ProcessorInterface::Fifo_CPUWritePointer); - for (cnt = 0; m_gatherPipeCount >= GATHER_PIPE_SIZE; cnt += GATHER_PIPE_SIZE) - { - // copy the GatherPipe - memcpy(curMem, m_gatherPipe + cnt, GATHER_PIPE_SIZE); - m_gatherPipeCount -= GATHER_PIPE_SIZE; + u32 cnt; + u8* curMem = Memory::GetPointer(ProcessorInterface::Fifo_CPUWritePointer); + for (cnt = 0; m_gatherPipeCount >= GATHER_PIPE_SIZE; cnt += GATHER_PIPE_SIZE) + { + // copy the GatherPipe + memcpy(curMem, m_gatherPipe + cnt, GATHER_PIPE_SIZE); + m_gatherPipeCount -= GATHER_PIPE_SIZE; - // increase the CPUWritePointer - if (ProcessorInterface::Fifo_CPUWritePointer == ProcessorInterface::Fifo_CPUEnd) - { - ProcessorInterface::Fifo_CPUWritePointer = ProcessorInterface::Fifo_CPUBase; - curMem = Memory::GetPointer(ProcessorInterface::Fifo_CPUWritePointer); - } - else - { - curMem += GATHER_PIPE_SIZE; - ProcessorInterface::Fifo_CPUWritePointer += GATHER_PIPE_SIZE; - } + // increase the CPUWritePointer + if (ProcessorInterface::Fifo_CPUWritePointer == ProcessorInterface::Fifo_CPUEnd) + { + ProcessorInterface::Fifo_CPUWritePointer = ProcessorInterface::Fifo_CPUBase; + curMem = Memory::GetPointer(ProcessorInterface::Fifo_CPUWritePointer); + } + else + { + curMem += GATHER_PIPE_SIZE; + ProcessorInterface::Fifo_CPUWritePointer += GATHER_PIPE_SIZE; + } - CommandProcessor::GatherPipeBursted(); - } + CommandProcessor::GatherPipeBursted(); + } - // move back the spill bytes - memmove(m_gatherPipe, m_gatherPipe + cnt, m_gatherPipeCount); + // move back the spill bytes + memmove(m_gatherPipe, m_gatherPipe + cnt, m_gatherPipeCount); } void FastCheckGatherPipe() { - if (m_gatherPipeCount >= GATHER_PIPE_SIZE) - { - UpdateGatherPipe(); - } + if (m_gatherPipeCount >= GATHER_PIPE_SIZE) + { + UpdateGatherPipe(); + } } void CheckGatherPipe() { - if (m_gatherPipeCount >= GATHER_PIPE_SIZE) - { - UpdateGatherPipe(); + if (m_gatherPipeCount >= GATHER_PIPE_SIZE) + { + UpdateGatherPipe(); - // Profile where slow FIFO writes are occurring. - JitInterface::CompileExceptionCheck(JitInterface::ExceptionType::EXCEPTIONS_FIFO_WRITE); - } + // Profile where slow FIFO writes are occurring. + JitInterface::CompileExceptionCheck(JitInterface::ExceptionType::EXCEPTIONS_FIFO_WRITE); + } } void Write8(const u8 value) { - FastWrite8(value); - CheckGatherPipe(); + FastWrite8(value); + CheckGatherPipe(); } void Write16(const u16 value) { - FastWrite16(value); - CheckGatherPipe(); + FastWrite16(value); + CheckGatherPipe(); } void Write32(const u32 value) { - FastWrite32(value); - CheckGatherPipe(); + FastWrite32(value); + CheckGatherPipe(); } void Write64(const u64 value) { - FastWrite64(value); - CheckGatherPipe(); + FastWrite64(value); + CheckGatherPipe(); } void FastWrite8(const u8 value) { - m_gatherPipe[m_gatherPipeCount] = value; - ++m_gatherPipeCount; + m_gatherPipe[m_gatherPipeCount] = value; + ++m_gatherPipeCount; } void FastWrite16(u16 value) { - value = Common::swap16(value); - std::memcpy(&m_gatherPipe[m_gatherPipeCount], &value, sizeof(u16)); - m_gatherPipeCount += sizeof(u16); + value = Common::swap16(value); + std::memcpy(&m_gatherPipe[m_gatherPipeCount], &value, sizeof(u16)); + m_gatherPipeCount += sizeof(u16); } void FastWrite32(u32 value) { - value = Common::swap32(value); - std::memcpy(&m_gatherPipe[m_gatherPipeCount], &value, sizeof(u32)); - m_gatherPipeCount += sizeof(u32); + value = Common::swap32(value); + std::memcpy(&m_gatherPipe[m_gatherPipeCount], &value, sizeof(u32)); + m_gatherPipeCount += sizeof(u32); } void FastWrite64(u64 value) { - value = Common::swap64(value); - std::memcpy(&m_gatherPipe[m_gatherPipeCount], &value, sizeof(u64)); - m_gatherPipeCount += sizeof(u64); + value = Common::swap64(value); + std::memcpy(&m_gatherPipe[m_gatherPipeCount], &value, sizeof(u64)); + m_gatherPipeCount += sizeof(u64); } -} // end of namespace GPFifo +} // end of namespace GPFifo diff --git a/Source/Core/Core/HW/GPFifo.h b/Source/Core/Core/HW/GPFifo.h index e8c6cf555d..73c95e8c75 100644 --- a/Source/Core/Core/HW/GPFifo.h +++ b/Source/Core/Core/HW/GPFifo.h @@ -10,10 +10,9 @@ class PointerWrap; namespace GPFifo { - enum { - GATHER_PIPE_SIZE = 32 + GATHER_PIPE_SIZE = 32 }; // More room for the fastmodes @@ -24,7 +23,7 @@ extern u32 m_gatherPipeCount; // Init void Init(); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); // ResetGatherPipe void ResetGatherPipe(); diff --git a/Source/Core/Core/HW/HW.cpp b/Source/Core/Core/HW/HW.cpp index a1073785ed..efb8590355 100644 --- a/Source/Core/Core/HW/HW.cpp +++ b/Source/Core/Core/HW/HW.cpp @@ -9,7 +9,6 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" -#include "Core/State.h" #include "Core/HW/AudioInterface.h" #include "Core/HW/CPU.h" #include "Core/HW/DSP.h" @@ -24,91 +23,92 @@ #include "Core/HW/VideoInterface.h" #include "Core/HW/WII_IPC.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" +#include "Core/State.h" #include "DiscIO/NANDContentLoader.h" namespace HW { - void Init() - { - CoreTiming::Init(); - SystemTimers::PreInit(); +void Init() +{ + CoreTiming::Init(); + SystemTimers::PreInit(); - State::Init(); + State::Init(); - // Init the whole Hardware - AudioInterface::Init(); - VideoInterface::Init(); - SerialInterface::Init(); - ProcessorInterface::Init(); - ExpansionInterface::Init(); // Needs to be initialized before Memory - Memory::Init(); - DSP::Init(SConfig::GetInstance().bDSPHLE); - DVDInterface::Init(); - GPFifo::Init(); - CPU::Init(SConfig::GetInstance().iCPUCore); - SystemTimers::Init(); + // Init the whole Hardware + AudioInterface::Init(); + VideoInterface::Init(); + SerialInterface::Init(); + ProcessorInterface::Init(); + ExpansionInterface::Init(); // Needs to be initialized before Memory + Memory::Init(); + DSP::Init(SConfig::GetInstance().bDSPHLE); + DVDInterface::Init(); + GPFifo::Init(); + CPU::Init(SConfig::GetInstance().iCPUCore); + SystemTimers::Init(); - if (SConfig::GetInstance().bWii) - { - Common::InitializeWiiRoot(Core::g_want_determinism); - DiscIO::cUIDsys::AccessInstance().UpdateLocation(); - DiscIO::CSharedContent::AccessInstance().UpdateLocation(); - WII_IPCInterface::Init(); - WII_IPC_HLE_Interface::Init(); // Depends on Memory - } - } - - void Shutdown() - { - if (SConfig::GetInstance().bWii) - { - WII_IPC_HLE_Interface::Shutdown(); // Depends on Memory - WII_IPCInterface::Shutdown(); - Common::ShutdownWiiRoot(); - } - - SystemTimers::Shutdown(); - CPU::Shutdown(); - DVDInterface::Shutdown(); - DSP::Shutdown(); - Memory::Shutdown(); - ExpansionInterface::Shutdown(); - SerialInterface::Shutdown(); - AudioInterface::Shutdown(); - - State::Shutdown(); - CoreTiming::Shutdown(); - } - - void DoState(PointerWrap &p) - { - Memory::DoState(p); - p.DoMarker("Memory"); - VideoInterface::DoState(p); - p.DoMarker("VideoInterface"); - SerialInterface::DoState(p); - p.DoMarker("SerialInterface"); - ProcessorInterface::DoState(p); - p.DoMarker("ProcessorInterface"); - DSP::DoState(p); - p.DoMarker("DSP"); - DVDInterface::DoState(p); - p.DoMarker("DVDInterface"); - GPFifo::DoState(p); - p.DoMarker("GPFifo"); - ExpansionInterface::DoState(p); - p.DoMarker("ExpansionInterface"); - AudioInterface::DoState(p); - p.DoMarker("AudioInterface"); - - if (SConfig::GetInstance().bWii) - { - WII_IPCInterface::DoState(p); - p.DoMarker("WII_IPCInterface"); - WII_IPC_HLE_Interface::DoState(p); - p.DoMarker("WII_IPC_HLE_Interface"); - } - - p.DoMarker("WIIHW"); - } + if (SConfig::GetInstance().bWii) + { + Common::InitializeWiiRoot(Core::g_want_determinism); + DiscIO::cUIDsys::AccessInstance().UpdateLocation(); + DiscIO::CSharedContent::AccessInstance().UpdateLocation(); + WII_IPCInterface::Init(); + WII_IPC_HLE_Interface::Init(); // Depends on Memory + } +} + +void Shutdown() +{ + if (SConfig::GetInstance().bWii) + { + WII_IPC_HLE_Interface::Shutdown(); // Depends on Memory + WII_IPCInterface::Shutdown(); + Common::ShutdownWiiRoot(); + } + + SystemTimers::Shutdown(); + CPU::Shutdown(); + DVDInterface::Shutdown(); + DSP::Shutdown(); + Memory::Shutdown(); + ExpansionInterface::Shutdown(); + SerialInterface::Shutdown(); + AudioInterface::Shutdown(); + + State::Shutdown(); + CoreTiming::Shutdown(); +} + +void DoState(PointerWrap& p) +{ + Memory::DoState(p); + p.DoMarker("Memory"); + VideoInterface::DoState(p); + p.DoMarker("VideoInterface"); + SerialInterface::DoState(p); + p.DoMarker("SerialInterface"); + ProcessorInterface::DoState(p); + p.DoMarker("ProcessorInterface"); + DSP::DoState(p); + p.DoMarker("DSP"); + DVDInterface::DoState(p); + p.DoMarker("DVDInterface"); + GPFifo::DoState(p); + p.DoMarker("GPFifo"); + ExpansionInterface::DoState(p); + p.DoMarker("ExpansionInterface"); + AudioInterface::DoState(p); + p.DoMarker("AudioInterface"); + + if (SConfig::GetInstance().bWii) + { + WII_IPCInterface::DoState(p); + p.DoMarker("WII_IPCInterface"); + WII_IPC_HLE_Interface::DoState(p); + p.DoMarker("WII_IPC_HLE_Interface"); + } + + p.DoMarker("WIIHW"); +} } diff --git a/Source/Core/Core/HW/HW.h b/Source/Core/Core/HW/HW.h index 2dde0d58f4..cf947abd82 100644 --- a/Source/Core/Core/HW/HW.h +++ b/Source/Core/Core/HW/HW.h @@ -8,7 +8,7 @@ class PointerWrap; namespace HW { - void Init(); - void Shutdown(); - void DoState(PointerWrap &p); +void Init(); +void Shutdown(); +void DoState(PointerWrap& p); } diff --git a/Source/Core/Core/HW/MMIO.cpp b/Source/Core/Core/HW/MMIO.cpp index 57d30ae2e0..8ee341554d 100644 --- a/Source/Core/Core/HW/MMIO.cpp +++ b/Source/Core/Core/HW/MMIO.cpp @@ -11,7 +11,6 @@ namespace MMIO { - // Base classes for the two handling method hierarchies. Note that a single // class can inherit from both. // @@ -21,15 +20,15 @@ template class ReadHandlingMethod { public: - virtual ~ReadHandlingMethod() {} - virtual void AcceptReadVisitor(ReadHandlingMethodVisitor& v) const = 0; + virtual ~ReadHandlingMethod() {} + virtual void AcceptReadVisitor(ReadHandlingMethodVisitor& v) const = 0; }; template class WriteHandlingMethod { public: - virtual ~WriteHandlingMethod() {} - virtual void AcceptWriteVisitor(WriteHandlingMethodVisitor& v) const = 0; + virtual ~WriteHandlingMethod() {} + virtual void AcceptWriteVisitor(WriteHandlingMethodVisitor& v) const = 0; }; // Constant: handling method holds a single integer and passes it to the @@ -39,24 +38,20 @@ template class ConstantHandlingMethod : public ReadHandlingMethod { public: - explicit ConstantHandlingMethod(T value) : value_(value) - { - } - - virtual ~ConstantHandlingMethod() {} - - void AcceptReadVisitor(ReadHandlingMethodVisitor& v) const override - { - v.VisitConstant(value_); - } + explicit ConstantHandlingMethod(T value) : value_(value) {} + virtual ~ConstantHandlingMethod() {} + void AcceptReadVisitor(ReadHandlingMethodVisitor& v) const override + { + v.VisitConstant(value_); + } private: - T value_; + T value_; }; template ReadHandlingMethod* Constant(T value) { - return new ConstantHandlingMethod(value); + return new ConstantHandlingMethod(value); } // Nop: extremely simple write handling method that does nothing at all, only @@ -66,129 +61,118 @@ template class NopHandlingMethod : public WriteHandlingMethod { public: - NopHandlingMethod() {} - virtual ~NopHandlingMethod() {} - - void AcceptWriteVisitor(WriteHandlingMethodVisitor& v) const override - { - v.VisitNop(); - } + NopHandlingMethod() {} + virtual ~NopHandlingMethod() {} + void AcceptWriteVisitor(WriteHandlingMethodVisitor& v) const override { v.VisitNop(); } }; template WriteHandlingMethod* Nop() { - return new NopHandlingMethod(); + return new NopHandlingMethod(); } // Direct: handling method holds a pointer to the value where to read/write the // data from, as well as a mask that is used to restrict reading/writing only // to a given set of bits. template -class DirectHandlingMethod : public ReadHandlingMethod, - public WriteHandlingMethod +class DirectHandlingMethod : public ReadHandlingMethod, public WriteHandlingMethod { public: - DirectHandlingMethod(T* addr, u32 mask) : addr_(addr), mask_(mask) - { - } + DirectHandlingMethod(T* addr, u32 mask) : addr_(addr), mask_(mask) {} + virtual ~DirectHandlingMethod() {} + void AcceptReadVisitor(ReadHandlingMethodVisitor& v) const override + { + v.VisitDirect(addr_, mask_); + } - virtual ~DirectHandlingMethod() {} - - void AcceptReadVisitor(ReadHandlingMethodVisitor& v) const override - { - v.VisitDirect(addr_, mask_); - } - - void AcceptWriteVisitor(WriteHandlingMethodVisitor& v) const override - { - v.VisitDirect(addr_, mask_); - } + void AcceptWriteVisitor(WriteHandlingMethodVisitor& v) const override + { + v.VisitDirect(addr_, mask_); + } private: - T* addr_; - u32 mask_; + T* addr_; + u32 mask_; }; template ReadHandlingMethod* DirectRead(const T* addr, u32 mask) { - return new DirectHandlingMethod(const_cast(addr), mask); + return new DirectHandlingMethod(const_cast(addr), mask); } template ReadHandlingMethod* DirectRead(volatile const T* addr, u32 mask) { - return new DirectHandlingMethod((T*)addr, mask); + return new DirectHandlingMethod((T*)addr, mask); } template WriteHandlingMethod* DirectWrite(T* addr, u32 mask) { - return new DirectHandlingMethod(addr, mask); + return new DirectHandlingMethod(addr, mask); } template WriteHandlingMethod* DirectWrite(volatile T* addr, u32 mask) { - return new DirectHandlingMethod((T*)addr, mask); + return new DirectHandlingMethod((T*)addr, mask); } // Complex: holds a lambda that is called when a read or a write is executed. // This gives complete control to the user as to what is going to happen during // that read or write, but reduces the optimization potential. template -class ComplexHandlingMethod : public ReadHandlingMethod, - public WriteHandlingMethod +class ComplexHandlingMethod : public ReadHandlingMethod, public WriteHandlingMethod { public: - explicit ComplexHandlingMethod(std::function read_lambda) - : read_lambda_(read_lambda), write_lambda_(InvalidWriteLambda()) - { - } + explicit ComplexHandlingMethod(std::function read_lambda) + : read_lambda_(read_lambda), write_lambda_(InvalidWriteLambda()) + { + } - explicit ComplexHandlingMethod(std::function write_lambda) - : read_lambda_(InvalidReadLambda()), write_lambda_(write_lambda) - { - } + explicit ComplexHandlingMethod(std::function write_lambda) + : read_lambda_(InvalidReadLambda()), write_lambda_(write_lambda) + { + } - virtual ~ComplexHandlingMethod() {} + virtual ~ComplexHandlingMethod() {} + void AcceptReadVisitor(ReadHandlingMethodVisitor& v) const override + { + v.VisitComplex(&read_lambda_); + } - void AcceptReadVisitor(ReadHandlingMethodVisitor& v) const override - { - v.VisitComplex(&read_lambda_); - } - - void AcceptWriteVisitor(WriteHandlingMethodVisitor& v) const override - { - v.VisitComplex(&write_lambda_); - } + void AcceptWriteVisitor(WriteHandlingMethodVisitor& v) const override + { + v.VisitComplex(&write_lambda_); + } private: - std::function InvalidReadLambda() const - { - return [](u32) { - _dbg_assert_msg_(MEMMAP, 0, "Called the read lambda on a write " - "complex handler."); - return 0; - }; - } + std::function InvalidReadLambda() const + { + return [](u32) { + _dbg_assert_msg_(MEMMAP, 0, "Called the read lambda on a write " + "complex handler."); + return 0; + }; + } - std::function InvalidWriteLambda() const - { - return [](u32, T) { - _dbg_assert_msg_(MEMMAP, 0, "Called the write lambda on a read " - "complex handler."); - }; - } + std::function InvalidWriteLambda() const + { + return [](u32, T) { + _dbg_assert_msg_(MEMMAP, 0, "Called the write lambda on a read " + "complex handler."); + }; + } - std::function read_lambda_; - std::function write_lambda_; + std::function read_lambda_; + std::function write_lambda_; }; template ReadHandlingMethod* ComplexRead(std::function lambda) { - return new ComplexHandlingMethod(lambda); + return new ComplexHandlingMethod(lambda); } template WriteHandlingMethod* ComplexWrite(std::function lambda) { - return new ComplexHandlingMethod(lambda); + return new ComplexHandlingMethod(lambda); } // Invalid: specialization of the complex handling type with lambdas that @@ -196,73 +180,93 @@ WriteHandlingMethod* ComplexWrite(std::function lambda) template ReadHandlingMethod* InvalidRead() { - return ComplexRead([](u32 addr) { - ERROR_LOG(MEMMAP, "Trying to read %zu bits from an invalid MMIO (addr=%08x)", - 8 * sizeof(T), addr); - return -1; - }); + return ComplexRead([](u32 addr) { + ERROR_LOG(MEMMAP, "Trying to read %zu bits from an invalid MMIO (addr=%08x)", 8 * sizeof(T), + addr); + return -1; + }); } template WriteHandlingMethod* InvalidWrite() { - return ComplexWrite([](u32 addr, T val) { - ERROR_LOG(MEMMAP, "Trying to write %zu bits to an invalid MMIO (addr=%08x, val=%08x)", - 8 * sizeof(T), addr, (u32)val); - }); + return ComplexWrite([](u32 addr, T val) { + ERROR_LOG(MEMMAP, "Trying to write %zu bits to an invalid MMIO (addr=%08x, val=%08x)", + 8 * sizeof(T), addr, (u32)val); + }); } // Converters to larger and smaller size. Probably the most complex of these // handlers to implement. They do not define new handling method types but // instead will internally use the types defined above. -template struct SmallerAccessSize {}; -template <> struct SmallerAccessSize { typedef u8 value; }; -template <> struct SmallerAccessSize { typedef u16 value; }; +template +struct SmallerAccessSize +{ +}; +template <> +struct SmallerAccessSize +{ + typedef u8 value; +}; +template <> +struct SmallerAccessSize +{ + typedef u16 value; +}; -template struct LargerAccessSize {}; -template <> struct LargerAccessSize { typedef u16 value; }; -template <> struct LargerAccessSize { typedef u32 value; }; +template +struct LargerAccessSize +{ +}; +template <> +struct LargerAccessSize +{ + typedef u16 value; +}; +template <> +struct LargerAccessSize +{ + typedef u32 value; +}; template ReadHandlingMethod* ReadToSmaller(Mapping* mmio, u32 high_part_addr, u32 low_part_addr) { - typedef typename SmallerAccessSize::value ST; + typedef typename SmallerAccessSize::value ST; - ReadHandler* high_part = &mmio->GetHandlerForRead(high_part_addr); - ReadHandler* low_part = &mmio->GetHandlerForRead(low_part_addr); + ReadHandler* high_part = &mmio->GetHandlerForRead(high_part_addr); + ReadHandler* low_part = &mmio->GetHandlerForRead(low_part_addr); - // TODO(delroth): optimize - return ComplexRead([=](u32 addr) { - return ((T)high_part->Read(high_part_addr) << (8 * sizeof (ST))) - | low_part->Read(low_part_addr); - }); + // TODO(delroth): optimize + return ComplexRead([=](u32 addr) { + return ((T)high_part->Read(high_part_addr) << (8 * sizeof(ST))) | low_part->Read(low_part_addr); + }); } template WriteHandlingMethod* WriteToSmaller(Mapping* mmio, u32 high_part_addr, u32 low_part_addr) { - typedef typename SmallerAccessSize::value ST; + typedef typename SmallerAccessSize::value ST; - WriteHandler* high_part = &mmio->GetHandlerForWrite(high_part_addr); - WriteHandler* low_part = &mmio->GetHandlerForWrite(low_part_addr); + WriteHandler* high_part = &mmio->GetHandlerForWrite(high_part_addr); + WriteHandler* low_part = &mmio->GetHandlerForWrite(low_part_addr); - // TODO(delroth): optimize - return ComplexWrite([=](u32 addr, T val) { - high_part->Write(high_part_addr, val >> (8 * sizeof (ST))); - low_part->Write(low_part_addr, (ST)val); - }); + // TODO(delroth): optimize + return ComplexWrite([=](u32 addr, T val) { + high_part->Write(high_part_addr, val >> (8 * sizeof(ST))); + low_part->Write(low_part_addr, (ST)val); + }); } template ReadHandlingMethod* ReadToLarger(Mapping* mmio, u32 larger_addr, u32 shift) { - typedef typename LargerAccessSize::value LT; + typedef typename LargerAccessSize::value LT; - ReadHandler* large = &mmio->GetHandlerForRead(larger_addr); + ReadHandler* large = &mmio->GetHandlerForRead(larger_addr); - // TODO(delroth): optimize - return ComplexRead([large, shift](u32 addr) { - return large->Read(addr & ~(sizeof (LT) - 1)) >> shift; - }); + // TODO(delroth): optimize + return ComplexRead( + [large, shift](u32 addr) { return large->Read(addr & ~(sizeof(LT) - 1)) >> shift; }); } // Inplementation of the ReadHandler and WriteHandler class. There is a lot of @@ -274,10 +278,9 @@ ReadHandler::ReadHandler() } template -ReadHandler::ReadHandler(ReadHandlingMethod* method) - : m_Method(nullptr) +ReadHandler::ReadHandler(ReadHandlingMethod* method) : m_Method(nullptr) { - ResetMethod(method); + ResetMethod(method); } template @@ -288,40 +291,37 @@ ReadHandler::~ReadHandler() template void ReadHandler::Visit(ReadHandlingMethodVisitor& visitor) { - if (!m_Method) - InitializeInvalid(); + if (!m_Method) + InitializeInvalid(); - m_Method->AcceptReadVisitor(visitor); + m_Method->AcceptReadVisitor(visitor); } template void ReadHandler::ResetMethod(ReadHandlingMethod* method) { - m_Method.reset(method); + m_Method.reset(method); - struct FuncCreatorVisitor : public ReadHandlingMethodVisitor - { - std::function ret; + struct FuncCreatorVisitor : public ReadHandlingMethodVisitor + { + std::function ret; - void VisitConstant(T value) override - { - ret = [value](u32) { return value; }; - } + void VisitConstant(T value) override + { + ret = [value](u32) { return value; }; + } - void VisitDirect(const T* addr, u32 mask) override - { - ret = [addr, mask](u32) { return *addr & mask; }; - } + void VisitDirect(const T* addr, u32 mask) override + { + ret = [addr, mask](u32) { return *addr & mask; }; + } - void VisitComplex(const std::function* lambda) override - { - ret = *lambda; - } - }; + void VisitComplex(const std::function* lambda) override { ret = *lambda; } + }; - FuncCreatorVisitor v; - Visit(v); - m_ReadFunc = v.ret; + FuncCreatorVisitor v; + Visit(v); + m_ReadFunc = v.ret; } template @@ -330,10 +330,9 @@ WriteHandler::WriteHandler() } template -WriteHandler::WriteHandler(WriteHandlingMethod* method) - : m_Method(nullptr) +WriteHandler::WriteHandler(WriteHandlingMethod* method) : m_Method(nullptr) { - ResetMethod(method); + ResetMethod(method); } template @@ -344,45 +343,41 @@ WriteHandler::~WriteHandler() template void WriteHandler::Visit(WriteHandlingMethodVisitor& visitor) { - if (!m_Method) - InitializeInvalid(); + if (!m_Method) + InitializeInvalid(); - m_Method->AcceptWriteVisitor(visitor); + m_Method->AcceptWriteVisitor(visitor); } template void WriteHandler::ResetMethod(WriteHandlingMethod* method) { - m_Method.reset(method); + m_Method.reset(method); - struct FuncCreatorVisitor : public WriteHandlingMethodVisitor - { - std::function ret; + struct FuncCreatorVisitor : public WriteHandlingMethodVisitor + { + std::function ret; - void VisitNop() override - { - ret = [](u32, T) {}; - } + void VisitNop() override + { + ret = [](u32, T) {}; + } - void VisitDirect(T* ptr, u32 mask) override - { - ret = [ptr, mask](u32, T val) { *ptr = val & mask; }; - } + void VisitDirect(T* ptr, u32 mask) override + { + ret = [ptr, mask](u32, T val) { *ptr = val & mask; }; + } - void VisitComplex(const std::function* lambda) override - { - ret = *lambda; - } - }; + void VisitComplex(const std::function* lambda) override { ret = *lambda; } + }; - FuncCreatorVisitor v; - Visit(v); - m_WriteFunc = v.ret; + FuncCreatorVisitor v; + Visit(v); + m_WriteFunc = v.ret; } // Define all the public specializations that are exported in MMIOHandlers.h. #define MaybeExtern MMIO_PUBLIC_SPECIALIZATIONS() #undef MaybeExtern - } diff --git a/Source/Core/Core/HW/MMIO.h b/Source/Core/Core/HW/MMIO.h index 25b5a1e0cb..9584fac332 100644 --- a/Source/Core/Core/HW/MMIO.h +++ b/Source/Core/Core/HW/MMIO.h @@ -15,7 +15,6 @@ namespace MMIO { - // There are three main MMIO blocks on the Wii (only one on the GameCube): // - 0x0C00xxxx: GameCube MMIOs (CP, PE, VI, PI, MI, DSP, DVD, SI, EI, AI, GP) // - 0x0D00xxxx: Wii MMIOs and GC mirrors (IPC, DVD, SI, EI, AI) @@ -25,10 +24,10 @@ namespace MMIO // assume internally that there are only two blocks: one for GC, one for Wii. enum Block { - GC_BLOCK = 0, - WII_BLOCK = 1, + GC_BLOCK = 0, + WII_BLOCK = 1, - NUM_BLOCKS + NUM_BLOCKS }; const u32 BLOCK_SIZE = 0x10000; const u32 NUM_MMIOS = NUM_BLOCKS * BLOCK_SIZE; @@ -42,18 +41,18 @@ const u32 NUM_MMIOS = NUM_BLOCKS * BLOCK_SIZE; // interface. inline bool IsMMIOAddress(u32 address) { - if (address == 0x0C008000) - return false; // WG Pipe - if ((address & 0xFFFF0000) == 0x0C000000) - return true; // GameCube MMIOs + if (address == 0x0C008000) + return false; // WG Pipe + if ((address & 0xFFFF0000) == 0x0C000000) + return true; // GameCube MMIOs - if(SConfig::GetInstance().bWii) - { - return ((address & 0xFFFF0000) == 0x0D000000) || // Wii MMIOs - ((address & 0xFFFF0000) == 0x0D800000); // Mirror of Wii MMIOs - } + if (SConfig::GetInstance().bWii) + { + return ((address & 0xFFFF0000) == 0x0D000000) || // Wii MMIOs + ((address & 0xFFFF0000) == 0x0D800000); // Mirror of Wii MMIOs + } - return false; + return false; } // Compute the internal unique ID for a given MMIO address. This ID is computed @@ -62,159 +61,176 @@ inline bool IsMMIOAddress(u32 address) // The block ID can easily be computed by simply checking bit 24 (CC vs. CD). inline u32 UniqueID(u32 address) { - _dbg_assert_msg_(MEMMAP, ((address & 0xFFFF0000) == 0x0C000000) || - ((address & 0xFFFF0000) == 0x0D000000) || - ((address & 0xFFFF0000) == 0x0D800000), - "Trying to get the ID of a non-existing MMIO address."); + _dbg_assert_msg_(MEMMAP, ((address & 0xFFFF0000) == 0x0C000000) || + ((address & 0xFFFF0000) == 0x0D000000) || + ((address & 0xFFFF0000) == 0x0D800000), + "Trying to get the ID of a non-existing MMIO address."); - return (((address >> 24) & 1) << 16) | (address & 0xFFFF); + return (((address >> 24) & 1) << 16) | (address & 0xFFFF); } // Some utilities functions to define MMIO mappings. namespace Utils { // Allow grabbing pointers to the high and low part of a 32 bits pointer. -inline u16* LowPart(u32* ptr) { return (u16*)ptr; } -inline u16* LowPart(volatile u32* ptr) { return (u16*)ptr; } -inline u16* HighPart(u32* ptr) { return LowPart(ptr) + 1; } -inline u16* HighPart(volatile u32* ptr) { return LowPart(ptr) + 1; } +inline u16* LowPart(u32* ptr) +{ + return (u16*)ptr; +} +inline u16* LowPart(volatile u32* ptr) +{ + return (u16*)ptr; +} +inline u16* HighPart(u32* ptr) +{ + return LowPart(ptr) + 1; +} +inline u16* HighPart(volatile u32* ptr) +{ + return LowPart(ptr) + 1; +} } class Mapping { public: - // MMIO registration interface. Use this to register new MMIO handlers. - // - // Example usages can be found in just about any HW/ module in Dolphin's - // codebase. - template - void RegisterRead(u32 addr, ReadHandlingMethod* read) - { - GetHandlerForRead(addr).ResetMethod(read); - } + // MMIO registration interface. Use this to register new MMIO handlers. + // + // Example usages can be found in just about any HW/ module in Dolphin's + // codebase. + template + void RegisterRead(u32 addr, ReadHandlingMethod* read) + { + GetHandlerForRead(addr).ResetMethod(read); + } - template - void RegisterWrite(u32 addr, WriteHandlingMethod* write) - { - GetHandlerForWrite(addr).ResetMethod(write); - } + template + void RegisterWrite(u32 addr, WriteHandlingMethod* write) + { + GetHandlerForWrite(addr).ResetMethod(write); + } - template - void Register(u32 addr, ReadHandlingMethod* read, WriteHandlingMethod* write) - { - RegisterRead(addr, read); - RegisterWrite(addr, write); - } + template + void Register(u32 addr, ReadHandlingMethod* read, WriteHandlingMethod* write) + { + RegisterRead(addr, read); + RegisterWrite(addr, write); + } - // Direct read/write interface. - // - // These functions allow reading/writing an MMIO register at a given - // address. They are used by the Memory:: access functions, which are - // called in interpreter mode, from Dolphin's own code, or from JIT'd code - // where the access address could not be predicted. - template - Unit Read(u32 addr) - { - return GetHandlerForRead(addr).Read(addr); - } + // Direct read/write interface. + // + // These functions allow reading/writing an MMIO register at a given + // address. They are used by the Memory:: access functions, which are + // called in interpreter mode, from Dolphin's own code, or from JIT'd code + // where the access address could not be predicted. + template + Unit Read(u32 addr) + { + return GetHandlerForRead(addr).Read(addr); + } - template - void Write(u32 addr, Unit val) - { - GetHandlerForWrite(addr).Write(addr, val); - } + template + void Write(u32 addr, Unit val) + { + GetHandlerForWrite(addr).Write(addr, val); + } - // Handlers access interface. - // - // Use when you care more about how to access the MMIO register for an - // address than the current value of that register. For example, this is - // what could be used to implement fast MMIO accesses in Dolphin's JIT. - template - ReadHandler& GetHandlerForRead(u32 addr) - { - return GetReadHandler(UniqueID(addr) / sizeof(Unit)); - } + // Handlers access interface. + // + // Use when you care more about how to access the MMIO register for an + // address than the current value of that register. For example, this is + // what could be used to implement fast MMIO accesses in Dolphin's JIT. + template + ReadHandler& GetHandlerForRead(u32 addr) + { + return GetReadHandler(UniqueID(addr) / sizeof(Unit)); + } - template - WriteHandler& GetHandlerForWrite(u32 addr) - { - return GetWriteHandler(UniqueID(addr) / sizeof(Unit)); - } + template + WriteHandler& GetHandlerForWrite(u32 addr) + { + return GetWriteHandler(UniqueID(addr) / sizeof(Unit)); + } private: - // These arrays contain the handlers for each MMIO access type: read/write - // to 8/16/32 bits. They are indexed using the UniqueID(addr) function - // defined earlier, which maps an MMIO address to a unique ID by using the - // MMIO block ID. - // - // Each array contains NUM_MMIOS / sizeof (AccessType) because larger - // access types mean less possible adresses (assuming aligned only - // accesses). - template - struct HandlerArray - { - using Read = std::array, NUM_MMIOS / sizeof(Unit)>; - using Write = std::array, NUM_MMIOS / sizeof(Unit)>; - }; + // These arrays contain the handlers for each MMIO access type: read/write + // to 8/16/32 bits. They are indexed using the UniqueID(addr) function + // defined earlier, which maps an MMIO address to a unique ID by using the + // MMIO block ID. + // + // Each array contains NUM_MMIOS / sizeof (AccessType) because larger + // access types mean less possible adresses (assuming aligned only + // accesses). + template + struct HandlerArray + { + using Read = std::array, NUM_MMIOS / sizeof(Unit)>; + using Write = std::array, NUM_MMIOS / sizeof(Unit)>; + }; - HandlerArray::Read m_read_handlers8; - HandlerArray::Read m_read_handlers16; - HandlerArray::Read m_read_handlers32; + HandlerArray::Read m_read_handlers8; + HandlerArray::Read m_read_handlers16; + HandlerArray::Read m_read_handlers32; - HandlerArray::Write m_write_handlers8; - HandlerArray::Write m_write_handlers16; - HandlerArray::Write m_write_handlers32; + HandlerArray::Write m_write_handlers8; + HandlerArray::Write m_write_handlers16; + HandlerArray::Write m_write_handlers32; - // Getter functions for the handler arrays. - // - // TODO: - // It would be desirable to clean these methods up using tuples, i.e. doing something like - // - // auto handlers = std::tie(m_read_handlers8, m_read_handlers16, m_read_handlers32); - // return std::get(handlers)[index]; - // - // However, we cannot use this currently because of a compiler bug in clang, presumably related - // to http://llvm.org/bugs/show_bug.cgi?id=18345, due to which the above code makes the compiler - // exceed the template recursion depth. - // As a workaround, we cast all handlers to the requested one's type. This cast will - // compile to a NOP for the returned member variable, but it's necessary to get this - // code to compile at all. - template - ReadHandler& GetReadHandler(size_t index) - { - static_assert(std::is_same::value || std::is_same::value || std::is_same::value, "Invalid unit used"); - using ArrayType = typename HandlerArray::Read; - ArrayType& handler = *(std::is_same::value ? (ArrayType*)&m_read_handlers8 - : std::is_same::value ? (ArrayType*)&m_read_handlers16 - : (ArrayType*)&m_read_handlers32); - return handler[index]; - } + // Getter functions for the handler arrays. + // + // TODO: + // It would be desirable to clean these methods up using tuples, i.e. doing something like + // + // auto handlers = std::tie(m_read_handlers8, m_read_handlers16, m_read_handlers32); + // return std::get(handlers)[index]; + // + // However, we cannot use this currently because of a compiler bug in clang, presumably related + // to http://llvm.org/bugs/show_bug.cgi?id=18345, due to which the above code makes the compiler + // exceed the template recursion depth. + // As a workaround, we cast all handlers to the requested one's type. This cast will + // compile to a NOP for the returned member variable, but it's necessary to get this + // code to compile at all. + template + ReadHandler& GetReadHandler(size_t index) + { + static_assert(std::is_same::value || std::is_same::value || + std::is_same::value, + "Invalid unit used"); + using ArrayType = typename HandlerArray::Read; + ArrayType& handler = *(std::is_same::value ? + (ArrayType*)&m_read_handlers8 : + std::is_same::value ? (ArrayType*)&m_read_handlers16 : + (ArrayType*)&m_read_handlers32); + return handler[index]; + } - template - WriteHandler& GetWriteHandler(size_t index) - { - static_assert(std::is_same::value || std::is_same::value || std::is_same::value, "Invalid unit used"); - using ArrayType = typename HandlerArray::Write; - ArrayType& handler = *(std::is_same::value ? (ArrayType*)&m_write_handlers8 - : std::is_same::value ? (ArrayType*)&m_write_handlers16 - : (ArrayType*)&m_write_handlers32); - return handler[index]; - } + template + WriteHandler& GetWriteHandler(size_t index) + { + static_assert(std::is_same::value || std::is_same::value || + std::is_same::value, + "Invalid unit used"); + using ArrayType = typename HandlerArray::Write; + ArrayType& handler = *(std::is_same::value ? + (ArrayType*)&m_write_handlers8 : + std::is_same::value ? (ArrayType*)&m_write_handlers16 : + (ArrayType*)&m_write_handlers32); + return handler[index]; + } }; // Dummy 64 bits variants of these functions. While 64 bits MMIO access is // not supported, we need these in order to make the code compile. -template<> +template <> inline u64 Mapping::Read(u32 addr) { - _dbg_assert_(MEMMAP, 0); - return 0; + _dbg_assert_(MEMMAP, 0); + return 0; } -template<> +template <> inline void Mapping::Write(u32 addr, u64 val) { - _dbg_assert_(MEMMAP, 0); + _dbg_assert_(MEMMAP, 0); } - } diff --git a/Source/Core/Core/HW/MMIOHandlers.h b/Source/Core/Core/HW/MMIOHandlers.h index 2a72608232..a406320a3b 100644 --- a/Source/Core/Core/HW/MMIOHandlers.h +++ b/Source/Core/Core/HW/MMIOHandlers.h @@ -22,40 +22,51 @@ namespace MMIO { - class Mapping; // Read and write handling methods are separated for type safety. On top of // that, some handling methods require different arguments for reads and writes // (Complex, for example). -template class ReadHandlingMethod; -template class WriteHandlingMethod; +template +class ReadHandlingMethod; +template +class WriteHandlingMethod; // Constant: use when the value read on this MMIO is always the same. This is // only for reads. -template ReadHandlingMethod* Constant(T value); +template +ReadHandlingMethod* Constant(T value); // Nop: use for writes that shouldn't have any effect and shouldn't log an // error either. -template WriteHandlingMethod* Nop(); +template +WriteHandlingMethod* Nop(); // Direct: use when all the MMIO does is read/write the given value to/from a // global variable, with an optional mask applied on the read/written value. -template ReadHandlingMethod* DirectRead(const T* addr, u32 mask = 0xFFFFFFFF); -template ReadHandlingMethod* DirectRead(volatile const T* addr, u32 mask = 0xFFFFFFFF); -template WriteHandlingMethod* DirectWrite(T* addr, u32 mask = 0xFFFFFFFF); -template WriteHandlingMethod* DirectWrite(volatile T* addr, u32 mask = 0xFFFFFFFF); +template +ReadHandlingMethod* DirectRead(const T* addr, u32 mask = 0xFFFFFFFF); +template +ReadHandlingMethod* DirectRead(volatile const T* addr, u32 mask = 0xFFFFFFFF); +template +WriteHandlingMethod* DirectWrite(T* addr, u32 mask = 0xFFFFFFFF); +template +WriteHandlingMethod* DirectWrite(volatile T* addr, u32 mask = 0xFFFFFFFF); // Complex: use when no other handling method fits your needs. These allow you // to directly provide a function that will be called when a read/write needs // to be done. -template ReadHandlingMethod* ComplexRead(std::function); -template WriteHandlingMethod* ComplexWrite(std::function); +template +ReadHandlingMethod* ComplexRead(std::function); +template +WriteHandlingMethod* ComplexWrite(std::function); // Invalid: log an error and return -1 in case of a read. These are the default // handlers set for all MMIO types. -template ReadHandlingMethod* InvalidRead(); -template WriteHandlingMethod* InvalidWrite(); +template +ReadHandlingMethod* InvalidRead(); +template +WriteHandlingMethod* InvalidWrite(); // {Read,Write}To{Smaller,Larger}: these functions are not themselves handling // methods but will try to combine accesses to two handlers into one new @@ -75,9 +86,12 @@ template WriteHandlingMethod* InvalidWrite(); // // Warning: unlike the other handling methods, *ToSmaller are obviously not // available for u8, and *ToLarger are not available for u32. -template ReadHandlingMethod* ReadToSmaller(Mapping* mmio, u32 high_part_addr, u32 low_part_addr); -template WriteHandlingMethod* WriteToSmaller(Mapping* mmio, u32 high_part_addr, u32 low_part_addr); -template ReadHandlingMethod* ReadToLarger(Mapping* mmio, u32 larger_addr, u32 shift); +template +ReadHandlingMethod* ReadToSmaller(Mapping* mmio, u32 high_part_addr, u32 low_part_addr); +template +WriteHandlingMethod* WriteToSmaller(Mapping* mmio, u32 high_part_addr, u32 low_part_addr); +template +ReadHandlingMethod* ReadToLarger(Mapping* mmio, u32 larger_addr, u32 shift); // Use these visitors interfaces if you need to write code that performs // different actions based on the handling method used by a handler. Write your @@ -87,17 +101,17 @@ template class ReadHandlingMethodVisitor { public: - virtual void VisitConstant(T value) = 0; - virtual void VisitDirect(const T* addr, u32 mask) = 0; - virtual void VisitComplex(const std::function* lambda) = 0; + virtual void VisitConstant(T value) = 0; + virtual void VisitDirect(const T* addr, u32 mask) = 0; + virtual void VisitComplex(const std::function* lambda) = 0; }; template class WriteHandlingMethodVisitor { public: - virtual void VisitNop() = 0; - virtual void VisitDirect(T* addr, u32 mask) = 0; - virtual void VisitComplex(const std::function* lambda) = 0; + virtual void VisitNop() = 0; + virtual void VisitDirect(T* addr, u32 mask) = 0; + virtual void VisitComplex(const std::function* lambda) = 0; }; // These classes are INTERNAL. Do not use outside of the MMIO implementation @@ -108,82 +122,74 @@ template class ReadHandler : public NonCopyable { public: - ReadHandler(); + ReadHandler(); - // Takes ownership of "method". - ReadHandler(ReadHandlingMethod* method); + // Takes ownership of "method". + ReadHandler(ReadHandlingMethod* method); - ~ReadHandler(); + ~ReadHandler(); - // Entry point for read handling method visitors. - void Visit(ReadHandlingMethodVisitor& visitor); + // Entry point for read handling method visitors. + void Visit(ReadHandlingMethodVisitor& visitor); - T Read(u32 addr) - { - // Check if the handler has already been initialized. For real - // handlers, this will always be the case, so this branch should be - // easily predictable. - if (!m_Method) - InitializeInvalid(); + T Read(u32 addr) + { + // Check if the handler has already been initialized. For real + // handlers, this will always be the case, so this branch should be + // easily predictable. + if (!m_Method) + InitializeInvalid(); - return m_ReadFunc(addr); - } + return m_ReadFunc(addr); + } - // Internal method called when changing the internal method object. Its - // main role is to make sure the read function is updated at the same time. - void ResetMethod(ReadHandlingMethod* method); + // Internal method called when changing the internal method object. Its + // main role is to make sure the read function is updated at the same time. + void ResetMethod(ReadHandlingMethod* method); private: - // Initialize this handler to an invalid handler. Done lazily to avoid - // useless initialization of thousands of unused handler objects. - void InitializeInvalid() - { - ResetMethod(InvalidRead()); - } - - std::unique_ptr> m_Method; - std::function m_ReadFunc; + // Initialize this handler to an invalid handler. Done lazily to avoid + // useless initialization of thousands of unused handler objects. + void InitializeInvalid() { ResetMethod(InvalidRead()); } + std::unique_ptr> m_Method; + std::function m_ReadFunc; }; template class WriteHandler : public NonCopyable { public: - WriteHandler(); + WriteHandler(); - // Takes ownership of "method". - WriteHandler(WriteHandlingMethod* method); + // Takes ownership of "method". + WriteHandler(WriteHandlingMethod* method); - ~WriteHandler(); + ~WriteHandler(); - // Entry point for write handling method visitors. - void Visit(WriteHandlingMethodVisitor& visitor); + // Entry point for write handling method visitors. + void Visit(WriteHandlingMethodVisitor& visitor); - void Write(u32 addr, T val) - { - // Check if the handler has already been initialized. For real - // handlers, this will always be the case, so this branch should be - // easily predictable. - if (!m_Method) - InitializeInvalid(); + void Write(u32 addr, T val) + { + // Check if the handler has already been initialized. For real + // handlers, this will always be the case, so this branch should be + // easily predictable. + if (!m_Method) + InitializeInvalid(); - m_WriteFunc(addr, val); - } + m_WriteFunc(addr, val); + } - // Internal method called when changing the internal method object. Its - // main role is to make sure the write function is updated at the same - // time. - void ResetMethod(WriteHandlingMethod* method); + // Internal method called when changing the internal method object. Its + // main role is to make sure the write function is updated at the same + // time. + void ResetMethod(WriteHandlingMethod* method); private: - // Initialize this handler to an invalid handler. Done lazily to avoid - // useless initialization of thousands of unused handler objects. - void InitializeInvalid() - { - ResetMethod(InvalidWrite()); - } - - std::unique_ptr> m_Method; - std::function m_WriteFunc; + // Initialize this handler to an invalid handler. Done lazily to avoid + // useless initialization of thousands of unused handler objects. + void InitializeInvalid() { ResetMethod(InvalidWrite()); } + std::unique_ptr> m_Method; + std::function m_WriteFunc; }; // Boilerplate boilerplate boilerplate. @@ -195,36 +201,41 @@ private: // // The "MaybeExtern" is there because that same macro is used for declaration // (where MaybeExtern = "extern") and definition (MaybeExtern = ""). -#define MMIO_GENERIC_PUBLIC_SPECIALIZATIONS(MaybeExtern, T) \ - MaybeExtern template ReadHandlingMethod* Constant(T value); \ - MaybeExtern template WriteHandlingMethod* Nop(); \ - MaybeExtern template ReadHandlingMethod* DirectRead(const T* addr, u32 mask); \ - MaybeExtern template ReadHandlingMethod* DirectRead(volatile const T* addr, u32 mask); \ - MaybeExtern template WriteHandlingMethod* DirectWrite(T* addr, u32 mask); \ - MaybeExtern template WriteHandlingMethod* DirectWrite(volatile T* addr, u32 mask); \ - MaybeExtern template ReadHandlingMethod* ComplexRead(std::function); \ - MaybeExtern template WriteHandlingMethod* ComplexWrite(std::function); \ - MaybeExtern template ReadHandlingMethod* InvalidRead(); \ - MaybeExtern template WriteHandlingMethod* InvalidWrite(); \ - MaybeExtern template class ReadHandler; \ - MaybeExtern template class WriteHandler +#define MMIO_GENERIC_PUBLIC_SPECIALIZATIONS(MaybeExtern, T) \ + MaybeExtern template ReadHandlingMethod* Constant(T value); \ + MaybeExtern template WriteHandlingMethod* Nop(); \ + MaybeExtern template ReadHandlingMethod* DirectRead(const T* addr, u32 mask); \ + MaybeExtern template ReadHandlingMethod* DirectRead(volatile const T* addr, u32 mask); \ + MaybeExtern template WriteHandlingMethod* DirectWrite(T* addr, u32 mask); \ + MaybeExtern template WriteHandlingMethod* DirectWrite(volatile T* addr, u32 mask); \ + MaybeExtern template ReadHandlingMethod* ComplexRead(std::function); \ + MaybeExtern template WriteHandlingMethod* ComplexWrite(std::function); \ + MaybeExtern template ReadHandlingMethod* InvalidRead(); \ + MaybeExtern template WriteHandlingMethod* InvalidWrite(); \ + MaybeExtern template class ReadHandler; \ + MaybeExtern template class WriteHandler -#define MMIO_SPECIAL_PUBLIC_SPECIALIZATIONS(MaybeExtern) \ - MaybeExtern template ReadHandlingMethod* ReadToSmaller(Mapping* mmio, u32 high_part_addr, u32 low_part_addr); \ - MaybeExtern template ReadHandlingMethod* ReadToSmaller(Mapping* mmio, u32 high_part_addr, u32 low_part_addr); \ - MaybeExtern template WriteHandlingMethod* WriteToSmaller(Mapping* mmio, u32 high_part_addr, u32 low_part_addr); \ - MaybeExtern template WriteHandlingMethod* WriteToSmaller(Mapping* mmio, u32 high_part_addr, u32 low_part_addr); \ - MaybeExtern template ReadHandlingMethod* ReadToLarger(Mapping* mmio, u32 larger_addr, u32 shift); \ - MaybeExtern template ReadHandlingMethod* ReadToLarger(Mapping* mmio, u32 larger_addr, u32 shift) +#define MMIO_SPECIAL_PUBLIC_SPECIALIZATIONS(MaybeExtern) \ + MaybeExtern template ReadHandlingMethod* ReadToSmaller(Mapping* mmio, u32 high_part_addr, \ + u32 low_part_addr); \ + MaybeExtern template ReadHandlingMethod* ReadToSmaller(Mapping* mmio, u32 high_part_addr, \ + u32 low_part_addr); \ + MaybeExtern template WriteHandlingMethod* WriteToSmaller(Mapping* mmio, u32 high_part_addr, \ + u32 low_part_addr); \ + MaybeExtern template WriteHandlingMethod* WriteToSmaller(Mapping* mmio, u32 high_part_addr, \ + u32 low_part_addr); \ + MaybeExtern template ReadHandlingMethod* ReadToLarger(Mapping* mmio, u32 larger_addr, \ + u32 shift); \ + MaybeExtern template ReadHandlingMethod* ReadToLarger(Mapping* mmio, u32 larger_addr, \ + u32 shift) -#define MMIO_PUBLIC_SPECIALIZATIONS() \ - MMIO_GENERIC_PUBLIC_SPECIALIZATIONS(MaybeExtern, u8); \ - MMIO_GENERIC_PUBLIC_SPECIALIZATIONS(MaybeExtern, u16); \ - MMIO_GENERIC_PUBLIC_SPECIALIZATIONS(MaybeExtern, u32); \ - MMIO_SPECIAL_PUBLIC_SPECIALIZATIONS(MaybeExtern); +#define MMIO_PUBLIC_SPECIALIZATIONS() \ + MMIO_GENERIC_PUBLIC_SPECIALIZATIONS(MaybeExtern, u8); \ + MMIO_GENERIC_PUBLIC_SPECIALIZATIONS(MaybeExtern, u16); \ + MMIO_GENERIC_PUBLIC_SPECIALIZATIONS(MaybeExtern, u32); \ + MMIO_SPECIAL_PUBLIC_SPECIALIZATIONS(MaybeExtern); #define MaybeExtern extern MMIO_PUBLIC_SPECIALIZATIONS() #undef MaybeExtern - } diff --git a/Source/Core/Core/HW/Memmap.cpp b/Source/Core/Core/HW/Memmap.cpp index 06dcfda353..a5242a77a9 100644 --- a/Source/Core/Core/HW/Memmap.cpp +++ b/Source/Core/Core/HW/Memmap.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // NOTE: // These functions are primarily used by the interpreter versions of the LoadStore instructions. // However, if a JITed instruction (for example lwz) wants to access a bad memory area that call @@ -14,22 +13,22 @@ #include "Common/ChunkFile.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" -#include "Common/MemArena.h" #include "Common/Logging/Log.h" +#include "Common/MemArena.h" #include "Core/ConfigManager.h" #include "Core/HW/AudioInterface.h" #include "Core/HW/DSP.h" #include "Core/HW/DVDInterface.h" #include "Core/HW/EXI.h" +#include "Core/HW/MMIO.h" #include "Core/HW/Memmap.h" #include "Core/HW/MemoryInterface.h" -#include "Core/HW/MMIO.h" #include "Core/HW/ProcessorInterface.h" #include "Core/HW/SI.h" #include "Core/HW/VideoInterface.h" #include "Core/HW/WII_IPC.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/JitCommon/JitBase.h" +#include "Core/PowerPC/PowerPC.h" #include "VideoCommon/CommandProcessor.h" #include "VideoCommon/PixelEngine.h" @@ -50,7 +49,7 @@ static MemArena g_arena; // ============== // STATE_TO_SAVE -static bool m_IsInitialized = false; // Save the Init(), Shutdown() state +static bool m_IsInitialized = false; // Save the Init(), Shutdown() state // END STATE_TO_SAVE u8* m_pRAM; @@ -63,41 +62,40 @@ std::unique_ptr mmio_mapping; static std::unique_ptr InitMMIO() { - auto mmio = std::make_unique(); + auto mmio = std::make_unique(); - CommandProcessor ::RegisterMMIO(mmio.get(), 0x0C000000); - PixelEngine ::RegisterMMIO(mmio.get(), 0x0C001000); - VideoInterface ::RegisterMMIO(mmio.get(), 0x0C002000); - ProcessorInterface::RegisterMMIO(mmio.get(), 0x0C003000); - MemoryInterface ::RegisterMMIO(mmio.get(), 0x0C004000); - DSP ::RegisterMMIO(mmio.get(), 0x0C005000); - DVDInterface ::RegisterMMIO(mmio.get(), 0x0C006000); - SerialInterface ::RegisterMMIO(mmio.get(), 0x0C006400); - ExpansionInterface::RegisterMMIO(mmio.get(), 0x0C006800); - AudioInterface ::RegisterMMIO(mmio.get(), 0x0C006C00); + CommandProcessor::RegisterMMIO(mmio.get(), 0x0C000000); + PixelEngine::RegisterMMIO(mmio.get(), 0x0C001000); + VideoInterface::RegisterMMIO(mmio.get(), 0x0C002000); + ProcessorInterface::RegisterMMIO(mmio.get(), 0x0C003000); + MemoryInterface::RegisterMMIO(mmio.get(), 0x0C004000); + DSP::RegisterMMIO(mmio.get(), 0x0C005000); + DVDInterface::RegisterMMIO(mmio.get(), 0x0C006000); + SerialInterface::RegisterMMIO(mmio.get(), 0x0C006400); + ExpansionInterface::RegisterMMIO(mmio.get(), 0x0C006800); + AudioInterface::RegisterMMIO(mmio.get(), 0x0C006C00); - return mmio; + return mmio; } static std::unique_ptr InitMMIOWii() { - auto mmio = InitMMIO(); + auto mmio = InitMMIO(); - WII_IPCInterface ::RegisterMMIO(mmio.get(), 0x0D000000); - DVDInterface ::RegisterMMIO(mmio.get(), 0x0D006000); - SerialInterface ::RegisterMMIO(mmio.get(), 0x0D006400); - ExpansionInterface::RegisterMMIO(mmio.get(), 0x0D006800); - AudioInterface ::RegisterMMIO(mmio.get(), 0x0D006C00); + WII_IPCInterface::RegisterMMIO(mmio.get(), 0x0D000000); + DVDInterface::RegisterMMIO(mmio.get(), 0x0D006000); + SerialInterface::RegisterMMIO(mmio.get(), 0x0D006400); + ExpansionInterface::RegisterMMIO(mmio.get(), 0x0D006800); + AudioInterface::RegisterMMIO(mmio.get(), 0x0D006C00); - return mmio; + return mmio; } bool IsInitialized() { - return m_IsInitialized; + return m_IsInitialized; } - // Dolphin allocates memory to represent four regions: // - 32MB RAM (actually 24MB on hardware), available on Gamecube and Wii // - 64MB "EXRAM", RAM only available on Wii @@ -154,242 +152,243 @@ bool IsInitialized() // // TODO: The actual size of RAM is REALRAM_SIZE (24MB); the other 8MB shouldn't // be backed by actual memory. -static MemoryView views[] = -{ - {&m_pRAM, 0x00000000, RAM_SIZE, 0}, - {nullptr, 0x200000000, RAM_SIZE, MV_MIRROR_PREVIOUS}, - {nullptr, 0x280000000, RAM_SIZE, MV_MIRROR_PREVIOUS}, - {nullptr, 0x2C0000000, RAM_SIZE, MV_MIRROR_PREVIOUS}, - {&m_pL1Cache, 0x2E0000000, L1_CACHE_SIZE, 0}, - {&m_pFakeVMEM, 0x27E000000, FAKEVMEM_SIZE, MV_FAKE_VMEM}, - {&m_pEXRAM, 0x10000000, EXRAM_SIZE, MV_WII_ONLY}, - {nullptr, 0x290000000, EXRAM_SIZE, MV_WII_ONLY | MV_MIRROR_PREVIOUS}, - {nullptr, 0x2D0000000, EXRAM_SIZE, MV_WII_ONLY | MV_MIRROR_PREVIOUS}, +static MemoryView views[] = { + {&m_pRAM, 0x00000000, RAM_SIZE, 0}, + {nullptr, 0x200000000, RAM_SIZE, MV_MIRROR_PREVIOUS}, + {nullptr, 0x280000000, RAM_SIZE, MV_MIRROR_PREVIOUS}, + {nullptr, 0x2C0000000, RAM_SIZE, MV_MIRROR_PREVIOUS}, + {&m_pL1Cache, 0x2E0000000, L1_CACHE_SIZE, 0}, + {&m_pFakeVMEM, 0x27E000000, FAKEVMEM_SIZE, MV_FAKE_VMEM}, + {&m_pEXRAM, 0x10000000, EXRAM_SIZE, MV_WII_ONLY}, + {nullptr, 0x290000000, EXRAM_SIZE, MV_WII_ONLY | MV_MIRROR_PREVIOUS}, + {nullptr, 0x2D0000000, EXRAM_SIZE, MV_WII_ONLY | MV_MIRROR_PREVIOUS}, }; static const int num_views = sizeof(views) / sizeof(MemoryView); void Init() { - bool wii = SConfig::GetInstance().bWii; - bool bMMU = SConfig::GetInstance().bMMU; + bool wii = SConfig::GetInstance().bWii; + bool bMMU = SConfig::GetInstance().bMMU; #ifndef _ARCH_32 - // If MMU is turned off in GameCube mode, turn on fake VMEM hack. - // The fake VMEM hack's address space is above the memory space that we - // allocate on 32bit targets, so disable it there. - bFakeVMEM = !wii && !bMMU; + // If MMU is turned off in GameCube mode, turn on fake VMEM hack. + // The fake VMEM hack's address space is above the memory space that we + // allocate on 32bit targets, so disable it there. + bFakeVMEM = !wii && !bMMU; #endif - u32 flags = 0; - if (wii) - flags |= MV_WII_ONLY; - if (bFakeVMEM) - flags |= MV_FAKE_VMEM; - physical_base = MemoryMap_Setup(views, num_views, flags, &g_arena); + u32 flags = 0; + if (wii) + flags |= MV_WII_ONLY; + if (bFakeVMEM) + flags |= MV_FAKE_VMEM; + physical_base = MemoryMap_Setup(views, num_views, flags, &g_arena); #ifndef _ARCH_32 - logical_base = physical_base + 0x200000000; + logical_base = physical_base + 0x200000000; #endif - if (wii) - mmio_mapping = InitMMIOWii(); - else - mmio_mapping = InitMMIO(); + if (wii) + mmio_mapping = InitMMIOWii(); + else + mmio_mapping = InitMMIO(); - Clear(); + Clear(); - INFO_LOG(MEMMAP, "Memory system initialized. RAM at %p", m_pRAM); - m_IsInitialized = true; + INFO_LOG(MEMMAP, "Memory system initialized. RAM at %p", m_pRAM); + m_IsInitialized = true; } -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - bool wii = SConfig::GetInstance().bWii; - p.DoArray(m_pRAM, RAM_SIZE); - p.DoArray(m_pL1Cache, L1_CACHE_SIZE); - p.DoMarker("Memory RAM"); - if (bFakeVMEM) - p.DoArray(m_pFakeVMEM, FAKEVMEM_SIZE); - p.DoMarker("Memory FakeVMEM"); - if (wii) - p.DoArray(m_pEXRAM, EXRAM_SIZE); - p.DoMarker("Memory EXRAM"); + bool wii = SConfig::GetInstance().bWii; + p.DoArray(m_pRAM, RAM_SIZE); + p.DoArray(m_pL1Cache, L1_CACHE_SIZE); + p.DoMarker("Memory RAM"); + if (bFakeVMEM) + p.DoArray(m_pFakeVMEM, FAKEVMEM_SIZE); + p.DoMarker("Memory FakeVMEM"); + if (wii) + p.DoArray(m_pEXRAM, EXRAM_SIZE); + p.DoMarker("Memory EXRAM"); } void Shutdown() { - m_IsInitialized = false; - u32 flags = 0; - if (SConfig::GetInstance().bWii) flags |= MV_WII_ONLY; - if (bFakeVMEM) flags |= MV_FAKE_VMEM; - MemoryMap_Shutdown(views, num_views, flags, &g_arena); - g_arena.ReleaseSHMSegment(); - physical_base = nullptr; - logical_base = nullptr; - mmio_mapping.reset(); - INFO_LOG(MEMMAP, "Memory system shut down."); + m_IsInitialized = false; + u32 flags = 0; + if (SConfig::GetInstance().bWii) + flags |= MV_WII_ONLY; + if (bFakeVMEM) + flags |= MV_FAKE_VMEM; + MemoryMap_Shutdown(views, num_views, flags, &g_arena); + g_arena.ReleaseSHMSegment(); + physical_base = nullptr; + logical_base = nullptr; + mmio_mapping.reset(); + INFO_LOG(MEMMAP, "Memory system shut down."); } void Clear() { - if (m_pRAM) - memset(m_pRAM, 0, RAM_SIZE); - if (m_pL1Cache) - memset(m_pL1Cache, 0, L1_CACHE_SIZE); - if (SConfig::GetInstance().bWii && m_pEXRAM) - memset(m_pEXRAM, 0, EXRAM_SIZE); + if (m_pRAM) + memset(m_pRAM, 0, RAM_SIZE); + if (m_pL1Cache) + memset(m_pL1Cache, 0, L1_CACHE_SIZE); + if (SConfig::GetInstance().bWii && m_pEXRAM) + memset(m_pEXRAM, 0, EXRAM_SIZE); } bool AreMemoryBreakpointsActivated() { #ifdef ENABLE_MEM_CHECK - return true; + return true; #else - return false; + return false; #endif } static inline u8* GetPointerForRange(u32 address, size_t size) { - // Make sure we don't have a range spanning 2 separate banks - if (size >= EXRAM_SIZE) - return nullptr; + // Make sure we don't have a range spanning 2 separate banks + if (size >= EXRAM_SIZE) + return nullptr; - // Check that the beginning and end of the range are valid - u8* pointer = GetPointer(address); - if (!pointer || !GetPointer(address + u32(size) - 1)) - return nullptr; + // Check that the beginning and end of the range are valid + u8* pointer = GetPointer(address); + if (!pointer || !GetPointer(address + u32(size) - 1)) + return nullptr; - return pointer; + return pointer; } void CopyFromEmu(void* data, u32 address, size_t size) { - if (size == 0) - return; + if (size == 0) + return; - void* pointer = GetPointerForRange(address, size); - if (!pointer) - { - PanicAlert("Invalid range in CopyFromEmu. %zx bytes from 0x%08x", size, address); - return; - } - memcpy(data, pointer, size); + void* pointer = GetPointerForRange(address, size); + if (!pointer) + { + PanicAlert("Invalid range in CopyFromEmu. %zx bytes from 0x%08x", size, address); + return; + } + memcpy(data, pointer, size); } void CopyToEmu(u32 address, const void* data, size_t size) { - if (size == 0) - return; + if (size == 0) + return; - void* pointer = GetPointerForRange(address, size); - if (!pointer) - { - PanicAlert("Invalid range in CopyToEmu. %zx bytes to 0x%08x", size, address); - return; - } - memcpy(pointer, data, size); + void* pointer = GetPointerForRange(address, size); + if (!pointer) + { + PanicAlert("Invalid range in CopyToEmu. %zx bytes to 0x%08x", size, address); + return; + } + memcpy(pointer, data, size); } void Memset(u32 address, u8 value, size_t size) { - if (size == 0) - return; + if (size == 0) + return; - void* pointer = GetPointerForRange(address, size); - if (!pointer) - { - PanicAlert("Invalid range in Memset. %zx bytes at 0x%08x", size, address); - return; - } - memset(pointer, value, size); + void* pointer = GetPointerForRange(address, size); + if (!pointer) + { + PanicAlert("Invalid range in Memset. %zx bytes at 0x%08x", size, address); + return; + } + memset(pointer, value, size); } std::string GetString(u32 em_address, size_t size) { - const char* ptr = reinterpret_cast(GetPointer(em_address)); - if (ptr == nullptr) - return ""; + const char* ptr = reinterpret_cast(GetPointer(em_address)); + if (ptr == nullptr) + return ""; - if (size == 0) // Null terminated string. - { - return std::string(ptr); - } - else // Fixed size string, potentially null terminated or null padded. - { - size_t length = strnlen(ptr, size); - return std::string(ptr, length); - } + if (size == 0) // Null terminated string. + { + return std::string(ptr); + } + else // Fixed size string, potentially null terminated or null padded. + { + size_t length = strnlen(ptr, size); + return std::string(ptr, length); + } } u8* GetPointer(u32 address) { - // TODO: Should we be masking off more bits here? Can all devices access - // EXRAM? - address &= 0x3FFFFFFF; - if (address < REALRAM_SIZE) - return m_pRAM + address; + // TODO: Should we be masking off more bits here? Can all devices access + // EXRAM? + address &= 0x3FFFFFFF; + if (address < REALRAM_SIZE) + return m_pRAM + address; - if (SConfig::GetInstance().bWii) - { - if ((address >> 28) == 0x1 && (address & 0x0fffffff) < EXRAM_SIZE) - return m_pEXRAM + (address & EXRAM_MASK); - } + if (SConfig::GetInstance().bWii) + { + if ((address >> 28) == 0x1 && (address & 0x0fffffff) < EXRAM_SIZE) + return m_pEXRAM + (address & EXRAM_MASK); + } - PanicAlert("Unknown Pointer 0x%08x PC 0x%08x LR 0x%08x", address, PC, LR); + PanicAlert("Unknown Pointer 0x%08x PC 0x%08x LR 0x%08x", address, PC, LR); - return nullptr; + return nullptr; } u8 Read_U8(u32 address) { - return *GetPointer(address); + return *GetPointer(address); } u16 Read_U16(u32 address) { - return Common::swap16(GetPointer(address)); + return Common::swap16(GetPointer(address)); } u32 Read_U32(u32 address) { - return Common::swap32(GetPointer(address)); + return Common::swap32(GetPointer(address)); } u64 Read_U64(u32 address) { - return Common::swap64(GetPointer(address)); + return Common::swap64(GetPointer(address)); } void Write_U8(u8 value, u32 address) { - *GetPointer(address) = value; + *GetPointer(address) = value; } void Write_U16(u16 value, u32 address) { - u16 swapped_value = Common::swap16(value); - std::memcpy(GetPointer(address), &swapped_value, sizeof(u16)); + u16 swapped_value = Common::swap16(value); + std::memcpy(GetPointer(address), &swapped_value, sizeof(u16)); } void Write_U32(u32 value, u32 address) { - u32 swapped_value = Common::swap32(value); - std::memcpy(GetPointer(address), &swapped_value, sizeof(u32)); + u32 swapped_value = Common::swap32(value); + std::memcpy(GetPointer(address), &swapped_value, sizeof(u32)); } void Write_U64(u64 value, u32 address) { - u64 swapped_value = Common::swap64(value); - std::memcpy(GetPointer(address), &swapped_value, sizeof(u64)); + u64 swapped_value = Common::swap64(value); + std::memcpy(GetPointer(address), &swapped_value, sizeof(u64)); } void Write_U32_Swap(u32 value, u32 address) { - std::memcpy(GetPointer(address), &value, sizeof(u32)); + std::memcpy(GetPointer(address), &value, sizeof(u32)); } void Write_U64_Swap(u64 value, u32 address) { - std::memcpy(GetPointer(address), &value, sizeof(u64)); + std::memcpy(GetPointer(address), &value, sizeof(u64)); } } // namespace diff --git a/Source/Core/Core/HW/Memmap.h b/Source/Core/Core/HW/Memmap.h index a1e5240b06..ba28e28e4f 100644 --- a/Source/Core/Core/HW/Memmap.h +++ b/Source/Core/Core/HW/Memmap.h @@ -12,12 +12,15 @@ // Enable memory checks in the Debug/DebugFast builds, but NOT in release #if defined(_DEBUG) || defined(DEBUGFAST) - #define ENABLE_MEM_CHECK +#define ENABLE_MEM_CHECK #endif // Global declarations class PointerWrap; -namespace MMIO { class Mapping; } +namespace MMIO +{ +class Mapping; +} namespace Memory { @@ -40,26 +43,26 @@ extern bool bFakeVMEM; enum { - // RAM_SIZE is the amount allocated by the emulator, whereas REALRAM_SIZE is - // what will be reported in lowmem, and thus used by emulated software. - // Note: Writing to lowmem is done by IPL. If using retail IPL, it will - // always be set to 24MB. - REALRAM_SIZE = 0x01800000, - RAM_SIZE = ROUND_UP_POW2(REALRAM_SIZE), - RAM_MASK = RAM_SIZE - 1, - FAKEVMEM_SIZE = 0x02000000, - FAKEVMEM_MASK = FAKEVMEM_SIZE - 1, - L1_CACHE_SIZE = 0x00040000, - L1_CACHE_MASK = L1_CACHE_SIZE - 1, - IO_SIZE = 0x00010000, - EXRAM_SIZE = 0x04000000, - EXRAM_MASK = EXRAM_SIZE - 1, + // RAM_SIZE is the amount allocated by the emulator, whereas REALRAM_SIZE is + // what will be reported in lowmem, and thus used by emulated software. + // Note: Writing to lowmem is done by IPL. If using retail IPL, it will + // always be set to 24MB. + REALRAM_SIZE = 0x01800000, + RAM_SIZE = ROUND_UP_POW2(REALRAM_SIZE), + RAM_MASK = RAM_SIZE - 1, + FAKEVMEM_SIZE = 0x02000000, + FAKEVMEM_MASK = FAKEVMEM_SIZE - 1, + L1_CACHE_SIZE = 0x00040000, + L1_CACHE_MASK = L1_CACHE_SIZE - 1, + IO_SIZE = 0x00010000, + EXRAM_SIZE = 0x04000000, + EXRAM_MASK = EXRAM_SIZE - 1, - ADDR_MASK_HW_ACCESS = 0x0c000000, - ADDR_MASK_MEM1 = 0x20000000, + ADDR_MASK_HW_ACCESS = 0x0c000000, + ADDR_MASK_MEM1 = 0x20000000, #if _ARCH_32 - MEMVIEW32_MASK = 0x3FFFFFFF, + MEMVIEW32_MASK = 0x3FFFFFFF, #endif }; @@ -70,7 +73,7 @@ extern std::unique_ptr mmio_mapping; bool IsInitialized(); void Init(); void Shutdown(); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); void Clear(); bool AreMemoryBreakpointsActivated(); @@ -82,7 +85,7 @@ u8* GetPointer(const u32 address); void CopyFromEmu(void* data, u32 address, size_t size); void CopyToEmu(u32 address, const void* data, size_t size); void Memset(u32 address, u8 value, size_t size); -u8 Read_U8(const u32 address); +u8 Read_U8(const u32 address); u16 Read_U16(const u32 address); u32 Read_U32(const u32 address); u64 Read_U64(const u32 address); @@ -97,25 +100,24 @@ void Write_U64_Swap(const u64 var, const u32 address); template void CopyFromEmuSwapped(T* data, u32 address, size_t size) { - const T* src = reinterpret_cast(GetPointer(address)); + const T* src = reinterpret_cast(GetPointer(address)); - if(src == nullptr) - return; + if (src == nullptr) + return; - for (size_t i = 0; i < size / sizeof(T); i++) - data[i] = Common::FromBigEndian(src[i]); + for (size_t i = 0; i < size / sizeof(T); i++) + data[i] = Common::FromBigEndian(src[i]); } template void CopyToEmuSwapped(u32 address, const T* data, size_t size) { - T* dest = reinterpret_cast(GetPointer(address)); + T* dest = reinterpret_cast(GetPointer(address)); - if (dest == nullptr) - return; + if (dest == nullptr) + return; - for (size_t i = 0; i < size / sizeof(T); i++) - dest[i] = Common::FromBigEndian(data[i]); + for (size_t i = 0; i < size / sizeof(T); i++) + dest[i] = Common::FromBigEndian(data[i]); } - } diff --git a/Source/Core/Core/HW/MemoryInterface.cpp b/Source/Core/Core/HW/MemoryInterface.cpp index b97bbdc078..21e05a2bf8 100644 --- a/Source/Core/Core/HW/MemoryInterface.cpp +++ b/Source/Core/Core/HW/MemoryInterface.cpp @@ -2,212 +2,192 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/MemoryInterface.h" #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" -#include "Core/HW/MemoryInterface.h" #include "Core/HW/MMIO.h" namespace MemoryInterface { - // internal hardware addresses enum { - MI_REGION0_FIRST = 0x000, - MI_REGION0_LAST = 0x002, - MI_REGION1_FIRST = 0x004, - MI_REGION1_LAST = 0x006, - MI_REGION2_FIRST = 0x008, - MI_REGION2_LAST = 0x00A, - MI_REGION3_FIRST = 0x00C, - MI_REGION3_LAST = 0x00E, - MI_PROT_TYPE = 0x010, - MI_IRQMASK = 0x01C, - MI_IRQFLAG = 0x01E, - MI_UNKNOWN1 = 0x020, - MI_PROT_ADDR_LO = 0x022, - MI_PROT_ADDR_HI = 0x024, - MI_TIMER0_HI = 0x032, - MI_TIMER0_LO = 0x034, - MI_TIMER1_HI = 0x036, - MI_TIMER1_LO = 0x038, - MI_TIMER2_HI = 0x03A, - MI_TIMER2_LO = 0x03C, - MI_TIMER3_HI = 0x03E, - MI_TIMER3_LO = 0x040, - MI_TIMER4_HI = 0x042, - MI_TIMER4_LO = 0x044, - MI_TIMER5_HI = 0x046, - MI_TIMER5_LO = 0x048, - MI_TIMER6_HI = 0x04A, - MI_TIMER6_LO = 0x04C, - MI_TIMER7_HI = 0x04E, - MI_TIMER7_LO = 0x050, - MI_TIMER8_HI = 0x052, - MI_TIMER8_LO = 0x054, - MI_TIMER9_HI = 0x056, - MI_TIMER9_LO = 0x058, - MI_UNKNOWN2 = 0x05A, + MI_REGION0_FIRST = 0x000, + MI_REGION0_LAST = 0x002, + MI_REGION1_FIRST = 0x004, + MI_REGION1_LAST = 0x006, + MI_REGION2_FIRST = 0x008, + MI_REGION2_LAST = 0x00A, + MI_REGION3_FIRST = 0x00C, + MI_REGION3_LAST = 0x00E, + MI_PROT_TYPE = 0x010, + MI_IRQMASK = 0x01C, + MI_IRQFLAG = 0x01E, + MI_UNKNOWN1 = 0x020, + MI_PROT_ADDR_LO = 0x022, + MI_PROT_ADDR_HI = 0x024, + MI_TIMER0_HI = 0x032, + MI_TIMER0_LO = 0x034, + MI_TIMER1_HI = 0x036, + MI_TIMER1_LO = 0x038, + MI_TIMER2_HI = 0x03A, + MI_TIMER2_LO = 0x03C, + MI_TIMER3_HI = 0x03E, + MI_TIMER3_LO = 0x040, + MI_TIMER4_HI = 0x042, + MI_TIMER4_LO = 0x044, + MI_TIMER5_HI = 0x046, + MI_TIMER5_LO = 0x048, + MI_TIMER6_HI = 0x04A, + MI_TIMER6_LO = 0x04C, + MI_TIMER7_HI = 0x04E, + MI_TIMER7_LO = 0x050, + MI_TIMER8_HI = 0x052, + MI_TIMER8_LO = 0x054, + MI_TIMER9_HI = 0x056, + MI_TIMER9_LO = 0x058, + MI_UNKNOWN2 = 0x05A, }; -union MIRegion -{ - u32 hex; - struct { u16 first_page; u16 last_page; }; +union MIRegion { + u32 hex; + struct + { + u16 first_page; + u16 last_page; + }; }; -union MIProtType -{ - u16 hex; - struct - { - u16 reg0 : 2; - u16 reg1 : 2; - u16 reg2 : 2; - u16 reg3 : 2; - u16 : 8; - }; +union MIProtType { + u16 hex; + struct + { + u16 reg0 : 2; + u16 reg1 : 2; + u16 reg2 : 2; + u16 reg3 : 2; + u16 : 8; + }; }; -union MIIRQMask -{ - u16 hex; - struct - { - u16 reg0 : 1; - u16 reg1 : 1; - u16 reg2 : 1; - u16 reg3 : 1; - u16 all_regs : 1; - u16 : 11; - }; +union MIIRQMask { + u16 hex; + struct + { + u16 reg0 : 1; + u16 reg1 : 1; + u16 reg2 : 1; + u16 reg3 : 1; + u16 all_regs : 1; + u16 : 11; + }; }; -union MIIRQFlag -{ - u16 hex; - struct - { - u16 reg0 : 1; - u16 reg1 : 1; - u16 reg2 : 1; - u16 reg3 : 1; - u16 all_regs : 1; - u16 : 11; - }; +union MIIRQFlag { + u16 hex; + struct + { + u16 reg0 : 1; + u16 reg1 : 1; + u16 reg2 : 1; + u16 reg3 : 1; + u16 all_regs : 1; + u16 : 11; + }; }; -union MIProtAddr -{ - u32 hex; - struct { u16 lo; u16 hi; }; - struct - { - u32 : 5; - u32 addr : 25; - u32 : 2; - }; +union MIProtAddr { + u32 hex; + struct + { + u16 lo; + u16 hi; + }; + struct + { + u32 : 5; + u32 addr : 25; + u32 : 2; + }; }; -union MITimer -{ - u32 hex; - struct { u16 lo; u16 hi; }; +union MITimer { + u32 hex; + struct + { + u16 lo; + u16 hi; + }; }; struct MIMemStruct { - MIRegion regions[4]; - MIProtType prot_type; - MIIRQMask irq_mask; - MIIRQFlag irq_flag; - u16 unknown1; - MIProtAddr prot_addr; - MITimer timers[10]; - u16 unknown2; + MIRegion regions[4]; + MIProtType prot_type; + MIIRQMask irq_mask; + MIIRQFlag irq_flag; + u16 unknown1; + MIProtAddr prot_addr; + MITimer timers[10]; + u16 unknown2; }; // STATE_TO_SAVE static MIMemStruct g_mi_mem; -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - p.Do(g_mi_mem); + p.Do(g_mi_mem); } void RegisterMMIO(MMIO::Mapping* mmio, u32 base) { - for (int i = MI_REGION0_FIRST; i <= MI_REGION3_LAST; i += 4) - { - auto& region = g_mi_mem.regions[i / 4]; - mmio->Register(base | i, - MMIO::DirectRead(®ion.first_page), - MMIO::DirectWrite(®ion.first_page) - ); - mmio->Register(base | (i + 2), - MMIO::DirectRead(®ion.last_page), - MMIO::DirectWrite(®ion.last_page) - ); - } + for (int i = MI_REGION0_FIRST; i <= MI_REGION3_LAST; i += 4) + { + auto& region = g_mi_mem.regions[i / 4]; + mmio->Register(base | i, MMIO::DirectRead(®ion.first_page), + MMIO::DirectWrite(®ion.first_page)); + mmio->Register(base | (i + 2), MMIO::DirectRead(®ion.last_page), + MMIO::DirectWrite(®ion.last_page)); + } - mmio->Register(base | MI_PROT_TYPE, - MMIO::DirectRead(&g_mi_mem.prot_type.hex), - MMIO::DirectWrite(&g_mi_mem.prot_type.hex) - ); + mmio->Register(base | MI_PROT_TYPE, MMIO::DirectRead(&g_mi_mem.prot_type.hex), + MMIO::DirectWrite(&g_mi_mem.prot_type.hex)); - mmio->Register(base | MI_IRQMASK, - MMIO::DirectRead(&g_mi_mem.irq_mask.hex), - MMIO::DirectWrite(&g_mi_mem.irq_mask.hex) - ); + mmio->Register(base | MI_IRQMASK, MMIO::DirectRead(&g_mi_mem.irq_mask.hex), + MMIO::DirectWrite(&g_mi_mem.irq_mask.hex)); - mmio->Register(base | MI_IRQFLAG, - MMIO::DirectRead(&g_mi_mem.irq_flag.hex), - MMIO::DirectWrite(&g_mi_mem.irq_flag.hex) - ); + mmio->Register(base | MI_IRQFLAG, MMIO::DirectRead(&g_mi_mem.irq_flag.hex), + MMIO::DirectWrite(&g_mi_mem.irq_flag.hex)); - mmio->Register(base | MI_UNKNOWN1, - MMIO::DirectRead(&g_mi_mem.unknown1), - MMIO::DirectWrite(&g_mi_mem.unknown1) - ); + mmio->Register(base | MI_UNKNOWN1, MMIO::DirectRead(&g_mi_mem.unknown1), + MMIO::DirectWrite(&g_mi_mem.unknown1)); - // The naming is confusing here: the registed contains the lower part of - // the address (hence MI_..._LO but this is still the high part of the - // overall register. - mmio->Register(base | MI_PROT_ADDR_LO, - MMIO::DirectRead(&g_mi_mem.prot_addr.hi), - MMIO::DirectWrite(&g_mi_mem.prot_addr.hi) - ); - mmio->Register(base | MI_PROT_ADDR_HI, - MMIO::DirectRead(&g_mi_mem.prot_addr.lo), - MMIO::DirectWrite(&g_mi_mem.prot_addr.lo) - ); + // The naming is confusing here: the registed contains the lower part of + // the address (hence MI_..._LO but this is still the high part of the + // overall register. + mmio->Register(base | MI_PROT_ADDR_LO, MMIO::DirectRead(&g_mi_mem.prot_addr.hi), + MMIO::DirectWrite(&g_mi_mem.prot_addr.hi)); + mmio->Register(base | MI_PROT_ADDR_HI, MMIO::DirectRead(&g_mi_mem.prot_addr.lo), + MMIO::DirectWrite(&g_mi_mem.prot_addr.lo)); - for (int i = 0; i < 10; ++i) - { - auto& timer = g_mi_mem.timers[i]; - mmio->Register(base | (MI_TIMER0_HI + 4 * i), - MMIO::DirectRead(&timer.hi), - MMIO::DirectWrite(&timer.hi) - ); - mmio->Register(base | (MI_TIMER0_LO + 4 * i), - MMIO::DirectRead(&timer.lo), - MMIO::DirectWrite(&timer.lo) - ); - } + for (int i = 0; i < 10; ++i) + { + auto& timer = g_mi_mem.timers[i]; + mmio->Register(base | (MI_TIMER0_HI + 4 * i), MMIO::DirectRead(&timer.hi), + MMIO::DirectWrite(&timer.hi)); + mmio->Register(base | (MI_TIMER0_LO + 4 * i), MMIO::DirectRead(&timer.lo), + MMIO::DirectWrite(&timer.lo)); + } - mmio->Register(base | MI_UNKNOWN2, - MMIO::DirectRead(&g_mi_mem.unknown2), - MMIO::DirectWrite(&g_mi_mem.unknown2) - ); + mmio->Register(base | MI_UNKNOWN2, MMIO::DirectRead(&g_mi_mem.unknown2), + MMIO::DirectWrite(&g_mi_mem.unknown2)); - for (int i = 0; i < 0x1000; i += 4) - { - mmio->Register(base | i, - MMIO::ReadToSmaller(mmio, base | i, base | (i + 2)), - MMIO::WriteToSmaller(mmio, base | i, base | (i + 2)) - ); - } + for (int i = 0; i < 0x1000; i += 4) + { + mmio->Register(base | i, MMIO::ReadToSmaller(mmio, base | i, base | (i + 2)), + MMIO::WriteToSmaller(mmio, base | i, base | (i + 2))); + } } -} // end of namespace MemoryInterface - +} // end of namespace MemoryInterface diff --git a/Source/Core/Core/HW/MemoryInterface.h b/Source/Core/Core/HW/MemoryInterface.h index 0a1b553e1d..54b86b57cf 100644 --- a/Source/Core/Core/HW/MemoryInterface.h +++ b/Source/Core/Core/HW/MemoryInterface.h @@ -6,12 +6,15 @@ #include "Common/CommonTypes.h" -namespace MMIO { class Mapping; } +namespace MMIO +{ +class Mapping; +} class PointerWrap; namespace MemoryInterface { -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); void RegisterMMIO(MMIO::Mapping* mmio, u32 base); -} // end of namespace MemoryInterface +} // end of namespace MemoryInterface diff --git a/Source/Core/Core/HW/ProcessorInterface.cpp b/Source/Core/Core/HW/ProcessorInterface.cpp index 601d53c77e..d9a0cd82d4 100644 --- a/Source/Core/Core/HW/ProcessorInterface.cpp +++ b/Source/Core/Core/HW/ProcessorInterface.cpp @@ -14,7 +14,6 @@ namespace ProcessorInterface { - // STATE_TO_SAVE u32 m_InterruptCause; u32 m_InterruptMask; @@ -28,7 +27,6 @@ static u32 m_ResetCode; static u32 m_FlipperRev; static u32 m_Unknown; - // ID and callback for scheduling reset button presses/releases static int toggleResetButton; static void ToggleResetButtonCallback(u64 userdata, s64 cyclesLate); @@ -36,175 +34,171 @@ static void ToggleResetButtonCallback(u64 userdata, s64 cyclesLate); // Let the PPC know that an external exception is set/cleared void UpdateException(); - -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - p.Do(m_InterruptMask); - p.Do(m_InterruptCause); - p.Do(Fifo_CPUBase); - p.Do(Fifo_CPUEnd); - p.Do(Fifo_CPUWritePointer); - p.Do(m_Fifo_Reset); - p.Do(m_ResetCode); - p.Do(m_FlipperRev); - p.Do(m_Unknown); + p.Do(m_InterruptMask); + p.Do(m_InterruptCause); + p.Do(Fifo_CPUBase); + p.Do(Fifo_CPUEnd); + p.Do(Fifo_CPUWritePointer); + p.Do(m_Fifo_Reset); + p.Do(m_ResetCode); + p.Do(m_FlipperRev); + p.Do(m_Unknown); } void Init() { - m_InterruptMask = 0; - m_InterruptCause = 0; + m_InterruptMask = 0; + m_InterruptCause = 0; - Fifo_CPUBase = 0; - Fifo_CPUEnd = 0; - Fifo_CPUWritePointer = 0; - /* - Previous Flipper IDs: - 0x046500B0 = A - 0x146500B1 = B - */ - m_FlipperRev = 0x246500B1; // revision C - m_Unknown = 0; + Fifo_CPUBase = 0; + Fifo_CPUEnd = 0; + Fifo_CPUWritePointer = 0; + /* + Previous Flipper IDs: + 0x046500B0 = A + 0x146500B1 = B + */ + m_FlipperRev = 0x246500B1; // revision C + m_Unknown = 0; - m_ResetCode = 0; // Cold reset - m_InterruptCause = INT_CAUSE_RST_BUTTON | INT_CAUSE_VI; + m_ResetCode = 0; // Cold reset + m_InterruptCause = INT_CAUSE_RST_BUTTON | INT_CAUSE_VI; - toggleResetButton = CoreTiming::RegisterEvent("ToggleResetButton", ToggleResetButtonCallback); + toggleResetButton = CoreTiming::RegisterEvent("ToggleResetButton", ToggleResetButtonCallback); } void RegisterMMIO(MMIO::Mapping* mmio, u32 base) { - mmio->Register(base | PI_INTERRUPT_CAUSE, - MMIO::DirectRead(&m_InterruptCause), - MMIO::ComplexWrite([](u32, u32 val) { - m_InterruptCause &= ~val; - UpdateException(); - }) - ); + mmio->Register(base | PI_INTERRUPT_CAUSE, MMIO::DirectRead(&m_InterruptCause), + MMIO::ComplexWrite([](u32, u32 val) { + m_InterruptCause &= ~val; + UpdateException(); + })); - mmio->Register(base | PI_INTERRUPT_MASK, - MMIO::DirectRead(&m_InterruptMask), - MMIO::ComplexWrite([](u32, u32 val) { - m_InterruptMask = val; - UpdateException(); - }) - ); + mmio->Register(base | PI_INTERRUPT_MASK, MMIO::DirectRead(&m_InterruptMask), + MMIO::ComplexWrite([](u32, u32 val) { + m_InterruptMask = val; + UpdateException(); + })); - mmio->Register(base | PI_FIFO_BASE, - MMIO::DirectRead(&Fifo_CPUBase), - MMIO::DirectWrite(&Fifo_CPUBase, 0xFFFFFFE0) - ); + mmio->Register(base | PI_FIFO_BASE, MMIO::DirectRead(&Fifo_CPUBase), + MMIO::DirectWrite(&Fifo_CPUBase, 0xFFFFFFE0)); - mmio->Register(base | PI_FIFO_END, - MMIO::DirectRead(&Fifo_CPUEnd), - MMIO::DirectWrite(&Fifo_CPUEnd, 0xFFFFFFE0) - ); + mmio->Register(base | PI_FIFO_END, MMIO::DirectRead(&Fifo_CPUEnd), + MMIO::DirectWrite(&Fifo_CPUEnd, 0xFFFFFFE0)); - mmio->Register(base | PI_FIFO_WPTR, - MMIO::DirectRead(&Fifo_CPUWritePointer), - MMIO::DirectWrite(&Fifo_CPUWritePointer, 0xFFFFFFE0) - ); + mmio->Register(base | PI_FIFO_WPTR, MMIO::DirectRead(&Fifo_CPUWritePointer), + MMIO::DirectWrite(&Fifo_CPUWritePointer, 0xFFFFFFE0)); - mmio->Register(base | PI_FIFO_RESET, - MMIO::InvalidRead(), - MMIO::ComplexWrite([](u32, u32 val) { - WARN_LOG(PROCESSORINTERFACE, "Fifo reset (%08x)", val); - }) - ); + mmio->Register(base | PI_FIFO_RESET, MMIO::InvalidRead(), + MMIO::ComplexWrite( + [](u32, u32 val) { WARN_LOG(PROCESSORINTERFACE, "Fifo reset (%08x)", val); })); - mmio->Register(base | PI_RESET_CODE, - MMIO::DirectRead(&m_ResetCode), - MMIO::DirectWrite(&m_ResetCode) - ); + mmio->Register(base | PI_RESET_CODE, MMIO::DirectRead(&m_ResetCode), + MMIO::DirectWrite(&m_ResetCode)); - mmio->Register(base | PI_FLIPPER_REV, - MMIO::DirectRead(&m_FlipperRev), - MMIO::InvalidWrite() - ); + mmio->Register(base | PI_FLIPPER_REV, MMIO::DirectRead(&m_FlipperRev), + MMIO::InvalidWrite()); - // 16 bit reads are based on 32 bit reads. - for (int i = 0; i < 0x1000; i += 4) - { - mmio->Register(base | i, - MMIO::ReadToLarger(mmio, base | i, 16), - MMIO::InvalidWrite() - ); - mmio->Register(base | (i + 2), - MMIO::ReadToLarger(mmio, base | i, 0), - MMIO::InvalidWrite() - ); - } + // 16 bit reads are based on 32 bit reads. + for (int i = 0; i < 0x1000; i += 4) + { + mmio->Register(base | i, MMIO::ReadToLarger(mmio, base | i, 16), + MMIO::InvalidWrite()); + mmio->Register(base | (i + 2), MMIO::ReadToLarger(mmio, base | i, 0), + MMIO::InvalidWrite()); + } } void UpdateException() { - if ((m_InterruptCause & m_InterruptMask) != 0) - PowerPC::ppcState.Exceptions |= EXCEPTION_EXTERNAL_INT; - else - PowerPC::ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT; + if ((m_InterruptCause & m_InterruptMask) != 0) + PowerPC::ppcState.Exceptions |= EXCEPTION_EXTERNAL_INT; + else + PowerPC::ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT; } -static const char *Debug_GetInterruptName(u32 _causemask) +static const char* Debug_GetInterruptName(u32 _causemask) { - switch (_causemask) - { - case INT_CAUSE_PI: return "INT_CAUSE_PI"; - case INT_CAUSE_DI: return "INT_CAUSE_DI"; - case INT_CAUSE_RSW: return "INT_CAUSE_RSW"; - case INT_CAUSE_SI: return "INT_CAUSE_SI"; - case INT_CAUSE_EXI: return "INT_CAUSE_EXI"; - case INT_CAUSE_AI: return "INT_CAUSE_AI"; - case INT_CAUSE_DSP: return "INT_CAUSE_DSP"; - case INT_CAUSE_MEMORY: return "INT_CAUSE_MEMORY"; - case INT_CAUSE_VI: return "INT_CAUSE_VI"; - case INT_CAUSE_PE_TOKEN: return "INT_CAUSE_PE_TOKEN"; - case INT_CAUSE_PE_FINISH: return "INT_CAUSE_PE_FINISH"; - case INT_CAUSE_CP: return "INT_CAUSE_CP"; - case INT_CAUSE_DEBUG: return "INT_CAUSE_DEBUG"; - case INT_CAUSE_WII_IPC: return "INT_CAUSE_WII_IPC"; - case INT_CAUSE_HSP: return "INT_CAUSE_HSP"; - case INT_CAUSE_RST_BUTTON: return "INT_CAUSE_RST_BUTTON"; - default: return "!!! ERROR-unknown Interrupt !!!"; - } + switch (_causemask) + { + case INT_CAUSE_PI: + return "INT_CAUSE_PI"; + case INT_CAUSE_DI: + return "INT_CAUSE_DI"; + case INT_CAUSE_RSW: + return "INT_CAUSE_RSW"; + case INT_CAUSE_SI: + return "INT_CAUSE_SI"; + case INT_CAUSE_EXI: + return "INT_CAUSE_EXI"; + case INT_CAUSE_AI: + return "INT_CAUSE_AI"; + case INT_CAUSE_DSP: + return "INT_CAUSE_DSP"; + case INT_CAUSE_MEMORY: + return "INT_CAUSE_MEMORY"; + case INT_CAUSE_VI: + return "INT_CAUSE_VI"; + case INT_CAUSE_PE_TOKEN: + return "INT_CAUSE_PE_TOKEN"; + case INT_CAUSE_PE_FINISH: + return "INT_CAUSE_PE_FINISH"; + case INT_CAUSE_CP: + return "INT_CAUSE_CP"; + case INT_CAUSE_DEBUG: + return "INT_CAUSE_DEBUG"; + case INT_CAUSE_WII_IPC: + return "INT_CAUSE_WII_IPC"; + case INT_CAUSE_HSP: + return "INT_CAUSE_HSP"; + case INT_CAUSE_RST_BUTTON: + return "INT_CAUSE_RST_BUTTON"; + default: + return "!!! ERROR-unknown Interrupt !!!"; + } } void SetInterrupt(u32 _causemask, bool _bSet) { - _dbg_assert_msg_(POWERPC, Core::IsCPUThread(), "SetInterrupt from wrong thread"); + _dbg_assert_msg_(POWERPC, Core::IsCPUThread(), "SetInterrupt from wrong thread"); - if (_bSet && !(m_InterruptCause & _causemask)) - { - DEBUG_LOG(PROCESSORINTERFACE, "Setting Interrupt %s (set)", Debug_GetInterruptName(_causemask)); - } + if (_bSet && !(m_InterruptCause & _causemask)) + { + DEBUG_LOG(PROCESSORINTERFACE, "Setting Interrupt %s (set)", Debug_GetInterruptName(_causemask)); + } - if (!_bSet && (m_InterruptCause & _causemask)) - { - DEBUG_LOG(PROCESSORINTERFACE, "Setting Interrupt %s (clear)", Debug_GetInterruptName(_causemask)); - } + if (!_bSet && (m_InterruptCause & _causemask)) + { + DEBUG_LOG(PROCESSORINTERFACE, "Setting Interrupt %s (clear)", + Debug_GetInterruptName(_causemask)); + } - if (_bSet) - m_InterruptCause |= _causemask; - else - m_InterruptCause &= ~_causemask;// is there any reason to have this possibility? - // F|RES: i think the hw devices reset the interrupt in the PI to 0 - // if the interrupt cause is eliminated. that isn't done by software (afaik) - UpdateException(); + if (_bSet) + m_InterruptCause |= _causemask; + else + m_InterruptCause &= ~_causemask; // is there any reason to have this possibility? + // F|RES: i think the hw devices reset the interrupt in the PI to 0 + // if the interrupt cause is eliminated. that isn't done by software (afaik) + UpdateException(); } static void SetResetButton(bool _bSet) { - SetInterrupt(INT_CAUSE_RST_BUTTON, !_bSet); + SetInterrupt(INT_CAUSE_RST_BUTTON, !_bSet); } static void ToggleResetButtonCallback(u64 userdata, s64 cyclesLate) { - SetResetButton(!!userdata); + SetResetButton(!!userdata); } void ResetButton_Tap() { - CoreTiming::ScheduleEvent_AnyThread(0, toggleResetButton, true); - CoreTiming::ScheduleEvent_AnyThread(243000000, toggleResetButton, false); + CoreTiming::ScheduleEvent_AnyThread(0, toggleResetButton, true); + CoreTiming::ScheduleEvent_AnyThread(243000000, toggleResetButton, false); } -} // namespace ProcessorInterface +} // namespace ProcessorInterface diff --git a/Source/Core/Core/HW/ProcessorInterface.h b/Source/Core/Core/HW/ProcessorInterface.h index 3313a0e6a5..5b9310e9fb 100644 --- a/Source/Core/Core/HW/ProcessorInterface.h +++ b/Source/Core/Core/HW/ProcessorInterface.h @@ -7,45 +7,49 @@ #include "Common/CommonTypes.h" class PointerWrap; -namespace MMIO { class Mapping; } +namespace MMIO +{ +class Mapping; +} -// Holds statuses of things like the write gatherer used for fifos, and interrupts from various sources +// Holds statuses of things like the write gatherer used for fifos, and interrupts from various +// sources namespace ProcessorInterface { - enum InterruptCause { - INT_CAUSE_PI = 0x1, // YAGCD says: GP runtime error - INT_CAUSE_RSW = 0x2, // Reset Switch - INT_CAUSE_DI = 0x4, // DVD interrupt - INT_CAUSE_SI = 0x8, // Serial interface - INT_CAUSE_EXI = 0x10, // Expansion interface - INT_CAUSE_AI = 0x20, // Audio Interface Streaming - INT_CAUSE_DSP = 0x40, // DSP interface - INT_CAUSE_MEMORY = 0x80, // Memory interface - INT_CAUSE_VI = 0x100, // Video interface - INT_CAUSE_PE_TOKEN = 0x200, // GP Token - INT_CAUSE_PE_FINISH = 0x400, // GP Finished - INT_CAUSE_CP = 0x800, // Command Fifo - INT_CAUSE_DEBUG = 0x1000, // Debugger (from devkit) - INT_CAUSE_HSP = 0x2000, // High Speed Port (from sdram controller) - INT_CAUSE_WII_IPC = 0x4000, // Wii IPC - INT_CAUSE_RST_BUTTON = 0x10000 // ResetButtonState (1 = unpressed, 0 = pressed) it's a state, not maskable + INT_CAUSE_PI = 0x1, // YAGCD says: GP runtime error + INT_CAUSE_RSW = 0x2, // Reset Switch + INT_CAUSE_DI = 0x4, // DVD interrupt + INT_CAUSE_SI = 0x8, // Serial interface + INT_CAUSE_EXI = 0x10, // Expansion interface + INT_CAUSE_AI = 0x20, // Audio Interface Streaming + INT_CAUSE_DSP = 0x40, // DSP interface + INT_CAUSE_MEMORY = 0x80, // Memory interface + INT_CAUSE_VI = 0x100, // Video interface + INT_CAUSE_PE_TOKEN = 0x200, // GP Token + INT_CAUSE_PE_FINISH = 0x400, // GP Finished + INT_CAUSE_CP = 0x800, // Command Fifo + INT_CAUSE_DEBUG = 0x1000, // Debugger (from devkit) + INT_CAUSE_HSP = 0x2000, // High Speed Port (from sdram controller) + INT_CAUSE_WII_IPC = 0x4000, // Wii IPC + INT_CAUSE_RST_BUTTON = + 0x10000 // ResetButtonState (1 = unpressed, 0 = pressed) it's a state, not maskable }; // Internal hardware addresses enum { - PI_INTERRUPT_CAUSE = 0x00, - PI_INTERRUPT_MASK = 0x04, - PI_FIFO_BASE = 0x0C, - PI_FIFO_END = 0x10, - PI_FIFO_WPTR = 0x14, - PI_FIFO_RESET = 0x18, // ??? - GXAbortFrame writes to it - PI_RESET_CODE = 0x24, - PI_FLIPPER_REV = 0x2C, - PI_FLIPPER_UNK = 0x30 // BS1 writes 0x0245248A to it - prolly some bootstrap thing + PI_INTERRUPT_CAUSE = 0x00, + PI_INTERRUPT_MASK = 0x04, + PI_FIFO_BASE = 0x0C, + PI_FIFO_END = 0x10, + PI_FIFO_WPTR = 0x14, + PI_FIFO_RESET = 0x18, // ??? - GXAbortFrame writes to it + PI_RESET_CODE = 0x24, + PI_FLIPPER_REV = 0x2C, + PI_FLIPPER_UNK = 0x30 // BS1 writes 0x0245248A to it - prolly some bootstrap thing }; extern u32 m_InterruptCause; @@ -54,18 +58,23 @@ extern u32 Fifo_CPUBase; extern u32 Fifo_CPUEnd; extern u32 Fifo_CPUWritePointer; - void Init(); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); void RegisterMMIO(MMIO::Mapping* mmio, u32 base); -inline u32 GetMask() { return m_InterruptMask; } -inline u32 GetCause() { return m_InterruptCause; } +inline u32 GetMask() +{ + return m_InterruptMask; +} +inline u32 GetCause() +{ + return m_InterruptCause; +} -void SetInterrupt(u32 _causemask, bool _bSet=true); +void SetInterrupt(u32 _causemask, bool _bSet = true); // Thread-safe func which sets and clears reset button state automagically void ResetButton_Tap(); -} // namespace ProcessorInterface +} // namespace ProcessorInterface diff --git a/Source/Core/Core/HW/SI.cpp b/Source/Core/Core/HW/SI.cpp index db5c6212c3..c0c2566ec7 100644 --- a/Source/Core/Core/HW/SI.cpp +++ b/Source/Core/Core/HW/SI.cpp @@ -11,18 +11,17 @@ #include "Common/CommonTypes.h" #include "Core/ConfigManager.h" #include "Core/CoreTiming.h" -#include "Core/Movie.h" -#include "Core/NetPlayProto.h" #include "Core/HW/MMIO.h" #include "Core/HW/ProcessorInterface.h" #include "Core/HW/SI.h" #include "Core/HW/SI_DeviceGBA.h" +#include "Core/Movie.h" +#include "Core/NetPlayProto.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" namespace SerialInterface { - static int changeDevice; static int et_transfer_pending; @@ -32,222 +31,215 @@ static void UpdateInterrupts(); // SI Interrupt Types enum SIInterruptType { - INT_RDSTINT = 0, - INT_TCINT = 1, + INT_RDSTINT = 0, + INT_TCINT = 1, }; static void GenerateSIInterrupt(SIInterruptType _SIInterrupt); // SI Internal Hardware Addresses enum { - SI_CHANNEL_0_OUT = 0x00, - SI_CHANNEL_0_IN_HI = 0x04, - SI_CHANNEL_0_IN_LO = 0x08, - SI_CHANNEL_1_OUT = 0x0C, - SI_CHANNEL_1_IN_HI = 0x10, - SI_CHANNEL_1_IN_LO = 0x14, - SI_CHANNEL_2_OUT = 0x18, - SI_CHANNEL_2_IN_HI = 0x1C, - SI_CHANNEL_2_IN_LO = 0x20, - SI_CHANNEL_3_OUT = 0x24, - SI_CHANNEL_3_IN_HI = 0x28, - SI_CHANNEL_3_IN_LO = 0x2C, - SI_POLL = 0x30, - SI_COM_CSR = 0x34, - SI_STATUS_REG = 0x38, - SI_EXI_CLOCK_COUNT = 0x3C, + SI_CHANNEL_0_OUT = 0x00, + SI_CHANNEL_0_IN_HI = 0x04, + SI_CHANNEL_0_IN_LO = 0x08, + SI_CHANNEL_1_OUT = 0x0C, + SI_CHANNEL_1_IN_HI = 0x10, + SI_CHANNEL_1_IN_LO = 0x14, + SI_CHANNEL_2_OUT = 0x18, + SI_CHANNEL_2_IN_HI = 0x1C, + SI_CHANNEL_2_IN_LO = 0x20, + SI_CHANNEL_3_OUT = 0x24, + SI_CHANNEL_3_IN_HI = 0x28, + SI_CHANNEL_3_IN_LO = 0x2C, + SI_POLL = 0x30, + SI_COM_CSR = 0x34, + SI_STATUS_REG = 0x38, + SI_EXI_CLOCK_COUNT = 0x3C, }; // SI Channel Output -union USIChannelOut -{ - u32 Hex; - struct - { - u32 OUTPUT1 : 8; - u32 OUTPUT0 : 8; - u32 CMD : 8; - u32 : 8; - }; +union USIChannelOut { + u32 Hex; + struct + { + u32 OUTPUT1 : 8; + u32 OUTPUT0 : 8; + u32 CMD : 8; + u32 : 8; + }; }; // SI Channel Input High u32 -union USIChannelIn_Hi -{ - u32 Hex; - struct - { - u32 INPUT3 : 8; - u32 INPUT2 : 8; - u32 INPUT1 : 8; - u32 INPUT0 : 6; - u32 ERRLATCH : 1; // 0: no error 1: Error latched. Check SISR. - u32 ERRSTAT : 1; // 0: no error 1: error on last transfer - }; +union USIChannelIn_Hi { + u32 Hex; + struct + { + u32 INPUT3 : 8; + u32 INPUT2 : 8; + u32 INPUT1 : 8; + u32 INPUT0 : 6; + u32 ERRLATCH : 1; // 0: no error 1: Error latched. Check SISR. + u32 ERRSTAT : 1; // 0: no error 1: error on last transfer + }; }; // SI Channel Input Low u32 -union USIChannelIn_Lo -{ - u32 Hex; - struct - { - u32 INPUT7 : 8; - u32 INPUT6 : 8; - u32 INPUT5 : 8; - u32 INPUT4 : 8; - }; +union USIChannelIn_Lo { + u32 Hex; + struct + { + u32 INPUT7 : 8; + u32 INPUT6 : 8; + u32 INPUT5 : 8; + u32 INPUT4 : 8; + }; }; // SI Channel struct SSIChannel { - USIChannelOut m_Out; - USIChannelIn_Hi m_InHi; - USIChannelIn_Lo m_InLo; - std::unique_ptr m_device; + USIChannelOut m_Out; + USIChannelIn_Hi m_InHi; + USIChannelIn_Lo m_InLo; + std::unique_ptr m_device; }; // SI Poll: Controls how often a device is polled -union USIPoll -{ - u32 Hex; - struct - { - u32 VBCPY3 : 1; // 1: write to output buffer only on vblank - u32 VBCPY2 : 1; - u32 VBCPY1 : 1; - u32 VBCPY0 : 1; - u32 EN3 : 1; // Enable polling of channel - u32 EN2 : 1; // does not affect communication RAM transfers - u32 EN1 : 1; - u32 EN0 : 1; - u32 Y : 8; // Polls per frame - u32 X : 10; // Polls per X lines. begins at vsync, min 7, max depends on video mode - u32 : 6; - }; +union USIPoll { + u32 Hex; + struct + { + u32 VBCPY3 : 1; // 1: write to output buffer only on vblank + u32 VBCPY2 : 1; + u32 VBCPY1 : 1; + u32 VBCPY0 : 1; + u32 EN3 : 1; // Enable polling of channel + u32 EN2 : 1; // does not affect communication RAM transfers + u32 EN1 : 1; + u32 EN0 : 1; + u32 Y : 8; // Polls per frame + u32 X : 10; // Polls per X lines. begins at vsync, min 7, max depends on video mode + u32 : 6; + }; }; // SI Communication Control Status Register -union USIComCSR -{ - u32 Hex; - struct - { - u32 TSTART : 1; // write: start transfer read: transfer status - u32 CHANNEL : 2; // determines which SI channel will be used on the communication interface. - u32 : 3; - u32 CALLBEN : 1; // Callback enable - u32 CMDEN : 1; // Command enable? - u32 INLNGTH : 7; - u32 : 1; - u32 OUTLNGTH : 7; // Communication Channel Output Length in bytes - u32 : 1; - u32 CHANEN : 1; // Channel enable? - u32 CHANNUM : 2; // Channel number? - u32 RDSTINTMSK : 1; // Read Status Interrupt Status Mask - u32 RDSTINT : 1; // Read Status Interrupt Status - u32 COMERR : 1; // Communication Error (set 0) - u32 TCINTMSK : 1; // Transfer Complete Interrupt Mask - u32 TCINT : 1; // Transfer Complete Interrupt - }; - USIComCSR() {Hex = 0;} - USIComCSR(u32 _hex) {Hex = _hex;} +union USIComCSR { + u32 Hex; + struct + { + u32 TSTART : 1; // write: start transfer read: transfer status + u32 CHANNEL : 2; // determines which SI channel will be used on the communication interface. + u32 : 3; + u32 CALLBEN : 1; // Callback enable + u32 CMDEN : 1; // Command enable? + u32 INLNGTH : 7; + u32 : 1; + u32 OUTLNGTH : 7; // Communication Channel Output Length in bytes + u32 : 1; + u32 CHANEN : 1; // Channel enable? + u32 CHANNUM : 2; // Channel number? + u32 RDSTINTMSK : 1; // Read Status Interrupt Status Mask + u32 RDSTINT : 1; // Read Status Interrupt Status + u32 COMERR : 1; // Communication Error (set 0) + u32 TCINTMSK : 1; // Transfer Complete Interrupt Mask + u32 TCINT : 1; // Transfer Complete Interrupt + }; + USIComCSR() { Hex = 0; } + USIComCSR(u32 _hex) { Hex = _hex; } }; // SI Status Register -union USIStatusReg -{ - u32 Hex; - struct - { - u32 UNRUN3 : 1; // (RWC) write 1: bit cleared read 1: main proc underrun error - u32 OVRUN3 : 1; // (RWC) write 1: bit cleared read 1: overrun error - u32 COLL3 : 1; // (RWC) write 1: bit cleared read 1: collision error - u32 NOREP3 : 1; // (RWC) write 1: bit cleared read 1: response error - u32 WRST3 : 1; // (R) 1: buffer channel0 not copied - u32 RDST3 : 1; // (R) 1: new Data available - u32 : 2; // 7:6 - u32 UNRUN2 : 1; // (RWC) write 1: bit cleared read 1: main proc underrun error - u32 OVRUN2 : 1; // (RWC) write 1: bit cleared read 1: overrun error - u32 COLL2 : 1; // (RWC) write 1: bit cleared read 1: collision error - u32 NOREP2 : 1; // (RWC) write 1: bit cleared read 1: response error - u32 WRST2 : 1; // (R) 1: buffer channel0 not copied - u32 RDST2 : 1; // (R) 1: new Data available - u32 : 2; // 15:14 - u32 UNRUN1 : 1; // (RWC) write 1: bit cleared read 1: main proc underrun error - u32 OVRUN1 : 1; // (RWC) write 1: bit cleared read 1: overrun error - u32 COLL1 : 1; // (RWC) write 1: bit cleared read 1: collision error - u32 NOREP1 : 1; // (RWC) write 1: bit cleared read 1: response error - u32 WRST1 : 1; // (R) 1: buffer channel0 not copied - u32 RDST1 : 1; // (R) 1: new Data available - u32 : 2; // 23:22 - u32 UNRUN0 : 1; // (RWC) write 1: bit cleared read 1: main proc underrun error - u32 OVRUN0 : 1; // (RWC) write 1: bit cleared read 1: overrun error - u32 COLL0 : 1; // (RWC) write 1: bit cleared read 1: collision error - u32 NOREP0 : 1; // (RWC) write 1: bit cleared read 1: response error - u32 WRST0 : 1; // (R) 1: buffer channel0 not copied - u32 RDST0 : 1; // (R) 1: new Data available - u32 : 1; - u32 WR : 1; // (RW) write 1 start copy, read 0 copy done - }; - USIStatusReg() {Hex = 0;} - USIStatusReg(u32 _hex) {Hex = _hex;} +union USIStatusReg { + u32 Hex; + struct + { + u32 UNRUN3 : 1; // (RWC) write 1: bit cleared read 1: main proc underrun error + u32 OVRUN3 : 1; // (RWC) write 1: bit cleared read 1: overrun error + u32 COLL3 : 1; // (RWC) write 1: bit cleared read 1: collision error + u32 NOREP3 : 1; // (RWC) write 1: bit cleared read 1: response error + u32 WRST3 : 1; // (R) 1: buffer channel0 not copied + u32 RDST3 : 1; // (R) 1: new Data available + u32 : 2; // 7:6 + u32 UNRUN2 : 1; // (RWC) write 1: bit cleared read 1: main proc underrun error + u32 OVRUN2 : 1; // (RWC) write 1: bit cleared read 1: overrun error + u32 COLL2 : 1; // (RWC) write 1: bit cleared read 1: collision error + u32 NOREP2 : 1; // (RWC) write 1: bit cleared read 1: response error + u32 WRST2 : 1; // (R) 1: buffer channel0 not copied + u32 RDST2 : 1; // (R) 1: new Data available + u32 : 2; // 15:14 + u32 UNRUN1 : 1; // (RWC) write 1: bit cleared read 1: main proc underrun error + u32 OVRUN1 : 1; // (RWC) write 1: bit cleared read 1: overrun error + u32 COLL1 : 1; // (RWC) write 1: bit cleared read 1: collision error + u32 NOREP1 : 1; // (RWC) write 1: bit cleared read 1: response error + u32 WRST1 : 1; // (R) 1: buffer channel0 not copied + u32 RDST1 : 1; // (R) 1: new Data available + u32 : 2; // 23:22 + u32 UNRUN0 : 1; // (RWC) write 1: bit cleared read 1: main proc underrun error + u32 OVRUN0 : 1; // (RWC) write 1: bit cleared read 1: overrun error + u32 COLL0 : 1; // (RWC) write 1: bit cleared read 1: collision error + u32 NOREP0 : 1; // (RWC) write 1: bit cleared read 1: response error + u32 WRST0 : 1; // (R) 1: buffer channel0 not copied + u32 RDST0 : 1; // (R) 1: new Data available + u32 : 1; + u32 WR : 1; // (RW) write 1 start copy, read 0 copy done + }; + USIStatusReg() { Hex = 0; } + USIStatusReg(u32 _hex) { Hex = _hex; } }; // SI EXI Clock Count -union USIEXIClockCount -{ - u32 Hex; - struct - { - u32 LOCK : 1; // 1: prevents CPU from setting EXI clock to 32MHz - u32 : 0; - }; +union USIEXIClockCount { + u32 Hex; + struct + { + u32 LOCK : 1; // 1: prevents CPU from setting EXI clock to 32MHz + u32 : 0; + }; }; // STATE_TO_SAVE static std::array g_Channel; -static USIPoll g_Poll; -static USIComCSR g_ComCSR; -static USIStatusReg g_StatusReg; +static USIPoll g_Poll; +static USIComCSR g_ComCSR; +static USIStatusReg g_StatusReg; static USIEXIClockCount g_EXIClockCount; -static u8 g_SIBuffer[128]; +static u8 g_SIBuffer[128]; -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - for (int i = 0; i < MAX_SI_CHANNELS; i++) - { - p.Do(g_Channel[i].m_InHi.Hex); - p.Do(g_Channel[i].m_InLo.Hex); - p.Do(g_Channel[i].m_Out.Hex); + for (int i = 0; i < MAX_SI_CHANNELS; i++) + { + p.Do(g_Channel[i].m_InHi.Hex); + p.Do(g_Channel[i].m_InLo.Hex); + p.Do(g_Channel[i].m_Out.Hex); - std::unique_ptr& device = g_Channel[i].m_device; - SIDevices type = device->GetDeviceType(); - p.Do(type); + std::unique_ptr& device = g_Channel[i].m_device; + SIDevices type = device->GetDeviceType(); + p.Do(type); - if (type == device->GetDeviceType()) - { - device->DoState(p); - } - else - { - // If no movie is active, we'll assume the user wants to keep their current devices - // instead of the ones they had when the savestate was created. - // But we need to restore the current devices first just in case. - SIDevices original_device = device->GetDeviceType(); - std::unique_ptr save_device = SIDevice_Create(type, i); - save_device->DoState(p); - AddDevice(std::move(save_device)); - ChangeDeviceDeterministic(original_device, i); - } - } + if (type == device->GetDeviceType()) + { + device->DoState(p); + } + else + { + // If no movie is active, we'll assume the user wants to keep their current devices + // instead of the ones they had when the savestate was created. + // But we need to restore the current devices first just in case. + SIDevices original_device = device->GetDeviceType(); + std::unique_ptr save_device = SIDevice_Create(type, i); + save_device->DoState(p); + AddDevice(std::move(save_device)); + ChangeDeviceDeterministic(original_device, i); + } + } - p.Do(g_Poll); - p.DoPOD(g_ComCSR); - p.DoPOD(g_StatusReg); - p.Do(g_EXIClockCount); - p.Do(g_SIBuffer); + p.Do(g_Poll); + p.DoPOD(g_ComCSR); + p.DoPOD(g_StatusReg); + p.Do(g_EXIClockCount); + p.Do(g_SIBuffer); } static void ChangeDeviceCallback(u64 userdata, s64 cyclesLate); @@ -255,350 +247,371 @@ static void RunSIBuffer(u64 userdata, s64 cyclesLate); void Init() { - for (int i = 0; i < MAX_SI_CHANNELS; i++) - { - g_Channel[i].m_Out.Hex = 0; - g_Channel[i].m_InHi.Hex = 0; - g_Channel[i].m_InLo.Hex = 0; + for (int i = 0; i < MAX_SI_CHANNELS; i++) + { + g_Channel[i].m_Out.Hex = 0; + g_Channel[i].m_InHi.Hex = 0; + g_Channel[i].m_InLo.Hex = 0; - if (Movie::IsMovieActive()) - { - if (Movie::IsUsingPad(i)) - { - SIDevices current = SConfig::GetInstance().m_SIDevice[i]; - // GC pad-compatible devices can be used for both playing and recording - if (SIDevice_IsGCController(current)) - AddDevice(Movie::IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : current, i); - else - AddDevice(Movie::IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER, i); - } - else - { - AddDevice(SIDEVICE_NONE, i); - } - } - else if (!NetPlay::IsNetPlayRunning()) - { - AddDevice(SConfig::GetInstance().m_SIDevice[i], i); - } - } + if (Movie::IsMovieActive()) + { + if (Movie::IsUsingPad(i)) + { + SIDevices current = SConfig::GetInstance().m_SIDevice[i]; + // GC pad-compatible devices can be used for both playing and recording + if (SIDevice_IsGCController(current)) + AddDevice(Movie::IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : current, i); + else + AddDevice(Movie::IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER, i); + } + else + { + AddDevice(SIDEVICE_NONE, i); + } + } + else if (!NetPlay::IsNetPlayRunning()) + { + AddDevice(SConfig::GetInstance().m_SIDevice[i], i); + } + } - g_Poll.Hex = 0; - g_Poll.X = 492; + g_Poll.Hex = 0; + g_Poll.X = 492; - g_ComCSR.Hex = 0; + g_ComCSR.Hex = 0; - g_StatusReg.Hex = 0; + g_StatusReg.Hex = 0; - g_EXIClockCount.Hex = 0; - //g_EXIClockCount.LOCK = 1; // Supposedly set on reset, but logs from real Wii don't look like it is... - memset(g_SIBuffer, 0, 128); + g_EXIClockCount.Hex = 0; + // g_EXIClockCount.LOCK = 1; // Supposedly set on reset, but logs from real Wii don't look like it + // is... + memset(g_SIBuffer, 0, 128); - changeDevice = CoreTiming::RegisterEvent("ChangeSIDevice", ChangeDeviceCallback); - et_transfer_pending = CoreTiming::RegisterEvent("SITransferPending", RunSIBuffer); + changeDevice = CoreTiming::RegisterEvent("ChangeSIDevice", ChangeDeviceCallback); + et_transfer_pending = CoreTiming::RegisterEvent("SITransferPending", RunSIBuffer); } void Shutdown() { - for (int i = 0; i < MAX_SI_CHANNELS; i++) - RemoveDevice(i); - GBAConnectionWaiter_Shutdown(); + for (int i = 0; i < MAX_SI_CHANNELS; i++) + RemoveDevice(i); + GBAConnectionWaiter_Shutdown(); } void RegisterMMIO(MMIO::Mapping* mmio, u32 base) { - // Register SI buffer direct accesses. - for (int i = 0; i < 0x80; i += 4) - mmio->Register(base | (0x80 + i), - MMIO::DirectRead((u32*)&g_SIBuffer[i]), - MMIO::DirectWrite((u32*)&g_SIBuffer[i]) - ); + // Register SI buffer direct accesses. + for (int i = 0; i < 0x80; i += 4) + mmio->Register(base | (0x80 + i), MMIO::DirectRead((u32*)&g_SIBuffer[i]), + MMIO::DirectWrite((u32*)&g_SIBuffer[i])); - // In and out for the 4 SI channels. - for (int i = 0; i < MAX_SI_CHANNELS; ++i) - { - // We need to clear the RDST bit for the SI channel when reading. - // CH0 -> Bit 24 + 5 - // CH1 -> Bit 16 + 5 - // CH2 -> Bit 8 + 5 - // CH3 -> Bit 0 + 5 - int rdst_bit = 8 * (3 - i) + 5; + // In and out for the 4 SI channels. + for (int i = 0; i < MAX_SI_CHANNELS; ++i) + { + // We need to clear the RDST bit for the SI channel when reading. + // CH0 -> Bit 24 + 5 + // CH1 -> Bit 16 + 5 + // CH2 -> Bit 8 + 5 + // CH3 -> Bit 0 + 5 + int rdst_bit = 8 * (3 - i) + 5; - mmio->Register(base | (SI_CHANNEL_0_OUT + 0xC * i), - MMIO::DirectRead(&g_Channel[i].m_Out.Hex), - MMIO::DirectWrite(&g_Channel[i].m_Out.Hex) - ); - mmio->Register(base | (SI_CHANNEL_0_IN_HI + 0xC * i), - MMIO::ComplexRead([i, rdst_bit](u32) { - g_StatusReg.Hex &= ~(1 << rdst_bit); - UpdateInterrupts(); - return g_Channel[i].m_InHi.Hex; - }), - MMIO::DirectWrite(&g_Channel[i].m_InHi.Hex) - ); - mmio->Register(base | (SI_CHANNEL_0_IN_LO + 0xC * i), - MMIO::ComplexRead([i, rdst_bit](u32) { - g_StatusReg.Hex &= ~(1 << rdst_bit); - UpdateInterrupts(); - return g_Channel[i].m_InLo.Hex; - }), - MMIO::DirectWrite(&g_Channel[i].m_InLo.Hex) - ); - } + mmio->Register(base | (SI_CHANNEL_0_OUT + 0xC * i), + MMIO::DirectRead(&g_Channel[i].m_Out.Hex), + MMIO::DirectWrite(&g_Channel[i].m_Out.Hex)); + mmio->Register(base | (SI_CHANNEL_0_IN_HI + 0xC * i), + MMIO::ComplexRead([i, rdst_bit](u32) { + g_StatusReg.Hex &= ~(1 << rdst_bit); + UpdateInterrupts(); + return g_Channel[i].m_InHi.Hex; + }), + MMIO::DirectWrite(&g_Channel[i].m_InHi.Hex)); + mmio->Register(base | (SI_CHANNEL_0_IN_LO + 0xC * i), + MMIO::ComplexRead([i, rdst_bit](u32) { + g_StatusReg.Hex &= ~(1 << rdst_bit); + UpdateInterrupts(); + return g_Channel[i].m_InLo.Hex; + }), + MMIO::DirectWrite(&g_Channel[i].m_InLo.Hex)); + } - mmio->Register(base | SI_POLL, - MMIO::DirectRead(&g_Poll.Hex), - MMIO::DirectWrite(&g_Poll.Hex) - ); + mmio->Register(base | SI_POLL, MMIO::DirectRead(&g_Poll.Hex), + MMIO::DirectWrite(&g_Poll.Hex)); - mmio->Register(base | SI_COM_CSR, - MMIO::DirectRead(&g_ComCSR.Hex), - MMIO::ComplexWrite([](u32, u32 val) { - USIComCSR tmpComCSR(val); + mmio->Register(base | SI_COM_CSR, MMIO::DirectRead(&g_ComCSR.Hex), + MMIO::ComplexWrite([](u32, u32 val) { + USIComCSR tmpComCSR(val); - g_ComCSR.CHANNEL = tmpComCSR.CHANNEL; - g_ComCSR.INLNGTH = tmpComCSR.INLNGTH; - g_ComCSR.OUTLNGTH = tmpComCSR.OUTLNGTH; - g_ComCSR.RDSTINTMSK = tmpComCSR.RDSTINTMSK; - g_ComCSR.TCINTMSK = tmpComCSR.TCINTMSK; + g_ComCSR.CHANNEL = tmpComCSR.CHANNEL; + g_ComCSR.INLNGTH = tmpComCSR.INLNGTH; + g_ComCSR.OUTLNGTH = tmpComCSR.OUTLNGTH; + g_ComCSR.RDSTINTMSK = tmpComCSR.RDSTINTMSK; + g_ComCSR.TCINTMSK = tmpComCSR.TCINTMSK; - g_ComCSR.COMERR = 0; + g_ComCSR.COMERR = 0; - if (tmpComCSR.RDSTINT) g_ComCSR.RDSTINT = 0; - if (tmpComCSR.TCINT) g_ComCSR.TCINT = 0; + if (tmpComCSR.RDSTINT) + g_ComCSR.RDSTINT = 0; + if (tmpComCSR.TCINT) + g_ComCSR.TCINT = 0; - // be careful: run si-buffer after updating the INT flags - if (tmpComCSR.TSTART) - { - g_ComCSR.TSTART = 1; - RunSIBuffer(0, 0); - } - else if (g_ComCSR.TSTART) - { - CoreTiming::RemoveEvent(et_transfer_pending); - } + // be careful: run si-buffer after updating the INT flags + if (tmpComCSR.TSTART) + { + g_ComCSR.TSTART = 1; + RunSIBuffer(0, 0); + } + else if (g_ComCSR.TSTART) + { + CoreTiming::RemoveEvent(et_transfer_pending); + } - if (!g_ComCSR.TSTART) - UpdateInterrupts(); - }) - ); + if (!g_ComCSR.TSTART) + UpdateInterrupts(); + })); - mmio->Register(base | SI_STATUS_REG, - MMIO::DirectRead(&g_StatusReg.Hex), - MMIO::ComplexWrite([](u32, u32 val) { - USIStatusReg tmpStatus(val); + mmio->Register(base | SI_STATUS_REG, MMIO::DirectRead(&g_StatusReg.Hex), + MMIO::ComplexWrite([](u32, u32 val) { + USIStatusReg tmpStatus(val); - // clear bits ( if (tmp.bit) SISR.bit=0 ) - if (tmpStatus.NOREP0) g_StatusReg.NOREP0 = 0; - if (tmpStatus.COLL0) g_StatusReg.COLL0 = 0; - if (tmpStatus.OVRUN0) g_StatusReg.OVRUN0 = 0; - if (tmpStatus.UNRUN0) g_StatusReg.UNRUN0 = 0; + // clear bits ( if (tmp.bit) SISR.bit=0 ) + if (tmpStatus.NOREP0) + g_StatusReg.NOREP0 = 0; + if (tmpStatus.COLL0) + g_StatusReg.COLL0 = 0; + if (tmpStatus.OVRUN0) + g_StatusReg.OVRUN0 = 0; + if (tmpStatus.UNRUN0) + g_StatusReg.UNRUN0 = 0; - if (tmpStatus.NOREP1) g_StatusReg.NOREP1 = 0; - if (tmpStatus.COLL1) g_StatusReg.COLL1 = 0; - if (tmpStatus.OVRUN1) g_StatusReg.OVRUN1 = 0; - if (tmpStatus.UNRUN1) g_StatusReg.UNRUN1 = 0; + if (tmpStatus.NOREP1) + g_StatusReg.NOREP1 = 0; + if (tmpStatus.COLL1) + g_StatusReg.COLL1 = 0; + if (tmpStatus.OVRUN1) + g_StatusReg.OVRUN1 = 0; + if (tmpStatus.UNRUN1) + g_StatusReg.UNRUN1 = 0; - if (tmpStatus.NOREP2) g_StatusReg.NOREP2 = 0; - if (tmpStatus.COLL2) g_StatusReg.COLL2 = 0; - if (tmpStatus.OVRUN2) g_StatusReg.OVRUN2 = 0; - if (tmpStatus.UNRUN2) g_StatusReg.UNRUN2 = 0; + if (tmpStatus.NOREP2) + g_StatusReg.NOREP2 = 0; + if (tmpStatus.COLL2) + g_StatusReg.COLL2 = 0; + if (tmpStatus.OVRUN2) + g_StatusReg.OVRUN2 = 0; + if (tmpStatus.UNRUN2) + g_StatusReg.UNRUN2 = 0; - if (tmpStatus.NOREP3) g_StatusReg.NOREP3 = 0; - if (tmpStatus.COLL3) g_StatusReg.COLL3 = 0; - if (tmpStatus.OVRUN3) g_StatusReg.OVRUN3 = 0; - if (tmpStatus.UNRUN3) g_StatusReg.UNRUN3 = 0; + if (tmpStatus.NOREP3) + g_StatusReg.NOREP3 = 0; + if (tmpStatus.COLL3) + g_StatusReg.COLL3 = 0; + if (tmpStatus.OVRUN3) + g_StatusReg.OVRUN3 = 0; + if (tmpStatus.UNRUN3) + g_StatusReg.UNRUN3 = 0; - // send command to devices - if (tmpStatus.WR) - { - g_Channel[0].m_device->SendCommand(g_Channel[0].m_Out.Hex, g_Poll.EN0); - g_Channel[1].m_device->SendCommand(g_Channel[1].m_Out.Hex, g_Poll.EN1); - g_Channel[2].m_device->SendCommand(g_Channel[2].m_Out.Hex, g_Poll.EN2); - g_Channel[3].m_device->SendCommand(g_Channel[3].m_Out.Hex, g_Poll.EN3); + // send command to devices + if (tmpStatus.WR) + { + g_Channel[0].m_device->SendCommand(g_Channel[0].m_Out.Hex, g_Poll.EN0); + g_Channel[1].m_device->SendCommand(g_Channel[1].m_Out.Hex, g_Poll.EN1); + g_Channel[2].m_device->SendCommand(g_Channel[2].m_Out.Hex, g_Poll.EN2); + g_Channel[3].m_device->SendCommand(g_Channel[3].m_Out.Hex, g_Poll.EN3); - g_StatusReg.WR = 0; - g_StatusReg.WRST0 = 0; - g_StatusReg.WRST1 = 0; - g_StatusReg.WRST2 = 0; - g_StatusReg.WRST3 = 0; - } - }) - ); + g_StatusReg.WR = 0; + g_StatusReg.WRST0 = 0; + g_StatusReg.WRST1 = 0; + g_StatusReg.WRST2 = 0; + g_StatusReg.WRST3 = 0; + } + })); - mmio->Register(base | SI_EXI_CLOCK_COUNT, - MMIO::DirectRead(&g_EXIClockCount.Hex), - MMIO::DirectWrite(&g_EXIClockCount.Hex) - ); + mmio->Register(base | SI_EXI_CLOCK_COUNT, MMIO::DirectRead(&g_EXIClockCount.Hex), + MMIO::DirectWrite(&g_EXIClockCount.Hex)); } static void UpdateInterrupts() { - // check if we have to update the RDSTINT flag - if (g_StatusReg.RDST0 || g_StatusReg.RDST1 || - g_StatusReg.RDST2 || g_StatusReg.RDST3) - g_ComCSR.RDSTINT = 1; - else - g_ComCSR.RDSTINT = 0; + // check if we have to update the RDSTINT flag + if (g_StatusReg.RDST0 || g_StatusReg.RDST1 || g_StatusReg.RDST2 || g_StatusReg.RDST3) + g_ComCSR.RDSTINT = 1; + else + g_ComCSR.RDSTINT = 0; - // check if we have to generate an interrupt - if ((g_ComCSR.RDSTINT & g_ComCSR.RDSTINTMSK) || - (g_ComCSR.TCINT & g_ComCSR.TCINTMSK)) - { - ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_SI, true); - } - else - { - ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_SI, false); - } + // check if we have to generate an interrupt + if ((g_ComCSR.RDSTINT & g_ComCSR.RDSTINTMSK) || (g_ComCSR.TCINT & g_ComCSR.TCINTMSK)) + { + ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_SI, true); + } + else + { + ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_SI, false); + } } void GenerateSIInterrupt(SIInterruptType _SIInterrupt) { - switch (_SIInterrupt) - { - case INT_RDSTINT: g_ComCSR.RDSTINT = 1; break; - case INT_TCINT: g_ComCSR.TCINT = 1; break; - } + switch (_SIInterrupt) + { + case INT_RDSTINT: + g_ComCSR.RDSTINT = 1; + break; + case INT_TCINT: + g_ComCSR.TCINT = 1; + break; + } - UpdateInterrupts(); + UpdateInterrupts(); } void RemoveDevice(int device_number) { - g_Channel.at(device_number).m_device.reset(); + g_Channel.at(device_number).m_device.reset(); } void AddDevice(std::unique_ptr device) { - int device_number = device->GetDeviceNumber(); + int device_number = device->GetDeviceNumber(); - // Delete the old device - RemoveDevice(device_number); + // Delete the old device + RemoveDevice(device_number); - // Set the new one - g_Channel.at(device_number).m_device = std::move(device); + // Set the new one + g_Channel.at(device_number).m_device = std::move(device); } void AddDevice(const SIDevices device, int device_number) { - AddDevice(SIDevice_Create(device, device_number)); + AddDevice(SIDevice_Create(device, device_number)); } static void SetNoResponse(u32 channel) { - // raise the NO RESPONSE error - switch (channel) - { - case 0: g_StatusReg.NOREP0 = 1; break; - case 1: g_StatusReg.NOREP1 = 1; break; - case 2: g_StatusReg.NOREP2 = 1; break; - case 3: g_StatusReg.NOREP3 = 1; break; - } - g_ComCSR.COMERR = 1; + // raise the NO RESPONSE error + switch (channel) + { + case 0: + g_StatusReg.NOREP0 = 1; + break; + case 1: + g_StatusReg.NOREP1 = 1; + break; + case 2: + g_StatusReg.NOREP2 = 1; + break; + case 3: + g_StatusReg.NOREP3 = 1; + break; + } + g_ComCSR.COMERR = 1; } static void ChangeDeviceCallback(u64 userdata, s64 cyclesLate) { - u8 channel = (u8)(userdata >> 32); - SIDevices device = (SIDevices)(u32)userdata; + u8 channel = (u8)(userdata >> 32); + SIDevices device = (SIDevices)(u32)userdata; - // Skip redundant (spammed) device changes - if (GetDeviceType(channel) != device) - { - g_Channel[channel].m_Out.Hex = 0; - g_Channel[channel].m_InHi.Hex = 0; - g_Channel[channel].m_InLo.Hex = 0; + // Skip redundant (spammed) device changes + if (GetDeviceType(channel) != device) + { + g_Channel[channel].m_Out.Hex = 0; + g_Channel[channel].m_InHi.Hex = 0; + g_Channel[channel].m_InLo.Hex = 0; - SetNoResponse(channel); + SetNoResponse(channel); - AddDevice(device, channel); - } + AddDevice(device, channel); + } } void ChangeDevice(SIDevices device, int channel) { - // Called from GUI, so we need to make it thread safe. - // Let the hardware see no device for .5b cycles - // TODO: Calling GetDeviceType here isn't threadsafe. - if (GetDeviceType(channel) != device) - { - CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | SIDEVICE_NONE); - CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | device); - } + // Called from GUI, so we need to make it thread safe. + // Let the hardware see no device for .5b cycles + // TODO: Calling GetDeviceType here isn't threadsafe. + if (GetDeviceType(channel) != device) + { + CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | SIDEVICE_NONE); + CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | device); + } } void ChangeDeviceDeterministic(SIDevices device, int channel) { - // Called from savestates, so no need to make it thread safe. - if (GetDeviceType(channel) != device) - { - CoreTiming::ScheduleEvent(0, changeDevice, ((u64)channel << 32) | SIDEVICE_NONE); - CoreTiming::ScheduleEvent(500000000, changeDevice, ((u64)channel << 32) | device); - } + // Called from savestates, so no need to make it thread safe. + if (GetDeviceType(channel) != device) + { + CoreTiming::ScheduleEvent(0, changeDevice, ((u64)channel << 32) | SIDEVICE_NONE); + CoreTiming::ScheduleEvent(500000000, changeDevice, ((u64)channel << 32) | device); + } } void UpdateDevices() { - // Update inputs at the rate of SI - // Typically 120hz but is variable - g_controller_interface.UpdateInput(); + // Update inputs at the rate of SI + // Typically 120hz but is variable + g_controller_interface.UpdateInput(); - // Update channels and set the status bit if there's new data - g_StatusReg.RDST0 = !!g_Channel[0].m_device->GetData(g_Channel[0].m_InHi.Hex, g_Channel[0].m_InLo.Hex); - g_StatusReg.RDST1 = !!g_Channel[1].m_device->GetData(g_Channel[1].m_InHi.Hex, g_Channel[1].m_InLo.Hex); - g_StatusReg.RDST2 = !!g_Channel[2].m_device->GetData(g_Channel[2].m_InHi.Hex, g_Channel[2].m_InLo.Hex); - g_StatusReg.RDST3 = !!g_Channel[3].m_device->GetData(g_Channel[3].m_InHi.Hex, g_Channel[3].m_InLo.Hex); + // Update channels and set the status bit if there's new data + g_StatusReg.RDST0 = + !!g_Channel[0].m_device->GetData(g_Channel[0].m_InHi.Hex, g_Channel[0].m_InLo.Hex); + g_StatusReg.RDST1 = + !!g_Channel[1].m_device->GetData(g_Channel[1].m_InHi.Hex, g_Channel[1].m_InLo.Hex); + g_StatusReg.RDST2 = + !!g_Channel[2].m_device->GetData(g_Channel[2].m_InHi.Hex, g_Channel[2].m_InLo.Hex); + g_StatusReg.RDST3 = + !!g_Channel[3].m_device->GetData(g_Channel[3].m_InHi.Hex, g_Channel[3].m_InLo.Hex); - UpdateInterrupts(); + UpdateInterrupts(); } SIDevices GetDeviceType(int channel) { - if (channel < 0 || channel > 3) - return SIDEVICE_NONE; + if (channel < 0 || channel > 3) + return SIDEVICE_NONE; - return g_Channel[channel].m_device->GetDeviceType(); + return g_Channel[channel].m_device->GetDeviceType(); } static void RunSIBuffer(u64 userdata, s64 cyclesLate) { - if (g_ComCSR.TSTART) - { - // Math inLength - int inLength = g_ComCSR.INLNGTH; - if (inLength == 0) - inLength = 128; - else - inLength++; + if (g_ComCSR.TSTART) + { + // Math inLength + int inLength = g_ComCSR.INLNGTH; + if (inLength == 0) + inLength = 128; + else + inLength++; - // Math outLength - int outLength = g_ComCSR.OUTLNGTH; - if (outLength == 0) - outLength = 128; - else - outLength++; + // Math outLength + int outLength = g_ComCSR.OUTLNGTH; + if (outLength == 0) + outLength = 128; + else + outLength++; - std::unique_ptr& device = g_Channel[g_ComCSR.CHANNEL].m_device; - int numOutput = device->RunBuffer(g_SIBuffer, inLength); + std::unique_ptr& device = g_Channel[g_ComCSR.CHANNEL].m_device; + int numOutput = device->RunBuffer(g_SIBuffer, inLength); - DEBUG_LOG(SERIALINTERFACE, "RunSIBuffer chan: %d inLen: %i outLen: %i processed: %i", g_ComCSR.CHANNEL, inLength, outLength, numOutput); + DEBUG_LOG(SERIALINTERFACE, "RunSIBuffer chan: %d inLen: %i outLen: %i processed: %i", + g_ComCSR.CHANNEL, inLength, outLength, numOutput); - if (numOutput != 0) - { - g_ComCSR.TSTART = 0; - GenerateSIInterrupt(INT_TCINT); - } - else - { - CoreTiming::ScheduleEvent(device->TransferInterval() - cyclesLate, et_transfer_pending); - } - } + if (numOutput != 0) + { + g_ComCSR.TSTART = 0; + GenerateSIInterrupt(INT_TCINT); + } + else + { + CoreTiming::ScheduleEvent(device->TransferInterval() - cyclesLate, et_transfer_pending); + } + } } u32 GetPollXLines() { - return g_Poll.X; + return g_Poll.X; } -} // end of namespace SerialInterface +} // end of namespace SerialInterface diff --git a/Source/Core/Core/HW/SI.h b/Source/Core/Core/HW/SI.h index e7d2273ef9..73f0cc9812 100644 --- a/Source/Core/Core/HW/SI.h +++ b/Source/Core/Core/HW/SI.h @@ -10,20 +10,22 @@ class PointerWrap; class ISIDevice; enum SIDevices : int; -namespace MMIO { class Mapping; } +namespace MMIO +{ +class Mapping; +} // SI number of channels enum { - MAX_SI_CHANNELS = 0x04 + MAX_SI_CHANNELS = 0x04 }; namespace SerialInterface { - void Init(); void Shutdown(); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); void RegisterMMIO(MMIO::Mapping* mmio, u32 base); @@ -40,4 +42,4 @@ SIDevices GetDeviceType(int channel); u32 GetPollXLines(); -} // end of namespace SerialInterface +} // end of namespace SerialInterface diff --git a/Source/Core/Core/HW/SI_Device.cpp b/Source/Core/Core/HW/SI_Device.cpp index 56c27b94df..114f064600 100644 --- a/Source/Core/Core/HW/SI_Device.cpp +++ b/Source/Core/Core/HW/SI_Device.cpp @@ -6,8 +6,8 @@ #include #include "Common/CommonTypes.h" -#include "Common/StringUtil.h" #include "Common/Logging/Log.h" +#include "Common/StringUtil.h" #include "Core/HW/SI_Device.h" #include "Core/HW/SI_DeviceAMBaseboard.h" #include "Core/HW/SI_DeviceDanceMat.h" @@ -21,103 +21,103 @@ int ISIDevice::RunBuffer(u8* _pBuffer, int _iLength) { #ifdef _DEBUG - DEBUG_LOG(SERIALINTERFACE, "Send Data Device(%i) - Length(%i) ", ISIDevice::m_iDeviceNumber, _iLength); + DEBUG_LOG(SERIALINTERFACE, "Send Data Device(%i) - Length(%i) ", ISIDevice::m_iDeviceNumber, + _iLength); - std::string temp; - int num = 0; + std::string temp; + int num = 0; - while (num < _iLength) - { - temp += StringFromFormat("0x%02x ", _pBuffer[num^3]); - num++; + while (num < _iLength) + { + temp += StringFromFormat("0x%02x ", _pBuffer[num ^ 3]); + num++; - if ((num % 8) == 0) - { - DEBUG_LOG(SERIALINTERFACE, "%s", temp.c_str()); - temp.clear(); - } - } + if ((num % 8) == 0) + { + DEBUG_LOG(SERIALINTERFACE, "%s", temp.c_str()); + temp.clear(); + } + } - DEBUG_LOG(SERIALINTERFACE, "%s", temp.c_str()); + DEBUG_LOG(SERIALINTERFACE, "%s", temp.c_str()); #endif - return 0; + return 0; } int ISIDevice::TransferInterval() { - return 0; + return 0; } // Stub class for saying nothing is attached, and not having to deal with null pointers :) class CSIDevice_Null : public ISIDevice { public: - CSIDevice_Null(SIDevices device, int _iDeviceNumber) : ISIDevice(device, _iDeviceNumber) {} - virtual ~CSIDevice_Null() {} - - int RunBuffer(u8* _pBuffer, int _iLength) override { - reinterpret_cast(_pBuffer)[0] = SI_ERROR_NO_RESPONSE; - return 4; - } - bool GetData(u32& _Hi, u32& _Low) override { - _Hi = 0x80000000; - return true; - } - void SendCommand(u32 _Cmd, u8 _Poll) override {} + CSIDevice_Null(SIDevices device, int _iDeviceNumber) : ISIDevice(device, _iDeviceNumber) {} + virtual ~CSIDevice_Null() {} + int RunBuffer(u8* _pBuffer, int _iLength) override + { + reinterpret_cast(_pBuffer)[0] = SI_ERROR_NO_RESPONSE; + return 4; + } + bool GetData(u32& _Hi, u32& _Low) override + { + _Hi = 0x80000000; + return true; + } + void SendCommand(u32 _Cmd, u8 _Poll) override {} }; - // Check if a device class is inheriting from CSIDevice_GCController // The goal of this function is to avoid special casing a long list of // device types when there is no "real" input device, e.g. when playing // a TAS movie, or netplay input. bool SIDevice_IsGCController(SIDevices type) { - switch (type) - { - case SIDEVICE_GC_CONTROLLER: - case SIDEVICE_WIIU_ADAPTER: - case SIDEVICE_GC_TARUKONGA: - case SIDEVICE_DANCEMAT: - case SIDEVICE_GC_STEERING: - return true; - default: - return false; - } + switch (type) + { + case SIDEVICE_GC_CONTROLLER: + case SIDEVICE_WIIU_ADAPTER: + case SIDEVICE_GC_TARUKONGA: + case SIDEVICE_DANCEMAT: + case SIDEVICE_GC_STEERING: + return true; + default: + return false; + } } - // F A C T O R Y std::unique_ptr SIDevice_Create(const SIDevices device, const int port_number) { - switch (device) - { - case SIDEVICE_GC_CONTROLLER: - return std::make_unique(device, port_number); + switch (device) + { + case SIDEVICE_GC_CONTROLLER: + return std::make_unique(device, port_number); - case SIDEVICE_WIIU_ADAPTER: - return std::make_unique(device, port_number); + case SIDEVICE_WIIU_ADAPTER: + return std::make_unique(device, port_number); - case SIDEVICE_DANCEMAT: - return std::make_unique(device, port_number); + case SIDEVICE_DANCEMAT: + return std::make_unique(device, port_number); - case SIDEVICE_GC_STEERING: - return std::make_unique(device, port_number); + case SIDEVICE_GC_STEERING: + return std::make_unique(device, port_number); - case SIDEVICE_GC_TARUKONGA: - return std::make_unique(device, port_number); + case SIDEVICE_GC_TARUKONGA: + return std::make_unique(device, port_number); - case SIDEVICE_GC_GBA: - return std::make_unique(device, port_number); + case SIDEVICE_GC_GBA: + return std::make_unique(device, port_number); - case SIDEVICE_GC_KEYBOARD: - return std::make_unique(device, port_number); + case SIDEVICE_GC_KEYBOARD: + return std::make_unique(device, port_number); - case SIDEVICE_AM_BASEBOARD: - return std::make_unique(device, port_number); + case SIDEVICE_AM_BASEBOARD: + return std::make_unique(device, port_number); - case SIDEVICE_NONE: - default: - return std::make_unique(device, port_number); - } + case SIDEVICE_NONE: + default: + return std::make_unique(device, port_number); + } } diff --git a/Source/Core/Core/HW/SI_Device.h b/Source/Core/Core/HW/SI_Device.h index 5671cfba05..d2fadc6ac4 100644 --- a/Source/Core/Core/HW/SI_Device.h +++ b/Source/Core/Core/HW/SI_Device.h @@ -12,99 +12,89 @@ class PointerWrap; // Devices can reply with these enum { - SI_ERROR_NO_RESPONSE = 0x0008, // Nothing is attached - SI_ERROR_UNKNOWN = 0x0040, // Unknown device is attached - SI_ERROR_BUSY = 0x0080 // Still detecting + SI_ERROR_NO_RESPONSE = 0x0008, // Nothing is attached + SI_ERROR_UNKNOWN = 0x0040, // Unknown device is attached + SI_ERROR_BUSY = 0x0080 // Still detecting }; // Device types enum { - SI_TYPE_MASK = 0x18000000, // ??? - SI_TYPE_GC = 0x08000000 + SI_TYPE_MASK = 0x18000000, // ??? + SI_TYPE_GC = 0x08000000 }; // GC Controller types enum { - SI_GC_NOMOTOR = 0x20000000, // No rumble motor - SI_GC_STANDARD = 0x01000000 + SI_GC_NOMOTOR = 0x20000000, // No rumble motor + SI_GC_STANDARD = 0x01000000 }; // SI Device IDs for emulator use enum TSIDevices { - SI_NONE = SI_ERROR_NO_RESPONSE, - SI_N64_MIC = 0x00010000, - SI_N64_KEYBOARD = 0x00020000, - SI_N64_MOUSE = 0x02000000, - SI_N64_CONTROLLER = 0x05000000, - SI_GBA = 0x00040000, - SI_GC_CONTROLLER = (SI_TYPE_GC | SI_GC_STANDARD), - SI_GC_KEYBOARD = (SI_TYPE_GC | 0x00200000), - SI_GC_STEERING = SI_TYPE_GC, // (shuffle2)I think the "chainsaw" is the same (Or else it's just standard) - SI_DANCEMAT = (SI_TYPE_GC | SI_GC_STANDARD | 0x00000300), - SI_AM_BASEBOARD = 0x10110800 // gets ORd with dipswitch state + SI_NONE = SI_ERROR_NO_RESPONSE, + SI_N64_MIC = 0x00010000, + SI_N64_KEYBOARD = 0x00020000, + SI_N64_MOUSE = 0x02000000, + SI_N64_CONTROLLER = 0x05000000, + SI_GBA = 0x00040000, + SI_GC_CONTROLLER = (SI_TYPE_GC | SI_GC_STANDARD), + SI_GC_KEYBOARD = (SI_TYPE_GC | 0x00200000), + SI_GC_STEERING = + SI_TYPE_GC, // (shuffle2)I think the "chainsaw" is the same (Or else it's just standard) + SI_DANCEMAT = (SI_TYPE_GC | SI_GC_STANDARD | 0x00000300), + SI_AM_BASEBOARD = 0x10110800 // gets ORd with dipswitch state }; // For configuration use, since some devices can have the same SI Device ID enum SIDevices : int { - SIDEVICE_NONE, - SIDEVICE_N64_MIC, - SIDEVICE_N64_KEYBOARD, - SIDEVICE_N64_MOUSE, - SIDEVICE_N64_CONTROLLER, - SIDEVICE_GC_GBA, - SIDEVICE_GC_CONTROLLER, - SIDEVICE_GC_KEYBOARD, - SIDEVICE_GC_STEERING, - SIDEVICE_DANCEMAT, - SIDEVICE_GC_TARUKONGA, - SIDEVICE_AM_BASEBOARD, - SIDEVICE_WIIU_ADAPTER, + SIDEVICE_NONE, + SIDEVICE_N64_MIC, + SIDEVICE_N64_KEYBOARD, + SIDEVICE_N64_MOUSE, + SIDEVICE_N64_CONTROLLER, + SIDEVICE_GC_GBA, + SIDEVICE_GC_CONTROLLER, + SIDEVICE_GC_KEYBOARD, + SIDEVICE_GC_STEERING, + SIDEVICE_DANCEMAT, + SIDEVICE_GC_TARUKONGA, + SIDEVICE_AM_BASEBOARD, + SIDEVICE_WIIU_ADAPTER, }; - class ISIDevice { protected: - int m_iDeviceNumber; - SIDevices m_deviceType; + int m_iDeviceNumber; + SIDevices m_deviceType; public: - // Constructor - ISIDevice(SIDevices deviceType, int _iDeviceNumber) - : m_iDeviceNumber(_iDeviceNumber) - , m_deviceType(deviceType) - {} + // Constructor + ISIDevice(SIDevices deviceType, int _iDeviceNumber) + : m_iDeviceNumber(_iDeviceNumber), m_deviceType(deviceType) + { + } - // Destructor - virtual ~ISIDevice() {} + // Destructor + virtual ~ISIDevice() {} + // Run the SI Buffer + virtual int RunBuffer(u8* _pBuffer, int _iLength); + virtual int TransferInterval(); - // Run the SI Buffer - virtual int RunBuffer(u8* _pBuffer, int _iLength); - virtual int TransferInterval(); + // Return true on new data + virtual bool GetData(u32& _Hi, u32& _Low) = 0; - // Return true on new data - virtual bool GetData(u32& _Hi, u32& _Low) = 0; + // Send a command directly (no detour per buffer) + virtual void SendCommand(u32 _Cmd, u8 _Poll) = 0; - // Send a command directly (no detour per buffer) - virtual void SendCommand(u32 _Cmd, u8 _Poll) = 0; - - // Savestate support - virtual void DoState(PointerWrap& p) {} - - - int GetDeviceNumber() const - { - return m_iDeviceNumber; - } - - SIDevices GetDeviceType() const - { - return m_deviceType; - } + // Savestate support + virtual void DoState(PointerWrap& p) {} + int GetDeviceNumber() const { return m_iDeviceNumber; } + SIDevices GetDeviceType() const { return m_deviceType; } }; bool SIDevice_IsGCController(SIDevices type); diff --git a/Source/Core/Core/HW/SI_DeviceAMBaseboard.cpp b/Source/Core/Core/HW/SI_DeviceAMBaseboard.cpp index 812472bb42..fd65412588 100644 --- a/Source/Core/Core/HW/SI_DeviceAMBaseboard.cpp +++ b/Source/Core/Core/HW/SI_DeviceAMBaseboard.cpp @@ -6,8 +6,8 @@ #include #include "Common/CommonTypes.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "Core/HW/GCPad.h" #include "Core/HW/SI_Device.h" #include "Core/HW/SI_DeviceAMBaseboard.h" @@ -20,440 +20,436 @@ class JVSIOMessage { public: - int m_ptr, m_last_start, m_csum; - unsigned char m_msg[0x80]; + int m_ptr, m_last_start, m_csum; + unsigned char m_msg[0x80]; - JVSIOMessage() - { - m_ptr = 0; - m_last_start = 0; - } + JVSIOMessage() + { + m_ptr = 0; + m_last_start = 0; + } - void Start(int node) - { - m_last_start = m_ptr; - unsigned char hdr[3] = {0xe0, (unsigned char)node, 0}; - m_csum = 0; - AddData(hdr, 3, 1); - } - void AddData(const void *data, size_t len) - { - AddData((const unsigned char*)data, len); - } - void AddData(const char *data) - { - AddData(data, strlen(data)); - } - void AddData(int n) - { - unsigned char cs = n; - AddData(&cs, 1); - } + void Start(int node) + { + m_last_start = m_ptr; + unsigned char hdr[3] = {0xe0, (unsigned char)node, 0}; + m_csum = 0; + AddData(hdr, 3, 1); + } + void AddData(const void* data, size_t len) { AddData((const unsigned char*)data, len); } + void AddData(const char* data) { AddData(data, strlen(data)); } + void AddData(int n) + { + unsigned char cs = n; + AddData(&cs, 1); + } - void End() - { - int len = m_ptr - m_last_start; - m_msg[m_last_start + 2] = len - 2; // assuming len <0xD0 - AddData(m_csum + len - 2); - } + void End() + { + int len = m_ptr - m_last_start; + m_msg[m_last_start + 2] = len - 2; // assuming len <0xD0 + AddData(m_csum + len - 2); + } - void AddData(const unsigned char *dst, size_t len, int sync = 0) - { - while (len--) - { - int c = *dst++; - if (!sync && ((c == 0xE0) || (c == 0xD0))) - { - m_msg[m_ptr++] = 0xD0; - m_msg[m_ptr++] = c - 1; - } - else - { - m_msg[m_ptr++] = c; - } - - if (!sync) - m_csum += c; - sync = 0; - if (m_ptr >= 0x80) - PanicAlert("JVSIOMessage overrun!"); - } - } -}; // end class JVSIOMessage + void AddData(const unsigned char* dst, size_t len, int sync = 0) + { + while (len--) + { + int c = *dst++; + if (!sync && ((c == 0xE0) || (c == 0xD0))) + { + m_msg[m_ptr++] = 0xD0; + m_msg[m_ptr++] = c - 1; + } + else + { + m_msg[m_ptr++] = c; + } + if (!sync) + m_csum += c; + sync = 0; + if (m_ptr >= 0x80) + PanicAlert("JVSIOMessage overrun!"); + } + } +}; // end class JVSIOMessage // AM-Baseboard device on SI CSIDevice_AMBaseboard::CSIDevice_AMBaseboard(SIDevices device, int _iDeviceNumber) - : ISIDevice(device, _iDeviceNumber) + : ISIDevice(device, _iDeviceNumber) { } int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength) { - // for debug logging only - ISIDevice::RunBuffer(_pBuffer, _iLength); + // for debug logging only + ISIDevice::RunBuffer(_pBuffer, _iLength); - int iPosition = 0; - while (iPosition < _iLength) - { - // read the command - EBufferCommands command = static_cast(_pBuffer[iPosition ^ 3]); - iPosition++; + int iPosition = 0; + while (iPosition < _iLength) + { + // read the command + EBufferCommands command = static_cast(_pBuffer[iPosition ^ 3]); + iPosition++; - // handle it - switch (command) - { - case CMD_RESET: // returns ID and dip switches - { - *(u32*)&_pBuffer[0] = SI_AM_BASEBOARD|0x100; // 0x100 is progressive flag according to dip switch - iPosition = _iLength; // break the while loop - } - break; - case CMD_GCAM: - { - int i; + // handle it + switch (command) + { + case CMD_RESET: // returns ID and dip switches + { + *(u32*)&_pBuffer[0] = + SI_AM_BASEBOARD | 0x100; // 0x100 is progressive flag according to dip switch + iPosition = _iLength; // break the while loop + } + break; + case CMD_GCAM: + { + int i; - // calculate checksum over buffer - int csum = 0; - for (i=0; i<_iLength; ++i) - csum += _pBuffer[i]; + // calculate checksum over buffer + int csum = 0; + for (i = 0; i < _iLength; ++i) + csum += _pBuffer[i]; - unsigned char res[0x80]; - int resp = 0; + unsigned char res[0x80]; + int resp = 0; - int real_len = _pBuffer[1^3]; - int p = 2; + int real_len = _pBuffer[1 ^ 3]; + int p = 2; - static int d10_1 = 0xfe; + static int d10_1 = 0xfe; - memset(res, 0, 0x80); - res[resp++] = 1; - res[resp++] = 1; + memset(res, 0, 0x80); + res[resp++] = 1; + res[resp++] = 1; -#define ptr(x) _pBuffer[(p + x)^3] - while (p < real_len+2) - { - switch (ptr(0)) - { - case 0x10: - { - DEBUG_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 10, %02x (READ STATUS&SWITCHES)", ptr(1)); - GCPadStatus PadStatus; - memset(&PadStatus, 0 ,sizeof(PadStatus)); - Pad::GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus); - res[resp++] = 0x10; - res[resp++] = 0x2; - int d10_0 = 0xdf; +#define ptr(x) _pBuffer[(p + x) ^ 3] + while (p < real_len + 2) + { + switch (ptr(0)) + { + case 0x10: + { + DEBUG_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 10, %02x (READ STATUS&SWITCHES)", ptr(1)); + GCPadStatus PadStatus; + memset(&PadStatus, 0, sizeof(PadStatus)); + Pad::GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus); + res[resp++] = 0x10; + res[resp++] = 0x2; + int d10_0 = 0xdf; - if (PadStatus.triggerLeft) - d10_0 &= ~0x80; - if (PadStatus.triggerRight) - d10_0 &= ~0x40; + if (PadStatus.triggerLeft) + d10_0 &= ~0x80; + if (PadStatus.triggerRight) + d10_0 &= ~0x40; - res[resp++] = d10_0; - res[resp++] = d10_1; - break; - } - case 0x12: - ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 12, %02x %02x", ptr(1), ptr(2)); - res[resp++] = 0x12; - res[resp++] = 0x00; - break; - case 0x11: - { - ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 11, %02x (READ SERIAL NR)", ptr(1)); - char string[] = "AADE-01A14964511"; - res[resp++] = 0x11; - res[resp++] = 0x10; - memcpy(res + resp, string, 0x10); - resp += 0x10; - break; - } - case 0x15: - ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 15, %02x (READ FIRM VERSION)", ptr(1)); - res[resp++] = 0x15; - res[resp++] = 0x02; - res[resp++] = 0x00; - res[resp++] = 0x29; // FIRM VERSION - break; - case 0x16: - ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 16, %02x (READ FPGA VERSION)", ptr(1)); - res[resp++] = 0x16; - res[resp++] = 0x02; - res[resp++] = 0x07; - res[resp++] = 0x06; // FPGAVERSION - /* - res[resp++] = 0x16; - res[resp++] = 0x00; - p += 2; - */ - break; - case 0x1f: - { - ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 1f, %02x %02x %02x %02x %02x (REGION)", ptr(1), ptr(2), ptr(3), ptr(4), ptr(5)); - unsigned char string[] = - "\x00\x00\x30\x00" - //"\x01\xfe\x00\x00" // JAPAN - "\x02\xfd\x00\x00" // USA - //"\x03\xfc\x00\x00" // export - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; - res[resp++] = 0x1f; - res[resp++] = 0x14; + res[resp++] = d10_0; + res[resp++] = d10_1; + break; + } + case 0x12: + ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 12, %02x %02x", ptr(1), ptr(2)); + res[resp++] = 0x12; + res[resp++] = 0x00; + break; + case 0x11: + { + ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 11, %02x (READ SERIAL NR)", ptr(1)); + char string[] = "AADE-01A14964511"; + res[resp++] = 0x11; + res[resp++] = 0x10; + memcpy(res + resp, string, 0x10); + resp += 0x10; + break; + } + case 0x15: + ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 15, %02x (READ FIRM VERSION)", ptr(1)); + res[resp++] = 0x15; + res[resp++] = 0x02; + res[resp++] = 0x00; + res[resp++] = 0x29; // FIRM VERSION + break; + case 0x16: + ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 16, %02x (READ FPGA VERSION)", ptr(1)); + res[resp++] = 0x16; + res[resp++] = 0x02; + res[resp++] = 0x07; + res[resp++] = 0x06; // FPGAVERSION + /* + res[resp++] = 0x16; + res[resp++] = 0x00; + p += 2; + */ + break; + case 0x1f: + { + ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 1f, %02x %02x %02x %02x %02x (REGION)", + ptr(1), ptr(2), ptr(3), ptr(4), ptr(5)); + unsigned char string[] = "\x00\x00\x30\x00" + //"\x01\xfe\x00\x00" // JAPAN + "\x02\xfd\x00\x00" // USA + //"\x03\xfc\x00\x00" // export + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; + res[resp++] = 0x1f; + res[resp++] = 0x14; - for (i=0; i<0x14; ++i) - res[resp++] = string[i]; - break; - } - case 0x31: - ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 31 (UNKNOWN)"); - res[resp++] = 0x31; - res[resp++] = 0x02; - res[resp++] = 0x00; - res[resp++] = 0x00; - break; - case 0x32: - ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 32 (UNKNOWN)"); - res[resp++] = 0x32; - res[resp++] = 0x02; - res[resp++] = 0x00; - res[resp++] = 0x00; - break; - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4a: - case 0x4b: - case 0x4c: - case 0x4d: - case 0x4e: - case 0x4f: - { - DEBUG_LOG(AMBASEBOARDDEBUG, "GC-AM: Command %02x, %02x %02x %02x %02x %02x %02x %02x (JVS IO)", - ptr(0), ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), ptr(6), ptr(7)); - int pptr = 2; - JVSIOMessage msg; + for (i = 0; i < 0x14; ++i) + res[resp++] = string[i]; + break; + } + case 0x31: + ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 31 (UNKNOWN)"); + res[resp++] = 0x31; + res[resp++] = 0x02; + res[resp++] = 0x00; + res[resp++] = 0x00; + break; + case 0x32: + ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: Command 32 (UNKNOWN)"); + res[resp++] = 0x32; + res[resp++] = 0x02; + res[resp++] = 0x00; + res[resp++] = 0x00; + break; + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + { + DEBUG_LOG(AMBASEBOARDDEBUG, + "GC-AM: Command %02x, %02x %02x %02x %02x %02x %02x %02x (JVS IO)", ptr(0), + ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), ptr(6), ptr(7)); + int pptr = 2; + JVSIOMessage msg; - msg.Start(0); - msg.AddData(1); + msg.Start(0); + msg.AddData(1); - unsigned char jvs_io_buffer[0x80]; - int nr_bytes = ptr(pptr + 2); // byte after e0 xx - int jvs_io_length = 0; - for (i=0; i(_pBuffer[3]); + // Read the command + EBufferCommands command = static_cast(_pBuffer[3]); - if (command == CMD_RESET) - { - ISIDevice::RunBuffer(_pBuffer, _iLength); - *(u32*)&_pBuffer[0] = SI_DANCEMAT; - } - else - { - return CSIDevice_GCController::RunBuffer(_pBuffer, _iLength); - } + if (command == CMD_RESET) + { + ISIDevice::RunBuffer(_pBuffer, _iLength); + *(u32*)&_pBuffer[0] = SI_DANCEMAT; + } + else + { + return CSIDevice_GCController::RunBuffer(_pBuffer, _iLength); + } - return _iLength; + return _iLength; } u32 CSIDevice_DanceMat::MapPadStatus(const GCPadStatus& pad_status) { - // Map the dpad to the blue arrows, the buttons to the orange arrows - // Z = + button, Start = - button - u16 map = 0; - if (pad_status.button & PAD_BUTTON_UP) - map |= 0x1000; - if (pad_status.button & PAD_BUTTON_DOWN) - map |= 0x2; - if (pad_status.button & PAD_BUTTON_LEFT) - map |= 0x8; - if (pad_status.button & PAD_BUTTON_RIGHT) - map |= 0x4; - if (pad_status.button & PAD_BUTTON_Y) - map |= 0x200; - if (pad_status.button & PAD_BUTTON_A) - map |= 0x10; - if (pad_status.button & PAD_BUTTON_B) - map |= 0x100; - if (pad_status.button & PAD_BUTTON_X) - map |= 0x800; - if (pad_status.button & PAD_TRIGGER_Z) - map |= 0x400; - if (pad_status.button & PAD_BUTTON_START) - map |= 0x1; + // Map the dpad to the blue arrows, the buttons to the orange arrows + // Z = + button, Start = - button + u16 map = 0; + if (pad_status.button & PAD_BUTTON_UP) + map |= 0x1000; + if (pad_status.button & PAD_BUTTON_DOWN) + map |= 0x2; + if (pad_status.button & PAD_BUTTON_LEFT) + map |= 0x8; + if (pad_status.button & PAD_BUTTON_RIGHT) + map |= 0x4; + if (pad_status.button & PAD_BUTTON_Y) + map |= 0x200; + if (pad_status.button & PAD_BUTTON_A) + map |= 0x10; + if (pad_status.button & PAD_BUTTON_B) + map |= 0x100; + if (pad_status.button & PAD_BUTTON_X) + map |= 0x800; + if (pad_status.button & PAD_TRIGGER_Z) + map |= 0x400; + if (pad_status.button & PAD_BUTTON_START) + map |= 0x1; - return (u32)(map << 16) | 0x8080; + return (u32)(map << 16) | 0x8080; } bool CSIDevice_DanceMat::GetData(u32& _Hi, u32& _Low) { - CSIDevice_GCController::GetData(_Hi, _Low); + CSIDevice_GCController::GetData(_Hi, _Low); - // Identifies the dance mat - _Low = 0x8080ffff; + // Identifies the dance mat + _Low = 0x8080ffff; - return true; + return true; } diff --git a/Source/Core/Core/HW/SI_DeviceDanceMat.h b/Source/Core/Core/HW/SI_DeviceDanceMat.h index a7ffafda6c..14e7c64edf 100644 --- a/Source/Core/Core/HW/SI_DeviceDanceMat.h +++ b/Source/Core/Core/HW/SI_DeviceDanceMat.h @@ -12,9 +12,9 @@ struct GCPadStatus; class CSIDevice_DanceMat : public CSIDevice_GCController { public: - CSIDevice_DanceMat(SIDevices device, int _iDeviceNumber); + CSIDevice_DanceMat(SIDevices device, int _iDeviceNumber); - int RunBuffer(u8* _pBuffer, int _iLength) override; - u32 MapPadStatus(const GCPadStatus& pad_status) override; - bool GetData(u32& _Hi, u32& _Low) override; + int RunBuffer(u8* _pBuffer, int _iLength) override; + u32 MapPadStatus(const GCPadStatus& pad_status) override; + bool GetData(u32& _Hi, u32& _Low) override; }; diff --git a/Source/Core/Core/HW/SI_DeviceGBA.cpp b/Source/Core/Core/HW/SI_DeviceGBA.cpp index f510ada3b1..802ecfd99b 100644 --- a/Source/Core/Core/HW/SI_DeviceGBA.cpp +++ b/Source/Core/Core/HW/SI_DeviceGBA.cpp @@ -9,8 +9,8 @@ #include "Common/CommonTypes.h" #include "Common/Flag.h" -#include "Common/Thread.h" #include "Common/Logging/Log.h" +#include "Common/Thread.h" #include "Core/CoreTiming.h" #include "Core/HW/SI_Device.h" #include "Core/HW/SI_DeviceGBA.h" @@ -25,14 +25,17 @@ static std::mutex cs_gba; static std::mutex cs_gba_clk; static u8 num_connected; -namespace { Common::Flag server_running; } +namespace +{ +Common::Flag server_running; +} enum EJoybusCmds { - CMD_RESET = 0xff, - CMD_STATUS = 0x00, - CMD_READ = 0x14, - CMD_WRITE = 0x15 + CMD_RESET = 0xff, + CMD_STATUS = 0x00, + CMD_READ = 0x14, + CMD_WRITE = 0x15 }; const u64 BITS_PER_SECOND = 115200; @@ -40,334 +43,328 @@ const u64 BYTES_PER_SECOND = BITS_PER_SECOND / 8; u8 GetNumConnected() { - int num_ports_connected = num_connected; - if (num_ports_connected == 0) - num_ports_connected = 1; + int num_ports_connected = num_connected; + if (num_ports_connected == 0) + num_ports_connected = 1; - return num_ports_connected; + return num_ports_connected; } // --- GameBoy Advance "Link Cable" --- int GetTransferTime(u8 cmd) { - u64 bytes_transferred = 0; + u64 bytes_transferred = 0; - switch (cmd) - { - case CMD_RESET: - case CMD_STATUS: - { - bytes_transferred = 4; - break; - } - case CMD_READ: - { - bytes_transferred = 6; - break; - } - case CMD_WRITE: - { - bytes_transferred = 1; - break; - } - default: - { - bytes_transferred = 1; - break; - } - } - return (int)(bytes_transferred * SystemTimers::GetTicksPerSecond() / (GetNumConnected() * BYTES_PER_SECOND)); + switch (cmd) + { + case CMD_RESET: + case CMD_STATUS: + { + bytes_transferred = 4; + break; + } + case CMD_READ: + { + bytes_transferred = 6; + break; + } + case CMD_WRITE: + { + bytes_transferred = 1; + break; + } + default: + { + bytes_transferred = 1; + break; + } + } + return (int)(bytes_transferred * SystemTimers::GetTicksPerSecond() / + (GetNumConnected() * BYTES_PER_SECOND)); } static void GBAConnectionWaiter() { - server_running.Set(); + server_running.Set(); - Common::SetCurrentThreadName("GBA Connection Waiter"); + Common::SetCurrentThreadName("GBA Connection Waiter"); - sf::TcpListener server; - sf::TcpListener clock_server; + sf::TcpListener server; + sf::TcpListener clock_server; - // "dolphin gba" - if (server.listen(0xd6ba) != sf::Socket::Done) - return; + // "dolphin gba" + if (server.listen(0xd6ba) != sf::Socket::Done) + return; - // "clock" - if (clock_server.listen(0xc10c) != sf::Socket::Done) - return; + // "clock" + if (clock_server.listen(0xc10c) != sf::Socket::Done) + return; - server.setBlocking(false); - clock_server.setBlocking(false); + server.setBlocking(false); + clock_server.setBlocking(false); - auto new_client = std::make_unique(); - while (server_running.IsSet()) - { - if (server.accept(*new_client) == sf::Socket::Done) - { - std::lock_guard lk(cs_gba); - waiting_socks.push(std::move(new_client)); + auto new_client = std::make_unique(); + while (server_running.IsSet()) + { + if (server.accept(*new_client) == sf::Socket::Done) + { + std::lock_guard lk(cs_gba); + waiting_socks.push(std::move(new_client)); - new_client = std::make_unique(); - } - if (clock_server.accept(*new_client) == sf::Socket::Done) - { - std::lock_guard lk(cs_gba_clk); - waiting_clocks.push(std::move(new_client)); + new_client = std::make_unique(); + } + if (clock_server.accept(*new_client) == sf::Socket::Done) + { + std::lock_guard lk(cs_gba_clk); + waiting_clocks.push(std::move(new_client)); - new_client = std::make_unique(); - } + new_client = std::make_unique(); + } - Common::SleepCurrentThread(1); - } + Common::SleepCurrentThread(1); + } } void GBAConnectionWaiter_Shutdown() { - server_running.Clear(); - if (connectionThread.joinable()) - connectionThread.join(); + server_running.Clear(); + if (connectionThread.joinable()) + connectionThread.join(); } static bool GetAvailableSock(std::unique_ptr& sock_to_fill) { - bool sock_filled = false; + bool sock_filled = false; - std::lock_guard lk(cs_gba); + std::lock_guard lk(cs_gba); - if (!waiting_socks.empty()) - { - sock_to_fill = std::move(waiting_socks.front()); - waiting_socks.pop(); - sock_filled = true; - } + if (!waiting_socks.empty()) + { + sock_to_fill = std::move(waiting_socks.front()); + waiting_socks.pop(); + sock_filled = true; + } - return sock_filled; + return sock_filled; } static bool GetNextClock(std::unique_ptr& sock_to_fill) { - bool sock_filled = false; + bool sock_filled = false; - std::lock_guard lk(cs_gba_clk); + std::lock_guard lk(cs_gba_clk); - if (!waiting_clocks.empty()) - { - sock_to_fill = std::move(waiting_clocks.front()); - waiting_clocks.pop(); - sock_filled = true; - } + if (!waiting_clocks.empty()) + { + sock_to_fill = std::move(waiting_clocks.front()); + waiting_clocks.pop(); + sock_filled = true; + } - return sock_filled; + return sock_filled; } GBASockServer::GBASockServer(int _iDeviceNumber) { - if (!connectionThread.joinable()) - connectionThread = std::thread(GBAConnectionWaiter); + if (!connectionThread.joinable()) + connectionThread = std::thread(GBAConnectionWaiter); - cmd = 0; - num_connected = 0; - last_time_slice = 0; - booted = false; - device_number = _iDeviceNumber; + cmd = 0; + num_connected = 0; + last_time_slice = 0; + booted = false; + device_number = _iDeviceNumber; } GBASockServer::~GBASockServer() { - Disconnect(); + Disconnect(); } void GBASockServer::Disconnect() { - if (client) - { - num_connected--; - client->disconnect(); - client = nullptr; - } - if (clock_sync) - { - clock_sync->disconnect(); - clock_sync = nullptr; - } - last_time_slice = 0; - booted = false; + if (client) + { + num_connected--; + client->disconnect(); + client = nullptr; + } + if (clock_sync) + { + clock_sync->disconnect(); + clock_sync = nullptr; + } + last_time_slice = 0; + booted = false; } void GBASockServer::ClockSync() { - if (!clock_sync) - if (!GetNextClock(clock_sync)) - return; + if (!clock_sync) + if (!GetNextClock(clock_sync)) + return; - u32 time_slice = 0; + u32 time_slice = 0; - if (last_time_slice == 0) - { - num_connected++; - last_time_slice = CoreTiming::GetTicks(); - time_slice = (u32)(SystemTimers::GetTicksPerSecond() / 60); - } - else - { - time_slice = (u32)(CoreTiming::GetTicks() - last_time_slice); - } + if (last_time_slice == 0) + { + num_connected++; + last_time_slice = CoreTiming::GetTicks(); + time_slice = (u32)(SystemTimers::GetTicksPerSecond() / 60); + } + else + { + time_slice = (u32)(CoreTiming::GetTicks() - last_time_slice); + } - time_slice = (u32)((u64)time_slice * 16777216 / SystemTimers::GetTicksPerSecond()); - last_time_slice = CoreTiming::GetTicks(); - char bytes[4] = { 0, 0, 0, 0 }; - bytes[0] = (time_slice >> 24) & 0xff; - bytes[1] = (time_slice >> 16) & 0xff; - bytes[2] = (time_slice >> 8) & 0xff; - bytes[3] = time_slice & 0xff; + time_slice = (u32)((u64)time_slice * 16777216 / SystemTimers::GetTicksPerSecond()); + last_time_slice = CoreTiming::GetTicks(); + char bytes[4] = {0, 0, 0, 0}; + bytes[0] = (time_slice >> 24) & 0xff; + bytes[1] = (time_slice >> 16) & 0xff; + bytes[2] = (time_slice >> 8) & 0xff; + bytes[3] = time_slice & 0xff; - sf::Socket::Status status = clock_sync->send(bytes, 4); - if (status == sf::Socket::Disconnected) - { - clock_sync->disconnect(); - clock_sync = nullptr; - } + sf::Socket::Status status = clock_sync->send(bytes, 4); + if (status == sf::Socket::Disconnected) + { + clock_sync->disconnect(); + clock_sync = nullptr; + } } void GBASockServer::Send(u8* si_buffer) { - if (!client) - if (!GetAvailableSock(client)) - return; + if (!client) + if (!GetAvailableSock(client)) + return; - for (int i = 0; i < 5; i++) - send_data[i] = si_buffer[i ^ 3]; + for (int i = 0; i < 5; i++) + send_data[i] = si_buffer[i ^ 3]; - cmd = (u8)send_data[0]; + cmd = (u8)send_data[0]; #ifdef _DEBUG - NOTICE_LOG(SERIALINTERFACE, "%01d cmd %02x [> %02x%02x%02x%02x]", - device_number, - (u8)send_data[0], (u8)send_data[1], (u8)send_data[2], - (u8)send_data[3], (u8)send_data[4]); + NOTICE_LOG(SERIALINTERFACE, "%01d cmd %02x [> %02x%02x%02x%02x]", device_number, (u8)send_data[0], + (u8)send_data[1], (u8)send_data[2], (u8)send_data[3], (u8)send_data[4]); #endif - client->setBlocking(false); - sf::Socket::Status status; - if (cmd == CMD_WRITE) - status = client->send(send_data, sizeof(send_data)); - else - status = client->send(send_data, 1); + client->setBlocking(false); + sf::Socket::Status status; + if (cmd == CMD_WRITE) + status = client->send(send_data, sizeof(send_data)); + else + status = client->send(send_data, 1); - if (cmd != CMD_STATUS) - booted = true; + if (cmd != CMD_STATUS) + booted = true; - if (status == sf::Socket::Disconnected) - Disconnect(); + if (status == sf::Socket::Disconnected) + Disconnect(); - time_cmd_sent = CoreTiming::GetTicks(); + time_cmd_sent = CoreTiming::GetTicks(); } int GBASockServer::Receive(u8* si_buffer) { - if (!client) - if (!GetAvailableSock(client)) - return 5; + if (!client) + if (!GetAvailableSock(client)) + return 5; - size_t num_received = 0; - u64 transferTime = GetTransferTime((u8)send_data[0]); - bool block = (CoreTiming::GetTicks() - time_cmd_sent) > transferTime; - if (cmd == CMD_STATUS && !booted) - block = false; + size_t num_received = 0; + u64 transferTime = GetTransferTime((u8)send_data[0]); + bool block = (CoreTiming::GetTicks() - time_cmd_sent) > transferTime; + if (cmd == CMD_STATUS && !booted) + block = false; - if (block) - { - sf::SocketSelector Selector; - Selector.add(*client); - Selector.wait(sf::milliseconds(1000)); - } + if (block) + { + sf::SocketSelector Selector; + Selector.add(*client); + Selector.wait(sf::milliseconds(1000)); + } - sf::Socket::Status recv_stat = client->receive(recv_data, sizeof(recv_data), num_received); - if (recv_stat == sf::Socket::Disconnected) - { - Disconnect(); - return 5; - } + sf::Socket::Status recv_stat = client->receive(recv_data, sizeof(recv_data), num_received); + if (recv_stat == sf::Socket::Disconnected) + { + Disconnect(); + return 5; + } - if (recv_stat == sf::Socket::NotReady) - num_received = 0; + if (recv_stat == sf::Socket::NotReady) + num_received = 0; - if (num_received > sizeof(recv_data)) - num_received = sizeof(recv_data); + if (num_received > sizeof(recv_data)) + num_received = sizeof(recv_data); - if (num_received > 0) - { + if (num_received > 0) + { #ifdef _DEBUG - if ((u8)send_data[0] == 0x00 || (u8)send_data[0] == 0xff) - { - WARN_LOG(SERIALINTERFACE, "%01d [< %02x%02x%02x%02x%02x] (%lu)", - device_number, - (u8)recv_data[0], (u8)recv_data[1], (u8)recv_data[2], - (u8)recv_data[3], (u8)recv_data[4], - num_received); - } - else - { - ERROR_LOG(SERIALINTERFACE, "%01d [< %02x%02x%02x%02x%02x] (%lu)", - device_number, - (u8)recv_data[0], (u8)recv_data[1], (u8)recv_data[2], - (u8)recv_data[3], (u8)recv_data[4], - num_received); - } + if ((u8)send_data[0] == 0x00 || (u8)send_data[0] == 0xff) + { + WARN_LOG(SERIALINTERFACE, "%01d [< %02x%02x%02x%02x%02x] (%lu)", + device_number, (u8)recv_data[0], (u8)recv_data[1], (u8)recv_data[2], + (u8)recv_data[3], (u8)recv_data[4], num_received); + } + else + { + ERROR_LOG(SERIALINTERFACE, "%01d [< %02x%02x%02x%02x%02x] (%lu)", + device_number, (u8)recv_data[0], (u8)recv_data[1], (u8)recv_data[2], + (u8)recv_data[3], (u8)recv_data[4], num_received); + } #endif - for (int i = 0; i < 5; i++) - si_buffer[i ^ 3] = recv_data[i]; - } + for (int i = 0; i < 5; i++) + si_buffer[i ^ 3] = recv_data[i]; + } - return (int)num_received; + return (int)num_received; } CSIDevice_GBA::CSIDevice_GBA(SIDevices _device, int _iDeviceNumber) - : ISIDevice(_device, _iDeviceNumber) - , GBASockServer(_iDeviceNumber) + : ISIDevice(_device, _iDeviceNumber), GBASockServer(_iDeviceNumber) { - waiting_for_response = false; + waiting_for_response = false; } CSIDevice_GBA::~CSIDevice_GBA() { - GBASockServer::Disconnect(); + GBASockServer::Disconnect(); } int CSIDevice_GBA::RunBuffer(u8* _pBuffer, int _iLength) { - if (!waiting_for_response) - { - for (int i = 0; i < 5; i++) - send_data[i] = _pBuffer[i ^ 3]; + if (!waiting_for_response) + { + for (int i = 0; i < 5; i++) + send_data[i] = _pBuffer[i ^ 3]; - num_data_received = 0; - ClockSync(); - Send(_pBuffer); - timestamp_sent = CoreTiming::GetTicks(); - waiting_for_response = true; - } + num_data_received = 0; + ClockSync(); + Send(_pBuffer); + timestamp_sent = CoreTiming::GetTicks(); + waiting_for_response = true; + } - if (waiting_for_response && num_data_received == 0) - { - num_data_received = Receive(_pBuffer); - } + if (waiting_for_response && num_data_received == 0) + { + num_data_received = Receive(_pBuffer); + } - if ((GetTransferTime(send_data[0])) > (int)(CoreTiming::GetTicks() - timestamp_sent)) - { - return 0; - } - else - { - if (num_data_received != 0) - waiting_for_response = false; - return num_data_received; - } + if ((GetTransferTime(send_data[0])) > (int)(CoreTiming::GetTicks() - timestamp_sent)) + { + return 0; + } + else + { + if (num_data_received != 0) + waiting_for_response = false; + return num_data_received; + } } int CSIDevice_GBA::TransferInterval() { - return GetTransferTime(send_data[0]); + return GetTransferTime(send_data[0]); } diff --git a/Source/Core/Core/HW/SI_DeviceGBA.h b/Source/Core/Core/HW/SI_DeviceGBA.h index 27da216afd..6b9a0f7aac 100644 --- a/Source/Core/Core/HW/SI_DeviceGBA.h +++ b/Source/Core/Core/HW/SI_DeviceGBA.h @@ -4,8 +4,8 @@ #pragma once -#include #include +#include #include "Common/CommonTypes.h" #include "Core/HW/SI_Device.h" @@ -19,44 +19,43 @@ void GBAConnectionWaiter_Shutdown(); class GBASockServer { public: - GBASockServer(int _iDeviceNumber); - ~GBASockServer(); + GBASockServer(int _iDeviceNumber); + ~GBASockServer(); - void Disconnect(); + void Disconnect(); - void ClockSync(); + void ClockSync(); - void Send(u8* si_buffer); - int Receive(u8* si_buffer); + void Send(u8* si_buffer); + int Receive(u8* si_buffer); private: - std::unique_ptr client; - std::unique_ptr clock_sync; - char send_data[5]; - char recv_data[5]; + std::unique_ptr client; + std::unique_ptr clock_sync; + char send_data[5]; + char recv_data[5]; - u64 time_cmd_sent; - u64 last_time_slice; - u8 device_number; - u8 cmd; - bool booted; + u64 time_cmd_sent; + u64 last_time_slice; + u8 device_number; + u8 cmd; + bool booted; }; class CSIDevice_GBA : public ISIDevice, private GBASockServer { public: - CSIDevice_GBA(SIDevices device, int _iDeviceNumber); - ~CSIDevice_GBA(); + CSIDevice_GBA(SIDevices device, int _iDeviceNumber); + ~CSIDevice_GBA(); - int RunBuffer(u8* _pBuffer, int _iLength) override; - int TransferInterval() override; - - bool GetData(u32& _Hi, u32& _Low) override { return false; } - void SendCommand(u32 _Cmd, u8 _Poll) override {} + int RunBuffer(u8* _pBuffer, int _iLength) override; + int TransferInterval() override; + bool GetData(u32& _Hi, u32& _Low) override { return false; } + void SendCommand(u32 _Cmd, u8 _Poll) override {} private: - u8 send_data[5]; - int num_data_received; - u64 timestamp_sent; - bool waiting_for_response; + u8 send_data[5]; + int num_data_received; + u64 timestamp_sent; + bool waiting_for_response; }; diff --git a/Source/Core/Core/HW/SI_DeviceGCAdapter.cpp b/Source/Core/Core/HW/SI_DeviceGCAdapter.cpp index 2f955164bf..280a85e465 100644 --- a/Source/Core/Core/HW/SI_DeviceGCAdapter.cpp +++ b/Source/Core/Core/HW/SI_DeviceGCAdapter.cpp @@ -5,66 +5,66 @@ #include #include "Common/CommonTypes.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "Core/ConfigManager.h" -#include "Core/NetPlayProto.h" #include "Core/HW/GCPad.h" #include "Core/HW/SI_DeviceGCAdapter.h" +#include "Core/NetPlayProto.h" #include "InputCommon/GCAdapter.h" CSIDevice_GCAdapter::CSIDevice_GCAdapter(SIDevices device, int _iDeviceNumber) - : CSIDevice_GCController(device, _iDeviceNumber) + : CSIDevice_GCController(device, _iDeviceNumber) { - // get the correct pad number that should rumble locally when using netplay - const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber); - if (numPAD < 4) - m_simulate_konga = SConfig::GetInstance().m_AdapterKonga[numPAD]; + // get the correct pad number that should rumble locally when using netplay + const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber); + if (numPAD < 4) + m_simulate_konga = SConfig::GetInstance().m_AdapterKonga[numPAD]; } GCPadStatus CSIDevice_GCAdapter::GetPadStatus() { - GCPadStatus PadStatus; - memset(&PadStatus, 0, sizeof(PadStatus)); + GCPadStatus PadStatus; + memset(&PadStatus, 0, sizeof(PadStatus)); - // For netplay, the local controllers are polled in GetNetPads(), and - // the remote controllers receive their status there as well - if (!NetPlay::IsNetPlayRunning()) - { - GCAdapter::Input(ISIDevice::m_iDeviceNumber, &PadStatus); - } + // For netplay, the local controllers are polled in GetNetPads(), and + // the remote controllers receive their status there as well + if (!NetPlay::IsNetPlayRunning()) + { + GCAdapter::Input(ISIDevice::m_iDeviceNumber, &PadStatus); + } - HandleMoviePadStatus(&PadStatus); + HandleMoviePadStatus(&PadStatus); - return PadStatus; + return PadStatus; } int CSIDevice_GCAdapter::RunBuffer(u8* buffer, int length) { - if (!NetPlay::IsNetPlayRunning()) - { - // The previous check is a hack to prevent a netplay desync due to - // SI devices being different and returning different values on - // RunBuffer(); the corresponding code in GCAdapter.cpp has the same - // check. + if (!NetPlay::IsNetPlayRunning()) + { + // The previous check is a hack to prevent a netplay desync due to + // SI devices being different and returning different values on + // RunBuffer(); the corresponding code in GCAdapter.cpp has the same + // check. - // This returns an error value if there is no controller plugged - // into this port on the hardware gc adapter, exposing it to the game. - if (!GCAdapter::DeviceConnected(ISIDevice::m_iDeviceNumber)) - { - TSIDevices device = SI_NONE; - memcpy(buffer, &device, sizeof(device)); - return 4; - } - } - return CSIDevice_GCController::RunBuffer(buffer, length); + // This returns an error value if there is no controller plugged + // into this port on the hardware gc adapter, exposing it to the game. + if (!GCAdapter::DeviceConnected(ISIDevice::m_iDeviceNumber)) + { + TSIDevices device = SI_NONE; + memcpy(buffer, &device, sizeof(device)); + return 4; + } + } + return CSIDevice_GCController::RunBuffer(buffer, length); } void CSIDevice_GCController::Rumble(u8 numPad, ControlState strength) { - SIDevices device = SConfig::GetInstance().m_SIDevice[numPad]; - if (device == SIDEVICE_WIIU_ADAPTER) - GCAdapter::Output(numPad, static_cast(strength)); - else if (SIDevice_IsGCController(device)) - Pad::Rumble(numPad, strength); + SIDevices device = SConfig::GetInstance().m_SIDevice[numPad]; + if (device == SIDEVICE_WIIU_ADAPTER) + GCAdapter::Output(numPad, static_cast(strength)); + else if (SIDevice_IsGCController(device)) + Pad::Rumble(numPad, strength); } diff --git a/Source/Core/Core/HW/SI_DeviceGCAdapter.h b/Source/Core/Core/HW/SI_DeviceGCAdapter.h index f073f318bf..ff0a3508ef 100644 --- a/Source/Core/Core/HW/SI_DeviceGCAdapter.h +++ b/Source/Core/Core/HW/SI_DeviceGCAdapter.h @@ -11,8 +11,8 @@ class CSIDevice_GCAdapter : public CSIDevice_GCController { public: - CSIDevice_GCAdapter(SIDevices device, int _iDeviceNumber); + CSIDevice_GCAdapter(SIDevices device, int _iDeviceNumber); - GCPadStatus GetPadStatus() override; - int RunBuffer(u8* buffer, int length) override; + GCPadStatus GetPadStatus() override; + int RunBuffer(u8* buffer, int length) override; }; diff --git a/Source/Core/Core/HW/SI_DeviceGCController.cpp b/Source/Core/Core/HW/SI_DeviceGCController.cpp index 572e49c8b8..4d32c20306 100644 --- a/Source/Core/Core/HW/SI_DeviceGCController.cpp +++ b/Source/Core/Core/HW/SI_DeviceGCController.cpp @@ -2,158 +2,156 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/SI_Device.h" #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "Core/CoreTiming.h" -#include "Core/Movie.h" -#include "Core/NetPlayProto.h" #include "Core/HW/GCPad.h" #include "Core/HW/ProcessorInterface.h" -#include "Core/HW/SI_Device.h" #include "Core/HW/SI_DeviceGCController.h" #include "Core/HW/SystemTimers.h" +#include "Core/Movie.h" +#include "Core/NetPlayProto.h" #include "InputCommon/GCPadStatus.h" // --- standard GameCube controller --- CSIDevice_GCController::CSIDevice_GCController(SIDevices device, int _iDeviceNumber) - : ISIDevice(device, _iDeviceNumber) - , m_TButtonComboStart(0) - , m_TButtonCombo(0) - , m_LastButtonCombo(COMBO_NONE) + : ISIDevice(device, _iDeviceNumber), m_TButtonComboStart(0), m_TButtonCombo(0), + m_LastButtonCombo(COMBO_NONE) { - // Dunno if we need to do this, game/lib should set it? - m_Mode = 0x03; + // Dunno if we need to do this, game/lib should set it? + m_Mode = 0x03; - m_Calibrated = false; + m_Calibrated = false; } void CSIDevice_GCController::Calibrate() { - GCPadStatus pad_origin = GetPadStatus(); - memset(&m_Origin, 0, sizeof(SOrigin)); - m_Origin.uButton = pad_origin.button; - m_Origin.uOriginStickX = pad_origin.stickX; - m_Origin.uOriginStickY = pad_origin.stickY; - m_Origin.uSubStickStickX = pad_origin.substickX; - m_Origin.uSubStickStickY = pad_origin.substickY; - m_Origin.uTrigger_L = pad_origin.triggerLeft; - m_Origin.uTrigger_R = pad_origin.triggerRight; + GCPadStatus pad_origin = GetPadStatus(); + memset(&m_Origin, 0, sizeof(SOrigin)); + m_Origin.uButton = pad_origin.button; + m_Origin.uOriginStickX = pad_origin.stickX; + m_Origin.uOriginStickY = pad_origin.stickY; + m_Origin.uSubStickStickX = pad_origin.substickX; + m_Origin.uSubStickStickY = pad_origin.substickY; + m_Origin.uTrigger_L = pad_origin.triggerLeft; + m_Origin.uTrigger_R = pad_origin.triggerRight; - m_Calibrated = true; + m_Calibrated = true; } int CSIDevice_GCController::RunBuffer(u8* _pBuffer, int _iLength) { - // For debug logging only - ISIDevice::RunBuffer(_pBuffer, _iLength); + // For debug logging only + ISIDevice::RunBuffer(_pBuffer, _iLength); - // Read the command - EBufferCommands command = static_cast(_pBuffer[3]); + // Read the command + EBufferCommands command = static_cast(_pBuffer[3]); - // Handle it - switch (command) - { - case CMD_RESET: - case CMD_ID: - *(u32*)&_pBuffer[0] = SI_GC_CONTROLLER; - break; + // Handle it + switch (command) + { + case CMD_RESET: + case CMD_ID: + *(u32*)&_pBuffer[0] = SI_GC_CONTROLLER; + break; - case CMD_DIRECT: - { - INFO_LOG(SERIALINTERFACE, "PAD - Direct (Length: %d)", _iLength); - u32 high, low; - GetData(high, low); - for (int i = 0; i < (_iLength - 1) / 2; i++) - { - _pBuffer[i + 0] = (high >> (i * 8)) & 0xff; - _pBuffer[i + 4] = (low >> (i * 8)) & 0xff; - } - } - break; + case CMD_DIRECT: + { + INFO_LOG(SERIALINTERFACE, "PAD - Direct (Length: %d)", _iLength); + u32 high, low; + GetData(high, low); + for (int i = 0; i < (_iLength - 1) / 2; i++) + { + _pBuffer[i + 0] = (high >> (i * 8)) & 0xff; + _pBuffer[i + 4] = (low >> (i * 8)) & 0xff; + } + } + break; - case CMD_ORIGIN: - { - INFO_LOG(SERIALINTERFACE, "PAD - Get Origin"); + case CMD_ORIGIN: + { + INFO_LOG(SERIALINTERFACE, "PAD - Get Origin"); - if (!m_Calibrated) - Calibrate(); + if (!m_Calibrated) + Calibrate(); - u8* pCalibration = reinterpret_cast(&m_Origin); - for (int i = 0; i < (int)sizeof(SOrigin); i++) - { - _pBuffer[i ^ 3] = *pCalibration++; - } - } - break; + u8* pCalibration = reinterpret_cast(&m_Origin); + for (int i = 0; i < (int)sizeof(SOrigin); i++) + { + _pBuffer[i ^ 3] = *pCalibration++; + } + } + break; - // Recalibrate (FiRES: i am not 100 percent sure about this) - case CMD_RECALIBRATE: - { - INFO_LOG(SERIALINTERFACE, "PAD - Recalibrate"); + // Recalibrate (FiRES: i am not 100 percent sure about this) + case CMD_RECALIBRATE: + { + INFO_LOG(SERIALINTERFACE, "PAD - Recalibrate"); - if (!m_Calibrated) - Calibrate(); + if (!m_Calibrated) + Calibrate(); - u8* pCalibration = reinterpret_cast(&m_Origin); - for (int i = 0; i < (int)sizeof(SOrigin); i++) - { - _pBuffer[i ^ 3] = *pCalibration++; - } - } - break; + u8* pCalibration = reinterpret_cast(&m_Origin); + for (int i = 0; i < (int)sizeof(SOrigin); i++) + { + _pBuffer[i ^ 3] = *pCalibration++; + } + } + break; - // DEFAULT - default: - { - ERROR_LOG(SERIALINTERFACE, "Unknown SI command (0x%x)", command); - PanicAlert("SI: Unknown command (0x%x)", command); - } - break; - } + // DEFAULT + default: + { + ERROR_LOG(SERIALINTERFACE, "Unknown SI command (0x%x)", command); + PanicAlert("SI: Unknown command (0x%x)", command); + } + break; + } - return _iLength; + return _iLength; } void CSIDevice_GCController::HandleMoviePadStatus(GCPadStatus* PadStatus) { - Movie::CallGCInputManip(PadStatus, ISIDevice::m_iDeviceNumber); + Movie::CallGCInputManip(PadStatus, ISIDevice::m_iDeviceNumber); - Movie::SetPolledDevice(); - if (NetPlay_GetInput(ISIDevice::m_iDeviceNumber, PadStatus)) - { - } - else if (Movie::IsPlayingInput()) - { - Movie::PlayController(PadStatus, ISIDevice::m_iDeviceNumber); - Movie::InputUpdate(); - } - else if (Movie::IsRecordingInput()) - { - Movie::RecordInput(PadStatus, ISIDevice::m_iDeviceNumber); - Movie::InputUpdate(); - } - else - { - Movie::CheckPadStatus(PadStatus, ISIDevice::m_iDeviceNumber); - } + Movie::SetPolledDevice(); + if (NetPlay_GetInput(ISIDevice::m_iDeviceNumber, PadStatus)) + { + } + else if (Movie::IsPlayingInput()) + { + Movie::PlayController(PadStatus, ISIDevice::m_iDeviceNumber); + Movie::InputUpdate(); + } + else if (Movie::IsRecordingInput()) + { + Movie::RecordInput(PadStatus, ISIDevice::m_iDeviceNumber); + Movie::InputUpdate(); + } + else + { + Movie::CheckPadStatus(PadStatus, ISIDevice::m_iDeviceNumber); + } } GCPadStatus CSIDevice_GCController::GetPadStatus() { - GCPadStatus PadStatus; - memset(&PadStatus, 0, sizeof(PadStatus)); + GCPadStatus PadStatus; + memset(&PadStatus, 0, sizeof(PadStatus)); - // For netplay, the local controllers are polled in GetNetPads(), and - // the remote controllers receive their status there as well - if (!NetPlay::IsNetPlayRunning()) - { - Pad::GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus); - } + // For netplay, the local controllers are polled in GetNetPads(), and + // the remote controllers receive their status there as well + if (!NetPlay::IsNetPlayRunning()) + { + Pad::GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus); + } - HandleMoviePadStatus(&PadStatus); - return PadStatus; + HandleMoviePadStatus(&PadStatus); + return PadStatus; } // GetData @@ -164,167 +162,168 @@ GCPadStatus CSIDevice_GCController::GetPadStatus() // |_ ERR_STATUS (error on last GetData or SendCmd?) bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low) { - GCPadStatus PadStatus = GetPadStatus(); - if (HandleButtonCombos(PadStatus) == COMBO_ORIGIN) - PadStatus.button |= PAD_GET_ORIGIN; + GCPadStatus PadStatus = GetPadStatus(); + if (HandleButtonCombos(PadStatus) == COMBO_ORIGIN) + PadStatus.button |= PAD_GET_ORIGIN; - _Hi = MapPadStatus(PadStatus); + _Hi = MapPadStatus(PadStatus); - // Low bits are packed differently per mode - if (m_Mode == 0 || m_Mode == 5 || m_Mode == 6 || m_Mode == 7) - { - _Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits - _Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits - _Low |= (u32)((u8)(PadStatus.triggerRight >> 4) << 8); // Top 4 bits - _Low |= (u32)((u8)(PadStatus.triggerLeft >> 4) << 12); // Top 4 bits - _Low |= (u32)((u8)(PadStatus.substickY) << 16); // All 8 bits - _Low |= (u32)((u8)(PadStatus.substickX) << 24); // All 8 bits - } - else if (m_Mode == 1) - { - _Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits - _Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits - _Low |= (u32)((u8)PadStatus.triggerRight << 8); // All 8 bits - _Low |= (u32)((u8)PadStatus.triggerLeft << 16); // All 8 bits - _Low |= (u32)((u8)PadStatus.substickY << 24); // Top 4 bits - _Low |= (u32)((u8)PadStatus.substickX << 28); // Top 4 bits - } - else if (m_Mode == 2) - { - _Low = (u8)(PadStatus.analogB); // All 8 bits - _Low |= (u32)((u8)(PadStatus.analogA) << 8); // All 8 bits - _Low |= (u32)((u8)(PadStatus.triggerRight >> 4) << 16); // Top 4 bits - _Low |= (u32)((u8)(PadStatus.triggerLeft >> 4) << 20); // Top 4 bits - _Low |= (u32)((u8)PadStatus.substickY << 24); // Top 4 bits - _Low |= (u32)((u8)PadStatus.substickX << 28); // Top 4 bits - } - else if (m_Mode == 3) - { - // Analog A/B are always 0 - _Low = (u8)PadStatus.triggerRight; // All 8 bits - _Low |= (u32)((u8)PadStatus.triggerLeft << 8); // All 8 bits - _Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits - _Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits - } - else if (m_Mode == 4) - { - _Low = (u8)(PadStatus.analogB); // All 8 bits - _Low |= (u32)((u8)(PadStatus.analogA) << 8); // All 8 bits - // triggerLeft/Right are always 0 - _Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits - _Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits - } + // Low bits are packed differently per mode + if (m_Mode == 0 || m_Mode == 5 || m_Mode == 6 || m_Mode == 7) + { + _Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits + _Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits + _Low |= (u32)((u8)(PadStatus.triggerRight >> 4) << 8); // Top 4 bits + _Low |= (u32)((u8)(PadStatus.triggerLeft >> 4) << 12); // Top 4 bits + _Low |= (u32)((u8)(PadStatus.substickY) << 16); // All 8 bits + _Low |= (u32)((u8)(PadStatus.substickX) << 24); // All 8 bits + } + else if (m_Mode == 1) + { + _Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits + _Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits + _Low |= (u32)((u8)PadStatus.triggerRight << 8); // All 8 bits + _Low |= (u32)((u8)PadStatus.triggerLeft << 16); // All 8 bits + _Low |= (u32)((u8)PadStatus.substickY << 24); // Top 4 bits + _Low |= (u32)((u8)PadStatus.substickX << 28); // Top 4 bits + } + else if (m_Mode == 2) + { + _Low = (u8)(PadStatus.analogB); // All 8 bits + _Low |= (u32)((u8)(PadStatus.analogA) << 8); // All 8 bits + _Low |= (u32)((u8)(PadStatus.triggerRight >> 4) << 16); // Top 4 bits + _Low |= (u32)((u8)(PadStatus.triggerLeft >> 4) << 20); // Top 4 bits + _Low |= (u32)((u8)PadStatus.substickY << 24); // Top 4 bits + _Low |= (u32)((u8)PadStatus.substickX << 28); // Top 4 bits + } + else if (m_Mode == 3) + { + // Analog A/B are always 0 + _Low = (u8)PadStatus.triggerRight; // All 8 bits + _Low |= (u32)((u8)PadStatus.triggerLeft << 8); // All 8 bits + _Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits + _Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits + } + else if (m_Mode == 4) + { + _Low = (u8)(PadStatus.analogB); // All 8 bits + _Low |= (u32)((u8)(PadStatus.analogA) << 8); // All 8 bits + // triggerLeft/Right are always 0 + _Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits + _Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits + } - // Unset all bits except those that represent - // A, B, X, Y, Start and the error bits, as they - // are not used. - if (m_simulate_konga) - _Hi &= ~0x20FFFFFF; + // Unset all bits except those that represent + // A, B, X, Y, Start and the error bits, as they + // are not used. + if (m_simulate_konga) + _Hi &= ~0x20FFFFFF; - return true; + return true; } u32 CSIDevice_GCController::MapPadStatus(const GCPadStatus& pad_status) { - // Thankfully changing mode does not change the high bits ;) - u32 _Hi = 0; - _Hi = (u32)((u8)pad_status.stickY); - _Hi |= (u32)((u8)pad_status.stickX << 8); - _Hi |= (u32)((u16)(pad_status.button | PAD_USE_ORIGIN) << 16); - return _Hi; + // Thankfully changing mode does not change the high bits ;) + u32 _Hi = 0; + _Hi = (u32)((u8)pad_status.stickY); + _Hi |= (u32)((u8)pad_status.stickX << 8); + _Hi |= (u32)((u16)(pad_status.button | PAD_USE_ORIGIN) << 16); + return _Hi; } -CSIDevice_GCController::EButtonCombo CSIDevice_GCController::HandleButtonCombos(const GCPadStatus& pad_status) +CSIDevice_GCController::EButtonCombo +CSIDevice_GCController::HandleButtonCombos(const GCPadStatus& pad_status) { - // Keep track of the special button combos (embedded in controller hardware... :( ) - EButtonCombo tempCombo; - if ((pad_status.button & 0xff00) == (PAD_BUTTON_Y|PAD_BUTTON_X|PAD_BUTTON_START)) - tempCombo = COMBO_ORIGIN; - else if ((pad_status.button & 0xff00) == (PAD_BUTTON_B|PAD_BUTTON_X|PAD_BUTTON_START)) - tempCombo = COMBO_RESET; - else - tempCombo = COMBO_NONE; - if (tempCombo != m_LastButtonCombo) - { - m_LastButtonCombo = tempCombo; - if (m_LastButtonCombo != COMBO_NONE) - m_TButtonComboStart = CoreTiming::GetTicks(); - } - if (m_LastButtonCombo != COMBO_NONE) - { - m_TButtonCombo = CoreTiming::GetTicks(); - if ((m_TButtonCombo - m_TButtonComboStart) > SystemTimers::GetTicksPerSecond() * 3) - { - if (m_LastButtonCombo == COMBO_RESET) - ProcessorInterface::ResetButton_Tap(); - else if (m_LastButtonCombo == COMBO_ORIGIN) - { - m_Origin.uOriginStickX = pad_status.stickX; - m_Origin.uOriginStickY = pad_status.stickY; - m_Origin.uSubStickStickX = pad_status.substickX; - m_Origin.uSubStickStickY = pad_status.substickY; - m_Origin.uTrigger_L = pad_status.triggerLeft; - m_Origin.uTrigger_R = pad_status.triggerRight; - } - m_LastButtonCombo = COMBO_NONE; - return tempCombo; - } - } + // Keep track of the special button combos (embedded in controller hardware... :( ) + EButtonCombo tempCombo; + if ((pad_status.button & 0xff00) == (PAD_BUTTON_Y | PAD_BUTTON_X | PAD_BUTTON_START)) + tempCombo = COMBO_ORIGIN; + else if ((pad_status.button & 0xff00) == (PAD_BUTTON_B | PAD_BUTTON_X | PAD_BUTTON_START)) + tempCombo = COMBO_RESET; + else + tempCombo = COMBO_NONE; + if (tempCombo != m_LastButtonCombo) + { + m_LastButtonCombo = tempCombo; + if (m_LastButtonCombo != COMBO_NONE) + m_TButtonComboStart = CoreTiming::GetTicks(); + } + if (m_LastButtonCombo != COMBO_NONE) + { + m_TButtonCombo = CoreTiming::GetTicks(); + if ((m_TButtonCombo - m_TButtonComboStart) > SystemTimers::GetTicksPerSecond() * 3) + { + if (m_LastButtonCombo == COMBO_RESET) + ProcessorInterface::ResetButton_Tap(); + else if (m_LastButtonCombo == COMBO_ORIGIN) + { + m_Origin.uOriginStickX = pad_status.stickX; + m_Origin.uOriginStickY = pad_status.stickY; + m_Origin.uSubStickStickX = pad_status.substickX; + m_Origin.uSubStickStickY = pad_status.substickY; + m_Origin.uTrigger_L = pad_status.triggerLeft; + m_Origin.uTrigger_R = pad_status.triggerRight; + } + m_LastButtonCombo = COMBO_NONE; + return tempCombo; + } + } - return COMBO_NONE; + return COMBO_NONE; } // SendCommand void CSIDevice_GCController::SendCommand(u32 _Cmd, u8 _Poll) { - UCommand command(_Cmd); + UCommand command(_Cmd); - switch (command.Command) - { - // Costis sent it in some demos :) - case 0x00: - break; + switch (command.Command) + { + // Costis sent it in some demos :) + case 0x00: + break; - case CMD_WRITE: - { - unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard - unsigned int uStrength = command.Parameter2; + case CMD_WRITE: + { + unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard + unsigned int uStrength = command.Parameter2; - // get the correct pad number that should rumble locally when using netplay - const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber); + // get the correct pad number that should rumble locally when using netplay + const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber); - if (numPAD < 4) - { - if (uType == 1 && uStrength > 2) - CSIDevice_GCController::Rumble(numPAD, 1.0); - else - CSIDevice_GCController::Rumble(numPAD, 0.0); - } + if (numPAD < 4) + { + if (uType == 1 && uStrength > 2) + CSIDevice_GCController::Rumble(numPAD, 1.0); + else + CSIDevice_GCController::Rumble(numPAD, 0.0); + } - if (!_Poll) - { - m_Mode = command.Parameter2; - INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode); - } - } - break; + if (!_Poll) + { + m_Mode = command.Parameter2; + INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode); + } + } + break; - default: - { - ERROR_LOG(SERIALINTERFACE, "Unknown direct command (0x%x)", _Cmd); - PanicAlert("SI: Unknown direct command"); - } - break; - } + default: + { + ERROR_LOG(SERIALINTERFACE, "Unknown direct command (0x%x)", _Cmd); + PanicAlert("SI: Unknown direct command"); + } + break; + } } // Savestate support void CSIDevice_GCController::DoState(PointerWrap& p) { - p.Do(m_Calibrated); - p.Do(m_Origin); - p.Do(m_Mode); - p.Do(m_TButtonComboStart); - p.Do(m_TButtonCombo); - p.Do(m_LastButtonCombo); + p.Do(m_Calibrated); + p.Do(m_Origin); + p.Do(m_Mode); + p.Do(m_TButtonComboStart); + p.Do(m_TButtonCombo); + p.Do(m_LastButtonCombo); } diff --git a/Source/Core/Core/HW/SI_DeviceGCController.h b/Source/Core/Core/HW/SI_DeviceGCController.h index 836b2182db..139c78978a 100644 --- a/Source/Core/Core/HW/SI_DeviceGCController.h +++ b/Source/Core/Core/HW/SI_DeviceGCController.h @@ -11,118 +11,115 @@ class CSIDevice_GCController : public ISIDevice { protected: + // Commands + enum EBufferCommands + { + CMD_RESET = 0x00, + CMD_DIRECT = 0x40, + CMD_ORIGIN = 0x41, + CMD_RECALIBRATE = 0x42, + CMD_ID = 0xff, + }; - // Commands - enum EBufferCommands - { - CMD_RESET = 0x00, - CMD_DIRECT = 0x40, - CMD_ORIGIN = 0x41, - CMD_RECALIBRATE = 0x42, - CMD_ID = 0xff, - }; + struct SOrigin + { + u16 uButton; + u8 uOriginStickX; + u8 uOriginStickY; + u8 uSubStickStickX; + u8 uSubStickStickY; + u8 uTrigger_L; + u8 uTrigger_R; + u8 unk_4; + u8 unk_5; + u8 unk_6; + u8 unk_7; + }; - struct SOrigin - { - u16 uButton; - u8 uOriginStickX; - u8 uOriginStickY; - u8 uSubStickStickX; - u8 uSubStickStickY; - u8 uTrigger_L; - u8 uTrigger_R; - u8 unk_4; - u8 unk_5; - u8 unk_6; - u8 unk_7; - }; + enum EDirectCommands + { + CMD_WRITE = 0x40 + }; - enum EDirectCommands - { - CMD_WRITE = 0x40 - }; + union UCommand { + u32 Hex; + struct + { + u32 Parameter1 : 8; + u32 Parameter2 : 8; + u32 Command : 8; + u32 : 8; + }; + UCommand() { Hex = 0; } + UCommand(u32 _iValue) { Hex = _iValue; } + }; - union UCommand - { - u32 Hex; - struct - { - u32 Parameter1 : 8; - u32 Parameter2 : 8; - u32 Command : 8; - u32 : 8; - }; - UCommand() {Hex = 0;} - UCommand(u32 _iValue) {Hex = _iValue;} - }; + enum EButtonCombo + { + COMBO_NONE = 0, + COMBO_ORIGIN, + COMBO_RESET + }; - enum EButtonCombo - { - COMBO_NONE = 0, - COMBO_ORIGIN, - COMBO_RESET - }; + // struct to compare input against + // Set on connection and (standard pad only) on button combo + SOrigin m_Origin; - // struct to compare input against - // Set on connection and (standard pad only) on button combo - SOrigin m_Origin; + bool m_Calibrated; - bool m_Calibrated; + // PADAnalogMode + u8 m_Mode; - // PADAnalogMode - u8 m_Mode; + // Timer to track special button combos: + // y, X, start for 3 seconds updates origin with current status + // Technically, the above is only on standard pad, wavebird does not support it for example + // b, x, start for 3 seconds triggers reset (PI reset button interrupt) + u64 m_TButtonComboStart, m_TButtonCombo; + // Type of button combo from the last/current poll + EButtonCombo m_LastButtonCombo; - // Timer to track special button combos: - // y, X, start for 3 seconds updates origin with current status - // Technically, the above is only on standard pad, wavebird does not support it for example - // b, x, start for 3 seconds triggers reset (PI reset button interrupt) - u64 m_TButtonComboStart, m_TButtonCombo; - // Type of button combo from the last/current poll - EButtonCombo m_LastButtonCombo; - - // Set this if we want to simulate the "TaruKonga" DK Bongo controller - bool m_simulate_konga = false; + // Set this if we want to simulate the "TaruKonga" DK Bongo controller + bool m_simulate_konga = false; public: + // Constructor + CSIDevice_GCController(SIDevices device, int _iDeviceNumber); - // Constructor - CSIDevice_GCController(SIDevices device, int _iDeviceNumber); + // Run the SI Buffer + int RunBuffer(u8* _pBuffer, int _iLength) override; - // Run the SI Buffer - int RunBuffer(u8* _pBuffer, int _iLength) override; + // Return true on new data + bool GetData(u32& _Hi, u32& _Low) override; - // Return true on new data - bool GetData(u32& _Hi, u32& _Low) override; + // Send a command directly + void SendCommand(u32 _Cmd, u8 _Poll) override; - // Send a command directly - void SendCommand(u32 _Cmd, u8 _Poll) override; + // Savestate support + void DoState(PointerWrap& p) override; - // Savestate support - void DoState(PointerWrap& p) override; + virtual GCPadStatus GetPadStatus(); + virtual u32 MapPadStatus(const GCPadStatus& pad_status); + virtual EButtonCombo HandleButtonCombos(const GCPadStatus& pad_status); - virtual GCPadStatus GetPadStatus(); - virtual u32 MapPadStatus(const GCPadStatus& pad_status); - virtual EButtonCombo HandleButtonCombos(const GCPadStatus& pad_status); + // Send and Receive pad input from network + static bool NetPlay_GetInput(u8 numPAD, GCPadStatus* status); + static u8 NetPlay_InGamePadToLocalPad(u8 numPAD); - // Send and Receive pad input from network - static bool NetPlay_GetInput(u8 numPAD, GCPadStatus* status); - static u8 NetPlay_InGamePadToLocalPad(u8 numPAD); - - // Direct rumble to the right GC Controller - static void Rumble(u8 numPad, ControlState strength); + // Direct rumble to the right GC Controller + static void Rumble(u8 numPad, ControlState strength); protected: - void Calibrate(); - void HandleMoviePadStatus(GCPadStatus* PadStatus); + void Calibrate(); + void HandleMoviePadStatus(GCPadStatus* PadStatus); }; - // "TaruKonga", the DK Bongo controller class CSIDevice_TaruKonga : public CSIDevice_GCController { public: - CSIDevice_TaruKonga(SIDevices device, int _iDeviceNumber) : CSIDevice_GCController(device, _iDeviceNumber) - { - m_simulate_konga = true; - } + CSIDevice_TaruKonga(SIDevices device, int _iDeviceNumber) + : CSIDevice_GCController(device, _iDeviceNumber) + { + m_simulate_konga = true; + } }; diff --git a/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.cpp b/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.cpp index b71f5ff423..00333cc1f0 100644 --- a/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.cpp +++ b/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.cpp @@ -2,107 +2,110 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/SI_DeviceGCSteeringWheel.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Core/HW/GCPad.h" -#include "Core/HW/SI_DeviceGCSteeringWheel.h" CSIDevice_GCSteeringWheel::CSIDevice_GCSteeringWheel(SIDevices device, int _iDeviceNumber) - : CSIDevice_GCController(device, _iDeviceNumber) -{} + : CSIDevice_GCController(device, _iDeviceNumber) +{ +} int CSIDevice_GCSteeringWheel::RunBuffer(u8* _pBuffer, int _iLength) { - // For debug logging only - ISIDevice::RunBuffer(_pBuffer, _iLength); + // For debug logging only + ISIDevice::RunBuffer(_pBuffer, _iLength); - // Read the command - EBufferCommands command = static_cast(_pBuffer[3]); + // Read the command + EBufferCommands command = static_cast(_pBuffer[3]); - // Handle it - switch (command) - { - case CMD_RESET: - case CMD_ID: - *(u32*)&_pBuffer[0] = SI_GC_STEERING; - break; + // Handle it + switch (command) + { + case CMD_RESET: + case CMD_ID: + *(u32*)&_pBuffer[0] = SI_GC_STEERING; + break; - // DEFAULT - default: - { - return CSIDevice_GCController::RunBuffer(_pBuffer, _iLength); - } - break; - } + // DEFAULT + default: + { + return CSIDevice_GCController::RunBuffer(_pBuffer, _iLength); + } + break; + } - return _iLength; + return _iLength; } bool CSIDevice_GCSteeringWheel::GetData(u32& _Hi, u32& _Low) { - if (m_Mode == 6) - { - GCPadStatus PadStatus = GetPadStatus(); + if (m_Mode == 6) + { + GCPadStatus PadStatus = GetPadStatus(); - _Hi = (u32)((u8)PadStatus.stickX); // Steering - _Hi |= 0x800; // Pedal connected flag - _Hi |= (u32)((u16)(PadStatus.button | PAD_USE_ORIGIN) << 16); + _Hi = (u32)((u8)PadStatus.stickX); // Steering + _Hi |= 0x800; // Pedal connected flag + _Hi |= (u32)((u16)(PadStatus.button | PAD_USE_ORIGIN) << 16); - _Low = (u8)PadStatus.triggerRight; // All 8 bits - _Low |= (u32)((u8)PadStatus.triggerLeft << 8); // All 8 bits + _Low = (u8)PadStatus.triggerRight; // All 8 bits + _Low |= (u32)((u8)PadStatus.triggerLeft << 8); // All 8 bits - // The GC Steering Wheel appears to have combined pedals - // (both the Accelerate and Brake pedals are mapped to a single axis) - // We use the stickY axis for the pedals. - if (PadStatus.stickY < 128) - _Low |= (u32)((u8)(255 - ((PadStatus.stickY & 0x7f) * 2)) << 16); // All 8 bits (Brake) - if (PadStatus.stickY >= 128) - _Low |= (u32)((u8)((PadStatus.stickY & 0x7f) * 2) << 24); // All 8 bits (Accelerate) + // The GC Steering Wheel appears to have combined pedals + // (both the Accelerate and Brake pedals are mapped to a single axis) + // We use the stickY axis for the pedals. + if (PadStatus.stickY < 128) + _Low |= (u32)((u8)(255 - ((PadStatus.stickY & 0x7f) * 2)) << 16); // All 8 bits (Brake) + if (PadStatus.stickY >= 128) + _Low |= (u32)((u8)((PadStatus.stickY & 0x7f) * 2) << 24); // All 8 bits (Accelerate) - HandleButtonCombos(PadStatus); - } - else - { - return CSIDevice_GCController::GetData(_Hi, _Low); - } + HandleButtonCombos(PadStatus); + } + else + { + return CSIDevice_GCController::GetData(_Hi, _Low); + } - return true; + return true; } void CSIDevice_GCSteeringWheel::SendCommand(u32 _Cmd, u8 _Poll) { - UCommand command(_Cmd); + UCommand command(_Cmd); - if (command.Command == CMD_FORCE) - { - unsigned int uStrength = command.Parameter1; // 0 = left strong, 127 = left weak, 128 = right weak, 255 = right strong - unsigned int uType = command.Parameter2; // 06 = motor on, 04 = motor off + if (command.Command == CMD_FORCE) + { + unsigned int uStrength = + command + .Parameter1; // 0 = left strong, 127 = left weak, 128 = right weak, 255 = right strong + unsigned int uType = command.Parameter2; // 06 = motor on, 04 = motor off - // get the correct pad number that should rumble locally when using netplay - const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber); + // get the correct pad number that should rumble locally when using netplay + const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber); - if (numPAD < 4) - { - if (uType == 0x06) - { - // map 0..255 to -1.0..1.0 - ControlState strength = uStrength / 127.5 - 1; - Pad::Rumble(numPAD, strength); - } - else - { - Pad::Rumble(numPAD, 0); - } - } + if (numPAD < 4) + { + if (uType == 0x06) + { + // map 0..255 to -1.0..1.0 + ControlState strength = uStrength / 127.5 - 1; + Pad::Rumble(numPAD, strength); + } + else + { + Pad::Rumble(numPAD, 0); + } + } - if (!_Poll) - { - m_Mode = command.Parameter2; - INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode); - } - } - else - { - return CSIDevice_GCController::SendCommand(_Cmd, _Poll); - } + if (!_Poll) + { + m_Mode = command.Parameter2; + INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode); + } + } + else + { + return CSIDevice_GCController::SendCommand(_Cmd, _Poll); + } } diff --git a/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.h b/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.h index fcc0805971..2d106b8a23 100644 --- a/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.h +++ b/Source/Core/Core/HW/SI_DeviceGCSteeringWheel.h @@ -9,25 +9,25 @@ class CSIDevice_GCSteeringWheel : public CSIDevice_GCController { private: - // Commands - enum EBufferCommands - { - CMD_RESET = 0x00, - CMD_ORIGIN = 0x41, - CMD_RECALIBRATE = 0x42, - CMD_ID = 0xff, - }; + // Commands + enum EBufferCommands + { + CMD_RESET = 0x00, + CMD_ORIGIN = 0x41, + CMD_RECALIBRATE = 0x42, + CMD_ID = 0xff, + }; - enum EDirectCommands - { - CMD_FORCE = 0x30, - CMD_WRITE = 0x40 - }; + enum EDirectCommands + { + CMD_FORCE = 0x30, + CMD_WRITE = 0x40 + }; public: - CSIDevice_GCSteeringWheel(SIDevices device, int _iDeviceNumber); + CSIDevice_GCSteeringWheel(SIDevices device, int _iDeviceNumber); - int RunBuffer(u8* _pBuffer, int _iLength) override; - bool GetData(u32& _Hi, u32& _Low) override; - void SendCommand(u32 _Cmd, u8 _Poll) override; + int RunBuffer(u8* _pBuffer, int _iLength) override; + bool GetData(u32& _Hi, u32& _Low) override; + void SendCommand(u32 _Cmd, u8 _Poll) override; }; diff --git a/Source/Core/Core/HW/SI_DeviceKeyboard.cpp b/Source/Core/Core/HW/SI_DeviceKeyboard.cpp index 1adb0a85b8..adfd810b9b 100644 --- a/Source/Core/Core/HW/SI_DeviceKeyboard.cpp +++ b/Source/Core/Core/HW/SI_DeviceKeyboard.cpp @@ -2,193 +2,619 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/SI_DeviceKeyboard.h" #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Core/HW/GCKeyboard.h" -#include "Core/HW/SI_DeviceKeyboard.h" #include "InputCommon/KeyboardStatus.h" // --- GameCube keyboard --- CSIDevice_Keyboard::CSIDevice_Keyboard(SIDevices device, int _iDeviceNumber) - : ISIDevice(device, _iDeviceNumber) -{} + : ISIDevice(device, _iDeviceNumber) +{ +} int CSIDevice_Keyboard::RunBuffer(u8* _pBuffer, int _iLength) { - // For debug logging only - ISIDevice::RunBuffer(_pBuffer, _iLength); + // For debug logging only + ISIDevice::RunBuffer(_pBuffer, _iLength); - // Read the command - EBufferCommands command = static_cast(_pBuffer[3]); + // Read the command + EBufferCommands command = static_cast(_pBuffer[3]); - // Handle it - switch (command) - { - case CMD_RESET: - case CMD_ID: - *(u32*)&_pBuffer[0] = SI_GC_KEYBOARD; - break; + // Handle it + switch (command) + { + case CMD_RESET: + case CMD_ID: + *(u32*)&_pBuffer[0] = SI_GC_KEYBOARD; + break; - case CMD_DIRECT: - { - INFO_LOG(SERIALINTERFACE, "Keyboard - Direct (Length: %d)", _iLength); - u32 high, low; - GetData(high, low); - for (int i = 0; i < (_iLength - 1) / 2; i++) - { - _pBuffer[i + 0] = (high >> (i * 8)) & 0xff; - _pBuffer[i + 4] = (low >> (i * 8)) & 0xff; - } - } - break; + case CMD_DIRECT: + { + INFO_LOG(SERIALINTERFACE, "Keyboard - Direct (Length: %d)", _iLength); + u32 high, low; + GetData(high, low); + for (int i = 0; i < (_iLength - 1) / 2; i++) + { + _pBuffer[i + 0] = (high >> (i * 8)) & 0xff; + _pBuffer[i + 4] = (low >> (i * 8)) & 0xff; + } + } + break; - default: - { - ERROR_LOG(SERIALINTERFACE, "Unknown SI command (0x%x)", command); - } - break; - } + default: + { + ERROR_LOG(SERIALINTERFACE, "Unknown SI command (0x%x)", command); + } + break; + } - return _iLength; + return _iLength; } KeyboardStatus CSIDevice_Keyboard::GetKeyboardStatus() { - KeyboardStatus KeyStatus = {}; - Keyboard::GetStatus(ISIDevice::m_iDeviceNumber, &KeyStatus); - return KeyStatus; + KeyboardStatus KeyStatus = {}; + Keyboard::GetStatus(ISIDevice::m_iDeviceNumber, &KeyStatus); + return KeyStatus; } bool CSIDevice_Keyboard::GetData(u32& _Hi, u32& _Low) { - KeyboardStatus KeyStatus = GetKeyboardStatus(); - u8 key[3] = { 0x00, 0x00, 0x00 }; - MapKeys(KeyStatus, key); - u8 checksum = key[0] ^ key[1] ^ key[2] ^ m_Counter; + KeyboardStatus KeyStatus = GetKeyboardStatus(); + u8 key[3] = {0x00, 0x00, 0x00}; + MapKeys(KeyStatus, key); + u8 checksum = key[0] ^ key[1] ^ key[2] ^ m_Counter; - _Hi = m_Counter << 24; - _Low = key[0] << 24 | key[1] << 16 | key[2] << 8 | checksum; + _Hi = m_Counter << 24; + _Low = key[0] << 24 | key[1] << 16 | key[2] << 8 | checksum; - return true; + return true; } void CSIDevice_Keyboard::SendCommand(u32 _Cmd, u8 _Poll) { - UCommand command(_Cmd); + UCommand command(_Cmd); - switch (command.Command) - { - case 0x00: - break; + switch (command.Command) + { + case 0x00: + break; - case CMD_POLL: - { - m_Counter++; - m_Counter &= 15; - } - break; - default: - { - ERROR_LOG(SERIALINTERFACE, "Unknown direct command (0x%x)", _Cmd); - } - break; - } + case CMD_POLL: + { + m_Counter++; + m_Counter &= 15; + } + break; + default: + { + ERROR_LOG(SERIALINTERFACE, "Unknown direct command (0x%x)", _Cmd); + } + break; + } } void CSIDevice_Keyboard::DoState(PointerWrap& p) { - p.Do(m_Counter); + p.Do(m_Counter); } void CSIDevice_Keyboard::MapKeys(KeyboardStatus& KeyStatus, u8* key) { - u8 keys_held = 0; - const u8 MAX_KEYS_HELD = 3; + u8 keys_held = 0; + const u8 MAX_KEYS_HELD = 3; - if (KeyStatus.key0x & KEYMASK_HOME) { key[keys_held++] = KEY_HOME; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key0x & KEYMASK_END) { key[keys_held++] = KEY_END; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key0x & KEYMASK_PGUP) { key[keys_held++] = KEY_PGUP; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key0x & KEYMASK_PGDN) { key[keys_held++] = KEY_PGDN; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key0x & KEYMASK_SCROLLLOCK) { key[keys_held++] = KEY_SCROLLLOCK; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key0x & KEYMASK_A) { key[keys_held++] = KEY_A; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key0x & KEYMASK_B) { key[keys_held++] = KEY_B; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key0x & KEYMASK_C) { key[keys_held++] = KEY_C; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key0x & KEYMASK_D) { key[keys_held++] = KEY_D; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key0x & KEYMASK_E) { key[keys_held++] = KEY_E; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key0x & KEYMASK_F) { key[keys_held++] = KEY_F; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key0x & KEYMASK_G) { key[keys_held++] = KEY_G; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key0x & KEYMASK_H) { key[keys_held++] = KEY_H; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key0x & KEYMASK_I) { key[keys_held++] = KEY_I; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key0x & KEYMASK_J) { key[keys_held++] = KEY_J; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key0x & KEYMASK_K) { key[keys_held++] = KEY_K; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_L) { key[keys_held++] = KEY_L; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_M) { key[keys_held++] = KEY_M; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_N) { key[keys_held++] = KEY_N; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_O) { key[keys_held++] = KEY_O; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_P) { key[keys_held++] = KEY_P; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_Q) { key[keys_held++] = KEY_Q; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_R) { key[keys_held++] = KEY_R; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_S) { key[keys_held++] = KEY_S; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_T) { key[keys_held++] = KEY_T; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_U) { key[keys_held++] = KEY_U; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_V) { key[keys_held++] = KEY_V; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_W) { key[keys_held++] = KEY_W; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_X) { key[keys_held++] = KEY_X; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_Y) { key[keys_held++] = KEY_Y; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_Z) { key[keys_held++] = KEY_Z; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key1x & KEYMASK_1) { key[keys_held++] = KEY_1; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_2) { key[keys_held++] = KEY_2; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_3) { key[keys_held++] = KEY_3; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_4) { key[keys_held++] = KEY_4; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_5) { key[keys_held++] = KEY_5; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_6) { key[keys_held++] = KEY_6; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_7) { key[keys_held++] = KEY_7; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_8) { key[keys_held++] = KEY_8; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_9) { key[keys_held++] = KEY_9; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_0) { key[keys_held++] = KEY_0; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_MINUS) { key[keys_held++] = KEY_MINUS; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_PLUS) { key[keys_held++] = KEY_PLUS; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_PRINTSCR) { key[keys_held++] = KEY_PRINTSCR; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_BRACE_OPEN) { key[keys_held++] = KEY_BRACE_OPEN; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_BRACE_CLOSE) { key[keys_held++] = KEY_BRACE_CLOSE; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_COLON) { key[keys_held++] = KEY_COLON; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key2x & KEYMASK_QUOTE) { key[keys_held++] = KEY_QUOTE; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_HASH) { key[keys_held++] = KEY_HASH; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_COMMA) { key[keys_held++] = KEY_COMMA; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_PERIOD) { key[keys_held++] = KEY_PERIOD; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_QUESTIONMARK) { key[keys_held++] = KEY_QUESTIONMARK; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_INTERNATIONAL1) { key[keys_held++] = KEY_INTERNATIONAL1; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_F1) { key[keys_held++] = KEY_F1; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_F2) { key[keys_held++] = KEY_F2; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_F3) { key[keys_held++] = KEY_F3; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_F4) { key[keys_held++] = KEY_F4; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_F5) { key[keys_held++] = KEY_F5; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_F6) { key[keys_held++] = KEY_F6; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_F7) { key[keys_held++] = KEY_F7; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_F8) { key[keys_held++] = KEY_F8; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_F9) { key[keys_held++] = KEY_F9; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_F10) { key[keys_held++] = KEY_F10; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key3x & KEYMASK_F11) { key[keys_held++] = KEY_F11; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_F12) { key[keys_held++] = KEY_F12; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_ESC) { key[keys_held++] = KEY_ESC; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_INSERT) { key[keys_held++] = KEY_INSERT; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_DELETE) { key[keys_held++] = KEY_DELETE; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_TILDE) { key[keys_held++] = KEY_TILDE; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_BACKSPACE) { key[keys_held++] = KEY_BACKSPACE; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_TAB) { key[keys_held++] = KEY_TAB; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_CAPSLOCK) { key[keys_held++] = KEY_CAPSLOCK; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_LEFTSHIFT) { key[keys_held++] = KEY_LEFTSHIFT; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_RIGHTSHIFT) { key[keys_held++] = KEY_RIGHTSHIFT; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_LEFTCONTROL) { key[keys_held++] = KEY_LEFTCONTROL; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_RIGHTALT) { key[keys_held++] = KEY_RIGHTALT; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_LEFTWINDOWS) { key[keys_held++] = KEY_LEFTWINDOWS; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_SPACE) { key[keys_held++] = KEY_SPACE; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_RIGHTWINDOWS) { key[keys_held++] = KEY_RIGHTWINDOWS; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key4x & KEYMASK_MENU) { key[keys_held++] = KEY_MENU; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key5x & KEYMASK_LEFTARROW) { key[keys_held++] = KEY_LEFTARROW; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key5x & KEYMASK_DOWNARROW) { key[keys_held++] = KEY_DOWNARROW; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key5x & KEYMASK_UPARROW) { key[keys_held++] = KEY_UPARROW; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key5x & KEYMASK_RIGHTARROW) { key[keys_held++] = KEY_RIGHTARROW; if (keys_held >= MAX_KEYS_HELD) return; } - if (KeyStatus.key5x & KEYMASK_ENTER) { key[keys_held++] = KEY_ENTER; if (keys_held >= MAX_KEYS_HELD) return; } + if (KeyStatus.key0x & KEYMASK_HOME) + { + key[keys_held++] = KEY_HOME; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key0x & KEYMASK_END) + { + key[keys_held++] = KEY_END; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key0x & KEYMASK_PGUP) + { + key[keys_held++] = KEY_PGUP; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key0x & KEYMASK_PGDN) + { + key[keys_held++] = KEY_PGDN; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key0x & KEYMASK_SCROLLLOCK) + { + key[keys_held++] = KEY_SCROLLLOCK; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key0x & KEYMASK_A) + { + key[keys_held++] = KEY_A; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key0x & KEYMASK_B) + { + key[keys_held++] = KEY_B; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key0x & KEYMASK_C) + { + key[keys_held++] = KEY_C; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key0x & KEYMASK_D) + { + key[keys_held++] = KEY_D; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key0x & KEYMASK_E) + { + key[keys_held++] = KEY_E; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key0x & KEYMASK_F) + { + key[keys_held++] = KEY_F; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key0x & KEYMASK_G) + { + key[keys_held++] = KEY_G; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key0x & KEYMASK_H) + { + key[keys_held++] = KEY_H; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key0x & KEYMASK_I) + { + key[keys_held++] = KEY_I; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key0x & KEYMASK_J) + { + key[keys_held++] = KEY_J; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key0x & KEYMASK_K) + { + key[keys_held++] = KEY_K; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_L) + { + key[keys_held++] = KEY_L; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_M) + { + key[keys_held++] = KEY_M; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_N) + { + key[keys_held++] = KEY_N; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_O) + { + key[keys_held++] = KEY_O; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_P) + { + key[keys_held++] = KEY_P; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_Q) + { + key[keys_held++] = KEY_Q; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_R) + { + key[keys_held++] = KEY_R; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_S) + { + key[keys_held++] = KEY_S; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_T) + { + key[keys_held++] = KEY_T; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_U) + { + key[keys_held++] = KEY_U; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_V) + { + key[keys_held++] = KEY_V; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_W) + { + key[keys_held++] = KEY_W; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_X) + { + key[keys_held++] = KEY_X; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_Y) + { + key[keys_held++] = KEY_Y; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_Z) + { + key[keys_held++] = KEY_Z; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key1x & KEYMASK_1) + { + key[keys_held++] = KEY_1; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_2) + { + key[keys_held++] = KEY_2; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_3) + { + key[keys_held++] = KEY_3; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_4) + { + key[keys_held++] = KEY_4; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_5) + { + key[keys_held++] = KEY_5; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_6) + { + key[keys_held++] = KEY_6; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_7) + { + key[keys_held++] = KEY_7; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_8) + { + key[keys_held++] = KEY_8; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_9) + { + key[keys_held++] = KEY_9; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_0) + { + key[keys_held++] = KEY_0; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_MINUS) + { + key[keys_held++] = KEY_MINUS; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_PLUS) + { + key[keys_held++] = KEY_PLUS; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_PRINTSCR) + { + key[keys_held++] = KEY_PRINTSCR; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_BRACE_OPEN) + { + key[keys_held++] = KEY_BRACE_OPEN; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_BRACE_CLOSE) + { + key[keys_held++] = KEY_BRACE_CLOSE; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_COLON) + { + key[keys_held++] = KEY_COLON; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key2x & KEYMASK_QUOTE) + { + key[keys_held++] = KEY_QUOTE; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_HASH) + { + key[keys_held++] = KEY_HASH; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_COMMA) + { + key[keys_held++] = KEY_COMMA; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_PERIOD) + { + key[keys_held++] = KEY_PERIOD; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_QUESTIONMARK) + { + key[keys_held++] = KEY_QUESTIONMARK; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_INTERNATIONAL1) + { + key[keys_held++] = KEY_INTERNATIONAL1; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_F1) + { + key[keys_held++] = KEY_F1; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_F2) + { + key[keys_held++] = KEY_F2; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_F3) + { + key[keys_held++] = KEY_F3; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_F4) + { + key[keys_held++] = KEY_F4; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_F5) + { + key[keys_held++] = KEY_F5; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_F6) + { + key[keys_held++] = KEY_F6; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_F7) + { + key[keys_held++] = KEY_F7; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_F8) + { + key[keys_held++] = KEY_F8; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_F9) + { + key[keys_held++] = KEY_F9; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_F10) + { + key[keys_held++] = KEY_F10; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key3x & KEYMASK_F11) + { + key[keys_held++] = KEY_F11; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_F12) + { + key[keys_held++] = KEY_F12; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_ESC) + { + key[keys_held++] = KEY_ESC; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_INSERT) + { + key[keys_held++] = KEY_INSERT; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_DELETE) + { + key[keys_held++] = KEY_DELETE; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_TILDE) + { + key[keys_held++] = KEY_TILDE; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_BACKSPACE) + { + key[keys_held++] = KEY_BACKSPACE; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_TAB) + { + key[keys_held++] = KEY_TAB; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_CAPSLOCK) + { + key[keys_held++] = KEY_CAPSLOCK; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_LEFTSHIFT) + { + key[keys_held++] = KEY_LEFTSHIFT; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_RIGHTSHIFT) + { + key[keys_held++] = KEY_RIGHTSHIFT; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_LEFTCONTROL) + { + key[keys_held++] = KEY_LEFTCONTROL; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_RIGHTALT) + { + key[keys_held++] = KEY_RIGHTALT; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_LEFTWINDOWS) + { + key[keys_held++] = KEY_LEFTWINDOWS; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_SPACE) + { + key[keys_held++] = KEY_SPACE; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_RIGHTWINDOWS) + { + key[keys_held++] = KEY_RIGHTWINDOWS; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key4x & KEYMASK_MENU) + { + key[keys_held++] = KEY_MENU; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key5x & KEYMASK_LEFTARROW) + { + key[keys_held++] = KEY_LEFTARROW; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key5x & KEYMASK_DOWNARROW) + { + key[keys_held++] = KEY_DOWNARROW; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key5x & KEYMASK_UPARROW) + { + key[keys_held++] = KEY_UPARROW; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key5x & KEYMASK_RIGHTARROW) + { + key[keys_held++] = KEY_RIGHTARROW; + if (keys_held >= MAX_KEYS_HELD) + return; + } + if (KeyStatus.key5x & KEYMASK_ENTER) + { + key[keys_held++] = KEY_ENTER; + if (keys_held >= MAX_KEYS_HELD) + return; + } } diff --git a/Source/Core/Core/HW/SI_DeviceKeyboard.h b/Source/Core/Core/HW/SI_DeviceKeyboard.h index 79d8f6252c..537fe6e47d 100644 --- a/Source/Core/Core/HW/SI_DeviceKeyboard.h +++ b/Source/Core/Core/HW/SI_DeviceKeyboard.h @@ -12,58 +12,55 @@ struct KeyboardStatus; class CSIDevice_Keyboard : public ISIDevice { protected: + // Commands + enum EBufferCommands + { + CMD_RESET = 0x00, + CMD_DIRECT = 0x54, + CMD_ID = 0xff, + }; - // Commands - enum EBufferCommands - { - CMD_RESET = 0x00, - CMD_DIRECT = 0x54, - CMD_ID = 0xff, - }; + enum EDirectCommands + { + CMD_WRITE = 0x40, + CMD_POLL = 0x54 + }; - enum EDirectCommands - { - CMD_WRITE = 0x40, - CMD_POLL = 0x54 - }; + union UCommand { + u32 Hex; + struct + { + u32 Parameter1 : 8; + u32 Parameter2 : 8; + u32 Command : 8; + u32 : 8; + }; + UCommand() { Hex = 0; } + UCommand(u32 _iValue) { Hex = _iValue; } + }; - union UCommand - { - u32 Hex; - struct - { - u32 Parameter1 : 8; - u32 Parameter2 : 8; - u32 Command : 8; - u32 : 8; - }; - UCommand() {Hex = 0;} - UCommand(u32 _iValue) {Hex = _iValue;} - }; + // PADAnalogMode + u8 m_Mode; - // PADAnalogMode - u8 m_Mode; - - // Internal counter synchonizing GC and keyboard - u8 m_Counter; + // Internal counter synchonizing GC and keyboard + u8 m_Counter; public: + // Constructor + CSIDevice_Keyboard(SIDevices device, int _iDeviceNumber); - // Constructor - CSIDevice_Keyboard(SIDevices device, int _iDeviceNumber); + // Run the SI Buffer + int RunBuffer(u8* _pBuffer, int _iLength) override; - // Run the SI Buffer - int RunBuffer(u8* _pBuffer, int _iLength) override; + // Return true on new data + bool GetData(u32& _Hi, u32& _Low) override; - // Return true on new data - bool GetData(u32& _Hi, u32& _Low) override; + KeyboardStatus GetKeyboardStatus(); + void MapKeys(KeyboardStatus& KeyStatus, u8* key); - KeyboardStatus GetKeyboardStatus(); - void MapKeys(KeyboardStatus& KeyStatus, u8* key); + // Send a command directly + void SendCommand(u32 _Cmd, u8 _Poll) override; - // Send a command directly - void SendCommand(u32 _Cmd, u8 _Poll) override; - - // Savestate support - void DoState(PointerWrap& p) override; + // Savestate support + void DoState(PointerWrap& p) override; }; diff --git a/Source/Core/Core/HW/Sram.cpp b/Source/Core/Core/HW/Sram.cpp index df8c80bd64..4c8884c43d 100644 --- a/Source/Core/Core/HW/Sram.cpp +++ b/Source/Core/Core/HW/Sram.cpp @@ -2,35 +2,17 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/Sram.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Core/ConfigManager.h" -#include "Core/HW/Sram.h" // english -SRAM sram_dump = {{ - 0xFF, 0x6B, - 0x00, 0x91, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0x40, - 0x00, - 0x00, - 0x00, - 0x2C, - 0x44, 0x4F, 0x4C, 0x50, 0x48, 0x49, 0x4E, 0x53, 0x4C, 0x4F, 0x54, 0x41, - 0x44, 0x4F, 0x4C, 0x50, 0x48, 0x49, 0x4E, 0x53, 0x4C, 0x4F, 0x54, 0x42, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, - 0x00, - 0x6E, 0x6D, - 0x00, 0x00, - 0x00, 0x00 -}}; +SRAM sram_dump = {{0xFF, 0x6B, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x2C, 0x44, 0x4F, 0x4C, 0x50, 0x48, 0x49, + 0x4E, 0x53, 0x4C, 0x4F, 0x54, 0x41, 0x44, 0x4F, 0x4C, 0x50, 0x48, 0x49, 0x4E, + 0x53, 0x4C, 0x4F, 0x54, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x6D, 0x00, 0x00, 0x00, 0x00}}; #if 0 // german @@ -61,45 +43,45 @@ SRAM sram_dump_german = {{ void InitSRAM() { - File::IOFile file(SConfig::GetInstance().m_strSRAM, "rb"); - if (file) - { - if (!file.ReadArray(&g_SRAM, 1)) - { - ERROR_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: Could not read all of SRAM"); - g_SRAM = sram_dump; - } - } - else - { - g_SRAM = sram_dump; - } + File::IOFile file(SConfig::GetInstance().m_strSRAM, "rb"); + if (file) + { + if (!file.ReadArray(&g_SRAM, 1)) + { + ERROR_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: Could not read all of SRAM"); + g_SRAM = sram_dump; + } + } + else + { + g_SRAM = sram_dump; + } } void SetCardFlashID(u8* buffer, u8 card_index) { - u64 rand = Common::swap64( *(u64*)&(buffer[12])); - u8 csum=0; - for (int i = 0; i < 12; i++) - { - rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); - csum += g_SRAM.flash_id[card_index][i] = buffer[i] - ((u8)rand&0xff); - rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); - rand &= (u64)0x0000000000007fffULL; - } - g_SRAM.flashID_chksum[card_index] = csum^0xFF; + u64 rand = Common::swap64(*(u64*)&(buffer[12])); + u8 csum = 0; + for (int i = 0; i < 12; i++) + { + rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); + csum += g_SRAM.flash_id[card_index][i] = buffer[i] - ((u8)rand & 0xff); + rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); + rand &= (u64)0x0000000000007fffULL; + } + g_SRAM.flashID_chksum[card_index] = csum ^ 0xFF; } void FixSRAMChecksums() { - u16 checksum = 0; - u16 checksum_inv = 0; - for (int i = 0x0C; i < 0x14; i += 2) - { - int value = (g_SRAM.p_SRAM[i] << 8) + g_SRAM.p_SRAM[i+1]; - checksum += value; - checksum_inv += value ^ 0xFFFF; - } - g_SRAM.checksum = Common::swap16(checksum); - g_SRAM.checksum_inv = Common::swap16(checksum_inv); + u16 checksum = 0; + u16 checksum_inv = 0; + for (int i = 0x0C; i < 0x14; i += 2) + { + int value = (g_SRAM.p_SRAM[i] << 8) + g_SRAM.p_SRAM[i + 1]; + checksum += value; + checksum_inv += value ^ 0xFFFF; + } + g_SRAM.checksum = Common::swap16(checksum); + g_SRAM.checksum_inv = Common::swap16(checksum_inv); } diff --git a/Source/Core/Core/HW/Sram.h b/Source/Core/Core/HW/Sram.h index 83606cf1fc..eb7be1e8ae 100644 --- a/Source/Core/Core/HW/Sram.h +++ b/Source/Core/Core/HW/Sram.h @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // Modified code taken from libogc /*------------------------------------------------------------- @@ -37,45 +36,46 @@ distribution. #include "Common/CommonTypes.h" -#pragma pack(push,1) -union SRAMFlags -{ - u8 Hex; - struct - { - u8 : 2; - u8 sound : 1; // Audio settings; 0 = Mono, 1 = Stereo - u8 initialized : 1; // if 0, displays prompt to set language on boot and asks user to set options and time/date - u8 : 2; - u8 boot_menu : 1; // if 1, skips logo animation and boots into the system menu regardless of if there is a disc inserted - u8 progressive : 1; // if 1, automatically displays Progressive Scan prompt in games that support it - }; +#pragma pack(push, 1) +union SRAMFlags { + u8 Hex; + struct + { + u8 : 2; + u8 sound : 1; // Audio settings; 0 = Mono, 1 = Stereo + u8 initialized : 1; // if 0, displays prompt to set language on boot and asks user to set + // options and time/date + u8 : 2; + u8 boot_menu : 1; // if 1, skips logo animation and boots into the system menu regardless of if + // there is a disc inserted + u8 progressive : 1; // if 1, automatically displays Progressive Scan prompt in games that + // support it + }; }; -union SRAM -{ - u8 p_SRAM[64]; - struct // Stored configuration value from the system SRAM area - { - u16 checksum; // Holds the block checksum. - u16 checksum_inv; // Holds the inverse block checksum - u32 ead0; // Unknown attribute - u32 ead1; // Unknown attribute - u32 counter_bias; // Bias value for the realtime clock - s8 display_offsetH; // Pixel offset for the VI - u8 ntd; // Unknown attribute - u8 lang; // Language of system - SRAMFlags flags; // Device and operations flag +union SRAM { + u8 p_SRAM[64]; + struct // Stored configuration value from the system SRAM area + { + u16 checksum; // Holds the block checksum. + u16 checksum_inv; // Holds the inverse block checksum + u32 ead0; // Unknown attribute + u32 ead1; // Unknown attribute + u32 counter_bias; // Bias value for the realtime clock + s8 display_offsetH; // Pixel offset for the VI + u8 ntd; // Unknown attribute + u8 lang; // Language of system + SRAMFlags flags; // Device and operations flag - // Stored configuration value from the extended SRAM area - u8 flash_id[2][12]; // flash_id[2][12] 96bit memorycard unlock flash ID - u32 wirelessKbd_id; // Device ID of last connected wireless keyboard - u16 wirelessPad_id[4]; // 16-bit device ID of last connected pad. - u8 dvderr_code; // last non-recoverable error from DVD interface - u8 __padding0; // reserved - u8 flashID_chksum[2]; // 8-bit checksum of unlock flash ID - u32 __padding1; // padding - }; + // Stored configuration value from the extended SRAM area + u8 flash_id[2][12]; // flash_id[2][12] 96bit memorycard unlock flash ID + u32 wirelessKbd_id; // Device ID of last connected wireless keyboard + u16 wirelessPad_id[4]; // 16-bit device ID of last connected pad. + u8 dvderr_code; // last non-recoverable error from DVD interface + u8 __padding0; // reserved + u8 flashID_chksum[2]; // 8-bit checksum of unlock flash ID + u32 __padding1; // padding + }; }; #pragma pack(pop) void InitSRAM(); diff --git a/Source/Core/Core/HW/StreamADPCM.cpp b/Source/Core/Core/HW/StreamADPCM.cpp index c142f39749..be130adc84 100644 --- a/Source/Core/Core/HW/StreamADPCM.cpp +++ b/Source/Core/Core/HW/StreamADPCM.cpp @@ -4,13 +4,12 @@ // Adapted from in_cube by hcs & destop +#include "Core/HW/StreamADPCM.h" #include "Common/CommonTypes.h" #include "Common/MathUtil.h" -#include "Core/HW/StreamADPCM.h" namespace StreamADPCM { - // STATE_TO_SAVE (not saved yet!) static s32 histl1; static s32 histl2; @@ -19,50 +18,51 @@ static s32 histr2; static s16 ADPDecodeSample(s32 bits, s32 q, s32& hist1, s32& hist2) { - s32 hist = 0; - switch (q >> 4) - { - case 0: - hist = 0; - break; - case 1: - hist = (hist1 * 0x3c); - break; - case 2: - hist = (hist1 * 0x73) - (hist2 * 0x34); - break; - case 3: - hist = (hist1 * 0x62) - (hist2 * 0x37); - break; - } - hist = MathUtil::Clamp((hist + 0x20) >> 6, -0x200000, 0x1fffff); + s32 hist = 0; + switch (q >> 4) + { + case 0: + hist = 0; + break; + case 1: + hist = (hist1 * 0x3c); + break; + case 2: + hist = (hist1 * 0x73) - (hist2 * 0x34); + break; + case 3: + hist = (hist1 * 0x62) - (hist2 * 0x37); + break; + } + hist = MathUtil::Clamp((hist + 0x20) >> 6, -0x200000, 0x1fffff); - s32 cur = (((s16)(bits << 12) >> (q & 0xf)) << 6) + hist; + s32 cur = (((s16)(bits << 12) >> (q & 0xf)) << 6) + hist; - hist2 = hist1; - hist1 = cur; + hist2 = hist1; + hist1 = cur; - cur >>= 6; - cur = MathUtil::Clamp(cur, -0x8000, 0x7fff); + cur >>= 6; + cur = MathUtil::Clamp(cur, -0x8000, 0x7fff); - return (s16)cur; + return (s16)cur; } void InitFilter() { - histl1 = 0; - histl2 = 0; - histr1 = 0; - histr2 = 0; + histl1 = 0; + histl2 = 0; + histr1 = 0; + histr2 = 0; } void DecodeBlock(s16* pcm, const u8* adpcm) { - for (int i = 0; i < SAMPLES_PER_BLOCK; i++) - { - pcm[i * 2] = ADPDecodeSample(adpcm[i + (ONE_BLOCK_SIZE - SAMPLES_PER_BLOCK)] & 0xf, adpcm[0], histl1, histl2); - pcm[i * 2 + 1] = ADPDecodeSample(adpcm[i + (ONE_BLOCK_SIZE - SAMPLES_PER_BLOCK)] >> 4, adpcm[1], histr1, histr2); - } + for (int i = 0; i < SAMPLES_PER_BLOCK; i++) + { + pcm[i * 2] = ADPDecodeSample(adpcm[i + (ONE_BLOCK_SIZE - SAMPLES_PER_BLOCK)] & 0xf, adpcm[0], + histl1, histl2); + pcm[i * 2 + 1] = ADPDecodeSample(adpcm[i + (ONE_BLOCK_SIZE - SAMPLES_PER_BLOCK)] >> 4, adpcm[1], + histr1, histr2); + } } - } diff --git a/Source/Core/Core/HW/StreamADPCM.h b/Source/Core/Core/HW/StreamADPCM.h index 11577b8693..69daf227f0 100644 --- a/Source/Core/Core/HW/StreamADPCM.h +++ b/Source/Core/Core/HW/StreamADPCM.h @@ -10,14 +10,12 @@ namespace StreamADPCM { - enum { - ONE_BLOCK_SIZE = 32, - SAMPLES_PER_BLOCK = 28 + ONE_BLOCK_SIZE = 32, + SAMPLES_PER_BLOCK = 28 }; void InitFilter(); void DecodeBlock(s16* pcm, const u8* adpcm); - } diff --git a/Source/Core/Core/HW/SystemTimers.cpp b/Source/Core/Core/HW/SystemTimers.cpp index 7ea8eaed0e..cda4e32b98 100644 --- a/Source/Core/Core/HW/SystemTimers.cpp +++ b/Source/Core/Core/HW/SystemTimers.cpp @@ -4,7 +4,8 @@ // This file controls all system timers -/* (shuffle2) I don't know who wrote this, but take it with salt. For starters, "time" is contextual... +/* (shuffle2) I don't know who wrote this, but take it with salt. For starters, "time" is +contextual... "Time" is measured in frames, not time: These update frequencies are determined by the passage of frames. So if a game runs slow, on a slow computer for example, these updates will occur less frequently. This makes sense because almost all console games are controlled by frames @@ -25,54 +26,53 @@ frame. IPC_HLE_PERIOD: For the Wiimote this is the call schedule: - IPC_HLE_UpdateCallback() // In this file + IPC_HLE_UpdateCallback() // In this file - // This function seems to call all devices' Update() function four times per frame - WII_IPC_HLE_Interface::Update() + // This function seems to call all devices' Update() function four times per frame + WII_IPC_HLE_Interface::Update() - // If the AclFrameQue is empty this will call Wiimote_Update() and make it send - the current input status to the game. I'm not sure if this occurs approximately - once every frame or if the frequency is not exactly tied to rendered frames - CWII_IPC_HLE_Device_usb_oh1_57e_305::Update() - PluginWiimote::Wiimote_Update() + // If the AclFrameQue is empty this will call Wiimote_Update() and make it send + the current input status to the game. I'm not sure if this occurs approximately + once every frame or if the frequency is not exactly tied to rendered frames + CWII_IPC_HLE_Device_usb_oh1_57e_305::Update() + PluginWiimote::Wiimote_Update() - // This is also a device updated by WII_IPC_HLE_Interface::Update() but it doesn't - seem to ultimately call PluginWiimote::Wiimote_Update(). However it can be called - by the /dev/usb/oh1 device if the AclFrameQue is empty. - CWII_IPC_HLE_WiiMote::Update() + // This is also a device updated by WII_IPC_HLE_Interface::Update() but it doesn't + seem to ultimately call PluginWiimote::Wiimote_Update(). However it can be called + by the /dev/usb/oh1 device if the AclFrameQue is empty. + CWII_IPC_HLE_WiiMote::Update() */ +#include "Core/HW/SystemTimers.h" #include "Common/Atomic.h" #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/Thread.h" #include "Common/Timer.h" -#include "Common/Logging/Log.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" #include "Core/DSPEmulator.h" -#include "Core/PatchEngine.h" #include "Core/HW/AudioInterface.h" #include "Core/HW/DSP.h" #include "Core/HW/EXI_DeviceIPL.h" -#include "Core/HW/SystemTimers.h" #include "Core/HW/VideoInterface.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" +#include "Core/PatchEngine.h" #include "Core/PowerPC/PowerPC.h" #include "VideoCommon/Fifo.h" namespace SystemTimers { - static int et_Dec; static int et_VI; static int et_AudioDMA; static int et_DSP; static int et_IPC_HLE; -static int et_PatchEngine; // PatchEngine updates every 1/60th of a second by default +static int et_PatchEngine; // PatchEngine updates every 1/60th of a second by default static int et_Throttle; -static u32 s_cpu_core_clock = 486000000u; // 486 mhz (its not 485, stop bugging me!) +static u32 s_cpu_core_clock = 486000000u; // 486 mhz (its not 485, stop bugging me!) // These two are badly educated guesses. // Feel free to experiment. Set them in Init below. @@ -83,169 +83,172 @@ static int s_audio_dma_period; // we can just increase this number. static int s_ipc_hle_period; - - u32 GetTicksPerSecond() { - return s_cpu_core_clock; + return s_cpu_core_clock; } // DSP/CPU timeslicing. static void DSPCallback(u64 userdata, s64 cyclesLate) { - //splits up the cycle budget in case lle is used - //for hle, just gives all of the slice to hle - DSP::UpdateDSPSlice(static_cast(DSP::GetDSPEmulator()->DSP_UpdateRate() - cyclesLate)); - CoreTiming::ScheduleEvent(DSP::GetDSPEmulator()->DSP_UpdateRate() - cyclesLate, et_DSP); + // splits up the cycle budget in case lle is used + // for hle, just gives all of the slice to hle + DSP::UpdateDSPSlice(static_cast(DSP::GetDSPEmulator()->DSP_UpdateRate() - cyclesLate)); + CoreTiming::ScheduleEvent(DSP::GetDSPEmulator()->DSP_UpdateRate() - cyclesLate, et_DSP); } static void AudioDMACallback(u64 userdata, s64 cyclesLate) { - int period = s_cpu_core_clock / (AudioInterface::GetAIDSampleRate() * 4 / 32); - DSP::UpdateAudioDMA(); // Push audio to speakers. - CoreTiming::ScheduleEvent(period - cyclesLate, et_AudioDMA); + int period = s_cpu_core_clock / (AudioInterface::GetAIDSampleRate() * 4 / 32); + DSP::UpdateAudioDMA(); // Push audio to speakers. + CoreTiming::ScheduleEvent(period - cyclesLate, et_AudioDMA); } static void IPC_HLE_UpdateCallback(u64 userdata, s64 cyclesLate) { - if (SConfig::GetInstance().bWii) - { - WII_IPC_HLE_Interface::UpdateDevices(); - CoreTiming::ScheduleEvent(s_ipc_hle_period - cyclesLate, et_IPC_HLE); - } + if (SConfig::GetInstance().bWii) + { + WII_IPC_HLE_Interface::UpdateDevices(); + CoreTiming::ScheduleEvent(s_ipc_hle_period - cyclesLate, et_IPC_HLE); + } } static void VICallback(u64 userdata, s64 cyclesLate) { - VideoInterface::Update(); - CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerHalfLine() - cyclesLate, et_VI); + VideoInterface::Update(); + CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerHalfLine() - cyclesLate, et_VI); } static void DecrementerCallback(u64 userdata, s64 cyclesLate) { - PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF; - PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER; + PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF; + PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER; } void DecrementerSet() { - u32 decValue = PowerPC::ppcState.spr[SPR_DEC]; + u32 decValue = PowerPC::ppcState.spr[SPR_DEC]; - CoreTiming::RemoveEvent(et_Dec); - if ((decValue & 0x80000000) == 0) - { - CoreTiming::SetFakeDecStartTicks(CoreTiming::GetTicks()); - CoreTiming::SetFakeDecStartValue(decValue); + CoreTiming::RemoveEvent(et_Dec); + if ((decValue & 0x80000000) == 0) + { + CoreTiming::SetFakeDecStartTicks(CoreTiming::GetTicks()); + CoreTiming::SetFakeDecStartValue(decValue); - CoreTiming::ScheduleEvent(decValue * TIMER_RATIO, et_Dec); - } + CoreTiming::ScheduleEvent(decValue * TIMER_RATIO, et_Dec); + } } u32 GetFakeDecrementer() { - return (CoreTiming::GetFakeDecStartValue() - (u32)((CoreTiming::GetTicks() - CoreTiming::GetFakeDecStartTicks()) / TIMER_RATIO)); + return (CoreTiming::GetFakeDecStartValue() - + (u32)((CoreTiming::GetTicks() - CoreTiming::GetFakeDecStartTicks()) / TIMER_RATIO)); } void TimeBaseSet() { - CoreTiming::SetFakeTBStartTicks(CoreTiming::GetTicks()); - CoreTiming::SetFakeTBStartValue(*((u64 *)&TL)); + CoreTiming::SetFakeTBStartTicks(CoreTiming::GetTicks()); + CoreTiming::SetFakeTBStartValue(*((u64*)&TL)); } u64 GetFakeTimeBase() { - return CoreTiming::GetFakeTBStartValue() + ((CoreTiming::GetTicks() - CoreTiming::GetFakeTBStartTicks()) / TIMER_RATIO); + return CoreTiming::GetFakeTBStartValue() + + ((CoreTiming::GetTicks() - CoreTiming::GetFakeTBStartTicks()) / TIMER_RATIO); } static void PatchEngineCallback(u64 userdata, s64 cyclesLate) { - // Patch mem and run the Action Replay - PatchEngine::ApplyFramePatches(); - CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerField() - cyclesLate, et_PatchEngine); + // Patch mem and run the Action Replay + PatchEngine::ApplyFramePatches(); + CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerField() - cyclesLate, et_PatchEngine); } static void ThrottleCallback(u64 last_time, s64 cyclesLate) { - // Allow the GPU thread to sleep. Setting this flag here limits the wakeups to 1 kHz. - Fifo::GpuMaySleep(); + // Allow the GPU thread to sleep. Setting this flag here limits the wakeups to 1 kHz. + Fifo::GpuMaySleep(); - u32 time = Common::Timer::GetTimeMs(); + u32 time = Common::Timer::GetTimeMs(); - int diff = (u32)last_time - time; - const SConfig& config = SConfig::GetInstance(); - bool frame_limiter = config.m_EmulationSpeed > 0.0f && !Core::GetIsThrottlerTempDisabled(); - u32 next_event = GetTicksPerSecond()/1000; - if (frame_limiter) - { - if (config.m_EmulationSpeed != 1.0f) - next_event = u32(next_event * config.m_EmulationSpeed); - const int max_fallback = config.iTimingVariance; - if (abs(diff) > max_fallback) - { - DEBUG_LOG(COMMON, "system too %s, %d ms skipped", diff<0 ? "slow" : "fast", abs(diff) - max_fallback); - last_time = time - max_fallback; - } - else if (diff > 0) - Common::SleepCurrentThread(diff); - } - CoreTiming::ScheduleEvent(next_event - cyclesLate, et_Throttle, last_time + 1); + int diff = (u32)last_time - time; + const SConfig& config = SConfig::GetInstance(); + bool frame_limiter = config.m_EmulationSpeed > 0.0f && !Core::GetIsThrottlerTempDisabled(); + u32 next_event = GetTicksPerSecond() / 1000; + if (frame_limiter) + { + if (config.m_EmulationSpeed != 1.0f) + next_event = u32(next_event * config.m_EmulationSpeed); + const int max_fallback = config.iTimingVariance; + if (abs(diff) > max_fallback) + { + DEBUG_LOG(COMMON, "system too %s, %d ms skipped", diff < 0 ? "slow" : "fast", + abs(diff) - max_fallback); + last_time = time - max_fallback; + } + else if (diff > 0) + Common::SleepCurrentThread(diff); + } + CoreTiming::ScheduleEvent(next_event - cyclesLate, et_Throttle, last_time + 1); } -// split from Init to break a circular dependency between VideoInterface::Init and SystemTimers::Init +// split from Init to break a circular dependency between VideoInterface::Init and +// SystemTimers::Init void PreInit() { - if (SConfig::GetInstance().bWii) - s_cpu_core_clock = 729000000u; - else - s_cpu_core_clock = 486000000u; + if (SConfig::GetInstance().bWii) + s_cpu_core_clock = 729000000u; + else + s_cpu_core_clock = 486000000u; } void Init() { - if (SConfig::GetInstance().bWii) - { - // AyuanX: TO BE TWEAKED - // Now the 1500 is a pure assumption - // We need to figure out the real frequency though + if (SConfig::GetInstance().bWii) + { + // AyuanX: TO BE TWEAKED + // Now the 1500 is a pure assumption + // We need to figure out the real frequency though - // FYI, WII_IPC_HLE_Interface::Update is also called in WII_IPCInterface::Write32 - const int freq = 1500; - s_ipc_hle_period = GetTicksPerSecond() / freq; - } + // FYI, WII_IPC_HLE_Interface::Update is also called in WII_IPCInterface::Write32 + const int freq = 1500; + s_ipc_hle_period = GetTicksPerSecond() / freq; + } - // System internal sample rate is fixed at 32KHz * 4 (16bit Stereo) / 32 bytes DMA - s_audio_dma_period = s_cpu_core_clock / (AudioInterface::GetAIDSampleRate() * 4 / 32); + // System internal sample rate is fixed at 32KHz * 4 (16bit Stereo) / 32 bytes DMA + s_audio_dma_period = s_cpu_core_clock / (AudioInterface::GetAIDSampleRate() * 4 / 32); - Common::Timer::IncreaseResolution(); - // store and convert localtime at boot to timebase ticks - CoreTiming::SetFakeTBStartValue((u64)(s_cpu_core_clock / TIMER_RATIO) * (u64)CEXIIPL::GetGCTime()); - CoreTiming::SetFakeTBStartTicks(CoreTiming::GetTicks()); + Common::Timer::IncreaseResolution(); + // store and convert localtime at boot to timebase ticks + CoreTiming::SetFakeTBStartValue((u64)(s_cpu_core_clock / TIMER_RATIO) * + (u64)CEXIIPL::GetGCTime()); + CoreTiming::SetFakeTBStartTicks(CoreTiming::GetTicks()); - CoreTiming::SetFakeDecStartValue(0xFFFFFFFF); - CoreTiming::SetFakeDecStartTicks(CoreTiming::GetTicks()); + CoreTiming::SetFakeDecStartValue(0xFFFFFFFF); + CoreTiming::SetFakeDecStartTicks(CoreTiming::GetTicks()); - et_Dec = CoreTiming::RegisterEvent("DecCallback", DecrementerCallback); - et_VI = CoreTiming::RegisterEvent("VICallback", VICallback); - et_DSP = CoreTiming::RegisterEvent("DSPCallback", DSPCallback); - et_AudioDMA = CoreTiming::RegisterEvent("AudioDMACallback", AudioDMACallback); - et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback); - et_PatchEngine = CoreTiming::RegisterEvent("PatchEngine", PatchEngineCallback); - et_Throttle = CoreTiming::RegisterEvent("Throttle", ThrottleCallback); + et_Dec = CoreTiming::RegisterEvent("DecCallback", DecrementerCallback); + et_VI = CoreTiming::RegisterEvent("VICallback", VICallback); + et_DSP = CoreTiming::RegisterEvent("DSPCallback", DSPCallback); + et_AudioDMA = CoreTiming::RegisterEvent("AudioDMACallback", AudioDMACallback); + et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback); + et_PatchEngine = CoreTiming::RegisterEvent("PatchEngine", PatchEngineCallback); + et_Throttle = CoreTiming::RegisterEvent("Throttle", ThrottleCallback); - CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerHalfLine(), et_VI); - CoreTiming::ScheduleEvent(0, et_DSP); - CoreTiming::ScheduleEvent(s_audio_dma_period, et_AudioDMA); - CoreTiming::ScheduleEvent(0, et_Throttle, Common::Timer::GetTimeMs()); + CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerHalfLine(), et_VI); + CoreTiming::ScheduleEvent(0, et_DSP); + CoreTiming::ScheduleEvent(s_audio_dma_period, et_AudioDMA); + CoreTiming::ScheduleEvent(0, et_Throttle, Common::Timer::GetTimeMs()); - CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerField(), et_PatchEngine); + CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerField(), et_PatchEngine); - if (SConfig::GetInstance().bWii) - CoreTiming::ScheduleEvent(s_ipc_hle_period, et_IPC_HLE); + if (SConfig::GetInstance().bWii) + CoreTiming::ScheduleEvent(s_ipc_hle_period, et_IPC_HLE); } void Shutdown() { - Common::Timer::RestoreResolution(); + Common::Timer::RestoreResolution(); } } // namespace diff --git a/Source/Core/Core/HW/SystemTimers.h b/Source/Core/Core/HW/SystemTimers.h index d8f3ef8519..18b7557658 100644 --- a/Source/Core/Core/HW/SystemTimers.h +++ b/Source/Core/Core/HW/SystemTimers.h @@ -8,7 +8,6 @@ namespace SystemTimers { - /* GameCube MHz flipper <-> ARAM bus: 81 (DSP) @@ -31,7 +30,7 @@ broadway: 729 enum { - TIMER_RATIO = 12 + TIMER_RATIO = 12 }; u32 GetTicksPerSecond(); @@ -45,5 +44,4 @@ u32 GetFakeDecrementer(); void TimeBaseSet(); u64 GetFakeTimeBase(); - } diff --git a/Source/Core/Core/HW/VideoInterface.cpp b/Source/Core/Core/HW/VideoInterface.cpp index c2bea06ee4..9af668f053 100644 --- a/Source/Core/Core/HW/VideoInterface.cpp +++ b/Source/Core/Core/HW/VideoInterface.cpp @@ -6,8 +6,8 @@ #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" -#include "Common/MathUtil.h" #include "Common/Logging/Log.h" +#include "Common/MathUtil.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" @@ -21,562 +21,540 @@ namespace VideoInterface { - // STATE_TO_SAVE // Registers listed in order: static UVIVerticalTimingRegister m_VerticalTimingRegister; static UVIDisplayControlRegister m_DisplayControlRegister; -static UVIHorizontalTiming0 m_HTiming0; -static UVIHorizontalTiming1 m_HTiming1; -static UVIVBlankTimingRegister m_VBlankTimingOdd; -static UVIVBlankTimingRegister m_VBlankTimingEven; -static UVIBurstBlankingRegister m_BurstBlankingOdd; -static UVIBurstBlankingRegister m_BurstBlankingEven; -static UVIFBInfoRegister m_XFBInfoTop; -static UVIFBInfoRegister m_XFBInfoBottom; -static UVIFBInfoRegister m_3DFBInfoTop; // Start making your stereoscopic demos! :p -static UVIFBInfoRegister m_3DFBInfoBottom; -static UVIInterruptRegister m_InterruptRegister[4]; -static UVILatchRegister m_LatchRegister[2]; -static PictureConfigurationRegister m_PictureConfiguration; -static UVIHorizontalScaling m_HorizontalScaling; -static SVIFilterCoefTables m_FilterCoefTables; -static u32 m_UnkAARegister = 0;// ??? 0x00FF0000 -static u16 m_Clock = 0; // 0: 27MHz, 1: 54MHz -static UVIDTVStatus m_DTVStatus; -static UVIHorizontalStepping m_FBWidth; // Only correct when scaling is enabled? -static UVIBorderBlankRegister m_BorderHBlank; +static UVIHorizontalTiming0 m_HTiming0; +static UVIHorizontalTiming1 m_HTiming1; +static UVIVBlankTimingRegister m_VBlankTimingOdd; +static UVIVBlankTimingRegister m_VBlankTimingEven; +static UVIBurstBlankingRegister m_BurstBlankingOdd; +static UVIBurstBlankingRegister m_BurstBlankingEven; +static UVIFBInfoRegister m_XFBInfoTop; +static UVIFBInfoRegister m_XFBInfoBottom; +static UVIFBInfoRegister m_3DFBInfoTop; // Start making your stereoscopic demos! :p +static UVIFBInfoRegister m_3DFBInfoBottom; +static UVIInterruptRegister m_InterruptRegister[4]; +static UVILatchRegister m_LatchRegister[2]; +static PictureConfigurationRegister m_PictureConfiguration; +static UVIHorizontalScaling m_HorizontalScaling; +static SVIFilterCoefTables m_FilterCoefTables; +static u32 m_UnkAARegister = 0; // ??? 0x00FF0000 +static u16 m_Clock = 0; // 0: 27MHz, 1: 54MHz +static UVIDTVStatus m_DTVStatus; +static UVIHorizontalStepping m_FBWidth; // Only correct when scaling is enabled? +static UVIBorderBlankRegister m_BorderHBlank; // 0xcc002076 - 0xcc00207f is full of 0x00FF: unknown // 0xcc002080 - 0xcc002100 even more unknown static u32 s_target_refresh_rate = 0; -static u32 s_clock_freqs[2] = -{ - 27000000UL, - 54000000UL, +static u32 s_clock_freqs[2] = { + 27000000UL, 54000000UL, }; static u64 s_ticks_last_line_start; // number of ticks when the current full scanline started -static u32 s_half_line_count; // number of halflines that have occurred for this full frame -static u32 s_half_line_of_next_si_poll; // halfline when next SI poll results should be available -static constexpr u32 num_half_lines_for_si_poll = (7 * 2) + 1; // this is how long an SI poll takes +static u32 s_half_line_count; // number of halflines that have occurred for this full frame +static u32 s_half_line_of_next_si_poll; // halfline when next SI poll results should be available +static constexpr u32 num_half_lines_for_si_poll = (7 * 2) + 1; // this is how long an SI poll takes static FieldType s_current_field; // below indexes are 1-based -static u32 s_even_field_first_hl; // index first halfline of the even field -static u32 s_odd_field_first_hl; // index first halfline of the odd field -static u32 s_even_field_last_hl; // index last halfline of the even field -static u32 s_odd_field_last_hl; // index last halfline of the odd field +static u32 s_even_field_first_hl; // index first halfline of the even field +static u32 s_odd_field_first_hl; // index first halfline of the odd field +static u32 s_even_field_last_hl; // index last halfline of the even field +static u32 s_odd_field_last_hl; // index last halfline of the odd field -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - p.DoPOD(m_VerticalTimingRegister); - p.DoPOD(m_DisplayControlRegister); - p.Do(m_HTiming0); - p.Do(m_HTiming1); - p.Do(m_VBlankTimingOdd); - p.Do(m_VBlankTimingEven); - p.Do(m_BurstBlankingOdd); - p.Do(m_BurstBlankingEven); - p.Do(m_XFBInfoTop); - p.Do(m_XFBInfoBottom); - p.Do(m_3DFBInfoTop); - p.Do(m_3DFBInfoBottom); - p.DoArray(m_InterruptRegister); - p.DoArray(m_LatchRegister); - p.Do(m_PictureConfiguration); - p.DoPOD(m_HorizontalScaling); - p.Do(m_FilterCoefTables); - p.Do(m_UnkAARegister); - p.Do(m_Clock); - p.Do(m_DTVStatus); - p.Do(m_FBWidth); - p.Do(m_BorderHBlank); - p.Do(s_target_refresh_rate); - p.Do(s_ticks_last_line_start); - p.Do(s_half_line_count); - p.Do(s_half_line_of_next_si_poll); - p.Do(s_current_field); - p.Do(s_even_field_first_hl); - p.Do(s_odd_field_first_hl); - p.Do(s_even_field_last_hl); - p.Do(s_odd_field_last_hl); + p.DoPOD(m_VerticalTimingRegister); + p.DoPOD(m_DisplayControlRegister); + p.Do(m_HTiming0); + p.Do(m_HTiming1); + p.Do(m_VBlankTimingOdd); + p.Do(m_VBlankTimingEven); + p.Do(m_BurstBlankingOdd); + p.Do(m_BurstBlankingEven); + p.Do(m_XFBInfoTop); + p.Do(m_XFBInfoBottom); + p.Do(m_3DFBInfoTop); + p.Do(m_3DFBInfoBottom); + p.DoArray(m_InterruptRegister); + p.DoArray(m_LatchRegister); + p.Do(m_PictureConfiguration); + p.DoPOD(m_HorizontalScaling); + p.Do(m_FilterCoefTables); + p.Do(m_UnkAARegister); + p.Do(m_Clock); + p.Do(m_DTVStatus); + p.Do(m_FBWidth); + p.Do(m_BorderHBlank); + p.Do(s_target_refresh_rate); + p.Do(s_ticks_last_line_start); + p.Do(s_half_line_count); + p.Do(s_half_line_of_next_si_poll); + p.Do(s_current_field); + p.Do(s_even_field_first_hl); + p.Do(s_odd_field_first_hl); + p.Do(s_even_field_last_hl); + p.Do(s_odd_field_last_hl); } // Executed after Init, before game boot void Preset(bool _bNTSC) { - // NOTE: Make sure all registers are set to the correct initial state. The - // variables are not going to start zeroed if another game has been run - // previously (and mutated everything). + // NOTE: Make sure all registers are set to the correct initial state. The + // variables are not going to start zeroed if another game has been run + // previously (and mutated everything). - m_VerticalTimingRegister.EQU = 6; - m_VerticalTimingRegister.ACV = 0; + m_VerticalTimingRegister.EQU = 6; + m_VerticalTimingRegister.ACV = 0; - m_DisplayControlRegister.ENB = 1; - m_DisplayControlRegister.RST = 0; - m_DisplayControlRegister.NIN = 0; - m_DisplayControlRegister.DLR = 0; - m_DisplayControlRegister.LE0 = 0; - m_DisplayControlRegister.LE1 = 0; - m_DisplayControlRegister.FMT = _bNTSC ? 0 : 1; + m_DisplayControlRegister.ENB = 1; + m_DisplayControlRegister.RST = 0; + m_DisplayControlRegister.NIN = 0; + m_DisplayControlRegister.DLR = 0; + m_DisplayControlRegister.LE0 = 0; + m_DisplayControlRegister.LE1 = 0; + m_DisplayControlRegister.FMT = _bNTSC ? 0 : 1; - m_HTiming0.HLW = 429; - m_HTiming0.HCE = 105; - m_HTiming0.HCS = 71; - m_HTiming1.HSY = 64; - m_HTiming1.HBE640 = 162; - m_HTiming1.HBS640 = 373; + m_HTiming0.HLW = 429; + m_HTiming0.HCE = 105; + m_HTiming0.HCS = 71; + m_HTiming1.HSY = 64; + m_HTiming1.HBE640 = 162; + m_HTiming1.HBS640 = 373; - m_VBlankTimingOdd.PRB = 502; - m_VBlankTimingOdd.PSB = 5; - m_VBlankTimingEven.PRB = 503; - m_VBlankTimingEven.PSB = 4; + m_VBlankTimingOdd.PRB = 502; + m_VBlankTimingOdd.PSB = 5; + m_VBlankTimingEven.PRB = 503; + m_VBlankTimingEven.PSB = 4; - m_BurstBlankingOdd.BS0 = 12; - m_BurstBlankingOdd.BE0 = 520; - m_BurstBlankingOdd.BS2 = 12; - m_BurstBlankingOdd.BE2 = 520; - m_BurstBlankingEven.BS0 = 13; - m_BurstBlankingEven.BE0 = 519; - m_BurstBlankingEven.BS2 = 13; - m_BurstBlankingEven.BE2 = 519; + m_BurstBlankingOdd.BS0 = 12; + m_BurstBlankingOdd.BE0 = 520; + m_BurstBlankingOdd.BS2 = 12; + m_BurstBlankingOdd.BE2 = 520; + m_BurstBlankingEven.BS0 = 13; + m_BurstBlankingEven.BE0 = 519; + m_BurstBlankingEven.BS2 = 13; + m_BurstBlankingEven.BE2 = 519; - m_XFBInfoTop.Hex = 0; - m_XFBInfoBottom.Hex = 0; - m_3DFBInfoTop.Hex = 0; - m_3DFBInfoBottom.Hex = 0; + m_XFBInfoTop.Hex = 0; + m_XFBInfoBottom.Hex = 0; + m_3DFBInfoTop.Hex = 0; + m_3DFBInfoBottom.Hex = 0; - m_InterruptRegister[0].HCT = 430; - m_InterruptRegister[0].VCT = 263; - m_InterruptRegister[0].IR_MASK = 1; - m_InterruptRegister[0].IR_INT = 0; - m_InterruptRegister[1].HCT = 1; - m_InterruptRegister[1].VCT = 1; - m_InterruptRegister[1].IR_MASK = 1; - m_InterruptRegister[1].IR_INT = 0; - m_InterruptRegister[2].Hex = 0; - m_InterruptRegister[3].Hex = 0; + m_InterruptRegister[0].HCT = 430; + m_InterruptRegister[0].VCT = 263; + m_InterruptRegister[0].IR_MASK = 1; + m_InterruptRegister[0].IR_INT = 0; + m_InterruptRegister[1].HCT = 1; + m_InterruptRegister[1].VCT = 1; + m_InterruptRegister[1].IR_MASK = 1; + m_InterruptRegister[1].IR_INT = 0; + m_InterruptRegister[2].Hex = 0; + m_InterruptRegister[3].Hex = 0; - m_LatchRegister[0].Hex = 0; - m_LatchRegister[1].Hex = 0; + m_LatchRegister[0].Hex = 0; + m_LatchRegister[1].Hex = 0; - m_PictureConfiguration.STD = 40; - m_PictureConfiguration.WPL = 40; + m_PictureConfiguration.STD = 40; + m_PictureConfiguration.WPL = 40; - m_HorizontalScaling.Hex = 0; - m_FilterCoefTables = {}; - m_UnkAARegister = 0; + m_HorizontalScaling.Hex = 0; + m_FilterCoefTables = {}; + m_UnkAARegister = 0; - // 54MHz, capable of progressive scan - m_Clock = SConfig::GetInstance().bNTSC; + // 54MHz, capable of progressive scan + m_Clock = SConfig::GetInstance().bNTSC; - // Say component cable is plugged - m_DTVStatus.component_plugged = SConfig::GetInstance().bProgressive; - m_DTVStatus.ntsc_j = SConfig::GetInstance().bForceNTSCJ; + // Say component cable is plugged + m_DTVStatus.component_plugged = SConfig::GetInstance().bProgressive; + m_DTVStatus.ntsc_j = SConfig::GetInstance().bForceNTSCJ; - m_FBWidth.Hex = 0; - m_BorderHBlank.Hex = 0; + m_FBWidth.Hex = 0; + m_BorderHBlank.Hex = 0; - s_ticks_last_line_start = 0; - s_half_line_count = 1; - s_half_line_of_next_si_poll = num_half_lines_for_si_poll; // first sampling starts at vsync - s_current_field = FIELD_ODD; + s_ticks_last_line_start = 0; + s_half_line_count = 1; + s_half_line_of_next_si_poll = num_half_lines_for_si_poll; // first sampling starts at vsync + s_current_field = FIELD_ODD; - UpdateParameters(); + UpdateParameters(); } void Init() { - Preset(true); + Preset(true); } void RegisterMMIO(MMIO::Mapping* mmio, u32 base) { - struct { - u32 addr; - u16* ptr; - } directly_mapped_vars[] = { - { VI_VERTICAL_TIMING, &m_VerticalTimingRegister.Hex }, - { VI_HORIZONTAL_TIMING_0_HI, &m_HTiming0.Hi }, - { VI_HORIZONTAL_TIMING_0_LO, &m_HTiming0.Lo }, - { VI_HORIZONTAL_TIMING_1_HI, &m_HTiming1.Hi }, - { VI_HORIZONTAL_TIMING_1_LO, &m_HTiming1.Lo }, - { VI_VBLANK_TIMING_ODD_HI, &m_VBlankTimingOdd.Hi }, - { VI_VBLANK_TIMING_ODD_LO, &m_VBlankTimingOdd.Lo }, - { VI_VBLANK_TIMING_EVEN_HI, &m_VBlankTimingEven.Hi }, - { VI_VBLANK_TIMING_EVEN_LO, &m_VBlankTimingEven.Lo }, - { VI_BURST_BLANKING_ODD_HI, &m_BurstBlankingOdd.Hi }, - { VI_BURST_BLANKING_ODD_LO, &m_BurstBlankingOdd.Lo }, - { VI_BURST_BLANKING_EVEN_HI, &m_BurstBlankingEven.Hi }, - { VI_BURST_BLANKING_EVEN_LO, &m_BurstBlankingEven.Lo }, - { VI_FB_LEFT_TOP_LO, &m_XFBInfoTop.Lo }, - { VI_FB_RIGHT_TOP_LO, &m_3DFBInfoTop.Lo }, - { VI_FB_LEFT_BOTTOM_LO, &m_XFBInfoBottom.Lo }, - { VI_FB_RIGHT_BOTTOM_LO, &m_3DFBInfoBottom.Lo }, - { VI_PRERETRACE_LO, &m_InterruptRegister[0].Lo }, - { VI_POSTRETRACE_LO, &m_InterruptRegister[1].Lo }, - { VI_DISPLAY_INTERRUPT_2_LO, &m_InterruptRegister[2].Lo }, - { VI_DISPLAY_INTERRUPT_3_LO, &m_InterruptRegister[3].Lo }, - { VI_DISPLAY_LATCH_0_HI, &m_LatchRegister[0].Hi }, - { VI_DISPLAY_LATCH_0_LO, &m_LatchRegister[0].Lo }, - { VI_DISPLAY_LATCH_1_HI, &m_LatchRegister[1].Hi }, - { VI_DISPLAY_LATCH_1_LO, &m_LatchRegister[1].Lo }, - { VI_HSCALEW, &m_PictureConfiguration.Hex }, - { VI_HSCALER, &m_HorizontalScaling.Hex }, - { VI_FILTER_COEF_0_HI, &m_FilterCoefTables.Tables02[0].Hi }, - { VI_FILTER_COEF_0_LO, &m_FilterCoefTables.Tables02[0].Lo }, - { VI_FILTER_COEF_1_HI, &m_FilterCoefTables.Tables02[1].Hi }, - { VI_FILTER_COEF_1_LO, &m_FilterCoefTables.Tables02[1].Lo }, - { VI_FILTER_COEF_2_HI, &m_FilterCoefTables.Tables02[2].Hi }, - { VI_FILTER_COEF_2_LO, &m_FilterCoefTables.Tables02[2].Lo }, - { VI_FILTER_COEF_3_HI, &m_FilterCoefTables.Tables36[0].Hi }, - { VI_FILTER_COEF_3_LO, &m_FilterCoefTables.Tables36[0].Lo }, - { VI_FILTER_COEF_4_HI, &m_FilterCoefTables.Tables36[1].Hi }, - { VI_FILTER_COEF_4_LO, &m_FilterCoefTables.Tables36[1].Lo }, - { VI_FILTER_COEF_5_HI, &m_FilterCoefTables.Tables36[2].Hi }, - { VI_FILTER_COEF_5_LO, &m_FilterCoefTables.Tables36[2].Lo }, - { VI_FILTER_COEF_6_HI, &m_FilterCoefTables.Tables36[3].Hi }, - { VI_FILTER_COEF_6_LO, &m_FilterCoefTables.Tables36[3].Lo }, - { VI_CLOCK, &m_Clock }, - { VI_DTV_STATUS, &m_DTVStatus.Hex }, - { VI_FBWIDTH, &m_FBWidth.Hex }, - { VI_BORDER_BLANK_END, &m_BorderHBlank.Lo }, - { VI_BORDER_BLANK_START, &m_BorderHBlank.Hi }, - }; + struct + { + u32 addr; + u16* ptr; + } directly_mapped_vars[] = { + {VI_VERTICAL_TIMING, &m_VerticalTimingRegister.Hex}, + {VI_HORIZONTAL_TIMING_0_HI, &m_HTiming0.Hi}, + {VI_HORIZONTAL_TIMING_0_LO, &m_HTiming0.Lo}, + {VI_HORIZONTAL_TIMING_1_HI, &m_HTiming1.Hi}, + {VI_HORIZONTAL_TIMING_1_LO, &m_HTiming1.Lo}, + {VI_VBLANK_TIMING_ODD_HI, &m_VBlankTimingOdd.Hi}, + {VI_VBLANK_TIMING_ODD_LO, &m_VBlankTimingOdd.Lo}, + {VI_VBLANK_TIMING_EVEN_HI, &m_VBlankTimingEven.Hi}, + {VI_VBLANK_TIMING_EVEN_LO, &m_VBlankTimingEven.Lo}, + {VI_BURST_BLANKING_ODD_HI, &m_BurstBlankingOdd.Hi}, + {VI_BURST_BLANKING_ODD_LO, &m_BurstBlankingOdd.Lo}, + {VI_BURST_BLANKING_EVEN_HI, &m_BurstBlankingEven.Hi}, + {VI_BURST_BLANKING_EVEN_LO, &m_BurstBlankingEven.Lo}, + {VI_FB_LEFT_TOP_LO, &m_XFBInfoTop.Lo}, + {VI_FB_RIGHT_TOP_LO, &m_3DFBInfoTop.Lo}, + {VI_FB_LEFT_BOTTOM_LO, &m_XFBInfoBottom.Lo}, + {VI_FB_RIGHT_BOTTOM_LO, &m_3DFBInfoBottom.Lo}, + {VI_PRERETRACE_LO, &m_InterruptRegister[0].Lo}, + {VI_POSTRETRACE_LO, &m_InterruptRegister[1].Lo}, + {VI_DISPLAY_INTERRUPT_2_LO, &m_InterruptRegister[2].Lo}, + {VI_DISPLAY_INTERRUPT_3_LO, &m_InterruptRegister[3].Lo}, + {VI_DISPLAY_LATCH_0_HI, &m_LatchRegister[0].Hi}, + {VI_DISPLAY_LATCH_0_LO, &m_LatchRegister[0].Lo}, + {VI_DISPLAY_LATCH_1_HI, &m_LatchRegister[1].Hi}, + {VI_DISPLAY_LATCH_1_LO, &m_LatchRegister[1].Lo}, + {VI_HSCALEW, &m_PictureConfiguration.Hex}, + {VI_HSCALER, &m_HorizontalScaling.Hex}, + {VI_FILTER_COEF_0_HI, &m_FilterCoefTables.Tables02[0].Hi}, + {VI_FILTER_COEF_0_LO, &m_FilterCoefTables.Tables02[0].Lo}, + {VI_FILTER_COEF_1_HI, &m_FilterCoefTables.Tables02[1].Hi}, + {VI_FILTER_COEF_1_LO, &m_FilterCoefTables.Tables02[1].Lo}, + {VI_FILTER_COEF_2_HI, &m_FilterCoefTables.Tables02[2].Hi}, + {VI_FILTER_COEF_2_LO, &m_FilterCoefTables.Tables02[2].Lo}, + {VI_FILTER_COEF_3_HI, &m_FilterCoefTables.Tables36[0].Hi}, + {VI_FILTER_COEF_3_LO, &m_FilterCoefTables.Tables36[0].Lo}, + {VI_FILTER_COEF_4_HI, &m_FilterCoefTables.Tables36[1].Hi}, + {VI_FILTER_COEF_4_LO, &m_FilterCoefTables.Tables36[1].Lo}, + {VI_FILTER_COEF_5_HI, &m_FilterCoefTables.Tables36[2].Hi}, + {VI_FILTER_COEF_5_LO, &m_FilterCoefTables.Tables36[2].Lo}, + {VI_FILTER_COEF_6_HI, &m_FilterCoefTables.Tables36[3].Hi}, + {VI_FILTER_COEF_6_LO, &m_FilterCoefTables.Tables36[3].Lo}, + {VI_CLOCK, &m_Clock}, + {VI_DTV_STATUS, &m_DTVStatus.Hex}, + {VI_FBWIDTH, &m_FBWidth.Hex}, + {VI_BORDER_BLANK_END, &m_BorderHBlank.Lo}, + {VI_BORDER_BLANK_START, &m_BorderHBlank.Hi}, + }; - // Declare all the boilerplate direct MMIOs. - for (auto& mapped_var : directly_mapped_vars) - { - mmio->Register(base | mapped_var.addr, - MMIO::DirectRead(mapped_var.ptr), - MMIO::DirectWrite(mapped_var.ptr) - ); - } + // Declare all the boilerplate direct MMIOs. + for (auto& mapped_var : directly_mapped_vars) + { + mmio->Register(base | mapped_var.addr, MMIO::DirectRead(mapped_var.ptr), + MMIO::DirectWrite(mapped_var.ptr)); + } - struct { - u32 addr; - u16* ptr; - } update_params_on_read_vars[] = { - { VI_VERTICAL_TIMING, &m_VerticalTimingRegister.Hex }, - { VI_HORIZONTAL_TIMING_0_HI, &m_HTiming0.Hi }, - { VI_HORIZONTAL_TIMING_0_LO, &m_HTiming0.Lo }, - { VI_VBLANK_TIMING_ODD_HI, &m_VBlankTimingOdd.Hi }, - { VI_VBLANK_TIMING_ODD_LO, &m_VBlankTimingOdd.Lo }, - { VI_VBLANK_TIMING_EVEN_HI, &m_VBlankTimingEven.Hi }, - { VI_VBLANK_TIMING_EVEN_LO, &m_VBlankTimingEven.Lo }, - { VI_CLOCK, &m_Clock }, - }; + struct + { + u32 addr; + u16* ptr; + } update_params_on_read_vars[] = { + {VI_VERTICAL_TIMING, &m_VerticalTimingRegister.Hex}, + {VI_HORIZONTAL_TIMING_0_HI, &m_HTiming0.Hi}, + {VI_HORIZONTAL_TIMING_0_LO, &m_HTiming0.Lo}, + {VI_VBLANK_TIMING_ODD_HI, &m_VBlankTimingOdd.Hi}, + {VI_VBLANK_TIMING_ODD_LO, &m_VBlankTimingOdd.Lo}, + {VI_VBLANK_TIMING_EVEN_HI, &m_VBlankTimingEven.Hi}, + {VI_VBLANK_TIMING_EVEN_LO, &m_VBlankTimingEven.Lo}, + {VI_CLOCK, &m_Clock}, + }; - // Declare all the MMIOs that update timing params. - for (auto& mapped_var : update_params_on_read_vars) - { - mmio->Register(base | mapped_var.addr, - MMIO::DirectRead(mapped_var.ptr), - MMIO::ComplexWrite([mapped_var](u32, u16 val) { - *mapped_var.ptr = val; - UpdateParameters(); - }) - ); - } + // Declare all the MMIOs that update timing params. + for (auto& mapped_var : update_params_on_read_vars) + { + mmio->Register(base | mapped_var.addr, MMIO::DirectRead(mapped_var.ptr), + MMIO::ComplexWrite([mapped_var](u32, u16 val) { + *mapped_var.ptr = val; + UpdateParameters(); + })); + } - // XFB related MMIOs that require special handling on writes. - mmio->Register(base | VI_FB_LEFT_TOP_HI, - MMIO::DirectRead(&m_XFBInfoTop.Hi), - MMIO::ComplexWrite([](u32, u16 val) { - m_XFBInfoTop.Hi = val; - if (m_XFBInfoTop.CLRPOFF) m_XFBInfoTop.POFF = 0; - }) - ); - mmio->Register(base | VI_FB_LEFT_BOTTOM_HI, - MMIO::DirectRead(&m_XFBInfoBottom.Hi), - MMIO::ComplexWrite([](u32, u16 val) { - m_XFBInfoBottom.Hi = val; - if (m_XFBInfoBottom.CLRPOFF) m_XFBInfoBottom.POFF = 0; - }) - ); - mmio->Register(base | VI_FB_RIGHT_TOP_HI, - MMIO::DirectRead(&m_3DFBInfoTop.Hi), - MMIO::ComplexWrite([](u32, u16 val) { - m_3DFBInfoTop.Hi = val; - if (m_3DFBInfoTop.CLRPOFF) m_3DFBInfoTop.POFF = 0; - }) - ); - mmio->Register(base | VI_FB_RIGHT_BOTTOM_HI, - MMIO::DirectRead(&m_3DFBInfoBottom.Hi), - MMIO::ComplexWrite([](u32, u16 val) { - m_3DFBInfoBottom.Hi = val; - if (m_3DFBInfoBottom.CLRPOFF) m_3DFBInfoBottom.POFF = 0; - }) - ); + // XFB related MMIOs that require special handling on writes. + mmio->Register(base | VI_FB_LEFT_TOP_HI, MMIO::DirectRead(&m_XFBInfoTop.Hi), + MMIO::ComplexWrite([](u32, u16 val) { + m_XFBInfoTop.Hi = val; + if (m_XFBInfoTop.CLRPOFF) + m_XFBInfoTop.POFF = 0; + })); + mmio->Register(base | VI_FB_LEFT_BOTTOM_HI, MMIO::DirectRead(&m_XFBInfoBottom.Hi), + MMIO::ComplexWrite([](u32, u16 val) { + m_XFBInfoBottom.Hi = val; + if (m_XFBInfoBottom.CLRPOFF) + m_XFBInfoBottom.POFF = 0; + })); + mmio->Register(base | VI_FB_RIGHT_TOP_HI, MMIO::DirectRead(&m_3DFBInfoTop.Hi), + MMIO::ComplexWrite([](u32, u16 val) { + m_3DFBInfoTop.Hi = val; + if (m_3DFBInfoTop.CLRPOFF) + m_3DFBInfoTop.POFF = 0; + })); + mmio->Register(base | VI_FB_RIGHT_BOTTOM_HI, MMIO::DirectRead(&m_3DFBInfoBottom.Hi), + MMIO::ComplexWrite([](u32, u16 val) { + m_3DFBInfoBottom.Hi = val; + if (m_3DFBInfoBottom.CLRPOFF) + m_3DFBInfoBottom.POFF = 0; + })); - // MMIOs with unimplemented writes that trigger warnings. - mmio->Register(base | VI_VERTICAL_BEAM_POSITION, - MMIO::ComplexRead([](u32) { - return 1 + (s_half_line_count-1) / 2; - }), - MMIO::ComplexWrite([](u32, u16 val) { - WARN_LOG(VIDEOINTERFACE, "Changing vertical beam position to 0x%04x - not documented or implemented yet", val); - }) - ); - mmio->Register(base | VI_HORIZONTAL_BEAM_POSITION, - MMIO::ComplexRead([](u32) { - u16 value = static_cast(1 + m_HTiming0.HLW * (CoreTiming::GetTicks() - s_ticks_last_line_start) / (GetTicksPerHalfLine())); - return MathUtil::Clamp(value, static_cast(1), static_cast(m_HTiming0.HLW * 2)); - }), - MMIO::ComplexWrite([](u32, u16 val) { - WARN_LOG(VIDEOINTERFACE, "Changing horizontal beam position to 0x%04x - not documented or implemented yet", val); - }) - ); + // MMIOs with unimplemented writes that trigger warnings. + mmio->Register( + base | VI_VERTICAL_BEAM_POSITION, + MMIO::ComplexRead([](u32) { return 1 + (s_half_line_count - 1) / 2; }), + MMIO::ComplexWrite([](u32, u16 val) { + WARN_LOG(VIDEOINTERFACE, + "Changing vertical beam position to 0x%04x - not documented or implemented yet", + val); + })); + mmio->Register( + base | VI_HORIZONTAL_BEAM_POSITION, MMIO::ComplexRead([](u32) { + u16 value = + static_cast(1 + + m_HTiming0.HLW * (CoreTiming::GetTicks() - s_ticks_last_line_start) / + (GetTicksPerHalfLine())); + return MathUtil::Clamp(value, static_cast(1), static_cast(m_HTiming0.HLW * 2)); + }), + MMIO::ComplexWrite([](u32, u16 val) { + WARN_LOG(VIDEOINTERFACE, + "Changing horizontal beam position to 0x%04x - not documented or implemented yet", + val); + })); - // The following MMIOs are interrupts related and update interrupt status - // on writes. - mmio->Register(base | VI_PRERETRACE_HI, - MMIO::DirectRead(&m_InterruptRegister[0].Hi), - MMIO::ComplexWrite([](u32, u16 val) { - m_InterruptRegister[0].Hi = val; - UpdateInterrupts(); - }) - ); - mmio->Register(base | VI_POSTRETRACE_HI, - MMIO::DirectRead(&m_InterruptRegister[1].Hi), - MMIO::ComplexWrite([](u32, u16 val) { - m_InterruptRegister[1].Hi = val; - UpdateInterrupts(); - }) - ); - mmio->Register(base | VI_DISPLAY_INTERRUPT_2_HI, - MMIO::DirectRead(&m_InterruptRegister[2].Hi), - MMIO::ComplexWrite([](u32, u16 val) { - m_InterruptRegister[2].Hi = val; - UpdateInterrupts(); - }) - ); - mmio->Register(base | VI_DISPLAY_INTERRUPT_3_HI, - MMIO::DirectRead(&m_InterruptRegister[3].Hi), - MMIO::ComplexWrite([](u32, u16 val) { - m_InterruptRegister[3].Hi = val; - UpdateInterrupts(); - }) - ); + // The following MMIOs are interrupts related and update interrupt status + // on writes. + mmio->Register(base | VI_PRERETRACE_HI, MMIO::DirectRead(&m_InterruptRegister[0].Hi), + MMIO::ComplexWrite([](u32, u16 val) { + m_InterruptRegister[0].Hi = val; + UpdateInterrupts(); + })); + mmio->Register(base | VI_POSTRETRACE_HI, MMIO::DirectRead(&m_InterruptRegister[1].Hi), + MMIO::ComplexWrite([](u32, u16 val) { + m_InterruptRegister[1].Hi = val; + UpdateInterrupts(); + })); + mmio->Register(base | VI_DISPLAY_INTERRUPT_2_HI, + MMIO::DirectRead(&m_InterruptRegister[2].Hi), + MMIO::ComplexWrite([](u32, u16 val) { + m_InterruptRegister[2].Hi = val; + UpdateInterrupts(); + })); + mmio->Register(base | VI_DISPLAY_INTERRUPT_3_HI, + MMIO::DirectRead(&m_InterruptRegister[3].Hi), + MMIO::ComplexWrite([](u32, u16 val) { + m_InterruptRegister[3].Hi = val; + UpdateInterrupts(); + })); - // Unknown anti-aliasing related MMIO register: puts a warning on log and - // needs to shift/mask when reading/writing. - mmio->Register(base | VI_UNK_AA_REG_HI, - MMIO::ComplexRead([](u32) { - return m_UnkAARegister >> 16; - }), - MMIO::ComplexWrite([](u32, u16 val) { - m_UnkAARegister = (m_UnkAARegister & 0x0000FFFF) | ((u32)val << 16); - WARN_LOG(VIDEOINTERFACE, "Writing to the unknown AA register (hi)"); - }) - ); - mmio->Register(base | VI_UNK_AA_REG_LO, - MMIO::ComplexRead([](u32) { - return m_UnkAARegister & 0xFFFF; - }), - MMIO::ComplexWrite([](u32, u16 val) { - m_UnkAARegister = (m_UnkAARegister & 0xFFFF0000) | val; - WARN_LOG(VIDEOINTERFACE, "Writing to the unknown AA register (lo)"); - }) - ); + // Unknown anti-aliasing related MMIO register: puts a warning on log and + // needs to shift/mask when reading/writing. + mmio->Register(base | VI_UNK_AA_REG_HI, + MMIO::ComplexRead([](u32) { return m_UnkAARegister >> 16; }), + MMIO::ComplexWrite([](u32, u16 val) { + m_UnkAARegister = (m_UnkAARegister & 0x0000FFFF) | ((u32)val << 16); + WARN_LOG(VIDEOINTERFACE, "Writing to the unknown AA register (hi)"); + })); + mmio->Register(base | VI_UNK_AA_REG_LO, + MMIO::ComplexRead([](u32) { return m_UnkAARegister & 0xFFFF; }), + MMIO::ComplexWrite([](u32, u16 val) { + m_UnkAARegister = (m_UnkAARegister & 0xFFFF0000) | val; + WARN_LOG(VIDEOINTERFACE, "Writing to the unknown AA register (lo)"); + })); - // Control register writes only updates some select bits, and additional - // processing needs to be done if a reset is requested. - mmio->Register(base | VI_CONTROL_REGISTER, - MMIO::DirectRead(&m_DisplayControlRegister.Hex), - MMIO::ComplexWrite([](u32, u16 val) { - UVIDisplayControlRegister tmpConfig(val); - m_DisplayControlRegister.ENB = tmpConfig.ENB; - m_DisplayControlRegister.NIN = tmpConfig.NIN; - m_DisplayControlRegister.DLR = tmpConfig.DLR; - m_DisplayControlRegister.LE0 = tmpConfig.LE0; - m_DisplayControlRegister.LE1 = tmpConfig.LE1; - m_DisplayControlRegister.FMT = tmpConfig.FMT; + // Control register writes only updates some select bits, and additional + // processing needs to be done if a reset is requested. + mmio->Register(base | VI_CONTROL_REGISTER, MMIO::DirectRead(&m_DisplayControlRegister.Hex), + MMIO::ComplexWrite([](u32, u16 val) { + UVIDisplayControlRegister tmpConfig(val); + m_DisplayControlRegister.ENB = tmpConfig.ENB; + m_DisplayControlRegister.NIN = tmpConfig.NIN; + m_DisplayControlRegister.DLR = tmpConfig.DLR; + m_DisplayControlRegister.LE0 = tmpConfig.LE0; + m_DisplayControlRegister.LE1 = tmpConfig.LE1; + m_DisplayControlRegister.FMT = tmpConfig.FMT; - if (tmpConfig.RST) - { - // shuffle2 clear all data, reset to default vals, and enter idle mode - m_DisplayControlRegister.RST = 0; - for (UVIInterruptRegister& reg : m_InterruptRegister) - { - reg.Hex = 0; - } - UpdateInterrupts(); - } + if (tmpConfig.RST) + { + // shuffle2 clear all data, reset to default vals, and enter idle mode + m_DisplayControlRegister.RST = 0; + for (UVIInterruptRegister& reg : m_InterruptRegister) + { + reg.Hex = 0; + } + UpdateInterrupts(); + } - UpdateParameters(); - }) - ); + UpdateParameters(); + })); - // Map 8 bit reads (not writes) to 16 bit reads. - for (int i = 0; i < 0x1000; i += 2) - { - mmio->Register(base | i, - MMIO::ReadToLarger(mmio, base | i, 8), - MMIO::InvalidWrite() - ); - mmio->Register(base | (i + 1), - MMIO::ReadToLarger(mmio, base | i, 0), - MMIO::InvalidWrite() - ); - } + // Map 8 bit reads (not writes) to 16 bit reads. + for (int i = 0; i < 0x1000; i += 2) + { + mmio->Register(base | i, MMIO::ReadToLarger(mmio, base | i, 8), MMIO::InvalidWrite()); + mmio->Register(base | (i + 1), MMIO::ReadToLarger(mmio, base | i, 0), + MMIO::InvalidWrite()); + } - // Map 32 bit reads and writes to 16 bit reads and writes. - for (int i = 0; i < 0x1000; i += 4) - { - mmio->Register(base | i, - MMIO::ReadToSmaller(mmio, base | i, base | (i + 2)), - MMIO::WriteToSmaller(mmio, base | i, base | (i + 2)) - ); - } + // Map 32 bit reads and writes to 16 bit reads and writes. + for (int i = 0; i < 0x1000; i += 4) + { + mmio->Register(base | i, MMIO::ReadToSmaller(mmio, base | i, base | (i + 2)), + MMIO::WriteToSmaller(mmio, base | i, base | (i + 2))); + } } void SetRegionReg(char region) { - if (!SConfig::GetInstance().bForceNTSCJ) - m_DTVStatus.ntsc_j = region == 'J'; + if (!SConfig::GetInstance().bForceNTSCJ) + m_DTVStatus.ntsc_j = region == 'J'; } void UpdateInterrupts() { - if ((m_InterruptRegister[0].IR_INT && m_InterruptRegister[0].IR_MASK) || - (m_InterruptRegister[1].IR_INT && m_InterruptRegister[1].IR_MASK) || - (m_InterruptRegister[2].IR_INT && m_InterruptRegister[2].IR_MASK) || - (m_InterruptRegister[3].IR_INT && m_InterruptRegister[3].IR_MASK)) - { - ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_VI, true); - } - else - { - ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_VI, false); - } + if ((m_InterruptRegister[0].IR_INT && m_InterruptRegister[0].IR_MASK) || + (m_InterruptRegister[1].IR_INT && m_InterruptRegister[1].IR_MASK) || + (m_InterruptRegister[2].IR_INT && m_InterruptRegister[2].IR_MASK) || + (m_InterruptRegister[3].IR_INT && m_InterruptRegister[3].IR_MASK)) + { + ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_VI, true); + } + else + { + ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_VI, false); + } } u32 GetXFBAddressTop() { - if (m_XFBInfoTop.POFF) - return m_XFBInfoTop.FBB << 5; - else - return m_XFBInfoTop.FBB; + if (m_XFBInfoTop.POFF) + return m_XFBInfoTop.FBB << 5; + else + return m_XFBInfoTop.FBB; } u32 GetXFBAddressBottom() { - // POFF for XFB bottom is connected to POFF for XFB top - if (m_XFBInfoTop.POFF) - return m_XFBInfoBottom.FBB << 5; - else - return m_XFBInfoBottom.FBB; + // POFF for XFB bottom is connected to POFF for XFB top + if (m_XFBInfoTop.POFF) + return m_XFBInfoBottom.FBB << 5; + else + return m_XFBInfoBottom.FBB; } static u32 GetHalfLinesPerEvenField() { - return (3 * m_VerticalTimingRegister.EQU + m_VBlankTimingEven.PRB + 2 * m_VerticalTimingRegister.ACV + m_VBlankTimingEven.PSB); + return (3 * m_VerticalTimingRegister.EQU + m_VBlankTimingEven.PRB + + 2 * m_VerticalTimingRegister.ACV + m_VBlankTimingEven.PSB); } static u32 GetHalfLinesPerOddField() { - return (3 * m_VerticalTimingRegister.EQU + m_VBlankTimingOdd.PRB + 2 * m_VerticalTimingRegister.ACV + m_VBlankTimingOdd.PSB); + return (3 * m_VerticalTimingRegister.EQU + m_VBlankTimingOdd.PRB + + 2 * m_VerticalTimingRegister.ACV + m_VBlankTimingOdd.PSB); } - static u32 GetTicksPerEvenField() { - return GetTicksPerHalfLine() * GetHalfLinesPerEvenField(); + return GetTicksPerHalfLine() * GetHalfLinesPerEvenField(); } static u32 GetTicksPerOddField() { - return GetTicksPerHalfLine() * GetHalfLinesPerOddField(); + return GetTicksPerHalfLine() * GetHalfLinesPerOddField(); } // Get the aspect ratio of VI's active area. float GetAspectRatio() { - // The picture of a PAL/NTSC TV signal is defined to have a 4:3 aspect ratio, - // but it's only 4:3 if the picture fill the entire active area. - // All games configure VideoInterface to add padding in both the horizontal and vertical - // directions and most games also do a slight horizontal scale. - // This means that XFB never fills the entire active area and is therefor almost never 4:3 + // The picture of a PAL/NTSC TV signal is defined to have a 4:3 aspect ratio, + // but it's only 4:3 if the picture fill the entire active area. + // All games configure VideoInterface to add padding in both the horizontal and vertical + // directions and most games also do a slight horizontal scale. + // This means that XFB never fills the entire active area and is therefor almost never 4:3 - // To work out the correct aspect ratio of the XFB, we need to know how VideoInterface's - // currently configured active area compares to the active area of a stock PAL or NTSC - // signal (which would be 4:3) + // To work out the correct aspect ratio of the XFB, we need to know how VideoInterface's + // currently configured active area compares to the active area of a stock PAL or NTSC + // signal (which would be 4:3) - // This function only deals with standard aspect ratios. For widescreen aspect ratios, - // multiply the result by 1.33333.. + // This function only deals with standard aspect ratios. For widescreen aspect ratios, + // multiply the result by 1.33333.. - // 1. Get our active area in BT.601 samples (more or less pixels) - int active_lines = m_VerticalTimingRegister.ACV; - int active_width_samples = (m_HTiming0.HLW + m_HTiming1.HBS640 - m_HTiming1.HBE640); + // 1. Get our active area in BT.601 samples (more or less pixels) + int active_lines = m_VerticalTimingRegister.ACV; + int active_width_samples = (m_HTiming0.HLW + m_HTiming1.HBS640 - m_HTiming1.HBE640); - // 2. TVs are analog and don't have pixels. So we convert to seconds. - float tick_length = (1.0f / SystemTimers::GetTicksPerSecond()); - float vertical_period = tick_length * GetTicksPerField(); - float horizontal_period= tick_length * GetTicksPerHalfLine() * 2; - float vertical_active_area = active_lines * horizontal_period; - float horizontal_active_area = tick_length * GetTicksPerSample() * active_width_samples; + // 2. TVs are analog and don't have pixels. So we convert to seconds. + float tick_length = (1.0f / SystemTimers::GetTicksPerSecond()); + float vertical_period = tick_length * GetTicksPerField(); + float horizontal_period = tick_length * GetTicksPerHalfLine() * 2; + float vertical_active_area = active_lines * horizontal_period; + float horizontal_active_area = tick_length * GetTicksPerSample() * active_width_samples; - // We are approximating the horizontal/vertical flyback transformers that control the - // position of the electron beam on the screen. Our flyback transformers create a - // perfect Sawtooth wave, with a smooth rise and a fall that takes zero time. - // For more accurate emulation of video signals out of the 525 or 625 line standards, - // it might be necessary to emulate a less precise flyback transformer with more flaws. - // But those modes aren't officially supported by TVs anyway and could behave differently - // on different TVs. + // We are approximating the horizontal/vertical flyback transformers that control the + // position of the electron beam on the screen. Our flyback transformers create a + // perfect Sawtooth wave, with a smooth rise and a fall that takes zero time. + // For more accurate emulation of video signals out of the 525 or 625 line standards, + // it might be necessary to emulate a less precise flyback transformer with more flaws. + // But those modes aren't officially supported by TVs anyway and could behave differently + // on different TVs. - // 3. Calculate the ratio of active time to total time for VI's active area - float vertical_active_ratio = vertical_active_area / vertical_period; - float horizontal_active_ratio = horizontal_active_area / horizontal_period; + // 3. Calculate the ratio of active time to total time for VI's active area + float vertical_active_ratio = vertical_active_area / vertical_period; + float horizontal_active_ratio = horizontal_active_area / horizontal_period; - // 4. And then scale the ratios to typical PAL/NTSC signals. - // NOTE: With the exception of selecting between PAL-M and NTSC color encoding on Brazilian - // GameCubes, the FMT field doesn't actually do anything on real hardware. But - // Nintendo's SDK always sets it appropriately to match the number of lines. - if (m_DisplayControlRegister.FMT == 1) // 625 line TV (PAL) - { - // PAL defines the horizontal active area as 52us of the 64us line. - // BT.470-6 defines the blanking period as 12.0us +0.0 -0.3 [table on page 5] - horizontal_active_ratio *= 64.0f / 52.0f; - // PAL defines the vertical active area as 576 of 625 lines. - vertical_active_ratio *= 625.0f / 576.0f; - // TODO: Should PAL60 games go through the 625 or 525 line codepath? - // The resulting aspect ratio is close, but not identical. - } - else // 525 line TV (NTSC or PAL-M) - { - // The NTSC standard doesn't define it's active area very well. - // The line is 63.55555..us long, which is derived from 1.001 / (30 * 525) - // but the blanking area is defined with a large amount of slack in the SMPTE 170M-2004 - // standard, 10.7us +0.3 -0.2 [derived from table on page 9] - // The BT.470-6 standard provides a different number of 10.9us +/- 0.2 [table on page 5] - // This results in an active area between 52.5555us and 53.05555us - // Lots of different numbers float around the Internet including: - // * 52.655555.. us -- http://web.archive.org/web/20140218044518/http://lipas.uwasa.fi/~f76998/video/conversion/ - // * 52.66 us -- http://www.ni.com/white-paper/4750/en/ - // * 52.6 us -- http://web.mit.edu/6.111/www/f2008/handouts/L12.pdf - // - // None of these website provide primary sources for their numbers, back in the days of - // analog, TV signal timings were not that precise to start with and it never got standardized - // during the move to digital. - // We are just going to use 52.655555.. as most other numbers on the Internet appear to be a - // simplification of it. 53.655555.. is a blanking period of 10.9us, matching the BT.470-6 standard - // and within tolerance of the SMPTE 170M-2004 standard. - horizontal_active_ratio *= 63.555555f / 52.655555f; - // Even 486 active lines isn't completely agreed upon. - // Depending on how you count the two half lines you could get 485 or 484 - vertical_active_ratio *= 525.0f / 486.0f; - } + // 4. And then scale the ratios to typical PAL/NTSC signals. + // NOTE: With the exception of selecting between PAL-M and NTSC color encoding on Brazilian + // GameCubes, the FMT field doesn't actually do anything on real hardware. But + // Nintendo's SDK always sets it appropriately to match the number of lines. + if (m_DisplayControlRegister.FMT == 1) // 625 line TV (PAL) + { + // PAL defines the horizontal active area as 52us of the 64us line. + // BT.470-6 defines the blanking period as 12.0us +0.0 -0.3 [table on page 5] + horizontal_active_ratio *= 64.0f / 52.0f; + // PAL defines the vertical active area as 576 of 625 lines. + vertical_active_ratio *= 625.0f / 576.0f; + // TODO: Should PAL60 games go through the 625 or 525 line codepath? + // The resulting aspect ratio is close, but not identical. + } + else // 525 line TV (NTSC or PAL-M) + { + // The NTSC standard doesn't define it's active area very well. + // The line is 63.55555..us long, which is derived from 1.001 / (30 * 525) + // but the blanking area is defined with a large amount of slack in the SMPTE 170M-2004 + // standard, 10.7us +0.3 -0.2 [derived from table on page 9] + // The BT.470-6 standard provides a different number of 10.9us +/- 0.2 [table on page 5] + // This results in an active area between 52.5555us and 53.05555us + // Lots of different numbers float around the Internet including: + // * 52.655555.. us -- + // http://web.archive.org/web/20140218044518/http://lipas.uwasa.fi/~f76998/video/conversion/ + // * 52.66 us -- http://www.ni.com/white-paper/4750/en/ + // * 52.6 us -- http://web.mit.edu/6.111/www/f2008/handouts/L12.pdf + // + // None of these website provide primary sources for their numbers, back in the days of + // analog, TV signal timings were not that precise to start with and it never got standardized + // during the move to digital. + // We are just going to use 52.655555.. as most other numbers on the Internet appear to be a + // simplification of it. 53.655555.. is a blanking period of 10.9us, matching the BT.470-6 + // standard + // and within tolerance of the SMPTE 170M-2004 standard. + horizontal_active_ratio *= 63.555555f / 52.655555f; + // Even 486 active lines isn't completely agreed upon. + // Depending on how you count the two half lines you could get 485 or 484 + vertical_active_ratio *= 525.0f / 486.0f; + } - // 5. Calculate the final ratio and scale to 4:3 - float ratio = horizontal_active_ratio / vertical_active_ratio; - if (std::isnormal(ratio)) // Check we have a sane ratio and haven't propagated any infs/nans/zeros - return ratio * (4.0f / 3.0f); // Scale to 4:3 - else - return (4.0f / 3.0f); // VI isn't initialized correctly, just return 4:3 instead + // 5. Calculate the final ratio and scale to 4:3 + float ratio = horizontal_active_ratio / vertical_active_ratio; + if (std::isnormal( + ratio)) // Check we have a sane ratio and haven't propagated any infs/nans/zeros + return ratio * (4.0f / 3.0f); // Scale to 4:3 + else + return (4.0f / 3.0f); // VI isn't initialized correctly, just return 4:3 instead } // This function updates: @@ -630,159 +608,161 @@ float GetAspectRatio() void UpdateParameters() { - s_even_field_first_hl = 3 * m_VerticalTimingRegister.EQU + m_VBlankTimingEven.PRB + 1; - s_odd_field_first_hl = GetHalfLinesPerEvenField() + 3 * m_VerticalTimingRegister.EQU + m_VBlankTimingOdd.PRB + 1; - s_even_field_last_hl = s_even_field_first_hl + m_VerticalTimingRegister.ACV * 2; - s_odd_field_last_hl = s_odd_field_first_hl + m_VerticalTimingRegister.ACV * 2; + s_even_field_first_hl = 3 * m_VerticalTimingRegister.EQU + m_VBlankTimingEven.PRB + 1; + s_odd_field_first_hl = + GetHalfLinesPerEvenField() + 3 * m_VerticalTimingRegister.EQU + m_VBlankTimingOdd.PRB + 1; + s_even_field_last_hl = s_even_field_first_hl + m_VerticalTimingRegister.ACV * 2; + s_odd_field_last_hl = s_odd_field_first_hl + m_VerticalTimingRegister.ACV * 2; - s_target_refresh_rate = lround(2.0 * SystemTimers::GetTicksPerSecond() / (GetTicksPerEvenField() + GetTicksPerOddField())); + s_target_refresh_rate = lround(2.0 * SystemTimers::GetTicksPerSecond() / + (GetTicksPerEvenField() + GetTicksPerOddField())); } u32 GetTargetRefreshRate() { - return s_target_refresh_rate; + return s_target_refresh_rate; } u32 GetTicksPerSample() { - return 2 * SystemTimers::GetTicksPerSecond() / s_clock_freqs[m_Clock]; + return 2 * SystemTimers::GetTicksPerSecond() / s_clock_freqs[m_Clock]; } u32 GetTicksPerHalfLine() { - return GetTicksPerSample() * m_HTiming0.HLW; + return GetTicksPerSample() * m_HTiming0.HLW; } u32 GetTicksPerField() { - return GetTicksPerEvenField(); + return GetTicksPerEvenField(); } static void BeginField(FieldType field) { - // Could we fit a second line of data in the stride? - bool potentially_interlaced_xfb = ((m_PictureConfiguration.STD / m_PictureConfiguration.WPL) == 2); - // Are there an odd number of half-lines per field (definition of interlaced video) - bool interlaced_video_mode = (GetHalfLinesPerEvenField() & 1) == 1; + // Could we fit a second line of data in the stride? + bool potentially_interlaced_xfb = + ((m_PictureConfiguration.STD / m_PictureConfiguration.WPL) == 2); + // Are there an odd number of half-lines per field (definition of interlaced video) + bool interlaced_video_mode = (GetHalfLinesPerEvenField() & 1) == 1; - u32 fbStride = m_PictureConfiguration.STD * 16; - u32 fbWidth = m_PictureConfiguration.WPL * 16; - u32 fbHeight = m_VerticalTimingRegister.ACV; + u32 fbStride = m_PictureConfiguration.STD * 16; + u32 fbWidth = m_PictureConfiguration.WPL * 16; + u32 fbHeight = m_VerticalTimingRegister.ACV; - u32 xfbAddr; + u32 xfbAddr; - if (field == FieldType::FIELD_EVEN) - { - xfbAddr = GetXFBAddressBottom(); - } - else - { - xfbAddr = GetXFBAddressTop(); - } + if (field == FieldType::FIELD_EVEN) + { + xfbAddr = GetXFBAddressBottom(); + } + else + { + xfbAddr = GetXFBAddressTop(); + } - if (potentially_interlaced_xfb && interlaced_video_mode && g_ActiveConfig.bForceProgressive) - { - // Strictly speaking, in interlaced mode, we're only supposed to read - // half of the lines of the XFB, and use that to display a field; the - // other lines are unspecified junk. However, in practice, we can - // almost always double the vertical resolution of the output by - // forcing progressive output: there's usually useful data in the - // other field. One notable exception: the title screen teaser - // videos in Metroid Prime don't render correctly using this hack. - fbStride /= 2; - fbHeight *= 2; + if (potentially_interlaced_xfb && interlaced_video_mode && g_ActiveConfig.bForceProgressive) + { + // Strictly speaking, in interlaced mode, we're only supposed to read + // half of the lines of the XFB, and use that to display a field; the + // other lines are unspecified junk. However, in practice, we can + // almost always double the vertical resolution of the output by + // forcing progressive output: there's usually useful data in the + // other field. One notable exception: the title screen teaser + // videos in Metroid Prime don't render correctly using this hack. + fbStride /= 2; + fbHeight *= 2; - // PRB for the different fields should only ever differ by 1 in - // interlaced mode, and which is less determines which field - // has the first line. For the field with the second line, we - // offset the xfb by (-stride_of_one_line) to get the start - // address of the full xfb. - if (field == FieldType::FIELD_ODD && m_VBlankTimingOdd.PRB == m_VBlankTimingEven.PRB + 1) - xfbAddr -= fbStride * 2; + // PRB for the different fields should only ever differ by 1 in + // interlaced mode, and which is less determines which field + // has the first line. For the field with the second line, we + // offset the xfb by (-stride_of_one_line) to get the start + // address of the full xfb. + if (field == FieldType::FIELD_ODD && m_VBlankTimingOdd.PRB == m_VBlankTimingEven.PRB + 1) + xfbAddr -= fbStride * 2; - if (field == FieldType::FIELD_EVEN && m_VBlankTimingOdd.PRB == m_VBlankTimingEven.PRB - 1) - xfbAddr -= fbStride * 2; - } + if (field == FieldType::FIELD_EVEN && m_VBlankTimingOdd.PRB == m_VBlankTimingEven.PRB - 1) + xfbAddr -= fbStride * 2; + } - static const char* const fieldTypeNames[] = { "Odd", "Even" }; + static const char* const fieldTypeNames[] = {"Odd", "Even"}; - static const UVIVBlankTimingRegister *vert_timing[] = { - &m_VBlankTimingOdd, - &m_VBlankTimingEven, - }; + static const UVIVBlankTimingRegister* vert_timing[] = { + &m_VBlankTimingOdd, &m_VBlankTimingEven, + }; - DEBUG_LOG(VIDEOINTERFACE, - "(VI->BeginField): Address: %.08X | WPL %u | STD %u | EQ %u | PRB %u | ACV %u | PSB %u | Field %s", - xfbAddr, m_PictureConfiguration.WPL, m_PictureConfiguration.STD, m_VerticalTimingRegister.EQU, - vert_timing[field]->PRB, m_VerticalTimingRegister.ACV, vert_timing[field]->PSB, fieldTypeNames[field]); + DEBUG_LOG(VIDEOINTERFACE, "(VI->BeginField): Address: %.08X | WPL %u | STD %u | EQ %u | PRB %u | " + "ACV %u | PSB %u | Field %s", + xfbAddr, m_PictureConfiguration.WPL, m_PictureConfiguration.STD, + m_VerticalTimingRegister.EQU, vert_timing[field]->PRB, m_VerticalTimingRegister.ACV, + vert_timing[field]->PSB, fieldTypeNames[field]); - DEBUG_LOG(VIDEOINTERFACE, - "HorizScaling: %04x | fbwidth %d | %u | %u", - m_HorizontalScaling.Hex, m_FBWidth.Hex, GetTicksPerEvenField(), GetTicksPerOddField()); + DEBUG_LOG(VIDEOINTERFACE, "HorizScaling: %04x | fbwidth %d | %u | %u", m_HorizontalScaling.Hex, + m_FBWidth.Hex, GetTicksPerEvenField(), GetTicksPerOddField()); - if (xfbAddr) - g_video_backend->Video_BeginField(xfbAddr, fbWidth, fbStride, fbHeight); + if (xfbAddr) + g_video_backend->Video_BeginField(xfbAddr, fbWidth, fbStride, fbHeight); } static void EndField() { - g_video_backend->Video_EndField(); - Core::VideoThrottle(); + g_video_backend->Video_EndField(); + Core::VideoThrottle(); } // Purpose: Send VI interrupt when triggered // Run when: When a frame is scanned (progressive/interlace) void Update() { - if (s_half_line_of_next_si_poll == s_half_line_count) - { - SerialInterface::UpdateDevices(); - s_half_line_of_next_si_poll += SerialInterface::GetPollXLines(); - } - if (s_half_line_count == s_even_field_first_hl) - { - BeginField(FIELD_EVEN); - } - else if (s_half_line_count == s_odd_field_first_hl) - { - BeginField(FIELD_ODD); - } - else if (s_half_line_count == s_even_field_last_hl) - { - EndField(); - } - else if (s_half_line_count == s_odd_field_last_hl) - { - EndField(); - } + if (s_half_line_of_next_si_poll == s_half_line_count) + { + SerialInterface::UpdateDevices(); + s_half_line_of_next_si_poll += SerialInterface::GetPollXLines(); + } + if (s_half_line_count == s_even_field_first_hl) + { + BeginField(FIELD_EVEN); + } + else if (s_half_line_count == s_odd_field_first_hl) + { + BeginField(FIELD_ODD); + } + else if (s_half_line_count == s_even_field_last_hl) + { + EndField(); + } + else if (s_half_line_count == s_odd_field_last_hl) + { + EndField(); + } - for (UVIInterruptRegister& reg : m_InterruptRegister) - { - if (s_half_line_count + 1 == 2u * reg.VCT) - { - reg.IR_INT = 1; - } - } + for (UVIInterruptRegister& reg : m_InterruptRegister) + { + if (s_half_line_count + 1 == 2u * reg.VCT) + { + reg.IR_INT = 1; + } + } - s_half_line_count++; + s_half_line_count++; - if (s_half_line_count > GetHalfLinesPerEvenField() + GetHalfLinesPerOddField()) - { - s_half_line_count = 1; - s_half_line_of_next_si_poll = num_half_lines_for_si_poll; // first results start at vsync - } + if (s_half_line_count > GetHalfLinesPerEvenField() + GetHalfLinesPerOddField()) + { + s_half_line_count = 1; + s_half_line_of_next_si_poll = num_half_lines_for_si_poll; // first results start at vsync + } - if (s_half_line_count == GetHalfLinesPerEvenField()) - { - s_half_line_of_next_si_poll = GetHalfLinesPerEvenField() + num_half_lines_for_si_poll; - } + if (s_half_line_count == GetHalfLinesPerEvenField()) + { + s_half_line_of_next_si_poll = GetHalfLinesPerEvenField() + num_half_lines_for_si_poll; + } - if (s_half_line_count & 1) - { - s_ticks_last_line_start = CoreTiming::GetTicks(); - } + if (s_half_line_count & 1) + { + s_ticks_last_line_start = CoreTiming::GetTicks(); + } - UpdateInterrupts(); + UpdateInterrupts(); } -} // namespace +} // namespace diff --git a/Source/Core/Core/HW/VideoInterface.h b/Source/Core/Core/HW/VideoInterface.h index 133aa3e680..653081ebc4 100644 --- a/Source/Core/Core/HW/VideoInterface.h +++ b/Source/Core/Core/HW/VideoInterface.h @@ -7,302 +7,320 @@ #include "Common/CommonTypes.h" class PointerWrap; -namespace MMIO { class Mapping; } +namespace MMIO +{ +class Mapping; +} namespace VideoInterface { - // VI Internal Hardware Addresses enum { - VI_VERTICAL_TIMING = 0x00, - VI_CONTROL_REGISTER = 0x02, - VI_HORIZONTAL_TIMING_0_HI = 0x04, - VI_HORIZONTAL_TIMING_0_LO = 0x06, - VI_HORIZONTAL_TIMING_1_HI = 0x08, - VI_HORIZONTAL_TIMING_1_LO = 0x0a, - VI_VBLANK_TIMING_ODD_HI = 0x0c, - VI_VBLANK_TIMING_ODD_LO = 0x0e, - VI_VBLANK_TIMING_EVEN_HI = 0x10, - VI_VBLANK_TIMING_EVEN_LO = 0x12, - VI_BURST_BLANKING_ODD_HI = 0x14, - VI_BURST_BLANKING_ODD_LO = 0x16, - VI_BURST_BLANKING_EVEN_HI = 0x18, - VI_BURST_BLANKING_EVEN_LO = 0x1a, - VI_FB_LEFT_TOP_HI = 0x1c, // FB_LEFT_TOP is first half of XFB info - VI_FB_LEFT_TOP_LO = 0x1e, - VI_FB_RIGHT_TOP_HI = 0x20, // FB_RIGHT_TOP is only used in 3D mode - VI_FB_RIGHT_TOP_LO = 0x22, - VI_FB_LEFT_BOTTOM_HI = 0x24, // FB_LEFT_BOTTOM is second half of XFB info - VI_FB_LEFT_BOTTOM_LO = 0x26, - VI_FB_RIGHT_BOTTOM_HI = 0x28, // FB_RIGHT_BOTTOM is only used in 3D mode - VI_FB_RIGHT_BOTTOM_LO = 0x2a, - VI_VERTICAL_BEAM_POSITION = 0x2c, - VI_HORIZONTAL_BEAM_POSITION = 0x2e, - VI_PRERETRACE_HI = 0x30, - VI_PRERETRACE_LO = 0x32, - VI_POSTRETRACE_HI = 0x34, - VI_POSTRETRACE_LO = 0x36, - VI_DISPLAY_INTERRUPT_2_HI = 0x38, - VI_DISPLAY_INTERRUPT_2_LO = 0x3a, - VI_DISPLAY_INTERRUPT_3_HI = 0x3c, - VI_DISPLAY_INTERRUPT_3_LO = 0x3e, - VI_DISPLAY_LATCH_0_HI = 0x40, - VI_DISPLAY_LATCH_0_LO = 0x42, - VI_DISPLAY_LATCH_1_HI = 0x44, - VI_DISPLAY_LATCH_1_LO = 0x46, - VI_HSCALEW = 0x48, - VI_HSCALER = 0x4a, - VI_FILTER_COEF_0_HI = 0x4c, - VI_FILTER_COEF_0_LO = 0x4e, - VI_FILTER_COEF_1_HI = 0x50, - VI_FILTER_COEF_1_LO = 0x52, - VI_FILTER_COEF_2_HI = 0x54, - VI_FILTER_COEF_2_LO = 0x56, - VI_FILTER_COEF_3_HI = 0x58, - VI_FILTER_COEF_3_LO = 0x5a, - VI_FILTER_COEF_4_HI = 0x5c, - VI_FILTER_COEF_4_LO = 0x5e, - VI_FILTER_COEF_5_HI = 0x60, - VI_FILTER_COEF_5_LO = 0x62, - VI_FILTER_COEF_6_HI = 0x64, - VI_FILTER_COEF_6_LO = 0x66, - VI_UNK_AA_REG_HI = 0x68, - VI_UNK_AA_REG_LO = 0x6a, - VI_CLOCK = 0x6c, - VI_DTV_STATUS = 0x6e, - VI_FBWIDTH = 0x70, - VI_BORDER_BLANK_END = 0x72, // Only used in debug video mode - VI_BORDER_BLANK_START = 0x74, // Only used in debug video mode - //VI_INTERLACE = 0x850, // ??? MYSTERY OLD CODE + VI_VERTICAL_TIMING = 0x00, + VI_CONTROL_REGISTER = 0x02, + VI_HORIZONTAL_TIMING_0_HI = 0x04, + VI_HORIZONTAL_TIMING_0_LO = 0x06, + VI_HORIZONTAL_TIMING_1_HI = 0x08, + VI_HORIZONTAL_TIMING_1_LO = 0x0a, + VI_VBLANK_TIMING_ODD_HI = 0x0c, + VI_VBLANK_TIMING_ODD_LO = 0x0e, + VI_VBLANK_TIMING_EVEN_HI = 0x10, + VI_VBLANK_TIMING_EVEN_LO = 0x12, + VI_BURST_BLANKING_ODD_HI = 0x14, + VI_BURST_BLANKING_ODD_LO = 0x16, + VI_BURST_BLANKING_EVEN_HI = 0x18, + VI_BURST_BLANKING_EVEN_LO = 0x1a, + VI_FB_LEFT_TOP_HI = 0x1c, // FB_LEFT_TOP is first half of XFB info + VI_FB_LEFT_TOP_LO = 0x1e, + VI_FB_RIGHT_TOP_HI = 0x20, // FB_RIGHT_TOP is only used in 3D mode + VI_FB_RIGHT_TOP_LO = 0x22, + VI_FB_LEFT_BOTTOM_HI = 0x24, // FB_LEFT_BOTTOM is second half of XFB info + VI_FB_LEFT_BOTTOM_LO = 0x26, + VI_FB_RIGHT_BOTTOM_HI = 0x28, // FB_RIGHT_BOTTOM is only used in 3D mode + VI_FB_RIGHT_BOTTOM_LO = 0x2a, + VI_VERTICAL_BEAM_POSITION = 0x2c, + VI_HORIZONTAL_BEAM_POSITION = 0x2e, + VI_PRERETRACE_HI = 0x30, + VI_PRERETRACE_LO = 0x32, + VI_POSTRETRACE_HI = 0x34, + VI_POSTRETRACE_LO = 0x36, + VI_DISPLAY_INTERRUPT_2_HI = 0x38, + VI_DISPLAY_INTERRUPT_2_LO = 0x3a, + VI_DISPLAY_INTERRUPT_3_HI = 0x3c, + VI_DISPLAY_INTERRUPT_3_LO = 0x3e, + VI_DISPLAY_LATCH_0_HI = 0x40, + VI_DISPLAY_LATCH_0_LO = 0x42, + VI_DISPLAY_LATCH_1_HI = 0x44, + VI_DISPLAY_LATCH_1_LO = 0x46, + VI_HSCALEW = 0x48, + VI_HSCALER = 0x4a, + VI_FILTER_COEF_0_HI = 0x4c, + VI_FILTER_COEF_0_LO = 0x4e, + VI_FILTER_COEF_1_HI = 0x50, + VI_FILTER_COEF_1_LO = 0x52, + VI_FILTER_COEF_2_HI = 0x54, + VI_FILTER_COEF_2_LO = 0x56, + VI_FILTER_COEF_3_HI = 0x58, + VI_FILTER_COEF_3_LO = 0x5a, + VI_FILTER_COEF_4_HI = 0x5c, + VI_FILTER_COEF_4_LO = 0x5e, + VI_FILTER_COEF_5_HI = 0x60, + VI_FILTER_COEF_5_LO = 0x62, + VI_FILTER_COEF_6_HI = 0x64, + VI_FILTER_COEF_6_LO = 0x66, + VI_UNK_AA_REG_HI = 0x68, + VI_UNK_AA_REG_LO = 0x6a, + VI_CLOCK = 0x6c, + VI_DTV_STATUS = 0x6e, + VI_FBWIDTH = 0x70, + VI_BORDER_BLANK_END = 0x72, // Only used in debug video mode + VI_BORDER_BLANK_START = 0x74, // Only used in debug video mode + // VI_INTERLACE = 0x850, // ??? MYSTERY OLD CODE }; -union UVIVerticalTimingRegister -{ - u16 Hex; - struct - { - u16 EQU : 4; // Equalization pulse in half lines - u16 ACV : 10; // Active video in lines per field (seems always zero) - u16 : 2; - }; - UVIVerticalTimingRegister(u16 _hex) { Hex = _hex;} - UVIVerticalTimingRegister() { Hex = 0;} +union UVIVerticalTimingRegister { + u16 Hex; + struct + { + u16 EQU : 4; // Equalization pulse in half lines + u16 ACV : 10; // Active video in lines per field (seems always zero) + u16 : 2; + }; + UVIVerticalTimingRegister(u16 _hex) { Hex = _hex; } + UVIVerticalTimingRegister() { Hex = 0; } }; -union UVIDisplayControlRegister -{ - u16 Hex; - struct - { - u16 ENB : 1; // Enables video timing generation and data request - u16 RST : 1; // Clears all data requests and puts VI into its idle state - u16 NIN : 1; // 0: Interlaced, 1: Non-Interlaced: top field drawn at field rate and bottom field is not displayed - u16 DLR : 1; // Selects 3D Display Mode - u16 LE0 : 2; // Display Latch; 0: Off, 1: On for 1 field, 2: On for 2 fields, 3: Always on - u16 LE1 : 2; - u16 FMT : 2; // 0: NTSC, 1: PAL, 2: MPAL, 3: Debug - u16 : 6; - }; - UVIDisplayControlRegister(u16 _hex) { Hex = _hex;} - UVIDisplayControlRegister() { Hex = 0;} +union UVIDisplayControlRegister { + u16 Hex; + struct + { + u16 ENB : 1; // Enables video timing generation and data request + u16 RST : 1; // Clears all data requests and puts VI into its idle state + u16 NIN : 1; // 0: Interlaced, 1: Non-Interlaced: top field drawn at field rate and bottom + // field is not displayed + u16 DLR : 1; // Selects 3D Display Mode + u16 LE0 : 2; // Display Latch; 0: Off, 1: On for 1 field, 2: On for 2 fields, 3: Always on + u16 LE1 : 2; + u16 FMT : 2; // 0: NTSC, 1: PAL, 2: MPAL, 3: Debug + u16 : 6; + }; + UVIDisplayControlRegister(u16 _hex) { Hex = _hex; } + UVIDisplayControlRegister() { Hex = 0; } }; -union UVIHorizontalTiming0 -{ - u32 Hex; - struct { u16 Lo, Hi; }; - struct - { - u32 HLW : 10; // Halfline Width (W*16 = Width (720)) - u32 : 6; - u32 HCE : 7; // Horizontal Sync Start to Color Burst End - u32 : 1; - u32 HCS : 7; // Horizontal Sync Start to Color Burst Start - u32 : 1; - }; +union UVIHorizontalTiming0 { + u32 Hex; + struct + { + u16 Lo, Hi; + }; + struct + { + u32 HLW : 10; // Halfline Width (W*16 = Width (720)) + u32 : 6; + u32 HCE : 7; // Horizontal Sync Start to Color Burst End + u32 : 1; + u32 HCS : 7; // Horizontal Sync Start to Color Burst Start + u32 : 1; + }; }; -union UVIHorizontalTiming1 -{ - u32 Hex; - struct { u16 Lo, Hi; }; - struct - { - u32 HSY : 7; // Horizontal Sync Width - u32 HBE640 : 10; // Horizontal Sync Start to horizontal blank end - u32 HBS640 : 10; // Half line to horizontal blanking start - u32 : 5; - }; +union UVIHorizontalTiming1 { + u32 Hex; + struct + { + u16 Lo, Hi; + }; + struct + { + u32 HSY : 7; // Horizontal Sync Width + u32 HBE640 : 10; // Horizontal Sync Start to horizontal blank end + u32 HBS640 : 10; // Half line to horizontal blanking start + u32 : 5; + }; }; // Exists for both odd and even fields -union UVIVBlankTimingRegister -{ - u32 Hex; - struct { u16 Lo, Hi; }; - struct - { - u32 PRB : 10; // Pre-blanking in half lines - u32 : 6; - u32 PSB : 10; // Post blanking in half lines - u32 : 6; - }; +union UVIVBlankTimingRegister { + u32 Hex; + struct + { + u16 Lo, Hi; + }; + struct + { + u32 PRB : 10; // Pre-blanking in half lines + u32 : 6; + u32 PSB : 10; // Post blanking in half lines + u32 : 6; + }; }; // Exists for both odd and even fields -union UVIBurstBlankingRegister -{ - u32 Hex; - struct { u16 Lo, Hi; }; - struct - { - u32 BS0 : 5; // Field x start to burst blanking start in halflines - u32 BE0 : 11; // Field x start to burst blanking end in halflines - u32 BS2 : 5; // Field x+2 start to burst blanking start in halflines - u32 BE2 : 11; // Field x+2 start to burst blanking end in halflines - }; +union UVIBurstBlankingRegister { + u32 Hex; + struct + { + u16 Lo, Hi; + }; + struct + { + u32 BS0 : 5; // Field x start to burst blanking start in halflines + u32 BE0 : 11; // Field x start to burst blanking end in halflines + u32 BS2 : 5; // Field x+2 start to burst blanking start in halflines + u32 BE2 : 11; // Field x+2 start to burst blanking end in halflines + }; }; -union UVIFBInfoRegister -{ - u32 Hex; - struct { u16 Lo, Hi; }; - struct - { - // TODO: mask out lower 9bits/align to 9bits??? - u32 FBB : 24; // Base address of the framebuffer in external mem - // POFF only seems to exist in the top reg. XOFF, unknown. - u32 XOFF : 4; // Horizontal Offset of the left-most pixel within the first word of the fetched picture - u32 POFF : 1; // Page offest: 1: fb address is (address>>5) - u32 CLRPOFF : 3; // ? setting bit 31 clears POFF - }; +union UVIFBInfoRegister { + u32 Hex; + struct + { + u16 Lo, Hi; + }; + struct + { + // TODO: mask out lower 9bits/align to 9bits??? + u32 FBB : 24; // Base address of the framebuffer in external mem + // POFF only seems to exist in the top reg. XOFF, unknown. + u32 XOFF : 4; // Horizontal Offset of the left-most pixel within the first word of the fetched + // picture + u32 POFF : 1; // Page offest: 1: fb address is (address>>5) + u32 CLRPOFF : 3; // ? setting bit 31 clears POFF + }; }; // VI Interrupt Register -union UVIInterruptRegister -{ - u32 Hex; - struct { u16 Lo, Hi; }; - struct - { - u32 HCT : 11; // Horizontal Position - u32 : 5; - u32 VCT : 11; // Vertical Position - u32 : 1; - u32 IR_MASK : 1; // Interrupt Mask Bit - u32 : 2; - u32 IR_INT : 1; // Interrupt Status (1=Active, 0=Clear) - }; +union UVIInterruptRegister { + u32 Hex; + struct + { + u16 Lo, Hi; + }; + struct + { + u32 HCT : 11; // Horizontal Position + u32 : 5; + u32 VCT : 11; // Vertical Position + u32 : 1; + u32 IR_MASK : 1; // Interrupt Mask Bit + u32 : 2; + u32 IR_INT : 1; // Interrupt Status (1=Active, 0=Clear) + }; }; -union UVILatchRegister -{ - u32 Hex; - struct { u16 Lo, Hi; }; - struct - { - u32 HCT : 11; // Horizontal Count - u32 : 5; - u32 VCT : 11; // Vertical Count - u32 : 4; - u32 TRG : 1; // Trigger Flag - }; +union UVILatchRegister { + u32 Hex; + struct + { + u16 Lo, Hi; + }; + struct + { + u32 HCT : 11; // Horizontal Count + u32 : 5; + u32 VCT : 11; // Vertical Count + u32 : 4; + u32 TRG : 1; // Trigger Flag + }; }; -union PictureConfigurationRegister -{ - u16 Hex; - struct - { - u16 STD : 8; - u16 WPL : 7; - u16 : 1; - }; +union PictureConfigurationRegister { + u16 Hex; + struct + { + u16 STD : 8; + u16 WPL : 7; + u16 : 1; + }; }; -union UVIHorizontalScaling -{ - u16 Hex; - struct - { - u16 STP : 9; // Horizontal stepping size (U1.8 Scaler Value) (0x160 Works for 320) - u16 : 3; - u16 HS_EN : 1; // Enable Horizontal Scaling - u16 : 3; - }; - UVIHorizontalScaling(u16 _hex) { Hex = _hex;} - UVIHorizontalScaling() { Hex = 0;} +union UVIHorizontalScaling { + u16 Hex; + struct + { + u16 STP : 9; // Horizontal stepping size (U1.8 Scaler Value) (0x160 Works for 320) + u16 : 3; + u16 HS_EN : 1; // Enable Horizontal Scaling + u16 : 3; + }; + UVIHorizontalScaling(u16 _hex) { Hex = _hex; } + UVIHorizontalScaling() { Hex = 0; } }; // Used for tables 0-2 -union UVIFilterCoefTable3 -{ - u32 Hex; - struct { u16 Lo, Hi; }; - struct - { - u32 Tap0 : 10; - u32 Tap1 : 10; - u32 Tap2 : 10; - u32 : 2; - }; +union UVIFilterCoefTable3 { + u32 Hex; + struct + { + u16 Lo, Hi; + }; + struct + { + u32 Tap0 : 10; + u32 Tap1 : 10; + u32 Tap2 : 10; + u32 : 2; + }; }; // Used for tables 3-6 -union UVIFilterCoefTable4 -{ - u32 Hex; - struct { u16 Lo, Hi; }; - struct - { - u32 Tap0 : 8; - u32 Tap1 : 8; - u32 Tap2 : 8; - u32 Tap3 : 8; - }; +union UVIFilterCoefTable4 { + u32 Hex; + struct + { + u16 Lo, Hi; + }; + struct + { + u32 Tap0 : 8; + u32 Tap1 : 8; + u32 Tap2 : 8; + u32 Tap3 : 8; + }; }; struct SVIFilterCoefTables { - UVIFilterCoefTable3 Tables02[3]; - UVIFilterCoefTable4 Tables36[4]; + UVIFilterCoefTable3 Tables02[3]; + UVIFilterCoefTable4 Tables36[4]; }; // Debug video mode only, probably never used in Dolphin... -union UVIBorderBlankRegister -{ - u32 Hex; - struct { u16 Lo, Hi; }; - struct - { - u32 HBE656 : 10; // Border Horizontal Blank End - u32 : 11; - u32 HBS656 : 10; // Border Horizontal Blank start - u32 BRDR_EN : 1; // Border Enable - }; +union UVIBorderBlankRegister { + u32 Hex; + struct + { + u16 Lo, Hi; + }; + struct + { + u32 HBE656 : 10; // Border Horizontal Blank End + u32 : 11; + u32 HBS656 : 10; // Border Horizontal Blank start + u32 BRDR_EN : 1; // Border Enable + }; }; // ntsc-j and component cable bits -union UVIDTVStatus -{ - u16 Hex; - struct - { - u16 component_plugged : 1; - u16 ntsc_j : 1; - u16 :14; - }; +union UVIDTVStatus { + u16 Hex; + struct + { + u16 component_plugged : 1; + u16 ntsc_j : 1; + u16 : 14; + }; }; -union UVIHorizontalStepping -{ - u16 Hex; - struct - { - u16 srcwidth : 10; - u16 : 6; - }; +union UVIHorizontalStepping { + u16 Hex; + struct + { + u16 srcwidth : 10; + u16 : 6; + }; }; // For BS2 HLE @@ -310,7 +328,7 @@ void Preset(bool _bNTSC); void Init(); void SetRegionReg(char region); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); void RegisterMMIO(MMIO::Mapping* mmio, u32 base); @@ -333,7 +351,8 @@ u32 GetTicksPerHalfLine(); u32 GetTicksPerField(); // Get the aspect ratio of VI's active area. -// This function only deals with standard aspect ratios. For widescreen aspect ratios, multiply the result by 1.33333.. +// This function only deals with standard aspect ratios. For widescreen aspect ratios, multiply the +// result by 1.33333.. float GetAspectRatio(); -} // namespace VideoInterface +} // namespace VideoInterface diff --git a/Source/Core/Core/HW/WII_IPC.cpp b/Source/Core/Core/HW/WII_IPC.cpp index c1d08ffbb8..646abb778d 100644 --- a/Source/Core/Core/HW/WII_IPC.cpp +++ b/Source/Core/Core/HW/WII_IPC.cpp @@ -2,17 +2,17 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/WII_IPC.h" #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Core/CoreTiming.h" #include "Core/HW/MMIO.h" #include "Core/HW/ProcessorInterface.h" -#include "Core/HW/WII_IPC.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" - -// This is the intercommunication between ARM and PPC. Currently only PPC actually uses it, because of the IOS HLE +// This is the intercommunication between ARM and PPC. Currently only PPC actually uses it, because +// of the IOS HLE // How IOS uses IPC: // X1 Execute command: a new pointer is available in HW_IPC_PPCCTRL // X2 Reload (a new IOS is being loaded, old one doesn't need to reply anymore) @@ -23,66 +23,67 @@ namespace WII_IPCInterface { - enum { - IPC_PPCMSG = 0x00, - IPC_PPCCTRL = 0x04, - IPC_ARMMSG = 0x08, - IPC_ARMCTRL = 0x0c, + IPC_PPCMSG = 0x00, + IPC_PPCCTRL = 0x04, + IPC_ARMMSG = 0x08, + IPC_ARMCTRL = 0x0c, - PPCSPEED = 0x18, - VISOLID = 0x24, + PPCSPEED = 0x18, + VISOLID = 0x24, - PPC_IRQFLAG = 0x30, - PPC_IRQMASK = 0x34, - ARM_IRQFLAG = 0x38, - ARM_IRQMASK = 0x3c, + PPC_IRQFLAG = 0x30, + PPC_IRQMASK = 0x34, + ARM_IRQFLAG = 0x38, + ARM_IRQMASK = 0x3c, - GPIOB_OUT = 0xc0, - GPIOB_DIR = 0xc4, - GPIOB_IN = 0xc8, + GPIOB_OUT = 0xc0, + GPIOB_DIR = 0xc4, + GPIOB_IN = 0xc8, - UNK_180 = 0x180, - UNK_1CC = 0x1cc, - UNK_1D0 = 0x1d0, + UNK_180 = 0x180, + UNK_1CC = 0x1cc, + UNK_1D0 = 0x1d0, }; struct CtrlRegister { - u8 X1 : 1; - u8 X2 : 1; - u8 Y1 : 1; - u8 Y2 : 1; - u8 IX1 : 1; - u8 IX2 : 1; - u8 IY1 : 1; - u8 IY2 : 1; + u8 X1 : 1; + u8 X2 : 1; + u8 Y1 : 1; + u8 Y2 : 1; + u8 IX1 : 1; + u8 IX2 : 1; + u8 IY1 : 1; + u8 IY2 : 1; - CtrlRegister() { X1 = X2 = Y1 = Y2 = IX1 = IX2 = IY1 = IY2 = 0; } + CtrlRegister() { X1 = X2 = Y1 = Y2 = IX1 = IX2 = IY1 = IY2 = 0; } + inline u8 ppc() { return (IY2 << 5) | (IY1 << 4) | (X2 << 3) | (Y1 << 2) | (Y2 << 1) | X1; } + inline u8 arm() { return (IX2 << 5) | (IX1 << 4) | (Y2 << 3) | (X1 << 2) | (X2 << 1) | Y1; } + inline void ppc(u32 v) + { + X1 = v & 1; + X2 = (v >> 3) & 1; + if ((v >> 2) & 1) + Y1 = 0; + if ((v >> 1) & 1) + Y2 = 0; + IY1 = (v >> 4) & 1; + IY2 = (v >> 5) & 1; + } - inline u8 ppc() { return (IY2<<5)|(IY1<<4)|(X2<<3)|(Y1<<2)|(Y2<<1)|X1; } - inline u8 arm() { return (IX2<<5)|(IX1<<4)|(Y2<<3)|(X1<<2)|(X2<<1)|Y1; } - - inline void ppc(u32 v) - { - X1 = v & 1; - X2 = (v >> 3) & 1; - if ((v >> 2) & 1) Y1 = 0; - if ((v >> 1) & 1) Y2 = 0; - IY1 = (v >> 4) & 1; - IY2 = (v >> 5) & 1; - } - - inline void arm(u32 v) - { - Y1 = v & 1; - Y2 = (v >> 3) & 1; - if ((v >> 2) & 1) X1 = 0; - if ((v >> 1) & 1) X2 = 0; - IX1 = (v >> 4) & 1; - IX2 = (v >> 5) & 1; - } + inline void arm(u32 v) + { + Y1 = v & 1; + Y2 = (v >> 3) & 1; + if ((v >> 2) & 1) + X1 = 0; + if ((v >> 1) & 1) + X2 = 0; + IX1 = (v >> 4) & 1; + IX2 = (v >> 5) & 1; + } }; // STATE_TO_SAVE @@ -95,46 +96,46 @@ static u32 ppc_irq_masks; static u32 arm_irq_flags; static u32 arm_irq_masks; -static u32 sensorbar_power; // do we need to care about this? +static u32 sensorbar_power; // do we need to care about this? static int updateInterrupts; static void UpdateInterrupts(u64 = 0, s64 cyclesLate = 0); -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - p.Do(ppc_msg); - p.Do(arm_msg); - p.DoPOD(ctrl); - p.Do(ppc_irq_flags); - p.Do(ppc_irq_masks); - p.Do(arm_irq_flags); - p.Do(arm_irq_masks); - p.Do(sensorbar_power); + p.Do(ppc_msg); + p.Do(arm_msg); + p.DoPOD(ctrl); + p.Do(ppc_irq_flags); + p.Do(ppc_irq_masks); + p.Do(arm_irq_flags); + p.Do(arm_irq_masks); + p.Do(sensorbar_power); } void Init() { - ctrl = CtrlRegister(); - ppc_msg = 0; - arm_msg = 0; + ctrl = CtrlRegister(); + ppc_msg = 0; + arm_msg = 0; - ppc_irq_flags = 0; - ppc_irq_masks = 0; - arm_irq_flags = 0; - arm_irq_masks = 0; + ppc_irq_flags = 0; + ppc_irq_masks = 0; + arm_irq_flags = 0; + arm_irq_masks = 0; - sensorbar_power = 0; + sensorbar_power = 0; - ppc_irq_masks |= INT_CAUSE_IPC_BROADWAY; + ppc_irq_masks |= INT_CAUSE_IPC_BROADWAY; - updateInterrupts = CoreTiming::RegisterEvent("IPCInterrupt", UpdateInterrupts); + updateInterrupts = CoreTiming::RegisterEvent("IPCInterrupt", UpdateInterrupts); } void Reset() { - INFO_LOG(WII_IPC, "Resetting ..."); - Init(); - WII_IPC_HLE_Interface::Reset(); + INFO_LOG(WII_IPC, "Resetting ..."); + Init(); + WII_IPC_HLE_Interface::Reset(); } void Shutdown() @@ -143,101 +144,85 @@ void Shutdown() void RegisterMMIO(MMIO::Mapping* mmio, u32 base) { - mmio->Register(base | IPC_PPCMSG, - MMIO::InvalidRead(), - MMIO::DirectWrite(&ppc_msg) - ); + mmio->Register(base | IPC_PPCMSG, MMIO::InvalidRead(), MMIO::DirectWrite(&ppc_msg)); - mmio->Register(base | IPC_PPCCTRL, - MMIO::ComplexRead([](u32) { - return ctrl.ppc(); - }), - MMIO::ComplexWrite([](u32, u32 val) { - ctrl.ppc(val); - if (ctrl.X1) - WII_IPC_HLE_Interface::EnqueueRequest(ppc_msg); - WII_IPC_HLE_Interface::Update(); - CoreTiming::ScheduleEvent(0, updateInterrupts, 0); - }) - ); + mmio->Register(base | IPC_PPCCTRL, MMIO::ComplexRead([](u32) { return ctrl.ppc(); }), + MMIO::ComplexWrite([](u32, u32 val) { + ctrl.ppc(val); + if (ctrl.X1) + WII_IPC_HLE_Interface::EnqueueRequest(ppc_msg); + WII_IPC_HLE_Interface::Update(); + CoreTiming::ScheduleEvent(0, updateInterrupts, 0); + })); - mmio->Register(base | IPC_ARMMSG, - MMIO::DirectRead(&arm_msg), - MMIO::InvalidWrite() - ); + mmio->Register(base | IPC_ARMMSG, MMIO::DirectRead(&arm_msg), MMIO::InvalidWrite()); - mmio->Register(base | PPC_IRQFLAG, - MMIO::InvalidRead(), - MMIO::ComplexWrite([](u32, u32 val) { - ppc_irq_flags &= ~val; - WII_IPC_HLE_Interface::Update(); - CoreTiming::ScheduleEvent(0, updateInterrupts, 0); - }) - ); + mmio->Register(base | PPC_IRQFLAG, MMIO::InvalidRead(), + MMIO::ComplexWrite([](u32, u32 val) { + ppc_irq_flags &= ~val; + WII_IPC_HLE_Interface::Update(); + CoreTiming::ScheduleEvent(0, updateInterrupts, 0); + })); - mmio->Register(base | PPC_IRQMASK, - MMIO::InvalidRead(), - MMIO::ComplexWrite([](u32, u32 val) { - ppc_irq_masks = val; - if (ppc_irq_masks & INT_CAUSE_IPC_BROADWAY) // wtf? - Reset(); - WII_IPC_HLE_Interface::Update(); - CoreTiming::ScheduleEvent(0, updateInterrupts, 0); - }) - ); + mmio->Register(base | PPC_IRQMASK, MMIO::InvalidRead(), + MMIO::ComplexWrite([](u32, u32 val) { + ppc_irq_masks = val; + if (ppc_irq_masks & INT_CAUSE_IPC_BROADWAY) // wtf? + Reset(); + WII_IPC_HLE_Interface::Update(); + CoreTiming::ScheduleEvent(0, updateInterrupts, 0); + })); - mmio->Register(base | GPIOB_OUT, - MMIO::Constant(0), - MMIO::DirectWrite(&sensorbar_power) - ); + mmio->Register(base | GPIOB_OUT, MMIO::Constant(0), + MMIO::DirectWrite(&sensorbar_power)); - // Register some stubbed/unknown MMIOs required to make Wii games work. - mmio->Register(base | PPCSPEED, MMIO::InvalidRead(), MMIO::Nop()); - mmio->Register(base | VISOLID, MMIO::InvalidRead(), MMIO::Nop()); - mmio->Register(base | GPIOB_DIR, MMIO::Constant(0), MMIO::Nop()); - mmio->Register(base | GPIOB_IN, MMIO::Constant(0), MMIO::Nop()); - mmio->Register(base | UNK_180, MMIO::Constant(0), MMIO::Nop()); - mmio->Register(base | UNK_1CC, MMIO::Constant(0), MMIO::Nop()); - mmio->Register(base | UNK_1D0, MMIO::Constant(0), MMIO::Nop()); + // Register some stubbed/unknown MMIOs required to make Wii games work. + mmio->Register(base | PPCSPEED, MMIO::InvalidRead(), MMIO::Nop()); + mmio->Register(base | VISOLID, MMIO::InvalidRead(), MMIO::Nop()); + mmio->Register(base | GPIOB_DIR, MMIO::Constant(0), MMIO::Nop()); + mmio->Register(base | GPIOB_IN, MMIO::Constant(0), MMIO::Nop()); + mmio->Register(base | UNK_180, MMIO::Constant(0), MMIO::Nop()); + mmio->Register(base | UNK_1CC, MMIO::Constant(0), MMIO::Nop()); + mmio->Register(base | UNK_1D0, MMIO::Constant(0), MMIO::Nop()); } static void UpdateInterrupts(u64 userdata, s64 cyclesLate) { - if ((ctrl.Y1 & ctrl.IY1) || (ctrl.Y2 & ctrl.IY2)) - { - ppc_irq_flags |= INT_CAUSE_IPC_BROADWAY; - } + if ((ctrl.Y1 & ctrl.IY1) || (ctrl.Y2 & ctrl.IY2)) + { + ppc_irq_flags |= INT_CAUSE_IPC_BROADWAY; + } - if ((ctrl.X1 & ctrl.IX1) || (ctrl.X2 & ctrl.IX2)) - { - ppc_irq_flags |= INT_CAUSE_IPC_STARLET; - } + if ((ctrl.X1 & ctrl.IX1) || (ctrl.X2 & ctrl.IX2)) + { + ppc_irq_flags |= INT_CAUSE_IPC_STARLET; + } - // Generate interrupt on PI if any of the devices behind starlet have an interrupt and mask is set - ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_WII_IPC, !!(ppc_irq_flags & ppc_irq_masks)); + // Generate interrupt on PI if any of the devices behind starlet have an interrupt and mask is set + ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_WII_IPC, + !!(ppc_irq_flags & ppc_irq_masks)); } void GenerateAck(u32 _Address) { - arm_msg = _Address; // dunno if it's really set here, but HLE needs to stay in context - ctrl.Y2 = 1; - INFO_LOG(WII_IPC, "GenerateAck: %08x | %08x [R:%i A:%i E:%i]", - ppc_msg,_Address, ctrl.Y1, ctrl.Y2, ctrl.X1); - CoreTiming::ScheduleEvent(1000, updateInterrupts, 0); + arm_msg = _Address; // dunno if it's really set here, but HLE needs to stay in context + ctrl.Y2 = 1; + INFO_LOG(WII_IPC, "GenerateAck: %08x | %08x [R:%i A:%i E:%i]", ppc_msg, _Address, ctrl.Y1, + ctrl.Y2, ctrl.X1); + CoreTiming::ScheduleEvent(1000, updateInterrupts, 0); } void GenerateReply(u32 _Address) { - arm_msg = _Address; - ctrl.Y1 = 1; - INFO_LOG(WII_IPC, "GenerateReply: %08x | %08x [R:%i A:%i E:%i]", - ppc_msg,_Address, ctrl.Y1, ctrl.Y2, ctrl.X1); - UpdateInterrupts(); + arm_msg = _Address; + ctrl.Y1 = 1; + INFO_LOG(WII_IPC, "GenerateReply: %08x | %08x [R:%i A:%i E:%i]", ppc_msg, _Address, ctrl.Y1, + ctrl.Y2, ctrl.X1); + UpdateInterrupts(); } bool IsReady() { - return ((ctrl.Y1 == 0) && (ctrl.Y2 == 0) && ((ppc_irq_flags & INT_CAUSE_IPC_BROADWAY) == 0)); + return ((ctrl.Y1 == 0) && (ctrl.Y2 == 0) && ((ppc_irq_flags & INT_CAUSE_IPC_BROADWAY) == 0)); } - } diff --git a/Source/Core/Core/HW/WII_IPC.h b/Source/Core/Core/HW/WII_IPC.h index 420faa69c3..99db2597fc 100644 --- a/Source/Core/Core/HW/WII_IPC.h +++ b/Source/Core/Core/HW/WII_IPC.h @@ -7,36 +7,38 @@ #include "Common/CommonTypes.h" class PointerWrap; -namespace MMIO { class Mapping; } +namespace MMIO +{ +class Mapping; +} namespace WII_IPCInterface { - enum StarletInterruptCause { - INT_CAUSE_TIMER = 0x1, - INT_CAUSE_NAND = 0x2, - INT_CAUSE_AES = 0x4, - INT_CAUSE_SHA1 = 0x8, - INT_CAUSE_EHCI = 0x10, - INT_CAUSE_OHCI0 = 0x20, - INT_CAUSE_OHCI1 = 0x40, - INT_CAUSE_SD = 0x80, - INT_CAUSE_WIFI = 0x100, + INT_CAUSE_TIMER = 0x1, + INT_CAUSE_NAND = 0x2, + INT_CAUSE_AES = 0x4, + INT_CAUSE_SHA1 = 0x8, + INT_CAUSE_EHCI = 0x10, + INT_CAUSE_OHCI0 = 0x20, + INT_CAUSE_OHCI1 = 0x40, + INT_CAUSE_SD = 0x80, + INT_CAUSE_WIFI = 0x100, - INT_CAUSE_GPIO_BROADWAY = 0x400, - INT_CAUSE_GPIO_STARLET = 0x800, + INT_CAUSE_GPIO_BROADWAY = 0x400, + INT_CAUSE_GPIO_STARLET = 0x800, - INT_CAUSE_RST_BUTTON = 0x40000, + INT_CAUSE_RST_BUTTON = 0x40000, - INT_CAUSE_IPC_BROADWAY = 0x40000000, - INT_CAUSE_IPC_STARLET = 0x80000000 + INT_CAUSE_IPC_BROADWAY = 0x40000000, + INT_CAUSE_IPC_STARLET = 0x80000000 }; void Init(); void Reset(); void Shutdown(); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); void RegisterMMIO(MMIO::Mapping* mmio, u32 base); @@ -44,5 +46,4 @@ void GenerateAck(u32 _Address); void GenerateReply(u32 _Address); bool IsReady(); - } diff --git a/Source/Core/Core/HW/WiiSaveCrypted.cpp b/Source/Core/Core/HW/WiiSaveCrypted.cpp index 84837e4a22..42b4155ec2 100644 --- a/Source/Core/Core/HW/WiiSaveCrypted.cpp +++ b/Source/Core/Core/HW/WiiSaveCrypted.cpp @@ -11,653 +11,648 @@ #include #include #include -#include -#include -#include #include #include #include +#include +#include +#include #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" +#include "Common/Crypto/ec.h" #include "Common/FileUtil.h" +#include "Common/Logging/Log.h" #include "Common/MathUtil.h" #include "Common/MsgHandler.h" #include "Common/NandPaths.h" #include "Common/StringUtil.h" -#include "Common/Crypto/ec.h" -#include "Common/Logging/Log.h" #include "Core/HW/WiiSaveCrypted.h" static Common::replace_v replacements; -const u8 CWiiSaveCrypted::s_sd_key[16] = { - 0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08, - 0xAF, 0xBA, 0xD8, 0x4D, 0xBF, 0xC2, 0xA5, 0x5D -}; -const u8 CWiiSaveCrypted::s_md5_blanker[16] = { - 0x0E, 0x65, 0x37, 0x81, 0x99, 0xBE, 0x45, 0x17, - 0xAB, 0x06, 0xEC, 0x22, 0x45, 0x1A, 0x57, 0x93 -}; +const u8 CWiiSaveCrypted::s_sd_key[16] = {0xAB, 0x01, 0xB9, 0xD8, 0xE1, 0x62, 0x2B, 0x08, + 0xAF, 0xBA, 0xD8, 0x4D, 0xBF, 0xC2, 0xA5, 0x5D}; +const u8 CWiiSaveCrypted::s_md5_blanker[16] = {0x0E, 0x65, 0x37, 0x81, 0x99, 0xBE, 0x45, 0x17, + 0xAB, 0x06, 0xEC, 0x22, 0x45, 0x1A, 0x57, 0x93}; const u32 CWiiSaveCrypted::s_ng_id = 0x0403AC68; bool CWiiSaveCrypted::ImportWiiSave(const std::string& filename) { - CWiiSaveCrypted save_file(filename); - return save_file.m_valid; + CWiiSaveCrypted save_file(filename); + return save_file.m_valid; } bool CWiiSaveCrypted::ExportWiiSave(u64 title_id) { - CWiiSaveCrypted export_save("", title_id); - if (export_save.m_valid) - { - SuccessAlertT("Successfully exported file to %s", - export_save.m_encrypted_save_path.c_str()); - } - else - { - PanicAlertT("Export failed"); - } - return export_save.m_valid; + CWiiSaveCrypted export_save("", title_id); + if (export_save.m_valid) + { + SuccessAlertT("Successfully exported file to %s", export_save.m_encrypted_save_path.c_str()); + } + else + { + PanicAlertT("Export failed"); + } + return export_save.m_valid; } void CWiiSaveCrypted::ExportAllSaves() { - std::string title_folder = File::GetUserPath(D_WIIROOT_IDX) + "/title"; - std::vector titles; - const u32 path_mask = 0x00010000; - for (int i = 0; i < 8; ++i) - { - std::string folder = StringFromFormat("%s/%08x/", title_folder.c_str(), path_mask | i); - File::FSTEntry fst_tmp = File::ScanDirectoryTree(folder, false); + std::string title_folder = File::GetUserPath(D_WIIROOT_IDX) + "/title"; + std::vector titles; + const u32 path_mask = 0x00010000; + for (int i = 0; i < 8; ++i) + { + std::string folder = StringFromFormat("%s/%08x/", title_folder.c_str(), path_mask | i); + File::FSTEntry fst_tmp = File::ScanDirectoryTree(folder, false); - for (const File::FSTEntry& entry : fst_tmp.children) - { - if (entry.isDirectory) - { - u32 game_id; - if (AsciiToHex(entry.virtualName, game_id)) - { - std::string banner_path = - StringFromFormat("%s%08x/data/banner.bin", folder.c_str(), game_id); - if (File::Exists(banner_path)) - { - u64 title_id = (((u64)path_mask | i) << 32) | game_id; - titles.push_back(title_id); - } - } - } - } - } - SuccessAlertT("Found %zu save files", titles.size()); - u32 success = 0; - for (const u64& title : titles) - { - CWiiSaveCrypted* export_save = new CWiiSaveCrypted("", title); - if (export_save->m_valid) - success++; - delete export_save; - } - SuccessAlertT("Successfully exported %u saves to %s", success, - (File::GetUserPath(D_USER_IDX) + "private/wii/title/").c_str()); + for (const File::FSTEntry& entry : fst_tmp.children) + { + if (entry.isDirectory) + { + u32 game_id; + if (AsciiToHex(entry.virtualName, game_id)) + { + std::string banner_path = + StringFromFormat("%s%08x/data/banner.bin", folder.c_str(), game_id); + if (File::Exists(banner_path)) + { + u64 title_id = (((u64)path_mask | i) << 32) | game_id; + titles.push_back(title_id); + } + } + } + } + } + SuccessAlertT("Found %zu save files", titles.size()); + u32 success = 0; + for (const u64& title : titles) + { + CWiiSaveCrypted* export_save = new CWiiSaveCrypted("", title); + if (export_save->m_valid) + success++; + delete export_save; + } + SuccessAlertT("Successfully exported %u saves to %s", success, + (File::GetUserPath(D_USER_IDX) + "private/wii/title/").c_str()); } CWiiSaveCrypted::CWiiSaveCrypted(const std::string& filename, u64 title_id) - : m_encrypted_save_path(filename), m_title_id(title_id) + : m_encrypted_save_path(filename), m_title_id(title_id) { - Common::ReadReplacements(replacements); - memcpy(m_sd_iv, "\x21\x67\x12\xE6\xAA\x1F\x68\x9F\x95\xC5\xA2\x23\x24\xDC\x6A\x98", 0x10); + Common::ReadReplacements(replacements); + memcpy(m_sd_iv, "\x21\x67\x12\xE6\xAA\x1F\x68\x9F\x95\xC5\xA2\x23\x24\xDC\x6A\x98", 0x10); - if (!title_id) // Import - { - mbedtls_aes_setkey_dec(&m_aes_ctx, s_sd_key, 128); - m_valid = true; - ReadHDR(); - ReadBKHDR(); - ImportWiiSaveFiles(); - // TODO: check_sig() - if (m_valid) - { - SuccessAlertT("Successfully imported save files"); - } - else - { - PanicAlertT("Import failed"); - } - } - else - { - mbedtls_aes_setkey_enc(&m_aes_ctx, s_sd_key, 128); + if (!title_id) // Import + { + mbedtls_aes_setkey_dec(&m_aes_ctx, s_sd_key, 128); + m_valid = true; + ReadHDR(); + ReadBKHDR(); + ImportWiiSaveFiles(); + // TODO: check_sig() + if (m_valid) + { + SuccessAlertT("Successfully imported save files"); + } + else + { + PanicAlertT("Import failed"); + } + } + else + { + mbedtls_aes_setkey_enc(&m_aes_ctx, s_sd_key, 128); - if (getPaths(true)) - { - m_valid = true; - WriteHDR(); - WriteBKHDR(); - ExportWiiSaveFiles(); - do_sig(); - } - } + if (getPaths(true)) + { + m_valid = true; + WriteHDR(); + WriteBKHDR(); + ExportWiiSaveFiles(); + do_sig(); + } + } } void CWiiSaveCrypted::ReadHDR() { - File::IOFile data_file(m_encrypted_save_path, "rb"); - if (!data_file) - { - ERROR_LOG(CONSOLE, "Cannot open %s", m_encrypted_save_path.c_str()); - m_valid = false; - return; - } - if (!data_file.ReadBytes(&m_encrypted_header, HEADER_SZ)) - { - ERROR_LOG(CONSOLE, "Failed to read header"); - m_valid = false; - return; - } - data_file.Close(); + File::IOFile data_file(m_encrypted_save_path, "rb"); + if (!data_file) + { + ERROR_LOG(CONSOLE, "Cannot open %s", m_encrypted_save_path.c_str()); + m_valid = false; + return; + } + if (!data_file.ReadBytes(&m_encrypted_header, HEADER_SZ)) + { + ERROR_LOG(CONSOLE, "Failed to read header"); + m_valid = false; + return; + } + data_file.Close(); - mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, HEADER_SZ, m_sd_iv, (const u8*)&m_encrypted_header, - (u8*)&m_header); - u32 banner_size = Common::swap32(m_header.hdr.BannerSize); - if ((banner_size < FULL_BNR_MIN) || (banner_size > FULL_BNR_MAX) || - (((banner_size - BNR_SZ) % ICON_SZ) != 0)) - { - ERROR_LOG(CONSOLE, "Not a Wii save or read failure for file header size %x", banner_size); - m_valid = false; - return; - } - m_title_id = Common::swap64(m_header.hdr.SaveGameTitle); + mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, HEADER_SZ, m_sd_iv, + (const u8*)&m_encrypted_header, (u8*)&m_header); + u32 banner_size = Common::swap32(m_header.hdr.BannerSize); + if ((banner_size < FULL_BNR_MIN) || (banner_size > FULL_BNR_MAX) || + (((banner_size - BNR_SZ) % ICON_SZ) != 0)) + { + ERROR_LOG(CONSOLE, "Not a Wii save or read failure for file header size %x", banner_size); + m_valid = false; + return; + } + m_title_id = Common::swap64(m_header.hdr.SaveGameTitle); + u8 md5_file[16]; + u8 md5_calc[16]; + memcpy(md5_file, m_header.hdr.Md5, 0x10); + memcpy(m_header.hdr.Md5, s_md5_blanker, 0x10); + mbedtls_md5((u8*)&m_header, HEADER_SZ, md5_calc); + if (memcmp(md5_file, md5_calc, 0x10)) + { + ERROR_LOG(CONSOLE, "MD5 mismatch\n %016" PRIx64 "%016" PRIx64 " != %016" PRIx64 "%016" PRIx64, + Common::swap64(md5_file), Common::swap64(md5_file + 8), Common::swap64(md5_calc), + Common::swap64(md5_calc + 8)); + m_valid = false; + } - u8 md5_file[16]; - u8 md5_calc[16]; - memcpy(md5_file, m_header.hdr.Md5, 0x10); - memcpy(m_header.hdr.Md5, s_md5_blanker, 0x10); - mbedtls_md5((u8*)&m_header, HEADER_SZ, md5_calc); - if (memcmp(md5_file, md5_calc, 0x10)) - { - ERROR_LOG(CONSOLE, "MD5 mismatch\n %016" PRIx64 "%016" PRIx64 " != %016" PRIx64 "%016" PRIx64, - Common::swap64(md5_file),Common::swap64(md5_file + 8), Common::swap64(md5_calc), - Common::swap64(md5_calc + 8)); - m_valid= false; - } - - if (!getPaths()) - { - m_valid = false; - return; - } - std::string banner_file_path = m_wii_title_path + "banner.bin"; - if (!File::Exists(banner_file_path) || - AskYesNoT("%s already exists, overwrite?", banner_file_path.c_str())) - { - INFO_LOG(CONSOLE, "Creating file %s", banner_file_path.c_str()); - File::IOFile banner_file(banner_file_path, "wb"); - banner_file.WriteBytes(m_header.BNR, banner_size); - } + if (!getPaths()) + { + m_valid = false; + return; + } + std::string banner_file_path = m_wii_title_path + "banner.bin"; + if (!File::Exists(banner_file_path) || + AskYesNoT("%s already exists, overwrite?", banner_file_path.c_str())) + { + INFO_LOG(CONSOLE, "Creating file %s", banner_file_path.c_str()); + File::IOFile banner_file(banner_file_path, "wb"); + banner_file.WriteBytes(m_header.BNR, banner_size); + } } void CWiiSaveCrypted::WriteHDR() { - if (!m_valid) return; - memset(&m_header, 0, HEADER_SZ); + if (!m_valid) + return; + memset(&m_header, 0, HEADER_SZ); - std::string banner_file_path = m_wii_title_path + "banner.bin"; - u32 banner_size = static_cast(File::GetSize(banner_file_path)); - m_header.hdr.BannerSize = Common::swap32(banner_size); + std::string banner_file_path = m_wii_title_path + "banner.bin"; + u32 banner_size = static_cast(File::GetSize(banner_file_path)); + m_header.hdr.BannerSize = Common::swap32(banner_size); - m_header.hdr.SaveGameTitle = Common::swap64(m_title_id); - memcpy(m_header.hdr.Md5, s_md5_blanker, 0x10); - m_header.hdr.Permissions = 0x3C; + m_header.hdr.SaveGameTitle = Common::swap64(m_title_id); + memcpy(m_header.hdr.Md5, s_md5_blanker, 0x10); + m_header.hdr.Permissions = 0x3C; - File::IOFile banner_file(banner_file_path, "rb"); - if (!banner_file.ReadBytes(m_header.BNR, banner_size)) - { - ERROR_LOG(CONSOLE, "Failed to read banner.bin"); - m_valid = false; - return; - } - // remove nocopy flag - m_header.BNR[7] &= ~1; + File::IOFile banner_file(banner_file_path, "rb"); + if (!banner_file.ReadBytes(m_header.BNR, banner_size)) + { + ERROR_LOG(CONSOLE, "Failed to read banner.bin"); + m_valid = false; + return; + } + // remove nocopy flag + m_header.BNR[7] &= ~1; - u8 md5_calc[16]; - mbedtls_md5((u8*)&m_header, HEADER_SZ, md5_calc); - memcpy(m_header.hdr.Md5, md5_calc, 0x10); + u8 md5_calc[16]; + mbedtls_md5((u8*)&m_header, HEADER_SZ, md5_calc); + memcpy(m_header.hdr.Md5, md5_calc, 0x10); - mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_ENCRYPT, HEADER_SZ, m_sd_iv, (const u8*)&m_header, - (u8*)&m_encrypted_header); + mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_ENCRYPT, HEADER_SZ, m_sd_iv, (const u8*)&m_header, + (u8*)&m_encrypted_header); - File::IOFile data_file(m_encrypted_save_path, "wb"); - if (!data_file.WriteBytes(&m_encrypted_header, HEADER_SZ)) - { - ERROR_LOG(CONSOLE, "Failed to write header for %s", m_encrypted_save_path.c_str()); - m_valid = false; - } + File::IOFile data_file(m_encrypted_save_path, "wb"); + if (!data_file.WriteBytes(&m_encrypted_header, HEADER_SZ)) + { + ERROR_LOG(CONSOLE, "Failed to write header for %s", m_encrypted_save_path.c_str()); + m_valid = false; + } } - - void CWiiSaveCrypted::ReadBKHDR() { - if (!m_valid) return; + if (!m_valid) + return; - File::IOFile fpData_bin(m_encrypted_save_path, "rb"); - if (!fpData_bin) - { - ERROR_LOG(CONSOLE, "Cannot open %s", m_encrypted_save_path.c_str()); - m_valid = false; - return; - } - fpData_bin.Seek(HEADER_SZ, SEEK_SET); - if (!fpData_bin.ReadBytes(&m_bk_hdr, BK_SZ)) - { - ERROR_LOG(CONSOLE, "Failed to read bk header"); - m_valid = false; - return; - } - fpData_bin.Close(); + File::IOFile fpData_bin(m_encrypted_save_path, "rb"); + if (!fpData_bin) + { + ERROR_LOG(CONSOLE, "Cannot open %s", m_encrypted_save_path.c_str()); + m_valid = false; + return; + } + fpData_bin.Seek(HEADER_SZ, SEEK_SET); + if (!fpData_bin.ReadBytes(&m_bk_hdr, BK_SZ)) + { + ERROR_LOG(CONSOLE, "Failed to read bk header"); + m_valid = false; + return; + } + fpData_bin.Close(); - if (m_bk_hdr.size != Common::swap32(BK_LISTED_SZ) || - m_bk_hdr.magic != Common::swap32(BK_HDR_MAGIC)) - { - ERROR_LOG(CONSOLE, "Invalid Size(%x) or Magic word (%x)", m_bk_hdr.size, m_bk_hdr.magic); - m_valid = false; - return; - } + if (m_bk_hdr.size != Common::swap32(BK_LISTED_SZ) || + m_bk_hdr.magic != Common::swap32(BK_HDR_MAGIC)) + { + ERROR_LOG(CONSOLE, "Invalid Size(%x) or Magic word (%x)", m_bk_hdr.size, m_bk_hdr.magic); + m_valid = false; + return; + } - m_files_list_size = Common::swap32(m_bk_hdr.numberOfFiles); - m_size_of_files = Common::swap32(m_bk_hdr.sizeOfFiles); - m_total_size = Common::swap32(m_bk_hdr.totalSize); + m_files_list_size = Common::swap32(m_bk_hdr.numberOfFiles); + m_size_of_files = Common::swap32(m_bk_hdr.sizeOfFiles); + m_total_size = Common::swap32(m_bk_hdr.totalSize); - if (m_size_of_files + FULL_CERT_SZ != m_total_size) - { - WARN_LOG(CONSOLE, "Size(%x) + cert(%x) does not equal totalsize(%x)", m_size_of_files, - FULL_CERT_SZ, m_total_size); - } - if (m_title_id != Common::swap64(m_bk_hdr.SaveGameTitle)) - { - WARN_LOG(CONSOLE, "Encrypted title (%" PRIx64 ") does not match unencrypted title (%" PRIx64 ")", - m_title_id, Common::swap64(m_bk_hdr.SaveGameTitle)); - } + if (m_size_of_files + FULL_CERT_SZ != m_total_size) + { + WARN_LOG(CONSOLE, "Size(%x) + cert(%x) does not equal totalsize(%x)", m_size_of_files, + FULL_CERT_SZ, m_total_size); + } + if (m_title_id != Common::swap64(m_bk_hdr.SaveGameTitle)) + { + WARN_LOG(CONSOLE, + "Encrypted title (%" PRIx64 ") does not match unencrypted title (%" PRIx64 ")", + m_title_id, Common::swap64(m_bk_hdr.SaveGameTitle)); + } } void CWiiSaveCrypted::WriteBKHDR() { - if (!m_valid) return; - m_files_list_size = 0; - m_size_of_files = 0; + if (!m_valid) + return; + m_files_list_size = 0; + m_size_of_files = 0; - ScanForFiles(m_wii_title_path, m_files_list, &m_files_list_size, &m_size_of_files); - memset(&m_bk_hdr, 0, BK_SZ); - m_bk_hdr.size = Common::swap32(BK_LISTED_SZ); - m_bk_hdr.magic = Common::swap32(BK_HDR_MAGIC); - m_bk_hdr.NGid = s_ng_id; - m_bk_hdr.numberOfFiles = Common::swap32(m_files_list_size); - m_bk_hdr.sizeOfFiles = Common::swap32(m_size_of_files); - m_bk_hdr.totalSize = Common::swap32(m_size_of_files + FULL_CERT_SZ); - m_bk_hdr.SaveGameTitle = Common::swap64(m_title_id); + ScanForFiles(m_wii_title_path, m_files_list, &m_files_list_size, &m_size_of_files); + memset(&m_bk_hdr, 0, BK_SZ); + m_bk_hdr.size = Common::swap32(BK_LISTED_SZ); + m_bk_hdr.magic = Common::swap32(BK_HDR_MAGIC); + m_bk_hdr.NGid = s_ng_id; + m_bk_hdr.numberOfFiles = Common::swap32(m_files_list_size); + m_bk_hdr.sizeOfFiles = Common::swap32(m_size_of_files); + m_bk_hdr.totalSize = Common::swap32(m_size_of_files + FULL_CERT_SZ); + m_bk_hdr.SaveGameTitle = Common::swap64(m_title_id); - File::IOFile data_file(m_encrypted_save_path, "ab"); - if (!data_file.WriteBytes(&m_bk_hdr, BK_SZ)) - { - ERROR_LOG(CONSOLE, "Failed to write bkhdr"); - m_valid = false; - } + File::IOFile data_file(m_encrypted_save_path, "ab"); + if (!data_file.WriteBytes(&m_bk_hdr, BK_SZ)) + { + ERROR_LOG(CONSOLE, "Failed to write bkhdr"); + m_valid = false; + } } void CWiiSaveCrypted::ImportWiiSaveFiles() { - if (!m_valid) return; + if (!m_valid) + return; - File::IOFile data_file(m_encrypted_save_path, "rb"); - if (!data_file) - { - ERROR_LOG(CONSOLE, "Cannot open %s", m_encrypted_save_path.c_str()); - m_valid = false; - return; - } + File::IOFile data_file(m_encrypted_save_path, "rb"); + if (!data_file) + { + ERROR_LOG(CONSOLE, "Cannot open %s", m_encrypted_save_path.c_str()); + m_valid = false; + return; + } - data_file.Seek(HEADER_SZ + BK_SZ, SEEK_SET); + data_file.Seek(HEADER_SZ + BK_SZ, SEEK_SET); - FileHDR file_hdr_tmp; + FileHDR file_hdr_tmp; - for (u32 i = 0; i < m_files_list_size; ++i) - { - memset(&file_hdr_tmp, 0, FILE_HDR_SZ); - memset(m_iv, 0, 0x10); - u32 file_size = 0; + for (u32 i = 0; i < m_files_list_size; ++i) + { + memset(&file_hdr_tmp, 0, FILE_HDR_SZ); + memset(m_iv, 0, 0x10); + u32 file_size = 0; - if (!data_file.ReadBytes(&file_hdr_tmp, FILE_HDR_SZ)) - { - ERROR_LOG(CONSOLE, "Failed to read header for file %d", i); - m_valid = false; - } + if (!data_file.ReadBytes(&file_hdr_tmp, FILE_HDR_SZ)) + { + ERROR_LOG(CONSOLE, "Failed to read header for file %d", i); + m_valid = false; + } - if (Common::swap32(file_hdr_tmp.magic) != FILE_HDR_MAGIC) - { - ERROR_LOG(CONSOLE, "Bad File Header"); - break; - } - else - { - std::string filename((char*)file_hdr_tmp.name); - for (const Common::replace_t& replacement : replacements) - { - for (size_t j = 0; (j = filename.find(replacement.first, j)) != filename.npos; ++j) - filename.replace(j, 1, replacement.second); - } + if (Common::swap32(file_hdr_tmp.magic) != FILE_HDR_MAGIC) + { + ERROR_LOG(CONSOLE, "Bad File Header"); + break; + } + else + { + std::string filename((char*)file_hdr_tmp.name); + for (const Common::replace_t& replacement : replacements) + { + for (size_t j = 0; (j = filename.find(replacement.first, j)) != filename.npos; ++j) + filename.replace(j, 1, replacement.second); + } - std::string file_path_full = m_wii_title_path + filename; - File::CreateFullPath(file_path_full); - if (file_hdr_tmp.type == 1) - { - file_size = Common::swap32(file_hdr_tmp.size); - u32 file_size_rounded = ROUND_UP(file_size, BLOCK_SZ); - std::vector file_data(file_size_rounded); - std::vector file_data_enc(file_size_rounded); + std::string file_path_full = m_wii_title_path + filename; + File::CreateFullPath(file_path_full); + if (file_hdr_tmp.type == 1) + { + file_size = Common::swap32(file_hdr_tmp.size); + u32 file_size_rounded = ROUND_UP(file_size, BLOCK_SZ); + std::vector file_data(file_size_rounded); + std::vector file_data_enc(file_size_rounded); - if (!data_file.ReadBytes(&file_data_enc[0], file_size_rounded)) - { - ERROR_LOG(CONSOLE, "Failed to read data from file %d", i); - m_valid = false; - break; - } + if (!data_file.ReadBytes(&file_data_enc[0], file_size_rounded)) + { + ERROR_LOG(CONSOLE, "Failed to read data from file %d", i); + m_valid = false; + break; + } - memcpy(m_iv, file_hdr_tmp.IV, 0x10); - mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, file_size_rounded, m_iv, - (const u8*)&file_data_enc[0], &file_data[0]); + memcpy(m_iv, file_hdr_tmp.IV, 0x10); + mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_DECRYPT, file_size_rounded, m_iv, + (const u8*)&file_data_enc[0], &file_data[0]); - if (!File::Exists(file_path_full) || - AskYesNoT("%s already exists, overwrite?", file_path_full.c_str())) - { - INFO_LOG(CONSOLE, "Creating file %s", file_path_full.c_str()); + if (!File::Exists(file_path_full) || + AskYesNoT("%s already exists, overwrite?", file_path_full.c_str())) + { + INFO_LOG(CONSOLE, "Creating file %s", file_path_full.c_str()); - File::IOFile raw_save_file(file_path_full, "wb"); - raw_save_file.WriteBytes(&file_data[0], file_size); - } - } - } - } + File::IOFile raw_save_file(file_path_full, "wb"); + raw_save_file.WriteBytes(&file_data[0], file_size); + } + } + } + } } void CWiiSaveCrypted::ExportWiiSaveFiles() { - if (!m_valid) return; + if (!m_valid) + return; - for (u32 i = 0; i < m_files_list_size; i++) - { - FileHDR file_hdr_tmp; - std::string name; - memset(&file_hdr_tmp, 0, FILE_HDR_SZ); + for (u32 i = 0; i < m_files_list_size; i++) + { + FileHDR file_hdr_tmp; + std::string name; + memset(&file_hdr_tmp, 0, FILE_HDR_SZ); - u32 file_size = 0; - if (File::IsDirectory(m_files_list[i])) - { - file_hdr_tmp.type = 2; - } - else - { - file_size = static_cast(File::GetSize(m_files_list[i])); - file_hdr_tmp.type = 1; - } + u32 file_size = 0; + if (File::IsDirectory(m_files_list[i])) + { + file_hdr_tmp.type = 2; + } + else + { + file_size = static_cast(File::GetSize(m_files_list[i])); + file_hdr_tmp.type = 1; + } - u32 file_size_rounded = ROUND_UP(file_size, BLOCK_SZ); - file_hdr_tmp.magic = Common::swap32(FILE_HDR_MAGIC); - file_hdr_tmp.size = Common::swap32(file_size); - file_hdr_tmp.Permissions = 0x3c; + u32 file_size_rounded = ROUND_UP(file_size, BLOCK_SZ); + file_hdr_tmp.magic = Common::swap32(FILE_HDR_MAGIC); + file_hdr_tmp.size = Common::swap32(file_size); + file_hdr_tmp.Permissions = 0x3c; - name = m_files_list[i].substr(m_wii_title_path.length() + 1); + name = m_files_list[i].substr(m_wii_title_path.length() + 1); - for (const Common::replace_t& repl : replacements) - { - for (size_t j = 0; (j = name.find(repl.second, j)) != name.npos; ++j) - { - name.replace(j, repl.second.length(), 1, repl.first); - } - } + for (const Common::replace_t& repl : replacements) + { + for (size_t j = 0; (j = name.find(repl.second, j)) != name.npos; ++j) + { + name.replace(j, repl.second.length(), 1, repl.first); + } + } - if (name.length() > 0x44) - { - ERROR_LOG(CONSOLE, "\"%s\" is too long for the filename, max length is 0x44 + \\0", name.c_str()); - m_valid = false; - return; - } - strncpy((char *)file_hdr_tmp.name, name.c_str(), sizeof(file_hdr_tmp.name)); + if (name.length() > 0x44) + { + ERROR_LOG(CONSOLE, "\"%s\" is too long for the filename, max length is 0x44 + \\0", + name.c_str()); + m_valid = false; + return; + } + strncpy((char*)file_hdr_tmp.name, name.c_str(), sizeof(file_hdr_tmp.name)); - { - File::IOFile fpData_bin(m_encrypted_save_path, "ab"); - fpData_bin.WriteBytes(&file_hdr_tmp, FILE_HDR_SZ); - } + { + File::IOFile fpData_bin(m_encrypted_save_path, "ab"); + fpData_bin.WriteBytes(&file_hdr_tmp, FILE_HDR_SZ); + } - if (file_hdr_tmp.type == 1) - { - if (file_size == 0) - { - ERROR_LOG(CONSOLE, "%s is a 0 byte file", m_files_list[i].c_str()); - m_valid = false; - return; - } - File::IOFile raw_save_file(m_files_list[i], "rb"); - if (!raw_save_file) - { - ERROR_LOG(CONSOLE, "%s failed to open", m_files_list[i].c_str()); - m_valid = false; - } + if (file_hdr_tmp.type == 1) + { + if (file_size == 0) + { + ERROR_LOG(CONSOLE, "%s is a 0 byte file", m_files_list[i].c_str()); + m_valid = false; + return; + } + File::IOFile raw_save_file(m_files_list[i], "rb"); + if (!raw_save_file) + { + ERROR_LOG(CONSOLE, "%s failed to open", m_files_list[i].c_str()); + m_valid = false; + } - std::vector file_data(file_size_rounded); - std::vector file_data_enc(file_size_rounded); + std::vector file_data(file_size_rounded); + std::vector file_data_enc(file_size_rounded); - if (!raw_save_file.ReadBytes(&file_data[0], file_size)) - { - ERROR_LOG(CONSOLE, "Failed to read data from file: %s", - m_files_list[i].c_str()); - m_valid = false; - } + if (!raw_save_file.ReadBytes(&file_data[0], file_size)) + { + ERROR_LOG(CONSOLE, "Failed to read data from file: %s", m_files_list[i].c_str()); + m_valid = false; + } - mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_ENCRYPT, file_size_rounded, - file_hdr_tmp.IV, (const u8*)&file_data[0], &file_data_enc[0]); + mbedtls_aes_crypt_cbc(&m_aes_ctx, MBEDTLS_AES_ENCRYPT, file_size_rounded, file_hdr_tmp.IV, + (const u8*)&file_data[0], &file_data_enc[0]); - File::IOFile fpData_bin(m_encrypted_save_path, "ab"); - if (!fpData_bin.WriteBytes(&file_data_enc[0], file_size_rounded)) - { - ERROR_LOG(CONSOLE, "Failed to write data to file: %s", - m_encrypted_save_path.c_str()); - } - } - } + File::IOFile fpData_bin(m_encrypted_save_path, "ab"); + if (!fpData_bin.WriteBytes(&file_data_enc[0], file_size_rounded)) + { + ERROR_LOG(CONSOLE, "Failed to write data to file: %s", m_encrypted_save_path.c_str()); + } + } + } } void CWiiSaveCrypted::do_sig() { - if (!m_valid) return; - u8 sig[0x40]; - u8 ng_cert[0x180]; - u8 ap_cert[0x180]; - u8 hash[0x14]; - u8 ap_priv[30]; - u8 ap_sig[60]; - char signer[64]; - char name[64]; - u32 data_size; + if (!m_valid) + return; + u8 sig[0x40]; + u8 ng_cert[0x180]; + u8 ap_cert[0x180]; + u8 hash[0x14]; + u8 ap_priv[30]; + u8 ap_sig[60]; + char signer[64]; + char name[64]; + u32 data_size; - const u32 ng_key_id = 0x6AAB8C59; + const u32 ng_key_id = 0x6AAB8C59; - const u8 ng_priv[30] = { - 0, 0xAB, 0xEE, 0xC1, 0xDD, 0xB4, 0xA6, 0x16, 0x6B, 0x70, 0xFD, 0x7E, 0x56, 0x67, 0x70, - 0x57, 0x55, 0x27, 0x38, 0xA3, 0x26, 0xC5, 0x46, 0x16, 0xF7, 0x62, 0xC9, 0xED, 0x73, 0xF2 - }; + const u8 ng_priv[30] = {0, 0xAB, 0xEE, 0xC1, 0xDD, 0xB4, 0xA6, 0x16, 0x6B, 0x70, + 0xFD, 0x7E, 0x56, 0x67, 0x70, 0x57, 0x55, 0x27, 0x38, 0xA3, + 0x26, 0xC5, 0x46, 0x16, 0xF7, 0x62, 0xC9, 0xED, 0x73, 0xF2}; - const u8 ng_sig[0x3C] = { - 0, 0xD8, 0x81, 0x63, 0xB2, 0x00, 0x6B, 0x0B, 0x54, 0x82, 0x88, 0x63, 0x81, 0x1C, 0x00, - 0x71, 0x12, 0xED, 0xB7, 0xFD, 0x21, 0xAB, 0x0E, 0x50, 0x0E, 0x1F, 0xBF, 0x78, 0xAD, 0x37, - 0x00, 0x71, 0x8D, 0x82, 0x41, 0xEE, 0x45, 0x11, 0xC7, 0x3B, 0xAC, 0x08, 0xB6, 0x83, 0xDC, - 0x05, 0xB8, 0xA8, 0x90, 0x1F, 0xA8, 0x2A, 0x0E, 0x4E, 0x76, 0xEF, 0x44, 0x72, 0x99, 0xF8 - }; + const u8 ng_sig[0x3C] = {0, 0xD8, 0x81, 0x63, 0xB2, 0x00, 0x6B, 0x0B, 0x54, 0x82, 0x88, 0x63, + 0x81, 0x1C, 0x00, 0x71, 0x12, 0xED, 0xB7, 0xFD, 0x21, 0xAB, 0x0E, 0x50, + 0x0E, 0x1F, 0xBF, 0x78, 0xAD, 0x37, 0x00, 0x71, 0x8D, 0x82, 0x41, 0xEE, + 0x45, 0x11, 0xC7, 0x3B, 0xAC, 0x08, 0xB6, 0x83, 0xDC, 0x05, 0xB8, 0xA8, + 0x90, 0x1F, 0xA8, 0x2A, 0x0E, 0x4E, 0x76, 0xEF, 0x44, 0x72, 0x99, 0xF8}; - sprintf(signer, "Root-CA00000001-MS00000002"); - sprintf(name, "NG%08x", s_ng_id); - make_ec_cert(ng_cert, ng_sig, signer, name, ng_priv, ng_key_id); + sprintf(signer, "Root-CA00000001-MS00000002"); + sprintf(name, "NG%08x", s_ng_id); + make_ec_cert(ng_cert, ng_sig, signer, name, ng_priv, ng_key_id); + memset(ap_priv, 0, sizeof ap_priv); + ap_priv[10] = 1; - memset(ap_priv, 0, sizeof ap_priv); - ap_priv[10] = 1; + memset(ap_sig, 81, sizeof ap_sig); // temp - memset(ap_sig, 81, sizeof ap_sig); // temp + sprintf(signer, "Root-CA00000001-MS00000002-NG%08x", s_ng_id); + sprintf(name, "AP%08x%08x", 1, 2); + make_ec_cert(ap_cert, ap_sig, signer, name, ap_priv, 0); - sprintf(signer, "Root-CA00000001-MS00000002-NG%08x", s_ng_id); - sprintf(name, "AP%08x%08x", 1, 2); - make_ec_cert(ap_cert, ap_sig, signer, name, ap_priv, 0); + mbedtls_sha1(ap_cert + 0x80, 0x100, hash); + generate_ecdsa(ap_sig, ap_sig + 30, ng_priv, hash); + make_ec_cert(ap_cert, ap_sig, signer, name, ap_priv, 0); - mbedtls_sha1(ap_cert + 0x80, 0x100, hash); - generate_ecdsa(ap_sig, ap_sig + 30, ng_priv, hash); - make_ec_cert(ap_cert, ap_sig, signer, name, ap_priv, 0); + data_size = Common::swap32(m_bk_hdr.sizeOfFiles) + 0x80; - data_size = Common::swap32(m_bk_hdr.sizeOfFiles) + 0x80; + File::IOFile data_file(m_encrypted_save_path, "rb"); + if (!data_file) + { + m_valid = false; + return; + } + auto data = std::make_unique(data_size); - File::IOFile data_file(m_encrypted_save_path, "rb"); - if (!data_file) - { - m_valid = false; - return; - } - auto data = std::make_unique(data_size); + data_file.Seek(0xf0c0, SEEK_SET); + if (!data_file.ReadBytes(data.get(), data_size)) + { + m_valid = false; + return; + } - data_file.Seek(0xf0c0, SEEK_SET); - if (!data_file.ReadBytes(data.get(), data_size)) - { - m_valid = false; - return; - } + mbedtls_sha1(data.get(), data_size, hash); + mbedtls_sha1(hash, 20, hash); - mbedtls_sha1(data.get(), data_size, hash); - mbedtls_sha1(hash, 20, hash); + data_file.Open(m_encrypted_save_path, "ab"); + if (!data_file) + { + m_valid = false; + return; + } + generate_ecdsa(sig, sig + 30, ap_priv, hash); + *(u32*)(sig + 60) = Common::swap32(0x2f536969); - data_file.Open(m_encrypted_save_path, "ab"); - if (!data_file) - { - m_valid = false; - return; - } - generate_ecdsa(sig, sig + 30, ap_priv, hash); - *(u32*)(sig + 60) = Common::swap32(0x2f536969); + data_file.WriteArray(sig, sizeof(sig)); + data_file.WriteArray(ng_cert, sizeof(ng_cert)); + data_file.WriteArray(ap_cert, sizeof(ap_cert)); - data_file.WriteArray(sig, sizeof(sig)); - data_file.WriteArray(ng_cert, sizeof(ng_cert)); - data_file.WriteArray(ap_cert, sizeof(ap_cert)); - - m_valid = data_file.IsGood(); + m_valid = data_file.IsGood(); } -void CWiiSaveCrypted::make_ec_cert(u8 *cert, const u8 *sig, const char *signer, const char *name, - const u8 *priv, const u32 key_id) +void CWiiSaveCrypted::make_ec_cert(u8* cert, const u8* sig, const char* signer, const char* name, + const u8* priv, const u32 key_id) { - memset(cert, 0, 0x180); - *(u32*)cert = Common::swap32(0x10002); + memset(cert, 0, 0x180); + *(u32*)cert = Common::swap32(0x10002); - memcpy(cert + 4, sig, 60); - strcpy((char*)cert + 0x80, signer); - *(u32*)(cert + 0xc0) = Common::swap32(2); - strcpy((char*)cert + 0xc4, name); - *(u32*)(cert + 0x104) = Common::swap32(key_id); - ec_priv_to_pub(priv, cert + 0x108); + memcpy(cert + 4, sig, 60); + strcpy((char*)cert + 0x80, signer); + *(u32*)(cert + 0xc0) = Common::swap32(2); + strcpy((char*)cert + 0xc4, name); + *(u32*)(cert + 0x104) = Common::swap32(key_id); + ec_priv_to_pub(priv, cert + 0x108); } bool CWiiSaveCrypted::getPaths(bool for_export) { - if (m_title_id) - { - // CONFIGURED because this whole class is only used from the GUI, not directly by games. - m_wii_title_path = Common::GetTitleDataPath(m_title_id, Common::FROM_CONFIGURED_ROOT); - } + if (m_title_id) + { + // CONFIGURED because this whole class is only used from the GUI, not directly by games. + m_wii_title_path = Common::GetTitleDataPath(m_title_id, Common::FROM_CONFIGURED_ROOT); + } - if (for_export) - { - char game_id[5]; - sprintf(game_id, "%c%c%c%c", - (u8)(m_title_id >> 24) & 0xFF, (u8)(m_title_id >> 16) & 0xFF, - (u8)(m_title_id >> 8) & 0xFF, (u8)m_title_id & 0xFF); + if (for_export) + { + char game_id[5]; + sprintf(game_id, "%c%c%c%c", (u8)(m_title_id >> 24) & 0xFF, (u8)(m_title_id >> 16) & 0xFF, + (u8)(m_title_id >> 8) & 0xFF, (u8)m_title_id & 0xFF); - if (!File::IsDirectory(m_wii_title_path)) - { - m_valid = false; - ERROR_LOG(CONSOLE, "No save folder found for title %s", game_id); - return false; - } + if (!File::IsDirectory(m_wii_title_path)) + { + m_valid = false; + ERROR_LOG(CONSOLE, "No save folder found for title %s", game_id); + return false; + } - if (!File::Exists(m_wii_title_path + "banner.bin")) - { - m_valid = false; - ERROR_LOG(CONSOLE, "No banner file found for title %s", game_id); - return false; - } - if (m_encrypted_save_path.length() == 0) - { - // If no path was passed, use User folder - m_encrypted_save_path = File::GetUserPath(D_USER_IDX); - } - m_encrypted_save_path += StringFromFormat("private/wii/title/%s/data.bin", game_id); - File::CreateFullPath(m_encrypted_save_path); - } - else - { - File::CreateFullPath(m_wii_title_path); - if (!AskYesNoT( - "Warning! it is advised to backup all files in the folder:\n%s\nDo you wish to continue?", - m_wii_title_path.c_str())) - { - return false; - } - } - return true; + if (!File::Exists(m_wii_title_path + "banner.bin")) + { + m_valid = false; + ERROR_LOG(CONSOLE, "No banner file found for title %s", game_id); + return false; + } + if (m_encrypted_save_path.length() == 0) + { + // If no path was passed, use User folder + m_encrypted_save_path = File::GetUserPath(D_USER_IDX); + } + m_encrypted_save_path += StringFromFormat("private/wii/title/%s/data.bin", game_id); + File::CreateFullPath(m_encrypted_save_path); + } + else + { + File::CreateFullPath(m_wii_title_path); + if (!AskYesNoT("Warning! it is advised to backup all files in the folder:\n%s\nDo you wish to " + "continue?", + m_wii_title_path.c_str())) + { + return false; + } + } + return true; } -void CWiiSaveCrypted::ScanForFiles(const std::string& save_directory, std::vector& file_list, - u32 *num_files, u32 *size_files) +void CWiiSaveCrypted::ScanForFiles(const std::string& save_directory, + std::vector& file_list, u32* num_files, + u32* size_files) { - std::vector directories; - directories.push_back(save_directory); - u32 num = 0; - u32 size = 0; + std::vector directories; + directories.push_back(save_directory); + u32 num = 0; + u32 size = 0; - for (u32 i = 0; i < directories.size(); ++i) - { - if (i != 0) - { - // add dir to fst - file_list.push_back(directories[i]); - } + for (u32 i = 0; i < directories.size(); ++i) + { + if (i != 0) + { + // add dir to fst + file_list.push_back(directories[i]); + } - File::FSTEntry fst_tmp = File::ScanDirectoryTree(directories[i], false); - for (const File::FSTEntry& elem : fst_tmp.children) - { - if (elem.virtualName != "banner.bin") - { - num++; - size += FILE_HDR_SZ; - if (elem.isDirectory) - { - if (elem.virtualName == "nocopy" || elem.virtualName == "nomove") - { - NOTICE_LOG(CONSOLE, - "This save will likely require homebrew tools to copy to a real Wii."); - } + File::FSTEntry fst_tmp = File::ScanDirectoryTree(directories[i], false); + for (const File::FSTEntry& elem : fst_tmp.children) + { + if (elem.virtualName != "banner.bin") + { + num++; + size += FILE_HDR_SZ; + if (elem.isDirectory) + { + if (elem.virtualName == "nocopy" || elem.virtualName == "nomove") + { + NOTICE_LOG(CONSOLE, + "This save will likely require homebrew tools to copy to a real Wii."); + } - directories.push_back(elem.physicalName); - } - else - { - file_list.push_back(elem.physicalName); - size += ROUND_UP(elem.size, BLOCK_SZ); - } - } - } - } + directories.push_back(elem.physicalName); + } + else + { + file_list.push_back(elem.physicalName); + size += ROUND_UP(elem.size, BLOCK_SZ); + } + } + } + } - *num_files = num; - *size_files = size; + *num_files = num; + *size_files = size; } CWiiSaveCrypted::~CWiiSaveCrypted() diff --git a/Source/Core/Core/HW/WiiSaveCrypted.h b/Source/Core/Core/HW/WiiSaveCrypted.h index bfb56e2b98..bd4f74838c 100644 --- a/Source/Core/Core/HW/WiiSaveCrypted.h +++ b/Source/Core/Core/HW/WiiSaveCrypted.h @@ -4,130 +4,130 @@ #pragma once +#include #include #include -#include #include "Common/CommonTypes.h" class CWiiSaveCrypted { public: - bool static ImportWiiSave(const std::string& filename); - bool static ExportWiiSave(u64 title_id); - void static ExportAllSaves(); + bool static ImportWiiSave(const std::string& filename); + bool static ExportWiiSave(u64 title_id); + void static ExportAllSaves(); private: - CWiiSaveCrypted(const std::string& filename, u64 title_id = 0); - ~CWiiSaveCrypted(); - void ReadHDR(); - void ReadBKHDR(); - void WriteHDR(); - void WriteBKHDR(); - void Extract(){} - void ImportWiiSaveFiles(); - void ExportWiiSaveFiles(); - void do_sig(); - void make_ec_cert(u8 *cert, const u8 *sig, const char *signer, const char *name, - const u8 *priv, const u32 key_id); - bool getPaths(bool for_export = false); - void ScanForFiles(const std::string& save_directory, std::vector& file_list, - u32 *num_files, u32 *size_files); + CWiiSaveCrypted(const std::string& filename, u64 title_id = 0); + ~CWiiSaveCrypted(); + void ReadHDR(); + void ReadBKHDR(); + void WriteHDR(); + void WriteBKHDR(); + void Extract() {} + void ImportWiiSaveFiles(); + void ExportWiiSaveFiles(); + void do_sig(); + void make_ec_cert(u8* cert, const u8* sig, const char* signer, const char* name, const u8* priv, + const u32 key_id); + bool getPaths(bool for_export = false); + void ScanForFiles(const std::string& save_directory, std::vector& file_list, + u32* num_files, u32* size_files); - static const u8 s_sd_key[16]; - static const u8 s_md5_blanker[16]; - static const u32 s_ng_id; + static const u8 s_sd_key[16]; + static const u8 s_md5_blanker[16]; + static const u32 s_ng_id; - mbedtls_aes_context m_aes_ctx; - u8 m_sd_iv[0x10]; - std::vector m_files_list; + mbedtls_aes_context m_aes_ctx; + u8 m_sd_iv[0x10]; + std::vector m_files_list; - std::string m_encrypted_save_path; + std::string m_encrypted_save_path; - std::string m_wii_title_path; + std::string m_wii_title_path; - u8 m_iv[0x10]; + u8 m_iv[0x10]; - u32 m_files_list_size; - u32 m_size_of_files; - u32 m_total_size; + u32 m_files_list_size; + u32 m_size_of_files; + u32 m_total_size; - u64 m_title_id; + u64 m_title_id; - bool m_valid; + bool m_valid; - enum - { - BLOCK_SZ = 0x40, - HDR_SZ = 0x20, - ICON_SZ = 0x1200, - BNR_SZ = 0x60a0, - FULL_BNR_MIN = 0x72a0, // BNR_SZ + 1*ICON_SZ - FULL_BNR_MAX = 0xF0A0, // BNR_SZ + 8*ICON_SZ - HEADER_SZ = 0xF0C0, // HDR_SZ + FULL_BNR_MAX - BK_LISTED_SZ = 0x70, // Size before rounding to nearest block - BK_SZ = 0x80, - FILE_HDR_SZ = 0x80, + enum + { + BLOCK_SZ = 0x40, + HDR_SZ = 0x20, + ICON_SZ = 0x1200, + BNR_SZ = 0x60a0, + FULL_BNR_MIN = 0x72a0, // BNR_SZ + 1*ICON_SZ + FULL_BNR_MAX = 0xF0A0, // BNR_SZ + 8*ICON_SZ + HEADER_SZ = 0xF0C0, // HDR_SZ + FULL_BNR_MAX + BK_LISTED_SZ = 0x70, // Size before rounding to nearest block + BK_SZ = 0x80, + FILE_HDR_SZ = 0x80, - SIG_SZ = 0x40, - NG_CERT_SZ = 0x180, - AP_CERT_SZ = 0x180, - FULL_CERT_SZ = 0x3C0, // SIG_SZ + NG_CERT_SZ + AP_CERT_SZ + 0x80? + SIG_SZ = 0x40, + NG_CERT_SZ = 0x180, + AP_CERT_SZ = 0x180, + FULL_CERT_SZ = 0x3C0, // SIG_SZ + NG_CERT_SZ + AP_CERT_SZ + 0x80? - BK_HDR_MAGIC = 0x426B0001, - FILE_HDR_MAGIC = 0x03adf17e - }; + BK_HDR_MAGIC = 0x426B0001, + FILE_HDR_MAGIC = 0x03adf17e + }; -#pragma pack(push,1) +#pragma pack(push, 1) - struct Data_Bin_HDR // encrypted - { - u64 SaveGameTitle; - u32 BannerSize; // (0x72A0 or 0xF0A0, also seen 0xBAA0) - u8 Permissions; - u8 unk1; // maybe permissions is a be16 - u8 Md5[0x10]; // md5 of plaintext header with md5 blanker applied - u16 unk2; - }; + struct Data_Bin_HDR // encrypted + { + u64 SaveGameTitle; + u32 BannerSize; // (0x72A0 or 0xF0A0, also seen 0xBAA0) + u8 Permissions; + u8 unk1; // maybe permissions is a be16 + u8 Md5[0x10]; // md5 of plaintext header with md5 blanker applied + u16 unk2; + }; - struct HEADER - { - Data_Bin_HDR hdr; - u8 BNR[FULL_BNR_MAX]; - }; + struct HEADER + { + Data_Bin_HDR hdr; + u8 BNR[FULL_BNR_MAX]; + }; - struct BK_Header // Not encrypted - { - u32 size; // 0x00000070 - // u16 magic; // 'Bk' - // u16 magic2; // or version (0x0001) - u32 magic; // 0x426B0001 - u32 NGid; - u32 numberOfFiles; - u32 sizeOfFiles; - u32 unk1; - u32 unk2; - u32 totalSize; - u8 unk3[64]; - u64 SaveGameTitle; - u8 MACaddress[6]; - u8 padding[0x12]; - }; + struct BK_Header // Not encrypted + { + u32 size; // 0x00000070 + // u16 magic; // 'Bk' + // u16 magic2; // or version (0x0001) + u32 magic; // 0x426B0001 + u32 NGid; + u32 numberOfFiles; + u32 sizeOfFiles; + u32 unk1; + u32 unk2; + u32 totalSize; + u8 unk3[64]; + u64 SaveGameTitle; + u8 MACaddress[6]; + u8 padding[0x12]; + }; - struct FileHDR // encrypted - { - u32 magic; //0x03adf17e - u32 size; - u8 Permissions; - u8 attrib; - u8 type; // (1=file, 2=directory) - u8 name[0x45]; - u8 IV[0x10]; - u8 unk[0x20]; - }; + struct FileHDR // encrypted + { + u32 magic; // 0x03adf17e + u32 size; + u8 Permissions; + u8 attrib; + u8 type; // (1=file, 2=directory) + u8 name[0x45]; + u8 IV[0x10]; + u8 unk[0x20]; + }; #pragma pack(pop) - HEADER m_header; - HEADER m_encrypted_header; - BK_Header m_bk_hdr; + HEADER m_header; + HEADER m_encrypted_header; + BK_Header m_bk_hdr; }; diff --git a/Source/Core/Core/HW/Wiimote.cpp b/Source/Core/Core/HW/Wiimote.cpp index 9451fcf36e..83c33e403b 100644 --- a/Source/Core/Core/HW/Wiimote.cpp +++ b/Source/Core/Core/HW/Wiimote.cpp @@ -2,131 +2,129 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/Wiimote.h" #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" -#include "Core/Movie.h" -#include "Core/HW/Wiimote.h" #include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" -#include "InputCommon/InputConfig.h" +#include "Core/Movie.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" +#include "InputCommon/InputConfig.h" namespace Wiimote { - static InputConfig s_config(WIIMOTE_INI_NAME, _trans("Wiimote"), "Wiimote"); InputConfig* GetConfig() { - return &s_config; + return &s_config; } void Shutdown() { - s_config.ClearControllers(); + s_config.ClearControllers(); - WiimoteReal::Stop(); + WiimoteReal::Stop(); - g_controller_interface.Shutdown(); + g_controller_interface.Shutdown(); } void Initialize(void* const hwnd, bool wait) { - if (s_config.ControllersNeedToBeCreated()) - { - for (unsigned int i = WIIMOTE_CHAN_0; i < MAX_BBMOTES; ++i) - s_config.CreateController(i); - } + if (s_config.ControllersNeedToBeCreated()) + { + for (unsigned int i = WIIMOTE_CHAN_0; i < MAX_BBMOTES; ++i) + s_config.CreateController(i); + } - g_controller_interface.Initialize(hwnd); + g_controller_interface.Initialize(hwnd); - s_config.LoadConfig(false); + s_config.LoadConfig(false); - WiimoteReal::Initialize(wait); + WiimoteReal::Initialize(wait); - // Reload Wiimotes with our settings - if (Movie::IsMovieActive()) - Movie::ChangeWiiPads(); + // Reload Wiimotes with our settings + if (Movie::IsMovieActive()) + Movie::ChangeWiiPads(); } void ResetAllWiimotes() { - for (int i = WIIMOTE_CHAN_0; i < MAX_BBMOTES; ++i) - static_cast(s_config.GetController(i))->Reset(); + for (int i = WIIMOTE_CHAN_0; i < MAX_BBMOTES; ++i) + static_cast(s_config.GetController(i))->Reset(); } void LoadConfig() { - s_config.LoadConfig(false); + s_config.LoadConfig(false); } - void Resume() { - WiimoteReal::Resume(); + WiimoteReal::Resume(); } void Pause() { - WiimoteReal::Pause(); + WiimoteReal::Pause(); } - // An L2CAP packet is passed from the Core to the Wiimote on the HID CONTROL channel. void ControlChannel(int number, u16 channel_id, const void* data, u32 size) { - if (WIIMOTE_SRC_HYBRID & g_wiimote_sources[number]) - static_cast(s_config.GetController(number))->ControlChannel(channel_id, data, size); + if (WIIMOTE_SRC_HYBRID & g_wiimote_sources[number]) + static_cast(s_config.GetController(number)) + ->ControlChannel(channel_id, data, size); } // An L2CAP packet is passed from the Core to the Wiimote on the HID INTERRUPT channel. void InterruptChannel(int number, u16 channel_id, const void* data, u32 size) { - if (WIIMOTE_SRC_HYBRID & g_wiimote_sources[number]) - static_cast(s_config.GetController(number))->InterruptChannel(channel_id, data, size); + if (WIIMOTE_SRC_HYBRID & g_wiimote_sources[number]) + static_cast(s_config.GetController(number)) + ->InterruptChannel(channel_id, data, size); } // This function is called periodically by the Core to update Wiimote state. void Update(int number, bool connected) { - if (connected) - { - if (WIIMOTE_SRC_EMU & g_wiimote_sources[number]) - static_cast(s_config.GetController(number))->Update(); - else - WiimoteReal::Update(number); - } - else - { - if (WIIMOTE_SRC_EMU & g_wiimote_sources[number]) - static_cast(s_config.GetController(number))->ConnectOnInput(); + if (connected) + { + if (WIIMOTE_SRC_EMU & g_wiimote_sources[number]) + static_cast(s_config.GetController(number))->Update(); + else + WiimoteReal::Update(number); + } + else + { + if (WIIMOTE_SRC_EMU & g_wiimote_sources[number]) + static_cast(s_config.GetController(number))->ConnectOnInput(); - if (WIIMOTE_SRC_REAL & g_wiimote_sources[number]) - WiimoteReal::ConnectOnInput(number); - } + if (WIIMOTE_SRC_REAL & g_wiimote_sources[number]) + WiimoteReal::ConnectOnInput(number); + } } // Get a mask of attached the pads (eg: controller 1 & 4 -> 0x9) unsigned int GetAttached() { - unsigned int attached = 0; - for (unsigned int i = 0; i < MAX_BBMOTES; ++i) - if (g_wiimote_sources[i]) - attached |= (1 << i); - return attached; + unsigned int attached = 0; + for (unsigned int i = 0; i < MAX_BBMOTES; ++i) + if (g_wiimote_sources[i]) + attached |= (1 << i); + return attached; } // Save/Load state void DoState(PointerWrap& p) { - for (int i = 0; i < MAX_BBMOTES; ++i) - static_cast(s_config.GetController(i))->DoState(p); + for (int i = 0; i < MAX_BBMOTES; ++i) + static_cast(s_config.GetController(i))->DoState(p); } // Notifies the plugin of a change in emulation state void EmuStateChange(EMUSTATE_CHANGE newState) { - WiimoteReal::StateChange(newState); + WiimoteReal::StateChange(newState); } - } diff --git a/Source/Core/Core/HW/Wiimote.h b/Source/Core/Core/HW/Wiimote.h index 887b75e861..d47d5aea93 100644 --- a/Source/Core/Core/HW/Wiimote.h +++ b/Source/Core/Core/HW/Wiimote.h @@ -11,31 +11,29 @@ class PointerWrap; enum { - WIIMOTE_CHAN_0 = 0, - WIIMOTE_CHAN_1, - WIIMOTE_CHAN_2, - WIIMOTE_CHAN_3, - WIIMOTE_BALANCE_BOARD, - MAX_WIIMOTES = WIIMOTE_BALANCE_BOARD, - MAX_BBMOTES = 5, + WIIMOTE_CHAN_0 = 0, + WIIMOTE_CHAN_1, + WIIMOTE_CHAN_2, + WIIMOTE_CHAN_3, + WIIMOTE_BALANCE_BOARD, + MAX_WIIMOTES = WIIMOTE_BALANCE_BOARD, + MAX_BBMOTES = 5, }; - -#define WIIMOTE_INI_NAME "WiimoteNew" +#define WIIMOTE_INI_NAME "WiimoteNew" enum { - WIIMOTE_SRC_NONE = 0, - WIIMOTE_SRC_EMU = 1, - WIIMOTE_SRC_REAL = 2, - WIIMOTE_SRC_HYBRID = 3, // emu + real + WIIMOTE_SRC_NONE = 0, + WIIMOTE_SRC_EMU = 1, + WIIMOTE_SRC_REAL = 2, + WIIMOTE_SRC_HYBRID = 3, // emu + real }; extern unsigned int g_wiimote_sources[MAX_BBMOTES]; namespace Wiimote { - void Shutdown(); void Initialize(void* const hwnd, bool wait = false); void ResetAllWiimotes(); @@ -51,12 +49,10 @@ InputConfig* GetConfig(); void ControlChannel(int _number, u16 _channelID, const void* _pData, u32 _Size); void InterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size); void Update(int _number, bool _connected); - } namespace WiimoteReal { - void Initialize(bool wait = false); void Stop(); void Shutdown(); @@ -65,5 +61,4 @@ void Pause(); void Refresh(); void LoadSettings(); - } diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Attachment.cpp b/Source/Core/Core/HW/WiimoteEmu/Attachment/Attachment.cpp index 1b1ac2d822..8047189be8 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Attachment.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Attachment.cpp @@ -6,59 +6,59 @@ #include "Common/Common.h" #include "Common/CommonTypes.h" -#include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteEmu/Attachment/Attachment.h" +#include "Core/HW/WiimoteEmu/WiimoteEmu.h" namespace WiimoteEmu { - // Extension device IDs to be written to the last bytes of the extension reg // The id for nothing inserted -static const u8 nothing_id[] = { 0x00, 0x00, 0x00, 0x00, 0x2e, 0x2e }; +static const u8 nothing_id[] = {0x00, 0x00, 0x00, 0x00, 0x2e, 0x2e}; // The id for a partially inserted extension (currently unused) -UNUSED static const u8 partially_id[] = { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }; +UNUSED static const u8 partially_id[] = {0x00, 0x00, 0x00, 0x00, 0xff, 0xff}; Attachment::Attachment(const char* const _name, WiimoteEmu::ExtensionReg& _reg) - : name(_name), reg(_reg) + : name(_name), reg(_reg) { - memset(id, 0, sizeof(id)); - memset(calibration, 0, sizeof(calibration)); + memset(id, 0, sizeof(id)); + memset(calibration, 0, sizeof(calibration)); } None::None(WiimoteEmu::ExtensionReg& _reg) : Attachment("None", _reg) { - // set up register - memcpy(&id, nothing_id, sizeof(nothing_id)); + // set up register + memcpy(&id, nothing_id, sizeof(nothing_id)); } std::string Attachment::GetName() const { - return name; + return name; } void Attachment::Reset() { - // set up register - memset(®, 0, WIIMOTE_REG_EXT_SIZE); - memcpy(®.constant_id, id, sizeof(id)); - memcpy(®.calibration, calibration, sizeof(calibration)); + // set up register + memset(®, 0, WIIMOTE_REG_EXT_SIZE); + memcpy(®.constant_id, id, sizeof(id)); + memcpy(®.calibration, calibration, sizeof(calibration)); } - } void ControllerEmu::Extension::GetState(u8* const data) { - ((WiimoteEmu::Attachment*)attachments[active_extension].get())->GetState(data); + ((WiimoteEmu::Attachment*)attachments[active_extension].get())->GetState(data); } bool ControllerEmu::Extension::IsButtonPressed() const { - // Extension == 0 means no Extension, > 0 means one is connected - // Since we want to use this to know if disconnected Wiimotes want to be connected, and disconnected - // Wiimotes (can? always?) have their active_extension set to -1, we also have to check the switch_extension - if (active_extension > 0) - return ((WiimoteEmu::Attachment*)attachments[active_extension].get())->IsButtonPressed(); - if (switch_extension > 0) - return ((WiimoteEmu::Attachment*)attachments[switch_extension].get())->IsButtonPressed(); - return false; + // Extension == 0 means no Extension, > 0 means one is connected + // Since we want to use this to know if disconnected Wiimotes want to be connected, and + // disconnected + // Wiimotes (can? always?) have their active_extension set to -1, we also have to check the + // switch_extension + if (active_extension > 0) + return ((WiimoteEmu::Attachment*)attachments[active_extension].get())->IsButtonPressed(); + if (switch_extension > 0) + return ((WiimoteEmu::Attachment*)attachments[switch_extension].get())->IsButtonPressed(); + return false; } diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Attachment.h b/Source/Core/Core/HW/WiimoteEmu/Attachment/Attachment.h index 22c0d238cb..65fe781f9d 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Attachment.h +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Attachment.h @@ -8,35 +8,32 @@ namespace WiimoteEmu { - struct ExtensionReg; class Attachment : public ControllerEmu { public: - Attachment(const char* const _name, WiimoteEmu::ExtensionReg& _reg); + Attachment(const char* const _name, WiimoteEmu::ExtensionReg& _reg); - virtual void GetState(u8* const data) {} - virtual bool IsButtonPressed() const { return false; } - void Reset(); - std::string GetName() const override; + virtual void GetState(u8* const data) {} + virtual bool IsButtonPressed() const { return false; } + void Reset(); + std::string GetName() const override; - const char* const name; - WiimoteEmu::ExtensionReg& reg; + const char* const name; + WiimoteEmu::ExtensionReg& reg; - u8 id[6]; - u8 calibration[0x10]; + u8 id[6]; + u8 calibration[0x10]; protected: - - // Default radius for attachment analog sticks. - static constexpr ControlState DEFAULT_ATTACHMENT_STICK_RADIUS = 1.0; + // Default radius for attachment analog sticks. + static constexpr ControlState DEFAULT_ATTACHMENT_STICK_RADIUS = 1.0; }; class None : public Attachment { public: - None(WiimoteEmu::ExtensionReg& _reg); + None(WiimoteEmu::ExtensionReg& _reg); }; - } diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.cpp b/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.cpp index c5ad18feda..f3577937c6 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.cpp @@ -6,147 +6,132 @@ #include "Common/Common.h" #include "Common/CommonTypes.h" -#include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteEmu/Attachment/Classic.h" +#include "Core/HW/WiimoteEmu/WiimoteEmu.h" namespace WiimoteEmu { - -static const u8 classic_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x01, 0x01 }; +static const u8 classic_id[] = {0x00, 0x00, 0xa4, 0x20, 0x01, 0x01}; /* Classic Controller calibration */ -static const u8 classic_calibration[] = -{ - 0xff, 0x00, 0x80, 0xff, 0x00, 0x80, - 0xff, 0x00, 0x80, 0xff, 0x00, 0x80, - 0x00, 0x00, 0x51, 0xa6 +static const u8 classic_calibration[] = {0xff, 0x00, 0x80, 0xff, 0x00, 0x80, 0xff, 0x00, + 0x80, 0xff, 0x00, 0x80, 0x00, 0x00, 0x51, 0xa6}; + +static const u16 classic_button_bitmasks[] = { + Classic::BUTTON_A, Classic::BUTTON_B, Classic::BUTTON_X, Classic::BUTTON_Y, + + Classic::BUTTON_ZL, Classic::BUTTON_ZR, + + Classic::BUTTON_MINUS, Classic::BUTTON_PLUS, + + Classic::BUTTON_HOME, }; -static const u16 classic_button_bitmasks[] = -{ - Classic::BUTTON_A, - Classic::BUTTON_B, - Classic::BUTTON_X, - Classic::BUTTON_Y, - - Classic::BUTTON_ZL, - Classic::BUTTON_ZR, - - Classic::BUTTON_MINUS, - Classic::BUTTON_PLUS, - - Classic::BUTTON_HOME, +static const char* const classic_button_names[] = { + "A", "B", "X", "Y", "ZL", "ZR", "-", "+", "Home", }; -static const char* const classic_button_names[] = -{ - "A","B","X","Y","ZL","ZR","-","+","Home", +static const u16 classic_trigger_bitmasks[] = { + Classic::TRIGGER_L, Classic::TRIGGER_R, }; -static const u16 classic_trigger_bitmasks[] = -{ - Classic::TRIGGER_L, Classic::TRIGGER_R, -}; +static const char* const classic_trigger_names[] = {"L", "R", "L-Analog", "R-Analog"}; -static const char* const classic_trigger_names[] = -{ - "L", "R", "L-Analog", "R-Analog" -}; - -static const u16 classic_dpad_bitmasks[] = -{ - Classic::PAD_UP, Classic::PAD_DOWN, Classic::PAD_LEFT, Classic::PAD_RIGHT -}; +static const u16 classic_dpad_bitmasks[] = {Classic::PAD_UP, Classic::PAD_DOWN, Classic::PAD_LEFT, + Classic::PAD_RIGHT}; Classic::Classic(WiimoteEmu::ExtensionReg& _reg) : Attachment(_trans("Classic"), _reg) { - // buttons - groups.emplace_back(m_buttons = new Buttons("Buttons")); - for (auto& classic_button_name : classic_button_names) - m_buttons->controls.emplace_back(new ControlGroup::Input(classic_button_name)); + // buttons + groups.emplace_back(m_buttons = new Buttons("Buttons")); + for (auto& classic_button_name : classic_button_names) + m_buttons->controls.emplace_back(new ControlGroup::Input(classic_button_name)); - // sticks - groups.emplace_back(m_left_stick = new AnalogStick(_trans("Left Stick"), DEFAULT_ATTACHMENT_STICK_RADIUS)); - groups.emplace_back(m_right_stick = new AnalogStick(_trans("Right Stick"), DEFAULT_ATTACHMENT_STICK_RADIUS)); + // sticks + groups.emplace_back(m_left_stick = + new AnalogStick(_trans("Left Stick"), DEFAULT_ATTACHMENT_STICK_RADIUS)); + groups.emplace_back(m_right_stick = + new AnalogStick(_trans("Right Stick"), DEFAULT_ATTACHMENT_STICK_RADIUS)); - // triggers - groups.emplace_back(m_triggers = new MixedTriggers("Triggers")); - for (auto& classic_trigger_name : classic_trigger_names) - m_triggers->controls.emplace_back(new ControlGroup::Input(classic_trigger_name)); + // triggers + groups.emplace_back(m_triggers = new MixedTriggers("Triggers")); + for (auto& classic_trigger_name : classic_trigger_names) + m_triggers->controls.emplace_back(new ControlGroup::Input(classic_trigger_name)); - // dpad - groups.emplace_back(m_dpad = new Buttons("D-Pad")); - for (auto& named_direction : named_directions) - m_dpad->controls.emplace_back(new ControlGroup::Input(named_direction)); + // dpad + groups.emplace_back(m_dpad = new Buttons("D-Pad")); + for (auto& named_direction : named_directions) + m_dpad->controls.emplace_back(new ControlGroup::Input(named_direction)); - // set up register - // calibration - memcpy(&calibration, classic_calibration, sizeof(classic_calibration)); - // id - memcpy(&id, classic_id, sizeof(classic_id)); + // set up register + // calibration + memcpy(&calibration, classic_calibration, sizeof(classic_calibration)); + // id + memcpy(&id, classic_id, sizeof(classic_id)); } void Classic::GetState(u8* const data) { - wm_classic_extension* const ccdata = (wm_classic_extension*)data; - ccdata->bt.hex = 0; + wm_classic_extension* const ccdata = (wm_classic_extension*)data; + ccdata->bt.hex = 0; - // not using calibration data, o well + // not using calibration data, o well - // left stick - { - ControlState x, y; - m_left_stick->GetState(&x, &y); + // left stick + { + ControlState x, y; + m_left_stick->GetState(&x, &y); - ccdata->regular_data.lx = static_cast(Classic::LEFT_STICK_CENTER_X + (x * Classic::LEFT_STICK_RADIUS)); - ccdata->regular_data.ly = static_cast(Classic::LEFT_STICK_CENTER_Y + (y * Classic::LEFT_STICK_RADIUS)); - } + ccdata->regular_data.lx = + static_cast(Classic::LEFT_STICK_CENTER_X + (x * Classic::LEFT_STICK_RADIUS)); + ccdata->regular_data.ly = + static_cast(Classic::LEFT_STICK_CENTER_Y + (y * Classic::LEFT_STICK_RADIUS)); + } - // right stick - { - ControlState x, y; - u8 x_, y_; - m_right_stick->GetState(&x, &y); + // right stick + { + ControlState x, y; + u8 x_, y_; + m_right_stick->GetState(&x, &y); - x_ = static_cast(Classic::RIGHT_STICK_CENTER_X + (x * Classic::RIGHT_STICK_RADIUS)); - y_ = static_cast(Classic::RIGHT_STICK_CENTER_Y + (y * Classic::RIGHT_STICK_RADIUS)); + x_ = static_cast(Classic::RIGHT_STICK_CENTER_X + (x * Classic::RIGHT_STICK_RADIUS)); + y_ = static_cast(Classic::RIGHT_STICK_CENTER_Y + (y * Classic::RIGHT_STICK_RADIUS)); - ccdata->rx1 = x_; - ccdata->rx2 = x_ >> 1; - ccdata->rx3 = x_ >> 3; - ccdata->ry = y_; - } + ccdata->rx1 = x_; + ccdata->rx2 = x_ >> 1; + ccdata->rx3 = x_ >> 3; + ccdata->ry = y_; + } - //triggers - { - ControlState trigs[2] = { 0, 0 }; - u8 lt, rt; - m_triggers->GetState(&ccdata->bt.hex, classic_trigger_bitmasks, trigs); + // triggers + { + ControlState trigs[2] = {0, 0}; + u8 lt, rt; + m_triggers->GetState(&ccdata->bt.hex, classic_trigger_bitmasks, trigs); - lt = static_cast(trigs[0] * Classic::LEFT_TRIGGER_RANGE); - rt = static_cast(trigs[1] * Classic::RIGHT_TRIGGER_RANGE); + lt = static_cast(trigs[0] * Classic::LEFT_TRIGGER_RANGE); + rt = static_cast(trigs[1] * Classic::RIGHT_TRIGGER_RANGE); - ccdata->lt1 = lt; - ccdata->lt2 = lt >> 3; - ccdata->rt = rt; - } + ccdata->lt1 = lt; + ccdata->lt2 = lt >> 3; + ccdata->rt = rt; + } - // buttons - m_buttons->GetState(&ccdata->bt.hex, classic_button_bitmasks); - // dpad - m_dpad->GetState(&ccdata->bt.hex, classic_dpad_bitmasks); + // buttons + m_buttons->GetState(&ccdata->bt.hex, classic_button_bitmasks); + // dpad + m_dpad->GetState(&ccdata->bt.hex, classic_dpad_bitmasks); - // flip button bits - ccdata->bt.hex ^= 0xFFFF; + // flip button bits + ccdata->bt.hex ^= 0xFFFF; } bool Classic::IsButtonPressed() const { - u16 buttons = 0; - ControlState trigs[2] = { 0, 0 }; - m_buttons->GetState(&buttons, classic_button_bitmasks); - m_dpad->GetState(&buttons, classic_dpad_bitmasks); - m_triggers->GetState(&buttons, classic_trigger_bitmasks, trigs); - return buttons != 0; + u16 buttons = 0; + ControlState trigs[2] = {0, 0}; + m_buttons->GetState(&buttons, classic_button_bitmasks); + m_dpad->GetState(&buttons, classic_dpad_bitmasks); + m_triggers->GetState(&buttons, classic_trigger_bitmasks, trigs); + return buttons != 0; } - } diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.h b/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.h index 9a1b9dce92..0ab968bdcc 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.h +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.h @@ -8,53 +8,51 @@ namespace WiimoteEmu { - struct ExtensionReg; class Classic : public Attachment { public: - Classic(WiimoteEmu::ExtensionReg& _reg); - void GetState(u8* const data) override; - bool IsButtonPressed() const override; + Classic(WiimoteEmu::ExtensionReg& _reg); + void GetState(u8* const data) override; + bool IsButtonPressed() const override; - enum - { - PAD_RIGHT = 0x80, - PAD_DOWN = 0x40, - TRIGGER_L = 0x20, - BUTTON_MINUS = 0x10, - BUTTON_HOME = 0x08, - BUTTON_PLUS = 0x04, - TRIGGER_R = 0x02, - NOTHING = 0x01, - BUTTON_ZL = 0x8000, - BUTTON_B = 0x4000, - BUTTON_Y = 0x2000, - BUTTON_A = 0x1000, - BUTTON_X = 0x0800, - BUTTON_ZR = 0x0400, - PAD_LEFT = 0x0200, - PAD_UP = 0x0100, - }; + enum + { + PAD_RIGHT = 0x80, + PAD_DOWN = 0x40, + TRIGGER_L = 0x20, + BUTTON_MINUS = 0x10, + BUTTON_HOME = 0x08, + BUTTON_PLUS = 0x04, + TRIGGER_R = 0x02, + NOTHING = 0x01, + BUTTON_ZL = 0x8000, + BUTTON_B = 0x4000, + BUTTON_Y = 0x2000, + BUTTON_A = 0x1000, + BUTTON_X = 0x0800, + BUTTON_ZR = 0x0400, + PAD_LEFT = 0x0200, + PAD_UP = 0x0100, + }; - static const u8 LEFT_STICK_CENTER_X = 0x20; - static const u8 LEFT_STICK_CENTER_Y = 0x20; - static const u8 LEFT_STICK_RADIUS = 0x1F; + static const u8 LEFT_STICK_CENTER_X = 0x20; + static const u8 LEFT_STICK_CENTER_Y = 0x20; + static const u8 LEFT_STICK_RADIUS = 0x1F; - static const u8 RIGHT_STICK_CENTER_X = 0x10; - static const u8 RIGHT_STICK_CENTER_Y = 0x10; - static const u8 RIGHT_STICK_RADIUS = 0x0F; + static const u8 RIGHT_STICK_CENTER_X = 0x10; + static const u8 RIGHT_STICK_CENTER_Y = 0x10; + static const u8 RIGHT_STICK_RADIUS = 0x0F; - static const u8 LEFT_TRIGGER_RANGE = 0x1F; - static const u8 RIGHT_TRIGGER_RANGE = 0x1F; + static const u8 LEFT_TRIGGER_RANGE = 0x1F; + static const u8 RIGHT_TRIGGER_RANGE = 0x1F; private: - Buttons* m_buttons; - MixedTriggers* m_triggers; - Buttons* m_dpad; - AnalogStick* m_left_stick; - AnalogStick* m_right_stick; + Buttons* m_buttons; + MixedTriggers* m_triggers; + Buttons* m_dpad; + AnalogStick* m_left_stick; + AnalogStick* m_right_stick; }; - } diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Drums.cpp b/Source/Core/Core/HW/WiimoteEmu/Attachment/Drums.cpp index 2ae0ab976e..46888214d1 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Drums.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Drums.cpp @@ -6,91 +6,79 @@ #include "Common/Common.h" #include "Common/CommonTypes.h" -#include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteEmu/Attachment/Drums.h" +#include "Core/HW/WiimoteEmu/WiimoteEmu.h" namespace WiimoteEmu { +static const u8 drums_id[] = {0x01, 0x00, 0xa4, 0x20, 0x01, 0x03}; -static const u8 drums_id[] = { 0x01, 0x00, 0xa4, 0x20, 0x01, 0x03 }; - -static const u16 drum_pad_bitmasks[] = -{ - Drums::PAD_RED, - Drums::PAD_YELLOW, - Drums::PAD_BLUE, - Drums::PAD_GREEN, - Drums::PAD_ORANGE, - Drums::PAD_BASS, +static const u16 drum_pad_bitmasks[] = { + Drums::PAD_RED, Drums::PAD_YELLOW, Drums::PAD_BLUE, + Drums::PAD_GREEN, Drums::PAD_ORANGE, Drums::PAD_BASS, }; -static const char* const drum_pad_names[] = -{ - _trans("Red"), _trans("Yellow"), _trans("Blue"), - _trans("Green"), _trans("Orange"), _trans("Bass") -}; +static const char* const drum_pad_names[] = {_trans("Red"), _trans("Yellow"), _trans("Blue"), + _trans("Green"), _trans("Orange"), _trans("Bass")}; -static const u16 drum_button_bitmasks[] = -{ - Drums::BUTTON_MINUS, - Drums::BUTTON_PLUS, +static const u16 drum_button_bitmasks[] = { + Drums::BUTTON_MINUS, Drums::BUTTON_PLUS, }; Drums::Drums(WiimoteEmu::ExtensionReg& _reg) : Attachment(_trans("Drums"), _reg) { - // pads - groups.emplace_back(m_pads = new Buttons(_trans("Pads"))); - for (auto& drum_pad_name : drum_pad_names) - m_pads->controls.emplace_back(new ControlGroup::Input(drum_pad_name)); + // pads + groups.emplace_back(m_pads = new Buttons(_trans("Pads"))); + for (auto& drum_pad_name : drum_pad_names) + m_pads->controls.emplace_back(new ControlGroup::Input(drum_pad_name)); - // stick - groups.emplace_back(m_stick = new AnalogStick("Stick", DEFAULT_ATTACHMENT_STICK_RADIUS)); + // stick + groups.emplace_back(m_stick = new AnalogStick("Stick", DEFAULT_ATTACHMENT_STICK_RADIUS)); - // buttons - groups.emplace_back(m_buttons = new Buttons("Buttons")); - m_buttons->controls.emplace_back(new ControlGroup::Input("-")); - m_buttons->controls.emplace_back(new ControlGroup::Input("+")); + // buttons + groups.emplace_back(m_buttons = new Buttons("Buttons")); + m_buttons->controls.emplace_back(new ControlGroup::Input("-")); + m_buttons->controls.emplace_back(new ControlGroup::Input("+")); - // set up register - // id - memcpy(&id, drums_id, sizeof(drums_id)); + // set up register + // id + memcpy(&id, drums_id, sizeof(drums_id)); } void Drums::GetState(u8* const data) { - wm_drums_extension* const ddata = (wm_drums_extension*)data; - ddata->bt = 0; + wm_drums_extension* const ddata = (wm_drums_extension*)data; + ddata->bt = 0; - // calibration data not figured out yet? + // calibration data not figured out yet? - // stick - { - ControlState x, y; - m_stick->GetState(&x, &y); + // stick + { + ControlState x, y; + m_stick->GetState(&x, &y); - ddata->sx = static_cast((x * 0x1F) + 0x20); - ddata->sy = static_cast((y * 0x1F) + 0x20); - } + ddata->sx = static_cast((x * 0x1F) + 0x20); + ddata->sy = static_cast((y * 0x1F) + 0x20); + } - // TODO: softness maybe - data[2] = 0xFF; - data[3] = 0xFF; + // TODO: softness maybe + data[2] = 0xFF; + data[3] = 0xFF; - // buttons - m_buttons->GetState(&ddata->bt, drum_button_bitmasks); - // pads - m_pads->GetState(&ddata->bt, drum_pad_bitmasks); + // buttons + m_buttons->GetState(&ddata->bt, drum_button_bitmasks); + // pads + m_pads->GetState(&ddata->bt, drum_pad_bitmasks); - // flip button bits - ddata->bt ^= 0xFFFF; + // flip button bits + ddata->bt ^= 0xFFFF; } bool Drums::IsButtonPressed() const { - u16 buttons = 0; - m_buttons->GetState(&buttons, drum_button_bitmasks); - m_pads->GetState(&buttons, drum_pad_bitmasks); - return buttons != 0; + u16 buttons = 0; + m_buttons->GetState(&buttons, drum_button_bitmasks); + m_pads->GetState(&buttons, drum_pad_bitmasks); + return buttons != 0; } - } diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Drums.h b/Source/Core/Core/HW/WiimoteEmu/Attachment/Drums.h index adb4032b29..36d22883a0 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Drums.h +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Drums.h @@ -8,33 +8,31 @@ namespace WiimoteEmu { - struct ExtensionReg; class Drums : public Attachment { public: - Drums(WiimoteEmu::ExtensionReg& _reg); - void GetState(u8* const data) override; - bool IsButtonPressed() const override; + Drums(WiimoteEmu::ExtensionReg& _reg); + void GetState(u8* const data) override; + bool IsButtonPressed() const override; - enum - { - BUTTON_PLUS = 0x04, - BUTTON_MINUS = 0x10, + enum + { + BUTTON_PLUS = 0x04, + BUTTON_MINUS = 0x10, - PAD_BASS = 0x0400, - PAD_BLUE = 0x0800, - PAD_GREEN = 0x1000, - PAD_YELLOW = 0x2000, - PAD_RED = 0x4000, - PAD_ORANGE = 0x8000, - }; + PAD_BASS = 0x0400, + PAD_BLUE = 0x0800, + PAD_GREEN = 0x1000, + PAD_YELLOW = 0x2000, + PAD_RED = 0x4000, + PAD_ORANGE = 0x8000, + }; private: - Buttons* m_buttons; - Buttons* m_pads; - AnalogStick* m_stick; + Buttons* m_buttons; + Buttons* m_pads; + AnalogStick* m_stick; }; - } diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Guitar.cpp b/Source/Core/Core/HW/WiimoteEmu/Attachment/Guitar.cpp index d3738a1ec5..aac7f5e325 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Guitar.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Guitar.cpp @@ -6,111 +6,100 @@ #include "Common/Common.h" #include "Common/CommonTypes.h" -#include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteEmu/Attachment/Guitar.h" +#include "Core/HW/WiimoteEmu/WiimoteEmu.h" namespace WiimoteEmu { +static const u8 guitar_id[] = {0x00, 0x00, 0xa4, 0x20, 0x01, 0x03}; -static const u8 guitar_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x01, 0x03 }; - -static const u16 guitar_fret_bitmasks[] = -{ - Guitar::FRET_GREEN, - Guitar::FRET_RED, - Guitar::FRET_YELLOW, - Guitar::FRET_BLUE, - Guitar::FRET_ORANGE, +static const u16 guitar_fret_bitmasks[] = { + Guitar::FRET_GREEN, Guitar::FRET_RED, Guitar::FRET_YELLOW, + Guitar::FRET_BLUE, Guitar::FRET_ORANGE, }; -static const char* const guitar_fret_names[] = -{ - "Green","Red","Yellow","Blue","Orange", +static const char* const guitar_fret_names[] = { + "Green", "Red", "Yellow", "Blue", "Orange", }; -static const u16 guitar_button_bitmasks[] = -{ - Guitar::BUTTON_MINUS, - Guitar::BUTTON_PLUS, +static const u16 guitar_button_bitmasks[] = { + Guitar::BUTTON_MINUS, Guitar::BUTTON_PLUS, }; -static const u16 guitar_strum_bitmasks[] = -{ - Guitar::BAR_UP, - Guitar::BAR_DOWN, +static const u16 guitar_strum_bitmasks[] = { + Guitar::BAR_UP, Guitar::BAR_DOWN, }; Guitar::Guitar(WiimoteEmu::ExtensionReg& _reg) : Attachment(_trans("Guitar"), _reg) { - // frets - groups.emplace_back(m_frets = new Buttons(_trans("Frets"))); - for (auto& guitar_fret_name : guitar_fret_names) - m_frets->controls.emplace_back(new ControlGroup::Input(guitar_fret_name)); + // frets + groups.emplace_back(m_frets = new Buttons(_trans("Frets"))); + for (auto& guitar_fret_name : guitar_fret_names) + m_frets->controls.emplace_back(new ControlGroup::Input(guitar_fret_name)); - // strum - groups.emplace_back(m_strum = new Buttons(_trans("Strum"))); - m_strum->controls.emplace_back(new ControlGroup::Input("Up")); - m_strum->controls.emplace_back(new ControlGroup::Input("Down")); + // strum + groups.emplace_back(m_strum = new Buttons(_trans("Strum"))); + m_strum->controls.emplace_back(new ControlGroup::Input("Up")); + m_strum->controls.emplace_back(new ControlGroup::Input("Down")); - // buttons - groups.emplace_back(m_buttons = new Buttons("Buttons")); - m_buttons->controls.emplace_back(new ControlGroup::Input("-")); - m_buttons->controls.emplace_back(new ControlGroup::Input("+")); + // buttons + groups.emplace_back(m_buttons = new Buttons("Buttons")); + m_buttons->controls.emplace_back(new ControlGroup::Input("-")); + m_buttons->controls.emplace_back(new ControlGroup::Input("+")); - // stick - groups.emplace_back(m_stick = new AnalogStick(_trans("Stick"), DEFAULT_ATTACHMENT_STICK_RADIUS)); + // stick + groups.emplace_back(m_stick = new AnalogStick(_trans("Stick"), DEFAULT_ATTACHMENT_STICK_RADIUS)); - // whammy - groups.emplace_back(m_whammy = new Triggers(_trans("Whammy"))); - m_whammy->controls.emplace_back(new ControlGroup::Input(_trans("Bar"))); + // whammy + groups.emplace_back(m_whammy = new Triggers(_trans("Whammy"))); + m_whammy->controls.emplace_back(new ControlGroup::Input(_trans("Bar"))); - // set up register - // id - memcpy(&id, guitar_id, sizeof(guitar_id)); + // set up register + // id + memcpy(&id, guitar_id, sizeof(guitar_id)); } void Guitar::GetState(u8* const data) { - wm_guitar_extension* const gdata = (wm_guitar_extension*)data; - gdata->bt = 0; + wm_guitar_extension* const gdata = (wm_guitar_extension*)data; + gdata->bt = 0; - // calibration data not figured out yet? + // calibration data not figured out yet? - // stick - { - ControlState x, y; - m_stick->GetState(&x, &y); + // stick + { + ControlState x, y; + m_stick->GetState(&x, &y); - gdata->sx = static_cast((x * 0x1F) + 0x20); - gdata->sy = static_cast((y * 0x1F) + 0x20); - } + gdata->sx = static_cast((x * 0x1F) + 0x20); + gdata->sy = static_cast((y * 0x1F) + 0x20); + } - // TODO: touch bar, probably not - gdata->tb = 0x0F; // not touched + // TODO: touch bar, probably not + gdata->tb = 0x0F; // not touched - // whammy bar - ControlState whammy; - m_whammy->GetState(&whammy); - gdata->whammy = static_cast(whammy * 0x1F); + // whammy bar + ControlState whammy; + m_whammy->GetState(&whammy); + gdata->whammy = static_cast(whammy * 0x1F); - // buttons - m_buttons->GetState(&gdata->bt, guitar_button_bitmasks); - // frets - m_frets->GetState(&gdata->bt, guitar_fret_bitmasks); - // strum - m_strum->GetState(&gdata->bt, guitar_strum_bitmasks); + // buttons + m_buttons->GetState(&gdata->bt, guitar_button_bitmasks); + // frets + m_frets->GetState(&gdata->bt, guitar_fret_bitmasks); + // strum + m_strum->GetState(&gdata->bt, guitar_strum_bitmasks); - // flip button bits - gdata->bt ^= 0xFFFF; + // flip button bits + gdata->bt ^= 0xFFFF; } bool Guitar::IsButtonPressed() const { - u16 buttons = 0; - m_buttons->GetState(&buttons, guitar_button_bitmasks); - m_frets->GetState(&buttons, guitar_fret_bitmasks); - m_strum->GetState(&buttons, guitar_strum_bitmasks); - return buttons != 0; + u16 buttons = 0; + m_buttons->GetState(&buttons, guitar_button_bitmasks); + m_frets->GetState(&buttons, guitar_fret_bitmasks); + m_strum->GetState(&buttons, guitar_strum_bitmasks); + return buttons != 0; } - } diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Guitar.h b/Source/Core/Core/HW/WiimoteEmu/Attachment/Guitar.h index a120ed891b..9d9a4d4130 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Guitar.h +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Guitar.h @@ -8,36 +8,34 @@ namespace WiimoteEmu { - struct ExtensionReg; class Guitar : public Attachment { public: - Guitar(WiimoteEmu::ExtensionReg& _reg); - void GetState(u8* const data) override; - bool IsButtonPressed() const override; + Guitar(WiimoteEmu::ExtensionReg& _reg); + void GetState(u8* const data) override; + bool IsButtonPressed() const override; - enum - { - BUTTON_PLUS = 0x04, - BUTTON_MINUS = 0x10, - BAR_DOWN = 0x40, + enum + { + BUTTON_PLUS = 0x04, + BUTTON_MINUS = 0x10, + BAR_DOWN = 0x40, - BAR_UP = 0x0100, - FRET_YELLOW = 0x0800, - FRET_GREEN = 0x1000, - FRET_BLUE = 0x2000, - FRET_RED = 0x4000, - FRET_ORANGE = 0x8000, - }; + BAR_UP = 0x0100, + FRET_YELLOW = 0x0800, + FRET_GREEN = 0x1000, + FRET_BLUE = 0x2000, + FRET_RED = 0x4000, + FRET_ORANGE = 0x8000, + }; private: - Buttons* m_buttons; - Buttons* m_frets; - Buttons* m_strum; - Triggers* m_whammy; - AnalogStick* m_stick; + Buttons* m_buttons; + Buttons* m_frets; + Buttons* m_strum; + Triggers* m_whammy; + AnalogStick* m_stick; }; - } diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp b/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp index 6a798fd2b0..91a27ed99d 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp @@ -7,135 +7,131 @@ #include "Common/Common.h" #include "Common/CommonTypes.h" #include "Common/MathUtil.h" -#include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteEmu/Attachment/Nunchuk.h" +#include "Core/HW/WiimoteEmu/WiimoteEmu.h" namespace WiimoteEmu { +static const u8 nunchuk_id[] = {0x00, 0x00, 0xa4, 0x20, 0x00, 0x00}; -static const u8 nunchuk_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x00, 0x00 }; - -static const u8 nunchuk_button_bitmasks[] = -{ - Nunchuk::BUTTON_C, - Nunchuk::BUTTON_Z, +static const u8 nunchuk_button_bitmasks[] = { + Nunchuk::BUTTON_C, Nunchuk::BUTTON_Z, }; Nunchuk::Nunchuk(WiimoteEmu::ExtensionReg& _reg) : Attachment(_trans("Nunchuk"), _reg) { - // buttons - groups.emplace_back(m_buttons = new Buttons("Buttons")); - m_buttons->controls.emplace_back(new ControlGroup::Input("C")); - m_buttons->controls.emplace_back(new ControlGroup::Input("Z")); + // buttons + groups.emplace_back(m_buttons = new Buttons("Buttons")); + m_buttons->controls.emplace_back(new ControlGroup::Input("C")); + m_buttons->controls.emplace_back(new ControlGroup::Input("Z")); - // stick - groups.emplace_back(m_stick = new AnalogStick("Stick", DEFAULT_ATTACHMENT_STICK_RADIUS)); + // stick + groups.emplace_back(m_stick = new AnalogStick("Stick", DEFAULT_ATTACHMENT_STICK_RADIUS)); - // swing - groups.emplace_back(m_swing = new Force("Swing")); + // swing + groups.emplace_back(m_swing = new Force("Swing")); - // tilt - groups.emplace_back(m_tilt = new Tilt("Tilt")); + // tilt + groups.emplace_back(m_tilt = new Tilt("Tilt")); - // shake - groups.emplace_back(m_shake = new Buttons("Shake")); - m_shake->controls.emplace_back(new ControlGroup::Input("X")); - m_shake->controls.emplace_back(new ControlGroup::Input("Y")); - m_shake->controls.emplace_back(new ControlGroup::Input("Z")); + // shake + groups.emplace_back(m_shake = new Buttons("Shake")); + m_shake->controls.emplace_back(new ControlGroup::Input("X")); + m_shake->controls.emplace_back(new ControlGroup::Input("Y")); + m_shake->controls.emplace_back(new ControlGroup::Input("Z")); - // id - memcpy(&id, nunchuk_id, sizeof(nunchuk_id)); + // id + memcpy(&id, nunchuk_id, sizeof(nunchuk_id)); - // this should get set to 0 on disconnect, but it isn't, o well - memset(m_shake_step, 0, sizeof(m_shake_step)); + // this should get set to 0 on disconnect, but it isn't, o well + memset(m_shake_step, 0, sizeof(m_shake_step)); } void Nunchuk::GetState(u8* const data) { - wm_nc* const ncdata = (wm_nc*)data; - ncdata->bt.hex = 0; + wm_nc* const ncdata = (wm_nc*)data; + ncdata->bt.hex = 0; - // stick - double jx, jy; - m_stick->GetState(&jx, &jy); + // stick + double jx, jy; + m_stick->GetState(&jx, &jy); - ncdata->jx = u8(STICK_CENTER + jx * STICK_RADIUS); - ncdata->jy = u8(STICK_CENTER + jy * STICK_RADIUS); + ncdata->jx = u8(STICK_CENTER + jx * STICK_RADIUS); + ncdata->jy = u8(STICK_CENTER + jy * STICK_RADIUS); - // Some terribly coded games check whether to move with a check like - // - // if (x != 0 && y != 0) - // do_movement(x, y); - // - // With keyboard controls, these games break if you simply hit - // of the axes. Adjust this if you're hitting one of the axes so that - // we slightly tweak the other axis. - if (ncdata->jx != STICK_CENTER || ncdata->jy != STICK_CENTER) - { - if (ncdata->jx == STICK_CENTER) - ++ncdata->jx; - if (ncdata->jy == STICK_CENTER) - ++ncdata->jy; - } + // Some terribly coded games check whether to move with a check like + // + // if (x != 0 && y != 0) + // do_movement(x, y); + // + // With keyboard controls, these games break if you simply hit + // of the axes. Adjust this if you're hitting one of the axes so that + // we slightly tweak the other axis. + if (ncdata->jx != STICK_CENTER || ncdata->jy != STICK_CENTER) + { + if (ncdata->jx == STICK_CENTER) + ++ncdata->jx; + if (ncdata->jy == STICK_CENTER) + ++ncdata->jy; + } - AccelData accel; + AccelData accel; - // tilt - EmulateTilt(&accel, m_tilt); + // tilt + EmulateTilt(&accel, m_tilt); - // swing - EmulateSwing(&accel, m_swing); - // shake - EmulateShake(&accel, m_shake, m_shake_step); - // buttons - m_buttons->GetState(&ncdata->bt.hex, nunchuk_button_bitmasks); + // swing + EmulateSwing(&accel, m_swing); + // shake + EmulateShake(&accel, m_shake, m_shake_step); + // buttons + m_buttons->GetState(&ncdata->bt.hex, nunchuk_button_bitmasks); - // flip the button bits :/ - ncdata->bt.hex ^= 0x03; + // flip the button bits :/ + ncdata->bt.hex ^= 0x03; - // We now use 2 bits more precision, so multiply by 4 before converting to int - s16 accel_x = (s16)(4 * (accel.x * ACCEL_RANGE + ACCEL_ZERO_G)); - s16 accel_y = (s16)(4 * (accel.y * ACCEL_RANGE + ACCEL_ZERO_G)); - s16 accel_z = (s16)(4 * (accel.z * ACCEL_RANGE + ACCEL_ZERO_G)); + // We now use 2 bits more precision, so multiply by 4 before converting to int + s16 accel_x = (s16)(4 * (accel.x * ACCEL_RANGE + ACCEL_ZERO_G)); + s16 accel_y = (s16)(4 * (accel.y * ACCEL_RANGE + ACCEL_ZERO_G)); + s16 accel_z = (s16)(4 * (accel.z * ACCEL_RANGE + ACCEL_ZERO_G)); - accel_x = MathUtil::Clamp(accel_x, 0, 1024); - accel_y = MathUtil::Clamp(accel_y, 0, 1024); - accel_z = MathUtil::Clamp(accel_z, 0, 1024); + accel_x = MathUtil::Clamp(accel_x, 0, 1024); + accel_y = MathUtil::Clamp(accel_y, 0, 1024); + accel_z = MathUtil::Clamp(accel_z, 0, 1024); - ncdata->ax = (accel_x >> 2) & 0xFF; - ncdata->ay = (accel_y >> 2) & 0xFF; - ncdata->az = (accel_z >> 2) & 0xFF; - ncdata->bt.acc_x_lsb = accel_x & 0x3; - ncdata->bt.acc_y_lsb = accel_y & 0x3; - ncdata->bt.acc_z_lsb = accel_z & 0x3; + ncdata->ax = (accel_x >> 2) & 0xFF; + ncdata->ay = (accel_y >> 2) & 0xFF; + ncdata->az = (accel_z >> 2) & 0xFF; + ncdata->bt.acc_x_lsb = accel_x & 0x3; + ncdata->bt.acc_y_lsb = accel_y & 0x3; + ncdata->bt.acc_z_lsb = accel_z & 0x3; } bool Nunchuk::IsButtonPressed() const { - u8 buttons = 0; - m_buttons->GetState(&buttons, nunchuk_button_bitmasks); - return buttons != 0; + u8 buttons = 0; + m_buttons->GetState(&buttons, nunchuk_button_bitmasks); + return buttons != 0; } void Nunchuk::LoadDefaults(const ControllerInterface& ciface) { - // Stick - m_stick->SetControlExpression(0, "W"); // up - m_stick->SetControlExpression(1, "S"); // down - m_stick->SetControlExpression(2, "A"); // left - m_stick->SetControlExpression(3, "D"); // right + // Stick + m_stick->SetControlExpression(0, "W"); // up + m_stick->SetControlExpression(1, "S"); // down + m_stick->SetControlExpression(2, "A"); // left + m_stick->SetControlExpression(3, "D"); // right - // Buttons +// Buttons #ifdef _WIN32 - m_buttons->SetControlExpression(0, "LCONTROL"); // C - m_buttons->SetControlExpression(1, "LSHIFT"); // Z + m_buttons->SetControlExpression(0, "LCONTROL"); // C + m_buttons->SetControlExpression(1, "LSHIFT"); // Z #elif __APPLE__ - m_buttons->SetControlExpression(0, "Left Control"); // C - m_buttons->SetControlExpression(1, "Left Shift"); // Z + m_buttons->SetControlExpression(0, "Left Control"); // C + m_buttons->SetControlExpression(1, "Left Shift"); // Z #else - m_buttons->SetControlExpression(0, "Control_L"); // C - m_buttons->SetControlExpression(1, "Shift_L"); // Z + m_buttons->SetControlExpression(0, "Control_L"); // C + m_buttons->SetControlExpression(1, "Shift_L"); // Z #endif } - } diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.h b/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.h index 3470fe94a3..236163eecb 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.h +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.h @@ -8,48 +8,46 @@ namespace WiimoteEmu { - struct ExtensionReg; class Nunchuk : public Attachment { public: - Nunchuk(WiimoteEmu::ExtensionReg& _reg); + Nunchuk(WiimoteEmu::ExtensionReg& _reg); - void GetState(u8* const data) override; - bool IsButtonPressed() const override; + void GetState(u8* const data) override; + bool IsButtonPressed() const override; - enum - { - BUTTON_C = 0x02, - BUTTON_Z = 0x01, - }; + enum + { + BUTTON_C = 0x02, + BUTTON_Z = 0x01, + }; - enum - { - ACCEL_ZERO_G = 0x80, - ACCEL_ONE_G = 0xB3, - ACCEL_RANGE = (ACCEL_ONE_G - ACCEL_ZERO_G), - }; + enum + { + ACCEL_ZERO_G = 0x80, + ACCEL_ONE_G = 0xB3, + ACCEL_RANGE = (ACCEL_ONE_G - ACCEL_ZERO_G), + }; - enum - { - STICK_CENTER = 0x80, - STICK_RADIUS = 0x7F, - }; + enum + { + STICK_CENTER = 0x80, + STICK_RADIUS = 0x7F, + }; - void LoadDefaults(const ControllerInterface& ciface) override; + void LoadDefaults(const ControllerInterface& ciface) override; private: - Tilt* m_tilt; - Force* m_swing; + Tilt* m_tilt; + Force* m_swing; - Buttons* m_shake; + Buttons* m_shake; - Buttons* m_buttons; - AnalogStick* m_stick; + Buttons* m_buttons; + AnalogStick* m_stick; - u8 m_shake_step[3]; + u8 m_shake_step[3]; }; - } diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Turntable.cpp b/Source/Core/Core/HW/WiimoteEmu/Attachment/Turntable.cpp index edfa5dfbe7..ed0678951d 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Turntable.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Turntable.cpp @@ -6,136 +6,129 @@ #include "Common/Common.h" #include "Common/CommonTypes.h" -#include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteEmu/Attachment/Turntable.h" +#include "Core/HW/WiimoteEmu/WiimoteEmu.h" namespace WiimoteEmu { - static const u8 turntable_id[] = {0x03, 0x00, 0xa4, 0x20, 0x01, 0x03}; -static const u16 turntable_button_bitmasks[] = -{ - Turntable::BUTTON_L_GREEN, - Turntable::BUTTON_L_RED, - Turntable::BUTTON_L_BLUE, - Turntable::BUTTON_R_GREEN, - Turntable::BUTTON_R_RED, - Turntable::BUTTON_R_BLUE, - Turntable::BUTTON_MINUS, - Turntable::BUTTON_PLUS, - Turntable::BUTTON_EUPHORIA, +static const u16 turntable_button_bitmasks[] = { + Turntable::BUTTON_L_GREEN, Turntable::BUTTON_L_RED, Turntable::BUTTON_L_BLUE, + Turntable::BUTTON_R_GREEN, Turntable::BUTTON_R_RED, Turntable::BUTTON_R_BLUE, + Turntable::BUTTON_MINUS, Turntable::BUTTON_PLUS, Turntable::BUTTON_EUPHORIA, }; -static const char* const turntable_button_names[] = -{ - _trans("Green Left"), _trans("Red Left"), _trans("Blue Left"), - _trans("Green Right"), _trans("Red Right"), _trans("Blue Right"), - "-", "+", _trans("Euphoria"), +static const char* const turntable_button_names[] = { + _trans("Green Left"), + _trans("Red Left"), + _trans("Blue Left"), + _trans("Green Right"), + _trans("Red Right"), + _trans("Blue Right"), + "-", + "+", + _trans("Euphoria"), }; Turntable::Turntable(WiimoteEmu::ExtensionReg& _reg) : Attachment(_trans("Turntable"), _reg) { - // buttons - groups.emplace_back(m_buttons = new Buttons("Buttons")); - for (auto& turntable_button_name : turntable_button_names) - m_buttons->controls.emplace_back(new ControlGroup::Input(turntable_button_name)); + // buttons + groups.emplace_back(m_buttons = new Buttons("Buttons")); + for (auto& turntable_button_name : turntable_button_names) + m_buttons->controls.emplace_back(new ControlGroup::Input(turntable_button_name)); - // turntables - groups.emplace_back(m_left_table = new Slider(_trans("Table Left"))); - groups.emplace_back(m_right_table = new Slider(_trans("Table Right"))); + // turntables + groups.emplace_back(m_left_table = new Slider(_trans("Table Left"))); + groups.emplace_back(m_right_table = new Slider(_trans("Table Right"))); - // stick - groups.emplace_back(m_stick = new AnalogStick("Stick", DEFAULT_ATTACHMENT_STICK_RADIUS)); + // stick + groups.emplace_back(m_stick = new AnalogStick("Stick", DEFAULT_ATTACHMENT_STICK_RADIUS)); - // effect dial - groups.emplace_back(m_effect_dial = new Triggers(_trans("Effect"))); - m_effect_dial->controls.emplace_back(new ControlGroup::Input(_trans("Dial"))); + // effect dial + groups.emplace_back(m_effect_dial = new Triggers(_trans("Effect"))); + m_effect_dial->controls.emplace_back(new ControlGroup::Input(_trans("Dial"))); - // crossfade - groups.emplace_back(m_crossfade = new Slider(_trans("Crossfade"))); + // crossfade + groups.emplace_back(m_crossfade = new Slider(_trans("Crossfade"))); - // set up register - // id - memcpy(&id, turntable_id, sizeof(turntable_id)); + // set up register + // id + memcpy(&id, turntable_id, sizeof(turntable_id)); } void Turntable::GetState(u8* const data) { - wm_turntable_extension* const ttdata = (wm_turntable_extension*)data; - ttdata->bt = 0; + wm_turntable_extension* const ttdata = (wm_turntable_extension*)data; + ttdata->bt = 0; - // stick - { - ControlState x, y; - m_stick->GetState(&x, &y); + // stick + { + ControlState x, y; + m_stick->GetState(&x, &y); - ttdata->sx = static_cast((x * 0x1F) + 0x20); - ttdata->sy = static_cast((y * 0x1F) + 0x20); - } + ttdata->sx = static_cast((x * 0x1F) + 0x20); + ttdata->sy = static_cast((y * 0x1F) + 0x20); + } - // left table - { - ControlState tt; - s8 tt_; - m_left_table->GetState(&tt); + // left table + { + ControlState tt; + s8 tt_; + m_left_table->GetState(&tt); - tt_ = static_cast(tt * 0x1F); + tt_ = static_cast(tt * 0x1F); - ttdata->ltable1 = tt_; - ttdata->ltable2 = tt_ >> 5; - } + ttdata->ltable1 = tt_; + ttdata->ltable2 = tt_ >> 5; + } - // right table - { - ControlState tt; - s8 tt_; - m_right_table->GetState(&tt); + // right table + { + ControlState tt; + s8 tt_; + m_right_table->GetState(&tt); - tt_ = static_cast(tt * 0x1F); + tt_ = static_cast(tt * 0x1F); - ttdata->rtable1 = tt_; - ttdata->rtable2 = tt_ >> 1; - ttdata->rtable3 = tt_ >> 3; - ttdata->rtable4 = tt_ >> 5; - } + ttdata->rtable1 = tt_; + ttdata->rtable2 = tt_ >> 1; + ttdata->rtable3 = tt_ >> 3; + ttdata->rtable4 = tt_ >> 5; + } - // effect dial - { - ControlState dial; - u8 dial_; - m_effect_dial->GetState(&dial); + // effect dial + { + ControlState dial; + u8 dial_; + m_effect_dial->GetState(&dial); - dial_ = static_cast(dial * 0x0F); + dial_ = static_cast(dial * 0x0F); - ttdata->dial1 = dial_; - ttdata->dial2 = dial_ >> 3; - } + ttdata->dial1 = dial_; + ttdata->dial2 = dial_ >> 3; + } - // crossfade slider - { - ControlState cfs; - m_crossfade->GetState(&cfs); + // crossfade slider + { + ControlState cfs; + m_crossfade->GetState(&cfs); - ttdata->slider = static_cast((cfs * 0x07) + 0x08); - } + ttdata->slider = static_cast((cfs * 0x07) + 0x08); + } - // buttons - m_buttons->GetState(&ttdata->bt, turntable_button_bitmasks); + // buttons + m_buttons->GetState(&ttdata->bt, turntable_button_bitmasks); - // flip button bits :/ - ttdata->bt ^= ( - BUTTON_L_GREEN | BUTTON_L_RED | BUTTON_L_BLUE | - BUTTON_R_GREEN | BUTTON_R_RED | BUTTON_R_BLUE | - BUTTON_MINUS | BUTTON_PLUS | BUTTON_EUPHORIA - ); + // flip button bits :/ + ttdata->bt ^= (BUTTON_L_GREEN | BUTTON_L_RED | BUTTON_L_BLUE | BUTTON_R_GREEN | BUTTON_R_RED | + BUTTON_R_BLUE | BUTTON_MINUS | BUTTON_PLUS | BUTTON_EUPHORIA); } bool Turntable::IsButtonPressed() const { - u16 buttons = 0; - m_buttons->GetState(&buttons, turntable_button_bitmasks); - return buttons != 0; + u16 buttons = 0; + m_buttons->GetState(&buttons, turntable_button_bitmasks); + return buttons != 0; } - } diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Turntable.h b/Source/Core/Core/HW/WiimoteEmu/Attachment/Turntable.h index 132d9946e4..ed037e5f28 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Turntable.h +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Turntable.h @@ -8,39 +8,37 @@ namespace WiimoteEmu { - struct ExtensionReg; class Turntable : public Attachment { public: - Turntable(WiimoteEmu::ExtensionReg& _reg); - void GetState(u8* const data) override; - bool IsButtonPressed() const override; + Turntable(WiimoteEmu::ExtensionReg& _reg); + void GetState(u8* const data) override; + bool IsButtonPressed() const override; - enum - { - BUTTON_EUPHORIA = 0x1000, + enum + { + BUTTON_EUPHORIA = 0x1000, - BUTTON_L_GREEN = 0x0800, - BUTTON_L_RED = 0x20, - BUTTON_L_BLUE = 0x8000, + BUTTON_L_GREEN = 0x0800, + BUTTON_L_RED = 0x20, + BUTTON_L_BLUE = 0x8000, - BUTTON_R_GREEN = 0x2000, - BUTTON_R_RED = 0x02, - BUTTON_R_BLUE = 0x0400, + BUTTON_R_GREEN = 0x2000, + BUTTON_R_RED = 0x02, + BUTTON_R_BLUE = 0x0400, - BUTTON_MINUS = 0x10, - BUTTON_PLUS = 0x04, - }; + BUTTON_MINUS = 0x10, + BUTTON_PLUS = 0x04, + }; private: - Buttons* m_buttons; - AnalogStick* m_stick; - Triggers* m_effect_dial; - Slider* m_left_table; - Slider* m_right_table; - Slider* m_crossfade; + Buttons* m_buttons; + AnalogStick* m_stick; + Triggers* m_effect_dial; + Slider* m_left_table; + Slider* m_right_table; + Slider* m_crossfade; }; - } diff --git a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp index 78d68e5f2a..ea6327b32b 100644 --- a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp @@ -2,18 +2,17 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - /* HID reports access guide. */ /* 0x10 - 0x1a Output EmuMain.cpp: HidOutputReport() 0x10 - 0x14: General - 0x15: Status report request from the Wii - 0x16 and 0x17: Write and read memory or registers + 0x15: Status report request from the Wii + 0x16 and 0x17: Write and read memory or registers 0x19 and 0x1a: General 0x20 - 0x22 Input EmuMain.cpp: HidOutputReport() to the destination 0x15 leads to a 0x20 Input report 0x17 leads to a 0x21 Input report - 0x10 - 0x1a leads to a 0x22 Input report + 0x10 - 0x1a leads to a 0x22 Input report 0x30 - 0x3f Input This file: Update() */ #include @@ -24,37 +23,36 @@ #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "Core/Core.h" +#include "Core/HW/WiimoteEmu/Attachment/Attachment.h" #include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteEmu/WiimoteHid.h" -#include "Core/HW/WiimoteEmu/Attachment/Attachment.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" namespace WiimoteEmu { - void Wiimote::ReportMode(const wm_report_mode* const dr) { - //INFO_LOG(WIIMOTE, "Set data report mode"); - //DEBUG_LOG(WIIMOTE, " Rumble: %x", dr->rumble); - //DEBUG_LOG(WIIMOTE, " Continuous: %x", dr->continuous); - //DEBUG_LOG(WIIMOTE, " All The Time: %x", dr->all_the_time); - //DEBUG_LOG(WIIMOTE, " Mode: 0x%02x", dr->mode); + // INFO_LOG(WIIMOTE, "Set data report mode"); + // DEBUG_LOG(WIIMOTE, " Rumble: %x", dr->rumble); + // DEBUG_LOG(WIIMOTE, " Continuous: %x", dr->continuous); + // DEBUG_LOG(WIIMOTE, " All The Time: %x", dr->all_the_time); + // DEBUG_LOG(WIIMOTE, " Mode: 0x%02x", dr->mode); - //m_reporting_auto = dr->all_the_time; - m_reporting_auto = dr->continuous; // this right? - m_reporting_mode = dr->mode; - //m_reporting_channel = _channelID; // this is set in every Interrupt/Control Channel now + // m_reporting_auto = dr->all_the_time; + m_reporting_auto = dr->continuous; // this right? + m_reporting_mode = dr->mode; + // m_reporting_channel = _channelID; // this is set in every Interrupt/Control Channel now - // reset IR camera - //memset(m_reg_ir, 0, sizeof(*m_reg_ir)); //ugly hack + // reset IR camera + // memset(m_reg_ir, 0, sizeof(*m_reg_ir)); //ugly hack - if (dr->mode > 0x37) - PanicAlert("Wiimote: Unsupported Reporting mode."); - else if (dr->mode < WM_REPORT_CORE) - PanicAlert("Wiimote: Reporting mode < 0x30."); + if (dr->mode > 0x37) + PanicAlert("Wiimote: Unsupported Reporting mode."); + else if (dr->mode < WM_REPORT_CORE) + PanicAlert("Wiimote: Reporting mode < 0x30."); } /* Here we process the Output Reports that the Wii sends. Our response will be @@ -68,102 +66,103 @@ void Wiimote::ReportMode(const wm_report_mode* const dr) 2. Wiimote_ControlChannel > ControlChannel > HidOutputReport The IR enable/disable and speaker enable/disable and mute/unmute values are - bit2: 0 = Disable (0x02), 1 = Enable (0x06) + bit2: 0 = Disable (0x02), 1 = Enable (0x06) */ void Wiimote::HidOutputReport(const wm_report* const sr, const bool send_ack) { - INFO_LOG(WIIMOTE, "HidOutputReport (page: %i, cid: 0x%02x, wm: 0x%02x)", m_index, m_reporting_channel, sr->wm); + INFO_LOG(WIIMOTE, "HidOutputReport (page: %i, cid: 0x%02x, wm: 0x%02x)", m_index, + m_reporting_channel, sr->wm); - // WiiBrew: - // In every single Output Report, bit 0 (0x01) of the first byte controls the Rumble feature. - m_rumble_on = sr->rumble; + // WiiBrew: + // In every single Output Report, bit 0 (0x01) of the first byte controls the Rumble feature. + m_rumble_on = sr->rumble; - switch (sr->wm) - { - case WM_RUMBLE : // 0x10 - // this is handled above - return; // no ack - break; + switch (sr->wm) + { + case WM_RUMBLE: // 0x10 + // this is handled above + return; // no ack + break; - case WM_LEDS : // 0x11 - //INFO_LOG(WIIMOTE, "Set LEDs: 0x%02x", sr->data[0]); - m_status.leds = sr->data[0] >> 4; - break; + case WM_LEDS: // 0x11 + // INFO_LOG(WIIMOTE, "Set LEDs: 0x%02x", sr->data[0]); + m_status.leds = sr->data[0] >> 4; + break; - case WM_REPORT_MODE : // 0x12 - ReportMode((wm_report_mode*)sr->data); - break; + case WM_REPORT_MODE: // 0x12 + ReportMode((wm_report_mode*)sr->data); + break; - case WM_IR_PIXEL_CLOCK : // 0x13 - //INFO_LOG(WIIMOTE, "WM IR Clock: 0x%02x", sr->data[0]); - //m_ir_clock = sr->enable; - if (false == sr->ack) - return; - break; + case WM_IR_PIXEL_CLOCK: // 0x13 + // INFO_LOG(WIIMOTE, "WM IR Clock: 0x%02x", sr->data[0]); + // m_ir_clock = sr->enable; + if (false == sr->ack) + return; + break; - case WM_SPEAKER_ENABLE : // 0x14 - //ERROR_LOG(WIIMOTE, "WM Speaker Enable: %02x", sr->enable); - //PanicAlert( "WM Speaker Enable: %d", sr->data[0] ); - m_status.speaker = sr->enable; - if (false == sr->ack) - return; - break; + case WM_SPEAKER_ENABLE: // 0x14 + // ERROR_LOG(WIIMOTE, "WM Speaker Enable: %02x", sr->enable); + // PanicAlert( "WM Speaker Enable: %d", sr->data[0] ); + m_status.speaker = sr->enable; + if (false == sr->ack) + return; + break; - case WM_REQUEST_STATUS : // 0x15 - if (WIIMOTE_SRC_EMU & g_wiimote_sources[m_index]) - RequestStatus((wm_request_status*)sr->data); - return; // sends its own ack - break; + case WM_REQUEST_STATUS: // 0x15 + if (WIIMOTE_SRC_EMU & g_wiimote_sources[m_index]) + RequestStatus((wm_request_status*)sr->data); + return; // sends its own ack + break; - case WM_WRITE_DATA : // 0x16 - WriteData((wm_write_data*)sr->data); - break; + case WM_WRITE_DATA: // 0x16 + WriteData((wm_write_data*)sr->data); + break; - case WM_READ_DATA : // 0x17 - if (WIIMOTE_SRC_EMU & g_wiimote_sources[m_index]) - ReadData((wm_read_data*)sr->data); - return; // sends its own ack - break; + case WM_READ_DATA: // 0x17 + if (WIIMOTE_SRC_EMU & g_wiimote_sources[m_index]) + ReadData((wm_read_data*)sr->data); + return; // sends its own ack + break; - case WM_WRITE_SPEAKER_DATA : // 0x18 - //wm_speaker_data *spkz = (wm_speaker_data*)sr->data; - //ERROR_LOG(WIIMOTE, "WM_WRITE_SPEAKER_DATA len:%x %s", spkz->length, - // ArrayToString(spkz->data, spkz->length, 100, false).c_str()); - if (WIIMOTE_SRC_EMU & g_wiimote_sources[m_index] && !m_speaker_mute) - Wiimote::SpeakerData((wm_speaker_data*) sr->data); - return; // no ack - break; + case WM_WRITE_SPEAKER_DATA: // 0x18 + // wm_speaker_data *spkz = (wm_speaker_data*)sr->data; + // ERROR_LOG(WIIMOTE, "WM_WRITE_SPEAKER_DATA len:%x %s", spkz->length, + // ArrayToString(spkz->data, spkz->length, 100, false).c_str()); + if (WIIMOTE_SRC_EMU & g_wiimote_sources[m_index] && !m_speaker_mute) + Wiimote::SpeakerData((wm_speaker_data*)sr->data); + return; // no ack + break; - case WM_SPEAKER_MUTE : // 0x19 - //ERROR_LOG(WIIMOTE, "WM Speaker Mute: %02x", sr->enable); - //PanicAlert( "WM Speaker Mute: %d", sr->data[0] & 0x04 ); - // testing - //if (sr->data[0] & 0x04) - // memset(&m_channel_status, 0, sizeof(m_channel_status)); - m_speaker_mute = sr->enable; - if (false == sr->ack) - return; - break; + case WM_SPEAKER_MUTE: // 0x19 + // ERROR_LOG(WIIMOTE, "WM Speaker Mute: %02x", sr->enable); + // PanicAlert( "WM Speaker Mute: %d", sr->data[0] & 0x04 ); + // testing + // if (sr->data[0] & 0x04) + // memset(&m_channel_status, 0, sizeof(m_channel_status)); + m_speaker_mute = sr->enable; + if (false == sr->ack) + return; + break; - case WM_IR_LOGIC: // 0x1a - // comment from old plugin: - // This enables or disables the IR lights, we update the global variable g_IR - // so that WmRequestStatus() knows about it - //INFO_LOG(WIIMOTE, "WM IR Enable: 0x%02x", sr->data[0]); - m_status.ir = sr->enable; - if (false == sr->ack) - return; - break; + case WM_IR_LOGIC: // 0x1a + // comment from old plugin: + // This enables or disables the IR lights, we update the global variable g_IR + // so that WmRequestStatus() knows about it + // INFO_LOG(WIIMOTE, "WM IR Enable: 0x%02x", sr->data[0]); + m_status.ir = sr->enable; + if (false == sr->ack) + return; + break; - default: - PanicAlert("HidOutputReport: Unknown channel 0x%02x", sr->wm); - return; // no ack - break; - } + default: + PanicAlert("HidOutputReport: Unknown channel 0x%02x", sr->wm); + return; // no ack + break; + } - // send ack - if (send_ack && WIIMOTE_SRC_EMU & g_wiimote_sources[m_index]) - SendAck(sr->wm); + // send ack + if (send_ack && WIIMOTE_SRC_EMU & g_wiimote_sources[m_index]) + SendAck(sr->wm); } /* This will generate the 0x22 acknowledgement for most Input reports. @@ -173,36 +172,38 @@ void Wiimote::HidOutputReport(const wm_report* const sr, const bool send_ack) The last byte is the success code 00. */ void Wiimote::SendAck(u8 _reportID) { - u8 data[6]; + u8 data[6]; - data[0] = 0xA1; - data[1] = WM_ACK_DATA; + data[0] = 0xA1; + data[1] = WM_ACK_DATA; - wm_acknowledge* const ack = (wm_acknowledge*)(data + 2); + wm_acknowledge* const ack = (wm_acknowledge*)(data + 2); - ack->buttons = m_status.buttons; - ack->reportID = _reportID; - ack->errorID = 0; + ack->buttons = m_status.buttons; + ack->reportID = _reportID; + ack->errorID = 0; - Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, data, sizeof(data)); + Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, data, sizeof(data)); } void Wiimote::HandleExtensionSwap() { - // handle switch extension - if (m_extension->active_extension != m_extension->switch_extension) - { - // if an extension is currently connected and we want to switch to a different extension - if ((m_extension->active_extension > 0) && m_extension->switch_extension) - // detach extension first, wait til next Update() or RequestStatus() call to change to the new extension - m_extension->active_extension = 0; - else - // set the wanted extension - m_extension->active_extension = m_extension->switch_extension; + // handle switch extension + if (m_extension->active_extension != m_extension->switch_extension) + { + // if an extension is currently connected and we want to switch to a different extension + if ((m_extension->active_extension > 0) && m_extension->switch_extension) + // detach extension first, wait til next Update() or RequestStatus() call to change to the new + // extension + m_extension->active_extension = 0; + else + // set the wanted extension + m_extension->active_extension = m_extension->switch_extension; - // reset register - ((WiimoteEmu::Attachment*)m_extension->attachments[m_extension->active_extension].get())->Reset(); - } + // reset register + ((WiimoteEmu::Attachment*)m_extension->attachments[m_extension->active_extension].get()) + ->Reset(); + } } // old comment @@ -212,306 +213,310 @@ void Wiimote::HandleExtensionSwap() report. */ void Wiimote::RequestStatus(const wm_request_status* const rs) { - HandleExtensionSwap(); + HandleExtensionSwap(); - // update status struct - m_status.extension = (m_extension->active_extension || m_motion_plus_active) ? 1 : 0; + // update status struct + m_status.extension = (m_extension->active_extension || m_motion_plus_active) ? 1 : 0; - // set up report - u8 data[8]; - data[0] = 0xA1; - data[1] = WM_STATUS_REPORT; + // set up report + u8 data[8]; + data[0] = 0xA1; + data[1] = WM_STATUS_REPORT; - // status values - *(wm_status_report*)(data + 2) = m_status; + // status values + *(wm_status_report*)(data + 2) = m_status; - // hybrid Wiimote stuff - if (WIIMOTE_SRC_REAL & g_wiimote_sources[m_index] && (m_extension->switch_extension <= 0)) - { - using namespace WiimoteReal; + // hybrid Wiimote stuff + if (WIIMOTE_SRC_REAL & g_wiimote_sources[m_index] && (m_extension->switch_extension <= 0)) + { + using namespace WiimoteReal; - std::lock_guard lk(g_refresh_lock); + std::lock_guard lk(g_refresh_lock); - if (g_wiimotes[m_index]) - { - wm_request_status rpt = {}; - g_wiimotes[m_index]->QueueReport(WM_REQUEST_STATUS, &rpt, sizeof(rpt)); - } + if (g_wiimotes[m_index]) + { + wm_request_status rpt = {}; + g_wiimotes[m_index]->QueueReport(WM_REQUEST_STATUS, &rpt, sizeof(rpt)); + } - return; - } + return; + } - // send report - Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, data, sizeof(data)); + // send report + Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, data, sizeof(data)); } /* Write data to Wiimote and Extensions registers. */ void Wiimote::WriteData(const wm_write_data* const wd) { - u32 address = Common::swap24(wd->address); + u32 address = Common::swap24(wd->address); - // ignore the 0x010000 bit - address &= ~0x010000; + // ignore the 0x010000 bit + address &= ~0x010000; - if (wd->size > 16) - { - PanicAlert("WriteData: size is > 16 bytes"); - return; - } + if (wd->size > 16) + { + PanicAlert("WriteData: size is > 16 bytes"); + return; + } - switch (wd->space) - { - case WM_SPACE_EEPROM : - { - // Write to EEPROM + switch (wd->space) + { + case WM_SPACE_EEPROM: + { + // Write to EEPROM - if (address + wd->size > WIIMOTE_EEPROM_SIZE) - { - ERROR_LOG(WIIMOTE, "WriteData: address + size out of bounds!"); - PanicAlert("WriteData: address + size out of bounds!"); - return; - } - memcpy(m_eeprom + address, wd->data, wd->size); + if (address + wd->size > WIIMOTE_EEPROM_SIZE) + { + ERROR_LOG(WIIMOTE, "WriteData: address + size out of bounds!"); + PanicAlert("WriteData: address + size out of bounds!"); + return; + } + memcpy(m_eeprom + address, wd->data, wd->size); - // write mii data to file - // i need to improve this greatly - if (address >= 0x0FCA && address < 0x12C0) - { - // writing the whole mii block each write :/ - std::ofstream file; - OpenFStream(file, File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/mii.bin", std::ios::binary | std::ios::out); - file.write((char*)m_eeprom + 0x0FCA, 0x02f0); - file.close(); - } - } - break; + // write mii data to file + // i need to improve this greatly + if (address >= 0x0FCA && address < 0x12C0) + { + // writing the whole mii block each write :/ + std::ofstream file; + OpenFStream(file, File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/mii.bin", + std::ios::binary | std::ios::out); + file.write((char*)m_eeprom + 0x0FCA, 0x02f0); + file.close(); + } + } + break; - case WM_SPACE_REGS1 : - case WM_SPACE_REGS2 : - { - // Write to Control Register + case WM_SPACE_REGS1: + case WM_SPACE_REGS2: + { + // Write to Control Register - // ignore second byte for extension area - if (0xA4 == (address >> 16)) - address &= 0xFF00FF; + // ignore second byte for extension area + if (0xA4 == (address >> 16)) + address &= 0xFF00FF; - const u8 region_offset = (u8)address; - void *region_ptr = nullptr; - int region_size = 0; + const u8 region_offset = (u8)address; + void* region_ptr = nullptr; + int region_size = 0; - switch (address >> 16) - { - // speaker - case 0xa2 : - region_ptr = &m_reg_speaker; - region_size = WIIMOTE_REG_SPEAKER_SIZE; - break; + switch (address >> 16) + { + // speaker + case 0xa2: + region_ptr = &m_reg_speaker; + region_size = WIIMOTE_REG_SPEAKER_SIZE; + break; - // extension register - case 0xa4 : - region_ptr = m_motion_plus_active ? (void*)&m_reg_motion_plus : (void*)&m_reg_ext; - region_size = WIIMOTE_REG_EXT_SIZE; - break; + // extension register + case 0xa4: + region_ptr = m_motion_plus_active ? (void*)&m_reg_motion_plus : (void*)&m_reg_ext; + region_size = WIIMOTE_REG_EXT_SIZE; + break; - // motion plus - case 0xa6 : - if (false == m_motion_plus_active) - { - region_ptr = &m_reg_motion_plus; - region_size = WIIMOTE_REG_EXT_SIZE; - } - break; + // motion plus + case 0xa6: + if (false == m_motion_plus_active) + { + region_ptr = &m_reg_motion_plus; + region_size = WIIMOTE_REG_EXT_SIZE; + } + break; - // ir - case 0xB0 : - region_ptr = &m_reg_ir; - region_size = WIIMOTE_REG_IR_SIZE; + // ir + case 0xB0: + region_ptr = &m_reg_ir; + region_size = WIIMOTE_REG_IR_SIZE; - //if (5 == m_reg_ir->mode) - // PanicAlert("IR Full Mode is Unsupported!"); - break; - } + // if (5 == m_reg_ir->mode) + // PanicAlert("IR Full Mode is Unsupported!"); + break; + } - if (region_ptr && (region_offset + wd->size <= region_size)) - { - memcpy((u8*)region_ptr + region_offset, wd->data, wd->size); - } - else - return; // TODO: generate a writedata error reply + if (region_ptr && (region_offset + wd->size <= region_size)) + { + memcpy((u8*)region_ptr + region_offset, wd->data, wd->size); + } + else + return; // TODO: generate a writedata error reply - /* TODO? - if (region_ptr == &m_reg_speaker) - { - ERROR_LOG(WIIMOTE, "Write to speaker register %x %s", address, - ArrayToString(wd->data, wd->size, 100, false).c_str()); - } - */ + /* TODO? + if (region_ptr == &m_reg_speaker) + { + ERROR_LOG(WIIMOTE, "Write to speaker register %x %s", address, + ArrayToString(wd->data, wd->size, 100, false).c_str()); + } + */ - if (&m_reg_ext == region_ptr) - { - // Run the key generation on all writes in the key area, it doesn't matter - // that we send it parts of a key, only the last full key will have an effect - if (address >= 0xa40040 && address <= 0xa4004c) - WiimoteGenerateKey(&m_ext_key, m_reg_ext.encryption_key); - } - else if (&m_reg_motion_plus == region_ptr) - { - // activate/deactivate motion plus - if (0x55 == m_reg_motion_plus.activated) - { - // maybe hacky - m_reg_motion_plus.activated = 0; - m_motion_plus_active ^= 1; + if (&m_reg_ext == region_ptr) + { + // Run the key generation on all writes in the key area, it doesn't matter + // that we send it parts of a key, only the last full key will have an effect + if (address >= 0xa40040 && address <= 0xa4004c) + WiimoteGenerateKey(&m_ext_key, m_reg_ext.encryption_key); + } + else if (&m_reg_motion_plus == region_ptr) + { + // activate/deactivate motion plus + if (0x55 == m_reg_motion_plus.activated) + { + // maybe hacky + m_reg_motion_plus.activated = 0; + m_motion_plus_active ^= 1; - RequestStatus(); - } - } - } - break; + RequestStatus(); + } + } + } + break; - default: - PanicAlert("WriteData: unimplemented parameters!"); - break; - } + default: + PanicAlert("WriteData: unimplemented parameters!"); + break; + } } /* Read data from Wiimote and Extensions registers. */ void Wiimote::ReadData(const wm_read_data* const rd) { - u32 address = Common::swap24(rd->address); - u16 size = Common::swap16(rd->size); + u32 address = Common::swap24(rd->address); + u16 size = Common::swap16(rd->size); - // ignore the 0x010000 bit - address &= 0xFEFFFF; + // ignore the 0x010000 bit + address &= 0xFEFFFF; - // hybrid Wiimote stuff - // relay the read data request to real-Wiimote - if (WIIMOTE_SRC_REAL & g_wiimote_sources[m_index] && ((0xA4 != (address >> 16)) || (m_extension->switch_extension <= 0))) - { - WiimoteReal::InterruptChannel(m_index, m_reporting_channel, ((u8*)rd) - 2, sizeof(wm_read_data) + 2); // hacky + // hybrid Wiimote stuff + // relay the read data request to real-Wiimote + if (WIIMOTE_SRC_REAL & g_wiimote_sources[m_index] && + ((0xA4 != (address >> 16)) || (m_extension->switch_extension <= 0))) + { + WiimoteReal::InterruptChannel(m_index, m_reporting_channel, ((u8*)rd) - 2, + sizeof(wm_read_data) + 2); // hacky - // don't want emu-Wiimote to send reply - return; - } + // don't want emu-Wiimote to send reply + return; + } - ReadRequest rr; - u8 *const block = new u8[size]; + ReadRequest rr; + u8* const block = new u8[size]; - switch (rd->space) - { - case WM_SPACE_EEPROM : - { - //PanicAlert("ReadData: reading from EEPROM: address: 0x%x size: 0x%x", address, size); - // Read from EEPROM - if (address + size >= WIIMOTE_EEPROM_FREE_SIZE) - { - if (address + size > WIIMOTE_EEPROM_SIZE) - { - PanicAlert("ReadData: address + size out of bounds"); - delete [] block; - return; - } - // generate a read error - size = 0; - } + switch (rd->space) + { + case WM_SPACE_EEPROM: + { + // PanicAlert("ReadData: reading from EEPROM: address: 0x%x size: 0x%x", address, size); + // Read from EEPROM + if (address + size >= WIIMOTE_EEPROM_FREE_SIZE) + { + if (address + size > WIIMOTE_EEPROM_SIZE) + { + PanicAlert("ReadData: address + size out of bounds"); + delete[] block; + return; + } + // generate a read error + size = 0; + } - // read mii data from file - // i need to improve this greatly - if (address >= 0x0FCA && address < 0x12C0) - { - // reading the whole mii block :/ - std::ifstream file; - file.open((File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/mii.bin").c_str(), std::ios::binary | std::ios::in); - file.read((char*)m_eeprom + 0x0FCA, 0x02f0); - file.close(); - } + // read mii data from file + // i need to improve this greatly + if (address >= 0x0FCA && address < 0x12C0) + { + // reading the whole mii block :/ + std::ifstream file; + file.open((File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/mii.bin").c_str(), + std::ios::binary | std::ios::in); + file.read((char*)m_eeprom + 0x0FCA, 0x02f0); + file.close(); + } - // read memory to be sent to Wii - memcpy(block, m_eeprom + address, size); - } - break; + // read memory to be sent to Wii + memcpy(block, m_eeprom + address, size); + } + break; - case WM_SPACE_REGS1 : - case WM_SPACE_REGS2 : - { - // Read from Control Register + case WM_SPACE_REGS1: + case WM_SPACE_REGS2: + { + // Read from Control Register - // ignore second byte for extension area - if (0xA4 == (address >> 16)) - address &= 0xFF00FF; + // ignore second byte for extension area + if (0xA4 == (address >> 16)) + address &= 0xFF00FF; - const u8 region_offset = (u8)address; - void *region_ptr = nullptr; - int region_size = 0; + const u8 region_offset = (u8)address; + void* region_ptr = nullptr; + int region_size = 0; - switch (address >> 16) - { - // speaker - case 0xa2: - region_ptr = &m_reg_speaker; - region_size = WIIMOTE_REG_SPEAKER_SIZE; - break; + switch (address >> 16) + { + // speaker + case 0xa2: + region_ptr = &m_reg_speaker; + region_size = WIIMOTE_REG_SPEAKER_SIZE; + break; - // extension - case 0xa4: - region_ptr = m_motion_plus_active ? (void*)&m_reg_motion_plus : (void*)&m_reg_ext; - region_size = WIIMOTE_REG_EXT_SIZE; - break; + // extension + case 0xa4: + region_ptr = m_motion_plus_active ? (void*)&m_reg_motion_plus : (void*)&m_reg_ext; + region_size = WIIMOTE_REG_EXT_SIZE; + break; - // motion plus - case 0xa6: - // reading from 0xa6 returns error when mplus is activated - if (false == m_motion_plus_active) - { - region_ptr = &m_reg_motion_plus; - region_size = WIIMOTE_REG_EXT_SIZE; - } - break; + // motion plus + case 0xa6: + // reading from 0xa6 returns error when mplus is activated + if (false == m_motion_plus_active) + { + region_ptr = &m_reg_motion_plus; + region_size = WIIMOTE_REG_EXT_SIZE; + } + break; - // ir - case 0xb0: - region_ptr = &m_reg_ir; - region_size = WIIMOTE_REG_IR_SIZE; - break; - } + // ir + case 0xb0: + region_ptr = &m_reg_ir; + region_size = WIIMOTE_REG_IR_SIZE; + break; + } - if (region_ptr && (region_offset + size <= region_size)) - { - memcpy(block, (u8*)region_ptr + region_offset, size); - } - else - size = 0; // generate read error + if (region_ptr && (region_offset + size <= region_size)) + { + memcpy(block, (u8*)region_ptr + region_offset, size); + } + else + size = 0; // generate read error - if (&m_reg_ext == region_ptr) - { - // Encrypt data read from extension register - // Check if encrypted reads is on - if (0xaa == m_reg_ext.encryption) - WiimoteEncrypt(&m_ext_key, block, address & 0xffff, (u8)size); - } - } - break; + if (&m_reg_ext == region_ptr) + { + // Encrypt data read from extension register + // Check if encrypted reads is on + if (0xaa == m_reg_ext.encryption) + WiimoteEncrypt(&m_ext_key, block, address & 0xffff, (u8)size); + } + } + break; - default : - PanicAlert("WmReadData: unimplemented parameters (size: %i, address: 0x%x)!", size, rd->space); - break; - } + default: + PanicAlert("WmReadData: unimplemented parameters (size: %i, address: 0x%x)!", size, rd->space); + break; + } - // want the requested address, not the above modified one - rr.address = Common::swap24(rd->address); - rr.size = size; - //rr.channel = _channelID; - rr.position = 0; - rr.data = block; + // want the requested address, not the above modified one + rr.address = Common::swap24(rd->address); + rr.size = size; + // rr.channel = _channelID; + rr.position = 0; + rr.data = block; - // send up to 16 bytes - SendReadDataReply(rr); + // send up to 16 bytes + SendReadDataReply(rr); - // if there is more data to be sent, add it to the queue - if (rr.size) - m_read_requests.push( rr ); - else - delete[] rr.data; + // if there is more data to be sent, add it to the queue + if (rr.size) + m_read_requests.push(rr); + else + delete[] rr.data; } // old comment @@ -524,139 +529,137 @@ void Wiimote::ReadData(const wm_read_data* const rd) */ void Wiimote::SendReadDataReply(ReadRequest& _request) { - u8 data[23]; - data[0] = 0xA1; - data[1] = WM_READ_DATA_REPLY; + u8 data[23]; + data[0] = 0xA1; + data[1] = WM_READ_DATA_REPLY; - wm_read_data_reply* const reply = (wm_read_data_reply*)(data + 2); - reply->buttons = m_status.buttons; - reply->address = Common::swap16(_request.address); + wm_read_data_reply* const reply = (wm_read_data_reply*)(data + 2); + reply->buttons = m_status.buttons; + reply->address = Common::swap16(_request.address); - // generate a read error - // Out of bounds. The real Wiimote generate an error for the first - // request to 0x1770 if we dont't replicate that the game will never - // read the calibration data at the beginning of Eeprom. I think this - // error is supposed to occur when we try to read above the freely - // usable space that ends at 0x16ff. - if (0 == _request.size) - { - reply->size = 0x0f; - reply->error = 0x08; + // generate a read error + // Out of bounds. The real Wiimote generate an error for the first + // request to 0x1770 if we dont't replicate that the game will never + // read the calibration data at the beginning of Eeprom. I think this + // error is supposed to occur when we try to read above the freely + // usable space that ends at 0x16ff. + if (0 == _request.size) + { + reply->size = 0x0f; + reply->error = 0x08; - memset(reply->data, 0, sizeof(reply->data)); - } - else - { - // Limit the amt to 16 bytes - // AyuanX: the MTU is 640B though... what a waste! - const int amt = std::min( (unsigned int)16, _request.size ); + memset(reply->data, 0, sizeof(reply->data)); + } + else + { + // Limit the amt to 16 bytes + // AyuanX: the MTU is 640B though... what a waste! + const int amt = std::min((unsigned int)16, _request.size); - // no error - reply->error = 0; + // no error + reply->error = 0; - // 0x1 means two bytes, 0xf means 16 bytes - reply->size = amt - 1; + // 0x1 means two bytes, 0xf means 16 bytes + reply->size = amt - 1; - // Clear the mem first - memset(reply->data, 0, sizeof(reply->data)); + // Clear the mem first + memset(reply->data, 0, sizeof(reply->data)); - // copy piece of mem - memcpy(reply->data, _request.data + _request.position, amt); + // copy piece of mem + memcpy(reply->data, _request.data + _request.position, amt); - // update request struct - _request.size -= amt; - _request.position += amt; - _request.address += amt; - } + // update request struct + _request.size -= amt; + _request.position += amt; + _request.address += amt; + } - // Send a piece - Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, data, sizeof(data)); + // Send a piece + Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, data, sizeof(data)); } void Wiimote::DoState(PointerWrap& p) { - p.Do(m_extension->active_extension); - p.Do(m_extension->switch_extension); + p.Do(m_extension->active_extension); + p.Do(m_extension->switch_extension); - p.Do(m_accel); - p.Do(m_index); - p.Do(ir_sin); - p.Do(ir_cos); - p.Do(m_rumble_on); - p.Do(m_speaker_mute); - p.Do(m_motion_plus_present); - p.Do(m_motion_plus_active); - p.Do(m_reporting_auto); - p.Do(m_reporting_mode); - p.Do(m_reporting_channel); - p.Do(m_shake_step); - p.Do(m_sensor_bar_on_top); - p.Do(m_status); - p.Do(m_adpcm_state); - p.Do(m_ext_key); - p.DoArray(m_eeprom); - p.Do(m_reg_motion_plus); - p.Do(m_reg_ir); - p.Do(m_reg_ext); - p.Do(m_reg_speaker); + p.Do(m_accel); + p.Do(m_index); + p.Do(ir_sin); + p.Do(ir_cos); + p.Do(m_rumble_on); + p.Do(m_speaker_mute); + p.Do(m_motion_plus_present); + p.Do(m_motion_plus_active); + p.Do(m_reporting_auto); + p.Do(m_reporting_mode); + p.Do(m_reporting_channel); + p.Do(m_shake_step); + p.Do(m_sensor_bar_on_top); + p.Do(m_status); + p.Do(m_adpcm_state); + p.Do(m_ext_key); + p.DoArray(m_eeprom); + p.Do(m_reg_motion_plus); + p.Do(m_reg_ir); + p.Do(m_reg_ext); + p.Do(m_reg_speaker); - //Do 'm_read_requests' queue - { - u32 size = 0; - if (p.mode == PointerWrap::MODE_READ) - { - //clear - while (!m_read_requests.empty()) - { - delete[] m_read_requests.front().data; - m_read_requests.pop(); - } + // Do 'm_read_requests' queue + { + u32 size = 0; + if (p.mode == PointerWrap::MODE_READ) + { + // clear + while (!m_read_requests.empty()) + { + delete[] m_read_requests.front().data; + m_read_requests.pop(); + } + p.Do(size); + while (size--) + { + ReadRequest tmp; + p.Do(tmp.address); + p.Do(tmp.position); + p.Do(tmp.size); + tmp.data = new u8[tmp.size]; + p.DoArray(tmp.data, tmp.size); + m_read_requests.push(tmp); + } + } + else + { + std::queue tmp_queue(m_read_requests); + size = (u32)(m_read_requests.size()); + p.Do(size); + while (!tmp_queue.empty()) + { + ReadRequest tmp = tmp_queue.front(); + p.Do(tmp.address); + p.Do(tmp.position); + p.Do(tmp.size); + p.DoArray(tmp.data, tmp.size); + tmp_queue.pop(); + } + } + } + p.DoMarker("Wiimote"); - p.Do(size); - while (size--) - { - ReadRequest tmp; - p.Do(tmp.address); - p.Do(tmp.position); - p.Do(tmp.size); - tmp.data = new u8[tmp.size]; - p.DoArray(tmp.data, tmp.size); - m_read_requests.push(tmp); - } - } - else - { - std::queue tmp_queue(m_read_requests); - size = (u32)(m_read_requests.size()); - p.Do(size); - while (!tmp_queue.empty()) - { - ReadRequest tmp = tmp_queue.front(); - p.Do(tmp.address); - p.Do(tmp.position); - p.Do(tmp.size); - p.DoArray(tmp.data, tmp.size); - tmp_queue.pop(); - } - } - } - p.DoMarker("Wiimote"); - - if (p.GetMode() == PointerWrap::MODE_READ) - RealState(); + if (p.GetMode() == PointerWrap::MODE_READ) + RealState(); } // load real Wiimote state void Wiimote::RealState() { - using namespace WiimoteReal; + using namespace WiimoteReal; - if (g_wiimotes[m_index]) - { - g_wiimotes[m_index]->SetChannel(m_reporting_channel); - g_wiimotes[m_index]->EnableDataReporting(m_reporting_mode); - } + if (g_wiimotes[m_index]) + { + g_wiimotes[m_index]->SetChannel(m_reporting_channel); + g_wiimotes[m_index]->EnableDataReporting(m_reporting_mode); + } } - } diff --git a/Source/Core/Core/HW/WiimoteEmu/Encryption.cpp b/Source/Core/Core/HW/WiimoteEmu/Encryption.cpp index 1ffde3d361..5e5825bc0d 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Encryption.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Encryption.cpp @@ -9,276 +9,285 @@ #include "Common/CommonTypes.h" #include "Core/HW/WiimoteEmu/Encryption.h" - static const u8 ans_tbl[7][6] = { - {0xA8,0x77,0xA6,0xE0,0xF7,0x43}, - {0x5A,0x35,0x85,0xE2,0x72,0x97}, - {0x8F,0xB7,0x1A,0x62,0x87,0x38}, - { 0xD,0x67,0xC7,0xBE,0x4F,0x3E}, - {0x20,0x76,0x37,0x8F,0x68,0xB7}, - {0xA9,0x26,0x3F,0x2B,0x10,0xE3}, - {0x30,0x7E,0x90, 0xE,0x85, 0xA}, + {0xA8, 0x77, 0xA6, 0xE0, 0xF7, 0x43}, {0x5A, 0x35, 0x85, 0xE2, 0x72, 0x97}, + {0x8F, 0xB7, 0x1A, 0x62, 0x87, 0x38}, {0xD, 0x67, 0xC7, 0xBE, 0x4F, 0x3E}, + {0x20, 0x76, 0x37, 0x8F, 0x68, 0xB7}, {0xA9, 0x26, 0x3F, 0x2B, 0x10, 0xE3}, + {0x30, 0x7E, 0x90, 0xE, 0x85, 0xA}, }; static const u8 tsbox[256] = { - 0x70,0x51, 3,0x86,0x40, 0xD,0x4F,0xEB,0x3E,0xCC,0xD1,0x87,0x35,0xBD,0xF5, 0xB, - 0x5E,0xD0,0xF8,0xF2,0xD5,0xE2,0x6C,0x31, 0xC,0xAD,0xFC,0x21,0xC3,0x78,0xC1, 6, - 0xC2,0x4C,0x55,0xE6,0x4A,0x34,0x48,0x11,0x1E,0xDA,0xE7,0x1A,0x84,0xA0,0x96,0xA7, - 0xE3,0x7F,0xAF,0x63,0x9C,0xFA,0x23,0x5B,0x79,0xC8,0x9E,0xBA,0xB2,0xC9,0x22,0x12, - 0x4B,0xB3,0xA1,0xB6,0x32,0x49,0xA2,0xE1,0x89,0x39,0x10,0x66,0xC5, 7,0x8F,0x54, - 0xEA,0x91,0xCA,0x3F,0xF9,0x19,0xF0,0xD7,0x46,0xBC,0x28,0x1B,0x61,0xE8,0x2F,0x6A, - 0xAE,0x9D,0xF6,0x4E, 9,0x14,0x77,0x4D,0xDB,0x1F,0x2E,0x7B,0x7C,0xF1,0x43,0xA3, - 0,0xB8,0x13,0x8C,0x85,0xB9,0x29,0x75,0x88,0xFD,0xD2,0x56,0x1C,0x50,0x97,0x41, - 0xE5,0x3B,0x60,0xB5,0xC0,0x64,0xEE,0x98,0xD6,0x2D,0x25,0xA4,0xAA,0xCD,0x7D,0xA8, - 0x83,0xC6,0xAB,0xBE,0x44,0x99,0x26,0x3C,0xCE,0x9F,0xBF,0xD3,0xCB,0x76,0x7A,0x7E, - 0x82, 1,0x8A,0x9A,0x80,0x1D, 0xE,0xB0,0x5C,0xD4,0x38,0x62,0xF4,0x30,0xE0,0x8E, - 0x53,0xB7, 2,0x57,0xAC,0xA6,0x52, 0xA,0x6D,0x92,0x65,0x17,0x24,0x33,0x45,0x72, - 0x74,0xB1,0xB4,0xF7,0x5D,0xED,0x2C,0xFF,0x47,0x37,0x5A,0x90,0xBB,0xDF,0x2A,0x16, - 0x59,0x95,0xD9,0xC4,0x27,0x67,0x73,0xC7,0x68,0xFE,0xA5,0xDD,0x6B,0x5F,0x93,0xD8, - 0xEC, 5,0x3A,0x8D,0x6E,0xFB,0x3D,0xA9,0x69,0x36,0xF3,0x94,0xDE,0xEF,0x15,0x6F, - 0x8B,0x9B, 8, 0xF,0xDC,0x81,0x18,0x20, 4,0xE4,0x71,0xCF,0xE9,0x2B,0x42,0x58, + 0x70, 0x51, 3, 0x86, 0x40, 0xD, 0x4F, 0xEB, 0x3E, 0xCC, 0xD1, 0x87, 0x35, 0xBD, 0xF5, 0xB, + 0x5E, 0xD0, 0xF8, 0xF2, 0xD5, 0xE2, 0x6C, 0x31, 0xC, 0xAD, 0xFC, 0x21, 0xC3, 0x78, 0xC1, 6, + 0xC2, 0x4C, 0x55, 0xE6, 0x4A, 0x34, 0x48, 0x11, 0x1E, 0xDA, 0xE7, 0x1A, 0x84, 0xA0, 0x96, 0xA7, + 0xE3, 0x7F, 0xAF, 0x63, 0x9C, 0xFA, 0x23, 0x5B, 0x79, 0xC8, 0x9E, 0xBA, 0xB2, 0xC9, 0x22, 0x12, + 0x4B, 0xB3, 0xA1, 0xB6, 0x32, 0x49, 0xA2, 0xE1, 0x89, 0x39, 0x10, 0x66, 0xC5, 7, 0x8F, 0x54, + 0xEA, 0x91, 0xCA, 0x3F, 0xF9, 0x19, 0xF0, 0xD7, 0x46, 0xBC, 0x28, 0x1B, 0x61, 0xE8, 0x2F, 0x6A, + 0xAE, 0x9D, 0xF6, 0x4E, 9, 0x14, 0x77, 0x4D, 0xDB, 0x1F, 0x2E, 0x7B, 0x7C, 0xF1, 0x43, 0xA3, + 0, 0xB8, 0x13, 0x8C, 0x85, 0xB9, 0x29, 0x75, 0x88, 0xFD, 0xD2, 0x56, 0x1C, 0x50, 0x97, 0x41, + 0xE5, 0x3B, 0x60, 0xB5, 0xC0, 0x64, 0xEE, 0x98, 0xD6, 0x2D, 0x25, 0xA4, 0xAA, 0xCD, 0x7D, 0xA8, + 0x83, 0xC6, 0xAB, 0xBE, 0x44, 0x99, 0x26, 0x3C, 0xCE, 0x9F, 0xBF, 0xD3, 0xCB, 0x76, 0x7A, 0x7E, + 0x82, 1, 0x8A, 0x9A, 0x80, 0x1D, 0xE, 0xB0, 0x5C, 0xD4, 0x38, 0x62, 0xF4, 0x30, 0xE0, 0x8E, + 0x53, 0xB7, 2, 0x57, 0xAC, 0xA6, 0x52, 0xA, 0x6D, 0x92, 0x65, 0x17, 0x24, 0x33, 0x45, 0x72, + 0x74, 0xB1, 0xB4, 0xF7, 0x5D, 0xED, 0x2C, 0xFF, 0x47, 0x37, 0x5A, 0x90, 0xBB, 0xDF, 0x2A, 0x16, + 0x59, 0x95, 0xD9, 0xC4, 0x27, 0x67, 0x73, 0xC7, 0x68, 0xFE, 0xA5, 0xDD, 0x6B, 0x5F, 0x93, 0xD8, + 0xEC, 5, 0x3A, 0x8D, 0x6E, 0xFB, 0x3D, 0xA9, 0x69, 0x36, 0xF3, 0x94, 0xDE, 0xEF, 0x15, 0x6F, + 0x8B, 0x9B, 8, 0xF, 0xDC, 0x81, 0x18, 0x20, 4, 0xE4, 0x71, 0xCF, 0xE9, 0x2B, 0x42, 0x58, }; static const u8 sboxes[8][256] = { - { - 1,0xA0,0xA9,0x62,0xD6,0x3F,0x85,0xA7,0xB6,0xD4,0xFA,0x15,0x66,0x17, 9,0xBD, - 0x5D,0x14,0x34,0x26,0x59,0x72,0x91,0x54, 6,0x4F,0xF8,0xB0,0x5B,0x74,0x93,0x99, - 0x8C,0xF2,0x45,0xCD,0xEA,0x4E,0xAD,0x10,0x4A,0xE5,0xCA,0xEE,0xDF,0xC6,0x6F,0x9F, - 0x88,0x8E, 2,0xCC, 8,0xA8,0x77,0x94,0x6D,0x21,0xB1,0x28,0xE4,0x39,0x79,0x96, - 0x60,0x71,0x81,0x16,0x2E,0xE6,0x78,0xB9,0xC4,0x46,0x9A,0x42,0xAE,0xB7,0x7C,0x43, - 0xB3,0x22,0x1A,0x86,0xC2,0x32,0x3D,0x2D,0x9C,0xD2,0x29,0xE9,0x63,0x9B,0xD1,0x31, - 0x38,0x5E,0x1E,0x36,0x41,0xBB, 3,0x18,0x2B,0x3E,0xBF,0x68,0x61,0xFC,0x52,0xC0, - 0xDE,0xE0, 0xA,0x58,0x13,0x5A, 0,0xBE,0x1C,0x90, 0xE,0x53,0x12,0xFD,0xE2,0x6E, - 0xBA,0xCE,0x24,0x27,0x44,0x7F,0x87,0xA3,0xA1,0xD5,0x50,0x40,0xE3,0xF9,0x83,0xF7, - 0xC7,0xA2,0x35,0xC8,0xDB,0x19,0xAB,0x2F,0x11,0x25,0xED,0x33,0x9E,0x55,0xE1,0x48, - 0xAF,0x73,0x84,0xDA,0x2A,0xAA,0x51,0xEB,0x9D,0x95,0xB2,0xCB,0xE7,0x70,0x80,0xFE, - 0x4C,0x65, 4,0xEF,0xC5,0xF1,0xC3,0x3A,0xB4,0xF5,0x5F,0x23,0x89,0xDD,0x30,0xA5, - 0x8B,0xD3,0xF6,0xDC,0x4D,0x64,0xD7,0xF0,0x8F,0xEC,0x56,0x37,0x5C,0xA4, 0xD, 7, - 0x76,0x8A,0x2C, 0xB,0xB5,0xD8,0xC1,0x1F,0xE8,0x3B,0xF4,0x4B,0x1B,0x47,0x6C,0x49, - 0x67,0x7B,0x92,0xCF,0x75,0x7E,0x20,0xD9,0x7D,0x3C,0x97,0x7A,0xD0, 5,0x6B, 0xF, - 0x1D,0xFB,0x82,0x98,0x57,0x8D,0xF3,0x6A,0xBC,0xAC,0xC9,0xA6,0xFF,0xB8,0x69, 0xC, - }, - { - 0x4C,0x4D,0x72, 7,0x5A,0x49,0x33,0x8D,0xA2,0xAB,0x46,0x3D,0x63, 0xD,0xA0,0x97, - 0xFF,0xF0,0xF5,0xFA,0xC0,0xE9,0xDB,0x62,0xE4,0xE1,0x74,0x43,0xDC,0x86,0x18,0x29, - 0x37,0xF4, 6,0xE2,0xED,0x6F,0x90,0x48,0x1E,0x2D,0x1D,0xEA,0x73,0x94,0x54,0xDF, - 0x25,0xF6,0x47,0x27,0xD9,0x11,0x77,0xC9,0x84,0x1C,0x5B,0x5C,0x51,0x81,0xA6,0x22, - 0x3E,0x24,0x96,0xC8,0x8A,0xEC,0x82,0x7C, 9,0xB8,0x45,0x4A,0x57,0xBB,0x2F,0x50, - 0x75,0x8E,0x61,0x70,0x8C,0x6C,0xAF,0xD0,0xFD,0xB4,0x1B,0xAE,0xDE,0xFE,0x3B,0xB5, - 0x36,0xBD,0x55, 1, 0xE,0x9C,0x41,0x56,0x5F,0xB3,0x26, 3,0x83,0xBA,0x13,0x4B, - 0xCA,0xC5, 0xA,0xF8,0x60,0xA5,0xB9,0xC7,0xC3,0x98,0x32,0xFB,0x12,0xF9,0xA7,0x92, - 0xAA,0x68,0xF3,0x78,0x7E, 5,0x20,0x21, 2,0xE8,0xBF,0xF2,0xB0,0x59,0x8F,0xD2, - 0xCB,0x87,0x65,0x15,0xF1,0x1A,0xB2,0x30,0xAD,0xEE,0x58,0xA3,0x8B,0x66,0x1F,0x2C, - 0xD7,0x5D,0x19,0x85,0xA8,0xE6,0xD3,0x6B,0xA1, 0xC,0x91,0x93,0x6A,0x5E, 0xB,0x79, - 0xE3,0xDD, 0,0x4F,0x3C,0x89,0x6E,0x71,0x69,0xA9,0xAC,0x40,0xE5,0x99,0x28,0xC6, - 0x31,0x4E,0x7A,0xCD, 8,0x9E,0x7D,0xEF,0x17,0xFC,0x88,0xD8,0xA4,0x6D,0x44,0x95, - 0xD1,0xB7,0xD4,0x9B,0xBE,0x2A,0x34,0x64,0x2B,0xCF,0x2E,0xEB,0x38,0xCE,0x23,0xE0, - 0x3A,0x3F,0xF7,0x7B,0x9F,0x10,0x53,0xBC,0x52,0x67,0x16,0xE7,0x80,0x76, 4,0xC4, - 0xB6,0xC1,0xC2,0x7F,0x9A,0xDA,0xD5,0x39,0x42,0x14,0x9D,0xB1, 0xF,0x35,0xD6,0xCC, - }, - { - 0xB9,0xDA,0x38, 0xC,0xA2,0x9C, 9,0x1F, 6,0xB1,0xB6,0xFD,0x1A,0x69,0x23,0x30, - 0xC4,0xDE, 1,0xD1,0xF4,0x58,0x29,0x37,0x1C,0x7D,0xD5,0xBF,0xFF,0xBD,0xC8,0xC9, - 0xCF,0x65,0xBE,0x7B,0x78,0x97,0x98,0x67, 8,0xB3,0x26,0x57,0xF7,0xFA,0x40,0xAD, - 0x8E,0x75,0xA6,0x7C,0xDB,0x91,0x8B,0x51,0x99,0xD4,0x17,0x7A,0x90,0x8D,0xCE,0x63, - 0xCB,0x4E,0xA0,0xAB,0x18,0x3A,0x5B,0x50,0x7F,0x21,0x74,0xC1,0xBB,0xB8,0xB7,0xBA, - 0xB,0x35,0x95,0x31,0x59,0x9A,0x4D, 4, 7,0x1E,0x5A,0x76,0x13,0xF3,0x71,0x83, - 0xD0,0x86, 3,0xA8,0x39,0x42,0xAA,0x28,0xE6,0xE4,0xD8,0x5D,0xD3,0xD0,0x6E,0x6F, - 0x96,0xFB,0x5E,0xBC,0x56,0xC2,0x5F,0x85,0x9B,0xE7,0xAF,0xD2,0x3B,0x84,0x6A,0xA7, - 0x53,0xC5,0x44,0x49,0xA5,0xF9,0x36,0x72,0x3D,0x2C,0xD9,0x1B,0xA1,0xF5,0x4F,0x93, - 0x9D,0x68,0x47,0x41,0x16,0xCA,0x2A,0x4C,0xA3,0x87,0xD6,0xE5,0x19,0x2E,0x77,0x15, - 0x6D,0x70,0xC0,0xDF,0xB2, 0,0x46,0xED,0xC6,0x6C,0x43,0x60,0x92,0x2D,0xA9,0x22, - 0x45,0x8F,0x34,0x55,0xAE,0xA4, 0xA,0x66,0x32,0xE0,0xDC, 2,0xAC,0xE8,0x20,0x8C, - 0x89,0x62,0x4A,0xFE,0xEE,0xC3,0xE3,0x3C,0xF1,0x79, 5,0xE9,0xF6,0x27,0x33,0xCC, - 0xF2,0x9E,0x11,0x81,0x7E,0x80,0x10,0x8A,0x82,0x9F,0x48, 0xD,0xD7,0xB4,0xFC,0x2F, - 0xB5,0xC7,0xDD,0x88,0x14,0x6B,0x2B,0x54,0xEA,0x1D,0x94,0x5C,0xB0,0xEF,0x12,0x24, - 0xCD,0xEB,0xE1,0xE2,0x64,0x73,0x3F, 0xE,0x52,0x61,0x25,0x3E,0xF8, 0xF,0x4B,0xEC, - }, - { - 0xC0, 0,0x30,0xF6, 2,0x49,0x3D,0x10,0x6E,0x20,0xC9,0xA6,0x2F,0xFE,0x2C,0x2B, - 0x75,0x2E,0x45,0x26,0xAB,0x48,0xA9,0x80,0xFC, 4,0xCC,0xD3,0xB5,0xBA,0xA3,0x38, - 0x31,0x7D, 1,0xD9,0xA7,0x7B,0x96,0xB6,0x63,0x69,0x4E,0xF7,0xDE,0xE0,0x78,0xCA, - 0x50,0xAA,0x41,0x91,0x65,0x88,0xE4,0x21,0x85,0xDA,0x3A,0x27,0xBE,0x1C,0x3E,0x42, - 0x5E,0x17,0x52,0x7F,0x1F,0x89,0x24,0x6F,0x8F,0x5C,0x67,0x74, 0xE,0x12,0x87,0x8D, - 0xE9,0x34,0xED,0x73,0xC4,0xF8,0x61,0x5B, 5,0xDF,0x59,0x4C,0x97,0x79,0x83,0x18, - 0xA4,0x55,0x95,0xEB,0xBD,0x53,0xF5,0xF1,0x57,0x66,0x46,0x9F,0xB2,0x81, 9,0x51, - 0x86,0x22,0x16,0xDD,0x23,0x93,0x76,0x29,0xC2,0xD7,0x1D,0xD4,0xBF,0x36,0x3F,0xEA, - 0x4B,0x11,0x32,0xB9,0x62,0x54,0x60,0xD6,0x6D,0x43,0x9A, 0xD,0x92,0x9C,0xB0,0xEF, - 0x58,0x6C,0x9D,0x77,0x2D,0x70,0xFA,0xF3,0xB3, 0xB,0xE2,0x40,0x7E,0xF4,0x8A,0xE5, - 0x8C,0x3C,0x56,0x71,0xD1,0x64,0xE1,0x82, 0xA,0xCB,0x13,0x15,0x90,0xEC, 3,0x99, - 0xAF,0x14,0x5D, 0xF,0x33,0x4A,0x94,0xA5,0xA8,0x35,0x1B,0xE3,0x6A,0xC6,0x28,0xFF, - 0x4D,0xE7,0x25,0x84,0xAC, 8,0xAE,0xC5,0xA2,0x2A,0xB8,0x37, 0xC,0x7A,0xA0,0xC3, - 0xCE,0xAD, 6,0x1A,0x9E,0x8B,0xFB,0xD5,0xD0,0xC1,0x1E,0xD0,0xB4,0x9B,0xB1,0x44, - 0xF2,0x47,0xC7,0x68,0xCF,0x72,0xBB,0x4F,0x5A,0xF9,0xDC,0x6B,0xDB,0xD2,0xE8,0x7C, - 0xC8,0xEE,0x98,0xA1,0xE6,0xD8,0x39, 7,0x5F,0xFD,0x8E,0x19,0xB7,0x3B,0xBC,0xCD, - }, - { - 0x7C,0xE3,0x81,0x73,0xB2,0x11,0xBF,0x6F,0x20,0x98,0xFE,0x75,0x96,0xEF,0x6C,0xDA, - 0x50,0xE1, 9,0x72,0x54,0x45,0xBA,0x34,0x80,0x5B,0xED,0x3E,0x53,0x2C,0x87,0xA4, - 0x57,0xF3,0x33,0x3F,0x3C,0xB7,0x67,0xB4,0xA3,0x25,0x60,0x4F, 7,0x6B,0x1B,0x47, - 0x15, 0xF,0xE4, 0xA,0xEA,0xD1,0x32,0x78,0x36,0x49,0x8D,0x4B,0xD2,0xBC,0xA5,0xDC, - 0x1D, 0xD,0x4D,0xCD,0x9A,0x82,0x5F,0xFC,0x94,0x65,0xBE,0xE2,0xF4,0xC9,0x1E,0x44, - 0xCB,0x9E, 0xC,0x64,0x71,0x26,0x63,0xB3,0x14,0xE8,0x40,0x70,0x8A, 0xE,0x19,0x42, - 0x6D,0xAC,0x88,0x10,0x5C,0xDF,0x41,0xA9,0xAD,0xE5,0xFB,0x74,0xCC,0xD5, 6,0x8E, - 0x59,0x86,0xCE,0x1F,0x3D,0x76,0xE0,0x8F,0xB9,0x77,0x27,0x7B,0xA6,0xD8,0x29,0xD3, - 0xEC,0xB8,0x13,0xF7,0xFA,0xC3,0x51,0x6A,0xDE,0x4A,0x5A,0xEB,0xC2,0x8B,0x23,0x48, - 0x92,0xCF,0x62,0xA8,0x99,0xF8,0xD0,0x2E,0x85,0x61,0x43,0xC8,0xBD,0xF0, 5,0x93, - 0xCA,0x4E,0xF1,0x7D,0x30,0xFD,0xC4,0x69,0x66,0x2F, 8,0xB1,0x52,0xF9,0x21,0xE6, - 0x7A,0x2B,0xDD,0x39,0x84,0xFF,0xC0,0x91,0xD6,0x37,0xD4,0x7F,0x2D,0x9B,0x5D,0xA1, - 0x3B,0x6E,0xB5,0xC5,0x46, 4,0xF5,0x90,0xEE,0x7E,0x83,0x1C, 3,0x56,0xB6,0xAA, - 0,0x17, 1,0x35,0x55,0x79, 0xB,0x12,0xBB,0x1A,0x31,0xE7, 2,0x28,0x16,0xC1, - 0xF6,0xA2,0xDB,0x18,0x9C,0x89,0x68,0x38,0x97,0xAB,0xC7,0x2A,0xD7,0x3A,0xF2,0xC6, - 0x24,0x4C,0xB0,0x58,0xA0,0x22,0x5E,0x9D,0xD9,0xA7,0xE9,0xAE,0xAF,0x8C,0x95,0x9F, - }, - { - 0x28,0xB7,0x20,0xD7,0xB0,0x30,0xC3, 9,0x19,0xC0,0x67,0xD6, 0,0x3C,0x7E,0xE7, - 0xE9,0xF4, 8,0x5A,0xF8,0xB8,0x2E, 5,0xA6,0x25,0x9E,0x5C,0xD8,0x15, 0xD,0xE1, - 0xF6,0x11,0x54,0x6B,0xCD,0x21,0x46,0x66,0x5E,0x84,0xAD, 6,0x38,0x29,0x44,0xC5, - 0xA2,0xCE,0xF1,0xAA,0xC1,0x40,0x71,0x86,0xB5,0xEF,0xFC,0x36,0xA8,0xCB, 0xA,0x48, - 0x27,0x45,0x64,0xA3,0xAF,0x8C,0xB2,0xC6,0x9F, 7,0x89,0xDC,0x17,0xD3,0x49,0x79, - 0xFB,0xFE,0x1D,0xD0,0xB9,0x88,0x43,0x52,0xBC, 1,0x78,0x2B,0x7D,0x94,0xC7, 0xE, - 0xDE,0xA5,0xD5,0x9B,0xCC,0xF7,0x61,0x7A,0xC2,0x74,0x81,0x39, 3,0xAB,0x96,0xA0, - 0x37,0xBD,0x2D,0x72,0x75,0x3F,0xC9,0xD4,0x8E,0x6F,0xF9,0x8D,0xED,0x62,0xDB,0x1C, - 0xDF, 4,0xAC,0x1B,0x6C,0x14,0x4B,0x63,0xD0,0xBF,0xB4,0x82,0xEC,0x7B,0x1A,0x59, - 0x92,0xD2,0x10,0x60,0xB6,0x3D,0x5F,0xE6,0x80,0x6E,0x70,0xC4,0xF2,0x35,0xD9,0x7C, - 0xEE,0xE5,0x41,0xA4,0x5B,0x50,0xDD,0xBB,0x4C,0xF3,0x1F,0x9D,0x5D,0x57,0x55,0x51, - 0x97,0xE3,0x58,0x42,0x4D,0x9C,0x73,0xBA,0xC8,0x77,0x31,0x69,0x26,0xAE,0xEA,0x8A, - 0xDA,0x22,0xB3,0x87,0x56,0xFA,0x93, 0xB,0x34,0x16,0x33,0xE8,0xE4,0x53,0xBE,0xA9, - 0xB1,0x3A,0x3E,0xF5,0x90,0x6A,0xCF,0x3B,0x12,0xFD,0x8F,0x9A,0xA7,0x47,0x91,0x99, - 0xEB, 0xF,0x24,0xFF,0x23,0x18,0x85,0x4E,0x7F, 0xC,0xE0,0xA1,0xD2,0xD1,0x2C,0x2A, - 0x4A, 2,0x4F,0x1E,0x95,0x68,0x8B,0x98,0x83,0x6D,0x76,0xCA,0x65,0x32,0x13,0x2F, - }, - { - 0xC3,0x82,0x9A,0xA4,0xBA,0x81,0x60,0x37,0x34,0x35,0xFC,0x80,0xA8,0x51,0x65,0x67, - 0xED,0x30,0x5F,0x10,0xD3,0x4A,0x27,0x2F,0x13,0xB9,0x2A,0xD2,0xCC,0xE1,0xEF,0xAE, - 0xEB,0xBE,0xF4,0xBD,0xCF,0x43,0xB3,0xC5,0x88,0x84,0xB7,0xDD,0x39,0x40,0xCE,0x48, - 0x6D,0x9B,0x72,0x61,0x7E,0xE7,0xA1,0x4E,0x53,0x2E,0x77,0x3B,0xE2,0xC9,0x36,0x22, - 0x1B,0x6E,0x73,0xB1, 3,0xB2,0x4C,0x87,0xA9,0xD4,0x4D, 0xF,0xD8,0x15,0x6C,0xAA, - 0x18,0xF6,0x49,0x57,0x5D,0xFB,0x7A,0x14,0x94,0x63,0xA0,0x11,0xB0,0x9E,0xDE, 5, - 0x46,0xC8,0xEE,0x47,0xDB,0xDC,0x24,0x89,0x9C,0x91,0x97,0x29,0xE9,0x7B,0xC1, 7, - 0x1E,0xB8,0xFD,0xFE,0xAC,0xC6,0x62,0x98,0x4F,0xF1,0x79,0xE0,0xE8,0x6B,0x78,0x56, - 0xB6,0x8D, 4,0x50,0x86,0xCA,0x6F,0x20,0xE6,0xEA,0xE5,0x76,0x17,0x1C,0x74,0x7F, - 0xBC, 0xD,0x2C,0x85,0xF7,0x66,0x96,0xE4,0x8B,0x75,0x3F,0x4B,0xD9,0x38,0xAF,0x7C, - 0xDA, 0xB,0x83,0x2D,0x31,0x32,0xA2,0xF5,0x1D,0x59,0x41,0x45,0xBF,0x3C,0x1F,0xF8, - 0xF9,0x8A,0xD0,0x16,0x25,0x69,0x12,0x99,0x9D,0x21,0x95,0xAB, 1,0xA6,0xD7,0xB5, - 0xC0,0x7D,0xFF,0x58, 0xE,0x3A,0x92,0xD1,0x55,0xE3, 8,0x9F,0xD6,0x3E,0x52,0x8E, - 0xFA,0xA3,0xC7, 2,0xCD,0xDF,0x8F,0x64,0x19,0x8C,0xF3,0xA7, 0xC,0x5E, 0xA,0x6A, - 9,0xF0,0x93,0x5B,0x42,0xC2, 6,0x23,0xEC,0x71,0xAD,0xB4,0xCB,0xBB,0x70,0x28, - 0xD5,0x1A,0x5C,0x33,0x68,0x5A, 0,0x44,0x90,0xA5,0xC4,0x26,0x3D,0x2B,0xF2,0x54, - }, - { - 0x96,0xAD,0xDA,0x1F,0xED,0x33,0xE1,0x81,0x69, 8, 0xD, 0xA,0xDB,0x35,0x77,0x9A, - 0x64,0xD1,0xFC,0x78,0xAA,0x1B,0xD0,0x67,0xA0,0xDD,0xFA,0x6C,0x63,0x71, 5,0x84, - 0x17,0x6A,0x89,0x4F,0x66,0x7F,0xC6,0x50,0x55,0x92,0x6F,0xBD,0xE7,0xD2,0x40,0x72, - 0x8D,0xBB,0xEC, 6,0x42,0x8A,0xE4,0x88,0x9D,0x7E,0x7A,0x82,0x27,0x13,0x41,0x1A, - 0xAF,0xC8,0xA4,0x76,0xB4,0xC2,0xFE,0x6D,0x1C,0xD9,0x61,0x30,0xB3,0x7C,0xEA,0xF7, - 0x29, 0xF,0xF2,0x3B,0x51,0xC1,0xDE,0x5F,0xE5,0x2A,0x2F,0x99, 0xB,0x5D,0xA3,0x2B, - 0x4A,0xAB,0x95,0xA5,0xD3,0x58,0x56,0xEE,0x28,0x31, 0,0xCC,0x15,0x46,0xCA,0xE6, - 0x86,0x38,0x3C,0x65,0xF5,0xE3,0x9F,0xD6,0x5B, 9,0x49,0x83,0x70,0x2D,0x53,0xA9, - 0x7D,0xE2,0xC4,0xAC,0x8E,0x5E,0xB8,0x25,0xF4,0xB9,0x57,0xF3,0xF1,0x68,0x47,0xB2, - 0xA2,0x59,0x20,0xCE,0x34,0x79,0x5C,0x90, 0xE,0x1E,0xBE,0xD5,0x22,0x23,0xB1,0xC9, - 0x18,0x62,0x16,0x2E,0x91,0x3E, 7,0x8F,0xD8,0x3F,0x93,0x3D,0xD4,0x9B,0xDF,0x85, - 0x21,0xFB,0x11,0x74,0x97,0xC7,0xD7,0xDC,0x4C,0x19,0x45,0x98,0xE9,0x43, 2,0x4B, - 0xBC,0xC3, 4,0x9C,0x6B,0xF0,0x75,0x52,0xA7,0x26,0xF6,0xC5,0xBA,0xCF,0xB0,0xB7, - 0xAE,0x5A,0xA1,0xBF, 3,0x8B,0x80,0x12,0x6E, 0xC,0xEB,0xF9,0xC0,0x44,0x24,0xEF, - 0x10,0xF8,0xA8,0x8C,0xE8,0x7B,0xFF,0x9E,0x2C,0xCD,0x60,0x36,0x87,0xB5,0x94,0xA6, - 0x54,0x73,0x3A,0x14,0x4E, 1,0x1D,0xB6,0xFD,0x37,0x48,0x4D,0x39,0xCB,0xE0,0x32, - } -}; - + { + 1, 0xA0, 0xA9, 0x62, 0xD6, 0x3F, 0x85, 0xA7, 0xB6, 0xD4, 0xFA, 0x15, 0x66, 0x17, 9, + 0xBD, 0x5D, 0x14, 0x34, 0x26, 0x59, 0x72, 0x91, 0x54, 6, 0x4F, 0xF8, 0xB0, 0x5B, 0x74, + 0x93, 0x99, 0x8C, 0xF2, 0x45, 0xCD, 0xEA, 0x4E, 0xAD, 0x10, 0x4A, 0xE5, 0xCA, 0xEE, 0xDF, + 0xC6, 0x6F, 0x9F, 0x88, 0x8E, 2, 0xCC, 8, 0xA8, 0x77, 0x94, 0x6D, 0x21, 0xB1, 0x28, + 0xE4, 0x39, 0x79, 0x96, 0x60, 0x71, 0x81, 0x16, 0x2E, 0xE6, 0x78, 0xB9, 0xC4, 0x46, 0x9A, + 0x42, 0xAE, 0xB7, 0x7C, 0x43, 0xB3, 0x22, 0x1A, 0x86, 0xC2, 0x32, 0x3D, 0x2D, 0x9C, 0xD2, + 0x29, 0xE9, 0x63, 0x9B, 0xD1, 0x31, 0x38, 0x5E, 0x1E, 0x36, 0x41, 0xBB, 3, 0x18, 0x2B, + 0x3E, 0xBF, 0x68, 0x61, 0xFC, 0x52, 0xC0, 0xDE, 0xE0, 0xA, 0x58, 0x13, 0x5A, 0, 0xBE, + 0x1C, 0x90, 0xE, 0x53, 0x12, 0xFD, 0xE2, 0x6E, 0xBA, 0xCE, 0x24, 0x27, 0x44, 0x7F, 0x87, + 0xA3, 0xA1, 0xD5, 0x50, 0x40, 0xE3, 0xF9, 0x83, 0xF7, 0xC7, 0xA2, 0x35, 0xC8, 0xDB, 0x19, + 0xAB, 0x2F, 0x11, 0x25, 0xED, 0x33, 0x9E, 0x55, 0xE1, 0x48, 0xAF, 0x73, 0x84, 0xDA, 0x2A, + 0xAA, 0x51, 0xEB, 0x9D, 0x95, 0xB2, 0xCB, 0xE7, 0x70, 0x80, 0xFE, 0x4C, 0x65, 4, 0xEF, + 0xC5, 0xF1, 0xC3, 0x3A, 0xB4, 0xF5, 0x5F, 0x23, 0x89, 0xDD, 0x30, 0xA5, 0x8B, 0xD3, 0xF6, + 0xDC, 0x4D, 0x64, 0xD7, 0xF0, 0x8F, 0xEC, 0x56, 0x37, 0x5C, 0xA4, 0xD, 7, 0x76, 0x8A, + 0x2C, 0xB, 0xB5, 0xD8, 0xC1, 0x1F, 0xE8, 0x3B, 0xF4, 0x4B, 0x1B, 0x47, 0x6C, 0x49, 0x67, + 0x7B, 0x92, 0xCF, 0x75, 0x7E, 0x20, 0xD9, 0x7D, 0x3C, 0x97, 0x7A, 0xD0, 5, 0x6B, 0xF, + 0x1D, 0xFB, 0x82, 0x98, 0x57, 0x8D, 0xF3, 0x6A, 0xBC, 0xAC, 0xC9, 0xA6, 0xFF, 0xB8, 0x69, + 0xC, + }, + { + 0x4C, 0x4D, 0x72, 7, 0x5A, 0x49, 0x33, 0x8D, 0xA2, 0xAB, 0x46, 0x3D, 0x63, 0xD, 0xA0, + 0x97, 0xFF, 0xF0, 0xF5, 0xFA, 0xC0, 0xE9, 0xDB, 0x62, 0xE4, 0xE1, 0x74, 0x43, 0xDC, 0x86, + 0x18, 0x29, 0x37, 0xF4, 6, 0xE2, 0xED, 0x6F, 0x90, 0x48, 0x1E, 0x2D, 0x1D, 0xEA, 0x73, + 0x94, 0x54, 0xDF, 0x25, 0xF6, 0x47, 0x27, 0xD9, 0x11, 0x77, 0xC9, 0x84, 0x1C, 0x5B, 0x5C, + 0x51, 0x81, 0xA6, 0x22, 0x3E, 0x24, 0x96, 0xC8, 0x8A, 0xEC, 0x82, 0x7C, 9, 0xB8, 0x45, + 0x4A, 0x57, 0xBB, 0x2F, 0x50, 0x75, 0x8E, 0x61, 0x70, 0x8C, 0x6C, 0xAF, 0xD0, 0xFD, 0xB4, + 0x1B, 0xAE, 0xDE, 0xFE, 0x3B, 0xB5, 0x36, 0xBD, 0x55, 1, 0xE, 0x9C, 0x41, 0x56, 0x5F, + 0xB3, 0x26, 3, 0x83, 0xBA, 0x13, 0x4B, 0xCA, 0xC5, 0xA, 0xF8, 0x60, 0xA5, 0xB9, 0xC7, + 0xC3, 0x98, 0x32, 0xFB, 0x12, 0xF9, 0xA7, 0x92, 0xAA, 0x68, 0xF3, 0x78, 0x7E, 5, 0x20, + 0x21, 2, 0xE8, 0xBF, 0xF2, 0xB0, 0x59, 0x8F, 0xD2, 0xCB, 0x87, 0x65, 0x15, 0xF1, 0x1A, + 0xB2, 0x30, 0xAD, 0xEE, 0x58, 0xA3, 0x8B, 0x66, 0x1F, 0x2C, 0xD7, 0x5D, 0x19, 0x85, 0xA8, + 0xE6, 0xD3, 0x6B, 0xA1, 0xC, 0x91, 0x93, 0x6A, 0x5E, 0xB, 0x79, 0xE3, 0xDD, 0, 0x4F, + 0x3C, 0x89, 0x6E, 0x71, 0x69, 0xA9, 0xAC, 0x40, 0xE5, 0x99, 0x28, 0xC6, 0x31, 0x4E, 0x7A, + 0xCD, 8, 0x9E, 0x7D, 0xEF, 0x17, 0xFC, 0x88, 0xD8, 0xA4, 0x6D, 0x44, 0x95, 0xD1, 0xB7, + 0xD4, 0x9B, 0xBE, 0x2A, 0x34, 0x64, 0x2B, 0xCF, 0x2E, 0xEB, 0x38, 0xCE, 0x23, 0xE0, 0x3A, + 0x3F, 0xF7, 0x7B, 0x9F, 0x10, 0x53, 0xBC, 0x52, 0x67, 0x16, 0xE7, 0x80, 0x76, 4, 0xC4, + 0xB6, 0xC1, 0xC2, 0x7F, 0x9A, 0xDA, 0xD5, 0x39, 0x42, 0x14, 0x9D, 0xB1, 0xF, 0x35, 0xD6, + 0xCC, + }, + { + 0xB9, 0xDA, 0x38, 0xC, 0xA2, 0x9C, 9, 0x1F, 6, 0xB1, 0xB6, 0xFD, 0x1A, 0x69, 0x23, + 0x30, 0xC4, 0xDE, 1, 0xD1, 0xF4, 0x58, 0x29, 0x37, 0x1C, 0x7D, 0xD5, 0xBF, 0xFF, 0xBD, + 0xC8, 0xC9, 0xCF, 0x65, 0xBE, 0x7B, 0x78, 0x97, 0x98, 0x67, 8, 0xB3, 0x26, 0x57, 0xF7, + 0xFA, 0x40, 0xAD, 0x8E, 0x75, 0xA6, 0x7C, 0xDB, 0x91, 0x8B, 0x51, 0x99, 0xD4, 0x17, 0x7A, + 0x90, 0x8D, 0xCE, 0x63, 0xCB, 0x4E, 0xA0, 0xAB, 0x18, 0x3A, 0x5B, 0x50, 0x7F, 0x21, 0x74, + 0xC1, 0xBB, 0xB8, 0xB7, 0xBA, 0xB, 0x35, 0x95, 0x31, 0x59, 0x9A, 0x4D, 4, 7, 0x1E, + 0x5A, 0x76, 0x13, 0xF3, 0x71, 0x83, 0xD0, 0x86, 3, 0xA8, 0x39, 0x42, 0xAA, 0x28, 0xE6, + 0xE4, 0xD8, 0x5D, 0xD3, 0xD0, 0x6E, 0x6F, 0x96, 0xFB, 0x5E, 0xBC, 0x56, 0xC2, 0x5F, 0x85, + 0x9B, 0xE7, 0xAF, 0xD2, 0x3B, 0x84, 0x6A, 0xA7, 0x53, 0xC5, 0x44, 0x49, 0xA5, 0xF9, 0x36, + 0x72, 0x3D, 0x2C, 0xD9, 0x1B, 0xA1, 0xF5, 0x4F, 0x93, 0x9D, 0x68, 0x47, 0x41, 0x16, 0xCA, + 0x2A, 0x4C, 0xA3, 0x87, 0xD6, 0xE5, 0x19, 0x2E, 0x77, 0x15, 0x6D, 0x70, 0xC0, 0xDF, 0xB2, + 0, 0x46, 0xED, 0xC6, 0x6C, 0x43, 0x60, 0x92, 0x2D, 0xA9, 0x22, 0x45, 0x8F, 0x34, 0x55, + 0xAE, 0xA4, 0xA, 0x66, 0x32, 0xE0, 0xDC, 2, 0xAC, 0xE8, 0x20, 0x8C, 0x89, 0x62, 0x4A, + 0xFE, 0xEE, 0xC3, 0xE3, 0x3C, 0xF1, 0x79, 5, 0xE9, 0xF6, 0x27, 0x33, 0xCC, 0xF2, 0x9E, + 0x11, 0x81, 0x7E, 0x80, 0x10, 0x8A, 0x82, 0x9F, 0x48, 0xD, 0xD7, 0xB4, 0xFC, 0x2F, 0xB5, + 0xC7, 0xDD, 0x88, 0x14, 0x6B, 0x2B, 0x54, 0xEA, 0x1D, 0x94, 0x5C, 0xB0, 0xEF, 0x12, 0x24, + 0xCD, 0xEB, 0xE1, 0xE2, 0x64, 0x73, 0x3F, 0xE, 0x52, 0x61, 0x25, 0x3E, 0xF8, 0xF, 0x4B, + 0xEC, + }, + { + 0xC0, 0, 0x30, 0xF6, 2, 0x49, 0x3D, 0x10, 0x6E, 0x20, 0xC9, 0xA6, 0x2F, 0xFE, 0x2C, + 0x2B, 0x75, 0x2E, 0x45, 0x26, 0xAB, 0x48, 0xA9, 0x80, 0xFC, 4, 0xCC, 0xD3, 0xB5, 0xBA, + 0xA3, 0x38, 0x31, 0x7D, 1, 0xD9, 0xA7, 0x7B, 0x96, 0xB6, 0x63, 0x69, 0x4E, 0xF7, 0xDE, + 0xE0, 0x78, 0xCA, 0x50, 0xAA, 0x41, 0x91, 0x65, 0x88, 0xE4, 0x21, 0x85, 0xDA, 0x3A, 0x27, + 0xBE, 0x1C, 0x3E, 0x42, 0x5E, 0x17, 0x52, 0x7F, 0x1F, 0x89, 0x24, 0x6F, 0x8F, 0x5C, 0x67, + 0x74, 0xE, 0x12, 0x87, 0x8D, 0xE9, 0x34, 0xED, 0x73, 0xC4, 0xF8, 0x61, 0x5B, 5, 0xDF, + 0x59, 0x4C, 0x97, 0x79, 0x83, 0x18, 0xA4, 0x55, 0x95, 0xEB, 0xBD, 0x53, 0xF5, 0xF1, 0x57, + 0x66, 0x46, 0x9F, 0xB2, 0x81, 9, 0x51, 0x86, 0x22, 0x16, 0xDD, 0x23, 0x93, 0x76, 0x29, + 0xC2, 0xD7, 0x1D, 0xD4, 0xBF, 0x36, 0x3F, 0xEA, 0x4B, 0x11, 0x32, 0xB9, 0x62, 0x54, 0x60, + 0xD6, 0x6D, 0x43, 0x9A, 0xD, 0x92, 0x9C, 0xB0, 0xEF, 0x58, 0x6C, 0x9D, 0x77, 0x2D, 0x70, + 0xFA, 0xF3, 0xB3, 0xB, 0xE2, 0x40, 0x7E, 0xF4, 0x8A, 0xE5, 0x8C, 0x3C, 0x56, 0x71, 0xD1, + 0x64, 0xE1, 0x82, 0xA, 0xCB, 0x13, 0x15, 0x90, 0xEC, 3, 0x99, 0xAF, 0x14, 0x5D, 0xF, + 0x33, 0x4A, 0x94, 0xA5, 0xA8, 0x35, 0x1B, 0xE3, 0x6A, 0xC6, 0x28, 0xFF, 0x4D, 0xE7, 0x25, + 0x84, 0xAC, 8, 0xAE, 0xC5, 0xA2, 0x2A, 0xB8, 0x37, 0xC, 0x7A, 0xA0, 0xC3, 0xCE, 0xAD, + 6, 0x1A, 0x9E, 0x8B, 0xFB, 0xD5, 0xD0, 0xC1, 0x1E, 0xD0, 0xB4, 0x9B, 0xB1, 0x44, 0xF2, + 0x47, 0xC7, 0x68, 0xCF, 0x72, 0xBB, 0x4F, 0x5A, 0xF9, 0xDC, 0x6B, 0xDB, 0xD2, 0xE8, 0x7C, + 0xC8, 0xEE, 0x98, 0xA1, 0xE6, 0xD8, 0x39, 7, 0x5F, 0xFD, 0x8E, 0x19, 0xB7, 0x3B, 0xBC, + 0xCD, + }, + { + 0x7C, 0xE3, 0x81, 0x73, 0xB2, 0x11, 0xBF, 0x6F, 0x20, 0x98, 0xFE, 0x75, 0x96, 0xEF, 0x6C, + 0xDA, 0x50, 0xE1, 9, 0x72, 0x54, 0x45, 0xBA, 0x34, 0x80, 0x5B, 0xED, 0x3E, 0x53, 0x2C, + 0x87, 0xA4, 0x57, 0xF3, 0x33, 0x3F, 0x3C, 0xB7, 0x67, 0xB4, 0xA3, 0x25, 0x60, 0x4F, 7, + 0x6B, 0x1B, 0x47, 0x15, 0xF, 0xE4, 0xA, 0xEA, 0xD1, 0x32, 0x78, 0x36, 0x49, 0x8D, 0x4B, + 0xD2, 0xBC, 0xA5, 0xDC, 0x1D, 0xD, 0x4D, 0xCD, 0x9A, 0x82, 0x5F, 0xFC, 0x94, 0x65, 0xBE, + 0xE2, 0xF4, 0xC9, 0x1E, 0x44, 0xCB, 0x9E, 0xC, 0x64, 0x71, 0x26, 0x63, 0xB3, 0x14, 0xE8, + 0x40, 0x70, 0x8A, 0xE, 0x19, 0x42, 0x6D, 0xAC, 0x88, 0x10, 0x5C, 0xDF, 0x41, 0xA9, 0xAD, + 0xE5, 0xFB, 0x74, 0xCC, 0xD5, 6, 0x8E, 0x59, 0x86, 0xCE, 0x1F, 0x3D, 0x76, 0xE0, 0x8F, + 0xB9, 0x77, 0x27, 0x7B, 0xA6, 0xD8, 0x29, 0xD3, 0xEC, 0xB8, 0x13, 0xF7, 0xFA, 0xC3, 0x51, + 0x6A, 0xDE, 0x4A, 0x5A, 0xEB, 0xC2, 0x8B, 0x23, 0x48, 0x92, 0xCF, 0x62, 0xA8, 0x99, 0xF8, + 0xD0, 0x2E, 0x85, 0x61, 0x43, 0xC8, 0xBD, 0xF0, 5, 0x93, 0xCA, 0x4E, 0xF1, 0x7D, 0x30, + 0xFD, 0xC4, 0x69, 0x66, 0x2F, 8, 0xB1, 0x52, 0xF9, 0x21, 0xE6, 0x7A, 0x2B, 0xDD, 0x39, + 0x84, 0xFF, 0xC0, 0x91, 0xD6, 0x37, 0xD4, 0x7F, 0x2D, 0x9B, 0x5D, 0xA1, 0x3B, 0x6E, 0xB5, + 0xC5, 0x46, 4, 0xF5, 0x90, 0xEE, 0x7E, 0x83, 0x1C, 3, 0x56, 0xB6, 0xAA, 0, 0x17, + 1, 0x35, 0x55, 0x79, 0xB, 0x12, 0xBB, 0x1A, 0x31, 0xE7, 2, 0x28, 0x16, 0xC1, 0xF6, + 0xA2, 0xDB, 0x18, 0x9C, 0x89, 0x68, 0x38, 0x97, 0xAB, 0xC7, 0x2A, 0xD7, 0x3A, 0xF2, 0xC6, + 0x24, 0x4C, 0xB0, 0x58, 0xA0, 0x22, 0x5E, 0x9D, 0xD9, 0xA7, 0xE9, 0xAE, 0xAF, 0x8C, 0x95, + 0x9F, + }, + { + 0x28, 0xB7, 0x20, 0xD7, 0xB0, 0x30, 0xC3, 9, 0x19, 0xC0, 0x67, 0xD6, 0, 0x3C, 0x7E, + 0xE7, 0xE9, 0xF4, 8, 0x5A, 0xF8, 0xB8, 0x2E, 5, 0xA6, 0x25, 0x9E, 0x5C, 0xD8, 0x15, + 0xD, 0xE1, 0xF6, 0x11, 0x54, 0x6B, 0xCD, 0x21, 0x46, 0x66, 0x5E, 0x84, 0xAD, 6, 0x38, + 0x29, 0x44, 0xC5, 0xA2, 0xCE, 0xF1, 0xAA, 0xC1, 0x40, 0x71, 0x86, 0xB5, 0xEF, 0xFC, 0x36, + 0xA8, 0xCB, 0xA, 0x48, 0x27, 0x45, 0x64, 0xA3, 0xAF, 0x8C, 0xB2, 0xC6, 0x9F, 7, 0x89, + 0xDC, 0x17, 0xD3, 0x49, 0x79, 0xFB, 0xFE, 0x1D, 0xD0, 0xB9, 0x88, 0x43, 0x52, 0xBC, 1, + 0x78, 0x2B, 0x7D, 0x94, 0xC7, 0xE, 0xDE, 0xA5, 0xD5, 0x9B, 0xCC, 0xF7, 0x61, 0x7A, 0xC2, + 0x74, 0x81, 0x39, 3, 0xAB, 0x96, 0xA0, 0x37, 0xBD, 0x2D, 0x72, 0x75, 0x3F, 0xC9, 0xD4, + 0x8E, 0x6F, 0xF9, 0x8D, 0xED, 0x62, 0xDB, 0x1C, 0xDF, 4, 0xAC, 0x1B, 0x6C, 0x14, 0x4B, + 0x63, 0xD0, 0xBF, 0xB4, 0x82, 0xEC, 0x7B, 0x1A, 0x59, 0x92, 0xD2, 0x10, 0x60, 0xB6, 0x3D, + 0x5F, 0xE6, 0x80, 0x6E, 0x70, 0xC4, 0xF2, 0x35, 0xD9, 0x7C, 0xEE, 0xE5, 0x41, 0xA4, 0x5B, + 0x50, 0xDD, 0xBB, 0x4C, 0xF3, 0x1F, 0x9D, 0x5D, 0x57, 0x55, 0x51, 0x97, 0xE3, 0x58, 0x42, + 0x4D, 0x9C, 0x73, 0xBA, 0xC8, 0x77, 0x31, 0x69, 0x26, 0xAE, 0xEA, 0x8A, 0xDA, 0x22, 0xB3, + 0x87, 0x56, 0xFA, 0x93, 0xB, 0x34, 0x16, 0x33, 0xE8, 0xE4, 0x53, 0xBE, 0xA9, 0xB1, 0x3A, + 0x3E, 0xF5, 0x90, 0x6A, 0xCF, 0x3B, 0x12, 0xFD, 0x8F, 0x9A, 0xA7, 0x47, 0x91, 0x99, 0xEB, + 0xF, 0x24, 0xFF, 0x23, 0x18, 0x85, 0x4E, 0x7F, 0xC, 0xE0, 0xA1, 0xD2, 0xD1, 0x2C, 0x2A, + 0x4A, 2, 0x4F, 0x1E, 0x95, 0x68, 0x8B, 0x98, 0x83, 0x6D, 0x76, 0xCA, 0x65, 0x32, 0x13, + 0x2F, + }, + { + 0xC3, 0x82, 0x9A, 0xA4, 0xBA, 0x81, 0x60, 0x37, 0x34, 0x35, 0xFC, 0x80, 0xA8, 0x51, 0x65, + 0x67, 0xED, 0x30, 0x5F, 0x10, 0xD3, 0x4A, 0x27, 0x2F, 0x13, 0xB9, 0x2A, 0xD2, 0xCC, 0xE1, + 0xEF, 0xAE, 0xEB, 0xBE, 0xF4, 0xBD, 0xCF, 0x43, 0xB3, 0xC5, 0x88, 0x84, 0xB7, 0xDD, 0x39, + 0x40, 0xCE, 0x48, 0x6D, 0x9B, 0x72, 0x61, 0x7E, 0xE7, 0xA1, 0x4E, 0x53, 0x2E, 0x77, 0x3B, + 0xE2, 0xC9, 0x36, 0x22, 0x1B, 0x6E, 0x73, 0xB1, 3, 0xB2, 0x4C, 0x87, 0xA9, 0xD4, 0x4D, + 0xF, 0xD8, 0x15, 0x6C, 0xAA, 0x18, 0xF6, 0x49, 0x57, 0x5D, 0xFB, 0x7A, 0x14, 0x94, 0x63, + 0xA0, 0x11, 0xB0, 0x9E, 0xDE, 5, 0x46, 0xC8, 0xEE, 0x47, 0xDB, 0xDC, 0x24, 0x89, 0x9C, + 0x91, 0x97, 0x29, 0xE9, 0x7B, 0xC1, 7, 0x1E, 0xB8, 0xFD, 0xFE, 0xAC, 0xC6, 0x62, 0x98, + 0x4F, 0xF1, 0x79, 0xE0, 0xE8, 0x6B, 0x78, 0x56, 0xB6, 0x8D, 4, 0x50, 0x86, 0xCA, 0x6F, + 0x20, 0xE6, 0xEA, 0xE5, 0x76, 0x17, 0x1C, 0x74, 0x7F, 0xBC, 0xD, 0x2C, 0x85, 0xF7, 0x66, + 0x96, 0xE4, 0x8B, 0x75, 0x3F, 0x4B, 0xD9, 0x38, 0xAF, 0x7C, 0xDA, 0xB, 0x83, 0x2D, 0x31, + 0x32, 0xA2, 0xF5, 0x1D, 0x59, 0x41, 0x45, 0xBF, 0x3C, 0x1F, 0xF8, 0xF9, 0x8A, 0xD0, 0x16, + 0x25, 0x69, 0x12, 0x99, 0x9D, 0x21, 0x95, 0xAB, 1, 0xA6, 0xD7, 0xB5, 0xC0, 0x7D, 0xFF, + 0x58, 0xE, 0x3A, 0x92, 0xD1, 0x55, 0xE3, 8, 0x9F, 0xD6, 0x3E, 0x52, 0x8E, 0xFA, 0xA3, + 0xC7, 2, 0xCD, 0xDF, 0x8F, 0x64, 0x19, 0x8C, 0xF3, 0xA7, 0xC, 0x5E, 0xA, 0x6A, 9, + 0xF0, 0x93, 0x5B, 0x42, 0xC2, 6, 0x23, 0xEC, 0x71, 0xAD, 0xB4, 0xCB, 0xBB, 0x70, 0x28, + 0xD5, 0x1A, 0x5C, 0x33, 0x68, 0x5A, 0, 0x44, 0x90, 0xA5, 0xC4, 0x26, 0x3D, 0x2B, 0xF2, + 0x54, + }, + { + 0x96, 0xAD, 0xDA, 0x1F, 0xED, 0x33, 0xE1, 0x81, 0x69, 8, 0xD, 0xA, 0xDB, 0x35, 0x77, + 0x9A, 0x64, 0xD1, 0xFC, 0x78, 0xAA, 0x1B, 0xD0, 0x67, 0xA0, 0xDD, 0xFA, 0x6C, 0x63, 0x71, + 5, 0x84, 0x17, 0x6A, 0x89, 0x4F, 0x66, 0x7F, 0xC6, 0x50, 0x55, 0x92, 0x6F, 0xBD, 0xE7, + 0xD2, 0x40, 0x72, 0x8D, 0xBB, 0xEC, 6, 0x42, 0x8A, 0xE4, 0x88, 0x9D, 0x7E, 0x7A, 0x82, + 0x27, 0x13, 0x41, 0x1A, 0xAF, 0xC8, 0xA4, 0x76, 0xB4, 0xC2, 0xFE, 0x6D, 0x1C, 0xD9, 0x61, + 0x30, 0xB3, 0x7C, 0xEA, 0xF7, 0x29, 0xF, 0xF2, 0x3B, 0x51, 0xC1, 0xDE, 0x5F, 0xE5, 0x2A, + 0x2F, 0x99, 0xB, 0x5D, 0xA3, 0x2B, 0x4A, 0xAB, 0x95, 0xA5, 0xD3, 0x58, 0x56, 0xEE, 0x28, + 0x31, 0, 0xCC, 0x15, 0x46, 0xCA, 0xE6, 0x86, 0x38, 0x3C, 0x65, 0xF5, 0xE3, 0x9F, 0xD6, + 0x5B, 9, 0x49, 0x83, 0x70, 0x2D, 0x53, 0xA9, 0x7D, 0xE2, 0xC4, 0xAC, 0x8E, 0x5E, 0xB8, + 0x25, 0xF4, 0xB9, 0x57, 0xF3, 0xF1, 0x68, 0x47, 0xB2, 0xA2, 0x59, 0x20, 0xCE, 0x34, 0x79, + 0x5C, 0x90, 0xE, 0x1E, 0xBE, 0xD5, 0x22, 0x23, 0xB1, 0xC9, 0x18, 0x62, 0x16, 0x2E, 0x91, + 0x3E, 7, 0x8F, 0xD8, 0x3F, 0x93, 0x3D, 0xD4, 0x9B, 0xDF, 0x85, 0x21, 0xFB, 0x11, 0x74, + 0x97, 0xC7, 0xD7, 0xDC, 0x4C, 0x19, 0x45, 0x98, 0xE9, 0x43, 2, 0x4B, 0xBC, 0xC3, 4, + 0x9C, 0x6B, 0xF0, 0x75, 0x52, 0xA7, 0x26, 0xF6, 0xC5, 0xBA, 0xCF, 0xB0, 0xB7, 0xAE, 0x5A, + 0xA1, 0xBF, 3, 0x8B, 0x80, 0x12, 0x6E, 0xC, 0xEB, 0xF9, 0xC0, 0x44, 0x24, 0xEF, 0x10, + 0xF8, 0xA8, 0x8C, 0xE8, 0x7B, 0xFF, 0x9E, 0x2C, 0xCD, 0x60, 0x36, 0x87, 0xB5, 0x94, 0xA6, + 0x54, 0x73, 0x3A, 0x14, 0x4E, 1, 0x1D, 0xB6, 0xFD, 0x37, 0x48, 0x4D, 0x39, 0xCB, 0xE0, + 0x32, + }}; static inline u8 ROR8(const u8 a, const u8 b) { - return (a>>b) | ((a<<(8-b))&0xff); + return (a >> b) | ((a << (8 - b)) & 0xff); } - static void GenerateKey(const u8* const rand, const u8 idx, u8* const key) { - const u8* const ans = ans_tbl[idx]; - u8 t0[10]; + const u8* const ans = ans_tbl[idx]; + u8 t0[10]; - for (int i=0; i<10; ++i) - t0[i] = tsbox[rand[i]]; + for (int i = 0; i < 10; ++i) + t0[i] = tsbox[rand[i]]; - key[0] = ((ROR8((ans[0]^t0[5]),(t0[2]%8)) - t0[9]) ^ t0[4]); - key[1] = ((ROR8((ans[1]^t0[1]),(t0[0]%8)) - t0[5]) ^ t0[7]); - key[2] = ((ROR8((ans[2]^t0[6]),(t0[8]%8)) - t0[2]) ^ t0[0]); - key[3] = ((ROR8((ans[3]^t0[4]),(t0[7]%8)) - t0[3]) ^ t0[2]); - key[4] = ((ROR8((ans[4]^t0[1]),(t0[6]%8)) - t0[3]) ^ t0[4]); - key[5] = ((ROR8((ans[5]^t0[7]),(t0[8]%8)) - t0[5]) ^ t0[9]); + key[0] = ((ROR8((ans[0] ^ t0[5]), (t0[2] % 8)) - t0[9]) ^ t0[4]); + key[1] = ((ROR8((ans[1] ^ t0[1]), (t0[0] % 8)) - t0[5]) ^ t0[7]); + key[2] = ((ROR8((ans[2] ^ t0[6]), (t0[8] % 8)) - t0[2]) ^ t0[0]); + key[3] = ((ROR8((ans[3] ^ t0[4]), (t0[7] % 8)) - t0[3]) ^ t0[2]); + key[4] = ((ROR8((ans[4] ^ t0[1]), (t0[6] % 8)) - t0[3]) ^ t0[4]); + key[5] = ((ROR8((ans[5] ^ t0[7]), (t0[8] % 8)) - t0[5]) ^ t0[9]); } - -static void GenerateTables(const u8* const rand, const u8* const key, const u8 idx, u8* const ft, u8* const sb) +static void GenerateTables(const u8* const rand, const u8* const key, const u8 idx, u8* const ft, + u8* const sb) { - ft[0] = sboxes[idx][key[4]] ^ sboxes[(idx+1)%8][rand[3]]; - ft[1] = sboxes[idx][key[2]] ^ sboxes[(idx+1)%8][rand[5]]; - ft[2] = sboxes[idx][key[5]] ^ sboxes[(idx+1)%8][rand[7]]; - ft[3] = sboxes[idx][key[0]] ^ sboxes[(idx+1)%8][rand[2]]; - ft[4] = sboxes[idx][key[1]] ^ sboxes[(idx+1)%8][rand[4]]; - ft[5] = sboxes[idx][key[3]] ^ sboxes[(idx+1)%8][rand[9]]; - ft[6] = sboxes[idx][rand[0]] ^ sboxes[(idx+1)%8][rand[6]]; - ft[7] = sboxes[idx][rand[1]] ^ sboxes[(idx+1)%8][rand[8]]; + ft[0] = sboxes[idx][key[4]] ^ sboxes[(idx + 1) % 8][rand[3]]; + ft[1] = sboxes[idx][key[2]] ^ sboxes[(idx + 1) % 8][rand[5]]; + ft[2] = sboxes[idx][key[5]] ^ sboxes[(idx + 1) % 8][rand[7]]; + ft[3] = sboxes[idx][key[0]] ^ sboxes[(idx + 1) % 8][rand[2]]; + ft[4] = sboxes[idx][key[1]] ^ sboxes[(idx + 1) % 8][rand[4]]; + ft[5] = sboxes[idx][key[3]] ^ sboxes[(idx + 1) % 8][rand[9]]; + ft[6] = sboxes[idx][rand[0]] ^ sboxes[(idx + 1) % 8][rand[6]]; + ft[7] = sboxes[idx][rand[1]] ^ sboxes[(idx + 1) % 8][rand[8]]; - sb[0] = sboxes[idx][key[0]] ^ sboxes[(idx+1)%8][rand[1]]; - sb[1] = sboxes[idx][key[5]] ^ sboxes[(idx+1)%8][rand[4]]; - sb[2] = sboxes[idx][key[3]] ^ sboxes[(idx+1)%8][rand[0]]; - sb[3] = sboxes[idx][key[2]] ^ sboxes[(idx+1)%8][rand[9]]; - sb[4] = sboxes[idx][key[4]] ^ sboxes[(idx+1)%8][rand[7]]; - sb[5] = sboxes[idx][key[1]] ^ sboxes[(idx+1)%8][rand[8]]; - sb[6] = sboxes[idx][rand[3]] ^ sboxes[(idx+1)%8][rand[5]]; - sb[7] = sboxes[idx][rand[2]] ^ sboxes[(idx+1)%8][rand[6]]; + sb[0] = sboxes[idx][key[0]] ^ sboxes[(idx + 1) % 8][rand[1]]; + sb[1] = sboxes[idx][key[5]] ^ sboxes[(idx + 1) % 8][rand[4]]; + sb[2] = sboxes[idx][key[3]] ^ sboxes[(idx + 1) % 8][rand[0]]; + sb[3] = sboxes[idx][key[2]] ^ sboxes[(idx + 1) % 8][rand[9]]; + sb[4] = sboxes[idx][key[4]] ^ sboxes[(idx + 1) % 8][rand[7]]; + sb[5] = sboxes[idx][key[1]] ^ sboxes[(idx + 1) % 8][rand[8]]; + sb[6] = sboxes[idx][rand[3]] ^ sboxes[(idx + 1) % 8][rand[5]]; + sb[7] = sboxes[idx][rand[2]] ^ sboxes[(idx + 1) % 8][rand[6]]; } - - - /* Generate key from the 0x40-0x4c data in g_RegExt */ void WiimoteGenerateKey(wiimote_key* const key, const u8* const keydata) { - u8 rand[10]; - u8 skey[6]; - u8 testkey[6]; - int idx; + u8 rand[10]; + u8 skey[6]; + u8 testkey[6]; + int idx; - for (int i=0; i<10; ++i) - rand[9-i] = keydata[i]; - for (int i=0; i<6; ++i) - skey[5-i] = keydata[i+10]; + for (int i = 0; i < 10; ++i) + rand[9 - i] = keydata[i]; + for (int i = 0; i < 6; ++i) + skey[5 - i] = keydata[i + 10]; - //DEBUG_LOG(WIIMOTE, "rand: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", rand[0], rand[1], rand[2], rand[3], rand[4], rand[5], rand[6], rand[7], rand[8], rand[9]); - //DEBUG_LOG(WIIMOTE, "key: %02x %02x %02x %02x %02x %02x", skey[0], skey[1], skey[2], skey[3], skey[4], skey[5]); + // DEBUG_LOG(WIIMOTE, "rand: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", rand[0], rand[1], + // rand[2], rand[3], rand[4], rand[5], rand[6], rand[7], rand[8], rand[9]); + // DEBUG_LOG(WIIMOTE, "key: %02x %02x %02x %02x %02x %02x", skey[0], skey[1], skey[2], skey[3], + // skey[4], skey[5]); - for (idx = 0; idx < 7; ++idx) - { - GenerateKey(rand, idx, testkey); - if (0 == memcmp(testkey, skey, 6)) - break; - } - // default case is idx = 7 which is valid (homebrew uses it for the 0x17 case) - //DEBUG_LOG(WIIMOTE, "idx: %d", idx); + for (idx = 0; idx < 7; ++idx) + { + GenerateKey(rand, idx, testkey); + if (0 == memcmp(testkey, skey, 6)) + break; + } + // default case is idx = 7 which is valid (homebrew uses it for the 0x17 case) + // DEBUG_LOG(WIIMOTE, "idx: %d", idx); - GenerateTables(rand, skey, idx, key->ft, key->sb); + GenerateTables(rand, skey, idx, key->ft, key->sb); - //DEBUG_LOG(WIIMOTE, "ft: %02x %02x %02x %02x %02x %02x %02x %02x", key->ft[0], key->ft[1], key->ft[2], key->ft[3], key->ft[4], key->ft[5], key->ft[6], key->ft[7]); - //DEBUG_LOG(WIIMOTE, "sb: %02x %02x %02x %02x %02x %02x %02x %02x", key->sb[0], key->sb[1], key->sb[2], key->sb[3], key->sb[4], key->sb[5], key->sb[6], key->sb[7]); + // DEBUG_LOG(WIIMOTE, "ft: %02x %02x %02x %02x %02x %02x %02x %02x", key->ft[0], key->ft[1], + // key->ft[2], key->ft[3], key->ft[4], key->ft[5], key->ft[6], key->ft[7]); + // DEBUG_LOG(WIIMOTE, "sb: %02x %02x %02x %02x %02x %02x %02x %02x", key->sb[0], key->sb[1], + // key->sb[2], key->sb[3], key->sb[4], key->sb[5], key->sb[6], key->sb[7]); - // for homebrew, ft and sb are all 0x97 which is equivalent to 0x17 + // for homebrew, ft and sb are all 0x97 which is equivalent to 0x17 } // TODO: is there a reason these can only handle a length of 255? /* Encrypt data */ void WiimoteEncrypt(const wiimote_key* const key, u8* const data, int addr, const u8 len) { - for (int i = 0; i < len; ++i, ++addr) - data[i] = (data[i] - key->ft[addr % 8]) ^ key->sb[addr % 8]; + for (int i = 0; i < len; ++i, ++addr) + data[i] = (data[i] - key->ft[addr % 8]) ^ key->sb[addr % 8]; } - /* Decrypt data */ void WiimoteDecrypt(const wiimote_key* const key, u8* const data, int addr, const u8 len) { - for (int i = 0; i < len; ++i, ++addr) - data[i] = (data[i] ^ key->sb[addr % 8]) + key->ft[addr % 8]; + for (int i = 0; i < len; ++i, ++addr) + data[i] = (data[i] ^ key->sb[addr % 8]) + key->ft[addr % 8]; } diff --git a/Source/Core/Core/HW/WiimoteEmu/Encryption.h b/Source/Core/Core/HW/WiimoteEmu/Encryption.h index 62302f4e7c..5fcf6ff4f4 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Encryption.h +++ b/Source/Core/Core/HW/WiimoteEmu/Encryption.h @@ -11,11 +11,10 @@ // The key structure to use with WiimoteGenerateKey() struct wiimote_key { - u8 ft[8]; - u8 sb[8]; + u8 ft[8]; + u8 sb[8]; }; - void WiimoteEncrypt(const wiimote_key* const key, u8* const data, int addr, const u8 len); void WiimoteDecrypt(const wiimote_key* const key, u8* const data, int addr, const u8 len); diff --git a/Source/Core/Core/HW/WiimoteEmu/MatrixMath.h b/Source/Core/Core/HW/WiimoteEmu/MatrixMath.h index 3c3218401f..e4daaad923 100644 --- a/Source/Core/Core/HW/WiimoteEmu/MatrixMath.h +++ b/Source/Core/Core/HW/WiimoteEmu/MatrixMath.h @@ -7,85 +7,133 @@ #include #ifndef M_PI -#define M_PI 3.14159265358979323846 +#define M_PI 3.14159265358979323846 #endif typedef double Matrix[4][4]; struct Vertex { - double x, y, z; + double x, y, z; }; -inline void MatrixIdentity(Matrix & m) +inline void MatrixIdentity(Matrix& m) { - m[0][0]=1; m[0][1]=0; m[0][2]=0; m[0][3]=0; - m[1][0]=0; m[1][1]=1; m[1][2]=0; m[1][3]=0; - m[2][0]=0; m[2][1]=0; m[2][2]=1; m[2][3]=0; - m[3][0]=0; m[3][1]=0; m[3][2]=0; m[3][3]=1; + m[0][0] = 1; + m[0][1] = 0; + m[0][2] = 0; + m[0][3] = 0; + m[1][0] = 0; + m[1][1] = 1; + m[1][2] = 0; + m[1][3] = 0; + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = 1; + m[2][3] = 0; + m[3][0] = 0; + m[3][1] = 0; + m[3][2] = 0; + m[3][3] = 1; } -inline void MatrixFrustum(Matrix &m, double l, double r, double b, double t, double n, double f) +inline void MatrixFrustum(Matrix& m, double l, double r, double b, double t, double n, double f) { - m[0][0]=2*n/(r-l); m[0][1]=0; m[0][2]=0; m[0][3]=0; - m[1][0]=0; m[1][1]=2*n/(t-b); m[1][2]=0; m[1][3]=0; - m[2][0]=(r+l)/(r-l); m[2][1]=(t+b)/(t-b); m[2][2]=(f+n)/(f-n); m[2][3]=-1; - m[3][0]=0; m[3][1]=0; m[3][2]=2*f*n/(f-n); m[3][3]=0; + m[0][0] = 2 * n / (r - l); + m[0][1] = 0; + m[0][2] = 0; + m[0][3] = 0; + m[1][0] = 0; + m[1][1] = 2 * n / (t - b); + m[1][2] = 0; + m[1][3] = 0; + m[2][0] = (r + l) / (r - l); + m[2][1] = (t + b) / (t - b); + m[2][2] = (f + n) / (f - n); + m[2][3] = -1; + m[3][0] = 0; + m[3][1] = 0; + m[3][2] = 2 * f * n / (f - n); + m[3][3] = 0; } -inline void MatrixPerspective(Matrix & m, double fovy, double aspect, double nplane, double fplane) +inline void MatrixPerspective(Matrix& m, double fovy, double aspect, double nplane, double fplane) { - double xmin, xmax, ymin, ymax; + double xmin, xmax, ymin, ymax; - ymax = nplane * tan(fovy * M_PI / 360.0); - ymin = -ymax; - xmin = ymin * aspect; - xmax = ymax * aspect; + ymax = nplane * tan(fovy * M_PI / 360.0); + ymin = -ymax; + xmin = ymin * aspect; + xmax = ymax * aspect; - MatrixFrustum(m,xmin,xmax,ymin,ymax,nplane,fplane); + MatrixFrustum(m, xmin, xmax, ymin, ymax, nplane, fplane); } -inline void MatrixRotationByZ(Matrix &m, double sin, double cos) +inline void MatrixRotationByZ(Matrix& m, double sin, double cos) { - m[0][0]=cos; m[0][1]=-sin; m[0][2]=0; m[0][3]=0; - m[1][0]=sin; m[1][1]=cos; m[1][2]=0; m[1][3]=0; - m[2][0]=0; m[2][1]=0; m[2][2]=1; m[2][3]=0; - m[3][0]=0; m[3][1]=0; m[3][2]=0; m[3][3]=1; + m[0][0] = cos; + m[0][1] = -sin; + m[0][2] = 0; + m[0][3] = 0; + m[1][0] = sin; + m[1][1] = cos; + m[1][2] = 0; + m[1][3] = 0; + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = 1; + m[2][3] = 0; + m[3][0] = 0; + m[3][1] = 0; + m[3][2] = 0; + m[3][3] = 1; } -inline void MatrixScale(Matrix &m, double xfact, double yfact, double zfact) +inline void MatrixScale(Matrix& m, double xfact, double yfact, double zfact) { - m[0][0]=xfact; m[0][1]=0; m[0][2]=0; m[0][3]=0; - m[1][0]=0; m[1][1]=yfact; m[1][2]=0; m[1][3]=0; - m[2][0]=0; m[2][1]=0; m[2][2]=zfact; m[2][3]=0; - m[3][0]=0; m[3][1]=0; m[3][2]=0; m[3][3]=1; + m[0][0] = xfact; + m[0][1] = 0; + m[0][2] = 0; + m[0][3] = 0; + m[1][0] = 0; + m[1][1] = yfact; + m[1][2] = 0; + m[1][3] = 0; + m[2][0] = 0; + m[2][1] = 0; + m[2][2] = zfact; + m[2][3] = 0; + m[3][0] = 0; + m[3][1] = 0; + m[3][2] = 0; + m[3][3] = 1; } -inline void MatrixMultiply(Matrix &r, const Matrix &a, const Matrix &b) +inline void MatrixMultiply(Matrix& r, const Matrix& a, const Matrix& b) { - for (int i=0; i<16; i++) - r[i>>2][i&3]=0.0f; + for (int i = 0; i < 16; i++) + r[i >> 2][i & 3] = 0.0f; - for (int i=0; i<4; i++) - for (int j=0; j<4; j++) - for (int k=0; k<4; k++) - r[i][j]+=a[i][k]*b[k][j]; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + for (int k = 0; k < 4; k++) + r[i][j] += a[i][k] * b[k][j]; } -inline void MatrixTransformVertex(Matrix const & m, Vertex & v) +inline void MatrixTransformVertex(Matrix const& m, Vertex& v) { - Vertex ov; - double w; - ov.x=v.x; - ov.y=v.y; - ov.z=v.z; - v.x = m[0][0] * ov.x + m[0][1] * ov.y + m[0][2] * ov.z + m[0][3]; - v.y = m[1][0] * ov.x + m[1][1] * ov.y + m[1][2] * ov.z + m[1][3]; - v.z = m[2][0] * ov.x + m[2][1] * ov.y + m[2][2] * ov.z + m[2][3]; - w = m[3][0] * ov.x + m[3][1] * ov.y + m[3][2] * ov.z + m[3][3]; - if (w!=0) - { - v.x/=w; - v.y/=w; - v.z/=w; - } + Vertex ov; + double w; + ov.x = v.x; + ov.y = v.y; + ov.z = v.z; + v.x = m[0][0] * ov.x + m[0][1] * ov.y + m[0][2] * ov.z + m[0][3]; + v.y = m[1][0] * ov.x + m[1][1] * ov.y + m[1][2] * ov.z + m[1][3]; + v.z = m[2][0] * ov.x + m[2][1] * ov.y + m[2][2] * ov.z + m[2][3]; + w = m[3][0] * ov.x + m[3][1] * ov.y + m[3][2] * ov.z + m[3][3]; + if (w != 0) + { + v.x /= w; + v.y /= w; + v.z /= w; + } } diff --git a/Source/Core/Core/HW/WiimoteEmu/Speaker.cpp b/Source/Core/Core/HW/WiimoteEmu/Speaker.cpp index 720d47af49..7c34cf80a3 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Speaker.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Speaker.cpp @@ -19,136 +19,140 @@ namespace WiimoteEmu { - // Yamaha ADPCM decoder code based on The ffmpeg Project (Copyright (s) 2001-2003) -static const s32 yamaha_difflookup[] = { - 1, 3, 5, 7, 9, 11, 13, 15, - -1, -3, -5, -7, -9, -11, -13, -15 -}; +static const s32 yamaha_difflookup[] = {1, 3, 5, 7, 9, 11, 13, 15, + -1, -3, -5, -7, -9, -11, -13, -15}; -static const s32 yamaha_indexscale[] = { - 230, 230, 230, 230, 307, 409, 512, 614, - 230, 230, 230, 230, 307, 409, 512, 614 -}; +static const s32 yamaha_indexscale[] = {230, 230, 230, 230, 307, 409, 512, 614, + 230, 230, 230, 230, 307, 409, 512, 614}; static s16 av_clip16(s32 a) { - if ((a+32768) & ~65535) return (a>>31) ^ 32767; - else return a; + if ((a + 32768) & ~65535) + return (a >> 31) ^ 32767; + else + return a; } static s32 av_clip(s32 a, s32 amin, s32 amax) { - if (a < amin) return amin; - else if (a > amax) return amax; - else return a; + if (a < amin) + return amin; + else if (a > amax) + return amax; + else + return a; } static s16 adpcm_yamaha_expand_nibble(ADPCMState& s, u8 nibble) { - s.predictor += (s.step * yamaha_difflookup[nibble]) / 8; - s.predictor = av_clip16(s.predictor); - s.step = (s.step * yamaha_indexscale[nibble]) >> 8; - s.step = av_clip(s.step, 127, 24576); - return s.predictor; + s.predictor += (s.step * yamaha_difflookup[nibble]) / 8; + s.predictor = av_clip16(s.predictor); + s.step = (s.step * yamaha_indexscale[nibble]) >> 8; + s.step = av_clip(s.step, 127, 24576); + return s.predictor; } #ifdef WIIMOTE_SPEAKER_DUMP std::ofstream ofile; WaveFileWriter wav; -void stopdamnwav(){wav.Stop();ofile.close();} +void stopdamnwav() +{ + wav.Stop(); + ofile.close(); +} #endif void Wiimote::SpeakerData(wm_speaker_data* sd) { - if (!SConfig::GetInstance().m_WiimoteEnableSpeaker) - return; - if (m_reg_speaker.volume == 0 || m_reg_speaker.sample_rate == 0 || sd->length == 0) - return; + if (!SConfig::GetInstance().m_WiimoteEnableSpeaker) + return; + if (m_reg_speaker.volume == 0 || m_reg_speaker.sample_rate == 0 || sd->length == 0) + return; - // TODO consider using static max size instead of new - std::unique_ptr samples(new s16[sd->length * 2]); + // TODO consider using static max size instead of new + std::unique_ptr samples(new s16[sd->length * 2]); - unsigned int sample_rate_dividend, sample_length; - u8 volume_divisor; + unsigned int sample_rate_dividend, sample_length; + u8 volume_divisor; - if (m_reg_speaker.format == 0x40) - { - // 8 bit PCM - for (int i = 0; i < sd->length; ++i) - { - samples[i] = ((s16)(s8)sd->data[i]) << 8; - } + if (m_reg_speaker.format == 0x40) + { + // 8 bit PCM + for (int i = 0; i < sd->length; ++i) + { + samples[i] = ((s16)(s8)sd->data[i]) << 8; + } - // Following details from http://wiibrew.org/wiki/Wiimote#Speaker - sample_rate_dividend = 12000000; - volume_divisor = 0xff; - sample_length = (unsigned int)sd->length; - } - else if (m_reg_speaker.format == 0x00) - { - // 4 bit Yamaha ADPCM (same as dreamcast) - for (int i = 0; i < sd->length; ++i) - { - samples[i * 2] = adpcm_yamaha_expand_nibble(m_adpcm_state, (sd->data[i] >> 4) & 0xf); - samples[i * 2 + 1] = adpcm_yamaha_expand_nibble(m_adpcm_state, sd->data[i] & 0xf); - } + // Following details from http://wiibrew.org/wiki/Wiimote#Speaker + sample_rate_dividend = 12000000; + volume_divisor = 0xff; + sample_length = (unsigned int)sd->length; + } + else if (m_reg_speaker.format == 0x00) + { + // 4 bit Yamaha ADPCM (same as dreamcast) + for (int i = 0; i < sd->length; ++i) + { + samples[i * 2] = adpcm_yamaha_expand_nibble(m_adpcm_state, (sd->data[i] >> 4) & 0xf); + samples[i * 2 + 1] = adpcm_yamaha_expand_nibble(m_adpcm_state, sd->data[i] & 0xf); + } - // Following details from http://wiibrew.org/wiki/Wiimote#Speaker - sample_rate_dividend = 6000000; + // Following details from http://wiibrew.org/wiki/Wiimote#Speaker + sample_rate_dividend = 6000000; - // 0 - 127 - // TODO: does it go beyond 127 for format == 0x40? - volume_divisor = 0x7F; - sample_length = (unsigned int)sd->length * 2; - } - else - { - ERROR_LOG(WII_IPC_WIIMOTE, "Unknown speaker format %x\n", m_reg_speaker.format); - return; - } + // 0 - 127 + // TODO: does it go beyond 127 for format == 0x40? + volume_divisor = 0x7F; + sample_length = (unsigned int)sd->length * 2; + } + else + { + ERROR_LOG(WII_IPC_WIIMOTE, "Unknown speaker format %x\n", m_reg_speaker.format); + return; + } - // Speaker Pan - unsigned int vol = (unsigned int)(m_options->settings[4]->GetValue() * 100); + // Speaker Pan + unsigned int vol = (unsigned int)(m_options->settings[4]->GetValue() * 100); - unsigned int sample_rate = sample_rate_dividend / m_reg_speaker.sample_rate; - float speaker_volume_ratio = (float)m_reg_speaker.volume / volume_divisor; - unsigned int left_volume = (unsigned int)((128 + vol) * speaker_volume_ratio); - unsigned int right_volume = (unsigned int)((128 - vol) * speaker_volume_ratio); + unsigned int sample_rate = sample_rate_dividend / m_reg_speaker.sample_rate; + float speaker_volume_ratio = (float)m_reg_speaker.volume / volume_divisor; + unsigned int left_volume = (unsigned int)((128 + vol) * speaker_volume_ratio); + unsigned int right_volume = (unsigned int)((128 - vol) * speaker_volume_ratio); - if (left_volume > 255) - left_volume = 255; - if (right_volume > 255) - right_volume = 255; + if (left_volume > 255) + left_volume = 255; + if (right_volume > 255) + right_volume = 255; - g_sound_stream->GetMixer()->SetWiimoteSpeakerVolume(left_volume, right_volume); + g_sound_stream->GetMixer()->SetWiimoteSpeakerVolume(left_volume, right_volume); - // ADPCM sample rate is thought to be x2.(3000 x2 = 6000). - g_sound_stream->GetMixer()->PushWiimoteSpeakerSamples(samples.get(), sample_length, sample_rate * 2); + // ADPCM sample rate is thought to be x2.(3000 x2 = 6000). + g_sound_stream->GetMixer()->PushWiimoteSpeakerSamples(samples.get(), sample_length, + sample_rate * 2); #ifdef WIIMOTE_SPEAKER_DUMP - static int num = 0; + static int num = 0; - if (num == 0) - { - File::Delete("rmtdump.wav"); - File::Delete("rmtdump.bin"); - atexit(stopdamnwav); - OpenFStream(ofile, "rmtdump.bin", ofile.binary | ofile.out); - wav.Start("rmtdump.wav", 6000/*Common::swap16(m_reg_speaker.sample_rate)*/); - } - wav.AddMonoSamples(samples.get(), sd->length*2); - if (ofile.good()) - { - for (int i = 0; i < sd->length; i++) - { - ofile << sd->data[i]; - } - } - num++; + if (num == 0) + { + File::Delete("rmtdump.wav"); + File::Delete("rmtdump.bin"); + atexit(stopdamnwav); + OpenFStream(ofile, "rmtdump.bin", ofile.binary | ofile.out); + wav.Start("rmtdump.wav", 6000 /*Common::swap16(m_reg_speaker.sample_rate)*/); + } + wav.AddMonoSamples(samples.get(), sd->length * 2); + if (ofile.good()) + { + for (int i = 0; i < sd->length; i++) + { + ofile << sd->data[i]; + } + } + num++; #endif } - } diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index 289b25a9a5..9adc810833 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -11,18 +11,18 @@ #include "Common/MsgHandler.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/Host.h" -#include "Core/Movie.h" -#include "Core/NetPlayClient.h" -#include "Core/HW/WiimoteEmu/MatrixMath.h" -#include "Core/HW/WiimoteEmu/WiimoteEmu.h" -#include "Core/HW/WiimoteEmu/WiimoteHid.h" #include "Core/HW/WiimoteEmu/Attachment/Classic.h" #include "Core/HW/WiimoteEmu/Attachment/Drums.h" #include "Core/HW/WiimoteEmu/Attachment/Guitar.h" #include "Core/HW/WiimoteEmu/Attachment/Nunchuk.h" #include "Core/HW/WiimoteEmu/Attachment/Turntable.h" +#include "Core/HW/WiimoteEmu/MatrixMath.h" +#include "Core/HW/WiimoteEmu/WiimoteEmu.h" +#include "Core/HW/WiimoteEmu/WiimoteHid.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" +#include "Core/Host.h" +#include "Core/Movie.h" +#include "Core/NetPlayClient.h" namespace { @@ -33,919 +33,910 @@ auto const PI = TAU / 2.0; namespace WiimoteEmu { - static const u8 eeprom_data_0[] = { - // IR, maybe more - // assuming last 2 bytes are checksum - 0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30, 0xA7, /*0x74, 0xD3,*/ 0x00, 0x00, // messing up the checksum on purpose - 0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30, 0xA7, /*0x74, 0xD3,*/ 0x00, 0x00, - // Accelerometer - // Important: checksum is required for tilt games - ACCEL_ZERO_G, ACCEL_ZERO_G, ACCEL_ZERO_G, 0, ACCEL_ONE_G, ACCEL_ONE_G, ACCEL_ONE_G, 0, 0, 0xA3, - ACCEL_ZERO_G, ACCEL_ZERO_G, ACCEL_ZERO_G, 0, ACCEL_ONE_G, ACCEL_ONE_G, ACCEL_ONE_G, 0, 0, 0xA3, + // IR, maybe more + // assuming last 2 bytes are checksum + 0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30, 0xA7, /*0x74, 0xD3,*/ 0x00, + 0x00, // messing up the checksum on purpose + 0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30, 0xA7, /*0x74, 0xD3,*/ 0x00, 0x00, + // Accelerometer + // Important: checksum is required for tilt games + ACCEL_ZERO_G, ACCEL_ZERO_G, ACCEL_ZERO_G, 0, ACCEL_ONE_G, ACCEL_ONE_G, ACCEL_ONE_G, 0, 0, 0xA3, + ACCEL_ZERO_G, ACCEL_ZERO_G, ACCEL_ZERO_G, 0, ACCEL_ONE_G, ACCEL_ONE_G, ACCEL_ONE_G, 0, 0, 0xA3, }; -static const u8 motion_plus_id[] = { 0x00, 0x00, 0xA6, 0x20, 0x00, 0x05 }; +static const u8 motion_plus_id[] = {0x00, 0x00, 0xA6, 0x20, 0x00, 0x05}; -static const u8 eeprom_data_16D0[] = { - 0x00, 0x00, 0x00, 0xFF, 0x11, 0xEE, 0x00, 0x00, - 0x33, 0xCC, 0x44, 0xBB, 0x00, 0x00, 0x66, 0x99, - 0x77, 0x88, 0x00, 0x00, 0x2B, 0x01, 0xE8, 0x13 +static const u8 eeprom_data_16D0[] = {0x00, 0x00, 0x00, 0xFF, 0x11, 0xEE, 0x00, 0x00, + 0x33, 0xCC, 0x44, 0xBB, 0x00, 0x00, 0x66, 0x99, + 0x77, 0x88, 0x00, 0x00, 0x2B, 0x01, 0xE8, 0x13}; + +static const ReportFeatures reporting_mode_features[] = { + // 0x30: Core Buttons + {2, 0, 0, 0, 4}, + // 0x31: Core Buttons and Accelerometer + {2, 4, 0, 0, 7}, + // 0x32: Core Buttons with 8 Extension bytes + {2, 0, 0, 4, 12}, + // 0x33: Core Buttons and Accelerometer with 12 IR bytes + {2, 4, 7, 0, 19}, + // 0x34: Core Buttons with 19 Extension bytes + {2, 0, 0, 4, 23}, + // 0x35: Core Buttons and Accelerometer with 16 Extension Bytes + {2, 4, 0, 7, 23}, + // 0x36: Core Buttons with 10 IR bytes and 9 Extension Bytes + {2, 0, 4, 14, 23}, + // 0x37: Core Buttons and Accelerometer with 10 IR bytes and 6 Extension Bytes + {2, 4, 7, 17, 23}, + + // UNSUPPORTED: + // 0x3d: 21 Extension Bytes + {0, 0, 0, 2, 23}, + // 0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes + {0, 0, 0, 0, 23}, }; -static const ReportFeatures reporting_mode_features[] = +void EmulateShake(AccelData* const accel, ControllerEmu::Buttons* const buttons_group, + u8* const shake_step) { - //0x30: Core Buttons - { 2, 0, 0, 0, 4 }, - //0x31: Core Buttons and Accelerometer - { 2, 4, 0, 0, 7 }, - //0x32: Core Buttons with 8 Extension bytes - { 2, 0, 0, 4, 12 }, - //0x33: Core Buttons and Accelerometer with 12 IR bytes - { 2, 4, 7, 0, 19 }, - //0x34: Core Buttons with 19 Extension bytes - { 2, 0, 0, 4, 23 }, - //0x35: Core Buttons and Accelerometer with 16 Extension Bytes - { 2, 4, 0, 7, 23 }, - //0x36: Core Buttons with 10 IR bytes and 9 Extension Bytes - { 2, 0, 4, 14, 23 }, - //0x37: Core Buttons and Accelerometer with 10 IR bytes and 6 Extension Bytes - { 2, 4, 7, 17, 23 }, + // frame count of one up/down shake + // < 9 no shake detection in "Wario Land: Shake It" + auto const shake_step_max = 15; - // UNSUPPORTED: - //0x3d: 21 Extension Bytes - { 0, 0, 0, 2, 23 }, - //0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes - { 0, 0, 0, 0, 23 }, -}; + // peak G-force + auto const shake_intensity = 3.0; -void EmulateShake(AccelData* const accel - , ControllerEmu::Buttons* const buttons_group - , u8* const shake_step ) -{ - // frame count of one up/down shake - // < 9 no shake detection in "Wario Land: Shake It" - auto const shake_step_max = 15; + // shake is a bitfield of X,Y,Z shake button states + static const unsigned int btns[] = {0x01, 0x02, 0x04}; + unsigned int shake = 0; + buttons_group->GetState(&shake, btns); - // peak G-force - auto const shake_intensity = 3.0; - - // shake is a bitfield of X,Y,Z shake button states - static const unsigned int btns[] = { 0x01, 0x02, 0x04 }; - unsigned int shake = 0; - buttons_group->GetState(&shake, btns); - - for (int i = 0; i != 3; ++i) - { - if (shake & (1 << i)) - { - (&(accel->x))[i] = std::sin(TAU * shake_step[i] / shake_step_max) * shake_intensity; - shake_step[i] = (shake_step[i] + 1) % shake_step_max; - } - else - shake_step[i] = 0; - } + for (int i = 0; i != 3; ++i) + { + if (shake & (1 << i)) + { + (&(accel->x))[i] = std::sin(TAU * shake_step[i] / shake_step_max) * shake_intensity; + shake_step[i] = (shake_step[i] + 1) % shake_step_max; + } + else + shake_step[i] = 0; + } } -void EmulateTilt(AccelData* const accel - , ControllerEmu::Tilt* const tilt_group - , const bool sideways, const bool upright) +void EmulateTilt(AccelData* const accel, ControllerEmu::Tilt* const tilt_group, const bool sideways, + const bool upright) { - ControlState roll, pitch; - // 180 degrees - tilt_group->GetState(&roll, &pitch); + ControlState roll, pitch; + // 180 degrees + tilt_group->GetState(&roll, &pitch); - roll *= PI; - pitch *= PI; + roll *= PI; + pitch *= PI; - unsigned int ud = 0, lr = 0, fb = 0; + unsigned int ud = 0, lr = 0, fb = 0; - // some notes that no one will understand but me :p - // left, forward, up - // lr/ left == negative for all orientations - // ud/ up == negative for upright longways - // fb/ forward == positive for (sideways flat) + // some notes that no one will understand but me :p + // left, forward, up + // lr/ left == negative for all orientations + // ud/ up == negative for upright longways + // fb/ forward == positive for (sideways flat) - // determine which axis is which direction - ud = upright ? (sideways ? 0 : 1) : 2; - lr = sideways; - fb = upright ? 2 : (sideways ? 0 : 1); + // determine which axis is which direction + ud = upright ? (sideways ? 0 : 1) : 2; + lr = sideways; + fb = upright ? 2 : (sideways ? 0 : 1); - int sgn[3]={-1,1,1}; //sign fix + int sgn[3] = {-1, 1, 1}; // sign fix - if (sideways && !upright) - sgn[fb] *= -1; - if (!sideways && upright) - sgn[ud] *= -1; + if (sideways && !upright) + sgn[fb] *= -1; + if (!sideways && upright) + sgn[ud] *= -1; - (&accel->x)[ud] = (sin((PI / 2) - std::max(fabs(roll), fabs(pitch))))*sgn[ud]; - (&accel->x)[lr] = -sin(roll)*sgn[lr]; - (&accel->x)[fb] = sin(pitch)*sgn[fb]; + (&accel->x)[ud] = (sin((PI / 2) - std::max(fabs(roll), fabs(pitch)))) * sgn[ud]; + (&accel->x)[lr] = -sin(roll) * sgn[lr]; + (&accel->x)[fb] = sin(pitch) * sgn[fb]; } -#define SWING_INTENSITY 2.5//-uncalibrated(aprox) 0x40-calibrated +#define SWING_INTENSITY 2.5 //-uncalibrated(aprox) 0x40-calibrated -void EmulateSwing(AccelData* const accel - , ControllerEmu::Force* const swing_group - , const bool sideways, const bool upright) +void EmulateSwing(AccelData* const accel, ControllerEmu::Force* const swing_group, + const bool sideways, const bool upright) { - ControlState swing[3]; - swing_group->GetState(swing); + ControlState swing[3]; + swing_group->GetState(swing); - s8 g_dir[3] = {-1, -1, -1}; - u8 axis_map[3]; + s8 g_dir[3] = {-1, -1, -1}; + u8 axis_map[3]; - // determine which axis is which direction - axis_map[0] = upright ? (sideways ? 0 : 1) : 2; // up/down - axis_map[1] = sideways; // left|right - axis_map[2] = upright ? 2 : (sideways ? 0 : 1); // forward/backward + // determine which axis is which direction + axis_map[0] = upright ? (sideways ? 0 : 1) : 2; // up/down + axis_map[1] = sideways; // left|right + axis_map[2] = upright ? 2 : (sideways ? 0 : 1); // forward/backward - // some orientations have up as positive, some as negative - // same with forward - if (sideways && !upright) - g_dir[axis_map[2]] *= -1; - if (!sideways && upright) - g_dir[axis_map[0]] *= -1; + // some orientations have up as positive, some as negative + // same with forward + if (sideways && !upright) + g_dir[axis_map[2]] *= -1; + if (!sideways && upright) + g_dir[axis_map[0]] *= -1; - for (unsigned int i = 0; i < 3; ++i) - (&accel->x)[axis_map[i]] += swing[i] * g_dir[i] * SWING_INTENSITY; + for (unsigned int i = 0; i < 3; ++i) + (&accel->x)[axis_map[i]] += swing[i] * g_dir[i] * SWING_INTENSITY; } -static const u16 button_bitmasks[] = -{ - Wiimote::BUTTON_A, - Wiimote::BUTTON_B, - Wiimote::BUTTON_ONE, - Wiimote::BUTTON_TWO, - Wiimote::BUTTON_MINUS, - Wiimote::BUTTON_PLUS, - Wiimote::BUTTON_HOME -}; +static const u16 button_bitmasks[] = { + Wiimote::BUTTON_A, Wiimote::BUTTON_B, Wiimote::BUTTON_ONE, Wiimote::BUTTON_TWO, + Wiimote::BUTTON_MINUS, Wiimote::BUTTON_PLUS, Wiimote::BUTTON_HOME}; -static const u16 dpad_bitmasks[] = -{ - Wiimote::PAD_UP, Wiimote::PAD_DOWN, Wiimote::PAD_LEFT, Wiimote::PAD_RIGHT -}; -static const u16 dpad_sideways_bitmasks[] = -{ - Wiimote::PAD_RIGHT, Wiimote::PAD_LEFT, Wiimote::PAD_UP, Wiimote::PAD_DOWN -}; +static const u16 dpad_bitmasks[] = {Wiimote::PAD_UP, Wiimote::PAD_DOWN, Wiimote::PAD_LEFT, + Wiimote::PAD_RIGHT}; +static const u16 dpad_sideways_bitmasks[] = {Wiimote::PAD_RIGHT, Wiimote::PAD_LEFT, Wiimote::PAD_UP, + Wiimote::PAD_DOWN}; -static const char* const named_buttons[] = -{ - "A", "B", "1", "2", "-", "+", "Home", +static const char* const named_buttons[] = { + "A", "B", "1", "2", "-", "+", "Home", }; void Wiimote::Reset() { - m_reporting_mode = WM_REPORT_CORE; - // i think these two are good - m_reporting_channel = 0; - m_reporting_auto = false; + m_reporting_mode = WM_REPORT_CORE; + // i think these two are good + m_reporting_channel = 0; + m_reporting_auto = false; - m_rumble_on = false; - m_speaker_mute = false; - m_motion_plus_present = false; - m_motion_plus_active = false; + m_rumble_on = false; + m_speaker_mute = false; + m_motion_plus_present = false; + m_motion_plus_active = false; - // will make the first Update() call send a status request - // the first call to RequestStatus() will then set up the status struct extension bit - m_extension->active_extension = -1; + // will make the first Update() call send a status request + // the first call to RequestStatus() will then set up the status struct extension bit + m_extension->active_extension = -1; - // eeprom - memset(m_eeprom, 0, sizeof(m_eeprom)); - // calibration data - memcpy(m_eeprom, eeprom_data_0, sizeof(eeprom_data_0)); - // dunno what this is for, copied from old plugin - memcpy(m_eeprom + 0x16D0, eeprom_data_16D0, sizeof(eeprom_data_16D0)); + // eeprom + memset(m_eeprom, 0, sizeof(m_eeprom)); + // calibration data + memcpy(m_eeprom, eeprom_data_0, sizeof(eeprom_data_0)); + // dunno what this is for, copied from old plugin + memcpy(m_eeprom + 0x16D0, eeprom_data_16D0, sizeof(eeprom_data_16D0)); - // set up the register - memset(&m_reg_speaker, 0, sizeof(m_reg_speaker)); - memset(&m_reg_ir, 0, sizeof(m_reg_ir)); - memset(&m_reg_ext, 0, sizeof(m_reg_ext)); - memset(&m_reg_motion_plus, 0, sizeof(m_reg_motion_plus)); + // set up the register + memset(&m_reg_speaker, 0, sizeof(m_reg_speaker)); + memset(&m_reg_ir, 0, sizeof(m_reg_ir)); + memset(&m_reg_ext, 0, sizeof(m_reg_ext)); + memset(&m_reg_motion_plus, 0, sizeof(m_reg_motion_plus)); - memcpy(&m_reg_motion_plus.ext_identifier, motion_plus_id, sizeof(motion_plus_id)); + memcpy(&m_reg_motion_plus.ext_identifier, motion_plus_id, sizeof(motion_plus_id)); - // status - memset(&m_status, 0, sizeof(m_status)); - // Battery levels in voltage - // 0x00 - 0x32: level 1 - // 0x33 - 0x43: level 2 - // 0x33 - 0x54: level 3 - // 0x55 - 0xff: level 4 - m_status.battery = (u8)(m_options->settings[5]->GetValue() * 100); + // status + memset(&m_status, 0, sizeof(m_status)); + // Battery levels in voltage + // 0x00 - 0x32: level 1 + // 0x33 - 0x43: level 2 + // 0x33 - 0x54: level 3 + // 0x55 - 0xff: level 4 + m_status.battery = (u8)(m_options->settings[5]->GetValue() * 100); - memset(m_shake_step, 0, sizeof(m_shake_step)); + memset(m_shake_step, 0, sizeof(m_shake_step)); - // clear read request queue - while (!m_read_requests.empty()) - { - delete[] m_read_requests.front().data; - m_read_requests.pop(); - } + // clear read request queue + while (!m_read_requests.empty()) + { + delete[] m_read_requests.front().data; + m_read_requests.pop(); + } - // Yamaha ADPCM state initialize - m_adpcm_state.predictor = 0; - m_adpcm_state.step = 127; + // Yamaha ADPCM state initialize + m_adpcm_state.predictor = 0; + m_adpcm_state.step = 127; } Wiimote::Wiimote(const unsigned int index) - : m_index(index) - , ir_sin(0) - , ir_cos(1) - , m_last_connect_request_counter(0) + : m_index(index), ir_sin(0), ir_cos(1), m_last_connect_request_counter(0) { - // ---- set up all the controls ---- + // ---- set up all the controls ---- - // buttons - groups.emplace_back(m_buttons = new Buttons("Buttons")); - for (auto& named_button : named_buttons) - m_buttons->controls.emplace_back(new ControlGroup::Input(named_button)); + // buttons + groups.emplace_back(m_buttons = new Buttons("Buttons")); + for (auto& named_button : named_buttons) + m_buttons->controls.emplace_back(new ControlGroup::Input(named_button)); - // ir - groups.emplace_back(m_ir = new Cursor(_trans("IR"))); + // ir + groups.emplace_back(m_ir = new Cursor(_trans("IR"))); - // swing - groups.emplace_back(m_swing = new Force(_trans("Swing"))); + // swing + groups.emplace_back(m_swing = new Force(_trans("Swing"))); - // tilt - groups.emplace_back(m_tilt = new Tilt(_trans("Tilt"))); + // tilt + groups.emplace_back(m_tilt = new Tilt(_trans("Tilt"))); - // shake - groups.emplace_back(m_shake = new Buttons(_trans("Shake"))); - m_shake->controls.emplace_back(new ControlGroup::Input("X")); - m_shake->controls.emplace_back(new ControlGroup::Input("Y")); - m_shake->controls.emplace_back(new ControlGroup::Input("Z")); + // shake + groups.emplace_back(m_shake = new Buttons(_trans("Shake"))); + m_shake->controls.emplace_back(new ControlGroup::Input("X")); + m_shake->controls.emplace_back(new ControlGroup::Input("Y")); + m_shake->controls.emplace_back(new ControlGroup::Input("Z")); - // extension - groups.emplace_back(m_extension = new Extension(_trans("Extension"))); - m_extension->attachments.emplace_back(new WiimoteEmu::None(m_reg_ext)); - m_extension->attachments.emplace_back(new WiimoteEmu::Nunchuk(m_reg_ext)); - m_extension->attachments.emplace_back(new WiimoteEmu::Classic(m_reg_ext)); - m_extension->attachments.emplace_back(new WiimoteEmu::Guitar(m_reg_ext)); - m_extension->attachments.emplace_back(new WiimoteEmu::Drums(m_reg_ext)); - m_extension->attachments.emplace_back(new WiimoteEmu::Turntable(m_reg_ext)); + // extension + groups.emplace_back(m_extension = new Extension(_trans("Extension"))); + m_extension->attachments.emplace_back(new WiimoteEmu::None(m_reg_ext)); + m_extension->attachments.emplace_back(new WiimoteEmu::Nunchuk(m_reg_ext)); + m_extension->attachments.emplace_back(new WiimoteEmu::Classic(m_reg_ext)); + m_extension->attachments.emplace_back(new WiimoteEmu::Guitar(m_reg_ext)); + m_extension->attachments.emplace_back(new WiimoteEmu::Drums(m_reg_ext)); + m_extension->attachments.emplace_back(new WiimoteEmu::Turntable(m_reg_ext)); - m_extension->settings.emplace_back(new ControlGroup::Setting(_trans("Motion Plus"), 0, 0, 1)); + m_extension->settings.emplace_back(new ControlGroup::Setting(_trans("Motion Plus"), 0, 0, 1)); - // rumble - groups.emplace_back(m_rumble = new ControlGroup(_trans("Rumble"))); - m_rumble->controls.emplace_back(new ControlGroup::Output(_trans("Motor"))); + // rumble + groups.emplace_back(m_rumble = new ControlGroup(_trans("Rumble"))); + m_rumble->controls.emplace_back(new ControlGroup::Output(_trans("Motor"))); - // dpad - groups.emplace_back(m_dpad = new Buttons("D-Pad")); - for (auto& named_direction : named_directions) - m_dpad->controls.emplace_back(new ControlGroup::Input(named_direction)); + // dpad + groups.emplace_back(m_dpad = new Buttons("D-Pad")); + for (auto& named_direction : named_directions) + m_dpad->controls.emplace_back(new ControlGroup::Input(named_direction)); - // options - groups.emplace_back(m_options = new ControlGroup(_trans("Options"))); - m_options->settings.emplace_back(new ControlGroup::BackgroundInputSetting(_trans("Background Input"))); - m_options->settings.emplace_back(new ControlGroup::Setting(_trans("Sideways Wiimote"), false)); - m_options->settings.emplace_back(new ControlGroup::Setting(_trans("Upright Wiimote"), false)); - m_options->settings.emplace_back(new ControlGroup::IterateUI(_trans("Iterative Input"))); - m_options->settings.emplace_back(new ControlGroup::Setting(_trans("Speaker Pan"), 0, -127, 127)); - m_options->settings.emplace_back(new ControlGroup::Setting(_trans("Battery"), 95.0 / 100, 0, 255)); + // options + groups.emplace_back(m_options = new ControlGroup(_trans("Options"))); + m_options->settings.emplace_back( + new ControlGroup::BackgroundInputSetting(_trans("Background Input"))); + m_options->settings.emplace_back(new ControlGroup::Setting(_trans("Sideways Wiimote"), false)); + m_options->settings.emplace_back(new ControlGroup::Setting(_trans("Upright Wiimote"), false)); + m_options->settings.emplace_back(new ControlGroup::IterateUI(_trans("Iterative Input"))); + m_options->settings.emplace_back(new ControlGroup::Setting(_trans("Speaker Pan"), 0, -127, 127)); + m_options->settings.emplace_back( + new ControlGroup::Setting(_trans("Battery"), 95.0 / 100, 0, 255)); - // TODO: This value should probably be re-read if SYSCONF gets changed - m_sensor_bar_on_top = SConfig::GetInstance().m_SYSCONF->GetData("BT.BAR") != 0; + // TODO: This value should probably be re-read if SYSCONF gets changed + m_sensor_bar_on_top = SConfig::GetInstance().m_SYSCONF->GetData("BT.BAR") != 0; - // --- reset eeprom/register/values to default --- - Reset(); + // --- reset eeprom/register/values to default --- + Reset(); } std::string Wiimote::GetName() const { - return std::string("Wiimote") + char('1'+m_index); + return std::string("Wiimote") + char('1' + m_index); } bool Wiimote::Step() { - // TODO: change this a bit - m_motion_plus_present = m_extension->settings[0]->value != 0; + // TODO: change this a bit + m_motion_plus_present = m_extension->settings[0]->value != 0; - m_rumble->controls[0]->control_ref->State(m_rumble_on); + m_rumble->controls[0]->control_ref->State(m_rumble_on); - // when a movie is active, this button status update is disabled (moved), because movies only record data reports. - if (!Core::g_want_determinism) - { - UpdateButtonsStatus(); - } + // when a movie is active, this button status update is disabled (moved), because movies only + // record data reports. + if (!Core::g_want_determinism) + { + UpdateButtonsStatus(); + } - // check if there is a read data request - if (!m_read_requests.empty()) - { - ReadRequest& rr = m_read_requests.front(); - // send up to 16 bytes to the Wii - SendReadDataReply(rr); - //SendReadDataReply(rr.channel, rr); + // check if there is a read data request + if (!m_read_requests.empty()) + { + ReadRequest& rr = m_read_requests.front(); + // send up to 16 bytes to the Wii + SendReadDataReply(rr); + // SendReadDataReply(rr.channel, rr); - // if there is no more data, remove from queue - if (0 == rr.size) - { - delete[] rr.data; - m_read_requests.pop(); - } + // if there is no more data, remove from queue + if (0 == rr.size) + { + delete[] rr.data; + m_read_requests.pop(); + } - // don't send any other reports - return true; - } + // don't send any other reports + return true; + } - // check if a status report needs to be sent - // this happens on Wiimote sync and when extensions are switched - if (m_extension->active_extension != m_extension->switch_extension) - { - RequestStatus(); + // check if a status report needs to be sent + // this happens on Wiimote sync and when extensions are switched + if (m_extension->active_extension != m_extension->switch_extension) + { + RequestStatus(); - // WiiBrew: Following a connection or disconnection event on the Extension Port, - // data reporting is disabled and the Data Reporting Mode must be reset before new data can arrive. - // after a game receives an unrequested status report, - // it expects data reports to stop until it sets the reporting mode again - m_reporting_auto = false; + // WiiBrew: Following a connection or disconnection event on the Extension Port, + // data reporting is disabled and the Data Reporting Mode must be reset before new data can + // arrive. + // after a game receives an unrequested status report, + // it expects data reports to stop until it sets the reporting mode again + m_reporting_auto = false; - return true; - } + return true; + } - return false; + return false; } void Wiimote::UpdateButtonsStatus() { - // update buttons in status struct - m_status.buttons.hex = 0; - const bool is_sideways = m_options->settings[1]->value != 0; - m_buttons->GetState(&m_status.buttons.hex, button_bitmasks); - m_dpad->GetState(&m_status.buttons.hex, is_sideways ? dpad_sideways_bitmasks : dpad_bitmasks); + // update buttons in status struct + m_status.buttons.hex = 0; + const bool is_sideways = m_options->settings[1]->value != 0; + m_buttons->GetState(&m_status.buttons.hex, button_bitmasks); + m_dpad->GetState(&m_status.buttons.hex, is_sideways ? dpad_sideways_bitmasks : dpad_bitmasks); } void Wiimote::GetButtonData(u8* const data) { - // when a movie is active, the button update happens here instead of Wiimote::Step, to avoid potential desync issues. - if (Core::g_want_determinism) - { - UpdateButtonsStatus(); - } + // when a movie is active, the button update happens here instead of Wiimote::Step, to avoid + // potential desync issues. + if (Core::g_want_determinism) + { + UpdateButtonsStatus(); + } - ((wm_buttons*)data)->hex |= m_status.buttons.hex; + ((wm_buttons*)data)->hex |= m_status.buttons.hex; } void Wiimote::GetAccelData(u8* const data, const ReportFeatures& rptf) { - const bool is_sideways = m_options->settings[1]->value != 0; - const bool is_upright = m_options->settings[2]->value != 0; + const bool is_sideways = m_options->settings[1]->value != 0; + const bool is_upright = m_options->settings[2]->value != 0; - EmulateTilt(&m_accel, m_tilt, is_sideways, is_upright); - EmulateSwing(&m_accel, m_swing, is_sideways, is_upright); - EmulateShake(&m_accel, m_shake, m_shake_step); + EmulateTilt(&m_accel, m_tilt, is_sideways, is_upright); + EmulateSwing(&m_accel, m_swing, is_sideways, is_upright); + EmulateShake(&m_accel, m_shake, m_shake_step); - wm_accel& accel = *(wm_accel*)(data + rptf.accel); - wm_buttons& core = *(wm_buttons*)(data + rptf.core); + wm_accel& accel = *(wm_accel*)(data + rptf.accel); + wm_buttons& core = *(wm_buttons*)(data + rptf.core); - // We now use 2 bits more precision, so multiply by 4 before converting to int - s16 x = (s16)(4 * (m_accel.x * ACCEL_RANGE + ACCEL_ZERO_G)); - s16 y = (s16)(4 * (m_accel.y * ACCEL_RANGE + ACCEL_ZERO_G)); - s16 z = (s16)(4 * (m_accel.z * ACCEL_RANGE + ACCEL_ZERO_G)); + // We now use 2 bits more precision, so multiply by 4 before converting to int + s16 x = (s16)(4 * (m_accel.x * ACCEL_RANGE + ACCEL_ZERO_G)); + s16 y = (s16)(4 * (m_accel.y * ACCEL_RANGE + ACCEL_ZERO_G)); + s16 z = (s16)(4 * (m_accel.z * ACCEL_RANGE + ACCEL_ZERO_G)); - x = MathUtil::Clamp(x, 0, 1024); - y = MathUtil::Clamp(y, 0, 1024); - z = MathUtil::Clamp(z, 0, 1024); + x = MathUtil::Clamp(x, 0, 1024); + y = MathUtil::Clamp(y, 0, 1024); + z = MathUtil::Clamp(z, 0, 1024); - accel.x = (x >> 2) & 0xFF; - accel.y = (y >> 2) & 0xFF; - accel.z = (z >> 2) & 0xFF; + accel.x = (x >> 2) & 0xFF; + accel.y = (y >> 2) & 0xFF; + accel.z = (z >> 2) & 0xFF; - core.acc_x_lsb = x & 0x3; - core.acc_y_lsb = (y >> 1) & 0x1; - core.acc_z_lsb = (z >> 1) & 0x1; + core.acc_x_lsb = x & 0x3; + core.acc_y_lsb = (y >> 1) & 0x1; + core.acc_z_lsb = (z >> 1) & 0x1; } inline void LowPassFilter(double& var, double newval, double period) { - static const double CUTOFF_FREQUENCY = 5.0; + static const double CUTOFF_FREQUENCY = 5.0; - double RC = 1.0 / CUTOFF_FREQUENCY; - double alpha = period / (period + RC); - var = newval * alpha + var * (1.0 - alpha); + double RC = 1.0 / CUTOFF_FREQUENCY; + double alpha = period / (period + RC); + var = newval * alpha + var * (1.0 - alpha); } void Wiimote::GetIRData(u8* const data, bool use_accel) { - u16 x[4], y[4]; - memset(x, 0xFF, sizeof(x)); + u16 x[4], y[4]; + memset(x, 0xFF, sizeof(x)); - ControlState xx = 10000, yy = 0, zz = 0; - double nsin,ncos; + ControlState xx = 10000, yy = 0, zz = 0; + double nsin, ncos; - if (use_accel) - { - double ax,az,len; - ax = m_accel.x; - az = m_accel.z; - len = sqrt(ax*ax+az*az); - if (len) - { - ax/=len; - az/=len; //normalizing the vector - nsin=ax; - ncos=az; - } - else - { - nsin=0; - ncos=1; - } - // PanicAlert("%d %d %d\nx:%f\nz:%f\nsin:%f\ncos:%f",accel->x,accel->y,accel->z,ax,az,sin,cos); - // PanicAlert("%d %d %d\n%d %d %d\n%d %d %d",accel->x,accel->y,accel->z,calib->zero_g.x,calib->zero_g.y,calib->zero_g.z, calib->one_g.x,calib->one_g.y,calib->one_g.z); - } - else - { - nsin=0; //m_tilt stuff here (can't figure it out yet....) - ncos=1; - } + if (use_accel) + { + double ax, az, len; + ax = m_accel.x; + az = m_accel.z; + len = sqrt(ax * ax + az * az); + if (len) + { + ax /= len; + az /= len; // normalizing the vector + nsin = ax; + ncos = az; + } + else + { + nsin = 0; + ncos = 1; + } + // PanicAlert("%d %d %d\nx:%f\nz:%f\nsin:%f\ncos:%f",accel->x,accel->y,accel->z,ax,az,sin,cos); + // PanicAlert("%d %d %d\n%d %d %d\n%d %d + // %d",accel->x,accel->y,accel->z,calib->zero_g.x,calib->zero_g.y,calib->zero_g.z, + // calib->one_g.x,calib->one_g.y,calib->one_g.z); + } + else + { + nsin = 0; // m_tilt stuff here (can't figure it out yet....) + ncos = 1; + } - LowPassFilter(ir_sin,nsin,1.0/60); - LowPassFilter(ir_cos,ncos,1.0/60); + LowPassFilter(ir_sin, nsin, 1.0 / 60); + LowPassFilter(ir_cos, ncos, 1.0 / 60); - m_ir->GetState(&xx, &yy, &zz, true); + m_ir->GetState(&xx, &yy, &zz, true); - Vertex v[4]; + Vertex v[4]; - static const int camWidth=1024; - static const int camHeight=768; - static const double bndup=-0.315447; - static const double bnddown=0.85; - static const double bndleft=0.443364; - static const double bndright=-0.443364; - static const double dist1=100.0/camWidth; //this seems the optimal distance for zelda - static const double dist2=1.2*dist1; + static const int camWidth = 1024; + static const int camHeight = 768; + static const double bndup = -0.315447; + static const double bnddown = 0.85; + static const double bndleft = 0.443364; + static const double bndright = -0.443364; + static const double dist1 = 100.0 / camWidth; // this seems the optimal distance for zelda + static const double dist2 = 1.2 * dist1; - for (auto& vtx : v) - { - vtx.x = xx * (bndright - bndleft) / 2 + (bndleft + bndright) / 2; - if (m_sensor_bar_on_top) - vtx.y = yy * (bndup - bnddown) / 2 + (bndup + bnddown) / 2; - else - vtx.y = yy * (bndup - bnddown) / 2 - (bndup + bnddown) / 2; - vtx.z=0; - } + for (auto& vtx : v) + { + vtx.x = xx * (bndright - bndleft) / 2 + (bndleft + bndright) / 2; + if (m_sensor_bar_on_top) + vtx.y = yy * (bndup - bnddown) / 2 + (bndup + bnddown) / 2; + else + vtx.y = yy * (bndup - bnddown) / 2 - (bndup + bnddown) / 2; + vtx.z = 0; + } - v[0].x-=(zz*0.5+1)*dist1; - v[1].x+=(zz*0.5+1)*dist1; - v[2].x-=(zz*0.5+1)*dist2; - v[3].x+=(zz*0.5+1)*dist2; + v[0].x -= (zz * 0.5 + 1) * dist1; + v[1].x += (zz * 0.5 + 1) * dist1; + v[2].x -= (zz * 0.5 + 1) * dist2; + v[3].x += (zz * 0.5 + 1) * dist2; -#define printmatrix(m) PanicAlert("%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n",m[0][0],m[0][1],m[0][2],m[0][3],m[1][0],m[1][1],m[1][2],m[1][3],m[2][0],m[2][1],m[2][2],m[2][3],m[3][0],m[3][1],m[3][2],m[3][3]) - Matrix rot,tot; - static Matrix scale; - MatrixScale(scale,1,camWidth/camHeight,1); - //MatrixIdentity(scale); - MatrixRotationByZ(rot,ir_sin,ir_cos); - //MatrixIdentity(rot); - MatrixMultiply(tot,scale,rot); +#define printmatrix(m) \ + PanicAlert("%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n", m[0][0], m[0][1], m[0][2], \ + m[0][3], m[1][0], m[1][1], m[1][2], m[1][3], m[2][0], m[2][1], m[2][2], m[2][3], \ + m[3][0], m[3][1], m[3][2], m[3][3]) + Matrix rot, tot; + static Matrix scale; + MatrixScale(scale, 1, camWidth / camHeight, 1); + // MatrixIdentity(scale); + MatrixRotationByZ(rot, ir_sin, ir_cos); + // MatrixIdentity(rot); + MatrixMultiply(tot, scale, rot); - for (int i = 0; i < 4; i++) - { - MatrixTransformVertex(tot,v[i]); - if ((v[i].x<-1)||(v[i].x>1)||(v[i].y<-1)||(v[i].y>1)) - continue; - x[i] = (u16)lround((v[i].x+1)/2*(camWidth-1)); - y[i] = (u16)lround((v[i].y+1)/2*(camHeight-1)); - } - // PanicAlert("%f %f\n%f %f\n%f %f\n%f %f\n%d %d\n%d %d\n%d %d\n%d %d", - // v[0].x,v[0].y,v[1].x,v[1].y,v[2].x,v[2].y,v[3].x,v[3].y, - // x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[38]); + for (int i = 0; i < 4; i++) + { + MatrixTransformVertex(tot, v[i]); + if ((v[i].x < -1) || (v[i].x > 1) || (v[i].y < -1) || (v[i].y > 1)) + continue; + x[i] = (u16)lround((v[i].x + 1) / 2 * (camWidth - 1)); + y[i] = (u16)lround((v[i].y + 1) / 2 * (camHeight - 1)); + } + // PanicAlert("%f %f\n%f %f\n%f %f\n%f %f\n%d %d\n%d %d\n%d %d\n%d %d", + // v[0].x,v[0].y,v[1].x,v[1].y,v[2].x,v[2].y,v[3].x,v[3].y, + // x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[38]); - // Fill report with valid data when full handshake was done - if (m_reg_ir.data[0x30]) - // ir mode - switch (m_reg_ir.mode) - { - // basic - case 1 : - { - memset(data, 0xFF, 10); - wm_ir_basic* const irdata = (wm_ir_basic*)data; - for (unsigned int i=0; i<2; ++i) - { - if (x[i*2] < 1024 && y[i*2] < 768) - { - irdata[i].x1 = static_cast(x[i*2]); - irdata[i].x1hi = x[i*2] >> 8; + // Fill report with valid data when full handshake was done + if (m_reg_ir.data[0x30]) + // ir mode + switch (m_reg_ir.mode) + { + // basic + case 1: + { + memset(data, 0xFF, 10); + wm_ir_basic* const irdata = (wm_ir_basic*)data; + for (unsigned int i = 0; i < 2; ++i) + { + if (x[i * 2] < 1024 && y[i * 2] < 768) + { + irdata[i].x1 = static_cast(x[i * 2]); + irdata[i].x1hi = x[i * 2] >> 8; - irdata[i].y1 = static_cast(y[i*2]); - irdata[i].y1hi = y[i*2] >> 8; - } - if (x[i*2+1] < 1024 && y[i*2+1] < 768) - { - irdata[i].x2 = static_cast(x[i*2+1]); - irdata[i].x2hi = x[i*2+1] >> 8; + irdata[i].y1 = static_cast(y[i * 2]); + irdata[i].y1hi = y[i * 2] >> 8; + } + if (x[i * 2 + 1] < 1024 && y[i * 2 + 1] < 768) + { + irdata[i].x2 = static_cast(x[i * 2 + 1]); + irdata[i].x2hi = x[i * 2 + 1] >> 8; - irdata[i].y2 = static_cast(y[i*2+1]); - irdata[i].y2hi = y[i*2+1] >> 8; - } - } - } - break; - // extended - case 3 : - { - memset(data, 0xFF, 12); - wm_ir_extended* const irdata = (wm_ir_extended*)data; - for (unsigned int i = 0; i < 4; ++i) - if (x[i] < 1024 && y[i] < 768) - { - irdata[i].x = static_cast(x[i]); - irdata[i].xhi = x[i] >> 8; + irdata[i].y2 = static_cast(y[i * 2 + 1]); + irdata[i].y2hi = y[i * 2 + 1] >> 8; + } + } + } + break; + // extended + case 3: + { + memset(data, 0xFF, 12); + wm_ir_extended* const irdata = (wm_ir_extended*)data; + for (unsigned int i = 0; i < 4; ++i) + if (x[i] < 1024 && y[i] < 768) + { + irdata[i].x = static_cast(x[i]); + irdata[i].xhi = x[i] >> 8; - irdata[i].y = static_cast(y[i]); - irdata[i].yhi = y[i] >> 8; + irdata[i].y = static_cast(y[i]); + irdata[i].yhi = y[i] >> 8; - irdata[i].size = 10; - } - } - break; - // full - case 5 : - PanicAlert("Full IR report"); - // UNSUPPORTED - break; - } + irdata[i].size = 10; + } + } + break; + // full + case 5: + PanicAlert("Full IR report"); + // UNSUPPORTED + break; + } } void Wiimote::GetExtData(u8* const data) { - m_extension->GetState(data); + m_extension->GetState(data); - // i dont think anything accesses the extension data like this, but ill support it. Indeed, commercial games don't do this. - // i think it should be unencrpyted in the register, encrypted when read. - memcpy(m_reg_ext.controller_data, data, sizeof(wm_nc)); // TODO: Should it be nc specific? + // i dont think anything accesses the extension data like this, but ill support it. Indeed, + // commercial games don't do this. + // i think it should be unencrpyted in the register, encrypted when read. + memcpy(m_reg_ext.controller_data, data, sizeof(wm_nc)); // TODO: Should it be nc specific? - // motionplus pass-through modes - if (m_motion_plus_active) - { - switch (m_reg_motion_plus.ext_identifier[0x4]) - { - // nunchuk pass-through mode - // Bit 7 of byte 5 is moved to bit 6 of byte 5, overwriting it - // Bit 0 of byte 4 is moved to bit 7 of byte 5 - // Bit 3 of byte 5 is moved to bit 4 of byte 5, overwriting it - // Bit 1 of byte 5 is moved to bit 3 of byte 5 - // Bit 0 of byte 5 is moved to bit 2 of byte 5, overwriting it - case 0x5: - //data[5] & (1 << 7) - //data[4] & (1 << 0) - //data[5] & (1 << 3) - //data[5] & (1 << 1) - //data[5] & (1 << 0) - break; + // motionplus pass-through modes + if (m_motion_plus_active) + { + switch (m_reg_motion_plus.ext_identifier[0x4]) + { + // nunchuk pass-through mode + // Bit 7 of byte 5 is moved to bit 6 of byte 5, overwriting it + // Bit 0 of byte 4 is moved to bit 7 of byte 5 + // Bit 3 of byte 5 is moved to bit 4 of byte 5, overwriting it + // Bit 1 of byte 5 is moved to bit 3 of byte 5 + // Bit 0 of byte 5 is moved to bit 2 of byte 5, overwriting it + case 0x5: + // data[5] & (1 << 7) + // data[4] & (1 << 0) + // data[5] & (1 << 3) + // data[5] & (1 << 1) + // data[5] & (1 << 0) + break; - // classic controller/musical instrument pass-through mode - // Bit 0 of Byte 4 is overwritten - // Bits 0 and 1 of Byte 5 are moved to bit 0 of Bytes 0 and 1, overwriting - case 0x7: - //data[4] & (1 << 0) - //data[5] & (1 << 0) - //data[5] & (1 << 1) - break; + // classic controller/musical instrument pass-through mode + // Bit 0 of Byte 4 is overwritten + // Bits 0 and 1 of Byte 5 are moved to bit 0 of Bytes 0 and 1, overwriting + case 0x7: + // data[4] & (1 << 0) + // data[5] & (1 << 0) + // data[5] & (1 << 1) + break; - // unknown pass-through mode - default: - break; - } + // unknown pass-through mode + default: + break; + } - ((wm_motionplus_data*)data)->is_mp_data = 0; - ((wm_motionplus_data*)data)->extension_connected = m_extension->active_extension; - } + ((wm_motionplus_data*)data)->is_mp_data = 0; + ((wm_motionplus_data*)data)->extension_connected = m_extension->active_extension; + } - if (0xAA == m_reg_ext.encryption) - WiimoteEncrypt(&m_ext_key, data, 0x00, sizeof(wm_nc)); + if (0xAA == m_reg_ext.encryption) + WiimoteEncrypt(&m_ext_key, data, 0x00, sizeof(wm_nc)); } void Wiimote::Update() { - // no channel == not connected i guess - if (0 == m_reporting_channel) - return; + // no channel == not connected i guess + if (0 == m_reporting_channel) + return; - // returns true if a report was sent - if (Step()) - return; + // returns true if a report was sent + if (Step()) + return; - u8 data[MAX_PAYLOAD]; - memset(data, 0, sizeof(data)); + u8 data[MAX_PAYLOAD]; + memset(data, 0, sizeof(data)); - Movie::SetPolledDevice(); + Movie::SetPolledDevice(); - m_status.battery = (u8)(m_options->settings[5]->GetValue() * 100); + m_status.battery = (u8)(m_options->settings[5]->GetValue() * 100); - const ReportFeatures& rptf = reporting_mode_features[m_reporting_mode - WM_REPORT_CORE]; - s8 rptf_size = rptf.size; - if (Movie::IsPlayingInput() && Movie::PlayWiimote(m_index, data, rptf, m_extension->active_extension, m_ext_key)) - { - if (rptf.core) - m_status.buttons = *(wm_buttons*)(data + rptf.core); - } - else - { - data[0] = 0xA1; - data[1] = m_reporting_mode; + const ReportFeatures& rptf = reporting_mode_features[m_reporting_mode - WM_REPORT_CORE]; + s8 rptf_size = rptf.size; + if (Movie::IsPlayingInput() && + Movie::PlayWiimote(m_index, data, rptf, m_extension->active_extension, m_ext_key)) + { + if (rptf.core) + m_status.buttons = *(wm_buttons*)(data + rptf.core); + } + else + { + data[0] = 0xA1; + data[1] = m_reporting_mode; - // core buttons - if (rptf.core) - GetButtonData(data + rptf.core); + // core buttons + if (rptf.core) + GetButtonData(data + rptf.core); - // acceleration - if (rptf.accel) - GetAccelData(data, rptf); + // acceleration + if (rptf.accel) + GetAccelData(data, rptf); - // IR - if (rptf.ir) - GetIRData(data + rptf.ir, (rptf.accel != 0)); + // IR + if (rptf.ir) + GetIRData(data + rptf.ir, (rptf.accel != 0)); - // extension - if (rptf.ext) - GetExtData(data + rptf.ext); + // extension + if (rptf.ext) + GetExtData(data + rptf.ext); - // hybrid Wiimote stuff (for now, it's not supported while recording) - if (WIIMOTE_SRC_HYBRID == g_wiimote_sources[m_index] && !Movie::IsRecordingInput()) - { - using namespace WiimoteReal; + // hybrid Wiimote stuff (for now, it's not supported while recording) + if (WIIMOTE_SRC_HYBRID == g_wiimote_sources[m_index] && !Movie::IsRecordingInput()) + { + using namespace WiimoteReal; - std::lock_guard lk(g_refresh_lock); - if (g_wiimotes[m_index]) - { - const Report& rpt = g_wiimotes[m_index]->ProcessReadQueue(); - if (!rpt.empty()) - { - const u8 *real_data = rpt.data(); - switch (real_data[1]) - { - // use data reports - default: - if (real_data[1] >= WM_REPORT_CORE) - { - const ReportFeatures& real_rptf = reporting_mode_features[real_data[1] - WM_REPORT_CORE]; + std::lock_guard lk(g_refresh_lock); + if (g_wiimotes[m_index]) + { + const Report& rpt = g_wiimotes[m_index]->ProcessReadQueue(); + if (!rpt.empty()) + { + const u8* real_data = rpt.data(); + switch (real_data[1]) + { + // use data reports + default: + if (real_data[1] >= WM_REPORT_CORE) + { + const ReportFeatures& real_rptf = + reporting_mode_features[real_data[1] - WM_REPORT_CORE]; - // force same report type from real-Wiimote - if (&real_rptf != &rptf) - rptf_size = 0; + // force same report type from real-Wiimote + if (&real_rptf != &rptf) + rptf_size = 0; - // core - // mix real-buttons with emu-buttons in the status struct, and in the report - if (real_rptf.core && rptf.core) - { - m_status.buttons.hex |= ((wm_buttons*)(real_data + real_rptf.core))->hex; - *(wm_buttons*)(data + rptf.core) = m_status.buttons; - } + // core + // mix real-buttons with emu-buttons in the status struct, and in the report + if (real_rptf.core && rptf.core) + { + m_status.buttons.hex |= ((wm_buttons*)(real_data + real_rptf.core))->hex; + *(wm_buttons*)(data + rptf.core) = m_status.buttons; + } - // accel - // use real-accel data always i guess - if (real_rptf.accel && rptf.accel) - memcpy(data + rptf.accel, real_data + real_rptf.accel, sizeof(wm_accel)); + // accel + // use real-accel data always i guess + if (real_rptf.accel && rptf.accel) + memcpy(data + rptf.accel, real_data + real_rptf.accel, sizeof(wm_accel)); - // ir - // TODO + // ir + // TODO - // ext - // use real-ext data if an emu-extention isn't chosen - if (real_rptf.ext && rptf.ext && (0 == m_extension->switch_extension)) - memcpy(data + rptf.ext, real_data + real_rptf.ext, sizeof(wm_nc)); // TODO: Why NC specific? - } - else if (WM_ACK_DATA != real_data[1] || m_extension->active_extension > 0) - rptf_size = 0; - else - // use real-acks if an emu-extension isn't chosen - rptf_size = -1; - break; + // ext + // use real-ext data if an emu-extention isn't chosen + if (real_rptf.ext && rptf.ext && (0 == m_extension->switch_extension)) + memcpy(data + rptf.ext, real_data + real_rptf.ext, + sizeof(wm_nc)); // TODO: Why NC specific? + } + else if (WM_ACK_DATA != real_data[1] || m_extension->active_extension > 0) + rptf_size = 0; + else + // use real-acks if an emu-extension isn't chosen + rptf_size = -1; + break; - // use all status reports, after modification of the extension bit - case WM_STATUS_REPORT : - //if (m_extension->switch_extension) - //((wm_status_report*)(real_data + 2))->extension = (m_extension->active_extension > 0); - if (m_extension->active_extension) - ((wm_status_report*)(real_data + 2))->extension = 1; - rptf_size = -1; - break; + // use all status reports, after modification of the extension bit + case WM_STATUS_REPORT: + // if (m_extension->switch_extension) + //((wm_status_report*)(real_data + 2))->extension = (m_extension->active_extension > 0); + if (m_extension->active_extension) + ((wm_status_report*)(real_data + 2))->extension = 1; + rptf_size = -1; + break; - // use all read-data replies - case WM_READ_DATA_REPLY: - rptf_size = -1; - break; + // use all read-data replies + case WM_READ_DATA_REPLY: + rptf_size = -1; + break; + } - } + // copy over report from real-Wiimote + if (-1 == rptf_size) + { + std::copy(rpt.begin(), rpt.end(), data); + rptf_size = (s8)(rpt.size()); + } + } + } + } - // copy over report from real-Wiimote - if (-1 == rptf_size) - { - std::copy(rpt.begin(), rpt.end(), data); - rptf_size = (s8)(rpt.size()); - } - } - } - } + Movie::CallWiiInputManip(data, rptf, m_index, m_extension->active_extension, m_ext_key); + } + if (NetPlay::IsNetPlayRunning()) + { + NetPlay_GetWiimoteData(m_index, data, rptf.size); + if (rptf.core) + m_status.buttons = *(wm_buttons*)(data + rptf.core); + } - Movie::CallWiiInputManip(data, rptf, m_index, m_extension->active_extension, m_ext_key); - } - if (NetPlay::IsNetPlayRunning()) - { - NetPlay_GetWiimoteData(m_index, data, rptf.size); - if (rptf.core) - m_status.buttons = *(wm_buttons*)(data + rptf.core); - } + Movie::CheckWiimoteStatus(m_index, data, rptf, m_extension->active_extension, m_ext_key); - Movie::CheckWiimoteStatus(m_index, data, rptf, m_extension->active_extension, m_ext_key); + // don't send a data report if auto reporting is off + if (false == m_reporting_auto && data[1] >= WM_REPORT_CORE) + return; - // don't send a data report if auto reporting is off - if (false == m_reporting_auto && data[1] >= WM_REPORT_CORE) - return; - - // send data report - if (rptf_size) - { - Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, data, rptf_size); - } + // send data report + if (rptf_size) + { + Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, data, rptf_size); + } } void Wiimote::ControlChannel(const u16 _channelID, const void* _pData, u32 _Size) { - // Check for custom communication - if (99 == _channelID) - { - // Wiimote disconnected - // reset eeprom/register/reporting mode - Reset(); - return; - } + // Check for custom communication + if (99 == _channelID) + { + // Wiimote disconnected + // reset eeprom/register/reporting mode + Reset(); + return; + } - // this all good? - m_reporting_channel = _channelID; + // this all good? + m_reporting_channel = _channelID; - const hid_packet* const hidp = (hid_packet*)_pData; + const hid_packet* const hidp = (hid_packet*)_pData; - INFO_LOG(WIIMOTE, "Emu ControlChannel (page: %i, type: 0x%02x, param: 0x%02x)", m_index, hidp->type, hidp->param); + INFO_LOG(WIIMOTE, "Emu ControlChannel (page: %i, type: 0x%02x, param: 0x%02x)", m_index, + hidp->type, hidp->param); - switch (hidp->type) - { - case HID_TYPE_HANDSHAKE : - PanicAlert("HID_TYPE_HANDSHAKE - %s", (hidp->param == HID_PARAM_INPUT) ? "INPUT" : "OUPUT"); - break; + switch (hidp->type) + { + case HID_TYPE_HANDSHAKE: + PanicAlert("HID_TYPE_HANDSHAKE - %s", (hidp->param == HID_PARAM_INPUT) ? "INPUT" : "OUPUT"); + break; - case HID_TYPE_SET_REPORT : - if (HID_PARAM_INPUT == hidp->param) - { - PanicAlert("HID_TYPE_SET_REPORT - INPUT"); - } - else - { - // AyuanX: My experiment shows Control Channel is never used - // shuffle2: but lwbt uses this, so we'll do what we must :) - HidOutputReport((wm_report*)hidp->data); + case HID_TYPE_SET_REPORT: + if (HID_PARAM_INPUT == hidp->param) + { + PanicAlert("HID_TYPE_SET_REPORT - INPUT"); + } + else + { + // AyuanX: My experiment shows Control Channel is never used + // shuffle2: but lwbt uses this, so we'll do what we must :) + HidOutputReport((wm_report*)hidp->data); - u8 handshake = HID_HANDSHAKE_SUCCESS; - Core::Callback_WiimoteInterruptChannel(m_index, _channelID, &handshake, 1); - } - break; + u8 handshake = HID_HANDSHAKE_SUCCESS; + Core::Callback_WiimoteInterruptChannel(m_index, _channelID, &handshake, 1); + } + break; - case HID_TYPE_DATA : - PanicAlert("HID_TYPE_DATA - %s", (hidp->param == HID_PARAM_INPUT) ? "INPUT" : "OUTPUT"); - break; - - default : - PanicAlert("HidControlChannel: Unknown type %x and param %x", hidp->type, hidp->param); - break; - } + case HID_TYPE_DATA: + PanicAlert("HID_TYPE_DATA - %s", (hidp->param == HID_PARAM_INPUT) ? "INPUT" : "OUTPUT"); + break; + default: + PanicAlert("HidControlChannel: Unknown type %x and param %x", hidp->type, hidp->param); + break; + } } void Wiimote::InterruptChannel(const u16 _channelID, const void* _pData, u32 _Size) { - // this all good? - m_reporting_channel = _channelID; + // this all good? + m_reporting_channel = _channelID; - const hid_packet* const hidp = (hid_packet*)_pData; + const hid_packet* const hidp = (hid_packet*)_pData; - switch (hidp->type) - { - case HID_TYPE_DATA: - switch (hidp->param) - { - case HID_PARAM_OUTPUT : - { - const wm_report* const sr = (wm_report*)hidp->data; + switch (hidp->type) + { + case HID_TYPE_DATA: + switch (hidp->param) + { + case HID_PARAM_OUTPUT: + { + const wm_report* const sr = (wm_report*)hidp->data; - if (WIIMOTE_SRC_REAL & g_wiimote_sources[m_index]) - { - switch (sr->wm) - { - // these two types are handled in RequestStatus() & ReadData() - case WM_REQUEST_STATUS : - case WM_READ_DATA : - if (WIIMOTE_SRC_REAL == g_wiimote_sources[m_index]) - WiimoteReal::InterruptChannel(m_index, _channelID, _pData, _Size); - break; + if (WIIMOTE_SRC_REAL & g_wiimote_sources[m_index]) + { + switch (sr->wm) + { + // these two types are handled in RequestStatus() & ReadData() + case WM_REQUEST_STATUS: + case WM_READ_DATA: + if (WIIMOTE_SRC_REAL == g_wiimote_sources[m_index]) + WiimoteReal::InterruptChannel(m_index, _channelID, _pData, _Size); + break; - default : - WiimoteReal::InterruptChannel(m_index, _channelID, _pData, _Size); - break; - } + default: + WiimoteReal::InterruptChannel(m_index, _channelID, _pData, _Size); + break; + } - HidOutputReport(sr, m_extension->switch_extension > 0); - } - else - HidOutputReport(sr); - } - break; + HidOutputReport(sr, m_extension->switch_extension > 0); + } + else + HidOutputReport(sr); + } + break; - default : - PanicAlert("HidInput: HID_TYPE_DATA - param 0x%02x", hidp->param); - break; - } - break; + default: + PanicAlert("HidInput: HID_TYPE_DATA - param 0x%02x", hidp->param); + break; + } + break; - default: - PanicAlert("HidInput: Unknown type 0x%02x and param 0x%02x", hidp->type, hidp->param); - break; - } + default: + PanicAlert("HidInput: Unknown type 0x%02x and param 0x%02x", hidp->type, hidp->param); + break; + } } void Wiimote::ConnectOnInput() { - if (m_last_connect_request_counter > 0) - { - --m_last_connect_request_counter; - return; - } + if (m_last_connect_request_counter > 0) + { + --m_last_connect_request_counter; + return; + } - u16 buttons = 0; - m_buttons->GetState(&buttons, button_bitmasks); - m_dpad->GetState(&buttons, dpad_bitmasks); + u16 buttons = 0; + m_buttons->GetState(&buttons, button_bitmasks); + m_dpad->GetState(&buttons, dpad_bitmasks); - if (buttons != 0 || m_extension->IsButtonPressed()) - { - Host_ConnectWiimote(m_index, true); - // arbitrary value so it doesn't try to send multiple requests before Dolphin can react - // if Wiimotes are polled at 200Hz then this results in one request being sent per 500ms - m_last_connect_request_counter = 100; - } + if (buttons != 0 || m_extension->IsButtonPressed()) + { + Host_ConnectWiimote(m_index, true); + // arbitrary value so it doesn't try to send multiple requests before Dolphin can react + // if Wiimotes are polled at 200Hz then this results in one request being sent per 500ms + m_last_connect_request_counter = 100; + } } void Wiimote::LoadDefaults(const ControllerInterface& ciface) { - ControllerEmu::LoadDefaults(ciface); + ControllerEmu::LoadDefaults(ciface); - // Buttons +// Buttons #if defined HAVE_X11 && HAVE_X11 - m_buttons->SetControlExpression(0, "Click 1"); // A - m_buttons->SetControlExpression(1, "Click 3"); // B + m_buttons->SetControlExpression(0, "Click 1"); // A + m_buttons->SetControlExpression(1, "Click 3"); // B #else - m_buttons->SetControlExpression(0, "Click 0"); // A - m_buttons->SetControlExpression(1, "Click 1"); // B + m_buttons->SetControlExpression(0, "Click 0"); // A + m_buttons->SetControlExpression(1, "Click 1"); // B #endif - m_buttons->SetControlExpression(2, "1"); // 1 - m_buttons->SetControlExpression(3, "2"); // 2 - m_buttons->SetControlExpression(4, "Q"); // - - m_buttons->SetControlExpression(5, "E"); // + + m_buttons->SetControlExpression(2, "1"); // 1 + m_buttons->SetControlExpression(3, "2"); // 2 + m_buttons->SetControlExpression(4, "Q"); // - + m_buttons->SetControlExpression(5, "E"); // + #ifdef _WIN32 - m_buttons->SetControlExpression(6, "!LMENU & RETURN"); // Home + m_buttons->SetControlExpression(6, "!LMENU & RETURN"); // Home #else - m_buttons->SetControlExpression(6, "!`Alt_L` & Return"); // Home + m_buttons->SetControlExpression(6, "!`Alt_L` & Return"); // Home #endif - // Shake - for (int i = 0; i < 3; ++i) - m_shake->SetControlExpression(i, "Click 2"); + // Shake + for (int i = 0; i < 3; ++i) + m_shake->SetControlExpression(i, "Click 2"); - // IR - m_ir->SetControlExpression(0, "Cursor Y-"); - m_ir->SetControlExpression(1, "Cursor Y+"); - m_ir->SetControlExpression(2, "Cursor X-"); - m_ir->SetControlExpression(3, "Cursor X+"); + // IR + m_ir->SetControlExpression(0, "Cursor Y-"); + m_ir->SetControlExpression(1, "Cursor Y+"); + m_ir->SetControlExpression(2, "Cursor X-"); + m_ir->SetControlExpression(3, "Cursor X+"); - // DPad +// DPad #ifdef _WIN32 - m_dpad->SetControlExpression(0, "UP"); // Up - m_dpad->SetControlExpression(1, "DOWN"); // Down - m_dpad->SetControlExpression(2, "LEFT"); // Left - m_dpad->SetControlExpression(3, "RIGHT"); // Right + m_dpad->SetControlExpression(0, "UP"); // Up + m_dpad->SetControlExpression(1, "DOWN"); // Down + m_dpad->SetControlExpression(2, "LEFT"); // Left + m_dpad->SetControlExpression(3, "RIGHT"); // Right #elif __APPLE__ - m_dpad->SetControlExpression(0, "Up Arrow"); // Up - m_dpad->SetControlExpression(1, "Down Arrow"); // Down - m_dpad->SetControlExpression(2, "Left Arrow"); // Left - m_dpad->SetControlExpression(3, "Right Arrow"); // Right + m_dpad->SetControlExpression(0, "Up Arrow"); // Up + m_dpad->SetControlExpression(1, "Down Arrow"); // Down + m_dpad->SetControlExpression(2, "Left Arrow"); // Left + m_dpad->SetControlExpression(3, "Right Arrow"); // Right #else - m_dpad->SetControlExpression(0, "Up"); // Up - m_dpad->SetControlExpression(1, "Down"); // Down - m_dpad->SetControlExpression(2, "Left"); // Left - m_dpad->SetControlExpression(3, "Right"); // Right + m_dpad->SetControlExpression(0, "Up"); // Up + m_dpad->SetControlExpression(1, "Down"); // Down + m_dpad->SetControlExpression(2, "Left"); // Left + m_dpad->SetControlExpression(3, "Right"); // Right #endif - // ugly stuff - // enable nunchuk - m_extension->switch_extension = 1; + // ugly stuff + // enable nunchuk + m_extension->switch_extension = 1; - // set nunchuk defaults - m_extension->attachments[1]->LoadDefaults(ciface); + // set nunchuk defaults + m_extension->attachments[1]->LoadDefaults(ciface); } - } diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h index 3bafaac290..777c10057d 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h @@ -12,11 +12,11 @@ #include "InputCommon/ControllerEmu.h" // Registry sizes -#define WIIMOTE_EEPROM_SIZE (16*1024) -#define WIIMOTE_EEPROM_FREE_SIZE 0x1700 -#define WIIMOTE_REG_SPEAKER_SIZE 10 -#define WIIMOTE_REG_EXT_SIZE 0x100 -#define WIIMOTE_REG_IR_SIZE 0x34 +#define WIIMOTE_EEPROM_SIZE (16 * 1024) +#define WIIMOTE_EEPROM_FREE_SIZE 0x1700 +#define WIIMOTE_REG_SPEAKER_SIZE 10 +#define WIIMOTE_REG_EXT_SIZE 0x100 +#define WIIMOTE_REG_IR_SIZE 0x34 class PointerWrap; @@ -26,215 +26,209 @@ class Wiimote; } namespace WiimoteEmu { -#pragma pack(push,1) +#pragma pack(push, 1) struct ReportFeatures { - u8 core, accel, ir, ext, size; + u8 core, accel, ir, ext, size; }; struct AccelData { - double x,y,z; + double x, y, z; }; struct ADPCMState { - s32 predictor, step; + s32 predictor, step; }; struct ExtensionReg { - u8 unknown1[0x08]; + u8 unknown1[0x08]; - // address 0x08 - u8 controller_data[0x06]; - u8 unknown2[0x12]; + // address 0x08 + u8 controller_data[0x06]; + u8 unknown2[0x12]; - // address 0x20 - u8 calibration[0x10]; - u8 unknown3[0x10]; + // address 0x20 + u8 calibration[0x10]; + u8 unknown3[0x10]; - // address 0x40 - u8 encryption_key[0x10]; - u8 unknown4[0xA0]; + // address 0x40 + u8 encryption_key[0x10]; + u8 unknown4[0xA0]; - // address 0xF0 - u8 encryption; - u8 unknown5[0x9]; + // address 0xF0 + u8 encryption; + u8 unknown5[0x9]; - // address 0xFA - u8 constant_id[6]; + // address 0xFA + u8 constant_id[6]; }; -void EmulateShake(AccelData* const accel_data - , ControllerEmu::Buttons* const buttons_group - , u8* const shake_step); +void EmulateShake(AccelData* const accel_data, ControllerEmu::Buttons* const buttons_group, + u8* const shake_step); -void EmulateTilt(AccelData* const accel - , ControllerEmu::Tilt* const tilt_group - , const bool sideways = false, const bool upright = false); +void EmulateTilt(AccelData* const accel, ControllerEmu::Tilt* const tilt_group, + const bool sideways = false, const bool upright = false); -void EmulateSwing(AccelData* const accel - , ControllerEmu::Force* const tilt_group - , const bool sideways = false, const bool upright = false); +void EmulateSwing(AccelData* const accel, ControllerEmu::Force* const tilt_group, + const bool sideways = false, const bool upright = false); enum { - ACCEL_ZERO_G = 0x80, - ACCEL_ONE_G = 0x9A, - ACCEL_RANGE = (ACCEL_ONE_G - ACCEL_ZERO_G), + ACCEL_ZERO_G = 0x80, + ACCEL_ONE_G = 0x9A, + ACCEL_RANGE = (ACCEL_ONE_G - ACCEL_ZERO_G), }; class Wiimote : public ControllerEmu { -friend class WiimoteReal::Wiimote; + friend class WiimoteReal::Wiimote; + public: + enum + { + PAD_LEFT = 0x01, + PAD_RIGHT = 0x02, + PAD_DOWN = 0x04, + PAD_UP = 0x08, + BUTTON_PLUS = 0x10, - enum - { - PAD_LEFT = 0x01, - PAD_RIGHT = 0x02, - PAD_DOWN = 0x04, - PAD_UP = 0x08, - BUTTON_PLUS = 0x10, + BUTTON_TWO = 0x0100, + BUTTON_ONE = 0x0200, + BUTTON_B = 0x0400, + BUTTON_A = 0x0800, + BUTTON_MINUS = 0x1000, + BUTTON_HOME = 0x8000, + }; - BUTTON_TWO = 0x0100, - BUTTON_ONE = 0x0200, - BUTTON_B = 0x0400, - BUTTON_A = 0x0800, - BUTTON_MINUS = 0x1000, - BUTTON_HOME = 0x8000, - }; + Wiimote(const unsigned int index); + std::string GetName() const override; - Wiimote(const unsigned int index); - std::string GetName() const override; + void Update(); + void InterruptChannel(const u16 _channelID, const void* _pData, u32 _Size); + void ControlChannel(const u16 _channelID, const void* _pData, u32 _Size); + void ConnectOnInput(); + void Reset(); - void Update(); - void InterruptChannel(const u16 _channelID, const void* _pData, u32 _Size); - void ControlChannel(const u16 _channelID, const void* _pData, u32 _Size); - void ConnectOnInput(); - void Reset(); + void DoState(PointerWrap& p); + void RealState(); - void DoState(PointerWrap& p); - void RealState(); - - void LoadDefaults(const ControllerInterface& ciface) override; - - int CurrentExtension() const { return m_extension->active_extension; } + void LoadDefaults(const ControllerInterface& ciface) override; + int CurrentExtension() const { return m_extension->active_extension; } protected: - bool Step(); - void HidOutputReport(const wm_report* const sr, const bool send_ack = true); - void HandleExtensionSwap(); - void UpdateButtonsStatus(); + bool Step(); + void HidOutputReport(const wm_report* const sr, const bool send_ack = true); + void HandleExtensionSwap(); + void UpdateButtonsStatus(); - void GetButtonData(u8* const data); - void GetAccelData(u8* const data, const ReportFeatures& rptf); - void GetIRData(u8* const data, bool use_accel); - void GetExtData(u8* const data); - - bool HaveExtension() const { return m_extension->active_extension > 0; } - bool WantExtension() const { return m_extension->switch_extension != 0; } + void GetButtonData(u8* const data); + void GetAccelData(u8* const data, const ReportFeatures& rptf); + void GetIRData(u8* const data, bool use_accel); + void GetExtData(u8* const data); + bool HaveExtension() const { return m_extension->active_extension > 0; } + bool WantExtension() const { return m_extension->switch_extension != 0; } private: - struct ReadRequest - { - //u16 channel; - u32 address, size, position; - u8* data; - }; + struct ReadRequest + { + // u16 channel; + u32 address, size, position; + u8* data; + }; - void ReportMode(const wm_report_mode* const dr); - void SendAck(const u8 _reportID); - void RequestStatus(const wm_request_status* const rs = nullptr); - void ReadData(const wm_read_data* const rd); - void WriteData(const wm_write_data* const wd); - void SendReadDataReply(ReadRequest& _request); - void SpeakerData(wm_speaker_data* sd); - bool NetPlay_GetWiimoteData(int wiimote, u8* data, u8 size); + void ReportMode(const wm_report_mode* const dr); + void SendAck(const u8 _reportID); + void RequestStatus(const wm_request_status* const rs = nullptr); + void ReadData(const wm_read_data* const rd); + void WriteData(const wm_write_data* const wd); + void SendReadDataReply(ReadRequest& _request); + void SpeakerData(wm_speaker_data* sd); + bool NetPlay_GetWiimoteData(int wiimote, u8* data, u8 size); - // control groups - Buttons *m_buttons, *m_dpad, *m_shake; - Cursor* m_ir; - Tilt* m_tilt; - Force* m_swing; - ControlGroup* m_rumble; - Extension* m_extension; - ControlGroup* m_options; + // control groups + Buttons *m_buttons, *m_dpad, *m_shake; + Cursor* m_ir; + Tilt* m_tilt; + Force* m_swing; + ControlGroup* m_rumble; + Extension* m_extension; + ControlGroup* m_options; - // Wiimote accel data - AccelData m_accel; + // Wiimote accel data + AccelData m_accel; - // Wiimote index, 0-3 - const u8 m_index; + // Wiimote index, 0-3 + const u8 m_index; - double ir_sin, ir_cos; //for the low pass filter + double ir_sin, ir_cos; // for the low pass filter - bool m_rumble_on; - bool m_speaker_mute; - bool m_motion_plus_present; - bool m_motion_plus_active; + bool m_rumble_on; + bool m_speaker_mute; + bool m_motion_plus_present; + bool m_motion_plus_active; - bool m_reporting_auto; - u8 m_reporting_mode; - u16 m_reporting_channel; + bool m_reporting_auto; + u8 m_reporting_mode; + u16 m_reporting_channel; - u8 m_shake_step[3]; + u8 m_shake_step[3]; - bool m_sensor_bar_on_top; + bool m_sensor_bar_on_top; - wm_status_report m_status; + wm_status_report m_status; - ADPCMState m_adpcm_state; + ADPCMState m_adpcm_state; - // read data request queue - // maybe it isn't actually a queue - // maybe read requests cancel any current requests - std::queue m_read_requests; + // read data request queue + // maybe it isn't actually a queue + // maybe read requests cancel any current requests + std::queue m_read_requests; - wiimote_key m_ext_key; + wiimote_key m_ext_key; - u8 m_eeprom[WIIMOTE_EEPROM_SIZE]; - struct MotionPlusReg - { - u8 unknown[0xF0]; + u8 m_eeprom[WIIMOTE_EEPROM_SIZE]; + struct MotionPlusReg + { + u8 unknown[0xF0]; - // address 0xF0 - u8 activated; + // address 0xF0 + u8 activated; - u8 unknown2[9]; + u8 unknown2[9]; - // address 0xFA - u8 ext_identifier[6]; - } m_reg_motion_plus; + // address 0xFA + u8 ext_identifier[6]; + } m_reg_motion_plus; - struct IrReg - { - u8 data[0x33]; - u8 mode; - } m_reg_ir; + struct IrReg + { + u8 data[0x33]; + u8 mode; + } m_reg_ir; - ExtensionReg m_reg_ext; + ExtensionReg m_reg_ext; - struct SpeakerReg - { - u8 unused_0; - u8 unk_1; - u8 format; - // seems to always play at 6khz no matter what this is set to? - // or maybe it only applies to pcm input - u16 sample_rate; - u8 volume; - u8 unk_6; - u8 unk_7; - u8 play; - u8 unk_9; - } m_reg_speaker; + struct SpeakerReg + { + u8 unused_0; + u8 unk_1; + u8 format; + // seems to always play at 6khz no matter what this is set to? + // or maybe it only applies to pcm input + u16 sample_rate; + u8 volume; + u8 unk_6; + u8 unk_7; + u8 play; + u8 unk_9; + } m_reg_speaker; - // limits the amount of connect requests we send when a button is pressed in disconnected state - u8 m_last_connect_request_counter; + // limits the amount of connect requests we send when a button is pressed in disconnected state + u8 m_last_connect_request_counter; #pragma pack(pop) }; - } diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteHid.h b/Source/Core/Core/HW/WiimoteEmu/WiimoteHid.h index c268fd3597..029c4154fa 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteHid.h +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteHid.h @@ -8,7 +8,7 @@ // what is this ? #ifdef _MSC_VER -#pragma warning(disable:4200) +#pragma warning(disable : 4200) #endif #pragma pack(push, 1) @@ -17,9 +17,9 @@ struct hid_packet { - u8 param : 4; - u8 type : 4; - u8 data[0]; + u8 param : 4; + u8 type : 4; + u8 data[0]; }; #define HID_TYPE_HANDSHAKE 0 @@ -33,303 +33,297 @@ struct hid_packet // Source: http://wiibrew.org/wiki/Wiimote -union wm_buttons // also just called "core data" +union wm_buttons // also just called "core data" { - u16 hex; + u16 hex; - struct - { - u8 left : 1; - u8 right : 1; - u8 down : 1; - u8 up : 1; - u8 plus : 1; - u8 acc_x_lsb : 2; // LSB of accelerometer (10 bits in total) - u8 unknown : 1; + struct + { + u8 left : 1; + u8 right : 1; + u8 down : 1; + u8 up : 1; + u8 plus : 1; + u8 acc_x_lsb : 2; // LSB of accelerometer (10 bits in total) + u8 unknown : 1; - u8 two : 1; - u8 one : 1; - u8 b : 1; - u8 a : 1; - u8 minus : 1; - u8 acc_y_lsb : 1; // LSB of accelerometer (9 bits in total) - u8 acc_z_lsb : 1; // LSB of accelerometer (9 bits in total) - u8 home : 1; - }; + u8 two : 1; + u8 one : 1; + u8 b : 1; + u8 a : 1; + u8 minus : 1; + u8 acc_y_lsb : 1; // LSB of accelerometer (9 bits in total) + u8 acc_z_lsb : 1; // LSB of accelerometer (9 bits in total) + u8 home : 1; + }; }; struct wm_accel { - u8 x, y, z; + u8 x, y, z; }; // Four bytes for two objects. Filled with 0xFF if empty struct wm_ir_basic { - u8 x1; - u8 y1; - u8 x2hi : 2; - u8 y2hi : 2; - u8 x1hi : 2; - u8 y1hi : 2; - u8 x2; - u8 y2; + u8 x1; + u8 y1; + u8 x2hi : 2; + u8 y2hi : 2; + u8 x1hi : 2; + u8 y1hi : 2; + u8 x2; + u8 y2; }; // Three bytes for one object struct wm_ir_extended { - u8 x; - u8 y; - u8 size : 4; - u8 xhi : 2; - u8 yhi : 2; + u8 x; + u8 y; + u8 size : 4; + u8 xhi : 2; + u8 yhi : 2; }; // Nunchuk -union wm_nc_core -{ - u8 hex; +union wm_nc_core { + u8 hex; - struct - { - u8 z : 1; - u8 c : 1; + struct + { + u8 z : 1; + u8 c : 1; - // LSBs of accelerometer - u8 acc_x_lsb : 2; - u8 acc_y_lsb : 2; - u8 acc_z_lsb : 2; - }; + // LSBs of accelerometer + u8 acc_x_lsb : 2; + u8 acc_y_lsb : 2; + u8 acc_z_lsb : 2; + }; }; -union wm_nc -{ - struct - { - // joystick x, y - u8 jx; - u8 jy; +union wm_nc { + struct + { + // joystick x, y + u8 jx; + u8 jy; - // accelerometer - u8 ax; - u8 ay; - u8 az; + // accelerometer + u8 ax; + u8 ay; + u8 az; - wm_nc_core bt; // buttons + accelerometer LSBs - }; // regular data + wm_nc_core bt; // buttons + accelerometer LSBs + }; // regular data - struct - { - u8 reserved[4]; // jx, jy, ax and ay as in regular case + struct + { + u8 reserved[4]; // jx, jy, ax and ay as in regular case - u8 extension_connected : 1; - u8 acc_z : 7; // MSBs of accelerometer data + u8 extension_connected : 1; + u8 acc_z : 7; // MSBs of accelerometer data - u8 unknown : 1; // always 0? - u8 report_type : 1; // 1: report contains M+ data, 0: report contains extension data + u8 unknown : 1; // always 0? + u8 report_type : 1; // 1: report contains M+ data, 0: report contains extension data - u8 z : 1; - u8 c : 1; + u8 z : 1; + u8 c : 1; - // LSBs of accelerometer - starting from bit 1! - u8 acc_x_lsb : 1; - u8 acc_y_lsb : 1; - u8 acc_z_lsb : 2; - } passthrough_data; + // LSBs of accelerometer - starting from bit 1! + u8 acc_x_lsb : 1; + u8 acc_y_lsb : 1; + u8 acc_z_lsb : 2; + } passthrough_data; }; -union wm_classic_extension_buttons -{ - u16 hex; +union wm_classic_extension_buttons { + u16 hex; - struct - { - u8 extension_connected : 1; - u8 rt : 1; // right trigger - u8 plus : 1; - u8 home : 1; - u8 minus : 1; - u8 lt : 1; // left trigger - u8 dpad_down : 1; - u8 dpad_right : 1; + struct + { + u8 extension_connected : 1; + u8 rt : 1; // right trigger + u8 plus : 1; + u8 home : 1; + u8 minus : 1; + u8 lt : 1; // left trigger + u8 dpad_down : 1; + u8 dpad_right : 1; - u8 : 2; // cf. extension_data and passthrough_data - u8 zr : 1; // right z button - u8 x : 1; - u8 a : 1; - u8 y : 1; - u8 b : 1; - u8 zl : 1; // left z button - }; // common data + u8 : 2; // cf. extension_data and passthrough_data + u8 zr : 1; // right z button + u8 x : 1; + u8 a : 1; + u8 y : 1; + u8 b : 1; + u8 zl : 1; // left z button + }; // common data - // M+ pass-through mode slightly differs from the regular data. - // Refer to the common data for unnamed fields - struct - { - u8 : 8; + // M+ pass-through mode slightly differs from the regular data. + // Refer to the common data for unnamed fields + struct + { + u8 : 8; - u8 dpad_up : 1; - u8 dpad_left : 1; - u8 : 6; - } regular_data; + u8 dpad_up : 1; + u8 dpad_left : 1; + u8 : 6; + } regular_data; - struct - { - u8 : 8; + struct + { + u8 : 8; - u8 unknown : 1; // always 0? - u8 report_type : 1; // 1: report contains M+ data, 0: report contains extension data - u8 : 6; - } passthrough_data; + u8 unknown : 1; // always 0? + u8 report_type : 1; // 1: report contains M+ data, 0: report contains extension data + u8 : 6; + } passthrough_data; }; -union wm_classic_extension -{ - // lx/ly/lz; left joystick - // rx/ry/rz; right joystick - // lt; left trigger - // rt; left trigger +union wm_classic_extension { + // lx/ly/lz; left joystick + // rx/ry/rz; right joystick + // lt; left trigger + // rt; left trigger - struct - { - u8 : 6; - u8 rx3 : 2; + struct + { + u8 : 6; + u8 rx3 : 2; - u8 : 6; - u8 rx2 : 2; + u8 : 6; + u8 rx2 : 2; - u8 ry : 5; - u8 lt2 : 2; - u8 rx1 : 1; + u8 ry : 5; + u8 lt2 : 2; + u8 rx1 : 1; - u8 rt : 5; - u8 lt1 : 3; + u8 rt : 5; + u8 lt1 : 3; - wm_classic_extension_buttons bt; // byte 4, 5 - }; + wm_classic_extension_buttons bt; // byte 4, 5 + }; - struct - { - u8 lx : 6; // byte 0 - u8 : 2; + struct + { + u8 lx : 6; // byte 0 + u8 : 2; - u8 ly : 6; // byte 1 - u8 : 2; + u8 ly : 6; // byte 1 + u8 : 2; - unsigned : 32; - } regular_data; + unsigned : 32; + } regular_data; - struct - { - u8 dpad_up : 1; - u8 lx : 5; // Bits 1-5 - u8 : 2; + struct + { + u8 dpad_up : 1; + u8 lx : 5; // Bits 1-5 + u8 : 2; - u8 dpad_left : 1; - u8 ly : 5; // Bits 1-5 - u8 : 2; + u8 dpad_left : 1; + u8 ly : 5; // Bits 1-5 + u8 : 2; - unsigned : 32; - } passthrough_data; + unsigned : 32; + } passthrough_data; }; struct wm_guitar_extension { - u8 sx : 6; - u8 pad1 : 2; // 1 on gh3, 0 on ghwt + u8 sx : 6; + u8 pad1 : 2; // 1 on gh3, 0 on ghwt - u8 sy : 6; - u8 pad2 : 2; // 1 on gh3, 0 on ghwt + u8 sy : 6; + u8 pad2 : 2; // 1 on gh3, 0 on ghwt - u8 tb : 5; // not used in gh3 - u8 pad3 : 3; // always 0 + u8 tb : 5; // not used in gh3 + u8 pad3 : 3; // always 0 - u8 whammy : 5; - u8 pad4 : 3; // always 0 + u8 whammy : 5; + u8 pad4 : 3; // always 0 - u16 bt; // buttons + u16 bt; // buttons }; struct wm_drums_extension { - u8 sx : 6; - u8 pad1 : 2; // always 0 + u8 sx : 6; + u8 pad1 : 2; // always 0 - u8 sy : 6; - u8 pad2 : 2; // always 0 + u8 sy : 6; + u8 pad2 : 2; // always 0 - u8 pad3 : 1; // unknown - u8 which : 5; - u8 none : 1; - u8 hhp : 1; + u8 pad3 : 1; // unknown + u8 which : 5; + u8 none : 1; + u8 hhp : 1; - u8 pad4 : 1; // unknown - u8 velocity : 4; // unknown - u8 softness : 3; + u8 pad4 : 1; // unknown + u8 velocity : 4; // unknown + u8 softness : 3; - u16 bt; // buttons + u16 bt; // buttons }; struct wm_turntable_extension { - u8 sx : 6; - u8 rtable3 : 2; + u8 sx : 6; + u8 rtable3 : 2; - u8 sy : 6; - u8 rtable2 : 2; + u8 sy : 6; + u8 rtable2 : 2; - u8 rtable4 : 1; - u8 slider : 4; - u8 dial2 : 2; - u8 rtable1 : 1; + u8 rtable4 : 1; + u8 slider : 4; + u8 dial2 : 2; + u8 rtable1 : 1; - u8 ltable1 : 5; - u8 dial1 : 3; + u8 ltable1 : 5; + u8 dial1 : 3; - union - { - u16 ltable2 : 1; - u16 bt; // buttons - }; + union { + u16 ltable2 : 1; + u16 bt; // buttons + }; }; struct wm_motionplus_data { - // yaw1, roll1, pitch1: Bits 0-7 - // yaw2, roll2, pitch2: Bits 8-13 + // yaw1, roll1, pitch1: Bits 0-7 + // yaw2, roll2, pitch2: Bits 8-13 - u8 yaw1; - u8 roll1; - u8 pitch1; + u8 yaw1; + u8 roll1; + u8 pitch1; - u8 pitch_slow : 1; - u8 yaw_slow : 1; - u8 yaw2 : 6; + u8 pitch_slow : 1; + u8 yaw_slow : 1; + u8 yaw2 : 6; - u8 extension_connected : 1; - u8 roll_slow : 1; - u8 roll2 : 6; + u8 extension_connected : 1; + u8 roll_slow : 1; + u8 roll2 : 6; - u8 zero : 1; - u8 is_mp_data : 1; - u8 pitch2 : 6; + u8 zero : 1; + u8 is_mp_data : 1; + u8 pitch2 : 6; }; struct wm_report { - u8 wm; - union - { - u8 data[0]; - struct - { - u8 rumble : 1; // enable/disable rumble - // only valid for certain reports - u8 ack : 1; // respond with an ack - u8 enable : 1; // enable/disable certain features - }; - }; + u8 wm; + union { + u8 data[0]; + struct + { + u8 rumble : 1; // enable/disable rumble + // only valid for certain reports + u8 ack : 1; // respond with an ack + u8 enable : 1; // enable/disable certain features + }; + }; }; #define WM_RUMBLE 0x10 @@ -337,21 +331,21 @@ struct wm_report #define WM_LEDS 0x11 struct wm_leds { - u8 rumble : 1; - // real Wii also sets bit 0x2 (unknown purpose) - u8 : 3; - u8 leds : 4; + u8 rumble : 1; + // real Wii also sets bit 0x2 (unknown purpose) + u8 : 3; + u8 leds : 4; }; #define WM_REPORT_MODE 0x12 struct wm_report_mode { - u8 rumble : 1; - // unsure what "all_the_time" actually is, the real Wii does set it (bit 0x2) - u8 all_the_time : 1; - u8 continuous : 1; - u8 : 5; - u8 mode; + u8 rumble : 1; + // unsure what "all_the_time" actually is, the real Wii does set it (bit 0x2) + u8 all_the_time : 1; + u8 continuous : 1; + u8 : 5; + u8 mode; }; #define WM_IR_PIXEL_CLOCK 0x13 @@ -360,50 +354,50 @@ struct wm_report_mode #define WM_REQUEST_STATUS 0x15 struct wm_request_status { - u8 rumble : 1; - u8 : 7; + u8 rumble : 1; + u8 : 7; }; #define WM_STATUS_REPORT 0x20 struct wm_status_report { - wm_buttons buttons; - u8 battery_low : 1; - u8 extension : 1; - u8 speaker : 1; - u8 ir : 1; - u8 leds : 4; - u8 padding2[2]; // two 00, TODO: this needs more investigation - u8 battery; + wm_buttons buttons; + u8 battery_low : 1; + u8 extension : 1; + u8 speaker : 1; + u8 ir : 1; + u8 leds : 4; + u8 padding2[2]; // two 00, TODO: this needs more investigation + u8 battery; }; #define WM_WRITE_DATA 0x16 struct wm_write_data { - u8 rumble : 1; - u8 space : 2; //see WM_SPACE_* - u8 : 5; - u8 address[3]; - u8 size; - u8 data[16]; + u8 rumble : 1; + u8 space : 2; // see WM_SPACE_* + u8 : 5; + u8 address[3]; + u8 size; + u8 data[16]; }; #define WM_ACK_DATA 0x22 struct wm_acknowledge { - wm_buttons buttons; - u8 reportID; - u8 errorID; + wm_buttons buttons; + u8 reportID; + u8 errorID; }; #define WM_READ_DATA 0x17 struct wm_read_data { - u8 rumble : 1; - u8 space : 2; //see WM_SPACE_* - u8 : 5; - u8 address[3]; - u16 size; + u8 rumble : 1; + u8 space : 2; // see WM_SPACE_* + u8 : 5; + u8 address[3]; + u16 size; }; #define WM_SPACE_EEPROM 0 @@ -414,30 +408,29 @@ struct wm_read_data #define WM_READ_DATA_REPLY 0x21 struct wm_read_data_reply { - wm_buttons buttons; - u8 error : 4; //see WM_RDERR_* - u8 size : 4; - u16 address; - u8 data[16]; + wm_buttons buttons; + u8 error : 4; // see WM_RDERR_* + u8 size : 4; + u16 address; + u8 data[16]; }; #define WM_RDERR_WOREG 7 #define WM_RDERR_NOMEM 8 - // Data reports #define WM_REPORT_CORE 0x30 struct wm_report_core { - wm_buttons c; + wm_buttons c; }; #define WM_REPORT_CORE_ACCEL 0x31 struct wm_report_core_accel { - wm_buttons c; - wm_accel a; + wm_buttons c; + wm_accel a; }; #define WM_REPORT_CORE_EXT8 0x32 @@ -445,21 +438,20 @@ struct wm_report_core_accel #define WM_REPORT_CORE_ACCEL_IR12 0x33 struct wm_report_core_accel_ir12 { - wm_buttons c; - wm_accel a; - wm_ir_extended ir[4]; + wm_buttons c; + wm_accel a; + wm_ir_extended ir[4]; }; #define WM_REPORT_CORE_EXT19 0x34 #define WM_REPORT_CORE_ACCEL_EXT16 0x35 struct wm_report_core_accel_ext16 { - wm_buttons c; - wm_accel a; - wm_nc ext; // TODO: Does this make any sense? Shouldn't it be just a general "extension" field? - //wm_ir_basic ir[2]; - u8 pad[10]; - + wm_buttons c; + wm_accel a; + wm_nc ext; // TODO: Does this make any sense? Shouldn't it be just a general "extension" field? + // wm_ir_basic ir[2]; + u8 pad[10]; }; #define WM_REPORT_CORE_IR10_EXT9 0x36 @@ -467,17 +459,17 @@ struct wm_report_core_accel_ext16 #define WM_REPORT_CORE_ACCEL_IR10_EXT6 0x37 struct wm_report_core_accel_ir10_ext6 { - wm_buttons c; - wm_accel a; - wm_ir_basic ir[2]; - //u8 ext[6]; - wm_nc ext; // TODO: Does this make any sense? Shouldn't it be just a general "extension" field? + wm_buttons c; + wm_accel a; + wm_ir_basic ir[2]; + // u8 ext[6]; + wm_nc ext; // TODO: Does this make any sense? Shouldn't it be just a general "extension" field? }; -#define WM_REPORT_EXT21 0x3d // never used? +#define WM_REPORT_EXT21 0x3d // never used? struct wm_report_ext21 { - u8 ext[21]; + u8 ext[21]; }; #define WM_REPORT_INTERLEAVE1 0x3e @@ -488,9 +480,9 @@ struct wm_report_ext21 #define WM_WRITE_SPEAKER_DATA 0x18 struct wm_speaker_data { - u8 unknown : 3; - u8 length : 5; - u8 data[20]; + u8 unknown : 3; + u8 length : 5; + u8 data[20]; }; // Custom structs diff --git a/Source/Core/Core/HW/WiimoteReal/IOAndroid.cpp b/Source/Core/Core/HW/WiimoteReal/IOAndroid.cpp index 7a2e1e249c..d69eef4e10 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOAndroid.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOAndroid.cpp @@ -7,10 +7,10 @@ #include "Common/CommonTypes.h" #include "Common/Event.h" #include "Common/Flag.h" +#include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "Common/Thread.h" #include "Common/Timer.h" -#include "Common/Logging/Log.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" @@ -19,113 +19,116 @@ extern JavaVM* g_java_vm; namespace WiimoteReal { - // Java classes static jclass s_adapter_class; class WiimoteAndroid final : public Wiimote { public: - WiimoteAndroid(int index); - ~WiimoteAndroid() override; + WiimoteAndroid(int index); + ~WiimoteAndroid() override; protected: - bool ConnectInternal() override; - void DisconnectInternal() override; - bool IsConnected() const override; - void IOWakeup() {} - int IORead(u8* buf) override; - int IOWrite(u8 const* buf, size_t len) override; + bool ConnectInternal() override; + void DisconnectInternal() override; + bool IsConnected() const override; + void IOWakeup() {} + int IORead(u8* buf) override; + int IOWrite(u8 const* buf, size_t len) override; private: - int m_mayflash_index; - bool is_connected = true; + int m_mayflash_index; + bool is_connected = true; - JNIEnv* m_env; + JNIEnv* m_env; - jmethodID m_input_func; - jmethodID m_output_func; + jmethodID m_input_func; + jmethodID m_output_func; - jbyteArray m_java_wiimote_payload; + jbyteArray m_java_wiimote_payload; }; WiimoteScanner::WiimoteScanner() -{} +{ +} WiimoteScanner::~WiimoteScanner() -{} +{ +} void WiimoteScanner::Update() -{} +{ +} void WiimoteScanner::FindWiimotes(std::vector& found_wiimotes, Wiimote*& found_board) { - found_wiimotes.clear(); - found_board = nullptr; + found_wiimotes.clear(); + found_board = nullptr; - NOTICE_LOG(WIIMOTE, "Finding Wiimotes"); + NOTICE_LOG(WIIMOTE, "Finding Wiimotes"); - JNIEnv* env; - int get_env_status = g_java_vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); + JNIEnv* env; + int get_env_status = g_java_vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); - if (get_env_status == JNI_EDETACHED) - g_java_vm->AttachCurrentThread(&env, nullptr); + if (get_env_status == JNI_EDETACHED) + g_java_vm->AttachCurrentThread(&env, nullptr); - jmethodID openadapter_func = env->GetStaticMethodID(s_adapter_class, "OpenAdapter", "()Z"); - jmethodID queryadapter_func = env->GetStaticMethodID(s_adapter_class, "QueryAdapter", "()Z"); + jmethodID openadapter_func = env->GetStaticMethodID(s_adapter_class, "OpenAdapter", "()Z"); + jmethodID queryadapter_func = env->GetStaticMethodID(s_adapter_class, "QueryAdapter", "()Z"); - if (env->CallStaticBooleanMethod(s_adapter_class, queryadapter_func) && - env->CallStaticBooleanMethod(s_adapter_class, openadapter_func)) - { - for (int i = 0; i < MAX_WIIMOTES; ++i) - found_wiimotes.emplace_back(new WiimoteAndroid(i)); - } + if (env->CallStaticBooleanMethod(s_adapter_class, queryadapter_func) && + env->CallStaticBooleanMethod(s_adapter_class, openadapter_func)) + { + for (int i = 0; i < MAX_WIIMOTES; ++i) + found_wiimotes.emplace_back(new WiimoteAndroid(i)); + } - if (get_env_status == JNI_EDETACHED) - g_java_vm->DetachCurrentThread(); + if (get_env_status == JNI_EDETACHED) + g_java_vm->DetachCurrentThread(); } bool WiimoteScanner::IsReady() const { - return true; + return true; } -WiimoteAndroid::WiimoteAndroid(int index) - : Wiimote(), m_mayflash_index(index) +WiimoteAndroid::WiimoteAndroid(int index) : Wiimote(), m_mayflash_index(index) { } WiimoteAndroid::~WiimoteAndroid() { - Shutdown(); + Shutdown(); } // Connect to a Wiimote with a known address. bool WiimoteAndroid::ConnectInternal() { - g_java_vm->AttachCurrentThread(&m_env, nullptr); + g_java_vm->AttachCurrentThread(&m_env, nullptr); - jfieldID payload_field = m_env->GetStaticFieldID(s_adapter_class, "wiimote_payload", "[[B"); - jobjectArray payload_object = reinterpret_cast(m_env->GetStaticObjectField(s_adapter_class, payload_field)); - m_java_wiimote_payload = (jbyteArray)m_env->GetObjectArrayElement(payload_object, m_mayflash_index); + jfieldID payload_field = m_env->GetStaticFieldID(s_adapter_class, "wiimote_payload", "[[B"); + jobjectArray payload_object = + reinterpret_cast(m_env->GetStaticObjectField(s_adapter_class, payload_field)); + m_java_wiimote_payload = + (jbyteArray)m_env->GetObjectArrayElement(payload_object, m_mayflash_index); - // Get function pointers - m_input_func = m_env->GetStaticMethodID(s_adapter_class, "Input", "(I)I"); - m_output_func = m_env->GetStaticMethodID(s_adapter_class, "Output", "(I[BI)I"); + // Get function pointers + m_input_func = m_env->GetStaticMethodID(s_adapter_class, "Input", "(I)I"); + m_output_func = m_env->GetStaticMethodID(s_adapter_class, "Output", "(I[BI)I"); - is_connected = true; + is_connected = true; - return true; + return true; } void WiimoteAndroid::DisconnectInternal() { - g_java_vm->DetachCurrentThread(); + g_java_vm->DetachCurrentThread(); } bool WiimoteAndroid::IsConnected() const { - return is_connected; + return is_connected; } // positive = read packet @@ -133,33 +136,32 @@ bool WiimoteAndroid::IsConnected() const // zero = error int WiimoteAndroid::IORead(u8* buf) { - int read_size = m_env->CallStaticIntMethod(s_adapter_class, m_input_func, m_mayflash_index); - jbyte* java_data = m_env->GetByteArrayElements(m_java_wiimote_payload, nullptr); - memcpy(buf + 1, java_data, std::min(MAX_PAYLOAD - 1, read_size)); - buf[0] = 0xA1; - m_env->ReleaseByteArrayElements(m_java_wiimote_payload, java_data, 0); - return read_size <= 0 ? read_size : read_size + 1; + int read_size = m_env->CallStaticIntMethod(s_adapter_class, m_input_func, m_mayflash_index); + jbyte* java_data = m_env->GetByteArrayElements(m_java_wiimote_payload, nullptr); + memcpy(buf + 1, java_data, std::min(MAX_PAYLOAD - 1, read_size)); + buf[0] = 0xA1; + m_env->ReleaseByteArrayElements(m_java_wiimote_payload, java_data, 0); + return read_size <= 0 ? read_size : read_size + 1; } - int WiimoteAndroid::IOWrite(u8 const* buf, size_t len) { - jbyteArray output_array = m_env->NewByteArray(len); - jbyte* output = m_env->GetByteArrayElements(output_array, nullptr); - memcpy(output, buf, len); - m_env->ReleaseByteArrayElements(output_array, output, 0); - int written = m_env->CallStaticIntMethod(s_adapter_class, m_output_func, m_mayflash_index, output_array, len); - m_env->DeleteLocalRef(output_array); - return written; + jbyteArray output_array = m_env->NewByteArray(len); + jbyte* output = m_env->GetByteArrayElements(output_array, nullptr); + memcpy(output, buf, len); + m_env->ReleaseByteArrayElements(output_array, output, 0); + int written = m_env->CallStaticIntMethod(s_adapter_class, m_output_func, m_mayflash_index, + output_array, len); + m_env->DeleteLocalRef(output_array); + return written; } void InitAdapterClass() { - JNIEnv* env; - g_java_vm->AttachCurrentThread(&env, nullptr); + JNIEnv* env; + g_java_vm->AttachCurrentThread(&env, nullptr); - jclass adapter_class = env->FindClass("org/dolphinemu/dolphinemu/utils/Java_WiimoteAdapter"); - s_adapter_class = reinterpret_cast(env->NewGlobalRef(adapter_class)); + jclass adapter_class = env->FindClass("org/dolphinemu/dolphinemu/utils/Java_WiimoteAdapter"); + s_adapter_class = reinterpret_cast(env->NewGlobalRef(adapter_class)); } - } diff --git a/Source/Core/Core/HW/WiimoteReal/IODummy.cpp b/Source/Core/Core/HW/WiimoteReal/IODummy.cpp index a36cf17489..9f0ed27f56 100644 --- a/Source/Core/Core/HW/WiimoteReal/IODummy.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IODummy.cpp @@ -7,25 +7,26 @@ namespace WiimoteReal { - WiimoteScanner::WiimoteScanner() -{} +{ +} WiimoteScanner::~WiimoteScanner() -{} +{ +} void WiimoteScanner::Update() -{} - -void WiimoteScanner::FindWiimotes(std::vector & found_wiimotes, Wiimote* & found_board) { - found_wiimotes.clear(); - found_board = nullptr; +} + +void WiimoteScanner::FindWiimotes(std::vector& found_wiimotes, Wiimote*& found_board) +{ + found_wiimotes.clear(); + found_board = nullptr; } bool WiimoteScanner::IsReady() const { - return false; + return false; } - }; diff --git a/Source/Core/Core/HW/WiimoteReal/IONix.cpp b/Source/Core/Core/HW/WiimoteReal/IONix.cpp index f2abd830ea..3c4bc19d6b 100644 --- a/Source/Core/Core/HW/WiimoteReal/IONix.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IONix.cpp @@ -17,211 +17,209 @@ namespace WiimoteReal { - class WiimoteLinux final : public Wiimote { public: - WiimoteLinux(bdaddr_t bdaddr); - ~WiimoteLinux() override; + WiimoteLinux(bdaddr_t bdaddr); + ~WiimoteLinux() override; protected: - bool ConnectInternal() override; - void DisconnectInternal() override; - bool IsConnected() const override; - void IOWakeup() override; - int IORead(u8* buf) override; - int IOWrite(u8 const* buf, size_t len) override; + bool ConnectInternal() override; + void DisconnectInternal() override; + bool IsConnected() const override; + void IOWakeup() override; + int IORead(u8* buf) override; + int IOWrite(u8 const* buf, size_t len) override; private: - bdaddr_t m_bdaddr; // Bluetooth address - int m_cmd_sock; // Command socket - int m_int_sock; // Interrupt socket - int m_wakeup_pipe_w; - int m_wakeup_pipe_r; + bdaddr_t m_bdaddr; // Bluetooth address + int m_cmd_sock; // Command socket + int m_int_sock; // Interrupt socket + int m_wakeup_pipe_w; + int m_wakeup_pipe_r; }; -WiimoteScanner::WiimoteScanner() - : device_id(-1) - , device_sock(-1) +WiimoteScanner::WiimoteScanner() : device_id(-1), device_sock(-1) { - // Get the id of the first Bluetooth device. - device_id = hci_get_route(nullptr); - if (device_id < 0) - { - NOTICE_LOG(WIIMOTE, "Bluetooth not found."); - return; - } + // Get the id of the first Bluetooth device. + device_id = hci_get_route(nullptr); + if (device_id < 0) + { + NOTICE_LOG(WIIMOTE, "Bluetooth not found."); + return; + } - // Create a socket to the device - device_sock = hci_open_dev(device_id); - if (device_sock < 0) - { - ERROR_LOG(WIIMOTE, "Unable to open Bluetooth."); - return; - } + // Create a socket to the device + device_sock = hci_open_dev(device_id); + if (device_sock < 0) + { + ERROR_LOG(WIIMOTE, "Unable to open Bluetooth."); + return; + } } bool WiimoteScanner::IsReady() const { - return device_sock > 0; + return device_sock > 0; } WiimoteScanner::~WiimoteScanner() { - if (IsReady()) - close(device_sock); + if (IsReady()) + close(device_sock); } void WiimoteScanner::Update() -{} - -void WiimoteScanner::FindWiimotes(std::vector & found_wiimotes, Wiimote* & found_board) { - // supposedly 1.28 seconds - int const wait_len = 1; +} - int const max_infos = 255; - inquiry_info scan_infos[max_infos] = {}; - auto* scan_infos_ptr = scan_infos; - found_board = nullptr; +void WiimoteScanner::FindWiimotes(std::vector& found_wiimotes, Wiimote*& found_board) +{ + // supposedly 1.28 seconds + int const wait_len = 1; - // Scan for Bluetooth devices - int const found_devices = hci_inquiry(device_id, wait_len, max_infos, nullptr, &scan_infos_ptr, IREQ_CACHE_FLUSH); - if (found_devices < 0) - { - ERROR_LOG(WIIMOTE, "Error searching for Bluetooth devices."); - return; - } + int const max_infos = 255; + inquiry_info scan_infos[max_infos] = {}; + auto* scan_infos_ptr = scan_infos; + found_board = nullptr; - DEBUG_LOG(WIIMOTE, "Found %i Bluetooth device(s).", found_devices); + // Scan for Bluetooth devices + int const found_devices = + hci_inquiry(device_id, wait_len, max_infos, nullptr, &scan_infos_ptr, IREQ_CACHE_FLUSH); + if (found_devices < 0) + { + ERROR_LOG(WIIMOTE, "Error searching for Bluetooth devices."); + return; + } - // Display discovered devices - for (int i = 0; i < found_devices; ++i) - { - ERROR_LOG(WIIMOTE, "found a device..."); + DEBUG_LOG(WIIMOTE, "Found %i Bluetooth device(s).", found_devices); - // BT names are a maximum of 248 bytes apparently - char name[255] = {}; - if (hci_read_remote_name(device_sock, &scan_infos[i].bdaddr, sizeof(name), name, 1000) < 0) - { - ERROR_LOG(WIIMOTE, "name request failed"); - continue; - } + // Display discovered devices + for (int i = 0; i < found_devices; ++i) + { + ERROR_LOG(WIIMOTE, "found a device..."); - ERROR_LOG(WIIMOTE, "device name %s", name); - if (IsValidBluetoothName(name)) - { - bool new_wiimote = true; + // BT names are a maximum of 248 bytes apparently + char name[255] = {}; + if (hci_read_remote_name(device_sock, &scan_infos[i].bdaddr, sizeof(name), name, 1000) < 0) + { + ERROR_LOG(WIIMOTE, "name request failed"); + continue; + } - // TODO: do this + ERROR_LOG(WIIMOTE, "device name %s", name); + if (IsValidBluetoothName(name)) + { + bool new_wiimote = true; - // Determine if this Wiimote has already been found. - //for (int j = 0; j < MAX_WIIMOTES && new_wiimote; ++j) - //{ - // if (wm[j] && bacmp(&scan_infos[i].bdaddr,&wm[j]->bdaddr) == 0) - // new_wiimote = false; - //} + // TODO: do this - if (new_wiimote) - { - // Found a new device - char bdaddr_str[18] = {}; - ba2str(&scan_infos[i].bdaddr, bdaddr_str); + // Determine if this Wiimote has already been found. + // for (int j = 0; j < MAX_WIIMOTES && new_wiimote; ++j) + //{ + // if (wm[j] && bacmp(&scan_infos[i].bdaddr,&wm[j]->bdaddr) == 0) + // new_wiimote = false; + //} - Wiimote* wm = new WiimoteLinux(scan_infos[i].bdaddr); - if (IsBalanceBoardName(name)) - { - found_board = wm; - NOTICE_LOG(WIIMOTE, "Found balance board (%s).", bdaddr_str); - } - else - { - found_wiimotes.push_back(wm); - NOTICE_LOG(WIIMOTE, "Found Wiimote (%s).", bdaddr_str); - } - } - } - } + if (new_wiimote) + { + // Found a new device + char bdaddr_str[18] = {}; + ba2str(&scan_infos[i].bdaddr, bdaddr_str); + Wiimote* wm = new WiimoteLinux(scan_infos[i].bdaddr); + if (IsBalanceBoardName(name)) + { + found_board = wm; + NOTICE_LOG(WIIMOTE, "Found balance board (%s).", bdaddr_str); + } + else + { + found_wiimotes.push_back(wm); + NOTICE_LOG(WIIMOTE, "Found Wiimote (%s).", bdaddr_str); + } + } + } + } } WiimoteLinux::WiimoteLinux(bdaddr_t bdaddr) : Wiimote(), m_bdaddr(bdaddr) { - m_cmd_sock = -1; - m_int_sock = -1; + m_cmd_sock = -1; + m_int_sock = -1; - int fds[2]; - if (pipe(fds)) - { - ERROR_LOG(WIIMOTE, "pipe failed"); - abort(); - } - m_wakeup_pipe_w = fds[1]; - m_wakeup_pipe_r = fds[0]; + int fds[2]; + if (pipe(fds)) + { + ERROR_LOG(WIIMOTE, "pipe failed"); + abort(); + } + m_wakeup_pipe_w = fds[1]; + m_wakeup_pipe_r = fds[0]; } WiimoteLinux::~WiimoteLinux() { - Shutdown(); - close(m_wakeup_pipe_w); - close(m_wakeup_pipe_r); + Shutdown(); + close(m_wakeup_pipe_w); + close(m_wakeup_pipe_r); } // Connect to a Wiimote with a known address. bool WiimoteLinux::ConnectInternal() { - sockaddr_l2 addr = {}; - addr.l2_family = AF_BLUETOOTH; - addr.l2_bdaddr = m_bdaddr; - addr.l2_cid = 0; + sockaddr_l2 addr = {}; + addr.l2_family = AF_BLUETOOTH; + addr.l2_bdaddr = m_bdaddr; + addr.l2_cid = 0; - // Output channel - addr.l2_psm = htobs(WM_OUTPUT_CHANNEL); - if ((m_cmd_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 || - connect(m_cmd_sock, (sockaddr*)&addr, sizeof(addr)) < 0) - { - WARN_LOG(WIIMOTE, "Unable to open output socket to Wiimote: %s", strerror(errno)); - close(m_cmd_sock); - m_cmd_sock = -1; - return false; - } + // Output channel + addr.l2_psm = htobs(WM_OUTPUT_CHANNEL); + if ((m_cmd_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 || + connect(m_cmd_sock, (sockaddr*)&addr, sizeof(addr)) < 0) + { + WARN_LOG(WIIMOTE, "Unable to open output socket to Wiimote: %s", strerror(errno)); + close(m_cmd_sock); + m_cmd_sock = -1; + return false; + } - // Input channel - addr.l2_psm = htobs(WM_INPUT_CHANNEL); - if ((m_int_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 || - connect(m_int_sock, (sockaddr*)&addr, sizeof(addr)) < 0) - { - WARN_LOG(WIIMOTE, "Unable to open input socket from Wiimote: %s", strerror(errno)); - close(m_int_sock); - close(m_cmd_sock); - m_int_sock = m_cmd_sock = -1; - return false; - } + // Input channel + addr.l2_psm = htobs(WM_INPUT_CHANNEL); + if ((m_int_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 || + connect(m_int_sock, (sockaddr*)&addr, sizeof(addr)) < 0) + { + WARN_LOG(WIIMOTE, "Unable to open input socket from Wiimote: %s", strerror(errno)); + close(m_int_sock); + close(m_cmd_sock); + m_int_sock = m_cmd_sock = -1; + return false; + } - return true; + return true; } void WiimoteLinux::DisconnectInternal() { - close(m_cmd_sock); - close(m_int_sock); + close(m_cmd_sock); + close(m_int_sock); - m_cmd_sock = -1; - m_int_sock = -1; + m_cmd_sock = -1; + m_int_sock = -1; } bool WiimoteLinux::IsConnected() const { - return m_cmd_sock != -1;// && int_sock != -1; + return m_cmd_sock != -1; // && int_sock != -1; } void WiimoteLinux::IOWakeup() { - char c = 0; - if (write(m_wakeup_pipe_w, &c, 1) != 1) - { - ERROR_LOG(WIIMOTE, "Unable to write to wakeup pipe."); - } + char c = 0; + if (write(m_wakeup_pipe_w, &c, 1) != 1) + { + ERROR_LOG(WIIMOTE, "Unable to write to wakeup pipe."); + } } // positive = read packet @@ -229,55 +227,56 @@ void WiimoteLinux::IOWakeup() // zero = error int WiimoteLinux::IORead(u8* buf) { - // Block select for 1/2000th of a second + // Block select for 1/2000th of a second - fd_set fds; - FD_ZERO(&fds); - FD_SET(m_int_sock, &fds); - FD_SET(m_wakeup_pipe_r, &fds); + fd_set fds; + FD_ZERO(&fds); + FD_SET(m_int_sock, &fds); + FD_SET(m_wakeup_pipe_r, &fds); - if (select(m_int_sock + 1, &fds, nullptr, nullptr, nullptr) == -1) - { - ERROR_LOG(WIIMOTE, "Unable to select Wiimote %i input socket.", m_index + 1); - return -1; - } + if (select(m_int_sock + 1, &fds, nullptr, nullptr, nullptr) == -1) + { + ERROR_LOG(WIIMOTE, "Unable to select Wiimote %i input socket.", m_index + 1); + return -1; + } - if (FD_ISSET(m_wakeup_pipe_r, &fds)) - { - char c; - if (read(m_wakeup_pipe_r, &c, 1) != 1) - { - ERROR_LOG(WIIMOTE, "Unable to read from wakeup pipe."); - } - return -1; - } + if (FD_ISSET(m_wakeup_pipe_r, &fds)) + { + char c; + if (read(m_wakeup_pipe_r, &c, 1) != 1) + { + ERROR_LOG(WIIMOTE, "Unable to read from wakeup pipe."); + } + return -1; + } - if (!FD_ISSET(m_int_sock, &fds)) - return -1; + if (!FD_ISSET(m_int_sock, &fds)) + return -1; - // Read the pending message into the buffer - int r = read(m_int_sock, buf, MAX_PAYLOAD); - if (r == -1) - { - // Error reading data - ERROR_LOG(WIIMOTE, "Receiving data from Wiimote %i.", m_index + 1); + // Read the pending message into the buffer + int r = read(m_int_sock, buf, MAX_PAYLOAD); + if (r == -1) + { + // Error reading data + ERROR_LOG(WIIMOTE, "Receiving data from Wiimote %i.", m_index + 1); - if (errno == ENOTCONN) - { - // This can happen if the Bluetooth dongle is disconnected - ERROR_LOG(WIIMOTE, "Bluetooth appears to be disconnected. " - "Wiimote %i will be disconnected.", m_index + 1); - } + if (errno == ENOTCONN) + { + // This can happen if the Bluetooth dongle is disconnected + ERROR_LOG(WIIMOTE, "Bluetooth appears to be disconnected. " + "Wiimote %i will be disconnected.", + m_index + 1); + } - r = 0; - } + r = 0; + } - return r; + return r; } int WiimoteLinux::IOWrite(u8 const* buf, size_t len) { - return write(m_int_sock, buf, (int)len); + return write(m_int_sock, buf, (int)len); } -}; // WiimoteReal +}; // WiimoteReal diff --git a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp index 39a0e3835c..bf0c70a906 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp @@ -11,19 +11,19 @@ #include #include // The following Windows headers must be included AFTER windows.h. -#include //NOLINT -#include //NOLINT +#include //NOLINT +#include //NOLINT // initguid.h must be included before Devpkey.h -#include //NOLINT -#include //NOLINT -#include //NOLINT -#include //NOLINT +#include //NOLINT +#include //NOLINT +#include //NOLINT +#include //NOLINT #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "Common/Thread.h" -#include "Common/Logging/Log.h" #include "Core/HW/WiimoteEmu/WiimoteHid.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" @@ -32,9 +32,9 @@ // Create func_t function pointer type and declare a nullptr-initialized static variable of that // type named "pfunc". -#define DYN_FUNC_DECLARE(func) \ - typedef decltype(&func) func ## _t; \ - static func ## _t p ## func = nullptr; +#define DYN_FUNC_DECLARE(func) \ + typedef decltype(&func) func##_t; \ + static func##_t p##func = nullptr; DYN_FUNC_DECLARE(HidD_GetHidGuid); DYN_FUNC_DECLARE(HidD_GetAttributes); @@ -67,103 +67,100 @@ std::unordered_set> g_connected_wiimotes; std::mutex g_connected_wiimotes_lock; #endif -#define DYN_FUNC_UNLOAD(func) \ - p ## func = nullptr; +#define DYN_FUNC_UNLOAD(func) p##func = nullptr; // Attempt to load the function from the given module handle. -#define DYN_FUNC_LOAD(module, func) \ - p ## func = ( func ## _t)::GetProcAddress(module, # func ); \ - if (! p ## func ) \ - { \ - return false; \ - } +#define DYN_FUNC_LOAD(module, func) \ + p##func = (func##_t)::GetProcAddress(module, #func); \ + if (!p##func) \ + { \ + return false; \ + } bool load_hid() { - auto loader = [&]() - { - s_hid_lib = ::LoadLibrary(_T("hid.dll")); - if (!s_hid_lib) - { - return false; - } + auto loader = [&]() { + s_hid_lib = ::LoadLibrary(_T("hid.dll")); + if (!s_hid_lib) + { + return false; + } - DYN_FUNC_LOAD(s_hid_lib, HidD_GetHidGuid); - DYN_FUNC_LOAD(s_hid_lib, HidD_GetAttributes); - DYN_FUNC_LOAD(s_hid_lib, HidD_SetOutputReport); - DYN_FUNC_LOAD(s_hid_lib, HidD_GetProductString); + DYN_FUNC_LOAD(s_hid_lib, HidD_GetHidGuid); + DYN_FUNC_LOAD(s_hid_lib, HidD_GetAttributes); + DYN_FUNC_LOAD(s_hid_lib, HidD_SetOutputReport); + DYN_FUNC_LOAD(s_hid_lib, HidD_GetProductString); - return true; - }; + return true; + }; - bool loaded_ok = loader(); + bool loaded_ok = loader(); - if (!loaded_ok) - { - DYN_FUNC_UNLOAD(HidD_GetHidGuid); - DYN_FUNC_UNLOAD(HidD_GetAttributes); - DYN_FUNC_UNLOAD(HidD_SetOutputReport); - DYN_FUNC_UNLOAD(HidD_GetProductString); + if (!loaded_ok) + { + DYN_FUNC_UNLOAD(HidD_GetHidGuid); + DYN_FUNC_UNLOAD(HidD_GetAttributes); + DYN_FUNC_UNLOAD(HidD_SetOutputReport); + DYN_FUNC_UNLOAD(HidD_GetProductString); - if (s_hid_lib) - { - ::FreeLibrary(s_hid_lib); - s_hid_lib = nullptr; - } - } + if (s_hid_lib) + { + ::FreeLibrary(s_hid_lib); + s_hid_lib = nullptr; + } + } - return loaded_ok; + return loaded_ok; } bool load_bthprops() { - auto loader = [&]() - { - s_bthprops_lib = ::LoadLibrary(_T("bthprops.cpl")); - if (!s_bthprops_lib) - { - return false; - } + auto loader = [&]() { + s_bthprops_lib = ::LoadLibrary(_T("bthprops.cpl")); + if (!s_bthprops_lib) + { + return false; + } - DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindDeviceClose); - DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindFirstDevice); - DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindFirstRadio); - DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindNextDevice); - DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindNextRadio); - DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindRadioClose); - DYN_FUNC_LOAD(s_bthprops_lib, BluetoothGetRadioInfo); - DYN_FUNC_LOAD(s_bthprops_lib, BluetoothRemoveDevice); - DYN_FUNC_LOAD(s_bthprops_lib, BluetoothSetServiceState); - DYN_FUNC_LOAD(s_bthprops_lib, BluetoothAuthenticateDeviceEx); - DYN_FUNC_LOAD(s_bthprops_lib, BluetoothEnumerateInstalledServices); + DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindDeviceClose); + DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindFirstDevice); + DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindFirstRadio); + DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindNextDevice); + DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindNextRadio); + DYN_FUNC_LOAD(s_bthprops_lib, BluetoothFindRadioClose); + DYN_FUNC_LOAD(s_bthprops_lib, BluetoothGetRadioInfo); + DYN_FUNC_LOAD(s_bthprops_lib, BluetoothRemoveDevice); + DYN_FUNC_LOAD(s_bthprops_lib, BluetoothSetServiceState); + DYN_FUNC_LOAD(s_bthprops_lib, BluetoothAuthenticateDeviceEx); + DYN_FUNC_LOAD(s_bthprops_lib, BluetoothEnumerateInstalledServices); - return true; - }; + return true; + }; - bool loaded_ok = loader(); + bool loaded_ok = loader(); - if (!loaded_ok) - { - DYN_FUNC_UNLOAD(BluetoothFindDeviceClose); - DYN_FUNC_UNLOAD(BluetoothFindFirstDevice); - DYN_FUNC_UNLOAD(BluetoothFindFirstRadio); - DYN_FUNC_UNLOAD(BluetoothFindNextDevice); - DYN_FUNC_UNLOAD(BluetoothFindNextRadio); - DYN_FUNC_UNLOAD(BluetoothFindRadioClose); - DYN_FUNC_UNLOAD(BluetoothGetRadioInfo); - DYN_FUNC_UNLOAD(BluetoothRemoveDevice); - DYN_FUNC_UNLOAD(BluetoothSetServiceState); - DYN_FUNC_UNLOAD(BluetoothAuthenticateDeviceEx); - DYN_FUNC_UNLOAD(BluetoothEnumerateInstalledServices); + if (!loaded_ok) + { + DYN_FUNC_UNLOAD(BluetoothFindDeviceClose); + DYN_FUNC_UNLOAD(BluetoothFindFirstDevice); + DYN_FUNC_UNLOAD(BluetoothFindFirstRadio); + DYN_FUNC_UNLOAD(BluetoothFindNextDevice); + DYN_FUNC_UNLOAD(BluetoothFindNextRadio); + DYN_FUNC_UNLOAD(BluetoothFindRadioClose); + DYN_FUNC_UNLOAD(BluetoothGetRadioInfo); + DYN_FUNC_UNLOAD(BluetoothRemoveDevice); + DYN_FUNC_UNLOAD(BluetoothSetServiceState); + DYN_FUNC_UNLOAD(BluetoothAuthenticateDeviceEx); + DYN_FUNC_UNLOAD(BluetoothEnumerateInstalledServices); - if (s_bthprops_lib) - { - ::FreeLibrary(s_bthprops_lib); - s_bthprops_lib = nullptr; - } - } + if (s_bthprops_lib) + { + ::FreeLibrary(s_bthprops_lib); + s_bthprops_lib = nullptr; + } + } - return loaded_ok; + return loaded_ok; } #undef DYN_FUNC_LOAD @@ -171,53 +168,52 @@ bool load_bthprops() inline void init_lib() { - static bool initialized = false; + static bool initialized = false; - if (!initialized) - { - // Only try once - initialized = true; + if (!initialized) + { + // Only try once + initialized = true; - // After these calls, we know all dynamically loaded APIs will either all be valid or - // all nullptr. - if (!load_hid() || !load_bthprops()) - { - NOTICE_LOG(WIIMOTE, - "Failed to load Bluetooth support libraries, Wiimotes will not function"); - return; - } + // After these calls, we know all dynamically loaded APIs will either all be valid or + // all nullptr. + if (!load_hid() || !load_bthprops()) + { + NOTICE_LOG(WIIMOTE, "Failed to load Bluetooth support libraries, Wiimotes will not function"); + return; + } - s_loaded_ok = true; - } + s_loaded_ok = true; + } } namespace WiimoteReal { - class WiimoteWindows final : public Wiimote { public: - WiimoteWindows(const std::basic_string& path, WinWriteMethod initial_write_method); - ~WiimoteWindows() override; + WiimoteWindows(const std::basic_string& path, WinWriteMethod initial_write_method); + ~WiimoteWindows() override; protected: - bool ConnectInternal() override; - void DisconnectInternal() override; - bool IsConnected() const override; - void IOWakeup() override; - int IORead(u8* buf) override; - int IOWrite(u8 const* buf, size_t len) override; + bool ConnectInternal() override; + void DisconnectInternal() override; + bool IsConnected() const override; + void IOWakeup() override; + int IORead(u8* buf) override; + int IOWrite(u8 const* buf, size_t len) override; private: - std::basic_string m_devicepath; // Unique Wiimote reference - HANDLE m_dev_handle; // HID handle - OVERLAPPED m_hid_overlap_read; // Overlap handles - OVERLAPPED m_hid_overlap_write; - WinWriteMethod m_write_method; // Type of Write Method to use + std::basic_string m_devicepath; // Unique Wiimote reference + HANDLE m_dev_handle; // HID handle + OVERLAPPED m_hid_overlap_read; // Overlap handles + OVERLAPPED m_hid_overlap_write; + WinWriteMethod m_write_method; // Type of Write Method to use }; -int IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum WinWriteMethod &stack, const u8* buf, size_t len, DWORD* written); -int IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index); +int IOWrite(HANDLE& dev_handle, OVERLAPPED& hid_overlap_write, enum WinWriteMethod& stack, + const u8* buf, size_t len, DWORD* written); +int IORead(HANDLE& dev_handle, OVERLAPPED& hid_overlap_read, u8* buf, int index); template void ProcessWiimotes(bool new_scan, T& callback); @@ -228,12 +224,12 @@ bool ForgetWiimote(BLUETOOTH_DEVICE_INFO_STRUCT&); WiimoteScanner::WiimoteScanner() { - init_lib(); + init_lib(); } WiimoteScanner::~WiimoteScanner() { - // TODO: what do we want here? +// TODO: what do we want here? #if 0 ProcessWiimotes(false, [](HANDLE, BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_INFO_STRUCT& btdi) { @@ -244,415 +240,423 @@ WiimoteScanner::~WiimoteScanner() void WiimoteScanner::Update() { - if (!s_loaded_ok) - return; + if (!s_loaded_ok) + return; - bool forgot_some = false; + bool forgot_some = false; - ProcessWiimotes(false, [&](HANDLE, BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_INFO_STRUCT& btdi) - { - forgot_some |= ForgetWiimote(btdi); - }); + ProcessWiimotes(false, [&](HANDLE, BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_INFO_STRUCT& btdi) { + forgot_some |= ForgetWiimote(btdi); + }); - // Some hacks that allows disconnects to be detected before connections are handled - // workaround for Wiimote 1 moving to slot 2 on temporary disconnect - if (forgot_some) - Common::SleepCurrentThread(100); + // Some hacks that allows disconnects to be detected before connections are handled + // workaround for Wiimote 1 moving to slot 2 on temporary disconnect + if (forgot_some) + Common::SleepCurrentThread(100); } -// Moves up one node in the device tree and returns its device info data along with an info set only including that device for further processing +// Moves up one node in the device tree and returns its device info data along with an info set only +// including that device for further processing // See https://msdn.microsoft.com/en-us/library/windows/hardware/ff549417(v=vs.85).aspx -static bool GetParentDevice(const DEVINST &child_device_instance, HDEVINFO *parent_device_info, PSP_DEVINFO_DATA parent_device_data) +static bool GetParentDevice(const DEVINST& child_device_instance, HDEVINFO* parent_device_info, + PSP_DEVINFO_DATA parent_device_data) { - ULONG status; - ULONG problem_number; - CONFIGRET result; + ULONG status; + ULONG problem_number; + CONFIGRET result; - // Check if that device instance has device node present - result = CM_Get_DevNode_Status(&status, &problem_number, child_device_instance, 0); - if (result != CR_SUCCESS) - { - return false; - } + // Check if that device instance has device node present + result = CM_Get_DevNode_Status(&status, &problem_number, child_device_instance, 0); + if (result != CR_SUCCESS) + { + return false; + } - DEVINST parent_device; + DEVINST parent_device; - // Get the device instance of the parent - result = CM_Get_Parent(&parent_device, child_device_instance, 0); - if (result != CR_SUCCESS) - { - return false; - } + // Get the device instance of the parent + result = CM_Get_Parent(&parent_device, child_device_instance, 0); + if (result != CR_SUCCESS) + { + return false; + } - std::vector parent_device_id(MAX_DEVICE_ID_LEN);; + std::vector parent_device_id(MAX_DEVICE_ID_LEN); + ; - // Get the device id of the parent, required to open the device info - result = CM_Get_Device_ID(parent_device, parent_device_id.data(), (ULONG)parent_device_id.size(), 0); - if (result != CR_SUCCESS) - { - return false; - } + // Get the device id of the parent, required to open the device info + result = + CM_Get_Device_ID(parent_device, parent_device_id.data(), (ULONG)parent_device_id.size(), 0); + if (result != CR_SUCCESS) + { + return false; + } - // Create a new empty device info set for the device info data - (*parent_device_info) = SetupDiCreateDeviceInfoList(nullptr, nullptr); + // Create a new empty device info set for the device info data + (*parent_device_info) = SetupDiCreateDeviceInfoList(nullptr, nullptr); - // Open the device info data of the parent and put it in the emtpy info set - if (!SetupDiOpenDeviceInfo((*parent_device_info), parent_device_id.data(), nullptr, 0, parent_device_data)) - { - SetupDiDestroyDeviceInfoList(parent_device_info); - return false; - } + // Open the device info data of the parent and put it in the emtpy info set + if (!SetupDiOpenDeviceInfo((*parent_device_info), parent_device_id.data(), nullptr, 0, + parent_device_data)) + { + SetupDiDestroyDeviceInfoList(parent_device_info); + return false; + } - return true; + return true; } -std::wstring GetDeviceProperty(const HDEVINFO &device_info, const PSP_DEVINFO_DATA device_data, const DEVPROPKEY *requested_property) +std::wstring GetDeviceProperty(const HDEVINFO& device_info, const PSP_DEVINFO_DATA device_data, + const DEVPROPKEY* requested_property) { - DWORD required_size = 0; - DEVPROPTYPE device_property_type; + DWORD required_size = 0; + DEVPROPTYPE device_property_type; - SetupDiGetDeviceProperty(device_info, device_data, requested_property, &device_property_type, nullptr, 0, &required_size, 0); + SetupDiGetDeviceProperty(device_info, device_data, requested_property, &device_property_type, + nullptr, 0, &required_size, 0); - std::vector unicode_buffer(required_size, 0); + std::vector unicode_buffer(required_size, 0); - BOOL result = SetupDiGetDeviceProperty(device_info, device_data, requested_property, &device_property_type, unicode_buffer.data(), required_size, nullptr, 0); - if (!result) - { - return std::wstring(); - } + BOOL result = + SetupDiGetDeviceProperty(device_info, device_data, requested_property, &device_property_type, + unicode_buffer.data(), required_size, nullptr, 0); + if (!result) + { + return std::wstring(); + } - return std::wstring((PWCHAR)unicode_buffer.data()); + return std::wstring((PWCHAR)unicode_buffer.data()); } -// The enumerated device nodes/instances are "empty" PDO's that act as interfaces for the HID Class Driver. -// Since those PDO's normaly don't have a FDO and therefore no driver loaded, we need to move one device node up in the device tree. -// Then check the provider of the device driver, which will be "Microsoft" in case of the default HID Class Driver +// The enumerated device nodes/instances are "empty" PDO's that act as interfaces for the HID Class +// Driver. +// Since those PDO's normaly don't have a FDO and therefore no driver loaded, we need to move one +// device node up in the device tree. +// Then check the provider of the device driver, which will be "Microsoft" in case of the default +// HID Class Driver // or "TOSHIBA" in case of the Toshiba Bluetooth Stack, because it provides its own Class Driver. -static bool CheckForToshibaStack(const DEVINST &hid_interface_device_instance) +static bool CheckForToshibaStack(const DEVINST& hid_interface_device_instance) { - HDEVINFO parent_device_info = nullptr; - SP_DEVINFO_DATA parent_device_data = {}; - parent_device_data.cbSize = sizeof(SP_DEVINFO_DATA); + HDEVINFO parent_device_info = nullptr; + SP_DEVINFO_DATA parent_device_data = {}; + parent_device_data.cbSize = sizeof(SP_DEVINFO_DATA); - if (GetParentDevice(hid_interface_device_instance, &parent_device_info, &parent_device_data)) - { - std::wstring class_driver_provider = GetDeviceProperty(parent_device_info, &parent_device_data, &DEVPKEY_Device_DriverProvider); + if (GetParentDevice(hid_interface_device_instance, &parent_device_info, &parent_device_data)) + { + std::wstring class_driver_provider = + GetDeviceProperty(parent_device_info, &parent_device_data, &DEVPKEY_Device_DriverProvider); - SetupDiDestroyDeviceInfoList(parent_device_info); + SetupDiDestroyDeviceInfoList(parent_device_info); - return (class_driver_provider == L"TOSHIBA"); - } + return (class_driver_provider == L"TOSHIBA"); + } - DEBUG_LOG(WIIMOTE, "Unable to detect class driver provider!"); + DEBUG_LOG(WIIMOTE, "Unable to detect class driver provider!"); - return false; + return false; } static WinWriteMethod GetInitialWriteMethod(bool IsUsingToshibaStack) { - // Currently Toshiba Bluetooth Stack needs the Output buffer to be the size of the largest output report - return (IsUsingToshibaStack ? WWM_WRITE_FILE_LARGEST_REPORT_SIZE : WWM_WRITE_FILE_ACTUAL_REPORT_SIZE); + // Currently Toshiba Bluetooth Stack needs the Output buffer to be the size of the largest output + // report + return (IsUsingToshibaStack ? WWM_WRITE_FILE_LARGEST_REPORT_SIZE : + WWM_WRITE_FILE_ACTUAL_REPORT_SIZE); } // Find and connect Wiimotes. // Does not replace already found Wiimotes even if they are disconnected. // wm is an array of max_wiimotes Wiimotes // Returns the total number of found and connected Wiimotes. -void WiimoteScanner::FindWiimotes(std::vector & found_wiimotes, Wiimote* & found_board) +void WiimoteScanner::FindWiimotes(std::vector& found_wiimotes, Wiimote*& found_board) { - if (!s_loaded_ok) - return; + if (!s_loaded_ok) + return; - ProcessWiimotes(true, [](HANDLE hRadio, const BLUETOOTH_RADIO_INFO& rinfo, BLUETOOTH_DEVICE_INFO_STRUCT& btdi) - { - ForgetWiimote(btdi); - AttachWiimote(hRadio, rinfo, btdi); - }); + ProcessWiimotes(true, [](HANDLE hRadio, const BLUETOOTH_RADIO_INFO& rinfo, + BLUETOOTH_DEVICE_INFO_STRUCT& btdi) { + ForgetWiimote(btdi); + AttachWiimote(hRadio, rinfo, btdi); + }); - // Get the device id - GUID device_id; - pHidD_GetHidGuid(&device_id); + // Get the device id + GUID device_id; + pHidD_GetHidGuid(&device_id); - // Get all hid devices connected - HDEVINFO const device_info = SetupDiGetClassDevs(&device_id, nullptr, nullptr, (DIGCF_DEVICEINTERFACE | DIGCF_PRESENT)); + // Get all hid devices connected + HDEVINFO const device_info = + SetupDiGetClassDevs(&device_id, nullptr, nullptr, (DIGCF_DEVICEINTERFACE | DIGCF_PRESENT)); - SP_DEVICE_INTERFACE_DATA device_data = {}; - device_data.cbSize = sizeof(device_data); - PSP_DEVICE_INTERFACE_DETAIL_DATA detail_data = nullptr; + SP_DEVICE_INTERFACE_DATA device_data = {}; + device_data.cbSize = sizeof(device_data); + PSP_DEVICE_INTERFACE_DETAIL_DATA detail_data = nullptr; - for (int index = 0; SetupDiEnumDeviceInterfaces(device_info, nullptr, &device_id, index, &device_data); ++index) - { - // Get the size of the data block required - DWORD len; - SetupDiGetDeviceInterfaceDetail(device_info, &device_data, nullptr, 0, &len, nullptr); - detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(len); - detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + for (int index = 0; + SetupDiEnumDeviceInterfaces(device_info, nullptr, &device_id, index, &device_data); ++index) + { + // Get the size of the data block required + DWORD len; + SetupDiGetDeviceInterfaceDetail(device_info, &device_data, nullptr, 0, &len, nullptr); + detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(len); + detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); - SP_DEVINFO_DATA device_info_data = {}; - device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); + SP_DEVINFO_DATA device_info_data = {}; + device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); - // Query the data for this device - if (SetupDiGetDeviceInterfaceDetail(device_info, &device_data, detail_data, len, nullptr, &device_info_data)) - { - std::basic_string device_path(detail_data->DevicePath); - bool real_wiimote = false; - bool is_bb = false; - bool IsUsingToshibaStack = CheckForToshibaStack(device_info_data.DevInst); + // Query the data for this device + if (SetupDiGetDeviceInterfaceDetail(device_info, &device_data, detail_data, len, nullptr, + &device_info_data)) + { + std::basic_string device_path(detail_data->DevicePath); + bool real_wiimote = false; + bool is_bb = false; + bool IsUsingToshibaStack = CheckForToshibaStack(device_info_data.DevInst); - WinWriteMethod write_method = GetInitialWriteMethod(IsUsingToshibaStack); + WinWriteMethod write_method = GetInitialWriteMethod(IsUsingToshibaStack); - CheckDeviceType(device_path, write_method, real_wiimote, is_bb); + CheckDeviceType(device_path, write_method, real_wiimote, is_bb); - if (real_wiimote) - { - Wiimote* wm = new WiimoteWindows(device_path, write_method); + if (real_wiimote) + { + Wiimote* wm = new WiimoteWindows(device_path, write_method); - if (is_bb) - { - found_board = wm; - } - else - { - found_wiimotes.push_back(wm); - } - } - } + if (is_bb) + { + found_board = wm; + } + else + { + found_wiimotes.push_back(wm); + } + } + } - free(detail_data); - } + free(detail_data); + } - SetupDiDestroyDeviceInfoList(device_info); + SetupDiDestroyDeviceInfoList(device_info); } -int CheckDeviceType_Write(HANDLE &dev_handle, WinWriteMethod &write_method, const u8* buf, size_t size, int attempts) +int CheckDeviceType_Write(HANDLE& dev_handle, WinWriteMethod& write_method, const u8* buf, + size_t size, int attempts) { - OVERLAPPED hid_overlap_write = OVERLAPPED(); - hid_overlap_write.hEvent = CreateEvent(nullptr, true, false, nullptr); + OVERLAPPED hid_overlap_write = OVERLAPPED(); + hid_overlap_write.hEvent = CreateEvent(nullptr, true, false, nullptr); - DWORD written = 0; + DWORD written = 0; - for (; attempts>0; --attempts) - { - if (IOWrite(dev_handle, hid_overlap_write, write_method, buf, size, &written)) - break; - } + for (; attempts > 0; --attempts) + { + if (IOWrite(dev_handle, hid_overlap_write, write_method, buf, size, &written)) + break; + } - CloseHandle(hid_overlap_write.hEvent); + CloseHandle(hid_overlap_write.hEvent); - return written; + return written; } -int CheckDeviceType_Read(HANDLE &dev_handle, u8* buf, int attempts) +int CheckDeviceType_Read(HANDLE& dev_handle, u8* buf, int attempts) { - OVERLAPPED hid_overlap_read = OVERLAPPED(); - hid_overlap_read.hEvent = CreateEvent(nullptr, true, false, nullptr); - int read = 0; - for (; attempts>0; --attempts) - { - read = IORead(dev_handle, hid_overlap_read, buf, 1); - if (read > 0) - break; - } + OVERLAPPED hid_overlap_read = OVERLAPPED(); + hid_overlap_read.hEvent = CreateEvent(nullptr, true, false, nullptr); + int read = 0; + for (; attempts > 0; --attempts) + { + read = IORead(dev_handle, hid_overlap_read, buf, 1); + if (read > 0) + break; + } - CloseHandle(hid_overlap_read.hEvent); + CloseHandle(hid_overlap_read.hEvent); - return read; + return read; } -// A convoluted way of checking if a device is a Wii Balance Board and if it is a connectible Wiimote. +// A convoluted way of checking if a device is a Wii Balance Board and if it is a connectible +// Wiimote. // Because nothing on Windows should be easy. // (We can't seem to easily identify the Bluetooth device an HID device belongs to...) -void WiimoteScanner::CheckDeviceType(std::basic_string &devicepath, WinWriteMethod &write_method, bool &real_wiimote, bool &is_bb) +void WiimoteScanner::CheckDeviceType(std::basic_string& devicepath, + WinWriteMethod& write_method, bool& real_wiimote, bool& is_bb) { - real_wiimote = false; - is_bb = false; + real_wiimote = false; + is_bb = false; #ifdef SHARE_WRITE_WIIMOTES - std::lock_guard lk(g_connected_wiimotes_lock); - if (g_connected_wiimotes.count(devicepath) != 0) - return; + std::lock_guard lk(g_connected_wiimotes_lock); + if (g_connected_wiimotes.count(devicepath) != 0) + return; #endif - HANDLE dev_handle = CreateFile(devicepath.c_str(), - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, - nullptr); - if (dev_handle == INVALID_HANDLE_VALUE) - return; - // enable to only check for official nintendo wiimotes/bb's - bool check_vidpid = false; - HIDD_ATTRIBUTES attrib; - attrib.Size = sizeof(attrib); - if (!check_vidpid || - (pHidD_GetAttributes(dev_handle, &attrib) && - (attrib.VendorID == 0x057e) && - (attrib.ProductID == 0x0306))) - { - // max_cycles insures we are never stuck here due to bad coding... - int max_cycles = 20; - u8 buf[MAX_PAYLOAD] = {0}; + HANDLE dev_handle = CreateFile(devicepath.c_str(), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, nullptr); + if (dev_handle == INVALID_HANDLE_VALUE) + return; + // enable to only check for official nintendo wiimotes/bb's + bool check_vidpid = false; + HIDD_ATTRIBUTES attrib; + attrib.Size = sizeof(attrib); + if (!check_vidpid || (pHidD_GetAttributes(dev_handle, &attrib) && (attrib.VendorID == 0x057e) && + (attrib.ProductID == 0x0306))) + { + // max_cycles insures we are never stuck here due to bad coding... + int max_cycles = 20; + u8 buf[MAX_PAYLOAD] = {0}; - u8 const req_status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0}; - // The new way to initialize the extension is by writing 0x55 to 0x(4)A400F0, then writing 0x00 to 0x(4)A400FB - // 52 16 04 A4 00 F0 01 55 - // 52 16 04 A4 00 FB 01 00 - u8 const disable_enc_pt1_report[MAX_PAYLOAD] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_WRITE_DATA, 0x04, 0xa4, 0x00, 0xf0, 0x01, 0x55}; - u8 const disable_enc_pt2_report[MAX_PAYLOAD] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_WRITE_DATA, 0x04, 0xa4, 0x00, 0xfb, 0x01, 0x00}; + u8 const req_status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0}; + // The new way to initialize the extension is by writing 0x55 to 0x(4)A400F0, then writing 0x00 + // to 0x(4)A400FB + // 52 16 04 A4 00 F0 01 55 + // 52 16 04 A4 00 FB 01 00 + u8 const disable_enc_pt1_report[MAX_PAYLOAD] = { + WM_SET_REPORT | WM_BT_OUTPUT, WM_WRITE_DATA, 0x04, 0xa4, 0x00, 0xf0, 0x01, 0x55}; + u8 const disable_enc_pt2_report[MAX_PAYLOAD] = { + WM_SET_REPORT | WM_BT_OUTPUT, WM_WRITE_DATA, 0x04, 0xa4, 0x00, 0xfb, 0x01, 0x00}; - CheckDeviceType_Write(dev_handle, - write_method, - disable_enc_pt1_report, - sizeof(disable_enc_pt1_report), - 1); - CheckDeviceType_Write(dev_handle, - write_method, - disable_enc_pt2_report, - sizeof(disable_enc_pt2_report), - 1); + CheckDeviceType_Write(dev_handle, write_method, disable_enc_pt1_report, + sizeof(disable_enc_pt1_report), 1); + CheckDeviceType_Write(dev_handle, write_method, disable_enc_pt2_report, + sizeof(disable_enc_pt2_report), 1); - int rc = CheckDeviceType_Write(dev_handle, - write_method, - req_status_report, - sizeof(req_status_report), - 1); + int rc = CheckDeviceType_Write(dev_handle, write_method, req_status_report, + sizeof(req_status_report), 1); - while (rc > 0 && --max_cycles > 0) - { - if ((rc = CheckDeviceType_Read(dev_handle, buf, 1)) <= 0) - { - // DEBUG_LOG(WIIMOTE, "CheckDeviceType: Read failed..."); - break; - } + while (rc > 0 && --max_cycles > 0) + { + if ((rc = CheckDeviceType_Read(dev_handle, buf, 1)) <= 0) + { + // DEBUG_LOG(WIIMOTE, "CheckDeviceType: Read failed..."); + break; + } - switch (buf[1]) - { - case WM_STATUS_REPORT: - { - real_wiimote = true; + switch (buf[1]) + { + case WM_STATUS_REPORT: + { + real_wiimote = true; - // DEBUG_LOG(WIIMOTE, "CheckDeviceType: Got Status Report"); - wm_status_report * wsr = (wm_status_report*)&buf[2]; - if (wsr->extension) - { - // Wiimote with extension, we ask it what kind. - u8 read_ext[MAX_PAYLOAD] = {0}; - read_ext[0] = WM_SET_REPORT | WM_BT_OUTPUT; - read_ext[1] = WM_READ_DATA; - // Extension type register. - *(u32*)&read_ext[2] = Common::swap32(0x4a400fa); - // Size. - *(u16*)&read_ext[6] = Common::swap16(6); - rc = CheckDeviceType_Write(dev_handle, write_method, read_ext, 8, 1); - } - else - { - // Normal Wiimote, exit while and be happy. - rc = -1; - } - break; - } - case WM_ACK_DATA: - { - real_wiimote = true; - //wm_acknowledge * wm = (wm_acknowledge*)&buf[2]; - //DEBUG_LOG(WIIMOTE, "CheckDeviceType: Got Ack Error: %X ReportID: %X", wm->errorID, wm->reportID); - break; - } - case WM_READ_DATA_REPLY: - { - // DEBUG_LOG(WIIMOTE, "CheckDeviceType: Got Data Reply"); - wm_read_data_reply * wrdr - = (wm_read_data_reply*)&buf[2]; - // Check if it has returned what we asked. - if (Common::swap16(wrdr->address) == 0x00fa) - { - real_wiimote = true; - // 0x020420A40000ULL means balance board. - u64 ext_type = (*(u64*)&wrdr->data[0]); - // DEBUG_LOG(WIIMOTE, - // "CheckDeviceType: GOT EXT TYPE %llX", - // ext_type); - is_bb = (ext_type == 0x020420A40000ULL); - } - else - { - ERROR_LOG(WIIMOTE, - "CheckDeviceType: GOT UNREQUESTED ADDRESS %X", - Common::swap16(wrdr->address)); - } - // force end - rc = -1; + // DEBUG_LOG(WIIMOTE, "CheckDeviceType: Got Status Report"); + wm_status_report* wsr = (wm_status_report*)&buf[2]; + if (wsr->extension) + { + // Wiimote with extension, we ask it what kind. + u8 read_ext[MAX_PAYLOAD] = {0}; + read_ext[0] = WM_SET_REPORT | WM_BT_OUTPUT; + read_ext[1] = WM_READ_DATA; + // Extension type register. + *(u32*)&read_ext[2] = Common::swap32(0x4a400fa); + // Size. + *(u16*)&read_ext[6] = Common::swap16(6); + rc = CheckDeviceType_Write(dev_handle, write_method, read_ext, 8, 1); + } + else + { + // Normal Wiimote, exit while and be happy. + rc = -1; + } + break; + } + case WM_ACK_DATA: + { + real_wiimote = true; + // wm_acknowledge * wm = (wm_acknowledge*)&buf[2]; + // DEBUG_LOG(WIIMOTE, "CheckDeviceType: Got Ack Error: %X ReportID: %X", wm->errorID, + // wm->reportID); + break; + } + case WM_READ_DATA_REPLY: + { + // DEBUG_LOG(WIIMOTE, "CheckDeviceType: Got Data Reply"); + wm_read_data_reply* wrdr = (wm_read_data_reply*)&buf[2]; + // Check if it has returned what we asked. + if (Common::swap16(wrdr->address) == 0x00fa) + { + real_wiimote = true; + // 0x020420A40000ULL means balance board. + u64 ext_type = (*(u64*)&wrdr->data[0]); + // DEBUG_LOG(WIIMOTE, + // "CheckDeviceType: GOT EXT TYPE %llX", + // ext_type); + is_bb = (ext_type == 0x020420A40000ULL); + } + else + { + ERROR_LOG(WIIMOTE, "CheckDeviceType: GOT UNREQUESTED ADDRESS %X", + Common::swap16(wrdr->address)); + } + // force end + rc = -1; - break; - } - default: - { - // We let read try again incase there is another packet waiting. - // DEBUG_LOG(WIIMOTE, "CheckDeviceType: GOT UNKNOWN REPLY: %X", buf[1]); - break; - } - } - } - } - CloseHandle(dev_handle); + break; + } + default: + { + // We let read try again incase there is another packet waiting. + // DEBUG_LOG(WIIMOTE, "CheckDeviceType: GOT UNKNOWN REPLY: %X", buf[1]); + break; + } + } + } + } + CloseHandle(dev_handle); } bool WiimoteScanner::IsReady() const { - if (!s_loaded_ok) - { - return false; - } + if (!s_loaded_ok) + { + return false; + } - // TODO: don't search for a radio each time + // TODO: don't search for a radio each time - BLUETOOTH_FIND_RADIO_PARAMS radioParam; - radioParam.dwSize = sizeof(radioParam); + BLUETOOTH_FIND_RADIO_PARAMS radioParam; + radioParam.dwSize = sizeof(radioParam); - HANDLE hRadio; - HBLUETOOTH_RADIO_FIND hFindRadio = pBluetoothFindFirstRadio(&radioParam, &hRadio); + HANDLE hRadio; + HBLUETOOTH_RADIO_FIND hFindRadio = pBluetoothFindFirstRadio(&radioParam, &hRadio); - if (nullptr != hFindRadio) - { - pBluetoothFindRadioClose(hFindRadio); - return true; - } - else - { - return false; - } + if (nullptr != hFindRadio) + { + pBluetoothFindRadioClose(hFindRadio); + return true; + } + else + { + return false; + } } // Connect to a Wiimote with a known device path. bool WiimoteWindows::ConnectInternal() { - if (IsConnected()) - return false; + if (IsConnected()) + return false; #ifdef SHARE_WRITE_WIIMOTES - std::lock_guard lk(g_connected_wiimotes_lock); - if (g_connected_wiimotes.count(m_devicepath) != 0) - return false; + std::lock_guard lk(g_connected_wiimotes_lock); + if (g_connected_wiimotes.count(m_devicepath) != 0) + return false; - auto const open_flags = FILE_SHARE_READ | FILE_SHARE_WRITE; + auto const open_flags = FILE_SHARE_READ | FILE_SHARE_WRITE; #else - // Having no FILE_SHARE_WRITE disallows us from connecting to the same Wiimote twice. - // (And disallows using Wiimotes in use by other programs) - // This is what "WiiYourself" does. - // Apparently this doesn't work for everyone. It might be their fault. - auto const open_flags = FILE_SHARE_READ; + // Having no FILE_SHARE_WRITE disallows us from connecting to the same Wiimote twice. + // (And disallows using Wiimotes in use by other programs) + // This is what "WiiYourself" does. + // Apparently this doesn't work for everyone. It might be their fault. + auto const open_flags = FILE_SHARE_READ; #endif - m_dev_handle = CreateFile(m_devicepath.c_str(), - GENERIC_READ | GENERIC_WRITE, open_flags, - nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr); + m_dev_handle = CreateFile(m_devicepath.c_str(), GENERIC_READ | GENERIC_WRITE, open_flags, nullptr, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr); - if (m_dev_handle == INVALID_HANDLE_VALUE) - { - m_dev_handle = nullptr; - return false; - } + if (m_dev_handle == INVALID_HANDLE_VALUE) + { + m_dev_handle = nullptr; + return false; + } #if 0 TCHAR name[128] = {}; @@ -679,414 +683,434 @@ bool WiimoteWindows::ConnectInternal() } #endif - // TODO: thread isn't started here now, do this elsewhere - // This isn't as drastic as it sounds, since the process in which the threads - // reside is normal priority. Needed for keeping audio reports at a decent rate +// TODO: thread isn't started here now, do this elsewhere +// This isn't as drastic as it sounds, since the process in which the threads +// reside is normal priority. Needed for keeping audio reports at a decent rate /* - if (!SetThreadPriority(m_wiimote_thread.native_handle(), THREAD_PRIORITY_TIME_CRITICAL)) - { - ERROR_LOG(WIIMOTE, "Failed to set Wiimote thread priority"); - } + if (!SetThreadPriority(m_wiimote_thread.native_handle(), THREAD_PRIORITY_TIME_CRITICAL)) + { + ERROR_LOG(WIIMOTE, "Failed to set Wiimote thread priority"); + } */ #ifdef SHARE_WRITE_WIIMOTES - g_connected_wiimotes.insert(m_devicepath); + g_connected_wiimotes.insert(m_devicepath); #endif - return true; + return true; } void WiimoteWindows::DisconnectInternal() { - if (!IsConnected()) - return; + if (!IsConnected()) + return; - CloseHandle(m_dev_handle); - m_dev_handle = nullptr; + CloseHandle(m_dev_handle); + m_dev_handle = nullptr; #ifdef SHARE_WRITE_WIIMOTES - std::lock_guard lk(g_connected_wiimotes_lock); - g_connected_wiimotes.erase(m_devicepath); + std::lock_guard lk(g_connected_wiimotes_lock); + g_connected_wiimotes.erase(m_devicepath); #endif } -WiimoteWindows::WiimoteWindows(const std::basic_string& path, WinWriteMethod initial_write_method) -: m_devicepath(path), m_write_method(initial_write_method) +WiimoteWindows::WiimoteWindows(const std::basic_string& path, + WinWriteMethod initial_write_method) + : m_devicepath(path), m_write_method(initial_write_method) { - m_dev_handle = nullptr; + m_dev_handle = nullptr; - m_hid_overlap_read = OVERLAPPED(); - m_hid_overlap_read.hEvent = CreateEvent(nullptr, true, false, nullptr); + m_hid_overlap_read = OVERLAPPED(); + m_hid_overlap_read.hEvent = CreateEvent(nullptr, true, false, nullptr); - m_hid_overlap_write = OVERLAPPED(); - m_hid_overlap_write.hEvent = CreateEvent(nullptr, true, false, nullptr); + m_hid_overlap_write = OVERLAPPED(); + m_hid_overlap_write.hEvent = CreateEvent(nullptr, true, false, nullptr); } WiimoteWindows::~WiimoteWindows() { - Shutdown(); - CloseHandle(m_hid_overlap_read.hEvent); - CloseHandle(m_hid_overlap_write.hEvent); + Shutdown(); + CloseHandle(m_hid_overlap_read.hEvent); + CloseHandle(m_hid_overlap_write.hEvent); } bool WiimoteWindows::IsConnected() const { - return m_dev_handle != nullptr; + return m_dev_handle != nullptr; } // positive = read packet // negative = didn't read packet // zero = error -int IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index) +int IORead(HANDLE& dev_handle, OVERLAPPED& hid_overlap_read, u8* buf, int index) { - // Add data report indicator byte (here, 0xa1) - buf[0] = 0xa1; - // Used below for a warning - buf[1] = 0; + // Add data report indicator byte (here, 0xa1) + buf[0] = 0xa1; + // Used below for a warning + buf[1] = 0; - DWORD bytes = 0; - ResetEvent(hid_overlap_read.hEvent); - if (!ReadFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap_read)) - { - auto const read_err = GetLastError(); + DWORD bytes = 0; + ResetEvent(hid_overlap_read.hEvent); + if (!ReadFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap_read)) + { + auto const read_err = GetLastError(); - if (ERROR_IO_PENDING == read_err) - { - if (!GetOverlappedResult(dev_handle, &hid_overlap_read, &bytes, TRUE)) - { - auto const overlapped_err = GetLastError(); + if (ERROR_IO_PENDING == read_err) + { + if (!GetOverlappedResult(dev_handle, &hid_overlap_read, &bytes, TRUE)) + { + auto const overlapped_err = GetLastError(); - // In case it was aborted by someone else - if (ERROR_OPERATION_ABORTED == overlapped_err) - { - return -1; - } + // In case it was aborted by someone else + if (ERROR_OPERATION_ABORTED == overlapped_err) + { + return -1; + } - WARN_LOG(WIIMOTE, "GetOverlappedResult error %d on Wiimote %i.", overlapped_err, index + 1); - return 0; - } - // If IOWakeup sets the event so GetOverlappedResult returns prematurely, but the request is still pending - else if (hid_overlap_read.Internal == STATUS_PENDING) - { - // Don't forget to cancel it. - CancelIo(dev_handle); - return -1; - } - } - else - { - WARN_LOG(WIIMOTE, "ReadFile error %d on Wiimote %i.", read_err, index + 1); - return 0; - } - } + WARN_LOG(WIIMOTE, "GetOverlappedResult error %d on Wiimote %i.", overlapped_err, index + 1); + return 0; + } + // If IOWakeup sets the event so GetOverlappedResult returns prematurely, but the request is + // still pending + else if (hid_overlap_read.Internal == STATUS_PENDING) + { + // Don't forget to cancel it. + CancelIo(dev_handle); + return -1; + } + } + else + { + WARN_LOG(WIIMOTE, "ReadFile error %d on Wiimote %i.", read_err, index + 1); + return 0; + } + } - return bytes + 1; + return bytes + 1; } void WiimoteWindows::IOWakeup() { - SetEvent(m_hid_overlap_read.hEvent); + SetEvent(m_hid_overlap_read.hEvent); } - // positive = read packet // negative = didn't read packet // zero = error int WiimoteWindows::IORead(u8* buf) { - return WiimoteReal::IORead(m_dev_handle, m_hid_overlap_read, buf, m_index); + return WiimoteReal::IORead(m_dev_handle, m_hid_overlap_read, buf, m_index); } -static int IOWritePerSetOutputReport(HANDLE &dev_handle, const u8* buf, size_t len, DWORD* written) +static int IOWritePerSetOutputReport(HANDLE& dev_handle, const u8* buf, size_t len, DWORD* written) { - BOOLEAN result = pHidD_SetOutputReport(dev_handle, const_cast(buf) + 1, (ULONG)(len - 1)); - if (!result) - { - DWORD err = GetLastError(); - if (err == 121) - { - // Semaphore timeout - NOTICE_LOG(WIIMOTE, "IOWrite[WWM_SET_OUTPUT_REPORT]: Unable to send data to the Wiimote"); - } - else if (err != 0x1F) // Some third-party adapters (DolphinBar) use this - // error code to signal the absence of a Wiimote - // linked to the HID device. - { - WARN_LOG(WIIMOTE, "IOWrite[WWM_SET_OUTPUT_REPORT]: Error: %08x", err); - } - } + BOOLEAN result = pHidD_SetOutputReport(dev_handle, const_cast(buf) + 1, (ULONG)(len - 1)); + if (!result) + { + DWORD err = GetLastError(); + if (err == 121) + { + // Semaphore timeout + NOTICE_LOG(WIIMOTE, "IOWrite[WWM_SET_OUTPUT_REPORT]: Unable to send data to the Wiimote"); + } + else if (err != 0x1F) // Some third-party adapters (DolphinBar) use this + // error code to signal the absence of a Wiimote + // linked to the HID device. + { + WARN_LOG(WIIMOTE, "IOWrite[WWM_SET_OUTPUT_REPORT]: Error: %08x", err); + } + } - if (written) - { - *written = (result ? (DWORD)len : 0); - } + if (written) + { + *written = (result ? (DWORD)len : 0); + } - return result; + return result; } -static int IOWritePerWriteFile(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, WinWriteMethod &write_method, const u8* buf, size_t len, DWORD* written) +static int IOWritePerWriteFile(HANDLE& dev_handle, OVERLAPPED& hid_overlap_write, + WinWriteMethod& write_method, const u8* buf, size_t len, + DWORD* written) { - DWORD bytes_written; - LPCVOID write_buffer = buf + 1; - DWORD bytes_to_write = (DWORD)(len - 1); + DWORD bytes_written; + LPCVOID write_buffer = buf + 1; + DWORD bytes_to_write = (DWORD)(len - 1); - u8 resized_buffer[MAX_PAYLOAD]; + u8 resized_buffer[MAX_PAYLOAD]; - // Resize the buffer, if the underlying HID Class driver needs the buffer to be the size of HidCaps.OuputReportSize - // In case of Wiimote HidCaps.OuputReportSize is 22 Byte. - // This is currently needed by the Toshiba Bluetooth Stack. - if ((write_method == WWM_WRITE_FILE_LARGEST_REPORT_SIZE) && (MAX_PAYLOAD > len)) - { - std::copy(buf, buf + len, resized_buffer); - std::fill(resized_buffer + len, resized_buffer + MAX_PAYLOAD, 0); - write_buffer = resized_buffer + 1; - bytes_to_write = MAX_PAYLOAD - 1; - } + // Resize the buffer, if the underlying HID Class driver needs the buffer to be the size of + // HidCaps.OuputReportSize + // In case of Wiimote HidCaps.OuputReportSize is 22 Byte. + // This is currently needed by the Toshiba Bluetooth Stack. + if ((write_method == WWM_WRITE_FILE_LARGEST_REPORT_SIZE) && (MAX_PAYLOAD > len)) + { + std::copy(buf, buf + len, resized_buffer); + std::fill(resized_buffer + len, resized_buffer + MAX_PAYLOAD, 0); + write_buffer = resized_buffer + 1; + bytes_to_write = MAX_PAYLOAD - 1; + } - ResetEvent(hid_overlap_write.hEvent); - BOOLEAN result = WriteFile(dev_handle, write_buffer, bytes_to_write, &bytes_written, &hid_overlap_write); - if (!result) - { - const DWORD error = GetLastError(); + ResetEvent(hid_overlap_write.hEvent); + BOOLEAN result = + WriteFile(dev_handle, write_buffer, bytes_to_write, &bytes_written, &hid_overlap_write); + if (!result) + { + const DWORD error = GetLastError(); - switch (error) - { - case ERROR_INVALID_USER_BUFFER: - INFO_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: Falling back to SetOutputReport"); - write_method = WWM_SET_OUTPUT_REPORT; - return IOWritePerSetOutputReport(dev_handle, buf, len, written); - case ERROR_IO_PENDING: - // Pending is no error! - break; - default: - WARN_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: Error on WriteFile: %08x", error); - CancelIo(dev_handle); - return 0; - } - } + switch (error) + { + case ERROR_INVALID_USER_BUFFER: + INFO_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: Falling back to SetOutputReport"); + write_method = WWM_SET_OUTPUT_REPORT; + return IOWritePerSetOutputReport(dev_handle, buf, len, written); + case ERROR_IO_PENDING: + // Pending is no error! + break; + default: + WARN_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: Error on WriteFile: %08x", error); + CancelIo(dev_handle); + return 0; + } + } - if (written) - { - *written = 0; - } + if (written) + { + *written = 0; + } - // Wait for completion - DWORD wait_result = WaitForSingleObject(hid_overlap_write.hEvent, WIIMOTE_DEFAULT_TIMEOUT); + // Wait for completion + DWORD wait_result = WaitForSingleObject(hid_overlap_write.hEvent, WIIMOTE_DEFAULT_TIMEOUT); - if (WAIT_TIMEOUT == wait_result) - { - WARN_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: A timeout occurred on writing to Wiimote."); - CancelIo(dev_handle); - return 1; - } - else if (WAIT_FAILED == wait_result) - { - WARN_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: A wait error occurred on writing to Wiimote."); - CancelIo(dev_handle); - return 1; - } + if (WAIT_TIMEOUT == wait_result) + { + WARN_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: A timeout occurred on writing to Wiimote."); + CancelIo(dev_handle); + return 1; + } + else if (WAIT_FAILED == wait_result) + { + WARN_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: A wait error occurred on writing to Wiimote."); + CancelIo(dev_handle); + return 1; + } - if (written) - { - if (!GetOverlappedResult(dev_handle, &hid_overlap_write, written, TRUE)) - { - *written = 0; - } - } + if (written) + { + if (!GetOverlappedResult(dev_handle, &hid_overlap_write, written, TRUE)) + { + *written = 0; + } + } - return 1; + return 1; } -// As of https://msdn.microsoft.com/en-us/library/windows/hardware/ff543402(v=vs.85).aspx, WriteFile is the preferred method -// to send output reports to the HID. WriteFile sends an IRP_MJ_WRITE to the HID Class Driver (https://msdn.microsoft.com/en-us/library/windows/hardware/ff543402(v=vs.85).aspx). -// https://msdn.microsoft.com/en-us/library/windows/hardware/ff541027(v=vs.85).aspx & https://msdn.microsoft.com/en-us/library/windows/hardware/ff543402(v=vs.85).aspx -// state that the used buffer shall be the size of HidCaps.OutputReportSize (the largest output report). -// However as it seems only the Toshiba Bluetooth Stack, which provides its own HID Class Driver, as well as the HID Class Driver -// on Windows 7 enforce this requirement. Whereas on Windows 8/8.1/10 the buffer size can be the actual used report size. -// On Windows 7 when sending a smaller report to the device all bytes of the largest report are sent, which results in -// an error on the Wiimote. Toshiba Bluetooth Stack in contrast only sends the neccessary bytes of the report to the device. -// Therefore it is not possible to use WriteFile on Windows 7 to send data to the Wiimote and the fallback +// As of https://msdn.microsoft.com/en-us/library/windows/hardware/ff543402(v=vs.85).aspx, WriteFile +// is the preferred method +// to send output reports to the HID. WriteFile sends an IRP_MJ_WRITE to the HID Class Driver +// (https://msdn.microsoft.com/en-us/library/windows/hardware/ff543402(v=vs.85).aspx). +// https://msdn.microsoft.com/en-us/library/windows/hardware/ff541027(v=vs.85).aspx & +// https://msdn.microsoft.com/en-us/library/windows/hardware/ff543402(v=vs.85).aspx +// state that the used buffer shall be the size of HidCaps.OutputReportSize (the largest output +// report). +// However as it seems only the Toshiba Bluetooth Stack, which provides its own HID Class Driver, as +// well as the HID Class Driver +// on Windows 7 enforce this requirement. Whereas on Windows 8/8.1/10 the buffer size can be the +// actual used report size. +// On Windows 7 when sending a smaller report to the device all bytes of the largest report are +// sent, which results in +// an error on the Wiimote. Toshiba Bluetooth Stack in contrast only sends the neccessary bytes of +// the report to the device. +// Therefore it is not possible to use WriteFile on Windows 7 to send data to the Wiimote and the +// fallback // to HidP_SetOutputReport is implemented, which in turn does not support "-TR" Wiimotes. -// As to why on the later Windows' WriteFile or the HID Class Driver doesn't follow the documentation, it may be a bug or a feature. +// As to why on the later Windows' WriteFile or the HID Class Driver doesn't follow the +// documentation, it may be a bug or a feature. // This leads to the following: // - Toshiba Bluetooth Stack: Use WriteFile with resized output buffer // - Windows Default HID Class: Try WriteFile with actual output buffer (will work in Win8/8.1/10) // - When WriteFile fails, fallback to HidP_SetOutputReport (for Win7) -// Besides the documentation, WriteFile shall be the preferred method to send data, because it seems to use the Bluetooth Interrupt/Data Channel, -// whereas SetOutputReport uses the Control Channel. This leads to the advantage, that "-TR" Wiimotes work with WriteFile +// Besides the documentation, WriteFile shall be the preferred method to send data, because it seems +// to use the Bluetooth Interrupt/Data Channel, +// whereas SetOutputReport uses the Control Channel. This leads to the advantage, that "-TR" +// Wiimotes work with WriteFile // as they don't accept output reports via the Control Channel. -int IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, WinWriteMethod &write_method, const u8* buf, size_t len, DWORD* written) +int IOWrite(HANDLE& dev_handle, OVERLAPPED& hid_overlap_write, WinWriteMethod& write_method, + const u8* buf, size_t len, DWORD* written) { - switch (write_method) - { - case WWM_WRITE_FILE_LARGEST_REPORT_SIZE: - case WWM_WRITE_FILE_ACTUAL_REPORT_SIZE: - return IOWritePerWriteFile(dev_handle, hid_overlap_write, write_method, buf, len, written); - case WWM_SET_OUTPUT_REPORT: - return IOWritePerSetOutputReport(dev_handle, buf, len, written); - } + switch (write_method) + { + case WWM_WRITE_FILE_LARGEST_REPORT_SIZE: + case WWM_WRITE_FILE_ACTUAL_REPORT_SIZE: + return IOWritePerWriteFile(dev_handle, hid_overlap_write, write_method, buf, len, written); + case WWM_SET_OUTPUT_REPORT: + return IOWritePerSetOutputReport(dev_handle, buf, len, written); + } - return 0; + return 0; } int WiimoteWindows::IOWrite(const u8* buf, size_t len) { - return WiimoteReal::IOWrite(m_dev_handle, m_hid_overlap_write, m_write_method, buf, len, nullptr); + return WiimoteReal::IOWrite(m_dev_handle, m_hid_overlap_write, m_write_method, buf, len, nullptr); } // invokes callback for each found Wiimote Bluetooth device template void ProcessWiimotes(bool new_scan, T& callback) { - BLUETOOTH_DEVICE_SEARCH_PARAMS srch; - srch.dwSize = sizeof(srch); - srch.fReturnAuthenticated = true; - srch.fReturnRemembered = true; - // Does not filter properly somehow, so we need to do an additional check on - // fConnected BT Devices - srch.fReturnConnected = true; - srch.fReturnUnknown = true; - srch.fIssueInquiry = new_scan; - // multiple of 1.28 seconds - srch.cTimeoutMultiplier = 2; + BLUETOOTH_DEVICE_SEARCH_PARAMS srch; + srch.dwSize = sizeof(srch); + srch.fReturnAuthenticated = true; + srch.fReturnRemembered = true; + // Does not filter properly somehow, so we need to do an additional check on + // fConnected BT Devices + srch.fReturnConnected = true; + srch.fReturnUnknown = true; + srch.fIssueInquiry = new_scan; + // multiple of 1.28 seconds + srch.cTimeoutMultiplier = 2; - BLUETOOTH_FIND_RADIO_PARAMS radioParam; - radioParam.dwSize = sizeof(radioParam); + BLUETOOTH_FIND_RADIO_PARAMS radioParam; + radioParam.dwSize = sizeof(radioParam); - HANDLE hRadio; + HANDLE hRadio; - // TODO: save radio(s) in the WiimoteScanner constructor? + // TODO: save radio(s) in the WiimoteScanner constructor? - // Enumerate BT radios - HBLUETOOTH_RADIO_FIND hFindRadio = pBluetoothFindFirstRadio(&radioParam, &hRadio); - while (hFindRadio) - { - BLUETOOTH_RADIO_INFO radioInfo; - radioInfo.dwSize = sizeof(radioInfo); + // Enumerate BT radios + HBLUETOOTH_RADIO_FIND hFindRadio = pBluetoothFindFirstRadio(&radioParam, &hRadio); + while (hFindRadio) + { + BLUETOOTH_RADIO_INFO radioInfo; + radioInfo.dwSize = sizeof(radioInfo); - auto const rinfo_result = pBluetoothGetRadioInfo(hRadio, &radioInfo); - if (ERROR_SUCCESS == rinfo_result) - { - srch.hRadio = hRadio; + auto const rinfo_result = pBluetoothGetRadioInfo(hRadio, &radioInfo); + if (ERROR_SUCCESS == rinfo_result) + { + srch.hRadio = hRadio; - BLUETOOTH_DEVICE_INFO btdi; - btdi.dwSize = sizeof(btdi); + BLUETOOTH_DEVICE_INFO btdi; + btdi.dwSize = sizeof(btdi); - // Enumerate BT devices - HBLUETOOTH_DEVICE_FIND hFindDevice = pBluetoothFindFirstDevice(&srch, &btdi); - while (hFindDevice) - { - // btdi.szName is sometimes missing it's content - it's a bt feature.. - DEBUG_LOG(WIIMOTE, "Authenticated %i connected %i remembered %i ", - btdi.fAuthenticated, btdi.fConnected, btdi.fRemembered); + // Enumerate BT devices + HBLUETOOTH_DEVICE_FIND hFindDevice = pBluetoothFindFirstDevice(&srch, &btdi); + while (hFindDevice) + { + // btdi.szName is sometimes missing it's content - it's a bt feature.. + DEBUG_LOG(WIIMOTE, "Authenticated %i connected %i remembered %i ", btdi.fAuthenticated, + btdi.fConnected, btdi.fRemembered); - if (IsValidBluetoothName(UTF16ToUTF8(btdi.szName))) - { - callback(hRadio, radioInfo, btdi); - } + if (IsValidBluetoothName(UTF16ToUTF8(btdi.szName))) + { + callback(hRadio, radioInfo, btdi); + } - if (false == pBluetoothFindNextDevice(hFindDevice, &btdi)) - { - pBluetoothFindDeviceClose(hFindDevice); - hFindDevice = nullptr; - } - } - } + if (false == pBluetoothFindNextDevice(hFindDevice, &btdi)) + { + pBluetoothFindDeviceClose(hFindDevice); + hFindDevice = nullptr; + } + } + } - if (false == pBluetoothFindNextRadio(hFindRadio, &hRadio)) - { - pBluetoothFindRadioClose(hFindRadio); - hFindRadio = nullptr; - } - } + if (false == pBluetoothFindNextRadio(hFindRadio, &hRadio)) + { + pBluetoothFindRadioClose(hFindRadio); + hFindRadio = nullptr; + } + } } void RemoveWiimote(BLUETOOTH_DEVICE_INFO_STRUCT& btdi) { - //if (btdi.fConnected) - { - if (SUCCEEDED(pBluetoothRemoveDevice(&btdi.Address))) - { - NOTICE_LOG(WIIMOTE, "Removed BT Device", GetLastError()); - } - } + // if (btdi.fConnected) + { + if (SUCCEEDED(pBluetoothRemoveDevice(&btdi.Address))) + { + NOTICE_LOG(WIIMOTE, "Removed BT Device", GetLastError()); + } + } } -bool AttachWiimote(HANDLE hRadio, const BLUETOOTH_RADIO_INFO& radio_info, BLUETOOTH_DEVICE_INFO_STRUCT& btdi) +bool AttachWiimote(HANDLE hRadio, const BLUETOOTH_RADIO_INFO& radio_info, + BLUETOOTH_DEVICE_INFO_STRUCT& btdi) { - // We don't want "remembered" devices. - // SetServiceState will just fail with them.. - if (!btdi.fConnected && !btdi.fRemembered) - { - auto const& wm_addr = btdi.Address.rgBytes; + // We don't want "remembered" devices. + // SetServiceState will just fail with them.. + if (!btdi.fConnected && !btdi.fRemembered) + { + auto const& wm_addr = btdi.Address.rgBytes; - NOTICE_LOG(WIIMOTE, "Found Wiimote (%02x:%02x:%02x:%02x:%02x:%02x). Enabling HID service.", - wm_addr[0], wm_addr[1], wm_addr[2], wm_addr[3], wm_addr[4], wm_addr[5]); + NOTICE_LOG(WIIMOTE, "Found Wiimote (%02x:%02x:%02x:%02x:%02x:%02x). Enabling HID service.", + wm_addr[0], wm_addr[1], wm_addr[2], wm_addr[3], wm_addr[4], wm_addr[5]); #if defined(AUTHENTICATE_WIIMOTES) - // Authenticate - auto const& radio_addr = radio_info.address.rgBytes; - // FIXME Not sure this usage of OOB_DATA_INFO is correct... - BLUETOOTH_OOB_DATA_INFO oob_data_info = { 0 }; - memcpy(&oob_data_info.C[0], &radio_addr[0], sizeof(WCHAR) * 6); - const DWORD auth_result = pBluetoothAuthenticateDeviceEx(nullptr, hRadio, &btdi, - &oob_data_info, MITMProtectionNotDefined); + // Authenticate + auto const& radio_addr = radio_info.address.rgBytes; + // FIXME Not sure this usage of OOB_DATA_INFO is correct... + BLUETOOTH_OOB_DATA_INFO oob_data_info = {0}; + memcpy(&oob_data_info.C[0], &radio_addr[0], sizeof(WCHAR) * 6); + const DWORD auth_result = pBluetoothAuthenticateDeviceEx(nullptr, hRadio, &btdi, &oob_data_info, + MITMProtectionNotDefined); - if (ERROR_SUCCESS != auth_result) - { - ERROR_LOG(WIIMOTE, "AttachWiimote: BluetoothAuthenticateDeviceEx returned %08x", auth_result); - } + if (ERROR_SUCCESS != auth_result) + { + ERROR_LOG(WIIMOTE, "AttachWiimote: BluetoothAuthenticateDeviceEx returned %08x", auth_result); + } - DWORD pcServices = 16; - GUID guids[16]; - // If this is not done, the Wii device will not remember the pairing - const DWORD srv_result = pBluetoothEnumerateInstalledServices(hRadio, &btdi, &pcServices, guids); + DWORD pcServices = 16; + GUID guids[16]; + // If this is not done, the Wii device will not remember the pairing + const DWORD srv_result = + pBluetoothEnumerateInstalledServices(hRadio, &btdi, &pcServices, guids); - if (ERROR_SUCCESS != srv_result) - { - ERROR_LOG(WIIMOTE, "AttachWiimote: BluetoothEnumerateInstalledServices returned %08x", srv_result); - } + if (ERROR_SUCCESS != srv_result) + { + ERROR_LOG(WIIMOTE, "AttachWiimote: BluetoothEnumerateInstalledServices returned %08x", + srv_result); + } #endif - // Activate service - const DWORD hr = pBluetoothSetServiceState(hRadio, &btdi, - &HumanInterfaceDeviceServiceClass_UUID, BLUETOOTH_SERVICE_ENABLE); + // Activate service + const DWORD hr = pBluetoothSetServiceState( + hRadio, &btdi, &HumanInterfaceDeviceServiceClass_UUID, BLUETOOTH_SERVICE_ENABLE); - g_connect_times[btdi.Address.ullLong] = std::time(nullptr); + g_connect_times[btdi.Address.ullLong] = std::time(nullptr); - if (FAILED(hr)) - { - ERROR_LOG(WIIMOTE, "AttachWiimote: BluetoothSetServiceState returned %08x", hr); - } - else - { - return true; - } - } + if (FAILED(hr)) + { + ERROR_LOG(WIIMOTE, "AttachWiimote: BluetoothSetServiceState returned %08x", hr); + } + else + { + return true; + } + } - return false; + return false; } // Removes remembered non-connected devices bool ForgetWiimote(BLUETOOTH_DEVICE_INFO_STRUCT& btdi) { - if (!btdi.fConnected && btdi.fRemembered) - { - // Time to avoid RemoveDevice after SetServiceState. - // Sometimes SetServiceState takes a while.. - auto const avoid_forget_seconds = 5.0; + if (!btdi.fConnected && btdi.fRemembered) + { + // Time to avoid RemoveDevice after SetServiceState. + // Sometimes SetServiceState takes a while.. + auto const avoid_forget_seconds = 5.0; - auto pair_time = g_connect_times.find(btdi.Address.ullLong); - if (pair_time == g_connect_times.end() || - std::difftime(time(nullptr), pair_time->second) >= avoid_forget_seconds) - { - // Make Windows forget about device so it will re-find it if visible. - // This is also required to detect a disconnect for some reason.. - NOTICE_LOG(WIIMOTE, "Removing remembered Wiimote."); - pBluetoothRemoveDevice(&btdi.Address); - return true; - } - } + auto pair_time = g_connect_times.find(btdi.Address.ullLong); + if (pair_time == g_connect_times.end() || + std::difftime(time(nullptr), pair_time->second) >= avoid_forget_seconds) + { + // Make Windows forget about device so it will re-find it if visible. + // This is also required to detect a disconnect for some reason.. + NOTICE_LOG(WIIMOTE, "Removing remembered Wiimote."); + pBluetoothRemoveDevice(&btdi.Address); + return true; + } + } - return false; + return false; } - }; diff --git a/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm b/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm index e6a518643e..3471896951 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm +++ b/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm @@ -5,560 +5,562 @@ #include "Core/HW/WiimoteEmu/WiimoteHid.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" -@interface SearchBT: NSObject { +@interface SearchBT : NSObject +{ @public - unsigned int maxDevices; - bool done; + unsigned int maxDevices; + bool done; } @end -@interface ConnectBT: NSObject {} +@interface ConnectBT : NSObject +{ +} @end namespace WiimoteReal { - class WiimoteDarwin final : public Wiimote { public: - WiimoteDarwin(IOBluetoothDevice* device); - ~WiimoteDarwin() override; + WiimoteDarwin(IOBluetoothDevice* device); + ~WiimoteDarwin() override; - // These are not protected/private because ConnectBT needs them. - void DisconnectInternal() override; - IOBluetoothDevice* m_btd; - unsigned char* m_input; - int m_inputlen; + // These are not protected/private because ConnectBT needs them. + void DisconnectInternal() override; + IOBluetoothDevice* m_btd; + unsigned char* m_input; + int m_inputlen; protected: - bool ConnectInternal() override; - bool IsConnected() const override; - void IOWakeup() override; - int IORead(u8* buf) override; - int IOWrite(u8 const* buf, size_t len) override; - void EnablePowerAssertionInternal() override; - void DisablePowerAssertionInternal() override; + bool ConnectInternal() override; + bool IsConnected() const override; + void IOWakeup() override; + int IORead(u8* buf) override; + int IOWrite(u8 const* buf, size_t len) override; + void EnablePowerAssertionInternal() override; + void DisablePowerAssertionInternal() override; private: - IOBluetoothL2CAPChannel* m_ichan; - IOBluetoothL2CAPChannel* m_cchan; - bool m_connected; - CFRunLoopRef m_wiimote_thread_run_loop; - IOPMAssertionID m_pm_assertion; + IOBluetoothL2CAPChannel* m_ichan; + IOBluetoothL2CAPChannel* m_cchan; + bool m_connected; + CFRunLoopRef m_wiimote_thread_run_loop; + IOPMAssertionID m_pm_assertion; }; class WiimoteDarwinHid final : public Wiimote { public: - WiimoteDarwinHid(IOHIDDeviceRef device); - ~WiimoteDarwinHid() override; + WiimoteDarwinHid(IOHIDDeviceRef device); + ~WiimoteDarwinHid() override; protected: - bool ConnectInternal() override; - void DisconnectInternal() override; - bool IsConnected() const override; - void IOWakeup() override; - int IORead(u8* buf) override; - int IOWrite(u8 const* buf, size_t len) override; + bool ConnectInternal() override; + void DisconnectInternal() override; + bool IsConnected() const override; + void IOWakeup() override; + int IORead(u8* buf) override; + int IOWrite(u8 const* buf, size_t len) override; private: - static void ReportCallback(void* context, IOReturn result, void* sender, IOHIDReportType type, u32 reportID, u8* report, CFIndex reportLength); - static void RemoveCallback(void* context, IOReturn result, void* sender); - void QueueBufferReport(int length); - IOHIDDeviceRef m_device; - bool m_connected; - std::atomic m_interrupted; - Report m_report_buffer; - Common::FifoQueue m_buffered_reports; + static void ReportCallback(void* context, IOReturn result, void* sender, IOHIDReportType type, + u32 reportID, u8* report, CFIndex reportLength); + static void RemoveCallback(void* context, IOReturn result, void* sender); + void QueueBufferReport(int length); + IOHIDDeviceRef m_device; + bool m_connected; + std::atomic m_interrupted; + Report m_report_buffer; + Common::FifoQueue m_buffered_reports; }; WiimoteScanner::WiimoteScanner() -{} +{ +} WiimoteScanner::~WiimoteScanner() -{} +{ +} void WiimoteScanner::Update() -{} - -void WiimoteScanner::FindWiimotes(std::vector & found_wiimotes, Wiimote* & found_board) { - // TODO: find the device in the constructor and save it for later - IOBluetoothHostController *bth; - IOBluetoothDeviceInquiry *bti; - IOHIDManagerRef hid; - SearchBT *sbt; - NSEnumerator *en; - found_board = nullptr; +} - bool btFailed = false; - bool hidFailed = false; +void WiimoteScanner::FindWiimotes(std::vector& found_wiimotes, Wiimote*& found_board) +{ + // TODO: find the device in the constructor and save it for later + IOBluetoothHostController* bth; + IOBluetoothDeviceInquiry* bti; + IOHIDManagerRef hid; + SearchBT* sbt; + NSEnumerator* en; + found_board = nullptr; - bth = [[IOBluetoothHostController alloc] init]; - btFailed = [bth addressAsString] == nil; - if (btFailed) - WARN_LOG(WIIMOTE, "No Bluetooth host controller"); + bool btFailed = false; + bool hidFailed = false; - hid = IOHIDManagerCreate(NULL, kIOHIDOptionsTypeNone); - hidFailed = CFGetTypeID(hid) != IOHIDManagerGetTypeID(); - if (hidFailed) - WARN_LOG(WIIMOTE, "No HID manager"); + bth = [[IOBluetoothHostController alloc] init]; + btFailed = [bth addressAsString] == nil; + if (btFailed) + WARN_LOG(WIIMOTE, "No Bluetooth host controller"); - if (hidFailed && btFailed) - { - CFRelease(hid); - [bth release]; - return; - } + hid = IOHIDManagerCreate(NULL, kIOHIDOptionsTypeNone); + hidFailed = CFGetTypeID(hid) != IOHIDManagerGetTypeID(); + if (hidFailed) + WARN_LOG(WIIMOTE, "No HID manager"); - if (!btFailed) - { - sbt = [[SearchBT alloc] init]; - sbt->maxDevices = 32; - bti = [[IOBluetoothDeviceInquiry alloc] init]; - [bti setDelegate: sbt]; - [bti setInquiryLength: 2]; + if (hidFailed && btFailed) + { + CFRelease(hid); + [bth release]; + return; + } - if ([bti start] != kIOReturnSuccess) - { - ERROR_LOG(WIIMOTE, "Unable to do Bluetooth discovery"); - [bth release]; - [sbt release]; - btFailed = true; - } + if (!btFailed) + { + sbt = [[SearchBT alloc] init]; + sbt->maxDevices = 32; + bti = [[IOBluetoothDeviceInquiry alloc] init]; + [bti setDelegate:sbt]; + [bti setInquiryLength:2]; - do - { - CFRunLoopRun(); - } - while (!sbt->done); + if ([bti start] != kIOReturnSuccess) + { + ERROR_LOG(WIIMOTE, "Unable to do Bluetooth discovery"); + [bth release]; + [sbt release]; + btFailed = true; + } - int found_devices = [[bti foundDevices] count]; + do + { + CFRunLoopRun(); + } while (!sbt->done); - if (found_devices) - NOTICE_LOG(WIIMOTE, "Found %i Bluetooth devices", found_devices); + int found_devices = [[bti foundDevices] count]; - en = [[bti foundDevices] objectEnumerator]; - for (int i = 0; i < found_devices; i++) - { - IOBluetoothDevice *dev = [en nextObject]; - if (!IsValidBluetoothName([[dev name] UTF8String])) - continue; + if (found_devices) + NOTICE_LOG(WIIMOTE, "Found %i Bluetooth devices", found_devices); - Wiimote* wm = new WiimoteDarwin([dev retain]); + en = [[bti foundDevices] objectEnumerator]; + for (int i = 0; i < found_devices; i++) + { + IOBluetoothDevice* dev = [en nextObject]; + if (!IsValidBluetoothName([[dev name] UTF8String])) + continue; - if (IsBalanceBoardName([[dev name] UTF8String])) - { - found_board = wm; - } - else - { - found_wiimotes.push_back(wm); - } - } + Wiimote* wm = new WiimoteDarwin([dev retain]); - [bth release]; - [bti release]; - [sbt release]; - } + if (IsBalanceBoardName([[dev name] UTF8String])) + { + found_board = wm; + } + else + { + found_wiimotes.push_back(wm); + } + } - if (!hidFailed) - { - NSArray *criteria = @[ - @{ @kIOHIDVendorIDKey: @0x057e, @kIOHIDProductIDKey: @0x0306 }, - @{ @kIOHIDVendorIDKey: @0x057e, @kIOHIDProductIDKey: @0x0330 }, - ]; - IOHIDManagerSetDeviceMatchingMultiple(hid, (CFArrayRef)criteria); - if (IOHIDManagerOpen(hid, kIOHIDOptionsTypeNone) != kIOReturnSuccess) - WARN_LOG(WIIMOTE, "Failed to open HID Manager"); - CFSetRef devices = IOHIDManagerCopyDevices(hid); - if (devices) - { - int found_devices = CFSetGetCount(devices); - if (found_devices) - { - NOTICE_LOG(WIIMOTE, "Found %i HID devices", found_devices); + [bth release]; + [bti release]; + [sbt release]; + } - IOHIDDeviceRef values[found_devices]; - CFSetGetValues(devices, reinterpret_cast(&values)); - for (int i = 0; i < found_devices; i++) - { - Wiimote* wm = new WiimoteDarwinHid(values[i]); - found_wiimotes.push_back(wm); - } - } - } - CFRelease(hid); - } + if (!hidFailed) + { + NSArray* criteria = @[ + @{ @kIOHIDVendorIDKey : @0x057e, + @kIOHIDProductIDKey : @0x0306 }, + @{ @kIOHIDVendorIDKey : @0x057e, + @kIOHIDProductIDKey : @0x0330 }, + ]; + IOHIDManagerSetDeviceMatchingMultiple(hid, (CFArrayRef)criteria); + if (IOHIDManagerOpen(hid, kIOHIDOptionsTypeNone) != kIOReturnSuccess) + WARN_LOG(WIIMOTE, "Failed to open HID Manager"); + CFSetRef devices = IOHIDManagerCopyDevices(hid); + if (devices) + { + int found_devices = CFSetGetCount(devices); + if (found_devices) + { + NOTICE_LOG(WIIMOTE, "Found %i HID devices", found_devices); + + IOHIDDeviceRef values[found_devices]; + CFSetGetValues(devices, reinterpret_cast(&values)); + for (int i = 0; i < found_devices; i++) + { + Wiimote* wm = new WiimoteDarwinHid(values[i]); + found_wiimotes.push_back(wm); + } + } + } + CFRelease(hid); + } } bool WiimoteScanner::IsReady() const { - // TODO: only return true when a BT device is present - return true; + // TODO: only return true when a BT device is present + return true; } WiimoteDarwin::WiimoteDarwin(IOBluetoothDevice* device) : m_btd(device) { - m_inputlen = 0; - m_connected = false; - m_wiimote_thread_run_loop = nullptr; - m_pm_assertion = kIOPMNullAssertionID; + m_inputlen = 0; + m_connected = false; + m_wiimote_thread_run_loop = nullptr; + m_pm_assertion = kIOPMNullAssertionID; } WiimoteDarwin::~WiimoteDarwin() { - Shutdown(); - if (m_wiimote_thread_run_loop) - { - CFRelease(m_wiimote_thread_run_loop); - m_wiimote_thread_run_loop = nullptr; - } - [m_btd release]; - m_btd = nil; - DisablePowerAssertionInternal(); + Shutdown(); + if (m_wiimote_thread_run_loop) + { + CFRelease(m_wiimote_thread_run_loop); + m_wiimote_thread_run_loop = nullptr; + } + [m_btd release]; + m_btd = nil; + DisablePowerAssertionInternal(); } // Connect to a Wiimote with a known address. bool WiimoteDarwin::ConnectInternal() { - if (IsConnected()) - return false; + if (IsConnected()) + return false; - ConnectBT *cbt = [[ConnectBT alloc] init]; + ConnectBT* cbt = [[ConnectBT alloc] init]; - m_cchan = m_ichan = nil; + m_cchan = m_ichan = nil; - IOReturn ret = [m_btd openConnection]; - if (ret) - { - ERROR_LOG(WIIMOTE, "Unable to open Bluetooth connection to Wiimote %i: %x", - m_index + 1, ret); - [cbt release]; - return false; - } + IOReturn ret = [m_btd openConnection]; + if (ret) + { + ERROR_LOG(WIIMOTE, "Unable to open Bluetooth connection to Wiimote %i: %x", m_index + 1, ret); + [cbt release]; + return false; + } - ret = [m_btd openL2CAPChannelSync: &m_cchan - withPSM: kBluetoothL2CAPPSMHIDControl delegate: cbt]; - if (ret) - { - ERROR_LOG(WIIMOTE, "Unable to open control channel for Wiimote %i: %x", - m_index + 1, ret); - goto bad; - } - // Apple docs claim: - // "The L2CAP channel object is already retained when this function returns - // success; the channel must be released when the caller is done with it." - // But without this, the channels get over-autoreleased, even though the - // refcounting behavior here is clearly correct. - [m_cchan retain]; + ret = [m_btd openL2CAPChannelSync:&m_cchan withPSM:kBluetoothL2CAPPSMHIDControl delegate:cbt]; + if (ret) + { + ERROR_LOG(WIIMOTE, "Unable to open control channel for Wiimote %i: %x", m_index + 1, ret); + goto bad; + } + // Apple docs claim: + // "The L2CAP channel object is already retained when this function returns + // success; the channel must be released when the caller is done with it." + // But without this, the channels get over-autoreleased, even though the + // refcounting behavior here is clearly correct. + [m_cchan retain]; - ret = [m_btd openL2CAPChannelSync: &m_ichan - withPSM: kBluetoothL2CAPPSMHIDInterrupt delegate: cbt]; - if (ret) - { - WARN_LOG(WIIMOTE, "Unable to open interrupt channel for Wiimote %i: %x", - m_index + 1, ret); - goto bad; - } - [m_ichan retain]; + ret = [m_btd openL2CAPChannelSync:&m_ichan withPSM:kBluetoothL2CAPPSMHIDInterrupt delegate:cbt]; + if (ret) + { + WARN_LOG(WIIMOTE, "Unable to open interrupt channel for Wiimote %i: %x", m_index + 1, ret); + goto bad; + } + [m_ichan retain]; - NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i at %s", - m_index + 1, [[m_btd addressString] UTF8String]); + NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i at %s", m_index + 1, + [[m_btd addressString] UTF8String]); - m_connected = true; + m_connected = true; - [cbt release]; + [cbt release]; - m_wiimote_thread_run_loop = (CFRunLoopRef) CFRetain(CFRunLoopGetCurrent()); + m_wiimote_thread_run_loop = (CFRunLoopRef)CFRetain(CFRunLoopGetCurrent()); - return true; + return true; bad: - DisconnectInternal(); - [cbt release]; - return false; + DisconnectInternal(); + [cbt release]; + return false; } // Disconnect a Wiimote. void WiimoteDarwin::DisconnectInternal() { - [m_ichan closeChannel]; - [m_ichan release]; - m_ichan = nil; + [m_ichan closeChannel]; + [m_ichan release]; + m_ichan = nil; - [m_cchan closeChannel]; - [m_cchan release]; - m_cchan = nil; + [m_cchan closeChannel]; + [m_cchan release]; + m_cchan = nil; - [m_btd closeConnection]; + [m_btd closeConnection]; - if (!IsConnected()) - return; + if (!IsConnected()) + return; - NOTICE_LOG(WIIMOTE, "Disconnecting Wiimote %i", m_index + 1); + NOTICE_LOG(WIIMOTE, "Disconnecting Wiimote %i", m_index + 1); - m_connected = false; + m_connected = false; } bool WiimoteDarwin::IsConnected() const { - return m_connected; + return m_connected; } void WiimoteDarwin::IOWakeup() { - if (m_wiimote_thread_run_loop) - { - CFRunLoopStop(m_wiimote_thread_run_loop); - } + if (m_wiimote_thread_run_loop) + { + CFRunLoopStop(m_wiimote_thread_run_loop); + } } -int WiimoteDarwin::IORead(unsigned char *buf) +int WiimoteDarwin::IORead(unsigned char* buf) { - m_input = buf; - m_inputlen = -1; + m_input = buf; + m_inputlen = -1; - CFRunLoopRun(); + CFRunLoopRun(); - return m_inputlen; + return m_inputlen; } -int WiimoteDarwin::IOWrite(const unsigned char *buf, size_t len) +int WiimoteDarwin::IOWrite(const unsigned char* buf, size_t len) { - IOReturn ret; + IOReturn ret; - if (!IsConnected()) - return 0; + if (!IsConnected()) + return 0; - ret = [m_ichan writeAsync: const_cast((void *)buf) length: (int)len refcon: nil]; + ret = [m_ichan writeAsync:const_cast((void*)buf) length:(int)len refcon:nil]; - if (ret == kIOReturnSuccess) - return len; - else - return 0; + if (ret == kIOReturnSuccess) + return len; + else + return 0; } void WiimoteDarwin::EnablePowerAssertionInternal() { - if (m_pm_assertion == kIOPMNullAssertionID) - { - if (IOReturn ret = IOPMAssertionCreateWithName(kIOPMAssertPreventUserIdleDisplaySleep, kIOPMAssertionLevelOn, CFSTR("Dolphin Wiimote activity"), &m_pm_assertion)) - ERROR_LOG(WIIMOTE, "Could not create power management assertion: %08x", ret); - } + if (m_pm_assertion == kIOPMNullAssertionID) + { + if (IOReturn ret = IOPMAssertionCreateWithName( + kIOPMAssertPreventUserIdleDisplaySleep, kIOPMAssertionLevelOn, + CFSTR("Dolphin Wiimote activity"), &m_pm_assertion)) + ERROR_LOG(WIIMOTE, "Could not create power management assertion: %08x", ret); + } } void WiimoteDarwin::DisablePowerAssertionInternal() { - if (m_pm_assertion != kIOPMNullAssertionID) - { - if (IOReturn ret = IOPMAssertionRelease(m_pm_assertion)) - ERROR_LOG(WIIMOTE, "Could not release power management assertion: %08x", ret); - } + if (m_pm_assertion != kIOPMNullAssertionID) + { + if (IOReturn ret = IOPMAssertionRelease(m_pm_assertion)) + ERROR_LOG(WIIMOTE, "Could not release power management assertion: %08x", ret); + } } WiimoteDarwinHid::WiimoteDarwinHid(IOHIDDeviceRef device) : m_device(device) { - CFRetain(m_device); - m_connected = false; - m_report_buffer = Report(MAX_PAYLOAD); + CFRetain(m_device); + m_connected = false; + m_report_buffer = Report(MAX_PAYLOAD); } WiimoteDarwinHid::~WiimoteDarwinHid() { - Shutdown(); - CFRelease(m_device); + Shutdown(); + CFRelease(m_device); } bool WiimoteDarwinHid::ConnectInternal() { - IOReturn ret = IOHIDDeviceOpen(m_device, kIOHIDOptionsTypeNone); - m_connected = ret == kIOReturnSuccess; - if (m_connected) - { - IOHIDDeviceScheduleWithRunLoop(m_device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - IOHIDDeviceRegisterInputReportCallback(m_device, - m_report_buffer.data() + 1, - MAX_PAYLOAD - 1, - &WiimoteDarwinHid::ReportCallback, - this); - IOHIDDeviceRegisterRemovalCallback(m_device, &WiimoteDarwinHid::RemoveCallback, this); - NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i", m_index + 1); - } - else - { - ERROR_LOG(WIIMOTE, "Could not open IOHID Wiimote: %08x", ret); - } + IOReturn ret = IOHIDDeviceOpen(m_device, kIOHIDOptionsTypeNone); + m_connected = ret == kIOReturnSuccess; + if (m_connected) + { + IOHIDDeviceScheduleWithRunLoop(m_device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + IOHIDDeviceRegisterInputReportCallback(m_device, m_report_buffer.data() + 1, MAX_PAYLOAD - 1, + &WiimoteDarwinHid::ReportCallback, this); + IOHIDDeviceRegisterRemovalCallback(m_device, &WiimoteDarwinHid::RemoveCallback, this); + NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i", m_index + 1); + } + else + { + ERROR_LOG(WIIMOTE, "Could not open IOHID Wiimote: %08x", ret); + } - return m_connected; + return m_connected; } void WiimoteDarwinHid::DisconnectInternal() { - IOHIDDeviceUnscheduleFromRunLoop(m_device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - IOWakeup(); - IOReturn ret = IOHIDDeviceClose(m_device, kIOHIDOptionsTypeNone); - if (ret != kIOReturnSuccess) - ERROR_LOG(WIIMOTE, "Error closing IOHID Wiimote: %08x", ret); + IOHIDDeviceUnscheduleFromRunLoop(m_device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + IOWakeup(); + IOReturn ret = IOHIDDeviceClose(m_device, kIOHIDOptionsTypeNone); + if (ret != kIOReturnSuccess) + ERROR_LOG(WIIMOTE, "Error closing IOHID Wiimote: %08x", ret); - if (!IsConnected()) - return; + if (!IsConnected()) + return; - NOTICE_LOG(WIIMOTE, "Disconnecting Wiimote %i", m_index + 1); + NOTICE_LOG(WIIMOTE, "Disconnecting Wiimote %i", m_index + 1); - m_buffered_reports.Clear(); + m_buffered_reports.Clear(); - m_connected = false; + m_connected = false; } bool WiimoteDarwinHid::IsConnected() const { - return m_connected; + return m_connected; } void WiimoteDarwinHid::IOWakeup() { - m_interrupted.store(true); - CFRunLoopStop(CFRunLoopGetCurrent()); + m_interrupted.store(true); + CFRunLoopStop(CFRunLoopGetCurrent()); } int WiimoteDarwinHid::IORead(u8* buf) { - Report rpt; - m_interrupted.store(false); - while (m_buffered_reports.Empty() && !m_interrupted.load()) - CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); + Report rpt; + m_interrupted.store(false); + while (m_buffered_reports.Empty() && !m_interrupted.load()) + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); - if (m_buffered_reports.Pop(rpt)) - { - memcpy(buf, rpt.data(), rpt.size()); - return rpt.size(); - } - return -1; + if (m_buffered_reports.Pop(rpt)) + { + memcpy(buf, rpt.data(), rpt.size()); + return rpt.size(); + } + return -1; } int WiimoteDarwinHid::IOWrite(u8 const* buf, size_t len) { - IOReturn ret = IOHIDDeviceSetReport(m_device, kIOHIDReportTypeOutput, buf[1], buf + 1, len - 1); - if (ret != kIOReturnSuccess) - { - ERROR_LOG(WIIMOTE, "Error writing to Wiimote: %08x", ret); - return 0; - } - return len; + IOReturn ret = IOHIDDeviceSetReport(m_device, kIOHIDReportTypeOutput, buf[1], buf + 1, len - 1); + if (ret != kIOReturnSuccess) + { + ERROR_LOG(WIIMOTE, "Error writing to Wiimote: %08x", ret); + return 0; + } + return len; } void WiimoteDarwinHid::QueueBufferReport(int length) { - Report rpt(m_report_buffer); - rpt[0] = 0xa1; - rpt.resize(length + 1); - m_buffered_reports.Push(std::move(rpt)); + Report rpt(m_report_buffer); + rpt[0] = 0xa1; + rpt.resize(length + 1); + m_buffered_reports.Push(std::move(rpt)); } -void WiimoteDarwinHid::ReportCallback(void* context, IOReturn result, void*, IOHIDReportType type, u32 report_id, u8* report, CFIndex report_length) +void WiimoteDarwinHid::ReportCallback(void* context, IOReturn result, void*, IOHIDReportType type, + u32 report_id, u8* report, CFIndex report_length) { - WiimoteDarwinHid* wm = static_cast(context); - report[0] = report_id; - wm->QueueBufferReport(report_length); + WiimoteDarwinHid* wm = static_cast(context); + report[0] = report_id; + wm->QueueBufferReport(report_length); } void WiimoteDarwinHid::RemoveCallback(void* context, IOReturn result, void*) { - WiimoteDarwinHid* wm = static_cast(context); - wm->DisconnectInternal(); + WiimoteDarwinHid* wm = static_cast(context); + wm->DisconnectInternal(); } -} // namespace +} // namespace @implementation SearchBT -- (void) deviceInquiryComplete: (IOBluetoothDeviceInquiry *) sender - error: (IOReturn) error - aborted: (BOOL) aborted +- (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender + error:(IOReturn)error + aborted:(BOOL)aborted { - done = true; - CFRunLoopStop(CFRunLoopGetCurrent()); + done = true; + CFRunLoopStop(CFRunLoopGetCurrent()); } -- (void) deviceInquiryDeviceFound: (IOBluetoothDeviceInquiry *) sender - device: (IOBluetoothDevice *) device +- (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender device:(IOBluetoothDevice*)device { - NOTICE_LOG(WIIMOTE, "Discovered Bluetooth device at %s: %s", - [[device addressString] UTF8String], - [[device name] UTF8String]); + NOTICE_LOG(WIIMOTE, "Discovered Bluetooth device at %s: %s", [[device addressString] UTF8String], + [[device name] UTF8String]); - if ([[sender foundDevices] count] == maxDevices) - [sender stop]; + if ([[sender foundDevices] count] == maxDevices) + [sender stop]; } @end @implementation ConnectBT -- (void) l2capChannelData: (IOBluetoothL2CAPChannel *) l2capChannel - data: (unsigned char *) data - length: (NSUInteger) length +- (void)l2capChannelData:(IOBluetoothL2CAPChannel*)l2capChannel + data:(unsigned char*)data + length:(NSUInteger)length { - IOBluetoothDevice *device = [l2capChannel device]; - WiimoteReal::WiimoteDarwin *wm = nullptr; + IOBluetoothDevice* device = [l2capChannel device]; + WiimoteReal::WiimoteDarwin* wm = nullptr; - std::lock_guard lk(WiimoteReal::g_refresh_lock); + std::lock_guard lk(WiimoteReal::g_refresh_lock); - for (int i = 0; i < MAX_WIIMOTES; i++) - { - wm = static_cast(WiimoteReal::g_wiimotes[i]); - if (!wm) - continue; - if ([device isEqual: wm->m_btd]) - break; - wm = nullptr; - } + for (int i = 0; i < MAX_WIIMOTES; i++) + { + wm = static_cast(WiimoteReal::g_wiimotes[i]); + if (!wm) + continue; + if ([device isEqual:wm->m_btd]) + break; + wm = nullptr; + } - if (wm == nullptr) { - ERROR_LOG(WIIMOTE, "Received packet for unknown Wiimote"); - return; - } + if (wm == nullptr) + { + ERROR_LOG(WIIMOTE, "Received packet for unknown Wiimote"); + return; + } - if (length > MAX_PAYLOAD) { - WARN_LOG(WIIMOTE, "Dropping packet for Wiimote %i, too large", - wm->GetIndex() + 1); - return; - } + if (length > MAX_PAYLOAD) + { + WARN_LOG(WIIMOTE, "Dropping packet for Wiimote %i, too large", wm->GetIndex() + 1); + return; + } - if (wm->m_inputlen != -1) { - WARN_LOG(WIIMOTE, "Dropping packet for Wiimote %i, queue full", - wm->GetIndex() + 1); - return; - } + if (wm->m_inputlen != -1) + { + WARN_LOG(WIIMOTE, "Dropping packet for Wiimote %i, queue full", wm->GetIndex() + 1); + return; + } - memcpy(wm->m_input, data, length); - wm->m_inputlen = length; + memcpy(wm->m_input, data, length); + wm->m_inputlen = length; - CFRunLoopStop(CFRunLoopGetCurrent()); + CFRunLoopStop(CFRunLoopGetCurrent()); } -- (void) l2capChannelClosed: (IOBluetoothL2CAPChannel *) l2capChannel +- (void)l2capChannelClosed:(IOBluetoothL2CAPChannel*)l2capChannel { - IOBluetoothDevice *device = [l2capChannel device]; - WiimoteReal::WiimoteDarwin *wm = nullptr; + IOBluetoothDevice* device = [l2capChannel device]; + WiimoteReal::WiimoteDarwin* wm = nullptr; - std::lock_guard lk(WiimoteReal::g_refresh_lock); + std::lock_guard lk(WiimoteReal::g_refresh_lock); - for (int i = 0; i < MAX_WIIMOTES; i++) - { - wm = static_cast(WiimoteReal::g_wiimotes[i]); - if (!wm) - continue; - if ([device isEqual: wm->m_btd]) - break; - wm = nullptr; - } + for (int i = 0; i < MAX_WIIMOTES; i++) + { + wm = static_cast(WiimoteReal::g_wiimotes[i]); + if (!wm) + continue; + if ([device isEqual:wm->m_btd]) + break; + wm = nullptr; + } - if (wm == nullptr) { - ERROR_LOG(WIIMOTE, "Channel for unknown Wiimote was closed"); - return; - } + if (wm == nullptr) + { + ERROR_LOG(WIIMOTE, "Channel for unknown Wiimote was closed"); + return; + } - WARN_LOG(WIIMOTE, "Lost channel to Wiimote %i", wm->GetIndex() + 1); + WARN_LOG(WIIMOTE, "Lost channel to Wiimote %i", wm->GetIndex() + 1); - wm->DisconnectInternal(); + wm->DisconnectInternal(); } @end diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp index 1c793258ad..1f4dcddb98 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp @@ -13,10 +13,10 @@ #include "Common/Thread.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/Host.h" #include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteEmu/WiimoteHid.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" +#include "Core/Host.h" #include "InputCommon/InputConfig.h" #include "SFML/Network.hpp" @@ -25,7 +25,6 @@ unsigned int g_wiimote_sources[MAX_BBMOTES]; namespace WiimoteReal { - void HandleFoundWiimotes(const std::vector&); void TryToConnectBalanceBoard(Wiimote*); void TryToConnectWiimote(Wiimote*); @@ -40,878 +39,872 @@ Wiimote* g_wiimotes[MAX_BBMOTES]; WiimoteScanner g_wiimote_scanner; Wiimote::Wiimote() - : m_index() - , m_last_input_report() - , m_channel(0) - , m_last_connect_request_counter(0) - , m_rumble_state() -{} + : m_index(), m_last_input_report(), m_channel(0), m_last_connect_request_counter(0), + m_rumble_state() +{ +} void Wiimote::Shutdown() { - StopThread(); - ClearReadQueue(); - m_write_reports.Clear(); + StopThread(); + ClearReadQueue(); + m_write_reports.Clear(); } // to be called from CPU thread void Wiimote::WriteReport(Report rpt) { - if (rpt.size() >= 3) - { - bool const new_rumble_state = (rpt[2] & 0x1) != 0; + if (rpt.size() >= 3) + { + bool const new_rumble_state = (rpt[2] & 0x1) != 0; - // If this is a rumble report and the rumble state didn't change, ignore. - if (WM_RUMBLE == rpt[1] && new_rumble_state == m_rumble_state) - return; + // If this is a rumble report and the rumble state didn't change, ignore. + if (WM_RUMBLE == rpt[1] && new_rumble_state == m_rumble_state) + return; - m_rumble_state = new_rumble_state; - } + m_rumble_state = new_rumble_state; + } - m_write_reports.Push(std::move(rpt)); - IOWakeup(); + m_write_reports.Push(std::move(rpt)); + IOWakeup(); } // to be called from CPU thread void Wiimote::QueueReport(u8 rpt_id, const void* _data, unsigned int size) { - auto const data = static_cast(_data); + auto const data = static_cast(_data); - Report rpt(size + 2); - rpt[0] = WM_SET_REPORT | WM_BT_OUTPUT; - rpt[1] = rpt_id; - std::copy_n(data, size, rpt.begin() + 2); - WriteReport(std::move(rpt)); + Report rpt(size + 2); + rpt[0] = WM_SET_REPORT | WM_BT_OUTPUT; + rpt[1] = rpt_id; + std::copy_n(data, size, rpt.begin() + 2); + WriteReport(std::move(rpt)); } void Wiimote::DisableDataReporting() { - m_last_input_report.clear(); + m_last_input_report.clear(); - // This probably accomplishes nothing. - wm_report_mode rpt = {}; - rpt.mode = WM_REPORT_CORE; - rpt.all_the_time = 0; - rpt.continuous = 0; - rpt.rumble = 0; - QueueReport(WM_REPORT_MODE, &rpt, sizeof(rpt)); + // This probably accomplishes nothing. + wm_report_mode rpt = {}; + rpt.mode = WM_REPORT_CORE; + rpt.all_the_time = 0; + rpt.continuous = 0; + rpt.rumble = 0; + QueueReport(WM_REPORT_MODE, &rpt, sizeof(rpt)); } void Wiimote::EnableDataReporting(u8 mode) { - m_last_input_report.clear(); + m_last_input_report.clear(); - wm_report_mode rpt = {}; - rpt.mode = mode; - rpt.all_the_time = 1; - rpt.continuous = 1; - QueueReport(WM_REPORT_MODE, &rpt, sizeof(rpt)); + wm_report_mode rpt = {}; + rpt.mode = mode; + rpt.all_the_time = 1; + rpt.continuous = 1; + QueueReport(WM_REPORT_MODE, &rpt, sizeof(rpt)); } void Wiimote::SetChannel(u16 channel) { - m_channel = channel; + m_channel = channel; } void Wiimote::ClearReadQueue() { - Report rpt; + Report rpt; - // The "Clear" function isn't thread-safe :/ - while (m_read_reports.Pop(rpt)) - {} + // The "Clear" function isn't thread-safe :/ + while (m_read_reports.Pop(rpt)) + { + } } void Wiimote::ControlChannel(const u16 channel, const void* const data, const u32 size) { - // Check for custom communication - if (99 == channel) - { - EmuStop(); - } - else - { - InterruptChannel(channel, data, size); - const hid_packet* const hidp = (hid_packet*)data; - if (hidp->type == HID_TYPE_SET_REPORT) - { - u8 handshake_ok = HID_HANDSHAKE_SUCCESS; - Core::Callback_WiimoteInterruptChannel(m_index, channel, &handshake_ok, sizeof(handshake_ok)); - } - } + // Check for custom communication + if (99 == channel) + { + EmuStop(); + } + else + { + InterruptChannel(channel, data, size); + const hid_packet* const hidp = (hid_packet*)data; + if (hidp->type == HID_TYPE_SET_REPORT) + { + u8 handshake_ok = HID_HANDSHAKE_SUCCESS; + Core::Callback_WiimoteInterruptChannel(m_index, channel, &handshake_ok, sizeof(handshake_ok)); + } + } } void Wiimote::InterruptChannel(const u16 channel, const void* const _data, const u32 size) { - // first interrupt/control channel sent - if (channel != m_channel) - { - m_channel = channel; + // first interrupt/control channel sent + if (channel != m_channel) + { + m_channel = channel; - ClearReadQueue(); + ClearReadQueue(); - EmuStart(); - } + EmuStart(); + } - auto const data = static_cast(_data); - Report rpt(data, data + size); - WiimoteEmu::Wiimote* const wm = static_cast(::Wiimote::GetConfig()->GetController(m_index)); + auto const data = static_cast(_data); + Report rpt(data, data + size); + WiimoteEmu::Wiimote* const wm = + static_cast(::Wiimote::GetConfig()->GetController(m_index)); - // Convert output DATA packets to SET_REPORT packets. - // Nintendo Wiimotes work without this translation, but 3rd - // party ones don't. - if (rpt[0] == 0xa2) - { - rpt[0] = WM_SET_REPORT | WM_BT_OUTPUT; - } + // Convert output DATA packets to SET_REPORT packets. + // Nintendo Wiimotes work without this translation, but 3rd + // party ones don't. + if (rpt[0] == 0xa2) + { + rpt[0] = WM_SET_REPORT | WM_BT_OUTPUT; + } - // Disallow games from turning off all of the LEDs. - // It makes Wiimote connection status confusing. - if (rpt[1] == WM_LEDS) - { - auto& leds_rpt = *reinterpret_cast(&rpt[2]); - if (0 == leds_rpt.leds) - { - // Turn on ALL of the LEDs. - leds_rpt.leds = 0xf; - } - } - else if (rpt[1] == WM_WRITE_SPEAKER_DATA && - (!SConfig::GetInstance().m_WiimoteEnableSpeaker || - (!wm->m_status.speaker || wm->m_speaker_mute))) - { - // Translate speaker data reports into rumble reports. - rpt[1] = WM_RUMBLE; - // Keep only the rumble bit. - rpt[2] &= 0x1; - rpt.resize(3); - } + // Disallow games from turning off all of the LEDs. + // It makes Wiimote connection status confusing. + if (rpt[1] == WM_LEDS) + { + auto& leds_rpt = *reinterpret_cast(&rpt[2]); + if (0 == leds_rpt.leds) + { + // Turn on ALL of the LEDs. + leds_rpt.leds = 0xf; + } + } + else if (rpt[1] == WM_WRITE_SPEAKER_DATA && (!SConfig::GetInstance().m_WiimoteEnableSpeaker || + (!wm->m_status.speaker || wm->m_speaker_mute))) + { + // Translate speaker data reports into rumble reports. + rpt[1] = WM_RUMBLE; + // Keep only the rumble bit. + rpt[2] &= 0x1; + rpt.resize(3); + } - WriteReport(std::move(rpt)); + WriteReport(std::move(rpt)); } void Wiimote::Read() { - Report rpt(MAX_PAYLOAD); - auto const result = IORead(rpt.data()); + Report rpt(MAX_PAYLOAD); + auto const result = IORead(rpt.data()); - if (result > 0 && m_channel > 0) - { - if (SConfig::GetInstance().iBBDumpPort > 0 && - m_index == WIIMOTE_BALANCE_BOARD) - { - static sf::UdpSocket Socket; - Socket.send((char*)rpt.data(), - rpt.size(), - sf::IpAddress::LocalHost, - SConfig::GetInstance().iBBDumpPort); - } + if (result > 0 && m_channel > 0) + { + if (SConfig::GetInstance().iBBDumpPort > 0 && m_index == WIIMOTE_BALANCE_BOARD) + { + static sf::UdpSocket Socket; + Socket.send((char*)rpt.data(), rpt.size(), sf::IpAddress::LocalHost, + SConfig::GetInstance().iBBDumpPort); + } - // Add it to queue - rpt.resize(result); - m_read_reports.Push(std::move(rpt)); - } - else if (0 == result) - { - ERROR_LOG(WIIMOTE, "Wiimote::IORead failed. Disconnecting Wiimote %d.", m_index + 1); - DisconnectInternal(); - } + // Add it to queue + rpt.resize(result); + m_read_reports.Push(std::move(rpt)); + } + else if (0 == result) + { + ERROR_LOG(WIIMOTE, "Wiimote::IORead failed. Disconnecting Wiimote %d.", m_index + 1); + DisconnectInternal(); + } } void Wiimote::Write() { - if (m_write_reports.Empty()) - return; + if (m_write_reports.Empty()) + return; - Report const& rpt = m_write_reports.Front(); + Report const& rpt = m_write_reports.Front(); - if (SConfig::GetInstance().iBBDumpPort > 0 && m_index == WIIMOTE_BALANCE_BOARD) - { - static sf::UdpSocket Socket; - Socket.send((char*)rpt.data(), rpt.size(), sf::IpAddress::LocalHost, SConfig::GetInstance().iBBDumpPort); - } - IOWrite(rpt.data(), rpt.size()); + if (SConfig::GetInstance().iBBDumpPort > 0 && m_index == WIIMOTE_BALANCE_BOARD) + { + static sf::UdpSocket Socket; + Socket.send((char*)rpt.data(), rpt.size(), sf::IpAddress::LocalHost, + SConfig::GetInstance().iBBDumpPort); + } + IOWrite(rpt.data(), rpt.size()); - m_write_reports.Pop(); + m_write_reports.Pop(); - if (!m_write_reports.Empty()) - IOWakeup(); + if (!m_write_reports.Empty()) + IOWakeup(); } static bool IsDataReport(const Report& rpt) { - return rpt.size() >= 2 && rpt[1] >= WM_REPORT_CORE; + return rpt.size() >= 2 && rpt[1] >= WM_REPORT_CORE; } // Returns the next report that should be sent const Report& Wiimote::ProcessReadQueue() { - // Pop through the queued reports - while (m_read_reports.Pop(m_last_input_report)) - { - if (!IsDataReport(m_last_input_report)) - { - // A non-data report, use it. - return m_last_input_report; + // Pop through the queued reports + while (m_read_reports.Pop(m_last_input_report)) + { + if (!IsDataReport(m_last_input_report)) + { + // A non-data report, use it. + return m_last_input_report; - // Forget the last data report as it may be of the wrong type - // or contain outdated button data - // or it's not supposed to be sent at this time - // It's just easier to be correct this way and it's probably not horrible. - } - } + // Forget the last data report as it may be of the wrong type + // or contain outdated button data + // or it's not supposed to be sent at this time + // It's just easier to be correct this way and it's probably not horrible. + } + } - // If the last report wasn't a data report it's irrelevant. - if (!IsDataReport(m_last_input_report)) - m_last_input_report.clear(); + // If the last report wasn't a data report it's irrelevant. + if (!IsDataReport(m_last_input_report)) + m_last_input_report.clear(); - // If it was a data report, we repeat that until something else comes in. - return m_last_input_report; + // If it was a data report, we repeat that until something else comes in. + return m_last_input_report; } void Wiimote::Update() { - if (!IsConnected()) - { - HandleWiimoteDisconnect(m_index); - return; - } + if (!IsConnected()) + { + HandleWiimoteDisconnect(m_index); + return; + } - // Pop through the queued reports - const Report& rpt = ProcessReadQueue(); + // Pop through the queued reports + const Report& rpt = ProcessReadQueue(); - // Send the report - if (!rpt.empty() && m_channel > 0) - { - Core::Callback_WiimoteInterruptChannel(m_index, m_channel, - rpt.data(), (u32)rpt.size()); - } + // Send the report + if (!rpt.empty() && m_channel > 0) + { + Core::Callback_WiimoteInterruptChannel(m_index, m_channel, rpt.data(), (u32)rpt.size()); + } } void Wiimote::ConnectOnInput() { - if (m_last_connect_request_counter > 0) - { - --m_last_connect_request_counter; - return; - } + if (m_last_connect_request_counter > 0) + { + --m_last_connect_request_counter; + return; + } - const Report& rpt = ProcessReadQueue(); - if (rpt.size() >= 4) - { - switch (rpt[1]) - { - case WM_REPORT_CORE: - case WM_REPORT_CORE_ACCEL: - case WM_REPORT_CORE_EXT8: - case WM_REPORT_CORE_ACCEL_IR12: - case WM_REPORT_CORE_EXT19: - case WM_REPORT_CORE_ACCEL_EXT16: - case WM_REPORT_CORE_IR10_EXT9: - case WM_REPORT_CORE_ACCEL_IR10_EXT6: - case WM_REPORT_INTERLEAVE1: - case WM_REPORT_INTERLEAVE2: - // check any button without checking accelerometer data - if ((rpt[2] & 0x1F) != 0 || (rpt[3] & 0x9F) != 0) - { - Host_ConnectWiimote(m_index, true); - // see WiimoteEmu::Wiimote::ConnectOnInput(), same idea here - m_last_connect_request_counter = 100; - } - break; - default: - break; - } - } + const Report& rpt = ProcessReadQueue(); + if (rpt.size() >= 4) + { + switch (rpt[1]) + { + case WM_REPORT_CORE: + case WM_REPORT_CORE_ACCEL: + case WM_REPORT_CORE_EXT8: + case WM_REPORT_CORE_ACCEL_IR12: + case WM_REPORT_CORE_EXT19: + case WM_REPORT_CORE_ACCEL_EXT16: + case WM_REPORT_CORE_IR10_EXT9: + case WM_REPORT_CORE_ACCEL_IR10_EXT6: + case WM_REPORT_INTERLEAVE1: + case WM_REPORT_INTERLEAVE2: + // check any button without checking accelerometer data + if ((rpt[2] & 0x1F) != 0 || (rpt[3] & 0x9F) != 0) + { + Host_ConnectWiimote(m_index, true); + // see WiimoteEmu::Wiimote::ConnectOnInput(), same idea here + m_last_connect_request_counter = 100; + } + break; + default: + break; + } + } } void Wiimote::Prepare() { - m_need_prepare.store(true); - IOWakeup(); + m_need_prepare.store(true); + IOWakeup(); } bool Wiimote::PrepareOnThread() { - // core buttons, no continuous reporting - u8 static const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REPORT_MODE, 0, WM_REPORT_CORE}; + // core buttons, no continuous reporting + u8 static const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REPORT_MODE, 0, WM_REPORT_CORE}; - // Set the active LEDs and turn on rumble. - u8 static led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_LEDS, 0}; - led_report[2] = u8(WIIMOTE_LED_1 << (m_index%WIIMOTE_BALANCE_BOARD) | 0x1); + // Set the active LEDs and turn on rumble. + u8 static led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_LEDS, 0}; + led_report[2] = u8(WIIMOTE_LED_1 << (m_index % WIIMOTE_BALANCE_BOARD) | 0x1); - // Turn off rumble - u8 static const rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_RUMBLE, 0}; + // Turn off rumble + u8 static const rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_RUMBLE, 0}; - // Request status report - u8 static const req_status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0}; - // TODO: check for sane response? + // Request status report + u8 static const req_status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0}; + // TODO: check for sane response? - return (IOWrite(mode_report, sizeof(mode_report)) && - IOWrite(led_report, sizeof(led_report)) && - (Common::SleepCurrentThread(200), IOWrite(rumble_report, sizeof(rumble_report))) && - IOWrite(req_status_report, sizeof(req_status_report))); + return (IOWrite(mode_report, sizeof(mode_report)) && IOWrite(led_report, sizeof(led_report)) && + (Common::SleepCurrentThread(200), IOWrite(rumble_report, sizeof(rumble_report))) && + IOWrite(req_status_report, sizeof(req_status_report))); } void Wiimote::EmuStart() { - DisableDataReporting(); - EnablePowerAssertionInternal(); + DisableDataReporting(); + EnablePowerAssertionInternal(); } void Wiimote::EmuStop() { - m_channel = 0; + m_channel = 0; - DisableDataReporting(); + DisableDataReporting(); - NOTICE_LOG(WIIMOTE, "Stopping Wiimote data reporting."); + NOTICE_LOG(WIIMOTE, "Stopping Wiimote data reporting."); - DisablePowerAssertionInternal(); + DisablePowerAssertionInternal(); } void Wiimote::EmuResume() { - WiimoteEmu::Wiimote* const wm = static_cast(::Wiimote::GetConfig()->GetController(m_index)); + WiimoteEmu::Wiimote* const wm = + static_cast(::Wiimote::GetConfig()->GetController(m_index)); - m_last_input_report.clear(); + m_last_input_report.clear(); - wm_report_mode rpt = {}; - rpt.mode = wm->m_reporting_mode; - rpt.all_the_time = 1; - rpt.continuous = 1; - QueueReport(WM_REPORT_MODE, &rpt, sizeof(rpt)); + wm_report_mode rpt = {}; + rpt.mode = wm->m_reporting_mode; + rpt.all_the_time = 1; + rpt.continuous = 1; + QueueReport(WM_REPORT_MODE, &rpt, sizeof(rpt)); - NOTICE_LOG(WIIMOTE, "Resuming Wiimote data reporting."); + NOTICE_LOG(WIIMOTE, "Resuming Wiimote data reporting."); - EnablePowerAssertionInternal(); + EnablePowerAssertionInternal(); } void Wiimote::EmuPause() { - m_last_input_report.clear(); + m_last_input_report.clear(); - wm_report_mode rpt = {}; - rpt.mode = WM_REPORT_CORE; - rpt.all_the_time = 0; - rpt.continuous = 0; - QueueReport(WM_REPORT_MODE, &rpt, sizeof(rpt)); + wm_report_mode rpt = {}; + rpt.mode = WM_REPORT_CORE; + rpt.all_the_time = 0; + rpt.continuous = 0; + QueueReport(WM_REPORT_MODE, &rpt, sizeof(rpt)); - NOTICE_LOG(WIIMOTE, "Pausing Wiimote data reporting."); + NOTICE_LOG(WIIMOTE, "Pausing Wiimote data reporting."); - DisablePowerAssertionInternal(); + DisablePowerAssertionInternal(); } static unsigned int CalculateConnectedWiimotes() { - unsigned int connected_wiimotes = 0; - for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) - if (g_wiimotes[i]) - ++connected_wiimotes; + unsigned int connected_wiimotes = 0; + for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) + if (g_wiimotes[i]) + ++connected_wiimotes; - return connected_wiimotes; + return connected_wiimotes; } static unsigned int CalculateWantedWiimotes() { - // Figure out how many real Wiimotes are required - unsigned int wanted_wiimotes = 0; - for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) - if (WIIMOTE_SRC_REAL & g_wiimote_sources[i] && !g_wiimotes[i]) - ++wanted_wiimotes; + // Figure out how many real Wiimotes are required + unsigned int wanted_wiimotes = 0; + for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) + if (WIIMOTE_SRC_REAL & g_wiimote_sources[i] && !g_wiimotes[i]) + ++wanted_wiimotes; - return wanted_wiimotes; + return wanted_wiimotes; } static unsigned int CalculateWantedBB() { - unsigned int wanted_bb = 0; - if (WIIMOTE_SRC_REAL & g_wiimote_sources[WIIMOTE_BALANCE_BOARD] && !g_wiimotes[WIIMOTE_BALANCE_BOARD]) - ++wanted_bb; - return wanted_bb; + unsigned int wanted_bb = 0; + if (WIIMOTE_SRC_REAL & g_wiimote_sources[WIIMOTE_BALANCE_BOARD] && + !g_wiimotes[WIIMOTE_BALANCE_BOARD]) + ++wanted_bb; + return wanted_bb; } void WiimoteScanner::WantWiimotes(bool do_want) { - m_want_wiimotes.store(do_want); + m_want_wiimotes.store(do_want); } - void WiimoteScanner::WantBB(bool do_want) { - m_want_bb.store(do_want); + m_want_bb.store(do_want); } void WiimoteScanner::StartScanning() { - if (!m_run_thread.load()) - { - m_run_thread.store(true); - m_scan_thread = std::thread(&WiimoteScanner::ThreadFunc, this); - } + if (!m_run_thread.load()) + { + m_run_thread.store(true); + m_scan_thread = std::thread(&WiimoteScanner::ThreadFunc, this); + } } void WiimoteScanner::StopScanning() { - m_run_thread.store(false); - if (m_scan_thread.joinable()) - { - m_scan_thread.join(); - } + m_run_thread.store(false); + if (m_scan_thread.joinable()) + { + m_scan_thread.join(); + } } static void CheckForDisconnectedWiimotes() { - std::lock_guard lk(g_refresh_lock); + std::lock_guard lk(g_refresh_lock); - for (unsigned int i = 0; i < MAX_BBMOTES; ++i) - if (g_wiimotes[i] && !g_wiimotes[i]->IsConnected()) - HandleWiimoteDisconnect(i); + for (unsigned int i = 0; i < MAX_BBMOTES; ++i) + if (g_wiimotes[i] && !g_wiimotes[i]->IsConnected()) + HandleWiimoteDisconnect(i); } void WiimoteScanner::ThreadFunc() { - Common::SetCurrentThreadName("Wiimote Scanning Thread"); + Common::SetCurrentThreadName("Wiimote Scanning Thread"); - NOTICE_LOG(WIIMOTE, "Wiimote scanning has started."); + NOTICE_LOG(WIIMOTE, "Wiimote scanning has started."); - while (m_run_thread.load()) - { - std::vector found_wiimotes; - Wiimote* found_board = nullptr; + while (m_run_thread.load()) + { + std::vector found_wiimotes; + Wiimote* found_board = nullptr; - //NOTICE_LOG(WIIMOTE, "In loop"); + // NOTICE_LOG(WIIMOTE, "In loop"); - if (m_want_wiimotes.load() || m_want_bb.load()) - { - FindWiimotes(found_wiimotes, found_board); - } - else - { - // Does stuff needed to detect disconnects on Windows - Update(); - } + if (m_want_wiimotes.load() || m_want_bb.load()) + { + FindWiimotes(found_wiimotes, found_board); + } + else + { + // Does stuff needed to detect disconnects on Windows + Update(); + } - //NOTICE_LOG(WIIMOTE, "After update"); + // NOTICE_LOG(WIIMOTE, "After update"); - // TODO: this is a fairly lame place for this - CheckForDisconnectedWiimotes(); + // TODO: this is a fairly lame place for this + CheckForDisconnectedWiimotes(); - if (m_want_wiimotes.load()) - HandleFoundWiimotes(found_wiimotes); + if (m_want_wiimotes.load()) + HandleFoundWiimotes(found_wiimotes); - if (m_want_bb.load() && found_board) - TryToConnectBalanceBoard(found_board); + if (m_want_bb.load() && found_board) + TryToConnectBalanceBoard(found_board); - //std::this_thread::yield(); - Common::SleepCurrentThread(500); - } + // std::this_thread::yield(); + Common::SleepCurrentThread(500); + } - NOTICE_LOG(WIIMOTE, "Wiimote scanning has stopped."); + NOTICE_LOG(WIIMOTE, "Wiimote scanning has stopped."); } bool Wiimote::Connect(int index) { - m_index = index; - m_need_prepare.store(true); + m_index = index; + m_need_prepare.store(true); - if (!m_run_thread.load()) - { - m_thread_ready.store(false); - StartThread(); - WaitReady(); - } - return IsConnected(); + if (!m_run_thread.load()) + { + m_thread_ready.store(false); + StartThread(); + WaitReady(); + } + return IsConnected(); } void Wiimote::StartThread() { - m_run_thread.store(true); - m_wiimote_thread = std::thread(&Wiimote::ThreadFunc, this); + m_run_thread.store(true); + m_wiimote_thread = std::thread(&Wiimote::ThreadFunc, this); } void Wiimote::StopThread() { - m_run_thread.store(false); - IOWakeup(); - if (m_wiimote_thread.joinable()) - m_wiimote_thread.join(); + m_run_thread.store(false); + IOWakeup(); + if (m_wiimote_thread.joinable()) + m_wiimote_thread.join(); } void Wiimote::SetReady() { - if (!m_thread_ready.load()) - { - m_thread_ready.store(true); - m_thread_ready_cond.notify_all(); - } + if (!m_thread_ready.load()) + { + m_thread_ready.store(true); + m_thread_ready_cond.notify_all(); + } } void Wiimote::WaitReady() { - std::unique_lock lock(m_thread_ready_mutex); - while (!m_thread_ready.load()) - { - m_thread_ready_cond.wait(lock); - } + std::unique_lock lock(m_thread_ready_mutex); + while (!m_thread_ready.load()) + { + m_thread_ready_cond.wait(lock); + } } void Wiimote::ThreadFunc() { - Common::SetCurrentThreadName("Wiimote Device Thread"); + Common::SetCurrentThreadName("Wiimote Device Thread"); - bool ok = ConnectInternal(); + bool ok = ConnectInternal(); - if (!ok) - { - // try again, it might take a moment to settle - Common::SleepCurrentThread(100); - ok = ConnectInternal(); - } + if (!ok) + { + // try again, it might take a moment to settle + Common::SleepCurrentThread(100); + ok = ConnectInternal(); + } - SetReady(); + SetReady(); - if (!ok) - { - return; - } + if (!ok) + { + return; + } - // main loop - while (IsConnected() && m_run_thread.load()) - { - if (m_need_prepare.load()) - { - m_need_prepare.store(false); - if (!PrepareOnThread()) - { - ERROR_LOG(WIIMOTE, "Wiimote::PrepareOnThread failed. Disconnecting Wiimote %d.", m_index + 1); - break; - } - } - Write(); - Read(); - } + // main loop + while (IsConnected() && m_run_thread.load()) + { + if (m_need_prepare.load()) + { + m_need_prepare.store(false); + if (!PrepareOnThread()) + { + ERROR_LOG(WIIMOTE, "Wiimote::PrepareOnThread failed. Disconnecting Wiimote %d.", + m_index + 1); + break; + } + } + Write(); + Read(); + } - DisconnectInternal(); + DisconnectInternal(); } int Wiimote::GetIndex() const { - return m_index; + return m_index; } void LoadSettings() { - std::string ini_filename = File::GetUserPath(D_CONFIG_IDX) + WIIMOTE_INI_NAME ".ini"; + std::string ini_filename = File::GetUserPath(D_CONFIG_IDX) + WIIMOTE_INI_NAME ".ini"; - IniFile inifile; - inifile.Load(ini_filename); + IniFile inifile; + inifile.Load(ini_filename); - for (unsigned int i=0; i lk(g_refresh_lock); + std::lock_guard lk(g_refresh_lock); - g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes()); - g_wiimote_scanner.WantBB(0 != CalculateWantedBB()); + g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes()); + g_wiimote_scanner.WantBB(0 != CalculateWantedBB()); - // wait for connection because it should exist before state load - if (wait) - { - int timeout = 100; - std::vector found_wiimotes; - Wiimote* found_board = nullptr; - g_wiimote_scanner.FindWiimotes(found_wiimotes, found_board); - if (SConfig::GetInstance().m_WiimoteContinuousScanning) - { - while (CalculateWantedWiimotes() && CalculateConnectedWiimotes() < found_wiimotes.size() && timeout) - { - Common::SleepCurrentThread(100); - timeout--; - } - } - } + // wait for connection because it should exist before state load + if (wait) + { + int timeout = 100; + std::vector found_wiimotes; + Wiimote* found_board = nullptr; + g_wiimote_scanner.FindWiimotes(found_wiimotes, found_board); + if (SConfig::GetInstance().m_WiimoteContinuousScanning) + { + while (CalculateWantedWiimotes() && CalculateConnectedWiimotes() < found_wiimotes.size() && + timeout) + { + Common::SleepCurrentThread(100); + timeout--; + } + } + } - if (g_real_wiimotes_initialized) - return; + if (g_real_wiimotes_initialized) + return; - NOTICE_LOG(WIIMOTE, "WiimoteReal::Initialize"); + NOTICE_LOG(WIIMOTE, "WiimoteReal::Initialize"); - g_real_wiimotes_initialized = true; + g_real_wiimotes_initialized = true; } // called on emulation shutdown void Stop() { - for (auto& wiimote : g_wiimotes) - if (wiimote && wiimote->IsConnected()) - wiimote->EmuStop(); + for (auto& wiimote : g_wiimotes) + if (wiimote && wiimote->IsConnected()) + wiimote->EmuStop(); } // called when the Dolphin app exits void Shutdown() { - g_wiimote_scanner.StopScanning(); + g_wiimote_scanner.StopScanning(); - std::lock_guard lk(g_refresh_lock); + std::lock_guard lk(g_refresh_lock); - if (!g_real_wiimotes_initialized) - return; + if (!g_real_wiimotes_initialized) + return; - NOTICE_LOG(WIIMOTE, "WiimoteReal::Shutdown"); + NOTICE_LOG(WIIMOTE, "WiimoteReal::Shutdown"); - g_real_wiimotes_initialized = false; + g_real_wiimotes_initialized = false; - for (unsigned int i = 0; i < MAX_BBMOTES; ++i) - HandleWiimoteDisconnect(i); + for (unsigned int i = 0; i < MAX_BBMOTES; ++i) + HandleWiimoteDisconnect(i); } void Resume() { - for (auto& wiimote : g_wiimotes) - if (wiimote && wiimote->IsConnected()) - wiimote->EmuResume(); + for (auto& wiimote : g_wiimotes) + if (wiimote && wiimote->IsConnected()) + wiimote->EmuResume(); } void Pause() { - for (auto& wiimote : g_wiimotes) - if (wiimote && wiimote->IsConnected()) - wiimote->EmuPause(); + for (auto& wiimote : g_wiimotes) + if (wiimote && wiimote->IsConnected()) + wiimote->EmuPause(); } void ChangeWiimoteSource(unsigned int index, int source) { - { - std::lock_guard lk(g_refresh_lock); - g_wiimote_sources[index] = source; - g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes()); - g_wiimote_scanner.WantBB(0 != CalculateWantedBB()); - // kill real connection (or swap to different slot) - DoneWithWiimote(index); - } + { + std::lock_guard lk(g_refresh_lock); + g_wiimote_sources[index] = source; + g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes()); + g_wiimote_scanner.WantBB(0 != CalculateWantedBB()); + // kill real connection (or swap to different slot) + DoneWithWiimote(index); + } - // reconnect to the emulator - Host_ConnectWiimote(index, false); - if (WIIMOTE_SRC_EMU & source) - Host_ConnectWiimote(index, true); + // reconnect to the emulator + Host_ConnectWiimote(index, false); + if (WIIMOTE_SRC_EMU & source) + Host_ConnectWiimote(index, true); } static bool TryToConnectWiimoteN(Wiimote* wm, unsigned int i) { - if (WIIMOTE_SRC_REAL & g_wiimote_sources[i] && !g_wiimotes[i]) - { - if (wm->Connect(i)) - { - NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i.", i + 1); - g_wiimotes[i] = wm; - Host_ConnectWiimote(i, true); - } - return true; - } - return false; + if (WIIMOTE_SRC_REAL & g_wiimote_sources[i] && !g_wiimotes[i]) + { + if (wm->Connect(i)) + { + NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i.", i + 1); + g_wiimotes[i] = wm; + Host_ConnectWiimote(i, true); + } + return true; + } + return false; } void TryToConnectWiimote(Wiimote* wm) { - std::unique_lock lk(g_refresh_lock); + std::unique_lock lk(g_refresh_lock); - for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) - { - if (TryToConnectWiimoteN(wm, i)) - { - wm = nullptr; - break; - } - } + for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) + { + if (TryToConnectWiimoteN(wm, i)) + { + wm = nullptr; + break; + } + } - g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes()); + g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes()); - lk.unlock(); + lk.unlock(); - delete wm; + delete wm; } void TryToConnectBalanceBoard(Wiimote* wm) { - std::unique_lock lk(g_refresh_lock); + std::unique_lock lk(g_refresh_lock); - if (TryToConnectWiimoteN(wm, WIIMOTE_BALANCE_BOARD)) - { - wm = nullptr; - } + if (TryToConnectWiimoteN(wm, WIIMOTE_BALANCE_BOARD)) + { + wm = nullptr; + } - g_wiimote_scanner.WantBB(0 != CalculateWantedBB()); + g_wiimote_scanner.WantBB(0 != CalculateWantedBB()); - lk.unlock(); + lk.unlock(); - delete wm; + delete wm; } void DoneWithWiimote(int index) { - std::lock_guard lk(g_refresh_lock); + std::lock_guard lk(g_refresh_lock); - Wiimote* wm = g_wiimotes[index]; + Wiimote* wm = g_wiimotes[index]; - if (wm) - { - g_wiimotes[index] = nullptr; - // First see if we can use this real Wiimote in another slot. - TryToConnectWiimote(wm); - } + if (wm) + { + g_wiimotes[index] = nullptr; + // First see if we can use this real Wiimote in another slot. + TryToConnectWiimote(wm); + } - // else, just disconnect the Wiimote - HandleWiimoteDisconnect(index); + // else, just disconnect the Wiimote + HandleWiimoteDisconnect(index); } void HandleWiimoteDisconnect(int index) { - Wiimote* wm = nullptr; + Wiimote* wm = nullptr; - { - std::lock_guard lk(g_refresh_lock); + { + std::lock_guard lk(g_refresh_lock); - std::swap(wm, g_wiimotes[index]); - g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes()); - g_wiimote_scanner.WantBB(0 != CalculateWantedBB()); - } + std::swap(wm, g_wiimotes[index]); + g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes()); + g_wiimote_scanner.WantBB(0 != CalculateWantedBB()); + } - if (wm) - { - delete wm; - NOTICE_LOG(WIIMOTE, "Disconnected Wiimote %i.", index + 1); - } + if (wm) + { + delete wm; + NOTICE_LOG(WIIMOTE, "Disconnected Wiimote %i.", index + 1); + } } void HandleFoundWiimotes(const std::vector& wiimotes) { - std::for_each(wiimotes.begin(), wiimotes.end(), TryToConnectWiimote); + std::for_each(wiimotes.begin(), wiimotes.end(), TryToConnectWiimote); } // This is called from the GUI thread void Refresh() { - g_wiimote_scanner.StopScanning(); + g_wiimote_scanner.StopScanning(); - { - std::unique_lock lk(g_refresh_lock); - std::vector found_wiimotes; - Wiimote* found_board = nullptr; + { + std::unique_lock lk(g_refresh_lock); + std::vector found_wiimotes; + Wiimote* found_board = nullptr; - if (0 != CalculateWantedWiimotes() || 0 != CalculateWantedBB()) - { - // Don't hang Dolphin when searching - lk.unlock(); - g_wiimote_scanner.FindWiimotes(found_wiimotes, found_board); - lk.lock(); - } + if (0 != CalculateWantedWiimotes() || 0 != CalculateWantedBB()) + { + // Don't hang Dolphin when searching + lk.unlock(); + g_wiimote_scanner.FindWiimotes(found_wiimotes, found_board); + lk.lock(); + } - CheckForDisconnectedWiimotes(); + CheckForDisconnectedWiimotes(); - // Brief rumble for already connected Wiimotes. - // Don't do this for Balance Board as it doesn't have rumble anyway. - for (int i = 0; i < MAX_WIIMOTES; ++i) - { - if (g_wiimotes[i]) - { - g_wiimotes[i]->Prepare(); - } - } + // Brief rumble for already connected Wiimotes. + // Don't do this for Balance Board as it doesn't have rumble anyway. + for (int i = 0; i < MAX_WIIMOTES; ++i) + { + if (g_wiimotes[i]) + { + g_wiimotes[i]->Prepare(); + } + } - HandleFoundWiimotes(found_wiimotes); - if (found_board) - TryToConnectBalanceBoard(found_board); - } + HandleFoundWiimotes(found_wiimotes); + if (found_board) + TryToConnectBalanceBoard(found_board); + } - Initialize(); + Initialize(); } void InterruptChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size) { - std::lock_guard lk(g_refresh_lock); - if (g_wiimotes[_WiimoteNumber]) - g_wiimotes[_WiimoteNumber]->InterruptChannel(_channelID, _pData, _Size); + std::lock_guard lk(g_refresh_lock); + if (g_wiimotes[_WiimoteNumber]) + g_wiimotes[_WiimoteNumber]->InterruptChannel(_channelID, _pData, _Size); } void ControlChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size) { - std::lock_guard lk(g_refresh_lock); + std::lock_guard lk(g_refresh_lock); - if (g_wiimotes[_WiimoteNumber]) - g_wiimotes[_WiimoteNumber]->ControlChannel(_channelID, _pData, _Size); + if (g_wiimotes[_WiimoteNumber]) + g_wiimotes[_WiimoteNumber]->ControlChannel(_channelID, _pData, _Size); } - // Read the Wiimote once void Update(int _WiimoteNumber) { - // Try to get a lock and return without doing anything if we fail - // This avoids deadlocks when adding a Wiimote during continuous scan - if(!g_refresh_lock.try_lock()) - return; + // Try to get a lock and return without doing anything if we fail + // This avoids deadlocks when adding a Wiimote during continuous scan + if (!g_refresh_lock.try_lock()) + return; - if (g_wiimotes[_WiimoteNumber]) - g_wiimotes[_WiimoteNumber]->Update(); + if (g_wiimotes[_WiimoteNumber]) + g_wiimotes[_WiimoteNumber]->Update(); - // Wiimote::Update() may remove the Wiimote if it was disconnected. - if (!g_wiimotes[_WiimoteNumber]) - { - Host_ConnectWiimote(_WiimoteNumber, false); - } - g_refresh_lock.unlock(); + // Wiimote::Update() may remove the Wiimote if it was disconnected. + if (!g_wiimotes[_WiimoteNumber]) + { + Host_ConnectWiimote(_WiimoteNumber, false); + } + g_refresh_lock.unlock(); } void ConnectOnInput(int _WiimoteNumber) { - // see Update() above - if (!g_refresh_lock.try_lock()) - return; + // see Update() above + if (!g_refresh_lock.try_lock()) + return; - if (g_wiimotes[_WiimoteNumber]) - g_wiimotes[_WiimoteNumber]->ConnectOnInput(); + if (g_wiimotes[_WiimoteNumber]) + g_wiimotes[_WiimoteNumber]->ConnectOnInput(); - g_refresh_lock.unlock(); + g_refresh_lock.unlock(); } void StateChange(EMUSTATE_CHANGE newState) { - //std::lock_guard lk(g_refresh_lock); + // std::lock_guard lk(g_refresh_lock); - // TODO: disable/enable auto reporting, maybe + // TODO: disable/enable auto reporting, maybe } bool IsValidBluetoothName(const std::string& name) { - return - "Nintendo RVL-CNT-01" == name || - "Nintendo RVL-CNT-01-TR" == name || - IsBalanceBoardName(name); + return "Nintendo RVL-CNT-01" == name || "Nintendo RVL-CNT-01-TR" == name || + IsBalanceBoardName(name); } bool IsBalanceBoardName(const std::string& name) { - return - "Nintendo RVL-WBC-01" == name; + return "Nintendo RVL-WBC-01" == name; } -}; // end of namespace +}; // end of namespace diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h index 60c5e38bbb..b0abbb0c8e 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h @@ -23,132 +23,131 @@ typedef std::vector Report; namespace WiimoteReal { - class Wiimote : NonCopyable { public: - virtual ~Wiimote() {} - // This needs to be called in derived destructors! - void Shutdown(); + virtual ~Wiimote() {} + // This needs to be called in derived destructors! + void Shutdown(); - void ControlChannel(const u16 channel, const void* const data, const u32 size); - void InterruptChannel(const u16 channel, const void* const data, const u32 size); - void Update(); - void ConnectOnInput(); + void ControlChannel(const u16 channel, const void* const data, const u32 size); + void InterruptChannel(const u16 channel, const void* const data, const u32 size); + void Update(); + void ConnectOnInput(); - const Report& ProcessReadQueue(); + const Report& ProcessReadQueue(); - void Read(); - void Write(); + void Read(); + void Write(); - void StartThread(); - void StopThread(); + void StartThread(); + void StopThread(); - // "handshake" / stop packets - void EmuStart(); - void EmuStop(); - void EmuResume(); - void EmuPause(); + // "handshake" / stop packets + void EmuStart(); + void EmuStop(); + void EmuResume(); + void EmuPause(); - virtual void EnablePowerAssertionInternal() {} - virtual void DisablePowerAssertionInternal() {} + virtual void EnablePowerAssertionInternal() {} + virtual void DisablePowerAssertionInternal() {} + // connecting and disconnecting from physical devices + // (using address inserted by FindWiimotes) + // these are called from the Wiimote's thread. + virtual bool ConnectInternal() = 0; + virtual void DisconnectInternal() = 0; - // connecting and disconnecting from physical devices - // (using address inserted by FindWiimotes) - // these are called from the Wiimote's thread. - virtual bool ConnectInternal() = 0; - virtual void DisconnectInternal() = 0; + bool Connect(int index); - bool Connect(int index); + // TODO: change to something like IsRelevant + virtual bool IsConnected() const = 0; - // TODO: change to something like IsRelevant - virtual bool IsConnected() const = 0; + void Prepare(); + bool PrepareOnThread(); - void Prepare(); - bool PrepareOnThread(); + void DisableDataReporting(); + void EnableDataReporting(u8 mode); + void SetChannel(u16 channel); - void DisableDataReporting(); - void EnableDataReporting(u8 mode); - void SetChannel(u16 channel); + void QueueReport(u8 rpt_id, const void* data, unsigned int size); - void QueueReport(u8 rpt_id, const void* data, unsigned int size); - - int GetIndex() const; + int GetIndex() const; protected: - Wiimote(); - int m_index; - Report m_last_input_report; - u16 m_channel; - u8 m_last_connect_request_counter; + Wiimote(); + int m_index; + Report m_last_input_report; + u16 m_channel; + u8 m_last_connect_request_counter; private: - void ClearReadQueue(); - void WriteReport(Report rpt); + void ClearReadQueue(); + void WriteReport(Report rpt); - virtual int IORead(u8* buf) = 0; - virtual int IOWrite(u8 const* buf, size_t len) = 0; - virtual void IOWakeup() = 0; + virtual int IORead(u8* buf) = 0; + virtual int IOWrite(u8 const* buf, size_t len) = 0; + virtual void IOWakeup() = 0; - void ThreadFunc(); - void SetReady(); - void WaitReady(); + void ThreadFunc(); + void SetReady(); + void WaitReady(); - bool m_rumble_state; + bool m_rumble_state; - std::thread m_wiimote_thread; - // Whether to keep running the thread. - std::atomic m_run_thread {false}; - // Whether to call PrepareOnThread. - std::atomic m_need_prepare {false}; - // Whether the thread has finished ConnectInternal. - std::atomic m_thread_ready {false}; - std::mutex m_thread_ready_mutex; - std::condition_variable m_thread_ready_cond; + std::thread m_wiimote_thread; + // Whether to keep running the thread. + std::atomic m_run_thread{false}; + // Whether to call PrepareOnThread. + std::atomic m_need_prepare{false}; + // Whether the thread has finished ConnectInternal. + std::atomic m_thread_ready{false}; + std::mutex m_thread_ready_mutex; + std::condition_variable m_thread_ready_cond; - Common::FifoQueue m_read_reports; - Common::FifoQueue m_write_reports; + Common::FifoQueue m_read_reports; + Common::FifoQueue m_write_reports; }; class WiimoteScanner { public: - WiimoteScanner(); - ~WiimoteScanner(); + WiimoteScanner(); + ~WiimoteScanner(); - bool IsReady() const; + bool IsReady() const; - void WantWiimotes(bool do_want); - void WantBB(bool do_want); + void WantWiimotes(bool do_want); + void WantBB(bool do_want); - void StartScanning(); - void StopScanning(); + void StartScanning(); + void StopScanning(); - void FindWiimotes(std::vector&, Wiimote*&); + void FindWiimotes(std::vector&, Wiimote*&); - // function called when not looking for more Wiimotes - void Update(); + // function called when not looking for more Wiimotes + void Update(); private: - void ThreadFunc(); + void ThreadFunc(); - std::thread m_scan_thread; + std::thread m_scan_thread; - std::atomic m_run_thread {false}; - std::atomic m_want_wiimotes {false}; - std::atomic m_want_bb {false}; + std::atomic m_run_thread{false}; + std::atomic m_want_wiimotes{false}; + std::atomic m_want_bb{false}; #if defined(_WIN32) - void CheckDeviceType(std::basic_string &devicepath, WinWriteMethod &write_method, bool &real_wiimote, bool &is_bb); + void CheckDeviceType(std::basic_string& devicepath, WinWriteMethod& write_method, + bool& real_wiimote, bool& is_bb); #elif defined(__linux__) && HAVE_BLUEZ - int device_id; - int device_sock; + int device_id; + int device_sock; #endif }; extern std::recursive_mutex g_refresh_lock; extern WiimoteScanner g_wiimote_scanner; -extern Wiimote *g_wiimotes[MAX_BBMOTES]; +extern Wiimote* g_wiimotes[MAX_BBMOTES]; void InterruptChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size); void ControlChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size); @@ -165,4 +164,4 @@ bool IsBalanceBoardName(const std::string& name); void InitAdapterClass(); #endif -} // WiimoteReal +} // WiimoteReal diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h b/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h index 856d5858df..8df3838141 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h @@ -5,59 +5,59 @@ #pragma once #ifdef _WIN32 - #include +#include #elif defined(__APPLE__) - // Work around an Apple bug: for some reason, IOBluetooth.h errors on - // inclusion in Mavericks, but only in Objective-C++ C++11 mode. I filed - // this as ; in the meantime... - #import - #undef NS_ENUM_AVAILABLE - #define NS_ENUM_AVAILABLE(...) - // end hack - #import - #include - #include +// Work around an Apple bug: for some reason, IOBluetooth.h errors on +// inclusion in Mavericks, but only in Objective-C++ C++11 mode. I filed +// this as ; in the meantime... +#import +#undef NS_ENUM_AVAILABLE +#define NS_ENUM_AVAILABLE(...) +// end hack +#import +#include +#include #elif defined(__linux__) && HAVE_BLUEZ - #include +#include #endif // Wiimote internal codes // Communication channels -#define WM_OUTPUT_CHANNEL 0x11 -#define WM_INPUT_CHANNEL 0x13 +#define WM_OUTPUT_CHANNEL 0x11 +#define WM_INPUT_CHANNEL 0x13 // The 4 most significant bits of the first byte of an outgoing command must be // 0x50 if sending on the command channel and 0xA0 if sending on the interrupt // channel. On Mac and Linux we use interrupt channel; on Windows, command. #ifdef _WIN32 -#define WM_SET_REPORT 0x50 +#define WM_SET_REPORT 0x50 #else -#define WM_SET_REPORT 0xA0 +#define WM_SET_REPORT 0xA0 #endif -#define WM_BT_INPUT 0x01 -#define WM_BT_OUTPUT 0x02 +#define WM_BT_INPUT 0x01 +#define WM_BT_OUTPUT 0x02 // LED bit masks -#define WIIMOTE_LED_NONE 0x00 -#define WIIMOTE_LED_1 0x10 -#define WIIMOTE_LED_2 0x20 -#define WIIMOTE_LED_3 0x40 -#define WIIMOTE_LED_4 0x80 +#define WIIMOTE_LED_NONE 0x00 +#define WIIMOTE_LED_1 0x10 +#define WIIMOTE_LED_2 0x20 +#define WIIMOTE_LED_3 0x40 +#define WIIMOTE_LED_4 0x80 // End Wiimote internal codes // It's 23. NOT 32! -#define MAX_PAYLOAD 23 -#define WIIMOTE_DEFAULT_TIMEOUT 1000 +#define MAX_PAYLOAD 23 +#define WIIMOTE_DEFAULT_TIMEOUT 1000 #ifdef _WIN32 // Different methods to send data Wiimote on Windows depending on OS and Bluetooth Stack enum WinWriteMethod { - WWM_WRITE_FILE_LARGEST_REPORT_SIZE, - WWM_WRITE_FILE_ACTUAL_REPORT_SIZE, - WWM_SET_OUTPUT_REPORT + WWM_WRITE_FILE_LARGEST_REPORT_SIZE, + WWM_WRITE_FILE_ACTUAL_REPORT_SIZE, + WWM_SET_OUTPUT_REPORT }; #endif diff --git a/Source/Core/Core/HotkeyManager.cpp b/Source/Core/Core/HotkeyManager.cpp index 39743d5dd7..24275f8767 100644 --- a/Source/Core/Core/HotkeyManager.cpp +++ b/Source/Core/Core/HotkeyManager.cpp @@ -10,129 +10,128 @@ #include "Core/HotkeyManager.h" #include "InputCommon/GCPadStatus.h" -const std::string hotkey_labels[] = -{ - _trans("Open"), - _trans("Change Disc"), - _trans("Refresh List"), +const std::string hotkey_labels[] = { + _trans("Open"), + _trans("Change Disc"), + _trans("Refresh List"), - _trans("Toggle Pause"), - _trans("Stop"), - _trans("Reset"), - _trans("Frame Advance"), - _trans("Frame Advance Decrease Speed"), - _trans("Frame Advance Increase Speed"), - _trans("Frame Advance Reset Speed"), + _trans("Toggle Pause"), + _trans("Stop"), + _trans("Reset"), + _trans("Frame Advance"), + _trans("Frame Advance Decrease Speed"), + _trans("Frame Advance Increase Speed"), + _trans("Frame Advance Reset Speed"), - _trans("Start Recording"), - _trans("Play Recording"), - _trans("Export Recording"), - _trans("Read-only mode"), + _trans("Start Recording"), + _trans("Play Recording"), + _trans("Export Recording"), + _trans("Read-only mode"), - _trans("Toggle Fullscreen"), - _trans("Take Screenshot"), - _trans("Exit"), + _trans("Toggle Fullscreen"), + _trans("Take Screenshot"), + _trans("Exit"), - _trans("Connect Wiimote 1"), - _trans("Connect Wiimote 2"), - _trans("Connect Wiimote 3"), - _trans("Connect Wiimote 4"), - _trans("Connect Balance Board"), + _trans("Connect Wiimote 1"), + _trans("Connect Wiimote 2"), + _trans("Connect Wiimote 3"), + _trans("Connect Wiimote 4"), + _trans("Connect Balance Board"), - _trans("Volume Down"), - _trans("Volume Up"), - _trans("Volume Toggle Mute"), + _trans("Volume Down"), + _trans("Volume Up"), + _trans("Volume Toggle Mute"), - _trans("Increase IR"), - _trans("Decrease IR"), + _trans("Increase IR"), + _trans("Decrease IR"), - _trans("Toggle Crop"), - _trans("Toggle Aspect Ratio"), - _trans("Toggle EFB Copies"), - _trans("Toggle Fog"), - _trans("Disable Emulation Speed Limit"), - _trans("Decrease Emulation Speed"), - _trans("Increase Emulation Speed"), + _trans("Toggle Crop"), + _trans("Toggle Aspect Ratio"), + _trans("Toggle EFB Copies"), + _trans("Toggle Fog"), + _trans("Disable Emulation Speed Limit"), + _trans("Decrease Emulation Speed"), + _trans("Increase Emulation Speed"), - _trans("Freelook Decrease Speed"), - _trans("Freelook Increase Speed"), - _trans("Freelook Reset Speed"), - _trans("Freelook Move Up"), - _trans("Freelook Move Down"), - _trans("Freelook Move Left"), - _trans("Freelook Move Right"), - _trans("Freelook Zoom In"), - _trans("Freelook Zoom Out"), - _trans("Freelook Reset"), + _trans("Freelook Decrease Speed"), + _trans("Freelook Increase Speed"), + _trans("Freelook Reset Speed"), + _trans("Freelook Move Up"), + _trans("Freelook Move Down"), + _trans("Freelook Move Left"), + _trans("Freelook Move Right"), + _trans("Freelook Zoom In"), + _trans("Freelook Zoom Out"), + _trans("Freelook Reset"), - _trans("Toggle 3D Side-by-side"), - _trans("Toggle 3D Top-bottom"), - _trans("Toggle 3D Anaglyph"), - _trans("Toggle 3D Vision"), + _trans("Toggle 3D Side-by-side"), + _trans("Toggle 3D Top-bottom"), + _trans("Toggle 3D Anaglyph"), + _trans("Toggle 3D Vision"), - _trans("Decrease Depth"), - _trans("Increase Depth"), - _trans("Decrease Convergence"), - _trans("Increase Convergence"), + _trans("Decrease Depth"), + _trans("Increase Depth"), + _trans("Decrease Convergence"), + _trans("Increase Convergence"), - _trans("Load State Slot 1"), - _trans("Load State Slot 2"), - _trans("Load State Slot 3"), - _trans("Load State Slot 4"), - _trans("Load State Slot 5"), - _trans("Load State Slot 6"), - _trans("Load State Slot 7"), - _trans("Load State Slot 8"), - _trans("Load State Slot 9"), - _trans("Load State Slot 10"), + _trans("Load State Slot 1"), + _trans("Load State Slot 2"), + _trans("Load State Slot 3"), + _trans("Load State Slot 4"), + _trans("Load State Slot 5"), + _trans("Load State Slot 6"), + _trans("Load State Slot 7"), + _trans("Load State Slot 8"), + _trans("Load State Slot 9"), + _trans("Load State Slot 10"), - _trans("Save State Slot 1"), - _trans("Save State Slot 2"), - _trans("Save State Slot 3"), - _trans("Save State Slot 4"), - _trans("Save State Slot 5"), - _trans("Save State Slot 6"), - _trans("Save State Slot 7"), - _trans("Save State Slot 8"), - _trans("Save State Slot 9"), - _trans("Save State Slot 10"), + _trans("Save State Slot 1"), + _trans("Save State Slot 2"), + _trans("Save State Slot 3"), + _trans("Save State Slot 4"), + _trans("Save State Slot 5"), + _trans("Save State Slot 6"), + _trans("Save State Slot 7"), + _trans("Save State Slot 8"), + _trans("Save State Slot 9"), + _trans("Save State Slot 10"), - _trans("Select State Slot 1"), - _trans("Select State Slot 2"), - _trans("Select State Slot 3"), - _trans("Select State Slot 4"), - _trans("Select State Slot 5"), - _trans("Select State Slot 6"), - _trans("Select State Slot 7"), - _trans("Select State Slot 8"), - _trans("Select State Slot 9"), - _trans("Select State Slot 10"), + _trans("Select State Slot 1"), + _trans("Select State Slot 2"), + _trans("Select State Slot 3"), + _trans("Select State Slot 4"), + _trans("Select State Slot 5"), + _trans("Select State Slot 6"), + _trans("Select State Slot 7"), + _trans("Select State Slot 8"), + _trans("Select State Slot 9"), + _trans("Select State Slot 10"), - _trans("Save to selected slot"), - _trans("Load from selected slot"), + _trans("Save to selected slot"), + _trans("Load from selected slot"), - _trans("Load State Last 1"), - _trans("Load State Last 2"), - _trans("Load State Last 3"), - _trans("Load State Last 4"), - _trans("Load State Last 5"), - _trans("Load State Last 6"), - _trans("Load State Last 7"), - _trans("Load State Last 8"), - _trans("Load State Last 9"), - _trans("Load State Last 10"), + _trans("Load State Last 1"), + _trans("Load State Last 2"), + _trans("Load State Last 3"), + _trans("Load State Last 4"), + _trans("Load State Last 5"), + _trans("Load State Last 6"), + _trans("Load State Last 7"), + _trans("Load State Last 8"), + _trans("Load State Last 9"), + _trans("Load State Last 10"), - _trans("Save Oldest State"), - _trans("Undo Load State"), - _trans("Undo Save State"), - _trans("Save State"), - _trans("Load State"), + _trans("Save Oldest State"), + _trans("Undo Load State"), + _trans("Undo Save State"), + _trans("Save State"), + _trans("Load State"), }; -static_assert(NUM_HOTKEYS == sizeof(hotkey_labels) / sizeof(hotkey_labels[0]), "Wrong count of hotkey_labels"); +static_assert(NUM_HOTKEYS == sizeof(hotkey_labels) / sizeof(hotkey_labels[0]), + "Wrong count of hotkey_labels"); namespace HotkeyManagerEmu { - static u32 s_hotkeyDown[(NUM_HOTKEYS + 31) / 32]; static HotkeyStatus s_hotkey; static bool s_enabled; @@ -141,91 +140,91 @@ static InputConfig s_config("Hotkeys", _trans("Hotkeys"), "Hotkeys"); InputConfig* GetConfig() { - return &s_config; + return &s_config; } void GetStatus() { - s_hotkey.err = PAD_ERR_NONE; + s_hotkey.err = PAD_ERR_NONE; - // Get input - static_cast(s_config.GetController(0))->GetInput(&s_hotkey); + // Get input + static_cast(s_config.GetController(0))->GetInput(&s_hotkey); } bool IsEnabled() { - return s_enabled; + return s_enabled; } void Enable(bool enable_toggle) { - s_enabled = enable_toggle; + s_enabled = enable_toggle; } bool IsPressed(int Id, bool held) { - unsigned int set = Id / 32; - unsigned int setKey = Id % 32; - if (s_hotkey.button[set] & (1 << setKey)) - { - bool pressed = !!(s_hotkeyDown[set] & (1 << setKey)); - s_hotkeyDown[set] |= (1 << setKey); - if (!pressed || held) - return true; - } - else - { - s_hotkeyDown[set] &= ~(1 << setKey); - } + unsigned int set = Id / 32; + unsigned int setKey = Id % 32; + if (s_hotkey.button[set] & (1 << setKey)) + { + bool pressed = !!(s_hotkeyDown[set] & (1 << setKey)); + s_hotkeyDown[set] |= (1 << setKey); + if (!pressed || held) + return true; + } + else + { + s_hotkeyDown[set] &= ~(1 << setKey); + } - return false; + return false; } void Initialize(void* const hwnd) { - if (s_config.ControllersNeedToBeCreated()) - s_config.CreateController(); + if (s_config.ControllersNeedToBeCreated()) + s_config.CreateController(); - g_controller_interface.Initialize(hwnd); + g_controller_interface.Initialize(hwnd); - // load the saved controller config - s_config.LoadConfig(true); + // load the saved controller config + s_config.LoadConfig(true); - for (u32& key : s_hotkeyDown) - key = 0; + for (u32& key : s_hotkeyDown) + key = 0; - s_enabled = true; + s_enabled = true; } void LoadConfig() { - s_config.LoadConfig(true); + s_config.LoadConfig(true); } void Shutdown() { - s_config.ClearControllers(); + s_config.ClearControllers(); - g_controller_interface.Shutdown(); + g_controller_interface.Shutdown(); } - } HotkeyManager::HotkeyManager() { - for (int key = 0; key < NUM_HOTKEYS; key++) - { - int set = key / 32; + for (int key = 0; key < NUM_HOTKEYS; key++) + { + int set = key / 32; - if (key % 32 == 0) - groups.emplace_back(m_keys[set] = new Buttons(_trans("Keys"))); + if (key % 32 == 0) + groups.emplace_back(m_keys[set] = new Buttons(_trans("Keys"))); - m_keys[set]->controls.emplace_back(new ControlGroup::Input(hotkey_labels[key])); - } + m_keys[set]->controls.emplace_back(new ControlGroup::Input(hotkey_labels[key])); + } - groups.emplace_back(m_options = new ControlGroup(_trans("Options"))); - m_options->settings.emplace_back(new ControlGroup::BackgroundInputSetting(_trans("Background Input"))); - m_options->settings.emplace_back(new ControlGroup::IterateUI(_trans("Iterative Input"))); + groups.emplace_back(m_options = new ControlGroup(_trans("Options"))); + m_options->settings.emplace_back( + new ControlGroup::BackgroundInputSetting(_trans("Background Input"))); + m_options->settings.emplace_back(new ControlGroup::IterateUI(_trans("Iterative Input"))); } HotkeyManager::~HotkeyManager() @@ -234,82 +233,84 @@ HotkeyManager::~HotkeyManager() std::string HotkeyManager::GetName() const { - return std::string("Hotkeys") + char('1' + 0); + return std::string("Hotkeys") + char('1' + 0); } void HotkeyManager::GetInput(HotkeyStatus* const kb) { - for (int set = 0; set < (NUM_HOTKEYS + 31) / 32; set++) - { - std::vector bitmasks; - for (int key = 0; key < std::min(32, NUM_HOTKEYS - set * 32); key++) - bitmasks.push_back(1 << key); + for (int set = 0; set < (NUM_HOTKEYS + 31) / 32; set++) + { + std::vector bitmasks; + for (int key = 0; key < std::min(32, NUM_HOTKEYS - set * 32); key++) + bitmasks.push_back(1 << key); - kb->button[set] = 0; - m_keys[set]->GetState(&kb->button[set], bitmasks.data()); - } + kb->button[set] = 0; + m_keys[set]->GetState(&kb->button[set], bitmasks.data()); + } } void HotkeyManager::LoadDefaults(const ControllerInterface& ciface) { - ControllerEmu::LoadDefaults(ciface); + ControllerEmu::LoadDefaults(ciface); #ifdef _WIN32 - const std::string NON = "(!(LMENU | RMENU) & !(LSHIFT | RSHIFT) & !(LCONTROL | RCONTROL))"; - const std::string ALT = "((LMENU | RMENU) & !(LSHIFT | RSHIFT) & !(LCONTROL | RCONTROL))"; - const std::string SHIFT = "(!(LMENU | RMENU) & (LSHIFT | RSHIFT) & !(LCONTROL | RCONTROL))"; - const std::string CTRL = "(!(LMENU | RMENU) & !(LSHIFT | RSHIFT) & (LCONTROL | RCONTROL))"; + const std::string NON = "(!(LMENU | RMENU) & !(LSHIFT | RSHIFT) & !(LCONTROL | RCONTROL))"; + const std::string ALT = "((LMENU | RMENU) & !(LSHIFT | RSHIFT) & !(LCONTROL | RCONTROL))"; + const std::string SHIFT = "(!(LMENU | RMENU) & (LSHIFT | RSHIFT) & !(LCONTROL | RCONTROL))"; + const std::string CTRL = "(!(LMENU | RMENU) & !(LSHIFT | RSHIFT) & (LCONTROL | RCONTROL))"; #else - const std::string NON = "(!`Alt_L` & !(`Shift_L` | `Shift_R`) & !(`Control_L` | `Control_R` ))"; - const std::string ALT = "(`Alt_L` & !(`Shift_L` | `Shift_R`) & !(`Control_L` | `Control_R` ))"; - const std::string SHIFT = "(!`Alt_L` & (`Shift_L` | `Shift_R`) & !(`Control_L` | `Control_R` ))"; - const std::string CTRL = "(!`Alt_L` & !(`Shift_L` | `Shift_R`) & (`Control_L` | `Control_R` ))"; + const std::string NON = "(!`Alt_L` & !(`Shift_L` | `Shift_R`) & !(`Control_L` | `Control_R` ))"; + const std::string ALT = "(`Alt_L` & !(`Shift_L` | `Shift_R`) & !(`Control_L` | `Control_R` ))"; + const std::string SHIFT = "(!`Alt_L` & (`Shift_L` | `Shift_R`) & !(`Control_L` | `Control_R` ))"; + const std::string CTRL = "(!`Alt_L` & !(`Shift_L` | `Shift_R`) & (`Control_L` | `Control_R` ))"; #endif - auto set_key_expression = [this](int index, const std::string& expression) { - m_keys[index / 32]->controls[index % 32]->control_ref->expression = expression; - }; + auto set_key_expression = [this](int index, const std::string& expression) { + m_keys[index / 32]->controls[index % 32]->control_ref->expression = expression; + }; - // General hotkeys - set_key_expression(HK_OPEN, CTRL + " & O"); - set_key_expression(HK_PLAY_PAUSE, "`F10`"); + // General hotkeys + set_key_expression(HK_OPEN, CTRL + " & O"); + set_key_expression(HK_PLAY_PAUSE, "`F10`"); #ifdef _WIN32 - set_key_expression(HK_STOP, "ESCAPE"); - set_key_expression(HK_FULLSCREEN, ALT + " & RETURN"); + set_key_expression(HK_STOP, "ESCAPE"); + set_key_expression(HK_FULLSCREEN, ALT + " & RETURN"); #else - set_key_expression(HK_STOP, "Escape"); - set_key_expression(HK_FULLSCREEN, ALT + " & Return"); + set_key_expression(HK_STOP, "Escape"); + set_key_expression(HK_FULLSCREEN, ALT + " & Return"); #endif - set_key_expression(HK_SCREENSHOT, NON + " & `F9`"); - set_key_expression(HK_WIIMOTE1_CONNECT, ALT + " & `F5`"); - set_key_expression(HK_WIIMOTE2_CONNECT, ALT + " & `F6`"); - set_key_expression(HK_WIIMOTE3_CONNECT, ALT + " & `F7`"); - set_key_expression(HK_WIIMOTE4_CONNECT, ALT + " & `F8`"); - set_key_expression(HK_BALANCEBOARD_CONNECT, ALT + " & `F9`"); + set_key_expression(HK_SCREENSHOT, NON + " & `F9`"); + set_key_expression(HK_WIIMOTE1_CONNECT, ALT + " & `F5`"); + set_key_expression(HK_WIIMOTE2_CONNECT, ALT + " & `F6`"); + set_key_expression(HK_WIIMOTE3_CONNECT, ALT + " & `F7`"); + set_key_expression(HK_WIIMOTE4_CONNECT, ALT + " & `F8`"); + set_key_expression(HK_BALANCEBOARD_CONNECT, ALT + " & `F9`"); #ifdef _WIN32 - set_key_expression(HK_TOGGLE_THROTTLE, "TAB"); + set_key_expression(HK_TOGGLE_THROTTLE, "TAB"); #else - set_key_expression(HK_TOGGLE_THROTTLE, "Tab"); + set_key_expression(HK_TOGGLE_THROTTLE, "Tab"); #endif - // Freelook - set_key_expression(HK_FREELOOK_DECREASE_SPEED, SHIFT + " & `1`"); - set_key_expression(HK_FREELOOK_INCREASE_SPEED, SHIFT + " & `2`"); - set_key_expression(HK_FREELOOK_RESET_SPEED, SHIFT + " & F"); - set_key_expression(HK_FREELOOK_UP, SHIFT + " & E"); - set_key_expression(HK_FREELOOK_DOWN, SHIFT + " & Q"); - set_key_expression(HK_FREELOOK_LEFT, SHIFT + " & A"); - set_key_expression(HK_FREELOOK_RIGHT, SHIFT + " & D"); - set_key_expression(HK_FREELOOK_ZOOM_IN, SHIFT + " & W"); - set_key_expression(HK_FREELOOK_ZOOM_OUT, SHIFT + " & S"); - set_key_expression(HK_FREELOOK_RESET, SHIFT + " & R"); + // Freelook + set_key_expression(HK_FREELOOK_DECREASE_SPEED, SHIFT + " & `1`"); + set_key_expression(HK_FREELOOK_INCREASE_SPEED, SHIFT + " & `2`"); + set_key_expression(HK_FREELOOK_RESET_SPEED, SHIFT + " & F"); + set_key_expression(HK_FREELOOK_UP, SHIFT + " & E"); + set_key_expression(HK_FREELOOK_DOWN, SHIFT + " & Q"); + set_key_expression(HK_FREELOOK_LEFT, SHIFT + " & A"); + set_key_expression(HK_FREELOOK_RIGHT, SHIFT + " & D"); + set_key_expression(HK_FREELOOK_ZOOM_IN, SHIFT + " & W"); + set_key_expression(HK_FREELOOK_ZOOM_OUT, SHIFT + " & S"); + set_key_expression(HK_FREELOOK_RESET, SHIFT + " & R"); - // Savestates - for (int i = 0; i < 8; i++) - { - set_key_expression(HK_LOAD_STATE_SLOT_1 + i, StringFromFormat((NON + " & `F%d`").c_str(), i + 1)); - set_key_expression(HK_SAVE_STATE_SLOT_1 + i, StringFromFormat((SHIFT + " & `F%d`").c_str(), i + 1)); - } - set_key_expression(HK_UNDO_LOAD_STATE, NON + " & `F12`"); - set_key_expression(HK_UNDO_SAVE_STATE, SHIFT + " & `F12`"); + // Savestates + for (int i = 0; i < 8; i++) + { + set_key_expression(HK_LOAD_STATE_SLOT_1 + i, + StringFromFormat((NON + " & `F%d`").c_str(), i + 1)); + set_key_expression(HK_SAVE_STATE_SLOT_1 + i, + StringFromFormat((SHIFT + " & `F%d`").c_str(), i + 1)); + } + set_key_expression(HK_UNDO_LOAD_STATE, NON + " & `F12`"); + set_key_expression(HK_UNDO_SAVE_STATE, SHIFT + " & `F12`"); } diff --git a/Source/Core/Core/HotkeyManager.h b/Source/Core/Core/HotkeyManager.h index cb41840457..02b2e2df8b 100644 --- a/Source/Core/Core/HotkeyManager.h +++ b/Source/Core/Core/HotkeyManager.h @@ -10,156 +10,156 @@ enum Hotkey { - HK_OPEN, - HK_CHANGE_DISC, - HK_REFRESH_LIST, + HK_OPEN, + HK_CHANGE_DISC, + HK_REFRESH_LIST, - HK_PLAY_PAUSE, - HK_STOP, - HK_RESET, - HK_FRAME_ADVANCE, - HK_FRAME_ADVANCE_DECREASE_SPEED, - HK_FRAME_ADVANCE_INCREASE_SPEED, - HK_FRAME_ADVANCE_RESET_SPEED, + HK_PLAY_PAUSE, + HK_STOP, + HK_RESET, + HK_FRAME_ADVANCE, + HK_FRAME_ADVANCE_DECREASE_SPEED, + HK_FRAME_ADVANCE_INCREASE_SPEED, + HK_FRAME_ADVANCE_RESET_SPEED, - HK_START_RECORDING, - HK_PLAY_RECORDING, - HK_EXPORT_RECORDING, - HK_READ_ONLY_MODE, + HK_START_RECORDING, + HK_PLAY_RECORDING, + HK_EXPORT_RECORDING, + HK_READ_ONLY_MODE, - HK_FULLSCREEN, - HK_SCREENSHOT, - HK_EXIT, + HK_FULLSCREEN, + HK_SCREENSHOT, + HK_EXIT, - HK_WIIMOTE1_CONNECT, - HK_WIIMOTE2_CONNECT, - HK_WIIMOTE3_CONNECT, - HK_WIIMOTE4_CONNECT, - HK_BALANCEBOARD_CONNECT, + HK_WIIMOTE1_CONNECT, + HK_WIIMOTE2_CONNECT, + HK_WIIMOTE3_CONNECT, + HK_WIIMOTE4_CONNECT, + HK_BALANCEBOARD_CONNECT, - HK_VOLUME_DOWN, - HK_VOLUME_UP, - HK_VOLUME_TOGGLE_MUTE, + HK_VOLUME_DOWN, + HK_VOLUME_UP, + HK_VOLUME_TOGGLE_MUTE, - HK_INCREASE_IR, - HK_DECREASE_IR, + HK_INCREASE_IR, + HK_DECREASE_IR, - HK_TOGGLE_CROP, - HK_TOGGLE_AR, - HK_TOGGLE_EFBCOPIES, - HK_TOGGLE_FOG, - HK_TOGGLE_THROTTLE, + HK_TOGGLE_CROP, + HK_TOGGLE_AR, + HK_TOGGLE_EFBCOPIES, + HK_TOGGLE_FOG, + HK_TOGGLE_THROTTLE, - HK_DECREASE_EMULATION_SPEED, - HK_INCREASE_EMULATION_SPEED, + HK_DECREASE_EMULATION_SPEED, + HK_INCREASE_EMULATION_SPEED, - HK_FREELOOK_DECREASE_SPEED, - HK_FREELOOK_INCREASE_SPEED, - HK_FREELOOK_RESET_SPEED, - HK_FREELOOK_UP, - HK_FREELOOK_DOWN, - HK_FREELOOK_LEFT, - HK_FREELOOK_RIGHT, - HK_FREELOOK_ZOOM_IN, - HK_FREELOOK_ZOOM_OUT, - HK_FREELOOK_RESET, + HK_FREELOOK_DECREASE_SPEED, + HK_FREELOOK_INCREASE_SPEED, + HK_FREELOOK_RESET_SPEED, + HK_FREELOOK_UP, + HK_FREELOOK_DOWN, + HK_FREELOOK_LEFT, + HK_FREELOOK_RIGHT, + HK_FREELOOK_ZOOM_IN, + HK_FREELOOK_ZOOM_OUT, + HK_FREELOOK_RESET, - HK_TOGGLE_STEREO_SBS, - HK_TOGGLE_STEREO_TAB, - HK_TOGGLE_STEREO_ANAGLYPH, - HK_TOGGLE_STEREO_3DVISION, + HK_TOGGLE_STEREO_SBS, + HK_TOGGLE_STEREO_TAB, + HK_TOGGLE_STEREO_ANAGLYPH, + HK_TOGGLE_STEREO_3DVISION, - HK_DECREASE_DEPTH, - HK_INCREASE_DEPTH, - HK_DECREASE_CONVERGENCE, - HK_INCREASE_CONVERGENCE, + HK_DECREASE_DEPTH, + HK_INCREASE_DEPTH, + HK_DECREASE_CONVERGENCE, + HK_INCREASE_CONVERGENCE, - HK_LOAD_STATE_SLOT_1, - HK_LOAD_STATE_SLOT_2, - HK_LOAD_STATE_SLOT_3, - HK_LOAD_STATE_SLOT_4, - HK_LOAD_STATE_SLOT_5, - HK_LOAD_STATE_SLOT_6, - HK_LOAD_STATE_SLOT_7, - HK_LOAD_STATE_SLOT_8, - HK_LOAD_STATE_SLOT_9, - HK_LOAD_STATE_SLOT_10, + HK_LOAD_STATE_SLOT_1, + HK_LOAD_STATE_SLOT_2, + HK_LOAD_STATE_SLOT_3, + HK_LOAD_STATE_SLOT_4, + HK_LOAD_STATE_SLOT_5, + HK_LOAD_STATE_SLOT_6, + HK_LOAD_STATE_SLOT_7, + HK_LOAD_STATE_SLOT_8, + HK_LOAD_STATE_SLOT_9, + HK_LOAD_STATE_SLOT_10, - HK_SAVE_STATE_SLOT_1, - HK_SAVE_STATE_SLOT_2, - HK_SAVE_STATE_SLOT_3, - HK_SAVE_STATE_SLOT_4, - HK_SAVE_STATE_SLOT_5, - HK_SAVE_STATE_SLOT_6, - HK_SAVE_STATE_SLOT_7, - HK_SAVE_STATE_SLOT_8, - HK_SAVE_STATE_SLOT_9, - HK_SAVE_STATE_SLOT_10, + HK_SAVE_STATE_SLOT_1, + HK_SAVE_STATE_SLOT_2, + HK_SAVE_STATE_SLOT_3, + HK_SAVE_STATE_SLOT_4, + HK_SAVE_STATE_SLOT_5, + HK_SAVE_STATE_SLOT_6, + HK_SAVE_STATE_SLOT_7, + HK_SAVE_STATE_SLOT_8, + HK_SAVE_STATE_SLOT_9, + HK_SAVE_STATE_SLOT_10, - HK_SELECT_STATE_SLOT_1, - HK_SELECT_STATE_SLOT_2, - HK_SELECT_STATE_SLOT_3, - HK_SELECT_STATE_SLOT_4, - HK_SELECT_STATE_SLOT_5, - HK_SELECT_STATE_SLOT_6, - HK_SELECT_STATE_SLOT_7, - HK_SELECT_STATE_SLOT_8, - HK_SELECT_STATE_SLOT_9, - HK_SELECT_STATE_SLOT_10, + HK_SELECT_STATE_SLOT_1, + HK_SELECT_STATE_SLOT_2, + HK_SELECT_STATE_SLOT_3, + HK_SELECT_STATE_SLOT_4, + HK_SELECT_STATE_SLOT_5, + HK_SELECT_STATE_SLOT_6, + HK_SELECT_STATE_SLOT_7, + HK_SELECT_STATE_SLOT_8, + HK_SELECT_STATE_SLOT_9, + HK_SELECT_STATE_SLOT_10, - HK_SAVE_STATE_SLOT_SELECTED, - HK_LOAD_STATE_SLOT_SELECTED, + HK_SAVE_STATE_SLOT_SELECTED, + HK_LOAD_STATE_SLOT_SELECTED, - HK_LOAD_LAST_STATE_1, - HK_LOAD_LAST_STATE_2, - HK_LOAD_LAST_STATE_3, - HK_LOAD_LAST_STATE_4, - HK_LOAD_LAST_STATE_5, - HK_LOAD_LAST_STATE_6, - HK_LOAD_LAST_STATE_7, - HK_LOAD_LAST_STATE_8, - HK_LOAD_LAST_STATE_9, - HK_LOAD_LAST_STATE_10, + HK_LOAD_LAST_STATE_1, + HK_LOAD_LAST_STATE_2, + HK_LOAD_LAST_STATE_3, + HK_LOAD_LAST_STATE_4, + HK_LOAD_LAST_STATE_5, + HK_LOAD_LAST_STATE_6, + HK_LOAD_LAST_STATE_7, + HK_LOAD_LAST_STATE_8, + HK_LOAD_LAST_STATE_9, + HK_LOAD_LAST_STATE_10, - HK_SAVE_FIRST_STATE, - HK_UNDO_LOAD_STATE, - HK_UNDO_SAVE_STATE, - HK_SAVE_STATE_FILE, - HK_LOAD_STATE_FILE, + HK_SAVE_FIRST_STATE, + HK_UNDO_LOAD_STATE, + HK_UNDO_SAVE_STATE, + HK_SAVE_STATE_FILE, + HK_LOAD_STATE_FILE, - NUM_HOTKEYS, + NUM_HOTKEYS, }; struct HotkeyStatus { - u32 button[(NUM_HOTKEYS + 31) / 32]; - s8 err; + u32 button[(NUM_HOTKEYS + 31) / 32]; + s8 err; }; class HotkeyManager : public ControllerEmu { public: - HotkeyManager(); - ~HotkeyManager(); + HotkeyManager(); + ~HotkeyManager(); - void GetInput(HotkeyStatus* const hk); - std::string GetName() const override; - void LoadDefaults(const ControllerInterface& ciface) override; + void GetInput(HotkeyStatus* const hk); + std::string GetName() const override; + void LoadDefaults(const ControllerInterface& ciface) override; private: - Buttons* m_keys[(NUM_HOTKEYS + 31) / 32]; - ControlGroup* m_options; + Buttons* m_keys[(NUM_HOTKEYS + 31) / 32]; + ControlGroup* m_options; }; namespace HotkeyManagerEmu { - void Initialize(void* const hwnd); - void Shutdown(); - void LoadConfig(); +void Initialize(void* const hwnd); +void Shutdown(); +void LoadConfig(); - InputConfig* GetConfig(); - void GetStatus(); - bool IsEnabled(); - void Enable(bool enable_toggle); - bool IsPressed(int Id, bool held); +InputConfig* GetConfig(); +void GetStatus(); +bool IsEnabled(); +void Enable(bool enable_toggle); +bool IsPressed(int Id, bool held); } diff --git a/Source/Core/Core/IPC_HLE/ICMP.h b/Source/Core/Core/IPC_HLE/ICMP.h index 72e82ea453..bd248d0782 100644 --- a/Source/Core/Core/IPC_HLE/ICMP.h +++ b/Source/Core/Core/IPC_HLE/ICMP.h @@ -12,5 +12,5 @@ #include "Common/CommonTypes.h" -int icmp_echo_req(const u32 s, const sockaddr_in *addr, const u8 *data, const u32 data_length); -int icmp_echo_rep(const u32 s, sockaddr_in *addr, const u32 timeout, const u32 data_length); +int icmp_echo_req(const u32 s, const sockaddr_in* addr, const u8* data, const u32 data_length); +int icmp_echo_rep(const u32 s, sockaddr_in* addr, const u32 timeout, const u32 data_length); diff --git a/Source/Core/Core/IPC_HLE/ICMPLin.cpp b/Source/Core/Core/IPC_HLE/ICMPLin.cpp index f3e6aa3092..d847d8d0a2 100644 --- a/Source/Core/Core/IPC_HLE/ICMPLin.cpp +++ b/Source/Core/Core/IPC_HLE/ICMPLin.cpp @@ -7,14 +7,14 @@ // Currently stubbed. AFAIK (delroth) there is no way to send ICMP echo // requests without being root on current Linux versions. -int icmp_echo_req(const u32 s, const sockaddr_in *addr, const u8 *data, const u32 data_length) +int icmp_echo_req(const u32 s, const sockaddr_in* addr, const u8* data, const u32 data_length) { - // TODO - return -1; + // TODO + return -1; } -int icmp_echo_rep(const u32 s, sockaddr_in *addr, const u32 timeout, const u32 data_length) +int icmp_echo_rep(const u32 s, sockaddr_in* addr, const u32 timeout, const u32 data_length) { - // TODO - return -1; + // TODO + return -1; } diff --git a/Source/Core/Core/IPC_HLE/ICMPWin.cpp b/Source/Core/Core/IPC_HLE/ICMPWin.cpp index f00ae19a77..ced1b4d320 100644 --- a/Source/Core/Core/IPC_HLE/ICMPWin.cpp +++ b/Source/Core/Core/IPC_HLE/ICMPWin.cpp @@ -6,25 +6,25 @@ enum { - ICMP_ECHOREPLY = 0, - ICMP_ECHOREQ = 8 + ICMP_ECHOREPLY = 0, + ICMP_ECHOREQ = 8 }; enum { - ICMP_HDR_LEN = 4, - IP_HDR_LEN = 20 + ICMP_HDR_LEN = 4, + IP_HDR_LEN = 20 }; #pragma pack(push, 1) struct icmp_hdr { - u8 type; - u8 code; - u16 checksum; - u16 id; - u16 seq; - char data[1]; + u8 type; + u8 code; + u16 checksum; + u16 id; + u16 seq; + char data[1]; }; #pragma pack(pop) @@ -38,65 +38,64 @@ static u8 workspace[56]; * NOTE: to handle odd number of bytes, last (even) byte in * buffer have a value of 0 (we assume that it does) */ -u16 cksum(const u16 *buffer, int length) +u16 cksum(const u16* buffer, int length) { - u32 sum = 0; + u32 sum = 0; - while (length > 0) - { - sum += *(buffer++); - length -= 2; - } + while (length > 0) + { + sum += *(buffer++); + length -= 2; + } - sum = (sum & 0xffff) + (sum >> 16); - sum += sum >> 16; + sum = (sum & 0xffff) + (sum >> 16); + sum += sum >> 16; - return (u16)~sum; + return (u16)~sum; } -int icmp_echo_req(const u32 s, const sockaddr_in *addr, const u8 *data, const u32 data_length) +int icmp_echo_req(const u32 s, const sockaddr_in* addr, const u8* data, const u32 data_length) { - memset(workspace, 0, sizeof(workspace)); - icmp_hdr *header = (icmp_hdr *)workspace; - header->type = ICMP_ECHOREQ; - header->code = 0; - header->checksum = 0; - memcpy(&header->id, data, data_length); + memset(workspace, 0, sizeof(workspace)); + icmp_hdr* header = (icmp_hdr*)workspace; + header->type = ICMP_ECHOREQ; + header->code = 0; + header->checksum = 0; + memcpy(&header->id, data, data_length); - header->checksum = cksum((u16 *)header, ICMP_HDR_LEN + data_length); + header->checksum = cksum((u16*)header, ICMP_HDR_LEN + data_length); - int num_bytes = sendto((SOCKET)s, (LPSTR)header, ICMP_HDR_LEN + data_length, 0, - (sockaddr *)addr, sizeof(sockaddr)); + int num_bytes = sendto((SOCKET)s, (LPSTR)header, ICMP_HDR_LEN + data_length, 0, (sockaddr*)addr, + sizeof(sockaddr)); - if (num_bytes >= ICMP_HDR_LEN) - num_bytes -= ICMP_HDR_LEN; + if (num_bytes >= ICMP_HDR_LEN) + num_bytes -= ICMP_HDR_LEN; - return num_bytes; + return num_bytes; } -int icmp_echo_rep(const u32 s, sockaddr_in *addr, const u32 timeout, const u32 data_length) +int icmp_echo_rep(const u32 s, sockaddr_in* addr, const u32 timeout, const u32 data_length) { - memset(workspace, 0, sizeof(workspace)); - int addr_length = sizeof(sockaddr_in); - int num_bytes = 0; + memset(workspace, 0, sizeof(workspace)); + int addr_length = sizeof(sockaddr_in); + int num_bytes = 0; - fd_set read_fds; - FD_ZERO(&read_fds); - FD_SET(s, &read_fds); + fd_set read_fds; + FD_ZERO(&read_fds); + FD_SET(s, &read_fds); - timeval t; - t.tv_sec = timeout / 1000; - if (select(0, &read_fds, nullptr, nullptr, &t) > 0) - { - num_bytes = recvfrom((SOCKET)s, (LPSTR)workspace, - IP_HDR_LEN + ICMP_HDR_LEN + data_length, - 0, (sockaddr *)addr, &addr_length); + timeval t; + t.tv_sec = timeout / 1000; + if (select(0, &read_fds, nullptr, nullptr, &t) > 0) + { + num_bytes = recvfrom((SOCKET)s, (LPSTR)workspace, IP_HDR_LEN + ICMP_HDR_LEN + data_length, 0, + (sockaddr*)addr, &addr_length); - // TODO do we need to memcmp the data? + // TODO do we need to memcmp the data? - if (num_bytes >= IP_HDR_LEN + ICMP_HDR_LEN) - num_bytes -= IP_HDR_LEN + ICMP_HDR_LEN; - } + if (num_bytes >= IP_HDR_LEN + ICMP_HDR_LEN) + num_bytes -= IP_HDR_LEN + ICMP_HDR_LEN; + } - return num_bytes; + return num_bytes; } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp index 529ab1b057..faf2895799 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp @@ -10,13 +10,13 @@ IPC basics (IOS' usage): Return values for file handles: All IPC calls will generate a return value to 0x04, in case of success they are - Open: DeviceID - Close: 0 - Read: Bytes read - Write: Bytes written - Seek: Seek position - Ioctl: 0 (in addition to that there may be messages to the out buffers) - Ioctlv: 0 (in addition to that there may be messages to the out buffers) + Open: DeviceID + Close: 0 + Read: Bytes read + Write: Bytes written + Seek: Seek position + Ioctl: 0 (in addition to that there may be messages to the out buffers) + Ioctlv: 0 (in addition to that there may be messages to the out buffers) They will also generate a true or false return for UpdateInterrupts() in WII_IPC.cpp. */ @@ -42,8 +42,8 @@ They will also generate a true or false return for UpdateInterrupts() in WII_IPC #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_DI.h" -#include "Core/IPC_HLE/WII_IPC_HLE_Device_es.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_es.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_fs.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_net.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.h" @@ -52,15 +52,14 @@ They will also generate a true or false return for UpdateInterrupts() in WII_IPC #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.h" -#if defined(__LIBUSB__) || defined (_WIN32) - #include "Core/IPC_HLE/WII_IPC_HLE_Device_hid.h" +#if defined(__LIBUSB__) || defined(_WIN32) +#include "Core/IPC_HLE/WII_IPC_HLE_Device_hid.h" #endif #include "Core/PowerPC/PowerPC.h" namespace WII_IPC_HLE_Interface { - typedef std::map> TDeviceMap; static TDeviceMap g_DeviceMap; @@ -71,11 +70,10 @@ static std::shared_ptr g_FdMap[IPC_MAX_FDS]; static bool es_inuse[ES_MAX_COUNT]; static std::shared_ptr es_handles[ES_MAX_COUNT]; - typedef std::deque ipc_msg_queue; -static ipc_msg_queue request_queue; // ppc -> arm -static ipc_msg_queue reply_queue; // arm -> ppc -static ipc_msg_queue ack_queue; // arm -> ppc +static ipc_msg_queue request_queue; // ppc -> arm +static ipc_msg_queue reply_queue; // arm -> ppc +static ipc_msg_queue ack_queue; // arm -> ppc static int event_enqueue; @@ -85,19 +83,19 @@ static const u64 ENQUEUE_REQUEST_FLAG = 0x100000000ULL; static const u64 ENQUEUE_ACKNOWLEDGEMENT_FLAG = 0x200000000ULL; static void EnqueueEvent(u64 userdata, s64 cycles_late = 0) { - if (userdata & ENQUEUE_ACKNOWLEDGEMENT_FLAG) - { - ack_queue.push_back((u32)userdata); - } - else if (userdata & ENQUEUE_REQUEST_FLAG) - { - request_queue.push_back((u32)userdata); - } - else - { - reply_queue.push_back((u32)userdata); - } - Update(); + if (userdata & ENQUEUE_ACKNOWLEDGEMENT_FLAG) + { + ack_queue.push_back((u32)userdata); + } + else if (userdata & ENQUEUE_REQUEST_FLAG) + { + request_queue.push_back((u32)userdata); + } + else + { + reply_queue.push_back((u32)userdata); + } + Update(); } static u32 num_devices; @@ -105,438 +103,441 @@ static u32 num_devices; template std::shared_ptr AddDevice(const char* deviceName) { - auto device = std::make_shared(num_devices, deviceName); - g_DeviceMap[num_devices] = device; - num_devices++; - return device; + auto device = std::make_shared(num_devices, deviceName); + g_DeviceMap[num_devices] = device; + num_devices++; + return device; } void Init() { - _dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isn't empty on init"); - CWII_IPC_HLE_Device_es::m_ContentFile = ""; + _dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isn't empty on init"); + CWII_IPC_HLE_Device_es::m_ContentFile = ""; - num_devices = 0; + num_devices = 0; - // Build hardware devices - AddDevice("/dev/usb/oh1/57e/305"); - AddDevice("/dev/stm/immediate"); - AddDevice("/dev/stm/eventhook"); - AddDevice("/dev/fs"); + // Build hardware devices + AddDevice("/dev/usb/oh1/57e/305"); + AddDevice("/dev/stm/immediate"); + AddDevice("/dev/stm/eventhook"); + AddDevice("/dev/fs"); - // IOS allows two ES devices at a time - for (u32 j=0; j("/dev/es"); - es_inuse[j] = false; - } + // IOS allows two ES devices at a time + for (u32 j = 0; j < ES_MAX_COUNT; j++) + { + es_handles[j] = AddDevice("/dev/es"); + es_inuse[j] = false; + } - AddDevice("/dev/di"); - AddDevice("/dev/net/kd/request"); - AddDevice("/dev/net/kd/time"); - AddDevice("/dev/net/ncd/manage"); - AddDevice("/dev/net/wd/command"); - AddDevice("/dev/net/ip/top"); - AddDevice("/dev/net/ssl"); - AddDevice("/dev/usb/kbd"); - AddDevice("/dev/sdio/slot0"); - AddDevice("/dev/sdio/slot1"); - #if defined(__LIBUSB__) || defined(_WIN32) - AddDevice("/dev/usb/hid"); - #else - AddDevice("/dev/usb/hid"); - #endif - AddDevice("/dev/usb/oh1"); - AddDevice("_Unimplemented_Device_"); + AddDevice("/dev/di"); + AddDevice("/dev/net/kd/request"); + AddDevice("/dev/net/kd/time"); + AddDevice("/dev/net/ncd/manage"); + AddDevice("/dev/net/wd/command"); + AddDevice("/dev/net/ip/top"); + AddDevice("/dev/net/ssl"); + AddDevice("/dev/usb/kbd"); + AddDevice("/dev/sdio/slot0"); + AddDevice("/dev/sdio/slot1"); +#if defined(__LIBUSB__) || defined(_WIN32) + AddDevice("/dev/usb/hid"); +#else + AddDevice("/dev/usb/hid"); +#endif + AddDevice("/dev/usb/oh1"); + AddDevice("_Unimplemented_Device_"); - event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent); + event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent); } void Reset(bool _bHard) { - CoreTiming::RemoveAllEvents(event_enqueue); + CoreTiming::RemoveAllEvents(event_enqueue); - for (auto& dev : g_FdMap) - { - if (dev && !dev->IsHardware()) - { - // close all files and delete their resources - dev->Close(0, true); - } + for (auto& dev : g_FdMap) + { + if (dev && !dev->IsHardware()) + { + // close all files and delete their resources + dev->Close(0, true); + } - dev.reset(); - } + dev.reset(); + } - for (bool& in_use : es_inuse) - { - in_use = false; - } + for (bool& in_use : es_inuse) + { + in_use = false; + } - for (const auto& entry : g_DeviceMap) - { - if (entry.second) - { - // Force close - entry.second->Close(0, true); - } - } + for (const auto& entry : g_DeviceMap) + { + if (entry.second) + { + // Force close + entry.second->Close(0, true); + } + } - if (_bHard) - { - g_DeviceMap.clear(); - } - request_queue.clear(); - reply_queue.clear(); + if (_bHard) + { + g_DeviceMap.clear(); + } + request_queue.clear(); + reply_queue.clear(); - last_reply_time = 0; + last_reply_time = 0; } void Shutdown() { - Reset(true); + Reset(true); } void SetDefaultContentFile(const std::string& _rFilename) { - for (const auto& entry : g_DeviceMap) - { - if (entry.second && entry.second->GetDeviceName().find("/dev/es") == 0) - { - static_cast(entry.second.get())->LoadWAD(_rFilename); - } - } + for (const auto& entry : g_DeviceMap) + { + if (entry.second && entry.second->GetDeviceName().find("/dev/es") == 0) + { + static_cast(entry.second.get())->LoadWAD(_rFilename); + } + } } void ES_DIVerify(const std::vector& tmd) { - CWII_IPC_HLE_Device_es::ES_DIVerify(tmd); + CWII_IPC_HLE_Device_es::ES_DIVerify(tmd); } void SDIO_EventNotify() { - auto pDevice = static_cast(GetDeviceByName("/dev/sdio/slot0").get()); - if (pDevice) - pDevice->EventNotify(); + auto pDevice = + static_cast(GetDeviceByName("/dev/sdio/slot0").get()); + if (pDevice) + pDevice->EventNotify(); } int getFreeDeviceId() { - for (u32 i=0; i GetDeviceByName(const std::string& _rDeviceName) { - for (const auto& entry : g_DeviceMap) - { - if (entry.second && entry.second->GetDeviceName() == _rDeviceName) - { - return entry.second; - } - } + for (const auto& entry : g_DeviceMap) + { + if (entry.second && entry.second->GetDeviceName() == _rDeviceName) + { + return entry.second; + } + } - return nullptr; + return nullptr; } std::shared_ptr AccessDeviceByID(u32 _ID) { - if (g_DeviceMap.find(_ID) != g_DeviceMap.end()) - { - return g_DeviceMap[_ID]; - } + if (g_DeviceMap.find(_ID) != g_DeviceMap.end()) + { + return g_DeviceMap[_ID]; + } - return nullptr; + return nullptr; } // This is called from ExecuteCommand() COMMAND_OPEN_DEVICE std::shared_ptr CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName) { - // scan device name and create the right one - INFO_LOG(WII_IPC_FILEIO, "IOP: Create FileIO %s", _rDeviceName.c_str()); - return std::make_shared(_DeviceID, _rDeviceName); + // scan device name and create the right one + INFO_LOG(WII_IPC_FILEIO, "IOP: Create FileIO %s", _rDeviceName.c_str()); + return std::make_shared(_DeviceID, _rDeviceName); } - -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - p.Do(request_queue); - p.Do(reply_queue); - p.Do(last_reply_time); + p.Do(request_queue); + p.Do(reply_queue); + p.Do(last_reply_time); - // We need to make sure all file handles are closed so WII_IPC_Devices_fs::DoState can successfully save or re-create /tmp - for (auto& descriptor : g_FdMap) - { - if (descriptor) - descriptor->PrepareForState(p.GetMode()); - } + // We need to make sure all file handles are closed so WII_IPC_Devices_fs::DoState can + // successfully save or re-create /tmp + for (auto& descriptor : g_FdMap) + { + if (descriptor) + descriptor->PrepareForState(p.GetMode()); + } - for (const auto& entry : g_DeviceMap) - { - if (entry.second->IsHardware()) - { - entry.second->DoState(p); - } - } + for (const auto& entry : g_DeviceMap) + { + if (entry.second->IsHardware()) + { + entry.second->DoState(p); + } + } - if (p.GetMode() == PointerWrap::MODE_READ) - { - for (u32 i=0; i < IPC_MAX_FDS; i++) - { - u32 exists = 0; - p.Do(exists); - if (exists) - { - u32 isHw = 0; - p.Do(isHw); - if (isHw) - { - u32 hwId = 0; - p.Do(hwId); - g_FdMap[i] = AccessDeviceByID(hwId); - } - else - { - g_FdMap[i] = std::make_shared(i, ""); - g_FdMap[i]->DoState(p); - } - } - } + if (p.GetMode() == PointerWrap::MODE_READ) + { + for (u32 i = 0; i < IPC_MAX_FDS; i++) + { + u32 exists = 0; + p.Do(exists); + if (exists) + { + u32 isHw = 0; + p.Do(isHw); + if (isHw) + { + u32 hwId = 0; + p.Do(hwId); + g_FdMap[i] = AccessDeviceByID(hwId); + } + else + { + g_FdMap[i] = std::make_shared(i, ""); + g_FdMap[i]->DoState(p); + } + } + } - for (u32 i=0; i < ES_MAX_COUNT; i++) - { - p.Do(es_inuse[i]); - u32 handleID = es_handles[i]->GetDeviceID(); - p.Do(handleID); + for (u32 i = 0; i < ES_MAX_COUNT; i++) + { + p.Do(es_inuse[i]); + u32 handleID = es_handles[i]->GetDeviceID(); + p.Do(handleID); - es_handles[i] = AccessDeviceByID(handleID); - } - } - else - { - for (auto& descriptor : g_FdMap) - { - u32 exists = descriptor ? 1 : 0; - p.Do(exists); - if (exists) - { - u32 isHw = descriptor->IsHardware() ? 1 : 0; - p.Do(isHw); - if (isHw) - { - u32 hwId = descriptor->GetDeviceID(); - p.Do(hwId); - } - else - { - descriptor->DoState(p); - } - } - } + es_handles[i] = AccessDeviceByID(handleID); + } + } + else + { + for (auto& descriptor : g_FdMap) + { + u32 exists = descriptor ? 1 : 0; + p.Do(exists); + if (exists) + { + u32 isHw = descriptor->IsHardware() ? 1 : 0; + p.Do(isHw); + if (isHw) + { + u32 hwId = descriptor->GetDeviceID(); + p.Do(hwId); + } + else + { + descriptor->DoState(p); + } + } + } - for (u32 i=0; i < ES_MAX_COUNT; i++) - { - p.Do(es_inuse[i]); - u32 handleID = es_handles[i]->GetDeviceID(); - p.Do(handleID); - } - } + for (u32 i = 0; i < ES_MAX_COUNT; i++) + { + p.Do(es_inuse[i]); + u32 handleID = es_handles[i]->GetDeviceID(); + p.Do(handleID); + } + } } void ExecuteCommand(u32 _Address) { - IPCCommandResult result = IWII_IPC_HLE_Device::GetNoReply(); + IPCCommandResult result = IWII_IPC_HLE_Device::GetNoReply(); - IPCCommandType Command = static_cast(Memory::Read_U32(_Address)); - s32 DeviceID = Memory::Read_U32(_Address + 8); + IPCCommandType Command = static_cast(Memory::Read_U32(_Address)); + s32 DeviceID = Memory::Read_U32(_Address + 8); - std::shared_ptr pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : nullptr; + std::shared_ptr pDevice = + (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : nullptr; - INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, Command, DeviceID, pDevice.get()); + INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, + Command, DeviceID, pDevice.get()); - switch (Command) - { - case IPC_CMD_OPEN: - { - u32 Mode = Memory::Read_U32(_Address + 0x10); - DeviceID = getFreeDeviceId(); + switch (Command) + { + case IPC_CMD_OPEN: + { + u32 Mode = Memory::Read_U32(_Address + 0x10); + DeviceID = getFreeDeviceId(); - std::string DeviceName = Memory::GetString(Memory::Read_U32(_Address + 0xC)); + std::string DeviceName = Memory::GetString(Memory::Read_U32(_Address + 0xC)); - WARN_LOG(WII_IPC_HLE, "Trying to open %s as %d", DeviceName.c_str(), DeviceID); - if (DeviceID >= 0) - { - if (DeviceName.find("/dev/es") == 0) - { - u32 j; - for (j=0; jOpen(_Address, Mode); - Memory::Write_U32(DeviceID, _Address+4); - break; - } - } + WARN_LOG(WII_IPC_HLE, "Trying to open %s as %d", DeviceName.c_str(), DeviceID); + if (DeviceID >= 0) + { + if (DeviceName.find("/dev/es") == 0) + { + u32 j; + for (j = 0; j < ES_MAX_COUNT; j++) + { + if (!es_inuse[j]) + { + es_inuse[j] = true; + g_FdMap[DeviceID] = es_handles[j]; + result = es_handles[j]->Open(_Address, Mode); + Memory::Write_U32(DeviceID, _Address + 4); + break; + } + } - if (j == ES_MAX_COUNT) - { - Memory::Write_U32(FS_EESEXHAUSTED, _Address + 4); - result = IWII_IPC_HLE_Device::GetDefaultReply(); - } - } - else if (DeviceName.find("/dev/") == 0) - { - pDevice = GetDeviceByName(DeviceName); - if (pDevice) - { - g_FdMap[DeviceID] = pDevice; - result = pDevice->Open(_Address, Mode); - INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)", - pDevice->GetDeviceName().c_str(), DeviceID, Mode); - Memory::Write_U32(DeviceID, _Address+4); - } - else - { - WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str()); - Memory::Write_U32(FS_ENOENT, _Address+4); - result = IWII_IPC_HLE_Device::GetDefaultReply(); - } - } - else - { - pDevice = CreateFileIO(DeviceID, DeviceName); - result = pDevice->Open(_Address, Mode); + if (j == ES_MAX_COUNT) + { + Memory::Write_U32(FS_EESEXHAUSTED, _Address + 4); + result = IWII_IPC_HLE_Device::GetDefaultReply(); + } + } + else if (DeviceName.find("/dev/") == 0) + { + pDevice = GetDeviceByName(DeviceName); + if (pDevice) + { + g_FdMap[DeviceID] = pDevice; + result = pDevice->Open(_Address, Mode); + INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)", + pDevice->GetDeviceName().c_str(), DeviceID, Mode); + Memory::Write_U32(DeviceID, _Address + 4); + } + else + { + WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str()); + Memory::Write_U32(FS_ENOENT, _Address + 4); + result = IWII_IPC_HLE_Device::GetDefaultReply(); + } + } + else + { + pDevice = CreateFileIO(DeviceID, DeviceName); + result = pDevice->Open(_Address, Mode); - INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)", - pDevice->GetDeviceName().c_str(), DeviceID, Mode); - if (Memory::Read_U32(_Address + 4) == (u32)DeviceID) - { - g_FdMap[DeviceID] = pDevice; - } - } - } - else - { - Memory::Write_U32(FS_EFDEXHAUSTED, _Address + 4); - result = IWII_IPC_HLE_Device::GetDefaultReply(); - } - break; - } - case IPC_CMD_CLOSE: - { - if (pDevice) - { - result = pDevice->Close(_Address); + INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)", + pDevice->GetDeviceName().c_str(), DeviceID, Mode); + if (Memory::Read_U32(_Address + 4) == (u32)DeviceID) + { + g_FdMap[DeviceID] = pDevice; + } + } + } + else + { + Memory::Write_U32(FS_EFDEXHAUSTED, _Address + 4); + result = IWII_IPC_HLE_Device::GetDefaultReply(); + } + break; + } + case IPC_CMD_CLOSE: + { + if (pDevice) + { + result = pDevice->Close(_Address); - for (u32 j=0; jRead(_Address); - } - else - { - Memory::Write_U32(FS_EINVAL, _Address + 4); - result = IWII_IPC_HLE_Device::GetDefaultReply(); - } - break; - } - case IPC_CMD_WRITE: - { - if (pDevice) - { - result = pDevice->Write(_Address); - } - else - { - Memory::Write_U32(FS_EINVAL, _Address + 4); - result = IWII_IPC_HLE_Device::GetDefaultReply(); - } - break; - } - case IPC_CMD_SEEK: - { - if (pDevice) - { - result = pDevice->Seek(_Address); - } - else - { - Memory::Write_U32(FS_EINVAL, _Address + 4); - result = IWII_IPC_HLE_Device::GetDefaultReply(); - } - break; - } - case IPC_CMD_IOCTL: - { - if (pDevice) - { - result = pDevice->IOCtl(_Address); - } - break; - } - case IPC_CMD_IOCTLV: - { - if (pDevice) - { - result = pDevice->IOCtlV(_Address); - } - break; - } - default: - { - _dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, _Address); - break; - } - } + g_FdMap[DeviceID].reset(); + } + else + { + Memory::Write_U32(FS_EINVAL, _Address + 4); + result = IWII_IPC_HLE_Device::GetDefaultReply(); + } + break; + } + case IPC_CMD_READ: + { + if (pDevice) + { + result = pDevice->Read(_Address); + } + else + { + Memory::Write_U32(FS_EINVAL, _Address + 4); + result = IWII_IPC_HLE_Device::GetDefaultReply(); + } + break; + } + case IPC_CMD_WRITE: + { + if (pDevice) + { + result = pDevice->Write(_Address); + } + else + { + Memory::Write_U32(FS_EINVAL, _Address + 4); + result = IWII_IPC_HLE_Device::GetDefaultReply(); + } + break; + } + case IPC_CMD_SEEK: + { + if (pDevice) + { + result = pDevice->Seek(_Address); + } + else + { + Memory::Write_U32(FS_EINVAL, _Address + 4); + result = IWII_IPC_HLE_Device::GetDefaultReply(); + } + break; + } + case IPC_CMD_IOCTL: + { + if (pDevice) + { + result = pDevice->IOCtl(_Address); + } + break; + } + case IPC_CMD_IOCTLV: + { + if (pDevice) + { + result = pDevice->IOCtlV(_Address); + } + break; + } + default: + { + _dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, _Address); + break; + } + } - // Ensure replies happen in order - const s64 ticks_until_last_reply = last_reply_time - CoreTiming::GetTicks(); - if (ticks_until_last_reply > 0) - result.reply_delay_ticks += ticks_until_last_reply; - last_reply_time = CoreTiming::GetTicks() + result.reply_delay_ticks; + // Ensure replies happen in order + const s64 ticks_until_last_reply = last_reply_time - CoreTiming::GetTicks(); + if (ticks_until_last_reply > 0) + result.reply_delay_ticks += ticks_until_last_reply; + last_reply_time = CoreTiming::GetTicks() + result.reply_delay_ticks; - if (result.send_reply) - { - // The original hardware overwrites the command type with the async reply type. - Memory::Write_U32(IPC_REP_ASYNC, _Address); - // IOS also seems to write back the command that was responded to in the FD field. - Memory::Write_U32(Command, _Address + 8); - // Generate a reply to the IPC command - EnqueueReply(_Address, (int)result.reply_delay_ticks); - } + if (result.send_reply) + { + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, _Address); + // IOS also seems to write back the command that was responded to in the FD field. + Memory::Write_U32(Command, _Address + 8); + // Generate a reply to the IPC command + EnqueueReply(_Address, (int)result.reply_delay_ticks); + } } // Happens AS SOON AS IPC gets a new pointer! void EnqueueRequest(u32 address) { - CoreTiming::ScheduleEvent(1000, event_enqueue, address | ENQUEUE_REQUEST_FLAG); + CoreTiming::ScheduleEvent(1000, event_enqueue, address | ENQUEUE_REQUEST_FLAG); } // Called when IOS module has some reply @@ -545,79 +546,78 @@ void EnqueueRequest(u32 address) // Please search for examples of this being called elsewhere. void EnqueueReply(u32 address, int cycles_in_future) { - CoreTiming::ScheduleEvent(cycles_in_future, event_enqueue, address); + CoreTiming::ScheduleEvent(cycles_in_future, event_enqueue, address); } void EnqueueReply_Threadsafe(u32 address, int cycles_in_future) { - CoreTiming::ScheduleEvent_Threadsafe(cycles_in_future, event_enqueue, address); + CoreTiming::ScheduleEvent_Threadsafe(cycles_in_future, event_enqueue, address); } void EnqueueReply_Immediate(u32 address) { - EnqueueEvent(address); + EnqueueEvent(address); } void EnqueueCommandAcknowledgement(u32 address, int cycles_in_future) { - CoreTiming::ScheduleEvent(cycles_in_future, event_enqueue, - address | ENQUEUE_ACKNOWLEDGEMENT_FLAG); + CoreTiming::ScheduleEvent(cycles_in_future, event_enqueue, + address | ENQUEUE_ACKNOWLEDGEMENT_FLAG); } // This is called every IPC_HLE_PERIOD from SystemTimers.cpp // Takes care of routing ipc <-> ipc HLE void Update() { - if (!WII_IPCInterface::IsReady()) - return; + if (!WII_IPCInterface::IsReady()) + return; - if (request_queue.size()) - { - WII_IPCInterface::GenerateAck(request_queue.front()); - INFO_LOG(WII_IPC_HLE, "||-- Acknowledge IPC Request @ 0x%08x", request_queue.front()); - u32 command = request_queue.front(); - request_queue.pop_front(); - ExecuteCommand(command); - return; - } + if (request_queue.size()) + { + WII_IPCInterface::GenerateAck(request_queue.front()); + INFO_LOG(WII_IPC_HLE, "||-- Acknowledge IPC Request @ 0x%08x", request_queue.front()); + u32 command = request_queue.front(); + request_queue.pop_front(); + ExecuteCommand(command); + return; + } - if (reply_queue.size()) - { - WII_IPCInterface::GenerateReply(reply_queue.front()); - INFO_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", reply_queue.front()); - reply_queue.pop_front(); - return; - } + if (reply_queue.size()) + { + WII_IPCInterface::GenerateReply(reply_queue.front()); + INFO_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", reply_queue.front()); + reply_queue.pop_front(); + return; + } - if (ack_queue.size()) - { - WII_IPCInterface::GenerateAck(ack_queue.front()); - WARN_LOG(WII_IPC_HLE, "<<-- Double-ack to IPC Request @ 0x%08x", ack_queue.front()); - ack_queue.pop_front(); - return; - } + if (ack_queue.size()) + { + WII_IPCInterface::GenerateAck(ack_queue.front()); + WARN_LOG(WII_IPC_HLE, "<<-- Double-ack to IPC Request @ 0x%08x", ack_queue.front()); + ack_queue.pop_front(); + return; + } } void UpdateDevices() { - // Check if a hardware device must be updated - for (const auto& entry : g_DeviceMap) - { - if (entry.second->IsOpened()) - { - entry.second->Update(); - } - } + // Check if a hardware device must be updated + for (const auto& entry : g_DeviceMap) + { + if (entry.second->IsOpened()) + { + entry.second->Update(); + } + } } - -} // end of namespace WII_IPC_HLE_Interface +} // end of namespace WII_IPC_HLE_Interface // TODO: create WII_IPC_HLE_Device.cpp ? void IWII_IPC_HLE_Device::DoStateShared(PointerWrap& p) { - p.Do(m_Name); - p.Do(m_DeviceID); - p.Do(m_Hardware); - p.Do(m_Active); + p.Do(m_Name); + p.Do(m_DeviceID); + p.Do(m_Hardware); + p.Do(m_Active); } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h index f442d02a78..2a5f1a28e5 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.h @@ -17,30 +17,29 @@ class PointerWrap; struct IPCCommandResult { - bool send_reply; - u64 reply_delay_ticks; + bool send_reply; + u64 reply_delay_ticks; }; enum IPCCommandType : u32 { - IPC_CMD_OPEN = 1, - IPC_CMD_CLOSE = 2, - IPC_CMD_READ = 3, - IPC_CMD_WRITE = 4, - IPC_CMD_SEEK = 5, - IPC_CMD_IOCTL = 6, - IPC_CMD_IOCTLV = 7, - // IPC_REP_ASYNC is used for messages that are automatically - // sent to an IOS queue when an asynchronous syscall completes. - // Reference: http://wiibrew.org/wiki/IOS - IPC_REP_ASYNC = 8 + IPC_CMD_OPEN = 1, + IPC_CMD_CLOSE = 2, + IPC_CMD_READ = 3, + IPC_CMD_WRITE = 4, + IPC_CMD_SEEK = 5, + IPC_CMD_IOCTL = 6, + IPC_CMD_IOCTLV = 7, + // IPC_REP_ASYNC is used for messages that are automatically + // sent to an IOS queue when an asynchronous syscall completes. + // Reference: http://wiibrew.org/wiki/IOS + IPC_REP_ASYNC = 8 }; namespace WII_IPC_HLE_Interface { - -#define IPC_FIRST_ID 0x00 // First IPC device ID -#define IPC_MAX_FILES 0x10 // First IPC file ID +#define IPC_FIRST_ID 0x00 // First IPC device ID +#define IPC_MAX_FILES 0x10 // First IPC file ID // Init void Init(); @@ -52,7 +51,7 @@ void Shutdown(); void Reset(bool _bHard = false); // Do State -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); // Set default content file void SetDefaultContentFile(const std::string& _rFilename); @@ -60,7 +59,6 @@ void ES_DIVerify(const std::vector& tmd); void SDIO_EventNotify(); - std::shared_ptr CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName); std::shared_ptr GetDeviceByName(const std::string& _rDeviceName); @@ -81,4 +79,4 @@ void EnqueueReply_Threadsafe(u32 address, int cycles_in_future = 0); void EnqueueReply_Immediate(u32 address); void EnqueueCommandAcknowledgement(u32 _Address, int cycles_in_future = 0); -} // end of namespace WII_IPC_HLE_Interface +} // end of namespace WII_IPC_HLE_Interface diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device.h index a5100a4953..f294aff9eb 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device.h @@ -13,252 +13,250 @@ #include "Core/HW/Memmap.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" -#define FS_SUCCESS (u32)0 // Success -#define FS_EACCES (u32)-1 // Permission denied -#define FS_EEXIST (u32)-2 // File exists -#define FS_EINVAL (u32)-4 // Invalid argument Invalid FD -#define FS_ENOENT (u32)-6 // File not found -#define FS_EBUSY (u32)-8 // Resource busy -#define FS_EIO (u32)-12 // Returned on ECC error -#define FS_ENOMEM (u32)-22 // Alloc failed during request -#define FS_EFATAL (u32)-101 // Fatal error -#define FS_EACCESS (u32)-102 // Permission denied -#define FS_ECORRUPT (u32)-103 // returned for "corrupted" NAND -#define FS_EEXIST2 (u32)-105 // File exists -#define FS_ENOENT2 (u32)-106 // File not found -#define FS_ENFILE (u32)-107 // Too many fds open -#define FS_EFBIG (u32)-108 // Max block count reached? -#define FS_EFDEXHAUSTED (u32)-109 // Too many fds open -#define FS_ENAMELEN (u32)-110 // Pathname is too long -#define FS_EFDOPEN (u32)-111 // FD is already open -#define FS_EIO2 (u32)-114 // Returned on ECC error -#define FS_ENOTEMPTY (u32)-115 // Directory not empty -#define FS_EDIRDEPTH (u32)-116 // Max directory depth exceeded -#define FS_EBUSY2 (u32)-118 // Resource busy +#define FS_SUCCESS (u32)0 // Success +#define FS_EACCES (u32) - 1 // Permission denied +#define FS_EEXIST (u32) - 2 // File exists +#define FS_EINVAL (u32) - 4 // Invalid argument Invalid FD +#define FS_ENOENT (u32) - 6 // File not found +#define FS_EBUSY (u32) - 8 // Resource busy +#define FS_EIO (u32) - 12 // Returned on ECC error +#define FS_ENOMEM (u32) - 22 // Alloc failed during request +#define FS_EFATAL (u32) - 101 // Fatal error +#define FS_EACCESS (u32) - 102 // Permission denied +#define FS_ECORRUPT (u32) - 103 // returned for "corrupted" NAND +#define FS_EEXIST2 (u32) - 105 // File exists +#define FS_ENOENT2 (u32) - 106 // File not found +#define FS_ENFILE (u32) - 107 // Too many fds open +#define FS_EFBIG (u32) - 108 // Max block count reached? +#define FS_EFDEXHAUSTED (u32) - 109 // Too many fds open +#define FS_ENAMELEN (u32) - 110 // Pathname is too long +#define FS_EFDOPEN (u32) - 111 // FD is already open +#define FS_EIO2 (u32) - 114 // Returned on ECC error +#define FS_ENOTEMPTY (u32) - 115 // Directory not empty +#define FS_EDIRDEPTH (u32) - 116 // Max directory depth exceeded +#define FS_EBUSY2 (u32) - 118 // Resource busy //#define FS_EFATAL (u32)-119 // Fatal error not used by IOS as fatal ERROR -#define FS_EESEXHAUSTED (u32)-1016 // Max of 2 ES handles at a time +#define FS_EESEXHAUSTED (u32) - 1016 // Max of 2 ES handles at a time // A struct for IOS ioctlv calls struct SIOCtlVBuffer { - SIOCtlVBuffer(u32 _Address) : m_Address(_Address) - { - // These are the Ioctlv parameters in the IOS communication. The BufferVector - // is a memory address offset at where the in and out buffer addresses are - // stored. - Parameter = Memory::Read_U32(m_Address + 0x0C); // command 3, arg0 - NumberInBuffer = Memory::Read_U32(m_Address + 0x10); // 4, arg1 - NumberPayloadBuffer = Memory::Read_U32(m_Address + 0x14); // 5, arg2 - BufferVector = Memory::Read_U32(m_Address + 0x18); // 6, arg3 + SIOCtlVBuffer(u32 _Address) : m_Address(_Address) + { + // These are the Ioctlv parameters in the IOS communication. The BufferVector + // is a memory address offset at where the in and out buffer addresses are + // stored. + Parameter = Memory::Read_U32(m_Address + 0x0C); // command 3, arg0 + NumberInBuffer = Memory::Read_U32(m_Address + 0x10); // 4, arg1 + NumberPayloadBuffer = Memory::Read_U32(m_Address + 0x14); // 5, arg2 + BufferVector = Memory::Read_U32(m_Address + 0x18); // 6, arg3 - // The start of the out buffer - u32 BufferVectorOffset = BufferVector; + // The start of the out buffer + u32 BufferVectorOffset = BufferVector; - // Write the address and size for all in messages - for (u32 i = 0; i < NumberInBuffer; i++) - { - SBuffer Buffer; - Buffer.m_Address = Memory::Read_U32(BufferVectorOffset); - BufferVectorOffset += 4; - Buffer.m_Size = Memory::Read_U32(BufferVectorOffset); - BufferVectorOffset += 4; - InBuffer.push_back(Buffer); - DEBUG_LOG(WII_IPC_HLE, "SIOCtlVBuffer in%i: 0x%08x, 0x%x", - i, Buffer.m_Address, Buffer.m_Size); - } + // Write the address and size for all in messages + for (u32 i = 0; i < NumberInBuffer; i++) + { + SBuffer Buffer; + Buffer.m_Address = Memory::Read_U32(BufferVectorOffset); + BufferVectorOffset += 4; + Buffer.m_Size = Memory::Read_U32(BufferVectorOffset); + BufferVectorOffset += 4; + InBuffer.push_back(Buffer); + DEBUG_LOG(WII_IPC_HLE, "SIOCtlVBuffer in%i: 0x%08x, 0x%x", i, Buffer.m_Address, + Buffer.m_Size); + } - // Write the address and size for all out or in-out messages - for (u32 i = 0; i < NumberPayloadBuffer; i++) - { - SBuffer Buffer; - Buffer.m_Address = Memory::Read_U32(BufferVectorOffset); - BufferVectorOffset += 4; - Buffer.m_Size = Memory::Read_U32(BufferVectorOffset); - BufferVectorOffset += 4; - PayloadBuffer.push_back(Buffer); - DEBUG_LOG(WII_IPC_HLE, "SIOCtlVBuffer io%i: 0x%08x, 0x%x", - i, Buffer.m_Address, Buffer.m_Size); - } - } + // Write the address and size for all out or in-out messages + for (u32 i = 0; i < NumberPayloadBuffer; i++) + { + SBuffer Buffer; + Buffer.m_Address = Memory::Read_U32(BufferVectorOffset); + BufferVectorOffset += 4; + Buffer.m_Size = Memory::Read_U32(BufferVectorOffset); + BufferVectorOffset += 4; + PayloadBuffer.push_back(Buffer); + DEBUG_LOG(WII_IPC_HLE, "SIOCtlVBuffer io%i: 0x%08x, 0x%x", i, Buffer.m_Address, + Buffer.m_Size); + } + } - const u32 m_Address; + const u32 m_Address; - u32 Parameter; - u32 NumberInBuffer; - u32 NumberPayloadBuffer; - u32 BufferVector; + u32 Parameter; + u32 NumberInBuffer; + u32 NumberPayloadBuffer; + u32 BufferVector; - struct SBuffer { u32 m_Address, m_Size; }; - std::vector InBuffer; - std::vector PayloadBuffer; + struct SBuffer + { + u32 m_Address, m_Size; + }; + std::vector InBuffer; + std::vector PayloadBuffer; }; class IWII_IPC_HLE_Device { public: + IWII_IPC_HLE_Device(u32 _DeviceID, const std::string& _rName, bool _Hardware = true) + : m_Name(_rName), m_DeviceID(_DeviceID), m_Hardware(_Hardware), m_Active(false) + { + } - IWII_IPC_HLE_Device(u32 _DeviceID, const std::string& _rName, bool _Hardware = true) : - m_Name(_rName), - m_DeviceID(_DeviceID), - m_Hardware(_Hardware), - m_Active(false) - { - } + virtual ~IWII_IPC_HLE_Device() {} + // Release any resources which might interfere with savestating. + virtual void PrepareForState(PointerWrap::Mode mode) {} + virtual void DoState(PointerWrap& p) + { + DoStateShared(p); + p.Do(m_Active); + } - virtual ~IWII_IPC_HLE_Device() - { - } + void DoStateShared(PointerWrap& p); - // Release any resources which might interfere with savestating. - virtual void PrepareForState(PointerWrap::Mode mode) - { - } + const std::string& GetDeviceName() const { return m_Name; } + u32 GetDeviceID() const { return m_DeviceID; } + virtual IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) + { + (void)_Mode; + WARN_LOG(WII_IPC_HLE, "%s does not support Open()", m_Name.c_str()); + Memory::Write_U32(FS_ENOENT, _CommandAddress + 4); + m_Active = true; + return GetDefaultReply(); + } - virtual void DoState(PointerWrap& p) - { - DoStateShared(p); - p.Do(m_Active); - } + virtual IPCCommandResult Close(u32 _CommandAddress, bool _bForce = false) + { + WARN_LOG(WII_IPC_HLE, "%s does not support Close()", m_Name.c_str()); + if (!_bForce) + Memory::Write_U32(FS_EINVAL, _CommandAddress + 4); + m_Active = false; + return GetDefaultReply(); + } - void DoStateShared(PointerWrap& p); - - const std::string& GetDeviceName() const { return m_Name; } - u32 GetDeviceID() const { return m_DeviceID; } - - virtual IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) - { - (void)_Mode; - WARN_LOG(WII_IPC_HLE, "%s does not support Open()", m_Name.c_str()); - Memory::Write_U32(FS_ENOENT, _CommandAddress + 4); - m_Active = true; - return GetDefaultReply(); - } - - virtual IPCCommandResult Close(u32 _CommandAddress, bool _bForce = false) - { - WARN_LOG(WII_IPC_HLE, "%s does not support Close()", m_Name.c_str()); - if (!_bForce) - Memory::Write_U32(FS_EINVAL, _CommandAddress + 4); - m_Active = false; - return GetDefaultReply(); - } - -#define UNIMPLEMENTED_CMD(cmd) WARN_LOG(WII_IPC_HLE, "%s does not support "#cmd"()", m_Name.c_str()); return GetDefaultReply(); - virtual IPCCommandResult Seek(u32) { UNIMPLEMENTED_CMD(Seek) } - virtual IPCCommandResult Read(u32) { UNIMPLEMENTED_CMD(Read) } - virtual IPCCommandResult Write(u32) { UNIMPLEMENTED_CMD(Write) } - virtual IPCCommandResult IOCtl(u32) { UNIMPLEMENTED_CMD(IOCtl) } - virtual IPCCommandResult IOCtlV(u32) { UNIMPLEMENTED_CMD(IOCtlV) } +#define UNIMPLEMENTED_CMD(cmd) \ + WARN_LOG(WII_IPC_HLE, "%s does not support " #cmd "()", m_Name.c_str()); \ + return GetDefaultReply(); + virtual IPCCommandResult Seek(u32) { UNIMPLEMENTED_CMD(Seek) } + virtual IPCCommandResult Read(u32) { UNIMPLEMENTED_CMD(Read) } + virtual IPCCommandResult Write(u32) { UNIMPLEMENTED_CMD(Write) } + virtual IPCCommandResult IOCtl(u32) { UNIMPLEMENTED_CMD(IOCtl) } + virtual IPCCommandResult IOCtlV(u32) { UNIMPLEMENTED_CMD(IOCtlV) } #undef UNIMPLEMENTED_CMD - virtual u32 Update() { return 0; } + virtual u32 Update() { return 0; } + virtual bool IsHardware() { return m_Hardware; } + virtual bool IsOpened() { return m_Active; } + // Returns an IPCCommandResult for a reply that takes 250 us (arbitrarily chosen value) + static IPCCommandResult GetDefaultReply() + { + return {true, SystemTimers::GetTicksPerSecond() / 4000}; + } + // Returns an IPCCommandResult with no reply. Useful for async commands that will generate a reply + // later + static IPCCommandResult GetNoReply() { return {false, 0}; } + std::string m_Name; - virtual bool IsHardware() { return m_Hardware; } - virtual bool IsOpened() { return m_Active; } - - // Returns an IPCCommandResult for a reply that takes 250 us (arbitrarily chosen value) - static IPCCommandResult GetDefaultReply() { return { true, SystemTimers::GetTicksPerSecond() / 4000 }; } - // Returns an IPCCommandResult with no reply. Useful for async commands that will generate a reply later - static IPCCommandResult GetNoReply() { return { false, 0 }; } - - std::string m_Name; protected: + // STATE_TO_SAVE + u32 m_DeviceID; + bool m_Hardware; + bool m_Active; - // STATE_TO_SAVE - u32 m_DeviceID; - bool m_Hardware; - bool m_Active; + // Write out the IPC struct from _CommandAddress to _NumberOfCommands numbers + // of 4 byte commands. + void DumpCommands(u32 _CommandAddress, size_t _NumberOfCommands = 8, + LogTypes::LOG_TYPE LogType = LogTypes::WII_IPC_HLE, + LogTypes::LOG_LEVELS Verbosity = LogTypes::LDEBUG) + { + GENERIC_LOG(LogType, Verbosity, "CommandDump of %s", GetDeviceName().c_str()); + for (u32 i = 0; i < _NumberOfCommands; i++) + { + GENERIC_LOG(LogType, Verbosity, " Command%02i: 0x%08x", i, + Memory::Read_U32(_CommandAddress + i * 4)); + } + } - // Write out the IPC struct from _CommandAddress to _NumberOfCommands numbers - // of 4 byte commands. - void DumpCommands(u32 _CommandAddress, size_t _NumberOfCommands = 8, - LogTypes::LOG_TYPE LogType = LogTypes::WII_IPC_HLE, - LogTypes::LOG_LEVELS Verbosity = LogTypes::LDEBUG) - { - GENERIC_LOG(LogType, Verbosity, "CommandDump of %s", - GetDeviceName().c_str()); - for (u32 i = 0; i < _NumberOfCommands; i++) - { - GENERIC_LOG(LogType, Verbosity, " Command%02i: 0x%08x", i, - Memory::Read_U32(_CommandAddress + i*4)); - } - } + void DumpAsync(u32 BufferVector, u32 NumberInBuffer, u32 NumberOutBuffer, + LogTypes::LOG_TYPE LogType = LogTypes::WII_IPC_HLE, + LogTypes::LOG_LEVELS Verbosity = LogTypes::LDEBUG) + { + GENERIC_LOG(LogType, Verbosity, "======= DumpAsync ======"); - void DumpAsync(u32 BufferVector, u32 NumberInBuffer, u32 NumberOutBuffer, - LogTypes::LOG_TYPE LogType = LogTypes::WII_IPC_HLE, - LogTypes::LOG_LEVELS Verbosity = LogTypes::LDEBUG) - { - GENERIC_LOG(LogType, Verbosity, "======= DumpAsync ======"); + u32 BufferOffset = BufferVector; + for (u32 i = 0; i < NumberInBuffer; i++) + { + u32 InBuffer = Memory::Read_U32(BufferOffset); + BufferOffset += 4; + u32 InBufferSize = Memory::Read_U32(BufferOffset); + BufferOffset += 4; - u32 BufferOffset = BufferVector; - for (u32 i = 0; i < NumberInBuffer; i++) - { - u32 InBuffer = Memory::Read_U32(BufferOffset); BufferOffset += 4; - u32 InBufferSize = Memory::Read_U32(BufferOffset); BufferOffset += 4; + GENERIC_LOG(LogType, LogTypes::LINFO, "%s - IOCtlV InBuffer[%i]:", GetDeviceName().c_str(), + i); - GENERIC_LOG(LogType, LogTypes::LINFO, "%s - IOCtlV InBuffer[%i]:", - GetDeviceName().c_str(), i); + std::string Temp; + for (u32 j = 0; j < InBufferSize; j++) + { + Temp += StringFromFormat("%02x ", Memory::Read_U8(InBuffer + j)); + } - std::string Temp; - for (u32 j = 0; j < InBufferSize; j++) - { - Temp += StringFromFormat("%02x ", Memory::Read_U8(InBuffer+j)); - } + GENERIC_LOG(LogType, LogTypes::LDEBUG, " Buffer: %s", Temp.c_str()); + } - GENERIC_LOG(LogType, LogTypes::LDEBUG, " Buffer: %s", Temp.c_str()); - } + for (u32 i = 0; i < NumberOutBuffer; i++) + { + u32 OutBuffer = Memory::Read_U32(BufferOffset); + BufferOffset += 4; + u32 OutBufferSize = Memory::Read_U32(BufferOffset); + BufferOffset += 4; - for (u32 i = 0; i < NumberOutBuffer; i++) - { - u32 OutBuffer = Memory::Read_U32(BufferOffset); BufferOffset += 4; - u32 OutBufferSize = Memory::Read_U32(BufferOffset); BufferOffset += 4; + GENERIC_LOG(LogType, LogTypes::LINFO, "%s - IOCtlV OutBuffer[%i]:", GetDeviceName().c_str(), + i); + GENERIC_LOG(LogType, LogTypes::LINFO, " OutBuffer: 0x%08x (0x%x):", OutBuffer, + OutBufferSize); - GENERIC_LOG(LogType, LogTypes::LINFO, "%s - IOCtlV OutBuffer[%i]:", - GetDeviceName().c_str(), i); - GENERIC_LOG(LogType, LogTypes::LINFO, " OutBuffer: 0x%08x (0x%x):", - OutBuffer, OutBufferSize); - - if (Verbosity >= LogTypes::LOG_LEVELS::LINFO) - DumpCommands(OutBuffer, OutBufferSize, LogType, Verbosity); - } - } + if (Verbosity >= LogTypes::LOG_LEVELS::LINFO) + DumpCommands(OutBuffer, OutBufferSize, LogType, Verbosity); + } + } }; class CWII_IPC_HLE_Device_stub : public IWII_IPC_HLE_Device { public: - CWII_IPC_HLE_Device_stub(u32 DeviceID, const std::string& Name) - : IWII_IPC_HLE_Device(DeviceID, Name) - { - } + CWII_IPC_HLE_Device_stub(u32 DeviceID, const std::string& Name) + : IWII_IPC_HLE_Device(DeviceID, Name) + { + } - IPCCommandResult Open(u32 CommandAddress, u32 Mode) override - { - (void)Mode; - WARN_LOG(WII_IPC_HLE, "%s faking Open()", m_Name.c_str()); - Memory::Write_U32(GetDeviceID(), CommandAddress + 4); - m_Active = true; - return GetDefaultReply(); - } - IPCCommandResult Close(u32 CommandAddress, bool bForce = false) override - { - WARN_LOG(WII_IPC_HLE, "%s faking Close()", m_Name.c_str()); - if (!bForce) - Memory::Write_U32(FS_SUCCESS, CommandAddress + 4); - m_Active = false; - return GetDefaultReply(); - } + IPCCommandResult Open(u32 CommandAddress, u32 Mode) override + { + (void)Mode; + WARN_LOG(WII_IPC_HLE, "%s faking Open()", m_Name.c_str()); + Memory::Write_U32(GetDeviceID(), CommandAddress + 4); + m_Active = true; + return GetDefaultReply(); + } + IPCCommandResult Close(u32 CommandAddress, bool bForce = false) override + { + WARN_LOG(WII_IPC_HLE, "%s faking Close()", m_Name.c_str()); + if (!bForce) + Memory::Write_U32(FS_SUCCESS, CommandAddress + 4); + m_Active = false; + return GetDefaultReply(); + } - IPCCommandResult IOCtl(u32 CommandAddress) override - { - WARN_LOG(WII_IPC_HLE, "%s faking IOCtl()", m_Name.c_str()); - Memory::Write_U32(FS_SUCCESS, CommandAddress + 4); - return GetDefaultReply(); - } - IPCCommandResult IOCtlV(u32 CommandAddress) override - { - WARN_LOG(WII_IPC_HLE, "%s faking IOCtlV()", m_Name.c_str()); - Memory::Write_U32(FS_SUCCESS, CommandAddress + 4); - return GetDefaultReply(); - } + IPCCommandResult IOCtl(u32 CommandAddress) override + { + WARN_LOG(WII_IPC_HLE, "%s faking IOCtl()", m_Name.c_str()); + Memory::Write_U32(FS_SUCCESS, CommandAddress + 4); + return GetDefaultReply(); + } + IPCCommandResult IOCtlV(u32 CommandAddress) override + { + WARN_LOG(WII_IPC_HLE, "%s faking IOCtlV()", m_Name.c_str()); + Memory::Write_U32(FS_SUCCESS, CommandAddress + 4); + return GetDefaultReply(); + } }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_DI.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_DI.cpp index 36c1d046c3..03f10d75b0 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_DI.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_DI.cpp @@ -17,7 +17,7 @@ #include "Core/IPC_HLE/WII_IPC_HLE_Device_DI.h" CWII_IPC_HLE_Device_di::CWII_IPC_HLE_Device_di(u32 _DeviceID, const std::string& _rDeviceName) - : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) { } @@ -27,139 +27,143 @@ CWII_IPC_HLE_Device_di::~CWII_IPC_HLE_Device_di() void CWII_IPC_HLE_Device_di::DoState(PointerWrap& p) { - DoStateShared(p); - p.Do(m_commands_to_execute); + DoStateShared(p); + p.Do(m_commands_to_execute); } IPCCommandResult CWII_IPC_HLE_Device_di::Open(u32 _CommandAddress, u32 _Mode) { - Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); - m_Active = true; - return GetDefaultReply(); + Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); + m_Active = true; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_di::Close(u32 _CommandAddress, bool _bForce) { - if (!_bForce) - Memory::Write_U32(0, _CommandAddress + 4); - m_Active = false; - return GetDefaultReply(); + if (!_bForce) + Memory::Write_U32(0, _CommandAddress + 4); + m_Active = false; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_di::IOCtl(u32 _CommandAddress) { - // DI IOCtls are handled in a special way by Dolphin - // compared to other WII_IPC_HLE functions. - // This is a wrapper around DVDInterface's ExecuteCommand, - // which will execute commands more or less asynchronously. - // Only one command can be executed at a time, so commands - // are queued until DVDInterface is ready to handle them. + // DI IOCtls are handled in a special way by Dolphin + // compared to other WII_IPC_HLE functions. + // This is a wrapper around DVDInterface's ExecuteCommand, + // which will execute commands more or less asynchronously. + // Only one command can be executed at a time, so commands + // are queued until DVDInterface is ready to handle them. - bool ready_to_execute = m_commands_to_execute.empty(); - m_commands_to_execute.push_back(_CommandAddress); - if (ready_to_execute) - StartIOCtl(_CommandAddress); + bool ready_to_execute = m_commands_to_execute.empty(); + m_commands_to_execute.push_back(_CommandAddress); + if (ready_to_execute) + StartIOCtl(_CommandAddress); - // DVDInterface handles the timing and we handle the reply, - // so WII_IPC_HLE shouldn't handle anything. - return GetNoReply(); + // DVDInterface handles the timing and we handle the reply, + // so WII_IPC_HLE shouldn't handle anything. + return GetNoReply(); } void CWII_IPC_HLE_Device_di::StartIOCtl(u32 command_address) { - u32 BufferIn = Memory::Read_U32(command_address + 0x10); - u32 BufferInSize = Memory::Read_U32(command_address + 0x14); - u32 BufferOut = Memory::Read_U32(command_address + 0x18); - u32 BufferOutSize = Memory::Read_U32(command_address + 0x1C); + u32 BufferIn = Memory::Read_U32(command_address + 0x10); + u32 BufferInSize = Memory::Read_U32(command_address + 0x14); + u32 BufferOut = Memory::Read_U32(command_address + 0x18); + u32 BufferOutSize = Memory::Read_U32(command_address + 0x1C); - u32 command_0 = Memory::Read_U32(BufferIn); - u32 command_1 = Memory::Read_U32(BufferIn + 4); - u32 command_2 = Memory::Read_U32(BufferIn + 8); + u32 command_0 = Memory::Read_U32(BufferIn); + u32 command_1 = Memory::Read_U32(BufferIn + 4); + u32 command_2 = Memory::Read_U32(BufferIn + 8); - DEBUG_LOG(WII_IPC_DVD, "IOCtl Command(0x%08x) BufferIn(0x%08x, 0x%x) BufferOut(0x%08x, 0x%x)", - command_0, BufferIn, BufferInSize, BufferOut, BufferOutSize); + DEBUG_LOG(WII_IPC_DVD, "IOCtl Command(0x%08x) BufferIn(0x%08x, 0x%x) BufferOut(0x%08x, 0x%x)", + command_0, BufferIn, BufferInSize, BufferOut, BufferOutSize); - // TATSUNOKO VS CAPCOM: Gets here with BufferOut == 0!!! - if (BufferOut != 0) - { - // Set out buffer to zeroes as a safety precaution - // to avoid answering nonsense values - Memory::Memset(BufferOut, 0, BufferOutSize); - } + // TATSUNOKO VS CAPCOM: Gets here with BufferOut == 0!!! + if (BufferOut != 0) + { + // Set out buffer to zeroes as a safety precaution + // to avoid answering nonsense values + Memory::Memset(BufferOut, 0, BufferOutSize); + } - // DVDInterface's ExecuteCommand handles most of the work. - // The IOCtl callback is used to generate a reply afterwards. - DVDInterface::ExecuteCommand(command_0, command_1, command_2, BufferOut, BufferOutSize, true); + // DVDInterface's ExecuteCommand handles most of the work. + // The IOCtl callback is used to generate a reply afterwards. + DVDInterface::ExecuteCommand(command_0, command_1, command_2, BufferOut, BufferOutSize, true); } void CWII_IPC_HLE_Device_di::FinishIOCtl(DVDInterface::DIInterruptType interrupt_type) { - if (m_commands_to_execute.empty()) - { - PanicAlert("WII_IPC_HLE_Device_DI: There is no command to execute!"); - return; - } + if (m_commands_to_execute.empty()) + { + PanicAlert("WII_IPC_HLE_Device_DI: There is no command to execute!"); + return; + } - // This command has been executed, so it's removed from the queue - u32 command_address = m_commands_to_execute.front(); - m_commands_to_execute.pop_front(); + // This command has been executed, so it's removed from the queue + u32 command_address = m_commands_to_execute.front(); + m_commands_to_execute.pop_front(); - // The DI interrupt type is used as a return value - Memory::Write_U32(interrupt_type, command_address + 4); + // The DI interrupt type is used as a return value + Memory::Write_U32(interrupt_type, command_address + 4); - // The original hardware overwrites the command type with the async reply type. - Memory::Write_U32(IPC_REP_ASYNC, command_address); - // IOS also seems to write back the command that was responded to in the FD field. - Memory::Write_U32(Memory::Read_U32(command_address), command_address + 8); - // Generate a reply to the IPC command - WII_IPC_HLE_Interface::EnqueueReply_Immediate(command_address); + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, command_address); + // IOS also seems to write back the command that was responded to in the FD field. + Memory::Write_U32(Memory::Read_U32(command_address), command_address + 8); + // Generate a reply to the IPC command + WII_IPC_HLE_Interface::EnqueueReply_Immediate(command_address); - // DVDInterface is now ready to execute another command, - // so we start executing a command from the queue if there is one - if (!m_commands_to_execute.empty()) - StartIOCtl(m_commands_to_execute.front()); + // DVDInterface is now ready to execute another command, + // so we start executing a command from the queue if there is one + if (!m_commands_to_execute.empty()) + StartIOCtl(m_commands_to_execute.front()); } IPCCommandResult CWII_IPC_HLE_Device_di::IOCtlV(u32 _CommandAddress) { - SIOCtlVBuffer CommandBuffer(_CommandAddress); + SIOCtlVBuffer CommandBuffer(_CommandAddress); - // Prepare the out buffer(s) with zeros as a safety precaution - // to avoid returning bad values - for (u32 i = 0; i < CommandBuffer.NumberPayloadBuffer; i++) - { - Memory::Memset(CommandBuffer.PayloadBuffer[i].m_Address, 0, - CommandBuffer.PayloadBuffer[i].m_Size); - } + // Prepare the out buffer(s) with zeros as a safety precaution + // to avoid returning bad values + for (u32 i = 0; i < CommandBuffer.NumberPayloadBuffer; i++) + { + Memory::Memset(CommandBuffer.PayloadBuffer[i].m_Address, 0, + CommandBuffer.PayloadBuffer[i].m_Size); + } - u32 ReturnValue = 0; - switch (CommandBuffer.Parameter) - { - case DVDInterface::DVDLowOpenPartition: - { - _dbg_assert_msg_(WII_IPC_DVD, CommandBuffer.InBuffer[1].m_Address == 0, "DVDLowOpenPartition with ticket"); - _dbg_assert_msg_(WII_IPC_DVD, CommandBuffer.InBuffer[2].m_Address == 0, "DVDLowOpenPartition with cert chain"); + u32 ReturnValue = 0; + switch (CommandBuffer.Parameter) + { + case DVDInterface::DVDLowOpenPartition: + { + _dbg_assert_msg_(WII_IPC_DVD, CommandBuffer.InBuffer[1].m_Address == 0, + "DVDLowOpenPartition with ticket"); + _dbg_assert_msg_(WII_IPC_DVD, CommandBuffer.InBuffer[2].m_Address == 0, + "DVDLowOpenPartition with cert chain"); - u64 const partition_offset = ((u64)Memory::Read_U32(CommandBuffer.InBuffer[0].m_Address + 4) << 2); - DVDInterface::ChangePartition(partition_offset); + u64 const partition_offset = + ((u64)Memory::Read_U32(CommandBuffer.InBuffer[0].m_Address + 4) << 2); + DVDInterface::ChangePartition(partition_offset); - INFO_LOG(WII_IPC_DVD, "DVDLowOpenPartition: partition_offset 0x%016" PRIx64, partition_offset); + INFO_LOG(WII_IPC_DVD, "DVDLowOpenPartition: partition_offset 0x%016" PRIx64, partition_offset); - // Read TMD to the buffer - std::vector tmd_buffer = DVDInterface::GetVolume().GetTMD(); - Memory::CopyToEmu(CommandBuffer.PayloadBuffer[0].m_Address, tmd_buffer.data(), tmd_buffer.size()); - WII_IPC_HLE_Interface::ES_DIVerify(tmd_buffer); + // Read TMD to the buffer + std::vector tmd_buffer = DVDInterface::GetVolume().GetTMD(); + Memory::CopyToEmu(CommandBuffer.PayloadBuffer[0].m_Address, tmd_buffer.data(), + tmd_buffer.size()); + WII_IPC_HLE_Interface::ES_DIVerify(tmd_buffer); - ReturnValue = 1; - } - break; + ReturnValue = 1; + } + break; - default: - ERROR_LOG(WII_IPC_DVD, "IOCtlV: %i", CommandBuffer.Parameter); - _dbg_assert_msg_(WII_IPC_DVD, 0, "IOCtlV: %i", CommandBuffer.Parameter); - break; - } + default: + ERROR_LOG(WII_IPC_DVD, "IOCtlV: %i", CommandBuffer.Parameter); + _dbg_assert_msg_(WII_IPC_DVD, 0, "IOCtlV: %i", CommandBuffer.Parameter); + break; + } - Memory::Write_U32(ReturnValue, _CommandAddress + 4); - return GetDefaultReply(); + Memory::Write_U32(ReturnValue, _CommandAddress + 4); + return GetDefaultReply(); } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_DI.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_DI.h index 7096b655cb..e4dd893ea0 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_DI.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_DI.h @@ -8,28 +8,30 @@ #include "Core/IPC_HLE/WII_IPC_HLE_Device.h" class PointerWrap; -namespace DVDInterface { enum DIInterruptType : int; } +namespace DVDInterface +{ +enum DIInterruptType : int; +} class CWII_IPC_HLE_Device_di : public IWII_IPC_HLE_Device { public: + CWII_IPC_HLE_Device_di(u32 _DeviceID, const std::string& _rDeviceName); - CWII_IPC_HLE_Device_di(u32 _DeviceID, const std::string& _rDeviceName); + virtual ~CWII_IPC_HLE_Device_di(); - virtual ~CWII_IPC_HLE_Device_di(); + void DoState(PointerWrap& p) override; - void DoState(PointerWrap& p) override; + IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; + IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; - IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; - IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; + IPCCommandResult IOCtl(u32 _CommandAddress) override; + IPCCommandResult IOCtlV(u32 _CommandAddress) override; - IPCCommandResult IOCtl(u32 _CommandAddress) override; - IPCCommandResult IOCtlV(u32 _CommandAddress) override; + void FinishIOCtl(DVDInterface::DIInterruptType interrupt_type); - void FinishIOCtl(DVDInterface::DIInterruptType interrupt_type); private: + void StartIOCtl(u32 command_address); - void StartIOCtl(u32 command_address); - - std::deque m_commands_to_execute; + std::deque m_commands_to_execute; }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp index 136533d03e..da4e5db565 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp @@ -16,68 +16,69 @@ #include "Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_fs.h" - static Common::replace_v replacements; -static std::map > openFiles; +static std::map> openFiles; // This is used by several of the FileIO and /dev/fs functions std::string HLE_IPC_BuildFilename(std::string path_wii) { - std::string path_full = File::GetUserPath(D_SESSION_WIIROOT_IDX); + std::string path_full = File::GetUserPath(D_SESSION_WIIROOT_IDX); - // Replaces chars that FAT32 can't support with strings defined in /sys/replace - for (auto& replacement : replacements) - { - for (size_t j = 0; (j = path_wii.find(replacement.first, j)) != path_wii.npos; ++j) - path_wii.replace(j, 1, replacement.second); - } + // Replaces chars that FAT32 can't support with strings defined in /sys/replace + for (auto& replacement : replacements) + { + for (size_t j = 0; (j = path_wii.find(replacement.first, j)) != path_wii.npos; ++j) + path_wii.replace(j, 1, replacement.second); + } - path_full += path_wii; + path_full += path_wii; - return path_full; + return path_full; } void HLE_IPC_CreateVirtualFATFilesystem() { - const int cdbSize = 0x01400000; - const std::string cdbPath = Common::GetTitleDataPath(TITLEID_SYSMENU, Common::FROM_SESSION_ROOT) + "cdb.vff"; - if ((int)File::GetSize(cdbPath) < cdbSize) - { - // cdb.vff is a virtual Fat filesystem created on first launch of sysmenu - // we create it here as it is faster ~3 minutes for me when sysmenu does it ~1 second created here - const u8 cdbHDR[0x20] = {'V', 'F', 'F', 0x20, 0xfe, 0xff, 1, 0, 1, 0x40, 0, 0, 0, 0x20}; - const u8 cdbFAT[4] = {0xf0, 0xff, 0xff, 0xff}; + const int cdbSize = 0x01400000; + const std::string cdbPath = + Common::GetTitleDataPath(TITLEID_SYSMENU, Common::FROM_SESSION_ROOT) + "cdb.vff"; + if ((int)File::GetSize(cdbPath) < cdbSize) + { + // cdb.vff is a virtual Fat filesystem created on first launch of sysmenu + // we create it here as it is faster ~3 minutes for me when sysmenu does it ~1 second created + // here + const u8 cdbHDR[0x20] = {'V', 'F', 'F', 0x20, 0xfe, 0xff, 1, 0, 1, 0x40, 0, 0, 0, 0x20}; + const u8 cdbFAT[4] = {0xf0, 0xff, 0xff, 0xff}; - File::IOFile cdbFile(cdbPath, "wb"); - if (cdbFile) - { - cdbFile.WriteBytes(cdbHDR, 0x20); - cdbFile.WriteBytes(cdbFAT, 0x4); - cdbFile.Seek(0x14020, SEEK_SET); - cdbFile.WriteBytes(cdbFAT, 0x4); - // 20 MiB file - cdbFile.Seek(cdbSize - 1, SEEK_SET); - // write the final 0 to 0 file from the second FAT to 20 MiB - cdbFile.WriteBytes(cdbHDR + 14, 1); - if (!cdbFile.IsGood()) - { - cdbFile.Close(); - File::Delete(cdbPath); - } - cdbFile.Flush(); - cdbFile.Close(); - } - } + File::IOFile cdbFile(cdbPath, "wb"); + if (cdbFile) + { + cdbFile.WriteBytes(cdbHDR, 0x20); + cdbFile.WriteBytes(cdbFAT, 0x4); + cdbFile.Seek(0x14020, SEEK_SET); + cdbFile.WriteBytes(cdbFAT, 0x4); + // 20 MiB file + cdbFile.Seek(cdbSize - 1, SEEK_SET); + // write the final 0 to 0 file from the second FAT to 20 MiB + cdbFile.WriteBytes(cdbHDR + 14, 1); + if (!cdbFile.IsGood()) + { + cdbFile.Close(); + File::Delete(cdbPath); + } + cdbFile.Flush(); + cdbFile.Close(); + } + } } -CWII_IPC_HLE_Device_FileIO::CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, const std::string& _rDeviceName) - : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName, false) // not a real hardware - , m_Mode(0) - , m_SeekPos(0) - , m_file() +CWII_IPC_HLE_Device_FileIO::CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, + const std::string& _rDeviceName) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName, false) // not a real hardware + , + m_Mode(0), m_SeekPos(0), m_file() { - Common::ReadReplacements(replacements); + Common::ReadReplacements(replacements); } CWII_IPC_HLE_Device_FileIO::~CWII_IPC_HLE_Device_FileIO() @@ -86,294 +87,301 @@ CWII_IPC_HLE_Device_FileIO::~CWII_IPC_HLE_Device_FileIO() IPCCommandResult CWII_IPC_HLE_Device_FileIO::Close(u32 _CommandAddress, bool _bForce) { - INFO_LOG(WII_IPC_FILEIO, "FileIO: Close %s (DeviceID=%08x)", m_Name.c_str(), m_DeviceID); - m_Mode = 0; + INFO_LOG(WII_IPC_FILEIO, "FileIO: Close %s (DeviceID=%08x)", m_Name.c_str(), m_DeviceID); + m_Mode = 0; - // Let go of our pointer to the file, it will automatically close if we are the last handle accessing it. - m_file.reset(); + // Let go of our pointer to the file, it will automatically close if we are the last handle + // accessing it. + m_file.reset(); - // Close always return 0 for success - if (_CommandAddress && !_bForce) - Memory::Write_U32(0, _CommandAddress + 4); - m_Active = false; - return GetDefaultReply(); + // Close always return 0 for success + if (_CommandAddress && !_bForce) + Memory::Write_U32(0, _CommandAddress + 4); + m_Active = false; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode) { - m_Mode = _Mode; - u32 ReturnValue = 0; + m_Mode = _Mode; + u32 ReturnValue = 0; - static const char* const Modes[] = - { - "Unk Mode", - "Read only", - "Write only", - "Read and Write" - }; + static const char* const Modes[] = {"Unk Mode", "Read only", "Write only", "Read and Write"}; - m_filepath = HLE_IPC_BuildFilename(m_Name); + m_filepath = HLE_IPC_BuildFilename(m_Name); - // The file must exist before we can open it - // It should be created by ISFS_CreateFile, not here - if (File::Exists(m_filepath) && !File::IsDirectory(m_filepath)) - { - INFO_LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s == %08X)", m_Name.c_str(), Modes[_Mode], _Mode); - OpenFile(); - ReturnValue = m_DeviceID; - } - else - { - WARN_LOG(WII_IPC_FILEIO, "FileIO: Open (%s) failed - File doesn't exist %s", Modes[_Mode], m_filepath.c_str()); - ReturnValue = FS_FILE_NOT_EXIST; - } + // The file must exist before we can open it + // It should be created by ISFS_CreateFile, not here + if (File::Exists(m_filepath) && !File::IsDirectory(m_filepath)) + { + INFO_LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s == %08X)", m_Name.c_str(), Modes[_Mode], _Mode); + OpenFile(); + ReturnValue = m_DeviceID; + } + else + { + WARN_LOG(WII_IPC_FILEIO, "FileIO: Open (%s) failed - File doesn't exist %s", Modes[_Mode], + m_filepath.c_str()); + ReturnValue = FS_FILE_NOT_EXIST; + } - if (_CommandAddress) - Memory::Write_U32(ReturnValue, _CommandAddress+4); - m_Active = true; - return GetDefaultReply(); + if (_CommandAddress) + Memory::Write_U32(ReturnValue, _CommandAddress + 4); + m_Active = true; + return GetDefaultReply(); } // This isn't theadsafe, but it's only called from the CPU thread. void CWII_IPC_HLE_Device_FileIO::OpenFile() { - // On the wii, all file operations are strongly ordered. - // If a game opens the same file twice (or 8 times, looking at you PokePark Wii) - // and writes to one file handle, it will be able to immediately read the written - // data from the other handle. - // On 'real' operating systems, there are various buffers and caches meaning - // applications doing such naughty things will not get expected results. + // On the wii, all file operations are strongly ordered. + // If a game opens the same file twice (or 8 times, looking at you PokePark Wii) + // and writes to one file handle, it will be able to immediately read the written + // data from the other handle. + // On 'real' operating systems, there are various buffers and caches meaning + // applications doing such naughty things will not get expected results. - // So we fix this by catching any attempts to open the same file twice and - // only opening one file. Accesses to a single file handle are ordered. - // - // Hall of Shame: - // - PokePark Wii (gets stuck on the loading screen of Pikachu falling) - // - PokePark 2 (Also gets stuck while loading) - // - Wii System Menu (Can't access the system settings, gets stuck on blank screen) - // - The Beatles: Rock Band (saving doesn't work) + // So we fix this by catching any attempts to open the same file twice and + // only opening one file. Accesses to a single file handle are ordered. + // + // Hall of Shame: + // - PokePark Wii (gets stuck on the loading screen of Pikachu falling) + // - PokePark 2 (Also gets stuck while loading) + // - Wii System Menu (Can't access the system settings, gets stuck on blank screen) + // - The Beatles: Rock Band (saving doesn't work) - // Check if the file has already been opened. - auto search = openFiles.find(m_Name); - if (search != openFiles.end()) - { - m_file = search->second.lock(); // Lock a shared pointer to use. - } - else - { - std::string path = m_Name; - // This code will be called when all references to the shared pointer below have been removed. - auto deleter = [path](File::IOFile* ptr) - { - delete ptr; // IOFile's deconstructor closes the file. - openFiles.erase(path); // erase the weak pointer from the list of open files. - }; + // Check if the file has already been opened. + auto search = openFiles.find(m_Name); + if (search != openFiles.end()) + { + m_file = search->second.lock(); // Lock a shared pointer to use. + } + else + { + std::string path = m_Name; + // This code will be called when all references to the shared pointer below have been removed. + auto deleter = [path](File::IOFile* ptr) { + delete ptr; // IOFile's deconstructor closes the file. + openFiles.erase(path); // erase the weak pointer from the list of open files. + }; - // All files are opened read/write. Actual access rights will be controlled per handle by the read/write functions below - m_file = std::shared_ptr(new File::IOFile(m_filepath, "r+b"), deleter); // Use the custom deleter from above. + // All files are opened read/write. Actual access rights will be controlled per handle by the + // read/write functions below + m_file = std::shared_ptr(new File::IOFile(m_filepath, "r+b"), + deleter); // Use the custom deleter from above. - // Store a weak pointer to our newly opened file in the cache. - openFiles[path] = std::weak_ptr(m_file); - } + // Store a weak pointer to our newly opened file in the cache. + openFiles[path] = std::weak_ptr(m_file); + } } IPCCommandResult CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) { - u32 ReturnValue = FS_RESULT_FATAL; - const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC); - const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10); + u32 ReturnValue = FS_RESULT_FATAL; + const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC); + const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10); - if (m_file->IsOpen()) - { - ReturnValue = FS_RESULT_FATAL; + if (m_file->IsOpen()) + { + ReturnValue = FS_RESULT_FATAL; - const s32 fileSize = (s32) m_file->GetSize(); - INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08x)", SeekPosition, Mode, m_Name.c_str(), fileSize); + const s32 fileSize = (s32)m_file->GetSize(); + INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08x)", SeekPosition, + Mode, m_Name.c_str(), fileSize); - switch (Mode) - { - case WII_SEEK_SET: - { - if ((SeekPosition >=0) && (SeekPosition <= fileSize)) - { - m_SeekPos = SeekPosition; - ReturnValue = m_SeekPos; - } - break; - } + switch (Mode) + { + case WII_SEEK_SET: + { + if ((SeekPosition >= 0) && (SeekPosition <= fileSize)) + { + m_SeekPos = SeekPosition; + ReturnValue = m_SeekPos; + } + break; + } - case WII_SEEK_CUR: - { - s32 wantedPos = SeekPosition+m_SeekPos; - if (wantedPos >=0 && wantedPos <= fileSize) - { - m_SeekPos = wantedPos; - ReturnValue = m_SeekPos; - } - break; - } + case WII_SEEK_CUR: + { + s32 wantedPos = SeekPosition + m_SeekPos; + if (wantedPos >= 0 && wantedPos <= fileSize) + { + m_SeekPos = wantedPos; + ReturnValue = m_SeekPos; + } + break; + } - case WII_SEEK_END: - { - s32 wantedPos = SeekPosition+fileSize; - if (wantedPos >=0 && wantedPos <= fileSize) - { - m_SeekPos = wantedPos; - ReturnValue = m_SeekPos; - } - break; - } + case WII_SEEK_END: + { + s32 wantedPos = SeekPosition + fileSize; + if (wantedPos >= 0 && wantedPos <= fileSize) + { + m_SeekPos = wantedPos; + ReturnValue = m_SeekPos; + } + break; + } - default: - { - PanicAlert("CWII_IPC_HLE_Device_FileIO Unsupported seek mode %i", Mode); - ReturnValue = FS_RESULT_FATAL; - break; - } - } - } - else - { - ReturnValue = FS_FILE_NOT_EXIST; - } - Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); + default: + { + PanicAlert("CWII_IPC_HLE_Device_FileIO Unsupported seek mode %i", Mode); + ReturnValue = FS_RESULT_FATAL; + break; + } + } + } + else + { + ReturnValue = FS_FILE_NOT_EXIST; + } + Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); - return GetDefaultReply(); + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress) { - u32 ReturnValue = FS_EACCESS; - const u32 Address = Memory::Read_U32(_CommandAddress + 0xC); // Read to this memory address - const u32 Size = Memory::Read_U32(_CommandAddress + 0x10); + u32 ReturnValue = FS_EACCESS; + const u32 Address = Memory::Read_U32(_CommandAddress + 0xC); // Read to this memory address + const u32 Size = Memory::Read_U32(_CommandAddress + 0x10); + if (m_file->IsOpen()) + { + if (m_Mode == ISFS_OPEN_WRITE) + { + WARN_LOG(WII_IPC_FILEIO, + "FileIO: Attempted to read 0x%x bytes to 0x%08x on a write-only file %s", Size, + Address, m_Name.c_str()); + } + else + { + INFO_LOG(WII_IPC_FILEIO, "FileIO: Read 0x%x bytes to 0x%08x from %s", Size, Address, + m_Name.c_str()); + m_file->Seek(m_SeekPos, SEEK_SET); // File might be opened twice, need to seek before we read + ReturnValue = (u32)fread(Memory::GetPointer(Address), 1, Size, m_file->GetHandle()); + if (ReturnValue != Size && ferror(m_file->GetHandle())) + { + ReturnValue = FS_EACCESS; + } + else + { + m_SeekPos += Size; + } + } + } + else + { + ERROR_LOG(WII_IPC_FILEIO, "FileIO: Failed to read from %s (Addr=0x%08x Size=0x%x) - file could " + "not be opened or does not exist", + m_Name.c_str(), Address, Size); + ReturnValue = FS_FILE_NOT_EXIST; + } - if (m_file->IsOpen()) - { - if (m_Mode == ISFS_OPEN_WRITE) - { - WARN_LOG(WII_IPC_FILEIO, "FileIO: Attempted to read 0x%x bytes to 0x%08x on a write-only file %s", Size, Address, m_Name.c_str()); - } - else - { - INFO_LOG(WII_IPC_FILEIO, "FileIO: Read 0x%x bytes to 0x%08x from %s", Size, Address, m_Name.c_str()); - m_file->Seek(m_SeekPos, SEEK_SET); // File might be opened twice, need to seek before we read - ReturnValue = (u32)fread(Memory::GetPointer(Address), 1, Size, m_file->GetHandle()); - if (ReturnValue != Size && ferror(m_file->GetHandle())) - { - ReturnValue = FS_EACCESS; - } - else - { - m_SeekPos += Size; - } - - } - } - else - { - ERROR_LOG(WII_IPC_FILEIO, "FileIO: Failed to read from %s (Addr=0x%08x Size=0x%x) - file could not be opened or does not exist", m_Name.c_str(), Address, Size); - ReturnValue = FS_FILE_NOT_EXIST; - } - - Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); - return GetDefaultReply(); + Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress) { - u32 ReturnValue = FS_EACCESS; - const u32 Address = Memory::Read_U32(_CommandAddress + 0xC); // Write data from this memory address - const u32 Size = Memory::Read_U32(_CommandAddress + 0x10); + u32 ReturnValue = FS_EACCESS; + const u32 Address = + Memory::Read_U32(_CommandAddress + 0xC); // Write data from this memory address + const u32 Size = Memory::Read_U32(_CommandAddress + 0x10); - if (m_file->IsOpen()) - { - if (m_Mode == ISFS_OPEN_READ) - { - WARN_LOG(WII_IPC_FILEIO, "FileIO: Attempted to write 0x%x bytes from 0x%08x to a read-only file %s", Size, Address, m_Name.c_str()); - } - else - { - INFO_LOG(WII_IPC_FILEIO, "FileIO: Write 0x%04x bytes from 0x%08x to %s", Size, Address, m_Name.c_str()); - m_file->Seek(m_SeekPos, SEEK_SET); // File might be opened twice, need to seek before we write - if (m_file->WriteBytes(Memory::GetPointer(Address), Size)) - { - ReturnValue = Size; - m_SeekPos += Size; - } - } - } - else - { - ERROR_LOG(WII_IPC_FILEIO, "FileIO: Failed to read from %s (Addr=0x%08x Size=0x%x) - file could not be opened or does not exist", m_Name.c_str(), Address, Size); - ReturnValue = FS_FILE_NOT_EXIST; - } + if (m_file->IsOpen()) + { + if (m_Mode == ISFS_OPEN_READ) + { + WARN_LOG(WII_IPC_FILEIO, + "FileIO: Attempted to write 0x%x bytes from 0x%08x to a read-only file %s", Size, + Address, m_Name.c_str()); + } + else + { + INFO_LOG(WII_IPC_FILEIO, "FileIO: Write 0x%04x bytes from 0x%08x to %s", Size, Address, + m_Name.c_str()); + m_file->Seek(m_SeekPos, + SEEK_SET); // File might be opened twice, need to seek before we write + if (m_file->WriteBytes(Memory::GetPointer(Address), Size)) + { + ReturnValue = Size; + m_SeekPos += Size; + } + } + } + else + { + ERROR_LOG(WII_IPC_FILEIO, "FileIO: Failed to read from %s (Addr=0x%08x Size=0x%x) - file could " + "not be opened or does not exist", + m_Name.c_str(), Address, Size); + ReturnValue = FS_FILE_NOT_EXIST; + } - Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); - return GetDefaultReply(); + Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress) { - INFO_LOG(WII_IPC_FILEIO, "FileIO: IOCtl (Device=%s)", m_Name.c_str()); + INFO_LOG(WII_IPC_FILEIO, "FileIO: IOCtl (Device=%s)", m_Name.c_str()); #if defined(_DEBUG) || defined(DEBUGFAST) - DumpCommands(_CommandAddress); + DumpCommands(_CommandAddress); #endif - const u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); - u32 ReturnValue = 0; + const u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); + u32 ReturnValue = 0; - switch (Parameter) - { - case ISFS_IOCTL_GETFILESTATS: - { - if (m_file->IsOpen()) - { - u32 m_FileLength = (u32)m_file->GetSize(); + switch (Parameter) + { + case ISFS_IOCTL_GETFILESTATS: + { + if (m_file->IsOpen()) + { + u32 m_FileLength = (u32)m_file->GetSize(); - const u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - INFO_LOG(WII_IPC_FILEIO, " File: %s, Length: %i, Pos: %i", m_Name.c_str(), m_FileLength, m_SeekPos); + const u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); + INFO_LOG(WII_IPC_FILEIO, " File: %s, Length: %i, Pos: %i", m_Name.c_str(), m_FileLength, + m_SeekPos); - Memory::Write_U32(m_FileLength, BufferOut); - Memory::Write_U32(m_SeekPos, BufferOut+4); - } - else - { - ReturnValue = FS_FILE_NOT_EXIST; - } - } - break; + Memory::Write_U32(m_FileLength, BufferOut); + Memory::Write_U32(m_SeekPos, BufferOut + 4); + } + else + { + ReturnValue = FS_FILE_NOT_EXIST; + } + } + break; - default: - { - PanicAlert("CWII_IPC_HLE_Device_FileIO: Parameter %i", Parameter); - } - break; + default: + { + PanicAlert("CWII_IPC_HLE_Device_FileIO: Parameter %i", Parameter); + } + break; + } - } + Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); - Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); - - return GetDefaultReply(); + return GetDefaultReply(); } - void CWII_IPC_HLE_Device_FileIO::PrepareForState(PointerWrap::Mode mode) { - // Temporally close the file, to prevent any issues with the savestating of /tmp - // it can be opened again with another call to OpenFile() - m_file.reset(); + // Temporally close the file, to prevent any issues with the savestating of /tmp + // it can be opened again with another call to OpenFile() + m_file.reset(); } -void CWII_IPC_HLE_Device_FileIO::DoState(PointerWrap &p) +void CWII_IPC_HLE_Device_FileIO::DoState(PointerWrap& p) { - DoStateShared(p); + DoStateShared(p); - p.Do(m_Mode); - p.Do(m_SeekPos); + p.Do(m_Mode); + p.Do(m_SeekPos); - m_filepath = HLE_IPC_BuildFilename(m_Name); + m_filepath = HLE_IPC_BuildFilename(m_Name); - // The file was closed during state (and might now be pointing at another file) - // Open it again - OpenFile(); + // The file was closed during state (and might now be pointing at another file) + // Open it again + OpenFile(); } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h index 880887a637..29e5b687db 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_FileIO.h @@ -8,7 +8,10 @@ #include "Core/IPC_HLE/WII_IPC_HLE_Device.h" class PointerWrap; -namespace File { class IOFile; } +namespace File +{ +class IOFile; +} std::string HLE_IPC_BuildFilename(std::string _pFilename); void HLE_IPC_CreateVirtualFATFilesystem(); @@ -16,65 +19,65 @@ void HLE_IPC_CreateVirtualFATFilesystem(); class CWII_IPC_HLE_Device_FileIO : public IWII_IPC_HLE_Device { public: - CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, const std::string& _rDeviceName); + CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, const std::string& _rDeviceName); - virtual ~CWII_IPC_HLE_Device_FileIO(); + virtual ~CWII_IPC_HLE_Device_FileIO(); - IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; - IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; - IPCCommandResult Seek(u32 _CommandAddress) override; - IPCCommandResult Read(u32 _CommandAddress) override; - IPCCommandResult Write(u32 _CommandAddress) override; - IPCCommandResult IOCtl(u32 _CommandAddress) override; - void PrepareForState(PointerWrap::Mode mode) override; - void DoState(PointerWrap &p) override; + IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; + IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; + IPCCommandResult Seek(u32 _CommandAddress) override; + IPCCommandResult Read(u32 _CommandAddress) override; + IPCCommandResult Write(u32 _CommandAddress) override; + IPCCommandResult IOCtl(u32 _CommandAddress) override; + void PrepareForState(PointerWrap::Mode mode) override; + void DoState(PointerWrap& p) override; - void OpenFile(); + void OpenFile(); private: - enum - { - ISFS_OPEN_READ = 1, - ISFS_OPEN_WRITE = 2, - ISFS_OPEN_RW = (ISFS_OPEN_READ | ISFS_OPEN_WRITE) - }; + enum + { + ISFS_OPEN_READ = 1, + ISFS_OPEN_WRITE = 2, + ISFS_OPEN_RW = (ISFS_OPEN_READ | ISFS_OPEN_WRITE) + }; - enum - { - WII_SEEK_SET = 0, - WII_SEEK_CUR = 1, - WII_SEEK_END = 2, - }; + enum + { + WII_SEEK_SET = 0, + WII_SEEK_CUR = 1, + WII_SEEK_END = 2, + }; - enum - { - ISFS_FUNCNULL = 0, - ISFS_FUNCGETSTAT = 1, - ISFS_FUNCREADDIR = 2, - ISFS_FUNCGETATTR = 3, - ISFS_FUNCGETUSAGE = 4 - }; + enum + { + ISFS_FUNCNULL = 0, + ISFS_FUNCGETSTAT = 1, + ISFS_FUNCREADDIR = 2, + ISFS_FUNCGETATTR = 3, + ISFS_FUNCGETUSAGE = 4 + }; - enum - { - ISFS_IOCTL_FORMAT = 1, - ISFS_IOCTL_GETSTATS = 2, - ISFS_IOCTL_CREATEDIR = 3, - ISFS_IOCTL_READDIR = 4, - ISFS_IOCTL_SETATTR = 5, - ISFS_IOCTL_GETATTR = 6, - ISFS_IOCTL_DELETE = 7, - ISFS_IOCTL_RENAME = 8, - ISFS_IOCTL_CREATEFILE = 9, - ISFS_IOCTL_SETFILEVERCTRL = 10, - ISFS_IOCTL_GETFILESTATS = 11, - ISFS_IOCTL_GETUSAGE = 12, - ISFS_IOCTL_SHUTDOWN = 13 - }; + enum + { + ISFS_IOCTL_FORMAT = 1, + ISFS_IOCTL_GETSTATS = 2, + ISFS_IOCTL_CREATEDIR = 3, + ISFS_IOCTL_READDIR = 4, + ISFS_IOCTL_SETATTR = 5, + ISFS_IOCTL_GETATTR = 6, + ISFS_IOCTL_DELETE = 7, + ISFS_IOCTL_RENAME = 8, + ISFS_IOCTL_CREATEFILE = 9, + ISFS_IOCTL_SETFILEVERCTRL = 10, + ISFS_IOCTL_GETFILESTATS = 11, + ISFS_IOCTL_GETUSAGE = 12, + ISFS_IOCTL_SHUTDOWN = 13 + }; - u32 m_Mode; - u32 m_SeekPos; + u32 m_Mode; + u32 m_SeekPos; - std::string m_filepath; - std::shared_ptr m_file; + std::string m_filepath; + std::shared_ptr m_file; }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp index da601455c4..fccf14c51f 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp @@ -2,33 +2,31 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - - // ======================================================= // File description // ------------- /* Here we handle /dev/es requests. We have cases for these functions, the exact - DevKitPro/libogc name is in parenthesis: + DevKitPro/libogc name is in parenthesis: - 0x20 GetTitleID (ES_GetTitleID) (Input: none, Output: 8 bytes) - 0x1d GetDataDir (ES_GetDataDir) (Input: 8 bytes, Output: 30 bytes) + 0x20 GetTitleID (ES_GetTitleID) (Input: none, Output: 8 bytes) + 0x1d GetDataDir (ES_GetDataDir) (Input: 8 bytes, Output: 30 bytes) - 0x1b DiGetTicketView (Input: none, Output: 216 bytes) - 0x16 GetConsumption (Input: 8 bytes, Output: 0 bytes, 4 bytes) // there are two output buffers + 0x1b DiGetTicketView (Input: none, Output: 216 bytes) + 0x16 GetConsumption (Input: 8 bytes, Output: 0 bytes, 4 bytes) // there are two output buffers - 0x12 GetNumTicketViews (ES_GetNumTicketViews) (Input: 8 bytes, Output: 4 bytes) - 0x14 GetTMDViewSize (ES_GetTMDViewSize) (Input: ?, Output: ?) // I don't get this anymore, - it used to come after 0x12 + 0x12 GetNumTicketViews (ES_GetNumTicketViews) (Input: 8 bytes, Output: 4 bytes) + 0x14 GetTMDViewSize (ES_GetTMDViewSize) (Input: ?, Output: ?) // I don't get this anymore, + it used to come after 0x12 - but only the first two are correctly supported. For the other four we ignore any potential - input and only write zero to the out buffer. However, most games only use first two, - but some Nintendo developed games use the other ones to: + but only the first two are correctly supported. For the other four we ignore any potential + input and only write zero to the out buffer. However, most games only use first two, + but some Nintendo developed games use the other ones to: - 0x1b: Mario Galaxy, Mario Kart, SSBB - 0x16: Mario Galaxy, Mario Kart, SSBB - 0x12: Mario Kart - 0x14: Mario Kart: But only if we don't return a zeroed out buffer for the 0x12 question, - and instead answer for example 1 will this question appear. + 0x1b: Mario Galaxy, Mario Kart, SSBB + 0x16: Mario Galaxy, Mario Kart, SSBB + 0x12: Mario Kart + 0x14: Mario Kart: But only if we don't return a zeroed out buffer for the 0x12 question, + and instead answer for example 1 will this question appear. */ // ============= @@ -36,24 +34,24 @@ // need to include this before mbedtls/aes.h, // otherwise we may not get __STDC_FORMAT_MACROS #include +#include #include #include -#include #include "Common/ChunkFile.h" #include "Common/CommonPaths.h" #include "Common/FileUtil.h" #include "Common/NandPaths.h" #include "Common/StringUtil.h" -#include "Core/ConfigManager.h" -#include "Core/ec_wii.h" -#include "Core/Movie.h" #include "Core/Boot/Boot_DOL.h" +#include "Core/ConfigManager.h" #include "Core/HW/DVDInterface.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_es.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" #include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h" +#include "Core/Movie.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/ec_wii.h" #include "DiscIO/NANDContentLoader.h" #ifdef _WIN32 @@ -63,1076 +61,1146 @@ std::string CWII_IPC_HLE_Device_es::m_ContentFile; CWII_IPC_HLE_Device_es::CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string& _rDeviceName) - : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) - , m_TitleID(-1) - , m_AccessIdentID(0x6000000) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName), m_TitleID(-1), m_AccessIdentID(0x6000000) { } -static u8 key_sd [0x10] = {0xab, 0x01, 0xb9, 0xd8, 0xe1, 0x62, 0x2b, 0x08, 0xaf, 0xba, 0xd8, 0x4d, 0xbf, 0xc2, 0xa5, 0x5d}; -static u8 key_ecc [0x1e] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; -static u8 key_empty[0x10] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static u8 key_sd[0x10] = {0xab, 0x01, 0xb9, 0xd8, 0xe1, 0x62, 0x2b, 0x08, + 0xaf, 0xba, 0xd8, 0x4d, 0xbf, 0xc2, 0xa5, 0x5d}; +static u8 key_ecc[0x1e] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; +static u8 key_empty[0x10] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // default key table u8* CWII_IPC_HLE_Device_es::keyTable[11] = { - key_ecc, // ECC Private Key - key_empty, // Console ID - key_empty, // NAND AES Key - key_empty, // NAND HMAC - key_empty, // Common Key - key_empty, // PRNG seed - key_sd, // SD Key - key_empty, // Unknown - key_empty, // Unknown - key_empty, // Unknown - key_empty, // Unknown + key_ecc, // ECC Private Key + key_empty, // Console ID + key_empty, // NAND AES Key + key_empty, // NAND HMAC + key_empty, // Common Key + key_empty, // PRNG seed + key_sd, // SD Key + key_empty, // Unknown + key_empty, // Unknown + key_empty, // Unknown + key_empty, // Unknown }; CWII_IPC_HLE_Device_es::~CWII_IPC_HLE_Device_es() -{} +{ +} void CWII_IPC_HLE_Device_es::LoadWAD(const std::string& _rContentFile) { - m_ContentFile = _rContentFile; + m_ContentFile = _rContentFile; } void CWII_IPC_HLE_Device_es::OpenInternal() { - auto& contentLoader = DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile); + auto& contentLoader = DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile); - // check for cd ... - if (contentLoader.IsValid()) - { - m_TitleID = contentLoader.GetTitleID(); + // check for cd ... + if (contentLoader.IsValid()) + { + m_TitleID = contentLoader.GetTitleID(); - m_TitleIDs.clear(); - DiscIO::cUIDsys::AccessInstance().GetTitleIDs(m_TitleIDs); - // uncomment if ES_GetOwnedTitlesCount / ES_GetOwnedTitles is implemented - // m_TitleIDsOwned.clear(); - // DiscIO::cUIDsys::AccessInstance().GetTitleIDs(m_TitleIDsOwned, true); - } - else if (DVDInterface::VolumeIsValid()) - { - // blindly grab the titleID from the disc - it's unencrypted at: - // offset 0x0F8001DC and 0x0F80044C - DVDInterface::GetVolume().GetTitleID(&m_TitleID); - } - else - { - m_TitleID = ((u64)0x00010000 << 32) | 0xF00DBEEF; - } + m_TitleIDs.clear(); + DiscIO::cUIDsys::AccessInstance().GetTitleIDs(m_TitleIDs); + // uncomment if ES_GetOwnedTitlesCount / ES_GetOwnedTitles is implemented + // m_TitleIDsOwned.clear(); + // DiscIO::cUIDsys::AccessInstance().GetTitleIDs(m_TitleIDsOwned, true); + } + else if (DVDInterface::VolumeIsValid()) + { + // blindly grab the titleID from the disc - it's unencrypted at: + // offset 0x0F8001DC and 0x0F80044C + DVDInterface::GetVolume().GetTitleID(&m_TitleID); + } + else + { + m_TitleID = ((u64)0x00010000 << 32) | 0xF00DBEEF; + } - INFO_LOG(WII_IPC_ES, "Set default title to %08x/%08x", (u32)(m_TitleID>>32), (u32)m_TitleID); + INFO_LOG(WII_IPC_ES, "Set default title to %08x/%08x", (u32)(m_TitleID >> 32), (u32)m_TitleID); } void CWII_IPC_HLE_Device_es::DoState(PointerWrap& p) { - IWII_IPC_HLE_Device::DoState(p); - p.Do(m_ContentFile); - OpenInternal(); - p.Do(m_AccessIdentID); - p.Do(m_TitleIDs); + IWII_IPC_HLE_Device::DoState(p); + p.Do(m_ContentFile); + OpenInternal(); + p.Do(m_AccessIdentID); + p.Do(m_TitleIDs); - u32 Count = (u32)(m_ContentAccessMap.size()); - p.Do(Count); + u32 Count = (u32)(m_ContentAccessMap.size()); + p.Do(Count); - u32 CFD = 0; - u32 Position = 0; - u64 TitleID = 0; - u16 Index = 0; - if (p.GetMode() == PointerWrap::MODE_READ) - { - for (u32 i = 0; i < Count; i++) - { - p.Do(CFD); - p.Do(Position); - p.Do(TitleID); - p.Do(Index); - CFD = OpenTitleContent(CFD, TitleID, Index); - if (CFD != 0xffffffff) - { - m_ContentAccessMap[CFD].m_Position = Position; - } - } - } - else - { - for (auto& pair : m_ContentAccessMap) - { - CFD = pair.first; - SContentAccess& Access = pair.second; - Position = Access.m_Position; - TitleID = Access.m_TitleID; - Index = Access.m_Index; - p.Do(CFD); - p.Do(Position); - p.Do(TitleID); - p.Do(Index); - } - } + u32 CFD = 0; + u32 Position = 0; + u64 TitleID = 0; + u16 Index = 0; + if (p.GetMode() == PointerWrap::MODE_READ) + { + for (u32 i = 0; i < Count; i++) + { + p.Do(CFD); + p.Do(Position); + p.Do(TitleID); + p.Do(Index); + CFD = OpenTitleContent(CFD, TitleID, Index); + if (CFD != 0xffffffff) + { + m_ContentAccessMap[CFD].m_Position = Position; + } + } + } + else + { + for (auto& pair : m_ContentAccessMap) + { + CFD = pair.first; + SContentAccess& Access = pair.second; + Position = Access.m_Position; + TitleID = Access.m_TitleID; + Index = Access.m_Index; + p.Do(CFD); + p.Do(Position); + p.Do(TitleID); + p.Do(Index); + } + } } IPCCommandResult CWII_IPC_HLE_Device_es::Open(u32 _CommandAddress, u32 _Mode) { - OpenInternal(); + OpenInternal(); - Memory::Write_U32(GetDeviceID(), _CommandAddress+4); - if (m_Active) - INFO_LOG(WII_IPC_ES, "Device was re-opened."); - m_Active = true; - return GetDefaultReply(); + Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); + if (m_Active) + INFO_LOG(WII_IPC_ES, "Device was re-opened."); + m_Active = true; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_es::Close(u32 _CommandAddress, bool _bForce) { - m_ContentAccessMap.clear(); - m_TitleIDs.clear(); - m_TitleID = -1; - m_AccessIdentID = 0x6000000; + m_ContentAccessMap.clear(); + m_TitleIDs.clear(); + m_TitleID = -1; + m_AccessIdentID = 0x6000000; - INFO_LOG(WII_IPC_ES, "ES: Close"); - if (!_bForce) - Memory::Write_U32(0, _CommandAddress + 4); - m_Active = false; - // clear the NAND content cache to make sure nothing remains open. - DiscIO::CNANDContentManager::Access().ClearCache(); - return GetDefaultReply(); + INFO_LOG(WII_IPC_ES, "ES: Close"); + if (!_bForce) + Memory::Write_U32(0, _CommandAddress + 4); + m_Active = false; + // clear the NAND content cache to make sure nothing remains open. + DiscIO::CNANDContentManager::Access().ClearCache(); + return GetDefaultReply(); } u32 CWII_IPC_HLE_Device_es::OpenTitleContent(u32 CFD, u64 TitleID, u16 Index) { - const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); + const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); - if (!Loader.IsValid()) - { - WARN_LOG(WII_IPC_ES, "ES: loader not valid for %" PRIx64, TitleID); - return 0xffffffff; - } + if (!Loader.IsValid()) + { + WARN_LOG(WII_IPC_ES, "ES: loader not valid for %" PRIx64, TitleID); + return 0xffffffff; + } - const DiscIO::SNANDContent* pContent = Loader.GetContentByIndex(Index); + const DiscIO::SNANDContent* pContent = Loader.GetContentByIndex(Index); - if (pContent == nullptr) - { - return 0xffffffff; //TODO: what is the correct error value here? - } + if (pContent == nullptr) + { + return 0xffffffff; // TODO: what is the correct error value here? + } - SContentAccess Access; - Access.m_Position = 0; - Access.m_Index = pContent->m_Index; - Access.m_Size = pContent->m_Size; - Access.m_TitleID = TitleID; + SContentAccess Access; + Access.m_Position = 0; + Access.m_Index = pContent->m_Index; + Access.m_Size = pContent->m_Size; + Access.m_TitleID = TitleID; - pContent->m_Data->Open(); + pContent->m_Data->Open(); - m_ContentAccessMap[CFD] = Access; - return CFD; + m_ContentAccessMap[CFD] = Access; + return CFD; } IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) { - SIOCtlVBuffer Buffer(_CommandAddress); - - DEBUG_LOG(WII_IPC_ES, "%s (0x%x)", GetDeviceName().c_str(), Buffer.Parameter); - - // Prepare the out buffer(s) with zeroes as a safety precaution - // to avoid returning bad values - // XXX: is this still necessary? - for (u32 i = 0; i < Buffer.NumberPayloadBuffer; i++) - { - u32 j; - for (j = 0; j < Buffer.NumberInBuffer; j++) - { - if (Buffer.InBuffer[j].m_Address == Buffer.PayloadBuffer[i].m_Address) - { - // The out buffer is the same as one of the in buffers. Don't zero it. - break; - } - } - if (j == Buffer.NumberInBuffer) - { - Memory::Memset(Buffer.PayloadBuffer[i].m_Address, 0, - Buffer.PayloadBuffer[i].m_Size); - } - } - - switch (Buffer.Parameter) - { - case IOCTL_ES_GETDEVICEID: - { - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETDEVICEID no out buffer"); - - EcWii &ec = EcWii::GetInstance(); - INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETDEVICEID %08X", ec.getNgId()); - Memory::Write_U32(ec.getNgId(), Buffer.PayloadBuffer[0].m_Address); - Memory::Write_U32(0, _CommandAddress + 0x4); - return GetDefaultReply(); - } - break; - - case IOCTL_ES_GETTITLECONTENTSCNT: - { - _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); - _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1); - - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - - const DiscIO::CNANDContentLoader& rNANDContent = AccessContentDevice(TitleID); - u16 NumberOfPrivateContent = 0; - if (rNANDContent.IsValid()) // Not sure if dolphin will ever fail this check - { - NumberOfPrivateContent = rNANDContent.GetNumEntries(); - - if ((u32)(TitleID>>32) == 0x00010000) - Memory::Write_U32(0, Buffer.PayloadBuffer[0].m_Address); - else - Memory::Write_U32(NumberOfPrivateContent, Buffer.PayloadBuffer[0].m_Address); - - Memory::Write_U32(0, _CommandAddress + 0x4); - } - else - Memory::Write_U32((u32)rNANDContent.GetContentSize(), _CommandAddress + 0x4); - - INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTSCNT: TitleID: %08x/%08x content count %i", - (u32)(TitleID>>32), (u32)TitleID, rNANDContent.IsValid() ? NumberOfPrivateContent : (u32)rNANDContent.GetContentSize()); - - return GetDefaultReply(); - } - break; - - case IOCTL_ES_GETTITLECONTENTS: - { - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2, "IOCTL_ES_GETTITLECONTENTS bad in buffer"); - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTITLECONTENTS bad out buffer"); - - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - - const DiscIO::CNANDContentLoader& rNANDContent = AccessContentDevice(TitleID); - if (rNANDContent.IsValid()) // Not sure if dolphin will ever fail this check - { - for (u16 i = 0; i < rNANDContent.GetNumEntries(); i++) - { - Memory::Write_U32(rNANDContent.GetContentByIndex(i)->m_ContentID, Buffer.PayloadBuffer[0].m_Address + i*4); - INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTS: Index %d: %08x", i, rNANDContent.GetContentByIndex(i)->m_ContentID); - } - Memory::Write_U32(0, _CommandAddress + 0x4); - } - else - { - Memory::Write_U32((u32)rNANDContent.GetContentSize(), _CommandAddress + 0x4); - INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTS: Unable to open content %zu", - rNANDContent.GetContentSize()); - } - - return GetDefaultReply(); - } - break; - - - case IOCTL_ES_OPENTITLECONTENT: - { - _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 3); - _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0); - - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - u32 Index = Memory::Read_U32(Buffer.InBuffer[2].m_Address); - - u32 CFD = OpenTitleContent(m_AccessIdentID++, TitleID, Index); - Memory::Write_U32(CFD, _CommandAddress + 0x4); - - INFO_LOG(WII_IPC_ES, "IOCTL_ES_OPENTITLECONTENT: TitleID: %08x/%08x Index %i -> got CFD %x", (u32)(TitleID>>32), (u32)TitleID, Index, CFD); - - return GetDefaultReply(); - } - break; - - case IOCTL_ES_OPENCONTENT: - { - _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); - _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0); - u32 Index = Memory::Read_U32(Buffer.InBuffer[0].m_Address); - - u32 CFD = OpenTitleContent(m_AccessIdentID++, m_TitleID, Index); - Memory::Write_U32(CFD, _CommandAddress + 0x4); - INFO_LOG(WII_IPC_ES, "IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD); - - return GetDefaultReply(); - } - break; - - case IOCTL_ES_READCONTENT: - { - _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); - _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1); - - u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address); - u32 Size = Buffer.PayloadBuffer[0].m_Size; - u32 Addr = Buffer.PayloadBuffer[0].m_Address; - - auto itr = m_ContentAccessMap.find(CFD); - if (itr == m_ContentAccessMap.end()) - { - Memory::Write_U32(-1, _CommandAddress + 0x4); - return GetDefaultReply(); - } - SContentAccess& rContent = itr->second; - - u8* pDest = Memory::GetPointer(Addr); - - if (rContent.m_Position + Size > rContent.m_Size) - { - Size = rContent.m_Size - rContent.m_Position; - } - - if (Size > 0) - { - if (pDest) - { - const DiscIO::CNANDContentLoader& ContentLoader = AccessContentDevice(rContent.m_TitleID); - // ContentLoader should never be invalid; rContent has been created by it. - if (ContentLoader.IsValid()) - { - const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(rContent.m_Index); - if (!pContent->m_Data->GetRange(rContent.m_Position, Size, pDest)) - ERROR_LOG(WII_IPC_ES, "ES: failed to read %u bytes from %u!", Size, rContent.m_Position); - } - - rContent.m_Position += Size; - } - else - { - PanicAlert("IOCTL_ES_READCONTENT - bad destination"); - } - } - - INFO_LOG(WII_IPC_ES, "IOCTL_ES_READCONTENT: CFD %x, Address 0x%x, Size %i -> stream pos %i (Index %i)", CFD, Addr, Size, rContent.m_Position, rContent.m_Index); - - Memory::Write_U32(Size, _CommandAddress + 0x4); - return GetDefaultReply(); - } - break; - - case IOCTL_ES_CLOSECONTENT: - { - _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); - _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0); - - u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address); - - INFO_LOG(WII_IPC_ES, "IOCTL_ES_CLOSECONTENT: CFD %x", CFD); - - auto itr = m_ContentAccessMap.find(CFD); - if (itr == m_ContentAccessMap.end()) - { - Memory::Write_U32(-1, _CommandAddress + 0x4); - return GetDefaultReply(); - } - - const DiscIO::CNANDContentLoader& ContentLoader = AccessContentDevice(itr->second.m_TitleID); - // ContentLoader should never be invalid; we shouldn't be here if ES_OPENCONTENT failed before. - if (ContentLoader.IsValid()) - { - const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(itr->second.m_Index); - pContent->m_Data->Close(); - } - - m_ContentAccessMap.erase(itr); - - Memory::Write_U32(0, _CommandAddress + 0x4); - return GetDefaultReply(); - } - break; - - case IOCTL_ES_SEEKCONTENT: - { - _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 3); - _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0); - - u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address); - u32 Addr = Memory::Read_U32(Buffer.InBuffer[1].m_Address); - u32 Mode = Memory::Read_U32(Buffer.InBuffer[2].m_Address); - - auto itr = m_ContentAccessMap.find(CFD); - if (itr == m_ContentAccessMap.end()) - { - Memory::Write_U32(-1, _CommandAddress + 0x4); - return GetDefaultReply(); - } - SContentAccess& rContent = itr->second; - - switch (Mode) - { - case 0: // SET - rContent.m_Position = Addr; - break; - - case 1: // CUR - rContent.m_Position += Addr; - break; - - case 2: // END - rContent.m_Position = rContent.m_Size + Addr; - break; - } - - INFO_LOG(WII_IPC_ES, "IOCTL_ES_SEEKCONTENT: CFD %x, Address 0x%x, Mode %i -> Pos %i", CFD, Addr, Mode, rContent.m_Position); - - Memory::Write_U32(rContent.m_Position, _CommandAddress + 0x4); - return GetDefaultReply(); - } - break; - - case IOCTL_ES_GETTITLEDIR: - { - _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); - _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1); - - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - - char* Path = (char*)Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address); - sprintf(Path, "/title/%08x/%08x/data", (u32)(TitleID >> 32), (u32)TitleID); - - INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLEDIR: %s", Path); - } - break; - - case IOCTL_ES_GETTITLEID: - { - _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 0); - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTITLEID no out buffer"); - - Memory::Write_U64(m_TitleID, Buffer.PayloadBuffer[0].m_Address); - INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLEID: %08x/%08x", (u32)(m_TitleID>>32), (u32)m_TitleID); - } - break; - - case IOCTL_ES_SETUID: - { - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_SETUID no in buffer"); - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0, "IOCTL_ES_SETUID has a payload, it shouldn't"); - // TODO: fs permissions based on this - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - INFO_LOG(WII_IPC_ES, "IOCTL_ES_SETUID titleID: %08x/%08x", (u32)(TitleID>>32), (u32)TitleID); - } - break; - - case IOCTL_ES_GETTITLECNT: - { - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 0, "IOCTL_ES_GETTITLECNT has an in buffer"); - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTITLECNT has no out buffer"); - _dbg_assert_msg_(WII_IPC_ES, Buffer.PayloadBuffer[0].m_Size == 4, "IOCTL_ES_GETTITLECNT payload[0].size != 4"); - - Memory::Write_U32((u32)m_TitleIDs.size(), Buffer.PayloadBuffer[0].m_Address); - - INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECNT: Number of Titles %zu", m_TitleIDs.size()); - - Memory::Write_U32(0, _CommandAddress + 0x4); - - return GetDefaultReply(); - } - break; - - - case IOCTL_ES_GETTITLES: - { - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETTITLES has an in buffer"); - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTITLES has no out buffer"); - - u32 MaxCount = Memory::Read_U32(Buffer.InBuffer[0].m_Address); - u32 Count = 0; - for (int i = 0; i < (int)m_TitleIDs.size(); i++) - { - Memory::Write_U64(m_TitleIDs[i], Buffer.PayloadBuffer[0].m_Address + i*8); - INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLES: %08x/%08x", (u32)(m_TitleIDs[i] >> 32), (u32)m_TitleIDs[i]); - Count++; - if (Count >= MaxCount) - break; - } - - INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLES: Number of titles returned %i", Count); - Memory::Write_U32(0, _CommandAddress + 0x4); - return GetDefaultReply(); - } - break; - - - case IOCTL_ES_GETVIEWCNT: - { - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETVIEWCNT no in buffer"); - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETVIEWCNT no out buffer"); - - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - - u32 retVal = 0; - const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); - u32 ViewCount = static_cast(Loader.GetTicket().size()) / DiscIO::CNANDContentLoader::TICKET_SIZE; - - if (!ViewCount) - { - std::string TicketFilename = Common::GetTicketFileName(TitleID, Common::FROM_SESSION_ROOT); - if (File::Exists(TicketFilename)) - { - u32 FileSize = (u32)File::GetSize(TicketFilename); - _dbg_assert_msg_(WII_IPC_ES, (FileSize % DiscIO::CNANDContentLoader::TICKET_SIZE) == 0, "IOCTL_ES_GETVIEWCNT ticket file size seems to be wrong"); - - ViewCount = FileSize / DiscIO::CNANDContentLoader::TICKET_SIZE; - _dbg_assert_msg_(WII_IPC_ES, (ViewCount>0) && (ViewCount<=4), "IOCTL_ES_GETVIEWCNT ticket count seems to be wrong"); - } - else if (TitleID >> 32 == 0x00000001) - { - // Fake a ticket view to make IOS reload work. - ViewCount = 1; - } - else - { - ViewCount = 0; - if (TitleID == TITLEID_SYSMENU) - { - PanicAlertT("There must be a ticket for 00000001/00000002. Your NAND dump is probably incomplete."); - } - //retVal = ES_NO_TICKET_INSTALLED; - } - } - - INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETVIEWCNT for titleID: %08x/%08x (View Count = %i)", (u32)(TitleID>>32), (u32)TitleID, ViewCount); - - Memory::Write_U32(ViewCount, Buffer.PayloadBuffer[0].m_Address); - Memory::Write_U32(retVal, _CommandAddress + 0x4); - return GetDefaultReply(); - } - break; - - case IOCTL_ES_GETVIEWS: - { - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2, "IOCTL_ES_GETVIEWS no in buffer"); - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETVIEWS no out buffer"); - - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - u32 maxViews = Memory::Read_U32(Buffer.InBuffer[1].m_Address); - u32 retVal = 0; - - const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); - - const std::vector& ticket = Loader.GetTicket(); - - if (ticket.empty()) - { - std::string TicketFilename = Common::GetTicketFileName(TitleID, Common::FROM_SESSION_ROOT); - if (File::Exists(TicketFilename)) - { - File::IOFile pFile(TicketFilename, "rb"); - if (pFile) - { - u8 FileTicket[DiscIO::CNANDContentLoader::TICKET_SIZE]; - for (unsigned int View = 0; View != maxViews && pFile.ReadBytes(FileTicket, DiscIO::CNANDContentLoader::TICKET_SIZE); ++View) - { - Memory::Write_U32(View, Buffer.PayloadBuffer[0].m_Address + View * 0xD8); - Memory::CopyToEmu(Buffer.PayloadBuffer[0].m_Address + 4 + View * 0xD8, FileTicket+0x1D0, 212); - } - } - } - else if (TitleID >> 32 == 0x00000001) - { - // For IOS titles, the ticket view isn't normally parsed by either the - // SDK or libogc, just passed to LaunchTitle, so this - // shouldn't matter at all. Just fill out some fields just - // to be on the safe side. - u32 Address = Buffer.PayloadBuffer[0].m_Address; - Memory::Memset(Address, 0, 0xD8); - Memory::Write_U64(TitleID, Address + 4 + (0x1dc - 0x1d0)); // title ID - Memory::Write_U16(0xffff, Address + 4 + (0x1e4 - 0x1d0)); // unnnown - Memory::Write_U32(0xff00, Address + 4 + (0x1ec - 0x1d0)); // access mask - Memory::Memset(Address + 4 + (0x222 - 0x1d0), 0xff, 0x20); // content permissions - } - else - { - //retVal = ES_NO_TICKET_INSTALLED; - PanicAlertT("IOCTL_ES_GETVIEWS: Tried to get data from an unknown ticket: %08x/%08x", (u32)(TitleID >> 32), (u32)TitleID); - } - } - else - { - u32 view_count = static_cast(Loader.GetTicket().size()) / DiscIO::CNANDContentLoader::TICKET_SIZE; - for (unsigned int view = 0; view != maxViews && view < view_count; ++view) - { - Memory::Write_U32(view, Buffer.PayloadBuffer[0].m_Address + view * 0xD8); - Memory::CopyToEmu(Buffer.PayloadBuffer[0].m_Address + 4 + view * 0xD8, - &ticket[0x1D0 + (view * DiscIO::CNANDContentLoader::TICKET_SIZE)], 212); - } - } - - INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETVIEWS for titleID: %08x/%08x (MaxViews = %i)", (u32)(TitleID >> 32), (u32)TitleID, maxViews); - - Memory::Write_U32(retVal, _CommandAddress + 0x4); - return GetDefaultReply(); - } - break; - - case IOCTL_ES_GETTMDVIEWCNT: - { - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETTMDVIEWCNT no in buffer"); - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTMDVIEWCNT no out buffer"); - - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - - const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); - - u32 TMDViewCnt = 0; - if (Loader.IsValid()) - { - TMDViewCnt += DiscIO::CNANDContentLoader::TMD_VIEW_SIZE; - TMDViewCnt += 2; // title version - TMDViewCnt += 2; // num entries - TMDViewCnt += (u32)Loader.GetContentSize() * (4+2+2+8); // content id, index, type, size - } - Memory::Write_U32(TMDViewCnt, Buffer.PayloadBuffer[0].m_Address); - - Memory::Write_U32(0, _CommandAddress + 0x4); - - INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x (view size %i)", (u32)(TitleID >> 32), (u32)TitleID, TMDViewCnt); - return GetDefaultReply(); - } - break; - - case IOCTL_ES_GETTMDVIEWS: - { - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2, "IOCTL_ES_GETTMDVIEWCNT no in buffer"); - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTMDVIEWCNT no out buffer"); - - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - u32 MaxCount = Memory::Read_U32(Buffer.InBuffer[1].m_Address); - - const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); - - INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x buffer size: %i", (u32)(TitleID >> 32), (u32)TitleID, MaxCount); - - if (Loader.IsValid()) - { - u32 Address = Buffer.PayloadBuffer[0].m_Address; - - Memory::CopyToEmu(Address, Loader.GetTMDView(), DiscIO::CNANDContentLoader::TMD_VIEW_SIZE); - Address += DiscIO::CNANDContentLoader::TMD_VIEW_SIZE; - - Memory::Write_U16(Loader.GetTitleVersion(), Address); Address += 2; - Memory::Write_U16(Loader.GetNumEntries(), Address); Address += 2; - - const std::vector& rContent = Loader.GetContent(); - for (size_t i=0; i> 32), (u32)TitleID, MaxCount); - return GetDefaultReply(); - } - break; - - case IOCTL_ES_GETCONSUMPTION: // This is at least what crediar's ES module does - Memory::Write_U32(0, Buffer.PayloadBuffer[1].m_Address); - Memory::Write_U32(0, _CommandAddress + 0x4); - WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETCONSUMPTION:%d", Memory::Read_U32(_CommandAddress+4)); - return GetDefaultReply(); - - case IOCTL_ES_DELETETICKET: - { - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - INFO_LOG(WII_IPC_ES, "IOCTL_ES_DELETETICKET: title: %08x/%08x", (u32)(TitleID >> 32), (u32)TitleID); - if (File::Delete(Common::GetTicketFileName(TitleID, Common::FROM_SESSION_ROOT))) - { - Memory::Write_U32(0, _CommandAddress + 0x4); - } - else - { - // Presumably return -1017 when delete fails - Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT, _CommandAddress + 0x4); - } - } - break; - case IOCTL_ES_DELETETITLECONTENT: - { - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - INFO_LOG(WII_IPC_ES, "IOCTL_ES_DELETETITLECONTENT: title: %08x/%08x", (u32)(TitleID >> 32), (u32)TitleID); - if (DiscIO::CNANDContentManager::Access().RemoveTitle(TitleID, Common::FROM_SESSION_ROOT)) - { - Memory::Write_U32(0, _CommandAddress + 0x4); - } - else - { - // Presumably return -1017 when title not installed TODO verify - Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT, _CommandAddress + 0x4); - } - - } - break; - case IOCTL_ES_GETSTOREDTMDSIZE: - { - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETSTOREDTMDSIZE no in buffer"); - // _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_ES_GETSTOREDTMDSIZE no out buffer"); - - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); - - _dbg_assert_(WII_IPC_ES, Loader.IsValid()); - u32 TMDCnt = 0; - if (Loader.IsValid()) - { - TMDCnt += DiscIO::CNANDContentLoader::TMD_HEADER_SIZE; - TMDCnt += (u32)Loader.GetContentSize() * DiscIO::CNANDContentLoader::CONTENT_HEADER_SIZE; - } - if (Buffer.NumberPayloadBuffer) - Memory::Write_U32(TMDCnt, Buffer.PayloadBuffer[0].m_Address); - - Memory::Write_U32(0, _CommandAddress + 0x4); - - INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETSTOREDTMDSIZE: title: %08x/%08x (view size %i)", (u32)(TitleID >> 32), (u32)TitleID, TMDCnt); - return GetDefaultReply(); - } - break; - case IOCTL_ES_GETSTOREDTMD: - { - _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer > 0, "IOCTL_ES_GETSTOREDTMD no in buffer"); - // requires 1 inbuffer and no outbuffer, presumably outbuffer required when second inbuffer is used for maxcount (allocated mem?) - // called with 1 inbuffer after deleting a titleid - //_dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETSTOREDTMD no out buffer"); - - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - u32 MaxCount = 0; - if (Buffer.NumberInBuffer > 1) - { - // TODO: actually use this param in when writing to the outbuffer :/ - MaxCount = Memory::Read_U32(Buffer.InBuffer[1].m_Address); - } - const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); - - - INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x buffer size: %i", (u32)(TitleID >> 32), (u32)TitleID, MaxCount); - - if (Loader.IsValid() && Buffer.NumberPayloadBuffer) - { - u32 Address = Buffer.PayloadBuffer[0].m_Address; - - Memory::CopyToEmu(Address, Loader.GetTMDHeader(), DiscIO::CNANDContentLoader::TMD_HEADER_SIZE); - Address += DiscIO::CNANDContentLoader::TMD_HEADER_SIZE; - - const std::vector& rContent = Loader.GetContent(); - for (size_t i=0; i> 32), (u32)TitleID, MaxCount); - return GetDefaultReply(); - } - break; - - case IOCTL_ES_ENCRYPT: - { - u32 keyIndex = Memory::Read_U32(Buffer.InBuffer[0].m_Address); - u8* IV = Memory::GetPointer(Buffer.InBuffer[1].m_Address); - u8* source = Memory::GetPointer(Buffer.InBuffer[2].m_Address); - u32 size = Buffer.InBuffer[2].m_Size; - u8* newIV = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address); - u8* destination = Memory::GetPointer(Buffer.PayloadBuffer[1].m_Address); - - mbedtls_aes_context AES_ctx; - mbedtls_aes_setkey_enc(&AES_ctx, keyTable[keyIndex], 128); - memcpy(newIV, IV, 16); - mbedtls_aes_crypt_cbc(&AES_ctx, MBEDTLS_AES_ENCRYPT, size, newIV, source, destination); - - _dbg_assert_msg_(WII_IPC_ES, keyIndex == 6, "IOCTL_ES_ENCRYPT: Key type is not SD, data will be crap"); - } - break; - - case IOCTL_ES_DECRYPT: - { - u32 keyIndex = Memory::Read_U32(Buffer.InBuffer[0].m_Address); - u8* IV = Memory::GetPointer(Buffer.InBuffer[1].m_Address); - u8* source = Memory::GetPointer(Buffer.InBuffer[2].m_Address); - u32 size = Buffer.InBuffer[2].m_Size; - u8* newIV = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address); - u8* destination = Memory::GetPointer(Buffer.PayloadBuffer[1].m_Address); - - mbedtls_aes_context AES_ctx; - mbedtls_aes_setkey_dec(&AES_ctx, keyTable[keyIndex], 128); - memcpy(newIV, IV, 16); - mbedtls_aes_crypt_cbc(&AES_ctx, MBEDTLS_AES_DECRYPT, size, newIV, source, destination); - - _dbg_assert_msg_(WII_IPC_ES, keyIndex == 6, "IOCTL_ES_DECRYPT: Key type is not SD, data will be crap"); - } - break; - - - case IOCTL_ES_LAUNCH: - { - _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 2); - bool bSuccess = false; - u16 IOSv = 0xffff; - - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - u32 view = Memory::Read_U32(Buffer.InBuffer[1].m_Address); - u64 ticketid = Memory::Read_U64(Buffer.InBuffer[1].m_Address+4); - u32 devicetype = Memory::Read_U32(Buffer.InBuffer[1].m_Address+12); - u64 titleid = Memory::Read_U64(Buffer.InBuffer[1].m_Address+16); - u16 access = Memory::Read_U16(Buffer.InBuffer[1].m_Address+24); - - // ES_LAUNCH should probably reset thw whole state, which at least means closing all open files. - // leaving them open through ES_LAUNCH may cause hangs and other funky behavior - // (supposedly when trying to re-open those files). - DiscIO::CNANDContentManager::Access().ClearCache(); - - std::string tContentFile; - if ((u32)(TitleID>>32) != 0x00000001 || TitleID == TITLEID_SYSMENU) - { - const DiscIO::CNANDContentLoader& ContentLoader = AccessContentDevice(TitleID); - if (ContentLoader.IsValid()) - { - u32 bootInd = ContentLoader.GetBootIndex(); - const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(bootInd); - if (pContent) - { - tContentFile = Common::GetTitleContentPath(TitleID, Common::FROM_SESSION_ROOT); - std::unique_ptr pDolLoader = std::make_unique(pContent->m_Data->Get()); - - if (pDolLoader->IsValid()) - { - pDolLoader->Load(); // TODO: Check why sysmenu does not load the DOL correctly - PC = pDolLoader->GetEntryPoint(); - bSuccess = true; - } - else - { - PanicAlertT("IOCTL_ES_LAUNCH: The DOL file is invalid!"); - bSuccess = false; - } - - IOSv = ContentLoader.GetIosVersion(); - } - } - } - else // IOS, MIOS, BC etc - { - //TODO: fixme - // The following is obviously a hack - // Lie to mem about loading a different IOS - // someone with an affected game should test - IOSv = TitleID & 0xffff; - bSuccess = true; - } - if (!bSuccess) - { - PanicAlertT("IOCTL_ES_LAUNCH: Game tried to reload a title that is not available in your NAND dump\n" - "TitleID %016" PRIx64".\n Dolphin will likely hang now.", TitleID); - } - else - { - CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer(); - size_t size = s_Usb->m_WiiMotes.size(); - bool* wiiMoteConnected = new bool[size]; - for (unsigned int i = 0; i < size; i++) - wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected(); - - WII_IPC_HLE_Interface::Reset(true); - WII_IPC_HLE_Interface::Init(); - s_Usb = GetUsbPointer(); - for (unsigned int i = 0; i < s_Usb->m_WiiMotes.size(); i++) - { - if (wiiMoteConnected[i]) - { - s_Usb->m_WiiMotes[i].Activate(false); - s_Usb->m_WiiMotes[i].Activate(true); - } - else - { - s_Usb->m_WiiMotes[i].Activate(false); - } - } - - delete[] wiiMoteConnected; - WII_IPC_HLE_Interface::SetDefaultContentFile(tContentFile); - } - // Pass the "#002 check" - // Apploader should write the IOS version and revision to 0x3140, and compare it - // to 0x3188 to pass the check, but we don't do it, and i don't know where to read the IOS rev... - // Currently we just write 0xFFFF for the revision, copy manually and it works fine :p - // TODO : figure it correctly : where should we read the IOS rev that the wad "needs" ? - Memory::Write_U16(IOSv, 0x00003140); - Memory::Write_U16(0xFFFF, 0x00003142); - Memory::Write_U32(Memory::Read_U32(0x00003140), 0x00003188); - - //TODO: provide correct return code when bSuccess= false - Memory::Write_U32(0, _CommandAddress + 0x4); - - ERROR_LOG(WII_IPC_ES, "IOCTL_ES_LAUNCH %016" PRIx64 " %08x %016" PRIx64 " %08x %016" PRIx64 " %04x", TitleID,view,ticketid,devicetype,titleid,access); - // IOCTL_ES_LAUNCH 0001000248414341 00000001 0001c0fef3df2cfa 00000000 0001000248414341 ffff - - // This is necessary because Reset(true) above deleted this object. Ew. - - // The original hardware overwrites the command type with the async reply type. - Memory::Write_U32(IPC_REP_ASYNC, _CommandAddress); - // IOS also seems to write back the command that was responded to in the FD field. - Memory::Write_U32(IPC_CMD_IOCTLV, _CommandAddress + 8); - - // Generate a "reply" to the IPC command. ES_LAUNCH is unique because it - // involves restarting IOS; IOS generates two acknowledgements in a row. - WII_IPC_HLE_Interface::EnqueueCommandAcknowledgement(_CommandAddress, 0); - return GetNoReply(); - } - break; - - case IOCTL_ES_CHECKKOREAREGION: //note by DacoTaco : name is unknown, i just tried to name it SOMETHING - //IOS70 has this to let system menu 4.2 check if the console is region changed. it returns -1017 - //if the IOS didn't find the Korean keys and 0 if it does. 0 leads to a error 003 - WARN_LOG(WII_IPC_ES,"IOCTL_ES_CHECKKOREAREGION: Title checked for Korean keys."); - Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT , _CommandAddress + 0x4); - return GetDefaultReply(); - - case IOCTL_ES_GETDEVICECERT: // (Input: none, Output: 384 bytes) - { - WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETDEVICECERT"); - _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1); - u8* destination = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address); - - EcWii &ec = EcWii::GetInstance(); - get_ng_cert(destination, ec.getNgId(), ec.getNgKeyId(), ec.getNgPriv(), ec.getNgSig()); - } - break; - - case IOCTL_ES_SIGN: - { - WARN_LOG(WII_IPC_ES, "IOCTL_ES_SIGN"); - u8 *ap_cert_out = Memory::GetPointer(Buffer.PayloadBuffer[1].m_Address); - u8 *data = Memory::GetPointer(Buffer.InBuffer[0].m_Address); - u32 data_size = Buffer.InBuffer[0].m_Size; - u8 *sig_out = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address); - - EcWii &ec = EcWii::GetInstance(); - get_ap_sig_and_cert(sig_out, ap_cert_out, m_TitleID, data, data_size, ec.getNgPriv(), ec.getNgId()); - } - break; - - case IOCTL_ES_GETBOOT2VERSION: - { - WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETBOOT2VERSION"); - - Memory::Write_U32(4, Buffer.PayloadBuffer[0].m_Address); // as of 26/02/2012, this was latest bootmii version - } - break; - - // =============================================================================================== - // unsupported functions - // =============================================================================================== - case IOCTL_ES_DIGETTICKETVIEW: // (Input: none, Output: 216 bytes) bug crediar :D - WARN_LOG(WII_IPC_ES, "IOCTL_ES_DIGETTICKETVIEW: this looks really wrong..."); - break; - - case IOCTL_ES_GETOWNEDTITLECNT: - WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETOWNEDTITLECNT"); - Memory::Write_U32(0, Buffer.PayloadBuffer[0].m_Address); - break; - - default: - WARN_LOG(WII_IPC_ES, "CWII_IPC_HLE_Device_es: 0x%x", Buffer.Parameter); - DumpCommands(_CommandAddress, 8, LogTypes::WII_IPC_ES); - INFO_LOG(WII_IPC_ES, "command.Parameter: 0x%08x", Buffer.Parameter); - break; - } - - // Write return value (0 means OK) - Memory::Write_U32(0, _CommandAddress + 0x4); - - return GetDefaultReply(); + SIOCtlVBuffer Buffer(_CommandAddress); + + DEBUG_LOG(WII_IPC_ES, "%s (0x%x)", GetDeviceName().c_str(), Buffer.Parameter); + + // Prepare the out buffer(s) with zeroes as a safety precaution + // to avoid returning bad values + // XXX: is this still necessary? + for (u32 i = 0; i < Buffer.NumberPayloadBuffer; i++) + { + u32 j; + for (j = 0; j < Buffer.NumberInBuffer; j++) + { + if (Buffer.InBuffer[j].m_Address == Buffer.PayloadBuffer[i].m_Address) + { + // The out buffer is the same as one of the in buffers. Don't zero it. + break; + } + } + if (j == Buffer.NumberInBuffer) + { + Memory::Memset(Buffer.PayloadBuffer[i].m_Address, 0, Buffer.PayloadBuffer[i].m_Size); + } + } + + switch (Buffer.Parameter) + { + case IOCTL_ES_GETDEVICEID: + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, + "IOCTL_ES_GETDEVICEID no out buffer"); + + EcWii& ec = EcWii::GetInstance(); + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETDEVICEID %08X", ec.getNgId()); + Memory::Write_U32(ec.getNgId(), Buffer.PayloadBuffer[0].m_Address); + Memory::Write_U32(0, _CommandAddress + 0x4); + return GetDefaultReply(); + } + break; + + case IOCTL_ES_GETTITLECONTENTSCNT: + { + _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); + _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1); + + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + + const DiscIO::CNANDContentLoader& rNANDContent = AccessContentDevice(TitleID); + u16 NumberOfPrivateContent = 0; + if (rNANDContent.IsValid()) // Not sure if dolphin will ever fail this check + { + NumberOfPrivateContent = rNANDContent.GetNumEntries(); + + if ((u32)(TitleID >> 32) == 0x00010000) + Memory::Write_U32(0, Buffer.PayloadBuffer[0].m_Address); + else + Memory::Write_U32(NumberOfPrivateContent, Buffer.PayloadBuffer[0].m_Address); + + Memory::Write_U32(0, _CommandAddress + 0x4); + } + else + Memory::Write_U32((u32)rNANDContent.GetContentSize(), _CommandAddress + 0x4); + + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTSCNT: TitleID: %08x/%08x content count %i", + (u32)(TitleID >> 32), (u32)TitleID, + rNANDContent.IsValid() ? NumberOfPrivateContent : (u32)rNANDContent.GetContentSize()); + + return GetDefaultReply(); + } + break; + + case IOCTL_ES_GETTITLECONTENTS: + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2, + "IOCTL_ES_GETTITLECONTENTS bad in buffer"); + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, + "IOCTL_ES_GETTITLECONTENTS bad out buffer"); + + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + + const DiscIO::CNANDContentLoader& rNANDContent = AccessContentDevice(TitleID); + if (rNANDContent.IsValid()) // Not sure if dolphin will ever fail this check + { + for (u16 i = 0; i < rNANDContent.GetNumEntries(); i++) + { + Memory::Write_U32(rNANDContent.GetContentByIndex(i)->m_ContentID, + Buffer.PayloadBuffer[0].m_Address + i * 4); + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTS: Index %d: %08x", i, + rNANDContent.GetContentByIndex(i)->m_ContentID); + } + Memory::Write_U32(0, _CommandAddress + 0x4); + } + else + { + Memory::Write_U32((u32)rNANDContent.GetContentSize(), _CommandAddress + 0x4); + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTS: Unable to open content %zu", + rNANDContent.GetContentSize()); + } + + return GetDefaultReply(); + } + break; + + case IOCTL_ES_OPENTITLECONTENT: + { + _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 3); + _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0); + + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + u32 Index = Memory::Read_U32(Buffer.InBuffer[2].m_Address); + + u32 CFD = OpenTitleContent(m_AccessIdentID++, TitleID, Index); + Memory::Write_U32(CFD, _CommandAddress + 0x4); + + INFO_LOG(WII_IPC_ES, "IOCTL_ES_OPENTITLECONTENT: TitleID: %08x/%08x Index %i -> got CFD %x", + (u32)(TitleID >> 32), (u32)TitleID, Index, CFD); + + return GetDefaultReply(); + } + break; + + case IOCTL_ES_OPENCONTENT: + { + _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); + _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0); + u32 Index = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + + u32 CFD = OpenTitleContent(m_AccessIdentID++, m_TitleID, Index); + Memory::Write_U32(CFD, _CommandAddress + 0x4); + INFO_LOG(WII_IPC_ES, "IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD); + + return GetDefaultReply(); + } + break; + + case IOCTL_ES_READCONTENT: + { + _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); + _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1); + + u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + u32 Size = Buffer.PayloadBuffer[0].m_Size; + u32 Addr = Buffer.PayloadBuffer[0].m_Address; + + auto itr = m_ContentAccessMap.find(CFD); + if (itr == m_ContentAccessMap.end()) + { + Memory::Write_U32(-1, _CommandAddress + 0x4); + return GetDefaultReply(); + } + SContentAccess& rContent = itr->second; + + u8* pDest = Memory::GetPointer(Addr); + + if (rContent.m_Position + Size > rContent.m_Size) + { + Size = rContent.m_Size - rContent.m_Position; + } + + if (Size > 0) + { + if (pDest) + { + const DiscIO::CNANDContentLoader& ContentLoader = AccessContentDevice(rContent.m_TitleID); + // ContentLoader should never be invalid; rContent has been created by it. + if (ContentLoader.IsValid()) + { + const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(rContent.m_Index); + if (!pContent->m_Data->GetRange(rContent.m_Position, Size, pDest)) + ERROR_LOG(WII_IPC_ES, "ES: failed to read %u bytes from %u!", Size, + rContent.m_Position); + } + + rContent.m_Position += Size; + } + else + { + PanicAlert("IOCTL_ES_READCONTENT - bad destination"); + } + } + + INFO_LOG(WII_IPC_ES, + "IOCTL_ES_READCONTENT: CFD %x, Address 0x%x, Size %i -> stream pos %i (Index %i)", CFD, + Addr, Size, rContent.m_Position, rContent.m_Index); + + Memory::Write_U32(Size, _CommandAddress + 0x4); + return GetDefaultReply(); + } + break; + + case IOCTL_ES_CLOSECONTENT: + { + _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); + _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0); + + u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + + INFO_LOG(WII_IPC_ES, "IOCTL_ES_CLOSECONTENT: CFD %x", CFD); + + auto itr = m_ContentAccessMap.find(CFD); + if (itr == m_ContentAccessMap.end()) + { + Memory::Write_U32(-1, _CommandAddress + 0x4); + return GetDefaultReply(); + } + + const DiscIO::CNANDContentLoader& ContentLoader = AccessContentDevice(itr->second.m_TitleID); + // ContentLoader should never be invalid; we shouldn't be here if ES_OPENCONTENT failed before. + if (ContentLoader.IsValid()) + { + const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(itr->second.m_Index); + pContent->m_Data->Close(); + } + + m_ContentAccessMap.erase(itr); + + Memory::Write_U32(0, _CommandAddress + 0x4); + return GetDefaultReply(); + } + break; + + case IOCTL_ES_SEEKCONTENT: + { + _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 3); + _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0); + + u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + u32 Addr = Memory::Read_U32(Buffer.InBuffer[1].m_Address); + u32 Mode = Memory::Read_U32(Buffer.InBuffer[2].m_Address); + + auto itr = m_ContentAccessMap.find(CFD); + if (itr == m_ContentAccessMap.end()) + { + Memory::Write_U32(-1, _CommandAddress + 0x4); + return GetDefaultReply(); + } + SContentAccess& rContent = itr->second; + + switch (Mode) + { + case 0: // SET + rContent.m_Position = Addr; + break; + + case 1: // CUR + rContent.m_Position += Addr; + break; + + case 2: // END + rContent.m_Position = rContent.m_Size + Addr; + break; + } + + INFO_LOG(WII_IPC_ES, "IOCTL_ES_SEEKCONTENT: CFD %x, Address 0x%x, Mode %i -> Pos %i", CFD, Addr, + Mode, rContent.m_Position); + + Memory::Write_U32(rContent.m_Position, _CommandAddress + 0x4); + return GetDefaultReply(); + } + break; + + case IOCTL_ES_GETTITLEDIR: + { + _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); + _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1); + + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + + char* Path = (char*)Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address); + sprintf(Path, "/title/%08x/%08x/data", (u32)(TitleID >> 32), (u32)TitleID); + + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLEDIR: %s", Path); + } + break; + + case IOCTL_ES_GETTITLEID: + { + _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 0); + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, + "IOCTL_ES_GETTITLEID no out buffer"); + + Memory::Write_U64(m_TitleID, Buffer.PayloadBuffer[0].m_Address); + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLEID: %08x/%08x", (u32)(m_TitleID >> 32), (u32)m_TitleID); + } + break; + + case IOCTL_ES_SETUID: + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_SETUID no in buffer"); + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0, + "IOCTL_ES_SETUID has a payload, it shouldn't"); + // TODO: fs permissions based on this + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + INFO_LOG(WII_IPC_ES, "IOCTL_ES_SETUID titleID: %08x/%08x", (u32)(TitleID >> 32), (u32)TitleID); + } + break; + + case IOCTL_ES_GETTITLECNT: + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 0, + "IOCTL_ES_GETTITLECNT has an in buffer"); + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, + "IOCTL_ES_GETTITLECNT has no out buffer"); + _dbg_assert_msg_(WII_IPC_ES, Buffer.PayloadBuffer[0].m_Size == 4, + "IOCTL_ES_GETTITLECNT payload[0].size != 4"); + + Memory::Write_U32((u32)m_TitleIDs.size(), Buffer.PayloadBuffer[0].m_Address); + + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECNT: Number of Titles %zu", m_TitleIDs.size()); + + Memory::Write_U32(0, _CommandAddress + 0x4); + + return GetDefaultReply(); + } + break; + + case IOCTL_ES_GETTITLES: + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETTITLES has an in buffer"); + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, + "IOCTL_ES_GETTITLES has no out buffer"); + + u32 MaxCount = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + u32 Count = 0; + for (int i = 0; i < (int)m_TitleIDs.size(); i++) + { + Memory::Write_U64(m_TitleIDs[i], Buffer.PayloadBuffer[0].m_Address + i * 8); + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLES: %08x/%08x", (u32)(m_TitleIDs[i] >> 32), + (u32)m_TitleIDs[i]); + Count++; + if (Count >= MaxCount) + break; + } + + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLES: Number of titles returned %i", Count); + Memory::Write_U32(0, _CommandAddress + 0x4); + return GetDefaultReply(); + } + break; + + case IOCTL_ES_GETVIEWCNT: + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETVIEWCNT no in buffer"); + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, + "IOCTL_ES_GETVIEWCNT no out buffer"); + + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + + u32 retVal = 0; + const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); + u32 ViewCount = + static_cast(Loader.GetTicket().size()) / DiscIO::CNANDContentLoader::TICKET_SIZE; + + if (!ViewCount) + { + std::string TicketFilename = Common::GetTicketFileName(TitleID, Common::FROM_SESSION_ROOT); + if (File::Exists(TicketFilename)) + { + u32 FileSize = (u32)File::GetSize(TicketFilename); + _dbg_assert_msg_(WII_IPC_ES, (FileSize % DiscIO::CNANDContentLoader::TICKET_SIZE) == 0, + "IOCTL_ES_GETVIEWCNT ticket file size seems to be wrong"); + + ViewCount = FileSize / DiscIO::CNANDContentLoader::TICKET_SIZE; + _dbg_assert_msg_(WII_IPC_ES, (ViewCount > 0) && (ViewCount <= 4), + "IOCTL_ES_GETVIEWCNT ticket count seems to be wrong"); + } + else if (TitleID >> 32 == 0x00000001) + { + // Fake a ticket view to make IOS reload work. + ViewCount = 1; + } + else + { + ViewCount = 0; + if (TitleID == TITLEID_SYSMENU) + { + PanicAlertT("There must be a ticket for 00000001/00000002. Your NAND dump is probably " + "incomplete."); + } + // retVal = ES_NO_TICKET_INSTALLED; + } + } + + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETVIEWCNT for titleID: %08x/%08x (View Count = %i)", + (u32)(TitleID >> 32), (u32)TitleID, ViewCount); + + Memory::Write_U32(ViewCount, Buffer.PayloadBuffer[0].m_Address); + Memory::Write_U32(retVal, _CommandAddress + 0x4); + return GetDefaultReply(); + } + break; + + case IOCTL_ES_GETVIEWS: + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2, "IOCTL_ES_GETVIEWS no in buffer"); + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, + "IOCTL_ES_GETVIEWS no out buffer"); + + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + u32 maxViews = Memory::Read_U32(Buffer.InBuffer[1].m_Address); + u32 retVal = 0; + + const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); + + const std::vector& ticket = Loader.GetTicket(); + + if (ticket.empty()) + { + std::string TicketFilename = Common::GetTicketFileName(TitleID, Common::FROM_SESSION_ROOT); + if (File::Exists(TicketFilename)) + { + File::IOFile pFile(TicketFilename, "rb"); + if (pFile) + { + u8 FileTicket[DiscIO::CNANDContentLoader::TICKET_SIZE]; + for (unsigned int View = 0; + View != maxViews && + pFile.ReadBytes(FileTicket, DiscIO::CNANDContentLoader::TICKET_SIZE); + ++View) + { + Memory::Write_U32(View, Buffer.PayloadBuffer[0].m_Address + View * 0xD8); + Memory::CopyToEmu(Buffer.PayloadBuffer[0].m_Address + 4 + View * 0xD8, + FileTicket + 0x1D0, 212); + } + } + } + else if (TitleID >> 32 == 0x00000001) + { + // For IOS titles, the ticket view isn't normally parsed by either the + // SDK or libogc, just passed to LaunchTitle, so this + // shouldn't matter at all. Just fill out some fields just + // to be on the safe side. + u32 Address = Buffer.PayloadBuffer[0].m_Address; + Memory::Memset(Address, 0, 0xD8); + Memory::Write_U64(TitleID, Address + 4 + (0x1dc - 0x1d0)); // title ID + Memory::Write_U16(0xffff, Address + 4 + (0x1e4 - 0x1d0)); // unnnown + Memory::Write_U32(0xff00, Address + 4 + (0x1ec - 0x1d0)); // access mask + Memory::Memset(Address + 4 + (0x222 - 0x1d0), 0xff, 0x20); // content permissions + } + else + { + // retVal = ES_NO_TICKET_INSTALLED; + PanicAlertT("IOCTL_ES_GETVIEWS: Tried to get data from an unknown ticket: %08x/%08x", + (u32)(TitleID >> 32), (u32)TitleID); + } + } + else + { + u32 view_count = + static_cast(Loader.GetTicket().size()) / DiscIO::CNANDContentLoader::TICKET_SIZE; + for (unsigned int view = 0; view != maxViews && view < view_count; ++view) + { + Memory::Write_U32(view, Buffer.PayloadBuffer[0].m_Address + view * 0xD8); + Memory::CopyToEmu(Buffer.PayloadBuffer[0].m_Address + 4 + view * 0xD8, + &ticket[0x1D0 + (view * DiscIO::CNANDContentLoader::TICKET_SIZE)], 212); + } + } + + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETVIEWS for titleID: %08x/%08x (MaxViews = %i)", + (u32)(TitleID >> 32), (u32)TitleID, maxViews); + + Memory::Write_U32(retVal, _CommandAddress + 0x4); + return GetDefaultReply(); + } + break; + + case IOCTL_ES_GETTMDVIEWCNT: + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETTMDVIEWCNT no in buffer"); + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, + "IOCTL_ES_GETTMDVIEWCNT no out buffer"); + + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + + const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); + + u32 TMDViewCnt = 0; + if (Loader.IsValid()) + { + TMDViewCnt += DiscIO::CNANDContentLoader::TMD_VIEW_SIZE; + TMDViewCnt += 2; // title version + TMDViewCnt += 2; // num entries + TMDViewCnt += + (u32)Loader.GetContentSize() * (4 + 2 + 2 + 8); // content id, index, type, size + } + Memory::Write_U32(TMDViewCnt, Buffer.PayloadBuffer[0].m_Address); + + Memory::Write_U32(0, _CommandAddress + 0x4); + + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x (view size %i)", + (u32)(TitleID >> 32), (u32)TitleID, TMDViewCnt); + return GetDefaultReply(); + } + break; + + case IOCTL_ES_GETTMDVIEWS: + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2, "IOCTL_ES_GETTMDVIEWCNT no in buffer"); + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, + "IOCTL_ES_GETTMDVIEWCNT no out buffer"); + + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + u32 MaxCount = Memory::Read_U32(Buffer.InBuffer[1].m_Address); + + const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); + + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTMDVIEWCNT: title: %08x/%08x buffer size: %i", + (u32)(TitleID >> 32), (u32)TitleID, MaxCount); + + if (Loader.IsValid()) + { + u32 Address = Buffer.PayloadBuffer[0].m_Address; + + Memory::CopyToEmu(Address, Loader.GetTMDView(), DiscIO::CNANDContentLoader::TMD_VIEW_SIZE); + Address += DiscIO::CNANDContentLoader::TMD_VIEW_SIZE; + + Memory::Write_U16(Loader.GetTitleVersion(), Address); + Address += 2; + Memory::Write_U16(Loader.GetNumEntries(), Address); + Address += 2; + + const std::vector& rContent = Loader.GetContent(); + for (size_t i = 0; i < Loader.GetContentSize(); i++) + { + Memory::Write_U32(rContent[i].m_ContentID, Address); + Address += 4; + Memory::Write_U16(rContent[i].m_Index, Address); + Address += 2; + Memory::Write_U16(rContent[i].m_Type, Address); + Address += 2; + Memory::Write_U64(rContent[i].m_Size, Address); + Address += 8; + } + + _dbg_assert_(WII_IPC_ES, + (Address - Buffer.PayloadBuffer[0].m_Address) == Buffer.PayloadBuffer[0].m_Size); + } + Memory::Write_U32(0, _CommandAddress + 0x4); + + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTMDVIEWS: title: %08x/%08x (buffer size: %i)", + (u32)(TitleID >> 32), (u32)TitleID, MaxCount); + return GetDefaultReply(); + } + break; + + case IOCTL_ES_GETCONSUMPTION: // This is at least what crediar's ES module does + Memory::Write_U32(0, Buffer.PayloadBuffer[1].m_Address); + Memory::Write_U32(0, _CommandAddress + 0x4); + WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETCONSUMPTION:%d", Memory::Read_U32(_CommandAddress + 4)); + return GetDefaultReply(); + + case IOCTL_ES_DELETETICKET: + { + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + INFO_LOG(WII_IPC_ES, "IOCTL_ES_DELETETICKET: title: %08x/%08x", (u32)(TitleID >> 32), + (u32)TitleID); + if (File::Delete(Common::GetTicketFileName(TitleID, Common::FROM_SESSION_ROOT))) + { + Memory::Write_U32(0, _CommandAddress + 0x4); + } + else + { + // Presumably return -1017 when delete fails + Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT, _CommandAddress + 0x4); + } + } + break; + case IOCTL_ES_DELETETITLECONTENT: + { + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + INFO_LOG(WII_IPC_ES, "IOCTL_ES_DELETETITLECONTENT: title: %08x/%08x", (u32)(TitleID >> 32), + (u32)TitleID); + if (DiscIO::CNANDContentManager::Access().RemoveTitle(TitleID, Common::FROM_SESSION_ROOT)) + { + Memory::Write_U32(0, _CommandAddress + 0x4); + } + else + { + // Presumably return -1017 when title not installed TODO verify + Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT, _CommandAddress + 0x4); + } + } + break; + case IOCTL_ES_GETSTOREDTMDSIZE: + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, + "IOCTL_ES_GETSTOREDTMDSIZE no in buffer"); + // _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_ES_GETSTOREDTMDSIZE + // no out buffer"); + + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); + + _dbg_assert_(WII_IPC_ES, Loader.IsValid()); + u32 TMDCnt = 0; + if (Loader.IsValid()) + { + TMDCnt += DiscIO::CNANDContentLoader::TMD_HEADER_SIZE; + TMDCnt += (u32)Loader.GetContentSize() * DiscIO::CNANDContentLoader::CONTENT_HEADER_SIZE; + } + if (Buffer.NumberPayloadBuffer) + Memory::Write_U32(TMDCnt, Buffer.PayloadBuffer[0].m_Address); + + Memory::Write_U32(0, _CommandAddress + 0x4); + + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETSTOREDTMDSIZE: title: %08x/%08x (view size %i)", + (u32)(TitleID >> 32), (u32)TitleID, TMDCnt); + return GetDefaultReply(); + } + break; + case IOCTL_ES_GETSTOREDTMD: + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer > 0, "IOCTL_ES_GETSTOREDTMD no in buffer"); + // requires 1 inbuffer and no outbuffer, presumably outbuffer required when second inbuffer is + // used for maxcount (allocated mem?) + // called with 1 inbuffer after deleting a titleid + //_dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETSTOREDTMD no out + //buffer"); + + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + u32 MaxCount = 0; + if (Buffer.NumberInBuffer > 1) + { + // TODO: actually use this param in when writing to the outbuffer :/ + MaxCount = Memory::Read_U32(Buffer.InBuffer[1].m_Address); + } + const DiscIO::CNANDContentLoader& Loader = AccessContentDevice(TitleID); + + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x buffer size: %i", + (u32)(TitleID >> 32), (u32)TitleID, MaxCount); + + if (Loader.IsValid() && Buffer.NumberPayloadBuffer) + { + u32 Address = Buffer.PayloadBuffer[0].m_Address; + + Memory::CopyToEmu(Address, Loader.GetTMDHeader(), + DiscIO::CNANDContentLoader::TMD_HEADER_SIZE); + Address += DiscIO::CNANDContentLoader::TMD_HEADER_SIZE; + + const std::vector& rContent = Loader.GetContent(); + for (size_t i = 0; i < Loader.GetContentSize(); i++) + { + Memory::CopyToEmu(Address, rContent[i].m_Header, + DiscIO::CNANDContentLoader::CONTENT_HEADER_SIZE); + Address += DiscIO::CNANDContentLoader::CONTENT_HEADER_SIZE; + } + + _dbg_assert_(WII_IPC_ES, + (Address - Buffer.PayloadBuffer[0].m_Address) == Buffer.PayloadBuffer[0].m_Size); + } + Memory::Write_U32(0, _CommandAddress + 0x4); + + INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x (buffer size: %i)", + (u32)(TitleID >> 32), (u32)TitleID, MaxCount); + return GetDefaultReply(); + } + break; + + case IOCTL_ES_ENCRYPT: + { + u32 keyIndex = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + u8* IV = Memory::GetPointer(Buffer.InBuffer[1].m_Address); + u8* source = Memory::GetPointer(Buffer.InBuffer[2].m_Address); + u32 size = Buffer.InBuffer[2].m_Size; + u8* newIV = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address); + u8* destination = Memory::GetPointer(Buffer.PayloadBuffer[1].m_Address); + + mbedtls_aes_context AES_ctx; + mbedtls_aes_setkey_enc(&AES_ctx, keyTable[keyIndex], 128); + memcpy(newIV, IV, 16); + mbedtls_aes_crypt_cbc(&AES_ctx, MBEDTLS_AES_ENCRYPT, size, newIV, source, destination); + + _dbg_assert_msg_(WII_IPC_ES, keyIndex == 6, + "IOCTL_ES_ENCRYPT: Key type is not SD, data will be crap"); + } + break; + + case IOCTL_ES_DECRYPT: + { + u32 keyIndex = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + u8* IV = Memory::GetPointer(Buffer.InBuffer[1].m_Address); + u8* source = Memory::GetPointer(Buffer.InBuffer[2].m_Address); + u32 size = Buffer.InBuffer[2].m_Size; + u8* newIV = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address); + u8* destination = Memory::GetPointer(Buffer.PayloadBuffer[1].m_Address); + + mbedtls_aes_context AES_ctx; + mbedtls_aes_setkey_dec(&AES_ctx, keyTable[keyIndex], 128); + memcpy(newIV, IV, 16); + mbedtls_aes_crypt_cbc(&AES_ctx, MBEDTLS_AES_DECRYPT, size, newIV, source, destination); + + _dbg_assert_msg_(WII_IPC_ES, keyIndex == 6, + "IOCTL_ES_DECRYPT: Key type is not SD, data will be crap"); + } + break; + + case IOCTL_ES_LAUNCH: + { + _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 2); + bool bSuccess = false; + u16 IOSv = 0xffff; + + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + u32 view = Memory::Read_U32(Buffer.InBuffer[1].m_Address); + u64 ticketid = Memory::Read_U64(Buffer.InBuffer[1].m_Address + 4); + u32 devicetype = Memory::Read_U32(Buffer.InBuffer[1].m_Address + 12); + u64 titleid = Memory::Read_U64(Buffer.InBuffer[1].m_Address + 16); + u16 access = Memory::Read_U16(Buffer.InBuffer[1].m_Address + 24); + + // ES_LAUNCH should probably reset thw whole state, which at least means closing all open files. + // leaving them open through ES_LAUNCH may cause hangs and other funky behavior + // (supposedly when trying to re-open those files). + DiscIO::CNANDContentManager::Access().ClearCache(); + + std::string tContentFile; + if ((u32)(TitleID >> 32) != 0x00000001 || TitleID == TITLEID_SYSMENU) + { + const DiscIO::CNANDContentLoader& ContentLoader = AccessContentDevice(TitleID); + if (ContentLoader.IsValid()) + { + u32 bootInd = ContentLoader.GetBootIndex(); + const DiscIO::SNANDContent* pContent = ContentLoader.GetContentByIndex(bootInd); + if (pContent) + { + tContentFile = Common::GetTitleContentPath(TitleID, Common::FROM_SESSION_ROOT); + std::unique_ptr pDolLoader = + std::make_unique(pContent->m_Data->Get()); + + if (pDolLoader->IsValid()) + { + pDolLoader->Load(); // TODO: Check why sysmenu does not load the DOL correctly + PC = pDolLoader->GetEntryPoint(); + bSuccess = true; + } + else + { + PanicAlertT("IOCTL_ES_LAUNCH: The DOL file is invalid!"); + bSuccess = false; + } + + IOSv = ContentLoader.GetIosVersion(); + } + } + } + else // IOS, MIOS, BC etc + { + // TODO: fixme + // The following is obviously a hack + // Lie to mem about loading a different IOS + // someone with an affected game should test + IOSv = TitleID & 0xffff; + bSuccess = true; + } + if (!bSuccess) + { + PanicAlertT( + "IOCTL_ES_LAUNCH: Game tried to reload a title that is not available in your NAND dump\n" + "TitleID %016" PRIx64 ".\n Dolphin will likely hang now.", + TitleID); + } + else + { + CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer(); + size_t size = s_Usb->m_WiiMotes.size(); + bool* wiiMoteConnected = new bool[size]; + for (unsigned int i = 0; i < size; i++) + wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected(); + + WII_IPC_HLE_Interface::Reset(true); + WII_IPC_HLE_Interface::Init(); + s_Usb = GetUsbPointer(); + for (unsigned int i = 0; i < s_Usb->m_WiiMotes.size(); i++) + { + if (wiiMoteConnected[i]) + { + s_Usb->m_WiiMotes[i].Activate(false); + s_Usb->m_WiiMotes[i].Activate(true); + } + else + { + s_Usb->m_WiiMotes[i].Activate(false); + } + } + + delete[] wiiMoteConnected; + WII_IPC_HLE_Interface::SetDefaultContentFile(tContentFile); + } + // Pass the "#002 check" + // Apploader should write the IOS version and revision to 0x3140, and compare it + // to 0x3188 to pass the check, but we don't do it, and i don't know where to read the IOS + // rev... + // Currently we just write 0xFFFF for the revision, copy manually and it works fine :p + // TODO : figure it correctly : where should we read the IOS rev that the wad "needs" ? + Memory::Write_U16(IOSv, 0x00003140); + Memory::Write_U16(0xFFFF, 0x00003142); + Memory::Write_U32(Memory::Read_U32(0x00003140), 0x00003188); + + // TODO: provide correct return code when bSuccess= false + Memory::Write_U32(0, _CommandAddress + 0x4); + + ERROR_LOG(WII_IPC_ES, + "IOCTL_ES_LAUNCH %016" PRIx64 " %08x %016" PRIx64 " %08x %016" PRIx64 " %04x", + TitleID, view, ticketid, devicetype, titleid, access); + // IOCTL_ES_LAUNCH 0001000248414341 00000001 0001c0fef3df2cfa 00000000 + // 0001000248414341 ffff + + // This is necessary because Reset(true) above deleted this object. Ew. + + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, _CommandAddress); + // IOS also seems to write back the command that was responded to in the FD field. + Memory::Write_U32(IPC_CMD_IOCTLV, _CommandAddress + 8); + + // Generate a "reply" to the IPC command. ES_LAUNCH is unique because it + // involves restarting IOS; IOS generates two acknowledgements in a row. + WII_IPC_HLE_Interface::EnqueueCommandAcknowledgement(_CommandAddress, 0); + return GetNoReply(); + } + break; + + case IOCTL_ES_CHECKKOREAREGION: // note by DacoTaco : name is unknown, i just tried to name it + // SOMETHING + // IOS70 has this to let system menu 4.2 check if the console is region changed. it returns + // -1017 + // if the IOS didn't find the Korean keys and 0 if it does. 0 leads to a error 003 + WARN_LOG(WII_IPC_ES, "IOCTL_ES_CHECKKOREAREGION: Title checked for Korean keys."); + Memory::Write_U32(ES_PARAMTER_SIZE_OR_ALIGNMENT, _CommandAddress + 0x4); + return GetDefaultReply(); + + case IOCTL_ES_GETDEVICECERT: // (Input: none, Output: 384 bytes) + { + WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETDEVICECERT"); + _dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1); + u8* destination = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address); + + EcWii& ec = EcWii::GetInstance(); + get_ng_cert(destination, ec.getNgId(), ec.getNgKeyId(), ec.getNgPriv(), ec.getNgSig()); + } + break; + + case IOCTL_ES_SIGN: + { + WARN_LOG(WII_IPC_ES, "IOCTL_ES_SIGN"); + u8* ap_cert_out = Memory::GetPointer(Buffer.PayloadBuffer[1].m_Address); + u8* data = Memory::GetPointer(Buffer.InBuffer[0].m_Address); + u32 data_size = Buffer.InBuffer[0].m_Size; + u8* sig_out = Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address); + + EcWii& ec = EcWii::GetInstance(); + get_ap_sig_and_cert(sig_out, ap_cert_out, m_TitleID, data, data_size, ec.getNgPriv(), + ec.getNgId()); + } + break; + + case IOCTL_ES_GETBOOT2VERSION: + { + WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETBOOT2VERSION"); + + Memory::Write_U32( + 4, Buffer.PayloadBuffer[0].m_Address); // as of 26/02/2012, this was latest bootmii version + } + break; + + // =============================================================================================== + // unsupported functions + // =============================================================================================== + case IOCTL_ES_DIGETTICKETVIEW: // (Input: none, Output: 216 bytes) bug crediar :D + WARN_LOG(WII_IPC_ES, "IOCTL_ES_DIGETTICKETVIEW: this looks really wrong..."); + break; + + case IOCTL_ES_GETOWNEDTITLECNT: + WARN_LOG(WII_IPC_ES, "IOCTL_ES_GETOWNEDTITLECNT"); + Memory::Write_U32(0, Buffer.PayloadBuffer[0].m_Address); + break; + + default: + WARN_LOG(WII_IPC_ES, "CWII_IPC_HLE_Device_es: 0x%x", Buffer.Parameter); + DumpCommands(_CommandAddress, 8, LogTypes::WII_IPC_ES); + INFO_LOG(WII_IPC_ES, "command.Parameter: 0x%08x", Buffer.Parameter); + break; + } + + // Write return value (0 means OK) + Memory::Write_U32(0, _CommandAddress + 0x4); + + return GetDefaultReply(); } const DiscIO::CNANDContentLoader& CWII_IPC_HLE_Device_es::AccessContentDevice(u64 title_id) { - // for WADs, the passed title id and the stored title id match; along with m_ContentFile being set to the - // actual WAD file name. We cannot simply get a NAND Loader for the title id in those cases, since the WAD - // need not be installed in the NAND, but it could be opened directly from a WAD file anywhere on disk. - if (m_TitleID == title_id && !m_ContentFile.empty()) - return DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile); + // for WADs, the passed title id and the stored title id match; along with m_ContentFile being set + // to the + // actual WAD file name. We cannot simply get a NAND Loader for the title id in those cases, since + // the WAD + // need not be installed in the NAND, but it could be opened directly from a WAD file anywhere on + // disk. + if (m_TitleID == title_id && !m_ContentFile.empty()) + return DiscIO::CNANDContentManager::Access().GetNANDLoader(m_ContentFile); - return DiscIO::CNANDContentManager::Access().GetNANDLoader(title_id, Common::FROM_SESSION_ROOT); + return DiscIO::CNANDContentManager::Access().GetNANDLoader(title_id, Common::FROM_SESSION_ROOT); } u32 CWII_IPC_HLE_Device_es::ES_DIVerify(const std::vector& tmd) { - u64 title_id = 0xDEADBEEFDEADBEEFull; - u64 tmd_title_id = Common::swap64(&tmd[0x18C]); + u64 title_id = 0xDEADBEEFDEADBEEFull; + u64 tmd_title_id = Common::swap64(&tmd[0x18C]); - DVDInterface::GetVolume().GetTitleID(&title_id); - if (title_id != tmd_title_id) - return -1; + DVDInterface::GetVolume().GetTitleID(&title_id); + if (title_id != tmd_title_id) + return -1; - std::string tmd_path = Common::GetTMDFileName(tmd_title_id, Common::FROM_SESSION_ROOT); + std::string tmd_path = Common::GetTMDFileName(tmd_title_id, Common::FROM_SESSION_ROOT); - File::CreateFullPath(tmd_path); - File::CreateFullPath(Common::GetTitleDataPath(tmd_title_id, Common::FROM_SESSION_ROOT)); + File::CreateFullPath(tmd_path); + File::CreateFullPath(Common::GetTitleDataPath(tmd_title_id, Common::FROM_SESSION_ROOT)); - Movie::g_titleID = tmd_title_id; - std::string save_path = Common::GetTitleDataPath(tmd_title_id, Common::FROM_SESSION_ROOT); - if (Movie::IsRecordingInput()) - { - // TODO: Check for the actual save data - if (File::Exists(save_path + "banner.bin")) - Movie::g_bClearSave = false; - else - Movie::g_bClearSave = true; - } + Movie::g_titleID = tmd_title_id; + std::string save_path = Common::GetTitleDataPath(tmd_title_id, Common::FROM_SESSION_ROOT); + if (Movie::IsRecordingInput()) + { + // TODO: Check for the actual save data + if (File::Exists(save_path + "banner.bin")) + Movie::g_bClearSave = false; + else + Movie::g_bClearSave = true; + } - // TODO: Force the game to save to another location, instead of moving the user's save. - if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsStartingFromClearSave()) - { - if (File::Exists(save_path + "banner.bin")) - { - if (File::Exists(save_path + "../backup/")) - { - // The last run of this game must have been to play back a movie, so their save is already backed up. - File::DeleteDirRecursively(save_path); - } - else - { - #ifdef _WIN32 - MoveFile(UTF8ToTStr(save_path).c_str(), UTF8ToTStr(save_path + "../backup/").c_str()); - #else - File::CopyDir(save_path, save_path + "../backup/"); - File::DeleteDirRecursively(save_path); - #endif - } - } - } - else if (File::Exists(save_path + "../backup/")) - { - // Delete the save made by a previous movie, and copy back the user's save. - if (File::Exists(save_path + "banner.bin")) - File::DeleteDirRecursively(save_path); - #ifdef _WIN32 - MoveFile(UTF8ToTStr(save_path + "../backup/").c_str(), UTF8ToTStr(save_path).c_str()); - #else - File::CopyDir(save_path + "../backup/", save_path); - File::DeleteDirRecursively(save_path + "../backup/"); - #endif - } + // TODO: Force the game to save to another location, instead of moving the user's save. + if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsStartingFromClearSave()) + { + if (File::Exists(save_path + "banner.bin")) + { + if (File::Exists(save_path + "../backup/")) + { + // The last run of this game must have been to play back a movie, so their save is already + // backed up. + File::DeleteDirRecursively(save_path); + } + else + { +#ifdef _WIN32 + MoveFile(UTF8ToTStr(save_path).c_str(), UTF8ToTStr(save_path + "../backup/").c_str()); +#else + File::CopyDir(save_path, save_path + "../backup/"); + File::DeleteDirRecursively(save_path); +#endif + } + } + } + else if (File::Exists(save_path + "../backup/")) + { + // Delete the save made by a previous movie, and copy back the user's save. + if (File::Exists(save_path + "banner.bin")) + File::DeleteDirRecursively(save_path); +#ifdef _WIN32 + MoveFile(UTF8ToTStr(save_path + "../backup/").c_str(), UTF8ToTStr(save_path).c_str()); +#else + File::CopyDir(save_path + "../backup/", save_path); + File::DeleteDirRecursively(save_path + "../backup/"); +#endif + } - if (!File::Exists(tmd_path)) - { - File::IOFile tmd_file(tmd_path, "wb"); - if (!tmd_file.WriteBytes(tmd.data(), tmd.size())) - ERROR_LOG(WII_IPC_ES, "DIVerify failed to write disc TMD to NAND."); - } - DiscIO::cUIDsys::AccessInstance().AddTitle(tmd_title_id); - // DI_VERIFY writes to title.tmd, which is read and cached inside the NAND Content Manager. - // clear the cache to avoid content access mismatches. - DiscIO::CNANDContentManager::Access().ClearCache(); - return 0; + if (!File::Exists(tmd_path)) + { + File::IOFile tmd_file(tmd_path, "wb"); + if (!tmd_file.WriteBytes(tmd.data(), tmd.size())) + ERROR_LOG(WII_IPC_ES, "DIVerify failed to write disc TMD to NAND."); + } + DiscIO::cUIDsys::AccessInstance().AddTitle(tmd_title_id); + // DI_VERIFY writes to title.tmd, which is read and cached inside the NAND Content Manager. + // clear the cache to avoid content access mismatches. + DiscIO::CNANDContentManager::Access().ClearCache(); + return 0; } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.h index a0d0d72065..e7f8ab0dd3 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.h @@ -14,143 +14,142 @@ class PointerWrap; namespace DiscIO { - class CNANDContentLoader; - struct SNANDContent; +class CNANDContentLoader; +struct SNANDContent; } class CWII_IPC_HLE_Device_es : public IWII_IPC_HLE_Device { public: + CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string& _rDeviceName); - CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string& _rDeviceName); + virtual ~CWII_IPC_HLE_Device_es(); - virtual ~CWII_IPC_HLE_Device_es(); + void LoadWAD(const std::string& _rContentFile); - void LoadWAD(const std::string& _rContentFile); + void OpenInternal(); - void OpenInternal(); + void DoState(PointerWrap& p) override; - void DoState(PointerWrap& p) override; + IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; + IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; - IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; - IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; + IPCCommandResult IOCtlV(u32 _CommandAddress) override; - IPCCommandResult IOCtlV(u32 _CommandAddress) override; + static u32 ES_DIVerify(const std::vector& tmd); - static u32 ES_DIVerify(const std::vector& tmd); - - // This should only be cleared on power reset - static std::string m_ContentFile; + // This should only be cleared on power reset + static std::string m_ContentFile; private: - enum - { - IOCTL_ES_ADDTICKET = 0x01, - IOCTL_ES_ADDTITLESTART = 0x02, - IOCTL_ES_ADDCONTENTSTART = 0x03, - IOCTL_ES_ADDCONTENTDATA = 0x04, - IOCTL_ES_ADDCONTENTFINISH = 0x05, - IOCTL_ES_ADDTITLEFINISH = 0x06, - IOCTL_ES_GETDEVICEID = 0x07, - IOCTL_ES_LAUNCH = 0x08, - IOCTL_ES_OPENCONTENT = 0x09, - IOCTL_ES_READCONTENT = 0x0A, - IOCTL_ES_CLOSECONTENT = 0x0B, - IOCTL_ES_GETOWNEDTITLECNT = 0x0C, - IOCTL_ES_GETOWNEDTITLES = 0x0D, - IOCTL_ES_GETTITLECNT = 0x0E, - IOCTL_ES_GETTITLES = 0x0F, - IOCTL_ES_GETTITLECONTENTSCNT = 0x10, - IOCTL_ES_GETTITLECONTENTS = 0x11, - IOCTL_ES_GETVIEWCNT = 0x12, - IOCTL_ES_GETVIEWS = 0x13, - IOCTL_ES_GETTMDVIEWCNT = 0x14, - IOCTL_ES_GETTMDVIEWS = 0x15, - IOCTL_ES_GETCONSUMPTION = 0x16, - IOCTL_ES_DELETETITLE = 0x17, - IOCTL_ES_DELETETICKET = 0x18, - // IOCTL_ES_DIGETTMDVIEWSIZE = 0x19, - // IOCTL_ES_DIGETTMDVIEW = 0x1A, - IOCTL_ES_DIGETTICKETVIEW = 0x1B, - IOCTL_ES_DIVERIFY = 0x1C, - IOCTL_ES_GETTITLEDIR = 0x1D, - IOCTL_ES_GETDEVICECERT = 0x1E, - IOCTL_ES_IMPORTBOOT = 0x1F, - IOCTL_ES_GETTITLEID = 0x20, - IOCTL_ES_SETUID = 0x21, - IOCTL_ES_DELETETITLECONTENT = 0x22, - IOCTL_ES_SEEKCONTENT = 0x23, - IOCTL_ES_OPENTITLECONTENT = 0x24, - // IOCTL_ES_LAUNCHBC = 0x25, - // IOCTL_ES_EXPORTTITLEINIT = 0x26, - // IOCTL_ES_EXPORTCONTENTBEGIN = 0x27, - // IOCTL_ES_EXPORTCONTENTDATA = 0x28, - // IOCTL_ES_EXPORTCONTENTEND = 0x29, - // IOCTL_ES_EXPORTTITLEDONE = 0x2A, - IOCTL_ES_ADDTMD = 0x2B, - IOCTL_ES_ENCRYPT = 0x2C, - IOCTL_ES_DECRYPT = 0x2D, - IOCTL_ES_GETBOOT2VERSION = 0x2E, - IOCTL_ES_ADDTITLECANCEL = 0x2F, - IOCTL_ES_SIGN = 0x30, - // IOCTL_ES_VERIFYSIGN = 0x31, - IOCTL_ES_GETSTOREDCONTENTCNT = 0x32, - IOCTL_ES_GETSTOREDCONTENTS = 0x33, - IOCTL_ES_GETSTOREDTMDSIZE = 0x34, - IOCTL_ES_GETSTOREDTMD = 0x35, - IOCTL_ES_GETSHAREDCONTENTCNT = 0x36, - IOCTL_ES_GETSHAREDCONTENTS = 0x37, - IOCTL_ES_DELETESHAREDCONTENT = 0x38, - // - IOCTL_ES_CHECKKOREAREGION = 0x45, - }; + enum + { + IOCTL_ES_ADDTICKET = 0x01, + IOCTL_ES_ADDTITLESTART = 0x02, + IOCTL_ES_ADDCONTENTSTART = 0x03, + IOCTL_ES_ADDCONTENTDATA = 0x04, + IOCTL_ES_ADDCONTENTFINISH = 0x05, + IOCTL_ES_ADDTITLEFINISH = 0x06, + IOCTL_ES_GETDEVICEID = 0x07, + IOCTL_ES_LAUNCH = 0x08, + IOCTL_ES_OPENCONTENT = 0x09, + IOCTL_ES_READCONTENT = 0x0A, + IOCTL_ES_CLOSECONTENT = 0x0B, + IOCTL_ES_GETOWNEDTITLECNT = 0x0C, + IOCTL_ES_GETOWNEDTITLES = 0x0D, + IOCTL_ES_GETTITLECNT = 0x0E, + IOCTL_ES_GETTITLES = 0x0F, + IOCTL_ES_GETTITLECONTENTSCNT = 0x10, + IOCTL_ES_GETTITLECONTENTS = 0x11, + IOCTL_ES_GETVIEWCNT = 0x12, + IOCTL_ES_GETVIEWS = 0x13, + IOCTL_ES_GETTMDVIEWCNT = 0x14, + IOCTL_ES_GETTMDVIEWS = 0x15, + IOCTL_ES_GETCONSUMPTION = 0x16, + IOCTL_ES_DELETETITLE = 0x17, + IOCTL_ES_DELETETICKET = 0x18, + // IOCTL_ES_DIGETTMDVIEWSIZE = 0x19, + // IOCTL_ES_DIGETTMDVIEW = 0x1A, + IOCTL_ES_DIGETTICKETVIEW = 0x1B, + IOCTL_ES_DIVERIFY = 0x1C, + IOCTL_ES_GETTITLEDIR = 0x1D, + IOCTL_ES_GETDEVICECERT = 0x1E, + IOCTL_ES_IMPORTBOOT = 0x1F, + IOCTL_ES_GETTITLEID = 0x20, + IOCTL_ES_SETUID = 0x21, + IOCTL_ES_DELETETITLECONTENT = 0x22, + IOCTL_ES_SEEKCONTENT = 0x23, + IOCTL_ES_OPENTITLECONTENT = 0x24, + // IOCTL_ES_LAUNCHBC = 0x25, + // IOCTL_ES_EXPORTTITLEINIT = 0x26, + // IOCTL_ES_EXPORTCONTENTBEGIN = 0x27, + // IOCTL_ES_EXPORTCONTENTDATA = 0x28, + // IOCTL_ES_EXPORTCONTENTEND = 0x29, + // IOCTL_ES_EXPORTTITLEDONE = 0x2A, + IOCTL_ES_ADDTMD = 0x2B, + IOCTL_ES_ENCRYPT = 0x2C, + IOCTL_ES_DECRYPT = 0x2D, + IOCTL_ES_GETBOOT2VERSION = 0x2E, + IOCTL_ES_ADDTITLECANCEL = 0x2F, + IOCTL_ES_SIGN = 0x30, + // IOCTL_ES_VERIFYSIGN = 0x31, + IOCTL_ES_GETSTOREDCONTENTCNT = 0x32, + IOCTL_ES_GETSTOREDCONTENTS = 0x33, + IOCTL_ES_GETSTOREDTMDSIZE = 0x34, + IOCTL_ES_GETSTOREDTMD = 0x35, + IOCTL_ES_GETSHAREDCONTENTCNT = 0x36, + IOCTL_ES_GETSHAREDCONTENTS = 0x37, + IOCTL_ES_DELETESHAREDCONTENT = 0x38, + // + IOCTL_ES_CHECKKOREAREGION = 0x45, + }; - enum EErrorCodes - { - ES_INVALID_TMD = -106, // or access denied - ES_READ_LESS_DATA_THAN_EXPECTED = -1009, - ES_WRITE_FAILURE = -1010, - ES_PARAMTER_SIZE_OR_ALIGNMENT = -1017, - ES_HASH_DOESNT_MATCH = -1022, - ES_MEM_ALLOC_FAILED = -1024, - ES_INCORRECT_ACCESS_RIGHT = -1026, - ES_NO_TICKET_INSTALLED = -1028, - ES_INSTALLED_TICKET_INVALID = -1029, - ES_INVALID_PARAMETR = -2008, - ES_SIGNATURE_CHECK_FAILED = -2011, - ES_HASH_SIZE_WRONG = -2014, // HASH !=20 - }; + enum EErrorCodes + { + ES_INVALID_TMD = -106, // or access denied + ES_READ_LESS_DATA_THAN_EXPECTED = -1009, + ES_WRITE_FAILURE = -1010, + ES_PARAMTER_SIZE_OR_ALIGNMENT = -1017, + ES_HASH_DOESNT_MATCH = -1022, + ES_MEM_ALLOC_FAILED = -1024, + ES_INCORRECT_ACCESS_RIGHT = -1026, + ES_NO_TICKET_INSTALLED = -1028, + ES_INSTALLED_TICKET_INVALID = -1029, + ES_INVALID_PARAMETR = -2008, + ES_SIGNATURE_CHECK_FAILED = -2011, + ES_HASH_SIZE_WRONG = -2014, // HASH !=20 + }; - struct SContentAccess - { - u32 m_Position; - u64 m_TitleID; - u16 m_Index; - u32 m_Size; - }; + struct SContentAccess + { + u32 m_Position; + u64 m_TitleID; + u16 m_Index; + u32 m_Size; + }; - typedef std::map CContentAccessMap; - CContentAccessMap m_ContentAccessMap; + typedef std::map CContentAccessMap; + CContentAccessMap m_ContentAccessMap; - std::vector m_TitleIDs; - u64 m_TitleID; - u32 m_AccessIdentID; + std::vector m_TitleIDs; + u64 m_TitleID; + u32 m_AccessIdentID; - static u8 *keyTable[11]; + static u8* keyTable[11]; - const DiscIO::CNANDContentLoader& AccessContentDevice(u64 title_id); - u32 OpenTitleContent(u32 CFD, u64 TitleID, u16 Index); + const DiscIO::CNANDContentLoader& AccessContentDevice(u64 title_id); + u32 OpenTitleContent(u32 CFD, u64 TitleID, u16 Index); - struct ecc_cert_t - { - u32 sig_type ; - u8 sig [0x3c]; - u8 pad [0x40]; - u8 issuer [0x40]; - u32 key_type ; - u8 key_name [0x40]; - u32 ng_key_id ; - u8 ecc_pubkey [0x3c]; - u8 padding [0x3c]; - }; + struct ecc_cert_t + { + u32 sig_type; + u8 sig[0x3c]; + u8 pad[0x40]; + u8 issuer[0x40]; + u32 key_type; + u8 key_name[0x40]; + u32 ng_key_id; + u8 ecc_pubkey[0x3c]; + u8 padding[0x3c]; + }; }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.cpp index 77c1f9ac25..c687ea8a0d 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.cpp @@ -19,555 +19,589 @@ static Common::replace_v replacements; CWII_IPC_HLE_Device_fs::CWII_IPC_HLE_Device_fs(u32 _DeviceID, const std::string& _rDeviceName) - : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) { - Common::ReadReplacements(replacements); + Common::ReadReplacements(replacements); } CWII_IPC_HLE_Device_fs::~CWII_IPC_HLE_Device_fs() -{} +{ +} IPCCommandResult CWII_IPC_HLE_Device_fs::Open(u32 _CommandAddress, u32 _Mode) { - // clear tmp folder - { - std::string Path = HLE_IPC_BuildFilename("/tmp"); - File::DeleteDirRecursively(Path); - File::CreateDir(Path); - } + // clear tmp folder + { + std::string Path = HLE_IPC_BuildFilename("/tmp"); + File::DeleteDirRecursively(Path); + File::CreateDir(Path); + } - Memory::Write_U32(GetDeviceID(), _CommandAddress+4); - m_Active = true; - return GetFSReply(); + Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); + m_Active = true; + return GetFSReply(); } IPCCommandResult CWII_IPC_HLE_Device_fs::Close(u32 _CommandAddress, bool _bForce) { - INFO_LOG(WII_IPC_FILEIO, "Close"); - if (!_bForce) - Memory::Write_U32(0, _CommandAddress + 4); - m_Active = false; - return GetFSReply(); + INFO_LOG(WII_IPC_FILEIO, "Close"); + if (!_bForce) + Memory::Write_U32(0, _CommandAddress + 4); + m_Active = false; + return GetFSReply(); } // Get total filesize of contents of a directory (recursive) // Only used for ES_GetUsage atm, could be useful elsewhere? static u64 ComputeTotalFileSize(const File::FSTEntry& parentEntry) { - u64 sizeOfFiles = 0; - for (const File::FSTEntry& entry : parentEntry.children) - { - if (entry.isDirectory) - sizeOfFiles += ComputeTotalFileSize(entry); - else - sizeOfFiles += entry.size; - } - return sizeOfFiles; + u64 sizeOfFiles = 0; + for (const File::FSTEntry& entry : parentEntry.children) + { + if (entry.isDirectory) + sizeOfFiles += ComputeTotalFileSize(entry); + else + sizeOfFiles += entry.size; + } + return sizeOfFiles; } IPCCommandResult CWII_IPC_HLE_Device_fs::IOCtlV(u32 _CommandAddress) { - u32 ReturnValue = FS_RESULT_OK; - SIOCtlVBuffer CommandBuffer(_CommandAddress); + u32 ReturnValue = FS_RESULT_OK; + SIOCtlVBuffer CommandBuffer(_CommandAddress); - // Prepare the out buffer(s) with zeros as a safety precaution - // to avoid returning bad values - for (u32 i = 0; i < CommandBuffer.NumberPayloadBuffer; i++) - { - Memory::Memset(CommandBuffer.PayloadBuffer[i].m_Address, 0, - CommandBuffer.PayloadBuffer[i].m_Size); - } + // Prepare the out buffer(s) with zeros as a safety precaution + // to avoid returning bad values + for (u32 i = 0; i < CommandBuffer.NumberPayloadBuffer; i++) + { + Memory::Memset(CommandBuffer.PayloadBuffer[i].m_Address, 0, + CommandBuffer.PayloadBuffer[i].m_Size); + } - switch (CommandBuffer.Parameter) - { - case IOCTLV_READ_DIR: - { - // the Wii uses this function to define the type (dir or file) - std::string DirName(HLE_IPC_BuildFilename(Memory::GetString( - CommandBuffer.InBuffer[0].m_Address, CommandBuffer.InBuffer[0].m_Size))); + switch (CommandBuffer.Parameter) + { + case IOCTLV_READ_DIR: + { + // the Wii uses this function to define the type (dir or file) + std::string DirName(HLE_IPC_BuildFilename( + Memory::GetString(CommandBuffer.InBuffer[0].m_Address, CommandBuffer.InBuffer[0].m_Size))); - INFO_LOG(WII_IPC_FILEIO, "FS: IOCTL_READ_DIR %s", DirName.c_str()); + INFO_LOG(WII_IPC_FILEIO, "FS: IOCTL_READ_DIR %s", DirName.c_str()); - if (!File::Exists(DirName)) - { - WARN_LOG(WII_IPC_FILEIO, "FS: Search not found: %s", DirName.c_str()); - ReturnValue = FS_FILE_NOT_EXIST; - break; - } - else if (!File::IsDirectory(DirName)) - { - // It's not a directory, so error. - // Games don't usually seem to care WHICH error they get, as long as it's < - // Well the system menu CARES! - WARN_LOG(WII_IPC_FILEIO, "\tNot a directory - return FS_RESULT_FATAL"); - ReturnValue = FS_RESULT_FATAL; - break; - } + if (!File::Exists(DirName)) + { + WARN_LOG(WII_IPC_FILEIO, "FS: Search not found: %s", DirName.c_str()); + ReturnValue = FS_FILE_NOT_EXIST; + break; + } + else if (!File::IsDirectory(DirName)) + { + // It's not a directory, so error. + // Games don't usually seem to care WHICH error they get, as long as it's < + // Well the system menu CARES! + WARN_LOG(WII_IPC_FILEIO, "\tNot a directory - return FS_RESULT_FATAL"); + ReturnValue = FS_RESULT_FATAL; + break; + } - File::FSTEntry entry = File::ScanDirectoryTree(DirName, false); + File::FSTEntry entry = File::ScanDirectoryTree(DirName, false); - // it is one - if ((CommandBuffer.InBuffer.size() == 1) && (CommandBuffer.PayloadBuffer.size() == 1)) - { - size_t numFile = entry.children.size(); - INFO_LOG(WII_IPC_FILEIO, "\t%zu files found", numFile); + // it is one + if ((CommandBuffer.InBuffer.size() == 1) && (CommandBuffer.PayloadBuffer.size() == 1)) + { + size_t numFile = entry.children.size(); + INFO_LOG(WII_IPC_FILEIO, "\t%zu files found", numFile); - Memory::Write_U32((u32)numFile, CommandBuffer.PayloadBuffer[0].m_Address); - } - else - { - for (File::FSTEntry& child : entry.children) - { - // Decode entities of invalid file system characters so that - // games (such as HP:HBP) will be able to find what they expect. - for (const Common::replace_t& r : replacements) - child.virtualName = ReplaceAll(child.virtualName, r.second, {r.first}); - } + Memory::Write_U32((u32)numFile, CommandBuffer.PayloadBuffer[0].m_Address); + } + else + { + for (File::FSTEntry& child : entry.children) + { + // Decode entities of invalid file system characters so that + // games (such as HP:HBP) will be able to find what they expect. + for (const Common::replace_t& r : replacements) + child.virtualName = ReplaceAll(child.virtualName, r.second, {r.first}); + } - std::sort(entry.children.begin(), entry.children.end(), [](const File::FSTEntry& one, const File::FSTEntry& two) { return one.virtualName < two.virtualName; }); + std::sort(entry.children.begin(), entry.children.end(), + [](const File::FSTEntry& one, const File::FSTEntry& two) { + return one.virtualName < two.virtualName; + }); - u32 MaxEntries = Memory::Read_U32(CommandBuffer.InBuffer[0].m_Address); + u32 MaxEntries = Memory::Read_U32(CommandBuffer.InBuffer[0].m_Address); - memset(Memory::GetPointer(CommandBuffer.PayloadBuffer[0].m_Address), 0, CommandBuffer.PayloadBuffer[0].m_Size); + memset(Memory::GetPointer(CommandBuffer.PayloadBuffer[0].m_Address), 0, + CommandBuffer.PayloadBuffer[0].m_Size); - size_t numFiles = 0; - char* pFilename = (char*)Memory::GetPointer((u32)(CommandBuffer.PayloadBuffer[0].m_Address)); + size_t numFiles = 0; + char* pFilename = (char*)Memory::GetPointer((u32)(CommandBuffer.PayloadBuffer[0].m_Address)); - for (size_t i=0; i < entry.children.size() && i < MaxEntries; i++) - { - const std::string& FileName = entry.children[i].virtualName; + for (size_t i = 0; i < entry.children.size() && i < MaxEntries; i++) + { + const std::string& FileName = entry.children[i].virtualName; + strcpy(pFilename, FileName.c_str()); + pFilename += FileName.length(); + *pFilename++ = 0x00; // termination + numFiles++; - strcpy(pFilename, FileName.c_str()); - pFilename += FileName.length(); - *pFilename++ = 0x00; // termination - numFiles++; + INFO_LOG(WII_IPC_FILEIO, "\tFound: %s", FileName.c_str()); + } - INFO_LOG(WII_IPC_FILEIO, "\tFound: %s", FileName.c_str()); - } + Memory::Write_U32((u32)numFiles, CommandBuffer.PayloadBuffer[1].m_Address); + } - Memory::Write_U32((u32)numFiles, CommandBuffer.PayloadBuffer[1].m_Address); - } + ReturnValue = FS_RESULT_OK; + } + break; - ReturnValue = FS_RESULT_OK; - } - break; + case IOCTLV_GETUSAGE: + { + _dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer.size() == 2); + _dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer[0].m_Size == 4); + _dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer[1].m_Size == 4); - case IOCTLV_GETUSAGE: - { - _dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer.size() == 2); - _dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer[0].m_Size == 4); - _dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer[1].m_Size == 4); + // this command sucks because it asks of the number of used + // fsBlocks and inodes + // It should be correct, but don't count on it... + std::string relativepath = + Memory::GetString(CommandBuffer.InBuffer[0].m_Address, CommandBuffer.InBuffer[0].m_Size); + std::string path(HLE_IPC_BuildFilename(relativepath)); + u32 fsBlocks = 0; + u32 iNodes = 0; - // this command sucks because it asks of the number of used - // fsBlocks and inodes - // It should be correct, but don't count on it... - std::string relativepath = Memory::GetString(CommandBuffer.InBuffer[0].m_Address, CommandBuffer.InBuffer[0].m_Size); - std::string path(HLE_IPC_BuildFilename(relativepath)); - u32 fsBlocks = 0; - u32 iNodes = 0; + INFO_LOG(WII_IPC_FILEIO, "IOCTL_GETUSAGE %s", path.c_str()); + if (File::IsDirectory(path)) + { + // LPFaint99: After I found that setting the number of inodes to the number of children + 1 + // for the directory itself + // I decided to compare with sneek which has the following 2 special cases which are + // Copyright (C) 2009-2011 crediar http://code.google.com/p/sneek/ + if ((relativepath.compare(0, 16, "/title/00010001") == 0) || + (relativepath.compare(0, 16, "/title/00010005") == 0)) + { + fsBlocks = 23; // size is size/0x4000 + iNodes = 42; // empty folders return a FileCount of 1 + } + else + { + File::FSTEntry parentDir = File::ScanDirectoryTree(path, true); + // add one for the folder itself + iNodes = 1 + (u32)parentDir.size; - INFO_LOG(WII_IPC_FILEIO, "IOCTL_GETUSAGE %s", path.c_str()); - if (File::IsDirectory(path)) - { - // LPFaint99: After I found that setting the number of inodes to the number of children + 1 for the directory itself - // I decided to compare with sneek which has the following 2 special cases which are - // Copyright (C) 2009-2011 crediar http://code.google.com/p/sneek/ - if ((relativepath.compare(0, 16, "/title/00010001") == 0 ) || - (relativepath.compare(0, 16, "/title/00010005") == 0 )) - { - fsBlocks = 23; // size is size/0x4000 - iNodes = 42; // empty folders return a FileCount of 1 - } - else - { - File::FSTEntry parentDir = File::ScanDirectoryTree(path, true); - // add one for the folder itself - iNodes = 1 + (u32)parentDir.size; + u64 totalSize = + ComputeTotalFileSize(parentDir); // "Real" size, to be converted to nand blocks - u64 totalSize = ComputeTotalFileSize(parentDir); // "Real" size, to be converted to nand blocks + fsBlocks = (u32)(totalSize / (16 * 1024)); // one bock is 16kb + } + ReturnValue = FS_RESULT_OK; - fsBlocks = (u32)(totalSize / (16 * 1024)); // one bock is 16kb - } - ReturnValue = FS_RESULT_OK; + INFO_LOG(WII_IPC_FILEIO, "FS: fsBlock: %i, iNodes: %i", fsBlocks, iNodes); + } + else + { + fsBlocks = 0; + iNodes = 0; + ReturnValue = FS_RESULT_OK; + WARN_LOG(WII_IPC_FILEIO, "FS: fsBlock failed, cannot find directory: %s", path.c_str()); + } - INFO_LOG(WII_IPC_FILEIO, "FS: fsBlock: %i, iNodes: %i", fsBlocks, iNodes); - } - else - { - fsBlocks = 0; - iNodes = 0; - ReturnValue = FS_RESULT_OK; - WARN_LOG(WII_IPC_FILEIO, "FS: fsBlock failed, cannot find directory: %s", path.c_str()); - } + Memory::Write_U32(fsBlocks, CommandBuffer.PayloadBuffer[0].m_Address); + Memory::Write_U32(iNodes, CommandBuffer.PayloadBuffer[1].m_Address); + } + break; - Memory::Write_U32(fsBlocks, CommandBuffer.PayloadBuffer[0].m_Address); - Memory::Write_U32(iNodes, CommandBuffer.PayloadBuffer[1].m_Address); - } - break; + default: + PanicAlert("CWII_IPC_HLE_Device_fs::IOCtlV: %i", CommandBuffer.Parameter); + break; + } + Memory::Write_U32(ReturnValue, _CommandAddress + 4); - default: - PanicAlert("CWII_IPC_HLE_Device_fs::IOCtlV: %i", CommandBuffer.Parameter); - break; - } - - Memory::Write_U32(ReturnValue, _CommandAddress+4); - - return GetFSReply(); + return GetFSReply(); } IPCCommandResult CWII_IPC_HLE_Device_fs::IOCtl(u32 _CommandAddress) { - //u32 DeviceID = Memory::Read_U32(_CommandAddress + 8); + // u32 DeviceID = Memory::Read_U32(_CommandAddress + 8); - u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); - u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); - u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); - u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); + u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); + u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); + u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); + u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); + u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); - /* Prepare the out buffer(s) with zeroes as a safety precaution - to avoid returning bad values. */ - //LOG(WII_IPC_FILEIO, "Cleared %u bytes of the out buffer", _BufferOutSize); - Memory::Memset(BufferOut, 0, BufferOutSize); + /* Prepare the out buffer(s) with zeroes as a safety precaution + to avoid returning bad values. */ + // LOG(WII_IPC_FILEIO, "Cleared %u bytes of the out buffer", _BufferOutSize); + Memory::Memset(BufferOut, 0, BufferOutSize); - u32 ReturnValue = ExecuteCommand(Parameter, BufferIn, BufferInSize, BufferOut, BufferOutSize); - Memory::Write_U32(ReturnValue, _CommandAddress + 4); + u32 ReturnValue = ExecuteCommand(Parameter, BufferIn, BufferInSize, BufferOut, BufferOutSize); + Memory::Write_U32(ReturnValue, _CommandAddress + 4); - return GetFSReply(); + return GetFSReply(); } -s32 CWII_IPC_HLE_Device_fs::ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, u32 _BufferOutSize) +s32 CWII_IPC_HLE_Device_fs::ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _BufferInSize, + u32 _BufferOut, u32 _BufferOutSize) { - switch (_Parameter) - { - case IOCTL_GET_STATS: - { - if (_BufferOutSize < 0x1c) - return -1017; + switch (_Parameter) + { + case IOCTL_GET_STATS: + { + if (_BufferOutSize < 0x1c) + return -1017; - WARN_LOG(WII_IPC_FILEIO, "FS: GET STATS - returning static values for now"); + WARN_LOG(WII_IPC_FILEIO, "FS: GET STATS - returning static values for now"); - NANDStat fs; + NANDStat fs; - //TODO: scrape the real amounts from somewhere... - fs.BlockSize = 0x4000; - fs.FreeUserBlocks = 0x5DEC; - fs.UsedUserBlocks = 0x1DD4; - fs.FreeSysBlocks = 0x10; - fs.UsedSysBlocks = 0x02F0; - fs.Free_INodes = 0x146B; - fs.Used_Inodes = 0x0394; + // TODO: scrape the real amounts from somewhere... + fs.BlockSize = 0x4000; + fs.FreeUserBlocks = 0x5DEC; + fs.UsedUserBlocks = 0x1DD4; + fs.FreeSysBlocks = 0x10; + fs.UsedSysBlocks = 0x02F0; + fs.Free_INodes = 0x146B; + fs.Used_Inodes = 0x0394; - std::memcpy(Memory::GetPointer(_BufferOut), &fs, sizeof(NANDStat)); + std::memcpy(Memory::GetPointer(_BufferOut), &fs, sizeof(NANDStat)); - return FS_RESULT_OK; - } - break; + return FS_RESULT_OK; + } + break; - case IOCTL_CREATE_DIR: - { - _dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0); - u32 Addr = _BufferIn; + case IOCTL_CREATE_DIR: + { + _dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0); + u32 Addr = _BufferIn; - u32 OwnerID = Memory::Read_U32(Addr); Addr += 4; - u16 GroupID = Memory::Read_U16(Addr); Addr += 2; - std::string DirName(HLE_IPC_BuildFilename(Memory::GetString(Addr, 64))); Addr += 64; - Addr += 9; // owner attribs, permission - u8 Attribs = Memory::Read_U8(Addr); + u32 OwnerID = Memory::Read_U32(Addr); + Addr += 4; + u16 GroupID = Memory::Read_U16(Addr); + Addr += 2; + std::string DirName(HLE_IPC_BuildFilename(Memory::GetString(Addr, 64))); + Addr += 64; + Addr += 9; // owner attribs, permission + u8 Attribs = Memory::Read_U8(Addr); - INFO_LOG(WII_IPC_FILEIO, "FS: CREATE_DIR %s, OwnerID %#x, GroupID %#x, Attributes %#x", DirName.c_str(), OwnerID, GroupID, Attribs); + INFO_LOG(WII_IPC_FILEIO, "FS: CREATE_DIR %s, OwnerID %#x, GroupID %#x, Attributes %#x", + DirName.c_str(), OwnerID, GroupID, Attribs); - DirName += DIR_SEP; - File::CreateFullPath(DirName); - _dbg_assert_msg_(WII_IPC_FILEIO, File::IsDirectory(DirName), "FS: CREATE_DIR %s failed", DirName.c_str()); + DirName += DIR_SEP; + File::CreateFullPath(DirName); + _dbg_assert_msg_(WII_IPC_FILEIO, File::IsDirectory(DirName), "FS: CREATE_DIR %s failed", + DirName.c_str()); - return FS_RESULT_OK; - } - break; + return FS_RESULT_OK; + } + break; - case IOCTL_SET_ATTR: - { - u32 Addr = _BufferIn; + case IOCTL_SET_ATTR: + { + u32 Addr = _BufferIn; - u32 OwnerID = Memory::Read_U32(Addr); Addr += 4; - u16 GroupID = Memory::Read_U16(Addr); Addr += 2; - std::string Filename = HLE_IPC_BuildFilename(Memory::GetString(_BufferIn, 64)); Addr += 64; - u8 OwnerPerm = Memory::Read_U8(Addr); Addr += 1; - u8 GroupPerm = Memory::Read_U8(Addr); Addr += 1; - u8 OtherPerm = Memory::Read_U8(Addr); Addr += 1; - u8 Attributes = Memory::Read_U8(Addr); Addr += 1; + u32 OwnerID = Memory::Read_U32(Addr); + Addr += 4; + u16 GroupID = Memory::Read_U16(Addr); + Addr += 2; + std::string Filename = HLE_IPC_BuildFilename(Memory::GetString(_BufferIn, 64)); + Addr += 64; + u8 OwnerPerm = Memory::Read_U8(Addr); + Addr += 1; + u8 GroupPerm = Memory::Read_U8(Addr); + Addr += 1; + u8 OtherPerm = Memory::Read_U8(Addr); + Addr += 1; + u8 Attributes = Memory::Read_U8(Addr); + Addr += 1; - INFO_LOG(WII_IPC_FILEIO, "FS: SetAttrib %s", Filename.c_str()); - DEBUG_LOG(WII_IPC_FILEIO, " OwnerID: 0x%08x", OwnerID); - DEBUG_LOG(WII_IPC_FILEIO, " GroupID: 0x%04x", GroupID); - DEBUG_LOG(WII_IPC_FILEIO, " OwnerPerm: 0x%02x", OwnerPerm); - DEBUG_LOG(WII_IPC_FILEIO, " GroupPerm: 0x%02x", GroupPerm); - DEBUG_LOG(WII_IPC_FILEIO, " OtherPerm: 0x%02x", OtherPerm); - DEBUG_LOG(WII_IPC_FILEIO, " Attributes: 0x%02x", Attributes); + INFO_LOG(WII_IPC_FILEIO, "FS: SetAttrib %s", Filename.c_str()); + DEBUG_LOG(WII_IPC_FILEIO, " OwnerID: 0x%08x", OwnerID); + DEBUG_LOG(WII_IPC_FILEIO, " GroupID: 0x%04x", GroupID); + DEBUG_LOG(WII_IPC_FILEIO, " OwnerPerm: 0x%02x", OwnerPerm); + DEBUG_LOG(WII_IPC_FILEIO, " GroupPerm: 0x%02x", GroupPerm); + DEBUG_LOG(WII_IPC_FILEIO, " OtherPerm: 0x%02x", OtherPerm); + DEBUG_LOG(WII_IPC_FILEIO, " Attributes: 0x%02x", Attributes); - return FS_RESULT_OK; - } - break; + return FS_RESULT_OK; + } + break; - case IOCTL_GET_ATTR: - { - _dbg_assert_msg_(WII_IPC_FILEIO, _BufferOutSize == 76, - " GET_ATTR needs an 76 bytes large output buffer but it is %i bytes large", - _BufferOutSize); + case IOCTL_GET_ATTR: + { + _dbg_assert_msg_(WII_IPC_FILEIO, _BufferOutSize == 76, + " GET_ATTR needs an 76 bytes large output buffer but it is %i bytes large", + _BufferOutSize); - u32 OwnerID = 0; - u16 GroupID = 0x3031; // this is also known as makercd, 01 (0x3031) for nintendo and 08 (0x3038) for MH3 etc - std::string Filename = HLE_IPC_BuildFilename(Memory::GetString(_BufferIn, 64)); - u8 OwnerPerm = 0x3; // read/write - u8 GroupPerm = 0x3; // read/write - u8 OtherPerm = 0x3; // read/write - u8 Attributes = 0x00; // no attributes - if (File::IsDirectory(Filename)) - { - INFO_LOG(WII_IPC_FILEIO, "FS: GET_ATTR Directory %s - all permission flags are set", Filename.c_str()); - } - else - { - if (File::Exists(Filename)) - { - INFO_LOG(WII_IPC_FILEIO, "FS: GET_ATTR %s - all permission flags are set", Filename.c_str()); - } - else - { - INFO_LOG(WII_IPC_FILEIO, "FS: GET_ATTR unknown %s", Filename.c_str()); - return FS_FILE_NOT_EXIST; - } - } + u32 OwnerID = 0; + u16 GroupID = 0x3031; // this is also known as makercd, 01 (0x3031) for nintendo and 08 + // (0x3038) for MH3 etc + std::string Filename = HLE_IPC_BuildFilename(Memory::GetString(_BufferIn, 64)); + u8 OwnerPerm = 0x3; // read/write + u8 GroupPerm = 0x3; // read/write + u8 OtherPerm = 0x3; // read/write + u8 Attributes = 0x00; // no attributes + if (File::IsDirectory(Filename)) + { + INFO_LOG(WII_IPC_FILEIO, "FS: GET_ATTR Directory %s - all permission flags are set", + Filename.c_str()); + } + else + { + if (File::Exists(Filename)) + { + INFO_LOG(WII_IPC_FILEIO, "FS: GET_ATTR %s - all permission flags are set", + Filename.c_str()); + } + else + { + INFO_LOG(WII_IPC_FILEIO, "FS: GET_ATTR unknown %s", Filename.c_str()); + return FS_FILE_NOT_EXIST; + } + } - // write answer to buffer - if (_BufferOutSize == 76) - { - u32 Addr = _BufferOut; - Memory::Write_U32(OwnerID, Addr); Addr += 4; - Memory::Write_U16(GroupID, Addr); Addr += 2; - memcpy(Memory::GetPointer(Addr), Memory::GetPointer(_BufferIn), 64); Addr += 64; - Memory::Write_U8(OwnerPerm, Addr); Addr += 1; - Memory::Write_U8(GroupPerm, Addr); Addr += 1; - Memory::Write_U8(OtherPerm, Addr); Addr += 1; - Memory::Write_U8(Attributes, Addr); Addr += 1; - } + // write answer to buffer + if (_BufferOutSize == 76) + { + u32 Addr = _BufferOut; + Memory::Write_U32(OwnerID, Addr); + Addr += 4; + Memory::Write_U16(GroupID, Addr); + Addr += 2; + memcpy(Memory::GetPointer(Addr), Memory::GetPointer(_BufferIn), 64); + Addr += 64; + Memory::Write_U8(OwnerPerm, Addr); + Addr += 1; + Memory::Write_U8(GroupPerm, Addr); + Addr += 1; + Memory::Write_U8(OtherPerm, Addr); + Addr += 1; + Memory::Write_U8(Attributes, Addr); + Addr += 1; + } - return FS_RESULT_OK; - } - break; + return FS_RESULT_OK; + } + break; + case IOCTL_DELETE_FILE: + { + _dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0); + int Offset = 0; - case IOCTL_DELETE_FILE: - { - _dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0); - int Offset = 0; + std::string Filename = HLE_IPC_BuildFilename(Memory::GetString(_BufferIn + Offset, 64)); + Offset += 64; + if (File::Delete(Filename)) + { + INFO_LOG(WII_IPC_FILEIO, "FS: DeleteFile %s", Filename.c_str()); + } + else if (File::DeleteDir(Filename)) + { + INFO_LOG(WII_IPC_FILEIO, "FS: DeleteDir %s", Filename.c_str()); + } + else + { + WARN_LOG(WII_IPC_FILEIO, "FS: DeleteFile %s - failed!!!", Filename.c_str()); + } - std::string Filename = HLE_IPC_BuildFilename(Memory::GetString(_BufferIn+Offset, 64)); - Offset += 64; - if (File::Delete(Filename)) - { - INFO_LOG(WII_IPC_FILEIO, "FS: DeleteFile %s", Filename.c_str()); - } - else if (File::DeleteDir(Filename)) - { - INFO_LOG(WII_IPC_FILEIO, "FS: DeleteDir %s", Filename.c_str()); - } - else - { - WARN_LOG(WII_IPC_FILEIO, "FS: DeleteFile %s - failed!!!", Filename.c_str()); - } + return FS_RESULT_OK; + } + break; - return FS_RESULT_OK; - } - break; + case IOCTL_RENAME_FILE: + { + _dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0); + int Offset = 0; - case IOCTL_RENAME_FILE: - { - _dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0); - int Offset = 0; + std::string Filename = HLE_IPC_BuildFilename(Memory::GetString(_BufferIn + Offset, 64)); + Offset += 64; - std::string Filename = HLE_IPC_BuildFilename(Memory::GetString(_BufferIn+Offset, 64)); - Offset += 64; + std::string FilenameRename = HLE_IPC_BuildFilename(Memory::GetString(_BufferIn + Offset, 64)); + Offset += 64; - std::string FilenameRename = HLE_IPC_BuildFilename(Memory::GetString(_BufferIn+Offset, 64)); - Offset += 64; + // try to make the basis directory + File::CreateFullPath(FilenameRename); - // try to make the basis directory - File::CreateFullPath(FilenameRename); + // if there is already a file, delete it + if (File::Exists(Filename) && File::Exists(FilenameRename)) + { + File::Delete(FilenameRename); + } - // if there is already a file, delete it - if (File::Exists(Filename) && File::Exists(FilenameRename)) - { - File::Delete(FilenameRename); - } + // finally try to rename the file + if (File::Rename(Filename, FilenameRename)) + { + INFO_LOG(WII_IPC_FILEIO, "FS: Rename %s to %s", Filename.c_str(), FilenameRename.c_str()); + } + else + { + ERROR_LOG(WII_IPC_FILEIO, "FS: Rename %s to %s - failed", Filename.c_str(), + FilenameRename.c_str()); + return FS_FILE_NOT_EXIST; + } - // finally try to rename the file - if (File::Rename(Filename, FilenameRename)) - { - INFO_LOG(WII_IPC_FILEIO, "FS: Rename %s to %s", Filename.c_str(), FilenameRename.c_str()); - } - else - { - ERROR_LOG(WII_IPC_FILEIO, "FS: Rename %s to %s - failed", Filename.c_str(), FilenameRename.c_str()); - return FS_FILE_NOT_EXIST; - } + return FS_RESULT_OK; + } + break; - return FS_RESULT_OK; - } - break; + case IOCTL_CREATE_FILE: + { + _dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0); - case IOCTL_CREATE_FILE: - { - _dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0); + u32 Addr = _BufferIn; + u32 OwnerID = Memory::Read_U32(Addr); + Addr += 4; + u16 GroupID = Memory::Read_U16(Addr); + Addr += 2; + std::string Filename(HLE_IPC_BuildFilename(Memory::GetString(Addr, 64))); + Addr += 64; + u8 OwnerPerm = Memory::Read_U8(Addr); + Addr++; + u8 GroupPerm = Memory::Read_U8(Addr); + Addr++; + u8 OtherPerm = Memory::Read_U8(Addr); + Addr++; + u8 Attributes = Memory::Read_U8(Addr); + Addr++; - u32 Addr = _BufferIn; - u32 OwnerID = Memory::Read_U32(Addr); Addr += 4; - u16 GroupID = Memory::Read_U16(Addr); Addr += 2; - std::string Filename(HLE_IPC_BuildFilename(Memory::GetString(Addr, 64))); Addr += 64; - u8 OwnerPerm = Memory::Read_U8(Addr); Addr++; - u8 GroupPerm = Memory::Read_U8(Addr); Addr++; - u8 OtherPerm = Memory::Read_U8(Addr); Addr++; - u8 Attributes = Memory::Read_U8(Addr); Addr++; + INFO_LOG(WII_IPC_FILEIO, "FS: CreateFile %s", Filename.c_str()); + DEBUG_LOG(WII_IPC_FILEIO, " OwnerID: 0x%08x", OwnerID); + DEBUG_LOG(WII_IPC_FILEIO, " GroupID: 0x%04x", GroupID); + DEBUG_LOG(WII_IPC_FILEIO, " OwnerPerm: 0x%02x", OwnerPerm); + DEBUG_LOG(WII_IPC_FILEIO, " GroupPerm: 0x%02x", GroupPerm); + DEBUG_LOG(WII_IPC_FILEIO, " OtherPerm: 0x%02x", OtherPerm); + DEBUG_LOG(WII_IPC_FILEIO, " Attributes: 0x%02x", Attributes); - INFO_LOG(WII_IPC_FILEIO, "FS: CreateFile %s", Filename.c_str()); - DEBUG_LOG(WII_IPC_FILEIO, " OwnerID: 0x%08x", OwnerID); - DEBUG_LOG(WII_IPC_FILEIO, " GroupID: 0x%04x", GroupID); - DEBUG_LOG(WII_IPC_FILEIO, " OwnerPerm: 0x%02x", OwnerPerm); - DEBUG_LOG(WII_IPC_FILEIO, " GroupPerm: 0x%02x", GroupPerm); - DEBUG_LOG(WII_IPC_FILEIO, " OtherPerm: 0x%02x", OtherPerm); - DEBUG_LOG(WII_IPC_FILEIO, " Attributes: 0x%02x", Attributes); + // check if the file already exist + if (File::Exists(Filename)) + { + WARN_LOG(WII_IPC_FILEIO, "\tresult = FS_RESULT_EXISTS"); + return FS_FILE_EXIST; + } - // check if the file already exist - if (File::Exists(Filename)) - { - WARN_LOG(WII_IPC_FILEIO, "\tresult = FS_RESULT_EXISTS"); - return FS_FILE_EXIST; - } + // create the file + File::CreateFullPath(Filename); // just to be sure + bool Result = File::CreateEmptyFile(Filename); + if (!Result) + { + ERROR_LOG(WII_IPC_FILEIO, "CWII_IPC_HLE_Device_fs: couldn't create new file"); + PanicAlert("CWII_IPC_HLE_Device_fs: couldn't create new file"); + return FS_RESULT_FATAL; + } - // create the file - File::CreateFullPath(Filename); // just to be sure - bool Result = File::CreateEmptyFile(Filename); - if (!Result) - { - ERROR_LOG(WII_IPC_FILEIO, "CWII_IPC_HLE_Device_fs: couldn't create new file"); - PanicAlert("CWII_IPC_HLE_Device_fs: couldn't create new file"); - return FS_RESULT_FATAL; - } + INFO_LOG(WII_IPC_FILEIO, "\tresult = FS_RESULT_OK"); + return FS_RESULT_OK; + } + break; + case IOCTL_SHUTDOWN: + { + INFO_LOG(WII_IPC_FILEIO, "Wii called Shutdown()"); + // TODO: stop emulation + } + break; + default: + ERROR_LOG(WII_IPC_FILEIO, "CWII_IPC_HLE_Device_fs::IOCtl: ni 0x%x", _Parameter); + PanicAlert("CWII_IPC_HLE_Device_fs::IOCtl: ni 0x%x", _Parameter); + break; + } - INFO_LOG(WII_IPC_FILEIO, "\tresult = FS_RESULT_OK"); - return FS_RESULT_OK; - } - break; - case IOCTL_SHUTDOWN: - { - INFO_LOG(WII_IPC_FILEIO, "Wii called Shutdown()"); - // TODO: stop emulation - } - break; - default: - ERROR_LOG(WII_IPC_FILEIO, "CWII_IPC_HLE_Device_fs::IOCtl: ni 0x%x", _Parameter); - PanicAlert("CWII_IPC_HLE_Device_fs::IOCtl: ni 0x%x", _Parameter); - break; - } - - return FS_RESULT_FATAL; + return FS_RESULT_FATAL; } void CWII_IPC_HLE_Device_fs::DoState(PointerWrap& p) { - DoStateShared(p); + DoStateShared(p); - // handle /tmp + // handle /tmp - std::string Path = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/tmp"; - if (p.GetMode() == PointerWrap::MODE_READ) - { - File::DeleteDirRecursively(Path); - File::CreateDir(Path); + std::string Path = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/tmp"; + if (p.GetMode() == PointerWrap::MODE_READ) + { + File::DeleteDirRecursively(Path); + File::CreateDir(Path); - //now restore from the stream - while (1) - { - char type = 0; - p.Do(type); - if (!type) - break; - std::string filename; - p.Do(filename); - std::string name = Path + DIR_SEP + filename; - switch (type) - { - case 'd': - { - File::CreateDir(name); - break; - } - case 'f': - { - u32 size = 0; - p.Do(size); + // now restore from the stream + while (1) + { + char type = 0; + p.Do(type); + if (!type) + break; + std::string filename; + p.Do(filename); + std::string name = Path + DIR_SEP + filename; + switch (type) + { + case 'd': + { + File::CreateDir(name); + break; + } + case 'f': + { + u32 size = 0; + p.Do(size); - File::IOFile handle(name, "wb"); - char buf[65536]; - u32 count = size; - while (count > 65536) - { - p.DoArray(buf); - handle.WriteArray(&buf[0], 65536); - count -= 65536; - } - p.DoArray(&buf[0], count); - handle.WriteArray(&buf[0], count); - break; - } - } - } - } - else - { - //recurse through tmp and save dirs and files + File::IOFile handle(name, "wb"); + char buf[65536]; + u32 count = size; + while (count > 65536) + { + p.DoArray(buf); + handle.WriteArray(&buf[0], 65536); + count -= 65536; + } + p.DoArray(&buf[0], count); + handle.WriteArray(&buf[0], count); + break; + } + } + } + } + else + { + // recurse through tmp and save dirs and files - File::FSTEntry parentEntry = File::ScanDirectoryTree(Path, true); - std::deque todo; - todo.insert(todo.end(), parentEntry.children.begin(), - parentEntry.children.end()); + File::FSTEntry parentEntry = File::ScanDirectoryTree(Path, true); + std::deque todo; + todo.insert(todo.end(), parentEntry.children.begin(), parentEntry.children.end()); - while (!todo.empty()) - { - File::FSTEntry &entry = todo.front(); - std::string name = entry.physicalName; - name.erase(0,Path.length()+1); - char type = entry.isDirectory?'d':'f'; - p.Do(type); - p.Do(name); - if (entry.isDirectory) - { - todo.insert(todo.end(), entry.children.begin(), - entry.children.end()); - } - else - { - u32 size = (u32)entry.size; - p.Do(size); + while (!todo.empty()) + { + File::FSTEntry& entry = todo.front(); + std::string name = entry.physicalName; + name.erase(0, Path.length() + 1); + char type = entry.isDirectory ? 'd' : 'f'; + p.Do(type); + p.Do(name); + if (entry.isDirectory) + { + todo.insert(todo.end(), entry.children.begin(), entry.children.end()); + } + else + { + u32 size = (u32)entry.size; + p.Do(size); - File::IOFile handle(entry.physicalName, "rb"); - char buf[65536]; - u32 count = size; - while (count > 65536) - { - handle.ReadArray(&buf[0], 65536); - p.DoArray(buf); - count -= 65536; - } - handle.ReadArray(&buf[0], count); - p.DoArray(&buf[0], count); - } - todo.pop_front(); - } + File::IOFile handle(entry.physicalName, "rb"); + char buf[65536]; + u32 count = size; + while (count > 65536) + { + handle.ReadArray(&buf[0], 65536); + p.DoArray(buf); + count -= 65536; + } + handle.ReadArray(&buf[0], count); + p.DoArray(&buf[0], count); + } + todo.pop_front(); + } - char type = 0; - p.Do(type); - } + char type = 0; + p.Do(type); + } } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.h index 0b97bb8798..a18cc55b83 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_fs.h @@ -10,61 +10,59 @@ class PointerWrap; struct NANDStat { - u32 BlockSize; - u32 FreeUserBlocks; - u32 UsedUserBlocks; - u32 FreeSysBlocks; - u32 UsedSysBlocks; - u32 Free_INodes; - u32 Used_Inodes; + u32 BlockSize; + u32 FreeUserBlocks; + u32 UsedUserBlocks; + u32 FreeSysBlocks; + u32 UsedSysBlocks; + u32 Free_INodes; + u32 Used_Inodes; }; enum { - FS_RESULT_OK = 0, - FS_INVALID = -4, - FS_DIRFILE_NOT_FOUND = -6, - FS_RESULT_FATAL = -101, - FS_NO_ACCESS = -102, - FS_FILE_EXIST = -105, - FS_FILE_NOT_EXIST = -106, - FS_NO_HANDLE = -106, + FS_RESULT_OK = 0, + FS_INVALID = -4, + FS_DIRFILE_NOT_FOUND = -6, + FS_RESULT_FATAL = -101, + FS_NO_ACCESS = -102, + FS_FILE_EXIST = -105, + FS_FILE_NOT_EXIST = -106, + FS_NO_HANDLE = -106, }; class CWII_IPC_HLE_Device_fs : public IWII_IPC_HLE_Device { public: + CWII_IPC_HLE_Device_fs(u32 _DeviceID, const std::string& _rDeviceName); + virtual ~CWII_IPC_HLE_Device_fs(); - CWII_IPC_HLE_Device_fs(u32 _DeviceID, const std::string& _rDeviceName); - virtual ~CWII_IPC_HLE_Device_fs(); + void DoState(PointerWrap& p) override; - void DoState(PointerWrap& p) override; + IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; + IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; - IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; - IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; - - IPCCommandResult IOCtl(u32 _CommandAddress) override; - IPCCommandResult IOCtlV(u32 _CommandAddress) override; + IPCCommandResult IOCtl(u32 _CommandAddress) override; + IPCCommandResult IOCtlV(u32 _CommandAddress) override; private: + enum + { + IOCTL_GET_STATS = 0x02, + IOCTL_CREATE_DIR = 0x03, + IOCTLV_READ_DIR = 0x04, + IOCTL_SET_ATTR = 0x05, + IOCTL_GET_ATTR = 0x06, + IOCTL_DELETE_FILE = 0x07, + IOCTL_RENAME_FILE = 0x08, + IOCTL_CREATE_FILE = 0x09, + IOCTLV_GETUSAGE = 0x0C, + IOCTL_SHUTDOWN = 0x0D + }; - enum - { - IOCTL_GET_STATS = 0x02, - IOCTL_CREATE_DIR = 0x03, - IOCTLV_READ_DIR = 0x04, - IOCTL_SET_ATTR = 0x05, - IOCTL_GET_ATTR = 0x06, - IOCTL_DELETE_FILE = 0x07, - IOCTL_RENAME_FILE = 0x08, - IOCTL_CREATE_FILE = 0x09, - IOCTLV_GETUSAGE = 0x0C, - IOCTL_SHUTDOWN = 0x0D - }; - - // ~1/1000th of a second is too short and causes hangs in Wii Party - // Play it safe at 1/500th - IPCCommandResult GetFSReply() const { return { true, SystemTimers::GetTicksPerSecond() / 500 }; } - - s32 ExecuteCommand(u32 Parameter, u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, u32 _BufferOutSize); + // ~1/1000th of a second is too short and causes hangs in Wii Party + // Play it safe at 1/500th + IPCCommandResult GetFSReply() const { return {true, SystemTimers::GetTicksPerSecond() / 500}; } + s32 ExecuteCommand(u32 Parameter, u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, + u32 _BufferOutSize); }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_hid.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_hid.cpp index ee0201383a..4a57a03097 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_hid.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_hid.cpp @@ -18,634 +18,633 @@ static u64 hidDeviceAliases[MAX_DEVICE_DEVNUM]; // Regular thread void CWII_IPC_HLE_Device_hid::checkUsbUpdates(CWII_IPC_HLE_Device_hid* hid) { - timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 500; - while (hid->usb_thread_running) - { + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 500; + while (hid->usb_thread_running) + { + static u16 timeToFill = 0; + if (timeToFill == 0) + { + std::lock_guard lk(hid->m_device_list_reply_mutex); + if (hid->deviceCommandAddress != 0) + { + hid->FillOutDevices(Memory::Read_U32(hid->deviceCommandAddress + 0x18), + Memory::Read_U32(hid->deviceCommandAddress + 0x1C)); - static u16 timeToFill = 0; - if (timeToFill == 0) - { - std::lock_guard lk(hid->m_device_list_reply_mutex); - if (hid->deviceCommandAddress != 0) - { - hid->FillOutDevices(Memory::Read_U32(hid->deviceCommandAddress + 0x18), Memory::Read_U32(hid->deviceCommandAddress + 0x1C)); + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, hid->deviceCommandAddress); + // IOS also seems to write back the command that was responded to in the FD field. + Memory::Write_U32(IPC_CMD_IOCTL, hid->deviceCommandAddress + 8); - // The original hardware overwrites the command type with the async reply type. - Memory::Write_U32(IPC_REP_ASYNC, hid->deviceCommandAddress); - // IOS also seems to write back the command that was responded to in the FD field. - Memory::Write_U32(IPC_CMD_IOCTL, hid->deviceCommandAddress + 8); + // Return value + Memory::Write_U32(0, hid->deviceCommandAddress + 4); - // Return value - Memory::Write_U32(0, hid->deviceCommandAddress + 4); + WII_IPC_HLE_Interface::EnqueueReply_Threadsafe(hid->deviceCommandAddress); + hid->deviceCommandAddress = 0; + } + } + timeToFill += 8; + libusb_handle_events_timeout(nullptr, &tv); + } - WII_IPC_HLE_Interface::EnqueueReply_Threadsafe(hid->deviceCommandAddress); - hid->deviceCommandAddress = 0; - } - } - timeToFill += 8; - libusb_handle_events_timeout(nullptr, &tv); - } - - return; + return; } -void CWII_IPC_HLE_Device_hid::handleUsbUpdates(struct libusb_transfer *transfer) +void CWII_IPC_HLE_Device_hid::handleUsbUpdates(struct libusb_transfer* transfer) { - int ret = HIDERR_NO_DEVICE_FOUND; - u32 replyAddress = (u32)(size_t)transfer->user_data; - if (transfer->status == LIBUSB_TRANSFER_COMPLETED) - { - ret = transfer->length; - } + int ret = HIDERR_NO_DEVICE_FOUND; + u32 replyAddress = (u32)(size_t)transfer->user_data; + if (transfer->status == LIBUSB_TRANSFER_COMPLETED) + { + ret = transfer->length; + } - // The original hardware overwrites the command type with the async reply type. - Memory::Write_U32(IPC_REP_ASYNC, replyAddress); - // IOS also seems to write back the command that was responded to in the FD field. - Memory::Write_U32(IPC_CMD_IOCTL, replyAddress + 8); + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, replyAddress); + // IOS also seems to write back the command that was responded to in the FD field. + Memory::Write_U32(IPC_CMD_IOCTL, replyAddress + 8); - // Return value - Memory::Write_U32(ret, replyAddress + 4); + // Return value + Memory::Write_U32(ret, replyAddress + 4); - WII_IPC_HLE_Interface::EnqueueReply_Threadsafe(replyAddress); - //DEBUG_LOG(WII_IPC_HID, "OMG OMG OMG I GOT A CALLBACK, IMMA BE FAMOUS %d %d %d", transfer->actual_length, transfer->length, transfer->status); + WII_IPC_HLE_Interface::EnqueueReply_Threadsafe(replyAddress); + // DEBUG_LOG(WII_IPC_HID, "OMG OMG OMG I GOT A CALLBACK, IMMA BE FAMOUS %d %d %d", + // transfer->actual_length, transfer->length, transfer->status); } - CWII_IPC_HLE_Device_hid::CWII_IPC_HLE_Device_hid(u32 _DeviceID, const std::string& _rDeviceName) - : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) { - deviceCommandAddress = 0; - memset(hidDeviceAliases, 0, sizeof(hidDeviceAliases)); - int ret = libusb_init(nullptr); - if (ret) - { - ERROR_LOG(WII_IPC_HID, "libusb_init failed with error: %d", ret); - } - else - { - usb_thread_running = true; - usb_thread = std::thread(checkUsbUpdates, this); - } + deviceCommandAddress = 0; + memset(hidDeviceAliases, 0, sizeof(hidDeviceAliases)); + int ret = libusb_init(nullptr); + if (ret) + { + ERROR_LOG(WII_IPC_HID, "libusb_init failed with error: %d", ret); + } + else + { + usb_thread_running = true; + usb_thread = std::thread(checkUsbUpdates, this); + } } CWII_IPC_HLE_Device_hid::~CWII_IPC_HLE_Device_hid() { - bool deinit_libusb = false; - if (usb_thread_running) - { - usb_thread_running = false; - usb_thread.join(); - deinit_libusb = true; - } + bool deinit_libusb = false; + if (usb_thread_running) + { + usb_thread_running = false; + usb_thread.join(); + deinit_libusb = true; + } - for (const auto& device : m_open_devices) - { - libusb_close(device.second); - } - m_open_devices.clear(); + for (const auto& device : m_open_devices) + { + libusb_close(device.second); + } + m_open_devices.clear(); - if (deinit_libusb) - libusb_exit(nullptr); + if (deinit_libusb) + libusb_exit(nullptr); } IPCCommandResult CWII_IPC_HLE_Device_hid::Open(u32 _CommandAddress, u32 _Mode) { - DEBUG_LOG(WII_IPC_HID, "HID::Open"); - m_Active = true; - Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); - return GetDefaultReply(); + DEBUG_LOG(WII_IPC_HID, "HID::Open"); + m_Active = true; + Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_hid::Close(u32 _CommandAddress, bool _bForce) { - DEBUG_LOG(WII_IPC_HID, "HID::Close"); - m_Active = false; - if (!_bForce) - Memory::Write_U32(0, _CommandAddress + 4); - return GetDefaultReply(); + DEBUG_LOG(WII_IPC_HID, "HID::Close"); + m_Active = false; + if (!_bForce) + Memory::Write_U32(0, _CommandAddress + 4); + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_hid::IOCtl(u32 _CommandAddress) { - if (Core::g_want_determinism) - { - Memory::Write_U32(-1, _CommandAddress + 0x4); - return GetDefaultReply(); - } + if (Core::g_want_determinism) + { + Memory::Write_U32(-1, _CommandAddress + 0x4); + return GetDefaultReply(); + } - u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); - u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); - u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); - u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); + u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); + u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); + u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); + u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); + u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); - u32 ReturnValue = 0; - switch (Parameter) - { - case IOCTL_HID_GET_ATTACHED: - { - DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Get Attached) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - BufferIn, BufferInSize, BufferOut, BufferOutSize); - deviceCommandAddress = _CommandAddress; - return GetNoReply(); - } - case IOCTL_HID_OPEN: - { - DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Open) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - BufferIn, BufferInSize, BufferOut, BufferOutSize); + u32 ReturnValue = 0; + switch (Parameter) + { + case IOCTL_HID_GET_ATTACHED: + { + DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Get Attached) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); + deviceCommandAddress = _CommandAddress; + return GetNoReply(); + } + case IOCTL_HID_OPEN: + { + DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Open) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); - //hid version, apparently - ReturnValue = 0x40001; - break; - } - case IOCTL_HID_SET_SUSPEND: - { - DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Set Suspend) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - BufferIn, BufferInSize, BufferOut, BufferOutSize); - // not actually implemented in IOS - ReturnValue = 0; - break; - } - case IOCTL_HID_CANCEL_INTERRUPT: - { - DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Cancel Interrupt) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - BufferIn, BufferInSize, BufferOut, BufferOutSize); - ReturnValue = 0; - break; - } - case IOCTL_HID_CONTROL: - { - /* - ERROR CODES: - -4 Can't find device specified - */ + // hid version, apparently + ReturnValue = 0x40001; + break; + } + case IOCTL_HID_SET_SUSPEND: + { + DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Set Suspend) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); + // not actually implemented in IOS + ReturnValue = 0; + break; + } + case IOCTL_HID_CANCEL_INTERRUPT: + { + DEBUG_LOG(WII_IPC_HID, + "HID::IOCtl(Cancel Interrupt) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", BufferIn, + BufferInSize, BufferOut, BufferOutSize); + ReturnValue = 0; + break; + } + case IOCTL_HID_CONTROL: + { + /* + ERROR CODES: + -4 Can't find device specified + */ - u32 dev_num = Memory::Read_U32(BufferIn + 0x10); - u8 bmRequestType = Memory::Read_U8(BufferIn + 0x14); - u8 bRequest = Memory::Read_U8(BufferIn + 0x15); - u16 wValue = Memory::Read_U16(BufferIn + 0x16); - u16 wIndex = Memory::Read_U16(BufferIn + 0x18); - u16 wLength = Memory::Read_U16(BufferIn + 0x1A); - u32 data = Memory::Read_U32(BufferIn + 0x1C); + u32 dev_num = Memory::Read_U32(BufferIn + 0x10); + u8 bmRequestType = Memory::Read_U8(BufferIn + 0x14); + u8 bRequest = Memory::Read_U8(BufferIn + 0x15); + u16 wValue = Memory::Read_U16(BufferIn + 0x16); + u16 wIndex = Memory::Read_U16(BufferIn + 0x18); + u16 wLength = Memory::Read_U16(BufferIn + 0x1A); + u32 data = Memory::Read_U32(BufferIn + 0x1C); - ReturnValue = HIDERR_NO_DEVICE_FOUND; + ReturnValue = HIDERR_NO_DEVICE_FOUND; - libusb_device_handle * dev_handle = GetDeviceByDevNum(dev_num); + libusb_device_handle* dev_handle = GetDeviceByDevNum(dev_num); - if (dev_handle == nullptr) - { - DEBUG_LOG(WII_IPC_HID, "Could not find handle: %X", dev_num); - break; - } - struct libusb_transfer *transfer = libusb_alloc_transfer(0); - transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; + if (dev_handle == nullptr) + { + DEBUG_LOG(WII_IPC_HID, "Could not find handle: %X", dev_num); + break; + } + struct libusb_transfer* transfer = libusb_alloc_transfer(0); + transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; - u8 * buffer = (u8*)malloc(wLength + LIBUSB_CONTROL_SETUP_SIZE); - libusb_fill_control_setup(buffer, bmRequestType, bRequest, wValue, wIndex, wLength); - Memory::CopyFromEmu(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, wLength); - libusb_fill_control_transfer(transfer, dev_handle, buffer, handleUsbUpdates, (void*)(size_t)_CommandAddress, /* no timeout */ 0); - libusb_submit_transfer(transfer); + u8* buffer = (u8*)malloc(wLength + LIBUSB_CONTROL_SETUP_SIZE); + libusb_fill_control_setup(buffer, bmRequestType, bRequest, wValue, wIndex, wLength); + Memory::CopyFromEmu(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, wLength); + libusb_fill_control_transfer(transfer, dev_handle, buffer, handleUsbUpdates, + (void*)(size_t)_CommandAddress, /* no timeout */ 0); + libusb_submit_transfer(transfer); - //DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Control)(%02X, %02X) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - // bmRequestType, bRequest, BufferIn, BufferInSize, BufferOut, BufferOutSize); + // DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Control)(%02X, %02X) (BufferIn: (%08x, %i), BufferOut: + // (%08x, %i)", + // bmRequestType, bRequest, BufferIn, BufferInSize, BufferOut, BufferOutSize); - // It's the async way! - return GetNoReply(); - } - case IOCTL_HID_INTERRUPT_OUT: - case IOCTL_HID_INTERRUPT_IN: - { - u32 dev_num = Memory::Read_U32(BufferIn + 0x10); - u32 endpoint = Memory::Read_U32(BufferIn + 0x14); - u32 length = Memory::Read_U32(BufferIn + 0x18); + // It's the async way! + return GetNoReply(); + } + case IOCTL_HID_INTERRUPT_OUT: + case IOCTL_HID_INTERRUPT_IN: + { + u32 dev_num = Memory::Read_U32(BufferIn + 0x10); + u32 endpoint = Memory::Read_U32(BufferIn + 0x14); + u32 length = Memory::Read_U32(BufferIn + 0x18); - u32 data = Memory::Read_U32(BufferIn + 0x1C); + u32 data = Memory::Read_U32(BufferIn + 0x1C); - ReturnValue = HIDERR_NO_DEVICE_FOUND; + ReturnValue = HIDERR_NO_DEVICE_FOUND; - libusb_device_handle * dev_handle = GetDeviceByDevNum(dev_num); + libusb_device_handle* dev_handle = GetDeviceByDevNum(dev_num); - if (dev_handle == nullptr) - { - DEBUG_LOG(WII_IPC_HID, "Could not find handle: %X", dev_num); - break; - } + if (dev_handle == nullptr) + { + DEBUG_LOG(WII_IPC_HID, "Could not find handle: %X", dev_num); + break; + } - struct libusb_transfer *transfer = libusb_alloc_transfer(0); - transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; - libusb_fill_interrupt_transfer(transfer, dev_handle, endpoint, Memory::GetPointer(data), length, - handleUsbUpdates, (void*)(size_t)_CommandAddress, 0); - libusb_submit_transfer(transfer); + struct libusb_transfer* transfer = libusb_alloc_transfer(0); + transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; + libusb_fill_interrupt_transfer(transfer, dev_handle, endpoint, Memory::GetPointer(data), length, + handleUsbUpdates, (void*)(size_t)_CommandAddress, 0); + libusb_submit_transfer(transfer); - //DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Interrupt %s)(%d,%d,%X) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - // Parameter == IOCTL_HID_INTERRUPT_IN ? "In" : "Out", endpoint, length, data, BufferIn, BufferInSize, BufferOut, BufferOutSize); + // DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Interrupt %s)(%d,%d,%X) (BufferIn: (%08x, %i), BufferOut: + // (%08x, %i)", + // Parameter == IOCTL_HID_INTERRUPT_IN ? "In" : "Out", endpoint, length, data, + // BufferIn, BufferInSize, BufferOut, BufferOutSize); - // It's the async way! - return GetNoReply(); - } - case IOCTL_HID_SHUTDOWN: - { - std::lock_guard lk(m_device_list_reply_mutex); - if (deviceCommandAddress != 0) - { - Memory::Write_U32(0xFFFFFFFF, Memory::Read_U32(deviceCommandAddress + 0x18)); + // It's the async way! + return GetNoReply(); + } + case IOCTL_HID_SHUTDOWN: + { + std::lock_guard lk(m_device_list_reply_mutex); + if (deviceCommandAddress != 0) + { + Memory::Write_U32(0xFFFFFFFF, Memory::Read_U32(deviceCommandAddress + 0x18)); - // The original hardware overwrites the command type with the async reply type. - Memory::Write_U32(IPC_REP_ASYNC, deviceCommandAddress); - // IOS also seems to write back the command that was responded to in the FD field. - Memory::Write_U32(IPC_CMD_IOCTL, deviceCommandAddress + 8); + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, deviceCommandAddress); + // IOS also seems to write back the command that was responded to in the FD field. + Memory::Write_U32(IPC_CMD_IOCTL, deviceCommandAddress + 8); - // Return value - Memory::Write_U32(-1, deviceCommandAddress + 4); - WII_IPC_HLE_Interface::EnqueueReply(deviceCommandAddress); - deviceCommandAddress = 0; - } - DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Shutdown) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - BufferIn, BufferInSize, BufferOut, BufferOutSize); - break; - } - default: - { - DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(0x%x) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - Parameter, BufferIn, BufferInSize, BufferOut, BufferOutSize); - break; - } - } + // Return value + Memory::Write_U32(-1, deviceCommandAddress + 4); + WII_IPC_HLE_Interface::EnqueueReply(deviceCommandAddress); + deviceCommandAddress = 0; + } + DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Shutdown) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); + break; + } + default: + { + DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(0x%x) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + Parameter, BufferIn, BufferInSize, BufferOut, BufferOutSize); + break; + } + } - Memory::Write_U32(ReturnValue, _CommandAddress + 4); + Memory::Write_U32(ReturnValue, _CommandAddress + 4); - return GetDefaultReply(); + return GetDefaultReply(); } - -bool CWII_IPC_HLE_Device_hid::ClaimDevice(libusb_device_handle * dev) +bool CWII_IPC_HLE_Device_hid::ClaimDevice(libusb_device_handle* dev) { - int ret = 0; - if ((ret = libusb_kernel_driver_active(dev, 0)) == 1) - { - if ((ret = libusb_detach_kernel_driver(dev, 0)) && ret != LIBUSB_ERROR_NOT_SUPPORTED) - { - DEBUG_LOG(WII_IPC_HID, "libusb_detach_kernel_driver failed with error: %d", ret); - return false; - } - } - else if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED) - { - DEBUG_LOG(WII_IPC_HID, "libusb_kernel_driver_active error ret = %d", ret); - return false; - } + int ret = 0; + if ((ret = libusb_kernel_driver_active(dev, 0)) == 1) + { + if ((ret = libusb_detach_kernel_driver(dev, 0)) && ret != LIBUSB_ERROR_NOT_SUPPORTED) + { + DEBUG_LOG(WII_IPC_HID, "libusb_detach_kernel_driver failed with error: %d", ret); + return false; + } + } + else if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED) + { + DEBUG_LOG(WII_IPC_HID, "libusb_kernel_driver_active error ret = %d", ret); + return false; + } - if ((ret = libusb_claim_interface(dev, 0))) - { - DEBUG_LOG(WII_IPC_HID, "libusb_claim_interface failed with error: %d", ret); - return false; - } + if ((ret = libusb_claim_interface(dev, 0))) + { + DEBUG_LOG(WII_IPC_HID, "libusb_claim_interface failed with error: %d", ret); + return false; + } - return true; + return true; } IPCCommandResult CWII_IPC_HLE_Device_hid::IOCtlV(u32 _CommandAddress) { + Dolphin_Debugger::PrintCallstack(LogTypes::WII_IPC_HID, LogTypes::LWARNING); + u32 ReturnValue = 0; + SIOCtlVBuffer CommandBuffer(_CommandAddress); - Dolphin_Debugger::PrintCallstack(LogTypes::WII_IPC_HID, LogTypes::LWARNING); - u32 ReturnValue = 0; - SIOCtlVBuffer CommandBuffer(_CommandAddress); + DEBUG_LOG(WII_IPC_HID, "%s - IOCtlV:", GetDeviceName().c_str()); + DEBUG_LOG(WII_IPC_HID, " Parameter: 0x%x", CommandBuffer.Parameter); + DEBUG_LOG(WII_IPC_HID, " NumberIn: 0x%08x", CommandBuffer.NumberInBuffer); + DEBUG_LOG(WII_IPC_HID, " NumberOut: 0x%08x", CommandBuffer.NumberPayloadBuffer); + DEBUG_LOG(WII_IPC_HID, " BufferVector: 0x%08x", CommandBuffer.BufferVector); + DEBUG_LOG(WII_IPC_HID, " PayloadAddr: 0x%08x", CommandBuffer.PayloadBuffer[0].m_Address); + DEBUG_LOG(WII_IPC_HID, " PayloadSize: 0x%08x", CommandBuffer.PayloadBuffer[0].m_Size); +#if defined(_DEBUG) || defined(DEBUGFAST) + DumpAsync(CommandBuffer.BufferVector, CommandBuffer.NumberInBuffer, + CommandBuffer.NumberPayloadBuffer); +#endif - DEBUG_LOG(WII_IPC_HID, "%s - IOCtlV:", GetDeviceName().c_str()); - DEBUG_LOG(WII_IPC_HID, " Parameter: 0x%x", CommandBuffer.Parameter); - DEBUG_LOG(WII_IPC_HID, " NumberIn: 0x%08x", CommandBuffer.NumberInBuffer); - DEBUG_LOG(WII_IPC_HID, " NumberOut: 0x%08x", CommandBuffer.NumberPayloadBuffer); - DEBUG_LOG(WII_IPC_HID, " BufferVector: 0x%08x", CommandBuffer.BufferVector); - DEBUG_LOG(WII_IPC_HID, " PayloadAddr: 0x%08x", CommandBuffer.PayloadBuffer[0].m_Address); - DEBUG_LOG(WII_IPC_HID, " PayloadSize: 0x%08x", CommandBuffer.PayloadBuffer[0].m_Size); - #if defined(_DEBUG) || defined(DEBUGFAST) - DumpAsync(CommandBuffer.BufferVector, CommandBuffer.NumberInBuffer, CommandBuffer.NumberPayloadBuffer); - #endif - - Memory::Write_U32(ReturnValue, _CommandAddress + 4); - return GetDefaultReply(); + Memory::Write_U32(ReturnValue, _CommandAddress + 4); + return GetDefaultReply(); } - - -void CWII_IPC_HLE_Device_hid::ConvertDeviceToWii(WiiHIDDeviceDescriptor *dest, const struct libusb_device_descriptor *src) +void CWII_IPC_HLE_Device_hid::ConvertDeviceToWii(WiiHIDDeviceDescriptor* dest, + const struct libusb_device_descriptor* src) { - dest->bLength = src->bLength; - dest->bDescriptorType = src->bDescriptorType; - dest->bcdUSB = Common::swap16(src->bcdUSB); - dest->bDeviceClass = src->bDeviceClass; - dest->bDeviceSubClass = src->bDeviceSubClass; - dest->bDeviceProtocol = src->bDeviceProtocol; - dest->bMaxPacketSize0 = src->bMaxPacketSize0; - dest->idVendor = Common::swap16(src->idVendor); - dest->idProduct = Common::swap16(src->idProduct); - dest->bcdDevice = Common::swap16(src->bcdDevice); - dest->iManufacturer = src->iManufacturer; - dest->iProduct = src->iProduct; - dest->iSerialNumber = src->iSerialNumber; - dest->bNumConfigurations = src->bNumConfigurations; + dest->bLength = src->bLength; + dest->bDescriptorType = src->bDescriptorType; + dest->bcdUSB = Common::swap16(src->bcdUSB); + dest->bDeviceClass = src->bDeviceClass; + dest->bDeviceSubClass = src->bDeviceSubClass; + dest->bDeviceProtocol = src->bDeviceProtocol; + dest->bMaxPacketSize0 = src->bMaxPacketSize0; + dest->idVendor = Common::swap16(src->idVendor); + dest->idProduct = Common::swap16(src->idProduct); + dest->bcdDevice = Common::swap16(src->bcdDevice); + dest->iManufacturer = src->iManufacturer; + dest->iProduct = src->iProduct; + dest->iSerialNumber = src->iSerialNumber; + dest->bNumConfigurations = src->bNumConfigurations; } -void CWII_IPC_HLE_Device_hid::ConvertConfigToWii(WiiHIDConfigDescriptor *dest, const struct libusb_config_descriptor *src) +void CWII_IPC_HLE_Device_hid::ConvertConfigToWii(WiiHIDConfigDescriptor* dest, + const struct libusb_config_descriptor* src) { - memcpy(dest,src,sizeof(WiiHIDConfigDescriptor)); - dest->wTotalLength = Common::swap16(dest->wTotalLength); + memcpy(dest, src, sizeof(WiiHIDConfigDescriptor)); + dest->wTotalLength = Common::swap16(dest->wTotalLength); } -void CWII_IPC_HLE_Device_hid::ConvertInterfaceToWii(WiiHIDInterfaceDescriptor *dest, const struct libusb_interface_descriptor *src) +void CWII_IPC_HLE_Device_hid::ConvertInterfaceToWii(WiiHIDInterfaceDescriptor* dest, + const struct libusb_interface_descriptor* src) { - memcpy(dest,src,sizeof(WiiHIDInterfaceDescriptor)); + memcpy(dest, src, sizeof(WiiHIDInterfaceDescriptor)); } -void CWII_IPC_HLE_Device_hid::ConvertEndpointToWii(WiiHIDEndpointDescriptor *dest, const struct libusb_endpoint_descriptor *src) +void CWII_IPC_HLE_Device_hid::ConvertEndpointToWii(WiiHIDEndpointDescriptor* dest, + const struct libusb_endpoint_descriptor* src) { - memcpy(dest,src,sizeof(WiiHIDEndpointDescriptor)); - dest->wMaxPacketSize = Common::swap16(dest->wMaxPacketSize); + memcpy(dest, src, sizeof(WiiHIDEndpointDescriptor)); + dest->wMaxPacketSize = Common::swap16(dest->wMaxPacketSize); } void CWII_IPC_HLE_Device_hid::FillOutDevices(u32 BufferOut, u32 BufferOutSize) { - static u16 check = 1; - int OffsetBuffer = BufferOut; - int OffsetStart = 0; - //int OffsetDevice = 0; - int d,c,ic,i,e; /* config, interface container, interface, endpoint */ + static u16 check = 1; + int OffsetBuffer = BufferOut; + int OffsetStart = 0; + // int OffsetDevice = 0; + int d, c, ic, i, e; /* config, interface container, interface, endpoint */ - libusb_device **list; - //libusb_device *found = nullptr; - ssize_t cnt = libusb_get_device_list(nullptr, &list); - DEBUG_LOG(WII_IPC_HID, "Found %ld viable USB devices.", cnt); - for (d = 0; d < cnt; d++) - { - libusb_device *device = list[d]; - struct libusb_device_descriptor desc; - int dRet = libusb_get_device_descriptor (device, &desc); - if (dRet) - { - // could not aquire the descriptor, no point in trying to use it. - DEBUG_LOG(WII_IPC_HID, "libusb_get_device_descriptor failed with error: %d", dRet); - continue; - } - OffsetStart = OffsetBuffer; - OffsetBuffer += 4; // skip length for now, fill at end + libusb_device** list; + // libusb_device *found = nullptr; + ssize_t cnt = libusb_get_device_list(nullptr, &list); + DEBUG_LOG(WII_IPC_HID, "Found %ld viable USB devices.", cnt); + for (d = 0; d < cnt; d++) + { + libusb_device* device = list[d]; + struct libusb_device_descriptor desc; + int dRet = libusb_get_device_descriptor(device, &desc); + if (dRet) + { + // could not aquire the descriptor, no point in trying to use it. + DEBUG_LOG(WII_IPC_HID, "libusb_get_device_descriptor failed with error: %d", dRet); + continue; + } + OffsetStart = OffsetBuffer; + OffsetBuffer += 4; // skip length for now, fill at end - OffsetBuffer += 4; // skip devNum for now + OffsetBuffer += 4; // skip devNum for now - WiiHIDDeviceDescriptor wii_device; - ConvertDeviceToWii(&wii_device, &desc); - Memory::CopyToEmu(OffsetBuffer, &wii_device, Align(wii_device.bLength, 4)); - OffsetBuffer += Align(wii_device.bLength, 4); - bool deviceValid = true; - bool isHID = false; + WiiHIDDeviceDescriptor wii_device; + ConvertDeviceToWii(&wii_device, &desc); + Memory::CopyToEmu(OffsetBuffer, &wii_device, Align(wii_device.bLength, 4)); + OffsetBuffer += Align(wii_device.bLength, 4); + bool deviceValid = true; + bool isHID = false; - for (c = 0; deviceValid && c < desc.bNumConfigurations; c++) - { - struct libusb_config_descriptor *config = nullptr; - int cRet = libusb_get_config_descriptor(device, c, &config); - // do not try to use usb devices with more than one interface, games can crash - if (cRet == 0 && config->bNumInterfaces <= MAX_HID_INTERFACES) - { - WiiHIDConfigDescriptor wii_config; - ConvertConfigToWii(&wii_config, config); - Memory::CopyToEmu(OffsetBuffer, &wii_config, Align(wii_config.bLength, 4)); - OffsetBuffer += Align(wii_config.bLength, 4); + for (c = 0; deviceValid && c < desc.bNumConfigurations; c++) + { + struct libusb_config_descriptor* config = nullptr; + int cRet = libusb_get_config_descriptor(device, c, &config); + // do not try to use usb devices with more than one interface, games can crash + if (cRet == 0 && config->bNumInterfaces <= MAX_HID_INTERFACES) + { + WiiHIDConfigDescriptor wii_config; + ConvertConfigToWii(&wii_config, config); + Memory::CopyToEmu(OffsetBuffer, &wii_config, Align(wii_config.bLength, 4)); + OffsetBuffer += Align(wii_config.bLength, 4); - for (ic = 0; ic < config->bNumInterfaces; ic++) - { - const struct libusb_interface *interfaceContainer = &config->interface[ic]; + for (ic = 0; ic < config->bNumInterfaces; ic++) + { + const struct libusb_interface* interfaceContainer = &config->interface[ic]; - for (i = 0; i < interfaceContainer->num_altsetting; i++) - { - const struct libusb_interface_descriptor *interface = &interfaceContainer->altsetting[i]; + for (i = 0; i < interfaceContainer->num_altsetting; i++) + { + const struct libusb_interface_descriptor* interface = + &interfaceContainer->altsetting[i]; - if (interface->bInterfaceClass == LIBUSB_CLASS_HID) - isHID = true; + if (interface->bInterfaceClass == LIBUSB_CLASS_HID) + isHID = true; - WiiHIDInterfaceDescriptor wii_interface; - ConvertInterfaceToWii(&wii_interface, interface); - Memory::CopyToEmu(OffsetBuffer, &wii_interface, Align(wii_interface.bLength, 4)); - OffsetBuffer += Align(wii_interface.bLength, 4); + WiiHIDInterfaceDescriptor wii_interface; + ConvertInterfaceToWii(&wii_interface, interface); + Memory::CopyToEmu(OffsetBuffer, &wii_interface, Align(wii_interface.bLength, 4)); + OffsetBuffer += Align(wii_interface.bLength, 4); - for (e = 0; e < interface->bNumEndpoints; e++) - { - const struct libusb_endpoint_descriptor *endpoint = &interface->endpoint[e]; + for (e = 0; e < interface->bNumEndpoints; e++) + { + const struct libusb_endpoint_descriptor* endpoint = &interface->endpoint[e]; - WiiHIDEndpointDescriptor wii_endpoint; - ConvertEndpointToWii(&wii_endpoint, endpoint); - Memory::CopyToEmu(OffsetBuffer, &wii_endpoint, Align(wii_endpoint.bLength, 4)); - OffsetBuffer += Align(wii_endpoint.bLength, 4); + WiiHIDEndpointDescriptor wii_endpoint; + ConvertEndpointToWii(&wii_endpoint, endpoint); + Memory::CopyToEmu(OffsetBuffer, &wii_endpoint, Align(wii_endpoint.bLength, 4)); + OffsetBuffer += Align(wii_endpoint.bLength, 4); - } //endpoints - } // interfaces - } // interface containters - libusb_free_config_descriptor(config); - config = nullptr; - } - else - { - if (cRet) - DEBUG_LOG(WII_IPC_HID, "libusb_get_config_descriptor failed with: %d", cRet); - deviceValid = false; - OffsetBuffer = OffsetStart; - } - } // configs + } // endpoints + } // interfaces + } // interface containters + libusb_free_config_descriptor(config); + config = nullptr; + } + else + { + if (cRet) + DEBUG_LOG(WII_IPC_HID, "libusb_get_config_descriptor failed with: %d", cRet); + deviceValid = false; + OffsetBuffer = OffsetStart; + } + } // configs - if (!isHID) - { - deviceValid = false; - OffsetBuffer = OffsetStart; - } + if (!isHID) + { + deviceValid = false; + OffsetBuffer = OffsetStart; + } - if (deviceValid) - { - Memory::Write_U32(OffsetBuffer-OffsetStart, OffsetStart); // fill in length + if (deviceValid) + { + Memory::Write_U32(OffsetBuffer - OffsetStart, OffsetStart); // fill in length - int devNum = GetAvailableDevNum(desc.idVendor, - desc.idProduct, - libusb_get_bus_number (device), - libusb_get_device_address (device), - check); - if (devNum < 0 ) - { - // too many devices to handle. - ERROR_LOG(WII_IPC_HID, "Exhausted device list, there are way too many usb devices plugged in."); - OffsetBuffer = OffsetStart; - continue; - } + int devNum = GetAvailableDevNum(desc.idVendor, desc.idProduct, libusb_get_bus_number(device), + libusb_get_device_address(device), check); + if (devNum < 0) + { + // too many devices to handle. + ERROR_LOG(WII_IPC_HID, + "Exhausted device list, there are way too many usb devices plugged in."); + OffsetBuffer = OffsetStart; + continue; + } - DEBUG_LOG(WII_IPC_HID, "Found device with Vendor: %X Product: %X Devnum: %d", desc.idVendor, desc.idProduct, devNum); + DEBUG_LOG(WII_IPC_HID, "Found device with Vendor: %X Product: %X Devnum: %d", desc.idVendor, + desc.idProduct, devNum); - Memory::Write_U32(devNum , OffsetStart+4); //write device num - } - } + Memory::Write_U32(devNum, OffsetStart + 4); // write device num + } + } - // Find devices that no longer exists and free them - for (i=0; i> 48); - if (hidDeviceAliases[i] != 0 && check_cur != check) - { - DEBUG_LOG(WII_IPC_HID, "Removing: device %d %hX %hX", i, check, check_cur); - std::lock_guard lk(m_open_devices_mutex); - if (m_open_devices.find(i) != m_open_devices.end()) - { - libusb_device_handle *handle = m_open_devices[i]; - libusb_close(handle); - m_open_devices.erase(i); - } - hidDeviceAliases[i] = 0; - } - } - check++; + // Find devices that no longer exists and free them + for (i = 0; i < MAX_DEVICE_DEVNUM; i++) + { + u16 check_cur = (u16)(hidDeviceAliases[i] >> 48); + if (hidDeviceAliases[i] != 0 && check_cur != check) + { + DEBUG_LOG(WII_IPC_HID, "Removing: device %d %hX %hX", i, check, check_cur); + std::lock_guard lk(m_open_devices_mutex); + if (m_open_devices.find(i) != m_open_devices.end()) + { + libusb_device_handle* handle = m_open_devices[i]; + libusb_close(handle); + m_open_devices.erase(i); + } + hidDeviceAliases[i] = 0; + } + } + check++; + libusb_free_device_list(list, 1); - libusb_free_device_list(list, 1); - - Memory::Write_U32(0xFFFFFFFF, OffsetBuffer); // no more devices - + Memory::Write_U32(0xFFFFFFFF, OffsetBuffer); // no more devices } int CWII_IPC_HLE_Device_hid::Align(int num, int alignment) { - return (num + (alignment-1)) & ~(alignment-1); + return (num + (alignment - 1)) & ~(alignment - 1); } - -libusb_device_handle * CWII_IPC_HLE_Device_hid::GetDeviceByDevNum(u32 devNum) +libusb_device_handle* CWII_IPC_HLE_Device_hid::GetDeviceByDevNum(u32 devNum) { - libusb_device **list; - libusb_device_handle *handle = nullptr; - ssize_t cnt; + libusb_device** list; + libusb_device_handle* handle = nullptr; + ssize_t cnt; - if (devNum >= MAX_DEVICE_DEVNUM) - return nullptr; + if (devNum >= MAX_DEVICE_DEVNUM) + return nullptr; + std::lock_guard lk(m_open_devices_mutex); - std::lock_guard lk(m_open_devices_mutex); + if (m_open_devices.find(devNum) != m_open_devices.end()) + { + handle = m_open_devices[devNum]; + if (libusb_kernel_driver_active(handle, 0) != LIBUSB_ERROR_NO_DEVICE) + { + return handle; + } + else + { + libusb_close(handle); + m_open_devices.erase(devNum); + } + } - if (m_open_devices.find(devNum) != m_open_devices.end()) - { - handle = m_open_devices[devNum]; - if (libusb_kernel_driver_active(handle, 0) != LIBUSB_ERROR_NO_DEVICE) - { - return handle; - } - else - { - libusb_close(handle); - m_open_devices.erase(devNum); - } - } + cnt = libusb_get_device_list(nullptr, &list); - cnt = libusb_get_device_list(nullptr, &list); - - if (cnt < 0) - return nullptr; + if (cnt < 0) + return nullptr; #ifdef _WIN32 - static bool has_warned_about_drivers = false; + static bool has_warned_about_drivers = false; #endif - for (ssize_t i = 0; i < cnt; i++) - { - libusb_device *device = list[i]; - struct libusb_device_descriptor desc; - int dRet = libusb_get_device_descriptor (device, &desc); - u8 bus = libusb_get_bus_number (device); - u8 port = libusb_get_device_address (device); - u64 unique_id = ((u64)desc.idVendor << 32) | ((u64)desc.idProduct << 16) | ((u64)bus << 8) | (u64)port; - if ((hidDeviceAliases[devNum] & HID_ID_MASK) == unique_id) - { - int ret = libusb_open(device, &handle); - if (ret) - { - if (ret == LIBUSB_ERROR_ACCESS) - { - if (dRet) - { - ERROR_LOG(WII_IPC_HID, "Dolphin does not have access to this device: Bus %03d Device %03d: ID ????:???? (couldn't get id).", - bus, - port - ); - } - else - { - ERROR_LOG(WII_IPC_HID, "Dolphin does not have access to this device: Bus %03d Device %03d: ID %04X:%04X.", - bus, - port, - desc.idVendor, - desc.idProduct - ); - } - } + for (ssize_t i = 0; i < cnt; i++) + { + libusb_device* device = list[i]; + struct libusb_device_descriptor desc; + int dRet = libusb_get_device_descriptor(device, &desc); + u8 bus = libusb_get_bus_number(device); + u8 port = libusb_get_device_address(device); + u64 unique_id = + ((u64)desc.idVendor << 32) | ((u64)desc.idProduct << 16) | ((u64)bus << 8) | (u64)port; + if ((hidDeviceAliases[devNum] & HID_ID_MASK) == unique_id) + { + int ret = libusb_open(device, &handle); + if (ret) + { + if (ret == LIBUSB_ERROR_ACCESS) + { + if (dRet) + { + ERROR_LOG(WII_IPC_HID, "Dolphin does not have access to this device: Bus %03d Device " + "%03d: ID ????:???? (couldn't get id).", + bus, port); + } + else + { + ERROR_LOG( + WII_IPC_HID, + "Dolphin does not have access to this device: Bus %03d Device %03d: ID %04X:%04X.", + bus, port, desc.idVendor, desc.idProduct); + } + } #ifdef _WIN32 - else if (ret == LIBUSB_ERROR_NOT_SUPPORTED) - { - if (!has_warned_about_drivers) - { - // Max of one warning. - has_warned_about_drivers = true; - WARN_LOG(WII_IPC_HID, "Please install the libusb drivers for the device %04X:%04X", desc.idVendor, desc.idProduct); - } - } + else if (ret == LIBUSB_ERROR_NOT_SUPPORTED) + { + if (!has_warned_about_drivers) + { + // Max of one warning. + has_warned_about_drivers = true; + WARN_LOG(WII_IPC_HID, "Please install the libusb drivers for the device %04X:%04X", + desc.idVendor, desc.idProduct); + } + } #endif - else - { - ERROR_LOG(WII_IPC_HID, "libusb_open failed to open device with error = %d", ret); - } - continue; - } + else + { + ERROR_LOG(WII_IPC_HID, "libusb_open failed to open device with error = %d", ret); + } + continue; + } + if (!ClaimDevice(handle)) + { + ERROR_LOG(WII_IPC_HID, "Could not claim the device for handle: %X", devNum); + libusb_close(handle); + continue; + } - if (!ClaimDevice(handle)) - { - ERROR_LOG(WII_IPC_HID, "Could not claim the device for handle: %X", devNum); - libusb_close(handle); - continue; - } + m_open_devices[devNum] = handle; + break; + } + else + { + handle = nullptr; + } + } - m_open_devices[devNum] = handle; - break; - } - else - { - handle = nullptr; - } - } + libusb_free_device_list(list, 1); - libusb_free_device_list(list, 1); - - - return handle; + return handle; } - -int CWII_IPC_HLE_Device_hid::GetAvailableDevNum(u16 idVendor, u16 idProduct, u8 bus, u8 port, u16 check) +int CWII_IPC_HLE_Device_hid::GetAvailableDevNum(u16 idVendor, u16 idProduct, u8 bus, u8 port, + u16 check) { - int pos = -1; - u64 unique_id = ((u64)idVendor << 32) | ((u64)idProduct << 16) | ((u64)bus << 8) | (u64)port; + int pos = -1; + u64 unique_id = ((u64)idVendor << 32) | ((u64)idProduct << 16) | ((u64)bus << 8) | (u64)port; - for (int i=0; i m_open_devices; - std::mutex m_open_devices_mutex; - std::mutex m_device_list_reply_mutex; + libusb_device_handle* GetDeviceByDevNum(u32 devNum); + std::map m_open_devices; + std::mutex m_open_devices_mutex; + std::mutex m_device_list_reply_mutex; - std::thread usb_thread; - bool usb_thread_running; + std::thread usb_thread; + bool usb_thread_running; }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.cpp index fa0e7f330f..4af2e469c1 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.cpp @@ -16,37 +16,37 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/ec_wii.h" #include "Core/IPC_HLE/ICMP.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_es.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_net.h" #include "Core/IPC_HLE/WII_Socket.h" +#include "Core/ec_wii.h" #ifdef _WIN32 -#include #include +#include #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) #elif defined(__linux__) or defined(__APPLE__) -#include #include -#include -#include -#include -#include -#include #include +#include +#include +#include #include #include +#include +#include +#include typedef struct pollfd pollfd_t; #else -#include -#include -#include #include +#include +#include +#include #endif // WSAPoll doesn't support POLLPRI and POLLWRBAND flags @@ -58,292 +58,292 @@ typedef struct pollfd pollfd_t; // ********************************************************************************** // Handle /dev/net/kd/request requests -CWII_IPC_HLE_Device_net_kd_request::CWII_IPC_HLE_Device_net_kd_request(u32 _DeviceID, const std::string& _rDeviceName) - : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) +CWII_IPC_HLE_Device_net_kd_request::CWII_IPC_HLE_Device_net_kd_request( + u32 _DeviceID, const std::string& _rDeviceName) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) { } CWII_IPC_HLE_Device_net_kd_request::~CWII_IPC_HLE_Device_net_kd_request() { - WiiSockMan::GetInstance().Clean(); + WiiSockMan::GetInstance().Clean(); } IPCCommandResult CWII_IPC_HLE_Device_net_kd_request::Open(u32 _CommandAddress, u32 _Mode) { - INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: Open"); - Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); - m_Active = true; - return GetDefaultReply(); + INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: Open"); + Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); + m_Active = true; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_net_kd_request::Close(u32 _CommandAddress, bool _bForce) { - INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: Close"); - if (!_bForce) - Memory::Write_U32(0, _CommandAddress + 4); - m_Active = false; - return GetDefaultReply(); + INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: Close"); + if (!_bForce) + Memory::Write_U32(0, _CommandAddress + 4); + m_Active = false; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_net_kd_request::IOCtl(u32 _CommandAddress) { - u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); - u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); - u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); - u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); + u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); + u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); + u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); + u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); + u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); - u32 ReturnValue = 0; - switch (Parameter) - { - case IOCTL_NWC24_SUSPEND_SCHEDULAR: - // NWC24iResumeForCloseLib from NWC24SuspendScheduler (Input: none, Output: 32 bytes) - INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_SUSPEND_SCHEDULAR - NI"); - Memory::Write_U32(0, BufferOut); // no error - break; + u32 ReturnValue = 0; + switch (Parameter) + { + case IOCTL_NWC24_SUSPEND_SCHEDULAR: + // NWC24iResumeForCloseLib from NWC24SuspendScheduler (Input: none, Output: 32 bytes) + INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_SUSPEND_SCHEDULAR - NI"); + Memory::Write_U32(0, BufferOut); // no error + break; - case IOCTL_NWC24_EXEC_TRY_SUSPEND_SCHEDULAR: // NWC24iResumeForCloseLib - INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_EXEC_TRY_SUSPEND_SCHEDULAR - NI"); - break; + case IOCTL_NWC24_EXEC_TRY_SUSPEND_SCHEDULAR: // NWC24iResumeForCloseLib + INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_EXEC_TRY_SUSPEND_SCHEDULAR - NI"); + break; - case IOCTL_NWC24_EXEC_RESUME_SCHEDULAR: // NWC24iResumeForCloseLib - INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_EXEC_RESUME_SCHEDULAR - NI"); - Memory::Write_U32(0, BufferOut); // no error - break; + case IOCTL_NWC24_EXEC_RESUME_SCHEDULAR: // NWC24iResumeForCloseLib + INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_EXEC_RESUME_SCHEDULAR - NI"); + Memory::Write_U32(0, BufferOut); // no error + break; - case IOCTL_NWC24_STARTUP_SOCKET: // NWC24iStartupSocket - Memory::Write_U32(0, BufferOut); - Memory::Write_U32(0, BufferOut + 4); - ReturnValue = 0; - INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_STARTUP_SOCKET - NI"); - break; + case IOCTL_NWC24_STARTUP_SOCKET: // NWC24iStartupSocket + Memory::Write_U32(0, BufferOut); + Memory::Write_U32(0, BufferOut + 4); + ReturnValue = 0; + INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_STARTUP_SOCKET - NI"); + break; - case IOCTL_NWC24_CLEANUP_SOCKET: - Memory::Memset(BufferOut, 0, BufferOutSize); - INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_CLEANUP_SOCKET - NI"); - break; + case IOCTL_NWC24_CLEANUP_SOCKET: + Memory::Memset(BufferOut, 0, BufferOutSize); + INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_CLEANUP_SOCKET - NI"); + break; - case IOCTL_NWC24_LOCK_SOCKET: // WiiMenu - INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_LOCK_SOCKET - NI"); - break; + case IOCTL_NWC24_LOCK_SOCKET: // WiiMenu + INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_LOCK_SOCKET - NI"); + break; - case IOCTL_NWC24_UNLOCK_SOCKET: - INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_UNLOCK_SOCKET - NI"); - break; + case IOCTL_NWC24_UNLOCK_SOCKET: + INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_UNLOCK_SOCKET - NI"); + break; - case IOCTL_NWC24_REQUEST_REGISTER_USER_ID: - INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_REQUEST_REGISTER_USER_ID"); - Memory::Write_U32(0, BufferOut); - Memory::Write_U32(0, BufferOut + 4); - break; + case IOCTL_NWC24_REQUEST_REGISTER_USER_ID: + INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_REQUEST_REGISTER_USER_ID"); + Memory::Write_U32(0, BufferOut); + Memory::Write_U32(0, BufferOut + 4); + break; - case IOCTL_NWC24_REQUEST_GENERATED_USER_ID: // (Input: none, Output: 32 bytes) - INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_REQUEST_GENERATED_USER_ID"); - if (config.CreationStage() == nwc24_config_t::NWC24_IDCS_INITIAL) - { - std::string settings_Filename(Common::GetTitleDataPath(TITLEID_SYSMENU, Common::FROM_SESSION_ROOT) + WII_SETTING); - SettingsHandler gen; - std::string area, model; - bool _GotSettings = false; + case IOCTL_NWC24_REQUEST_GENERATED_USER_ID: // (Input: none, Output: 32 bytes) + INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_REQUEST_GENERATED_USER_ID"); + if (config.CreationStage() == nwc24_config_t::NWC24_IDCS_INITIAL) + { + std::string settings_Filename( + Common::GetTitleDataPath(TITLEID_SYSMENU, Common::FROM_SESSION_ROOT) + WII_SETTING); + SettingsHandler gen; + std::string area, model; + bool _GotSettings = false; - if (File::Exists(settings_Filename)) - { - File::IOFile settingsFileHandle(settings_Filename, "rb"); - if (settingsFileHandle.ReadBytes((void*)gen.GetData(), SettingsHandler::SETTINGS_SIZE)) - { - gen.Decrypt(); - area = gen.GetValue("AREA"); - model = gen.GetValue("MODEL"); - _GotSettings = true; - } - } - if (_GotSettings) - { - u8 area_code = GetAreaCode(area); - u8 id_ctr = config.IdGen(); - u8 hardware_model = GetHardwareModel(model); + if (File::Exists(settings_Filename)) + { + File::IOFile settingsFileHandle(settings_Filename, "rb"); + if (settingsFileHandle.ReadBytes((void*)gen.GetData(), SettingsHandler::SETTINGS_SIZE)) + { + gen.Decrypt(); + area = gen.GetValue("AREA"); + model = gen.GetValue("MODEL"); + _GotSettings = true; + } + } + if (_GotSettings) + { + u8 area_code = GetAreaCode(area); + u8 id_ctr = config.IdGen(); + u8 hardware_model = GetHardwareModel(model); - EcWii &ec = EcWii::GetInstance(); - u32 HollywoodID = ec.getNgId(); - u64 UserID = 0; + EcWii& ec = EcWii::GetInstance(); + u32 HollywoodID = ec.getNgId(); + u64 UserID = 0; - s32 ret = NWC24MakeUserID(&UserID, HollywoodID, id_ctr, hardware_model, area_code); - config.SetId(UserID); - config.IncrementIdGen(); - config.SetCreationStage(nwc24_config_t::NWC24_IDCS_GENERATED); - config.WriteConfig(); + s32 ret = NWC24MakeUserID(&UserID, HollywoodID, id_ctr, hardware_model, area_code); + config.SetId(UserID); + config.IncrementIdGen(); + config.SetCreationStage(nwc24_config_t::NWC24_IDCS_GENERATED); + config.WriteConfig(); - Memory::Write_U32(ret, BufferOut); - } - else - { - Memory::Write_U32(WC24_ERR_FATAL, BufferOut); - } - } - else if (config.CreationStage() == nwc24_config_t::NWC24_IDCS_GENERATED) - { - Memory::Write_U32(WC24_ERR_ID_GENERATED, BufferOut); - } - else if (config.CreationStage() == nwc24_config_t::NWC24_IDCS_REGISTERED) - { - Memory::Write_U32(WC24_ERR_ID_REGISTERED, BufferOut); - } - Memory::Write_U64(config.Id(), BufferOut + 4); - Memory::Write_U32(config.CreationStage(), BufferOut + 0xC); - break; + Memory::Write_U32(ret, BufferOut); + } + else + { + Memory::Write_U32(WC24_ERR_FATAL, BufferOut); + } + } + else if (config.CreationStage() == nwc24_config_t::NWC24_IDCS_GENERATED) + { + Memory::Write_U32(WC24_ERR_ID_GENERATED, BufferOut); + } + else if (config.CreationStage() == nwc24_config_t::NWC24_IDCS_REGISTERED) + { + Memory::Write_U32(WC24_ERR_ID_REGISTERED, BufferOut); + } + Memory::Write_U64(config.Id(), BufferOut + 4); + Memory::Write_U32(config.CreationStage(), BufferOut + 0xC); + break; - case IOCTL_NWC24_GET_SCHEDULAR_STAT: - INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_GET_SCHEDULAR_STAT - NI"); - break; + case IOCTL_NWC24_GET_SCHEDULAR_STAT: + INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_GET_SCHEDULAR_STAT - NI"); + break; - case IOCTL_NWC24_SAVE_MAIL_NOW: - INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_SAVE_MAIL_NOW - NI"); - break; + case IOCTL_NWC24_SAVE_MAIL_NOW: + INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_SAVE_MAIL_NOW - NI"); + break; - case IOCTL_NWC24_REQUEST_SHUTDOWN: - // if ya set the IOS version to a very high value this happens ... - INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_REQUEST_SHUTDOWN - NI"); - break; + case IOCTL_NWC24_REQUEST_SHUTDOWN: + // if ya set the IOS version to a very high value this happens ... + INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: IOCTL_NWC24_REQUEST_SHUTDOWN - NI"); + break; - default: - INFO_LOG(WII_IPC_WC24, "/dev/net/kd/request::IOCtl request 0x%x (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - Parameter, BufferIn, BufferInSize, BufferOut, BufferOutSize); - break; - } + default: + INFO_LOG(WII_IPC_WC24, + "/dev/net/kd/request::IOCtl request 0x%x (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + Parameter, BufferIn, BufferInSize, BufferOut, BufferOutSize); + break; + } - Memory::Write_U32(ReturnValue, _CommandAddress + 4); - return GetDefaultReply(); + Memory::Write_U32(ReturnValue, _CommandAddress + 4); + return GetDefaultReply(); } - u8 CWII_IPC_HLE_Device_net_kd_request::GetAreaCode(const std::string& area) const { - static std::map regions = { - { "JPN", 0 }, { "USA", 1 }, { "EUR", 2 }, - { "AUS", 2 }, { "BRA", 1 }, { "TWN", 3 }, - { "ROC", 3 }, { "KOR", 4 }, { "HKG", 5 }, - { "ASI", 5 }, { "LTN", 1 }, { "SAF", 2 }, - { "CHN", 6 }, - }; + static std::map regions = { + {"JPN", 0}, {"USA", 1}, {"EUR", 2}, {"AUS", 2}, {"BRA", 1}, {"TWN", 3}, {"ROC", 3}, + {"KOR", 4}, {"HKG", 5}, {"ASI", 5}, {"LTN", 1}, {"SAF", 2}, {"CHN", 6}, + }; - auto entryPos = regions.find(area); - if (entryPos != regions.end()) - return entryPos->second; - else - return 7; // Unknown + auto entryPos = regions.find(area); + if (entryPos != regions.end()) + return entryPos->second; + else + return 7; // Unknown } u8 CWII_IPC_HLE_Device_net_kd_request::GetHardwareModel(const std::string& model) const { - static std::map models = { - { "RVL", MODEL_RVL }, - { "RVT", MODEL_RVT }, - { "RVV", MODEL_RVV }, - { "RVD", MODEL_RVD }, - }; + static std::map models = { + {"RVL", MODEL_RVL}, {"RVT", MODEL_RVT}, {"RVV", MODEL_RVV}, {"RVD", MODEL_RVD}, + }; - auto entryPos = models.find(model); - if (entryPos != models.end()) - return entryPos->second; - else - return MODEL_ELSE; + auto entryPos = models.find(model); + if (entryPos != models.end()) + return entryPos->second; + else + return MODEL_ELSE; } static inline u8 u64_get_byte(u64 value, u8 shift) { - return (u8)(value >> (shift*8)); + return (u8)(value >> (shift * 8)); } static inline u64 u64_insert_byte(u64 value, u8 shift, u8 byte) { - u64 mask = 0x00000000000000FFULL << (shift*8); - u64 inst = (u64)byte << (shift*8); - return (value & ~mask) | inst; + u64 mask = 0x00000000000000FFULL << (shift * 8); + u64 inst = (u64)byte << (shift * 8); + return (value & ~mask) | inst; } -s32 CWII_IPC_HLE_Device_net_kd_request::NWC24MakeUserID(u64* nwc24_id, u32 hollywood_id, u16 id_ctr, u8 hardware_model, u8 area_code) +s32 CWII_IPC_HLE_Device_net_kd_request::NWC24MakeUserID(u64* nwc24_id, u32 hollywood_id, u16 id_ctr, + u8 hardware_model, u8 area_code) { - const u8 table2[8] = {0x1, 0x5, 0x0, 0x4, 0x2, 0x3, 0x6, 0x7}; - const u8 table1[16] = {0x4, 0xB, 0x7, 0x9, 0xF, 0x1, 0xD, 0x3, 0xC, 0x2, 0x6, 0xE, 0x8, 0x0, 0xA, 0x5}; + const u8 table2[8] = {0x1, 0x5, 0x0, 0x4, 0x2, 0x3, 0x6, 0x7}; + const u8 table1[16] = {0x4, 0xB, 0x7, 0x9, 0xF, 0x1, 0xD, 0x3, + 0xC, 0x2, 0x6, 0xE, 0x8, 0x0, 0xA, 0x5}; - u64 mix_id = ((u64)area_code << 50) | ((u64)hardware_model << 47) | ((u64)hollywood_id << 15) | ((u64)id_ctr << 10); - u64 mix_id_copy1 = mix_id; + u64 mix_id = ((u64)area_code << 50) | ((u64)hardware_model << 47) | ((u64)hollywood_id << 15) | + ((u64)id_ctr << 10); + u64 mix_id_copy1 = mix_id; - int ctr = 0; - for (ctr = 0; ctr <= 42; ctr++) - { - u64 value = mix_id >> (52 - ctr); - if (value & 1) - { - value = 0x0000000000000635ULL << (42-ctr); - mix_id ^= value; - } - } + int ctr = 0; + for (ctr = 0; ctr <= 42; ctr++) + { + u64 value = mix_id >> (52 - ctr); + if (value & 1) + { + value = 0x0000000000000635ULL << (42 - ctr); + mix_id ^= value; + } + } - mix_id = (mix_id_copy1 | (mix_id & 0xFFFFFFFFUL)) ^ 0x0000B3B3B3B3B3B3ULL; - mix_id = (mix_id >> 10) | ((mix_id & 0x3FF) << (11 + 32)); + mix_id = (mix_id_copy1 | (mix_id & 0xFFFFFFFFUL)) ^ 0x0000B3B3B3B3B3B3ULL; + mix_id = (mix_id >> 10) | ((mix_id & 0x3FF) << (11 + 32)); - for (ctr = 0; ctr <= 5; ctr++) - { - u8 ret = u64_get_byte(mix_id, ctr); - u8 foobar = ((table1[(ret >> 4) & 0xF]) << 4) | (table1[ret & 0xF]); - mix_id = u64_insert_byte(mix_id, ctr, foobar & 0xff); - } - u64 mix_id_copy2 = mix_id; + for (ctr = 0; ctr <= 5; ctr++) + { + u8 ret = u64_get_byte(mix_id, ctr); + u8 foobar = ((table1[(ret >> 4) & 0xF]) << 4) | (table1[ret & 0xF]); + mix_id = u64_insert_byte(mix_id, ctr, foobar & 0xff); + } + u64 mix_id_copy2 = mix_id; - for (ctr = 0; ctr <= 5; ctr++) - { - u8 ret = u64_get_byte(mix_id_copy2, ctr); - mix_id = u64_insert_byte(mix_id, table2[ctr], ret); - } + for (ctr = 0; ctr <= 5; ctr++) + { + u8 ret = u64_get_byte(mix_id_copy2, ctr); + mix_id = u64_insert_byte(mix_id, table2[ctr], ret); + } - mix_id &= 0x001FFFFFFFFFFFFFULL; - mix_id = (mix_id << 1) | ((mix_id >> 52) & 1); + mix_id &= 0x001FFFFFFFFFFFFFULL; + mix_id = (mix_id << 1) | ((mix_id >> 52) & 1); - mix_id ^= 0x00005E5E5E5E5E5EULL; - mix_id &= 0x001FFFFFFFFFFFFFULL; + mix_id ^= 0x00005E5E5E5E5E5EULL; + mix_id &= 0x001FFFFFFFFFFFFFULL; - *nwc24_id = mix_id; + *nwc24_id = mix_id; - if (mix_id > 9999999999999999ULL) - return WC24_ERR_FATAL; + if (mix_id > 9999999999999999ULL) + return WC24_ERR_FATAL; - return WC24_OK; + return WC24_OK; } static void SaveMacAddress(u8* mac) { - SConfig::GetInstance().m_WirelessMac = MacAddressToString(mac); - SConfig::GetInstance().SaveSettings(); + SConfig::GetInstance().m_WirelessMac = MacAddressToString(mac); + SConfig::GetInstance().SaveSettings(); } static void GetMacAddress(u8* mac) { - // Parse MAC address from config, and generate a new one if it doesn't - // exist or can't be parsed. - std::string wireless_mac = SConfig::GetInstance().m_WirelessMac; + // Parse MAC address from config, and generate a new one if it doesn't + // exist or can't be parsed. + std::string wireless_mac = SConfig::GetInstance().m_WirelessMac; - if (Core::g_want_determinism) - wireless_mac = "12:34:56:78:9a:bc"; + if (Core::g_want_determinism) + wireless_mac = "12:34:56:78:9a:bc"; - if (!StringToMacAddress(wireless_mac, mac)) - { - GenerateMacAddress(IOS, mac); - SaveMacAddress(mac); - if (!wireless_mac.empty()) - { - ERROR_LOG(WII_IPC_NET, "The MAC provided (%s) is invalid. We have "\ - "generated another one for you.", - MacAddressToString(mac).c_str()); - } - } - INFO_LOG(WII_IPC_NET, "Using MAC address: %s", MacAddressToString(mac).c_str()); + if (!StringToMacAddress(wireless_mac, mac)) + { + GenerateMacAddress(IOS, mac); + SaveMacAddress(mac); + if (!wireless_mac.empty()) + { + ERROR_LOG(WII_IPC_NET, "The MAC provided (%s) is invalid. We have " + "generated another one for you.", + MacAddressToString(mac).c_str()); + } + } + INFO_LOG(WII_IPC_NET, "Using MAC address: %s", MacAddressToString(mac).c_str()); } // ********************************************************************************** // Handle /dev/net/ncd/manage requests -CWII_IPC_HLE_Device_net_ncd_manage::CWII_IPC_HLE_Device_net_ncd_manage(u32 _DeviceID, const std::string& _rDeviceName) - : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) +CWII_IPC_HLE_Device_net_ncd_manage::CWII_IPC_HLE_Device_net_ncd_manage( + u32 _DeviceID, const std::string& _rDeviceName) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) { } @@ -353,94 +353,96 @@ CWII_IPC_HLE_Device_net_ncd_manage::~CWII_IPC_HLE_Device_net_ncd_manage() IPCCommandResult CWII_IPC_HLE_Device_net_ncd_manage::Open(u32 _CommandAddress, u32 _Mode) { - INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: Open"); - Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); - m_Active = true; - return GetDefaultReply(); + INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: Open"); + Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); + m_Active = true; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_net_ncd_manage::Close(u32 _CommandAddress, bool _bForce) { - INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: Close"); - if (!_bForce) - Memory::Write_U32(0, _CommandAddress + 4); - m_Active = false; - return GetDefaultReply(); + INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: Close"); + if (!_bForce) + Memory::Write_U32(0, _CommandAddress + 4); + m_Active = false; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_net_ncd_manage::IOCtlV(u32 _CommandAddress) { - u32 return_value = 0; - u32 common_result = 0; - u32 common_vector = 0; + u32 return_value = 0; + u32 common_result = 0; + u32 common_vector = 0; - SIOCtlVBuffer CommandBuffer(_CommandAddress); + SIOCtlVBuffer CommandBuffer(_CommandAddress); - switch (CommandBuffer.Parameter) - { - case IOCTLV_NCD_LOCKWIRELESSDRIVER: - break; + switch (CommandBuffer.Parameter) + { + case IOCTLV_NCD_LOCKWIRELESSDRIVER: + break; - case IOCTLV_NCD_UNLOCKWIRELESSDRIVER: - //Memory::Read_U32(CommandBuffer.InBuffer.at(0).m_Address); - break; + case IOCTLV_NCD_UNLOCKWIRELESSDRIVER: + // Memory::Read_U32(CommandBuffer.InBuffer.at(0).m_Address); + break; - case IOCTLV_NCD_GETCONFIG: - INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: IOCTLV_NCD_GETCONFIG"); - config.WriteToMem(CommandBuffer.PayloadBuffer.at(0).m_Address); - common_vector = 1; - break; + case IOCTLV_NCD_GETCONFIG: + INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: IOCTLV_NCD_GETCONFIG"); + config.WriteToMem(CommandBuffer.PayloadBuffer.at(0).m_Address); + common_vector = 1; + break; - case IOCTLV_NCD_SETCONFIG: - INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: IOCTLV_NCD_SETCONFIG"); - config.ReadFromMem(CommandBuffer.InBuffer.at(0).m_Address); - break; + case IOCTLV_NCD_SETCONFIG: + INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: IOCTLV_NCD_SETCONFIG"); + config.ReadFromMem(CommandBuffer.InBuffer.at(0).m_Address); + break; - case IOCTLV_NCD_READCONFIG: - INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: IOCTLV_NCD_READCONFIG"); - config.ReadConfig(); - config.WriteToMem(CommandBuffer.PayloadBuffer.at(0).m_Address); - common_vector = 1; - break; + case IOCTLV_NCD_READCONFIG: + INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: IOCTLV_NCD_READCONFIG"); + config.ReadConfig(); + config.WriteToMem(CommandBuffer.PayloadBuffer.at(0).m_Address); + common_vector = 1; + break; - case IOCTLV_NCD_WRITECONFIG: - INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: IOCTLV_NCD_WRITECONFIG"); - config.ReadFromMem(CommandBuffer.InBuffer.at(0).m_Address); - config.WriteConfig(); - break; + case IOCTLV_NCD_WRITECONFIG: + INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: IOCTLV_NCD_WRITECONFIG"); + config.ReadFromMem(CommandBuffer.InBuffer.at(0).m_Address); + config.WriteConfig(); + break; - case IOCTLV_NCD_GETLINKSTATUS: - INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: IOCTLV_NCD_GETLINKSTATUS"); - // Always connected - Memory::Write_U32(netcfg_connection_t::LINK_WIRED, CommandBuffer.PayloadBuffer.at(0).m_Address + 4); - break; + case IOCTLV_NCD_GETLINKSTATUS: + INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: IOCTLV_NCD_GETLINKSTATUS"); + // Always connected + Memory::Write_U32(netcfg_connection_t::LINK_WIRED, + CommandBuffer.PayloadBuffer.at(0).m_Address + 4); + break; - case IOCTLV_NCD_GETWIRELESSMACADDRESS: - INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: IOCTLV_NCD_GETWIRELESSMACADDRESS"); + case IOCTLV_NCD_GETWIRELESSMACADDRESS: + INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: IOCTLV_NCD_GETWIRELESSMACADDRESS"); - u8 address[MAC_ADDRESS_SIZE]; - GetMacAddress(address); - Memory::CopyToEmu(CommandBuffer.PayloadBuffer.at(1).m_Address, address, sizeof(address)); - break; + u8 address[MAC_ADDRESS_SIZE]; + GetMacAddress(address); + Memory::CopyToEmu(CommandBuffer.PayloadBuffer.at(1).m_Address, address, sizeof(address)); + break; - default: - INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE IOCtlV: %#x", CommandBuffer.Parameter); - break; - } + default: + INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE IOCtlV: %#x", CommandBuffer.Parameter); + break; + } - Memory::Write_U32(common_result, CommandBuffer.PayloadBuffer.at(common_vector).m_Address); - if (common_vector == 1) - { - Memory::Write_U32(common_result, CommandBuffer.PayloadBuffer.at(common_vector).m_Address + 4); - } - Memory::Write_U32(return_value, _CommandAddress + 4); - return GetDefaultReply(); + Memory::Write_U32(common_result, CommandBuffer.PayloadBuffer.at(common_vector).m_Address); + if (common_vector == 1) + { + Memory::Write_U32(common_result, CommandBuffer.PayloadBuffer.at(common_vector).m_Address + 4); + } + Memory::Write_U32(return_value, _CommandAddress + 4); + return GetDefaultReply(); } // ********************************************************************************** // Handle /dev/net/wd/command requests -CWII_IPC_HLE_Device_net_wd_command::CWII_IPC_HLE_Device_net_wd_command(u32 DeviceID, const std::string& DeviceName) - : IWII_IPC_HLE_Device(DeviceID, DeviceName) +CWII_IPC_HLE_Device_net_wd_command::CWII_IPC_HLE_Device_net_wd_command( + u32 DeviceID, const std::string& DeviceName) + : IWII_IPC_HLE_Device(DeviceID, DeviceName) { } @@ -450,19 +452,19 @@ CWII_IPC_HLE_Device_net_wd_command::~CWII_IPC_HLE_Device_net_wd_command() IPCCommandResult CWII_IPC_HLE_Device_net_wd_command::Open(u32 CommandAddress, u32 Mode) { - INFO_LOG(WII_IPC_NET, "NET_WD_COMMAND: Open"); - Memory::Write_U32(GetDeviceID(), CommandAddress + 4); - m_Active = true; - return GetDefaultReply(); + INFO_LOG(WII_IPC_NET, "NET_WD_COMMAND: Open"); + Memory::Write_U32(GetDeviceID(), CommandAddress + 4); + m_Active = true; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_net_wd_command::Close(u32 CommandAddress, bool Force) { - INFO_LOG(WII_IPC_NET, "NET_WD_COMMAND: Close"); - if (!Force) - Memory::Write_U32(0, CommandAddress + 4); - m_Active = false; - return GetDefaultReply(); + INFO_LOG(WII_IPC_NET, "NET_WD_COMMAND: Close"); + if (!Force) + Memory::Write_U32(0, CommandAddress + 4); + m_Active = false; + return GetDefaultReply(); } // This is just for debugging / playing around. @@ -470,1086 +472,1076 @@ IPCCommandResult CWII_IPC_HLE_Device_net_wd_command::Close(u32 CommandAddress, b // we can talk to the DS. IPCCommandResult CWII_IPC_HLE_Device_net_wd_command::IOCtlV(u32 CommandAddress) { - u32 return_value = 0; + u32 return_value = 0; - SIOCtlVBuffer CommandBuffer(CommandAddress); + SIOCtlVBuffer CommandBuffer(CommandAddress); - switch (CommandBuffer.Parameter) - { - case IOCTLV_WD_SCAN: - { - // Gives parameters detailing type of scan and what to match - // XXX - unused - // ScanInfo *scan = (ScanInfo *)Memory::GetPointer(CommandBuffer.InBuffer.at(0).m_Address); + switch (CommandBuffer.Parameter) + { + case IOCTLV_WD_SCAN: + { + // Gives parameters detailing type of scan and what to match + // XXX - unused + // ScanInfo *scan = (ScanInfo *)Memory::GetPointer(CommandBuffer.InBuffer.at(0).m_Address); - u16* results = (u16*)Memory::GetPointer(CommandBuffer.PayloadBuffer.at(0).m_Address); - // first u16 indicates number of BSSInfo following - results[0] = Common::swap16(1); + u16* results = (u16*)Memory::GetPointer(CommandBuffer.PayloadBuffer.at(0).m_Address); + // first u16 indicates number of BSSInfo following + results[0] = Common::swap16(1); - BSSInfo* bss = (BSSInfo*)&results[1]; - memset(bss, 0, sizeof(BSSInfo)); + BSSInfo* bss = (BSSInfo*)&results[1]; + memset(bss, 0, sizeof(BSSInfo)); - bss->length = Common::swap16(sizeof(BSSInfo)); - bss->rssi = Common::swap16(0xffff); + bss->length = Common::swap16(sizeof(BSSInfo)); + bss->rssi = Common::swap16(0xffff); - for (int i = 0; i < BSSID_SIZE; ++i) - bss->bssid[i] = i; + for (int i = 0; i < BSSID_SIZE; ++i) + bss->bssid[i] = i; - const char* ssid = "dolphin-emu"; - strcpy((char*)bss->ssid, ssid); - bss->ssid_length = Common::swap16((u16)strlen(ssid)); + const char* ssid = "dolphin-emu"; + strcpy((char*)bss->ssid, ssid); + bss->ssid_length = Common::swap16((u16)strlen(ssid)); - bss->channel = Common::swap16(2); - } - break; + bss->channel = Common::swap16(2); + } + break; - case IOCTLV_WD_GET_INFO: - { - Info* info = (Info*)Memory::GetPointer(CommandBuffer.PayloadBuffer.at(0).m_Address); - memset(info, 0, sizeof(Info)); - // Probably used to disallow certain channels? - memcpy(info->country, "US", 2); - info->ntr_allowed_channels = Common::swap16(0xfffe); + case IOCTLV_WD_GET_INFO: + { + Info* info = (Info*)Memory::GetPointer(CommandBuffer.PayloadBuffer.at(0).m_Address); + memset(info, 0, sizeof(Info)); + // Probably used to disallow certain channels? + memcpy(info->country, "US", 2); + info->ntr_allowed_channels = Common::swap16(0xfffe); - u8 address[MAC_ADDRESS_SIZE]; - GetMacAddress(address); - memcpy(info->mac, address, sizeof(info->mac)); - } - break; + u8 address[MAC_ADDRESS_SIZE]; + GetMacAddress(address); + memcpy(info->mac, address, sizeof(info->mac)); + } + break; - case IOCTLV_WD_GET_MODE: - case IOCTLV_WD_SET_LINKSTATE: - case IOCTLV_WD_GET_LINKSTATE: - case IOCTLV_WD_SET_CONFIG: - case IOCTLV_WD_GET_CONFIG: - case IOCTLV_WD_CHANGE_BEACON: - case IOCTLV_WD_DISASSOC: - case IOCTLV_WD_MP_SEND_FRAME: - case IOCTLV_WD_SEND_FRAME: - case IOCTLV_WD_CALL_WL: - case IOCTLV_WD_MEASURE_CHANNEL: - case IOCTLV_WD_GET_LASTERROR: - case IOCTLV_WD_CHANGE_GAMEINFO: - case IOCTLV_WD_CHANGE_VTSF: - case IOCTLV_WD_RECV_FRAME: - case IOCTLV_WD_RECV_NOTIFICATION: - default: - INFO_LOG(WII_IPC_NET, "NET_WD_COMMAND IOCtlV %#x in %i out %i", - CommandBuffer.Parameter, CommandBuffer.NumberInBuffer, CommandBuffer.NumberPayloadBuffer); - for (u32 i = 0; i < CommandBuffer.NumberInBuffer; ++i) - { - INFO_LOG(WII_IPC_NET, "in %i addr %x size %i", i, - CommandBuffer.InBuffer.at(i).m_Address, CommandBuffer.InBuffer.at(i).m_Size); - INFO_LOG(WII_IPC_NET, "%s", - ArrayToString( - Memory::GetPointer(CommandBuffer.InBuffer.at(i).m_Address), - CommandBuffer.InBuffer.at(i).m_Size).c_str() - ); - } - for (u32 i = 0; i < CommandBuffer.NumberPayloadBuffer; ++i) - { - INFO_LOG(WII_IPC_NET, "out %i addr %x size %i", i, - CommandBuffer.PayloadBuffer.at(i).m_Address, CommandBuffer.PayloadBuffer.at(i).m_Size); - } - break; - } + case IOCTLV_WD_GET_MODE: + case IOCTLV_WD_SET_LINKSTATE: + case IOCTLV_WD_GET_LINKSTATE: + case IOCTLV_WD_SET_CONFIG: + case IOCTLV_WD_GET_CONFIG: + case IOCTLV_WD_CHANGE_BEACON: + case IOCTLV_WD_DISASSOC: + case IOCTLV_WD_MP_SEND_FRAME: + case IOCTLV_WD_SEND_FRAME: + case IOCTLV_WD_CALL_WL: + case IOCTLV_WD_MEASURE_CHANNEL: + case IOCTLV_WD_GET_LASTERROR: + case IOCTLV_WD_CHANGE_GAMEINFO: + case IOCTLV_WD_CHANGE_VTSF: + case IOCTLV_WD_RECV_FRAME: + case IOCTLV_WD_RECV_NOTIFICATION: + default: + INFO_LOG(WII_IPC_NET, "NET_WD_COMMAND IOCtlV %#x in %i out %i", CommandBuffer.Parameter, + CommandBuffer.NumberInBuffer, CommandBuffer.NumberPayloadBuffer); + for (u32 i = 0; i < CommandBuffer.NumberInBuffer; ++i) + { + INFO_LOG(WII_IPC_NET, "in %i addr %x size %i", i, CommandBuffer.InBuffer.at(i).m_Address, + CommandBuffer.InBuffer.at(i).m_Size); + INFO_LOG(WII_IPC_NET, "%s", + ArrayToString(Memory::GetPointer(CommandBuffer.InBuffer.at(i).m_Address), + CommandBuffer.InBuffer.at(i).m_Size) + .c_str()); + } + for (u32 i = 0; i < CommandBuffer.NumberPayloadBuffer; ++i) + { + INFO_LOG(WII_IPC_NET, "out %i addr %x size %i", i, + CommandBuffer.PayloadBuffer.at(i).m_Address, + CommandBuffer.PayloadBuffer.at(i).m_Size); + } + break; + } - Memory::Write_U32(return_value, CommandAddress + 4); - return GetDefaultReply(); + Memory::Write_U32(return_value, CommandAddress + 4); + return GetDefaultReply(); } // ********************************************************************************** // Handle /dev/net/ip/top requests -CWII_IPC_HLE_Device_net_ip_top::CWII_IPC_HLE_Device_net_ip_top(u32 _DeviceID, const std::string& _rDeviceName) - : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) +CWII_IPC_HLE_Device_net_ip_top::CWII_IPC_HLE_Device_net_ip_top(u32 _DeviceID, + const std::string& _rDeviceName) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) { #ifdef _WIN32 - int ret = WSAStartup(MAKEWORD(2,2), &InitData); - INFO_LOG(WII_IPC_NET, "WSAStartup: %d", ret); + int ret = WSAStartup(MAKEWORD(2, 2), &InitData); + INFO_LOG(WII_IPC_NET, "WSAStartup: %d", ret); #endif } CWII_IPC_HLE_Device_net_ip_top::~CWII_IPC_HLE_Device_net_ip_top() { #ifdef _WIN32 - WSACleanup(); + WSACleanup(); #endif } IPCCommandResult CWII_IPC_HLE_Device_net_ip_top::Open(u32 _CommandAddress, u32 _Mode) { - INFO_LOG(WII_IPC_NET, "NET_IP_TOP: Open"); - Memory::Write_U32(GetDeviceID(), _CommandAddress+4); - m_Active = true; - return GetDefaultReply(); + INFO_LOG(WII_IPC_NET, "NET_IP_TOP: Open"); + Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); + m_Active = true; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_net_ip_top::Close(u32 _CommandAddress, bool _bForce) { - INFO_LOG(WII_IPC_NET, "NET_IP_TOP: Close"); - if (!_bForce) - Memory::Write_U32(0, _CommandAddress + 4); - m_Active = false; - return GetDefaultReply(); + INFO_LOG(WII_IPC_NET, "NET_IP_TOP: Close"); + if (!_bForce) + Memory::Write_U32(0, _CommandAddress + 4); + m_Active = false; + return GetDefaultReply(); } static int inet_pton(const char* src, unsigned char* dst) { - int saw_digit, octets; - char ch; - unsigned char tmp[4], *tp; + int saw_digit, octets; + char ch; + unsigned char tmp[4], *tp; - saw_digit = 0; - octets = 0; - *(tp = tmp) = 0; - while ((ch = *src++) != '\0') - { - if (ch >= '0' && ch <= '9') - { - unsigned int newt = (*tp * 10) + (ch - '0'); + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') + { + if (ch >= '0' && ch <= '9') + { + unsigned int newt = (*tp * 10) + (ch - '0'); - if (newt > 255) - return 0; - *tp = newt; - if (!saw_digit) - { - if (++octets > 4) - return 0; - saw_digit = 1; - } - } - else if (ch == '.' && saw_digit) - { - if (octets == 4) - return 0; - *++tp = 0; - saw_digit = 0; - } - else - { - return 0; - } - } - if (octets < 4) - return 0; - memcpy(dst, tmp, 4); - return 1; + if (newt > 255) + return 0; + *tp = newt; + if (!saw_digit) + { + if (++octets > 4) + return 0; + saw_digit = 1; + } + } + else if (ch == '.' && saw_digit) + { + if (octets == 4) + return 0; + *++tp = 0; + saw_digit = 0; + } + else + { + return 0; + } + } + if (octets < 4) + return 0; + memcpy(dst, tmp, 4); + return 1; } // Maps SOCKOPT level from native to Wii -static unsigned int opt_level_mapping[][2] = { - { SOL_SOCKET, 0xFFFF } -}; +static unsigned int opt_level_mapping[][2] = {{SOL_SOCKET, 0xFFFF}}; // Maps SOCKOPT optname from native to Wii static unsigned int opt_name_mapping[][2] = { - { SO_REUSEADDR, 0x4 }, - { SO_SNDBUF, 0x1001 }, - { SO_RCVBUF, 0x1002 }, - { SO_ERROR, 0x1009 } -}; + {SO_REUSEADDR, 0x4}, {SO_SNDBUF, 0x1001}, {SO_RCVBUF, 0x1002}, {SO_ERROR, 0x1009}}; IPCCommandResult CWII_IPC_HLE_Device_net_ip_top::IOCtl(u32 _CommandAddress) { - if (Core::g_want_determinism) - { - Memory::Write_U32(-1, _CommandAddress + 4); - return GetDefaultReply(); - } + if (Core::g_want_determinism) + { + Memory::Write_U32(-1, _CommandAddress + 4); + return GetDefaultReply(); + } + u32 Command = Memory::Read_U32(_CommandAddress + 0x0C); + u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); + u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); + u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); + u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); - u32 Command = Memory::Read_U32(_CommandAddress + 0x0C); - u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); - u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); - u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); + u32 ReturnValue = 0; + switch (Command) + { + case IOCTL_SO_STARTUP: + { + INFO_LOG(WII_IPC_NET, "IOCTL_SO_STARTUP " + "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); + break; + } + case IOCTL_SO_SOCKET: + { + u32 af = Memory::Read_U32(BufferIn); + u32 type = Memory::Read_U32(BufferIn + 0x04); + u32 prot = Memory::Read_U32(BufferIn + 0x08); - u32 ReturnValue = 0; - switch (Command) - { - case IOCTL_SO_STARTUP: - { - INFO_LOG(WII_IPC_NET, "IOCTL_SO_STARTUP " - "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - BufferIn, BufferInSize, BufferOut, BufferOutSize); - break; - } - case IOCTL_SO_SOCKET: - { - u32 af = Memory::Read_U32(BufferIn); - u32 type = Memory::Read_U32(BufferIn + 0x04); - u32 prot = Memory::Read_U32(BufferIn + 0x08); + WiiSockMan& sm = WiiSockMan::GetInstance(); + ReturnValue = sm.NewSocket(af, type, prot); + INFO_LOG(WII_IPC_NET, "IOCTL_SO_SOCKET " + "Socket: %08x (%d,%d,%d), BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + ReturnValue, af, type, prot, BufferIn, BufferInSize, BufferOut, BufferOutSize); + break; + } + case IOCTL_SO_ICMPSOCKET: + { + u32 pf = Memory::Read_U32(BufferIn); - WiiSockMan &sm = WiiSockMan::GetInstance(); - ReturnValue = sm.NewSocket(af, type, prot); - INFO_LOG(WII_IPC_NET, "IOCTL_SO_SOCKET " - "Socket: %08x (%d,%d,%d), BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - ReturnValue, af, type, prot, BufferIn, BufferInSize, BufferOut, BufferOutSize); - break; - } - case IOCTL_SO_ICMPSOCKET: - { - u32 pf = Memory::Read_U32(BufferIn); + WiiSockMan& sm = WiiSockMan::GetInstance(); + ReturnValue = sm.NewSocket(pf, SOCK_RAW, IPPROTO_ICMP); + INFO_LOG(WII_IPC_NET, "IOCTL_SO_ICMPSOCKET(%x) %d", pf, ReturnValue); + break; + } + case IOCTL_SO_CLOSE: + case IOCTL_SO_ICMPCLOSE: + { + u32 fd = Memory::Read_U32(BufferIn); + WiiSockMan& sm = WiiSockMan::GetInstance(); + ReturnValue = sm.DeleteSocket(fd); + DEBUG_LOG(WII_IPC_NET, "%s(%x) %x", + Command == IOCTL_SO_ICMPCLOSE ? "IOCTL_SO_ICMPCLOSE" : "IOCTL_SO_CLOSE", fd, + ReturnValue); + break; + } + case IOCTL_SO_ACCEPT: + case IOCTL_SO_BIND: + case IOCTL_SO_CONNECT: + case IOCTL_SO_FCNTL: + { + u32 fd = Memory::Read_U32(BufferIn); + WiiSockMan& sm = WiiSockMan::GetInstance(); + sm.DoSock(fd, _CommandAddress, (NET_IOCTL)Command); + return GetNoReply(); + } + ///////////////////////////////////////////////////////////// + // TODO: Tidy all below // + ///////////////////////////////////////////////////////////// + case IOCTL_SO_SHUTDOWN: + { + INFO_LOG(WII_IPC_NET, "IOCTL_SO_SHUTDOWN " + "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); - WiiSockMan &sm = WiiSockMan::GetInstance(); - ReturnValue = sm.NewSocket(pf, SOCK_RAW, IPPROTO_ICMP); - INFO_LOG(WII_IPC_NET, "IOCTL_SO_ICMPSOCKET(%x) %d", pf, ReturnValue); - break; - } - case IOCTL_SO_CLOSE: - case IOCTL_SO_ICMPCLOSE: - { - u32 fd = Memory::Read_U32(BufferIn); - WiiSockMan &sm = WiiSockMan::GetInstance(); - ReturnValue = sm.DeleteSocket(fd); - DEBUG_LOG(WII_IPC_NET, "%s(%x) %x", - Command == IOCTL_SO_ICMPCLOSE ? "IOCTL_SO_ICMPCLOSE" : "IOCTL_SO_CLOSE", - fd, ReturnValue); - break; - } - case IOCTL_SO_ACCEPT: - case IOCTL_SO_BIND: - case IOCTL_SO_CONNECT: - case IOCTL_SO_FCNTL: - { - u32 fd = Memory::Read_U32(BufferIn); - WiiSockMan &sm = WiiSockMan::GetInstance(); - sm.DoSock(fd, _CommandAddress, (NET_IOCTL)Command); - return GetNoReply(); - } - ///////////////////////////////////////////////////////////// - // TODO: Tidy all below // - ///////////////////////////////////////////////////////////// - case IOCTL_SO_SHUTDOWN: - { - INFO_LOG(WII_IPC_NET, "IOCTL_SO_SHUTDOWN " - "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - BufferIn, BufferInSize, BufferOut, BufferOutSize); + u32 fd = Memory::Read_U32(BufferIn); + u32 how = Memory::Read_U32(BufferIn + 4); + int ret = shutdown(fd, how); + ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_SHUTDOWN", false); + break; + } + case IOCTL_SO_LISTEN: + { + u32 fd = Memory::Read_U32(BufferIn); + u32 BACKLOG = Memory::Read_U32(BufferIn + 0x04); + u32 ret = listen(fd, BACKLOG); + ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_LISTEN", false); + INFO_LOG(WII_IPC_NET, "IOCTL_SO_LISTEN = %d " + "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + ReturnValue, BufferIn, BufferInSize, BufferOut, BufferOutSize); + break; + } + case IOCTL_SO_GETSOCKOPT: + { + u32 fd = Memory::Read_U32(BufferOut); + u32 level = Memory::Read_U32(BufferOut + 4); + u32 optname = Memory::Read_U32(BufferOut + 8); - u32 fd = Memory::Read_U32(BufferIn); - u32 how = Memory::Read_U32(BufferIn+4); - int ret = shutdown(fd, how); - ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_SHUTDOWN", false); - break; - } - case IOCTL_SO_LISTEN: - { + INFO_LOG(WII_IPC_NET, "IOCTL_SO_GETSOCKOPT(%08x, %08x, %08x)" + "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + fd, level, optname, BufferIn, BufferInSize, BufferOut, BufferOutSize); - u32 fd = Memory::Read_U32(BufferIn); - u32 BACKLOG = Memory::Read_U32(BufferIn + 0x04); - u32 ret = listen(fd, BACKLOG); - ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_LISTEN", false); - INFO_LOG(WII_IPC_NET, "IOCTL_SO_LISTEN = %d " - "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - ReturnValue, BufferIn, BufferInSize, BufferOut, BufferOutSize); - break; - } - case IOCTL_SO_GETSOCKOPT: - { - u32 fd = Memory::Read_U32(BufferOut); - u32 level = Memory::Read_U32(BufferOut + 4); - u32 optname = Memory::Read_U32(BufferOut + 8); + // Do the level/optname translation + int nat_level = -1, nat_optname = -1; - INFO_LOG(WII_IPC_NET,"IOCTL_SO_GETSOCKOPT(%08x, %08x, %08x)" - "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - fd, level, optname, - BufferIn, BufferInSize, BufferOut, BufferOutSize); + for (auto& map : opt_level_mapping) + if (level == map[1]) + nat_level = map[0]; - // Do the level/optname translation - int nat_level = -1, nat_optname = -1; + for (auto& map : opt_name_mapping) + if (optname == map[1]) + nat_optname = map[0]; - for (auto& map : opt_level_mapping) - if (level == map[1]) - nat_level = map[0]; + u8 optval[20]; + u32 optlen = 4; - for (auto& map : opt_name_mapping) - if (optname == map[1]) - nat_optname = map[0]; + int ret = getsockopt(fd, nat_level, nat_optname, (char*)&optval, (socklen_t*)&optlen); + ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_GETSOCKOPT", false); - u8 optval[20]; - u32 optlen = 4; + Memory::Write_U32(optlen, BufferOut + 0xC); + Memory::CopyToEmu(BufferOut + 0x10, optval, optlen); - int ret = getsockopt(fd, nat_level, nat_optname, (char*)&optval, (socklen_t*)&optlen); - ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_GETSOCKOPT", false); + if (optname == SO_ERROR) + { + s32 last_error = WiiSockMan::GetInstance().GetLastNetError(); + Memory::Write_U32(sizeof(s32), BufferOut + 0xC); + Memory::Write_U32(last_error, BufferOut + 0x10); + } + break; + } - Memory::Write_U32(optlen, BufferOut + 0xC); - Memory::CopyToEmu(BufferOut + 0x10, optval, optlen); + case IOCTL_SO_SETSOCKOPT: + { + u32 fd = Memory::Read_U32(BufferIn); + u32 level = Memory::Read_U32(BufferIn + 4); + u32 optname = Memory::Read_U32(BufferIn + 8); + u32 optlen = Memory::Read_U32(BufferIn + 0xc); + u8 optval[20]; + optlen = std::min(optlen, (u32)sizeof(optval)); + Memory::CopyFromEmu(optval, BufferIn + 0x10, optlen); - if (optname == SO_ERROR) - { - s32 last_error = WiiSockMan::GetInstance().GetLastNetError(); + INFO_LOG(WII_IPC_NET, "IOCTL_SO_SETSOCKOPT(%08x, %08x, %08x, %08x) " + "BufferIn: (%08x, %i), BufferOut: (%08x, %i)" + "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx " + "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx", + fd, level, optname, optlen, BufferIn, BufferInSize, BufferOut, BufferOutSize, + optval[0], optval[1], optval[2], optval[3], optval[4], optval[5], optval[6], optval[7], + optval[8], optval[9], optval[10], optval[11], optval[12], optval[13], optval[14], + optval[15], optval[16], optval[17], optval[18], optval[19]); - Memory::Write_U32(sizeof(s32), BufferOut + 0xC); - Memory::Write_U32(last_error, BufferOut + 0x10); - } - break; - } + // TODO: bug booto about this, 0x2005 most likely timeout related, default value on Wii is , + // 0x2001 is most likely tcpnodelay + if (level == 6 && (optname == 0x2005 || optname == 0x2001)) + { + ReturnValue = 0; + break; + } - case IOCTL_SO_SETSOCKOPT: - { - u32 fd = Memory::Read_U32(BufferIn); - u32 level = Memory::Read_U32(BufferIn + 4); - u32 optname = Memory::Read_U32(BufferIn + 8); - u32 optlen = Memory::Read_U32(BufferIn + 0xc); - u8 optval[20]; - optlen = std::min(optlen, (u32)sizeof(optval)); - Memory::CopyFromEmu(optval, BufferIn + 0x10, optlen); + // Do the level/optname translation + int nat_level = -1, nat_optname = -1; - INFO_LOG(WII_IPC_NET, "IOCTL_SO_SETSOCKOPT(%08x, %08x, %08x, %08x) " - "BufferIn: (%08x, %i), BufferOut: (%08x, %i)" - "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx", - fd, level, optname, optlen, BufferIn, BufferInSize, BufferOut, BufferOutSize, optval[0], optval[1], optval[2], optval[3], - optval[4], optval[5], optval[6], optval[7], optval[8], optval[9], optval[10], optval[11], optval[12], optval[13], optval[14], - optval[15], optval[16], optval[17], optval[18], optval[19]); + for (auto& map : opt_level_mapping) + if (level == map[1]) + nat_level = map[0]; - //TODO: bug booto about this, 0x2005 most likely timeout related, default value on Wii is , 0x2001 is most likely tcpnodelay - if (level == 6 && (optname == 0x2005 || optname == 0x2001)) - { - ReturnValue = 0; - break; - } + for (auto& map : opt_name_mapping) + if (optname == map[1]) + nat_optname = map[0]; - // Do the level/optname translation - int nat_level = -1, nat_optname = -1; + if (nat_level == -1 || nat_optname == -1) + { + INFO_LOG(WII_IPC_NET, "SO_SETSOCKOPT: unknown level %d or optname %d", level, optname); - for (auto& map : opt_level_mapping) - if (level == map[1]) - nat_level = map[0]; + // Default to the given level/optname. They match on Windows... + nat_level = level; + nat_optname = optname; + } - for (auto& map : opt_name_mapping) - if (optname == map[1]) - nat_optname = map[0]; + int ret = setsockopt(fd, nat_level, nat_optname, (char*)optval, optlen); + ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_SETSOCKOPT", false); + break; + } + case IOCTL_SO_GETSOCKNAME: + { + u32 fd = Memory::Read_U32(BufferIn); - if (nat_level == -1 || nat_optname == -1) - { - INFO_LOG(WII_IPC_NET, "SO_SETSOCKOPT: unknown level %d or optname %d", level, optname); + INFO_LOG(WII_IPC_NET, "IOCTL_SO_GETSOCKNAME " + "Socket: %08X, BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + fd, BufferIn, BufferInSize, BufferOut, BufferOutSize); - // Default to the given level/optname. They match on Windows... - nat_level = level; - nat_optname = optname; - } + sockaddr sa; + socklen_t sa_len; + sa_len = sizeof(sa); + int ret = getsockname(fd, &sa, &sa_len); - int ret = setsockopt(fd, nat_level, nat_optname, (char*)optval, optlen); - ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_SETSOCKOPT", false); - break; - } - case IOCTL_SO_GETSOCKNAME: - { - u32 fd = Memory::Read_U32(BufferIn); + Memory::Write_U8(BufferOutSize, BufferOut); + Memory::Write_U8(sa.sa_family & 0xFF, BufferOut + 1); + Memory::CopyToEmu(BufferOut + 2, &sa.sa_data, BufferOutSize - 2); + ReturnValue = ret; + break; + } + case IOCTL_SO_GETPEERNAME: + { + u32 fd = Memory::Read_U32(BufferIn); - INFO_LOG(WII_IPC_NET, "IOCTL_SO_GETSOCKNAME " - "Socket: %08X, BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - fd, BufferIn, BufferInSize, BufferOut, BufferOutSize); + sockaddr sa; + socklen_t sa_len; + sa_len = sizeof(sa); - sockaddr sa; - socklen_t sa_len; - sa_len = sizeof(sa); - int ret = getsockname(fd, &sa, &sa_len); + int ret = getpeername(fd, &sa, &sa_len); - Memory::Write_U8(BufferOutSize, BufferOut); - Memory::Write_U8(sa.sa_family & 0xFF, BufferOut + 1); - Memory::CopyToEmu(BufferOut + 2, &sa.sa_data, BufferOutSize - 2); - ReturnValue = ret; - break; - } - case IOCTL_SO_GETPEERNAME: - { - u32 fd = Memory::Read_U32(BufferIn); + Memory::Write_U8(BufferOutSize, BufferOut); + Memory::Write_U8(AF_INET, BufferOut + 1); + Memory::CopyToEmu(BufferOut + 2, &sa.sa_data, BufferOutSize - 2); - sockaddr sa; - socklen_t sa_len; - sa_len = sizeof(sa); + INFO_LOG(WII_IPC_NET, "IOCTL_SO_GETPEERNAME(%x)", fd); - int ret = getpeername(fd, &sa, &sa_len); + ReturnValue = ret; + break; + } - Memory::Write_U8(BufferOutSize, BufferOut); - Memory::Write_U8(AF_INET, BufferOut + 1); - Memory::CopyToEmu(BufferOut + 2, &sa.sa_data, BufferOutSize - 2); - - INFO_LOG(WII_IPC_NET, "IOCTL_SO_GETPEERNAME(%x)", fd); - - ReturnValue = ret; - break; - } - - case IOCTL_SO_GETHOSTID: - { - INFO_LOG(WII_IPC_NET, "IOCTL_SO_GETHOSTID " - "(BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - BufferIn, BufferInSize, BufferOut, BufferOutSize); + case IOCTL_SO_GETHOSTID: + { + INFO_LOG(WII_IPC_NET, "IOCTL_SO_GETHOSTID " + "(BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); #ifdef _WIN32 - DWORD forwardTableSize, ipTableSize, result; - DWORD ifIndex = -1; - std::unique_ptr forwardTable; - std::unique_ptr ipTable; + DWORD forwardTableSize, ipTableSize, result; + DWORD ifIndex = -1; + std::unique_ptr forwardTable; + std::unique_ptr ipTable; - forwardTableSize = 0; - if (GetIpForwardTable(nullptr, &forwardTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) - { - forwardTable = std::unique_ptr((PMIB_IPFORWARDTABLE)operator new(forwardTableSize)); - } + forwardTableSize = 0; + if (GetIpForwardTable(nullptr, &forwardTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) + { + forwardTable = + std::unique_ptr((PMIB_IPFORWARDTABLE) operator new(forwardTableSize)); + } - ipTableSize = 0; - if (GetIpAddrTable(nullptr, &ipTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) - { - ipTable = std::unique_ptr((PMIB_IPADDRTABLE)operator new(ipTableSize)); - } + ipTableSize = 0; + if (GetIpAddrTable(nullptr, &ipTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) + { + ipTable = std::unique_ptr((PMIB_IPADDRTABLE) operator new(ipTableSize)); + } - // find the interface IP used for the default route and use that - result = GetIpForwardTable(forwardTable.get(), &forwardTableSize, FALSE); - while (result == NO_ERROR || result == ERROR_MORE_DATA) // can return ERROR_MORE_DATA on XP even after the first call - { - for (DWORD i = 0; i < forwardTable->dwNumEntries; ++i) - { - if (forwardTable->table[i].dwForwardDest == 0) - { - ifIndex = forwardTable->table[i].dwForwardIfIndex; - break; - } - } + // find the interface IP used for the default route and use that + result = GetIpForwardTable(forwardTable.get(), &forwardTableSize, FALSE); + while (result == NO_ERROR || + result == ERROR_MORE_DATA) // can return ERROR_MORE_DATA on XP even after the first call + { + for (DWORD i = 0; i < forwardTable->dwNumEntries; ++i) + { + if (forwardTable->table[i].dwForwardDest == 0) + { + ifIndex = forwardTable->table[i].dwForwardIfIndex; + break; + } + } - if (result == NO_ERROR || ifIndex != -1) - break; + if (result == NO_ERROR || ifIndex != -1) + break; - result = GetIpForwardTable(forwardTable.get(), &forwardTableSize, FALSE); - } + result = GetIpForwardTable(forwardTable.get(), &forwardTableSize, FALSE); + } - if (ifIndex != -1 && GetIpAddrTable(ipTable.get(), &ipTableSize, FALSE) == NO_ERROR) - { - for (DWORD i = 0; i < ipTable->dwNumEntries; ++i) - { - if (ipTable->table[i].dwIndex == ifIndex) - { - ReturnValue = Common::swap32(ipTable->table[i].dwAddr); - break; - } - } - } + if (ifIndex != -1 && GetIpAddrTable(ipTable.get(), &ipTableSize, FALSE) == NO_ERROR) + { + for (DWORD i = 0; i < ipTable->dwNumEntries; ++i) + { + if (ipTable->table[i].dwIndex == ifIndex) + { + ReturnValue = Common::swap32(ipTable->table[i].dwAddr); + break; + } + } + } #endif - // default placeholder, in case of failure - if (ReturnValue == 0) - ReturnValue = 192 << 24 | 168 << 16 | 1 << 8 | 150; - break; - } + // default placeholder, in case of failure + if (ReturnValue == 0) + ReturnValue = 192 << 24 | 168 << 16 | 1 << 8 | 150; + break; + } - case IOCTL_SO_INETATON: - { - std::string hostname = Memory::GetString(BufferIn); - struct hostent* remoteHost = gethostbyname(hostname.c_str()); + case IOCTL_SO_INETATON: + { + std::string hostname = Memory::GetString(BufferIn); + struct hostent* remoteHost = gethostbyname(hostname.c_str()); - if (remoteHost == nullptr || remoteHost->h_addr_list == nullptr || remoteHost->h_addr_list[0] == nullptr) - { - INFO_LOG(WII_IPC_NET, "IOCTL_SO_INETATON = -1 " - "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: None", - hostname.c_str(), BufferIn, BufferInSize, BufferOut, BufferOutSize); - ReturnValue = 0; - } - else - { - Memory::Write_U32(Common::swap32(*(u32*)remoteHost->h_addr_list[0]), BufferOut); - INFO_LOG(WII_IPC_NET, "IOCTL_SO_INETATON = 0 " - "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: %08X", - hostname.c_str(), BufferIn, BufferInSize, BufferOut, BufferOutSize, - Common::swap32(*(u32*)remoteHost->h_addr_list[0])); - ReturnValue = 1; - } - break; - } + if (remoteHost == nullptr || remoteHost->h_addr_list == nullptr || + remoteHost->h_addr_list[0] == nullptr) + { + INFO_LOG(WII_IPC_NET, "IOCTL_SO_INETATON = -1 " + "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: None", + hostname.c_str(), BufferIn, BufferInSize, BufferOut, BufferOutSize); + ReturnValue = 0; + } + else + { + Memory::Write_U32(Common::swap32(*(u32*)remoteHost->h_addr_list[0]), BufferOut); + INFO_LOG(WII_IPC_NET, "IOCTL_SO_INETATON = 0 " + "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: %08X", + hostname.c_str(), BufferIn, BufferInSize, BufferOut, BufferOutSize, + Common::swap32(*(u32*)remoteHost->h_addr_list[0])); + ReturnValue = 1; + } + break; + } - case IOCTL_SO_INETPTON: - { - std::string address = Memory::GetString(BufferIn); - INFO_LOG(WII_IPC_NET, "IOCTL_SO_INETPTON " - "(Translating: %s)", address.c_str()); - ReturnValue = inet_pton(address.c_str(), Memory::GetPointer(BufferOut + 4)); - break; - } + case IOCTL_SO_INETPTON: + { + std::string address = Memory::GetString(BufferIn); + INFO_LOG(WII_IPC_NET, "IOCTL_SO_INETPTON " + "(Translating: %s)", + address.c_str()); + ReturnValue = inet_pton(address.c_str(), Memory::GetPointer(BufferOut + 4)); + break; + } - case IOCTL_SO_INETNTOP: - { - //u32 af = Memory::Read_U32(BufferIn); - //u32 validAddress = Memory::Read_U32(BufferIn + 4); - //u32 src = Memory::Read_U32(BufferIn + 8); - char ip_s[16]; - sprintf(ip_s, "%i.%i.%i.%i", - Memory::Read_U8(BufferIn + 8), - Memory::Read_U8(BufferIn + 8 + 1), - Memory::Read_U8(BufferIn + 8 + 2), - Memory::Read_U8(BufferIn + 8 + 3) - ); - INFO_LOG(WII_IPC_NET, "IOCTL_SO_INETNTOP %s", ip_s); - Memory::Memset(BufferOut, 0, BufferOutSize); - Memory::CopyToEmu(BufferOut, (u8*)ip_s, strlen(ip_s)); - break; - } + case IOCTL_SO_INETNTOP: + { + // u32 af = Memory::Read_U32(BufferIn); + // u32 validAddress = Memory::Read_U32(BufferIn + 4); + // u32 src = Memory::Read_U32(BufferIn + 8); + char ip_s[16]; + sprintf(ip_s, "%i.%i.%i.%i", Memory::Read_U8(BufferIn + 8), Memory::Read_U8(BufferIn + 8 + 1), + Memory::Read_U8(BufferIn + 8 + 2), Memory::Read_U8(BufferIn + 8 + 3)); + INFO_LOG(WII_IPC_NET, "IOCTL_SO_INETNTOP %s", ip_s); + Memory::Memset(BufferOut, 0, BufferOutSize); + Memory::CopyToEmu(BufferOut, (u8*)ip_s, strlen(ip_s)); + break; + } - case IOCTL_SO_POLL: - { - // Map Wii/native poll events types - struct - { - int native; - int wii; - } mapping[] = - { - { POLLRDNORM, 0x0001 }, - { POLLRDBAND, 0x0002 }, - { POLLPRI, 0x0004 }, - { POLLWRNORM, 0x0008 }, - { POLLWRBAND, 0x0010 }, - { POLLERR, 0x0020 }, - { POLLHUP, 0x0040 }, - { POLLNVAL, 0x0080 }, - }; + case IOCTL_SO_POLL: + { + // Map Wii/native poll events types + struct + { + int native; + int wii; + } mapping[] = { + {POLLRDNORM, 0x0001}, {POLLRDBAND, 0x0002}, {POLLPRI, 0x0004}, {POLLWRNORM, 0x0008}, + {POLLWRBAND, 0x0010}, {POLLERR, 0x0020}, {POLLHUP, 0x0040}, {POLLNVAL, 0x0080}, + }; - u32 unknown = Memory::Read_U32(BufferIn); - u32 timeout = Memory::Read_U32(BufferIn + 4); + u32 unknown = Memory::Read_U32(BufferIn); + u32 timeout = Memory::Read_U32(BufferIn + 4); - int nfds = BufferOutSize / 0xc; - if (nfds == 0) - ERROR_LOG(WII_IPC_NET, "Hidden POLL"); + int nfds = BufferOutSize / 0xc; + if (nfds == 0) + ERROR_LOG(WII_IPC_NET, "Hidden POLL"); - std::vector ufds(nfds); + std::vector ufds(nfds); - for (int i = 0; i < nfds; ++i) - { - ufds[i].fd = Memory::Read_U32(BufferOut + 0xc*i); //fd - int events = Memory::Read_U32(BufferOut + 0xc*i + 4); //events - ufds[i].revents = Memory::Read_U32(BufferOut + 0xc*i + 8); //revents + for (int i = 0; i < nfds; ++i) + { + ufds[i].fd = Memory::Read_U32(BufferOut + 0xc * i); // fd + int events = Memory::Read_U32(BufferOut + 0xc * i + 4); // events + ufds[i].revents = Memory::Read_U32(BufferOut + 0xc * i + 8); // revents - // Translate Wii to native events - int unhandled_events = events; - ufds[i].events = 0; - for (auto& map : mapping) - { - if (events & map.wii) - ufds[i].events |= map.native; - unhandled_events &= ~map.wii; - } - DEBUG_LOG(WII_IPC_NET, "IOCTL_SO_POLL(%d) " - "Sock: %08x, Unknown: %08x, Events: %08x, " - "NativeEvents: %08x", - i, ufds[i].fd, unknown, events, ufds[i].events - ); + // Translate Wii to native events + int unhandled_events = events; + ufds[i].events = 0; + for (auto& map : mapping) + { + if (events & map.wii) + ufds[i].events |= map.native; + unhandled_events &= ~map.wii; + } + DEBUG_LOG(WII_IPC_NET, "IOCTL_SO_POLL(%d) " + "Sock: %08x, Unknown: %08x, Events: %08x, " + "NativeEvents: %08x", + i, ufds[i].fd, unknown, events, ufds[i].events); - // Do not pass return-only events to the native poll - ufds[i].events &= ~(POLLERR | POLLHUP | POLLNVAL | UNSUPPORTED_WSAPOLL); + // Do not pass return-only events to the native poll + ufds[i].events &= ~(POLLERR | POLLHUP | POLLNVAL | UNSUPPORTED_WSAPOLL); - if (unhandled_events) - ERROR_LOG(WII_IPC_NET, "SO_POLL: unhandled Wii event types: %04x", unhandled_events); - } + if (unhandled_events) + ERROR_LOG(WII_IPC_NET, "SO_POLL: unhandled Wii event types: %04x", unhandled_events); + } - int ret = poll(ufds.data(), nfds, timeout); - ret = WiiSockMan::GetNetErrorCode(ret, "SO_POLL", false); + int ret = poll(ufds.data(), nfds, timeout); + ret = WiiSockMan::GetNetErrorCode(ret, "SO_POLL", false); - for (int i = 0; i < nfds; ++i) - { + for (int i = 0; i < nfds; ++i) + { + // Translate native to Wii events + int revents = 0; + for (auto& map : mapping) + { + if (ufds[i].revents & map.native) + revents |= map.wii; + } - // Translate native to Wii events - int revents = 0; - for (auto& map : mapping) - { - if (ufds[i].revents & map.native) - revents |= map.wii; - } + // No need to change fd or events as they are input only. + // Memory::Write_U32(ufds[i].fd, BufferOut + 0xc*i); //fd + // Memory::Write_U32(events, BufferOut + 0xc*i + 4); //events + Memory::Write_U32(revents, BufferOut + 0xc * i + 8); // revents - // No need to change fd or events as they are input only. - //Memory::Write_U32(ufds[i].fd, BufferOut + 0xc*i); //fd - //Memory::Write_U32(events, BufferOut + 0xc*i + 4); //events - Memory::Write_U32(revents, BufferOut + 0xc*i + 8); //revents + DEBUG_LOG(WII_IPC_NET, "IOCTL_SO_POLL socket %d wevents %08X events %08X revents %08X", i, + revents, ufds[i].events, ufds[i].revents); + } - DEBUG_LOG(WII_IPC_NET, "IOCTL_SO_POLL socket %d wevents %08X events %08X revents %08X", i, revents, ufds[i].events, ufds[i].revents); - } + ReturnValue = ret; + break; + } - ReturnValue = ret; - break; - } + case IOCTL_SO_GETHOSTBYNAME: + { + if (BufferOutSize != 0x460) + { + ERROR_LOG(WII_IPC_NET, "Bad buffer size for IOCTL_SO_GETHOSTBYNAME"); + ReturnValue = -1; + break; + } - case IOCTL_SO_GETHOSTBYNAME: - { - if (BufferOutSize != 0x460) - { - ERROR_LOG(WII_IPC_NET, "Bad buffer size for IOCTL_SO_GETHOSTBYNAME"); - ReturnValue = -1; - break; - } + std::string hostname = Memory::GetString(BufferIn); + hostent* remoteHost = gethostbyname(hostname.c_str()); - std::string hostname = Memory::GetString(BufferIn); - hostent* remoteHost = gethostbyname(hostname.c_str()); + INFO_LOG(WII_IPC_NET, "IOCTL_SO_GETHOSTBYNAME " + "Address: %s, BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + hostname.c_str(), BufferIn, BufferInSize, BufferOut, BufferOutSize); - INFO_LOG(WII_IPC_NET, "IOCTL_SO_GETHOSTBYNAME " - "Address: %s, BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - hostname.c_str(), BufferIn, BufferInSize, BufferOut, BufferOutSize); + if (remoteHost) + { + for (int i = 0; remoteHost->h_aliases[i]; ++i) + { + INFO_LOG(WII_IPC_NET, "alias%i:%s", i, remoteHost->h_aliases[i]); + } - if (remoteHost) - { - for (int i = 0; remoteHost->h_aliases[i]; ++i) - { - INFO_LOG(WII_IPC_NET, "alias%i:%s", i, remoteHost->h_aliases[i]); - } + for (int i = 0; remoteHost->h_addr_list[i]; ++i) + { + u32 ip = Common::swap32(*(u32*)(remoteHost->h_addr_list[i])); + std::string ip_s = StringFromFormat("%i.%i.%i.%i", ip >> 24, (ip >> 16) & 0xff, + (ip >> 8) & 0xff, ip & 0xff); + DEBUG_LOG(WII_IPC_NET, "addr%i:%s", i, ip_s.c_str()); + } - for (int i = 0; remoteHost->h_addr_list[i]; ++i) - { - u32 ip = Common::swap32(*(u32*)(remoteHost->h_addr_list[i])); - std::string ip_s = StringFromFormat("%i.%i.%i.%i", ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); - DEBUG_LOG(WII_IPC_NET, "addr%i:%s", i, ip_s.c_str()); - } + Memory::Memset(BufferOut, 0, BufferOutSize); - Memory::Memset(BufferOut, 0, BufferOutSize); + // Host name; located immediately after struct + static const u32 GETHOSTBYNAME_STRUCT_SIZE = 0x10; + static const u32 GETHOSTBYNAME_IP_LIST_OFFSET = 0x110; + // Limit host name length to avoid buffer overflow. + u32 name_length = (u32)strlen(remoteHost->h_name) + 1; + if (name_length > (GETHOSTBYNAME_IP_LIST_OFFSET - GETHOSTBYNAME_STRUCT_SIZE)) + { + ERROR_LOG(WII_IPC_NET, "Hostname too long in IOCTL_SO_GETHOSTBYNAME"); + ReturnValue = -1; + break; + } + Memory::CopyToEmu(BufferOut + GETHOSTBYNAME_STRUCT_SIZE, remoteHost->h_name, name_length); + Memory::Write_U32(BufferOut + GETHOSTBYNAME_STRUCT_SIZE, BufferOut); - // Host name; located immediately after struct - static const u32 GETHOSTBYNAME_STRUCT_SIZE = 0x10; - static const u32 GETHOSTBYNAME_IP_LIST_OFFSET = 0x110; - // Limit host name length to avoid buffer overflow. - u32 name_length = (u32)strlen(remoteHost->h_name) + 1; - if (name_length > (GETHOSTBYNAME_IP_LIST_OFFSET - GETHOSTBYNAME_STRUCT_SIZE)) - { - ERROR_LOG(WII_IPC_NET, "Hostname too long in IOCTL_SO_GETHOSTBYNAME"); - ReturnValue = -1; - break; - } - Memory::CopyToEmu(BufferOut + GETHOSTBYNAME_STRUCT_SIZE, remoteHost->h_name, name_length); - Memory::Write_U32(BufferOut + GETHOSTBYNAME_STRUCT_SIZE, BufferOut); + // IP address list; located at offset 0x110. + u32 num_ip_addr = 0; + while (remoteHost->h_addr_list[num_ip_addr]) + num_ip_addr++; + // Limit number of IP addresses to avoid buffer overflow. + // (0x460 - 0x340) / sizeof(pointer) == 72 + static const u32 GETHOSTBYNAME_MAX_ADDRESSES = 71; + num_ip_addr = std::min(num_ip_addr, GETHOSTBYNAME_MAX_ADDRESSES); + for (u32 i = 0; i < num_ip_addr; ++i) + { + u32 addr = BufferOut + GETHOSTBYNAME_IP_LIST_OFFSET + i * 4; + Memory::Write_U32_Swap(*(u32*)(remoteHost->h_addr_list[i]), addr); + } - // IP address list; located at offset 0x110. - u32 num_ip_addr = 0; - while (remoteHost->h_addr_list[num_ip_addr]) - num_ip_addr++; - // Limit number of IP addresses to avoid buffer overflow. - // (0x460 - 0x340) / sizeof(pointer) == 72 - static const u32 GETHOSTBYNAME_MAX_ADDRESSES = 71; - num_ip_addr = std::min(num_ip_addr, GETHOSTBYNAME_MAX_ADDRESSES); - for (u32 i = 0; i < num_ip_addr; ++i) - { - u32 addr = BufferOut + GETHOSTBYNAME_IP_LIST_OFFSET + i * 4; - Memory::Write_U32_Swap(*(u32*)(remoteHost->h_addr_list[i]), addr); - } + // List of pointers to IP addresses; located at offset 0x340. + // This must be exact: PPC code to convert the struct hardcodes + // this offset. + static const u32 GETHOSTBYNAME_IP_PTR_LIST_OFFSET = 0x340; + Memory::Write_U32(BufferOut + GETHOSTBYNAME_IP_PTR_LIST_OFFSET, BufferOut + 12); + for (u32 i = 0; i < num_ip_addr; ++i) + { + u32 addr = BufferOut + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + i * 4; + Memory::Write_U32(BufferOut + GETHOSTBYNAME_IP_LIST_OFFSET + i * 4, addr); + } + Memory::Write_U32(0, BufferOut + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + num_ip_addr * 4); - // List of pointers to IP addresses; located at offset 0x340. - // This must be exact: PPC code to convert the struct hardcodes - // this offset. - static const u32 GETHOSTBYNAME_IP_PTR_LIST_OFFSET = 0x340; - Memory::Write_U32(BufferOut + GETHOSTBYNAME_IP_PTR_LIST_OFFSET, BufferOut + 12); - for (u32 i = 0; i < num_ip_addr; ++i) - { - u32 addr = BufferOut + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + i * 4; - Memory::Write_U32(BufferOut + GETHOSTBYNAME_IP_LIST_OFFSET + i * 4, addr); - } - Memory::Write_U32(0, BufferOut + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + num_ip_addr * 4); + // Aliases - empty. (Hardware doesn't return anything.) + Memory::Write_U32(BufferOut + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + num_ip_addr * 4, + BufferOut + 4); - // Aliases - empty. (Hardware doesn't return anything.) - Memory::Write_U32(BufferOut + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + num_ip_addr * 4, BufferOut + 4); + // Returned struct must be ipv4. + _assert_msg_(WII_IPC_NET, + remoteHost->h_addrtype == AF_INET && remoteHost->h_length == sizeof(u32), + "returned host info is not IPv4"); + Memory::Write_U16(AF_INET, BufferOut + 8); + Memory::Write_U16(sizeof(u32), BufferOut + 10); - // Returned struct must be ipv4. - _assert_msg_(WII_IPC_NET, - remoteHost->h_addrtype == AF_INET && remoteHost->h_length == sizeof(u32), - "returned host info is not IPv4"); - Memory::Write_U16(AF_INET, BufferOut + 8); - Memory::Write_U16(sizeof(u32), BufferOut + 10); + ReturnValue = 0; + } + else + { + ReturnValue = -1; + } - ReturnValue = 0; - } - else - { - ReturnValue = -1; - } + break; + } - break; - } + case IOCTL_SO_ICMPCANCEL: + ERROR_LOG(WII_IPC_NET, "IOCTL_SO_ICMPCANCEL"); + goto default_; - case IOCTL_SO_ICMPCANCEL: - ERROR_LOG(WII_IPC_NET, "IOCTL_SO_ICMPCANCEL"); - goto default_; + default: + INFO_LOG(WII_IPC_NET, "0x%x " + "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + Command, BufferIn, BufferInSize, BufferOut, BufferOutSize); + default_: + if (BufferInSize) + { + ERROR_LOG(WII_IPC_NET, "in addr %x size %x", BufferIn, BufferInSize); + ERROR_LOG(WII_IPC_NET, "\n%s", + ArrayToString(Memory::GetPointer(BufferIn), BufferInSize, 4).c_str()); + } - default: - INFO_LOG(WII_IPC_NET, "0x%x " - "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - Command, BufferIn, BufferInSize, BufferOut, BufferOutSize); - default_: - if (BufferInSize) - { - ERROR_LOG(WII_IPC_NET, "in addr %x size %x", BufferIn, BufferInSize); - ERROR_LOG(WII_IPC_NET, "\n%s", ArrayToString(Memory::GetPointer(BufferIn), BufferInSize, 4).c_str()); - } + if (BufferOutSize) + { + ERROR_LOG(WII_IPC_NET, "out addr %x size %x", BufferOut, BufferOutSize); + } + break; + } - if (BufferOutSize) - { - ERROR_LOG(WII_IPC_NET, "out addr %x size %x", BufferOut, BufferOutSize); - } - break; - } + Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); - Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); - - return GetDefaultReply(); + return GetDefaultReply(); } - IPCCommandResult CWII_IPC_HLE_Device_net_ip_top::IOCtlV(u32 CommandAddress) { - SIOCtlVBuffer CommandBuffer(CommandAddress); + SIOCtlVBuffer CommandBuffer(CommandAddress); - s32 ReturnValue = 0; + s32 ReturnValue = 0; + u32 _BufferIn = 0, _BufferIn2 = 0, _BufferIn3 = 0; + u32 BufferInSize = 0, BufferInSize2 = 0, BufferInSize3 = 0; - u32 _BufferIn = 0, _BufferIn2 = 0, _BufferIn3 = 0; - u32 BufferInSize = 0, BufferInSize2 = 0, BufferInSize3 = 0; + u32 _BufferOut = 0, _BufferOut2 = 0; + u32 BufferOutSize = 0; - u32 _BufferOut = 0, _BufferOut2 = 0; - u32 BufferOutSize = 0; + if (CommandBuffer.InBuffer.size() > 0) + { + _BufferIn = CommandBuffer.InBuffer.at(0).m_Address; + BufferInSize = CommandBuffer.InBuffer.at(0).m_Size; + } + if (CommandBuffer.InBuffer.size() > 1) + { + _BufferIn2 = CommandBuffer.InBuffer.at(1).m_Address; + BufferInSize2 = CommandBuffer.InBuffer.at(1).m_Size; + } + if (CommandBuffer.InBuffer.size() > 2) + { + _BufferIn3 = CommandBuffer.InBuffer.at(2).m_Address; + BufferInSize3 = CommandBuffer.InBuffer.at(2).m_Size; + } - if (CommandBuffer.InBuffer.size() > 0) - { - _BufferIn = CommandBuffer.InBuffer.at(0).m_Address; - BufferInSize = CommandBuffer.InBuffer.at(0).m_Size; - } - if (CommandBuffer.InBuffer.size() > 1) - { - _BufferIn2 = CommandBuffer.InBuffer.at(1).m_Address; - BufferInSize2 = CommandBuffer.InBuffer.at(1).m_Size; - } - if (CommandBuffer.InBuffer.size() > 2) - { - _BufferIn3 = CommandBuffer.InBuffer.at(2).m_Address; - BufferInSize3 = CommandBuffer.InBuffer.at(2).m_Size; - } + if (CommandBuffer.PayloadBuffer.size() > 0) + { + _BufferOut = CommandBuffer.PayloadBuffer.at(0).m_Address; + BufferOutSize = CommandBuffer.PayloadBuffer.at(0).m_Size; + } + if (CommandBuffer.PayloadBuffer.size() > 1) + { + _BufferOut2 = CommandBuffer.PayloadBuffer.at(1).m_Address; + } - if (CommandBuffer.PayloadBuffer.size() > 0) - { - _BufferOut = CommandBuffer.PayloadBuffer.at(0).m_Address; - BufferOutSize = CommandBuffer.PayloadBuffer.at(0).m_Size; - } - if (CommandBuffer.PayloadBuffer.size() > 1) - { - _BufferOut2 = CommandBuffer.PayloadBuffer.at(1).m_Address; - } + u32 param = 0, param2 = 0, param3, param4, param5 = 0; - u32 param = 0, param2 = 0, param3, param4, param5 = 0; + switch (CommandBuffer.Parameter) + { + case IOCTLV_SO_GETINTERFACEOPT: + { + param = Memory::Read_U32(_BufferIn); + param2 = Memory::Read_U32(_BufferIn + 4); + param3 = Memory::Read_U32(_BufferOut); + param4 = Memory::Read_U32(_BufferOut2); + if (BufferOutSize >= 8) + { + param5 = Memory::Read_U32(_BufferOut + 4); + } - switch (CommandBuffer.Parameter) - { - case IOCTLV_SO_GETINTERFACEOPT: - { - param = Memory::Read_U32(_BufferIn); - param2 = Memory::Read_U32(_BufferIn + 4); - param3 = Memory::Read_U32(_BufferOut); - param4 = Memory::Read_U32(_BufferOut2); - if (BufferOutSize >= 8) - { - param5 = Memory::Read_U32(_BufferOut + 4); - } + INFO_LOG(WII_IPC_NET, "IOCTLV_SO_GETINTERFACEOPT(%08X, %08X, %X, %X, %X) " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i) ", + param, param2, param3, param4, param5, _BufferIn, BufferInSize, _BufferIn2, + BufferInSize2); - INFO_LOG(WII_IPC_NET, "IOCTLV_SO_GETINTERFACEOPT(%08X, %08X, %X, %X, %X) " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i) ", - param, param2, param3, param4, param5, - _BufferIn, BufferInSize, _BufferIn2, BufferInSize2); - - switch (param2) - { - case 0xb003: // dns server table - { - u32 address = 0; + switch (param2) + { + case 0xb003: // dns server table + { + u32 address = 0; #ifdef _WIN32 - if (!Core::g_want_determinism) - { - PIP_ADAPTER_ADDRESSES AdapterAddresses = nullptr; - ULONG OutBufferLength = 0; - ULONG RetVal = 0, i; - for (i = 0; i < 5; ++i) - { - RetVal = GetAdaptersAddresses( - AF_INET, - 0, - nullptr, - AdapterAddresses, - &OutBufferLength); + if (!Core::g_want_determinism) + { + PIP_ADAPTER_ADDRESSES AdapterAddresses = nullptr; + ULONG OutBufferLength = 0; + ULONG RetVal = 0, i; + for (i = 0; i < 5; ++i) + { + RetVal = GetAdaptersAddresses(AF_INET, 0, nullptr, AdapterAddresses, &OutBufferLength); - if (RetVal != ERROR_BUFFER_OVERFLOW) - { - break; - } + if (RetVal != ERROR_BUFFER_OVERFLOW) + { + break; + } - if (AdapterAddresses != nullptr) - { - FREE(AdapterAddresses); - } + if (AdapterAddresses != nullptr) + { + FREE(AdapterAddresses); + } - AdapterAddresses = (PIP_ADAPTER_ADDRESSES)MALLOC(OutBufferLength); - if (AdapterAddresses == nullptr) - { - RetVal = GetLastError(); - break; - } - } - if (RetVal == NO_ERROR) - { - unsigned long dwBestIfIndex = 0; - IPAddr dwDestAddr = (IPAddr)0x08080808; - // If successful, output some information from the data we received - PIP_ADAPTER_ADDRESSES AdapterList = AdapterAddresses; - if (GetBestInterface(dwDestAddr, &dwBestIfIndex) == NO_ERROR) - { - while (AdapterList) - { - if (AdapterList->IfIndex == dwBestIfIndex && - AdapterList->FirstDnsServerAddress && - AdapterList->OperStatus == IfOperStatusUp) - { - INFO_LOG(WII_IPC_NET, "Name of valid interface: %S", AdapterList->FriendlyName); - INFO_LOG(WII_IPC_NET, "DNS: %u.%u.%u.%u", - (unsigned char)AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[2], - (unsigned char)AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[3], - (unsigned char)AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[4], - (unsigned char)AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[5]); - address = Common::swap32(*(u32*)(&AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[2])); - break; - } - AdapterList = AdapterList->Next; - } - } - } - if (AdapterAddresses != nullptr) - { - FREE(AdapterAddresses); - } - } + AdapterAddresses = (PIP_ADAPTER_ADDRESSES)MALLOC(OutBufferLength); + if (AdapterAddresses == nullptr) + { + RetVal = GetLastError(); + break; + } + } + if (RetVal == NO_ERROR) + { + unsigned long dwBestIfIndex = 0; + IPAddr dwDestAddr = (IPAddr)0x08080808; + // If successful, output some information from the data we received + PIP_ADAPTER_ADDRESSES AdapterList = AdapterAddresses; + if (GetBestInterface(dwDestAddr, &dwBestIfIndex) == NO_ERROR) + { + while (AdapterList) + { + if (AdapterList->IfIndex == dwBestIfIndex && AdapterList->FirstDnsServerAddress && + AdapterList->OperStatus == IfOperStatusUp) + { + INFO_LOG(WII_IPC_NET, "Name of valid interface: %S", AdapterList->FriendlyName); + INFO_LOG(WII_IPC_NET, "DNS: %u.%u.%u.%u", + (unsigned char) + AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[2], + (unsigned char) + AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[3], + (unsigned char) + AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[4], + (unsigned char) + AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[5]); + address = Common::swap32( + *(u32*)(&AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[2])); + break; + } + AdapterList = AdapterList->Next; + } + } + } + if (AdapterAddresses != nullptr) + { + FREE(AdapterAddresses); + } + } #endif - if (address == 0) - address = 0x08080808; + if (address == 0) + address = 0x08080808; - Memory::Write_U32(address, _BufferOut); - Memory::Write_U32(0x08080404, _BufferOut + 4); - break; - } - case 0x1003: // error - Memory::Write_U32(0, _BufferOut); - break; + Memory::Write_U32(address, _BufferOut); + Memory::Write_U32(0x08080404, _BufferOut + 4); + break; + } + case 0x1003: // error + Memory::Write_U32(0, _BufferOut); + break; - case 0x1004: // mac address - u8 address[MAC_ADDRESS_SIZE]; - GetMacAddress(address); - Memory::CopyToEmu(_BufferOut, address, sizeof(address)); - break; + case 0x1004: // mac address + u8 address[MAC_ADDRESS_SIZE]; + GetMacAddress(address); + Memory::CopyToEmu(_BufferOut, address, sizeof(address)); + break; - case 0x1005: // link state - Memory::Write_U32(1, _BufferOut); - break; + case 0x1005: // link state + Memory::Write_U32(1, _BufferOut); + break; - case 0x4002: // ip addr number - Memory::Write_U32(1, _BufferOut); - break; + case 0x4002: // ip addr number + Memory::Write_U32(1, _BufferOut); + break; - case 0x4003: // ip addr table - Memory::Write_U32(0xC, _BufferOut2); - Memory::Write_U32(10 << 24 | 1 << 8 | 30, _BufferOut); - Memory::Write_U32(255 << 24 | 255 << 16 | 255 << 8 | 0, _BufferOut + 4); - Memory::Write_U32(10 << 24 | 0 << 16 | 255 << 8 | 255, _BufferOut + 8); - break; + case 0x4003: // ip addr table + Memory::Write_U32(0xC, _BufferOut2); + Memory::Write_U32(10 << 24 | 1 << 8 | 30, _BufferOut); + Memory::Write_U32(255 << 24 | 255 << 16 | 255 << 8 | 0, _BufferOut + 4); + Memory::Write_U32(10 << 24 | 0 << 16 | 255 << 8 | 255, _BufferOut + 8); + break; - default: - ERROR_LOG(WII_IPC_NET, "Unknown param2: %08X", param2); - break; - } - break; - } - case IOCTLV_SO_SENDTO: - { - u32 fd = Memory::Read_U32(_BufferIn2); - WiiSockMan &sm = WiiSockMan::GetInstance(); - sm.DoSock(fd, CommandAddress, IOCTLV_SO_SENDTO); - return GetNoReply(); - break; - } - case IOCTLV_SO_RECVFROM: - { - u32 fd = Memory::Read_U32(_BufferIn); - WiiSockMan &sm = WiiSockMan::GetInstance(); - sm.DoSock(fd, CommandAddress, IOCTLV_SO_RECVFROM); - return GetNoReply(); - break; - } - case IOCTLV_SO_GETADDRINFO: - { - addrinfo hints; + default: + ERROR_LOG(WII_IPC_NET, "Unknown param2: %08X", param2); + break; + } + break; + } + case IOCTLV_SO_SENDTO: + { + u32 fd = Memory::Read_U32(_BufferIn2); + WiiSockMan& sm = WiiSockMan::GetInstance(); + sm.DoSock(fd, CommandAddress, IOCTLV_SO_SENDTO); + return GetNoReply(); + break; + } + case IOCTLV_SO_RECVFROM: + { + u32 fd = Memory::Read_U32(_BufferIn); + WiiSockMan& sm = WiiSockMan::GetInstance(); + sm.DoSock(fd, CommandAddress, IOCTLV_SO_RECVFROM); + return GetNoReply(); + break; + } + case IOCTLV_SO_GETADDRINFO: + { + addrinfo hints; - if (BufferInSize3) - { - hints.ai_flags = Memory::Read_U32(_BufferIn3); - hints.ai_family = Memory::Read_U32(_BufferIn3 + 0x4); - hints.ai_socktype = Memory::Read_U32(_BufferIn3 + 0x8); - hints.ai_protocol = Memory::Read_U32(_BufferIn3 + 0xC); - hints.ai_addrlen = Memory::Read_U32(_BufferIn3 + 0x10); - hints.ai_canonname = nullptr; - hints.ai_addr = nullptr; - hints.ai_next = nullptr; - } + if (BufferInSize3) + { + hints.ai_flags = Memory::Read_U32(_BufferIn3); + hints.ai_family = Memory::Read_U32(_BufferIn3 + 0x4); + hints.ai_socktype = Memory::Read_U32(_BufferIn3 + 0x8); + hints.ai_protocol = Memory::Read_U32(_BufferIn3 + 0xC); + hints.ai_addrlen = Memory::Read_U32(_BufferIn3 + 0x10); + hints.ai_canonname = nullptr; + hints.ai_addr = nullptr; + hints.ai_next = nullptr; + } - // getaddrinfo allows a null pointer for the nodeName or serviceName strings - // So we have to do a bit of juggling here. - std::string nodeNameStr; - const char* pNodeName = nullptr; - if (BufferInSize > 0) - { - nodeNameStr = Memory::GetString(_BufferIn, BufferInSize); - pNodeName = nodeNameStr.c_str(); - } + // getaddrinfo allows a null pointer for the nodeName or serviceName strings + // So we have to do a bit of juggling here. + std::string nodeNameStr; + const char* pNodeName = nullptr; + if (BufferInSize > 0) + { + nodeNameStr = Memory::GetString(_BufferIn, BufferInSize); + pNodeName = nodeNameStr.c_str(); + } - std::string serviceNameStr; - const char* pServiceName = nullptr; - if (BufferInSize2 > 0) - { - serviceNameStr = Memory::GetString(_BufferIn2, BufferInSize2); - pServiceName = serviceNameStr.c_str(); - } + std::string serviceNameStr; + const char* pServiceName = nullptr; + if (BufferInSize2 > 0) + { + serviceNameStr = Memory::GetString(_BufferIn2, BufferInSize2); + pServiceName = serviceNameStr.c_str(); + } - addrinfo* result = nullptr; - int ret = getaddrinfo(pNodeName, pServiceName, BufferInSize3 ? &hints : nullptr, &result); - u32 addr = _BufferOut; - u32 sockoffset = addr + 0x460; - if (ret == 0) - { - for (addrinfo* result_iter = result; result_iter != nullptr; result_iter = result_iter->ai_next) - { - Memory::Write_U32(result_iter->ai_flags, addr); - Memory::Write_U32(result_iter->ai_family, addr + 0x04); - Memory::Write_U32(result_iter->ai_socktype, addr + 0x08); - Memory::Write_U32(result_iter->ai_protocol, addr + 0x0C); - Memory::Write_U32((u32)result_iter->ai_addrlen, addr + 0x10); - // what to do? where to put? the buffer of 0x834 doesn't allow space for this - Memory::Write_U32(/*result->ai_cannonname*/ 0, addr + 0x14); + addrinfo* result = nullptr; + int ret = getaddrinfo(pNodeName, pServiceName, BufferInSize3 ? &hints : nullptr, &result); + u32 addr = _BufferOut; + u32 sockoffset = addr + 0x460; + if (ret == 0) + { + for (addrinfo* result_iter = result; result_iter != nullptr; + result_iter = result_iter->ai_next) + { + Memory::Write_U32(result_iter->ai_flags, addr); + Memory::Write_U32(result_iter->ai_family, addr + 0x04); + Memory::Write_U32(result_iter->ai_socktype, addr + 0x08); + Memory::Write_U32(result_iter->ai_protocol, addr + 0x0C); + Memory::Write_U32((u32)result_iter->ai_addrlen, addr + 0x10); + // what to do? where to put? the buffer of 0x834 doesn't allow space for this + Memory::Write_U32(/*result->ai_cannonname*/ 0, addr + 0x14); - if (result_iter->ai_addr) - { - Memory::Write_U32(sockoffset, addr + 0x18); - Memory::Write_U16(((result_iter->ai_addr->sa_family & 0xFF) << 8) | (result_iter->ai_addrlen & 0xFF), sockoffset); - Memory::CopyToEmu(sockoffset + 0x2, result_iter->ai_addr->sa_data, sizeof(result_iter->ai_addr->sa_data)); - sockoffset += 0x1C; - } - else - { - Memory::Write_U32(0, addr + 0x18); - } + if (result_iter->ai_addr) + { + Memory::Write_U32(sockoffset, addr + 0x18); + Memory::Write_U16(((result_iter->ai_addr->sa_family & 0xFF) << 8) | + (result_iter->ai_addrlen & 0xFF), + sockoffset); + Memory::CopyToEmu(sockoffset + 0x2, result_iter->ai_addr->sa_data, + sizeof(result_iter->ai_addr->sa_data)); + sockoffset += 0x1C; + } + else + { + Memory::Write_U32(0, addr + 0x18); + } - if (result_iter->ai_next) - { - Memory::Write_U32(addr + sizeof(addrinfo), addr + 0x1C); - } - else - { - Memory::Write_U32(0, addr + 0x1C); - } + if (result_iter->ai_next) + { + Memory::Write_U32(addr + sizeof(addrinfo), addr + 0x1C); + } + else + { + Memory::Write_U32(0, addr + 0x1C); + } - addr += sizeof(addrinfo); - } + addr += sizeof(addrinfo); + } - freeaddrinfo(result); - } - else - { - // Host not found - ret = -305; - } + freeaddrinfo(result); + } + else + { + // Host not found + ret = -305; + } - INFO_LOG(WII_IPC_NET, "IOCTLV_SO_GETADDRINFO " - "(BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - _BufferIn, BufferInSize, _BufferOut, BufferOutSize); - INFO_LOG(WII_IPC_NET, "IOCTLV_SO_GETADDRINFO: %s", Memory::GetString(_BufferIn).c_str()); - ReturnValue = ret; - break; - } - case IOCTLV_SO_ICMPPING: - { - struct - { - u8 length; - u8 addr_family; - u16 icmp_id; - u32 ip; - } ip_info; + INFO_LOG(WII_IPC_NET, "IOCTLV_SO_GETADDRINFO " + "(BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + _BufferIn, BufferInSize, _BufferOut, BufferOutSize); + INFO_LOG(WII_IPC_NET, "IOCTLV_SO_GETADDRINFO: %s", Memory::GetString(_BufferIn).c_str()); + ReturnValue = ret; + break; + } + case IOCTLV_SO_ICMPPING: + { + struct + { + u8 length; + u8 addr_family; + u16 icmp_id; + u32 ip; + } ip_info; - u32 fd = Memory::Read_U32(_BufferIn); - u32 num_ip = Memory::Read_U32(_BufferIn + 4); - u64 timeout = Memory::Read_U64(_BufferIn + 8); + u32 fd = Memory::Read_U32(_BufferIn); + u32 num_ip = Memory::Read_U32(_BufferIn + 4); + u64 timeout = Memory::Read_U64(_BufferIn + 8); - if (num_ip != 1) - { - INFO_LOG(WII_IPC_NET, "IOCTLV_SO_ICMPPING %i IPs", num_ip); - } + if (num_ip != 1) + { + INFO_LOG(WII_IPC_NET, "IOCTLV_SO_ICMPPING %i IPs", num_ip); + } - ip_info.length = Memory::Read_U8(_BufferIn + 16); - ip_info.addr_family = Memory::Read_U8(_BufferIn + 17); - ip_info.icmp_id = Memory::Read_U16(_BufferIn + 18); - ip_info.ip = Memory::Read_U32(_BufferIn + 20); + ip_info.length = Memory::Read_U8(_BufferIn + 16); + ip_info.addr_family = Memory::Read_U8(_BufferIn + 17); + ip_info.icmp_id = Memory::Read_U16(_BufferIn + 18); + ip_info.ip = Memory::Read_U32(_BufferIn + 20); - if (ip_info.length != 8 || ip_info.addr_family != AF_INET) - { - INFO_LOG(WII_IPC_NET, "IOCTLV_SO_ICMPPING strange IPInfo:\n" - "length %x addr_family %x", - ip_info.length, ip_info.addr_family); - } + if (ip_info.length != 8 || ip_info.addr_family != AF_INET) + { + INFO_LOG(WII_IPC_NET, "IOCTLV_SO_ICMPPING strange IPInfo:\n" + "length %x addr_family %x", + ip_info.length, ip_info.addr_family); + } - DEBUG_LOG(WII_IPC_NET, "IOCTLV_SO_ICMPPING %x", ip_info.ip); + DEBUG_LOG(WII_IPC_NET, "IOCTLV_SO_ICMPPING %x", ip_info.ip); - sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = Common::swap32(ip_info.ip); - memset(addr.sin_zero, 0, 8); + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = Common::swap32(ip_info.ip); + memset(addr.sin_zero, 0, 8); - u8 data[0x20]; - memset(data, 0, sizeof(data)); - s32 icmp_length = sizeof(data); + u8 data[0x20]; + memset(data, 0, sizeof(data)); + s32 icmp_length = sizeof(data); - if (BufferInSize2 == sizeof(data)) - Memory::CopyFromEmu(data, _BufferIn2, BufferInSize2); - else - { - // TODO sequence number is incremented either statically, by - // port, or by socket. Doesn't seem to matter, so we just leave - // it 0 - ((u16*)data)[0] = Common::swap16(ip_info.icmp_id); - icmp_length = 22; - } + if (BufferInSize2 == sizeof(data)) + Memory::CopyFromEmu(data, _BufferIn2, BufferInSize2); + else + { + // TODO sequence number is incremented either statically, by + // port, or by socket. Doesn't seem to matter, so we just leave + // it 0 + ((u16*)data)[0] = Common::swap16(ip_info.icmp_id); + icmp_length = 22; + } - int ret = icmp_echo_req(fd, &addr, data, icmp_length); - if (ret == icmp_length) - { - ret = icmp_echo_rep(fd, &addr, (u32)timeout, icmp_length); - } + int ret = icmp_echo_req(fd, &addr, data, icmp_length); + if (ret == icmp_length) + { + ret = icmp_echo_rep(fd, &addr, (u32)timeout, icmp_length); + } - // TODO proper error codes - ReturnValue = 0; - break; - } - default: - INFO_LOG(WII_IPC_NET,"0x%x (BufferIn: (%08x, %i), BufferIn2: (%08x, %i)", - CommandBuffer.Parameter, _BufferIn, BufferInSize, _BufferIn2, BufferInSize2); - for (u32 i = 0; i < CommandBuffer.NumberInBuffer; ++i) - { - ERROR_LOG(WII_IPC_NET, "in %i addr %x size %x", i, - CommandBuffer.InBuffer.at(i).m_Address, CommandBuffer.InBuffer.at(i).m_Size); - ERROR_LOG(WII_IPC_NET, "\n%s", - ArrayToString( - Memory::GetPointer(CommandBuffer.InBuffer.at(i).m_Address), - CommandBuffer.InBuffer.at(i).m_Size, 4).c_str() - ); - } - for (u32 i = 0; i < CommandBuffer.NumberPayloadBuffer; ++i) - { - ERROR_LOG(WII_IPC_NET, "out %i addr %x size %x", i, - CommandBuffer.PayloadBuffer.at(i).m_Address, CommandBuffer.PayloadBuffer.at(i).m_Size); - } - break; - } + // TODO proper error codes + ReturnValue = 0; + break; + } + default: + INFO_LOG(WII_IPC_NET, "0x%x (BufferIn: (%08x, %i), BufferIn2: (%08x, %i)", + CommandBuffer.Parameter, _BufferIn, BufferInSize, _BufferIn2, BufferInSize2); + for (u32 i = 0; i < CommandBuffer.NumberInBuffer; ++i) + { + ERROR_LOG(WII_IPC_NET, "in %i addr %x size %x", i, CommandBuffer.InBuffer.at(i).m_Address, + CommandBuffer.InBuffer.at(i).m_Size); + ERROR_LOG(WII_IPC_NET, "\n%s", + ArrayToString(Memory::GetPointer(CommandBuffer.InBuffer.at(i).m_Address), + CommandBuffer.InBuffer.at(i).m_Size, 4) + .c_str()); + } + for (u32 i = 0; i < CommandBuffer.NumberPayloadBuffer; ++i) + { + ERROR_LOG(WII_IPC_NET, "out %i addr %x size %x", i, + CommandBuffer.PayloadBuffer.at(i).m_Address, + CommandBuffer.PayloadBuffer.at(i).m_Size); + } + break; + } - Memory::Write_U32(ReturnValue, CommandAddress + 4); - return GetDefaultReply(); + Memory::Write_U32(ReturnValue, CommandAddress + 4); + return GetDefaultReply(); } u32 CWII_IPC_HLE_Device_net_ip_top::Update() { - WiiSockMan::GetInstance().Update(); - return 0; + WiiSockMan::GetInstance().Update(); + return 0; } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.h index ef89581da4..e340347416 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net.h @@ -21,368 +21,357 @@ #pragma pack(push, 1) struct netcfg_proxy_t { - u8 use_proxy; - u8 use_proxy_userandpass; - u8 padding_1[2]; - u8 proxy_name[255]; - u8 padding_2; - u16 proxy_port; // 0-34463 - u8 proxy_username[32]; - u8 padding_3; - u8 proxy_password[32]; + u8 use_proxy; + u8 use_proxy_userandpass; + u8 padding_1[2]; + u8 proxy_name[255]; + u8 padding_2; + u16 proxy_port; // 0-34463 + u8 proxy_username[32]; + u8 padding_3; + u8 proxy_password[32]; }; struct netcfg_connection_t { - enum - { - WIRED_IF = 1, // 0: wifi 1: wired - DNS_DHCP = 2, // 0: manual 1: DHCP - IP_DHCP = 4, // 0: manual 1: DHCP - USE_PROXY = 16, - CONNECTION_TEST_OK = 32, - CONNECTION_SELECTED = 128 - }; + enum + { + WIRED_IF = 1, // 0: wifi 1: wired + DNS_DHCP = 2, // 0: manual 1: DHCP + IP_DHCP = 4, // 0: manual 1: DHCP + USE_PROXY = 16, + CONNECTION_TEST_OK = 32, + CONNECTION_SELECTED = 128 + }; - enum - { - OPEN = 0, - WEP64 = 1, - WEP128 = 2, - WPA_TKIP = 4, - WPA2_AES = 5, - WPA_AES = 6 - }; + enum + { + OPEN = 0, + WEP64 = 1, + WEP128 = 2, + WPA_TKIP = 4, + WPA2_AES = 5, + WPA_AES = 6 + }; - enum status - { - LINK_BUSY = 1, - LINK_NONE = 2, - LINK_WIRED = 3, - LINK_WIFI_DOWN = 4, - LINK_WIFI_UP = 5 - }; + enum status + { + LINK_BUSY = 1, + LINK_NONE = 2, + LINK_WIRED = 3, + LINK_WIFI_DOWN = 4, + LINK_WIFI_UP = 5 + }; - enum - { - PERM_NONE = 0, - PERM_SEND_MAIL = 1, - PERM_RECV_MAIL = 2, - PERM_DOWNLOAD = 4, - PERM_ALL = PERM_SEND_MAIL | PERM_RECV_MAIL | PERM_DOWNLOAD - }; + enum + { + PERM_NONE = 0, + PERM_SEND_MAIL = 1, + PERM_RECV_MAIL = 2, + PERM_DOWNLOAD = 4, + PERM_ALL = PERM_SEND_MAIL | PERM_RECV_MAIL | PERM_DOWNLOAD + }; - // settings common to both wired and wireless connections - u8 flags; - u8 padding_1[3]; - u8 ip[4]; - u8 netmask[4]; - u8 gateway[4]; - u8 dns1[4]; - u8 dns2[4]; - u8 padding_2[2]; - u16 mtu; - u8 padding_3[8]; - netcfg_proxy_t proxy_settings; - u8 padding_4; - netcfg_proxy_t proxy_settings_copy; - u8 padding_5[1297]; + // settings common to both wired and wireless connections + u8 flags; + u8 padding_1[3]; + u8 ip[4]; + u8 netmask[4]; + u8 gateway[4]; + u8 dns1[4]; + u8 dns2[4]; + u8 padding_2[2]; + u16 mtu; + u8 padding_3[8]; + netcfg_proxy_t proxy_settings; + u8 padding_4; + netcfg_proxy_t proxy_settings_copy; + u8 padding_5[1297]; - // wireless specific settings - u8 ssid[32]; - u8 padding_6; - u8 ssid_length; // length of ssid in bytes. - u8 padding_7[3]; - u8 encryption; - u8 padding_8[3]; - u8 key_length; // length of key in bytes. 0x00 for WEP64 and WEP128. - u8 unknown; // 0x00 or 0x01 toggled with a WPA-PSK (TKIP) and with a WEP entered with hex instead of ascii. - u8 padding_9; - u8 key[64]; // encryption key; for WEP, key is stored 4 times (20 bytes for WEP64 and 52 bytes for WEP128) then padded with 0x00 - u8 padding_10[236]; + // wireless specific settings + u8 ssid[32]; + u8 padding_6; + u8 ssid_length; // length of ssid in bytes. + u8 padding_7[3]; + u8 encryption; + u8 padding_8[3]; + u8 key_length; // length of key in bytes. 0x00 for WEP64 and WEP128. + u8 unknown; // 0x00 or 0x01 toggled with a WPA-PSK (TKIP) and with a WEP entered with hex instead + // of ascii. + u8 padding_9; + u8 key[64]; // encryption key; for WEP, key is stored 4 times (20 bytes for WEP64 and 52 bytes + // for WEP128) then padded with 0x00 + u8 padding_10[236]; }; struct network_config_t { - enum - { - IF_NONE, - IF_WIFI, - IF_WIRED - }; + enum + { + IF_NONE, + IF_WIFI, + IF_WIRED + }; - u32 version; - u8 connType; - u8 linkTimeout; - u8 nwc24Permission; - u8 padding; + u32 version; + u8 connType; + u8 linkTimeout; + u8 nwc24Permission; + u8 padding; - netcfg_connection_t connection[3]; + netcfg_connection_t connection[3]; }; enum nwc24_err_t { - WC24_OK = 0, - WC24_ERR_FATAL = -1, - WC24_ERR_ID_NONEXISTANCE = -34, - WC24_ERR_ID_GENERATED = -35, - WC24_ERR_ID_REGISTERED = -36, - WC24_ERR_ID_NOT_REGISTERED = -44, + WC24_OK = 0, + WC24_ERR_FATAL = -1, + WC24_ERR_ID_NONEXISTANCE = -34, + WC24_ERR_ID_GENERATED = -35, + WC24_ERR_ID_REGISTERED = -36, + WC24_ERR_ID_NOT_REGISTERED = -44, }; struct nwc24_config_t { - enum - { - NWC24_IDCS_INITIAL = 0, - NWC24_IDCS_GENERATED = 1, - NWC24_IDCS_REGISTERED = 2 - }; + enum + { + NWC24_IDCS_INITIAL = 0, + NWC24_IDCS_GENERATED = 1, + NWC24_IDCS_REGISTERED = 2 + }; - enum - { - URL_COUNT = 0x05, - MAX_URL_LENGTH = 0x80, - MAX_EMAIL_LENGTH = 0x40, - MAX_PASSWORD_LENGTH = 0x20, - }; + enum + { + URL_COUNT = 0x05, + MAX_URL_LENGTH = 0x80, + MAX_EMAIL_LENGTH = 0x40, + MAX_PASSWORD_LENGTH = 0x20, + }; - u32 magic; /* 'WcCf' 0x57634366 */ - u32 _unk_04; /* must be 8 */ - u64 nwc24_id; - u32 id_generation; - u32 creation_stage; /* 0==not_generated;1==generated;2==registered; */ - char email[MAX_EMAIL_LENGTH]; - char paswd[MAX_PASSWORD_LENGTH]; - char mlchkid[0x24]; - char http_urls[URL_COUNT][MAX_URL_LENGTH]; - u8 reserved[0xDC]; - u32 enable_booting; - u32 checksum; + u32 magic; /* 'WcCf' 0x57634366 */ + u32 _unk_04; /* must be 8 */ + u64 nwc24_id; + u32 id_generation; + u32 creation_stage; /* 0==not_generated;1==generated;2==registered; */ + char email[MAX_EMAIL_LENGTH]; + char paswd[MAX_PASSWORD_LENGTH]; + char mlchkid[0x24]; + char http_urls[URL_COUNT][MAX_URL_LENGTH]; + u8 reserved[0xDC]; + u32 enable_booting; + u32 checksum; }; #pragma pack(pop) - - class NWC24Config { private: - std::string path; - nwc24_config_t config; + std::string path; + nwc24_config_t config; public: - NWC24Config() - { - path = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/" WII_WC24CONF_DIR "/nwc24msg.cfg"; - ReadConfig(); - } + NWC24Config() + { + path = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/" WII_WC24CONF_DIR "/nwc24msg.cfg"; + ReadConfig(); + } - void ResetConfig() - { - if (File::Exists(path)) - File::Delete(path); + void ResetConfig() + { + if (File::Exists(path)) + File::Delete(path); - const char* urls[5] = { - "https://amw.wc24.wii.com/cgi-bin/account.cgi", - "http://rcw.wc24.wii.com/cgi-bin/check.cgi", - "http://mtw.wc24.wii.com/cgi-bin/receive.cgi", - "http://mtw.wc24.wii.com/cgi-bin/delete.cgi", - "http://mtw.wc24.wii.com/cgi-bin/send.cgi", - }; + const char* urls[5] = { + "https://amw.wc24.wii.com/cgi-bin/account.cgi", + "http://rcw.wc24.wii.com/cgi-bin/check.cgi", + "http://mtw.wc24.wii.com/cgi-bin/receive.cgi", + "http://mtw.wc24.wii.com/cgi-bin/delete.cgi", + "http://mtw.wc24.wii.com/cgi-bin/send.cgi", + }; - memset(&config, 0, sizeof(config)); + memset(&config, 0, sizeof(config)); - SetMagic(0x57634366); - SetUnk(8); - SetCreationStage(nwc24_config_t::NWC24_IDCS_INITIAL); - SetEnableBooting(0); - SetEmail("@wii.com"); + SetMagic(0x57634366); + SetUnk(8); + SetCreationStage(nwc24_config_t::NWC24_IDCS_INITIAL); + SetEnableBooting(0); + SetEmail("@wii.com"); - for (int i = 0; i < nwc24_config_t::URL_COUNT; ++i) - { - strncpy(config.http_urls[i], urls[i], nwc24_config_t::MAX_URL_LENGTH); - } + for (int i = 0; i < nwc24_config_t::URL_COUNT; ++i) + { + strncpy(config.http_urls[i], urls[i], nwc24_config_t::MAX_URL_LENGTH); + } - SetChecksum(CalculateNwc24ConfigChecksum()); + SetChecksum(CalculateNwc24ConfigChecksum()); - WriteConfig(); - } + WriteConfig(); + } - void WriteConfig() - { - if (!File::Exists(path)) - { - if (!File::CreateFullPath(File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/" WII_WC24CONF_DIR)) - { - ERROR_LOG(WII_IPC_WC24, "Failed to create directory for WC24"); - } - } + void WriteConfig() + { + if (!File::Exists(path)) + { + if (!File::CreateFullPath(File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/" WII_WC24CONF_DIR)) + { + ERROR_LOG(WII_IPC_WC24, "Failed to create directory for WC24"); + } + } - File::IOFile(path, "wb").WriteBytes((void*)&config, sizeof(config)); - } + File::IOFile(path, "wb").WriteBytes((void*)&config, sizeof(config)); + } + void ReadConfig() + { + if (File::Exists(path)) + { + if (!File::IOFile(path, "rb").ReadBytes((void*)&config, sizeof(config))) + ResetConfig(); + else + { + s32 config_error = CheckNwc24Config(); + if (config_error) + ERROR_LOG(WII_IPC_WC24, "There is an error in the config for for WC24: %d", config_error); + } + } + else + { + ResetConfig(); + } + } - void ReadConfig() - { - if (File::Exists(path)) - { - if (!File::IOFile(path, "rb").ReadBytes((void*)&config, sizeof(config))) - ResetConfig(); - else - { - s32 config_error = CheckNwc24Config(); - if (config_error) - ERROR_LOG(WII_IPC_WC24, "There is an error in the config for for WC24: %d", config_error); - } - } - else - { - ResetConfig(); - } - } + u32 CalculateNwc24ConfigChecksum() + { + u32* ptr = (u32*)&config; + u32 sum = 0; + for (int i = 0; i < 0xFF; ++i) + { + sum += Common::swap32(*ptr++); + } + return sum; + } - u32 CalculateNwc24ConfigChecksum() - { - u32* ptr = (u32*)&config; - u32 sum = 0; - for (int i = 0; i < 0xFF; ++i) - { - sum += Common::swap32(*ptr++); - } - return sum; - } + s32 CheckNwc24Config() + { + if (Magic() != 0x57634366) /* 'WcCf' magic */ + { + ERROR_LOG(WII_IPC_WC24, "Magic mismatch"); + return -14; + } + u32 checksum = CalculateNwc24ConfigChecksum(); + DEBUG_LOG(WII_IPC_WC24, "Checksum: %X", checksum); + if (Checksum() != checksum) + { + ERROR_LOG(WII_IPC_WC24, "Checksum mismatch expected %X and got %X", checksum, Checksum()); + return -14; + } + if (IdGen() > 0x1F) + { + ERROR_LOG(WII_IPC_WC24, "Id gen error"); + return -14; + } + if (Unk() != 8) + return -27; - s32 CheckNwc24Config() - { - if (Magic() != 0x57634366) /* 'WcCf' magic */ - { - ERROR_LOG(WII_IPC_WC24, "Magic mismatch"); - return -14; - } - u32 checksum = CalculateNwc24ConfigChecksum(); - DEBUG_LOG(WII_IPC_WC24, "Checksum: %X", checksum); - if (Checksum() != checksum) - { - ERROR_LOG(WII_IPC_WC24, "Checksum mismatch expected %X and got %X", checksum, Checksum()); - return -14; - } - if (IdGen() > 0x1F) - { - ERROR_LOG(WII_IPC_WC24, "Id gen error"); - return -14; - } - if (Unk() != 8) - return -27; + return 0; + } - return 0; - } + u32 Magic() const { return Common::swap32(config.magic); } + void SetMagic(u32 magic) { config.magic = Common::swap32(magic); } + u32 Unk() const { return Common::swap32(config._unk_04); } + void SetUnk(u32 _unk_04) { config._unk_04 = Common::swap32(_unk_04); } + u32 IdGen() const { return Common::swap32(config.id_generation); } + void SetIdGen(u32 id_generation) { config.id_generation = Common::swap32(id_generation); } + void IncrementIdGen() + { + u32 id_ctr = IdGen(); + id_ctr++; + id_ctr &= 0x1F; + SetIdGen(id_ctr); + } - u32 Magic() const { return Common::swap32(config.magic); } - void SetMagic(u32 magic) { config.magic = Common::swap32(magic); } + u32 Checksum() const { return Common::swap32(config.checksum); } + void SetChecksum(u32 checksum) { config.checksum = Common::swap32(checksum); } + u32 CreationStage() const { return Common::swap32(config.creation_stage); } + void SetCreationStage(u32 creation_stage) + { + config.creation_stage = Common::swap32(creation_stage); + } - u32 Unk() const { return Common::swap32(config._unk_04); } - void SetUnk(u32 _unk_04) { config._unk_04 = Common::swap32(_unk_04); } - - u32 IdGen() const { return Common::swap32(config.id_generation); } - void SetIdGen(u32 id_generation) { config.id_generation = Common::swap32(id_generation); } - - void IncrementIdGen() - { - u32 id_ctr = IdGen(); - id_ctr++; - id_ctr &= 0x1F; - SetIdGen(id_ctr); - } - - u32 Checksum() const { return Common::swap32(config.checksum); } - void SetChecksum(u32 checksum) { config.checksum = Common::swap32(checksum); } - - u32 CreationStage() const { return Common::swap32(config.creation_stage); } - void SetCreationStage(u32 creation_stage) { config.creation_stage = Common::swap32(creation_stage); } - - u32 EnableBooting() const { return Common::swap32(config.enable_booting); } - void SetEnableBooting(u32 enable_booting) { config.enable_booting = Common::swap32(enable_booting); } - - u64 Id() const { return Common::swap64(config.nwc24_id); } - void SetId(u64 nwc24_id) { config.nwc24_id = Common::swap64(nwc24_id); } - - const char* Email() const { return config.email; } - void SetEmail(const char* email) - { - strncpy(config.email, email, nwc24_config_t::MAX_EMAIL_LENGTH); - config.email[nwc24_config_t::MAX_EMAIL_LENGTH-1] = '\0'; - } + u32 EnableBooting() const { return Common::swap32(config.enable_booting); } + void SetEnableBooting(u32 enable_booting) + { + config.enable_booting = Common::swap32(enable_booting); + } + u64 Id() const { return Common::swap64(config.nwc24_id); } + void SetId(u64 nwc24_id) { config.nwc24_id = Common::swap64(nwc24_id); } + const char* Email() const { return config.email; } + void SetEmail(const char* email) + { + strncpy(config.email, email, nwc24_config_t::MAX_EMAIL_LENGTH); + config.email[nwc24_config_t::MAX_EMAIL_LENGTH - 1] = '\0'; + } }; class WiiNetConfig { - std::string path; - network_config_t config; + std::string path; + network_config_t config; public: - WiiNetConfig() - { - path = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/" WII_SYSCONF_DIR "/net/02/config.dat"; - ReadConfig(); - } + WiiNetConfig() + { + path = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/" WII_SYSCONF_DIR "/net/02/config.dat"; + ReadConfig(); + } - void ResetConfig() - { - if (File::Exists(path)) - File::Delete(path); + void ResetConfig() + { + if (File::Exists(path)) + File::Delete(path); - memset(&config, 0, sizeof(config)); - config.connType = network_config_t::IF_WIRED; - config.connection[0].flags = - netcfg_connection_t::WIRED_IF | - netcfg_connection_t::DNS_DHCP | - netcfg_connection_t::IP_DHCP | - netcfg_connection_t::CONNECTION_TEST_OK | - netcfg_connection_t::CONNECTION_SELECTED; + memset(&config, 0, sizeof(config)); + config.connType = network_config_t::IF_WIRED; + config.connection[0].flags = netcfg_connection_t::WIRED_IF | netcfg_connection_t::DNS_DHCP | + netcfg_connection_t::IP_DHCP | + netcfg_connection_t::CONNECTION_TEST_OK | + netcfg_connection_t::CONNECTION_SELECTED; - WriteConfig(); - } + WriteConfig(); + } - void WriteConfig() - { - if (!File::Exists(path)) - { - if (!File::CreateFullPath(std::string(File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/" WII_SYSCONF_DIR "/net/02/"))) - { - ERROR_LOG(WII_IPC_NET, "Failed to create directory for network config file"); - } - } + void WriteConfig() + { + if (!File::Exists(path)) + { + if (!File::CreateFullPath(std::string(File::GetUserPath(D_SESSION_WIIROOT_IDX) + + "/" WII_SYSCONF_DIR "/net/02/"))) + { + ERROR_LOG(WII_IPC_NET, "Failed to create directory for network config file"); + } + } - File::IOFile(path, "wb").WriteBytes((void*)&config, sizeof(config)); - } + File::IOFile(path, "wb").WriteBytes((void*)&config, sizeof(config)); + } - void WriteToMem(const u32 address) - { - Memory::CopyToEmu(address, &config, sizeof(config)); - } - - void ReadFromMem(const u32 address) - { - Memory::CopyFromEmu(&config, address, sizeof(config)); - } - - void ReadConfig() - { - if (File::Exists(path)) - { - if (!File::IOFile(path, "rb").ReadBytes((void*)&config, sizeof(config))) - ResetConfig(); - } - else - { - ResetConfig(); - } - } + void WriteToMem(const u32 address) { Memory::CopyToEmu(address, &config, sizeof(config)); } + void ReadFromMem(const u32 address) { Memory::CopyFromEmu(&config, address, sizeof(config)); } + void ReadConfig() + { + if (File::Exists(path)) + { + if (!File::IOFile(path, "rb").ReadBytes((void*)&config, sizeof(config))) + ResetConfig(); + } + else + { + ResetConfig(); + } + } }; - ////////////////////////////////////////////////////////////////////////// // KD is the IOS module responsible for implementing WiiConnect24 functionality. // It can perform HTTPS downloads, send and receive mail via SMTP, and execute a @@ -390,227 +379,215 @@ public: class CWII_IPC_HLE_Device_net_kd_request : public IWII_IPC_HLE_Device { public: - CWII_IPC_HLE_Device_net_kd_request(u32 _DeviceID, const std::string& _rDeviceName); + CWII_IPC_HLE_Device_net_kd_request(u32 _DeviceID, const std::string& _rDeviceName); - virtual ~CWII_IPC_HLE_Device_net_kd_request(); + virtual ~CWII_IPC_HLE_Device_net_kd_request(); - IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; - IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; - IPCCommandResult IOCtl(u32 _CommandAddress) override; + IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; + IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; + IPCCommandResult IOCtl(u32 _CommandAddress) override; private: - enum - { - IOCTL_NWC24_SUSPEND_SCHEDULAR = 0x01, - IOCTL_NWC24_EXEC_TRY_SUSPEND_SCHEDULAR = 0x02, - IOCTL_NWC24_EXEC_RESUME_SCHEDULAR = 0x03, - IOCTL_NWC24_KD_GET_TIME_TRIGGERS = 0x04, - IOCTL_NWC24_SET_SCHEDULE_SPAN = 0x05, - IOCTL_NWC24_STARTUP_SOCKET = 0x06, - IOCTL_NWC24_CLEANUP_SOCKET = 0x07, - IOCTL_NWC24_LOCK_SOCKET = 0x08, - IOCTL_NWC24_UNLOCK_SOCKET = 0x09, - IOCTL_NWC24_CHECK_MAIL_NOW = 0x0A, - IOCTL_NWC24_SEND_MAIL_NOW = 0x0B, - IOCTL_NWC24_RECEIVE_MAIL_NOW = 0x0C, - IOCTL_NWC24_SAVE_MAIL_NOW = 0x0D, - IOCTL_NWC24_DOWNLOAD_NOW_EX = 0x0E, - IOCTL_NWC24_REQUEST_GENERATED_USER_ID = 0x0F, - IOCTL_NWC24_REQUEST_REGISTER_USER_ID = 0x10, - IOCTL_NWC24_GET_SCHEDULAR_STAT = 0x1E, - IOCTL_NWC24_SET_FILTER_MODE = 0x1F, - IOCTL_NWC24_SET_DEBUG_MODE = 0x20, - IOCTL_NWC24_KD_SET_NEXT_WAKEUP = 0x21, - IOCTL_NWC24_SET_SCRIPT_MODE = 0x22, - IOCTL_NWC24_REQUEST_SHUTDOWN = 0x28, - }; + enum + { + IOCTL_NWC24_SUSPEND_SCHEDULAR = 0x01, + IOCTL_NWC24_EXEC_TRY_SUSPEND_SCHEDULAR = 0x02, + IOCTL_NWC24_EXEC_RESUME_SCHEDULAR = 0x03, + IOCTL_NWC24_KD_GET_TIME_TRIGGERS = 0x04, + IOCTL_NWC24_SET_SCHEDULE_SPAN = 0x05, + IOCTL_NWC24_STARTUP_SOCKET = 0x06, + IOCTL_NWC24_CLEANUP_SOCKET = 0x07, + IOCTL_NWC24_LOCK_SOCKET = 0x08, + IOCTL_NWC24_UNLOCK_SOCKET = 0x09, + IOCTL_NWC24_CHECK_MAIL_NOW = 0x0A, + IOCTL_NWC24_SEND_MAIL_NOW = 0x0B, + IOCTL_NWC24_RECEIVE_MAIL_NOW = 0x0C, + IOCTL_NWC24_SAVE_MAIL_NOW = 0x0D, + IOCTL_NWC24_DOWNLOAD_NOW_EX = 0x0E, + IOCTL_NWC24_REQUEST_GENERATED_USER_ID = 0x0F, + IOCTL_NWC24_REQUEST_REGISTER_USER_ID = 0x10, + IOCTL_NWC24_GET_SCHEDULAR_STAT = 0x1E, + IOCTL_NWC24_SET_FILTER_MODE = 0x1F, + IOCTL_NWC24_SET_DEBUG_MODE = 0x20, + IOCTL_NWC24_KD_SET_NEXT_WAKEUP = 0x21, + IOCTL_NWC24_SET_SCRIPT_MODE = 0x22, + IOCTL_NWC24_REQUEST_SHUTDOWN = 0x28, + }; - enum - { - MODEL_RVT = 0, - MODEL_RVV = 0, - MODEL_RVL = 1, - MODEL_RVD = 2, - MODEL_ELSE = 7 - }; + enum + { + MODEL_RVT = 0, + MODEL_RVV = 0, + MODEL_RVL = 1, + MODEL_RVD = 2, + MODEL_ELSE = 7 + }; - u8 GetAreaCode(const std::string& area) const; - u8 GetHardwareModel(const std::string& model) const; + u8 GetAreaCode(const std::string& area) const; + u8 GetHardwareModel(const std::string& model) const; - s32 NWC24MakeUserID(u64* nwc24_id, u32 hollywood_id, u16 id_ctr, u8 hardware_model, u8 area_code); + s32 NWC24MakeUserID(u64* nwc24_id, u32 hollywood_id, u16 id_ctr, u8 hardware_model, u8 area_code); - NWC24Config config; + NWC24Config config; }; - ////////////////////////////////////////////////////////////////////////// class CWII_IPC_HLE_Device_net_kd_time : public IWII_IPC_HLE_Device { public: - CWII_IPC_HLE_Device_net_kd_time(u32 _DeviceID, const std::string& _rDeviceName) - : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) - , rtc() - , utcdiff() - { - } + CWII_IPC_HLE_Device_net_kd_time(u32 _DeviceID, const std::string& _rDeviceName) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName), rtc(), utcdiff() + { + } - virtual ~CWII_IPC_HLE_Device_net_kd_time() - {} + virtual ~CWII_IPC_HLE_Device_net_kd_time() {} + IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override + { + INFO_LOG(WII_IPC_NET, "NET_KD_TIME: Open"); + Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); + return GetDefaultReply(); + } - IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override - { - INFO_LOG(WII_IPC_NET, "NET_KD_TIME: Open"); - Memory::Write_U32(GetDeviceID(), _CommandAddress+4); - return GetDefaultReply(); - } + IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override + { + INFO_LOG(WII_IPC_NET, "NET_KD_TIME: Close"); + if (!_bForce) + Memory::Write_U32(0, _CommandAddress + 4); + return GetDefaultReply(); + } - IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override - { - INFO_LOG(WII_IPC_NET, "NET_KD_TIME: Close"); - if (!_bForce) - Memory::Write_U32(0, _CommandAddress + 4); - return GetDefaultReply(); - } + IPCCommandResult IOCtl(u32 _CommandAddress) override + { + u32 Parameter = Memory::Read_U32(_CommandAddress + 0x0C); + u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); + u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - IPCCommandResult IOCtl(u32 _CommandAddress) override - { - u32 Parameter = Memory::Read_U32(_CommandAddress + 0x0C); - u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); - u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); + u32 result = 0; + u32 common_result = 0; + // TODO Writes stuff to /shared2/nwc24/misc.bin + // u32 update_misc = 0; - u32 result = 0; - u32 common_result = 0; - // TODO Writes stuff to /shared2/nwc24/misc.bin - //u32 update_misc = 0; + switch (Parameter) + { + case IOCTL_NW24_GET_UNIVERSAL_TIME: + Memory::Write_U64(GetAdjustedUTC(), BufferOut + 4); + break; - switch (Parameter) - { - case IOCTL_NW24_GET_UNIVERSAL_TIME: - Memory::Write_U64(GetAdjustedUTC(), BufferOut + 4); - break; + case IOCTL_NW24_SET_UNIVERSAL_TIME: + SetAdjustedUTC(Memory::Read_U64(BufferIn)); + // update_misc = Memory::Read_U32(BufferIn + 8); + break; - case IOCTL_NW24_SET_UNIVERSAL_TIME: - SetAdjustedUTC(Memory::Read_U64(BufferIn)); - //update_misc = Memory::Read_U32(BufferIn + 8); - break; + case IOCTL_NW24_SET_RTC_COUNTER: + rtc = Memory::Read_U32(BufferIn); + // update_misc = Memory::Read_U32(BufferIn + 4); + break; - case IOCTL_NW24_SET_RTC_COUNTER: - rtc = Memory::Read_U32(BufferIn); - //update_misc = Memory::Read_U32(BufferIn + 4); - break; + case IOCTL_NW24_GET_TIME_DIFF: + Memory::Write_U64(GetAdjustedUTC() - rtc, BufferOut + 4); + break; - case IOCTL_NW24_GET_TIME_DIFF: - Memory::Write_U64(GetAdjustedUTC() - rtc, BufferOut + 4); - break; + case IOCTL_NW24_UNIMPLEMENTED: + result = -9; + break; - case IOCTL_NW24_UNIMPLEMENTED: - result = -9; - break; + default: + ERROR_LOG(WII_IPC_NET, "%s - unknown IOCtl: %x\n", GetDeviceName().c_str(), Parameter); + break; + } - default: - ERROR_LOG(WII_IPC_NET, "%s - unknown IOCtl: %x\n", GetDeviceName().c_str(), Parameter); - break; - } - - // write return values - Memory::Write_U32(common_result, BufferOut); - Memory::Write_U32(result, _CommandAddress + 4); - return GetDefaultReply(); - } + // write return values + Memory::Write_U32(common_result, BufferOut); + Memory::Write_U32(result, _CommandAddress + 4); + return GetDefaultReply(); + } private: - enum - { - IOCTL_NW24_GET_UNIVERSAL_TIME = 0x14, - IOCTL_NW24_SET_UNIVERSAL_TIME = 0x15, - IOCTL_NW24_UNIMPLEMENTED = 0x16, - IOCTL_NW24_SET_RTC_COUNTER = 0x17, - IOCTL_NW24_GET_TIME_DIFF = 0x18, - }; + enum + { + IOCTL_NW24_GET_UNIVERSAL_TIME = 0x14, + IOCTL_NW24_SET_UNIVERSAL_TIME = 0x15, + IOCTL_NW24_UNIMPLEMENTED = 0x16, + IOCTL_NW24_SET_RTC_COUNTER = 0x17, + IOCTL_NW24_GET_TIME_DIFF = 0x18, + }; - u64 rtc; - s64 utcdiff; + u64 rtc; + s64 utcdiff; - // TODO: depending on CEXIIPL is a hack which I don't feel like removing - // because the function itself is pretty hackish; wait until I re-port my - // netplay rewrite; also, is that random 16:00:38 actually meaningful? - // seems very very doubtful since Wii was released in 2006 + // TODO: depending on CEXIIPL is a hack which I don't feel like removing + // because the function itself is pretty hackish; wait until I re-port my + // netplay rewrite; also, is that random 16:00:38 actually meaningful? + // seems very very doubtful since Wii was released in 2006 - // Seconds between 1.1.2000 and 4.1.2008 16:00:38 - static const u64 wii_bias = 0x477E5826 - 0x386D4380; + // Seconds between 1.1.2000 and 4.1.2008 16:00:38 + static const u64 wii_bias = 0x477E5826 - 0x386D4380; - // Returns seconds since Wii epoch - // +/- any bias set from IOCTL_NW24_SET_UNIVERSAL_TIME - u64 GetAdjustedUTC() const - { - return CEXIIPL::GetGCTime() - wii_bias + utcdiff; - } - - // Store the difference between what the Wii thinks is UTC and - // what the host OS thinks - void SetAdjustedUTC(u64 wii_utc) - { - utcdiff = CEXIIPL::GetGCTime() - wii_bias - wii_utc; - } + // Returns seconds since Wii epoch + // +/- any bias set from IOCTL_NW24_SET_UNIVERSAL_TIME + u64 GetAdjustedUTC() const { return CEXIIPL::GetGCTime() - wii_bias + utcdiff; } + // Store the difference between what the Wii thinks is UTC and + // what the host OS thinks + void SetAdjustedUTC(u64 wii_utc) { utcdiff = CEXIIPL::GetGCTime() - wii_bias - wii_utc; } }; enum NET_IOCTL { - IOCTL_SO_ACCEPT = 1, - IOCTL_SO_BIND, - IOCTL_SO_CLOSE, - IOCTL_SO_CONNECT, - IOCTL_SO_FCNTL, - IOCTL_SO_GETPEERNAME, - IOCTL_SO_GETSOCKNAME, - IOCTL_SO_GETSOCKOPT, - IOCTL_SO_SETSOCKOPT, - IOCTL_SO_LISTEN, - IOCTL_SO_POLL, - IOCTLV_SO_RECVFROM, - IOCTLV_SO_SENDTO, - IOCTL_SO_SHUTDOWN, - IOCTL_SO_SOCKET, - IOCTL_SO_GETHOSTID, - IOCTL_SO_GETHOSTBYNAME, - IOCTL_SO_GETHOSTBYADDR, - IOCTLV_SO_GETNAMEINFO, - IOCTL_SO_UNK14, - IOCTL_SO_INETATON, - IOCTL_SO_INETPTON, - IOCTL_SO_INETNTOP, - IOCTLV_SO_GETADDRINFO, - IOCTL_SO_SOCKATMARK, - IOCTLV_SO_UNK1A, - IOCTLV_SO_UNK1B, - IOCTLV_SO_GETINTERFACEOPT, - IOCTLV_SO_SETINTERFACEOPT, - IOCTL_SO_SETINTERFACE, - IOCTL_SO_STARTUP, - IOCTL_SO_ICMPSOCKET = 0x30, - IOCTLV_SO_ICMPPING, - IOCTL_SO_ICMPCANCEL, - IOCTL_SO_ICMPCLOSE + IOCTL_SO_ACCEPT = 1, + IOCTL_SO_BIND, + IOCTL_SO_CLOSE, + IOCTL_SO_CONNECT, + IOCTL_SO_FCNTL, + IOCTL_SO_GETPEERNAME, + IOCTL_SO_GETSOCKNAME, + IOCTL_SO_GETSOCKOPT, + IOCTL_SO_SETSOCKOPT, + IOCTL_SO_LISTEN, + IOCTL_SO_POLL, + IOCTLV_SO_RECVFROM, + IOCTLV_SO_SENDTO, + IOCTL_SO_SHUTDOWN, + IOCTL_SO_SOCKET, + IOCTL_SO_GETHOSTID, + IOCTL_SO_GETHOSTBYNAME, + IOCTL_SO_GETHOSTBYADDR, + IOCTLV_SO_GETNAMEINFO, + IOCTL_SO_UNK14, + IOCTL_SO_INETATON, + IOCTL_SO_INETPTON, + IOCTL_SO_INETNTOP, + IOCTLV_SO_GETADDRINFO, + IOCTL_SO_SOCKATMARK, + IOCTLV_SO_UNK1A, + IOCTLV_SO_UNK1B, + IOCTLV_SO_GETINTERFACEOPT, + IOCTLV_SO_SETINTERFACEOPT, + IOCTL_SO_SETINTERFACE, + IOCTL_SO_STARTUP, + IOCTL_SO_ICMPSOCKET = 0x30, + IOCTLV_SO_ICMPPING, + IOCTL_SO_ICMPCANCEL, + IOCTL_SO_ICMPCLOSE }; ////////////////////////////////////////////////////////////////////////// class CWII_IPC_HLE_Device_net_ip_top : public IWII_IPC_HLE_Device { public: - CWII_IPC_HLE_Device_net_ip_top(u32 _DeviceID, const std::string& _rDeviceName); + CWII_IPC_HLE_Device_net_ip_top(u32 _DeviceID, const std::string& _rDeviceName); - virtual ~CWII_IPC_HLE_Device_net_ip_top(); + virtual ~CWII_IPC_HLE_Device_net_ip_top(); - IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; - IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; - IPCCommandResult IOCtl(u32 _CommandAddress) override; - IPCCommandResult IOCtlV(u32 _CommandAddress) override; + IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; + IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; + IPCCommandResult IOCtl(u32 _CommandAddress) override; + IPCCommandResult IOCtlV(u32 _CommandAddress) override; - u32 Update() override; + u32 Update() override; private: #ifdef _WIN32 - WSADATA InitData; + WSADATA InitData; #endif }; @@ -619,120 +596,120 @@ private: class CWII_IPC_HLE_Device_net_ncd_manage : public IWII_IPC_HLE_Device { public: - CWII_IPC_HLE_Device_net_ncd_manage(u32 _DeviceID, const std::string& _rDeviceName); + CWII_IPC_HLE_Device_net_ncd_manage(u32 _DeviceID, const std::string& _rDeviceName); - virtual ~CWII_IPC_HLE_Device_net_ncd_manage(); + virtual ~CWII_IPC_HLE_Device_net_ncd_manage(); - IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; - IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; - IPCCommandResult IOCtlV(u32 _CommandAddress) override; + IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; + IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; + IPCCommandResult IOCtlV(u32 _CommandAddress) override; private: - enum - { - IOCTLV_NCD_LOCKWIRELESSDRIVER = 0x1, // NCDLockWirelessDriver - IOCTLV_NCD_UNLOCKWIRELESSDRIVER = 0x2, // NCDUnlockWirelessDriver - IOCTLV_NCD_GETCONFIG = 0x3, // NCDiGetConfig - IOCTLV_NCD_SETCONFIG = 0x4, // NCDiSetConfig - IOCTLV_NCD_READCONFIG = 0x5, - IOCTLV_NCD_WRITECONFIG = 0x6, - IOCTLV_NCD_GETLINKSTATUS = 0x7, // NCDGetLinkStatus - IOCTLV_NCD_GETWIRELESSMACADDRESS = 0x8, // NCDGetWirelessMacAddress - }; + enum + { + IOCTLV_NCD_LOCKWIRELESSDRIVER = 0x1, // NCDLockWirelessDriver + IOCTLV_NCD_UNLOCKWIRELESSDRIVER = 0x2, // NCDUnlockWirelessDriver + IOCTLV_NCD_GETCONFIG = 0x3, // NCDiGetConfig + IOCTLV_NCD_SETCONFIG = 0x4, // NCDiSetConfig + IOCTLV_NCD_READCONFIG = 0x5, + IOCTLV_NCD_WRITECONFIG = 0x6, + IOCTLV_NCD_GETLINKSTATUS = 0x7, // NCDGetLinkStatus + IOCTLV_NCD_GETWIRELESSMACADDRESS = 0x8, // NCDGetWirelessMacAddress + }; - WiiNetConfig config; + WiiNetConfig config; }; ////////////////////////////////////////////////////////////////////////// class CWII_IPC_HLE_Device_net_wd_command : public IWII_IPC_HLE_Device { public: - CWII_IPC_HLE_Device_net_wd_command(u32 DeviceID, const std::string& DeviceName); + CWII_IPC_HLE_Device_net_wd_command(u32 DeviceID, const std::string& DeviceName); - virtual ~CWII_IPC_HLE_Device_net_wd_command(); + virtual ~CWII_IPC_HLE_Device_net_wd_command(); - IPCCommandResult Open(u32 CommandAddress, u32 Mode) override; - IPCCommandResult Close(u32 CommandAddress, bool Force) override; - IPCCommandResult IOCtlV(u32 CommandAddress) override; + IPCCommandResult Open(u32 CommandAddress, u32 Mode) override; + IPCCommandResult Close(u32 CommandAddress, bool Force) override; + IPCCommandResult IOCtlV(u32 CommandAddress) override; private: - enum - { - IOCTLV_WD_GET_MODE = 0x1001, // WD_GetMode - IOCTLV_WD_SET_LINKSTATE = 0x1002, // WD_SetLinkState - IOCTLV_WD_GET_LINKSTATE = 0x1003, // WD_GetLinkState - IOCTLV_WD_SET_CONFIG = 0x1004, // WD_SetConfig - IOCTLV_WD_GET_CONFIG = 0x1005, // WD_GetConfig - IOCTLV_WD_CHANGE_BEACON = 0x1006, // WD_ChangeBeacon - IOCTLV_WD_DISASSOC = 0x1007, // WD_DisAssoc - IOCTLV_WD_MP_SEND_FRAME = 0x1008, // WD_MpSendFrame - IOCTLV_WD_SEND_FRAME = 0x1009, // WD_SendFrame - IOCTLV_WD_SCAN = 0x100a, // WD_Scan - IOCTLV_WD_CALL_WL = 0x100c, // WD_CallWL - IOCTLV_WD_MEASURE_CHANNEL = 0x100b, // WD_MeasureChannel - IOCTLV_WD_GET_LASTERROR = 0x100d, // WD_GetLastError - IOCTLV_WD_GET_INFO = 0x100e, // WD_GetInfo - IOCTLV_WD_CHANGE_GAMEINFO = 0x100f, // WD_ChangeGameInfo - IOCTLV_WD_CHANGE_VTSF = 0x1010, // WD_ChangeVTSF - IOCTLV_WD_RECV_FRAME = 0x8000, // WD_ReceiveFrame - IOCTLV_WD_RECV_NOTIFICATION = 0x8001 // WD_ReceiveNotification - }; + enum + { + IOCTLV_WD_GET_MODE = 0x1001, // WD_GetMode + IOCTLV_WD_SET_LINKSTATE = 0x1002, // WD_SetLinkState + IOCTLV_WD_GET_LINKSTATE = 0x1003, // WD_GetLinkState + IOCTLV_WD_SET_CONFIG = 0x1004, // WD_SetConfig + IOCTLV_WD_GET_CONFIG = 0x1005, // WD_GetConfig + IOCTLV_WD_CHANGE_BEACON = 0x1006, // WD_ChangeBeacon + IOCTLV_WD_DISASSOC = 0x1007, // WD_DisAssoc + IOCTLV_WD_MP_SEND_FRAME = 0x1008, // WD_MpSendFrame + IOCTLV_WD_SEND_FRAME = 0x1009, // WD_SendFrame + IOCTLV_WD_SCAN = 0x100a, // WD_Scan + IOCTLV_WD_CALL_WL = 0x100c, // WD_CallWL + IOCTLV_WD_MEASURE_CHANNEL = 0x100b, // WD_MeasureChannel + IOCTLV_WD_GET_LASTERROR = 0x100d, // WD_GetLastError + IOCTLV_WD_GET_INFO = 0x100e, // WD_GetInfo + IOCTLV_WD_CHANGE_GAMEINFO = 0x100f, // WD_ChangeGameInfo + IOCTLV_WD_CHANGE_VTSF = 0x1010, // WD_ChangeVTSF + IOCTLV_WD_RECV_FRAME = 0x8000, // WD_ReceiveFrame + IOCTLV_WD_RECV_NOTIFICATION = 0x8001 // WD_ReceiveNotification + }; - enum - { - BSSID_SIZE = 6, - SSID_SIZE = 32 - }; + enum + { + BSSID_SIZE = 6, + SSID_SIZE = 32 + }; - enum - { - SCAN_ACTIVE, - SCAN_PASSIVE - }; + enum + { + SCAN_ACTIVE, + SCAN_PASSIVE + }; #pragma pack(push, 1) - struct ScanInfo - { - u16 channel_bitmap; - u16 max_channel_time; - u8 bssid[BSSID_SIZE]; - u16 scan_type; - u16 ssid_length; - u8 ssid[SSID_SIZE]; - u8 ssid_match_mask[SSID_SIZE]; - }; + struct ScanInfo + { + u16 channel_bitmap; + u16 max_channel_time; + u8 bssid[BSSID_SIZE]; + u16 scan_type; + u16 ssid_length; + u8 ssid[SSID_SIZE]; + u8 ssid_match_mask[SSID_SIZE]; + }; - struct BSSInfo - { - u16 length; - u16 rssi; - u8 bssid[BSSID_SIZE]; - u16 ssid_length; - u8 ssid[SSID_SIZE]; - u16 capabilities; - struct rate - { - u16 basic; - u16 support; - }; - u16 beacon_period; - u16 DTIM_period; - u16 channel; - u16 CF_period; - u16 CF_max_duration; - u16 element_info_length; - u16 element_info[1]; - }; + struct BSSInfo + { + u16 length; + u16 rssi; + u8 bssid[BSSID_SIZE]; + u16 ssid_length; + u8 ssid[SSID_SIZE]; + u16 capabilities; + struct rate + { + u16 basic; + u16 support; + }; + u16 beacon_period; + u16 DTIM_period; + u16 channel; + u16 CF_period; + u16 CF_max_duration; + u16 element_info_length; + u16 element_info[1]; + }; - struct Info - { - u8 mac[6]; - u16 ntr_allowed_channels; - u16 unk8; - char country[2]; - u32 unkc; - char wlversion[0x50]; - u8 unk[0x30]; - }; + struct Info + { + u8 mac[6]; + u16 ntr_allowed_channels; + u16 unk8; + char country[2]; + u32 unkc; + char wlversion[0x50]; + u8 unk[0x30]; + }; #pragma pack(pop) }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp index 82e7895b25..4a4e9823b3 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp @@ -12,511 +12,494 @@ WII_SSL CWII_IPC_HLE_Device_net_ssl::_SSL[NET_SSL_MAXINSTANCES]; -CWII_IPC_HLE_Device_net_ssl::CWII_IPC_HLE_Device_net_ssl(u32 _DeviceID, const std::string& _rDeviceName) - : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) +CWII_IPC_HLE_Device_net_ssl::CWII_IPC_HLE_Device_net_ssl(u32 _DeviceID, + const std::string& _rDeviceName) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) { - for (WII_SSL& ssl : _SSL) - { - ssl.active = false; - } + for (WII_SSL& ssl : _SSL) + { + ssl.active = false; + } } CWII_IPC_HLE_Device_net_ssl::~CWII_IPC_HLE_Device_net_ssl() { - // Cleanup sessions - for (WII_SSL& ssl : _SSL) - { - if (ssl.active) - { - mbedtls_ssl_close_notify(&ssl.ctx); - mbedtls_ssl_session_free(&ssl.session); - mbedtls_ssl_free(&ssl.ctx); - mbedtls_ssl_config_free(&ssl.config); + // Cleanup sessions + for (WII_SSL& ssl : _SSL) + { + if (ssl.active) + { + mbedtls_ssl_close_notify(&ssl.ctx); + mbedtls_ssl_session_free(&ssl.session); + mbedtls_ssl_free(&ssl.ctx); + mbedtls_ssl_config_free(&ssl.config); - mbedtls_x509_crt_free(&ssl.cacert); - mbedtls_x509_crt_free(&ssl.clicert); + mbedtls_x509_crt_free(&ssl.cacert); + mbedtls_x509_crt_free(&ssl.clicert); - ssl.hostname.clear(); + ssl.hostname.clear(); - ssl.active = false; - } - } + ssl.active = false; + } + } } int CWII_IPC_HLE_Device_net_ssl::GetSSLFreeID() const { - for (int i = 0; i < NET_SSL_MAXINSTANCES; i++) - { - if (!_SSL[i].active) - { - return i + 1; - } - } - return 0; + for (int i = 0; i < NET_SSL_MAXINSTANCES; i++) + { + if (!_SSL[i].active) + { + return i + 1; + } + } + return 0; } IPCCommandResult CWII_IPC_HLE_Device_net_ssl::Open(u32 _CommandAddress, u32 _Mode) { - Memory::Write_U32(GetDeviceID(), _CommandAddress+4); - m_Active = true; - return GetDefaultReply(); + Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); + m_Active = true; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_net_ssl::Close(u32 _CommandAddress, bool _bForce) { - if (!_bForce) - { - Memory::Write_U32(0, _CommandAddress + 4); - } - m_Active = false; - return GetDefaultReply(); + if (!_bForce) + { + Memory::Write_U32(0, _CommandAddress + 4); + } + m_Active = false; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_net_ssl::IOCtl(u32 _CommandAddress) { - u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); - u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); - u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); - u32 Command = Memory::Read_U32(_CommandAddress + 0x0C); + u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); + u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); + u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); + u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); + u32 Command = Memory::Read_U32(_CommandAddress + 0x0C); - INFO_LOG(WII_IPC_SSL, "%s unknown %i " - "(BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - GetDeviceName().c_str(), Command, - BufferIn, BufferInSize, BufferOut, BufferOutSize); - Memory::Write_U32(0, _CommandAddress + 0x4); - return GetDefaultReply(); + INFO_LOG(WII_IPC_SSL, "%s unknown %i " + "(BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + GetDeviceName().c_str(), Command, BufferIn, BufferInSize, BufferOut, BufferOutSize); + Memory::Write_U32(0, _CommandAddress + 0x4); + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_net_ssl::IOCtlV(u32 _CommandAddress) { - SIOCtlVBuffer CommandBuffer(_CommandAddress); + SIOCtlVBuffer CommandBuffer(_CommandAddress); - u32 _BufferIn = 0, _BufferIn2 = 0, _BufferIn3 = 0; - u32 BufferInSize = 0, BufferInSize2 = 0, BufferInSize3 = 0; + u32 _BufferIn = 0, _BufferIn2 = 0, _BufferIn3 = 0; + u32 BufferInSize = 0, BufferInSize2 = 0, BufferInSize3 = 0; - u32 BufferOut = 0, BufferOut2 = 0, BufferOut3 = 0; - u32 BufferOutSize = 0, BufferOutSize2 = 0, BufferOutSize3 = 0; + u32 BufferOut = 0, BufferOut2 = 0, BufferOut3 = 0; + u32 BufferOutSize = 0, BufferOutSize2 = 0, BufferOutSize3 = 0; - if (CommandBuffer.InBuffer.size() > 0) - { - _BufferIn = CommandBuffer.InBuffer.at(0).m_Address; - BufferInSize = CommandBuffer.InBuffer.at(0).m_Size; - } - if (CommandBuffer.InBuffer.size() > 1) - { - _BufferIn2 = CommandBuffer.InBuffer.at(1).m_Address; - BufferInSize2 = CommandBuffer.InBuffer.at(1).m_Size; - } - if (CommandBuffer.InBuffer.size() > 2) - { - _BufferIn3 = CommandBuffer.InBuffer.at(2).m_Address; - BufferInSize3 = CommandBuffer.InBuffer.at(2).m_Size; - } + if (CommandBuffer.InBuffer.size() > 0) + { + _BufferIn = CommandBuffer.InBuffer.at(0).m_Address; + BufferInSize = CommandBuffer.InBuffer.at(0).m_Size; + } + if (CommandBuffer.InBuffer.size() > 1) + { + _BufferIn2 = CommandBuffer.InBuffer.at(1).m_Address; + BufferInSize2 = CommandBuffer.InBuffer.at(1).m_Size; + } + if (CommandBuffer.InBuffer.size() > 2) + { + _BufferIn3 = CommandBuffer.InBuffer.at(2).m_Address; + BufferInSize3 = CommandBuffer.InBuffer.at(2).m_Size; + } - if (CommandBuffer.PayloadBuffer.size() > 0) - { - BufferOut = CommandBuffer.PayloadBuffer.at(0).m_Address; - BufferOutSize = CommandBuffer.PayloadBuffer.at(0).m_Size; - } - if (CommandBuffer.PayloadBuffer.size() > 1) - { - BufferOut2 = CommandBuffer.PayloadBuffer.at(1).m_Address; - BufferOutSize2 = CommandBuffer.PayloadBuffer.at(1).m_Size; - } - if (CommandBuffer.PayloadBuffer.size() > 2) - { - BufferOut3 = CommandBuffer.PayloadBuffer.at(2).m_Address; - BufferOutSize3 = CommandBuffer.PayloadBuffer.at(2).m_Size; - } + if (CommandBuffer.PayloadBuffer.size() > 0) + { + BufferOut = CommandBuffer.PayloadBuffer.at(0).m_Address; + BufferOutSize = CommandBuffer.PayloadBuffer.at(0).m_Size; + } + if (CommandBuffer.PayloadBuffer.size() > 1) + { + BufferOut2 = CommandBuffer.PayloadBuffer.at(1).m_Address; + BufferOutSize2 = CommandBuffer.PayloadBuffer.at(1).m_Size; + } + if (CommandBuffer.PayloadBuffer.size() > 2) + { + BufferOut3 = CommandBuffer.PayloadBuffer.at(2).m_Address; + BufferOutSize3 = CommandBuffer.PayloadBuffer.at(2).m_Size; + } - // I don't trust SSL to be deterministic, and this is never going to sync - // as such (as opposed to forwarding IPC results or whatever), so - - if (Core::g_want_determinism) - { - Memory::Write_U32(-1, _CommandAddress + 0x4); - return GetDefaultReply(); - } + // I don't trust SSL to be deterministic, and this is never going to sync + // as such (as opposed to forwarding IPC results or whatever), so - + if (Core::g_want_determinism) + { + Memory::Write_U32(-1, _CommandAddress + 0x4); + return GetDefaultReply(); + } - switch (CommandBuffer.Parameter) - { - case IOCTLV_NET_SSL_NEW: - { - int verifyOption = Memory::Read_U32(BufferOut); - std::string hostname = Memory::GetString(BufferOut2, BufferOutSize2); + switch (CommandBuffer.Parameter) + { + case IOCTLV_NET_SSL_NEW: + { + int verifyOption = Memory::Read_U32(BufferOut); + std::string hostname = Memory::GetString(BufferOut2, BufferOutSize2); - int freeSSL = GetSSLFreeID(); - if (freeSSL) - { - int sslID = freeSSL - 1; - WII_SSL* ssl = &_SSL[sslID]; - mbedtls_ssl_init(&ssl->ctx); - mbedtls_entropy_init(&ssl->entropy); - const char* pers = "dolphin-emu"; - mbedtls_ctr_drbg_init(&ssl->ctr_drbg); - int ret = mbedtls_ctr_drbg_seed(&ssl->ctr_drbg, mbedtls_entropy_func, - &ssl->entropy, - (const unsigned char*)pers, - strlen(pers)); - if (ret) - { - mbedtls_ssl_free(&ssl->ctx); - mbedtls_entropy_free(&ssl->entropy); - goto _SSL_NEW_ERROR; - } + int freeSSL = GetSSLFreeID(); + if (freeSSL) + { + int sslID = freeSSL - 1; + WII_SSL* ssl = &_SSL[sslID]; + mbedtls_ssl_init(&ssl->ctx); + mbedtls_entropy_init(&ssl->entropy); + const char* pers = "dolphin-emu"; + mbedtls_ctr_drbg_init(&ssl->ctr_drbg); + int ret = mbedtls_ctr_drbg_seed(&ssl->ctr_drbg, mbedtls_entropy_func, &ssl->entropy, + (const unsigned char*)pers, strlen(pers)); + if (ret) + { + mbedtls_ssl_free(&ssl->ctx); + mbedtls_entropy_free(&ssl->entropy); + goto _SSL_NEW_ERROR; + } - mbedtls_ssl_config_init(&ssl->config); - mbedtls_ssl_config_defaults(&ssl->config, MBEDTLS_SSL_IS_CLIENT, - MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); - mbedtls_ssl_conf_rng(&ssl->config, mbedtls_ctr_drbg_random, &ssl->ctr_drbg); + mbedtls_ssl_config_init(&ssl->config); + mbedtls_ssl_config_defaults(&ssl->config, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT); + mbedtls_ssl_conf_rng(&ssl->config, mbedtls_ctr_drbg_random, &ssl->ctr_drbg); - // For some reason we can't use TLSv1.2, v1.1 and below are fine! - mbedtls_ssl_conf_max_version(&ssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_2); + // For some reason we can't use TLSv1.2, v1.1 and below are fine! + mbedtls_ssl_conf_max_version(&ssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + MBEDTLS_SSL_MINOR_VERSION_2); - mbedtls_ssl_set_session(&ssl->ctx, &ssl->session); + mbedtls_ssl_set_session(&ssl->ctx, &ssl->session); - mbedtls_ssl_conf_authmode(&ssl->config, MBEDTLS_SSL_VERIFY_NONE); - mbedtls_ssl_conf_renegotiation(&ssl->config, MBEDTLS_SSL_RENEGOTIATION_ENABLED); + mbedtls_ssl_conf_authmode(&ssl->config, MBEDTLS_SSL_VERIFY_NONE); + mbedtls_ssl_conf_renegotiation(&ssl->config, MBEDTLS_SSL_RENEGOTIATION_ENABLED); - ssl->hostname = hostname; - mbedtls_ssl_set_hostname(&ssl->ctx, ssl->hostname.c_str()); + ssl->hostname = hostname; + mbedtls_ssl_set_hostname(&ssl->ctx, ssl->hostname.c_str()); - ssl->active = true; - Memory::Write_U32(freeSSL, _BufferIn); - } - else - { -_SSL_NEW_ERROR: - Memory::Write_U32(SSL_ERR_FAILED, _BufferIn); - } + ssl->active = true; + Memory::Write_U32(freeSSL, _BufferIn); + } + else + { + _SSL_NEW_ERROR: + Memory::Write_U32(SSL_ERR_FAILED, _BufferIn); + } - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_NEW (%d, %s) " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " - "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", - verifyOption, hostname.c_str(), - _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, - _BufferIn3, BufferInSize3, BufferOut, BufferOutSize, - BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); - break; - } - case IOCTLV_NET_SSL_SHUTDOWN: - { - int sslID = Memory::Read_U32(BufferOut) - 1; - if (SSLID_VALID(sslID)) - { - WII_SSL* ssl = &_SSL[sslID]; - mbedtls_ssl_close_notify(&ssl->ctx); - mbedtls_ssl_session_free(&ssl->session); - mbedtls_ssl_free(&ssl->ctx); - mbedtls_ssl_config_free(&ssl->config); + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_NEW (%d, %s) " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " + "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", + verifyOption, hostname.c_str(), _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, + _BufferIn3, BufferInSize3, BufferOut, BufferOutSize, BufferOut2, BufferOutSize2, + BufferOut3, BufferOutSize3); + break; + } + case IOCTLV_NET_SSL_SHUTDOWN: + { + int sslID = Memory::Read_U32(BufferOut) - 1; + if (SSLID_VALID(sslID)) + { + WII_SSL* ssl = &_SSL[sslID]; + mbedtls_ssl_close_notify(&ssl->ctx); + mbedtls_ssl_session_free(&ssl->session); + mbedtls_ssl_free(&ssl->ctx); + mbedtls_ssl_config_free(&ssl->config); - mbedtls_entropy_free(&ssl->entropy); + mbedtls_entropy_free(&ssl->entropy); - mbedtls_x509_crt_free(&ssl->cacert); - mbedtls_x509_crt_free(&ssl->clicert); + mbedtls_x509_crt_free(&ssl->cacert); + mbedtls_x509_crt_free(&ssl->clicert); - ssl->hostname.clear(); + ssl->hostname.clear(); - ssl->active = false; + ssl->active = false; - Memory::Write_U32(SSL_OK, _BufferIn); - } - else - { - Memory::Write_U32(SSL_ERR_ID, _BufferIn); - } - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SHUTDOWN " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " - "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", - _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, - _BufferIn3, BufferInSize3, BufferOut, BufferOutSize, - BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); - break; - } - case IOCTLV_NET_SSL_SETROOTCA: - { - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETROOTCA " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " - "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", - _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, - _BufferIn3, BufferInSize3, BufferOut, BufferOutSize, - BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); + Memory::Write_U32(SSL_OK, _BufferIn); + } + else + { + Memory::Write_U32(SSL_ERR_ID, _BufferIn); + } + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SHUTDOWN " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " + "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", + _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, _BufferIn3, BufferInSize3, + BufferOut, BufferOutSize, BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); + break; + } + case IOCTLV_NET_SSL_SETROOTCA: + { + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETROOTCA " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " + "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", + _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, _BufferIn3, BufferInSize3, + BufferOut, BufferOutSize, BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); + int sslID = Memory::Read_U32(BufferOut) - 1; + if (SSLID_VALID(sslID)) + { + WII_SSL* ssl = &_SSL[sslID]; + int ret = + mbedtls_x509_crt_parse_der(&ssl->cacert, Memory::GetPointer(BufferOut2), BufferOutSize2); - int sslID = Memory::Read_U32(BufferOut) - 1; - if (SSLID_VALID(sslID)) - { - WII_SSL* ssl = &_SSL[sslID]; - int ret = mbedtls_x509_crt_parse_der( - &ssl->cacert, - Memory::GetPointer(BufferOut2), - BufferOutSize2); + if (ret) + { + Memory::Write_U32(SSL_ERR_FAILED, _BufferIn); + } + else + { + mbedtls_ssl_conf_ca_chain(&ssl->config, &ssl->cacert, nullptr); + Memory::Write_U32(SSL_OK, _BufferIn); + } - if (ret) - { - Memory::Write_U32(SSL_ERR_FAILED, _BufferIn); - } - else - { - mbedtls_ssl_conf_ca_chain(&ssl->config, &ssl->cacert, nullptr); - Memory::Write_U32(SSL_OK, _BufferIn); - } + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETROOTCA = %d", ret); + } + else + { + Memory::Write_U32(SSL_ERR_ID, _BufferIn); + } + break; + } + case IOCTLV_NET_SSL_SETBUILTINCLIENTCERT: + { + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETBUILTINCLIENTCERT " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " + "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", + _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, _BufferIn3, BufferInSize3, + BufferOut, BufferOutSize, BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETROOTCA = %d", ret); - } - else - { - Memory::Write_U32(SSL_ERR_ID, _BufferIn); - } - break; - } - case IOCTLV_NET_SSL_SETBUILTINCLIENTCERT: - { - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETBUILTINCLIENTCERT " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " - "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", - _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, - _BufferIn3, BufferInSize3, BufferOut, BufferOutSize, - BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); + int sslID = Memory::Read_U32(BufferOut) - 1; + if (SSLID_VALID(sslID)) + { + WII_SSL* ssl = &_SSL[sslID]; + std::string cert_base_path = File::GetUserPath(D_SESSION_WIIROOT_IDX); + int ret = + mbedtls_x509_crt_parse_file(&ssl->clicert, (cert_base_path + "/clientca.pem").c_str()); + int pk_ret = mbedtls_pk_parse_keyfile(&ssl->pk, (cert_base_path + "/clientcakey.pem").c_str(), + nullptr); + if (ret || pk_ret) + { + mbedtls_x509_crt_free(&ssl->clicert); + mbedtls_pk_free(&ssl->pk); + Memory::Write_U32(SSL_ERR_FAILED, _BufferIn); + } + else + { + mbedtls_ssl_conf_own_cert(&ssl->config, &ssl->clicert, &ssl->pk); + Memory::Write_U32(SSL_OK, _BufferIn); + } - int sslID = Memory::Read_U32(BufferOut) - 1; - if (SSLID_VALID(sslID)) - { - WII_SSL* ssl = &_SSL[sslID]; - std::string cert_base_path = File::GetUserPath(D_SESSION_WIIROOT_IDX); - int ret = mbedtls_x509_crt_parse_file(&ssl->clicert, (cert_base_path + "/clientca.pem").c_str()); - int pk_ret = mbedtls_pk_parse_keyfile(&ssl->pk, (cert_base_path + "/clientcakey.pem").c_str(), nullptr); - if (ret || pk_ret) - { - mbedtls_x509_crt_free(&ssl->clicert); - mbedtls_pk_free(&ssl->pk); - Memory::Write_U32(SSL_ERR_FAILED, _BufferIn); - } - else - { - mbedtls_ssl_conf_own_cert(&ssl->config, &ssl->clicert, &ssl->pk); - Memory::Write_U32(SSL_OK, _BufferIn); - } + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETBUILTINCLIENTCERT = (%d, %d)", ret, pk_ret); + } + else + { + Memory::Write_U32(SSL_ERR_ID, _BufferIn); + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETBUILTINCLIENTCERT invalid sslID = %d", sslID); + } + break; + } + case IOCTLV_NET_SSL_REMOVECLIENTCERT: + { + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_REMOVECLIENTCERT " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " + "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", + _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, _BufferIn3, BufferInSize3, + BufferOut, BufferOutSize, BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETBUILTINCLIENTCERT = (%d, %d)", ret, pk_ret); - } - else - { - Memory::Write_U32(SSL_ERR_ID, _BufferIn); - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETBUILTINCLIENTCERT invalid sslID = %d", sslID); - } - break; - } - case IOCTLV_NET_SSL_REMOVECLIENTCERT: - { - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_REMOVECLIENTCERT " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " - "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", - _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, - _BufferIn3, BufferInSize3, BufferOut, BufferOutSize, - BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); + int sslID = Memory::Read_U32(BufferOut) - 1; + if (SSLID_VALID(sslID)) + { + WII_SSL* ssl = &_SSL[sslID]; + mbedtls_x509_crt_free(&ssl->clicert); + mbedtls_pk_free(&ssl->pk); - int sslID = Memory::Read_U32(BufferOut) - 1; - if (SSLID_VALID(sslID)) - { - WII_SSL* ssl = &_SSL[sslID]; - mbedtls_x509_crt_free(&ssl->clicert); - mbedtls_pk_free(&ssl->pk); + mbedtls_ssl_conf_own_cert(&ssl->config, nullptr, nullptr); + Memory::Write_U32(SSL_OK, _BufferIn); + } + else + { + Memory::Write_U32(SSL_ERR_ID, _BufferIn); + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETBUILTINCLIENTCERT invalid sslID = %d", sslID); + } + break; + } + case IOCTLV_NET_SSL_SETBUILTINROOTCA: + { + int sslID = Memory::Read_U32(BufferOut) - 1; + if (SSLID_VALID(sslID)) + { + WII_SSL* ssl = &_SSL[sslID]; - mbedtls_ssl_conf_own_cert(&ssl->config, nullptr, nullptr); - Memory::Write_U32(SSL_OK, _BufferIn); - } - else - { - Memory::Write_U32(SSL_ERR_ID, _BufferIn); - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETBUILTINCLIENTCERT invalid sslID = %d", sslID); - } - break; - } - case IOCTLV_NET_SSL_SETBUILTINROOTCA: - { - int sslID = Memory::Read_U32(BufferOut) - 1; - if (SSLID_VALID(sslID)) - { - WII_SSL* ssl = &_SSL[sslID]; + int ret = mbedtls_x509_crt_parse_file( + &ssl->cacert, (File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/rootca.pem").c_str()); + if (ret) + { + mbedtls_x509_crt_free(&ssl->clicert); + Memory::Write_U32(SSL_ERR_FAILED, _BufferIn); + } + else + { + mbedtls_ssl_conf_ca_chain(&ssl->config, &ssl->cacert, nullptr); + Memory::Write_U32(SSL_OK, _BufferIn); + } + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETBUILTINROOTCA = %d", ret); + } + else + { + Memory::Write_U32(SSL_ERR_ID, _BufferIn); + } + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETBUILTINROOTCA " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " + "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", + _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, _BufferIn3, BufferInSize3, + BufferOut, BufferOutSize, BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); + break; + } + case IOCTLV_NET_SSL_CONNECT: + { + int sslID = Memory::Read_U32(BufferOut) - 1; + if (SSLID_VALID(sslID)) + { + WII_SSL* ssl = &_SSL[sslID]; + mbedtls_ssl_setup(&ssl->ctx, &ssl->config); + ssl->sockfd = Memory::Read_U32(BufferOut2); + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_CONNECT socket = %d", ssl->sockfd); + mbedtls_ssl_set_bio(&ssl->ctx, &ssl->sockfd, mbedtls_net_send, mbedtls_net_recv, nullptr); + Memory::Write_U32(SSL_OK, _BufferIn); + } + else + { + Memory::Write_U32(SSL_ERR_ID, _BufferIn); + } + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_CONNECT " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " + "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", + _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, _BufferIn3, BufferInSize3, + BufferOut, BufferOutSize, BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); + break; + } + case IOCTLV_NET_SSL_DOHANDSHAKE: + { + int sslID = Memory::Read_U32(BufferOut) - 1; + if (SSLID_VALID(sslID)) + { + WiiSockMan& sm = WiiSockMan::GetInstance(); + sm.DoSock(_SSL[sslID].sockfd, _CommandAddress, IOCTLV_NET_SSL_DOHANDSHAKE); + return GetNoReply(); + } + else + { + Memory::Write_U32(SSL_ERR_ID, _BufferIn); + } + break; + } + case IOCTLV_NET_SSL_WRITE: + { + int sslID = Memory::Read_U32(BufferOut) - 1; + if (SSLID_VALID(sslID)) + { + WiiSockMan& sm = WiiSockMan::GetInstance(); + sm.DoSock(_SSL[sslID].sockfd, _CommandAddress, IOCTLV_NET_SSL_WRITE); + return GetNoReply(); + } + else + { + Memory::Write_U32(SSL_ERR_ID, _BufferIn); + } + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_WRITE " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " + "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", + _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, _BufferIn3, BufferInSize3, + BufferOut, BufferOutSize, BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); + INFO_LOG(WII_IPC_SSL, "%s", Memory::GetString(BufferOut2).c_str()); + break; + } + case IOCTLV_NET_SSL_READ: + { + int ret = 0; + int sslID = Memory::Read_U32(BufferOut) - 1; + if (SSLID_VALID(sslID)) + { + WiiSockMan& sm = WiiSockMan::GetInstance(); + sm.DoSock(_SSL[sslID].sockfd, _CommandAddress, IOCTLV_NET_SSL_READ); + return GetNoReply(); + } + else + { + Memory::Write_U32(SSL_ERR_ID, _BufferIn); + } - int ret = mbedtls_x509_crt_parse_file(&ssl->cacert, (File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/rootca.pem").c_str()); - if (ret) - { - mbedtls_x509_crt_free(&ssl->clicert); - Memory::Write_U32(SSL_ERR_FAILED, _BufferIn); - } - else - { - mbedtls_ssl_conf_ca_chain(&ssl->config, &ssl->cacert, nullptr); - Memory::Write_U32(SSL_OK, _BufferIn); - } - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETBUILTINROOTCA = %d", ret); - } - else - { - Memory::Write_U32(SSL_ERR_ID, _BufferIn); - } - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETBUILTINROOTCA " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " - "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", - _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, - _BufferIn3, BufferInSize3, BufferOut, BufferOutSize, - BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); - break; - } - case IOCTLV_NET_SSL_CONNECT: - { - int sslID = Memory::Read_U32(BufferOut) - 1; - if (SSLID_VALID(sslID)) - { - WII_SSL* ssl = &_SSL[sslID]; - mbedtls_ssl_setup(&ssl->ctx, &ssl->config); - ssl->sockfd = Memory::Read_U32(BufferOut2); - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_CONNECT socket = %d", ssl->sockfd); - mbedtls_ssl_set_bio(&ssl->ctx, &ssl->sockfd, mbedtls_net_send, - mbedtls_net_recv, nullptr); - Memory::Write_U32(SSL_OK, _BufferIn); - } - else - { - Memory::Write_U32(SSL_ERR_ID, _BufferIn); - } - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_CONNECT " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " - "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", - _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, - _BufferIn3, BufferInSize3, BufferOut, BufferOutSize, - BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); - break; - } - case IOCTLV_NET_SSL_DOHANDSHAKE: - { - int sslID = Memory::Read_U32(BufferOut) - 1; - if (SSLID_VALID(sslID)) - { - WiiSockMan &sm = WiiSockMan::GetInstance(); - sm.DoSock(_SSL[sslID].sockfd, _CommandAddress, IOCTLV_NET_SSL_DOHANDSHAKE); - return GetNoReply(); - } - else - { - Memory::Write_U32(SSL_ERR_ID, _BufferIn); - } - break; - } - case IOCTLV_NET_SSL_WRITE: - { - int sslID = Memory::Read_U32(BufferOut) - 1; - if (SSLID_VALID(sslID)) - { - WiiSockMan &sm = WiiSockMan::GetInstance(); - sm.DoSock(_SSL[sslID].sockfd, _CommandAddress, IOCTLV_NET_SSL_WRITE); - return GetNoReply(); - } - else - { - Memory::Write_U32(SSL_ERR_ID, _BufferIn); - } - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_WRITE " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " - "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", - _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, - _BufferIn3, BufferInSize3, BufferOut, BufferOutSize, - BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); - INFO_LOG(WII_IPC_SSL, "%s", Memory::GetString(BufferOut2).c_str()); - break; - } - case IOCTLV_NET_SSL_READ: - { + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_READ(%d)" + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " + "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", + ret, _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, _BufferIn3, BufferInSize3, + BufferOut, BufferOutSize, BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); + break; + } + case IOCTLV_NET_SSL_SETROOTCADEFAULT: + { + int sslID = Memory::Read_U32(BufferOut) - 1; + if (SSLID_VALID(sslID)) + { + Memory::Write_U32(SSL_OK, _BufferIn); + } + else + { + Memory::Write_U32(SSL_ERR_ID, _BufferIn); + } + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETROOTCADEFAULT " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " + "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", + _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, _BufferIn3, BufferInSize3, + BufferOut, BufferOutSize, BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); + break; + } + case IOCTLV_NET_SSL_SETCLIENTCERTDEFAULT: + { + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETCLIENTCERTDEFAULT " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " + "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", + _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, _BufferIn3, BufferInSize3, + BufferOut, BufferOutSize, BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); - int ret = 0; - int sslID = Memory::Read_U32(BufferOut) - 1; - if (SSLID_VALID(sslID)) - { - WiiSockMan &sm = WiiSockMan::GetInstance(); - sm.DoSock(_SSL[sslID].sockfd, _CommandAddress, IOCTLV_NET_SSL_READ); - return GetNoReply(); - } - else - { - Memory::Write_U32(SSL_ERR_ID, _BufferIn); - } + int sslID = Memory::Read_U32(BufferOut) - 1; + if (SSLID_VALID(sslID)) + { + Memory::Write_U32(SSL_OK, _BufferIn); + } + else + { + Memory::Write_U32(SSL_ERR_ID, _BufferIn); + } + break; + } + default: + ERROR_LOG(WII_IPC_SSL, "%i " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " + "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", + CommandBuffer.Parameter, _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, + _BufferIn3, BufferInSize3, BufferOut, BufferOutSize, BufferOut2, BufferOutSize2, + BufferOut3, BufferOutSize3); + break; + } - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_READ(%d)" - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " - "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", - ret, - _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, - _BufferIn3, BufferInSize3, BufferOut, BufferOutSize, - BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); - break; - } - case IOCTLV_NET_SSL_SETROOTCADEFAULT: - { - int sslID = Memory::Read_U32(BufferOut) - 1; - if (SSLID_VALID(sslID)) - { - Memory::Write_U32(SSL_OK, _BufferIn); - } - else - { - Memory::Write_U32(SSL_ERR_ID, _BufferIn); - } - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETROOTCADEFAULT " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " - "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", - _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, - _BufferIn3, BufferInSize3, BufferOut, BufferOutSize, - BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); - break; - } - case IOCTLV_NET_SSL_SETCLIENTCERTDEFAULT: - { - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_SETCLIENTCERTDEFAULT " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " - "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", - _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, - _BufferIn3, BufferInSize3, BufferOut, BufferOutSize, - BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); + // SSL return codes are written to BufferIn + Memory::Write_U32(0, _CommandAddress + 4); - int sslID = Memory::Read_U32(BufferOut) - 1; - if (SSLID_VALID(sslID)) - { - Memory::Write_U32(SSL_OK, _BufferIn); - } - else - { - Memory::Write_U32(SSL_ERR_ID, _BufferIn); - } - break; - } - default: - ERROR_LOG(WII_IPC_SSL, "%i " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferIn3: (%08x, %i), BufferOut: (%08x, %i), " - "BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)", - CommandBuffer.Parameter, - _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, - _BufferIn3, BufferInSize3, BufferOut, BufferOutSize, - BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3); - break; - } - - // SSL return codes are written to BufferIn - Memory::Write_U32(0, _CommandAddress+4); - - return GetDefaultReply(); + return GetDefaultReply(); } - diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.h index 8665435acf..e97c282cda 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_net_ssl.h @@ -4,86 +4,86 @@ #pragma once -#include #include #include #include #include +#include #include "Core/IPC_HLE/WII_IPC_HLE_Device.h" #define NET_SSL_MAXINSTANCES 4 -#define SSLID_VALID(x) (x >= 0 && x < NET_SSL_MAXINSTANCES && CWII_IPC_HLE_Device_net_ssl::_SSL[x].active) +#define SSLID_VALID(x) \ + (x >= 0 && x < NET_SSL_MAXINSTANCES && CWII_IPC_HLE_Device_net_ssl::_SSL[x].active) enum ssl_err_t { - SSL_OK = 0, - SSL_ERR_FAILED = -1, - SSL_ERR_RAGAIN = -2, - SSL_ERR_WAGAIN = -3, - SSL_ERR_SYSCALL = -5, - SSL_ERR_ZERO = -6, // read or write returned 0 - SSL_ERR_CAGAIN = -7, // BIO not connected - SSL_ERR_ID = -8, // invalid SSL id - SSL_ERR_VCOMMONNAME = -9, // verify failed: common name - SSL_ERR_VROOTCA = -10, // verify failed: root ca - SSL_ERR_VCHAIN = -11, // verify failed: certificate chain - SSL_ERR_VDATE = -12, // verify failed: date invalid - SSL_ERR_SERVER_CERT = -13, // certificate cert invalid + SSL_OK = 0, + SSL_ERR_FAILED = -1, + SSL_ERR_RAGAIN = -2, + SSL_ERR_WAGAIN = -3, + SSL_ERR_SYSCALL = -5, + SSL_ERR_ZERO = -6, // read or write returned 0 + SSL_ERR_CAGAIN = -7, // BIO not connected + SSL_ERR_ID = -8, // invalid SSL id + SSL_ERR_VCOMMONNAME = -9, // verify failed: common name + SSL_ERR_VROOTCA = -10, // verify failed: root ca + SSL_ERR_VCHAIN = -11, // verify failed: certificate chain + SSL_ERR_VDATE = -12, // verify failed: date invalid + SSL_ERR_SERVER_CERT = -13, // certificate cert invalid }; enum SSL_IOCTL { - IOCTLV_NET_SSL_NEW = 0x01, - IOCTLV_NET_SSL_CONNECT = 0x02, - IOCTLV_NET_SSL_DOHANDSHAKE = 0x03, - IOCTLV_NET_SSL_READ = 0x04, - IOCTLV_NET_SSL_WRITE = 0x05, - IOCTLV_NET_SSL_SHUTDOWN = 0x06, - IOCTLV_NET_SSL_SETCLIENTCERT = 0x07, - IOCTLV_NET_SSL_SETCLIENTCERTDEFAULT = 0x08, - IOCTLV_NET_SSL_REMOVECLIENTCERT = 0x09, - IOCTLV_NET_SSL_SETROOTCA = 0x0A, - IOCTLV_NET_SSL_SETROOTCADEFAULT = 0x0B, - IOCTLV_NET_SSL_DOHANDSHAKEEX = 0x0C, - IOCTLV_NET_SSL_SETBUILTINROOTCA = 0x0D, - IOCTLV_NET_SSL_SETBUILTINCLIENTCERT = 0x0E, - IOCTLV_NET_SSL_DISABLEVERIFYOPTIONFORDEBUG = 0x0F, - IOCTLV_NET_SSL_DEBUGGETVERSION = 0x14, - IOCTLV_NET_SSL_DEBUGGETTIME = 0x15, + IOCTLV_NET_SSL_NEW = 0x01, + IOCTLV_NET_SSL_CONNECT = 0x02, + IOCTLV_NET_SSL_DOHANDSHAKE = 0x03, + IOCTLV_NET_SSL_READ = 0x04, + IOCTLV_NET_SSL_WRITE = 0x05, + IOCTLV_NET_SSL_SHUTDOWN = 0x06, + IOCTLV_NET_SSL_SETCLIENTCERT = 0x07, + IOCTLV_NET_SSL_SETCLIENTCERTDEFAULT = 0x08, + IOCTLV_NET_SSL_REMOVECLIENTCERT = 0x09, + IOCTLV_NET_SSL_SETROOTCA = 0x0A, + IOCTLV_NET_SSL_SETROOTCADEFAULT = 0x0B, + IOCTLV_NET_SSL_DOHANDSHAKEEX = 0x0C, + IOCTLV_NET_SSL_SETBUILTINROOTCA = 0x0D, + IOCTLV_NET_SSL_SETBUILTINCLIENTCERT = 0x0E, + IOCTLV_NET_SSL_DISABLEVERIFYOPTIONFORDEBUG = 0x0F, + IOCTLV_NET_SSL_DEBUGGETVERSION = 0x14, + IOCTLV_NET_SSL_DEBUGGETTIME = 0x15, }; struct WII_SSL { - mbedtls_ssl_context ctx; - mbedtls_ssl_config config; - mbedtls_ssl_session session; - mbedtls_entropy_context entropy; - mbedtls_ctr_drbg_context ctr_drbg; - mbedtls_x509_crt cacert; - mbedtls_x509_crt clicert; - mbedtls_pk_context pk; - int sockfd; - std::string hostname; - bool active; + mbedtls_ssl_context ctx; + mbedtls_ssl_config config; + mbedtls_ssl_session session; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_x509_crt cacert; + mbedtls_x509_crt clicert; + mbedtls_pk_context pk; + int sockfd; + std::string hostname; + bool active; }; class CWII_IPC_HLE_Device_net_ssl : public IWII_IPC_HLE_Device { public: + CWII_IPC_HLE_Device_net_ssl(u32 _DeviceID, const std::string& _rDeviceName); - CWII_IPC_HLE_Device_net_ssl(u32 _DeviceID, const std::string& _rDeviceName); + virtual ~CWII_IPC_HLE_Device_net_ssl(); - virtual ~CWII_IPC_HLE_Device_net_ssl(); + IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; + IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; - IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; - IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; + IPCCommandResult IOCtl(u32 _CommandAddress) override; + IPCCommandResult IOCtlV(u32 _CommandAddress) override; - IPCCommandResult IOCtl(u32 _CommandAddress) override; - IPCCommandResult IOCtlV(u32 _CommandAddress) override; + int GetSSLFreeID() const; - int GetSSLFreeID() const; - - static WII_SSL _SSL[NET_SSL_MAXINSTANCES]; + static WII_SSL _SSL[NET_SSL_MAXINSTANCES]; }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp index 8ddb161e6c..734f95e324 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp @@ -16,447 +16,446 @@ void CWII_IPC_HLE_Device_sdio_slot0::EnqueueReply(u32 CommandAddress, u32 ReturnValue) { - // IOS seems to write back the command that was responded to, this class does not - // overwrite the command so it is safe to read. - Memory::Write_U32(Memory::Read_U32(CommandAddress), CommandAddress + 8); - // The original hardware overwrites the command type with the async reply type. - Memory::Write_U32(IPC_REP_ASYNC, CommandAddress); + // IOS seems to write back the command that was responded to, this class does not + // overwrite the command so it is safe to read. + Memory::Write_U32(Memory::Read_U32(CommandAddress), CommandAddress + 8); + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, CommandAddress); - Memory::Write_U32(ReturnValue, CommandAddress + 4); + Memory::Write_U32(ReturnValue, CommandAddress + 4); - WII_IPC_HLE_Interface::EnqueueReply(CommandAddress); + WII_IPC_HLE_Interface::EnqueueReply(CommandAddress); } -CWII_IPC_HLE_Device_sdio_slot0::CWII_IPC_HLE_Device_sdio_slot0(u32 _DeviceID, const std::string& _rDeviceName) - : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) - , m_Status(CARD_NOT_EXIST) - , m_BlockLength(0) - , m_BusWidth(0) - , m_Card(nullptr) -{} +CWII_IPC_HLE_Device_sdio_slot0::CWII_IPC_HLE_Device_sdio_slot0(u32 _DeviceID, + const std::string& _rDeviceName) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName), m_Status(CARD_NOT_EXIST), m_BlockLength(0), + m_BusWidth(0), m_Card(nullptr) +{ +} void CWII_IPC_HLE_Device_sdio_slot0::DoState(PointerWrap& p) { - DoStateShared(p); - if (p.GetMode() == PointerWrap::MODE_READ) - { - OpenInternal(); - } - p.Do(m_Status); - p.Do(m_BlockLength); - p.Do(m_BusWidth); - p.Do(m_Registers); + DoStateShared(p); + if (p.GetMode() == PointerWrap::MODE_READ) + { + OpenInternal(); + } + p.Do(m_Status); + p.Do(m_BlockLength); + p.Do(m_BusWidth); + p.Do(m_Registers); } void CWII_IPC_HLE_Device_sdio_slot0::EventNotify() { - if ((SConfig::GetInstance().m_WiiSDCard && m_event.type == EVENT_INSERT) || - (!SConfig::GetInstance().m_WiiSDCard && m_event.type == EVENT_REMOVE)) - { - EnqueueReply(m_event.addr, m_event.type); - m_event.addr = 0; - m_event.type = EVENT_NONE; - } + if ((SConfig::GetInstance().m_WiiSDCard && m_event.type == EVENT_INSERT) || + (!SConfig::GetInstance().m_WiiSDCard && m_event.type == EVENT_REMOVE)) + { + EnqueueReply(m_event.addr, m_event.type); + m_event.addr = 0; + m_event.type = EVENT_NONE; + } } void CWII_IPC_HLE_Device_sdio_slot0::OpenInternal() { - const std::string filename = File::GetUserPath(D_WIIROOT_IDX) + "/sd.raw"; - m_Card.Open(filename, "r+b"); - if (!m_Card) - { - WARN_LOG(WII_IPC_SD, "Failed to open SD Card image, trying to create a new 128MB image..."); - if (SDCardCreate(128, filename)) - { - WARN_LOG(WII_IPC_SD, "Successfully created %s", filename.c_str()); - m_Card.Open(filename, "r+b"); - } - if (!m_Card) - { - ERROR_LOG(WII_IPC_SD, "Could not open SD Card image or create a new one, are you running from a read-only directory?"); - } - } + const std::string filename = File::GetUserPath(D_WIIROOT_IDX) + "/sd.raw"; + m_Card.Open(filename, "r+b"); + if (!m_Card) + { + WARN_LOG(WII_IPC_SD, "Failed to open SD Card image, trying to create a new 128MB image..."); + if (SDCardCreate(128, filename)) + { + WARN_LOG(WII_IPC_SD, "Successfully created %s", filename.c_str()); + m_Card.Open(filename, "r+b"); + } + if (!m_Card) + { + ERROR_LOG(WII_IPC_SD, "Could not open SD Card image or create a new one, are you running " + "from a read-only directory?"); + } + } } IPCCommandResult CWII_IPC_HLE_Device_sdio_slot0::Open(u32 _CommandAddress, u32 _Mode) { - INFO_LOG(WII_IPC_SD, "Open"); + INFO_LOG(WII_IPC_SD, "Open"); - OpenInternal(); + OpenInternal(); - Memory::Write_U32(GetDeviceID(), _CommandAddress + 0x4); - memset(m_Registers, 0, sizeof(m_Registers)); - m_Active = true; - return GetDefaultReply(); + Memory::Write_U32(GetDeviceID(), _CommandAddress + 0x4); + memset(m_Registers, 0, sizeof(m_Registers)); + m_Active = true; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_sdio_slot0::Close(u32 _CommandAddress, bool _bForce) { - INFO_LOG(WII_IPC_SD, "Close"); + INFO_LOG(WII_IPC_SD, "Close"); - m_Card.Close(); - m_BlockLength = 0; - m_BusWidth = 0; + m_Card.Close(); + m_BlockLength = 0; + m_BusWidth = 0; - if (!_bForce) - Memory::Write_U32(0, _CommandAddress + 0x4); - m_Active = false; - return GetDefaultReply(); + if (!_bForce) + Memory::Write_U32(0, _CommandAddress + 0x4); + m_Active = false; + return GetDefaultReply(); } // The front SD slot IPCCommandResult CWII_IPC_HLE_Device_sdio_slot0::IOCtl(u32 _CommandAddress) { - u32 Cmd = Memory::Read_U32(_CommandAddress + 0xC); + u32 Cmd = Memory::Read_U32(_CommandAddress + 0xC); - u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); - u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); - u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); + u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); + u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); + u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); + u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); - // As a safety precaution we fill the out buffer with zeros to avoid - // returning nonsense values - Memory::Memset(BufferOut, 0, BufferOutSize); + // As a safety precaution we fill the out buffer with zeros to avoid + // returning nonsense values + Memory::Memset(BufferOut, 0, BufferOutSize); - u32 ReturnValue = 0; - switch (Cmd) - { - case IOCTL_WRITEHCR: - { - u32 reg = Memory::Read_U32(BufferIn); - u32 val = Memory::Read_U32(BufferIn + 16); + u32 ReturnValue = 0; + switch (Cmd) + { + case IOCTL_WRITEHCR: + { + u32 reg = Memory::Read_U32(BufferIn); + u32 val = Memory::Read_U32(BufferIn + 16); - DEBUG_LOG(WII_IPC_SD, "IOCTL_WRITEHCR 0x%08x - 0x%08x", reg, val); + DEBUG_LOG(WII_IPC_SD, "IOCTL_WRITEHCR 0x%08x - 0x%08x", reg, val); - if (reg >= 0x200) - { - DEBUG_LOG(WII_IPC_SD, "IOCTL_WRITEHCR out of range"); - break; - } + if (reg >= 0x200) + { + DEBUG_LOG(WII_IPC_SD, "IOCTL_WRITEHCR out of range"); + break; + } - if ((reg == HCR_CLOCKCONTROL) && (val & 1)) - { - // Clock is set to oscillate, enable bit 1 to say it's stable - m_Registers[reg] = val | 2; - } - else if ((reg == HCR_SOFTWARERESET) && val) - { - // When a reset is specified, the register gets cleared - m_Registers[reg] = 0; - } - else - { - // Default to just storing the new value - m_Registers[reg] = val; - } - } - break; + if ((reg == HCR_CLOCKCONTROL) && (val & 1)) + { + // Clock is set to oscillate, enable bit 1 to say it's stable + m_Registers[reg] = val | 2; + } + else if ((reg == HCR_SOFTWARERESET) && val) + { + // When a reset is specified, the register gets cleared + m_Registers[reg] = 0; + } + else + { + // Default to just storing the new value + m_Registers[reg] = val; + } + } + break; - case IOCTL_READHCR: - { - u32 reg = Memory::Read_U32(BufferIn); + case IOCTL_READHCR: + { + u32 reg = Memory::Read_U32(BufferIn); - if (reg >= 0x200) - { - DEBUG_LOG(WII_IPC_SD, "IOCTL_READHCR out of range"); - break; - } + if (reg >= 0x200) + { + DEBUG_LOG(WII_IPC_SD, "IOCTL_READHCR out of range"); + break; + } - u32 val = m_Registers[reg]; - DEBUG_LOG(WII_IPC_SD, "IOCTL_READHCR 0x%08x - 0x%08x", reg, val); + u32 val = m_Registers[reg]; + DEBUG_LOG(WII_IPC_SD, "IOCTL_READHCR 0x%08x - 0x%08x", reg, val); - // Just reading the register - Memory::Write_U32(val, BufferOut); - } - break; + // Just reading the register + Memory::Write_U32(val, BufferOut); + } + break; - case IOCTL_RESETCARD: - DEBUG_LOG(WII_IPC_SD, "IOCTL_RESETCARD"); - if (m_Card) - m_Status |= CARD_INITIALIZED; - // Returns 16bit RCA and 16bit 0s (meaning success) - Memory::Write_U32(0x9f620000, BufferOut); - break; + case IOCTL_RESETCARD: + DEBUG_LOG(WII_IPC_SD, "IOCTL_RESETCARD"); + if (m_Card) + m_Status |= CARD_INITIALIZED; + // Returns 16bit RCA and 16bit 0s (meaning success) + Memory::Write_U32(0x9f620000, BufferOut); + break; - case IOCTL_SETCLK: - { - DEBUG_LOG(WII_IPC_SD, "IOCTL_SETCLK"); - // libogc only sets it to 1 and makes sure the return isn't negative... - // one half of the sdclk divisor: a power of two or zero. - u32 clock = Memory::Read_U32(BufferIn); - if (clock != 1) - INFO_LOG(WII_IPC_SD, "Setting to %i, interesting", clock); - } - break; + case IOCTL_SETCLK: + { + DEBUG_LOG(WII_IPC_SD, "IOCTL_SETCLK"); + // libogc only sets it to 1 and makes sure the return isn't negative... + // one half of the sdclk divisor: a power of two or zero. + u32 clock = Memory::Read_U32(BufferIn); + if (clock != 1) + INFO_LOG(WII_IPC_SD, "Setting to %i, interesting", clock); + } + break; - case IOCTL_SENDCMD: - INFO_LOG(WII_IPC_SD, "IOCTL_SENDCMD %x IPC:%08x", - Memory::Read_U32(BufferIn), _CommandAddress); - ReturnValue = ExecuteCommand(BufferIn, BufferInSize, 0, 0, BufferOut, BufferOutSize); - break; + case IOCTL_SENDCMD: + INFO_LOG(WII_IPC_SD, "IOCTL_SENDCMD %x IPC:%08x", Memory::Read_U32(BufferIn), _CommandAddress); + ReturnValue = ExecuteCommand(BufferIn, BufferInSize, 0, 0, BufferOut, BufferOutSize); + break; - case IOCTL_GETSTATUS: - if (SConfig::GetInstance().m_WiiSDCard) - m_Status |= CARD_INSERTED; - else - m_Status = CARD_NOT_EXIST; - INFO_LOG(WII_IPC_SD, "IOCTL_GETSTATUS. Replying that SD card is %s%s", - (m_Status & CARD_INSERTED) ? "inserted" : "not present", - (m_Status & CARD_INITIALIZED) ? " and initialized" : ""); - Memory::Write_U32(m_Status, BufferOut); - break; + case IOCTL_GETSTATUS: + if (SConfig::GetInstance().m_WiiSDCard) + m_Status |= CARD_INSERTED; + else + m_Status = CARD_NOT_EXIST; + INFO_LOG(WII_IPC_SD, "IOCTL_GETSTATUS. Replying that SD card is %s%s", + (m_Status & CARD_INSERTED) ? "inserted" : "not present", + (m_Status & CARD_INITIALIZED) ? " and initialized" : ""); + Memory::Write_U32(m_Status, BufferOut); + break; - case IOCTL_GETOCR: - DEBUG_LOG(WII_IPC_SD, "IOCTL_GETOCR"); - Memory::Write_U32(0x80ff8000, BufferOut); - break; + case IOCTL_GETOCR: + DEBUG_LOG(WII_IPC_SD, "IOCTL_GETOCR"); + Memory::Write_U32(0x80ff8000, BufferOut); + break; - default: - ERROR_LOG(WII_IPC_SD, "Unknown SD IOCtl command (0x%08x)", Cmd); - break; - } + default: + ERROR_LOG(WII_IPC_SD, "Unknown SD IOCtl command (0x%08x)", Cmd); + break; + } - // INFO_LOG(WII_IPC_SD, "InBuffer"); - // DumpCommands(BufferIn, BufferInSize / 4, LogTypes::WII_IPC_SD); - // INFO_LOG(WII_IPC_SD, "OutBuffer"); - // DumpCommands(BufferOut, BufferOutSize/4, LogTypes::WII_IPC_SD); + // INFO_LOG(WII_IPC_SD, "InBuffer"); + // DumpCommands(BufferIn, BufferInSize / 4, LogTypes::WII_IPC_SD); + // INFO_LOG(WII_IPC_SD, "OutBuffer"); + // DumpCommands(BufferOut, BufferOutSize/4, LogTypes::WII_IPC_SD); - if (ReturnValue == RET_EVENT_REGISTER) - { - // async - m_event.addr = _CommandAddress; - Memory::Write_U32(0, _CommandAddress + 0x4); - // Check if the condition is already true - EventNotify(); - return GetNoReply(); - } - else if (ReturnValue == RET_EVENT_UNREGISTER) - { - // release returns 0 - // unknown sd int - // technically we do it out of order, oh well - EnqueueReply(m_event.addr, EVENT_INVALID); - m_event.addr = 0; - m_event.type = EVENT_NONE; - Memory::Write_U32(0, _CommandAddress + 0x4); - return GetDefaultReply(); - } - else - { - Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); - return GetDefaultReply(); - } + if (ReturnValue == RET_EVENT_REGISTER) + { + // async + m_event.addr = _CommandAddress; + Memory::Write_U32(0, _CommandAddress + 0x4); + // Check if the condition is already true + EventNotify(); + return GetNoReply(); + } + else if (ReturnValue == RET_EVENT_UNREGISTER) + { + // release returns 0 + // unknown sd int + // technically we do it out of order, oh well + EnqueueReply(m_event.addr, EVENT_INVALID); + m_event.addr = 0; + m_event.type = EVENT_NONE; + Memory::Write_U32(0, _CommandAddress + 0x4); + return GetDefaultReply(); + } + else + { + Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); + return GetDefaultReply(); + } } IPCCommandResult CWII_IPC_HLE_Device_sdio_slot0::IOCtlV(u32 _CommandAddress) { - // PPC sending commands + // PPC sending commands - SIOCtlVBuffer CommandBuffer(_CommandAddress); + SIOCtlVBuffer CommandBuffer(_CommandAddress); - // Prepare the out buffer(s) with zeros as a safety precaution - // to avoid returning bad values - for (u32 i = 0; i < CommandBuffer.NumberPayloadBuffer; i++) - { - Memory::Memset(CommandBuffer.PayloadBuffer[i].m_Address, 0, - CommandBuffer.PayloadBuffer[i].m_Size); - } + // Prepare the out buffer(s) with zeros as a safety precaution + // to avoid returning bad values + for (u32 i = 0; i < CommandBuffer.NumberPayloadBuffer; i++) + { + Memory::Memset(CommandBuffer.PayloadBuffer[i].m_Address, 0, + CommandBuffer.PayloadBuffer[i].m_Size); + } - u32 ReturnValue = 0; - switch (CommandBuffer.Parameter) - { - case IOCTLV_SENDCMD: - INFO_LOG(WII_IPC_SD, "IOCTLV_SENDCMD 0x%08x", Memory::Read_U32(CommandBuffer.InBuffer[0].m_Address)); - ReturnValue = ExecuteCommand( - CommandBuffer.InBuffer[0].m_Address, CommandBuffer.InBuffer[0].m_Size, - CommandBuffer.InBuffer[1].m_Address, CommandBuffer.InBuffer[1].m_Size, - CommandBuffer.PayloadBuffer[0].m_Address, CommandBuffer.PayloadBuffer[0].m_Size); - break; + u32 ReturnValue = 0; + switch (CommandBuffer.Parameter) + { + case IOCTLV_SENDCMD: + INFO_LOG(WII_IPC_SD, "IOCTLV_SENDCMD 0x%08x", + Memory::Read_U32(CommandBuffer.InBuffer[0].m_Address)); + ReturnValue = ExecuteCommand( + CommandBuffer.InBuffer[0].m_Address, CommandBuffer.InBuffer[0].m_Size, + CommandBuffer.InBuffer[1].m_Address, CommandBuffer.InBuffer[1].m_Size, + CommandBuffer.PayloadBuffer[0].m_Address, CommandBuffer.PayloadBuffer[0].m_Size); + break; - default: - ERROR_LOG(WII_IPC_SD, "Unknown SD IOCtlV command 0x%08x", CommandBuffer.Parameter); - break; - } + default: + ERROR_LOG(WII_IPC_SD, "Unknown SD IOCtlV command 0x%08x", CommandBuffer.Parameter); + break; + } - //DumpAsync(CommandBuffer.BufferVector, CommandBuffer.NumberInBuffer, CommandBuffer.NumberPayloadBuffer, LogTypes::WII_IPC_SD); + // DumpAsync(CommandBuffer.BufferVector, CommandBuffer.NumberInBuffer, + // CommandBuffer.NumberPayloadBuffer, LogTypes::WII_IPC_SD); - Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); + Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); - return GetDefaultReply(); + return GetDefaultReply(); } -u32 CWII_IPC_HLE_Device_sdio_slot0::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, - u32 _rwBuffer, u32 _rwBufferSize, - u32 _BufferOut, u32 _BufferOutSize) +u32 CWII_IPC_HLE_Device_sdio_slot0::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32 _rwBuffer, + u32 _rwBufferSize, u32 _BufferOut, + u32 _BufferOutSize) { - // The game will send us a SendCMD with this information. To be able to read and write - // to a file we need to prepare a 0x10 byte output buffer as response. - struct Request - { - u32 command; - u32 type; - u32 resp; - u32 arg; - u32 blocks; - u32 bsize; - u32 addr; - u32 isDMA; - u32 pad0; - } req; + // The game will send us a SendCMD with this information. To be able to read and write + // to a file we need to prepare a 0x10 byte output buffer as response. + struct Request + { + u32 command; + u32 type; + u32 resp; + u32 arg; + u32 blocks; + u32 bsize; + u32 addr; + u32 isDMA; + u32 pad0; + } req; - req.command = Memory::Read_U32(_BufferIn + 0); - req.type = Memory::Read_U32(_BufferIn + 4); - req.resp = Memory::Read_U32(_BufferIn + 8); - req.arg = Memory::Read_U32(_BufferIn + 12); - req.blocks = Memory::Read_U32(_BufferIn + 16); - req.bsize = Memory::Read_U32(_BufferIn + 20); - req.addr = Memory::Read_U32(_BufferIn + 24); - req.isDMA = Memory::Read_U32(_BufferIn + 28); - req.pad0 = Memory::Read_U32(_BufferIn + 32); + req.command = Memory::Read_U32(_BufferIn + 0); + req.type = Memory::Read_U32(_BufferIn + 4); + req.resp = Memory::Read_U32(_BufferIn + 8); + req.arg = Memory::Read_U32(_BufferIn + 12); + req.blocks = Memory::Read_U32(_BufferIn + 16); + req.bsize = Memory::Read_U32(_BufferIn + 20); + req.addr = Memory::Read_U32(_BufferIn + 24); + req.isDMA = Memory::Read_U32(_BufferIn + 28); + req.pad0 = Memory::Read_U32(_BufferIn + 32); - // Note: req.addr is the virtual address of _rwBuffer + // Note: req.addr is the virtual address of _rwBuffer + u32 ret = RET_OK; - u32 ret = RET_OK; + switch (req.command) + { + case GO_IDLE_STATE: + // libogc can use it during init.. + break; - switch (req.command) - { - case GO_IDLE_STATE: - // libogc can use it during init.. - break; + case SEND_RELATIVE_ADDR: + // Technically RCA should be generated when asked and at power on...w/e :p + Memory::Write_U32(0x9f62, _BufferOut); + break; - case SEND_RELATIVE_ADDR: - // Technically RCA should be generated when asked and at power on...w/e :p - Memory::Write_U32(0x9f62, _BufferOut); - break; + case SELECT_CARD: + // This covers both select and deselect + // Differentiate by checking if rca is set in req.arg + // If it is, it's a select and return 0x700 + Memory::Write_U32((req.arg >> 16) ? 0x700 : 0x900, _BufferOut); + break; - case SELECT_CARD: - // This covers both select and deselect - // Differentiate by checking if rca is set in req.arg - // If it is, it's a select and return 0x700 - Memory::Write_U32((req.arg>>16) ? 0x700 : 0x900, _BufferOut); - break; + case SEND_IF_COND: + // If the card can operate on the supplied voltage, the response echoes back the supply + // voltage and the check pattern that were set in the command argument. + Memory::Write_U32(req.arg, _BufferOut); + break; - case SEND_IF_COND: - // If the card can operate on the supplied voltage, the response echoes back the supply - // voltage and the check pattern that were set in the command argument. - Memory::Write_U32(req.arg, _BufferOut); - break; + case SEND_CSD: + DEBUG_LOG(WII_IPC_SD, "SEND_CSD"); + // shuffle2_, OCR: 0x80ff8000 CID: 0x38a00000 0x480032d5 0x3c608030 0x8803d420 + // CSD: 0xff928040 0xc93efbcf 0x325f5a83 0x00002600 - case SEND_CSD: - DEBUG_LOG(WII_IPC_SD, "SEND_CSD"); - // shuffle2_, OCR: 0x80ff8000 CID: 0x38a00000 0x480032d5 0x3c608030 0x8803d420 - // CSD: 0xff928040 0xc93efbcf 0x325f5a83 0x00002600 + // Values used currently are from lpfaint99 + Memory::Write_U32(0x80168000, _BufferOut); + Memory::Write_U32(0xa9ffffff, _BufferOut + 4); + Memory::Write_U32(0x325b5a83, _BufferOut + 8); + Memory::Write_U32(0x00002e00, _BufferOut + 12); + break; - // Values used currently are from lpfaint99 - Memory::Write_U32(0x80168000, _BufferOut); - Memory::Write_U32(0xa9ffffff, _BufferOut + 4); - Memory::Write_U32(0x325b5a83, _BufferOut + 8); - Memory::Write_U32(0x00002e00, _BufferOut + 12); - break; + case ALL_SEND_CID: + case SEND_CID: + DEBUG_LOG(WII_IPC_SD, "(ALL_)SEND_CID"); + Memory::Write_U32(0x80114d1c, _BufferOut); + Memory::Write_U32(0x80080000, _BufferOut + 4); + Memory::Write_U32(0x8007b520, _BufferOut + 8); + Memory::Write_U32(0x80080000, _BufferOut + 12); + break; - case ALL_SEND_CID: - case SEND_CID: - DEBUG_LOG(WII_IPC_SD, "(ALL_)SEND_CID"); - Memory::Write_U32(0x80114d1c, _BufferOut); - Memory::Write_U32(0x80080000, _BufferOut + 4); - Memory::Write_U32(0x8007b520, _BufferOut + 8); - Memory::Write_U32(0x80080000, _BufferOut + 12); - break; + case SET_BLOCKLEN: + m_BlockLength = req.arg; + Memory::Write_U32(0x900, _BufferOut); + break; - case SET_BLOCKLEN: - m_BlockLength = req.arg; - Memory::Write_U32(0x900, _BufferOut); - break; + case APP_CMD_NEXT: + // Next cmd is going to be ACMD_* + Memory::Write_U32(0x920, _BufferOut); + break; - case APP_CMD_NEXT: - // Next cmd is going to be ACMD_* - Memory::Write_U32(0x920, _BufferOut); - break; + case ACMD_SETBUSWIDTH: + // 0 = 1bit, 2 = 4bit + m_BusWidth = (req.arg & 3); + Memory::Write_U32(0x920, _BufferOut); + break; - case ACMD_SETBUSWIDTH: - // 0 = 1bit, 2 = 4bit - m_BusWidth = (req.arg & 3); - Memory::Write_U32(0x920, _BufferOut); - break; + case ACMD_SENDOPCOND: + // Sends host capacity support information (HCS) and asks the accessed card to send + // its operating condition register (OCR) content + Memory::Write_U32(0x80ff8000, _BufferOut); + break; - case ACMD_SENDOPCOND: - // Sends host capacity support information (HCS) and asks the accessed card to send - // its operating condition register (OCR) content - Memory::Write_U32(0x80ff8000, _BufferOut); - break; + case READ_MULTIPLE_BLOCK: + { + // Data address (req.arg) is in byte units in a Standard Capacity SD Memory Card + // and in block (512 Byte) units in a High Capacity SD Memory Card. + DEBUG_LOG(WII_IPC_SD, "%sRead %i Block(s) from 0x%08x bsize %i into 0x%08x!", + req.isDMA ? "DMA " : "", req.blocks, req.arg, req.bsize, req.addr); - case READ_MULTIPLE_BLOCK: - { - // Data address (req.arg) is in byte units in a Standard Capacity SD Memory Card - // and in block (512 Byte) units in a High Capacity SD Memory Card. - DEBUG_LOG(WII_IPC_SD, "%sRead %i Block(s) from 0x%08x bsize %i into 0x%08x!", - req.isDMA ? "DMA " : "", req.blocks, req.arg, req.bsize, req.addr); + if (m_Card) + { + u32 size = req.bsize * req.blocks; - if (m_Card) - { - u32 size = req.bsize * req.blocks; + if (!m_Card.Seek(req.arg, SEEK_SET)) + ERROR_LOG(WII_IPC_SD, "Seek failed WTF"); - if (!m_Card.Seek(req.arg, SEEK_SET)) - ERROR_LOG(WII_IPC_SD, "Seek failed WTF"); + if (m_Card.ReadBytes(Memory::GetPointer(req.addr), size)) + { + DEBUG_LOG(WII_IPC_SD, "Outbuffer size %i got %i", _rwBufferSize, size); + } + else + { + ERROR_LOG(WII_IPC_SD, "Read Failed - error: %i, eof: %i", ferror(m_Card.GetHandle()), + feof(m_Card.GetHandle())); + ret = RET_FAIL; + } + } + } + Memory::Write_U32(0x900, _BufferOut); + break; + case WRITE_MULTIPLE_BLOCK: + { + // Data address (req.arg) is in byte units in a Standard Capacity SD Memory Card + // and in block (512 Byte) units in a High Capacity SD Memory Card. + DEBUG_LOG(WII_IPC_SD, "%sWrite %i Block(s) from 0x%08x bsize %i to offset 0x%08x!", + req.isDMA ? "DMA " : "", req.blocks, req.addr, req.bsize, req.arg); - if (m_Card.ReadBytes(Memory::GetPointer(req.addr), size)) - { - DEBUG_LOG(WII_IPC_SD, "Outbuffer size %i got %i", _rwBufferSize, size); - } - else - { - ERROR_LOG(WII_IPC_SD, "Read Failed - error: %i, eof: %i", - ferror(m_Card.GetHandle()), feof(m_Card.GetHandle())); - ret = RET_FAIL; - } - } - } - Memory::Write_U32(0x900, _BufferOut); - break; + if (m_Card && SConfig::GetInstance().bEnableMemcardSdWriting) + { + u32 size = req.bsize * req.blocks; - case WRITE_MULTIPLE_BLOCK: - { - // Data address (req.arg) is in byte units in a Standard Capacity SD Memory Card - // and in block (512 Byte) units in a High Capacity SD Memory Card. - DEBUG_LOG(WII_IPC_SD, "%sWrite %i Block(s) from 0x%08x bsize %i to offset 0x%08x!", - req.isDMA ? "DMA " : "", req.blocks, req.addr, req.bsize, req.arg); + if (!m_Card.Seek(req.arg, SEEK_SET)) + ERROR_LOG(WII_IPC_SD, "fseeko failed WTF"); - if (m_Card && SConfig::GetInstance().bEnableMemcardSdWriting) - { - u32 size = req.bsize * req.blocks; + if (!m_Card.WriteBytes(Memory::GetPointer(req.addr), size)) + { + ERROR_LOG(WII_IPC_SD, "Write Failed - error: %i, eof: %i", ferror(m_Card.GetHandle()), + feof(m_Card.GetHandle())); + ret = RET_FAIL; + } + } + } + Memory::Write_U32(0x900, _BufferOut); + break; - if (!m_Card.Seek(req.arg, SEEK_SET)) - ERROR_LOG(WII_IPC_SD, "fseeko failed WTF"); + case EVENT_REGISTER: // async + DEBUG_LOG(WII_IPC_SD, "Register event %x", req.arg); + m_event.type = (EventType)req.arg; + ret = RET_EVENT_REGISTER; + break; - if (!m_Card.WriteBytes(Memory::GetPointer(req.addr), size)) - { - ERROR_LOG(WII_IPC_SD, "Write Failed - error: %i, eof: %i", - ferror(m_Card.GetHandle()), feof(m_Card.GetHandle())); - ret = RET_FAIL; - } - } - } - Memory::Write_U32(0x900, _BufferOut); - break; + case EVENT_UNREGISTER: // synchronous + DEBUG_LOG(WII_IPC_SD, "Unregister event %x", req.arg); + m_event.type = (EventType)req.arg; + ret = RET_EVENT_UNREGISTER; + break; - case EVENT_REGISTER: // async - DEBUG_LOG(WII_IPC_SD, "Register event %x", req.arg); - m_event.type = (EventType)req.arg; - ret = RET_EVENT_REGISTER; - break; + default: + ERROR_LOG(WII_IPC_SD, "Unknown SD command 0x%08x", req.command); + break; + } - case EVENT_UNREGISTER: // synchronous - DEBUG_LOG(WII_IPC_SD, "Unregister event %x", req.arg); - m_event.type = (EventType)req.arg; - ret = RET_EVENT_UNREGISTER; - break; - - default: - ERROR_LOG(WII_IPC_SD, "Unknown SD command 0x%08x", req.command); - break; - } - - return ret; + return ret; } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.h index 93af6785be..9cf96ca8ce 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.h @@ -10,123 +10,120 @@ #include "Core/IPC_HLE/WII_IPC_HLE_Device.h" class PointerWrap; -namespace File { class IOFile; } +namespace File +{ +class IOFile; +} class CWII_IPC_HLE_Device_sdio_slot0 : public IWII_IPC_HLE_Device { public: + CWII_IPC_HLE_Device_sdio_slot0(u32 _DeviceID, const std::string& _rDeviceName); - CWII_IPC_HLE_Device_sdio_slot0(u32 _DeviceID, const std::string& _rDeviceName); + void DoState(PointerWrap& p) override; - void DoState(PointerWrap& p) override; + IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; + IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; - IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; - IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; + IPCCommandResult IOCtl(u32 _CommandAddress) override; + IPCCommandResult IOCtlV(u32 _CommandAddress) override; - IPCCommandResult IOCtl(u32 _CommandAddress) override; - IPCCommandResult IOCtlV(u32 _CommandAddress) override; - - static void EnqueueReply(u32 CommandAddress, u32 ReturnValue); - void EventNotify(); + static void EnqueueReply(u32 CommandAddress, u32 ReturnValue); + void EventNotify(); private: + // SD Host Controller Registers + enum + { + HCR_CLOCKCONTROL = 0x2C, + HCR_SOFTWARERESET = 0x2F, + }; - // SD Host Controller Registers - enum - { - HCR_CLOCKCONTROL = 0x2C, - HCR_SOFTWARERESET = 0x2F, - }; + // IOCtl + enum + { + IOCTL_WRITEHCR = 0x01, + IOCTL_READHCR = 0x02, + IOCTL_RESETCARD = 0x04, + IOCTL_SETCLK = 0x06, + IOCTL_SENDCMD = 0x07, + IOCTL_GETSTATUS = 0x0B, + IOCTL_GETOCR = 0x0C, + }; - // IOCtl - enum - { - IOCTL_WRITEHCR = 0x01, - IOCTL_READHCR = 0x02, - IOCTL_RESETCARD = 0x04, - IOCTL_SETCLK = 0x06, - IOCTL_SENDCMD = 0x07, - IOCTL_GETSTATUS = 0x0B, - IOCTL_GETOCR = 0x0C, - }; + // IOCtlV + enum + { + IOCTLV_SENDCMD = 0x07, + }; - // IOCtlV - enum - { - IOCTLV_SENDCMD = 0x07, - }; + // ExecuteCommand + enum + { + RET_OK, + RET_FAIL, + RET_EVENT_REGISTER, // internal state only - not actually returned + RET_EVENT_UNREGISTER + }; - // ExecuteCommand - enum - { - RET_OK, - RET_FAIL, - RET_EVENT_REGISTER, // internal state only - not actually returned - RET_EVENT_UNREGISTER - }; + // Status + enum + { + CARD_NOT_EXIST = 0, + CARD_INSERTED = 1, + CARD_INITIALIZED = 0x10000, + }; - // Status - enum - { - CARD_NOT_EXIST = 0, - CARD_INSERTED = 1, - CARD_INITIALIZED = 0x10000, - }; + // Commands + enum + { + GO_IDLE_STATE = 0x00, + ALL_SEND_CID = 0x02, + SEND_RELATIVE_ADDR = 0x03, + SELECT_CARD = 0x07, + SEND_IF_COND = 0x08, + SEND_CSD = 0x09, + SEND_CID = 0x0A, + SEND_STATUS = 0x0D, + SET_BLOCKLEN = 0x10, + READ_MULTIPLE_BLOCK = 0x12, + WRITE_MULTIPLE_BLOCK = 0x19, + APP_CMD_NEXT = 0x37, - // Commands - enum - { - GO_IDLE_STATE = 0x00, - ALL_SEND_CID = 0x02, - SEND_RELATIVE_ADDR = 0x03, - SELECT_CARD = 0x07, - SEND_IF_COND = 0x08, - SEND_CSD = 0x09, - SEND_CID = 0x0A, - SEND_STATUS = 0x0D, - SET_BLOCKLEN = 0x10, - READ_MULTIPLE_BLOCK = 0x12, - WRITE_MULTIPLE_BLOCK = 0x19, - APP_CMD_NEXT = 0x37, + ACMD_SETBUSWIDTH = 0x06, + ACMD_SENDOPCOND = 0x29, + ACMD_SENDSCR = 0x33, - ACMD_SETBUSWIDTH = 0x06, - ACMD_SENDOPCOND = 0x29, - ACMD_SENDSCR = 0x33, + EVENT_REGISTER = 0x40, + EVENT_UNREGISTER = 0x41, + }; - EVENT_REGISTER = 0x40, - EVENT_UNREGISTER = 0x41, - }; + enum EventType + { + EVENT_NONE = 0, + EVENT_INSERT, + EVENT_REMOVE, + // from unregister, i think it is just meant to be invalid + EVENT_INVALID = 0xc210000 + }; - enum EventType - { - EVENT_NONE = 0, - EVENT_INSERT, - EVENT_REMOVE, - // from unregister, i think it is just meant to be invalid - EVENT_INVALID = 0xc210000 - }; + // TODO do we need more than one? + struct Event + { + EventType type; + u32 addr; + Event() : type(EVENT_NONE), addr() {} + } m_event; - // TODO do we need more than one? - struct Event - { - EventType type; - u32 addr; - Event() - : type(EVENT_NONE) - , addr() - {} - } m_event; + u32 m_Status; + u32 m_BlockLength; + u32 m_BusWidth; - u32 m_Status; - u32 m_BlockLength; - u32 m_BusWidth; + u32 m_Registers[0x200 / 4]; - u32 m_Registers[0x200/4]; + File::IOFile m_Card; - File::IOFile m_Card; - - u32 ExecuteCommand(u32 BufferIn, u32 BufferInSize, - u32 BufferIn2, u32 BufferInSize2, - u32 _BufferOut, u32 BufferOutSize); - void OpenInternal(); + u32 ExecuteCommand(u32 BufferIn, u32 BufferInSize, u32 BufferIn2, u32 BufferInSize2, + u32 _BufferOut, u32 BufferOutSize); + void OpenInternal(); }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_stm.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_stm.h index 7104796fb0..1d7982db0b 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_stm.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_stm.h @@ -9,183 +9,176 @@ enum { - IOCTL_STM_EVENTHOOK = 0x1000, - IOCTL_STM_GET_IDLEMODE = 0x3001, - IOCTL_STM_RELEASE_EH = 0x3002, - IOCTL_STM_HOTRESET = 0x2001, - IOCTL_STM_HOTRESET_FOR_PD = 0x2002, - IOCTL_STM_SHUTDOWN = 0x2003, - IOCTL_STM_IDLE = 0x2004, - IOCTL_STM_WAKEUP = 0x2005, - IOCTL_STM_VIDIMMING = 0x5001, - IOCTL_STM_LEDFLASH = 0x6001, - IOCTL_STM_LEDMODE = 0x6002, - IOCTL_STM_READVER = 0x7001, - IOCTL_STM_READDDRREG = 0x4001, - IOCTL_STM_READDDRREG2 = 0x4002, + IOCTL_STM_EVENTHOOK = 0x1000, + IOCTL_STM_GET_IDLEMODE = 0x3001, + IOCTL_STM_RELEASE_EH = 0x3002, + IOCTL_STM_HOTRESET = 0x2001, + IOCTL_STM_HOTRESET_FOR_PD = 0x2002, + IOCTL_STM_SHUTDOWN = 0x2003, + IOCTL_STM_IDLE = 0x2004, + IOCTL_STM_WAKEUP = 0x2005, + IOCTL_STM_VIDIMMING = 0x5001, + IOCTL_STM_LEDFLASH = 0x6001, + IOCTL_STM_LEDMODE = 0x6002, + IOCTL_STM_READVER = 0x7001, + IOCTL_STM_READDDRREG = 0x4001, + IOCTL_STM_READDDRREG2 = 0x4002, }; // The /dev/stm/immediate class CWII_IPC_HLE_Device_stm_immediate : public IWII_IPC_HLE_Device { public: + CWII_IPC_HLE_Device_stm_immediate(u32 _DeviceID, const std::string& _rDeviceName) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) + { + } - CWII_IPC_HLE_Device_stm_immediate(u32 _DeviceID, const std::string& _rDeviceName) : - IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) - {} + virtual ~CWII_IPC_HLE_Device_stm_immediate() {} + IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override + { + INFO_LOG(WII_IPC_STM, "STM immediate: Open"); + Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); + m_Active = true; + return GetDefaultReply(); + } - virtual ~CWII_IPC_HLE_Device_stm_immediate() - {} + IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override + { + INFO_LOG(WII_IPC_STM, "STM immediate: Close"); + if (!_bForce) + Memory::Write_U32(0, _CommandAddress + 4); + m_Active = false; + return GetDefaultReply(); + } - IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override - { - INFO_LOG(WII_IPC_STM, "STM immediate: Open"); - Memory::Write_U32(GetDeviceID(), _CommandAddress+4); - m_Active = true; - return GetDefaultReply(); - } + IPCCommandResult IOCtl(u32 _CommandAddress) override + { + u32 Parameter = Memory::Read_U32(_CommandAddress + 0x0C); + u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); + u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); + u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); + u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); - IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override - { - INFO_LOG(WII_IPC_STM, "STM immediate: Close"); - if (!_bForce) - Memory::Write_U32(0, _CommandAddress+4); - m_Active = false; - return GetDefaultReply(); - } + // Prepare the out buffer(s) with zeroes as a safety precaution + // to avoid returning bad values + Memory::Memset(BufferOut, 0, BufferOutSize); + u32 ReturnValue = 0; - IPCCommandResult IOCtl(u32 _CommandAddress) override - { - u32 Parameter = Memory::Read_U32(_CommandAddress + 0x0C); - u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); - u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); - u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); + switch (Parameter) + { + case IOCTL_STM_RELEASE_EH: + INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str()); + INFO_LOG(WII_IPC_STM, " IOCTL_STM_RELEASE_EH"); + break; - // Prepare the out buffer(s) with zeroes as a safety precaution - // to avoid returning bad values - Memory::Memset(BufferOut, 0, BufferOutSize); - u32 ReturnValue = 0; + case IOCTL_STM_HOTRESET: + INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str()); + INFO_LOG(WII_IPC_STM, " IOCTL_STM_HOTRESET"); + break; - switch (Parameter) - { - case IOCTL_STM_RELEASE_EH: - INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str()); - INFO_LOG(WII_IPC_STM, " IOCTL_STM_RELEASE_EH"); - break; + case IOCTL_STM_VIDIMMING: // (Input: 20 bytes, Output: 20 bytes) + INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str()); + INFO_LOG(WII_IPC_STM, " IOCTL_STM_VIDIMMING"); + // DumpCommands(BufferIn, BufferInSize / 4, LogTypes::WII_IPC_STM); + // Memory::Write_U32(1, BufferOut); + // ReturnValue = 1; + break; - case IOCTL_STM_HOTRESET: - INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str()); - INFO_LOG(WII_IPC_STM, " IOCTL_STM_HOTRESET"); - break; + case IOCTL_STM_LEDMODE: // (Input: 20 bytes, Output: 20 bytes) + INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str()); + INFO_LOG(WII_IPC_STM, " IOCTL_STM_LEDMODE"); + break; - case IOCTL_STM_VIDIMMING: // (Input: 20 bytes, Output: 20 bytes) - INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str()); - INFO_LOG(WII_IPC_STM, " IOCTL_STM_VIDIMMING"); - //DumpCommands(BufferIn, BufferInSize / 4, LogTypes::WII_IPC_STM); - //Memory::Write_U32(1, BufferOut); - //ReturnValue = 1; - break; + default: + { + _dbg_assert_msg_(WII_IPC_STM, 0, "CWII_IPC_HLE_Device_stm_immediate: 0x%x", Parameter); - case IOCTL_STM_LEDMODE: // (Input: 20 bytes, Output: 20 bytes) - INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str()); - INFO_LOG(WII_IPC_STM, " IOCTL_STM_LEDMODE"); - break; + INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str()); + DEBUG_LOG(WII_IPC_STM, " Parameter: 0x%x", Parameter); + DEBUG_LOG(WII_IPC_STM, " InBuffer: 0x%08x", BufferIn); + DEBUG_LOG(WII_IPC_STM, " InBufferSize: 0x%08x", BufferInSize); + DEBUG_LOG(WII_IPC_STM, " OutBuffer: 0x%08x", BufferOut); + DEBUG_LOG(WII_IPC_STM, " OutBufferSize: 0x%08x", BufferOutSize); + } + break; + } - default: - { - _dbg_assert_msg_(WII_IPC_STM, 0, "CWII_IPC_HLE_Device_stm_immediate: 0x%x", Parameter); - - INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str()); - DEBUG_LOG(WII_IPC_STM, " Parameter: 0x%x", Parameter); - DEBUG_LOG(WII_IPC_STM, " InBuffer: 0x%08x", BufferIn); - DEBUG_LOG(WII_IPC_STM, " InBufferSize: 0x%08x", BufferInSize); - DEBUG_LOG(WII_IPC_STM, " OutBuffer: 0x%08x", BufferOut); - DEBUG_LOG(WII_IPC_STM, " OutBufferSize: 0x%08x", BufferOutSize); - } - break; - } - - // Write return value to the IPC call - Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); - return GetDefaultReply(); - } + // Write return value to the IPC call + Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); + return GetDefaultReply(); + } }; // The /dev/stm/eventhook class CWII_IPC_HLE_Device_stm_eventhook : public IWII_IPC_HLE_Device { public: + CWII_IPC_HLE_Device_stm_eventhook(u32 _DeviceID, const std::string& _rDeviceName) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName), m_EventHookAddress(0) + { + } - CWII_IPC_HLE_Device_stm_eventhook(u32 _DeviceID, const std::string& _rDeviceName) - : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) - , m_EventHookAddress(0) - {} + virtual ~CWII_IPC_HLE_Device_stm_eventhook() {} + IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override + { + Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); + m_Active = true; + return GetDefaultReply(); + } - virtual ~CWII_IPC_HLE_Device_stm_eventhook() - { - } + IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override + { + m_EventHookAddress = 0; - IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override - { - Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); - m_Active = true; - return GetDefaultReply(); - } + INFO_LOG(WII_IPC_STM, "STM eventhook: Close"); + if (!_bForce) + Memory::Write_U32(0, _CommandAddress + 4); + m_Active = false; + return GetDefaultReply(); + } - IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override - { - m_EventHookAddress = 0; + IPCCommandResult IOCtl(u32 _CommandAddress) override + { + u32 Parameter = Memory::Read_U32(_CommandAddress + 0x0C); + u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); + u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); + u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); + u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); - INFO_LOG(WII_IPC_STM, "STM eventhook: Close"); - if (!_bForce) - Memory::Write_U32(0, _CommandAddress+4); - m_Active = false; - return GetDefaultReply(); - } + // Prepare the out buffer(s) with zeros as a safety precaution + // to avoid returning bad values + Memory::Memset(BufferOut, 0, BufferOutSize); + u32 ReturnValue = 0; - IPCCommandResult IOCtl(u32 _CommandAddress) override - { - u32 Parameter = Memory::Read_U32(_CommandAddress + 0x0C); - u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); - u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); - u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); + // write return value + switch (Parameter) + { + case IOCTL_STM_EVENTHOOK: + { + m_EventHookAddress = _CommandAddress; - // Prepare the out buffer(s) with zeros as a safety precaution - // to avoid returning bad values - Memory::Memset(BufferOut, 0, BufferOutSize); - u32 ReturnValue = 0; + INFO_LOG(WII_IPC_STM, "%s registers event hook:", GetDeviceName().c_str()); + DEBUG_LOG(WII_IPC_STM, "%x - IOCTL_STM_EVENTHOOK", Parameter); + DEBUG_LOG(WII_IPC_STM, "BufferIn: 0x%08x", BufferIn); + DEBUG_LOG(WII_IPC_STM, "BufferInSize: 0x%08x", BufferInSize); + DEBUG_LOG(WII_IPC_STM, "BufferOut: 0x%08x", BufferOut); + DEBUG_LOG(WII_IPC_STM, "BufferOutSize: 0x%08x", BufferOutSize); - // write return value - switch (Parameter) - { - case IOCTL_STM_EVENTHOOK: - { - m_EventHookAddress = _CommandAddress; + DumpCommands(BufferIn, BufferInSize / 4, LogTypes::WII_IPC_STM); + } + break; - INFO_LOG(WII_IPC_STM, "%s registers event hook:", GetDeviceName().c_str()); - DEBUG_LOG(WII_IPC_STM, "%x - IOCTL_STM_EVENTHOOK", Parameter); - DEBUG_LOG(WII_IPC_STM, "BufferIn: 0x%08x", BufferIn); - DEBUG_LOG(WII_IPC_STM, "BufferInSize: 0x%08x", BufferInSize); - DEBUG_LOG(WII_IPC_STM, "BufferOut: 0x%08x", BufferOut); - DEBUG_LOG(WII_IPC_STM, "BufferOutSize: 0x%08x", BufferOutSize); + default: + _dbg_assert_msg_(WII_IPC_STM, 0, "unknown %s ioctl %x", GetDeviceName().c_str(), Parameter); + break; + } - DumpCommands(BufferIn, BufferInSize/4, LogTypes::WII_IPC_STM); - } - break; + // Write return value to the IPC call, 0 means success + Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); + return GetDefaultReply(); + } - default: - _dbg_assert_msg_(WII_IPC_STM, 0, "unknown %s ioctl %x", - GetDeviceName().c_str(), Parameter); - break; - } - - // Write return value to the IPC call, 0 means success - Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); - return GetDefaultReply(); - } - - // STATE_TO_SAVE - u32 m_EventHookAddress; + // STATE_TO_SAVE + u32 m_EventHookAddress; }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp index f5666badf4..bba2ccaeca 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.cpp @@ -2,226 +2,227 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/HW/WII_IPC.h" #include "Common/CommonPaths.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" -#include "Core/Host.h" -#include "Core/Movie.h" #include "Core/Debugger/Debugger_SymbolMap.h" #include "Core/HW/SystemTimers.h" -#include "Core/HW/WII_IPC.h" #include "Core/HW/Wiimote.h" +#include "Core/Host.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" #include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h" +#include "Core/Movie.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" - void CWII_IPC_HLE_Device_usb_oh1_57e_305::EnqueueReply(u32 CommandAddress) { - // IOS seems to write back the command that was responded to in the FD field, this - // class does not overwrite the command so it is safe to read back. - Memory::Write_U32(Memory::Read_U32(CommandAddress), CommandAddress + 8); - // The original hardware overwrites the command type with the async reply type. - Memory::Write_U32(IPC_REP_ASYNC, CommandAddress); + // IOS seems to write back the command that was responded to in the FD field, this + // class does not overwrite the command so it is safe to read back. + Memory::Write_U32(Memory::Read_U32(CommandAddress), CommandAddress + 8); + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, CommandAddress); - WII_IPC_HLE_Interface::EnqueueReply(CommandAddress); + WII_IPC_HLE_Interface::EnqueueReply(CommandAddress); } // The device class -CWII_IPC_HLE_Device_usb_oh1_57e_305::CWII_IPC_HLE_Device_usb_oh1_57e_305(u32 _DeviceID, const std::string& _rDeviceName) - : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) - , m_ScanEnable(0) - , m_HCIEndpoint(0) - , m_ACLEndpoint(0) - , m_last_ticks(0) +CWII_IPC_HLE_Device_usb_oh1_57e_305::CWII_IPC_HLE_Device_usb_oh1_57e_305( + u32 _DeviceID, const std::string& _rDeviceName) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName), m_ScanEnable(0), m_HCIEndpoint(0), + m_ACLEndpoint(0), m_last_ticks(0) { - SysConf* sysconf; - std::unique_ptr owned_sysconf; - if (Core::g_want_determinism) - { - // See SysConf::UpdateLocation for comment about the Future. - owned_sysconf.reset(new SysConf()); - sysconf = owned_sysconf.get(); - sysconf->LoadFromFile(File::GetUserPath(D_SESSION_WIIROOT_IDX) + DIR_SEP WII_SYSCONF_DIR DIR_SEP WII_SYSCONF); - } - else - { - sysconf = SConfig::GetInstance().m_SYSCONF; - } + SysConf* sysconf; + std::unique_ptr owned_sysconf; + if (Core::g_want_determinism) + { + // See SysConf::UpdateLocation for comment about the Future. + owned_sysconf.reset(new SysConf()); + sysconf = owned_sysconf.get(); + sysconf->LoadFromFile(File::GetUserPath(D_SESSION_WIIROOT_IDX) + + DIR_SEP WII_SYSCONF_DIR DIR_SEP WII_SYSCONF); + } + else + { + sysconf = SConfig::GetInstance().m_SYSCONF; + } - // Activate only first Wiimote by default + // Activate only first Wiimote by default - _conf_pads BT_DINF; - SetUsbPointer(this); - if (!sysconf->GetArrayData("BT.DINF", (u8*)&BT_DINF, sizeof(_conf_pads))) - { - PanicAlertT("Trying to read from invalid SYSCONF\nWiimote bt ids are not available"); - } - else - { - bdaddr_t tmpBD = BDADDR_ANY; - u8 i = 0; - while (i < MAX_BBMOTES) - { - if (i < BT_DINF.num_registered) - { - tmpBD.b[5] = BT_DINF.active[i].bdaddr[0] = BT_DINF.registered[i].bdaddr[0]; - tmpBD.b[4] = BT_DINF.active[i].bdaddr[1] = BT_DINF.registered[i].bdaddr[1]; - tmpBD.b[3] = BT_DINF.active[i].bdaddr[2] = BT_DINF.registered[i].bdaddr[2]; - tmpBD.b[2] = BT_DINF.active[i].bdaddr[3] = BT_DINF.registered[i].bdaddr[3]; - tmpBD.b[1] = BT_DINF.active[i].bdaddr[4] = BT_DINF.registered[i].bdaddr[4]; - tmpBD.b[0] = BT_DINF.active[i].bdaddr[5] = BT_DINF.registered[i].bdaddr[5]; - } - else - { - tmpBD.b[5] = BT_DINF.active[i].bdaddr[0] = BT_DINF.registered[i].bdaddr[0] = i; - tmpBD.b[4] = BT_DINF.active[i].bdaddr[1] = BT_DINF.registered[i].bdaddr[1] = 0; - tmpBD.b[3] = BT_DINF.active[i].bdaddr[2] = BT_DINF.registered[i].bdaddr[2] = 0x79; - tmpBD.b[2] = BT_DINF.active[i].bdaddr[3] = BT_DINF.registered[i].bdaddr[3] = 0x19; - tmpBD.b[1] = BT_DINF.active[i].bdaddr[4] = BT_DINF.registered[i].bdaddr[4] = 2; - tmpBD.b[0] = BT_DINF.active[i].bdaddr[5] = BT_DINF.registered[i].bdaddr[5] = 0x11; - } + _conf_pads BT_DINF; + SetUsbPointer(this); + if (!sysconf->GetArrayData("BT.DINF", (u8*)&BT_DINF, sizeof(_conf_pads))) + { + PanicAlertT("Trying to read from invalid SYSCONF\nWiimote bt ids are not available"); + } + else + { + bdaddr_t tmpBD = BDADDR_ANY; + u8 i = 0; + while (i < MAX_BBMOTES) + { + if (i < BT_DINF.num_registered) + { + tmpBD.b[5] = BT_DINF.active[i].bdaddr[0] = BT_DINF.registered[i].bdaddr[0]; + tmpBD.b[4] = BT_DINF.active[i].bdaddr[1] = BT_DINF.registered[i].bdaddr[1]; + tmpBD.b[3] = BT_DINF.active[i].bdaddr[2] = BT_DINF.registered[i].bdaddr[2]; + tmpBD.b[2] = BT_DINF.active[i].bdaddr[3] = BT_DINF.registered[i].bdaddr[3]; + tmpBD.b[1] = BT_DINF.active[i].bdaddr[4] = BT_DINF.registered[i].bdaddr[4]; + tmpBD.b[0] = BT_DINF.active[i].bdaddr[5] = BT_DINF.registered[i].bdaddr[5]; + } + else + { + tmpBD.b[5] = BT_DINF.active[i].bdaddr[0] = BT_DINF.registered[i].bdaddr[0] = i; + tmpBD.b[4] = BT_DINF.active[i].bdaddr[1] = BT_DINF.registered[i].bdaddr[1] = 0; + tmpBD.b[3] = BT_DINF.active[i].bdaddr[2] = BT_DINF.registered[i].bdaddr[2] = 0x79; + tmpBD.b[2] = BT_DINF.active[i].bdaddr[3] = BT_DINF.registered[i].bdaddr[3] = 0x19; + tmpBD.b[1] = BT_DINF.active[i].bdaddr[4] = BT_DINF.registered[i].bdaddr[4] = 2; + tmpBD.b[0] = BT_DINF.active[i].bdaddr[5] = BT_DINF.registered[i].bdaddr[5] = 0x11; + } - const char* wmName; - if (i == WIIMOTE_BALANCE_BOARD) - wmName = "Nintendo RVL-WBC-01"; - else - wmName = "Nintendo RVL-CNT-01"; - memcpy(BT_DINF.registered[i].name, wmName, 20); - memcpy(BT_DINF.active[i].name, wmName, 20); + const char* wmName; + if (i == WIIMOTE_BALANCE_BOARD) + wmName = "Nintendo RVL-WBC-01"; + else + wmName = "Nintendo RVL-CNT-01"; + memcpy(BT_DINF.registered[i].name, wmName, 20); + memcpy(BT_DINF.active[i].name, wmName, 20); - INFO_LOG(WII_IPC_WIIMOTE, "Wiimote %d BT ID %x,%x,%x,%x,%x,%x", i, tmpBD.b[0], tmpBD.b[1], tmpBD.b[2], tmpBD.b[3], tmpBD.b[4], tmpBD.b[5]); - m_WiiMotes.push_back(CWII_IPC_HLE_WiiMote(this, i, tmpBD, false)); - i++; - } + INFO_LOG(WII_IPC_WIIMOTE, "Wiimote %d BT ID %x,%x,%x,%x,%x,%x", i, tmpBD.b[0], tmpBD.b[1], + tmpBD.b[2], tmpBD.b[3], tmpBD.b[4], tmpBD.b[5]); + m_WiiMotes.push_back(CWII_IPC_HLE_WiiMote(this, i, tmpBD, false)); + i++; + } - // save now so that when games load sysconf file it includes the new Wiimotes - // and the correct order for connected Wiimotes - if (!sysconf->SetArrayData("BT.DINF", (u8*)&BT_DINF, sizeof(_conf_pads)) || !sysconf->Save()) - PanicAlertT("Failed to write BT.DINF to SYSCONF"); - } + // save now so that when games load sysconf file it includes the new Wiimotes + // and the correct order for connected Wiimotes + if (!sysconf->SetArrayData("BT.DINF", (u8*)&BT_DINF, sizeof(_conf_pads)) || !sysconf->Save()) + PanicAlertT("Failed to write BT.DINF to SYSCONF"); + } - // The BCM2045's btaddr: - m_ControllerBD.b[0] = 0x11; - m_ControllerBD.b[1] = 0x02; - m_ControllerBD.b[2] = 0x19; - m_ControllerBD.b[3] = 0x79; - m_ControllerBD.b[4] = 0x00; - m_ControllerBD.b[5] = 0xFF; + // The BCM2045's btaddr: + m_ControllerBD.b[0] = 0x11; + m_ControllerBD.b[1] = 0x02; + m_ControllerBD.b[2] = 0x19; + m_ControllerBD.b[3] = 0x79; + m_ControllerBD.b[4] = 0x00; + m_ControllerBD.b[5] = 0xFF; - memset(m_PacketCount, 0, sizeof(m_PacketCount)); + memset(m_PacketCount, 0, sizeof(m_PacketCount)); - Host_SetWiiMoteConnectionState(0); + Host_SetWiiMoteConnectionState(0); } CWII_IPC_HLE_Device_usb_oh1_57e_305::~CWII_IPC_HLE_Device_usb_oh1_57e_305() { - m_WiiMotes.clear(); - SetUsbPointer(nullptr); + m_WiiMotes.clear(); + SetUsbPointer(nullptr); } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap &p) +void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap& p) { - p.Do(m_Active); - p.Do(m_ControllerBD); - p.Do(m_CtrlSetup); - p.Do(m_ACLSetup); - p.DoPOD(m_HCIEndpoint); - p.DoPOD(m_ACLEndpoint); - p.Do(m_last_ticks); - p.DoArray(m_PacketCount); - p.Do(m_ScanEnable); - p.Do(m_EventQueue); - m_acl_pool.DoState(p); + p.Do(m_Active); + p.Do(m_ControllerBD); + p.Do(m_CtrlSetup); + p.Do(m_ACLSetup); + p.DoPOD(m_HCIEndpoint); + p.DoPOD(m_ACLEndpoint); + p.Do(m_last_ticks); + p.DoArray(m_PacketCount); + p.Do(m_ScanEnable); + p.Do(m_EventQueue); + m_acl_pool.DoState(p); - for (unsigned int i = 0; i < MAX_BBMOTES; i++) - m_WiiMotes[i].DoState(p); + for (unsigned int i = 0; i < MAX_BBMOTES; i++) + m_WiiMotes[i].DoState(p); } bool CWII_IPC_HLE_Device_usb_oh1_57e_305::RemoteDisconnect(u16 _connectionHandle) { - return SendEventDisconnect(_connectionHandle, 0x13); + return SendEventDisconnect(_connectionHandle, 0x13); } IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::Open(u32 _CommandAddress, u32 _Mode) { - m_ScanEnable = 0; + m_ScanEnable = 0; - m_last_ticks = 0; - memset(m_PacketCount, 0, sizeof(m_PacketCount)); + m_last_ticks = 0; + memset(m_PacketCount, 0, sizeof(m_PacketCount)); - m_HCIEndpoint.m_address = 0; - m_ACLEndpoint.m_address = 0; + m_HCIEndpoint.m_address = 0; + m_ACLEndpoint.m_address = 0; - Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); - m_Active = true; - return GetDefaultReply(); + Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); + m_Active = true; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::Close(u32 _CommandAddress, bool _bForce) { - m_ScanEnable = 0; + m_ScanEnable = 0; - m_last_ticks = 0; - memset(m_PacketCount, 0, sizeof(m_PacketCount)); + m_last_ticks = 0; + memset(m_PacketCount, 0, sizeof(m_PacketCount)); - m_HCIEndpoint.m_address = 0; - m_ACLEndpoint.m_address = 0; + m_HCIEndpoint.m_address = 0; + m_ACLEndpoint.m_address = 0; - if (!_bForce) - Memory::Write_U32(0, _CommandAddress + 4); - m_Active = false; - return GetDefaultReply(); + if (!_bForce) + Memory::Write_U32(0, _CommandAddress + 4); + m_Active = false; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtl(u32 _CommandAddress) { - // NeoGamma (homebrew) is known to use this path. - ERROR_LOG(WII_IPC_WIIMOTE, "Bad IOCtl in CWII_IPC_HLE_Device_usb_oh1_57e_305"); - Memory::Write_U32(FS_EINVAL, _CommandAddress + 4); - return GetDefaultReply(); + // NeoGamma (homebrew) is known to use this path. + ERROR_LOG(WII_IPC_WIIMOTE, "Bad IOCtl in CWII_IPC_HLE_Device_usb_oh1_57e_305"); + Memory::Write_U32(FS_EINVAL, _CommandAddress + 4); + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtlV(u32 _CommandAddress) { -/* - Memory::Write_U8(255, 0x80149950); // BTM LOG // 3 logs L2Cap // 4 logs l2_csm$ - Memory::Write_U8(255, 0x80149949); // Security Manager - Memory::Write_U8(255, 0x80149048); // HID - Memory::Write_U8(3, 0x80152058); // low ?? // >= 4 and you will get a lot of event messages of the same type - Memory::Write_U8(1, 0x80152018); // WUD - Memory::Write_U8(1, 0x80151FC8); // DEBUGPrint - Memory::Write_U8(1, 0x80151488); // WPAD_LOG - Memory::Write_U8(1, 0x801514A8); // USB_LOG - Memory::Write_U8(1, 0x801514D8); // WUD_DEBUGPrint - Memory::Write_U8(1, 0x80148E09); // HID LOG -*/ + /* + Memory::Write_U8(255, 0x80149950); // BTM LOG // 3 logs L2Cap // 4 logs l2_csm$ + Memory::Write_U8(255, 0x80149949); // Security Manager + Memory::Write_U8(255, 0x80149048); // HID + Memory::Write_U8(3, 0x80152058); // low ?? // >= 4 and you will get a lot of event messages + of the same type + Memory::Write_U8(1, 0x80152018); // WUD + Memory::Write_U8(1, 0x80151FC8); // DEBUGPrint + Memory::Write_U8(1, 0x80151488); // WPAD_LOG + Memory::Write_U8(1, 0x801514A8); // USB_LOG + Memory::Write_U8(1, 0x801514D8); // WUD_DEBUGPrint + Memory::Write_U8(1, 0x80148E09); // HID LOG + */ - bool _SendReply = false; + bool _SendReply = false; - SIOCtlVBuffer CommandBuffer(_CommandAddress); + SIOCtlVBuffer CommandBuffer(_CommandAddress); - switch (CommandBuffer.Parameter) - { - case USBV0_IOCTL_CTRLMSG: // HCI command is received from the stack - { - // This is the HCI datapath from CPU to Wiimote, the USB stuff is little endian.. - m_CtrlSetup.bRequestType = *( u8*)Memory::GetPointer(CommandBuffer.InBuffer[0].m_Address); - m_CtrlSetup.bRequest = *( u8*)Memory::GetPointer(CommandBuffer.InBuffer[1].m_Address); - m_CtrlSetup.wValue = *(u16*)Memory::GetPointer(CommandBuffer.InBuffer[2].m_Address); - m_CtrlSetup.wIndex = *(u16*)Memory::GetPointer(CommandBuffer.InBuffer[3].m_Address); - m_CtrlSetup.wLength = *(u16*)Memory::GetPointer(CommandBuffer.InBuffer[4].m_Address); - m_CtrlSetup.m_PayLoadAddr = CommandBuffer.PayloadBuffer[0].m_Address; - m_CtrlSetup.m_PayLoadSize = CommandBuffer.PayloadBuffer[0].m_Size; - m_CtrlSetup.m_Address = CommandBuffer.m_Address; + switch (CommandBuffer.Parameter) + { + case USBV0_IOCTL_CTRLMSG: // HCI command is received from the stack + { + // This is the HCI datapath from CPU to Wiimote, the USB stuff is little endian.. + m_CtrlSetup.bRequestType = *(u8*)Memory::GetPointer(CommandBuffer.InBuffer[0].m_Address); + m_CtrlSetup.bRequest = *(u8*)Memory::GetPointer(CommandBuffer.InBuffer[1].m_Address); + m_CtrlSetup.wValue = *(u16*)Memory::GetPointer(CommandBuffer.InBuffer[2].m_Address); + m_CtrlSetup.wIndex = *(u16*)Memory::GetPointer(CommandBuffer.InBuffer[3].m_Address); + m_CtrlSetup.wLength = *(u16*)Memory::GetPointer(CommandBuffer.InBuffer[4].m_Address); + m_CtrlSetup.m_PayLoadAddr = CommandBuffer.PayloadBuffer[0].m_Address; + m_CtrlSetup.m_PayLoadSize = CommandBuffer.PayloadBuffer[0].m_Size; + m_CtrlSetup.m_Address = CommandBuffer.m_Address; - // check termination - _dbg_assert_msg_(WII_IPC_WIIMOTE, *(u8*)Memory::GetPointer(CommandBuffer.InBuffer[5].m_Address) == 0, - "WIIMOTE: Termination != 0"); + // check termination + _dbg_assert_msg_(WII_IPC_WIIMOTE, + *(u8*)Memory::GetPointer(CommandBuffer.InBuffer[5].m_Address) == 0, + "WIIMOTE: Termination != 0"); - #if 0 // this log can get really annoying +#if 0 // this log can get really annoying DEBUG_LOG(WII_IPC_WIIMOTE, "USB_IOCTL_CTRLMSG (0x%08x) - execute command", _CommandAddress); DEBUG_LOG(WII_IPC_WIIMOTE, " bRequestType: 0x%x", m_CtrlSetup.bRequestType); DEBUG_LOG(WII_IPC_WIIMOTE, " bRequest: 0x%x", m_CtrlSetup.bRequest); @@ -230,120 +231,121 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtlV(u32 _CommandAddress DEBUG_LOG(WII_IPC_WIIMOTE, " wLength: 0x%x", m_CtrlSetup.wLength); DEBUG_LOG(WII_IPC_WIIMOTE, " m_PayLoadAddr: 0x%x", m_CtrlSetup.m_PayLoadAddr); DEBUG_LOG(WII_IPC_WIIMOTE, " m_PayLoadSize: 0x%x", m_CtrlSetup.m_PayLoadSize); - #endif +#endif - // Replies are generated inside - ExecuteHCICommandMessage(m_CtrlSetup); - } - break; + // Replies are generated inside + ExecuteHCICommandMessage(m_CtrlSetup); + } + break; - case USBV0_IOCTL_BLKMSG: - { - u8 Command = Memory::Read_U8(CommandBuffer.InBuffer[0].m_Address); - switch (Command) - { - case ACL_DATA_OUT: // ACL data is received from the stack - { - // This is the ACL datapath from CPU to Wiimote - // Here we only need to record the command address in case we need to delay the reply - m_ACLSetup = CommandBuffer.m_Address; + case USBV0_IOCTL_BLKMSG: + { + u8 Command = Memory::Read_U8(CommandBuffer.InBuffer[0].m_Address); + switch (Command) + { + case ACL_DATA_OUT: // ACL data is received from the stack + { + // This is the ACL datapath from CPU to Wiimote + // Here we only need to record the command address in case we need to delay the reply + m_ACLSetup = CommandBuffer.m_Address; - #if defined(_DEBUG) || defined(DEBUGFAST) - DumpAsync(CommandBuffer.BufferVector, CommandBuffer.NumberInBuffer, CommandBuffer.NumberPayloadBuffer); - #endif +#if defined(_DEBUG) || defined(DEBUGFAST) + DumpAsync(CommandBuffer.BufferVector, CommandBuffer.NumberInBuffer, + CommandBuffer.NumberPayloadBuffer); +#endif - CtrlBuffer BulkBuffer(_CommandAddress); - hci_acldata_hdr_t* pACLHeader = (hci_acldata_hdr_t*)Memory::GetPointer(BulkBuffer.m_buffer); + CtrlBuffer BulkBuffer(_CommandAddress); + hci_acldata_hdr_t* pACLHeader = (hci_acldata_hdr_t*)Memory::GetPointer(BulkBuffer.m_buffer); - _dbg_assert_(WII_IPC_WIIMOTE, HCI_BC_FLAG(pACLHeader->con_handle) == HCI_POINT2POINT); - _dbg_assert_(WII_IPC_WIIMOTE, HCI_PB_FLAG(pACLHeader->con_handle) == HCI_PACKET_START); + _dbg_assert_(WII_IPC_WIIMOTE, HCI_BC_FLAG(pACLHeader->con_handle) == HCI_POINT2POINT); + _dbg_assert_(WII_IPC_WIIMOTE, HCI_PB_FLAG(pACLHeader->con_handle) == HCI_PACKET_START); - SendToDevice(HCI_CON_HANDLE(pACLHeader->con_handle), - Memory::GetPointer(BulkBuffer.m_buffer + sizeof(hci_acldata_hdr_t)), - pACLHeader->length); + SendToDevice(HCI_CON_HANDLE(pACLHeader->con_handle), + Memory::GetPointer(BulkBuffer.m_buffer + sizeof(hci_acldata_hdr_t)), + pACLHeader->length); - _SendReply = true; - } - break; + _SendReply = true; + } + break; - case ACL_DATA_IN: // We are given an ACL buffer to fill - { - CtrlBuffer temp(_CommandAddress); - m_ACLEndpoint = temp; + case ACL_DATA_IN: // We are given an ACL buffer to fill + { + CtrlBuffer temp(_CommandAddress); + m_ACLEndpoint = temp; - DEBUG_LOG(WII_IPC_WIIMOTE, "ACL_DATA_IN: 0x%08x ", _CommandAddress); - } - break; + DEBUG_LOG(WII_IPC_WIIMOTE, "ACL_DATA_IN: 0x%08x ", _CommandAddress); + } + break; - default: - { - _dbg_assert_msg_(WII_IPC_WIIMOTE, 0, "Unknown USBV0_IOCTL_BLKMSG: %x", Command); - } - break; - } - } - break; + default: + { + _dbg_assert_msg_(WII_IPC_WIIMOTE, 0, "Unknown USBV0_IOCTL_BLKMSG: %x", Command); + } + break; + } + } + break; + case USBV0_IOCTL_INTRMSG: + { + u8 Command = Memory::Read_U8(CommandBuffer.InBuffer[0].m_Address); + if (Command == HCI_EVENT) // We are given a HCI buffer to fill + { + CtrlBuffer temp(_CommandAddress); + m_HCIEndpoint = temp; - case USBV0_IOCTL_INTRMSG: - { - u8 Command = Memory::Read_U8(CommandBuffer.InBuffer[0].m_Address); - if (Command == HCI_EVENT) // We are given a HCI buffer to fill - { - CtrlBuffer temp(_CommandAddress); - m_HCIEndpoint = temp; + DEBUG_LOG(WII_IPC_WIIMOTE, "HCI_EVENT: 0x%08x ", _CommandAddress); + } + else + { + _dbg_assert_msg_(WII_IPC_WIIMOTE, 0, "Unknown USBV0_IOCTL_INTRMSG: %x", Command); + } + } + break; - DEBUG_LOG(WII_IPC_WIIMOTE, "HCI_EVENT: 0x%08x ", _CommandAddress); - } - else - { - _dbg_assert_msg_(WII_IPC_WIIMOTE, 0, "Unknown USBV0_IOCTL_INTRMSG: %x", Command); - } - } - break; + default: + { + _dbg_assert_msg_(WII_IPC_WIIMOTE, 0, "Unknown CWII_IPC_HLE_Device_usb_oh1_57e_305: %x", + CommandBuffer.Parameter); - default: - { - _dbg_assert_msg_(WII_IPC_WIIMOTE, 0, "Unknown CWII_IPC_HLE_Device_usb_oh1_57e_305: %x", CommandBuffer.Parameter); + DEBUG_LOG(WII_IPC_WIIMOTE, "%s - IOCtlV:", GetDeviceName().c_str()); + DEBUG_LOG(WII_IPC_WIIMOTE, " Parameter: 0x%x", CommandBuffer.Parameter); + DEBUG_LOG(WII_IPC_WIIMOTE, " NumberIn: 0x%08x", CommandBuffer.NumberInBuffer); + DEBUG_LOG(WII_IPC_WIIMOTE, " NumberOut: 0x%08x", CommandBuffer.NumberPayloadBuffer); + DEBUG_LOG(WII_IPC_WIIMOTE, " BufferVector: 0x%08x", CommandBuffer.BufferVector); + DEBUG_LOG(WII_IPC_WIIMOTE, " PayloadAddr: 0x%08x", CommandBuffer.PayloadBuffer[0].m_Address); + DEBUG_LOG(WII_IPC_WIIMOTE, " PayloadSize: 0x%08x", CommandBuffer.PayloadBuffer[0].m_Size); +#if defined(_DEBUG) || defined(DEBUGFAST) + DumpAsync(CommandBuffer.BufferVector, CommandBuffer.NumberInBuffer, + CommandBuffer.NumberPayloadBuffer); +#endif + } + break; + } - DEBUG_LOG(WII_IPC_WIIMOTE, "%s - IOCtlV:", GetDeviceName().c_str()); - DEBUG_LOG(WII_IPC_WIIMOTE, " Parameter: 0x%x", CommandBuffer.Parameter); - DEBUG_LOG(WII_IPC_WIIMOTE, " NumberIn: 0x%08x", CommandBuffer.NumberInBuffer); - DEBUG_LOG(WII_IPC_WIIMOTE, " NumberOut: 0x%08x", CommandBuffer.NumberPayloadBuffer); - DEBUG_LOG(WII_IPC_WIIMOTE, " BufferVector: 0x%08x", CommandBuffer.BufferVector); - DEBUG_LOG(WII_IPC_WIIMOTE, " PayloadAddr: 0x%08x", CommandBuffer.PayloadBuffer[0].m_Address); - DEBUG_LOG(WII_IPC_WIIMOTE, " PayloadSize: 0x%08x", CommandBuffer.PayloadBuffer[0].m_Size); - #if defined(_DEBUG) || defined(DEBUGFAST) - DumpAsync(CommandBuffer.BufferVector, CommandBuffer.NumberInBuffer, CommandBuffer.NumberPayloadBuffer); - #endif - } - break; - } - - // write return value - Memory::Write_U32(0, _CommandAddress + 4); - return _SendReply ? GetDefaultReply() : GetNoReply(); + // write return value + Memory::Write_U32(0, _CommandAddress + 4); + return _SendReply ? GetDefaultReply() : GetNoReply(); } - // Here we handle the USBV0_IOCTL_BLKMSG Ioctlv void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendToDevice(u16 _ConnectionHandle, u8* _pData, u32 _Size) { - CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_ConnectionHandle); - if (pWiiMote == nullptr) - return; + CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_ConnectionHandle); + if (pWiiMote == nullptr) + return; - INFO_LOG(WII_IPC_WIIMOTE, "Send ACL Packet to ConnectionHandle 0x%04x", _ConnectionHandle); - IncDataPacket(_ConnectionHandle); - pWiiMote->ExecuteL2capCmd(_pData, _Size); + INFO_LOG(WII_IPC_WIIMOTE, "Send ACL Packet to ConnectionHandle 0x%04x", _ConnectionHandle); + IncDataPacket(_ConnectionHandle); + pWiiMote->ExecuteL2capCmd(_pData, _Size); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::IncDataPacket(u16 _ConnectionHandle) { - m_PacketCount[_ConnectionHandle & 0xff]++; + m_PacketCount[_ConnectionHandle & 0xff]++; - // I don't think this makes sense or should be necessary - // m_PacketCount refers to "completed" packets and is not related to some buffer size, yes? +// I don't think this makes sense or should be necessary +// m_PacketCount refers to "completed" packets and is not related to some buffer size, yes? #if 0 if (m_PacketCount[_ConnectionHandle & 0xff] > (unsigned int)m_acl_pkts_num) { @@ -355,30 +357,33 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::IncDataPacket(u16 _ConnectionHandle) // Here we send ACL packets to CPU. They will consist of header + data. // The header is for example 07 00 41 00 which means size 0x0007 and channel 0x0041. -void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 connection_handle, const u8* data, u32 size) +void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 connection_handle, const u8* data, + u32 size) { - DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet from %x ready to send to stack...", connection_handle); + DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet from %x ready to send to stack...", connection_handle); - if (m_ACLEndpoint.IsValid() && !m_HCIEndpoint.IsValid() && m_EventQueue.empty()) - { - DEBUG_LOG(WII_IPC_WIIMOTE, "ACL endpoint valid, sending packet to %08x", m_ACLEndpoint.m_address); + if (m_ACLEndpoint.IsValid() && !m_HCIEndpoint.IsValid() && m_EventQueue.empty()) + { + DEBUG_LOG(WII_IPC_WIIMOTE, "ACL endpoint valid, sending packet to %08x", + m_ACLEndpoint.m_address); - hci_acldata_hdr_t* header = reinterpret_cast(Memory::GetPointer(m_ACLEndpoint.m_buffer)); - header->con_handle = HCI_MK_CON_HANDLE(connection_handle, HCI_PACKET_START, HCI_POINT2POINT); - header->length = size; + hci_acldata_hdr_t* header = + reinterpret_cast(Memory::GetPointer(m_ACLEndpoint.m_buffer)); + header->con_handle = HCI_MK_CON_HANDLE(connection_handle, HCI_PACKET_START, HCI_POINT2POINT); + header->length = size; - // Write the packet to the buffer - memcpy(reinterpret_cast(header) + sizeof(hci_acldata_hdr_t), data, header->length); + // Write the packet to the buffer + memcpy(reinterpret_cast(header) + sizeof(hci_acldata_hdr_t), data, header->length); - m_ACLEndpoint.SetRetVal(sizeof(hci_acldata_hdr_t) + size); - EnqueueReply(m_ACLEndpoint.m_address); - m_ACLEndpoint.Invalidate(); - } - else - { - DEBUG_LOG(WII_IPC_WIIMOTE, "ACL endpoint not currently valid, queuing..."); - m_acl_pool.Store(data, size, connection_handle); - } + m_ACLEndpoint.SetRetVal(sizeof(hci_acldata_hdr_t) + size); + EnqueueReply(m_ACLEndpoint.m_address); + m_ACLEndpoint.Invalidate(); + } + else + { + DEBUG_LOG(WII_IPC_WIIMOTE, "ACL endpoint not currently valid, queuing..."); + m_acl_pool.Store(data, size, connection_handle); + } } // These messages are sent from the Wiimote to the game, for example RequestConnection() @@ -388,863 +393,886 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 connection_handle, c // rather than enqueue it to some other memory and this will do good for StateSave void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _event) { - DEBUG_LOG(WII_IPC_WIIMOTE, "HCI event %x completed...", ((hci_event_hdr_t*)_event.m_buffer)->event); + DEBUG_LOG(WII_IPC_WIIMOTE, "HCI event %x completed...", + ((hci_event_hdr_t*)_event.m_buffer)->event); - if (m_HCIEndpoint.IsValid()) - { - if (m_EventQueue.empty()) // fast path :) - { - DEBUG_LOG(WII_IPC_WIIMOTE, "HCI endpoint valid, sending packet to %08x", m_HCIEndpoint.m_address); - m_HCIEndpoint.FillBuffer(_event.m_buffer, _event.m_size); - m_HCIEndpoint.SetRetVal(_event.m_size); - // Send a reply to indicate HCI buffer is filled - EnqueueReply(m_HCIEndpoint.m_address); - m_HCIEndpoint.Invalidate(); - } - else // push new one, pop oldest - { - DEBUG_LOG(WII_IPC_WIIMOTE, "HCI endpoint not currently valid, queueing (%zu)...", - m_EventQueue.size()); - m_EventQueue.push_back(_event); - const SQueuedEvent& event = m_EventQueue.front(); - DEBUG_LOG(WII_IPC_WIIMOTE, "HCI event %x " - "being written from queue (%zu) to %08x...", - ((hci_event_hdr_t*)event.m_buffer)->event, - m_EventQueue.size()-1, - m_HCIEndpoint.m_address); - m_HCIEndpoint.FillBuffer(event.m_buffer, event.m_size); - m_HCIEndpoint.SetRetVal(event.m_size); - // Send a reply to indicate HCI buffer is filled - EnqueueReply(m_HCIEndpoint.m_address); - m_HCIEndpoint.Invalidate(); - m_EventQueue.pop_front(); - } - } - else - { - DEBUG_LOG(WII_IPC_WIIMOTE, "HCI endpoint not currently valid, queuing (%zu)...", m_EventQueue.size()); - m_EventQueue.push_back(_event); - } + if (m_HCIEndpoint.IsValid()) + { + if (m_EventQueue.empty()) // fast path :) + { + DEBUG_LOG(WII_IPC_WIIMOTE, "HCI endpoint valid, sending packet to %08x", + m_HCIEndpoint.m_address); + m_HCIEndpoint.FillBuffer(_event.m_buffer, _event.m_size); + m_HCIEndpoint.SetRetVal(_event.m_size); + // Send a reply to indicate HCI buffer is filled + EnqueueReply(m_HCIEndpoint.m_address); + m_HCIEndpoint.Invalidate(); + } + else // push new one, pop oldest + { + DEBUG_LOG(WII_IPC_WIIMOTE, "HCI endpoint not currently valid, queueing (%zu)...", + m_EventQueue.size()); + m_EventQueue.push_back(_event); + const SQueuedEvent& event = m_EventQueue.front(); + DEBUG_LOG(WII_IPC_WIIMOTE, "HCI event %x " + "being written from queue (%zu) to %08x...", + ((hci_event_hdr_t*)event.m_buffer)->event, m_EventQueue.size() - 1, + m_HCIEndpoint.m_address); + m_HCIEndpoint.FillBuffer(event.m_buffer, event.m_size); + m_HCIEndpoint.SetRetVal(event.m_size); + // Send a reply to indicate HCI buffer is filled + EnqueueReply(m_HCIEndpoint.m_address); + m_HCIEndpoint.Invalidate(); + m_EventQueue.pop_front(); + } + } + else + { + DEBUG_LOG(WII_IPC_WIIMOTE, "HCI endpoint not currently valid, queuing (%zu)...", + m_EventQueue.size()); + m_EventQueue.push_back(_event); + } } u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update() { - bool packet_transferred = false; + bool packet_transferred = false; - // check HCI queue - if (!m_EventQueue.empty() && m_HCIEndpoint.IsValid()) - { - // an endpoint has become available, and we have a stored response. - const SQueuedEvent& event = m_EventQueue.front(); - DEBUG_LOG(WII_IPC_WIIMOTE, - "HCI event %x being written from queue (%zu) to %08x...", - ((hci_event_hdr_t*)event.m_buffer)->event, - m_EventQueue.size()-1, - m_HCIEndpoint.m_address); - m_HCIEndpoint.FillBuffer(event.m_buffer, event.m_size); - m_HCIEndpoint.SetRetVal(event.m_size); - // Send a reply to indicate HCI buffer is filled - EnqueueReply(m_HCIEndpoint.m_address); - m_HCIEndpoint.Invalidate(); - m_EventQueue.pop_front(); - packet_transferred = true; - } + // check HCI queue + if (!m_EventQueue.empty() && m_HCIEndpoint.IsValid()) + { + // an endpoint has become available, and we have a stored response. + const SQueuedEvent& event = m_EventQueue.front(); + DEBUG_LOG(WII_IPC_WIIMOTE, "HCI event %x being written from queue (%zu) to %08x...", + ((hci_event_hdr_t*)event.m_buffer)->event, m_EventQueue.size() - 1, + m_HCIEndpoint.m_address); + m_HCIEndpoint.FillBuffer(event.m_buffer, event.m_size); + m_HCIEndpoint.SetRetVal(event.m_size); + // Send a reply to indicate HCI buffer is filled + EnqueueReply(m_HCIEndpoint.m_address); + m_HCIEndpoint.Invalidate(); + m_EventQueue.pop_front(); + packet_transferred = true; + } - // check ACL queue - if (!m_acl_pool.IsEmpty() && m_ACLEndpoint.IsValid() && m_EventQueue.empty()) - { - m_acl_pool.WriteToEndpoint(m_ACLEndpoint); - packet_transferred = true; - } + // check ACL queue + if (!m_acl_pool.IsEmpty() && m_ACLEndpoint.IsValid() && m_EventQueue.empty()) + { + m_acl_pool.WriteToEndpoint(m_ACLEndpoint); + packet_transferred = true; + } - // We wait for ScanEnable to be sent from the Bluetooth stack through HCI_CMD_WRITE_SCAN_ENABLE - // before we initiate the connection. - // - // FiRES: TODO find a better way to do this + // We wait for ScanEnable to be sent from the Bluetooth stack through HCI_CMD_WRITE_SCAN_ENABLE + // before we initiate the connection. + // + // FiRES: TODO find a better way to do this - // Create ACL connection - if (m_HCIEndpoint.IsValid() && (m_ScanEnable & HCI_PAGE_SCAN_ENABLE)) - { - for (auto& wiimote : m_WiiMotes) - { - if (wiimote.EventPagingChanged(m_ScanEnable)) - { - Host_SetWiiMoteConnectionState(1); - SendEventRequestConnection(wiimote); - } - } - } + // Create ACL connection + if (m_HCIEndpoint.IsValid() && (m_ScanEnable & HCI_PAGE_SCAN_ENABLE)) + { + for (auto& wiimote : m_WiiMotes) + { + if (wiimote.EventPagingChanged(m_ScanEnable)) + { + Host_SetWiiMoteConnectionState(1); + SendEventRequestConnection(wiimote); + } + } + } - // Link channels when connected - if (m_ACLEndpoint.IsValid()) - { - for (auto& wiimote : m_WiiMotes) - { - if (wiimote.LinkChannel()) - break; - } - } + // Link channels when connected + if (m_ACLEndpoint.IsValid()) + { + for (auto& wiimote : m_WiiMotes) + { + if (wiimote.LinkChannel()) + break; + } + } - // The Real Wiimote sends report every ~5ms (200 Hz). - const u64 interval = SystemTimers::GetTicksPerSecond() / 200; - const u64 now = CoreTiming::GetTicks(); + // The Real Wiimote sends report every ~5ms (200 Hz). + const u64 interval = SystemTimers::GetTicksPerSecond() / 200; + const u64 now = CoreTiming::GetTicks(); - if (now - m_last_ticks > interval) - { - g_controller_interface.UpdateInput(); - for (unsigned int i = 0; i < m_WiiMotes.size(); i++) - Wiimote::Update(i, m_WiiMotes[i].IsConnected()); - m_last_ticks = now; - } + if (now - m_last_ticks > interval) + { + g_controller_interface.UpdateInput(); + for (unsigned int i = 0; i < m_WiiMotes.size(); i++) + Wiimote::Update(i, m_WiiMotes[i].IsConnected()); + m_last_ticks = now; + } - SendEventNumberOfCompletedPackets(); + SendEventNumberOfCompletedPackets(); - return packet_transferred; + return packet_transferred; } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::Store(const u8* data, const u16 size, const u16 conn_handle) +void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::Store(const u8* data, const u16 size, + const u16 conn_handle) { - if (m_queue.size() >= 100) - { - // Many simultaneous exchanges of ACL packets tend to cause the queue to fill up. - ERROR_LOG(WII_IPC_WIIMOTE, "ACL queue size reached 100 - current packet will be dropped!"); - return; - } + if (m_queue.size() >= 100) + { + // Many simultaneous exchanges of ACL packets tend to cause the queue to fill up. + ERROR_LOG(WII_IPC_WIIMOTE, "ACL queue size reached 100 - current packet will be dropped!"); + return; + } - _dbg_assert_msg_(WII_IPC_WIIMOTE, - size < m_acl_pkt_size, "ACL packet too large for pool"); + _dbg_assert_msg_(WII_IPC_WIIMOTE, size < m_acl_pkt_size, "ACL packet too large for pool"); - m_queue.push_back(Packet()); - auto& packet = m_queue.back(); + m_queue.push_back(Packet()); + auto& packet = m_queue.back(); - std::copy(data, data + size, packet.data); - packet.size = size; - packet.conn_handle = conn_handle; + std::copy(data, data + size, packet.data); + packet.size = size; + packet.conn_handle = conn_handle; } void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::WriteToEndpoint(CtrlBuffer& endpoint) { - auto& packet = m_queue.front(); + auto& packet = m_queue.front(); - const u8* const data = packet.data; - const u16 size = packet.size; - const u16 conn_handle = packet.conn_handle; + const u8* const data = packet.data; + const u16 size = packet.size; + const u16 conn_handle = packet.conn_handle; - DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet being written from " - "queue to %08x", endpoint.m_address); + DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet being written from " + "queue to %08x", + endpoint.m_address); - hci_acldata_hdr_t* pHeader = (hci_acldata_hdr_t*)Memory::GetPointer(endpoint.m_buffer); - pHeader->con_handle = HCI_MK_CON_HANDLE(conn_handle, HCI_PACKET_START, HCI_POINT2POINT); - pHeader->length = size; + hci_acldata_hdr_t* pHeader = (hci_acldata_hdr_t*)Memory::GetPointer(endpoint.m_buffer); + pHeader->con_handle = HCI_MK_CON_HANDLE(conn_handle, HCI_PACKET_START, HCI_POINT2POINT); + pHeader->length = size; - // Write the packet to the buffer - std::copy(data, data + size, (u8*)pHeader + sizeof(hci_acldata_hdr_t)); + // Write the packet to the buffer + std::copy(data, data + size, (u8*)pHeader + sizeof(hci_acldata_hdr_t)); - endpoint.SetRetVal(sizeof(hci_acldata_hdr_t) + size); + endpoint.SetRetVal(sizeof(hci_acldata_hdr_t) + size); - m_queue.pop_front(); + m_queue.pop_front(); - EnqueueReply(endpoint.m_address); - endpoint.Invalidate(); + EnqueueReply(endpoint.m_address); + endpoint.Invalidate(); } bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventInquiryComplete() { - SQueuedEvent Event(sizeof(SHCIEventInquiryComplete), 0); + SQueuedEvent Event(sizeof(SHCIEventInquiryComplete), 0); - SHCIEventInquiryComplete* pInquiryComplete = (SHCIEventInquiryComplete*)Event.m_buffer; - pInquiryComplete->EventType = HCI_EVENT_INQUIRY_COMPL; - pInquiryComplete->PayloadLength = sizeof(SHCIEventInquiryComplete) - 2; - pInquiryComplete->EventStatus = 0x00; + SHCIEventInquiryComplete* pInquiryComplete = (SHCIEventInquiryComplete*)Event.m_buffer; + pInquiryComplete->EventType = HCI_EVENT_INQUIRY_COMPL; + pInquiryComplete->PayloadLength = sizeof(SHCIEventInquiryComplete) - 2; + pInquiryComplete->EventStatus = 0x00; - AddEventToQueue(Event); + AddEventToQueue(Event); - INFO_LOG(WII_IPC_WIIMOTE, "Event: Inquiry complete"); + INFO_LOG(WII_IPC_WIIMOTE, "Event: Inquiry complete"); - return true; + return true; } bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventInquiryResponse() { - if (m_WiiMotes.empty()) - return false; + if (m_WiiMotes.empty()) + return false; - _dbg_assert_(WII_IPC_WIIMOTE, sizeof(SHCIEventInquiryResult) - 2 + (m_WiiMotes.size() * sizeof(hci_inquiry_response)) < 256); + _dbg_assert_(WII_IPC_WIIMOTE, sizeof(SHCIEventInquiryResult) - 2 + + (m_WiiMotes.size() * sizeof(hci_inquiry_response)) < + 256); - SQueuedEvent Event(static_cast(sizeof(SHCIEventInquiryResult) + m_WiiMotes.size()*sizeof(hci_inquiry_response)), 0); + SQueuedEvent Event(static_cast(sizeof(SHCIEventInquiryResult) + + m_WiiMotes.size() * sizeof(hci_inquiry_response)), + 0); - SHCIEventInquiryResult* pInquiryResult = (SHCIEventInquiryResult*)Event.m_buffer; + SHCIEventInquiryResult* pInquiryResult = (SHCIEventInquiryResult*)Event.m_buffer; - pInquiryResult->EventType = HCI_EVENT_INQUIRY_RESULT; - pInquiryResult->PayloadLength = (u8)(sizeof(SHCIEventInquiryResult) - 2 + (m_WiiMotes.size() * sizeof(hci_inquiry_response))); - pInquiryResult->num_responses = (u8)m_WiiMotes.size(); + pInquiryResult->EventType = HCI_EVENT_INQUIRY_RESULT; + pInquiryResult->PayloadLength = + (u8)(sizeof(SHCIEventInquiryResult) - 2 + (m_WiiMotes.size() * sizeof(hci_inquiry_response))); + pInquiryResult->num_responses = (u8)m_WiiMotes.size(); - for (size_t i=0; i < m_WiiMotes.size(); i++) - { - if (m_WiiMotes[i].IsConnected()) - continue; + for (size_t i = 0; i < m_WiiMotes.size(); i++) + { + if (m_WiiMotes[i].IsConnected()) + continue; - u8* pBuffer = Event.m_buffer + sizeof(SHCIEventInquiryResult) + i*sizeof(hci_inquiry_response); - hci_inquiry_response* pResponse = (hci_inquiry_response*)pBuffer; + u8* pBuffer = + Event.m_buffer + sizeof(SHCIEventInquiryResult) + i * sizeof(hci_inquiry_response); + hci_inquiry_response* pResponse = (hci_inquiry_response*)pBuffer; - pResponse->bdaddr = m_WiiMotes[i].GetBD(); - pResponse->uclass[0]= m_WiiMotes[i].GetClass()[0]; - pResponse->uclass[1]= m_WiiMotes[i].GetClass()[1]; - pResponse->uclass[2]= m_WiiMotes[i].GetClass()[2]; + pResponse->bdaddr = m_WiiMotes[i].GetBD(); + pResponse->uclass[0] = m_WiiMotes[i].GetClass()[0]; + pResponse->uclass[1] = m_WiiMotes[i].GetClass()[1]; + pResponse->uclass[2] = m_WiiMotes[i].GetClass()[2]; - pResponse->page_scan_rep_mode = 1; - pResponse->page_scan_period_mode = 0; - pResponse->page_scan_mode = 0; - pResponse->clock_offset = 0x3818; + pResponse->page_scan_rep_mode = 1; + pResponse->page_scan_period_mode = 0; + pResponse->page_scan_mode = 0; + pResponse->clock_offset = 0x3818; - INFO_LOG(WII_IPC_WIIMOTE, "Event: Send Fake Inquiry of one controller"); - INFO_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", - pResponse->bdaddr.b[0], pResponse->bdaddr.b[1], pResponse->bdaddr.b[2], - pResponse->bdaddr.b[3], pResponse->bdaddr.b[4], pResponse->bdaddr.b[5]); - } + INFO_LOG(WII_IPC_WIIMOTE, "Event: Send Fake Inquiry of one controller"); + INFO_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", pResponse->bdaddr.b[0], + pResponse->bdaddr.b[1], pResponse->bdaddr.b[2], pResponse->bdaddr.b[3], + pResponse->bdaddr.b[4], pResponse->bdaddr.b[5]); + } - AddEventToQueue(Event); + AddEventToQueue(Event); - return true; + return true; } bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventConnectionComplete(const bdaddr_t& _bd) { - CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_bd); - if (pWiiMote == nullptr) - return false; + CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_bd); + if (pWiiMote == nullptr) + return false; - SQueuedEvent Event(sizeof(SHCIEventConnectionComplete), 0); + SQueuedEvent Event(sizeof(SHCIEventConnectionComplete), 0); - SHCIEventConnectionComplete* pConnectionComplete = (SHCIEventConnectionComplete*)Event.m_buffer; + SHCIEventConnectionComplete* pConnectionComplete = (SHCIEventConnectionComplete*)Event.m_buffer; - pConnectionComplete->EventType = HCI_EVENT_CON_COMPL; - pConnectionComplete->PayloadLength = sizeof(SHCIEventConnectionComplete) - 2; - pConnectionComplete->EventStatus = 0x00; - pConnectionComplete->Connection_Handle = pWiiMote->GetConnectionHandle(); - pConnectionComplete->bdaddr = _bd; - pConnectionComplete->LinkType = HCI_LINK_ACL; - pConnectionComplete->EncryptionEnabled = HCI_ENCRYPTION_MODE_NONE; + pConnectionComplete->EventType = HCI_EVENT_CON_COMPL; + pConnectionComplete->PayloadLength = sizeof(SHCIEventConnectionComplete) - 2; + pConnectionComplete->EventStatus = 0x00; + pConnectionComplete->Connection_Handle = pWiiMote->GetConnectionHandle(); + pConnectionComplete->bdaddr = _bd; + pConnectionComplete->LinkType = HCI_LINK_ACL; + pConnectionComplete->EncryptionEnabled = HCI_ENCRYPTION_MODE_NONE; - AddEventToQueue(Event); + AddEventToQueue(Event); - CWII_IPC_HLE_WiiMote* pWiimote = AccessWiiMote(pConnectionComplete->Connection_Handle); - if (pWiimote) - pWiimote->EventConnectionAccepted(); + CWII_IPC_HLE_WiiMote* pWiimote = AccessWiiMote(pConnectionComplete->Connection_Handle); + if (pWiimote) + pWiimote->EventConnectionAccepted(); - static char s_szLinkType[][128] = - { - { "HCI_LINK_SCO 0x00 - Voice"}, - { "HCI_LINK_ACL 0x01 - Data"}, - { "HCI_LINK_eSCO 0x02 - eSCO"}, - }; + static char s_szLinkType[][128] = { + {"HCI_LINK_SCO 0x00 - Voice"}, + {"HCI_LINK_ACL 0x01 - Data"}, + {"HCI_LINK_eSCO 0x02 - eSCO"}, + }; - INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventConnectionComplete"); - INFO_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", pConnectionComplete->Connection_Handle); - DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", - pConnectionComplete->bdaddr.b[0], pConnectionComplete->bdaddr.b[1], pConnectionComplete->bdaddr.b[2], - pConnectionComplete->bdaddr.b[3], pConnectionComplete->bdaddr.b[4], pConnectionComplete->bdaddr.b[5]); - DEBUG_LOG(WII_IPC_WIIMOTE, " LinkType: %s", s_szLinkType[pConnectionComplete->LinkType]); - DEBUG_LOG(WII_IPC_WIIMOTE, " EncryptionEnabled: %i", pConnectionComplete->EncryptionEnabled); + INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventConnectionComplete"); + INFO_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", pConnectionComplete->Connection_Handle); + DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", + pConnectionComplete->bdaddr.b[0], pConnectionComplete->bdaddr.b[1], + pConnectionComplete->bdaddr.b[2], pConnectionComplete->bdaddr.b[3], + pConnectionComplete->bdaddr.b[4], pConnectionComplete->bdaddr.b[5]); + DEBUG_LOG(WII_IPC_WIIMOTE, " LinkType: %s", s_szLinkType[pConnectionComplete->LinkType]); + DEBUG_LOG(WII_IPC_WIIMOTE, " EncryptionEnabled: %i", pConnectionComplete->EncryptionEnabled); - return true; + return true; } // This is called from Update() after ScanEnable has been enabled. -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRequestConnection(CWII_IPC_HLE_WiiMote& _rWiiMote) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRequestConnection( + CWII_IPC_HLE_WiiMote& _rWiiMote) { - SQueuedEvent Event(sizeof(SHCIEventRequestConnection), 0); + SQueuedEvent Event(sizeof(SHCIEventRequestConnection), 0); - SHCIEventRequestConnection* pEventRequestConnection = (SHCIEventRequestConnection*)Event.m_buffer; + SHCIEventRequestConnection* pEventRequestConnection = (SHCIEventRequestConnection*)Event.m_buffer; - pEventRequestConnection->EventType = HCI_EVENT_CON_REQ; - pEventRequestConnection->PayloadLength = sizeof(SHCIEventRequestConnection) - 2; - pEventRequestConnection->bdaddr = _rWiiMote.GetBD(); - pEventRequestConnection->uclass[0] = _rWiiMote.GetClass()[0]; - pEventRequestConnection->uclass[1] = _rWiiMote.GetClass()[1]; - pEventRequestConnection->uclass[2] = _rWiiMote.GetClass()[2]; - pEventRequestConnection->LinkType = HCI_LINK_ACL; + pEventRequestConnection->EventType = HCI_EVENT_CON_REQ; + pEventRequestConnection->PayloadLength = sizeof(SHCIEventRequestConnection) - 2; + pEventRequestConnection->bdaddr = _rWiiMote.GetBD(); + pEventRequestConnection->uclass[0] = _rWiiMote.GetClass()[0]; + pEventRequestConnection->uclass[1] = _rWiiMote.GetClass()[1]; + pEventRequestConnection->uclass[2] = _rWiiMote.GetClass()[2]; + pEventRequestConnection->LinkType = HCI_LINK_ACL; - AddEventToQueue(Event); + AddEventToQueue(Event); - static char LinkType[][128] = - { - { "HCI_LINK_SCO 0x00 - Voice"}, - { "HCI_LINK_ACL 0x01 - Data" }, - { "HCI_LINK_eSCO 0x02 - eSCO" }, - }; + static char LinkType[][128] = { + {"HCI_LINK_SCO 0x00 - Voice"}, + {"HCI_LINK_ACL 0x01 - Data"}, + {"HCI_LINK_eSCO 0x02 - eSCO"}, + }; - INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventRequestConnection"); - INFO_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", - pEventRequestConnection->bdaddr.b[0], pEventRequestConnection->bdaddr.b[1], pEventRequestConnection->bdaddr.b[2], - pEventRequestConnection->bdaddr.b[3], pEventRequestConnection->bdaddr.b[4], pEventRequestConnection->bdaddr.b[5]); - DEBUG_LOG(WII_IPC_WIIMOTE, " COD[0]: 0x%02x", pEventRequestConnection->uclass[0]); - DEBUG_LOG(WII_IPC_WIIMOTE, " COD[1]: 0x%02x", pEventRequestConnection->uclass[1]); - DEBUG_LOG(WII_IPC_WIIMOTE, " COD[2]: 0x%02x", pEventRequestConnection->uclass[2]); - DEBUG_LOG(WII_IPC_WIIMOTE, " LinkType: %s", LinkType[pEventRequestConnection->LinkType]); + INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventRequestConnection"); + INFO_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", + pEventRequestConnection->bdaddr.b[0], pEventRequestConnection->bdaddr.b[1], + pEventRequestConnection->bdaddr.b[2], pEventRequestConnection->bdaddr.b[3], + pEventRequestConnection->bdaddr.b[4], pEventRequestConnection->bdaddr.b[5]); + DEBUG_LOG(WII_IPC_WIIMOTE, " COD[0]: 0x%02x", pEventRequestConnection->uclass[0]); + DEBUG_LOG(WII_IPC_WIIMOTE, " COD[1]: 0x%02x", pEventRequestConnection->uclass[1]); + DEBUG_LOG(WII_IPC_WIIMOTE, " COD[2]: 0x%02x", pEventRequestConnection->uclass[2]); + DEBUG_LOG(WII_IPC_WIIMOTE, " LinkType: %s", LinkType[pEventRequestConnection->LinkType]); - return true; + return true; } bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventDisconnect(u16 _connectionHandle, u8 _Reason) { - CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); - if (pWiiMote == nullptr) - return false; + CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); + if (pWiiMote == nullptr) + return false; - SQueuedEvent Event(sizeof(SHCIEventDisconnectCompleted), _connectionHandle); + SQueuedEvent Event(sizeof(SHCIEventDisconnectCompleted), _connectionHandle); - SHCIEventDisconnectCompleted* pDisconnect = (SHCIEventDisconnectCompleted*)Event.m_buffer; - pDisconnect->EventType = HCI_EVENT_DISCON_COMPL; - pDisconnect->PayloadLength = sizeof(SHCIEventDisconnectCompleted) - 2; - pDisconnect->EventStatus = 0; - pDisconnect->Connection_Handle = _connectionHandle; - pDisconnect->Reason = _Reason; + SHCIEventDisconnectCompleted* pDisconnect = (SHCIEventDisconnectCompleted*)Event.m_buffer; + pDisconnect->EventType = HCI_EVENT_DISCON_COMPL; + pDisconnect->PayloadLength = sizeof(SHCIEventDisconnectCompleted) - 2; + pDisconnect->EventStatus = 0; + pDisconnect->Connection_Handle = _connectionHandle; + pDisconnect->Reason = _Reason; - AddEventToQueue(Event); + AddEventToQueue(Event); - INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventDisconnect"); - INFO_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", pDisconnect->Connection_Handle); - INFO_LOG(WII_IPC_WIIMOTE, " Reason: 0x%02x", pDisconnect->Reason); + INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventDisconnect"); + INFO_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", pDisconnect->Connection_Handle); + INFO_LOG(WII_IPC_WIIMOTE, " Reason: 0x%02x", pDisconnect->Reason); - return true; + return true; } bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventAuthenticationCompleted(u16 _connectionHandle) { - CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); - if (pWiiMote == nullptr) - return false; + CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); + if (pWiiMote == nullptr) + return false; - SQueuedEvent Event(sizeof(SHCIEventAuthenticationCompleted), _connectionHandle); + SQueuedEvent Event(sizeof(SHCIEventAuthenticationCompleted), _connectionHandle); - SHCIEventAuthenticationCompleted* pEventAuthenticationCompleted = (SHCIEventAuthenticationCompleted*)Event.m_buffer; - pEventAuthenticationCompleted->EventType = HCI_EVENT_AUTH_COMPL; - pEventAuthenticationCompleted->PayloadLength = sizeof(SHCIEventAuthenticationCompleted) - 2; - pEventAuthenticationCompleted->EventStatus = 0; - pEventAuthenticationCompleted->Connection_Handle = _connectionHandle; + SHCIEventAuthenticationCompleted* pEventAuthenticationCompleted = + (SHCIEventAuthenticationCompleted*)Event.m_buffer; + pEventAuthenticationCompleted->EventType = HCI_EVENT_AUTH_COMPL; + pEventAuthenticationCompleted->PayloadLength = sizeof(SHCIEventAuthenticationCompleted) - 2; + pEventAuthenticationCompleted->EventStatus = 0; + pEventAuthenticationCompleted->Connection_Handle = _connectionHandle; - INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventAuthenticationCompleted"); - INFO_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", pEventAuthenticationCompleted->Connection_Handle); + INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventAuthenticationCompleted"); + INFO_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", + pEventAuthenticationCompleted->Connection_Handle); - AddEventToQueue(Event); + AddEventToQueue(Event); - return true; + return true; } bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRemoteNameReq(const bdaddr_t& _bd) { - CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_bd); - if (pWiiMote == nullptr) - return false; + CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_bd); + if (pWiiMote == nullptr) + return false; - SQueuedEvent Event(sizeof(SHCIEventRemoteNameReq), 0); + SQueuedEvent Event(sizeof(SHCIEventRemoteNameReq), 0); - SHCIEventRemoteNameReq* pRemoteNameReq = (SHCIEventRemoteNameReq*)Event.m_buffer; + SHCIEventRemoteNameReq* pRemoteNameReq = (SHCIEventRemoteNameReq*)Event.m_buffer; - pRemoteNameReq->EventType = HCI_EVENT_REMOTE_NAME_REQ_COMPL; - pRemoteNameReq->PayloadLength = sizeof(SHCIEventRemoteNameReq) - 2; - pRemoteNameReq->EventStatus = 0x00; - pRemoteNameReq->bdaddr = _bd; - strcpy((char*)pRemoteNameReq->RemoteName, pWiiMote->GetName()); + pRemoteNameReq->EventType = HCI_EVENT_REMOTE_NAME_REQ_COMPL; + pRemoteNameReq->PayloadLength = sizeof(SHCIEventRemoteNameReq) - 2; + pRemoteNameReq->EventStatus = 0x00; + pRemoteNameReq->bdaddr = _bd; + strcpy((char*)pRemoteNameReq->RemoteName, pWiiMote->GetName()); - INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventRemoteNameReq"); - INFO_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", - pRemoteNameReq->bdaddr.b[0], pRemoteNameReq->bdaddr.b[1], pRemoteNameReq->bdaddr.b[2], - pRemoteNameReq->bdaddr.b[3], pRemoteNameReq->bdaddr.b[4], pRemoteNameReq->bdaddr.b[5]); - DEBUG_LOG(WII_IPC_WIIMOTE, " RemoteName: %s", pRemoteNameReq->RemoteName); + INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventRemoteNameReq"); + INFO_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", pRemoteNameReq->bdaddr.b[0], + pRemoteNameReq->bdaddr.b[1], pRemoteNameReq->bdaddr.b[2], pRemoteNameReq->bdaddr.b[3], + pRemoteNameReq->bdaddr.b[4], pRemoteNameReq->bdaddr.b[5]); + DEBUG_LOG(WII_IPC_WIIMOTE, " RemoteName: %s", pRemoteNameReq->RemoteName); - AddEventToQueue(Event); + AddEventToQueue(Event); - return true; + return true; } bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventReadRemoteFeatures(u16 _connectionHandle) { - CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); - if (pWiiMote == nullptr) - return false; + CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); + if (pWiiMote == nullptr) + return false; - SQueuedEvent Event(sizeof(SHCIEventReadRemoteFeatures), _connectionHandle); + SQueuedEvent Event(sizeof(SHCIEventReadRemoteFeatures), _connectionHandle); - SHCIEventReadRemoteFeatures* pReadRemoteFeatures = (SHCIEventReadRemoteFeatures*)Event.m_buffer; + SHCIEventReadRemoteFeatures* pReadRemoteFeatures = (SHCIEventReadRemoteFeatures*)Event.m_buffer; - pReadRemoteFeatures->EventType = HCI_EVENT_READ_REMOTE_FEATURES_COMPL; - pReadRemoteFeatures->PayloadLength = sizeof(SHCIEventReadRemoteFeatures) - 2; - pReadRemoteFeatures->EventStatus = 0x00; - pReadRemoteFeatures->ConnectionHandle = _connectionHandle; - pReadRemoteFeatures->features[0] = pWiiMote->GetFeatures()[0]; - pReadRemoteFeatures->features[1] = pWiiMote->GetFeatures()[1]; - pReadRemoteFeatures->features[2] = pWiiMote->GetFeatures()[2]; - pReadRemoteFeatures->features[3] = pWiiMote->GetFeatures()[3]; - pReadRemoteFeatures->features[4] = pWiiMote->GetFeatures()[4]; - pReadRemoteFeatures->features[5] = pWiiMote->GetFeatures()[5]; - pReadRemoteFeatures->features[6] = pWiiMote->GetFeatures()[6]; - pReadRemoteFeatures->features[7] = pWiiMote->GetFeatures()[7]; + pReadRemoteFeatures->EventType = HCI_EVENT_READ_REMOTE_FEATURES_COMPL; + pReadRemoteFeatures->PayloadLength = sizeof(SHCIEventReadRemoteFeatures) - 2; + pReadRemoteFeatures->EventStatus = 0x00; + pReadRemoteFeatures->ConnectionHandle = _connectionHandle; + pReadRemoteFeatures->features[0] = pWiiMote->GetFeatures()[0]; + pReadRemoteFeatures->features[1] = pWiiMote->GetFeatures()[1]; + pReadRemoteFeatures->features[2] = pWiiMote->GetFeatures()[2]; + pReadRemoteFeatures->features[3] = pWiiMote->GetFeatures()[3]; + pReadRemoteFeatures->features[4] = pWiiMote->GetFeatures()[4]; + pReadRemoteFeatures->features[5] = pWiiMote->GetFeatures()[5]; + pReadRemoteFeatures->features[6] = pWiiMote->GetFeatures()[6]; + pReadRemoteFeatures->features[7] = pWiiMote->GetFeatures()[7]; - INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventReadRemoteFeatures"); - DEBUG_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", pReadRemoteFeatures->ConnectionHandle); - DEBUG_LOG(WII_IPC_WIIMOTE, " features: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", - pReadRemoteFeatures->features[0], pReadRemoteFeatures->features[1], pReadRemoteFeatures->features[2], - pReadRemoteFeatures->features[3], pReadRemoteFeatures->features[4], pReadRemoteFeatures->features[5], - pReadRemoteFeatures->features[6], pReadRemoteFeatures->features[7]); + INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventReadRemoteFeatures"); + DEBUG_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", pReadRemoteFeatures->ConnectionHandle); + DEBUG_LOG(WII_IPC_WIIMOTE, " features: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + pReadRemoteFeatures->features[0], pReadRemoteFeatures->features[1], + pReadRemoteFeatures->features[2], pReadRemoteFeatures->features[3], + pReadRemoteFeatures->features[4], pReadRemoteFeatures->features[5], + pReadRemoteFeatures->features[6], pReadRemoteFeatures->features[7]); - AddEventToQueue(Event); + AddEventToQueue(Event); - return true; + return true; } bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventReadRemoteVerInfo(u16 _connectionHandle) { - CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); - if (pWiiMote == nullptr) - return false; + CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); + if (pWiiMote == nullptr) + return false; - SQueuedEvent Event(sizeof(SHCIEventReadRemoteVerInfo), _connectionHandle); + SQueuedEvent Event(sizeof(SHCIEventReadRemoteVerInfo), _connectionHandle); - SHCIEventReadRemoteVerInfo* pReadRemoteVerInfo = (SHCIEventReadRemoteVerInfo*)Event.m_buffer; - pReadRemoteVerInfo->EventType = HCI_EVENT_READ_REMOTE_VER_INFO_COMPL; - pReadRemoteVerInfo->PayloadLength = sizeof(SHCIEventReadRemoteVerInfo) - 2; - pReadRemoteVerInfo->EventStatus = 0x00; - pReadRemoteVerInfo->ConnectionHandle = _connectionHandle; - pReadRemoteVerInfo->lmp_version = pWiiMote->GetLMPVersion(); - pReadRemoteVerInfo->manufacturer = pWiiMote->GetManufactorID(); - pReadRemoteVerInfo->lmp_subversion = pWiiMote->GetLMPSubVersion(); + SHCIEventReadRemoteVerInfo* pReadRemoteVerInfo = (SHCIEventReadRemoteVerInfo*)Event.m_buffer; + pReadRemoteVerInfo->EventType = HCI_EVENT_READ_REMOTE_VER_INFO_COMPL; + pReadRemoteVerInfo->PayloadLength = sizeof(SHCIEventReadRemoteVerInfo) - 2; + pReadRemoteVerInfo->EventStatus = 0x00; + pReadRemoteVerInfo->ConnectionHandle = _connectionHandle; + pReadRemoteVerInfo->lmp_version = pWiiMote->GetLMPVersion(); + pReadRemoteVerInfo->manufacturer = pWiiMote->GetManufactorID(); + pReadRemoteVerInfo->lmp_subversion = pWiiMote->GetLMPSubVersion(); - INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventReadRemoteVerInfo"); - DEBUG_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", pReadRemoteVerInfo->ConnectionHandle); - DEBUG_LOG(WII_IPC_WIIMOTE, " lmp_version: 0x%02x", pReadRemoteVerInfo->lmp_version); - DEBUG_LOG(WII_IPC_WIIMOTE, " manufacturer: 0x%04x", pReadRemoteVerInfo->manufacturer); - DEBUG_LOG(WII_IPC_WIIMOTE, " lmp_subversion: 0x%04x", pReadRemoteVerInfo->lmp_subversion); + INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventReadRemoteVerInfo"); + DEBUG_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", pReadRemoteVerInfo->ConnectionHandle); + DEBUG_LOG(WII_IPC_WIIMOTE, " lmp_version: 0x%02x", pReadRemoteVerInfo->lmp_version); + DEBUG_LOG(WII_IPC_WIIMOTE, " manufacturer: 0x%04x", pReadRemoteVerInfo->manufacturer); + DEBUG_LOG(WII_IPC_WIIMOTE, " lmp_subversion: 0x%04x", pReadRemoteVerInfo->lmp_subversion); - AddEventToQueue(Event); + AddEventToQueue(Event); - return true; + return true; } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventCommandComplete(u16 opcode, const void* data, u32 data_size) +void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventCommandComplete(u16 opcode, const void* data, + u32 data_size) { - _dbg_assert_(WII_IPC_WIIMOTE, (sizeof(SHCIEventCommand) - 2 + data_size) < 256); + _dbg_assert_(WII_IPC_WIIMOTE, (sizeof(SHCIEventCommand) - 2 + data_size) < 256); - SQueuedEvent event(sizeof(SHCIEventCommand) + data_size, 0); + SQueuedEvent event(sizeof(SHCIEventCommand) + data_size, 0); - SHCIEventCommand* hci_event = reinterpret_cast(event.m_buffer); - hci_event->EventType = HCI_EVENT_COMMAND_COMPL; - hci_event->PayloadLength = (u8)(sizeof(SHCIEventCommand) - 2 + data_size); - hci_event->PacketIndicator = 0x01; - hci_event->Opcode = opcode; + SHCIEventCommand* hci_event = reinterpret_cast(event.m_buffer); + hci_event->EventType = HCI_EVENT_COMMAND_COMPL; + hci_event->PayloadLength = (u8)(sizeof(SHCIEventCommand) - 2 + data_size); + hci_event->PacketIndicator = 0x01; + hci_event->Opcode = opcode; - // add the payload - if (data != nullptr && data_size > 0) - { - u8* payload = event.m_buffer + sizeof(SHCIEventCommand); - memcpy(payload, data, data_size); - } + // add the payload + if (data != nullptr && data_size > 0) + { + u8* payload = event.m_buffer + sizeof(SHCIEventCommand); + memcpy(payload, data, data_size); + } - INFO_LOG(WII_IPC_WIIMOTE, "Event: Command Complete (Opcode: 0x%04x)", hci_event->Opcode); + INFO_LOG(WII_IPC_WIIMOTE, "Event: Command Complete (Opcode: 0x%04x)", hci_event->Opcode); - AddEventToQueue(event); + AddEventToQueue(event); } bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventCommandStatus(u16 _Opcode) { - SQueuedEvent Event(sizeof(SHCIEventStatus), 0); + SQueuedEvent Event(sizeof(SHCIEventStatus), 0); - SHCIEventStatus* pHCIEvent = (SHCIEventStatus*)Event.m_buffer; - pHCIEvent->EventType = HCI_EVENT_COMMAND_STATUS; - pHCIEvent->PayloadLength = sizeof(SHCIEventStatus) - 2; - pHCIEvent->EventStatus = 0x0; - pHCIEvent->PacketIndicator = 0x01; - pHCIEvent->Opcode = _Opcode; + SHCIEventStatus* pHCIEvent = (SHCIEventStatus*)Event.m_buffer; + pHCIEvent->EventType = HCI_EVENT_COMMAND_STATUS; + pHCIEvent->PayloadLength = sizeof(SHCIEventStatus) - 2; + pHCIEvent->EventStatus = 0x0; + pHCIEvent->PacketIndicator = 0x01; + pHCIEvent->Opcode = _Opcode; - INFO_LOG(WII_IPC_WIIMOTE, "Event: Command Status (Opcode: 0x%04x)", pHCIEvent->Opcode); + INFO_LOG(WII_IPC_WIIMOTE, "Event: Command Status (Opcode: 0x%04x)", pHCIEvent->Opcode); - AddEventToQueue(Event); + AddEventToQueue(Event); - return true; + return true; } bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRoleChange(bdaddr_t _bd, bool _master) { - CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_bd); - if (pWiiMote == nullptr) - return false; + CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_bd); + if (pWiiMote == nullptr) + return false; - SQueuedEvent Event(sizeof(SHCIEventRoleChange), 0); + SQueuedEvent Event(sizeof(SHCIEventRoleChange), 0); - SHCIEventRoleChange* pRoleChange = (SHCIEventRoleChange*)Event.m_buffer; + SHCIEventRoleChange* pRoleChange = (SHCIEventRoleChange*)Event.m_buffer; - pRoleChange->EventType = HCI_EVENT_ROLE_CHANGE; - pRoleChange->PayloadLength = sizeof(SHCIEventRoleChange) - 2; - pRoleChange->EventStatus = 0x00; - pRoleChange->bdaddr = _bd; - pRoleChange->NewRole = _master ? 0x00 : 0x01; + pRoleChange->EventType = HCI_EVENT_ROLE_CHANGE; + pRoleChange->PayloadLength = sizeof(SHCIEventRoleChange) - 2; + pRoleChange->EventStatus = 0x00; + pRoleChange->bdaddr = _bd; + pRoleChange->NewRole = _master ? 0x00 : 0x01; - AddEventToQueue(Event); + AddEventToQueue(Event); - INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventRoleChange"); - DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", - pRoleChange->bdaddr.b[0], pRoleChange->bdaddr.b[1], pRoleChange->bdaddr.b[2], - pRoleChange->bdaddr.b[3], pRoleChange->bdaddr.b[4], pRoleChange->bdaddr.b[5]); - DEBUG_LOG(WII_IPC_WIIMOTE, " NewRole: %i", pRoleChange->NewRole); + INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventRoleChange"); + DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", pRoleChange->bdaddr.b[0], + pRoleChange->bdaddr.b[1], pRoleChange->bdaddr.b[2], pRoleChange->bdaddr.b[3], + pRoleChange->bdaddr.b[4], pRoleChange->bdaddr.b[5]); + DEBUG_LOG(WII_IPC_WIIMOTE, " NewRole: %i", pRoleChange->NewRole); - return true; + return true; } bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventNumberOfCompletedPackets() { - SQueuedEvent Event((u32)(sizeof(hci_event_hdr_t) + sizeof(hci_num_compl_pkts_ep) + (sizeof(hci_num_compl_pkts_info) * m_WiiMotes.size())), 0); + SQueuedEvent Event((u32)(sizeof(hci_event_hdr_t) + sizeof(hci_num_compl_pkts_ep) + + (sizeof(hci_num_compl_pkts_info) * m_WiiMotes.size())), + 0); - INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventNumberOfCompletedPackets"); + INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventNumberOfCompletedPackets"); - hci_event_hdr_t* event_hdr = (hci_event_hdr_t*)Event.m_buffer; - hci_num_compl_pkts_ep* event = (hci_num_compl_pkts_ep*)((u8*)event_hdr + sizeof(hci_event_hdr_t)); - hci_num_compl_pkts_info* info = (hci_num_compl_pkts_info*)((u8*)event + sizeof(hci_num_compl_pkts_ep)); + hci_event_hdr_t* event_hdr = (hci_event_hdr_t*)Event.m_buffer; + hci_num_compl_pkts_ep* event = (hci_num_compl_pkts_ep*)((u8*)event_hdr + sizeof(hci_event_hdr_t)); + hci_num_compl_pkts_info* info = + (hci_num_compl_pkts_info*)((u8*)event + sizeof(hci_num_compl_pkts_ep)); - event_hdr->event = HCI_EVENT_NUM_COMPL_PKTS; - event_hdr->length = sizeof(hci_num_compl_pkts_ep); - event->num_con_handles = 0; + event_hdr->event = HCI_EVENT_NUM_COMPL_PKTS; + event_hdr->length = sizeof(hci_num_compl_pkts_ep); + event->num_con_handles = 0; - u32 acc = 0; + u32 acc = 0; - for (unsigned int i = 0; i < m_WiiMotes.size(); i++) - { - event_hdr->length += sizeof(hci_num_compl_pkts_info); - event->num_con_handles++; - info->compl_pkts = m_PacketCount[i]; - info->con_handle = m_WiiMotes[i].GetConnectionHandle(); + for (unsigned int i = 0; i < m_WiiMotes.size(); i++) + { + event_hdr->length += sizeof(hci_num_compl_pkts_info); + event->num_con_handles++; + info->compl_pkts = m_PacketCount[i]; + info->con_handle = m_WiiMotes[i].GetConnectionHandle(); - DEBUG_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", info->con_handle); - DEBUG_LOG(WII_IPC_WIIMOTE, " Number_Of_Completed_Packets: %i", info->compl_pkts); + DEBUG_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", info->con_handle); + DEBUG_LOG(WII_IPC_WIIMOTE, " Number_Of_Completed_Packets: %i", info->compl_pkts); - acc += info->compl_pkts; - m_PacketCount[i] = 0; - info++; - } + acc += info->compl_pkts; + m_PacketCount[i] = 0; + info++; + } - if (acc) - { - AddEventToQueue(Event); - } - else - { - INFO_LOG(WII_IPC_WIIMOTE, "SendEventNumberOfCompletedPackets: no packets; no event"); - } + if (acc) + { + AddEventToQueue(Event); + } + else + { + INFO_LOG(WII_IPC_WIIMOTE, "SendEventNumberOfCompletedPackets: no packets; no event"); + } - return true; + return true; } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventModeChange(u16 _connectionHandle, u8 _mode, u16 _value) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventModeChange(u16 _connectionHandle, u8 _mode, + u16 _value) { - CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); - if (pWiiMote == nullptr) - return false; + CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); + if (pWiiMote == nullptr) + return false; - SQueuedEvent Event(sizeof(SHCIEventModeChange), _connectionHandle); + SQueuedEvent Event(sizeof(SHCIEventModeChange), _connectionHandle); - SHCIEventModeChange* pModeChange = (SHCIEventModeChange*)Event.m_buffer; - pModeChange->EventType = HCI_EVENT_MODE_CHANGE; - pModeChange->PayloadLength = sizeof(SHCIEventModeChange) - 2; - pModeChange->EventStatus = 0; - pModeChange->Connection_Handle = _connectionHandle; - pModeChange->CurrentMode = _mode; - pModeChange->Value = _value; + SHCIEventModeChange* pModeChange = (SHCIEventModeChange*)Event.m_buffer; + pModeChange->EventType = HCI_EVENT_MODE_CHANGE; + pModeChange->PayloadLength = sizeof(SHCIEventModeChange) - 2; + pModeChange->EventStatus = 0; + pModeChange->Connection_Handle = _connectionHandle; + pModeChange->CurrentMode = _mode; + pModeChange->Value = _value; - INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventModeChange"); - DEBUG_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", pModeChange->Connection_Handle); - DEBUG_LOG(WII_IPC_WIIMOTE, " Current Mode: 0x%02x", pModeChange->CurrentMode = _mode); + INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventModeChange"); + DEBUG_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", pModeChange->Connection_Handle); + DEBUG_LOG(WII_IPC_WIIMOTE, " Current Mode: 0x%02x", pModeChange->CurrentMode = _mode); - AddEventToQueue(Event); + AddEventToQueue(Event); - return true; + return true; } bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventLinkKeyNotification(const u8 num_to_send) { - u8 payload_length = sizeof(hci_return_link_keys_ep) + sizeof(hci_link_key_rep_cp) * num_to_send; - SQueuedEvent Event(2 + payload_length, 0); - SHCIEventLinkKeyNotification* pEventLinkKey = (SHCIEventLinkKeyNotification*)Event.m_buffer; + u8 payload_length = sizeof(hci_return_link_keys_ep) + sizeof(hci_link_key_rep_cp) * num_to_send; + SQueuedEvent Event(2 + payload_length, 0); + SHCIEventLinkKeyNotification* pEventLinkKey = (SHCIEventLinkKeyNotification*)Event.m_buffer; - INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventLinkKeyNotification"); + INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventLinkKeyNotification"); - // event header - pEventLinkKey->EventType = HCI_EVENT_RETURN_LINK_KEYS; - pEventLinkKey->PayloadLength = payload_length; - // this is really hci_return_link_keys_ep.num_keys - pEventLinkKey->numKeys = num_to_send; + // event header + pEventLinkKey->EventType = HCI_EVENT_RETURN_LINK_KEYS; + pEventLinkKey->PayloadLength = payload_length; + // this is really hci_return_link_keys_ep.num_keys + pEventLinkKey->numKeys = num_to_send; - // copy infos - this only works correctly if we're meant to start at first device and read all keys - for (int i = 0; i < num_to_send; i++) - { - hci_link_key_rep_cp* link_key_info - = (hci_link_key_rep_cp*)((u8*)&pEventLinkKey->bdaddr + sizeof(hci_link_key_rep_cp) * i); - link_key_info->bdaddr = m_WiiMotes[i].GetBD(); - memcpy(link_key_info->key, m_WiiMotes[i].GetLinkKey(), HCI_KEY_SIZE); + // copy infos - this only works correctly if we're meant to start at first device and read all + // keys + for (int i = 0; i < num_to_send; i++) + { + hci_link_key_rep_cp* link_key_info = + (hci_link_key_rep_cp*)((u8*)&pEventLinkKey->bdaddr + sizeof(hci_link_key_rep_cp) * i); + link_key_info->bdaddr = m_WiiMotes[i].GetBD(); + memcpy(link_key_info->key, m_WiiMotes[i].GetLinkKey(), HCI_KEY_SIZE); - DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", - link_key_info->bdaddr.b[0], link_key_info->bdaddr.b[1], link_key_info->bdaddr.b[2], - link_key_info->bdaddr.b[3], link_key_info->bdaddr.b[4], link_key_info->bdaddr.b[5]); - LOG_LinkKey(link_key_info->key); - } + DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", link_key_info->bdaddr.b[0], + link_key_info->bdaddr.b[1], link_key_info->bdaddr.b[2], link_key_info->bdaddr.b[3], + link_key_info->bdaddr.b[4], link_key_info->bdaddr.b[5]); + LOG_LinkKey(link_key_info->key); + } - AddEventToQueue(Event); + AddEventToQueue(Event); - return true; + return true; }; bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRequestLinkKey(const bdaddr_t& _bd) { - SQueuedEvent Event(sizeof(SHCIEventRequestLinkKey), 0); + SQueuedEvent Event(sizeof(SHCIEventRequestLinkKey), 0); - SHCIEventRequestLinkKey* pEventRequestLinkKey = (SHCIEventRequestLinkKey*)Event.m_buffer; + SHCIEventRequestLinkKey* pEventRequestLinkKey = (SHCIEventRequestLinkKey*)Event.m_buffer; - pEventRequestLinkKey->EventType = HCI_EVENT_LINK_KEY_REQ; - pEventRequestLinkKey->PayloadLength = sizeof(SHCIEventRequestLinkKey) - 2; - pEventRequestLinkKey->bdaddr = _bd; + pEventRequestLinkKey->EventType = HCI_EVENT_LINK_KEY_REQ; + pEventRequestLinkKey->PayloadLength = sizeof(SHCIEventRequestLinkKey) - 2; + pEventRequestLinkKey->bdaddr = _bd; - INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventRequestLinkKey"); - DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", - pEventRequestLinkKey->bdaddr.b[0], pEventRequestLinkKey->bdaddr.b[1], pEventRequestLinkKey->bdaddr.b[2], - pEventRequestLinkKey->bdaddr.b[3], pEventRequestLinkKey->bdaddr.b[4], pEventRequestLinkKey->bdaddr.b[5]); + INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventRequestLinkKey"); + DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", + pEventRequestLinkKey->bdaddr.b[0], pEventRequestLinkKey->bdaddr.b[1], + pEventRequestLinkKey->bdaddr.b[2], pEventRequestLinkKey->bdaddr.b[3], + pEventRequestLinkKey->bdaddr.b[4], pEventRequestLinkKey->bdaddr.b[5]); - AddEventToQueue(Event); + AddEventToQueue(Event); - return true; + return true; }; bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventReadClockOffsetComplete(u16 _connectionHandle) { - CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); - if (pWiiMote == nullptr) - return false; + CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); + if (pWiiMote == nullptr) + return false; - SQueuedEvent Event(sizeof(SHCIEventReadClockOffsetComplete), _connectionHandle); + SQueuedEvent Event(sizeof(SHCIEventReadClockOffsetComplete), _connectionHandle); - SHCIEventReadClockOffsetComplete* pReadClockOffsetComplete = (SHCIEventReadClockOffsetComplete*)Event.m_buffer; - pReadClockOffsetComplete->EventType = HCI_EVENT_READ_CLOCK_OFFSET_COMPL; - pReadClockOffsetComplete->PayloadLength = sizeof(SHCIEventReadClockOffsetComplete) - 2; - pReadClockOffsetComplete->EventStatus = 0x00; - pReadClockOffsetComplete->ConnectionHandle = _connectionHandle; - pReadClockOffsetComplete->ClockOffset = 0x3818; + SHCIEventReadClockOffsetComplete* pReadClockOffsetComplete = + (SHCIEventReadClockOffsetComplete*)Event.m_buffer; + pReadClockOffsetComplete->EventType = HCI_EVENT_READ_CLOCK_OFFSET_COMPL; + pReadClockOffsetComplete->PayloadLength = sizeof(SHCIEventReadClockOffsetComplete) - 2; + pReadClockOffsetComplete->EventStatus = 0x00; + pReadClockOffsetComplete->ConnectionHandle = _connectionHandle; + pReadClockOffsetComplete->ClockOffset = 0x3818; - INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventReadClockOffsetComplete"); - DEBUG_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", pReadClockOffsetComplete->ConnectionHandle); - DEBUG_LOG(WII_IPC_WIIMOTE, " ClockOffset: 0x%04x", pReadClockOffsetComplete->ClockOffset); + INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventReadClockOffsetComplete"); + DEBUG_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", + pReadClockOffsetComplete->ConnectionHandle); + DEBUG_LOG(WII_IPC_WIIMOTE, " ClockOffset: 0x%04x", pReadClockOffsetComplete->ClockOffset); - AddEventToQueue(Event); + AddEventToQueue(Event); - return true; + return true; } -bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventConPacketTypeChange(u16 _connectionHandle, u16 _packetType) +bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventConPacketTypeChange(u16 _connectionHandle, + u16 _packetType) { - CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); - if (pWiiMote == nullptr) - return false; + CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_connectionHandle); + if (pWiiMote == nullptr) + return false; - SQueuedEvent Event(sizeof(SHCIEventConPacketTypeChange), _connectionHandle); + SQueuedEvent Event(sizeof(SHCIEventConPacketTypeChange), _connectionHandle); - SHCIEventConPacketTypeChange* pChangeConPacketType = (SHCIEventConPacketTypeChange*)Event.m_buffer; - pChangeConPacketType->EventType = HCI_EVENT_CON_PKT_TYPE_CHANGED; - pChangeConPacketType->PayloadLength = sizeof(SHCIEventConPacketTypeChange) - 2; - pChangeConPacketType->EventStatus = 0x00; - pChangeConPacketType->ConnectionHandle = _connectionHandle; - pChangeConPacketType->PacketType = _packetType; + SHCIEventConPacketTypeChange* pChangeConPacketType = + (SHCIEventConPacketTypeChange*)Event.m_buffer; + pChangeConPacketType->EventType = HCI_EVENT_CON_PKT_TYPE_CHANGED; + pChangeConPacketType->PayloadLength = sizeof(SHCIEventConPacketTypeChange) - 2; + pChangeConPacketType->EventStatus = 0x00; + pChangeConPacketType->ConnectionHandle = _connectionHandle; + pChangeConPacketType->PacketType = _packetType; - INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventConPacketTypeChange"); - DEBUG_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", pChangeConPacketType->ConnectionHandle); - DEBUG_LOG(WII_IPC_WIIMOTE, " PacketType: 0x%04x", pChangeConPacketType->PacketType); + INFO_LOG(WII_IPC_WIIMOTE, "Event: SendEventConPacketTypeChange"); + DEBUG_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", pChangeConPacketType->ConnectionHandle); + DEBUG_LOG(WII_IPC_WIIMOTE, " PacketType: 0x%04x", pChangeConPacketType->PacketType); - AddEventToQueue(Event); + AddEventToQueue(Event); - return true; + return true; } - // Command dispatcher // This is called from the USBV0_IOCTL_CTRLMSG Ioctlv -void CWII_IPC_HLE_Device_usb_oh1_57e_305::ExecuteHCICommandMessage(const SHCICommandMessage& _rHCICommandMessage) +void CWII_IPC_HLE_Device_usb_oh1_57e_305::ExecuteHCICommandMessage( + const SHCICommandMessage& _rHCICommandMessage) { - u8* pInput = Memory::GetPointer(_rHCICommandMessage.m_PayLoadAddr + 3); - SCommandMessage* pMsg = (SCommandMessage*)Memory::GetPointer(_rHCICommandMessage.m_PayLoadAddr); + u8* pInput = Memory::GetPointer(_rHCICommandMessage.m_PayLoadAddr + 3); + SCommandMessage* pMsg = (SCommandMessage*)Memory::GetPointer(_rHCICommandMessage.m_PayLoadAddr); - u16 ocf = HCI_OCF(pMsg->Opcode); - u16 ogf = HCI_OGF(pMsg->Opcode); + u16 ocf = HCI_OCF(pMsg->Opcode); + u16 ogf = HCI_OGF(pMsg->Opcode); - INFO_LOG(WII_IPC_WIIMOTE, "**************************************************"); - INFO_LOG(WII_IPC_WIIMOTE, "Execute HCI Command: 0x%04x (ocf: 0x%02x, ogf: 0x%02x)", pMsg->Opcode, ocf, ogf); + INFO_LOG(WII_IPC_WIIMOTE, "**************************************************"); + INFO_LOG(WII_IPC_WIIMOTE, "Execute HCI Command: 0x%04x (ocf: 0x%02x, ogf: 0x%02x)", pMsg->Opcode, + ocf, ogf); - switch (pMsg->Opcode) - { - // - // --- read commands --- - // - case HCI_CMD_RESET: - CommandReset(pInput); - break; + switch (pMsg->Opcode) + { + // + // --- read commands --- + // + case HCI_CMD_RESET: + CommandReset(pInput); + break; - case HCI_CMD_READ_BUFFER_SIZE: - CommandReadBufferSize(pInput); - break; + case HCI_CMD_READ_BUFFER_SIZE: + CommandReadBufferSize(pInput); + break; - case HCI_CMD_READ_LOCAL_VER: - CommandReadLocalVer(pInput); - break; + case HCI_CMD_READ_LOCAL_VER: + CommandReadLocalVer(pInput); + break; - case HCI_CMD_READ_BDADDR: - CommandReadBDAdrr(pInput); - break; + case HCI_CMD_READ_BDADDR: + CommandReadBDAdrr(pInput); + break; - case HCI_CMD_READ_LOCAL_FEATURES: - CommandReadLocalFeatures(pInput); - break; + case HCI_CMD_READ_LOCAL_FEATURES: + CommandReadLocalFeatures(pInput); + break; - case HCI_CMD_READ_STORED_LINK_KEY: - CommandReadStoredLinkKey(pInput); - break; + case HCI_CMD_READ_STORED_LINK_KEY: + CommandReadStoredLinkKey(pInput); + break; - case HCI_CMD_WRITE_UNIT_CLASS: - CommandWriteUnitClass(pInput); - break; + case HCI_CMD_WRITE_UNIT_CLASS: + CommandWriteUnitClass(pInput); + break; - case HCI_CMD_WRITE_LOCAL_NAME: - CommandWriteLocalName(pInput); - break; + case HCI_CMD_WRITE_LOCAL_NAME: + CommandWriteLocalName(pInput); + break; - case HCI_CMD_WRITE_PIN_TYPE: - CommandWritePinType(pInput); - break; + case HCI_CMD_WRITE_PIN_TYPE: + CommandWritePinType(pInput); + break; - case HCI_CMD_HOST_BUFFER_SIZE: - CommandHostBufferSize(pInput); - break; + case HCI_CMD_HOST_BUFFER_SIZE: + CommandHostBufferSize(pInput); + break; - case HCI_CMD_WRITE_PAGE_TIMEOUT: - CommandWritePageTimeOut(pInput); - break; + case HCI_CMD_WRITE_PAGE_TIMEOUT: + CommandWritePageTimeOut(pInput); + break; - case HCI_CMD_WRITE_SCAN_ENABLE: - CommandWriteScanEnable(pInput); - break; + case HCI_CMD_WRITE_SCAN_ENABLE: + CommandWriteScanEnable(pInput); + break; - case HCI_CMD_WRITE_INQUIRY_MODE: - CommandWriteInquiryMode(pInput); - break; + case HCI_CMD_WRITE_INQUIRY_MODE: + CommandWriteInquiryMode(pInput); + break; - case HCI_CMD_WRITE_PAGE_SCAN_TYPE: - CommandWritePageScanType(pInput); - break; + case HCI_CMD_WRITE_PAGE_SCAN_TYPE: + CommandWritePageScanType(pInput); + break; - case HCI_CMD_SET_EVENT_FILTER: - CommandSetEventFilter(pInput); - break; + case HCI_CMD_SET_EVENT_FILTER: + CommandSetEventFilter(pInput); + break; - case HCI_CMD_INQUIRY: - CommandInquiry(pInput); - break; + case HCI_CMD_INQUIRY: + CommandInquiry(pInput); + break; - case HCI_CMD_WRITE_INQUIRY_SCAN_TYPE: - CommandWriteInquiryScanType(pInput); - break; + case HCI_CMD_WRITE_INQUIRY_SCAN_TYPE: + CommandWriteInquiryScanType(pInput); + break; - // vendor specific... - case 0xFC4C: - CommandVendorSpecific_FC4C(pInput, _rHCICommandMessage.m_PayLoadSize - 3); - break; + // vendor specific... + case 0xFC4C: + CommandVendorSpecific_FC4C(pInput, _rHCICommandMessage.m_PayLoadSize - 3); + break; - case 0xFC4F: - CommandVendorSpecific_FC4F(pInput, _rHCICommandMessage.m_PayLoadSize - 3); - break; + case 0xFC4F: + CommandVendorSpecific_FC4F(pInput, _rHCICommandMessage.m_PayLoadSize - 3); + break; - case HCI_CMD_INQUIRY_CANCEL: - CommandInquiryCancel(pInput); - break; + case HCI_CMD_INQUIRY_CANCEL: + CommandInquiryCancel(pInput); + break; - case HCI_CMD_REMOTE_NAME_REQ: - CommandRemoteNameReq(pInput); - break; + case HCI_CMD_REMOTE_NAME_REQ: + CommandRemoteNameReq(pInput); + break; - case HCI_CMD_CREATE_CON: - CommandCreateCon(pInput); - break; + case HCI_CMD_CREATE_CON: + CommandCreateCon(pInput); + break; - case HCI_CMD_ACCEPT_CON: - CommandAcceptCon(pInput); - break; + case HCI_CMD_ACCEPT_CON: + CommandAcceptCon(pInput); + break; - case HCI_CMD_CHANGE_CON_PACKET_TYPE: - CommandChangeConPacketType(pInput); - break; + case HCI_CMD_CHANGE_CON_PACKET_TYPE: + CommandChangeConPacketType(pInput); + break; - case HCI_CMD_READ_CLOCK_OFFSET: - CommandReadClockOffset(pInput); - break; + case HCI_CMD_READ_CLOCK_OFFSET: + CommandReadClockOffset(pInput); + break; - case HCI_CMD_READ_REMOTE_VER_INFO: - CommandReadRemoteVerInfo(pInput); - break; + case HCI_CMD_READ_REMOTE_VER_INFO: + CommandReadRemoteVerInfo(pInput); + break; - case HCI_CMD_READ_REMOTE_FEATURES: - CommandReadRemoteFeatures(pInput); - break; + case HCI_CMD_READ_REMOTE_FEATURES: + CommandReadRemoteFeatures(pInput); + break; - case HCI_CMD_WRITE_LINK_POLICY_SETTINGS: - CommandWriteLinkPolicy(pInput); - break; + case HCI_CMD_WRITE_LINK_POLICY_SETTINGS: + CommandWriteLinkPolicy(pInput); + break; - case HCI_CMD_AUTH_REQ: - CommandAuthenticationRequested(pInput); - break; + case HCI_CMD_AUTH_REQ: + CommandAuthenticationRequested(pInput); + break; - case HCI_CMD_SNIFF_MODE: - CommandSniffMode(pInput); - break; + case HCI_CMD_SNIFF_MODE: + CommandSniffMode(pInput); + break; - case HCI_CMD_DISCONNECT: - CommandDisconnect(pInput); - break; + case HCI_CMD_DISCONNECT: + CommandDisconnect(pInput); + break; - case HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT: - CommandWriteLinkSupervisionTimeout(pInput); - break; + case HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT: + CommandWriteLinkSupervisionTimeout(pInput); + break; - case HCI_CMD_LINK_KEY_NEG_REP: - CommandLinkKeyNegRep(pInput); - break; + case HCI_CMD_LINK_KEY_NEG_REP: + CommandLinkKeyNegRep(pInput); + break; - case HCI_CMD_LINK_KEY_REP: - CommandLinkKeyRep(pInput); - break; + case HCI_CMD_LINK_KEY_REP: + CommandLinkKeyRep(pInput); + break; - case HCI_CMD_DELETE_STORED_LINK_KEY: - CommandDeleteStoredLinkKey(pInput); - break; + case HCI_CMD_DELETE_STORED_LINK_KEY: + CommandDeleteStoredLinkKey(pInput); + break; - default: - // send fake okay msg... - SendEventCommandComplete(pMsg->Opcode, nullptr, 0); + default: + // send fake okay msg... + SendEventCommandComplete(pMsg->Opcode, nullptr, 0); - if (ogf == HCI_OGF_VENDOR) - { - ERROR_LOG(WII_IPC_WIIMOTE, "Command: vendor specific: 0x%04X (ocf: 0x%x)", pMsg->Opcode, ocf); - for (int i = 0; i < pMsg->len; i++) - { - ERROR_LOG(WII_IPC_WIIMOTE, " 0x02%x", pInput[i]); - } - } - else - { - _dbg_assert_msg_(WII_IPC_WIIMOTE, 0, - "Unknown USB_IOCTL_CTRLMSG: 0x%04X (ocf: 0x%x ogf 0x%x)", pMsg->Opcode, ocf, ogf); - } - break; - } + if (ogf == HCI_OGF_VENDOR) + { + ERROR_LOG(WII_IPC_WIIMOTE, "Command: vendor specific: 0x%04X (ocf: 0x%x)", pMsg->Opcode, ocf); + for (int i = 0; i < pMsg->len; i++) + { + ERROR_LOG(WII_IPC_WIIMOTE, " 0x02%x", pInput[i]); + } + } + else + { + _dbg_assert_msg_(WII_IPC_WIIMOTE, 0, + "Unknown USB_IOCTL_CTRLMSG: 0x%04X (ocf: 0x%x ogf 0x%x)", pMsg->Opcode, ocf, + ogf); + } + break; + } - // HCI command is finished, send a reply to command - EnqueueReply(_rHCICommandMessage.m_Address); + // HCI command is finished, send a reply to command + EnqueueReply(_rHCICommandMessage.m_Address); } - // // // --- command helper @@ -1252,588 +1280,609 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::ExecuteHCICommandMessage(const SHCICom // void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandInquiry(const u8* input) { - // Inquiry should not be called normally - const hci_inquiry_cp* inquiry = reinterpret_cast(input); + // Inquiry should not be called normally + const hci_inquiry_cp* inquiry = reinterpret_cast(input); - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_INQUIRY:"); - DEBUG_LOG(WII_IPC_WIIMOTE, "write:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " LAP[0]: 0x%02x", inquiry->lap[0]); - DEBUG_LOG(WII_IPC_WIIMOTE, " LAP[1]: 0x%02x", inquiry->lap[1]); - DEBUG_LOG(WII_IPC_WIIMOTE, " LAP[2]: 0x%02x", inquiry->lap[2]); - DEBUG_LOG(WII_IPC_WIIMOTE, " inquiry_length: %i (N x 1.28) sec", inquiry->inquiry_length); - DEBUG_LOG(WII_IPC_WIIMOTE, " num_responses: %i (N x 1.28) sec", inquiry->num_responses); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_INQUIRY:"); + DEBUG_LOG(WII_IPC_WIIMOTE, "write:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " LAP[0]: 0x%02x", inquiry->lap[0]); + DEBUG_LOG(WII_IPC_WIIMOTE, " LAP[1]: 0x%02x", inquiry->lap[1]); + DEBUG_LOG(WII_IPC_WIIMOTE, " LAP[2]: 0x%02x", inquiry->lap[2]); + DEBUG_LOG(WII_IPC_WIIMOTE, " inquiry_length: %i (N x 1.28) sec", inquiry->inquiry_length); + DEBUG_LOG(WII_IPC_WIIMOTE, " num_responses: %i (N x 1.28) sec", inquiry->num_responses); - SendEventCommandStatus(HCI_CMD_INQUIRY); - SendEventInquiryResponse(); - SendEventInquiryComplete(); + SendEventCommandStatus(HCI_CMD_INQUIRY); + SendEventInquiryResponse(); + SendEventInquiryComplete(); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandInquiryCancel(const u8* input) { - hci_inquiry_cancel_rp reply; - reply.status = 0x00; + hci_inquiry_cancel_rp reply; + reply.status = 0x00; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_INQUIRY_CANCEL"); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_INQUIRY_CANCEL"); - SendEventCommandComplete(HCI_CMD_INQUIRY_CANCEL, &reply, sizeof(hci_inquiry_cancel_rp)); + SendEventCommandComplete(HCI_CMD_INQUIRY_CANCEL, &reply, sizeof(hci_inquiry_cancel_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandCreateCon(const u8* input) { - const hci_create_con_cp* create_connection = reinterpret_cast(input); + const hci_create_con_cp* create_connection = reinterpret_cast(input); - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_CREATE_CON"); - DEBUG_LOG(WII_IPC_WIIMOTE, "Input:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", - create_connection->bdaddr.b[0], create_connection->bdaddr.b[1], create_connection->bdaddr.b[2], - create_connection->bdaddr.b[3], create_connection->bdaddr.b[4], create_connection->bdaddr.b[5]); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_CREATE_CON"); + DEBUG_LOG(WII_IPC_WIIMOTE, "Input:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", create_connection->bdaddr.b[0], + create_connection->bdaddr.b[1], create_connection->bdaddr.b[2], + create_connection->bdaddr.b[3], create_connection->bdaddr.b[4], + create_connection->bdaddr.b[5]); - DEBUG_LOG(WII_IPC_WIIMOTE, " pkt_type: %i", create_connection->pkt_type); - DEBUG_LOG(WII_IPC_WIIMOTE, " page_scan_rep_mode: %i", create_connection->page_scan_rep_mode); - DEBUG_LOG(WII_IPC_WIIMOTE, " page_scan_mode: %i", create_connection->page_scan_mode); - DEBUG_LOG(WII_IPC_WIIMOTE, " clock_offset: %i", create_connection->clock_offset); - DEBUG_LOG(WII_IPC_WIIMOTE, " accept_role_switch: %i", create_connection->accept_role_switch); + DEBUG_LOG(WII_IPC_WIIMOTE, " pkt_type: %i", create_connection->pkt_type); + DEBUG_LOG(WII_IPC_WIIMOTE, " page_scan_rep_mode: %i", create_connection->page_scan_rep_mode); + DEBUG_LOG(WII_IPC_WIIMOTE, " page_scan_mode: %i", create_connection->page_scan_mode); + DEBUG_LOG(WII_IPC_WIIMOTE, " clock_offset: %i", create_connection->clock_offset); + DEBUG_LOG(WII_IPC_WIIMOTE, " accept_role_switch: %i", create_connection->accept_role_switch); - SendEventCommandStatus(HCI_CMD_CREATE_CON); - SendEventConnectionComplete(create_connection->bdaddr); + SendEventCommandStatus(HCI_CMD_CREATE_CON); + SendEventConnectionComplete(create_connection->bdaddr); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandDisconnect(const u8* input) { - const hci_discon_cp* disconnect = reinterpret_cast(input); + const hci_discon_cp* disconnect = reinterpret_cast(input); - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_DISCONNECT"); - DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%04x", disconnect->con_handle); - DEBUG_LOG(WII_IPC_WIIMOTE, " Reason: 0x%02x", disconnect->reason); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_DISCONNECT"); + DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%04x", disconnect->con_handle); + DEBUG_LOG(WII_IPC_WIIMOTE, " Reason: 0x%02x", disconnect->reason); - Host_SetWiiMoteConnectionState(0); - DisplayDisconnectMessage((disconnect->con_handle & 0xFF) + 1, disconnect->reason); + Host_SetWiiMoteConnectionState(0); + DisplayDisconnectMessage((disconnect->con_handle & 0xFF) + 1, disconnect->reason); - SendEventCommandStatus(HCI_CMD_DISCONNECT); - SendEventDisconnect(disconnect->con_handle, disconnect->reason); + SendEventCommandStatus(HCI_CMD_DISCONNECT); + SendEventDisconnect(disconnect->con_handle, disconnect->reason); - CWII_IPC_HLE_WiiMote* wiimote = AccessWiiMote(disconnect->con_handle); - if (wiimote) - wiimote->EventDisconnect(); + CWII_IPC_HLE_WiiMote* wiimote = AccessWiiMote(disconnect->con_handle); + if (wiimote) + wiimote->EventDisconnect(); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandAcceptCon(const u8* input) { - const hci_accept_con_cp* accept_connection = reinterpret_cast(input); + const hci_accept_con_cp* accept_connection = reinterpret_cast(input); - static char roles[][128] = - { - { "Master (0x00)"}, - { "Slave (0x01)"}, - }; + static char roles[][128] = { + {"Master (0x00)"}, {"Slave (0x01)"}, + }; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_ACCEPT_CON"); - DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", - accept_connection->bdaddr.b[0], accept_connection->bdaddr.b[1], accept_connection->bdaddr.b[2], - accept_connection->bdaddr.b[3], accept_connection->bdaddr.b[4], accept_connection->bdaddr.b[5]); - DEBUG_LOG(WII_IPC_WIIMOTE, " role: %s", roles[accept_connection->role]); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_ACCEPT_CON"); + DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", accept_connection->bdaddr.b[0], + accept_connection->bdaddr.b[1], accept_connection->bdaddr.b[2], + accept_connection->bdaddr.b[3], accept_connection->bdaddr.b[4], + accept_connection->bdaddr.b[5]); + DEBUG_LOG(WII_IPC_WIIMOTE, " role: %s", roles[accept_connection->role]); - SendEventCommandStatus(HCI_CMD_ACCEPT_CON); + SendEventCommandStatus(HCI_CMD_ACCEPT_CON); - // this connection wants to be the master - if (accept_connection->role == 0) - { - SendEventRoleChange(accept_connection->bdaddr, true); - } + // this connection wants to be the master + if (accept_connection->role == 0) + { + SendEventRoleChange(accept_connection->bdaddr, true); + } - SendEventConnectionComplete(accept_connection->bdaddr); + SendEventConnectionComplete(accept_connection->bdaddr); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandLinkKeyRep(const u8* input) { - const hci_link_key_rep_cp* key_rep = reinterpret_cast(input); + const hci_link_key_rep_cp* key_rep = reinterpret_cast(input); - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_LINK_KEY_REP"); - DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", - key_rep->bdaddr.b[0], key_rep->bdaddr.b[1], key_rep->bdaddr.b[2], - key_rep->bdaddr.b[3], key_rep->bdaddr.b[4], key_rep->bdaddr.b[5]); - LOG_LinkKey(key_rep->key); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_LINK_KEY_REP"); + DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", key_rep->bdaddr.b[0], + key_rep->bdaddr.b[1], key_rep->bdaddr.b[2], key_rep->bdaddr.b[3], key_rep->bdaddr.b[4], + key_rep->bdaddr.b[5]); + LOG_LinkKey(key_rep->key); + hci_link_key_rep_rp reply; + reply.status = 0x00; + reply.bdaddr = key_rep->bdaddr; - hci_link_key_rep_rp reply; - reply.status = 0x00; - reply.bdaddr = key_rep->bdaddr; - - SendEventCommandComplete(HCI_CMD_LINK_KEY_REP, &reply, sizeof(hci_link_key_rep_rp)); + SendEventCommandComplete(HCI_CMD_LINK_KEY_REP, &reply, sizeof(hci_link_key_rep_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandLinkKeyNegRep(const u8* input) { - const hci_link_key_neg_rep_cp* key_neg = reinterpret_cast(input); + const hci_link_key_neg_rep_cp* key_neg = reinterpret_cast(input); - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_LINK_KEY_NEG_REP"); - DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", - key_neg->bdaddr.b[0], key_neg->bdaddr.b[1], key_neg->bdaddr.b[2], - key_neg->bdaddr.b[3], key_neg->bdaddr.b[4], key_neg->bdaddr.b[5]); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_LINK_KEY_NEG_REP"); + DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", key_neg->bdaddr.b[0], + key_neg->bdaddr.b[1], key_neg->bdaddr.b[2], key_neg->bdaddr.b[3], key_neg->bdaddr.b[4], + key_neg->bdaddr.b[5]); - hci_link_key_neg_rep_rp reply; - reply.status = 0x00; - reply.bdaddr = key_neg->bdaddr; + hci_link_key_neg_rep_rp reply; + reply.status = 0x00; + reply.bdaddr = key_neg->bdaddr; - SendEventCommandComplete(HCI_CMD_LINK_KEY_NEG_REP, &reply, sizeof(hci_link_key_neg_rep_rp)); + SendEventCommandComplete(HCI_CMD_LINK_KEY_NEG_REP, &reply, sizeof(hci_link_key_neg_rep_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandChangeConPacketType(const u8* input) { - const hci_change_con_pkt_type_cp* change_packet_type = reinterpret_cast(input); + const hci_change_con_pkt_type_cp* change_packet_type = + reinterpret_cast(input); - // ntd stack sets packet type 0xcc18, which is HCI_PKT_DH5 | HCI_PKT_DM5 | HCI_PKT_DH1 | HCI_PKT_DM1 - // dunno what to do...run awayyyyyy! - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_CHANGE_CON_PACKET_TYPE"); - DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%04x", change_packet_type->con_handle); - DEBUG_LOG(WII_IPC_WIIMOTE, " PacketType: 0x%04x", change_packet_type->pkt_type); + // ntd stack sets packet type 0xcc18, which is HCI_PKT_DH5 | HCI_PKT_DM5 | HCI_PKT_DH1 | + // HCI_PKT_DM1 + // dunno what to do...run awayyyyyy! + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_CHANGE_CON_PACKET_TYPE"); + DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%04x", change_packet_type->con_handle); + DEBUG_LOG(WII_IPC_WIIMOTE, " PacketType: 0x%04x", change_packet_type->pkt_type); - SendEventCommandStatus(HCI_CMD_CHANGE_CON_PACKET_TYPE); - SendEventConPacketTypeChange(change_packet_type->con_handle, change_packet_type->pkt_type); + SendEventCommandStatus(HCI_CMD_CHANGE_CON_PACKET_TYPE); + SendEventConPacketTypeChange(change_packet_type->con_handle, change_packet_type->pkt_type); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandAuthenticationRequested(const u8* input) { - const hci_auth_req_cp* auth_req = reinterpret_cast(input); + const hci_auth_req_cp* auth_req = reinterpret_cast(input); - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_AUTH_REQ"); - DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%04x", auth_req->con_handle); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_AUTH_REQ"); + DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%04x", auth_req->con_handle); - SendEventCommandStatus(HCI_CMD_AUTH_REQ); - SendEventAuthenticationCompleted(auth_req->con_handle); + SendEventCommandStatus(HCI_CMD_AUTH_REQ); + SendEventAuthenticationCompleted(auth_req->con_handle); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandRemoteNameReq(const u8* input) { - const hci_remote_name_req_cp* remote_name_req = reinterpret_cast(input); + const hci_remote_name_req_cp* remote_name_req = + reinterpret_cast(input); - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_REMOTE_NAME_REQ"); - DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", - remote_name_req->bdaddr.b[0], remote_name_req->bdaddr.b[1], remote_name_req->bdaddr.b[2], - remote_name_req->bdaddr.b[3], remote_name_req->bdaddr.b[4], remote_name_req->bdaddr.b[5]); - DEBUG_LOG(WII_IPC_WIIMOTE, " page_scan_rep_mode: %i", remote_name_req->page_scan_rep_mode); - DEBUG_LOG(WII_IPC_WIIMOTE, " page_scan_mode: %i", remote_name_req->page_scan_mode); - DEBUG_LOG(WII_IPC_WIIMOTE, " clock_offset: %i", remote_name_req->clock_offset); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_REMOTE_NAME_REQ"); + DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", remote_name_req->bdaddr.b[0], + remote_name_req->bdaddr.b[1], remote_name_req->bdaddr.b[2], + remote_name_req->bdaddr.b[3], remote_name_req->bdaddr.b[4], + remote_name_req->bdaddr.b[5]); + DEBUG_LOG(WII_IPC_WIIMOTE, " page_scan_rep_mode: %i", remote_name_req->page_scan_rep_mode); + DEBUG_LOG(WII_IPC_WIIMOTE, " page_scan_mode: %i", remote_name_req->page_scan_mode); + DEBUG_LOG(WII_IPC_WIIMOTE, " clock_offset: %i", remote_name_req->clock_offset); - SendEventCommandStatus(HCI_CMD_REMOTE_NAME_REQ); - SendEventRemoteNameReq(remote_name_req->bdaddr); + SendEventCommandStatus(HCI_CMD_REMOTE_NAME_REQ); + SendEventRemoteNameReq(remote_name_req->bdaddr); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadRemoteFeatures(const u8* input) { - const hci_read_remote_features_cp* read_remote_features = reinterpret_cast(input); + const hci_read_remote_features_cp* read_remote_features = + reinterpret_cast(input); - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_REMOTE_FEATURES"); - DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%04x", read_remote_features->con_handle); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_REMOTE_FEATURES"); + DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%04x", read_remote_features->con_handle); - SendEventCommandStatus(HCI_CMD_READ_REMOTE_FEATURES); - SendEventReadRemoteFeatures(read_remote_features->con_handle); + SendEventCommandStatus(HCI_CMD_READ_REMOTE_FEATURES); + SendEventReadRemoteFeatures(read_remote_features->con_handle); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadRemoteVerInfo(const u8* input) { - const hci_read_remote_ver_info_cp* read_remote_ver_info = reinterpret_cast(input); + const hci_read_remote_ver_info_cp* read_remote_ver_info = + reinterpret_cast(input); - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_REMOTE_VER_INFO"); - DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%02x", read_remote_ver_info->con_handle); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_REMOTE_VER_INFO"); + DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%02x", read_remote_ver_info->con_handle); - SendEventCommandStatus(HCI_CMD_READ_REMOTE_VER_INFO); - SendEventReadRemoteVerInfo(read_remote_ver_info->con_handle); + SendEventCommandStatus(HCI_CMD_READ_REMOTE_VER_INFO); + SendEventReadRemoteVerInfo(read_remote_ver_info->con_handle); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadClockOffset(const u8* input) { - const hci_read_clock_offset_cp* read_clock_offset = reinterpret_cast(input); + const hci_read_clock_offset_cp* read_clock_offset = + reinterpret_cast(input); - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_CLOCK_OFFSET"); - DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%02x", read_clock_offset->con_handle); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_CLOCK_OFFSET"); + DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%02x", read_clock_offset->con_handle); - SendEventCommandStatus(HCI_CMD_READ_CLOCK_OFFSET); - SendEventReadClockOffsetComplete(read_clock_offset->con_handle); + SendEventCommandStatus(HCI_CMD_READ_CLOCK_OFFSET); + SendEventReadClockOffsetComplete(read_clock_offset->con_handle); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandSniffMode(const u8* input) { - const hci_sniff_mode_cp* sniff_mode = reinterpret_cast(input); + const hci_sniff_mode_cp* sniff_mode = reinterpret_cast(input); - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_SNIFF_MODE"); - INFO_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%04x", sniff_mode->con_handle); - DEBUG_LOG(WII_IPC_WIIMOTE, " max_interval: %f msec", sniff_mode->max_interval * .625); - DEBUG_LOG(WII_IPC_WIIMOTE, " min_interval: %f msec", sniff_mode->min_interval * .625); - DEBUG_LOG(WII_IPC_WIIMOTE, " attempt: %f msec", sniff_mode->attempt * 1.25); - DEBUG_LOG(WII_IPC_WIIMOTE, " timeout: %f msec", sniff_mode->timeout * 1.25); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_SNIFF_MODE"); + INFO_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%04x", sniff_mode->con_handle); + DEBUG_LOG(WII_IPC_WIIMOTE, " max_interval: %f msec", sniff_mode->max_interval * .625); + DEBUG_LOG(WII_IPC_WIIMOTE, " min_interval: %f msec", sniff_mode->min_interval * .625); + DEBUG_LOG(WII_IPC_WIIMOTE, " attempt: %f msec", sniff_mode->attempt * 1.25); + DEBUG_LOG(WII_IPC_WIIMOTE, " timeout: %f msec", sniff_mode->timeout * 1.25); - SendEventCommandStatus(HCI_CMD_SNIFF_MODE); - SendEventModeChange(sniff_mode->con_handle, 0x02, sniff_mode->max_interval); // 0x02 - sniff mode + SendEventCommandStatus(HCI_CMD_SNIFF_MODE); + SendEventModeChange(sniff_mode->con_handle, 0x02, sniff_mode->max_interval); // 0x02 - sniff mode } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteLinkPolicy(const u8* input) { - const hci_write_link_policy_settings_cp* link_policy = reinterpret_cast(input); + const hci_write_link_policy_settings_cp* link_policy = + reinterpret_cast(input); - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_LINK_POLICY_SETTINGS"); - DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%04x", link_policy->con_handle); - DEBUG_LOG(WII_IPC_WIIMOTE, " Policy: 0x%04x", link_policy->settings); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_LINK_POLICY_SETTINGS"); + DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%04x", link_policy->con_handle); + DEBUG_LOG(WII_IPC_WIIMOTE, " Policy: 0x%04x", link_policy->settings); - SendEventCommandStatus(HCI_CMD_WRITE_LINK_POLICY_SETTINGS); + SendEventCommandStatus(HCI_CMD_WRITE_LINK_POLICY_SETTINGS); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReset(const u8* input) { - hci_status_rp reply; - reply.status = 0x00; + hci_status_rp reply; + reply.status = 0x00; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_RESET"); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_RESET"); - SendEventCommandComplete(HCI_CMD_RESET, &reply, sizeof(hci_status_rp)); + SendEventCommandComplete(HCI_CMD_RESET, &reply, sizeof(hci_status_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandSetEventFilter(const u8* input) { - const hci_set_event_filter_cp* set_event_filter = reinterpret_cast(input); + const hci_set_event_filter_cp* set_event_filter = + reinterpret_cast(input); - hci_set_event_filter_rp reply; - reply.status = 0x00; + hci_set_event_filter_rp reply; + reply.status = 0x00; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_SET_EVENT_FILTER:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " filter_type: %i", set_event_filter->filter_type); - DEBUG_LOG(WII_IPC_WIIMOTE, " filter_condition_type: %i", set_event_filter->filter_condition_type); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_SET_EVENT_FILTER:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " filter_type: %i", set_event_filter->filter_type); + DEBUG_LOG(WII_IPC_WIIMOTE, " filter_condition_type: %i", + set_event_filter->filter_condition_type); - SendEventCommandComplete(HCI_CMD_SET_EVENT_FILTER, &reply, sizeof(hci_set_event_filter_rp)); + SendEventCommandComplete(HCI_CMD_SET_EVENT_FILTER, &reply, sizeof(hci_set_event_filter_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWritePinType(const u8* input) { - const hci_write_pin_type_cp* write_pin_type = reinterpret_cast(input); + const hci_write_pin_type_cp* write_pin_type = + reinterpret_cast(input); - hci_write_pin_type_rp reply; - reply.status = 0x00; + hci_write_pin_type_rp reply; + reply.status = 0x00; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_PIN_TYPE:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " pin_type: %x", write_pin_type->pin_type); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_PIN_TYPE:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " pin_type: %x", write_pin_type->pin_type); - SendEventCommandComplete(HCI_CMD_WRITE_PIN_TYPE, &reply, sizeof(hci_write_pin_type_rp)); + SendEventCommandComplete(HCI_CMD_WRITE_PIN_TYPE, &reply, sizeof(hci_write_pin_type_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadStoredLinkKey(const u8* input) { - const hci_read_stored_link_key_cp* read_stored_link_key = reinterpret_cast(input); + const hci_read_stored_link_key_cp* read_stored_link_key = + reinterpret_cast(input); - hci_read_stored_link_key_rp reply; - reply.status = 0x00; - reply.num_keys_read = 0; - reply.max_num_keys = 255; + hci_read_stored_link_key_rp reply; + reply.status = 0x00; + reply.num_keys_read = 0; + reply.max_num_keys = 255; - if (read_stored_link_key->read_all == 1) - { - reply.num_keys_read = (u16)m_WiiMotes.size(); - } - else - { - ERROR_LOG(WII_IPC_WIIMOTE, "CommandReadStoredLinkKey isn't looking for all devices"); - } + if (read_stored_link_key->read_all == 1) + { + reply.num_keys_read = (u16)m_WiiMotes.size(); + } + else + { + ERROR_LOG(WII_IPC_WIIMOTE, "CommandReadStoredLinkKey isn't looking for all devices"); + } - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_STORED_LINK_KEY:"); - DEBUG_LOG(WII_IPC_WIIMOTE, "input:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", - read_stored_link_key->bdaddr.b[0], read_stored_link_key->bdaddr.b[1], read_stored_link_key->bdaddr.b[2], - read_stored_link_key->bdaddr.b[3], read_stored_link_key->bdaddr.b[4], read_stored_link_key->bdaddr.b[5]); - DEBUG_LOG(WII_IPC_WIIMOTE, " read_all: %i", read_stored_link_key->read_all); - DEBUG_LOG(WII_IPC_WIIMOTE, "return:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " max_num_keys: %i", reply.max_num_keys); - DEBUG_LOG(WII_IPC_WIIMOTE, " num_keys_read: %i", reply.num_keys_read); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_STORED_LINK_KEY:"); + DEBUG_LOG(WII_IPC_WIIMOTE, "input:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", + read_stored_link_key->bdaddr.b[0], read_stored_link_key->bdaddr.b[1], + read_stored_link_key->bdaddr.b[2], read_stored_link_key->bdaddr.b[3], + read_stored_link_key->bdaddr.b[4], read_stored_link_key->bdaddr.b[5]); + DEBUG_LOG(WII_IPC_WIIMOTE, " read_all: %i", read_stored_link_key->read_all); + DEBUG_LOG(WII_IPC_WIIMOTE, "return:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " max_num_keys: %i", reply.max_num_keys); + DEBUG_LOG(WII_IPC_WIIMOTE, " num_keys_read: %i", reply.num_keys_read); - SendEventLinkKeyNotification((u8)reply.num_keys_read); - SendEventCommandComplete(HCI_CMD_READ_STORED_LINK_KEY, &reply, sizeof(hci_read_stored_link_key_rp)); + SendEventLinkKeyNotification((u8)reply.num_keys_read); + SendEventCommandComplete(HCI_CMD_READ_STORED_LINK_KEY, &reply, + sizeof(hci_read_stored_link_key_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandDeleteStoredLinkKey(const u8* input) { - const hci_delete_stored_link_key_cp* delete_stored_link_key = reinterpret_cast(input); + const hci_delete_stored_link_key_cp* delete_stored_link_key = + reinterpret_cast(input); - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_OCF_DELETE_STORED_LINK_KEY"); - DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", - delete_stored_link_key->bdaddr.b[0], delete_stored_link_key->bdaddr.b[1], delete_stored_link_key->bdaddr.b[2], - delete_stored_link_key->bdaddr.b[3], delete_stored_link_key->bdaddr.b[4], delete_stored_link_key->bdaddr.b[5]); - DEBUG_LOG(WII_IPC_WIIMOTE, " delete_all: 0x%01x", delete_stored_link_key->delete_all); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_OCF_DELETE_STORED_LINK_KEY"); + DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", + delete_stored_link_key->bdaddr.b[0], delete_stored_link_key->bdaddr.b[1], + delete_stored_link_key->bdaddr.b[2], delete_stored_link_key->bdaddr.b[3], + delete_stored_link_key->bdaddr.b[4], delete_stored_link_key->bdaddr.b[5]); + DEBUG_LOG(WII_IPC_WIIMOTE, " delete_all: 0x%01x", delete_stored_link_key->delete_all); + CWII_IPC_HLE_WiiMote* wiiMote = AccessWiiMote(delete_stored_link_key->bdaddr); + if (wiiMote == nullptr) + return; - CWII_IPC_HLE_WiiMote* wiiMote = AccessWiiMote(delete_stored_link_key->bdaddr); - if (wiiMote == nullptr) - return; + hci_delete_stored_link_key_rp reply; + reply.status = 0x00; + reply.num_keys_deleted = 0; - hci_delete_stored_link_key_rp reply; - reply.status = 0x00; - reply.num_keys_deleted = 0; + SendEventCommandComplete(HCI_CMD_DELETE_STORED_LINK_KEY, &reply, + sizeof(hci_delete_stored_link_key_rp)); - SendEventCommandComplete(HCI_CMD_DELETE_STORED_LINK_KEY, &reply, sizeof(hci_delete_stored_link_key_rp)); - - ERROR_LOG(WII_IPC_WIIMOTE, "HCI: CommandDeleteStoredLinkKey... Probably the security for linking has failed. Could be a problem with loading the SCONF"); + ERROR_LOG(WII_IPC_WIIMOTE, "HCI: CommandDeleteStoredLinkKey... Probably the security for linking " + "has failed. Could be a problem with loading the SCONF"); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteLocalName(const u8* input) { - const hci_write_local_name_cp* write_local_name = reinterpret_cast(input); + const hci_write_local_name_cp* write_local_name = + reinterpret_cast(input); - hci_write_local_name_rp reply; - reply.status = 0x00; + hci_write_local_name_rp reply; + reply.status = 0x00; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_LOCAL_NAME:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " local_name: %s", write_local_name->name); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_LOCAL_NAME:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " local_name: %s", write_local_name->name); - SendEventCommandComplete(HCI_CMD_WRITE_LOCAL_NAME, &reply, sizeof(hci_write_local_name_rp)); + SendEventCommandComplete(HCI_CMD_WRITE_LOCAL_NAME, &reply, sizeof(hci_write_local_name_rp)); } // Here we normally receive the timeout interval. // But not from homebrew games that use lwbt. Why not? void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWritePageTimeOut(const u8* input) { - const hci_write_page_timeout_cp* write_page_timeout = reinterpret_cast(input); + const hci_write_page_timeout_cp* write_page_timeout = + reinterpret_cast(input); - hci_host_buffer_size_rp reply; - reply.status = 0x00; + hci_host_buffer_size_rp reply; + reply.status = 0x00; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_PAGE_TIMEOUT:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " timeout: %i", write_page_timeout->timeout); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_PAGE_TIMEOUT:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " timeout: %i", write_page_timeout->timeout); - SendEventCommandComplete(HCI_CMD_WRITE_PAGE_TIMEOUT, &reply, sizeof(hci_host_buffer_size_rp)); + SendEventCommandComplete(HCI_CMD_WRITE_PAGE_TIMEOUT, &reply, sizeof(hci_host_buffer_size_rp)); } /* This will enable ScanEnable so that Update() can start the Wiimote. */ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteScanEnable(const u8* input) { - const hci_write_scan_enable_cp* write_scan_enable = reinterpret_cast(input); - m_ScanEnable = write_scan_enable->scan_enable; + const hci_write_scan_enable_cp* write_scan_enable = + reinterpret_cast(input); + m_ScanEnable = write_scan_enable->scan_enable; - hci_write_scan_enable_rp reply; - reply.status = 0x00; + hci_write_scan_enable_rp reply; + reply.status = 0x00; - static char scanning[][128] = - { - { "HCI_NO_SCAN_ENABLE"}, - { "HCI_INQUIRY_SCAN_ENABLE"}, - { "HCI_PAGE_SCAN_ENABLE"}, - { "HCI_INQUIRY_AND_PAGE_SCAN_ENABLE"}, - }; + static char scanning[][128] = { + {"HCI_NO_SCAN_ENABLE"}, + {"HCI_INQUIRY_SCAN_ENABLE"}, + {"HCI_PAGE_SCAN_ENABLE"}, + {"HCI_INQUIRY_AND_PAGE_SCAN_ENABLE"}, + }; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_SCAN_ENABLE: (0x%02x)", write_scan_enable->scan_enable); - DEBUG_LOG(WII_IPC_WIIMOTE, " scan_enable: %s", scanning[write_scan_enable->scan_enable]); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_SCAN_ENABLE: (0x%02x)", + write_scan_enable->scan_enable); + DEBUG_LOG(WII_IPC_WIIMOTE, " scan_enable: %s", scanning[write_scan_enable->scan_enable]); - SendEventCommandComplete(HCI_CMD_WRITE_SCAN_ENABLE, &reply, sizeof(hci_write_scan_enable_rp)); + SendEventCommandComplete(HCI_CMD_WRITE_SCAN_ENABLE, &reply, sizeof(hci_write_scan_enable_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteUnitClass(const u8* input) { - const hci_write_unit_class_cp* write_unit_class = reinterpret_cast(input); + const hci_write_unit_class_cp* write_unit_class = + reinterpret_cast(input); - hci_write_unit_class_rp reply; - reply.status = 0x00; + hci_write_unit_class_rp reply; + reply.status = 0x00; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_UNIT_CLASS:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " COD[0]: 0x%02x", write_unit_class->uclass[0]); - DEBUG_LOG(WII_IPC_WIIMOTE, " COD[1]: 0x%02x", write_unit_class->uclass[1]); - DEBUG_LOG(WII_IPC_WIIMOTE, " COD[2]: 0x%02x", write_unit_class->uclass[2]); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_UNIT_CLASS:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " COD[0]: 0x%02x", write_unit_class->uclass[0]); + DEBUG_LOG(WII_IPC_WIIMOTE, " COD[1]: 0x%02x", write_unit_class->uclass[1]); + DEBUG_LOG(WII_IPC_WIIMOTE, " COD[2]: 0x%02x", write_unit_class->uclass[2]); - SendEventCommandComplete(HCI_CMD_WRITE_UNIT_CLASS, &reply, sizeof(hci_write_unit_class_rp)); + SendEventCommandComplete(HCI_CMD_WRITE_UNIT_CLASS, &reply, sizeof(hci_write_unit_class_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandHostBufferSize(const u8* input) { - const hci_host_buffer_size_cp* host_buffer_size = reinterpret_cast(input); + const hci_host_buffer_size_cp* host_buffer_size = + reinterpret_cast(input); - hci_host_buffer_size_rp reply; - reply.status = 0x00; + hci_host_buffer_size_rp reply; + reply.status = 0x00; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_HOST_BUFFER_SIZE:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " max_acl_size: %i", host_buffer_size->max_acl_size); - DEBUG_LOG(WII_IPC_WIIMOTE, " max_sco_size: %i", host_buffer_size->max_sco_size); - DEBUG_LOG(WII_IPC_WIIMOTE, " num_acl_pkts: %i", host_buffer_size->num_acl_pkts); - DEBUG_LOG(WII_IPC_WIIMOTE, " num_sco_pkts: %i", host_buffer_size->num_sco_pkts); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_HOST_BUFFER_SIZE:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " max_acl_size: %i", host_buffer_size->max_acl_size); + DEBUG_LOG(WII_IPC_WIIMOTE, " max_sco_size: %i", host_buffer_size->max_sco_size); + DEBUG_LOG(WII_IPC_WIIMOTE, " num_acl_pkts: %i", host_buffer_size->num_acl_pkts); + DEBUG_LOG(WII_IPC_WIIMOTE, " num_sco_pkts: %i", host_buffer_size->num_sco_pkts); - SendEventCommandComplete(HCI_CMD_HOST_BUFFER_SIZE, &reply, sizeof(hci_host_buffer_size_rp)); + SendEventCommandComplete(HCI_CMD_HOST_BUFFER_SIZE, &reply, sizeof(hci_host_buffer_size_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteLinkSupervisionTimeout(const u8* input) { - const hci_write_link_supervision_timeout_cp* supervision = reinterpret_cast(input); + const hci_write_link_supervision_timeout_cp* supervision = + reinterpret_cast(input); - // timeout of 0 means timing out is disabled - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT"); - DEBUG_LOG(WII_IPC_WIIMOTE, " con_handle: 0x%04x", supervision->con_handle); - DEBUG_LOG(WII_IPC_WIIMOTE, " timeout: 0x%02x", supervision->timeout); + // timeout of 0 means timing out is disabled + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT"); + DEBUG_LOG(WII_IPC_WIIMOTE, " con_handle: 0x%04x", supervision->con_handle); + DEBUG_LOG(WII_IPC_WIIMOTE, " timeout: 0x%02x", supervision->timeout); - hci_write_link_supervision_timeout_rp reply; - reply.status = 0x00; - reply.con_handle = supervision->con_handle; + hci_write_link_supervision_timeout_rp reply; + reply.status = 0x00; + reply.con_handle = supervision->con_handle; - SendEventCommandComplete(HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT, &reply, sizeof(hci_write_link_supervision_timeout_rp)); + SendEventCommandComplete(HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT, &reply, + sizeof(hci_write_link_supervision_timeout_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteInquiryScanType(const u8* input) { - const hci_write_inquiry_scan_type_cp* set_event_filter = reinterpret_cast(input); + const hci_write_inquiry_scan_type_cp* set_event_filter = + reinterpret_cast(input); - hci_write_inquiry_scan_type_rp reply; - reply.status = 0x00; + hci_write_inquiry_scan_type_rp reply; + reply.status = 0x00; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_INQUIRY_SCAN_TYPE:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " type: %i", set_event_filter->type); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_INQUIRY_SCAN_TYPE:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " type: %i", set_event_filter->type); - SendEventCommandComplete(HCI_CMD_WRITE_INQUIRY_SCAN_TYPE, &reply, sizeof(hci_write_inquiry_scan_type_rp)); + SendEventCommandComplete(HCI_CMD_WRITE_INQUIRY_SCAN_TYPE, &reply, + sizeof(hci_write_inquiry_scan_type_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteInquiryMode(const u8* input) { - const hci_write_inquiry_mode_cp* inquiry_mode = reinterpret_cast(input); + const hci_write_inquiry_mode_cp* inquiry_mode = + reinterpret_cast(input); - hci_write_inquiry_mode_rp reply; - reply.status = 0x00; + hci_write_inquiry_mode_rp reply; + reply.status = 0x00; - static char inquiry_mode_tag[][128] = - { - { "Standard Inquiry Result event format (default)" }, - { "Inquiry Result format with RSSI" }, - { "Inquiry Result with RSSI format or Extended Inquiry Result format" } - }; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_INQUIRY_MODE:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " mode: %s", inquiry_mode_tag[inquiry_mode->mode]); + static char inquiry_mode_tag[][128] = { + {"Standard Inquiry Result event format (default)"}, + {"Inquiry Result format with RSSI"}, + {"Inquiry Result with RSSI format or Extended Inquiry Result format"}}; + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_INQUIRY_MODE:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " mode: %s", inquiry_mode_tag[inquiry_mode->mode]); - SendEventCommandComplete(HCI_CMD_WRITE_INQUIRY_MODE, &reply, sizeof(hci_write_inquiry_mode_rp)); + SendEventCommandComplete(HCI_CMD_WRITE_INQUIRY_MODE, &reply, sizeof(hci_write_inquiry_mode_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWritePageScanType(const u8* input) { - const hci_write_page_scan_type_cp* write_page_scan_type = reinterpret_cast(input); + const hci_write_page_scan_type_cp* write_page_scan_type = + reinterpret_cast(input); - hci_write_page_scan_type_rp reply; - reply.status = 0x00; + hci_write_page_scan_type_rp reply; + reply.status = 0x00; - static char page_scan_type[][128] = - { - { "Mandatory: Standard Scan (default)" }, - { "Optional: Interlaced Scan" } - }; + static char page_scan_type[][128] = {{"Mandatory: Standard Scan (default)"}, + {"Optional: Interlaced Scan"}}; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_PAGE_SCAN_TYPE:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " type: %s", page_scan_type[write_page_scan_type->type]); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_WRITE_PAGE_SCAN_TYPE:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " type: %s", page_scan_type[write_page_scan_type->type]); - SendEventCommandComplete(HCI_CMD_WRITE_PAGE_SCAN_TYPE, &reply, sizeof(hci_write_page_scan_type_rp)); + SendEventCommandComplete(HCI_CMD_WRITE_PAGE_SCAN_TYPE, &reply, + sizeof(hci_write_page_scan_type_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadLocalVer(const u8* input) { - hci_read_local_ver_rp reply; - reply.status = 0x00; - reply.hci_version = 0x03; // HCI version: 1.1 - reply.hci_revision = 0x40a7; // current revision (?) - reply.lmp_version = 0x03; // LMP version: 1.1 - reply.manufacturer = 0x000F; // manufacturer: reserved for tests - reply.lmp_subversion = 0x430e; // LMP subversion + hci_read_local_ver_rp reply; + reply.status = 0x00; + reply.hci_version = 0x03; // HCI version: 1.1 + reply.hci_revision = 0x40a7; // current revision (?) + reply.lmp_version = 0x03; // LMP version: 1.1 + reply.manufacturer = 0x000F; // manufacturer: reserved for tests + reply.lmp_subversion = 0x430e; // LMP subversion - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_LOCAL_VER:"); - DEBUG_LOG(WII_IPC_WIIMOTE, "return:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " status: %i", reply.status); - DEBUG_LOG(WII_IPC_WIIMOTE, " hci_revision: %i", reply.hci_revision); - DEBUG_LOG(WII_IPC_WIIMOTE, " lmp_version: %i", reply.lmp_version); - DEBUG_LOG(WII_IPC_WIIMOTE, " manufacturer: %i", reply.manufacturer); - DEBUG_LOG(WII_IPC_WIIMOTE, " lmp_subversion: %i", reply.lmp_subversion); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_LOCAL_VER:"); + DEBUG_LOG(WII_IPC_WIIMOTE, "return:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " status: %i", reply.status); + DEBUG_LOG(WII_IPC_WIIMOTE, " hci_revision: %i", reply.hci_revision); + DEBUG_LOG(WII_IPC_WIIMOTE, " lmp_version: %i", reply.lmp_version); + DEBUG_LOG(WII_IPC_WIIMOTE, " manufacturer: %i", reply.manufacturer); + DEBUG_LOG(WII_IPC_WIIMOTE, " lmp_subversion: %i", reply.lmp_subversion); - SendEventCommandComplete(HCI_CMD_READ_LOCAL_VER, &reply, sizeof(hci_read_local_ver_rp)); + SendEventCommandComplete(HCI_CMD_READ_LOCAL_VER, &reply, sizeof(hci_read_local_ver_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadLocalFeatures(const u8* input) { - hci_read_local_features_rp reply; - reply.status = 0x00; - reply.features[0] = 0xFF; - reply.features[1] = 0xFF; - reply.features[2] = 0x8D; - reply.features[3] = 0xFE; - reply.features[4] = 0x9B; - reply.features[5] = 0xF9; - reply.features[6] = 0x00; - reply.features[7] = 0x80; + hci_read_local_features_rp reply; + reply.status = 0x00; + reply.features[0] = 0xFF; + reply.features[1] = 0xFF; + reply.features[2] = 0x8D; + reply.features[3] = 0xFE; + reply.features[4] = 0x9B; + reply.features[5] = 0xF9; + reply.features[6] = 0x00; + reply.features[7] = 0x80; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_LOCAL_FEATURES:"); - DEBUG_LOG(WII_IPC_WIIMOTE, "return:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " features: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", - reply.features[0], reply.features[1], reply.features[2], - reply.features[3], reply.features[4], reply.features[5], - reply.features[6], reply.features[7]); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_LOCAL_FEATURES:"); + DEBUG_LOG(WII_IPC_WIIMOTE, "return:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " features: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + reply.features[0], reply.features[1], reply.features[2], reply.features[3], + reply.features[4], reply.features[5], reply.features[6], reply.features[7]); - SendEventCommandComplete(HCI_CMD_READ_LOCAL_FEATURES, &reply, sizeof(hci_read_local_features_rp)); + SendEventCommandComplete(HCI_CMD_READ_LOCAL_FEATURES, &reply, sizeof(hci_read_local_features_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadBufferSize(const u8* input) { - hci_read_buffer_size_rp reply; - reply.status = 0x00; - reply.max_acl_size = m_acl_pkt_size; - // Due to how the widcomm stack which Nintendo uses is coded, we must never - // let the stack think the controller is buffering more than 10 data packets - // - it will cause a u8 underflow and royally screw things up. - reply.num_acl_pkts = m_acl_pkts_num; - reply.max_sco_size = 64; - reply.num_sco_pkts = 0; + hci_read_buffer_size_rp reply; + reply.status = 0x00; + reply.max_acl_size = m_acl_pkt_size; + // Due to how the widcomm stack which Nintendo uses is coded, we must never + // let the stack think the controller is buffering more than 10 data packets + // - it will cause a u8 underflow and royally screw things up. + reply.num_acl_pkts = m_acl_pkts_num; + reply.max_sco_size = 64; + reply.num_sco_pkts = 0; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_BUFFER_SIZE:"); - DEBUG_LOG(WII_IPC_WIIMOTE, "return:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " max_acl_size: %i", reply.max_acl_size); - DEBUG_LOG(WII_IPC_WIIMOTE, " num_acl_pkts: %i", reply.num_acl_pkts); - DEBUG_LOG(WII_IPC_WIIMOTE, " max_sco_size: %i", reply.max_sco_size); - DEBUG_LOG(WII_IPC_WIIMOTE, " num_sco_pkts: %i", reply.num_sco_pkts); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_BUFFER_SIZE:"); + DEBUG_LOG(WII_IPC_WIIMOTE, "return:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " max_acl_size: %i", reply.max_acl_size); + DEBUG_LOG(WII_IPC_WIIMOTE, " num_acl_pkts: %i", reply.num_acl_pkts); + DEBUG_LOG(WII_IPC_WIIMOTE, " max_sco_size: %i", reply.max_sco_size); + DEBUG_LOG(WII_IPC_WIIMOTE, " num_sco_pkts: %i", reply.num_sco_pkts); - SendEventCommandComplete(HCI_CMD_READ_BUFFER_SIZE, &reply, sizeof(hci_read_buffer_size_rp)); + SendEventCommandComplete(HCI_CMD_READ_BUFFER_SIZE, &reply, sizeof(hci_read_buffer_size_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadBDAdrr(const u8* input) { - hci_read_bdaddr_rp reply; - reply.status = 0x00; - reply.bdaddr = m_ControllerBD; + hci_read_bdaddr_rp reply; + reply.status = 0x00; + reply.bdaddr = m_ControllerBD; - INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_BDADDR:"); - DEBUG_LOG(WII_IPC_WIIMOTE, "return:"); - DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", - reply.bdaddr.b[0], reply.bdaddr.b[1], reply.bdaddr.b[2], - reply.bdaddr.b[3], reply.bdaddr.b[4], reply.bdaddr.b[5]); + INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_BDADDR:"); + DEBUG_LOG(WII_IPC_WIIMOTE, "return:"); + DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", reply.bdaddr.b[0], + reply.bdaddr.b[1], reply.bdaddr.b[2], reply.bdaddr.b[3], reply.bdaddr.b[4], + reply.bdaddr.b[5]); - SendEventCommandComplete(HCI_CMD_READ_BDADDR, &reply, sizeof(hci_read_bdaddr_rp)); + SendEventCommandComplete(HCI_CMD_READ_BDADDR, &reply, sizeof(hci_read_bdaddr_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandVendorSpecific_FC4F(const u8* input, u32 size) { - // callstack... - // BTM_VendorSpecificCommad() - // WUDiRemovePatch() - // WUDiAppendRuntimePatch() - // WUDiGetFirmwareVersion() - // WUDiStackSetupComplete() + // callstack... + // BTM_VendorSpecificCommad() + // WUDiRemovePatch() + // WUDiAppendRuntimePatch() + // WUDiGetFirmwareVersion() + // WUDiStackSetupComplete() - hci_status_rp reply; - reply.status = 0x00; + hci_status_rp reply; + reply.status = 0x00; - INFO_LOG(WII_IPC_WIIMOTE, "Command: CommandVendorSpecific_FC4F: (callstack WUDiRemovePatch)"); - INFO_LOG(WII_IPC_WIIMOTE, "Input (size 0x%x):", size); + INFO_LOG(WII_IPC_WIIMOTE, "Command: CommandVendorSpecific_FC4F: (callstack WUDiRemovePatch)"); + INFO_LOG(WII_IPC_WIIMOTE, "Input (size 0x%x):", size); - Dolphin_Debugger::PrintDataBuffer(LogTypes::WII_IPC_WIIMOTE, input, size, "Data: "); + Dolphin_Debugger::PrintDataBuffer(LogTypes::WII_IPC_WIIMOTE, input, size, "Data: "); - SendEventCommandComplete(0xFC4F, &reply, sizeof(hci_status_rp)); + SendEventCommandComplete(0xFC4F, &reply, sizeof(hci_status_rp)); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandVendorSpecific_FC4C(const u8* input, u32 size) { - hci_status_rp reply; - reply.status = 0x00; + hci_status_rp reply; + reply.status = 0x00; - INFO_LOG(WII_IPC_WIIMOTE, "Command: CommandVendorSpecific_FC4C:"); - INFO_LOG(WII_IPC_WIIMOTE, "Input (size 0x%x):", size); - Dolphin_Debugger::PrintDataBuffer(LogTypes::WII_IPC_WIIMOTE, input, size, "Data: "); + INFO_LOG(WII_IPC_WIIMOTE, "Command: CommandVendorSpecific_FC4C:"); + INFO_LOG(WII_IPC_WIIMOTE, "Input (size 0x%x):", size); + Dolphin_Debugger::PrintDataBuffer(LogTypes::WII_IPC_WIIMOTE, input, size, "Data: "); - SendEventCommandComplete(0xFC4C, &reply, sizeof(hci_status_rp)); + SendEventCommandComplete(0xFC4C, &reply, sizeof(hci_status_rp)); } - // // // --- helper @@ -1841,49 +1890,48 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandVendorSpecific_FC4C(const u8* i // CWII_IPC_HLE_WiiMote* CWII_IPC_HLE_Device_usb_oh1_57e_305::AccessWiiMote(const bdaddr_t& _rAddr) { - for (auto& wiimote : m_WiiMotes) - { - const bdaddr_t& BD = wiimote.GetBD(); - if ((_rAddr.b[0] == BD.b[0]) && - (_rAddr.b[1] == BD.b[1]) && - (_rAddr.b[2] == BD.b[2]) && - (_rAddr.b[3] == BD.b[3]) && - (_rAddr.b[4] == BD.b[4]) && - (_rAddr.b[5] == BD.b[5])) - return &wiimote; - } + for (auto& wiimote : m_WiiMotes) + { + const bdaddr_t& BD = wiimote.GetBD(); + if ((_rAddr.b[0] == BD.b[0]) && (_rAddr.b[1] == BD.b[1]) && (_rAddr.b[2] == BD.b[2]) && + (_rAddr.b[3] == BD.b[3]) && (_rAddr.b[4] == BD.b[4]) && (_rAddr.b[5] == BD.b[5])) + return &wiimote; + } - ERROR_LOG(WII_IPC_WIIMOTE,"Can't find WiiMote by bd: %02x:%02x:%02x:%02x:%02x:%02x", - _rAddr.b[0], _rAddr.b[1], _rAddr.b[2], _rAddr.b[3], _rAddr.b[4], _rAddr.b[5]); - return nullptr; + ERROR_LOG(WII_IPC_WIIMOTE, "Can't find WiiMote by bd: %02x:%02x:%02x:%02x:%02x:%02x", _rAddr.b[0], + _rAddr.b[1], _rAddr.b[2], _rAddr.b[3], _rAddr.b[4], _rAddr.b[5]); + return nullptr; } CWII_IPC_HLE_WiiMote* CWII_IPC_HLE_Device_usb_oh1_57e_305::AccessWiiMote(u16 _ConnectionHandle) { - for (auto& wiimote : m_WiiMotes) - { - if (wiimote.GetConnectionHandle() == _ConnectionHandle) - return &wiimote; - } + for (auto& wiimote : m_WiiMotes) + { + if (wiimote.GetConnectionHandle() == _ConnectionHandle) + return &wiimote; + } - ERROR_LOG(WII_IPC_WIIMOTE, "Can't find Wiimote by connection handle %02x", _ConnectionHandle); - PanicAlertT("Can't find Wiimote by connection handle %02x", _ConnectionHandle); - return nullptr; + ERROR_LOG(WII_IPC_WIIMOTE, "Can't find Wiimote by connection handle %02x", _ConnectionHandle); + PanicAlertT("Can't find Wiimote by connection handle %02x", _ConnectionHandle); + return nullptr; } -void CWII_IPC_HLE_Device_usb_oh1_57e_305::DisplayDisconnectMessage(const int wiimoteNumber, const int reason) +void CWII_IPC_HLE_Device_usb_oh1_57e_305::DisplayDisconnectMessage(const int wiimoteNumber, + const int reason) { - // TODO: If someone wants to be fancy we could also figure out what the values for pDiscon->reason mean - // and display things like "Wiimote %i disconnected due to inactivity!" etc. - Core::DisplayMessage(StringFromFormat("Wiimote %i disconnected by emulated software", wiimoteNumber), 3000); + // TODO: If someone wants to be fancy we could also figure out what the values for pDiscon->reason + // mean + // and display things like "Wiimote %i disconnected due to inactivity!" etc. + Core::DisplayMessage( + StringFromFormat("Wiimote %i disconnected by emulated software", wiimoteNumber), 3000); } void CWII_IPC_HLE_Device_usb_oh1_57e_305::LOG_LinkKey(const u8* _pLinkKey) { - DEBUG_LOG(WII_IPC_WIIMOTE, " link key: " - "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x " - "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x " - , _pLinkKey[0], _pLinkKey[1], _pLinkKey[2], _pLinkKey[3], _pLinkKey[4], _pLinkKey[5], _pLinkKey[6], _pLinkKey[7] - , _pLinkKey[8], _pLinkKey[9], _pLinkKey[10], _pLinkKey[11], _pLinkKey[12], _pLinkKey[13], _pLinkKey[14], _pLinkKey[15]); - + DEBUG_LOG(WII_IPC_WIIMOTE, " link key: " + "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x " + "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ", + _pLinkKey[0], _pLinkKey[1], _pLinkKey[2], _pLinkKey[3], _pLinkKey[4], _pLinkKey[5], + _pLinkKey[6], _pLinkKey[7], _pLinkKey[8], _pLinkKey[9], _pLinkKey[10], _pLinkKey[11], + _pLinkKey[12], _pLinkKey[13], _pLinkKey[14], _pLinkKey[15]); } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.h index d35190ee6e..3cdda8d61f 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb.h @@ -10,35 +10,29 @@ #include #include "Core/HW/Wiimote.h" -#include "Core/IPC_HLE/hci.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device.h" +#include "Core/IPC_HLE/hci.h" class CWII_IPC_HLE_WiiMote; struct SQueuedEvent { - u8 m_buffer[1024]; - u32 m_size; - u16 m_connectionHandle; + u8 m_buffer[1024]; + u32 m_size; + u16 m_connectionHandle; - SQueuedEvent(u32 size, u16 connectionHandle) - : m_size(size) - , m_connectionHandle(connectionHandle) - { - if (m_size > 1024) - { - // i know this code sux... - PanicAlert("SQueuedEvent: allocate too big buffer!!"); - } - memset(m_buffer, 0, 1024); - } + SQueuedEvent(u32 size, u16 connectionHandle) : m_size(size), m_connectionHandle(connectionHandle) + { + if (m_size > 1024) + { + // i know this code sux... + PanicAlert("SQueuedEvent: allocate too big buffer!!"); + } + memset(m_buffer, 0, 1024); + } - SQueuedEvent() - : m_size(0) - , m_connectionHandle(0) - { - } + SQueuedEvent() : m_size(0), m_connectionHandle(0) {} }; // Important to remember that this class is for /dev/usb/oh1/57e/305 ONLY @@ -48,244 +42,221 @@ struct SQueuedEvent class CWII_IPC_HLE_Device_usb_oh1_57e_305 : public IWII_IPC_HLE_Device { public: - CWII_IPC_HLE_Device_usb_oh1_57e_305(u32 _DeviceID, const std::string& _rDeviceName); + CWII_IPC_HLE_Device_usb_oh1_57e_305(u32 _DeviceID, const std::string& _rDeviceName); - virtual ~CWII_IPC_HLE_Device_usb_oh1_57e_305(); + virtual ~CWII_IPC_HLE_Device_usb_oh1_57e_305(); - IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; - IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; + IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; + IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; - IPCCommandResult IOCtlV(u32 _CommandAddress) override; - IPCCommandResult IOCtl(u32 _CommandAddress) override; + IPCCommandResult IOCtlV(u32 _CommandAddress) override; + IPCCommandResult IOCtl(u32 _CommandAddress) override; - u32 Update() override; + u32 Update() override; - static void EnqueueReply(u32 CommandAddress); + static void EnqueueReply(u32 CommandAddress); - // Send ACL data back to Bluetooth stack - void SendACLPacket(u16 connection_handle, const u8* data, u32 size); + // Send ACL data back to Bluetooth stack + void SendACLPacket(u16 connection_handle, const u8* data, u32 size); - bool RemoteDisconnect(u16 _connectionHandle); + bool RemoteDisconnect(u16 _connectionHandle); -// hack for Wiimote plugin + // hack for Wiimote plugin public: - std::vector m_WiiMotes; - CWII_IPC_HLE_WiiMote* AccessWiiMote(const bdaddr_t& _rAddr); - CWII_IPC_HLE_WiiMote* AccessWiiMote(u16 _ConnectionHandle); + std::vector m_WiiMotes; + CWII_IPC_HLE_WiiMote* AccessWiiMote(const bdaddr_t& _rAddr); + CWII_IPC_HLE_WiiMote* AccessWiiMote(u16 _ConnectionHandle); - void DoState(PointerWrap &p) override; + void DoState(PointerWrap& p) override; private: - enum USBIOCtl - { - USBV0_IOCTL_CTRLMSG = 0, - USBV0_IOCTL_BLKMSG = 1, - USBV0_IOCTL_INTRMSG = 2, - }; + enum USBIOCtl + { + USBV0_IOCTL_CTRLMSG = 0, + USBV0_IOCTL_BLKMSG = 1, + USBV0_IOCTL_INTRMSG = 2, + }; - enum USBEndpoint - { - HCI_CTRL = 0x00, - HCI_EVENT = 0x81, - ACL_DATA_IN = 0x82, - ACL_DATA_OUT = 0x02 - }; + enum USBEndpoint + { + HCI_CTRL = 0x00, + HCI_EVENT = 0x81, + ACL_DATA_IN = 0x82, + ACL_DATA_OUT = 0x02 + }; - struct SHCICommandMessage - { - u8 bRequestType; - u8 bRequest; - u16 wValue; - u16 wIndex; - u16 wLength; + struct SHCICommandMessage + { + u8 bRequestType; + u8 bRequest; + u16 wValue; + u16 wIndex; + u16 wLength; - u32 m_PayLoadAddr; - u32 m_PayLoadSize; - u32 m_Address; - }; + u32 m_PayLoadAddr; + u32 m_PayLoadSize; + u32 m_Address; + }; - // This is a lightweight/specialized version of SIOCtlVBuffer - struct CtrlBuffer - { - u32 m_address; - u32 m_buffer; + // This is a lightweight/specialized version of SIOCtlVBuffer + struct CtrlBuffer + { + u32 m_address; + u32 m_buffer; - CtrlBuffer(u32 _Address) : m_address(_Address), m_buffer() - { - if (m_address) - { - u32 InBufferNum = Memory::Read_U32(m_address + 0x10); - u32 BufferVector = Memory::Read_U32(m_address + 0x18); - m_buffer = Memory::Read_U32( - BufferVector + InBufferNum * sizeof(SIOCtlVBuffer::SBuffer)); - } - } + CtrlBuffer(u32 _Address) : m_address(_Address), m_buffer() + { + if (m_address) + { + u32 InBufferNum = Memory::Read_U32(m_address + 0x10); + u32 BufferVector = Memory::Read_U32(m_address + 0x18); + m_buffer = Memory::Read_U32(BufferVector + InBufferNum * sizeof(SIOCtlVBuffer::SBuffer)); + } + } - inline void FillBuffer(const void* src, const size_t size) const - { - Memory::CopyToEmu(m_buffer, (u8*)src, size); - } + inline void FillBuffer(const void* src, const size_t size) const + { + Memory::CopyToEmu(m_buffer, (u8*)src, size); + } - inline void SetRetVal(const u32 retval) const - { - Memory::Write_U32(retval, m_address + 4); - } + inline void SetRetVal(const u32 retval) const { Memory::Write_U32(retval, m_address + 4); } + inline bool IsValid() const { return m_address != 0; } + inline void Invalidate() { m_address = m_buffer = 0; } + }; - inline bool IsValid() const - { - return m_address != 0; - } + bdaddr_t m_ControllerBD; - inline void Invalidate() - { - m_address = m_buffer = 0; - } - }; + // this is used to trigger connecting via ACL + u8 m_ScanEnable; - bdaddr_t m_ControllerBD; + SHCICommandMessage m_CtrlSetup; + CtrlBuffer m_HCIEndpoint; + std::deque m_EventQueue; - // this is used to trigger connecting via ACL - u8 m_ScanEnable; + u32 m_ACLSetup; + CtrlBuffer m_ACLEndpoint; - SHCICommandMessage m_CtrlSetup; - CtrlBuffer m_HCIEndpoint; - std::deque m_EventQueue; + static const int m_acl_pkt_size = 339; + static const int m_acl_pkts_num = 10; - u32 m_ACLSetup; - CtrlBuffer m_ACLEndpoint; + class ACLPool + { + struct Packet + { + u8 data[m_acl_pkt_size]; + u16 size; + u16 conn_handle; + }; - static const int m_acl_pkt_size = 339; - static const int m_acl_pkts_num = 10; + std::deque m_queue; - class ACLPool - { - struct Packet - { - u8 data[m_acl_pkt_size]; - u16 size; - u16 conn_handle; - }; + public: + ACLPool() : m_queue() {} + void Store(const u8* data, const u16 size, const u16 conn_handle); - std::deque m_queue; + void WriteToEndpoint(CtrlBuffer& endpoint); - public: - ACLPool() - : m_queue() - {} + bool IsEmpty() const { return m_queue.empty(); } + // For SaveStates + void DoState(PointerWrap& p) { p.Do(m_queue); } + } m_acl_pool; - void Store(const u8* data, const u16 size, const u16 conn_handle); + u32 m_PacketCount[MAX_BBMOTES]; + u64 m_last_ticks; - void WriteToEndpoint(CtrlBuffer& endpoint); + // Send ACL data to a device (wiimote) + void IncDataPacket(u16 _ConnectionHandle); + void SendToDevice(u16 _ConnectionHandle, u8* _pData, u32 _Size); - bool IsEmpty() const - { - return m_queue.empty(); - } + // Events + void AddEventToQueue(const SQueuedEvent& _event); + bool SendEventCommandStatus(u16 _Opcode); + void SendEventCommandComplete(u16 opcode, const void* data, u32 data_size); + bool SendEventInquiryResponse(); + bool SendEventInquiryComplete(); + bool SendEventRemoteNameReq(const bdaddr_t& _bd); + bool SendEventRequestConnection(CWII_IPC_HLE_WiiMote& _rWiiMote); + bool SendEventConnectionComplete(const bdaddr_t& _bd); + bool SendEventReadClockOffsetComplete(u16 _connectionHandle); + bool SendEventConPacketTypeChange(u16 _connectionHandle, u16 _packetType); + bool SendEventReadRemoteVerInfo(u16 _connectionHandle); + bool SendEventReadRemoteFeatures(u16 _connectionHandle); + bool SendEventRoleChange(bdaddr_t _bd, bool _master); + bool SendEventNumberOfCompletedPackets(); + bool SendEventAuthenticationCompleted(u16 _connectionHandle); + bool SendEventModeChange(u16 _connectionHandle, u8 _mode, u16 _value); + bool SendEventDisconnect(u16 _connectionHandle, u8 _Reason); + bool SendEventRequestLinkKey(const bdaddr_t& _bd); + bool SendEventLinkKeyNotification(const u8 num_to_send); - // For SaveStates - void DoState(PointerWrap &p) - { - p.Do(m_queue); - } - } m_acl_pool; + // Execute HCI Message + void ExecuteHCICommandMessage(const SHCICommandMessage& _rCtrlMessage); - u32 m_PacketCount[MAX_BBMOTES]; - u64 m_last_ticks; + // OGF 0x01 - Link control commands and return parameters + void CommandWriteInquiryMode(const u8* input); + void CommandWritePageScanType(const u8* input); + void CommandHostBufferSize(const u8* input); + void CommandInquiryCancel(const u8* input); + void CommandRemoteNameReq(const u8* input); + void CommandCreateCon(const u8* input); + void CommandAcceptCon(const u8* input); + void CommandReadClockOffset(const u8* input); + void CommandReadRemoteVerInfo(const u8* input); + void CommandReadRemoteFeatures(const u8* input); + void CommandAuthenticationRequested(const u8* input); + void CommandInquiry(const u8* input); + void CommandDisconnect(const u8* input); + void CommandLinkKeyNegRep(const u8* input); + void CommandLinkKeyRep(const u8* input); + void CommandDeleteStoredLinkKey(const u8* input); + void CommandChangeConPacketType(const u8* input); - // Send ACL data to a device (wiimote) - void IncDataPacket(u16 _ConnectionHandle); - void SendToDevice(u16 _ConnectionHandle, u8* _pData, u32 _Size); + // OGF 0x02 - Link policy commands and return parameters + void CommandWriteLinkPolicy(const u8* input); + void CommandSniffMode(const u8* input); - // Events - void AddEventToQueue(const SQueuedEvent& _event); - bool SendEventCommandStatus(u16 _Opcode); - void SendEventCommandComplete(u16 opcode, const void* data, u32 data_size); - bool SendEventInquiryResponse(); - bool SendEventInquiryComplete(); - bool SendEventRemoteNameReq(const bdaddr_t& _bd); - bool SendEventRequestConnection(CWII_IPC_HLE_WiiMote& _rWiiMote); - bool SendEventConnectionComplete(const bdaddr_t& _bd); - bool SendEventReadClockOffsetComplete(u16 _connectionHandle); - bool SendEventConPacketTypeChange(u16 _connectionHandle, u16 _packetType); - bool SendEventReadRemoteVerInfo(u16 _connectionHandle); - bool SendEventReadRemoteFeatures(u16 _connectionHandle); - bool SendEventRoleChange(bdaddr_t _bd, bool _master); - bool SendEventNumberOfCompletedPackets(); - bool SendEventAuthenticationCompleted(u16 _connectionHandle); - bool SendEventModeChange(u16 _connectionHandle, u8 _mode, u16 _value); - bool SendEventDisconnect(u16 _connectionHandle, u8 _Reason); - bool SendEventRequestLinkKey(const bdaddr_t& _bd); - bool SendEventLinkKeyNotification(const u8 num_to_send); + // OGF 0x03 - Host Controller and Baseband commands and return parameters + void CommandReset(const u8* input); + void CommandWriteLocalName(const u8* input); + void CommandWritePageTimeOut(const u8* input); + void CommandWriteScanEnable(const u8* input); + void CommandWriteUnitClass(const u8* input); + void CommandReadStoredLinkKey(const u8* input); + void CommandWritePinType(const u8* input); + void CommandSetEventFilter(const u8* input); + void CommandWriteInquiryScanType(const u8* input); + void CommandWriteLinkSupervisionTimeout(const u8* input); - // Execute HCI Message - void ExecuteHCICommandMessage(const SHCICommandMessage& _rCtrlMessage); + // OGF 0x04 - Informational commands and return parameters + void CommandReadBufferSize(const u8* input); + void CommandReadLocalVer(const u8* input); + void CommandReadLocalFeatures(const u8* input); + void CommandReadBDAdrr(const u8* input); - // OGF 0x01 - Link control commands and return parameters - void CommandWriteInquiryMode(const u8* input); - void CommandWritePageScanType(const u8* input); - void CommandHostBufferSize(const u8* input); - void CommandInquiryCancel(const u8* input); - void CommandRemoteNameReq(const u8* input); - void CommandCreateCon(const u8* input); - void CommandAcceptCon(const u8* input); - void CommandReadClockOffset(const u8* input); - void CommandReadRemoteVerInfo(const u8* input); - void CommandReadRemoteFeatures(const u8* input); - void CommandAuthenticationRequested(const u8* input); - void CommandInquiry(const u8* input); - void CommandDisconnect(const u8* input); - void CommandLinkKeyNegRep(const u8* input); - void CommandLinkKeyRep(const u8* input); - void CommandDeleteStoredLinkKey(const u8* input); - void CommandChangeConPacketType(const u8* input); + // OGF 0x3F - Vendor specific + void CommandVendorSpecific_FC4C(const u8* input, u32 size); + void CommandVendorSpecific_FC4F(const u8* input, u32 size); - // OGF 0x02 - Link policy commands and return parameters - void CommandWriteLinkPolicy(const u8* input); - void CommandSniffMode(const u8* input); + static void DisplayDisconnectMessage(const int wiimoteNumber, const int reason); - // OGF 0x03 - Host Controller and Baseband commands and return parameters - void CommandReset(const u8* input); - void CommandWriteLocalName(const u8* input); - void CommandWritePageTimeOut(const u8* input); - void CommandWriteScanEnable(const u8* input); - void CommandWriteUnitClass(const u8* input); - void CommandReadStoredLinkKey(const u8* input); - void CommandWritePinType(const u8* input); - void CommandSetEventFilter(const u8* input); - void CommandWriteInquiryScanType(const u8* input); - void CommandWriteLinkSupervisionTimeout(const u8* input); + // Debugging + void LOG_LinkKey(const u8* _pLinkKey); - // OGF 0x04 - Informational commands and return parameters - void CommandReadBufferSize(const u8* input); - void CommandReadLocalVer(const u8* input); - void CommandReadLocalFeatures(const u8* input); - void CommandReadBDAdrr(const u8* input); - - // OGF 0x3F - Vendor specific - void CommandVendorSpecific_FC4C(const u8* input, u32 size); - void CommandVendorSpecific_FC4F(const u8* input, u32 size); - - static void DisplayDisconnectMessage(const int wiimoteNumber, const int reason); - - // Debugging - void LOG_LinkKey(const u8* _pLinkKey); - -#pragma pack(push,1) +#pragma pack(push, 1) #define CONF_PAD_MAX_REGISTERED 10 - struct _conf_pad_device - { - u8 bdaddr[6]; - char name[0x40]; - }; + struct _conf_pad_device + { + u8 bdaddr[6]; + char name[0x40]; + }; - struct _conf_pads - { - u8 num_registered; - _conf_pad_device registered[CONF_PAD_MAX_REGISTERED]; - _conf_pad_device active[MAX_BBMOTES]; - u8 unknown[0x45]; - }; + struct _conf_pads + { + u8 num_registered; + _conf_pad_device registered[CONF_PAD_MAX_REGISTERED]; + _conf_pad_device active[MAX_BBMOTES]; + u8 unknown[0x45]; + }; #pragma pack(pop) - }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp index d87fd51f07..1fea6575ad 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp @@ -5,7 +5,7 @@ #include "Common/FileUtil.h" #include "Core/ConfigManager.h" -#include "Core/Core.h" // Local core functions +#include "Core/Core.h" // Local core functions #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.h" @@ -15,343 +15,314 @@ // TODO: support in netplay/movies. -CWII_IPC_HLE_Device_usb_kbd::CWII_IPC_HLE_Device_usb_kbd(u32 _DeviceID, const std::string& _rDeviceName) -: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) -{} +CWII_IPC_HLE_Device_usb_kbd::CWII_IPC_HLE_Device_usb_kbd(u32 _DeviceID, + const std::string& _rDeviceName) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) +{ +} CWII_IPC_HLE_Device_usb_kbd::~CWII_IPC_HLE_Device_usb_kbd() -{} +{ +} IPCCommandResult CWII_IPC_HLE_Device_usb_kbd::Open(u32 _CommandAddress, u32 _Mode) { - INFO_LOG(WII_IPC_STM, "CWII_IPC_HLE_Device_usb_kbd: Open"); - IniFile ini; - ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); - ini.GetOrCreateSection("USB Keyboard")->Get("Layout", &m_KeyboardLayout, KBD_LAYOUT_QWERTY); + INFO_LOG(WII_IPC_STM, "CWII_IPC_HLE_Device_usb_kbd: Open"); + IniFile ini; + ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); + ini.GetOrCreateSection("USB Keyboard")->Get("Layout", &m_KeyboardLayout, KBD_LAYOUT_QWERTY); - for (bool& pressed : m_OldKeyBuffer) - { - pressed = false; - } + for (bool& pressed : m_OldKeyBuffer) + { + pressed = false; + } - m_OldModifiers = 0x00; + m_OldModifiers = 0x00; - //m_MessageQueue.push(SMessageData(MSG_KBD_CONNECT, 0, nullptr)); - Memory::Write_U32(m_DeviceID, _CommandAddress+4); - m_Active = true; - return GetDefaultReply(); + // m_MessageQueue.push(SMessageData(MSG_KBD_CONNECT, 0, nullptr)); + Memory::Write_U32(m_DeviceID, _CommandAddress + 4); + m_Active = true; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_usb_kbd::Close(u32 _CommandAddress, bool _bForce) { - INFO_LOG(WII_IPC_STM, "CWII_IPC_HLE_Device_usb_kbd: Close"); - while (!m_MessageQueue.empty()) - m_MessageQueue.pop(); - if (!_bForce) - Memory::Write_U32(0, _CommandAddress + 4); - m_Active = false; - return GetDefaultReply(); + INFO_LOG(WII_IPC_STM, "CWII_IPC_HLE_Device_usb_kbd: Close"); + while (!m_MessageQueue.empty()) + m_MessageQueue.pop(); + if (!_bForce) + Memory::Write_U32(0, _CommandAddress + 4); + m_Active = false; + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_usb_kbd::Write(u32 _CommandAddress) { - INFO_LOG(WII_IPC_STM, "Ignoring write to CWII_IPC_HLE_Device_usb_kbd"); + INFO_LOG(WII_IPC_STM, "Ignoring write to CWII_IPC_HLE_Device_usb_kbd"); #if defined(_DEBUG) || defined(DEBUGFAST) - DumpCommands(_CommandAddress, 10, LogTypes::WII_IPC_STM, LogTypes::LDEBUG); + DumpCommands(_CommandAddress, 10, LogTypes::WII_IPC_STM, LogTypes::LDEBUG); #endif - return GetDefaultReply(); + return GetDefaultReply(); } IPCCommandResult CWII_IPC_HLE_Device_usb_kbd::IOCtl(u32 _CommandAddress) { - u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); + u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - if (SConfig::GetInstance().m_WiiKeyboard && !Core::g_want_determinism && !m_MessageQueue.empty()) - { - Memory::CopyToEmu(BufferOut, &m_MessageQueue.front(), sizeof(SMessageData)); - m_MessageQueue.pop(); - } + if (SConfig::GetInstance().m_WiiKeyboard && !Core::g_want_determinism && !m_MessageQueue.empty()) + { + Memory::CopyToEmu(BufferOut, &m_MessageQueue.front(), sizeof(SMessageData)); + m_MessageQueue.pop(); + } - Memory::Write_U32(0, _CommandAddress + 0x4); - return GetDefaultReply(); + Memory::Write_U32(0, _CommandAddress + 0x4); + return GetDefaultReply(); } bool CWII_IPC_HLE_Device_usb_kbd::IsKeyPressed(int _Key) { #ifdef _WIN32 - if (GetAsyncKeyState(_Key) & 0x8000) - return true; - else - return false; + if (GetAsyncKeyState(_Key) & 0x8000) + return true; + else + return false; #else - // TODO: do it for non-Windows platforms - return false; + // TODO: do it for non-Windows platforms + return false; #endif } u32 CWII_IPC_HLE_Device_usb_kbd::Update() { - if (!SConfig::GetInstance().m_WiiKeyboard || Core::g_want_determinism || !m_Active) - return 0; + if (!SConfig::GetInstance().m_WiiKeyboard || Core::g_want_determinism || !m_Active) + return 0; - u8 Modifiers = 0x00; - u8 PressedKeys[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - bool GotEvent = false; - int num_pressed_keys = 0; - for (int i = 0; i < 256; i++) - { - bool KeyPressedNow = IsKeyPressed(i); - bool KeyPressedBefore = m_OldKeyBuffer[i]; - u8 KeyCode = 0; + u8 Modifiers = 0x00; + u8 PressedKeys[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + bool GotEvent = false; + int num_pressed_keys = 0; + for (int i = 0; i < 256; i++) + { + bool KeyPressedNow = IsKeyPressed(i); + bool KeyPressedBefore = m_OldKeyBuffer[i]; + u8 KeyCode = 0; - if (KeyPressedNow ^ KeyPressedBefore) - { - if (KeyPressedNow) - { - switch (m_KeyboardLayout) - { - case KBD_LAYOUT_QWERTY: - KeyCode = m_KeyCodesQWERTY[i]; - break; + if (KeyPressedNow ^ KeyPressedBefore) + { + if (KeyPressedNow) + { + switch (m_KeyboardLayout) + { + case KBD_LAYOUT_QWERTY: + KeyCode = m_KeyCodesQWERTY[i]; + break; - case KBD_LAYOUT_AZERTY: - KeyCode = m_KeyCodesAZERTY[i]; - break; - } + case KBD_LAYOUT_AZERTY: + KeyCode = m_KeyCodesAZERTY[i]; + break; + } - if (KeyCode == 0x00) - continue; + if (KeyCode == 0x00) + continue; - PressedKeys[num_pressed_keys] = KeyCode; + PressedKeys[num_pressed_keys] = KeyCode; - num_pressed_keys++; - if (num_pressed_keys == 6) - break; - } + num_pressed_keys++; + if (num_pressed_keys == 6) + break; + } - GotEvent = true; - } + GotEvent = true; + } - m_OldKeyBuffer[i] = KeyPressedNow; - } + m_OldKeyBuffer[i] = KeyPressedNow; + } #ifdef _WIN32 - if (GetAsyncKeyState(VK_LCONTROL) & 0x8000) - Modifiers |= 0x01; - if (GetAsyncKeyState(VK_LSHIFT) & 0x8000) - Modifiers |= 0x02; - if (GetAsyncKeyState(VK_MENU) & 0x8000) - Modifiers |= 0x04; - if (GetAsyncKeyState(VK_LWIN) & 0x8000) - Modifiers |= 0x08; - if (GetAsyncKeyState(VK_RCONTROL) & 0x8000) - Modifiers |= 0x10; - if (GetAsyncKeyState(VK_RSHIFT) & 0x8000) - Modifiers |= 0x20; - if (GetAsyncKeyState(VK_MENU) & 0x8000) // TODO: VK_MENU is for ALT, not for ALT GR (ALT GR seems to work though...) - Modifiers |= 0x40; - if (GetAsyncKeyState(VK_RWIN) & 0x8000) - Modifiers |= 0x80; + if (GetAsyncKeyState(VK_LCONTROL) & 0x8000) + Modifiers |= 0x01; + if (GetAsyncKeyState(VK_LSHIFT) & 0x8000) + Modifiers |= 0x02; + if (GetAsyncKeyState(VK_MENU) & 0x8000) + Modifiers |= 0x04; + if (GetAsyncKeyState(VK_LWIN) & 0x8000) + Modifiers |= 0x08; + if (GetAsyncKeyState(VK_RCONTROL) & 0x8000) + Modifiers |= 0x10; + if (GetAsyncKeyState(VK_RSHIFT) & 0x8000) + Modifiers |= 0x20; + if (GetAsyncKeyState(VK_MENU) & + 0x8000) // TODO: VK_MENU is for ALT, not for ALT GR (ALT GR seems to work though...) + Modifiers |= 0x40; + if (GetAsyncKeyState(VK_RWIN) & 0x8000) + Modifiers |= 0x80; #else - // TODO: modifiers for non-Windows platforms +// TODO: modifiers for non-Windows platforms #endif - if (Modifiers ^ m_OldModifiers) - { - GotEvent = true; - m_OldModifiers = Modifiers; - } + if (Modifiers ^ m_OldModifiers) + { + GotEvent = true; + m_OldModifiers = Modifiers; + } - if (GotEvent) - m_MessageQueue.push(SMessageData(MSG_EVENT, Modifiers, PressedKeys)); + if (GotEvent) + m_MessageQueue.push(SMessageData(MSG_EVENT, Modifiers, PressedKeys)); - return 0; + return 0; } - // Crazy ugly #ifdef _WIN32 u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2A, // Backspace - 0x2B, // Tab - 0x00, 0x00, - 0x00, // Clear - 0x28, // Return - 0x00, 0x00, - 0x00, // Shift - 0x00, // Control - 0x00, // ALT - 0x48, // Pause - 0x39, // Capital - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x29, // Escape - 0x00, 0x00, 0x00, 0x00, - 0x2C, // Space - 0x4B, // Prior - 0x4E, // Next - 0x4D, // End - 0x4A, // Home - 0x50, // Left - 0x52, // Up - 0x4F, // Right - 0x51, // Down - 0x00, 0x00, 0x00, - 0x46, // Print screen - 0x49, // Insert - 0x4C, // Delete - 0x00, - // 0 -> 9 - 0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x25, 0x26, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - // A -> Z - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, - 0x1C, 0x1D, - 0x00, 0x00, 0x00, 0x00, - 0x00, - // Numpad 0 -> 9 - 0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, - 0x60, 0x61, - 0x55, // Multiply - 0x57, // Add - 0x00, // Separator - 0x56, // Subtract - 0x63, // Decimal - 0x54, // Divide - // F1 -> F12 - 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, - 0x42, 0x43, 0x44, 0x45, - // F13 -> F24 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x53, // Numlock - 0x47, // Scroll lock - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // Modifier keys - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x33, // ';' - 0x2E, // Plus - 0x36, // Comma - 0x2D, // Minus - 0x37, // Period - 0x38, // '/' - 0x35, // '~' - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, - 0x2F, // '[' - 0x32, // '\' - 0x30, // ']' - 0x34, // ''' - 0x00, // - 0x00, // Nothing interesting past this point. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2A, // Backspace + 0x2B, // Tab + 0x00, 0x00, + 0x00, // Clear + 0x28, // Return + 0x00, 0x00, + 0x00, // Shift + 0x00, // Control + 0x00, // ALT + 0x48, // Pause + 0x39, // Capital + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x29, // Escape + 0x00, 0x00, 0x00, 0x00, + 0x2C, // Space + 0x4B, // Prior + 0x4E, // Next + 0x4D, // End + 0x4A, // Home + 0x50, // Left + 0x52, // Up + 0x4F, // Right + 0x51, // Down + 0x00, 0x00, 0x00, + 0x46, // Print screen + 0x49, // Insert + 0x4C, // Delete + 0x00, + // 0 -> 9 + 0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + // A -> Z + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, + // Numpad 0 -> 9 + 0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, + 0x55, // Multiply + 0x57, // Add + 0x00, // Separator + 0x56, // Subtract + 0x63, // Decimal + 0x54, // Divide + // F1 -> F12 + 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, + // F13 -> F24 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x53, // Numlock + 0x47, // Scroll lock + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Modifier keys + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, // ';' + 0x2E, // Plus + 0x36, // Comma + 0x2D, // Minus + 0x37, // Period + 0x38, // '/' + 0x35, // '~' + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2F, // '[' + 0x32, // '\' + 0x30, // ']' + 0x34, // ''' + 0x00, // + 0x00, // Nothing interesting past this point. }; u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2A, // Backspace - 0x2B, // Tab - 0x00, 0x00, - 0x00, // Clear - 0x28, // Return - 0x00, 0x00, - 0x00, // Shift - 0x00, // Control - 0x00, // ALT - 0x48, // Pause - 0x39, // Capital - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x29, // Escape - 0x00, 0x00, 0x00, 0x00, - 0x2C, // Space - 0x4B, // Prior - 0x4E, // Next - 0x4D, // End - 0x4A, // Home - 0x50, // Left - 0x52, // Up - 0x4F, // Right - 0x51, // Down - 0x00, 0x00, 0x00, - 0x46, // Print screen - 0x49, // Insert - 0x4C, // Delete - 0x00, - // 0 -> 9 - 0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x25, 0x26, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - // A -> Z - 0x14, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x33, 0x11, 0x12, 0x13, - 0x04, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1D, 0x1B, - 0x1C, 0x1A, - 0x00, 0x00, 0x00, 0x00, - 0x00, - // Numpad 0 -> 9 - 0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, - 0x60, 0x61, - 0x55, // Multiply - 0x57, // Add - 0x00, // Separator - 0x56, // Substract - 0x63, // Decimal - 0x54, // Divide - // F1 -> F12 - 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, - 0x42, 0x43, 0x44, 0x45, - // F13 -> F24 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x53, // Numlock - 0x47, // Scroll lock - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // Modifier keys - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x30, // '$' - 0x2E, // Plus - 0x10, // Comma - 0x00, // Minus - 0x36, // Period - 0x37, // '/' - 0x34, // ' ' - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, - 0x2D, // ')' - 0x32, // '\' - 0x2F, // '^' - 0x00, // ' ' - 0x38, // '!' - 0x00, // Nothing interesting past this point. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2A, // Backspace + 0x2B, // Tab + 0x00, 0x00, + 0x00, // Clear + 0x28, // Return + 0x00, 0x00, + 0x00, // Shift + 0x00, // Control + 0x00, // ALT + 0x48, // Pause + 0x39, // Capital + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x29, // Escape + 0x00, 0x00, 0x00, 0x00, + 0x2C, // Space + 0x4B, // Prior + 0x4E, // Next + 0x4D, // End + 0x4A, // Home + 0x50, // Left + 0x52, // Up + 0x4F, // Right + 0x51, // Down + 0x00, 0x00, 0x00, + 0x46, // Print screen + 0x49, // Insert + 0x4C, // Delete + 0x00, + // 0 -> 9 + 0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + // A -> Z + 0x14, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x33, 0x11, 0x12, 0x13, + 0x04, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1D, 0x1B, 0x1C, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, + // Numpad 0 -> 9 + 0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, + 0x55, // Multiply + 0x57, // Add + 0x00, // Separator + 0x56, // Substract + 0x63, // Decimal + 0x54, // Divide + // F1 -> F12 + 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, + // F13 -> F24 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x53, // Numlock + 0x47, // Scroll lock + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Modifier keys + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, // '$' + 0x2E, // Plus + 0x10, // Comma + 0x00, // Minus + 0x36, // Period + 0x37, // '/' + 0x34, // ' ' + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2D, // ')' + 0x32, // '\' + 0x2F, // '^' + 0x00, // ' ' + 0x38, // '!' + 0x00, // Nothing interesting past this point. }; #else -u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = { - 0 -}; +u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesQWERTY[256] = {0}; -u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = { - 0 -}; +u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = {0}; #endif diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.h index 457d22bee6..7fbcd7de79 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.h @@ -12,60 +12,60 @@ class CWII_IPC_HLE_Device_usb_kbd : public IWII_IPC_HLE_Device { public: - CWII_IPC_HLE_Device_usb_kbd(u32 _DeviceID, const std::string& _rDeviceName); - virtual ~CWII_IPC_HLE_Device_usb_kbd(); + CWII_IPC_HLE_Device_usb_kbd(u32 _DeviceID, const std::string& _rDeviceName); + virtual ~CWII_IPC_HLE_Device_usb_kbd(); - IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; - IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; - IPCCommandResult Write(u32 _CommandAddress) override; - IPCCommandResult IOCtl(u32 _CommandAddress) override; - u32 Update() override; + IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override; + IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override; + IPCCommandResult Write(u32 _CommandAddress) override; + IPCCommandResult IOCtl(u32 _CommandAddress) override; + u32 Update() override; private: - enum - { - MSG_KBD_CONNECT = 0, - MSG_KBD_DISCONNECT = 1, - MSG_EVENT = 2 - }; + enum + { + MSG_KBD_CONNECT = 0, + MSG_KBD_DISCONNECT = 1, + MSG_EVENT = 2 + }; - #pragma pack(push, 1) - struct SMessageData - { - u32 MsgType; - u32 Unk1; - u8 Modifiers; - u8 Unk2; - u8 PressedKeys[6]; +#pragma pack(push, 1) + struct SMessageData + { + u32 MsgType; + u32 Unk1; + u8 Modifiers; + u8 Unk2; + u8 PressedKeys[6]; - SMessageData(u32 _MsgType, u8 _Modifiers, u8 *_PressedKeys) - { - MsgType = Common::swap32(_MsgType); - Unk1 = 0; // swapped - Modifiers = _Modifiers; - Unk2 = 0; + SMessageData(u32 _MsgType, u8 _Modifiers, u8* _PressedKeys) + { + MsgType = Common::swap32(_MsgType); + Unk1 = 0; // swapped + Modifiers = _Modifiers; + Unk2 = 0; - if (_PressedKeys) // Doesn't need to be in a specific order - memcpy(PressedKeys, _PressedKeys, sizeof(PressedKeys)); - else - memset(PressedKeys, 0, sizeof(PressedKeys)); - } - }; - #pragma pack(pop) - std::queue m_MessageQueue; + if (_PressedKeys) // Doesn't need to be in a specific order + memcpy(PressedKeys, _PressedKeys, sizeof(PressedKeys)); + else + memset(PressedKeys, 0, sizeof(PressedKeys)); + } + }; +#pragma pack(pop) + std::queue m_MessageQueue; - bool m_OldKeyBuffer[256]; - u8 m_OldModifiers; + bool m_OldKeyBuffer[256]; + u8 m_OldModifiers; - virtual bool IsKeyPressed(int _Key); + virtual bool IsKeyPressed(int _Key); - // This stuff should probably die - enum - { - KBD_LAYOUT_QWERTY = 0, - KBD_LAYOUT_AZERTY = 1 - }; - int m_KeyboardLayout; - static u8 m_KeyCodesQWERTY[256]; - static u8 m_KeyCodesAZERTY[256]; + // This stuff should probably die + enum + { + KBD_LAYOUT_QWERTY = 0, + KBD_LAYOUT_AZERTY = 1 + }; + int m_KeyboardLayout; + static u8 m_KeyCodesQWERTY[256]; + static u8 m_KeyCodesAZERTY[256]; }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.cpp index 1914f691b0..fd74a35c32 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.cpp @@ -8,97 +8,92 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/Host.h" #include "Core/HW/Wiimote.h" -#include "Core/IPC_HLE/l2cap.h" +#include "Core/Host.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" #include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h" #include "Core/IPC_HLE/WiiMote_HID_Attr.h" +#include "Core/IPC_HLE/l2cap.h" static CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = nullptr; CWII_IPC_HLE_Device_usb_oh1_57e_305* GetUsbPointer() { - return s_Usb; + return s_Usb; } void SetUsbPointer(CWII_IPC_HLE_Device_usb_oh1_57e_305* ptr) { - s_Usb = ptr; + s_Usb = ptr; } - -CWII_IPC_HLE_WiiMote::CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305* _pHost, int _Number, bdaddr_t _BD, bool ready) - : m_HIDControlChannel_Connected(false) - , m_HIDControlChannel_ConnectedWait(false) - , m_HIDControlChannel_Config(false) - , m_HIDControlChannel_ConfigWait(false) - , m_HIDInterruptChannel_Connected(false) - , m_HIDInterruptChannel_ConnectedWait(false) - , m_HIDInterruptChannel_Config(false) - , m_HIDInterruptChannel_ConfigWait(false) - , m_BD(_BD) - , m_Name(_Number == WIIMOTE_BALANCE_BOARD ? "Nintendo RVL-WBC-01" : "Nintendo RVL-CNT-01") - , m_pHost(_pHost) +CWII_IPC_HLE_WiiMote::CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305* _pHost, int _Number, + bdaddr_t _BD, bool ready) + : m_HIDControlChannel_Connected(false), m_HIDControlChannel_ConnectedWait(false), + m_HIDControlChannel_Config(false), m_HIDControlChannel_ConfigWait(false), + m_HIDInterruptChannel_Connected(false), m_HIDInterruptChannel_ConnectedWait(false), + m_HIDInterruptChannel_Config(false), m_HIDInterruptChannel_ConfigWait(false), m_BD(_BD), + m_Name(_Number == WIIMOTE_BALANCE_BOARD ? "Nintendo RVL-WBC-01" : "Nintendo RVL-CNT-01"), + m_pHost(_pHost) { - DEBUG_LOG(WII_IPC_WIIMOTE, "Wiimote: #%i Constructed", _Number); + DEBUG_LOG(WII_IPC_WIIMOTE, "Wiimote: #%i Constructed", _Number); - m_ConnectionState = (ready) ? CONN_READY : CONN_INACTIVE; - m_ConnectionHandle = 0x100 + _Number; - memset(m_LinkKey, 0xA0 + _Number, HCI_KEY_SIZE); + m_ConnectionState = (ready) ? CONN_READY : CONN_INACTIVE; + m_ConnectionHandle = 0x100 + _Number; + memset(m_LinkKey, 0xA0 + _Number, HCI_KEY_SIZE); - bdaddr_t _nullBD = BDADDR_ANY; - if (memcmp(&m_BD, &_nullBD, sizeof(bdaddr_t))==0) - { - m_BD.b[0] = 0x11; - m_BD.b[1] = 0x02; - m_BD.b[2] = 0x19; - m_BD.b[3] = 0x79; - m_BD.b[4] = 0x00; - m_BD.b[5] = _Number; - } - uclass[0]= 0x00; - uclass[1]= 0x04; - uclass[2]= 0x48; + bdaddr_t _nullBD = BDADDR_ANY; + if (memcmp(&m_BD, &_nullBD, sizeof(bdaddr_t)) == 0) + { + m_BD.b[0] = 0x11; + m_BD.b[1] = 0x02; + m_BD.b[2] = 0x19; + m_BD.b[3] = 0x79; + m_BD.b[4] = 0x00; + m_BD.b[5] = _Number; + } + uclass[0] = 0x00; + uclass[1] = 0x04; + uclass[2] = 0x48; - features[0] = 0xBC; - features[1] = 0x02; - features[2] = 0x04; - features[3] = 0x38; - features[4] = 0x08; - features[5] = 0x00; - features[6] = 0x00; - features[7] = 0x00; + features[0] = 0xBC; + features[1] = 0x02; + features[2] = 0x04; + features[3] = 0x38; + features[4] = 0x08; + features[5] = 0x00; + features[6] = 0x00; + features[7] = 0x00; - lmp_version = 0x2; - lmp_subversion = 0x229; + lmp_version = 0x2; + lmp_subversion = 0x229; } -void CWII_IPC_HLE_WiiMote::DoState(PointerWrap &p) +void CWII_IPC_HLE_WiiMote::DoState(PointerWrap& p) { - // this function is usually not called... see CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState + // this function is usually not called... see CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState - p.Do(m_ConnectionState); + p.Do(m_ConnectionState); - p.Do(m_HIDControlChannel_Connected); - p.Do(m_HIDControlChannel_ConnectedWait); - p.Do(m_HIDControlChannel_Config); - p.Do(m_HIDControlChannel_ConfigWait); - p.Do(m_HIDInterruptChannel_Connected); - p.Do(m_HIDInterruptChannel_ConnectedWait); - p.Do(m_HIDInterruptChannel_Config); - p.Do(m_HIDInterruptChannel_ConfigWait); + p.Do(m_HIDControlChannel_Connected); + p.Do(m_HIDControlChannel_ConnectedWait); + p.Do(m_HIDControlChannel_Config); + p.Do(m_HIDControlChannel_ConfigWait); + p.Do(m_HIDInterruptChannel_Connected); + p.Do(m_HIDInterruptChannel_ConnectedWait); + p.Do(m_HIDInterruptChannel_Config); + p.Do(m_HIDInterruptChannel_ConfigWait); - p.Do(m_BD); - p.Do(m_ConnectionHandle); - p.Do(uclass); - p.Do(features); - p.Do(lmp_version); - p.Do(lmp_subversion); - p.Do(m_LinkKey); - p.Do(m_Name); + p.Do(m_BD); + p.Do(m_ConnectionHandle); + p.Do(uclass); + p.Do(features); + p.Do(lmp_version); + p.Do(lmp_subversion); + p.Do(m_LinkKey); + p.Do(m_Name); - p.Do(m_Channel); + p.Do(m_Channel); } // @@ -114,57 +109,57 @@ void CWII_IPC_HLE_WiiMote::DoState(PointerWrap &p) bool CWII_IPC_HLE_WiiMote::LinkChannel() { - if (m_ConnectionState != CONN_LINKING) - return false; + if (m_ConnectionState != CONN_LINKING) + return false; - // try to connect L2CAP_PSM_HID_CNTL - if (!m_HIDControlChannel_Connected) - { - if (m_HIDControlChannel_ConnectedWait) - return false; + // try to connect L2CAP_PSM_HID_CNTL + if (!m_HIDControlChannel_Connected) + { + if (m_HIDControlChannel_ConnectedWait) + return false; - m_HIDControlChannel_ConnectedWait = true; - SendConnectionRequest(0x0040, L2CAP_PSM_HID_CNTL); - return true; - } + m_HIDControlChannel_ConnectedWait = true; + SendConnectionRequest(0x0040, L2CAP_PSM_HID_CNTL); + return true; + } - // try to config L2CAP_PSM_HID_CNTL - if (!m_HIDControlChannel_Config) - { - if (m_HIDControlChannel_ConfigWait) - return false; + // try to config L2CAP_PSM_HID_CNTL + if (!m_HIDControlChannel_Config) + { + if (m_HIDControlChannel_ConfigWait) + return false; - m_HIDControlChannel_ConfigWait = true; - SendConfigurationRequest(0x0040); - return true; - } + m_HIDControlChannel_ConfigWait = true; + SendConfigurationRequest(0x0040); + return true; + } - // try to connect L2CAP_PSM_HID_INTR - if (!m_HIDInterruptChannel_Connected) - { - if (m_HIDInterruptChannel_ConnectedWait) - return false; + // try to connect L2CAP_PSM_HID_INTR + if (!m_HIDInterruptChannel_Connected) + { + if (m_HIDInterruptChannel_ConnectedWait) + return false; - m_HIDInterruptChannel_ConnectedWait = true; - SendConnectionRequest(0x0041, L2CAP_PSM_HID_INTR); - return true; - } + m_HIDInterruptChannel_ConnectedWait = true; + SendConnectionRequest(0x0041, L2CAP_PSM_HID_INTR); + return true; + } - // try to config L2CAP_PSM_HID_INTR - if (!m_HIDInterruptChannel_Config) - { - if (m_HIDInterruptChannel_ConfigWait) - return false; + // try to config L2CAP_PSM_HID_INTR + if (!m_HIDInterruptChannel_Config) + { + if (m_HIDInterruptChannel_ConfigWait) + return false; - m_HIDInterruptChannel_ConfigWait = true; - SendConfigurationRequest(0x0041); - return true; - } + m_HIDInterruptChannel_ConfigWait = true; + SendConfigurationRequest(0x0041); + return true; + } - DEBUG_LOG(WII_IPC_WIIMOTE, "ConnectionState CONN_LINKING -> CONN_COMPLETE"); - m_ConnectionState = CONN_COMPLETE; + DEBUG_LOG(WII_IPC_WIIMOTE, "ConnectionState CONN_LINKING -> CONN_COMPLETE"); + m_ConnectionState = CONN_COMPLETE; - return false; + return false; } // @@ -179,55 +174,54 @@ bool CWII_IPC_HLE_WiiMote::LinkChannel() // void CWII_IPC_HLE_WiiMote::Activate(bool ready) { - if (ready && (m_ConnectionState == CONN_INACTIVE)) - { - m_ConnectionState = CONN_READY; - } - else if (!ready) - { - m_pHost->RemoteDisconnect(m_ConnectionHandle); - EventDisconnect(); - } + if (ready && (m_ConnectionState == CONN_INACTIVE)) + { + m_ConnectionState = CONN_READY; + } + else if (!ready) + { + m_pHost->RemoteDisconnect(m_ConnectionHandle); + EventDisconnect(); + } } void CWII_IPC_HLE_WiiMote::EventConnectionAccepted() { - DEBUG_LOG(WII_IPC_WIIMOTE, "ConnectionState %x -> CONN_LINKING", m_ConnectionState); - m_ConnectionState = CONN_LINKING; + DEBUG_LOG(WII_IPC_WIIMOTE, "ConnectionState %x -> CONN_LINKING", m_ConnectionState); + m_ConnectionState = CONN_LINKING; } void CWII_IPC_HLE_WiiMote::EventDisconnect() { - // Send disconnect message to plugin - Wiimote::ControlChannel(m_ConnectionHandle & 0xFF, 99, nullptr, 0); + // Send disconnect message to plugin + Wiimote::ControlChannel(m_ConnectionHandle & 0xFF, 99, nullptr, 0); - m_ConnectionState = CONN_INACTIVE; - // Clear channel flags - ResetChannels(); + m_ConnectionState = CONN_INACTIVE; + // Clear channel flags + ResetChannels(); } bool CWII_IPC_HLE_WiiMote::EventPagingChanged(u8 _pageMode) { - if ((m_ConnectionState == CONN_READY) && (_pageMode & HCI_PAGE_SCAN_ENABLE)) - return true; + if ((m_ConnectionState == CONN_READY) && (_pageMode & HCI_PAGE_SCAN_ENABLE)) + return true; - return false; + return false; } void CWII_IPC_HLE_WiiMote::ResetChannels() { - // reset connection process - m_HIDControlChannel_Connected = false; - m_HIDControlChannel_Config = false; - m_HIDInterruptChannel_Connected = false; - m_HIDInterruptChannel_Config = false; - m_HIDControlChannel_ConnectedWait = false; - m_HIDControlChannel_ConfigWait = false; - m_HIDInterruptChannel_ConnectedWait = false; - m_HIDInterruptChannel_ConfigWait = false; + // reset connection process + m_HIDControlChannel_Connected = false; + m_HIDControlChannel_Config = false; + m_HIDInterruptChannel_Connected = false; + m_HIDInterruptChannel_Config = false; + m_HIDControlChannel_ConnectedWait = false; + m_HIDControlChannel_ConfigWait = false; + m_HIDInterruptChannel_ConnectedWait = false; + m_HIDInterruptChannel_ConfigWait = false; } - // // // @@ -239,115 +233,117 @@ void CWII_IPC_HLE_WiiMote::ResetChannels() // // - // This function receives L2CAP commands from the CPU void CWII_IPC_HLE_WiiMote::ExecuteL2capCmd(u8* _pData, u32 _Size) { - // parse the command - l2cap_hdr_t* pHeader = (l2cap_hdr_t*)_pData; - u8* pData = _pData + sizeof(l2cap_hdr_t); - u32 DataSize = _Size - sizeof(l2cap_hdr_t); - INFO_LOG(WII_IPC_WIIMOTE, " CID 0x%04x, Len 0x%x, DataSize 0x%x", pHeader->dcid, pHeader->length, DataSize); + // parse the command + l2cap_hdr_t* pHeader = (l2cap_hdr_t*)_pData; + u8* pData = _pData + sizeof(l2cap_hdr_t); + u32 DataSize = _Size - sizeof(l2cap_hdr_t); + INFO_LOG(WII_IPC_WIIMOTE, " CID 0x%04x, Len 0x%x, DataSize 0x%x", pHeader->dcid, pHeader->length, + DataSize); - if (pHeader->length != DataSize) - { - INFO_LOG(WII_IPC_WIIMOTE, "Faulty packet. It is dropped."); - return; - } + if (pHeader->length != DataSize) + { + INFO_LOG(WII_IPC_WIIMOTE, "Faulty packet. It is dropped."); + return; + } - switch (pHeader->dcid) - { - case L2CAP_SIGNAL_CID: - SignalChannel(pData, DataSize); - break; + switch (pHeader->dcid) + { + case L2CAP_SIGNAL_CID: + SignalChannel(pData, DataSize); + break; - default: - { - _dbg_assert_msg_(WII_IPC_WIIMOTE, DoesChannelExist(pHeader->dcid), "L2CAP: SendACLPacket to unknown channel %i", pHeader->dcid); - CChannelMap::iterator itr= m_Channel.find(pHeader->dcid); + default: + { + _dbg_assert_msg_(WII_IPC_WIIMOTE, DoesChannelExist(pHeader->dcid), + "L2CAP: SendACLPacket to unknown channel %i", pHeader->dcid); + CChannelMap::iterator itr = m_Channel.find(pHeader->dcid); - const int number = m_ConnectionHandle & 0xFF; + const int number = m_ConnectionHandle & 0xFF; - if (itr != m_Channel.end()) - { - SChannel& rChannel = itr->second; - switch (rChannel.PSM) - { - case L2CAP_PSM_SDP: - HandleSDP(pHeader->dcid, pData, DataSize); - break; + if (itr != m_Channel.end()) + { + SChannel& rChannel = itr->second; + switch (rChannel.PSM) + { + case L2CAP_PSM_SDP: + HandleSDP(pHeader->dcid, pData, DataSize); + break; - case L2CAP_PSM_HID_CNTL: - if (number < MAX_BBMOTES) - Wiimote::ControlChannel(number, pHeader->dcid, pData, DataSize); - break; + case L2CAP_PSM_HID_CNTL: + if (number < MAX_BBMOTES) + Wiimote::ControlChannel(number, pHeader->dcid, pData, DataSize); + break; - case L2CAP_PSM_HID_INTR: - { - if (number < MAX_BBMOTES) - { - DEBUG_LOG(WIIMOTE, "Wiimote_InterruptChannel"); - DEBUG_LOG(WIIMOTE, " Channel ID: %04x", pHeader->dcid); - std::string Temp = ArrayToString((const u8*)pData, DataSize); - DEBUG_LOG(WIIMOTE, " Data: %s", Temp.c_str()); + case L2CAP_PSM_HID_INTR: + { + if (number < MAX_BBMOTES) + { + DEBUG_LOG(WIIMOTE, "Wiimote_InterruptChannel"); + DEBUG_LOG(WIIMOTE, " Channel ID: %04x", pHeader->dcid); + std::string Temp = ArrayToString((const u8*)pData, DataSize); + DEBUG_LOG(WIIMOTE, " Data: %s", Temp.c_str()); - Wiimote::InterruptChannel(number, pHeader->dcid, pData, DataSize); - } - } - break; + Wiimote::InterruptChannel(number, pHeader->dcid, pData, DataSize); + } + } + break; - default: - ERROR_LOG(WII_IPC_WIIMOTE, "Channel 0x04%x has unknown PSM %x", pHeader->dcid, rChannel.PSM); - break; - } - } - } - break; - } + default: + ERROR_LOG(WII_IPC_WIIMOTE, "Channel 0x04%x has unknown PSM %x", pHeader->dcid, + rChannel.PSM); + break; + } + } + } + break; + } } void CWII_IPC_HLE_WiiMote::SignalChannel(u8* _pData, u32 _Size) { - while (_Size >= sizeof(l2cap_cmd_hdr_t)) - { - l2cap_cmd_hdr_t* cmd_hdr = (l2cap_cmd_hdr_t*)_pData; - _pData += sizeof(l2cap_cmd_hdr_t); - _Size = _Size - sizeof(l2cap_cmd_hdr_t) - cmd_hdr->length; + while (_Size >= sizeof(l2cap_cmd_hdr_t)) + { + l2cap_cmd_hdr_t* cmd_hdr = (l2cap_cmd_hdr_t*)_pData; + _pData += sizeof(l2cap_cmd_hdr_t); + _Size = _Size - sizeof(l2cap_cmd_hdr_t) - cmd_hdr->length; - switch (cmd_hdr->code) - { - case L2CAP_COMMAND_REJ: - ERROR_LOG(WII_IPC_WIIMOTE, "SignalChannel - L2CAP_COMMAND_REJ (something went wrong)." - "Try to replace your SYSCONF file with a new copy."); - break; + switch (cmd_hdr->code) + { + case L2CAP_COMMAND_REJ: + ERROR_LOG(WII_IPC_WIIMOTE, "SignalChannel - L2CAP_COMMAND_REJ (something went wrong)." + "Try to replace your SYSCONF file with a new copy."); + break; - case L2CAP_CONNECT_REQ: - ReceiveConnectionReq(cmd_hdr->ident, _pData, cmd_hdr->length); - break; + case L2CAP_CONNECT_REQ: + ReceiveConnectionReq(cmd_hdr->ident, _pData, cmd_hdr->length); + break; - case L2CAP_CONNECT_RSP: - ReceiveConnectionResponse(cmd_hdr->ident, _pData, cmd_hdr->length); - break; + case L2CAP_CONNECT_RSP: + ReceiveConnectionResponse(cmd_hdr->ident, _pData, cmd_hdr->length); + break; - case L2CAP_CONFIG_REQ: - ReceiveConfigurationReq(cmd_hdr->ident, _pData, cmd_hdr->length); - break; + case L2CAP_CONFIG_REQ: + ReceiveConfigurationReq(cmd_hdr->ident, _pData, cmd_hdr->length); + break; - case L2CAP_CONFIG_RSP: - ReceiveConfigurationResponse(cmd_hdr->ident, _pData, cmd_hdr->length); - break; + case L2CAP_CONFIG_RSP: + ReceiveConfigurationResponse(cmd_hdr->ident, _pData, cmd_hdr->length); + break; - case L2CAP_DISCONNECT_REQ: - ReceiveDisconnectionReq(cmd_hdr->ident, _pData, cmd_hdr->length); - break; + case L2CAP_DISCONNECT_REQ: + ReceiveDisconnectionReq(cmd_hdr->ident, _pData, cmd_hdr->length); + break; - default: - ERROR_LOG(WII_IPC_WIIMOTE, " Unknown Command-Code (0x%02x)", cmd_hdr->code); - return; - } + default: + ERROR_LOG(WII_IPC_WIIMOTE, " Unknown Command-Code (0x%02x)", cmd_hdr->code); + return; + } - _pData += cmd_hdr->length; - } + _pData += cmd_hdr->length; + } } // @@ -363,176 +359,177 @@ void CWII_IPC_HLE_WiiMote::SignalChannel(u8* _pData, u32 _Size) void CWII_IPC_HLE_WiiMote::ReceiveConnectionReq(u8 _Ident, u8* _pData, u32 _Size) { - l2cap_con_req_cp* pCommandConnectionReq = (l2cap_con_req_cp*)_pData; + l2cap_con_req_cp* pCommandConnectionReq = (l2cap_con_req_cp*)_pData; - // create the channel - SChannel& rChannel = m_Channel[pCommandConnectionReq->scid]; - rChannel.PSM = pCommandConnectionReq->psm; - rChannel.SCID = pCommandConnectionReq->scid; - rChannel.DCID = pCommandConnectionReq->scid; + // create the channel + SChannel& rChannel = m_Channel[pCommandConnectionReq->scid]; + rChannel.PSM = pCommandConnectionReq->psm; + rChannel.SCID = pCommandConnectionReq->scid; + rChannel.DCID = pCommandConnectionReq->scid; - INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] ReceiveConnectionRequest"); - DEBUG_LOG(WII_IPC_WIIMOTE, " Ident: 0x%02x", _Ident); - DEBUG_LOG(WII_IPC_WIIMOTE, " PSM: 0x%04x", rChannel.PSM); - DEBUG_LOG(WII_IPC_WIIMOTE, " SCID: 0x%04x", rChannel.SCID); - DEBUG_LOG(WII_IPC_WIIMOTE, " DCID: 0x%04x", rChannel.DCID); + INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] ReceiveConnectionRequest"); + DEBUG_LOG(WII_IPC_WIIMOTE, " Ident: 0x%02x", _Ident); + DEBUG_LOG(WII_IPC_WIIMOTE, " PSM: 0x%04x", rChannel.PSM); + DEBUG_LOG(WII_IPC_WIIMOTE, " SCID: 0x%04x", rChannel.SCID); + DEBUG_LOG(WII_IPC_WIIMOTE, " DCID: 0x%04x", rChannel.DCID); - // response - l2cap_con_rsp_cp Rsp; - Rsp.scid = rChannel.SCID; - Rsp.dcid = rChannel.DCID; - Rsp.result = L2CAP_SUCCESS; - Rsp.status = L2CAP_NO_INFO; + // response + l2cap_con_rsp_cp Rsp; + Rsp.scid = rChannel.SCID; + Rsp.dcid = rChannel.DCID; + Rsp.result = L2CAP_SUCCESS; + Rsp.status = L2CAP_NO_INFO; - INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] SendConnectionResponse"); - SendCommandToACL(_Ident, L2CAP_CONNECT_RSP, sizeof(l2cap_con_rsp_cp), (u8*)&Rsp); + INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] SendConnectionResponse"); + SendCommandToACL(_Ident, L2CAP_CONNECT_RSP, sizeof(l2cap_con_rsp_cp), (u8*)&Rsp); - // update state machine - /* - if (rChannel.PSM == L2CAP_PSM_HID_CNTL) - m_HIDControlChannel_Connected = true; - else if (rChannel.PSM == L2CAP_PSM_HID_INTR) - m_HIDInterruptChannel_Connected = true; - */ + // update state machine + /* + if (rChannel.PSM == L2CAP_PSM_HID_CNTL) + m_HIDControlChannel_Connected = true; + else if (rChannel.PSM == L2CAP_PSM_HID_INTR) + m_HIDInterruptChannel_Connected = true; + */ } void CWII_IPC_HLE_WiiMote::ReceiveConnectionResponse(u8 _Ident, u8* _pData, u32 _Size) { - l2cap_con_rsp_cp* rsp = (l2cap_con_rsp_cp*)_pData; + l2cap_con_rsp_cp* rsp = (l2cap_con_rsp_cp*)_pData; - _dbg_assert_(WII_IPC_WIIMOTE, _Size == sizeof(l2cap_con_rsp_cp)); + _dbg_assert_(WII_IPC_WIIMOTE, _Size == sizeof(l2cap_con_rsp_cp)); - INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] ReceiveConnectionResponse"); - DEBUG_LOG(WII_IPC_WIIMOTE, " DCID: 0x%04x", rsp->dcid); - DEBUG_LOG(WII_IPC_WIIMOTE, " SCID: 0x%04x", rsp->scid); - DEBUG_LOG(WII_IPC_WIIMOTE, " Result: 0x%04x", rsp->result); - DEBUG_LOG(WII_IPC_WIIMOTE, " Status: 0x%04x", rsp->status); + INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] ReceiveConnectionResponse"); + DEBUG_LOG(WII_IPC_WIIMOTE, " DCID: 0x%04x", rsp->dcid); + DEBUG_LOG(WII_IPC_WIIMOTE, " SCID: 0x%04x", rsp->scid); + DEBUG_LOG(WII_IPC_WIIMOTE, " Result: 0x%04x", rsp->result); + DEBUG_LOG(WII_IPC_WIIMOTE, " Status: 0x%04x", rsp->status); - _dbg_assert_(WII_IPC_WIIMOTE, rsp->result == L2CAP_SUCCESS); - _dbg_assert_(WII_IPC_WIIMOTE, rsp->status == L2CAP_NO_INFO); - _dbg_assert_(WII_IPC_WIIMOTE, DoesChannelExist(rsp->scid)); + _dbg_assert_(WII_IPC_WIIMOTE, rsp->result == L2CAP_SUCCESS); + _dbg_assert_(WII_IPC_WIIMOTE, rsp->status == L2CAP_NO_INFO); + _dbg_assert_(WII_IPC_WIIMOTE, DoesChannelExist(rsp->scid)); - SChannel& rChannel = m_Channel[rsp->scid]; - rChannel.DCID = rsp->dcid; + SChannel& rChannel = m_Channel[rsp->scid]; + rChannel.DCID = rsp->dcid; - // update state machine - if (rChannel.PSM == L2CAP_PSM_HID_CNTL) - m_HIDControlChannel_Connected = true; - else if (rChannel.PSM == L2CAP_PSM_HID_INTR) - m_HIDInterruptChannel_Connected = true; + // update state machine + if (rChannel.PSM == L2CAP_PSM_HID_CNTL) + m_HIDControlChannel_Connected = true; + else if (rChannel.PSM == L2CAP_PSM_HID_INTR) + m_HIDInterruptChannel_Connected = true; } void CWII_IPC_HLE_WiiMote::ReceiveConfigurationReq(u8 _Ident, u8* _pData, u32 _Size) { - u32 Offset = 0; - l2cap_cfg_req_cp* pCommandConfigReq = (l2cap_cfg_req_cp*)_pData; + u32 Offset = 0; + l2cap_cfg_req_cp* pCommandConfigReq = (l2cap_cfg_req_cp*)_pData; - _dbg_assert_(WII_IPC_WIIMOTE, pCommandConfigReq->flags == 0x00); // 1 means that the options are send in multi-packets - _dbg_assert_(WII_IPC_WIIMOTE, DoesChannelExist(pCommandConfigReq->dcid)); + _dbg_assert_(WII_IPC_WIIMOTE, pCommandConfigReq->flags == + 0x00); // 1 means that the options are send in multi-packets + _dbg_assert_(WII_IPC_WIIMOTE, DoesChannelExist(pCommandConfigReq->dcid)); - SChannel& rChannel = m_Channel[pCommandConfigReq->dcid]; + SChannel& rChannel = m_Channel[pCommandConfigReq->dcid]; - INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] ReceiveConfigurationRequest"); - DEBUG_LOG(WII_IPC_WIIMOTE, " Ident: 0x%02x", _Ident); - DEBUG_LOG(WII_IPC_WIIMOTE, " DCID: 0x%04x", pCommandConfigReq->dcid); - DEBUG_LOG(WII_IPC_WIIMOTE, " Flags: 0x%04x", pCommandConfigReq->flags); + INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] ReceiveConfigurationRequest"); + DEBUG_LOG(WII_IPC_WIIMOTE, " Ident: 0x%02x", _Ident); + DEBUG_LOG(WII_IPC_WIIMOTE, " DCID: 0x%04x", pCommandConfigReq->dcid); + DEBUG_LOG(WII_IPC_WIIMOTE, " Flags: 0x%04x", pCommandConfigReq->flags); - Offset += sizeof(l2cap_cfg_req_cp); + Offset += sizeof(l2cap_cfg_req_cp); - u8 TempBuffer[1024]; - u32 RespLen = 0; + u8 TempBuffer[1024]; + u32 RespLen = 0; - l2cap_cfg_rsp_cp* Rsp = (l2cap_cfg_rsp_cp*)TempBuffer; - Rsp->scid = rChannel.DCID; - Rsp->flags = 0x00; - Rsp->result = L2CAP_SUCCESS; + l2cap_cfg_rsp_cp* Rsp = (l2cap_cfg_rsp_cp*)TempBuffer; + Rsp->scid = rChannel.DCID; + Rsp->flags = 0x00; + Rsp->result = L2CAP_SUCCESS; - RespLen += sizeof(l2cap_cfg_rsp_cp); + RespLen += sizeof(l2cap_cfg_rsp_cp); - // read configuration options - while (Offset < _Size) - { - l2cap_cfg_opt_t* pOptions = (l2cap_cfg_opt_t*)&_pData[Offset]; - Offset += sizeof(l2cap_cfg_opt_t); + // read configuration options + while (Offset < _Size) + { + l2cap_cfg_opt_t* pOptions = (l2cap_cfg_opt_t*)&_pData[Offset]; + Offset += sizeof(l2cap_cfg_opt_t); - switch (pOptions->type) - { - case L2CAP_OPT_MTU: - { - _dbg_assert_(WII_IPC_WIIMOTE, pOptions->length == L2CAP_OPT_MTU_SIZE); - l2cap_cfg_opt_val_t* pMTU = (l2cap_cfg_opt_val_t*)&_pData[Offset]; - rChannel.MTU = pMTU->mtu; - DEBUG_LOG(WII_IPC_WIIMOTE, " MTU: 0x%04x", pMTU->mtu); - } - break; + switch (pOptions->type) + { + case L2CAP_OPT_MTU: + { + _dbg_assert_(WII_IPC_WIIMOTE, pOptions->length == L2CAP_OPT_MTU_SIZE); + l2cap_cfg_opt_val_t* pMTU = (l2cap_cfg_opt_val_t*)&_pData[Offset]; + rChannel.MTU = pMTU->mtu; + DEBUG_LOG(WII_IPC_WIIMOTE, " MTU: 0x%04x", pMTU->mtu); + } + break; - case L2CAP_OPT_FLUSH_TIMO: - { - _dbg_assert_(WII_IPC_WIIMOTE, pOptions->length == L2CAP_OPT_FLUSH_TIMO_SIZE); - l2cap_cfg_opt_val_t* pFlushTimeOut = (l2cap_cfg_opt_val_t*)&_pData[Offset]; - rChannel.FlushTimeOut = pFlushTimeOut->flush_timo; - DEBUG_LOG(WII_IPC_WIIMOTE, " FlushTimeOut: 0x%04x", pFlushTimeOut->flush_timo); - } - break; + case L2CAP_OPT_FLUSH_TIMO: + { + _dbg_assert_(WII_IPC_WIIMOTE, pOptions->length == L2CAP_OPT_FLUSH_TIMO_SIZE); + l2cap_cfg_opt_val_t* pFlushTimeOut = (l2cap_cfg_opt_val_t*)&_pData[Offset]; + rChannel.FlushTimeOut = pFlushTimeOut->flush_timo; + DEBUG_LOG(WII_IPC_WIIMOTE, " FlushTimeOut: 0x%04x", pFlushTimeOut->flush_timo); + } + break; - default: - _dbg_assert_msg_(WII_IPC_WIIMOTE, 0, "Unknown Option: 0x%02x", pOptions->type); - break; - } + default: + _dbg_assert_msg_(WII_IPC_WIIMOTE, 0, "Unknown Option: 0x%02x", pOptions->type); + break; + } - Offset += pOptions->length; + Offset += pOptions->length; - u32 OptionSize = sizeof(l2cap_cfg_opt_t) + pOptions->length; - memcpy(&TempBuffer[RespLen], pOptions, OptionSize); - RespLen += OptionSize; - } + u32 OptionSize = sizeof(l2cap_cfg_opt_t) + pOptions->length; + memcpy(&TempBuffer[RespLen], pOptions, OptionSize); + RespLen += OptionSize; + } - INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] SendConfigurationResponse"); - SendCommandToACL(_Ident, L2CAP_CONFIG_RSP, RespLen, TempBuffer); + INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] SendConfigurationResponse"); + SendCommandToACL(_Ident, L2CAP_CONFIG_RSP, RespLen, TempBuffer); - // update state machine - if (rChannel.PSM == L2CAP_PSM_HID_CNTL) - m_HIDControlChannel_Connected = true; - else if (rChannel.PSM == L2CAP_PSM_HID_INTR) - m_HIDInterruptChannel_Connected = true; + // update state machine + if (rChannel.PSM == L2CAP_PSM_HID_CNTL) + m_HIDControlChannel_Connected = true; + else if (rChannel.PSM == L2CAP_PSM_HID_INTR) + m_HIDInterruptChannel_Connected = true; } void CWII_IPC_HLE_WiiMote::ReceiveConfigurationResponse(u8 _Ident, u8* _pData, u32 _Size) { - l2cap_cfg_rsp_cp* rsp = (l2cap_cfg_rsp_cp*)_pData; + l2cap_cfg_rsp_cp* rsp = (l2cap_cfg_rsp_cp*)_pData; - INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] ReceiveConfigurationResponse"); - DEBUG_LOG(WII_IPC_WIIMOTE, " SCID: 0x%04x", rsp->scid); - DEBUG_LOG(WII_IPC_WIIMOTE, " Flags: 0x%04x", rsp->flags); - DEBUG_LOG(WII_IPC_WIIMOTE, " Result: 0x%04x", rsp->result); + INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] ReceiveConfigurationResponse"); + DEBUG_LOG(WII_IPC_WIIMOTE, " SCID: 0x%04x", rsp->scid); + DEBUG_LOG(WII_IPC_WIIMOTE, " Flags: 0x%04x", rsp->flags); + DEBUG_LOG(WII_IPC_WIIMOTE, " Result: 0x%04x", rsp->result); - _dbg_assert_(WII_IPC_WIIMOTE, rsp->result == L2CAP_SUCCESS); + _dbg_assert_(WII_IPC_WIIMOTE, rsp->result == L2CAP_SUCCESS); - // update state machine - SChannel& rChannel = m_Channel[rsp->scid]; + // update state machine + SChannel& rChannel = m_Channel[rsp->scid]; - if (rChannel.PSM == L2CAP_PSM_HID_CNTL) - m_HIDControlChannel_Config = true; - else if (rChannel.PSM == L2CAP_PSM_HID_INTR) - m_HIDInterruptChannel_Config = true; + if (rChannel.PSM == L2CAP_PSM_HID_CNTL) + m_HIDControlChannel_Config = true; + else if (rChannel.PSM == L2CAP_PSM_HID_INTR) + m_HIDInterruptChannel_Config = true; } void CWII_IPC_HLE_WiiMote::ReceiveDisconnectionReq(u8 _Ident, u8* _pData, u32 _Size) { - l2cap_discon_req_cp* pCommandDisconnectionReq = (l2cap_discon_req_cp*)_pData; + l2cap_discon_req_cp* pCommandDisconnectionReq = (l2cap_discon_req_cp*)_pData; - INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] ReceiveDisconnectionReq"); - DEBUG_LOG(WII_IPC_WIIMOTE, " Ident: 0x%02x", _Ident); - DEBUG_LOG(WII_IPC_WIIMOTE, " DCID: 0x%04x", pCommandDisconnectionReq->dcid); - DEBUG_LOG(WII_IPC_WIIMOTE, " SCID: 0x%04x", pCommandDisconnectionReq->scid); + INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] ReceiveDisconnectionReq"); + DEBUG_LOG(WII_IPC_WIIMOTE, " Ident: 0x%02x", _Ident); + DEBUG_LOG(WII_IPC_WIIMOTE, " DCID: 0x%04x", pCommandDisconnectionReq->dcid); + DEBUG_LOG(WII_IPC_WIIMOTE, " SCID: 0x%04x", pCommandDisconnectionReq->scid); - // response - l2cap_discon_req_cp Rsp; - Rsp.dcid = pCommandDisconnectionReq->dcid; - Rsp.scid = pCommandDisconnectionReq->scid; + // response + l2cap_discon_req_cp Rsp; + Rsp.dcid = pCommandDisconnectionReq->dcid; + Rsp.scid = pCommandDisconnectionReq->scid; - INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] SendDisconnectionResponse"); - SendCommandToACL(_Ident, L2CAP_DISCONNECT_RSP, sizeof(l2cap_discon_req_cp), (u8*)&Rsp); + INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] SendDisconnectionResponse"); + SendCommandToACL(_Ident, L2CAP_DISCONNECT_RSP, sizeof(l2cap_discon_req_cp), (u8*)&Rsp); } // @@ -549,88 +546,92 @@ void CWII_IPC_HLE_WiiMote::ReceiveDisconnectionReq(u8 _Ident, u8* _pData, u32 _S // We assume Wiimote is always connected void CWII_IPC_HLE_WiiMote::SendConnectionRequest(u16 scid, u16 psm) { - // create the channel - SChannel& rChannel = m_Channel[scid]; - rChannel.PSM = psm; - rChannel.SCID = scid; + // create the channel + SChannel& rChannel = m_Channel[scid]; + rChannel.PSM = psm; + rChannel.SCID = scid; - l2cap_con_req_cp cr; - cr.psm = psm; - cr.scid = scid; + l2cap_con_req_cp cr; + cr.psm = psm; + cr.scid = scid; - INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] SendConnectionRequest"); - DEBUG_LOG(WII_IPC_WIIMOTE, " Psm: 0x%04x", cr.psm); - DEBUG_LOG(WII_IPC_WIIMOTE, " Scid: 0x%04x", cr.scid); + INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] SendConnectionRequest"); + DEBUG_LOG(WII_IPC_WIIMOTE, " Psm: 0x%04x", cr.psm); + DEBUG_LOG(WII_IPC_WIIMOTE, " Scid: 0x%04x", cr.scid); - SendCommandToACL(L2CAP_CONNECT_REQ, L2CAP_CONNECT_REQ, sizeof(l2cap_con_req_cp), (u8*)&cr); + SendCommandToACL(L2CAP_CONNECT_REQ, L2CAP_CONNECT_REQ, sizeof(l2cap_con_req_cp), (u8*)&cr); } // We don't initially disconnect Wiimote though ... void CWII_IPC_HLE_WiiMote::SendDisconnectRequest(u16 scid) { - // create the channel - SChannel& rChannel = m_Channel[scid]; + // create the channel + SChannel& rChannel = m_Channel[scid]; - l2cap_discon_req_cp cr; - cr.dcid = rChannel.DCID; - cr.scid = rChannel.SCID; + l2cap_discon_req_cp cr; + cr.dcid = rChannel.DCID; + cr.scid = rChannel.SCID; - INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] SendDisconnectionRequest"); - DEBUG_LOG(WII_IPC_WIIMOTE, " Dcid: 0x%04x", cr.dcid); - DEBUG_LOG(WII_IPC_WIIMOTE, " Scid: 0x%04x", cr.scid); + INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] SendDisconnectionRequest"); + DEBUG_LOG(WII_IPC_WIIMOTE, " Dcid: 0x%04x", cr.dcid); + DEBUG_LOG(WII_IPC_WIIMOTE, " Scid: 0x%04x", cr.scid); - SendCommandToACL(L2CAP_DISCONNECT_REQ, L2CAP_DISCONNECT_REQ, sizeof(l2cap_discon_req_cp), (u8*)&cr); + SendCommandToACL(L2CAP_DISCONNECT_REQ, L2CAP_DISCONNECT_REQ, sizeof(l2cap_discon_req_cp), + (u8*)&cr); } void CWII_IPC_HLE_WiiMote::SendConfigurationRequest(u16 scid, u16 MTU, u16 FlushTimeOut) { - _dbg_assert_(WII_IPC_WIIMOTE, DoesChannelExist(scid)); - SChannel& rChannel = m_Channel[scid]; + _dbg_assert_(WII_IPC_WIIMOTE, DoesChannelExist(scid)); + SChannel& rChannel = m_Channel[scid]; - u8 Buffer[1024]; - int Offset = 0; + u8 Buffer[1024]; + int Offset = 0; - l2cap_cfg_req_cp* cr = (l2cap_cfg_req_cp*)&Buffer[Offset]; - cr->dcid = rChannel.DCID; - cr->flags = 0; - Offset += sizeof(l2cap_cfg_req_cp); + l2cap_cfg_req_cp* cr = (l2cap_cfg_req_cp*)&Buffer[Offset]; + cr->dcid = rChannel.DCID; + cr->flags = 0; + Offset += sizeof(l2cap_cfg_req_cp); - INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] SendConfigurationRequest"); - DEBUG_LOG(WII_IPC_WIIMOTE, " Dcid: 0x%04x", cr->dcid); - DEBUG_LOG(WII_IPC_WIIMOTE, " Flags: 0x%04x", cr->flags); + INFO_LOG(WII_IPC_WIIMOTE, "[L2CAP] SendConfigurationRequest"); + DEBUG_LOG(WII_IPC_WIIMOTE, " Dcid: 0x%04x", cr->dcid); + DEBUG_LOG(WII_IPC_WIIMOTE, " Flags: 0x%04x", cr->flags); - l2cap_cfg_opt_t* pOptions; + l2cap_cfg_opt_t* pOptions; - // (shuffle2) currently we end up not appending options. this is because we don't - // negotiate after trying to set MTU = 0 fails (stack will respond with - // "configuration failed" msg...). This is still fine, we'll just use whatever the - // Bluetooth stack defaults to. - if (MTU || rChannel.MTU) - { - if (MTU == 0) - MTU = rChannel.MTU; - pOptions = (l2cap_cfg_opt_t*)&Buffer[Offset]; Offset += sizeof(l2cap_cfg_opt_t); - pOptions->type = L2CAP_OPT_MTU; - pOptions->length = L2CAP_OPT_MTU_SIZE; - *(u16*)&Buffer[Offset] = MTU; Offset += L2CAP_OPT_MTU_SIZE; - DEBUG_LOG(WII_IPC_WIIMOTE, " MTU: 0x%04x", MTU); - } + // (shuffle2) currently we end up not appending options. this is because we don't + // negotiate after trying to set MTU = 0 fails (stack will respond with + // "configuration failed" msg...). This is still fine, we'll just use whatever the + // Bluetooth stack defaults to. + if (MTU || rChannel.MTU) + { + if (MTU == 0) + MTU = rChannel.MTU; + pOptions = (l2cap_cfg_opt_t*)&Buffer[Offset]; + Offset += sizeof(l2cap_cfg_opt_t); + pOptions->type = L2CAP_OPT_MTU; + pOptions->length = L2CAP_OPT_MTU_SIZE; + *(u16*)&Buffer[Offset] = MTU; + Offset += L2CAP_OPT_MTU_SIZE; + DEBUG_LOG(WII_IPC_WIIMOTE, " MTU: 0x%04x", MTU); + } - if (FlushTimeOut || rChannel.FlushTimeOut) - { - if (FlushTimeOut == 0) - FlushTimeOut = rChannel.FlushTimeOut; - pOptions = (l2cap_cfg_opt_t*)&Buffer[Offset]; Offset += sizeof(l2cap_cfg_opt_t); - pOptions->type = L2CAP_OPT_FLUSH_TIMO; - pOptions->length = L2CAP_OPT_FLUSH_TIMO_SIZE; - *(u16*)&Buffer[Offset] = FlushTimeOut; Offset += L2CAP_OPT_FLUSH_TIMO_SIZE; - DEBUG_LOG(WII_IPC_WIIMOTE, " FlushTimeOut: 0x%04x", FlushTimeOut); - } + if (FlushTimeOut || rChannel.FlushTimeOut) + { + if (FlushTimeOut == 0) + FlushTimeOut = rChannel.FlushTimeOut; + pOptions = (l2cap_cfg_opt_t*)&Buffer[Offset]; + Offset += sizeof(l2cap_cfg_opt_t); + pOptions->type = L2CAP_OPT_FLUSH_TIMO; + pOptions->length = L2CAP_OPT_FLUSH_TIMO_SIZE; + *(u16*)&Buffer[Offset] = FlushTimeOut; + Offset += L2CAP_OPT_FLUSH_TIMO_SIZE; + DEBUG_LOG(WII_IPC_WIIMOTE, " FlushTimeOut: 0x%04x", FlushTimeOut); + } - SendCommandToACL(L2CAP_CONFIG_REQ, L2CAP_CONFIG_REQ, Offset, Buffer); + SendCommandToACL(L2CAP_CONFIG_REQ, L2CAP_CONFIG_REQ, Offset, Buffer); } - // // // @@ -642,188 +643,209 @@ void CWII_IPC_HLE_WiiMote::SendConfigurationRequest(u16 scid, u16 MTU, u16 Flush // // -#define SDP_UINT8 0x08 -#define SDP_UINT16 0x09 -#define SDP_UINT32 0x0A -#define SDP_SEQ8 0x35 -#define SDP_SEQ16 0x36 +#define SDP_UINT8 0x08 +#define SDP_UINT16 0x09 +#define SDP_UINT32 0x0A +#define SDP_SEQ8 0x35 +#define SDP_SEQ16 0x36 -void CWII_IPC_HLE_WiiMote::SDPSendServiceSearchResponse(u16 cid, u16 TransactionID, u8* pServiceSearchPattern, u16 MaximumServiceRecordCount) +void CWII_IPC_HLE_WiiMote::SDPSendServiceSearchResponse(u16 cid, u16 TransactionID, + u8* pServiceSearchPattern, + u16 MaximumServiceRecordCount) { - // verify block... we handle search pattern for HID service only - { - CBigEndianBuffer buffer(pServiceSearchPattern); - _dbg_assert_(WII_IPC_WIIMOTE, buffer.Read8(0) == SDP_SEQ8); // data sequence - _dbg_assert_(WII_IPC_WIIMOTE, buffer.Read8(1) == 0x03); // sequence size + // verify block... we handle search pattern for HID service only + { + CBigEndianBuffer buffer(pServiceSearchPattern); + _dbg_assert_(WII_IPC_WIIMOTE, buffer.Read8(0) == SDP_SEQ8); // data sequence + _dbg_assert_(WII_IPC_WIIMOTE, buffer.Read8(1) == 0x03); // sequence size - // HIDClassID - _dbg_assert_(WII_IPC_WIIMOTE, buffer.Read8(2) == 0x19); - _dbg_assert_(WII_IPC_WIIMOTE, buffer.Read16(3) == 0x1124); - } + // HIDClassID + _dbg_assert_(WII_IPC_WIIMOTE, buffer.Read8(2) == 0x19); + _dbg_assert_(WII_IPC_WIIMOTE, buffer.Read16(3) == 0x1124); + } - u8 DataFrame[1000]; - CBigEndianBuffer buffer(DataFrame); + u8 DataFrame[1000]; + CBigEndianBuffer buffer(DataFrame); - int Offset = 0; - l2cap_hdr_t* pHeader = (l2cap_hdr_t*)&DataFrame[Offset]; Offset += sizeof(l2cap_hdr_t); - pHeader->dcid = cid; + int Offset = 0; + l2cap_hdr_t* pHeader = (l2cap_hdr_t*)&DataFrame[Offset]; + Offset += sizeof(l2cap_hdr_t); + pHeader->dcid = cid; - buffer.Write8 (Offset, 0x03); Offset++; - buffer.Write16(Offset, TransactionID); Offset += 2; // Transaction ID - buffer.Write16(Offset, 0x0009); Offset += 2; // Param length - buffer.Write16(Offset, 0x0001); Offset += 2; // TotalServiceRecordCount - buffer.Write16(Offset, 0x0001); Offset += 2; // CurrentServiceRecordCount - buffer.Write32(Offset, 0x10000); Offset += 4; // ServiceRecordHandleList[4] - buffer.Write8(Offset, 0x00); Offset++; // No continuation state; + buffer.Write8(Offset, 0x03); + Offset++; + buffer.Write16(Offset, TransactionID); + Offset += 2; // Transaction ID + buffer.Write16(Offset, 0x0009); + Offset += 2; // Param length + buffer.Write16(Offset, 0x0001); + Offset += 2; // TotalServiceRecordCount + buffer.Write16(Offset, 0x0001); + Offset += 2; // CurrentServiceRecordCount + buffer.Write32(Offset, 0x10000); + Offset += 4; // ServiceRecordHandleList[4] + buffer.Write8(Offset, 0x00); + Offset++; // No continuation state; - - pHeader->length = (u16)(Offset - sizeof(l2cap_hdr_t)); - m_pHost->SendACLPacket(GetConnectionHandle(), DataFrame, pHeader->length + sizeof(l2cap_hdr_t)); + pHeader->length = (u16)(Offset - sizeof(l2cap_hdr_t)); + m_pHost->SendACLPacket(GetConnectionHandle(), DataFrame, pHeader->length + sizeof(l2cap_hdr_t)); } static u32 ParseCont(u8* pCont) { - u32 attribOffset = 0; - CBigEndianBuffer attribList(pCont); - u8 typeID = attribList.Read8(attribOffset); attribOffset++; + u32 attribOffset = 0; + CBigEndianBuffer attribList(pCont); + u8 typeID = attribList.Read8(attribOffset); + attribOffset++; - if (typeID == 0x02) - { - return attribList.Read16(attribOffset); - } - else if (typeID == 0x00) - { - return 0x00; - } - ERROR_LOG(WII_IPC_WIIMOTE,"ParseCont: wrong cont: %i", typeID); - PanicAlert("ParseCont: wrong cont: %i", typeID); - return 0; + if (typeID == 0x02) + { + return attribList.Read16(attribOffset); + } + else if (typeID == 0x00) + { + return 0x00; + } + ERROR_LOG(WII_IPC_WIIMOTE, "ParseCont: wrong cont: %i", typeID); + PanicAlert("ParseCont: wrong cont: %i", typeID); + return 0; } - static int ParseAttribList(u8* pAttribIDList, u16& _startID, u16& _endID) { - u32 attribOffset = 0; - CBigEndianBuffer attribList(pAttribIDList); + u32 attribOffset = 0; + CBigEndianBuffer attribList(pAttribIDList); - u8 sequence = attribList.Read8(attribOffset); attribOffset++; - u8 seqSize = attribList.Read8(attribOffset); attribOffset++; - u8 typeID = attribList.Read8(attribOffset); attribOffset++; + u8 sequence = attribList.Read8(attribOffset); + attribOffset++; + u8 seqSize = attribList.Read8(attribOffset); + attribOffset++; + u8 typeID = attribList.Read8(attribOffset); + attribOffset++; - if (MAX_LOGLEVEL >= LogTypes::LOG_LEVELS::LDEBUG) - { - _dbg_assert_(WII_IPC_WIIMOTE, sequence == SDP_SEQ8); - (void)seqSize; - } + if (MAX_LOGLEVEL >= LogTypes::LOG_LEVELS::LDEBUG) + { + _dbg_assert_(WII_IPC_WIIMOTE, sequence == SDP_SEQ8); + (void)seqSize; + } - if (typeID == SDP_UINT32) - { - _startID = attribList.Read16(attribOffset); attribOffset += 2; - _endID = attribList.Read16(attribOffset); attribOffset += 2; - } - else - { - _startID = attribList.Read16(attribOffset); attribOffset += 2; - _endID = _startID; - DEBUG_LOG(WII_IPC_WIIMOTE, "Read just a single attrib - not tested"); - PanicAlert("Read just a single attrib - not tested"); - } + if (typeID == SDP_UINT32) + { + _startID = attribList.Read16(attribOffset); + attribOffset += 2; + _endID = attribList.Read16(attribOffset); + attribOffset += 2; + } + else + { + _startID = attribList.Read16(attribOffset); + attribOffset += 2; + _endID = _startID; + DEBUG_LOG(WII_IPC_WIIMOTE, "Read just a single attrib - not tested"); + PanicAlert("Read just a single attrib - not tested"); + } - return attribOffset; + return attribOffset; } - -void CWII_IPC_HLE_WiiMote::SDPSendServiceAttributeResponse(u16 cid, u16 TransactionID, u32 ServiceHandle, - u16 startAttrID, u16 endAttrID, - u16 MaximumAttributeByteCount, u8* pContinuationState) +void CWII_IPC_HLE_WiiMote::SDPSendServiceAttributeResponse(u16 cid, u16 TransactionID, + u32 ServiceHandle, u16 startAttrID, + u16 endAttrID, + u16 MaximumAttributeByteCount, + u8* pContinuationState) { - if (ServiceHandle != 0x10000) - { - ERROR_LOG(WII_IPC_WIIMOTE, "Unknown service handle %x" , ServiceHandle); - PanicAlert("Unknown service handle %x" , ServiceHandle); - } + if (ServiceHandle != 0x10000) + { + ERROR_LOG(WII_IPC_WIIMOTE, "Unknown service handle %x", ServiceHandle); + PanicAlert("Unknown service handle %x", ServiceHandle); + } + // _dbg_assert_(WII_IPC_WIIMOTE, ServiceHandle == 0x10000); - // _dbg_assert_(WII_IPC_WIIMOTE, ServiceHandle == 0x10000); + u32 contState = ParseCont(pContinuationState); - u32 contState = ParseCont(pContinuationState); + u32 packetSize = 0; + const u8* pPacket = GetAttribPacket(ServiceHandle, contState, packetSize); - u32 packetSize = 0; - const u8* pPacket = GetAttribPacket(ServiceHandle, contState, packetSize); + // generate package + u8 DataFrame[1000]; + CBigEndianBuffer buffer(DataFrame); - // generate package - u8 DataFrame[1000]; - CBigEndianBuffer buffer(DataFrame); + int Offset = 0; + l2cap_hdr_t* pHeader = (l2cap_hdr_t*)&DataFrame[Offset]; + Offset += sizeof(l2cap_hdr_t); + pHeader->dcid = cid; - int Offset = 0; - l2cap_hdr_t* pHeader = (l2cap_hdr_t*)&DataFrame[Offset]; Offset += sizeof(l2cap_hdr_t); - pHeader->dcid = cid; + buffer.Write8(Offset, 0x05); + Offset++; + buffer.Write16(Offset, TransactionID); + Offset += 2; // Transaction ID - buffer.Write8 (Offset, 0x05); Offset++; - buffer.Write16(Offset, TransactionID); Offset += 2; // Transaction ID + memcpy(buffer.GetPointer(Offset), pPacket, packetSize); + Offset += packetSize; - memcpy(buffer.GetPointer(Offset), pPacket, packetSize); Offset += packetSize; + pHeader->length = (u16)(Offset - sizeof(l2cap_hdr_t)); + m_pHost->SendACLPacket(GetConnectionHandle(), DataFrame, pHeader->length + sizeof(l2cap_hdr_t)); - pHeader->length = (u16)(Offset - sizeof(l2cap_hdr_t)); - m_pHost->SendACLPacket(GetConnectionHandle(), DataFrame, pHeader->length + sizeof(l2cap_hdr_t)); - - // Debugger::PrintDataBuffer(LogTypes::WIIMOTE, DataFrame, pHeader->length + sizeof(l2cap_hdr_t), "test response: "); + // Debugger::PrintDataBuffer(LogTypes::WIIMOTE, DataFrame, pHeader->length + sizeof(l2cap_hdr_t), + // "test response: "); } void CWII_IPC_HLE_WiiMote::HandleSDP(u16 cid, u8* _pData, u32 _Size) { - // Debugger::PrintDataBuffer(LogTypes::WIIMOTE, _pData, _Size, "HandleSDP: "); + // Debugger::PrintDataBuffer(LogTypes::WIIMOTE, _pData, _Size, "HandleSDP: "); - CBigEndianBuffer buffer(_pData); + CBigEndianBuffer buffer(_pData); - switch (buffer.Read8(0)) - { - // SDP_ServiceSearchRequest - case 0x02: - { - WARN_LOG(WII_IPC_WIIMOTE, "!!! SDP_ServiceSearchRequest !!!"); + switch (buffer.Read8(0)) + { + // SDP_ServiceSearchRequest + case 0x02: + { + WARN_LOG(WII_IPC_WIIMOTE, "!!! SDP_ServiceSearchRequest !!!"); - _dbg_assert_(WII_IPC_WIIMOTE, _Size == 13); + _dbg_assert_(WII_IPC_WIIMOTE, _Size == 13); - u16 TransactionID = buffer.Read16(1); - u8* pServiceSearchPattern = buffer.GetPointer(5); - u16 MaximumServiceRecordCount = buffer.Read16(10); + u16 TransactionID = buffer.Read16(1); + u8* pServiceSearchPattern = buffer.GetPointer(5); + u16 MaximumServiceRecordCount = buffer.Read16(10); - SDPSendServiceSearchResponse(cid, TransactionID, pServiceSearchPattern, MaximumServiceRecordCount); - } - break; + SDPSendServiceSearchResponse(cid, TransactionID, pServiceSearchPattern, + MaximumServiceRecordCount); + } + break; - // SDP_ServiceAttributeRequest - case 0x04: - { - WARN_LOG(WII_IPC_WIIMOTE, "!!! SDP_ServiceAttributeRequest !!!"); + // SDP_ServiceAttributeRequest + case 0x04: + { + WARN_LOG(WII_IPC_WIIMOTE, "!!! SDP_ServiceAttributeRequest !!!"); - u16 startAttrID, endAttrID; - u32 offset = 1; + u16 startAttrID, endAttrID; + u32 offset = 1; - u16 TransactionID = buffer.Read16(offset); - offset += 2; - // u16 ParameterLength = buffer.Read16(offset); - offset += 2; - u32 ServiceHandle = buffer.Read32(offset); - offset += 4; - u16 MaximumAttributeByteCount = buffer.Read16(offset); - offset += 2; - offset += ParseAttribList(buffer.GetPointer(offset), startAttrID, endAttrID); - u8* pContinuationState = buffer.GetPointer(offset); + u16 TransactionID = buffer.Read16(offset); + offset += 2; + // u16 ParameterLength = buffer.Read16(offset); + offset += 2; + u32 ServiceHandle = buffer.Read32(offset); + offset += 4; + u16 MaximumAttributeByteCount = buffer.Read16(offset); + offset += 2; + offset += ParseAttribList(buffer.GetPointer(offset), startAttrID, endAttrID); + u8* pContinuationState = buffer.GetPointer(offset); - SDPSendServiceAttributeResponse(cid, TransactionID, ServiceHandle, startAttrID, endAttrID, MaximumAttributeByteCount, pContinuationState); - } - break; + SDPSendServiceAttributeResponse(cid, TransactionID, ServiceHandle, startAttrID, endAttrID, + MaximumAttributeByteCount, pContinuationState); + } + break; - default: - ERROR_LOG(WII_IPC_WIIMOTE, "WIIMOTE: Unknown SDP command %x", _pData[0]); - PanicAlert("WIIMOTE: Unknown SDP command %x", _pData[0]); - break; - } + default: + ERROR_LOG(WII_IPC_WIIMOTE, "WIIMOTE: Unknown SDP command %x", _pData[0]); + PanicAlert("WIIMOTE: Unknown SDP command %x", _pData[0]); + break; + } } - // // // @@ -835,77 +857,77 @@ void CWII_IPC_HLE_WiiMote::HandleSDP(u16 cid, u8* _pData, u32 _Size) // // -void CWII_IPC_HLE_WiiMote::SendCommandToACL(u8 _Ident, u8 _Code, u8 _CommandLength, u8* _pCommandData) +void CWII_IPC_HLE_WiiMote::SendCommandToACL(u8 _Ident, u8 _Code, u8 _CommandLength, + u8* _pCommandData) { - u8 DataFrame[1024]; - u32 Offset = 0; + u8 DataFrame[1024]; + u32 Offset = 0; - l2cap_hdr_t* pHeader = (l2cap_hdr_t*)&DataFrame[Offset]; Offset += sizeof(l2cap_hdr_t); - pHeader->length = sizeof(l2cap_cmd_hdr_t) + _CommandLength; - pHeader->dcid = L2CAP_SIGNAL_CID; + l2cap_hdr_t* pHeader = (l2cap_hdr_t*)&DataFrame[Offset]; + Offset += sizeof(l2cap_hdr_t); + pHeader->length = sizeof(l2cap_cmd_hdr_t) + _CommandLength; + pHeader->dcid = L2CAP_SIGNAL_CID; - l2cap_cmd_hdr_t* pCommand = (l2cap_cmd_hdr_t*)&DataFrame[Offset]; Offset += sizeof(l2cap_cmd_hdr_t); - pCommand->code = _Code; - pCommand->ident = _Ident; - pCommand->length = _CommandLength; + l2cap_cmd_hdr_t* pCommand = (l2cap_cmd_hdr_t*)&DataFrame[Offset]; + Offset += sizeof(l2cap_cmd_hdr_t); + pCommand->code = _Code; + pCommand->ident = _Ident; + pCommand->length = _CommandLength; - memcpy(&DataFrame[Offset], _pCommandData, _CommandLength); + memcpy(&DataFrame[Offset], _pCommandData, _CommandLength); - INFO_LOG(WII_IPC_WIIMOTE, "Send ACL Command to CPU"); - DEBUG_LOG(WII_IPC_WIIMOTE, " Ident: 0x%02x", _Ident); - DEBUG_LOG(WII_IPC_WIIMOTE, " Code: 0x%02x", _Code); + INFO_LOG(WII_IPC_WIIMOTE, "Send ACL Command to CPU"); + DEBUG_LOG(WII_IPC_WIIMOTE, " Ident: 0x%02x", _Ident); + DEBUG_LOG(WII_IPC_WIIMOTE, " Code: 0x%02x", _Code); - // send .... - m_pHost->SendACLPacket(GetConnectionHandle(), DataFrame, pHeader->length + sizeof(l2cap_hdr_t)); + // send .... + m_pHost->SendACLPacket(GetConnectionHandle(), DataFrame, pHeader->length + sizeof(l2cap_hdr_t)); - //Debugger::PrintDataBuffer(LogTypes::WIIMOTE, DataFrame, pHeader->length + sizeof(l2cap_hdr_t), "m_pHost->SendACLPacket: "); + // Debugger::PrintDataBuffer(LogTypes::WIIMOTE, DataFrame, pHeader->length + sizeof(l2cap_hdr_t), + // "m_pHost->SendACLPacket: "); } void CWII_IPC_HLE_WiiMote::ReceiveL2capData(u16 scid, const void* _pData, u32 _Size) { + // Allocate DataFrame + u8 DataFrame[1024]; + u32 Offset = 0; + l2cap_hdr_t* pHeader = (l2cap_hdr_t*)DataFrame; + Offset += sizeof(l2cap_hdr_t); - // Allocate DataFrame - u8 DataFrame[1024]; - u32 Offset = 0; - l2cap_hdr_t* pHeader = (l2cap_hdr_t*)DataFrame; - Offset += sizeof(l2cap_hdr_t); + // Check if we are already reporting on this channel + _dbg_assert_(WII_IPC_WIIMOTE, DoesChannelExist(scid)); + SChannel& rChannel = m_Channel[scid]; - // Check if we are already reporting on this channel - _dbg_assert_(WII_IPC_WIIMOTE, DoesChannelExist(scid)); - SChannel& rChannel = m_Channel[scid]; + // Add an additional 4 byte header to the Wiimote report + pHeader->dcid = rChannel.DCID; + pHeader->length = _Size; - // Add an additional 4 byte header to the Wiimote report - pHeader->dcid = rChannel.DCID; - pHeader->length = _Size; + // Copy the Wiimote report to DataFrame + memcpy(DataFrame + Offset, _pData, _Size); + // Update Offset to the final size of the report + Offset += _Size; - // Copy the Wiimote report to DataFrame - memcpy(DataFrame + Offset, _pData, _Size); - // Update Offset to the final size of the report - Offset += _Size; + // Update the status bar + Host_SetWiiMoteConnectionState(2); - // Update the status bar - Host_SetWiiMoteConnectionState(2); - - // Send the report - m_pHost->SendACLPacket(GetConnectionHandle(), DataFrame, Offset); + // Send the report + m_pHost->SendACLPacket(GetConnectionHandle(), DataFrame, Offset); } - - namespace Core { - /* This is called continuously from the Wiimote plugin as soon as it has received - a reporting mode. _Size is the byte size of the report. */ - void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size) - { - const u8* pData = (const u8*)_pData; +/* This is called continuously from the Wiimote plugin as soon as it has received + a reporting mode. _Size is the byte size of the report. */ +void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size) +{ + const u8* pData = (const u8*)_pData; - INFO_LOG(WIIMOTE, "===================="); - INFO_LOG(WIIMOTE, "Callback_WiimoteInterruptChannel: (Wiimote: #%i)", _number); - DEBUG_LOG(WIIMOTE, " Data: %s", ArrayToString(pData, _Size, 50).c_str()); - DEBUG_LOG(WIIMOTE, " Channel: %x", _channelID); + INFO_LOG(WIIMOTE, "===================="); + INFO_LOG(WIIMOTE, "Callback_WiimoteInterruptChannel: (Wiimote: #%i)", _number); + DEBUG_LOG(WIIMOTE, " Data: %s", ArrayToString(pData, _Size, 50).c_str()); + DEBUG_LOG(WIIMOTE, " Channel: %x", _channelID); - s_Usb->m_WiiMotes[_number].ReceiveL2capData(_channelID, _pData, _Size); - } + s_Usb->m_WiiMotes[_number].ReceiveL2capData(_channelID, _pData, _Size); +} } - diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.h index e9b5bbc3e9..b9cf483234 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_WiiMote.h @@ -20,125 +20,116 @@ void SetUsbPointer(CWII_IPC_HLE_Device_usb_oh1_57e_305* ptr); class CBigEndianBuffer { public: - CBigEndianBuffer(u8* pBuffer) : m_pBuffer(pBuffer) {} - - u8 Read8(u32 offset) const { return m_pBuffer[offset]; } - u16 Read16(u32 offset) const { return Common::swap16(*(u16*)&m_pBuffer[offset]); } - u32 Read32(u32 offset) const { return Common::swap32(*(u32*)&m_pBuffer[offset]); } - - void Write8(u32 offset, u8 data) { m_pBuffer[offset] = data; } - void Write16(u32 offset, u16 data) { *(u16*)&m_pBuffer[offset] = Common::swap16(data); } - void Write32(u32 offset, u32 data) { *(u32*)&m_pBuffer[offset] = Common::swap32(data); } - - u8* GetPointer(u32 offset) { return &m_pBuffer[offset]; } - + CBigEndianBuffer(u8* pBuffer) : m_pBuffer(pBuffer) {} + u8 Read8(u32 offset) const { return m_pBuffer[offset]; } + u16 Read16(u32 offset) const { return Common::swap16(*(u16*)&m_pBuffer[offset]); } + u32 Read32(u32 offset) const { return Common::swap32(*(u32*)&m_pBuffer[offset]); } + void Write8(u32 offset, u8 data) { m_pBuffer[offset] = data; } + void Write16(u32 offset, u16 data) { *(u16*)&m_pBuffer[offset] = Common::swap16(data); } + void Write32(u32 offset, u32 data) { *(u32*)&m_pBuffer[offset] = Common::swap32(data); } + u8* GetPointer(u32 offset) { return &m_pBuffer[offset]; } private: - u8* m_pBuffer; + u8* m_pBuffer; }; - class CWII_IPC_HLE_WiiMote { public: - CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305* _pHost, int _Number, bdaddr_t _BD, bool ready = false); + CWII_IPC_HLE_WiiMote(CWII_IPC_HLE_Device_usb_oh1_57e_305* _pHost, int _Number, bdaddr_t _BD, + bool ready = false); - virtual ~CWII_IPC_HLE_WiiMote() {} + virtual ~CWII_IPC_HLE_WiiMote() {} + void DoState(PointerWrap& p); - void DoState(PointerWrap &p); + // ugly Host handling.... + // we really have to clean all this code - // ugly Host handling.... - // we really have to clean all this code + bool IsConnected() const { return m_ConnectionState == CONN_COMPLETE; } + bool IsInactive() const { return m_ConnectionState == CONN_INACTIVE; } + bool LinkChannel(); + void ResetChannels(); + void Activate(bool ready); + void ExecuteL2capCmd(u8* _pData, u32 _Size); // From CPU + void ReceiveL2capData(u16 scid, const void* _pData, u32 _Size); // From Wiimote - bool IsConnected() const { return m_ConnectionState == CONN_COMPLETE; } - bool IsInactive() const { return m_ConnectionState == CONN_INACTIVE; } - bool LinkChannel(); - void ResetChannels(); - void Activate(bool ready); - void ExecuteL2capCmd(u8* _pData, u32 _Size); // From CPU - void ReceiveL2capData(u16 scid, const void* _pData, u32 _Size); // From Wiimote - - void EventConnectionAccepted(); - void EventDisconnect(); - bool EventPagingChanged(u8 _pageMode); - - const bdaddr_t& GetBD() const { return m_BD; } - const uint8_t* GetClass() const { return uclass; } - u16 GetConnectionHandle() const { return m_ConnectionHandle; } - const u8* GetFeatures() const { return features; } - const char* GetName() const { return m_Name.c_str(); } - u8 GetLMPVersion() const { return lmp_version; } - u16 GetLMPSubVersion() const { return lmp_subversion; } - u16 GetManufactorID() const { return 0x000F; } // Broadcom Corporation - const u8* GetLinkKey() const { return m_LinkKey; } + void EventConnectionAccepted(); + void EventDisconnect(); + bool EventPagingChanged(u8 _pageMode); + const bdaddr_t& GetBD() const { return m_BD; } + const uint8_t* GetClass() const { return uclass; } + u16 GetConnectionHandle() const { return m_ConnectionHandle; } + const u8* GetFeatures() const { return features; } + const char* GetName() const { return m_Name.c_str(); } + u8 GetLMPVersion() const { return lmp_version; } + u16 GetLMPSubVersion() const { return lmp_subversion; } + u16 GetManufactorID() const { return 0x000F; } // Broadcom Corporation + const u8* GetLinkKey() const { return m_LinkKey; } private: - enum ConnectionState - { - CONN_INACTIVE = -1, - CONN_READY, - CONN_LINKING, - CONN_COMPLETE - }; - ConnectionState m_ConnectionState; + enum ConnectionState + { + CONN_INACTIVE = -1, + CONN_READY, + CONN_LINKING, + CONN_COMPLETE + }; + ConnectionState m_ConnectionState; - bool m_HIDControlChannel_Connected; - bool m_HIDControlChannel_ConnectedWait; - bool m_HIDControlChannel_Config; - bool m_HIDControlChannel_ConfigWait; - bool m_HIDInterruptChannel_Connected; - bool m_HIDInterruptChannel_ConnectedWait; - bool m_HIDInterruptChannel_Config; - bool m_HIDInterruptChannel_ConfigWait; + bool m_HIDControlChannel_Connected; + bool m_HIDControlChannel_ConnectedWait; + bool m_HIDControlChannel_Config; + bool m_HIDControlChannel_ConfigWait; + bool m_HIDInterruptChannel_Connected; + bool m_HIDInterruptChannel_ConnectedWait; + bool m_HIDInterruptChannel_Config; + bool m_HIDInterruptChannel_ConfigWait; - // STATE_TO_SAVE - bdaddr_t m_BD; - u16 m_ConnectionHandle; - uint8_t uclass[HCI_CLASS_SIZE]; - u8 features[HCI_FEATURES_SIZE]; - u8 lmp_version; - u16 lmp_subversion; - u8 m_LinkKey[HCI_KEY_SIZE]; - std::string m_Name; - CWII_IPC_HLE_Device_usb_oh1_57e_305* m_pHost; + // STATE_TO_SAVE + bdaddr_t m_BD; + u16 m_ConnectionHandle; + uint8_t uclass[HCI_CLASS_SIZE]; + u8 features[HCI_FEATURES_SIZE]; + u8 lmp_version; + u16 lmp_subversion; + u8 m_LinkKey[HCI_KEY_SIZE]; + std::string m_Name; + CWII_IPC_HLE_Device_usb_oh1_57e_305* m_pHost; - struct SChannel - { - u16 SCID; - u16 DCID; - u16 PSM; + struct SChannel + { + u16 SCID; + u16 DCID; + u16 PSM; - u16 MTU; - u16 FlushTimeOut; - }; + u16 MTU; + u16 FlushTimeOut; + }; - typedef std::map CChannelMap; - CChannelMap m_Channel; + typedef std::map CChannelMap; + CChannelMap m_Channel; - bool DoesChannelExist(u16 _SCID) - { - return m_Channel.find(_SCID) != m_Channel.end(); - } + bool DoesChannelExist(u16 _SCID) { return m_Channel.find(_SCID) != m_Channel.end(); } + void SendCommandToACL(u8 _Ident, u8 _Code, u8 _CommandLength, u8* _pCommandData); - void SendCommandToACL(u8 _Ident, u8 _Code, u8 _CommandLength, u8* _pCommandData); + void SignalChannel(u8* _pData, u32 _Size); - void SignalChannel(u8* _pData, u32 _Size); + void SendConnectionRequest(u16 _SCID, u16 _PSM); + void SendConfigurationRequest(u16 _SCID, u16 _pMTU = 0, u16 _pFlushTimeOut = 0); + void SendDisconnectRequest(u16 _SCID); - void SendConnectionRequest(u16 _SCID, u16 _PSM); - void SendConfigurationRequest(u16 _SCID, u16 _pMTU = 0, u16 _pFlushTimeOut = 0); - void SendDisconnectRequest(u16 _SCID); + void ReceiveConnectionReq(u8 _Ident, u8* _pData, u32 _Size); + void ReceiveConnectionResponse(u8 _Ident, u8* _pData, u32 _Size); + void ReceiveDisconnectionReq(u8 _Ident, u8* _pData, u32 _Size); + void ReceiveConfigurationReq(u8 _Ident, u8* _pData, u32 _Size); + void ReceiveConfigurationResponse(u8 _Ident, u8* _pData, u32 _Size); - void ReceiveConnectionReq(u8 _Ident, u8* _pData, u32 _Size); - void ReceiveConnectionResponse(u8 _Ident, u8* _pData, u32 _Size); - void ReceiveDisconnectionReq(u8 _Ident, u8* _pData, u32 _Size); - void ReceiveConfigurationReq(u8 _Ident, u8* _pData, u32 _Size); - void ReceiveConfigurationResponse(u8 _Ident, u8* _pData, u32 _Size); + // some new ugly stuff + // should be inside the plugin + void HandleSDP(u16 _SCID, u8* _pData, u32 _Size); + void SDPSendServiceSearchResponse(u16 _SCID, u16 _TransactionID, u8* _pServiceSearchPattern, + u16 _MaximumServiceRecordCount); - // some new ugly stuff - // should be inside the plugin - void HandleSDP(u16 _SCID, u8* _pData, u32 _Size); - void SDPSendServiceSearchResponse(u16 _SCID, u16 _TransactionID, u8* _pServiceSearchPattern, u16 _MaximumServiceRecordCount); - - void SDPSendServiceAttributeResponse(u16 _SCID, u16 TransactionID, u32 _ServiceHandle, - u16 _StartAttrID, u16 _EndAttrID, - u16 _MaximumAttributeByteCount, u8* _pContinuationState); + void SDPSendServiceAttributeResponse(u16 _SCID, u16 TransactionID, u32 _ServiceHandle, + u16 _StartAttrID, u16 _EndAttrID, + u16 _MaximumAttributeByteCount, u8* _pContinuationState); }; diff --git a/Source/Core/Core/IPC_HLE/WII_Socket.cpp b/Source/Core/Core/IPC_HLE/WII_Socket.cpp index a4dde7f50b..1608316061 100644 --- a/Source/Core/Core/IPC_HLE/WII_Socket.cpp +++ b/Source/Core/Core/IPC_HLE/WII_Socket.cpp @@ -11,10 +11,10 @@ #include "Core/Core.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device.h" -#include "Core/IPC_HLE/WII_Socket.h" // No Wii socket support while using NetPlay or TAS +#include "Core/IPC_HLE/WII_Socket.h" // No Wii socket support while using NetPlay or TAS #ifdef _WIN32 -#define ERRORCODE(name) WSA ## name +#define ERRORCODE(name) WSA##name #define EITHER(win32, posix) win32 #else #define ERRORCODE(name) name @@ -24,652 +24,639 @@ char* WiiSockMan::DecodeError(s32 ErrorCode) { #ifdef _WIN32 - // NOT THREAD SAFE - static char Message[1024]; + // NOT THREAD SAFE + static char Message[1024]; - FormatMessageA( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, - nullptr, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), Message, - sizeof(Message), nullptr); + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_MAX_WIDTH_MASK, + nullptr, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), Message, + sizeof(Message), nullptr); - return Message; + return Message; #else - return strerror(ErrorCode); + return strerror(ErrorCode); #endif } static s32 TranslateErrorCode(s32 native_error, bool isRW) { - switch (native_error) - { - case ERRORCODE(EMSGSIZE): - ERROR_LOG(WII_IPC_NET, "Find out why this happened, looks like PEEK failure?"); - return -1; // Should be -SO_EMSGSIZE - case EITHER(WSAENOTSOCK, EBADF): - return -SO_EBADF; - case ERRORCODE(EADDRINUSE): - return -SO_EADDRINUSE; - case ERRORCODE(ECONNRESET): - return -SO_ECONNRESET; - case ERRORCODE(EISCONN): - return -SO_EISCONN; - case ERRORCODE(ENOTCONN): - return -SO_EAGAIN; // After proper blocking SO_EAGAIN shouldn't be needed... - case ERRORCODE(EINPROGRESS): - return -SO_EINPROGRESS; - case ERRORCODE(EALREADY): - return -SO_EALREADY; - case ERRORCODE(EACCES): - return -SO_EACCES; - case ERRORCODE(ECONNREFUSED): - return -SO_ECONNREFUSED; - case ERRORCODE(ENETUNREACH): - return -SO_ENETUNREACH; - case ERRORCODE(EHOSTUNREACH): - return -SO_EHOSTUNREACH; - case EITHER(WSAEWOULDBLOCK, EAGAIN): - if (isRW) - { - return -SO_EAGAIN; // EAGAIN - } - else - { - return -SO_EINPROGRESS; // EINPROGRESS - } - default: - return -1; - } + switch (native_error) + { + case ERRORCODE(EMSGSIZE): + ERROR_LOG(WII_IPC_NET, "Find out why this happened, looks like PEEK failure?"); + return -1; // Should be -SO_EMSGSIZE + case EITHER(WSAENOTSOCK, EBADF): + return -SO_EBADF; + case ERRORCODE(EADDRINUSE): + return -SO_EADDRINUSE; + case ERRORCODE(ECONNRESET): + return -SO_ECONNRESET; + case ERRORCODE(EISCONN): + return -SO_EISCONN; + case ERRORCODE(ENOTCONN): + return -SO_EAGAIN; // After proper blocking SO_EAGAIN shouldn't be needed... + case ERRORCODE(EINPROGRESS): + return -SO_EINPROGRESS; + case ERRORCODE(EALREADY): + return -SO_EALREADY; + case ERRORCODE(EACCES): + return -SO_EACCES; + case ERRORCODE(ECONNREFUSED): + return -SO_ECONNREFUSED; + case ERRORCODE(ENETUNREACH): + return -SO_ENETUNREACH; + case ERRORCODE(EHOSTUNREACH): + return -SO_EHOSTUNREACH; + case EITHER(WSAEWOULDBLOCK, EAGAIN): + if (isRW) + { + return -SO_EAGAIN; // EAGAIN + } + else + { + return -SO_EINPROGRESS; // EINPROGRESS + } + default: + return -1; + } } // Don't use string! (see https://github.com/dolphin-emu/dolphin/pull/3143) s32 WiiSockMan::GetNetErrorCode(s32 ret, const char* caller, bool isRW) { #ifdef _WIN32 - s32 errorCode = WSAGetLastError(); + s32 errorCode = WSAGetLastError(); #else - s32 errorCode = errno; + s32 errorCode = errno; #endif - if (ret >= 0) - { - WiiSockMan::GetInstance().SetLastNetError(ret); - return ret; - } + if (ret >= 0) + { + WiiSockMan::GetInstance().SetLastNetError(ret); + return ret; + } - INFO_LOG(WII_IPC_NET, "%s failed with error %d: %s, ret= %d", - caller, errorCode, DecodeError(errorCode), ret); + INFO_LOG(WII_IPC_NET, "%s failed with error %d: %s, ret= %d", caller, errorCode, + DecodeError(errorCode), ret); - s32 ReturnValue = TranslateErrorCode(errorCode, isRW); - WiiSockMan::GetInstance().SetLastNetError(ReturnValue); + s32 ReturnValue = TranslateErrorCode(errorCode, isRW); + WiiSockMan::GetInstance().SetLastNetError(ReturnValue); - return ReturnValue; + return ReturnValue; } WiiSocket::~WiiSocket() { - if (fd >= 0) - { - (void)CloseFd(); - } + if (fd >= 0) + { + (void)CloseFd(); + } } void WiiSocket::SetFd(s32 s) { - if (fd >= 0) - (void)CloseFd(); + if (fd >= 0) + (void)CloseFd(); - nonBlock = false; - fd = s; + nonBlock = false; + fd = s; - // Set socket to NON-BLOCK +// Set socket to NON-BLOCK #ifdef _WIN32 - u_long iMode = 1; - ioctlsocket(fd, FIONBIO, &iMode); + u_long iMode = 1; + ioctlsocket(fd, FIONBIO, &iMode); #else - int flags; - if (-1 == (flags = fcntl(fd, F_GETFL, 0))) - flags = 0; - fcntl(fd, F_SETFL, flags | O_NONBLOCK); + int flags; + if (-1 == (flags = fcntl(fd, F_GETFL, 0))) + flags = 0; + fcntl(fd, F_SETFL, flags | O_NONBLOCK); #endif } s32 WiiSocket::CloseFd() { - s32 ReturnValue = 0; - if (fd >= 0) - { + s32 ReturnValue = 0; + if (fd >= 0) + { #ifdef _WIN32 - s32 ret = closesocket(fd); + s32 ret = closesocket(fd); #else - s32 ret = close(fd); + s32 ret = close(fd); #endif - ReturnValue = WiiSockMan::GetNetErrorCode(ret, "CloseFd", false); - } - else - { - ReturnValue = WiiSockMan::GetNetErrorCode(EITHER(WSAENOTSOCK, EBADF), "CloseFd", false); - } - fd = -1; - return ReturnValue; + ReturnValue = WiiSockMan::GetNetErrorCode(ret, "CloseFd", false); + } + else + { + ReturnValue = WiiSockMan::GetNetErrorCode(EITHER(WSAENOTSOCK, EBADF), "CloseFd", false); + } + fd = -1; + return ReturnValue; } s32 WiiSocket::FCntl(u32 cmd, u32 arg) { -#define F_GETFL 3 -#define F_SETFL 4 -#define F_NONBLOCK 4 - s32 ret = 0; - if (cmd == F_GETFL) - { - ret = nonBlock ? F_NONBLOCK : 0; - } - else if (cmd == F_SETFL) - { - nonBlock = (arg & F_NONBLOCK) == F_NONBLOCK; - } - else - { - ERROR_LOG(WII_IPC_NET, "SO_FCNTL unknown command"); - } +#define F_GETFL 3 +#define F_SETFL 4 +#define F_NONBLOCK 4 + s32 ret = 0; + if (cmd == F_GETFL) + { + ret = nonBlock ? F_NONBLOCK : 0; + } + else if (cmd == F_SETFL) + { + nonBlock = (arg & F_NONBLOCK) == F_NONBLOCK; + } + else + { + ERROR_LOG(WII_IPC_NET, "SO_FCNTL unknown command"); + } - INFO_LOG(WII_IPC_NET, "IOCTL_SO_FCNTL(%08x, %08X, %08X)", - fd, cmd, arg); + INFO_LOG(WII_IPC_NET, "IOCTL_SO_FCNTL(%08x, %08X, %08X)", fd, cmd, arg); - return ret; + return ret; } void WiiSocket::Update(bool read, bool write, bool except) { - auto it = pending_sockops.begin(); - while (it != pending_sockops.end()) - { - s32 ReturnValue = 0; - bool forceNonBlock = false; - IPCCommandType ct = static_cast(Memory::Read_U32(it->_CommandAddress)); - if (!it->is_ssl && ct == IPC_CMD_IOCTL) - { - u32 BufferIn = Memory::Read_U32(it->_CommandAddress + 0x10); - u32 BufferInSize = Memory::Read_U32(it->_CommandAddress + 0x14); - u32 BufferOut = Memory::Read_U32(it->_CommandAddress + 0x18); - u32 BufferOutSize = Memory::Read_U32(it->_CommandAddress + 0x1C); + auto it = pending_sockops.begin(); + while (it != pending_sockops.end()) + { + s32 ReturnValue = 0; + bool forceNonBlock = false; + IPCCommandType ct = static_cast(Memory::Read_U32(it->_CommandAddress)); + if (!it->is_ssl && ct == IPC_CMD_IOCTL) + { + u32 BufferIn = Memory::Read_U32(it->_CommandAddress + 0x10); + u32 BufferInSize = Memory::Read_U32(it->_CommandAddress + 0x14); + u32 BufferOut = Memory::Read_U32(it->_CommandAddress + 0x18); + u32 BufferOutSize = Memory::Read_U32(it->_CommandAddress + 0x1C); - switch (it->net_type) - { - case IOCTL_SO_FCNTL: - { - u32 cmd = Memory::Read_U32(BufferIn + 4); - u32 arg = Memory::Read_U32(BufferIn + 8); - ReturnValue = FCntl(cmd, arg); - break; - } - case IOCTL_SO_BIND: - { - //u32 has_addr = Memory::Read_U32(BufferIn + 0x04); - sockaddr_in local_name; - WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferIn + 0x08); - WiiSockMan::Convert(*wii_name, local_name); + switch (it->net_type) + { + case IOCTL_SO_FCNTL: + { + u32 cmd = Memory::Read_U32(BufferIn + 4); + u32 arg = Memory::Read_U32(BufferIn + 8); + ReturnValue = FCntl(cmd, arg); + break; + } + case IOCTL_SO_BIND: + { + // u32 has_addr = Memory::Read_U32(BufferIn + 0x04); + sockaddr_in local_name; + WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferIn + 0x08); + WiiSockMan::Convert(*wii_name, local_name); - int ret = bind(fd, (sockaddr*)&local_name, sizeof(local_name)); - ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_BIND", false); + int ret = bind(fd, (sockaddr*)&local_name, sizeof(local_name)); + ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_BIND", false); - INFO_LOG(WII_IPC_NET, "IOCTL_SO_BIND (%08X %s:%d) = %d ", fd, - inet_ntoa(local_name.sin_addr), Common::swap16(local_name.sin_port), ret); - break; - } - case IOCTL_SO_CONNECT: - { - //u32 has_addr = Memory::Read_U32(BufferIn + 0x04); - sockaddr_in local_name; - WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferIn + 0x08); - WiiSockMan::Convert(*wii_name, local_name); + INFO_LOG(WII_IPC_NET, "IOCTL_SO_BIND (%08X %s:%d) = %d ", fd, + inet_ntoa(local_name.sin_addr), Common::swap16(local_name.sin_port), ret); + break; + } + case IOCTL_SO_CONNECT: + { + // u32 has_addr = Memory::Read_U32(BufferIn + 0x04); + sockaddr_in local_name; + WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferIn + 0x08); + WiiSockMan::Convert(*wii_name, local_name); - int ret = connect(fd, (sockaddr*)&local_name, sizeof(local_name)); - ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_CONNECT", false); + int ret = connect(fd, (sockaddr*)&local_name, sizeof(local_name)); + ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_CONNECT", false); - INFO_LOG(WII_IPC_NET,"IOCTL_SO_CONNECT (%08x, %s:%d)", - fd, inet_ntoa(local_name.sin_addr), Common::swap16(local_name.sin_port)); - break; - } - case IOCTL_SO_ACCEPT: - { - if (BufferOutSize > 0) - { - sockaddr_in local_name; - WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferOut); - WiiSockMan::Convert(*wii_name, local_name); + INFO_LOG(WII_IPC_NET, "IOCTL_SO_CONNECT (%08x, %s:%d)", fd, inet_ntoa(local_name.sin_addr), + Common::swap16(local_name.sin_port)); + break; + } + case IOCTL_SO_ACCEPT: + { + if (BufferOutSize > 0) + { + sockaddr_in local_name; + WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferOut); + WiiSockMan::Convert(*wii_name, local_name); - socklen_t addrlen = sizeof(sockaddr_in); - int ret = (s32)accept(fd, (sockaddr*)&local_name, &addrlen); - ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_ACCEPT", true); + socklen_t addrlen = sizeof(sockaddr_in); + int ret = (s32)accept(fd, (sockaddr*)&local_name, &addrlen); + ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_ACCEPT", true); - WiiSockMan::Convert(local_name, *wii_name, addrlen); - } - else - { - int ret = (s32)accept(fd, nullptr, nullptr); - ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_ACCEPT", true); - } + WiiSockMan::Convert(local_name, *wii_name, addrlen); + } + else + { + int ret = (s32)accept(fd, nullptr, nullptr); + ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_ACCEPT", true); + } - WiiSockMan::GetInstance().AddSocket(ReturnValue); + WiiSockMan::GetInstance().AddSocket(ReturnValue); - INFO_LOG(WII_IPC_NET, "IOCTL_SO_ACCEPT " - "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - BufferIn, BufferInSize, BufferOut, BufferOutSize); + INFO_LOG(WII_IPC_NET, "IOCTL_SO_ACCEPT " + "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); - break; - } - default: - break; - } + break; + } + default: + break; + } - // Fix blocking error codes - if (!nonBlock) - { - if (it->net_type == IOCTL_SO_CONNECT && - ReturnValue == -SO_EISCONN) - { - ReturnValue = SO_SUCCESS; - } - } - } - else if (ct == IPC_CMD_IOCTLV) - { - SIOCtlVBuffer CommandBuffer(it->_CommandAddress); - u32 BufferIn = 0, BufferIn2 = 0; - u32 BufferInSize = 0, BufferInSize2 = 0; - u32 BufferOut = 0, BufferOut2 = 0; - u32 BufferOutSize = 0, BufferOutSize2 = 0; + // Fix blocking error codes + if (!nonBlock) + { + if (it->net_type == IOCTL_SO_CONNECT && ReturnValue == -SO_EISCONN) + { + ReturnValue = SO_SUCCESS; + } + } + } + else if (ct == IPC_CMD_IOCTLV) + { + SIOCtlVBuffer CommandBuffer(it->_CommandAddress); + u32 BufferIn = 0, BufferIn2 = 0; + u32 BufferInSize = 0, BufferInSize2 = 0; + u32 BufferOut = 0, BufferOut2 = 0; + u32 BufferOutSize = 0, BufferOutSize2 = 0; - if (CommandBuffer.InBuffer.size() > 0) - { - BufferIn = CommandBuffer.InBuffer.at(0).m_Address; - BufferInSize = CommandBuffer.InBuffer.at(0).m_Size; - } + if (CommandBuffer.InBuffer.size() > 0) + { + BufferIn = CommandBuffer.InBuffer.at(0).m_Address; + BufferInSize = CommandBuffer.InBuffer.at(0).m_Size; + } - if (CommandBuffer.PayloadBuffer.size() > 0) - { - BufferOut = CommandBuffer.PayloadBuffer.at(0).m_Address; - BufferOutSize = CommandBuffer.PayloadBuffer.at(0).m_Size; - } + if (CommandBuffer.PayloadBuffer.size() > 0) + { + BufferOut = CommandBuffer.PayloadBuffer.at(0).m_Address; + BufferOutSize = CommandBuffer.PayloadBuffer.at(0).m_Size; + } - if (CommandBuffer.PayloadBuffer.size() > 1) - { - BufferOut2 = CommandBuffer.PayloadBuffer.at(1).m_Address; - BufferOutSize2 = CommandBuffer.PayloadBuffer.at(1).m_Size; - } + if (CommandBuffer.PayloadBuffer.size() > 1) + { + BufferOut2 = CommandBuffer.PayloadBuffer.at(1).m_Address; + BufferOutSize2 = CommandBuffer.PayloadBuffer.at(1).m_Size; + } - if (CommandBuffer.InBuffer.size() > 1) - { - BufferIn2 = CommandBuffer.InBuffer.at(1).m_Address; - BufferInSize2 = CommandBuffer.InBuffer.at(1).m_Size; - } + if (CommandBuffer.InBuffer.size() > 1) + { + BufferIn2 = CommandBuffer.InBuffer.at(1).m_Address; + BufferInSize2 = CommandBuffer.InBuffer.at(1).m_Size; + } - if (it->is_ssl) - { - int sslID = Memory::Read_U32(BufferOut) - 1; - if (SSLID_VALID(sslID)) - { - switch (it->ssl_type) - { - case IOCTLV_NET_SSL_DOHANDSHAKE: - { + if (it->is_ssl) + { + int sslID = Memory::Read_U32(BufferOut) - 1; + if (SSLID_VALID(sslID)) + { + switch (it->ssl_type) + { + case IOCTLV_NET_SSL_DOHANDSHAKE: + { + int ret = mbedtls_ssl_handshake(&CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx); + switch (ret) + { + case 0: + Memory::Write_U32(SSL_OK, BufferIn); + break; + case MBEDTLS_ERR_SSL_WANT_READ: + Memory::Write_U32(SSL_ERR_RAGAIN, BufferIn); + if (!nonBlock) + ReturnValue = SSL_ERR_RAGAIN; + break; + case MBEDTLS_ERR_SSL_WANT_WRITE: + Memory::Write_U32(SSL_ERR_WAGAIN, BufferIn); + if (!nonBlock) + ReturnValue = SSL_ERR_WAGAIN; + break; + default: + Memory::Write_U32(SSL_ERR_FAILED, BufferIn); + break; + } - int ret = mbedtls_ssl_handshake(&CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx); - switch (ret) - { - case 0: - Memory::Write_U32(SSL_OK, BufferIn); - break; - case MBEDTLS_ERR_SSL_WANT_READ: - Memory::Write_U32(SSL_ERR_RAGAIN, BufferIn); - if (!nonBlock) - ReturnValue = SSL_ERR_RAGAIN; - break; - case MBEDTLS_ERR_SSL_WANT_WRITE: - Memory::Write_U32(SSL_ERR_WAGAIN, BufferIn); - if (!nonBlock) - ReturnValue = SSL_ERR_WAGAIN; - break; - default: - Memory::Write_U32(SSL_ERR_FAILED, BufferIn); - break; - } - - INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_DOHANDSHAKE = (%d) " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferOut: (%08x, %i), BufferOut2: (%08x, %i)", - ret, - BufferIn, BufferInSize, BufferIn2, BufferInSize2, - BufferOut, BufferOutSize, BufferOut2, BufferOutSize2); - break; - } - case IOCTLV_NET_SSL_WRITE: - { - int ret = mbedtls_ssl_write(&CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx, Memory::GetPointer(BufferOut2), BufferOutSize2); + INFO_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_DOHANDSHAKE = (%d) " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferOut: (%08x, %i), BufferOut2: (%08x, %i)", + ret, BufferIn, BufferInSize, BufferIn2, BufferInSize2, BufferOut, + BufferOutSize, BufferOut2, BufferOutSize2); + break; + } + case IOCTLV_NET_SSL_WRITE: + { + int ret = mbedtls_ssl_write(&CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx, + Memory::GetPointer(BufferOut2), BufferOutSize2); #ifdef DEBUG_SSL - File::IOFile("ssl_write.bin", "ab").WriteBytes(Memory::GetPointer(BufferOut2), BufferOutSize2); + File::IOFile("ssl_write.bin", "ab") + .WriteBytes(Memory::GetPointer(BufferOut2), BufferOutSize2); #endif - if (ret >= 0) - { - // Return bytes written or SSL_ERR_ZERO if none - Memory::Write_U32((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn); - } - else - { - switch (ret) - { - case MBEDTLS_ERR_SSL_WANT_READ: - Memory::Write_U32(SSL_ERR_RAGAIN, BufferIn); - if (!nonBlock) - ReturnValue = SSL_ERR_RAGAIN; - break; - case MBEDTLS_ERR_SSL_WANT_WRITE: - Memory::Write_U32(SSL_ERR_WAGAIN, BufferIn); - if (!nonBlock) - ReturnValue = SSL_ERR_WAGAIN; - break; - default: - Memory::Write_U32(SSL_ERR_FAILED, BufferIn); - break; - } - } - break; - } - case IOCTLV_NET_SSL_READ: - { - int ret = mbedtls_ssl_read(&CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx, Memory::GetPointer(BufferIn2), BufferInSize2); + if (ret >= 0) + { + // Return bytes written or SSL_ERR_ZERO if none + Memory::Write_U32((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn); + } + else + { + switch (ret) + { + case MBEDTLS_ERR_SSL_WANT_READ: + Memory::Write_U32(SSL_ERR_RAGAIN, BufferIn); + if (!nonBlock) + ReturnValue = SSL_ERR_RAGAIN; + break; + case MBEDTLS_ERR_SSL_WANT_WRITE: + Memory::Write_U32(SSL_ERR_WAGAIN, BufferIn); + if (!nonBlock) + ReturnValue = SSL_ERR_WAGAIN; + break; + default: + Memory::Write_U32(SSL_ERR_FAILED, BufferIn); + break; + } + } + break; + } + case IOCTLV_NET_SSL_READ: + { + int ret = mbedtls_ssl_read(&CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx, + Memory::GetPointer(BufferIn2), BufferInSize2); #ifdef DEBUG_SSL - if (ret > 0) - { - File::IOFile("ssl_read.bin", "ab").WriteBytes(Memory::GetPointer(BufferIn2), ret); - } + if (ret > 0) + { + File::IOFile("ssl_read.bin", "ab").WriteBytes(Memory::GetPointer(BufferIn2), ret); + } #endif - if (ret >= 0) - { - // Return bytes read or SSL_ERR_ZERO if none - Memory::Write_U32((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn); - } - else - { - switch (ret) - { - case MBEDTLS_ERR_SSL_WANT_READ: - Memory::Write_U32(SSL_ERR_RAGAIN, BufferIn); - if (!nonBlock) - ReturnValue = SSL_ERR_RAGAIN; - break; - case MBEDTLS_ERR_SSL_WANT_WRITE: - Memory::Write_U32(SSL_ERR_WAGAIN, BufferIn); - if (!nonBlock) - ReturnValue = SSL_ERR_WAGAIN; - break; - default: - Memory::Write_U32(SSL_ERR_FAILED, BufferIn); - break; - } - } - break; - } - default: - break; - } - } - else - { - Memory::Write_U32(SSL_ERR_ID, BufferIn); - } - } - else - { - switch (it->net_type) - { - case IOCTLV_SO_SENDTO: - { + if (ret >= 0) + { + // Return bytes read or SSL_ERR_ZERO if none + Memory::Write_U32((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn); + } + else + { + switch (ret) + { + case MBEDTLS_ERR_SSL_WANT_READ: + Memory::Write_U32(SSL_ERR_RAGAIN, BufferIn); + if (!nonBlock) + ReturnValue = SSL_ERR_RAGAIN; + break; + case MBEDTLS_ERR_SSL_WANT_WRITE: + Memory::Write_U32(SSL_ERR_WAGAIN, BufferIn); + if (!nonBlock) + ReturnValue = SSL_ERR_WAGAIN; + break; + default: + Memory::Write_U32(SSL_ERR_FAILED, BufferIn); + break; + } + } + break; + } + default: + break; + } + } + else + { + Memory::Write_U32(SSL_ERR_ID, BufferIn); + } + } + else + { + switch (it->net_type) + { + case IOCTLV_SO_SENDTO: + { + u32 flags = Memory::Read_U32(BufferIn2 + 0x04); + u32 has_destaddr = Memory::Read_U32(BufferIn2 + 0x08); - u32 flags = Memory::Read_U32(BufferIn2 + 0x04); - u32 has_destaddr = Memory::Read_U32(BufferIn2 + 0x08); + // Not a string, Windows requires a const char* for sendto + const char* data = (const char*)Memory::GetPointer(BufferIn); - // Not a string, Windows requires a const char* for sendto - const char* data = (const char*)Memory::GetPointer(BufferIn); + // Act as non blocking when SO_MSG_NONBLOCK is specified + forceNonBlock = ((flags & SO_MSG_NONBLOCK) == SO_MSG_NONBLOCK); + // send/sendto only handles MSG_OOB + flags &= SO_MSG_OOB; - // Act as non blocking when SO_MSG_NONBLOCK is specified - forceNonBlock = ((flags & SO_MSG_NONBLOCK) == SO_MSG_NONBLOCK); - // send/sendto only handles MSG_OOB - flags &= SO_MSG_OOB; + sockaddr_in local_name = {0}; + if (has_destaddr) + { + WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferIn2 + 0x0C); + WiiSockMan::Convert(*wii_name, local_name); + } - sockaddr_in local_name = {0}; - if (has_destaddr) - { - WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferIn2 + 0x0C); - WiiSockMan::Convert(*wii_name, local_name); - } + int ret = sendto(fd, data, BufferInSize, flags, + has_destaddr ? (struct sockaddr*)&local_name : nullptr, + has_destaddr ? sizeof(sockaddr) : 0); + ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_SENDTO", true); - int ret = sendto(fd, data, BufferInSize, flags, - has_destaddr ? (struct sockaddr*)&local_name : nullptr, - has_destaddr ? sizeof(sockaddr) : 0); - ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_SENDTO", true); + INFO_LOG(WII_IPC_NET, + "%s = %d Socket: %08x, BufferIn: (%08x, %i), BufferIn2: (%08x, %i), %u.%u.%u.%u", + has_destaddr ? "IOCTLV_SO_SENDTO " : "IOCTLV_SO_SEND ", ReturnValue, fd, + BufferIn, BufferInSize, BufferIn2, BufferInSize2, + local_name.sin_addr.s_addr & 0xFF, (local_name.sin_addr.s_addr >> 8) & 0xFF, + (local_name.sin_addr.s_addr >> 16) & 0xFF, + (local_name.sin_addr.s_addr >> 24) & 0xFF); + break; + } + case IOCTLV_SO_RECVFROM: + { + u32 flags = Memory::Read_U32(BufferIn + 0x04); + // Not a string, Windows requires a char* for recvfrom + char* data = (char*)Memory::GetPointer(BufferOut); + int data_len = BufferOutSize; - INFO_LOG(WII_IPC_NET, - "%s = %d Socket: %08x, BufferIn: (%08x, %i), BufferIn2: (%08x, %i), %u.%u.%u.%u", - has_destaddr ? "IOCTLV_SO_SENDTO " : "IOCTLV_SO_SEND ", - ReturnValue, fd, BufferIn, BufferInSize, - BufferIn2, BufferInSize2, - local_name.sin_addr.s_addr & 0xFF, - (local_name.sin_addr.s_addr >> 8) & 0xFF, - (local_name.sin_addr.s_addr >> 16) & 0xFF, - (local_name.sin_addr.s_addr >> 24) & 0xFF - ); - break; - } - case IOCTLV_SO_RECVFROM: - { - u32 flags = Memory::Read_U32(BufferIn + 0x04); - // Not a string, Windows requires a char* for recvfrom - char* data = (char*)Memory::GetPointer(BufferOut); - int data_len = BufferOutSize; + sockaddr_in local_name; + memset(&local_name, 0, sizeof(sockaddr_in)); - sockaddr_in local_name; - memset(&local_name, 0, sizeof(sockaddr_in)); + if (BufferOutSize2 != 0) + { + WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferOut2); + WiiSockMan::Convert(*wii_name, local_name); + } - if (BufferOutSize2 != 0) - { - WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferOut2); - WiiSockMan::Convert(*wii_name, local_name); - } + // Act as non blocking when SO_MSG_NONBLOCK is specified + forceNonBlock = ((flags & SO_MSG_NONBLOCK) == SO_MSG_NONBLOCK); - // Act as non blocking when SO_MSG_NONBLOCK is specified - forceNonBlock = ((flags & SO_MSG_NONBLOCK) == SO_MSG_NONBLOCK); - - // recv/recvfrom only handles PEEK/OOB - flags &= SO_MSG_PEEK | SO_MSG_OOB; + // recv/recvfrom only handles PEEK/OOB + flags &= SO_MSG_PEEK | SO_MSG_OOB; #ifdef _WIN32 - if (flags & SO_MSG_PEEK) - { - unsigned long totallen = 0; - ioctlsocket(fd, FIONREAD, &totallen); - ReturnValue = totallen; - break; - } + if (flags & SO_MSG_PEEK) + { + unsigned long totallen = 0; + ioctlsocket(fd, FIONREAD, &totallen); + ReturnValue = totallen; + break; + } #endif - socklen_t addrlen = sizeof(sockaddr_in); - int ret = recvfrom(fd, data, data_len, flags, - BufferOutSize2 ? (struct sockaddr*) &local_name : nullptr, - BufferOutSize2 ? &addrlen : nullptr); - ReturnValue = WiiSockMan::GetNetErrorCode(ret, BufferOutSize2 ? "SO_RECVFROM" : "SO_RECV", true); + socklen_t addrlen = sizeof(sockaddr_in); + int ret = recvfrom(fd, data, data_len, flags, + BufferOutSize2 ? (struct sockaddr*)&local_name : nullptr, + BufferOutSize2 ? &addrlen : nullptr); + ReturnValue = + WiiSockMan::GetNetErrorCode(ret, BufferOutSize2 ? "SO_RECVFROM" : "SO_RECV", true); - INFO_LOG(WII_IPC_NET, "%s(%d, %p) Socket: %08X, Flags: %08X, " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferOut: (%08x, %i), BufferOut2: (%08x, %i)", - BufferOutSize2 ? "IOCTLV_SO_RECVFROM " : "IOCTLV_SO_RECV ", - ReturnValue, data, fd, flags, - BufferIn, BufferInSize, BufferIn2, BufferInSize2, - BufferOut, BufferOutSize, BufferOut2, BufferOutSize2); + INFO_LOG(WII_IPC_NET, "%s(%d, %p) Socket: %08X, Flags: %08X, " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferOut: (%08x, %i), BufferOut2: (%08x, %i)", + BufferOutSize2 ? "IOCTLV_SO_RECVFROM " : "IOCTLV_SO_RECV ", ReturnValue, data, + fd, flags, BufferIn, BufferInSize, BufferIn2, BufferInSize2, BufferOut, + BufferOutSize, BufferOut2, BufferOutSize2); - if (BufferOutSize2 != 0) - { - WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferOut2); - WiiSockMan::Convert(local_name, *wii_name, addrlen); - } - break; - } - default: - break; - } - } - } + if (BufferOutSize2 != 0) + { + WiiSockAddrIn* wii_name = (WiiSockAddrIn*)Memory::GetPointer(BufferOut2); + WiiSockMan::Convert(local_name, *wii_name, addrlen); + } + break; + } + default: + break; + } + } + } - if (nonBlock || - forceNonBlock || - (!it->is_ssl && - ReturnValue != -SO_EAGAIN && - ReturnValue != -SO_EINPROGRESS && - ReturnValue != -SO_EALREADY) || - (it->is_ssl && - ReturnValue != SSL_ERR_WAGAIN && - ReturnValue != SSL_ERR_RAGAIN)) - { - DEBUG_LOG(WII_IPC_NET, - "IOCTL(V) Sock: %08x ioctl/v: %d returned: %d nonBlock: %d forceNonBlock: %d", - fd, it->is_ssl ? (int) it->ssl_type : (int) it->net_type, ReturnValue, nonBlock, forceNonBlock); - WiiSockMan::EnqueueReply(it->_CommandAddress, ReturnValue, ct); - it = pending_sockops.erase(it); - } - else - { - ++it; - } - } + if (nonBlock || forceNonBlock || + (!it->is_ssl && ReturnValue != -SO_EAGAIN && ReturnValue != -SO_EINPROGRESS && + ReturnValue != -SO_EALREADY) || + (it->is_ssl && ReturnValue != SSL_ERR_WAGAIN && ReturnValue != SSL_ERR_RAGAIN)) + { + DEBUG_LOG(WII_IPC_NET, + "IOCTL(V) Sock: %08x ioctl/v: %d returned: %d nonBlock: %d forceNonBlock: %d", fd, + it->is_ssl ? (int)it->ssl_type : (int)it->net_type, ReturnValue, nonBlock, + forceNonBlock); + WiiSockMan::EnqueueReply(it->_CommandAddress, ReturnValue, ct); + it = pending_sockops.erase(it); + } + else + { + ++it; + } + } } void WiiSocket::DoSock(u32 _CommandAddress, NET_IOCTL type) { - sockop so = {_CommandAddress, false}; - so.net_type = type; - pending_sockops.push_back(so); + sockop so = {_CommandAddress, false}; + so.net_type = type; + pending_sockops.push_back(so); } void WiiSocket::DoSock(u32 _CommandAddress, SSL_IOCTL type) { - sockop so = {_CommandAddress, true}; - so.ssl_type = type; - pending_sockops.push_back(so); + sockop so = {_CommandAddress, true}; + so.ssl_type = type; + pending_sockops.push_back(so); } void WiiSockMan::AddSocket(s32 fd) { - if (fd >= 0) - { - WiiSocket& sock = WiiSockets[fd]; - sock.SetFd(fd); - } + if (fd >= 0) + { + WiiSocket& sock = WiiSockets[fd]; + sock.SetFd(fd); + } } s32 WiiSockMan::NewSocket(s32 af, s32 type, s32 protocol) { - s32 fd = (s32)socket(af, type, protocol); - s32 ret = GetNetErrorCode(fd, "NewSocket", false); - AddSocket(ret); - return ret; + s32 fd = (s32)socket(af, type, protocol); + s32 ret = GetNetErrorCode(fd, "NewSocket", false); + AddSocket(ret); + return ret; } s32 WiiSockMan::DeleteSocket(s32 s) { - auto socket_entry = WiiSockets.find(s); - s32 ReturnValue = socket_entry->second.CloseFd(); - WiiSockets.erase(socket_entry); - return ReturnValue; + auto socket_entry = WiiSockets.find(s); + s32 ReturnValue = socket_entry->second.CloseFd(); + WiiSockets.erase(socket_entry); + return ReturnValue; } void WiiSockMan::Update() { - s32 nfds = 0; - fd_set read_fds, write_fds, except_fds; - struct timeval t = {0,0}; - FD_ZERO(&read_fds); - FD_ZERO(&write_fds); - FD_ZERO(&except_fds); + s32 nfds = 0; + fd_set read_fds, write_fds, except_fds; + struct timeval t = {0, 0}; + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + FD_ZERO(&except_fds); - auto socket_iter = WiiSockets.begin(); - auto end_socks = WiiSockets.end(); + auto socket_iter = WiiSockets.begin(); + auto end_socks = WiiSockets.end(); - while (socket_iter != end_socks) - { - WiiSocket& sock = socket_iter->second; - if (sock.IsValid()) - { - FD_SET(sock.fd, &read_fds); - FD_SET(sock.fd, &write_fds); - FD_SET(sock.fd, &except_fds); - nfds = std::max(nfds, sock.fd+1); - ++socket_iter; - } - else - { - // Good time to clean up invalid sockets. - socket_iter = WiiSockets.erase(socket_iter); - } - } - s32 ret = select(nfds, &read_fds, &write_fds, &except_fds, &t); + while (socket_iter != end_socks) + { + WiiSocket& sock = socket_iter->second; + if (sock.IsValid()) + { + FD_SET(sock.fd, &read_fds); + FD_SET(sock.fd, &write_fds); + FD_SET(sock.fd, &except_fds); + nfds = std::max(nfds, sock.fd + 1); + ++socket_iter; + } + else + { + // Good time to clean up invalid sockets. + socket_iter = WiiSockets.erase(socket_iter); + } + } + s32 ret = select(nfds, &read_fds, &write_fds, &except_fds, &t); - if (ret >= 0) - { - for (auto& pair : WiiSockets) - { - WiiSocket& sock = pair.second; - sock.Update( - FD_ISSET(sock.fd, &read_fds) != 0, - FD_ISSET(sock.fd, &write_fds) != 0, - FD_ISSET(sock.fd, &except_fds) != 0 - ); - } - } - else - { - for (auto& elem : WiiSockets) - { - elem.second.Update(false, false, false); - } - } + if (ret >= 0) + { + for (auto& pair : WiiSockets) + { + WiiSocket& sock = pair.second; + sock.Update(FD_ISSET(sock.fd, &read_fds) != 0, FD_ISSET(sock.fd, &write_fds) != 0, + FD_ISSET(sock.fd, &except_fds) != 0); + } + } + else + { + for (auto& elem : WiiSockets) + { + elem.second.Update(false, false, false); + } + } } void WiiSockMan::EnqueueReply(u32 CommandAddress, s32 ReturnValue, IPCCommandType CommandType) { - // The original hardware overwrites the command type with the async reply type. - Memory::Write_U32(IPC_REP_ASYNC, CommandAddress); - // IOS also seems to write back the command that was responded to in the FD field. - Memory::Write_U32(CommandType, CommandAddress + 8); + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, CommandAddress); + // IOS also seems to write back the command that was responded to in the FD field. + Memory::Write_U32(CommandType, CommandAddress + 8); - // Return value - Memory::Write_U32(ReturnValue, CommandAddress + 4); + // Return value + Memory::Write_U32(ReturnValue, CommandAddress + 4); - WII_IPC_HLE_Interface::EnqueueReply(CommandAddress); + WII_IPC_HLE_Interface::EnqueueReply(CommandAddress); } - -void WiiSockMan::Convert(WiiSockAddrIn const & from, sockaddr_in& to) +void WiiSockMan::Convert(WiiSockAddrIn const& from, sockaddr_in& to) { - to.sin_addr.s_addr = from.addr.addr; - to.sin_family = from.family; - to.sin_port = from.port; + to.sin_addr.s_addr = from.addr.addr; + to.sin_family = from.family; + to.sin_port = from.port; } -void WiiSockMan::Convert(sockaddr_in const & from, WiiSockAddrIn& to, s32 addrlen) +void WiiSockMan::Convert(sockaddr_in const& from, WiiSockAddrIn& to, s32 addrlen) { - to.addr.addr = from.sin_addr.s_addr; - to.family = from.sin_family & 0xFF; - to.port = from.sin_port; - if (addrlen < 0 || addrlen > (s32) sizeof(WiiSockAddrIn)) - to.len = sizeof(WiiSockAddrIn); - else - to.len = addrlen; + to.addr.addr = from.sin_addr.s_addr; + to.family = from.sin_family & 0xFF; + to.port = from.sin_port; + if (addrlen < 0 || addrlen > (s32)sizeof(WiiSockAddrIn)) + to.len = sizeof(WiiSockAddrIn); + else + to.len = addrlen; } void WiiSockMan::UpdateWantDeterminism(bool want) { - // If we switched into movie recording, kill existing sockets. - if (want) - Clean(); + // If we switched into movie recording, kill existing sockets. + if (want) + Clean(); } #undef ERRORCODE diff --git a/Source/Core/Core/IPC_HLE/WII_Socket.h b/Source/Core/Core/IPC_HLE/WII_Socket.h index 8793235306..7127634516 100644 --- a/Source/Core/Core/IPC_HLE/WII_Socket.h +++ b/Source/Core/Core/IPC_HLE/WII_Socket.h @@ -5,9 +5,9 @@ #pragma once #ifdef _WIN32 -#include -#include #include +#include +#include typedef pollfd pollfd_t; @@ -16,29 +16,29 @@ typedef pollfd pollfd_t; #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) #elif defined(__linux__) or defined(__APPLE__) or defined(__FreeBSD__) -#include #include -#include -#include +#include #include +#include +#include #if defined(ANDROID) #include #else #include #endif -#include -#include #include +#include +#include #include #include typedef struct pollfd pollfd_t; #else -#include -#include -#include -#include #include +#include +#include +#include +#include #endif #include @@ -55,199 +55,192 @@ typedef struct pollfd pollfd_t; enum { - SO_MSG_OOB = 0x01, - SO_MSG_PEEK = 0x02, - SO_MSG_NONBLOCK = 0x04, + SO_MSG_OOB = 0x01, + SO_MSG_PEEK = 0x02, + SO_MSG_NONBLOCK = 0x04, }; enum { - SO_SUCCESS, - SO_E2BIG = 1, - SO_EACCES, - SO_EADDRINUSE, - SO_EADDRNOTAVAIL, - SO_EAFNOSUPPORT, - SO_EAGAIN, - SO_EALREADY, - SO_EBADF, - SO_EBADMSG, - SO_EBUSY, - SO_ECANCELED, - SO_ECHILD, - SO_ECONNABORTED, - SO_ECONNREFUSED, - SO_ECONNRESET, - SO_EDEADLK, - SO_EDESTADDRREQ, - SO_EDOM, - SO_EDQUOT, - SO_EEXIST, - SO_EFAULT, - SO_EFBIG, - SO_EHOSTUNREACH, - SO_EIDRM, - SO_EILSEQ, - SO_EINPROGRESS, - SO_EINTR, - SO_EINVAL, - SO_EIO, - SO_EISCONN, - SO_EISDIR, - SO_ELOOP, - SO_EMFILE, - SO_EMLINK, - SO_EMSGSIZE, - SO_EMULTIHOP, - SO_ENAMETOOLONG, - SO_ENETDOWN, - SO_ENETRESET, - SO_ENETUNREACH, - SO_ENFILE, - SO_ENOBUFS, - SO_ENODATA, - SO_ENODEV, - SO_ENOENT, - SO_ENOEXEC, - SO_ENOLCK, - SO_ENOLINK, - SO_ENOMEM, - SO_ENOMSG, - SO_ENOPROTOOPT, - SO_ENOSPC, - SO_ENOSR, - SO_ENOSTR, - SO_ENOSYS, - SO_ENOTCONN, - SO_ENOTDIR, - SO_ENOTEMPTY, - SO_ENOTSOCK, - SO_ENOTSUP, - SO_ENOTTY, - SO_ENXIO, - SO_EOPNOTSUPP, - SO_EOVERFLOW, - SO_EPERM, - SO_EPIPE, - SO_EPROTO, - SO_EPROTONOSUPPORT, - SO_EPROTOTYPE, - SO_ERANGE, - SO_EROFS, - SO_ESPIPE, - SO_ESRCH, - SO_ESTALE, - SO_ETIME, - SO_ETIMEDOUT, - SO_ETXTBSY, - SO_EXDEV + SO_SUCCESS, + SO_E2BIG = 1, + SO_EACCES, + SO_EADDRINUSE, + SO_EADDRNOTAVAIL, + SO_EAFNOSUPPORT, + SO_EAGAIN, + SO_EALREADY, + SO_EBADF, + SO_EBADMSG, + SO_EBUSY, + SO_ECANCELED, + SO_ECHILD, + SO_ECONNABORTED, + SO_ECONNREFUSED, + SO_ECONNRESET, + SO_EDEADLK, + SO_EDESTADDRREQ, + SO_EDOM, + SO_EDQUOT, + SO_EEXIST, + SO_EFAULT, + SO_EFBIG, + SO_EHOSTUNREACH, + SO_EIDRM, + SO_EILSEQ, + SO_EINPROGRESS, + SO_EINTR, + SO_EINVAL, + SO_EIO, + SO_EISCONN, + SO_EISDIR, + SO_ELOOP, + SO_EMFILE, + SO_EMLINK, + SO_EMSGSIZE, + SO_EMULTIHOP, + SO_ENAMETOOLONG, + SO_ENETDOWN, + SO_ENETRESET, + SO_ENETUNREACH, + SO_ENFILE, + SO_ENOBUFS, + SO_ENODATA, + SO_ENODEV, + SO_ENOENT, + SO_ENOEXEC, + SO_ENOLCK, + SO_ENOLINK, + SO_ENOMEM, + SO_ENOMSG, + SO_ENOPROTOOPT, + SO_ENOSPC, + SO_ENOSR, + SO_ENOSTR, + SO_ENOSYS, + SO_ENOTCONN, + SO_ENOTDIR, + SO_ENOTEMPTY, + SO_ENOTSOCK, + SO_ENOTSUP, + SO_ENOTTY, + SO_ENXIO, + SO_EOPNOTSUPP, + SO_EOVERFLOW, + SO_EPERM, + SO_EPIPE, + SO_EPROTO, + SO_EPROTONOSUPPORT, + SO_EPROTOTYPE, + SO_ERANGE, + SO_EROFS, + SO_ESPIPE, + SO_ESRCH, + SO_ESTALE, + SO_ETIME, + SO_ETIMEDOUT, + SO_ETXTBSY, + SO_EXDEV }; #pragma pack(push, 1) struct WiiInAddr { - u32 addr; + u32 addr; }; struct WiiSockAddr { - u8 len; - u8 family; - u8 data[6]; + u8 len; + u8 family; + u8 data[6]; }; struct WiiSockAddrIn { - u8 len; - u8 family; - u16 port; - WiiInAddr addr; + u8 len; + u8 family; + u16 port; + WiiInAddr addr; }; #pragma pack(pop) class WiiSocket { - struct sockop - { - u32 _CommandAddress; - bool is_ssl; - union - { - NET_IOCTL net_type; - SSL_IOCTL ssl_type; - }; - }; + struct sockop + { + u32 _CommandAddress; + bool is_ssl; + union { + NET_IOCTL net_type; + SSL_IOCTL ssl_type; + }; + }; + private: - s32 fd; - bool nonBlock; - std::list pending_sockops; + s32 fd; + bool nonBlock; + std::list pending_sockops; - friend class WiiSockMan; - void SetFd(s32 s); - s32 CloseFd(); - s32 FCntl(u32 cmd, u32 arg); + friend class WiiSockMan; + void SetFd(s32 s); + s32 CloseFd(); + s32 FCntl(u32 cmd, u32 arg); - void DoSock(u32 _CommandAddress, NET_IOCTL type); - void DoSock(u32 _CommandAddress, SSL_IOCTL type); - void Update(bool read, bool write, bool except); - bool IsValid() const { return fd >= 0; } + void DoSock(u32 _CommandAddress, NET_IOCTL type); + void DoSock(u32 _CommandAddress, SSL_IOCTL type); + void Update(bool read, bool write, bool except); + bool IsValid() const { return fd >= 0; } public: - WiiSocket() : fd(-1), nonBlock(false) {} - ~WiiSocket(); - void operator=(WiiSocket const&) = delete; - + WiiSocket() : fd(-1), nonBlock(false) {} + ~WiiSocket(); + void operator=(WiiSocket const&) = delete; }; class WiiSockMan : public ::NonCopyable { public: - static s32 GetNetErrorCode(s32 ret, const char* caller, bool isRW); - static char* DecodeError(s32 ErrorCode); + static s32 GetNetErrorCode(s32 ret, const char* caller, bool isRW); + static char* DecodeError(s32 ErrorCode); - static WiiSockMan& GetInstance() - { - static WiiSockMan instance; // Guaranteed to be destroyed. - return instance; // Instantiated on first use. - } - void Update(); - static void EnqueueReply(u32 CommandAddress, s32 ReturnValue, IPCCommandType CommandType); - static void Convert(WiiSockAddrIn const & from, sockaddr_in& to); - static void Convert(sockaddr_in const & from, WiiSockAddrIn& to, s32 addrlen = -1); - // NON-BLOCKING FUNCTIONS - s32 NewSocket(s32 af, s32 type, s32 protocol); - void AddSocket(s32 fd); - s32 DeleteSocket(s32 s); - s32 GetLastNetError() const { return errno_last; } - void SetLastNetError(s32 error) { errno_last = error; } + static WiiSockMan& GetInstance() + { + static WiiSockMan instance; // Guaranteed to be destroyed. + return instance; // Instantiated on first use. + } + void Update(); + static void EnqueueReply(u32 CommandAddress, s32 ReturnValue, IPCCommandType CommandType); + static void Convert(WiiSockAddrIn const& from, sockaddr_in& to); + static void Convert(sockaddr_in const& from, WiiSockAddrIn& to, s32 addrlen = -1); + // NON-BLOCKING FUNCTIONS + s32 NewSocket(s32 af, s32 type, s32 protocol); + void AddSocket(s32 fd); + s32 DeleteSocket(s32 s); + s32 GetLastNetError() const { return errno_last; } + void SetLastNetError(s32 error) { errno_last = error; } + void Clean() { WiiSockets.clear(); } + template + void DoSock(s32 sock, u32 CommandAddress, T type) + { + auto socket_entry = WiiSockets.find(sock); + if (socket_entry == WiiSockets.end()) + { + IPCCommandType ct = static_cast(Memory::Read_U32(CommandAddress)); + ERROR_LOG(WII_IPC_NET, "DoSock: Error, fd not found (%08x, %08X, %08X)", sock, CommandAddress, + type); + EnqueueReply(CommandAddress, -SO_EBADF, ct); + } + else + { + socket_entry->second.DoSock(CommandAddress, type); + } + } - void Clean() - { - WiiSockets.clear(); - } - - template - void DoSock(s32 sock, u32 CommandAddress, T type) - { - auto socket_entry = WiiSockets.find(sock); - if (socket_entry == WiiSockets.end()) - { - IPCCommandType ct = static_cast(Memory::Read_U32(CommandAddress)); - ERROR_LOG(WII_IPC_NET, - "DoSock: Error, fd not found (%08x, %08X, %08X)", - sock, CommandAddress, type); - EnqueueReply(CommandAddress, -SO_EBADF, ct); - } - else - { - socket_entry->second.DoSock(CommandAddress, type); - } - } - - void UpdateWantDeterminism(bool want); + void UpdateWantDeterminism(bool want); private: - WiiSockMan() = default; + WiiSockMan() = default; - std::unordered_map WiiSockets; - s32 errno_last; + std::unordered_map WiiSockets; + s32 errno_last; }; diff --git a/Source/Core/Core/IPC_HLE/WiiMote_HID_Attr.cpp b/Source/Core/Core/IPC_HLE/WiiMote_HID_Attr.cpp index 33f994e45f..574b6944e9 100644 --- a/Source/Core/Core/IPC_HLE/WiiMote_HID_Attr.cpp +++ b/Source/Core/Core/IPC_HLE/WiiMote_HID_Attr.cpp @@ -6,8 +6,8 @@ #include "Common/Assert.h" #include "Common/CommonTypes.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "Core/IPC_HLE/WiiMote_HID_Attr.h" #if 0 @@ -145,99 +145,95 @@ u8 HIDUnk_020D[] = { 0x28, 0x00 }; u8 HIDBootDevice[] = { 0x28, 0x00 }; #endif - static u8 packet1[] = { - 0x00, 0x7b, 0x00, 0x76, 0x36, 0x01, 0xcc, 0x09, 0x00, 0x00, 0x0a, 0x00, 0x01, - 0x00, 0x00, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x24, 0x09, 0x00, 0x04, 0x35, 0x0d, 0x35, - 0x06, 0x19, 0x01, 0x00, 0x09, 0x00, 0x11, 0x35, 0x03, 0x19, 0x00, 0x11, 0x09, 0x00, 0x05, 0x35, - 0x03, 0x19, 0x10, 0x02, 0x09, 0x00, 0x06, 0x35, 0x09, 0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, - 0x01, 0x00, 0x09, 0x00, 0x09, 0x35, 0x08, 0x35, 0x06, 0x19, 0x11, 0x24, 0x09, 0x01, 0x00, 0x09, - 0x00, 0x0d, 0x35, 0x0f, 0x35, 0x0d, 0x35, 0x06, 0x19, 0x01, 0x00, 0x09, 0x00, 0x13, 0x35, 0x03, - 0x19, 0x00, 0x11, 0x09, 0x01, 0x00, 0x25, 0x13, 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x6f, - 0x20, 0x52, 0x56, 0x4c, 0x2d, 0x43, 0x4e, 0x54, 0x2d, 0x30, 0x31, 0x09, 0x01, 0x02, 0x00, 0x76, + 0x00, 0x7b, 0x00, 0x76, 0x36, 0x01, 0xcc, 0x09, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x09, + 0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x24, 0x09, 0x00, 0x04, 0x35, 0x0d, 0x35, 0x06, 0x19, 0x01, + 0x00, 0x09, 0x00, 0x11, 0x35, 0x03, 0x19, 0x00, 0x11, 0x09, 0x00, 0x05, 0x35, 0x03, 0x19, 0x10, + 0x02, 0x09, 0x00, 0x06, 0x35, 0x09, 0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01, 0x00, 0x09, + 0x00, 0x09, 0x35, 0x08, 0x35, 0x06, 0x19, 0x11, 0x24, 0x09, 0x01, 0x00, 0x09, 0x00, 0x0d, 0x35, + 0x0f, 0x35, 0x0d, 0x35, 0x06, 0x19, 0x01, 0x00, 0x09, 0x00, 0x13, 0x35, 0x03, 0x19, 0x00, 0x11, + 0x09, 0x01, 0x00, 0x25, 0x13, 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x6f, 0x20, 0x52, 0x56, + 0x4c, 0x2d, 0x43, 0x4e, 0x54, 0x2d, 0x30, 0x31, 0x09, 0x01, 0x02, 0x00, 0x76, }; static u8 packet2[] = { - 0x00, 0x7b, 0x00, 0x76, 0x01, 0x25, 0x13, 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e, - 0x64, 0x6f, 0x20, 0x52, 0x56, 0x4c, 0x2d, 0x43, 0x4e, 0x54, 0x2d, 0x30, 0x31, 0x09, 0x01, 0x02, - 0x25, 0x08, 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x6f, 0x09, 0x02, 0x00, 0x09, 0x01, 0x00, - 0x09, 0x02, 0x01, 0x09, 0x01, 0x11, 0x09, 0x02, 0x02, 0x08, 0x04, 0x09, 0x02, 0x03, 0x08, 0x33, - 0x09, 0x02, 0x04, 0x28, 0x00, 0x09, 0x02, 0x05, 0x28, 0x01, 0x09, 0x02, 0x06, 0x35, 0xdf, 0x35, - 0xdd, 0x08, 0x22, 0x25, 0xd9, 0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x10, 0x15, 0x00, 0x26, - 0xff, 0x00, 0x75, 0x08, 0x95, 0x01, 0x06, 0x00, 0xff, 0x09, 0x01, 0x91, 0x00, 0x85, 0x11, 0x95, - 0x01, 0x09, 0x01, 0x91, 0x00, 0x85, 0x12, 0x95, 0x02, 0x09, 0x01, 0x91, 0x00, 0x02, 0x00, 0xec, + 0x00, 0x7b, 0x00, 0x76, 0x01, 0x25, 0x13, 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x6f, 0x20, + 0x52, 0x56, 0x4c, 0x2d, 0x43, 0x4e, 0x54, 0x2d, 0x30, 0x31, 0x09, 0x01, 0x02, 0x25, 0x08, 0x4e, + 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x6f, 0x09, 0x02, 0x00, 0x09, 0x01, 0x00, 0x09, 0x02, 0x01, + 0x09, 0x01, 0x11, 0x09, 0x02, 0x02, 0x08, 0x04, 0x09, 0x02, 0x03, 0x08, 0x33, 0x09, 0x02, 0x04, + 0x28, 0x00, 0x09, 0x02, 0x05, 0x28, 0x01, 0x09, 0x02, 0x06, 0x35, 0xdf, 0x35, 0xdd, 0x08, 0x22, + 0x25, 0xd9, 0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x10, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, + 0x08, 0x95, 0x01, 0x06, 0x00, 0xff, 0x09, 0x01, 0x91, 0x00, 0x85, 0x11, 0x95, 0x01, 0x09, 0x01, + 0x91, 0x00, 0x85, 0x12, 0x95, 0x02, 0x09, 0x01, 0x91, 0x00, 0x02, 0x00, 0xec, }; static u8 packet3[] = { - 0x00, 0x7b, 0x00, 0x76, 0x85, 0x13, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85, - 0x14, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85, 0x15, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85, - 0x16, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00, 0x85, 0x17, 0x95, 0x06, 0x09, 0x01, 0x91, 0x00, 0x85, - 0x18, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00, 0x85, 0x19, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85, - 0x1a, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85, 0x20, 0x95, 0x06, 0x09, 0x01, 0x81, 0x00, 0x85, - 0x21, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x22, 0x95, 0x04, 0x09, 0x01, 0x81, 0x00, 0x85, - 0x30, 0x95, 0x02, 0x09, 0x01, 0x81, 0x00, 0x85, 0x31, 0x95, 0x05, 0x09, 0x01, 0x81, 0x00, 0x85, - 0x32, 0x95, 0x0a, 0x09, 0x01, 0x81, 0x00, 0x85, 0x33, 0x95, 0x11, 0x09, 0x01, 0x02, 0x01, 0x62, + 0x00, 0x7b, 0x00, 0x76, 0x85, 0x13, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85, 0x14, 0x95, 0x01, + 0x09, 0x01, 0x91, 0x00, 0x85, 0x15, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85, 0x16, 0x95, 0x15, + 0x09, 0x01, 0x91, 0x00, 0x85, 0x17, 0x95, 0x06, 0x09, 0x01, 0x91, 0x00, 0x85, 0x18, 0x95, 0x15, + 0x09, 0x01, 0x91, 0x00, 0x85, 0x19, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85, 0x1a, 0x95, 0x01, + 0x09, 0x01, 0x91, 0x00, 0x85, 0x20, 0x95, 0x06, 0x09, 0x01, 0x81, 0x00, 0x85, 0x21, 0x95, 0x15, + 0x09, 0x01, 0x81, 0x00, 0x85, 0x22, 0x95, 0x04, 0x09, 0x01, 0x81, 0x00, 0x85, 0x30, 0x95, 0x02, + 0x09, 0x01, 0x81, 0x00, 0x85, 0x31, 0x95, 0x05, 0x09, 0x01, 0x81, 0x00, 0x85, 0x32, 0x95, 0x0a, + 0x09, 0x01, 0x81, 0x00, 0x85, 0x33, 0x95, 0x11, 0x09, 0x01, 0x02, 0x01, 0x62, }; static u8 packet4[] = { - 0x00, 0x70, 0x00, 0x6d, 0x81, 0x00, 0x85, 0x34, 0x95, 0x15, 0x09, 0x01, 0x81, - 0x00, 0x85, 0x35, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x36, 0x95, 0x15, 0x09, 0x01, 0x81, - 0x00, 0x85, 0x37, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x3d, 0x95, 0x15, 0x09, 0x01, 0x81, - 0x00, 0x85, 0x3e, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x3f, 0x95, 0x15, 0x09, 0x01, 0x81, - 0x00, 0xc0, 0x09, 0x02, 0x07, 0x35, 0x08, 0x35, 0x06, 0x09, 0x04, 0x09, 0x09, 0x01, 0x00, 0x09, - 0x02, 0x08, 0x28, 0x00, 0x09, 0x02, 0x09, 0x28, 0x01, 0x09, 0x02, 0x0a, 0x28, 0x01, 0x09, 0x02, - 0x0b, 0x09, 0x01, 0x00, 0x09, 0x02, 0x0c, 0x09, 0x0c, 0x80, 0x09, 0x02, 0x0d, 0x28, 0x00, 0x09, - 0x02, 0x0e, 0x28, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x6d, 0x81, 0x00, 0x85, 0x34, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, + 0x35, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x36, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, + 0x85, 0x37, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x3d, 0x95, 0x15, 0x09, 0x01, 0x81, + 0x00, 0x85, 0x3e, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x3f, 0x95, 0x15, 0x09, 0x01, + 0x81, 0x00, 0xc0, 0x09, 0x02, 0x07, 0x35, 0x08, 0x35, 0x06, 0x09, 0x04, 0x09, 0x09, 0x01, + 0x00, 0x09, 0x02, 0x08, 0x28, 0x00, 0x09, 0x02, 0x09, 0x28, 0x01, 0x09, 0x02, 0x0a, 0x28, + 0x01, 0x09, 0x02, 0x0b, 0x09, 0x01, 0x00, 0x09, 0x02, 0x0c, 0x09, 0x0c, 0x80, 0x09, 0x02, + 0x0d, 0x28, 0x00, 0x09, 0x02, 0x0e, 0x28, 0x00, 0x00, }; - static u8 packet4_0x10001[] = { - 0x00, 0x60, 0x00, 0x5d, 0x36, 0x00, 0x5a, 0x09, 0x00, 0x00, 0x0a, 0x00, 0x01, - 0x00, 0x01, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x12, 0x00, 0x09, 0x00, 0x04, 0x35, 0x0d, 0x35, - 0x06, 0x19, 0x01, 0x00, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x00, 0x01, 0x09, 0x00, 0x05, 0x35, - 0x03, 0x19, 0x10, 0x02, 0x09, 0x00, 0x09, 0x35, 0x08, 0x35, 0x06, 0x19, 0x12, 0x00, 0x09, 0x01, - 0x00, 0x09, 0x02, 0x00, 0x09, 0x01, 0x00, 0x09, 0x02, 0x01, 0x09, 0x05, 0x7e, 0x09, 0x02, 0x02, - 0x09, 0x03, 0x06, 0x09, 0x02, 0x03, 0x09, 0x06, 0x00, 0x09, 0x02, 0x04, 0x28, 0x01, 0x09, 0x02, - 0x05, 0x09, 0x00, 0x02, 0x00, + 0x00, 0x60, 0x00, 0x5d, 0x36, 0x00, 0x5a, 0x09, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, + 0x01, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x12, 0x00, 0x09, 0x00, 0x04, 0x35, 0x0d, + 0x35, 0x06, 0x19, 0x01, 0x00, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x00, 0x01, 0x09, + 0x00, 0x05, 0x35, 0x03, 0x19, 0x10, 0x02, 0x09, 0x00, 0x09, 0x35, 0x08, 0x35, 0x06, + 0x19, 0x12, 0x00, 0x09, 0x01, 0x00, 0x09, 0x02, 0x00, 0x09, 0x01, 0x00, 0x09, 0x02, + 0x01, 0x09, 0x05, 0x7e, 0x09, 0x02, 0x02, 0x09, 0x03, 0x06, 0x09, 0x02, 0x03, 0x09, + 0x06, 0x00, 0x09, 0x02, 0x04, 0x28, 0x01, 0x09, 0x02, 0x05, 0x09, 0x00, 0x02, 0x00, }; - - const u8* GetAttribPacket(u32 serviceHandle, u32 cont, u32& _size) { - if (serviceHandle == 0x10000) - { - if (cont == 0) - { - _size = sizeof(packet1); - return packet1; - } - else if (cont == 0x76) - { - _size = sizeof(packet2); - return packet2; - } - else if (cont == 0xec) - { - _size = sizeof(packet3); - return packet3; - } - else if (cont == 0x162) - { - _size = sizeof(packet4); - return packet4; - } - } + if (serviceHandle == 0x10000) + { + if (cont == 0) + { + _size = sizeof(packet1); + return packet1; + } + else if (cont == 0x76) + { + _size = sizeof(packet2); + return packet2; + } + else if (cont == 0xec) + { + _size = sizeof(packet3); + return packet3; + } + else if (cont == 0x162) + { + _size = sizeof(packet4); + return packet4; + } + } - if (serviceHandle == 0x10001) - { - _dbg_assert_(WII_IPC_WIIMOTE, cont == 0x00); - _size = sizeof(packet4_0x10001); - return packet4_0x10001; - } + if (serviceHandle == 0x10001) + { + _dbg_assert_(WII_IPC_WIIMOTE, cont == 0x00); + _size = sizeof(packet4_0x10001); + return packet4_0x10001; + } - return nullptr; + return nullptr; } // XXX keep these? diff --git a/Source/Core/Core/IPC_HLE/hci.h b/Source/Core/Core/IPC_HLE/hci.h index 0172366d17..f3d352f92c 100644 --- a/Source/Core/Core/IPC_HLE/hci.h +++ b/Source/Core/Core/IPC_HLE/hci.h @@ -89,16 +89,22 @@ #pragma pack(push, 1) /* All sizes are in bytes */ -#define BLUETOOTH_BDADDR_SIZE 6 +#define BLUETOOTH_BDADDR_SIZE 6 /* * Bluetooth device address */ #ifndef __BLUETOOTH_H -typedef struct { - uint8_t b[BLUETOOTH_BDADDR_SIZE]; +typedef struct +{ + uint8_t b[BLUETOOTH_BDADDR_SIZE]; } bdaddr_t; -#define BDADDR_ANY { { 0, 0, 0, 0, 0, 0 } } +#define BDADDR_ANY \ + { \ + { \ + 0, 0, 0, 0, 0, 0 \ + } \ + } #endif /************************************************************************** @@ -107,104 +113,104 @@ typedef struct { ************************************************************************** **************************************************************************/ -#define HCI_LAP_SIZE 3 /* unit LAP */ -#define HCI_KEY_SIZE 16 /* link key */ -#define HCI_PIN_SIZE 16 /* link PIN */ -#define HCI_EVENT_MASK_SIZE 8 /* event mask */ -#define HCI_CLASS_SIZE 3 /* unit class */ -#define HCI_FEATURES_SIZE 8 /* LMP features */ -#define HCI_UNIT_NAME_SIZE 248 /* unit name size */ -#define HCI_DEVNAME_SIZE 16 /* same as dv_xname */ -#define HCI_COMMANDS_SIZE 64 /* supported commands mask */ +#define HCI_LAP_SIZE 3 /* unit LAP */ +#define HCI_KEY_SIZE 16 /* link key */ +#define HCI_PIN_SIZE 16 /* link PIN */ +#define HCI_EVENT_MASK_SIZE 8 /* event mask */ +#define HCI_CLASS_SIZE 3 /* unit class */ +#define HCI_FEATURES_SIZE 8 /* LMP features */ +#define HCI_UNIT_NAME_SIZE 248 /* unit name size */ +#define HCI_DEVNAME_SIZE 16 /* same as dv_xname */ +#define HCI_COMMANDS_SIZE 64 /* supported commands mask */ /* HCI specification */ -#define HCI_SPEC_V10 0x00 /* v1.0b */ -#define HCI_SPEC_V11 0x01 /* v1.1 */ -#define HCI_SPEC_V12 0x02 /* v1.2 */ -#define HCI_SPEC_V20 0x03 /* v2.0 + EDR */ -#define HCI_SPEC_V21 0x04 /* v2.1 + EDR */ -#define HCI_SPEC_V30 0x05 /* v3.0 + HS */ +#define HCI_SPEC_V10 0x00 /* v1.0b */ +#define HCI_SPEC_V11 0x01 /* v1.1 */ +#define HCI_SPEC_V12 0x02 /* v1.2 */ +#define HCI_SPEC_V20 0x03 /* v2.0 + EDR */ +#define HCI_SPEC_V21 0x04 /* v2.1 + EDR */ +#define HCI_SPEC_V30 0x05 /* v3.0 + HS */ /* 0x06 - 0xFF - reserved for future use */ /* LMP features (and page 0 of extended features) */ /* ------------------- byte 0 --------------------*/ -#define HCI_LMP_3SLOT 0x01 -#define HCI_LMP_5SLOT 0x02 -#define HCI_LMP_ENCRYPTION 0x04 -#define HCI_LMP_SLOT_OFFSET 0x08 -#define HCI_LMP_TIMIACCURACY 0x10 -#define HCI_LMP_ROLE_SWITCH 0x20 -#define HCI_LMP_HOLD_MODE 0x40 -#define HCI_LMP_SNIFF_MODE 0x80 +#define HCI_LMP_3SLOT 0x01 +#define HCI_LMP_5SLOT 0x02 +#define HCI_LMP_ENCRYPTION 0x04 +#define HCI_LMP_SLOT_OFFSET 0x08 +#define HCI_LMP_TIMIACCURACY 0x10 +#define HCI_LMP_ROLE_SWITCH 0x20 +#define HCI_LMP_HOLD_MODE 0x40 +#define HCI_LMP_SNIFF_MODE 0x80 /* ------------------- byte 1 --------------------*/ -#define HCI_LMP_PARK_MODE 0x01 -#define HCI_LMP_RSSI 0x02 -#define HCI_LMP_CHANNEL_QUALITY 0x04 -#define HCI_LMP_SCO_LINK 0x08 -#define HCI_LMP_HV2_PKT 0x10 -#define HCI_LMP_HV3_PKT 0x20 -#define HCI_LMP_ULAW_LOG 0x40 -#define HCI_LMP_ALAW_LOG 0x80 +#define HCI_LMP_PARK_MODE 0x01 +#define HCI_LMP_RSSI 0x02 +#define HCI_LMP_CHANNEL_QUALITY 0x04 +#define HCI_LMP_SCO_LINK 0x08 +#define HCI_LMP_HV2_PKT 0x10 +#define HCI_LMP_HV3_PKT 0x20 +#define HCI_LMP_ULAW_LOG 0x40 +#define HCI_LMP_ALAW_LOG 0x80 /* ------------------- byte 2 --------------------*/ -#define HCI_LMP_CVSD 0x01 -#define HCI_LMP_PAGISCHEME 0x02 -#define HCI_LMP_POWER_CONTROL 0x04 -#define HCI_LMP_TRANSPARENT_SCO 0x08 -#define HCI_LMP_FLOW_CONTROL_LAG0 0x10 -#define HCI_LMP_FLOW_CONTROL_LAG1 0x20 -#define HCI_LMP_FLOW_CONTROL_LAG2 0x40 -#define HCI_LMP_BC_ENCRYPTION 0x80 +#define HCI_LMP_CVSD 0x01 +#define HCI_LMP_PAGISCHEME 0x02 +#define HCI_LMP_POWER_CONTROL 0x04 +#define HCI_LMP_TRANSPARENT_SCO 0x08 +#define HCI_LMP_FLOW_CONTROL_LAG0 0x10 +#define HCI_LMP_FLOW_CONTROL_LAG1 0x20 +#define HCI_LMP_FLOW_CONTROL_LAG2 0x40 +#define HCI_LMP_BC_ENCRYPTION 0x80 /* ------------------- byte 3 --------------------*/ /* reserved 0x01 */ -#define HCI_LMP_EDR_ACL_2MBPS 0x02 -#define HCI_LMP_EDR_ACL_3MBPS 0x04 -#define HCI_LMP_ENHANCED_ISCAN 0x08 -#define HCI_LMP_INTERLACED_ISCAN 0x10 -#define HCI_LMP_INTERLACED_PSCAN 0x20 -#define HCI_LMP_RSSI_INQUIRY 0x40 -#define HCI_LMP_EV3_PKT 0x80 +#define HCI_LMP_EDR_ACL_2MBPS 0x02 +#define HCI_LMP_EDR_ACL_3MBPS 0x04 +#define HCI_LMP_ENHANCED_ISCAN 0x08 +#define HCI_LMP_INTERLACED_ISCAN 0x10 +#define HCI_LMP_INTERLACED_PSCAN 0x20 +#define HCI_LMP_RSSI_INQUIRY 0x40 +#define HCI_LMP_EV3_PKT 0x80 /* ------------------- byte 4 --------------------*/ -#define HCI_LMP_EV4_PKT 0x01 -#define HCI_LMP_EV5_PKT 0x02 +#define HCI_LMP_EV4_PKT 0x01 +#define HCI_LMP_EV5_PKT 0x02 /* reserved 0x04 */ -#define HCI_LMP_AFH_CAPABLE_SLAVE 0x08 -#define HCI_LMP_AFH_CLASS_SLAVE 0x10 +#define HCI_LMP_AFH_CAPABLE_SLAVE 0x08 +#define HCI_LMP_AFH_CLASS_SLAVE 0x10 /* reserved 0x20 */ /* reserved 0x40 */ -#define HCI_LMP_3SLOT_EDR_ACL 0x80 +#define HCI_LMP_3SLOT_EDR_ACL 0x80 /* ------------------- byte 5 --------------------*/ -#define HCI_LMP_5SLOT_EDR_ACL 0x01 -#define HCI_LMP_SNIFF_SUBRATING 0x02 -#define HCI_LMP_PAUSE_ENCRYPTION 0x04 -#define HCI_LMP_AFH_CAPABLE_MASTER 0x08 -#define HCI_LMP_AFH_CLASS_MASTER 0x10 -#define HCI_LMP_EDR_eSCO_2MBPS 0x20 -#define HCI_LMP_EDR_eSCO_3MBPS 0x40 -#define HCI_LMP_3SLOT_EDR_eSCO 0x80 +#define HCI_LMP_5SLOT_EDR_ACL 0x01 +#define HCI_LMP_SNIFF_SUBRATING 0x02 +#define HCI_LMP_PAUSE_ENCRYPTION 0x04 +#define HCI_LMP_AFH_CAPABLE_MASTER 0x08 +#define HCI_LMP_AFH_CLASS_MASTER 0x10 +#define HCI_LMP_EDR_eSCO_2MBPS 0x20 +#define HCI_LMP_EDR_eSCO_3MBPS 0x40 +#define HCI_LMP_3SLOT_EDR_eSCO 0x80 /* ------------------- byte 6 --------------------*/ -#define HCI_LMP_EXTENDED_INQUIRY 0x01 +#define HCI_LMP_EXTENDED_INQUIRY 0x01 /* reserved 0x02 */ /* reserved 0x04 */ -#define HCI_LMP_SIMPLE_PAIRING 0x08 -#define HCI_LMP_ENCAPSULATED_PDU 0x10 -#define HCI_LMP_ERRDATA_REPORTING 0x20 -#define HCI_LMP_NOFLUSH_PB_FLAG 0x40 +#define HCI_LMP_SIMPLE_PAIRING 0x08 +#define HCI_LMP_ENCAPSULATED_PDU 0x10 +#define HCI_LMP_ERRDATA_REPORTING 0x20 +#define HCI_LMP_NOFLUSH_PB_FLAG 0x40 /* reserved 0x80 */ /* ------------------- byte 7 --------------------*/ -#define HCI_LMP_LINK_SUPERVISION_TO 0x01 -#define HCI_LMP_INQ_RSP_TX_POWER 0x02 -#define HCI_LMP_ENHANCED_POWER_CONTROL 0x04 -#define HCI_LMP_EXTENDED_FEATURES 0x80 +#define HCI_LMP_LINK_SUPERVISION_TO 0x01 +#define HCI_LMP_INQ_RSP_TX_POWER 0x02 +#define HCI_LMP_ENHANCED_POWER_CONTROL 0x04 +#define HCI_LMP_EXTENDED_FEATURES 0x80 /* page 1 of extended features */ /* ------------------- byte 0 --------------------*/ -#define HCI_LMP_SSP 0x01 +#define HCI_LMP_SSP 0x01 /* Link types */ -#define HCI_LINK_SCO 0x00 /* Voice */ -#define HCI_LINK_ACL 0x01 /* Data */ -#define HCI_LINK_eSCO 0x02 /* eSCO */ -/* 0x03 - 0xFF - reserved for future use */ +#define HCI_LINK_SCO 0x00 /* Voice */ +#define HCI_LINK_ACL 0x01 /* Data */ +#define HCI_LINK_eSCO 0x02 /* eSCO */ + /* 0x03 - 0xFF - reserved for future use */ /* * ACL/SCO packet type bits are set to enable the @@ -212,30 +218,30 @@ typedef struct { * are unset to enable the packet type. */ /* ACL Packet types for "Create Connection" */ -#define HCI_PKT_2MBPS_DH1 0x0002 -#define HCI_PKT_3MBPS_DH1 0x0004 -#define HCI_PKT_DM1 0x0008 -#define HCI_PKT_DH1 0x0010 -#define HCI_PKT_2MBPS_DH3 0x0100 -#define HCI_PKT_3MBPS_DH3 0x0200 -#define HCI_PKT_DM3 0x0400 -#define HCI_PKT_DH3 0x0800 -#define HCI_PKT_2MBPS_DH5 0x1000 -#define HCI_PKT_3MBPS_DH5 0x2000 -#define HCI_PKT_DM5 0x4000 -#define HCI_PKT_DH5 0x8000 +#define HCI_PKT_2MBPS_DH1 0x0002 +#define HCI_PKT_3MBPS_DH1 0x0004 +#define HCI_PKT_DM1 0x0008 +#define HCI_PKT_DH1 0x0010 +#define HCI_PKT_2MBPS_DH3 0x0100 +#define HCI_PKT_3MBPS_DH3 0x0200 +#define HCI_PKT_DM3 0x0400 +#define HCI_PKT_DH3 0x0800 +#define HCI_PKT_2MBPS_DH5 0x1000 +#define HCI_PKT_3MBPS_DH5 0x2000 +#define HCI_PKT_DM5 0x4000 +#define HCI_PKT_DH5 0x8000 /* SCO Packet types for "Setup Synchronous Connection" */ -#define HCI_PKT_HV1 0x0001 -#define HCI_PKT_HV2 0x0002 -#define HCI_PKT_HV3 0x0004 -#define HCI_PKT_EV3 0x0008 -#define HCI_PKT_EV4 0x0010 -#define HCI_PKT_EV5 0x0020 -#define HCI_PKT_2MBPS_EV3 0x0040 -#define HCI_PKT_3MBPS_EV3 0x0080 -#define HCI_PKT_2MBPS_EV5 0x0100 -#define HCI_PKT_3MBPS_EV5 0x0200 +#define HCI_PKT_HV1 0x0001 +#define HCI_PKT_HV2 0x0002 +#define HCI_PKT_HV3 0x0004 +#define HCI_PKT_EV3 0x0008 +#define HCI_PKT_EV4 0x0010 +#define HCI_PKT_EV5 0x0020 +#define HCI_PKT_2MBPS_EV3 0x0040 +#define HCI_PKT_3MBPS_EV3 0x0080 +#define HCI_PKT_2MBPS_EV5 0x0100 +#define HCI_PKT_3MBPS_EV5 0x0200 /* * Connection modes/Unit modes @@ -246,148 +252,148 @@ typedef struct { */ /* Page scan modes (are deprecated) */ -#define HCI_MANDATORY_PAGE_SCAN_MODE 0x00 -#define HCI_OPTIONAL_PAGE_SCAN_MODE1 0x01 -#define HCI_OPTIONAL_PAGE_SCAN_MODE2 0x02 -#define HCI_OPTIONAL_PAGE_SCAN_MODE3 0x03 +#define HCI_MANDATORY_PAGE_SCAN_MODE 0x00 +#define HCI_OPTIONAL_PAGE_SCAN_MODE1 0x01 +#define HCI_OPTIONAL_PAGE_SCAN_MODE2 0x02 +#define HCI_OPTIONAL_PAGE_SCAN_MODE3 0x03 /* 0x04 - 0xFF - reserved for future use */ /* Page scan repetition modes */ -#define HCI_SCAN_REP_MODE0 0x00 -#define HCI_SCAN_REP_MODE1 0x01 -#define HCI_SCAN_REP_MODE2 0x02 +#define HCI_SCAN_REP_MODE0 0x00 +#define HCI_SCAN_REP_MODE1 0x01 +#define HCI_SCAN_REP_MODE2 0x02 /* 0x03 - 0xFF - reserved for future use */ /* Page scan period modes */ -#define HCI_PAGE_SCAN_PERIOD_MODE0 0x00 -#define HCI_PAGE_SCAN_PERIOD_MODE1 0x01 -#define HCI_PAGE_SCAN_PERIOD_MODE2 0x02 +#define HCI_PAGE_SCAN_PERIOD_MODE0 0x00 +#define HCI_PAGE_SCAN_PERIOD_MODE1 0x01 +#define HCI_PAGE_SCAN_PERIOD_MODE2 0x02 /* 0x03 - 0xFF - reserved for future use */ /* Scan enable */ -#define HCI_NO_SCAN_ENABLE 0x00 -#define HCI_INQUIRY_SCAN_ENABLE 0x01 -#define HCI_PAGE_SCAN_ENABLE 0x02 +#define HCI_NO_SCAN_ENABLE 0x00 +#define HCI_INQUIRY_SCAN_ENABLE 0x01 +#define HCI_PAGE_SCAN_ENABLE 0x02 /* 0x04 - 0xFF - reserved for future use */ /* Hold mode activities */ -#define HCI_HOLD_MODE_NO_CHANGE 0x00 -#define HCI_HOLD_MODE_SUSPEND_PAGE_SCAN 0x01 -#define HCI_HOLD_MODE_SUSPEND_INQUIRY_SCAN 0x02 -#define HCI_HOLD_MODE_SUSPEND_PERIOD_INQUIRY 0x04 +#define HCI_HOLD_MODE_NO_CHANGE 0x00 +#define HCI_HOLD_MODE_SUSPEND_PAGE_SCAN 0x01 +#define HCI_HOLD_MODE_SUSPEND_INQUIRY_SCAN 0x02 +#define HCI_HOLD_MODE_SUSPEND_PERIOD_INQUIRY 0x04 /* 0x08 - 0x80 - reserved for future use */ /* Connection roles */ -#define HCI_ROLE_MASTER 0x00 -#define HCI_ROLE_SLAVE 0x01 +#define HCI_ROLE_MASTER 0x00 +#define HCI_ROLE_SLAVE 0x01 /* 0x02 - 0xFF - reserved for future use */ /* Key flags */ -#define HCI_USE_SEMI_PERMANENT_LINK_KEYS 0x00 -#define HCI_USE_TEMPORARY_LINK_KEY 0x01 +#define HCI_USE_SEMI_PERMANENT_LINK_KEYS 0x00 +#define HCI_USE_TEMPORARY_LINK_KEY 0x01 /* 0x02 - 0xFF - reserved for future use */ /* Pin types */ -#define HCI_PIN_TYPE_VARIABLE 0x00 -#define HCI_PIN_TYPE_FIXED 0x01 +#define HCI_PIN_TYPE_VARIABLE 0x00 +#define HCI_PIN_TYPE_FIXED 0x01 /* Link key types */ -#define HCI_LINK_KEY_TYPE_COMBINATION_KEY 0x00 -#define HCI_LINK_KEY_TYPE_LOCAL_UNIT_KEY 0x01 -#define HCI_LINK_KEY_TYPE_REMOTE_UNIT_KEY 0x02 +#define HCI_LINK_KEY_TYPE_COMBINATION_KEY 0x00 +#define HCI_LINK_KEY_TYPE_LOCAL_UNIT_KEY 0x01 +#define HCI_LINK_KEY_TYPE_REMOTE_UNIT_KEY 0x02 /* 0x03 - 0xFF - reserved for future use */ /* Encryption modes */ -#define HCI_ENCRYPTION_MODE_NONE 0x00 -#define HCI_ENCRYPTION_MODE_P2P 0x01 -#define HCI_ENCRYPTION_MODE_ALL 0x02 +#define HCI_ENCRYPTION_MODE_NONE 0x00 +#define HCI_ENCRYPTION_MODE_P2P 0x01 +#define HCI_ENCRYPTION_MODE_ALL 0x02 /* 0x03 - 0xFF - reserved for future use */ /* Quality of service types */ -#define HCI_SERVICE_TYPE_NO_TRAFFIC 0x00 -#define HCI_SERVICE_TYPE_BEST_EFFORT 0x01 -#define HCI_SERVICE_TYPE_GUARANTEED 0x02 +#define HCI_SERVICE_TYPE_NO_TRAFFIC 0x00 +#define HCI_SERVICE_TYPE_BEST_EFFORT 0x01 +#define HCI_SERVICE_TYPE_GUARANTEED 0x02 /* 0x03 - 0xFF - reserved for future use */ /* Link policy settings */ -#define HCI_LINK_POLICY_DISABLE_ALL_LM_MODES 0x0000 -#define HCI_LINK_POLICY_ENABLE_ROLE_SWITCH 0x0001 /* Master/Slave switch */ -#define HCI_LINK_POLICY_ENABLE_HOLD_MODE 0x0002 -#define HCI_LINK_POLICY_ENABLE_SNIFF_MODE 0x0004 -#define HCI_LINK_POLICY_ENABLE_PARK_MODE 0x0008 +#define HCI_LINK_POLICY_DISABLE_ALL_LM_MODES 0x0000 +#define HCI_LINK_POLICY_ENABLE_ROLE_SWITCH 0x0001 /* Master/Slave switch */ +#define HCI_LINK_POLICY_ENABLE_HOLD_MODE 0x0002 +#define HCI_LINK_POLICY_ENABLE_SNIFF_MODE 0x0004 +#define HCI_LINK_POLICY_ENABLE_PARK_MODE 0x0008 /* 0x0010 - 0x8000 - reserved for future use */ /* Event masks */ -#define HCI_EVMSK_ALL 0x00000000ffffffff -#define HCI_EVMSK_NONE 0x0000000000000000 -#define HCI_EVMSK_INQUIRY_COMPL 0x0000000000000001 -#define HCI_EVMSK_INQUIRY_RESULT 0x0000000000000002 -#define HCI_EVMSK_CON_COMPL 0x0000000000000004 -#define HCI_EVMSK_CON_REQ 0x0000000000000008 -#define HCI_EVMSK_DISCON_COMPL 0x0000000000000010 -#define HCI_EVMSK_AUTH_COMPL 0x0000000000000020 -#define HCI_EVMSK_REMOTE_NAME_REQ_COMPL 0x0000000000000040 -#define HCI_EVMSK_ENCRYPTION_CHANGE 0x0000000000000080 -#define HCI_EVMSK_CHANGE_CON_LINK_KEY_COMPL 0x0000000000000100 -#define HCI_EVMSK_MASTER_LINK_KEY_COMPL 0x0000000000000200 -#define HCI_EVMSK_READ_REMOTE_FEATURES_COMPL 0x0000000000000400 -#define HCI_EVMSK_READ_REMOTE_VER_INFO_COMPL 0x0000000000000800 -#define HCI_EVMSK_QOS_SETUP_COMPL 0x0000000000001000 -#define HCI_EVMSK_COMMAND_COMPL 0x0000000000002000 -#define HCI_EVMSK_COMMAND_STATUS 0x0000000000004000 -#define HCI_EVMSK_HARDWARE_ERROR 0x0000000000008000 -#define HCI_EVMSK_FLUSH_OCCUR 0x0000000000010000 -#define HCI_EVMSK_ROLE_CHANGE 0x0000000000020000 -#define HCI_EVMSK_NUM_COMPL_PKTS 0x0000000000040000 -#define HCI_EVMSK_MODE_CHANGE 0x0000000000080000 -#define HCI_EVMSK_RETURN_LINK_KEYS 0x0000000000100000 -#define HCI_EVMSK_PIN_CODE_REQ 0x0000000000200000 -#define HCI_EVMSK_LINK_KEY_REQ 0x0000000000400000 -#define HCI_EVMSK_LINK_KEY_NOTIFICATION 0x0000000000800000 -#define HCI_EVMSK_LOOPBACK_COMMAND 0x0000000001000000 -#define HCI_EVMSK_DATA_BUFFER_OVERFLOW 0x0000000002000000 -#define HCI_EVMSK_MAX_SLOT_CHANGE 0x0000000004000000 -#define HCI_EVMSK_READ_CLOCK_OFFSET_COMLETE 0x0000000008000000 -#define HCI_EVMSK_CON_PKT_TYPE_CHANGED 0x0000000010000000 -#define HCI_EVMSK_QOS_VIOLATION 0x0000000020000000 -#define HCI_EVMSK_PAGE_SCAN_MODE_CHANGE 0x0000000040000000 -#define HCI_EVMSK_PAGE_SCAN_REP_MODE_CHANGE 0x0000000080000000 +#define HCI_EVMSK_ALL 0x00000000ffffffff +#define HCI_EVMSK_NONE 0x0000000000000000 +#define HCI_EVMSK_INQUIRY_COMPL 0x0000000000000001 +#define HCI_EVMSK_INQUIRY_RESULT 0x0000000000000002 +#define HCI_EVMSK_CON_COMPL 0x0000000000000004 +#define HCI_EVMSK_CON_REQ 0x0000000000000008 +#define HCI_EVMSK_DISCON_COMPL 0x0000000000000010 +#define HCI_EVMSK_AUTH_COMPL 0x0000000000000020 +#define HCI_EVMSK_REMOTE_NAME_REQ_COMPL 0x0000000000000040 +#define HCI_EVMSK_ENCRYPTION_CHANGE 0x0000000000000080 +#define HCI_EVMSK_CHANGE_CON_LINK_KEY_COMPL 0x0000000000000100 +#define HCI_EVMSK_MASTER_LINK_KEY_COMPL 0x0000000000000200 +#define HCI_EVMSK_READ_REMOTE_FEATURES_COMPL 0x0000000000000400 +#define HCI_EVMSK_READ_REMOTE_VER_INFO_COMPL 0x0000000000000800 +#define HCI_EVMSK_QOS_SETUP_COMPL 0x0000000000001000 +#define HCI_EVMSK_COMMAND_COMPL 0x0000000000002000 +#define HCI_EVMSK_COMMAND_STATUS 0x0000000000004000 +#define HCI_EVMSK_HARDWARE_ERROR 0x0000000000008000 +#define HCI_EVMSK_FLUSH_OCCUR 0x0000000000010000 +#define HCI_EVMSK_ROLE_CHANGE 0x0000000000020000 +#define HCI_EVMSK_NUM_COMPL_PKTS 0x0000000000040000 +#define HCI_EVMSK_MODE_CHANGE 0x0000000000080000 +#define HCI_EVMSK_RETURN_LINK_KEYS 0x0000000000100000 +#define HCI_EVMSK_PIN_CODE_REQ 0x0000000000200000 +#define HCI_EVMSK_LINK_KEY_REQ 0x0000000000400000 +#define HCI_EVMSK_LINK_KEY_NOTIFICATION 0x0000000000800000 +#define HCI_EVMSK_LOOPBACK_COMMAND 0x0000000001000000 +#define HCI_EVMSK_DATA_BUFFER_OVERFLOW 0x0000000002000000 +#define HCI_EVMSK_MAX_SLOT_CHANGE 0x0000000004000000 +#define HCI_EVMSK_READ_CLOCK_OFFSET_COMLETE 0x0000000008000000 +#define HCI_EVMSK_CON_PKT_TYPE_CHANGED 0x0000000010000000 +#define HCI_EVMSK_QOS_VIOLATION 0x0000000020000000 +#define HCI_EVMSK_PAGE_SCAN_MODE_CHANGE 0x0000000040000000 +#define HCI_EVMSK_PAGE_SCAN_REP_MODE_CHANGE 0x0000000080000000 /* 0x0000000100000000 - 0x8000000000000000 - reserved for future use */ /* Filter types */ -#define HCI_FILTER_TYPE_NONE 0x00 -#define HCI_FILTER_TYPE_INQUIRY_RESULT 0x01 -#define HCI_FILTER_TYPE_CON_SETUP 0x02 +#define HCI_FILTER_TYPE_NONE 0x00 +#define HCI_FILTER_TYPE_INQUIRY_RESULT 0x01 +#define HCI_FILTER_TYPE_CON_SETUP 0x02 /* 0x03 - 0xFF - reserved for future use */ /* Filter condition types for HCI_FILTER_TYPE_INQUIRY_RESULT */ -#define HCI_FILTER_COND_INQUIRY_NEW_UNIT 0x00 -#define HCI_FILTER_COND_INQUIRY_UNIT_CLASS 0x01 -#define HCI_FILTER_COND_INQUIRY_BDADDR 0x02 +#define HCI_FILTER_COND_INQUIRY_NEW_UNIT 0x00 +#define HCI_FILTER_COND_INQUIRY_UNIT_CLASS 0x01 +#define HCI_FILTER_COND_INQUIRY_BDADDR 0x02 /* 0x03 - 0xFF - reserved for future use */ /* Filter condition types for HCI_FILTER_TYPE_CON_SETUP */ -#define HCI_FILTER_COND_CON_ANY_UNIT 0x00 -#define HCI_FILTER_COND_CON_UNIT_CLASS 0x01 -#define HCI_FILTER_COND_CON_BDADDR 0x02 +#define HCI_FILTER_COND_CON_ANY_UNIT 0x00 +#define HCI_FILTER_COND_CON_UNIT_CLASS 0x01 +#define HCI_FILTER_COND_CON_BDADDR 0x02 /* 0x03 - 0xFF - reserved for future use */ /* Xmit level types */ -#define HCI_XMIT_LEVEL_CURRENT 0x00 -#define HCI_XMIT_LEVEL_MAXIMUM 0x01 +#define HCI_XMIT_LEVEL_CURRENT 0x00 +#define HCI_XMIT_LEVEL_MAXIMUM 0x01 /* 0x02 - 0xFF - reserved for future use */ /* Host Controller to Host flow control */ -#define HCI_HC2H_FLOW_CONTROL_NONE 0x00 -#define HCI_HC2H_FLOW_CONTROL_ACL 0x01 -#define HCI_HC2H_FLOW_CONTROL_SCO 0x02 -#define HCI_HC2H_FLOW_CONTROL_BOTH 0x03 +#define HCI_HC2H_FLOW_CONTROL_NONE 0x00 +#define HCI_HC2H_FLOW_CONTROL_ACL 0x01 +#define HCI_HC2H_FLOW_CONTROL_SCO 0x02 +#define HCI_HC2H_FLOW_CONTROL_BOTH 0x03 /* 0x04 - 0xFF - reserved future use */ /* Loopback modes */ -#define HCI_LOOPBACK_NONE 0x00 -#define HCI_LOOPBACK_LOCAL 0x01 -#define HCI_LOOPBACK_REMOTE 0x02 +#define HCI_LOOPBACK_NONE 0x00 +#define HCI_LOOPBACK_LOCAL 0x01 +#define HCI_LOOPBACK_REMOTE 0x02 /* 0x03 - 0xFF - reserved future use */ /************************************************************************** @@ -401,76 +407,80 @@ typedef struct { * and OCF (OpCode Command Field) from OpCode. */ -#define HCI_OPCODE(gf,cf) ((((gf) & 0x3f) << 10) | ((cf) & 0x3ff)) -#define HCI_OCF(op) ((op) & 0x3ff) -#define HCI_OGF(op) (((op) >> 10) & 0x3f) +#define HCI_OPCODE(gf, cf) ((((gf)&0x3f) << 10) | ((cf)&0x3ff)) +#define HCI_OCF(op) ((op)&0x3ff) +#define HCI_OGF(op) (((op) >> 10) & 0x3f) /* * Macro(s) to extract/combine connection handle, BC (Broadcast) and * PB (Packet boundary) flags. */ -#define HCI_CON_HANDLE(h) ((h) & 0x0fff) -#define HCI_PB_FLAG(h) (((h) & 0x3000) >> 12) -#define HCI_BC_FLAG(h) (((h) & 0xc000) >> 14) -#define HCI_MK_CON_HANDLE(h, pb, bc) \ - (((h) & 0x0fff) | (((pb) & 3) << 12) | (((bc) & 3) << 14)) +#define HCI_CON_HANDLE(h) ((h)&0x0fff) +#define HCI_PB_FLAG(h) (((h)&0x3000) >> 12) +#define HCI_BC_FLAG(h) (((h)&0xc000) >> 14) +#define HCI_MK_CON_HANDLE(h, pb, bc) (((h)&0x0fff) | (((pb)&3) << 12) | (((bc)&3) << 14)) /* PB flag values */ - /* 00 - reserved for future use */ -#define HCI_PACKET_FRAGMENT 0x1 -#define HCI_PACKET_START 0x2 - /* 11 - reserved for future use */ +/* 00 - reserved for future use */ +#define HCI_PACKET_FRAGMENT 0x1 +#define HCI_PACKET_START 0x2 +/* 11 - reserved for future use */ /* BC flag values */ -#define HCI_POINT2POINT 0x0 /* only Host controller to Host */ -#define HCI_BROADCAST_ACTIVE 0x1 /* both directions */ -#define HCI_BROADCAST_PICONET 0x2 /* both directions */ - /* 11 - reserved for future use */ +#define HCI_POINT2POINT 0x0 /* only Host controller to Host */ +#define HCI_BROADCAST_ACTIVE 0x1 /* both directions */ +#define HCI_BROADCAST_PICONET 0x2 /* both directions */ + /* 11 - reserved for future use */ /* HCI command packet header */ -typedef struct { - //uint8_t type; /* MUST be 0x01 */ - uint16_t opcode; /* OpCode */ - uint8_t length; /* parameter(s) length in bytes */ +typedef struct +{ + // uint8_t type; /* MUST be 0x01 */ + uint16_t opcode; /* OpCode */ + uint8_t length; /* parameter(s) length in bytes */ } hci_cmd_hdr_t; -#define HCI_CMD_PKT 0x01 -#define HCI_CMD_PKT_SIZE (sizeof(hci_cmd_hdr_t) + 0xff) +#define HCI_CMD_PKT 0x01 +#define HCI_CMD_PKT_SIZE (sizeof(hci_cmd_hdr_t) + 0xff) /* ACL data packet header */ -typedef struct { - //uint8_t type; /* MUST be 0x02 */ - uint16_t con_handle; /* connection handle + PB + BC flags */ - uint16_t length; /* payload length in bytes */ +typedef struct +{ + // uint8_t type; /* MUST be 0x02 */ + uint16_t con_handle; /* connection handle + PB + BC flags */ + uint16_t length; /* payload length in bytes */ } hci_acldata_hdr_t; -#define HCI_ACL_DATA_PKT 0x02 -#define HCI_ACL_PKT_SIZE (sizeof(hci_acldata_hdr_t) + 0xffff) +#define HCI_ACL_DATA_PKT 0x02 +#define HCI_ACL_PKT_SIZE (sizeof(hci_acldata_hdr_t) + 0xffff) /* SCO data packet header */ -typedef struct { - //uint8_t type; /* MUST be 0x03 */ - uint16_t con_handle; /* connection handle + reserved bits */ - uint8_t length; /* payload length in bytes */ +typedef struct +{ + // uint8_t type; /* MUST be 0x03 */ + uint16_t con_handle; /* connection handle + reserved bits */ + uint8_t length; /* payload length in bytes */ } hci_scodata_hdr_t; -#define HCI_SCO_DATA_PKT 0x03 -#define HCI_SCO_PKT_SIZE (sizeof(hci_scodata_hdr_t) + 0xff) +#define HCI_SCO_DATA_PKT 0x03 +#define HCI_SCO_PKT_SIZE (sizeof(hci_scodata_hdr_t) + 0xff) /* HCI event packet header */ -typedef struct { - //uint8_t type; /* MUST be 0x04 */ - uint8_t event; /* event */ - uint8_t length; /* parameter(s) length in bytes */ +typedef struct +{ + // uint8_t type; /* MUST be 0x04 */ + uint8_t event; /* event */ + uint8_t length; /* parameter(s) length in bytes */ } hci_event_hdr_t; -#define HCI_EVENT_PKT 0x04 -#define HCI_EVENT_PKT_SIZE (sizeof(hci_event_hdr_t) + 0xff) +#define HCI_EVENT_PKT 0x04 +#define HCI_EVENT_PKT_SIZE (sizeof(hci_event_hdr_t) + 0xff) /* HCI status return parameter */ -typedef struct { - uint8_t status; /* 0x00 - success */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ } hci_status_rp; /************************************************************************** @@ -479,369 +489,419 @@ typedef struct { ************************************************************************** **************************************************************************/ -#define HCI_OGF_LINK_CONTROL 0x01 +#define HCI_OGF_LINK_CONTROL 0x01 -#define HCI_OCF_INQUIRY 0x0001 -#define HCI_CMD_INQUIRY 0x0401 -typedef struct { - uint8_t lap[HCI_LAP_SIZE]; /* LAP */ - uint8_t inquiry_length; /* (N x 1.28) sec */ - uint8_t num_responses; /* Max. # of responses */ +#define HCI_OCF_INQUIRY 0x0001 +#define HCI_CMD_INQUIRY 0x0401 +typedef struct +{ + uint8_t lap[HCI_LAP_SIZE]; /* LAP */ + uint8_t inquiry_length; /* (N x 1.28) sec */ + uint8_t num_responses; /* Max. # of responses */ } hci_inquiry_cp; /* No return parameter(s) */ -#define HCI_OCF_INQUIRY_CANCEL 0x0002 -#define HCI_CMD_INQUIRY_CANCEL 0x0402 +#define HCI_OCF_INQUIRY_CANCEL 0x0002 +#define HCI_CMD_INQUIRY_CANCEL 0x0402 /* No command parameter(s) */ -typedef hci_status_rp hci_inquiry_cancel_rp; +typedef hci_status_rp hci_inquiry_cancel_rp; -#define HCI_OCF_PERIODIC_INQUIRY 0x0003 -#define HCI_CMD_PERIODIC_INQUIRY 0x0403 -typedef struct { - uint16_t max_period_length; /* Max. and min. amount of time */ - uint16_t min_period_length; /* between consecutive inquiries */ - uint8_t lap[HCI_LAP_SIZE]; /* LAP */ - uint8_t inquiry_length; /* (inquiry_length * 1.28) sec */ - uint8_t num_responses; /* Max. # of responses */ +#define HCI_OCF_PERIODIC_INQUIRY 0x0003 +#define HCI_CMD_PERIODIC_INQUIRY 0x0403 +typedef struct +{ + uint16_t max_period_length; /* Max. and min. amount of time */ + uint16_t min_period_length; /* between consecutive inquiries */ + uint8_t lap[HCI_LAP_SIZE]; /* LAP */ + uint8_t inquiry_length; /* (inquiry_length * 1.28) sec */ + uint8_t num_responses; /* Max. # of responses */ } hci_periodic_inquiry_cp; -typedef hci_status_rp hci_periodic_inquiry_rp; +typedef hci_status_rp hci_periodic_inquiry_rp; -#define HCI_OCF_EXIT_PERIODIC_INQUIRY 0x0004 -#define HCI_CMD_EXIT_PERIODIC_INQUIRY 0x0404 +#define HCI_OCF_EXIT_PERIODIC_INQUIRY 0x0004 +#define HCI_CMD_EXIT_PERIODIC_INQUIRY 0x0404 /* No command parameter(s) */ -typedef hci_status_rp hci_exit_periodic_inquiry_rp; +typedef hci_status_rp hci_exit_periodic_inquiry_rp; -#define HCI_OCF_CREATE_CON 0x0005 -#define HCI_CMD_CREATE_CON 0x0405 -typedef struct { - bdaddr_t bdaddr; /* destination address */ - uint16_t pkt_type; /* packet type */ - uint8_t page_scan_rep_mode; /* page scan repetition mode */ - uint8_t page_scan_mode; /* reserved - set to 0x00 */ - uint16_t clock_offset; /* clock offset */ - uint8_t accept_role_switch; /* accept role switch? 0x00 == No */ +#define HCI_OCF_CREATE_CON 0x0005 +#define HCI_CMD_CREATE_CON 0x0405 +typedef struct +{ + bdaddr_t bdaddr; /* destination address */ + uint16_t pkt_type; /* packet type */ + uint8_t page_scan_rep_mode; /* page scan repetition mode */ + uint8_t page_scan_mode; /* reserved - set to 0x00 */ + uint16_t clock_offset; /* clock offset */ + uint8_t accept_role_switch; /* accept role switch? 0x00 == No */ } hci_create_con_cp; /* No return parameter(s) */ -#define HCI_OCF_DISCONNECT 0x0006 -#define HCI_CMD_DISCONNECT 0x0406 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t reason; /* reason to disconnect */ +#define HCI_OCF_DISCONNECT 0x0006 +#define HCI_CMD_DISCONNECT 0x0406 +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint8_t reason; /* reason to disconnect */ } hci_discon_cp; /* No return parameter(s) */ /* Add SCO Connection is deprecated */ -#define HCI_OCF_ADD_SCO_CON 0x0007 -#define HCI_CMD_ADD_SCO_CON 0x0407 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t pkt_type; /* packet type */ +#define HCI_OCF_ADD_SCO_CON 0x0007 +#define HCI_CMD_ADD_SCO_CON 0x0407 +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint16_t pkt_type; /* packet type */ } hci_add_sco_con_cp; /* No return parameter(s) */ -#define HCI_OCF_CREATE_CON_CANCEL 0x0008 -#define HCI_CMD_CREATE_CON_CANCEL 0x0408 -typedef struct { - bdaddr_t bdaddr; /* destination address */ +#define HCI_OCF_CREATE_CON_CANCEL 0x0008 +#define HCI_CMD_CREATE_CON_CANCEL 0x0408 +typedef struct +{ + bdaddr_t bdaddr; /* destination address */ } hci_create_con_cancel_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* destination address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* destination address */ } hci_create_con_cancel_rp; -#define HCI_OCF_ACCEPT_CON 0x0009 -#define HCI_CMD_ACCEPT_CON 0x0409 -typedef struct { - bdaddr_t bdaddr; /* address of unit to be connected */ - uint8_t role; /* connection role */ +#define HCI_OCF_ACCEPT_CON 0x0009 +#define HCI_CMD_ACCEPT_CON 0x0409 +typedef struct +{ + bdaddr_t bdaddr; /* address of unit to be connected */ + uint8_t role; /* connection role */ } hci_accept_con_cp; /* No return parameter(s) */ -#define HCI_OCF_REJECT_CON 0x000a -#define HCI_CMD_REJECT_CON 0x040A -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t reason; /* reason to reject */ +#define HCI_OCF_REJECT_CON 0x000a +#define HCI_CMD_REJECT_CON 0x040A +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ + uint8_t reason; /* reason to reject */ } hci_reject_con_cp; /* No return parameter(s) */ -#define HCI_OCF_LINK_KEY_REP 0x000b -#define HCI_CMD_LINK_KEY_REP 0x040B -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t key[HCI_KEY_SIZE]; /* key */ +#define HCI_OCF_LINK_KEY_REP 0x000b +#define HCI_CMD_LINK_KEY_REP 0x040B +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ + uint8_t key[HCI_KEY_SIZE]; /* key */ } hci_link_key_rep_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* unit address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* unit address */ } hci_link_key_rep_rp; -#define HCI_OCF_LINK_KEY_NEG_REP 0x000c -#define HCI_CMD_LINK_KEY_NEG_REP 0x040C -typedef struct { - bdaddr_t bdaddr; /* remote address */ +#define HCI_OCF_LINK_KEY_NEG_REP 0x000c +#define HCI_CMD_LINK_KEY_NEG_REP 0x040C +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ } hci_link_key_neg_rep_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* unit address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* unit address */ } hci_link_key_neg_rep_rp; -#define HCI_OCF_PIN_CODE_REP 0x000d -#define HCI_CMD_PIN_CODE_REP 0x040D -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t pin_size; /* pin code length (in bytes) */ - uint8_t pin[HCI_PIN_SIZE]; /* pin code */ +#define HCI_OCF_PIN_CODE_REP 0x000d +#define HCI_CMD_PIN_CODE_REP 0x040D +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ + uint8_t pin_size; /* pin code length (in bytes) */ + uint8_t pin[HCI_PIN_SIZE]; /* pin code */ } hci_pin_code_rep_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* unit address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* unit address */ } hci_pin_code_rep_rp; -#define HCI_OCF_PIN_CODE_NEG_REP 0x000e -#define HCI_CMD_PIN_CODE_NEG_REP 0x040E -typedef struct { - bdaddr_t bdaddr; /* remote address */ +#define HCI_OCF_PIN_CODE_NEG_REP 0x000e +#define HCI_CMD_PIN_CODE_NEG_REP 0x040E +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ } hci_pin_code_neg_rep_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* unit address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* unit address */ } hci_pin_code_neg_rep_rp; -#define HCI_OCF_CHANGE_CON_PACKET_TYPE 0x000f -#define HCI_CMD_CHANGE_CON_PACKET_TYPE 0x040F -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t pkt_type; /* packet type */ +#define HCI_OCF_CHANGE_CON_PACKET_TYPE 0x000f +#define HCI_CMD_CHANGE_CON_PACKET_TYPE 0x040F +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint16_t pkt_type; /* packet type */ } hci_change_con_pkt_type_cp; /* No return parameter(s) */ -#define HCI_OCF_AUTH_REQ 0x0011 -#define HCI_CMD_AUTH_REQ 0x0411 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_AUTH_REQ 0x0011 +#define HCI_CMD_AUTH_REQ 0x0411 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_auth_req_cp; /* No return parameter(s) */ -#define HCI_OCF_SET_CON_ENCRYPTION 0x0013 -#define HCI_CMD_SET_CON_ENCRYPTION 0x0413 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t encryption_enable; /* 0x00 - disable, 0x01 - enable */ +#define HCI_OCF_SET_CON_ENCRYPTION 0x0013 +#define HCI_CMD_SET_CON_ENCRYPTION 0x0413 +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint8_t encryption_enable; /* 0x00 - disable, 0x01 - enable */ } hci_set_con_encryption_cp; /* No return parameter(s) */ -#define HCI_OCF_CHANGE_CON_LINK_KEY 0x0015 -#define HCI_CMD_CHANGE_CON_LINK_KEY 0x0415 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_CHANGE_CON_LINK_KEY 0x0015 +#define HCI_CMD_CHANGE_CON_LINK_KEY 0x0415 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_change_con_link_key_cp; /* No return parameter(s) */ -#define HCI_OCF_MASTER_LINK_KEY 0x0017 -#define HCI_CMD_MASTER_LINK_KEY 0x0417 -typedef struct { - uint8_t key_flag; /* key flag */ +#define HCI_OCF_MASTER_LINK_KEY 0x0017 +#define HCI_CMD_MASTER_LINK_KEY 0x0417 +typedef struct +{ + uint8_t key_flag; /* key flag */ } hci_master_link_key_cp; /* No return parameter(s) */ -#define HCI_OCF_REMOTE_NAME_REQ 0x0019 -#define HCI_CMD_REMOTE_NAME_REQ 0x0419 -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t page_scan_rep_mode; /* page scan repetition mode */ - uint8_t page_scan_mode; /* page scan mode */ - uint16_t clock_offset; /* clock offset */ +#define HCI_OCF_REMOTE_NAME_REQ 0x0019 +#define HCI_CMD_REMOTE_NAME_REQ 0x0419 +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ + uint8_t page_scan_rep_mode; /* page scan repetition mode */ + uint8_t page_scan_mode; /* page scan mode */ + uint16_t clock_offset; /* clock offset */ } hci_remote_name_req_cp; /* No return parameter(s) */ -#define HCI_OCF_REMOTE_NAME_REQ_CANCEL 0x001a -#define HCI_CMD_REMOTE_NAME_REQ_CANCEL 0x041A -typedef struct { - bdaddr_t bdaddr; /* remote address */ +#define HCI_OCF_REMOTE_NAME_REQ_CANCEL 0x001a +#define HCI_CMD_REMOTE_NAME_REQ_CANCEL 0x041A +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ } hci_remote_name_req_cancel_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ } hci_remote_name_req_cancel_rp; -#define HCI_OCF_READ_REMOTE_FEATURES 0x001b -#define HCI_CMD_READ_REMOTE_FEATURES 0x041B -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_READ_REMOTE_FEATURES 0x001b +#define HCI_CMD_READ_REMOTE_FEATURES 0x041B +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_read_remote_features_cp; /* No return parameter(s) */ -#define HCI_OCF_READ_REMOTE_EXTENDED_FEATURES 0x001c -#define HCI_CMD_READ_REMOTE_EXTENDED_FEATURES 0x041C -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t page; /* page number */ +#define HCI_OCF_READ_REMOTE_EXTENDED_FEATURES 0x001c +#define HCI_CMD_READ_REMOTE_EXTENDED_FEATURES 0x041C +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint8_t page; /* page number */ } hci_read_remote_extended_features_cp; /* No return parameter(s) */ -#define HCI_OCF_READ_REMOTE_VER_INFO 0x001d -#define HCI_CMD_READ_REMOTE_VER_INFO 0x041D -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_READ_REMOTE_VER_INFO 0x001d +#define HCI_CMD_READ_REMOTE_VER_INFO 0x041D +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_read_remote_ver_info_cp; /* No return parameter(s) */ -#define HCI_OCF_READ_CLOCK_OFFSET 0x001f -#define HCI_CMD_READ_CLOCK_OFFSET 0x041F -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_READ_CLOCK_OFFSET 0x001f +#define HCI_CMD_READ_CLOCK_OFFSET 0x041F +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_read_clock_offset_cp; /* No return parameter(s) */ -#define HCI_OCF_READ_LMP_HANDLE 0x0020 -#define HCI_CMD_READ_LMP_HANDLE 0x0420 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_READ_LMP_HANDLE 0x0020 +#define HCI_CMD_READ_LMP_HANDLE 0x0420 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_read_lmp_handle_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t lmp_handle; /* LMP handle */ - uint32_t reserved; /* reserved */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t lmp_handle; /* LMP handle */ + uint32_t reserved; /* reserved */ } hci_read_lmp_handle_rp; -#define HCI_OCF_SETUP_SCO_CON 0x0028 -#define HCI_CMD_SETUP_SCO_CON 0x0428 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint32_t tx_bandwidth; /* transmit bandwidth */ - uint32_t rx_bandwidth; /* receive bandwidth */ - uint16_t latency; /* maximum latency */ - uint16_t voice; /* voice setting */ - uint8_t rt_effort; /* retransmission effort */ - uint16_t pkt_type; /* packet types */ +#define HCI_OCF_SETUP_SCO_CON 0x0028 +#define HCI_CMD_SETUP_SCO_CON 0x0428 +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint32_t tx_bandwidth; /* transmit bandwidth */ + uint32_t rx_bandwidth; /* receive bandwidth */ + uint16_t latency; /* maximum latency */ + uint16_t voice; /* voice setting */ + uint8_t rt_effort; /* retransmission effort */ + uint16_t pkt_type; /* packet types */ } hci_setup_sco_con_cp; /* No return parameter(s) */ -#define HCI_OCF_ACCEPT_SCO_CON_REQ 0x0029 -#define HCI_CMD_ACCEPT_SCO_CON_REQ 0x0429 -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint32_t tx_bandwidth; /* transmit bandwidth */ - uint32_t rx_bandwidth; /* receive bandwidth */ - uint16_t latency; /* maximum latency */ - uint16_t content; /* voice setting */ - uint8_t rt_effort; /* retransmission effort */ - uint16_t pkt_type; /* packet types */ +#define HCI_OCF_ACCEPT_SCO_CON_REQ 0x0029 +#define HCI_CMD_ACCEPT_SCO_CON_REQ 0x0429 +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ + uint32_t tx_bandwidth; /* transmit bandwidth */ + uint32_t rx_bandwidth; /* receive bandwidth */ + uint16_t latency; /* maximum latency */ + uint16_t content; /* voice setting */ + uint8_t rt_effort; /* retransmission effort */ + uint16_t pkt_type; /* packet types */ } hci_accept_sco_con_req_cp; /* No return parameter(s) */ -#define HCI_OCF_REJECT_SCO_CON_REQ 0x002a -#define HCI_CMD_REJECT_SCO_CON_REQ 0x042a -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t reason; /* reject error code */ +#define HCI_OCF_REJECT_SCO_CON_REQ 0x002a +#define HCI_CMD_REJECT_SCO_CON_REQ 0x042a +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ + uint8_t reason; /* reject error code */ } hci_reject_sco_con_req_cp; /* No return parameter(s) */ -#define HCI_OCF_IO_CAPABILITY_REP 0x002b -#define HCI_CMD_IO_CAPABILITY_REP 0x042a -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t io_cap; /* IO capability */ - uint8_t oob_data; /* OOB data present */ - uint8_t auth_req; /* auth requirements */ +#define HCI_OCF_IO_CAPABILITY_REP 0x002b +#define HCI_CMD_IO_CAPABILITY_REP 0x042a +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ + uint8_t io_cap; /* IO capability */ + uint8_t oob_data; /* OOB data present */ + uint8_t auth_req; /* auth requirements */ } hci_io_capability_rep_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ } hci_io_capability_rep_rp; -#define HCI_OCF_USER_CONFIRM_REP 0x002c -#define HCI_CMD_USER_CONFIRM_REP 0x042c -typedef struct { - bdaddr_t bdaddr; /* remote address */ +#define HCI_OCF_USER_CONFIRM_REP 0x002c +#define HCI_CMD_USER_CONFIRM_REP 0x042c +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ } hci_user_confirm_rep_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ } hci_user_confirm_rep_rp; -#define HCI_OCF_USER_CONFIRM_NEG_REP 0x002d -#define HCI_CMD_USER_CONFIRM_NEG_REP 0x042d -typedef struct { - bdaddr_t bdaddr; /* remote address */ +#define HCI_OCF_USER_CONFIRM_NEG_REP 0x002d +#define HCI_CMD_USER_CONFIRM_NEG_REP 0x042d +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ } hci_user_confirm_neg_rep_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ } hci_user_confirm_neg_rep_rp; -#define HCI_OCF_USER_PASSKEY_REP 0x002e -#define HCI_CMD_USER_PASSKEY_REP 0x042e -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint32_t value; /* 000000 - 999999 */ +#define HCI_OCF_USER_PASSKEY_REP 0x002e +#define HCI_CMD_USER_PASSKEY_REP 0x042e +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ + uint32_t value; /* 000000 - 999999 */ } hci_user_passkey_rep_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ } hci_user_passkey_rep_rp; -#define HCI_OCF_USER_PASSKEY_NEG_REP 0x002f -#define HCI_CMD_USER_PASSKEY_NEG_REP 0x042f -typedef struct { - bdaddr_t bdaddr; /* remote address */ +#define HCI_OCF_USER_PASSKEY_NEG_REP 0x002f +#define HCI_CMD_USER_PASSKEY_NEG_REP 0x042f +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ } hci_user_passkey_neg_rep_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ } hci_user_passkey_neg_rep_rp; -#define HCI_OCF_OOB_DATA_REP 0x0030 -#define HCI_CMD_OOB_DATA_REP 0x0430 -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t c[16]; /* pairing hash */ - uint8_t r[16]; /* pairing randomizer */ +#define HCI_OCF_OOB_DATA_REP 0x0030 +#define HCI_CMD_OOB_DATA_REP 0x0430 +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ + uint8_t c[16]; /* pairing hash */ + uint8_t r[16]; /* pairing randomizer */ } hci_user_oob_data_rep_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ } hci_user_oob_data_rep_rp; -#define HCI_OCF_OOB_DATA_NEG_REP 0x0033 -#define HCI_CMD_OOB_DATA_NEG_REP 0x0433 -typedef struct { - bdaddr_t bdaddr; /* remote address */ +#define HCI_OCF_OOB_DATA_NEG_REP 0x0033 +#define HCI_CMD_OOB_DATA_NEG_REP 0x0433 +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ } hci_user_oob_data_neg_rep_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ } hci_user_oob_data_neg_rep_rp; -#define HCI_OCF_IO_CAPABILITY_NEG_REP 0x0034 -#define HCI_CMD_IO_CAPABILITY_NEG_REP 0x0434 -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t reason; /* error code */ +#define HCI_OCF_IO_CAPABILITY_NEG_REP 0x0034 +#define HCI_CMD_IO_CAPABILITY_NEG_REP 0x0434 +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ + uint8_t reason; /* error code */ } hci_io_capability_neg_rep_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ } hci_io_capability_neg_rep_rp; /************************************************************************** @@ -850,150 +910,168 @@ typedef struct { ************************************************************************** **************************************************************************/ -#define HCI_OGF_LINK_POLICY 0x02 +#define HCI_OGF_LINK_POLICY 0x02 -#define HCI_OCF_HOLD_MODE 0x0001 -#define HCI_CMD_HOLD_MODE 0x0801 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t max_interval; /* (max_interval * 0.625) msec */ - uint16_t min_interval; /* (max_interval * 0.625) msec */ +#define HCI_OCF_HOLD_MODE 0x0001 +#define HCI_CMD_HOLD_MODE 0x0801 +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint16_t max_interval; /* (max_interval * 0.625) msec */ + uint16_t min_interval; /* (max_interval * 0.625) msec */ } hci_hold_mode_cp; /* No return parameter(s) */ -#define HCI_OCF_SNIFF_MODE 0x0003 -#define HCI_CMD_SNIFF_MODE 0x0803 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t max_interval; /* (max_interval * 0.625) msec */ - uint16_t min_interval; /* (max_interval * 0.625) msec */ - uint16_t attempt; /* (2 * attempt - 1) * 0.625 msec */ - uint16_t timeout; /* (2 * attempt - 1) * 0.625 msec */ +#define HCI_OCF_SNIFF_MODE 0x0003 +#define HCI_CMD_SNIFF_MODE 0x0803 +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint16_t max_interval; /* (max_interval * 0.625) msec */ + uint16_t min_interval; /* (max_interval * 0.625) msec */ + uint16_t attempt; /* (2 * attempt - 1) * 0.625 msec */ + uint16_t timeout; /* (2 * attempt - 1) * 0.625 msec */ } hci_sniff_mode_cp; /* No return parameter(s) */ -#define HCI_OCF_EXIT_SNIFF_MODE 0x0004 -#define HCI_CMD_EXIT_SNIFF_MODE 0x0804 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_EXIT_SNIFF_MODE 0x0004 +#define HCI_CMD_EXIT_SNIFF_MODE 0x0804 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_exit_sniff_mode_cp; /* No return parameter(s) */ -#define HCI_OCF_PARK_MODE 0x0005 -#define HCI_CMD_PARK_MODE 0x0805 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t max_interval; /* (max_interval * 0.625) msec */ - uint16_t min_interval; /* (max_interval * 0.625) msec */ +#define HCI_OCF_PARK_MODE 0x0005 +#define HCI_CMD_PARK_MODE 0x0805 +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint16_t max_interval; /* (max_interval * 0.625) msec */ + uint16_t min_interval; /* (max_interval * 0.625) msec */ } hci_park_mode_cp; /* No return parameter(s) */ -#define HCI_OCF_EXIT_PARK_MODE 0x0006 -#define HCI_CMD_EXIT_PARK_MODE 0x0806 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_EXIT_PARK_MODE 0x0006 +#define HCI_CMD_EXIT_PARK_MODE 0x0806 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_exit_park_mode_cp; /* No return parameter(s) */ -#define HCI_OCF_QOS_SETUP 0x0007 -#define HCI_CMD_QOS_SETUP 0x0807 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t flags; /* reserved for future use */ - uint8_t service_type; /* service type */ - uint32_t token_rate; /* bytes per second */ - uint32_t peak_bandwidth; /* bytes per second */ - uint32_t latency; /* microseconds */ - uint32_t delay_variation; /* microseconds */ +#define HCI_OCF_QOS_SETUP 0x0007 +#define HCI_CMD_QOS_SETUP 0x0807 +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint8_t flags; /* reserved for future use */ + uint8_t service_type; /* service type */ + uint32_t token_rate; /* bytes per second */ + uint32_t peak_bandwidth; /* bytes per second */ + uint32_t latency; /* microseconds */ + uint32_t delay_variation; /* microseconds */ } hci_qos_setup_cp; /* No return parameter(s) */ -#define HCI_OCF_ROLE_DISCOVERY 0x0009 -#define HCI_CMD_ROLE_DISCOVERY 0x0809 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_ROLE_DISCOVERY 0x0009 +#define HCI_CMD_ROLE_DISCOVERY 0x0809 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_role_discovery_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t role; /* role for the connection handle */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t role; /* role for the connection handle */ } hci_role_discovery_rp; -#define HCI_OCF_SWITCH_ROLE 0x000b -#define HCI_CMD_SWITCH_ROLE 0x080B -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t role; /* new local role */ +#define HCI_OCF_SWITCH_ROLE 0x000b +#define HCI_CMD_SWITCH_ROLE 0x080B +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ + uint8_t role; /* new local role */ } hci_switch_role_cp; /* No return parameter(s) */ -#define HCI_OCF_READ_LINK_POLICY_SETTINGS 0x000c -#define HCI_CMD_READ_LINK_POLICY_SETTINGS 0x080C -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_READ_LINK_POLICY_SETTINGS 0x000c +#define HCI_CMD_READ_LINK_POLICY_SETTINGS 0x080C +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_read_link_policy_settings_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint16_t settings; /* link policy settings */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint16_t settings; /* link policy settings */ } hci_read_link_policy_settings_rp; -#define HCI_OCF_WRITE_LINK_POLICY_SETTINGS 0x000d -#define HCI_CMD_WRITE_LINK_POLICY_SETTINGS 0x080D -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t settings; /* link policy settings */ +#define HCI_OCF_WRITE_LINK_POLICY_SETTINGS 0x000d +#define HCI_CMD_WRITE_LINK_POLICY_SETTINGS 0x080D +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint16_t settings; /* link policy settings */ } hci_write_link_policy_settings_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ } hci_write_link_policy_settings_rp; -#define HCI_OCF_READ_DEFAULT_LINK_POLICY_SETTINGS 0x000e -#define HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS 0x080E +#define HCI_OCF_READ_DEFAULT_LINK_POLICY_SETTINGS 0x000e +#define HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS 0x080E /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t settings; /* link policy settings */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t settings; /* link policy settings */ } hci_read_default_link_policy_settings_rp; -#define HCI_OCF_WRITE_DEFAULT_LINK_POLICY_SETTINGS 0x000f -#define HCI_CMD_WRITE_DEFAULT_LINK_POLICY_SETTINGS 0x080F -typedef struct { - uint16_t settings; /* link policy settings */ +#define HCI_OCF_WRITE_DEFAULT_LINK_POLICY_SETTINGS 0x000f +#define HCI_CMD_WRITE_DEFAULT_LINK_POLICY_SETTINGS 0x080F +typedef struct +{ + uint16_t settings; /* link policy settings */ } hci_write_default_link_policy_settings_cp; -typedef hci_status_rp hci_write_default_link_policy_settings_rp; +typedef hci_status_rp hci_write_default_link_policy_settings_rp; -#define HCI_OCF_FLOW_SPECIFICATION 0x0010 -#define HCI_CMD_FLOW_SPECIFICATION 0x0810 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t flags; /* reserved */ - uint8_t flow_direction; - uint8_t service_type; - uint32_t token_rate; - uint32_t token_bucket; - uint32_t peak_bandwidth; - uint32_t latency; +#define HCI_OCF_FLOW_SPECIFICATION 0x0010 +#define HCI_CMD_FLOW_SPECIFICATION 0x0810 +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint8_t flags; /* reserved */ + uint8_t flow_direction; + uint8_t service_type; + uint32_t token_rate; + uint32_t token_bucket; + uint32_t peak_bandwidth; + uint32_t latency; } hci_flow_specification_cp; /* No return parameter(s) */ -#define HCI_OCF_SNIFF_SUBRATING 0x0011 -#define HCI_CMD_SNIFF_SUBRATING 0x0810 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t max_latency; - uint16_t max_timeout; /* max remote timeout */ - uint16_t min_timeout; /* min local timeout */ +#define HCI_OCF_SNIFF_SUBRATING 0x0011 +#define HCI_CMD_SNIFF_SUBRATING 0x0810 +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint16_t max_latency; + uint16_t max_timeout; /* max remote timeout */ + uint16_t min_timeout; /* min local timeout */ } hci_sniff_subrating_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ } hci_sniff_subrating_rp; /************************************************************************** @@ -1002,654 +1080,734 @@ typedef struct { ************************************************************************** **************************************************************************/ -#define HCI_OGF_HC_BASEBAND 0x03 +#define HCI_OGF_HC_BASEBAND 0x03 -#define HCI_OCF_SET_EVENT_MASK 0x0001 -#define HCI_CMD_SET_EVENT_MASK 0x0C01 -typedef struct { - uint8_t event_mask[HCI_EVENT_MASK_SIZE]; /* event_mask */ +#define HCI_OCF_SET_EVENT_MASK 0x0001 +#define HCI_CMD_SET_EVENT_MASK 0x0C01 +typedef struct +{ + uint8_t event_mask[HCI_EVENT_MASK_SIZE]; /* event_mask */ } hci_set_event_mask_cp; -typedef hci_status_rp hci_set_event_mask_rp; +typedef hci_status_rp hci_set_event_mask_rp; -#define HCI_OCF_RESET 0x0003 -#define HCI_CMD_RESET 0x0C03 +#define HCI_OCF_RESET 0x0003 +#define HCI_CMD_RESET 0x0C03 /* No command parameter(s) */ -typedef hci_status_rp hci_reset_rp; +typedef hci_status_rp hci_reset_rp; -#define HCI_OCF_SET_EVENT_FILTER 0x0005 -#define HCI_CMD_SET_EVENT_FILTER 0x0C05 -typedef struct { - uint8_t filter_type; /* filter type */ - uint8_t filter_condition_type; /* filter condition type */ -/* variable size condition - uint8_t condition[]; -- conditions */ +#define HCI_OCF_SET_EVENT_FILTER 0x0005 +#define HCI_CMD_SET_EVENT_FILTER 0x0C05 +typedef struct +{ + uint8_t filter_type; /* filter type */ + uint8_t filter_condition_type; /* filter condition type */ + /* variable size condition + uint8_t condition[]; -- conditions */ } hci_set_event_filter_cp; -typedef hci_status_rp hci_set_event_filter_rp; +typedef hci_status_rp hci_set_event_filter_rp; -#define HCI_OCF_FLUSH 0x0008 -#define HCI_CMD_FLUSH 0x0C08 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_FLUSH 0x0008 +#define HCI_CMD_FLUSH 0x0C08 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_flush_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ } hci_flush_rp; -#define HCI_OCF_READ_PIN_TYPE 0x0009 -#define HCI_CMD_READ_PIN_TYPE 0x0C09 +#define HCI_OCF_READ_PIN_TYPE 0x0009 +#define HCI_CMD_READ_PIN_TYPE 0x0C09 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t pin_type; /* PIN type */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t pin_type; /* PIN type */ } hci_read_pin_type_rp; -#define HCI_OCF_WRITE_PIN_TYPE 0x000a -#define HCI_CMD_WRITE_PIN_TYPE 0x0C0A -typedef struct { - uint8_t pin_type; /* PIN type */ +#define HCI_OCF_WRITE_PIN_TYPE 0x000a +#define HCI_CMD_WRITE_PIN_TYPE 0x0C0A +typedef struct +{ + uint8_t pin_type; /* PIN type */ } hci_write_pin_type_cp; -typedef hci_status_rp hci_write_pin_type_rp; +typedef hci_status_rp hci_write_pin_type_rp; -#define HCI_OCF_CREATE_NEW_UNIT_KEY 0x000b -#define HCI_CMD_CREATE_NEW_UNIT_KEY 0x0C0B +#define HCI_OCF_CREATE_NEW_UNIT_KEY 0x000b +#define HCI_CMD_CREATE_NEW_UNIT_KEY 0x0C0B /* No command parameter(s) */ -typedef hci_status_rp hci_create_new_unit_key_rp; +typedef hci_status_rp hci_create_new_unit_key_rp; -#define HCI_OCF_READ_STORED_LINK_KEY 0x000d -#define HCI_CMD_READ_STORED_LINK_KEY 0x0C0D -typedef struct { - bdaddr_t bdaddr; /* address */ - uint8_t read_all; /* read all keys? 0x01 - yes */ +#define HCI_OCF_READ_STORED_LINK_KEY 0x000d +#define HCI_CMD_READ_STORED_LINK_KEY 0x0C0D +typedef struct +{ + bdaddr_t bdaddr; /* address */ + uint8_t read_all; /* read all keys? 0x01 - yes */ } hci_read_stored_link_key_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t max_num_keys; /* Max. number of keys */ - uint16_t num_keys_read; /* Number of stored keys */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t max_num_keys; /* Max. number of keys */ + uint16_t num_keys_read; /* Number of stored keys */ } hci_read_stored_link_key_rp; -#define HCI_OCF_WRITE_STORED_LINK_KEY 0x0011 -#define HCI_CMD_WRITE_STORED_LINK_KEY 0x0C11 -typedef struct { - uint8_t num_keys_write; /* # of keys to write */ -/* these are repeated "num_keys_write" times - bdaddr_t bdaddr; --- remote address(es) - uint8_t key[HCI_KEY_SIZE]; --- key(s) */ +#define HCI_OCF_WRITE_STORED_LINK_KEY 0x0011 +#define HCI_CMD_WRITE_STORED_LINK_KEY 0x0C11 +typedef struct +{ + uint8_t num_keys_write; /* # of keys to write */ + /* these are repeated "num_keys_write" times + bdaddr_t bdaddr; --- remote address(es) + uint8_t key[HCI_KEY_SIZE]; --- key(s) */ } hci_write_stored_link_key_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t num_keys_written; /* # of keys successfully written */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t num_keys_written; /* # of keys successfully written */ } hci_write_stored_link_key_rp; -#define HCI_OCF_DELETE_STORED_LINK_KEY 0x0012 -#define HCI_CMD_DELETE_STORED_LINK_KEY 0x0C12 -typedef struct { - bdaddr_t bdaddr; /* address */ - uint8_t delete_all; /* delete all keys? 0x01 - yes */ +#define HCI_OCF_DELETE_STORED_LINK_KEY 0x0012 +#define HCI_CMD_DELETE_STORED_LINK_KEY 0x0C12 +typedef struct +{ + bdaddr_t bdaddr; /* address */ + uint8_t delete_all; /* delete all keys? 0x01 - yes */ } hci_delete_stored_link_key_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t num_keys_deleted; /* Number of keys deleted */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t num_keys_deleted; /* Number of keys deleted */ } hci_delete_stored_link_key_rp; -#define HCI_OCF_WRITE_LOCAL_NAME 0x0013 -#define HCI_CMD_WRITE_LOCAL_NAME 0x0C13 -typedef struct { - char name[HCI_UNIT_NAME_SIZE]; /* new unit name */ +#define HCI_OCF_WRITE_LOCAL_NAME 0x0013 +#define HCI_CMD_WRITE_LOCAL_NAME 0x0C13 +typedef struct +{ + char name[HCI_UNIT_NAME_SIZE]; /* new unit name */ } hci_write_local_name_cp; -typedef hci_status_rp hci_write_local_name_rp; +typedef hci_status_rp hci_write_local_name_rp; -#define HCI_OCF_READ_LOCAL_NAME 0x0014 -#define HCI_CMD_READ_LOCAL_NAME 0x0C14 +#define HCI_OCF_READ_LOCAL_NAME 0x0014 +#define HCI_CMD_READ_LOCAL_NAME 0x0C14 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - char name[HCI_UNIT_NAME_SIZE]; /* unit name */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + char name[HCI_UNIT_NAME_SIZE]; /* unit name */ } hci_read_local_name_rp; -#define HCI_OCF_READ_CON_ACCEPT_TIMEOUT 0x0015 -#define HCI_CMD_READ_CON_ACCEPT_TIMEOUT 0x0C15 +#define HCI_OCF_READ_CON_ACCEPT_TIMEOUT 0x0015 +#define HCI_CMD_READ_CON_ACCEPT_TIMEOUT 0x0C15 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t timeout; /* (timeout * 0.625) msec */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t timeout; /* (timeout * 0.625) msec */ } hci_read_con_accept_timeout_rp; -#define HCI_OCF_WRITE_CON_ACCEPT_TIMEOUT 0x0016 -#define HCI_CMD_WRITE_CON_ACCEPT_TIMEOUT 0x0C16 -typedef struct { - uint16_t timeout; /* (timeout * 0.625) msec */ +#define HCI_OCF_WRITE_CON_ACCEPT_TIMEOUT 0x0016 +#define HCI_CMD_WRITE_CON_ACCEPT_TIMEOUT 0x0C16 +typedef struct +{ + uint16_t timeout; /* (timeout * 0.625) msec */ } hci_write_con_accept_timeout_cp; -typedef hci_status_rp hci_write_con_accept_timeout_rp; +typedef hci_status_rp hci_write_con_accept_timeout_rp; -#define HCI_OCF_READ_PAGE_TIMEOUT 0x0017 -#define HCI_CMD_READ_PAGE_TIMEOUT 0x0C17 +#define HCI_OCF_READ_PAGE_TIMEOUT 0x0017 +#define HCI_CMD_READ_PAGE_TIMEOUT 0x0C17 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t timeout; /* (timeout * 0.625) msec */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t timeout; /* (timeout * 0.625) msec */ } hci_read_page_timeout_rp; -#define HCI_OCF_WRITE_PAGE_TIMEOUT 0x0018 -#define HCI_CMD_WRITE_PAGE_TIMEOUT 0x0C18 -typedef struct { - uint16_t timeout; /* (timeout * 0.625) msec */ +#define HCI_OCF_WRITE_PAGE_TIMEOUT 0x0018 +#define HCI_CMD_WRITE_PAGE_TIMEOUT 0x0C18 +typedef struct +{ + uint16_t timeout; /* (timeout * 0.625) msec */ } hci_write_page_timeout_cp; -typedef hci_status_rp hci_write_page_timeout_rp; +typedef hci_status_rp hci_write_page_timeout_rp; -#define HCI_OCF_READ_SCAN_ENABLE 0x0019 -#define HCI_CMD_READ_SCAN_ENABLE 0x0C19 +#define HCI_OCF_READ_SCAN_ENABLE 0x0019 +#define HCI_CMD_READ_SCAN_ENABLE 0x0C19 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t scan_enable; /* Scan enable */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t scan_enable; /* Scan enable */ } hci_read_scan_enable_rp; -#define HCI_OCF_WRITE_SCAN_ENABLE 0x001a -#define HCI_CMD_WRITE_SCAN_ENABLE 0x0C1A -typedef struct { - uint8_t scan_enable; /* Scan enable */ +#define HCI_OCF_WRITE_SCAN_ENABLE 0x001a +#define HCI_CMD_WRITE_SCAN_ENABLE 0x0C1A +typedef struct +{ + uint8_t scan_enable; /* Scan enable */ } hci_write_scan_enable_cp; -typedef hci_status_rp hci_write_scan_enable_rp; +typedef hci_status_rp hci_write_scan_enable_rp; -#define HCI_OCF_READ_PAGE_SCAN_ACTIVITY 0x001b -#define HCI_CMD_READ_PAGE_SCAN_ACTIVITY 0x0C1B +#define HCI_OCF_READ_PAGE_SCAN_ACTIVITY 0x001b +#define HCI_CMD_READ_PAGE_SCAN_ACTIVITY 0x0C1B /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t page_scan_interval; /* interval * 0.625 msec */ - uint16_t page_scan_window; /* window * 0.625 msec */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t page_scan_interval; /* interval * 0.625 msec */ + uint16_t page_scan_window; /* window * 0.625 msec */ } hci_read_page_scan_activity_rp; -#define HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY 0x001c -#define HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY 0x0C1C -typedef struct { - uint16_t page_scan_interval; /* interval * 0.625 msec */ - uint16_t page_scan_window; /* window * 0.625 msec */ +#define HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY 0x001c +#define HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY 0x0C1C +typedef struct +{ + uint16_t page_scan_interval; /* interval * 0.625 msec */ + uint16_t page_scan_window; /* window * 0.625 msec */ } hci_write_page_scan_activity_cp; -typedef hci_status_rp hci_write_page_scan_activity_rp; +typedef hci_status_rp hci_write_page_scan_activity_rp; -#define HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY 0x001d -#define HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY 0x0C1D +#define HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY 0x001d +#define HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY 0x0C1D /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t inquiry_scan_interval; /* interval * 0.625 msec */ - uint16_t inquiry_scan_window; /* window * 0.625 msec */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t inquiry_scan_interval; /* interval * 0.625 msec */ + uint16_t inquiry_scan_window; /* window * 0.625 msec */ } hci_read_inquiry_scan_activity_rp; -#define HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY 0x001e -#define HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY 0x0C1E -typedef struct { - uint16_t inquiry_scan_interval; /* interval * 0.625 msec */ - uint16_t inquiry_scan_window; /* window * 0.625 msec */ +#define HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY 0x001e +#define HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY 0x0C1E +typedef struct +{ + uint16_t inquiry_scan_interval; /* interval * 0.625 msec */ + uint16_t inquiry_scan_window; /* window * 0.625 msec */ } hci_write_inquiry_scan_activity_cp; -typedef hci_status_rp hci_write_inquiry_scan_activity_rp; +typedef hci_status_rp hci_write_inquiry_scan_activity_rp; -#define HCI_OCF_READ_AUTH_ENABLE 0x001f -#define HCI_CMD_READ_AUTH_ENABLE 0x0C1F +#define HCI_OCF_READ_AUTH_ENABLE 0x001f +#define HCI_CMD_READ_AUTH_ENABLE 0x0C1F /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t auth_enable; /* 0x01 - enabled */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t auth_enable; /* 0x01 - enabled */ } hci_read_auth_enable_rp; -#define HCI_OCF_WRITE_AUTH_ENABLE 0x0020 -#define HCI_CMD_WRITE_AUTH_ENABLE 0x0C20 -typedef struct { - uint8_t auth_enable; /* 0x01 - enabled */ +#define HCI_OCF_WRITE_AUTH_ENABLE 0x0020 +#define HCI_CMD_WRITE_AUTH_ENABLE 0x0C20 +typedef struct +{ + uint8_t auth_enable; /* 0x01 - enabled */ } hci_write_auth_enable_cp; -typedef hci_status_rp hci_write_auth_enable_rp; +typedef hci_status_rp hci_write_auth_enable_rp; /* Read Encryption Mode is deprecated */ -#define HCI_OCF_READ_ENCRYPTION_MODE 0x0021 -#define HCI_CMD_READ_ENCRYPTION_MODE 0x0C21 +#define HCI_OCF_READ_ENCRYPTION_MODE 0x0021 +#define HCI_CMD_READ_ENCRYPTION_MODE 0x0C21 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t encryption_mode; /* encryption mode */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t encryption_mode; /* encryption mode */ } hci_read_encryption_mode_rp; /* Write Encryption Mode is deprecated */ -#define HCI_OCF_WRITE_ENCRYPTION_MODE 0x0022 -#define HCI_CMD_WRITE_ENCRYPTION_MODE 0x0C22 -typedef struct { - uint8_t encryption_mode; /* encryption mode */ +#define HCI_OCF_WRITE_ENCRYPTION_MODE 0x0022 +#define HCI_CMD_WRITE_ENCRYPTION_MODE 0x0C22 +typedef struct +{ + uint8_t encryption_mode; /* encryption mode */ } hci_write_encryption_mode_cp; -typedef hci_status_rp hci_write_encryption_mode_rp; +typedef hci_status_rp hci_write_encryption_mode_rp; -#define HCI_OCF_READ_UNIT_CLASS 0x0023 -#define HCI_CMD_READ_UNIT_CLASS 0x0C23 +#define HCI_OCF_READ_UNIT_CLASS 0x0023 +#define HCI_CMD_READ_UNIT_CLASS 0x0C23 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ } hci_read_unit_class_rp; -#define HCI_OCF_WRITE_UNIT_CLASS 0x0024 -#define HCI_CMD_WRITE_UNIT_CLASS 0x0C24 -typedef struct { - uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ +#define HCI_OCF_WRITE_UNIT_CLASS 0x0024 +#define HCI_CMD_WRITE_UNIT_CLASS 0x0C24 +typedef struct +{ + uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ } hci_write_unit_class_cp; -typedef hci_status_rp hci_write_unit_class_rp; +typedef hci_status_rp hci_write_unit_class_rp; -#define HCI_OCF_READ_VOICE_SETTING 0x0025 -#define HCI_CMD_READ_VOICE_SETTING 0x0C25 +#define HCI_OCF_READ_VOICE_SETTING 0x0025 +#define HCI_CMD_READ_VOICE_SETTING 0x0C25 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t settings; /* voice settings */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t settings; /* voice settings */ } hci_read_voice_setting_rp; -#define HCI_OCF_WRITE_VOICE_SETTING 0x0026 -#define HCI_CMD_WRITE_VOICE_SETTING 0x0C26 -typedef struct { - uint16_t settings; /* voice settings */ +#define HCI_OCF_WRITE_VOICE_SETTING 0x0026 +#define HCI_CMD_WRITE_VOICE_SETTING 0x0C26 +typedef struct +{ + uint16_t settings; /* voice settings */ } hci_write_voice_setting_cp; -typedef hci_status_rp hci_write_voice_setting_rp; +typedef hci_status_rp hci_write_voice_setting_rp; -#define HCI_OCF_READ_AUTO_FLUSH_TIMEOUT 0x0027 -#define HCI_CMD_READ_AUTO_FLUSH_TIMEOUT 0x0C27 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_READ_AUTO_FLUSH_TIMEOUT 0x0027 +#define HCI_CMD_READ_AUTO_FLUSH_TIMEOUT 0x0C27 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_read_auto_flush_timeout_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint16_t timeout; /* 0x00 - no flush, timeout * 0.625 msec */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint16_t timeout; /* 0x00 - no flush, timeout * 0.625 msec */ } hci_read_auto_flush_timeout_rp; -#define HCI_OCF_WRITE_AUTO_FLUSH_TIMEOUT 0x0028 -#define HCI_CMD_WRITE_AUTO_FLUSH_TIMEOUT 0x0C28 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t timeout; /* 0x00 - no flush, timeout * 0.625 msec */ +#define HCI_OCF_WRITE_AUTO_FLUSH_TIMEOUT 0x0028 +#define HCI_CMD_WRITE_AUTO_FLUSH_TIMEOUT 0x0C28 +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint16_t timeout; /* 0x00 - no flush, timeout * 0.625 msec */ } hci_write_auto_flush_timeout_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ } hci_write_auto_flush_timeout_rp; -#define HCI_OCF_READ_NUM_BROADCAST_RETRANS 0x0029 -#define HCI_CMD_READ_NUM_BROADCAST_RETRANS 0x0C29 +#define HCI_OCF_READ_NUM_BROADCAST_RETRANS 0x0029 +#define HCI_CMD_READ_NUM_BROADCAST_RETRANS 0x0C29 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t counter; /* number of broadcast retransmissions */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t counter; /* number of broadcast retransmissions */ } hci_read_num_broadcast_retrans_rp; -#define HCI_OCF_WRITE_NUM_BROADCAST_RETRANS 0x002a -#define HCI_CMD_WRITE_NUM_BROADCAST_RETRANS 0x0C2A -typedef struct { - uint8_t counter; /* number of broadcast retransmissions */ +#define HCI_OCF_WRITE_NUM_BROADCAST_RETRANS 0x002a +#define HCI_CMD_WRITE_NUM_BROADCAST_RETRANS 0x0C2A +typedef struct +{ + uint8_t counter; /* number of broadcast retransmissions */ } hci_write_num_broadcast_retrans_cp; -typedef hci_status_rp hci_write_num_broadcast_retrans_rp; +typedef hci_status_rp hci_write_num_broadcast_retrans_rp; -#define HCI_OCF_READ_HOLD_MODE_ACTIVITY 0x002b -#define HCI_CMD_READ_HOLD_MODE_ACTIVITY 0x0C2B +#define HCI_OCF_READ_HOLD_MODE_ACTIVITY 0x002b +#define HCI_CMD_READ_HOLD_MODE_ACTIVITY 0x0C2B /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t hold_mode_activity; /* Hold mode activities */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t hold_mode_activity; /* Hold mode activities */ } hci_read_hold_mode_activity_rp; -#define HCI_OCF_WRITE_HOLD_MODE_ACTIVITY 0x002c -#define HCI_CMD_WRITE_HOLD_MODE_ACTIVITY 0x0C2C -typedef struct { - uint8_t hold_mode_activity; /* Hold mode activities */ +#define HCI_OCF_WRITE_HOLD_MODE_ACTIVITY 0x002c +#define HCI_CMD_WRITE_HOLD_MODE_ACTIVITY 0x0C2C +typedef struct +{ + uint8_t hold_mode_activity; /* Hold mode activities */ } hci_write_hold_mode_activity_cp; -typedef hci_status_rp hci_write_hold_mode_activity_rp; +typedef hci_status_rp hci_write_hold_mode_activity_rp; -#define HCI_OCF_READ_XMIT_LEVEL 0x002d -#define HCI_CMD_READ_XMIT_LEVEL 0x0C2D -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t type; /* Xmit level type */ +#define HCI_OCF_READ_XMIT_LEVEL 0x002d +#define HCI_CMD_READ_XMIT_LEVEL 0x0C2D +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint8_t type; /* Xmit level type */ } hci_read_xmit_level_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - char level; /* -30 <= level <= 30 dBm */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + char level; /* -30 <= level <= 30 dBm */ } hci_read_xmit_level_rp; -#define HCI_OCF_READ_SCO_FLOW_CONTROL 0x002e -#define HCI_CMD_READ_SCO_FLOW_CONTROL 0x0C2E +#define HCI_OCF_READ_SCO_FLOW_CONTROL 0x002e +#define HCI_CMD_READ_SCO_FLOW_CONTROL 0x0C2E /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t flow_control; /* 0x00 - disabled */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t flow_control; /* 0x00 - disabled */ } hci_read_sco_flow_control_rp; -#define HCI_OCF_WRITE_SCO_FLOW_CONTROL 0x002f -#define HCI_CMD_WRITE_SCO_FLOW_CONTROL 0x0C2F -typedef struct { - uint8_t flow_control; /* 0x00 - disabled */ +#define HCI_OCF_WRITE_SCO_FLOW_CONTROL 0x002f +#define HCI_CMD_WRITE_SCO_FLOW_CONTROL 0x0C2F +typedef struct +{ + uint8_t flow_control; /* 0x00 - disabled */ } hci_write_sco_flow_control_cp; -typedef hci_status_rp hci_write_sco_flow_control_rp; +typedef hci_status_rp hci_write_sco_flow_control_rp; -#define HCI_OCF_HC2H_FLOW_CONTROL 0x0031 -#define HCI_CMD_HC2H_FLOW_CONTROL 0x0C31 -typedef struct { - uint8_t hc2h_flow; /* Host Controller to Host flow control */ +#define HCI_OCF_HC2H_FLOW_CONTROL 0x0031 +#define HCI_CMD_HC2H_FLOW_CONTROL 0x0C31 +typedef struct +{ + uint8_t hc2h_flow; /* Host Controller to Host flow control */ } hci_hc2h_flow_control_cp; -typedef hci_status_rp hci_h2hc_flow_control_rp; +typedef hci_status_rp hci_h2hc_flow_control_rp; -#define HCI_OCF_HOST_BUFFER_SIZE 0x0033 -#define HCI_CMD_HOST_BUFFER_SIZE 0x0C33 -typedef struct { - uint16_t max_acl_size; /* Max. size of ACL packet (bytes) */ - uint8_t max_sco_size; /* Max. size of SCO packet (bytes) */ - uint16_t num_acl_pkts; /* Max. number of ACL packets */ - uint16_t num_sco_pkts; /* Max. number of SCO packets */ +#define HCI_OCF_HOST_BUFFER_SIZE 0x0033 +#define HCI_CMD_HOST_BUFFER_SIZE 0x0C33 +typedef struct +{ + uint16_t max_acl_size; /* Max. size of ACL packet (bytes) */ + uint8_t max_sco_size; /* Max. size of SCO packet (bytes) */ + uint16_t num_acl_pkts; /* Max. number of ACL packets */ + uint16_t num_sco_pkts; /* Max. number of SCO packets */ } hci_host_buffer_size_cp; -typedef hci_status_rp hci_host_buffer_size_rp; +typedef hci_status_rp hci_host_buffer_size_rp; -#define HCI_OCF_HOST_NUM_COMPL_PKTS 0x0035 -#define HCI_CMD_HOST_NUM_COMPL_PKTS 0x0C35 -typedef struct { - uint8_t nu_con_handles; /* # of connection handles */ -/* these are repeated "num_con_handles" times - uint16_t con_handle; --- connection handle(s) - uint16_t compl_pkts; --- # of completed packets */ +#define HCI_OCF_HOST_NUM_COMPL_PKTS 0x0035 +#define HCI_CMD_HOST_NUM_COMPL_PKTS 0x0C35 +typedef struct +{ + uint8_t nu_con_handles; /* # of connection handles */ + /* these are repeated "num_con_handles" times + uint16_t con_handle; --- connection handle(s) + uint16_t compl_pkts; --- # of completed packets */ } hci_host_num_compl_pkts_cp; /* No return parameter(s) */ -#define HCI_OCF_READ_LINK_SUPERVISION_TIMEOUT 0x0036 -#define HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT 0x0C36 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_READ_LINK_SUPERVISION_TIMEOUT 0x0036 +#define HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT 0x0C36 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_read_link_supervision_timeout_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint16_t timeout; /* Link supervision timeout * 0.625 msec */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint16_t timeout; /* Link supervision timeout * 0.625 msec */ } hci_read_link_supervision_timeout_rp; -#define HCI_OCF_WRITE_LINK_SUPERVISION_TIMEOUT 0x0037 -#define HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT 0x0C37 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t timeout; /* Link supervision timeout * 0.625 msec */ +#define HCI_OCF_WRITE_LINK_SUPERVISION_TIMEOUT 0x0037 +#define HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT 0x0C37 +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint16_t timeout; /* Link supervision timeout * 0.625 msec */ } hci_write_link_supervision_timeout_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ } hci_write_link_supervision_timeout_rp; -#define HCI_OCF_READ_NUM_SUPPORTED_IAC 0x0038 -#define HCI_CMD_READ_NUM_SUPPORTED_IAC 0x0C38 +#define HCI_OCF_READ_NUM_SUPPORTED_IAC 0x0038 +#define HCI_CMD_READ_NUM_SUPPORTED_IAC 0x0C38 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t num_iac; /* # of supported IAC during scan */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t num_iac; /* # of supported IAC during scan */ } hci_read_num_supported_iac_rp; -#define HCI_OCF_READ_IAC_LAP 0x0039 -#define HCI_CMD_READ_IAC_LAP 0x0C39 +#define HCI_OCF_READ_IAC_LAP 0x0039 +#define HCI_CMD_READ_IAC_LAP 0x0C39 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t num_iac; /* # of IAC */ -/* these are repeated "num_iac" times - uint8_t laps[HCI_LAP_SIZE]; --- LAPs */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t num_iac; /* # of IAC */ + /* these are repeated "num_iac" times + uint8_t laps[HCI_LAP_SIZE]; --- LAPs */ } hci_read_iac_lap_rp; -#define HCI_OCF_WRITE_IAC_LAP 0x003a -#define HCI_CMD_WRITE_IAC_LAP 0x0C3A -typedef struct { - uint8_t num_iac; /* # of IAC */ -/* these are repeated "num_iac" times - uint8_t laps[HCI_LAP_SIZE]; --- LAPs */ +#define HCI_OCF_WRITE_IAC_LAP 0x003a +#define HCI_CMD_WRITE_IAC_LAP 0x0C3A +typedef struct +{ + uint8_t num_iac; /* # of IAC */ + /* these are repeated "num_iac" times + uint8_t laps[HCI_LAP_SIZE]; --- LAPs */ } hci_write_iac_lap_cp; -typedef hci_status_rp hci_write_iac_lap_rp; +typedef hci_status_rp hci_write_iac_lap_rp; /* Read Page Scan Period Mode is deprecated */ -#define HCI_OCF_READ_PAGE_SCAN_PERIOD 0x003b -#define HCI_CMD_READ_PAGE_SCAN_PERIOD 0x0C3B +#define HCI_OCF_READ_PAGE_SCAN_PERIOD 0x003b +#define HCI_CMD_READ_PAGE_SCAN_PERIOD 0x0C3B /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t page_scan_period_mode; /* Page scan period mode */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t page_scan_period_mode; /* Page scan period mode */ } hci_read_page_scan_period_rp; /* Write Page Scan Period Mode is deprecated */ -#define HCI_OCF_WRITE_PAGE_SCAN_PERIOD 0x003c -#define HCI_CMD_WRITE_PAGE_SCAN_PERIOD 0x0C3C -typedef struct { - uint8_t page_scan_period_mode; /* Page scan period mode */ +#define HCI_OCF_WRITE_PAGE_SCAN_PERIOD 0x003c +#define HCI_CMD_WRITE_PAGE_SCAN_PERIOD 0x0C3C +typedef struct +{ + uint8_t page_scan_period_mode; /* Page scan period mode */ } hci_write_page_scan_period_cp; -typedef hci_status_rp hci_write_page_scan_period_rp; +typedef hci_status_rp hci_write_page_scan_period_rp; /* Read Page Scan Mode is deprecated */ -#define HCI_OCF_READ_PAGE_SCAN 0x003d -#define HCI_CMD_READ_PAGE_SCAN 0x0C3D +#define HCI_OCF_READ_PAGE_SCAN 0x003d +#define HCI_CMD_READ_PAGE_SCAN 0x0C3D /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t page_scan_mode; /* Page scan mode */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t page_scan_mode; /* Page scan mode */ } hci_read_page_scan_rp; /* Write Page Scan Mode is deprecated */ -#define HCI_OCF_WRITE_PAGE_SCAN 0x003e -#define HCI_CMD_WRITE_PAGE_SCAN 0x0C3E -typedef struct { - uint8_t page_scan_mode; /* Page scan mode */ +#define HCI_OCF_WRITE_PAGE_SCAN 0x003e +#define HCI_CMD_WRITE_PAGE_SCAN 0x0C3E +typedef struct +{ + uint8_t page_scan_mode; /* Page scan mode */ } hci_write_page_scan_cp; -typedef hci_status_rp hci_write_page_scan_rp; +typedef hci_status_rp hci_write_page_scan_rp; -#define HCI_OCF_SET_AFH_CLASSIFICATION 0x003f -#define HCI_CMD_SET_AFH_CLASSIFICATION 0x0C3F -typedef struct { - uint8_t classification[10]; +#define HCI_OCF_SET_AFH_CLASSIFICATION 0x003f +#define HCI_CMD_SET_AFH_CLASSIFICATION 0x0C3F +typedef struct +{ + uint8_t classification[10]; } hci_set_afh_classification_cp; -typedef hci_status_rp hci_set_afh_classification_rp; +typedef hci_status_rp hci_set_afh_classification_rp; -#define HCI_OCF_READ_INQUIRY_SCAN_TYPE 0x0042 -#define HCI_CMD_READ_INQUIRY_SCAN_TYPE 0x0C42 +#define HCI_OCF_READ_INQUIRY_SCAN_TYPE 0x0042 +#define HCI_CMD_READ_INQUIRY_SCAN_TYPE 0x0C42 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t type; /* inquiry scan type */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t type; /* inquiry scan type */ } hci_read_inquiry_scan_type_rp; -#define HCI_OCF_WRITE_INQUIRY_SCAN_TYPE 0x0043 -#define HCI_CMD_WRITE_INQUIRY_SCAN_TYPE 0x0C43 -typedef struct { - uint8_t type; /* inquiry scan type */ +#define HCI_OCF_WRITE_INQUIRY_SCAN_TYPE 0x0043 +#define HCI_CMD_WRITE_INQUIRY_SCAN_TYPE 0x0C43 +typedef struct +{ + uint8_t type; /* inquiry scan type */ } hci_write_inquiry_scan_type_cp; -typedef hci_status_rp hci_write_inquiry_scan_type_rp; +typedef hci_status_rp hci_write_inquiry_scan_type_rp; -#define HCI_OCF_READ_INQUIRY_MODE 0x0044 -#define HCI_CMD_READ_INQUIRY_MODE 0x0C44 +#define HCI_OCF_READ_INQUIRY_MODE 0x0044 +#define HCI_CMD_READ_INQUIRY_MODE 0x0C44 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t mode; /* inquiry mode */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t mode; /* inquiry mode */ } hci_read_inquiry_mode_rp; -#define HCI_OCF_WRITE_INQUIRY_MODE 0x0045 -#define HCI_CMD_WRITE_INQUIRY_MODE 0x0C45 -typedef struct { - uint8_t mode; /* inquiry mode */ +#define HCI_OCF_WRITE_INQUIRY_MODE 0x0045 +#define HCI_CMD_WRITE_INQUIRY_MODE 0x0C45 +typedef struct +{ + uint8_t mode; /* inquiry mode */ } hci_write_inquiry_mode_cp; -typedef hci_status_rp hci_write_inquiry_mode_rp; +typedef hci_status_rp hci_write_inquiry_mode_rp; -#define HCI_OCF_READ_PAGE_SCAN_TYPE 0x0046 -#define HCI_CMD_READ_PAGE_SCAN_TYPE 0x0C46 +#define HCI_OCF_READ_PAGE_SCAN_TYPE 0x0046 +#define HCI_CMD_READ_PAGE_SCAN_TYPE 0x0C46 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t type; /* page scan type */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t type; /* page scan type */ } hci_read_page_scan_type_rp; -#define HCI_OCF_WRITE_PAGE_SCAN_TYPE 0x0047 -#define HCI_CMD_WRITE_PAGE_SCAN_TYPE 0x0C47 -typedef struct { - uint8_t type; /* page scan type */ +#define HCI_OCF_WRITE_PAGE_SCAN_TYPE 0x0047 +#define HCI_CMD_WRITE_PAGE_SCAN_TYPE 0x0C47 +typedef struct +{ + uint8_t type; /* page scan type */ } hci_write_page_scan_type_cp; -typedef hci_status_rp hci_write_page_scan_type_rp; +typedef hci_status_rp hci_write_page_scan_type_rp; -#define HCI_OCF_READ_AFH_ASSESSMENT 0x0048 -#define HCI_CMD_READ_AFH_ASSESSMENT 0x0C48 +#define HCI_OCF_READ_AFH_ASSESSMENT 0x0048 +#define HCI_CMD_READ_AFH_ASSESSMENT 0x0C48 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t mode; /* assessment mode */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t mode; /* assessment mode */ } hci_read_afh_assessment_rp; -#define HCI_OCF_WRITE_AFH_ASSESSMENT 0x0049 -#define HCI_CMD_WRITE_AFH_ASSESSMENT 0x0C49 -typedef struct { - uint8_t mode; /* assessment mode */ +#define HCI_OCF_WRITE_AFH_ASSESSMENT 0x0049 +#define HCI_CMD_WRITE_AFH_ASSESSMENT 0x0C49 +typedef struct +{ + uint8_t mode; /* assessment mode */ } hci_write_afh_assessment_cp; -typedef hci_status_rp hci_write_afh_assessment_rp; +typedef hci_status_rp hci_write_afh_assessment_rp; -#define HCI_OCF_READ_EXTENDED_INQUIRY_RSP 0x0051 -#define HCI_CMD_READ_EXTENDED_INQUIRY_RSP 0x0C51 +#define HCI_OCF_READ_EXTENDED_INQUIRY_RSP 0x0051 +#define HCI_CMD_READ_EXTENDED_INQUIRY_RSP 0x0C51 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t fec_required; - uint8_t response[240]; +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t fec_required; + uint8_t response[240]; } hci_read_extended_inquiry_rsp_rp; -#define HCI_OCF_WRITE_EXTENDED_INQUIRY_RSP 0x0052 -#define HCI_CMD_WRITE_EXTENDED_INQUIRY_RSP 0x0C52 -typedef struct { - uint8_t fec_required; - uint8_t response[240]; +#define HCI_OCF_WRITE_EXTENDED_INQUIRY_RSP 0x0052 +#define HCI_CMD_WRITE_EXTENDED_INQUIRY_RSP 0x0C52 +typedef struct +{ + uint8_t fec_required; + uint8_t response[240]; } hci_write_extended_inquiry_rsp_cp; -typedef hci_status_rp hci_write_extended_inquiry_rsp_rp; +typedef hci_status_rp hci_write_extended_inquiry_rsp_rp; -#define HCI_OCF_REFRESH_ENCRYPTION_KEY 0x0053 -#define HCI_CMD_REFRESH_ENCRYPTION_KEY 0x0C53 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_REFRESH_ENCRYPTION_KEY 0x0053 +#define HCI_CMD_REFRESH_ENCRYPTION_KEY 0x0C53 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_refresh_encryption_key_cp; -typedef hci_status_rp hci_refresh_encryption_key_rp; +typedef hci_status_rp hci_refresh_encryption_key_rp; -#define HCI_OCF_READ_SIMPLE_PAIRING_MODE 0x0055 -#define HCI_CMD_READ_SIMPLE_PAIRING_MODE 0x0C55 +#define HCI_OCF_READ_SIMPLE_PAIRING_MODE 0x0055 +#define HCI_CMD_READ_SIMPLE_PAIRING_MODE 0x0C55 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t mode; /* simple pairing mode */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t mode; /* simple pairing mode */ } hci_read_simple_pairing_mode_rp; -#define HCI_OCF_WRITE_SIMPLE_PAIRING_MODE 0x0056 -#define HCI_CMD_WRITE_SIMPLE_PAIRING_MODE 0x0C56 -typedef struct { - uint8_t mode; /* simple pairing mode */ +#define HCI_OCF_WRITE_SIMPLE_PAIRING_MODE 0x0056 +#define HCI_CMD_WRITE_SIMPLE_PAIRING_MODE 0x0C56 +typedef struct +{ + uint8_t mode; /* simple pairing mode */ } hci_write_simple_pairing_mode_cp; -typedef hci_status_rp hci_write_simple_pairing_mode_rp; +typedef hci_status_rp hci_write_simple_pairing_mode_rp; -#define HCI_OCF_READ_LOCAL_OOB_DATA 0x0057 -#define HCI_CMD_READ_LOCAL_OOB_DATA 0x0C57 +#define HCI_OCF_READ_LOCAL_OOB_DATA 0x0057 +#define HCI_CMD_READ_LOCAL_OOB_DATA 0x0C57 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t c[16]; /* pairing hash */ - uint8_t r[16]; /* pairing randomizer */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t c[16]; /* pairing hash */ + uint8_t r[16]; /* pairing randomizer */ } hci_read_local_oob_data_rp; -#define HCI_OCF_READ_INQUIRY_RSP_XMIT_POWER 0x0058 -#define HCI_CMD_READ_INQUIRY_RSP_XMIT_POWER 0x0C58 +#define HCI_OCF_READ_INQUIRY_RSP_XMIT_POWER 0x0058 +#define HCI_CMD_READ_INQUIRY_RSP_XMIT_POWER 0x0C58 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - int8_t power; /* TX power */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + int8_t power; /* TX power */ } hci_read_inquiry_rsp_xmit_power_rp; -#define HCI_OCF_WRITE_INQUIRY_RSP_XMIT_POWER 0x0059 -#define HCI_CMD_WRITE_INQUIRY_RSP_XMIT_POWER 0x0C59 -typedef struct { - int8_t power; /* TX power */ +#define HCI_OCF_WRITE_INQUIRY_RSP_XMIT_POWER 0x0059 +#define HCI_CMD_WRITE_INQUIRY_RSP_XMIT_POWER 0x0C59 +typedef struct +{ + int8_t power; /* TX power */ } hci_write_inquiry_rsp_xmit_power_cp; -typedef hci_status_rp hci_write_inquiry_rsp_xmit_power_rp; +typedef hci_status_rp hci_write_inquiry_rsp_xmit_power_rp; -#define HCI_OCF_READ_DEFAULT_ERRDATA_REPORTING 0x005A -#define HCI_CMD_READ_DEFAULT_ERRDATA_REPORTING 0x0C5A +#define HCI_OCF_READ_DEFAULT_ERRDATA_REPORTING 0x005A +#define HCI_CMD_READ_DEFAULT_ERRDATA_REPORTING 0x0C5A /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t reporting; /* erroneous data reporting */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t reporting; /* erroneous data reporting */ } hci_read_default_errdata_reporting_rp; -#define HCI_OCF_WRITE_DEFAULT_ERRDATA_REPORTING 0x005B -#define HCI_CMD_WRITE_DEFAULT_ERRDATA_REPORTING 0x0C5B -typedef struct { - uint8_t reporting; /* erroneous data reporting */ +#define HCI_OCF_WRITE_DEFAULT_ERRDATA_REPORTING 0x005B +#define HCI_CMD_WRITE_DEFAULT_ERRDATA_REPORTING 0x0C5B +typedef struct +{ + uint8_t reporting; /* erroneous data reporting */ } hci_write_default_errdata_reporting_cp; -typedef hci_status_rp hci_write_default_errdata_reporting_rp; +typedef hci_status_rp hci_write_default_errdata_reporting_rp; -#define HCI_OCF_ENHANCED_FLUSH 0x005F -#define HCI_CMD_ENHANCED_FLUSH 0x0C5F -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t packet_type; +#define HCI_OCF_ENHANCED_FLUSH 0x005F +#define HCI_CMD_ENHANCED_FLUSH 0x0C5F +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint8_t packet_type; } hci_enhanced_flush_cp; /* No response parameter(s) */ -#define HCI_OCF_SEND_KEYPRESS_NOTIFICATION 0x0060 -#define HCI_CMD_SEND_KEYPRESS_NOTIFICATION 0x0C60 -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t type; /* notification type */ +#define HCI_OCF_SEND_KEYPRESS_NOTIFICATION 0x0060 +#define HCI_CMD_SEND_KEYPRESS_NOTIFICATION 0x0C60 +typedef struct +{ + bdaddr_t bdaddr; /* remote address */ + uint8_t type; /* notification type */ } hci_send_keypress_notification_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote address */ } hci_send_keypress_notification_rp; /************************************************************************** @@ -1658,75 +1816,83 @@ typedef struct { ************************************************************************** **************************************************************************/ -#define HCI_OGF_INFO 0x04 +#define HCI_OGF_INFO 0x04 -#define HCI_OCF_READ_LOCAL_VER 0x0001 -#define HCI_CMD_READ_LOCAL_VER 0x1001 +#define HCI_OCF_READ_LOCAL_VER 0x0001 +#define HCI_CMD_READ_LOCAL_VER 0x1001 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t hci_version; /* HCI version */ - uint16_t hci_revision; /* HCI revision */ - uint8_t lmp_version; /* LMP version */ - uint16_t manufacturer; /* Hardware manufacturer name */ - uint16_t lmp_subversion; /* LMP sub-version */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t hci_version; /* HCI version */ + uint16_t hci_revision; /* HCI revision */ + uint8_t lmp_version; /* LMP version */ + uint16_t manufacturer; /* Hardware manufacturer name */ + uint16_t lmp_subversion; /* LMP sub-version */ } hci_read_local_ver_rp; -#define HCI_OCF_READ_LOCAL_COMMANDS 0x0002 -#define HCI_CMD_READ_LOCAL_COMMANDS 0x1002 +#define HCI_OCF_READ_LOCAL_COMMANDS 0x0002 +#define HCI_CMD_READ_LOCAL_COMMANDS 0x1002 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t commands[HCI_COMMANDS_SIZE]; /* opcode bitmask */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t commands[HCI_COMMANDS_SIZE]; /* opcode bitmask */ } hci_read_local_commands_rp; -#define HCI_OCF_READ_LOCAL_FEATURES 0x0003 -#define HCI_CMD_READ_LOCAL_FEATURES 0x1003 +#define HCI_OCF_READ_LOCAL_FEATURES 0x0003 +#define HCI_CMD_READ_LOCAL_FEATURES 0x1003 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ } hci_read_local_features_rp; -#define HCI_OCF_READ_LOCAL_EXTENDED_FEATURES 0x0004 -#define HCI_CMD_READ_LOCAL_EXTENDED_FEATURES 0x1004 -typedef struct { - uint8_t page; /* page number */ +#define HCI_OCF_READ_LOCAL_EXTENDED_FEATURES 0x0004 +#define HCI_CMD_READ_LOCAL_EXTENDED_FEATURES 0x1004 +typedef struct +{ + uint8_t page; /* page number */ } hci_read_local_extended_features_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t page; /* page number */ - uint8_t max_page; /* maximum page number */ - uint8_t features[HCI_FEATURES_SIZE]; /* LMP features */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t page; /* page number */ + uint8_t max_page; /* maximum page number */ + uint8_t features[HCI_FEATURES_SIZE]; /* LMP features */ } hci_read_local_extended_features_rp; -#define HCI_OCF_READ_BUFFER_SIZE 0x0005 -#define HCI_CMD_READ_BUFFER_SIZE 0x1005 +#define HCI_OCF_READ_BUFFER_SIZE 0x0005 +#define HCI_CMD_READ_BUFFER_SIZE 0x1005 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t max_acl_size; /* Max. size of ACL packet (bytes) */ - uint8_t max_sco_size; /* Max. size of SCO packet (bytes) */ - uint16_t num_acl_pkts; /* Max. number of ACL packets */ - uint16_t num_sco_pkts; /* Max. number of SCO packets */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t max_acl_size; /* Max. size of ACL packet (bytes) */ + uint8_t max_sco_size; /* Max. size of SCO packet (bytes) */ + uint16_t num_acl_pkts; /* Max. number of ACL packets */ + uint16_t num_sco_pkts; /* Max. number of SCO packets */ } hci_read_buffer_size_rp; /* Read Country Code is deprecated */ -#define HCI_OCF_READ_COUNTRY_CODE 0x0007 -#define HCI_CMD_READ_COUNTRY_CODE 0x1007 +#define HCI_OCF_READ_COUNTRY_CODE 0x0007 +#define HCI_CMD_READ_COUNTRY_CODE 0x1007 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t country_code; /* 0x00 - NAM, EUR, JP; 0x01 - France */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t country_code; /* 0x00 - NAM, EUR, JP; 0x01 - France */ } hci_read_country_code_rp; -#define HCI_OCF_READ_BDADDR 0x0009 -#define HCI_CMD_READ_BDADDR 0x1009 +#define HCI_OCF_READ_BDADDR 0x0009 +#define HCI_CMD_READ_BDADDR 0x1009 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* unit address */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* unit address */ } hci_read_bdaddr_rp; /************************************************************************** @@ -1735,119 +1901,133 @@ typedef struct { ************************************************************************** **************************************************************************/ -#define HCI_OGF_STATUS 0x05 +#define HCI_OGF_STATUS 0x05 -#define HCI_OCF_READ_FAILED_CONTACT_CNTR 0x0001 -#define HCI_CMD_READ_FAILED_CONTACT_CNTR 0x1401 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_READ_FAILED_CONTACT_CNTR 0x0001 +#define HCI_CMD_READ_FAILED_CONTACT_CNTR 0x1401 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_read_failed_contact_cntr_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint16_t counter; /* number of consecutive failed contacts */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint16_t counter; /* number of consecutive failed contacts */ } hci_read_failed_contact_cntr_rp; -#define HCI_OCF_RESET_FAILED_CONTACT_CNTR 0x0002 -#define HCI_CMD_RESET_FAILED_CONTACT_CNTR 0x1402 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_RESET_FAILED_CONTACT_CNTR 0x0002 +#define HCI_CMD_RESET_FAILED_CONTACT_CNTR 0x1402 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_reset_failed_contact_cntr_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ } hci_reset_failed_contact_cntr_rp; -#define HCI_OCF_READ_LINK_QUALITY 0x0003 -#define HCI_CMD_READ_LINK_QUALITY 0x1403 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_READ_LINK_QUALITY 0x0003 +#define HCI_CMD_READ_LINK_QUALITY 0x1403 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_read_link_quality_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t quality; /* higher value means better quality */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t quality; /* higher value means better quality */ } hci_read_link_quality_rp; -#define HCI_OCF_READ_RSSI 0x0005 -#define HCI_CMD_READ_RSSI 0x1405 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_READ_RSSI 0x0005 +#define HCI_CMD_READ_RSSI 0x1405 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_read_rssi_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - char rssi; /* -127 <= rssi <= 127 dB */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + char rssi; /* -127 <= rssi <= 127 dB */ } hci_read_rssi_rp; -#define HCI_OCF_READ_AFH_CHANNEL_MAP 0x0006 -#define HCI_CMD_READ_AFH_CHANNEL_MAP 0x1406 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_OCF_READ_AFH_CHANNEL_MAP 0x0006 +#define HCI_CMD_READ_AFH_CHANNEL_MAP 0x1406 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_read_afh_channel_map_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t mode; /* AFH mode */ - uint8_t map[10]; /* AFH Channel Map */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t mode; /* AFH mode */ + uint8_t map[10]; /* AFH Channel Map */ } hci_read_afh_channel_map_rp; -#define HCI_OCF_READ_CLOCK 0x0007 -#define HCI_CMD_READ_CLOCK 0x1407 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t clock; /* which clock */ +#define HCI_OCF_READ_CLOCK 0x0007 +#define HCI_CMD_READ_CLOCK 0x1407 +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint8_t clock; /* which clock */ } hci_read_clock_cp; -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint32_t clock; /* clock value */ - uint16_t accuracy; /* clock accuracy */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint32_t clock; /* clock value */ + uint16_t accuracy; /* clock accuracy */ } hci_read_clock_rp; - /************************************************************************** ************************************************************************** ** OGF 0x06 Testing commands and return parameters ************************************************************************** **************************************************************************/ -#define HCI_OGF_TESTING 0x06 +#define HCI_OGF_TESTING 0x06 -#define HCI_OCF_READ_LOOPBACK_MODE 0x0001 -#define HCI_CMD_READ_LOOPBACK_MODE 0x1801 +#define HCI_OCF_READ_LOOPBACK_MODE 0x0001 +#define HCI_CMD_READ_LOOPBACK_MODE 0x1801 /* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t lbmode; /* loopback mode */ +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint8_t lbmode; /* loopback mode */ } hci_read_loopback_mode_rp; -#define HCI_OCF_WRITE_LOOPBACK_MODE 0x0002 -#define HCI_CMD_WRITE_LOOPBACK_MODE 0x1802 -typedef struct { - uint8_t lbmode; /* loopback mode */ +#define HCI_OCF_WRITE_LOOPBACK_MODE 0x0002 +#define HCI_CMD_WRITE_LOOPBACK_MODE 0x1802 +typedef struct +{ + uint8_t lbmode; /* loopback mode */ } hci_write_loopback_mode_cp; -typedef hci_status_rp hci_write_loopback_mode_rp; +typedef hci_status_rp hci_write_loopback_mode_rp; -#define HCI_OCF_ENABLE_UNIT_UNDER_TEST 0x0003 -#define HCI_CMD_ENABLE_UNIT_UNDER_TEST 0x1803 +#define HCI_OCF_ENABLE_UNIT_UNDER_TEST 0x0003 +#define HCI_CMD_ENABLE_UNIT_UNDER_TEST 0x1803 /* No command parameter(s) */ -typedef hci_status_rp hci_enable_unit_under_test_rp; +typedef hci_status_rp hci_enable_unit_under_test_rp; -#define HCI_OCF_WRITE_SIMPLE_PAIRING_DEBUG_MODE 0x0004 -#define HCI_CMD_WRITE_SIMPLE_PAIRING_DEBUG_MODE 0x1804 -typedef struct { - uint8_t mode; /* simple pairing debug mode */ +#define HCI_OCF_WRITE_SIMPLE_PAIRING_DEBUG_MODE 0x0004 +#define HCI_CMD_WRITE_SIMPLE_PAIRING_DEBUG_MODE 0x1804 +typedef struct +{ + uint8_t mode; /* simple pairing debug mode */ } hci_write_simple_pairing_debug_mode_cp; -typedef hci_status_rp hci_write_simple_pairing_debug_mode_rp; +typedef hci_status_rp hci_write_simple_pairing_debug_mode_rp; /************************************************************************** ************************************************************************** @@ -1856,17 +2036,16 @@ typedef hci_status_rp hci_write_simple_pairing_debug_mode_rp; ************************************************************************** **************************************************************************/ -#define HCI_OGF_BT_LOGO 0x3e -#define HCI_OGF_VENDOR 0x3f +#define HCI_OGF_BT_LOGO 0x3e +#define HCI_OGF_VENDOR 0x3f /* Ericsson specific FC */ -#define HCI_CMD_ERICSSON_WRITE_PCM_SETTINGS 0xFC07 -#define HCI_CMD_ERICSSON_SET_UART_BAUD_RATE 0xFC09 -#define HCI_CMD_ERICSSON_SET_SCO_DATA_PATH 0xFC1D +#define HCI_CMD_ERICSSON_WRITE_PCM_SETTINGS 0xFC07 +#define HCI_CMD_ERICSSON_SET_UART_BAUD_RATE 0xFC09 +#define HCI_CMD_ERICSSON_SET_SCO_DATA_PATH 0xFC1D /* Cambridge Silicon Radio specific FC */ -#define HCI_CMD_CSR_EXTN 0xFC00 - +#define HCI_CMD_CSR_EXTN 0xFC00 /************************************************************************** ************************************************************************** @@ -1874,388 +2053,441 @@ typedef hci_status_rp hci_write_simple_pairing_debug_mode_rp; ************************************************************************** **************************************************************************/ -#define HCI_EVENT_INQUIRY_COMPL 0x01 -typedef struct { - uint8_t status; /* 0x00 - success */ +#define HCI_EVENT_INQUIRY_COMPL 0x01 +typedef struct +{ + uint8_t status; /* 0x00 - success */ } hci_inquiry_compl_ep; -#define HCI_EVENT_INQUIRY_RESULT 0x02 -typedef struct { - uint8_t num_responses; /* number of responses */ -/* hci_inquiry_response[num_responses] -- see below */ +#define HCI_EVENT_INQUIRY_RESULT 0x02 +typedef struct +{ + uint8_t num_responses; /* number of responses */ + /* hci_inquiry_response[num_responses] -- see below */ } hci_inquiry_result_ep; -typedef struct { - bdaddr_t bdaddr; /* unit address */ - uint8_t page_scan_rep_mode; /* page scan rep. mode */ - uint8_t page_scan_period_mode; /* page scan period mode */ - uint8_t page_scan_mode; /* page scan mode */ - uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ - uint16_t clock_offset; /* clock offset */ +typedef struct +{ + bdaddr_t bdaddr; /* unit address */ + uint8_t page_scan_rep_mode; /* page scan rep. mode */ + uint8_t page_scan_period_mode; /* page scan period mode */ + uint8_t page_scan_mode; /* page scan mode */ + uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ + uint16_t clock_offset; /* clock offset */ } hci_inquiry_response; -#define HCI_EVENT_CON_COMPL 0x03 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ - bdaddr_t bdaddr; /* remote unit address */ - uint8_t link_type; /* Link type */ - uint8_t encryption_mode; /* Encryption mode */ +#define HCI_EVENT_CON_COMPL 0x03 +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* Connection handle */ + bdaddr_t bdaddr; /* remote unit address */ + uint8_t link_type; /* Link type */ + uint8_t encryption_mode; /* Encryption mode */ } hci_con_compl_ep; -#define HCI_EVENT_CON_REQ 0x04 -typedef struct { - bdaddr_t bdaddr; /* remote unit address */ - uint8_t uclass[HCI_CLASS_SIZE]; /* remote unit class */ - uint8_t link_type; /* link type */ +#define HCI_EVENT_CON_REQ 0x04 +typedef struct +{ + bdaddr_t bdaddr; /* remote unit address */ + uint8_t uclass[HCI_CLASS_SIZE]; /* remote unit class */ + uint8_t link_type; /* link type */ } hci_con_req_ep; -#define HCI_EVENT_DISCON_COMPL 0x05 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t reason; /* reason to disconnect */ +#define HCI_EVENT_DISCON_COMPL 0x05 +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t reason; /* reason to disconnect */ } hci_discon_compl_ep; -#define HCI_EVENT_AUTH_COMPL 0x06 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ +#define HCI_EVENT_AUTH_COMPL 0x06 +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ } hci_auth_compl_ep; -#define HCI_EVENT_REMOTE_NAME_REQ_COMPL 0x07 -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote unit address */ - char name[HCI_UNIT_NAME_SIZE]; /* remote unit name */ +#define HCI_EVENT_REMOTE_NAME_REQ_COMPL 0x07 +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote unit address */ + char name[HCI_UNIT_NAME_SIZE]; /* remote unit name */ } hci_remote_name_req_compl_ep; -#define HCI_EVENT_ENCRYPTION_CHANGE 0x08 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ - uint8_t encryption_enable; /* 0x00 - disable */ +#define HCI_EVENT_ENCRYPTION_CHANGE 0x08 +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* Connection handle */ + uint8_t encryption_enable; /* 0x00 - disable */ } hci_encryption_change_ep; -#define HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL 0x09 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ +#define HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL 0x09 +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* Connection handle */ } hci_change_con_link_key_compl_ep; -#define HCI_EVENT_MASTER_LINK_KEY_COMPL 0x0a -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ - uint8_t key_flag; /* Key flag */ +#define HCI_EVENT_MASTER_LINK_KEY_COMPL 0x0a +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* Connection handle */ + uint8_t key_flag; /* Key flag */ } hci_master_link_key_compl_ep; -#define HCI_EVENT_READ_REMOTE_FEATURES_COMPL 0x0b -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ - uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ +#define HCI_EVENT_READ_REMOTE_FEATURES_COMPL 0x0b +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* Connection handle */ + uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ } hci_read_remote_features_compl_ep; -#define HCI_EVENT_READ_REMOTE_VER_INFO_COMPL 0x0c -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ - uint8_t lmp_version; /* LMP version */ - uint16_t manufacturer; /* Hardware manufacturer name */ - uint16_t lmp_subversion; /* LMP sub-version */ +#define HCI_EVENT_READ_REMOTE_VER_INFO_COMPL 0x0c +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* Connection handle */ + uint8_t lmp_version; /* LMP version */ + uint16_t manufacturer; /* Hardware manufacturer name */ + uint16_t lmp_subversion; /* LMP sub-version */ } hci_read_remote_ver_info_compl_ep; -#define HCI_EVENT_QOS_SETUP_COMPL 0x0d -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t flags; /* reserved for future use */ - uint8_t service_type; /* service type */ - uint32_t token_rate; /* bytes per second */ - uint32_t peak_bandwidth; /* bytes per second */ - uint32_t latency; /* microseconds */ - uint32_t delay_variation; /* microseconds */ +#define HCI_EVENT_QOS_SETUP_COMPL 0x0d +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t flags; /* reserved for future use */ + uint8_t service_type; /* service type */ + uint32_t token_rate; /* bytes per second */ + uint32_t peak_bandwidth; /* bytes per second */ + uint32_t latency; /* microseconds */ + uint32_t delay_variation; /* microseconds */ } hci_qos_setup_compl_ep; -#define HCI_EVENT_COMMAND_COMPL 0x0e -typedef struct { - uint8_t num_cmd_pkts; /* # of HCI command packets */ - uint16_t opcode; /* command OpCode */ - /* command return parameters (if any) */ +#define HCI_EVENT_COMMAND_COMPL 0x0e +typedef struct +{ + uint8_t num_cmd_pkts; /* # of HCI command packets */ + uint16_t opcode; /* command OpCode */ + /* command return parameters (if any) */ } hci_command_compl_ep; -#define HCI_EVENT_COMMAND_STATUS 0x0f -typedef struct { - uint8_t status; /* 0x00 - pending */ - uint8_t num_cmd_pkts; /* # of HCI command packets */ - uint16_t opcode; /* command OpCode */ +#define HCI_EVENT_COMMAND_STATUS 0x0f +typedef struct +{ + uint8_t status; /* 0x00 - pending */ + uint8_t num_cmd_pkts; /* # of HCI command packets */ + uint16_t opcode; /* command OpCode */ } hci_command_status_ep; -#define HCI_EVENT_HARDWARE_ERROR 0x10 -typedef struct { - uint8_t hardware_code; /* hardware error code */ +#define HCI_EVENT_HARDWARE_ERROR 0x10 +typedef struct +{ + uint8_t hardware_code; /* hardware error code */ } hci_hardware_error_ep; -#define HCI_EVENT_FLUSH_OCCUR 0x11 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_EVENT_FLUSH_OCCUR 0x11 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_flush_occur_ep; -#define HCI_EVENT_ROLE_CHANGE 0x12 -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* address of remote unit */ - uint8_t role; /* new connection role */ +#define HCI_EVENT_ROLE_CHANGE 0x12 +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* address of remote unit */ + uint8_t role; /* new connection role */ } hci_role_change_ep; -#define HCI_EVENT_NUM_COMPL_PKTS 0x13 -typedef struct { - uint8_t num_con_handles; /* # of connection handles */ -/* these are repeated "num_con_handles" times - uint16_t con_handle; --- connection handle(s) - uint16_t compl_pkts; --- # of completed packets */ +#define HCI_EVENT_NUM_COMPL_PKTS 0x13 +typedef struct +{ + uint8_t num_con_handles; /* # of connection handles */ + /* these are repeated "num_con_handles" times + uint16_t con_handle; --- connection handle(s) + uint16_t compl_pkts; --- # of completed packets */ } hci_num_compl_pkts_ep; -typedef struct { - uint16_t con_handle; - uint16_t compl_pkts; +typedef struct +{ + uint16_t con_handle; + uint16_t compl_pkts; } hci_num_compl_pkts_info; -#define HCI_EVENT_MODE_CHANGE 0x14 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t unit_mode; /* remote unit mode */ - uint16_t interval; /* interval * 0.625 msec */ +#define HCI_EVENT_MODE_CHANGE 0x14 +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t unit_mode; /* remote unit mode */ + uint16_t interval; /* interval * 0.625 msec */ } hci_mode_change_ep; -#define HCI_EVENT_RETURN_LINK_KEYS 0x15 -typedef struct { - uint8_t num_keys; /* # of keys */ -/* these are repeated "num_keys" times - bdaddr_t bdaddr; --- remote address(es) - uint8_t key[HCI_KEY_SIZE]; --- key(s) */ +#define HCI_EVENT_RETURN_LINK_KEYS 0x15 +typedef struct +{ + uint8_t num_keys; /* # of keys */ + /* these are repeated "num_keys" times + bdaddr_t bdaddr; --- remote address(es) + uint8_t key[HCI_KEY_SIZE]; --- key(s) */ } hci_return_link_keys_ep; -#define HCI_EVENT_PIN_CODE_REQ 0x16 -typedef struct { - bdaddr_t bdaddr; /* remote unit address */ +#define HCI_EVENT_PIN_CODE_REQ 0x16 +typedef struct +{ + bdaddr_t bdaddr; /* remote unit address */ } hci_pin_code_req_ep; -#define HCI_EVENT_LINK_KEY_REQ 0x17 -typedef struct { - bdaddr_t bdaddr; /* remote unit address */ +#define HCI_EVENT_LINK_KEY_REQ 0x17 +typedef struct +{ + bdaddr_t bdaddr; /* remote unit address */ } hci_link_key_req_ep; -#define HCI_EVENT_LINK_KEY_NOTIFICATION 0x18 -typedef struct { - bdaddr_t bdaddr; /* remote unit address */ - uint8_t key[HCI_KEY_SIZE]; /* link key */ - uint8_t key_type; /* type of the key */ +#define HCI_EVENT_LINK_KEY_NOTIFICATION 0x18 +typedef struct +{ + bdaddr_t bdaddr; /* remote unit address */ + uint8_t key[HCI_KEY_SIZE]; /* link key */ + uint8_t key_type; /* type of the key */ } hci_link_key_notification_ep; -#define HCI_EVENT_LOOPBACK_COMMAND 0x19 -typedef hci_cmd_hdr_t hci_loopback_command_ep; +#define HCI_EVENT_LOOPBACK_COMMAND 0x19 +typedef hci_cmd_hdr_t hci_loopback_command_ep; -#define HCI_EVENT_DATA_BUFFER_OVERFLOW 0x1a -typedef struct { - uint8_t link_type; /* Link type */ +#define HCI_EVENT_DATA_BUFFER_OVERFLOW 0x1a +typedef struct +{ + uint8_t link_type; /* Link type */ } hci_data_buffer_overflow_ep; -#define HCI_EVENT_MAX_SLOT_CHANGE 0x1b -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t lmp_max_slots; /* Max. # of slots allowed */ +#define HCI_EVENT_MAX_SLOT_CHANGE 0x1b +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint8_t lmp_max_slots; /* Max. # of slots allowed */ } hci_max_slot_change_ep; -#define HCI_EVENT_READ_CLOCK_OFFSET_COMPL 0x1c -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ - uint16_t clock_offset; /* Clock offset */ +#define HCI_EVENT_READ_CLOCK_OFFSET_COMPL 0x1c +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* Connection handle */ + uint16_t clock_offset; /* Clock offset */ } hci_read_clock_offset_compl_ep; -#define HCI_EVENT_CON_PKT_TYPE_CHANGED 0x1d -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint16_t pkt_type; /* packet type */ +#define HCI_EVENT_CON_PKT_TYPE_CHANGED 0x1d +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint16_t pkt_type; /* packet type */ } hci_con_pkt_type_changed_ep; -#define HCI_EVENT_QOS_VIOLATION 0x1e -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_EVENT_QOS_VIOLATION 0x1e +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_qos_violation_ep; /* Page Scan Mode Change Event is deprecated */ -#define HCI_EVENT_PAGE_SCAN_MODE_CHANGE 0x1f -typedef struct { - bdaddr_t bdaddr; /* destination address */ - uint8_t page_scan_mode; /* page scan mode */ +#define HCI_EVENT_PAGE_SCAN_MODE_CHANGE 0x1f +typedef struct +{ + bdaddr_t bdaddr; /* destination address */ + uint8_t page_scan_mode; /* page scan mode */ } hci_page_scan_mode_change_ep; -#define HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE 0x20 -typedef struct { - bdaddr_t bdaddr; /* destination address */ - uint8_t page_scan_rep_mode; /* page scan repetition mode */ +#define HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE 0x20 +typedef struct +{ + bdaddr_t bdaddr; /* destination address */ + uint8_t page_scan_rep_mode; /* page scan repetition mode */ } hci_page_scan_rep_mode_change_ep; -#define HCI_EVENT_FLOW_SPECIFICATION_COMPL 0x21 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t flags; /* reserved */ - uint8_t direction; /* flow direction */ - uint8_t type; /* service type */ - uint32_t token_rate; /* token rate */ - uint32_t bucket_size; /* token bucket size */ - uint32_t peak_bandwidth; /* peak bandwidth */ - uint32_t latency; /* access latency */ +#define HCI_EVENT_FLOW_SPECIFICATION_COMPL 0x21 +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t flags; /* reserved */ + uint8_t direction; /* flow direction */ + uint8_t type; /* service type */ + uint32_t token_rate; /* token rate */ + uint32_t bucket_size; /* token bucket size */ + uint32_t peak_bandwidth; /* peak bandwidth */ + uint32_t latency; /* access latency */ } hci_flow_specification_compl_ep; -#define HCI_EVENT_RSSI_RESULT 0x22 -typedef struct { - uint8_t num_responses; /* number of responses */ -/* hci_rssi_response[num_responses] -- see below */ +#define HCI_EVENT_RSSI_RESULT 0x22 +typedef struct +{ + uint8_t num_responses; /* number of responses */ + /* hci_rssi_response[num_responses] -- see below */ } hci_rssi_result_ep; -typedef struct { - bdaddr_t bdaddr; /* unit address */ - uint8_t page_scan_rep_mode; /* page scan rep. mode */ - uint8_t blank; /* reserved */ - uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ - uint16_t clock_offset; /* clock offset */ - int8_t rssi; /* rssi */ +typedef struct +{ + bdaddr_t bdaddr; /* unit address */ + uint8_t page_scan_rep_mode; /* page scan rep. mode */ + uint8_t blank; /* reserved */ + uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ + uint16_t clock_offset; /* clock offset */ + int8_t rssi; /* rssi */ } hci_rssi_response; -#define HCI_EVENT_READ_REMOTE_EXTENDED_FEATURES 0x23 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t page; /* page number */ - uint8_t max; /* max page number */ - uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ +#define HCI_EVENT_READ_REMOTE_EXTENDED_FEATURES 0x23 +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t page; /* page number */ + uint8_t max; /* max page number */ + uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ } hci_read_remote_extended_features_ep; -#define HCI_EVENT_SCO_CON_COMPL 0x2c -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - bdaddr_t bdaddr; /* unit address */ - uint8_t link_type; /* link type */ - uint8_t interval; /* transmission interval */ - uint8_t window; /* retransmission window */ - uint16_t rxlen; /* rx packet length */ - uint16_t txlen; /* tx packet length */ - uint8_t mode; /* air mode */ +#define HCI_EVENT_SCO_CON_COMPL 0x2c +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + bdaddr_t bdaddr; /* unit address */ + uint8_t link_type; /* link type */ + uint8_t interval; /* transmission interval */ + uint8_t window; /* retransmission window */ + uint16_t rxlen; /* rx packet length */ + uint16_t txlen; /* tx packet length */ + uint8_t mode; /* air mode */ } hci_sco_con_compl_ep; -#define HCI_EVENT_SCO_CON_CHANGED 0x2d -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t interval; /* transmission interval */ - uint8_t window; /* retransmission window */ - uint16_t rxlen; /* rx packet length */ - uint16_t txlen; /* tx packet length */ +#define HCI_EVENT_SCO_CON_CHANGED 0x2d +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t interval; /* transmission interval */ + uint8_t window; /* retransmission window */ + uint16_t rxlen; /* rx packet length */ + uint16_t txlen; /* tx packet length */ } hci_sco_con_changed_ep; -#define HCI_EVENT_SNIFF_SUBRATING 0x2e -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint16_t tx_latency; /* max transmit latency */ - uint16_t rx_latency; /* max receive latency */ - uint16_t remote_timeout; /* remote timeout */ - uint16_t local_timeout; /* local timeout */ +#define HCI_EVENT_SNIFF_SUBRATING 0x2e +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint16_t tx_latency; /* max transmit latency */ + uint16_t rx_latency; /* max receive latency */ + uint16_t remote_timeout; /* remote timeout */ + uint16_t local_timeout; /* local timeout */ } hci_sniff_subrating_ep; -#define HCI_EVENT_EXTENDED_RESULT 0x2f -typedef struct { - uint8_t num_responses; /* must be 0x01 */ - bdaddr_t bdaddr; /* remote device address */ - uint8_t page_scan_rep_mode; - uint8_t reserved; - uint8_t uclass[HCI_CLASS_SIZE]; - uint16_t clock_offset; - int8_t rssi; - uint8_t response[240]; /* extended inquiry response */ +#define HCI_EVENT_EXTENDED_RESULT 0x2f +typedef struct +{ + uint8_t num_responses; /* must be 0x01 */ + bdaddr_t bdaddr; /* remote device address */ + uint8_t page_scan_rep_mode; + uint8_t reserved; + uint8_t uclass[HCI_CLASS_SIZE]; + uint16_t clock_offset; + int8_t rssi; + uint8_t response[240]; /* extended inquiry response */ } hci_extended_result_ep; -#define HCI_EVENT_ENCRYPTION_KEY_REFRESH 0x30 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ +#define HCI_EVENT_ENCRYPTION_KEY_REFRESH 0x30 +typedef struct +{ + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ } hci_encryption_key_refresh_ep; -#define HCI_EVENT_IO_CAPABILITY_REQ 0x31 -typedef struct { - bdaddr_t bdaddr; /* remote device address */ +#define HCI_EVENT_IO_CAPABILITY_REQ 0x31 +typedef struct +{ + bdaddr_t bdaddr; /* remote device address */ } hci_io_capability_req_ep; -#define HCI_EVENT_IO_CAPABILITY_RSP 0x32 -typedef struct { - bdaddr_t bdaddr; /* remote device address */ - uint8_t io_capability; - uint8_t oob_data_present; - uint8_t auth_requirement; +#define HCI_EVENT_IO_CAPABILITY_RSP 0x32 +typedef struct +{ + bdaddr_t bdaddr; /* remote device address */ + uint8_t io_capability; + uint8_t oob_data_present; + uint8_t auth_requirement; } hci_io_capability_rsp_ep; -#define HCI_EVENT_USER_CONFIRM_REQ 0x33 -typedef struct { - bdaddr_t bdaddr; /* remote device address */ - uint32_t value; /* 000000 - 999999 */ +#define HCI_EVENT_USER_CONFIRM_REQ 0x33 +typedef struct +{ + bdaddr_t bdaddr; /* remote device address */ + uint32_t value; /* 000000 - 999999 */ } hci_user_confirm_req_ep; -#define HCI_EVENT_USER_PASSKEY_REQ 0x34 -typedef struct { - bdaddr_t bdaddr; /* remote device address */ +#define HCI_EVENT_USER_PASSKEY_REQ 0x34 +typedef struct +{ + bdaddr_t bdaddr; /* remote device address */ } hci_user_passkey_req_ep; -#define HCI_EVENT_REMOTE_OOB_DATA_REQ 0x35 -typedef struct { - bdaddr_t bdaddr; /* remote device address */ +#define HCI_EVENT_REMOTE_OOB_DATA_REQ 0x35 +typedef struct +{ + bdaddr_t bdaddr; /* remote device address */ } hci_remote_oob_data_req_ep; -#define HCI_EVENT_SIMPLE_PAIRING_COMPL 0x36 -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote device address */ +#define HCI_EVENT_SIMPLE_PAIRING_COMPL 0x36 +typedef struct +{ + uint8_t status; /* 0x00 - success */ + bdaddr_t bdaddr; /* remote device address */ } hci_simple_pairing_compl_ep; -#define HCI_EVENT_LINK_SUPERVISION_TO_CHANGED 0x38 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t timeout; /* link supervision timeout */ +#define HCI_EVENT_LINK_SUPERVISION_TO_CHANGED 0x38 +typedef struct +{ + uint16_t con_handle; /* connection handle */ + uint16_t timeout; /* link supervision timeout */ } hci_link_supervision_to_changed_ep; -#define HCI_EVENT_ENHANCED_FLUSH_COMPL 0x39 -typedef struct { - uint16_t con_handle; /* connection handle */ +#define HCI_EVENT_ENHANCED_FLUSH_COMPL 0x39 +typedef struct +{ + uint16_t con_handle; /* connection handle */ } hci_enhanced_flush_compl_ep; -#define HCI_EVENT_USER_PASSKEY_NOTIFICATION 0x3b -typedef struct { - bdaddr_t bdaddr; /* remote device address */ - uint32_t value; /* 000000 - 999999 */ +#define HCI_EVENT_USER_PASSKEY_NOTIFICATION 0x3b +typedef struct +{ + bdaddr_t bdaddr; /* remote device address */ + uint32_t value; /* 000000 - 999999 */ } hci_user_passkey_notification_ep; -#define HCI_EVENT_KEYPRESS_NOTIFICATION 0x3c -typedef struct { - bdaddr_t bdaddr; /* remote device address */ - uint8_t notification_type; +#define HCI_EVENT_KEYPRESS_NOTIFICATION 0x3c +typedef struct +{ + bdaddr_t bdaddr; /* remote device address */ + uint8_t notification_type; } hci_keypress_notification_ep; -#define HCI_EVENT_REMOTE_FEATURES_NOTIFICATION 0x3d -typedef struct { - bdaddr_t bdaddr; /* remote device address */ - uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ +#define HCI_EVENT_REMOTE_FEATURES_NOTIFICATION 0x3d +typedef struct +{ + bdaddr_t bdaddr; /* remote device address */ + uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ } hci_remote_features_notification_ep; -#define HCI_EVENT_BT_LOGO 0xfe +#define HCI_EVENT_BT_LOGO 0xfe -#define HCI_EVENT_VENDOR 0xff +#define HCI_EVENT_VENDOR 0xff /************************************************************************** ************************************************************************** @@ -2264,47 +2496,45 @@ typedef struct { **************************************************************************/ /* HCI socket options */ -#define SO_HCI_EVT_FILTER 1 /* get/set event filter */ -#define SO_HCI_PKT_FILTER 2 /* get/set packet filter */ -#define SO_HCI_DIRECTION 3 /* packet direction indicator */ +#define SO_HCI_EVT_FILTER 1 /* get/set event filter */ +#define SO_HCI_PKT_FILTER 2 /* get/set packet filter */ +#define SO_HCI_DIRECTION 3 /* packet direction indicator */ /* Control Messages */ -#define SCM_HCI_DIRECTION SO_HCI_DIRECTION +#define SCM_HCI_DIRECTION SO_HCI_DIRECTION /* * HCI socket filter and get/set routines * * for ease of use, we filter 256 possible events/packets */ -struct hci_filter { - uint32_t mask[8]; /* 256 bits */ +struct hci_filter +{ + uint32_t mask[8]; /* 256 bits */ }; -static __inline void -hci_filter_set(uint8_t bit, struct hci_filter *filter) +static __inline void hci_filter_set(uint8_t bit, struct hci_filter* filter) { - uint8_t off = bit - 1; + uint8_t off = bit - 1; - off >>= 5; - filter->mask[off] |= (1 << ((bit - 1) & 0x1f)); + off >>= 5; + filter->mask[off] |= (1 << ((bit - 1) & 0x1f)); } -static __inline void -hci_filter_clr(uint8_t bit, struct hci_filter *filter) +static __inline void hci_filter_clr(uint8_t bit, struct hci_filter* filter) { - uint8_t off = bit - 1; + uint8_t off = bit - 1; - off >>= 5; - filter->mask[off] &= ~(1 << ((bit - 1) & 0x1f)); + off >>= 5; + filter->mask[off] &= ~(1 << ((bit - 1) & 0x1f)); } -static __inline int -hci_filter_test(uint8_t bit, const struct hci_filter *filter) +static __inline int hci_filter_test(uint8_t bit, const struct hci_filter* filter) { - uint8_t off = bit - 1; + uint8_t off = bit - 1; - off >>= 5; - return (filter->mask[off] & (1 << ((bit - 1) & 0x1f))); + off >>= 5; + return (filter->mask[off] & (1 << ((bit - 1) & 0x1f))); } /* @@ -2313,81 +2543,81 @@ hci_filter_test(uint8_t bit, const struct hci_filter *filter) * Apart from GBTINFOA, these are all indexed on the unit name */ -#define SIOCGBTINFO _IOWR('b', 5, struct btreq) /* get unit info */ -#define SIOCGBTINFOA _IOWR('b', 6, struct btreq) /* get info by address */ -#define SIOCNBTINFO _IOWR('b', 7, struct btreq) /* next unit info */ +#define SIOCGBTINFO _IOWR('b', 5, struct btreq) /* get unit info */ +#define SIOCGBTINFOA _IOWR('b', 6, struct btreq) /* get info by address */ +#define SIOCNBTINFO _IOWR('b', 7, struct btreq) /* next unit info */ -#define SIOCSBTFLAGS _IOWR('b', 8, struct btreq) /* set unit flags */ -#define SIOCSBTPOLICY _IOWR('b', 9, struct btreq) /* set unit link policy */ -#define SIOCSBTPTYPE _IOWR('b', 10, struct btreq) /* set unit packet type */ +#define SIOCSBTFLAGS _IOWR('b', 8, struct btreq) /* set unit flags */ +#define SIOCSBTPOLICY _IOWR('b', 9, struct btreq) /* set unit link policy */ +#define SIOCSBTPTYPE _IOWR('b', 10, struct btreq) /* set unit packet type */ -#define SIOCGBTSTATS _IOWR('b', 11, struct btreq) /* get unit statistics */ -#define SIOCZBTSTATS _IOWR('b', 12, struct btreq) /* zero unit statistics */ +#define SIOCGBTSTATS _IOWR('b', 11, struct btreq) /* get unit statistics */ +#define SIOCZBTSTATS _IOWR('b', 12, struct btreq) /* zero unit statistics */ -#define SIOCBTDUMP _IOW('b', 13, struct btreq) /* print debug info */ -#define SIOCSBTSCOMTU _IOWR('b', 17, struct btreq) /* set sco_mtu value */ +#define SIOCBTDUMP _IOW('b', 13, struct btreq) /* print debug info */ +#define SIOCSBTSCOMTU _IOWR('b', 17, struct btreq) /* set sco_mtu value */ -struct bt_stats { - uint32_t err_tx; - uint32_t err_rx; - uint32_t cmd_tx; - uint32_t evt_rx; - uint32_t acl_tx; - uint32_t acl_rx; - uint32_t sco_tx; - uint32_t sco_rx; - uint32_t byte_tx; - uint32_t byte_rx; +struct bt_stats +{ + uint32_t err_tx; + uint32_t err_rx; + uint32_t cmd_tx; + uint32_t evt_rx; + uint32_t acl_tx; + uint32_t acl_rx; + uint32_t sco_tx; + uint32_t sco_rx; + uint32_t byte_tx; + uint32_t byte_rx; }; -struct btreq { - char btr_name[HCI_DEVNAME_SIZE]; /* device name */ +struct btreq +{ + char btr_name[HCI_DEVNAME_SIZE]; /* device name */ - union { - struct { - bdaddr_t btri_bdaddr; /* device bdaddr */ - uint16_t btri_flags; /* flags */ - uint16_t btri_num_cmd; /* # of free cmd buffers */ - uint16_t btri_num_acl; /* # of free ACL buffers */ - uint16_t btri_num_sco; /* # of free SCO buffers */ - uint16_t btri_acl_mtu; /* ACL mtu */ - uint16_t btri_sco_mtu; /* SCO mtu */ - uint16_t btri_link_policy; /* Link Policy */ - uint16_t btri_packet_type; /* Packet Type */ - } btri; - struct bt_stats btrs; /* unit stats */ - } btru; + union { + struct + { + bdaddr_t btri_bdaddr; /* device bdaddr */ + uint16_t btri_flags; /* flags */ + uint16_t btri_num_cmd; /* # of free cmd buffers */ + uint16_t btri_num_acl; /* # of free ACL buffers */ + uint16_t btri_num_sco; /* # of free SCO buffers */ + uint16_t btri_acl_mtu; /* ACL mtu */ + uint16_t btri_sco_mtu; /* SCO mtu */ + uint16_t btri_link_policy; /* Link Policy */ + uint16_t btri_packet_type; /* Packet Type */ + } btri; + struct bt_stats btrs; /* unit stats */ + } btru; }; -#define btr_flags btru.btri.btri_flags -#define btr_bdaddr btru.btri.btri_bdaddr -#define btr_num_cmd btru.btri.btri_num_cmd -#define btr_num_acl btru.btri.btri_num_acl -#define btr_num_sco btru.btri.btri_num_sco -#define btr_acl_mtu btru.btri.btri_acl_mtu -#define btr_sco_mtu btru.btri.btri_sco_mtu +#define btr_flags btru.btri.btri_flags +#define btr_bdaddr btru.btri.btri_bdaddr +#define btr_num_cmd btru.btri.btri_num_cmd +#define btr_num_acl btru.btri.btri_num_acl +#define btr_num_sco btru.btri.btri_num_sco +#define btr_acl_mtu btru.btri.btri_acl_mtu +#define btr_sco_mtu btru.btri.btri_sco_mtu #define btr_link_policy btru.btri.btri_link_policy #define btr_packet_type btru.btri.btri_packet_type -#define btr_stats btru.btrs +#define btr_stats btru.btrs /* hci_unit & btr_flags */ -#define BTF_UP (1<<0) /* unit is up */ -#define BTF_RUNNING (1<<1) /* unit is running */ -#define BTF_XMIT_CMD (1<<2) /* unit is transmitting CMD packets */ -#define BTF_XMIT_ACL (1<<3) /* unit is transmitting ACL packets */ -#define BTF_XMIT_SCO (1<<4) /* unit is transmitting SCO packets */ -#define BTF_XMIT (BTF_XMIT_CMD | BTF_XMIT_ACL | BTF_XMIT_SCO) -#define BTF_INIT_BDADDR (1<<5) /* waiting for bdaddr */ -#define BTF_INIT_BUFFER_SIZE (1<<6) /* waiting for buffer size */ -#define BTF_INIT_FEATURES (1<<7) /* waiting for features */ -#define BTF_POWER_UP_NOOP (1<<8) /* should wait for No-op on power up */ -#define BTF_INIT_COMMANDS (1<<9) /* waiting for supported commands */ -#define BTF_MASTER (1<<10) /* request Master role */ +#define BTF_UP (1 << 0) /* unit is up */ +#define BTF_RUNNING (1 << 1) /* unit is running */ +#define BTF_XMIT_CMD (1 << 2) /* unit is transmitting CMD packets */ +#define BTF_XMIT_ACL (1 << 3) /* unit is transmitting ACL packets */ +#define BTF_XMIT_SCO (1 << 4) /* unit is transmitting SCO packets */ +#define BTF_XMIT (BTF_XMIT_CMD | BTF_XMIT_ACL | BTF_XMIT_SCO) +#define BTF_INIT_BDADDR (1 << 5) /* waiting for bdaddr */ +#define BTF_INIT_BUFFER_SIZE (1 << 6) /* waiting for buffer size */ +#define BTF_INIT_FEATURES (1 << 7) /* waiting for features */ +#define BTF_POWER_UP_NOOP (1 << 8) /* should wait for No-op on power up */ +#define BTF_INIT_COMMANDS (1 << 9) /* waiting for supported commands */ +#define BTF_MASTER (1 << 10) /* request Master role */ -#define BTF_INIT (BTF_INIT_BDADDR \ - | BTF_INIT_BUFFER_SIZE \ - | BTF_INIT_FEATURES \ - | BTF_INIT_COMMANDS) +#define BTF_INIT (BTF_INIT_BDADDR | BTF_INIT_BUFFER_SIZE | BTF_INIT_FEATURES | BTF_INIT_COMMANDS) ////////////////////////////////////////////////////////////////////////// // Dolphin-custom structs (to kill) @@ -2395,159 +2625,158 @@ struct btreq { #include "Common/CommonTypes.h" struct SCommandMessage { - u16 Opcode; - u8 len; + u16 Opcode; + u8 len; }; struct SHCIEventCommand { - u8 EventType; - u8 PayloadLength; - u8 PacketIndicator; - u16 Opcode; + u8 EventType; + u8 PayloadLength; + u8 PacketIndicator; + u16 Opcode; }; struct SHCIEventStatus { - u8 EventType; - u8 PayloadLength; - u8 EventStatus; - u8 PacketIndicator; - u16 Opcode; + u8 EventType; + u8 PayloadLength; + u8 EventStatus; + u8 PacketIndicator; + u16 Opcode; }; struct SHCIEventInquiryResult { - u8 EventType; - u8 PayloadLength; - u8 num_responses; + u8 EventType; + u8 PayloadLength; + u8 num_responses; }; struct SHCIEventInquiryComplete { - u8 EventType; - u8 PayloadLength; - u8 EventStatus; + u8 EventType; + u8 PayloadLength; + u8 EventStatus; }; struct SHCIEventReadClockOffsetComplete { - u8 EventType; - u8 PayloadLength; - u8 EventStatus; - u16 ConnectionHandle; - u16 ClockOffset; + u8 EventType; + u8 PayloadLength; + u8 EventStatus; + u16 ConnectionHandle; + u16 ClockOffset; }; struct SHCIEventConPacketTypeChange { - u8 EventType; - u8 PayloadLength; - u8 EventStatus; - u16 ConnectionHandle; - u16 PacketType; + u8 EventType; + u8 PayloadLength; + u8 EventStatus; + u16 ConnectionHandle; + u16 PacketType; }; struct SHCIEventReadRemoteVerInfo { - u8 EventType; - u8 PayloadLength; - u8 EventStatus; - u16 ConnectionHandle; - u8 lmp_version; - u16 manufacturer; - u16 lmp_subversion; + u8 EventType; + u8 PayloadLength; + u8 EventStatus; + u16 ConnectionHandle; + u8 lmp_version; + u16 manufacturer; + u16 lmp_subversion; }; struct SHCIEventReadRemoteFeatures { - u8 EventType; - u8 PayloadLength; - u8 EventStatus; - u16 ConnectionHandle; - u8 features[HCI_FEATURES_SIZE]; + u8 EventType; + u8 PayloadLength; + u8 EventStatus; + u16 ConnectionHandle; + u8 features[HCI_FEATURES_SIZE]; }; struct SHCIEventRemoteNameReq { - u8 EventType; - u8 PayloadLength; - u8 EventStatus; - bdaddr_t bdaddr; - u8 RemoteName[HCI_UNIT_NAME_SIZE]; + u8 EventType; + u8 PayloadLength; + u8 EventStatus; + bdaddr_t bdaddr; + u8 RemoteName[HCI_UNIT_NAME_SIZE]; }; struct SHCIEventRequestConnection { - u8 EventType; - u8 PayloadLength; - bdaddr_t bdaddr; - uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ - u8 LinkType; + u8 EventType; + u8 PayloadLength; + bdaddr_t bdaddr; + uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ + u8 LinkType; }; struct SHCIEventConnectionComplete { - u8 EventType; - u8 PayloadLength; - u8 EventStatus; - u16 Connection_Handle; - bdaddr_t bdaddr; - u8 LinkType; - u8 EncryptionEnabled; + u8 EventType; + u8 PayloadLength; + u8 EventStatus; + u16 Connection_Handle; + bdaddr_t bdaddr; + u8 LinkType; + u8 EncryptionEnabled; }; struct SHCIEventRoleChange { - u8 EventType; - u8 PayloadLength; - u8 EventStatus; - bdaddr_t bdaddr; - u8 NewRole; + u8 EventType; + u8 PayloadLength; + u8 EventStatus; + bdaddr_t bdaddr; + u8 NewRole; }; struct SHCIEventAuthenticationCompleted { - u8 EventType; - u8 PayloadLength; - u8 EventStatus; - u16 Connection_Handle; + u8 EventType; + u8 PayloadLength; + u8 EventStatus; + u16 Connection_Handle; }; struct SHCIEventModeChange { - u8 EventType; - u8 PayloadLength; - u8 EventStatus; - u16 Connection_Handle; - u8 CurrentMode; - u16 Value; - + u8 EventType; + u8 PayloadLength; + u8 EventStatus; + u16 Connection_Handle; + u8 CurrentMode; + u16 Value; }; struct SHCIEventDisconnectCompleted { - u8 EventType; - u8 PayloadLength; - u8 EventStatus; - u16 Connection_Handle; - u8 Reason; + u8 EventType; + u8 PayloadLength; + u8 EventStatus; + u16 Connection_Handle; + u8 Reason; }; struct SHCIEventRequestLinkKey { - u8 EventType; - u8 PayloadLength; - bdaddr_t bdaddr; + u8 EventType; + u8 PayloadLength; + bdaddr_t bdaddr; }; struct SHCIEventLinkKeyNotification { - u8 EventType; - u8 PayloadLength; - u8 numKeys; - bdaddr_t bdaddr; - u8 LinkKey[HCI_KEY_SIZE]; + u8 EventType; + u8 PayloadLength; + u8 numKeys; + bdaddr_t bdaddr; + u8 LinkKey[HCI_KEY_SIZE]; }; ////////////////////////////////////////////////////////////////////////// diff --git a/Source/Core/Core/IPC_HLE/l2cap.h b/Source/Core/Core/IPC_HLE/l2cap.h index e5f9387b49..d29ea3cffc 100644 --- a/Source/Core/Core/IPC_HLE/l2cap.h +++ b/Source/Core/Core/IPC_HLE/l2cap.h @@ -86,128 +86,130 @@ * This number does not depend on number of HCI connections. */ -#define L2CAP_NULL_CID 0x0000 /* DO NOT USE THIS CID */ -#define L2CAP_SIGNAL_CID 0x0001 /* signaling channel ID */ -#define L2CAP_CLT_CID 0x0002 /* connectionless channel ID */ +#define L2CAP_NULL_CID 0x0000 /* DO NOT USE THIS CID */ +#define L2CAP_SIGNAL_CID 0x0001 /* signaling channel ID */ +#define L2CAP_CLT_CID 0x0002 /* connectionless channel ID */ /* 0x0003 - 0x003f Reserved */ -#define L2CAP_FIRST_CID 0x0040 /* dynamically alloc. (start) */ -#define L2CAP_LAST_CID 0xffff /* dynamically alloc. (end) */ +#define L2CAP_FIRST_CID 0x0040 /* dynamically alloc. (start) */ +#define L2CAP_LAST_CID 0xffff /* dynamically alloc. (end) */ /* L2CAP MTU */ -#define L2CAP_MTU_MINIMUM 48 -#define L2CAP_MTU_DEFAULT 672 -#define L2CAP_MTU_MAXIMUM 0xffff +#define L2CAP_MTU_MINIMUM 48 +#define L2CAP_MTU_DEFAULT 672 +#define L2CAP_MTU_MAXIMUM 0xffff /* L2CAP flush and link timeouts */ -#define L2CAP_FLUSH_TIMO_DEFAULT 0xffff /* always retransmit */ -#define L2CAP_LINK_TIMO_DEFAULT 0xffff +#define L2CAP_FLUSH_TIMO_DEFAULT 0xffff /* always retransmit */ +#define L2CAP_LINK_TIMO_DEFAULT 0xffff /* L2CAP Command Reject reasons */ -#define L2CAP_REJ_NOT_UNDERSTOOD 0x0000 -#define L2CAP_REJ_MTU_EXCEEDED 0x0001 -#define L2CAP_REJ_INVALID_CID 0x0002 +#define L2CAP_REJ_NOT_UNDERSTOOD 0x0000 +#define L2CAP_REJ_MTU_EXCEEDED 0x0001 +#define L2CAP_REJ_INVALID_CID 0x0002 /* 0x0003 - 0xffff - reserved for future use */ /* Protocol/Service Multiplexor (PSM) values */ -#define L2CAP_PSM_ANY 0x0000 /* Any/Invalid PSM */ -#define L2CAP_PSM_SDP 0x0001 /* Service Discovery Protocol */ -#define L2CAP_PSM_RFCOMM 0x0003 /* RFCOMM protocol */ -#define L2CAP_PSM_TCP 0x0005 /* Telephony Control Protocol */ -#define L2CAP_PSM_TCS 0x0007 /* TCS cordless */ -#define L2CAP_PSM_BNEP 0x000f /* Bluetooth Network */ +#define L2CAP_PSM_ANY 0x0000 /* Any/Invalid PSM */ +#define L2CAP_PSM_SDP 0x0001 /* Service Discovery Protocol */ +#define L2CAP_PSM_RFCOMM 0x0003 /* RFCOMM protocol */ +#define L2CAP_PSM_TCP 0x0005 /* Telephony Control Protocol */ +#define L2CAP_PSM_TCS 0x0007 /* TCS cordless */ +#define L2CAP_PSM_BNEP 0x000f /* Bluetooth Network */ /* Encapsulation Protocol*/ -#define L2CAP_PSM_HID_CNTL 0x0011 /* HID Control */ -#define L2CAP_PSM_HID_INTR 0x0013 /* HID Interrupt */ -#define L2CAP_PSM_ESDP 0x0015 /* Extended Service */ +#define L2CAP_PSM_HID_CNTL 0x0011 /* HID Control */ +#define L2CAP_PSM_HID_INTR 0x0013 /* HID Interrupt */ +#define L2CAP_PSM_ESDP 0x0015 /* Extended Service */ /* Discovery Profile */ -#define L2CAP_PSM_AVCTP 0x0017 /* Audio/Visual Control */ +#define L2CAP_PSM_AVCTP 0x0017 /* Audio/Visual Control */ /* Transport Protocol */ -#define L2CAP_PSM_AVDTP 0x0019 /* Audio/Visual Distribution */ +#define L2CAP_PSM_AVDTP 0x0019 /* Audio/Visual Distribution */ /* Transport Protocol */ /* 0x0019 - 0x1000 - reserved for future use */ -#define L2CAP_PSM_INVALID(psm) (((psm) & 0x0101) != 0x0001) +#define L2CAP_PSM_INVALID(psm) (((psm)&0x0101) != 0x0001) /* L2CAP Connection response command result codes */ -#define L2CAP_SUCCESS 0x0000 -#define L2CAP_PENDING 0x0001 -#define L2CAP_PSM_NOT_SUPPORTED 0x0002 -#define L2CAP_SECURITY_BLOCK 0x0003 -#define L2CAP_NO_RESOURCES 0x0004 -#define L2CAP_TIMEOUT 0xeeee -#define L2CAP_UNKNOWN 0xffff +#define L2CAP_SUCCESS 0x0000 +#define L2CAP_PENDING 0x0001 +#define L2CAP_PSM_NOT_SUPPORTED 0x0002 +#define L2CAP_SECURITY_BLOCK 0x0003 +#define L2CAP_NO_RESOURCES 0x0004 +#define L2CAP_TIMEOUT 0xeeee +#define L2CAP_UNKNOWN 0xffff /* 0x0005 - 0xffff - reserved for future use */ /* L2CAP Connection response status codes */ -#define L2CAP_NO_INFO 0x0000 -#define L2CAP_AUTH_PENDING 0x0001 -#define L2CAP_AUTZ_PENDING 0x0002 +#define L2CAP_NO_INFO 0x0000 +#define L2CAP_AUTH_PENDING 0x0001 +#define L2CAP_AUTZ_PENDING 0x0002 /* 0x0003 - 0xffff - reserved for future use */ /* L2CAP Configuration response result codes */ -#define L2CAP_UNACCEPTABLE_PARAMS 0x0001 -#define L2CAP_REJECT 0x0002 -#define L2CAP_UNKNOWN_OPTION 0x0003 +#define L2CAP_UNACCEPTABLE_PARAMS 0x0001 +#define L2CAP_REJECT 0x0002 +#define L2CAP_UNKNOWN_OPTION 0x0003 /* 0x0003 - 0xffff - reserved for future use */ /* L2CAP Configuration options */ -#define L2CAP_OPT_CFLAG_BIT 0x0001 -#define L2CAP_OPT_CFLAG(flags) ((flags) & L2CAP_OPT_CFLAG_BIT) -#define L2CAP_OPT_HINT_BIT 0x80 -#define L2CAP_OPT_HINT(type) ((type) & L2CAP_OPT_HINT_BIT) -#define L2CAP_OPT_HINT_MASK 0x7f -#define L2CAP_OPT_MTU 0x01 -#define L2CAP_OPT_MTU_SIZE sizeof(uint16_t) -#define L2CAP_OPT_FLUSH_TIMO 0x02 -#define L2CAP_OPT_FLUSH_TIMO_SIZE sizeof(uint16_t) -#define L2CAP_OPT_QOS 0x03 -#define L2CAP_OPT_QOS_SIZE sizeof(l2cap_qos_t) -#define L2CAP_OPT_RFC 0x04 -#define L2CAP_OPT_RFC_SIZE sizeof(l2cap_rfc_t) +#define L2CAP_OPT_CFLAG_BIT 0x0001 +#define L2CAP_OPT_CFLAG(flags) ((flags)&L2CAP_OPT_CFLAG_BIT) +#define L2CAP_OPT_HINT_BIT 0x80 +#define L2CAP_OPT_HINT(type) ((type)&L2CAP_OPT_HINT_BIT) +#define L2CAP_OPT_HINT_MASK 0x7f +#define L2CAP_OPT_MTU 0x01 +#define L2CAP_OPT_MTU_SIZE sizeof(uint16_t) +#define L2CAP_OPT_FLUSH_TIMO 0x02 +#define L2CAP_OPT_FLUSH_TIMO_SIZE sizeof(uint16_t) +#define L2CAP_OPT_QOS 0x03 +#define L2CAP_OPT_QOS_SIZE sizeof(l2cap_qos_t) +#define L2CAP_OPT_RFC 0x04 +#define L2CAP_OPT_RFC_SIZE sizeof(l2cap_rfc_t) /* 0x05 - 0xff - reserved for future use */ /* L2CAP Information request type codes */ -#define L2CAP_CONNLESS_MTU 0x0001 -#define L2CAP_EXTENDED_FEATURES 0x0002 +#define L2CAP_CONNLESS_MTU 0x0001 +#define L2CAP_EXTENDED_FEATURES 0x0002 /* 0x0003 - 0xffff - reserved for future use */ /* L2CAP Information response codes */ -#define L2CAP_NOT_SUPPORTED 0x0001 +#define L2CAP_NOT_SUPPORTED 0x0001 /* 0x0002 - 0xffff - reserved for future use */ #pragma pack(push, 1) /* L2CAP Quality of Service option */ -typedef struct { - uint8_t flags; /* reserved for future use */ - uint8_t service_type; /* service type */ - uint32_t token_rate; /* bytes per second */ - uint32_t token_bucket_size; /* bytes */ - uint32_t peak_bandwidth; /* bytes per second */ - uint32_t latency; /* microseconds */ - uint32_t delay_variation; /* microseconds */ +typedef struct +{ + uint8_t flags; /* reserved for future use */ + uint8_t service_type; /* service type */ + uint32_t token_rate; /* bytes per second */ + uint32_t token_bucket_size; /* bytes */ + uint32_t peak_bandwidth; /* bytes per second */ + uint32_t latency; /* microseconds */ + uint32_t delay_variation; /* microseconds */ } l2cap_qos_t; /* L2CAP QoS type */ -#define L2CAP_QOS_NO_TRAFFIC 0x00 -#define L2CAP_QOS_BEST_EFFORT 0x01 /* (default) */ -#define L2CAP_QOS_GUARANTEED 0x02 +#define L2CAP_QOS_NO_TRAFFIC 0x00 +#define L2CAP_QOS_BEST_EFFORT 0x01 /* (default) */ +#define L2CAP_QOS_GUARANTEED 0x02 /* 0x03 - 0xff - reserved for future use */ /* L2CAP Retransmission & Flow Control option */ -typedef struct { - uint8_t mode; /* RFC mode */ - uint8_t window_size; /* bytes */ - uint8_t max_transmit; /* max retransmissions */ - uint16_t retransmit_timo; /* milliseconds */ - uint16_t monitor_timo; /* milliseconds */ - uint16_t max_pdu_size; /* bytes */ +typedef struct +{ + uint8_t mode; /* RFC mode */ + uint8_t window_size; /* bytes */ + uint8_t max_transmit; /* max retransmissions */ + uint16_t retransmit_timo; /* milliseconds */ + uint16_t monitor_timo; /* milliseconds */ + uint16_t max_pdu_size; /* bytes */ } l2cap_rfc_t; /* L2CAP RFC mode */ -#define L2CAP_RFC_BASIC 0x00 /* (default) */ -#define L2CAP_RFC_RETRANSMIT 0x01 -#define L2CAP_RFC_FLOW 0x02 +#define L2CAP_RFC_BASIC 0x00 /* (default) */ +#define L2CAP_RFC_RETRANSMIT 0x01 +#define L2CAP_RFC_FLOW 0x02 /* 0x03 - 0xff - reserved for future use */ /************************************************************************** @@ -217,124 +219,135 @@ typedef struct { **************************************************************************/ /* L2CAP header */ -typedef struct { - uint16_t length; /* payload size */ - uint16_t dcid; /* destination channel ID */ +typedef struct +{ + uint16_t length; /* payload size */ + uint16_t dcid; /* destination channel ID */ } l2cap_hdr_t; /* L2CAP ConnectionLess Traffic (dcid == L2CAP_CLT_CID) */ -typedef struct { - uint16_t psm; /* Protocol/Service Multiplexor */ +typedef struct +{ + uint16_t psm; /* Protocol/Service Multiplexor */ } l2cap_clt_hdr_t; -#define L2CAP_CLT_MTU_MAXIMUM \ - (L2CAP_MTU_MAXIMUM - sizeof(l2cap_clt_hdr_t)) +#define L2CAP_CLT_MTU_MAXIMUM (L2CAP_MTU_MAXIMUM - sizeof(l2cap_clt_hdr_t)) /* L2CAP Command header (dcid == L2CAP_SIGNAL_CID) */ -typedef struct { - uint8_t code; /* command OpCode */ - uint8_t ident; /* identifier to match request and response */ - uint16_t length; /* command parameters length */ +typedef struct +{ + uint8_t code; /* command OpCode */ + uint8_t ident; /* identifier to match request and response */ + uint16_t length; /* command parameters length */ } l2cap_cmd_hdr_t; /* L2CAP Command Reject */ -#define L2CAP_COMMAND_REJ 0x01 -typedef struct { - uint16_t reason; /* reason to reject command */ - uint16_t data[2];/* optional data */ +#define L2CAP_COMMAND_REJ 0x01 +typedef struct +{ + uint16_t reason; /* reason to reject command */ + uint16_t data[2]; /* optional data */ } l2cap_cmd_rej_cp; /* L2CAP Connection Request */ -#define L2CAP_CONNECT_REQ 0x02 -typedef struct { - uint16_t psm; /* Protocol/Service Multiplexor (PSM) */ - uint16_t scid; /* source channel ID */ +#define L2CAP_CONNECT_REQ 0x02 +typedef struct +{ + uint16_t psm; /* Protocol/Service Multiplexor (PSM) */ + uint16_t scid; /* source channel ID */ } l2cap_con_req_cp; /* L2CAP Connection Response */ -#define L2CAP_CONNECT_RSP 0x03 -typedef struct { - uint16_t dcid; /* destination channel ID */ - uint16_t scid; /* source channel ID */ - uint16_t result; /* 0x00 - success */ - uint16_t status; /* more info if result != 0x00 */ +#define L2CAP_CONNECT_RSP 0x03 +typedef struct +{ + uint16_t dcid; /* destination channel ID */ + uint16_t scid; /* source channel ID */ + uint16_t result; /* 0x00 - success */ + uint16_t status; /* more info if result != 0x00 */ } l2cap_con_rsp_cp; /* L2CAP Configuration Request */ -#define L2CAP_CONFIG_REQ 0x04 -typedef struct { - uint16_t dcid; /* destination channel ID */ - uint16_t flags; /* flags */ - /* uint8_t options[] -- options */ +#define L2CAP_CONFIG_REQ 0x04 +typedef struct +{ + uint16_t dcid; /* destination channel ID */ + uint16_t flags; /* flags */ + /* uint8_t options[] -- options */ } l2cap_cfg_req_cp; /* L2CAP Configuration Response */ -#define L2CAP_CONFIG_RSP 0x05 -typedef struct { - uint16_t scid; /* source channel ID */ - uint16_t flags; /* flags */ - uint16_t result; /* 0x00 - success */ - /* uint8_t options[] -- options */ +#define L2CAP_CONFIG_RSP 0x05 +typedef struct +{ + uint16_t scid; /* source channel ID */ + uint16_t flags; /* flags */ + uint16_t result; /* 0x00 - success */ + /* uint8_t options[] -- options */ } l2cap_cfg_rsp_cp; /* L2CAP configuration option */ -typedef struct { - uint8_t type; - uint8_t length; - /* uint8_t value[] -- option value (depends on type) */ +typedef struct +{ + uint8_t type; + uint8_t length; + /* uint8_t value[] -- option value (depends on type) */ } l2cap_cfg_opt_t; /* L2CAP configuration option value */ typedef union { - uint16_t mtu; /* L2CAP_OPT_MTU */ - uint16_t flush_timo; /* L2CAP_OPT_FLUSH_TIMO */ - l2cap_qos_t qos; /* L2CAP_OPT_QOS */ - l2cap_rfc_t rfc; /* L2CAP_OPT_RFC */ + uint16_t mtu; /* L2CAP_OPT_MTU */ + uint16_t flush_timo; /* L2CAP_OPT_FLUSH_TIMO */ + l2cap_qos_t qos; /* L2CAP_OPT_QOS */ + l2cap_rfc_t rfc; /* L2CAP_OPT_RFC */ } l2cap_cfg_opt_val_t; /* L2CAP Disconnect Request */ -#define L2CAP_DISCONNECT_REQ 0x06 -typedef struct { - uint16_t dcid; /* destination channel ID */ - uint16_t scid; /* source channel ID */ +#define L2CAP_DISCONNECT_REQ 0x06 +typedef struct +{ + uint16_t dcid; /* destination channel ID */ + uint16_t scid; /* source channel ID */ } l2cap_discon_req_cp; /* L2CAP Disconnect Response */ -#define L2CAP_DISCONNECT_RSP 0x07 -typedef l2cap_discon_req_cp l2cap_discon_rsp_cp; +#define L2CAP_DISCONNECT_RSP 0x07 +typedef l2cap_discon_req_cp l2cap_discon_rsp_cp; /* L2CAP Echo Request */ -#define L2CAP_ECHO_REQ 0x08 +#define L2CAP_ECHO_REQ 0x08 /* No command parameters, only optional data */ /* L2CAP Echo Response */ -#define L2CAP_ECHO_RSP 0x09 -#define L2CAP_MAX_ECHO_SIZE \ - (L2CAP_MTU_MAXIMUM - sizeof(l2cap_cmd_hdr_t)) +#define L2CAP_ECHO_RSP 0x09 +#define L2CAP_MAX_ECHO_SIZE (L2CAP_MTU_MAXIMUM - sizeof(l2cap_cmd_hdr_t)) /* No command parameters, only optional data */ /* L2CAP Information Request */ -#define L2CAP_INFO_REQ 0x0a -typedef struct { - uint16_t type; /* requested information type */ +#define L2CAP_INFO_REQ 0x0a +typedef struct +{ + uint16_t type; /* requested information type */ } l2cap_info_req_cp; /* L2CAP Information Response */ -#define L2CAP_INFO_RSP 0x0b -typedef struct { - uint16_t type; /* requested information type */ - uint16_t result; /* 0x00 - success */ - /* uint8_t info[] -- info data (depends on type) - * - * L2CAP_CONNLESS_MTU - 2 bytes connectionless MTU - */ +#define L2CAP_INFO_RSP 0x0b +typedef struct +{ + uint16_t type; /* requested information type */ + uint16_t result; /* 0x00 - success */ + /* uint8_t info[] -- info data (depends on type) + * + * L2CAP_CONNLESS_MTU - 2 bytes connectionless MTU + */ } l2cap_info_rsp_cp; typedef union { - /* L2CAP_CONNLESS_MTU */ - struct { - uint16_t mtu; - } mtu; + /* L2CAP_CONNLESS_MTU */ + struct + { + uint16_t mtu; + } mtu; } l2cap_info_rsp_data_t; #pragma pack(pop) @@ -346,14 +359,14 @@ typedef union { **************************************************************************/ /* Socket options */ -#define SO_L2CAP_IMTU 1 /* incoming MTU */ -#define SO_L2CAP_OMTU 2 /* outgoing MTU */ -#define SO_L2CAP_IQOS 3 /* incoming QoS */ -#define SO_L2CAP_OQOS 4 /* outgoing QoS */ -#define SO_L2CAP_FLUSH 5 /* flush timeout */ -#define SO_L2CAP_LM 6 /* link mode */ +#define SO_L2CAP_IMTU 1 /* incoming MTU */ +#define SO_L2CAP_OMTU 2 /* outgoing MTU */ +#define SO_L2CAP_IQOS 3 /* incoming QoS */ +#define SO_L2CAP_OQOS 4 /* outgoing QoS */ +#define SO_L2CAP_FLUSH 5 /* flush timeout */ +#define SO_L2CAP_LM 6 /* link mode */ /* L2CAP link mode flags */ -#define L2CAP_LM_AUTH (1<<0) /* want authentication */ -#define L2CAP_LM_ENCRYPT (1<<1) /* want encryption */ -#define L2CAP_LM_SECURE (1<<2) /* want secured link */ +#define L2CAP_LM_AUTH (1 << 0) /* want authentication */ +#define L2CAP_LM_ENCRYPT (1 << 1) /* want encryption */ +#define L2CAP_LM_SECURE (1 << 2) /* want secured link */ diff --git a/Source/Core/Core/MachineContext.h b/Source/Core/Core/MachineContext.h index 75305f97e8..8c683121d1 100644 --- a/Source/Core/Core/MachineContext.h +++ b/Source/Core/Core/MachineContext.h @@ -8,188 +8,176 @@ // meh. #if defined(_M_GENERIC) - // JitBase uses SContext; it should have no concrete implementations in a - // generic build. - struct FakeGenericContext; - typedef FakeGenericContext SContext; +// JitBase uses SContext; it should have no concrete implementations in a +// generic build. +struct FakeGenericContext; +typedef FakeGenericContext SContext; #elif defined(_WIN32) - #include - typedef CONTEXT SContext; - #if _M_X86_64 - #define CTX_RAX Rax - #define CTX_RBX Rbx - #define CTX_RCX Rcx - #define CTX_RDX Rdx - #define CTX_RDI Rdi - #define CTX_RSI Rsi - #define CTX_RBP Rbp - #define CTX_RSP Rsp - #define CTX_R8 R8 - #define CTX_R9 R9 - #define CTX_R10 R10 - #define CTX_R11 R11 - #define CTX_R12 R12 - #define CTX_R13 R13 - #define CTX_R14 R14 - #define CTX_R15 R15 - #define CTX_RIP Rip - #else - #error No context definition for OS - #endif +#include +typedef CONTEXT SContext; +#if _M_X86_64 +#define CTX_RAX Rax +#define CTX_RBX Rbx +#define CTX_RCX Rcx +#define CTX_RDX Rdx +#define CTX_RDI Rdi +#define CTX_RSI Rsi +#define CTX_RBP Rbp +#define CTX_RSP Rsp +#define CTX_R8 R8 +#define CTX_R9 R9 +#define CTX_R10 R10 +#define CTX_R11 R11 +#define CTX_R12 R12 +#define CTX_R13 R13 +#define CTX_R14 R14 +#define CTX_R15 R15 +#define CTX_RIP Rip +#else +#error No context definition for OS +#endif #elif defined(__APPLE__) && !defined(USE_SIGACTION_ON_APPLE) - // for modules: - #define _XOPEN_SOURCE - #include +// for modules: +#define _XOPEN_SOURCE +#include - #include - #include - #if _M_X86_64 - typedef x86_thread_state64_t SContext; - #define CTX_RAX __rax - #define CTX_RBX __rbx - #define CTX_RCX __rcx - #define CTX_RDX __rdx - #define CTX_RDI __rdi - #define CTX_RSI __rsi - #define CTX_RBP __rbp - #define CTX_RSP __rsp - #define CTX_R8 __r8 - #define CTX_R9 __r9 - #define CTX_R10 __r10 - #define CTX_R11 __r11 - #define CTX_R12 __r12 - #define CTX_R13 __r13 - #define CTX_R14 __r14 - #define CTX_R15 __r15 - #define CTX_RIP __rip - #else - #error No context definition for OS - #endif +#include +#include +#if _M_X86_64 +typedef x86_thread_state64_t SContext; +#define CTX_RAX __rax +#define CTX_RBX __rbx +#define CTX_RCX __rcx +#define CTX_RDX __rdx +#define CTX_RDI __rdi +#define CTX_RSI __rsi +#define CTX_RBP __rbp +#define CTX_RSP __rsp +#define CTX_R8 __r8 +#define CTX_R9 __r9 +#define CTX_R10 __r10 +#define CTX_R11 __r11 +#define CTX_R12 __r12 +#define CTX_R13 __r13 +#define CTX_R14 __r14 +#define CTX_R15 __r15 +#define CTX_RIP __rip +#else +#error No context definition for OS +#endif #elif defined(__APPLE__) - #include - typedef _STRUCT_MCONTEXT64 SContext; - #define CTX_RAX __ss.__rax - #define CTX_RBX __ss.__rbx - #define CTX_RCX __ss.__rcx - #define CTX_RDX __ss.__rdx - #define CTX_RDI __ss.__rdi - #define CTX_RSI __ss.__rsi - #define CTX_RBP __ss.__rbp - #define CTX_RSP __ss.__rsp - #define CTX_R8 __ss.__r8 - #define CTX_R9 __ss.__r9 - #define CTX_R10 __ss.__r10 - #define CTX_R11 __ss.__r11 - #define CTX_R12 __ss.__r12 - #define CTX_R13 __ss.__r13 - #define CTX_R14 __ss.__r14 - #define CTX_R15 __ss.__r15 - #define CTX_RIP __ss.__rip +#include +typedef _STRUCT_MCONTEXT64 SContext; +#define CTX_RAX __ss.__rax +#define CTX_RBX __ss.__rbx +#define CTX_RCX __ss.__rcx +#define CTX_RDX __ss.__rdx +#define CTX_RDI __ss.__rdi +#define CTX_RSI __ss.__rsi +#define CTX_RBP __ss.__rbp +#define CTX_RSP __ss.__rsp +#define CTX_R8 __ss.__r8 +#define CTX_R9 __ss.__r9 +#define CTX_R10 __ss.__r10 +#define CTX_R11 __ss.__r11 +#define CTX_R12 __ss.__r12 +#define CTX_R13 __ss.__r13 +#define CTX_R14 __ss.__r14 +#define CTX_R15 __ss.__r15 +#define CTX_RIP __ss.__rip #elif defined(__linux__) - #include +#include - #include - typedef mcontext_t SContext; +#include +typedef mcontext_t SContext; - #if _M_X86_64 - #define CTX_RAX gregs[REG_RAX] - #define CTX_RBX gregs[REG_RBX] - #define CTX_RCX gregs[REG_RCX] - #define CTX_RDX gregs[REG_RDX] - #define CTX_RDI gregs[REG_RDI] - #define CTX_RSI gregs[REG_RSI] - #define CTX_RBP gregs[REG_RBP] - #define CTX_RSP gregs[REG_RSP] - #define CTX_R8 gregs[REG_R8] - #define CTX_R9 gregs[REG_R9] - #define CTX_R10 gregs[REG_R10] - #define CTX_R11 gregs[REG_R11] - #define CTX_R12 gregs[REG_R12] - #define CTX_R13 gregs[REG_R13] - #define CTX_R14 gregs[REG_R14] - #define CTX_R15 gregs[REG_R15] - #define CTX_RIP gregs[REG_RIP] - #elif _M_ARM_64 - #define CTX_REG(x) regs[x] - #define CTX_SP sp - #define CTX_PC pc - #else - #warning No context definition for OS - #endif +#if _M_X86_64 +#define CTX_RAX gregs[REG_RAX] +#define CTX_RBX gregs[REG_RBX] +#define CTX_RCX gregs[REG_RCX] +#define CTX_RDX gregs[REG_RDX] +#define CTX_RDI gregs[REG_RDI] +#define CTX_RSI gregs[REG_RSI] +#define CTX_RBP gregs[REG_RBP] +#define CTX_RSP gregs[REG_RSP] +#define CTX_R8 gregs[REG_R8] +#define CTX_R9 gregs[REG_R9] +#define CTX_R10 gregs[REG_R10] +#define CTX_R11 gregs[REG_R11] +#define CTX_R12 gregs[REG_R12] +#define CTX_R13 gregs[REG_R13] +#define CTX_R14 gregs[REG_R14] +#define CTX_R15 gregs[REG_R15] +#define CTX_RIP gregs[REG_RIP] +#elif _M_ARM_64 +#define CTX_REG(x) regs[x] +#define CTX_SP sp +#define CTX_PC pc +#else +#warning No context definition for OS +#endif #elif defined(__NetBSD__) - #include - typedef mcontext_t SContext; - #if _M_X86_64 - #define CTX_RAX __gregs[_REG_RAX] - #define CTX_RBX __gregs[_REG_RBX] - #define CTX_RCX __gregs[_REG_RCX] - #define CTX_RDX __gregs[_REG_RDX] - #define CTX_RDI __gregs[_REG_RDI] - #define CTX_RSI __gregs[_REG_RSI] - #define CTX_RBP __gregs[_REG_RBP] - #define CTX_RSP __gregs[_REG_RSP] - #define CTX_R8 __gregs[_REG_R8] - #define CTX_R9 __gregs[_REG_R9] - #define CTX_R10 __gregs[_REG_R10] - #define CTX_R11 __gregs[_REG_R11] - #define CTX_R12 __gregs[_REG_R12] - #define CTX_R13 __gregs[_REG_R13] - #define CTX_R14 __gregs[_REG_R14] - #define CTX_R15 __gregs[_REG_R15] - #define CTX_RIP __gregs[_REG_RIP] - #else - #error No context definition for OS - #endif +#include +typedef mcontext_t SContext; +#if _M_X86_64 +#define CTX_RAX __gregs[_REG_RAX] +#define CTX_RBX __gregs[_REG_RBX] +#define CTX_RCX __gregs[_REG_RCX] +#define CTX_RDX __gregs[_REG_RDX] +#define CTX_RDI __gregs[_REG_RDI] +#define CTX_RSI __gregs[_REG_RSI] +#define CTX_RBP __gregs[_REG_RBP] +#define CTX_RSP __gregs[_REG_RSP] +#define CTX_R8 __gregs[_REG_R8] +#define CTX_R9 __gregs[_REG_R9] +#define CTX_R10 __gregs[_REG_R10] +#define CTX_R11 __gregs[_REG_R11] +#define CTX_R12 __gregs[_REG_R12] +#define CTX_R13 __gregs[_REG_R13] +#define CTX_R14 __gregs[_REG_R14] +#define CTX_R15 __gregs[_REG_R15] +#define CTX_RIP __gregs[_REG_RIP] +#else +#error No context definition for OS +#endif #elif defined(__FreeBSD__) - #include - typedef mcontext_t SContext; - #if _M_X86_64 - #define CTX_RAX mc_rax - #define CTX_RBX mc_rbx - #define CTX_RCX mc_rcx - #define CTX_RDX mc_rdx - #define CTX_RDI mc_rdi - #define CTX_RSI mc_rsi - #define CTX_RBP mc_rbp - #define CTX_RSP mc_rsp - #define CTX_R8 mc_r8 - #define CTX_R9 mc_r9 - #define CTX_R10 mc_r10 - #define CTX_R11 mc_r11 - #define CTX_R12 mc_r12 - #define CTX_R13 mc_r13 - #define CTX_R14 mc_r14 - #define CTX_R15 mc_r15 - #define CTX_RIP mc_rip - #else - #error No context definition for OS - #endif +#include +typedef mcontext_t SContext; +#if _M_X86_64 +#define CTX_RAX mc_rax +#define CTX_RBX mc_rbx +#define CTX_RCX mc_rcx +#define CTX_RDX mc_rdx +#define CTX_RDI mc_rdi +#define CTX_RSI mc_rsi +#define CTX_RBP mc_rbp +#define CTX_RSP mc_rsp +#define CTX_R8 mc_r8 +#define CTX_R9 mc_r9 +#define CTX_R10 mc_r10 +#define CTX_R11 mc_r11 +#define CTX_R12 mc_r12 +#define CTX_R13 mc_r13 +#define CTX_R14 mc_r14 +#define CTX_R15 mc_r15 +#define CTX_RIP mc_rip +#else +#error No context definition for OS +#endif #endif #if _M_X86_64 #include #define CTX_PC CTX_RIP -static inline u64 *ContextRN(SContext* ctx, int n) +static inline u64* ContextRN(SContext* ctx, int n) { - static const u8 offsets[] = - { - offsetof(SContext, CTX_RAX), - offsetof(SContext, CTX_RCX), - offsetof(SContext, CTX_RDX), - offsetof(SContext, CTX_RBX), - offsetof(SContext, CTX_RSP), - offsetof(SContext, CTX_RBP), - offsetof(SContext, CTX_RSI), - offsetof(SContext, CTX_RDI), - offsetof(SContext, CTX_R8), - offsetof(SContext, CTX_R9), - offsetof(SContext, CTX_R10), - offsetof(SContext, CTX_R11), - offsetof(SContext, CTX_R12), - offsetof(SContext, CTX_R13), - offsetof(SContext, CTX_R14), - offsetof(SContext, CTX_R15) - }; - return (u64 *) ((char *) ctx + offsets[n]); + static const u8 offsets[] = { + offsetof(SContext, CTX_RAX), offsetof(SContext, CTX_RCX), offsetof(SContext, CTX_RDX), + offsetof(SContext, CTX_RBX), offsetof(SContext, CTX_RSP), offsetof(SContext, CTX_RBP), + offsetof(SContext, CTX_RSI), offsetof(SContext, CTX_RDI), offsetof(SContext, CTX_R8), + offsetof(SContext, CTX_R9), offsetof(SContext, CTX_R10), offsetof(SContext, CTX_R11), + offsetof(SContext, CTX_R12), offsetof(SContext, CTX_R13), offsetof(SContext, CTX_R14), + offsetof(SContext, CTX_R15)}; + return (u64*)((char*)ctx + offsets[n]); } #endif diff --git a/Source/Core/Core/MemTools.cpp b/Source/Core/Core/MemTools.cpp index 1f11fd55e4..0788e8f176 100644 --- a/Source/Core/Core/MemTools.cpp +++ b/Source/Core/Core/MemTools.cpp @@ -10,9 +10,9 @@ #include "Common/Thread.h" #include "Common/x64Analyzer.h" +#include "Core/HW/Memmap.h" #include "Core/MachineContext.h" #include "Core/MemTools.h" -#include "Core/HW/Memmap.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/PowerPC.h" #ifndef _M_GENERIC @@ -22,276 +22,292 @@ #include #endif #ifndef _WIN32 -#include // Needed for _POSIX_VERSION +#include // Needed for _POSIX_VERSION #endif namespace EMM { - #ifdef _WIN32 LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs) { - switch (pPtrs->ExceptionRecord->ExceptionCode) - { - case EXCEPTION_ACCESS_VIOLATION: - { - int accessType = (int)pPtrs->ExceptionRecord->ExceptionInformation[0]; - if (accessType == 8) //Rule out DEP - { - return (DWORD)EXCEPTION_CONTINUE_SEARCH; - } + switch (pPtrs->ExceptionRecord->ExceptionCode) + { + case EXCEPTION_ACCESS_VIOLATION: + { + int accessType = (int)pPtrs->ExceptionRecord->ExceptionInformation[0]; + if (accessType == 8) // Rule out DEP + { + return (DWORD)EXCEPTION_CONTINUE_SEARCH; + } - // virtual address of the inaccessible data - uintptr_t badAddress = (uintptr_t)pPtrs->ExceptionRecord->ExceptionInformation[1]; - CONTEXT *ctx = pPtrs->ContextRecord; + // virtual address of the inaccessible data + uintptr_t badAddress = (uintptr_t)pPtrs->ExceptionRecord->ExceptionInformation[1]; + CONTEXT* ctx = pPtrs->ContextRecord; - if (JitInterface::HandleFault(badAddress, ctx)) - { - return (DWORD)EXCEPTION_CONTINUE_EXECUTION; - } - else - { - // Let's not prevent debugging. - return (DWORD)EXCEPTION_CONTINUE_SEARCH; - } - } + if (JitInterface::HandleFault(badAddress, ctx)) + { + return (DWORD)EXCEPTION_CONTINUE_EXECUTION; + } + else + { + // Let's not prevent debugging. + return (DWORD)EXCEPTION_CONTINUE_SEARCH; + } + } - case EXCEPTION_STACK_OVERFLOW: - if (JitInterface::HandleStackFault()) - return EXCEPTION_CONTINUE_EXECUTION; - else - return EXCEPTION_CONTINUE_SEARCH; + case EXCEPTION_STACK_OVERFLOW: + if (JitInterface::HandleStackFault()) + return EXCEPTION_CONTINUE_EXECUTION; + else + return EXCEPTION_CONTINUE_SEARCH; - case EXCEPTION_ILLEGAL_INSTRUCTION: - //No SSE support? Or simply bad codegen? - return EXCEPTION_CONTINUE_SEARCH; + case EXCEPTION_ILLEGAL_INSTRUCTION: + // No SSE support? Or simply bad codegen? + return EXCEPTION_CONTINUE_SEARCH; - case EXCEPTION_PRIV_INSTRUCTION: - //okay, dynarec codegen is obviously broken. - return EXCEPTION_CONTINUE_SEARCH; + case EXCEPTION_PRIV_INSTRUCTION: + // okay, dynarec codegen is obviously broken. + return EXCEPTION_CONTINUE_SEARCH; - case EXCEPTION_IN_PAGE_ERROR: - //okay, something went seriously wrong, out of memory? - return EXCEPTION_CONTINUE_SEARCH; + case EXCEPTION_IN_PAGE_ERROR: + // okay, something went seriously wrong, out of memory? + return EXCEPTION_CONTINUE_SEARCH; - case EXCEPTION_BREAKPOINT: - //might want to do something fun with this one day? - return EXCEPTION_CONTINUE_SEARCH; + case EXCEPTION_BREAKPOINT: + // might want to do something fun with this one day? + return EXCEPTION_CONTINUE_SEARCH; - default: - return EXCEPTION_CONTINUE_SEARCH; - } + default: + return EXCEPTION_CONTINUE_SEARCH; + } } void InstallExceptionHandler() { - // Make sure this is only called once per process execution - // Instead, could make a Uninstall function, but whatever.. - static bool handlerInstalled = false; - if (handlerInstalled) - return; + // Make sure this is only called once per process execution + // Instead, could make a Uninstall function, but whatever.. + static bool handlerInstalled = false; + if (handlerInstalled) + return; - AddVectoredExceptionHandler(TRUE, Handler); - handlerInstalled = true; + AddVectoredExceptionHandler(TRUE, Handler); + handlerInstalled = true; } -void UninstallExceptionHandler() {} +void UninstallExceptionHandler() +{ +} #elif defined(__APPLE__) && !defined(USE_SIGACTION_ON_APPLE) static void CheckKR(const char* name, kern_return_t kr) { - if (kr) - { - PanicAlert("%s failed: kr=%x", name, kr); - } + if (kr) + { + PanicAlert("%s failed: kr=%x", name, kr); + } } static void ExceptionThread(mach_port_t port) { - Common::SetCurrentThreadName("Mach exception thread"); - #pragma pack(4) - struct - { - mach_msg_header_t Head; - NDR_record_t NDR; - exception_type_t exception; - mach_msg_type_number_t codeCnt; - int64_t code[2]; - int flavor; - mach_msg_type_number_t old_stateCnt; - natural_t old_state[x86_THREAD_STATE64_COUNT]; - mach_msg_trailer_t trailer; - } msg_in; + Common::SetCurrentThreadName("Mach exception thread"); +#pragma pack(4) + struct + { + mach_msg_header_t Head; + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[x86_THREAD_STATE64_COUNT]; + mach_msg_trailer_t trailer; + } msg_in; - struct - { - mach_msg_header_t Head; - NDR_record_t NDR; - kern_return_t RetCode; - int flavor; - mach_msg_type_number_t new_stateCnt; - natural_t new_state[x86_THREAD_STATE64_COUNT]; - } msg_out; - #pragma pack() - memset(&msg_in, 0xee, sizeof(msg_in)); - memset(&msg_out, 0xee, sizeof(msg_out)); - mach_msg_header_t *send_msg = nullptr; - mach_msg_size_t send_size = 0; - mach_msg_option_t option = MACH_RCV_MSG; - while (true) - { - // If this isn't the first run, send the reply message. Then, receive - // a message: either a mach_exception_raise_state RPC due to - // thread_set_exception_ports, or MACH_NOTIFY_NO_SENDERS due to - // mach_port_request_notification. - CheckKR("mach_msg_overwrite", mach_msg_overwrite(send_msg, option, send_size, sizeof(msg_in), port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, &msg_in.Head, 0)); + struct + { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[x86_THREAD_STATE64_COUNT]; + } msg_out; +#pragma pack() + memset(&msg_in, 0xee, sizeof(msg_in)); + memset(&msg_out, 0xee, sizeof(msg_out)); + mach_msg_header_t* send_msg = nullptr; + mach_msg_size_t send_size = 0; + mach_msg_option_t option = MACH_RCV_MSG; + while (true) + { + // If this isn't the first run, send the reply message. Then, receive + // a message: either a mach_exception_raise_state RPC due to + // thread_set_exception_ports, or MACH_NOTIFY_NO_SENDERS due to + // mach_port_request_notification. + CheckKR("mach_msg_overwrite", + mach_msg_overwrite(send_msg, option, send_size, sizeof(msg_in), port, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, &msg_in.Head, 0)); - if (msg_in.Head.msgh_id == MACH_NOTIFY_NO_SENDERS) - { - // the other thread exited - mach_port_destroy(mach_task_self(), port); - return; - } + if (msg_in.Head.msgh_id == MACH_NOTIFY_NO_SENDERS) + { + // the other thread exited + mach_port_destroy(mach_task_self(), port); + return; + } - if (msg_in.Head.msgh_id != 2406) - { - PanicAlert("unknown message received"); - return; - } + if (msg_in.Head.msgh_id != 2406) + { + PanicAlert("unknown message received"); + return; + } - if (msg_in.flavor != x86_THREAD_STATE64) - { - PanicAlert("unknown flavor %d (expected %d)", msg_in.flavor, x86_THREAD_STATE64); - return; - } + if (msg_in.flavor != x86_THREAD_STATE64) + { + PanicAlert("unknown flavor %d (expected %d)", msg_in.flavor, x86_THREAD_STATE64); + return; + } - x86_thread_state64_t *state = (x86_thread_state64_t *) msg_in.old_state; + x86_thread_state64_t* state = (x86_thread_state64_t*)msg_in.old_state; - bool ok = JitInterface::HandleFault((uintptr_t) msg_in.code[1], state); + bool ok = JitInterface::HandleFault((uintptr_t)msg_in.code[1], state); - // Set up the reply. - msg_out.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(msg_in.Head.msgh_bits), 0); - msg_out.Head.msgh_remote_port = msg_in.Head.msgh_remote_port; - msg_out.Head.msgh_local_port = MACH_PORT_NULL; - msg_out.Head.msgh_id = msg_in.Head.msgh_id + 100; - msg_out.NDR = msg_in.NDR; - if (ok) - { - msg_out.RetCode = KERN_SUCCESS; - msg_out.flavor = x86_THREAD_STATE64; - msg_out.new_stateCnt = x86_THREAD_STATE64_COUNT; - memcpy(msg_out.new_state, msg_in.old_state, x86_THREAD_STATE64_COUNT * sizeof(natural_t)); - } - else - { - // Pass the exception to the next handler (debugger or crash). - msg_out.RetCode = KERN_FAILURE; - msg_out.flavor = 0; - msg_out.new_stateCnt = 0; - } - msg_out.Head.msgh_size = offsetof(__typeof__(msg_out), new_state) + msg_out.new_stateCnt * sizeof(natural_t); + // Set up the reply. + msg_out.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(msg_in.Head.msgh_bits), 0); + msg_out.Head.msgh_remote_port = msg_in.Head.msgh_remote_port; + msg_out.Head.msgh_local_port = MACH_PORT_NULL; + msg_out.Head.msgh_id = msg_in.Head.msgh_id + 100; + msg_out.NDR = msg_in.NDR; + if (ok) + { + msg_out.RetCode = KERN_SUCCESS; + msg_out.flavor = x86_THREAD_STATE64; + msg_out.new_stateCnt = x86_THREAD_STATE64_COUNT; + memcpy(msg_out.new_state, msg_in.old_state, x86_THREAD_STATE64_COUNT * sizeof(natural_t)); + } + else + { + // Pass the exception to the next handler (debugger or crash). + msg_out.RetCode = KERN_FAILURE; + msg_out.flavor = 0; + msg_out.new_stateCnt = 0; + } + msg_out.Head.msgh_size = + offsetof(__typeof__(msg_out), new_state) + msg_out.new_stateCnt * sizeof(natural_t); - send_msg = &msg_out.Head; - send_size = msg_out.Head.msgh_size; - option |= MACH_SEND_MSG; - } + send_msg = &msg_out.Head; + send_size = msg_out.Head.msgh_size; + option |= MACH_SEND_MSG; + } } void InstallExceptionHandler() { - mach_port_t port; - CheckKR("mach_port_allocate", mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port)); - std::thread exc_thread(ExceptionThread, port); - exc_thread.detach(); - // Obtain a send right for thread_set_exception_ports to copy... - CheckKR("mach_port_insert_right", mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)); - // Mach tries the following exception ports in order: thread, task, host. - // Debuggers set the task port, so we grab the thread port. - CheckKR("thread_set_exception_ports", thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, port, EXCEPTION_STATE | MACH_EXCEPTION_CODES, x86_THREAD_STATE64)); - // ...and get rid of our copy so that MACH_NOTIFY_NO_SENDERS works. - CheckKR("mach_port_mod_refs", mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, -1)); - mach_port_t previous; - CheckKR("mach_port_request_notification", mach_port_request_notification(mach_task_self(), port, MACH_NOTIFY_NO_SENDERS, 0, port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous)); + mach_port_t port; + CheckKR("mach_port_allocate", + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port)); + std::thread exc_thread(ExceptionThread, port); + exc_thread.detach(); + // Obtain a send right for thread_set_exception_ports to copy... + CheckKR("mach_port_insert_right", + mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)); + // Mach tries the following exception ports in order: thread, task, host. + // Debuggers set the task port, so we grab the thread port. + CheckKR("thread_set_exception_ports", + thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, port, + EXCEPTION_STATE | MACH_EXCEPTION_CODES, x86_THREAD_STATE64)); + // ...and get rid of our copy so that MACH_NOTIFY_NO_SENDERS works. + CheckKR("mach_port_mod_refs", + mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, -1)); + mach_port_t previous; + CheckKR("mach_port_request_notification", + mach_port_request_notification(mach_task_self(), port, MACH_NOTIFY_NO_SENDERS, 0, port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous)); } -void UninstallExceptionHandler() {} +void UninstallExceptionHandler() +{ +} #elif defined(_POSIX_VERSION) && !defined(_M_GENERIC) -static void sigsegv_handler(int sig, siginfo_t *info, void *raw_context) +static void sigsegv_handler(int sig, siginfo_t* info, void* raw_context) { - if (sig != SIGSEGV && sig != SIGBUS) - { - // We are not interested in other signals - handle it as usual. - return; - } - ucontext_t *context = (ucontext_t *)raw_context; - int sicode = info->si_code; - if (sicode != SEGV_MAPERR && sicode != SEGV_ACCERR) - { - // Huh? Return. - return; - } - uintptr_t bad_address = (uintptr_t)info->si_addr; + if (sig != SIGSEGV && sig != SIGBUS) + { + // We are not interested in other signals - handle it as usual. + return; + } + ucontext_t* context = (ucontext_t*)raw_context; + int sicode = info->si_code; + if (sicode != SEGV_MAPERR && sicode != SEGV_ACCERR) + { + // Huh? Return. + return; + } + uintptr_t bad_address = (uintptr_t)info->si_addr; - // Get all the information we can out of the context. - mcontext_t *ctx = &context->uc_mcontext; - // assume it's not a write - if (!JitInterface::HandleFault(bad_address, + // Get all the information we can out of the context. + mcontext_t* ctx = &context->uc_mcontext; + // assume it's not a write + if (!JitInterface::HandleFault(bad_address, #ifdef __APPLE__ - *ctx + *ctx #else - ctx + ctx #endif - )) - { - // retry and crash - signal(SIGSEGV, SIG_DFL); + )) + { + // retry and crash + signal(SIGSEGV, SIG_DFL); #ifdef __APPLE__ - signal(SIGBUS, SIG_DFL); + signal(SIGBUS, SIG_DFL); #endif - } + } } void InstallExceptionHandler() { - stack_t signal_stack; + stack_t signal_stack; #ifdef __FreeBSD__ - signal_stack.ss_sp = (char*)malloc(SIGSTKSZ); + signal_stack.ss_sp = (char*)malloc(SIGSTKSZ); #else - signal_stack.ss_sp = malloc(SIGSTKSZ); + signal_stack.ss_sp = malloc(SIGSTKSZ); #endif - signal_stack.ss_size = SIGSTKSZ; - signal_stack.ss_flags = 0; - if (sigaltstack(&signal_stack, nullptr)) - PanicAlert("sigaltstack failed"); - struct sigaction sa; - sa.sa_handler = nullptr; - sa.sa_sigaction = &sigsegv_handler; - sa.sa_flags = SA_SIGINFO; - sigemptyset(&sa.sa_mask); - sigaction(SIGSEGV, &sa, nullptr); + signal_stack.ss_size = SIGSTKSZ; + signal_stack.ss_flags = 0; + if (sigaltstack(&signal_stack, nullptr)) + PanicAlert("sigaltstack failed"); + struct sigaction sa; + sa.sa_handler = nullptr; + sa.sa_sigaction = &sigsegv_handler; + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + sigaction(SIGSEGV, &sa, nullptr); #ifdef __APPLE__ - sigaction(SIGBUS, &sa, nullptr); + sigaction(SIGBUS, &sa, nullptr); #endif } void UninstallExceptionHandler() { - stack_t signal_stack, old_stack; - signal_stack.ss_flags = SS_DISABLE; - if (!sigaltstack(&signal_stack, &old_stack) && - !(old_stack.ss_flags & SS_DISABLE)) - { - free(old_stack.ss_sp); - } + stack_t signal_stack, old_stack; + signal_stack.ss_flags = SS_DISABLE; + if (!sigaltstack(&signal_stack, &old_stack) && !(old_stack.ss_flags & SS_DISABLE)) + { + free(old_stack.ss_sp); + } } -#else // _M_GENERIC or unsupported platform +#else // _M_GENERIC or unsupported platform -void InstallExceptionHandler() {} -void UninstallExceptionHandler() {} +void InstallExceptionHandler() +{ +} +void UninstallExceptionHandler() +{ +} #endif diff --git a/Source/Core/Core/MemTools.h b/Source/Core/Core/MemTools.h index 6786d847e7..b9258eb0a9 100644 --- a/Source/Core/Core/MemTools.h +++ b/Source/Core/Core/MemTools.h @@ -6,8 +6,6 @@ namespace EMM { - void InstallExceptionHandler(); void UninstallExceptionHandler(); - } diff --git a/Source/Core/Core/MemoryWatcher.cpp b/Source/Core/Core/MemoryWatcher.cpp index 66f0eef2b7..76ff2d9538 100644 --- a/Source/Core/Core/MemoryWatcher.cpp +++ b/Source/Core/Core/MemoryWatcher.cpp @@ -10,126 +10,120 @@ #include "Common/FileUtil.h" #include "Core/CoreTiming.h" -#include "Core/MemoryWatcher.h" #include "Core/HW/Memmap.h" #include "Core/HW/SystemTimers.h" +#include "Core/MemoryWatcher.h" static std::unique_ptr s_memory_watcher; static int s_event; -static const int MW_RATE = 600; // Steps per second +static const int MW_RATE = 600; // Steps per second static void MWCallback(u64 userdata, s64 cyclesLate) { - s_memory_watcher->Step(); - CoreTiming::ScheduleEvent( - (SystemTimers::GetTicksPerSecond() / MW_RATE) - cyclesLate, s_event); + s_memory_watcher->Step(); + CoreTiming::ScheduleEvent((SystemTimers::GetTicksPerSecond() / MW_RATE) - cyclesLate, s_event); } void MemoryWatcher::Init() { - s_memory_watcher = std::make_unique(); - s_event = CoreTiming::RegisterEvent("MemoryWatcher", MWCallback); - CoreTiming::ScheduleEvent(0, s_event); + s_memory_watcher = std::make_unique(); + s_event = CoreTiming::RegisterEvent("MemoryWatcher", MWCallback); + CoreTiming::ScheduleEvent(0, s_event); } void MemoryWatcher::Shutdown() { - CoreTiming::RemoveEvent(s_event); - s_memory_watcher.reset(); + CoreTiming::RemoveEvent(s_event); + s_memory_watcher.reset(); } MemoryWatcher::MemoryWatcher() { - m_running = false; - if (!LoadAddresses(File::GetUserPath(F_MEMORYWATCHERLOCATIONS_IDX))) - return; - if (!OpenSocket(File::GetUserPath(F_MEMORYWATCHERSOCKET_IDX))) - return; - m_running = true; + m_running = false; + if (!LoadAddresses(File::GetUserPath(F_MEMORYWATCHERLOCATIONS_IDX))) + return; + if (!OpenSocket(File::GetUserPath(F_MEMORYWATCHERSOCKET_IDX))) + return; + m_running = true; } MemoryWatcher::~MemoryWatcher() { - if (!m_running) - return; + if (!m_running) + return; - m_running = false; - close(m_fd); + m_running = false; + close(m_fd); } bool MemoryWatcher::LoadAddresses(const std::string& path) { - std::ifstream locations(path); - if (!locations) - return false; + std::ifstream locations(path); + if (!locations) + return false; - std::string line; - while (std::getline(locations, line)) - ParseLine(line); + std::string line; + while (std::getline(locations, line)) + ParseLine(line); - return m_values.size() > 0; + return m_values.size() > 0; } void MemoryWatcher::ParseLine(const std::string& line) { - m_values[line] = 0; - m_addresses[line] = std::vector(); + m_values[line] = 0; + m_addresses[line] = std::vector(); - std::stringstream offsets(line); - offsets >> std::hex; - u32 offset; - while (offsets >> offset) - m_addresses[line].push_back(offset); + std::stringstream offsets(line); + offsets >> std::hex; + u32 offset; + while (offsets >> offset) + m_addresses[line].push_back(offset); } bool MemoryWatcher::OpenSocket(const std::string& path) { - memset(&m_addr, 0, sizeof(m_addr)); - m_addr.sun_family = AF_UNIX; - strncpy(m_addr.sun_path, path.c_str(), sizeof(m_addr.sun_path) - 1); + memset(&m_addr, 0, sizeof(m_addr)); + m_addr.sun_family = AF_UNIX; + strncpy(m_addr.sun_path, path.c_str(), sizeof(m_addr.sun_path) - 1); - m_fd = socket(AF_UNIX, SOCK_DGRAM, 0); - return m_fd >= 0; + m_fd = socket(AF_UNIX, SOCK_DGRAM, 0); + return m_fd >= 0; } u32 MemoryWatcher::ChasePointer(const std::string& line) { - u32 value = 0; - for (u32 offset : m_addresses[line]) - value = Memory::Read_U32(value + offset); - return value; + u32 value = 0; + for (u32 offset : m_addresses[line]) + value = Memory::Read_U32(value + offset); + return value; } std::string MemoryWatcher::ComposeMessage(const std::string& line, u32 value) { - std::stringstream message_stream; - message_stream << line << '\n' << std::hex << value; - return message_stream.str(); + std::stringstream message_stream; + message_stream << line << '\n' << std::hex << value; + return message_stream.str(); } void MemoryWatcher::Step() { - if (!m_running) - return; + if (!m_running) + return; - for (auto& entry : m_values) - { - std::string address = entry.first; - u32& current_value = entry.second; + for (auto& entry : m_values) + { + std::string address = entry.first; + u32& current_value = entry.second; - u32 new_value = ChasePointer(address); - if (new_value != current_value) - { - // Update the value - current_value = new_value; - std::string message = ComposeMessage(address, new_value); - sendto( - m_fd, - message.c_str(), - message.size() + 1, - 0, - reinterpret_cast(&m_addr), - sizeof(m_addr)); - } - } + u32 new_value = ChasePointer(address); + if (new_value != current_value) + { + // Update the value + current_value = new_value; + std::string message = ComposeMessage(address, new_value); + sendto(m_fd, message.c_str(), message.size() + 1, 0, reinterpret_cast(&m_addr), + sizeof(m_addr)); + } + } } diff --git a/Source/Core/Core/MemoryWatcher.h b/Source/Core/Core/MemoryWatcher.h index 7ea38ff354..e2dc4790bc 100644 --- a/Source/Core/Core/MemoryWatcher.h +++ b/Source/Core/Core/MemoryWatcher.h @@ -5,9 +5,9 @@ #pragma once #include -#include #include #include +#include // MemoryWatcher reads a file containing in-game memory addresses and outputs // changes to those memory addresses to a unix domain socket as the game runs. @@ -20,28 +20,28 @@ class MemoryWatcher final { public: - MemoryWatcher(); - ~MemoryWatcher(); - void Step(); + MemoryWatcher(); + ~MemoryWatcher(); + void Step(); - static void Init(); - static void Shutdown(); + static void Init(); + static void Shutdown(); private: - bool LoadAddresses(const std::string& path); - bool OpenSocket(const std::string& path); + bool LoadAddresses(const std::string& path); + bool OpenSocket(const std::string& path); - void ParseLine(const std::string& line); - u32 ChasePointer(const std::string& line); - std::string ComposeMessage(const std::string& line, u32 value); + void ParseLine(const std::string& line); + u32 ChasePointer(const std::string& line); + std::string ComposeMessage(const std::string& line, u32 value); - bool m_running; + bool m_running; - int m_fd; - sockaddr_un m_addr; + int m_fd; + sockaddr_un m_addr; - // Address as stored in the file -> list of offsets to follow - std::map> m_addresses; - // Address as stored in the file -> current value - std::map m_values; + // Address as stored in the file -> list of offsets to follow + std::map> m_addresses; + // Address as stored in the file -> current value + std::map m_values; }; diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index 8cca59fd4c..3ebed8b7ef 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -5,9 +5,9 @@ #include #include #include -#include #include #include +#include #include "Common/ChunkFile.h" #include "Common/CommonPaths.h" @@ -19,10 +19,6 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" -#include "Core/Movie.h" -#include "Core/NetPlayClient.h" -#include "Core/NetPlayProto.h" -#include "Core/State.h" #include "Core/DSP/DSPCore.h" #include "Core/HW/CPU.h" #include "Core/HW/DVDInterface.h" @@ -34,7 +30,11 @@ #include "Core/HW/WiimoteEmu/WiimoteHid.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" #include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h" +#include "Core/Movie.h" +#include "Core/NetPlayClient.h" +#include "Core/NetPlayProto.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/State.h" #include "InputCommon/GCPadStatus.h" #include "VideoCommon/Fifo.h" #include "VideoCommon/VideoBackendBase.h" @@ -45,8 +45,8 @@ static std::mutex cs_frameSkip; -namespace Movie { - +namespace Movie +{ static bool s_bFrameStep = false; static bool s_bReadOnly = true; static u32 s_rerecords = 0; @@ -60,12 +60,12 @@ static DTMHeader tmpHeader; static u8* tmpInput = nullptr; static size_t tmpInputAllocated = 0; static u64 s_currentByte = 0, s_totalBytes = 0; -u64 g_currentFrame = 0, g_totalFrames = 0; // VI +u64 g_currentFrame = 0, g_totalFrames = 0; // VI u64 g_currentLagCount = 0; -static u64 s_totalLagCount = 0; // just stats -u64 g_currentInputCount = 0, g_totalInputCount = 0; // just stats -static u64 s_totalTickCount = 0, s_tickCountAtLastInput = 0; // just stats -static u64 s_recordingStartTime; // seconds since 1970 that recording started +static u64 s_totalLagCount = 0; // just stats +u64 g_currentInputCount = 0, g_totalInputCount = 0; // just stats +static u64 s_totalTickCount = 0, s_tickCountAtLastInput = 0; // just stats +static u64 s_recordingStartTime; // seconds since 1970 that recording started static bool s_bSaveConfig = false, s_bSkipIdle = false, s_bDualCore = false; static bool s_bProgressive = false, s_bPAL60 = false; static bool s_bDSPHLE = false, s_bFastDiscSpeed = false; @@ -83,13 +83,13 @@ static u8 s_bongos, s_memcards; static u8 s_revision[20]; static u32 s_DSPiromHash = 0; static u32 s_DSPcoefHash = 0; -static u8 s_language = 10; //Set to unknown until language is known +static u8 s_language = 10; // Set to unknown until language is known static bool s_bRecordingFromSaveState = false; static bool s_bPolled = false; // s_InputDisplay is used by both CPU and GPU (is mutable). -static std::mutex s_input_display_lock; +static std::mutex s_input_display_lock; static std::string s_InputDisplay[8]; static GCManipFunction gcmfunc = nullptr; @@ -98,113 +98,110 @@ static WiiManipFunction wiimfunc = nullptr; // NOTE: Host / CPU Thread static void EnsureTmpInputSize(size_t bound) { - if (tmpInputAllocated >= bound) - return; - // The buffer expands in powers of two of DTM_BASE_LENGTH - // (standard exponential buffer growth). - size_t newAlloc = DTM_BASE_LENGTH; - while (newAlloc < bound) - newAlloc *= 2; + if (tmpInputAllocated >= bound) + return; + // The buffer expands in powers of two of DTM_BASE_LENGTH + // (standard exponential buffer growth). + size_t newAlloc = DTM_BASE_LENGTH; + while (newAlloc < bound) + newAlloc *= 2; - u8* newTmpInput = new u8[newAlloc]; - tmpInputAllocated = newAlloc; - if (tmpInput != nullptr) - { - if (s_totalBytes > 0) - memcpy(newTmpInput, tmpInput, (size_t)s_totalBytes); - delete[] tmpInput; - } - tmpInput = newTmpInput; + u8* newTmpInput = new u8[newAlloc]; + tmpInputAllocated = newAlloc; + if (tmpInput != nullptr) + { + if (s_totalBytes > 0) + memcpy(newTmpInput, tmpInput, (size_t)s_totalBytes); + delete[] tmpInput; + } + tmpInput = newTmpInput; } static bool IsMovieHeader(u8 magic[4]) { - return magic[0] == 'D' && - magic[1] == 'T' && - magic[2] == 'M' && - magic[3] == 0x1A; + return magic[0] == 'D' && magic[1] == 'T' && magic[2] == 'M' && magic[3] == 0x1A; } static std::array ConvertGitRevisionToBytes(const std::string& revision) { - std::array revision_bytes{}; + std::array revision_bytes{}; - if (revision.size() % 2 == 0 && std::all_of(revision.begin(), revision.end(), ::isxdigit)) - { - // The revision string normally contains a git commit hash, - // which is 40 hexadecimal digits long. In DTM files, each pair of - // hexadecimal digits is stored as one byte, for a total of 20 bytes. - size_t bytes_to_write = std::min(revision.size() / 2, revision_bytes.size()); - unsigned int temp; - for (size_t i = 0; i < bytes_to_write; ++i) - { - sscanf(&revision[2 * i], "%02x", &temp); - revision_bytes[i] = temp; - } - } - else - { - // If the revision string for some reason doesn't only contain hexadecimal digit - // pairs, we instead copy the string with no conversion. This probably doesn't match - // the intended design of the DTM format, but it's the most sensible fallback. - size_t bytes_to_write = std::min(revision.size(), revision_bytes.size()); - std::copy_n(std::begin(revision), bytes_to_write, std::begin(revision_bytes)); - } + if (revision.size() % 2 == 0 && std::all_of(revision.begin(), revision.end(), ::isxdigit)) + { + // The revision string normally contains a git commit hash, + // which is 40 hexadecimal digits long. In DTM files, each pair of + // hexadecimal digits is stored as one byte, for a total of 20 bytes. + size_t bytes_to_write = std::min(revision.size() / 2, revision_bytes.size()); + unsigned int temp; + for (size_t i = 0; i < bytes_to_write; ++i) + { + sscanf(&revision[2 * i], "%02x", &temp); + revision_bytes[i] = temp; + } + } + else + { + // If the revision string for some reason doesn't only contain hexadecimal digit + // pairs, we instead copy the string with no conversion. This probably doesn't match + // the intended design of the DTM format, but it's the most sensible fallback. + size_t bytes_to_write = std::min(revision.size(), revision_bytes.size()); + std::copy_n(std::begin(revision), bytes_to_write, std::begin(revision_bytes)); + } - return revision_bytes; + return revision_bytes; } // NOTE: GPU Thread std::string GetInputDisplay() { - if (!IsMovieActive()) - { - s_numPads = 0; - for (int i = 0; i < 4; ++i) - { - if (SerialInterface::GetDeviceType(i) != SIDEVICE_NONE) - s_numPads |= (1 << i); - if (g_wiimote_sources[i] != WIIMOTE_SRC_NONE) - s_numPads |= (1 << (i + 4)); - } - } + if (!IsMovieActive()) + { + s_numPads = 0; + for (int i = 0; i < 4; ++i) + { + if (SerialInterface::GetDeviceType(i) != SIDEVICE_NONE) + s_numPads |= (1 << i); + if (g_wiimote_sources[i] != WIIMOTE_SRC_NONE) + s_numPads |= (1 << (i + 4)); + } + } - std::string input_display; - { - std::lock_guard guard(s_input_display_lock); - for (int i = 0; i < 8; ++i) - { - if ((s_numPads & (1 << i)) != 0) - input_display += s_InputDisplay[i]; - } - } - return input_display; + std::string input_display; + { + std::lock_guard guard(s_input_display_lock); + for (int i = 0; i < 8; ++i) + { + if ((s_numPads & (1 << i)) != 0) + input_display += s_InputDisplay[i]; + } + } + return input_display; } // NOTE: GPU Thread void FrameUpdate() { - // TODO[comex]: This runs on the GPU thread, yet it messes with the CPU - // state directly. That's super sketchy. - g_currentFrame++; - if (!s_bPolled) - g_currentLagCount++; + // TODO[comex]: This runs on the GPU thread, yet it messes with the CPU + // state directly. That's super sketchy. + g_currentFrame++; + if (!s_bPolled) + g_currentLagCount++; - if (IsRecordingInput()) - { - g_totalFrames = g_currentFrame; - s_totalLagCount = g_currentLagCount; - } - if (s_bFrameStep) - { - s_bFrameStep = false; - CPU::Break(); - } + if (IsRecordingInput()) + { + g_totalFrames = g_currentFrame; + s_totalLagCount = g_currentLagCount; + } + if (s_bFrameStep) + { + s_bFrameStep = false; + CPU::Break(); + } - if (s_framesToSkip) - FrameSkipping(); + if (s_framesToSkip) + FrameSkipping(); - s_bPolled = false; + s_bPolled = false; } // called when game is booting up, even if no movie is active, @@ -212,1249 +209,1292 @@ void FrameUpdate() // NOTE: EmuThread void Init() { - s_bPolled = false; - s_bFrameStep = false; - s_bSaveConfig = false; - s_iCPUCore = SConfig::GetInstance().iCPUCore; - if (IsPlayingInput()) - { - ReadHeader(); - std::thread md5thread(CheckMD5); - md5thread.detach(); - if (strncmp(tmpHeader.gameID, SConfig::GetInstance().GetUniqueID().c_str(), 6)) - { - PanicAlertT("The recorded game (%s) is not the same as the selected game (%s)", tmpHeader.gameID, SConfig::GetInstance().GetUniqueID().c_str()); - EndPlayInput(false); - } - } + s_bPolled = false; + s_bFrameStep = false; + s_bSaveConfig = false; + s_iCPUCore = SConfig::GetInstance().iCPUCore; + if (IsPlayingInput()) + { + ReadHeader(); + std::thread md5thread(CheckMD5); + md5thread.detach(); + if (strncmp(tmpHeader.gameID, SConfig::GetInstance().GetUniqueID().c_str(), 6)) + { + PanicAlertT("The recorded game (%s) is not the same as the selected game (%s)", + tmpHeader.gameID, SConfig::GetInstance().GetUniqueID().c_str()); + EndPlayInput(false); + } + } - if (IsRecordingInput()) - { - GetSettings(); - std::thread md5thread(GetMD5); - md5thread.detach(); - s_tickCountAtLastInput = 0; - } + if (IsRecordingInput()) + { + GetSettings(); + std::thread md5thread(GetMD5); + md5thread.detach(); + s_tickCountAtLastInput = 0; + } - s_frameSkipCounter = s_framesToSkip; - memset(&s_padState, 0, sizeof(s_padState)); - if (!tmpHeader.bFromSaveState || !IsPlayingInput()) - Core::SetStateFileName(""); + s_frameSkipCounter = s_framesToSkip; + memset(&s_padState, 0, sizeof(s_padState)); + if (!tmpHeader.bFromSaveState || !IsPlayingInput()) + Core::SetStateFileName(""); - for (auto& disp : s_InputDisplay) - disp.clear(); + for (auto& disp : s_InputDisplay) + disp.clear(); - if (!IsMovieActive()) - { - s_bRecordingFromSaveState = false; - s_rerecords = 0; - s_currentByte = 0; - g_currentFrame = 0; - g_currentLagCount = 0; - g_currentInputCount = 0; - } + if (!IsMovieActive()) + { + s_bRecordingFromSaveState = false; + s_rerecords = 0; + s_currentByte = 0; + g_currentFrame = 0; + g_currentLagCount = 0; + g_currentInputCount = 0; + } } // NOTE: CPU Thread void InputUpdate() { - g_currentInputCount++; - if (IsRecordingInput()) - { - g_totalInputCount = g_currentInputCount; - s_totalTickCount += CoreTiming::GetTicks() - s_tickCountAtLastInput; - s_tickCountAtLastInput = CoreTiming::GetTicks(); - } + g_currentInputCount++; + if (IsRecordingInput()) + { + g_totalInputCount = g_currentInputCount; + s_totalTickCount += CoreTiming::GetTicks() - s_tickCountAtLastInput; + s_tickCountAtLastInput = CoreTiming::GetTicks(); + } } // NOTE: Host Thread void SetFrameSkipping(unsigned int framesToSkip) { - std::lock_guard lk(cs_frameSkip); + std::lock_guard lk(cs_frameSkip); - s_framesToSkip = framesToSkip; - s_frameSkipCounter = 0; + s_framesToSkip = framesToSkip; + s_frameSkipCounter = 0; - // Don't forget to re-enable rendering in case it wasn't... - // as this won't be changed anymore when frameskip is turned off - if (framesToSkip == 0) - Fifo::SetRendering(true); + // Don't forget to re-enable rendering in case it wasn't... + // as this won't be changed anymore when frameskip is turned off + if (framesToSkip == 0) + Fifo::SetRendering(true); } // NOTE: CPU Thread void SetPolledDevice() { - s_bPolled = true; + s_bPolled = true; } // NOTE: Host Thread void DoFrameStep() { - if (Core::GetState() == Core::CORE_PAUSE) - { - // if already paused, frame advance for 1 frame - s_bFrameStep = true; - Core::RequestRefreshInfo(); - Core::SetState(Core::CORE_RUN); - } - else if (!s_bFrameStep) - { - // if not paused yet, pause immediately instead - Core::SetState(Core::CORE_PAUSE); - } + if (Core::GetState() == Core::CORE_PAUSE) + { + // if already paused, frame advance for 1 frame + s_bFrameStep = true; + Core::RequestRefreshInfo(); + Core::SetState(Core::CORE_RUN); + } + else if (!s_bFrameStep) + { + // if not paused yet, pause immediately instead + Core::SetState(Core::CORE_PAUSE); + } } // NOTE: Host Thread void SetReadOnly(bool bEnabled) { - if (s_bReadOnly != bEnabled) - Core::DisplayMessage(bEnabled ? "Read-only mode." : "Read+Write mode.", 1000); + if (s_bReadOnly != bEnabled) + Core::DisplayMessage(bEnabled ? "Read-only mode." : "Read+Write mode.", 1000); - s_bReadOnly = bEnabled; + s_bReadOnly = bEnabled; } // NOTE: GPU Thread void FrameSkipping() { - // Frameskipping will desync movie playback - if (!IsMovieActive() || NetPlay::IsNetPlayRunning()) - { - std::lock_guard lk(cs_frameSkip); + // Frameskipping will desync movie playback + if (!IsMovieActive() || NetPlay::IsNetPlayRunning()) + { + std::lock_guard lk(cs_frameSkip); - s_frameSkipCounter++; - if (s_frameSkipCounter > s_framesToSkip || Core::ShouldSkipFrame(s_frameSkipCounter) == false) - s_frameSkipCounter = 0; + s_frameSkipCounter++; + if (s_frameSkipCounter > s_framesToSkip || Core::ShouldSkipFrame(s_frameSkipCounter) == false) + s_frameSkipCounter = 0; - Fifo::SetRendering(!s_frameSkipCounter); - } + Fifo::SetRendering(!s_frameSkipCounter); + } } bool IsRecordingInput() { - return (s_playMode == MODE_RECORDING); + return (s_playMode == MODE_RECORDING); } bool IsRecordingInputFromSaveState() { - return s_bRecordingFromSaveState; + return s_bRecordingFromSaveState; } bool IsJustStartingRecordingInputFromSaveState() { - return IsRecordingInputFromSaveState() && g_currentFrame == 0; + return IsRecordingInputFromSaveState() && g_currentFrame == 0; } bool IsJustStartingPlayingInputFromSaveState() { - return IsRecordingInputFromSaveState() && g_currentFrame == 1 && IsPlayingInput(); + return IsRecordingInputFromSaveState() && g_currentFrame == 1 && IsPlayingInput(); } bool IsPlayingInput() { - return (s_playMode == MODE_PLAYING); + return (s_playMode == MODE_PLAYING); } bool IsMovieActive() { - return s_playMode != MODE_NONE; + return s_playMode != MODE_NONE; } bool IsReadOnly() { - return s_bReadOnly; + return s_bReadOnly; } u64 GetRecordingStartTime() { - return s_recordingStartTime; + return s_recordingStartTime; } bool IsUsingPad(int controller) { - return ((s_numPads & (1 << controller)) != 0); + return ((s_numPads & (1 << controller)) != 0); } bool IsUsingBongo(int controller) { - return ((s_bongos & (1 << controller)) != 0); + return ((s_bongos & (1 << controller)) != 0); } bool IsUsingWiimote(int wiimote) { - return ((s_numPads & (1 << (wiimote + 4))) != 0); + return ((s_numPads & (1 << (wiimote + 4))) != 0); } bool IsConfigSaved() { - return s_bSaveConfig; + return s_bSaveConfig; } bool IsDualCore() { - return s_bDualCore; + return s_bDualCore; } bool IsProgressive() { - return s_bProgressive; + return s_bProgressive; } bool IsPAL60() { - return s_bPAL60; + return s_bPAL60; } bool IsSkipIdle() { - return s_bSkipIdle; + return s_bSkipIdle; } bool IsDSPHLE() { - return s_bDSPHLE; + return s_bDSPHLE; } bool IsFastDiscSpeed() { - return s_bFastDiscSpeed; + return s_bFastDiscSpeed; } int GetCPUMode() { - return s_iCPUCore; + return s_iCPUCore; } u8 GetLanguage() { - return s_language; + return s_language; } bool IsStartingFromClearSave() { - return g_bClearSave; + return g_bClearSave; } bool IsUsingMemcard(int memcard) { - return (s_memcards & (1 << memcard)) != 0; + return (s_memcards & (1 << memcard)) != 0; } bool IsSyncGPU() { - return s_bSyncGPU; + return s_bSyncGPU; } bool IsNetPlayRecording() { - return s_bNetPlay; + return s_bNetPlay; } // NOTE: Host Thread void ChangePads(bool instantly) { - if (!Core::IsRunning()) - return; + if (!Core::IsRunning()) + return; - int controllers = 0; + int controllers = 0; - for (int i = 0; i < MAX_SI_CHANNELS; ++i) - if (SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i])) - controllers |= (1 << i); + for (int i = 0; i < MAX_SI_CHANNELS; ++i) + if (SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i])) + controllers |= (1 << i); - if (instantly && (s_numPads & 0x0F) == controllers) - return; + if (instantly && (s_numPads & 0x0F) == controllers) + return; - for (int i = 0; i < MAX_SI_CHANNELS; ++i) - { - SIDevices device = SIDEVICE_NONE; - if (IsUsingPad(i)) - { - if (SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i])) - device = SConfig::GetInstance().m_SIDevice[i]; - else - device = IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER; - } + for (int i = 0; i < MAX_SI_CHANNELS; ++i) + { + SIDevices device = SIDEVICE_NONE; + if (IsUsingPad(i)) + { + if (SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i])) + device = SConfig::GetInstance().m_SIDevice[i]; + else + device = IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER; + } - if (instantly) // Changes from savestates need to be instantaneous - SerialInterface::AddDevice(device, i); - else - SerialInterface::ChangeDevice(device, i); - } + if (instantly) // Changes from savestates need to be instantaneous + SerialInterface::AddDevice(device, i); + else + SerialInterface::ChangeDevice(device, i); + } } // NOTE: Host / Emu Threads void ChangeWiiPads(bool instantly) { - int controllers = 0; + int controllers = 0; - for (int i = 0; i < MAX_WIIMOTES; ++i) - if (g_wiimote_sources[i] != WIIMOTE_SRC_NONE) - controllers |= (1 << i); + for (int i = 0; i < MAX_WIIMOTES; ++i) + if (g_wiimote_sources[i] != WIIMOTE_SRC_NONE) + controllers |= (1 << i); - // This is important for Wiimotes, because they can desync easily if they get re-activated - if (instantly && (s_numPads >> 4) == controllers) - return; + // This is important for Wiimotes, because they can desync easily if they get re-activated + if (instantly && (s_numPads >> 4) == controllers) + return; - for (int i = 0; i < MAX_WIIMOTES; ++i) - { - g_wiimote_sources[i] = IsUsingWiimote(i) ? WIIMOTE_SRC_EMU : WIIMOTE_SRC_NONE; - GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(IsUsingWiimote(i)); - } + for (int i = 0; i < MAX_WIIMOTES; ++i) + { + g_wiimote_sources[i] = IsUsingWiimote(i) ? WIIMOTE_SRC_EMU : WIIMOTE_SRC_NONE; + GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(IsUsingWiimote(i)); + } } // NOTE: Host Thread bool BeginRecordingInput(int controllers) { - if (s_playMode != MODE_NONE || controllers == 0) - return false; + if (s_playMode != MODE_NONE || controllers == 0) + return false; - bool was_unpaused = Core::PauseAndLock(true); + bool was_unpaused = Core::PauseAndLock(true); - s_numPads = controllers; - g_currentFrame = g_totalFrames = 0; - g_currentLagCount = s_totalLagCount = 0; - g_currentInputCount = g_totalInputCount = 0; - s_totalTickCount = s_tickCountAtLastInput = 0; - s_bongos = 0; - s_memcards = 0; - if (NetPlay::IsNetPlayRunning()) - { - s_bNetPlay = true; - s_recordingStartTime = g_netplay_initial_gctime; - } - else - { - s_recordingStartTime = Common::Timer::GetLocalTimeSinceJan1970(); - } + s_numPads = controllers; + g_currentFrame = g_totalFrames = 0; + g_currentLagCount = s_totalLagCount = 0; + g_currentInputCount = g_totalInputCount = 0; + s_totalTickCount = s_tickCountAtLastInput = 0; + s_bongos = 0; + s_memcards = 0; + if (NetPlay::IsNetPlayRunning()) + { + s_bNetPlay = true; + s_recordingStartTime = g_netplay_initial_gctime; + } + else + { + s_recordingStartTime = Common::Timer::GetLocalTimeSinceJan1970(); + } - s_rerecords = 0; + s_rerecords = 0; - for (int i = 0; i < MAX_SI_CHANNELS; ++i) - if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_TARUKONGA) - s_bongos |= (1 << i); + for (int i = 0; i < MAX_SI_CHANNELS; ++i) + if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_TARUKONGA) + s_bongos |= (1 << i); - if (Core::IsRunningAndStarted()) - { - const std::string save_path = File::GetUserPath(D_STATESAVES_IDX) + "dtm.sav"; - if (File::Exists(save_path)) - File::Delete(save_path); + if (Core::IsRunningAndStarted()) + { + const std::string save_path = File::GetUserPath(D_STATESAVES_IDX) + "dtm.sav"; + if (File::Exists(save_path)) + File::Delete(save_path); - State::SaveAs(save_path); - s_bRecordingFromSaveState = true; + State::SaveAs(save_path); + s_bRecordingFromSaveState = true; - // This is only done here if starting from save state because otherwise we won't have the titleid. Otherwise it's set in WII_IPC_HLE_Device_es.cpp. - // TODO: find a way to GetTitleDataPath() from Movie::Init() - if (SConfig::GetInstance().bWii) - { - if (File::Exists(Common::GetTitleDataPath(g_titleID, Common::FROM_SESSION_ROOT) + "banner.bin")) - Movie::g_bClearSave = false; - else - Movie::g_bClearSave = true; - } - std::thread md5thread(GetMD5); - md5thread.detach(); - GetSettings(); - } + // This is only done here if starting from save state because otherwise we won't have the + // titleid. Otherwise it's set in WII_IPC_HLE_Device_es.cpp. + // TODO: find a way to GetTitleDataPath() from Movie::Init() + if (SConfig::GetInstance().bWii) + { + if (File::Exists(Common::GetTitleDataPath(g_titleID, Common::FROM_SESSION_ROOT) + + "banner.bin")) + Movie::g_bClearSave = false; + else + Movie::g_bClearSave = true; + } + std::thread md5thread(GetMD5); + md5thread.detach(); + GetSettings(); + } - // Wiimotes cause desync issues if they're not reset before launching the game - if (!Core::IsRunningAndStarted()) - { - // This will also reset the wiimotes for gamecube games, but that shouldn't do anything - Wiimote::ResetAllWiimotes(); - } + // Wiimotes cause desync issues if they're not reset before launching the game + if (!Core::IsRunningAndStarted()) + { + // This will also reset the wiimotes for gamecube games, but that shouldn't do anything + Wiimote::ResetAllWiimotes(); + } - s_playMode = MODE_RECORDING; - s_author = SConfig::GetInstance().m_strMovieAuthor; - EnsureTmpInputSize(1); + s_playMode = MODE_RECORDING; + s_author = SConfig::GetInstance().m_strMovieAuthor; + EnsureTmpInputSize(1); - s_currentByte = s_totalBytes = 0; + s_currentByte = s_totalBytes = 0; - Core::UpdateWantDeterminism(); + Core::UpdateWantDeterminism(); - Core::PauseAndLock(false, was_unpaused); + Core::PauseAndLock(false, was_unpaused); - Core::DisplayMessage("Starting movie recording", 2000); - return true; + Core::DisplayMessage("Starting movie recording", 2000); + return true; } static std::string Analog2DToString(u8 x, u8 y, const std::string& prefix, u8 range = 255) { - u8 center = range / 2 + 1; - if ((x <= 1 || x == center || x >= range) && - (y <= 1 || y == center || y >= range)) - { - if (x != center || y != center) - { - if (x != center && y != center) - { - return StringFromFormat("%s:%s,%s", prefix.c_str(), x < center ? "LEFT" : "RIGHT", y < center ? "DOWN" : "UP"); - } - else if (x != center) - { - return StringFromFormat("%s:%s", prefix.c_str(), x < center ? "LEFT" : "RIGHT"); - } - else - { - return StringFromFormat("%s:%s", prefix.c_str(), y < center ? "DOWN" : "UP"); - } - } - else - { - return ""; - } - } - else - { - return StringFromFormat("%s:%d,%d", prefix.c_str(), x, y); - } + u8 center = range / 2 + 1; + if ((x <= 1 || x == center || x >= range) && (y <= 1 || y == center || y >= range)) + { + if (x != center || y != center) + { + if (x != center && y != center) + { + return StringFromFormat("%s:%s,%s", prefix.c_str(), x < center ? "LEFT" : "RIGHT", + y < center ? "DOWN" : "UP"); + } + else if (x != center) + { + return StringFromFormat("%s:%s", prefix.c_str(), x < center ? "LEFT" : "RIGHT"); + } + else + { + return StringFromFormat("%s:%s", prefix.c_str(), y < center ? "DOWN" : "UP"); + } + } + else + { + return ""; + } + } + else + { + return StringFromFormat("%s:%d,%d", prefix.c_str(), x, y); + } } static std::string Analog1DToString(u8 v, const std::string& prefix, u8 range = 255) { - if (v > 0) - { - if (v == range) - { - return prefix; - } - else - { - return StringFromFormat("%s:%d", prefix.c_str(), v); - } - } - else - { - return ""; - } + if (v > 0) + { + if (v == range) + { + return prefix; + } + else + { + return StringFromFormat("%s:%d", prefix.c_str(), v); + } + } + else + { + return ""; + } } // NOTE: CPU Thread static void SetInputDisplayString(ControllerState padState, int controllerID) { - std::string display_str = StringFromFormat("P%d:", controllerID + 1); + std::string display_str = StringFromFormat("P%d:", controllerID + 1); - if (padState.A) - display_str += " A"; - if (padState.B) - display_str += " B"; - if (padState.X) - display_str += " X"; - if (padState.Y) - display_str += " Y"; - if (padState.Z) - display_str += " Z"; - if (padState.Start) - display_str += " START"; + if (padState.A) + display_str += " A"; + if (padState.B) + display_str += " B"; + if (padState.X) + display_str += " X"; + if (padState.Y) + display_str += " Y"; + if (padState.Z) + display_str += " Z"; + if (padState.Start) + display_str += " START"; - if (padState.DPadUp) - display_str += " UP"; - if (padState.DPadDown) - display_str += " DOWN"; - if (padState.DPadLeft) - display_str += " LEFT"; - if (padState.DPadRight) - display_str += " RIGHT"; - if (padState.reset) - display_str += " RESET"; + if (padState.DPadUp) + display_str += " UP"; + if (padState.DPadDown) + display_str += " DOWN"; + if (padState.DPadLeft) + display_str += " LEFT"; + if (padState.DPadRight) + display_str += " RIGHT"; + if (padState.reset) + display_str += " RESET"; - display_str += Analog1DToString(padState.TriggerL, " L"); - display_str += Analog1DToString(padState.TriggerR, " R"); - display_str += Analog2DToString(padState.AnalogStickX, padState.AnalogStickY, " ANA"); - display_str += Analog2DToString(padState.CStickX, padState.CStickY, " C"); - display_str += '\n'; + display_str += Analog1DToString(padState.TriggerL, " L"); + display_str += Analog1DToString(padState.TriggerR, " R"); + display_str += Analog2DToString(padState.AnalogStickX, padState.AnalogStickY, " ANA"); + display_str += Analog2DToString(padState.CStickX, padState.CStickY, " C"); + display_str += '\n'; - std::lock_guard guard(s_input_display_lock); - s_InputDisplay[controllerID] = std::move(display_str); + std::lock_guard guard(s_input_display_lock); + s_InputDisplay[controllerID] = std::move(display_str); } // NOTE: CPU Thread -static void SetWiiInputDisplayString(int remoteID, u8* const data, const WiimoteEmu::ReportFeatures& rptf, int ext, const wiimote_key key) +static void SetWiiInputDisplayString(int remoteID, u8* const data, + const WiimoteEmu::ReportFeatures& rptf, int ext, + const wiimote_key key) { - int controllerID = remoteID + 4; + int controllerID = remoteID + 4; - std::string display_str = StringFromFormat("R%d:", remoteID + 1); + std::string display_str = StringFromFormat("R%d:", remoteID + 1); - u8* const coreData = rptf.core ? (data + rptf.core) : nullptr; - u8* const accelData = rptf.accel ? (data + rptf.accel) : nullptr; - u8* const irData = rptf.ir ? (data + rptf.ir) : nullptr; - u8* const extData = rptf.ext ? (data + rptf.ext) : nullptr; + u8* const coreData = rptf.core ? (data + rptf.core) : nullptr; + u8* const accelData = rptf.accel ? (data + rptf.accel) : nullptr; + u8* const irData = rptf.ir ? (data + rptf.ir) : nullptr; + u8* const extData = rptf.ext ? (data + rptf.ext) : nullptr; - if (coreData) - { - wm_buttons buttons = *(wm_buttons*)coreData; - if(buttons.left) - display_str += " LEFT"; - if(buttons.right) - display_str += " RIGHT"; - if(buttons.down) - display_str += " DOWN"; - if(buttons.up) - display_str += " UP"; - if(buttons.a) - display_str += " A"; - if(buttons.b) - display_str += " B"; - if(buttons.plus) - display_str += " +"; - if(buttons.minus) - display_str += " -"; - if(buttons.one) - display_str += " 1"; - if(buttons.two) - display_str += " 2"; - if(buttons.home) - display_str += " HOME"; - } + if (coreData) + { + wm_buttons buttons = *(wm_buttons*)coreData; + if (buttons.left) + display_str += " LEFT"; + if (buttons.right) + display_str += " RIGHT"; + if (buttons.down) + display_str += " DOWN"; + if (buttons.up) + display_str += " UP"; + if (buttons.a) + display_str += " A"; + if (buttons.b) + display_str += " B"; + if (buttons.plus) + display_str += " +"; + if (buttons.minus) + display_str += " -"; + if (buttons.one) + display_str += " 1"; + if (buttons.two) + display_str += " 2"; + if (buttons.home) + display_str += " HOME"; + } - if (accelData) - { - wm_accel* dt = (wm_accel*)accelData; - display_str += StringFromFormat(" ACC:%d,%d,%d", - dt->x << 2 | ((wm_buttons*)coreData)->acc_x_lsb, - dt->y << 2 | ((wm_buttons*)coreData)->acc_y_lsb << 1, - dt->z << 2 | ((wm_buttons*)coreData)->acc_z_lsb << 1); - } + if (accelData) + { + wm_accel* dt = (wm_accel*)accelData; + display_str += + StringFromFormat(" ACC:%d,%d,%d", dt->x << 2 | ((wm_buttons*)coreData)->acc_x_lsb, + dt->y << 2 | ((wm_buttons*)coreData)->acc_y_lsb << 1, + dt->z << 2 | ((wm_buttons*)coreData)->acc_z_lsb << 1); + } - if (irData) - { - u16 x = irData[0] | ((irData[2] >> 4 & 0x3) << 8); - u16 y = irData[1] | ((irData[2] >> 6 & 0x3) << 8); - display_str += StringFromFormat(" IR:%d,%d", x, y); - } + if (irData) + { + u16 x = irData[0] | ((irData[2] >> 4 & 0x3) << 8); + u16 y = irData[1] | ((irData[2] >> 6 & 0x3) << 8); + display_str += StringFromFormat(" IR:%d,%d", x, y); + } - // Nunchuk - if (extData && ext == 1) - { - wm_nc nunchuk; - memcpy(&nunchuk, extData, sizeof(wm_nc)); - WiimoteDecrypt(&key, (u8*)&nunchuk, 0, sizeof(wm_nc)); - nunchuk.bt.hex = nunchuk.bt.hex ^ 0x3; + // Nunchuk + if (extData && ext == 1) + { + wm_nc nunchuk; + memcpy(&nunchuk, extData, sizeof(wm_nc)); + WiimoteDecrypt(&key, (u8*)&nunchuk, 0, sizeof(wm_nc)); + nunchuk.bt.hex = nunchuk.bt.hex ^ 0x3; - std::string accel = StringFromFormat(" N-ACC:%d,%d,%d", - (nunchuk.ax << 2) | nunchuk.bt.acc_x_lsb, (nunchuk.ay << 2) | nunchuk.bt.acc_y_lsb, (nunchuk.az << 2) | nunchuk.bt.acc_z_lsb); + std::string accel = StringFromFormat( + " N-ACC:%d,%d,%d", (nunchuk.ax << 2) | nunchuk.bt.acc_x_lsb, + (nunchuk.ay << 2) | nunchuk.bt.acc_y_lsb, (nunchuk.az << 2) | nunchuk.bt.acc_z_lsb); - if (nunchuk.bt.c) - display_str += " C"; - if (nunchuk.bt.z) - display_str += " Z"; - display_str += accel; - display_str += Analog2DToString(nunchuk.jx, nunchuk.jy, " ANA"); - } + if (nunchuk.bt.c) + display_str += " C"; + if (nunchuk.bt.z) + display_str += " Z"; + display_str += accel; + display_str += Analog2DToString(nunchuk.jx, nunchuk.jy, " ANA"); + } - // Classic controller - if (extData && ext == 2) - { - wm_classic_extension cc; - memcpy(&cc, extData, sizeof(wm_classic_extension)); - WiimoteDecrypt(&key, (u8*)&cc, 0, sizeof(wm_classic_extension)); - cc.bt.hex = cc.bt.hex ^ 0xFFFF; + // Classic controller + if (extData && ext == 2) + { + wm_classic_extension cc; + memcpy(&cc, extData, sizeof(wm_classic_extension)); + WiimoteDecrypt(&key, (u8*)&cc, 0, sizeof(wm_classic_extension)); + cc.bt.hex = cc.bt.hex ^ 0xFFFF; - if (cc.bt.regular_data.dpad_left) - display_str += " LEFT"; - if (cc.bt.dpad_right) - display_str += " RIGHT"; - if (cc.bt.dpad_down) - display_str += " DOWN"; - if (cc.bt.regular_data.dpad_up) - display_str += " UP"; - if (cc.bt.a) - display_str += " A"; - if (cc.bt.b) - display_str += " B"; - if (cc.bt.x) - display_str += " X"; - if (cc.bt.y) - display_str += " Y"; - if (cc.bt.zl) - display_str += " ZL"; - if (cc.bt.zr) - display_str += " ZR"; - if (cc.bt.plus) - display_str += " +"; - if (cc.bt.minus) - display_str += " -"; - if (cc.bt.home) - display_str += " HOME"; + if (cc.bt.regular_data.dpad_left) + display_str += " LEFT"; + if (cc.bt.dpad_right) + display_str += " RIGHT"; + if (cc.bt.dpad_down) + display_str += " DOWN"; + if (cc.bt.regular_data.dpad_up) + display_str += " UP"; + if (cc.bt.a) + display_str += " A"; + if (cc.bt.b) + display_str += " B"; + if (cc.bt.x) + display_str += " X"; + if (cc.bt.y) + display_str += " Y"; + if (cc.bt.zl) + display_str += " ZL"; + if (cc.bt.zr) + display_str += " ZR"; + if (cc.bt.plus) + display_str += " +"; + if (cc.bt.minus) + display_str += " -"; + if (cc.bt.home) + display_str += " HOME"; - display_str += Analog1DToString(cc.lt1 | (cc.lt2 << 3), " L", 31); - display_str += Analog1DToString(cc.rt, " R", 31); - display_str += Analog2DToString(cc.regular_data.lx, cc.regular_data.ly, " ANA", 63); - display_str += Analog2DToString(cc.rx1 | (cc.rx2 << 1) | (cc.rx3 << 3), cc.ry, " R-ANA", 31); - } + display_str += Analog1DToString(cc.lt1 | (cc.lt2 << 3), " L", 31); + display_str += Analog1DToString(cc.rt, " R", 31); + display_str += Analog2DToString(cc.regular_data.lx, cc.regular_data.ly, " ANA", 63); + display_str += Analog2DToString(cc.rx1 | (cc.rx2 << 1) | (cc.rx3 << 3), cc.ry, " R-ANA", 31); + } - display_str += '\n'; + display_str += '\n'; - std::lock_guard guard(s_input_display_lock); - s_InputDisplay[controllerID] = std::move(display_str); + std::lock_guard guard(s_input_display_lock); + s_InputDisplay[controllerID] = std::move(display_str); } // NOTE: CPU Thread void CheckPadStatus(GCPadStatus* PadStatus, int controllerID) { - s_padState.A = ((PadStatus->button & PAD_BUTTON_A) != 0); - s_padState.B = ((PadStatus->button & PAD_BUTTON_B) != 0); - s_padState.X = ((PadStatus->button & PAD_BUTTON_X) != 0); - s_padState.Y = ((PadStatus->button & PAD_BUTTON_Y) != 0); - s_padState.Z = ((PadStatus->button & PAD_TRIGGER_Z) != 0); - s_padState.Start = ((PadStatus->button & PAD_BUTTON_START) != 0); + s_padState.A = ((PadStatus->button & PAD_BUTTON_A) != 0); + s_padState.B = ((PadStatus->button & PAD_BUTTON_B) != 0); + s_padState.X = ((PadStatus->button & PAD_BUTTON_X) != 0); + s_padState.Y = ((PadStatus->button & PAD_BUTTON_Y) != 0); + s_padState.Z = ((PadStatus->button & PAD_TRIGGER_Z) != 0); + s_padState.Start = ((PadStatus->button & PAD_BUTTON_START) != 0); - s_padState.DPadUp = ((PadStatus->button & PAD_BUTTON_UP) != 0); - s_padState.DPadDown = ((PadStatus->button & PAD_BUTTON_DOWN) != 0); - s_padState.DPadLeft = ((PadStatus->button & PAD_BUTTON_LEFT) != 0); - s_padState.DPadRight = ((PadStatus->button & PAD_BUTTON_RIGHT) != 0); + s_padState.DPadUp = ((PadStatus->button & PAD_BUTTON_UP) != 0); + s_padState.DPadDown = ((PadStatus->button & PAD_BUTTON_DOWN) != 0); + s_padState.DPadLeft = ((PadStatus->button & PAD_BUTTON_LEFT) != 0); + s_padState.DPadRight = ((PadStatus->button & PAD_BUTTON_RIGHT) != 0); - s_padState.L = ((PadStatus->button & PAD_TRIGGER_L) != 0); - s_padState.R = ((PadStatus->button & PAD_TRIGGER_R) != 0); - s_padState.TriggerL = PadStatus->triggerLeft; - s_padState.TriggerR = PadStatus->triggerRight; + s_padState.L = ((PadStatus->button & PAD_TRIGGER_L) != 0); + s_padState.R = ((PadStatus->button & PAD_TRIGGER_R) != 0); + s_padState.TriggerL = PadStatus->triggerLeft; + s_padState.TriggerR = PadStatus->triggerRight; - s_padState.AnalogStickX = PadStatus->stickX; - s_padState.AnalogStickY = PadStatus->stickY; + s_padState.AnalogStickX = PadStatus->stickX; + s_padState.AnalogStickY = PadStatus->stickY; - s_padState.CStickX = PadStatus->substickX; - s_padState.CStickY = PadStatus->substickY; + s_padState.CStickX = PadStatus->substickX; + s_padState.CStickY = PadStatus->substickY; - s_padState.disc = g_bDiscChange; - g_bDiscChange = false; - s_padState.reset = g_bReset; - g_bReset = false; + s_padState.disc = g_bDiscChange; + g_bDiscChange = false; + s_padState.reset = g_bReset; + g_bReset = false; - SetInputDisplayString(s_padState, controllerID); + SetInputDisplayString(s_padState, controllerID); } // NOTE: CPU Thread void RecordInput(GCPadStatus* PadStatus, int controllerID) { - if (!IsRecordingInput() || !IsUsingPad(controllerID)) - return; + if (!IsRecordingInput() || !IsUsingPad(controllerID)) + return; - CheckPadStatus(PadStatus, controllerID); + CheckPadStatus(PadStatus, controllerID); - EnsureTmpInputSize((size_t)(s_currentByte + 8)); - memcpy(&(tmpInput[s_currentByte]), &s_padState, 8); - s_currentByte += 8; - s_totalBytes = s_currentByte; + EnsureTmpInputSize((size_t)(s_currentByte + 8)); + memcpy(&(tmpInput[s_currentByte]), &s_padState, 8); + s_currentByte += 8; + s_totalBytes = s_currentByte; } // NOTE: CPU Thread -void CheckWiimoteStatus(int wiimote, u8 *data, const WiimoteEmu::ReportFeatures& rptf, int ext, const wiimote_key key) +void CheckWiimoteStatus(int wiimote, u8* data, const WiimoteEmu::ReportFeatures& rptf, int ext, + const wiimote_key key) { - SetWiiInputDisplayString(wiimote, data, rptf, ext, key); + SetWiiInputDisplayString(wiimote, data, rptf, ext, key); - if (IsRecordingInput()) - RecordWiimote(wiimote, data, rptf.size); + if (IsRecordingInput()) + RecordWiimote(wiimote, data, rptf.size); } -void RecordWiimote(int wiimote, u8 *data, u8 size) +void RecordWiimote(int wiimote, u8* data, u8 size) { - if (!IsRecordingInput() || !IsUsingWiimote(wiimote)) - return; + if (!IsRecordingInput() || !IsUsingWiimote(wiimote)) + return; - InputUpdate(); - EnsureTmpInputSize((size_t)(s_currentByte + size + 1)); - tmpInput[s_currentByte++] = size; - memcpy(&(tmpInput[s_currentByte]), data, size); - s_currentByte += size; - s_totalBytes = s_currentByte; + InputUpdate(); + EnsureTmpInputSize((size_t)(s_currentByte + size + 1)); + tmpInput[s_currentByte++] = size; + memcpy(&(tmpInput[s_currentByte]), data, size); + s_currentByte += size; + s_totalBytes = s_currentByte; } // NOTE: EmuThread / Host Thread void ReadHeader() { - s_numPads = tmpHeader.numControllers; - s_recordingStartTime = tmpHeader.recordingStartTime; - if (s_rerecords < tmpHeader.numRerecords) - s_rerecords = tmpHeader.numRerecords; + s_numPads = tmpHeader.numControllers; + s_recordingStartTime = tmpHeader.recordingStartTime; + if (s_rerecords < tmpHeader.numRerecords) + s_rerecords = tmpHeader.numRerecords; - if (tmpHeader.bSaveConfig) - { - s_bSaveConfig = true; - s_bSkipIdle = tmpHeader.bSkipIdle; - s_bDualCore = tmpHeader.bDualCore; - s_bProgressive = tmpHeader.bProgressive; - s_bPAL60 = tmpHeader.bPAL60; - s_bDSPHLE = tmpHeader.bDSPHLE; - s_bFastDiscSpeed = tmpHeader.bFastDiscSpeed; - s_iCPUCore = tmpHeader.CPUCore; - g_bClearSave = tmpHeader.bClearSave; - s_memcards = tmpHeader.memcards; - s_bongos = tmpHeader.bongos; - s_bSyncGPU = tmpHeader.bSyncGPU; - s_bNetPlay = tmpHeader.bNetPlay; - s_language = tmpHeader.language; - memcpy(s_revision, tmpHeader.revision, ArraySize(s_revision)); - } - else - { - GetSettings(); - } + if (tmpHeader.bSaveConfig) + { + s_bSaveConfig = true; + s_bSkipIdle = tmpHeader.bSkipIdle; + s_bDualCore = tmpHeader.bDualCore; + s_bProgressive = tmpHeader.bProgressive; + s_bPAL60 = tmpHeader.bPAL60; + s_bDSPHLE = tmpHeader.bDSPHLE; + s_bFastDiscSpeed = tmpHeader.bFastDiscSpeed; + s_iCPUCore = tmpHeader.CPUCore; + g_bClearSave = tmpHeader.bClearSave; + s_memcards = tmpHeader.memcards; + s_bongos = tmpHeader.bongos; + s_bSyncGPU = tmpHeader.bSyncGPU; + s_bNetPlay = tmpHeader.bNetPlay; + s_language = tmpHeader.language; + memcpy(s_revision, tmpHeader.revision, ArraySize(s_revision)); + } + else + { + GetSettings(); + } - s_videoBackend = (char*) tmpHeader.videoBackend; - g_discChange = (char*) tmpHeader.discChange; - s_author = (char*) tmpHeader.author; - memcpy(s_MD5, tmpHeader.md5, 16); - s_DSPiromHash = tmpHeader.DSPiromHash; - s_DSPcoefHash = tmpHeader.DSPcoefHash; + s_videoBackend = (char*)tmpHeader.videoBackend; + g_discChange = (char*)tmpHeader.discChange; + s_author = (char*)tmpHeader.author; + memcpy(s_MD5, tmpHeader.md5, 16); + s_DSPiromHash = tmpHeader.DSPiromHash; + s_DSPcoefHash = tmpHeader.DSPcoefHash; } // NOTE: Host Thread bool PlayInput(const std::string& filename) { - if (s_playMode != MODE_NONE) - return false; + if (s_playMode != MODE_NONE) + return false; - if (!File::Exists(filename)) - return false; + if (!File::Exists(filename)) + return false; - File::IOFile g_recordfd; + File::IOFile g_recordfd; - if (!g_recordfd.Open(filename, "rb")) - return false; + if (!g_recordfd.Open(filename, "rb")) + return false; - g_recordfd.ReadArray(&tmpHeader, 1); + g_recordfd.ReadArray(&tmpHeader, 1); - if (!IsMovieHeader(tmpHeader.filetype)) - { - PanicAlertT("Invalid recording file"); - g_recordfd.Close(); - return false; - } + if (!IsMovieHeader(tmpHeader.filetype)) + { + PanicAlertT("Invalid recording file"); + g_recordfd.Close(); + return false; + } - ReadHeader(); - g_totalFrames = tmpHeader.frameCount; - s_totalLagCount = tmpHeader.lagCount; - g_totalInputCount = tmpHeader.inputCount; - s_totalTickCount = tmpHeader.tickCount; - g_currentFrame = 0; - g_currentLagCount = 0; - g_currentInputCount = 0; + ReadHeader(); + g_totalFrames = tmpHeader.frameCount; + s_totalLagCount = tmpHeader.lagCount; + g_totalInputCount = tmpHeader.inputCount; + s_totalTickCount = tmpHeader.tickCount; + g_currentFrame = 0; + g_currentLagCount = 0; + g_currentInputCount = 0; - s_playMode = MODE_PLAYING; + s_playMode = MODE_PLAYING; - // Wiimotes cause desync issues if they're not reset before launching the game - Wiimote::ResetAllWiimotes(); + // Wiimotes cause desync issues if they're not reset before launching the game + Wiimote::ResetAllWiimotes(); - Core::UpdateWantDeterminism(); + Core::UpdateWantDeterminism(); - s_totalBytes = g_recordfd.GetSize() - 256; - EnsureTmpInputSize((size_t)s_totalBytes); - g_recordfd.ReadArray(tmpInput, (size_t)s_totalBytes); - s_currentByte = 0; - g_recordfd.Close(); + s_totalBytes = g_recordfd.GetSize() - 256; + EnsureTmpInputSize((size_t)s_totalBytes); + g_recordfd.ReadArray(tmpInput, (size_t)s_totalBytes); + s_currentByte = 0; + g_recordfd.Close(); - // Load savestate (and skip to frame data) - if (tmpHeader.bFromSaveState) - { - const std::string stateFilename = filename + ".sav"; - if (File::Exists(stateFilename)) - Core::SetStateFileName(stateFilename); - s_bRecordingFromSaveState = true; - Movie::LoadInput(filename); - } + // Load savestate (and skip to frame data) + if (tmpHeader.bFromSaveState) + { + const std::string stateFilename = filename + ".sav"; + if (File::Exists(stateFilename)) + Core::SetStateFileName(stateFilename); + s_bRecordingFromSaveState = true; + Movie::LoadInput(filename); + } - return true; + return true; } -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - // many of these could be useful to save even when no movie is active, - // and the data is tiny, so let's just save it regardless of movie state. - p.Do(g_currentFrame); - p.Do(s_currentByte); - p.Do(g_currentLagCount); - p.Do(g_currentInputCount); - p.Do(s_bPolled); - p.Do(s_tickCountAtLastInput); - // other variables (such as s_totalBytes and g_totalFrames) are set in LoadInput + // many of these could be useful to save even when no movie is active, + // and the data is tiny, so let's just save it regardless of movie state. + p.Do(g_currentFrame); + p.Do(s_currentByte); + p.Do(g_currentLagCount); + p.Do(g_currentInputCount); + p.Do(s_bPolled); + p.Do(s_tickCountAtLastInput); + // other variables (such as s_totalBytes and g_totalFrames) are set in LoadInput } // NOTE: Host Thread void LoadInput(const std::string& filename) { - File::IOFile t_record; - if (!t_record.Open(filename, "r+b")) - { - PanicAlertT("Failed to read %s", filename.c_str()); - EndPlayInput(false); - return; - } + File::IOFile t_record; + if (!t_record.Open(filename, "r+b")) + { + PanicAlertT("Failed to read %s", filename.c_str()); + EndPlayInput(false); + return; + } - t_record.ReadArray(&tmpHeader, 1); + t_record.ReadArray(&tmpHeader, 1); - if (!IsMovieHeader(tmpHeader.filetype)) - { - PanicAlertT("Savestate movie %s is corrupted, movie recording stopping...", filename.c_str()); - EndPlayInput(false); - return; - } - ReadHeader(); - if (!s_bReadOnly) - { - s_rerecords++; - tmpHeader.numRerecords = s_rerecords; - t_record.Seek(0, SEEK_SET); - t_record.WriteArray(&tmpHeader, 1); - } + if (!IsMovieHeader(tmpHeader.filetype)) + { + PanicAlertT("Savestate movie %s is corrupted, movie recording stopping...", filename.c_str()); + EndPlayInput(false); + return; + } + ReadHeader(); + if (!s_bReadOnly) + { + s_rerecords++; + tmpHeader.numRerecords = s_rerecords; + t_record.Seek(0, SEEK_SET); + t_record.WriteArray(&tmpHeader, 1); + } - ChangePads(true); - if (SConfig::GetInstance().bWii) - ChangeWiiPads(true); + ChangePads(true); + if (SConfig::GetInstance().bWii) + ChangeWiiPads(true); - u64 totalSavedBytes = t_record.GetSize() - 256; + u64 totalSavedBytes = t_record.GetSize() - 256; - bool afterEnd = false; - // This can only happen if the user manually deletes data from the dtm. - if (s_currentByte > totalSavedBytes) - { - PanicAlertT("Warning: You loaded a save whose movie ends before the current frame in the save (byte %u < %u) (frame %u < %u). You should load another save before continuing.", (u32)totalSavedBytes+256, (u32)s_currentByte+256, (u32)tmpHeader.frameCount, (u32)g_currentFrame); - afterEnd = true; - } + bool afterEnd = false; + // This can only happen if the user manually deletes data from the dtm. + if (s_currentByte > totalSavedBytes) + { + PanicAlertT("Warning: You loaded a save whose movie ends before the current frame in the save " + "(byte %u < %u) (frame %u < %u). You should load another save before continuing.", + (u32)totalSavedBytes + 256, (u32)s_currentByte + 256, (u32)tmpHeader.frameCount, + (u32)g_currentFrame); + afterEnd = true; + } - if (!s_bReadOnly || tmpInput == nullptr) - { - g_totalFrames = tmpHeader.frameCount; - s_totalLagCount = tmpHeader.lagCount; - g_totalInputCount = tmpHeader.inputCount; - s_totalTickCount = s_tickCountAtLastInput = tmpHeader.tickCount; + if (!s_bReadOnly || tmpInput == nullptr) + { + g_totalFrames = tmpHeader.frameCount; + s_totalLagCount = tmpHeader.lagCount; + g_totalInputCount = tmpHeader.inputCount; + s_totalTickCount = s_tickCountAtLastInput = tmpHeader.tickCount; - EnsureTmpInputSize((size_t)totalSavedBytes); - s_totalBytes = totalSavedBytes; - t_record.ReadArray(tmpInput, (size_t)s_totalBytes); - } - else if (s_currentByte > 0) - { - if (s_currentByte > totalSavedBytes) - { - } - else if (s_currentByte > s_totalBytes) - { - afterEnd = true; - PanicAlertT("Warning: You loaded a save that's after the end of the current movie. (byte %u > %u) (frame %u > %u). You should load another save before continuing, or load this state with read-only mode off.", (u32)s_currentByte+256, (u32)s_totalBytes+256, (u32)g_currentFrame, (u32)g_totalFrames); - } - else if (s_currentByte > 0 && s_totalBytes > 0) - { - // verify identical from movie start to the save's current frame - u32 len = (u32)s_currentByte; - u8* movInput = new u8[len]; - t_record.ReadArray(movInput, (size_t)len); - for (u32 i = 0; i < len; ++i) - { - if (movInput[i] != tmpInput[i]) - { - // this is a "you did something wrong" alert for the user's benefit. - // we'll try to say what's going on in excruciating detail, otherwise the user might not believe us. - if (IsUsingWiimote(0)) - { - // TODO: more detail - PanicAlertT("Warning: You loaded a save whose movie mismatches on byte %d (0x%X). You should load another save before continuing, or load this state with read-only mode off. Otherwise you'll probably get a desync.", i+256, i+256); - memcpy(tmpInput, movInput, s_currentByte); - } - else - { - int frame = i / 8; - ControllerState curPadState; - memcpy(&curPadState, &(tmpInput[frame*8]), 8); - ControllerState movPadState; - memcpy(&movPadState, &(movInput[frame*8]), 8); - PanicAlertT("Warning: You loaded a save whose movie mismatches on frame %d. You should load another save before continuing, or load this state with read-only mode off. Otherwise you'll probably get a desync.\n\n" - "More information: The current movie is %d frames long and the savestate's movie is %d frames long.\n\n" - "On frame %d, the current movie presses:\n" - "Start=%d, A=%d, B=%d, X=%d, Y=%d, Z=%d, DUp=%d, DDown=%d, DLeft=%d, DRight=%d, L=%d, R=%d, LT=%d, RT=%d, AnalogX=%d, AnalogY=%d, CX=%d, CY=%d" - "\n\n" - "On frame %d, the savestate's movie presses:\n" - "Start=%d, A=%d, B=%d, X=%d, Y=%d, Z=%d, DUp=%d, DDown=%d, DLeft=%d, DRight=%d, L=%d, R=%d, LT=%d, RT=%d, AnalogX=%d, AnalogY=%d, CX=%d, CY=%d", - (int)frame, - (int)g_totalFrames, (int)tmpHeader.frameCount, - (int)frame, - (int)curPadState.Start, (int)curPadState.A, (int)curPadState.B, (int)curPadState.X, (int)curPadState.Y, (int)curPadState.Z, (int)curPadState.DPadUp, (int)curPadState.DPadDown, (int)curPadState.DPadLeft, (int)curPadState.DPadRight, (int)curPadState.L, (int)curPadState.R, (int)curPadState.TriggerL, (int)curPadState.TriggerR, (int)curPadState.AnalogStickX, (int)curPadState.AnalogStickY, (int)curPadState.CStickX, (int)curPadState.CStickY, - (int)frame, - (int)movPadState.Start, (int)movPadState.A, (int)movPadState.B, (int)movPadState.X, (int)movPadState.Y, (int)movPadState.Z, (int)movPadState.DPadUp, (int)movPadState.DPadDown, (int)movPadState.DPadLeft, (int)movPadState.DPadRight, (int)movPadState.L, (int)movPadState.R, (int)movPadState.TriggerL, (int)movPadState.TriggerR, (int)movPadState.AnalogStickX, (int)movPadState.AnalogStickY, (int)movPadState.CStickX, (int)movPadState.CStickY); + EnsureTmpInputSize((size_t)totalSavedBytes); + s_totalBytes = totalSavedBytes; + t_record.ReadArray(tmpInput, (size_t)s_totalBytes); + } + else if (s_currentByte > 0) + { + if (s_currentByte > totalSavedBytes) + { + } + else if (s_currentByte > s_totalBytes) + { + afterEnd = true; + PanicAlertT("Warning: You loaded a save that's after the end of the current movie. (byte %u " + "> %u) (frame %u > %u). You should load another save before continuing, or load " + "this state with read-only mode off.", + (u32)s_currentByte + 256, (u32)s_totalBytes + 256, (u32)g_currentFrame, + (u32)g_totalFrames); + } + else if (s_currentByte > 0 && s_totalBytes > 0) + { + // verify identical from movie start to the save's current frame + u32 len = (u32)s_currentByte; + u8* movInput = new u8[len]; + t_record.ReadArray(movInput, (size_t)len); + for (u32 i = 0; i < len; ++i) + { + if (movInput[i] != tmpInput[i]) + { + // this is a "you did something wrong" alert for the user's benefit. + // we'll try to say what's going on in excruciating detail, otherwise the user might not + // believe us. + if (IsUsingWiimote(0)) + { + // TODO: more detail + PanicAlertT("Warning: You loaded a save whose movie mismatches on byte %d (0x%X). You " + "should load another save before continuing, or load this state with " + "read-only mode off. Otherwise you'll probably get a desync.", + i + 256, i + 256); + memcpy(tmpInput, movInput, s_currentByte); + } + else + { + int frame = i / 8; + ControllerState curPadState; + memcpy(&curPadState, &(tmpInput[frame * 8]), 8); + ControllerState movPadState; + memcpy(&movPadState, &(movInput[frame * 8]), 8); + PanicAlertT( + "Warning: You loaded a save whose movie mismatches on frame %d. You should load " + "another save before continuing, or load this state with read-only mode off. " + "Otherwise you'll probably get a desync.\n\n" + "More information: The current movie is %d frames long and the savestate's movie " + "is %d frames long.\n\n" + "On frame %d, the current movie presses:\n" + "Start=%d, A=%d, B=%d, X=%d, Y=%d, Z=%d, DUp=%d, DDown=%d, DLeft=%d, DRight=%d, " + "L=%d, R=%d, LT=%d, RT=%d, AnalogX=%d, AnalogY=%d, CX=%d, CY=%d" + "\n\n" + "On frame %d, the savestate's movie presses:\n" + "Start=%d, A=%d, B=%d, X=%d, Y=%d, Z=%d, DUp=%d, DDown=%d, DLeft=%d, DRight=%d, " + "L=%d, R=%d, LT=%d, RT=%d, AnalogX=%d, AnalogY=%d, CX=%d, CY=%d", + (int)frame, (int)g_totalFrames, (int)tmpHeader.frameCount, (int)frame, + (int)curPadState.Start, (int)curPadState.A, (int)curPadState.B, (int)curPadState.X, + (int)curPadState.Y, (int)curPadState.Z, (int)curPadState.DPadUp, + (int)curPadState.DPadDown, (int)curPadState.DPadLeft, (int)curPadState.DPadRight, + (int)curPadState.L, (int)curPadState.R, (int)curPadState.TriggerL, + (int)curPadState.TriggerR, (int)curPadState.AnalogStickX, + (int)curPadState.AnalogStickY, (int)curPadState.CStickX, (int)curPadState.CStickY, + (int)frame, (int)movPadState.Start, (int)movPadState.A, (int)movPadState.B, + (int)movPadState.X, (int)movPadState.Y, (int)movPadState.Z, (int)movPadState.DPadUp, + (int)movPadState.DPadDown, (int)movPadState.DPadLeft, (int)movPadState.DPadRight, + (int)movPadState.L, (int)movPadState.R, (int)movPadState.TriggerL, + (int)movPadState.TriggerR, (int)movPadState.AnalogStickX, + (int)movPadState.AnalogStickY, (int)movPadState.CStickX, (int)movPadState.CStickY); + } + break; + } + } + delete[] movInput; + } + } + t_record.Close(); - } - break; - } - } - delete [] movInput; - } - } - t_record.Close(); + s_bSaveConfig = tmpHeader.bSaveConfig; - s_bSaveConfig = tmpHeader.bSaveConfig; - - if (!afterEnd) - { - if (s_bReadOnly) - { - if (s_playMode != MODE_PLAYING) - { - s_playMode = MODE_PLAYING; - Core::DisplayMessage("Switched to playback", 2000); - } - } - else - { - if (s_playMode != MODE_RECORDING) - { - s_playMode = MODE_RECORDING; - Core::DisplayMessage("Switched to recording", 2000); - } - } - } - else - { - EndPlayInput(false); - } + if (!afterEnd) + { + if (s_bReadOnly) + { + if (s_playMode != MODE_PLAYING) + { + s_playMode = MODE_PLAYING; + Core::DisplayMessage("Switched to playback", 2000); + } + } + else + { + if (s_playMode != MODE_RECORDING) + { + s_playMode = MODE_RECORDING; + Core::DisplayMessage("Switched to recording", 2000); + } + } + } + else + { + EndPlayInput(false); + } } // NOTE: CPU Thread static void CheckInputEnd() { - if (g_currentFrame > g_totalFrames || s_currentByte >= s_totalBytes || (CoreTiming::GetTicks() > s_totalTickCount && !IsRecordingInputFromSaveState())) - { - EndPlayInput(!s_bReadOnly); - } + if (g_currentFrame > g_totalFrames || s_currentByte >= s_totalBytes || + (CoreTiming::GetTicks() > s_totalTickCount && !IsRecordingInputFromSaveState())) + { + EndPlayInput(!s_bReadOnly); + } } // NOTE: CPU Thread void PlayController(GCPadStatus* PadStatus, int controllerID) { - // Correct playback is entirely dependent on the emulator polling the controllers - // in the same order done during recording - if (!IsPlayingInput() || !IsUsingPad(controllerID) || tmpInput == nullptr) - return; + // Correct playback is entirely dependent on the emulator polling the controllers + // in the same order done during recording + if (!IsPlayingInput() || !IsUsingPad(controllerID) || tmpInput == nullptr) + return; - if (s_currentByte + 8 > s_totalBytes) - { - PanicAlertT("Premature movie end in PlayController. %u + 8 > %u", (u32)s_currentByte, (u32)s_totalBytes); - EndPlayInput(!s_bReadOnly); - return; - } + if (s_currentByte + 8 > s_totalBytes) + { + PanicAlertT("Premature movie end in PlayController. %u + 8 > %u", (u32)s_currentByte, + (u32)s_totalBytes); + EndPlayInput(!s_bReadOnly); + return; + } - // dtm files don't save the mic button or error bit. not sure if they're actually used, but better safe than sorry - signed char e = PadStatus->err; - memset(PadStatus, 0, sizeof(GCPadStatus)); - PadStatus->err = e; + // dtm files don't save the mic button or error bit. not sure if they're actually used, but better + // safe than sorry + signed char e = PadStatus->err; + memset(PadStatus, 0, sizeof(GCPadStatus)); + PadStatus->err = e; + memcpy(&s_padState, &(tmpInput[s_currentByte]), 8); + s_currentByte += 8; - memcpy(&s_padState, &(tmpInput[s_currentByte]), 8); - s_currentByte += 8; + PadStatus->triggerLeft = s_padState.TriggerL; + PadStatus->triggerRight = s_padState.TriggerR; - PadStatus->triggerLeft = s_padState.TriggerL; - PadStatus->triggerRight = s_padState.TriggerR; + PadStatus->stickX = s_padState.AnalogStickX; + PadStatus->stickY = s_padState.AnalogStickY; - PadStatus->stickX = s_padState.AnalogStickX; - PadStatus->stickY = s_padState.AnalogStickY; + PadStatus->substickX = s_padState.CStickX; + PadStatus->substickY = s_padState.CStickY; - PadStatus->substickX = s_padState.CStickX; - PadStatus->substickY = s_padState.CStickY; + PadStatus->button |= PAD_USE_ORIGIN; - PadStatus->button |= PAD_USE_ORIGIN; + if (s_padState.A) + { + PadStatus->button |= PAD_BUTTON_A; + PadStatus->analogA = 0xFF; + } + if (s_padState.B) + { + PadStatus->button |= PAD_BUTTON_B; + PadStatus->analogB = 0xFF; + } + if (s_padState.X) + PadStatus->button |= PAD_BUTTON_X; + if (s_padState.Y) + PadStatus->button |= PAD_BUTTON_Y; + if (s_padState.Z) + PadStatus->button |= PAD_TRIGGER_Z; + if (s_padState.Start) + PadStatus->button |= PAD_BUTTON_START; - if (s_padState.A) - { - PadStatus->button |= PAD_BUTTON_A; - PadStatus->analogA = 0xFF; - } - if (s_padState.B) - { - PadStatus->button |= PAD_BUTTON_B; - PadStatus->analogB = 0xFF; - } - if (s_padState.X) - PadStatus->button |= PAD_BUTTON_X; - if (s_padState.Y) - PadStatus->button |= PAD_BUTTON_Y; - if (s_padState.Z) - PadStatus->button |= PAD_TRIGGER_Z; - if (s_padState.Start) - PadStatus->button |= PAD_BUTTON_START; + if (s_padState.DPadUp) + PadStatus->button |= PAD_BUTTON_UP; + if (s_padState.DPadDown) + PadStatus->button |= PAD_BUTTON_DOWN; + if (s_padState.DPadLeft) + PadStatus->button |= PAD_BUTTON_LEFT; + if (s_padState.DPadRight) + PadStatus->button |= PAD_BUTTON_RIGHT; - if (s_padState.DPadUp) - PadStatus->button |= PAD_BUTTON_UP; - if (s_padState.DPadDown) - PadStatus->button |= PAD_BUTTON_DOWN; - if (s_padState.DPadLeft) - PadStatus->button |= PAD_BUTTON_LEFT; - if (s_padState.DPadRight) - PadStatus->button |= PAD_BUTTON_RIGHT; + if (s_padState.L) + PadStatus->button |= PAD_TRIGGER_L; + if (s_padState.R) + PadStatus->button |= PAD_TRIGGER_R; + if (s_padState.disc) + { + // This implementation assumes the disc change will only happen once. Trying to change more than + // that will cause + // it to load the last disc every time. As far as i know though, there are no 3+ disc games, so + // this should be fine. + CPU::Break(); + bool found = false; + std::string path; + for (size_t i = 0; i < SConfig::GetInstance().m_ISOFolder.size(); ++i) + { + path = SConfig::GetInstance().m_ISOFolder[i]; + if (File::Exists(path + '/' + g_discChange)) + { + found = true; + break; + } + } + if (found) + { + path += '/' + g_discChange; - if (s_padState.L) - PadStatus->button |= PAD_TRIGGER_L; - if (s_padState.R) - PadStatus->button |= PAD_TRIGGER_R; - if (s_padState.disc) - { - // This implementation assumes the disc change will only happen once. Trying to change more than that will cause - // it to load the last disc every time. As far as i know though, there are no 3+ disc games, so this should be fine. - CPU::Break(); - bool found = false; - std::string path; - for (size_t i = 0; i < SConfig::GetInstance().m_ISOFolder.size(); ++i) - { - path = SConfig::GetInstance().m_ISOFolder[i]; - if (File::Exists(path + '/' + g_discChange)) - { - found = true; - break; - } - } - if (found) - { - path += '/' + g_discChange; + Core::QueueHostJob([=] { + if (!Movie::IsPlayingInput()) + return; - Core::QueueHostJob([=] - { - if (!Movie::IsPlayingInput()) - return; + DVDInterface::ChangeDisc(path); + CPU::EnableStepping(false); + }); + } + else + { + PanicAlertT("Change the disc to %s", g_discChange.c_str()); + } + } - DVDInterface::ChangeDisc(path); - CPU::EnableStepping(false); - }); - } - else - { - PanicAlertT("Change the disc to %s", g_discChange.c_str()); - } - } + if (s_padState.reset) + ProcessorInterface::ResetButton_Tap(); - if (s_padState.reset) - ProcessorInterface::ResetButton_Tap(); - - SetInputDisplayString(s_padState, controllerID); - CheckInputEnd(); + SetInputDisplayString(s_padState, controllerID); + CheckInputEnd(); } // NOTE: CPU Thread -bool PlayWiimote(int wiimote, u8 *data, const WiimoteEmu::ReportFeatures& rptf, int ext, const wiimote_key key) +bool PlayWiimote(int wiimote, u8* data, const WiimoteEmu::ReportFeatures& rptf, int ext, + const wiimote_key key) { - if (!IsPlayingInput() || !IsUsingWiimote(wiimote) || tmpInput == nullptr) - return false; + if (!IsPlayingInput() || !IsUsingWiimote(wiimote) || tmpInput == nullptr) + return false; - if (s_currentByte > s_totalBytes) - { - PanicAlertT("Premature movie end in PlayWiimote. %u > %u", (u32)s_currentByte, (u32)s_totalBytes); - EndPlayInput(!s_bReadOnly); - return false; - } + if (s_currentByte > s_totalBytes) + { + PanicAlertT("Premature movie end in PlayWiimote. %u > %u", (u32)s_currentByte, + (u32)s_totalBytes); + EndPlayInput(!s_bReadOnly); + return false; + } - u8 size = rptf.size; + u8 size = rptf.size; - u8 sizeInMovie = tmpInput[s_currentByte]; + u8 sizeInMovie = tmpInput[s_currentByte]; - if (size != sizeInMovie) - { - PanicAlertT("Fatal desync. Aborting playback. (Error in PlayWiimote: %u != %u, byte %u.)%s", (u32)sizeInMovie, (u32)size, (u32)s_currentByte, - (s_numPads & 0xF)?" Try re-creating the recording with all GameCube controllers disabled (in Configure > GameCube > Device Settings)." : ""); - EndPlayInput(!s_bReadOnly); - return false; - } + if (size != sizeInMovie) + { + PanicAlertT("Fatal desync. Aborting playback. (Error in PlayWiimote: %u != %u, byte %u.)%s", + (u32)sizeInMovie, (u32)size, (u32)s_currentByte, + (s_numPads & 0xF) ? " Try re-creating the recording with all GameCube controllers " + "disabled (in Configure > GameCube > Device Settings)." : + ""); + EndPlayInput(!s_bReadOnly); + return false; + } - s_currentByte++; + s_currentByte++; - if (s_currentByte + size > s_totalBytes) - { - PanicAlertT("Premature movie end in PlayWiimote. %u + %d > %u", (u32)s_currentByte, size, (u32)s_totalBytes); - EndPlayInput(!s_bReadOnly); - return false; - } + if (s_currentByte + size > s_totalBytes) + { + PanicAlertT("Premature movie end in PlayWiimote. %u + %d > %u", (u32)s_currentByte, size, + (u32)s_totalBytes); + EndPlayInput(!s_bReadOnly); + return false; + } - memcpy(data, &(tmpInput[s_currentByte]), size); - s_currentByte += size; + memcpy(data, &(tmpInput[s_currentByte]), size); + s_currentByte += size; - g_currentInputCount++; + g_currentInputCount++; - CheckInputEnd(); - return true; + CheckInputEnd(); + return true; } // NOTE: Host / EmuThread / CPU Thread void EndPlayInput(bool cont) { - if (cont) - { - s_playMode = MODE_RECORDING; - Core::DisplayMessage("Reached movie end. Resuming recording.", 2000); - } - else if (s_playMode != MODE_NONE) - { - // We can be called by EmuThread during boot (CPU_POWERDOWN) - bool was_running = Core::IsRunningAndStarted() && !CPU::IsStepping(); - if (was_running) - CPU::Break(); - s_rerecords = 0; - s_currentByte = 0; - s_playMode = MODE_NONE; - Core::DisplayMessage("Movie End.", 2000); - s_bRecordingFromSaveState = false; - // we don't clear these things because otherwise we can't resume playback if we load a movie state later - //g_totalFrames = s_totalBytes = 0; - //delete tmpInput; - //tmpInput = nullptr; + if (cont) + { + s_playMode = MODE_RECORDING; + Core::DisplayMessage("Reached movie end. Resuming recording.", 2000); + } + else if (s_playMode != MODE_NONE) + { + // We can be called by EmuThread during boot (CPU_POWERDOWN) + bool was_running = Core::IsRunningAndStarted() && !CPU::IsStepping(); + if (was_running) + CPU::Break(); + s_rerecords = 0; + s_currentByte = 0; + s_playMode = MODE_NONE; + Core::DisplayMessage("Movie End.", 2000); + s_bRecordingFromSaveState = false; + // we don't clear these things because otherwise we can't resume playback if we load a movie + // state later + // g_totalFrames = s_totalBytes = 0; + // delete tmpInput; + // tmpInput = nullptr; - Core::QueueHostJob([=] - { - Core::UpdateWantDeterminism(); - if (was_running && !SConfig::GetInstance().m_PauseMovie) - CPU::EnableStepping(false); - }); - } + Core::QueueHostJob([=] { + Core::UpdateWantDeterminism(); + if (was_running && !SConfig::GetInstance().m_PauseMovie) + CPU::EnableStepping(false); + }); + } } // NOTE: Save State + Host Thread void SaveRecording(const std::string& filename) { - File::IOFile save_record(filename, "wb"); - // Create the real header now and write it - DTMHeader header; - memset(&header, 0, sizeof(DTMHeader)); + File::IOFile save_record(filename, "wb"); + // Create the real header now and write it + DTMHeader header; + memset(&header, 0, sizeof(DTMHeader)); - header.filetype[0] = 'D'; header.filetype[1] = 'T'; header.filetype[2] = 'M'; header.filetype[3] = 0x1A; - strncpy(header.gameID, SConfig::GetInstance().GetUniqueID().c_str(), 6); - header.bWii = SConfig::GetInstance().bWii; - header.numControllers = s_numPads & (SConfig::GetInstance().bWii ? 0xFF : 0x0F); + header.filetype[0] = 'D'; + header.filetype[1] = 'T'; + header.filetype[2] = 'M'; + header.filetype[3] = 0x1A; + strncpy(header.gameID, SConfig::GetInstance().GetUniqueID().c_str(), 6); + header.bWii = SConfig::GetInstance().bWii; + header.numControllers = s_numPads & (SConfig::GetInstance().bWii ? 0xFF : 0x0F); - header.bFromSaveState = s_bRecordingFromSaveState; - header.frameCount = g_totalFrames; - header.lagCount = s_totalLagCount; - header.inputCount = g_totalInputCount; - header.numRerecords = s_rerecords; - header.recordingStartTime = s_recordingStartTime; + header.bFromSaveState = s_bRecordingFromSaveState; + header.frameCount = g_totalFrames; + header.lagCount = s_totalLagCount; + header.inputCount = g_totalInputCount; + header.numRerecords = s_rerecords; + header.recordingStartTime = s_recordingStartTime; - header.bSaveConfig = true; - header.bSkipIdle = s_bSkipIdle; - header.bDualCore = s_bDualCore; - header.bProgressive = s_bProgressive; - header.bPAL60 = s_bPAL60; - header.bDSPHLE = s_bDSPHLE; - header.bFastDiscSpeed = s_bFastDiscSpeed; - strncpy((char *)header.videoBackend, s_videoBackend.c_str(),ArraySize(header.videoBackend)); - header.CPUCore = s_iCPUCore; - header.bEFBAccessEnable = g_ActiveConfig.bEFBAccessEnable; - header.bEFBCopyEnable = true; - header.bSkipEFBCopyToRam = g_ActiveConfig.bSkipEFBCopyToRam; - header.bEFBCopyCacheEnable = false; - header.bEFBEmulateFormatChanges = g_ActiveConfig.bEFBEmulateFormatChanges; - header.bUseXFB = g_ActiveConfig.bUseXFB; - header.bUseRealXFB = g_ActiveConfig.bUseRealXFB; - header.memcards = s_memcards; - header.bClearSave = g_bClearSave; - header.bSyncGPU = s_bSyncGPU; - header.bNetPlay = s_bNetPlay; - strncpy((char *)header.discChange, g_discChange.c_str(),ArraySize(header.discChange)); - strncpy((char *)header.author, s_author.c_str(),ArraySize(header.author)); - memcpy(header.md5,s_MD5,16); - header.bongos = s_bongos; - memcpy(header.revision, s_revision, ArraySize(header.revision)); - header.DSPiromHash = s_DSPiromHash; - header.DSPcoefHash = s_DSPcoefHash; - header.tickCount = s_totalTickCount; - header.language = s_language; + header.bSaveConfig = true; + header.bSkipIdle = s_bSkipIdle; + header.bDualCore = s_bDualCore; + header.bProgressive = s_bProgressive; + header.bPAL60 = s_bPAL60; + header.bDSPHLE = s_bDSPHLE; + header.bFastDiscSpeed = s_bFastDiscSpeed; + strncpy((char*)header.videoBackend, s_videoBackend.c_str(), ArraySize(header.videoBackend)); + header.CPUCore = s_iCPUCore; + header.bEFBAccessEnable = g_ActiveConfig.bEFBAccessEnable; + header.bEFBCopyEnable = true; + header.bSkipEFBCopyToRam = g_ActiveConfig.bSkipEFBCopyToRam; + header.bEFBCopyCacheEnable = false; + header.bEFBEmulateFormatChanges = g_ActiveConfig.bEFBEmulateFormatChanges; + header.bUseXFB = g_ActiveConfig.bUseXFB; + header.bUseRealXFB = g_ActiveConfig.bUseRealXFB; + header.memcards = s_memcards; + header.bClearSave = g_bClearSave; + header.bSyncGPU = s_bSyncGPU; + header.bNetPlay = s_bNetPlay; + strncpy((char*)header.discChange, g_discChange.c_str(), ArraySize(header.discChange)); + strncpy((char*)header.author, s_author.c_str(), ArraySize(header.author)); + memcpy(header.md5, s_MD5, 16); + header.bongos = s_bongos; + memcpy(header.revision, s_revision, ArraySize(header.revision)); + header.DSPiromHash = s_DSPiromHash; + header.DSPcoefHash = s_DSPcoefHash; + header.tickCount = s_totalTickCount; + header.language = s_language; - // TODO - header.uniqueID = 0; - // header.audioEmulator; + // TODO + header.uniqueID = 0; + // header.audioEmulator; - save_record.WriteArray(&header, 1); + save_record.WriteArray(&header, 1); - bool success = save_record.WriteArray(tmpInput, (size_t)s_totalBytes); + bool success = save_record.WriteArray(tmpInput, (size_t)s_totalBytes); - if (success && s_bRecordingFromSaveState) - { - std::string stateFilename = filename + ".sav"; - success = File::Copy(File::GetUserPath(D_STATESAVES_IDX) + "dtm.sav", stateFilename); - } + if (success && s_bRecordingFromSaveState) + { + std::string stateFilename = filename + ".sav"; + success = File::Copy(File::GetUserPath(D_STATESAVES_IDX) + "dtm.sav", stateFilename); + } - if (success) - Core::DisplayMessage(StringFromFormat("DTM %s saved", filename.c_str()), 2000); - else - Core::DisplayMessage(StringFromFormat("Failed to save %s", filename.c_str()), 2000); + if (success) + Core::DisplayMessage(StringFromFormat("DTM %s saved", filename.c_str()), 2000); + else + Core::DisplayMessage(StringFromFormat("Failed to save %s", filename.c_str()), 2000); } void SetGCInputManip(GCManipFunction func) { - gcmfunc = func; + gcmfunc = func; } void SetWiiInputManip(WiiManipFunction func) { - wiimfunc = func; + wiimfunc = func; } // NOTE: CPU Thread void CallGCInputManip(GCPadStatus* PadStatus, int controllerID) { - if (gcmfunc) - (*gcmfunc)(PadStatus, controllerID); + if (gcmfunc) + (*gcmfunc)(PadStatus, controllerID); } // NOTE: CPU Thread -void CallWiiInputManip(u8* data, WiimoteEmu::ReportFeatures rptf, int controllerID, int ext, const wiimote_key key) +void CallWiiInputManip(u8* data, WiimoteEmu::ReportFeatures rptf, int controllerID, int ext, + const wiimote_key key) { - if (wiimfunc) - (*wiimfunc)(data, rptf, controllerID, ext, key); + if (wiimfunc) + (*wiimfunc)(data, rptf, controllerID, ext, key); } // NOTE: GPU Thread void SetGraphicsConfig() { - g_Config.bEFBAccessEnable = tmpHeader.bEFBAccessEnable; - g_Config.bSkipEFBCopyToRam = tmpHeader.bSkipEFBCopyToRam; - g_Config.bEFBEmulateFormatChanges = tmpHeader.bEFBEmulateFormatChanges; - g_Config.bUseXFB = tmpHeader.bUseXFB; - g_Config.bUseRealXFB = tmpHeader.bUseRealXFB; + g_Config.bEFBAccessEnable = tmpHeader.bEFBAccessEnable; + g_Config.bSkipEFBCopyToRam = tmpHeader.bSkipEFBCopyToRam; + g_Config.bEFBEmulateFormatChanges = tmpHeader.bEFBEmulateFormatChanges; + g_Config.bUseXFB = tmpHeader.bUseXFB; + g_Config.bUseRealXFB = tmpHeader.bUseRealXFB; } // NOTE: EmuThread / Host Thread void GetSettings() { - s_bSaveConfig = true; - s_bSkipIdle = SConfig::GetInstance().bSkipIdle; - s_bDualCore = SConfig::GetInstance().bCPUThread; - s_bProgressive = SConfig::GetInstance().bProgressive; - s_bPAL60 = SConfig::GetInstance().bPAL60; - s_bDSPHLE = SConfig::GetInstance().bDSPHLE; - s_bFastDiscSpeed = SConfig::GetInstance().bFastDiscSpeed; - s_videoBackend = g_video_backend->GetName(); - s_bSyncGPU = SConfig::GetInstance().bSyncGPU; - s_iCPUCore = SConfig::GetInstance().iCPUCore; - s_bNetPlay = NetPlay::IsNetPlayRunning(); - s_language = SConfig::GetInstance().m_SYSCONF->GetData("IPL.LNG"); - if (!SConfig::GetInstance().bWii) - g_bClearSave = !File::Exists(SConfig::GetInstance().m_strMemoryCardA); - s_memcards |= (SConfig::GetInstance().m_EXIDevice[0] == EXIDEVICE_MEMORYCARD) << 0; - s_memcards |= (SConfig::GetInstance().m_EXIDevice[1] == EXIDEVICE_MEMORYCARD) << 1; + s_bSaveConfig = true; + s_bSkipIdle = SConfig::GetInstance().bSkipIdle; + s_bDualCore = SConfig::GetInstance().bCPUThread; + s_bProgressive = SConfig::GetInstance().bProgressive; + s_bPAL60 = SConfig::GetInstance().bPAL60; + s_bDSPHLE = SConfig::GetInstance().bDSPHLE; + s_bFastDiscSpeed = SConfig::GetInstance().bFastDiscSpeed; + s_videoBackend = g_video_backend->GetName(); + s_bSyncGPU = SConfig::GetInstance().bSyncGPU; + s_iCPUCore = SConfig::GetInstance().iCPUCore; + s_bNetPlay = NetPlay::IsNetPlayRunning(); + s_language = SConfig::GetInstance().m_SYSCONF->GetData("IPL.LNG"); + if (!SConfig::GetInstance().bWii) + g_bClearSave = !File::Exists(SConfig::GetInstance().m_strMemoryCardA); + s_memcards |= (SConfig::GetInstance().m_EXIDevice[0] == EXIDEVICE_MEMORYCARD) << 0; + s_memcards |= (SConfig::GetInstance().m_EXIDevice[1] == EXIDEVICE_MEMORYCARD) << 1; - std::array revision = ConvertGitRevisionToBytes(scm_rev_git_str); - std::copy(std::begin(revision), std::end(revision), std::begin(s_revision)); + std::array revision = ConvertGitRevisionToBytes(scm_rev_git_str); + std::copy(std::begin(revision), std::end(revision), std::begin(s_revision)); - if (!s_bDSPHLE) - { - std::string irom_file = File::GetUserPath(D_GCUSER_IDX) + DSP_IROM; - std::string coef_file = File::GetUserPath(D_GCUSER_IDX) + DSP_COEF; + if (!s_bDSPHLE) + { + std::string irom_file = File::GetUserPath(D_GCUSER_IDX) + DSP_IROM; + std::string coef_file = File::GetUserPath(D_GCUSER_IDX) + DSP_COEF; - if (!File::Exists(irom_file)) - irom_file = File::GetSysDirectory() + GC_SYS_DIR DIR_SEP DSP_IROM; - if (!File::Exists(coef_file)) - coef_file = File::GetSysDirectory() + GC_SYS_DIR DIR_SEP DSP_COEF; - std::vector irom(DSP_IROM_SIZE); - File::IOFile file_irom(irom_file, "rb"); + if (!File::Exists(irom_file)) + irom_file = File::GetSysDirectory() + GC_SYS_DIR DIR_SEP DSP_IROM; + if (!File::Exists(coef_file)) + coef_file = File::GetSysDirectory() + GC_SYS_DIR DIR_SEP DSP_COEF; + std::vector irom(DSP_IROM_SIZE); + File::IOFile file_irom(irom_file, "rb"); - file_irom.ReadArray(irom.data(), DSP_IROM_SIZE); - file_irom.Close(); - for (u32 i = 0; i < DSP_IROM_SIZE; ++i) - irom[i] = Common::swap16(irom[i]); + file_irom.ReadArray(irom.data(), DSP_IROM_SIZE); + file_irom.Close(); + for (u32 i = 0; i < DSP_IROM_SIZE; ++i) + irom[i] = Common::swap16(irom[i]); - std::vector coef(DSP_COEF_SIZE); - File::IOFile file_coef(coef_file, "rb"); + std::vector coef(DSP_COEF_SIZE); + File::IOFile file_coef(coef_file, "rb"); - file_coef.ReadArray(coef.data(), DSP_COEF_SIZE); - file_coef.Close(); - for (u32 i = 0; i < DSP_COEF_SIZE; ++i) - coef[i] = Common::swap16(coef[i]); - s_DSPiromHash = HashAdler32((u8*)irom.data(), DSP_IROM_BYTE_SIZE); - s_DSPcoefHash = HashAdler32((u8*)coef.data(), DSP_COEF_BYTE_SIZE); - } - else - { - s_DSPiromHash = 0; - s_DSPcoefHash = 0; - } + file_coef.ReadArray(coef.data(), DSP_COEF_SIZE); + file_coef.Close(); + for (u32 i = 0; i < DSP_COEF_SIZE; ++i) + coef[i] = Common::swap16(coef[i]); + s_DSPiromHash = HashAdler32((u8*)irom.data(), DSP_IROM_BYTE_SIZE); + s_DSPcoefHash = HashAdler32((u8*)coef.data(), DSP_COEF_BYTE_SIZE); + } + else + { + s_DSPiromHash = 0; + s_DSPcoefHash = 0; + } } static const mbedtls_md_info_t* s_md5_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5); @@ -1462,40 +1502,41 @@ static const mbedtls_md_info_t* s_md5_info = mbedtls_md_info_from_type(MBEDTLS_M // NOTE: Entrypoint for own thread void CheckMD5() { - for (int i = 0, n = 0; i < 16; ++i) - { - if (tmpHeader.md5[i] != 0) - continue; - n++; - if (n == 16) - return; - } - Core::DisplayMessage("Verifying checksum...", 2000); + for (int i = 0, n = 0; i < 16; ++i) + { + if (tmpHeader.md5[i] != 0) + continue; + n++; + if (n == 16) + return; + } + Core::DisplayMessage("Verifying checksum...", 2000); - unsigned char gameMD5[16]; - mbedtls_md_file(s_md5_info, SConfig::GetInstance().m_strFilename.c_str(), gameMD5); + unsigned char gameMD5[16]; + mbedtls_md_file(s_md5_info, SConfig::GetInstance().m_strFilename.c_str(), gameMD5); - if (memcmp(gameMD5,s_MD5,16) == 0) - Core::DisplayMessage("Checksum of current game matches the recorded game.", 2000); - else - Core::DisplayMessage("Checksum of current game does not match the recorded game!", 3000); + if (memcmp(gameMD5, s_MD5, 16) == 0) + Core::DisplayMessage("Checksum of current game matches the recorded game.", 2000); + else + Core::DisplayMessage("Checksum of current game does not match the recorded game!", 3000); } // NOTE: Entrypoint for own thread void GetMD5() { - Core::DisplayMessage("Calculating checksum of game file...", 2000); - memset(s_MD5, 0, sizeof(s_MD5)); - mbedtls_md_file(s_md5_info, SConfig::GetInstance().m_strFilename.c_str(), s_MD5); - Core::DisplayMessage("Finished calculating checksum.", 2000); + Core::DisplayMessage("Calculating checksum of game file...", 2000); + memset(s_MD5, 0, sizeof(s_MD5)); + mbedtls_md_file(s_md5_info, SConfig::GetInstance().m_strFilename.c_str(), s_MD5); + Core::DisplayMessage("Finished calculating checksum.", 2000); } // NOTE: EmuThread void Shutdown() { - g_currentInputCount = g_totalInputCount = g_totalFrames = s_totalBytes = s_tickCountAtLastInput = 0; - delete [] tmpInput; - tmpInput = nullptr; - tmpInputAllocated = 0; + g_currentInputCount = g_totalInputCount = g_totalFrames = s_totalBytes = s_tickCountAtLastInput = + 0; + delete[] tmpInput; + tmpInput = nullptr; + tmpInputAllocated = 0; } }; diff --git a/Source/Core/Core/Movie.h b/Source/Core/Core/Movie.h index 350c9da28e..5edb8e3fa3 100644 --- a/Source/Core/Core/Movie.h +++ b/Source/Core/Core/Movie.h @@ -21,30 +21,29 @@ struct ReportFeatures; namespace Movie { - // Enumerations and structs enum PlayMode { - MODE_NONE = 0, - MODE_RECORDING, - MODE_PLAYING + MODE_NONE = 0, + MODE_RECORDING, + MODE_PLAYING }; // GameCube Controller State -#pragma pack(push,1) +#pragma pack(push, 1) struct ControllerState { - bool Start:1, A:1, B:1, X:1, Y:1, Z:1; // Binary buttons, 6 bits - bool DPadUp:1, DPadDown:1, // Binary D-Pad buttons, 4 bits - DPadLeft:1, DPadRight:1; - bool L:1, R:1; // Binary triggers, 2 bits - bool disc:1; // Checks for disc being changed - bool reset:1; // Console reset button - bool reserved:2; // Reserved bits used for padding, 2 bits + bool Start : 1, A : 1, B : 1, X : 1, Y : 1, Z : 1; // Binary buttons, 6 bits + bool DPadUp : 1, DPadDown : 1, // Binary D-Pad buttons, 4 bits + DPadLeft : 1, DPadRight : 1; + bool L : 1, R : 1; // Binary triggers, 2 bits + bool disc : 1; // Checks for disc being changed + bool reset : 1; // Console reset button + bool reserved : 2; // Reserved bits used for padding, 2 bits - u8 TriggerL, TriggerR; // Triggers, 16 bits - u8 AnalogStickX, AnalogStickY; // Main Stick, 16 bits - u8 CStickX, CStickY; // Sub-Stick, 16 bits + u8 TriggerL, TriggerR; // Triggers, 16 bits + u8 AnalogStickX, AnalogStickY; // Main Stick, 16 bits + u8 CStickX, CStickY; // Sub-Stick, 16 bits }; static_assert(sizeof(ControllerState) == 8, "ControllerState should be 8 bytes"); #pragma pack(pop) @@ -58,58 +57,59 @@ extern u64 g_currentLagCount; extern u64 g_currentInputCount, g_totalInputCount; extern std::string g_discChange; -#pragma pack(push,1) +#pragma pack(push, 1) struct DTMHeader { - u8 filetype[4]; // Unique Identifier (always "DTM"0x1A) + u8 filetype[4]; // Unique Identifier (always "DTM"0x1A) - char gameID[6]; // The Game ID - bool bWii; // Wii game + char gameID[6]; // The Game ID + bool bWii; // Wii game - u8 numControllers; // The number of connected controllers (1-4) + u8 numControllers; // The number of connected controllers (1-4) - bool bFromSaveState; // false indicates that the recording started from bootup, true for savestate - u64 frameCount; // Number of frames in the recording - u64 inputCount; // Number of input frames in recording - u64 lagCount; // Number of lag frames in the recording - u64 uniqueID; // (not implemented) A Unique ID comprised of: md5(time + Game ID) - u32 numRerecords; // Number of rerecords/'cuts' of this TAS - u8 author[32]; // Author's name (encoded in UTF-8) + bool + bFromSaveState; // false indicates that the recording started from bootup, true for savestate + u64 frameCount; // Number of frames in the recording + u64 inputCount; // Number of input frames in recording + u64 lagCount; // Number of lag frames in the recording + u64 uniqueID; // (not implemented) A Unique ID comprised of: md5(time + Game ID) + u32 numRerecords; // Number of rerecords/'cuts' of this TAS + u8 author[32]; // Author's name (encoded in UTF-8) - u8 videoBackend[16]; // UTF-8 representation of the video backend - u8 audioEmulator[16]; // UTF-8 representation of the audio emulator - u8 md5[16]; // MD5 of game iso + u8 videoBackend[16]; // UTF-8 representation of the video backend + u8 audioEmulator[16]; // UTF-8 representation of the audio emulator + u8 md5[16]; // MD5 of game iso - u64 recordingStartTime; // seconds since 1970 that recording started (used for RTC) + u64 recordingStartTime; // seconds since 1970 that recording started (used for RTC) - bool bSaveConfig; // Loads the settings below on startup if true - bool bSkipIdle; - bool bDualCore; - bool bProgressive; - bool bDSPHLE; - bool bFastDiscSpeed; - u8 CPUCore; // 0 = interpreter, 1 = JIT, 2 = JITIL - bool bEFBAccessEnable; - bool bEFBCopyEnable; - bool bSkipEFBCopyToRam; - bool bEFBCopyCacheEnable; - bool bEFBEmulateFormatChanges; - bool bUseXFB; - bool bUseRealXFB; - u8 memcards; - bool bClearSave; // Create a new memory card when playing back a movie if true - u8 bongos; - bool bSyncGPU; - bool bNetPlay; - bool bPAL60; - u8 language; - u8 reserved[11]; // Padding for any new config options - u8 discChange[40]; // Name of iso file to switch to, for two disc games. - u8 revision[20]; // Git hash - u32 DSPiromHash; - u32 DSPcoefHash; - u64 tickCount; // Number of ticks in the recording - u8 reserved2[11]; // Make heading 256 bytes, just because we can + bool bSaveConfig; // Loads the settings below on startup if true + bool bSkipIdle; + bool bDualCore; + bool bProgressive; + bool bDSPHLE; + bool bFastDiscSpeed; + u8 CPUCore; // 0 = interpreter, 1 = JIT, 2 = JITIL + bool bEFBAccessEnable; + bool bEFBCopyEnable; + bool bSkipEFBCopyToRam; + bool bEFBCopyCacheEnable; + bool bEFBEmulateFormatChanges; + bool bUseXFB; + bool bUseRealXFB; + u8 memcards; + bool bClearSave; // Create a new memory card when playing back a movie if true + u8 bongos; + bool bSyncGPU; + bool bNetPlay; + bool bPAL60; + u8 language; + u8 reserved[11]; // Padding for any new config options + u8 discChange[40]; // Name of iso file to switch to, for two disc games. + u8 revision[20]; // Git hash + u32 DSPiromHash; + u32 DSPcoefHash; + u64 tickCount; // Number of ticks in the recording + u8 reserved2[11]; // Make heading 256 bytes, just because we can }; static_assert(sizeof(DTMHeader) == 256, "DTMHeader should be 256 bytes"); @@ -128,7 +128,7 @@ bool IsJustStartingPlayingInputFromSaveState(); bool IsPlayingInput(); bool IsMovieActive(); bool IsReadOnly(); -u64 GetRecordingStartTime(); +u64 GetRecordingStartTime(); bool IsConfigSaved(); bool IsDualCore(); @@ -137,8 +137,8 @@ bool IsPAL60(); bool IsSkipIdle(); bool IsDSPHLE(); bool IsFastDiscSpeed(); -int GetCPUMode(); -u8 GetLanguage(); +int GetCPUMode(); +u8 GetLanguage(); bool IsStartingFromClearSave(); bool IsUsingMemcard(int memcard); bool IsSyncGPU(); @@ -160,30 +160,33 @@ void FrameSkipping(); bool BeginRecordingInput(int controllers); void RecordInput(GCPadStatus* PadStatus, int controllerID); -void RecordWiimote(int wiimote, u8 *data, u8 size); +void RecordWiimote(int wiimote, u8* data, u8 size); bool PlayInput(const std::string& filename); void LoadInput(const std::string& filename); void ReadHeader(); void PlayController(GCPadStatus* PadStatus, int controllerID); -bool PlayWiimote(int wiimote, u8* data, const struct WiimoteEmu::ReportFeatures& rptf, int ext, const wiimote_key key); +bool PlayWiimote(int wiimote, u8* data, const struct WiimoteEmu::ReportFeatures& rptf, int ext, + const wiimote_key key); void EndPlayInput(bool cont); void SaveRecording(const std::string& filename); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); void CheckMD5(); void GetMD5(); void Shutdown(); void CheckPadStatus(GCPadStatus* PadStatus, int controllerID); -void CheckWiimoteStatus(int wiimote, u8* data, const struct WiimoteEmu::ReportFeatures& rptf, int ext, const wiimote_key key); +void CheckWiimoteStatus(int wiimote, u8* data, const struct WiimoteEmu::ReportFeatures& rptf, + int ext, const wiimote_key key); std::string GetInputDisplay(); // Done this way to avoid mixing of core and gui code -typedef void(*GCManipFunction)(GCPadStatus*, int); -typedef void(*WiiManipFunction)(u8*, WiimoteEmu::ReportFeatures, int, int, wiimote_key); +typedef void (*GCManipFunction)(GCPadStatus*, int); +typedef void (*WiiManipFunction)(u8*, WiimoteEmu::ReportFeatures, int, int, wiimote_key); void SetGCInputManip(GCManipFunction); void SetWiiInputManip(WiiManipFunction); void CallGCInputManip(GCPadStatus* PadStatus, int controllerID); -void CallWiiInputManip(u8* core, WiimoteEmu::ReportFeatures rptf, int controllerID, int ext, const wiimote_key key); +void CallWiiInputManip(u8* core, WiimoteEmu::ReportFeatures rptf, int controllerID, int ext, + const wiimote_key key); } diff --git a/Source/Core/Core/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp index a8992e1a21..9170b2b03d 100644 --- a/Source/Core/Core/NetPlayClient.cpp +++ b/Source/Core/Core/NetPlayClient.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/NetPlayClient.h" #include #include #include "Common/Common.h" @@ -10,8 +11,6 @@ #include "Common/MsgHandler.h" #include "Common/Timer.h" #include "Core/ConfigManager.h" -#include "Core/Movie.h" -#include "Core/NetPlayClient.h" #include "Core/HW/EXI_DeviceIPL.h" #include "Core/HW/SI.h" #include "Core/HW/SI_DeviceGCController.h" @@ -19,1144 +18,1132 @@ #include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" +#include "Core/Movie.h" #include "InputCommon/GCAdapter.h" static std::mutex crit_netplay_client; -static NetPlayClient * netplay_client = nullptr; +static NetPlayClient* netplay_client = nullptr; static std::array s_wiimote_sources_cache; NetSettings g_NetPlaySettings; // called from ---GUI--- thread NetPlayClient::~NetPlayClient() { - // not perfect - if (m_is_running.load()) - StopGame(); + // not perfect + if (m_is_running.load()) + StopGame(); - if (m_is_connected) - { - m_do_loop.store(false); - m_thread.join(); - } + if (m_is_connected) + { + m_do_loop.store(false); + m_thread.join(); + } - if (m_server) - { - Disconnect(); - } + if (m_server) + { + Disconnect(); + } - if (g_MainNetHost.get() == m_client) - { - g_MainNetHost.release(); - } - if (m_client) - { - enet_host_destroy(m_client); - m_client = nullptr; - } + if (g_MainNetHost.get() == m_client) + { + g_MainNetHost.release(); + } + if (m_client) + { + enet_host_destroy(m_client); + m_client = nullptr; + } - if (m_traversal_client) - { - ReleaseTraversalClient(); - } + if (m_traversal_client) + { + ReleaseTraversalClient(); + } } // called from ---GUI--- thread -NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name, bool traversal, const std::string& centralServer, u16 centralPort) - : m_dialog(dialog) - , m_player_name(name) +NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, + const std::string& name, bool traversal, + const std::string& centralServer, u16 centralPort) + : m_dialog(dialog), m_player_name(name) { - ClearBuffers(); + ClearBuffers(); - if (!traversal) - { - //Direct Connection - m_client = enet_host_create(nullptr, 1, 3, 0, 0); + if (!traversal) + { + // Direct Connection + m_client = enet_host_create(nullptr, 1, 3, 0, 0); - if (m_client == nullptr) - { - PanicAlertT("Couldn't Create Client"); - } + if (m_client == nullptr) + { + PanicAlertT("Couldn't Create Client"); + } - ENetAddress addr; - enet_address_set_host(&addr, address.c_str()); - addr.port = port; + ENetAddress addr; + enet_address_set_host(&addr, address.c_str()); + addr.port = port; - m_server = enet_host_connect(m_client, &addr, 3, 0); + m_server = enet_host_connect(m_client, &addr, 3, 0); - if (m_server == nullptr) - { - PanicAlertT("Couldn't create peer."); - } + if (m_server == nullptr) + { + PanicAlertT("Couldn't create peer."); + } - ENetEvent netEvent; - int net = enet_host_service(m_client, &netEvent, 5000); - if (net > 0 && netEvent.type == ENET_EVENT_TYPE_CONNECT) - { - if (Connect()) - { - m_client->intercept = ENetUtil::InterceptCallback; - m_thread = std::thread(&NetPlayClient::ThreadFunc, this); - } - } - else - { - PanicAlertT("Failed to Connect!"); - } + ENetEvent netEvent; + int net = enet_host_service(m_client, &netEvent, 5000); + if (net > 0 && netEvent.type == ENET_EVENT_TYPE_CONNECT) + { + if (Connect()) + { + m_client->intercept = ENetUtil::InterceptCallback; + m_thread = std::thread(&NetPlayClient::ThreadFunc, this); + } + } + else + { + PanicAlertT("Failed to Connect!"); + } + } + else + { + if (address.size() > NETPLAY_CODE_SIZE) + { + PanicAlertT("Host code size is to large.\nPlease recheck that you have the correct code"); + return; + } - } - else - { - if (address.size() > NETPLAY_CODE_SIZE) - { - PanicAlertT("Host code size is to large.\nPlease recheck that you have the correct code"); - return; - } + if (!EnsureTraversalClient(centralServer, centralPort)) + return; + m_client = g_MainNetHost.get(); - if (!EnsureTraversalClient(centralServer, centralPort)) - return; - m_client = g_MainNetHost.get(); + m_traversal_client = g_TraversalClient.get(); - m_traversal_client = g_TraversalClient.get(); + // If we were disconnected in the background, reconnect. + if (m_traversal_client->m_State == TraversalClient::Failure) + m_traversal_client->ReconnectToServer(); + m_traversal_client->m_Client = this; + m_host_spec = address; + m_connection_state = ConnectionState::WaitingForTraversalClientConnection; + OnTraversalStateChanged(); + m_connecting = true; - // If we were disconnected in the background, reconnect. - if (m_traversal_client->m_State == TraversalClient::Failure) - m_traversal_client->ReconnectToServer(); - m_traversal_client->m_Client = this; - m_host_spec = address; - m_connection_state = ConnectionState::WaitingForTraversalClientConnection; - OnTraversalStateChanged(); - m_connecting = true; + Common::Timer connect_timer; + connect_timer.Start(); - Common::Timer connect_timer; - connect_timer.Start(); + while (m_connecting) + { + ENetEvent netEvent; + if (m_traversal_client) + m_traversal_client->HandleResends(); - while (m_connecting) - { - ENetEvent netEvent; - if (m_traversal_client) - m_traversal_client->HandleResends(); - - while (enet_host_service(m_client, &netEvent, 4) > 0) - { - sf::Packet rpac; - switch (netEvent.type) - { - case ENET_EVENT_TYPE_CONNECT: - m_server = netEvent.peer; - if (Connect()) - { - m_connection_state = ConnectionState::Connected; - m_thread = std::thread(&NetPlayClient::ThreadFunc, this); - } - return; - default: - break; - } - } - if (connect_timer.GetTimeElapsed() > 5000) - break; - } - PanicAlertT("Failed To Connect!"); - } + while (enet_host_service(m_client, &netEvent, 4) > 0) + { + sf::Packet rpac; + switch (netEvent.type) + { + case ENET_EVENT_TYPE_CONNECT: + m_server = netEvent.peer; + if (Connect()) + { + m_connection_state = ConnectionState::Connected; + m_thread = std::thread(&NetPlayClient::ThreadFunc, this); + } + return; + default: + break; + } + } + if (connect_timer.GetTimeElapsed() > 5000) + break; + } + PanicAlertT("Failed To Connect!"); + } } bool NetPlayClient::Connect() { - // send connect message - sf::Packet spac; - spac << scm_rev_git_str; - spac << netplay_dolphin_ver; - spac << m_player_name; - Send(spac); - enet_host_flush(m_client); - sf::Packet rpac; - // TODO: make this not hang - ENetEvent netEvent; - if (enet_host_service(m_client, &netEvent, 5000) > 0 && netEvent.type == ENET_EVENT_TYPE_RECEIVE) - { - rpac.append(netEvent.packet->data, netEvent.packet->dataLength); - enet_packet_destroy(netEvent.packet); - } - else - { - return false; - } + // send connect message + sf::Packet spac; + spac << scm_rev_git_str; + spac << netplay_dolphin_ver; + spac << m_player_name; + Send(spac); + enet_host_flush(m_client); + sf::Packet rpac; + // TODO: make this not hang + ENetEvent netEvent; + if (enet_host_service(m_client, &netEvent, 5000) > 0 && netEvent.type == ENET_EVENT_TYPE_RECEIVE) + { + rpac.append(netEvent.packet->data, netEvent.packet->dataLength); + enet_packet_destroy(netEvent.packet); + } + else + { + return false; + } - MessageId error; - rpac >> error; + MessageId error; + rpac >> error; - // got error message - if (error) - { - switch (error) - { - case CON_ERR_SERVER_FULL: - PanicAlertT("The server is full!"); - break; - case CON_ERR_VERSION_MISMATCH: - PanicAlertT("The server and client's NetPlay versions are incompatible!"); - break; - case CON_ERR_GAME_RUNNING: - PanicAlertT("The server responded: the game is currently running!"); - break; - default: - PanicAlertT("The server sent an unknown error message!"); - break; - } + // got error message + if (error) + { + switch (error) + { + case CON_ERR_SERVER_FULL: + PanicAlertT("The server is full!"); + break; + case CON_ERR_VERSION_MISMATCH: + PanicAlertT("The server and client's NetPlay versions are incompatible!"); + break; + case CON_ERR_GAME_RUNNING: + PanicAlertT("The server responded: the game is currently running!"); + break; + default: + PanicAlertT("The server sent an unknown error message!"); + break; + } - Disconnect(); - return false; - } - else - { - rpac >> m_pid; + Disconnect(); + return false; + } + else + { + rpac >> m_pid; - Player player; - player.name = m_player_name; - player.pid = m_pid; - player.revision = netplay_dolphin_ver; + Player player; + player.name = m_player_name; + player.pid = m_pid; + player.revision = netplay_dolphin_ver; - // add self to player list - m_players[m_pid] = player; - m_local_player = &m_players[m_pid]; + // add self to player list + m_players[m_pid] = player; + m_local_player = &m_players[m_pid]; - m_dialog->Update(); + m_dialog->Update(); - m_is_connected = true; + m_is_connected = true; - return true; - } + return true; + } } // called from ---NETPLAY--- thread unsigned int NetPlayClient::OnData(sf::Packet& packet) { - MessageId mid; - packet >> mid; + MessageId mid; + packet >> mid; - switch (mid) - { - case NP_MSG_PLAYER_JOIN: - { - Player player; - packet >> player.pid; - packet >> player.name; - packet >> player.revision; + switch (mid) + { + case NP_MSG_PLAYER_JOIN: + { + Player player; + packet >> player.pid; + packet >> player.name; + packet >> player.revision; - { - std::lock_guard lkp(m_crit.players); - m_players[player.pid] = player; - } + { + std::lock_guard lkp(m_crit.players); + m_players[player.pid] = player; + } - m_dialog->Update(); - } - break; + m_dialog->Update(); + } + break; - case NP_MSG_PLAYER_LEAVE: - { - PlayerId pid; - packet >> pid; + case NP_MSG_PLAYER_LEAVE: + { + PlayerId pid; + packet >> pid; - { - std::lock_guard lkp(m_crit.players); - m_players.erase(m_players.find(pid)); - } + { + std::lock_guard lkp(m_crit.players); + m_players.erase(m_players.find(pid)); + } - m_dialog->Update(); - } - break; + m_dialog->Update(); + } + break; - case NP_MSG_CHAT_MESSAGE: - { - PlayerId pid; - packet >> pid; - std::string msg; - packet >> msg; + case NP_MSG_CHAT_MESSAGE: + { + PlayerId pid; + packet >> pid; + std::string msg; + packet >> msg; - // don't need lock to read in this thread - const Player& player = m_players[pid]; + // don't need lock to read in this thread + const Player& player = m_players[pid]; - // add to gui - std::ostringstream ss; - ss << player.name << '[' << (char)(pid + '0') << "]: " << msg; + // add to gui + std::ostringstream ss; + ss << player.name << '[' << (char)(pid + '0') << "]: " << msg; - m_dialog->AppendChat(ss.str()); - } - break; + m_dialog->AppendChat(ss.str()); + } + break; - case NP_MSG_PAD_MAPPING: - { - for (PadMapping& mapping : m_pad_map) - { - packet >> mapping; - } + case NP_MSG_PAD_MAPPING: + { + for (PadMapping& mapping : m_pad_map) + { + packet >> mapping; + } - UpdateDevices(); + UpdateDevices(); - m_dialog->Update(); - } - break; + m_dialog->Update(); + } + break; - case NP_MSG_WIIMOTE_MAPPING: - { - for (PadMapping& mapping : m_wiimote_map) - { - packet >> mapping; - } + case NP_MSG_WIIMOTE_MAPPING: + { + for (PadMapping& mapping : m_wiimote_map) + { + packet >> mapping; + } - m_dialog->Update(); - } - break; + m_dialog->Update(); + } + break; - case NP_MSG_PAD_DATA: - { - PadMapping map = 0; - GCPadStatus pad; - packet >> map - >> pad.button - >> pad.analogA - >> pad.analogB - >> pad.stickX - >> pad.stickY - >> pad.substickX - >> pad.substickY - >> pad.triggerLeft - >> pad.triggerRight; + case NP_MSG_PAD_DATA: + { + PadMapping map = 0; + GCPadStatus pad; + packet >> map >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >> + pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight; - // Trusting server for good map value (>=0 && <4) - // add to pad buffer - m_pad_buffer.at(map).Push(pad); - } - break; + // Trusting server for good map value (>=0 && <4) + // add to pad buffer + m_pad_buffer.at(map).Push(pad); + } + break; - case NP_MSG_WIIMOTE_DATA: - { - PadMapping map = 0; - NetWiimote nw; - u8 size; - packet >> map >> size; + case NP_MSG_WIIMOTE_DATA: + { + PadMapping map = 0; + NetWiimote nw; + u8 size; + packet >> map >> size; - nw.resize(size); + nw.resize(size); - for (unsigned int i = 0; i < size; ++i) - packet >> nw[i]; + for (unsigned int i = 0; i < size; ++i) + packet >> nw[i]; - // Trusting server for good map value (>=0 && <4) - // add to Wiimote buffer - m_wiimote_buffer.at(map).Push(nw); - } - break; + // Trusting server for good map value (>=0 && <4) + // add to Wiimote buffer + m_wiimote_buffer.at(map).Push(nw); + } + break; + case NP_MSG_PAD_BUFFER: + { + u32 size = 0; + packet >> size; - case NP_MSG_PAD_BUFFER: - { - u32 size = 0; - packet >> size; + m_target_buffer_size = size; + } + break; - m_target_buffer_size = size; - } - break; + case NP_MSG_CHANGE_GAME: + { + { + std::lock_guard lkg(m_crit.game); + packet >> m_selected_game; + } - case NP_MSG_CHANGE_GAME: - { - { - std::lock_guard lkg(m_crit.game); - packet >> m_selected_game; - } + // update gui + m_dialog->OnMsgChangeGame(m_selected_game); + } + break; - // update gui - m_dialog->OnMsgChangeGame(m_selected_game); - } - break; + case NP_MSG_START_GAME: + { + { + std::lock_guard lkg(m_crit.game); + packet >> m_current_game; + packet >> g_NetPlaySettings.m_CPUthread; + packet >> g_NetPlaySettings.m_CPUcore; + packet >> g_NetPlaySettings.m_SelectedLanguage; + packet >> g_NetPlaySettings.m_OverrideGCLanguage; + packet >> g_NetPlaySettings.m_ProgressiveScan; + packet >> g_NetPlaySettings.m_PAL60; + packet >> g_NetPlaySettings.m_DSPEnableJIT; + packet >> g_NetPlaySettings.m_DSPHLE; + packet >> g_NetPlaySettings.m_WriteToMemcard; + packet >> g_NetPlaySettings.m_OCEnable; + packet >> g_NetPlaySettings.m_OCFactor; - case NP_MSG_START_GAME: - { - { - std::lock_guard lkg(m_crit.game); - packet >> m_current_game; - packet >> g_NetPlaySettings.m_CPUthread; - packet >> g_NetPlaySettings.m_CPUcore; - packet >> g_NetPlaySettings.m_SelectedLanguage; - packet >> g_NetPlaySettings.m_OverrideGCLanguage; - packet >> g_NetPlaySettings.m_ProgressiveScan; - packet >> g_NetPlaySettings.m_PAL60; - packet >> g_NetPlaySettings.m_DSPEnableJIT; - packet >> g_NetPlaySettings.m_DSPHLE; - packet >> g_NetPlaySettings.m_WriteToMemcard; - packet >> g_NetPlaySettings.m_OCEnable; - packet >> g_NetPlaySettings.m_OCFactor; + int tmp; + packet >> tmp; + g_NetPlaySettings.m_EXIDevice[0] = (TEXIDevices)tmp; + packet >> tmp; + g_NetPlaySettings.m_EXIDevice[1] = (TEXIDevices)tmp; - int tmp; - packet >> tmp; - g_NetPlaySettings.m_EXIDevice[0] = (TEXIDevices)tmp; - packet >> tmp; - g_NetPlaySettings.m_EXIDevice[1] = (TEXIDevices)tmp; + u32 time_low, time_high; + packet >> time_low; + packet >> time_high; + g_netplay_initial_gctime = time_low | ((u64)time_high << 32); + } - u32 time_low, time_high; - packet >> time_low; - packet >> time_high; - g_netplay_initial_gctime = time_low | ((u64)time_high << 32); - } + m_dialog->OnMsgStartGame(); + } + break; - m_dialog->OnMsgStartGame(); - } - break; + case NP_MSG_STOP_GAME: + { + m_dialog->OnMsgStopGame(); + } + break; - case NP_MSG_STOP_GAME: - { - m_dialog->OnMsgStopGame(); - } - break; + case NP_MSG_DISABLE_GAME: + { + PanicAlertT("Other client disconnected while game is running!! NetPlay is disabled. You must " + "manually stop the game."); + m_is_running.store(false); + NetPlay_Disable(); + } + break; - case NP_MSG_DISABLE_GAME: - { - PanicAlertT("Other client disconnected while game is running!! NetPlay is disabled. You must manually stop the game."); - m_is_running.store(false); - NetPlay_Disable(); - } - break; + case NP_MSG_PING: + { + u32 ping_key = 0; + packet >> ping_key; - case NP_MSG_PING: - { - u32 ping_key = 0; - packet >> ping_key; + sf::Packet spac; + spac << (MessageId)NP_MSG_PONG; + spac << ping_key; - sf::Packet spac; - spac << (MessageId)NP_MSG_PONG; - spac << ping_key; + Send(spac); + } + break; - Send(spac); - } - break; + case NP_MSG_PLAYER_PING_DATA: + { + PlayerId pid; + packet >> pid; - case NP_MSG_PLAYER_PING_DATA: - { - PlayerId pid; - packet >> pid; + { + std::lock_guard lkp(m_crit.players); + Player& player = m_players[pid]; + packet >> player.ping; + } - { - std::lock_guard lkp(m_crit.players); - Player& player = m_players[pid]; - packet >> player.ping; - } + m_dialog->Update(); + } + break; - m_dialog->Update(); - } - break; + case NP_MSG_DESYNC_DETECTED: + { + int pid_to_blame; + u32 frame; + packet >> pid_to_blame; + packet >> frame; + const char* blame_str = ""; + const char* blame_name = ""; + std::lock_guard lkp(m_crit.players); + if (pid_to_blame != -1) + { + auto it = m_players.find(pid_to_blame); + blame_str = " from player "; + blame_name = it != m_players.end() ? it->second.name.c_str() : "??"; + } - case NP_MSG_DESYNC_DETECTED: - { - int pid_to_blame; - u32 frame; - packet >> pid_to_blame; - packet >> frame; - const char* blame_str = ""; - const char* blame_name = ""; - std::lock_guard lkp(m_crit.players); - if (pid_to_blame != -1) - { - auto it = m_players.find(pid_to_blame); - blame_str = " from player "; - blame_name = it != m_players.end() ? it->second.name.c_str() : "??"; - } + m_dialog->AppendChat(StringFromFormat("/!\\ Possible desync detected%s%s on frame %u", + blame_str, blame_name, frame)); + } + break; - m_dialog->AppendChat(StringFromFormat("/!\\ Possible desync detected%s%s on frame %u", blame_str, blame_name, frame)); - } - break; + case NP_MSG_SYNC_GC_SRAM: + { + u8 sram[sizeof(g_SRAM.p_SRAM)]; + for (size_t i = 0; i < sizeof(g_SRAM.p_SRAM); ++i) + { + packet >> sram[i]; + } - case NP_MSG_SYNC_GC_SRAM: - { - u8 sram[sizeof(g_SRAM.p_SRAM)]; - for (size_t i = 0; i < sizeof(g_SRAM.p_SRAM); ++i) - { - packet >> sram[i]; - } + { + std::lock_guard lkg(m_crit.game); + memcpy(g_SRAM.p_SRAM, sram, sizeof(g_SRAM.p_SRAM)); + g_SRAM_netplay_initialized = true; + } + } + break; - { - std::lock_guard lkg(m_crit.game); - memcpy(g_SRAM.p_SRAM, sram, sizeof(g_SRAM.p_SRAM)); - g_SRAM_netplay_initialized = true; - } - } - break; + default: + PanicAlertT("Unknown message received with id : %d", mid); + break; + } - default: - PanicAlertT("Unknown message received with id : %d", mid); - break; - - } - - return 0; + return 0; } void NetPlayClient::Send(sf::Packet& packet) { - ENetPacket* epac = enet_packet_create(packet.getData(), packet.getDataSize(), ENET_PACKET_FLAG_RELIABLE); - enet_peer_send(m_server, 0, epac); + ENetPacket* epac = + enet_packet_create(packet.getData(), packet.getDataSize(), ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(m_server, 0, epac); } void NetPlayClient::Disconnect() { - ENetEvent netEvent; - m_connecting = false; - m_connection_state = ConnectionState::Failure; - if (m_server) - enet_peer_disconnect(m_server, 0); - else - return; + ENetEvent netEvent; + m_connecting = false; + m_connection_state = ConnectionState::Failure; + if (m_server) + enet_peer_disconnect(m_server, 0); + else + return; - while (enet_host_service(m_client, &netEvent, 3000) > 0) - { - switch (netEvent.type) - { - case ENET_EVENT_TYPE_RECEIVE: - enet_packet_destroy(netEvent.packet); - break; - case ENET_EVENT_TYPE_DISCONNECT: - m_server = nullptr; - return; - default: - break; - } - } - //didn't disconnect gracefully force disconnect - enet_peer_reset(m_server); - m_server = nullptr; + while (enet_host_service(m_client, &netEvent, 3000) > 0) + { + switch (netEvent.type) + { + case ENET_EVENT_TYPE_RECEIVE: + enet_packet_destroy(netEvent.packet); + break; + case ENET_EVENT_TYPE_DISCONNECT: + m_server = nullptr; + return; + default: + break; + } + } + // didn't disconnect gracefully force disconnect + enet_peer_reset(m_server); + m_server = nullptr; } void NetPlayClient::SendAsync(std::unique_ptr packet) { - { - std::lock_guard lkq(m_crit.async_queue_write); - m_async_queue.Push(std::move(packet)); - } - ENetUtil::WakeupThread(m_client); + { + std::lock_guard lkq(m_crit.async_queue_write); + m_async_queue.Push(std::move(packet)); + } + ENetUtil::WakeupThread(m_client); } // called from ---NETPLAY--- thread void NetPlayClient::ThreadFunc() { - while (m_do_loop.load()) - { - ENetEvent netEvent; - int net; - if (m_traversal_client) - m_traversal_client->HandleResends(); - net = enet_host_service(m_client, &netEvent, 250); - while (!m_async_queue.Empty()) - { - Send(*(m_async_queue.Front().get())); - m_async_queue.Pop(); - } - if (net > 0) - { - sf::Packet rpac; - switch (netEvent.type) - { - case ENET_EVENT_TYPE_RECEIVE: - rpac.append(netEvent.packet->data, netEvent.packet->dataLength); - OnData(rpac); + while (m_do_loop.load()) + { + ENetEvent netEvent; + int net; + if (m_traversal_client) + m_traversal_client->HandleResends(); + net = enet_host_service(m_client, &netEvent, 250); + while (!m_async_queue.Empty()) + { + Send(*(m_async_queue.Front().get())); + m_async_queue.Pop(); + } + if (net > 0) + { + sf::Packet rpac; + switch (netEvent.type) + { + case ENET_EVENT_TYPE_RECEIVE: + rpac.append(netEvent.packet->data, netEvent.packet->dataLength); + OnData(rpac); - enet_packet_destroy(netEvent.packet); - break; - case ENET_EVENT_TYPE_DISCONNECT: - m_is_running.store(false); - NetPlay_Disable(); - m_dialog->AppendChat("< LOST CONNECTION TO SERVER >"); - PanicAlertT("Lost connection to server!"); - m_do_loop.store(false); + enet_packet_destroy(netEvent.packet); + break; + case ENET_EVENT_TYPE_DISCONNECT: + m_is_running.store(false); + NetPlay_Disable(); + m_dialog->AppendChat("< LOST CONNECTION TO SERVER >"); + PanicAlertT("Lost connection to server!"); + m_do_loop.store(false); - netEvent.peer->data = nullptr; - break; - default: - break; - } - } - } + netEvent.peer->data = nullptr; + break; + default: + break; + } + } + } - Disconnect(); - return; + Disconnect(); + return; } // called from ---GUI--- thread void NetPlayClient::GetPlayerList(std::string& list, std::vector& pid_list) { - std::lock_guard lkp(m_crit.players); + std::lock_guard lkp(m_crit.players); - std::ostringstream ss; + std::ostringstream ss; - const auto enumerate_player_controller_mappings = [&ss](const PadMappingArray& mappings, const Player& player) { - for (size_t i = 0; i < mappings.size(); i++) - { - if (mappings[i] == player.pid) - ss << i + 1; - else - ss << '-'; - } - }; + const auto enumerate_player_controller_mappings = [&ss](const PadMappingArray& mappings, + const Player& player) { + for (size_t i = 0; i < mappings.size(); i++) + { + if (mappings[i] == player.pid) + ss << i + 1; + else + ss << '-'; + } + }; - for (const auto& entry : m_players) - { - const Player& player = entry.second; - ss << player.name << "[" << static_cast(player.pid) << "] : " << player.revision << " | "; + for (const auto& entry : m_players) + { + const Player& player = entry.second; + ss << player.name << "[" << static_cast(player.pid) << "] : " << player.revision << " | "; - enumerate_player_controller_mappings(m_pad_map, player); - enumerate_player_controller_mappings(m_wiimote_map, player); + enumerate_player_controller_mappings(m_pad_map, player); + enumerate_player_controller_mappings(m_wiimote_map, player); - ss << " |\nPing: " << player.ping << "ms\n\n"; - pid_list.push_back(player.pid); - } + ss << " |\nPing: " << player.ping << "ms\n\n"; + pid_list.push_back(player.pid); + } - list = ss.str(); + list = ss.str(); } // called from ---GUI--- thread std::vector NetPlayClient::GetPlayers() { - std::lock_guard lkp(m_crit.players); - std::vector players; + std::lock_guard lkp(m_crit.players); + std::vector players; - for (const auto& pair : m_players) - players.push_back(&pair.second); + for (const auto& pair : m_players) + players.push_back(&pair.second); - return players; + return players; } // called from ---GUI--- thread void NetPlayClient::SendChatMessage(const std::string& msg) { - auto spac = std::make_unique(); - *spac << static_cast(NP_MSG_CHAT_MESSAGE); - *spac << msg; + auto spac = std::make_unique(); + *spac << static_cast(NP_MSG_CHAT_MESSAGE); + *spac << msg; - SendAsync(std::move(spac)); + SendAsync(std::move(spac)); } // called from ---CPU--- thread void NetPlayClient::SendPadState(const PadMapping in_game_pad, const GCPadStatus& pad) { - auto spac = std::make_unique(); - *spac << static_cast(NP_MSG_PAD_DATA); - *spac << in_game_pad; - *spac << pad.button - << pad.analogA - << pad.analogB - << pad.stickX - << pad.stickY - << pad.substickX - << pad.substickY - << pad.triggerLeft - << pad.triggerRight; + auto spac = std::make_unique(); + *spac << static_cast(NP_MSG_PAD_DATA); + *spac << in_game_pad; + *spac << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX + << pad.substickY << pad.triggerLeft << pad.triggerRight; - SendAsync(std::move(spac)); + SendAsync(std::move(spac)); } // called from ---CPU--- thread void NetPlayClient::SendWiimoteState(const PadMapping in_game_pad, const NetWiimote& nw) { - auto spac = std::make_unique(); - *spac << static_cast(NP_MSG_WIIMOTE_DATA); - *spac << in_game_pad; - *spac << static_cast(nw.size()); - for (auto it : nw) - { - *spac << it; - } + auto spac = std::make_unique(); + *spac << static_cast(NP_MSG_WIIMOTE_DATA); + *spac << in_game_pad; + *spac << static_cast(nw.size()); + for (auto it : nw) + { + *spac << it; + } - SendAsync(std::move(spac)); + SendAsync(std::move(spac)); } // called from ---GUI--- thread void NetPlayClient::SendStartGamePacket() { - auto spac = std::make_unique(); - *spac << static_cast(NP_MSG_START_GAME); - *spac << m_current_game; + auto spac = std::make_unique(); + *spac << static_cast(NP_MSG_START_GAME); + *spac << m_current_game; - SendAsync(std::move(spac)); + SendAsync(std::move(spac)); } // called from ---GUI--- thread void NetPlayClient::SendStopGamePacket() { - auto spac = std::make_unique(); - *spac << static_cast(NP_MSG_STOP_GAME); + auto spac = std::make_unique(); + *spac << static_cast(NP_MSG_STOP_GAME); - SendAsync(std::move(spac)); + SendAsync(std::move(spac)); } // called from ---GUI--- thread -bool NetPlayClient::StartGame(const std::string &path) +bool NetPlayClient::StartGame(const std::string& path) { - std::lock_guard lkg(m_crit.game); - SendStartGamePacket(); + std::lock_guard lkg(m_crit.game); + SendStartGamePacket(); - if (m_is_running.load()) - { - PanicAlertT("Game is already running!"); - return false; - } + if (m_is_running.load()) + { + PanicAlertT("Game is already running!"); + return false; + } - m_dialog->AppendChat(" -- STARTING GAME -- "); + m_dialog->AppendChat(" -- STARTING GAME -- "); - m_timebase_frame = 0; + m_timebase_frame = 0; - m_is_running.store(true); - NetPlay_Enable(this); + m_is_running.store(true); + NetPlay_Enable(this); - ClearBuffers(); + ClearBuffers(); - if (m_dialog->IsRecording()) - { + if (m_dialog->IsRecording()) + { + if (Movie::IsReadOnly()) + Movie::SetReadOnly(false); - if (Movie::IsReadOnly()) - Movie::SetReadOnly(false); + u8 controllers_mask = 0; + for (unsigned int i = 0; i < 4; ++i) + { + if (m_pad_map[i] > 0) + controllers_mask |= (1 << i); + if (m_wiimote_map[i] > 0) + controllers_mask |= (1 << (i + 4)); + } + Movie::BeginRecordingInput(controllers_mask); + } - u8 controllers_mask = 0; - for (unsigned int i = 0; i < 4; ++i) - { - if (m_pad_map[i] > 0) - controllers_mask |= (1 << i); - if (m_wiimote_map[i] > 0) - controllers_mask |= (1 << (i + 4)); - } - Movie::BeginRecordingInput(controllers_mask); - } + // boot game - // boot game + m_dialog->BootGame(path); - m_dialog->BootGame(path); + // Disable wiimotes on game start + // TODO: remove this when re-implementing wiimote netplay + if (SConfig::GetInstance().bWii) + { + for (unsigned int i = 0; i < 4; ++i) + { + s_wiimote_sources_cache[i] = g_wiimote_sources[i]; + WiimoteReal::ChangeWiimoteSource(i, WIIMOTE_SRC_NONE); + } + } - // Disable wiimotes on game start - // TODO: remove this when re-implementing wiimote netplay - if (SConfig::GetInstance().bWii) - { - for (unsigned int i = 0; i < 4; ++i) - { - s_wiimote_sources_cache[i] = g_wiimote_sources[i]; - WiimoteReal::ChangeWiimoteSource(i, WIIMOTE_SRC_NONE); - } - } + UpdateDevices(); - UpdateDevices(); - - return true; + return true; } // called from ---GUI--- thread bool NetPlayClient::ChangeGame(const std::string&) { - return true; + return true; } // called from ---NETPLAY--- thread void NetPlayClient::UpdateDevices() { - u8 local_pad = 0; - u8 pad = 0; + u8 local_pad = 0; + u8 pad = 0; - for (auto player_id : m_pad_map) - { - // Use local controller types for local controllers if they are compatible - // Only GCController-like controllers are supported, GBA and similar - // exotic devices are not supported on netplay. - if (player_id == m_local_player->pid) - { - if (SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[local_pad])) - { - SerialInterface::AddDevice(SConfig::GetInstance().m_SIDevice[local_pad], pad); - } - else - { - SerialInterface::AddDevice(SIDEVICE_GC_CONTROLLER, pad); - } - local_pad++; - } - else if (player_id > 0) - { - SerialInterface::AddDevice(SIDEVICE_GC_CONTROLLER, pad); - } - else - { - SerialInterface::AddDevice(SIDEVICE_NONE, pad); - } - pad++; - } + for (auto player_id : m_pad_map) + { + // Use local controller types for local controllers if they are compatible + // Only GCController-like controllers are supported, GBA and similar + // exotic devices are not supported on netplay. + if (player_id == m_local_player->pid) + { + if (SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[local_pad])) + { + SerialInterface::AddDevice(SConfig::GetInstance().m_SIDevice[local_pad], pad); + } + else + { + SerialInterface::AddDevice(SIDEVICE_GC_CONTROLLER, pad); + } + local_pad++; + } + else if (player_id > 0) + { + SerialInterface::AddDevice(SIDEVICE_GC_CONTROLLER, pad); + } + else + { + SerialInterface::AddDevice(SIDEVICE_NONE, pad); + } + pad++; + } } // called from ---NETPLAY--- thread void NetPlayClient::ClearBuffers() { - // clear pad buffers, Clear method isn't thread safe - for (unsigned int i = 0; i<4; ++i) - { - while (m_pad_buffer[i].Size()) - m_pad_buffer[i].Pop(); + // clear pad buffers, Clear method isn't thread safe + for (unsigned int i = 0; i < 4; ++i) + { + while (m_pad_buffer[i].Size()) + m_pad_buffer[i].Pop(); - while (m_wiimote_buffer[i].Size()) - m_wiimote_buffer[i].Pop(); - } + while (m_wiimote_buffer[i].Size()) + m_wiimote_buffer[i].Pop(); + } } // called from ---NETPLAY--- thread void NetPlayClient::OnTraversalStateChanged() { - if (m_connection_state == ConnectionState::WaitingForTraversalClientConnection && - m_traversal_client->m_State == TraversalClient::Connected) - { - m_connection_state = ConnectionState::WaitingForTraversalClientConnectReady; - m_traversal_client->ConnectToClient(m_host_spec); - } - else if (m_connection_state != ConnectionState::Failure && - m_traversal_client->m_State == TraversalClient::Failure) - { - Disconnect(); - } + if (m_connection_state == ConnectionState::WaitingForTraversalClientConnection && + m_traversal_client->m_State == TraversalClient::Connected) + { + m_connection_state = ConnectionState::WaitingForTraversalClientConnectReady; + m_traversal_client->ConnectToClient(m_host_spec); + } + else if (m_connection_state != ConnectionState::Failure && + m_traversal_client->m_State == TraversalClient::Failure) + { + Disconnect(); + } } // called from ---NETPLAY--- thread void NetPlayClient::OnConnectReady(ENetAddress addr) { - if (m_connection_state == ConnectionState::WaitingForTraversalClientConnectReady) - { - m_connection_state = ConnectionState::Connecting; - enet_host_connect(m_client, &addr, 0, 0); - } + if (m_connection_state == ConnectionState::WaitingForTraversalClientConnectReady) + { + m_connection_state = ConnectionState::Connecting; + enet_host_connect(m_client, &addr, 0, 0); + } } // called from ---NETPLAY--- thread void NetPlayClient::OnConnectFailed(u8 reason) { - m_connecting = false; - m_connection_state = ConnectionState::Failure; - switch (reason) - { - case TraversalConnectFailedClientDidntRespond: - PanicAlertT("Traversal server timed out connecting to the host"); - break; - case TraversalConnectFailedClientFailure: - PanicAlertT("Server rejected traversal attempt"); - break; - case TraversalConnectFailedNoSuchClient: - PanicAlertT("Invalid host"); - break; - default: - PanicAlertT("Unknown error %x", reason); - break; - } + m_connecting = false; + m_connection_state = ConnectionState::Failure; + switch (reason) + { + case TraversalConnectFailedClientDidntRespond: + PanicAlertT("Traversal server timed out connecting to the host"); + break; + case TraversalConnectFailedClientFailure: + PanicAlertT("Server rejected traversal attempt"); + break; + case TraversalConnectFailedNoSuchClient: + PanicAlertT("Invalid host"); + break; + default: + PanicAlertT("Unknown error %x", reason); + break; + } } // called from ---CPU--- thread bool NetPlayClient::GetNetPads(const u8 pad_nb, GCPadStatus* pad_status) { - // The interface for this is extremely silly. - // - // Imagine a physical device that links three GameCubes together - // and emulates NetPlay that way. Which GameCube controls which - // in-game controllers can be configured on the device (m_pad_map) - // but which sockets on each individual GameCube should be used - // to control which players? The solution that Dolphin uses is - // that we hardcode the knowledge that they go in order, so if - // you have a 3P game with three GameCubes, then every single - // controller should be plugged into slot 1. - // - // If you have a 4P game, then one of the GameCubes will have - // a controller plugged into slot 1, and another in slot 2. - // - // The slot number is the "local" pad number, and what player - // it actually means is the "in-game" pad number. + // The interface for this is extremely silly. + // + // Imagine a physical device that links three GameCubes together + // and emulates NetPlay that way. Which GameCube controls which + // in-game controllers can be configured on the device (m_pad_map) + // but which sockets on each individual GameCube should be used + // to control which players? The solution that Dolphin uses is + // that we hardcode the knowledge that they go in order, so if + // you have a 3P game with three GameCubes, then every single + // controller should be plugged into slot 1. + // + // If you have a 4P game, then one of the GameCubes will have + // a controller plugged into slot 1, and another in slot 2. + // + // The slot number is the "local" pad number, and what player + // it actually means is the "in-game" pad number. - // When the 1st in-game pad is polled, we assume the others will - // will be polled as well. To reduce latency, we poll all local - // controllers at once and then send the status to the other - // clients. - if (IsFirstInGamePad(pad_nb)) - { - const u8 num_local_pads = NumLocalPads(); - for (u8 local_pad = 0; local_pad < num_local_pads; local_pad++) - { - switch (SConfig::GetInstance().m_SIDevice[local_pad]) - { - case SIDEVICE_WIIU_ADAPTER: - GCAdapter::Input(local_pad, pad_status); - break; - case SIDEVICE_GC_CONTROLLER: - default: - Pad::GetStatus(local_pad, pad_status); - break; - } + // When the 1st in-game pad is polled, we assume the others will + // will be polled as well. To reduce latency, we poll all local + // controllers at once and then send the status to the other + // clients. + if (IsFirstInGamePad(pad_nb)) + { + const u8 num_local_pads = NumLocalPads(); + for (u8 local_pad = 0; local_pad < num_local_pads; local_pad++) + { + switch (SConfig::GetInstance().m_SIDevice[local_pad]) + { + case SIDEVICE_WIIU_ADAPTER: + GCAdapter::Input(local_pad, pad_status); + break; + case SIDEVICE_GC_CONTROLLER: + default: + Pad::GetStatus(local_pad, pad_status); + break; + } - u8 ingame_pad = LocalPadToInGamePad(local_pad); + u8 ingame_pad = LocalPadToInGamePad(local_pad); - // adjust the buffer either up or down - // inserting multiple padstates or dropping states - while (m_pad_buffer[ingame_pad].Size() <= m_target_buffer_size) - { - // add to buffer - m_pad_buffer[ingame_pad].Push(*pad_status); + // adjust the buffer either up or down + // inserting multiple padstates or dropping states + while (m_pad_buffer[ingame_pad].Size() <= m_target_buffer_size) + { + // add to buffer + m_pad_buffer[ingame_pad].Push(*pad_status); - // send - SendPadState(ingame_pad, *pad_status); - } - } - } + // send + SendPadState(ingame_pad, *pad_status); + } + } + } - // Now, we either use the data pushed earlier, or wait for the - // other clients to send it to us - while (!m_pad_buffer[pad_nb].Pop(*pad_status)) - { - if (!m_is_running.load()) - return false; + // Now, we either use the data pushed earlier, or wait for the + // other clients to send it to us + while (!m_pad_buffer[pad_nb].Pop(*pad_status)) + { + if (!m_is_running.load()) + return false; - // TODO: use a condition instead of sleeping - Common::SleepCurrentThread(1); - } + // TODO: use a condition instead of sleeping + Common::SleepCurrentThread(1); + } - if (Movie::IsRecordingInput()) - { - Movie::RecordInput(pad_status, pad_nb); - Movie::InputUpdate(); - } - else - { - Movie::CheckPadStatus(pad_status, pad_nb); - } + if (Movie::IsRecordingInput()) + { + Movie::RecordInput(pad_status, pad_nb); + Movie::InputUpdate(); + } + else + { + Movie::CheckPadStatus(pad_status, pad_nb); + } - return true; + return true; } - // called from ---CPU--- thread bool NetPlayClient::WiimoteUpdate(int _number, u8* data, const u8 size) { - NetWiimote nw; - static u8 previousSize[4] = { 4, 4, 4, 4 }; - { - std::lock_guard lkp(m_crit.players); + NetWiimote nw; + static u8 previousSize[4] = {4, 4, 4, 4}; + { + std::lock_guard lkp(m_crit.players); - // in game mapping for this local Wiimote - unsigned int in_game_num = LocalWiimoteToInGameWiimote(_number); - // does this local Wiimote map in game? - if (in_game_num < 4) - { - if (previousSize[in_game_num] == size) - { - nw.assign(data, data + size); - do - { - // add to buffer - m_wiimote_buffer[in_game_num].Push(nw); + // in game mapping for this local Wiimote + unsigned int in_game_num = LocalWiimoteToInGameWiimote(_number); + // does this local Wiimote map in game? + if (in_game_num < 4) + { + if (previousSize[in_game_num] == size) + { + nw.assign(data, data + size); + do + { + // add to buffer + m_wiimote_buffer[in_game_num].Push(nw); - SendWiimoteState(in_game_num, nw); - } while (m_wiimote_buffer[in_game_num].Size() <= m_target_buffer_size * 200 / 120); // TODO: add a seperate setting for wiimote buffer? - } - else - { - while (m_wiimote_buffer[in_game_num].Size() > 0) - { - // Reporting mode changed, so previous buffer is no good. - m_wiimote_buffer[in_game_num].Pop(); - } - nw.resize(size, 0); + SendWiimoteState(in_game_num, nw); + } while (m_wiimote_buffer[in_game_num].Size() <= + m_target_buffer_size * 200 / + 120); // TODO: add a seperate setting for wiimote buffer? + } + else + { + while (m_wiimote_buffer[in_game_num].Size() > 0) + { + // Reporting mode changed, so previous buffer is no good. + m_wiimote_buffer[in_game_num].Pop(); + } + nw.resize(size, 0); - m_wiimote_buffer[in_game_num].Push(nw); - m_wiimote_buffer[in_game_num].Push(nw); - m_wiimote_buffer[in_game_num].Push(nw); - m_wiimote_buffer[in_game_num].Push(nw); - m_wiimote_buffer[in_game_num].Push(nw); - m_wiimote_buffer[in_game_num].Push(nw); - previousSize[in_game_num] = size; - } - } + m_wiimote_buffer[in_game_num].Push(nw); + m_wiimote_buffer[in_game_num].Push(nw); + m_wiimote_buffer[in_game_num].Push(nw); + m_wiimote_buffer[in_game_num].Push(nw); + m_wiimote_buffer[in_game_num].Push(nw); + m_wiimote_buffer[in_game_num].Push(nw); + previousSize[in_game_num] = size; + } + } - } // unlock players + } // unlock players - while (previousSize[_number] == size && !m_wiimote_buffer[_number].Pop(nw)) - { - // wait for receiving thread to push some data - Common::SleepCurrentThread(1); - if (!m_is_running.load()) - return false; - } + while (previousSize[_number] == size && !m_wiimote_buffer[_number].Pop(nw)) + { + // wait for receiving thread to push some data + Common::SleepCurrentThread(1); + if (!m_is_running.load()) + return false; + } - // Use a blank input, since we may not have any valid input. - if (previousSize[_number] != size) - { - nw.resize(size, 0); - m_wiimote_buffer[_number].Push(nw); - m_wiimote_buffer[_number].Push(nw); - m_wiimote_buffer[_number].Push(nw); - m_wiimote_buffer[_number].Push(nw); - m_wiimote_buffer[_number].Push(nw); - } + // Use a blank input, since we may not have any valid input. + if (previousSize[_number] != size) + { + nw.resize(size, 0); + m_wiimote_buffer[_number].Push(nw); + m_wiimote_buffer[_number].Push(nw); + m_wiimote_buffer[_number].Push(nw); + m_wiimote_buffer[_number].Push(nw); + m_wiimote_buffer[_number].Push(nw); + } - // We should have used a blank input last time, so now we just need to pop through the old buffer, until we reach a good input - if (nw.size() != size) - { - u8 tries = 0; - // Clear the buffer and wait for new input, since we probably just changed reporting mode. - while (nw.size() != size) - { - while (!m_wiimote_buffer[_number].Pop(nw)) - { - Common::SleepCurrentThread(1); - if (!m_is_running.load()) - return false; - } - ++tries; - if (tries > m_target_buffer_size * 200 / 120) - break; - } + // We should have used a blank input last time, so now we just need to pop through the old buffer, + // until we reach a good input + if (nw.size() != size) + { + u8 tries = 0; + // Clear the buffer and wait for new input, since we probably just changed reporting mode. + while (nw.size() != size) + { + while (!m_wiimote_buffer[_number].Pop(nw)) + { + Common::SleepCurrentThread(1); + if (!m_is_running.load()) + return false; + } + ++tries; + if (tries > m_target_buffer_size * 200 / 120) + break; + } - // If it still mismatches, it surely desynced - if (size != nw.size()) - { - PanicAlertT("Netplay has desynced. There is no way to recover from this."); - return false; - } - } + // If it still mismatches, it surely desynced + if (size != nw.size()) + { + PanicAlertT("Netplay has desynced. There is no way to recover from this."); + return false; + } + } - previousSize[_number] = size; - memcpy(data, nw.data(), size); - return true; + previousSize[_number] = size; + memcpy(data, nw.data(), size); + return true; } // called from ---GUI--- thread and ---NETPLAY--- thread (client side) bool NetPlayClient::StopGame() { - if (!m_is_running.load()) - { - PanicAlertT("Game isn't running!"); - return false; - } + if (!m_is_running.load()) + { + PanicAlertT("Game isn't running!"); + return false; + } - m_dialog->AppendChat(" -- STOPPING GAME -- "); + m_dialog->AppendChat(" -- STOPPING GAME -- "); - m_is_running.store(false); - NetPlay_Disable(); + m_is_running.store(false); + NetPlay_Disable(); - // stop game - m_dialog->StopGame(); + // stop game + m_dialog->StopGame(); - // Restore wiimote settings on game stop - // TODO: remove this when re-implementing wiimote netplay - if (SConfig::GetInstance().bWii) - { - for (unsigned int i = 0; i < 4; ++i) - { - g_wiimote_sources[i] = s_wiimote_sources_cache[i]; - WiimoteReal::ChangeWiimoteSource(i, s_wiimote_sources_cache[i]); - } - } + // Restore wiimote settings on game stop + // TODO: remove this when re-implementing wiimote netplay + if (SConfig::GetInstance().bWii) + { + for (unsigned int i = 0; i < 4; ++i) + { + g_wiimote_sources[i] = s_wiimote_sources_cache[i]; + WiimoteReal::ChangeWiimoteSource(i, s_wiimote_sources_cache[i]); + } + } - return true; + return true; } // called from ---GUI--- thread void NetPlayClient::Stop() { - if (!m_is_running.load()) - return; + if (!m_is_running.load()) + return; - // Tell the server to stop if we have a pad mapped in game. - if (LocalPlayerHasControllerMapped()) - SendStopGamePacket(); + // Tell the server to stop if we have a pad mapped in game. + if (LocalPlayerHasControllerMapped()) + SendStopGamePacket(); } // called from ---GUI--- thread bool NetPlayClient::LocalPlayerHasControllerMapped() const { - const auto mapping_matches_player_id = [this](const PadMapping& mapping) { - return mapping == m_local_player->pid; - }; + const auto mapping_matches_player_id = [this](const PadMapping& mapping) { + return mapping == m_local_player->pid; + }; - return std::any_of(m_pad_map.begin(), m_pad_map.end(), mapping_matches_player_id) || - std::any_of(m_wiimote_map.begin(), m_wiimote_map.end(), mapping_matches_player_id); + return std::any_of(m_pad_map.begin(), m_pad_map.end(), mapping_matches_player_id) || + std::any_of(m_wiimote_map.begin(), m_wiimote_map.end(), mapping_matches_player_id); } bool NetPlayClient::IsFirstInGamePad(u8 ingame_pad) const { - return std::none_of(m_pad_map.begin(), m_pad_map.begin() + ingame_pad, [](auto mapping) { - return mapping > 0; - }); + return std::none_of(m_pad_map.begin(), m_pad_map.begin() + ingame_pad, + [](auto mapping) { return mapping > 0; }); } u8 NetPlayClient::NumLocalPads() const { - return static_cast(std::count_if(m_pad_map.begin(), m_pad_map.end(), [this](auto mapping) { - return mapping == m_local_player->pid; - })); + return static_cast(std::count_if(m_pad_map.begin(), m_pad_map.end(), [this](auto mapping) { + return mapping == m_local_player->pid; + })); } u8 NetPlayClient::InGamePadToLocalPad(u8 ingame_pad) { - // not our pad - if (m_pad_map[ingame_pad] != m_local_player->pid) - return 4; + // not our pad + if (m_pad_map[ingame_pad] != m_local_player->pid) + return 4; - int local_pad = 0; - int pad = 0; + int local_pad = 0; + int pad = 0; - for (; pad < ingame_pad; pad++) - { - if (m_pad_map[pad] == m_local_player->pid) - local_pad++; - } + for (; pad < ingame_pad; pad++) + { + if (m_pad_map[pad] == m_local_player->pid) + local_pad++; + } - return local_pad; + return local_pad; } u8 NetPlayClient::LocalPadToInGamePad(u8 local_pad) { - // Figure out which in-game pad maps to which local pad. - // The logic we have here is that the local slots always - // go in order. - int local_pad_count = -1; - int ingame_pad = 0; - for (; ingame_pad < 4; ingame_pad++) - { - if (m_pad_map[ingame_pad] == m_local_player->pid) - local_pad_count++; + // Figure out which in-game pad maps to which local pad. + // The logic we have here is that the local slots always + // go in order. + int local_pad_count = -1; + int ingame_pad = 0; + for (; ingame_pad < 4; ingame_pad++) + { + if (m_pad_map[ingame_pad] == m_local_player->pid) + local_pad_count++; - if (local_pad_count == local_pad) - break; - } + if (local_pad_count == local_pad) + break; + } - return ingame_pad; + return ingame_pad; } u8 NetPlayClient::LocalWiimoteToInGameWiimote(u8 local_pad) { - // Figure out which in-game pad maps to which local pad. - // The logic we have here is that the local slots always - // go in order. - int local_pad_count = -1; - int ingame_pad = 0; - for (; ingame_pad < 4; ingame_pad++) - { - if (m_wiimote_map[ingame_pad] == m_local_player->pid) - local_pad_count++; + // Figure out which in-game pad maps to which local pad. + // The logic we have here is that the local slots always + // go in order. + int local_pad_count = -1; + int ingame_pad = 0; + for (; ingame_pad < 4; ingame_pad++) + { + if (m_wiimote_map[ingame_pad] == m_local_player->pid) + local_pad_count++; - if (local_pad_count == local_pad) - break; - } + if (local_pad_count == local_pad) + break; + } - return ingame_pad; + return ingame_pad; } void NetPlayClient::SendTimeBase() { - std::lock_guard lk(crit_netplay_client); + std::lock_guard lk(crit_netplay_client); - u64 timebase = SystemTimers::GetFakeTimeBase(); + u64 timebase = SystemTimers::GetFakeTimeBase(); - auto spac = std::make_unique(); - *spac << static_cast(NP_MSG_TIMEBASE); - *spac << static_cast(timebase); - *spac << static_cast(timebase << 32); - *spac << netplay_client->m_timebase_frame++; + auto spac = std::make_unique(); + *spac << static_cast(NP_MSG_TIMEBASE); + *spac << static_cast(timebase); + *spac << static_cast(timebase << 32); + *spac << netplay_client->m_timebase_frame++; - netplay_client->SendAsync(std::move(spac)); + netplay_client->SendAsync(std::move(spac)); } // stuff hacked into dolphin @@ -1165,61 +1152,61 @@ void NetPlayClient::SendTimeBase() // Actual Core function which is called on every frame bool CSIDevice_GCController::NetPlay_GetInput(u8 numPAD, GCPadStatus* PadStatus) { - std::lock_guard lk(crit_netplay_client); + std::lock_guard lk(crit_netplay_client); - if (netplay_client) - return netplay_client->GetNetPads(numPAD, PadStatus); - else - return false; + if (netplay_client) + return netplay_client->GetNetPads(numPAD, PadStatus); + else + return false; } bool WiimoteEmu::Wiimote::NetPlay_GetWiimoteData(int wiimote, u8* data, u8 size) { - std::lock_guard lk(crit_netplay_client); + std::lock_guard lk(crit_netplay_client); - if (netplay_client) - return netplay_client->WiimoteUpdate(wiimote, data, size); - else - return false; + if (netplay_client) + return netplay_client->WiimoteUpdate(wiimote, data, size); + else + return false; } // called from ---CPU--- thread // so all players' games get the same time u64 CEXIIPL::NetPlay_GetGCTime() { - std::lock_guard lk(crit_netplay_client); + std::lock_guard lk(crit_netplay_client); - if (netplay_client) - return g_netplay_initial_gctime; - else - return 0; + if (netplay_client) + return g_netplay_initial_gctime; + else + return 0; } // called from ---CPU--- thread // return the local pad num that should rumble given a ingame pad num u8 CSIDevice_GCController::NetPlay_InGamePadToLocalPad(u8 numPAD) { - std::lock_guard lk(crit_netplay_client); + std::lock_guard lk(crit_netplay_client); - if (netplay_client) - return netplay_client->InGamePadToLocalPad(numPAD); - else - return numPAD; + if (netplay_client) + return netplay_client->InGamePadToLocalPad(numPAD); + else + return numPAD; } bool NetPlay::IsNetPlayRunning() { - return netplay_client != nullptr; + return netplay_client != nullptr; } void NetPlay_Enable(NetPlayClient* const np) { - std::lock_guard lk(crit_netplay_client); - netplay_client = np; + std::lock_guard lk(crit_netplay_client); + netplay_client = np; } void NetPlay_Disable() { - std::lock_guard lk(crit_netplay_client); - netplay_client = nullptr; + std::lock_guard lk(crit_netplay_client); + netplay_client = nullptr; } diff --git a/Source/Core/Core/NetPlayClient.h b/Source/Core/Core/NetPlayClient.h index 285db13b5b..33d94e9cfc 100644 --- a/Source/Core/Core/NetPlayClient.h +++ b/Source/Core/Core/NetPlayClient.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -12,151 +13,149 @@ #include #include #include -#include #include "Common/CommonTypes.h" #include "Common/FifoQueue.h" #include "Common/TraversalClient.h" #include "Core/NetPlayProto.h" #include "InputCommon/GCPadStatus.h" - class NetPlayUI { public: - virtual ~NetPlayUI() {} + virtual ~NetPlayUI() {} + virtual void BootGame(const std::string& filename) = 0; + virtual void StopGame() = 0; - virtual void BootGame(const std::string& filename) = 0; - virtual void StopGame() = 0; + virtual void Update() = 0; + virtual void AppendChat(const std::string& msg) = 0; - virtual void Update() = 0; - virtual void AppendChat(const std::string& msg) = 0; - - virtual void OnMsgChangeGame(const std::string& filename) = 0; - virtual void OnMsgStartGame() = 0; - virtual void OnMsgStopGame() = 0; - virtual bool IsRecording() = 0; + virtual void OnMsgChangeGame(const std::string& filename) = 0; + virtual void OnMsgStartGame() = 0; + virtual void OnMsgStopGame() = 0; + virtual bool IsRecording() = 0; }; class Player { public: - PlayerId pid; - std::string name; - std::string revision; - u32 ping; + PlayerId pid; + std::string name; + std::string revision; + u32 ping; }; class NetPlayClient : public TraversalClientClient { public: - void ThreadFunc(); - void SendAsync(std::unique_ptr packet); + void ThreadFunc(); + void SendAsync(std::unique_ptr packet); - NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name, bool traversal, const std::string& centralServer, u16 centralPort); - ~NetPlayClient(); + NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, + const std::string& name, bool traversal, const std::string& centralServer, + u16 centralPort); + ~NetPlayClient(); - void GetPlayerList(std::string& list, std::vector& pid_list); - std::vector GetPlayers(); + void GetPlayerList(std::string& list, std::vector& pid_list); + std::vector GetPlayers(); - // Called from the GUI thread. - bool IsConnected() const { return m_is_connected; } + // Called from the GUI thread. + bool IsConnected() const { return m_is_connected; } + bool StartGame(const std::string& path); + bool StopGame(); + void Stop(); + bool ChangeGame(const std::string& game); + void SendChatMessage(const std::string& msg); - bool StartGame(const std::string &path); - bool StopGame(); - void Stop(); - bool ChangeGame(const std::string& game); - void SendChatMessage(const std::string& msg); + // Send and receive pads values + bool WiimoteUpdate(int _number, u8* data, const u8 size); + bool GetNetPads(const u8 pad_nb, GCPadStatus* pad_status); - // Send and receive pads values - bool WiimoteUpdate(int _number, u8* data, const u8 size); - bool GetNetPads(const u8 pad_nb, GCPadStatus* pad_status); + void OnTraversalStateChanged() override; + void OnConnectReady(ENetAddress addr) override; + void OnConnectFailed(u8 reason) override; - void OnTraversalStateChanged() override; - void OnConnectReady(ENetAddress addr) override; - void OnConnectFailed(u8 reason) override; + bool IsFirstInGamePad(u8 ingame_pad) const; + u8 NumLocalPads() const; - bool IsFirstInGamePad(u8 ingame_pad) const; - u8 NumLocalPads() const; + u8 InGamePadToLocalPad(u8 ingame_pad); + u8 LocalPadToInGamePad(u8 localPad); - u8 InGamePadToLocalPad(u8 ingame_pad); - u8 LocalPadToInGamePad(u8 localPad); + u8 LocalWiimoteToInGameWiimote(u8 local_pad); - u8 LocalWiimoteToInGameWiimote(u8 local_pad); - - static void SendTimeBase(); + static void SendTimeBase(); protected: - void ClearBuffers(); + void ClearBuffers(); - struct - { - std::recursive_mutex game; - // lock order - std::recursive_mutex players; - std::recursive_mutex async_queue_write; - } m_crit; + struct + { + std::recursive_mutex game; + // lock order + std::recursive_mutex players; + std::recursive_mutex async_queue_write; + } m_crit; - Common::FifoQueue, false> m_async_queue; + Common::FifoQueue, false> m_async_queue; - std::array, 4> m_pad_buffer; - std::array, 4> m_wiimote_buffer; + std::array, 4> m_pad_buffer; + std::array, 4> m_wiimote_buffer; - NetPlayUI* m_dialog = nullptr; + NetPlayUI* m_dialog = nullptr; - ENetHost* m_client = nullptr; - ENetPeer* m_server = nullptr; - std::thread m_thread; + ENetHost* m_client = nullptr; + ENetPeer* m_server = nullptr; + std::thread m_thread; - std::string m_selected_game; - std::atomic m_is_running{false}; - std::atomic m_do_loop{true}; + std::string m_selected_game; + std::atomic m_is_running{false}; + std::atomic m_do_loop{true}; - unsigned int m_target_buffer_size = 20; + unsigned int m_target_buffer_size = 20; - Player* m_local_player = nullptr; + Player* m_local_player = nullptr; - u32 m_current_game = 0; + u32 m_current_game = 0; - PadMappingArray m_pad_map; - PadMappingArray m_wiimote_map; + PadMappingArray m_pad_map; + PadMappingArray m_wiimote_map; - bool m_is_recording = false; + bool m_is_recording = false; private: - enum class ConnectionState - { - WaitingForTraversalClientConnection, - WaitingForTraversalClientConnectReady, - Connecting, - WaitingForHelloResponse, - Connected, - Failure - }; + enum class ConnectionState + { + WaitingForTraversalClientConnection, + WaitingForTraversalClientConnectReady, + Connecting, + WaitingForHelloResponse, + Connected, + Failure + }; - bool LocalPlayerHasControllerMapped() const; + bool LocalPlayerHasControllerMapped() const; - void SendStartGamePacket(); - void SendStopGamePacket(); + void SendStartGamePacket(); + void SendStopGamePacket(); - void UpdateDevices(); - void SendPadState(const PadMapping in_game_pad, const GCPadStatus& np); - void SendWiimoteState(const PadMapping in_game_pad, const NetWiimote& nw); - unsigned int OnData(sf::Packet& packet); - void Send(sf::Packet& packet); - void Disconnect(); - bool Connect(); + void UpdateDevices(); + void SendPadState(const PadMapping in_game_pad, const GCPadStatus& np); + void SendWiimoteState(const PadMapping in_game_pad, const NetWiimote& nw); + unsigned int OnData(sf::Packet& packet); + void Send(sf::Packet& packet); + void Disconnect(); + bool Connect(); - bool m_is_connected = false; - ConnectionState m_connection_state = ConnectionState::Failure; + bool m_is_connected = false; + ConnectionState m_connection_state = ConnectionState::Failure; - PlayerId m_pid = 0; - std::map m_players; - std::string m_host_spec; - std::string m_player_name; - bool m_connecting = false; - TraversalClient* m_traversal_client = nullptr; + PlayerId m_pid = 0; + std::map m_players; + std::string m_host_spec; + std::string m_player_name; + bool m_connecting = false; + TraversalClient* m_traversal_client = nullptr; - u32 m_timebase_frame = 0; + u32 m_timebase_frame = 0; }; void NetPlay_Enable(NetPlayClient* const np); diff --git a/Source/Core/Core/NetPlayProto.h b/Source/Core/Core/NetPlayProto.h index 1fe2345482..09451b9b76 100644 --- a/Source/Core/Core/NetPlayProto.h +++ b/Source/Core/Core/NetPlayProto.h @@ -11,18 +11,18 @@ struct NetSettings { - bool m_CPUthread; - int m_CPUcore; - int m_SelectedLanguage; - bool m_OverrideGCLanguage; - bool m_ProgressiveScan; - bool m_PAL60; - bool m_DSPHLE; - bool m_DSPEnableJIT; - bool m_WriteToMemcard; - bool m_OCEnable; - float m_OCFactor; - TEXIDevices m_EXIDevice[2]; + bool m_CPUthread; + int m_CPUcore; + int m_SelectedLanguage; + bool m_OverrideGCLanguage; + bool m_ProgressiveScan; + bool m_PAL60; + bool m_DSPHLE; + bool m_DSPEnableJIT; + bool m_WriteToMemcard; + bool m_OCEnable; + float m_OCFactor; + TEXIDevices m_EXIDevice[2]; }; extern NetSettings g_NetPlaySettings; @@ -30,57 +30,57 @@ extern u64 g_netplay_initial_gctime; struct Rpt : public std::vector { - u16 channel; + u16 channel; }; // messages enum { - NP_MSG_PLAYER_JOIN = 0x10, - NP_MSG_PLAYER_LEAVE = 0x11, + NP_MSG_PLAYER_JOIN = 0x10, + NP_MSG_PLAYER_LEAVE = 0x11, - NP_MSG_CHAT_MESSAGE = 0x30, + NP_MSG_CHAT_MESSAGE = 0x30, - NP_MSG_PAD_DATA = 0x60, - NP_MSG_PAD_MAPPING = 0x61, - NP_MSG_PAD_BUFFER = 0x62, + NP_MSG_PAD_DATA = 0x60, + NP_MSG_PAD_MAPPING = 0x61, + NP_MSG_PAD_BUFFER = 0x62, - NP_MSG_WIIMOTE_DATA = 0x70, - NP_MSG_WIIMOTE_MAPPING = 0x71, + NP_MSG_WIIMOTE_DATA = 0x70, + NP_MSG_WIIMOTE_MAPPING = 0x71, - NP_MSG_START_GAME = 0xA0, - NP_MSG_CHANGE_GAME = 0xA1, - NP_MSG_STOP_GAME = 0xA2, - NP_MSG_DISABLE_GAME = 0xA3, + NP_MSG_START_GAME = 0xA0, + NP_MSG_CHANGE_GAME = 0xA1, + NP_MSG_STOP_GAME = 0xA2, + NP_MSG_DISABLE_GAME = 0xA3, - NP_MSG_TIMEBASE = 0xB0, - NP_MSG_DESYNC_DETECTED = 0xB1, + NP_MSG_TIMEBASE = 0xB0, + NP_MSG_DESYNC_DETECTED = 0xB1, - NP_MSG_READY = 0xD0, - NP_MSG_NOT_READY = 0xD1, + NP_MSG_READY = 0xD0, + NP_MSG_NOT_READY = 0xD1, - NP_MSG_PING = 0xE0, - NP_MSG_PONG = 0xE1, - NP_MSG_PLAYER_PING_DATA = 0xE2, + NP_MSG_PING = 0xE0, + NP_MSG_PONG = 0xE1, + NP_MSG_PLAYER_PING_DATA = 0xE2, - NP_MSG_SYNC_GC_SRAM = 0xF0, + NP_MSG_SYNC_GC_SRAM = 0xF0, }; enum { - CON_ERR_SERVER_FULL = 1, - CON_ERR_GAME_RUNNING = 2, - CON_ERR_VERSION_MISMATCH = 3 + CON_ERR_SERVER_FULL = 1, + CON_ERR_GAME_RUNNING = 2, + CON_ERR_VERSION_MISMATCH = 3 }; using NetWiimote = std::vector; -using MessageId = u8; -using PlayerId = u8; -using FrameNum = u32; +using MessageId = u8; +using PlayerId = u8; +using FrameNum = u32; using PadMapping = s8; using PadMappingArray = std::array; namespace NetPlay { - bool IsNetPlayRunning(); +bool IsNetPlayRunning(); } diff --git a/Source/Core/Core/NetPlayServer.cpp b/Source/Core/Core/NetPlayServer.cpp index 514e3c4d20..d21b0e86fd 100644 --- a/Source/Core/Core/NetPlayServer.cpp +++ b/Source/Core/Core/NetPlayServer.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/NetPlayServer.h" #include #include #include @@ -11,14 +12,13 @@ #include "Common/IniFile.h" #include "Common/StringUtil.h" #include "Core/ConfigManager.h" -#include "Core/NetPlayClient.h" //for NetPlayUI -#include "Core/NetPlayServer.h" #include "Core/HW/EXI_DeviceIPL.h" #include "Core/HW/Sram.h" +#include "Core/NetPlayClient.h" //for NetPlayUI #include "InputCommon/GCPadStatus.h" #if !defined(_WIN32) -#include #include +#include #ifndef ANDROID #include #endif @@ -29,828 +29,818 @@ u64 g_netplay_initial_gctime = 1272737767; NetPlayServer::~NetPlayServer() { - if (is_connected) - { - m_do_loop = false; - m_thread.join(); - enet_host_destroy(m_server); + if (is_connected) + { + m_do_loop = false; + m_thread.join(); + enet_host_destroy(m_server); - if (g_MainNetHost.get() == m_server) - { - g_MainNetHost.release(); - } + if (g_MainNetHost.get() == m_server) + { + g_MainNetHost.release(); + } - if (m_traversal_client) - { - g_TraversalClient->m_Client = nullptr; - ReleaseTraversalClient(); - } - } + if (m_traversal_client) + { + g_TraversalClient->m_Client = nullptr; + ReleaseTraversalClient(); + } + } #ifdef USE_UPNP - if (m_upnp_thread.joinable()) - m_upnp_thread.join(); - m_upnp_thread = std::thread(&NetPlayServer::unmapPortThread); - m_upnp_thread.join(); + if (m_upnp_thread.joinable()) + m_upnp_thread.join(); + m_upnp_thread = std::thread(&NetPlayServer::unmapPortThread); + m_upnp_thread.join(); #endif } // called from ---GUI--- thread -NetPlayServer::NetPlayServer(const u16 port, bool traversal, const std::string& centralServer, u16 centralPort) +NetPlayServer::NetPlayServer(const u16 port, bool traversal, const std::string& centralServer, + u16 centralPort) { - //--use server time - if (enet_initialize() != 0) - { - PanicAlertT("Enet Didn't Initialize"); - } + //--use server time + if (enet_initialize() != 0) + { + PanicAlertT("Enet Didn't Initialize"); + } - m_pad_map.fill(-1); - m_wiimote_map.fill(-1); + m_pad_map.fill(-1); + m_wiimote_map.fill(-1); - if (traversal) - { - if (!EnsureTraversalClient(centralServer, centralPort, port)) - return; + if (traversal) + { + if (!EnsureTraversalClient(centralServer, centralPort, port)) + return; - g_TraversalClient->m_Client = this; - m_traversal_client = g_TraversalClient.get(); + g_TraversalClient->m_Client = this; + m_traversal_client = g_TraversalClient.get(); - m_server = g_MainNetHost.get(); + m_server = g_MainNetHost.get(); - if (g_TraversalClient->m_State == TraversalClient::Failure) - g_TraversalClient->ReconnectToServer(); - } - else - { - ENetAddress serverAddr; - serverAddr.host = ENET_HOST_ANY; - serverAddr.port = port; - m_server = enet_host_create(&serverAddr, 10, 3, 0, 0); - if (m_server != nullptr) - m_server->intercept = ENetUtil::InterceptCallback; - } - if (m_server != nullptr) - { - is_connected = true; - m_do_loop = true; - m_thread = std::thread(&NetPlayServer::ThreadFunc, this); - m_target_buffer_size = 5; - } + if (g_TraversalClient->m_State == TraversalClient::Failure) + g_TraversalClient->ReconnectToServer(); + } + else + { + ENetAddress serverAddr; + serverAddr.host = ENET_HOST_ANY; + serverAddr.port = port; + m_server = enet_host_create(&serverAddr, 10, 3, 0, 0); + if (m_server != nullptr) + m_server->intercept = ENetUtil::InterceptCallback; + } + if (m_server != nullptr) + { + is_connected = true; + m_do_loop = true; + m_thread = std::thread(&NetPlayServer::ThreadFunc, this); + m_target_buffer_size = 5; + } } // called from ---NETPLAY--- thread void NetPlayServer::ThreadFunc() { - while (m_do_loop) - { - // update pings every so many seconds - if ((m_ping_timer.GetTimeElapsed() > 1000) || m_update_pings) - { - m_ping_key = Common::Timer::GetTimeMs(); + while (m_do_loop) + { + // update pings every so many seconds + if ((m_ping_timer.GetTimeElapsed() > 1000) || m_update_pings) + { + m_ping_key = Common::Timer::GetTimeMs(); - sf::Packet spac; - spac << (MessageId)NP_MSG_PING; - spac << m_ping_key; + sf::Packet spac; + spac << (MessageId)NP_MSG_PING; + spac << m_ping_key; - m_ping_timer.Start(); - SendToClients(spac); - m_update_pings = false; - } + m_ping_timer.Start(); + SendToClients(spac); + m_update_pings = false; + } - ENetEvent netEvent; - int net; - if (m_traversal_client) - m_traversal_client->HandleResends(); - net = enet_host_service(m_server, &netEvent, 1000); - while (!m_async_queue.Empty()) - { - { - std::lock_guard lkp(m_crit.players); - SendToClients(*(m_async_queue.Front().get())); - } - m_async_queue.Pop(); - } - if (net > 0) - { - switch (netEvent.type) - { - case ENET_EVENT_TYPE_CONNECT: - { - ENetPeer* accept_peer = netEvent.peer; - unsigned int error; - { - std::lock_guard lkg(m_crit.game); - error = OnConnect(accept_peer); - } + ENetEvent netEvent; + int net; + if (m_traversal_client) + m_traversal_client->HandleResends(); + net = enet_host_service(m_server, &netEvent, 1000); + while (!m_async_queue.Empty()) + { + { + std::lock_guard lkp(m_crit.players); + SendToClients(*(m_async_queue.Front().get())); + } + m_async_queue.Pop(); + } + if (net > 0) + { + switch (netEvent.type) + { + case ENET_EVENT_TYPE_CONNECT: + { + ENetPeer* accept_peer = netEvent.peer; + unsigned int error; + { + std::lock_guard lkg(m_crit.game); + error = OnConnect(accept_peer); + } - if (error) - { - sf::Packet spac; - spac << (MessageId)error; - // don't need to lock, this client isn't in the client map - Send(accept_peer, spac); - if (netEvent.peer->data) - { - delete (PlayerId *) netEvent.peer->data; - netEvent.peer->data = nullptr; - } - enet_peer_disconnect(accept_peer, 0); - } - } - break; - case ENET_EVENT_TYPE_RECEIVE: - { - sf::Packet rpac; - rpac.append(netEvent.packet->data, netEvent.packet->dataLength); + if (error) + { + sf::Packet spac; + spac << (MessageId)error; + // don't need to lock, this client isn't in the client map + Send(accept_peer, spac); + if (netEvent.peer->data) + { + delete (PlayerId*)netEvent.peer->data; + netEvent.peer->data = nullptr; + } + enet_peer_disconnect(accept_peer, 0); + } + } + break; + case ENET_EVENT_TYPE_RECEIVE: + { + sf::Packet rpac; + rpac.append(netEvent.packet->data, netEvent.packet->dataLength); - auto it = m_players.find(*(PlayerId *)netEvent.peer->data); - Client& client = it->second; - if (OnData(rpac, client) != 0) - { - // if a bad packet is received, disconnect the client - std::lock_guard lkg(m_crit.game); - OnDisconnect(client); + auto it = m_players.find(*(PlayerId*)netEvent.peer->data); + Client& client = it->second; + if (OnData(rpac, client) != 0) + { + // if a bad packet is received, disconnect the client + std::lock_guard lkg(m_crit.game); + OnDisconnect(client); - if (netEvent.peer->data) - { - delete (PlayerId *)netEvent.peer->data; - netEvent.peer->data = nullptr; - } - } - enet_packet_destroy(netEvent.packet); - } - break; - case ENET_EVENT_TYPE_DISCONNECT: - { - std::lock_guard lkg(m_crit.game); - if (!netEvent.peer->data) - break; - auto it = m_players.find(*(PlayerId *)netEvent.peer->data); - if (it != m_players.end()) - { - Client& client = it->second; - OnDisconnect(client); + if (netEvent.peer->data) + { + delete (PlayerId*)netEvent.peer->data; + netEvent.peer->data = nullptr; + } + } + enet_packet_destroy(netEvent.packet); + } + break; + case ENET_EVENT_TYPE_DISCONNECT: + { + std::lock_guard lkg(m_crit.game); + if (!netEvent.peer->data) + break; + auto it = m_players.find(*(PlayerId*)netEvent.peer->data); + if (it != m_players.end()) + { + Client& client = it->second; + OnDisconnect(client); - if (netEvent.peer->data) - { - delete (PlayerId *)netEvent.peer->data; - netEvent.peer->data = nullptr; - } - } - } - break; - default: - break; - } - } - } + if (netEvent.peer->data) + { + delete (PlayerId*)netEvent.peer->data; + netEvent.peer->data = nullptr; + } + } + } + break; + default: + break; + } + } + } - // close listening socket and client sockets - for (auto& player_entry : m_players) - { - delete (PlayerId *)player_entry.second.socket->data; - player_entry.second.socket->data = nullptr; - enet_peer_disconnect(player_entry.second.socket, 0); - } + // close listening socket and client sockets + for (auto& player_entry : m_players) + { + delete (PlayerId*)player_entry.second.socket->data; + player_entry.second.socket->data = nullptr; + enet_peer_disconnect(player_entry.second.socket, 0); + } } // called from ---NETPLAY--- thread unsigned int NetPlayServer::OnConnect(ENetPeer* socket) { - sf::Packet rpac; - ENetPacket* epack; - do - { - epack = enet_peer_receive(socket, nullptr); - } while (epack == nullptr); - rpac.append(epack->data, epack->dataLength); + sf::Packet rpac; + ENetPacket* epack; + do + { + epack = enet_peer_receive(socket, nullptr); + } while (epack == nullptr); + rpac.append(epack->data, epack->dataLength); - // give new client first available id - PlayerId pid = 1; - for (auto i = m_players.begin(); i != m_players.end(); ++i) - { - if (i->second.pid == pid) - { - pid++; - i = m_players.begin(); - } - } - socket->data = new PlayerId(pid); + // give new client first available id + PlayerId pid = 1; + for (auto i = m_players.begin(); i != m_players.end(); ++i) + { + if (i->second.pid == pid) + { + pid++; + i = m_players.begin(); + } + } + socket->data = new PlayerId(pid); - std::string npver; - rpac >> npver; - // Dolphin netplay version - if (npver != scm_rev_git_str) - return CON_ERR_VERSION_MISMATCH; + std::string npver; + rpac >> npver; + // Dolphin netplay version + if (npver != scm_rev_git_str) + return CON_ERR_VERSION_MISMATCH; - // game is currently running - if (m_is_running) - return CON_ERR_GAME_RUNNING; + // game is currently running + if (m_is_running) + return CON_ERR_GAME_RUNNING; - // too many players - if (m_players.size() >= 255) - return CON_ERR_SERVER_FULL; + // too many players + if (m_players.size() >= 255) + return CON_ERR_SERVER_FULL; - // cause pings to be updated - m_update_pings = true; + // cause pings to be updated + m_update_pings = true; - Client player; - player.pid = pid; - player.socket = socket; - rpac >> player.revision; - rpac >> player.name; + Client player; + player.pid = pid; + player.socket = socket; + rpac >> player.revision; + rpac >> player.name; - enet_packet_destroy(epack); - // try to automatically assign new user a pad - for (PadMapping& mapping : m_pad_map) - { - if (mapping == -1) - { - mapping = player.pid; - break; - } - } + enet_packet_destroy(epack); + // try to automatically assign new user a pad + for (PadMapping& mapping : m_pad_map) + { + if (mapping == -1) + { + mapping = player.pid; + break; + } + } - // send join message to already connected clients - sf::Packet spac; - spac << (MessageId)NP_MSG_PLAYER_JOIN; - spac << player.pid << player.name << player.revision; - SendToClients(spac); + // send join message to already connected clients + sf::Packet spac; + spac << (MessageId)NP_MSG_PLAYER_JOIN; + spac << player.pid << player.name << player.revision; + SendToClients(spac); - // send new client success message with their id - spac.clear(); - spac << (MessageId)0; - spac << player.pid; - Send(player.socket, spac); + // send new client success message with their id + spac.clear(); + spac << (MessageId)0; + spac << player.pid; + Send(player.socket, spac); - // send new client the selected game - if (m_selected_game != "") - { - spac.clear(); - spac << (MessageId)NP_MSG_CHANGE_GAME; - spac << m_selected_game; - Send(player.socket, spac); - } + // send new client the selected game + if (m_selected_game != "") + { + spac.clear(); + spac << (MessageId)NP_MSG_CHANGE_GAME; + spac << m_selected_game; + Send(player.socket, spac); + } - // send the pad buffer value - spac.clear(); - spac << (MessageId)NP_MSG_PAD_BUFFER; - spac << (u32)m_target_buffer_size; - Send(player.socket, spac); + // send the pad buffer value + spac.clear(); + spac << (MessageId)NP_MSG_PAD_BUFFER; + spac << (u32)m_target_buffer_size; + Send(player.socket, spac); - // sync GC SRAM with new client - if (!g_SRAM_netplay_initialized) - { - SConfig::GetInstance().m_strSRAM = File::GetUserPath(F_GCSRAM_IDX); - InitSRAM(); - g_SRAM_netplay_initialized = true; - } - spac.clear(); - spac << (MessageId)NP_MSG_SYNC_GC_SRAM; - for (size_t i = 0; i < sizeof(g_SRAM.p_SRAM); ++i) - { - spac << g_SRAM.p_SRAM[i]; - } - Send(player.socket, spac); + // sync GC SRAM with new client + if (!g_SRAM_netplay_initialized) + { + SConfig::GetInstance().m_strSRAM = File::GetUserPath(F_GCSRAM_IDX); + InitSRAM(); + g_SRAM_netplay_initialized = true; + } + spac.clear(); + spac << (MessageId)NP_MSG_SYNC_GC_SRAM; + for (size_t i = 0; i < sizeof(g_SRAM.p_SRAM); ++i) + { + spac << g_SRAM.p_SRAM[i]; + } + Send(player.socket, spac); - // sync values with new client - for (const auto& p : m_players) - { - spac.clear(); - spac << (MessageId)NP_MSG_PLAYER_JOIN; - spac << p.second.pid << p.second.name << p.second.revision; - Send(player.socket, spac); - } + // sync values with new client + for (const auto& p : m_players) + { + spac.clear(); + spac << (MessageId)NP_MSG_PLAYER_JOIN; + spac << p.second.pid << p.second.name << p.second.revision; + Send(player.socket, spac); + } - // add client to the player list - { - std::lock_guard lkp(m_crit.players); - m_players.emplace(*(PlayerId *)player.socket->data, player); - UpdatePadMapping(); // sync pad mappings with everyone - UpdateWiimoteMapping(); - } + // add client to the player list + { + std::lock_guard lkp(m_crit.players); + m_players.emplace(*(PlayerId*)player.socket->data, player); + UpdatePadMapping(); // sync pad mappings with everyone + UpdateWiimoteMapping(); + } - return 0; + return 0; } // called from ---NETPLAY--- thread unsigned int NetPlayServer::OnDisconnect(Client& player) { - PlayerId pid = player.pid; + PlayerId pid = player.pid; - if (m_is_running) - { - for (PadMapping mapping : m_pad_map) - { - if (mapping == pid && pid != 1) - { - PanicAlertT("Client disconnect while game is running!! NetPlay is disabled. You must manually stop the game."); - std::lock_guard lkg(m_crit.game); - m_is_running = false; + if (m_is_running) + { + for (PadMapping mapping : m_pad_map) + { + if (mapping == pid && pid != 1) + { + PanicAlertT("Client disconnect while game is running!! NetPlay is disabled. You must " + "manually stop the game."); + std::lock_guard lkg(m_crit.game); + m_is_running = false; - sf::Packet spac; - spac << (MessageId)NP_MSG_DISABLE_GAME; - // this thread doesn't need players lock - SendToClients(spac, 1); - break; - } - } - } + sf::Packet spac; + spac << (MessageId)NP_MSG_DISABLE_GAME; + // this thread doesn't need players lock + SendToClients(spac, 1); + break; + } + } + } - sf::Packet spac; - spac << (MessageId)NP_MSG_PLAYER_LEAVE; - spac << pid; + sf::Packet spac; + spac << (MessageId)NP_MSG_PLAYER_LEAVE; + spac << pid; - enet_peer_disconnect(player.socket, 0); + enet_peer_disconnect(player.socket, 0); - std::lock_guard lkp(m_crit.players); - auto it = m_players.find(player.pid); - if (it != m_players.end()) - m_players.erase(it); + std::lock_guard lkp(m_crit.players); + auto it = m_players.find(player.pid); + if (it != m_players.end()) + m_players.erase(it); - // alert other players of disconnect - SendToClients(spac); + // alert other players of disconnect + SendToClients(spac); - for (PadMapping& mapping : m_pad_map) - { - if (mapping == pid) - { - mapping = -1; - } - } - UpdatePadMapping(); + for (PadMapping& mapping : m_pad_map) + { + if (mapping == pid) + { + mapping = -1; + } + } + UpdatePadMapping(); - for (PadMapping& mapping : m_wiimote_map) - { - if (mapping == pid) - { - mapping = -1; - } - } - UpdateWiimoteMapping(); + for (PadMapping& mapping : m_wiimote_map) + { + if (mapping == pid) + { + mapping = -1; + } + } + UpdateWiimoteMapping(); - return 0; + return 0; } // called from ---GUI--- thread PadMappingArray NetPlayServer::GetPadMapping() const { - return m_pad_map; + return m_pad_map; } PadMappingArray NetPlayServer::GetWiimoteMapping() const { - return m_wiimote_map; + return m_wiimote_map; } // called from ---GUI--- thread void NetPlayServer::SetPadMapping(const PadMappingArray& mappings) { - m_pad_map = mappings; - UpdatePadMapping(); + m_pad_map = mappings; + UpdatePadMapping(); } // called from ---GUI--- thread void NetPlayServer::SetWiimoteMapping(const PadMappingArray& mappings) { - m_wiimote_map = mappings; - UpdateWiimoteMapping(); + m_wiimote_map = mappings; + UpdateWiimoteMapping(); } // called from ---GUI--- thread and ---NETPLAY--- thread void NetPlayServer::UpdatePadMapping() { - sf::Packet spac; - spac << (MessageId)NP_MSG_PAD_MAPPING; - for (PadMapping mapping : m_pad_map) - { - spac << mapping; - } - SendToClients(spac); + sf::Packet spac; + spac << (MessageId)NP_MSG_PAD_MAPPING; + for (PadMapping mapping : m_pad_map) + { + spac << mapping; + } + SendToClients(spac); } // called from ---NETPLAY--- thread void NetPlayServer::UpdateWiimoteMapping() { - sf::Packet spac; - spac << (MessageId)NP_MSG_WIIMOTE_MAPPING; - for (PadMapping mapping : m_wiimote_map) - { - spac << mapping; - } - SendToClients(spac); + sf::Packet spac; + spac << (MessageId)NP_MSG_WIIMOTE_MAPPING; + for (PadMapping mapping : m_wiimote_map) + { + spac << mapping; + } + SendToClients(spac); } // called from ---GUI--- thread and ---NETPLAY--- thread void NetPlayServer::AdjustPadBufferSize(unsigned int size) { - std::lock_guard lkg(m_crit.game); + std::lock_guard lkg(m_crit.game); - m_target_buffer_size = size; + m_target_buffer_size = size; - // tell clients to change buffer size - auto spac = std::make_unique(); - *spac << static_cast(NP_MSG_PAD_BUFFER); - *spac << static_cast(m_target_buffer_size); + // tell clients to change buffer size + auto spac = std::make_unique(); + *spac << static_cast(NP_MSG_PAD_BUFFER); + *spac << static_cast(m_target_buffer_size); - SendAsyncToClients(std::move(spac)); + SendAsyncToClients(std::move(spac)); } void NetPlayServer::SendAsyncToClients(std::unique_ptr packet) { - { - std::lock_guard lkq(m_crit.async_queue_write); - m_async_queue.Push(std::move(packet)); - } - ENetUtil::WakeupThread(m_server); + { + std::lock_guard lkq(m_crit.async_queue_write); + m_async_queue.Push(std::move(packet)); + } + ENetUtil::WakeupThread(m_server); } // called from ---NETPLAY--- thread unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player) { - MessageId mid; - packet >> mid; + MessageId mid; + packet >> mid; - // don't need lock because this is the only thread that modifies the players - // only need locks for writes to m_players in this thread + // don't need lock because this is the only thread that modifies the players + // only need locks for writes to m_players in this thread - switch (mid) - { - case NP_MSG_CHAT_MESSAGE: - { - std::string msg; - packet >> msg; + switch (mid) + { + case NP_MSG_CHAT_MESSAGE: + { + std::string msg; + packet >> msg; - // send msg to other clients - sf::Packet spac; - spac << (MessageId)NP_MSG_CHAT_MESSAGE; - spac << player.pid; - spac << msg; + // send msg to other clients + sf::Packet spac; + spac << (MessageId)NP_MSG_CHAT_MESSAGE; + spac << player.pid; + spac << msg; - SendToClients(spac, player.pid); - } - break; + SendToClients(spac, player.pid); + } + break; - case NP_MSG_PAD_DATA: - { - // if this is pad data from the last game still being received, ignore it - if (player.current_game != m_current_game) - break; + case NP_MSG_PAD_DATA: + { + // if this is pad data from the last game still being received, ignore it + if (player.current_game != m_current_game) + break; - PadMapping map = 0; - GCPadStatus pad; - packet >> map - >> pad.button - >> pad.analogA - >> pad.analogB - >> pad.stickX - >> pad.stickY - >> pad.substickX - >> pad.substickY - >> pad.triggerLeft - >> pad.triggerRight; + PadMapping map = 0; + GCPadStatus pad; + packet >> map >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >> + pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight; - // If the data is not from the correct player, - // then disconnect them. - if (m_pad_map.at(map) != player.pid) - { - return 1; - } + // If the data is not from the correct player, + // then disconnect them. + if (m_pad_map.at(map) != player.pid) + { + return 1; + } - // Relay to clients - sf::Packet spac; - spac << (MessageId)NP_MSG_PAD_DATA; - spac << map - << pad.button - << pad.analogA - << pad.analogB - << pad.stickX - << pad.stickY - << pad.substickX - << pad.substickY - << pad.triggerLeft - << pad.triggerRight; + // Relay to clients + sf::Packet spac; + spac << (MessageId)NP_MSG_PAD_DATA; + spac << map << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY + << pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight; - SendToClients(spac, player.pid); - } - break; + SendToClients(spac, player.pid); + } + break; - case NP_MSG_WIIMOTE_DATA: - { - // if this is Wiimote data from the last game still being received, ignore it - if (player.current_game != m_current_game) - break; + case NP_MSG_WIIMOTE_DATA: + { + // if this is Wiimote data from the last game still being received, ignore it + if (player.current_game != m_current_game) + break; - PadMapping map = 0; - u8 size; - packet >> map >> size; - std::vector data(size); - for (size_t i = 0; i < data.size(); ++i) - packet >> data[i]; + PadMapping map = 0; + u8 size; + packet >> map >> size; + std::vector data(size); + for (size_t i = 0; i < data.size(); ++i) + packet >> data[i]; - // If the data is not from the correct player, - // then disconnect them. - if (m_wiimote_map.at(map) != player.pid) - { - return 1; - } + // If the data is not from the correct player, + // then disconnect them. + if (m_wiimote_map.at(map) != player.pid) + { + return 1; + } - // relay to clients - sf::Packet spac; - spac << (MessageId)NP_MSG_WIIMOTE_DATA; - spac << map; - spac << size; - for (const u8& byte : data) - spac << byte; + // relay to clients + sf::Packet spac; + spac << (MessageId)NP_MSG_WIIMOTE_DATA; + spac << map; + spac << size; + for (const u8& byte : data) + spac << byte; - SendToClients(spac, player.pid); - } - break; + SendToClients(spac, player.pid); + } + break; - case NP_MSG_PONG: - { - const u32 ping = (u32)m_ping_timer.GetTimeElapsed(); - u32 ping_key = 0; - packet >> ping_key; + case NP_MSG_PONG: + { + const u32 ping = (u32)m_ping_timer.GetTimeElapsed(); + u32 ping_key = 0; + packet >> ping_key; - if (m_ping_key == ping_key) - { - player.ping = ping; - } + if (m_ping_key == ping_key) + { + player.ping = ping; + } - sf::Packet spac; - spac << (MessageId)NP_MSG_PLAYER_PING_DATA; - spac << player.pid; - spac << player.ping; + sf::Packet spac; + spac << (MessageId)NP_MSG_PLAYER_PING_DATA; + spac << player.pid; + spac << player.ping; - SendToClients(spac); - } - break; + SendToClients(spac); + } + break; - case NP_MSG_START_GAME: - { - packet >> player.current_game; - } - break; + case NP_MSG_START_GAME: + { + packet >> player.current_game; + } + break; - case NP_MSG_STOP_GAME: - { - // tell clients to stop game - sf::Packet spac; - spac << (MessageId)NP_MSG_STOP_GAME; + case NP_MSG_STOP_GAME: + { + // tell clients to stop game + sf::Packet spac; + spac << (MessageId)NP_MSG_STOP_GAME; - std::lock_guard lkp(m_crit.players); - SendToClients(spac); + std::lock_guard lkp(m_crit.players); + SendToClients(spac); - m_is_running = false; - } - break; + m_is_running = false; + } + break; - case NP_MSG_TIMEBASE: - { - u32 x, y, frame; - packet >> x; - packet >> y; - packet >> frame; + case NP_MSG_TIMEBASE: + { + u32 x, y, frame; + packet >> x; + packet >> y; + packet >> frame; - if (m_desync_detected) - break; + if (m_desync_detected) + break; - u64 timebase = x | ((u64)y << 32); - std::vector>& timebases = m_timebase_by_frame[frame]; - timebases.emplace_back(player.pid, timebase); - if (timebases.size() >= m_players.size()) - { - // we have all records for this frame + u64 timebase = x | ((u64)y << 32); + std::vector>& timebases = m_timebase_by_frame[frame]; + timebases.emplace_back(player.pid, timebase); + if (timebases.size() >= m_players.size()) + { + // we have all records for this frame - if (!std::all_of(timebases.begin(), timebases.end(), [&](std::pair pair){ return pair.second == timebases[0].second; })) - { - int pid_to_blame = -1; - if (timebases.size() > 2) - { - for (auto pair : timebases) - { - if (std::all_of(timebases.begin(), timebases.end(), [&](std::pair other) { - return other.first == pair.first || other.second != pair.second; - })) - { - // we are the only outlier - pid_to_blame = pair.first; - break; - } - } - } + if (!std::all_of(timebases.begin(), timebases.end(), [&](std::pair pair) { + return pair.second == timebases[0].second; + })) + { + int pid_to_blame = -1; + if (timebases.size() > 2) + { + for (auto pair : timebases) + { + if (std::all_of(timebases.begin(), timebases.end(), + [&](std::pair other) { + return other.first == pair.first || other.second != pair.second; + })) + { + // we are the only outlier + pid_to_blame = pair.first; + break; + } + } + } - sf::Packet spac; - spac << (MessageId) NP_MSG_DESYNC_DETECTED; - spac << pid_to_blame; - spac << frame; - SendToClients(spac); + sf::Packet spac; + spac << (MessageId)NP_MSG_DESYNC_DETECTED; + spac << pid_to_blame; + spac << frame; + SendToClients(spac); - m_desync_detected = true; - } - m_timebase_by_frame.erase(frame); - } - } - break; - default: - PanicAlertT("Unknown message with id:%d received from player:%d Kicking player!", mid, player.pid); - // unknown message, kick the client - return 1; - break; - } + m_desync_detected = true; + } + m_timebase_by_frame.erase(frame); + } + } + break; + default: + PanicAlertT("Unknown message with id:%d received from player:%d Kicking player!", mid, + player.pid); + // unknown message, kick the client + return 1; + break; + } - return 0; + return 0; } - void NetPlayServer::OnTraversalStateChanged() { - if (m_dialog) - m_dialog->Update(); + if (m_dialog) + m_dialog->Update(); } // called from ---GUI--- thread void NetPlayServer::SendChatMessage(const std::string& msg) { - auto spac = std::make_unique(); - *spac << (MessageId)NP_MSG_CHAT_MESSAGE; - *spac << (PlayerId)0; // server id always 0 - *spac << msg; + auto spac = std::make_unique(); + *spac << (MessageId)NP_MSG_CHAT_MESSAGE; + *spac << (PlayerId)0; // server id always 0 + *spac << msg; - SendAsyncToClients(std::move(spac)); + SendAsyncToClients(std::move(spac)); } // called from ---GUI--- thread -bool NetPlayServer::ChangeGame(const std::string &game) +bool NetPlayServer::ChangeGame(const std::string& game) { - std::lock_guard lkg(m_crit.game); + std::lock_guard lkg(m_crit.game); - m_selected_game = game; + m_selected_game = game; - // send changed game to clients - auto spac = std::make_unique(); - *spac << (MessageId)NP_MSG_CHANGE_GAME; - *spac << game; + // send changed game to clients + auto spac = std::make_unique(); + *spac << (MessageId)NP_MSG_CHANGE_GAME; + *spac << game; - SendAsyncToClients(std::move(spac)); + SendAsyncToClients(std::move(spac)); - return true; + return true; } // called from ---GUI--- thread -void NetPlayServer::SetNetSettings(const NetSettings &settings) +void NetPlayServer::SetNetSettings(const NetSettings& settings) { - m_settings = settings; + m_settings = settings; } // called from ---GUI--- thread bool NetPlayServer::StartGame() { - m_timebase_by_frame.clear(); - m_desync_detected = false; - std::lock_guard lkg(m_crit.game); - m_current_game = Common::Timer::GetTimeMs(); + m_timebase_by_frame.clear(); + m_desync_detected = false; + std::lock_guard lkg(m_crit.game); + m_current_game = Common::Timer::GetTimeMs(); - // no change, just update with clients - AdjustPadBufferSize(m_target_buffer_size); + // no change, just update with clients + AdjustPadBufferSize(m_target_buffer_size); - g_netplay_initial_gctime = Common::Timer::GetLocalTimeSinceJan1970(); + g_netplay_initial_gctime = Common::Timer::GetLocalTimeSinceJan1970(); - // tell clients to start game - auto spac = std::make_unique(); - *spac << (MessageId)NP_MSG_START_GAME; - *spac << m_current_game; - *spac << m_settings.m_CPUthread; - *spac << m_settings.m_CPUcore; - *spac << m_settings.m_SelectedLanguage; - *spac << m_settings.m_OverrideGCLanguage; - *spac << m_settings.m_ProgressiveScan; - *spac << m_settings.m_PAL60; - *spac << m_settings.m_DSPEnableJIT; - *spac << m_settings.m_DSPHLE; - *spac << m_settings.m_WriteToMemcard; - *spac << m_settings.m_OCEnable; - *spac << m_settings.m_OCFactor; - *spac << m_settings.m_EXIDevice[0]; - *spac << m_settings.m_EXIDevice[1]; - *spac << (u32)g_netplay_initial_gctime; - *spac << (u32)(g_netplay_initial_gctime >> 32); + // tell clients to start game + auto spac = std::make_unique(); + *spac << (MessageId)NP_MSG_START_GAME; + *spac << m_current_game; + *spac << m_settings.m_CPUthread; + *spac << m_settings.m_CPUcore; + *spac << m_settings.m_SelectedLanguage; + *spac << m_settings.m_OverrideGCLanguage; + *spac << m_settings.m_ProgressiveScan; + *spac << m_settings.m_PAL60; + *spac << m_settings.m_DSPEnableJIT; + *spac << m_settings.m_DSPHLE; + *spac << m_settings.m_WriteToMemcard; + *spac << m_settings.m_OCEnable; + *spac << m_settings.m_OCFactor; + *spac << m_settings.m_EXIDevice[0]; + *spac << m_settings.m_EXIDevice[1]; + *spac << (u32)g_netplay_initial_gctime; + *spac << (u32)(g_netplay_initial_gctime >> 32); - SendAsyncToClients(std::move(spac)); + SendAsyncToClients(std::move(spac)); - m_is_running = true; + m_is_running = true; - return true; + return true; } // called from multiple threads void NetPlayServer::SendToClients(sf::Packet& packet, const PlayerId skip_pid) { - for (auto& p : m_players) - { - if (p.second.pid && p.second.pid != skip_pid) - { - Send(p.second.socket, packet); - } - } + for (auto& p : m_players) + { + if (p.second.pid && p.second.pid != skip_pid) + { + Send(p.second.socket, packet); + } + } } void NetPlayServer::Send(ENetPeer* socket, sf::Packet& packet) { - ENetPacket* epac = enet_packet_create(packet.getData(), packet.getDataSize(), ENET_PACKET_FLAG_RELIABLE); - enet_peer_send(socket, 0, epac); + ENetPacket* epac = + enet_packet_create(packet.getData(), packet.getDataSize(), ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(socket, 0, epac); } void NetPlayServer::KickPlayer(PlayerId player) { - for (auto& current_player : m_players) - { - if (current_player.second.pid == player) - { - enet_peer_disconnect(current_player.second.socket, 0); - return; - } - } + for (auto& current_player : m_players) + { + if (current_player.second.pid == player) + { + enet_peer_disconnect(current_player.second.socket, 0); + return; + } + } } u16 NetPlayServer::GetPort() { - return m_server->address.port; + return m_server->address.port; } void NetPlayServer::SetNetPlayUI(NetPlayUI* dialog) { - m_dialog = dialog; + m_dialog = dialog; } // called from ---GUI--- thread std::unordered_set NetPlayServer::GetInterfaceSet() { - std::unordered_set result; - auto lst = GetInterfaceListInternal(); - for (auto list_entry : lst) - result.emplace(list_entry.first); - return result; + std::unordered_set result; + auto lst = GetInterfaceListInternal(); + for (auto list_entry : lst) + result.emplace(list_entry.first); + return result; } // called from ---GUI--- thread std::string NetPlayServer::GetInterfaceHost(const std::string& inter) { - char buf[16]; - sprintf(buf, ":%d", GetPort()); - auto lst = GetInterfaceListInternal(); - for (const auto& list_entry : lst) - { - if (list_entry.first == inter) - { - return list_entry.second + buf; - } - } - return "?"; + char buf[16]; + sprintf(buf, ":%d", GetPort()); + auto lst = GetInterfaceListInternal(); + for (const auto& list_entry : lst) + { + if (list_entry.first == inter) + { + return list_entry.second + buf; + } + } + return "?"; } // called from ---GUI--- thread std::vector> NetPlayServer::GetInterfaceListInternal() { - std::vector> result; + std::vector> result; #if defined(_WIN32) #elif defined(ANDROID) - // Android has no getifaddrs for some stupid reason. If this - // functionality ends up actually being used on Android, fix this. +// Android has no getifaddrs for some stupid reason. If this +// functionality ends up actually being used on Android, fix this. #else - ifaddrs* ifp = nullptr; - char buf[512]; - if (getifaddrs(&ifp) != -1) - { - for (ifaddrs* curifp = ifp; curifp; curifp = curifp->ifa_next) - { - sockaddr* sa = curifp->ifa_addr; + ifaddrs* ifp = nullptr; + char buf[512]; + if (getifaddrs(&ifp) != -1) + { + for (ifaddrs* curifp = ifp; curifp; curifp = curifp->ifa_next) + { + sockaddr* sa = curifp->ifa_addr; - if (sa == nullptr) - continue; - if (sa->sa_family != AF_INET) - continue; - sockaddr_in* sai = (struct sockaddr_in*) sa; - if (ntohl(((struct sockaddr_in*) sa)->sin_addr.s_addr) == 0x7f000001) - continue; - const char* ip = inet_ntop(sa->sa_family, &sai->sin_addr, buf, sizeof(buf)); - if (ip == nullptr) - continue; - result.emplace_back(std::make_pair(curifp->ifa_name, ip)); - } - freeifaddrs(ifp); - } + if (sa == nullptr) + continue; + if (sa->sa_family != AF_INET) + continue; + sockaddr_in* sai = (struct sockaddr_in*)sa; + if (ntohl(((struct sockaddr_in*)sa)->sin_addr.s_addr) == 0x7f000001) + continue; + const char* ip = inet_ntop(sa->sa_family, &sai->sin_addr, buf, sizeof(buf)); + if (ip == nullptr) + continue; + result.emplace_back(std::make_pair(curifp->ifa_name, ip)); + } + freeifaddrs(ifp); + } #endif - if (result.empty()) - result.emplace_back(std::make_pair("!local!", "127.0.0.1")); - return result; + if (result.empty()) + result.emplace_back(std::make_pair("!local!", "127.0.0.1")); + return result; } #ifdef USE_UPNP -#include #include +#include #include struct UPNPUrls NetPlayServer::m_upnp_urls; @@ -863,128 +853,127 @@ std::thread NetPlayServer::m_upnp_thread; // called from ---GUI--- thread void NetPlayServer::TryPortmapping(u16 port) { - if (m_upnp_thread.joinable()) - m_upnp_thread.join(); - m_upnp_thread = std::thread(&NetPlayServer::mapPortThread, port); + if (m_upnp_thread.joinable()) + m_upnp_thread.join(); + m_upnp_thread = std::thread(&NetPlayServer::mapPortThread, port); } // UPnP thread: try to map a port void NetPlayServer::mapPortThread(const u16 port) { - ENetAddress adr = { ENET_HOST_ANY, port }; - char cIP[20]; + ENetAddress adr = {ENET_HOST_ANY, port}; + char cIP[20]; - enet_address_get_host(&adr, cIP, 20); - std::string ourIP(cIP); + enet_address_get_host(&adr, cIP, 20); + std::string ourIP(cIP); - if (!m_upnp_inited) - if (!initUPnP()) - goto fail; + if (!m_upnp_inited) + if (!initUPnP()) + goto fail; - if (!UPnPMapPort(ourIP, port)) - goto fail; + if (!UPnPMapPort(ourIP, port)) + goto fail; - NOTICE_LOG(NETPLAY, "Successfully mapped port %d to %s.", port, ourIP.c_str()); - return; + NOTICE_LOG(NETPLAY, "Successfully mapped port %d to %s.", port, ourIP.c_str()); + return; fail: - WARN_LOG(NETPLAY, "Failed to map port %d to %s.", port, ourIP.c_str()); - return; + WARN_LOG(NETPLAY, "Failed to map port %d to %s.", port, ourIP.c_str()); + return; } // UPnP thread: try to unmap a port void NetPlayServer::unmapPortThread() { - if (m_upnp_mapped > 0) - UPnPUnmapPort(m_upnp_mapped); + if (m_upnp_mapped > 0) + UPnPUnmapPort(m_upnp_mapped); } // called from ---UPnP--- thread // discovers the IGD bool NetPlayServer::initUPnP() { - std::vector igds; - int descXMLsize = 0, upnperror = 0; + std::vector igds; + int descXMLsize = 0, upnperror = 0; - // Don't init if already inited - if (m_upnp_inited) - return true; + // Don't init if already inited + if (m_upnp_inited) + return true; - // Don't init if it failed before - if (m_upnp_error) - return false; + // Don't init if it failed before + if (m_upnp_error) + return false; - memset(&m_upnp_urls, 0, sizeof(UPNPUrls)); - memset(&m_upnp_data, 0, sizeof(IGDdatas)); + memset(&m_upnp_urls, 0, sizeof(UPNPUrls)); + memset(&m_upnp_data, 0, sizeof(IGDdatas)); - // Find all UPnP devices - std::unique_ptr devlist(nullptr, freeUPNPDevlist); + // Find all UPnP devices + std::unique_ptr devlist(nullptr, freeUPNPDevlist); #if MINIUPNPC_API_VERSION >= 14 - devlist.reset(upnpDiscover(2000, nullptr, nullptr, 0, 0, 2, &upnperror)); + devlist.reset(upnpDiscover(2000, nullptr, nullptr, 0, 0, 2, &upnperror)); #else - devlist.reset(upnpDiscover(2000, nullptr, nullptr, 0, 0, &upnperror)); + devlist.reset(upnpDiscover(2000, nullptr, nullptr, 0, 0, &upnperror)); #endif - if (!devlist) - { - WARN_LOG(NETPLAY, "An error occurred trying to discover UPnP devices."); + if (!devlist) + { + WARN_LOG(NETPLAY, "An error occurred trying to discover UPnP devices."); - m_upnp_error = true; - m_upnp_inited = false; + m_upnp_error = true; + m_upnp_inited = false; - return false; - } + return false; + } - // Look for the IGD - for (UPNPDev* dev = devlist.get(); dev; dev = dev->pNext) - { - if (strstr(dev->st, "InternetGatewayDevice")) - igds.push_back(dev); - } + // Look for the IGD + for (UPNPDev* dev = devlist.get(); dev; dev = dev->pNext) + { + if (strstr(dev->st, "InternetGatewayDevice")) + igds.push_back(dev); + } - for (const UPNPDev* dev : igds) - { - std::unique_ptr descXML(nullptr, std::free); - int statusCode = 200; + for (const UPNPDev* dev : igds) + { + std::unique_ptr descXML(nullptr, std::free); + int statusCode = 200; #if MINIUPNPC_API_VERSION >= 16 - descXML.reset(static_cast(miniwget(dev->descURL, &descXMLsize, 0, &statusCode))); + descXML.reset(static_cast(miniwget(dev->descURL, &descXMLsize, 0, &statusCode))); #else - descXML.reset(static_cast(miniwget(dev->descURL, &descXMLsize, 0))); + descXML.reset(static_cast(miniwget(dev->descURL, &descXMLsize, 0))); #endif - if (descXML && statusCode == 200) - { - parserootdesc(descXML.get(), descXMLsize, &m_upnp_data); - GetUPNPUrls(&m_upnp_urls, &m_upnp_data, dev->descURL, 0); + if (descXML && statusCode == 200) + { + parserootdesc(descXML.get(), descXMLsize, &m_upnp_data); + GetUPNPUrls(&m_upnp_urls, &m_upnp_data, dev->descURL, 0); - NOTICE_LOG(NETPLAY, "Got info from IGD at %s.", dev->descURL); - break; - } - else - { - WARN_LOG(NETPLAY, "Error getting info from IGD at %s.", dev->descURL); - } - } + NOTICE_LOG(NETPLAY, "Got info from IGD at %s.", dev->descURL); + break; + } + else + { + WARN_LOG(NETPLAY, "Error getting info from IGD at %s.", dev->descURL); + } + } - return true; + return true; } // called from ---UPnP--- thread // Attempt to portforward! bool NetPlayServer::UPnPMapPort(const std::string& addr, const u16 port) { - if (m_upnp_mapped > 0) - UPnPUnmapPort(m_upnp_mapped); + if (m_upnp_mapped > 0) + UPnPUnmapPort(m_upnp_mapped); - std::string port_str = StringFromFormat("%d", port); - int result = UPNP_AddPortMapping(m_upnp_urls.controlURL, m_upnp_data.first.servicetype, - port_str.c_str(), port_str.c_str(), addr.c_str(), - (std::string("dolphin-emu UDP on ") + addr).c_str(), - "UDP", nullptr, nullptr); + std::string port_str = StringFromFormat("%d", port); + int result = UPNP_AddPortMapping( + m_upnp_urls.controlURL, m_upnp_data.first.servicetype, port_str.c_str(), port_str.c_str(), + addr.c_str(), (std::string("dolphin-emu UDP on ") + addr).c_str(), "UDP", nullptr, nullptr); - if (result != 0) - return false; + if (result != 0) + return false; - m_upnp_mapped = port; + m_upnp_mapped = port; - return true; + return true; } // called from ---UPnP--- thread @@ -997,10 +986,10 @@ bool NetPlayServer::UPnPMapPort(const std::string& addr, const u16 port) // -- bool NetPlayServer::UPnPUnmapPort(const u16 port) { - std::string port_str = StringFromFormat("%d", port); - UPNP_DeletePortMapping(m_upnp_urls.controlURL, m_upnp_data.first.servicetype, - port_str.c_str(), "UDP", nullptr); + std::string port_str = StringFromFormat("%d", port); + UPNP_DeletePortMapping(m_upnp_urls.controlURL, m_upnp_data.first.servicetype, port_str.c_str(), + "UDP", nullptr); - return true; + return true; } #endif diff --git a/Source/Core/Core/NetPlayServer.h b/Source/Core/Core/NetPlayServer.h index f85383c120..3af57d9cc3 100644 --- a/Source/Core/Core/NetPlayServer.h +++ b/Source/Core/Core/NetPlayServer.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -11,7 +12,6 @@ #include #include #include -#include #include "Common/Timer.h" #include "Common/TraversalClient.h" #include "Core/NetPlayProto.h" @@ -21,119 +21,115 @@ class NetPlayUI; class NetPlayServer : public TraversalClientClient { public: - void ThreadFunc(); - void SendAsyncToClients(std::unique_ptr packet); + void ThreadFunc(); + void SendAsyncToClients(std::unique_ptr packet); - NetPlayServer(const u16 port, bool traversal, const std::string& centralServer, u16 centralPort); - ~NetPlayServer(); + NetPlayServer(const u16 port, bool traversal, const std::string& centralServer, u16 centralPort); + ~NetPlayServer(); - bool ChangeGame(const std::string& game); - void SendChatMessage(const std::string& msg); + bool ChangeGame(const std::string& game); + void SendChatMessage(const std::string& msg); - void SetNetSettings(const NetSettings &settings); + void SetNetSettings(const NetSettings& settings); - bool StartGame(); + bool StartGame(); - PadMappingArray GetPadMapping() const; - void SetPadMapping(const PadMappingArray& mappings); + PadMappingArray GetPadMapping() const; + void SetPadMapping(const PadMappingArray& mappings); - PadMappingArray GetWiimoteMapping() const; - void SetWiimoteMapping(const PadMappingArray& mappings); + PadMappingArray GetWiimoteMapping() const; + void SetWiimoteMapping(const PadMappingArray& mappings); - void AdjustPadBufferSize(unsigned int size); + void AdjustPadBufferSize(unsigned int size); - void KickPlayer(PlayerId player); + void KickPlayer(PlayerId player); - u16 GetPort(); + u16 GetPort(); - void SetNetPlayUI(NetPlayUI* dialog); - std::unordered_set GetInterfaceSet(); - std::string GetInterfaceHost(const std::string& inter); + void SetNetPlayUI(NetPlayUI* dialog); + std::unordered_set GetInterfaceSet(); + std::string GetInterfaceHost(const std::string& inter); - bool is_connected = false; + bool is_connected = false; #ifdef USE_UPNP - void TryPortmapping(u16 port); + void TryPortmapping(u16 port); #endif private: - class Client - { - public: - PlayerId pid; - std::string name; - std::string revision; + class Client + { + public: + PlayerId pid; + std::string name; + std::string revision; - ENetPeer* socket; - u32 ping; - u32 current_game; + ENetPeer* socket; + u32 ping; + u32 current_game; - bool operator==(const Client& other) const - { - return this == &other; - } - }; + bool operator==(const Client& other) const { return this == &other; } + }; - void SendToClients(sf::Packet& packet, const PlayerId skip_pid = 0); - void Send(ENetPeer* socket, sf::Packet& packet); - unsigned int OnConnect(ENetPeer* socket); - unsigned int OnDisconnect(Client& player); - unsigned int OnData(sf::Packet& packet, Client& player); + void SendToClients(sf::Packet& packet, const PlayerId skip_pid = 0); + void Send(ENetPeer* socket, sf::Packet& packet); + unsigned int OnConnect(ENetPeer* socket); + unsigned int OnDisconnect(Client& player); + unsigned int OnData(sf::Packet& packet, Client& player); - void OnTraversalStateChanged() override; - void OnConnectReady(ENetAddress) override {} - void OnConnectFailed(u8) override {} + void OnTraversalStateChanged() override; + void OnConnectReady(ENetAddress) override {} + void OnConnectFailed(u8) override {} + void UpdatePadMapping(); + void UpdateWiimoteMapping(); + std::vector> GetInterfaceListInternal(); - void UpdatePadMapping(); - void UpdateWiimoteMapping(); - std::vector> GetInterfaceListInternal(); + NetSettings m_settings; - NetSettings m_settings; + bool m_is_running = false; + bool m_do_loop = false; + Common::Timer m_ping_timer; + u32 m_ping_key = 0; + bool m_update_pings = false; + u32 m_current_game = 0; + unsigned int m_target_buffer_size = 0; + PadMappingArray m_pad_map; + PadMappingArray m_wiimote_map; - bool m_is_running = false; - bool m_do_loop = false; - Common::Timer m_ping_timer; - u32 m_ping_key = 0; - bool m_update_pings = false; - u32 m_current_game = 0; - unsigned int m_target_buffer_size = 0; - PadMappingArray m_pad_map; - PadMappingArray m_wiimote_map; + std::map m_players; - std::map m_players; + std::unordered_map>> m_timebase_by_frame; + bool m_desync_detected; - std::unordered_map>> m_timebase_by_frame; - bool m_desync_detected; + struct + { + std::recursive_mutex game; + // lock order + std::recursive_mutex players; + std::recursive_mutex async_queue_write; + } m_crit; - struct - { - std::recursive_mutex game; - // lock order - std::recursive_mutex players; - std::recursive_mutex async_queue_write; - } m_crit; + std::string m_selected_game; + std::thread m_thread; + Common::FifoQueue, false> m_async_queue; - std::string m_selected_game; - std::thread m_thread; - Common::FifoQueue, false> m_async_queue; - - ENetHost* m_server = nullptr; - TraversalClient* m_traversal_client = nullptr; - NetPlayUI* m_dialog = nullptr; + ENetHost* m_server = nullptr; + TraversalClient* m_traversal_client = nullptr; + NetPlayUI* m_dialog = nullptr; #ifdef USE_UPNP - static void mapPortThread(const u16 port); - static void unmapPortThread(); + static void mapPortThread(const u16 port); + static void unmapPortThread(); - static bool initUPnP(); - static bool UPnPMapPort(const std::string& addr, const u16 port); - static bool UPnPUnmapPort(const u16 port); + static bool initUPnP(); + static bool UPnPMapPort(const std::string& addr, const u16 port); + static bool UPnPUnmapPort(const u16 port); - static struct UPNPUrls m_upnp_urls; - static struct IGDdatas m_upnp_data; - static u16 m_upnp_mapped; - static bool m_upnp_inited; - static bool m_upnp_error; - static std::thread m_upnp_thread; + static struct UPNPUrls m_upnp_urls; + static struct IGDdatas m_upnp_data; + static u16 m_upnp_mapped; + static bool m_upnp_inited; + static bool m_upnp_error; + static std::thread m_upnp_thread; #endif }; diff --git a/Source/Core/Core/PatchEngine.cpp b/Source/Core/Core/PatchEngine.cpp index 48211a61e0..eef8f919b8 100644 --- a/Source/Core/Core/PatchEngine.cpp +++ b/Source/Core/Core/PatchEngine.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // PatchEngine // Supports simple memory patches, and has a partial Action Replay implementation // in ActionReplay.cpp/h. @@ -37,196 +36,194 @@ using namespace Common; namespace PatchEngine { - -const char *PatchTypeStrings[] = -{ - "byte", - "word", - "dword", +const char* PatchTypeStrings[] = { + "byte", "word", "dword", }; static std::vector onFrame; static std::map speedHacks; -void LoadPatchSection(const std::string& section, std::vector& patches, IniFile& globalIni, IniFile& localIni) +void LoadPatchSection(const std::string& section, std::vector& patches, IniFile& globalIni, + IniFile& localIni) { - // Load the name of all enabled patches - std::string enabledSectionName = section + "_Enabled"; - std::vector enabledLines; - std::set enabledNames; - localIni.GetLines(enabledSectionName, &enabledLines); - for (const std::string& line : enabledLines) - { - if (line.size() != 0 && line[0] == '$') - { - std::string name = line.substr(1, line.size() - 1); - enabledNames.insert(name); - } - } + // Load the name of all enabled patches + std::string enabledSectionName = section + "_Enabled"; + std::vector enabledLines; + std::set enabledNames; + localIni.GetLines(enabledSectionName, &enabledLines); + for (const std::string& line : enabledLines) + { + if (line.size() != 0 && line[0] == '$') + { + std::string name = line.substr(1, line.size() - 1); + enabledNames.insert(name); + } + } - const IniFile* inis[2] = {&globalIni, &localIni}; + const IniFile* inis[2] = {&globalIni, &localIni}; - for (const IniFile* ini : inis) - { - std::vector lines; - Patch currentPatch; - ini->GetLines(section, &lines); + for (const IniFile* ini : inis) + { + std::vector lines; + Patch currentPatch; + ini->GetLines(section, &lines); - for (std::string& line : lines) - { - if (line.size() == 0) - continue; + for (std::string& line : lines) + { + if (line.size() == 0) + continue; - if (line[0] == '$') - { - // Take care of the previous code - if (currentPatch.name.size()) - { - patches.push_back(currentPatch); - } - currentPatch.entries.clear(); + if (line[0] == '$') + { + // Take care of the previous code + if (currentPatch.name.size()) + { + patches.push_back(currentPatch); + } + currentPatch.entries.clear(); - // Set active and name - currentPatch.name = line.substr(1, line.size() - 1); - currentPatch.active = enabledNames.find(currentPatch.name) != enabledNames.end(); - currentPatch.user_defined = (ini == &localIni); - } - else - { - std::string::size_type loc = line.find('='); + // Set active and name + currentPatch.name = line.substr(1, line.size() - 1); + currentPatch.active = enabledNames.find(currentPatch.name) != enabledNames.end(); + currentPatch.user_defined = (ini == &localIni); + } + else + { + std::string::size_type loc = line.find('='); - if (loc != std::string::npos) - { - line[loc] = ':'; - } + if (loc != std::string::npos) + { + line[loc] = ':'; + } - std::vector items; - SplitString(line, ':', items); + std::vector items; + SplitString(line, ':', items); - if (items.size() >= 3) - { - PatchEntry pE; - bool success = true; - success &= TryParse(items[0], &pE.address); - success &= TryParse(items[2], &pE.value); + if (items.size() >= 3) + { + PatchEntry pE; + bool success = true; + success &= TryParse(items[0], &pE.address); + success &= TryParse(items[2], &pE.value); - pE.type = PatchType(std::find(PatchTypeStrings, PatchTypeStrings + 3, items[1]) - PatchTypeStrings); - success &= (pE.type != (PatchType)3); - if (success) - { - currentPatch.entries.push_back(pE); - } - } - } - } + pE.type = PatchType(std::find(PatchTypeStrings, PatchTypeStrings + 3, items[1]) - + PatchTypeStrings); + success &= (pE.type != (PatchType)3); + if (success) + { + currentPatch.entries.push_back(pE); + } + } + } + } - if (currentPatch.name.size() && currentPatch.entries.size()) - { - patches.push_back(currentPatch); - } - } + if (currentPatch.name.size() && currentPatch.entries.size()) + { + patches.push_back(currentPatch); + } + } } static void LoadSpeedhacks(const std::string& section, IniFile& ini) { - std::vector keys; - ini.GetKeys(section, &keys); - for (const std::string& key : keys) - { - std::string value; - ini.GetOrCreateSection(section)->Get(key, &value, "BOGUS"); - if (value != "BOGUS") - { - u32 address; - u32 cycles; - bool success = true; - success &= TryParse(key, &address); - success &= TryParse(value, &cycles); - if (success) - { - speedHacks[address] = (int)cycles; - } - } - } + std::vector keys; + ini.GetKeys(section, &keys); + for (const std::string& key : keys) + { + std::string value; + ini.GetOrCreateSection(section)->Get(key, &value, "BOGUS"); + if (value != "BOGUS") + { + u32 address; + u32 cycles; + bool success = true; + success &= TryParse(key, &address); + success &= TryParse(value, &cycles); + if (success) + { + speedHacks[address] = (int)cycles; + } + } + } } int GetSpeedhackCycles(const u32 addr) { - std::map::const_iterator iter = speedHacks.find(addr); - if (iter == speedHacks.end()) - return 0; - else - return iter->second; + std::map::const_iterator iter = speedHacks.find(addr); + if (iter == speedHacks.end()) + return 0; + else + return iter->second; } void LoadPatches() { - IniFile merged = SConfig::GetInstance().LoadGameIni(); - IniFile globalIni = SConfig::GetInstance().LoadDefaultGameIni(); - IniFile localIni = SConfig::GetInstance().LoadLocalGameIni(); + IniFile merged = SConfig::GetInstance().LoadGameIni(); + IniFile globalIni = SConfig::GetInstance().LoadDefaultGameIni(); + IniFile localIni = SConfig::GetInstance().LoadLocalGameIni(); - LoadPatchSection("OnFrame", onFrame, globalIni, localIni); - ActionReplay::LoadAndApplyCodes(globalIni, localIni); + LoadPatchSection("OnFrame", onFrame, globalIni, localIni); + ActionReplay::LoadAndApplyCodes(globalIni, localIni); - // lil silly - std::vector gcodes; - Gecko::LoadCodes(globalIni, localIni, gcodes); - Gecko::SetActiveCodes(gcodes); + // lil silly + std::vector gcodes; + Gecko::LoadCodes(globalIni, localIni, gcodes); + Gecko::SetActiveCodes(gcodes); - LoadSpeedhacks("Speedhacks", merged); + LoadSpeedhacks("Speedhacks", merged); } -static void ApplyPatches(const std::vector &patches) +static void ApplyPatches(const std::vector& patches) { - for (const Patch& patch : patches) - { - if (patch.active) - { - for (const PatchEntry& entry : patch.entries) - { - u32 addr = entry.address; - u32 value = entry.value; - switch (entry.type) - { - case PATCH_8BIT: - PowerPC::HostWrite_U8((u8)value, addr); - break; - case PATCH_16BIT: - PowerPC::HostWrite_U16((u16)value, addr); - break; - case PATCH_32BIT: - PowerPC::HostWrite_U32(value, addr); - break; - default: - //unknown patchtype - break; - } - } - } - } + for (const Patch& patch : patches) + { + if (patch.active) + { + for (const PatchEntry& entry : patch.entries) + { + u32 addr = entry.address; + u32 value = entry.value; + switch (entry.type) + { + case PATCH_8BIT: + PowerPC::HostWrite_U8((u8)value, addr); + break; + case PATCH_16BIT: + PowerPC::HostWrite_U16((u16)value, addr); + break; + case PATCH_32BIT: + PowerPC::HostWrite_U32(value, addr); + break; + default: + // unknown patchtype + break; + } + } + } + } } void ApplyFramePatches() { - // TODO: Messing with MSR this way is really, really, evil; we should - // probably be using some sort of Gecko OS-style hooking mechanism - // so the emulated CPU is in a predictable state when we process cheats. - u32 oldMSR = MSR; - UReg_MSR newMSR = oldMSR; - newMSR.IR = 1; - newMSR.DR = 1; - MSR = newMSR.Hex; - ApplyPatches(onFrame); + // TODO: Messing with MSR this way is really, really, evil; we should + // probably be using some sort of Gecko OS-style hooking mechanism + // so the emulated CPU is in a predictable state when we process cheats. + u32 oldMSR = MSR; + UReg_MSR newMSR = oldMSR; + newMSR.IR = 1; + newMSR.DR = 1; + MSR = newMSR.Hex; + ApplyPatches(onFrame); - // Run the Gecko code handler - Gecko::RunCodeHandler(); - ActionReplay::RunAllActive(); - MSR = oldMSR; + // Run the Gecko code handler + Gecko::RunCodeHandler(); + ActionReplay::RunAllActive(); + MSR = oldMSR; } void Shutdown() { - onFrame.clear(); + onFrame.clear(); } } // namespace diff --git a/Source/Core/Core/PatchEngine.h b/Source/Core/Core/PatchEngine.h index 8132a15fa6..61975a8d82 100644 --- a/Source/Core/Core/PatchEngine.h +++ b/Source/Core/Core/PatchEngine.h @@ -13,58 +13,57 @@ class IniFile; namespace PatchEngine { - enum PatchType { - PATCH_8BIT, - PATCH_16BIT, - PATCH_32BIT, + PATCH_8BIT, + PATCH_16BIT, + PATCH_32BIT, }; -extern const char *PatchTypeStrings[]; +extern const char* PatchTypeStrings[]; struct PatchEntry { - PatchEntry() {} - PatchEntry(PatchType _t, u32 _addr, u32 _value) : type(_t), address(_addr), value(_value) {} - PatchType type; - u32 address; - u32 value; + PatchEntry() {} + PatchEntry(PatchType _t, u32 _addr, u32 _value) : type(_t), address(_addr), value(_value) {} + PatchType type; + u32 address; + u32 value; }; struct Patch { - std::string name; - std::vector entries; - bool active; - bool user_defined; // False if this code is shipped with Dolphin. + std::string name; + std::vector entries; + bool active; + bool user_defined; // False if this code is shipped with Dolphin. }; int GetSpeedhackCycles(const u32 addr); -void LoadPatchSection(const std::string& section, std::vector &patches, - IniFile &globalIni, IniFile &localIni); +void LoadPatchSection(const std::string& section, std::vector& patches, IniFile& globalIni, + IniFile& localIni); void LoadPatches(); void ApplyFramePatches(); void Shutdown(); inline int GetPatchTypeCharLength(PatchType type) { - int size = 8; - switch (type) - { - case PatchEngine::PATCH_8BIT: - size = 2; - break; + int size = 8; + switch (type) + { + case PatchEngine::PATCH_8BIT: + size = 2; + break; - case PatchEngine::PATCH_16BIT: - size = 4; - break; + case PatchEngine::PATCH_16BIT: + size = 4; + break; - case PatchEngine::PATCH_32BIT: - size = 8; - break; - } - return size; + case PatchEngine::PATCH_32BIT: + size = 8; + break; + } + return size; } } // namespace diff --git a/Source/Core/Core/PowerPC/CPUCoreBase.h b/Source/Core/Core/PowerPC/CPUCoreBase.h index 2de9cd28f6..55700b4ece 100644 --- a/Source/Core/Core/PowerPC/CPUCoreBase.h +++ b/Source/Core/Core/PowerPC/CPUCoreBase.h @@ -7,12 +7,11 @@ class CPUCoreBase { public: - virtual ~CPUCoreBase() {} - - virtual void Init() = 0; - virtual void Shutdown() = 0; - virtual void ClearCache() = 0; - virtual void Run() = 0; - virtual void SingleStep() = 0; - virtual const char *GetName() = 0; + virtual ~CPUCoreBase() {} + virtual void Init() = 0; + virtual void Shutdown() = 0; + virtual void ClearCache() = 0; + virtual void Run() = 0; + virtual void SingleStep() = 0; + virtual const char* GetName() = 0; }; diff --git a/Source/Core/Core/PowerPC/CachedInterpreter.cpp b/Source/Core/Core/PowerPC/CachedInterpreter.cpp index 622906cca5..8bdc6bd23e 100644 --- a/Source/Core/Core/PowerPC/CachedInterpreter.cpp +++ b/Source/Core/Core/PowerPC/CachedInterpreter.cpp @@ -2,194 +2,195 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/CachedInterpreter.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Core/ConfigManager.h" #include "Core/CoreTiming.h" #include "Core/HLE/HLE.h" #include "Core/HW/CPU.h" -#include "Core/PowerPC/CachedInterpreter.h" #include "Core/PowerPC/Gekko.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PPCAnalyst.h" +#include "Core/PowerPC/PowerPC.h" void CachedInterpreter::Init() { - m_code.reserve(CODE_SIZE / sizeof(Instruction)); + m_code.reserve(CODE_SIZE / sizeof(Instruction)); - jo.enableBlocklink = false; + jo.enableBlocklink = false; - JitBaseBlockCache::Init(); + JitBaseBlockCache::Init(); - code_block.m_stats = &js.st; - code_block.m_gpa = &js.gpa; - code_block.m_fpa = &js.fpa; + code_block.m_stats = &js.st; + code_block.m_gpa = &js.gpa; + code_block.m_fpa = &js.fpa; } void CachedInterpreter::Shutdown() { - JitBaseBlockCache::Shutdown(); + JitBaseBlockCache::Shutdown(); } void CachedInterpreter::Run() { - while (!CPU::GetState()) - { - SingleStep(); - } + while (!CPU::GetState()) + { + SingleStep(); + } } void CachedInterpreter::SingleStep() { - int block = GetBlockNumberFromStartAddress(PC); - if (block >= 0) - { - Instruction* code = (Instruction*)GetCompiledCodeFromBlock(block); + int block = GetBlockNumberFromStartAddress(PC); + if (block >= 0) + { + Instruction* code = (Instruction*)GetCompiledCodeFromBlock(block); - while (true) - { - switch (code->type) - { - case Instruction::INSTRUCTION_ABORT: - return; + while (true) + { + switch (code->type) + { + case Instruction::INSTRUCTION_ABORT: + return; - case Instruction::INSTRUCTION_TYPE_COMMON: - code->common_callback(UGeckoInstruction(code->data)); - code++; - break; + case Instruction::INSTRUCTION_TYPE_COMMON: + code->common_callback(UGeckoInstruction(code->data)); + code++; + break; - case Instruction::INSTRUCTION_TYPE_CONDITIONAL: - bool ret = code->conditional_callback(code->data); - code++; - if (ret) - return; - break; - } - } - } + case Instruction::INSTRUCTION_TYPE_CONDITIONAL: + bool ret = code->conditional_callback(code->data); + code++; + if (ret) + return; + break; + } + } + } - Jit(PC); + Jit(PC); } static void EndBlock(UGeckoInstruction data) { - PC = NPC; - PowerPC::ppcState.downcount -= data.hex; - if (PowerPC::ppcState.downcount <= 0) - { - CoreTiming::Advance(); - } + PC = NPC; + PowerPC::ppcState.downcount -= data.hex; + if (PowerPC::ppcState.downcount <= 0) + { + CoreTiming::Advance(); + } } static void WritePC(UGeckoInstruction data) { - PC = data.hex; - NPC = data.hex + 4; + PC = data.hex; + NPC = data.hex + 4; } static bool CheckFPU(u32 data) { - UReg_MSR& msr = (UReg_MSR&)MSR; - if (!msr.FP) - { - PC = NPC = data; - PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE; - PowerPC::CheckExceptions(); - return true; - } - return false; + UReg_MSR& msr = (UReg_MSR&)MSR; + if (!msr.FP) + { + PC = NPC = data; + PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE; + PowerPC::CheckExceptions(); + return true; + } + return false; } void CachedInterpreter::Jit(u32 address) { - if (m_code.size() >= CODE_SIZE / sizeof(Instruction) - 0x1000 || IsFull() || SConfig::GetInstance().bJITNoBlockCache) - { - ClearCache(); - } + if (m_code.size() >= CODE_SIZE / sizeof(Instruction) - 0x1000 || IsFull() || + SConfig::GetInstance().bJITNoBlockCache) + { + ClearCache(); + } - u32 nextPC = analyzer.Analyze(PC, &code_block, &code_buffer, code_buffer.GetSize()); - if (code_block.m_memory_exception) - { - // Address of instruction could not be translated - NPC = nextPC; - PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; - PowerPC::CheckExceptions(); - WARN_LOG(POWERPC, "ISI exception at 0x%08x", nextPC); - return; - } + u32 nextPC = analyzer.Analyze(PC, &code_block, &code_buffer, code_buffer.GetSize()); + if (code_block.m_memory_exception) + { + // Address of instruction could not be translated + NPC = nextPC; + PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; + PowerPC::CheckExceptions(); + WARN_LOG(POWERPC, "ISI exception at 0x%08x", nextPC); + return; + } - int block_num = AllocateBlock(PC); - JitBlock *b = GetBlock(block_num); + int block_num = AllocateBlock(PC); + JitBlock* b = GetBlock(block_num); - js.blockStart = PC; - js.firstFPInstructionFound = false; - js.fifoBytesThisBlock = 0; - js.downcountAmount = 0; - js.curBlock = b; + js.blockStart = PC; + js.firstFPInstructionFound = false; + js.fifoBytesThisBlock = 0; + js.downcountAmount = 0; + js.curBlock = b; - PPCAnalyst::CodeOp *ops = code_buffer.codebuffer; + PPCAnalyst::CodeOp* ops = code_buffer.codebuffer; - b->checkedEntry = GetCodePtr(); - b->normalEntry = GetCodePtr(); - b->runCount = 0; + b->checkedEntry = GetCodePtr(); + b->normalEntry = GetCodePtr(); + b->runCount = 0; - for (u32 i = 0; i < code_block.m_num_instructions; i++) - { - js.downcountAmount += ops[i].opinfo->numCycles; + for (u32 i = 0; i < code_block.m_num_instructions; i++) + { + js.downcountAmount += ops[i].opinfo->numCycles; - u32 function = HLE::GetFunctionIndex(ops[i].address); - if (function != 0) - { - int type = HLE::GetFunctionTypeByIndex(function); - if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE) - { - int flags = HLE::GetFunctionFlagsByIndex(function); - if (HLE::IsEnabled(flags)) - { - m_code.emplace_back(WritePC, ops[i].address); - m_code.emplace_back(Interpreter::HLEFunction, ops[i].inst); - if (type == HLE::HLE_HOOK_REPLACE) - { - m_code.emplace_back(EndBlock, js.downcountAmount); - m_code.emplace_back(); - break; - } - } - } - } + u32 function = HLE::GetFunctionIndex(ops[i].address); + if (function != 0) + { + int type = HLE::GetFunctionTypeByIndex(function); + if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE) + { + int flags = HLE::GetFunctionFlagsByIndex(function); + if (HLE::IsEnabled(flags)) + { + m_code.emplace_back(WritePC, ops[i].address); + m_code.emplace_back(Interpreter::HLEFunction, ops[i].inst); + if (type == HLE::HLE_HOOK_REPLACE) + { + m_code.emplace_back(EndBlock, js.downcountAmount); + m_code.emplace_back(); + break; + } + } + } + } - if (!ops[i].skip) - { - if ((ops[i].opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound) - { - m_code.emplace_back(CheckFPU, ops[i].address); - js.firstFPInstructionFound = true; - } + if (!ops[i].skip) + { + if ((ops[i].opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound) + { + m_code.emplace_back(CheckFPU, ops[i].address); + js.firstFPInstructionFound = true; + } - if (ops[i].opinfo->flags & FL_ENDBLOCK) - m_code.emplace_back(WritePC, ops[i].address); - m_code.emplace_back(GetInterpreterOp(ops[i].inst), ops[i].inst); - if (ops[i].opinfo->flags & FL_ENDBLOCK) - m_code.emplace_back(EndBlock, js.downcountAmount); - } - } - if (code_block.m_broken) - { - m_code.emplace_back(WritePC, nextPC); - m_code.emplace_back(EndBlock, js.downcountAmount); - } - m_code.emplace_back(); + if (ops[i].opinfo->flags & FL_ENDBLOCK) + m_code.emplace_back(WritePC, ops[i].address); + m_code.emplace_back(GetInterpreterOp(ops[i].inst), ops[i].inst); + if (ops[i].opinfo->flags & FL_ENDBLOCK) + m_code.emplace_back(EndBlock, js.downcountAmount); + } + } + if (code_block.m_broken) + { + m_code.emplace_back(WritePC, nextPC); + m_code.emplace_back(EndBlock, js.downcountAmount); + } + m_code.emplace_back(); - b->codeSize = (u32)(GetCodePtr() - b->checkedEntry); - b->originalSize = code_block.m_num_instructions; + b->codeSize = (u32)(GetCodePtr() - b->checkedEntry); + b->originalSize = code_block.m_num_instructions; - FinalizeBlock(block_num, jo.enableBlocklink, b->checkedEntry); + FinalizeBlock(block_num, jo.enableBlocklink, b->checkedEntry); } void CachedInterpreter::ClearCache() { - m_code.clear(); - JitBaseBlockCache::Clear(); + m_code.clear(); + JitBaseBlockCache::Clear(); } void CachedInterpreter::WriteDestroyBlock(const u8* location, u32 address) diff --git a/Source/Core/Core/PowerPC/CachedInterpreter.h b/Source/Core/Core/PowerPC/CachedInterpreter.h index cf7aa90615..d43fa7e9ff 100644 --- a/Source/Core/Core/PowerPC/CachedInterpreter.h +++ b/Source/Core/Core/PowerPC/CachedInterpreter.h @@ -7,69 +7,59 @@ #include #include "Common/CommonTypes.h" -#include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/JitCommon/JitBase.h" +#include "Core/PowerPC/PPCAnalyst.h" class CachedInterpreter : public JitBase, JitBaseBlockCache { public: - CachedInterpreter() : code_buffer(32000) {} - ~CachedInterpreter() {} + CachedInterpreter() : code_buffer(32000) {} + ~CachedInterpreter() {} + void Init() override; + void Shutdown() override; - void Init() override; - void Shutdown() override; + bool HandleFault(uintptr_t access_address, SContext* ctx) override { return false; } + void ClearCache() override; - bool HandleFault(uintptr_t access_address, SContext* ctx) override { return false; } + void Run() override; + void SingleStep() override; - void ClearCache() override; + void Jit(u32 address) override; - void Run() override; - void SingleStep() override; + JitBaseBlockCache* GetBlockCache() override { return this; } + const char* GetName() override { return "Cached Interpreter"; } + void WriteLinkBlock(u8* location, const JitBlock& block) override; - void Jit(u32 address) override; - - JitBaseBlockCache* GetBlockCache() override { return this; } - - const char* GetName() override - { - return "Cached Interpreter"; - } - - void WriteLinkBlock(u8* location, const JitBlock& block) override; - - void WriteDestroyBlock(const u8* location, u32 address) override; - - const CommonAsmRoutinesBase* GetAsmRoutines() override { return nullptr; }; + void WriteDestroyBlock(const u8* location, u32 address) override; + const CommonAsmRoutinesBase* GetAsmRoutines() override { return nullptr; }; private: - struct Instruction - { - typedef void (*CommonCallback)(UGeckoInstruction); - typedef bool (*ConditionalCallback)(u32 data); + struct Instruction + { + typedef void (*CommonCallback)(UGeckoInstruction); + typedef bool (*ConditionalCallback)(u32 data); - Instruction() : type(INSTRUCTION_ABORT) {}; - Instruction(const CommonCallback c, UGeckoInstruction i) : common_callback(c), data(i.hex), type(INSTRUCTION_TYPE_COMMON) {}; - Instruction(const ConditionalCallback c, u32 d) : conditional_callback(c), data(d), type(INSTRUCTION_TYPE_CONDITIONAL) {}; + Instruction() : type(INSTRUCTION_ABORT){}; + Instruction(const CommonCallback c, UGeckoInstruction i) + : common_callback(c), data(i.hex), type(INSTRUCTION_TYPE_COMMON){}; + Instruction(const ConditionalCallback c, u32 d) + : conditional_callback(c), data(d), type(INSTRUCTION_TYPE_CONDITIONAL){}; - union - { - const CommonCallback common_callback; - const ConditionalCallback conditional_callback; + union { + const CommonCallback common_callback; + const ConditionalCallback conditional_callback; + }; + u32 data; + enum + { + INSTRUCTION_ABORT, + INSTRUCTION_TYPE_COMMON, + INSTRUCTION_TYPE_CONDITIONAL, + } type; + }; - }; - u32 data; - enum - { - INSTRUCTION_ABORT, - INSTRUCTION_TYPE_COMMON, - INSTRUCTION_TYPE_CONDITIONAL, - } type; - }; + const u8* GetCodePtr() { return (u8*)(m_code.data() + m_code.size()); } + std::vector m_code; - const u8* GetCodePtr() { return (u8*)(m_code.data() + m_code.size()); } - - std::vector m_code; - - PPCAnalyst::CodeBuffer code_buffer; + PPCAnalyst::CodeBuffer code_buffer; }; - diff --git a/Source/Core/Core/PowerPC/GDBStub.cpp b/Source/Core/Core/PowerPC/GDBStub.cpp index 3ad2715d18..b97c373a96 100644 --- a/Source/Core/Core/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/PowerPC/GDBStub.cpp @@ -10,27 +10,26 @@ #include #include #ifdef _WIN32 +#include +#include #include -#include -#include #else +#include #include #include #include -#include #endif #include "Core/Host.h" #include "Core/PowerPC/GDBStub.h" -#define GDB_BFR_MAX 10000 -#define GDB_MAX_BP 10 +#define GDB_BFR_MAX 10000 +#define GDB_MAX_BP 10 #define GDB_STUB_START '$' -#define GDB_STUB_END '#' -#define GDB_STUB_ACK '+' -#define GDB_STUB_NAK '-' - +#define GDB_STUB_END '#' +#define GDB_STUB_ACK '+' +#define GDB_STUB_NAK '-' static int tmpsock = -1; static int sock = -1; @@ -42,10 +41,11 @@ static u32 sig = 0; static u32 send_signal = 0; static u32 step_break = 0; -typedef struct { - u32 active; - u32 addr; - u32 len; +typedef struct +{ + u32 active; + u32 addr; + u32 len; } gdb_bp_t; static gdb_bp_t bp_x[GDB_MAX_BP]; @@ -56,742 +56,746 @@ static gdb_bp_t bp_a[GDB_MAX_BP]; // private helpers static u8 hex2char(u8 hex) { - if (hex >= '0' && hex <= '9') - return hex - '0'; - else if (hex >= 'a' && hex <= 'f') - return hex - 'a' + 0xa; - else if (hex >= 'A' && hex <= 'F') - return hex - 'A' + 0xa; + if (hex >= '0' && hex <= '9') + return hex - '0'; + else if (hex >= 'a' && hex <= 'f') + return hex - 'a' + 0xa; + else if (hex >= 'A' && hex <= 'F') + return hex - 'A' + 0xa; - ERROR_LOG(GDB_STUB, "Invalid nibble: %c (%02x)\n", hex, hex); - return 0; + ERROR_LOG(GDB_STUB, "Invalid nibble: %c (%02x)\n", hex, hex); + return 0; } static u8 nibble2hex(u8 n) { - n &= 0xf; - if (n < 0xa) - return '0' + n; - else - return 'A' + n - 0xa; + n &= 0xf; + if (n < 0xa) + return '0' + n; + else + return 'A' + n - 0xa; } -static void mem2hex(u8 *dst, u8 *src, u32 len) +static void mem2hex(u8* dst, u8* src, u32 len) { - u8 tmp; + u8 tmp; - while (len-- > 0) { - tmp = *src++; - *dst++ = nibble2hex(tmp>>4); - *dst++ = nibble2hex(tmp); - } + while (len-- > 0) + { + tmp = *src++; + *dst++ = nibble2hex(tmp >> 4); + *dst++ = nibble2hex(tmp); + } } -static void hex2mem(u8 *dst, u8 *src, u32 len) +static void hex2mem(u8* dst, u8* src, u32 len) { - while (len-- > 0) { - *dst++ = (hex2char(*src) << 4) | hex2char(*(src+1)); - src += 2; - } + while (len-- > 0) + { + *dst++ = (hex2char(*src) << 4) | hex2char(*(src + 1)); + src += 2; + } } static u8 gdb_read_byte() { - ssize_t res; - u8 c = '+'; + ssize_t res; + u8 c = '+'; - res = recv(sock, &c, 1, MSG_WAITALL); - if (res != 1) - { - ERROR_LOG(GDB_STUB, "recv failed : %ld", res); - gdb_deinit(); - } + res = recv(sock, &c, 1, MSG_WAITALL); + if (res != 1) + { + ERROR_LOG(GDB_STUB, "recv failed : %ld", res); + gdb_deinit(); + } - return c; + return c; } static u8 gdb_calc_chksum() { - u32 len = cmd_len; - u8 *ptr = cmd_bfr; - u8 c = 0; + u32 len = cmd_len; + u8* ptr = cmd_bfr; + u8 c = 0; - while (len-- > 0) - c += *ptr++; + while (len-- > 0) + c += *ptr++; - return c; + return c; } -static gdb_bp_t *gdb_bp_ptr(u32 type) +static gdb_bp_t* gdb_bp_ptr(u32 type) { - switch (type) { - case GDB_BP_TYPE_X: - return bp_x; - case GDB_BP_TYPE_R: - return bp_x; - case GDB_BP_TYPE_W: - return bp_x; - case GDB_BP_TYPE_A: - return bp_x; - default: - return nullptr; - } + switch (type) + { + case GDB_BP_TYPE_X: + return bp_x; + case GDB_BP_TYPE_R: + return bp_x; + case GDB_BP_TYPE_W: + return bp_x; + case GDB_BP_TYPE_A: + return bp_x; + default: + return nullptr; + } } -static gdb_bp_t *gdb_bp_empty_slot(u32 type) +static gdb_bp_t* gdb_bp_empty_slot(u32 type) { - gdb_bp_t *p; - u32 i; + gdb_bp_t* p; + u32 i; - p = gdb_bp_ptr(type); - if (p == nullptr) - return nullptr; + p = gdb_bp_ptr(type); + if (p == nullptr) + return nullptr; - for (i = 0; i < GDB_MAX_BP; i++) - { - if (p[i].active == 0) - return &p[i]; - } + for (i = 0; i < GDB_MAX_BP; i++) + { + if (p[i].active == 0) + return &p[i]; + } - return nullptr; + return nullptr; } -static gdb_bp_t *gdb_bp_find(u32 type, u32 addr, u32 len) +static gdb_bp_t* gdb_bp_find(u32 type, u32 addr, u32 len) { - gdb_bp_t *p; - u32 i; + gdb_bp_t* p; + u32 i; - p = gdb_bp_ptr(type); - if (p == nullptr) - return nullptr; + p = gdb_bp_ptr(type); + if (p == nullptr) + return nullptr; - for (i = 0; i < GDB_MAX_BP; i++) - { - if (p[i].active == 1 && - p[i].addr == addr && - p[i].len == len) - return &p[i]; - } + for (i = 0; i < GDB_MAX_BP; i++) + { + if (p[i].active == 1 && p[i].addr == addr && p[i].len == len) + return &p[i]; + } - return nullptr; + return nullptr; } static void gdb_bp_remove(u32 type, u32 addr, u32 len) { - gdb_bp_t *p; + gdb_bp_t* p; - do - { - p = gdb_bp_find(type, addr, len); - if (p != nullptr) - { - DEBUG_LOG(GDB_STUB, "gdb: removed a breakpoint: %08x bytes at %08x\n", len, addr); - p->active = 0; - memset(p, 0, sizeof(gdb_bp_t)); - } - } while (p != nullptr); + do + { + p = gdb_bp_find(type, addr, len); + if (p != nullptr) + { + DEBUG_LOG(GDB_STUB, "gdb: removed a breakpoint: %08x bytes at %08x\n", len, addr); + p->active = 0; + memset(p, 0, sizeof(gdb_bp_t)); + } + } while (p != nullptr); } static int gdb_bp_check(u32 addr, u32 type) { - gdb_bp_t *p; - u32 i; + gdb_bp_t* p; + u32 i; - p = gdb_bp_ptr(type); - if (p == nullptr) - return 0; + p = gdb_bp_ptr(type); + if (p == nullptr) + return 0; - for (i = 0; i < GDB_MAX_BP; i++) - { - if (p[i].active == 1 && - (addr >= p[i].addr && addr < p[i].addr + p[i].len)) - return 1; - } + for (i = 0; i < GDB_MAX_BP; i++) + { + if (p[i].active == 1 && (addr >= p[i].addr && addr < p[i].addr + p[i].len)) + return 1; + } - return 0; + return 0; } static void gdb_nak() { - const char nak = GDB_STUB_NAK; - ssize_t res; + const char nak = GDB_STUB_NAK; + ssize_t res; - res = send(sock, &nak, 1, 0); - if (res != 1) - ERROR_LOG(GDB_STUB, "send failed"); + res = send(sock, &nak, 1, 0); + if (res != 1) + ERROR_LOG(GDB_STUB, "send failed"); } static void gdb_ack() { - const char ack = GDB_STUB_ACK; - ssize_t res; + const char ack = GDB_STUB_ACK; + ssize_t res; - res = send(sock, &ack, 1, 0); - if (res != 1) - ERROR_LOG(GDB_STUB, "send failed"); + res = send(sock, &ack, 1, 0); + if (res != 1) + ERROR_LOG(GDB_STUB, "send failed"); } static void gdb_read_command() { - u8 c; - u8 chk_read, chk_calc; + u8 c; + u8 chk_read, chk_calc; - cmd_len = 0; - memset(cmd_bfr, 0, sizeof cmd_bfr); + cmd_len = 0; + memset(cmd_bfr, 0, sizeof cmd_bfr); - c = gdb_read_byte(); - if (c == '+') - { - //ignore ack - return; - } - else if (c == 0x03) - { - CPU::Break(); - gdb_signal(SIGTRAP); - return; - } - else if (c != GDB_STUB_START) - { - DEBUG_LOG(GDB_STUB, "gdb: read invalid byte %02x\n", c); - return; - } + c = gdb_read_byte(); + if (c == '+') + { + // ignore ack + return; + } + else if (c == 0x03) + { + CPU::Break(); + gdb_signal(SIGTRAP); + return; + } + else if (c != GDB_STUB_START) + { + DEBUG_LOG(GDB_STUB, "gdb: read invalid byte %02x\n", c); + return; + } - while ((c = gdb_read_byte()) != GDB_STUB_END) - { - cmd_bfr[cmd_len++] = c; - if (cmd_len == sizeof cmd_bfr) - { - ERROR_LOG(GDB_STUB, "gdb: cmd_bfr overflow\n"); - gdb_nak(); - return; - } - } + while ((c = gdb_read_byte()) != GDB_STUB_END) + { + cmd_bfr[cmd_len++] = c; + if (cmd_len == sizeof cmd_bfr) + { + ERROR_LOG(GDB_STUB, "gdb: cmd_bfr overflow\n"); + gdb_nak(); + return; + } + } - chk_read = hex2char(gdb_read_byte()) << 4; - chk_read |= hex2char(gdb_read_byte()); + chk_read = hex2char(gdb_read_byte()) << 4; + chk_read |= hex2char(gdb_read_byte()); - chk_calc = gdb_calc_chksum(); + chk_calc = gdb_calc_chksum(); - if (chk_calc != chk_read) - { - ERROR_LOG(GDB_STUB, "gdb: invalid checksum: calculated %02x and read %02x for $%s# (length: %d)\n", chk_calc, chk_read, cmd_bfr, cmd_len); - cmd_len = 0; + if (chk_calc != chk_read) + { + ERROR_LOG(GDB_STUB, + "gdb: invalid checksum: calculated %02x and read %02x for $%s# (length: %d)\n", + chk_calc, chk_read, cmd_bfr, cmd_len); + cmd_len = 0; - gdb_nak(); - return; - } + gdb_nak(); + return; + } - DEBUG_LOG(GDB_STUB, "gdb: read command %c with a length of %d: %s\n", cmd_bfr[0], cmd_len, cmd_bfr); - gdb_ack(); + DEBUG_LOG(GDB_STUB, "gdb: read command %c with a length of %d: %s\n", cmd_bfr[0], cmd_len, + cmd_bfr); + gdb_ack(); } -static int gdb_data_available() { - struct timeval t; - fd_set _fds, *fds = &_fds; - - FD_ZERO(fds); - FD_SET(sock, fds); - - t.tv_sec = 0; - t.tv_usec = 20; - - if (select(sock + 1, fds, nullptr, nullptr, &t) < 0) - { - ERROR_LOG(GDB_STUB, "select failed"); - return 0; - } - - if (FD_ISSET(sock, fds)) - return 1; - return 0; -} - -static void gdb_reply(const char *reply) +static int gdb_data_available() { - u8 chk; - u32 left; - u8 *ptr; - int n; + struct timeval t; + fd_set _fds, *fds = &_fds; - if (!gdb_active()) - return; + FD_ZERO(fds); + FD_SET(sock, fds); - memset(cmd_bfr, 0, sizeof cmd_bfr); + t.tv_sec = 0; + t.tv_usec = 20; - cmd_len = strlen(reply); - if (cmd_len + 4 > sizeof cmd_bfr) - ERROR_LOG(GDB_STUB, "cmd_bfr overflow in gdb_reply"); + if (select(sock + 1, fds, nullptr, nullptr, &t) < 0) + { + ERROR_LOG(GDB_STUB, "select failed"); + return 0; + } - memcpy(cmd_bfr + 1, reply, cmd_len); + if (FD_ISSET(sock, fds)) + return 1; + return 0; +} - cmd_len++; - chk = gdb_calc_chksum(); - cmd_len--; - cmd_bfr[0] = GDB_STUB_START; - cmd_bfr[cmd_len + 1] = GDB_STUB_END; - cmd_bfr[cmd_len + 2] = nibble2hex(chk >> 4); - cmd_bfr[cmd_len + 3] = nibble2hex(chk); +static void gdb_reply(const char* reply) +{ + u8 chk; + u32 left; + u8* ptr; + int n; - DEBUG_LOG(GDB_STUB, "gdb: reply (len: %d): %s\n", cmd_len, cmd_bfr); + if (!gdb_active()) + return; - ptr = cmd_bfr; - left = cmd_len + 4; - while (left > 0) - { - n = send(sock, ptr, left, 0); - if (n < 0) - { - ERROR_LOG(GDB_STUB, "gdb: send failed"); - return gdb_deinit(); - } - left -= n; - ptr += n; - } + memset(cmd_bfr, 0, sizeof cmd_bfr); + + cmd_len = strlen(reply); + if (cmd_len + 4 > sizeof cmd_bfr) + ERROR_LOG(GDB_STUB, "cmd_bfr overflow in gdb_reply"); + + memcpy(cmd_bfr + 1, reply, cmd_len); + + cmd_len++; + chk = gdb_calc_chksum(); + cmd_len--; + cmd_bfr[0] = GDB_STUB_START; + cmd_bfr[cmd_len + 1] = GDB_STUB_END; + cmd_bfr[cmd_len + 2] = nibble2hex(chk >> 4); + cmd_bfr[cmd_len + 3] = nibble2hex(chk); + + DEBUG_LOG(GDB_STUB, "gdb: reply (len: %d): %s\n", cmd_len, cmd_bfr); + + ptr = cmd_bfr; + left = cmd_len + 4; + while (left > 0) + { + n = send(sock, ptr, left, 0); + if (n < 0) + { + ERROR_LOG(GDB_STUB, "gdb: send failed"); + return gdb_deinit(); + } + left -= n; + ptr += n; + } } static void gdb_handle_query() { - DEBUG_LOG(GDB_STUB, "gdb: query '%s'\n", cmd_bfr+1); + DEBUG_LOG(GDB_STUB, "gdb: query '%s'\n", cmd_bfr + 1); - if (!strcmp((const char *)(cmd_bfr+1), "TStatus")) - { - return gdb_reply("T0"); - } + if (!strcmp((const char*)(cmd_bfr + 1), "TStatus")) + { + return gdb_reply("T0"); + } - gdb_reply(""); + gdb_reply(""); } static void gdb_handle_set_thread() { - if (memcmp(cmd_bfr, "Hg0", 3) == 0 || - memcmp(cmd_bfr, "Hc-1", 4) == 0 || - memcmp(cmd_bfr, "Hc0", 4) == 0 || - memcmp(cmd_bfr, "Hc1", 4) == 0) - return gdb_reply("OK"); - gdb_reply("E01"); + if (memcmp(cmd_bfr, "Hg0", 3) == 0 || memcmp(cmd_bfr, "Hc-1", 4) == 0 || + memcmp(cmd_bfr, "Hc0", 4) == 0 || memcmp(cmd_bfr, "Hc1", 4) == 0) + return gdb_reply("OK"); + gdb_reply("E01"); } static void gdb_handle_signal() { - char bfr[128]; - memset(bfr, 0, sizeof bfr); - sprintf(bfr, "T%02x%02x:%08x;%02x:%08x;", sig, 64, PC, 1, GPR(1)); - gdb_reply(bfr); + char bfr[128]; + memset(bfr, 0, sizeof bfr); + sprintf(bfr, "T%02x%02x:%08x;%02x:%08x;", sig, 64, PC, 1, GPR(1)); + gdb_reply(bfr); } -static void wbe32hex(u8 *p, u32 v) +static void wbe32hex(u8* p, u32 v) { - u32 i; - for (i = 0; i < 8; i++) - p[i] = nibble2hex(v >> (28 - 4*i)); + u32 i; + for (i = 0; i < 8; i++) + p[i] = nibble2hex(v >> (28 - 4 * i)); } -static void wbe64hex(u8 *p, u64 v) +static void wbe64hex(u8* p, u64 v) { - u32 i; - for (i = 0; i < 16; i++) - p[i] = nibble2hex(v >> (60 - 4*i)); + u32 i; + for (i = 0; i < 16; i++) + p[i] = nibble2hex(v >> (60 - 4 * i)); } -static u32 re32hex(u8 *p) +static u32 re32hex(u8* p) { - u32 i; - u32 res = 0; + u32 i; + u32 res = 0; - for (i = 0; i < 8; i++) - res = (res << 4) | hex2char(p[i]); + for (i = 0; i < 8; i++) + res = (res << 4) | hex2char(p[i]); - return res; + return res; } -static u64 re64hex(u8 *p) +static u64 re64hex(u8* p) { - u32 i; - u64 res = 0; + u32 i; + u64 res = 0; - for (i = 0; i < 16; i++) - res = (res << 4) | hex2char(p[i]); + for (i = 0; i < 16; i++) + res = (res << 4) | hex2char(p[i]); - return res; + return res; } static void gdb_read_register() { - static u8 reply[64]; - u32 id; + static u8 reply[64]; + u32 id; - memset(reply, 0, sizeof reply); - id = hex2char(cmd_bfr[1]); - if (cmd_bfr[2] != '\0') - { - id <<= 4; - id |= hex2char(cmd_bfr[2]); - } + memset(reply, 0, sizeof reply); + id = hex2char(cmd_bfr[1]); + if (cmd_bfr[2] != '\0') + { + id <<= 4; + id |= hex2char(cmd_bfr[2]); + } + switch (id) + { + case 0 ... 31: + wbe32hex(reply, GPR(id)); + break; + case 32 ... 63: + wbe64hex(reply, riPS0(id - 32)); + break; + case 64: + wbe32hex(reply, PC); + break; + case 65: + wbe32hex(reply, MSR); + break; + case 66: + wbe32hex(reply, GetCR()); + break; + case 67: + wbe32hex(reply, LR); + break; + case 68: + wbe32hex(reply, CTR); + break; + case 69: + wbe32hex(reply, PowerPC::ppcState.spr[SPR_XER]); + break; + case 70: + wbe32hex(reply, 0x0BADC0DE); + break; + case 71: + wbe32hex(reply, FPSCR.Hex); + break; + default: + return gdb_reply("E01"); + break; + } - switch (id) { - case 0 ... 31: - wbe32hex(reply, GPR(id)); - break; - case 32 ... 63: - wbe64hex(reply, riPS0(id-32)); - break; - case 64: - wbe32hex(reply, PC); - break; - case 65: - wbe32hex(reply, MSR); - break; - case 66: - wbe32hex(reply, GetCR()); - break; - case 67: - wbe32hex(reply, LR); - break; - case 68: - wbe32hex(reply, CTR); - break; - case 69: - wbe32hex(reply, PowerPC::ppcState.spr[SPR_XER]); - break; - case 70: - wbe32hex(reply, 0x0BADC0DE); - break; - case 71: - wbe32hex(reply, FPSCR.Hex); - break; - default: - return gdb_reply("E01"); - break; - } - - gdb_reply((char *)reply); + gdb_reply((char*)reply); } static void gdb_read_registers() { - static u8 bfr[GDB_BFR_MAX - 4]; - u8 * bufptr = bfr; - u32 i; + static u8 bfr[GDB_BFR_MAX - 4]; + u8* bufptr = bfr; + u32 i; - memset(bfr, 0, sizeof bfr); + memset(bfr, 0, sizeof bfr); - for (i = 0; i < 32; i++) - { - wbe32hex(bufptr + i*8, GPR(i)); - } - bufptr += 32 * 8; + for (i = 0; i < 32; i++) + { + wbe32hex(bufptr + i * 8, GPR(i)); + } + bufptr += 32 * 8; - /* - for (i = 0; i < 32; i++) - { - wbe32hex(bufptr + i*8, riPS0(i)); - } - bufptr += 32 * 8; - wbe32hex(bufptr, PC); bufptr += 4; - wbe32hex(bufptr, MSR); bufptr += 4; - wbe32hex(bufptr, GetCR()); bufptr += 4; - wbe32hex(bufptr, LR); bufptr += 4; + /* + for (i = 0; i < 32; i++) + { + wbe32hex(bufptr + i*8, riPS0(i)); + } + bufptr += 32 * 8; + wbe32hex(bufptr, PC); bufptr += 4; + wbe32hex(bufptr, MSR); bufptr += 4; + wbe32hex(bufptr, GetCR()); bufptr += 4; + wbe32hex(bufptr, LR); bufptr += 4; - wbe32hex(bufptr, CTR); bufptr += 4; - wbe32hex(bufptr, PowerPC::ppcState.spr[SPR_XER]); bufptr += 4; - // MQ register not used. - wbe32hex(bufptr, 0x0BADC0DE); bufptr += 4; - */ + wbe32hex(bufptr, CTR); bufptr += 4; + wbe32hex(bufptr, PowerPC::ppcState.spr[SPR_XER]); bufptr += 4; + // MQ register not used. + wbe32hex(bufptr, 0x0BADC0DE); bufptr += 4; + */ - - gdb_reply((char *)bfr); + gdb_reply((char*)bfr); } static void gdb_write_registers() { - u32 i; - u8 * bufptr = cmd_bfr; + u32 i; + u8* bufptr = cmd_bfr; - for (i = 0; i < 32; i++) - { - GPR(i) = re32hex(bufptr + i*8); - } - bufptr += 32 * 8; + for (i = 0; i < 32; i++) + { + GPR(i) = re32hex(bufptr + i * 8); + } + bufptr += 32 * 8; - gdb_reply("OK"); + gdb_reply("OK"); } static void gdb_write_register() { - u32 id; + u32 id; - u8 * bufptr = cmd_bfr + 3; + u8* bufptr = cmd_bfr + 3; - id = hex2char(cmd_bfr[1]); - if (cmd_bfr[2] != '=') - { - ++bufptr; - id <<= 4; - id |= hex2char(cmd_bfr[2]); - } + id = hex2char(cmd_bfr[1]); + if (cmd_bfr[2] != '=') + { + ++bufptr; + id <<= 4; + id |= hex2char(cmd_bfr[2]); + } - switch (id) { - case 0 ... 31: - GPR(id) = re32hex(bufptr); - break; - case 32 ... 63: - riPS0(id-32) = re64hex(bufptr); - break; - case 64: - PC = re32hex(bufptr); - break; - case 65: - MSR = re32hex(bufptr); - break; - case 66: - SetCR(re32hex(bufptr)); - break; - case 67: - LR = re32hex(bufptr); - break; - case 68: - CTR = re32hex(bufptr); - break; - case 69: - PowerPC::ppcState.spr[SPR_XER] = re32hex(bufptr); - break; - case 70: - // do nothing, we dont have MQ - break; - case 71: - FPSCR.Hex = re32hex(bufptr); - break; - default: - return gdb_reply("E01"); - break; - } + switch (id) + { + case 0 ... 31: + GPR(id) = re32hex(bufptr); + break; + case 32 ... 63: + riPS0(id - 32) = re64hex(bufptr); + break; + case 64: + PC = re32hex(bufptr); + break; + case 65: + MSR = re32hex(bufptr); + break; + case 66: + SetCR(re32hex(bufptr)); + break; + case 67: + LR = re32hex(bufptr); + break; + case 68: + CTR = re32hex(bufptr); + break; + case 69: + PowerPC::ppcState.spr[SPR_XER] = re32hex(bufptr); + break; + case 70: + // do nothing, we dont have MQ + break; + case 71: + FPSCR.Hex = re32hex(bufptr); + break; + default: + return gdb_reply("E01"); + break; + } - gdb_reply("OK"); + gdb_reply("OK"); } static void gdb_read_mem() { - static u8 reply[GDB_BFR_MAX - 4]; - u32 addr, len; - u32 i; + static u8 reply[GDB_BFR_MAX - 4]; + u32 addr, len; + u32 i; - i = 1; - addr = 0; - while (cmd_bfr[i] != ',') - addr = (addr << 4) | hex2char(cmd_bfr[i++]); - i++; + i = 1; + addr = 0; + while (cmd_bfr[i] != ',') + addr = (addr << 4) | hex2char(cmd_bfr[i++]); + i++; - len = 0; - while (i < cmd_len) - len = (len << 4) | hex2char(cmd_bfr[i++]); - DEBUG_LOG(GDB_STUB, "gdb: read memory: %08x bytes from %08x\n", len, addr); + len = 0; + while (i < cmd_len) + len = (len << 4) | hex2char(cmd_bfr[i++]); + DEBUG_LOG(GDB_STUB, "gdb: read memory: %08x bytes from %08x\n", len, addr); - if (len*2 > sizeof reply) - gdb_reply("E01"); - u8 * data = Memory::GetPointer(addr); - if (!data) - return gdb_reply("E0"); - mem2hex(reply, data, len); - reply[len*2] = '\0'; - gdb_reply((char *)reply); + if (len * 2 > sizeof reply) + gdb_reply("E01"); + u8* data = Memory::GetPointer(addr); + if (!data) + return gdb_reply("E0"); + mem2hex(reply, data, len); + reply[len * 2] = '\0'; + gdb_reply((char*)reply); } static void gdb_write_mem() { - u32 addr, len; - u32 i; + u32 addr, len; + u32 i; - i = 1; - addr = 0; - while (cmd_bfr[i] != ',') - addr = (addr << 4) | hex2char(cmd_bfr[i++]); - i++; + i = 1; + addr = 0; + while (cmd_bfr[i] != ',') + addr = (addr << 4) | hex2char(cmd_bfr[i++]); + i++; - len = 0; - while (cmd_bfr[i] != ':') - len = (len << 4) | hex2char(cmd_bfr[i++]); - DEBUG_LOG(GDB_STUB, "gdb: write memory: %08x bytes to %08x\n", len, addr); + len = 0; + while (cmd_bfr[i] != ':') + len = (len << 4) | hex2char(cmd_bfr[i++]); + DEBUG_LOG(GDB_STUB, "gdb: write memory: %08x bytes to %08x\n", len, addr); - u8 * dst = Memory::GetPointer(addr); - if (!dst) - return gdb_reply("E00"); - hex2mem(dst, cmd_bfr + i + 1, len); - gdb_reply("OK"); + u8* dst = Memory::GetPointer(addr); + if (!dst) + return gdb_reply("E00"); + hex2mem(dst, cmd_bfr + i + 1, len); + gdb_reply("OK"); } // forces a break on next instruction check void gdb_break() { - step_break = 1; - send_signal = 1; + step_break = 1; + send_signal = 1; } static void gdb_step() { - gdb_break(); + gdb_break(); } static void gdb_continue() { - send_signal = 1; + send_signal = 1; } bool gdb_add_bp(u32 type, u32 addr, u32 len) { - gdb_bp_t *bp; - bp = gdb_bp_empty_slot(type); - if (bp == nullptr) - return false; + gdb_bp_t* bp; + bp = gdb_bp_empty_slot(type); + if (bp == nullptr) + return false; - bp->active = 1; - bp->addr = addr; - bp->len = len; + bp->active = 1; + bp->addr = addr; + bp->len = len; - DEBUG_LOG(GDB_STUB, "gdb: added %d breakpoint: %08x bytes at %08x\n", type, bp->len, bp->addr); - return true; + DEBUG_LOG(GDB_STUB, "gdb: added %d breakpoint: %08x bytes at %08x\n", type, bp->len, bp->addr); + return true; } static void _gdb_add_bp() { - u32 type; - u32 i, addr = 0, len = 0; + u32 type; + u32 i, addr = 0, len = 0; - type = hex2char(cmd_bfr[1]); - switch (type) - { - case 0: - case 1: - type = GDB_BP_TYPE_X; - break; - case 2: - type = GDB_BP_TYPE_W; - break; - case 3: - type = GDB_BP_TYPE_R; - break; - case 4: - type = GDB_BP_TYPE_A; - break; - default: - return gdb_reply("E01"); - } + type = hex2char(cmd_bfr[1]); + switch (type) + { + case 0: + case 1: + type = GDB_BP_TYPE_X; + break; + case 2: + type = GDB_BP_TYPE_W; + break; + case 3: + type = GDB_BP_TYPE_R; + break; + case 4: + type = GDB_BP_TYPE_A; + break; + default: + return gdb_reply("E01"); + } - i = 3; - while (cmd_bfr[i] != ',') - addr = addr << 4 | hex2char(cmd_bfr[i++]); - i++; + i = 3; + while (cmd_bfr[i] != ',') + addr = addr << 4 | hex2char(cmd_bfr[i++]); + i++; - while (i < cmd_len) - len = len << 4 | hex2char(cmd_bfr[i++]); + while (i < cmd_len) + len = len << 4 | hex2char(cmd_bfr[i++]); - if (!gdb_add_bp(type, addr, len)) - return gdb_reply("E02"); - gdb_reply("OK"); + if (!gdb_add_bp(type, addr, len)) + return gdb_reply("E02"); + gdb_reply("OK"); } static void gdb_remove_bp() { - u32 type, addr, len, i; + u32 type, addr, len, i; - type = hex2char(cmd_bfr[1]); - switch (type) { - case 0: - case 1: - type = GDB_BP_TYPE_X; - break; - case 2: - type = GDB_BP_TYPE_W; - break; - case 3: - type = GDB_BP_TYPE_R; - break; - case 4: - type = GDB_BP_TYPE_A; - break; - default: - return gdb_reply("E01"); - } + type = hex2char(cmd_bfr[1]); + switch (type) + { + case 0: + case 1: + type = GDB_BP_TYPE_X; + break; + case 2: + type = GDB_BP_TYPE_W; + break; + case 3: + type = GDB_BP_TYPE_R; + break; + case 4: + type = GDB_BP_TYPE_A; + break; + default: + return gdb_reply("E01"); + } - addr = 0; - len = 0; + addr = 0; + len = 0; - i = 3; - while (cmd_bfr[i] != ',') - addr = (addr << 4) | hex2char(cmd_bfr[i++]); - i++; + i = 3; + while (cmd_bfr[i] != ',') + addr = (addr << 4) | hex2char(cmd_bfr[i++]); + i++; - while (i < cmd_len) - len = (len << 4) | hex2char(cmd_bfr[i++]); + while (i < cmd_len) + len = (len << 4) | hex2char(cmd_bfr[i++]); - gdb_bp_remove(type, addr, len); - gdb_reply("OK"); + gdb_bp_remove(type, addr, len); + gdb_reply("OK"); } void gdb_handle_exception() { - while (gdb_active()) - { - if (!gdb_data_available()) - continue; - gdb_read_command(); - if (cmd_len == 0) - continue; + while (gdb_active()) + { + if (!gdb_data_available()) + continue; + gdb_read_command(); + if (cmd_len == 0) + continue; - switch (cmd_bfr[0]) { - case 'q': - gdb_handle_query(); - break; - case 'H': - gdb_handle_set_thread(); - break; - case '?': - gdb_handle_signal(); - break; - case 'k': - gdb_deinit(); - INFO_LOG(GDB_STUB, "killed by gdb"); - return; - case 'g': - gdb_read_registers(); - break; - case 'G': - gdb_write_registers(); - break; - case 'p': - gdb_read_register(); - break; - case 'P': - gdb_write_register(); - break; - case 'm': - gdb_read_mem(); - break; - case 'M': - gdb_write_mem(); - PowerPC::ppcState.iCache.Reset(); - Host_UpdateDisasmDialog(); - break; - case 's': - gdb_step(); - return; - case 'C': - case 'c': - gdb_continue(); - return; - case 'z': - gdb_remove_bp(); - break; - case 'Z': - _gdb_add_bp(); - break; - default: - gdb_reply(""); - break; - } - } + switch (cmd_bfr[0]) + { + case 'q': + gdb_handle_query(); + break; + case 'H': + gdb_handle_set_thread(); + break; + case '?': + gdb_handle_signal(); + break; + case 'k': + gdb_deinit(); + INFO_LOG(GDB_STUB, "killed by gdb"); + return; + case 'g': + gdb_read_registers(); + break; + case 'G': + gdb_write_registers(); + break; + case 'p': + gdb_read_register(); + break; + case 'P': + gdb_write_register(); + break; + case 'm': + gdb_read_mem(); + break; + case 'M': + gdb_write_mem(); + PowerPC::ppcState.iCache.Reset(); + Host_UpdateDisasmDialog(); + break; + case 's': + gdb_step(); + return; + case 'C': + case 'c': + gdb_continue(); + return; + case 'z': + gdb_remove_bp(); + break; + case 'Z': + _gdb_add_bp(); + break; + default: + gdb_reply(""); + break; + } + } } #ifdef _WIN32 @@ -800,163 +804,158 @@ WSADATA InitData; // exported functions -static void gdb_init_generic(int domain, - const sockaddr *server_addr, socklen_t server_addrlen, - sockaddr *client_addr, socklen_t *client_addrlen); +static void gdb_init_generic(int domain, const sockaddr* server_addr, socklen_t server_addrlen, + sockaddr* client_addr, socklen_t* client_addrlen); #ifndef _WIN32 -void gdb_init_local(const char *socket) +void gdb_init_local(const char* socket) { - unlink(socket); + unlink(socket); - sockaddr_un addr = {}; - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, socket); + sockaddr_un addr = {}; + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, socket); - gdb_init_generic(PF_LOCAL, (const sockaddr *)&addr, sizeof(addr), - NULL, NULL); + gdb_init_generic(PF_LOCAL, (const sockaddr*)&addr, sizeof(addr), NULL, NULL); } #endif void gdb_init(u32 port) { - sockaddr_in saddr_server = {}; - sockaddr_in saddr_client; + sockaddr_in saddr_server = {}; + sockaddr_in saddr_client; - saddr_server.sin_family = AF_INET; - saddr_server.sin_port = htons(port); - saddr_server.sin_addr.s_addr = INADDR_ANY; + saddr_server.sin_family = AF_INET; + saddr_server.sin_port = htons(port); + saddr_server.sin_addr.s_addr = INADDR_ANY; - socklen_t client_addrlen = sizeof(saddr_client); + socklen_t client_addrlen = sizeof(saddr_client); - gdb_init_generic(PF_INET, - (const sockaddr *)&saddr_server, sizeof(saddr_server), - (sockaddr *)&saddr_client, &client_addrlen); + gdb_init_generic(PF_INET, (const sockaddr*)&saddr_server, sizeof(saddr_server), + (sockaddr*)&saddr_client, &client_addrlen); - saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr); - /*if (((saddr_client.sin_addr.s_addr >> 24) & 0xff) != 127 || - * ((saddr_client.sin_addr.s_addr >> 16) & 0xff) != 0 || - * ((saddr_client.sin_addr.s_addr >> 8) & 0xff) != 0 || - * ((saddr_client.sin_addr.s_addr >> 0) & 0xff) != 1) - * ERROR_LOG(GDB_STUB, "gdb: incoming connection not from localhost"); - */ + saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr); + /*if (((saddr_client.sin_addr.s_addr >> 24) & 0xff) != 127 || + * ((saddr_client.sin_addr.s_addr >> 16) & 0xff) != 0 || + * ((saddr_client.sin_addr.s_addr >> 8) & 0xff) != 0 || + * ((saddr_client.sin_addr.s_addr >> 0) & 0xff) != 1) + * ERROR_LOG(GDB_STUB, "gdb: incoming connection not from localhost"); + */ } -static void gdb_init_generic(int domain, - const sockaddr *server_addr, socklen_t server_addrlen, - sockaddr *client_addr, socklen_t *client_addrlen) +static void gdb_init_generic(int domain, const sockaddr* server_addr, socklen_t server_addrlen, + sockaddr* client_addr, socklen_t* client_addrlen) { - int on; - #ifdef _WIN32 - WSAStartup(MAKEWORD(2,2), &InitData); - #endif + int on; +#ifdef _WIN32 + WSAStartup(MAKEWORD(2, 2), &InitData); +#endif - memset(bp_x, 0, sizeof bp_x); - memset(bp_r, 0, sizeof bp_r); - memset(bp_w, 0, sizeof bp_w); - memset(bp_a, 0, sizeof bp_a); + memset(bp_x, 0, sizeof bp_x); + memset(bp_r, 0, sizeof bp_r); + memset(bp_w, 0, sizeof bp_w); + memset(bp_a, 0, sizeof bp_a); - tmpsock = socket(domain, SOCK_STREAM, 0); - if (tmpsock == -1) - ERROR_LOG(GDB_STUB, "Failed to create gdb socket"); + tmpsock = socket(domain, SOCK_STREAM, 0); + if (tmpsock == -1) + ERROR_LOG(GDB_STUB, "Failed to create gdb socket"); - on = 1; - if (setsockopt(tmpsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on) < 0) - ERROR_LOG(GDB_STUB, "Failed to setsockopt"); + on = 1; + if (setsockopt(tmpsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on) < 0) + ERROR_LOG(GDB_STUB, "Failed to setsockopt"); - if (bind(tmpsock, server_addr, server_addrlen) < 0) - ERROR_LOG(GDB_STUB, "Failed to bind gdb socket"); + if (bind(tmpsock, server_addr, server_addrlen) < 0) + ERROR_LOG(GDB_STUB, "Failed to bind gdb socket"); - if (listen(tmpsock, 1) < 0) - ERROR_LOG(GDB_STUB, "Failed to listen to gdb socket"); + if (listen(tmpsock, 1) < 0) + ERROR_LOG(GDB_STUB, "Failed to listen to gdb socket"); - INFO_LOG(GDB_STUB, "Waiting for gdb to connect...\n"); + INFO_LOG(GDB_STUB, "Waiting for gdb to connect...\n"); - sock = accept(tmpsock, client_addr, client_addrlen); - if (sock < 0) - ERROR_LOG(GDB_STUB, "Failed to accept gdb client"); - INFO_LOG(GDB_STUB, "Client connected.\n"); + sock = accept(tmpsock, client_addr, client_addrlen); + if (sock < 0) + ERROR_LOG(GDB_STUB, "Failed to accept gdb client"); + INFO_LOG(GDB_STUB, "Client connected.\n"); - close(tmpsock); - tmpsock = -1; + close(tmpsock); + tmpsock = -1; } - void gdb_deinit() { - if (tmpsock != -1) - { - shutdown(tmpsock, SHUT_RDWR); - tmpsock = -1; - } - if (sock != -1) - { - shutdown(sock, SHUT_RDWR); - sock = -1; - } + if (tmpsock != -1) + { + shutdown(tmpsock, SHUT_RDWR); + tmpsock = -1; + } + if (sock != -1) + { + shutdown(sock, SHUT_RDWR); + sock = -1; + } - #ifdef _WIN32 - WSACleanup(); - #endif +#ifdef _WIN32 + WSACleanup(); +#endif } bool gdb_active() { - return tmpsock != -1 || sock != -1; + return tmpsock != -1 || sock != -1; } int gdb_signal(u32 s) { - if (sock == -1) - return 1; + if (sock == -1) + return 1; - sig = s; + sig = s; - if (send_signal) - { - gdb_handle_signal(); - send_signal = 0; - } + if (send_signal) + { + gdb_handle_signal(); + send_signal = 0; + } - return 0; + return 0; } int gdb_bp_x(u32 addr) { - if (sock == -1) - return 0; + if (sock == -1) + return 0; - if (step_break) - { - step_break = 0; + if (step_break) + { + step_break = 0; - DEBUG_LOG(GDB_STUB, "Step was successful."); - return 1; - } + DEBUG_LOG(GDB_STUB, "Step was successful."); + return 1; + } - return gdb_bp_check(addr, GDB_BP_TYPE_X); + return gdb_bp_check(addr, GDB_BP_TYPE_X); } int gdb_bp_r(u32 addr) { - if (sock == -1) - return 0; + if (sock == -1) + return 0; - return gdb_bp_check(addr, GDB_BP_TYPE_R); + return gdb_bp_check(addr, GDB_BP_TYPE_R); } int gdb_bp_w(u32 addr) { - if (sock == -1) - return 0; + if (sock == -1) + return 0; - return gdb_bp_check(addr, GDB_BP_TYPE_W); + return gdb_bp_check(addr, GDB_BP_TYPE_W); } int gdb_bp_a(u32 addr) { - if (sock == -1) - return 0; + if (sock == -1) + return 0; - return gdb_bp_check(addr, GDB_BP_TYPE_A); + return gdb_bp_check(addr, GDB_BP_TYPE_A); } diff --git a/Source/Core/Core/PowerPC/GDBStub.h b/Source/Core/Core/PowerPC/GDBStub.h index b064e3f85f..f9abc54043 100644 --- a/Source/Core/Core/PowerPC/GDBStub.h +++ b/Source/Core/Core/PowerPC/GDBStub.h @@ -16,31 +16,31 @@ #include "Core/PowerPC/PowerPC.h" #ifdef _WIN32 -#define SIGTRAP 5 -#define SIGTERM 15 -#define MSG_WAITALL 8 +#define SIGTRAP 5 +#define SIGTERM 15 +#define MSG_WAITALL 8 #endif typedef enum { - GDB_BP_TYPE_NONE = 0, - GDB_BP_TYPE_X, - GDB_BP_TYPE_R, - GDB_BP_TYPE_W, - GDB_BP_TYPE_A + GDB_BP_TYPE_NONE = 0, + GDB_BP_TYPE_X, + GDB_BP_TYPE_R, + GDB_BP_TYPE_W, + GDB_BP_TYPE_A } gdb_bp_type; void gdb_init(u32 port); -void gdb_init_local(const char *socket); +void gdb_init_local(const char* socket); void gdb_deinit(); bool gdb_active(); void gdb_break(); void gdb_handle_exception(); -int gdb_signal(u32 signal); +int gdb_signal(u32 signal); -int gdb_bp_x(u32 addr); -int gdb_bp_r(u32 addr); -int gdb_bp_w(u32 addr); -int gdb_bp_a(u32 addr); +int gdb_bp_x(u32 addr); +int gdb_bp_r(u32 addr); +int gdb_bp_w(u32 addr); +int gdb_bp_a(u32 addr); bool gdb_add_bp(u32 type, u32 addr, u32 len); diff --git a/Source/Core/Core/PowerPC/Gekko.h b/Source/Core/Core/PowerPC/Gekko.h index 52910f8780..d4f25c7dff 100644 --- a/Source/Core/Core/PowerPC/Gekko.h +++ b/Source/Core/Core/PowerPC/Gekko.h @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // Gekko related unions, structs, ... #pragma once @@ -12,291 +11,288 @@ // --- Gekko Instruction --- +union UGeckoInstruction { + u32 hex; -union UGeckoInstruction -{ - u32 hex; + UGeckoInstruction(u32 _hex) : hex(_hex) {} + UGeckoInstruction() : hex(0) {} + struct + { + // Record bit + // 1, if the condition register should be updated by this instruction + u32 Rc : 1; + u32 SUBOP10 : 10; + // Source GPR + u32 RB : 5; + // Source or destination GPR + u32 RA : 5; + // Destination GPR + u32 RD : 5; + // Primary opcode + u32 OPCD : 6; + }; + struct + { + // Immediate, signed 16-bit + signed SIMM_16 : 16; + u32 : 5; + // Conditions on which to trap + u32 TO : 5; + u32 OPCD_2 : 6; + }; + struct + { + u32 Rc_2 : 1; + u32 : 10; + u32 : 5; + u32 : 5; + // Source GPR + u32 RS : 5; + u32 OPCD_3 : 6; + }; + struct + { + // Immediate, unsigned 16-bit + u32 UIMM : 16; + u32 : 5; + u32 : 5; + u32 OPCD_4 : 6; + }; + struct + { + // Link bit + // 1, if branch instructions should put the address of the next instruction into the link + // register + u32 LK : 1; + // Absolute address bit + // 1, if the immediate field represents an absolute address + u32 AA : 1; + // Immediate, signed 24-bit + u32 LI : 24; + u32 OPCD_5 : 6; + }; + struct + { + u32 LK_2 : 1; + u32 AA_2 : 1; + // Branch displacement, signed 14-bit (right-extended by 0b00) + u32 BD : 14; + // Branch condition + u32 BI : 5; + // Conditional branch control + u32 BO : 5; + u32 OPCD_6 : 6; + }; + struct + { + u32 LK_3 : 1; + u32 : 10; + u32 : 5; + u32 BI_2 : 5; + u32 BO_2 : 5; + u32 OPCD_7 : 6; + }; + struct + { + u32 : 11; + u32 RB_2 : 5; + u32 RA_2 : 5; + // ? + u32 L : 1; + u32 : 1; + // Destination field in CR or FPSCR + u32 CRFD : 3; + u32 OPCD_8 : 6; + }; + struct + { + signed SIMM_16_2 : 16; + u32 RA_3 : 5; + u32 L_2 : 1; + u32 : 1; + u32 CRFD_2 : 3; + u32 OPCD_9 : 6; + }; + struct + { + u32 UIMM_2 : 16; + u32 RA_4 : 5; + u32 L_3 : 1; + u32 : 1; + u32 CRFD_3 : 3; + u32 OPCD_A : 6; + }; + struct + { + u32 : 1; + u32 SUBOP10_2 : 10; + u32 RB_5 : 5; + u32 RA_5 : 5; + u32 L_4 : 1; + u32 : 1; + u32 CRFD_4 : 3; + u32 OPCD_B : 6; + }; + struct + { + u32 : 16; + // Segment register + u32 SR : 4; + u32 : 1; + u32 RS_2 : 5; + u32 OPCD_C : 6; + }; - UGeckoInstruction(u32 _hex) : hex(_hex) {} - UGeckoInstruction() : hex(0) {} + // Table 59 + struct + { + u32 Rc_4 : 1; + u32 SUBOP5 : 5; + // ? + u32 RC : 5; + u32 : 5; + u32 RA_6 : 5; + u32 RD_2 : 5; + u32 OPCD_D : 6; + }; - struct - { - // Record bit - // 1, if the condition register should be updated by this instruction - u32 Rc : 1; - u32 SUBOP10 : 10; - // Source GPR - u32 RB : 5; - // Source or destination GPR - u32 RA : 5; - // Destination GPR - u32 RD : 5; - // Primary opcode - u32 OPCD : 6; - }; - struct - { - // Immediate, signed 16-bit - signed SIMM_16 : 16; - u32 : 5; - // Conditions on which to trap - u32 TO : 5; - u32 OPCD_2 : 6; - }; - struct - { - u32 Rc_2 : 1; - u32 : 10; - u32 : 5; - u32 : 5; - // Source GPR - u32 RS : 5; - u32 OPCD_3 : 6; - }; - struct - { - // Immediate, unsigned 16-bit - u32 UIMM : 16; - u32 : 5; - u32 : 5; - u32 OPCD_4 : 6; - }; - struct - { - // Link bit - // 1, if branch instructions should put the address of the next instruction into the link register - u32 LK : 1; - // Absolute address bit - // 1, if the immediate field represents an absolute address - u32 AA : 1; - // Immediate, signed 24-bit - u32 LI : 24; - u32 OPCD_5 : 6; - }; - struct - { - u32 LK_2 : 1; - u32 AA_2 : 1; - // Branch displacement, signed 14-bit (right-extended by 0b00) - u32 BD : 14; - // Branch condition - u32 BI : 5; - // Conditional branch control - u32 BO : 5; - u32 OPCD_6 : 6; - }; - struct - { - u32 LK_3 : 1; - u32 : 10; - u32 : 5; - u32 BI_2 : 5; - u32 BO_2 : 5; - u32 OPCD_7 : 6; - }; - struct - { - u32 : 11; - u32 RB_2 : 5; - u32 RA_2 : 5; - // ? - u32 L : 1; - u32 : 1; - // Destination field in CR or FPSCR - u32 CRFD : 3; - u32 OPCD_8 : 6; - }; - struct - { - signed SIMM_16_2 : 16; - u32 RA_3 : 5; - u32 L_2 : 1; - u32 : 1; - u32 CRFD_2 : 3; - u32 OPCD_9 : 6; - }; - struct - { - u32 UIMM_2 : 16; - u32 RA_4 : 5; - u32 L_3 : 1; - u32 : 1; - u32 CRFD_3 : 3; - u32 OPCD_A : 6; - }; - struct - { - u32 : 1; - u32 SUBOP10_2: 10; - u32 RB_5 : 5; - u32 RA_5 : 5; - u32 L_4 : 1; - u32 : 1; - u32 CRFD_4 : 3; - u32 OPCD_B : 6; - }; - struct - { - u32 : 16; - // Segment register - u32 SR : 4; - u32 : 1; - u32 RS_2 : 5; - u32 OPCD_C : 6; - }; + struct + { + u32 : 10; + // Overflow enable + u32 OE : 1; + // Special-purpose register + u32 SPR : 10; + u32 : 11; + }; + struct + { + u32 : 10; + u32 OE_3 : 1; + // Upper special-purpose register + u32 SPRU : 5; + // Lower special-purpose register + u32 SPRL : 5; + u32 : 11; + }; - // Table 59 - struct - { - u32 Rc_4 : 1; - u32 SUBOP5 : 5; - // ? - u32 RC : 5; - u32 : 5; - u32 RA_6 : 5; - u32 RD_2 : 5; - u32 OPCD_D : 6; - }; + // rlwinmx + struct + { + u32 Rc_3 : 1; + // Mask end + u32 ME : 5; + // Mask begin + u32 MB : 5; + // Shift amount + u32 SH : 5; + u32 : 16; + }; - struct - { - u32 : 10; - // Overflow enable - u32 OE : 1; - // Special-purpose register - u32 SPR : 10; - u32 : 11; - }; - struct - { - u32 : 10; - u32 OE_3 : 1; - // Upper special-purpose register - u32 SPRU : 5; - // Lower special-purpose register - u32 SPRL : 5; - u32 : 11; - }; + // crxor + struct + { + u32 : 11; + // Source bit in the CR + u32 CRBB : 5; + // Source bit in the CR + u32 CRBA : 5; + // Destination bit in the CR + u32 CRBD : 5; + u32 : 6; + }; - // rlwinmx - struct - { - u32 Rc_3 : 1; - // Mask end - u32 ME : 5; - // Mask begin - u32 MB : 5; - // Shift amount - u32 SH : 5; - u32 : 16; - }; + // mftb + struct + { + u32 : 11; + // Time base register + u32 TBR : 10; + u32 : 11; + }; - // crxor - struct - { - u32 : 11; - // Source bit in the CR - u32 CRBB : 5; - // Source bit in the CR - u32 CRBA : 5; - // Destination bit in the CR - u32 CRBD : 5; - u32 : 6; - }; + struct + { + u32 : 11; + // Upper time base register + u32 TBRU : 5; + // Lower time base register + u32 TBRL : 5; + u32 : 11; + }; - // mftb - struct - { - u32 : 11; - // Time base register - u32 TBR : 10; - u32 : 11; - }; + struct + { + u32 : 18; + // Source field in the CR or FPSCR + u32 CRFS : 3; + u32 : 2; + u32 CRFD_5 : 3; + u32 : 6; + }; - struct - { - u32 : 11; - // Upper time base register - u32 TBRU : 5; - // Lower time base register - u32 TBRL : 5; - u32 : 11; - }; + struct + { + u32 : 12; + // Field mask, identifies the CR fields to be updated by mtcrf + u32 CRM : 8; + u32 : 1; + // Destination FPR + u32 FD : 5; + u32 : 6; + }; + struct + { + u32 : 6; + // Source FPR + u32 FC : 5; + // Source FPR + u32 FB : 5; + // Source FPR + u32 FA : 5; + // Source FPR + u32 FS : 5; + u32 : 6; + }; + struct + { + u32 : 17; + // Field mask, identifies the FPSCR fields to be updated by mtfsf + u32 FM : 8; + u32 : 7; + }; - struct - { - u32 : 18; - // Source field in the CR or FPSCR - u32 CRFS : 3; - u32 : 2; - u32 CRFD_5 : 3; - u32 : 6; - }; + // paired single quantized load/store + struct + { + u32 : 1; + u32 SUBOP6 : 6; + // Graphics quantization register to use + u32 Ix : 3; + // 0: paired single, 1: scalar + u32 Wx : 1; + u32 : 1; + // Graphics quantization register to use + u32 I : 3; + // 0: paired single, 1: scalar + u32 W : 1; + u32 : 16; + }; - struct - { - u32 : 12; - // Field mask, identifies the CR fields to be updated by mtcrf - u32 CRM : 8; - u32 : 1; - // Destination FPR - u32 FD : 5; - u32 : 6; - }; - struct - { - u32 : 6; - // Source FPR - u32 FC : 5; - // Source FPR - u32 FB : 5; - // Source FPR - u32 FA : 5; - // Source FPR - u32 FS : 5; - u32 : 6; - }; - struct - { - u32 : 17; - // Field mask, identifies the FPSCR fields to be updated by mtfsf - u32 FM : 8; - u32 : 7; - }; + struct + { + signed SIMM_12 : 12; + u32 : 20; + }; - // paired single quantized load/store - struct - { - u32 : 1; - u32 SUBOP6 : 6; - // Graphics quantization register to use - u32 Ix : 3; - // 0: paired single, 1: scalar - u32 Wx : 1; - u32 : 1; - // Graphics quantization register to use - u32 I : 3; - // 0: paired single, 1: scalar - u32 W : 1; - u32 : 16; - }; - - struct - { - signed SIMM_12 : 12; - u32 : 20; - }; - - struct - { - u32 : 11; - // Number of bytes to use in lswi/stswi (0 means 32 bytes) - u32 NB : 5; - }; + struct + { + u32 : 11; + // Number of bytes to use in lswi/stswi (0 means 32 bytes) + u32 NB : 5; + }; }; - // // --- Gekko Special Registers --- // @@ -304,39 +300,37 @@ union UGeckoInstruction // quantize types enum EQuantizeType : u32 { - QUANTIZE_FLOAT = 0, - QUANTIZE_INVALID1 = 1, - QUANTIZE_INVALID2 = 2, - QUANTIZE_INVALID3 = 3, - QUANTIZE_U8 = 4, - QUANTIZE_U16 = 5, - QUANTIZE_S8 = 6, - QUANTIZE_S16 = 7, + QUANTIZE_FLOAT = 0, + QUANTIZE_INVALID1 = 1, + QUANTIZE_INVALID2 = 2, + QUANTIZE_INVALID3 = 3, + QUANTIZE_U8 = 4, + QUANTIZE_U16 = 5, + QUANTIZE_S8 = 6, + QUANTIZE_S16 = 7, }; // GQR Register -union UGQR -{ - BitField< 0, 3, EQuantizeType> st_type; - BitField< 8, 6, u32> st_scale; - BitField<16, 3, EQuantizeType> ld_type; - BitField<24, 6, u32> ld_scale; +union UGQR { + BitField<0, 3, EQuantizeType> st_type; + BitField<8, 6, u32> st_scale; + BitField<16, 3, EQuantizeType> ld_type; + BitField<24, 6, u32> ld_scale; - u32 Hex; + u32 Hex; - UGQR(u32 _hex) { Hex = _hex; } - UGQR() { Hex = 0; } + UGQR(u32 _hex) { Hex = _hex; } + UGQR() { Hex = 0; } }; // FPU Register -union UFPR -{ - u64 as_u64; - s64 as_s64; - double d; - u32 as_u32[2]; - s32 as_s32[2]; - float f[2]; +union UFPR { + u64 as_u64; + s64 as_s64; + double d; + u32 as_u32[2]; + s32 as_s32[2]; + float f[2]; }; #define XER_CA_SHIFT 29 @@ -345,54 +339,52 @@ union UFPR #define XER_OV_MASK 1 #define XER_SO_MASK 2 // XER -union UReg_XER -{ - struct - { - u32 BYTE_COUNT : 7; - u32 : 1; - u32 BYTE_CMP : 8; - u32 : 13; - u32 CA : 1; - u32 OV : 1; - u32 SO : 1; - }; - u32 Hex; +union UReg_XER { + struct + { + u32 BYTE_COUNT : 7; + u32 : 1; + u32 BYTE_CMP : 8; + u32 : 13; + u32 CA : 1; + u32 OV : 1; + u32 SO : 1; + }; + u32 Hex; - UReg_XER(u32 _hex) { Hex = _hex; } - UReg_XER() { Hex = 0; } + UReg_XER(u32 _hex) { Hex = _hex; } + UReg_XER() { Hex = 0; } }; // Machine State Register -union UReg_MSR -{ - struct - { - u32 LE : 1; - u32 RI : 1; - u32 PM : 1; - u32 : 1; // res28 - u32 DR : 1; - u32 IR : 1; - u32 IP : 1; - u32 : 1; // res24 - u32 FE1 : 1; - u32 BE : 1; - u32 SE : 1; - u32 FE0 : 1; - u32 MCHECK : 1; - u32 FP : 1; - u32 PR : 1; - u32 EE : 1; - u32 ILE : 1; - u32 : 1; // res14 - u32 POW : 1; - u32 res : 13; - }; - u32 Hex; +union UReg_MSR { + struct + { + u32 LE : 1; + u32 RI : 1; + u32 PM : 1; + u32 : 1; // res28 + u32 DR : 1; + u32 IR : 1; + u32 IP : 1; + u32 : 1; // res24 + u32 FE1 : 1; + u32 BE : 1; + u32 SE : 1; + u32 FE0 : 1; + u32 MCHECK : 1; + u32 FP : 1; + u32 PR : 1; + u32 EE : 1; + u32 ILE : 1; + u32 : 1; // res14 + u32 POW : 1; + u32 res : 13; + }; + u32 Hex; - UReg_MSR(u32 _hex) { Hex = _hex; } - UReg_MSR() { Hex = 0; } + UReg_MSR(u32 _hex) { Hex = _hex; } + UReg_MSR() { Hex = 0; } }; #define FPRF_SHIFT 12 @@ -401,334 +393,319 @@ union UReg_MSR // FPSCR exception flags enum FPSCRExceptionFlag : u32 { - FPSCR_FX = 1U << (31 - 0), - FPSCR_FEX = 1U << (31 - 1), - FPSCR_VX = 1U << (31 - 2), - FPSCR_OX = 1U << (31 - 3), - FPSCR_UX = 1U << (31 - 4), - FPSCR_ZX = 1U << (31 - 5), - FPSCR_XX = 1U << (31 - 6), - FPSCR_VXSNAN = 1U << (31 - 7), - FPSCR_VXISI = 1U << (31 - 8), - FPSCR_VXIDI = 1U << (31 - 9), - FPSCR_VXZDZ = 1U << (31 - 10), - FPSCR_VXIMZ = 1U << (31 - 11), - FPSCR_VXVC = 1U << (31 - 12), - FPSCR_VXSOFT = 1U << (31 - 21), - FPSCR_VXSQRT = 1U << (31 - 22), - FPSCR_VXCVI = 1U << (31 - 23), - FPSCR_VE = 1U << (31 - 24), + FPSCR_FX = 1U << (31 - 0), + FPSCR_FEX = 1U << (31 - 1), + FPSCR_VX = 1U << (31 - 2), + FPSCR_OX = 1U << (31 - 3), + FPSCR_UX = 1U << (31 - 4), + FPSCR_ZX = 1U << (31 - 5), + FPSCR_XX = 1U << (31 - 6), + FPSCR_VXSNAN = 1U << (31 - 7), + FPSCR_VXISI = 1U << (31 - 8), + FPSCR_VXIDI = 1U << (31 - 9), + FPSCR_VXZDZ = 1U << (31 - 10), + FPSCR_VXIMZ = 1U << (31 - 11), + FPSCR_VXVC = 1U << (31 - 12), + FPSCR_VXSOFT = 1U << (31 - 21), + FPSCR_VXSQRT = 1U << (31 - 22), + FPSCR_VXCVI = 1U << (31 - 23), + FPSCR_VE = 1U << (31 - 24), - FPSCR_VX_ANY = FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI | FPSCR_VXZDZ | FPSCR_VXIMZ | - FPSCR_VXVC | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI, + FPSCR_VX_ANY = FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI | FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC | + FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI, - FPSCR_ANY_X = FPSCR_OX | FPSCR_UX | FPSCR_ZX | FPSCR_XX | FPSCR_VX_ANY, + FPSCR_ANY_X = FPSCR_OX | FPSCR_UX | FPSCR_ZX | FPSCR_XX | FPSCR_VX_ANY, }; // Floating Point Status and Control Register -union UReg_FPSCR -{ - struct - { - // Rounding mode (towards: nearest, zero, +inf, -inf) - u32 RN : 2; - // Non-IEEE mode enable (aka flush-to-zero) - u32 NI : 1; - // Inexact exception enable - u32 XE : 1; - // IEEE division by zero exception enable - u32 ZE : 1; - // IEEE underflow exception enable - u32 UE : 1; - // IEEE overflow exception enable - u32 OE : 1; - // Invalid operation exception enable - u32 VE : 1; - // Invalid operation exception for integer conversion (sticky) - u32 VXCVI : 1; - // Invalid operation exception for square root (sticky) - u32 VXSQRT : 1; - // Invalid operation exception for software request (sticky) - u32 VXSOFT : 1; - // reserved - u32 : 1; - // Floating point result flags (includes FPCC) (not sticky) - // from more to less significand: class, <, >, =, ? - u32 FPRF : 5; - // Fraction inexact (not sticky) - u32 FI : 1; - // Fraction rounded (not sticky) - u32 FR : 1; - // Invalid operation exception for invalid comparison (sticky) - u32 VXVC : 1; - // Invalid operation exception for inf * 0 (sticky) - u32 VXIMZ : 1; - // Invalid operation exception for 0 / 0 (sticky) - u32 VXZDZ : 1; - // Invalid operation exception for inf / inf (sticky) - u32 VXIDI : 1; - // Invalid operation exception for inf - inf (sticky) - u32 VXISI : 1; - // Invalid operation exception for SNaN (sticky) - u32 VXSNAN : 1; - // Inexact exception (sticky) - u32 XX : 1; - // Division by zero exception (sticky) - u32 ZX : 1; - // Underflow exception (sticky) - u32 UX : 1; - // Overflow exception (sticky) - u32 OX : 1; - // Invalid operation exception summary (not sticky) - u32 VX : 1; - // Enabled exception summary (not sticky) - u32 FEX : 1; - // Exception summary (sticky) - u32 FX : 1; - }; - u32 Hex; +union UReg_FPSCR { + struct + { + // Rounding mode (towards: nearest, zero, +inf, -inf) + u32 RN : 2; + // Non-IEEE mode enable (aka flush-to-zero) + u32 NI : 1; + // Inexact exception enable + u32 XE : 1; + // IEEE division by zero exception enable + u32 ZE : 1; + // IEEE underflow exception enable + u32 UE : 1; + // IEEE overflow exception enable + u32 OE : 1; + // Invalid operation exception enable + u32 VE : 1; + // Invalid operation exception for integer conversion (sticky) + u32 VXCVI : 1; + // Invalid operation exception for square root (sticky) + u32 VXSQRT : 1; + // Invalid operation exception for software request (sticky) + u32 VXSOFT : 1; + // reserved + u32 : 1; + // Floating point result flags (includes FPCC) (not sticky) + // from more to less significand: class, <, >, =, ? + u32 FPRF : 5; + // Fraction inexact (not sticky) + u32 FI : 1; + // Fraction rounded (not sticky) + u32 FR : 1; + // Invalid operation exception for invalid comparison (sticky) + u32 VXVC : 1; + // Invalid operation exception for inf * 0 (sticky) + u32 VXIMZ : 1; + // Invalid operation exception for 0 / 0 (sticky) + u32 VXZDZ : 1; + // Invalid operation exception for inf / inf (sticky) + u32 VXIDI : 1; + // Invalid operation exception for inf - inf (sticky) + u32 VXISI : 1; + // Invalid operation exception for SNaN (sticky) + u32 VXSNAN : 1; + // Inexact exception (sticky) + u32 XX : 1; + // Division by zero exception (sticky) + u32 ZX : 1; + // Underflow exception (sticky) + u32 UX : 1; + // Overflow exception (sticky) + u32 OX : 1; + // Invalid operation exception summary (not sticky) + u32 VX : 1; + // Enabled exception summary (not sticky) + u32 FEX : 1; + // Exception summary (sticky) + u32 FX : 1; + }; + u32 Hex; - UReg_FPSCR(u32 _hex) { Hex = _hex; } - UReg_FPSCR() { Hex = 0;} + UReg_FPSCR(u32 _hex) { Hex = _hex; } + UReg_FPSCR() { Hex = 0; } }; // Hardware Implementation-Dependent Register 0 -union UReg_HID0 -{ - struct - { - u32 NOOPTI : 1; - u32 : 1; - u32 BHT : 1; - u32 ABE : 1; - u32 : 1; - u32 BTIC : 1; - u32 DCFA : 1; - u32 SGE : 1; - u32 IFEM : 1; - u32 SPD : 1; - u32 DCFI : 1; - u32 ICFI : 1; - u32 DLOCK : 1; - u32 ILOCK : 1; - u32 DCE : 1; - u32 ICE : 1; - u32 NHR : 1; - u32 : 3; - u32 DPM : 1; - u32 SLEEP : 1; - u32 NAP : 1; - u32 DOZE : 1; - u32 PAR : 1; - u32 ECLK : 1; - u32 : 1; - u32 BCLK : 1; - u32 EBD : 1; - u32 EBA : 1; - u32 DBP : 1; - u32 EMCP : 1; - }; - u32 Hex; +union UReg_HID0 { + struct + { + u32 NOOPTI : 1; + u32 : 1; + u32 BHT : 1; + u32 ABE : 1; + u32 : 1; + u32 BTIC : 1; + u32 DCFA : 1; + u32 SGE : 1; + u32 IFEM : 1; + u32 SPD : 1; + u32 DCFI : 1; + u32 ICFI : 1; + u32 DLOCK : 1; + u32 ILOCK : 1; + u32 DCE : 1; + u32 ICE : 1; + u32 NHR : 1; + u32 : 3; + u32 DPM : 1; + u32 SLEEP : 1; + u32 NAP : 1; + u32 DOZE : 1; + u32 PAR : 1; + u32 ECLK : 1; + u32 : 1; + u32 BCLK : 1; + u32 EBD : 1; + u32 EBA : 1; + u32 DBP : 1; + u32 EMCP : 1; + }; + u32 Hex; }; // Hardware Implementation-Dependent Register 2 -union UReg_HID2 -{ - struct - { - u32 : 16; - u32 DQOEE : 1; - u32 DCMEE : 1; - u32 DNCEE : 1; - u32 DCHEE : 1; - u32 DQOERR : 1; - u32 DCMERR : 1; - u32 DNCERR : 1; - u32 DCHERR : 1; - u32 DMAQL : 4; - u32 LCE : 1; - u32 PSE : 1; - u32 WPE : 1; - u32 LSQE : 1; - }; - u32 Hex; +union UReg_HID2 { + struct + { + u32 : 16; + u32 DQOEE : 1; + u32 DCMEE : 1; + u32 DNCEE : 1; + u32 DCHEE : 1; + u32 DQOERR : 1; + u32 DCMERR : 1; + u32 DNCERR : 1; + u32 DCHERR : 1; + u32 DMAQL : 4; + u32 LCE : 1; + u32 PSE : 1; + u32 WPE : 1; + u32 LSQE : 1; + }; + u32 Hex; - UReg_HID2(u32 _hex) { Hex = _hex; } - UReg_HID2() { Hex = 0; } + UReg_HID2(u32 _hex) { Hex = _hex; } + UReg_HID2() { Hex = 0; } }; // Hardware Implementation-Dependent Register 4 -union UReg_HID4 -{ - struct - { - u32 : 20; - u32 L2CFI : 1; - u32 L2MUM : 1; - u32 DBP : 1; - u32 LPE : 1; - u32 ST0 : 1; - u32 SBE : 1; - u32 : 1; - u32 BPD : 2; - u32 L2FM : 2; - u32 : 1; - }; - u32 Hex; +union UReg_HID4 { + struct + { + u32 : 20; + u32 L2CFI : 1; + u32 L2MUM : 1; + u32 DBP : 1; + u32 LPE : 1; + u32 ST0 : 1; + u32 SBE : 1; + u32 : 1; + u32 BPD : 2; + u32 L2FM : 2; + u32 : 1; + }; + u32 Hex; - UReg_HID4(u32 _hex) { Hex = _hex; } - UReg_HID4() { Hex = 0; } + UReg_HID4(u32 _hex) { Hex = _hex; } + UReg_HID4() { Hex = 0; } }; // SPR1 - Page Table format -union UReg_SPR1 -{ - u32 Hex; - struct - { - u32 htaborg : 16; - u32 : 7; - u32 htabmask : 9; - }; +union UReg_SPR1 { + u32 Hex; + struct + { + u32 htaborg : 16; + u32 : 7; + u32 htabmask : 9; + }; }; // MMCR0 - Monitor Mode Control Register 0 format -union UReg_MMCR0 -{ - u32 Hex; - struct - { - u32 PMC2SELECT : 6; - u32 PMC1SELECT : 7; - u32 PMCTRIGGER : 1; - u32 PMCINTCONTROL : 1; - u32 PMC1INTCONTROL : 1; - u32 THRESHOLD : 6; - u32 INTONBITTRANS : 1; - u32 RTCSELECT : 2; - u32 DISCOUNT : 1; - u32 ENINT : 1; - u32 DMR : 1; - u32 DMS : 1; - u32 DU : 1; - u32 DP : 1; - u32 DIS : 1; - }; +union UReg_MMCR0 { + u32 Hex; + struct + { + u32 PMC2SELECT : 6; + u32 PMC1SELECT : 7; + u32 PMCTRIGGER : 1; + u32 PMCINTCONTROL : 1; + u32 PMC1INTCONTROL : 1; + u32 THRESHOLD : 6; + u32 INTONBITTRANS : 1; + u32 RTCSELECT : 2; + u32 DISCOUNT : 1; + u32 ENINT : 1; + u32 DMR : 1; + u32 DMS : 1; + u32 DU : 1; + u32 DP : 1; + u32 DIS : 1; + }; }; // MMCR1 - Monitor Mode Control Register 1 format -union UReg_MMCR1 -{ - u32 Hex; - struct - { - u32 : 22; - u32 PMC4SELECT : 5; - u32 PMC3SELECT : 5; - }; +union UReg_MMCR1 { + u32 Hex; + struct + { + u32 : 22; + u32 PMC4SELECT : 5; + u32 PMC3SELECT : 5; + }; }; // Write Pipe Address Register -union UReg_WPAR -{ - struct - { - u32 BNE : 1; - u32 : 4; - u32 GB_ADDR : 27; - }; - u32 Hex; +union UReg_WPAR { + struct + { + u32 BNE : 1; + u32 : 4; + u32 GB_ADDR : 27; + }; + u32 Hex; - UReg_WPAR(u32 _hex) { Hex = _hex; } - UReg_WPAR() { Hex = 0; } + UReg_WPAR(u32 _hex) { Hex = _hex; } + UReg_WPAR() { Hex = 0; } }; // Direct Memory Access Upper register -union UReg_DMAU -{ - struct - { - u32 DMA_LEN_U : 5; - u32 MEM_ADDR : 27; - }; - u32 Hex; +union UReg_DMAU { + struct + { + u32 DMA_LEN_U : 5; + u32 MEM_ADDR : 27; + }; + u32 Hex; - UReg_DMAU(u32 _hex) { Hex = _hex; } - UReg_DMAU() { Hex = 0; } + UReg_DMAU(u32 _hex) { Hex = _hex; } + UReg_DMAU() { Hex = 0; } }; // Direct Memory Access Lower (DMAL) register -union UReg_DMAL -{ - struct - { - u32 DMA_F : 1; - u32 DMA_T : 1; - u32 DMA_LEN_L : 2; - u32 DMA_LD : 1; - u32 LC_ADDR : 27; - }; - u32 Hex; +union UReg_DMAL { + struct + { + u32 DMA_F : 1; + u32 DMA_T : 1; + u32 DMA_LEN_L : 2; + u32 DMA_LD : 1; + u32 LC_ADDR : 27; + }; + u32 Hex; - UReg_DMAL(u32 _hex) { Hex = _hex; } - UReg_DMAL() { Hex = 0; } + UReg_DMAL(u32 _hex) { Hex = _hex; } + UReg_DMAL() { Hex = 0; } }; -union UReg_BAT_Up -{ - struct - { - u32 VP : 1; - u32 VS : 1; - u32 BL : 11; // Block length (aka block size mask) - u32 : 4; - u32 BEPI : 15; - }; - u32 Hex; +union UReg_BAT_Up { + struct + { + u32 VP : 1; + u32 VS : 1; + u32 BL : 11; // Block length (aka block size mask) + u32 : 4; + u32 BEPI : 15; + }; + u32 Hex; - UReg_BAT_Up(u32 _hex) { Hex = _hex; } - UReg_BAT_Up() { Hex = 0; } + UReg_BAT_Up(u32 _hex) { Hex = _hex; } + UReg_BAT_Up() { Hex = 0; } }; -union UReg_BAT_Lo -{ - struct - { - u32 PP : 2; - u32 : 1; - u32 WIMG : 4; - u32 : 10; - u32 BRPN : 15; // Physical Block Number - }; - u32 Hex; +union UReg_BAT_Lo { + struct + { + u32 PP : 2; + u32 : 1; + u32 WIMG : 4; + u32 : 10; + u32 BRPN : 15; // Physical Block Number + }; + u32 Hex; - UReg_BAT_Lo(u32 _hex) { Hex = _hex; } - UReg_BAT_Lo() { Hex = 0; } + UReg_BAT_Lo(u32 _hex) { Hex = _hex; } + UReg_BAT_Lo() { Hex = 0; } }; -union UReg_PTE -{ - struct - { - u64 API : 6; - u64 H : 1; - u64 VSID : 24; - u64 V : 1; - u64 PP : 2; - u64 : 1; - u64 WIMG : 4; - u64 C : 1; - u64 R : 1; - u64 : 3; - u64 RPN : 20; +union UReg_PTE { + struct + { + u64 API : 6; + u64 H : 1; + u64 VSID : 24; + u64 V : 1; + u64 PP : 2; + u64 : 1; + u64 WIMG : 4; + u64 C : 1; + u64 R : 1; + u64 : 3; + u64 RPN : 20; + }; - }; - - u64 Hex; - u32 Hex32[2]; + u64 Hex; + u32 Hex32[2]; }; - // // --- Gekko Types and Defs --- // @@ -736,105 +713,111 @@ union UReg_PTE // branches enum { - BO_BRANCH_IF_CTR_0 = 2, // 3 - BO_DONT_DECREMENT_FLAG = 4, // 2 - BO_BRANCH_IF_TRUE = 8, // 1 - BO_DONT_CHECK_CONDITION = 16, // 0 + BO_BRANCH_IF_CTR_0 = 2, // 3 + BO_DONT_DECREMENT_FLAG = 4, // 2 + BO_BRANCH_IF_TRUE = 8, // 1 + BO_DONT_CHECK_CONDITION = 16, // 0 }; // Special purpose register indices enum { - SPR_XER = 1, - SPR_LR = 8, - SPR_CTR = 9, - SPR_DSISR = 18, - SPR_DAR = 19, - SPR_DEC = 22, - SPR_SDR = 25, - SPR_SRR0 = 26, - SPR_SRR1 = 27, - SPR_TL = 268, - SPR_TU = 269, - SPR_TL_W = 284, - SPR_TU_W = 285, - SPR_PVR = 287, - SPR_SPRG0 = 272, - SPR_SPRG1 = 273, - SPR_SPRG2 = 274, - SPR_SPRG3 = 275, - SPR_EAR = 282, - SPR_IBAT0U = 528, - SPR_IBAT0L = 529, - SPR_IBAT1U = 530, - SPR_IBAT1L = 531, - SPR_IBAT2U = 532, - SPR_IBAT2L = 533, - SPR_IBAT3U = 534, - SPR_IBAT3L = 535, - SPR_DBAT0U = 536, - SPR_DBAT0L = 537, - SPR_DBAT1U = 538, - SPR_DBAT1L = 539, - SPR_DBAT2U = 540, - SPR_DBAT2L = 541, - SPR_DBAT3U = 542, - SPR_DBAT3L = 543, - SPR_IBAT4U = 560, - SPR_IBAT4L = 561, - SPR_IBAT5U = 562, - SPR_IBAT5L = 563, - SPR_IBAT6U = 564, - SPR_IBAT6L = 565, - SPR_IBAT7U = 566, - SPR_IBAT7L = 567, - SPR_DBAT4U = 568, - SPR_DBAT4L = 569, - SPR_DBAT5U = 570, - SPR_DBAT5L = 571, - SPR_DBAT6U = 572, - SPR_DBAT6L = 573, - SPR_DBAT7U = 574, - SPR_DBAT7L = 575, - SPR_GQR0 = 912, - SPR_HID0 = 1008, - SPR_HID1 = 1009, - SPR_HID2 = 920, - SPR_HID4 = 1011, - SPR_WPAR = 921, - SPR_DMAU = 922, - SPR_DMAL = 923, - SPR_ECID_U = 924, - SPR_ECID_M = 925, - SPR_ECID_L = 926, - SPR_L2CR = 1017, + SPR_XER = 1, + SPR_LR = 8, + SPR_CTR = 9, + SPR_DSISR = 18, + SPR_DAR = 19, + SPR_DEC = 22, + SPR_SDR = 25, + SPR_SRR0 = 26, + SPR_SRR1 = 27, + SPR_TL = 268, + SPR_TU = 269, + SPR_TL_W = 284, + SPR_TU_W = 285, + SPR_PVR = 287, + SPR_SPRG0 = 272, + SPR_SPRG1 = 273, + SPR_SPRG2 = 274, + SPR_SPRG3 = 275, + SPR_EAR = 282, + SPR_IBAT0U = 528, + SPR_IBAT0L = 529, + SPR_IBAT1U = 530, + SPR_IBAT1L = 531, + SPR_IBAT2U = 532, + SPR_IBAT2L = 533, + SPR_IBAT3U = 534, + SPR_IBAT3L = 535, + SPR_DBAT0U = 536, + SPR_DBAT0L = 537, + SPR_DBAT1U = 538, + SPR_DBAT1L = 539, + SPR_DBAT2U = 540, + SPR_DBAT2L = 541, + SPR_DBAT3U = 542, + SPR_DBAT3L = 543, + SPR_IBAT4U = 560, + SPR_IBAT4L = 561, + SPR_IBAT5U = 562, + SPR_IBAT5L = 563, + SPR_IBAT6U = 564, + SPR_IBAT6L = 565, + SPR_IBAT7U = 566, + SPR_IBAT7L = 567, + SPR_DBAT4U = 568, + SPR_DBAT4L = 569, + SPR_DBAT5U = 570, + SPR_DBAT5L = 571, + SPR_DBAT6U = 572, + SPR_DBAT6L = 573, + SPR_DBAT7U = 574, + SPR_DBAT7L = 575, + SPR_GQR0 = 912, + SPR_HID0 = 1008, + SPR_HID1 = 1009, + SPR_HID2 = 920, + SPR_HID4 = 1011, + SPR_WPAR = 921, + SPR_DMAU = 922, + SPR_DMAL = 923, + SPR_ECID_U = 924, + SPR_ECID_M = 925, + SPR_ECID_L = 926, + SPR_L2CR = 1017, - SPR_UMMCR0 = 936, - SPR_MMCR0 = 952, - SPR_PMC1 = 953, - SPR_PMC2 = 954, + SPR_UMMCR0 = 936, + SPR_MMCR0 = 952, + SPR_PMC1 = 953, + SPR_PMC2 = 954, - SPR_UMMCR1 = 940, - SPR_MMCR1 = 956, - SPR_PMC3 = 957, - SPR_PMC4 = 958, + SPR_UMMCR1 = 940, + SPR_MMCR1 = 956, + SPR_PMC3 = 957, + SPR_PMC4 = 958, }; // Exceptions enum { - EXCEPTION_DECREMENTER = 0x00000001, - EXCEPTION_SYSCALL = 0x00000002, - EXCEPTION_EXTERNAL_INT = 0x00000004, - EXCEPTION_DSI = 0x00000008, - EXCEPTION_ISI = 0x00000010, - EXCEPTION_ALIGNMENT = 0x00000020, - EXCEPTION_FPU_UNAVAILABLE = 0x00000040, - EXCEPTION_PROGRAM = 0x00000080, - EXCEPTION_PERFORMANCE_MONITOR = 0x00000100, + EXCEPTION_DECREMENTER = 0x00000001, + EXCEPTION_SYSCALL = 0x00000002, + EXCEPTION_EXTERNAL_INT = 0x00000004, + EXCEPTION_DSI = 0x00000008, + EXCEPTION_ISI = 0x00000010, + EXCEPTION_ALIGNMENT = 0x00000020, + EXCEPTION_FPU_UNAVAILABLE = 0x00000040, + EXCEPTION_PROGRAM = 0x00000080, + EXCEPTION_PERFORMANCE_MONITOR = 0x00000100, - EXCEPTION_FAKE_MEMCHECK_HIT = 0x00000200, + EXCEPTION_FAKE_MEMCHECK_HIT = 0x00000200, }; -constexpr s32 SignExt16(s16 x) {return (s32)x;} -constexpr s32 SignExt26(u32 x) {return x & 0x2000000 ? (s32)(x | 0xFC000000) : (s32)(x);} +constexpr s32 SignExt16(s16 x) +{ + return (s32)x; +} +constexpr s32 SignExt26(u32 x) +{ + return x & 0x2000000 ? (s32)(x | 0xFC000000) : (s32)(x); +} diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp index ecf3bbb151..24337e37d7 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp @@ -9,17 +9,17 @@ #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/GekkoDisassembler.h" -#include "Common/StringUtil.h" #include "Common/Logging/Log.h" +#include "Common/StringUtil.h" #include "Core/ConfigManager.h" #include "Core/CoreTiming.h" -#include "Core/Host.h" #include "Core/Debugger/Debugger_SymbolMap.h" #include "Core/HLE/HLE.h" #include "Core/HW/CPU.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCTables.h" +#include "Core/Host.h" #include "Core/PowerPC/Interpreter/Interpreter.h" +#include "Core/PowerPC/PPCTables.h" +#include "Core/PowerPC/PowerPC.h" #ifdef USE_GDBSTUB #include "Core/PowerPC/GDBStub.h" @@ -27,7 +27,7 @@ namespace { - u32 last_pc; +u32 last_pc; } bool Interpreter::m_EndBlock; @@ -40,16 +40,31 @@ Interpreter::Instruction Interpreter::m_opTable31[1024]; Interpreter::Instruction Interpreter::m_opTable59[32]; Interpreter::Instruction Interpreter::m_opTable63[1024]; -void Interpreter::RunTable4(UGeckoInstruction _inst) { m_opTable4 [_inst.SUBOP10](_inst); } -void Interpreter::RunTable19(UGeckoInstruction _inst) { m_opTable19[_inst.SUBOP10](_inst); } -void Interpreter::RunTable31(UGeckoInstruction _inst) { m_opTable31[_inst.SUBOP10](_inst); } -void Interpreter::RunTable59(UGeckoInstruction _inst) { m_opTable59[_inst.SUBOP5 ](_inst); } -void Interpreter::RunTable63(UGeckoInstruction _inst) { m_opTable63[_inst.SUBOP10](_inst); } +void Interpreter::RunTable4(UGeckoInstruction _inst) +{ + m_opTable4[_inst.SUBOP10](_inst); +} +void Interpreter::RunTable19(UGeckoInstruction _inst) +{ + m_opTable19[_inst.SUBOP10](_inst); +} +void Interpreter::RunTable31(UGeckoInstruction _inst) +{ + m_opTable31[_inst.SUBOP10](_inst); +} +void Interpreter::RunTable59(UGeckoInstruction _inst) +{ + m_opTable59[_inst.SUBOP5](_inst); +} +void Interpreter::RunTable63(UGeckoInstruction _inst) +{ + m_opTable63[_inst.SUBOP10](_inst); +} void Interpreter::Init() { - g_bReserve = false; - m_EndBlock = false; + g_bReserve = false; + m_EndBlock = false; } void Interpreter::Shutdown() @@ -60,139 +75,144 @@ static int startTrace = 0; static void Trace(UGeckoInstruction& instCode) { - std::string regs = ""; - for (int i = 0; i < 32; i++) - { - regs += StringFromFormat("r%02d: %08x ", i, PowerPC::ppcState.gpr[i]); - } + std::string regs = ""; + for (int i = 0; i < 32; i++) + { + regs += StringFromFormat("r%02d: %08x ", i, PowerPC::ppcState.gpr[i]); + } - std::string fregs = ""; - for (int i = 0; i < 32; i++) - { - fregs += StringFromFormat("f%02d: %08" PRIx64 " %08" PRIx64 " ", i, PowerPC::ppcState.ps[i][0], PowerPC::ppcState.ps[i][1]); - } + std::string fregs = ""; + for (int i = 0; i < 32; i++) + { + fregs += StringFromFormat("f%02d: %08" PRIx64 " %08" PRIx64 " ", i, PowerPC::ppcState.ps[i][0], + PowerPC::ppcState.ps[i][1]); + } - std::string ppc_inst = GekkoDisassembler::Disassemble(instCode.hex, PC); - DEBUG_LOG(POWERPC, "INTER PC: %08x SRR0: %08x SRR1: %08x CRval: %016lx FPSCR: %08x MSR: %08x LR: %08x %s %08x %s", PC, SRR0, SRR1, (unsigned long) PowerPC::ppcState.cr_val[0], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), instCode.hex, ppc_inst.c_str()); + std::string ppc_inst = GekkoDisassembler::Disassemble(instCode.hex, PC); + DEBUG_LOG(POWERPC, "INTER PC: %08x SRR0: %08x SRR1: %08x CRval: %016lx FPSCR: %08x MSR: %08x LR: " + "%08x %s %08x %s", + PC, SRR0, SRR1, (unsigned long)PowerPC::ppcState.cr_val[0], PowerPC::ppcState.fpscr, + PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), instCode.hex, + ppc_inst.c_str()); } int Interpreter::SingleStepInner() { - static UGeckoInstruction instCode; - u32 function = HLE::GetFunctionIndex(PC); - if (function != 0) - { - int type = HLE::GetFunctionTypeByIndex(function); - if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE) - { - int flags = HLE::GetFunctionFlagsByIndex(function); - if (HLE::IsEnabled(flags)) - { - HLEFunction(function); - if (type == HLE::HLE_HOOK_START) - { - // Run the original. - function = 0; - } - } - else - { - function = 0; - } - } - } + static UGeckoInstruction instCode; + u32 function = HLE::GetFunctionIndex(PC); + if (function != 0) + { + int type = HLE::GetFunctionTypeByIndex(function); + if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE) + { + int flags = HLE::GetFunctionFlagsByIndex(function); + if (HLE::IsEnabled(flags)) + { + HLEFunction(function); + if (type == HLE::HLE_HOOK_START) + { + // Run the original. + function = 0; + } + } + else + { + function = 0; + } + } + } - if (function == 0) - { - #ifdef USE_GDBSTUB - if (gdb_active() && gdb_bp_x(PC)) - { - Host_UpdateDisasmDialog(); + if (function == 0) + { +#ifdef USE_GDBSTUB + if (gdb_active() && gdb_bp_x(PC)) + { + Host_UpdateDisasmDialog(); - gdb_signal(SIGTRAP); - gdb_handle_exception(); - } - #endif + gdb_signal(SIGTRAP); + gdb_handle_exception(); + } +#endif - NPC = PC + sizeof(UGeckoInstruction); - instCode.hex = PowerPC::Read_Opcode(PC); + NPC = PC + sizeof(UGeckoInstruction); + instCode.hex = PowerPC::Read_Opcode(PC); - // Uncomment to trace the interpreter - //if ((PC & 0xffffff)>=0x0ab54c && (PC & 0xffffff)<=0x0ab624) - // startTrace = 1; - //else - // startTrace = 0; + // Uncomment to trace the interpreter + // if ((PC & 0xffffff)>=0x0ab54c && (PC & 0xffffff)<=0x0ab624) + // startTrace = 1; + // else + // startTrace = 0; - if (startTrace) - { - Trace(instCode); - } + if (startTrace) + { + Trace(instCode); + } - if (instCode.hex != 0) - { - UReg_MSR& msr = (UReg_MSR&)MSR; - if (msr.FP) //If FPU is enabled, just execute - { - m_opTable[instCode.OPCD](instCode); - if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) - { - PowerPC::CheckExceptions(); - m_EndBlock = true; - } - } - else - { - // check if we have to generate a FPU unavailable exception - if (!PPCTables::UsesFPU(instCode)) - { - m_opTable[instCode.OPCD](instCode); - if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) - { - PowerPC::CheckExceptions(); - m_EndBlock = true; - } - } - else - { - PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE; - PowerPC::CheckExceptions(); - m_EndBlock = true; - } - } - } - else - { - // Memory exception on instruction fetch - PowerPC::CheckExceptions(); - m_EndBlock = true; - } - } - last_pc = PC; - PC = NPC; + if (instCode.hex != 0) + { + UReg_MSR& msr = (UReg_MSR&)MSR; + if (msr.FP) // If FPU is enabled, just execute + { + m_opTable[instCode.OPCD](instCode); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + PowerPC::CheckExceptions(); + m_EndBlock = true; + } + } + else + { + // check if we have to generate a FPU unavailable exception + if (!PPCTables::UsesFPU(instCode)) + { + m_opTable[instCode.OPCD](instCode); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + PowerPC::CheckExceptions(); + m_EndBlock = true; + } + } + else + { + PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE; + PowerPC::CheckExceptions(); + m_EndBlock = true; + } + } + } + else + { + // Memory exception on instruction fetch + PowerPC::CheckExceptions(); + m_EndBlock = true; + } + } + last_pc = PC; + PC = NPC; - GekkoOPInfo *opinfo = GetOpInfo(instCode); - return opinfo->numCycles; + GekkoOPInfo* opinfo = GetOpInfo(instCode); + return opinfo->numCycles; } void Interpreter::SingleStep() { - SingleStepInner(); + SingleStepInner(); - CoreTiming::g_slicelength = 1; - PowerPC::ppcState.downcount = 0; - CoreTiming::Advance(); + CoreTiming::g_slicelength = 1; + PowerPC::ppcState.downcount = 0; + CoreTiming::Advance(); - if (PowerPC::ppcState.Exceptions) - { - PowerPC::CheckExceptions(); - PC = NPC; - } + if (PowerPC::ppcState.Exceptions) + { + PowerPC::CheckExceptions(); + PC = NPC; + } } //#define SHOW_HISTORY #ifdef SHOW_HISTORY -std::vector PCVec; -std::vector PCBlockVec; +std::vector PCVec; +std::vector PCBlockVec; int ShowBlocks = 30; int ShowSteps = 300; #endif @@ -200,118 +220,118 @@ int ShowSteps = 300; // FastRun - inspired by GCemu (to imitate the JIT so that they can be compared). void Interpreter::Run() { - while (!CPU::GetState()) - { - //we have to check exceptions at branches apparently (or maybe just rfi?) - if (SConfig::GetInstance().bEnableDebugging) - { - #ifdef SHOW_HISTORY - PCBlockVec.push_back(PC); - if (PCBlockVec.size() > ShowBlocks) - PCBlockVec.erase(PCBlockVec.begin()); - #endif + while (!CPU::GetState()) + { + // we have to check exceptions at branches apparently (or maybe just rfi?) + if (SConfig::GetInstance().bEnableDebugging) + { +#ifdef SHOW_HISTORY + PCBlockVec.push_back(PC); + if (PCBlockVec.size() > ShowBlocks) + PCBlockVec.erase(PCBlockVec.begin()); +#endif - // Debugging friendly version of inner loop. Tries to do the timing as similarly to the - // JIT as possible. Does not take into account that some instructions take multiple cycles. - while (PowerPC::ppcState.downcount > 0) - { - m_EndBlock = false; - int i; - for (i = 0; !m_EndBlock; i++) - { - #ifdef SHOW_HISTORY - PCVec.push_back(PC); - if (PCVec.size() > ShowSteps) - PCVec.erase(PCVec.begin()); - #endif + // Debugging friendly version of inner loop. Tries to do the timing as similarly to the + // JIT as possible. Does not take into account that some instructions take multiple cycles. + while (PowerPC::ppcState.downcount > 0) + { + m_EndBlock = false; + int i; + for (i = 0; !m_EndBlock; i++) + { +#ifdef SHOW_HISTORY + PCVec.push_back(PC); + if (PCVec.size() > ShowSteps) + PCVec.erase(PCVec.begin()); +#endif + // 2: check for breakpoint + if (PowerPC::breakpoints.IsAddressBreakPoint(PC)) + { +#ifdef SHOW_HISTORY + NOTICE_LOG(POWERPC, "----------------------------"); + NOTICE_LOG(POWERPC, "Blocks:"); + for (int j = 0; j < PCBlockVec.size(); j++) + NOTICE_LOG(POWERPC, "PC: 0x%08x", PCBlockVec.at(j)); + NOTICE_LOG(POWERPC, "----------------------------"); + NOTICE_LOG(POWERPC, "Steps:"); + for (int j = 0; j < PCVec.size(); j++) + { + // Write space + if (j > 0) + { + if (PCVec.at(j) != PCVec.at(j - 1) + 4) + NOTICE_LOG(POWERPC, ""); + } - //2: check for breakpoint - if (PowerPC::breakpoints.IsAddressBreakPoint(PC)) - { - #ifdef SHOW_HISTORY - NOTICE_LOG(POWERPC, "----------------------------"); - NOTICE_LOG(POWERPC, "Blocks:"); - for (int j = 0; j < PCBlockVec.size(); j++) - NOTICE_LOG(POWERPC, "PC: 0x%08x", PCBlockVec.at(j)); - NOTICE_LOG(POWERPC, "----------------------------"); - NOTICE_LOG(POWERPC, "Steps:"); - for (int j = 0; j < PCVec.size(); j++) - { - // Write space - if (j > 0) - { - if (PCVec.at(j) != PCVec.at(j-1) + 4) - NOTICE_LOG(POWERPC, ""); - } + NOTICE_LOG(POWERPC, "PC: 0x%08x", PCVec.at(j)); + } +#endif + INFO_LOG(POWERPC, "Hit Breakpoint - %08x", PC); + CPU::Break(); + if (PowerPC::breakpoints.IsTempBreakPoint(PC)) + PowerPC::breakpoints.Remove(PC); - NOTICE_LOG(POWERPC, "PC: 0x%08x", PCVec.at(j)); - } - #endif - INFO_LOG(POWERPC, "Hit Breakpoint - %08x", PC); - CPU::Break(); - if (PowerPC::breakpoints.IsTempBreakPoint(PC)) - PowerPC::breakpoints.Remove(PC); + Host_UpdateDisasmDialog(); + return; + } + SingleStepInner(); + } + PowerPC::ppcState.downcount -= i; + } + } + else + { + // "fast" version of inner loop. well, it's not so fast. + while (PowerPC::ppcState.downcount > 0) + { + m_EndBlock = false; - Host_UpdateDisasmDialog(); - return; - } - SingleStepInner(); - } - PowerPC::ppcState.downcount -= i; - } - } - else - { - // "fast" version of inner loop. well, it's not so fast. - while (PowerPC::ppcState.downcount > 0) - { - m_EndBlock = false; + int cycles = 0; + while (!m_EndBlock) + { + cycles += SingleStepInner(); + } + PowerPC::ppcState.downcount -= cycles; + } + } - int cycles = 0; - while (!m_EndBlock) - { - cycles += SingleStepInner(); - } - PowerPC::ppcState.downcount -= cycles; - } - } - - CoreTiming::Advance(); - } + CoreTiming::Advance(); + } } void Interpreter::unknown_instruction(UGeckoInstruction _inst) { - std::string disasm = GekkoDisassembler::Disassemble(PowerPC::HostRead_U32(last_pc), last_pc); - NOTICE_LOG(POWERPC, "Last PC = %08x : %s", last_pc, disasm.c_str()); - Dolphin_Debugger::PrintCallstack(); - NOTICE_LOG(POWERPC, "\nIntCPU: Unknown instruction %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR); - for (int i = 0; i < 32; i += 4) - NOTICE_LOG(POWERPC, "r%d: 0x%08x r%d: 0x%08x r%d:0x%08x r%d: 0x%08x", - i, rGPR[i], - i + 1, rGPR[i + 1], - i + 2, rGPR[i + 2], - i + 3, rGPR[i + 3]); - _assert_msg_(POWERPC, 0, "\nIntCPU: Unknown instruction %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR); + std::string disasm = GekkoDisassembler::Disassemble(PowerPC::HostRead_U32(last_pc), last_pc); + NOTICE_LOG(POWERPC, "Last PC = %08x : %s", last_pc, disasm.c_str()); + Dolphin_Debugger::PrintCallstack(); + NOTICE_LOG(POWERPC, + "\nIntCPU: Unknown instruction %08x at PC = %08x last_PC = %08x LR = %08x\n", + _inst.hex, PC, last_pc, LR); + for (int i = 0; i < 32; i += 4) + NOTICE_LOG(POWERPC, "r%d: 0x%08x r%d: 0x%08x r%d:0x%08x r%d: 0x%08x", i, rGPR[i], i + 1, + rGPR[i + 1], i + 2, rGPR[i + 2], i + 3, rGPR[i + 3]); + _assert_msg_(POWERPC, 0, + "\nIntCPU: Unknown instruction %08x at PC = %08x last_PC = %08x LR = %08x\n", + _inst.hex, PC, last_pc, LR); } void Interpreter::ClearCache() { - // Do nothing. + // Do nothing. } -const char *Interpreter::GetName() +const char* Interpreter::GetName() { #ifdef _ARCH_64 - return "Interpreter64"; + return "Interpreter64"; #else - return "Interpreter32"; + return "Interpreter32"; #endif } -Interpreter *Interpreter::getInstance() +Interpreter* Interpreter::getInstance() { - static Interpreter instance; - return &instance; + static Interpreter instance; + return &instance; } diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.h b/Source/Core/Core/PowerPC/Interpreter/Interpreter.h index 2d81a60a3b..b756fd9ef1 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.h +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.h @@ -11,300 +11,300 @@ class Interpreter : public CPUCoreBase { public: - void Init() override; - void Shutdown() override; - void SingleStep() override; - int SingleStepInner(); + void Init() override; + void Shutdown() override; + void SingleStep() override; + int SingleStepInner(); - void Run() override; - void ClearCache() override; - const char *GetName() override; + void Run() override; + void ClearCache() override; + const char* GetName() override; - static bool m_EndBlock; + static bool m_EndBlock; - static void unknown_instruction(UGeckoInstruction _inst); + static void unknown_instruction(UGeckoInstruction _inst); - // Branch Instructions - static void bx(UGeckoInstruction _inst); - static void bcx(UGeckoInstruction _inst); - static void bcctrx(UGeckoInstruction _inst); - static void bclrx(UGeckoInstruction _inst); - static void HLEFunction(UGeckoInstruction _inst); + // Branch Instructions + static void bx(UGeckoInstruction _inst); + static void bcx(UGeckoInstruction _inst); + static void bcctrx(UGeckoInstruction _inst); + static void bclrx(UGeckoInstruction _inst); + static void HLEFunction(UGeckoInstruction _inst); - // Syscall Instruction - static void sc(UGeckoInstruction _inst); + // Syscall Instruction + static void sc(UGeckoInstruction _inst); - // Floating Point Instructions - static void faddsx(UGeckoInstruction _inst); - static void fdivsx(UGeckoInstruction _inst); - static void fmaddsx(UGeckoInstruction _inst); - static void fmsubsx(UGeckoInstruction _inst); - static void fmulsx(UGeckoInstruction _inst); - static void fnmaddsx(UGeckoInstruction _inst); - static void fnmsubsx(UGeckoInstruction _inst); - static void fresx(UGeckoInstruction _inst); - static void fsubsx(UGeckoInstruction _inst); - static void fabsx(UGeckoInstruction _inst); - static void fcmpo(UGeckoInstruction _inst); - static void fcmpu(UGeckoInstruction _inst); - static void fctiwx(UGeckoInstruction _inst); - static void fctiwzx(UGeckoInstruction _inst); - static void fmrx(UGeckoInstruction _inst); - static void fnabsx(UGeckoInstruction _inst); - static void fnegx(UGeckoInstruction _inst); - static void frspx(UGeckoInstruction _inst); - static void faddx(UGeckoInstruction _inst); - static void fdivx(UGeckoInstruction _inst); - static void fmaddx(UGeckoInstruction _inst); - static void fmsubx(UGeckoInstruction _inst); - static void fmulx(UGeckoInstruction _inst); - static void fnmaddx(UGeckoInstruction _inst); - static void fnmsubx(UGeckoInstruction _inst); - static void frsqrtex(UGeckoInstruction _inst); - static void fselx(UGeckoInstruction _inst); - static void fsubx(UGeckoInstruction _inst); + // Floating Point Instructions + static void faddsx(UGeckoInstruction _inst); + static void fdivsx(UGeckoInstruction _inst); + static void fmaddsx(UGeckoInstruction _inst); + static void fmsubsx(UGeckoInstruction _inst); + static void fmulsx(UGeckoInstruction _inst); + static void fnmaddsx(UGeckoInstruction _inst); + static void fnmsubsx(UGeckoInstruction _inst); + static void fresx(UGeckoInstruction _inst); + static void fsubsx(UGeckoInstruction _inst); + static void fabsx(UGeckoInstruction _inst); + static void fcmpo(UGeckoInstruction _inst); + static void fcmpu(UGeckoInstruction _inst); + static void fctiwx(UGeckoInstruction _inst); + static void fctiwzx(UGeckoInstruction _inst); + static void fmrx(UGeckoInstruction _inst); + static void fnabsx(UGeckoInstruction _inst); + static void fnegx(UGeckoInstruction _inst); + static void frspx(UGeckoInstruction _inst); + static void faddx(UGeckoInstruction _inst); + static void fdivx(UGeckoInstruction _inst); + static void fmaddx(UGeckoInstruction _inst); + static void fmsubx(UGeckoInstruction _inst); + static void fmulx(UGeckoInstruction _inst); + static void fnmaddx(UGeckoInstruction _inst); + static void fnmsubx(UGeckoInstruction _inst); + static void frsqrtex(UGeckoInstruction _inst); + static void fselx(UGeckoInstruction _inst); + static void fsubx(UGeckoInstruction _inst); - // Integer Instructions - static void addi(UGeckoInstruction _inst); - static void addic(UGeckoInstruction _inst); - static void addic_rc(UGeckoInstruction _inst); - static void addis(UGeckoInstruction _inst); - static void andi_rc(UGeckoInstruction _inst); - static void andis_rc(UGeckoInstruction _inst); - static void cmpi(UGeckoInstruction _inst); - static void cmpli(UGeckoInstruction _inst); - static void mulli(UGeckoInstruction _inst); - static void ori(UGeckoInstruction _inst); - static void oris(UGeckoInstruction _inst); - static void subfic(UGeckoInstruction _inst); - static void twi(UGeckoInstruction _inst); - static void xori(UGeckoInstruction _inst); - static void xoris(UGeckoInstruction _inst); - static void rlwimix(UGeckoInstruction _inst); - static void rlwinmx(UGeckoInstruction _inst); - static void rlwnmx(UGeckoInstruction _inst); - static void andx(UGeckoInstruction _inst); - static void andcx(UGeckoInstruction _inst); - static void cmp(UGeckoInstruction _inst); - static void cmpl(UGeckoInstruction _inst); - static void cntlzwx(UGeckoInstruction _inst); - static void eqvx(UGeckoInstruction _inst); - static void extsbx(UGeckoInstruction _inst); - static void extshx(UGeckoInstruction _inst); - static void nandx(UGeckoInstruction _inst); - static void norx(UGeckoInstruction _inst); - static void orx(UGeckoInstruction _inst); - static void orcx(UGeckoInstruction _inst); - static void slwx(UGeckoInstruction _inst); - static void srawx(UGeckoInstruction _inst); - static void srawix(UGeckoInstruction _inst); - static void srwx(UGeckoInstruction _inst); - static void tw(UGeckoInstruction _inst); - static void xorx(UGeckoInstruction _inst); - static void addx(UGeckoInstruction _inst); - static void addcx(UGeckoInstruction _inst); - static void addex(UGeckoInstruction _inst); - static void addmex(UGeckoInstruction _inst); - static void addzex(UGeckoInstruction _inst); - static void divwx(UGeckoInstruction _inst); - static void divwux(UGeckoInstruction _inst); - static void mulhwx(UGeckoInstruction _inst); - static void mulhwux(UGeckoInstruction _inst); - static void mullwx(UGeckoInstruction _inst); - static void negx(UGeckoInstruction _inst); - static void subfx(UGeckoInstruction _inst); - static void subfcx(UGeckoInstruction _inst); - static void subfex(UGeckoInstruction _inst); - static void subfmex(UGeckoInstruction _inst); - static void subfzex(UGeckoInstruction _inst); + // Integer Instructions + static void addi(UGeckoInstruction _inst); + static void addic(UGeckoInstruction _inst); + static void addic_rc(UGeckoInstruction _inst); + static void addis(UGeckoInstruction _inst); + static void andi_rc(UGeckoInstruction _inst); + static void andis_rc(UGeckoInstruction _inst); + static void cmpi(UGeckoInstruction _inst); + static void cmpli(UGeckoInstruction _inst); + static void mulli(UGeckoInstruction _inst); + static void ori(UGeckoInstruction _inst); + static void oris(UGeckoInstruction _inst); + static void subfic(UGeckoInstruction _inst); + static void twi(UGeckoInstruction _inst); + static void xori(UGeckoInstruction _inst); + static void xoris(UGeckoInstruction _inst); + static void rlwimix(UGeckoInstruction _inst); + static void rlwinmx(UGeckoInstruction _inst); + static void rlwnmx(UGeckoInstruction _inst); + static void andx(UGeckoInstruction _inst); + static void andcx(UGeckoInstruction _inst); + static void cmp(UGeckoInstruction _inst); + static void cmpl(UGeckoInstruction _inst); + static void cntlzwx(UGeckoInstruction _inst); + static void eqvx(UGeckoInstruction _inst); + static void extsbx(UGeckoInstruction _inst); + static void extshx(UGeckoInstruction _inst); + static void nandx(UGeckoInstruction _inst); + static void norx(UGeckoInstruction _inst); + static void orx(UGeckoInstruction _inst); + static void orcx(UGeckoInstruction _inst); + static void slwx(UGeckoInstruction _inst); + static void srawx(UGeckoInstruction _inst); + static void srawix(UGeckoInstruction _inst); + static void srwx(UGeckoInstruction _inst); + static void tw(UGeckoInstruction _inst); + static void xorx(UGeckoInstruction _inst); + static void addx(UGeckoInstruction _inst); + static void addcx(UGeckoInstruction _inst); + static void addex(UGeckoInstruction _inst); + static void addmex(UGeckoInstruction _inst); + static void addzex(UGeckoInstruction _inst); + static void divwx(UGeckoInstruction _inst); + static void divwux(UGeckoInstruction _inst); + static void mulhwx(UGeckoInstruction _inst); + static void mulhwux(UGeckoInstruction _inst); + static void mullwx(UGeckoInstruction _inst); + static void negx(UGeckoInstruction _inst); + static void subfx(UGeckoInstruction _inst); + static void subfcx(UGeckoInstruction _inst); + static void subfex(UGeckoInstruction _inst); + static void subfmex(UGeckoInstruction _inst); + static void subfzex(UGeckoInstruction _inst); - // Load/Store Instructions - static void lbz(UGeckoInstruction _inst); - static void lbzu(UGeckoInstruction _inst); - static void lfd(UGeckoInstruction _inst); - static void lfdu(UGeckoInstruction _inst); - static void lfs(UGeckoInstruction _inst); - static void lfsu(UGeckoInstruction _inst); - static void lha(UGeckoInstruction _inst); - static void lhau(UGeckoInstruction _inst); - static void lhz(UGeckoInstruction _inst); - static void lhzu(UGeckoInstruction _inst); - static void lmw(UGeckoInstruction _inst); - static void lwz(UGeckoInstruction _inst); - static void lwzu(UGeckoInstruction _inst); - static void stb(UGeckoInstruction _inst); - static void stbu(UGeckoInstruction _inst); - static void stfd(UGeckoInstruction _inst); - static void stfdu(UGeckoInstruction _inst); - static void stfs(UGeckoInstruction _inst); - static void stfsu(UGeckoInstruction _inst); - static void sth(UGeckoInstruction _inst); - static void sthu(UGeckoInstruction _inst); - static void stmw(UGeckoInstruction _inst); - static void stw(UGeckoInstruction _inst); - static void stwu(UGeckoInstruction _inst); - static void dcba(UGeckoInstruction _inst); - static void dcbf(UGeckoInstruction _inst); - static void dcbi(UGeckoInstruction _inst); - static void dcbst(UGeckoInstruction _inst); - static void dcbt(UGeckoInstruction _inst); - static void dcbtst(UGeckoInstruction _inst); - static void dcbz(UGeckoInstruction _inst); - static void eciwx(UGeckoInstruction _inst); - static void ecowx(UGeckoInstruction _inst); - static void eieio(UGeckoInstruction _inst); - static void icbi(UGeckoInstruction _inst); - static void lbzux(UGeckoInstruction _inst); - static void lbzx(UGeckoInstruction _inst); - static void lfdux(UGeckoInstruction _inst); - static void lfdx(UGeckoInstruction _inst); - static void lfsux(UGeckoInstruction _inst); - static void lfsx(UGeckoInstruction _inst); - static void lhaux(UGeckoInstruction _inst); - static void lhax(UGeckoInstruction _inst); - static void lhbrx(UGeckoInstruction _inst); - static void lhzux(UGeckoInstruction _inst); - static void lhzx(UGeckoInstruction _inst); - static void lswi(UGeckoInstruction _inst); - static void lswx(UGeckoInstruction _inst); - static void lwarx(UGeckoInstruction _inst); - static void lwbrx(UGeckoInstruction _inst); - static void lwzux(UGeckoInstruction _inst); - static void lwzx(UGeckoInstruction _inst); - static void stbux(UGeckoInstruction _inst); - static void stbx(UGeckoInstruction _inst); - static void stfdux(UGeckoInstruction _inst); - static void stfdx(UGeckoInstruction _inst); - static void stfiwx(UGeckoInstruction _inst); - static void stfsux(UGeckoInstruction _inst); - static void stfsx(UGeckoInstruction _inst); - static void sthbrx(UGeckoInstruction _inst); - static void sthux(UGeckoInstruction _inst); - static void sthx(UGeckoInstruction _inst); - static void stswi(UGeckoInstruction _inst); - static void stswx(UGeckoInstruction _inst); - static void stwbrx(UGeckoInstruction _inst); - static void stwcxd(UGeckoInstruction _inst); - static void stwux(UGeckoInstruction _inst); - static void stwx(UGeckoInstruction _inst); - static void tlbie(UGeckoInstruction _inst); - static void tlbsync(UGeckoInstruction _inst); + // Load/Store Instructions + static void lbz(UGeckoInstruction _inst); + static void lbzu(UGeckoInstruction _inst); + static void lfd(UGeckoInstruction _inst); + static void lfdu(UGeckoInstruction _inst); + static void lfs(UGeckoInstruction _inst); + static void lfsu(UGeckoInstruction _inst); + static void lha(UGeckoInstruction _inst); + static void lhau(UGeckoInstruction _inst); + static void lhz(UGeckoInstruction _inst); + static void lhzu(UGeckoInstruction _inst); + static void lmw(UGeckoInstruction _inst); + static void lwz(UGeckoInstruction _inst); + static void lwzu(UGeckoInstruction _inst); + static void stb(UGeckoInstruction _inst); + static void stbu(UGeckoInstruction _inst); + static void stfd(UGeckoInstruction _inst); + static void stfdu(UGeckoInstruction _inst); + static void stfs(UGeckoInstruction _inst); + static void stfsu(UGeckoInstruction _inst); + static void sth(UGeckoInstruction _inst); + static void sthu(UGeckoInstruction _inst); + static void stmw(UGeckoInstruction _inst); + static void stw(UGeckoInstruction _inst); + static void stwu(UGeckoInstruction _inst); + static void dcba(UGeckoInstruction _inst); + static void dcbf(UGeckoInstruction _inst); + static void dcbi(UGeckoInstruction _inst); + static void dcbst(UGeckoInstruction _inst); + static void dcbt(UGeckoInstruction _inst); + static void dcbtst(UGeckoInstruction _inst); + static void dcbz(UGeckoInstruction _inst); + static void eciwx(UGeckoInstruction _inst); + static void ecowx(UGeckoInstruction _inst); + static void eieio(UGeckoInstruction _inst); + static void icbi(UGeckoInstruction _inst); + static void lbzux(UGeckoInstruction _inst); + static void lbzx(UGeckoInstruction _inst); + static void lfdux(UGeckoInstruction _inst); + static void lfdx(UGeckoInstruction _inst); + static void lfsux(UGeckoInstruction _inst); + static void lfsx(UGeckoInstruction _inst); + static void lhaux(UGeckoInstruction _inst); + static void lhax(UGeckoInstruction _inst); + static void lhbrx(UGeckoInstruction _inst); + static void lhzux(UGeckoInstruction _inst); + static void lhzx(UGeckoInstruction _inst); + static void lswi(UGeckoInstruction _inst); + static void lswx(UGeckoInstruction _inst); + static void lwarx(UGeckoInstruction _inst); + static void lwbrx(UGeckoInstruction _inst); + static void lwzux(UGeckoInstruction _inst); + static void lwzx(UGeckoInstruction _inst); + static void stbux(UGeckoInstruction _inst); + static void stbx(UGeckoInstruction _inst); + static void stfdux(UGeckoInstruction _inst); + static void stfdx(UGeckoInstruction _inst); + static void stfiwx(UGeckoInstruction _inst); + static void stfsux(UGeckoInstruction _inst); + static void stfsx(UGeckoInstruction _inst); + static void sthbrx(UGeckoInstruction _inst); + static void sthux(UGeckoInstruction _inst); + static void sthx(UGeckoInstruction _inst); + static void stswi(UGeckoInstruction _inst); + static void stswx(UGeckoInstruction _inst); + static void stwbrx(UGeckoInstruction _inst); + static void stwcxd(UGeckoInstruction _inst); + static void stwux(UGeckoInstruction _inst); + static void stwx(UGeckoInstruction _inst); + static void tlbie(UGeckoInstruction _inst); + static void tlbsync(UGeckoInstruction _inst); - // Paired Instructions - static void psq_l(UGeckoInstruction _inst); - static void psq_lu(UGeckoInstruction _inst); - static void psq_st(UGeckoInstruction _inst); - static void psq_stu(UGeckoInstruction _inst); - static void psq_lx(UGeckoInstruction _inst); - static void psq_stx(UGeckoInstruction _inst); - static void psq_lux(UGeckoInstruction _inst); - static void psq_stux(UGeckoInstruction _inst); - static void ps_div(UGeckoInstruction _inst); - static void ps_sub(UGeckoInstruction _inst); - static void ps_add(UGeckoInstruction _inst); - static void ps_sel(UGeckoInstruction _inst); - static void ps_res(UGeckoInstruction _inst); - static void ps_mul(UGeckoInstruction _inst); - static void ps_rsqrte(UGeckoInstruction _inst); - static void ps_msub(UGeckoInstruction _inst); - static void ps_madd(UGeckoInstruction _inst); - static void ps_nmsub(UGeckoInstruction _inst); - static void ps_nmadd(UGeckoInstruction _inst); - static void ps_neg(UGeckoInstruction _inst); - static void ps_mr(UGeckoInstruction _inst); - static void ps_nabs(UGeckoInstruction _inst); - static void ps_abs(UGeckoInstruction _inst); - static void ps_sum0(UGeckoInstruction _inst); - static void ps_sum1(UGeckoInstruction _inst); - static void ps_muls0(UGeckoInstruction _inst); - static void ps_muls1(UGeckoInstruction _inst); - static void ps_madds0(UGeckoInstruction _inst); - static void ps_madds1(UGeckoInstruction _inst); - static void ps_cmpu0(UGeckoInstruction _inst); - static void ps_cmpo0(UGeckoInstruction _inst); - static void ps_cmpu1(UGeckoInstruction _inst); - static void ps_cmpo1(UGeckoInstruction _inst); - static void ps_merge00(UGeckoInstruction _inst); - static void ps_merge01(UGeckoInstruction _inst); - static void ps_merge10(UGeckoInstruction _inst); - static void ps_merge11(UGeckoInstruction _inst); - static void dcbz_l(UGeckoInstruction _inst); + // Paired Instructions + static void psq_l(UGeckoInstruction _inst); + static void psq_lu(UGeckoInstruction _inst); + static void psq_st(UGeckoInstruction _inst); + static void psq_stu(UGeckoInstruction _inst); + static void psq_lx(UGeckoInstruction _inst); + static void psq_stx(UGeckoInstruction _inst); + static void psq_lux(UGeckoInstruction _inst); + static void psq_stux(UGeckoInstruction _inst); + static void ps_div(UGeckoInstruction _inst); + static void ps_sub(UGeckoInstruction _inst); + static void ps_add(UGeckoInstruction _inst); + static void ps_sel(UGeckoInstruction _inst); + static void ps_res(UGeckoInstruction _inst); + static void ps_mul(UGeckoInstruction _inst); + static void ps_rsqrte(UGeckoInstruction _inst); + static void ps_msub(UGeckoInstruction _inst); + static void ps_madd(UGeckoInstruction _inst); + static void ps_nmsub(UGeckoInstruction _inst); + static void ps_nmadd(UGeckoInstruction _inst); + static void ps_neg(UGeckoInstruction _inst); + static void ps_mr(UGeckoInstruction _inst); + static void ps_nabs(UGeckoInstruction _inst); + static void ps_abs(UGeckoInstruction _inst); + static void ps_sum0(UGeckoInstruction _inst); + static void ps_sum1(UGeckoInstruction _inst); + static void ps_muls0(UGeckoInstruction _inst); + static void ps_muls1(UGeckoInstruction _inst); + static void ps_madds0(UGeckoInstruction _inst); + static void ps_madds1(UGeckoInstruction _inst); + static void ps_cmpu0(UGeckoInstruction _inst); + static void ps_cmpo0(UGeckoInstruction _inst); + static void ps_cmpu1(UGeckoInstruction _inst); + static void ps_cmpo1(UGeckoInstruction _inst); + static void ps_merge00(UGeckoInstruction _inst); + static void ps_merge01(UGeckoInstruction _inst); + static void ps_merge10(UGeckoInstruction _inst); + static void ps_merge11(UGeckoInstruction _inst); + static void dcbz_l(UGeckoInstruction _inst); - // System Registers Instructions - static void mcrfs(UGeckoInstruction _inst); - static void mffsx(UGeckoInstruction _inst); - static void mtfsb0x(UGeckoInstruction _inst); - static void mtfsb1x(UGeckoInstruction _inst); - static void mtfsfix(UGeckoInstruction _inst); - static void mtfsfx(UGeckoInstruction _inst); - static void mcrxr(UGeckoInstruction _inst); - static void mfcr(UGeckoInstruction _inst); - static void mfmsr(UGeckoInstruction _inst); - static void mfsr(UGeckoInstruction _inst); - static void mfsrin(UGeckoInstruction _inst); - static void mtmsr(UGeckoInstruction _inst); - static void mtsr(UGeckoInstruction _inst); - static void mtsrin(UGeckoInstruction _inst); - static void mfspr(UGeckoInstruction _inst); - static void mftb(UGeckoInstruction _inst); - static void mtcrf(UGeckoInstruction _inst); - static void mtspr(UGeckoInstruction _inst); - static void crand(UGeckoInstruction _inst); - static void crandc(UGeckoInstruction _inst); - static void creqv(UGeckoInstruction _inst); - static void crnand(UGeckoInstruction _inst); - static void crnor(UGeckoInstruction _inst); - static void cror(UGeckoInstruction _inst); - static void crorc(UGeckoInstruction _inst); - static void crxor(UGeckoInstruction _inst); - static void mcrf(UGeckoInstruction _inst); - static void rfi(UGeckoInstruction _inst); - static void sync(UGeckoInstruction _inst); - static void isync(UGeckoInstruction _inst); + // System Registers Instructions + static void mcrfs(UGeckoInstruction _inst); + static void mffsx(UGeckoInstruction _inst); + static void mtfsb0x(UGeckoInstruction _inst); + static void mtfsb1x(UGeckoInstruction _inst); + static void mtfsfix(UGeckoInstruction _inst); + static void mtfsfx(UGeckoInstruction _inst); + static void mcrxr(UGeckoInstruction _inst); + static void mfcr(UGeckoInstruction _inst); + static void mfmsr(UGeckoInstruction _inst); + static void mfsr(UGeckoInstruction _inst); + static void mfsrin(UGeckoInstruction _inst); + static void mtmsr(UGeckoInstruction _inst); + static void mtsr(UGeckoInstruction _inst); + static void mtsrin(UGeckoInstruction _inst); + static void mfspr(UGeckoInstruction _inst); + static void mftb(UGeckoInstruction _inst); + static void mtcrf(UGeckoInstruction _inst); + static void mtspr(UGeckoInstruction _inst); + static void crand(UGeckoInstruction _inst); + static void crandc(UGeckoInstruction _inst); + static void creqv(UGeckoInstruction _inst); + static void crnand(UGeckoInstruction _inst); + static void crnor(UGeckoInstruction _inst); + static void cror(UGeckoInstruction _inst); + static void crorc(UGeckoInstruction _inst); + static void crxor(UGeckoInstruction _inst); + static void mcrf(UGeckoInstruction _inst); + static void rfi(UGeckoInstruction _inst); + static void sync(UGeckoInstruction _inst); + static void isync(UGeckoInstruction _inst); - using Instruction = void (*)(UGeckoInstruction instCode); - static Instruction m_opTable[64]; - static Instruction m_opTable4[1024]; - static Instruction m_opTable19[1024]; - static Instruction m_opTable31[1024]; - static Instruction m_opTable59[32]; - static Instruction m_opTable63[1024]; + using Instruction = void (*)(UGeckoInstruction instCode); + static Instruction m_opTable[64]; + static Instruction m_opTable4[1024]; + static Instruction m_opTable19[1024]; + static Instruction m_opTable31[1024]; + static Instruction m_opTable59[32]; + static Instruction m_opTable63[1024]; - // singleton - static Interpreter* getInstance(); + // singleton + static Interpreter* getInstance(); - static void RunTable4(UGeckoInstruction _instCode); - static void RunTable19(UGeckoInstruction _instCode); - static void RunTable31(UGeckoInstruction _instCode); - static void RunTable59(UGeckoInstruction _instCode); - static void RunTable63(UGeckoInstruction _instCode); + static void RunTable4(UGeckoInstruction _instCode); + static void RunTable19(UGeckoInstruction _instCode); + static void RunTable31(UGeckoInstruction _instCode); + static void RunTable59(UGeckoInstruction _instCode); + static void RunTable63(UGeckoInstruction _instCode); - static u32 Helper_Carry(u32 _uValue1, u32 _uValue2); + static u32 Helper_Carry(u32 _uValue1, u32 _uValue2); private: - // flag helper - static void Helper_UpdateCR0(u32 _uValue); - static void Helper_UpdateCR1(); - static void Helper_UpdateCRx(int _x, u32 _uValue); + // flag helper + static void Helper_UpdateCR0(u32 _uValue); + static void Helper_UpdateCR1(); + static void Helper_UpdateCRx(int _x, u32 _uValue); - // address helper - static u32 Helper_Get_EA (const UGeckoInstruction _inst); - static u32 Helper_Get_EA_U (const UGeckoInstruction _inst); - static u32 Helper_Get_EA_X (const UGeckoInstruction _inst); - static u32 Helper_Get_EA_UX(const UGeckoInstruction _inst); + // address helper + static u32 Helper_Get_EA(const UGeckoInstruction _inst); + static u32 Helper_Get_EA_U(const UGeckoInstruction _inst); + static u32 Helper_Get_EA_X(const UGeckoInstruction _inst); + static u32 Helper_Get_EA_UX(const UGeckoInstruction _inst); - // paired helper - static void Helper_Dequantize(u32 addr, u32 instI, u32 instRD, u32 instW); - static void Helper_Quantize(u32 addr, u32 instI, u32 instRS, u32 instW); + // paired helper + static void Helper_Dequantize(u32 addr, u32 instI, u32 instRD, u32 instW); + static void Helper_Quantize(u32 addr, u32 instI, u32 instRS, u32 instW); - // other helper - static u32 Helper_Mask(int mb, int me); + // other helper + static u32 Helper_Mask(int mb, int me); - static void Helper_FloatCompareOrdered(UGeckoInstruction _inst, double a, double b); - static void Helper_FloatCompareUnordered(UGeckoInstruction _inst, double a, double b); + static void Helper_FloatCompareOrdered(UGeckoInstruction _inst, double a, double b); + static void Helper_FloatCompareUnordered(UGeckoInstruction _inst, double a, double b); - // TODO: These should really be in the save state, although it's unlikely to matter much. - // They are for lwarx and its friend stwcxd. - static bool g_bReserve; - static u32 g_reserveAddr; + // TODO: These should really be in the save state, although it's unlikely to matter much. + // They are for lwarx and its friend stwcxd. + static bool g_bReserve; + static u32 g_reserveAddr; }; diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp index 68ef28b1a5..93530f0c80 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp @@ -2,138 +2,142 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/Interpreter/Interpreter.h" #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Core/ConfigManager.h" #include "Core/CoreTiming.h" #include "Core/HLE/HLE.h" #include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/Interpreter/Interpreter.h" void Interpreter::bx(UGeckoInstruction _inst) { - if (_inst.LK) - LR = PC + 4; + if (_inst.LK) + LR = PC + 4; - if (_inst.AA) - NPC = SignExt26(_inst.LI << 2); - else - NPC = PC+SignExt26(_inst.LI << 2); + if (_inst.AA) + NPC = SignExt26(_inst.LI << 2); + else + NPC = PC + SignExt26(_inst.LI << 2); - m_EndBlock = true; + m_EndBlock = true; - if (NPC == PC && SConfig::GetInstance().bSkipIdle) - { - CoreTiming::Idle(); - } + if (NPC == PC && SConfig::GetInstance().bSkipIdle) + { + CoreTiming::Idle(); + } } // bcx - ugly, straight from PPC manual equations :) void Interpreter::bcx(UGeckoInstruction _inst) { - if ((_inst.BO & BO_DONT_DECREMENT_FLAG) == 0) - CTR--; + if ((_inst.BO & BO_DONT_DECREMENT_FLAG) == 0) + CTR--; - const bool true_false = ((_inst.BO >> 3) & 1); - const bool only_counter_check = ((_inst.BO >> 4) & 1); - const bool only_condition_check = ((_inst.BO >> 2) & 1); - int ctr_check = ((CTR != 0) ^ (_inst.BO >> 1)) & 1; - bool counter = only_condition_check || ctr_check; - bool condition = only_counter_check || (GetCRBit(_inst.BI) == u32(true_false)); + const bool true_false = ((_inst.BO >> 3) & 1); + const bool only_counter_check = ((_inst.BO >> 4) & 1); + const bool only_condition_check = ((_inst.BO >> 2) & 1); + int ctr_check = ((CTR != 0) ^ (_inst.BO >> 1)) & 1; + bool counter = only_condition_check || ctr_check; + bool condition = only_counter_check || (GetCRBit(_inst.BI) == u32(true_false)); - if (counter && condition) - { - if (_inst.LK) - LR = PC + 4; + if (counter && condition) + { + if (_inst.LK) + LR = PC + 4; - if (_inst.AA) - NPC = SignExt16(_inst.BD << 2); - else - NPC = PC + SignExt16(_inst.BD << 2); - } + if (_inst.AA) + NPC = SignExt16(_inst.BD << 2); + else + NPC = PC + SignExt16(_inst.BD << 2); + } - m_EndBlock = true; + m_EndBlock = true; - // this code trys to detect the most common idle loop: - // lwz r0, XXXX(r13) - // cmpXwi r0,0 - // beq -8 - if (NPC == PC - 8 && _inst.hex == 0x4182fff8 /* beq */ && SConfig::GetInstance().bSkipIdle) - { - if (PowerPC::HostRead_U32(PC - 8) >> 16 == 0x800D /* lwz */ ) - { - u32 last_inst = PowerPC::HostRead_U32(PC - 4); + // this code trys to detect the most common idle loop: + // lwz r0, XXXX(r13) + // cmpXwi r0,0 + // beq -8 + if (NPC == PC - 8 && _inst.hex == 0x4182fff8 /* beq */ && SConfig::GetInstance().bSkipIdle) + { + if (PowerPC::HostRead_U32(PC - 8) >> 16 == 0x800D /* lwz */) + { + u32 last_inst = PowerPC::HostRead_U32(PC - 4); - if (last_inst == 0x28000000 /* cmplwi */ || (last_inst == 0x2C000000 /* cmpwi */ && SConfig::GetInstance().bWii)) - { - CoreTiming::Idle(); - } - } - } + if (last_inst == 0x28000000 /* cmplwi */ || + (last_inst == 0x2C000000 /* cmpwi */ && SConfig::GetInstance().bWii)) + { + CoreTiming::Idle(); + } + } + } } void Interpreter::bcctrx(UGeckoInstruction _inst) { - _dbg_assert_msg_(POWERPC, _inst.BO_2 & BO_DONT_DECREMENT_FLAG, "bcctrx with decrement and test CTR option is invalid!"); + _dbg_assert_msg_(POWERPC, _inst.BO_2 & BO_DONT_DECREMENT_FLAG, + "bcctrx with decrement and test CTR option is invalid!"); - int condition = ((_inst.BO_2>>4) | (GetCRBit(_inst.BI_2) == ((_inst.BO_2>>3) & 1))) & 1; + int condition = ((_inst.BO_2 >> 4) | (GetCRBit(_inst.BI_2) == ((_inst.BO_2 >> 3) & 1))) & 1; - if (condition) - { - NPC = CTR & (~3); - if (_inst.LK_3) - LR = PC + 4; - } + if (condition) + { + NPC = CTR & (~3); + if (_inst.LK_3) + LR = PC + 4; + } - m_EndBlock = true; + m_EndBlock = true; } void Interpreter::bclrx(UGeckoInstruction _inst) { - if ((_inst.BO_2 & BO_DONT_DECREMENT_FLAG) == 0) - CTR--; + if ((_inst.BO_2 & BO_DONT_DECREMENT_FLAG) == 0) + CTR--; - int counter = ((_inst.BO_2 >> 2) | ((CTR != 0) ^ (_inst.BO_2 >> 1))) & 1; - int condition = ((_inst.BO_2 >> 4) | (GetCRBit(_inst.BI_2) == ((_inst.BO_2 >> 3) & 1))) & 1; + int counter = ((_inst.BO_2 >> 2) | ((CTR != 0) ^ (_inst.BO_2 >> 1))) & 1; + int condition = ((_inst.BO_2 >> 4) | (GetCRBit(_inst.BI_2) == ((_inst.BO_2 >> 3) & 1))) & 1; - if (counter & condition) - { - NPC = LR & (~3); - if (_inst.LK_3) - LR = PC + 4; - } + if (counter & condition) + { + NPC = LR & (~3); + if (_inst.LK_3) + LR = PC + 4; + } - m_EndBlock = true; + m_EndBlock = true; } void Interpreter::HLEFunction(UGeckoInstruction _inst) { - m_EndBlock = true; - HLE::Execute(PC, _inst.hex); + m_EndBlock = true; + HLE::Execute(PC, _inst.hex); } void Interpreter::rfi(UGeckoInstruction _inst) { - // Restore saved bits from SRR1 to MSR. - // Gecko/Broadway can save more bits than explicitly defined in ppc spec - const int mask = 0x87C0FFFF; - MSR = (MSR & ~mask) | (SRR1 & mask); - //MSR[13] is set to 0. - MSR &= 0xFFFBFFFF; - // Here we should check if there are pending exceptions, and if their corresponding enable bits are set - // if above is true, we'd do: - //PowerPC::CheckExceptions(); - //else - // set NPC to saved offset and resume - NPC = SRR0; - m_EndBlock = true; + // Restore saved bits from SRR1 to MSR. + // Gecko/Broadway can save more bits than explicitly defined in ppc spec + const int mask = 0x87C0FFFF; + MSR = (MSR & ~mask) | (SRR1 & mask); + // MSR[13] is set to 0. + MSR &= 0xFFFBFFFF; + // Here we should check if there are pending exceptions, and if their corresponding enable bits + // are set + // if above is true, we'd do: + // PowerPC::CheckExceptions(); + // else + // set NPC to saved offset and resume + NPC = SRR0; + m_EndBlock = true; } -// sc isn't really used for anything important in GameCube games (just for a write barrier) so we really don't have to emulate it. +// sc isn't really used for anything important in GameCube games (just for a write barrier) so we +// really don't have to emulate it. // We do it anyway, though :P void Interpreter::sc(UGeckoInstruction _inst) { - PowerPC::ppcState.Exceptions |= EXCEPTION_SYSCALL; - PowerPC::CheckExceptions(); - m_EndBlock = true; + PowerPC::ppcState.Exceptions |= EXCEPTION_SYSCALL; + PowerPC::CheckExceptions(); + m_EndBlock = true; } diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h index 302d00540f..bff677cb46 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h @@ -7,81 +7,81 @@ #include #include -#include "Common/CommonTypes.h" #include "Common/CPUDetect.h" +#include "Common/CommonTypes.h" #include "Common/MathUtil.h" #include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/PowerPC.h" const u64 PPC_NAN_U64 = 0x7ff8000000000000ull; -const double PPC_NAN = *(double* const)&PPC_NAN_U64; +const double PPC_NAN = *(double* const) & PPC_NAN_U64; // the 4 less-significand bits in FPSCR[FPRF] enum FPCC { - FL = 8, // < - FG = 4, // > - FE = 2, // = - FU = 1, // ? + FL = 8, // < + FG = 4, // > + FE = 2, // = + FU = 1, // ? }; inline void SetFPException(u32 mask) { - if ((FPSCR.Hex & mask) != mask) - { - FPSCR.FX = 1; - } - FPSCR.Hex |= mask; + if ((FPSCR.Hex & mask) != mask) + { + FPSCR.FX = 1; + } + FPSCR.Hex |= mask; } inline void SetFI(int FI) { - if (FI) - { - SetFPException(FPSCR_XX); - } - FPSCR.FI = FI; + if (FI) + { + SetFPException(FPSCR_XX); + } + FPSCR.FI = FI; } inline void UpdateFPSCR() { - FPSCR.VX = (FPSCR.Hex & FPSCR_VX_ANY) != 0; - FPSCR.FEX = 0; // we assume that "?E" bits are always 0 + FPSCR.VX = (FPSCR.Hex & FPSCR_VX_ANY) != 0; + FPSCR.FEX = 0; // we assume that "?E" bits are always 0 } inline double ForceSingle(double _x) { - // convert to float... - float x = (float) _x; - if (!cpu_info.bFlushToZero && FPSCR.NI) - { - x = MathUtil::FlushToZero(x); - } - // ...and back to double: - return x; + // convert to float... + float x = (float)_x; + if (!cpu_info.bFlushToZero && FPSCR.NI) + { + x = MathUtil::FlushToZero(x); + } + // ...and back to double: + return x; } inline double ForceDouble(double d) { - if (!cpu_info.bFlushToZero && FPSCR.NI) - { - d = MathUtil::FlushToZero(d); - } - return d; + if (!cpu_info.bFlushToZero && FPSCR.NI) + { + d = MathUtil::FlushToZero(d); + } + return d; } inline double Force25Bit(double d) { - MathUtil::IntDouble x(d); - x.i = (x.i & 0xFFFFFFFFF8000000ULL) + (x.i & 0x8000000); - return x.d; + MathUtil::IntDouble x(d); + x.i = (x.i & 0xFFFFFFFFF8000000ULL) + (x.i & 0x8000000); + return x.d; } inline double MakeQuiet(double d) { - MathUtil::IntDouble x(d); - x.i |= MathUtil::DOUBLE_QBIT; - return x.d; + MathUtil::IntDouble x(d); + x.i |= MathUtil::DOUBLE_QBIT; + return x.d; } // these functions allow globally modify operations behaviour @@ -89,63 +89,71 @@ inline double MakeQuiet(double d) inline double NI_mul(double a, double b) { - double t = a * b; - if (std::isnan(t)) - { - if (std::isnan(a)) return MakeQuiet(a); - if (std::isnan(b)) return MakeQuiet(b); - SetFPException(FPSCR_VXIMZ); - return PPC_NAN; - } - return t; + double t = a * b; + if (std::isnan(t)) + { + if (std::isnan(a)) + return MakeQuiet(a); + if (std::isnan(b)) + return MakeQuiet(b); + SetFPException(FPSCR_VXIMZ); + return PPC_NAN; + } + return t; } inline double NI_div(double a, double b) { - double t = a / b; - if (std::isnan(t)) - { - if (std::isnan(a)) return MakeQuiet(a); - if (std::isnan(b)) return MakeQuiet(b); - if (b == 0.0) - { - SetFPException(FPSCR_ZX); - if (a == 0.0) - SetFPException(FPSCR_VXZDZ); - } - else if (std::isinf(a) && std::isinf(b)) - { - SetFPException(FPSCR_VXIDI); - } - return PPC_NAN; - } - return t; + double t = a / b; + if (std::isnan(t)) + { + if (std::isnan(a)) + return MakeQuiet(a); + if (std::isnan(b)) + return MakeQuiet(b); + if (b == 0.0) + { + SetFPException(FPSCR_ZX); + if (a == 0.0) + SetFPException(FPSCR_VXZDZ); + } + else if (std::isinf(a) && std::isinf(b)) + { + SetFPException(FPSCR_VXIDI); + } + return PPC_NAN; + } + return t; } inline double NI_add(double a, double b) { - double t = a + b; - if (std::isnan(t)) - { - if (std::isnan(a)) return MakeQuiet(a); - if (std::isnan(b)) return MakeQuiet(b); - SetFPException(FPSCR_VXISI); - return PPC_NAN; - } - return t; + double t = a + b; + if (std::isnan(t)) + { + if (std::isnan(a)) + return MakeQuiet(a); + if (std::isnan(b)) + return MakeQuiet(b); + SetFPException(FPSCR_VXISI); + return PPC_NAN; + } + return t; } inline double NI_sub(double a, double b) { - double t = a - b; - if (std::isnan(t)) - { - if (std::isnan(a)) return MakeQuiet(a); - if (std::isnan(b)) return MakeQuiet(b); - SetFPException(FPSCR_VXISI); - return PPC_NAN; - } - return t; + double t = a - b; + if (std::isnan(t)) + { + if (std::isnan(a)) + return MakeQuiet(a); + if (std::isnan(b)) + return MakeQuiet(b); + SetFPException(FPSCR_VXISI); + return PPC_NAN; + } + return t; } // FMA instructions on PowerPC are weird: @@ -153,117 +161,124 @@ inline double NI_sub(double a, double b) // inputs are checked for NaN is still a, b, c. inline double NI_madd(double a, double c, double b) { - double t = a * c; - if (std::isnan(t)) - { - if (std::isnan(a)) return MakeQuiet(a); - if (std::isnan(b)) return MakeQuiet(b); // ! - if (std::isnan(c)) return MakeQuiet(c); - SetFPException(FPSCR_VXIMZ); - return PPC_NAN; - } - t += b; - if (std::isnan(t)) - { - if (std::isnan(b)) return MakeQuiet(b); - SetFPException(FPSCR_VXISI); - return PPC_NAN; - } - return t; + double t = a * c; + if (std::isnan(t)) + { + if (std::isnan(a)) + return MakeQuiet(a); + if (std::isnan(b)) + return MakeQuiet(b); // ! + if (std::isnan(c)) + return MakeQuiet(c); + SetFPException(FPSCR_VXIMZ); + return PPC_NAN; + } + t += b; + if (std::isnan(t)) + { + if (std::isnan(b)) + return MakeQuiet(b); + SetFPException(FPSCR_VXISI); + return PPC_NAN; + } + return t; } inline double NI_msub(double a, double c, double b) { - double t = a * c; - if (std::isnan(t)) - { - if (std::isnan(a)) return MakeQuiet(a); - if (std::isnan(b)) return MakeQuiet(b); // ! - if (std::isnan(c)) return MakeQuiet(c); - SetFPException(FPSCR_VXIMZ); - return PPC_NAN; - } + double t = a * c; + if (std::isnan(t)) + { + if (std::isnan(a)) + return MakeQuiet(a); + if (std::isnan(b)) + return MakeQuiet(b); // ! + if (std::isnan(c)) + return MakeQuiet(c); + SetFPException(FPSCR_VXIMZ); + return PPC_NAN; + } - t -= b; - if (std::isnan(t)) - { - if (std::isnan(b)) return MakeQuiet(b); - SetFPException(FPSCR_VXISI); - return PPC_NAN; - } - return t; + t -= b; + if (std::isnan(t)) + { + if (std::isnan(b)) + return MakeQuiet(b); + SetFPException(FPSCR_VXISI); + return PPC_NAN; + } + return t; } // used by stfsXX instructions and ps_rsqrte inline u32 ConvertToSingle(u64 x) { - u32 exp = (x >> 52) & 0x7ff; - if (exp > 896 || (x & ~MathUtil::DOUBLE_SIGN) == 0) - { - return ((x >> 32) & 0xc0000000) | ((x >> 29) & 0x3fffffff); - } - else if (exp >= 874) - { - u32 t = (u32)(0x80000000 | ((x & MathUtil::DOUBLE_FRAC) >> 21)); - t = t >> (905 - exp); - t |= (x >> 32) & 0x80000000; - return t; - } - else - { - // This is said to be undefined. - // The code is based on hardware tests. - return ((x >> 32) & 0xc0000000) | ((x >> 29) & 0x3fffffff); - } + u32 exp = (x >> 52) & 0x7ff; + if (exp > 896 || (x & ~MathUtil::DOUBLE_SIGN) == 0) + { + return ((x >> 32) & 0xc0000000) | ((x >> 29) & 0x3fffffff); + } + else if (exp >= 874) + { + u32 t = (u32)(0x80000000 | ((x & MathUtil::DOUBLE_FRAC) >> 21)); + t = t >> (905 - exp); + t |= (x >> 32) & 0x80000000; + return t; + } + else + { + // This is said to be undefined. + // The code is based on hardware tests. + return ((x >> 32) & 0xc0000000) | ((x >> 29) & 0x3fffffff); + } } // used by psq_stXX operations. inline u32 ConvertToSingleFTZ(u64 x) { - u32 exp = (x >> 52) & 0x7ff; - if (exp > 896 || (x & ~MathUtil::DOUBLE_SIGN) == 0) - { - return ((x >> 32) & 0xc0000000) | ((x >> 29) & 0x3fffffff); - } - else - { - return (x >> 32) & 0x80000000; - } + u32 exp = (x >> 52) & 0x7ff; + if (exp > 896 || (x & ~MathUtil::DOUBLE_SIGN) == 0) + { + return ((x >> 32) & 0xc0000000) | ((x >> 29) & 0x3fffffff); + } + else + { + return (x >> 32) & 0x80000000; + } } inline u64 ConvertToDouble(u32 _x) { - // This is a little-endian re-implementation of the algorithm described in - // the PowerPC Programming Environments Manual for loading single - // precision floating point numbers. - // See page 566 of http://www.freescale.com/files/product/doc/MPCFPE32B.pdf + // This is a little-endian re-implementation of the algorithm described in + // the PowerPC Programming Environments Manual for loading single + // precision floating point numbers. + // See page 566 of http://www.freescale.com/files/product/doc/MPCFPE32B.pdf - u64 x = _x; - u64 exp = (x >> 23) & 0xff; - u64 frac = x & 0x007fffff; + u64 x = _x; + u64 exp = (x >> 23) & 0xff; + u64 frac = x & 0x007fffff; - if (exp > 0 && exp < 255) // Normal number - { - u64 y = !(exp >> 7); - u64 z = y << 61 | y << 60 | y << 59; - return ((x & 0xc0000000) << 32) | z | ((x & 0x3fffffff) << 29); - } - else if (exp == 0 && frac != 0) // Subnormal number - { - exp = 1023 - 126; - do - { - frac <<= 1; - exp -= 1; - } while ((frac & 0x00800000) == 0); + if (exp > 0 && exp < 255) // Normal number + { + u64 y = !(exp >> 7); + u64 z = y << 61 | y << 60 | y << 59; + return ((x & 0xc0000000) << 32) | z | ((x & 0x3fffffff) << 29); + } + else if (exp == 0 && frac != 0) // Subnormal number + { + exp = 1023 - 126; + do + { + frac <<= 1; + exp -= 1; + } while ((frac & 0x00800000) == 0); - return ((x & 0x80000000) << 32) | (exp << 52) | ((frac & 0x007fffff) << 29); - } - else // QNaN, SNaN or Zero - { - u64 y = exp >> 7; - u64 z = y << 61 | y << 60 | y << 59; - return ((x & 0xc0000000) << 32) | z | ((x & 0x3fffffff) << 29); - } + return ((x & 0x80000000) << 32) | (exp << 52) | ((frac & 0x007fffff) << 29); + } + else // QNaN, SNaN or Zero + { + u64 y = exp >> 7; + u64 z = y << 61 | y << 60 | y << 59; + return ((x & 0xc0000000) << 32) | z | ((x & 0x3fffffff) << 29); + } } - diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp index 404599d718..457d5b3a4d 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp @@ -7,9 +7,9 @@ #include "Common/CommonTypes.h" #include "Common/MathUtil.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/Interpreter/Interpreter.h" #include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h" +#include "Core/PowerPC/PowerPC.h" using namespace MathUtil; @@ -17,256 +17,256 @@ using namespace MathUtil; // Star Wars : Rogue Leader spams that at some point :| void Interpreter::Helper_UpdateCR1() { - SetCRField(1, (FPSCR.FX << 3) | (FPSCR.FEX << 2) | (FPSCR.VX << 1) | FPSCR.OX); + SetCRField(1, (FPSCR.FX << 3) | (FPSCR.FEX << 2) | (FPSCR.VX << 1) | FPSCR.OX); } void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction _inst, double fa, double fb) { - int compareResult; + int compareResult; - if (std::isnan(fa) || std::isnan(fb)) - { - compareResult = FPCC::FU; - if (IsSNAN(fa) || IsSNAN(fb)) - { - SetFPException(FPSCR_VXSNAN); - if (FPSCR.VE == 0) - { - SetFPException(FPSCR_VXVC); - } - } - else // QNaN - { - SetFPException(FPSCR_VXVC); - } - } - else if (fa < fb) - { - compareResult = FPCC::FL; - } - else if (fa > fb) - { - compareResult = FPCC::FG; - } - else // Equals - { - compareResult = FPCC::FE; - } + if (std::isnan(fa) || std::isnan(fb)) + { + compareResult = FPCC::FU; + if (IsSNAN(fa) || IsSNAN(fb)) + { + SetFPException(FPSCR_VXSNAN); + if (FPSCR.VE == 0) + { + SetFPException(FPSCR_VXVC); + } + } + else // QNaN + { + SetFPException(FPSCR_VXVC); + } + } + else if (fa < fb) + { + compareResult = FPCC::FL; + } + else if (fa > fb) + { + compareResult = FPCC::FG; + } + else // Equals + { + compareResult = FPCC::FE; + } - // Clear and set the FPCC bits accordingly. - FPSCR.FPRF = (FPSCR.FPRF & ~0xF) | compareResult; + // Clear and set the FPCC bits accordingly. + FPSCR.FPRF = (FPSCR.FPRF & ~0xF) | compareResult; - SetCRField(_inst.CRFD, compareResult); + SetCRField(_inst.CRFD, compareResult); } void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction _inst, double fa, double fb) { - int compareResult; + int compareResult; - if (std::isnan(fa) || std::isnan(fb)) - { - compareResult = FPCC::FU; + if (std::isnan(fa) || std::isnan(fb)) + { + compareResult = FPCC::FU; - if (IsSNAN(fa) || IsSNAN(fb)) - { - SetFPException(FPSCR_VXSNAN); - } - } - else if (fa < fb) - { - compareResult = FPCC::FL; - } - else if (fa > fb) - { - compareResult = FPCC::FG; - } - else // Equals - { - compareResult = FPCC::FE; - } + if (IsSNAN(fa) || IsSNAN(fb)) + { + SetFPException(FPSCR_VXSNAN); + } + } + else if (fa < fb) + { + compareResult = FPCC::FL; + } + else if (fa > fb) + { + compareResult = FPCC::FG; + } + else // Equals + { + compareResult = FPCC::FE; + } - // Clear and set the FPCC bits accordingly. - FPSCR.FPRF = (FPSCR.FPRF & ~0xF) | compareResult; + // Clear and set the FPCC bits accordingly. + FPSCR.FPRF = (FPSCR.FPRF & ~0xF) | compareResult; - SetCRField(_inst.CRFD, compareResult); + SetCRField(_inst.CRFD, compareResult); } void Interpreter::fcmpo(UGeckoInstruction _inst) { - Helper_FloatCompareOrdered(_inst, rPS0(_inst.FA), rPS0(_inst.FB)); + Helper_FloatCompareOrdered(_inst, rPS0(_inst.FA), rPS0(_inst.FB)); } void Interpreter::fcmpu(UGeckoInstruction _inst) { - Helper_FloatCompareUnordered(_inst, rPS0(_inst.FA), rPS0(_inst.FB)); + Helper_FloatCompareUnordered(_inst, rPS0(_inst.FA), rPS0(_inst.FB)); } // Apply current rounding mode void Interpreter::fctiwx(UGeckoInstruction _inst) { - const double b = rPS0(_inst.FB); - u32 value; + const double b = rPS0(_inst.FB); + u32 value; - if (b > (double)0x7fffffff) - { - value = 0x7fffffff; - SetFPException(FPSCR_VXCVI); - FPSCR.FI = 0; - FPSCR.FR = 0; - } - else if (b < -(double)0x80000000) - { - value = 0x80000000; - SetFPException(FPSCR_VXCVI); - FPSCR.FI = 0; - FPSCR.FR = 0; - } - else - { - s32 i = 0; - switch (FPSCR.RN) - { - case 0: // nearest - { - double t = b + 0.5; - i = (s32)t; + if (b > (double)0x7fffffff) + { + value = 0x7fffffff; + SetFPException(FPSCR_VXCVI); + FPSCR.FI = 0; + FPSCR.FR = 0; + } + else if (b < -(double)0x80000000) + { + value = 0x80000000; + SetFPException(FPSCR_VXCVI); + FPSCR.FI = 0; + FPSCR.FR = 0; + } + else + { + s32 i = 0; + switch (FPSCR.RN) + { + case 0: // nearest + { + double t = b + 0.5; + i = (s32)t; - if (t - i < 0 || (t - i == 0 && b > 0)) - { - i--; - } - break; - } - case 1: // zero - i = (s32)b; - break; - case 2: // +inf - i = (s32)b; - if (b - i > 0) - { - i++; - } - break; - case 3: // -inf - i = (s32)b; - if (b - i < 0) - { - i--; - } - break; - } - value = (u32)i; - double di = i; - if (di == b) - { - FPSCR.FI = 0; - FPSCR.FR = 0; - } - else - { - SetFI(1); - FPSCR.FR = fabs(di) > fabs(b); - } - } + if (t - i < 0 || (t - i == 0 && b > 0)) + { + i--; + } + break; + } + case 1: // zero + i = (s32)b; + break; + case 2: // +inf + i = (s32)b; + if (b - i > 0) + { + i++; + } + break; + case 3: // -inf + i = (s32)b; + if (b - i < 0) + { + i--; + } + break; + } + value = (u32)i; + double di = i; + if (di == b) + { + FPSCR.FI = 0; + FPSCR.FR = 0; + } + else + { + SetFI(1); + FPSCR.FR = fabs(di) > fabs(b); + } + } - // based on HW tests - // FPRF is not affected - riPS0(_inst.FD) = 0xfff8000000000000ull | value; - if (value == 0 && std::signbit(b)) - riPS0(_inst.FD) |= 0x100000000ull; - if (_inst.Rc) - Helper_UpdateCR1(); + // based on HW tests + // FPRF is not affected + riPS0(_inst.FD) = 0xfff8000000000000ull | value; + if (value == 0 && std::signbit(b)) + riPS0(_inst.FD) |= 0x100000000ull; + if (_inst.Rc) + Helper_UpdateCR1(); } // Always round toward zero void Interpreter::fctiwzx(UGeckoInstruction _inst) { - const double b = rPS0(_inst.FB); - u32 value; + const double b = rPS0(_inst.FB); + u32 value; - if (b > (double)0x7fffffff) - { - value = 0x7fffffff; - SetFPException(FPSCR_VXCVI); - FPSCR.FI = 0; - FPSCR.FR = 0; - } - else if (b < -(double)0x80000000) - { - value = 0x80000000; - SetFPException(FPSCR_VXCVI); - FPSCR.FI = 0; - FPSCR.FR = 0; - } - else - { - s32 i = (s32)b; - double di = i; - if (di == b) - { - FPSCR.FI = 0; - FPSCR.FR = 0; - } - else - { - SetFI(1); - FPSCR.FR = fabs(di) > fabs(b); - } - value = (u32)i; - } + if (b > (double)0x7fffffff) + { + value = 0x7fffffff; + SetFPException(FPSCR_VXCVI); + FPSCR.FI = 0; + FPSCR.FR = 0; + } + else if (b < -(double)0x80000000) + { + value = 0x80000000; + SetFPException(FPSCR_VXCVI); + FPSCR.FI = 0; + FPSCR.FR = 0; + } + else + { + s32 i = (s32)b; + double di = i; + if (di == b) + { + FPSCR.FI = 0; + FPSCR.FR = 0; + } + else + { + SetFI(1); + FPSCR.FR = fabs(di) > fabs(b); + } + value = (u32)i; + } - // based on HW tests - // FPRF is not affected - riPS0(_inst.FD) = 0xfff8000000000000ull | value; - if (value == 0 && std::signbit(b)) - riPS0(_inst.FD) |= 0x100000000ull; - if (_inst.Rc) - Helper_UpdateCR1(); + // based on HW tests + // FPRF is not affected + riPS0(_inst.FD) = 0xfff8000000000000ull | value; + if (value == 0 && std::signbit(b)) + riPS0(_inst.FD) |= 0x100000000ull; + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fmrx(UGeckoInstruction _inst) { - riPS0(_inst.FD) = riPS0(_inst.FB); + riPS0(_inst.FD) = riPS0(_inst.FB); - // This is a binary instruction. Does not alter FPSCR - if (_inst.Rc) - Helper_UpdateCR1(); + // This is a binary instruction. Does not alter FPSCR + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fabsx(UGeckoInstruction _inst) { - rPS0(_inst.FD) = fabs(rPS0(_inst.FB)); + rPS0(_inst.FD) = fabs(rPS0(_inst.FB)); - // This is a binary instruction. Does not alter FPSCR - if (_inst.Rc) - Helper_UpdateCR1(); + // This is a binary instruction. Does not alter FPSCR + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fnabsx(UGeckoInstruction _inst) { - riPS0(_inst.FD) = riPS0(_inst.FB) | (1ULL << 63); + riPS0(_inst.FD) = riPS0(_inst.FB) | (1ULL << 63); - // This is a binary instruction. Does not alter FPSCR - if (_inst.Rc) - Helper_UpdateCR1(); + // This is a binary instruction. Does not alter FPSCR + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fnegx(UGeckoInstruction _inst) { - riPS0(_inst.FD) = riPS0(_inst.FB) ^ (1ULL << 63); + riPS0(_inst.FD) = riPS0(_inst.FB) ^ (1ULL << 63); - // This is a binary instruction. Does not alter FPSCR - if (_inst.Rc) - Helper_UpdateCR1(); + // This is a binary instruction. Does not alter FPSCR + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fselx(UGeckoInstruction _inst) { - rPS0(_inst.FD) = (rPS0(_inst.FA) >= -0.0) ? rPS0(_inst.FC) : rPS0(_inst.FB); + rPS0(_inst.FD) = (rPS0(_inst.FA) >= -0.0) ? rPS0(_inst.FC) : rPS0(_inst.FB); - // This is a binary instruction. Does not alter FPSCR - if (_inst.Rc) - Helper_UpdateCR1(); + // This is a binary instruction. Does not alter FPSCR + if (_inst.Rc) + Helper_UpdateCR1(); } // !!! warning !!! @@ -274,213 +274,211 @@ void Interpreter::fselx(UGeckoInstruction _inst) // PS1 is said to be undefined void Interpreter::frspx(UGeckoInstruction inst) // round to single { - double b = rPS0(inst.FB); - double rounded = ForceSingle(b); - SetFI(b != rounded); - FPSCR.FR = fabs(rounded) > fabs(b); - UpdateFPRF(rounded); - rPS0(inst.FD) = rPS1(inst.FD) = rounded; + double b = rPS0(inst.FB); + double rounded = ForceSingle(b); + SetFI(b != rounded); + FPSCR.FR = fabs(rounded) > fabs(b); + UpdateFPRF(rounded); + rPS0(inst.FD) = rPS1(inst.FD) = rounded; - if (inst.Rc) - Helper_UpdateCR1(); + if (inst.Rc) + Helper_UpdateCR1(); } - void Interpreter::fmulx(UGeckoInstruction _inst) { - rPS0(_inst.FD) = ForceDouble(NI_mul(rPS0(_inst.FA), rPS0(_inst.FC))); - FPSCR.FI = 0; // are these flags important? - FPSCR.FR = 0; - UpdateFPRF(rPS0(_inst.FD)); + rPS0(_inst.FD) = ForceDouble(NI_mul(rPS0(_inst.FA), rPS0(_inst.FC))); + FPSCR.FI = 0; // are these flags important? + FPSCR.FR = 0; + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fmulsx(UGeckoInstruction _inst) { - double c_value = Force25Bit(rPS0(_inst.FC)); - double d_value = NI_mul(rPS0(_inst.FA), c_value); - rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(d_value); - //FPSCR.FI = d_value != rPS0(_inst.FD); - FPSCR.FI = 0; - FPSCR.FR = 0; - UpdateFPRF(rPS0(_inst.FD)); + double c_value = Force25Bit(rPS0(_inst.FC)); + double d_value = NI_mul(rPS0(_inst.FA), c_value); + rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(d_value); + // FPSCR.FI = d_value != rPS0(_inst.FD); + FPSCR.FI = 0; + FPSCR.FR = 0; + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fmaddx(UGeckoInstruction _inst) { - double result = ForceDouble(NI_madd(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB))); - rPS0(_inst.FD) = result; - UpdateFPRF(result); + double result = ForceDouble(NI_madd(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB))); + rPS0(_inst.FD) = result; + UpdateFPRF(result); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fmaddsx(UGeckoInstruction _inst) { - double c_value = Force25Bit(rPS0(_inst.FC)); - double d_value = NI_madd(rPS0(_inst.FA), c_value, rPS0(_inst.FB)); - rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(d_value); - FPSCR.FI = d_value != rPS0(_inst.FD); - FPSCR.FR = 0; - UpdateFPRF(rPS0(_inst.FD)); + double c_value = Force25Bit(rPS0(_inst.FC)); + double d_value = NI_madd(rPS0(_inst.FA), c_value, rPS0(_inst.FB)); + rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(d_value); + FPSCR.FI = d_value != rPS0(_inst.FD); + FPSCR.FR = 0; + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } - void Interpreter::faddx(UGeckoInstruction _inst) { - rPS0(_inst.FD) = ForceDouble(NI_add(rPS0(_inst.FA), rPS0(_inst.FB))); - UpdateFPRF(rPS0(_inst.FD)); + rPS0(_inst.FD) = ForceDouble(NI_add(rPS0(_inst.FA), rPS0(_inst.FB))); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::faddsx(UGeckoInstruction _inst) { - rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_add(rPS0(_inst.FA), rPS0(_inst.FB))); - UpdateFPRF(rPS0(_inst.FD)); + rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_add(rPS0(_inst.FA), rPS0(_inst.FB))); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fdivx(UGeckoInstruction _inst) { - rPS0(_inst.FD) = ForceDouble(NI_div(rPS0(_inst.FA), rPS0(_inst.FB))); - UpdateFPRF(rPS0(_inst.FD)); + rPS0(_inst.FD) = ForceDouble(NI_div(rPS0(_inst.FA), rPS0(_inst.FB))); + UpdateFPRF(rPS0(_inst.FD)); - // FR,FI,OX,UX??? - if (_inst.Rc) - Helper_UpdateCR1(); + // FR,FI,OX,UX??? + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fdivsx(UGeckoInstruction _inst) { - rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_div(rPS0(_inst.FA), rPS0(_inst.FB))); - UpdateFPRF(rPS0(_inst.FD)); + rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_div(rPS0(_inst.FA), rPS0(_inst.FB))); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } // Single precision only. void Interpreter::fresx(UGeckoInstruction _inst) { - double b = rPS0(_inst.FB); - rPS0(_inst.FD) = rPS1(_inst.FD) = ApproximateReciprocal(b); + double b = rPS0(_inst.FB); + rPS0(_inst.FD) = rPS1(_inst.FD) = ApproximateReciprocal(b); - if (b == 0.0) - { - SetFPException(FPSCR_ZX); - } + if (b == 0.0) + { + SetFPException(FPSCR_ZX); + } - UpdateFPRF(rPS0(_inst.FD)); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::frsqrtex(UGeckoInstruction _inst) { - double b = rPS0(_inst.FB); + double b = rPS0(_inst.FB); - if (b < 0.0) - { - SetFPException(FPSCR_VXSQRT); - } - else if (b == 0.0) - { - SetFPException(FPSCR_ZX); - } + if (b < 0.0) + { + SetFPException(FPSCR_VXSQRT); + } + else if (b == 0.0) + { + SetFPException(FPSCR_ZX); + } - rPS0(_inst.FD) = ApproximateReciprocalSquareRoot(b); - UpdateFPRF(rPS0(_inst.FD)); + rPS0(_inst.FD) = ApproximateReciprocalSquareRoot(b); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fmsubx(UGeckoInstruction _inst) { - rPS0(_inst.FD) = ForceDouble(NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB))); - UpdateFPRF(rPS0(_inst.FD)); + rPS0(_inst.FD) = ForceDouble(NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB))); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fmsubsx(UGeckoInstruction _inst) { - double c_value = Force25Bit(rPS0(_inst.FC)); - rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_msub(rPS0(_inst.FA), c_value, rPS0(_inst.FB))); - UpdateFPRF(rPS0(_inst.FD)); + double c_value = Force25Bit(rPS0(_inst.FC)); + rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_msub(rPS0(_inst.FA), c_value, rPS0(_inst.FB))); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fnmaddx(UGeckoInstruction _inst) { - double result = ForceDouble(NI_madd(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB))); - rPS0(_inst.FD) = std::isnan(result) ? result : -result; - UpdateFPRF(rPS0(_inst.FD)); + double result = ForceDouble(NI_madd(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB))); + rPS0(_inst.FD) = std::isnan(result) ? result : -result; + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fnmaddsx(UGeckoInstruction _inst) { - double c_value = Force25Bit(rPS0(_inst.FC)); - double result = ForceSingle(NI_madd(rPS0(_inst.FA), c_value, rPS0(_inst.FB))); - rPS0(_inst.FD) = rPS1(_inst.FD) = std::isnan(result) ? result : -result; - UpdateFPRF(rPS0(_inst.FD)); + double c_value = Force25Bit(rPS0(_inst.FC)); + double result = ForceSingle(NI_madd(rPS0(_inst.FA), c_value, rPS0(_inst.FB))); + rPS0(_inst.FD) = rPS1(_inst.FD) = std::isnan(result) ? result : -result; + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fnmsubx(UGeckoInstruction _inst) { - double result = ForceDouble(NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB))); - rPS0(_inst.FD) = std::isnan(result) ? result : -result; - UpdateFPRF(rPS0(_inst.FD)); + double result = ForceDouble(NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB))); + rPS0(_inst.FD) = std::isnan(result) ? result : -result; + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fnmsubsx(UGeckoInstruction _inst) { - double c_value = Force25Bit(rPS0(_inst.FC)); - double result = ForceSingle(NI_msub(rPS0(_inst.FA), c_value, rPS0(_inst.FB))); - rPS0(_inst.FD) = rPS1(_inst.FD) = std::isnan(result) ? result : -result; - UpdateFPRF(rPS0(_inst.FD)); + double c_value = Force25Bit(rPS0(_inst.FC)); + double result = ForceSingle(NI_msub(rPS0(_inst.FA), c_value, rPS0(_inst.FB))); + rPS0(_inst.FD) = rPS1(_inst.FD) = std::isnan(result) ? result : -result; + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fsubx(UGeckoInstruction _inst) { - rPS0(_inst.FD) = ForceDouble(NI_sub(rPS0(_inst.FA), rPS0(_inst.FB))); - UpdateFPRF(rPS0(_inst.FD)); + rPS0(_inst.FD) = ForceDouble(NI_sub(rPS0(_inst.FA), rPS0(_inst.FB))); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::fsubsx(UGeckoInstruction _inst) { - rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_sub(rPS0(_inst.FA), rPS0(_inst.FB))); - UpdateFPRF(rPS0(_inst.FD)); + rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_sub(rPS0(_inst.FA), rPS0(_inst.FB))); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Integer.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Integer.cpp index b2c4d5406d..68b743995b 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Integer.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Integer.cpp @@ -2,680 +2,674 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/Interpreter/Interpreter.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/Interpreter/Interpreter.h" void Interpreter::Helper_UpdateCR0(u32 value) { - Helper_UpdateCRx(0, value); + Helper_UpdateCRx(0, value); } void Interpreter::Helper_UpdateCRx(int idx, u32 value) { - s64 sign_extended = (s64)(s32)value; - u64 cr_val = (u64)sign_extended; - cr_val = (cr_val & ~(1ull << 61)) | ((u64)GetXER_SO() << 61); + s64 sign_extended = (s64)(s32)value; + u64 cr_val = (u64)sign_extended; + cr_val = (cr_val & ~(1ull << 61)) | ((u64)GetXER_SO() << 61); - PowerPC::ppcState.cr_val[idx] = cr_val; + PowerPC::ppcState.cr_val[idx] = cr_val; } u32 Interpreter::Helper_Carry(u32 _uValue1, u32 _uValue2) { - return _uValue2 > (~_uValue1); + return _uValue2 > (~_uValue1); } u32 Interpreter::Helper_Mask(int mb, int me) { - //first make 001111111111111 part - u32 begin = 0xFFFFFFFF >> mb; - //then make 000000000001111 part, which is used to flip the bits of the first one - u32 end = 0x7FFFFFFF >> me; - //do the bitflip - u32 mask = begin ^ end; - //and invert if backwards - if (me < mb) - return ~mask; - else - return mask; + // first make 001111111111111 part + u32 begin = 0xFFFFFFFF >> mb; + // then make 000000000001111 part, which is used to flip the bits of the first one + u32 end = 0x7FFFFFFF >> me; + // do the bitflip + u32 mask = begin ^ end; + // and invert if backwards + if (me < mb) + return ~mask; + else + return mask; } void Interpreter::addi(UGeckoInstruction _inst) { - if (_inst.RA) - rGPR[_inst.RD] = rGPR[_inst.RA] + _inst.SIMM_16; - else - rGPR[_inst.RD] = _inst.SIMM_16; + if (_inst.RA) + rGPR[_inst.RD] = rGPR[_inst.RA] + _inst.SIMM_16; + else + rGPR[_inst.RD] = _inst.SIMM_16; } void Interpreter::addic(UGeckoInstruction _inst) { - u32 a = rGPR[_inst.RA]; - u32 imm = (u32)(s32)_inst.SIMM_16; - // TODO(ector): verify this thing - rGPR[_inst.RD] = a + imm; - SetCarry(Helper_Carry(a, imm)); + u32 a = rGPR[_inst.RA]; + u32 imm = (u32)(s32)_inst.SIMM_16; + // TODO(ector): verify this thing + rGPR[_inst.RD] = a + imm; + SetCarry(Helper_Carry(a, imm)); } void Interpreter::addic_rc(UGeckoInstruction _inst) { - addic(_inst); - Helper_UpdateCR0(rGPR[_inst.RD]); + addic(_inst); + Helper_UpdateCR0(rGPR[_inst.RD]); } void Interpreter::addis(UGeckoInstruction _inst) { - if (_inst.RA) - rGPR[_inst.RD] = rGPR[_inst.RA] + (_inst.SIMM_16 << 16); - else - rGPR[_inst.RD] = (_inst.SIMM_16 << 16); + if (_inst.RA) + rGPR[_inst.RD] = rGPR[_inst.RA] + (_inst.SIMM_16 << 16); + else + rGPR[_inst.RD] = (_inst.SIMM_16 << 16); } void Interpreter::andi_rc(UGeckoInstruction _inst) { - rGPR[_inst.RA] = rGPR[_inst.RS] & _inst.UIMM; - Helper_UpdateCR0(rGPR[_inst.RA]); + rGPR[_inst.RA] = rGPR[_inst.RS] & _inst.UIMM; + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::andis_rc(UGeckoInstruction _inst) { - rGPR[_inst.RA] = rGPR[_inst.RS] & ((u32)_inst.UIMM << 16); - Helper_UpdateCR0(rGPR[_inst.RA]); + rGPR[_inst.RA] = rGPR[_inst.RS] & ((u32)_inst.UIMM << 16); + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::cmpi(UGeckoInstruction _inst) { - Helper_UpdateCRx(_inst.CRFD, rGPR[_inst.RA] - _inst.SIMM_16); + Helper_UpdateCRx(_inst.CRFD, rGPR[_inst.RA] - _inst.SIMM_16); } void Interpreter::cmpli(UGeckoInstruction _inst) { - u32 a = rGPR[_inst.RA]; - u32 b = _inst.UIMM; - int f; + u32 a = rGPR[_inst.RA]; + u32 b = _inst.UIMM; + int f; - if (a < b) - f = 0x8; - else if (a > b) - f = 0x4; - else - f = 0x2; //equals + if (a < b) + f = 0x8; + else if (a > b) + f = 0x4; + else + f = 0x2; // equals - if (GetXER_SO()) - f |= 0x1; + if (GetXER_SO()) + f |= 0x1; - SetCRField(_inst.CRFD, f); + SetCRField(_inst.CRFD, f); } void Interpreter::mulli(UGeckoInstruction _inst) { - rGPR[_inst.RD] = (s32)rGPR[_inst.RA] * _inst.SIMM_16; + rGPR[_inst.RD] = (s32)rGPR[_inst.RA] * _inst.SIMM_16; } void Interpreter::ori(UGeckoInstruction _inst) { - rGPR[_inst.RA] = rGPR[_inst.RS] | _inst.UIMM; + rGPR[_inst.RA] = rGPR[_inst.RS] | _inst.UIMM; } void Interpreter::oris(UGeckoInstruction _inst) { - rGPR[_inst.RA] = rGPR[_inst.RS] | (_inst.UIMM << 16); + rGPR[_inst.RA] = rGPR[_inst.RS] | (_inst.UIMM << 16); } void Interpreter::subfic(UGeckoInstruction _inst) { -/* u32 rra = ~rGPR[_inst.RA]; - s32 immediate = (s16)_inst.SIMM_16 + 1; + /* u32 rra = ~rGPR[_inst.RA]; + s32 immediate = (s16)_inst.SIMM_16 + 1; -// #define CALC_XER_CA(X,Y) (((X) + (Y) < X) ? SET_XER_CA : CLEAR_XER_CA) - if ((rra + immediate) < rra) - SetCarry(1); - else - SetCarry(0); + // #define CALC_XER_CA(X,Y) (((X) + (Y) < X) ? SET_XER_CA : CLEAR_XER_CA) + if ((rra + immediate) < rra) + SetCarry(1); + else + SetCarry(0); - rGPR[_inst.RD] = rra - immediate; -*/ + rGPR[_inst.RD] = rra - immediate; + */ - s32 immediate = _inst.SIMM_16; - rGPR[_inst.RD] = immediate - (int)rGPR[_inst.RA]; - SetCarry((rGPR[_inst.RA] == 0) || (Helper_Carry(0 - rGPR[_inst.RA], immediate))); + s32 immediate = _inst.SIMM_16; + rGPR[_inst.RD] = immediate - (int)rGPR[_inst.RA]; + SetCarry((rGPR[_inst.RA] == 0) || (Helper_Carry(0 - rGPR[_inst.RA], immediate))); } void Interpreter::twi(UGeckoInstruction _inst) { - s32 a = rGPR[_inst.RA]; - s32 b = _inst.SIMM_16; - s32 TO = _inst.TO; + s32 a = rGPR[_inst.RA]; + s32 b = _inst.SIMM_16; + s32 TO = _inst.TO; - DEBUG_LOG(POWERPC, "twi rA %x SIMM %x TO %0x", a, b, TO); + DEBUG_LOG(POWERPC, "twi rA %x SIMM %x TO %0x", a, b, TO); - if (((a < b) && (TO & 0x10)) || - ((a > b) && (TO & 0x08)) || - ((a ==b) && (TO & 0x04)) || - (((u32)a <(u32)b) && (TO & 0x02)) || - (((u32)a >(u32)b) && (TO & 0x01))) - { - PowerPC::ppcState.Exceptions |= EXCEPTION_PROGRAM; - PowerPC::CheckExceptions(); - m_EndBlock = true; // Dunno about this - } + if (((a < b) && (TO & 0x10)) || ((a > b) && (TO & 0x08)) || ((a == b) && (TO & 0x04)) || + (((u32)a < (u32)b) && (TO & 0x02)) || (((u32)a > (u32)b) && (TO & 0x01))) + { + PowerPC::ppcState.Exceptions |= EXCEPTION_PROGRAM; + PowerPC::CheckExceptions(); + m_EndBlock = true; // Dunno about this + } } void Interpreter::xori(UGeckoInstruction _inst) { - rGPR[_inst.RA] = rGPR[_inst.RS] ^ _inst.UIMM; + rGPR[_inst.RA] = rGPR[_inst.RS] ^ _inst.UIMM; } void Interpreter::xoris(UGeckoInstruction _inst) { - rGPR[_inst.RA] = rGPR[_inst.RS] ^ (_inst.UIMM << 16); + rGPR[_inst.RA] = rGPR[_inst.RS] ^ (_inst.UIMM << 16); } void Interpreter::rlwimix(UGeckoInstruction _inst) { - u32 mask = Helper_Mask(_inst.MB,_inst.ME); - rGPR[_inst.RA] = (rGPR[_inst.RA] & ~mask) | (_rotl(rGPR[_inst.RS],_inst.SH) & mask); + u32 mask = Helper_Mask(_inst.MB, _inst.ME); + rGPR[_inst.RA] = (rGPR[_inst.RA] & ~mask) | (_rotl(rGPR[_inst.RS], _inst.SH) & mask); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::rlwinmx(UGeckoInstruction _inst) { - u32 mask = Helper_Mask(_inst.MB,_inst.ME); - rGPR[_inst.RA] = _rotl(rGPR[_inst.RS],_inst.SH) & mask; + u32 mask = Helper_Mask(_inst.MB, _inst.ME); + rGPR[_inst.RA] = _rotl(rGPR[_inst.RS], _inst.SH) & mask; - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::rlwnmx(UGeckoInstruction _inst) { - u32 mask = Helper_Mask(_inst.MB,_inst.ME); - rGPR[_inst.RA] = _rotl(rGPR[_inst.RS], rGPR[_inst.RB] & 0x1F) & mask; + u32 mask = Helper_Mask(_inst.MB, _inst.ME); + rGPR[_inst.RA] = _rotl(rGPR[_inst.RS], rGPR[_inst.RB] & 0x1F) & mask; - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::andx(UGeckoInstruction _inst) { - rGPR[_inst.RA] = rGPR[_inst.RS] & rGPR[_inst.RB]; + rGPR[_inst.RA] = rGPR[_inst.RS] & rGPR[_inst.RB]; - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::andcx(UGeckoInstruction _inst) { - rGPR[_inst.RA] = rGPR[_inst.RS] & ~rGPR[_inst.RB]; + rGPR[_inst.RA] = rGPR[_inst.RS] & ~rGPR[_inst.RB]; - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::cmp(UGeckoInstruction _inst) { - s32 a = (s32)rGPR[_inst.RA]; - s32 b = (s32)rGPR[_inst.RB]; - int fTemp; + s32 a = (s32)rGPR[_inst.RA]; + s32 b = (s32)rGPR[_inst.RB]; + int fTemp; - if (a < b) - fTemp = 0x8; - else if (a > b) - fTemp = 0x4; - else // Equals - fTemp = 0x2; + if (a < b) + fTemp = 0x8; + else if (a > b) + fTemp = 0x4; + else // Equals + fTemp = 0x2; - if (GetXER_SO()) - fTemp |= 0x1; + if (GetXER_SO()) + fTemp |= 0x1; - SetCRField(_inst.CRFD, fTemp); + SetCRField(_inst.CRFD, fTemp); } void Interpreter::cmpl(UGeckoInstruction _inst) { - u32 a = rGPR[_inst.RA]; - u32 b = rGPR[_inst.RB]; - u32 fTemp; + u32 a = rGPR[_inst.RA]; + u32 b = rGPR[_inst.RB]; + u32 fTemp; - if (a < b) - fTemp = 0x8; - else if (a > b) - fTemp = 0x4; - else // Equals - fTemp = 0x2; + if (a < b) + fTemp = 0x8; + else if (a > b) + fTemp = 0x4; + else // Equals + fTemp = 0x2; - if (GetXER_SO()) - fTemp |= 0x1; + if (GetXER_SO()) + fTemp |= 0x1; - SetCRField(_inst.CRFD, fTemp); + SetCRField(_inst.CRFD, fTemp); } void Interpreter::cntlzwx(UGeckoInstruction _inst) { - u32 val = rGPR[_inst.RS]; - u32 mask = 0x80000000; + u32 val = rGPR[_inst.RS]; + u32 mask = 0x80000000; - int i = 0; - for (; i < 32; i++, mask >>= 1) - { - if (val & mask) - break; - } + int i = 0; + for (; i < 32; i++, mask >>= 1) + { + if (val & mask) + break; + } - rGPR[_inst.RA] = i; + rGPR[_inst.RA] = i; - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::eqvx(UGeckoInstruction _inst) { - rGPR[_inst.RA] = ~(rGPR[_inst.RS] ^ rGPR[_inst.RB]); + rGPR[_inst.RA] = ~(rGPR[_inst.RS] ^ rGPR[_inst.RB]); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::extsbx(UGeckoInstruction _inst) { - rGPR[_inst.RA] = (u32)(s32)(s8)rGPR[_inst.RS]; + rGPR[_inst.RA] = (u32)(s32)(s8)rGPR[_inst.RS]; - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::extshx(UGeckoInstruction _inst) { - rGPR[_inst.RA] = (u32)(s32)(s16)rGPR[_inst.RS]; + rGPR[_inst.RA] = (u32)(s32)(s16)rGPR[_inst.RS]; - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::nandx(UGeckoInstruction _inst) { - rGPR[_inst.RA] = ~(rGPR[_inst.RS] & rGPR[_inst.RB]); + rGPR[_inst.RA] = ~(rGPR[_inst.RS] & rGPR[_inst.RB]); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::norx(UGeckoInstruction _inst) { - rGPR[_inst.RA] = ~(rGPR[_inst.RS] | rGPR[_inst.RB]); + rGPR[_inst.RA] = ~(rGPR[_inst.RS] | rGPR[_inst.RB]); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::orx(UGeckoInstruction _inst) { - rGPR[_inst.RA] = rGPR[_inst.RS] | rGPR[_inst.RB]; + rGPR[_inst.RA] = rGPR[_inst.RS] | rGPR[_inst.RB]; - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::orcx(UGeckoInstruction _inst) { - rGPR[_inst.RA] = rGPR[_inst.RS] | (~rGPR[_inst.RB]); + rGPR[_inst.RA] = rGPR[_inst.RS] | (~rGPR[_inst.RB]); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::slwx(UGeckoInstruction _inst) { - u32 amount = rGPR[_inst.RB]; - rGPR[_inst.RA] = (amount & 0x20) ? 0 : rGPR[_inst.RS] << (amount & 0x1f); + u32 amount = rGPR[_inst.RB]; + rGPR[_inst.RA] = (amount & 0x20) ? 0 : rGPR[_inst.RS] << (amount & 0x1f); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::srawx(UGeckoInstruction _inst) { - int rb = rGPR[_inst.RB]; + int rb = rGPR[_inst.RB]; - if (rb & 0x20) - { - if (rGPR[_inst.RS] & 0x80000000) - { - rGPR[_inst.RA] = 0xFFFFFFFF; - SetCarry(1); - } - else - { - rGPR[_inst.RA] = 0x00000000; - SetCarry(0); - } - } - else - { - int amount = rb & 0x1f; - if (amount == 0) - { - rGPR[_inst.RA] = rGPR[_inst.RS]; - SetCarry(0); - } - else - { - s32 rrs = rGPR[_inst.RS]; - rGPR[_inst.RA] = rrs >> amount; + if (rb & 0x20) + { + if (rGPR[_inst.RS] & 0x80000000) + { + rGPR[_inst.RA] = 0xFFFFFFFF; + SetCarry(1); + } + else + { + rGPR[_inst.RA] = 0x00000000; + SetCarry(0); + } + } + else + { + int amount = rb & 0x1f; + if (amount == 0) + { + rGPR[_inst.RA] = rGPR[_inst.RS]; + SetCarry(0); + } + else + { + s32 rrs = rGPR[_inst.RS]; + rGPR[_inst.RA] = rrs >> amount; - if ((rrs < 0) && (rrs << (32 - amount))) - SetCarry(1); - else - SetCarry(0); - } - } + if ((rrs < 0) && (rrs << (32 - amount))) + SetCarry(1); + else + SetCarry(0); + } + } - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::srawix(UGeckoInstruction _inst) { - int amount = _inst.SH; + int amount = _inst.SH; - if (amount != 0) - { - s32 rrs = rGPR[_inst.RS]; - rGPR[_inst.RA] = rrs >> amount; + if (amount != 0) + { + s32 rrs = rGPR[_inst.RS]; + rGPR[_inst.RA] = rrs >> amount; - if ((rrs < 0) && (rrs << (32 - amount))) - SetCarry(1); - else - SetCarry(0); - } - else - { - SetCarry(0); - rGPR[_inst.RA] = rGPR[_inst.RS]; - } + if ((rrs < 0) && (rrs << (32 - amount))) + SetCarry(1); + else + SetCarry(0); + } + else + { + SetCarry(0); + rGPR[_inst.RA] = rGPR[_inst.RS]; + } - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::srwx(UGeckoInstruction _inst) { - u32 amount = rGPR[_inst.RB]; - rGPR[_inst.RA] = (amount & 0x20) ? 0 : (rGPR[_inst.RS] >> (amount & 0x1f)); + u32 amount = rGPR[_inst.RB]; + rGPR[_inst.RA] = (amount & 0x20) ? 0 : (rGPR[_inst.RS] >> (amount & 0x1f)); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::tw(UGeckoInstruction _inst) { - s32 a = rGPR[_inst.RA]; - s32 b = rGPR[_inst.RB]; - s32 TO = _inst.TO; + s32 a = rGPR[_inst.RA]; + s32 b = rGPR[_inst.RB]; + s32 TO = _inst.TO; - DEBUG_LOG(POWERPC, "tw rA %0x rB %0x TO %0x", a, b, TO); + DEBUG_LOG(POWERPC, "tw rA %0x rB %0x TO %0x", a, b, TO); - if (((a < b) && (TO & 0x10)) || - ((a > b) && (TO & 0x08)) || - ((a ==b) && (TO & 0x04)) || - (((u32)a <(u32)b) && (TO & 0x02)) || - (((u32)a >(u32)b) && (TO & 0x01))) - { - PowerPC::ppcState.Exceptions |= EXCEPTION_PROGRAM; - PowerPC::CheckExceptions(); - m_EndBlock = true; // Dunno about this - } + if (((a < b) && (TO & 0x10)) || ((a > b) && (TO & 0x08)) || ((a == b) && (TO & 0x04)) || + (((u32)a < (u32)b) && (TO & 0x02)) || (((u32)a > (u32)b) && (TO & 0x01))) + { + PowerPC::ppcState.Exceptions |= EXCEPTION_PROGRAM; + PowerPC::CheckExceptions(); + m_EndBlock = true; // Dunno about this + } } void Interpreter::xorx(UGeckoInstruction _inst) { - rGPR[_inst.RA] = rGPR[_inst.RS] ^ rGPR[_inst.RB]; + rGPR[_inst.RA] = rGPR[_inst.RS] ^ rGPR[_inst.RB]; - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RA]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RA]); } void Interpreter::addx(UGeckoInstruction _inst) { - rGPR[_inst.RD] = rGPR[_inst.RA] + rGPR[_inst.RB]; + rGPR[_inst.RD] = rGPR[_inst.RA] + rGPR[_inst.RB]; - if (_inst.OE) - PanicAlert("OE: addx"); + if (_inst.OE) + PanicAlert("OE: addx"); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } void Interpreter::addcx(UGeckoInstruction _inst) { - u32 a = rGPR[_inst.RA]; - u32 b = rGPR[_inst.RB]; - rGPR[_inst.RD] = a + b; - SetCarry(Helper_Carry(a,b)); + u32 a = rGPR[_inst.RA]; + u32 b = rGPR[_inst.RB]; + rGPR[_inst.RD] = a + b; + SetCarry(Helper_Carry(a, b)); - if (_inst.OE) - PanicAlert("OE: addcx"); + if (_inst.OE) + PanicAlert("OE: addcx"); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } void Interpreter::addex(UGeckoInstruction _inst) { - int carry = GetCarry(); - int a = rGPR[_inst.RA]; - int b = rGPR[_inst.RB]; - rGPR[_inst.RD] = a + b + carry; - SetCarry(Helper_Carry(a, b) || (carry != 0 && Helper_Carry(a + b, carry))); + int carry = GetCarry(); + int a = rGPR[_inst.RA]; + int b = rGPR[_inst.RB]; + rGPR[_inst.RD] = a + b + carry; + SetCarry(Helper_Carry(a, b) || (carry != 0 && Helper_Carry(a + b, carry))); - if (_inst.OE) - PanicAlert("OE: addex"); + if (_inst.OE) + PanicAlert("OE: addex"); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } void Interpreter::addmex(UGeckoInstruction _inst) { - int carry = GetCarry(); - int a = rGPR[_inst.RA]; - rGPR[_inst.RD] = a + carry - 1; - SetCarry(Helper_Carry(a, carry - 1)); + int carry = GetCarry(); + int a = rGPR[_inst.RA]; + rGPR[_inst.RD] = a + carry - 1; + SetCarry(Helper_Carry(a, carry - 1)); - if (_inst.OE) - PanicAlert("OE: addmex"); + if (_inst.OE) + PanicAlert("OE: addmex"); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } void Interpreter::addzex(UGeckoInstruction _inst) { - int carry = GetCarry(); - int a = rGPR[_inst.RA]; - rGPR[_inst.RD] = a + carry; - SetCarry(Helper_Carry(a, carry)); + int carry = GetCarry(); + int a = rGPR[_inst.RA]; + rGPR[_inst.RD] = a + carry; + SetCarry(Helper_Carry(a, carry)); - if (_inst.OE) - PanicAlert("OE: addzex"); + if (_inst.OE) + PanicAlert("OE: addzex"); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } void Interpreter::divwx(UGeckoInstruction _inst) { - s32 a = rGPR[_inst.RA]; - s32 b = rGPR[_inst.RB]; + s32 a = rGPR[_inst.RA]; + s32 b = rGPR[_inst.RB]; - if (b == 0 || ((u32)a == 0x80000000 && b == -1)) - { - if (_inst.OE) - { - // should set OV - PanicAlert("OE: divwx"); - } + if (b == 0 || ((u32)a == 0x80000000 && b == -1)) + { + if (_inst.OE) + { + // should set OV + PanicAlert("OE: divwx"); + } - if (((u32)a & 0x80000000) && b == 0) - rGPR[_inst.RD] = -1; - else - rGPR[_inst.RD] = 0; - } - else - { - rGPR[_inst.RD] = (u32)(a / b); - } + if (((u32)a & 0x80000000) && b == 0) + rGPR[_inst.RD] = -1; + else + rGPR[_inst.RD] = 0; + } + else + { + rGPR[_inst.RD] = (u32)(a / b); + } - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } - void Interpreter::divwux(UGeckoInstruction _inst) { - u32 a = rGPR[_inst.RA]; - u32 b = rGPR[_inst.RB]; + u32 a = rGPR[_inst.RA]; + u32 b = rGPR[_inst.RB]; - if (b == 0) - { - if (_inst.OE) - { - // should set OV - PanicAlert("OE: divwux"); - } + if (b == 0) + { + if (_inst.OE) + { + // should set OV + PanicAlert("OE: divwux"); + } - rGPR[_inst.RD] = 0; - } - else - { - rGPR[_inst.RD] = a / b; - } + rGPR[_inst.RD] = 0; + } + else + { + rGPR[_inst.RD] = a / b; + } - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } void Interpreter::mulhwx(UGeckoInstruction _inst) { - u32 a = rGPR[_inst.RA]; - u32 b = rGPR[_inst.RB]; - u32 d = (u32)((u64)(((s64)(s32)a * (s64)(s32)b) ) >> 32); // This can be done better. Not in plain C/C++ though. - rGPR[_inst.RD] = d; + u32 a = rGPR[_inst.RA]; + u32 b = rGPR[_inst.RB]; + u32 d = (u32)((u64)(((s64)(s32)a * (s64)(s32)b)) >> + 32); // This can be done better. Not in plain C/C++ though. + rGPR[_inst.RD] = d; - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } void Interpreter::mulhwux(UGeckoInstruction _inst) { - u32 a = rGPR[_inst.RA]; - u32 b = rGPR[_inst.RB]; - u32 d = (u32)(((u64)a * (u64)b) >> 32); - rGPR[_inst.RD] = d; + u32 a = rGPR[_inst.RA]; + u32 b = rGPR[_inst.RB]; + u32 d = (u32)(((u64)a * (u64)b) >> 32); + rGPR[_inst.RD] = d; - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } void Interpreter::mullwx(UGeckoInstruction _inst) { - u32 a = rGPR[_inst.RA]; - u32 b = rGPR[_inst.RB]; - u32 d = (u32)((s32)a * (s32)b); - rGPR[_inst.RD] = d; + u32 a = rGPR[_inst.RA]; + u32 b = rGPR[_inst.RB]; + u32 d = (u32)((s32)a * (s32)b); + rGPR[_inst.RD] = d; - if (_inst.OE) - PanicAlert("OE: mullwx"); + if (_inst.OE) + PanicAlert("OE: mullwx"); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } void Interpreter::negx(UGeckoInstruction _inst) { - rGPR[_inst.RD] = (~rGPR[_inst.RA]) + 1; + rGPR[_inst.RD] = (~rGPR[_inst.RA]) + 1; - if (rGPR[_inst.RD] == 0x80000000) - { - if (_inst.OE) - PanicAlert("OE: negx"); - } + if (rGPR[_inst.RD] == 0x80000000) + { + if (_inst.OE) + PanicAlert("OE: negx"); + } - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } void Interpreter::subfx(UGeckoInstruction _inst) { - rGPR[_inst.RD] = rGPR[_inst.RB] - rGPR[_inst.RA]; + rGPR[_inst.RD] = rGPR[_inst.RB] - rGPR[_inst.RA]; - if (_inst.OE) - PanicAlert("OE: subfx"); + if (_inst.OE) + PanicAlert("OE: subfx"); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } void Interpreter::subfcx(UGeckoInstruction _inst) { - u32 a = rGPR[_inst.RA]; - u32 b = rGPR[_inst.RB]; - rGPR[_inst.RD] = b - a; - SetCarry(a == 0 || Helper_Carry(b, 0-a)); + u32 a = rGPR[_inst.RA]; + u32 b = rGPR[_inst.RB]; + rGPR[_inst.RD] = b - a; + SetCarry(a == 0 || Helper_Carry(b, 0 - a)); - if (_inst.OE) - PanicAlert("OE: subfcx"); + if (_inst.OE) + PanicAlert("OE: subfcx"); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } void Interpreter::subfex(UGeckoInstruction _inst) { - u32 a = rGPR[_inst.RA]; - u32 b = rGPR[_inst.RB]; - int carry = GetCarry(); - rGPR[_inst.RD] = (~a) + b + carry; - SetCarry(Helper_Carry(~a, b) || Helper_Carry((~a) + b, carry)); + u32 a = rGPR[_inst.RA]; + u32 b = rGPR[_inst.RB]; + int carry = GetCarry(); + rGPR[_inst.RD] = (~a) + b + carry; + SetCarry(Helper_Carry(~a, b) || Helper_Carry((~a) + b, carry)); - if (_inst.OE) - PanicAlert("OE: subfex"); + if (_inst.OE) + PanicAlert("OE: subfex"); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } // sub from minus one void Interpreter::subfmex(UGeckoInstruction _inst) { - u32 a = rGPR[_inst.RA]; - int carry = GetCarry(); - rGPR[_inst.RD] = (~a) + carry - 1; - SetCarry(Helper_Carry(~a, carry - 1)); + u32 a = rGPR[_inst.RA]; + int carry = GetCarry(); + rGPR[_inst.RD] = (~a) + carry - 1; + SetCarry(Helper_Carry(~a, carry - 1)); - if (_inst.OE) - PanicAlert("OE: subfmex"); + if (_inst.OE) + PanicAlert("OE: subfmex"); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } // sub from zero void Interpreter::subfzex(UGeckoInstruction _inst) { - u32 a = rGPR[_inst.RA]; - int carry = GetCarry(); - rGPR[_inst.RD] = (~a) + carry; - SetCarry(Helper_Carry(~a, carry)); + u32 a = rGPR[_inst.RA]; + int carry = GetCarry(); + rGPR[_inst.RD] = (~a) + carry; + SetCarry(Helper_Carry(~a, carry)); - if (_inst.OE) - PanicAlert("OE: subfzex"); + if (_inst.OE) + PanicAlert("OE: subfzex"); - if (_inst.Rc) - Helper_UpdateCR0(rGPR[_inst.RD]); + if (_inst.Rc) + Helper_UpdateCR0(rGPR[_inst.RD]); } diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStore.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStore.cpp index f3855904e9..a5cafc01d8 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStore.cpp @@ -7,629 +7,630 @@ #include "Core/ConfigManager.h" #include "Core/HW/DSP.h" -#include "Core/PowerPC/JitInterface.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/Interpreter/Interpreter.h" #include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h" - +#include "Core/PowerPC/JitInterface.h" +#include "Core/PowerPC/PowerPC.h" bool Interpreter::g_bReserve; -u32 Interpreter::g_reserveAddr; +u32 Interpreter::g_reserveAddr; u32 Interpreter::Helper_Get_EA(const UGeckoInstruction _inst) { - return _inst.RA ? (rGPR[_inst.RA] + _inst.SIMM_16) : (u32)_inst.SIMM_16; + return _inst.RA ? (rGPR[_inst.RA] + _inst.SIMM_16) : (u32)_inst.SIMM_16; } u32 Interpreter::Helper_Get_EA_U(const UGeckoInstruction _inst) { - return (rGPR[_inst.RA] + _inst.SIMM_16); + return (rGPR[_inst.RA] + _inst.SIMM_16); } u32 Interpreter::Helper_Get_EA_X(const UGeckoInstruction _inst) { - return _inst.RA ? (rGPR[_inst.RA] + rGPR[_inst.RB]) : rGPR[_inst.RB]; + return _inst.RA ? (rGPR[_inst.RA] + rGPR[_inst.RB]) : rGPR[_inst.RB]; } u32 Interpreter::Helper_Get_EA_UX(const UGeckoInstruction _inst) { - return (rGPR[_inst.RA] + rGPR[_inst.RB]); + return (rGPR[_inst.RA] + rGPR[_inst.RB]); } void Interpreter::lbz(UGeckoInstruction _inst) { - u32 temp = (u32)PowerPC::Read_U8(Helper_Get_EA(_inst)); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - rGPR[_inst.RD] = temp; + u32 temp = (u32)PowerPC::Read_U8(Helper_Get_EA(_inst)); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + rGPR[_inst.RD] = temp; } void Interpreter::lbzu(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_U(_inst); - u32 temp = (u32)PowerPC::Read_U8(uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_U(_inst); + u32 temp = (u32)PowerPC::Read_U8(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + rGPR[_inst.RA] = uAddress; + } } void Interpreter::lfd(UGeckoInstruction _inst) { - u64 temp = PowerPC::Read_U64(Helper_Get_EA(_inst)); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - riPS0(_inst.FD) = temp; + u64 temp = PowerPC::Read_U64(Helper_Get_EA(_inst)); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + riPS0(_inst.FD) = temp; } void Interpreter::lfdu(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_U(_inst); - u64 temp = PowerPC::Read_U64(uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - riPS0(_inst.FD) = temp; - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_U(_inst); + u64 temp = PowerPC::Read_U64(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + riPS0(_inst.FD) = temp; + rGPR[_inst.RA] = uAddress; + } } void Interpreter::lfdux(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_UX(_inst); - u64 temp = PowerPC::Read_U64(uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - riPS0(_inst.FD) = temp; - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_UX(_inst); + u64 temp = PowerPC::Read_U64(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + riPS0(_inst.FD) = temp; + rGPR[_inst.RA] = uAddress; + } } void Interpreter::lfdx(UGeckoInstruction _inst) { - u64 temp = PowerPC::Read_U64(Helper_Get_EA_X(_inst)); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - riPS0(_inst.FD) = temp; + u64 temp = PowerPC::Read_U64(Helper_Get_EA_X(_inst)); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + riPS0(_inst.FD) = temp; } void Interpreter::lfs(UGeckoInstruction _inst) { - u32 uTemp = PowerPC::Read_U32(Helper_Get_EA(_inst)); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - u64 value = ConvertToDouble(uTemp); - riPS0(_inst.FD) = value; - riPS1(_inst.FD) = value; - } + u32 uTemp = PowerPC::Read_U32(Helper_Get_EA(_inst)); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + u64 value = ConvertToDouble(uTemp); + riPS0(_inst.FD) = value; + riPS1(_inst.FD) = value; + } } void Interpreter::lfsu(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_U(_inst); - u32 uTemp = PowerPC::Read_U32(uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - u64 value = ConvertToDouble(uTemp); - riPS0(_inst.FD) = value; - riPS1(_inst.FD) = value; - rGPR[_inst.RA] = uAddress; - } - + u32 uAddress = Helper_Get_EA_U(_inst); + u32 uTemp = PowerPC::Read_U32(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + u64 value = ConvertToDouble(uTemp); + riPS0(_inst.FD) = value; + riPS1(_inst.FD) = value; + rGPR[_inst.RA] = uAddress; + } } void Interpreter::lfsux(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_UX(_inst); - u32 uTemp = PowerPC::Read_U32(uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - u64 value = ConvertToDouble(uTemp); - riPS0(_inst.FD) = value; - riPS1(_inst.FD) = value; - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_UX(_inst); + u32 uTemp = PowerPC::Read_U32(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + u64 value = ConvertToDouble(uTemp); + riPS0(_inst.FD) = value; + riPS1(_inst.FD) = value; + rGPR[_inst.RA] = uAddress; + } } void Interpreter::lfsx(UGeckoInstruction _inst) { - u32 uTemp = PowerPC::Read_U32(Helper_Get_EA_X(_inst)); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - u64 value = ConvertToDouble(uTemp); - riPS0(_inst.FD) = value; - riPS1(_inst.FD) = value; - } + u32 uTemp = PowerPC::Read_U32(Helper_Get_EA_X(_inst)); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + u64 value = ConvertToDouble(uTemp); + riPS0(_inst.FD) = value; + riPS1(_inst.FD) = value; + } } void Interpreter::lha(UGeckoInstruction _inst) { - u32 temp = (u32)(s32)(s16)PowerPC::Read_U16(Helper_Get_EA(_inst)); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - } + u32 temp = (u32)(s32)(s16)PowerPC::Read_U16(Helper_Get_EA(_inst)); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + } } void Interpreter::lhau(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_U(_inst); - u32 temp = (u32)(s32)(s16)PowerPC::Read_U16(uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_U(_inst); + u32 temp = (u32)(s32)(s16)PowerPC::Read_U16(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + rGPR[_inst.RA] = uAddress; + } } void Interpreter::lhz(UGeckoInstruction _inst) { - u32 temp = (u32)(u16)PowerPC::Read_U16(Helper_Get_EA(_inst)); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - } + u32 temp = (u32)(u16)PowerPC::Read_U16(Helper_Get_EA(_inst)); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + } } void Interpreter::lhzu(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_U(_inst); - u32 temp = (u32)(u16)PowerPC::Read_U16(uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_U(_inst); + u32 temp = (u32)(u16)PowerPC::Read_U16(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + rGPR[_inst.RA] = uAddress; + } } // FIXME: lmw should do a total rollback if a DSI occurs void Interpreter::lmw(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA(_inst); - for (int iReg = _inst.RD; iReg <= 31; iReg++, uAddress += 4) - { - u32 TempReg = PowerPC::Read_U32(uAddress); - if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) - { - PanicAlert("DSI exception in lmw"); - NOTICE_LOG(POWERPC, "DSI exception in lmw"); - return; - } - else - { - rGPR[iReg] = TempReg; - } - } + u32 uAddress = Helper_Get_EA(_inst); + for (int iReg = _inst.RD; iReg <= 31; iReg++, uAddress += 4) + { + u32 TempReg = PowerPC::Read_U32(uAddress); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + PanicAlert("DSI exception in lmw"); + NOTICE_LOG(POWERPC, "DSI exception in lmw"); + return; + } + else + { + rGPR[iReg] = TempReg; + } + } } // FIXME: stmw should do a total rollback if a DSI occurs void Interpreter::stmw(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA(_inst); - for (int iReg = _inst.RS; iReg <= 31; iReg++, uAddress+=4) - { - PowerPC::Write_U32(rGPR[iReg], uAddress); - if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) - { - PanicAlert("DSI exception in stmw"); - NOTICE_LOG(POWERPC, "DSI exception in stmw"); - return; - } - } + u32 uAddress = Helper_Get_EA(_inst); + for (int iReg = _inst.RS; iReg <= 31; iReg++, uAddress += 4) + { + PowerPC::Write_U32(rGPR[iReg], uAddress); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + PanicAlert("DSI exception in stmw"); + NOTICE_LOG(POWERPC, "DSI exception in stmw"); + return; + } + } } void Interpreter::lwz(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA(_inst); - u32 temp = PowerPC::Read_U32(uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - } + u32 uAddress = Helper_Get_EA(_inst); + u32 temp = PowerPC::Read_U32(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + } } void Interpreter::lwzu(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_U(_inst); - u32 temp = PowerPC::Read_U32(uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_U(_inst); + u32 temp = PowerPC::Read_U32(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + rGPR[_inst.RA] = uAddress; + } } void Interpreter::stb(UGeckoInstruction _inst) { - PowerPC::Write_U8((u8)rGPR[_inst.RS], Helper_Get_EA(_inst)); + PowerPC::Write_U8((u8)rGPR[_inst.RS], Helper_Get_EA(_inst)); } void Interpreter::stbu(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_U(_inst); - PowerPC::Write_U8((u8)rGPR[_inst.RS], uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_U(_inst); + PowerPC::Write_U8((u8)rGPR[_inst.RS], uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RA] = uAddress; + } } void Interpreter::stfd(UGeckoInstruction _inst) { - PowerPC::Write_U64(riPS0(_inst.FS), Helper_Get_EA(_inst)); + PowerPC::Write_U64(riPS0(_inst.FS), Helper_Get_EA(_inst)); } void Interpreter::stfdu(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_U(_inst); - PowerPC::Write_U64(riPS0(_inst.FS), uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_U(_inst); + PowerPC::Write_U64(riPS0(_inst.FS), uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RA] = uAddress; + } } void Interpreter::stfs(UGeckoInstruction _inst) { - PowerPC::Write_U32(ConvertToSingle(riPS0(_inst.FS)), Helper_Get_EA(_inst)); + PowerPC::Write_U32(ConvertToSingle(riPS0(_inst.FS)), Helper_Get_EA(_inst)); } void Interpreter::stfsu(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_U(_inst); - PowerPC::Write_U32(ConvertToSingle(riPS0(_inst.FS)), uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_U(_inst); + PowerPC::Write_U32(ConvertToSingle(riPS0(_inst.FS)), uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RA] = uAddress; + } } void Interpreter::sth(UGeckoInstruction _inst) { - PowerPC::Write_U16((u16)rGPR[_inst.RS], Helper_Get_EA(_inst)); + PowerPC::Write_U16((u16)rGPR[_inst.RS], Helper_Get_EA(_inst)); } void Interpreter::sthu(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_U(_inst); - PowerPC::Write_U16((u16)rGPR[_inst.RS], uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_U(_inst); + PowerPC::Write_U16((u16)rGPR[_inst.RS], uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RA] = uAddress; + } } void Interpreter::stw(UGeckoInstruction _inst) { - PowerPC::Write_U32(rGPR[_inst.RS], Helper_Get_EA(_inst)); + PowerPC::Write_U32(rGPR[_inst.RS], Helper_Get_EA(_inst)); } void Interpreter::stwu(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_U(_inst); - PowerPC::Write_U32(rGPR[_inst.RS], uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_U(_inst); + PowerPC::Write_U32(rGPR[_inst.RS], uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RA] = uAddress; + } } void Interpreter::dcba(UGeckoInstruction _inst) { - _assert_msg_(POWERPC,0,"dcba - Not implemented - not a Gekko instruction"); + _assert_msg_(POWERPC, 0, "dcba - Not implemented - not a Gekko instruction"); } void Interpreter::dcbf(UGeckoInstruction _inst) { - //This should tell GFX backend to throw out any cached data here - // !!! SPEEDUP HACK for OSProtectRange !!! -/* u32 tmp1 = PowerPC::HostRead_U32(PC+4); - u32 tmp2 = PowerPC::HostRead_U32(PC+8); + // This should tell GFX backend to throw out any cached data here + // !!! SPEEDUP HACK for OSProtectRange !!! + /* u32 tmp1 = PowerPC::HostRead_U32(PC+4); + u32 tmp2 = PowerPC::HostRead_U32(PC+8); - if ((tmp1 == 0x38630020) && - (tmp2 == 0x4200fff8)) - { - NPC = PC + 12; - }*/ - u32 address = Helper_Get_EA_X(_inst); - JitInterface::InvalidateICache(address & ~0x1f, 32, false); + if ((tmp1 == 0x38630020) && + (tmp2 == 0x4200fff8)) + { + NPC = PC + 12; + }*/ + u32 address = Helper_Get_EA_X(_inst); + JitInterface::InvalidateICache(address & ~0x1f, 32, false); } void Interpreter::dcbi(UGeckoInstruction _inst) { - // Removes a block from data cache. Since we don't emulate the data cache, we don't need to do anything to the data cache - // However, we invalidate the jit block cache on dcbi - u32 address = Helper_Get_EA_X(_inst); - JitInterface::InvalidateICache(address & ~0x1f, 32, false); + // Removes a block from data cache. Since we don't emulate the data cache, we don't need to do + // anything to the data cache + // However, we invalidate the jit block cache on dcbi + u32 address = Helper_Get_EA_X(_inst); + JitInterface::InvalidateICache(address & ~0x1f, 32, false); - // The following detects a situation where the game is writing to the dcache at the address being DMA'd. As we do not - // have dcache emulation, invalid data is being DMA'd causing audio glitches. The following code detects this and - // enables the DMA to complete instantly before the invalid data is written. Resident Evil 2 & 3 trigger this. - DSP::FlushInstantDMA(address); + // The following detects a situation where the game is writing to the dcache at the address being + // DMA'd. As we do not + // have dcache emulation, invalid data is being DMA'd causing audio glitches. The following code + // detects this and + // enables the DMA to complete instantly before the invalid data is written. Resident Evil 2 & 3 + // trigger this. + DSP::FlushInstantDMA(address); } void Interpreter::dcbst(UGeckoInstruction _inst) { - // Cache line flush. Since we don't emulate the data cache, we don't need to do anything. - // Invalidate the jit block cache on dcbst in case new code has been loaded via the data cache - u32 address = Helper_Get_EA_X(_inst); - JitInterface::InvalidateICache(address & ~0x1f, 32, false); + // Cache line flush. Since we don't emulate the data cache, we don't need to do anything. + // Invalidate the jit block cache on dcbst in case new code has been loaded via the data cache + u32 address = Helper_Get_EA_X(_inst); + JitInterface::InvalidateICache(address & ~0x1f, 32, false); } void Interpreter::dcbt(UGeckoInstruction _inst) { - // Prefetch. Since we don't emulate the data cache, we don't need to do anything. + // Prefetch. Since we don't emulate the data cache, we don't need to do anything. } void Interpreter::dcbtst(UGeckoInstruction _inst) { - // This is just some sort of store "prefetching". - // Since we don't emulate the data cache, we don't need to do anything. + // This is just some sort of store "prefetching". + // Since we don't emulate the data cache, we don't need to do anything. } void Interpreter::dcbz(UGeckoInstruction _inst) { - // HACK but works... we think - if (!SConfig::GetInstance().bDCBZOFF) - PowerPC::ClearCacheLine(Helper_Get_EA_X(_inst) & (~31)); - if (!JitInterface::GetCore()) - PowerPC::CheckExceptions(); + // HACK but works... we think + if (!SConfig::GetInstance().bDCBZOFF) + PowerPC::ClearCacheLine(Helper_Get_EA_X(_inst) & (~31)); + if (!JitInterface::GetCore()) + PowerPC::CheckExceptions(); } // eciwx/ecowx technically should access the specified device // We just do it instantly from ppc...and hey, it works! :D void Interpreter::eciwx(UGeckoInstruction _inst) { - u32 EA = Helper_Get_EA_X(_inst); + u32 EA = Helper_Get_EA_X(_inst); - if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000)) - { - PowerPC::ppcState.Exceptions |= EXCEPTION_DSI; - } - if (EA & 3) - PowerPC::ppcState.Exceptions |= EXCEPTION_ALIGNMENT; + if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000)) + { + PowerPC::ppcState.Exceptions |= EXCEPTION_DSI; + } + if (EA & 3) + PowerPC::ppcState.Exceptions |= EXCEPTION_ALIGNMENT; -// _assert_msg_(POWERPC,0,"eciwx - fill r%i with word @ %08x from device %02x", -// _inst.RS, EA, PowerPC::ppcState.spr[SPR_EAR] & 0x1f); + // _assert_msg_(POWERPC,0,"eciwx - fill r%i with word @ %08x from device %02x", + // _inst.RS, EA, PowerPC::ppcState.spr[SPR_EAR] & 0x1f); - rGPR[_inst.RD] = PowerPC::Read_U32(EA); + rGPR[_inst.RD] = PowerPC::Read_U32(EA); } void Interpreter::ecowx(UGeckoInstruction _inst) { - u32 EA = Helper_Get_EA_X(_inst); + u32 EA = Helper_Get_EA_X(_inst); - if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000)) - { - PowerPC::ppcState.Exceptions |= EXCEPTION_DSI; - } - if (EA & 3) - PowerPC::ppcState.Exceptions |= EXCEPTION_ALIGNMENT; + if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000)) + { + PowerPC::ppcState.Exceptions |= EXCEPTION_DSI; + } + if (EA & 3) + PowerPC::ppcState.Exceptions |= EXCEPTION_ALIGNMENT; -// _assert_msg_(POWERPC,0,"ecowx - send stw request (%08x@%08x) to device %02x", -// rGPR[_inst.RS], EA, PowerPC::ppcState.spr[SPR_EAR] & 0x1f); + // _assert_msg_(POWERPC,0,"ecowx - send stw request (%08x@%08x) to device %02x", + // rGPR[_inst.RS], EA, PowerPC::ppcState.spr[SPR_EAR] & 0x1f); - PowerPC::Write_U32(rGPR[_inst.RS], EA); + PowerPC::Write_U32(rGPR[_inst.RS], EA); } void Interpreter::eieio(UGeckoInstruction _inst) { - // Basically ensures that loads/stores before this instruction - // have completed (in order) before executing the next op. - // Prevents real ppc from "smartly" reordering loads/stores - // But (at least in interpreter) we do everything realtime anyways. + // Basically ensures that loads/stores before this instruction + // have completed (in order) before executing the next op. + // Prevents real ppc from "smartly" reordering loads/stores + // But (at least in interpreter) we do everything realtime anyways. } void Interpreter::icbi(UGeckoInstruction _inst) { - u32 address = Helper_Get_EA_X(_inst); - PowerPC::ppcState.iCache.Invalidate(address); + u32 address = Helper_Get_EA_X(_inst); + PowerPC::ppcState.iCache.Invalidate(address); } void Interpreter::lbzux(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_UX(_inst); - u32 temp = (u32)PowerPC::Read_U8(uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_UX(_inst); + u32 temp = (u32)PowerPC::Read_U8(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + rGPR[_inst.RA] = uAddress; + } } void Interpreter::lbzx(UGeckoInstruction _inst) { - u32 temp = (u32)PowerPC::Read_U8(Helper_Get_EA_X(_inst)); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - } + u32 temp = (u32)PowerPC::Read_U8(Helper_Get_EA_X(_inst)); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + } } void Interpreter::lhaux(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_UX(_inst); - s32 temp = (s32)(s16)PowerPC::Read_U16(uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_UX(_inst); + s32 temp = (s32)(s16)PowerPC::Read_U16(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + rGPR[_inst.RA] = uAddress; + } } void Interpreter::lhax(UGeckoInstruction _inst) { - s32 temp = (s32)(s16)PowerPC::Read_U16(Helper_Get_EA_X(_inst)); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - } + s32 temp = (s32)(s16)PowerPC::Read_U16(Helper_Get_EA_X(_inst)); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + } } void Interpreter::lhbrx(UGeckoInstruction _inst) { - u32 temp = (u32)Common::swap16(PowerPC::Read_U16(Helper_Get_EA_X(_inst))); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - } + u32 temp = (u32)Common::swap16(PowerPC::Read_U16(Helper_Get_EA_X(_inst))); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + } } void Interpreter::lhzux(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_UX(_inst); - u32 temp = (u32)PowerPC::Read_U16(uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_UX(_inst); + u32 temp = (u32)PowerPC::Read_U16(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + rGPR[_inst.RA] = uAddress; + } } void Interpreter::lhzx(UGeckoInstruction _inst) { - u32 temp = (u32)PowerPC::Read_U16(Helper_Get_EA_X(_inst)); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - } + u32 temp = (u32)PowerPC::Read_U16(Helper_Get_EA_X(_inst)); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + } } // TODO: is this right? // FIXME: Should rollback if a DSI occurs void Interpreter::lswx(UGeckoInstruction _inst) { - u32 EA = Helper_Get_EA_X(_inst); - u32 n = (u8)PowerPC::ppcState.xer_stringctrl; - int r = _inst.RD; - int i = 0; + u32 EA = Helper_Get_EA_X(_inst); + u32 n = (u8)PowerPC::ppcState.xer_stringctrl; + int r = _inst.RD; + int i = 0; - if (n > 0) - { - rGPR[r] = 0; - do - { - u32 TempValue = PowerPC::Read_U8(EA) << (24 - i); - if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) - { - PanicAlert("DSI exception in lswx."); - NOTICE_LOG(POWERPC, "DSI exception in lswx"); - return; - } - rGPR[r] |= TempValue; + if (n > 0) + { + rGPR[r] = 0; + do + { + u32 TempValue = PowerPC::Read_U8(EA) << (24 - i); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + PanicAlert("DSI exception in lswx."); + NOTICE_LOG(POWERPC, "DSI exception in lswx"); + return; + } + rGPR[r] |= TempValue; - EA++; - n--; - i += 8; - if (i == 32) - { - i = 0; - r = (r + 1) & 31; - rGPR[r] = 0; - } - } while (n > 0); - } + EA++; + n--; + i += 8; + if (i == 32) + { + i = 0; + r = (r + 1) & 31; + rGPR[r] = 0; + } + } while (n > 0); + } } void Interpreter::lwbrx(UGeckoInstruction _inst) { - u32 temp = Common::swap32(PowerPC::Read_U32(Helper_Get_EA_X(_inst))); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - } + u32 temp = Common::swap32(PowerPC::Read_U32(Helper_Get_EA_X(_inst))); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + } } void Interpreter::lwzux(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_UX(_inst); - u32 temp = PowerPC::Read_U32(uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_UX(_inst); + u32 temp = PowerPC::Read_U32(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + rGPR[_inst.RA] = uAddress; + } } void Interpreter::lwzx(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_X(_inst); - u32 temp = PowerPC::Read_U32(uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - } + u32 uAddress = Helper_Get_EA_X(_inst); + u32 temp = PowerPC::Read_U32(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + } } void Interpreter::stbux(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_UX(_inst); - PowerPC::Write_U8((u8)rGPR[_inst.RS], uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_UX(_inst); + PowerPC::Write_U8((u8)rGPR[_inst.RS], uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RA] = uAddress; + } } void Interpreter::stbx(UGeckoInstruction _inst) { - PowerPC::Write_U8((u8)rGPR[_inst.RS], Helper_Get_EA_X(_inst)); + PowerPC::Write_U8((u8)rGPR[_inst.RS], Helper_Get_EA_X(_inst)); } void Interpreter::stfdux(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_UX(_inst); - PowerPC::Write_U64(riPS0(_inst.FS), uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_UX(_inst); + PowerPC::Write_U64(riPS0(_inst.FS), uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RA] = uAddress; + } } void Interpreter::stfdx(UGeckoInstruction _inst) { - PowerPC::Write_U64(riPS0(_inst.FS), Helper_Get_EA_X(_inst)); + PowerPC::Write_U64(riPS0(_inst.FS), Helper_Get_EA_X(_inst)); } // Stores Floating points into Integers indeXed void Interpreter::stfiwx(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_X(_inst); + u32 uAddress = Helper_Get_EA_X(_inst); - PowerPC::Write_U32((u32)riPS0(_inst.FS), uAddress); + PowerPC::Write_U32((u32)riPS0(_inst.FS), uAddress); } - void Interpreter::stfsux(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_UX(_inst); - PowerPC::Write_U32(ConvertToSingle(riPS0(_inst.FS)), uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_UX(_inst); + PowerPC::Write_U32(ConvertToSingle(riPS0(_inst.FS)), uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RA] = uAddress; + } } void Interpreter::stfsx(UGeckoInstruction _inst) { - PowerPC::Write_U32(ConvertToSingle(riPS0(_inst.FS)), Helper_Get_EA_X(_inst)); + PowerPC::Write_U32(ConvertToSingle(riPS0(_inst.FS)), Helper_Get_EA_X(_inst)); } void Interpreter::sthbrx(UGeckoInstruction _inst) { - PowerPC::Write_U16(Common::swap16((u16)rGPR[_inst.RS]), Helper_Get_EA_X(_inst)); + PowerPC::Write_U16(Common::swap16((u16)rGPR[_inst.RS]), Helper_Get_EA_X(_inst)); } void Interpreter::sthux(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_UX(_inst); - PowerPC::Write_U16((u16)rGPR[_inst.RS], uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_UX(_inst); + PowerPC::Write_U16((u16)rGPR[_inst.RS], uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RA] = uAddress; + } } void Interpreter::sthx(UGeckoInstruction _inst) { - PowerPC::Write_U16((u16)rGPR[_inst.RS], Helper_Get_EA_X(_inst)); + PowerPC::Write_U16((u16)rGPR[_inst.RS], Helper_Get_EA_X(_inst)); } // __________________________________________________________________________________________________ @@ -637,44 +638,44 @@ void Interpreter::sthx(UGeckoInstruction _inst) // FIXME: Should rollback if a DSI occurs void Interpreter::lswi(UGeckoInstruction _inst) { - u32 EA; - if (_inst.RA == 0) - EA = 0; - else - EA = rGPR[_inst.RA]; + u32 EA; + if (_inst.RA == 0) + EA = 0; + else + EA = rGPR[_inst.RA]; - u32 n; - if (_inst.NB == 0) - n = 32; - else - n = _inst.NB; + u32 n; + if (_inst.NB == 0) + n = 32; + else + n = _inst.NB; - int r = _inst.RD - 1; - int i = 0; - while (n>0) - { - if (i==0) - { - r++; - r &= 31; - rGPR[r] = 0; - } + int r = _inst.RD - 1; + int i = 0; + while (n > 0) + { + if (i == 0) + { + r++; + r &= 31; + rGPR[r] = 0; + } - u32 TempValue = PowerPC::Read_U8(EA) << (24 - i); - if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) - { - PanicAlert("DSI exception in lsw."); - return; - } + u32 TempValue = PowerPC::Read_U8(EA) << (24 - i); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + PanicAlert("DSI exception in lsw."); + return; + } - rGPR[r] |= TempValue; + rGPR[r] |= TempValue; - i += 8; - if (i == 32) - i = 0; - EA++; - n--; - } + i += 8; + if (i == 32) + i = 0; + EA++; + n--; + } } // todo : optimize ? @@ -683,138 +684,137 @@ void Interpreter::lswi(UGeckoInstruction _inst) // FIXME: Should rollback if a DSI occurs void Interpreter::stswi(UGeckoInstruction _inst) { - u32 EA; - if (_inst.RA == 0) - EA = 0; - else - EA = rGPR[_inst.RA]; + u32 EA; + if (_inst.RA == 0) + EA = 0; + else + EA = rGPR[_inst.RA]; - u32 n; - if (_inst.NB == 0) - n = 32; - else - n = _inst.NB; + u32 n; + if (_inst.NB == 0) + n = 32; + else + n = _inst.NB; - int r = _inst.RS - 1; - int i = 0; - while (n > 0) - { - if (i == 0) - { - r++; - r &= 31; - } - PowerPC::Write_U8((rGPR[r] >> (24 - i)) & 0xFF, EA); - if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) - { - return; - } + int r = _inst.RS - 1; + int i = 0; + while (n > 0) + { + if (i == 0) + { + r++; + r &= 31; + } + PowerPC::Write_U8((rGPR[r] >> (24 - i)) & 0xFF, EA); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } - i += 8; - if (i == 32) - i = 0; - EA++; - n--; - } + i += 8; + if (i == 32) + i = 0; + EA++; + n--; + } } // TODO: is this right? is it DSI interruptible? void Interpreter::stswx(UGeckoInstruction _inst) { - u32 EA = Helper_Get_EA_X(_inst); - u32 n = (u8)PowerPC::ppcState.xer_stringctrl; - int r = _inst.RS; - int i = 0; + u32 EA = Helper_Get_EA_X(_inst); + u32 n = (u8)PowerPC::ppcState.xer_stringctrl; + int r = _inst.RS; + int i = 0; - while (n > 0) - { - PowerPC::Write_U8((rGPR[r] >> (24 - i)) & 0xFF, EA); + while (n > 0) + { + PowerPC::Write_U8((rGPR[r] >> (24 - i)) & 0xFF, EA); - EA++; - n--; - i += 8; - if (i == 32) - { - i = 0; - r++; - } - } + EA++; + n--; + i += 8; + if (i == 32) + { + i = 0; + r++; + } + } } void Interpreter::stwbrx(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_X(_inst); - PowerPC::Write_U32(Common::swap32(rGPR[_inst.RS]), uAddress); + u32 uAddress = Helper_Get_EA_X(_inst); + PowerPC::Write_U32(Common::swap32(rGPR[_inst.RS]), uAddress); } - // The following two instructions are for SMP communications. On a single // CPU, they cannot fail unless an interrupt happens in between. void Interpreter::lwarx(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_X(_inst); - u32 temp = PowerPC::Read_U32(uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RD] = temp; - g_bReserve = true; - g_reserveAddr = uAddress; - } + u32 uAddress = Helper_Get_EA_X(_inst); + u32 temp = PowerPC::Read_U32(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RD] = temp; + g_bReserve = true; + g_reserveAddr = uAddress; + } } void Interpreter::stwcxd(UGeckoInstruction _inst) { - // Stores Word Conditional indeXed - u32 uAddress; - if (g_bReserve) - { - uAddress = Helper_Get_EA_X(_inst); + // Stores Word Conditional indeXed + u32 uAddress; + if (g_bReserve) + { + uAddress = Helper_Get_EA_X(_inst); - if (uAddress == g_reserveAddr) - { - PowerPC::Write_U32(rGPR[_inst.RS], uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - g_bReserve = false; - SetCRField(0, 2 | GetXER_SO()); - return; - } - } - } + if (uAddress == g_reserveAddr) + { + PowerPC::Write_U32(rGPR[_inst.RS], uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + g_bReserve = false; + SetCRField(0, 2 | GetXER_SO()); + return; + } + } + } - SetCRField(0, GetXER_SO()); + SetCRField(0, GetXER_SO()); } void Interpreter::stwux(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_UX(_inst); - PowerPC::Write_U32(rGPR[_inst.RS], uAddress); - if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) - { - rGPR[_inst.RA] = uAddress; - } + u32 uAddress = Helper_Get_EA_UX(_inst); + PowerPC::Write_U32(rGPR[_inst.RS], uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + rGPR[_inst.RA] = uAddress; + } } void Interpreter::stwx(UGeckoInstruction _inst) { - u32 uAddress = Helper_Get_EA_X(_inst); - PowerPC::Write_U32(rGPR[_inst.RS], uAddress); + u32 uAddress = Helper_Get_EA_X(_inst); + PowerPC::Write_U32(rGPR[_inst.RS], uAddress); } void Interpreter::sync(UGeckoInstruction _inst) { - //ignored + // ignored } void Interpreter::tlbie(UGeckoInstruction _inst) { - // Invalidate TLB entry - u32 _Address = rGPR[_inst.RB]; - PowerPC::InvalidateTLBEntry(_Address); + // Invalidate TLB entry + u32 _Address = rGPR[_inst.RB]; + PowerPC::InvalidateTLBEntry(_Address); } void Interpreter::tlbsync(UGeckoInstruction _inst) { - //MessageBox(0,"TLBsync","TLBsyncE",0); + // MessageBox(0,"TLBsync","TLBsyncE",0); } diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStorePaired.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStorePaired.cpp index df22d4b29e..b03e11f521 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStorePaired.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStorePaired.cpp @@ -9,347 +9,360 @@ #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/MathUtil.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/Interpreter/Interpreter.h" #include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h" +#include "Core/PowerPC/PowerPC.h" // dequantize table -const float m_dequantizeTable[] = -{ - 1.0 / (1ULL << 0), 1.0 / (1ULL << 1), 1.0 / (1ULL << 2), 1.0 / (1ULL << 3), - 1.0 / (1ULL << 4), 1.0 / (1ULL << 5), 1.0 / (1ULL << 6), 1.0 / (1ULL << 7), - 1.0 / (1ULL << 8), 1.0 / (1ULL << 9), 1.0 / (1ULL << 10), 1.0 / (1ULL << 11), - 1.0 / (1ULL << 12), 1.0 / (1ULL << 13), 1.0 / (1ULL << 14), 1.0 / (1ULL << 15), - 1.0 / (1ULL << 16), 1.0 / (1ULL << 17), 1.0 / (1ULL << 18), 1.0 / (1ULL << 19), - 1.0 / (1ULL << 20), 1.0 / (1ULL << 21), 1.0 / (1ULL << 22), 1.0 / (1ULL << 23), - 1.0 / (1ULL << 24), 1.0 / (1ULL << 25), 1.0 / (1ULL << 26), 1.0 / (1ULL << 27), - 1.0 / (1ULL << 28), 1.0 / (1ULL << 29), 1.0 / (1ULL << 30), 1.0 / (1ULL << 31), - (1ULL << 32), (1ULL << 31), (1ULL << 30), (1ULL << 29), - (1ULL << 28), (1ULL << 27), (1ULL << 26), (1ULL << 25), - (1ULL << 24), (1ULL << 23), (1ULL << 22), (1ULL << 21), - (1ULL << 20), (1ULL << 19), (1ULL << 18), (1ULL << 17), - (1ULL << 16), (1ULL << 15), (1ULL << 14), (1ULL << 13), - (1ULL << 12), (1ULL << 11), (1ULL << 10), (1ULL << 9), - (1ULL << 8), (1ULL << 7), (1ULL << 6), (1ULL << 5), - (1ULL << 4), (1ULL << 3), (1ULL << 2), (1ULL << 1), +const float m_dequantizeTable[] = { + 1.0 / (1ULL << 0), 1.0 / (1ULL << 1), 1.0 / (1ULL << 2), 1.0 / (1ULL << 3), + 1.0 / (1ULL << 4), 1.0 / (1ULL << 5), 1.0 / (1ULL << 6), 1.0 / (1ULL << 7), + 1.0 / (1ULL << 8), 1.0 / (1ULL << 9), 1.0 / (1ULL << 10), 1.0 / (1ULL << 11), + 1.0 / (1ULL << 12), 1.0 / (1ULL << 13), 1.0 / (1ULL << 14), 1.0 / (1ULL << 15), + 1.0 / (1ULL << 16), 1.0 / (1ULL << 17), 1.0 / (1ULL << 18), 1.0 / (1ULL << 19), + 1.0 / (1ULL << 20), 1.0 / (1ULL << 21), 1.0 / (1ULL << 22), 1.0 / (1ULL << 23), + 1.0 / (1ULL << 24), 1.0 / (1ULL << 25), 1.0 / (1ULL << 26), 1.0 / (1ULL << 27), + 1.0 / (1ULL << 28), 1.0 / (1ULL << 29), 1.0 / (1ULL << 30), 1.0 / (1ULL << 31), + (1ULL << 32), (1ULL << 31), (1ULL << 30), (1ULL << 29), + (1ULL << 28), (1ULL << 27), (1ULL << 26), (1ULL << 25), + (1ULL << 24), (1ULL << 23), (1ULL << 22), (1ULL << 21), + (1ULL << 20), (1ULL << 19), (1ULL << 18), (1ULL << 17), + (1ULL << 16), (1ULL << 15), (1ULL << 14), (1ULL << 13), + (1ULL << 12), (1ULL << 11), (1ULL << 10), (1ULL << 9), + (1ULL << 8), (1ULL << 7), (1ULL << 6), (1ULL << 5), + (1ULL << 4), (1ULL << 3), (1ULL << 2), (1ULL << 1), }; // quantize table -const float m_quantizeTable[] = -{ - (1ULL << 0), (1ULL << 1), (1ULL << 2), (1ULL << 3), - (1ULL << 4), (1ULL << 5), (1ULL << 6), (1ULL << 7), - (1ULL << 8), (1ULL << 9), (1ULL << 10), (1ULL << 11), - (1ULL << 12), (1ULL << 13), (1ULL << 14), (1ULL << 15), - (1ULL << 16), (1ULL << 17), (1ULL << 18), (1ULL << 19), - (1ULL << 20), (1ULL << 21), (1ULL << 22), (1ULL << 23), - (1ULL << 24), (1ULL << 25), (1ULL << 26), (1ULL << 27), - (1ULL << 28), (1ULL << 29), (1ULL << 30), (1ULL << 31), - 1.0 / (1ULL << 32), 1.0 / (1ULL << 31), 1.0 / (1ULL << 30), 1.0 / (1ULL << 29), - 1.0 / (1ULL << 28), 1.0 / (1ULL << 27), 1.0 / (1ULL << 26), 1.0 / (1ULL << 25), - 1.0 / (1ULL << 24), 1.0 / (1ULL << 23), 1.0 / (1ULL << 22), 1.0 / (1ULL << 21), - 1.0 / (1ULL << 20), 1.0 / (1ULL << 19), 1.0 / (1ULL << 18), 1.0 / (1ULL << 17), - 1.0 / (1ULL << 16), 1.0 / (1ULL << 15), 1.0 / (1ULL << 14), 1.0 / (1ULL << 13), - 1.0 / (1ULL << 12), 1.0 / (1ULL << 11), 1.0 / (1ULL << 10), 1.0 / (1ULL << 9), - 1.0 / (1ULL << 8), 1.0 / (1ULL << 7), 1.0 / (1ULL << 6), 1.0 / (1ULL << 5), - 1.0 / (1ULL << 4), 1.0 / (1ULL << 3), 1.0 / (1ULL << 2), 1.0 / (1ULL << 1), +const float m_quantizeTable[] = { + (1ULL << 0), (1ULL << 1), (1ULL << 2), (1ULL << 3), + (1ULL << 4), (1ULL << 5), (1ULL << 6), (1ULL << 7), + (1ULL << 8), (1ULL << 9), (1ULL << 10), (1ULL << 11), + (1ULL << 12), (1ULL << 13), (1ULL << 14), (1ULL << 15), + (1ULL << 16), (1ULL << 17), (1ULL << 18), (1ULL << 19), + (1ULL << 20), (1ULL << 21), (1ULL << 22), (1ULL << 23), + (1ULL << 24), (1ULL << 25), (1ULL << 26), (1ULL << 27), + (1ULL << 28), (1ULL << 29), (1ULL << 30), (1ULL << 31), + 1.0 / (1ULL << 32), 1.0 / (1ULL << 31), 1.0 / (1ULL << 30), 1.0 / (1ULL << 29), + 1.0 / (1ULL << 28), 1.0 / (1ULL << 27), 1.0 / (1ULL << 26), 1.0 / (1ULL << 25), + 1.0 / (1ULL << 24), 1.0 / (1ULL << 23), 1.0 / (1ULL << 22), 1.0 / (1ULL << 21), + 1.0 / (1ULL << 20), 1.0 / (1ULL << 19), 1.0 / (1ULL << 18), 1.0 / (1ULL << 17), + 1.0 / (1ULL << 16), 1.0 / (1ULL << 15), 1.0 / (1ULL << 14), 1.0 / (1ULL << 13), + 1.0 / (1ULL << 12), 1.0 / (1ULL << 11), 1.0 / (1ULL << 10), 1.0 / (1ULL << 9), + 1.0 / (1ULL << 8), 1.0 / (1ULL << 7), 1.0 / (1ULL << 6), 1.0 / (1ULL << 5), + 1.0 / (1ULL << 4), 1.0 / (1ULL << 3), 1.0 / (1ULL << 2), 1.0 / (1ULL << 1), }; -template SType ScaleAndClamp(double ps, u32 stScale) +template +SType ScaleAndClamp(double ps, u32 stScale) { - float convPS = (float)ps * m_quantizeTable[stScale]; - float min = (float)std::numeric_limits::min(); - float max = (float)std::numeric_limits::max(); + float convPS = (float)ps * m_quantizeTable[stScale]; + float min = (float)std::numeric_limits::min(); + float max = (float)std::numeric_limits::max(); - return (SType)MathUtil::Clamp(convPS, min, max); + return (SType)MathUtil::Clamp(convPS, min, max); } -template static T ReadUnpaired(u32 addr); +template +static T ReadUnpaired(u32 addr); -template<> u8 ReadUnpaired(u32 addr) +template <> +u8 ReadUnpaired(u32 addr) { - return PowerPC::Read_U8(addr); + return PowerPC::Read_U8(addr); } -template<> u16 ReadUnpaired(u32 addr) +template <> +u16 ReadUnpaired(u32 addr) { - return PowerPC::Read_U16(addr); + return PowerPC::Read_U16(addr); } -template<> u32 ReadUnpaired(u32 addr) +template <> +u32 ReadUnpaired(u32 addr) { - return PowerPC::Read_U32(addr); + return PowerPC::Read_U32(addr); } -template static std::pair ReadPair(u32 addr); +template +static std::pair ReadPair(u32 addr); -template<> std::pair ReadPair(u32 addr) +template <> +std::pair ReadPair(u32 addr) { - u16 val = PowerPC::Read_U16(addr); - return { (u8)(val >> 8), (u8)val }; + u16 val = PowerPC::Read_U16(addr); + return {(u8)(val >> 8), (u8)val}; } -template<> std::pair ReadPair(u32 addr) +template <> +std::pair ReadPair(u32 addr) { - u32 val = PowerPC::Read_U32(addr); - return { (u16)(val >> 16), (u16)val }; + u32 val = PowerPC::Read_U32(addr); + return {(u16)(val >> 16), (u16)val}; } -template<> std::pair ReadPair(u32 addr) +template <> +std::pair ReadPair(u32 addr) { - u64 val = PowerPC::Read_U64(addr); - return { (u32)(val >> 32), (u32)val }; + u64 val = PowerPC::Read_U64(addr); + return {(u32)(val >> 32), (u32)val}; } -template static void WriteUnpaired(T val, u32 addr); +template +static void WriteUnpaired(T val, u32 addr); -template<> void WriteUnpaired(u8 val, u32 addr) +template <> +void WriteUnpaired(u8 val, u32 addr) { - PowerPC::Write_U8(val, addr); + PowerPC::Write_U8(val, addr); } -template<> void WriteUnpaired(u16 val, u32 addr) +template <> +void WriteUnpaired(u16 val, u32 addr) { - PowerPC::Write_U16(val, addr); + PowerPC::Write_U16(val, addr); } -template<> void WriteUnpaired(u32 val, u32 addr) +template <> +void WriteUnpaired(u32 val, u32 addr) { - PowerPC::Write_U32(val, addr); + PowerPC::Write_U32(val, addr); } -template static void WritePair(T val1, T val2, u32 addr); +template +static void WritePair(T val1, T val2, u32 addr); -template<> void WritePair(u8 val1, u8 val2, u32 addr) +template <> +void WritePair(u8 val1, u8 val2, u32 addr) { - PowerPC::Write_U16(((u16)val1 << 8) | (u16)val2, addr); + PowerPC::Write_U16(((u16)val1 << 8) | (u16)val2, addr); } -template<> void WritePair(u16 val1, u16 val2, u32 addr) +template <> +void WritePair(u16 val1, u16 val2, u32 addr) { - PowerPC::Write_U32(((u32)val1 << 16) | (u32)val2, addr); + PowerPC::Write_U32(((u32)val1 << 16) | (u32)val2, addr); } -template<> void WritePair(u32 val1, u32 val2, u32 addr) +template <> +void WritePair(u32 val1, u32 val2, u32 addr) { - PowerPC::Write_U64(((u64)val1 << 32) | (u64)val2, addr); + PowerPC::Write_U64(((u64)val1 << 32) | (u64)val2, addr); } -template +template void QuantizeAndStore(double ps0, double ps1, u32 addr, u32 instW, u32 stScale) { - typedef typename std::make_unsigned::type U; - U convPS0 = (U)ScaleAndClamp(ps0, stScale); - if (instW) - { - WriteUnpaired(convPS0, addr); - } - else - { - U convPS1 = (U)ScaleAndClamp(ps1, stScale); - WritePair(convPS0, convPS1, addr); - } + typedef typename std::make_unsigned::type U; + U convPS0 = (U)ScaleAndClamp(ps0, stScale); + if (instW) + { + WriteUnpaired(convPS0, addr); + } + else + { + U convPS1 = (U)ScaleAndClamp(ps1, stScale); + WritePair(convPS0, convPS1, addr); + } } void Interpreter::Helper_Quantize(u32 addr, u32 instI, u32 instRS, u32 instW) { - const UGQR gqr(rSPR(SPR_GQR0 + instI)); - const EQuantizeType stType = gqr.st_type; - const unsigned int stScale = gqr.st_scale; + const UGQR gqr(rSPR(SPR_GQR0 + instI)); + const EQuantizeType stType = gqr.st_type; + const unsigned int stScale = gqr.st_scale; - double ps0 = rPS0(instRS); - double ps1 = rPS1(instRS); - switch (stType) - { - case QUANTIZE_FLOAT: - { - u32 convPS0 = ConvertToSingleFTZ(MathUtil::IntDouble(ps0).i); - if (instW) - { - WriteUnpaired(convPS0, addr); - } - else - { - u32 convPS1 = ConvertToSingleFTZ(MathUtil::IntDouble(ps1).i); - WritePair(convPS0, convPS1, addr); - } - break; - } + double ps0 = rPS0(instRS); + double ps1 = rPS1(instRS); + switch (stType) + { + case QUANTIZE_FLOAT: + { + u32 convPS0 = ConvertToSingleFTZ(MathUtil::IntDouble(ps0).i); + if (instW) + { + WriteUnpaired(convPS0, addr); + } + else + { + u32 convPS1 = ConvertToSingleFTZ(MathUtil::IntDouble(ps1).i); + WritePair(convPS0, convPS1, addr); + } + break; + } - case QUANTIZE_U8: - QuantizeAndStore(ps0, ps1, addr, instW, stScale); - break; + case QUANTIZE_U8: + QuantizeAndStore(ps0, ps1, addr, instW, stScale); + break; - case QUANTIZE_U16: - QuantizeAndStore(ps0, ps1, addr, instW, stScale); - break; + case QUANTIZE_U16: + QuantizeAndStore(ps0, ps1, addr, instW, stScale); + break; - case QUANTIZE_S8: - QuantizeAndStore(ps0, ps1, addr, instW, stScale); - break; + case QUANTIZE_S8: + QuantizeAndStore(ps0, ps1, addr, instW, stScale); + break; - case QUANTIZE_S16: - QuantizeAndStore(ps0, ps1, addr, instW, stScale); - break; + case QUANTIZE_S16: + QuantizeAndStore(ps0, ps1, addr, instW, stScale); + break; - case QUANTIZE_INVALID1: - case QUANTIZE_INVALID2: - case QUANTIZE_INVALID3: - _assert_msg_(POWERPC, 0, "PS dequantize - unknown type to read"); - break; - } + case QUANTIZE_INVALID1: + case QUANTIZE_INVALID2: + case QUANTIZE_INVALID3: + _assert_msg_(POWERPC, 0, "PS dequantize - unknown type to read"); + break; + } } -template +template std::pair LoadAndDequantize(u32 addr, u32 instW, u32 ldScale) { - typedef typename std::make_unsigned::type U; - float ps0, ps1; - if (instW) - { - U value = ReadUnpaired(addr); - ps0 = (float)(T)(value) * m_dequantizeTable[ldScale]; - ps1 = 1.0f; - } - else - { - std::pair value = ReadPair(addr); - ps0 = (float)(T)(value.first) * m_dequantizeTable[ldScale]; - ps1 = (float)(T)(value.second) * m_dequantizeTable[ldScale]; - } - return { ps0, ps1 }; + typedef typename std::make_unsigned::type U; + float ps0, ps1; + if (instW) + { + U value = ReadUnpaired(addr); + ps0 = (float)(T)(value)*m_dequantizeTable[ldScale]; + ps1 = 1.0f; + } + else + { + std::pair value = ReadPair(addr); + ps0 = (float)(T)(value.first) * m_dequantizeTable[ldScale]; + ps1 = (float)(T)(value.second) * m_dequantizeTable[ldScale]; + } + return {ps0, ps1}; } void Interpreter::Helper_Dequantize(u32 addr, u32 instI, u32 instRD, u32 instW) { - UGQR gqr(rSPR(SPR_GQR0 + instI)); - EQuantizeType ldType = gqr.ld_type; - unsigned int ldScale = gqr.ld_scale; + UGQR gqr(rSPR(SPR_GQR0 + instI)); + EQuantizeType ldType = gqr.ld_type; + unsigned int ldScale = gqr.ld_scale; - float ps0 = 0.0f; - float ps1 = 0.0f; + float ps0 = 0.0f; + float ps1 = 0.0f; - switch (ldType) - { - case QUANTIZE_FLOAT: - if (instW) - { - u32 value = ReadUnpaired(addr); - ps0 = MathUtil::IntFloat(value).f; - ps1 = 1.0f; - } - else - { - std::pair value = ReadPair(addr); - ps0 = MathUtil::IntFloat(value.first).f; - ps1 = MathUtil::IntFloat(value.second).f; - } - break; + switch (ldType) + { + case QUANTIZE_FLOAT: + if (instW) + { + u32 value = ReadUnpaired(addr); + ps0 = MathUtil::IntFloat(value).f; + ps1 = 1.0f; + } + else + { + std::pair value = ReadPair(addr); + ps0 = MathUtil::IntFloat(value.first).f; + ps1 = MathUtil::IntFloat(value.second).f; + } + break; - case QUANTIZE_U8: - std::tie(ps0, ps1) = LoadAndDequantize(addr, instW, ldScale); - break; + case QUANTIZE_U8: + std::tie(ps0, ps1) = LoadAndDequantize(addr, instW, ldScale); + break; - case QUANTIZE_U16: - std::tie(ps0, ps1) = LoadAndDequantize(addr, instW, ldScale); - break; + case QUANTIZE_U16: + std::tie(ps0, ps1) = LoadAndDequantize(addr, instW, ldScale); + break; - case QUANTIZE_S8: - std::tie(ps0, ps1) = LoadAndDequantize(addr, instW, ldScale); - break; + case QUANTIZE_S8: + std::tie(ps0, ps1) = LoadAndDequantize(addr, instW, ldScale); + break; - case QUANTIZE_S16: - std::tie(ps0, ps1) = LoadAndDequantize(addr, instW, ldScale); - break; + case QUANTIZE_S16: + std::tie(ps0, ps1) = LoadAndDequantize(addr, instW, ldScale); + break; - case QUANTIZE_INVALID1: - case QUANTIZE_INVALID2: - case QUANTIZE_INVALID3: - _assert_msg_(POWERPC, 0, "PS dequantize - unknown type to read"); - ps0 = 0.f; - ps1 = 0.f; - break; - } + case QUANTIZE_INVALID1: + case QUANTIZE_INVALID2: + case QUANTIZE_INVALID3: + _assert_msg_(POWERPC, 0, "PS dequantize - unknown type to read"); + ps0 = 0.f; + ps1 = 0.f; + break; + } - if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) - { - return; - } + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } - rPS0(instRD) = ps0; - rPS1(instRD) = ps1; + rPS0(instRD) = ps0; + rPS1(instRD) = ps1; } void Interpreter::psq_l(UGeckoInstruction _inst) { - const u32 EA = _inst.RA ? - (rGPR[_inst.RA] + _inst.SIMM_12) : (u32)_inst.SIMM_12; - Helper_Dequantize(EA, _inst.I, _inst.RD, _inst.W); + const u32 EA = _inst.RA ? (rGPR[_inst.RA] + _inst.SIMM_12) : (u32)_inst.SIMM_12; + Helper_Dequantize(EA, _inst.I, _inst.RD, _inst.W); } void Interpreter::psq_lu(UGeckoInstruction _inst) { - const u32 EA = rGPR[_inst.RA] + _inst.SIMM_12; - Helper_Dequantize(EA, _inst.I, _inst.RD, _inst.W); + const u32 EA = rGPR[_inst.RA] + _inst.SIMM_12; + Helper_Dequantize(EA, _inst.I, _inst.RD, _inst.W); - if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) - { - return; - } - rGPR[_inst.RA] = EA; + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } + rGPR[_inst.RA] = EA; } void Interpreter::psq_st(UGeckoInstruction _inst) { - const u32 EA = _inst.RA ? - (rGPR[_inst.RA] + _inst.SIMM_12) : (u32)_inst.SIMM_12; - Helper_Quantize(EA, _inst.I, _inst.RS, _inst.W); + const u32 EA = _inst.RA ? (rGPR[_inst.RA] + _inst.SIMM_12) : (u32)_inst.SIMM_12; + Helper_Quantize(EA, _inst.I, _inst.RS, _inst.W); } void Interpreter::psq_stu(UGeckoInstruction _inst) { - const u32 EA = rGPR[_inst.RA] + _inst.SIMM_12; - Helper_Quantize(EA, _inst.I, _inst.RS, _inst.W); + const u32 EA = rGPR[_inst.RA] + _inst.SIMM_12; + Helper_Quantize(EA, _inst.I, _inst.RS, _inst.W); - if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) - { - return; - } - rGPR[_inst.RA] = EA; + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } + rGPR[_inst.RA] = EA; } void Interpreter::psq_lx(UGeckoInstruction _inst) { - const u32 EA = _inst.RA ? (rGPR[_inst.RA] + rGPR[_inst.RB]) : rGPR[_inst.RB]; - Helper_Dequantize(EA, _inst.Ix, _inst.RD, _inst.Wx); + const u32 EA = _inst.RA ? (rGPR[_inst.RA] + rGPR[_inst.RB]) : rGPR[_inst.RB]; + Helper_Dequantize(EA, _inst.Ix, _inst.RD, _inst.Wx); } void Interpreter::psq_stx(UGeckoInstruction _inst) { - const u32 EA = _inst.RA ? (rGPR[_inst.RA] + rGPR[_inst.RB]) : rGPR[_inst.RB]; - Helper_Quantize(EA, _inst.Ix, _inst.RS, _inst.Wx); + const u32 EA = _inst.RA ? (rGPR[_inst.RA] + rGPR[_inst.RB]) : rGPR[_inst.RB]; + Helper_Quantize(EA, _inst.Ix, _inst.RS, _inst.Wx); } void Interpreter::psq_lux(UGeckoInstruction _inst) { - const u32 EA = rGPR[_inst.RA] + rGPR[_inst.RB]; - Helper_Dequantize(EA, _inst.Ix, _inst.RD, _inst.Wx); + const u32 EA = rGPR[_inst.RA] + rGPR[_inst.RB]; + Helper_Dequantize(EA, _inst.Ix, _inst.RD, _inst.Wx); - if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) - { - return; - } - rGPR[_inst.RA] = EA; + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } + rGPR[_inst.RA] = EA; } void Interpreter::psq_stux(UGeckoInstruction _inst) { - const u32 EA = rGPR[_inst.RA] + rGPR[_inst.RB]; - Helper_Quantize(EA, _inst.Ix, _inst.RS, _inst.Wx); + const u32 EA = rGPR[_inst.RA] + rGPR[_inst.RB]; + Helper_Quantize(EA, _inst.Ix, _inst.RS, _inst.Wx); - if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) - { - return; - } - rGPR[_inst.RA] = EA; + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } + rGPR[_inst.RA] = EA; } diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp index 3190c7eae1..597096e14b 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp @@ -6,334 +6,332 @@ #include "Common/CommonTypes.h" #include "Common/MathUtil.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/Interpreter/Interpreter.h" #include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h" +#include "Core/PowerPC/PowerPC.h" using namespace MathUtil; // These "binary instructions" do not alter FPSCR. void Interpreter::ps_sel(UGeckoInstruction _inst) { - rPS0(_inst.FD) = rPS0(_inst.FA) >= -0.0 ? rPS0(_inst.FC) : rPS0(_inst.FB); - rPS1(_inst.FD) = rPS1(_inst.FA) >= -0.0 ? rPS1(_inst.FC) : rPS1(_inst.FB); + rPS0(_inst.FD) = rPS0(_inst.FA) >= -0.0 ? rPS0(_inst.FC) : rPS0(_inst.FB); + rPS1(_inst.FD) = rPS1(_inst.FA) >= -0.0 ? rPS1(_inst.FC) : rPS1(_inst.FB); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_neg(UGeckoInstruction _inst) { - riPS0(_inst.FD) = riPS0(_inst.FB) ^ (1ULL << 63); - riPS1(_inst.FD) = riPS1(_inst.FB) ^ (1ULL << 63); + riPS0(_inst.FD) = riPS0(_inst.FB) ^ (1ULL << 63); + riPS1(_inst.FD) = riPS1(_inst.FB) ^ (1ULL << 63); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_mr(UGeckoInstruction _inst) { - rPS0(_inst.FD) = rPS0(_inst.FB); - rPS1(_inst.FD) = rPS1(_inst.FB); + rPS0(_inst.FD) = rPS0(_inst.FB); + rPS1(_inst.FD) = rPS1(_inst.FB); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_nabs(UGeckoInstruction _inst) { - riPS0(_inst.FD) = riPS0(_inst.FB) | (1ULL << 63); - riPS1(_inst.FD) = riPS1(_inst.FB) | (1ULL << 63); + riPS0(_inst.FD) = riPS0(_inst.FB) | (1ULL << 63); + riPS1(_inst.FD) = riPS1(_inst.FB) | (1ULL << 63); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_abs(UGeckoInstruction _inst) { - riPS0(_inst.FD) = riPS0(_inst.FB) & ~(1ULL << 63); - riPS1(_inst.FD) = riPS1(_inst.FB) & ~(1ULL << 63); + riPS0(_inst.FD) = riPS0(_inst.FB) & ~(1ULL << 63); + riPS1(_inst.FD) = riPS1(_inst.FB) & ~(1ULL << 63); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } // These are just moves, double is OK. void Interpreter::ps_merge00(UGeckoInstruction _inst) { - double p0 = rPS0(_inst.FA); - double p1 = rPS0(_inst.FB); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; + double p0 = rPS0(_inst.FA); + double p1 = rPS0(_inst.FB); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_merge01(UGeckoInstruction _inst) { - double p0 = rPS0(_inst.FA); - double p1 = rPS1(_inst.FB); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; + double p0 = rPS0(_inst.FA); + double p1 = rPS1(_inst.FB); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_merge10(UGeckoInstruction _inst) { - double p0 = rPS1(_inst.FA); - double p1 = rPS0(_inst.FB); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; + double p0 = rPS1(_inst.FA); + double p1 = rPS0(_inst.FB); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_merge11(UGeckoInstruction _inst) { - double p0 = rPS1(_inst.FA); - double p1 = rPS1(_inst.FB); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; + double p0 = rPS1(_inst.FA); + double p1 = rPS1(_inst.FB); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } // From here on, the real deal. void Interpreter::ps_div(UGeckoInstruction _inst) { - rPS0(_inst.FD) = ForceSingle(NI_div(rPS0(_inst.FA), rPS0(_inst.FB))); - rPS1(_inst.FD) = ForceSingle(NI_div(rPS1(_inst.FA), rPS1(_inst.FB))); - UpdateFPRF(rPS0(_inst.FD)); + rPS0(_inst.FD) = ForceSingle(NI_div(rPS0(_inst.FA), rPS0(_inst.FB))); + rPS1(_inst.FD) = ForceSingle(NI_div(rPS1(_inst.FA), rPS1(_inst.FB))); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_res(UGeckoInstruction _inst) { - // this code is based on the real hardware tests - double a = rPS0(_inst.FB); - double b = rPS1(_inst.FB); + // this code is based on the real hardware tests + double a = rPS0(_inst.FB); + double b = rPS1(_inst.FB); - if (a == 0.0 || b == 0.0) - { - SetFPException(FPSCR_ZX); - } + if (a == 0.0 || b == 0.0) + { + SetFPException(FPSCR_ZX); + } - rPS0(_inst.FD) = ApproximateReciprocal(a); - rPS1(_inst.FD) = ApproximateReciprocal(b); - UpdateFPRF(rPS0(_inst.FD)); + rPS0(_inst.FD) = ApproximateReciprocal(a); + rPS1(_inst.FD) = ApproximateReciprocal(b); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_rsqrte(UGeckoInstruction _inst) { - if (rPS0(_inst.FB) == 0.0 || rPS1(_inst.FB) == 0.0) - { - SetFPException(FPSCR_ZX); - } + if (rPS0(_inst.FB) == 0.0 || rPS1(_inst.FB) == 0.0) + { + SetFPException(FPSCR_ZX); + } - if (rPS0(_inst.FB) < 0.0 || rPS1(_inst.FB) < 0.0) - { - SetFPException(FPSCR_VXSQRT); - } + if (rPS0(_inst.FB) < 0.0 || rPS1(_inst.FB) < 0.0) + { + SetFPException(FPSCR_VXSQRT); + } - rPS0(_inst.FD) = ForceSingle(ApproximateReciprocalSquareRoot(rPS0(_inst.FB))); - rPS1(_inst.FD) = ForceSingle(ApproximateReciprocalSquareRoot(rPS1(_inst.FB))); + rPS0(_inst.FD) = ForceSingle(ApproximateReciprocalSquareRoot(rPS0(_inst.FB))); + rPS1(_inst.FD) = ForceSingle(ApproximateReciprocalSquareRoot(rPS1(_inst.FB))); - UpdateFPRF(rPS0(_inst.FD)); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } - void Interpreter::ps_sub(UGeckoInstruction _inst) { - rPS0(_inst.FD) = ForceSingle(NI_sub(rPS0(_inst.FA), rPS0(_inst.FB))); - rPS1(_inst.FD) = ForceSingle(NI_sub(rPS1(_inst.FA), rPS1(_inst.FB))); - UpdateFPRF(rPS0(_inst.FD)); + rPS0(_inst.FD) = ForceSingle(NI_sub(rPS0(_inst.FA), rPS0(_inst.FB))); + rPS1(_inst.FD) = ForceSingle(NI_sub(rPS1(_inst.FA), rPS1(_inst.FB))); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_add(UGeckoInstruction _inst) { - rPS0(_inst.FD) = ForceSingle(NI_add(rPS0(_inst.FA), rPS0(_inst.FB))); - rPS1(_inst.FD) = ForceSingle(NI_add(rPS1(_inst.FA), rPS1(_inst.FB))); - UpdateFPRF(rPS0(_inst.FD)); + rPS0(_inst.FD) = ForceSingle(NI_add(rPS0(_inst.FA), rPS0(_inst.FB))); + rPS1(_inst.FD) = ForceSingle(NI_add(rPS1(_inst.FA), rPS1(_inst.FB))); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_mul(UGeckoInstruction _inst) { - double c0 = Force25Bit(rPS0(_inst.FC)); - double c1 = Force25Bit(rPS1(_inst.FC)); - rPS0(_inst.FD) = ForceSingle(NI_mul(rPS0(_inst.FA), c0)); - rPS1(_inst.FD) = ForceSingle(NI_mul(rPS1(_inst.FA), c1)); - UpdateFPRF(rPS0(_inst.FD)); + double c0 = Force25Bit(rPS0(_inst.FC)); + double c1 = Force25Bit(rPS1(_inst.FC)); + rPS0(_inst.FD) = ForceSingle(NI_mul(rPS0(_inst.FA), c0)); + rPS1(_inst.FD) = ForceSingle(NI_mul(rPS1(_inst.FA), c1)); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } - void Interpreter::ps_msub(UGeckoInstruction _inst) { - double c0 = Force25Bit(rPS0(_inst.FC)); - double c1 = Force25Bit(rPS1(_inst.FC)); - rPS0(_inst.FD) = ForceSingle(NI_msub(rPS0(_inst.FA), c0, rPS0(_inst.FB))); - rPS1(_inst.FD) = ForceSingle(NI_msub(rPS1(_inst.FA), c1, rPS1(_inst.FB))); - UpdateFPRF(rPS0(_inst.FD)); + double c0 = Force25Bit(rPS0(_inst.FC)); + double c1 = Force25Bit(rPS1(_inst.FC)); + rPS0(_inst.FD) = ForceSingle(NI_msub(rPS0(_inst.FA), c0, rPS0(_inst.FB))); + rPS1(_inst.FD) = ForceSingle(NI_msub(rPS1(_inst.FA), c1, rPS1(_inst.FB))); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_madd(UGeckoInstruction _inst) { - double c0 = Force25Bit(rPS0(_inst.FC)); - double c1 = Force25Bit(rPS1(_inst.FC)); - rPS0(_inst.FD) = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB))); - rPS1(_inst.FD) = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB))); - UpdateFPRF(rPS0(_inst.FD)); + double c0 = Force25Bit(rPS0(_inst.FC)); + double c1 = Force25Bit(rPS1(_inst.FC)); + rPS0(_inst.FD) = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB))); + rPS1(_inst.FD) = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB))); + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_nmsub(UGeckoInstruction _inst) { - double c0 = Force25Bit(rPS0(_inst.FC)); - double c1 = Force25Bit(rPS1(_inst.FC)); - double result0 = ForceSingle(NI_msub(rPS0(_inst.FA), c0, rPS0(_inst.FB))); - double result1 = ForceSingle(NI_msub(rPS1(_inst.FA), c1, rPS1(_inst.FB))); - rPS0(_inst.FD) = std::isnan(result0) ? result0 : -result0; - rPS1(_inst.FD) = std::isnan(result1) ? result1 : -result1; - UpdateFPRF(rPS0(_inst.FD)); + double c0 = Force25Bit(rPS0(_inst.FC)); + double c1 = Force25Bit(rPS1(_inst.FC)); + double result0 = ForceSingle(NI_msub(rPS0(_inst.FA), c0, rPS0(_inst.FB))); + double result1 = ForceSingle(NI_msub(rPS1(_inst.FA), c1, rPS1(_inst.FB))); + rPS0(_inst.FD) = std::isnan(result0) ? result0 : -result0; + rPS1(_inst.FD) = std::isnan(result1) ? result1 : -result1; + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_nmadd(UGeckoInstruction _inst) { - double c0 = Force25Bit(rPS0(_inst.FC)); - double c1 = Force25Bit(rPS1(_inst.FC)); - double result0 = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB))); - double result1 = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB))); - rPS0(_inst.FD) = std::isnan(result0) ? result0 : -result0; - rPS1(_inst.FD) = std::isnan(result1) ? result1 : -result1; - UpdateFPRF(rPS0(_inst.FD)); + double c0 = Force25Bit(rPS0(_inst.FC)); + double c1 = Force25Bit(rPS1(_inst.FC)); + double result0 = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB))); + double result1 = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB))); + rPS0(_inst.FD) = std::isnan(result0) ? result0 : -result0; + rPS1(_inst.FD) = std::isnan(result1) ? result1 : -result1; + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_sum0(UGeckoInstruction _inst) { - double p0 = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB))); - double p1 = ForceSingle(rPS1(_inst.FC)); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; - UpdateFPRF(rPS0(_inst.FD)); + double p0 = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB))); + double p1 = ForceSingle(rPS1(_inst.FC)); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_sum1(UGeckoInstruction _inst) { - double p0 = ForceSingle(rPS0(_inst.FC)); - double p1 = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB))); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; - UpdateFPRF(rPS1(_inst.FD)); + double p0 = ForceSingle(rPS0(_inst.FC)); + double p1 = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB))); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; + UpdateFPRF(rPS1(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_muls0(UGeckoInstruction _inst) { - double c0 = Force25Bit(rPS0(_inst.FC)); - double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c0)); - double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c0)); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; - UpdateFPRF(rPS0(_inst.FD)); + double c0 = Force25Bit(rPS0(_inst.FC)); + double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c0)); + double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c0)); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_muls1(UGeckoInstruction _inst) { - double c1 = Force25Bit(rPS1(_inst.FC)); - double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c1)); - double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c1)); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; - UpdateFPRF(rPS0(_inst.FD)); + double c1 = Force25Bit(rPS1(_inst.FC)); + double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c1)); + double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c1)); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_madds0(UGeckoInstruction _inst) { - double c0 = Force25Bit(rPS0(_inst.FC)); - double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB))); - double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c0, rPS1(_inst.FB))); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; - UpdateFPRF(rPS0(_inst.FD)); + double c0 = Force25Bit(rPS0(_inst.FC)); + double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB))); + double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c0, rPS1(_inst.FB))); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_madds1(UGeckoInstruction _inst) { - double c1 = Force25Bit(rPS1(_inst.FC)); - double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c1, rPS0(_inst.FB))); - double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB))); - rPS0(_inst.FD) = p0; - rPS1(_inst.FD) = p1; - UpdateFPRF(rPS0(_inst.FD)); + double c1 = Force25Bit(rPS1(_inst.FC)); + double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c1, rPS0(_inst.FB))); + double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB))); + rPS0(_inst.FD) = p0; + rPS1(_inst.FD) = p1; + UpdateFPRF(rPS0(_inst.FD)); - if (_inst.Rc) - Helper_UpdateCR1(); + if (_inst.Rc) + Helper_UpdateCR1(); } void Interpreter::ps_cmpu0(UGeckoInstruction _inst) { - Helper_FloatCompareUnordered(_inst, rPS0(_inst.FA), rPS0(_inst.FB)); + Helper_FloatCompareUnordered(_inst, rPS0(_inst.FA), rPS0(_inst.FB)); } void Interpreter::ps_cmpo0(UGeckoInstruction _inst) { - Helper_FloatCompareOrdered(_inst, rPS0(_inst.FA), rPS0(_inst.FB)); + Helper_FloatCompareOrdered(_inst, rPS0(_inst.FA), rPS0(_inst.FB)); } void Interpreter::ps_cmpu1(UGeckoInstruction _inst) { - Helper_FloatCompareUnordered(_inst, rPS1(_inst.FA), rPS1(_inst.FB)); + Helper_FloatCompareUnordered(_inst, rPS1(_inst.FA), rPS1(_inst.FB)); } void Interpreter::ps_cmpo1(UGeckoInstruction _inst) { - Helper_FloatCompareOrdered(_inst, rPS1(_inst.FA), rPS1(_inst.FB)); + Helper_FloatCompareOrdered(_inst, rPS1(_inst.FA), rPS1(_inst.FB)); } // __________________________________________________________________________________________________ @@ -341,6 +339,6 @@ void Interpreter::ps_cmpo1(UGeckoInstruction _inst) // TODO(ector) check docs void Interpreter::dcbz_l(UGeckoInstruction _inst) { - //FAKE: clear memory instead of clearing the cache block - PowerPC::ClearCacheLine(Helper_Get_EA_X(_inst) & (~31)); + // FAKE: clear memory instead of clearing the cache block + PowerPC::ClearCacheLine(Helper_Get_EA_X(_inst) & (~31)); } diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp index 57cfdd1f31..1a85292923 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp @@ -2,15 +2,15 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/Interpreter/Interpreter.h" #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/FPURoundMode.h" #include "Common/Logging/Log.h" #include "Core/HW/GPFifo.h" #include "Core/HW/SystemTimers.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/Interpreter/Interpreter.h" #include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h" +#include "Core/PowerPC/PowerPC.h" /* @@ -29,433 +29,432 @@ mffsx: 80036650 (huh?) static void FPSCRtoFPUSettings(UReg_FPSCR fp) { - FPURoundMode::SetRoundMode(fp.RN); + FPURoundMode::SetRoundMode(fp.RN); - if (fp.VE || fp.OE || fp.UE || fp.ZE || fp.XE) - { - //PanicAlert("FPSCR - exceptions enabled. Please report. VE=%i OE=%i UE=%i ZE=%i XE=%i", - // fp.VE, fp.OE, fp.UE, fp.ZE, fp.XE); - // Pokemon Colosseum does this. Gah. - } + if (fp.VE || fp.OE || fp.UE || fp.ZE || fp.XE) + { + // PanicAlert("FPSCR - exceptions enabled. Please report. VE=%i OE=%i UE=%i ZE=%i XE=%i", + // fp.VE, fp.OE, fp.UE, fp.ZE, fp.XE); + // Pokemon Colosseum does this. Gah. + } - // Set SSE rounding mode and denormal handling - FPURoundMode::SetSIMDMode(fp.RN, fp.NI); + // Set SSE rounding mode and denormal handling + FPURoundMode::SetSIMDMode(fp.RN, fp.NI); } void Interpreter::mtfsb0x(UGeckoInstruction _inst) { - u32 b = 0x80000000 >> _inst.CRBD; + u32 b = 0x80000000 >> _inst.CRBD; - /*if (b & 0x9ff80700) - PanicAlert("mtfsb0 clears bit %d, PC=%x", _inst.CRBD, PC);*/ + /*if (b & 0x9ff80700) + PanicAlert("mtfsb0 clears bit %d, PC=%x", _inst.CRBD, PC);*/ - FPSCR.Hex &= ~b; - FPSCRtoFPUSettings(FPSCR); + FPSCR.Hex &= ~b; + FPSCRtoFPUSettings(FPSCR); - if (_inst.Rc) - PanicAlert("mtfsb0x: inst_.Rc"); + if (_inst.Rc) + PanicAlert("mtfsb0x: inst_.Rc"); } void Interpreter::mtfsb1x(UGeckoInstruction _inst) { - // this instruction can affect FX - u32 b = 0x80000000 >> _inst.CRBD; - if (b & FPSCR_ANY_X) - SetFPException(b); - else - FPSCR.Hex |= b; - FPSCRtoFPUSettings(FPSCR); + // this instruction can affect FX + u32 b = 0x80000000 >> _inst.CRBD; + if (b & FPSCR_ANY_X) + SetFPException(b); + else + FPSCR.Hex |= b; + FPSCRtoFPUSettings(FPSCR); - if (_inst.Rc) - PanicAlert("mtfsb1x: inst_.Rc"); + if (_inst.Rc) + PanicAlert("mtfsb1x: inst_.Rc"); } void Interpreter::mtfsfix(UGeckoInstruction _inst) { - u32 mask = (0xF0000000 >> (4 * _inst.CRFD)); - u32 imm = (_inst.hex << 16) & 0xF0000000; + u32 mask = (0xF0000000 >> (4 * _inst.CRFD)); + u32 imm = (_inst.hex << 16) & 0xF0000000; - /*u32 cleared = ~(imm >> (4 * _inst.CRFD)) & FPSCR.Hex & mask; - if (cleared & 0x9ff80700) - PanicAlert("mtfsfi clears %08x, PC=%x", cleared, PC);*/ + /*u32 cleared = ~(imm >> (4 * _inst.CRFD)) & FPSCR.Hex & mask; + if (cleared & 0x9ff80700) + PanicAlert("mtfsfi clears %08x, PC=%x", cleared, PC);*/ - FPSCR.Hex = (FPSCR.Hex & ~mask) | (imm >> (4 * _inst.CRFD)); + FPSCR.Hex = (FPSCR.Hex & ~mask) | (imm >> (4 * _inst.CRFD)); - FPSCRtoFPUSettings(FPSCR); + FPSCRtoFPUSettings(FPSCR); - if (_inst.Rc) - PanicAlert("mtfsfix: inst_.Rc"); + if (_inst.Rc) + PanicAlert("mtfsfix: inst_.Rc"); } void Interpreter::mtfsfx(UGeckoInstruction _inst) { - u32 fm = _inst.FM; - u32 m = 0; - for (int i = 0; i < 8; i++) - { - if (fm & (1 << i)) - m |= (0xF << (i * 4)); - } + u32 fm = _inst.FM; + u32 m = 0; + for (int i = 0; i < 8; i++) + { + if (fm & (1 << i)) + m |= (0xF << (i * 4)); + } - /*u32 cleared = ~((u32)(riPS0(_inst.FB))) & FPSCR.Hex & m; - if (cleared & 0x9ff80700) - PanicAlert("mtfsf clears %08x, PC=%x", cleared, PC);*/ + /*u32 cleared = ~((u32)(riPS0(_inst.FB))) & FPSCR.Hex & m; + if (cleared & 0x9ff80700) + PanicAlert("mtfsf clears %08x, PC=%x", cleared, PC);*/ - FPSCR.Hex = (FPSCR.Hex & ~m) | ((u32)(riPS0(_inst.FB)) & m); - FPSCRtoFPUSettings(FPSCR); + FPSCR.Hex = (FPSCR.Hex & ~m) | ((u32)(riPS0(_inst.FB)) & m); + FPSCRtoFPUSettings(FPSCR); - if (_inst.Rc) - PanicAlert("mtfsfx: inst_.Rc"); + if (_inst.Rc) + PanicAlert("mtfsfx: inst_.Rc"); } void Interpreter::mcrxr(UGeckoInstruction _inst) { - SetCRField(_inst.CRFD, GetXER().Hex >> 28); - PowerPC::ppcState.xer_ca = 0; - PowerPC::ppcState.xer_so_ov = 0; + SetCRField(_inst.CRFD, GetXER().Hex >> 28); + PowerPC::ppcState.xer_ca = 0; + PowerPC::ppcState.xer_so_ov = 0; } void Interpreter::mfcr(UGeckoInstruction _inst) { - rGPR[_inst.RD] = GetCR(); + rGPR[_inst.RD] = GetCR(); } void Interpreter::mtcrf(UGeckoInstruction _inst) { - u32 crm = _inst.CRM; - if (crm == 0xFF) - { - SetCR(rGPR[_inst.RS]); - } - else - { - //TODO: use lookup table? probably not worth it - u32 mask = 0; - for (int i = 0; i < 8; i++) - { - if (crm & (1 << i)) - mask |= 0xF << (i*4); - } + u32 crm = _inst.CRM; + if (crm == 0xFF) + { + SetCR(rGPR[_inst.RS]); + } + else + { + // TODO: use lookup table? probably not worth it + u32 mask = 0; + for (int i = 0; i < 8; i++) + { + if (crm & (1 << i)) + mask |= 0xF << (i * 4); + } - SetCR((GetCR() & ~mask) | (rGPR[_inst.RS] & mask)); - } + SetCR((GetCR() & ~mask) | (rGPR[_inst.RS] & mask)); + } } - void Interpreter::mfmsr(UGeckoInstruction _inst) { - //Privileged? - rGPR[_inst.RD] = MSR; + // Privileged? + rGPR[_inst.RD] = MSR; } void Interpreter::mfsr(UGeckoInstruction _inst) { - rGPR[_inst.RD] = PowerPC::ppcState.sr[_inst.SR]; + rGPR[_inst.RD] = PowerPC::ppcState.sr[_inst.SR]; } void Interpreter::mfsrin(UGeckoInstruction _inst) { - int index = (rGPR[_inst.RB] >> 28) & 0xF; - rGPR[_inst.RD] = PowerPC::ppcState.sr[index]; + int index = (rGPR[_inst.RB] >> 28) & 0xF; + rGPR[_inst.RD] = PowerPC::ppcState.sr[index]; } void Interpreter::mtmsr(UGeckoInstruction _inst) { - // Privileged? - MSR = rGPR[_inst.RS]; - PowerPC::CheckExceptions(); - m_EndBlock = true; + // Privileged? + MSR = rGPR[_inst.RS]; + PowerPC::CheckExceptions(); + m_EndBlock = true; } // Segment registers. MMU control. static void SetSR(int index, u32 value) { - DEBUG_LOG(POWERPC, "%08x: MMU: Segment register %i set to %08x", PowerPC::ppcState.pc, index, value); - PowerPC::ppcState.sr[index] = value; + DEBUG_LOG(POWERPC, "%08x: MMU: Segment register %i set to %08x", PowerPC::ppcState.pc, index, + value); + PowerPC::ppcState.sr[index] = value; } void Interpreter::mtsr(UGeckoInstruction _inst) { - int index = _inst.SR; - u32 value = rGPR[_inst.RS]; - SetSR(index, value); + int index = _inst.SR; + u32 value = rGPR[_inst.RS]; + SetSR(index, value); } void Interpreter::mtsrin(UGeckoInstruction _inst) { - int index = (rGPR[_inst.RB] >> 28) & 0xF; - u32 value = rGPR[_inst.RS]; - SetSR(index, value); + int index = (rGPR[_inst.RB] >> 28) & 0xF; + u32 value = rGPR[_inst.RS]; + SetSR(index, value); } - - void Interpreter::mftb(UGeckoInstruction _inst) { - int iIndex = (_inst.TBR >> 5) | ((_inst.TBR & 0x1F) << 5); - _dbg_assert_msg_(POWERPC, (iIndex == SPR_TL) || (iIndex == SPR_TU), "Invalid mftb"); - (void)iIndex; - mfspr(_inst); + int iIndex = (_inst.TBR >> 5) | ((_inst.TBR & 0x1F) << 5); + _dbg_assert_msg_(POWERPC, (iIndex == SPR_TL) || (iIndex == SPR_TU), "Invalid mftb"); + (void)iIndex; + mfspr(_inst); } - void Interpreter::mfspr(UGeckoInstruction _inst) { - u32 iIndex = ((_inst.SPR & 0x1F) << 5) + ((_inst.SPR >> 5) & 0x1F); + u32 iIndex = ((_inst.SPR & 0x1F) << 5) + ((_inst.SPR >> 5) & 0x1F); - //TODO - check processor privilege level - many of these require privilege - //XER LR CTR are the only ones available in user mode, time base can be read too. - //GameCube games always run in superuser mode, but hey.... + // TODO - check processor privilege level - many of these require privilege + // XER LR CTR are the only ones available in user mode, time base can be read too. + // GameCube games always run in superuser mode, but hey.... - switch (iIndex) - { - case SPR_DEC: - if ((rSPR(iIndex) & 0x80000000) == 0) // We are still decrementing - { - rSPR(iIndex) = SystemTimers::GetFakeDecrementer(); - } - break; + switch (iIndex) + { + case SPR_DEC: + if ((rSPR(iIndex) & 0x80000000) == 0) // We are still decrementing + { + rSPR(iIndex) = SystemTimers::GetFakeDecrementer(); + } + break; - case SPR_TL: - case SPR_TU: - *((u64 *)&TL) = SystemTimers::GetFakeTimeBase(); //works since we are little endian and TL comes first :) - break; + case SPR_TL: + case SPR_TU: + *((u64*)&TL) = + SystemTimers::GetFakeTimeBase(); // works since we are little endian and TL comes first :) + break; - case SPR_WPAR: - { - // TODO: If wpar_empty ever is false, Paper Mario hangs. Strange. - // Maybe WPAR is automatically flushed after a certain amount of time? - bool wpar_empty = true; //GPFifo::IsEmpty(); - if (!wpar_empty) - rSPR(iIndex) |= 1; // BNE = buffer not empty - else - rSPR(iIndex) &= ~1; - } - break; - case SPR_XER: - rSPR(iIndex) = GetXER().Hex; - break; - } - rGPR[_inst.RD] = rSPR(iIndex); + case SPR_WPAR: + { + // TODO: If wpar_empty ever is false, Paper Mario hangs. Strange. + // Maybe WPAR is automatically flushed after a certain amount of time? + bool wpar_empty = true; // GPFifo::IsEmpty(); + if (!wpar_empty) + rSPR(iIndex) |= 1; // BNE = buffer not empty + else + rSPR(iIndex) &= ~1; + } + break; + case SPR_XER: + rSPR(iIndex) = GetXER().Hex; + break; + } + rGPR[_inst.RD] = rSPR(iIndex); } void Interpreter::mtspr(UGeckoInstruction _inst) { - u32 iIndex = (_inst.SPRU << 5) | (_inst.SPRL & 0x1F); - u32 oldValue = rSPR(iIndex); - rSPR(iIndex) = rGPR[_inst.RD]; + u32 iIndex = (_inst.SPRU << 5) | (_inst.SPRL & 0x1F); + u32 oldValue = rSPR(iIndex); + rSPR(iIndex) = rGPR[_inst.RD]; - //TODO - check processor privilege level - many of these require privilege - //XER LR CTR are the only ones available in user mode, time base can be read too. - //GameCube games always run in superuser mode, but hey.... + // TODO - check processor privilege level - many of these require privilege + // XER LR CTR are the only ones available in user mode, time base can be read too. + // GameCube games always run in superuser mode, but hey.... - //Our DMA emulation is highly inaccurate - instead of properly emulating the queue - //and so on, we simply make all DMA:s complete instantaneously. + // Our DMA emulation is highly inaccurate - instead of properly emulating the queue + // and so on, we simply make all DMA:s complete instantaneously. - switch (iIndex) - { - case SPR_TL: - case SPR_TU: - PanicAlert("Illegal Write to TL/TU"); - break; + switch (iIndex) + { + case SPR_TL: + case SPR_TU: + PanicAlert("Illegal Write to TL/TU"); + break; - case SPR_TL_W: - TL = rGPR[_inst.RD]; - SystemTimers::TimeBaseSet(); - break; + case SPR_TL_W: + TL = rGPR[_inst.RD]; + SystemTimers::TimeBaseSet(); + break; - case SPR_TU_W: - TU = rGPR[_inst.RD]; - SystemTimers::TimeBaseSet(); - break; + case SPR_TU_W: + TU = rGPR[_inst.RD]; + SystemTimers::TimeBaseSet(); + break; - case SPR_HID0: // HID0 - { - UReg_HID0 old_hid0; - old_hid0.Hex = oldValue; - if (HID0.ICE != old_hid0.ICE) - { - INFO_LOG(POWERPC, "Instruction Cache Enable (HID0.ICE) = %d", (int)HID0.ICE); - } - if (HID0.ILOCK != old_hid0.ILOCK) - { - INFO_LOG(POWERPC, "Instruction Cache Lock (HID0.ILOCK) = %d", (int)HID0.ILOCK); - } - if (HID0.ICFI) - { - HID0.ICFI = 0; - INFO_LOG(POWERPC, "Flush Instruction Cache! ICE=%d", (int)HID0.ICE); - // this is rather slow - // most games do it only once during initialization - PowerPC::ppcState.iCache.Reset(); - } - } - break; - case SPR_HID2: // HID2 - // TODO: generate illegal instruction for paired inst if PSE or LSQE - // not set. - // TODO: disable write gather pipe if WPE not set - // TODO: emulate locked cache and DMA bits. - break; + case SPR_HID0: // HID0 + { + UReg_HID0 old_hid0; + old_hid0.Hex = oldValue; + if (HID0.ICE != old_hid0.ICE) + { + INFO_LOG(POWERPC, "Instruction Cache Enable (HID0.ICE) = %d", (int)HID0.ICE); + } + if (HID0.ILOCK != old_hid0.ILOCK) + { + INFO_LOG(POWERPC, "Instruction Cache Lock (HID0.ILOCK) = %d", (int)HID0.ILOCK); + } + if (HID0.ICFI) + { + HID0.ICFI = 0; + INFO_LOG(POWERPC, "Flush Instruction Cache! ICE=%d", (int)HID0.ICE); + // this is rather slow + // most games do it only once during initialization + PowerPC::ppcState.iCache.Reset(); + } + } + break; + case SPR_HID2: // HID2 + // TODO: generate illegal instruction for paired inst if PSE or LSQE + // not set. + // TODO: disable write gather pipe if WPE not set + // TODO: emulate locked cache and DMA bits. + break; - case SPR_WPAR: - _assert_msg_(POWERPC, rGPR[_inst.RD] == 0x0C008000, "Gather pipe @ %08x", PC); - GPFifo::ResetGatherPipe(); - break; + case SPR_WPAR: + _assert_msg_(POWERPC, rGPR[_inst.RD] == 0x0C008000, "Gather pipe @ %08x", PC); + GPFifo::ResetGatherPipe(); + break; - // Graphics Quantization Registers - case SPR_GQR0: - case SPR_GQR0 + 1: - case SPR_GQR0 + 2: - case SPR_GQR0 + 3: - case SPR_GQR0 + 4: - case SPR_GQR0 + 5: - case SPR_GQR0 + 6: - case SPR_GQR0 + 7: - break; + // Graphics Quantization Registers + case SPR_GQR0: + case SPR_GQR0 + 1: + case SPR_GQR0 + 2: + case SPR_GQR0 + 3: + case SPR_GQR0 + 4: + case SPR_GQR0 + 5: + case SPR_GQR0 + 6: + case SPR_GQR0 + 7: + break; - case SPR_DMAL: - // Locked cache<->Memory DMA - // Total fake, we ignore that DMAs take time. - if (DMAL.DMA_T) - { - u32 dwMemAddress = DMAU.MEM_ADDR << 5; - u32 dwCacheAddress = DMAL.LC_ADDR << 5; - u32 iLength = ((DMAU.DMA_LEN_U << 2) | DMAL.DMA_LEN_L); - // INFO_LOG(POWERPC, "DMA: mem = %x, cache = %x, len = %u, LD = %d, PC=%x", dwMemAddress, dwCacheAddress, iLength, (int)DMAL.DMA_LD, PC); - if (iLength == 0) - iLength = 128; - if (DMAL.DMA_LD) - PowerPC::DMA_MemoryToLC(dwCacheAddress, dwMemAddress, iLength); - else - PowerPC::DMA_LCToMemory(dwMemAddress, dwCacheAddress, iLength); - } - DMAL.DMA_T = 0; - break; + case SPR_DMAL: + // Locked cache<->Memory DMA + // Total fake, we ignore that DMAs take time. + if (DMAL.DMA_T) + { + u32 dwMemAddress = DMAU.MEM_ADDR << 5; + u32 dwCacheAddress = DMAL.LC_ADDR << 5; + u32 iLength = ((DMAU.DMA_LEN_U << 2) | DMAL.DMA_LEN_L); + // INFO_LOG(POWERPC, "DMA: mem = %x, cache = %x, len = %u, LD = %d, PC=%x", dwMemAddress, + // dwCacheAddress, iLength, (int)DMAL.DMA_LD, PC); + if (iLength == 0) + iLength = 128; + if (DMAL.DMA_LD) + PowerPC::DMA_MemoryToLC(dwCacheAddress, dwMemAddress, iLength); + else + PowerPC::DMA_LCToMemory(dwMemAddress, dwCacheAddress, iLength); + } + DMAL.DMA_T = 0; + break; - case SPR_L2CR: - //PanicAlert("mtspr( L2CR )!"); - break; + case SPR_L2CR: + // PanicAlert("mtspr( L2CR )!"); + break; - case SPR_DEC: - if (!(oldValue >> 31) && (rGPR[_inst.RD]>>31)) //top bit from 0 to 1 - { - PanicAlert("Interesting - Software triggered Decrementer exception"); - PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER; - } - SystemTimers::DecrementerSet(); - break; + case SPR_DEC: + if (!(oldValue >> 31) && (rGPR[_inst.RD] >> 31)) // top bit from 0 to 1 + { + PanicAlert("Interesting - Software triggered Decrementer exception"); + PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER; + } + SystemTimers::DecrementerSet(); + break; - // Page table base etc - case SPR_SDR: - PowerPC::SDRUpdated(); - break; + // Page table base etc + case SPR_SDR: + PowerPC::SDRUpdated(); + break; - case SPR_XER: - SetXER(rSPR(iIndex)); - break; - } + case SPR_XER: + SetXER(rSPR(iIndex)); + break; + } } void Interpreter::crand(UGeckoInstruction _inst) { - SetCRBit(_inst.CRBD, GetCRBit(_inst.CRBA) & GetCRBit(_inst.CRBB)); + SetCRBit(_inst.CRBD, GetCRBit(_inst.CRBA) & GetCRBit(_inst.CRBB)); } void Interpreter::crandc(UGeckoInstruction _inst) { - SetCRBit(_inst.CRBD, GetCRBit(_inst.CRBA) & (1 ^ GetCRBit(_inst.CRBB))); + SetCRBit(_inst.CRBD, GetCRBit(_inst.CRBA) & (1 ^ GetCRBit(_inst.CRBB))); } void Interpreter::creqv(UGeckoInstruction _inst) { - SetCRBit(_inst.CRBD, 1 ^ (GetCRBit(_inst.CRBA) ^ GetCRBit(_inst.CRBB))); + SetCRBit(_inst.CRBD, 1 ^ (GetCRBit(_inst.CRBA) ^ GetCRBit(_inst.CRBB))); } void Interpreter::crnand(UGeckoInstruction _inst) { - SetCRBit(_inst.CRBD, 1 ^ (GetCRBit(_inst.CRBA) & GetCRBit(_inst.CRBB))); + SetCRBit(_inst.CRBD, 1 ^ (GetCRBit(_inst.CRBA) & GetCRBit(_inst.CRBB))); } void Interpreter::crnor(UGeckoInstruction _inst) { - SetCRBit(_inst.CRBD, 1 ^ (GetCRBit(_inst.CRBA) | GetCRBit(_inst.CRBB))); + SetCRBit(_inst.CRBD, 1 ^ (GetCRBit(_inst.CRBA) | GetCRBit(_inst.CRBB))); } void Interpreter::cror(UGeckoInstruction _inst) { - SetCRBit(_inst.CRBD, (GetCRBit(_inst.CRBA) | GetCRBit(_inst.CRBB))); + SetCRBit(_inst.CRBD, (GetCRBit(_inst.CRBA) | GetCRBit(_inst.CRBB))); } void Interpreter::crorc(UGeckoInstruction _inst) { - SetCRBit(_inst.CRBD, (GetCRBit(_inst.CRBA) | (1 ^ GetCRBit(_inst.CRBB)))); + SetCRBit(_inst.CRBD, (GetCRBit(_inst.CRBA) | (1 ^ GetCRBit(_inst.CRBB)))); } void Interpreter::crxor(UGeckoInstruction _inst) { - SetCRBit(_inst.CRBD, (GetCRBit(_inst.CRBA) ^ GetCRBit(_inst.CRBB))); + SetCRBit(_inst.CRBD, (GetCRBit(_inst.CRBA) ^ GetCRBit(_inst.CRBB))); } void Interpreter::mcrf(UGeckoInstruction _inst) { - int cr_f = GetCRField(_inst.CRFS); - SetCRField(_inst.CRFD, cr_f); + int cr_f = GetCRField(_inst.CRFS); + SetCRField(_inst.CRFD, cr_f); } void Interpreter::isync(UGeckoInstruction _inst) { - //shouldn't do anything + // shouldn't do anything } // the following commands read from FPSCR void Interpreter::mcrfs(UGeckoInstruction _inst) { - //if (_inst.CRFS != 3 && _inst.CRFS != 4) - // PanicAlert("msrfs at %x, CRFS = %d, CRFD = %d", PC, (int)_inst.CRFS, (int)_inst.CRFD); + // if (_inst.CRFS != 3 && _inst.CRFS != 4) + // PanicAlert("msrfs at %x, CRFS = %d, CRFD = %d", PC, (int)_inst.CRFS, (int)_inst.CRFD); - UpdateFPSCR(); - u32 fpflags = ((FPSCR.Hex >> (4 * (7 - _inst.CRFS))) & 0xF); - switch (_inst.CRFS) - { - case 0: - FPSCR.FX = 0; - FPSCR.OX = 0; - break; - case 1: - FPSCR.UX = 0; - FPSCR.ZX = 0; - FPSCR.XX = 0; - FPSCR.VXSNAN = 0; - break; - case 2: - FPSCR.VXISI = 0; - FPSCR.VXIDI = 0; - FPSCR.VXZDZ = 0; - FPSCR.VXIMZ = 0; - break; - case 3: - FPSCR.VXVC = 0; - break; - case 5: - FPSCR.VXSOFT = 0; - FPSCR.VXSQRT = 0; - FPSCR.VXCVI = 0; - break; - } - SetCRField(_inst.CRFD, fpflags); + UpdateFPSCR(); + u32 fpflags = ((FPSCR.Hex >> (4 * (7 - _inst.CRFS))) & 0xF); + switch (_inst.CRFS) + { + case 0: + FPSCR.FX = 0; + FPSCR.OX = 0; + break; + case 1: + FPSCR.UX = 0; + FPSCR.ZX = 0; + FPSCR.XX = 0; + FPSCR.VXSNAN = 0; + break; + case 2: + FPSCR.VXISI = 0; + FPSCR.VXIDI = 0; + FPSCR.VXZDZ = 0; + FPSCR.VXIMZ = 0; + break; + case 3: + FPSCR.VXVC = 0; + break; + case 5: + FPSCR.VXSOFT = 0; + FPSCR.VXSQRT = 0; + FPSCR.VXCVI = 0; + break; + } + SetCRField(_inst.CRFD, fpflags); } void Interpreter::mffsx(UGeckoInstruction _inst) { - // load from FPSCR - // TODO(ector): grab all overflow flags etc and set them in FPSCR + // load from FPSCR + // TODO(ector): grab all overflow flags etc and set them in FPSCR - UpdateFPSCR(); - riPS0(_inst.FD) = 0xFFF8000000000000 | FPSCR.Hex; + UpdateFPSCR(); + riPS0(_inst.FD) = 0xFFF8000000000000 | FPSCR.Hex; - if (_inst.Rc) - PanicAlert("mffsx: inst_.Rc"); + if (_inst.Rc) + PanicAlert("mffsx: inst_.Rc"); } diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp index d9fd06c804..17ec3117a9 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp @@ -2,17 +2,17 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/Interpreter/Interpreter.h" #include "Common/MsgHandler.h" #include "Core/PowerPC/Gekko.h" -#include "Core/PowerPC/PPCTables.h" -#include "Core/PowerPC/Interpreter/Interpreter.h" #include "Core/PowerPC/Interpreter/Interpreter_Tables.h" +#include "Core/PowerPC/PPCTables.h" struct GekkoOPTemplate { - int opcode; - Interpreter::Instruction Inst; - GekkoOPInfo opinfo; + int opcode; + Interpreter::Instruction Inst; + GekkoOPInfo opinfo; }; // clang-format off @@ -357,140 +357,138 @@ static GekkoOPTemplate table63_2[] = namespace InterpreterTables { - void InitTables() { - // once initialized, tables are read-only - static bool initialized = false; - if (initialized) - return; + // once initialized, tables are read-only + static bool initialized = false; + if (initialized) + return; - //clear - for (int i = 0; i < 64; i++) - { - Interpreter::m_opTable[i] = Interpreter::unknown_instruction; - m_infoTable[i] = &unknownopinfo; - } + // clear + for (int i = 0; i < 64; i++) + { + Interpreter::m_opTable[i] = Interpreter::unknown_instruction; + m_infoTable[i] = &unknownopinfo; + } - for (int i = 0; i < 32; i++) - { - Interpreter::m_opTable59[i] = Interpreter::unknown_instruction; - m_infoTable59[i] = &unknownopinfo; - } + for (int i = 0; i < 32; i++) + { + Interpreter::m_opTable59[i] = Interpreter::unknown_instruction; + m_infoTable59[i] = &unknownopinfo; + } - for (int i = 0; i < 1024; i++) - { - Interpreter::m_opTable4 [i] = Interpreter::unknown_instruction; - Interpreter::m_opTable19[i] = Interpreter::unknown_instruction; - Interpreter::m_opTable31[i] = Interpreter::unknown_instruction; - Interpreter::m_opTable63[i] = Interpreter::unknown_instruction; - m_infoTable4[i] = &unknownopinfo; - m_infoTable19[i] = &unknownopinfo; - m_infoTable31[i] = &unknownopinfo; - m_infoTable63[i] = &unknownopinfo; - } + for (int i = 0; i < 1024; i++) + { + Interpreter::m_opTable4[i] = Interpreter::unknown_instruction; + Interpreter::m_opTable19[i] = Interpreter::unknown_instruction; + Interpreter::m_opTable31[i] = Interpreter::unknown_instruction; + Interpreter::m_opTable63[i] = Interpreter::unknown_instruction; + m_infoTable4[i] = &unknownopinfo; + m_infoTable19[i] = &unknownopinfo; + m_infoTable31[i] = &unknownopinfo; + m_infoTable63[i] = &unknownopinfo; + } - for (auto& tpl : primarytable) - { - Interpreter::m_opTable[tpl.opcode] = tpl.Inst; - m_infoTable[tpl.opcode] = &tpl.opinfo; - } + for (auto& tpl : primarytable) + { + Interpreter::m_opTable[tpl.opcode] = tpl.Inst; + m_infoTable[tpl.opcode] = &tpl.opinfo; + } - for (int i = 0; i < 32; i++) - { - int fill = i << 5; - for (auto& tpl : table4_2) - { - int op = fill+tpl.opcode; - Interpreter::m_opTable4[op] = tpl.Inst; - m_infoTable4[op] = &tpl.opinfo; - } - } + for (int i = 0; i < 32; i++) + { + int fill = i << 5; + for (auto& tpl : table4_2) + { + int op = fill + tpl.opcode; + Interpreter::m_opTable4[op] = tpl.Inst; + m_infoTable4[op] = &tpl.opinfo; + } + } - for (int i = 0; i < 16; i++) - { - int fill = i << 6; - for (auto& tpl : table4_3) - { - int op = fill+tpl.opcode; - Interpreter::m_opTable4[op] = tpl.Inst; - m_infoTable4[op] = &tpl.opinfo; - } - } + for (int i = 0; i < 16; i++) + { + int fill = i << 6; + for (auto& tpl : table4_3) + { + int op = fill + tpl.opcode; + Interpreter::m_opTable4[op] = tpl.Inst; + m_infoTable4[op] = &tpl.opinfo; + } + } - for (auto& tpl : table4) - { - int op = tpl.opcode; - Interpreter::m_opTable4[op] = tpl.Inst; - m_infoTable4[op] = &tpl.opinfo; - } + for (auto& tpl : table4) + { + int op = tpl.opcode; + Interpreter::m_opTable4[op] = tpl.Inst; + m_infoTable4[op] = &tpl.opinfo; + } - for (auto& tpl : table31) - { - int op = tpl.opcode; - Interpreter::m_opTable31[op] = tpl.Inst; - m_infoTable31[op] = &tpl.opinfo; - } + for (auto& tpl : table31) + { + int op = tpl.opcode; + Interpreter::m_opTable31[op] = tpl.Inst; + m_infoTable31[op] = &tpl.opinfo; + } - for (auto& tpl : table19) - { - int op = tpl.opcode; - Interpreter::m_opTable19[op] = tpl.Inst; - m_infoTable19[op] = &tpl.opinfo; - } + for (auto& tpl : table19) + { + int op = tpl.opcode; + Interpreter::m_opTable19[op] = tpl.Inst; + m_infoTable19[op] = &tpl.opinfo; + } - for (auto& tpl : table59) - { - int op = tpl.opcode; - Interpreter::m_opTable59[op] = tpl.Inst; - m_infoTable59[op] = &tpl.opinfo; - } + for (auto& tpl : table59) + { + int op = tpl.opcode; + Interpreter::m_opTable59[op] = tpl.Inst; + m_infoTable59[op] = &tpl.opinfo; + } - for (auto& tpl : table63) - { - int op = tpl.opcode; - Interpreter::m_opTable63[op] = tpl.Inst; - m_infoTable63[op] = &tpl.opinfo; - } + for (auto& tpl : table63) + { + int op = tpl.opcode; + Interpreter::m_opTable63[op] = tpl.Inst; + m_infoTable63[op] = &tpl.opinfo; + } - for (int i = 0; i < 32; i++) - { - int fill = i << 5; - for (auto& tpl : table63_2) - { - int op = fill + tpl.opcode; - Interpreter::m_opTable63[op] = tpl.Inst; - m_infoTable63[op] = &tpl.opinfo; - } - } + for (int i = 0; i < 32; i++) + { + int fill = i << 5; + for (auto& tpl : table63_2) + { + int op = fill + tpl.opcode; + Interpreter::m_opTable63[op] = tpl.Inst; + m_infoTable63[op] = &tpl.opinfo; + } + } - m_numInstructions = 0; - for (auto& tpl : primarytable) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table4_2) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table4_3) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table4) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table31) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table19) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table59) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table63) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table63_2) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; + m_numInstructions = 0; + for (auto& tpl : primarytable) + m_allInstructions[m_numInstructions++] = &tpl.opinfo; + for (auto& tpl : table4_2) + m_allInstructions[m_numInstructions++] = &tpl.opinfo; + for (auto& tpl : table4_3) + m_allInstructions[m_numInstructions++] = &tpl.opinfo; + for (auto& tpl : table4) + m_allInstructions[m_numInstructions++] = &tpl.opinfo; + for (auto& tpl : table31) + m_allInstructions[m_numInstructions++] = &tpl.opinfo; + for (auto& tpl : table19) + m_allInstructions[m_numInstructions++] = &tpl.opinfo; + for (auto& tpl : table59) + m_allInstructions[m_numInstructions++] = &tpl.opinfo; + for (auto& tpl : table63) + m_allInstructions[m_numInstructions++] = &tpl.opinfo; + for (auto& tpl : table63_2) + m_allInstructions[m_numInstructions++] = &tpl.opinfo; - if (m_numInstructions >= 512) - { - PanicAlert("m_allInstructions underdimensioned"); - } + if (m_numInstructions >= 512) + { + PanicAlert("m_allInstructions underdimensioned"); + } - initialized = true; + initialized = true; } - } -//remove +// remove diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.h b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.h index 595ef038d1..ce7796bf2d 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.h +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.h @@ -6,5 +6,5 @@ namespace InterpreterTables { - void InitTables(); +void InitTables(); } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index e4f211a090..291d2667d7 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -11,25 +11,25 @@ #endif #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/MemoryUtil.h" #include "Common/StringUtil.h" #include "Common/x64ABI.h" -#include "Common/Logging/Log.h" #include "Core/Core.h" #include "Core/CoreTiming.h" -#include "Core/PatchEngine.h" #include "Core/HLE/HLE.h" #include "Core/HW/CPU.h" #include "Core/HW/GPFifo.h" #include "Core/HW/ProcessorInterface.h" -#include "Core/PowerPC/JitInterface.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/Profiler.h" +#include "Core/PatchEngine.h" #include "Core/PowerPC/Jit64/Jit.h" #include "Core/PowerPC/Jit64/Jit64_Tables.h" #include "Core/PowerPC/Jit64/JitAsm.h" #include "Core/PowerPC/Jit64/JitRegCache.h" #include "Core/PowerPC/JitCommon/Jit_Util.h" +#include "Core/PowerPC/JitInterface.h" +#include "Core/PowerPC/PowerPC.h" +#include "Core/PowerPC/Profiler.h" #if defined(_DEBUG) || defined(DEBUGFAST) #include "Common/GekkoDisassembler.h" #endif @@ -44,44 +44,52 @@ using namespace PowerPC; // * Fast dispatcher // Unfeatures: -// * Does not recompile all instructions - sometimes falls back to inserting a CALL to the corresponding Interpreter function. +// * Does not recompile all instructions - sometimes falls back to inserting a CALL to the +// corresponding Interpreter function. // Various notes below // IMPORTANT: // Make sure that all generated code and all emulator state sits under the 2GB boundary so that -// RIP addressing can be used easily. Windows will always allocate static code under the 2GB boundary. +// RIP addressing can be used easily. Windows will always allocate static code under the 2GB +// boundary. // Also make sure to use VirtualAlloc and specify EXECUTE permission. // Open questions // * Should there be any statically allocated registers? r3, r4, r5, r8, r0 come to mind.. maybe sp -// * Does it make sense to finish off the remaining non-jitted instructions? Seems we are hitting diminishing returns. +// * Does it make sense to finish off the remaining non-jitted instructions? Seems we are hitting +// diminishing returns. // Other considerations // -// We support block linking. Reserve space at the exits of every block for a full 5-byte jmp. Save 16-bit offsets +// We support block linking. Reserve space at the exits of every block for a full 5-byte jmp. Save +// 16-bit offsets // from the starts of each block, marking the exits so that they can be nicely patched at any time. // // Blocks do NOT use call/ret, they only jmp to each other and to the dispatcher when necessary. // -// All blocks that can be precompiled will be precompiled. Code will be memory protected - any write will mark -// the region as non-compilable, and all links to the page will be torn out and replaced with dispatcher jmps. +// All blocks that can be precompiled will be precompiled. Code will be memory protected - any write +// will mark +// the region as non-compilable, and all links to the page will be torn out and replaced with +// dispatcher jmps. // // Alternatively, icbi instruction SHOULD mark where we can't compile // -// Seldom-happening events is handled by adding a decrement of a counter to all blr instructions (which are +// Seldom-happening events is handled by adding a decrement of a counter to all blr instructions +// (which are // expensive anyway since we need to return to dispatcher, except when they can be predicted). -// TODO: SERIOUS synchronization problem with the video backend setting tokens and breakpoints in dual core mode!!! +// TODO: SERIOUS synchronization problem with the video backend setting tokens and breakpoints in +// dual core mode!!! // Somewhat fixed by disabling idle skipping when certain interrupts are enabled // This is no permanent reliable fix // TODO: Zeldas go whacko when you hang the gfx thread // Idea - Accurate exception handling -// Compute register state at a certain instruction by running the JIT in "dry mode", and stopping at the right place. +// Compute register state at a certain instruction by running the JIT in "dry mode", and stopping at +// the right place. // Not likely to be done :P - // Optimization Ideas - /* * Assume SP is in main RAM (in Wii mode too?) - partly done @@ -91,7 +99,7 @@ using namespace PowerPC; * HLE functions like floorf, sin, memcpy, etc - they can be much faster * ABI optimizations - drop F0-F13 on blr, for example. Watch out for context switching. CR2-CR4 are non-volatile, rest of CR is volatile -> dropped on blr. - R5-R12 are volatile -> dropped on blr. + R5-R12 are volatile -> dropped on blr. * classic inlining across calls. * Track which registers a block clobbers without using, then take advantage of this knowledge when compiling a block that links to that block. @@ -134,180 +142,183 @@ using namespace PowerPC; enum { - STACK_SIZE = 2 * 1024 * 1024, - SAFE_STACK_SIZE = 512 * 1024, - GUARD_SIZE = 0x10000, // two guards - bottom (permanent) and middle (see above) - GUARD_OFFSET = STACK_SIZE - SAFE_STACK_SIZE - GUARD_SIZE, + STACK_SIZE = 2 * 1024 * 1024, + SAFE_STACK_SIZE = 512 * 1024, + GUARD_SIZE = 0x10000, // two guards - bottom (permanent) and middle (see above) + GUARD_OFFSET = STACK_SIZE - SAFE_STACK_SIZE - GUARD_SIZE, }; void Jit64::AllocStack() { #ifndef _WIN32 - m_stack = (u8*)AllocateMemoryPages(STACK_SIZE); - ReadProtectMemory(m_stack, GUARD_SIZE); - ReadProtectMemory(m_stack + GUARD_OFFSET, GUARD_SIZE); + m_stack = (u8*)AllocateMemoryPages(STACK_SIZE); + ReadProtectMemory(m_stack, GUARD_SIZE); + ReadProtectMemory(m_stack + GUARD_OFFSET, GUARD_SIZE); #else - // For windows we just keep using the system stack and reserve a large amount of memory at the end of the stack. - ULONG reserveSize = SAFE_STACK_SIZE; - SetThreadStackGuarantee(&reserveSize); + // For windows we just keep using the system stack and reserve a large amount of memory at the end + // of the stack. + ULONG reserveSize = SAFE_STACK_SIZE; + SetThreadStackGuarantee(&reserveSize); #endif } void Jit64::FreeStack() { #ifndef _WIN32 - if (m_stack) - { - FreeMemoryPages(m_stack, STACK_SIZE); - m_stack = nullptr; - } + if (m_stack) + { + FreeMemoryPages(m_stack, STACK_SIZE); + m_stack = nullptr; + } #endif } bool Jit64::HandleStackFault() { - // It's possible the stack fault might have been caused by something other than - // the BLR optimization. If the fault was triggered from another thread, or - // when BLR optimization isn't enabled then there is nothing we can do about the fault. - // Return false so the regular stack overflow handler can trigger (which crashes) - if (!m_enable_blr_optimization || !Core::IsCPUThread()) - return false; + // It's possible the stack fault might have been caused by something other than + // the BLR optimization. If the fault was triggered from another thread, or + // when BLR optimization isn't enabled then there is nothing we can do about the fault. + // Return false so the regular stack overflow handler can trigger (which crashes) + if (!m_enable_blr_optimization || !Core::IsCPUThread()) + return false; - WARN_LOG(POWERPC, "BLR cache disabled due to excessive BL in the emulated program."); - m_enable_blr_optimization = false; + WARN_LOG(POWERPC, "BLR cache disabled due to excessive BL in the emulated program."); + m_enable_blr_optimization = false; #ifndef _WIN32 - // Windows does this automatically. - UnWriteProtectMemory(m_stack + GUARD_OFFSET, GUARD_SIZE); + // Windows does this automatically. + UnWriteProtectMemory(m_stack + GUARD_OFFSET, GUARD_SIZE); #endif - // We're going to need to clear the whole cache to get rid of the bad - // CALLs, but we can't yet. Fake the downcount so we're forced to the - // dispatcher (no block linking), and clear the cache so we're sent to - // Jit. In the case of Windows, we will also need to call _resetstkoflw() - // to reset the guard page. - // Yeah, it's kind of gross. - GetBlockCache()->InvalidateICache(0, 0xffffffff, true); - CoreTiming::ForceExceptionCheck(0); - m_cleanup_after_stackfault = true; + // We're going to need to clear the whole cache to get rid of the bad + // CALLs, but we can't yet. Fake the downcount so we're forced to the + // dispatcher (no block linking), and clear the cache so we're sent to + // Jit. In the case of Windows, we will also need to call _resetstkoflw() + // to reset the guard page. + // Yeah, it's kind of gross. + GetBlockCache()->InvalidateICache(0, 0xffffffff, true); + CoreTiming::ForceExceptionCheck(0); + m_cleanup_after_stackfault = true; - return true; + return true; } bool Jit64::HandleFault(uintptr_t access_address, SContext* ctx) { - uintptr_t stack = (uintptr_t)m_stack; - uintptr_t diff = access_address - stack; - // In the trap region? - if (m_enable_blr_optimization && diff >= GUARD_OFFSET && diff < GUARD_OFFSET + GUARD_SIZE) - return HandleStackFault(); + uintptr_t stack = (uintptr_t)m_stack; + uintptr_t diff = access_address - stack; + // In the trap region? + if (m_enable_blr_optimization && diff >= GUARD_OFFSET && diff < GUARD_OFFSET + GUARD_SIZE) + return HandleStackFault(); - return Jitx86Base::HandleFault(access_address, ctx); + return Jitx86Base::HandleFault(access_address, ctx); } void Jit64::Init() { - EnableBlockLink(); + EnableBlockLink(); - jo.optimizeGatherPipe = true; - jo.accurateSinglePrecision = true; - UpdateMemoryOptions(); - js.fastmemLoadStore = nullptr; - js.compilerPC = 0; + jo.optimizeGatherPipe = true; + jo.accurateSinglePrecision = true; + UpdateMemoryOptions(); + js.fastmemLoadStore = nullptr; + js.compilerPC = 0; - gpr.SetEmitter(this); - fpr.SetEmitter(this); + gpr.SetEmitter(this); + fpr.SetEmitter(this); - trampolines.Init(jo.memcheck ? TRAMPOLINE_CODE_SIZE_MMU : TRAMPOLINE_CODE_SIZE); - AllocCodeSpace(CODE_SIZE); + trampolines.Init(jo.memcheck ? TRAMPOLINE_CODE_SIZE_MMU : TRAMPOLINE_CODE_SIZE); + AllocCodeSpace(CODE_SIZE); - // BLR optimization has the same consequences as block linking, as well as - // depending on the fault handler to be safe in the event of excessive BL. - m_enable_blr_optimization = jo.enableBlocklink && SConfig::GetInstance().bFastmem && !SConfig::GetInstance().bEnableDebugging; - m_cleanup_after_stackfault = false; + // BLR optimization has the same consequences as block linking, as well as + // depending on the fault handler to be safe in the event of excessive BL. + m_enable_blr_optimization = jo.enableBlocklink && SConfig::GetInstance().bFastmem && + !SConfig::GetInstance().bEnableDebugging; + m_cleanup_after_stackfault = false; - m_stack = nullptr; - if (m_enable_blr_optimization) - AllocStack(); + m_stack = nullptr; + if (m_enable_blr_optimization) + AllocStack(); - blocks.Init(); - asm_routines.Init(m_stack ? (m_stack + STACK_SIZE) : nullptr); + blocks.Init(); + asm_routines.Init(m_stack ? (m_stack + STACK_SIZE) : nullptr); - // important: do this *after* generating the global asm routines, because we can't use farcode in them. - // it'll crash because the farcode functions get cleared on JIT clears. - farcode.Init(jo.memcheck ? FARCODE_SIZE_MMU : FARCODE_SIZE); - Clear(); + // important: do this *after* generating the global asm routines, because we can't use farcode in + // them. + // it'll crash because the farcode functions get cleared on JIT clears. + farcode.Init(jo.memcheck ? FARCODE_SIZE_MMU : FARCODE_SIZE); + Clear(); - code_block.m_stats = &js.st; - code_block.m_gpa = &js.gpa; - code_block.m_fpa = &js.fpa; - EnableOptimization(); + code_block.m_stats = &js.st; + code_block.m_gpa = &js.gpa; + code_block.m_fpa = &js.fpa; + EnableOptimization(); } void Jit64::ClearCache() { - blocks.Clear(); - trampolines.ClearCodeSpace(); - farcode.ClearCodeSpace(); - ClearCodeSpace(); - Clear(); - UpdateMemoryOptions(); + blocks.Clear(); + trampolines.ClearCodeSpace(); + farcode.ClearCodeSpace(); + ClearCodeSpace(); + Clear(); + UpdateMemoryOptions(); } void Jit64::Shutdown() { - FreeStack(); - FreeCodeSpace(); + FreeStack(); + FreeCodeSpace(); - blocks.Shutdown(); - trampolines.Shutdown(); - asm_routines.Shutdown(); - farcode.Shutdown(); + blocks.Shutdown(); + trampolines.Shutdown(); + asm_routines.Shutdown(); + farcode.Shutdown(); } void Jit64::FallBackToInterpreter(UGeckoInstruction inst) { - gpr.Flush(); - fpr.Flush(); - if (js.op->opinfo->flags & FL_ENDBLOCK) - { - MOV(32, PPCSTATE(pc), Imm32(js.compilerPC)); - MOV(32, PPCSTATE(npc), Imm32(js.compilerPC + 4)); - } - Interpreter::Instruction instr = GetInterpreterOp(inst); - ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunctionC((void*)instr, inst.hex); - ABI_PopRegistersAndAdjustStack({}, 0); - if (js.op->opinfo->flags & FL_ENDBLOCK) - { - if (js.isLastInstruction) - { - MOV(32, R(RSCRATCH), PPCSTATE(npc)); - MOV(32, PPCSTATE(pc), R(RSCRATCH)); - WriteExceptionExit(); - } - else - { - MOV(32, R(RSCRATCH), PPCSTATE(npc)); - CMP(32, R(RSCRATCH), Imm32(js.compilerPC + 4)); - FixupBranch c = J_CC(CC_Z); - MOV(32, PPCSTATE(pc), R(RSCRATCH)); - WriteExceptionExit(); - SetJumpTarget(c); - } - } + gpr.Flush(); + fpr.Flush(); + if (js.op->opinfo->flags & FL_ENDBLOCK) + { + MOV(32, PPCSTATE(pc), Imm32(js.compilerPC)); + MOV(32, PPCSTATE(npc), Imm32(js.compilerPC + 4)); + } + Interpreter::Instruction instr = GetInterpreterOp(inst); + ABI_PushRegistersAndAdjustStack({}, 0); + ABI_CallFunctionC((void*)instr, inst.hex); + ABI_PopRegistersAndAdjustStack({}, 0); + if (js.op->opinfo->flags & FL_ENDBLOCK) + { + if (js.isLastInstruction) + { + MOV(32, R(RSCRATCH), PPCSTATE(npc)); + MOV(32, PPCSTATE(pc), R(RSCRATCH)); + WriteExceptionExit(); + } + else + { + MOV(32, R(RSCRATCH), PPCSTATE(npc)); + CMP(32, R(RSCRATCH), Imm32(js.compilerPC + 4)); + FixupBranch c = J_CC(CC_Z); + MOV(32, PPCSTATE(pc), R(RSCRATCH)); + WriteExceptionExit(); + SetJumpTarget(c); + } + } } void Jit64::HLEFunction(UGeckoInstruction _inst) { - gpr.Flush(); - fpr.Flush(); - ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunctionCC((void*)&HLE::Execute, js.compilerPC, _inst.hex); - ABI_PopRegistersAndAdjustStack({}, 0); + gpr.Flush(); + fpr.Flush(); + ABI_PushRegistersAndAdjustStack({}, 0); + ABI_CallFunctionCC((void*)&HLE::Execute, js.compilerPC, _inst.hex); + ABI_PopRegistersAndAdjustStack({}, 0); } void Jit64::DoNothing(UGeckoInstruction _inst) { - // Yup, just don't do anything. + // Yup, just don't do anything. } static const bool ImHereDebug = false; @@ -316,640 +327,650 @@ static std::map been_here; static void ImHere() { - static File::IOFile f; - if (ImHereLog) - { - if (!f) - f.Open("log64.txt", "w"); + static File::IOFile f; + if (ImHereLog) + { + if (!f) + f.Open("log64.txt", "w"); - fprintf(f.GetHandle(), "%08x\n", PC); - } - if (been_here.find(PC) != been_here.end()) - { - been_here.find(PC)->second++; - if ((been_here.find(PC)->second) & 1023) - return; - } - DEBUG_LOG(DYNA_REC, "I'm here - PC = %08x , LR = %08x", PC, LR); - been_here[PC] = 1; + fprintf(f.GetHandle(), "%08x\n", PC); + } + if (been_here.find(PC) != been_here.end()) + { + been_here.find(PC)->second++; + if ((been_here.find(PC)->second) & 1023) + return; + } + DEBUG_LOG(DYNA_REC, "I'm here - PC = %08x , LR = %08x", PC, LR); + been_here[PC] = 1; } bool Jit64::Cleanup() { - bool did_something = false; + bool did_something = false; - if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0) - { - ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunction((void *)&GPFifo::FastCheckGatherPipe); - ABI_PopRegistersAndAdjustStack({}, 0); - did_something = true; - } + if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0) + { + ABI_PushRegistersAndAdjustStack({}, 0); + ABI_CallFunction((void*)&GPFifo::FastCheckGatherPipe); + ABI_PopRegistersAndAdjustStack({}, 0); + did_something = true; + } - // SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time. - if (MMCR0.Hex || MMCR1.Hex) - { - ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunctionCCC((void *)&PowerPC::UpdatePerformanceMonitor, js.downcountAmount, js.numLoadStoreInst, js.numFloatingPointInst); - ABI_PopRegistersAndAdjustStack({}, 0); - did_something = true; - } + // SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time. + if (MMCR0.Hex || MMCR1.Hex) + { + ABI_PushRegistersAndAdjustStack({}, 0); + ABI_CallFunctionCCC((void*)&PowerPC::UpdatePerformanceMonitor, js.downcountAmount, + js.numLoadStoreInst, js.numFloatingPointInst); + ABI_PopRegistersAndAdjustStack({}, 0); + did_something = true; + } - return did_something; + return did_something; } void Jit64::WriteExit(u32 destination, bool bl, u32 after) { - if (!m_enable_blr_optimization) - bl = false; + if (!m_enable_blr_optimization) + bl = false; - Cleanup(); + Cleanup(); - if (bl) - { - MOV(32, R(RSCRATCH2), Imm32(after)); - PUSH(RSCRATCH2); - } + if (bl) + { + MOV(32, R(RSCRATCH2), Imm32(after)); + PUSH(RSCRATCH2); + } - SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); + SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); - JustWriteExit(destination, bl, after); + JustWriteExit(destination, bl, after); } void Jit64::JustWriteExit(u32 destination, bool bl, u32 after) { - //If nobody has taken care of this yet (this can be removed when all branches are done) - JitBlock *b = js.curBlock; - JitBlock::LinkData linkData; - linkData.exitAddress = destination; - linkData.linkStatus = false; + // If nobody has taken care of this yet (this can be removed when all branches are done) + JitBlock* b = js.curBlock; + JitBlock::LinkData linkData; + linkData.exitAddress = destination; + linkData.linkStatus = false; - // Link opportunity! - int block; - if (jo.enableBlocklink && (block = blocks.GetBlockNumberFromStartAddress(destination)) >= 0) - { - // It exists! Joy of joy! - JitBlock* jb = blocks.GetBlock(block); - const u8* addr = jb->checkedEntry; - linkData.exitPtrs = GetWritableCodePtr(); - if (bl) - CALL(addr); - else - JMP(addr, true); - linkData.linkStatus = true; - } - else - { - MOV(32, PPCSTATE(pc), Imm32(destination)); - linkData.exitPtrs = GetWritableCodePtr(); - if (bl) - CALL(asm_routines.dispatcher); - else - JMP(asm_routines.dispatcher, true); - } + // Link opportunity! + int block; + if (jo.enableBlocklink && (block = blocks.GetBlockNumberFromStartAddress(destination)) >= 0) + { + // It exists! Joy of joy! + JitBlock* jb = blocks.GetBlock(block); + const u8* addr = jb->checkedEntry; + linkData.exitPtrs = GetWritableCodePtr(); + if (bl) + CALL(addr); + else + JMP(addr, true); + linkData.linkStatus = true; + } + else + { + MOV(32, PPCSTATE(pc), Imm32(destination)); + linkData.exitPtrs = GetWritableCodePtr(); + if (bl) + CALL(asm_routines.dispatcher); + else + JMP(asm_routines.dispatcher, true); + } - b->linkData.push_back(linkData); + b->linkData.push_back(linkData); - if (bl) - { - POP(RSCRATCH); - JustWriteExit(after, false, 0); - } + if (bl) + { + POP(RSCRATCH); + JustWriteExit(after, false, 0); + } } void Jit64::WriteExitDestInRSCRATCH(bool bl, u32 after) { - if (!m_enable_blr_optimization) - bl = false; - MOV(32, PPCSTATE(pc), R(RSCRATCH)); - Cleanup(); + if (!m_enable_blr_optimization) + bl = false; + MOV(32, PPCSTATE(pc), R(RSCRATCH)); + Cleanup(); - if (bl) - { - MOV(32, R(RSCRATCH2), Imm32(after)); - PUSH(RSCRATCH2); - } + if (bl) + { + MOV(32, R(RSCRATCH2), Imm32(after)); + PUSH(RSCRATCH2); + } - SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); - if (bl) - { - CALL(asm_routines.dispatcher); - POP(RSCRATCH); - JustWriteExit(after, false, 0); - } - else - { - JMP(asm_routines.dispatcher, true); - } + SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); + if (bl) + { + CALL(asm_routines.dispatcher); + POP(RSCRATCH); + JustWriteExit(after, false, 0); + } + else + { + JMP(asm_routines.dispatcher, true); + } } void Jit64::WriteBLRExit() { - if (!m_enable_blr_optimization) - { - WriteExitDestInRSCRATCH(); - return; - } - MOV(32, PPCSTATE(pc), R(RSCRATCH)); - bool disturbed = Cleanup(); - if (disturbed) - MOV(32, R(RSCRATCH), PPCSTATE(pc)); - MOV(32, R(RSCRATCH2), Imm32(js.downcountAmount)); - CMP(64, R(RSCRATCH), MDisp(RSP, 8)); - J_CC(CC_NE, asm_routines.dispatcherMispredictedBLR); - SUB(32, PPCSTATE(downcount), R(RSCRATCH2)); - RET(); + if (!m_enable_blr_optimization) + { + WriteExitDestInRSCRATCH(); + return; + } + MOV(32, PPCSTATE(pc), R(RSCRATCH)); + bool disturbed = Cleanup(); + if (disturbed) + MOV(32, R(RSCRATCH), PPCSTATE(pc)); + MOV(32, R(RSCRATCH2), Imm32(js.downcountAmount)); + CMP(64, R(RSCRATCH), MDisp(RSP, 8)); + J_CC(CC_NE, asm_routines.dispatcherMispredictedBLR); + SUB(32, PPCSTATE(downcount), R(RSCRATCH2)); + RET(); } void Jit64::WriteRfiExitDestInRSCRATCH() { - MOV(32, PPCSTATE(pc), R(RSCRATCH)); - MOV(32, PPCSTATE(npc), R(RSCRATCH)); - Cleanup(); - ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunction(reinterpret_cast(&PowerPC::CheckExceptions)); - ABI_PopRegistersAndAdjustStack({}, 0); - SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); - JMP(asm_routines.dispatcher, true); + MOV(32, PPCSTATE(pc), R(RSCRATCH)); + MOV(32, PPCSTATE(npc), R(RSCRATCH)); + Cleanup(); + ABI_PushRegistersAndAdjustStack({}, 0); + ABI_CallFunction(reinterpret_cast(&PowerPC::CheckExceptions)); + ABI_PopRegistersAndAdjustStack({}, 0); + SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); + JMP(asm_routines.dispatcher, true); } void Jit64::WriteExceptionExit() { - Cleanup(); - MOV(32, R(RSCRATCH), PPCSTATE(pc)); - MOV(32, PPCSTATE(npc), R(RSCRATCH)); - ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunction(reinterpret_cast(&PowerPC::CheckExceptions)); - ABI_PopRegistersAndAdjustStack({}, 0); - SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); - JMP(asm_routines.dispatcher, true); + Cleanup(); + MOV(32, R(RSCRATCH), PPCSTATE(pc)); + MOV(32, PPCSTATE(npc), R(RSCRATCH)); + ABI_PushRegistersAndAdjustStack({}, 0); + ABI_CallFunction(reinterpret_cast(&PowerPC::CheckExceptions)); + ABI_PopRegistersAndAdjustStack({}, 0); + SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); + JMP(asm_routines.dispatcher, true); } void Jit64::WriteExternalExceptionExit() { - Cleanup(); - MOV(32, R(RSCRATCH), PPCSTATE(pc)); - MOV(32, PPCSTATE(npc), R(RSCRATCH)); - ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunction(reinterpret_cast(&PowerPC::CheckExternalExceptions)); - ABI_PopRegistersAndAdjustStack({}, 0); - SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); - JMP(asm_routines.dispatcher, true); + Cleanup(); + MOV(32, R(RSCRATCH), PPCSTATE(pc)); + MOV(32, PPCSTATE(npc), R(RSCRATCH)); + ABI_PushRegistersAndAdjustStack({}, 0); + ABI_CallFunction(reinterpret_cast(&PowerPC::CheckExternalExceptions)); + ABI_PopRegistersAndAdjustStack({}, 0); + SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); + JMP(asm_routines.dispatcher, true); } void Jit64::Run() { - CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode; - pExecAddr(); + CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode; + pExecAddr(); } void Jit64::SingleStep() { - CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode; - pExecAddr(); + CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode; + pExecAddr(); } void Jit64::Trace() { - std::string regs; - std::string fregs; + std::string regs; + std::string fregs; #ifdef JIT_LOG_GPR - for (int i = 0; i < 32; i++) - { - regs += StringFromFormat("r%02d: %08x ", i, PowerPC::ppcState.gpr[i]); - } + for (int i = 0; i < 32; i++) + { + regs += StringFromFormat("r%02d: %08x ", i, PowerPC::ppcState.gpr[i]); + } #endif #ifdef JIT_LOG_FPR - for (int i = 0; i < 32; i++) - { - fregs += StringFromFormat("f%02d: %016x ", i, riPS0(i)); - } + for (int i = 0; i < 32; i++) + { + fregs += StringFromFormat("f%02d: %016x ", i, riPS0(i)); + } #endif - DEBUG_LOG(DYNA_REC, "JIT64 PC: %08x SRR0: %08x SRR1: %08x FPSCR: %08x MSR: %08x LR: %08x %s %s", - PC, SRR0, SRR1, PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), fregs.c_str()); + DEBUG_LOG(DYNA_REC, "JIT64 PC: %08x SRR0: %08x SRR1: %08x FPSCR: %08x MSR: %08x LR: %08x %s %s", + PC, SRR0, SRR1, PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, + PowerPC::ppcState.spr[8], regs.c_str(), fregs.c_str()); } void Jit64::Jit(u32 em_address) { - if (m_cleanup_after_stackfault) - { - ClearCache(); - m_cleanup_after_stackfault = false; + if (m_cleanup_after_stackfault) + { + ClearCache(); + m_cleanup_after_stackfault = false; #ifdef _WIN32 - // The stack is in an invalid state with no guard page, reset it. - _resetstkoflw(); + // The stack is in an invalid state with no guard page, reset it. + _resetstkoflw(); #endif - } + } - if (IsAlmostFull() || farcode.IsAlmostFull() || trampolines.IsAlmostFull() || - blocks.IsFull() || - SConfig::GetInstance().bJITNoBlockCache) - { - ClearCache(); - } + if (IsAlmostFull() || farcode.IsAlmostFull() || trampolines.IsAlmostFull() || blocks.IsFull() || + SConfig::GetInstance().bJITNoBlockCache) + { + ClearCache(); + } - int blockSize = code_buffer.GetSize(); + int blockSize = code_buffer.GetSize(); - if (SConfig::GetInstance().bEnableDebugging) - { - // We can link blocks as long as we are not single stepping and there are no breakpoints here - EnableBlockLink(); - EnableOptimization(); + if (SConfig::GetInstance().bEnableDebugging) + { + // We can link blocks as long as we are not single stepping and there are no breakpoints here + EnableBlockLink(); + EnableOptimization(); - // Comment out the following to disable breakpoints (speed-up) - if (!Profiler::g_ProfileBlocks) - { - if (CPU::GetState() == CPU::CPU_STEPPING) - { - blockSize = 1; + // Comment out the following to disable breakpoints (speed-up) + if (!Profiler::g_ProfileBlocks) + { + if (CPU::GetState() == CPU::CPU_STEPPING) + { + blockSize = 1; - // Do not link this block to other blocks While single stepping - jo.enableBlocklink = false; - analyzer.ClearOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE); - analyzer.ClearOption(PPCAnalyst::PPCAnalyzer::OPTION_BRANCH_MERGE); - analyzer.ClearOption(PPCAnalyst::PPCAnalyzer::OPTION_CROR_MERGE); - analyzer.ClearOption(PPCAnalyst::PPCAnalyzer::OPTION_CARRY_MERGE); - } - Trace(); - } - } + // Do not link this block to other blocks While single stepping + jo.enableBlocklink = false; + analyzer.ClearOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE); + analyzer.ClearOption(PPCAnalyst::PPCAnalyzer::OPTION_BRANCH_MERGE); + analyzer.ClearOption(PPCAnalyst::PPCAnalyzer::OPTION_CROR_MERGE); + analyzer.ClearOption(PPCAnalyst::PPCAnalyzer::OPTION_CARRY_MERGE); + } + Trace(); + } + } - // Analyze the block, collect all instructions it is made of (including inlining, - // if that is enabled), reorder instructions for optimal performance, and join joinable instructions. - u32 nextPC = analyzer.Analyze(em_address, &code_block, &code_buffer, blockSize); + // Analyze the block, collect all instructions it is made of (including inlining, + // if that is enabled), reorder instructions for optimal performance, and join joinable + // instructions. + u32 nextPC = analyzer.Analyze(em_address, &code_block, &code_buffer, blockSize); - if (code_block.m_memory_exception) - { - // Address of instruction could not be translated - NPC = nextPC; - PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; - PowerPC::CheckExceptions(); - WARN_LOG(POWERPC, "ISI exception at 0x%08x", nextPC); - return; - } + if (code_block.m_memory_exception) + { + // Address of instruction could not be translated + NPC = nextPC; + PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; + PowerPC::CheckExceptions(); + WARN_LOG(POWERPC, "ISI exception at 0x%08x", nextPC); + return; + } - int block_num = blocks.AllocateBlock(em_address); - JitBlock *b = blocks.GetBlock(block_num); - blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b, nextPC)); + int block_num = blocks.AllocateBlock(em_address); + JitBlock* b = blocks.GetBlock(block_num); + blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b, nextPC)); } -const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b, u32 nextPC) +const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBlock* b, u32 nextPC) { - js.firstFPInstructionFound = false; - js.isLastInstruction = false; - js.blockStart = em_address; - js.fifoBytesThisBlock = 0; - js.curBlock = b; - js.numLoadStoreInst = 0; - js.numFloatingPointInst = 0; + js.firstFPInstructionFound = false; + js.isLastInstruction = false; + js.blockStart = em_address; + js.fifoBytesThisBlock = 0; + js.curBlock = b; + js.numLoadStoreInst = 0; + js.numFloatingPointInst = 0; - PPCAnalyst::CodeOp *ops = code_buf->codebuffer; + PPCAnalyst::CodeOp* ops = code_buf->codebuffer; - const u8 *start = AlignCode4(); // TODO: Test if this or AlignCode16 make a difference from GetCodePtr - b->checkedEntry = start; - b->runCount = 0; + const u8* start = + AlignCode4(); // TODO: Test if this or AlignCode16 make a difference from GetCodePtr + b->checkedEntry = start; + b->runCount = 0; - // Downcount flag check. The last block decremented downcounter, and the flag should still be available. - FixupBranch skip = J_CC(CC_NBE); - MOV(32, PPCSTATE(pc), Imm32(js.blockStart)); - JMP(asm_routines.doTiming, true); // downcount hit zero - go doTiming. - SetJumpTarget(skip); + // Downcount flag check. The last block decremented downcounter, and the flag should still be + // available. + FixupBranch skip = J_CC(CC_NBE); + MOV(32, PPCSTATE(pc), Imm32(js.blockStart)); + JMP(asm_routines.doTiming, true); // downcount hit zero - go doTiming. + SetJumpTarget(skip); - const u8 *normalEntry = GetCodePtr(); - b->normalEntry = normalEntry; + const u8* normalEntry = GetCodePtr(); + b->normalEntry = normalEntry; - if (ImHereDebug) - { - ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunction((void *)&ImHere); //Used to get a trace of the last few blocks before a crash, sometimes VERY useful - ABI_PopRegistersAndAdjustStack({}, 0); - } + if (ImHereDebug) + { + ABI_PushRegistersAndAdjustStack({}, 0); + ABI_CallFunction((void*)&ImHere); // Used to get a trace of the last few blocks before a crash, + // sometimes VERY useful + ABI_PopRegistersAndAdjustStack({}, 0); + } - // Conditionally add profiling code. - if (Profiler::g_ProfileBlocks) - { - MOV(64, R(RSCRATCH), Imm64((u64)&b->runCount)); - ADD(32, MatR(RSCRATCH), Imm8(1)); - b->ticCounter = 0; - b->ticStart = 0; - b->ticStop = 0; - // get start tic - PROFILER_QUERY_PERFORMANCE_COUNTER(&b->ticStart); - } + // Conditionally add profiling code. + if (Profiler::g_ProfileBlocks) + { + MOV(64, R(RSCRATCH), Imm64((u64)&b->runCount)); + ADD(32, MatR(RSCRATCH), Imm8(1)); + b->ticCounter = 0; + b->ticStart = 0; + b->ticStop = 0; + // get start tic + PROFILER_QUERY_PERFORMANCE_COUNTER(&b->ticStart); + } #if defined(_DEBUG) || defined(DEBUGFAST) || defined(NAN_CHECK) - // should help logged stack-traces become more accurate - MOV(32, PPCSTATE(pc), Imm32(js.blockStart)); + // should help logged stack-traces become more accurate + MOV(32, PPCSTATE(pc), Imm32(js.blockStart)); #endif - // Start up the register allocators - // They use the information in gpa/fpa to preload commonly used registers. - gpr.Start(); - fpr.Start(); + // Start up the register allocators + // They use the information in gpa/fpa to preload commonly used registers. + gpr.Start(); + fpr.Start(); - js.downcountAmount = 0; - if (!SConfig::GetInstance().bEnableDebugging) - js.downcountAmount += PatchEngine::GetSpeedhackCycles(code_block.m_address); + js.downcountAmount = 0; + if (!SConfig::GetInstance().bEnableDebugging) + js.downcountAmount += PatchEngine::GetSpeedhackCycles(code_block.m_address); - js.skipInstructions = 0; - js.carryFlagSet = false; - js.carryFlagInverted = false; - js.assumeNoPairedQuantize = false; + js.skipInstructions = 0; + js.carryFlagSet = false; + js.carryFlagInverted = false; + js.assumeNoPairedQuantize = false; - // If the block only uses one GQR and the GQR is zero at compile time, make a guess that the block - // never uses quantized loads/stores. Many paired-heavy games use largely float loads and stores, - // which are significantly faster when inlined (especially in MMU mode, where this lets them use - // fastmem). - // Insert a check that the GQR is still zero at the start of the block in case our guess turns out - // wrong. - // TODO: support any other constant GQR value, not merely zero/unquantized: we can optimize quantized - // loadstores too, it'd just be more code. - if (code_block.m_gqr_used.Count() == 1 && js.pairedQuantizeAddresses.find(js.blockStart) == js.pairedQuantizeAddresses.end()) - { - int gqr = *code_block.m_gqr_used.begin(); - if (!code_block.m_gqr_modified[gqr] && !GQR(gqr)) - { - CMP(32, PPCSTATE(spr[SPR_GQR0 + gqr]), Imm8(0)); - FixupBranch failure = J_CC(CC_NZ, true); - SwitchToFarCode(); - SetJumpTarget(failure); - MOV(32, PPCSTATE(pc), Imm32(js.blockStart)); - ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunctionC((void *)&JitInterface::CompileExceptionCheck, - (u32)JitInterface::ExceptionType::EXCEPTIONS_PAIRED_QUANTIZE); - ABI_PopRegistersAndAdjustStack({}, 0); - JMP(asm_routines.dispatcher, true); - SwitchToNearCode(); - js.assumeNoPairedQuantize = true; - } - } + // If the block only uses one GQR and the GQR is zero at compile time, make a guess that the block + // never uses quantized loads/stores. Many paired-heavy games use largely float loads and stores, + // which are significantly faster when inlined (especially in MMU mode, where this lets them use + // fastmem). + // Insert a check that the GQR is still zero at the start of the block in case our guess turns out + // wrong. + // TODO: support any other constant GQR value, not merely zero/unquantized: we can optimize + // quantized + // loadstores too, it'd just be more code. + if (code_block.m_gqr_used.Count() == 1 && + js.pairedQuantizeAddresses.find(js.blockStart) == js.pairedQuantizeAddresses.end()) + { + int gqr = *code_block.m_gqr_used.begin(); + if (!code_block.m_gqr_modified[gqr] && !GQR(gqr)) + { + CMP(32, PPCSTATE(spr[SPR_GQR0 + gqr]), Imm8(0)); + FixupBranch failure = J_CC(CC_NZ, true); + SwitchToFarCode(); + SetJumpTarget(failure); + MOV(32, PPCSTATE(pc), Imm32(js.blockStart)); + ABI_PushRegistersAndAdjustStack({}, 0); + ABI_CallFunctionC((void*)&JitInterface::CompileExceptionCheck, + (u32)JitInterface::ExceptionType::EXCEPTIONS_PAIRED_QUANTIZE); + ABI_PopRegistersAndAdjustStack({}, 0); + JMP(asm_routines.dispatcher, true); + SwitchToNearCode(); + js.assumeNoPairedQuantize = true; + } + } - // Translate instructions - for (u32 i = 0; i < code_block.m_num_instructions; i++) - { - js.compilerPC = ops[i].address; - js.op = &ops[i]; - js.instructionNumber = i; - js.instructionsLeft = (code_block.m_num_instructions - 1) - i; - const GekkoOPInfo *opinfo = ops[i].opinfo; - js.downcountAmount += opinfo->numCycles; - js.fastmemLoadStore = nullptr; - js.fixupExceptionHandler = false; - js.revertGprLoad = -1; - js.revertFprLoad = -1; + // Translate instructions + for (u32 i = 0; i < code_block.m_num_instructions; i++) + { + js.compilerPC = ops[i].address; + js.op = &ops[i]; + js.instructionNumber = i; + js.instructionsLeft = (code_block.m_num_instructions - 1) - i; + const GekkoOPInfo* opinfo = ops[i].opinfo; + js.downcountAmount += opinfo->numCycles; + js.fastmemLoadStore = nullptr; + js.fixupExceptionHandler = false; + js.revertGprLoad = -1; + js.revertFprLoad = -1; - if (i == (code_block.m_num_instructions - 1)) - { - if (Profiler::g_ProfileBlocks) - { - // WARNING - cmp->branch merging will screw this up. - PROFILER_VPUSH; - // get end tic - PROFILER_QUERY_PERFORMANCE_COUNTER(&b->ticStop); - // tic counter += (end tic - start tic) - PROFILER_UPDATE_TIME(b); - PROFILER_VPOP; - } - js.isLastInstruction = true; - } + if (i == (code_block.m_num_instructions - 1)) + { + if (Profiler::g_ProfileBlocks) + { + // WARNING - cmp->branch merging will screw this up. + PROFILER_VPUSH; + // get end tic + PROFILER_QUERY_PERFORMANCE_COUNTER(&b->ticStop); + // tic counter += (end tic - start tic) + PROFILER_UPDATE_TIME(b); + PROFILER_VPOP; + } + js.isLastInstruction = true; + } - // Gather pipe writes using a non-immediate address are discovered by profiling. - bool gatherPipeIntCheck = js.fifoWriteAddresses.find(ops[i].address) != js.fifoWriteAddresses.end(); + // Gather pipe writes using a non-immediate address are discovered by profiling. + bool gatherPipeIntCheck = + js.fifoWriteAddresses.find(ops[i].address) != js.fifoWriteAddresses.end(); - // Gather pipe writes using an immediate address are explicitly tracked. - if (jo.optimizeGatherPipe && js.fifoBytesThisBlock >= 32) - { - js.fifoBytesThisBlock -= 32; - BitSet32 registersInUse = CallerSavedRegistersInUse(); - ABI_PushRegistersAndAdjustStack(registersInUse, 0); - ABI_CallFunction((void *)&GPFifo::FastCheckGatherPipe); - ABI_PopRegistersAndAdjustStack(registersInUse, 0); - gatherPipeIntCheck = true; - } + // Gather pipe writes using an immediate address are explicitly tracked. + if (jo.optimizeGatherPipe && js.fifoBytesThisBlock >= 32) + { + js.fifoBytesThisBlock -= 32; + BitSet32 registersInUse = CallerSavedRegistersInUse(); + ABI_PushRegistersAndAdjustStack(registersInUse, 0); + ABI_CallFunction((void*)&GPFifo::FastCheckGatherPipe); + ABI_PopRegistersAndAdjustStack(registersInUse, 0); + gatherPipeIntCheck = true; + } - // Gather pipe writes can generate an exception; add an exception check. - // TODO: This doesn't really match hardware; the CP interrupt is - // asynchronous. - if (gatherPipeIntCheck) - { - TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_EXTERNAL_INT)); - FixupBranch extException = J_CC(CC_NZ, true); + // Gather pipe writes can generate an exception; add an exception check. + // TODO: This doesn't really match hardware; the CP interrupt is + // asynchronous. + if (gatherPipeIntCheck) + { + TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_EXTERNAL_INT)); + FixupBranch extException = J_CC(CC_NZ, true); - SwitchToFarCode(); - SetJumpTarget(extException); - TEST(32, PPCSTATE(msr), Imm32(0x0008000)); - FixupBranch noExtIntEnable = J_CC(CC_Z, true); - TEST(32, M(&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP | - ProcessorInterface::INT_CAUSE_PE_TOKEN | - ProcessorInterface::INT_CAUSE_PE_FINISH)); - FixupBranch noCPInt = J_CC(CC_Z, true); + SwitchToFarCode(); + SetJumpTarget(extException); + TEST(32, PPCSTATE(msr), Imm32(0x0008000)); + FixupBranch noExtIntEnable = J_CC(CC_Z, true); + TEST(32, M(&ProcessorInterface::m_InterruptCause), + Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN | + ProcessorInterface::INT_CAUSE_PE_FINISH)); + FixupBranch noCPInt = J_CC(CC_Z, true); - gpr.Flush(FLUSH_MAINTAIN_STATE); - fpr.Flush(FLUSH_MAINTAIN_STATE); + gpr.Flush(FLUSH_MAINTAIN_STATE); + fpr.Flush(FLUSH_MAINTAIN_STATE); - MOV(32, PPCSTATE(pc), Imm32(ops[i].address)); - WriteExternalExceptionExit(); - SwitchToNearCode(); + MOV(32, PPCSTATE(pc), Imm32(ops[i].address)); + WriteExternalExceptionExit(); + SwitchToNearCode(); - SetJumpTarget(noCPInt); - SetJumpTarget(noExtIntEnable); - } + SetJumpTarget(noCPInt); + SetJumpTarget(noExtIntEnable); + } - u32 function = HLE::GetFunctionIndex(ops[i].address); - if (function != 0) - { - int type = HLE::GetFunctionTypeByIndex(function); - if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE) - { - int flags = HLE::GetFunctionFlagsByIndex(function); - if (HLE::IsEnabled(flags)) - { - HLEFunction(function); - if (type == HLE::HLE_HOOK_REPLACE) - { - MOV(32, R(RSCRATCH), PPCSTATE(npc)); - js.downcountAmount += js.st.numCycles; - WriteExitDestInRSCRATCH(); - break; - } - } - } - } + u32 function = HLE::GetFunctionIndex(ops[i].address); + if (function != 0) + { + int type = HLE::GetFunctionTypeByIndex(function); + if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE) + { + int flags = HLE::GetFunctionFlagsByIndex(function); + if (HLE::IsEnabled(flags)) + { + HLEFunction(function); + if (type == HLE::HLE_HOOK_REPLACE) + { + MOV(32, R(RSCRATCH), PPCSTATE(npc)); + js.downcountAmount += js.st.numCycles; + WriteExitDestInRSCRATCH(); + break; + } + } + } + } - if (!ops[i].skip) - { - if ((opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound) - { - //This instruction uses FPU - needs to add FP exception bailout - TEST(32, PPCSTATE(msr), Imm32(1 << 13)); // Test FP enabled bit - FixupBranch b1 = J_CC(CC_Z, true); + if (!ops[i].skip) + { + if ((opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound) + { + // This instruction uses FPU - needs to add FP exception bailout + TEST(32, PPCSTATE(msr), Imm32(1 << 13)); // Test FP enabled bit + FixupBranch b1 = J_CC(CC_Z, true); - SwitchToFarCode(); - SetJumpTarget(b1); - gpr.Flush(FLUSH_MAINTAIN_STATE); - fpr.Flush(FLUSH_MAINTAIN_STATE); + SwitchToFarCode(); + SetJumpTarget(b1); + gpr.Flush(FLUSH_MAINTAIN_STATE); + fpr.Flush(FLUSH_MAINTAIN_STATE); - // If a FPU exception occurs, the exception handler will read - // from PC. Update PC with the latest value in case that happens. - MOV(32, PPCSTATE(pc), Imm32(ops[i].address)); - OR(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE)); - WriteExceptionExit(); - SwitchToNearCode(); + // If a FPU exception occurs, the exception handler will read + // from PC. Update PC with the latest value in case that happens. + MOV(32, PPCSTATE(pc), Imm32(ops[i].address)); + OR(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE)); + WriteExceptionExit(); + SwitchToNearCode(); - js.firstFPInstructionFound = true; - } + js.firstFPInstructionFound = true; + } - if (SConfig::GetInstance().bEnableDebugging && - breakpoints.IsAddressBreakPoint(ops[i].address) && - CPU::GetState() != CPU::CPU_STEPPING) - { - // Turn off block linking if there are breakpoints so that the Step Over command does not link this block. - jo.enableBlocklink = false; + if (SConfig::GetInstance().bEnableDebugging && + breakpoints.IsAddressBreakPoint(ops[i].address) && CPU::GetState() != CPU::CPU_STEPPING) + { + // Turn off block linking if there are breakpoints so that the Step Over command does not + // link this block. + jo.enableBlocklink = false; - gpr.Flush(); - fpr.Flush(); + gpr.Flush(); + fpr.Flush(); - MOV(32, PPCSTATE(pc), Imm32(ops[i].address)); - ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunction(reinterpret_cast(&PowerPC::CheckBreakPoints)); - ABI_PopRegistersAndAdjustStack({}, 0); - TEST(32, M(CPU::GetStatePtr()), Imm32(0xFFFFFFFF)); - FixupBranch noBreakpoint = J_CC(CC_Z); + MOV(32, PPCSTATE(pc), Imm32(ops[i].address)); + ABI_PushRegistersAndAdjustStack({}, 0); + ABI_CallFunction(reinterpret_cast(&PowerPC::CheckBreakPoints)); + ABI_PopRegistersAndAdjustStack({}, 0); + TEST(32, M(CPU::GetStatePtr()), Imm32(0xFFFFFFFF)); + FixupBranch noBreakpoint = J_CC(CC_Z); - WriteExit(ops[i].address); - SetJumpTarget(noBreakpoint); - } + WriteExit(ops[i].address); + SetJumpTarget(noBreakpoint); + } - // If we have an input register that is going to be used again, load it pre-emptively, - // even if the instruction doesn't strictly need it in a register, to avoid redundant - // loads later. Of course, don't do this if we're already out of registers. - // As a bit of a heuristic, make sure we have at least one register left over for the - // output, which needs to be bound in the actual instruction compilation. - // TODO: make this smarter in the case that we're actually register-starved, i.e. - // prioritize the more important registers. - for (int reg : ops[i].regsIn) - { - if (gpr.NumFreeRegisters() < 2) - break; - if (ops[i].gprInReg[reg] && !gpr.R(reg).IsImm()) - gpr.BindToRegister(reg, true, false); - } - for (int reg : ops[i].fregsIn) - { - if (fpr.NumFreeRegisters() < 2) - break; - if (ops[i].fprInXmm[reg]) - fpr.BindToRegister(reg, true, false); - } + // If we have an input register that is going to be used again, load it pre-emptively, + // even if the instruction doesn't strictly need it in a register, to avoid redundant + // loads later. Of course, don't do this if we're already out of registers. + // As a bit of a heuristic, make sure we have at least one register left over for the + // output, which needs to be bound in the actual instruction compilation. + // TODO: make this smarter in the case that we're actually register-starved, i.e. + // prioritize the more important registers. + for (int reg : ops[i].regsIn) + { + if (gpr.NumFreeRegisters() < 2) + break; + if (ops[i].gprInReg[reg] && !gpr.R(reg).IsImm()) + gpr.BindToRegister(reg, true, false); + } + for (int reg : ops[i].fregsIn) + { + if (fpr.NumFreeRegisters() < 2) + break; + if (ops[i].fprInXmm[reg]) + fpr.BindToRegister(reg, true, false); + } - Jit64Tables::CompileInstruction(ops[i]); + Jit64Tables::CompileInstruction(ops[i]); - if (jo.memcheck && (opinfo->flags & FL_LOADSTORE)) - { - // If we have a fastmem loadstore, we can omit the exception check and let fastmem handle it. - FixupBranch memException; - _assert_msg_(DYNA_REC, !(js.fastmemLoadStore && js.fixupExceptionHandler), - "Fastmem loadstores shouldn't have exception handler fixups (PC=%x)!", ops[i].address); - if (!js.fastmemLoadStore && !js.fixupExceptionHandler) - { - TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_DSI)); - memException = J_CC(CC_NZ, true); - } + if (jo.memcheck && (opinfo->flags & FL_LOADSTORE)) + { + // If we have a fastmem loadstore, we can omit the exception check and let fastmem handle + // it. + FixupBranch memException; + _assert_msg_(DYNA_REC, !(js.fastmemLoadStore && js.fixupExceptionHandler), + "Fastmem loadstores shouldn't have exception handler fixups (PC=%x)!", + ops[i].address); + if (!js.fastmemLoadStore && !js.fixupExceptionHandler) + { + TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_DSI)); + memException = J_CC(CC_NZ, true); + } - SwitchToFarCode(); - if (!js.fastmemLoadStore) - { - exceptionHandlerAtLoc[js.fastmemLoadStore] = nullptr; - SetJumpTarget(js.fixupExceptionHandler ? js.exceptionHandler : memException); - } - else - { - exceptionHandlerAtLoc[js.fastmemLoadStore] = GetWritableCodePtr(); - } + SwitchToFarCode(); + if (!js.fastmemLoadStore) + { + exceptionHandlerAtLoc[js.fastmemLoadStore] = nullptr; + SetJumpTarget(js.fixupExceptionHandler ? js.exceptionHandler : memException); + } + else + { + exceptionHandlerAtLoc[js.fastmemLoadStore] = GetWritableCodePtr(); + } - BitSet32 gprToFlush = BitSet32::AllTrue(32); - BitSet32 fprToFlush = BitSet32::AllTrue(32); - if (js.revertGprLoad >= 0) - gprToFlush[js.revertGprLoad] = false; - if (js.revertFprLoad >= 0) - fprToFlush[js.revertFprLoad] = false; - gpr.Flush(FLUSH_MAINTAIN_STATE, gprToFlush); - fpr.Flush(FLUSH_MAINTAIN_STATE, fprToFlush); + BitSet32 gprToFlush = BitSet32::AllTrue(32); + BitSet32 fprToFlush = BitSet32::AllTrue(32); + if (js.revertGprLoad >= 0) + gprToFlush[js.revertGprLoad] = false; + if (js.revertFprLoad >= 0) + fprToFlush[js.revertFprLoad] = false; + gpr.Flush(FLUSH_MAINTAIN_STATE, gprToFlush); + fpr.Flush(FLUSH_MAINTAIN_STATE, fprToFlush); - // If a memory exception occurs, the exception handler will read - // from PC. Update PC with the latest value in case that happens. - MOV(32, PPCSTATE(pc), Imm32(ops[i].address)); - WriteExceptionExit(); - SwitchToNearCode(); - } + // If a memory exception occurs, the exception handler will read + // from PC. Update PC with the latest value in case that happens. + MOV(32, PPCSTATE(pc), Imm32(ops[i].address)); + WriteExceptionExit(); + SwitchToNearCode(); + } - // If we have a register that will never be used again, flush it. - for (int j : ~ops[i].gprInUse) - gpr.StoreFromRegister(j); - for (int j : ~ops[i].fprInUse) - fpr.StoreFromRegister(j); + // If we have a register that will never be used again, flush it. + for (int j : ~ops[i].gprInUse) + gpr.StoreFromRegister(j); + for (int j : ~ops[i].fprInUse) + fpr.StoreFromRegister(j); - if (opinfo->flags & FL_LOADSTORE) - ++js.numLoadStoreInst; + if (opinfo->flags & FL_LOADSTORE) + ++js.numLoadStoreInst; - if (opinfo->flags & FL_USE_FPU) - ++js.numFloatingPointInst; - } + if (opinfo->flags & FL_USE_FPU) + ++js.numFloatingPointInst; + } #if defined(_DEBUG) || defined(DEBUGFAST) - if (gpr.SanityCheck() || fpr.SanityCheck()) - { - std::string ppc_inst = GekkoDisassembler::Disassemble(ops[i].inst.hex, em_address); - //NOTICE_LOG(DYNA_REC, "Unflushed register: %s", ppc_inst.c_str()); - } + if (gpr.SanityCheck() || fpr.SanityCheck()) + { + std::string ppc_inst = GekkoDisassembler::Disassemble(ops[i].inst.hex, em_address); + // NOTICE_LOG(DYNA_REC, "Unflushed register: %s", ppc_inst.c_str()); + } #endif - i += js.skipInstructions; - js.skipInstructions = 0; - } + i += js.skipInstructions; + js.skipInstructions = 0; + } - if (code_block.m_broken) - { - gpr.Flush(); - fpr.Flush(); - WriteExit(nextPC); - } + if (code_block.m_broken) + { + gpr.Flush(); + fpr.Flush(); + WriteExit(nextPC); + } - b->codeSize = (u32)(GetCodePtr() - start); - b->originalSize = code_block.m_num_instructions; + b->codeSize = (u32)(GetCodePtr() - start); + b->originalSize = code_block.m_num_instructions; #ifdef JIT_LOG_X86 - LogGeneratedX86(code_block.m_num_instructions, code_buf, start, b); + LogGeneratedX86(code_block.m_num_instructions, code_buf, start, b); #endif - return normalEntry; + return normalEntry; } BitSet32 Jit64::CallerSavedRegistersInUse() { - BitSet32 result; - for (int i = 0; i < NUMXREGS; i++) - { - if (!gpr.IsFreeX(i)) - result[i] = true; - if (!fpr.IsFreeX(i)) - result[16 + i] = true; - } - return result & ABI_ALL_CALLER_SAVED; + BitSet32 result; + for (int i = 0; i < NUMXREGS; i++) + { + if (!gpr.IsFreeX(i)) + result[i] = true; + if (!fpr.IsFreeX(i)) + result[16 + i] = true; + } + return result & ABI_ALL_CALLER_SAVED; } void Jit64::EnableBlockLink() { - jo.enableBlocklink = true; - if (SConfig::GetInstance().bJITNoBlockLinking) - jo.enableBlocklink = false; + jo.enableBlocklink = true; + if (SConfig::GetInstance().bJITNoBlockLinking) + jo.enableBlocklink = false; } void Jit64::EnableOptimization() { - analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE); - analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_BRANCH_MERGE); - analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CROR_MERGE); - analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CARRY_MERGE); + analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE); + analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_BRANCH_MERGE); + analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CROR_MERGE); + analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CARRY_MERGE); } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.h b/Source/Core/Core/PowerPC/Jit64/Jit.h index e7d169bf86..4d006f4d12 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/PowerPC/Jit64/Jit.h @@ -20,233 +20,223 @@ #include "Common/CommonTypes.h" #include "Common/x64Emitter.h" -#include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/Jit64/JitAsm.h" #include "Core/PowerPC/Jit64/JitRegCache.h" #include "Core/PowerPC/JitCommon/JitBase.h" #include "Core/PowerPC/JitCommon/JitCache.h" +#include "Core/PowerPC/PPCAnalyst.h" class Jit64 : public Jitx86Base { private: - void AllocStack(); - void FreeStack(); + void AllocStack(); + void FreeStack(); - GPRRegCache gpr; - FPURegCache fpr; + GPRRegCache gpr; + FPURegCache fpr; - // The default code buffer. We keep it around to not have to alloc/dealloc a - // large chunk of memory for each recompiled block. - PPCAnalyst::CodeBuffer code_buffer; - Jit64AsmRoutineManager asm_routines; + // The default code buffer. We keep it around to not have to alloc/dealloc a + // large chunk of memory for each recompiled block. + PPCAnalyst::CodeBuffer code_buffer; + Jit64AsmRoutineManager asm_routines; - bool m_enable_blr_optimization; - bool m_cleanup_after_stackfault; - u8* m_stack; + bool m_enable_blr_optimization; + bool m_cleanup_after_stackfault; + u8* m_stack; public: - Jit64() : code_buffer(32000) {} - ~Jit64() {} + Jit64() : code_buffer(32000) {} + ~Jit64() {} + void Init() override; - void Init() override; + void EnableOptimization(); - void EnableOptimization(); + void EnableBlockLink(); - void EnableBlockLink(); + void Shutdown() override; - void Shutdown() override; + bool HandleFault(uintptr_t access_address, SContext* ctx) override; - bool HandleFault(uintptr_t access_address, SContext* ctx) override; + bool HandleStackFault() override; - bool HandleStackFault() override; + // Jit! - // Jit! + void Jit(u32 em_address) override; + const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBlock* b, u32 nextPC); - void Jit(u32 em_address) override; - const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b, u32 nextPC); + BitSet32 CallerSavedRegistersInUse(); - BitSet32 CallerSavedRegistersInUse(); + JitBlockCache* GetBlockCache() override { return &blocks; } + void Trace(); - JitBlockCache *GetBlockCache() override { return &blocks; } + void ClearCache() override; - void Trace(); + const CommonAsmRoutines* GetAsmRoutines() override { return &asm_routines; } + const char* GetName() override { return "JIT64"; } + // Run! + void Run() override; + void SingleStep() override; - void ClearCache() override; + // Utilities for use by opcodes - const CommonAsmRoutines *GetAsmRoutines() override - { - return &asm_routines; - } + void WriteExit(u32 destination, bool bl = false, u32 after = 0); + void JustWriteExit(u32 destination, bool bl, u32 after); + void WriteExitDestInRSCRATCH(bool bl = false, u32 after = 0); + void WriteBLRExit(); + void WriteExceptionExit(); + void WriteExternalExceptionExit(); + void WriteRfiExitDestInRSCRATCH(); + bool Cleanup(); - const char *GetName() override - { - return "JIT64"; - } + void GenerateConstantOverflow(bool overflow); + void GenerateConstantOverflow(s64 val); + void GenerateOverflow(); + void FinalizeCarryOverflow(bool oe, bool inv = false); + void FinalizeCarry(Gen::CCFlags cond); + void FinalizeCarry(bool ca); + void ComputeRC(const Gen::OpArg& arg, bool needs_test = true, bool needs_sext = true); - // Run! - void Run() override; - void SingleStep() override; + // Use to extract bytes from a register using the regcache. offset is in bytes. + Gen::OpArg ExtractFromReg(int reg, int offset); + void AndWithMask(Gen::X64Reg reg, u32 mask); + bool CheckMergedBranch(int crf); + void DoMergedBranch(); + void DoMergedBranchCondition(); + void DoMergedBranchImmediate(s64 val); - // Utilities for use by opcodes + // Reads a given bit of a given CR register part. + void GetCRFieldBit(int field, int bit, Gen::X64Reg out, bool negate = false); + // Clobbers RDX. + void SetCRFieldBit(int field, int bit, Gen::X64Reg in); + void ClearCRFieldBit(int field, int bit); + void SetCRFieldBit(int field, int bit); - void WriteExit(u32 destination, bool bl = false, u32 after = 0); - void JustWriteExit(u32 destination, bool bl, u32 after); - void WriteExitDestInRSCRATCH(bool bl = false, u32 after = 0); - void WriteBLRExit(); - void WriteExceptionExit(); - void WriteExternalExceptionExit(); - void WriteRfiExitDestInRSCRATCH(); - bool Cleanup(); + // Generates a branch that will check if a given bit of a CR register part + // is set or not. + Gen::FixupBranch JumpIfCRFieldBit(int field, int bit, bool jump_if_set = true); + void SetFPRFIfNeeded(Gen::X64Reg xmm); - void GenerateConstantOverflow(bool overflow); - void GenerateConstantOverflow(s64 val); - void GenerateOverflow(); - void FinalizeCarryOverflow(bool oe, bool inv = false); - void FinalizeCarry(Gen::CCFlags cond); - void FinalizeCarry(bool ca); - void ComputeRC(const Gen::OpArg & arg, bool needs_test = true, bool needs_sext = true); + void HandleNaNs(UGeckoInstruction inst, Gen::X64Reg xmm_out, Gen::X64Reg xmm_in, + Gen::X64Reg clobber = Gen::XMM0); - // Use to extract bytes from a register using the regcache. offset is in bytes. - Gen::OpArg ExtractFromReg(int reg, int offset); - void AndWithMask(Gen::X64Reg reg, u32 mask); - bool CheckMergedBranch(int crf); - void DoMergedBranch(); - void DoMergedBranchCondition(); - void DoMergedBranchImmediate(s64 val); + void MultiplyImmediate(u32 imm, int a, int d, bool overflow); - // Reads a given bit of a given CR register part. - void GetCRFieldBit(int field, int bit, Gen::X64Reg out, bool negate = false); - // Clobbers RDX. - void SetCRFieldBit(int field, int bit, Gen::X64Reg in); - void ClearCRFieldBit(int field, int bit); - void SetCRFieldBit(int field, int bit); + typedef u32 (*Operation)(u32 a, u32 b); + void regimmop(int d, int a, bool binary, u32 value, Operation doop, + void (Gen::XEmitter::*op)(int, const Gen::OpArg&, const Gen::OpArg&), + bool Rc = false, bool carry = false); + Gen::X64Reg fp_tri_op(int d, int a, int b, bool reversible, bool single, + void (Gen::XEmitter::*avxOp)(Gen::X64Reg, Gen::X64Reg, const Gen::OpArg&), + void (Gen::XEmitter::*sseOp)(Gen::X64Reg, const Gen::OpArg&), bool packed, + bool preserve_inputs, bool roundRHS = false); + void FloatCompare(UGeckoInstruction inst, bool upper = false); + void UpdateMXCSR(); - // Generates a branch that will check if a given bit of a CR register part - // is set or not. - Gen::FixupBranch JumpIfCRFieldBit(int field, int bit, bool jump_if_set = true); - void SetFPRFIfNeeded(Gen::X64Reg xmm); + // OPCODES + using Instruction = void (Jit64::*)(UGeckoInstruction instCode); + void FallBackToInterpreter(UGeckoInstruction _inst); + void DoNothing(UGeckoInstruction _inst); + void HLEFunction(UGeckoInstruction _inst); - void HandleNaNs(UGeckoInstruction inst, Gen::X64Reg xmm_out, Gen::X64Reg xmm_in, - Gen::X64Reg clobber = Gen::XMM0); + void DynaRunTable4(UGeckoInstruction _inst); + void DynaRunTable19(UGeckoInstruction _inst); + void DynaRunTable31(UGeckoInstruction _inst); + void DynaRunTable59(UGeckoInstruction _inst); + void DynaRunTable63(UGeckoInstruction _inst); - void MultiplyImmediate(u32 imm, int a, int d, bool overflow); + void addx(UGeckoInstruction inst); + void arithcx(UGeckoInstruction inst); + void mulli(UGeckoInstruction inst); + void mulhwXx(UGeckoInstruction inst); + void mullwx(UGeckoInstruction inst); + void divwux(UGeckoInstruction inst); + void divwx(UGeckoInstruction inst); + void srawix(UGeckoInstruction inst); + void srawx(UGeckoInstruction inst); + void arithXex(UGeckoInstruction inst); - typedef u32 (*Operation)(u32 a, u32 b); - void regimmop(int d, int a, bool binary, u32 value, Operation doop, - void (Gen::XEmitter::*op)(int, const Gen::OpArg&, const Gen::OpArg&), - bool Rc = false, bool carry = false); - Gen::X64Reg fp_tri_op(int d, int a, int b, bool reversible, bool single, - void (Gen::XEmitter::*avxOp)(Gen::X64Reg, Gen::X64Reg, const Gen::OpArg&), - void (Gen::XEmitter::*sseOp)(Gen::X64Reg, const Gen::OpArg&), - bool packed, bool preserve_inputs, bool roundRHS = false); - void FloatCompare(UGeckoInstruction inst, bool upper = false); - void UpdateMXCSR(); + void extsXx(UGeckoInstruction inst); - // OPCODES - using Instruction = void (Jit64::*)(UGeckoInstruction instCode); - void FallBackToInterpreter(UGeckoInstruction _inst); - void DoNothing(UGeckoInstruction _inst); - void HLEFunction(UGeckoInstruction _inst); + void sc(UGeckoInstruction _inst); + void rfi(UGeckoInstruction _inst); - void DynaRunTable4(UGeckoInstruction _inst); - void DynaRunTable19(UGeckoInstruction _inst); - void DynaRunTable31(UGeckoInstruction _inst); - void DynaRunTable59(UGeckoInstruction _inst); - void DynaRunTable63(UGeckoInstruction _inst); + void bx(UGeckoInstruction inst); + void bclrx(UGeckoInstruction _inst); + void bcctrx(UGeckoInstruction _inst); + void bcx(UGeckoInstruction inst); - void addx(UGeckoInstruction inst); - void arithcx(UGeckoInstruction inst); - void mulli(UGeckoInstruction inst); - void mulhwXx(UGeckoInstruction inst); - void mullwx(UGeckoInstruction inst); - void divwux(UGeckoInstruction inst); - void divwx(UGeckoInstruction inst); - void srawix(UGeckoInstruction inst); - void srawx(UGeckoInstruction inst); - void arithXex(UGeckoInstruction inst); + void mtspr(UGeckoInstruction inst); + void mfspr(UGeckoInstruction inst); + void mtmsr(UGeckoInstruction inst); + void mfmsr(UGeckoInstruction inst); + void mftb(UGeckoInstruction inst); + void mtcrf(UGeckoInstruction inst); + void mfcr(UGeckoInstruction inst); + void mcrf(UGeckoInstruction inst); + void mcrxr(UGeckoInstruction inst); + void mcrfs(UGeckoInstruction inst); + void mffsx(UGeckoInstruction inst); + void mtfsb0x(UGeckoInstruction inst); + void mtfsb1x(UGeckoInstruction inst); + void mtfsfix(UGeckoInstruction inst); + void mtfsfx(UGeckoInstruction inst); - void extsXx(UGeckoInstruction inst); + void boolX(UGeckoInstruction inst); + void crXXX(UGeckoInstruction inst); - void sc(UGeckoInstruction _inst); - void rfi(UGeckoInstruction _inst); + void reg_imm(UGeckoInstruction inst); - void bx(UGeckoInstruction inst); - void bclrx(UGeckoInstruction _inst); - void bcctrx(UGeckoInstruction _inst); - void bcx(UGeckoInstruction inst); + void ps_mr(UGeckoInstruction inst); + void ps_mergeXX(UGeckoInstruction inst); + void ps_res(UGeckoInstruction inst); + void ps_rsqrte(UGeckoInstruction inst); + void ps_sum(UGeckoInstruction inst); + void ps_muls(UGeckoInstruction inst); + void ps_cmpXX(UGeckoInstruction inst); - void mtspr(UGeckoInstruction inst); - void mfspr(UGeckoInstruction inst); - void mtmsr(UGeckoInstruction inst); - void mfmsr(UGeckoInstruction inst); - void mftb(UGeckoInstruction inst); - void mtcrf(UGeckoInstruction inst); - void mfcr(UGeckoInstruction inst); - void mcrf(UGeckoInstruction inst); - void mcrxr(UGeckoInstruction inst); - void mcrfs(UGeckoInstruction inst); - void mffsx(UGeckoInstruction inst); - void mtfsb0x(UGeckoInstruction inst); - void mtfsb1x(UGeckoInstruction inst); - void mtfsfix(UGeckoInstruction inst); - void mtfsfx(UGeckoInstruction inst); + void fp_arith(UGeckoInstruction inst); - void boolX(UGeckoInstruction inst); - void crXXX(UGeckoInstruction inst); + void fcmpX(UGeckoInstruction inst); + void fctiwx(UGeckoInstruction inst); + void fmrx(UGeckoInstruction inst); + void frspx(UGeckoInstruction inst); + void frsqrtex(UGeckoInstruction inst); + void fresx(UGeckoInstruction inst); - void reg_imm(UGeckoInstruction inst); + void cmpXX(UGeckoInstruction inst); - void ps_mr(UGeckoInstruction inst); - void ps_mergeXX(UGeckoInstruction inst); - void ps_res(UGeckoInstruction inst); - void ps_rsqrte(UGeckoInstruction inst); - void ps_sum(UGeckoInstruction inst); - void ps_muls(UGeckoInstruction inst); - void ps_cmpXX(UGeckoInstruction inst); + void cntlzwx(UGeckoInstruction inst); - void fp_arith(UGeckoInstruction inst); + void lfXXX(UGeckoInstruction inst); + void stfXXX(UGeckoInstruction inst); + void stfiwx(UGeckoInstruction inst); + void psq_lXX(UGeckoInstruction inst); + void psq_stXX(UGeckoInstruction inst); - void fcmpX(UGeckoInstruction inst); - void fctiwx(UGeckoInstruction inst); - void fmrx(UGeckoInstruction inst); - void frspx(UGeckoInstruction inst); - void frsqrtex(UGeckoInstruction inst); - void fresx(UGeckoInstruction inst); + void fmaddXX(UGeckoInstruction inst); + void fsign(UGeckoInstruction inst); + void fselx(UGeckoInstruction inst); + void stX(UGeckoInstruction inst); // stw sth stb + void rlwinmx(UGeckoInstruction inst); + void rlwimix(UGeckoInstruction inst); + void rlwnmx(UGeckoInstruction inst); + void negx(UGeckoInstruction inst); + void slwx(UGeckoInstruction inst); + void srwx(UGeckoInstruction inst); + void dcbt(UGeckoInstruction inst); + void dcbz(UGeckoInstruction inst); - void cmpXX(UGeckoInstruction inst); + void subfic(UGeckoInstruction inst); + void subfx(UGeckoInstruction inst); - void cntlzwx(UGeckoInstruction inst); + void twX(UGeckoInstruction inst); - void lfXXX(UGeckoInstruction inst); - void stfXXX(UGeckoInstruction inst); - void stfiwx(UGeckoInstruction inst); - void psq_lXX(UGeckoInstruction inst); - void psq_stXX(UGeckoInstruction inst); + void lXXx(UGeckoInstruction inst); - void fmaddXX(UGeckoInstruction inst); - void fsign(UGeckoInstruction inst); - void fselx(UGeckoInstruction inst); - void stX(UGeckoInstruction inst); //stw sth stb - void rlwinmx(UGeckoInstruction inst); - void rlwimix(UGeckoInstruction inst); - void rlwnmx(UGeckoInstruction inst); - void negx(UGeckoInstruction inst); - void slwx(UGeckoInstruction inst); - void srwx(UGeckoInstruction inst); - void dcbt(UGeckoInstruction inst); - void dcbz(UGeckoInstruction inst); + void stXx(UGeckoInstruction inst); - void subfic(UGeckoInstruction inst); - void subfx(UGeckoInstruction inst); + void lmw(UGeckoInstruction inst); + void stmw(UGeckoInstruction inst); - void twX(UGeckoInstruction inst); - - void lXXx(UGeckoInstruction inst); - - void stXx(UGeckoInstruction inst); - - void lmw(UGeckoInstruction inst); - void stmw(UGeckoInstruction inst); - - void dcbx(UGeckoInstruction inst); + void dcbx(UGeckoInstruction inst); }; diff --git a/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp b/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp index d6541173fe..75df5bf07e 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp @@ -2,8 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/Jit64/Jit.h" +#include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/Jit64/Jit64_Tables.h" static Jit64::Instruction dynaOpTable[64]; @@ -12,460 +12,464 @@ static Jit64::Instruction dynaOpTable19[1024]; static Jit64::Instruction dynaOpTable31[1024]; static Jit64::Instruction dynaOpTable59[32]; static Jit64::Instruction dynaOpTable63[1024]; -void Jit64::DynaRunTable4(UGeckoInstruction _inst) {(this->*dynaOpTable4 [_inst.SUBOP10])(_inst);} -void Jit64::DynaRunTable19(UGeckoInstruction _inst) {(this->*dynaOpTable19[_inst.SUBOP10])(_inst);} -void Jit64::DynaRunTable31(UGeckoInstruction _inst) {(this->*dynaOpTable31[_inst.SUBOP10])(_inst);} -void Jit64::DynaRunTable59(UGeckoInstruction _inst) {(this->*dynaOpTable59[_inst.SUBOP5 ])(_inst);} -void Jit64::DynaRunTable63(UGeckoInstruction _inst) {(this->*dynaOpTable63[_inst.SUBOP10])(_inst);} +void Jit64::DynaRunTable4(UGeckoInstruction _inst) +{ + (this->*dynaOpTable4[_inst.SUBOP10])(_inst); +} +void Jit64::DynaRunTable19(UGeckoInstruction _inst) +{ + (this->*dynaOpTable19[_inst.SUBOP10])(_inst); +} +void Jit64::DynaRunTable31(UGeckoInstruction _inst) +{ + (this->*dynaOpTable31[_inst.SUBOP10])(_inst); +} +void Jit64::DynaRunTable59(UGeckoInstruction _inst) +{ + (this->*dynaOpTable59[_inst.SUBOP5])(_inst); +} +void Jit64::DynaRunTable63(UGeckoInstruction _inst) +{ + (this->*dynaOpTable63[_inst.SUBOP10])(_inst); +} struct GekkoOPTemplate { - int opcode; - Jit64::Instruction Inst; + int opcode; + Jit64::Instruction Inst; }; -static GekkoOPTemplate primarytable[] = -{ - {4, &Jit64::DynaRunTable4}, // RunTable4 - {19, &Jit64::DynaRunTable19}, // RunTable19 - {31, &Jit64::DynaRunTable31}, // RunTable31 - {59, &Jit64::DynaRunTable59}, // RunTable59 - {63, &Jit64::DynaRunTable63}, // RunTable63 +static GekkoOPTemplate primarytable[] = { + {4, &Jit64::DynaRunTable4}, // RunTable4 + {19, &Jit64::DynaRunTable19}, // RunTable19 + {31, &Jit64::DynaRunTable31}, // RunTable31 + {59, &Jit64::DynaRunTable59}, // RunTable59 + {63, &Jit64::DynaRunTable63}, // RunTable63 - {16, &Jit64::bcx}, // bcx - {18, &Jit64::bx}, // bx + {16, &Jit64::bcx}, // bcx + {18, &Jit64::bx}, // bx - {3, &Jit64::twX}, // twi - {17, &Jit64::sc}, // sc + {3, &Jit64::twX}, // twi + {17, &Jit64::sc}, // sc - {7, &Jit64::mulli}, // mulli - {8, &Jit64::subfic}, // subfic - {10, &Jit64::cmpXX}, // cmpli - {11, &Jit64::cmpXX}, // cmpi - {12, &Jit64::reg_imm}, // addic - {13, &Jit64::reg_imm}, // addic_rc - {14, &Jit64::reg_imm}, // addi - {15, &Jit64::reg_imm}, // addis + {7, &Jit64::mulli}, // mulli + {8, &Jit64::subfic}, // subfic + {10, &Jit64::cmpXX}, // cmpli + {11, &Jit64::cmpXX}, // cmpi + {12, &Jit64::reg_imm}, // addic + {13, &Jit64::reg_imm}, // addic_rc + {14, &Jit64::reg_imm}, // addi + {15, &Jit64::reg_imm}, // addis - {20, &Jit64::rlwimix}, // rlwimix - {21, &Jit64::rlwinmx}, // rlwinmx - {23, &Jit64::rlwnmx}, // rlwnmx + {20, &Jit64::rlwimix}, // rlwimix + {21, &Jit64::rlwinmx}, // rlwinmx + {23, &Jit64::rlwnmx}, // rlwnmx - {24, &Jit64::reg_imm}, // ori - {25, &Jit64::reg_imm}, // oris - {26, &Jit64::reg_imm}, // xori - {27, &Jit64::reg_imm}, // xoris - {28, &Jit64::reg_imm}, // andi_rc - {29, &Jit64::reg_imm}, // andis_rc + {24, &Jit64::reg_imm}, // ori + {25, &Jit64::reg_imm}, // oris + {26, &Jit64::reg_imm}, // xori + {27, &Jit64::reg_imm}, // xoris + {28, &Jit64::reg_imm}, // andi_rc + {29, &Jit64::reg_imm}, // andis_rc - {32, &Jit64::lXXx}, // lwz - {33, &Jit64::lXXx}, // lwzu - {34, &Jit64::lXXx}, // lbz - {35, &Jit64::lXXx}, // lbzu - {40, &Jit64::lXXx}, // lhz - {41, &Jit64::lXXx}, // lhzu - {42, &Jit64::lXXx}, // lha - {43, &Jit64::lXXx}, // lhau + {32, &Jit64::lXXx}, // lwz + {33, &Jit64::lXXx}, // lwzu + {34, &Jit64::lXXx}, // lbz + {35, &Jit64::lXXx}, // lbzu + {40, &Jit64::lXXx}, // lhz + {41, &Jit64::lXXx}, // lhzu + {42, &Jit64::lXXx}, // lha + {43, &Jit64::lXXx}, // lhau - {44, &Jit64::stX}, // sth - {45, &Jit64::stX}, // sthu - {36, &Jit64::stX}, // stw - {37, &Jit64::stX}, // stwu - {38, &Jit64::stX}, // stb - {39, &Jit64::stX}, // stbu + {44, &Jit64::stX}, // sth + {45, &Jit64::stX}, // sthu + {36, &Jit64::stX}, // stw + {37, &Jit64::stX}, // stwu + {38, &Jit64::stX}, // stb + {39, &Jit64::stX}, // stbu - {46, &Jit64::lmw}, // lmw - {47, &Jit64::stmw}, // stmw + {46, &Jit64::lmw}, // lmw + {47, &Jit64::stmw}, // stmw - {48, &Jit64::lfXXX}, // lfs - {49, &Jit64::lfXXX}, // lfsu - {50, &Jit64::lfXXX}, // lfd - {51, &Jit64::lfXXX}, // lfdu + {48, &Jit64::lfXXX}, // lfs + {49, &Jit64::lfXXX}, // lfsu + {50, &Jit64::lfXXX}, // lfd + {51, &Jit64::lfXXX}, // lfdu - {52, &Jit64::stfXXX}, // stfs - {53, &Jit64::stfXXX}, // stfsu - {54, &Jit64::stfXXX}, // stfd - {55, &Jit64::stfXXX}, // stfdu + {52, &Jit64::stfXXX}, // stfs + {53, &Jit64::stfXXX}, // stfsu + {54, &Jit64::stfXXX}, // stfd + {55, &Jit64::stfXXX}, // stfdu - {56, &Jit64::psq_lXX}, // psq_l - {57, &Jit64::psq_lXX}, // psq_lu - {60, &Jit64::psq_stXX}, // psq_st - {61, &Jit64::psq_stXX}, // psq_stu + {56, &Jit64::psq_lXX}, // psq_l + {57, &Jit64::psq_lXX}, // psq_lu + {60, &Jit64::psq_stXX}, // psq_st + {61, &Jit64::psq_stXX}, // psq_stu - //missing: 0, 1, 2, 5, 6, 9, 22, 30, 62, 58 + // missing: 0, 1, 2, 5, 6, 9, 22, 30, 62, 58 }; -static GekkoOPTemplate table4[] = -{ //SUBOP10 - {0, &Jit64::ps_cmpXX}, // ps_cmpu0 - {32, &Jit64::ps_cmpXX}, // ps_cmpo0 - {40, &Jit64::fsign}, // ps_neg - {136, &Jit64::fsign}, // ps_nabs - {264, &Jit64::fsign}, // ps_abs - {64, &Jit64::ps_cmpXX}, // ps_cmpu1 - {72, &Jit64::ps_mr}, // ps_mr - {96, &Jit64::ps_cmpXX}, // ps_cmpo1 - {528, &Jit64::ps_mergeXX}, // ps_merge00 - {560, &Jit64::ps_mergeXX}, // ps_merge01 - {592, &Jit64::ps_mergeXX}, // ps_merge10 - {624, &Jit64::ps_mergeXX}, // ps_merge11 +static GekkoOPTemplate table4[] = { + // SUBOP10 + {0, &Jit64::ps_cmpXX}, // ps_cmpu0 + {32, &Jit64::ps_cmpXX}, // ps_cmpo0 + {40, &Jit64::fsign}, // ps_neg + {136, &Jit64::fsign}, // ps_nabs + {264, &Jit64::fsign}, // ps_abs + {64, &Jit64::ps_cmpXX}, // ps_cmpu1 + {72, &Jit64::ps_mr}, // ps_mr + {96, &Jit64::ps_cmpXX}, // ps_cmpo1 + {528, &Jit64::ps_mergeXX}, // ps_merge00 + {560, &Jit64::ps_mergeXX}, // ps_merge01 + {592, &Jit64::ps_mergeXX}, // ps_merge10 + {624, &Jit64::ps_mergeXX}, // ps_merge11 - {1014, &Jit64::FallBackToInterpreter}, // dcbz_l + {1014, &Jit64::FallBackToInterpreter}, // dcbz_l }; -static GekkoOPTemplate table4_2[] = -{ - {10, &Jit64::ps_sum}, // ps_sum0 - {11, &Jit64::ps_sum}, // ps_sum1 - {12, &Jit64::ps_muls}, // ps_muls0 - {13, &Jit64::ps_muls}, // ps_muls1 - {14, &Jit64::fmaddXX}, // ps_madds0 - {15, &Jit64::fmaddXX}, // ps_madds1 - {18, &Jit64::fp_arith}, // ps_div - {20, &Jit64::fp_arith}, // ps_sub - {21, &Jit64::fp_arith}, // ps_add - {23, &Jit64::fselx}, // ps_sel - {24, &Jit64::ps_res}, // ps_res - {25, &Jit64::fp_arith}, // ps_mul - {26, &Jit64::ps_rsqrte}, // ps_rsqrte - {28, &Jit64::fmaddXX}, // ps_msub - {29, &Jit64::fmaddXX}, // ps_madd - {30, &Jit64::fmaddXX}, // ps_nmsub - {31, &Jit64::fmaddXX}, // ps_nmadd +static GekkoOPTemplate table4_2[] = { + {10, &Jit64::ps_sum}, // ps_sum0 + {11, &Jit64::ps_sum}, // ps_sum1 + {12, &Jit64::ps_muls}, // ps_muls0 + {13, &Jit64::ps_muls}, // ps_muls1 + {14, &Jit64::fmaddXX}, // ps_madds0 + {15, &Jit64::fmaddXX}, // ps_madds1 + {18, &Jit64::fp_arith}, // ps_div + {20, &Jit64::fp_arith}, // ps_sub + {21, &Jit64::fp_arith}, // ps_add + {23, &Jit64::fselx}, // ps_sel + {24, &Jit64::ps_res}, // ps_res + {25, &Jit64::fp_arith}, // ps_mul + {26, &Jit64::ps_rsqrte}, // ps_rsqrte + {28, &Jit64::fmaddXX}, // ps_msub + {29, &Jit64::fmaddXX}, // ps_madd + {30, &Jit64::fmaddXX}, // ps_nmsub + {31, &Jit64::fmaddXX}, // ps_nmadd }; - -static GekkoOPTemplate table4_3[] = -{ - {6, &Jit64::psq_lXX}, // psq_lx - {7, &Jit64::psq_stXX}, // psq_stx - {38, &Jit64::psq_lXX}, // psq_lux - {39, &Jit64::psq_stXX}, // psq_stux +static GekkoOPTemplate table4_3[] = { + {6, &Jit64::psq_lXX}, // psq_lx + {7, &Jit64::psq_stXX}, // psq_stx + {38, &Jit64::psq_lXX}, // psq_lux + {39, &Jit64::psq_stXX}, // psq_stux }; -static GekkoOPTemplate table19[] = -{ - {528, &Jit64::bcctrx}, // bcctrx - {16, &Jit64::bclrx}, // bclrx - {257, &Jit64::crXXX}, // crand - {129, &Jit64::crXXX}, // crandc - {289, &Jit64::crXXX}, // creqv - {225, &Jit64::crXXX}, // crnand - {33, &Jit64::crXXX}, // crnor - {449, &Jit64::crXXX}, // cror - {417, &Jit64::crXXX}, // crorc - {193, &Jit64::crXXX}, // crxor +static GekkoOPTemplate table19[] = { + {528, &Jit64::bcctrx}, // bcctrx + {16, &Jit64::bclrx}, // bclrx + {257, &Jit64::crXXX}, // crand + {129, &Jit64::crXXX}, // crandc + {289, &Jit64::crXXX}, // creqv + {225, &Jit64::crXXX}, // crnand + {33, &Jit64::crXXX}, // crnor + {449, &Jit64::crXXX}, // cror + {417, &Jit64::crXXX}, // crorc + {193, &Jit64::crXXX}, // crxor - {150, &Jit64::DoNothing}, // isync - {0, &Jit64::mcrf}, // mcrf + {150, &Jit64::DoNothing}, // isync + {0, &Jit64::mcrf}, // mcrf - {50, &Jit64::rfi}, // rfi + {50, &Jit64::rfi}, // rfi }; +static GekkoOPTemplate table31[] = { + {266, &Jit64::addx}, // addx + {778, &Jit64::addx}, // addox + {10, &Jit64::arithcx}, // addcx + {522, &Jit64::arithcx}, // addcox + {138, &Jit64::arithXex}, // addex + {650, &Jit64::arithXex}, // addeox + {234, &Jit64::arithXex}, // addmex + {746, &Jit64::arithXex}, // addmeox + {202, &Jit64::arithXex}, // addzex + {714, &Jit64::arithXex}, // addzeox + {491, &Jit64::divwx}, // divwx + {1003, &Jit64::divwx}, // divwox + {459, &Jit64::divwux}, // divwux + {971, &Jit64::divwux}, // divwuox + {75, &Jit64::mulhwXx}, // mulhwx + {11, &Jit64::mulhwXx}, // mulhwux + {235, &Jit64::mullwx}, // mullwx + {747, &Jit64::mullwx}, // mullwox + {104, &Jit64::negx}, // negx + {616, &Jit64::negx}, // negox + {40, &Jit64::subfx}, // subfx + {552, &Jit64::subfx}, // subfox + {8, &Jit64::arithcx}, // subfcx + {520, &Jit64::arithcx}, // subfcox + {136, &Jit64::arithXex}, // subfex + {648, &Jit64::arithXex}, // subfeox + {232, &Jit64::arithXex}, // subfmex + {744, &Jit64::arithXex}, // subfmeox + {200, &Jit64::arithXex}, // subfzex + {712, &Jit64::arithXex}, // subfzeox -static GekkoOPTemplate table31[] = -{ - {266, &Jit64::addx}, // addx - {778, &Jit64::addx}, // addox - {10, &Jit64::arithcx}, // addcx - {522, &Jit64::arithcx}, // addcox - {138, &Jit64::arithXex}, // addex - {650, &Jit64::arithXex}, // addeox - {234, &Jit64::arithXex}, // addmex - {746, &Jit64::arithXex}, // addmeox - {202, &Jit64::arithXex}, // addzex - {714, &Jit64::arithXex}, // addzeox - {491, &Jit64::divwx}, // divwx - {1003, &Jit64::divwx}, // divwox - {459, &Jit64::divwux}, // divwux - {971, &Jit64::divwux}, // divwuox - {75, &Jit64::mulhwXx}, // mulhwx - {11, &Jit64::mulhwXx}, // mulhwux - {235, &Jit64::mullwx}, // mullwx - {747, &Jit64::mullwx}, // mullwox - {104, &Jit64::negx}, // negx - {616, &Jit64::negx}, // negox - {40, &Jit64::subfx}, // subfx - {552, &Jit64::subfx}, // subfox - {8, &Jit64::arithcx}, // subfcx - {520, &Jit64::arithcx}, // subfcox - {136, &Jit64::arithXex}, // subfex - {648, &Jit64::arithXex}, // subfeox - {232, &Jit64::arithXex}, // subfmex - {744, &Jit64::arithXex}, // subfmeox - {200, &Jit64::arithXex}, // subfzex - {712, &Jit64::arithXex}, // subfzeox + {28, &Jit64::boolX}, // andx + {60, &Jit64::boolX}, // andcx + {444, &Jit64::boolX}, // orx + {124, &Jit64::boolX}, // norx + {316, &Jit64::boolX}, // xorx + {412, &Jit64::boolX}, // orcx + {476, &Jit64::boolX}, // nandx + {284, &Jit64::boolX}, // eqvx + {0, &Jit64::cmpXX}, // cmp + {32, &Jit64::cmpXX}, // cmpl + {26, &Jit64::cntlzwx}, // cntlzwx + {922, &Jit64::extsXx}, // extshx + {954, &Jit64::extsXx}, // extsbx + {536, &Jit64::srwx}, // srwx + {792, &Jit64::srawx}, // srawx + {824, &Jit64::srawix}, // srawix + {24, &Jit64::slwx}, // slwx - {28, &Jit64::boolX}, // andx - {60, &Jit64::boolX}, // andcx - {444, &Jit64::boolX}, // orx - {124, &Jit64::boolX}, // norx - {316, &Jit64::boolX}, // xorx - {412, &Jit64::boolX}, // orcx - {476, &Jit64::boolX}, // nandx - {284, &Jit64::boolX}, // eqvx - {0, &Jit64::cmpXX}, // cmp - {32, &Jit64::cmpXX}, // cmpl - {26, &Jit64::cntlzwx}, // cntlzwx - {922, &Jit64::extsXx}, // extshx - {954, &Jit64::extsXx}, // extsbx - {536, &Jit64::srwx}, // srwx - {792, &Jit64::srawx}, // srawx - {824, &Jit64::srawix}, // srawix - {24, &Jit64::slwx}, // slwx + {54, &Jit64::dcbx}, // dcbst + {86, &Jit64::dcbx}, // dcbf + {246, &Jit64::dcbt}, // dcbtst + {278, &Jit64::dcbt}, // dcbt + {470, &Jit64::dcbx}, // dcbi + {758, &Jit64::DoNothing}, // dcba + {1014, &Jit64::dcbz}, // dcbz - {54, &Jit64::dcbx}, // dcbst - {86, &Jit64::dcbx}, // dcbf - {246, &Jit64::dcbt}, // dcbtst - {278, &Jit64::dcbt}, // dcbt - {470, &Jit64::dcbx}, // dcbi - {758, &Jit64::DoNothing}, // dcba - {1014, &Jit64::dcbz}, // dcbz + // load word + {23, &Jit64::lXXx}, // lwzx + {55, &Jit64::lXXx}, // lwzux - //load word - {23, &Jit64::lXXx}, // lwzx - {55, &Jit64::lXXx}, // lwzux + // load halfword + {279, &Jit64::lXXx}, // lhzx + {311, &Jit64::lXXx}, // lhzux - //load halfword - {279, &Jit64::lXXx}, // lhzx - {311, &Jit64::lXXx}, // lhzux + // load halfword signextend + {343, &Jit64::lXXx}, // lhax + {375, &Jit64::lXXx}, // lhaux - //load halfword signextend - {343, &Jit64::lXXx}, // lhax - {375, &Jit64::lXXx}, // lhaux + // load byte + {87, &Jit64::lXXx}, // lbzx + {119, &Jit64::lXXx}, // lbzux - //load byte - {87, &Jit64::lXXx}, // lbzx - {119, &Jit64::lXXx}, // lbzux + // load byte reverse + {534, &Jit64::lXXx}, // lwbrx + {790, &Jit64::lXXx}, // lhbrx - //load byte reverse - {534, &Jit64::lXXx}, // lwbrx - {790, &Jit64::lXXx}, // lhbrx + // Conditional load/store (Wii SMP) + {150, &Jit64::FallBackToInterpreter}, // stwcxd + {20, &Jit64::FallBackToInterpreter}, // lwarx - // Conditional load/store (Wii SMP) - {150, &Jit64::FallBackToInterpreter}, // stwcxd - {20, &Jit64::FallBackToInterpreter}, // lwarx + // load string (interpret these) + {533, &Jit64::FallBackToInterpreter}, // lswx + {597, &Jit64::FallBackToInterpreter}, // lswi - //load string (interpret these) - {533, &Jit64::FallBackToInterpreter}, // lswx - {597, &Jit64::FallBackToInterpreter}, // lswi + // store word + {151, &Jit64::stXx}, // stwx + {183, &Jit64::stXx}, // stwux - //store word - {151, &Jit64::stXx}, // stwx - {183, &Jit64::stXx}, // stwux + // store halfword + {407, &Jit64::stXx}, // sthx + {439, &Jit64::stXx}, // sthux - //store halfword - {407, &Jit64::stXx}, // sthx - {439, &Jit64::stXx}, // sthux + // store byte + {215, &Jit64::stXx}, // stbx + {247, &Jit64::stXx}, // stbux - //store byte - {215, &Jit64::stXx}, // stbx - {247, &Jit64::stXx}, // stbux + // store bytereverse + {662, &Jit64::stXx}, // stwbrx + {918, &Jit64::stXx}, // sthbrx - //store bytereverse - {662, &Jit64::stXx}, // stwbrx - {918, &Jit64::stXx}, // sthbrx + {661, &Jit64::FallBackToInterpreter}, // stswx + {725, &Jit64::FallBackToInterpreter}, // stswi - {661, &Jit64::FallBackToInterpreter}, // stswx - {725, &Jit64::FallBackToInterpreter}, // stswi + // fp load/store + {535, &Jit64::lfXXX}, // lfsx + {567, &Jit64::lfXXX}, // lfsux + {599, &Jit64::lfXXX}, // lfdx + {631, &Jit64::lfXXX}, // lfdux - // fp load/store - {535, &Jit64::lfXXX}, // lfsx - {567, &Jit64::lfXXX}, // lfsux - {599, &Jit64::lfXXX}, // lfdx - {631, &Jit64::lfXXX}, // lfdux + {663, &Jit64::stfXXX}, // stfsx + {695, &Jit64::stfXXX}, // stfsux + {727, &Jit64::stfXXX}, // stfdx + {759, &Jit64::stfXXX}, // stfdux + {983, &Jit64::stfiwx}, // stfiwx - {663, &Jit64::stfXXX}, // stfsx - {695, &Jit64::stfXXX}, // stfsux - {727, &Jit64::stfXXX}, // stfdx - {759, &Jit64::stfXXX}, // stfdux - {983, &Jit64::stfiwx}, // stfiwx + {19, &Jit64::mfcr}, // mfcr + {83, &Jit64::mfmsr}, // mfmsr + {144, &Jit64::mtcrf}, // mtcrf + {146, &Jit64::mtmsr}, // mtmsr + {210, &Jit64::FallBackToInterpreter}, // mtsr + {242, &Jit64::FallBackToInterpreter}, // mtsrin + {339, &Jit64::mfspr}, // mfspr + {467, &Jit64::mtspr}, // mtspr + {371, &Jit64::mftb}, // mftb + {512, &Jit64::mcrxr}, // mcrxr + {595, &Jit64::FallBackToInterpreter}, // mfsr + {659, &Jit64::FallBackToInterpreter}, // mfsrin - {19, &Jit64::mfcr}, // mfcr - {83, &Jit64::mfmsr}, // mfmsr - {144, &Jit64::mtcrf}, // mtcrf - {146, &Jit64::mtmsr}, // mtmsr - {210, &Jit64::FallBackToInterpreter}, // mtsr - {242, &Jit64::FallBackToInterpreter}, // mtsrin - {339, &Jit64::mfspr}, // mfspr - {467, &Jit64::mtspr}, // mtspr - {371, &Jit64::mftb}, // mftb - {512, &Jit64::mcrxr}, // mcrxr - {595, &Jit64::FallBackToInterpreter}, // mfsr - {659, &Jit64::FallBackToInterpreter}, // mfsrin + {4, &Jit64::twX}, // tw + {598, &Jit64::DoNothing}, // sync + {982, &Jit64::FallBackToInterpreter}, // icbi - {4, &Jit64::twX}, // tw - {598, &Jit64::DoNothing}, // sync - {982, &Jit64::FallBackToInterpreter}, // icbi - - // Unused instructions on GC - {310, &Jit64::FallBackToInterpreter}, // eciwx - {438, &Jit64::FallBackToInterpreter}, // ecowx - {854, &Jit64::DoNothing}, // eieio - {306, &Jit64::FallBackToInterpreter}, // tlbie - {566, &Jit64::DoNothing}, // tlbsync + // Unused instructions on GC + {310, &Jit64::FallBackToInterpreter}, // eciwx + {438, &Jit64::FallBackToInterpreter}, // ecowx + {854, &Jit64::DoNothing}, // eieio + {306, &Jit64::FallBackToInterpreter}, // tlbie + {566, &Jit64::DoNothing}, // tlbsync }; -static GekkoOPTemplate table59[] = -{ - {18, &Jit64::fp_arith}, // fdivsx - {20, &Jit64::fp_arith}, // fsubsx - {21, &Jit64::fp_arith}, // faddsx - {24, &Jit64::fresx}, // fresx - {25, &Jit64::fp_arith}, // fmulsx - {28, &Jit64::fmaddXX}, // fmsubsx - {29, &Jit64::fmaddXX}, // fmaddsx - {30, &Jit64::fmaddXX}, // fnmsubsx - {31, &Jit64::fmaddXX}, // fnmaddsx +static GekkoOPTemplate table59[] = { + {18, &Jit64::fp_arith}, // fdivsx + {20, &Jit64::fp_arith}, // fsubsx + {21, &Jit64::fp_arith}, // faddsx + {24, &Jit64::fresx}, // fresx + {25, &Jit64::fp_arith}, // fmulsx + {28, &Jit64::fmaddXX}, // fmsubsx + {29, &Jit64::fmaddXX}, // fmaddsx + {30, &Jit64::fmaddXX}, // fnmsubsx + {31, &Jit64::fmaddXX}, // fnmaddsx }; -static GekkoOPTemplate table63[] = -{ - {264, &Jit64::fsign}, // fabsx - {32, &Jit64::fcmpX}, // fcmpo - {0, &Jit64::fcmpX}, // fcmpu - {14, &Jit64::fctiwx}, // fctiwx - {15, &Jit64::fctiwx}, // fctiwzx - {72, &Jit64::fmrx}, // fmrx - {136, &Jit64::fsign}, // fnabsx - {40, &Jit64::fsign}, // fnegx - {12, &Jit64::frspx}, // frspx +static GekkoOPTemplate table63[] = { + {264, &Jit64::fsign}, // fabsx + {32, &Jit64::fcmpX}, // fcmpo + {0, &Jit64::fcmpX}, // fcmpu + {14, &Jit64::fctiwx}, // fctiwx + {15, &Jit64::fctiwx}, // fctiwzx + {72, &Jit64::fmrx}, // fmrx + {136, &Jit64::fsign}, // fnabsx + {40, &Jit64::fsign}, // fnegx + {12, &Jit64::frspx}, // frspx - {64, &Jit64::mcrfs}, // mcrfs - {583, &Jit64::mffsx}, // mffsx - {70, &Jit64::mtfsb0x}, // mtfsb0x - {38, &Jit64::mtfsb1x}, // mtfsb1x - {134, &Jit64::mtfsfix}, // mtfsfix - {711, &Jit64::mtfsfx}, // mtfsfx + {64, &Jit64::mcrfs}, // mcrfs + {583, &Jit64::mffsx}, // mffsx + {70, &Jit64::mtfsb0x}, // mtfsb0x + {38, &Jit64::mtfsb1x}, // mtfsb1x + {134, &Jit64::mtfsfix}, // mtfsfix + {711, &Jit64::mtfsfx}, // mtfsfx }; -static GekkoOPTemplate table63_2[] = -{ - {18, &Jit64::fp_arith}, // fdivx - {20, &Jit64::fp_arith}, // fsubx - {21, &Jit64::fp_arith}, // faddx - {23, &Jit64::fselx}, // fselx - {25, &Jit64::fp_arith}, // fmulx - {26, &Jit64::frsqrtex}, // frsqrtex - {28, &Jit64::fmaddXX}, // fmsubx - {29, &Jit64::fmaddXX}, // fmaddx - {30, &Jit64::fmaddXX}, // fnmsubx - {31, &Jit64::fmaddXX}, // fnmaddx +static GekkoOPTemplate table63_2[] = { + {18, &Jit64::fp_arith}, // fdivx + {20, &Jit64::fp_arith}, // fsubx + {21, &Jit64::fp_arith}, // faddx + {23, &Jit64::fselx}, // fselx + {25, &Jit64::fp_arith}, // fmulx + {26, &Jit64::frsqrtex}, // frsqrtex + {28, &Jit64::fmaddXX}, // fmsubx + {29, &Jit64::fmaddXX}, // fmaddx + {30, &Jit64::fmaddXX}, // fnmsubx + {31, &Jit64::fmaddXX}, // fnmaddx }; namespace Jit64Tables { - -void CompileInstruction(PPCAnalyst::CodeOp & op) +void CompileInstruction(PPCAnalyst::CodeOp& op) { - Jit64 *jit64 = (Jit64 *)jit; - (jit64->*dynaOpTable[op.inst.OPCD])(op.inst); - GekkoOPInfo *info = op.opinfo; - if (info) - { + Jit64* jit64 = (Jit64*)jit; + (jit64->*dynaOpTable[op.inst.OPCD])(op.inst); + GekkoOPInfo* info = op.opinfo; + if (info) + { #ifdef OPLOG - if (!strcmp(info->opname, OP_TO_LOG)) // "mcrfs" - { - rsplocations.push_back(jit.js.compilerPC); - } + if (!strcmp(info->opname, OP_TO_LOG)) // "mcrfs" + { + rsplocations.push_back(jit.js.compilerPC); + } #endif - info->compileCount++; - info->lastUse = jit->js.compilerPC; - } + info->compileCount++; + info->lastUse = jit->js.compilerPC; + } } void InitTables() { - // once initialized, tables are read-only - static bool initialized = false; - if (initialized) - return; + // once initialized, tables are read-only + static bool initialized = false; + if (initialized) + return; - //clear - for (auto& tpl : dynaOpTable) - { - tpl = &Jit64::FallBackToInterpreter; - } + // clear + for (auto& tpl : dynaOpTable) + { + tpl = &Jit64::FallBackToInterpreter; + } - for (auto& tpl : dynaOpTable59) - { - tpl = &Jit64::FallBackToInterpreter; - } + for (auto& tpl : dynaOpTable59) + { + tpl = &Jit64::FallBackToInterpreter; + } - for (int i = 0; i < 1024; i++) - { - dynaOpTable4 [i] = &Jit64::FallBackToInterpreter; - dynaOpTable19[i] = &Jit64::FallBackToInterpreter; - dynaOpTable31[i] = &Jit64::FallBackToInterpreter; - dynaOpTable63[i] = &Jit64::FallBackToInterpreter; - } + for (int i = 0; i < 1024; i++) + { + dynaOpTable4[i] = &Jit64::FallBackToInterpreter; + dynaOpTable19[i] = &Jit64::FallBackToInterpreter; + dynaOpTable31[i] = &Jit64::FallBackToInterpreter; + dynaOpTable63[i] = &Jit64::FallBackToInterpreter; + } - for (auto& tpl : primarytable) - { - dynaOpTable[tpl.opcode] = tpl.Inst; - } + for (auto& tpl : primarytable) + { + dynaOpTable[tpl.opcode] = tpl.Inst; + } - for (int i = 0; i < 32; i++) - { - int fill = i << 5; - for (auto& tpl : table4_2) - { - int op = fill+tpl.opcode; - dynaOpTable4[op] = tpl.Inst; - } - } + for (int i = 0; i < 32; i++) + { + int fill = i << 5; + for (auto& tpl : table4_2) + { + int op = fill + tpl.opcode; + dynaOpTable4[op] = tpl.Inst; + } + } - for (int i = 0; i < 16; i++) - { - int fill = i << 6; - for (auto& tpl : table4_3) - { - int op = fill+tpl.opcode; - dynaOpTable4[op] = tpl.Inst; - } - } + for (int i = 0; i < 16; i++) + { + int fill = i << 6; + for (auto& tpl : table4_3) + { + int op = fill + tpl.opcode; + dynaOpTable4[op] = tpl.Inst; + } + } - for (auto& tpl : table4) - { - int op = tpl.opcode; - dynaOpTable4[op] = tpl.Inst; - } + for (auto& tpl : table4) + { + int op = tpl.opcode; + dynaOpTable4[op] = tpl.Inst; + } - for (auto& tpl : table31) - { - int op = tpl.opcode; - dynaOpTable31[op] = tpl.Inst; - } + for (auto& tpl : table31) + { + int op = tpl.opcode; + dynaOpTable31[op] = tpl.Inst; + } - for (auto& tpl : table19) - { - int op = tpl.opcode; - dynaOpTable19[op] = tpl.Inst; - } + for (auto& tpl : table19) + { + int op = tpl.opcode; + dynaOpTable19[op] = tpl.Inst; + } - for (auto& tpl : table59) - { - int op = tpl.opcode; - dynaOpTable59[op] = tpl.Inst; - } + for (auto& tpl : table59) + { + int op = tpl.opcode; + dynaOpTable59[op] = tpl.Inst; + } - for (auto& tpl : table63) - { - int op = tpl.opcode; - dynaOpTable63[op] = tpl.Inst; - } + for (auto& tpl : table63) + { + int op = tpl.opcode; + dynaOpTable63[op] = tpl.Inst; + } - for (int i = 0; i < 32; i++) - { - int fill = i << 5; - for (auto& tpl : table63_2) - { - int op = fill + tpl.opcode; - dynaOpTable63[op] = tpl.Inst; - } - } + for (int i = 0; i < 32; i++) + { + int fill = i << 5; + for (auto& tpl : table63_2) + { + int op = fill + tpl.opcode; + dynaOpTable63[op] = tpl.Inst; + } + } - initialized = true; + initialized = true; } } // namespace diff --git a/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.h b/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.h index 012d335ffe..a36d0c5156 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.h +++ b/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.h @@ -4,10 +4,13 @@ #pragma once -namespace PPCAnalyst { struct CodeOp; } +namespace PPCAnalyst +{ +struct CodeOp; +} namespace Jit64Tables { - void CompileInstruction(PPCAnalyst::CodeOp& op); - void InitTables(); +void CompileInstruction(PPCAnalyst::CodeOp& op); +void InitTables(); } diff --git a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp index 28deee1053..fbc3eb584e 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/Jit64/Jit.h" #include "Common/CommonTypes.h" #include "Common/JitRegister.h" #include "Common/x64ABI.h" @@ -10,9 +11,8 @@ #include "Core/CoreTiming.h" #include "Core/HW/CPU.h" #include "Core/HW/Memmap.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/Jit64/Jit.h" #include "Core/PowerPC/Jit64/JitAsm.h" +#include "Core/PowerPC/PowerPC.h" using namespace Gen; @@ -25,255 +25,256 @@ static void* s_saved_rsp; void Jit64AsmRoutineManager::Generate() { - enterCode = AlignCode16(); - // We need to own the beginning of RSP, so we do an extra stack adjustment - // for the shadow region before calls in this function. This call will - // waste a bit of space for a second shadow, but whatever. - ABI_PushRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8, /*frame*/ 16); - if (m_stack_top) - { - // Pivot the stack to our custom one. - MOV(64, R(RSCRATCH), R(RSP)); - MOV(64, R(RSP), Imm64((u64)m_stack_top - 0x20)); - MOV(64, MDisp(RSP, 0x18), R(RSCRATCH)); - } - else - { - MOV(64, M(&s_saved_rsp), R(RSP)); - } - // something that can't pass the BLR test - MOV(64, MDisp(RSP, 8), Imm32((u32)-1)); + enterCode = AlignCode16(); + // We need to own the beginning of RSP, so we do an extra stack adjustment + // for the shadow region before calls in this function. This call will + // waste a bit of space for a second shadow, but whatever. + ABI_PushRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8, /*frame*/ 16); + if (m_stack_top) + { + // Pivot the stack to our custom one. + MOV(64, R(RSCRATCH), R(RSP)); + MOV(64, R(RSP), Imm64((u64)m_stack_top - 0x20)); + MOV(64, MDisp(RSP, 0x18), R(RSCRATCH)); + } + else + { + MOV(64, M(&s_saved_rsp), R(RSP)); + } + // something that can't pass the BLR test + MOV(64, MDisp(RSP, 8), Imm32((u32)-1)); - // Two statically allocated registers. - //MOV(64, R(RMEM), Imm64((u64)Memory::physical_base)); - MOV(64, R(RPPCSTATE), Imm64((u64)&PowerPC::ppcState + 0x80)); + // Two statically allocated registers. + // MOV(64, R(RMEM), Imm64((u64)Memory::physical_base)); + MOV(64, R(RPPCSTATE), Imm64((u64)&PowerPC::ppcState + 0x80)); - const u8* outerLoop = GetCodePtr(); - ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunction(reinterpret_cast(&CoreTiming::Advance)); - ABI_PopRegistersAndAdjustStack({}, 0); - FixupBranch skipToRealDispatch = J(SConfig::GetInstance().bEnableDebugging); //skip the sync and compare first time - dispatcherMispredictedBLR = GetCodePtr(); - AND(32, PPCSTATE(pc), Imm32(0xFFFFFFFC)); + const u8* outerLoop = GetCodePtr(); + ABI_PushRegistersAndAdjustStack({}, 0); + ABI_CallFunction(reinterpret_cast(&CoreTiming::Advance)); + ABI_PopRegistersAndAdjustStack({}, 0); + FixupBranch skipToRealDispatch = + J(SConfig::GetInstance().bEnableDebugging); // skip the sync and compare first time + dispatcherMispredictedBLR = GetCodePtr(); + AND(32, PPCSTATE(pc), Imm32(0xFFFFFFFC)); - #if 0 // debug mispredicts +#if 0 // debug mispredicts MOV(32, R(ABI_PARAM1), MDisp(RSP, 8)); // guessed_pc ABI_PushRegistersAndAdjustStack(1 << RSCRATCH2, 0); CALL(reinterpret_cast(&ReportMispredict)); ABI_PopRegistersAndAdjustStack(1 << RSCRATCH2, 0); - #endif +#endif - ResetStack(); + ResetStack(); - SUB(32, PPCSTATE(downcount), R(RSCRATCH2)); + SUB(32, PPCSTATE(downcount), R(RSCRATCH2)); - dispatcher = GetCodePtr(); - // The result of slice decrementation should be in flags if somebody jumped here - // IMPORTANT - We jump on negative, not carry!!! - FixupBranch bail = J_CC(CC_BE, true); + dispatcher = GetCodePtr(); + // The result of slice decrementation should be in flags if somebody jumped here + // IMPORTANT - We jump on negative, not carry!!! + FixupBranch bail = J_CC(CC_BE, true); - FixupBranch dbg_exit; + FixupBranch dbg_exit; - if (SConfig::GetInstance().bEnableDebugging) - { - TEST(32, M(CPU::GetStatePtr()), Imm32(CPU::CPU_STEPPING)); - FixupBranch notStepping = J_CC(CC_Z); - ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunction(reinterpret_cast(&PowerPC::CheckBreakPoints)); - ABI_PopRegistersAndAdjustStack({}, 0); - TEST(32, M(CPU::GetStatePtr()), Imm32(0xFFFFFFFF)); - dbg_exit = J_CC(CC_NZ, true); - SetJumpTarget(notStepping); - } + if (SConfig::GetInstance().bEnableDebugging) + { + TEST(32, M(CPU::GetStatePtr()), Imm32(CPU::CPU_STEPPING)); + FixupBranch notStepping = J_CC(CC_Z); + ABI_PushRegistersAndAdjustStack({}, 0); + ABI_CallFunction(reinterpret_cast(&PowerPC::CheckBreakPoints)); + ABI_PopRegistersAndAdjustStack({}, 0); + TEST(32, M(CPU::GetStatePtr()), Imm32(0xFFFFFFFF)); + dbg_exit = J_CC(CC_NZ, true); + SetJumpTarget(notStepping); + } - SetJumpTarget(skipToRealDispatch); + SetJumpTarget(skipToRealDispatch); - dispatcherNoCheck = GetCodePtr(); + dispatcherNoCheck = GetCodePtr(); - // Switch to the correct memory base, in case MSR.DR has changed. - // TODO: Is there a more efficient place to put this? We don't - // need to do this for indirect jumps, just exceptions etc. - TEST(32, PPCSTATE(msr), Imm32(1 << (31 - 27))); - FixupBranch physmem = J_CC(CC_NZ); - MOV(64, R(RMEM), Imm64((u64)Memory::physical_base)); - FixupBranch membaseend = J(); - SetJumpTarget(physmem); - MOV(64, R(RMEM), Imm64((u64)Memory::logical_base)); - SetJumpTarget(membaseend); + // Switch to the correct memory base, in case MSR.DR has changed. + // TODO: Is there a more efficient place to put this? We don't + // need to do this for indirect jumps, just exceptions etc. + TEST(32, PPCSTATE(msr), Imm32(1 << (31 - 27))); + FixupBranch physmem = J_CC(CC_NZ); + MOV(64, R(RMEM), Imm64((u64)Memory::physical_base)); + FixupBranch membaseend = J(); + SetJumpTarget(physmem); + MOV(64, R(RMEM), Imm64((u64)Memory::logical_base)); + SetJumpTarget(membaseend); - MOV(32, R(RSCRATCH), PPCSTATE(pc)); + MOV(32, R(RSCRATCH), PPCSTATE(pc)); - // TODO: We need to handle code which executes the same PC with - // different values of MSR.IR. It probably makes sense to handle - // MSR.DR here too, to allow IsOptimizableRAMAddress-based - // optimizations safe, because IR and DR are usually set/cleared together. - // TODO: Branching based on the 20 most significant bits of instruction - // addresses without translating them is wrong. - u64 icache = (u64)jit->GetBlockCache()->iCache.data(); - u64 icacheVmem = (u64)jit->GetBlockCache()->iCacheVMEM.data(); - u64 icacheEx = (u64)jit->GetBlockCache()->iCacheEx.data(); - u32 mask = 0; - FixupBranch no_mem; - FixupBranch exit_mem; - FixupBranch exit_vmem; - if (SConfig::GetInstance().bWii) - mask = JIT_ICACHE_EXRAM_BIT; - mask |= JIT_ICACHE_VMEM_BIT; - TEST(32, R(RSCRATCH), Imm32(mask)); - no_mem = J_CC(CC_NZ); - AND(32, R(RSCRATCH), Imm32(JIT_ICACHE_MASK)); + // TODO: We need to handle code which executes the same PC with + // different values of MSR.IR. It probably makes sense to handle + // MSR.DR here too, to allow IsOptimizableRAMAddress-based + // optimizations safe, because IR and DR are usually set/cleared together. + // TODO: Branching based on the 20 most significant bits of instruction + // addresses without translating them is wrong. + u64 icache = (u64)jit->GetBlockCache()->iCache.data(); + u64 icacheVmem = (u64)jit->GetBlockCache()->iCacheVMEM.data(); + u64 icacheEx = (u64)jit->GetBlockCache()->iCacheEx.data(); + u32 mask = 0; + FixupBranch no_mem; + FixupBranch exit_mem; + FixupBranch exit_vmem; + if (SConfig::GetInstance().bWii) + mask = JIT_ICACHE_EXRAM_BIT; + mask |= JIT_ICACHE_VMEM_BIT; + TEST(32, R(RSCRATCH), Imm32(mask)); + no_mem = J_CC(CC_NZ); + AND(32, R(RSCRATCH), Imm32(JIT_ICACHE_MASK)); - if (icache <= INT_MAX) - { - MOV(32, R(RSCRATCH), MDisp(RSCRATCH, (s32)icache)); - } - else - { - MOV(64, R(RSCRATCH2), Imm64(icache)); - MOV(32, R(RSCRATCH), MRegSum(RSCRATCH2, RSCRATCH)); - } + if (icache <= INT_MAX) + { + MOV(32, R(RSCRATCH), MDisp(RSCRATCH, (s32)icache)); + } + else + { + MOV(64, R(RSCRATCH2), Imm64(icache)); + MOV(32, R(RSCRATCH), MRegSum(RSCRATCH2, RSCRATCH)); + } - exit_mem = J(); - SetJumpTarget(no_mem); - TEST(32, R(RSCRATCH), Imm32(JIT_ICACHE_VMEM_BIT)); - FixupBranch no_vmem = J_CC(CC_Z); - AND(32, R(RSCRATCH), Imm32(JIT_ICACHE_MASK)); - if (icacheVmem <= INT_MAX) - { - MOV(32, R(RSCRATCH), MDisp(RSCRATCH, (s32)icacheVmem)); - } - else - { - MOV(64, R(RSCRATCH2), Imm64(icacheVmem)); - MOV(32, R(RSCRATCH), MRegSum(RSCRATCH2, RSCRATCH)); - } + exit_mem = J(); + SetJumpTarget(no_mem); + TEST(32, R(RSCRATCH), Imm32(JIT_ICACHE_VMEM_BIT)); + FixupBranch no_vmem = J_CC(CC_Z); + AND(32, R(RSCRATCH), Imm32(JIT_ICACHE_MASK)); + if (icacheVmem <= INT_MAX) + { + MOV(32, R(RSCRATCH), MDisp(RSCRATCH, (s32)icacheVmem)); + } + else + { + MOV(64, R(RSCRATCH2), Imm64(icacheVmem)); + MOV(32, R(RSCRATCH), MRegSum(RSCRATCH2, RSCRATCH)); + } - if (SConfig::GetInstance().bWii) exit_vmem = J(); - SetJumpTarget(no_vmem); - if (SConfig::GetInstance().bWii) - { - TEST(32, R(RSCRATCH), Imm32(JIT_ICACHE_EXRAM_BIT)); - FixupBranch no_exram = J_CC(CC_Z); - AND(32, R(RSCRATCH), Imm32(JIT_ICACHEEX_MASK)); + if (SConfig::GetInstance().bWii) + exit_vmem = J(); + SetJumpTarget(no_vmem); + if (SConfig::GetInstance().bWii) + { + TEST(32, R(RSCRATCH), Imm32(JIT_ICACHE_EXRAM_BIT)); + FixupBranch no_exram = J_CC(CC_Z); + AND(32, R(RSCRATCH), Imm32(JIT_ICACHEEX_MASK)); - if (icacheEx <= INT_MAX) - { - MOV(32, R(RSCRATCH), MDisp(RSCRATCH, (s32)icacheEx)); - } - else - { - MOV(64, R(RSCRATCH2), Imm64(icacheEx)); - MOV(32, R(RSCRATCH), MRegSum(RSCRATCH2, RSCRATCH)); - } + if (icacheEx <= INT_MAX) + { + MOV(32, R(RSCRATCH), MDisp(RSCRATCH, (s32)icacheEx)); + } + else + { + MOV(64, R(RSCRATCH2), Imm64(icacheEx)); + MOV(32, R(RSCRATCH), MRegSum(RSCRATCH2, RSCRATCH)); + } - SetJumpTarget(no_exram); - } - SetJumpTarget(exit_mem); - if (SConfig::GetInstance().bWii) - SetJumpTarget(exit_vmem); + SetJumpTarget(no_exram); + } + SetJumpTarget(exit_mem); + if (SConfig::GetInstance().bWii) + SetJumpTarget(exit_vmem); - TEST(32, R(RSCRATCH), R(RSCRATCH)); - FixupBranch notfound = J_CC(CC_L); - //grab from list and jump to it - u64 codePointers = (u64)jit->GetBlockCache()->GetCodePointers(); - if (codePointers <= INT_MAX) - { - JMPptr(MScaled(RSCRATCH, SCALE_8, (s32)codePointers)); - } - else - { - MOV(64, R(RSCRATCH2), Imm64(codePointers)); - JMPptr(MComplex(RSCRATCH2, RSCRATCH, SCALE_8, 0)); - } - SetJumpTarget(notfound); + TEST(32, R(RSCRATCH), R(RSCRATCH)); + FixupBranch notfound = J_CC(CC_L); + // grab from list and jump to it + u64 codePointers = (u64)jit->GetBlockCache()->GetCodePointers(); + if (codePointers <= INT_MAX) + { + JMPptr(MScaled(RSCRATCH, SCALE_8, (s32)codePointers)); + } + else + { + MOV(64, R(RSCRATCH2), Imm64(codePointers)); + JMPptr(MComplex(RSCRATCH2, RSCRATCH, SCALE_8, 0)); + } + SetJumpTarget(notfound); - // We reset the stack because Jit might clear the code cache. - // Also if we are in the middle of disabling BLR optimization on windows - // we need to reset the stack before _resetstkoflw() is called in Jit - // otherwise we will generate a second stack overflow exception during DoJit() - ResetStack(); + // We reset the stack because Jit might clear the code cache. + // Also if we are in the middle of disabling BLR optimization on windows + // we need to reset the stack before _resetstkoflw() is called in Jit + // otherwise we will generate a second stack overflow exception during DoJit() + ResetStack(); - //Ok, no block, let's jit - ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunctionA(32, (void *)&Jit, PPCSTATE(pc)); - ABI_PopRegistersAndAdjustStack({}, 0); + // Ok, no block, let's jit + ABI_PushRegistersAndAdjustStack({}, 0); + ABI_CallFunctionA(32, (void*)&Jit, PPCSTATE(pc)); + ABI_PopRegistersAndAdjustStack({}, 0); - JMP(dispatcherNoCheck, true); // no point in special casing this + JMP(dispatcherNoCheck, true); // no point in special casing this - SetJumpTarget(bail); - doTiming = GetCodePtr(); + SetJumpTarget(bail); + doTiming = GetCodePtr(); - // make sure npc contains the next pc (needed for exception checking in CoreTiming::Advance) - MOV(32, R(RSCRATCH), PPCSTATE(pc)); - MOV(32, PPCSTATE(npc), R(RSCRATCH)); + // make sure npc contains the next pc (needed for exception checking in CoreTiming::Advance) + MOV(32, R(RSCRATCH), PPCSTATE(pc)); + MOV(32, PPCSTATE(npc), R(RSCRATCH)); - // Check the state pointer to see if we are exiting - // Gets checked on at the end of every slice - TEST(32, M(CPU::GetStatePtr()), Imm32(0xFFFFFFFF)); - J_CC(CC_Z, outerLoop); + // Check the state pointer to see if we are exiting + // Gets checked on at the end of every slice + TEST(32, M(CPU::GetStatePtr()), Imm32(0xFFFFFFFF)); + J_CC(CC_Z, outerLoop); - //Landing pad for drec space - if (SConfig::GetInstance().bEnableDebugging) - SetJumpTarget(dbg_exit); - ResetStack(); - if (m_stack_top) - { - ADD(64, R(RSP), Imm8(0x18)); - POP(RSP); - } + // Landing pad for drec space + if (SConfig::GetInstance().bEnableDebugging) + SetJumpTarget(dbg_exit); + ResetStack(); + if (m_stack_top) + { + ADD(64, R(RSP), Imm8(0x18)); + POP(RSP); + } - ABI_PopRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8, 16); - RET(); + ABI_PopRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8, 16); + RET(); - JitRegister::Register(enterCode, GetCodePtr(), "JIT_Loop"); + JitRegister::Register(enterCode, GetCodePtr(), "JIT_Loop"); - GenerateCommon(); + GenerateCommon(); } void Jit64AsmRoutineManager::ResetStack() { - if (m_stack_top) - MOV(64, R(RSP), Imm64((u64)m_stack_top - 0x20)); - else - MOV(64, R(RSP), M(&s_saved_rsp)); + if (m_stack_top) + MOV(64, R(RSP), Imm64((u64)m_stack_top - 0x20)); + else + MOV(64, R(RSP), M(&s_saved_rsp)); } - void Jit64AsmRoutineManager::GenerateCommon() { - fifoDirectWrite8 = AlignCode4(); - GenFifoWrite(8); - fifoDirectWrite16 = AlignCode4(); - GenFifoWrite(16); - fifoDirectWrite32 = AlignCode4(); - GenFifoWrite(32); - fifoDirectWrite64 = AlignCode4(); - GenFifoWrite(64); - frsqrte = AlignCode4(); - GenFrsqrte(); - fres = AlignCode4(); - GenFres(); - mfcr = AlignCode4(); - GenMfcr(); + fifoDirectWrite8 = AlignCode4(); + GenFifoWrite(8); + fifoDirectWrite16 = AlignCode4(); + GenFifoWrite(16); + fifoDirectWrite32 = AlignCode4(); + GenFifoWrite(32); + fifoDirectWrite64 = AlignCode4(); + GenFifoWrite(64); + frsqrte = AlignCode4(); + GenFrsqrte(); + fres = AlignCode4(); + GenFres(); + mfcr = AlignCode4(); + GenMfcr(); - GenQuantizedLoads(); - GenQuantizedStores(); - GenQuantizedSingleStores(); + GenQuantizedLoads(); + GenQuantizedStores(); + GenQuantizedSingleStores(); - //CMPSD(R(XMM0), M(&zero), - // TODO + // CMPSD(R(XMM0), M(&zero), + // TODO - // Fast write routines - special case the most common hardware write - // TODO: use this. - // Even in x86, the param values will be in the right registers. - /* - const u8 *fastMemWrite8 = AlignCode16(); - CMP(32, R(ABI_PARAM2), Imm32(0xCC008000)); - FixupBranch skip_fast_write = J_CC(CC_NE, false); - MOV(32, RSCRATCH, M(&m_gatherPipeCount)); - MOV(8, MDisp(RSCRATCH, (u32)&m_gatherPipe), ABI_PARAM1); - ADD(32, 1, M(&m_gatherPipeCount)); - RET(); - SetJumpTarget(skip_fast_write); - CALL((void *)&PowerPC::Write_U8);*/ + // Fast write routines - special case the most common hardware write + // TODO: use this. + // Even in x86, the param values will be in the right registers. + /* + const u8 *fastMemWrite8 = AlignCode16(); + CMP(32, R(ABI_PARAM2), Imm32(0xCC008000)); + FixupBranch skip_fast_write = J_CC(CC_NE, false); + MOV(32, RSCRATCH, M(&m_gatherPipeCount)); + MOV(8, MDisp(RSCRATCH, (u32)&m_gatherPipe), ABI_PARAM1); + ADD(32, 1, M(&m_gatherPipeCount)); + RET(); + SetJumpTarget(skip_fast_write); + CALL((void *)&PowerPC::Write_U8);*/ } diff --git a/Source/Core/Core/PowerPC/Jit64/JitAsm.h b/Source/Core/Core/PowerPC/Jit64/JitAsm.h index 6e3332d275..006d38741d 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitAsm.h +++ b/Source/Core/Core/PowerPC/Jit64/JitAsm.h @@ -24,24 +24,21 @@ class Jit64AsmRoutineManager : public CommonAsmRoutines { private: - void Generate(); - void ResetStack(); - void GenerateCommon(); - u8* m_stack_top; + void Generate(); + void ResetStack(); + void GenerateCommon(); + u8* m_stack_top; public: - void Init(u8* stack_top) - { - m_stack_top = stack_top; - // NOTE: When making large additions to the AsmCommon code, you might - // want to ensure this number is big enough. - AllocCodeSpace(16384); - Generate(); - WriteProtect(); - } + void Init(u8* stack_top) + { + m_stack_top = stack_top; + // NOTE: When making large additions to the AsmCommon code, you might + // want to ensure this number is big enough. + AllocCodeSpace(16384); + Generate(); + WriteProtect(); + } - void Shutdown() - { - FreeCodeSpace(); - } + void Shutdown() { FreeCodeSpace(); } }; diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp index 19eb4238a8..bc5384d481 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp @@ -12,10 +12,10 @@ #include "Common/CommonTypes.h" #include "Common/MsgHandler.h" #include "Common/x64Emitter.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/Jit64/Jit.h" #include "Core/PowerPC/Jit64/JitRegCache.h" #include "Core/PowerPC/JitCommon/Jit_Util.h" +#include "Core/PowerPC/PowerPC.h" using namespace Gen; using namespace PowerPC; @@ -26,387 +26,388 @@ RegCache::RegCache() : emit(nullptr) void RegCache::Start() { - for (auto& xreg : xregs) - { - xreg.free = true; - xreg.dirty = false; - xreg.locked = false; - xreg.ppcReg = INVALID_REG; - } - for (size_t i = 0; i < regs.size(); i++) - { - regs[i].location = GetDefaultLocation(i); - regs[i].away = false; - regs[i].locked = false; - } + for (auto& xreg : xregs) + { + xreg.free = true; + xreg.dirty = false; + xreg.locked = false; + xreg.ppcReg = INVALID_REG; + } + for (size_t i = 0; i < regs.size(); i++) + { + regs[i].location = GetDefaultLocation(i); + regs[i].away = false; + regs[i].locked = false; + } - // todo: sort to find the most popular regs - /* - int maxPreload = 2; - for (int i = 0; i < 32; i++) - { - if (stats.numReads[i] > 2 || stats.numWrites[i] >= 2) - { - LoadToX64(i, true, false); //stats.firstRead[i] <= stats.firstWrite[i], false); - maxPreload--; - if (!maxPreload) - break; - } - }*/ - //Find top regs - preload them (load bursts ain't bad) - //But only preload IF written OR reads >= 3 + // todo: sort to find the most popular regs + /* + int maxPreload = 2; + for (int i = 0; i < 32; i++) + { + if (stats.numReads[i] > 2 || stats.numWrites[i] >= 2) + { + LoadToX64(i, true, false); //stats.firstRead[i] <= stats.firstWrite[i], false); + maxPreload--; + if (!maxPreload) + break; + } + }*/ + // Find top regs - preload them (load bursts ain't bad) + // But only preload IF written OR reads >= 3 } void RegCache::UnlockAll() { - for (auto& reg : regs) - reg.locked = false; + for (auto& reg : regs) + reg.locked = false; } void RegCache::UnlockAllX() { - for (auto& xreg : xregs) - xreg.locked = false; + for (auto& xreg : xregs) + xreg.locked = false; } BitSet32 GPRRegCache::GetRegUtilization() { - return jit->js.op->gprInReg; + return jit->js.op->gprInReg; } BitSet32 FPURegCache::GetRegUtilization() { - return jit->js.op->gprInReg; + return jit->js.op->gprInReg; } BitSet32 GPRRegCache::CountRegsIn(size_t preg, u32 lookahead) { - BitSet32 regsUsed; - for (u32 i = 1; i < lookahead; i++) - { - BitSet32 regsIn = jit->js.op[i].regsIn; - regsUsed |= regsIn; - if (regsIn[preg]) - return regsUsed; - } - return regsUsed; + BitSet32 regsUsed; + for (u32 i = 1; i < lookahead; i++) + { + BitSet32 regsIn = jit->js.op[i].regsIn; + regsUsed |= regsIn; + if (regsIn[preg]) + return regsUsed; + } + return regsUsed; } BitSet32 FPURegCache::CountRegsIn(size_t preg, u32 lookahead) { - BitSet32 regsUsed; - for (u32 i = 1; i < lookahead; i++) - { - BitSet32 regsIn = jit->js.op[i].fregsIn; - regsUsed |= regsIn; - if (regsIn[preg]) - return regsUsed; - } - return regsUsed; + BitSet32 regsUsed; + for (u32 i = 1; i < lookahead; i++) + { + BitSet32 regsIn = jit->js.op[i].fregsIn; + regsUsed |= regsIn; + if (regsIn[preg]) + return regsUsed; + } + return regsUsed; } // Estimate roughly how bad it would be to de-allocate this register. Higher score // means more bad. float RegCache::ScoreRegister(X64Reg xr) { - size_t preg = xregs[xr].ppcReg; - float score = 0; + size_t preg = xregs[xr].ppcReg; + float score = 0; - // If it's not dirty, we don't need a store to write it back to the register file, so - // bias a bit against dirty registers. Testing shows that a bias of 2 seems roughly - // right: 3 causes too many extra clobbers, while 1 saves very few clobbers relative - // to the number of extra stores it causes. - if (xregs[xr].dirty) - score += 2; + // If it's not dirty, we don't need a store to write it back to the register file, so + // bias a bit against dirty registers. Testing shows that a bias of 2 seems roughly + // right: 3 causes too many extra clobbers, while 1 saves very few clobbers relative + // to the number of extra stores it causes. + if (xregs[xr].dirty) + score += 2; - // If the register isn't actually needed in a physical register for a later instruction, - // writing it back to the register file isn't quite as bad. - if (GetRegUtilization()[preg]) - { - // Don't look too far ahead; we don't want to have quadratic compilation times for - // enormous block sizes! - // This actually improves register allocation a tiny bit; I'm not sure why. - u32 lookahead = std::min(jit->js.instructionsLeft, 64); - // Count how many other registers are going to be used before we need this one again. - u32 regs_in_count = CountRegsIn(preg, lookahead).Count(); - // Totally ad-hoc heuristic to bias based on how many other registers we'll need - // before this one gets used again. - score += 1 + 2 * (5 - log2f(1 + (float)regs_in_count)); - } + // If the register isn't actually needed in a physical register for a later instruction, + // writing it back to the register file isn't quite as bad. + if (GetRegUtilization()[preg]) + { + // Don't look too far ahead; we don't want to have quadratic compilation times for + // enormous block sizes! + // This actually improves register allocation a tiny bit; I'm not sure why. + u32 lookahead = std::min(jit->js.instructionsLeft, 64); + // Count how many other registers are going to be used before we need this one again. + u32 regs_in_count = CountRegsIn(preg, lookahead).Count(); + // Totally ad-hoc heuristic to bias based on how many other registers we'll need + // before this one gets used again. + score += 1 + 2 * (5 - log2f(1 + (float)regs_in_count)); + } - return score; + return score; } X64Reg RegCache::GetFreeXReg() { - size_t aCount; - const X64Reg* aOrder = GetAllocationOrder(&aCount); - for (size_t i = 0; i < aCount; i++) - { - X64Reg xr = aOrder[i]; - if (!xregs[xr].locked && xregs[xr].free) - { - return xr; - } - } + size_t aCount; + const X64Reg* aOrder = GetAllocationOrder(&aCount); + for (size_t i = 0; i < aCount; i++) + { + X64Reg xr = aOrder[i]; + if (!xregs[xr].locked && xregs[xr].free) + { + return xr; + } + } - // Okay, not found; run the register allocator heuristic and figure out which register we should - // clobber. - float min_score = std::numeric_limits::max(); - X64Reg best_xreg = INVALID_REG; - size_t best_preg = 0; - for (size_t i = 0; i < aCount; i++) - { - X64Reg xreg = (X64Reg)aOrder[i]; - size_t preg = xregs[xreg].ppcReg; - if (xregs[xreg].locked || regs[preg].locked) - continue; - float score = ScoreRegister(xreg); - if (score < min_score) - { - min_score = score; - best_xreg = xreg; - best_preg = preg; - } - } + // Okay, not found; run the register allocator heuristic and figure out which register we should + // clobber. + float min_score = std::numeric_limits::max(); + X64Reg best_xreg = INVALID_REG; + size_t best_preg = 0; + for (size_t i = 0; i < aCount; i++) + { + X64Reg xreg = (X64Reg)aOrder[i]; + size_t preg = xregs[xreg].ppcReg; + if (xregs[xreg].locked || regs[preg].locked) + continue; + float score = ScoreRegister(xreg); + if (score < min_score) + { + min_score = score; + best_xreg = xreg; + best_preg = preg; + } + } - if (best_xreg != INVALID_REG) - { - StoreFromRegister(best_preg); - return best_xreg; - } + if (best_xreg != INVALID_REG) + { + StoreFromRegister(best_preg); + return best_xreg; + } - //Still no dice? Die! - _assert_msg_(DYNA_REC, 0, "Regcache ran out of regs"); - return INVALID_REG; + // Still no dice? Die! + _assert_msg_(DYNA_REC, 0, "Regcache ran out of regs"); + return INVALID_REG; } void RegCache::FlushR(X64Reg reg) { - if (reg >= xregs.size()) - PanicAlert("Flushing non existent reg"); - if (!xregs[reg].free) - { - StoreFromRegister(xregs[reg].ppcReg); - } + if (reg >= xregs.size()) + PanicAlert("Flushing non existent reg"); + if (!xregs[reg].free) + { + StoreFromRegister(xregs[reg].ppcReg); + } } int RegCache::SanityCheck() const { - for (size_t i = 0; i < regs.size(); i++) - { - if (regs[i].away) - { - if (regs[i].location.IsSimpleReg()) - { - Gen::X64Reg simple = regs[i].location.GetSimpleReg(); - if (xregs[simple].locked) - return 1; - if (xregs[simple].ppcReg != i) - return 2; - } - else if (regs[i].location.IsImm()) - { - return 3; - } - } - } - return 0; + for (size_t i = 0; i < regs.size(); i++) + { + if (regs[i].away) + { + if (regs[i].location.IsSimpleReg()) + { + Gen::X64Reg simple = regs[i].location.GetSimpleReg(); + if (xregs[simple].locked) + return 1; + if (xregs[simple].ppcReg != i) + return 2; + } + else if (regs[i].location.IsImm()) + { + return 3; + } + } + } + return 0; } void RegCache::DiscardRegContentsIfCached(size_t preg) { - if (IsBound(preg)) - { - X64Reg xr = regs[preg].location.GetSimpleReg(); - xregs[xr].free = true; - xregs[xr].dirty = false; - xregs[xr].ppcReg = INVALID_REG; - regs[preg].away = false; - regs[preg].location = GetDefaultLocation(preg); - } + if (IsBound(preg)) + { + X64Reg xr = regs[preg].location.GetSimpleReg(); + xregs[xr].free = true; + xregs[xr].dirty = false; + xregs[xr].ppcReg = INVALID_REG; + regs[preg].away = false; + regs[preg].location = GetDefaultLocation(preg); + } } - void GPRRegCache::SetImmediate32(size_t preg, u32 immValue) { - DiscardRegContentsIfCached(preg); - regs[preg].away = true; - regs[preg].location = Imm32(immValue); + DiscardRegContentsIfCached(preg); + regs[preg].away = true; + regs[preg].location = Imm32(immValue); } const X64Reg* GPRRegCache::GetAllocationOrder(size_t* count) { - static const X64Reg allocationOrder[] = - { - // R12, when used as base register, for example in a LEA, can generate bad code! Need to look into this. + static const X64Reg allocationOrder[] = { +// R12, when used as base register, for example in a LEA, can generate bad code! Need to look into +// this. #ifdef _WIN32 - RSI, RDI, R13, R14, R15, R8, R9, R10, R11, R12, RCX + RSI, RDI, R13, R14, R15, R8, + R9, R10, R11, R12, RCX #else - R12, R13, R14, R15, RSI, RDI, R8, R9, R10, R11, RCX + R12, R13, R14, R15, RSI, RDI, + R8, R9, R10, R11, RCX #endif - }; - *count = sizeof(allocationOrder) / sizeof(X64Reg); - return allocationOrder; + }; + *count = sizeof(allocationOrder) / sizeof(X64Reg); + return allocationOrder; } const X64Reg* FPURegCache::GetAllocationOrder(size_t* count) { - static const X64Reg allocationOrder[] = - { - XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5 - }; - *count = sizeof(allocationOrder) / sizeof(X64Reg); - return allocationOrder; + static const X64Reg allocationOrder[] = {XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, + XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5}; + *count = sizeof(allocationOrder) / sizeof(X64Reg); + return allocationOrder; } OpArg GPRRegCache::GetDefaultLocation(size_t reg) const { - return PPCSTATE(gpr[reg]); + return PPCSTATE(gpr[reg]); } OpArg FPURegCache::GetDefaultLocation(size_t reg) const { - return PPCSTATE(ps[reg][0]); + return PPCSTATE(ps[reg][0]); } void RegCache::KillImmediate(size_t preg, bool doLoad, bool makeDirty) { - if (regs[preg].away) - { - if (regs[preg].location.IsImm()) - BindToRegister(preg, doLoad, makeDirty); - else if (regs[preg].location.IsSimpleReg()) - xregs[RX(preg)].dirty |= makeDirty; - } + if (regs[preg].away) + { + if (regs[preg].location.IsImm()) + BindToRegister(preg, doLoad, makeDirty); + else if (regs[preg].location.IsSimpleReg()) + xregs[RX(preg)].dirty |= makeDirty; + } } void RegCache::BindToRegister(size_t i, bool doLoad, bool makeDirty) { - if (!regs[i].away && regs[i].location.IsImm()) - PanicAlert("Bad immediate"); + if (!regs[i].away && regs[i].location.IsImm()) + PanicAlert("Bad immediate"); - if (!regs[i].away || (regs[i].away && regs[i].location.IsImm())) - { - X64Reg xr = GetFreeXReg(); - if (xregs[xr].dirty) PanicAlert("Xreg already dirty"); - if (xregs[xr].locked) PanicAlert("GetFreeXReg returned locked register"); - xregs[xr].free = false; - xregs[xr].ppcReg = i; - xregs[xr].dirty = makeDirty || regs[i].location.IsImm(); - if (doLoad) - LoadRegister(i, xr); - for (size_t j = 0; j < regs.size(); j++) - { - if (i != j && regs[j].location.IsSimpleReg(xr)) - { - Crash(); - } - } - regs[i].away = true; - regs[i].location = ::Gen::R(xr); - } - else - { - // reg location must be simplereg; memory locations - // and immediates are taken care of above. - xregs[RX(i)].dirty |= makeDirty; - } + if (!regs[i].away || (regs[i].away && regs[i].location.IsImm())) + { + X64Reg xr = GetFreeXReg(); + if (xregs[xr].dirty) + PanicAlert("Xreg already dirty"); + if (xregs[xr].locked) + PanicAlert("GetFreeXReg returned locked register"); + xregs[xr].free = false; + xregs[xr].ppcReg = i; + xregs[xr].dirty = makeDirty || regs[i].location.IsImm(); + if (doLoad) + LoadRegister(i, xr); + for (size_t j = 0; j < regs.size(); j++) + { + if (i != j && regs[j].location.IsSimpleReg(xr)) + { + Crash(); + } + } + regs[i].away = true; + regs[i].location = ::Gen::R(xr); + } + else + { + // reg location must be simplereg; memory locations + // and immediates are taken care of above. + xregs[RX(i)].dirty |= makeDirty; + } - if (xregs[RX(i)].locked) - { - PanicAlert("Seriously WTF, this reg should have been flushed"); - } + if (xregs[RX(i)].locked) + { + PanicAlert("Seriously WTF, this reg should have been flushed"); + } } void RegCache::StoreFromRegister(size_t i, FlushMode mode) { - if (regs[i].away) - { - bool doStore; - if (regs[i].location.IsSimpleReg()) - { - X64Reg xr = RX(i); - doStore = xregs[xr].dirty; - if (mode == FLUSH_ALL) - { - xregs[xr].free = true; - xregs[xr].ppcReg = INVALID_REG; - xregs[xr].dirty = false; - } - } - else - { - //must be immediate - do nothing - doStore = true; - } - OpArg newLoc = GetDefaultLocation(i); - if (doStore) - StoreRegister(i, newLoc); - if (mode == FLUSH_ALL) - { - regs[i].location = newLoc; - regs[i].away = false; - } - } + if (regs[i].away) + { + bool doStore; + if (regs[i].location.IsSimpleReg()) + { + X64Reg xr = RX(i); + doStore = xregs[xr].dirty; + if (mode == FLUSH_ALL) + { + xregs[xr].free = true; + xregs[xr].ppcReg = INVALID_REG; + xregs[xr].dirty = false; + } + } + else + { + // must be immediate - do nothing + doStore = true; + } + OpArg newLoc = GetDefaultLocation(i); + if (doStore) + StoreRegister(i, newLoc); + if (mode == FLUSH_ALL) + { + regs[i].location = newLoc; + regs[i].away = false; + } + } } void GPRRegCache::LoadRegister(size_t preg, X64Reg newLoc) { - emit->MOV(32, ::Gen::R(newLoc), regs[preg].location); + emit->MOV(32, ::Gen::R(newLoc), regs[preg].location); } void GPRRegCache::StoreRegister(size_t preg, const OpArg& newLoc) { - emit->MOV(32, newLoc, regs[preg].location); + emit->MOV(32, newLoc, regs[preg].location); } void FPURegCache::LoadRegister(size_t preg, X64Reg newLoc) { - emit->MOVAPD(newLoc, regs[preg].location); + emit->MOVAPD(newLoc, regs[preg].location); } void FPURegCache::StoreRegister(size_t preg, const OpArg& newLoc) { - emit->MOVAPD(newLoc, regs[preg].location.GetSimpleReg()); + emit->MOVAPD(newLoc, regs[preg].location.GetSimpleReg()); } void RegCache::Flush(FlushMode mode, BitSet32 regsToFlush) { - for (size_t i = 0; i < xregs.size(); i++) - { - if (xregs[i].locked) - PanicAlert("Someone forgot to unlock X64 reg %zu", i); - } + for (size_t i = 0; i < xregs.size(); i++) + { + if (xregs[i].locked) + PanicAlert("Someone forgot to unlock X64 reg %zu", i); + } - for (unsigned int i : regsToFlush) - { - if (regs[i].locked) - { - PanicAlert("Someone forgot to unlock PPC reg %u (X64 reg %i).", i, RX(i)); - } + for (unsigned int i : regsToFlush) + { + if (regs[i].locked) + { + PanicAlert("Someone forgot to unlock PPC reg %u (X64 reg %i).", i, RX(i)); + } - if (regs[i].away) - { - if (regs[i].location.IsSimpleReg() || regs[i].location.IsImm()) - { - StoreFromRegister(i, mode); - } - else - { - _assert_msg_(DYNA_REC,0,"Jit64 - Flush unhandled case, reg %u PC: %08x", i, PC); - } - } - } + if (regs[i].away) + { + if (regs[i].location.IsSimpleReg() || regs[i].location.IsImm()) + { + StoreFromRegister(i, mode); + } + else + { + _assert_msg_(DYNA_REC, 0, "Jit64 - Flush unhandled case, reg %u PC: %08x", i, PC); + } + } + } } int RegCache::NumFreeRegisters() { - int count = 0; - size_t aCount; - const X64Reg* aOrder = GetAllocationOrder(&aCount); - for (size_t i = 0; i < aCount; i++) - if (!xregs[aOrder[i]].locked && xregs[aOrder[i]].free) - count++; - return count; + int count = 0; + size_t aCount; + const X64Reg* aOrder = GetAllocationOrder(&aCount); + for (size_t i = 0; i < aCount; i++) + if (!xregs[aOrder[i]].locked && xregs[aOrder[i]].free) + count++; + return count; } diff --git a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h index 4515c7c420..14ed139a42 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/JitRegCache.h @@ -12,23 +12,23 @@ enum FlushMode { - FLUSH_ALL, - FLUSH_MAINTAIN_STATE, + FLUSH_ALL, + FLUSH_MAINTAIN_STATE, }; struct PPCCachedReg { - Gen::OpArg location; - bool away; // value not in source register - bool locked; + Gen::OpArg location; + bool away; // value not in source register + bool locked; }; struct X64CachedReg { - size_t ppcReg; - bool dirty; - bool free; - bool locked; + size_t ppcReg; + bool dirty; + bool free; + bool locked; }; typedef int XReg; @@ -39,157 +39,140 @@ typedef int PReg; class RegCache { protected: - std::array regs; - std::array xregs; + std::array regs; + std::array xregs; - virtual const Gen::X64Reg* GetAllocationOrder(size_t* count) = 0; + virtual const Gen::X64Reg* GetAllocationOrder(size_t* count) = 0; - virtual BitSet32 GetRegUtilization() = 0; - virtual BitSet32 CountRegsIn(size_t preg, u32 lookahead) = 0; + virtual BitSet32 GetRegUtilization() = 0; + virtual BitSet32 CountRegsIn(size_t preg, u32 lookahead) = 0; - Gen::XEmitter *emit; + Gen::XEmitter* emit; - float ScoreRegister(Gen::X64Reg xreg); + float ScoreRegister(Gen::X64Reg xreg); public: - RegCache(); - virtual ~RegCache() {} + RegCache(); + virtual ~RegCache() {} + void Start(); - void Start(); + void DiscardRegContentsIfCached(size_t preg); + void SetEmitter(Gen::XEmitter* emitter) { emit = emitter; } + void FlushR(Gen::X64Reg reg); + void FlushR(Gen::X64Reg reg, Gen::X64Reg reg2) + { + FlushR(reg); + FlushR(reg2); + } - void DiscardRegContentsIfCached(size_t preg); - void SetEmitter(Gen::XEmitter *emitter) - { - emit = emitter; - } + void FlushLockX(Gen::X64Reg reg) + { + FlushR(reg); + LockX(reg); + } + void FlushLockX(Gen::X64Reg reg1, Gen::X64Reg reg2) + { + FlushR(reg1); + FlushR(reg2); + LockX(reg1); + LockX(reg2); + } - void FlushR(Gen::X64Reg reg); - void FlushR(Gen::X64Reg reg, Gen::X64Reg reg2) - { - FlushR(reg); - FlushR(reg2); - } + void Flush(FlushMode mode = FLUSH_ALL, BitSet32 regsToFlush = BitSet32::AllTrue(32)); + void Flush(PPCAnalyst::CodeOp* op) { Flush(); } + int SanityCheck() const; + void KillImmediate(size_t preg, bool doLoad, bool makeDirty); - void FlushLockX(Gen::X64Reg reg) - { - FlushR(reg); - LockX(reg); - } - void FlushLockX(Gen::X64Reg reg1, Gen::X64Reg reg2) - { - FlushR(reg1); FlushR(reg2); - LockX(reg1); LockX(reg2); - } + // TODO - instead of doload, use "read", "write" + // read only will not set dirty flag + void BindToRegister(size_t preg, bool doLoad = true, bool makeDirty = true); + void StoreFromRegister(size_t preg, FlushMode mode = FLUSH_ALL); + virtual void StoreRegister(size_t preg, const Gen::OpArg& newLoc) = 0; + virtual void LoadRegister(size_t preg, Gen::X64Reg newLoc) = 0; - void Flush(FlushMode mode = FLUSH_ALL, BitSet32 regsToFlush = BitSet32::AllTrue(32)); - void Flush(PPCAnalyst::CodeOp *op) { Flush(); } - int SanityCheck() const; - void KillImmediate(size_t preg, bool doLoad, bool makeDirty); + const Gen::OpArg& R(size_t preg) const { return regs[preg].location; } + Gen::X64Reg RX(size_t preg) const + { + if (IsBound(preg)) + return regs[preg].location.GetSimpleReg(); - //TODO - instead of doload, use "read", "write" - //read only will not set dirty flag - void BindToRegister(size_t preg, bool doLoad = true, bool makeDirty = true); - void StoreFromRegister(size_t preg, FlushMode mode = FLUSH_ALL); - virtual void StoreRegister(size_t preg, const Gen::OpArg& newLoc) = 0; - virtual void LoadRegister(size_t preg, Gen::X64Reg newLoc) = 0; + PanicAlert("Unbound register - %zu", preg); + return Gen::INVALID_REG; + } + virtual Gen::OpArg GetDefaultLocation(size_t reg) const = 0; - const Gen::OpArg &R(size_t preg) const - { - return regs[preg].location; - } + // Register locking. - Gen::X64Reg RX(size_t preg) const - { - if (IsBound(preg)) - return regs[preg].location.GetSimpleReg(); + // these are powerpc reg indices + template + void Lock(T p) + { + regs[p].locked = true; + } + template + void Lock(T first, Args... args) + { + Lock(first); + Lock(args...); + } - PanicAlert("Unbound register - %zu", preg); - return Gen::INVALID_REG; - } - virtual Gen::OpArg GetDefaultLocation(size_t reg) const = 0; + // these are x64 reg indices + template + void LockX(T x) + { + if (xregs[x].locked) + PanicAlert("RegCache: x %i already locked!", x); + xregs[x].locked = true; + } + template + void LockX(T first, Args... args) + { + LockX(first); + LockX(args...); + } - // Register locking. + template + void UnlockX(T x) + { + if (!xregs[x].locked) + PanicAlert("RegCache: x %i already unlocked!", x); + xregs[x].locked = false; + } + template + void UnlockX(T first, Args... args) + { + UnlockX(first); + UnlockX(args...); + } - // these are powerpc reg indices - template - void Lock(T p) - { - regs[p].locked = true; - } - template - void Lock(T first, Args... args) - { - Lock(first); - Lock(args...); - } + void UnlockAll(); + void UnlockAllX(); - // these are x64 reg indices - template - void LockX(T x) - { - if (xregs[x].locked) - PanicAlert("RegCache: x %i already locked!", x); - xregs[x].locked = true; - } - template - void LockX(T first, Args... args) - { - LockX(first); - LockX(args...); - } - - template - void UnlockX(T x) - { - if (!xregs[x].locked) - PanicAlert("RegCache: x %i already unlocked!", x); - xregs[x].locked = false; - } - template - void UnlockX(T first, Args... args) - { - UnlockX(first); - UnlockX(args...); - } - - void UnlockAll(); - void UnlockAllX(); - - bool IsFreeX(size_t xreg) const - { - return xregs[xreg].free && !xregs[xreg].locked; - } - - bool IsBound(size_t preg) const - { - return regs[preg].away && regs[preg].location.IsSimpleReg(); - } - - - Gen::X64Reg GetFreeXReg(); - int NumFreeRegisters(); + bool IsFreeX(size_t xreg) const { return xregs[xreg].free && !xregs[xreg].locked; } + bool IsBound(size_t preg) const { return regs[preg].away && regs[preg].location.IsSimpleReg(); } + Gen::X64Reg GetFreeXReg(); + int NumFreeRegisters(); }; class GPRRegCache final : public RegCache { public: - void StoreRegister(size_t preg, const Gen::OpArg& newLoc) override; - void LoadRegister(size_t preg, Gen::X64Reg newLoc) override; - Gen::OpArg GetDefaultLocation(size_t reg) const override; - const Gen::X64Reg* GetAllocationOrder(size_t* count) override; - void SetImmediate32(size_t preg, u32 immValue); - BitSet32 GetRegUtilization() override; - BitSet32 CountRegsIn(size_t preg, u32 lookahead) override; + void StoreRegister(size_t preg, const Gen::OpArg& newLoc) override; + void LoadRegister(size_t preg, Gen::X64Reg newLoc) override; + Gen::OpArg GetDefaultLocation(size_t reg) const override; + const Gen::X64Reg* GetAllocationOrder(size_t* count) override; + void SetImmediate32(size_t preg, u32 immValue); + BitSet32 GetRegUtilization() override; + BitSet32 CountRegsIn(size_t preg, u32 lookahead) override; }; - class FPURegCache final : public RegCache { public: - void StoreRegister(size_t preg, const Gen::OpArg& newLoc) override; - void LoadRegister(size_t preg, Gen::X64Reg newLoc) override; - const Gen::X64Reg* GetAllocationOrder(size_t* count) override; - Gen::OpArg GetDefaultLocation(size_t reg) const override; - BitSet32 GetRegUtilization() override; - BitSet32 CountRegsIn(size_t preg, u32 lookahead) override; + void StoreRegister(size_t preg, const Gen::OpArg& newLoc) override; + void LoadRegister(size_t preg, Gen::X64Reg newLoc) override; + const Gen::X64Reg* GetAllocationOrder(size_t* count) override; + Gen::OpArg GetDefaultLocation(size_t reg) const override; + BitSet32 GetRegUtilization() override; + BitSet32 CountRegsIn(size_t preg, u32 lookahead) override; }; diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Branch.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Branch.cpp index 5b16b5ee47..f83acd8991 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Branch.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Branch.cpp @@ -2,15 +2,15 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/Jit64/Jit.h" #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/x64Emitter.h" #include "Core/ConfigManager.h" #include "Core/PowerPC/Gekko.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCAnalyst.h" -#include "Core/PowerPC/Jit64/Jit.h" #include "Core/PowerPC/Jit64/JitRegCache.h" +#include "Core/PowerPC/PPCAnalyst.h" +#include "Core/PowerPC/PowerPC.h" // The branches are known good, or at least reasonably good. // No need for a disable-mechanism. @@ -27,76 +27,76 @@ using namespace Gen; void Jit64::sc(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITBranchOff); + INSTRUCTION_START + JITDISABLE(bJITBranchOff); - gpr.Flush(); - fpr.Flush(); - MOV(32, PPCSTATE(pc), Imm32(js.compilerPC + 4)); - LOCK(); - OR(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_SYSCALL)); - WriteExceptionExit(); + gpr.Flush(); + fpr.Flush(); + MOV(32, PPCSTATE(pc), Imm32(js.compilerPC + 4)); + LOCK(); + OR(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_SYSCALL)); + WriteExceptionExit(); } void Jit64::rfi(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITBranchOff); + INSTRUCTION_START + JITDISABLE(bJITBranchOff); - gpr.Flush(); - fpr.Flush(); - // See Interpreter rfi for details - const u32 mask = 0x87C0FFFF; - const u32 clearMSR13 = 0xFFFBFFFF; // Mask used to clear the bit MSR[13] - // MSR = ((MSR & ~mask) | (SRR1 & mask)) & clearMSR13; - AND(32, PPCSTATE(msr), Imm32((~mask) & clearMSR13)); - MOV(32, R(RSCRATCH), PPCSTATE_SRR1); - AND(32, R(RSCRATCH), Imm32(mask & clearMSR13)); - OR(32, PPCSTATE(msr), R(RSCRATCH)); - // NPC = SRR0; - MOV(32, R(RSCRATCH), PPCSTATE_SRR0); - WriteRfiExitDestInRSCRATCH(); + gpr.Flush(); + fpr.Flush(); + // See Interpreter rfi for details + const u32 mask = 0x87C0FFFF; + const u32 clearMSR13 = 0xFFFBFFFF; // Mask used to clear the bit MSR[13] + // MSR = ((MSR & ~mask) | (SRR1 & mask)) & clearMSR13; + AND(32, PPCSTATE(msr), Imm32((~mask) & clearMSR13)); + MOV(32, R(RSCRATCH), PPCSTATE_SRR1); + AND(32, R(RSCRATCH), Imm32(mask & clearMSR13)); + OR(32, PPCSTATE(msr), R(RSCRATCH)); + // NPC = SRR0; + MOV(32, R(RSCRATCH), PPCSTATE_SRR0); + WriteRfiExitDestInRSCRATCH(); } void Jit64::bx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITBranchOff); + INSTRUCTION_START + JITDISABLE(bJITBranchOff); - // We must always process the following sentence - // even if the blocks are merged by PPCAnalyst::Flatten(). - if (inst.LK) - MOV(32, PPCSTATE_LR, Imm32(js.compilerPC + 4)); + // We must always process the following sentence + // even if the blocks are merged by PPCAnalyst::Flatten(). + if (inst.LK) + MOV(32, PPCSTATE_LR, Imm32(js.compilerPC + 4)); - // If this is not the last instruction of a block, - // we will skip the rest process. - // Because PPCAnalyst::Flatten() merged the blocks. - if (!js.isLastInstruction) - { - return; - } + // If this is not the last instruction of a block, + // we will skip the rest process. + // Because PPCAnalyst::Flatten() merged the blocks. + if (!js.isLastInstruction) + { + return; + } - gpr.Flush(); - fpr.Flush(); + gpr.Flush(); + fpr.Flush(); - u32 destination; - if (inst.AA) - destination = SignExt26(inst.LI << 2); - else - destination = js.compilerPC + SignExt26(inst.LI << 2); + u32 destination; + if (inst.AA) + destination = SignExt26(inst.LI << 2); + else + destination = js.compilerPC + SignExt26(inst.LI << 2); #ifdef ACID_TEST - if (inst.LK) - AND(32, PPCSTATE(cr), Imm32(~(0xFF000000))); + if (inst.LK) + AND(32, PPCSTATE(cr), Imm32(~(0xFF000000))); #endif - if (destination == js.compilerPC) - { - //PanicAlert("Idle loop detected at %08x", destination); - // CALL(ProtectFunction(&CoreTiming::Idle, 0)); - // JMP(Asm::testExceptions, true); - // make idle loops go faster - js.downcountAmount += 8; - } - WriteExit(destination, inst.LK, js.compilerPC + 4); + if (destination == js.compilerPC) + { + // PanicAlert("Idle loop detected at %08x", destination); + // CALL(ProtectFunction(&CoreTiming::Idle, 0)); + // JMP(Asm::testExceptions, true); + // make idle loops go faster + js.downcountAmount += 8; + } + WriteExit(destination, inst.LK, js.compilerPC + 4); } // TODO - optimize to hell and beyond @@ -104,156 +104,159 @@ void Jit64::bx(UGeckoInstruction inst) // variants of this instruction. void Jit64::bcx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITBranchOff); + INSTRUCTION_START + JITDISABLE(bJITBranchOff); - // USES_CR + // USES_CR - FixupBranch pCTRDontBranch; - if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR - { - SUB(32, PPCSTATE_CTR, Imm8(1)); - if (inst.BO & BO_BRANCH_IF_CTR_0) - pCTRDontBranch = J_CC(CC_NZ, true); - else - pCTRDontBranch = J_CC(CC_Z, true); - } + FixupBranch pCTRDontBranch; + if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR + { + SUB(32, PPCSTATE_CTR, Imm8(1)); + if (inst.BO & BO_BRANCH_IF_CTR_0) + pCTRDontBranch = J_CC(CC_NZ, true); + else + pCTRDontBranch = J_CC(CC_Z, true); + } - FixupBranch pConditionDontBranch; - if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit - { - pConditionDontBranch = JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3), - !(inst.BO_2 & BO_BRANCH_IF_TRUE)); - } + FixupBranch pConditionDontBranch; + if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit + { + pConditionDontBranch = + JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3), !(inst.BO_2 & BO_BRANCH_IF_TRUE)); + } - if (inst.LK) - MOV(32, PPCSTATE_LR, Imm32(js.compilerPC + 4)); + if (inst.LK) + MOV(32, PPCSTATE_LR, Imm32(js.compilerPC + 4)); - u32 destination; - if (inst.AA) - destination = SignExt16(inst.BD << 2); - else - destination = js.compilerPC + SignExt16(inst.BD << 2); + u32 destination; + if (inst.AA) + destination = SignExt16(inst.BD << 2); + else + destination = js.compilerPC + SignExt16(inst.BD << 2); - gpr.Flush(FLUSH_MAINTAIN_STATE); - fpr.Flush(FLUSH_MAINTAIN_STATE); - WriteExit(destination, inst.LK, js.compilerPC + 4); + gpr.Flush(FLUSH_MAINTAIN_STATE); + fpr.Flush(FLUSH_MAINTAIN_STATE); + WriteExit(destination, inst.LK, js.compilerPC + 4); - if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) - SetJumpTarget(pConditionDontBranch); - if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) - SetJumpTarget(pCTRDontBranch); + if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) + SetJumpTarget(pConditionDontBranch); + if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) + SetJumpTarget(pCTRDontBranch); - if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) - { - gpr.Flush(); - fpr.Flush(); - WriteExit(js.compilerPC + 4); - } + if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) + { + gpr.Flush(); + fpr.Flush(); + WriteExit(js.compilerPC + 4); + } } void Jit64::bcctrx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITBranchOff); + INSTRUCTION_START + JITDISABLE(bJITBranchOff); - // bcctrx doesn't decrement and/or test CTR - _dbg_assert_msg_(POWERPC, inst.BO_2 & BO_DONT_DECREMENT_FLAG, "bcctrx with decrement and test CTR option is invalid!"); + // bcctrx doesn't decrement and/or test CTR + _dbg_assert_msg_(POWERPC, inst.BO_2 & BO_DONT_DECREMENT_FLAG, + "bcctrx with decrement and test CTR option is invalid!"); - if (inst.BO_2 & BO_DONT_CHECK_CONDITION) - { - // BO_2 == 1z1zz -> b always + if (inst.BO_2 & BO_DONT_CHECK_CONDITION) + { + // BO_2 == 1z1zz -> b always - //NPC = CTR & 0xfffffffc; - gpr.Flush(); - fpr.Flush(); + // NPC = CTR & 0xfffffffc; + gpr.Flush(); + fpr.Flush(); - MOV(32, R(RSCRATCH), PPCSTATE_CTR); - if (inst.LK_3) - MOV(32, PPCSTATE_LR, Imm32(js.compilerPC + 4)); // LR = PC + 4; - AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC)); - WriteExitDestInRSCRATCH(inst.LK_3, js.compilerPC + 4); - } - else - { - // Rare condition seen in (just some versions of?) Nintendo's NES Emulator + MOV(32, R(RSCRATCH), PPCSTATE_CTR); + if (inst.LK_3) + MOV(32, PPCSTATE_LR, Imm32(js.compilerPC + 4)); // LR = PC + 4; + AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC)); + WriteExitDestInRSCRATCH(inst.LK_3, js.compilerPC + 4); + } + else + { + // Rare condition seen in (just some versions of?) Nintendo's NES Emulator - // BO_2 == 001zy -> b if false - // BO_2 == 011zy -> b if true + // BO_2 == 001zy -> b if false + // BO_2 == 011zy -> b if true - FixupBranch b = JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3), - !(inst.BO_2 & BO_BRANCH_IF_TRUE)); - MOV(32, R(RSCRATCH), PPCSTATE_CTR); - AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC)); - //MOV(32, PPCSTATE(pc), R(RSCRATCH)); => Already done in WriteExitDestInRSCRATCH() - if (inst.LK_3) - MOV(32, PPCSTATE_LR, Imm32(js.compilerPC + 4)); // LR = PC + 4; + FixupBranch b = + JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3), !(inst.BO_2 & BO_BRANCH_IF_TRUE)); + MOV(32, R(RSCRATCH), PPCSTATE_CTR); + AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC)); + // MOV(32, PPCSTATE(pc), R(RSCRATCH)); => Already done in WriteExitDestInRSCRATCH() + if (inst.LK_3) + MOV(32, PPCSTATE_LR, Imm32(js.compilerPC + 4)); // LR = PC + 4; - gpr.Flush(FLUSH_MAINTAIN_STATE); - fpr.Flush(FLUSH_MAINTAIN_STATE); - WriteExitDestInRSCRATCH(inst.LK_3, js.compilerPC + 4); - // Would really like to continue the block here, but it ends. TODO. - SetJumpTarget(b); + gpr.Flush(FLUSH_MAINTAIN_STATE); + fpr.Flush(FLUSH_MAINTAIN_STATE); + WriteExitDestInRSCRATCH(inst.LK_3, js.compilerPC + 4); + // Would really like to continue the block here, but it ends. TODO. + SetJumpTarget(b); - if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) - { - gpr.Flush(); - fpr.Flush(); - WriteExit(js.compilerPC + 4); - } - } + if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) + { + gpr.Flush(); + fpr.Flush(); + WriteExit(js.compilerPC + 4); + } + } } void Jit64::bclrx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITBranchOff); + INSTRUCTION_START + JITDISABLE(bJITBranchOff); - FixupBranch pCTRDontBranch; - if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR - { - SUB(32, PPCSTATE_CTR, Imm8(1)); - if (inst.BO & BO_BRANCH_IF_CTR_0) - pCTRDontBranch = J_CC(CC_NZ, true); - else - pCTRDontBranch = J_CC(CC_Z, true); - } + FixupBranch pCTRDontBranch; + if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR + { + SUB(32, PPCSTATE_CTR, Imm8(1)); + if (inst.BO & BO_BRANCH_IF_CTR_0) + pCTRDontBranch = J_CC(CC_NZ, true); + else + pCTRDontBranch = J_CC(CC_Z, true); + } - FixupBranch pConditionDontBranch; - if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit - { - pConditionDontBranch = JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3), - !(inst.BO_2 & BO_BRANCH_IF_TRUE)); - } + FixupBranch pConditionDontBranch; + if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit + { + pConditionDontBranch = + JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3), !(inst.BO_2 & BO_BRANCH_IF_TRUE)); + } - // This below line can be used to prove that blr "eats flags" in practice. - // This observation could let us do some useful optimizations. +// This below line can be used to prove that blr "eats flags" in practice. +// This observation could let us do some useful optimizations. #ifdef ACID_TEST - AND(32, PPCSTATE(cr), Imm32(~(0xFF000000))); + AND(32, PPCSTATE(cr), Imm32(~(0xFF000000))); #endif - MOV(32, R(RSCRATCH), PPCSTATE_LR); - // We don't have to do this because WriteBLRExit handles it for us. Specifically, since we only ever push - // divisible-by-four instruction addresses onto the stack, if the return address matches, we're already - // good. If it doesn't match, the mispredicted-BLR code handles the fixup. - if (!m_enable_blr_optimization) - AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC)); - if (inst.LK) - MOV(32, PPCSTATE_LR, Imm32(js.compilerPC + 4)); + MOV(32, R(RSCRATCH), PPCSTATE_LR); + // We don't have to do this because WriteBLRExit handles it for us. Specifically, since we only + // ever push + // divisible-by-four instruction addresses onto the stack, if the return address matches, we're + // already + // good. If it doesn't match, the mispredicted-BLR code handles the fixup. + if (!m_enable_blr_optimization) + AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC)); + if (inst.LK) + MOV(32, PPCSTATE_LR, Imm32(js.compilerPC + 4)); - gpr.Flush(FLUSH_MAINTAIN_STATE); - fpr.Flush(FLUSH_MAINTAIN_STATE); - WriteBLRExit(); + gpr.Flush(FLUSH_MAINTAIN_STATE); + fpr.Flush(FLUSH_MAINTAIN_STATE); + WriteBLRExit(); - if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) - SetJumpTarget(pConditionDontBranch); - if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) - SetJumpTarget(pCTRDontBranch); + if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) + SetJumpTarget(pConditionDontBranch); + if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) + SetJumpTarget(pCTRDontBranch); - if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) - { - gpr.Flush(); - fpr.Flush(); - WriteExit(js.compilerPC + 4); - } + if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) + { + gpr.Flush(); + fpr.Flush(); + WriteExit(js.compilerPC + 4); + } } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp index 4a923d4a0b..4a50a0ca82 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp @@ -6,49 +6,51 @@ #include #include "Common/Assert.h" -#include "Common/CommonTypes.h" #include "Common/CPUDetect.h" +#include "Common/CommonTypes.h" #include "Common/x64Emitter.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/Jit64/Jit.h" #include "Core/PowerPC/Jit64/JitRegCache.h" +#include "Core/PowerPC/PPCAnalyst.h" +#include "Core/PowerPC/PowerPC.h" using namespace Gen; -alignas(16) static const u64 psSignBits[2] = {0x8000000000000000ULL, 0x0000000000000000ULL}; -alignas(16) static const u64 psSignBits2[2] = {0x8000000000000000ULL, 0x8000000000000000ULL}; -alignas(16) static const u64 psAbsMask[2] = {0x7FFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL}; -alignas(16) static const u64 psAbsMask2[2] = {0x7FFFFFFFFFFFFFFFULL, 0x7FFFFFFFFFFFFFFFULL}; +alignas(16) static const u64 psSignBits[2] = {0x8000000000000000ULL, 0x0000000000000000ULL}; +alignas(16) static const u64 psSignBits2[2] = {0x8000000000000000ULL, 0x8000000000000000ULL}; +alignas(16) static const u64 psAbsMask[2] = {0x7FFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL}; +alignas(16) static const u64 psAbsMask2[2] = {0x7FFFFFFFFFFFFFFFULL, 0x7FFFFFFFFFFFFFFFULL}; alignas(16) static const u64 psGeneratedQNaN[2] = {0x7FF8000000000000ULL, 0x7FF8000000000000ULL}; alignas(16) static const double half_qnan_and_s32_max[2] = {0x7FFFFFFF, -0x80000}; -X64Reg Jit64::fp_tri_op(int d, int a, int b, bool reversible, bool single, void (XEmitter::*avxOp)(X64Reg, X64Reg, const OpArg&), - void (XEmitter::*sseOp)(X64Reg, const OpArg&), bool packed, bool preserve_inputs, bool roundRHS) +X64Reg Jit64::fp_tri_op(int d, int a, int b, bool reversible, bool single, + void (XEmitter::*avxOp)(X64Reg, X64Reg, const OpArg&), + void (XEmitter::*sseOp)(X64Reg, const OpArg&), bool packed, + bool preserve_inputs, bool roundRHS) { - fpr.Lock(d, a, b); - fpr.BindToRegister(d, d == a || d == b || !single); - X64Reg dest = preserve_inputs ? XMM1 : fpr.RX(d); - if (roundRHS) - { - if (d == a && !preserve_inputs) - { - Force25BitPrecision(XMM0, fpr.R(b), XMM1); - (this->*sseOp)(fpr.RX(d), R(XMM0)); - } - else - { - Force25BitPrecision(dest, fpr.R(b), XMM0); - (this->*sseOp)(dest, fpr.R(a)); - } - } - else - { - avx_op(avxOp, sseOp, dest, fpr.R(a), fpr.R(b), packed, reversible); - } - return dest; + fpr.Lock(d, a, b); + fpr.BindToRegister(d, d == a || d == b || !single); + X64Reg dest = preserve_inputs ? XMM1 : fpr.RX(d); + if (roundRHS) + { + if (d == a && !preserve_inputs) + { + Force25BitPrecision(XMM0, fpr.R(b), XMM1); + (this->*sseOp)(fpr.RX(d), R(XMM0)); + } + else + { + Force25BitPrecision(dest, fpr.R(b), XMM0); + (this->*sseOp)(dest, fpr.R(a)); + } + } + else + { + avx_op(avxOp, sseOp, dest, fpr.R(a), fpr.R(b), packed, reversible); + } + return dest; } // We can avoid calculating FPRF if it's not needed; every float operation resets it, so @@ -56,614 +58,626 @@ X64Reg Jit64::fp_tri_op(int d, int a, int b, bool reversible, bool single, void // not calculate it. void Jit64::SetFPRFIfNeeded(X64Reg xmm) { - // As far as we know, the games that use this flag only need FPRF for fmul and fmadd, but - // FPRF is fast enough in JIT that we might as well just enable it for every float instruction - // if the FPRF flag is set. - if (SConfig::GetInstance().bFPRF && js.op->wantsFPRF) - SetFPRF(xmm); + // As far as we know, the games that use this flag only need FPRF for fmul and fmadd, but + // FPRF is fast enough in JIT that we might as well just enable it for every float instruction + // if the FPRF flag is set. + if (SConfig::GetInstance().bFPRF && js.op->wantsFPRF) + SetFPRF(xmm); } void Jit64::HandleNaNs(UGeckoInstruction inst, X64Reg xmm_out, X64Reg xmm, X64Reg clobber) { - // | PowerPC | x86 - // ---------------------+----------+--------- - // input NaN precedence | 1*3 + 2 | 1*2 + 3 - // generated QNaN | positive | negative - // - // Dragon Ball: Revenge of King Piccolo requires generated NaNs - // to be positive, so we'll have to handle them manually. + // | PowerPC | x86 + // ---------------------+----------+--------- + // input NaN precedence | 1*3 + 2 | 1*2 + 3 + // generated QNaN | positive | negative + // + // Dragon Ball: Revenge of King Piccolo requires generated NaNs + // to be positive, so we'll have to handle them manually. - if (!SConfig::GetInstance().bAccurateNaNs) - { - if (xmm_out != xmm) - MOVAPD(xmm_out, R(xmm)); - return; - } + if (!SConfig::GetInstance().bAccurateNaNs) + { + if (xmm_out != xmm) + MOVAPD(xmm_out, R(xmm)); + return; + } - _assert_(xmm != clobber); + _assert_(xmm != clobber); - std::vector inputs; - u32 a = inst.FA, b = inst.FB, c = inst.FC; - for (u32 i : {a, b, c}) - { - if (!js.op->fregsIn[i]) - continue; - if (std::find(inputs.begin(), inputs.end(), i) == inputs.end()) - inputs.push_back(i); - } - if (inst.OPCD != 4) - { - // not paired-single - UCOMISD(xmm, R(xmm)); - FixupBranch handle_nan = J_CC(CC_P, true); - SwitchToFarCode(); - SetJumpTarget(handle_nan); - std::vector fixups; - for (u32 x : inputs) - { - MOVDDUP(xmm, fpr.R(x)); - UCOMISD(xmm, R(xmm)); - fixups.push_back(J_CC(CC_P)); - } - MOVDDUP(xmm, M(psGeneratedQNaN)); - for (FixupBranch fixup : fixups) - SetJumpTarget(fixup); - FixupBranch done = J(true); - SwitchToNearCode(); - SetJumpTarget(done); - } - else - { - // paired-single - std::reverse(inputs.begin(), inputs.end()); - if (cpu_info.bSSE4_1) - { - avx_op(&XEmitter::VCMPPD, &XEmitter::CMPPD, clobber, R(xmm), R(xmm), CMP_UNORD); - PTEST(clobber, R(clobber)); - FixupBranch handle_nan = J_CC(CC_NZ, true); - SwitchToFarCode(); - SetJumpTarget(handle_nan); - _assert_msg_(DYNA_REC, clobber == XMM0, "BLENDVPD implicitly uses XMM0"); - BLENDVPD(xmm, M(psGeneratedQNaN)); - for (u32 x : inputs) - { - avx_op(&XEmitter::VCMPPD, &XEmitter::CMPPD, clobber, fpr.R(x), fpr.R(x), CMP_UNORD); - BLENDVPD(xmm, fpr.R(x)); - } - FixupBranch done = J(true); - SwitchToNearCode(); - SetJumpTarget(done); - } - else - { - // SSE2 fallback - X64Reg tmp = fpr.GetFreeXReg(); - fpr.FlushLockX(tmp); - MOVAPD(clobber, R(xmm)); - CMPPD(clobber, R(clobber), CMP_UNORD); - MOVMSKPD(RSCRATCH, R(clobber)); - TEST(32, R(RSCRATCH), R(RSCRATCH)); - FixupBranch handle_nan = J_CC(CC_NZ, true); - SwitchToFarCode(); - SetJumpTarget(handle_nan); - MOVAPD(tmp, R(clobber)); - PANDN(clobber, R(xmm)); - PAND(tmp, M(psGeneratedQNaN)); - POR(tmp, R(clobber)); - MOVAPD(xmm, R(tmp)); - for (u32 x : inputs) - { - MOVAPD(clobber, fpr.R(x)); - CMPPD(clobber, R(clobber), CMP_ORD); - MOVAPD(tmp, R(clobber)); - PANDN(clobber, fpr.R(x)); - PAND(xmm, R(tmp)); - POR(xmm, R(clobber)); - } - FixupBranch done = J(true); - SwitchToNearCode(); - SetJumpTarget(done); - fpr.UnlockX(tmp); - } - } - if (xmm_out != xmm) - MOVAPD(xmm_out, R(xmm)); + std::vector inputs; + u32 a = inst.FA, b = inst.FB, c = inst.FC; + for (u32 i : {a, b, c}) + { + if (!js.op->fregsIn[i]) + continue; + if (std::find(inputs.begin(), inputs.end(), i) == inputs.end()) + inputs.push_back(i); + } + if (inst.OPCD != 4) + { + // not paired-single + UCOMISD(xmm, R(xmm)); + FixupBranch handle_nan = J_CC(CC_P, true); + SwitchToFarCode(); + SetJumpTarget(handle_nan); + std::vector fixups; + for (u32 x : inputs) + { + MOVDDUP(xmm, fpr.R(x)); + UCOMISD(xmm, R(xmm)); + fixups.push_back(J_CC(CC_P)); + } + MOVDDUP(xmm, M(psGeneratedQNaN)); + for (FixupBranch fixup : fixups) + SetJumpTarget(fixup); + FixupBranch done = J(true); + SwitchToNearCode(); + SetJumpTarget(done); + } + else + { + // paired-single + std::reverse(inputs.begin(), inputs.end()); + if (cpu_info.bSSE4_1) + { + avx_op(&XEmitter::VCMPPD, &XEmitter::CMPPD, clobber, R(xmm), R(xmm), CMP_UNORD); + PTEST(clobber, R(clobber)); + FixupBranch handle_nan = J_CC(CC_NZ, true); + SwitchToFarCode(); + SetJumpTarget(handle_nan); + _assert_msg_(DYNA_REC, clobber == XMM0, "BLENDVPD implicitly uses XMM0"); + BLENDVPD(xmm, M(psGeneratedQNaN)); + for (u32 x : inputs) + { + avx_op(&XEmitter::VCMPPD, &XEmitter::CMPPD, clobber, fpr.R(x), fpr.R(x), CMP_UNORD); + BLENDVPD(xmm, fpr.R(x)); + } + FixupBranch done = J(true); + SwitchToNearCode(); + SetJumpTarget(done); + } + else + { + // SSE2 fallback + X64Reg tmp = fpr.GetFreeXReg(); + fpr.FlushLockX(tmp); + MOVAPD(clobber, R(xmm)); + CMPPD(clobber, R(clobber), CMP_UNORD); + MOVMSKPD(RSCRATCH, R(clobber)); + TEST(32, R(RSCRATCH), R(RSCRATCH)); + FixupBranch handle_nan = J_CC(CC_NZ, true); + SwitchToFarCode(); + SetJumpTarget(handle_nan); + MOVAPD(tmp, R(clobber)); + PANDN(clobber, R(xmm)); + PAND(tmp, M(psGeneratedQNaN)); + POR(tmp, R(clobber)); + MOVAPD(xmm, R(tmp)); + for (u32 x : inputs) + { + MOVAPD(clobber, fpr.R(x)); + CMPPD(clobber, R(clobber), CMP_ORD); + MOVAPD(tmp, R(clobber)); + PANDN(clobber, fpr.R(x)); + PAND(xmm, R(tmp)); + POR(xmm, R(clobber)); + } + FixupBranch done = J(true); + SwitchToNearCode(); + SetJumpTarget(done); + fpr.UnlockX(tmp); + } + } + if (xmm_out != xmm) + MOVAPD(xmm_out, R(xmm)); } void Jit64::fp_arith(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); - int a = inst.FA; - int b = inst.FB; - int c = inst.FC; - int d = inst.FD; - int arg2 = inst.SUBOP5 == 25 ? c : b; + int a = inst.FA; + int b = inst.FB; + int c = inst.FC; + int d = inst.FD; + int arg2 = inst.SUBOP5 == 25 ? c : b; - bool single = inst.OPCD == 4 || inst.OPCD == 59; - // If both the inputs are known to have identical top and bottom halves, we can skip the MOVDDUP at the end by - // using packed arithmetic instead. - bool packed = inst.OPCD == 4 || (inst.OPCD == 59 && - jit->js.op->fprIsDuplicated[a] && - jit->js.op->fprIsDuplicated[arg2]); - // Packed divides are slower than scalar divides on basically all x86, so this optimization isn't worth it in that case. - // Atoms (and a few really old CPUs) are also slower on packed operations than scalar ones. - if (inst.OPCD == 59 && (inst.SUBOP5 == 18 || cpu_info.bAtom)) - packed = false; + bool single = inst.OPCD == 4 || inst.OPCD == 59; + // If both the inputs are known to have identical top and bottom halves, we can skip the MOVDDUP + // at the end by + // using packed arithmetic instead. + bool packed = inst.OPCD == 4 || (inst.OPCD == 59 && jit->js.op->fprIsDuplicated[a] && + jit->js.op->fprIsDuplicated[arg2]); + // Packed divides are slower than scalar divides on basically all x86, so this optimization isn't + // worth it in that case. + // Atoms (and a few really old CPUs) are also slower on packed operations than scalar ones. + if (inst.OPCD == 59 && (inst.SUBOP5 == 18 || cpu_info.bAtom)) + packed = false; - bool round_input = single && !jit->js.op->fprIsSingle[inst.FC]; - bool preserve_inputs = SConfig::GetInstance().bAccurateNaNs; + bool round_input = single && !jit->js.op->fprIsSingle[inst.FC]; + bool preserve_inputs = SConfig::GetInstance().bAccurateNaNs; - X64Reg dest = INVALID_REG; - switch (inst.SUBOP5) - { - case 18: dest = fp_tri_op(d, a, b, false, single, packed ? &XEmitter::VDIVPD : &XEmitter::VDIVSD, - packed ? &XEmitter::DIVPD : &XEmitter::DIVSD, packed, preserve_inputs); break; - case 20: dest = fp_tri_op(d, a, b, false, single, packed ? &XEmitter::VSUBPD : &XEmitter::VSUBSD, - packed ? &XEmitter::SUBPD : &XEmitter::SUBSD, packed, preserve_inputs); break; - case 21: dest = fp_tri_op(d, a, b, true, single, packed ? &XEmitter::VADDPD : &XEmitter::VADDSD, - packed ? &XEmitter::ADDPD : &XEmitter::ADDSD, packed, preserve_inputs); break; - case 25: dest = fp_tri_op(d, a, c, true, single, packed ? &XEmitter::VMULPD : &XEmitter::VMULSD, - packed ? &XEmitter::MULPD : &XEmitter::MULSD, packed, preserve_inputs, round_input); break; - default: - _assert_msg_(DYNA_REC, 0, "fp_arith WTF!!!"); - } - HandleNaNs(inst, fpr.RX(d), dest); - if (single) - ForceSinglePrecision(fpr.RX(d), fpr.R(d), packed, true); - SetFPRFIfNeeded(fpr.RX(d)); - fpr.UnlockAll(); + X64Reg dest = INVALID_REG; + switch (inst.SUBOP5) + { + case 18: + dest = fp_tri_op(d, a, b, false, single, packed ? &XEmitter::VDIVPD : &XEmitter::VDIVSD, + packed ? &XEmitter::DIVPD : &XEmitter::DIVSD, packed, preserve_inputs); + break; + case 20: + dest = fp_tri_op(d, a, b, false, single, packed ? &XEmitter::VSUBPD : &XEmitter::VSUBSD, + packed ? &XEmitter::SUBPD : &XEmitter::SUBSD, packed, preserve_inputs); + break; + case 21: + dest = fp_tri_op(d, a, b, true, single, packed ? &XEmitter::VADDPD : &XEmitter::VADDSD, + packed ? &XEmitter::ADDPD : &XEmitter::ADDSD, packed, preserve_inputs); + break; + case 25: + dest = fp_tri_op(d, a, c, true, single, packed ? &XEmitter::VMULPD : &XEmitter::VMULSD, + packed ? &XEmitter::MULPD : &XEmitter::MULSD, packed, preserve_inputs, + round_input); + break; + default: + _assert_msg_(DYNA_REC, 0, "fp_arith WTF!!!"); + } + HandleNaNs(inst, fpr.RX(d), dest); + if (single) + ForceSinglePrecision(fpr.RX(d), fpr.R(d), packed, true); + SetFPRFIfNeeded(fpr.RX(d)); + fpr.UnlockAll(); } void Jit64::fmaddXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); - int a = inst.FA; - int b = inst.FB; - int c = inst.FC; - int d = inst.FD; - bool single = inst.OPCD == 4 || inst.OPCD == 59; - bool round_input = single && !jit->js.op->fprIsSingle[c]; - bool packed = inst.OPCD == 4 || - (!cpu_info.bAtom && single && - jit->js.op->fprIsDuplicated[a] && - jit->js.op->fprIsDuplicated[b] && - jit->js.op->fprIsDuplicated[c]); + int a = inst.FA; + int b = inst.FB; + int c = inst.FC; + int d = inst.FD; + bool single = inst.OPCD == 4 || inst.OPCD == 59; + bool round_input = single && !jit->js.op->fprIsSingle[c]; + bool packed = + inst.OPCD == 4 || (!cpu_info.bAtom && single && jit->js.op->fprIsDuplicated[a] && + jit->js.op->fprIsDuplicated[b] && jit->js.op->fprIsDuplicated[c]); - fpr.Lock(a, b, c, d); + fpr.Lock(a, b, c, d); - switch(inst.SUBOP5) - { - case 14: - MOVDDUP(XMM1, fpr.R(c)); - if (round_input) - Force25BitPrecision(XMM1, R(XMM1), XMM0); - break; - case 15: - avx_op(&XEmitter::VSHUFPD, &XEmitter::SHUFPD, XMM1, fpr.R(c), fpr.R(c), 3); - if (round_input) - Force25BitPrecision(XMM1, R(XMM1), XMM0); - break; - default: - bool special = inst.SUBOP5 == 30 && (!cpu_info.bFMA || Core::g_want_determinism); - X64Reg tmp1 = special ? XMM0 : XMM1; - X64Reg tmp2 = special ? XMM1 : XMM0; - if (single && round_input) - Force25BitPrecision(tmp1, fpr.R(c), tmp2); - else - MOVAPD(tmp1, fpr.R(c)); - break; - } + switch (inst.SUBOP5) + { + case 14: + MOVDDUP(XMM1, fpr.R(c)); + if (round_input) + Force25BitPrecision(XMM1, R(XMM1), XMM0); + break; + case 15: + avx_op(&XEmitter::VSHUFPD, &XEmitter::SHUFPD, XMM1, fpr.R(c), fpr.R(c), 3); + if (round_input) + Force25BitPrecision(XMM1, R(XMM1), XMM0); + break; + default: + bool special = inst.SUBOP5 == 30 && (!cpu_info.bFMA || Core::g_want_determinism); + X64Reg tmp1 = special ? XMM0 : XMM1; + X64Reg tmp2 = special ? XMM1 : XMM0; + if (single && round_input) + Force25BitPrecision(tmp1, fpr.R(c), tmp2); + else + MOVAPD(tmp1, fpr.R(c)); + break; + } - // While we don't know if any games are actually affected (replays seem to work with all the usual - // suspects for desyncing), netplay and other applications need absolute perfect determinism, so - // be extra careful and don't use FMA, even if in theory it might be okay. - // Note that FMA isn't necessarily less correct (it may actually be closer to correct) compared - // to what the Gekko does here; in deterministic mode, the important thing is multiple Dolphin - // instances on different computers giving identical results. - if (cpu_info.bFMA && !Core::g_want_determinism) - { - // Statistics suggests b is a lot less likely to be unbound in practice, so - // if we have to pick one of a or b to bind, let's make it b. - fpr.BindToRegister(b, true, false); - switch (inst.SUBOP5) - { - case 28: //msub - if (packed) - VFMSUB132PD(XMM1, fpr.RX(b), fpr.R(a)); - else - VFMSUB132SD(XMM1, fpr.RX(b), fpr.R(a)); - break; - case 14: //madds0 - case 15: //madds1 - case 29: //madd - if (packed) - VFMADD132PD(XMM1, fpr.RX(b), fpr.R(a)); - else - VFMADD132SD(XMM1, fpr.RX(b), fpr.R(a)); - break; - // PowerPC and x86 define NMADD/NMSUB differently - // x86: D = -A*C (+/-) B - // PPC: D = -(A*C (+/-) B) - // so we have to swap them; the ADD/SUB here isn't a typo. - case 30: //nmsub - if (packed) - VFNMADD132PD(XMM1, fpr.RX(b), fpr.R(a)); - else - VFNMADD132SD(XMM1, fpr.RX(b), fpr.R(a)); - break; - case 31: //nmadd - if (packed) - VFNMSUB132PD(XMM1, fpr.RX(b), fpr.R(a)); - else - VFNMSUB132SD(XMM1, fpr.RX(b), fpr.R(a)); - break; - } - } - else if (inst.SUBOP5 == 30) //nmsub - { - // We implement nmsub a little differently ((b - a*c) instead of -(a*c - b)), so handle it separately. - MOVAPD(XMM1, fpr.R(b)); - if (packed) - { - MULPD(XMM0, fpr.R(a)); - SUBPD(XMM1, R(XMM0)); - } - else - { - MULSD(XMM0, fpr.R(a)); - SUBSD(XMM1, R(XMM0)); - } - } - else - { - if (packed) - { - MULPD(XMM1, fpr.R(a)); - if (inst.SUBOP5 == 28) //msub - SUBPD(XMM1, fpr.R(b)); - else //(n)madd(s[01]) - ADDPD(XMM1, fpr.R(b)); - } - else - { - MULSD(XMM1, fpr.R(a)); - if (inst.SUBOP5 == 28) - SUBSD(XMM1, fpr.R(b)); - else - ADDSD(XMM1, fpr.R(b)); - } - if (inst.SUBOP5 == 31) //nmadd - PXOR(XMM1, M(packed ? psSignBits2 : psSignBits)); - } - fpr.BindToRegister(d, !single); - if (single) - { - HandleNaNs(inst, fpr.RX(d), XMM1); - ForceSinglePrecision(fpr.RX(d), fpr.R(d), packed, true); - } - else - { - HandleNaNs(inst, XMM1, XMM1); - MOVSD(fpr.RX(d), R(XMM1)); - } - SetFPRFIfNeeded(fpr.RX(d)); - fpr.UnlockAll(); + // While we don't know if any games are actually affected (replays seem to work with all the usual + // suspects for desyncing), netplay and other applications need absolute perfect determinism, so + // be extra careful and don't use FMA, even if in theory it might be okay. + // Note that FMA isn't necessarily less correct (it may actually be closer to correct) compared + // to what the Gekko does here; in deterministic mode, the important thing is multiple Dolphin + // instances on different computers giving identical results. + if (cpu_info.bFMA && !Core::g_want_determinism) + { + // Statistics suggests b is a lot less likely to be unbound in practice, so + // if we have to pick one of a or b to bind, let's make it b. + fpr.BindToRegister(b, true, false); + switch (inst.SUBOP5) + { + case 28: // msub + if (packed) + VFMSUB132PD(XMM1, fpr.RX(b), fpr.R(a)); + else + VFMSUB132SD(XMM1, fpr.RX(b), fpr.R(a)); + break; + case 14: // madds0 + case 15: // madds1 + case 29: // madd + if (packed) + VFMADD132PD(XMM1, fpr.RX(b), fpr.R(a)); + else + VFMADD132SD(XMM1, fpr.RX(b), fpr.R(a)); + break; + // PowerPC and x86 define NMADD/NMSUB differently + // x86: D = -A*C (+/-) B + // PPC: D = -(A*C (+/-) B) + // so we have to swap them; the ADD/SUB here isn't a typo. + case 30: // nmsub + if (packed) + VFNMADD132PD(XMM1, fpr.RX(b), fpr.R(a)); + else + VFNMADD132SD(XMM1, fpr.RX(b), fpr.R(a)); + break; + case 31: // nmadd + if (packed) + VFNMSUB132PD(XMM1, fpr.RX(b), fpr.R(a)); + else + VFNMSUB132SD(XMM1, fpr.RX(b), fpr.R(a)); + break; + } + } + else if (inst.SUBOP5 == 30) // nmsub + { + // We implement nmsub a little differently ((b - a*c) instead of -(a*c - b)), so handle it + // separately. + MOVAPD(XMM1, fpr.R(b)); + if (packed) + { + MULPD(XMM0, fpr.R(a)); + SUBPD(XMM1, R(XMM0)); + } + else + { + MULSD(XMM0, fpr.R(a)); + SUBSD(XMM1, R(XMM0)); + } + } + else + { + if (packed) + { + MULPD(XMM1, fpr.R(a)); + if (inst.SUBOP5 == 28) // msub + SUBPD(XMM1, fpr.R(b)); + else //(n)madd(s[01]) + ADDPD(XMM1, fpr.R(b)); + } + else + { + MULSD(XMM1, fpr.R(a)); + if (inst.SUBOP5 == 28) + SUBSD(XMM1, fpr.R(b)); + else + ADDSD(XMM1, fpr.R(b)); + } + if (inst.SUBOP5 == 31) // nmadd + PXOR(XMM1, M(packed ? psSignBits2 : psSignBits)); + } + fpr.BindToRegister(d, !single); + if (single) + { + HandleNaNs(inst, fpr.RX(d), XMM1); + ForceSinglePrecision(fpr.RX(d), fpr.R(d), packed, true); + } + else + { + HandleNaNs(inst, XMM1, XMM1); + MOVSD(fpr.RX(d), R(XMM1)); + } + SetFPRFIfNeeded(fpr.RX(d)); + fpr.UnlockAll(); } void Jit64::fsign(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); - int d = inst.FD; - int b = inst.FB; - bool packed = inst.OPCD == 4; + int d = inst.FD; + int b = inst.FB; + bool packed = inst.OPCD == 4; - fpr.Lock(b, d); - OpArg src = fpr.R(b); - fpr.BindToRegister(d, false); + fpr.Lock(b, d); + OpArg src = fpr.R(b); + fpr.BindToRegister(d, false); - switch (inst.SUBOP10) - { - case 40: // neg - avx_op(&XEmitter::VPXOR, &XEmitter::PXOR, fpr.RX(d), src, M(packed ? psSignBits2 : psSignBits), packed); - break; - case 136: // nabs - avx_op(&XEmitter::VPOR, &XEmitter::POR, fpr.RX(d), src, M(packed ? psSignBits2 : psSignBits), packed); - break; - case 264: // abs - avx_op(&XEmitter::VPAND, &XEmitter::PAND, fpr.RX(d), src, M(packed ? psAbsMask2 : psAbsMask), packed); - break; - default: - PanicAlert("fsign bleh"); - break; - } - fpr.UnlockAll(); + switch (inst.SUBOP10) + { + case 40: // neg + avx_op(&XEmitter::VPXOR, &XEmitter::PXOR, fpr.RX(d), src, M(packed ? psSignBits2 : psSignBits), + packed); + break; + case 136: // nabs + avx_op(&XEmitter::VPOR, &XEmitter::POR, fpr.RX(d), src, M(packed ? psSignBits2 : psSignBits), + packed); + break; + case 264: // abs + avx_op(&XEmitter::VPAND, &XEmitter::PAND, fpr.RX(d), src, M(packed ? psAbsMask2 : psAbsMask), + packed); + break; + default: + PanicAlert("fsign bleh"); + break; + } + fpr.UnlockAll(); } void Jit64::fselx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); - int d = inst.FD; - int a = inst.FA; - int b = inst.FB; - int c = inst.FC; + int d = inst.FD; + int a = inst.FA; + int b = inst.FB; + int c = inst.FC; - bool packed = inst.OPCD == 4; // ps_sel + bool packed = inst.OPCD == 4; // ps_sel - fpr.Lock(a, b, c, d); - PXOR(XMM0, R(XMM0)); - // This condition is very tricky; there's only one right way to handle both the case of - // negative/positive zero and NaN properly. - // (a >= -0.0 ? c : b) transforms into (0 > a ? b : c), hence the NLE. - if (packed) - CMPPD(XMM0, fpr.R(a), CMP_NLE); - else - CMPSD(XMM0, fpr.R(a), CMP_NLE); + fpr.Lock(a, b, c, d); + PXOR(XMM0, R(XMM0)); + // This condition is very tricky; there's only one right way to handle both the case of + // negative/positive zero and NaN properly. + // (a >= -0.0 ? c : b) transforms into (0 > a ? b : c), hence the NLE. + if (packed) + CMPPD(XMM0, fpr.R(a), CMP_NLE); + else + CMPSD(XMM0, fpr.R(a), CMP_NLE); - if (cpu_info.bSSE4_1) - { - MOVAPD(XMM1, fpr.R(c)); - BLENDVPD(XMM1, fpr.R(b)); - } - else - { - MOVAPD(XMM1, R(XMM0)); - PAND(XMM0, fpr.R(b)); - PANDN(XMM1, fpr.R(c)); - POR(XMM1, R(XMM0)); - } + if (cpu_info.bSSE4_1) + { + MOVAPD(XMM1, fpr.R(c)); + BLENDVPD(XMM1, fpr.R(b)); + } + else + { + MOVAPD(XMM1, R(XMM0)); + PAND(XMM0, fpr.R(b)); + PANDN(XMM1, fpr.R(c)); + POR(XMM1, R(XMM0)); + } - fpr.BindToRegister(d, !packed); - if (packed) - MOVAPD(fpr.RX(d), R(XMM1)); - else - MOVSD(fpr.RX(d), R(XMM1)); - fpr.UnlockAll(); + fpr.BindToRegister(d, !packed); + if (packed) + MOVAPD(fpr.RX(d), R(XMM1)); + else + MOVSD(fpr.RX(d), R(XMM1)); + fpr.UnlockAll(); } void Jit64::fmrx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); - int d = inst.FD; - int b = inst.FB; + int d = inst.FD; + int b = inst.FB; - if (d == b) - return; + if (d == b) + return; - fpr.Lock(b, d); + fpr.Lock(b, d); - if (fpr.IsBound(d)) - { - // We don't need to load d, but if it is loaded, we need to mark it as dirty. - fpr.BindToRegister(d); - // We have to use MOVLPD if b isn't loaded because "MOVSD reg, mem" sets the upper bits (64+) - // to zero and we don't want that. - if (!fpr.R(b).IsSimpleReg()) - MOVLPD(fpr.RX(d), fpr.R(b)); - else - MOVSD(fpr.R(d), fpr.RX(b)); - } - else - { - fpr.BindToRegister(b, true, false); - MOVSD(fpr.R(d), fpr.RX(b)); - } + if (fpr.IsBound(d)) + { + // We don't need to load d, but if it is loaded, we need to mark it as dirty. + fpr.BindToRegister(d); + // We have to use MOVLPD if b isn't loaded because "MOVSD reg, mem" sets the upper bits (64+) + // to zero and we don't want that. + if (!fpr.R(b).IsSimpleReg()) + MOVLPD(fpr.RX(d), fpr.R(b)); + else + MOVSD(fpr.R(d), fpr.RX(b)); + } + else + { + fpr.BindToRegister(b, true, false); + MOVSD(fpr.R(d), fpr.RX(b)); + } - fpr.UnlockAll(); + fpr.UnlockAll(); } void Jit64::FloatCompare(UGeckoInstruction inst, bool upper) { - bool fprf = SConfig::GetInstance().bFPRF && js.op->wantsFPRF; - //bool ordered = !!(inst.SUBOP10 & 32); - int a = inst.FA; - int b = inst.FB; - int crf = inst.CRFD; - int output[4] = { CR_SO, CR_EQ, CR_GT, CR_LT }; + bool fprf = SConfig::GetInstance().bFPRF && js.op->wantsFPRF; + // bool ordered = !!(inst.SUBOP10 & 32); + int a = inst.FA; + int b = inst.FB; + int crf = inst.CRFD; + int output[4] = {CR_SO, CR_EQ, CR_GT, CR_LT}; - // Merge neighboring fcmp and cror (the primary use of cror). - UGeckoInstruction next = js.op[1].inst; - if (analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CROR_MERGE) && - MergeAllowedNextInstructions(1) && next.OPCD == 19 && next.SUBOP10 == 449 && - (next.CRBA >> 2) == crf && (next.CRBB >> 2) == crf && (next.CRBD >> 2) == crf) - { - js.skipInstructions = 1; - js.downcountAmount++; - int dst = 3 - (next.CRBD & 3); - output[3 - (next.CRBD & 3)] &= ~(1 << dst); - output[3 - (next.CRBA & 3)] |= 1 << dst; - output[3 - (next.CRBB & 3)] |= 1 << dst; - } + // Merge neighboring fcmp and cror (the primary use of cror). + UGeckoInstruction next = js.op[1].inst; + if (analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CROR_MERGE) && + MergeAllowedNextInstructions(1) && next.OPCD == 19 && next.SUBOP10 == 449 && + (next.CRBA >> 2) == crf && (next.CRBB >> 2) == crf && (next.CRBD >> 2) == crf) + { + js.skipInstructions = 1; + js.downcountAmount++; + int dst = 3 - (next.CRBD & 3); + output[3 - (next.CRBD & 3)] &= ~(1 << dst); + output[3 - (next.CRBA & 3)] |= 1 << dst; + output[3 - (next.CRBB & 3)] |= 1 << dst; + } - fpr.Lock(a, b); - fpr.BindToRegister(b, true, false); + fpr.Lock(a, b); + fpr.BindToRegister(b, true, false); - if (fprf) - AND(32, PPCSTATE(fpscr), Imm32(~FPRF_MASK)); + if (fprf) + AND(32, PPCSTATE(fpscr), Imm32(~FPRF_MASK)); - if (upper) - { - fpr.BindToRegister(a, true, false); - MOVHLPS(XMM0, fpr.RX(a)); - MOVHLPS(XMM1, fpr.RX(b)); - UCOMISD(XMM1, R(XMM0)); - } - else - { - UCOMISD(fpr.RX(b), fpr.R(a)); - } + if (upper) + { + fpr.BindToRegister(a, true, false); + MOVHLPS(XMM0, fpr.RX(a)); + MOVHLPS(XMM1, fpr.RX(b)); + UCOMISD(XMM1, R(XMM0)); + } + else + { + UCOMISD(fpr.RX(b), fpr.R(a)); + } - FixupBranch pNaN, pLesser, pGreater; - FixupBranch continue1, continue2, continue3; + FixupBranch pNaN, pLesser, pGreater; + FixupBranch continue1, continue2, continue3; - if (a != b) - { - // if B > A, goto Lesser's jump target - pLesser = J_CC(CC_A); - } + if (a != b) + { + // if B > A, goto Lesser's jump target + pLesser = J_CC(CC_A); + } - // if (B != B) or (A != A), goto NaN's jump target - pNaN = J_CC(CC_P); + // if (B != B) or (A != A), goto NaN's jump target + pNaN = J_CC(CC_P); - if (a != b) - { - // if B < A, goto Greater's jump target - // JB can't precede the NaN check because it doesn't test ZF - pGreater = J_CC(CC_B); - } + if (a != b) + { + // if B < A, goto Greater's jump target + // JB can't precede the NaN check because it doesn't test ZF + pGreater = J_CC(CC_B); + } - MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(output[CR_EQ_BIT]))); - if (fprf) - OR(32, PPCSTATE(fpscr), Imm32(CR_EQ << FPRF_SHIFT)); + MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(output[CR_EQ_BIT]))); + if (fprf) + OR(32, PPCSTATE(fpscr), Imm32(CR_EQ << FPRF_SHIFT)); - continue1 = J(); + continue1 = J(); - SetJumpTarget(pNaN); - MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(output[CR_SO_BIT]))); - if (fprf) - OR(32, PPCSTATE(fpscr), Imm32(CR_SO << FPRF_SHIFT)); + SetJumpTarget(pNaN); + MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(output[CR_SO_BIT]))); + if (fprf) + OR(32, PPCSTATE(fpscr), Imm32(CR_SO << FPRF_SHIFT)); - if (a != b) - { - continue2 = J(); + if (a != b) + { + continue2 = J(); - SetJumpTarget(pGreater); - MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(output[CR_GT_BIT]))); - if (fprf) - OR(32, PPCSTATE(fpscr), Imm32(CR_GT << FPRF_SHIFT)); - continue3 = J(); + SetJumpTarget(pGreater); + MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(output[CR_GT_BIT]))); + if (fprf) + OR(32, PPCSTATE(fpscr), Imm32(CR_GT << FPRF_SHIFT)); + continue3 = J(); - SetJumpTarget(pLesser); - MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(output[CR_LT_BIT]))); - if (fprf) - OR(32, PPCSTATE(fpscr), Imm32(CR_LT << FPRF_SHIFT)); - } + SetJumpTarget(pLesser); + MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(output[CR_LT_BIT]))); + if (fprf) + OR(32, PPCSTATE(fpscr), Imm32(CR_LT << FPRF_SHIFT)); + } - SetJumpTarget(continue1); - if (a != b) - { - SetJumpTarget(continue2); - SetJumpTarget(continue3); - } + SetJumpTarget(continue1); + if (a != b) + { + SetJumpTarget(continue2); + SetJumpTarget(continue3); + } - MOV(64, PPCSTATE(cr_val[crf]), R(RSCRATCH)); - fpr.UnlockAll(); + MOV(64, PPCSTATE(cr_val[crf]), R(RSCRATCH)); + fpr.UnlockAll(); } void Jit64::fcmpX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); - FloatCompare(inst); + FloatCompare(inst); } void Jit64::fctiwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); - int d = inst.RD; - int b = inst.RB; - fpr.Lock(d, b); - fpr.BindToRegister(d); + int d = inst.RD; + int b = inst.RB; + fpr.Lock(d, b); + fpr.BindToRegister(d); - // Intel uses 0x80000000 as a generic error code while PowerPC uses clamping: - // - // input | output fctiw | output CVTPD2DQ - // ------------+--------------+---------------- - // > +2^31 - 1 | 0x7fffffff | 0x80000000 - // < -2^31 | 0x80000000 | 0x80000000 - // any NaN | 0x80000000 | 0x80000000 - // - // The upper 32 bits of the result are set to 0xfff80000, - // except for -0.0 where they are set to 0xfff80001 (TODO). + // Intel uses 0x80000000 as a generic error code while PowerPC uses clamping: + // + // input | output fctiw | output CVTPD2DQ + // ------------+--------------+---------------- + // > +2^31 - 1 | 0x7fffffff | 0x80000000 + // < -2^31 | 0x80000000 | 0x80000000 + // any NaN | 0x80000000 | 0x80000000 + // + // The upper 32 bits of the result are set to 0xfff80000, + // except for -0.0 where they are set to 0xfff80001 (TODO). - MOVAPD(XMM0, M(half_qnan_and_s32_max)); - MINSD(XMM0, fpr.R(b)); - switch (inst.SUBOP10) - { - // fctiwx - case 14: - CVTPD2DQ(XMM0, R(XMM0)); - break; + MOVAPD(XMM0, M(half_qnan_and_s32_max)); + MINSD(XMM0, fpr.R(b)); + switch (inst.SUBOP10) + { + // fctiwx + case 14: + CVTPD2DQ(XMM0, R(XMM0)); + break; - // fctiwzx - case 15: - CVTTPD2DQ(XMM0, R(XMM0)); - break; - } - // d[64+] must not be modified - MOVSD(fpr.R(d), XMM0); - fpr.UnlockAll(); + // fctiwzx + case 15: + CVTTPD2DQ(XMM0, R(XMM0)); + break; + } + // d[64+] must not be modified + MOVSD(fpr.R(d), XMM0); + fpr.UnlockAll(); } void Jit64::frspx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); - int b = inst.FB; - int d = inst.FD; - bool packed = jit->js.op->fprIsDuplicated[b] && !cpu_info.bAtom; + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + int b = inst.FB; + int d = inst.FD; + bool packed = jit->js.op->fprIsDuplicated[b] && !cpu_info.bAtom; - fpr.Lock(b, d); - OpArg src = fpr.R(b); - fpr.BindToRegister(d, false); - ForceSinglePrecision(fpr.RX(d), src, packed, true); - SetFPRFIfNeeded(fpr.RX(d)); - fpr.UnlockAll(); + fpr.Lock(b, d); + OpArg src = fpr.R(b); + fpr.BindToRegister(d, false); + ForceSinglePrecision(fpr.RX(d), src, packed, true); + SetFPRFIfNeeded(fpr.RX(d)); + fpr.UnlockAll(); } void Jit64::frsqrtex(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); - int b = inst.FB; - int d = inst.FD; + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + int b = inst.FB; + int d = inst.FD; - gpr.FlushLockX(RSCRATCH_EXTRA); - fpr.Lock(b, d); - fpr.BindToRegister(d); - MOVAPD(XMM0, fpr.R(b)); - CALL(asm_routines.frsqrte); - MOVSD(fpr.R(d), XMM0); - SetFPRFIfNeeded(fpr.RX(d)); - fpr.UnlockAll(); - gpr.UnlockAllX(); + gpr.FlushLockX(RSCRATCH_EXTRA); + fpr.Lock(b, d); + fpr.BindToRegister(d); + MOVAPD(XMM0, fpr.R(b)); + CALL(asm_routines.frsqrte); + MOVSD(fpr.R(d), XMM0); + SetFPRFIfNeeded(fpr.RX(d)); + fpr.UnlockAll(); + gpr.UnlockAllX(); } void Jit64::fresx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); - int b = inst.FB; - int d = inst.FD; + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + int b = inst.FB; + int d = inst.FD; - gpr.FlushLockX(RSCRATCH_EXTRA); - fpr.Lock(b, d); - MOVAPD(XMM0, fpr.R(b)); - fpr.BindToRegister(d, false); - CALL(asm_routines.fres); - MOVDDUP(fpr.RX(d), R(XMM0)); - SetFPRFIfNeeded(fpr.RX(d)); - fpr.UnlockAll(); - gpr.UnlockAllX(); + gpr.FlushLockX(RSCRATCH_EXTRA); + fpr.Lock(b, d); + MOVAPD(XMM0, fpr.R(b)); + fpr.BindToRegister(d, false); + CALL(asm_routines.fres); + MOVDDUP(fpr.RX(d), R(XMM0)); + SetFPRFIfNeeded(fpr.RX(d)); + fpr.UnlockAll(); + gpr.UnlockAllX(); } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp index ef35d5242e..b70c31debf 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp @@ -10,124 +10,126 @@ #include "Common/MathUtil.h" #include "Common/x64Emitter.h" #include "Core/ConfigManager.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/Jit64/Jit.h" #include "Core/PowerPC/Jit64/JitRegCache.h" #include "Core/PowerPC/JitCommon/Jit_Util.h" +#include "Core/PowerPC/PPCAnalyst.h" +#include "Core/PowerPC/PowerPC.h" using namespace Gen; void Jit64::GenerateConstantOverflow(s64 val) { - GenerateConstantOverflow(val > std::numeric_limits::max() || val < std::numeric_limits::min()); + GenerateConstantOverflow(val > std::numeric_limits::max() || + val < std::numeric_limits::min()); } void Jit64::GenerateConstantOverflow(bool overflow) { - if (overflow) - { - //XER[OV/SO] = 1 - MOV(8, PPCSTATE(xer_so_ov), Imm8(XER_OV_MASK | XER_SO_MASK)); - } - else - { - //XER[OV] = 0 - AND(8, PPCSTATE(xer_so_ov), Imm8(~XER_OV_MASK)); - } + if (overflow) + { + // XER[OV/SO] = 1 + MOV(8, PPCSTATE(xer_so_ov), Imm8(XER_OV_MASK | XER_SO_MASK)); + } + else + { + // XER[OV] = 0 + AND(8, PPCSTATE(xer_so_ov), Imm8(~XER_OV_MASK)); + } } // We could do overflow branchlessly, but unlike carry it seems to be quite a bit rarer. void Jit64::GenerateOverflow() { - FixupBranch jno = J_CC(CC_NO); - //XER[OV/SO] = 1 - MOV(8, PPCSTATE(xer_so_ov), Imm8(XER_OV_MASK | XER_SO_MASK)); - FixupBranch exit = J(); - SetJumpTarget(jno); - //XER[OV] = 0 - //We need to do this without modifying flags so as not to break stuff that assumes flags - //aren't clobbered (carry, branch merging): speed doesn't really matter here (this is really - //rare). - static const u8 ovtable[4] = {0, 0, XER_SO_MASK, XER_SO_MASK}; - MOVZX(32, 8, RSCRATCH, PPCSTATE(xer_so_ov)); - MOV(8, R(RSCRATCH), MDisp(RSCRATCH, (u32)(u64)ovtable)); - MOV(8, PPCSTATE(xer_so_ov), R(RSCRATCH)); - SetJumpTarget(exit); + FixupBranch jno = J_CC(CC_NO); + // XER[OV/SO] = 1 + MOV(8, PPCSTATE(xer_so_ov), Imm8(XER_OV_MASK | XER_SO_MASK)); + FixupBranch exit = J(); + SetJumpTarget(jno); + // XER[OV] = 0 + // We need to do this without modifying flags so as not to break stuff that assumes flags + // aren't clobbered (carry, branch merging): speed doesn't really matter here (this is really + // rare). + static const u8 ovtable[4] = {0, 0, XER_SO_MASK, XER_SO_MASK}; + MOVZX(32, 8, RSCRATCH, PPCSTATE(xer_so_ov)); + MOV(8, R(RSCRATCH), MDisp(RSCRATCH, (u32)(u64)ovtable)); + MOV(8, PPCSTATE(xer_so_ov), R(RSCRATCH)); + SetJumpTarget(exit); } void Jit64::FinalizeCarry(CCFlags cond) { - js.carryFlagSet = false; - js.carryFlagInverted = false; - if (js.op->wantsCA) - { - // Not actually merging instructions, but the effect is equivalent (we can't have breakpoints/etc in between). - if (MergeAllowedNextInstructions(1) && js.op[1].wantsCAInFlags) - { - if (cond == CC_C || cond == CC_NC) - { - js.carryFlagInverted = cond == CC_NC; - } - else - { - // convert the condition to a carry flag (is there a better way?) - SETcc(cond, R(RSCRATCH)); - SHR(8, R(RSCRATCH), Imm8(1)); - } - LockFlags(); - js.carryFlagSet = true; - } - else - { - JitSetCAIf(cond); - } - } + js.carryFlagSet = false; + js.carryFlagInverted = false; + if (js.op->wantsCA) + { + // Not actually merging instructions, but the effect is equivalent (we can't have + // breakpoints/etc in between). + if (MergeAllowedNextInstructions(1) && js.op[1].wantsCAInFlags) + { + if (cond == CC_C || cond == CC_NC) + { + js.carryFlagInverted = cond == CC_NC; + } + else + { + // convert the condition to a carry flag (is there a better way?) + SETcc(cond, R(RSCRATCH)); + SHR(8, R(RSCRATCH), Imm8(1)); + } + LockFlags(); + js.carryFlagSet = true; + } + else + { + JitSetCAIf(cond); + } + } } // Unconditional version void Jit64::FinalizeCarry(bool ca) { - js.carryFlagSet = false; - js.carryFlagInverted = false; - if (js.op->wantsCA) - { - if (MergeAllowedNextInstructions(1) && js.op[1].wantsCAInFlags) - { - if (ca) - STC(); - else - CLC(); - LockFlags(); - js.carryFlagSet = true; - } - else if (ca) - { - JitSetCA(); - } - else - { - JitClearCA(); - } - } + js.carryFlagSet = false; + js.carryFlagInverted = false; + if (js.op->wantsCA) + { + if (MergeAllowedNextInstructions(1) && js.op[1].wantsCAInFlags) + { + if (ca) + STC(); + else + CLC(); + LockFlags(); + js.carryFlagSet = true; + } + else if (ca) + { + JitSetCA(); + } + else + { + JitClearCA(); + } + } } void Jit64::FinalizeCarryOverflow(bool oe, bool inv) { - if (oe) - { - // Make sure not to lose the carry flags (not a big deal, this path is rare). - PUSHF(); - //XER[OV] = 0 - AND(8, PPCSTATE(xer_so_ov), Imm8(~XER_OV_MASK)); - FixupBranch jno = J_CC(CC_NO); - //XER[OV/SO] = 1 - MOV(8, PPCSTATE(xer_so_ov), Imm8(XER_SO_MASK | XER_OV_MASK)); - SetJumpTarget(jno); - POPF(); - } - // Do carry - FinalizeCarry(inv ? CC_NC : CC_C); + if (oe) + { + // Make sure not to lose the carry flags (not a big deal, this path is rare). + PUSHF(); + // XER[OV] = 0 + AND(8, PPCSTATE(xer_so_ov), Imm8(~XER_OV_MASK)); + FixupBranch jno = J_CC(CC_NO); + // XER[OV/SO] = 1 + MOV(8, PPCSTATE(xer_so_ov), Imm8(XER_SO_MASK | XER_OV_MASK)); + SetJumpTarget(jno); + POPF(); + } + // Do carry + FinalizeCarry(inv ? CC_NC : CC_C); } // Be careful; only set needs_test to false if we can be absolutely sure flags don't need @@ -138,1781 +140,1783 @@ void Jit64::FinalizeCarryOverflow(bool oe, bool inv) // LT/GT either. void Jit64::ComputeRC(const OpArg& arg, bool needs_test, bool needs_sext) { - _assert_msg_(DYNA_REC, arg.IsSimpleReg() || arg.IsImm(), "Invalid ComputeRC operand"); - if (arg.IsImm()) - { - MOV(64, PPCSTATE(cr_val[0]), Imm32(arg.SImm32())); - } - else if (needs_sext) - { - MOVSX(64, 32, RSCRATCH, arg); - MOV(64, PPCSTATE(cr_val[0]), R(RSCRATCH)); - } - else - { - MOV(64, PPCSTATE(cr_val[0]), arg); - } - if (CheckMergedBranch(0)) - { - if (arg.IsImm()) - { - DoMergedBranchImmediate(arg.SImm32()); - } - else - { - if (needs_test) - { - TEST(32, arg, arg); - } - else - { - // If an operand to the cmp/rc op we're merging with the branch isn't used anymore, it'd be - // better to flush it here so that we don't have to flush it on both sides of the branch. - // We don't want to do this if a test is needed though, because it would interrupt macro-op - // fusion. - for (int j : ~js.op->gprInUse) - gpr.StoreFromRegister(j); - } - DoMergedBranchCondition(); - } - } + _assert_msg_(DYNA_REC, arg.IsSimpleReg() || arg.IsImm(), "Invalid ComputeRC operand"); + if (arg.IsImm()) + { + MOV(64, PPCSTATE(cr_val[0]), Imm32(arg.SImm32())); + } + else if (needs_sext) + { + MOVSX(64, 32, RSCRATCH, arg); + MOV(64, PPCSTATE(cr_val[0]), R(RSCRATCH)); + } + else + { + MOV(64, PPCSTATE(cr_val[0]), arg); + } + if (CheckMergedBranch(0)) + { + if (arg.IsImm()) + { + DoMergedBranchImmediate(arg.SImm32()); + } + else + { + if (needs_test) + { + TEST(32, arg, arg); + } + else + { + // If an operand to the cmp/rc op we're merging with the branch isn't used anymore, it'd be + // better to flush it here so that we don't have to flush it on both sides of the branch. + // We don't want to do this if a test is needed though, because it would interrupt macro-op + // fusion. + for (int j : ~js.op->gprInUse) + gpr.StoreFromRegister(j); + } + DoMergedBranchCondition(); + } + } } OpArg Jit64::ExtractFromReg(int reg, int offset) { - OpArg src = gpr.R(reg); - // store to load forwarding should handle this case efficiently - if (offset) - { - gpr.StoreFromRegister(reg, FLUSH_MAINTAIN_STATE); - src = gpr.GetDefaultLocation(reg); - src.AddMemOffset(offset); - } - return src; + OpArg src = gpr.R(reg); + // store to load forwarding should handle this case efficiently + if (offset) + { + gpr.StoreFromRegister(reg, FLUSH_MAINTAIN_STATE); + src = gpr.GetDefaultLocation(reg); + src.AddMemOffset(offset); + } + return src; } -// we can't do this optimization in the emitter because MOVZX and AND have different effects on flags. +// we can't do this optimization in the emitter because MOVZX and AND have different effects on +// flags. void Jit64::AndWithMask(X64Reg reg, u32 mask) { - if (mask == 0xff) - MOVZX(32, 8, reg, R(reg)); - else if (mask == 0xffff) - MOVZX(32, 16, reg, R(reg)); - else - AND(32, R(reg), Imm32(mask)); + if (mask == 0xff) + MOVZX(32, 8, reg, R(reg)); + else if (mask == 0xffff) + MOVZX(32, 16, reg, R(reg)); + else + AND(32, R(reg), Imm32(mask)); } // Following static functions are used in conjunction with regimmop static u32 Add(u32 a, u32 b) { - return a + b; + return a + b; } static u32 Or(u32 a, u32 b) { - return a | b; + return a | b; } static u32 And(u32 a, u32 b) { - return a & b; + return a & b; } static u32 Xor(u32 a, u32 b) { - return a ^ b; + return a ^ b; } -void Jit64::regimmop(int d, int a, bool binary, u32 value, Operation doop, void (XEmitter::*op)(int, const OpArg&, const OpArg&), bool Rc, bool carry) +void Jit64::regimmop(int d, int a, bool binary, u32 value, Operation doop, + void (XEmitter::*op)(int, const OpArg&, const OpArg&), bool Rc, bool carry) { - bool needs_test = doop == Add; - gpr.Lock(d, a); - // Be careful; addic treats r0 as r0, but addi treats r0 as zero. - if (a || binary || carry) - { - carry &= js.op->wantsCA; - if (gpr.R(a).IsImm() && !carry) - { - gpr.SetImmediate32(d, doop(gpr.R(a).Imm32(), value)); - } - else if (a == d) - { - gpr.BindToRegister(d, true); - (this->*op)(32, gpr.R(d), Imm32(value)); //m_GPR[d] = m_GPR[_inst.RA] + _inst.SIMM_16; - } - else - { - gpr.BindToRegister(d, false); - if (doop == Add && gpr.R(a).IsSimpleReg() && !carry) - { - LEA(32, gpr.RX(d), MDisp(gpr.RX(a), value)); - } - else - { - MOV(32, gpr.R(d), gpr.R(a)); - (this->*op)(32, gpr.R(d), Imm32(value)); //m_GPR[d] = m_GPR[_inst.RA] + _inst.SIMM_16; - } - } - if (carry) - FinalizeCarry(CC_C); - } - else if (doop == Add) - { - // a == 0, which for these instructions imply value = 0 - gpr.SetImmediate32(d, value); - } - else - { - _assert_msg_(DYNA_REC, 0, "WTF regimmop"); - } - if (Rc) - ComputeRC(gpr.R(d), needs_test, doop != And || (value & 0x80000000)); - gpr.UnlockAll(); + bool needs_test = doop == Add; + gpr.Lock(d, a); + // Be careful; addic treats r0 as r0, but addi treats r0 as zero. + if (a || binary || carry) + { + carry &= js.op->wantsCA; + if (gpr.R(a).IsImm() && !carry) + { + gpr.SetImmediate32(d, doop(gpr.R(a).Imm32(), value)); + } + else if (a == d) + { + gpr.BindToRegister(d, true); + (this->*op)(32, gpr.R(d), Imm32(value)); // m_GPR[d] = m_GPR[_inst.RA] + _inst.SIMM_16; + } + else + { + gpr.BindToRegister(d, false); + if (doop == Add && gpr.R(a).IsSimpleReg() && !carry) + { + LEA(32, gpr.RX(d), MDisp(gpr.RX(a), value)); + } + else + { + MOV(32, gpr.R(d), gpr.R(a)); + (this->*op)(32, gpr.R(d), Imm32(value)); // m_GPR[d] = m_GPR[_inst.RA] + _inst.SIMM_16; + } + } + if (carry) + FinalizeCarry(CC_C); + } + else if (doop == Add) + { + // a == 0, which for these instructions imply value = 0 + gpr.SetImmediate32(d, value); + } + else + { + _assert_msg_(DYNA_REC, 0, "WTF regimmop"); + } + if (Rc) + ComputeRC(gpr.R(d), needs_test, doop != And || (value & 0x80000000)); + gpr.UnlockAll(); } void Jit64::reg_imm(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - u32 d = inst.RD, a = inst.RA, s = inst.RS; - switch (inst.OPCD) - { - case 14: // addi - // occasionally used as MOV - emulate, with immediate propagation - if (gpr.R(a).IsImm() && d != a && a != 0) - { - gpr.SetImmediate32(d, gpr.R(a).Imm32() + (u32)(s32)inst.SIMM_16); - } - else if (inst.SIMM_16 == 0 && d != a && a != 0) - { - gpr.Lock(a, d); - gpr.BindToRegister(d, false, true); - MOV(32, gpr.R(d), gpr.R(a)); - gpr.UnlockAll(); - } - else - { - regimmop(d, a, false, (u32)(s32)inst.SIMM_16, Add, &XEmitter::ADD); //addi - } - break; - case 15: // addis - regimmop(d, a, false, (u32)inst.SIMM_16 << 16, Add, &XEmitter::ADD); - break; - case 24: // ori - if (a == 0 && s == 0 && inst.UIMM == 0 && !inst.Rc) //check for nop - { - // Make the nop visible in the generated code. not much use but interesting if we see one. - NOP(); - return; - } - regimmop(a, s, true, inst.UIMM, Or, &XEmitter::OR); - break; - case 25: // oris - regimmop(a, s, true, inst.UIMM << 16, Or, &XEmitter::OR, false); - break; - case 28: // andi - regimmop(a, s, true, inst.UIMM, And, &XEmitter::AND, true); - break; - case 29: // andis - regimmop(a, s, true, inst.UIMM << 16, And, &XEmitter::AND, true); - break; - case 26: // xori - regimmop(a, s, true, inst.UIMM, Xor, &XEmitter::XOR, false); - break; - case 27: // xoris - regimmop(a, s, true, inst.UIMM << 16, Xor, &XEmitter::XOR, false); - break; - case 12: // addic - regimmop(d, a, false, (u32)(s32)inst.SIMM_16, Add, &XEmitter::ADD, false, true); - break; - case 13: // addic_rc - regimmop(d, a, true, (u32)(s32)inst.SIMM_16, Add, &XEmitter::ADD, true, true); - break; - default: - FALLBACK_IF(true); - } + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + u32 d = inst.RD, a = inst.RA, s = inst.RS; + switch (inst.OPCD) + { + case 14: // addi + // occasionally used as MOV - emulate, with immediate propagation + if (gpr.R(a).IsImm() && d != a && a != 0) + { + gpr.SetImmediate32(d, gpr.R(a).Imm32() + (u32)(s32)inst.SIMM_16); + } + else if (inst.SIMM_16 == 0 && d != a && a != 0) + { + gpr.Lock(a, d); + gpr.BindToRegister(d, false, true); + MOV(32, gpr.R(d), gpr.R(a)); + gpr.UnlockAll(); + } + else + { + regimmop(d, a, false, (u32)(s32)inst.SIMM_16, Add, &XEmitter::ADD); // addi + } + break; + case 15: // addis + regimmop(d, a, false, (u32)inst.SIMM_16 << 16, Add, &XEmitter::ADD); + break; + case 24: // ori + if (a == 0 && s == 0 && inst.UIMM == 0 && !inst.Rc) // check for nop + { + // Make the nop visible in the generated code. not much use but interesting if we see one. + NOP(); + return; + } + regimmop(a, s, true, inst.UIMM, Or, &XEmitter::OR); + break; + case 25: // oris + regimmop(a, s, true, inst.UIMM << 16, Or, &XEmitter::OR, false); + break; + case 28: // andi + regimmop(a, s, true, inst.UIMM, And, &XEmitter::AND, true); + break; + case 29: // andis + regimmop(a, s, true, inst.UIMM << 16, And, &XEmitter::AND, true); + break; + case 26: // xori + regimmop(a, s, true, inst.UIMM, Xor, &XEmitter::XOR, false); + break; + case 27: // xoris + regimmop(a, s, true, inst.UIMM << 16, Xor, &XEmitter::XOR, false); + break; + case 12: // addic + regimmop(d, a, false, (u32)(s32)inst.SIMM_16, Add, &XEmitter::ADD, false, true); + break; + case 13: // addic_rc + regimmop(d, a, true, (u32)(s32)inst.SIMM_16, Add, &XEmitter::ADD, true, true); + break; + default: + FALLBACK_IF(true); + } } bool Jit64::CheckMergedBranch(int crf) { - if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_BRANCH_MERGE)) - return false; + if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_BRANCH_MERGE)) + return false; - if (!MergeAllowedNextInstructions(1)) - return false; + if (!MergeAllowedNextInstructions(1)) + return false; - const UGeckoInstruction& next = js.op[1].inst; - return (((next.OPCD == 16 /* bcx */) || - ((next.OPCD == 19) && (next.SUBOP10 == 528) /* bcctrx */) || - ((next.OPCD == 19) && (next.SUBOP10 == 16) /* bclrx */)) && - (next.BO & BO_DONT_DECREMENT_FLAG) && - !(next.BO & BO_DONT_CHECK_CONDITION) && - (next.BI >> 2) == crf); + const UGeckoInstruction& next = js.op[1].inst; + return (((next.OPCD == 16 /* bcx */) || + ((next.OPCD == 19) && (next.SUBOP10 == 528) /* bcctrx */) || + ((next.OPCD == 19) && (next.SUBOP10 == 16) /* bclrx */)) && + (next.BO & BO_DONT_DECREMENT_FLAG) && !(next.BO & BO_DONT_CHECK_CONDITION) && + (next.BI >> 2) == crf); } void Jit64::DoMergedBranch() { - // Code that handles successful PPC branching. - const UGeckoInstruction& next = js.op[1].inst; - const u32 nextPC = js.op[1].address; - if (next.OPCD == 16) // bcx - { - if (next.LK) - MOV(32, M(&LR), Imm32(nextPC + 4)); + // Code that handles successful PPC branching. + const UGeckoInstruction& next = js.op[1].inst; + const u32 nextPC = js.op[1].address; + if (next.OPCD == 16) // bcx + { + if (next.LK) + MOV(32, M(&LR), Imm32(nextPC + 4)); - u32 destination; - if (next.AA) - destination = SignExt16(next.BD << 2); - else - destination = nextPC + SignExt16(next.BD << 2); - WriteExit(destination, next.LK, nextPC + 4); - } - else if ((next.OPCD == 19) && (next.SUBOP10 == 528)) // bcctrx - { - if (next.LK) - MOV(32, M(&LR), Imm32(nextPC + 4)); - MOV(32, R(RSCRATCH), M(&CTR)); - AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC)); - WriteExitDestInRSCRATCH(next.LK, nextPC + 4); - } - else if ((next.OPCD == 19) && (next.SUBOP10 == 16)) // bclrx - { - MOV(32, R(RSCRATCH), M(&LR)); - if (!m_enable_blr_optimization) - AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC)); - if (next.LK) - MOV(32, M(&LR), Imm32(nextPC + 4)); - WriteBLRExit(); - } - else - { - PanicAlert("WTF invalid branch"); - } + u32 destination; + if (next.AA) + destination = SignExt16(next.BD << 2); + else + destination = nextPC + SignExt16(next.BD << 2); + WriteExit(destination, next.LK, nextPC + 4); + } + else if ((next.OPCD == 19) && (next.SUBOP10 == 528)) // bcctrx + { + if (next.LK) + MOV(32, M(&LR), Imm32(nextPC + 4)); + MOV(32, R(RSCRATCH), M(&CTR)); + AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC)); + WriteExitDestInRSCRATCH(next.LK, nextPC + 4); + } + else if ((next.OPCD == 19) && (next.SUBOP10 == 16)) // bclrx + { + MOV(32, R(RSCRATCH), M(&LR)); + if (!m_enable_blr_optimization) + AND(32, R(RSCRATCH), Imm32(0xFFFFFFFC)); + if (next.LK) + MOV(32, M(&LR), Imm32(nextPC + 4)); + WriteBLRExit(); + } + else + { + PanicAlert("WTF invalid branch"); + } } void Jit64::DoMergedBranchCondition() { - js.downcountAmount++; - js.skipInstructions = 1; - const UGeckoInstruction& next = js.op[1].inst; - int test_bit = 8 >> (next.BI & 3); - bool condition = !!(next.BO & BO_BRANCH_IF_TRUE); - const u32 nextPC = js.op[1].address; + js.downcountAmount++; + js.skipInstructions = 1; + const UGeckoInstruction& next = js.op[1].inst; + int test_bit = 8 >> (next.BI & 3); + bool condition = !!(next.BO & BO_BRANCH_IF_TRUE); + const u32 nextPC = js.op[1].address; - gpr.UnlockAll(); - gpr.UnlockAllX(); - FixupBranch pDontBranch; - if (test_bit & 8) - pDontBranch = J_CC(condition ? CC_GE : CC_L, true); // Test < 0, so jump over if >= 0. - else if (test_bit & 4) - pDontBranch = J_CC(condition ? CC_LE : CC_G, true); // Test > 0, so jump over if <= 0. - else if (test_bit & 2) - pDontBranch = J_CC(condition ? CC_NE : CC_E, true); // Test = 0, so jump over if != 0. - else // SO bit, do not branch (we don't emulate SO for cmp). - pDontBranch = J(true); + gpr.UnlockAll(); + gpr.UnlockAllX(); + FixupBranch pDontBranch; + if (test_bit & 8) + pDontBranch = J_CC(condition ? CC_GE : CC_L, true); // Test < 0, so jump over if >= 0. + else if (test_bit & 4) + pDontBranch = J_CC(condition ? CC_LE : CC_G, true); // Test > 0, so jump over if <= 0. + else if (test_bit & 2) + pDontBranch = J_CC(condition ? CC_NE : CC_E, true); // Test = 0, so jump over if != 0. + else // SO bit, do not branch (we don't emulate SO for cmp). + pDontBranch = J(true); - gpr.Flush(FLUSH_MAINTAIN_STATE); - fpr.Flush(FLUSH_MAINTAIN_STATE); + gpr.Flush(FLUSH_MAINTAIN_STATE); + fpr.Flush(FLUSH_MAINTAIN_STATE); - DoMergedBranch(); + DoMergedBranch(); - SetJumpTarget(pDontBranch); + SetJumpTarget(pDontBranch); - if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) - { - gpr.Flush(); - fpr.Flush(); - WriteExit(nextPC + 4); - } + if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) + { + gpr.Flush(); + fpr.Flush(); + WriteExit(nextPC + 4); + } } void Jit64::DoMergedBranchImmediate(s64 val) { - js.downcountAmount++; - js.skipInstructions = 1; - const UGeckoInstruction& next = js.op[1].inst; - int test_bit = 8 >> (next.BI & 3); - bool condition = !!(next.BO & BO_BRANCH_IF_TRUE); - const u32 nextPC = js.op[1].address; + js.downcountAmount++; + js.skipInstructions = 1; + const UGeckoInstruction& next = js.op[1].inst; + int test_bit = 8 >> (next.BI & 3); + bool condition = !!(next.BO & BO_BRANCH_IF_TRUE); + const u32 nextPC = js.op[1].address; - gpr.UnlockAll(); - gpr.UnlockAllX(); - bool branch; - if (test_bit & 8) - branch = condition ? val < 0 : val >= 0; - else if (test_bit & 4) - branch = condition ? val > 0 : val <= 0; - else if (test_bit & 2) - branch = condition ? val == 0 : val != 0; - else // SO bit, do not branch (we don't emulate SO for cmp). - branch = false; + gpr.UnlockAll(); + gpr.UnlockAllX(); + bool branch; + if (test_bit & 8) + branch = condition ? val < 0 : val >= 0; + else if (test_bit & 4) + branch = condition ? val > 0 : val <= 0; + else if (test_bit & 2) + branch = condition ? val == 0 : val != 0; + else // SO bit, do not branch (we don't emulate SO for cmp). + branch = false; - if (branch) - { - gpr.Flush(); - fpr.Flush(); - DoMergedBranch(); - } - else if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) - { - gpr.Flush(); - fpr.Flush(); - WriteExit(nextPC + 4); - } + if (branch) + { + gpr.Flush(); + fpr.Flush(); + DoMergedBranch(); + } + else if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) + { + gpr.Flush(); + fpr.Flush(); + WriteExit(nextPC + 4); + } } void Jit64::cmpXX(UGeckoInstruction inst) { - // USES_CR - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA; - int b = inst.RB; - int crf = inst.CRFD; - bool merge_branch = CheckMergedBranch(crf); + // USES_CR + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA; + int b = inst.RB; + int crf = inst.CRFD; + bool merge_branch = CheckMergedBranch(crf); - OpArg comparand; - bool signedCompare; - if (inst.OPCD == 31) - { - // cmp / cmpl - gpr.Lock(a, b); - comparand = gpr.R(b); - signedCompare = (inst.SUBOP10 == 0); - } - else - { - gpr.Lock(a); - if (inst.OPCD == 10) - { - //cmpli - comparand = Imm32((u32)inst.UIMM); - signedCompare = false; - } - else if (inst.OPCD == 11) - { - //cmpi - comparand = Imm32((u32)(s32)(s16)inst.UIMM); - signedCompare = true; - } - else - { - signedCompare = false; // silence compiler warning - PanicAlert("cmpXX"); - } - } + OpArg comparand; + bool signedCompare; + if (inst.OPCD == 31) + { + // cmp / cmpl + gpr.Lock(a, b); + comparand = gpr.R(b); + signedCompare = (inst.SUBOP10 == 0); + } + else + { + gpr.Lock(a); + if (inst.OPCD == 10) + { + // cmpli + comparand = Imm32((u32)inst.UIMM); + signedCompare = false; + } + else if (inst.OPCD == 11) + { + // cmpi + comparand = Imm32((u32)(s32)(s16)inst.UIMM); + signedCompare = true; + } + else + { + signedCompare = false; // silence compiler warning + PanicAlert("cmpXX"); + } + } - if (gpr.R(a).IsImm() && comparand.IsImm()) - { - // Both registers contain immediate values, so we can pre-compile the compare result - s64 compareResult = signedCompare ? (s64)gpr.R(a).SImm32() - (s64)comparand.SImm32() : - (u64)gpr.R(a).Imm32() - (u64)comparand.Imm32(); - if (compareResult == (s32)compareResult) - { - MOV(64, PPCSTATE(cr_val[crf]), Imm32((u32)compareResult)); - } - else - { - MOV(64, R(RSCRATCH), Imm64(compareResult)); - MOV(64, PPCSTATE(cr_val[crf]), R(RSCRATCH)); - } + if (gpr.R(a).IsImm() && comparand.IsImm()) + { + // Both registers contain immediate values, so we can pre-compile the compare result + s64 compareResult = signedCompare ? (s64)gpr.R(a).SImm32() - (s64)comparand.SImm32() : + (u64)gpr.R(a).Imm32() - (u64)comparand.Imm32(); + if (compareResult == (s32)compareResult) + { + MOV(64, PPCSTATE(cr_val[crf]), Imm32((u32)compareResult)); + } + else + { + MOV(64, R(RSCRATCH), Imm64(compareResult)); + MOV(64, PPCSTATE(cr_val[crf]), R(RSCRATCH)); + } - if (merge_branch) - DoMergedBranchImmediate(compareResult); - } - else - { - X64Reg input = RSCRATCH; - if (signedCompare) - { - if (gpr.R(a).IsImm()) - MOV(64, R(input), Imm32(gpr.R(a).SImm32())); - else - MOVSX(64, 32, input, gpr.R(a)); + if (merge_branch) + DoMergedBranchImmediate(compareResult); + } + else + { + X64Reg input = RSCRATCH; + if (signedCompare) + { + if (gpr.R(a).IsImm()) + MOV(64, R(input), Imm32(gpr.R(a).SImm32())); + else + MOVSX(64, 32, input, gpr.R(a)); - if (!comparand.IsImm()) - { - MOVSX(64, 32, RSCRATCH2, comparand); - comparand = R(RSCRATCH2); - } - } - else - { - if (gpr.R(a).IsImm()) - { - MOV(32, R(input), Imm32(gpr.R(a).Imm32())); - } - else if (comparand.IsImm() && !comparand.Imm32()) - { - gpr.BindToRegister(a, true, false); - input = gpr.RX(a); - } - else - { - MOVZX(64, 32, input, gpr.R(a)); - } + if (!comparand.IsImm()) + { + MOVSX(64, 32, RSCRATCH2, comparand); + comparand = R(RSCRATCH2); + } + } + else + { + if (gpr.R(a).IsImm()) + { + MOV(32, R(input), Imm32(gpr.R(a).Imm32())); + } + else if (comparand.IsImm() && !comparand.Imm32()) + { + gpr.BindToRegister(a, true, false); + input = gpr.RX(a); + } + else + { + MOVZX(64, 32, input, gpr.R(a)); + } - if (comparand.IsImm()) - { - // sign extension will ruin this, so store it in a register - if (comparand.Imm32() & 0x80000000U) - { - MOV(32, R(RSCRATCH2), comparand); - comparand = R(RSCRATCH2); - } - } - else - { - gpr.BindToRegister(b, true, false); - comparand = gpr.R(b); - } - } - if (comparand.IsImm() && !comparand.Imm32()) - { - MOV(64, PPCSTATE(cr_val[crf]), R(input)); - // Place the comparison next to the branch for macro-op fusion - if (merge_branch) - TEST(64, R(input), R(input)); - } - else - { - SUB(64, R(input), comparand); - MOV(64, PPCSTATE(cr_val[crf]), R(input)); - } + if (comparand.IsImm()) + { + // sign extension will ruin this, so store it in a register + if (comparand.Imm32() & 0x80000000U) + { + MOV(32, R(RSCRATCH2), comparand); + comparand = R(RSCRATCH2); + } + } + else + { + gpr.BindToRegister(b, true, false); + comparand = gpr.R(b); + } + } + if (comparand.IsImm() && !comparand.Imm32()) + { + MOV(64, PPCSTATE(cr_val[crf]), R(input)); + // Place the comparison next to the branch for macro-op fusion + if (merge_branch) + TEST(64, R(input), R(input)); + } + else + { + SUB(64, R(input), comparand); + MOV(64, PPCSTATE(cr_val[crf]), R(input)); + } - if (merge_branch) - DoMergedBranchCondition(); - } + if (merge_branch) + DoMergedBranchCondition(); + } - gpr.UnlockAll(); + gpr.UnlockAll(); } void Jit64::boolX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA, s = inst.RS, b = inst.RB; - bool needs_test = false; - _dbg_assert_msg_(DYNA_REC, inst.OPCD == 31, "Invalid boolX"); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA, s = inst.RS, b = inst.RB; + bool needs_test = false; + _dbg_assert_msg_(DYNA_REC, inst.OPCD == 31, "Invalid boolX"); - if (gpr.R(s).IsImm() && gpr.R(b).IsImm()) - { - const u32 rs_offset = gpr.R(s).Imm32(); - const u32 rb_offset = gpr.R(b).Imm32(); + if (gpr.R(s).IsImm() && gpr.R(b).IsImm()) + { + const u32 rs_offset = gpr.R(s).Imm32(); + const u32 rb_offset = gpr.R(b).Imm32(); - if (inst.SUBOP10 == 28) // andx - gpr.SetImmediate32(a, rs_offset & rb_offset); - else if (inst.SUBOP10 == 476) // nandx - gpr.SetImmediate32(a, ~(rs_offset & rb_offset)); - else if (inst.SUBOP10 == 60) // andcx - gpr.SetImmediate32(a, rs_offset & (~rb_offset)); - else if (inst.SUBOP10 == 444) // orx - gpr.SetImmediate32(a, rs_offset | rb_offset); - else if (inst.SUBOP10 == 124) // norx - gpr.SetImmediate32(a, ~(rs_offset | rb_offset)); - else if (inst.SUBOP10 == 412) // orcx - gpr.SetImmediate32(a, rs_offset | (~rb_offset)); - else if (inst.SUBOP10 == 316) // xorx - gpr.SetImmediate32(a, rs_offset ^ rb_offset); - else if (inst.SUBOP10 == 284) // eqvx - gpr.SetImmediate32(a, ~(rs_offset ^ rb_offset)); - } - else if (s == b) - { - if ((inst.SUBOP10 == 28 /* andx */) || (inst.SUBOP10 == 444 /* orx */)) - { - if (a != s) - { - gpr.Lock(a,s); - gpr.BindToRegister(a, false, true); - MOV(32, gpr.R(a), gpr.R(s)); - } - else if (inst.Rc) - { - gpr.BindToRegister(a, true, false); - } - needs_test = true; - } - else if ((inst.SUBOP10 == 476 /* nandx */) || (inst.SUBOP10 == 124 /* norx */)) - { - if (a != s) - { - gpr.Lock(a,s); - gpr.BindToRegister(a, false, true); - MOV(32, gpr.R(a), gpr.R(s)); - } - else if (inst.Rc) - { - gpr.BindToRegister(a, true, true); - } - else - { - gpr.KillImmediate(a, true, true); - } - NOT(32, gpr.R(a)); - needs_test = true; - } - else if ((inst.SUBOP10 == 412 /* orcx */) || (inst.SUBOP10 == 284 /* eqvx */)) - { - gpr.SetImmediate32(a, 0xFFFFFFFF); - } - else if ((inst.SUBOP10 == 60 /* andcx */) || (inst.SUBOP10 == 316 /* xorx */)) - { - gpr.SetImmediate32(a, 0); - } - else - { - PanicAlert("WTF!"); - } - } - else if ((a == s) || (a == b)) - { - gpr.Lock(a,((a == s) ? b : s)); - OpArg operand = ((a == s) ? gpr.R(b) : gpr.R(s)); - gpr.BindToRegister(a, true, true); + if (inst.SUBOP10 == 28) // andx + gpr.SetImmediate32(a, rs_offset & rb_offset); + else if (inst.SUBOP10 == 476) // nandx + gpr.SetImmediate32(a, ~(rs_offset & rb_offset)); + else if (inst.SUBOP10 == 60) // andcx + gpr.SetImmediate32(a, rs_offset & (~rb_offset)); + else if (inst.SUBOP10 == 444) // orx + gpr.SetImmediate32(a, rs_offset | rb_offset); + else if (inst.SUBOP10 == 124) // norx + gpr.SetImmediate32(a, ~(rs_offset | rb_offset)); + else if (inst.SUBOP10 == 412) // orcx + gpr.SetImmediate32(a, rs_offset | (~rb_offset)); + else if (inst.SUBOP10 == 316) // xorx + gpr.SetImmediate32(a, rs_offset ^ rb_offset); + else if (inst.SUBOP10 == 284) // eqvx + gpr.SetImmediate32(a, ~(rs_offset ^ rb_offset)); + } + else if (s == b) + { + if ((inst.SUBOP10 == 28 /* andx */) || (inst.SUBOP10 == 444 /* orx */)) + { + if (a != s) + { + gpr.Lock(a, s); + gpr.BindToRegister(a, false, true); + MOV(32, gpr.R(a), gpr.R(s)); + } + else if (inst.Rc) + { + gpr.BindToRegister(a, true, false); + } + needs_test = true; + } + else if ((inst.SUBOP10 == 476 /* nandx */) || (inst.SUBOP10 == 124 /* norx */)) + { + if (a != s) + { + gpr.Lock(a, s); + gpr.BindToRegister(a, false, true); + MOV(32, gpr.R(a), gpr.R(s)); + } + else if (inst.Rc) + { + gpr.BindToRegister(a, true, true); + } + else + { + gpr.KillImmediate(a, true, true); + } + NOT(32, gpr.R(a)); + needs_test = true; + } + else if ((inst.SUBOP10 == 412 /* orcx */) || (inst.SUBOP10 == 284 /* eqvx */)) + { + gpr.SetImmediate32(a, 0xFFFFFFFF); + } + else if ((inst.SUBOP10 == 60 /* andcx */) || (inst.SUBOP10 == 316 /* xorx */)) + { + gpr.SetImmediate32(a, 0); + } + else + { + PanicAlert("WTF!"); + } + } + else if ((a == s) || (a == b)) + { + gpr.Lock(a, ((a == s) ? b : s)); + OpArg operand = ((a == s) ? gpr.R(b) : gpr.R(s)); + gpr.BindToRegister(a, true, true); - if (inst.SUBOP10 == 28) // andx - { - AND(32, gpr.R(a), operand); - } - else if (inst.SUBOP10 == 476) // nandx - { - AND(32, gpr.R(a), operand); - NOT(32, gpr.R(a)); - needs_test = true; - } - else if (inst.SUBOP10 == 60) // andcx - { - if (cpu_info.bBMI1 && gpr.R(b).IsSimpleReg() && !gpr.R(s).IsImm()) - { - ANDN(32, gpr.RX(a), gpr.RX(b), gpr.R(s)); - } - else if (a == b) - { - NOT(32, gpr.R(a)); - AND(32, gpr.R(a), operand); - } - else - { - MOV(32, R(RSCRATCH), operand); - NOT(32, R(RSCRATCH)); - AND(32, gpr.R(a), R(RSCRATCH)); - } - } - else if (inst.SUBOP10 == 444) // orx - { - OR(32, gpr.R(a), operand); - } - else if (inst.SUBOP10 == 124) // norx - { - OR(32, gpr.R(a), operand); - NOT(32, gpr.R(a)); - needs_test = true; - } - else if (inst.SUBOP10 == 412) // orcx - { - if (a == b) - { - NOT(32, gpr.R(a)); - OR(32, gpr.R(a), operand); - } - else - { - MOV(32, R(RSCRATCH), operand); - NOT(32, R(RSCRATCH)); - OR(32, gpr.R(a), R(RSCRATCH)); - } - } - else if (inst.SUBOP10 == 316) // xorx - { - XOR(32, gpr.R(a), operand); - } - else if (inst.SUBOP10 == 284) // eqvx - { - NOT(32, gpr.R(a)); - XOR(32, gpr.R(a), operand); - } - else - { - PanicAlert("WTF"); - } - } - else - { - gpr.Lock(a,s,b); - gpr.BindToRegister(a, false, true); + if (inst.SUBOP10 == 28) // andx + { + AND(32, gpr.R(a), operand); + } + else if (inst.SUBOP10 == 476) // nandx + { + AND(32, gpr.R(a), operand); + NOT(32, gpr.R(a)); + needs_test = true; + } + else if (inst.SUBOP10 == 60) // andcx + { + if (cpu_info.bBMI1 && gpr.R(b).IsSimpleReg() && !gpr.R(s).IsImm()) + { + ANDN(32, gpr.RX(a), gpr.RX(b), gpr.R(s)); + } + else if (a == b) + { + NOT(32, gpr.R(a)); + AND(32, gpr.R(a), operand); + } + else + { + MOV(32, R(RSCRATCH), operand); + NOT(32, R(RSCRATCH)); + AND(32, gpr.R(a), R(RSCRATCH)); + } + } + else if (inst.SUBOP10 == 444) // orx + { + OR(32, gpr.R(a), operand); + } + else if (inst.SUBOP10 == 124) // norx + { + OR(32, gpr.R(a), operand); + NOT(32, gpr.R(a)); + needs_test = true; + } + else if (inst.SUBOP10 == 412) // orcx + { + if (a == b) + { + NOT(32, gpr.R(a)); + OR(32, gpr.R(a), operand); + } + else + { + MOV(32, R(RSCRATCH), operand); + NOT(32, R(RSCRATCH)); + OR(32, gpr.R(a), R(RSCRATCH)); + } + } + else if (inst.SUBOP10 == 316) // xorx + { + XOR(32, gpr.R(a), operand); + } + else if (inst.SUBOP10 == 284) // eqvx + { + NOT(32, gpr.R(a)); + XOR(32, gpr.R(a), operand); + } + else + { + PanicAlert("WTF"); + } + } + else + { + gpr.Lock(a, s, b); + gpr.BindToRegister(a, false, true); - if (inst.SUBOP10 == 28) // andx - { - MOV(32, gpr.R(a), gpr.R(s)); - AND(32, gpr.R(a), gpr.R(b)); - } - else if (inst.SUBOP10 == 476) // nandx - { - MOV(32, gpr.R(a), gpr.R(s)); - AND(32, gpr.R(a), gpr.R(b)); - NOT(32, gpr.R(a)); - needs_test = true; - } - else if (inst.SUBOP10 == 60) // andcx - { - if (cpu_info.bBMI1 && gpr.R(b).IsSimpleReg() && !gpr.R(s).IsImm()) - { - ANDN(32, gpr.RX(a), gpr.RX(b), gpr.R(s)); - } - else - { - MOV(32, gpr.R(a), gpr.R(b)); - NOT(32, gpr.R(a)); - AND(32, gpr.R(a), gpr.R(s)); - } - } - else if (inst.SUBOP10 == 444) // orx - { - MOV(32, gpr.R(a), gpr.R(s)); - OR(32, gpr.R(a), gpr.R(b)); - } - else if (inst.SUBOP10 == 124) // norx - { - MOV(32, gpr.R(a), gpr.R(s)); - OR(32, gpr.R(a), gpr.R(b)); - NOT(32, gpr.R(a)); - needs_test = true; - } - else if (inst.SUBOP10 == 412) // orcx - { - MOV(32, gpr.R(a), gpr.R(b)); - NOT(32, gpr.R(a)); - OR(32, gpr.R(a), gpr.R(s)); - } - else if (inst.SUBOP10 == 316) // xorx - { - MOV(32, gpr.R(a), gpr.R(s)); - XOR(32, gpr.R(a), gpr.R(b)); - } - else if (inst.SUBOP10 == 284) // eqvx - { - MOV(32, gpr.R(a), gpr.R(s)); - NOT(32, gpr.R(a)); - XOR(32, gpr.R(a), gpr.R(b)); - } - else - { - PanicAlert("WTF!"); - } - } - if (inst.Rc) - ComputeRC(gpr.R(a), needs_test); - gpr.UnlockAll(); + if (inst.SUBOP10 == 28) // andx + { + MOV(32, gpr.R(a), gpr.R(s)); + AND(32, gpr.R(a), gpr.R(b)); + } + else if (inst.SUBOP10 == 476) // nandx + { + MOV(32, gpr.R(a), gpr.R(s)); + AND(32, gpr.R(a), gpr.R(b)); + NOT(32, gpr.R(a)); + needs_test = true; + } + else if (inst.SUBOP10 == 60) // andcx + { + if (cpu_info.bBMI1 && gpr.R(b).IsSimpleReg() && !gpr.R(s).IsImm()) + { + ANDN(32, gpr.RX(a), gpr.RX(b), gpr.R(s)); + } + else + { + MOV(32, gpr.R(a), gpr.R(b)); + NOT(32, gpr.R(a)); + AND(32, gpr.R(a), gpr.R(s)); + } + } + else if (inst.SUBOP10 == 444) // orx + { + MOV(32, gpr.R(a), gpr.R(s)); + OR(32, gpr.R(a), gpr.R(b)); + } + else if (inst.SUBOP10 == 124) // norx + { + MOV(32, gpr.R(a), gpr.R(s)); + OR(32, gpr.R(a), gpr.R(b)); + NOT(32, gpr.R(a)); + needs_test = true; + } + else if (inst.SUBOP10 == 412) // orcx + { + MOV(32, gpr.R(a), gpr.R(b)); + NOT(32, gpr.R(a)); + OR(32, gpr.R(a), gpr.R(s)); + } + else if (inst.SUBOP10 == 316) // xorx + { + MOV(32, gpr.R(a), gpr.R(s)); + XOR(32, gpr.R(a), gpr.R(b)); + } + else if (inst.SUBOP10 == 284) // eqvx + { + MOV(32, gpr.R(a), gpr.R(s)); + NOT(32, gpr.R(a)); + XOR(32, gpr.R(a), gpr.R(b)); + } + else + { + PanicAlert("WTF!"); + } + } + if (inst.Rc) + ComputeRC(gpr.R(a), needs_test); + gpr.UnlockAll(); } void Jit64::extsXx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA, s = inst.RS; - int size = inst.SUBOP10 == 922 ? 16 : 8; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA, s = inst.RS; + int size = inst.SUBOP10 == 922 ? 16 : 8; - if (gpr.R(s).IsImm()) - { - gpr.SetImmediate32(a, (u32)(s32)(size == 16 ? (s16)gpr.R(s).Imm32() : (s8)gpr.R(s).Imm32())); - } - else - { - gpr.Lock(a, s); - gpr.BindToRegister(a, a == s, true); - MOVSX(32, size, gpr.RX(a), gpr.R(s)); - } - if (inst.Rc) - ComputeRC(gpr.R(a)); - gpr.UnlockAll(); + if (gpr.R(s).IsImm()) + { + gpr.SetImmediate32(a, (u32)(s32)(size == 16 ? (s16)gpr.R(s).Imm32() : (s8)gpr.R(s).Imm32())); + } + else + { + gpr.Lock(a, s); + gpr.BindToRegister(a, a == s, true); + MOVSX(32, size, gpr.RX(a), gpr.R(s)); + } + if (inst.Rc) + ComputeRC(gpr.R(a)); + gpr.UnlockAll(); } void Jit64::subfic(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA, d = inst.RD; - gpr.Lock(a, d); - gpr.BindToRegister(d, a == d, true); - int imm = inst.SIMM_16; - if (d == a) - { - if (imm == 0) - { - // Flags act exactly like subtracting from 0 - NEG(32, gpr.R(d)); - // Output carry is inverted - FinalizeCarry(CC_NC); - } - else if (imm == -1) - { - NOT(32, gpr.R(d)); - // CA is always set in this case - FinalizeCarry(true); - } - else - { - NOT(32, gpr.R(d)); - ADD(32, gpr.R(d), Imm32(imm+1)); - // Output carry is normal - FinalizeCarry(CC_C); - } - } - else - { - MOV(32, gpr.R(d), Imm32(imm)); - SUB(32, gpr.R(d), gpr.R(a)); - // Output carry is inverted - FinalizeCarry(CC_NC); - } - gpr.UnlockAll(); - // This instruction has no RC flag + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA, d = inst.RD; + gpr.Lock(a, d); + gpr.BindToRegister(d, a == d, true); + int imm = inst.SIMM_16; + if (d == a) + { + if (imm == 0) + { + // Flags act exactly like subtracting from 0 + NEG(32, gpr.R(d)); + // Output carry is inverted + FinalizeCarry(CC_NC); + } + else if (imm == -1) + { + NOT(32, gpr.R(d)); + // CA is always set in this case + FinalizeCarry(true); + } + else + { + NOT(32, gpr.R(d)); + ADD(32, gpr.R(d), Imm32(imm + 1)); + // Output carry is normal + FinalizeCarry(CC_C); + } + } + else + { + MOV(32, gpr.R(d), Imm32(imm)); + SUB(32, gpr.R(d), gpr.R(a)); + // Output carry is inverted + FinalizeCarry(CC_NC); + } + gpr.UnlockAll(); + // This instruction has no RC flag } void Jit64::subfx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA, b = inst.RB, d = inst.RD; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) - { - s32 i = gpr.R(b).SImm32(), j = gpr.R(a).SImm32(); - gpr.SetImmediate32(d, i - j); - if (inst.OE) - GenerateConstantOverflow((s64)i - (s64)j); - } - else - { - gpr.Lock(a, b, d); - gpr.BindToRegister(d, (d == a || d == b), true); - if (d == b) - { - SUB(32, gpr.R(d), gpr.R(a)); - } - else if (d == a) - { - MOV(32, R(RSCRATCH), gpr.R(a)); - MOV(32, gpr.R(d), gpr.R(b)); - SUB(32, gpr.R(d), R(RSCRATCH)); - } - else - { - MOV(32, gpr.R(d), gpr.R(b)); - SUB(32, gpr.R(d), gpr.R(a)); - } - if (inst.OE) - GenerateOverflow(); - } - if (inst.Rc) - ComputeRC(gpr.R(d)); - gpr.UnlockAll(); + if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) + { + s32 i = gpr.R(b).SImm32(), j = gpr.R(a).SImm32(); + gpr.SetImmediate32(d, i - j); + if (inst.OE) + GenerateConstantOverflow((s64)i - (s64)j); + } + else + { + gpr.Lock(a, b, d); + gpr.BindToRegister(d, (d == a || d == b), true); + if (d == b) + { + SUB(32, gpr.R(d), gpr.R(a)); + } + else if (d == a) + { + MOV(32, R(RSCRATCH), gpr.R(a)); + MOV(32, gpr.R(d), gpr.R(b)); + SUB(32, gpr.R(d), R(RSCRATCH)); + } + else + { + MOV(32, gpr.R(d), gpr.R(b)); + SUB(32, gpr.R(d), gpr.R(a)); + } + if (inst.OE) + GenerateOverflow(); + } + if (inst.Rc) + ComputeRC(gpr.R(d)); + gpr.UnlockAll(); } void Jit64::MultiplyImmediate(u32 imm, int a, int d, bool overflow) { - // simplest cases first - if (imm == 0) - { - XOR(32, gpr.R(d), gpr.R(d)); - return; - } + // simplest cases first + if (imm == 0) + { + XOR(32, gpr.R(d), gpr.R(d)); + return; + } - if (imm == (u32)-1) - { - if (d != a) - MOV(32, gpr.R(d), gpr.R(a)); - NEG(32, gpr.R(d)); - return; - } + if (imm == (u32)-1) + { + if (d != a) + MOV(32, gpr.R(d), gpr.R(a)); + NEG(32, gpr.R(d)); + return; + } - // skip these if we need to check overflow flag - if (!overflow) - { - // power of 2; just a shift - if (MathUtil::IsPow2(imm)) - { - u32 shift = IntLog2(imm); - // use LEA if it saves an op - if (d != a && shift <= 3 && shift >= 1 && gpr.R(a).IsSimpleReg()) - { - LEA(32, gpr.RX(d), MScaled(gpr.RX(a), SCALE_1 << shift, 0)); - } - else - { - if (d != a) - MOV(32, gpr.R(d), gpr.R(a)); - if (shift) - SHL(32, gpr.R(d), Imm8(shift)); - } - return; - } + // skip these if we need to check overflow flag + if (!overflow) + { + // power of 2; just a shift + if (MathUtil::IsPow2(imm)) + { + u32 shift = IntLog2(imm); + // use LEA if it saves an op + if (d != a && shift <= 3 && shift >= 1 && gpr.R(a).IsSimpleReg()) + { + LEA(32, gpr.RX(d), MScaled(gpr.RX(a), SCALE_1 << shift, 0)); + } + else + { + if (d != a) + MOV(32, gpr.R(d), gpr.R(a)); + if (shift) + SHL(32, gpr.R(d), Imm8(shift)); + } + return; + } - // We could handle factors of 2^N*3, 2^N*5, and 2^N*9 using lea+shl, but testing shows - // it seems to be slower overall. - static u8 lea_scales[3] = { 3, 5, 9 }; - for (int i = 0; i < 3; i++) - { - if (imm == lea_scales[i]) - { - if (d != a) - gpr.BindToRegister(a, true, false); - LEA(32, gpr.RX(d), MComplex(gpr.RX(a), gpr.RX(a), SCALE_2 << i, 0)); - return; - } - } - } + // We could handle factors of 2^N*3, 2^N*5, and 2^N*9 using lea+shl, but testing shows + // it seems to be slower overall. + static u8 lea_scales[3] = {3, 5, 9}; + for (int i = 0; i < 3; i++) + { + if (imm == lea_scales[i]) + { + if (d != a) + gpr.BindToRegister(a, true, false); + LEA(32, gpr.RX(d), MComplex(gpr.RX(a), gpr.RX(a), SCALE_2 << i, 0)); + return; + } + } + } - // if we didn't find any better options - IMUL(32, gpr.RX(d), gpr.R(a), Imm32(imm)); + // if we didn't find any better options + IMUL(32, gpr.RX(d), gpr.R(a), Imm32(imm)); } void Jit64::mulli(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA, d = inst.RD; - u32 imm = inst.SIMM_16; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA, d = inst.RD; + u32 imm = inst.SIMM_16; - if (gpr.R(a).IsImm()) - { - gpr.SetImmediate32(d, gpr.R(a).Imm32() * imm); - } - else - { - gpr.Lock(a, d); - gpr.BindToRegister(d, (d == a), true); - MultiplyImmediate(imm, a, d, false); - gpr.UnlockAll(); - } + if (gpr.R(a).IsImm()) + { + gpr.SetImmediate32(d, gpr.R(a).Imm32() * imm); + } + else + { + gpr.Lock(a, d); + gpr.BindToRegister(d, (d == a), true); + MultiplyImmediate(imm, a, d, false); + gpr.UnlockAll(); + } } void Jit64::mullwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA, b = inst.RB, d = inst.RD; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) - { - s32 i = gpr.R(a).SImm32(), j = gpr.R(b).SImm32(); - gpr.SetImmediate32(d, i * j); - if (inst.OE) - GenerateConstantOverflow((s64)i * (s64)j); - } - else - { - gpr.Lock(a, b, d); - gpr.BindToRegister(d, (d == a || d == b), true); - if (gpr.R(a).IsImm() || gpr.R(b).IsImm()) - { - u32 imm = gpr.R(a).IsImm() ? gpr.R(a).Imm32() : gpr.R(b).Imm32(); - int src = gpr.R(a).IsImm() ? b : a; - MultiplyImmediate(imm, src, d, inst.OE); - } - else if (d == a) - { - IMUL(32, gpr.RX(d), gpr.R(b)); - } - else if (d == b) - { - IMUL(32, gpr.RX(d), gpr.R(a)); - } - else - { - MOV(32, gpr.R(d), gpr.R(b)); - IMUL(32, gpr.RX(d), gpr.R(a)); - } - if (inst.OE) - GenerateOverflow(); - } - if (inst.Rc) - ComputeRC(gpr.R(d)); - gpr.UnlockAll(); + if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) + { + s32 i = gpr.R(a).SImm32(), j = gpr.R(b).SImm32(); + gpr.SetImmediate32(d, i * j); + if (inst.OE) + GenerateConstantOverflow((s64)i * (s64)j); + } + else + { + gpr.Lock(a, b, d); + gpr.BindToRegister(d, (d == a || d == b), true); + if (gpr.R(a).IsImm() || gpr.R(b).IsImm()) + { + u32 imm = gpr.R(a).IsImm() ? gpr.R(a).Imm32() : gpr.R(b).Imm32(); + int src = gpr.R(a).IsImm() ? b : a; + MultiplyImmediate(imm, src, d, inst.OE); + } + else if (d == a) + { + IMUL(32, gpr.RX(d), gpr.R(b)); + } + else if (d == b) + { + IMUL(32, gpr.RX(d), gpr.R(a)); + } + else + { + MOV(32, gpr.R(d), gpr.R(b)); + IMUL(32, gpr.RX(d), gpr.R(a)); + } + if (inst.OE) + GenerateOverflow(); + } + if (inst.Rc) + ComputeRC(gpr.R(d)); + gpr.UnlockAll(); } void Jit64::mulhwXx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA, b = inst.RB, d = inst.RD; - bool sign = inst.SUBOP10 == 75; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA, b = inst.RB, d = inst.RD; + bool sign = inst.SUBOP10 == 75; - if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) - { - if (sign) - gpr.SetImmediate32(d, (u32)((u64)(((s64)gpr.R(a).SImm32() * (s64)gpr.R(b).SImm32())) >> 32)); - else - gpr.SetImmediate32(d, (u32)(((u64)gpr.R(a).Imm32() * (u64)gpr.R(b).Imm32()) >> 32)); - } - else if (sign) - { - gpr.Lock(a, b, d); - // no register choice - gpr.FlushLockX(EDX, EAX); - gpr.BindToRegister(d, d == a || d == b, true); - MOV(32, R(EAX), gpr.R(a)); - gpr.KillImmediate(b, true, false); - IMUL(32, gpr.R(b)); - MOV(32, gpr.R(d), R(EDX)); - } - else - { - // Not faster for signed because we'd need two movsx. - gpr.Lock(a, b, d); - // We need to bind everything to registers since the top 32 bits need to be zero. - int src = d == b ? a : b; - gpr.BindToRegister(d, d == a || d == b, true); - gpr.BindToRegister(src, true, false); - if (d != a && d != b) - MOV(32, gpr.R(d), gpr.R(a)); - IMUL(64, gpr.RX(d), gpr.R(src)); - SHR(64, gpr.R(d), Imm8(32)); - } - if (inst.Rc) - ComputeRC(gpr.R(d)); - gpr.UnlockAll(); - gpr.UnlockAllX(); + if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) + { + if (sign) + gpr.SetImmediate32(d, (u32)((u64)(((s64)gpr.R(a).SImm32() * (s64)gpr.R(b).SImm32())) >> 32)); + else + gpr.SetImmediate32(d, (u32)(((u64)gpr.R(a).Imm32() * (u64)gpr.R(b).Imm32()) >> 32)); + } + else if (sign) + { + gpr.Lock(a, b, d); + // no register choice + gpr.FlushLockX(EDX, EAX); + gpr.BindToRegister(d, d == a || d == b, true); + MOV(32, R(EAX), gpr.R(a)); + gpr.KillImmediate(b, true, false); + IMUL(32, gpr.R(b)); + MOV(32, gpr.R(d), R(EDX)); + } + else + { + // Not faster for signed because we'd need two movsx. + gpr.Lock(a, b, d); + // We need to bind everything to registers since the top 32 bits need to be zero. + int src = d == b ? a : b; + gpr.BindToRegister(d, d == a || d == b, true); + gpr.BindToRegister(src, true, false); + if (d != a && d != b) + MOV(32, gpr.R(d), gpr.R(a)); + IMUL(64, gpr.RX(d), gpr.R(src)); + SHR(64, gpr.R(d), Imm8(32)); + } + if (inst.Rc) + ComputeRC(gpr.R(d)); + gpr.UnlockAll(); + gpr.UnlockAllX(); } void Jit64::divwux(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA, b = inst.RB, d = inst.RD; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) - { - if (gpr.R(b).Imm32() == 0) - { - gpr.SetImmediate32(d, 0); - if (inst.OE) - GenerateConstantOverflow(true); - } - else - { - gpr.SetImmediate32(d, gpr.R(a).Imm32() / gpr.R(b).Imm32()); - if (inst.OE) - GenerateConstantOverflow(false); - } - } - else if (gpr.R(b).IsImm()) - { - u32 divisor = gpr.R(b).Imm32(); - if (divisor == 0) - { - gpr.SetImmediate32(d, 0); - if (inst.OE) - GenerateConstantOverflow(true); - } - else - { - u32 shift = 31; - while (!(divisor & (1 << shift))) - shift--; + if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) + { + if (gpr.R(b).Imm32() == 0) + { + gpr.SetImmediate32(d, 0); + if (inst.OE) + GenerateConstantOverflow(true); + } + else + { + gpr.SetImmediate32(d, gpr.R(a).Imm32() / gpr.R(b).Imm32()); + if (inst.OE) + GenerateConstantOverflow(false); + } + } + else if (gpr.R(b).IsImm()) + { + u32 divisor = gpr.R(b).Imm32(); + if (divisor == 0) + { + gpr.SetImmediate32(d, 0); + if (inst.OE) + GenerateConstantOverflow(true); + } + else + { + u32 shift = 31; + while (!(divisor & (1 << shift))) + shift--; - if (divisor == (u32)(1 << shift)) - { - gpr.Lock(a, b, d); - gpr.BindToRegister(d, d == a, true); - if (d != a) - MOV(32, gpr.R(d), gpr.R(a)); - if (shift) - SHR(32, gpr.R(d), Imm8(shift)); - } - else - { - u64 magic_dividend = 0x100000000ULL << shift; - u32 magic = (u32)(magic_dividend / divisor); - u32 max_quotient = magic >> shift; + if (divisor == (u32)(1 << shift)) + { + gpr.Lock(a, b, d); + gpr.BindToRegister(d, d == a, true); + if (d != a) + MOV(32, gpr.R(d), gpr.R(a)); + if (shift) + SHR(32, gpr.R(d), Imm8(shift)); + } + else + { + u64 magic_dividend = 0x100000000ULL << shift; + u32 magic = (u32)(magic_dividend / divisor); + u32 max_quotient = magic >> shift; - // Test for failure in round-up method - if (((u64)(magic+1) * (max_quotient*divisor-1)) >> (shift + 32) != max_quotient-1) - { - // If failed, use slower round-down method - gpr.Lock(a, b, d); - gpr.BindToRegister(d, d == a, true); - MOV(32, R(RSCRATCH), Imm32(magic)); - if (d != a) - MOV(32, gpr.R(d), gpr.R(a)); - IMUL(64, gpr.RX(d), R(RSCRATCH)); - ADD(64, gpr.R(d), R(RSCRATCH)); - SHR(64, gpr.R(d), Imm8(shift+32)); - } - else - { - // If success, use faster round-up method - gpr.Lock(a, b, d); - gpr.BindToRegister(a, true, false); - gpr.BindToRegister(d, false, true); - if (d == a) - { - MOV(32, R(RSCRATCH), Imm32(magic+1)); - IMUL(64, gpr.RX(d), R(RSCRATCH)); - } - else - { - MOV(32, gpr.R(d), Imm32(magic+1)); - IMUL(64, gpr.RX(d), gpr.R(a)); - } - SHR(64, gpr.R(d), Imm8(shift+32)); - } - } - if (inst.OE) - GenerateConstantOverflow(false); - } - } - else - { - gpr.Lock(a, b, d); - // no register choice (do we need to do this?) - gpr.FlushLockX(EAX, EDX); - gpr.BindToRegister(d, (d == a || d == b), true); - MOV(32, R(EAX), gpr.R(a)); - XOR(32, R(EDX), R(EDX)); - gpr.KillImmediate(b, true, false); - CMP_or_TEST(32, gpr.R(b), Imm32(0)); - FixupBranch not_div_by_zero = J_CC(CC_NZ); - MOV(32, gpr.R(d), R(EDX)); - if (inst.OE) - { - GenerateConstantOverflow(true); - } - FixupBranch end = J(); - SetJumpTarget(not_div_by_zero); - DIV(32, gpr.R(b)); - MOV(32, gpr.R(d), R(EAX)); - if (inst.OE) - { - GenerateConstantOverflow(false); - } - SetJumpTarget(end); - } - if (inst.Rc) - ComputeRC(gpr.R(d)); - gpr.UnlockAll(); - gpr.UnlockAllX(); + // Test for failure in round-up method + if (((u64)(magic + 1) * (max_quotient * divisor - 1)) >> (shift + 32) != max_quotient - 1) + { + // If failed, use slower round-down method + gpr.Lock(a, b, d); + gpr.BindToRegister(d, d == a, true); + MOV(32, R(RSCRATCH), Imm32(magic)); + if (d != a) + MOV(32, gpr.R(d), gpr.R(a)); + IMUL(64, gpr.RX(d), R(RSCRATCH)); + ADD(64, gpr.R(d), R(RSCRATCH)); + SHR(64, gpr.R(d), Imm8(shift + 32)); + } + else + { + // If success, use faster round-up method + gpr.Lock(a, b, d); + gpr.BindToRegister(a, true, false); + gpr.BindToRegister(d, false, true); + if (d == a) + { + MOV(32, R(RSCRATCH), Imm32(magic + 1)); + IMUL(64, gpr.RX(d), R(RSCRATCH)); + } + else + { + MOV(32, gpr.R(d), Imm32(magic + 1)); + IMUL(64, gpr.RX(d), gpr.R(a)); + } + SHR(64, gpr.R(d), Imm8(shift + 32)); + } + } + if (inst.OE) + GenerateConstantOverflow(false); + } + } + else + { + gpr.Lock(a, b, d); + // no register choice (do we need to do this?) + gpr.FlushLockX(EAX, EDX); + gpr.BindToRegister(d, (d == a || d == b), true); + MOV(32, R(EAX), gpr.R(a)); + XOR(32, R(EDX), R(EDX)); + gpr.KillImmediate(b, true, false); + CMP_or_TEST(32, gpr.R(b), Imm32(0)); + FixupBranch not_div_by_zero = J_CC(CC_NZ); + MOV(32, gpr.R(d), R(EDX)); + if (inst.OE) + { + GenerateConstantOverflow(true); + } + FixupBranch end = J(); + SetJumpTarget(not_div_by_zero); + DIV(32, gpr.R(b)); + MOV(32, gpr.R(d), R(EAX)); + if (inst.OE) + { + GenerateConstantOverflow(false); + } + SetJumpTarget(end); + } + if (inst.Rc) + ComputeRC(gpr.R(d)); + gpr.UnlockAll(); + gpr.UnlockAllX(); } void Jit64::divwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA, b = inst.RB, d = inst.RD; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) - { - s32 i = gpr.R(a).SImm32(), j = gpr.R(b).SImm32(); - if (j == 0 || (i == (s32)0x80000000 && j == -1)) - { - gpr.SetImmediate32(d, (i >> 31) ^ j); - if (inst.OE) - GenerateConstantOverflow(true); - } - else - { - gpr.SetImmediate32(d, i / j); - if (inst.OE) - GenerateConstantOverflow(false); - } - } - else - { - gpr.Lock(a, b, d); - // no register choice - gpr.FlushLockX(EAX, EDX); - gpr.BindToRegister(d, (d == a || d == b), true); - MOV(32, R(EAX), gpr.R(a)); - CDQ(); - gpr.BindToRegister(b, true, false); - TEST(32, gpr.R(b), gpr.R(b)); - FixupBranch not_div_by_zero = J_CC(CC_NZ); - MOV(32, gpr.R(d), R(EDX)); - if (inst.OE) - { - GenerateConstantOverflow(true); - } - FixupBranch end1 = J(); - SetJumpTarget(not_div_by_zero); - CMP(32, gpr.R(b), R(EDX)); - FixupBranch not_div_by_neg_one = J_CC(CC_NZ); - MOV(32, gpr.R(d), R(EAX)); - NEG(32, gpr.R(d)); - FixupBranch no_overflow = J_CC(CC_NO); - XOR(32, gpr.R(d), gpr.R(d)); - if (inst.OE) - { - GenerateConstantOverflow(true); - } - FixupBranch end2 = J(); - SetJumpTarget(not_div_by_neg_one); - IDIV(32, gpr.R(b)); - MOV(32, gpr.R(d), R(EAX)); - SetJumpTarget(no_overflow); - if (inst.OE) - { - GenerateConstantOverflow(false); - } - SetJumpTarget(end1); - SetJumpTarget(end2); - } - if (inst.Rc) - ComputeRC(gpr.R(d)); - gpr.UnlockAll(); - gpr.UnlockAllX(); + if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) + { + s32 i = gpr.R(a).SImm32(), j = gpr.R(b).SImm32(); + if (j == 0 || (i == (s32)0x80000000 && j == -1)) + { + gpr.SetImmediate32(d, (i >> 31) ^ j); + if (inst.OE) + GenerateConstantOverflow(true); + } + else + { + gpr.SetImmediate32(d, i / j); + if (inst.OE) + GenerateConstantOverflow(false); + } + } + else + { + gpr.Lock(a, b, d); + // no register choice + gpr.FlushLockX(EAX, EDX); + gpr.BindToRegister(d, (d == a || d == b), true); + MOV(32, R(EAX), gpr.R(a)); + CDQ(); + gpr.BindToRegister(b, true, false); + TEST(32, gpr.R(b), gpr.R(b)); + FixupBranch not_div_by_zero = J_CC(CC_NZ); + MOV(32, gpr.R(d), R(EDX)); + if (inst.OE) + { + GenerateConstantOverflow(true); + } + FixupBranch end1 = J(); + SetJumpTarget(not_div_by_zero); + CMP(32, gpr.R(b), R(EDX)); + FixupBranch not_div_by_neg_one = J_CC(CC_NZ); + MOV(32, gpr.R(d), R(EAX)); + NEG(32, gpr.R(d)); + FixupBranch no_overflow = J_CC(CC_NO); + XOR(32, gpr.R(d), gpr.R(d)); + if (inst.OE) + { + GenerateConstantOverflow(true); + } + FixupBranch end2 = J(); + SetJumpTarget(not_div_by_neg_one); + IDIV(32, gpr.R(b)); + MOV(32, gpr.R(d), R(EAX)); + SetJumpTarget(no_overflow); + if (inst.OE) + { + GenerateConstantOverflow(false); + } + SetJumpTarget(end1); + SetJumpTarget(end2); + } + if (inst.Rc) + ComputeRC(gpr.R(d)); + gpr.UnlockAll(); + gpr.UnlockAllX(); } void Jit64::addx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA, b = inst.RB, d = inst.RD; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) - { - s32 i = gpr.R(a).SImm32(), j = gpr.R(b).SImm32(); - gpr.SetImmediate32(d, i + j); - if (inst.OE) - GenerateConstantOverflow((s64)i + (s64)j); - } - else if ((d == a) || (d == b)) - { - int operand = ((d == a) ? b : a); - gpr.Lock(a, b, d); - gpr.BindToRegister(d, true); - ADD(32, gpr.R(d), gpr.R(operand)); - if (inst.OE) - GenerateOverflow(); - } - else if (gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg() && !inst.OE) - { - gpr.Lock(a, b, d); - gpr.BindToRegister(d, false); - LEA(32, gpr.RX(d), MRegSum(gpr.RX(a), gpr.RX(b))); - } - else - { - gpr.Lock(a, b, d); - gpr.BindToRegister(d, false); - MOV(32, gpr.R(d), gpr.R(a)); - ADD(32, gpr.R(d), gpr.R(b)); - if (inst.OE) - GenerateOverflow(); - } - if (inst.Rc) - ComputeRC(gpr.R(d)); - gpr.UnlockAll(); + if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) + { + s32 i = gpr.R(a).SImm32(), j = gpr.R(b).SImm32(); + gpr.SetImmediate32(d, i + j); + if (inst.OE) + GenerateConstantOverflow((s64)i + (s64)j); + } + else if ((d == a) || (d == b)) + { + int operand = ((d == a) ? b : a); + gpr.Lock(a, b, d); + gpr.BindToRegister(d, true); + ADD(32, gpr.R(d), gpr.R(operand)); + if (inst.OE) + GenerateOverflow(); + } + else if (gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg() && !inst.OE) + { + gpr.Lock(a, b, d); + gpr.BindToRegister(d, false); + LEA(32, gpr.RX(d), MRegSum(gpr.RX(a), gpr.RX(b))); + } + else + { + gpr.Lock(a, b, d); + gpr.BindToRegister(d, false); + MOV(32, gpr.R(d), gpr.R(a)); + ADD(32, gpr.R(d), gpr.R(b)); + if (inst.OE) + GenerateOverflow(); + } + if (inst.Rc) + ComputeRC(gpr.R(d)); + gpr.UnlockAll(); } void Jit64::arithXex(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - bool regsource = !(inst.SUBOP10 & 64); // addex or subfex - bool mex = !!(inst.SUBOP10 & 32); // addmex/subfmex or addzex/subfzex - bool add = !!(inst.SUBOP10 & 2); // add or sub - int a = inst.RA; - int b = regsource ? inst.RB : a; - int d = inst.RD; - bool same_input_sub = !add && regsource && a == b; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + bool regsource = !(inst.SUBOP10 & 64); // addex or subfex + bool mex = !!(inst.SUBOP10 & 32); // addmex/subfmex or addzex/subfzex + bool add = !!(inst.SUBOP10 & 2); // add or sub + int a = inst.RA; + int b = regsource ? inst.RB : a; + int d = inst.RD; + bool same_input_sub = !add && regsource && a == b; - gpr.Lock(a, b, d); - gpr.BindToRegister(d, !same_input_sub && (d == a || d == b)); - if (!js.carryFlagSet) - JitGetAndClearCAOV(inst.OE); - else - UnlockFlags(); + gpr.Lock(a, b, d); + gpr.BindToRegister(d, !same_input_sub && (d == a || d == b)); + if (!js.carryFlagSet) + JitGetAndClearCAOV(inst.OE); + else + UnlockFlags(); - bool invertedCarry = false; - // Special case: subfe A, B, B is a common compiler idiom - if (same_input_sub) - { - // Convert carry to borrow - if (!js.carryFlagInverted) - CMC(); - SBB(32, gpr.R(d), gpr.R(d)); - invertedCarry = true; - } - else if (!add && regsource && d == b) - { - if (!js.carryFlagInverted) - CMC(); - if (d != b) - MOV(32, gpr.R(d), gpr.R(b)); - SBB(32, gpr.R(d), gpr.R(a)); - invertedCarry = true; - } - else - { - OpArg source = regsource ? gpr.R(d == b ? a : b) : Imm32(mex ? 0xFFFFFFFF : 0); - if (d != a && d != b) - MOV(32, gpr.R(d), gpr.R(a)); - if (!add) - NOT(32, gpr.R(d)); - // if the source is an immediate, we can invert carry by going from add -> sub and doing src = -1 - src - if (js.carryFlagInverted && source.IsImm()) - { - source = Imm32(-1 - source.SImm32()); - SBB(32, gpr.R(d), source); - invertedCarry = true; - } - else - { - if (js.carryFlagInverted) - CMC(); - ADC(32, gpr.R(d), source); - } - } - FinalizeCarryOverflow(inst.OE, invertedCarry); - if (inst.Rc) - ComputeRC(gpr.R(d)); - gpr.UnlockAll(); + bool invertedCarry = false; + // Special case: subfe A, B, B is a common compiler idiom + if (same_input_sub) + { + // Convert carry to borrow + if (!js.carryFlagInverted) + CMC(); + SBB(32, gpr.R(d), gpr.R(d)); + invertedCarry = true; + } + else if (!add && regsource && d == b) + { + if (!js.carryFlagInverted) + CMC(); + if (d != b) + MOV(32, gpr.R(d), gpr.R(b)); + SBB(32, gpr.R(d), gpr.R(a)); + invertedCarry = true; + } + else + { + OpArg source = regsource ? gpr.R(d == b ? a : b) : Imm32(mex ? 0xFFFFFFFF : 0); + if (d != a && d != b) + MOV(32, gpr.R(d), gpr.R(a)); + if (!add) + NOT(32, gpr.R(d)); + // if the source is an immediate, we can invert carry by going from add -> sub and doing src = + // -1 - src + if (js.carryFlagInverted && source.IsImm()) + { + source = Imm32(-1 - source.SImm32()); + SBB(32, gpr.R(d), source); + invertedCarry = true; + } + else + { + if (js.carryFlagInverted) + CMC(); + ADC(32, gpr.R(d), source); + } + } + FinalizeCarryOverflow(inst.OE, invertedCarry); + if (inst.Rc) + ComputeRC(gpr.R(d)); + gpr.UnlockAll(); } void Jit64::arithcx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - bool add = !!(inst.SUBOP10 & 2); // add or sub - int a = inst.RA, b = inst.RB, d = inst.RD; - gpr.Lock(a, b, d); - gpr.BindToRegister(d, d == a || d == b, true); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + bool add = !!(inst.SUBOP10 & 2); // add or sub + int a = inst.RA, b = inst.RB, d = inst.RD; + gpr.Lock(a, b, d); + gpr.BindToRegister(d, d == a || d == b, true); - if (d == a && d != b) - { - if (add) - { - ADD(32, gpr.R(d), gpr.R(b)); - } - else - { - // special case, because sub isn't reversible - MOV(32, R(RSCRATCH), gpr.R(a)); - MOV(32, gpr.R(d), gpr.R(b)); - SUB(32, gpr.R(d), R(RSCRATCH)); - } - } - else - { - if (d != b) - MOV(32, gpr.R(d), gpr.R(b)); - if (add) - ADD(32, gpr.R(d), gpr.R(a)); - else - SUB(32, gpr.R(d), gpr.R(a)); - } + if (d == a && d != b) + { + if (add) + { + ADD(32, gpr.R(d), gpr.R(b)); + } + else + { + // special case, because sub isn't reversible + MOV(32, R(RSCRATCH), gpr.R(a)); + MOV(32, gpr.R(d), gpr.R(b)); + SUB(32, gpr.R(d), R(RSCRATCH)); + } + } + else + { + if (d != b) + MOV(32, gpr.R(d), gpr.R(b)); + if (add) + ADD(32, gpr.R(d), gpr.R(a)); + else + SUB(32, gpr.R(d), gpr.R(a)); + } - FinalizeCarryOverflow(inst.OE, !add); - if (inst.Rc) - ComputeRC(gpr.R(d)); - gpr.UnlockAll(); + FinalizeCarryOverflow(inst.OE, !add); + if (inst.Rc) + ComputeRC(gpr.R(d)); + gpr.UnlockAll(); } void Jit64::rlwinmx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA; - int s = inst.RS; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA; + int s = inst.RS; - if (gpr.R(s).IsImm()) - { - u32 result = gpr.R(s).Imm32(); - if (inst.SH != 0) - result = _rotl(result, inst.SH); - result &= Helper_Mask(inst.MB, inst.ME); - gpr.SetImmediate32(a, result); - if (inst.Rc) - ComputeRC(gpr.R(a)); - } - else - { - bool left_shift = inst.SH && inst.MB == 0 && inst.ME == 31 - inst.SH; - bool right_shift = inst.SH && inst.ME == 31 && inst.MB == 32 - inst.SH; - u32 mask = Helper_Mask(inst.MB, inst.ME); - bool simple_mask = mask == 0xff || mask == 0xffff; - // In case of a merged branch, track whether or not we've set flags. - // If not, we need to do a test later to get them. - bool needs_test = true; - // If we know the high bit can't be set, we can avoid doing a sign extend for flag storage. - bool needs_sext = true; - int mask_size = inst.ME - inst.MB + 1; + if (gpr.R(s).IsImm()) + { + u32 result = gpr.R(s).Imm32(); + if (inst.SH != 0) + result = _rotl(result, inst.SH); + result &= Helper_Mask(inst.MB, inst.ME); + gpr.SetImmediate32(a, result); + if (inst.Rc) + ComputeRC(gpr.R(a)); + } + else + { + bool left_shift = inst.SH && inst.MB == 0 && inst.ME == 31 - inst.SH; + bool right_shift = inst.SH && inst.ME == 31 && inst.MB == 32 - inst.SH; + u32 mask = Helper_Mask(inst.MB, inst.ME); + bool simple_mask = mask == 0xff || mask == 0xffff; + // In case of a merged branch, track whether or not we've set flags. + // If not, we need to do a test later to get them. + bool needs_test = true; + // If we know the high bit can't be set, we can avoid doing a sign extend for flag storage. + bool needs_sext = true; + int mask_size = inst.ME - inst.MB + 1; - gpr.Lock(a, s); - gpr.BindToRegister(a, a == s); - if (a != s && left_shift && gpr.R(s).IsSimpleReg() && inst.SH <= 3) - { - LEA(32, gpr.RX(a), MScaled(gpr.RX(s), SCALE_1 << inst.SH, 0)); - } - // common optimized case: byte/word extract - else if (simple_mask && !(inst.SH & (mask_size - 1))) - { - MOVZX(32, mask_size, gpr.RX(a), ExtractFromReg(s, inst.SH ? (32 - inst.SH) >> 3 : 0)); - needs_sext = false; - } - // another optimized special case: byte/word extract plus shift - else if (((mask >> inst.SH) << inst.SH) == mask && !left_shift && - ((mask >> inst.SH) == 0xff || (mask >> inst.SH) == 0xffff)) - { - MOVZX(32, mask_size, gpr.RX(a), gpr.R(s)); - SHL(32, gpr.R(a), Imm8(inst.SH)); - needs_sext = inst.SH + mask_size >= 32; - } - else - { - if (a != s) - MOV(32, gpr.R(a), gpr.R(s)); + gpr.Lock(a, s); + gpr.BindToRegister(a, a == s); + if (a != s && left_shift && gpr.R(s).IsSimpleReg() && inst.SH <= 3) + { + LEA(32, gpr.RX(a), MScaled(gpr.RX(s), SCALE_1 << inst.SH, 0)); + } + // common optimized case: byte/word extract + else if (simple_mask && !(inst.SH & (mask_size - 1))) + { + MOVZX(32, mask_size, gpr.RX(a), ExtractFromReg(s, inst.SH ? (32 - inst.SH) >> 3 : 0)); + needs_sext = false; + } + // another optimized special case: byte/word extract plus shift + else if (((mask >> inst.SH) << inst.SH) == mask && !left_shift && + ((mask >> inst.SH) == 0xff || (mask >> inst.SH) == 0xffff)) + { + MOVZX(32, mask_size, gpr.RX(a), gpr.R(s)); + SHL(32, gpr.R(a), Imm8(inst.SH)); + needs_sext = inst.SH + mask_size >= 32; + } + else + { + if (a != s) + MOV(32, gpr.R(a), gpr.R(s)); - if (left_shift) - { - SHL(32, gpr.R(a), Imm8(inst.SH)); - } - else if (right_shift) - { - SHR(32, gpr.R(a), Imm8(inst.MB)); - needs_sext = false; - } - else - { - if (inst.SH != 0) - ROL(32, gpr.R(a), Imm8(inst.SH)); - if (!(inst.MB == 0 && inst.ME == 31)) - { - // we need flags if we're merging the branch - if (inst.Rc && CheckMergedBranch(0)) - AND(32, gpr.R(a), Imm32(mask)); - else - AndWithMask(gpr.RX(a), mask); - needs_sext = inst.MB == 0; - needs_test = false; - } - } - } - if (inst.Rc) - ComputeRC(gpr.R(a), needs_test, needs_sext); - gpr.UnlockAll(); - } + if (left_shift) + { + SHL(32, gpr.R(a), Imm8(inst.SH)); + } + else if (right_shift) + { + SHR(32, gpr.R(a), Imm8(inst.MB)); + needs_sext = false; + } + else + { + if (inst.SH != 0) + ROL(32, gpr.R(a), Imm8(inst.SH)); + if (!(inst.MB == 0 && inst.ME == 31)) + { + // we need flags if we're merging the branch + if (inst.Rc && CheckMergedBranch(0)) + AND(32, gpr.R(a), Imm32(mask)); + else + AndWithMask(gpr.RX(a), mask); + needs_sext = inst.MB == 0; + needs_test = false; + } + } + } + if (inst.Rc) + ComputeRC(gpr.R(a), needs_test, needs_sext); + gpr.UnlockAll(); + } } - void Jit64::rlwimix(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA; - int s = inst.RS; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA; + int s = inst.RS; - if (gpr.R(a).IsImm() && gpr.R(s).IsImm()) - { - u32 mask = Helper_Mask(inst.MB,inst.ME); - gpr.SetImmediate32(a, (gpr.R(a).Imm32() & ~mask) | (_rotl(gpr.R(s).Imm32(),inst.SH) & mask)); - if (inst.Rc) - ComputeRC(gpr.R(a)); - } - else - { - gpr.Lock(a, s); - u32 mask = Helper_Mask(inst.MB, inst.ME); - bool needs_test = false; - if (mask == 0 || (a == s && inst.SH == 0)) - { - needs_test = true; - } - else if (mask == 0xFFFFFFFF) - { - gpr.BindToRegister(a, a == s, true); - if (a != s) - MOV(32, gpr.R(a), gpr.R(s)); - if (inst.SH) - ROL(32, gpr.R(a), Imm8(inst.SH)); - needs_test = true; - } - else if(gpr.R(s).IsImm()) - { - gpr.BindToRegister(a, true, true); - AndWithMask(gpr.RX(a), ~mask); - OR(32, gpr.R(a), Imm32(_rotl(gpr.R(s).Imm32(), inst.SH) & mask)); - } - else if (inst.SH) - { - bool isLeftShift = mask == 0U - (1U << inst.SH); - bool isRightShift = mask == (1U << inst.SH) - 1; - if (gpr.R(a).IsImm()) - { - u32 maskA = gpr.R(a).Imm32() & ~mask; - gpr.BindToRegister(a, false, true); - MOV(32, gpr.R(a), gpr.R(s)); - if (isLeftShift) - { - SHL(32, gpr.R(a), Imm8(inst.SH)); - } - else if (isRightShift) - { - SHR(32, gpr.R(a), Imm8(32 - inst.SH)); - } - else - { - ROL(32, gpr.R(a), Imm8(inst.SH)); - AND(32, gpr.R(a), Imm32(mask)); - } - OR(32, gpr.R(a), Imm32(maskA)); - } - else - { - // TODO: common cases of this might be faster with pinsrb or abuse of AH - gpr.BindToRegister(a, true, true); - MOV(32, R(RSCRATCH), gpr.R(s)); - if (isLeftShift) - { - SHL(32, R(RSCRATCH), Imm8(inst.SH)); - AndWithMask(gpr.RX(a), ~mask); - OR(32, gpr.R(a), R(RSCRATCH)); - } - else if (isRightShift) - { - SHR(32, R(RSCRATCH), Imm8(32 - inst.SH)); - AndWithMask(gpr.RX(a), ~mask); - OR(32, gpr.R(a), R(RSCRATCH)); - } - else - { - ROL(32, R(RSCRATCH), Imm8(inst.SH)); - XOR(32, R(RSCRATCH), gpr.R(a)); - AndWithMask(RSCRATCH, mask); - XOR(32, gpr.R(a), R(RSCRATCH)); - } - } - } - else - { - gpr.BindToRegister(a, true, true); - XOR(32, gpr.R(a), gpr.R(s)); - AndWithMask(gpr.RX(a), ~mask); - XOR(32, gpr.R(a), gpr.R(s)); - } - if (inst.Rc) - ComputeRC(gpr.R(a), needs_test); - gpr.UnlockAll(); - } + if (gpr.R(a).IsImm() && gpr.R(s).IsImm()) + { + u32 mask = Helper_Mask(inst.MB, inst.ME); + gpr.SetImmediate32(a, (gpr.R(a).Imm32() & ~mask) | (_rotl(gpr.R(s).Imm32(), inst.SH) & mask)); + if (inst.Rc) + ComputeRC(gpr.R(a)); + } + else + { + gpr.Lock(a, s); + u32 mask = Helper_Mask(inst.MB, inst.ME); + bool needs_test = false; + if (mask == 0 || (a == s && inst.SH == 0)) + { + needs_test = true; + } + else if (mask == 0xFFFFFFFF) + { + gpr.BindToRegister(a, a == s, true); + if (a != s) + MOV(32, gpr.R(a), gpr.R(s)); + if (inst.SH) + ROL(32, gpr.R(a), Imm8(inst.SH)); + needs_test = true; + } + else if (gpr.R(s).IsImm()) + { + gpr.BindToRegister(a, true, true); + AndWithMask(gpr.RX(a), ~mask); + OR(32, gpr.R(a), Imm32(_rotl(gpr.R(s).Imm32(), inst.SH) & mask)); + } + else if (inst.SH) + { + bool isLeftShift = mask == 0U - (1U << inst.SH); + bool isRightShift = mask == (1U << inst.SH) - 1; + if (gpr.R(a).IsImm()) + { + u32 maskA = gpr.R(a).Imm32() & ~mask; + gpr.BindToRegister(a, false, true); + MOV(32, gpr.R(a), gpr.R(s)); + if (isLeftShift) + { + SHL(32, gpr.R(a), Imm8(inst.SH)); + } + else if (isRightShift) + { + SHR(32, gpr.R(a), Imm8(32 - inst.SH)); + } + else + { + ROL(32, gpr.R(a), Imm8(inst.SH)); + AND(32, gpr.R(a), Imm32(mask)); + } + OR(32, gpr.R(a), Imm32(maskA)); + } + else + { + // TODO: common cases of this might be faster with pinsrb or abuse of AH + gpr.BindToRegister(a, true, true); + MOV(32, R(RSCRATCH), gpr.R(s)); + if (isLeftShift) + { + SHL(32, R(RSCRATCH), Imm8(inst.SH)); + AndWithMask(gpr.RX(a), ~mask); + OR(32, gpr.R(a), R(RSCRATCH)); + } + else if (isRightShift) + { + SHR(32, R(RSCRATCH), Imm8(32 - inst.SH)); + AndWithMask(gpr.RX(a), ~mask); + OR(32, gpr.R(a), R(RSCRATCH)); + } + else + { + ROL(32, R(RSCRATCH), Imm8(inst.SH)); + XOR(32, R(RSCRATCH), gpr.R(a)); + AndWithMask(RSCRATCH, mask); + XOR(32, gpr.R(a), R(RSCRATCH)); + } + } + } + else + { + gpr.BindToRegister(a, true, true); + XOR(32, gpr.R(a), gpr.R(s)); + AndWithMask(gpr.RX(a), ~mask); + XOR(32, gpr.R(a), gpr.R(s)); + } + if (inst.Rc) + ComputeRC(gpr.R(a), needs_test); + gpr.UnlockAll(); + } } void Jit64::rlwnmx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA, b = inst.RB, s = inst.RS; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA, b = inst.RB, s = inst.RS; - u32 mask = Helper_Mask(inst.MB, inst.ME); - if (gpr.R(b).IsImm() && gpr.R(s).IsImm()) - { - gpr.SetImmediate32(a, _rotl(gpr.R(s).Imm32(), gpr.R(b).Imm32() & 0x1F) & mask); - } - else - { - // no register choice - gpr.FlushLockX(ECX); - gpr.Lock(a, b, s); - MOV(32, R(ECX), gpr.R(b)); - gpr.BindToRegister(a, (a == s), true); - if (a != s) - { - MOV(32, gpr.R(a), gpr.R(s)); - } - ROL(32, gpr.R(a), R(ECX)); - // we need flags if we're merging the branch - if (inst.Rc && CheckMergedBranch(0)) - AND(32, gpr.R(a), Imm32(mask)); - else - AndWithMask(gpr.RX(a), mask); - } - if (inst.Rc) - ComputeRC(gpr.R(a), false); - gpr.UnlockAll(); - gpr.UnlockAllX(); + u32 mask = Helper_Mask(inst.MB, inst.ME); + if (gpr.R(b).IsImm() && gpr.R(s).IsImm()) + { + gpr.SetImmediate32(a, _rotl(gpr.R(s).Imm32(), gpr.R(b).Imm32() & 0x1F) & mask); + } + else + { + // no register choice + gpr.FlushLockX(ECX); + gpr.Lock(a, b, s); + MOV(32, R(ECX), gpr.R(b)); + gpr.BindToRegister(a, (a == s), true); + if (a != s) + { + MOV(32, gpr.R(a), gpr.R(s)); + } + ROL(32, gpr.R(a), R(ECX)); + // we need flags if we're merging the branch + if (inst.Rc && CheckMergedBranch(0)) + AND(32, gpr.R(a), Imm32(mask)); + else + AndWithMask(gpr.RX(a), mask); + } + if (inst.Rc) + ComputeRC(gpr.R(a), false); + gpr.UnlockAll(); + gpr.UnlockAllX(); } void Jit64::negx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA; - int d = inst.RD; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA; + int d = inst.RD; - if (gpr.R(a).IsImm()) - { - gpr.SetImmediate32(d, ~(gpr.R(a).Imm32()) + 1); - if (inst.OE) - GenerateConstantOverflow(gpr.R(d).Imm32() == 0x80000000); - } - else - { - gpr.Lock(a, d); - gpr.BindToRegister(d, a == d, true); - if (a != d) - MOV(32, gpr.R(d), gpr.R(a)); - NEG(32, gpr.R(d)); - if (inst.OE) - GenerateOverflow(); - } - if (inst.Rc) - ComputeRC(gpr.R(d), false); - gpr.UnlockAll(); + if (gpr.R(a).IsImm()) + { + gpr.SetImmediate32(d, ~(gpr.R(a).Imm32()) + 1); + if (inst.OE) + GenerateConstantOverflow(gpr.R(d).Imm32() == 0x80000000); + } + else + { + gpr.Lock(a, d); + gpr.BindToRegister(d, a == d, true); + if (a != d) + MOV(32, gpr.R(d), gpr.R(a)); + NEG(32, gpr.R(d)); + if (inst.OE) + GenerateOverflow(); + } + if (inst.Rc) + ComputeRC(gpr.R(d), false); + gpr.UnlockAll(); } void Jit64::srwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA; - int b = inst.RB; - int s = inst.RS; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA; + int b = inst.RB; + int s = inst.RS; - if (gpr.R(b).IsImm() && gpr.R(s).IsImm()) - { - u32 amount = gpr.R(b).Imm32(); - gpr.SetImmediate32(a, (amount & 0x20) ? 0 : (gpr.R(s).Imm32() >> (amount & 0x1f))); - } - else - { - // no register choice - gpr.FlushLockX(ECX); - gpr.Lock(a, b, s); - MOV(32, R(ECX), gpr.R(b)); - gpr.BindToRegister(a, a == s, true); - if (a != s) - { - MOV(32, gpr.R(a), gpr.R(s)); - } - SHR(64, gpr.R(a), R(ECX)); - } - // Shift of 0 doesn't update flags, so we need to test just in case - if (inst.Rc) - ComputeRC(gpr.R(a)); - gpr.UnlockAll(); - gpr.UnlockAllX(); + if (gpr.R(b).IsImm() && gpr.R(s).IsImm()) + { + u32 amount = gpr.R(b).Imm32(); + gpr.SetImmediate32(a, (amount & 0x20) ? 0 : (gpr.R(s).Imm32() >> (amount & 0x1f))); + } + else + { + // no register choice + gpr.FlushLockX(ECX); + gpr.Lock(a, b, s); + MOV(32, R(ECX), gpr.R(b)); + gpr.BindToRegister(a, a == s, true); + if (a != s) + { + MOV(32, gpr.R(a), gpr.R(s)); + } + SHR(64, gpr.R(a), R(ECX)); + } + // Shift of 0 doesn't update flags, so we need to test just in case + if (inst.Rc) + ComputeRC(gpr.R(a)); + gpr.UnlockAll(); + gpr.UnlockAllX(); } void Jit64::slwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA; - int b = inst.RB; - int s = inst.RS; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA; + int b = inst.RB; + int s = inst.RS; - if (gpr.R(b).IsImm() && gpr.R(s).IsImm()) - { - u32 amount = gpr.R(b).Imm32(); - gpr.SetImmediate32(a, (amount & 0x20) ? 0 : gpr.R(s).Imm32() << (amount & 0x1f)); - if (inst.Rc) - ComputeRC(gpr.R(a)); - } - else - { - // no register choice - gpr.FlushLockX(ECX); - gpr.Lock(a, b, s); - MOV(32, R(ECX), gpr.R(b)); - gpr.BindToRegister(a, a == s, true); - if (a != s) - MOV(32, gpr.R(a), gpr.R(s)); - SHL(64, gpr.R(a), R(ECX)); - if (inst.Rc) - { - AND(32, gpr.R(a), gpr.R(a)); - ComputeRC(gpr.R(a), false); - } - else - { - MOVZX(64, 32, gpr.RX(a), gpr.R(a)); - } - gpr.UnlockAll(); - gpr.UnlockAllX(); - } + if (gpr.R(b).IsImm() && gpr.R(s).IsImm()) + { + u32 amount = gpr.R(b).Imm32(); + gpr.SetImmediate32(a, (amount & 0x20) ? 0 : gpr.R(s).Imm32() << (amount & 0x1f)); + if (inst.Rc) + ComputeRC(gpr.R(a)); + } + else + { + // no register choice + gpr.FlushLockX(ECX); + gpr.Lock(a, b, s); + MOV(32, R(ECX), gpr.R(b)); + gpr.BindToRegister(a, a == s, true); + if (a != s) + MOV(32, gpr.R(a), gpr.R(s)); + SHL(64, gpr.R(a), R(ECX)); + if (inst.Rc) + { + AND(32, gpr.R(a), gpr.R(a)); + ComputeRC(gpr.R(a), false); + } + else + { + MOVZX(64, 32, gpr.RX(a), gpr.R(a)); + } + gpr.UnlockAll(); + gpr.UnlockAllX(); + } } void Jit64::srawx(UGeckoInstruction inst) { - // USES_XER - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA; - int b = inst.RB; - int s = inst.RS; + // USES_XER + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA; + int b = inst.RB; + int s = inst.RS; - gpr.FlushLockX(ECX); - gpr.Lock(a, s, b); - gpr.BindToRegister(a, (a == s || a == b), true); - MOV(32, R(ECX), gpr.R(b)); - if (a != s) - MOV(32, gpr.R(a), gpr.R(s)); - SHL(64, gpr.R(a), Imm8(32)); - SAR(64, gpr.R(a), R(ECX)); - if (js.op->wantsCA) - { - MOV(32, R(RSCRATCH), gpr.R(a)); - SHR(64, gpr.R(a), Imm8(32)); - TEST(32, gpr.R(a), R(RSCRATCH)); - } - else - { - SHR(64, gpr.R(a), Imm8(32)); - } - FinalizeCarry(CC_NZ); - if (inst.Rc) - ComputeRC(gpr.R(a)); - gpr.UnlockAll(); - gpr.UnlockAllX(); + gpr.FlushLockX(ECX); + gpr.Lock(a, s, b); + gpr.BindToRegister(a, (a == s || a == b), true); + MOV(32, R(ECX), gpr.R(b)); + if (a != s) + MOV(32, gpr.R(a), gpr.R(s)); + SHL(64, gpr.R(a), Imm8(32)); + SAR(64, gpr.R(a), R(ECX)); + if (js.op->wantsCA) + { + MOV(32, R(RSCRATCH), gpr.R(a)); + SHR(64, gpr.R(a), Imm8(32)); + TEST(32, gpr.R(a), R(RSCRATCH)); + } + else + { + SHR(64, gpr.R(a), Imm8(32)); + } + FinalizeCarry(CC_NZ); + if (inst.Rc) + ComputeRC(gpr.R(a)); + gpr.UnlockAll(); + gpr.UnlockAllX(); } void Jit64::srawix(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA; - int s = inst.RS; - int amount = inst.SH; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA; + int s = inst.RS; + int amount = inst.SH; - if (amount != 0) - { - gpr.Lock(a, s); - gpr.BindToRegister(a, a == s, true); - if (!js.op->wantsCA) - { - if (a != s) - MOV(32, gpr.R(a), gpr.R(s)); - SAR(32, gpr.R(a), Imm8(amount)); - } - else - { - MOV(32, R(RSCRATCH), gpr.R(s)); - if (a != s) - MOV(32, gpr.R(a), R(RSCRATCH)); - // some optimized common cases that can be done in slightly fewer ops - if (amount == 1) - { - SHR(32, R(RSCRATCH), Imm8(31)); // sign - AND(32, R(RSCRATCH), gpr.R(a)); // (sign && carry) - SAR(32, gpr.R(a), Imm8(1)); - MOV(8, PPCSTATE(xer_ca), R(RSCRATCH)); // XER.CA = sign && carry, aka (input&0x80000001) == 0x80000001 - } - else - { - SAR(32, gpr.R(a), Imm8(amount)); - SHL(32, R(RSCRATCH), Imm8(32 - amount)); - TEST(32, R(RSCRATCH), gpr.R(a)); - FinalizeCarry(CC_NZ); - } - } - } - else - { - gpr.Lock(a, s); - FinalizeCarry(false); - gpr.BindToRegister(a, a == s, true); + if (amount != 0) + { + gpr.Lock(a, s); + gpr.BindToRegister(a, a == s, true); + if (!js.op->wantsCA) + { + if (a != s) + MOV(32, gpr.R(a), gpr.R(s)); + SAR(32, gpr.R(a), Imm8(amount)); + } + else + { + MOV(32, R(RSCRATCH), gpr.R(s)); + if (a != s) + MOV(32, gpr.R(a), R(RSCRATCH)); + // some optimized common cases that can be done in slightly fewer ops + if (amount == 1) + { + SHR(32, R(RSCRATCH), Imm8(31)); // sign + AND(32, R(RSCRATCH), gpr.R(a)); // (sign && carry) + SAR(32, gpr.R(a), Imm8(1)); + MOV(8, PPCSTATE(xer_ca), + R(RSCRATCH)); // XER.CA = sign && carry, aka (input&0x80000001) == 0x80000001 + } + else + { + SAR(32, gpr.R(a), Imm8(amount)); + SHL(32, R(RSCRATCH), Imm8(32 - amount)); + TEST(32, R(RSCRATCH), gpr.R(a)); + FinalizeCarry(CC_NZ); + } + } + } + else + { + gpr.Lock(a, s); + FinalizeCarry(false); + gpr.BindToRegister(a, a == s, true); - if (a != s) - MOV(32, gpr.R(a), gpr.R(s)); - } - if (inst.Rc) - ComputeRC(gpr.R(a)); - gpr.UnlockAll(); + if (a != s) + MOV(32, gpr.R(a), gpr.R(s)); + } + if (inst.Rc) + ComputeRC(gpr.R(a)); + gpr.UnlockAll(); } // count leading zeroes void Jit64::cntlzwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA; - int s = inst.RS; - bool needs_test = false; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA; + int s = inst.RS; + bool needs_test = false; - if (gpr.R(s).IsImm()) - { - u32 mask = 0x80000000; - u32 i = 0; - for (; i < 32; i++, mask >>= 1) - { - if (gpr.R(s).Imm32() & mask) - break; - } - gpr.SetImmediate32(a, i); - } - else - { - gpr.Lock(a, s); - gpr.BindToRegister(a, a == s, true); - if (cpu_info.bLZCNT) - { - LZCNT(32, gpr.RX(a), gpr.R(s)); - needs_test = true; - } - else - { - BSR(32, gpr.RX(a), gpr.R(s)); - FixupBranch gotone = J_CC(CC_NZ); - MOV(32, gpr.R(a), Imm32(63)); - SetJumpTarget(gotone); - XOR(32, gpr.R(a), Imm8(0x1f)); // flip order - } - } + if (gpr.R(s).IsImm()) + { + u32 mask = 0x80000000; + u32 i = 0; + for (; i < 32; i++, mask >>= 1) + { + if (gpr.R(s).Imm32() & mask) + break; + } + gpr.SetImmediate32(a, i); + } + else + { + gpr.Lock(a, s); + gpr.BindToRegister(a, a == s, true); + if (cpu_info.bLZCNT) + { + LZCNT(32, gpr.RX(a), gpr.R(s)); + needs_test = true; + } + else + { + BSR(32, gpr.RX(a), gpr.R(s)); + FixupBranch gotone = J_CC(CC_NZ); + MOV(32, gpr.R(a), Imm32(63)); + SetJumpTarget(gotone); + XOR(32, gpr.R(a), Imm8(0x1f)); // flip order + } + } - if (inst.Rc) - ComputeRC(gpr.R(a), needs_test, false); - gpr.UnlockAll(); + if (inst.Rc) + ComputeRC(gpr.R(a), needs_test, false); + gpr.UnlockAll(); } void Jit64::twX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - s32 a = inst.RA; + s32 a = inst.RA; - if (inst.OPCD == 3) // twi - { - gpr.KillImmediate(a, true, false); - CMP(32, gpr.R(a), Imm32((s32)(s16)inst.SIMM_16)); - } - else // tw - { - gpr.BindToRegister(a, true, false); - CMP(32, gpr.R(a), gpr.R(inst.RB)); - } + if (inst.OPCD == 3) // twi + { + gpr.KillImmediate(a, true, false); + CMP(32, gpr.R(a), Imm32((s32)(s16)inst.SIMM_16)); + } + else // tw + { + gpr.BindToRegister(a, true, false); + CMP(32, gpr.R(a), gpr.R(inst.RB)); + } - std::vector fixups; - CCFlags conditions[] = { CC_A, CC_B, CC_E, CC_G, CC_L }; + std::vector fixups; + CCFlags conditions[] = {CC_A, CC_B, CC_E, CC_G, CC_L}; - for (int i = 0; i < 5; i++) - { - if (inst.TO & (1 << i)) - { - FixupBranch f = J_CC(conditions[i], true); - fixups.push_back(f); - } - } - FixupBranch dont_trap = J(); + for (int i = 0; i < 5; i++) + { + if (inst.TO & (1 << i)) + { + FixupBranch f = J_CC(conditions[i], true); + fixups.push_back(f); + } + } + FixupBranch dont_trap = J(); - for (const FixupBranch& fixup : fixups) - { - SetJumpTarget(fixup); - } - LOCK(); - OR(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_PROGRAM)); + for (const FixupBranch& fixup : fixups) + { + SetJumpTarget(fixup); + } + LOCK(); + OR(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_PROGRAM)); - gpr.Flush(FLUSH_MAINTAIN_STATE); - fpr.Flush(FLUSH_MAINTAIN_STATE); + gpr.Flush(FLUSH_MAINTAIN_STATE); + fpr.Flush(FLUSH_MAINTAIN_STATE); - WriteExceptionExit(); + WriteExceptionExit(); - SetJumpTarget(dont_trap); + SetJumpTarget(dont_trap); - if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) - { - gpr.Flush(); - fpr.Flush(); - WriteExit(js.compilerPC + 4); - } + if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) + { + gpr.Flush(); + fpr.Flush(); + WriteExit(js.compilerPC + 4); + } } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp index 37fb86e17b..66ad4da6f1 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp @@ -5,6 +5,7 @@ // TODO(ector): Tons of pshufb optimization of the loads/stores, for SSSE3+, possibly SSE4, only. // Should give a very noticable speed boost to paired single heavy code. +#include "Core/PowerPC/Jit64/Jit.h" #include "Common/BitSet.h" #include "Common/CommonTypes.h" #include "Common/MsgHandler.h" @@ -15,623 +16,631 @@ #include "Core/HW/CPU.h" #include "Core/HW/DSP.h" #include "Core/HW/Memmap.h" -#include "Core/PowerPC/JitInterface.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/Jit64/Jit.h" #include "Core/PowerPC/Jit64/JitRegCache.h" #include "Core/PowerPC/JitCommon/Jit_Util.h" +#include "Core/PowerPC/JitInterface.h" +#include "Core/PowerPC/PowerPC.h" using namespace Gen; void Jit64::lXXx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); - int a = inst.RA, b = inst.RB, d = inst.RD; + int a = inst.RA, b = inst.RB, d = inst.RD; - // Skip disabled JIT instructions - FALLBACK_IF(SConfig::GetInstance().bJITLoadStorelbzxOff && (inst.OPCD == 31) && (inst.SUBOP10 == 87)); - FALLBACK_IF(SConfig::GetInstance().bJITLoadStorelXzOff && ((inst.OPCD == 34) || (inst.OPCD == 40) || (inst.OPCD == 32))); - FALLBACK_IF(SConfig::GetInstance().bJITLoadStorelwzOff && (inst.OPCD == 32)); + // Skip disabled JIT instructions + FALLBACK_IF(SConfig::GetInstance().bJITLoadStorelbzxOff && (inst.OPCD == 31) && + (inst.SUBOP10 == 87)); + FALLBACK_IF(SConfig::GetInstance().bJITLoadStorelXzOff && + ((inst.OPCD == 34) || (inst.OPCD == 40) || (inst.OPCD == 32))); + FALLBACK_IF(SConfig::GetInstance().bJITLoadStorelwzOff && (inst.OPCD == 32)); - // Determine memory access size and sign extend - int accessSize = 0; - bool signExtend = false; - bool byte_reversed = false; - switch (inst.OPCD) - { - case 32: // lwz - case 33: // lwzu - accessSize = 32; - signExtend = false; - break; + // Determine memory access size and sign extend + int accessSize = 0; + bool signExtend = false; + bool byte_reversed = false; + switch (inst.OPCD) + { + case 32: // lwz + case 33: // lwzu + accessSize = 32; + signExtend = false; + break; - case 34: // lbz - case 35: // lbzu - accessSize = 8; - signExtend = false; - break; + case 34: // lbz + case 35: // lbzu + accessSize = 8; + signExtend = false; + break; - case 40: // lhz - case 41: // lhzu - accessSize = 16; - signExtend = false; - break; + case 40: // lhz + case 41: // lhzu + accessSize = 16; + signExtend = false; + break; - case 42: // lha - case 43: // lhau - accessSize = 16; - signExtend = true; - break; + case 42: // lha + case 43: // lhau + accessSize = 16; + signExtend = true; + break; - case 31: - switch (inst.SUBOP10) - { - case 534: // lwbrx - byte_reversed = true; - case 23: // lwzx - case 55: // lwzux - accessSize = 32; - signExtend = false; - break; + case 31: + switch (inst.SUBOP10) + { + case 534: // lwbrx + byte_reversed = true; + case 23: // lwzx + case 55: // lwzux + accessSize = 32; + signExtend = false; + break; - case 87: // lbzx - case 119: // lbzux - accessSize = 8; - signExtend = false; - break; - case 790: // lhbrx - byte_reversed = true; - case 279: // lhzx - case 311: // lhzux - accessSize = 16; - signExtend = false; - break; + case 87: // lbzx + case 119: // lbzux + accessSize = 8; + signExtend = false; + break; + case 790: // lhbrx + byte_reversed = true; + case 279: // lhzx + case 311: // lhzux + accessSize = 16; + signExtend = false; + break; - case 343: // lhax - case 375: // lhaux - accessSize = 16; - signExtend = true; - break; + case 343: // lhax + case 375: // lhaux + accessSize = 16; + signExtend = true; + break; - default: - PanicAlert("Invalid instruction"); - } - break; + default: + PanicAlert("Invalid instruction"); + } + break; - default: - PanicAlert("Invalid instruction"); - } + default: + PanicAlert("Invalid instruction"); + } - // PowerPC has no 8-bit sign extended load, but x86 does, so merge extsb with the load if we find it. - if (MergeAllowedNextInstructions(1) && accessSize == 8 && js.op[1].inst.OPCD == 31 && js.op[1].inst.SUBOP10 == 954 && - js.op[1].inst.RS == inst.RD && js.op[1].inst.RA == inst.RD && !js.op[1].inst.Rc) - { - js.downcountAmount++; - js.skipInstructions = 1; - signExtend = true; - } + // PowerPC has no 8-bit sign extended load, but x86 does, so merge extsb with the load if we find + // it. + if (MergeAllowedNextInstructions(1) && accessSize == 8 && js.op[1].inst.OPCD == 31 && + js.op[1].inst.SUBOP10 == 954 && js.op[1].inst.RS == inst.RD && js.op[1].inst.RA == inst.RD && + !js.op[1].inst.Rc) + { + js.downcountAmount++; + js.skipInstructions = 1; + signExtend = true; + } - // TODO(ector): Make it dynamically enable/disable idle skipping where appropriate - // Will give nice boost to dual core mode - // (mb2): I agree, - // IMHO those Idles should always be skipped and replaced by a more controllable "native" Idle methode - // ... maybe the throttle one already do that :p - // TODO: We shouldn't use a debug read here. It should be possible to get - // the following instructions out of the JIT state. - if (SConfig::GetInstance().bSkipIdle && - CPU::GetState() != CPU::CPU_STEPPING && - inst.OPCD == 32 && - MergeAllowedNextInstructions(2) && - (inst.hex & 0xFFFF0000) == 0x800D0000 && - (js.op[1].inst.hex == 0x28000000 || - (SConfig::GetInstance().bWii && js.op[1].inst.hex == 0x2C000000)) && - js.op[2].inst.hex == 0x4182fff8) - { - // TODO(LinesPrower): - // - Rewrite this! - // It seems to be ugly and inefficient, but I don't know JIT stuff enough to make it right - // It only demonstrates the idea + // TODO(ector): Make it dynamically enable/disable idle skipping where appropriate + // Will give nice boost to dual core mode + // (mb2): I agree, + // IMHO those Idles should always be skipped and replaced by a more controllable "native" Idle + // methode + // ... maybe the throttle one already do that :p + // TODO: We shouldn't use a debug read here. It should be possible to get + // the following instructions out of the JIT state. + if (SConfig::GetInstance().bSkipIdle && CPU::GetState() != CPU::CPU_STEPPING && inst.OPCD == 32 && + MergeAllowedNextInstructions(2) && (inst.hex & 0xFFFF0000) == 0x800D0000 && + (js.op[1].inst.hex == 0x28000000 || + (SConfig::GetInstance().bWii && js.op[1].inst.hex == 0x2C000000)) && + js.op[2].inst.hex == 0x4182fff8) + { + // TODO(LinesPrower): + // - Rewrite this! + // It seems to be ugly and inefficient, but I don't know JIT stuff enough to make it right + // It only demonstrates the idea - // do our job at first - s32 offset = (s32)(s16)inst.SIMM_16; - gpr.BindToRegister(a, true, false); - gpr.BindToRegister(d, false, true); - SafeLoadToReg(gpr.RX(d), gpr.R(a), accessSize, offset, CallerSavedRegistersInUse(), signExtend); + // do our job at first + s32 offset = (s32)(s16)inst.SIMM_16; + gpr.BindToRegister(a, true, false); + gpr.BindToRegister(d, false, true); + SafeLoadToReg(gpr.RX(d), gpr.R(a), accessSize, offset, CallerSavedRegistersInUse(), signExtend); - // if it's still 0, we can wait until the next event - TEST(32, gpr.R(d), gpr.R(d)); - FixupBranch noIdle = J_CC(CC_NZ); + // if it's still 0, we can wait until the next event + TEST(32, gpr.R(d), gpr.R(d)); + FixupBranch noIdle = J_CC(CC_NZ); - BitSet32 registersInUse = CallerSavedRegistersInUse(); - ABI_PushRegistersAndAdjustStack(registersInUse, 0); + BitSet32 registersInUse = CallerSavedRegistersInUse(); + ABI_PushRegistersAndAdjustStack(registersInUse, 0); - ABI_CallFunction((void *)&CoreTiming::Idle); + ABI_CallFunction((void*)&CoreTiming::Idle); - ABI_PopRegistersAndAdjustStack(registersInUse, 0); + ABI_PopRegistersAndAdjustStack(registersInUse, 0); - // ! we must continue executing of the loop after exception handling, maybe there is still 0 in r0 - //MOV(32, PPCSTATE(pc), Imm32(js.compilerPC)); - WriteExceptionExit(); + // ! we must continue executing of the loop after exception handling, maybe there is still 0 in + // r0 + // MOV(32, PPCSTATE(pc), Imm32(js.compilerPC)); + WriteExceptionExit(); - SetJumpTarget(noIdle); + SetJumpTarget(noIdle); - //js.compilerPC += 8; - return; - } + // js.compilerPC += 8; + return; + } - // Determine whether this instruction updates inst.RA - bool update; - if (inst.OPCD == 31) - update = ((inst.SUBOP10 & 0x20) != 0) && (!gpr.R(b).IsImm() || gpr.R(b).Imm32() != 0); - else - update = ((inst.OPCD & 1) != 0) && inst.SIMM_16 != 0; + // Determine whether this instruction updates inst.RA + bool update; + if (inst.OPCD == 31) + update = ((inst.SUBOP10 & 0x20) != 0) && (!gpr.R(b).IsImm() || gpr.R(b).Imm32() != 0); + else + update = ((inst.OPCD & 1) != 0) && inst.SIMM_16 != 0; - bool storeAddress = false; - s32 loadOffset = 0; + bool storeAddress = false; + s32 loadOffset = 0; - // Prepare address operand - OpArg opAddress; - if (!update && !a) - { - if (inst.OPCD == 31) - { - if (!gpr.R(b).IsImm()) - gpr.BindToRegister(b, true, false); - opAddress = gpr.R(b); - } - else - { - opAddress = Imm32((u32)(s32)inst.SIMM_16); - } - } - else if (update && ((a == 0) || (d == a))) - { - PanicAlert("Invalid instruction"); - } - else - { - if ((inst.OPCD != 31) && gpr.R(a).IsImm() && !jo.memcheck) - { - u32 val = gpr.R(a).Imm32() + inst.SIMM_16; - opAddress = Imm32(val); - if (update) - gpr.SetImmediate32(a, val); - } - else if ((inst.OPCD == 31) && gpr.R(a).IsImm() && gpr.R(b).IsImm() && !jo.memcheck) - { - u32 val = gpr.R(a).Imm32() + gpr.R(b).Imm32(); - opAddress = Imm32(val); - if (update) - gpr.SetImmediate32(a, val); - } - else - { - // If we're using reg+reg mode and b is an immediate, pretend we're using constant offset mode - bool use_constant_offset = inst.OPCD != 31 || gpr.R(b).IsImm(); + // Prepare address operand + OpArg opAddress; + if (!update && !a) + { + if (inst.OPCD == 31) + { + if (!gpr.R(b).IsImm()) + gpr.BindToRegister(b, true, false); + opAddress = gpr.R(b); + } + else + { + opAddress = Imm32((u32)(s32)inst.SIMM_16); + } + } + else if (update && ((a == 0) || (d == a))) + { + PanicAlert("Invalid instruction"); + } + else + { + if ((inst.OPCD != 31) && gpr.R(a).IsImm() && !jo.memcheck) + { + u32 val = gpr.R(a).Imm32() + inst.SIMM_16; + opAddress = Imm32(val); + if (update) + gpr.SetImmediate32(a, val); + } + else if ((inst.OPCD == 31) && gpr.R(a).IsImm() && gpr.R(b).IsImm() && !jo.memcheck) + { + u32 val = gpr.R(a).Imm32() + gpr.R(b).Imm32(); + opAddress = Imm32(val); + if (update) + gpr.SetImmediate32(a, val); + } + else + { + // If we're using reg+reg mode and b is an immediate, pretend we're using constant offset mode + bool use_constant_offset = inst.OPCD != 31 || gpr.R(b).IsImm(); - s32 offset; - if (use_constant_offset) - offset = inst.OPCD == 31 ? gpr.R(b).SImm32() : (s32)inst.SIMM_16; - // Depending on whether we have an immediate and/or update, find the optimum way to calculate - // the load address. - if ((update || use_constant_offset) && !jo.memcheck) - { - gpr.BindToRegister(a, true, update); - opAddress = gpr.R(a); - if (!use_constant_offset) - ADD(32, opAddress, gpr.R(b)); - else if (update) - ADD(32, opAddress, Imm32((u32)offset)); - else - loadOffset = offset; - } - else - { - // In this case we need an extra temporary register. - opAddress = R(RSCRATCH2); - storeAddress = true; - if (use_constant_offset) - { - if (gpr.R(a).IsSimpleReg() && offset != 0) - { - LEA(32, RSCRATCH2, MDisp(gpr.RX(a), offset)); - } - else - { - MOV(32, opAddress, gpr.R(a)); - if (offset != 0) - ADD(32, opAddress, Imm32((u32)offset)); - } - } - else if (gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg()) - { - LEA(32, RSCRATCH2, MRegSum(gpr.RX(a), gpr.RX(b))); - } - else - { - MOV(32, opAddress, gpr.R(a)); - ADD(32, opAddress, gpr.R(b)); - } - } - } - } + s32 offset; + if (use_constant_offset) + offset = inst.OPCD == 31 ? gpr.R(b).SImm32() : (s32)inst.SIMM_16; + // Depending on whether we have an immediate and/or update, find the optimum way to calculate + // the load address. + if ((update || use_constant_offset) && !jo.memcheck) + { + gpr.BindToRegister(a, true, update); + opAddress = gpr.R(a); + if (!use_constant_offset) + ADD(32, opAddress, gpr.R(b)); + else if (update) + ADD(32, opAddress, Imm32((u32)offset)); + else + loadOffset = offset; + } + else + { + // In this case we need an extra temporary register. + opAddress = R(RSCRATCH2); + storeAddress = true; + if (use_constant_offset) + { + if (gpr.R(a).IsSimpleReg() && offset != 0) + { + LEA(32, RSCRATCH2, MDisp(gpr.RX(a), offset)); + } + else + { + MOV(32, opAddress, gpr.R(a)); + if (offset != 0) + ADD(32, opAddress, Imm32((u32)offset)); + } + } + else if (gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg()) + { + LEA(32, RSCRATCH2, MRegSum(gpr.RX(a), gpr.RX(b))); + } + else + { + MOV(32, opAddress, gpr.R(a)); + ADD(32, opAddress, gpr.R(b)); + } + } + } + } - gpr.Lock(a, b, d); + gpr.Lock(a, b, d); - if (update && storeAddress) - gpr.BindToRegister(a, true, true); + if (update && storeAddress) + gpr.BindToRegister(a, true, true); - // A bit of an evil hack here. We need to retain the original value of this register for the - // exception path, but we'd rather not needlessly pass it around if we don't have to, since - // the exception path is very rare. So we store the value in the regcache, let the load path - // clobber it, then restore the value in the exception path. - // TODO: no other load has to do this at the moment, since no other loads go directly to the - // target registers, but if that ever changes, we need to do it there too. - if (jo.memcheck) - { - gpr.StoreFromRegister(d); - js.revertGprLoad = d; - } - gpr.BindToRegister(d, false, true); + // A bit of an evil hack here. We need to retain the original value of this register for the + // exception path, but we'd rather not needlessly pass it around if we don't have to, since + // the exception path is very rare. So we store the value in the regcache, let the load path + // clobber it, then restore the value in the exception path. + // TODO: no other load has to do this at the moment, since no other loads go directly to the + // target registers, but if that ever changes, we need to do it there too. + if (jo.memcheck) + { + gpr.StoreFromRegister(d); + js.revertGprLoad = d; + } + gpr.BindToRegister(d, false, true); - BitSet32 registersInUse = CallerSavedRegistersInUse(); - // We need to save the (usually scratch) address register for the update. - if (update && storeAddress) - registersInUse[RSCRATCH2] = true; + BitSet32 registersInUse = CallerSavedRegistersInUse(); + // We need to save the (usually scratch) address register for the update. + if (update && storeAddress) + registersInUse[RSCRATCH2] = true; - SafeLoadToReg(gpr.RX(d), opAddress, accessSize, loadOffset, registersInUse, signExtend); + SafeLoadToReg(gpr.RX(d), opAddress, accessSize, loadOffset, registersInUse, signExtend); - if (update && storeAddress) - { - MemoryExceptionCheck(); - MOV(32, gpr.R(a), opAddress); - } + if (update && storeAddress) + { + MemoryExceptionCheck(); + MOV(32, gpr.R(a), opAddress); + } - // TODO: support no-swap in SafeLoadToReg instead - if (byte_reversed) - { - MemoryExceptionCheck(); - BSWAP(accessSize, gpr.RX(d)); - } + // TODO: support no-swap in SafeLoadToReg instead + if (byte_reversed) + { + MemoryExceptionCheck(); + BSWAP(accessSize, gpr.RX(d)); + } - gpr.UnlockAll(); - gpr.UnlockAllX(); + gpr.UnlockAll(); + gpr.UnlockAllX(); } void Jit64::dcbx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); - X64Reg addr = RSCRATCH; - X64Reg value = RSCRATCH2; - X64Reg tmp = gpr.GetFreeXReg(); - gpr.FlushLockX(tmp); + X64Reg addr = RSCRATCH; + X64Reg value = RSCRATCH2; + X64Reg tmp = gpr.GetFreeXReg(); + gpr.FlushLockX(tmp); - if (inst.RA && gpr.R(inst.RA).IsSimpleReg() && gpr.R(inst.RB).IsSimpleReg()) - { - LEA(32, addr, MRegSum(gpr.RX(inst.RA), gpr.RX(inst.RB))); - } - else - { - MOV(32, R(addr), gpr.R(inst.RB)); - if (inst.RA) - ADD(32, R(addr), gpr.R(inst.RA)); - } + if (inst.RA && gpr.R(inst.RA).IsSimpleReg() && gpr.R(inst.RB).IsSimpleReg()) + { + LEA(32, addr, MRegSum(gpr.RX(inst.RA), gpr.RX(inst.RB))); + } + else + { + MOV(32, R(addr), gpr.R(inst.RB)); + if (inst.RA) + ADD(32, R(addr), gpr.R(inst.RA)); + } - // Check whether a JIT cache line needs to be invalidated. - LEA(32, value, MScaled(addr, SCALE_8, 0)); // addr << 3 (masks the first 3 bits) - SHR(32, R(value), Imm8(3 + 5 + 5)); // >> 5 for cache line size, >> 5 for width of bitset - MOV(64, R(tmp), ImmPtr(jit->GetBlockCache()->GetBlockBitSet())); - MOV(32, R(value), MComplex(tmp, value, SCALE_4, 0)); - SHR(32, R(addr), Imm8(5)); - BT(32, R(value), R(addr)); + // Check whether a JIT cache line needs to be invalidated. + LEA(32, value, MScaled(addr, SCALE_8, 0)); // addr << 3 (masks the first 3 bits) + SHR(32, R(value), Imm8(3 + 5 + 5)); // >> 5 for cache line size, >> 5 for width of bitset + MOV(64, R(tmp), ImmPtr(jit->GetBlockCache()->GetBlockBitSet())); + MOV(32, R(value), MComplex(tmp, value, SCALE_4, 0)); + SHR(32, R(addr), Imm8(5)); + BT(32, R(value), R(addr)); - FixupBranch c = J_CC(CC_C, true); - SwitchToFarCode(); - SetJumpTarget(c); - BitSet32 registersInUse = CallerSavedRegistersInUse(); - ABI_PushRegistersAndAdjustStack(registersInUse, 0); - MOV(32, R(ABI_PARAM1), R(addr)); - SHL(32, R(ABI_PARAM1), Imm8(5)); - MOV(32, R(ABI_PARAM2), Imm32(32)); - XOR(32, R(ABI_PARAM3), R(ABI_PARAM3)); - ABI_CallFunction((void*)JitInterface::InvalidateICache); - ABI_PopRegistersAndAdjustStack(registersInUse, 0); - c = J(true); - SwitchToNearCode(); - SetJumpTarget(c); + FixupBranch c = J_CC(CC_C, true); + SwitchToFarCode(); + SetJumpTarget(c); + BitSet32 registersInUse = CallerSavedRegistersInUse(); + ABI_PushRegistersAndAdjustStack(registersInUse, 0); + MOV(32, R(ABI_PARAM1), R(addr)); + SHL(32, R(ABI_PARAM1), Imm8(5)); + MOV(32, R(ABI_PARAM2), Imm32(32)); + XOR(32, R(ABI_PARAM3), R(ABI_PARAM3)); + ABI_CallFunction((void*)JitInterface::InvalidateICache); + ABI_PopRegistersAndAdjustStack(registersInUse, 0); + c = J(true); + SwitchToNearCode(); + SetJumpTarget(c); - // dcbi - if (inst.SUBOP10 == 470) - { - // Flush DSP DMA if DMAState bit is set - TEST(16, M(&DSP::g_dspState), Imm16(1 << 9)); - c = J_CC(CC_NZ, true); - SwitchToFarCode(); - SetJumpTarget(c); - ABI_PushRegistersAndAdjustStack(registersInUse, 0); - SHL(32, R(addr), Imm8(5)); - ABI_CallFunctionR((void*)DSP::FlushInstantDMA, addr); - ABI_PopRegistersAndAdjustStack(registersInUse, 0); - c = J(true); - SwitchToNearCode(); - SetJumpTarget(c); - } + // dcbi + if (inst.SUBOP10 == 470) + { + // Flush DSP DMA if DMAState bit is set + TEST(16, M(&DSP::g_dspState), Imm16(1 << 9)); + c = J_CC(CC_NZ, true); + SwitchToFarCode(); + SetJumpTarget(c); + ABI_PushRegistersAndAdjustStack(registersInUse, 0); + SHL(32, R(addr), Imm8(5)); + ABI_CallFunctionR((void*)DSP::FlushInstantDMA, addr); + ABI_PopRegistersAndAdjustStack(registersInUse, 0); + c = J(true); + SwitchToNearCode(); + SetJumpTarget(c); + } - gpr.UnlockAllX(); + gpr.UnlockAllX(); } void Jit64::dcbt(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); - // Prefetch. Since we don't emulate the data cache, we don't need to do anything. + // Prefetch. Since we don't emulate the data cache, we don't need to do anything. - // If a dcbst follows a dcbt, it probably isn't a case of dynamic code - // modification, so don't bother invalidating the jit block cache. - // This is important because invalidating the block cache when we don't - // need to is terrible for performance. - // (Invalidating the jit block cache on dcbst is a heuristic.) - if (MergeAllowedNextInstructions(1) && - js.op[1].inst.OPCD == 31 && js.op[1].inst.SUBOP10 == 54 && - js.op[1].inst.RA == inst.RA && js.op[1].inst.RB == inst.RB) - { - js.skipInstructions = 1; - } + // If a dcbst follows a dcbt, it probably isn't a case of dynamic code + // modification, so don't bother invalidating the jit block cache. + // This is important because invalidating the block cache when we don't + // need to is terrible for performance. + // (Invalidating the jit block cache on dcbst is a heuristic.) + if (MergeAllowedNextInstructions(1) && js.op[1].inst.OPCD == 31 && js.op[1].inst.SUBOP10 == 54 && + js.op[1].inst.RA == inst.RA && js.op[1].inst.RB == inst.RB) + { + js.skipInstructions = 1; + } } // Zero cache line. void Jit64::dcbz(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - if (SConfig::GetInstance().bDCBZOFF) - return; + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + if (SConfig::GetInstance().bDCBZOFF) + return; - int a = inst.RA; - int b = inst.RB; + int a = inst.RA; + int b = inst.RB; - u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS; + u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS; - // The following masks the region used by the GC/Wii virtual memory lib - mem_mask |= Memory::ADDR_MASK_MEM1; + // The following masks the region used by the GC/Wii virtual memory lib + mem_mask |= Memory::ADDR_MASK_MEM1; - MOV(32, R(RSCRATCH), gpr.R(b)); - if (a) - ADD(32, R(RSCRATCH), gpr.R(a)); - AND(32, R(RSCRATCH), Imm32(~31)); - TEST(32, R(RSCRATCH), Imm32(mem_mask)); - FixupBranch slow = J_CC(CC_NZ, true); + MOV(32, R(RSCRATCH), gpr.R(b)); + if (a) + ADD(32, R(RSCRATCH), gpr.R(a)); + AND(32, R(RSCRATCH), Imm32(~31)); + TEST(32, R(RSCRATCH), Imm32(mem_mask)); + FixupBranch slow = J_CC(CC_NZ, true); - // Should this code ever run? I can't find any games that use DCBZ on non-physical addresses, but - // supposedly there are, at least for some MMU titles. Let's be careful and support it to be sure. - SwitchToFarCode(); - SetJumpTarget(slow); - MOV(32, M(&PC), Imm32(jit->js.compilerPC)); - BitSet32 registersInUse = CallerSavedRegistersInUse(); - ABI_PushRegistersAndAdjustStack(registersInUse, 0); - ABI_CallFunctionR((void *)&PowerPC::ClearCacheLine, RSCRATCH); - ABI_PopRegistersAndAdjustStack(registersInUse, 0); - FixupBranch exit = J(true); - SwitchToNearCode(); + // Should this code ever run? I can't find any games that use DCBZ on non-physical addresses, but + // supposedly there are, at least for some MMU titles. Let's be careful and support it to be sure. + SwitchToFarCode(); + SetJumpTarget(slow); + MOV(32, M(&PC), Imm32(jit->js.compilerPC)); + BitSet32 registersInUse = CallerSavedRegistersInUse(); + ABI_PushRegistersAndAdjustStack(registersInUse, 0); + ABI_CallFunctionR((void*)&PowerPC::ClearCacheLine, RSCRATCH); + ABI_PopRegistersAndAdjustStack(registersInUse, 0); + FixupBranch exit = J(true); + SwitchToNearCode(); - // Mask out the address so we don't write to MEM1 out of bounds - // FIXME: Work out why the AGP disc writes out of bounds - if (!SConfig::GetInstance().bWii) - AND(32, R(RSCRATCH), Imm32(Memory::RAM_MASK)); - PXOR(XMM0, R(XMM0)); - MOVAPS(MComplex(RMEM, RSCRATCH, SCALE_1, 0), XMM0); - MOVAPS(MComplex(RMEM, RSCRATCH, SCALE_1, 16), XMM0); - SetJumpTarget(exit); + // Mask out the address so we don't write to MEM1 out of bounds + // FIXME: Work out why the AGP disc writes out of bounds + if (!SConfig::GetInstance().bWii) + AND(32, R(RSCRATCH), Imm32(Memory::RAM_MASK)); + PXOR(XMM0, R(XMM0)); + MOVAPS(MComplex(RMEM, RSCRATCH, SCALE_1, 0), XMM0); + MOVAPS(MComplex(RMEM, RSCRATCH, SCALE_1, 16), XMM0); + SetJumpTarget(exit); } void Jit64::stX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); - int s = inst.RS; - int a = inst.RA; - s32 offset = (s32)(s16)inst.SIMM_16; - bool update = (inst.OPCD & 1) && offset; + int s = inst.RS; + int a = inst.RA; + s32 offset = (s32)(s16)inst.SIMM_16; + bool update = (inst.OPCD & 1) && offset; - if (!a && update) - PanicAlert("Invalid stX"); + if (!a && update) + PanicAlert("Invalid stX"); - int accessSize; - switch (inst.OPCD & ~1) - { - case 36: // stw - accessSize = 32; - break; - case 44: // sth - accessSize = 16; - break; - case 38: // stb - accessSize = 8; - break; - default: - _assert_msg_(DYNA_REC, 0, "stX: Invalid access size."); - return; - } + int accessSize; + switch (inst.OPCD & ~1) + { + case 36: // stw + accessSize = 32; + break; + case 44: // sth + accessSize = 16; + break; + case 38: // stb + accessSize = 8; + break; + default: + _assert_msg_(DYNA_REC, 0, "stX: Invalid access size."); + return; + } - // If we already know the address of the write - if (!a || gpr.R(a).IsImm()) - { - u32 addr = (a ? gpr.R(a).Imm32() : 0) + offset; - bool exception = WriteToConstAddress(accessSize, gpr.R(s), addr, CallerSavedRegistersInUse()); - if (update) - { - if (!jo.memcheck || !exception) - { - gpr.SetImmediate32(a, addr); - } - else - { - gpr.KillImmediate(a, true, true); - MemoryExceptionCheck(); - ADD(32, gpr.R(a), Imm32((u32)offset)); - } - } - } - else - { - gpr.Lock(a, s); - gpr.BindToRegister(a, true, update); - if (gpr.R(s).IsImm()) - { - SafeWriteRegToReg(gpr.R(s), gpr.RX(a), accessSize, offset, CallerSavedRegistersInUse(), SAFE_LOADSTORE_CLOBBER_RSCRATCH_INSTEAD_OF_ADDR); - } - else - { - X64Reg reg_value; - if (WriteClobbersRegValue(accessSize, /* swap */ true)) - { - MOV(32, R(RSCRATCH2), gpr.R(s)); - reg_value = RSCRATCH2; - } - else - { - gpr.BindToRegister(s, true, false); - reg_value = gpr.RX(s); - } - SafeWriteRegToReg(reg_value, gpr.RX(a), accessSize, offset, CallerSavedRegistersInUse(), SAFE_LOADSTORE_CLOBBER_RSCRATCH_INSTEAD_OF_ADDR); - } + // If we already know the address of the write + if (!a || gpr.R(a).IsImm()) + { + u32 addr = (a ? gpr.R(a).Imm32() : 0) + offset; + bool exception = WriteToConstAddress(accessSize, gpr.R(s), addr, CallerSavedRegistersInUse()); + if (update) + { + if (!jo.memcheck || !exception) + { + gpr.SetImmediate32(a, addr); + } + else + { + gpr.KillImmediate(a, true, true); + MemoryExceptionCheck(); + ADD(32, gpr.R(a), Imm32((u32)offset)); + } + } + } + else + { + gpr.Lock(a, s); + gpr.BindToRegister(a, true, update); + if (gpr.R(s).IsImm()) + { + SafeWriteRegToReg(gpr.R(s), gpr.RX(a), accessSize, offset, CallerSavedRegistersInUse(), + SAFE_LOADSTORE_CLOBBER_RSCRATCH_INSTEAD_OF_ADDR); + } + else + { + X64Reg reg_value; + if (WriteClobbersRegValue(accessSize, /* swap */ true)) + { + MOV(32, R(RSCRATCH2), gpr.R(s)); + reg_value = RSCRATCH2; + } + else + { + gpr.BindToRegister(s, true, false); + reg_value = gpr.RX(s); + } + SafeWriteRegToReg(reg_value, gpr.RX(a), accessSize, offset, CallerSavedRegistersInUse(), + SAFE_LOADSTORE_CLOBBER_RSCRATCH_INSTEAD_OF_ADDR); + } - if (update) - { - MemoryExceptionCheck(); - ADD(32, gpr.R(a), Imm32((u32)offset)); - } - } - gpr.UnlockAll(); + if (update) + { + MemoryExceptionCheck(); + ADD(32, gpr.R(a), Imm32((u32)offset)); + } + } + gpr.UnlockAll(); } void Jit64::stXx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); - int a = inst.RA, b = inst.RB, s = inst.RS; - bool update = !!(inst.SUBOP10 & 32); - bool byte_reverse = !!(inst.SUBOP10 & 512); - FALLBACK_IF(!a || (update && a == s) || (update && jo.memcheck && a == b)); + int a = inst.RA, b = inst.RB, s = inst.RS; + bool update = !!(inst.SUBOP10 & 32); + bool byte_reverse = !!(inst.SUBOP10 & 512); + FALLBACK_IF(!a || (update && a == s) || (update && jo.memcheck && a == b)); - gpr.Lock(a, b, s); + gpr.Lock(a, b, s); - if (update) - gpr.BindToRegister(a, true, true); + if (update) + gpr.BindToRegister(a, true, true); - if (gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg()) - { - LEA(32, RSCRATCH2, MRegSum(gpr.RX(a), gpr.RX(b))); - } - else - { - MOV(32, R(RSCRATCH2), gpr.R(a)); - ADD(32, R(RSCRATCH2), gpr.R(b)); - } + if (gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg()) + { + LEA(32, RSCRATCH2, MRegSum(gpr.RX(a), gpr.RX(b))); + } + else + { + MOV(32, R(RSCRATCH2), gpr.R(a)); + ADD(32, R(RSCRATCH2), gpr.R(b)); + } - int accessSize; - switch (inst.SUBOP10 & ~32) - { - case 151: - case 662: - accessSize = 32; - break; - case 407: - case 918: - accessSize = 16; - break; - case 215: - accessSize = 8; - break; - default: - PanicAlert("stXx: invalid access size"); - accessSize = 0; - break; - } + int accessSize; + switch (inst.SUBOP10 & ~32) + { + case 151: + case 662: + accessSize = 32; + break; + case 407: + case 918: + accessSize = 16; + break; + case 215: + accessSize = 8; + break; + default: + PanicAlert("stXx: invalid access size"); + accessSize = 0; + break; + } - if (gpr.R(s).IsImm()) - { - BitSet32 registersInUse = CallerSavedRegistersInUse(); - if (update) - registersInUse[RSCRATCH2] = true; - SafeWriteRegToReg(gpr.R(s), RSCRATCH2, accessSize, 0, registersInUse, byte_reverse ? SAFE_LOADSTORE_NO_SWAP : 0); - } - else - { - X64Reg reg_value; - if (WriteClobbersRegValue(accessSize, /* swap */ !byte_reverse)) - { - MOV(32, R(RSCRATCH), gpr.R(s)); - reg_value = RSCRATCH; - } - else - { - gpr.BindToRegister(s, true, false); - reg_value = gpr.RX(s); - } - BitSet32 registersInUse = CallerSavedRegistersInUse(); - if (update) - registersInUse[RSCRATCH2] = true; - SafeWriteRegToReg(reg_value, RSCRATCH2, accessSize, 0, registersInUse, byte_reverse ? SAFE_LOADSTORE_NO_SWAP : 0); - } + if (gpr.R(s).IsImm()) + { + BitSet32 registersInUse = CallerSavedRegistersInUse(); + if (update) + registersInUse[RSCRATCH2] = true; + SafeWriteRegToReg(gpr.R(s), RSCRATCH2, accessSize, 0, registersInUse, + byte_reverse ? SAFE_LOADSTORE_NO_SWAP : 0); + } + else + { + X64Reg reg_value; + if (WriteClobbersRegValue(accessSize, /* swap */ !byte_reverse)) + { + MOV(32, R(RSCRATCH), gpr.R(s)); + reg_value = RSCRATCH; + } + else + { + gpr.BindToRegister(s, true, false); + reg_value = gpr.RX(s); + } + BitSet32 registersInUse = CallerSavedRegistersInUse(); + if (update) + registersInUse[RSCRATCH2] = true; + SafeWriteRegToReg(reg_value, RSCRATCH2, accessSize, 0, registersInUse, + byte_reverse ? SAFE_LOADSTORE_NO_SWAP : 0); + } - if (update) - { - MemoryExceptionCheck(); - MOV(32, gpr.R(a), R(RSCRATCH2)); - } + if (update) + { + MemoryExceptionCheck(); + MOV(32, gpr.R(a), R(RSCRATCH2)); + } - gpr.UnlockAll(); - gpr.UnlockAllX(); + gpr.UnlockAll(); + gpr.UnlockAllX(); } // A few games use these heavily in video codecs. void Jit64::lmw(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); - // TODO: This doesn't handle rollback on DSI correctly - MOV(32, R(RSCRATCH2), Imm32((u32)(s32)inst.SIMM_16)); - if (inst.RA) - ADD(32, R(RSCRATCH2), gpr.R(inst.RA)); - for (int i = inst.RD; i < 32; i++) - { - SafeLoadToReg(RSCRATCH, R(RSCRATCH2), 32, (i - inst.RD) * 4, CallerSavedRegistersInUse() | BitSet32 { RSCRATCH2 }, false); - gpr.BindToRegister(i, false, true); - MOV(32, gpr.R(i), R(RSCRATCH)); - } - gpr.UnlockAllX(); + // TODO: This doesn't handle rollback on DSI correctly + MOV(32, R(RSCRATCH2), Imm32((u32)(s32)inst.SIMM_16)); + if (inst.RA) + ADD(32, R(RSCRATCH2), gpr.R(inst.RA)); + for (int i = inst.RD; i < 32; i++) + { + SafeLoadToReg(RSCRATCH, R(RSCRATCH2), 32, (i - inst.RD) * 4, + CallerSavedRegistersInUse() | BitSet32{RSCRATCH2}, false); + gpr.BindToRegister(i, false, true); + MOV(32, gpr.R(i), R(RSCRATCH)); + } + gpr.UnlockAllX(); } void Jit64::stmw(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); - // TODO: This doesn't handle rollback on DSI correctly - for (int i = inst.RD; i < 32; i++) - { - if (inst.RA) - MOV(32, R(RSCRATCH), gpr.R(inst.RA)); - else - XOR(32, R(RSCRATCH), R(RSCRATCH)); - if (gpr.R(i).IsImm()) - { - SafeWriteRegToReg(gpr.R(i), RSCRATCH, 32, (i - inst.RD) * 4 + (u32)(s32)inst.SIMM_16, CallerSavedRegistersInUse()); - } - else - { - MOV(32, R(RSCRATCH2), gpr.R(i)); - SafeWriteRegToReg(RSCRATCH2, RSCRATCH, 32, (i - inst.RD) * 4 + (u32)(s32)inst.SIMM_16, CallerSavedRegistersInUse()); - } - } - gpr.UnlockAllX(); + // TODO: This doesn't handle rollback on DSI correctly + for (int i = inst.RD; i < 32; i++) + { + if (inst.RA) + MOV(32, R(RSCRATCH), gpr.R(inst.RA)); + else + XOR(32, R(RSCRATCH), R(RSCRATCH)); + if (gpr.R(i).IsImm()) + { + SafeWriteRegToReg(gpr.R(i), RSCRATCH, 32, (i - inst.RD) * 4 + (u32)(s32)inst.SIMM_16, + CallerSavedRegistersInUse()); + } + else + { + MOV(32, R(RSCRATCH2), gpr.R(i)); + SafeWriteRegToReg(RSCRATCH2, RSCRATCH, 32, (i - inst.RD) * 4 + (u32)(s32)inst.SIMM_16, + CallerSavedRegistersInUse()); + } + } + gpr.UnlockAllX(); } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStoreFloating.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStoreFloating.cpp index e34dfe6429..6dbf8b14c4 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStoreFloating.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStoreFloating.cpp @@ -2,223 +2,225 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/Jit64/Jit.h" #include "Common/BitSet.h" -#include "Common/CommonTypes.h" #include "Common/CPUDetect.h" +#include "Common/CommonTypes.h" #include "Common/x64Emitter.h" #include "Core/ConfigManager.h" -#include "Core/PowerPC/Jit64/Jit.h" #include "Core/PowerPC/Jit64/JitRegCache.h" #include "Core/PowerPC/JitCommon/Jit_Util.h" using namespace Gen; -// TODO: Add peephole optimizations for multiple consecutive lfd/lfs/stfd/stfs since they are so common, +// TODO: Add peephole optimizations for multiple consecutive lfd/lfs/stfd/stfs since they are so +// common, // and pshufb could help a lot. void Jit64::lfXXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreFloatingOff); - bool indexed = inst.OPCD == 31; - bool update = indexed ? !!(inst.SUBOP10 & 0x20) : !!(inst.OPCD & 1); - bool single = indexed ? !(inst.SUBOP10 & 0x40) : !(inst.OPCD & 2); - update &= indexed || inst.SIMM_16; + INSTRUCTION_START + JITDISABLE(bJITLoadStoreFloatingOff); + bool indexed = inst.OPCD == 31; + bool update = indexed ? !!(inst.SUBOP10 & 0x20) : !!(inst.OPCD & 1); + bool single = indexed ? !(inst.SUBOP10 & 0x40) : !(inst.OPCD & 2); + update &= indexed || inst.SIMM_16; - int d = inst.RD; - int a = inst.RA; - int b = inst.RB; + int d = inst.RD; + int a = inst.RA; + int b = inst.RB; - FALLBACK_IF(!indexed && !a); + FALLBACK_IF(!indexed && !a); - gpr.BindToRegister(a, true, update); + gpr.BindToRegister(a, true, update); - s32 offset = 0; - OpArg addr = gpr.R(a); - if (update && jo.memcheck) - { - addr = R(RSCRATCH2); - MOV(32, addr, gpr.R(a)); - } - if (indexed) - { - if (update) - { - ADD(32, addr, gpr.R(b)); - } - else - { - addr = R(RSCRATCH2); - if (a && gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg()) - LEA(32, RSCRATCH2, MRegSum(gpr.RX(a), gpr.RX(b))); - else - { - MOV(32, addr, gpr.R(b)); - if (a) - ADD(32, addr, gpr.R(a)); - } - } - } - else - { - if (update) - ADD(32, addr, Imm32((s32)(s16)inst.SIMM_16)); - else - offset = (s16)inst.SIMM_16; - } + s32 offset = 0; + OpArg addr = gpr.R(a); + if (update && jo.memcheck) + { + addr = R(RSCRATCH2); + MOV(32, addr, gpr.R(a)); + } + if (indexed) + { + if (update) + { + ADD(32, addr, gpr.R(b)); + } + else + { + addr = R(RSCRATCH2); + if (a && gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg()) + LEA(32, RSCRATCH2, MRegSum(gpr.RX(a), gpr.RX(b))); + else + { + MOV(32, addr, gpr.R(b)); + if (a) + ADD(32, addr, gpr.R(a)); + } + } + } + else + { + if (update) + ADD(32, addr, Imm32((s32)(s16)inst.SIMM_16)); + else + offset = (s16)inst.SIMM_16; + } - fpr.Lock(d); - if (jo.memcheck && single) - { - fpr.StoreFromRegister(d); - js.revertFprLoad = d; - } - fpr.BindToRegister(d, !single); - BitSet32 registersInUse = CallerSavedRegistersInUse(); - if (update && jo.memcheck) - registersInUse[RSCRATCH2] = true; - SafeLoadToReg(RSCRATCH, addr, single ? 32 : 64, offset, registersInUse, false); + fpr.Lock(d); + if (jo.memcheck && single) + { + fpr.StoreFromRegister(d); + js.revertFprLoad = d; + } + fpr.BindToRegister(d, !single); + BitSet32 registersInUse = CallerSavedRegistersInUse(); + if (update && jo.memcheck) + registersInUse[RSCRATCH2] = true; + SafeLoadToReg(RSCRATCH, addr, single ? 32 : 64, offset, registersInUse, false); - MemoryExceptionCheck(); - if (single) - { - ConvertSingleToDouble(fpr.RX(d), RSCRATCH, true); - } - else - { - MOVQ_xmm(XMM0, R(RSCRATCH)); - MOVSD(fpr.RX(d), R(XMM0)); - } - if (update && jo.memcheck) - MOV(32, gpr.R(a), addr); - fpr.UnlockAll(); - gpr.UnlockAll(); + MemoryExceptionCheck(); + if (single) + { + ConvertSingleToDouble(fpr.RX(d), RSCRATCH, true); + } + else + { + MOVQ_xmm(XMM0, R(RSCRATCH)); + MOVSD(fpr.RX(d), R(XMM0)); + } + if (update && jo.memcheck) + MOV(32, gpr.R(a), addr); + fpr.UnlockAll(); + gpr.UnlockAll(); } void Jit64::stfXXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreFloatingOff); - bool indexed = inst.OPCD == 31; - bool update = indexed ? !!(inst.SUBOP10&0x20) : !!(inst.OPCD&1); - bool single = indexed ? !(inst.SUBOP10&0x40) : !(inst.OPCD&2); - update &= indexed || inst.SIMM_16; + INSTRUCTION_START + JITDISABLE(bJITLoadStoreFloatingOff); + bool indexed = inst.OPCD == 31; + bool update = indexed ? !!(inst.SUBOP10 & 0x20) : !!(inst.OPCD & 1); + bool single = indexed ? !(inst.SUBOP10 & 0x40) : !(inst.OPCD & 2); + update &= indexed || inst.SIMM_16; - int s = inst.RS; - int a = inst.RA; - int b = inst.RB; - s32 imm = (s16)inst.SIMM_16; - int accessSize = single ? 32 : 64; + int s = inst.RS; + int a = inst.RA; + int b = inst.RB; + s32 imm = (s16)inst.SIMM_16; + int accessSize = single ? 32 : 64; - FALLBACK_IF(update && jo.memcheck && a == b); + FALLBACK_IF(update && jo.memcheck && a == b); - if (single) - { - if (jit->js.op->fprIsStoreSafe[s]) - { - CVTSD2SS(XMM0, fpr.R(s)); - } - else - { - fpr.BindToRegister(s, true, false); - ConvertDoubleToSingle(XMM0, fpr.RX(s)); - } - MOVD_xmm(R(RSCRATCH), XMM0); - } - else - { - if (fpr.R(s).IsSimpleReg()) - MOVQ_xmm(R(RSCRATCH), fpr.RX(s)); - else - MOV(64, R(RSCRATCH), fpr.R(s)); - } + if (single) + { + if (jit->js.op->fprIsStoreSafe[s]) + { + CVTSD2SS(XMM0, fpr.R(s)); + } + else + { + fpr.BindToRegister(s, true, false); + ConvertDoubleToSingle(XMM0, fpr.RX(s)); + } + MOVD_xmm(R(RSCRATCH), XMM0); + } + else + { + if (fpr.R(s).IsSimpleReg()) + MOVQ_xmm(R(RSCRATCH), fpr.RX(s)); + else + MOV(64, R(RSCRATCH), fpr.R(s)); + } - if (!indexed && (!a || gpr.R(a).IsImm())) - { - u32 addr = (a ? gpr.R(a).Imm32() : 0) + imm; - bool exception = WriteToConstAddress(accessSize, R(RSCRATCH), addr, CallerSavedRegistersInUse()); + if (!indexed && (!a || gpr.R(a).IsImm())) + { + u32 addr = (a ? gpr.R(a).Imm32() : 0) + imm; + bool exception = + WriteToConstAddress(accessSize, R(RSCRATCH), addr, CallerSavedRegistersInUse()); - if (update) - { - if (!jo.memcheck || !exception) - { - gpr.SetImmediate32(a, addr); - } - else - { - gpr.KillImmediate(a, true, true); - MemoryExceptionCheck(); - ADD(32, gpr.R(a), Imm32((u32)imm)); - } - } - fpr.UnlockAll(); - gpr.UnlockAll(); - return; - } + if (update) + { + if (!jo.memcheck || !exception) + { + gpr.SetImmediate32(a, addr); + } + else + { + gpr.KillImmediate(a, true, true); + MemoryExceptionCheck(); + ADD(32, gpr.R(a), Imm32((u32)imm)); + } + } + fpr.UnlockAll(); + gpr.UnlockAll(); + return; + } - s32 offset = 0; - if (update) - gpr.BindToRegister(a, true, true); - if (indexed) - { - if (a && gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg()) - LEA(32, RSCRATCH2, MRegSum(gpr.RX(a), gpr.RX(b))); - else - { - MOV(32, R(RSCRATCH2), gpr.R(b)); - if (a) - ADD(32, R(RSCRATCH2), gpr.R(a)); - } - } - else - { - if (update) - { - LEA(32, RSCRATCH2, MDisp(gpr.RX(a), imm)); - } - else - { - offset = imm; - MOV(32, R(RSCRATCH2), gpr.R(a)); - } - } + s32 offset = 0; + if (update) + gpr.BindToRegister(a, true, true); + if (indexed) + { + if (a && gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg()) + LEA(32, RSCRATCH2, MRegSum(gpr.RX(a), gpr.RX(b))); + else + { + MOV(32, R(RSCRATCH2), gpr.R(b)); + if (a) + ADD(32, R(RSCRATCH2), gpr.R(a)); + } + } + else + { + if (update) + { + LEA(32, RSCRATCH2, MDisp(gpr.RX(a), imm)); + } + else + { + offset = imm; + MOV(32, R(RSCRATCH2), gpr.R(a)); + } + } - BitSet32 registersInUse = CallerSavedRegistersInUse(); - // We need to save the (usually scratch) address register for the update. - if (update) - registersInUse[RSCRATCH2] = true; + BitSet32 registersInUse = CallerSavedRegistersInUse(); + // We need to save the (usually scratch) address register for the update. + if (update) + registersInUse[RSCRATCH2] = true; - SafeWriteRegToReg(RSCRATCH, RSCRATCH2, accessSize, offset, registersInUse); + SafeWriteRegToReg(RSCRATCH, RSCRATCH2, accessSize, offset, registersInUse); - if (update) - { - MemoryExceptionCheck(); - MOV(32, gpr.R(a), R(RSCRATCH2)); - } + if (update) + { + MemoryExceptionCheck(); + MOV(32, gpr.R(a), R(RSCRATCH2)); + } - fpr.UnlockAll(); - gpr.UnlockAll(); - gpr.UnlockAllX(); + fpr.UnlockAll(); + gpr.UnlockAll(); + gpr.UnlockAllX(); } // This one is a little bit weird; it stores the low 32 bits of a double without converting it void Jit64::stfiwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreFloatingOff); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreFloatingOff); - int s = inst.RS; - int a = inst.RA; - int b = inst.RB; + int s = inst.RS; + int a = inst.RA; + int b = inst.RB; - MOV(32, R(RSCRATCH2), gpr.R(b)); - if (a) - ADD(32, R(RSCRATCH2), gpr.R(a)); + MOV(32, R(RSCRATCH2), gpr.R(b)); + if (a) + ADD(32, R(RSCRATCH2), gpr.R(a)); - if (fpr.R(s).IsSimpleReg()) - MOVD_xmm(R(RSCRATCH), fpr.RX(s)); - else - MOV(32, R(RSCRATCH), fpr.R(s)); - SafeWriteRegToReg(RSCRATCH, RSCRATCH2, 32, 0, CallerSavedRegistersInUse()); - gpr.UnlockAllX(); + if (fpr.R(s).IsSimpleReg()) + MOVD_xmm(R(RSCRATCH), fpr.RX(s)); + else + MOV(32, R(RSCRATCH), fpr.R(s)); + SafeWriteRegToReg(RSCRATCH, RSCRATCH2, 32, 0, CallerSavedRegistersInUse()); + gpr.UnlockAllX(); } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp index da9e813208..f5223347f9 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp @@ -5,16 +5,16 @@ // TODO(ector): Tons of pshufb optimization of the loads/stores, for SSSE3+, possibly SSE4, only. // Should give a very noticeable speed boost to paired single heavy code. +#include "Core/PowerPC/Jit64/Jit.h" #include "Common/BitSet.h" -#include "Common/CommonTypes.h" #include "Common/CPUDetect.h" +#include "Common/CommonTypes.h" #include "Common/x64Emitter.h" #include "Core/ConfigManager.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/Jit64/Jit.h" #include "Core/PowerPC/Jit64/JitRegCache.h" -#include "Core/PowerPC/JitCommon/Jit_Util.h" #include "Core/PowerPC/JitCommon/JitAsmCommon.h" +#include "Core/PowerPC/JitCommon/Jit_Util.h" +#include "Core/PowerPC/PowerPC.h" using namespace Gen; @@ -22,305 +22,307 @@ using namespace Gen; // We will have to break block after quantizers are written to. void Jit64::psq_stXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStorePairedOff); + INSTRUCTION_START + JITDISABLE(bJITLoadStorePairedOff); - s32 offset = inst.SIMM_12; - bool indexed = inst.OPCD == 4; - bool update = (inst.OPCD == 61 && offset) || (inst.OPCD == 4 && !!(inst.SUBOP6 & 32)); - int a = inst.RA; - int b = indexed ? inst.RB : a; - int s = inst.FS; - int i = indexed ? inst.Ix : inst.I; - int w = indexed ? inst.Wx : inst.W; - FALLBACK_IF(!a); + s32 offset = inst.SIMM_12; + bool indexed = inst.OPCD == 4; + bool update = (inst.OPCD == 61 && offset) || (inst.OPCD == 4 && !!(inst.SUBOP6 & 32)); + int a = inst.RA; + int b = indexed ? inst.RB : a; + int s = inst.FS; + int i = indexed ? inst.Ix : inst.I; + int w = indexed ? inst.Wx : inst.W; + FALLBACK_IF(!a); - gpr.Lock(a, b); - if (js.assumeNoPairedQuantize) - { - int storeOffset = 0; - gpr.BindToRegister(a, true, update); - X64Reg addr = gpr.RX(a); - // TODO: this is kind of ugly :/ we should probably create a universal load/store address calculation - // function that handles all these weird cases, e.g. how non-fastmem loadstores clobber addresses. - bool storeAddress = (update && jo.memcheck) || !jo.fastmem; - if (storeAddress) - { - addr = RSCRATCH2; - MOV(32, R(addr), gpr.R(a)); - } - if (indexed) - { - if (update) - { - ADD(32, R(addr), gpr.R(b)); - } - else - { - addr = RSCRATCH2; - if (a && gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg()) - { - LEA(32, addr, MRegSum(gpr.RX(a), gpr.RX(b))); - } - else - { - MOV(32, R(addr), gpr.R(b)); - if (a) - ADD(32, R(addr), gpr.R(a)); - } - } - } - else - { - if (update) - ADD(32, R(addr), Imm32(offset)); - else - storeOffset = offset; - } + gpr.Lock(a, b); + if (js.assumeNoPairedQuantize) + { + int storeOffset = 0; + gpr.BindToRegister(a, true, update); + X64Reg addr = gpr.RX(a); + // TODO: this is kind of ugly :/ we should probably create a universal load/store address + // calculation + // function that handles all these weird cases, e.g. how non-fastmem loadstores clobber + // addresses. + bool storeAddress = (update && jo.memcheck) || !jo.fastmem; + if (storeAddress) + { + addr = RSCRATCH2; + MOV(32, R(addr), gpr.R(a)); + } + if (indexed) + { + if (update) + { + ADD(32, R(addr), gpr.R(b)); + } + else + { + addr = RSCRATCH2; + if (a && gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg()) + { + LEA(32, addr, MRegSum(gpr.RX(a), gpr.RX(b))); + } + else + { + MOV(32, R(addr), gpr.R(b)); + if (a) + ADD(32, R(addr), gpr.R(a)); + } + } + } + else + { + if (update) + ADD(32, R(addr), Imm32(offset)); + else + storeOffset = offset; + } - fpr.Lock(s); - if (w) - { - CVTSD2SS(XMM0, fpr.R(s)); - MOVD_xmm(R(RSCRATCH), XMM0); - } - else - { - CVTPD2PS(XMM0, fpr.R(s)); - MOVQ_xmm(R(RSCRATCH), XMM0); - ROL(64, R(RSCRATCH), Imm8(32)); - } + fpr.Lock(s); + if (w) + { + CVTSD2SS(XMM0, fpr.R(s)); + MOVD_xmm(R(RSCRATCH), XMM0); + } + else + { + CVTPD2PS(XMM0, fpr.R(s)); + MOVQ_xmm(R(RSCRATCH), XMM0); + ROL(64, R(RSCRATCH), Imm8(32)); + } - BitSet32 registersInUse = CallerSavedRegistersInUse(); - if (update && storeAddress) - registersInUse[addr] = true; - SafeWriteRegToReg(RSCRATCH, addr, w ? 32 : 64, storeOffset, registersInUse); - MemoryExceptionCheck(); - if (update && storeAddress) - MOV(32, gpr.R(a), R(addr)); - gpr.UnlockAll(); - fpr.UnlockAll(); - return; - } - gpr.FlushLockX(RSCRATCH_EXTRA); - if (update) - gpr.BindToRegister(a, true, true); - if (gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg() && (indexed || offset)) - { - if (indexed) - LEA(32, RSCRATCH_EXTRA, MRegSum(gpr.RX(a), gpr.RX(b))); - else - LEA(32, RSCRATCH_EXTRA, MDisp(gpr.RX(a), offset)); - } - else - { - MOV(32, R(RSCRATCH_EXTRA), gpr.R(a)); - if (indexed) - ADD(32, R(RSCRATCH_EXTRA), gpr.R(b)); - else if (offset) - ADD(32, R(RSCRATCH_EXTRA), Imm32((u32)offset)); - } - // In memcheck mode, don't update the address until the exception check - if (update && !jo.memcheck) - MOV(32, gpr.R(a), R(RSCRATCH_EXTRA)); - // Some games (e.g. Dirt 2) incorrectly set the unused bits which breaks the lookup table code. - // Hence, we need to mask out the unused bits. The layout of the GQR register is - // UU[SCALE]UUUUU[TYPE] where SCALE is 6 bits and TYPE is 3 bits, so we have to AND with - // 0b0011111100000111, or 0x3F07. - MOV(32, R(RSCRATCH2), Imm32(0x3F07)); - AND(32, R(RSCRATCH2), PPCSTATE(spr[SPR_GQR0 + i])); - MOVZX(32, 8, RSCRATCH, R(RSCRATCH2)); + BitSet32 registersInUse = CallerSavedRegistersInUse(); + if (update && storeAddress) + registersInUse[addr] = true; + SafeWriteRegToReg(RSCRATCH, addr, w ? 32 : 64, storeOffset, registersInUse); + MemoryExceptionCheck(); + if (update && storeAddress) + MOV(32, gpr.R(a), R(addr)); + gpr.UnlockAll(); + fpr.UnlockAll(); + return; + } + gpr.FlushLockX(RSCRATCH_EXTRA); + if (update) + gpr.BindToRegister(a, true, true); + if (gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg() && (indexed || offset)) + { + if (indexed) + LEA(32, RSCRATCH_EXTRA, MRegSum(gpr.RX(a), gpr.RX(b))); + else + LEA(32, RSCRATCH_EXTRA, MDisp(gpr.RX(a), offset)); + } + else + { + MOV(32, R(RSCRATCH_EXTRA), gpr.R(a)); + if (indexed) + ADD(32, R(RSCRATCH_EXTRA), gpr.R(b)); + else if (offset) + ADD(32, R(RSCRATCH_EXTRA), Imm32((u32)offset)); + } + // In memcheck mode, don't update the address until the exception check + if (update && !jo.memcheck) + MOV(32, gpr.R(a), R(RSCRATCH_EXTRA)); + // Some games (e.g. Dirt 2) incorrectly set the unused bits which breaks the lookup table code. + // Hence, we need to mask out the unused bits. The layout of the GQR register is + // UU[SCALE]UUUUU[TYPE] where SCALE is 6 bits and TYPE is 3 bits, so we have to AND with + // 0b0011111100000111, or 0x3F07. + MOV(32, R(RSCRATCH2), Imm32(0x3F07)); + AND(32, R(RSCRATCH2), PPCSTATE(spr[SPR_GQR0 + i])); + MOVZX(32, 8, RSCRATCH, R(RSCRATCH2)); - if (w) - { - // One value - CVTSD2SS(XMM0, fpr.R(s)); - CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)asm_routines.singleStoreQuantized)); - } - else - { - // Pair of values - CVTPD2PS(XMM0, fpr.R(s)); - CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)asm_routines.pairedStoreQuantized)); - } + if (w) + { + // One value + CVTSD2SS(XMM0, fpr.R(s)); + CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)asm_routines.singleStoreQuantized)); + } + else + { + // Pair of values + CVTPD2PS(XMM0, fpr.R(s)); + CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)asm_routines.pairedStoreQuantized)); + } - if (update && jo.memcheck) - { - MemoryExceptionCheck(); - if (indexed) - ADD(32, gpr.R(a), gpr.R(b)); - else - ADD(32, gpr.R(a), Imm32((u32)offset)); - } - gpr.UnlockAll(); - gpr.UnlockAllX(); + if (update && jo.memcheck) + { + MemoryExceptionCheck(); + if (indexed) + ADD(32, gpr.R(a), gpr.R(b)); + else + ADD(32, gpr.R(a), Imm32((u32)offset)); + } + gpr.UnlockAll(); + gpr.UnlockAllX(); } void Jit64::psq_lXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStorePairedOff); + INSTRUCTION_START + JITDISABLE(bJITLoadStorePairedOff); - s32 offset = inst.SIMM_12; - bool indexed = inst.OPCD == 4; - bool update = (inst.OPCD == 57 && offset) || (inst.OPCD == 4 && !!(inst.SUBOP6 & 32)); - int a = inst.RA; - int b = indexed ? inst.RB : a; - int s = inst.FS; - int i = indexed ? inst.Ix : inst.I; - int w = indexed ? inst.Wx : inst.W; - FALLBACK_IF(!a); + s32 offset = inst.SIMM_12; + bool indexed = inst.OPCD == 4; + bool update = (inst.OPCD == 57 && offset) || (inst.OPCD == 4 && !!(inst.SUBOP6 & 32)); + int a = inst.RA; + int b = indexed ? inst.RB : a; + int s = inst.FS; + int i = indexed ? inst.Ix : inst.I; + int w = indexed ? inst.Wx : inst.W; + FALLBACK_IF(!a); - gpr.Lock(a, b); - if (js.assumeNoPairedQuantize) - { - s32 loadOffset = 0; - gpr.BindToRegister(a, true, update); - X64Reg addr = gpr.RX(a); - if (update && jo.memcheck) - { - addr = RSCRATCH2; - MOV(32, R(addr), gpr.R(a)); - } - if (indexed) - { - if (update) - { - ADD(32, R(addr), gpr.R(b)); - } - else - { - addr = RSCRATCH2; - if (a && gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg()) - { - LEA(32, addr, MRegSum(gpr.RX(a), gpr.RX(b))); - } - else - { - MOV(32, R(addr), gpr.R(b)); - if (a) - ADD(32, R(addr), gpr.R(a)); - } - } - } - else - { - if (update) - ADD(32, R(addr), Imm32(offset)); - else - loadOffset = offset; - } + gpr.Lock(a, b); + if (js.assumeNoPairedQuantize) + { + s32 loadOffset = 0; + gpr.BindToRegister(a, true, update); + X64Reg addr = gpr.RX(a); + if (update && jo.memcheck) + { + addr = RSCRATCH2; + MOV(32, R(addr), gpr.R(a)); + } + if (indexed) + { + if (update) + { + ADD(32, R(addr), gpr.R(b)); + } + else + { + addr = RSCRATCH2; + if (a && gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg()) + { + LEA(32, addr, MRegSum(gpr.RX(a), gpr.RX(b))); + } + else + { + MOV(32, R(addr), gpr.R(b)); + if (a) + ADD(32, R(addr), gpr.R(a)); + } + } + } + else + { + if (update) + ADD(32, R(addr), Imm32(offset)); + else + loadOffset = offset; + } - fpr.Lock(s); - if (jo.memcheck) - { - fpr.StoreFromRegister(s); - js.revertFprLoad = s; - } - fpr.BindToRegister(s, false); + fpr.Lock(s); + if (jo.memcheck) + { + fpr.StoreFromRegister(s); + js.revertFprLoad = s; + } + fpr.BindToRegister(s, false); - // Let's mirror the JitAsmCommon code and assume all non-MMU loads go to RAM. - if (!jo.memcheck) - { - if (w) - { - if (cpu_info.bSSSE3) - { - MOVD_xmm(XMM0, MComplex(RMEM, addr, SCALE_1, loadOffset)); - PSHUFB(XMM0, M(pbswapShuffle1x4)); - UNPCKLPS(XMM0, M(m_one)); - } - else - { - LoadAndSwap(32, RSCRATCH, MComplex(RMEM, addr, SCALE_1, loadOffset)); - MOVD_xmm(XMM0, R(RSCRATCH)); - UNPCKLPS(XMM0, M(m_one)); - } - } - else - { - if (cpu_info.bSSSE3) - { - MOVQ_xmm(XMM0, MComplex(RMEM, addr, SCALE_1, loadOffset)); - PSHUFB(XMM0, M(pbswapShuffle2x4)); - } - else - { - LoadAndSwap(64, RSCRATCH, MComplex(RMEM, addr, SCALE_1, loadOffset)); - ROL(64, R(RSCRATCH), Imm8(32)); - MOVQ_xmm(XMM0, R(RSCRATCH)); - } - } - CVTPS2PD(fpr.RX(s), R(XMM0)); - } - else - { - BitSet32 registersInUse = CallerSavedRegistersInUse(); - registersInUse[fpr.RX(s) << 16] = false; - if (update) - registersInUse[addr] = true; - SafeLoadToReg(RSCRATCH, R(addr), w ? 32 : 64, loadOffset, registersInUse, false); - MemoryExceptionCheck(); - if (w) - { - MOVD_xmm(XMM0, R(RSCRATCH)); - UNPCKLPS(XMM0, M(m_one)); - } - else - { - ROL(64, R(RSCRATCH), Imm8(32)); - MOVQ_xmm(XMM0, R(RSCRATCH)); - } - CVTPS2PD(fpr.RX(s), R(XMM0)); - if (update) - MOV(32, gpr.R(a), R(addr)); - } - gpr.UnlockAll(); - fpr.UnlockAll(); - return; - } - gpr.FlushLockX(RSCRATCH_EXTRA); - gpr.BindToRegister(a, true, update); - fpr.BindToRegister(s, false, true); - if (gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg() && (indexed || offset)) - { - if (indexed) - LEA(32, RSCRATCH_EXTRA, MRegSum(gpr.RX(a), gpr.RX(b))); - else - LEA(32, RSCRATCH_EXTRA, MDisp(gpr.RX(a), offset)); - } - else - { - MOV(32, R(RSCRATCH_EXTRA), gpr.R(a)); - if (indexed) - ADD(32, R(RSCRATCH_EXTRA), gpr.R(b)); - else if (offset) - ADD(32, R(RSCRATCH_EXTRA), Imm32((u32)offset)); - } - // In memcheck mode, don't update the address until the exception check - if (update && !jo.memcheck) - MOV(32, gpr.R(a), R(RSCRATCH_EXTRA)); - MOV(32, R(RSCRATCH2), Imm32(0x3F07)); + // Let's mirror the JitAsmCommon code and assume all non-MMU loads go to RAM. + if (!jo.memcheck) + { + if (w) + { + if (cpu_info.bSSSE3) + { + MOVD_xmm(XMM0, MComplex(RMEM, addr, SCALE_1, loadOffset)); + PSHUFB(XMM0, M(pbswapShuffle1x4)); + UNPCKLPS(XMM0, M(m_one)); + } + else + { + LoadAndSwap(32, RSCRATCH, MComplex(RMEM, addr, SCALE_1, loadOffset)); + MOVD_xmm(XMM0, R(RSCRATCH)); + UNPCKLPS(XMM0, M(m_one)); + } + } + else + { + if (cpu_info.bSSSE3) + { + MOVQ_xmm(XMM0, MComplex(RMEM, addr, SCALE_1, loadOffset)); + PSHUFB(XMM0, M(pbswapShuffle2x4)); + } + else + { + LoadAndSwap(64, RSCRATCH, MComplex(RMEM, addr, SCALE_1, loadOffset)); + ROL(64, R(RSCRATCH), Imm8(32)); + MOVQ_xmm(XMM0, R(RSCRATCH)); + } + } + CVTPS2PD(fpr.RX(s), R(XMM0)); + } + else + { + BitSet32 registersInUse = CallerSavedRegistersInUse(); + registersInUse[fpr.RX(s) << 16] = false; + if (update) + registersInUse[addr] = true; + SafeLoadToReg(RSCRATCH, R(addr), w ? 32 : 64, loadOffset, registersInUse, false); + MemoryExceptionCheck(); + if (w) + { + MOVD_xmm(XMM0, R(RSCRATCH)); + UNPCKLPS(XMM0, M(m_one)); + } + else + { + ROL(64, R(RSCRATCH), Imm8(32)); + MOVQ_xmm(XMM0, R(RSCRATCH)); + } + CVTPS2PD(fpr.RX(s), R(XMM0)); + if (update) + MOV(32, gpr.R(a), R(addr)); + } + gpr.UnlockAll(); + fpr.UnlockAll(); + return; + } + gpr.FlushLockX(RSCRATCH_EXTRA); + gpr.BindToRegister(a, true, update); + fpr.BindToRegister(s, false, true); + if (gpr.R(a).IsSimpleReg() && gpr.R(b).IsSimpleReg() && (indexed || offset)) + { + if (indexed) + LEA(32, RSCRATCH_EXTRA, MRegSum(gpr.RX(a), gpr.RX(b))); + else + LEA(32, RSCRATCH_EXTRA, MDisp(gpr.RX(a), offset)); + } + else + { + MOV(32, R(RSCRATCH_EXTRA), gpr.R(a)); + if (indexed) + ADD(32, R(RSCRATCH_EXTRA), gpr.R(b)); + else if (offset) + ADD(32, R(RSCRATCH_EXTRA), Imm32((u32)offset)); + } + // In memcheck mode, don't update the address until the exception check + if (update && !jo.memcheck) + MOV(32, gpr.R(a), R(RSCRATCH_EXTRA)); + MOV(32, R(RSCRATCH2), Imm32(0x3F07)); - // Get the high part of the GQR register - OpArg gqr = PPCSTATE(spr[SPR_GQR0 + i]); - gqr.AddMemOffset(2); + // Get the high part of the GQR register + OpArg gqr = PPCSTATE(spr[SPR_GQR0 + i]); + gqr.AddMemOffset(2); - AND(32, R(RSCRATCH2), gqr); - MOVZX(32, 8, RSCRATCH, R(RSCRATCH2)); + AND(32, R(RSCRATCH2), gqr); + MOVZX(32, 8, RSCRATCH, R(RSCRATCH2)); - CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)(&asm_routines.pairedLoadQuantized[w * 8]))); + CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)(&asm_routines.pairedLoadQuantized[w * 8]))); - MemoryExceptionCheck(); - CVTPS2PD(fpr.RX(s), R(XMM0)); - if (update && jo.memcheck) - { - if (indexed) - ADD(32, gpr.R(a), gpr.R(b)); - else - ADD(32, gpr.R(a), Imm32((u32)offset)); - } + MemoryExceptionCheck(); + CVTPS2PD(fpr.RX(s), R(XMM0)); + if (update && jo.memcheck) + { + if (indexed) + ADD(32, gpr.R(a), gpr.R(b)); + else + ADD(32, gpr.R(a), Imm32((u32)offset)); + } - gpr.UnlockAll(); - gpr.UnlockAllX(); + gpr.UnlockAll(); + gpr.UnlockAllX(); } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Paired.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Paired.cpp index 0ee03cf905..4cd1de68a0 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Paired.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Paired.cpp @@ -2,204 +2,202 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Common/CommonTypes.h" +#include "Core/PowerPC/Jit64/Jit.h" #include "Common/CPUDetect.h" +#include "Common/CommonTypes.h" #include "Common/MsgHandler.h" #include "Common/x64Emitter.h" #include "Core/ConfigManager.h" -#include "Core/PowerPC/Jit64/Jit.h" #include "Core/PowerPC/Jit64/JitRegCache.h" using namespace Gen; void Jit64::ps_mr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITPairedOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); - int d = inst.FD; - int b = inst.FB; - if (d == b) - return; + int d = inst.FD; + int b = inst.FB; + if (d == b) + return; - fpr.BindToRegister(d, false); - MOVAPD(fpr.RX(d), fpr.R(b)); + fpr.BindToRegister(d, false); + MOVAPD(fpr.RX(d), fpr.R(b)); } void Jit64::ps_sum(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITPairedOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); - int d = inst.FD; - int a = inst.FA; - int b = inst.FB; - int c = inst.FC; - fpr.Lock(a, b, c, d); - OpArg op_a = fpr.R(a); - fpr.BindToRegister(d, d == b || d == c); - X64Reg tmp = XMM1; - MOVDDUP(tmp, op_a); // {a.ps0, a.ps0} - ADDPD(tmp, fpr.R(b)); // {a.ps0 + b.ps0, a.ps0 + b.ps1} - switch (inst.SUBOP5) - { - case 10: // ps_sum0: {a.ps0 + b.ps1, c.ps1} - UNPCKHPD(tmp, fpr.R(c)); - break; - case 11: // ps_sum1: {c.ps0, a.ps0 + b.ps1} - if (fpr.R(c).IsSimpleReg()) - { - if (cpu_info.bSSE4_1) - { - BLENDPD(tmp, fpr.R(c), 1); - } - else - { - MOVAPD(XMM0, fpr.R(c)); - SHUFPD(XMM0, R(tmp), 2); - tmp = XMM0; - } - } - else - { - MOVLPD(tmp, fpr.R(c)); - } - break; - default: - PanicAlert("ps_sum WTF!!!"); - } - HandleNaNs(inst, fpr.RX(d), tmp, tmp == XMM1 ? XMM0 : XMM1); - ForceSinglePrecision(fpr.RX(d), fpr.R(d)); - SetFPRFIfNeeded(fpr.RX(d)); - fpr.UnlockAll(); + int d = inst.FD; + int a = inst.FA; + int b = inst.FB; + int c = inst.FC; + fpr.Lock(a, b, c, d); + OpArg op_a = fpr.R(a); + fpr.BindToRegister(d, d == b || d == c); + X64Reg tmp = XMM1; + MOVDDUP(tmp, op_a); // {a.ps0, a.ps0} + ADDPD(tmp, fpr.R(b)); // {a.ps0 + b.ps0, a.ps0 + b.ps1} + switch (inst.SUBOP5) + { + case 10: // ps_sum0: {a.ps0 + b.ps1, c.ps1} + UNPCKHPD(tmp, fpr.R(c)); + break; + case 11: // ps_sum1: {c.ps0, a.ps0 + b.ps1} + if (fpr.R(c).IsSimpleReg()) + { + if (cpu_info.bSSE4_1) + { + BLENDPD(tmp, fpr.R(c), 1); + } + else + { + MOVAPD(XMM0, fpr.R(c)); + SHUFPD(XMM0, R(tmp), 2); + tmp = XMM0; + } + } + else + { + MOVLPD(tmp, fpr.R(c)); + } + break; + default: + PanicAlert("ps_sum WTF!!!"); + } + HandleNaNs(inst, fpr.RX(d), tmp, tmp == XMM1 ? XMM0 : XMM1); + ForceSinglePrecision(fpr.RX(d), fpr.R(d)); + SetFPRFIfNeeded(fpr.RX(d)); + fpr.UnlockAll(); } - void Jit64::ps_muls(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITPairedOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); - int d = inst.FD; - int a = inst.FA; - int c = inst.FC; - bool round_input = !jit->js.op->fprIsSingle[c]; - fpr.Lock(a, c, d); - switch (inst.SUBOP5) - { - case 12: // ps_muls0 - MOVDDUP(XMM1, fpr.R(c)); - break; - case 13: // ps_muls1 - avx_op(&XEmitter::VSHUFPD, &XEmitter::SHUFPD, XMM1, fpr.R(c), fpr.R(c), 3); - break; - default: - PanicAlert("ps_muls WTF!!!"); - } - if (round_input) - Force25BitPrecision(XMM1, R(XMM1), XMM0); - MULPD(XMM1, fpr.R(a)); - fpr.BindToRegister(d, false); - HandleNaNs(inst, fpr.RX(d), XMM1); - ForceSinglePrecision(fpr.RX(d), fpr.R(d)); - SetFPRFIfNeeded(fpr.RX(d)); - fpr.UnlockAll(); + int d = inst.FD; + int a = inst.FA; + int c = inst.FC; + bool round_input = !jit->js.op->fprIsSingle[c]; + fpr.Lock(a, c, d); + switch (inst.SUBOP5) + { + case 12: // ps_muls0 + MOVDDUP(XMM1, fpr.R(c)); + break; + case 13: // ps_muls1 + avx_op(&XEmitter::VSHUFPD, &XEmitter::SHUFPD, XMM1, fpr.R(c), fpr.R(c), 3); + break; + default: + PanicAlert("ps_muls WTF!!!"); + } + if (round_input) + Force25BitPrecision(XMM1, R(XMM1), XMM0); + MULPD(XMM1, fpr.R(a)); + fpr.BindToRegister(d, false); + HandleNaNs(inst, fpr.RX(d), XMM1); + ForceSinglePrecision(fpr.RX(d), fpr.R(d)); + SetFPRFIfNeeded(fpr.RX(d)); + fpr.UnlockAll(); } - void Jit64::ps_mergeXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITPairedOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); - int d = inst.FD; - int a = inst.FA; - int b = inst.FB; - fpr.Lock(a, b, d); - fpr.BindToRegister(d, d == a || d == b); + int d = inst.FD; + int a = inst.FA; + int b = inst.FB; + fpr.Lock(a, b, d); + fpr.BindToRegister(d, d == a || d == b); - switch (inst.SUBOP10) - { - case 528: - avx_op(&XEmitter::VUNPCKLPD, &XEmitter::UNPCKLPD, fpr.RX(d), fpr.R(a), fpr.R(b)); - break; //00 - case 560: - avx_op(&XEmitter::VSHUFPD, &XEmitter::SHUFPD, fpr.RX(d), fpr.R(a), fpr.R(b), 2); - break; //01 - case 592: - avx_op(&XEmitter::VSHUFPD, &XEmitter::SHUFPD, fpr.RX(d), fpr.R(a), fpr.R(b), 1); - break; //10 - case 624: - avx_op(&XEmitter::VUNPCKHPD, &XEmitter::UNPCKHPD, fpr.RX(d), fpr.R(a), fpr.R(b)); - break; //11 - default: - _assert_msg_(DYNA_REC, 0, "ps_merge - invalid op"); - } - fpr.UnlockAll(); + switch (inst.SUBOP10) + { + case 528: + avx_op(&XEmitter::VUNPCKLPD, &XEmitter::UNPCKLPD, fpr.RX(d), fpr.R(a), fpr.R(b)); + break; // 00 + case 560: + avx_op(&XEmitter::VSHUFPD, &XEmitter::SHUFPD, fpr.RX(d), fpr.R(a), fpr.R(b), 2); + break; // 01 + case 592: + avx_op(&XEmitter::VSHUFPD, &XEmitter::SHUFPD, fpr.RX(d), fpr.R(a), fpr.R(b), 1); + break; // 10 + case 624: + avx_op(&XEmitter::VUNPCKHPD, &XEmitter::UNPCKHPD, fpr.RX(d), fpr.R(a), fpr.R(b)); + break; // 11 + default: + _assert_msg_(DYNA_REC, 0, "ps_merge - invalid op"); + } + fpr.UnlockAll(); } void Jit64::ps_rsqrte(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); - int b = inst.FB; - int d = inst.FD; + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + int b = inst.FB; + int d = inst.FD; - gpr.FlushLockX(RSCRATCH_EXTRA); - fpr.Lock(b, d); - fpr.BindToRegister(b, true, false); - fpr.BindToRegister(d, false); + gpr.FlushLockX(RSCRATCH_EXTRA); + fpr.Lock(b, d); + fpr.BindToRegister(b, true, false); + fpr.BindToRegister(d, false); - MOVSD(XMM0, fpr.R(b)); - CALL(asm_routines.frsqrte); - MOVSD(fpr.R(d), XMM0); + MOVSD(XMM0, fpr.R(b)); + CALL(asm_routines.frsqrte); + MOVSD(fpr.R(d), XMM0); - MOVHLPS(XMM0, fpr.RX(b)); - CALL(asm_routines.frsqrte); - MOVLHPS(fpr.RX(d), XMM0); + MOVHLPS(XMM0, fpr.RX(b)); + CALL(asm_routines.frsqrte); + MOVLHPS(fpr.RX(d), XMM0); - ForceSinglePrecision(fpr.RX(d), fpr.R(d)); - SetFPRFIfNeeded(fpr.RX(d)); - fpr.UnlockAll(); - gpr.UnlockAllX(); + ForceSinglePrecision(fpr.RX(d), fpr.R(d)); + SetFPRFIfNeeded(fpr.RX(d)); + fpr.UnlockAll(); + gpr.UnlockAllX(); } void Jit64::ps_res(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); - int b = inst.FB; - int d = inst.FD; + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + int b = inst.FB; + int d = inst.FD; - gpr.FlushLockX(RSCRATCH_EXTRA); - fpr.Lock(b, d); - fpr.BindToRegister(b, true, false); - fpr.BindToRegister(d, false); + gpr.FlushLockX(RSCRATCH_EXTRA); + fpr.Lock(b, d); + fpr.BindToRegister(b, true, false); + fpr.BindToRegister(d, false); - MOVSD(XMM0, fpr.R(b)); - CALL(asm_routines.fres); - MOVSD(fpr.R(d), XMM0); + MOVSD(XMM0, fpr.R(b)); + CALL(asm_routines.fres); + MOVSD(fpr.R(d), XMM0); - MOVHLPS(XMM0, fpr.RX(b)); - CALL(asm_routines.fres); - MOVLHPS(fpr.RX(d), XMM0); + MOVHLPS(XMM0, fpr.RX(b)); + CALL(asm_routines.fres); + MOVLHPS(fpr.RX(d), XMM0); - ForceSinglePrecision(fpr.RX(d), fpr.R(d)); - SetFPRFIfNeeded(fpr.RX(d)); - fpr.UnlockAll(); - gpr.UnlockAllX(); + ForceSinglePrecision(fpr.RX(d), fpr.R(d)); + SetFPRFIfNeeded(fpr.RX(d)); + fpr.UnlockAll(); + gpr.UnlockAllX(); } void Jit64::ps_cmpXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); - FloatCompare(inst, !!(inst.SUBOP10 & 64)); + FloatCompare(inst, !!(inst.SUBOP10 & 64)); } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp index 224b4501ad..eeeb91024f 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -2,747 +2,755 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/Jit64/Jit.h" #include "Common/BitSet.h" #include "Common/CommonTypes.h" #include "Common/x64Emitter.h" #include "Core/CoreTiming.h" #include "Core/HW/ProcessorInterface.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/Jit64/Jit.h" #include "Core/PowerPC/Jit64/JitRegCache.h" #include "Core/PowerPC/JitCommon/Jit_Util.h" +#include "Core/PowerPC/PowerPC.h" using namespace Gen; void Jit64::GetCRFieldBit(int field, int bit, X64Reg out, bool negate) { - switch (bit) - { - case CR_SO_BIT: // check bit 61 set - BT(64, PPCSTATE(cr_val[field]), Imm8(61)); - SETcc(negate ? CC_NC : CC_C, R(out)); - break; + switch (bit) + { + case CR_SO_BIT: // check bit 61 set + BT(64, PPCSTATE(cr_val[field]), Imm8(61)); + SETcc(negate ? CC_NC : CC_C, R(out)); + break; - case CR_EQ_BIT: // check bits 31-0 == 0 - CMP(32, PPCSTATE(cr_val[field]), Imm8(0)); - SETcc(negate ? CC_NZ : CC_Z, R(out)); - break; + case CR_EQ_BIT: // check bits 31-0 == 0 + CMP(32, PPCSTATE(cr_val[field]), Imm8(0)); + SETcc(negate ? CC_NZ : CC_Z, R(out)); + break; - case CR_GT_BIT: // check val > 0 - CMP(64, PPCSTATE(cr_val[field]), Imm8(0)); - SETcc(negate ? CC_NG : CC_G, R(out)); - break; + case CR_GT_BIT: // check val > 0 + CMP(64, PPCSTATE(cr_val[field]), Imm8(0)); + SETcc(negate ? CC_NG : CC_G, R(out)); + break; - case CR_LT_BIT: // check bit 62 set - BT(64, PPCSTATE(cr_val[field]), Imm8(62)); - SETcc(negate ? CC_NC : CC_C, R(out)); - break; + case CR_LT_BIT: // check bit 62 set + BT(64, PPCSTATE(cr_val[field]), Imm8(62)); + SETcc(negate ? CC_NC : CC_C, R(out)); + break; - default: - _assert_msg_(DYNA_REC, false, "Invalid CR bit"); - } + default: + _assert_msg_(DYNA_REC, false, "Invalid CR bit"); + } } void Jit64::SetCRFieldBit(int field, int bit, X64Reg in) { - MOV(64, R(RSCRATCH2), PPCSTATE(cr_val[field])); - MOVZX(32, 8, in, R(in)); + MOV(64, R(RSCRATCH2), PPCSTATE(cr_val[field])); + MOVZX(32, 8, in, R(in)); - // Gross but necessary; if the input is totally zero and we set SO or LT, - // or even just add the (1<<32), GT will suddenly end up set without us - // intending to. This can break actual games, so fix it up. - if (bit != CR_GT_BIT) - { - TEST(64, R(RSCRATCH2), R(RSCRATCH2)); - FixupBranch dont_clear_gt = J_CC(CC_NZ); - BTS(64, R(RSCRATCH2), Imm8(63)); - SetJumpTarget(dont_clear_gt); - } + // Gross but necessary; if the input is totally zero and we set SO or LT, + // or even just add the (1<<32), GT will suddenly end up set without us + // intending to. This can break actual games, so fix it up. + if (bit != CR_GT_BIT) + { + TEST(64, R(RSCRATCH2), R(RSCRATCH2)); + FixupBranch dont_clear_gt = J_CC(CC_NZ); + BTS(64, R(RSCRATCH2), Imm8(63)); + SetJumpTarget(dont_clear_gt); + } - switch (bit) - { - case CR_SO_BIT: // set bit 61 to input - BTR(64, R(RSCRATCH2), Imm8(61)); - SHL(64, R(in), Imm8(61)); - OR(64, R(RSCRATCH2), R(in)); - break; + switch (bit) + { + case CR_SO_BIT: // set bit 61 to input + BTR(64, R(RSCRATCH2), Imm8(61)); + SHL(64, R(in), Imm8(61)); + OR(64, R(RSCRATCH2), R(in)); + break; - case CR_EQ_BIT: // clear low 32 bits, set bit 0 to !input - SHR(64, R(RSCRATCH2), Imm8(32)); - SHL(64, R(RSCRATCH2), Imm8(32)); - XOR(32, R(in), Imm8(1)); - OR(64, R(RSCRATCH2), R(in)); - break; + case CR_EQ_BIT: // clear low 32 bits, set bit 0 to !input + SHR(64, R(RSCRATCH2), Imm8(32)); + SHL(64, R(RSCRATCH2), Imm8(32)); + XOR(32, R(in), Imm8(1)); + OR(64, R(RSCRATCH2), R(in)); + break; - case CR_GT_BIT: // set bit 63 to !input - BTR(64, R(RSCRATCH2), Imm8(63)); - NOT(32, R(in)); - SHL(64, R(in), Imm8(63)); - OR(64, R(RSCRATCH2), R(in)); - break; + case CR_GT_BIT: // set bit 63 to !input + BTR(64, R(RSCRATCH2), Imm8(63)); + NOT(32, R(in)); + SHL(64, R(in), Imm8(63)); + OR(64, R(RSCRATCH2), R(in)); + break; - case CR_LT_BIT: // set bit 62 to input - BTR(64, R(RSCRATCH2), Imm8(62)); - SHL(64, R(in), Imm8(62)); - OR(64, R(RSCRATCH2), R(in)); - break; - } + case CR_LT_BIT: // set bit 62 to input + BTR(64, R(RSCRATCH2), Imm8(62)); + SHL(64, R(in), Imm8(62)); + OR(64, R(RSCRATCH2), R(in)); + break; + } - BTS(64, R(RSCRATCH2), Imm8(32)); - MOV(64, PPCSTATE(cr_val[field]), R(RSCRATCH2)); + BTS(64, R(RSCRATCH2), Imm8(32)); + MOV(64, PPCSTATE(cr_val[field]), R(RSCRATCH2)); } void Jit64::ClearCRFieldBit(int field, int bit) { - switch (bit) - { - case CR_SO_BIT: - BTR(64, PPCSTATE(cr_val[field]), Imm8(61)); - break; + switch (bit) + { + case CR_SO_BIT: + BTR(64, PPCSTATE(cr_val[field]), Imm8(61)); + break; - case CR_EQ_BIT: - OR(64, PPCSTATE(cr_val[field]), Imm8(1)); - break; + case CR_EQ_BIT: + OR(64, PPCSTATE(cr_val[field]), Imm8(1)); + break; - case CR_GT_BIT: - BTS(64, PPCSTATE(cr_val[field]), Imm8(63)); - break; + case CR_GT_BIT: + BTS(64, PPCSTATE(cr_val[field]), Imm8(63)); + break; - case CR_LT_BIT: - BTR(64, PPCSTATE(cr_val[field]), Imm8(62)); - break; - } - // We don't need to set bit 32; the cases where that's needed only come up when setting bits, not clearing. + case CR_LT_BIT: + BTR(64, PPCSTATE(cr_val[field]), Imm8(62)); + break; + } + // We don't need to set bit 32; the cases where that's needed only come up when setting bits, not + // clearing. } void Jit64::SetCRFieldBit(int field, int bit) { - MOV(64, R(RSCRATCH), PPCSTATE(cr_val[field])); - if (bit != CR_GT_BIT) - { - TEST(64, R(RSCRATCH), R(RSCRATCH)); - FixupBranch dont_clear_gt = J_CC(CC_NZ); - BTS(64, R(RSCRATCH), Imm8(63)); - SetJumpTarget(dont_clear_gt); - } + MOV(64, R(RSCRATCH), PPCSTATE(cr_val[field])); + if (bit != CR_GT_BIT) + { + TEST(64, R(RSCRATCH), R(RSCRATCH)); + FixupBranch dont_clear_gt = J_CC(CC_NZ); + BTS(64, R(RSCRATCH), Imm8(63)); + SetJumpTarget(dont_clear_gt); + } - switch (bit) - { - case CR_SO_BIT: - BTS(64, PPCSTATE(cr_val[field]), Imm8(61)); - break; + switch (bit) + { + case CR_SO_BIT: + BTS(64, PPCSTATE(cr_val[field]), Imm8(61)); + break; - case CR_EQ_BIT: - SHR(64, R(RSCRATCH), Imm8(32)); - SHL(64, R(RSCRATCH), Imm8(32)); - break; + case CR_EQ_BIT: + SHR(64, R(RSCRATCH), Imm8(32)); + SHL(64, R(RSCRATCH), Imm8(32)); + break; - case CR_GT_BIT: - BTR(64, PPCSTATE(cr_val[field]), Imm8(63)); - break; + case CR_GT_BIT: + BTR(64, PPCSTATE(cr_val[field]), Imm8(63)); + break; - case CR_LT_BIT: - BTS(64, PPCSTATE(cr_val[field]), Imm8(62)); - break; - } + case CR_LT_BIT: + BTS(64, PPCSTATE(cr_val[field]), Imm8(62)); + break; + } - BTS(64, R(RSCRATCH), Imm8(32)); - MOV(64, PPCSTATE(cr_val[field]), R(RSCRATCH)); + BTS(64, R(RSCRATCH), Imm8(32)); + MOV(64, PPCSTATE(cr_val[field]), R(RSCRATCH)); } FixupBranch Jit64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set) { - switch (bit) - { - case CR_SO_BIT: // check bit 61 set - BT(64, PPCSTATE(cr_val[field]), Imm8(61)); - return J_CC(jump_if_set ? CC_C : CC_NC, true); + switch (bit) + { + case CR_SO_BIT: // check bit 61 set + BT(64, PPCSTATE(cr_val[field]), Imm8(61)); + return J_CC(jump_if_set ? CC_C : CC_NC, true); - case CR_EQ_BIT: // check bits 31-0 == 0 - CMP(32, PPCSTATE(cr_val[field]), Imm8(0)); - return J_CC(jump_if_set ? CC_Z : CC_NZ, true); + case CR_EQ_BIT: // check bits 31-0 == 0 + CMP(32, PPCSTATE(cr_val[field]), Imm8(0)); + return J_CC(jump_if_set ? CC_Z : CC_NZ, true); - case CR_GT_BIT: // check val > 0 - CMP(64, PPCSTATE(cr_val[field]), Imm8(0)); - return J_CC(jump_if_set ? CC_G : CC_LE, true); + case CR_GT_BIT: // check val > 0 + CMP(64, PPCSTATE(cr_val[field]), Imm8(0)); + return J_CC(jump_if_set ? CC_G : CC_LE, true); - case CR_LT_BIT: // check bit 62 set - BT(64, PPCSTATE(cr_val[field]), Imm8(62)); - return J_CC(jump_if_set ? CC_C : CC_NC, true); + case CR_LT_BIT: // check bit 62 set + BT(64, PPCSTATE(cr_val[field]), Imm8(62)); + return J_CC(jump_if_set ? CC_C : CC_NC, true); - default: - _assert_msg_(DYNA_REC, false, "Invalid CR bit"); - } + default: + _assert_msg_(DYNA_REC, false, "Invalid CR bit"); + } - // Should never happen. - return FixupBranch(); + // Should never happen. + return FixupBranch(); } static void DoICacheReset() { - PowerPC::ppcState.iCache.Reset(); + PowerPC::ppcState.iCache.Reset(); } void Jit64::mtspr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); - int d = inst.RD; + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); + int d = inst.RD; - switch (iIndex) - { - case SPR_DMAU: + switch (iIndex) + { + case SPR_DMAU: - case SPR_SPRG0: - case SPR_SPRG1: - case SPR_SPRG2: - case SPR_SPRG3: + case SPR_SPRG0: + case SPR_SPRG1: + case SPR_SPRG2: + case SPR_SPRG3: - case SPR_SRR0: - case SPR_SRR1: + case SPR_SRR0: + case SPR_SRR1: - case SPR_LR: - case SPR_CTR: + case SPR_LR: + case SPR_CTR: - case SPR_GQR0: - case SPR_GQR0 + 1: - case SPR_GQR0 + 2: - case SPR_GQR0 + 3: - case SPR_GQR0 + 4: - case SPR_GQR0 + 5: - case SPR_GQR0 + 6: - case SPR_GQR0 + 7: - // These are safe to do the easy way, see the bottom of this function. - break; + case SPR_GQR0: + case SPR_GQR0 + 1: + case SPR_GQR0 + 2: + case SPR_GQR0 + 3: + case SPR_GQR0 + 4: + case SPR_GQR0 + 5: + case SPR_GQR0 + 6: + case SPR_GQR0 + 7: + // These are safe to do the easy way, see the bottom of this function. + break; - case SPR_XER: - gpr.Lock(d); - gpr.BindToRegister(d, true, false); - MOV(32, R(RSCRATCH), gpr.R(d)); - AND(32, R(RSCRATCH), Imm32(0xff7f)); - MOV(16, PPCSTATE(xer_stringctrl), R(RSCRATCH)); + case SPR_XER: + gpr.Lock(d); + gpr.BindToRegister(d, true, false); + MOV(32, R(RSCRATCH), gpr.R(d)); + AND(32, R(RSCRATCH), Imm32(0xff7f)); + MOV(16, PPCSTATE(xer_stringctrl), R(RSCRATCH)); - MOV(32, R(RSCRATCH), gpr.R(d)); - SHR(32, R(RSCRATCH), Imm8(XER_CA_SHIFT)); - AND(8, R(RSCRATCH), Imm8(1)); - MOV(8, PPCSTATE(xer_ca), R(RSCRATCH)); + MOV(32, R(RSCRATCH), gpr.R(d)); + SHR(32, R(RSCRATCH), Imm8(XER_CA_SHIFT)); + AND(8, R(RSCRATCH), Imm8(1)); + MOV(8, PPCSTATE(xer_ca), R(RSCRATCH)); - MOV(32, R(RSCRATCH), gpr.R(d)); - SHR(32, R(RSCRATCH), Imm8(XER_OV_SHIFT)); - MOV(8, PPCSTATE(xer_so_ov), R(RSCRATCH)); - gpr.UnlockAll(); - return; + MOV(32, R(RSCRATCH), gpr.R(d)); + SHR(32, R(RSCRATCH), Imm8(XER_OV_SHIFT)); + MOV(8, PPCSTATE(xer_so_ov), R(RSCRATCH)); + gpr.UnlockAll(); + return; - case SPR_HID0: - { - gpr.BindToRegister(d, true, false); - BTR(32, gpr.R(d), Imm8(31 - 20)); // ICFI - MOV(32, PPCSTATE(spr[iIndex]), gpr.R(d)); - FixupBranch dont_reset_icache = J_CC(CC_NC); - BitSet32 regs = CallerSavedRegistersInUse(); - ABI_PushRegistersAndAdjustStack(regs, 0); - ABI_CallFunction((void*)DoICacheReset); - ABI_PopRegistersAndAdjustStack(regs, 0); - SetJumpTarget(dont_reset_icache); - break; - } + case SPR_HID0: + { + gpr.BindToRegister(d, true, false); + BTR(32, gpr.R(d), Imm8(31 - 20)); // ICFI + MOV(32, PPCSTATE(spr[iIndex]), gpr.R(d)); + FixupBranch dont_reset_icache = J_CC(CC_NC); + BitSet32 regs = CallerSavedRegistersInUse(); + ABI_PushRegistersAndAdjustStack(regs, 0); + ABI_CallFunction((void*)DoICacheReset); + ABI_PopRegistersAndAdjustStack(regs, 0); + SetJumpTarget(dont_reset_icache); + break; + } - default: - FALLBACK_IF(true); - } + default: + FALLBACK_IF(true); + } - // OK, this is easy. - if (!gpr.R(d).IsImm()) - { - gpr.Lock(d); - gpr.BindToRegister(d, true, false); - } - MOV(32, PPCSTATE(spr[iIndex]), gpr.R(d)); - gpr.UnlockAll(); + // OK, this is easy. + if (!gpr.R(d).IsImm()) + { + gpr.Lock(d); + gpr.BindToRegister(d, true, false); + } + MOV(32, PPCSTATE(spr[iIndex]), gpr.R(d)); + gpr.UnlockAll(); } void Jit64::mfspr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); - int d = inst.RD; - switch (iIndex) - { - case SPR_TL: - case SPR_TU: - { - // TODO: we really only need to call GetFakeTimeBase once per JIT block; this matters because - // typical use of this instruction is to call it three times, e.g. mftbu/mftbl/mftbu/cmpw/bne - // to deal with possible timer wraparound. This makes the second two (out of three) completely - // redundant for the JIT. - // no register choice + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); + int d = inst.RD; + switch (iIndex) + { + case SPR_TL: + case SPR_TU: + { + // TODO: we really only need to call GetFakeTimeBase once per JIT block; this matters because + // typical use of this instruction is to call it three times, e.g. mftbu/mftbl/mftbu/cmpw/bne + // to deal with possible timer wraparound. This makes the second two (out of three) completely + // redundant for the JIT. + // no register choice - gpr.FlushLockX(RDX, RAX); + gpr.FlushLockX(RDX, RAX); - // An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the - // cost of calling out to C for this is actually significant. - // Scale downcount by the CPU overclocking factor. - CVTSI2SS(XMM0, PPCSTATE(downcount)); - MULSS(XMM0, M(&CoreTiming::g_lastOCFactor_inverted)); - CVTSS2SI(RDX, R(XMM0)); // RDX is downcount scaled by the overclocking factor - MOV(32, R(RAX), M(&CoreTiming::g_slicelength)); - SUB(64, R(RAX), R(RDX)); // cycles since the last CoreTiming::Advance() event is (slicelength - Scaled_downcount) - ADD(64, R(RAX), M(&CoreTiming::g_globalTimer)); - SUB(64, R(RAX), M(&CoreTiming::g_fakeTBStartTicks)); - // It might seem convenient to correct the timer for the block position here for even more accurate - // timing, but as of currently, this can break games. If we end up reading a time *after* the time - // at which an interrupt was supposed to occur, e.g. because we're 100 cycles into a block with only - // 50 downcount remaining, some games don't function correctly, such as Karaoke Party Revolution, - // which won't get past the loading screen. - //if (js.downcountAmount) - // ADD(64, R(RAX), Imm32(js.downcountAmount)); + // An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the + // cost of calling out to C for this is actually significant. + // Scale downcount by the CPU overclocking factor. + CVTSI2SS(XMM0, PPCSTATE(downcount)); + MULSS(XMM0, M(&CoreTiming::g_lastOCFactor_inverted)); + CVTSS2SI(RDX, R(XMM0)); // RDX is downcount scaled by the overclocking factor + MOV(32, R(RAX), M(&CoreTiming::g_slicelength)); + SUB(64, R(RAX), R(RDX)); // cycles since the last CoreTiming::Advance() event is (slicelength - + // Scaled_downcount) + ADD(64, R(RAX), M(&CoreTiming::g_globalTimer)); + SUB(64, R(RAX), M(&CoreTiming::g_fakeTBStartTicks)); + // It might seem convenient to correct the timer for the block position here for even more + // accurate + // timing, but as of currently, this can break games. If we end up reading a time *after* the + // time + // at which an interrupt was supposed to occur, e.g. because we're 100 cycles into a block with + // only + // 50 downcount remaining, some games don't function correctly, such as Karaoke Party + // Revolution, + // which won't get past the loading screen. + // if (js.downcountAmount) + // ADD(64, R(RAX), Imm32(js.downcountAmount)); - // a / 12 = (a * 0xAAAAAAAAAAAAAAAB) >> 67 - MOV(64, R(RDX), Imm64(0xAAAAAAAAAAAAAAABULL)); - MUL(64, R(RDX)); - MOV(64, R(RAX), M(&CoreTiming::g_fakeTBStartValue)); - SHR(64, R(RDX), Imm8(3)); - ADD(64, R(RAX), R(RDX)); - MOV(64, PPCSTATE(spr[SPR_TL]), R(RAX)); + // a / 12 = (a * 0xAAAAAAAAAAAAAAAB) >> 67 + MOV(64, R(RDX), Imm64(0xAAAAAAAAAAAAAAABULL)); + MUL(64, R(RDX)); + MOV(64, R(RAX), M(&CoreTiming::g_fakeTBStartValue)); + SHR(64, R(RDX), Imm8(3)); + ADD(64, R(RAX), R(RDX)); + MOV(64, PPCSTATE(spr[SPR_TL]), R(RAX)); - if (MergeAllowedNextInstructions(1)) - { - const UGeckoInstruction& next = js.op[1].inst; - // Two calls of TU/TL next to each other are extremely common in typical usage, so merge them - // if we can. - u32 nextIndex = (next.SPRU << 5) | (next.SPRL & 0x1F); - // Be careful; the actual opcode is for mftb (371), not mfspr (339) - int n = next.RD; - if (next.OPCD == 31 && next.SUBOP10 == 371 && (nextIndex == SPR_TU || nextIndex == SPR_TL) && n != d) - { - js.downcountAmount++; - js.skipInstructions = 1; - gpr.Lock(d, n); - gpr.BindToRegister(d, false); - gpr.BindToRegister(n, false); - if (iIndex == SPR_TL) - MOV(32, gpr.R(d), R(RAX)); - if (nextIndex == SPR_TL) - MOV(32, gpr.R(n), R(RAX)); - SHR(64, R(RAX), Imm8(32)); - if (iIndex == SPR_TU) - MOV(32, gpr.R(d), R(RAX)); - if (nextIndex == SPR_TU) - MOV(32, gpr.R(n), R(RAX)); - break; - } - } - gpr.Lock(d); - gpr.BindToRegister(d, false); - if (iIndex == SPR_TU) - SHR(64, R(RAX), Imm8(32)); - MOV(32, gpr.R(d), R(RAX)); - break; - } - case SPR_XER: - gpr.Lock(d); - gpr.BindToRegister(d, false); - MOVZX(32, 16, gpr.RX(d), PPCSTATE(xer_stringctrl)); - MOVZX(32, 8, RSCRATCH, PPCSTATE(xer_ca)); - SHL(32, R(RSCRATCH), Imm8(XER_CA_SHIFT)); - OR(32, gpr.R(d), R(RSCRATCH)); + if (MergeAllowedNextInstructions(1)) + { + const UGeckoInstruction& next = js.op[1].inst; + // Two calls of TU/TL next to each other are extremely common in typical usage, so merge them + // if we can. + u32 nextIndex = (next.SPRU << 5) | (next.SPRL & 0x1F); + // Be careful; the actual opcode is for mftb (371), not mfspr (339) + int n = next.RD; + if (next.OPCD == 31 && next.SUBOP10 == 371 && (nextIndex == SPR_TU || nextIndex == SPR_TL) && + n != d) + { + js.downcountAmount++; + js.skipInstructions = 1; + gpr.Lock(d, n); + gpr.BindToRegister(d, false); + gpr.BindToRegister(n, false); + if (iIndex == SPR_TL) + MOV(32, gpr.R(d), R(RAX)); + if (nextIndex == SPR_TL) + MOV(32, gpr.R(n), R(RAX)); + SHR(64, R(RAX), Imm8(32)); + if (iIndex == SPR_TU) + MOV(32, gpr.R(d), R(RAX)); + if (nextIndex == SPR_TU) + MOV(32, gpr.R(n), R(RAX)); + break; + } + } + gpr.Lock(d); + gpr.BindToRegister(d, false); + if (iIndex == SPR_TU) + SHR(64, R(RAX), Imm8(32)); + MOV(32, gpr.R(d), R(RAX)); + break; + } + case SPR_XER: + gpr.Lock(d); + gpr.BindToRegister(d, false); + MOVZX(32, 16, gpr.RX(d), PPCSTATE(xer_stringctrl)); + MOVZX(32, 8, RSCRATCH, PPCSTATE(xer_ca)); + SHL(32, R(RSCRATCH), Imm8(XER_CA_SHIFT)); + OR(32, gpr.R(d), R(RSCRATCH)); - MOVZX(32, 8, RSCRATCH, PPCSTATE(xer_so_ov)); - SHL(32, R(RSCRATCH), Imm8(XER_OV_SHIFT)); - OR(32, gpr.R(d), R(RSCRATCH)); - break; - case SPR_WPAR: - case SPR_DEC: - case SPR_PMC1: - case SPR_PMC2: - case SPR_PMC3: - case SPR_PMC4: - FALLBACK_IF(true); - default: - gpr.Lock(d); - gpr.BindToRegister(d, false); - MOV(32, gpr.R(d), PPCSTATE(spr[iIndex])); - break; - } - gpr.UnlockAllX(); - gpr.UnlockAll(); + MOVZX(32, 8, RSCRATCH, PPCSTATE(xer_so_ov)); + SHL(32, R(RSCRATCH), Imm8(XER_OV_SHIFT)); + OR(32, gpr.R(d), R(RSCRATCH)); + break; + case SPR_WPAR: + case SPR_DEC: + case SPR_PMC1: + case SPR_PMC2: + case SPR_PMC3: + case SPR_PMC4: + FALLBACK_IF(true); + default: + gpr.Lock(d); + gpr.BindToRegister(d, false); + MOV(32, gpr.R(d), PPCSTATE(spr[iIndex])); + break; + } + gpr.UnlockAllX(); + gpr.UnlockAll(); } void Jit64::mtmsr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - if (!gpr.R(inst.RS).IsImm()) - { - gpr.Lock(inst.RS); - gpr.BindToRegister(inst.RS, true, false); - } - MOV(32, PPCSTATE(msr), gpr.R(inst.RS)); - gpr.UnlockAll(); - gpr.Flush(); - fpr.Flush(); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + if (!gpr.R(inst.RS).IsImm()) + { + gpr.Lock(inst.RS); + gpr.BindToRegister(inst.RS, true, false); + } + MOV(32, PPCSTATE(msr), gpr.R(inst.RS)); + gpr.UnlockAll(); + gpr.Flush(); + fpr.Flush(); - // If some exceptions are pending and EE are now enabled, force checking - // external exceptions when going out of mtmsr in order to execute delayed - // interrupts as soon as possible. - TEST(32, PPCSTATE(msr), Imm32(0x8000)); - FixupBranch eeDisabled = J_CC(CC_Z); + // If some exceptions are pending and EE are now enabled, force checking + // external exceptions when going out of mtmsr in order to execute delayed + // interrupts as soon as possible. + TEST(32, PPCSTATE(msr), Imm32(0x8000)); + FixupBranch eeDisabled = J_CC(CC_Z); - TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_EXTERNAL_INT | EXCEPTION_PERFORMANCE_MONITOR | EXCEPTION_DECREMENTER)); - FixupBranch noExceptionsPending = J_CC(CC_Z); + TEST(32, PPCSTATE(Exceptions), + Imm32(EXCEPTION_EXTERNAL_INT | EXCEPTION_PERFORMANCE_MONITOR | EXCEPTION_DECREMENTER)); + FixupBranch noExceptionsPending = J_CC(CC_Z); - // Check if a CP interrupt is waiting and keep the GPU emulation in sync (issue 4336) - TEST(32, M(&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); - FixupBranch cpInt = J_CC(CC_NZ); + // Check if a CP interrupt is waiting and keep the GPU emulation in sync (issue 4336) + TEST(32, M(&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); + FixupBranch cpInt = J_CC(CC_NZ); - MOV(32, PPCSTATE(pc), Imm32(js.compilerPC + 4)); - WriteExternalExceptionExit(); + MOV(32, PPCSTATE(pc), Imm32(js.compilerPC + 4)); + WriteExternalExceptionExit(); - SetJumpTarget(cpInt); - SetJumpTarget(noExceptionsPending); - SetJumpTarget(eeDisabled); + SetJumpTarget(cpInt); + SetJumpTarget(noExceptionsPending); + SetJumpTarget(eeDisabled); - MOV(32, R(RSCRATCH), Imm32(js.compilerPC + 4)); - WriteExitDestInRSCRATCH(); + MOV(32, R(RSCRATCH), Imm32(js.compilerPC + 4)); + WriteExitDestInRSCRATCH(); } void Jit64::mfmsr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - //Privileged? - gpr.Lock(inst.RD); - gpr.BindToRegister(inst.RD, false, true); - MOV(32, gpr.R(inst.RD), PPCSTATE(msr)); - gpr.UnlockAll(); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + // Privileged? + gpr.Lock(inst.RD); + gpr.BindToRegister(inst.RD, false, true); + MOV(32, gpr.R(inst.RD), PPCSTATE(msr)); + gpr.UnlockAll(); } void Jit64::mftb(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - mfspr(inst); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + mfspr(inst); } void Jit64::mfcr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - int d = inst.RD; - gpr.FlushLockX(RSCRATCH_EXTRA); - CALL(asm_routines.mfcr); - gpr.Lock(d); - gpr.BindToRegister(d, false, true); - MOV(32, gpr.R(d), R(RSCRATCH)); - gpr.UnlockAll(); - gpr.UnlockAllX(); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + int d = inst.RD; + gpr.FlushLockX(RSCRATCH_EXTRA); + CALL(asm_routines.mfcr); + gpr.Lock(d); + gpr.BindToRegister(d, false, true); + MOV(32, gpr.R(d), R(RSCRATCH)); + gpr.UnlockAll(); + gpr.UnlockAllX(); } void Jit64::mtcrf(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - // USES_CR - u32 crm = inst.CRM; - if (crm != 0) - { - if (gpr.R(inst.RS).IsImm()) - { - for (int i = 0; i < 8; i++) - { - if ((crm & (0x80 >> i)) != 0) - { - u8 newcr = (gpr.R(inst.RS).Imm32() >> (28 - (i * 4))) & 0xF; - u64 newcrval = PPCCRToInternal(newcr); - if ((s64)newcrval == (s32)newcrval) - { - MOV(64, PPCSTATE(cr_val[i]), Imm32((s32)newcrval)); - } - else - { - MOV(64, R(RSCRATCH), Imm64(newcrval)); - MOV(64, PPCSTATE(cr_val[i]), R(RSCRATCH)); - } - } - } - } - else - { - gpr.Lock(inst.RS); - gpr.BindToRegister(inst.RS, true, false); - for (int i = 0; i < 8; i++) - { - if ((crm & (0x80 >> i)) != 0) - { - MOV(32, R(RSCRATCH), gpr.R(inst.RS)); - if (i != 7) - SHR(32, R(RSCRATCH), Imm8(28 - (i * 4))); - if (i != 0) - AND(32, R(RSCRATCH), Imm8(0xF)); - MOV(64, R(RSCRATCH), MScaled(RSCRATCH, SCALE_8, (u32)(u64)m_crTable)); - MOV(64, PPCSTATE(cr_val[i]), R(RSCRATCH)); - } - } - gpr.UnlockAll(); - } - } + // USES_CR + u32 crm = inst.CRM; + if (crm != 0) + { + if (gpr.R(inst.RS).IsImm()) + { + for (int i = 0; i < 8; i++) + { + if ((crm & (0x80 >> i)) != 0) + { + u8 newcr = (gpr.R(inst.RS).Imm32() >> (28 - (i * 4))) & 0xF; + u64 newcrval = PPCCRToInternal(newcr); + if ((s64)newcrval == (s32)newcrval) + { + MOV(64, PPCSTATE(cr_val[i]), Imm32((s32)newcrval)); + } + else + { + MOV(64, R(RSCRATCH), Imm64(newcrval)); + MOV(64, PPCSTATE(cr_val[i]), R(RSCRATCH)); + } + } + } + } + else + { + gpr.Lock(inst.RS); + gpr.BindToRegister(inst.RS, true, false); + for (int i = 0; i < 8; i++) + { + if ((crm & (0x80 >> i)) != 0) + { + MOV(32, R(RSCRATCH), gpr.R(inst.RS)); + if (i != 7) + SHR(32, R(RSCRATCH), Imm8(28 - (i * 4))); + if (i != 0) + AND(32, R(RSCRATCH), Imm8(0xF)); + MOV(64, R(RSCRATCH), MScaled(RSCRATCH, SCALE_8, (u32)(u64)m_crTable)); + MOV(64, PPCSTATE(cr_val[i]), R(RSCRATCH)); + } + } + gpr.UnlockAll(); + } + } } void Jit64::mcrf(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - // USES_CR - if (inst.CRFS != inst.CRFD) - { - MOV(64, R(RSCRATCH), PPCSTATE(cr_val[inst.CRFS])); - MOV(64, PPCSTATE(cr_val[inst.CRFD]), R(RSCRATCH)); - } + // USES_CR + if (inst.CRFS != inst.CRFD) + { + MOV(64, R(RSCRATCH), PPCSTATE(cr_val[inst.CRFS])); + MOV(64, PPCSTATE(cr_val[inst.CRFD]), R(RSCRATCH)); + } } void Jit64::mcrxr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - // Copy XER[0-3] into CR[inst.CRFD] - MOVZX(32, 8, RSCRATCH, PPCSTATE(xer_ca)); - MOVZX(32, 8, RSCRATCH2, PPCSTATE(xer_so_ov)); - // [0 SO OV CA] - LEA(32, RSCRATCH, MComplex(RSCRATCH, RSCRATCH2, SCALE_2, 0)); - // [SO OV CA 0] << 3 - SHL(32, R(RSCRATCH), Imm8(4)); + // Copy XER[0-3] into CR[inst.CRFD] + MOVZX(32, 8, RSCRATCH, PPCSTATE(xer_ca)); + MOVZX(32, 8, RSCRATCH2, PPCSTATE(xer_so_ov)); + // [0 SO OV CA] + LEA(32, RSCRATCH, MComplex(RSCRATCH, RSCRATCH2, SCALE_2, 0)); + // [SO OV CA 0] << 3 + SHL(32, R(RSCRATCH), Imm8(4)); - MOV(64, R(RSCRATCH), MDisp(RSCRATCH, (u32)(u64)m_crTable)); - MOV(64, PPCSTATE(cr_val[inst.CRFD]), R(RSCRATCH)); + MOV(64, R(RSCRATCH), MDisp(RSCRATCH, (u32)(u64)m_crTable)); + MOV(64, PPCSTATE(cr_val[inst.CRFD]), R(RSCRATCH)); - // Clear XER[0-3] - MOV(8, PPCSTATE(xer_ca), Imm8(0)); - MOV(8, PPCSTATE(xer_so_ov), Imm8(0)); + // Clear XER[0-3] + MOV(8, PPCSTATE(xer_ca), Imm8(0)); + MOV(8, PPCSTATE(xer_so_ov), Imm8(0)); } void Jit64::crXXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - _dbg_assert_msg_(DYNA_REC, inst.OPCD == 19, "Invalid crXXX"); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + _dbg_assert_msg_(DYNA_REC, inst.OPCD == 19, "Invalid crXXX"); - // Special case: crclr - if (inst.CRBA == inst.CRBB && inst.CRBA == inst.CRBD && inst.SUBOP10 == 193) - { - ClearCRFieldBit(inst.CRBD >> 2, 3 - (inst.CRBD & 3)); - return; - } + // Special case: crclr + if (inst.CRBA == inst.CRBB && inst.CRBA == inst.CRBD && inst.SUBOP10 == 193) + { + ClearCRFieldBit(inst.CRBD >> 2, 3 - (inst.CRBD & 3)); + return; + } - // Special case: crset - if (inst.CRBA == inst.CRBB && inst.CRBA == inst.CRBD && inst.SUBOP10 == 289) - { - SetCRFieldBit(inst.CRBD >> 2, 3 - (inst.CRBD & 3)); - return; - } + // Special case: crset + if (inst.CRBA == inst.CRBB && inst.CRBA == inst.CRBD && inst.SUBOP10 == 289) + { + SetCRFieldBit(inst.CRBD >> 2, 3 - (inst.CRBD & 3)); + return; + } - // TODO(delroth): Potential optimizations could be applied here. For - // instance, if the two CR bits being loaded are the same, two loads are - // not required. + // TODO(delroth): Potential optimizations could be applied here. For + // instance, if the two CR bits being loaded are the same, two loads are + // not required. - // creqv or crnand or crnor - bool negateA = inst.SUBOP10 == 289 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33; - // crandc or crorc or crnand or crnor - bool negateB = inst.SUBOP10 == 129 || inst.SUBOP10 == 417 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33; + // creqv or crnand or crnor + bool negateA = inst.SUBOP10 == 289 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33; + // crandc or crorc or crnand or crnor + bool negateB = + inst.SUBOP10 == 129 || inst.SUBOP10 == 417 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33; - GetCRFieldBit(inst.CRBA >> 2, 3 - (inst.CRBA & 3), RSCRATCH, negateA); - GetCRFieldBit(inst.CRBB >> 2, 3 - (inst.CRBB & 3), RSCRATCH2, negateB); + GetCRFieldBit(inst.CRBA >> 2, 3 - (inst.CRBA & 3), RSCRATCH, negateA); + GetCRFieldBit(inst.CRBB >> 2, 3 - (inst.CRBB & 3), RSCRATCH2, negateB); - // Compute combined bit - switch (inst.SUBOP10) - { - case 33: // crnor: ~(A || B) == (~A && ~B) - case 129: // crandc: A && ~B - case 257: // crand: A && B - AND(8, R(RSCRATCH), R(RSCRATCH2)); - break; + // Compute combined bit + switch (inst.SUBOP10) + { + case 33: // crnor: ~(A || B) == (~A && ~B) + case 129: // crandc: A && ~B + case 257: // crand: A && B + AND(8, R(RSCRATCH), R(RSCRATCH2)); + break; - case 193: // crxor: A ^ B - case 289: // creqv: ~(A ^ B) = ~A ^ B - XOR(8, R(RSCRATCH), R(RSCRATCH2)); - break; + case 193: // crxor: A ^ B + case 289: // creqv: ~(A ^ B) = ~A ^ B + XOR(8, R(RSCRATCH), R(RSCRATCH2)); + break; - case 225: // crnand: ~(A && B) == (~A || ~B) - case 417: // crorc: A || ~B - case 449: // cror: A || B - OR(8, R(RSCRATCH), R(RSCRATCH2)); - break; - } + case 225: // crnand: ~(A && B) == (~A || ~B) + case 417: // crorc: A || ~B + case 449: // cror: A || B + OR(8, R(RSCRATCH), R(RSCRATCH2)); + break; + } - // Store result bit in CRBD - SetCRFieldBit(inst.CRBD >> 2, 3 - (inst.CRBD & 3), RSCRATCH); + // Store result bit in CRBD + SetCRFieldBit(inst.CRBD >> 2, 3 - (inst.CRBD & 3), RSCRATCH); } void Jit64::mcrfs(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - u8 shift = 4 * (7 - inst.CRFS); - u32 mask = 0xF << shift; + u8 shift = 4 * (7 - inst.CRFS); + u32 mask = 0xF << shift; - // Only clear exception bits (but not FEX/VX). - mask &= 0x9FF87000; + // Only clear exception bits (but not FEX/VX). + mask &= 0x9FF87000; - MOV(32, R(RSCRATCH), PPCSTATE(fpscr)); - if (cpu_info.bBMI1) - { - MOV(32, R(RSCRATCH2), Imm32((4 << 8) | shift)); - BEXTR(32, RSCRATCH2, R(RSCRATCH), RSCRATCH2); - } - else - { - MOV(32, R(RSCRATCH2), R(RSCRATCH)); - SHR(32, R(RSCRATCH2), Imm8(shift)); - AND(32, R(RSCRATCH2), Imm32(0xF)); - } - AND(32, R(RSCRATCH), Imm32(mask)); - MOV(32, PPCSTATE(fpscr), R(RSCRATCH)); - LEA(64, RSCRATCH, M(&m_crTable)); - MOV(64, R(RSCRATCH), MComplex(RSCRATCH, RSCRATCH2, SCALE_8, 0)); - MOV(64, PPCSTATE(cr_val[inst.CRFD]), R(RSCRATCH)); + MOV(32, R(RSCRATCH), PPCSTATE(fpscr)); + if (cpu_info.bBMI1) + { + MOV(32, R(RSCRATCH2), Imm32((4 << 8) | shift)); + BEXTR(32, RSCRATCH2, R(RSCRATCH), RSCRATCH2); + } + else + { + MOV(32, R(RSCRATCH2), R(RSCRATCH)); + SHR(32, R(RSCRATCH2), Imm8(shift)); + AND(32, R(RSCRATCH2), Imm32(0xF)); + } + AND(32, R(RSCRATCH), Imm32(mask)); + MOV(32, PPCSTATE(fpscr), R(RSCRATCH)); + LEA(64, RSCRATCH, M(&m_crTable)); + MOV(64, R(RSCRATCH), MComplex(RSCRATCH, RSCRATCH2, SCALE_8, 0)); + MOV(64, PPCSTATE(cr_val[inst.CRFD]), R(RSCRATCH)); } void Jit64::mffsx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + FALLBACK_IF(inst.Rc); - MOV(32, R(RSCRATCH), PPCSTATE(fpscr)); + MOV(32, R(RSCRATCH), PPCSTATE(fpscr)); - // FPSCR.FEX = 0 (and VX for below) - AND(32, R(RSCRATCH), Imm32(~0x60000000)); + // FPSCR.FEX = 0 (and VX for below) + AND(32, R(RSCRATCH), Imm32(~0x60000000)); - // FPSCR.VX = (FPSCR.Hex & FPSCR_VX_ANY) != 0; - XOR(32, R(RSCRATCH2), R(RSCRATCH2)); - TEST(32, R(RSCRATCH), Imm32(FPSCR_VX_ANY)); - SETcc(CC_NZ, R(RSCRATCH2)); - SHL(32, R(RSCRATCH2), Imm8(31 - 2)); - OR(32, R(RSCRATCH), R(RSCRATCH2)); + // FPSCR.VX = (FPSCR.Hex & FPSCR_VX_ANY) != 0; + XOR(32, R(RSCRATCH2), R(RSCRATCH2)); + TEST(32, R(RSCRATCH), Imm32(FPSCR_VX_ANY)); + SETcc(CC_NZ, R(RSCRATCH2)); + SHL(32, R(RSCRATCH2), Imm8(31 - 2)); + OR(32, R(RSCRATCH), R(RSCRATCH2)); - MOV(32, PPCSTATE(fpscr), R(RSCRATCH)); + MOV(32, PPCSTATE(fpscr), R(RSCRATCH)); - int d = inst.FD; - fpr.BindToRegister(d, false, true); - MOV(64, R(RSCRATCH2), Imm64(0xFFF8000000000000)); - OR(64, R(RSCRATCH), R(RSCRATCH2)); - MOVQ_xmm(XMM0, R(RSCRATCH)); - MOVSD(fpr.RX(d), R(XMM0)); + int d = inst.FD; + fpr.BindToRegister(d, false, true); + MOV(64, R(RSCRATCH2), Imm64(0xFFF8000000000000)); + OR(64, R(RSCRATCH), R(RSCRATCH2)); + MOVQ_xmm(XMM0, R(RSCRATCH)); + MOVSD(fpr.RX(d), R(XMM0)); } // MXCSR = s_fpscr_to_mxcsr[FPSCR & 7] static const u32 s_fpscr_to_mxcsr[] = { - 0x1F80, 0x7F80, 0x5F80, 0x3F80, - 0x9F80, 0xFF80, 0xDF80, 0xBF80, + 0x1F80, 0x7F80, 0x5F80, 0x3F80, 0x9F80, 0xFF80, 0xDF80, 0xBF80, }; // Needs value of FPSCR in RSCRATCH. void Jit64::UpdateMXCSR() { - LEA(64, RSCRATCH2, M(&s_fpscr_to_mxcsr)); - AND(32, R(RSCRATCH), Imm32(7)); - LDMXCSR(MComplex(RSCRATCH2, RSCRATCH, SCALE_4, 0)); + LEA(64, RSCRATCH2, M(&s_fpscr_to_mxcsr)); + AND(32, R(RSCRATCH), Imm32(7)); + LDMXCSR(MComplex(RSCRATCH2, RSCRATCH, SCALE_4, 0)); } void Jit64::mtfsb0x(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + FALLBACK_IF(inst.Rc); - u32 mask= ~(0x80000000 >> inst.CRBD); - if (inst.CRBD < 29) - { - AND(32, PPCSTATE(fpscr), Imm32(mask)); - } - else - { - MOV(32, R(RSCRATCH), PPCSTATE(fpscr)); - AND(32, R(RSCRATCH), Imm32(mask)); - MOV(32, PPCSTATE(fpscr), R(RSCRATCH)); - UpdateMXCSR(); - } + u32 mask = ~(0x80000000 >> inst.CRBD); + if (inst.CRBD < 29) + { + AND(32, PPCSTATE(fpscr), Imm32(mask)); + } + else + { + MOV(32, R(RSCRATCH), PPCSTATE(fpscr)); + AND(32, R(RSCRATCH), Imm32(mask)); + MOV(32, PPCSTATE(fpscr), R(RSCRATCH)); + UpdateMXCSR(); + } } void Jit64::mtfsb1x(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + FALLBACK_IF(inst.Rc); - u32 mask = 0x80000000 >> inst.CRBD; - MOV(32, R(RSCRATCH), PPCSTATE(fpscr)); - if (mask & FPSCR_ANY_X) - { - BTS(32, R(RSCRATCH), Imm32(31 - inst.CRBD)); - FixupBranch dont_set_fx = J_CC(CC_C); - OR(32, R(RSCRATCH), Imm32(1u << 31)); - SetJumpTarget(dont_set_fx); - } - else - { - OR(32, R(RSCRATCH), Imm32(mask)); - } - MOV(32, PPCSTATE(fpscr), R(RSCRATCH)); - if (inst.CRBD >= 29) - UpdateMXCSR(); + u32 mask = 0x80000000 >> inst.CRBD; + MOV(32, R(RSCRATCH), PPCSTATE(fpscr)); + if (mask & FPSCR_ANY_X) + { + BTS(32, R(RSCRATCH), Imm32(31 - inst.CRBD)); + FixupBranch dont_set_fx = J_CC(CC_C); + OR(32, R(RSCRATCH), Imm32(1u << 31)); + SetJumpTarget(dont_set_fx); + } + else + { + OR(32, R(RSCRATCH), Imm32(mask)); + } + MOV(32, PPCSTATE(fpscr), R(RSCRATCH)); + if (inst.CRBD >= 29) + UpdateMXCSR(); } void Jit64::mtfsfix(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + FALLBACK_IF(inst.Rc); - u8 imm = (inst.hex >> (31 - 19)) & 0xF; - u32 or_mask = imm << (28 - 4 * inst.CRFD); - u32 and_mask = ~(0xF0000000 >> (4 * inst.CRFD)); + u8 imm = (inst.hex >> (31 - 19)) & 0xF; + u32 or_mask = imm << (28 - 4 * inst.CRFD); + u32 and_mask = ~(0xF0000000 >> (4 * inst.CRFD)); - MOV(32, R(RSCRATCH), PPCSTATE(fpscr)); - AND(32, R(RSCRATCH), Imm32(and_mask)); - OR(32, R(RSCRATCH), Imm32(or_mask)); - MOV(32, PPCSTATE(fpscr), R(RSCRATCH)); + MOV(32, R(RSCRATCH), PPCSTATE(fpscr)); + AND(32, R(RSCRATCH), Imm32(and_mask)); + OR(32, R(RSCRATCH), Imm32(or_mask)); + MOV(32, PPCSTATE(fpscr), R(RSCRATCH)); - // Field 7 contains NI and RN. - if (inst.CRFD == 7) - LDMXCSR(M(&s_fpscr_to_mxcsr[imm & 7])); + // Field 7 contains NI and RN. + if (inst.CRFD == 7) + LDMXCSR(M(&s_fpscr_to_mxcsr[imm & 7])); } void Jit64::mtfsfx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + FALLBACK_IF(inst.Rc); - u32 mask = 0; - for (int i = 0; i < 8; i++) - { - if (inst.FM & (1 << i)) - mask |= 0xF << (4 * i); - } + u32 mask = 0; + for (int i = 0; i < 8; i++) + { + if (inst.FM & (1 << i)) + mask |= 0xF << (4 * i); + } - int b = inst.FB; - if (fpr.R(b).IsSimpleReg()) - MOVQ_xmm(R(RSCRATCH), fpr.RX(b)); - else - MOV(32, R(RSCRATCH), fpr.R(b)); + int b = inst.FB; + if (fpr.R(b).IsSimpleReg()) + MOVQ_xmm(R(RSCRATCH), fpr.RX(b)); + else + MOV(32, R(RSCRATCH), fpr.R(b)); - MOV(32, R(RSCRATCH2), PPCSTATE(fpscr)); - AND(32, R(RSCRATCH), Imm32(mask)); - AND(32, R(RSCRATCH2), Imm32(~mask)); - OR(32, R(RSCRATCH), R(RSCRATCH2)); - MOV(32, PPCSTATE(fpscr), R(RSCRATCH)); + MOV(32, R(RSCRATCH2), PPCSTATE(fpscr)); + AND(32, R(RSCRATCH), Imm32(mask)); + AND(32, R(RSCRATCH2), Imm32(~mask)); + OR(32, R(RSCRATCH), R(RSCRATCH2)); + MOV(32, PPCSTATE(fpscr), R(RSCRATCH)); - if (inst.FM & 1) - UpdateMXCSR(); + if (inst.FM & 1) + UpdateMXCSR(); } diff --git a/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp b/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp index 0fba07fa96..160b3fb05e 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp +++ b/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/Jit64Common/Jit64AsmCommon.h" #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/JitRegister.h" @@ -9,203 +10,205 @@ #include "Common/x64ABI.h" #include "Common/x64Emitter.h" #include "Core/HW/GPFifo.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/Jit64Common/Jit64AsmCommon.h" -#include "Core/PowerPC/JitCommon/Jit_Util.h" #include "Core/PowerPC/JitCommon/JitBase.h" +#include "Core/PowerPC/JitCommon/Jit_Util.h" +#include "Core/PowerPC/PowerPC.h" -#define QUANTIZED_REGS_TO_SAVE \ - (ABI_ALL_CALLER_SAVED & ~BitSet32 { \ - RSCRATCH, RSCRATCH2, RSCRATCH_EXTRA, XMM0+16, XMM1+16 \ - }) +#define QUANTIZED_REGS_TO_SAVE \ + (ABI_ALL_CALLER_SAVED & ~BitSet32{RSCRATCH, RSCRATCH2, RSCRATCH_EXTRA, XMM0 + 16, XMM1 + 16}) -#define QUANTIZED_REGS_TO_SAVE_LOAD (QUANTIZED_REGS_TO_SAVE | BitSet32 { RSCRATCH2 }) +#define QUANTIZED_REGS_TO_SAVE_LOAD (QUANTIZED_REGS_TO_SAVE | BitSet32{RSCRATCH2}) using namespace Gen; void CommonAsmRoutines::GenFifoWrite(int size) { - const void* start = GetCodePtr(); + const void* start = GetCodePtr(); - // Assume value in RSCRATCH - u32 gather_pipe = (u32)(u64)GPFifo::m_gatherPipe; - _assert_msg_(DYNA_REC, gather_pipe <= 0x7FFFFFFF, "Gather pipe not in low 2GB of memory!"); - MOV(32, R(RSCRATCH2), M(&GPFifo::m_gatherPipeCount)); - SwapAndStore(size, MDisp(RSCRATCH2, gather_pipe), RSCRATCH); - ADD(32, R(RSCRATCH2), Imm8(size >> 3)); - MOV(32, M(&GPFifo::m_gatherPipeCount), R(RSCRATCH2)); - RET(); + // Assume value in RSCRATCH + u32 gather_pipe = (u32)(u64)GPFifo::m_gatherPipe; + _assert_msg_(DYNA_REC, gather_pipe <= 0x7FFFFFFF, "Gather pipe not in low 2GB of memory!"); + MOV(32, R(RSCRATCH2), M(&GPFifo::m_gatherPipeCount)); + SwapAndStore(size, MDisp(RSCRATCH2, gather_pipe), RSCRATCH); + ADD(32, R(RSCRATCH2), Imm8(size >> 3)); + MOV(32, M(&GPFifo::m_gatherPipeCount), R(RSCRATCH2)); + RET(); - JitRegister::Register(start, GetCodePtr(), "JIT_FifoWrite_%i", size); + JitRegister::Register(start, GetCodePtr(), "JIT_FifoWrite_%i", size); } void CommonAsmRoutines::GenFrsqrte() { - const void* start = GetCodePtr(); + const void* start = GetCodePtr(); - // Assume input in XMM0. - // This function clobbers all three RSCRATCH. - MOVQ_xmm(R(RSCRATCH), XMM0); + // Assume input in XMM0. + // This function clobbers all three RSCRATCH. + MOVQ_xmm(R(RSCRATCH), XMM0); - // Negative and zero inputs set an exception and take the complex path. - TEST(64, R(RSCRATCH), R(RSCRATCH)); - FixupBranch zero = J_CC(CC_Z, true); - FixupBranch negative = J_CC(CC_S, true); - MOV(64, R(RSCRATCH_EXTRA), R(RSCRATCH)); - SHR(64, R(RSCRATCH_EXTRA), Imm8(52)); + // Negative and zero inputs set an exception and take the complex path. + TEST(64, R(RSCRATCH), R(RSCRATCH)); + FixupBranch zero = J_CC(CC_Z, true); + FixupBranch negative = J_CC(CC_S, true); + MOV(64, R(RSCRATCH_EXTRA), R(RSCRATCH)); + SHR(64, R(RSCRATCH_EXTRA), Imm8(52)); - // Zero and max exponents (non-normal floats) take the complex path. - FixupBranch complex1 = J_CC(CC_Z, true); - CMP(32, R(RSCRATCH_EXTRA), Imm32(0x7FF)); - FixupBranch complex2 = J_CC(CC_E, true); + // Zero and max exponents (non-normal floats) take the complex path. + FixupBranch complex1 = J_CC(CC_Z, true); + CMP(32, R(RSCRATCH_EXTRA), Imm32(0x7FF)); + FixupBranch complex2 = J_CC(CC_E, true); - SUB(32, R(RSCRATCH_EXTRA), Imm32(0x3FD)); - SAR(32, R(RSCRATCH_EXTRA), Imm8(1)); - MOV(32, R(RSCRATCH2), Imm32(0x3FF)); - SUB(32, R(RSCRATCH2), R(RSCRATCH_EXTRA)); - SHL(64, R(RSCRATCH2), Imm8(52)); // exponent = ((0x3FFLL << 52) - ((exponent - (0x3FELL << 52)) / 2)) & (0x7FFLL << 52); + SUB(32, R(RSCRATCH_EXTRA), Imm32(0x3FD)); + SAR(32, R(RSCRATCH_EXTRA), Imm8(1)); + MOV(32, R(RSCRATCH2), Imm32(0x3FF)); + SUB(32, R(RSCRATCH2), R(RSCRATCH_EXTRA)); + SHL(64, R(RSCRATCH2), Imm8(52)); // exponent = ((0x3FFLL << 52) - ((exponent - (0x3FELL << 52)) / + // 2)) & (0x7FFLL << 52); - MOV(64, R(RSCRATCH_EXTRA), R(RSCRATCH)); - SHR(64, R(RSCRATCH_EXTRA), Imm8(48)); - AND(32, R(RSCRATCH_EXTRA), Imm8(0x1F)); - XOR(32, R(RSCRATCH_EXTRA), Imm8(0x10)); // int index = i / 2048 + (odd_exponent ? 16 : 0); + MOV(64, R(RSCRATCH_EXTRA), R(RSCRATCH)); + SHR(64, R(RSCRATCH_EXTRA), Imm8(48)); + AND(32, R(RSCRATCH_EXTRA), Imm8(0x1F)); + XOR(32, R(RSCRATCH_EXTRA), Imm8(0x10)); // int index = i / 2048 + (odd_exponent ? 16 : 0); - SHR(64, R(RSCRATCH), Imm8(37)); - AND(32, R(RSCRATCH), Imm32(0x7FF)); - IMUL(32, RSCRATCH, MScaled(RSCRATCH_EXTRA, SCALE_4, (u32)(u64)MathUtil::frsqrte_expected_dec)); - MOV(32, R(RSCRATCH_EXTRA), MScaled(RSCRATCH_EXTRA, SCALE_4, (u32)(u64)MathUtil::frsqrte_expected_base)); - SUB(32, R(RSCRATCH_EXTRA), R(RSCRATCH)); - SHL(64, R(RSCRATCH_EXTRA), Imm8(26)); - OR(64, R(RSCRATCH2), R(RSCRATCH_EXTRA)); // vali |= (s64)(frsqrte_expected_base[index] - frsqrte_expected_dec[index] * (i % 2048)) << 26; - MOVQ_xmm(XMM0, R(RSCRATCH2)); - RET(); + SHR(64, R(RSCRATCH), Imm8(37)); + AND(32, R(RSCRATCH), Imm32(0x7FF)); + IMUL(32, RSCRATCH, MScaled(RSCRATCH_EXTRA, SCALE_4, (u32)(u64)MathUtil::frsqrte_expected_dec)); + MOV(32, R(RSCRATCH_EXTRA), + MScaled(RSCRATCH_EXTRA, SCALE_4, (u32)(u64)MathUtil::frsqrte_expected_base)); + SUB(32, R(RSCRATCH_EXTRA), R(RSCRATCH)); + SHL(64, R(RSCRATCH_EXTRA), Imm8(26)); + OR(64, R(RSCRATCH2), R(RSCRATCH_EXTRA)); // vali |= (s64)(frsqrte_expected_base[index] - + // frsqrte_expected_dec[index] * (i % 2048)) << 26; + MOVQ_xmm(XMM0, R(RSCRATCH2)); + RET(); - // Exception flags for zero input. - SetJumpTarget(zero); - TEST(32, PPCSTATE(fpscr), Imm32(FPSCR_ZX)); - FixupBranch skip_set_fx1 = J_CC(CC_NZ); - OR(32, PPCSTATE(fpscr), Imm32(FPSCR_FX | FPSCR_ZX)); - FixupBranch complex3 = J(); + // Exception flags for zero input. + SetJumpTarget(zero); + TEST(32, PPCSTATE(fpscr), Imm32(FPSCR_ZX)); + FixupBranch skip_set_fx1 = J_CC(CC_NZ); + OR(32, PPCSTATE(fpscr), Imm32(FPSCR_FX | FPSCR_ZX)); + FixupBranch complex3 = J(); - // Exception flags for negative input. - SetJumpTarget(negative); - TEST(32, PPCSTATE(fpscr), Imm32(FPSCR_VXSQRT)); - FixupBranch skip_set_fx2 = J_CC(CC_NZ); - OR(32, PPCSTATE(fpscr), Imm32(FPSCR_FX | FPSCR_VXSQRT)); + // Exception flags for negative input. + SetJumpTarget(negative); + TEST(32, PPCSTATE(fpscr), Imm32(FPSCR_VXSQRT)); + FixupBranch skip_set_fx2 = J_CC(CC_NZ); + OR(32, PPCSTATE(fpscr), Imm32(FPSCR_FX | FPSCR_VXSQRT)); - SetJumpTarget(skip_set_fx1); - SetJumpTarget(skip_set_fx2); - SetJumpTarget(complex1); - SetJumpTarget(complex2); - SetJumpTarget(complex3); - ABI_PushRegistersAndAdjustStack(QUANTIZED_REGS_TO_SAVE, 8); - ABI_CallFunction((void *)&MathUtil::ApproximateReciprocalSquareRoot); - ABI_PopRegistersAndAdjustStack(QUANTIZED_REGS_TO_SAVE, 8); - RET(); + SetJumpTarget(skip_set_fx1); + SetJumpTarget(skip_set_fx2); + SetJumpTarget(complex1); + SetJumpTarget(complex2); + SetJumpTarget(complex3); + ABI_PushRegistersAndAdjustStack(QUANTIZED_REGS_TO_SAVE, 8); + ABI_CallFunction((void*)&MathUtil::ApproximateReciprocalSquareRoot); + ABI_PopRegistersAndAdjustStack(QUANTIZED_REGS_TO_SAVE, 8); + RET(); - JitRegister::Register(start, GetCodePtr(), "JIT_Frsqrte"); + JitRegister::Register(start, GetCodePtr(), "JIT_Frsqrte"); } void CommonAsmRoutines::GenFres() { - const void* start = GetCodePtr(); + const void* start = GetCodePtr(); - // Assume input in XMM0. - // This function clobbers all three RSCRATCH. - MOVQ_xmm(R(RSCRATCH), XMM0); + // Assume input in XMM0. + // This function clobbers all three RSCRATCH. + MOVQ_xmm(R(RSCRATCH), XMM0); - // Zero inputs set an exception and take the complex path. - TEST(64, R(RSCRATCH), R(RSCRATCH)); - FixupBranch zero = J_CC(CC_Z); + // Zero inputs set an exception and take the complex path. + TEST(64, R(RSCRATCH), R(RSCRATCH)); + FixupBranch zero = J_CC(CC_Z); - MOV(64, R(RSCRATCH_EXTRA), R(RSCRATCH)); - SHR(64, R(RSCRATCH_EXTRA), Imm8(52)); - MOV(32, R(RSCRATCH2), R(RSCRATCH_EXTRA)); - AND(32, R(RSCRATCH_EXTRA), Imm32(0x7FF)); // exp - AND(32, R(RSCRATCH2), Imm32(0x800)); // sign - SUB(32, R(RSCRATCH_EXTRA), Imm32(895)); - CMP(32, R(RSCRATCH_EXTRA), Imm32(1149 - 895)); - // Take the complex path for very large/small exponents. - FixupBranch complex = J_CC(CC_AE); // if (exp < 895 || exp >= 1149) + MOV(64, R(RSCRATCH_EXTRA), R(RSCRATCH)); + SHR(64, R(RSCRATCH_EXTRA), Imm8(52)); + MOV(32, R(RSCRATCH2), R(RSCRATCH_EXTRA)); + AND(32, R(RSCRATCH_EXTRA), Imm32(0x7FF)); // exp + AND(32, R(RSCRATCH2), Imm32(0x800)); // sign + SUB(32, R(RSCRATCH_EXTRA), Imm32(895)); + CMP(32, R(RSCRATCH_EXTRA), Imm32(1149 - 895)); + // Take the complex path for very large/small exponents. + FixupBranch complex = J_CC(CC_AE); // if (exp < 895 || exp >= 1149) - SUB(32, R(RSCRATCH_EXTRA), Imm32(0x7FD - 895)); - NEG(32, R(RSCRATCH_EXTRA)); - OR(32, R(RSCRATCH_EXTRA), R(RSCRATCH2)); - SHL(64, R(RSCRATCH_EXTRA), Imm8(52)); // vali = sign | exponent + SUB(32, R(RSCRATCH_EXTRA), Imm32(0x7FD - 895)); + NEG(32, R(RSCRATCH_EXTRA)); + OR(32, R(RSCRATCH_EXTRA), R(RSCRATCH2)); + SHL(64, R(RSCRATCH_EXTRA), Imm8(52)); // vali = sign | exponent - MOV(64, R(RSCRATCH2), R(RSCRATCH)); - SHR(64, R(RSCRATCH), Imm8(37)); - SHR(64, R(RSCRATCH2), Imm8(47)); - AND(32, R(RSCRATCH), Imm32(0x3FF)); // i % 1024 - AND(32, R(RSCRATCH2), Imm8(0x1F)); // i / 1024 + MOV(64, R(RSCRATCH2), R(RSCRATCH)); + SHR(64, R(RSCRATCH), Imm8(37)); + SHR(64, R(RSCRATCH2), Imm8(47)); + AND(32, R(RSCRATCH), Imm32(0x3FF)); // i % 1024 + AND(32, R(RSCRATCH2), Imm8(0x1F)); // i / 1024 - IMUL(32, RSCRATCH, MScaled(RSCRATCH2, SCALE_4, (u32)(u64)MathUtil::fres_expected_dec)); - ADD(32, R(RSCRATCH), Imm8(1)); - SHR(32, R(RSCRATCH), Imm8(1)); + IMUL(32, RSCRATCH, MScaled(RSCRATCH2, SCALE_4, (u32)(u64)MathUtil::fres_expected_dec)); + ADD(32, R(RSCRATCH), Imm8(1)); + SHR(32, R(RSCRATCH), Imm8(1)); - MOV(32, R(RSCRATCH2), MScaled(RSCRATCH2, SCALE_4, (u32)(u64)MathUtil::fres_expected_base)); - SUB(32, R(RSCRATCH2), R(RSCRATCH)); - SHL(64, R(RSCRATCH2), Imm8(29)); - OR(64, R(RSCRATCH2), R(RSCRATCH_EXTRA)); // vali |= (s64)(fres_expected_base[i / 1024] - (fres_expected_dec[i / 1024] * (i % 1024) + 1) / 2) << 29 - MOVQ_xmm(XMM0, R(RSCRATCH2)); - RET(); + MOV(32, R(RSCRATCH2), MScaled(RSCRATCH2, SCALE_4, (u32)(u64)MathUtil::fres_expected_base)); + SUB(32, R(RSCRATCH2), R(RSCRATCH)); + SHL(64, R(RSCRATCH2), Imm8(29)); + OR(64, R(RSCRATCH2), R(RSCRATCH_EXTRA)); // vali |= (s64)(fres_expected_base[i / 1024] - + // (fres_expected_dec[i / 1024] * (i % 1024) + 1) / 2) + // << 29 + MOVQ_xmm(XMM0, R(RSCRATCH2)); + RET(); - // Exception flags for zero input. - SetJumpTarget(zero); - TEST(32, PPCSTATE(fpscr), Imm32(FPSCR_ZX)); - FixupBranch skip_set_fx1 = J_CC(CC_NZ); - OR(32, PPCSTATE(fpscr), Imm32(FPSCR_FX | FPSCR_ZX)); - SetJumpTarget(skip_set_fx1); + // Exception flags for zero input. + SetJumpTarget(zero); + TEST(32, PPCSTATE(fpscr), Imm32(FPSCR_ZX)); + FixupBranch skip_set_fx1 = J_CC(CC_NZ); + OR(32, PPCSTATE(fpscr), Imm32(FPSCR_FX | FPSCR_ZX)); + SetJumpTarget(skip_set_fx1); - SetJumpTarget(complex); - ABI_PushRegistersAndAdjustStack(QUANTIZED_REGS_TO_SAVE, 8); - ABI_CallFunction((void *)&MathUtil::ApproximateReciprocal); - ABI_PopRegistersAndAdjustStack(QUANTIZED_REGS_TO_SAVE, 8); - RET(); + SetJumpTarget(complex); + ABI_PushRegistersAndAdjustStack(QUANTIZED_REGS_TO_SAVE, 8); + ABI_CallFunction((void*)&MathUtil::ApproximateReciprocal); + ABI_PopRegistersAndAdjustStack(QUANTIZED_REGS_TO_SAVE, 8); + RET(); - JitRegister::Register(start, GetCodePtr(), "JIT_Fres"); + JitRegister::Register(start, GetCodePtr(), "JIT_Fres"); } void CommonAsmRoutines::GenMfcr() { - const void* start = GetCodePtr(); + const void* start = GetCodePtr(); - // Input: none - // Output: RSCRATCH - // This function clobbers all three RSCRATCH. - X64Reg dst = RSCRATCH; - X64Reg tmp = RSCRATCH2; - X64Reg cr_val = RSCRATCH_EXTRA; - XOR(32, R(dst), R(dst)); - // we only need to zero the high bits of tmp once - XOR(32, R(tmp), R(tmp)); - for (int i = 0; i < 8; i++) - { - static const u32 m_flagTable[8] = { 0x0, 0x1, 0x8, 0x9, 0x0, 0x1, 0x8, 0x9 }; - if (i != 0) - SHL(32, R(dst), Imm8(4)); + // Input: none + // Output: RSCRATCH + // This function clobbers all three RSCRATCH. + X64Reg dst = RSCRATCH; + X64Reg tmp = RSCRATCH2; + X64Reg cr_val = RSCRATCH_EXTRA; + XOR(32, R(dst), R(dst)); + // we only need to zero the high bits of tmp once + XOR(32, R(tmp), R(tmp)); + for (int i = 0; i < 8; i++) + { + static const u32 m_flagTable[8] = {0x0, 0x1, 0x8, 0x9, 0x0, 0x1, 0x8, 0x9}; + if (i != 0) + SHL(32, R(dst), Imm8(4)); - MOV(64, R(cr_val), PPCSTATE(cr_val[i])); + MOV(64, R(cr_val), PPCSTATE(cr_val[i])); - // EQ: Bits 31-0 == 0; set flag bit 1 - TEST(32, R(cr_val), R(cr_val)); - // FIXME: is there a better way to do this without the partial register merging? - SETcc(CC_Z, R(tmp)); - LEA(32, dst, MComplex(dst, tmp, SCALE_2, 0)); + // EQ: Bits 31-0 == 0; set flag bit 1 + TEST(32, R(cr_val), R(cr_val)); + // FIXME: is there a better way to do this without the partial register merging? + SETcc(CC_Z, R(tmp)); + LEA(32, dst, MComplex(dst, tmp, SCALE_2, 0)); - // GT: Value > 0; set flag bit 2 - TEST(64, R(cr_val), R(cr_val)); - SETcc(CC_G, R(tmp)); - LEA(32, dst, MComplex(dst, tmp, SCALE_4, 0)); + // GT: Value > 0; set flag bit 2 + TEST(64, R(cr_val), R(cr_val)); + SETcc(CC_G, R(tmp)); + LEA(32, dst, MComplex(dst, tmp, SCALE_4, 0)); - // SO: Bit 61 set; set flag bit 0 - // LT: Bit 62 set; set flag bit 3 - SHR(64, R(cr_val), Imm8(61)); - OR(32, R(dst), MScaled(cr_val, SCALE_4, (u32)(u64)m_flagTable)); - } - RET(); + // SO: Bit 61 set; set flag bit 0 + // LT: Bit 62 set; set flag bit 3 + SHR(64, R(cr_val), Imm8(61)); + OR(32, R(dst), MScaled(cr_val, SCALE_4, (u32)(u64)m_flagTable)); + } + RET(); - JitRegister::Register(start, GetCodePtr(), "JIT_Mfcr"); + JitRegister::Register(start, GetCodePtr(), "JIT_Mfcr"); } // Safe + Fast Quantizers, originally from JITIL by magumagu @@ -218,7 +221,8 @@ alignas(16) static const float m_m128 = -128.0f; #define QUANTIZE_OVERFLOW_SAFE -// according to Intel Docs CVTPS2DQ writes 0x80000000 if the source floating point value is out of int32 range +// according to Intel Docs CVTPS2DQ writes 0x80000000 if the source floating point value is out of +// int32 range // while it's OK for large negatives, it isn't for positives // I don't know whether the overflow actually happens in any games // but it potentially can cause problems, so we need some clamping @@ -226,408 +230,427 @@ alignas(16) static const float m_m128 = -128.0f; // See comment in header for in/outs. void CommonAsmRoutines::GenQuantizedStores() { - const void* start = GetCodePtr(); + const void* start = GetCodePtr(); - const u8* storePairedIllegal = AlignCode4(); - UD2(); + const u8* storePairedIllegal = AlignCode4(); + UD2(); - const u8* storePairedFloat = AlignCode4(); - if (cpu_info.bSSSE3) - { - PSHUFB(XMM0, M((void *)pbswapShuffle2x4)); - MOVQ_xmm(R(RSCRATCH), XMM0); - } - else - { - MOVQ_xmm(R(RSCRATCH), XMM0); - ROL(64, R(RSCRATCH), Imm8(32)); - BSWAP(64, RSCRATCH); - } - SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 64, 0, QUANTIZED_REGS_TO_SAVE, SAFE_LOADSTORE_NO_SWAP | SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); + const u8* storePairedFloat = AlignCode4(); + if (cpu_info.bSSSE3) + { + PSHUFB(XMM0, M((void*)pbswapShuffle2x4)); + MOVQ_xmm(R(RSCRATCH), XMM0); + } + else + { + MOVQ_xmm(R(RSCRATCH), XMM0); + ROL(64, R(RSCRATCH), Imm8(32)); + BSWAP(64, RSCRATCH); + } + SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 64, 0, QUANTIZED_REGS_TO_SAVE, + SAFE_LOADSTORE_NO_SWAP | SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); - RET(); + RET(); - const u8* storePairedU8 = AlignCode4(); - SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); - MULPS(XMM0, R(XMM1)); + const u8* storePairedU8 = AlignCode4(); + SHR(32, R(RSCRATCH2), Imm8(5)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); + MULPS(XMM0, R(XMM1)); #ifdef QUANTIZE_OVERFLOW_SAFE - MINPS(XMM0, M(m_65535)); + MINPS(XMM0, M(m_65535)); #endif - CVTTPS2DQ(XMM0, R(XMM0)); - PACKSSDW(XMM0, R(XMM0)); - PACKUSWB(XMM0, R(XMM0)); - MOVD_xmm(R(RSCRATCH), XMM0); - SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 16, 0, QUANTIZED_REGS_TO_SAVE, SAFE_LOADSTORE_NO_SWAP | SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); + CVTTPS2DQ(XMM0, R(XMM0)); + PACKSSDW(XMM0, R(XMM0)); + PACKUSWB(XMM0, R(XMM0)); + MOVD_xmm(R(RSCRATCH), XMM0); + SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 16, 0, QUANTIZED_REGS_TO_SAVE, + SAFE_LOADSTORE_NO_SWAP | SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); - RET(); + RET(); - const u8* storePairedS8 = AlignCode4(); - SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); - MULPS(XMM0, R(XMM1)); + const u8* storePairedS8 = AlignCode4(); + SHR(32, R(RSCRATCH2), Imm8(5)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); + MULPS(XMM0, R(XMM1)); #ifdef QUANTIZE_OVERFLOW_SAFE - MINPS(XMM0, M(m_65535)); + MINPS(XMM0, M(m_65535)); #endif - CVTTPS2DQ(XMM0, R(XMM0)); - PACKSSDW(XMM0, R(XMM0)); - PACKSSWB(XMM0, R(XMM0)); - MOVD_xmm(R(RSCRATCH), XMM0); + CVTTPS2DQ(XMM0, R(XMM0)); + PACKSSDW(XMM0, R(XMM0)); + PACKSSWB(XMM0, R(XMM0)); + MOVD_xmm(R(RSCRATCH), XMM0); - SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 16, 0, QUANTIZED_REGS_TO_SAVE, SAFE_LOADSTORE_NO_SWAP | SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); + SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 16, 0, QUANTIZED_REGS_TO_SAVE, + SAFE_LOADSTORE_NO_SWAP | SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); - RET(); + RET(); - const u8* storePairedU16 = AlignCode4(); - SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); - MULPS(XMM0, R(XMM1)); + const u8* storePairedU16 = AlignCode4(); + SHR(32, R(RSCRATCH2), Imm8(5)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); + MULPS(XMM0, R(XMM1)); - if (cpu_info.bSSE4_1) - { + if (cpu_info.bSSE4_1) + { #ifdef QUANTIZE_OVERFLOW_SAFE - MINPS(XMM0, M(m_65535)); + MINPS(XMM0, M(m_65535)); #endif - CVTTPS2DQ(XMM0, R(XMM0)); - PACKUSDW(XMM0, R(XMM0)); - MOVD_xmm(R(RSCRATCH), XMM0); - BSWAP(32, RSCRATCH); - ROL(32, R(RSCRATCH), Imm8(16)); - } - else - { - XORPS(XMM1, R(XMM1)); - MAXPS(XMM0, R(XMM1)); - MINPS(XMM0, M(m_65535)); + CVTTPS2DQ(XMM0, R(XMM0)); + PACKUSDW(XMM0, R(XMM0)); + MOVD_xmm(R(RSCRATCH), XMM0); + BSWAP(32, RSCRATCH); + ROL(32, R(RSCRATCH), Imm8(16)); + } + else + { + XORPS(XMM1, R(XMM1)); + MAXPS(XMM0, R(XMM1)); + MINPS(XMM0, M(m_65535)); - CVTTPS2DQ(XMM0, R(XMM0)); - PSHUFLW(XMM0, R(XMM0), 2); // AABBCCDD -> CCAA____ - MOVD_xmm(R(RSCRATCH), XMM0); - BSWAP(32, RSCRATCH); - } + CVTTPS2DQ(XMM0, R(XMM0)); + PSHUFLW(XMM0, R(XMM0), 2); // AABBCCDD -> CCAA____ + MOVD_xmm(R(RSCRATCH), XMM0); + BSWAP(32, RSCRATCH); + } - SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 32, 0, QUANTIZED_REGS_TO_SAVE, SAFE_LOADSTORE_NO_SWAP | SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); + SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 32, 0, QUANTIZED_REGS_TO_SAVE, + SAFE_LOADSTORE_NO_SWAP | SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); - RET(); + RET(); - const u8* storePairedS16 = AlignCode4(); - SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); - MULPS(XMM0, R(XMM1)); + const u8* storePairedS16 = AlignCode4(); + SHR(32, R(RSCRATCH2), Imm8(5)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); + MULPS(XMM0, R(XMM1)); #ifdef QUANTIZE_OVERFLOW_SAFE - MINPS(XMM0, M(m_65535)); + MINPS(XMM0, M(m_65535)); #endif - CVTTPS2DQ(XMM0, R(XMM0)); - PACKSSDW(XMM0, R(XMM0)); - MOVD_xmm(R(RSCRATCH), XMM0); - BSWAP(32, RSCRATCH); - ROL(32, R(RSCRATCH), Imm8(16)); - SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 32, 0, QUANTIZED_REGS_TO_SAVE, SAFE_LOADSTORE_NO_SWAP | SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); + CVTTPS2DQ(XMM0, R(XMM0)); + PACKSSDW(XMM0, R(XMM0)); + MOVD_xmm(R(RSCRATCH), XMM0); + BSWAP(32, RSCRATCH); + ROL(32, R(RSCRATCH), Imm8(16)); + SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 32, 0, QUANTIZED_REGS_TO_SAVE, + SAFE_LOADSTORE_NO_SWAP | SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); - RET(); + RET(); - JitRegister::Register(start, GetCodePtr(), "JIT_QuantizedStore"); + JitRegister::Register(start, GetCodePtr(), "JIT_QuantizedStore"); - pairedStoreQuantized = reinterpret_cast(const_cast(AlignCode16())); - ReserveCodeSpace(8 * sizeof(u8*)); + pairedStoreQuantized = reinterpret_cast(const_cast(AlignCode16())); + ReserveCodeSpace(8 * sizeof(u8*)); - pairedStoreQuantized[0] = storePairedFloat; - pairedStoreQuantized[1] = storePairedIllegal; - pairedStoreQuantized[2] = storePairedIllegal; - pairedStoreQuantized[3] = storePairedIllegal; - pairedStoreQuantized[4] = storePairedU8; - pairedStoreQuantized[5] = storePairedU16; - pairedStoreQuantized[6] = storePairedS8; - pairedStoreQuantized[7] = storePairedS16; + pairedStoreQuantized[0] = storePairedFloat; + pairedStoreQuantized[1] = storePairedIllegal; + pairedStoreQuantized[2] = storePairedIllegal; + pairedStoreQuantized[3] = storePairedIllegal; + pairedStoreQuantized[4] = storePairedU8; + pairedStoreQuantized[5] = storePairedU16; + pairedStoreQuantized[6] = storePairedS8; + pairedStoreQuantized[7] = storePairedS16; } // See comment in header for in/outs. void CommonAsmRoutines::GenQuantizedSingleStores() { - const void* start = GetCodePtr(); + const void* start = GetCodePtr(); - const u8* storeSingleIllegal = AlignCode4(); - UD2(); + const u8* storeSingleIllegal = AlignCode4(); + UD2(); - // Easy! - const u8* storeSingleFloat = AlignCode4(); - MOVD_xmm(R(RSCRATCH), XMM0); - SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 32, 0, QUANTIZED_REGS_TO_SAVE, SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); - RET(); + // Easy! + const u8* storeSingleFloat = AlignCode4(); + MOVD_xmm(R(RSCRATCH), XMM0); + SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 32, 0, QUANTIZED_REGS_TO_SAVE, + SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); + RET(); - const u8* storeSingleU8 = AlignCode4(); // Used by MKWii - SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); - XORPS(XMM1, R(XMM1)); - MAXSS(XMM0, R(XMM1)); - MINSS(XMM0, M(&m_255)); - CVTTSS2SI(RSCRATCH, R(XMM0)); - SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 8, 0, QUANTIZED_REGS_TO_SAVE, SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); - RET(); + const u8* storeSingleU8 = AlignCode4(); // Used by MKWii + SHR(32, R(RSCRATCH2), Imm8(5)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); + XORPS(XMM1, R(XMM1)); + MAXSS(XMM0, R(XMM1)); + MINSS(XMM0, M(&m_255)); + CVTTSS2SI(RSCRATCH, R(XMM0)); + SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 8, 0, QUANTIZED_REGS_TO_SAVE, + SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); + RET(); - const u8* storeSingleS8 = AlignCode4(); - SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); - MAXSS(XMM0, M(&m_m128)); - MINSS(XMM0, M(&m_127)); - CVTTSS2SI(RSCRATCH, R(XMM0)); - SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 8, 0, QUANTIZED_REGS_TO_SAVE, SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); - RET(); + const u8* storeSingleS8 = AlignCode4(); + SHR(32, R(RSCRATCH2), Imm8(5)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); + MAXSS(XMM0, M(&m_m128)); + MINSS(XMM0, M(&m_127)); + CVTTSS2SI(RSCRATCH, R(XMM0)); + SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 8, 0, QUANTIZED_REGS_TO_SAVE, + SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); + RET(); - const u8* storeSingleU16 = AlignCode4(); // Used by MKWii - SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); - XORPS(XMM1, R(XMM1)); - MAXSS(XMM0, R(XMM1)); - MINSS(XMM0, M(m_65535)); - CVTTSS2SI(RSCRATCH, R(XMM0)); - SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 16, 0, QUANTIZED_REGS_TO_SAVE, SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); - RET(); + const u8* storeSingleU16 = AlignCode4(); // Used by MKWii + SHR(32, R(RSCRATCH2), Imm8(5)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); + XORPS(XMM1, R(XMM1)); + MAXSS(XMM0, R(XMM1)); + MINSS(XMM0, M(m_65535)); + CVTTSS2SI(RSCRATCH, R(XMM0)); + SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 16, 0, QUANTIZED_REGS_TO_SAVE, + SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); + RET(); - const u8* storeSingleS16 = AlignCode4(); - SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); - MAXSS(XMM0, M(&m_m32768)); - MINSS(XMM0, M(&m_32767)); - CVTTSS2SI(RSCRATCH, R(XMM0)); - SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 16, 0, QUANTIZED_REGS_TO_SAVE, SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); - RET(); + const u8* storeSingleS16 = AlignCode4(); + SHR(32, R(RSCRATCH2), Imm8(5)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_quantizeTableS)); + MAXSS(XMM0, M(&m_m32768)); + MINSS(XMM0, M(&m_32767)); + CVTTSS2SI(RSCRATCH, R(XMM0)); + SafeWriteRegToReg(RSCRATCH, RSCRATCH_EXTRA, 16, 0, QUANTIZED_REGS_TO_SAVE, + SAFE_LOADSTORE_NO_PROLOG | SAFE_LOADSTORE_NO_FASTMEM); + RET(); - JitRegister::Register(start, GetCodePtr(), "JIT_QuantizedSingleStore"); + JitRegister::Register(start, GetCodePtr(), "JIT_QuantizedSingleStore"); - singleStoreQuantized = reinterpret_cast(const_cast(AlignCode16())); - ReserveCodeSpace(8 * sizeof(u8*)); + singleStoreQuantized = reinterpret_cast(const_cast(AlignCode16())); + ReserveCodeSpace(8 * sizeof(u8*)); - singleStoreQuantized[0] = storeSingleFloat; - singleStoreQuantized[1] = storeSingleIllegal; - singleStoreQuantized[2] = storeSingleIllegal; - singleStoreQuantized[3] = storeSingleIllegal; - singleStoreQuantized[4] = storeSingleU8; - singleStoreQuantized[5] = storeSingleU16; - singleStoreQuantized[6] = storeSingleS8; - singleStoreQuantized[7] = storeSingleS16; + singleStoreQuantized[0] = storeSingleFloat; + singleStoreQuantized[1] = storeSingleIllegal; + singleStoreQuantized[2] = storeSingleIllegal; + singleStoreQuantized[3] = storeSingleIllegal; + singleStoreQuantized[4] = storeSingleU8; + singleStoreQuantized[5] = storeSingleU16; + singleStoreQuantized[6] = storeSingleS8; + singleStoreQuantized[7] = storeSingleS16; } void CommonAsmRoutines::GenQuantizedLoads() { - const void* start = GetCodePtr(); + const void* start = GetCodePtr(); - const u8* loadPairedIllegal = AlignCode4(); - UD2(); + const u8* loadPairedIllegal = AlignCode4(); + UD2(); - // FIXME? This code (in non-MMU mode) assumes all accesses are directly to RAM, i.e. - // don't need hardware access handling. This will definitely crash if paired loads occur - // from non-RAM areas, but as far as I know, this never happens. I don't know if this is - // for a good reason, or merely because no game does this. - // If we find something that actually does do this, maybe this should be changed. How - // much of a performance hit would it be? - const u8* loadPairedFloatTwo = AlignCode4(); - if (jit->jo.memcheck) - { - SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 64, 0, QUANTIZED_REGS_TO_SAVE, false, SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); - ROL(64, R(RSCRATCH_EXTRA), Imm8(32)); - MOVQ_xmm(XMM0, R(RSCRATCH_EXTRA)); - } - else if (cpu_info.bSSSE3) - { - MOVQ_xmm(XMM0, MRegSum(RMEM, RSCRATCH_EXTRA)); - PSHUFB(XMM0, M(pbswapShuffle2x4)); - } - else - { - LoadAndSwap(64, RSCRATCH_EXTRA, MRegSum(RMEM, RSCRATCH_EXTRA)); - ROL(64, R(RSCRATCH_EXTRA), Imm8(32)); - MOVQ_xmm(XMM0, R(RSCRATCH_EXTRA)); - } - RET(); + // FIXME? This code (in non-MMU mode) assumes all accesses are directly to RAM, i.e. + // don't need hardware access handling. This will definitely crash if paired loads occur + // from non-RAM areas, but as far as I know, this never happens. I don't know if this is + // for a good reason, or merely because no game does this. + // If we find something that actually does do this, maybe this should be changed. How + // much of a performance hit would it be? + const u8* loadPairedFloatTwo = AlignCode4(); + if (jit->jo.memcheck) + { + SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 64, 0, QUANTIZED_REGS_TO_SAVE, false, + SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); + ROL(64, R(RSCRATCH_EXTRA), Imm8(32)); + MOVQ_xmm(XMM0, R(RSCRATCH_EXTRA)); + } + else if (cpu_info.bSSSE3) + { + MOVQ_xmm(XMM0, MRegSum(RMEM, RSCRATCH_EXTRA)); + PSHUFB(XMM0, M(pbswapShuffle2x4)); + } + else + { + LoadAndSwap(64, RSCRATCH_EXTRA, MRegSum(RMEM, RSCRATCH_EXTRA)); + ROL(64, R(RSCRATCH_EXTRA), Imm8(32)); + MOVQ_xmm(XMM0, R(RSCRATCH_EXTRA)); + } + RET(); - const u8* loadPairedFloatOne = AlignCode4(); - if (jit->jo.memcheck) - { - SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 32, 0, QUANTIZED_REGS_TO_SAVE, false, SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); - MOVD_xmm(XMM0, R(RSCRATCH_EXTRA)); - UNPCKLPS(XMM0, M(m_one)); - } - else if (cpu_info.bSSSE3) - { - MOVD_xmm(XMM0, MRegSum(RMEM, RSCRATCH_EXTRA)); - PSHUFB(XMM0, M(pbswapShuffle1x4)); - UNPCKLPS(XMM0, M(m_one)); - } - else - { - LoadAndSwap(32, RSCRATCH_EXTRA, MRegSum(RMEM, RSCRATCH_EXTRA)); - MOVD_xmm(XMM0, R(RSCRATCH_EXTRA)); - UNPCKLPS(XMM0, M(m_one)); - } - RET(); + const u8* loadPairedFloatOne = AlignCode4(); + if (jit->jo.memcheck) + { + SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 32, 0, QUANTIZED_REGS_TO_SAVE, false, + SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); + MOVD_xmm(XMM0, R(RSCRATCH_EXTRA)); + UNPCKLPS(XMM0, M(m_one)); + } + else if (cpu_info.bSSSE3) + { + MOVD_xmm(XMM0, MRegSum(RMEM, RSCRATCH_EXTRA)); + PSHUFB(XMM0, M(pbswapShuffle1x4)); + UNPCKLPS(XMM0, M(m_one)); + } + else + { + LoadAndSwap(32, RSCRATCH_EXTRA, MRegSum(RMEM, RSCRATCH_EXTRA)); + MOVD_xmm(XMM0, R(RSCRATCH_EXTRA)); + UNPCKLPS(XMM0, M(m_one)); + } + RET(); - const u8* loadPairedU8Two = AlignCode4(); - if (jit->jo.memcheck) - { - // TODO: Support not swapping in safeLoadToReg to avoid bswapping twice - SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 16, 0, QUANTIZED_REGS_TO_SAVE_LOAD, false, SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); - ROR(16, R(RSCRATCH_EXTRA), Imm8(8)); - } - else - { - UnsafeLoadRegToRegNoSwap(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 16, 0); - } - MOVD_xmm(XMM0, R(RSCRATCH_EXTRA)); - if (cpu_info.bSSE4_1) - { - PMOVZXBD(XMM0, R(XMM0)); - } - else - { - PXOR(XMM1, R(XMM1)); - PUNPCKLBW(XMM0, R(XMM1)); - PUNPCKLWD(XMM0, R(XMM1)); - } - CVTDQ2PS(XMM0, R(XMM0)); - SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); - MULPS(XMM0, R(XMM1)); - RET(); + const u8* loadPairedU8Two = AlignCode4(); + if (jit->jo.memcheck) + { + // TODO: Support not swapping in safeLoadToReg to avoid bswapping twice + SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 16, 0, QUANTIZED_REGS_TO_SAVE_LOAD, false, + SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); + ROR(16, R(RSCRATCH_EXTRA), Imm8(8)); + } + else + { + UnsafeLoadRegToRegNoSwap(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 16, 0); + } + MOVD_xmm(XMM0, R(RSCRATCH_EXTRA)); + if (cpu_info.bSSE4_1) + { + PMOVZXBD(XMM0, R(XMM0)); + } + else + { + PXOR(XMM1, R(XMM1)); + PUNPCKLBW(XMM0, R(XMM1)); + PUNPCKLWD(XMM0, R(XMM1)); + } + CVTDQ2PS(XMM0, R(XMM0)); + SHR(32, R(RSCRATCH2), Imm8(5)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); + MULPS(XMM0, R(XMM1)); + RET(); - const u8* loadPairedU8One = AlignCode4(); - if (jit->jo.memcheck) - SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 8, 0, QUANTIZED_REGS_TO_SAVE_LOAD, false, SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); - else - UnsafeLoadRegToRegNoSwap(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 8, 0); // RSCRATCH_EXTRA = 0x000000xx - CVTSI2SS(XMM0, R(RSCRATCH_EXTRA)); - SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); - UNPCKLPS(XMM0, M(m_one)); - RET(); + const u8* loadPairedU8One = AlignCode4(); + if (jit->jo.memcheck) + SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 8, 0, QUANTIZED_REGS_TO_SAVE_LOAD, false, + SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); + else + UnsafeLoadRegToRegNoSwap(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 8, 0); // RSCRATCH_EXTRA = 0x000000xx + CVTSI2SS(XMM0, R(RSCRATCH_EXTRA)); + SHR(32, R(RSCRATCH2), Imm8(5)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); + UNPCKLPS(XMM0, M(m_one)); + RET(); - const u8* loadPairedS8Two = AlignCode4(); - if (jit->jo.memcheck) - { - // TODO: Support not swapping in safeLoadToReg to avoid bswapping twice - SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 16, 0, QUANTIZED_REGS_TO_SAVE_LOAD, false, SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); - ROR(16, R(RSCRATCH_EXTRA), Imm8(8)); - } - else - { - UnsafeLoadRegToRegNoSwap(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 16, 0); - } - MOVD_xmm(XMM0, R(RSCRATCH_EXTRA)); - if (cpu_info.bSSE4_1) - { - PMOVSXBD(XMM0, R(XMM0)); - } - else - { - PUNPCKLBW(XMM0, R(XMM0)); - PUNPCKLWD(XMM0, R(XMM0)); - PSRAD(XMM0, 24); - } - CVTDQ2PS(XMM0, R(XMM0)); - SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); - MULPS(XMM0, R(XMM1)); - RET(); + const u8* loadPairedS8Two = AlignCode4(); + if (jit->jo.memcheck) + { + // TODO: Support not swapping in safeLoadToReg to avoid bswapping twice + SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 16, 0, QUANTIZED_REGS_TO_SAVE_LOAD, false, + SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); + ROR(16, R(RSCRATCH_EXTRA), Imm8(8)); + } + else + { + UnsafeLoadRegToRegNoSwap(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 16, 0); + } + MOVD_xmm(XMM0, R(RSCRATCH_EXTRA)); + if (cpu_info.bSSE4_1) + { + PMOVSXBD(XMM0, R(XMM0)); + } + else + { + PUNPCKLBW(XMM0, R(XMM0)); + PUNPCKLWD(XMM0, R(XMM0)); + PSRAD(XMM0, 24); + } + CVTDQ2PS(XMM0, R(XMM0)); + SHR(32, R(RSCRATCH2), Imm8(5)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); + MULPS(XMM0, R(XMM1)); + RET(); - const u8* loadPairedS8One = AlignCode4(); - if (jit->jo.memcheck) - SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 8, 0, QUANTIZED_REGS_TO_SAVE_LOAD, true, SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); - else - UnsafeLoadRegToRegNoSwap(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 8, 0, true); - CVTSI2SS(XMM0, R(RSCRATCH_EXTRA)); - SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); - UNPCKLPS(XMM0, M(m_one)); - RET(); + const u8* loadPairedS8One = AlignCode4(); + if (jit->jo.memcheck) + SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 8, 0, QUANTIZED_REGS_TO_SAVE_LOAD, true, + SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); + else + UnsafeLoadRegToRegNoSwap(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 8, 0, true); + CVTSI2SS(XMM0, R(RSCRATCH_EXTRA)); + SHR(32, R(RSCRATCH2), Imm8(5)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); + UNPCKLPS(XMM0, M(m_one)); + RET(); - const u8* loadPairedU16Two = AlignCode4(); - // TODO: Support not swapping in (un)safeLoadToReg to avoid bswapping twice - if (jit->jo.memcheck) - SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 32, 0, QUANTIZED_REGS_TO_SAVE_LOAD, false, SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); - else - UnsafeLoadRegToReg(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 32, 0, false); - ROL(32, R(RSCRATCH_EXTRA), Imm8(16)); - MOVD_xmm(XMM0, R(RSCRATCH_EXTRA)); - if (cpu_info.bSSE4_1) - { - PMOVZXWD(XMM0, R(XMM0)); - } - else - { - PXOR(XMM1, R(XMM1)); - PUNPCKLWD(XMM0, R(XMM1)); - } - CVTDQ2PS(XMM0, R(XMM0)); - SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); - MULPS(XMM0, R(XMM1)); - RET(); + const u8* loadPairedU16Two = AlignCode4(); + // TODO: Support not swapping in (un)safeLoadToReg to avoid bswapping twice + if (jit->jo.memcheck) + SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 32, 0, QUANTIZED_REGS_TO_SAVE_LOAD, false, + SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); + else + UnsafeLoadRegToReg(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 32, 0, false); + ROL(32, R(RSCRATCH_EXTRA), Imm8(16)); + MOVD_xmm(XMM0, R(RSCRATCH_EXTRA)); + if (cpu_info.bSSE4_1) + { + PMOVZXWD(XMM0, R(XMM0)); + } + else + { + PXOR(XMM1, R(XMM1)); + PUNPCKLWD(XMM0, R(XMM1)); + } + CVTDQ2PS(XMM0, R(XMM0)); + SHR(32, R(RSCRATCH2), Imm8(5)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); + MULPS(XMM0, R(XMM1)); + RET(); - const u8* loadPairedU16One = AlignCode4(); - if (jit->jo.memcheck) - SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 16, 0, QUANTIZED_REGS_TO_SAVE_LOAD, false, SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); - else - UnsafeLoadRegToReg(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 16, 0, false); - CVTSI2SS(XMM0, R(RSCRATCH_EXTRA)); - SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); - UNPCKLPS(XMM0, M(m_one)); - RET(); + const u8* loadPairedU16One = AlignCode4(); + if (jit->jo.memcheck) + SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 16, 0, QUANTIZED_REGS_TO_SAVE_LOAD, false, + SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); + else + UnsafeLoadRegToReg(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 16, 0, false); + CVTSI2SS(XMM0, R(RSCRATCH_EXTRA)); + SHR(32, R(RSCRATCH2), Imm8(5)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); + UNPCKLPS(XMM0, M(m_one)); + RET(); - const u8* loadPairedS16Two = AlignCode4(); - if (jit->jo.memcheck) - SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 32, 0, QUANTIZED_REGS_TO_SAVE_LOAD, false, SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); - else - UnsafeLoadRegToReg(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 32, 0, false); - ROL(32, R(RSCRATCH_EXTRA), Imm8(16)); - MOVD_xmm(XMM0, R(RSCRATCH_EXTRA)); - if (cpu_info.bSSE4_1) - { - PMOVSXWD(XMM0, R(XMM0)); - } - else - { - PUNPCKLWD(XMM0, R(XMM0)); - PSRAD(XMM0, 16); - } - CVTDQ2PS(XMM0, R(XMM0)); - SHR(32, R(RSCRATCH2), Imm8(5)); - MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); - MULPS(XMM0, R(XMM1)); - RET(); + const u8* loadPairedS16Two = AlignCode4(); + if (jit->jo.memcheck) + SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 32, 0, QUANTIZED_REGS_TO_SAVE_LOAD, false, + SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); + else + UnsafeLoadRegToReg(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 32, 0, false); + ROL(32, R(RSCRATCH_EXTRA), Imm8(16)); + MOVD_xmm(XMM0, R(RSCRATCH_EXTRA)); + if (cpu_info.bSSE4_1) + { + PMOVSXWD(XMM0, R(XMM0)); + } + else + { + PUNPCKLWD(XMM0, R(XMM0)); + PSRAD(XMM0, 16); + } + CVTDQ2PS(XMM0, R(XMM0)); + SHR(32, R(RSCRATCH2), Imm8(5)); + MOVQ_xmm(XMM1, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); + MULPS(XMM0, R(XMM1)); + RET(); - const u8* loadPairedS16One = AlignCode4(); - if (jit->jo.memcheck) - SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 16, 0, QUANTIZED_REGS_TO_SAVE_LOAD, true, SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); - else - UnsafeLoadRegToReg(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 16, 0, true); - CVTSI2SS(XMM0, R(RSCRATCH_EXTRA)); - SHR(32, R(RSCRATCH2), Imm8(5)); - MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); - UNPCKLPS(XMM0, M(m_one)); - RET(); + const u8* loadPairedS16One = AlignCode4(); + if (jit->jo.memcheck) + SafeLoadToReg(RSCRATCH_EXTRA, R(RSCRATCH_EXTRA), 16, 0, QUANTIZED_REGS_TO_SAVE_LOAD, true, + SAFE_LOADSTORE_NO_FASTMEM | SAFE_LOADSTORE_NO_PROLOG); + else + UnsafeLoadRegToReg(RSCRATCH_EXTRA, RSCRATCH_EXTRA, 16, 0, true); + CVTSI2SS(XMM0, R(RSCRATCH_EXTRA)); + SHR(32, R(RSCRATCH2), Imm8(5)); + MULSS(XMM0, MDisp(RSCRATCH2, (u32)(u64)m_dequantizeTableS)); + UNPCKLPS(XMM0, M(m_one)); + RET(); + JitRegister::Register(start, GetCodePtr(), "JIT_QuantizedLoad"); - JitRegister::Register(start, GetCodePtr(), "JIT_QuantizedLoad"); + pairedLoadQuantized = reinterpret_cast(const_cast(AlignCode16())); + ReserveCodeSpace(16 * sizeof(u8*)); - pairedLoadQuantized = reinterpret_cast(const_cast(AlignCode16())); - ReserveCodeSpace(16 * sizeof(u8*)); + pairedLoadQuantized[0] = loadPairedFloatTwo; + pairedLoadQuantized[1] = loadPairedIllegal; + pairedLoadQuantized[2] = loadPairedIllegal; + pairedLoadQuantized[3] = loadPairedIllegal; + pairedLoadQuantized[4] = loadPairedU8Two; + pairedLoadQuantized[5] = loadPairedU16Two; + pairedLoadQuantized[6] = loadPairedS8Two; + pairedLoadQuantized[7] = loadPairedS16Two; - pairedLoadQuantized[0] = loadPairedFloatTwo; - pairedLoadQuantized[1] = loadPairedIllegal; - pairedLoadQuantized[2] = loadPairedIllegal; - pairedLoadQuantized[3] = loadPairedIllegal; - pairedLoadQuantized[4] = loadPairedU8Two; - pairedLoadQuantized[5] = loadPairedU16Two; - pairedLoadQuantized[6] = loadPairedS8Two; - pairedLoadQuantized[7] = loadPairedS16Two; - - pairedLoadQuantized[8] = loadPairedFloatOne; - pairedLoadQuantized[9] = loadPairedIllegal; - pairedLoadQuantized[10] = loadPairedIllegal; - pairedLoadQuantized[11] = loadPairedIllegal; - pairedLoadQuantized[12] = loadPairedU8One; - pairedLoadQuantized[13] = loadPairedU16One; - pairedLoadQuantized[14] = loadPairedS8One; - pairedLoadQuantized[15] = loadPairedS16One; + pairedLoadQuantized[8] = loadPairedFloatOne; + pairedLoadQuantized[9] = loadPairedIllegal; + pairedLoadQuantized[10] = loadPairedIllegal; + pairedLoadQuantized[11] = loadPairedIllegal; + pairedLoadQuantized[12] = loadPairedU8One; + pairedLoadQuantized[13] = loadPairedU16One; + pairedLoadQuantized[14] = loadPairedS8One; + pairedLoadQuantized[15] = loadPairedS16One; } diff --git a/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.h b/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.h index 9509923bb9..62f38b5c8e 100644 --- a/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.h +++ b/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.h @@ -4,19 +4,19 @@ #pragma once -#include "Core/PowerPC/JitCommon/Jit_Util.h" #include "Core/PowerPC/JitCommon/JitAsmCommon.h" +#include "Core/PowerPC/JitCommon/Jit_Util.h" class CommonAsmRoutines : public CommonAsmRoutinesBase, public EmuCodeBlock { protected: - void GenQuantizedLoads(); - void GenQuantizedStores(); - void GenQuantizedSingleStores(); + void GenQuantizedLoads(); + void GenQuantizedStores(); + void GenQuantizedSingleStores(); public: - void GenFifoWrite(int size); - void GenFrsqrte(); - void GenFres(); - void GenMfcr(); + void GenFifoWrite(int size); + void GenFrsqrte(); + void GenFres(); + void GenMfcr(); }; diff --git a/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp index 06102dc8f7..dbcd3c6e91 100644 --- a/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp @@ -21,15 +21,16 @@ The register allocation is linear scan allocation. */ #ifdef _MSC_VER -#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned +#pragma warning( \ + disable : 4146) // unary minus operator applied to unsigned type, result still unsigned #endif #include #include #include "Common/BitSet.h" -#include "Common/CommonTypes.h" #include "Common/CPUDetect.h" +#include "Common/CommonTypes.h" #include "Common/MathUtil.h" #include "Common/MsgHandler.h" #include "Common/x64ABI.h" @@ -38,8 +39,8 @@ The register allocation is linear scan allocation. #include "Core/HW/CPU.h" #include "Core/HW/ProcessorInterface.h" #include "Core/PowerPC/Gekko.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/Jit64IL/JitIL.h" +#include "Core/PowerPC/PowerPC.h" using namespace IREmitter; using namespace Gen; @@ -48,67 +49,69 @@ static const unsigned int MAX_NUMBER_OF_REGS = 16; struct RegInfo { - JitIL *Jit; - IRBuilder* Build; - InstLoc FirstI; + JitIL* Jit; + IRBuilder* Build; + InstLoc FirstI; - // IInfo contains (per instruction) - // Bits 0-1: Saturating count of number of instructions referencing this instruction. - // Bits 2-3: single bit per operand marking if this is the last instruction to reference that operand's result. - // Used to decide if we should free any registers associated with the operands after this instruction - // and if we can clobber the operands registers. - // Warning, Memory instruction use these bits slightly differently. - // Bits 15-31: Spill location - std::vector IInfo; + // IInfo contains (per instruction) + // Bits 0-1: Saturating count of number of instructions referencing this instruction. + // Bits 2-3: single bit per operand marking if this is the last instruction to reference that + // operand's result. + // Used to decide if we should free any registers associated with the operands after + // this instruction + // and if we can clobber the operands registers. + // Warning, Memory instruction use these bits slightly differently. + // Bits 15-31: Spill location + std::vector IInfo; - // The last instruction which uses the result of this instruction. Used by the register allocator. - std::vector lastUsed; + // The last instruction which uses the result of this instruction. Used by the register allocator. + std::vector lastUsed; - InstLoc regs[MAX_NUMBER_OF_REGS]; - InstLoc fregs[MAX_NUMBER_OF_REGS]; - unsigned numSpills; - unsigned numFSpills; - unsigned exitNumber; + InstLoc regs[MAX_NUMBER_OF_REGS]; + InstLoc fregs[MAX_NUMBER_OF_REGS]; + unsigned numSpills; + unsigned numFSpills; + unsigned exitNumber; - RegInfo(JitIL* j, InstLoc f, unsigned insts) - : Jit(j), Build(nullptr), FirstI(f), IInfo(insts), lastUsed(insts) - , regs(), fregs(), numSpills(0), numFSpills(0), exitNumber(0) - { - } + RegInfo(JitIL* j, InstLoc f, unsigned insts) + : Jit(j), Build(nullptr), FirstI(f), IInfo(insts), lastUsed(insts), regs(), fregs(), + numSpills(0), numFSpills(0), exitNumber(0) + { + } - private: - RegInfo(RegInfo&); // DO NOT IMPLEMENT +private: + RegInfo(RegInfo&); // DO NOT IMPLEMENT }; static BitSet32 regsInUse(RegInfo& R) { - BitSet32 result; - for (unsigned i = 0; i < MAX_NUMBER_OF_REGS; i++) - { - if (R.regs[i] != nullptr) - result[i] = true; - if (R.fregs[i] != nullptr) - result[16 + i] = true; - } - return result; + BitSet32 result; + for (unsigned i = 0; i < MAX_NUMBER_OF_REGS; i++) + { + if (R.regs[i] != nullptr) + result[i] = true; + if (R.fregs[i] != nullptr) + result[16 + i] = true; + } + return result; } static void regMarkUse(RegInfo& R, InstLoc I, InstLoc Op, unsigned OpNum) { - unsigned& info = R.IInfo[Op - R.FirstI]; + unsigned& info = R.IInfo[Op - R.FirstI]; - if (info == 0) - R.IInfo[I - R.FirstI] |= 1 << (OpNum + 1); + if (info == 0) + R.IInfo[I - R.FirstI] |= 1 << (OpNum + 1); - if (info < 2) - info++; + if (info < 2) + info++; - R.lastUsed[Op - R.FirstI] = std::max(R.lastUsed[Op - R.FirstI], I); + R.lastUsed[Op - R.FirstI] = std::max(R.lastUsed[Op - R.FirstI], I); } static unsigned regReadUse(RegInfo& R, InstLoc I) { - return R.IInfo[I - R.FirstI] & 3; + return R.IInfo[I - R.FirstI] & 3; } static u64 SlotSet[1000]; @@ -116,66 +119,66 @@ alignas(16) static u8 FSlotSet[16 * 1000]; static OpArg regLocForSlot(RegInfo& RI, unsigned slot) { - return M(&SlotSet[slot - 1]); + return M(&SlotSet[slot - 1]); } static unsigned regCreateSpill(RegInfo& RI, InstLoc I) { - unsigned newSpill = ++RI.numSpills; - RI.IInfo[I - RI.FirstI] |= newSpill << 16; - return newSpill; + unsigned newSpill = ++RI.numSpills; + RI.IInfo[I - RI.FirstI] |= newSpill << 16; + return newSpill; } static unsigned regGetSpill(RegInfo& RI, InstLoc I) { - return RI.IInfo[I - RI.FirstI] >> 16; + return RI.IInfo[I - RI.FirstI] >> 16; } static void regSpill(RegInfo& RI, X64Reg reg) { - if (!RI.regs[reg]) - return; + if (!RI.regs[reg]) + return; - unsigned slot = regGetSpill(RI, RI.regs[reg]); - if (!slot) - { - slot = regCreateSpill(RI, RI.regs[reg]); - RI.Jit->MOV(64, regLocForSlot(RI, slot), R(reg)); - } + unsigned slot = regGetSpill(RI, RI.regs[reg]); + if (!slot) + { + slot = regCreateSpill(RI, RI.regs[reg]); + RI.Jit->MOV(64, regLocForSlot(RI, slot), R(reg)); + } - RI.regs[reg] = nullptr; + RI.regs[reg] = nullptr; } static OpArg fregLocForSlot(RegInfo& RI, unsigned slot) { - return M(&FSlotSet[slot*16]); + return M(&FSlotSet[slot * 16]); } static unsigned fregCreateSpill(RegInfo& RI, InstLoc I) { - unsigned newSpill = ++RI.numFSpills; - RI.IInfo[I - RI.FirstI] |= newSpill << 16; - return newSpill; + unsigned newSpill = ++RI.numFSpills; + RI.IInfo[I - RI.FirstI] |= newSpill << 16; + return newSpill; } static unsigned fregGetSpill(RegInfo& RI, InstLoc I) { - return RI.IInfo[I - RI.FirstI] >> 16; + return RI.IInfo[I - RI.FirstI] >> 16; } static void fregSpill(RegInfo& RI, X64Reg reg) { - if (!RI.fregs[reg]) - return; + if (!RI.fregs[reg]) + return; - unsigned slot = fregGetSpill(RI, RI.fregs[reg]); - if (!slot) - { - slot = fregCreateSpill(RI, RI.fregs[reg]); - RI.Jit->MOVAPD(fregLocForSlot(RI, slot), reg); - } + unsigned slot = fregGetSpill(RI, RI.fregs[reg]); + if (!slot) + { + slot = fregCreateSpill(RI, RI.fregs[reg]); + RI.Jit->MOVAPD(fregLocForSlot(RI, slot), reg); + } - RI.fregs[reg] = nullptr; + RI.fregs[reg] = nullptr; } // RAX and RDX are scratch, so we don't allocate them @@ -189,2157 +192,2164 @@ static const X64Reg RegAllocOrder[] = {RSI, RDI, R12, R13, R14, R8, R9, R10, R11 static const X64Reg RegAllocOrder[] = {R12, R13, R14, R8, R9, R10, R11}; #endif static const int RegAllocSize = sizeof(RegAllocOrder) / sizeof(X64Reg); -static const X64Reg FRegAllocOrder[] = {XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5}; +static const X64Reg FRegAllocOrder[] = {XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, + XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5}; static const int FRegAllocSize = sizeof(FRegAllocOrder) / sizeof(X64Reg); static X64Reg regFindFreeReg(RegInfo& RI) { - for (auto& reg : RegAllocOrder) - { - if (RI.regs[reg] == nullptr) - return reg; - } + for (auto& reg : RegAllocOrder) + { + if (RI.regs[reg] == nullptr) + return reg; + } - int bestIndex = -1; - InstLoc bestEnd = nullptr; - for (int i = 0; i < RegAllocSize; ++i) - { - const InstLoc start = RI.regs[RegAllocOrder[i]]; - const InstLoc end = RI.lastUsed[start - RI.FirstI]; + int bestIndex = -1; + InstLoc bestEnd = nullptr; + for (int i = 0; i < RegAllocSize; ++i) + { + const InstLoc start = RI.regs[RegAllocOrder[i]]; + const InstLoc end = RI.lastUsed[start - RI.FirstI]; - if (bestEnd < end) - { - bestEnd = end; - bestIndex = i; - } - } + if (bestEnd < end) + { + bestEnd = end; + bestIndex = i; + } + } - X64Reg reg = RegAllocOrder[bestIndex]; - regSpill(RI, reg); - return reg; + X64Reg reg = RegAllocOrder[bestIndex]; + regSpill(RI, reg); + return reg; } static X64Reg fregFindFreeReg(RegInfo& RI) { - for (auto& reg : FRegAllocOrder) - { - if (RI.fregs[reg] == nullptr) - return reg; - } + for (auto& reg : FRegAllocOrder) + { + if (RI.fregs[reg] == nullptr) + return reg; + } - int bestIndex = -1; - InstLoc bestEnd = nullptr; - for (int i = 0; i < FRegAllocSize; ++i) - { - const InstLoc start = RI.fregs[FRegAllocOrder[i]]; - const InstLoc end = RI.lastUsed[start - RI.FirstI]; + int bestIndex = -1; + InstLoc bestEnd = nullptr; + for (int i = 0; i < FRegAllocSize; ++i) + { + const InstLoc start = RI.fregs[FRegAllocOrder[i]]; + const InstLoc end = RI.lastUsed[start - RI.FirstI]; - if (bestEnd < end) - { - bestEnd = end; - bestIndex = i; - } - } + if (bestEnd < end) + { + bestEnd = end; + bestIndex = i; + } + } - X64Reg reg = FRegAllocOrder[bestIndex]; - fregSpill(RI, reg); - return reg; + X64Reg reg = FRegAllocOrder[bestIndex]; + fregSpill(RI, reg); + return reg; } static OpArg regLocForInst(RegInfo& RI, InstLoc I) { - for (auto& reg : RegAllocOrder) - { - if (RI.regs[reg] == I) - return R(reg); - } + for (auto& reg : RegAllocOrder) + { + if (RI.regs[reg] == I) + return R(reg); + } - unsigned slot = regGetSpill(RI, I); - if (!slot) - PanicAlert("Retrieving unknown spill slot?!"); - return regLocForSlot(RI, slot); + unsigned slot = regGetSpill(RI, I); + if (!slot) + PanicAlert("Retrieving unknown spill slot?!"); + return regLocForSlot(RI, slot); } static OpArg fregLocForInst(RegInfo& RI, InstLoc I) { - for (auto& reg : FRegAllocOrder) - { - if (RI.fregs[reg] == I) - return R(reg); - } + for (auto& reg : FRegAllocOrder) + { + if (RI.fregs[reg] == I) + return R(reg); + } - unsigned slot = fregGetSpill(RI, I); - if (!slot) - PanicAlert("Retrieving unknown spill slot?!"); - return fregLocForSlot(RI, slot); + unsigned slot = fregGetSpill(RI, I); + if (!slot) + PanicAlert("Retrieving unknown spill slot?!"); + return fregLocForSlot(RI, slot); } static void regClearInst(RegInfo& RI, InstLoc I) { - for (auto& reg : RegAllocOrder) - { - if (RI.regs[reg] == I) - RI.regs[reg] = nullptr; - } + for (auto& reg : RegAllocOrder) + { + if (RI.regs[reg] == I) + RI.regs[reg] = nullptr; + } } static void fregClearInst(RegInfo& RI, InstLoc I) { - for (auto& reg : FRegAllocOrder) - { - if (RI.fregs[reg] == I) - RI.fregs[reg] = nullptr; - } + for (auto& reg : FRegAllocOrder) + { + if (RI.fregs[reg] == I) + RI.fregs[reg] = nullptr; + } } static X64Reg regEnsureInReg(RegInfo& RI, InstLoc I) { - OpArg loc = regLocForInst(RI, I); + OpArg loc = regLocForInst(RI, I); - if (!loc.IsSimpleReg()) - { - X64Reg newReg = regFindFreeReg(RI); - RI.Jit->MOV(32, R(newReg), loc); - loc = R(newReg); - } + if (!loc.IsSimpleReg()) + { + X64Reg newReg = regFindFreeReg(RI); + RI.Jit->MOV(32, R(newReg), loc); + loc = R(newReg); + } - return loc.GetSimpleReg(); + return loc.GetSimpleReg(); } static X64Reg fregEnsureInReg(RegInfo& RI, InstLoc I) { - OpArg loc = fregLocForInst(RI, I); + OpArg loc = fregLocForInst(RI, I); - if (!loc.IsSimpleReg()) - { - X64Reg newReg = fregFindFreeReg(RI); - RI.Jit->MOVAPD(newReg, loc); - loc = R(newReg); - } + if (!loc.IsSimpleReg()) + { + X64Reg newReg = fregFindFreeReg(RI); + RI.Jit->MOVAPD(newReg, loc); + loc = R(newReg); + } - return loc.GetSimpleReg(); + return loc.GetSimpleReg(); } static void regSpillCallerSaved(RegInfo& RI) { - regSpill(RI, RCX); - regSpill(RI, RDX); - regSpill(RI, RSI); - regSpill(RI, RDI); - regSpill(RI, R8); - regSpill(RI, R9); - regSpill(RI, R10); - regSpill(RI, R11); + regSpill(RI, RCX); + regSpill(RI, RDX); + regSpill(RI, RSI); + regSpill(RI, RDI); + regSpill(RI, R8); + regSpill(RI, R9); + regSpill(RI, R10); + regSpill(RI, R11); } static X64Reg regUReg(RegInfo& RI, InstLoc I) { - const OpArg loc = regLocForInst(RI, getOp1(I)); + const OpArg loc = regLocForInst(RI, getOp1(I)); - if ((RI.IInfo[I - RI.FirstI] & 4) && loc.IsSimpleReg()) - { - return loc.GetSimpleReg(); - } + if ((RI.IInfo[I - RI.FirstI] & 4) && loc.IsSimpleReg()) + { + return loc.GetSimpleReg(); + } - return regFindFreeReg(RI); + return regFindFreeReg(RI); } // Recycle the register if the lifetime of op1 register ends at I. static X64Reg fregURegWithoutMov(RegInfo& RI, InstLoc I) { - const OpArg loc = fregLocForInst(RI, getOp1(I)); + const OpArg loc = fregLocForInst(RI, getOp1(I)); - if ((RI.IInfo[I - RI.FirstI] & 4) && loc.IsSimpleReg()) - { - return loc.GetSimpleReg(); - } + if ((RI.IInfo[I - RI.FirstI] & 4) && loc.IsSimpleReg()) + { + return loc.GetSimpleReg(); + } - return fregFindFreeReg(RI); + return fregFindFreeReg(RI); } static X64Reg fregURegWithMov(RegInfo& RI, InstLoc I) { - const OpArg loc = fregLocForInst(RI, getOp1(I)); + const OpArg loc = fregLocForInst(RI, getOp1(I)); - if ((RI.IInfo[I - RI.FirstI] & 4) && loc.IsSimpleReg()) - { - return loc.GetSimpleReg(); - } + if ((RI.IInfo[I - RI.FirstI] & 4) && loc.IsSimpleReg()) + { + return loc.GetSimpleReg(); + } - X64Reg reg = fregFindFreeReg(RI); - RI.Jit->MOVAPD(reg, loc); - return reg; + X64Reg reg = fregFindFreeReg(RI); + RI.Jit->MOVAPD(reg, loc); + return reg; } // Recycle the register if the lifetime of op1 register ends at I. static X64Reg fregBinLHSRegWithMov(RegInfo& RI, InstLoc I) { - const OpArg loc = fregLocForInst(RI, getOp1(I)); + const OpArg loc = fregLocForInst(RI, getOp1(I)); - if ((RI.IInfo[I - RI.FirstI] & 4) && loc.IsSimpleReg()) - { - return loc.GetSimpleReg(); - } + if ((RI.IInfo[I - RI.FirstI] & 4) && loc.IsSimpleReg()) + { + return loc.GetSimpleReg(); + } - X64Reg reg = fregFindFreeReg(RI); - RI.Jit->MOVAPD(reg, loc); - return reg; + X64Reg reg = fregFindFreeReg(RI); + RI.Jit->MOVAPD(reg, loc); + return reg; } // Recycle the register if the lifetime of op2 register ends at I. static X64Reg fregBinRHSRegWithMov(RegInfo& RI, InstLoc I) { - const OpArg loc = fregLocForInst(RI, getOp2(I)); + const OpArg loc = fregLocForInst(RI, getOp2(I)); - if ((RI.IInfo[I - RI.FirstI] & 8) && loc.IsSimpleReg()) - { - return loc.GetSimpleReg(); - } + if ((RI.IInfo[I - RI.FirstI] & 8) && loc.IsSimpleReg()) + { + return loc.GetSimpleReg(); + } - X64Reg reg = fregFindFreeReg(RI); - RI.Jit->MOVAPD(reg, loc); - return reg; + X64Reg reg = fregFindFreeReg(RI); + RI.Jit->MOVAPD(reg, loc); + return reg; } // If the lifetime of the register used by an operand ends at I, // return the register. Otherwise return a free register. static X64Reg regBinReg(RegInfo& RI, InstLoc I) { - // FIXME: When regLocForInst() is extracted as a local variable, - // "Retrieving unknown spill slot?!" is shown. - if ((RI.IInfo[I - RI.FirstI] & 4) && regLocForInst(RI, getOp1(I)).IsSimpleReg()) - { - return regLocForInst(RI, getOp1(I)).GetSimpleReg(); - } - else if ((RI.IInfo[I - RI.FirstI] & 8) && regLocForInst(RI, getOp2(I)).IsSimpleReg()) - { - return regLocForInst(RI, getOp2(I)).GetSimpleReg(); - } + // FIXME: When regLocForInst() is extracted as a local variable, + // "Retrieving unknown spill slot?!" is shown. + if ((RI.IInfo[I - RI.FirstI] & 4) && regLocForInst(RI, getOp1(I)).IsSimpleReg()) + { + return regLocForInst(RI, getOp1(I)).GetSimpleReg(); + } + else if ((RI.IInfo[I - RI.FirstI] & 8) && regLocForInst(RI, getOp2(I)).IsSimpleReg()) + { + return regLocForInst(RI, getOp2(I)).GetSimpleReg(); + } - return regFindFreeReg(RI); + return regFindFreeReg(RI); } static X64Reg regBinLHSReg(RegInfo& RI, InstLoc I) { - if (RI.IInfo[I - RI.FirstI] & 4) - { - return regEnsureInReg(RI, getOp1(I)); - } + if (RI.IInfo[I - RI.FirstI] & 4) + { + return regEnsureInReg(RI, getOp1(I)); + } - X64Reg reg = regFindFreeReg(RI); - RI.Jit->MOV(32, R(reg), regLocForInst(RI, getOp1(I))); - return reg; + X64Reg reg = regFindFreeReg(RI); + RI.Jit->MOV(32, R(reg), regLocForInst(RI, getOp1(I))); + return reg; } // Clear any registers which end their lifetime at I // Don't use this for special instructions like memory load/stores static void regNormalRegClear(RegInfo& RI, InstLoc I) { - if (RI.IInfo[I - RI.FirstI] & 4) - regClearInst(RI, getOp1(I)); - if (RI.IInfo[I - RI.FirstI] & 8) - regClearInst(RI, getOp2(I)); + if (RI.IInfo[I - RI.FirstI] & 4) + regClearInst(RI, getOp1(I)); + if (RI.IInfo[I - RI.FirstI] & 8) + regClearInst(RI, getOp2(I)); } // Clear any floating point registers which end their lifetime at I static void fregNormalRegClear(RegInfo& RI, InstLoc I) { - if (RI.IInfo[I - RI.FirstI] & 4) - fregClearInst(RI, getOp1(I)); - if (RI.IInfo[I - RI.FirstI] & 8) - fregClearInst(RI, getOp2(I)); + if (RI.IInfo[I - RI.FirstI] & 4) + fregClearInst(RI, getOp1(I)); + if (RI.IInfo[I - RI.FirstI] & 8) + fregClearInst(RI, getOp2(I)); } static void regEmitBinInst(RegInfo& RI, InstLoc I, void (JitIL::*op)(int, const OpArg&, const OpArg&), bool commutable = false) { - X64Reg reg; - bool commuted = false; - if (RI.IInfo[I - RI.FirstI] & 4) - { - reg = regEnsureInReg(RI, getOp1(I)); - } - else if (commutable && (RI.IInfo[I - RI.FirstI] & 8)) - { - reg = regEnsureInReg(RI, getOp2(I)); - commuted = true; - } - else - { - reg = regFindFreeReg(RI); - RI.Jit->MOV(32, R(reg), regLocForInst(RI, getOp1(I))); - } + X64Reg reg; + bool commuted = false; + if (RI.IInfo[I - RI.FirstI] & 4) + { + reg = regEnsureInReg(RI, getOp1(I)); + } + else if (commutable && (RI.IInfo[I - RI.FirstI] & 8)) + { + reg = regEnsureInReg(RI, getOp2(I)); + commuted = true; + } + else + { + reg = regFindFreeReg(RI); + RI.Jit->MOV(32, R(reg), regLocForInst(RI, getOp1(I))); + } - if (isImm(*getOp2(I))) - { - unsigned RHS = RI.Build->GetImmValue(getOp2(I)); - if (RHS + 128 < 256) - { - (RI.Jit->*op)(32, R(reg), Imm8(RHS)); - } - else - { - (RI.Jit->*op)(32, R(reg), Imm32(RHS)); - } - } - else if (commuted) - { - (RI.Jit->*op)(32, R(reg), regLocForInst(RI, getOp1(I))); - } - else - { - (RI.Jit->*op)(32, R(reg), regLocForInst(RI, getOp2(I))); - } + if (isImm(*getOp2(I))) + { + unsigned RHS = RI.Build->GetImmValue(getOp2(I)); + if (RHS + 128 < 256) + { + (RI.Jit->*op)(32, R(reg), Imm8(RHS)); + } + else + { + (RI.Jit->*op)(32, R(reg), Imm32(RHS)); + } + } + else if (commuted) + { + (RI.Jit->*op)(32, R(reg), regLocForInst(RI, getOp1(I))); + } + else + { + (RI.Jit->*op)(32, R(reg), regLocForInst(RI, getOp2(I))); + } - RI.regs[reg] = I; - regNormalRegClear(RI, I); + RI.regs[reg] = I; + regNormalRegClear(RI, I); } static void fregEmitBinInst(RegInfo& RI, InstLoc I, void (JitIL::*op)(X64Reg, const OpArg&)) { - X64Reg reg; + X64Reg reg; - if (RI.IInfo[I - RI.FirstI] & 4) - { - reg = fregEnsureInReg(RI, getOp1(I)); - } - else - { - reg = fregFindFreeReg(RI); - RI.Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); - } + if (RI.IInfo[I - RI.FirstI] & 4) + { + reg = fregEnsureInReg(RI, getOp1(I)); + } + else + { + reg = fregFindFreeReg(RI); + RI.Jit->MOVAPD(reg, fregLocForInst(RI, getOp1(I))); + } - (RI.Jit->*op)(reg, fregLocForInst(RI, getOp2(I))); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); + (RI.Jit->*op)(reg, fregLocForInst(RI, getOp2(I))); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); } // Mark and calculation routines for profiled load/store addresses // Could be extended to unprofiled addresses. static void regMarkMemAddress(RegInfo& RI, InstLoc I, InstLoc AI, unsigned OpNum) { - if (isImm(*AI)) - { - unsigned addr = RI.Build->GetImmValue(AI); - if (PowerPC::IsOptimizableRAMAddress(addr)) - return; - } + if (isImm(*AI)) + { + unsigned addr = RI.Build->GetImmValue(AI); + if (PowerPC::IsOptimizableRAMAddress(addr)) + return; + } - if (getOpcode(*AI) == Add && isImm(*getOp2(AI))) - { - regMarkUse(RI, I, getOp1(AI), OpNum); - return; - } + if (getOpcode(*AI) == Add && isImm(*getOp2(AI))) + { + regMarkUse(RI, I, getOp1(AI), OpNum); + return; + } - regMarkUse(RI, I, AI, OpNum); + regMarkUse(RI, I, AI, OpNum); } // in 64-bit build, this returns a completely bizarre address sometimes! -static std::pair regBuildMemAddress(RegInfo& RI, InstLoc I, InstLoc AI, - unsigned OpNum, X64Reg* dest) +static std::pair regBuildMemAddress(RegInfo& RI, InstLoc I, InstLoc AI, unsigned OpNum, + X64Reg* dest) { - if (isImm(*AI)) - { - unsigned addr = RI.Build->GetImmValue(AI); - if (PowerPC::IsOptimizableRAMAddress(addr)) - { - if (dest) - *dest = regFindFreeReg(RI); + if (isImm(*AI)) + { + unsigned addr = RI.Build->GetImmValue(AI); + if (PowerPC::IsOptimizableRAMAddress(addr)) + { + if (dest) + *dest = regFindFreeReg(RI); - return std::make_pair(Imm32(addr), 0); - } - } + return std::make_pair(Imm32(addr), 0); + } + } - unsigned offset; - InstLoc AddrBase; - if (getOpcode(*AI) == Add && isImm(*getOp2(AI))) - { - offset = RI.Build->GetImmValue(getOp2(AI)); - AddrBase = getOp1(AI); - } - else - { - offset = 0; - AddrBase = AI; - } + unsigned offset; + InstLoc AddrBase; + if (getOpcode(*AI) == Add && isImm(*getOp2(AI))) + { + offset = RI.Build->GetImmValue(getOp2(AI)); + AddrBase = getOp1(AI); + } + else + { + offset = 0; + AddrBase = AI; + } - X64Reg baseReg; - // Ok, this stuff needs a comment or three :P -ector - if (RI.IInfo[I - RI.FirstI] & (2 << OpNum)) - { - baseReg = regEnsureInReg(RI, AddrBase); - regClearInst(RI, AddrBase); - if (dest) - *dest = baseReg; - } - else if (dest) - { - X64Reg reg = regFindFreeReg(RI); - const OpArg loc = regLocForInst(RI, AddrBase); - if (!loc.IsSimpleReg()) - { - RI.Jit->MOV(32, R(reg), loc); - baseReg = reg; - } - else - { - baseReg = loc.GetSimpleReg(); - } - *dest = reg; - } - else - { - baseReg = regEnsureInReg(RI, AddrBase); - } + X64Reg baseReg; + // Ok, this stuff needs a comment or three :P -ector + if (RI.IInfo[I - RI.FirstI] & (2 << OpNum)) + { + baseReg = regEnsureInReg(RI, AddrBase); + regClearInst(RI, AddrBase); + if (dest) + *dest = baseReg; + } + else if (dest) + { + X64Reg reg = regFindFreeReg(RI); + const OpArg loc = regLocForInst(RI, AddrBase); + if (!loc.IsSimpleReg()) + { + RI.Jit->MOV(32, R(reg), loc); + baseReg = reg; + } + else + { + baseReg = loc.GetSimpleReg(); + } + *dest = reg; + } + else + { + baseReg = regEnsureInReg(RI, AddrBase); + } - return std::make_pair(R(baseReg), offset); + return std::make_pair(R(baseReg), offset); } static void regEmitMemLoad(RegInfo& RI, InstLoc I, unsigned Size) { - X64Reg reg; - auto info = regBuildMemAddress(RI, I, getOp1(I), 1, ®); + X64Reg reg; + auto info = regBuildMemAddress(RI, I, getOp1(I), 1, ®); - RI.Jit->SafeLoadToReg(reg, info.first, Size, info.second, regsInUse(RI), false); - if (regReadUse(RI, I)) - RI.regs[reg] = I; + RI.Jit->SafeLoadToReg(reg, info.first, Size, info.second, regsInUse(RI), false); + if (regReadUse(RI, I)) + RI.regs[reg] = I; } static OpArg regImmForConst(RegInfo& RI, InstLoc I, unsigned Size) { - unsigned imm = RI.Build->GetImmValue(I); + unsigned imm = RI.Build->GetImmValue(I); - if (Size == 32) - { - return Imm32(imm); - } - else if (Size == 16) - { - return Imm16(imm); - } - else - { - return Imm8(imm); - } + if (Size == 32) + { + return Imm32(imm); + } + else if (Size == 16) + { + return Imm16(imm); + } + else + { + return Imm8(imm); + } } static void regEmitMemStore(RegInfo& RI, InstLoc I, unsigned Size) { - auto info = regBuildMemAddress(RI, I, getOp2(I), 2, nullptr); - if (info.first.IsImm()) - RI.Jit->MOV(32, R(RSCRATCH2), info.first); - else - RI.Jit->LEA(32, RSCRATCH2, MDisp(info.first.GetSimpleReg(), info.second)); + auto info = regBuildMemAddress(RI, I, getOp2(I), 2, nullptr); + if (info.first.IsImm()) + RI.Jit->MOV(32, R(RSCRATCH2), info.first); + else + RI.Jit->LEA(32, RSCRATCH2, MDisp(info.first.GetSimpleReg(), info.second)); - regSpill(RI, RSCRATCH); + regSpill(RI, RSCRATCH); - if (isImm(*getOp1(I))) - { - RI.Jit->MOV(Size, R(RSCRATCH), regImmForConst(RI, getOp1(I), Size)); - } - else - { - RI.Jit->MOV(32, R(RSCRATCH), regLocForInst(RI, getOp1(I))); - } + if (isImm(*getOp1(I))) + { + RI.Jit->MOV(Size, R(RSCRATCH), regImmForConst(RI, getOp1(I), Size)); + } + else + { + RI.Jit->MOV(32, R(RSCRATCH), regLocForInst(RI, getOp1(I))); + } - RI.Jit->SafeWriteRegToReg(RSCRATCH, RSCRATCH2, Size, 0, regsInUse(RI)); - if (RI.IInfo[I - RI.FirstI] & 4) - regClearInst(RI, getOp1(I)); + RI.Jit->SafeWriteRegToReg(RSCRATCH, RSCRATCH2, Size, 0, regsInUse(RI)); + if (RI.IInfo[I - RI.FirstI] & 4) + regClearInst(RI, getOp1(I)); } -static void regEmitShiftInst(RegInfo& RI, InstLoc I, void (JitIL::*op)(int, const OpArg&, const OpArg&)) +static void regEmitShiftInst(RegInfo& RI, InstLoc I, + void (JitIL::*op)(int, const OpArg&, const OpArg&)) { - X64Reg reg = regBinLHSReg(RI, I); + X64Reg reg = regBinLHSReg(RI, I); - if (isImm(*getOp2(I))) - { - unsigned RHS = RI.Build->GetImmValue(getOp2(I)); - (RI.Jit->*op)(32, R(reg), Imm8(RHS)); - RI.regs[reg] = I; - return; - } + if (isImm(*getOp2(I))) + { + unsigned RHS = RI.Build->GetImmValue(getOp2(I)); + (RI.Jit->*op)(32, R(reg), Imm8(RHS)); + RI.regs[reg] = I; + return; + } - RI.Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I))); - (RI.Jit->*op)(32, R(reg), R(ECX)); - RI.regs[reg] = I; - regNormalRegClear(RI, I); + RI.Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I))); + (RI.Jit->*op)(32, R(reg), R(ECX)); + RI.regs[reg] = I; + regNormalRegClear(RI, I); } static void regStoreInstToConstLoc(RegInfo& RI, unsigned width, InstLoc I, void* loc) { - if (width != 32) - { - PanicAlert("Not implemented!"); - return; - } + if (width != 32) + { + PanicAlert("Not implemented!"); + return; + } - if (isImm(*I)) - { - RI.Jit->MOV(32, M(loc), Imm32(RI.Build->GetImmValue(I))); - return; - } + if (isImm(*I)) + { + RI.Jit->MOV(32, M(loc), Imm32(RI.Build->GetImmValue(I))); + return; + } - X64Reg reg = regEnsureInReg(RI, I); - RI.Jit->MOV(32, M(loc), R(reg)); + X64Reg reg = regEnsureInReg(RI, I); + RI.Jit->MOV(32, M(loc), R(reg)); } static void regEmitCmp(RegInfo& RI, InstLoc I) { - if (isImm(*getOp2(I))) - { - unsigned RHS = RI.Build->GetImmValue(getOp2(I)); - RI.Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm32(RHS)); - } - else - { - X64Reg reg = regEnsureInReg(RI, getOp1(I)); - RI.Jit->CMP(32, R(reg), regLocForInst(RI, getOp2(I))); - } + if (isImm(*getOp2(I))) + { + unsigned RHS = RI.Build->GetImmValue(getOp2(I)); + RI.Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm32(RHS)); + } + else + { + X64Reg reg = regEnsureInReg(RI, getOp1(I)); + RI.Jit->CMP(32, R(reg), regLocForInst(RI, getOp2(I))); + } } static void regEmitICmpInst(RegInfo& RI, InstLoc I, CCFlags flag) { - regEmitCmp(RI, I); - RI.Jit->SETcc(flag, R(RSCRATCH2)); // Caution: SETCC uses 8-bit regs! - X64Reg reg = regBinReg(RI, I); - RI.Jit->MOVZX(32, 8, reg, R(RSCRATCH2)); - RI.regs[reg] = I; - regNormalRegClear(RI, I); + regEmitCmp(RI, I); + RI.Jit->SETcc(flag, R(RSCRATCH2)); // Caution: SETCC uses 8-bit regs! + X64Reg reg = regBinReg(RI, I); + RI.Jit->MOVZX(32, 8, reg, R(RSCRATCH2)); + RI.regs[reg] = I; + regNormalRegClear(RI, I); } static void regEmitICmpCRInst(RegInfo& RI, InstLoc I) { - bool signed_compare = getOpcode(*I) == ICmpCRSigned; - X64Reg reg; + bool signed_compare = getOpcode(*I) == ICmpCRSigned; + X64Reg reg; - if (RI.IInfo[I - RI.FirstI] & 4) - { - reg = regEnsureInReg(RI, getOp1(I)); - if (signed_compare) - RI.Jit->MOVSX(64, 32, reg, R(reg)); - } - else - { - reg = regFindFreeReg(RI); - if (signed_compare) - RI.Jit->MOVSX(64, 32, reg, regLocForInst(RI, getOp1(I))); - else - RI.Jit->MOV(32, R(reg), regLocForInst(RI, getOp1(I))); - } + if (RI.IInfo[I - RI.FirstI] & 4) + { + reg = regEnsureInReg(RI, getOp1(I)); + if (signed_compare) + RI.Jit->MOVSX(64, 32, reg, R(reg)); + } + else + { + reg = regFindFreeReg(RI); + if (signed_compare) + RI.Jit->MOVSX(64, 32, reg, regLocForInst(RI, getOp1(I))); + else + RI.Jit->MOV(32, R(reg), regLocForInst(RI, getOp1(I))); + } - if (isImm(*getOp2(I))) - { - unsigned RHS = RI.Build->GetImmValue(getOp2(I)); - if (!signed_compare && (RHS & 0x80000000U)) - { - RI.Jit->MOV(32, R(RSCRATCH), Imm32(RHS)); - RI.Jit->SUB(64, R(reg), R(RSCRATCH)); - } - else if (RHS) - { - RI.Jit->SUB(64, R(reg), Imm32(RHS)); - } - } - else - { - if (signed_compare) - RI.Jit->MOVSX(64, 32, RSCRATCH, regLocForInst(RI, getOp2(I))); - else - RI.Jit->MOV(32, R(RSCRATCH), regLocForInst(RI, getOp2(I))); - RI.Jit->SUB(64, R(reg), R(RSCRATCH)); - } + if (isImm(*getOp2(I))) + { + unsigned RHS = RI.Build->GetImmValue(getOp2(I)); + if (!signed_compare && (RHS & 0x80000000U)) + { + RI.Jit->MOV(32, R(RSCRATCH), Imm32(RHS)); + RI.Jit->SUB(64, R(reg), R(RSCRATCH)); + } + else if (RHS) + { + RI.Jit->SUB(64, R(reg), Imm32(RHS)); + } + } + else + { + if (signed_compare) + RI.Jit->MOVSX(64, 32, RSCRATCH, regLocForInst(RI, getOp2(I))); + else + RI.Jit->MOV(32, R(RSCRATCH), regLocForInst(RI, getOp2(I))); + RI.Jit->SUB(64, R(reg), R(RSCRATCH)); + } - RI.regs[reg] = I; - regNormalRegClear(RI, I); + RI.regs[reg] = I; + regNormalRegClear(RI, I); } static void regWriteExit(RegInfo& RI, InstLoc dest) { - if (isImm(*dest)) - { - RI.exitNumber++; - RI.Jit->WriteExit(RI.Build->GetImmValue(dest)); - } - else - { - RI.Jit->WriteExitDestInOpArg(regLocForInst(RI, dest)); - } + if (isImm(*dest)) + { + RI.exitNumber++; + RI.Jit->WriteExit(RI.Build->GetImmValue(dest)); + } + else + { + RI.Jit->WriteExitDestInOpArg(regLocForInst(RI, dest)); + } } // Helper function to check floating point exceptions alignas(16) static double isSNANTemp[2][2]; static bool checkIsSNAN() { - return MathUtil::IsSNAN(isSNANTemp[0][0]) || MathUtil::IsSNAN(isSNANTemp[1][0]); + return MathUtil::IsSNAN(isSNANTemp[0][0]) || MathUtil::IsSNAN(isSNANTemp[1][0]); } static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress) { - //printf("Writing block: %x\n", js.blockStart); - RegInfo RI(Jit, ibuild->getFirstInst(), ibuild->getNumInsts()); - RI.Build = ibuild; - - // Pass to compute liveness - ibuild->StartBackPass(); - for (unsigned int index = (unsigned int)RI.IInfo.size() - 1; index != -1U; --index) - { - InstLoc I = ibuild->ReadBackward(); - unsigned int op = getOpcode(*I); - bool thisUsed = regReadUse(RI, I) ? true : false; - - switch (op) - { - default: - PanicAlert("Unexpected inst!"); - case Nop: - case CInt16: - case CInt32: - case LoadGReg: - case LoadLink: - case LoadCR: - case LoadCarry: - case LoadCTR: - case LoadMSR: - case LoadFReg: - case LoadFRegDENToZero: - case LoadGQR: - case BlockEnd: - case BlockStart: - case FallBackToInterpreter: - case SystemCall: - case RFIExit: - case InterpreterBranch: - case ShortIdleLoop: - case FPExceptionCheck: - case DSIExceptionCheck: - case ExtExceptionCheck: - case BreakPointCheck: - case Int3: - case Tramp: - // No liveness effects - break; - case SExt8: - case SExt16: - case BSwap32: - case BSwap16: - case Cntlzw: - case Not: - case DupSingleToMReg: - case DoubleToSingle: - case ExpandPackedToMReg: - case CompactMRegToPacked: - case FPNeg: - case FPDup0: - case FPDup1: - case FSNeg: - case FDNeg: - case ConvertFromFastCR: - case ConvertToFastCR: - case FastCRSOSet: - case FastCREQSet: - case FastCRGTSet: - case FastCRLTSet: - if (thisUsed) - regMarkUse(RI, I, getOp1(I), 1); - break; - case Load8: - case Load16: - case Load32: - case LoadDouble: - case LoadSingle: - regMarkMemAddress(RI, I, getOp1(I), 1); - break; - case LoadPaired: - if (thisUsed) - regMarkUse(RI, I, getOp1(I), 1); - break; - case StoreCR: - case StoreCarry: - case StoreFPRF: - regMarkUse(RI, I, getOp1(I), 1); - break; - case StoreGReg: - case StoreLink: - case StoreCTR: - case StoreMSR: - case StoreGQR: - case StoreSRR: - case StoreFReg: - if (!isImm(*getOp1(I))) - regMarkUse(RI, I, getOp1(I), 1); - break; - case Add: - case Sub: - case And: - case Or: - case Xor: - case Mul: - case MulHighUnsigned: - case Rol: - case Shl: - case Shrl: - case Sarl: - case ICmpCRUnsigned: - case ICmpCRSigned: - case ICmpEq: - case ICmpNe: - case ICmpUgt: - case ICmpUlt: - case ICmpUge: - case ICmpUle: - case ICmpSgt: - case ICmpSlt: - case ICmpSge: - case ICmpSle: - case FSMul: - case FSAdd: - case FSSub: - case FDMul: - case FDAdd: - case FDSub: - case FPAdd: - case FPMul: - case FPSub: - case FPMerge00: - case FPMerge01: - case FPMerge10: - case FPMerge11: - case FDCmpCR: - case InsertDoubleInMReg: - if (thisUsed) - { - regMarkUse(RI, I, getOp1(I), 1); - if (!isImm(*getOp2(I))) - regMarkUse(RI, I, getOp2(I), 2); - } - break; - case Store8: - case Store16: - case Store32: - if (!isImm(*getOp1(I))) - regMarkUse(RI, I, getOp1(I), 1); - regMarkMemAddress(RI, I, getOp2(I), 2); - break; - case StoreSingle: - case StoreDouble: - regMarkUse(RI, I, getOp1(I), 1); - regMarkMemAddress(RI, I, getOp2(I), 2); - break; - case StorePaired: - regMarkUse(RI, I, getOp1(I), 1); - regMarkUse(RI, I, getOp2(I), 2); - break; - case BranchUncond: - if (!isImm(*getOp1(I))) - regMarkUse(RI, I, getOp1(I), 1); - break; - case IdleBranch: - regMarkUse(RI, I, getOp1(I), 1); - break; - case BranchCond: - { - if (isICmp(*getOp1(I))) - { - regMarkUse(RI, I, getOp1(getOp1(I)), 1); - if (!isImm(*getOp2(getOp1(I)))) - regMarkUse(RI, I, getOp2(getOp1(I)), 2); - } - else - { - regMarkUse(RI, I, getOp1(I), 1); - } - if (!isImm(*getOp2(I))) - regMarkUse(RI, I, getOp2(I), 2); - break; - } - } - } - - ibuild->StartForwardPass(); - for (unsigned i = 0; i != RI.IInfo.size(); i++) - { - InstLoc I = ibuild->ReadForward(); - bool thisUsed = regReadUse(RI, I) ? true : false; - if (thisUsed) - { - // Needed for IR Writer - ibuild->SetMarkUsed(I); - } - - switch (getOpcode(*I)) - { - case FallBackToInterpreter: - { - unsigned InstCode = ibuild->GetImmValue(getOp1(I)); - unsigned InstLoc = ibuild->GetImmValue(getOp2(I)); - // There really shouldn't be anything live across an - // interpreter call at the moment, but optimizing interpreter - // calls isn't completely out of the question... - regSpillCallerSaved(RI); - Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc)); - Jit->MOV(32, PPCSTATE(npc), Imm32(InstLoc+4)); - Jit->ABI_CallFunctionC((void*)GetInterpreterOp(InstCode), - InstCode); - break; - } - case LoadGReg: - { - if (!thisUsed) - break; - - X64Reg reg = regFindFreeReg(RI); - unsigned ppcreg = *I >> 8; - Jit->MOV(32, R(reg), PPCSTATE(gpr[ppcreg])); - RI.regs[reg] = I; - break; - } - case LoadCR: - { - if (!thisUsed) - break; - - X64Reg reg = regFindFreeReg(RI); - unsigned ppcreg = *I >> 8; - Jit->MOV(64, R(reg), PPCSTATE(cr_val[ppcreg])); - RI.regs[reg] = I; - break; - } - case LoadCTR: - { - if (!thisUsed) - break; - - X64Reg reg = regFindFreeReg(RI); - Jit->MOV(32, R(reg), PPCSTATE_CTR); - RI.regs[reg] = I; - break; - } - case LoadLink: - { - if (!thisUsed) - break; - - X64Reg reg = regFindFreeReg(RI); - Jit->MOV(32, R(reg), PPCSTATE_LR); - RI.regs[reg] = I; - break; - } - case LoadMSR: - { - if (!thisUsed) - break; - - X64Reg reg = regFindFreeReg(RI); - Jit->MOV(32, R(reg), PPCSTATE(msr)); - RI.regs[reg] = I; - break; - } - case LoadGQR: - { - if (!thisUsed) - break; - - X64Reg reg = regFindFreeReg(RI); - unsigned gqr = *I >> 8; - Jit->MOV(32, R(reg), PPCSTATE(spr[SPR_GQR0 + gqr])); - RI.regs[reg] = I; - break; - } - case LoadCarry: - { - if (!thisUsed) - break; - - X64Reg reg = regFindFreeReg(RI); - Jit->MOVZX(32, 8, reg, PPCSTATE(xer_ca)); - RI.regs[reg] = I; - break; - } - case StoreGReg: - { - unsigned ppcreg = *I >> 16; - regStoreInstToConstLoc(RI, 32, getOp1(I), - &PowerPC::ppcState.gpr[ppcreg]); - regNormalRegClear(RI, I); - break; - } - case StoreCR: - { - X64Reg reg = regEnsureInReg(RI, getOp1(I)); - unsigned ppcreg = *I >> 16; - Jit->MOV(64, PPCSTATE(cr_val[ppcreg]), R(reg)); - regNormalRegClear(RI, I); - break; - } - case StoreLink: - { - regStoreInstToConstLoc(RI, 32, getOp1(I), &LR); - regNormalRegClear(RI, I); - break; - } - case StoreCTR: - { - regStoreInstToConstLoc(RI, 32, getOp1(I), &CTR); - regNormalRegClear(RI, I); - break; - } - case StoreMSR: - { - unsigned InstLoc = ibuild->GetImmValue(getOp2(I)); - regStoreInstToConstLoc(RI, 32, getOp1(I), &MSR); - regNormalRegClear(RI, I); - - // If some exceptions are pending and EE are now enabled, force checking - // external exceptions when going out of mtmsr in order to execute delayed - // interrupts as soon as possible. - Jit->MOV(32, R(RSCRATCH), PPCSTATE(msr)); - Jit->TEST(32, R(RSCRATCH), Imm32(0x8000)); - FixupBranch eeDisabled = Jit->J_CC(CC_Z); - - Jit->MOV(32, R(RSCRATCH), PPCSTATE(Exceptions)); - Jit->TEST(32, R(RSCRATCH), R(RSCRATCH)); - FixupBranch noExceptionsPending = Jit->J_CC(CC_Z); - - Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc + 4)); - Jit->WriteExceptionExit(); // TODO: Implement WriteExternalExceptionExit for JitIL - - Jit->SetJumpTarget(eeDisabled); - Jit->SetJumpTarget(noExceptionsPending); - break; - } - case StoreGQR: - { - unsigned gqr = *I >> 16; - regStoreInstToConstLoc(RI, 32, getOp1(I), &GQR(gqr)); - regNormalRegClear(RI, I); - break; - } - case StoreSRR: - { - unsigned srr = *I >> 16; - regStoreInstToConstLoc(RI, 32, getOp1(I), - &PowerPC::ppcState.spr[SPR_SRR0+srr]); - regNormalRegClear(RI, I); - break; - } - case StoreCarry: - { - Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm8(0)); - FixupBranch nocarry = Jit->J_CC(CC_Z); - Jit->JitSetCA(); - FixupBranch cont = Jit->J(); - Jit->SetJumpTarget(nocarry); - Jit->JitClearCA(); - Jit->SetJumpTarget(cont); - regNormalRegClear(RI, I); - break; - } - case StoreFPRF: - { - Jit->MOV(32, R(RSCRATCH2), regLocForInst(RI, getOp1(I))); - Jit->AND(32, R(RSCRATCH2), Imm8(0x1F)); - Jit->SHL(32, R(RSCRATCH2), Imm8(12)); - Jit->AND(32, PPCSTATE(fpscr), Imm32(~(0x1F << 12))); - Jit->OR(32, PPCSTATE(fpscr), R(RSCRATCH2)); - regNormalRegClear(RI, I); - break; - } - case Load8: - { - regEmitMemLoad(RI, I, 8); - break; - } - case Load16: - { - regEmitMemLoad(RI, I, 16); - break; - } - case Load32: - { - regEmitMemLoad(RI, I, 32); - break; - } - case Store8: - { - regEmitMemStore(RI, I, 8); - break; - } - case Store16: - { - regEmitMemStore(RI, I, 16); - break; - } - case Store32: - { - regEmitMemStore(RI, I, 32); - break; - } - case SExt8: - { - if (!thisUsed) - break; - - X64Reg reg = regUReg(RI, I); - Jit->MOV(32, R(RSCRATCH2), regLocForInst(RI, getOp1(I))); - Jit->MOVSX(32, 8, reg, R(RSCRATCH2)); - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case SExt16: - { - if (!thisUsed) - break; - - X64Reg reg = regUReg(RI, I); - Jit->MOVSX(32, 16, reg, regLocForInst(RI, getOp1(I))); - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case Cntlzw: - { - if (!thisUsed) - break; - - X64Reg reg = regUReg(RI, I); - Jit->MOV(32, R(RSCRATCH2), Imm32(63)); - Jit->BSR(32, reg, regLocForInst(RI, getOp1(I))); - Jit->CMOVcc(32, reg, R(RSCRATCH2), CC_Z); - Jit->XOR(32, R(reg), Imm8(31)); - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case Not: - { - if (!thisUsed) - break; - - X64Reg reg = regBinLHSReg(RI, I); - Jit->NOT(32, R(reg)); - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case And: - { - if (!thisUsed) - break; - - regEmitBinInst(RI, I, &JitIL::AND, true); - break; - } - case Xor: - { - if (!thisUsed) - break; - - regEmitBinInst(RI, I, &JitIL::XOR, true); - break; - } - case Sub: - { - if (!thisUsed) - break; - - regEmitBinInst(RI, I, &JitIL::SUB); - break; - } - case Or: - { - if (!thisUsed) - break; - - regEmitBinInst(RI, I, &JitIL::OR, true); - break; - } - case Add: - { - if (!thisUsed) - break; - - regEmitBinInst(RI, I, &JitIL::ADD, true); - break; - } - case Mul: - { - if (!thisUsed) - break; - - // FIXME: Use three-address capability of IMUL! - X64Reg reg = regBinLHSReg(RI, I); - if (isImm(*getOp2(I))) - { - unsigned RHS = RI.Build->GetImmValue(getOp2(I)); - if (RHS + 128 < 256) - Jit->IMUL(32, reg, Imm8(RHS)); - else - Jit->IMUL(32, reg, Imm32(RHS)); - } - else - { - Jit->IMUL(32, reg, regLocForInst(RI, getOp2(I))); - } - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case MulHighUnsigned: - { - if (!thisUsed) - break; - - // no register choice - regSpill(RI, EAX); - regSpill(RI, EDX); - X64Reg reg = regBinReg(RI, I); - if (isImm(*getOp2(I))) - { - unsigned RHS = RI.Build->GetImmValue(getOp2(I)); - Jit->MOV(32, R(EAX), Imm32(RHS)); - } - else - { - Jit->MOV(32, R(EAX), regLocForInst(RI, getOp2(I))); - } - Jit->MUL(32, regLocForInst(RI, getOp1(I))); - Jit->MOV(32, R(reg), R(EDX)); - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case Rol: - { - if (!thisUsed) - break; - - regEmitShiftInst(RI, I, &JitIL::ROL); - break; - } - case Shl: - { - if (!thisUsed) - break; - - regEmitShiftInst(RI, I, &JitIL::SHL); - break; - } - case Shrl: - { - if (!thisUsed) - break; - - regEmitShiftInst(RI, I, &JitIL::SHR); - break; - } - case Sarl: - { - if (!thisUsed) - break; - - regEmitShiftInst(RI, I, &JitIL::SAR); - break; - } - case ICmpEq: - { - if (!thisUsed) - break; - - regEmitICmpInst(RI, I, CC_E); - break; - } - case ICmpNe: - { - if (!thisUsed) - break; - - regEmitICmpInst(RI, I, CC_NE); - break; - } - case ICmpUgt: - { - if (!thisUsed) - break; - - regEmitICmpInst(RI, I, CC_A); - break; - } - case ICmpUlt: - { - if (!thisUsed) - break; - - regEmitICmpInst(RI, I, CC_B); - break; - } - case ICmpUge: - { - if (!thisUsed) - break; - - regEmitICmpInst(RI, I, CC_AE); - break; - } - case ICmpUle: - { - if (!thisUsed) - break; - - regEmitICmpInst(RI, I, CC_BE); - break; - } - case ICmpSgt: - { - if (!thisUsed) - break; - - regEmitICmpInst(RI, I, CC_G); - break; - } - case ICmpSlt: - { - if (!thisUsed) - break; - - regEmitICmpInst(RI, I, CC_L); - break; - } - case ICmpSge: - { - if (!thisUsed) - break; - - regEmitICmpInst(RI, I, CC_GE); - break; - } - case ICmpSle: - { - if (!thisUsed) - break; - - regEmitICmpInst(RI, I, CC_LE); - break; - } - case ICmpCRUnsigned: - { - if (!thisUsed) - break; - - regEmitICmpCRInst(RI, I); - break; - } - case ICmpCRSigned: - { - if (!thisUsed) - break; - - regEmitICmpCRInst(RI, I); - break; - } - case ConvertFromFastCR: - { - if (!thisUsed) - break; - - X64Reg cr_val = regUReg(RI, I); - Jit->MOV(64, R(cr_val), regLocForInst(RI, getOp1(I))); - - Jit->XOR(32, R(RSCRATCH), R(RSCRATCH)); - - // SO: Bit 61 set. - Jit->MOV(64, R(RSCRATCH2), R(cr_val)); - Jit->SHR(64, R(RSCRATCH2), Imm8(61)); - Jit->AND(32, R(RSCRATCH2), Imm8(1)); - Jit->OR(32, R(RSCRATCH), R(RSCRATCH2)); - - // EQ: Bits 31-0 == 0. - Jit->XOR(32, R(RSCRATCH2), R(RSCRATCH2)); - Jit->TEST(32, R(cr_val), R(cr_val)); - Jit->SETcc(CC_Z, R(RSCRATCH2)); - Jit->SHL(32, R(RSCRATCH2), Imm8(1)); - Jit->OR(32, R(RSCRATCH), R(RSCRATCH2)); - - // GT: Value > 0. - Jit->XOR(32, R(RSCRATCH2), R(RSCRATCH2)); - Jit->TEST(64, R(cr_val), R(cr_val)); - Jit->SETcc(CC_G, R(RSCRATCH2)); - Jit->SHL(32, R(RSCRATCH2), Imm8(2)); - Jit->OR(32, R(RSCRATCH), R(RSCRATCH2)); - - // LT: Bit 62 set. - Jit->MOV(64, R(RSCRATCH2), R(cr_val)); - Jit->SHR(64, R(RSCRATCH2), Imm8(62 - 3)); - Jit->AND(32, R(RSCRATCH2), Imm8(0x8)); - Jit->OR(32, R(RSCRATCH), R(RSCRATCH2)); - - Jit->MOV(32, R(cr_val), R(RSCRATCH)); - RI.regs[cr_val] = I; - regNormalRegClear(RI, I); - break; - } - case ConvertToFastCR: - { - if (!thisUsed) - break; - - X64Reg cr_val = regUReg(RI, I); - Jit->MOV(64, R(cr_val), regLocForInst(RI, getOp1(I))); - - Jit->MOV(64, R(RSCRATCH2), Imm64(1ull << 32)); - - // SO - Jit->MOV(64, R(RSCRATCH), R(cr_val)); - Jit->SHL(64, R(RSCRATCH), Imm8(63)); - Jit->SHR(64, R(RSCRATCH), Imm8(63 - 61)); - Jit->OR(64, R(RSCRATCH2), R(RSCRATCH)); - - // EQ - Jit->MOV(64, R(RSCRATCH), R(cr_val)); - Jit->NOT(64, R(RSCRATCH)); - Jit->AND(64, R(RSCRATCH), Imm8(CR_EQ)); - Jit->OR(64, R(RSCRATCH2), R(RSCRATCH)); - - // GT - Jit->MOV(64, R(RSCRATCH), R(cr_val)); - Jit->NOT(64, R(RSCRATCH)); - Jit->AND(64, R(RSCRATCH), Imm8(CR_GT)); - Jit->SHL(64, R(RSCRATCH), Imm8(63 - 2)); - Jit->OR(64, R(RSCRATCH2), R(RSCRATCH)); - - // LT - Jit->MOV(64, R(RSCRATCH), R(cr_val)); - Jit->AND(64, R(RSCRATCH), Imm8(CR_LT)); - Jit->SHL(64, R(RSCRATCH), Imm8(62 - 3)); - Jit->OR(64, R(RSCRATCH2), R(RSCRATCH)); - - Jit->MOV(64, R(cr_val), R(RSCRATCH2)); - - RI.regs[cr_val] = I; - regNormalRegClear(RI, I); - break; - } - case FastCRSOSet: - { - if (!thisUsed) - break; - - X64Reg reg = regUReg(RI, I); - Jit->MOV(64, R(RSCRATCH), Imm64(1ull << 61)); - Jit->TEST(64, regLocForInst(RI, getOp1(I)), R(RSCRATCH)); - Jit->SETcc(CC_NZ, R(RSCRATCH)); - Jit->MOVZX(32, 8, reg, R(RSCRATCH)); - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case FastCREQSet: - { - if (!thisUsed) - break; - - X64Reg reg = regUReg(RI, I); - Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm32(0)); - Jit->SETcc(CC_Z, R(RSCRATCH)); - Jit->MOVZX(32, 8, reg, R(RSCRATCH)); - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case FastCRGTSet: - { - if (!thisUsed) - break; - - X64Reg reg = regUReg(RI, I); - Jit->CMP(64, regLocForInst(RI, getOp1(I)), Imm8(0)); - Jit->SETcc(CC_G, R(RSCRATCH)); - Jit->MOVZX(32, 8, reg, R(RSCRATCH)); - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case FastCRLTSet: - { - if (!thisUsed) - break; - - X64Reg reg = regUReg(RI, I); - Jit->MOV(64, R(RSCRATCH), Imm64(1ull << 62)); - Jit->TEST(64, regLocForInst(RI, getOp1(I)), R(RSCRATCH)); - Jit->SETcc(CC_NZ, R(RSCRATCH)); - Jit->MOVZX(32, 8, reg, R(RSCRATCH)); - RI.regs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case LoadSingle: - { - if (!thisUsed) - break; - - X64Reg reg = fregFindFreeReg(RI); - auto info = regBuildMemAddress(RI, I, getOp1(I), 1, nullptr); - - RI.Jit->SafeLoadToReg(RSCRATCH2, info.first, 32, info.second, regsInUse(RI), false); - Jit->MOVD_xmm(reg, R(RSCRATCH2)); - RI.fregs[reg] = I; - break; - } - case LoadDouble: - { - if (!thisUsed) - break; - - X64Reg reg = fregFindFreeReg(RI); - auto info = regBuildMemAddress(RI, I, getOp1(I), 1, nullptr); - - RI.Jit->SafeLoadToReg(RSCRATCH2, info.first, 64, info.second, regsInUse(RI), false); - Jit->MOVQ_xmm(reg, R(RSCRATCH2)); - RI.fregs[reg] = I; - break; - } - case LoadPaired: - { - if (!thisUsed) - break; - - X64Reg reg = fregFindFreeReg(RI); - // The lower 3 bits is for GQR index. The next 1 bit is for inst.W - unsigned int quantreg = (*I >> 16) & 0x7; - unsigned int w = *I >> 19; - // Some games (e.g. Dirt 2) incorrectly set the unused bits which breaks the lookup table code. - // Hence, we need to mask out the unused bits. The layout of the GQR register is - // UU[SCALE]UUUUU[TYPE] where SCALE is 6 bits and TYPE is 3 bits, so we have to AND with - // 0b0011111100000111, or 0x3F07. - Jit->MOV(32, R(RSCRATCH2), Imm32(0x3F07)); - Jit->AND(32, R(RSCRATCH2), M(((char *)&GQR(quantreg)) + 2)); - Jit->MOVZX(32, 8, RSCRATCH, R(RSCRATCH2)); - Jit->OR(32, R(RSCRATCH), Imm8(w << 3)); - - Jit->MOV(32, R(RSCRATCH_EXTRA), regLocForInst(RI, getOp1(I))); - Jit->CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)(Jit->asm_routines.pairedLoadQuantized))); - Jit->MOVAPD(reg, R(XMM0)); - RI.fregs[reg] = I; - regNormalRegClear(RI, I); - break; - } - case StoreSingle: - { - regSpill(RI, RSCRATCH); - const OpArg loc1 = fregLocForInst(RI, getOp1(I)); - if (loc1.IsSimpleReg()) - Jit->MOVD_xmm(R(RSCRATCH), loc1.GetSimpleReg()); - else - Jit->MOV(32, R(RSCRATCH), loc1); - - auto info = regBuildMemAddress(RI, I, getOp2(I), 2, nullptr); - if (info.first.IsImm()) - RI.Jit->MOV(32, R(RSCRATCH2), info.first); - else - RI.Jit->LEA(32, RSCRATCH2, MDisp(info.first.GetSimpleReg(), info.second)); - - RI.Jit->SafeWriteRegToReg(RSCRATCH, RSCRATCH2, 32, 0, regsInUse(RI)); - - if (RI.IInfo[I - RI.FirstI] & 4) - fregClearInst(RI, getOp1(I)); - break; - } - case StoreDouble: - { - regSpill(RI, RSCRATCH); - - OpArg value = fregLocForInst(RI, getOp1(I)); - Jit->MOVAPD(XMM0, value); - Jit->MOVQ_xmm(R(RSCRATCH), XMM0); - - auto info = regBuildMemAddress(RI, I, getOp2(I), 2, nullptr); - if (info.first.IsImm()) - RI.Jit->MOV(32, R(RSCRATCH2), info.first); - else - RI.Jit->LEA(32, RSCRATCH2, MDisp(info.first.GetSimpleReg(), info.second)); - - RI.Jit->SafeWriteRegToReg(RSCRATCH, RSCRATCH2, 64, 0, regsInUse(RI)); - - if (RI.IInfo[I - RI.FirstI] & 4) - fregClearInst(RI, getOp1(I)); - break; - } - case StorePaired: - { - regSpill(RI, RSCRATCH); - regSpill(RI, RSCRATCH2); - u32 quantreg = *I >> 24; - Jit->MOV(32, R(RSCRATCH2), Imm32(0x3F07)); - Jit->AND(32, R(RSCRATCH2), PPCSTATE(spr[SPR_GQR0 + quantreg])); - Jit->MOVZX(32, 8, RSCRATCH, R(RSCRATCH2)); - - Jit->MOV(32, R(RSCRATCH_EXTRA), regLocForInst(RI, getOp2(I))); - Jit->MOVAPD(XMM0, fregLocForInst(RI, getOp1(I))); - Jit->CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)(Jit->asm_routines.pairedStoreQuantized))); - if (RI.IInfo[I - RI.FirstI] & 4) - fregClearInst(RI, getOp1(I)); - if (RI.IInfo[I - RI.FirstI] & 8) - regClearInst(RI, getOp2(I)); - break; - } - case DupSingleToMReg: - { - if (!thisUsed) break; - - X64Reg input = fregEnsureInReg(RI, getOp1(I)); - X64Reg output = fregURegWithoutMov(RI, I); - Jit->ConvertSingleToDouble(output, input); - - RI.fregs[output] = I; - fregNormalRegClear(RI, I); - break; - } - case InsertDoubleInMReg: - { - if (!thisUsed) break; - // r[0] = op1[0]; r[1] = op2[1]; - - // TODO: Optimize the case that the register of op1 can be - // recycled. (SHUFPD may not be so fast.) - X64Reg reg = fregBinRHSRegWithMov(RI, I); - OpArg loc1 = fregLocForInst(RI, getOp1(I)); - if (loc1.IsSimpleReg()) - { - Jit->MOVSD(reg, loc1); - } - else - { - // If op1 is in FSlotSet, we have to mov loc1 to XMM0 - // before MOVSD/MOVSS. - // Because register<->memory transfer with MOVSD/MOVSS - // clears upper 64/96-bits of the destination register. - Jit->MOVAPD(XMM0, loc1); - Jit->MOVSD(reg, R(XMM0)); - } - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case ExpandPackedToMReg: - { - if (!thisUsed) - break; - - X64Reg reg = fregURegWithoutMov(RI, I); - Jit->CVTPS2PD(reg, fregLocForInst(RI, getOp1(I))); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case CompactMRegToPacked: - { - if (!thisUsed) - break; - - X64Reg reg = fregURegWithoutMov(RI, I); - Jit->CVTPD2PS(reg, fregLocForInst(RI, getOp1(I))); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FSNeg: - { - if (!thisUsed) - break; - - X64Reg reg = fregURegWithMov(RI, I); - alignas(16) static const u32 ssSignBits[4] = {0x80000000}; - Jit->PXOR(reg, M(ssSignBits)); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FDNeg: - { - if (!thisUsed) - break; - - X64Reg reg = fregURegWithMov(RI, I); - alignas(16) static const u64 sdSignBits[2] = {0x8000000000000000ULL}; - Jit->PXOR(reg, M(sdSignBits)); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FPNeg: - { - if (!thisUsed) - break; - - X64Reg reg = fregURegWithMov(RI, I); - alignas(16) static const u32 psSignBits[4] = {0x80000000, 0x80000000}; - Jit->PXOR(reg, M(psSignBits)); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FPDup0: - { - if (!thisUsed) - break; - - X64Reg reg = fregURegWithMov(RI, I); - Jit->PUNPCKLDQ(reg, R(reg)); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FPDup1: - { - if (!thisUsed) - break; - - X64Reg reg = fregURegWithMov(RI, I); - Jit->SHUFPS(reg, R(reg), 0xE5); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case LoadFReg: - { - if (!thisUsed) - break; - - X64Reg reg = fregFindFreeReg(RI); - unsigned ppcreg = *I >> 8; - Jit->MOVAPD(reg, PPCSTATE(ps[ppcreg])); - RI.fregs[reg] = I; - break; - } - case LoadFRegDENToZero: - { - if (!thisUsed) - break; - - X64Reg reg = fregFindFreeReg(RI); - unsigned ppcreg = *I >> 8; - char *p = (char*)&(PowerPC::ppcState.ps[ppcreg][0]); - Jit->MOV(32, R(RSCRATCH2), M(p+4)); - Jit->AND(32, R(RSCRATCH2), Imm32(0x7ff00000)); - Jit->CMP(32, R(RSCRATCH2), Imm32(0x38000000)); - FixupBranch ok = Jit->J_CC(CC_AE); - Jit->AND(32, M(p+4), Imm32(0x80000000)); - Jit->MOV(32, M(p), Imm32(0)); - Jit->SetJumpTarget(ok); - Jit->MOVAPD(reg, PPCSTATE(ps[ppcreg])); - RI.fregs[reg] = I; - break; - } - case StoreFReg: - { - unsigned ppcreg = *I >> 16; - Jit->MOVAPD(PPCSTATE(ps[ppcreg]), - fregEnsureInReg(RI, getOp1(I))); - fregNormalRegClear(RI, I); - break; - } - case DoubleToSingle: - { - if (!thisUsed) - break; - - X64Reg input = fregEnsureInReg(RI, getOp1(I)); - X64Reg output = fregURegWithoutMov(RI, I); - Jit->ConvertDoubleToSingle(output, input); - - RI.fregs[output] = I; - fregNormalRegClear(RI, I); - break; - } - case FSMul: - { - if (!thisUsed) - break; - - fregEmitBinInst(RI, I, &JitIL::MULSS); - break; - } - case FSAdd: - { - if (!thisUsed) - break; - - fregEmitBinInst(RI, I, &JitIL::ADDSS); - break; - } - case FSSub: - { - if (!thisUsed) - break; - - fregEmitBinInst(RI, I, &JitIL::SUBSS); - break; - } - case FDMul: - { - if (!thisUsed) - break; - - fregEmitBinInst(RI, I, &JitIL::MULSD); - break; - } - case FDAdd: - { - if (!thisUsed) - break; - - fregEmitBinInst(RI, I, &JitIL::ADDSD); - break; - } - case FDSub: - { - if (!thisUsed) - break; - - fregEmitBinInst(RI, I, &JitIL::SUBSD); - break; - } - case FDCmpCR: - { - const u32 ordered = *I >> 24; - X64Reg destreg = regFindFreeReg(RI); - // TODO: Remove an extra MOVSD if loc1.IsSimpleReg() - OpArg loc1 = fregLocForInst(RI, getOp1(I)); - OpArg loc2 = fregLocForInst(RI, getOp2(I)); - Jit->MOVSD(XMM0, loc1); - Jit->UCOMISD(XMM0, loc2); - FixupBranch pNan = Jit->J_CC(CC_P); - FixupBranch pEqual = Jit->J_CC(CC_Z); - FixupBranch pLesser = Jit->J_CC(CC_C); - // Greater - Jit->MOV(32, R(destreg), Imm32(0x4)); - FixupBranch continue1 = Jit->J(); - // NaN - Jit->SetJumpTarget(pNan); - Jit->MOV(32, R(destreg), Imm32(0x1)); - - if (ordered) - { - // fcmpo - // TODO: Optimize the following code if slow. - // SNAN check may not be needed - // because it does not happen so much. - Jit->MOVSD(M(isSNANTemp[0]), XMM0); - if (loc2.IsSimpleReg()) - { - Jit->MOVSD(M(isSNANTemp[1]), loc2.GetSimpleReg()); - } - else - { - Jit->MOVSD(XMM0, loc2); - Jit->MOVSD(M(isSNANTemp[1]), XMM0); - } - Jit->ABI_CallFunction((void*)checkIsSNAN); - Jit->TEST(8, R(ABI_RETURN), R(ABI_RETURN)); - FixupBranch ok = Jit->J_CC(CC_Z); - Jit->OR(32, PPCSTATE(fpscr), Imm32(FPSCR_FX)); // FPSCR.FX = 1; - Jit->OR(32, PPCSTATE(fpscr), Imm32(FPSCR_VXSNAN)); // FPSCR.Hex |= mask; - Jit->TEST(32, PPCSTATE(fpscr), Imm32(FPSCR_VE)); - FixupBranch finish0 = Jit->J_CC(CC_NZ); - Jit->OR(32, PPCSTATE(fpscr), Imm32(FPSCR_VXVC)); // FPSCR.Hex |= mask; - FixupBranch finish1 = Jit->J(); - Jit->SetJumpTarget(ok); - Jit->OR(32, PPCSTATE(fpscr), Imm32(FPSCR_FX)); // FPSCR.FX = 1; - Jit->OR(32, PPCSTATE(fpscr), Imm32(FPSCR_VXVC)); // FPSCR.Hex |= mask; - Jit->SetJumpTarget(finish0); - Jit->SetJumpTarget(finish1); - } - else - { - // fcmpu - // TODO: Optimize the following code if slow - Jit->MOVSD(M(isSNANTemp[0]), XMM0); - if (loc2.IsSimpleReg()) - { - Jit->MOVSD(M(isSNANTemp[1]), loc2.GetSimpleReg()); - } - else - { - Jit->MOVSD(XMM0, loc2); - Jit->MOVSD(M(isSNANTemp[1]), XMM0); - } - Jit->ABI_CallFunction((void*)checkIsSNAN); - Jit->TEST(8, R(ABI_RETURN), R(ABI_RETURN)); - FixupBranch finish = Jit->J_CC(CC_Z); - Jit->OR(32, PPCSTATE(fpscr), Imm32(FPSCR_FX)); // FPSCR.FX = 1; - Jit->OR(32, PPCSTATE(fpscr), Imm32(FPSCR_VXVC)); // FPSCR.Hex |= mask; - Jit->SetJumpTarget(finish); - } - - FixupBranch continue2 = Jit->J(); - // Equal - Jit->SetJumpTarget(pEqual); - Jit->MOV(32, R(destreg), Imm32(0x2)); - FixupBranch continue3 = Jit->J(); - // Less - Jit->SetJumpTarget(pLesser); - Jit->MOV(32, R(destreg), Imm32(0x8)); - Jit->SetJumpTarget(continue1); - Jit->SetJumpTarget(continue2); - Jit->SetJumpTarget(continue3); - RI.regs[destreg] = I; - fregNormalRegClear(RI, I); - break; - } - case FPAdd: - { - if (!thisUsed) - break; - - fregEmitBinInst(RI, I, &JitIL::ADDPS); - break; - } - case FPMul: - { - if (!thisUsed) - break; - - fregEmitBinInst(RI, I, &JitIL::MULPS); - break; - } - case FPSub: - { - if (!thisUsed) - break; - - fregEmitBinInst(RI, I, &JitIL::SUBPS); - break; - } - case FPMerge00: - { - // r[0] = op1[0]; r[1] = op2[0]; - if (!thisUsed) - break; - - // TODO: Optimize the case that the register of only op2 can be - // recycled. - X64Reg reg = fregBinLHSRegWithMov(RI, I); - Jit->PUNPCKLDQ(reg, fregLocForInst(RI, getOp2(I))); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FPMerge01: - { - // r[0] = op1[0]; r[1] = op2[1]; - if (!thisUsed) - break; - - // TODO: Optimize the case that the register of only op1 can be - // recycled. - X64Reg reg = fregBinRHSRegWithMov(RI, I); - OpArg loc1 = fregLocForInst(RI, getOp1(I)); - if (loc1.IsSimpleReg()) - { - Jit->MOVSS(reg, loc1); - } - else - { - Jit->MOVAPD(XMM0, loc1); - Jit->MOVSS(reg, R(XMM0)); - } - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FPMerge10: - { - // r[0] = op1[1]; r[1] = op2[0]; - if (!thisUsed) - break; - - // TODO: Optimize the case that the register of only op2 can be - // recycled. - X64Reg reg = fregBinLHSRegWithMov(RI, I); - OpArg loc2 = fregLocForInst(RI, getOp2(I)); - if (loc2.IsSimpleReg()) - { - Jit->MOVSS(reg, loc2); - } - else - { - Jit->MOVAPD(XMM0, loc2); - Jit->MOVSS(reg, R(XMM0)); - } - Jit->SHUFPS(reg, R(reg), 0xF1); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case FPMerge11: - { - // r[0] = op1[1]; r[1] = op2[1]; - if (!thisUsed) - break; - - // TODO: Optimize the case that the register of only op2 can be - // recycled. - X64Reg reg = fregBinLHSRegWithMov(RI, I); - // TODO: Check whether the following code works - // when the op1 is in the FSlotSet - Jit->PUNPCKLDQ(reg, fregLocForInst(RI, getOp2(I))); - Jit->SHUFPD(reg, R(reg), 0x1); - RI.fregs[reg] = I; - fregNormalRegClear(RI, I); - break; - } - case CInt32: - case CInt16: - { - if (!thisUsed) - break; - - X64Reg reg = regFindFreeReg(RI); - u64 val = ibuild->GetImmValue64(I); - if ((u32)val == val) - Jit->MOV(32, R(reg), Imm32((u32)val)); - else if ((s32)val == (s64)val) - Jit->MOV(64, R(reg), Imm32((s32)val)); - else - Jit->MOV(64, R(reg), Imm64(val)); - RI.regs[reg] = I; - break; - } - case BlockStart: - case BlockEnd: - break; - - case IdleBranch: - { - // If value is 0, we don't need to call out to the idle function. - OpArg value = regLocForInst(RI, getOp1(I)); - Jit->TEST(32, value, value); - FixupBranch noidle = Jit->J_CC(CC_NZ); - - RI.Jit->Cleanup(); // is it needed? - Jit->ABI_CallFunction((void *)&CoreTiming::Idle); - - Jit->MOV(32, PPCSTATE(pc), Imm32(ibuild->GetImmValue( getOp2(I) ))); - Jit->WriteExceptionExit(); - - Jit->SetJumpTarget(noidle); - if (RI.IInfo[I - RI.FirstI] & 4) - regClearInst(RI, getOp1(I)); - if (RI.IInfo[I - RI.FirstI] & 8) - regClearInst(RI, getOp2(I)); - break; - } - - case BranchCond: - { - if (isICmp(*getOp1(I))) - { - regEmitCmp(RI, getOp1(I)); - CCFlags flag; - switch (getOpcode(*getOp1(I))) - { - case ICmpEq: - flag = CC_NE; - break; - case ICmpNe: - flag = CC_E; - break; - case ICmpUgt: - flag = CC_BE; - break; - case ICmpUlt: - flag = CC_AE; - break; - case ICmpUge: - flag = CC_B; - break; - case ICmpUle: - flag = CC_A; - break; - case ICmpSgt: - flag = CC_LE; - break; - case ICmpSlt: - flag = CC_GE; - break; - case ICmpSge: - flag = CC_L; - break; - case ICmpSle: - flag = CC_G; - break; - default: - PanicAlert("cmpXX"); - flag = CC_O; - break; - } - FixupBranch cont = Jit->J_CC(flag); - regWriteExit(RI, getOp2(I)); - Jit->SetJumpTarget(cont); - if (RI.IInfo[I - RI.FirstI] & 4) - regClearInst(RI, getOp1(getOp1(I))); - if (RI.IInfo[I - RI.FirstI] & 8) - regClearInst(RI, getOp2(getOp1(I))); - } - else - { - Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm8(0)); - FixupBranch cont = Jit->J_CC(CC_Z); - regWriteExit(RI, getOp2(I)); - Jit->SetJumpTarget(cont); - if (RI.IInfo[I - RI.FirstI] & 4) - regClearInst(RI, getOp1(I)); - } - if (RI.IInfo[I - RI.FirstI] & 8) - regClearInst(RI, getOp2(I)); - break; - } - case BranchUncond: - { - regWriteExit(RI, getOp1(I)); - regNormalRegClear(RI, I); - break; - } - case ShortIdleLoop: - { - unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); - Jit->ABI_CallFunction((void *)&CoreTiming::Idle); - Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc)); - Jit->WriteExceptionExit(); - break; - } - case SystemCall: - { - unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); - Jit->LOCK(); - Jit->OR(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_SYSCALL)); - Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc + 4)); - Jit->WriteExceptionExit(); - break; - } - case InterpreterBranch: - { - Jit->MOV(32, R(RSCRATCH), PPCSTATE(npc)); - Jit->WriteExitDestInOpArg(R(RSCRATCH)); - break; - } - case RFIExit: - { - // See Interpreter rfi for details - const u32 mask = 0x87C0FFFF; - // MSR = (MSR & ~mask) | (SRR1 & mask); - Jit->MOV(32, R(RSCRATCH), PPCSTATE(msr)); - Jit->MOV(32, R(RSCRATCH2), PPCSTATE_SRR1); - Jit->AND(32, R(RSCRATCH), Imm32(~mask)); - Jit->AND(32, R(RSCRATCH2), Imm32(mask)); - Jit->OR(32, R(RSCRATCH), R(RSCRATCH2)); - // MSR &= 0xFFFBFFFF; // Mask used to clear the bit MSR[13] - Jit->AND(32, R(RSCRATCH), Imm32(0xFFFBFFFF)); - Jit->MOV(32, PPCSTATE(msr), R(RSCRATCH)); - // NPC = SRR0; - Jit->MOV(32, R(RSCRATCH), PPCSTATE_SRR0); - Jit->WriteRfiExitDestInOpArg(R(RSCRATCH)); - break; - } - case FPExceptionCheck: - { - unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); - //This instruction uses FPU - needs to add FP exception bailout - Jit->TEST(32, PPCSTATE(msr), Imm32(1 << 13)); // Test FP enabled bit - FixupBranch b1 = Jit->J_CC(CC_NZ); - - // If a FPU exception occurs, the exception handler will read - // from PC. Update PC with the latest value in case that happens. - Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc)); - Jit->SUB(32, PPCSTATE(downcount), Imm32(Jit->js.downcountAmount)); - Jit->OR(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE)); - Jit->WriteExceptionExit(); - Jit->SetJumpTarget(b1); - break; - } - case DSIExceptionCheck: - { - unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); - Jit->TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_DSI)); - FixupBranch noMemException = Jit->J_CC(CC_Z); - - // If a memory exception occurs, the exception handler will read - // from PC. Update PC with the latest value in case that happens. - Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc)); - Jit->WriteExceptionExit(); - Jit->SetJumpTarget(noMemException); - break; - } - case ExtExceptionCheck: - { - unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); - - Jit->TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT)); - FixupBranch clearInt = Jit->J_CC(CC_NZ); - Jit->TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_EXTERNAL_INT)); - FixupBranch noExtException = Jit->J_CC(CC_Z); - Jit->TEST(32, PPCSTATE(msr), Imm32(0x0008000)); - FixupBranch noExtIntEnable = Jit->J_CC(CC_Z); - Jit->TEST(32, M(&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN | ProcessorInterface::INT_CAUSE_PE_FINISH)); - FixupBranch noCPInt = Jit->J_CC(CC_Z); - - Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc)); - Jit->WriteExceptionExit(); - - Jit->SetJumpTarget(noCPInt); - Jit->SetJumpTarget(noExtIntEnable); - Jit->SetJumpTarget(noExtException); - Jit->SetJumpTarget(clearInt); - break; - } - case BreakPointCheck: - { - unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); - - Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc)); - Jit->ABI_CallFunction(reinterpret_cast(&PowerPC::CheckBreakPoints)); - Jit->TEST(32, M(CPU::GetStatePtr()), Imm32(0xFFFFFFFF)); - FixupBranch noBreakpoint = Jit->J_CC(CC_Z); - Jit->WriteExit(InstLoc); - Jit->SetJumpTarget(noBreakpoint); - break; - } - case Int3: - { - Jit->INT3(); - break; - } - case Tramp: break; - case Nop: break; - default: - PanicAlert("Unknown JIT instruction; aborting!"); - exit(1); - } - } - - for (unsigned i = 0; i < MAX_NUMBER_OF_REGS; i++) - { - if (RI.regs[i]) - { - // Start a game in Burnout 2 to get this. Or animal crossing. - PanicAlert("Incomplete cleanup! (regs)"); - exit(1); - } - - if (RI.fregs[i]) - { - PanicAlert("Incomplete cleanup! (fregs)"); - exit(1); - } - } - - Jit->WriteExit(exitAddress); - Jit->UD2(); + // printf("Writing block: %x\n", js.blockStart); + RegInfo RI(Jit, ibuild->getFirstInst(), ibuild->getNumInsts()); + RI.Build = ibuild; + + // Pass to compute liveness + ibuild->StartBackPass(); + for (unsigned int index = (unsigned int)RI.IInfo.size() - 1; index != -1U; --index) + { + InstLoc I = ibuild->ReadBackward(); + unsigned int op = getOpcode(*I); + bool thisUsed = regReadUse(RI, I) ? true : false; + + switch (op) + { + default: + PanicAlert("Unexpected inst!"); + case Nop: + case CInt16: + case CInt32: + case LoadGReg: + case LoadLink: + case LoadCR: + case LoadCarry: + case LoadCTR: + case LoadMSR: + case LoadFReg: + case LoadFRegDENToZero: + case LoadGQR: + case BlockEnd: + case BlockStart: + case FallBackToInterpreter: + case SystemCall: + case RFIExit: + case InterpreterBranch: + case ShortIdleLoop: + case FPExceptionCheck: + case DSIExceptionCheck: + case ExtExceptionCheck: + case BreakPointCheck: + case Int3: + case Tramp: + // No liveness effects + break; + case SExt8: + case SExt16: + case BSwap32: + case BSwap16: + case Cntlzw: + case Not: + case DupSingleToMReg: + case DoubleToSingle: + case ExpandPackedToMReg: + case CompactMRegToPacked: + case FPNeg: + case FPDup0: + case FPDup1: + case FSNeg: + case FDNeg: + case ConvertFromFastCR: + case ConvertToFastCR: + case FastCRSOSet: + case FastCREQSet: + case FastCRGTSet: + case FastCRLTSet: + if (thisUsed) + regMarkUse(RI, I, getOp1(I), 1); + break; + case Load8: + case Load16: + case Load32: + case LoadDouble: + case LoadSingle: + regMarkMemAddress(RI, I, getOp1(I), 1); + break; + case LoadPaired: + if (thisUsed) + regMarkUse(RI, I, getOp1(I), 1); + break; + case StoreCR: + case StoreCarry: + case StoreFPRF: + regMarkUse(RI, I, getOp1(I), 1); + break; + case StoreGReg: + case StoreLink: + case StoreCTR: + case StoreMSR: + case StoreGQR: + case StoreSRR: + case StoreFReg: + if (!isImm(*getOp1(I))) + regMarkUse(RI, I, getOp1(I), 1); + break; + case Add: + case Sub: + case And: + case Or: + case Xor: + case Mul: + case MulHighUnsigned: + case Rol: + case Shl: + case Shrl: + case Sarl: + case ICmpCRUnsigned: + case ICmpCRSigned: + case ICmpEq: + case ICmpNe: + case ICmpUgt: + case ICmpUlt: + case ICmpUge: + case ICmpUle: + case ICmpSgt: + case ICmpSlt: + case ICmpSge: + case ICmpSle: + case FSMul: + case FSAdd: + case FSSub: + case FDMul: + case FDAdd: + case FDSub: + case FPAdd: + case FPMul: + case FPSub: + case FPMerge00: + case FPMerge01: + case FPMerge10: + case FPMerge11: + case FDCmpCR: + case InsertDoubleInMReg: + if (thisUsed) + { + regMarkUse(RI, I, getOp1(I), 1); + if (!isImm(*getOp2(I))) + regMarkUse(RI, I, getOp2(I), 2); + } + break; + case Store8: + case Store16: + case Store32: + if (!isImm(*getOp1(I))) + regMarkUse(RI, I, getOp1(I), 1); + regMarkMemAddress(RI, I, getOp2(I), 2); + break; + case StoreSingle: + case StoreDouble: + regMarkUse(RI, I, getOp1(I), 1); + regMarkMemAddress(RI, I, getOp2(I), 2); + break; + case StorePaired: + regMarkUse(RI, I, getOp1(I), 1); + regMarkUse(RI, I, getOp2(I), 2); + break; + case BranchUncond: + if (!isImm(*getOp1(I))) + regMarkUse(RI, I, getOp1(I), 1); + break; + case IdleBranch: + regMarkUse(RI, I, getOp1(I), 1); + break; + case BranchCond: + { + if (isICmp(*getOp1(I))) + { + regMarkUse(RI, I, getOp1(getOp1(I)), 1); + if (!isImm(*getOp2(getOp1(I)))) + regMarkUse(RI, I, getOp2(getOp1(I)), 2); + } + else + { + regMarkUse(RI, I, getOp1(I), 1); + } + if (!isImm(*getOp2(I))) + regMarkUse(RI, I, getOp2(I), 2); + break; + } + } + } + + ibuild->StartForwardPass(); + for (unsigned i = 0; i != RI.IInfo.size(); i++) + { + InstLoc I = ibuild->ReadForward(); + bool thisUsed = regReadUse(RI, I) ? true : false; + if (thisUsed) + { + // Needed for IR Writer + ibuild->SetMarkUsed(I); + } + + switch (getOpcode(*I)) + { + case FallBackToInterpreter: + { + unsigned InstCode = ibuild->GetImmValue(getOp1(I)); + unsigned InstLoc = ibuild->GetImmValue(getOp2(I)); + // There really shouldn't be anything live across an + // interpreter call at the moment, but optimizing interpreter + // calls isn't completely out of the question... + regSpillCallerSaved(RI); + Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc)); + Jit->MOV(32, PPCSTATE(npc), Imm32(InstLoc + 4)); + Jit->ABI_CallFunctionC((void*)GetInterpreterOp(InstCode), InstCode); + break; + } + case LoadGReg: + { + if (!thisUsed) + break; + + X64Reg reg = regFindFreeReg(RI); + unsigned ppcreg = *I >> 8; + Jit->MOV(32, R(reg), PPCSTATE(gpr[ppcreg])); + RI.regs[reg] = I; + break; + } + case LoadCR: + { + if (!thisUsed) + break; + + X64Reg reg = regFindFreeReg(RI); + unsigned ppcreg = *I >> 8; + Jit->MOV(64, R(reg), PPCSTATE(cr_val[ppcreg])); + RI.regs[reg] = I; + break; + } + case LoadCTR: + { + if (!thisUsed) + break; + + X64Reg reg = regFindFreeReg(RI); + Jit->MOV(32, R(reg), PPCSTATE_CTR); + RI.regs[reg] = I; + break; + } + case LoadLink: + { + if (!thisUsed) + break; + + X64Reg reg = regFindFreeReg(RI); + Jit->MOV(32, R(reg), PPCSTATE_LR); + RI.regs[reg] = I; + break; + } + case LoadMSR: + { + if (!thisUsed) + break; + + X64Reg reg = regFindFreeReg(RI); + Jit->MOV(32, R(reg), PPCSTATE(msr)); + RI.regs[reg] = I; + break; + } + case LoadGQR: + { + if (!thisUsed) + break; + + X64Reg reg = regFindFreeReg(RI); + unsigned gqr = *I >> 8; + Jit->MOV(32, R(reg), PPCSTATE(spr[SPR_GQR0 + gqr])); + RI.regs[reg] = I; + break; + } + case LoadCarry: + { + if (!thisUsed) + break; + + X64Reg reg = regFindFreeReg(RI); + Jit->MOVZX(32, 8, reg, PPCSTATE(xer_ca)); + RI.regs[reg] = I; + break; + } + case StoreGReg: + { + unsigned ppcreg = *I >> 16; + regStoreInstToConstLoc(RI, 32, getOp1(I), &PowerPC::ppcState.gpr[ppcreg]); + regNormalRegClear(RI, I); + break; + } + case StoreCR: + { + X64Reg reg = regEnsureInReg(RI, getOp1(I)); + unsigned ppcreg = *I >> 16; + Jit->MOV(64, PPCSTATE(cr_val[ppcreg]), R(reg)); + regNormalRegClear(RI, I); + break; + } + case StoreLink: + { + regStoreInstToConstLoc(RI, 32, getOp1(I), &LR); + regNormalRegClear(RI, I); + break; + } + case StoreCTR: + { + regStoreInstToConstLoc(RI, 32, getOp1(I), &CTR); + regNormalRegClear(RI, I); + break; + } + case StoreMSR: + { + unsigned InstLoc = ibuild->GetImmValue(getOp2(I)); + regStoreInstToConstLoc(RI, 32, getOp1(I), &MSR); + regNormalRegClear(RI, I); + + // If some exceptions are pending and EE are now enabled, force checking + // external exceptions when going out of mtmsr in order to execute delayed + // interrupts as soon as possible. + Jit->MOV(32, R(RSCRATCH), PPCSTATE(msr)); + Jit->TEST(32, R(RSCRATCH), Imm32(0x8000)); + FixupBranch eeDisabled = Jit->J_CC(CC_Z); + + Jit->MOV(32, R(RSCRATCH), PPCSTATE(Exceptions)); + Jit->TEST(32, R(RSCRATCH), R(RSCRATCH)); + FixupBranch noExceptionsPending = Jit->J_CC(CC_Z); + + Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc + 4)); + Jit->WriteExceptionExit(); // TODO: Implement WriteExternalExceptionExit for JitIL + + Jit->SetJumpTarget(eeDisabled); + Jit->SetJumpTarget(noExceptionsPending); + break; + } + case StoreGQR: + { + unsigned gqr = *I >> 16; + regStoreInstToConstLoc(RI, 32, getOp1(I), &GQR(gqr)); + regNormalRegClear(RI, I); + break; + } + case StoreSRR: + { + unsigned srr = *I >> 16; + regStoreInstToConstLoc(RI, 32, getOp1(I), &PowerPC::ppcState.spr[SPR_SRR0 + srr]); + regNormalRegClear(RI, I); + break; + } + case StoreCarry: + { + Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm8(0)); + FixupBranch nocarry = Jit->J_CC(CC_Z); + Jit->JitSetCA(); + FixupBranch cont = Jit->J(); + Jit->SetJumpTarget(nocarry); + Jit->JitClearCA(); + Jit->SetJumpTarget(cont); + regNormalRegClear(RI, I); + break; + } + case StoreFPRF: + { + Jit->MOV(32, R(RSCRATCH2), regLocForInst(RI, getOp1(I))); + Jit->AND(32, R(RSCRATCH2), Imm8(0x1F)); + Jit->SHL(32, R(RSCRATCH2), Imm8(12)); + Jit->AND(32, PPCSTATE(fpscr), Imm32(~(0x1F << 12))); + Jit->OR(32, PPCSTATE(fpscr), R(RSCRATCH2)); + regNormalRegClear(RI, I); + break; + } + case Load8: + { + regEmitMemLoad(RI, I, 8); + break; + } + case Load16: + { + regEmitMemLoad(RI, I, 16); + break; + } + case Load32: + { + regEmitMemLoad(RI, I, 32); + break; + } + case Store8: + { + regEmitMemStore(RI, I, 8); + break; + } + case Store16: + { + regEmitMemStore(RI, I, 16); + break; + } + case Store32: + { + regEmitMemStore(RI, I, 32); + break; + } + case SExt8: + { + if (!thisUsed) + break; + + X64Reg reg = regUReg(RI, I); + Jit->MOV(32, R(RSCRATCH2), regLocForInst(RI, getOp1(I))); + Jit->MOVSX(32, 8, reg, R(RSCRATCH2)); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case SExt16: + { + if (!thisUsed) + break; + + X64Reg reg = regUReg(RI, I); + Jit->MOVSX(32, 16, reg, regLocForInst(RI, getOp1(I))); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case Cntlzw: + { + if (!thisUsed) + break; + + X64Reg reg = regUReg(RI, I); + Jit->MOV(32, R(RSCRATCH2), Imm32(63)); + Jit->BSR(32, reg, regLocForInst(RI, getOp1(I))); + Jit->CMOVcc(32, reg, R(RSCRATCH2), CC_Z); + Jit->XOR(32, R(reg), Imm8(31)); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case Not: + { + if (!thisUsed) + break; + + X64Reg reg = regBinLHSReg(RI, I); + Jit->NOT(32, R(reg)); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case And: + { + if (!thisUsed) + break; + + regEmitBinInst(RI, I, &JitIL::AND, true); + break; + } + case Xor: + { + if (!thisUsed) + break; + + regEmitBinInst(RI, I, &JitIL::XOR, true); + break; + } + case Sub: + { + if (!thisUsed) + break; + + regEmitBinInst(RI, I, &JitIL::SUB); + break; + } + case Or: + { + if (!thisUsed) + break; + + regEmitBinInst(RI, I, &JitIL::OR, true); + break; + } + case Add: + { + if (!thisUsed) + break; + + regEmitBinInst(RI, I, &JitIL::ADD, true); + break; + } + case Mul: + { + if (!thisUsed) + break; + + // FIXME: Use three-address capability of IMUL! + X64Reg reg = regBinLHSReg(RI, I); + if (isImm(*getOp2(I))) + { + unsigned RHS = RI.Build->GetImmValue(getOp2(I)); + if (RHS + 128 < 256) + Jit->IMUL(32, reg, Imm8(RHS)); + else + Jit->IMUL(32, reg, Imm32(RHS)); + } + else + { + Jit->IMUL(32, reg, regLocForInst(RI, getOp2(I))); + } + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case MulHighUnsigned: + { + if (!thisUsed) + break; + + // no register choice + regSpill(RI, EAX); + regSpill(RI, EDX); + X64Reg reg = regBinReg(RI, I); + if (isImm(*getOp2(I))) + { + unsigned RHS = RI.Build->GetImmValue(getOp2(I)); + Jit->MOV(32, R(EAX), Imm32(RHS)); + } + else + { + Jit->MOV(32, R(EAX), regLocForInst(RI, getOp2(I))); + } + Jit->MUL(32, regLocForInst(RI, getOp1(I))); + Jit->MOV(32, R(reg), R(EDX)); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case Rol: + { + if (!thisUsed) + break; + + regEmitShiftInst(RI, I, &JitIL::ROL); + break; + } + case Shl: + { + if (!thisUsed) + break; + + regEmitShiftInst(RI, I, &JitIL::SHL); + break; + } + case Shrl: + { + if (!thisUsed) + break; + + regEmitShiftInst(RI, I, &JitIL::SHR); + break; + } + case Sarl: + { + if (!thisUsed) + break; + + regEmitShiftInst(RI, I, &JitIL::SAR); + break; + } + case ICmpEq: + { + if (!thisUsed) + break; + + regEmitICmpInst(RI, I, CC_E); + break; + } + case ICmpNe: + { + if (!thisUsed) + break; + + regEmitICmpInst(RI, I, CC_NE); + break; + } + case ICmpUgt: + { + if (!thisUsed) + break; + + regEmitICmpInst(RI, I, CC_A); + break; + } + case ICmpUlt: + { + if (!thisUsed) + break; + + regEmitICmpInst(RI, I, CC_B); + break; + } + case ICmpUge: + { + if (!thisUsed) + break; + + regEmitICmpInst(RI, I, CC_AE); + break; + } + case ICmpUle: + { + if (!thisUsed) + break; + + regEmitICmpInst(RI, I, CC_BE); + break; + } + case ICmpSgt: + { + if (!thisUsed) + break; + + regEmitICmpInst(RI, I, CC_G); + break; + } + case ICmpSlt: + { + if (!thisUsed) + break; + + regEmitICmpInst(RI, I, CC_L); + break; + } + case ICmpSge: + { + if (!thisUsed) + break; + + regEmitICmpInst(RI, I, CC_GE); + break; + } + case ICmpSle: + { + if (!thisUsed) + break; + + regEmitICmpInst(RI, I, CC_LE); + break; + } + case ICmpCRUnsigned: + { + if (!thisUsed) + break; + + regEmitICmpCRInst(RI, I); + break; + } + case ICmpCRSigned: + { + if (!thisUsed) + break; + + regEmitICmpCRInst(RI, I); + break; + } + case ConvertFromFastCR: + { + if (!thisUsed) + break; + + X64Reg cr_val = regUReg(RI, I); + Jit->MOV(64, R(cr_val), regLocForInst(RI, getOp1(I))); + + Jit->XOR(32, R(RSCRATCH), R(RSCRATCH)); + + // SO: Bit 61 set. + Jit->MOV(64, R(RSCRATCH2), R(cr_val)); + Jit->SHR(64, R(RSCRATCH2), Imm8(61)); + Jit->AND(32, R(RSCRATCH2), Imm8(1)); + Jit->OR(32, R(RSCRATCH), R(RSCRATCH2)); + + // EQ: Bits 31-0 == 0. + Jit->XOR(32, R(RSCRATCH2), R(RSCRATCH2)); + Jit->TEST(32, R(cr_val), R(cr_val)); + Jit->SETcc(CC_Z, R(RSCRATCH2)); + Jit->SHL(32, R(RSCRATCH2), Imm8(1)); + Jit->OR(32, R(RSCRATCH), R(RSCRATCH2)); + + // GT: Value > 0. + Jit->XOR(32, R(RSCRATCH2), R(RSCRATCH2)); + Jit->TEST(64, R(cr_val), R(cr_val)); + Jit->SETcc(CC_G, R(RSCRATCH2)); + Jit->SHL(32, R(RSCRATCH2), Imm8(2)); + Jit->OR(32, R(RSCRATCH), R(RSCRATCH2)); + + // LT: Bit 62 set. + Jit->MOV(64, R(RSCRATCH2), R(cr_val)); + Jit->SHR(64, R(RSCRATCH2), Imm8(62 - 3)); + Jit->AND(32, R(RSCRATCH2), Imm8(0x8)); + Jit->OR(32, R(RSCRATCH), R(RSCRATCH2)); + + Jit->MOV(32, R(cr_val), R(RSCRATCH)); + RI.regs[cr_val] = I; + regNormalRegClear(RI, I); + break; + } + case ConvertToFastCR: + { + if (!thisUsed) + break; + + X64Reg cr_val = regUReg(RI, I); + Jit->MOV(64, R(cr_val), regLocForInst(RI, getOp1(I))); + + Jit->MOV(64, R(RSCRATCH2), Imm64(1ull << 32)); + + // SO + Jit->MOV(64, R(RSCRATCH), R(cr_val)); + Jit->SHL(64, R(RSCRATCH), Imm8(63)); + Jit->SHR(64, R(RSCRATCH), Imm8(63 - 61)); + Jit->OR(64, R(RSCRATCH2), R(RSCRATCH)); + + // EQ + Jit->MOV(64, R(RSCRATCH), R(cr_val)); + Jit->NOT(64, R(RSCRATCH)); + Jit->AND(64, R(RSCRATCH), Imm8(CR_EQ)); + Jit->OR(64, R(RSCRATCH2), R(RSCRATCH)); + + // GT + Jit->MOV(64, R(RSCRATCH), R(cr_val)); + Jit->NOT(64, R(RSCRATCH)); + Jit->AND(64, R(RSCRATCH), Imm8(CR_GT)); + Jit->SHL(64, R(RSCRATCH), Imm8(63 - 2)); + Jit->OR(64, R(RSCRATCH2), R(RSCRATCH)); + + // LT + Jit->MOV(64, R(RSCRATCH), R(cr_val)); + Jit->AND(64, R(RSCRATCH), Imm8(CR_LT)); + Jit->SHL(64, R(RSCRATCH), Imm8(62 - 3)); + Jit->OR(64, R(RSCRATCH2), R(RSCRATCH)); + + Jit->MOV(64, R(cr_val), R(RSCRATCH2)); + + RI.regs[cr_val] = I; + regNormalRegClear(RI, I); + break; + } + case FastCRSOSet: + { + if (!thisUsed) + break; + + X64Reg reg = regUReg(RI, I); + Jit->MOV(64, R(RSCRATCH), Imm64(1ull << 61)); + Jit->TEST(64, regLocForInst(RI, getOp1(I)), R(RSCRATCH)); + Jit->SETcc(CC_NZ, R(RSCRATCH)); + Jit->MOVZX(32, 8, reg, R(RSCRATCH)); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case FastCREQSet: + { + if (!thisUsed) + break; + + X64Reg reg = regUReg(RI, I); + Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm32(0)); + Jit->SETcc(CC_Z, R(RSCRATCH)); + Jit->MOVZX(32, 8, reg, R(RSCRATCH)); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case FastCRGTSet: + { + if (!thisUsed) + break; + + X64Reg reg = regUReg(RI, I); + Jit->CMP(64, regLocForInst(RI, getOp1(I)), Imm8(0)); + Jit->SETcc(CC_G, R(RSCRATCH)); + Jit->MOVZX(32, 8, reg, R(RSCRATCH)); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case FastCRLTSet: + { + if (!thisUsed) + break; + + X64Reg reg = regUReg(RI, I); + Jit->MOV(64, R(RSCRATCH), Imm64(1ull << 62)); + Jit->TEST(64, regLocForInst(RI, getOp1(I)), R(RSCRATCH)); + Jit->SETcc(CC_NZ, R(RSCRATCH)); + Jit->MOVZX(32, 8, reg, R(RSCRATCH)); + RI.regs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case LoadSingle: + { + if (!thisUsed) + break; + + X64Reg reg = fregFindFreeReg(RI); + auto info = regBuildMemAddress(RI, I, getOp1(I), 1, nullptr); + + RI.Jit->SafeLoadToReg(RSCRATCH2, info.first, 32, info.second, regsInUse(RI), false); + Jit->MOVD_xmm(reg, R(RSCRATCH2)); + RI.fregs[reg] = I; + break; + } + case LoadDouble: + { + if (!thisUsed) + break; + + X64Reg reg = fregFindFreeReg(RI); + auto info = regBuildMemAddress(RI, I, getOp1(I), 1, nullptr); + + RI.Jit->SafeLoadToReg(RSCRATCH2, info.first, 64, info.second, regsInUse(RI), false); + Jit->MOVQ_xmm(reg, R(RSCRATCH2)); + RI.fregs[reg] = I; + break; + } + case LoadPaired: + { + if (!thisUsed) + break; + + X64Reg reg = fregFindFreeReg(RI); + // The lower 3 bits is for GQR index. The next 1 bit is for inst.W + unsigned int quantreg = (*I >> 16) & 0x7; + unsigned int w = *I >> 19; + // Some games (e.g. Dirt 2) incorrectly set the unused bits which breaks the lookup table + // code. + // Hence, we need to mask out the unused bits. The layout of the GQR register is + // UU[SCALE]UUUUU[TYPE] where SCALE is 6 bits and TYPE is 3 bits, so we have to AND with + // 0b0011111100000111, or 0x3F07. + Jit->MOV(32, R(RSCRATCH2), Imm32(0x3F07)); + Jit->AND(32, R(RSCRATCH2), M(((char*)&GQR(quantreg)) + 2)); + Jit->MOVZX(32, 8, RSCRATCH, R(RSCRATCH2)); + Jit->OR(32, R(RSCRATCH), Imm8(w << 3)); + + Jit->MOV(32, R(RSCRATCH_EXTRA), regLocForInst(RI, getOp1(I))); + Jit->CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)(Jit->asm_routines.pairedLoadQuantized))); + Jit->MOVAPD(reg, R(XMM0)); + RI.fregs[reg] = I; + regNormalRegClear(RI, I); + break; + } + case StoreSingle: + { + regSpill(RI, RSCRATCH); + const OpArg loc1 = fregLocForInst(RI, getOp1(I)); + if (loc1.IsSimpleReg()) + Jit->MOVD_xmm(R(RSCRATCH), loc1.GetSimpleReg()); + else + Jit->MOV(32, R(RSCRATCH), loc1); + + auto info = regBuildMemAddress(RI, I, getOp2(I), 2, nullptr); + if (info.first.IsImm()) + RI.Jit->MOV(32, R(RSCRATCH2), info.first); + else + RI.Jit->LEA(32, RSCRATCH2, MDisp(info.first.GetSimpleReg(), info.second)); + + RI.Jit->SafeWriteRegToReg(RSCRATCH, RSCRATCH2, 32, 0, regsInUse(RI)); + + if (RI.IInfo[I - RI.FirstI] & 4) + fregClearInst(RI, getOp1(I)); + break; + } + case StoreDouble: + { + regSpill(RI, RSCRATCH); + + OpArg value = fregLocForInst(RI, getOp1(I)); + Jit->MOVAPD(XMM0, value); + Jit->MOVQ_xmm(R(RSCRATCH), XMM0); + + auto info = regBuildMemAddress(RI, I, getOp2(I), 2, nullptr); + if (info.first.IsImm()) + RI.Jit->MOV(32, R(RSCRATCH2), info.first); + else + RI.Jit->LEA(32, RSCRATCH2, MDisp(info.first.GetSimpleReg(), info.second)); + + RI.Jit->SafeWriteRegToReg(RSCRATCH, RSCRATCH2, 64, 0, regsInUse(RI)); + + if (RI.IInfo[I - RI.FirstI] & 4) + fregClearInst(RI, getOp1(I)); + break; + } + case StorePaired: + { + regSpill(RI, RSCRATCH); + regSpill(RI, RSCRATCH2); + u32 quantreg = *I >> 24; + Jit->MOV(32, R(RSCRATCH2), Imm32(0x3F07)); + Jit->AND(32, R(RSCRATCH2), PPCSTATE(spr[SPR_GQR0 + quantreg])); + Jit->MOVZX(32, 8, RSCRATCH, R(RSCRATCH2)); + + Jit->MOV(32, R(RSCRATCH_EXTRA), regLocForInst(RI, getOp2(I))); + Jit->MOVAPD(XMM0, fregLocForInst(RI, getOp1(I))); + Jit->CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)(Jit->asm_routines.pairedStoreQuantized))); + if (RI.IInfo[I - RI.FirstI] & 4) + fregClearInst(RI, getOp1(I)); + if (RI.IInfo[I - RI.FirstI] & 8) + regClearInst(RI, getOp2(I)); + break; + } + case DupSingleToMReg: + { + if (!thisUsed) + break; + + X64Reg input = fregEnsureInReg(RI, getOp1(I)); + X64Reg output = fregURegWithoutMov(RI, I); + Jit->ConvertSingleToDouble(output, input); + + RI.fregs[output] = I; + fregNormalRegClear(RI, I); + break; + } + case InsertDoubleInMReg: + { + if (!thisUsed) + break; + // r[0] = op1[0]; r[1] = op2[1]; + + // TODO: Optimize the case that the register of op1 can be + // recycled. (SHUFPD may not be so fast.) + X64Reg reg = fregBinRHSRegWithMov(RI, I); + OpArg loc1 = fregLocForInst(RI, getOp1(I)); + if (loc1.IsSimpleReg()) + { + Jit->MOVSD(reg, loc1); + } + else + { + // If op1 is in FSlotSet, we have to mov loc1 to XMM0 + // before MOVSD/MOVSS. + // Because register<->memory transfer with MOVSD/MOVSS + // clears upper 64/96-bits of the destination register. + Jit->MOVAPD(XMM0, loc1); + Jit->MOVSD(reg, R(XMM0)); + } + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case ExpandPackedToMReg: + { + if (!thisUsed) + break; + + X64Reg reg = fregURegWithoutMov(RI, I); + Jit->CVTPS2PD(reg, fregLocForInst(RI, getOp1(I))); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case CompactMRegToPacked: + { + if (!thisUsed) + break; + + X64Reg reg = fregURegWithoutMov(RI, I); + Jit->CVTPD2PS(reg, fregLocForInst(RI, getOp1(I))); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FSNeg: + { + if (!thisUsed) + break; + + X64Reg reg = fregURegWithMov(RI, I); + alignas(16) static const u32 ssSignBits[4] = {0x80000000}; + Jit->PXOR(reg, M(ssSignBits)); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FDNeg: + { + if (!thisUsed) + break; + + X64Reg reg = fregURegWithMov(RI, I); + alignas(16) static const u64 sdSignBits[2] = {0x8000000000000000ULL}; + Jit->PXOR(reg, M(sdSignBits)); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FPNeg: + { + if (!thisUsed) + break; + + X64Reg reg = fregURegWithMov(RI, I); + alignas(16) static const u32 psSignBits[4] = {0x80000000, 0x80000000}; + Jit->PXOR(reg, M(psSignBits)); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FPDup0: + { + if (!thisUsed) + break; + + X64Reg reg = fregURegWithMov(RI, I); + Jit->PUNPCKLDQ(reg, R(reg)); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FPDup1: + { + if (!thisUsed) + break; + + X64Reg reg = fregURegWithMov(RI, I); + Jit->SHUFPS(reg, R(reg), 0xE5); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case LoadFReg: + { + if (!thisUsed) + break; + + X64Reg reg = fregFindFreeReg(RI); + unsigned ppcreg = *I >> 8; + Jit->MOVAPD(reg, PPCSTATE(ps[ppcreg])); + RI.fregs[reg] = I; + break; + } + case LoadFRegDENToZero: + { + if (!thisUsed) + break; + + X64Reg reg = fregFindFreeReg(RI); + unsigned ppcreg = *I >> 8; + char* p = (char*)&(PowerPC::ppcState.ps[ppcreg][0]); + Jit->MOV(32, R(RSCRATCH2), M(p + 4)); + Jit->AND(32, R(RSCRATCH2), Imm32(0x7ff00000)); + Jit->CMP(32, R(RSCRATCH2), Imm32(0x38000000)); + FixupBranch ok = Jit->J_CC(CC_AE); + Jit->AND(32, M(p + 4), Imm32(0x80000000)); + Jit->MOV(32, M(p), Imm32(0)); + Jit->SetJumpTarget(ok); + Jit->MOVAPD(reg, PPCSTATE(ps[ppcreg])); + RI.fregs[reg] = I; + break; + } + case StoreFReg: + { + unsigned ppcreg = *I >> 16; + Jit->MOVAPD(PPCSTATE(ps[ppcreg]), fregEnsureInReg(RI, getOp1(I))); + fregNormalRegClear(RI, I); + break; + } + case DoubleToSingle: + { + if (!thisUsed) + break; + + X64Reg input = fregEnsureInReg(RI, getOp1(I)); + X64Reg output = fregURegWithoutMov(RI, I); + Jit->ConvertDoubleToSingle(output, input); + + RI.fregs[output] = I; + fregNormalRegClear(RI, I); + break; + } + case FSMul: + { + if (!thisUsed) + break; + + fregEmitBinInst(RI, I, &JitIL::MULSS); + break; + } + case FSAdd: + { + if (!thisUsed) + break; + + fregEmitBinInst(RI, I, &JitIL::ADDSS); + break; + } + case FSSub: + { + if (!thisUsed) + break; + + fregEmitBinInst(RI, I, &JitIL::SUBSS); + break; + } + case FDMul: + { + if (!thisUsed) + break; + + fregEmitBinInst(RI, I, &JitIL::MULSD); + break; + } + case FDAdd: + { + if (!thisUsed) + break; + + fregEmitBinInst(RI, I, &JitIL::ADDSD); + break; + } + case FDSub: + { + if (!thisUsed) + break; + + fregEmitBinInst(RI, I, &JitIL::SUBSD); + break; + } + case FDCmpCR: + { + const u32 ordered = *I >> 24; + X64Reg destreg = regFindFreeReg(RI); + // TODO: Remove an extra MOVSD if loc1.IsSimpleReg() + OpArg loc1 = fregLocForInst(RI, getOp1(I)); + OpArg loc2 = fregLocForInst(RI, getOp2(I)); + Jit->MOVSD(XMM0, loc1); + Jit->UCOMISD(XMM0, loc2); + FixupBranch pNan = Jit->J_CC(CC_P); + FixupBranch pEqual = Jit->J_CC(CC_Z); + FixupBranch pLesser = Jit->J_CC(CC_C); + // Greater + Jit->MOV(32, R(destreg), Imm32(0x4)); + FixupBranch continue1 = Jit->J(); + // NaN + Jit->SetJumpTarget(pNan); + Jit->MOV(32, R(destreg), Imm32(0x1)); + + if (ordered) + { + // fcmpo + // TODO: Optimize the following code if slow. + // SNAN check may not be needed + // because it does not happen so much. + Jit->MOVSD(M(isSNANTemp[0]), XMM0); + if (loc2.IsSimpleReg()) + { + Jit->MOVSD(M(isSNANTemp[1]), loc2.GetSimpleReg()); + } + else + { + Jit->MOVSD(XMM0, loc2); + Jit->MOVSD(M(isSNANTemp[1]), XMM0); + } + Jit->ABI_CallFunction((void*)checkIsSNAN); + Jit->TEST(8, R(ABI_RETURN), R(ABI_RETURN)); + FixupBranch ok = Jit->J_CC(CC_Z); + Jit->OR(32, PPCSTATE(fpscr), Imm32(FPSCR_FX)); // FPSCR.FX = 1; + Jit->OR(32, PPCSTATE(fpscr), Imm32(FPSCR_VXSNAN)); // FPSCR.Hex |= mask; + Jit->TEST(32, PPCSTATE(fpscr), Imm32(FPSCR_VE)); + FixupBranch finish0 = Jit->J_CC(CC_NZ); + Jit->OR(32, PPCSTATE(fpscr), Imm32(FPSCR_VXVC)); // FPSCR.Hex |= mask; + FixupBranch finish1 = Jit->J(); + Jit->SetJumpTarget(ok); + Jit->OR(32, PPCSTATE(fpscr), Imm32(FPSCR_FX)); // FPSCR.FX = 1; + Jit->OR(32, PPCSTATE(fpscr), Imm32(FPSCR_VXVC)); // FPSCR.Hex |= mask; + Jit->SetJumpTarget(finish0); + Jit->SetJumpTarget(finish1); + } + else + { + // fcmpu + // TODO: Optimize the following code if slow + Jit->MOVSD(M(isSNANTemp[0]), XMM0); + if (loc2.IsSimpleReg()) + { + Jit->MOVSD(M(isSNANTemp[1]), loc2.GetSimpleReg()); + } + else + { + Jit->MOVSD(XMM0, loc2); + Jit->MOVSD(M(isSNANTemp[1]), XMM0); + } + Jit->ABI_CallFunction((void*)checkIsSNAN); + Jit->TEST(8, R(ABI_RETURN), R(ABI_RETURN)); + FixupBranch finish = Jit->J_CC(CC_Z); + Jit->OR(32, PPCSTATE(fpscr), Imm32(FPSCR_FX)); // FPSCR.FX = 1; + Jit->OR(32, PPCSTATE(fpscr), Imm32(FPSCR_VXVC)); // FPSCR.Hex |= mask; + Jit->SetJumpTarget(finish); + } + + FixupBranch continue2 = Jit->J(); + // Equal + Jit->SetJumpTarget(pEqual); + Jit->MOV(32, R(destreg), Imm32(0x2)); + FixupBranch continue3 = Jit->J(); + // Less + Jit->SetJumpTarget(pLesser); + Jit->MOV(32, R(destreg), Imm32(0x8)); + Jit->SetJumpTarget(continue1); + Jit->SetJumpTarget(continue2); + Jit->SetJumpTarget(continue3); + RI.regs[destreg] = I; + fregNormalRegClear(RI, I); + break; + } + case FPAdd: + { + if (!thisUsed) + break; + + fregEmitBinInst(RI, I, &JitIL::ADDPS); + break; + } + case FPMul: + { + if (!thisUsed) + break; + + fregEmitBinInst(RI, I, &JitIL::MULPS); + break; + } + case FPSub: + { + if (!thisUsed) + break; + + fregEmitBinInst(RI, I, &JitIL::SUBPS); + break; + } + case FPMerge00: + { + // r[0] = op1[0]; r[1] = op2[0]; + if (!thisUsed) + break; + + // TODO: Optimize the case that the register of only op2 can be + // recycled. + X64Reg reg = fregBinLHSRegWithMov(RI, I); + Jit->PUNPCKLDQ(reg, fregLocForInst(RI, getOp2(I))); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FPMerge01: + { + // r[0] = op1[0]; r[1] = op2[1]; + if (!thisUsed) + break; + + // TODO: Optimize the case that the register of only op1 can be + // recycled. + X64Reg reg = fregBinRHSRegWithMov(RI, I); + OpArg loc1 = fregLocForInst(RI, getOp1(I)); + if (loc1.IsSimpleReg()) + { + Jit->MOVSS(reg, loc1); + } + else + { + Jit->MOVAPD(XMM0, loc1); + Jit->MOVSS(reg, R(XMM0)); + } + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FPMerge10: + { + // r[0] = op1[1]; r[1] = op2[0]; + if (!thisUsed) + break; + + // TODO: Optimize the case that the register of only op2 can be + // recycled. + X64Reg reg = fregBinLHSRegWithMov(RI, I); + OpArg loc2 = fregLocForInst(RI, getOp2(I)); + if (loc2.IsSimpleReg()) + { + Jit->MOVSS(reg, loc2); + } + else + { + Jit->MOVAPD(XMM0, loc2); + Jit->MOVSS(reg, R(XMM0)); + } + Jit->SHUFPS(reg, R(reg), 0xF1); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case FPMerge11: + { + // r[0] = op1[1]; r[1] = op2[1]; + if (!thisUsed) + break; + + // TODO: Optimize the case that the register of only op2 can be + // recycled. + X64Reg reg = fregBinLHSRegWithMov(RI, I); + // TODO: Check whether the following code works + // when the op1 is in the FSlotSet + Jit->PUNPCKLDQ(reg, fregLocForInst(RI, getOp2(I))); + Jit->SHUFPD(reg, R(reg), 0x1); + RI.fregs[reg] = I; + fregNormalRegClear(RI, I); + break; + } + case CInt32: + case CInt16: + { + if (!thisUsed) + break; + + X64Reg reg = regFindFreeReg(RI); + u64 val = ibuild->GetImmValue64(I); + if ((u32)val == val) + Jit->MOV(32, R(reg), Imm32((u32)val)); + else if ((s32)val == (s64)val) + Jit->MOV(64, R(reg), Imm32((s32)val)); + else + Jit->MOV(64, R(reg), Imm64(val)); + RI.regs[reg] = I; + break; + } + case BlockStart: + case BlockEnd: + break; + + case IdleBranch: + { + // If value is 0, we don't need to call out to the idle function. + OpArg value = regLocForInst(RI, getOp1(I)); + Jit->TEST(32, value, value); + FixupBranch noidle = Jit->J_CC(CC_NZ); + + RI.Jit->Cleanup(); // is it needed? + Jit->ABI_CallFunction((void*)&CoreTiming::Idle); + + Jit->MOV(32, PPCSTATE(pc), Imm32(ibuild->GetImmValue(getOp2(I)))); + Jit->WriteExceptionExit(); + + Jit->SetJumpTarget(noidle); + if (RI.IInfo[I - RI.FirstI] & 4) + regClearInst(RI, getOp1(I)); + if (RI.IInfo[I - RI.FirstI] & 8) + regClearInst(RI, getOp2(I)); + break; + } + + case BranchCond: + { + if (isICmp(*getOp1(I))) + { + regEmitCmp(RI, getOp1(I)); + CCFlags flag; + switch (getOpcode(*getOp1(I))) + { + case ICmpEq: + flag = CC_NE; + break; + case ICmpNe: + flag = CC_E; + break; + case ICmpUgt: + flag = CC_BE; + break; + case ICmpUlt: + flag = CC_AE; + break; + case ICmpUge: + flag = CC_B; + break; + case ICmpUle: + flag = CC_A; + break; + case ICmpSgt: + flag = CC_LE; + break; + case ICmpSlt: + flag = CC_GE; + break; + case ICmpSge: + flag = CC_L; + break; + case ICmpSle: + flag = CC_G; + break; + default: + PanicAlert("cmpXX"); + flag = CC_O; + break; + } + FixupBranch cont = Jit->J_CC(flag); + regWriteExit(RI, getOp2(I)); + Jit->SetJumpTarget(cont); + if (RI.IInfo[I - RI.FirstI] & 4) + regClearInst(RI, getOp1(getOp1(I))); + if (RI.IInfo[I - RI.FirstI] & 8) + regClearInst(RI, getOp2(getOp1(I))); + } + else + { + Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm8(0)); + FixupBranch cont = Jit->J_CC(CC_Z); + regWriteExit(RI, getOp2(I)); + Jit->SetJumpTarget(cont); + if (RI.IInfo[I - RI.FirstI] & 4) + regClearInst(RI, getOp1(I)); + } + if (RI.IInfo[I - RI.FirstI] & 8) + regClearInst(RI, getOp2(I)); + break; + } + case BranchUncond: + { + regWriteExit(RI, getOp1(I)); + regNormalRegClear(RI, I); + break; + } + case ShortIdleLoop: + { + unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); + Jit->ABI_CallFunction((void*)&CoreTiming::Idle); + Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc)); + Jit->WriteExceptionExit(); + break; + } + case SystemCall: + { + unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); + Jit->LOCK(); + Jit->OR(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_SYSCALL)); + Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc + 4)); + Jit->WriteExceptionExit(); + break; + } + case InterpreterBranch: + { + Jit->MOV(32, R(RSCRATCH), PPCSTATE(npc)); + Jit->WriteExitDestInOpArg(R(RSCRATCH)); + break; + } + case RFIExit: + { + // See Interpreter rfi for details + const u32 mask = 0x87C0FFFF; + // MSR = (MSR & ~mask) | (SRR1 & mask); + Jit->MOV(32, R(RSCRATCH), PPCSTATE(msr)); + Jit->MOV(32, R(RSCRATCH2), PPCSTATE_SRR1); + Jit->AND(32, R(RSCRATCH), Imm32(~mask)); + Jit->AND(32, R(RSCRATCH2), Imm32(mask)); + Jit->OR(32, R(RSCRATCH), R(RSCRATCH2)); + // MSR &= 0xFFFBFFFF; // Mask used to clear the bit MSR[13] + Jit->AND(32, R(RSCRATCH), Imm32(0xFFFBFFFF)); + Jit->MOV(32, PPCSTATE(msr), R(RSCRATCH)); + // NPC = SRR0; + Jit->MOV(32, R(RSCRATCH), PPCSTATE_SRR0); + Jit->WriteRfiExitDestInOpArg(R(RSCRATCH)); + break; + } + case FPExceptionCheck: + { + unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); + // This instruction uses FPU - needs to add FP exception bailout + Jit->TEST(32, PPCSTATE(msr), Imm32(1 << 13)); // Test FP enabled bit + FixupBranch b1 = Jit->J_CC(CC_NZ); + + // If a FPU exception occurs, the exception handler will read + // from PC. Update PC with the latest value in case that happens. + Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc)); + Jit->SUB(32, PPCSTATE(downcount), Imm32(Jit->js.downcountAmount)); + Jit->OR(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE)); + Jit->WriteExceptionExit(); + Jit->SetJumpTarget(b1); + break; + } + case DSIExceptionCheck: + { + unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); + Jit->TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_DSI)); + FixupBranch noMemException = Jit->J_CC(CC_Z); + + // If a memory exception occurs, the exception handler will read + // from PC. Update PC with the latest value in case that happens. + Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc)); + Jit->WriteExceptionExit(); + Jit->SetJumpTarget(noMemException); + break; + } + case ExtExceptionCheck: + { + unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); + + Jit->TEST(32, PPCSTATE(Exceptions), + Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | + EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT)); + FixupBranch clearInt = Jit->J_CC(CC_NZ); + Jit->TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_EXTERNAL_INT)); + FixupBranch noExtException = Jit->J_CC(CC_Z); + Jit->TEST(32, PPCSTATE(msr), Imm32(0x0008000)); + FixupBranch noExtIntEnable = Jit->J_CC(CC_Z); + Jit->TEST(32, M(&ProcessorInterface::m_InterruptCause), + Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN | + ProcessorInterface::INT_CAUSE_PE_FINISH)); + FixupBranch noCPInt = Jit->J_CC(CC_Z); + + Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc)); + Jit->WriteExceptionExit(); + + Jit->SetJumpTarget(noCPInt); + Jit->SetJumpTarget(noExtIntEnable); + Jit->SetJumpTarget(noExtException); + Jit->SetJumpTarget(clearInt); + break; + } + case BreakPointCheck: + { + unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); + + Jit->MOV(32, PPCSTATE(pc), Imm32(InstLoc)); + Jit->ABI_CallFunction(reinterpret_cast(&PowerPC::CheckBreakPoints)); + Jit->TEST(32, M(CPU::GetStatePtr()), Imm32(0xFFFFFFFF)); + FixupBranch noBreakpoint = Jit->J_CC(CC_Z); + Jit->WriteExit(InstLoc); + Jit->SetJumpTarget(noBreakpoint); + break; + } + case Int3: + { + Jit->INT3(); + break; + } + case Tramp: + break; + case Nop: + break; + default: + PanicAlert("Unknown JIT instruction; aborting!"); + exit(1); + } + } + + for (unsigned i = 0; i < MAX_NUMBER_OF_REGS; i++) + { + if (RI.regs[i]) + { + // Start a game in Burnout 2 to get this. Or animal crossing. + PanicAlert("Incomplete cleanup! (regs)"); + exit(1); + } + + if (RI.fregs[i]) + { + PanicAlert("Incomplete cleanup! (fregs)"); + exit(1); + } + } + + Jit->WriteExit(exitAddress); + Jit->UD2(); } void JitIL::WriteCode(u32 exitAddress) { - DoWriteCode(&ibuild, this, exitAddress); + DoWriteCode(&ibuild, this, exitAddress); } diff --git a/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp b/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp index c8628b76e5..9d526cf3bc 100644 --- a/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp +++ b/Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #include -#include // For profiling +#include // For profiling #include #include #include @@ -12,16 +12,16 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/Intrinsics.h" +#include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "Common/x64ABI.h" -#include "Common/Logging/Log.h" -#include "Core/PatchEngine.h" #include "Core/HLE/HLE.h" #include "Core/HW/CPU.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/Profiler.h" +#include "Core/PatchEngine.h" #include "Core/PowerPC/Jit64IL/JitIL.h" #include "Core/PowerPC/Jit64IL/JitIL_Tables.h" +#include "Core/PowerPC/PowerPC.h" +#include "Core/PowerPC/Profiler.h" using namespace Gen; using namespace PowerPC; @@ -34,7 +34,8 @@ using namespace PowerPC; // * Fast dispatcher // Unfeatures: -// * Does not recompile all instructions - sometimes falls back to inserting a CALL to the corresponding Interpreter function. +// * Does not recompile all instructions - sometimes falls back to inserting a CALL to the +// corresponding Interpreter function. // Various notes below @@ -42,48 +43,57 @@ using namespace PowerPC; // RAX - Generic quicktemp register // RBX - point to base of memory map // RSI RDI R12 R13 R14 R15 - free for allocation -// RCX RDX R8 R9 R10 R11 - allocate in emergencies. These need to be flushed before functions are called. +// RCX RDX R8 R9 R10 R11 - allocate in emergencies. These need to be flushed before functions are +// called. // RSP - stack pointer, do not generally use, very dangerous // RBP - ? // IMPORTANT: // Make sure that all generated code and all emulator state sits under the 2GB boundary so that -// RIP addressing can be used easily. Windows will always allocate static code under the 2GB boundary. +// RIP addressing can be used easily. Windows will always allocate static code under the 2GB +// boundary. // Also make sure to use VirtualAlloc and specify EXECUTE permission. // Open questions // * Should there be any statically allocated registers? r3, r4, r5, r8, r0 come to mind.. maybe sp -// * Does it make sense to finish off the remaining non-jitted instructions? Seems we are hitting diminishing returns. +// * Does it make sense to finish off the remaining non-jitted instructions? Seems we are hitting +// diminishing returns. // Other considerations // // Many instructions have shorter forms for EAX. However, I believe their performance boost -// will be as small to be negligible, so I haven't dirtied up the code with that. AMD recommends it in their +// will be as small to be negligible, so I haven't dirtied up the code with that. AMD recommends it +// in their // optimization manuals, though. // -// We support block linking. Reserve space at the exits of every block for a full 5-byte jmp. Save 16-bit offsets +// We support block linking. Reserve space at the exits of every block for a full 5-byte jmp. Save +// 16-bit offsets // from the starts of each block, marking the exits so that they can be nicely patched at any time. // // Blocks do NOT use call/ret, they only jmp to each other and to the dispatcher when necessary. // -// All blocks that can be precompiled will be precompiled. Code will be memory protected - any write will mark -// the region as non-compilable, and all links to the page will be torn out and replaced with dispatcher jmps. +// All blocks that can be precompiled will be precompiled. Code will be memory protected - any write +// will mark +// the region as non-compilable, and all links to the page will be torn out and replaced with +// dispatcher jmps. // // Alternatively, icbi instruction SHOULD mark where we can't compile // -// Seldom-happening events is handled by adding a decrement of a counter to all blr instructions (which are +// Seldom-happening events is handled by adding a decrement of a counter to all blr instructions +// (which are // expensive anyway since we need to return to dispatcher, except when they can be predicted). -// TODO: SERIOUS synchronization problem with the video backend setting tokens and breakpoints in dual core mode!!! +// TODO: SERIOUS synchronization problem with the video backend setting tokens and breakpoints in +// dual core mode!!! // Somewhat fixed by disabling idle skipping when certain interrupts are enabled // This is no permanent reliable fix // TODO: Zeldas go whacko when you hang the gfx thread // Idea - Accurate exception handling -// Compute register state at a certain instruction by running the JIT in "dry mode", and stopping at the right place. +// Compute register state at a certain instruction by running the JIT in "dry mode", and stopping at +// the right place. // Not likely to be done :P - // Optimization Ideas - /* * Assume SP is in main RAM (in Wii mode too?) - partly done @@ -93,7 +103,7 @@ using namespace PowerPC; * HLE functions like floorf, sin, memcpy, etc - they can be much faster * ABI optimizations - drop F0-F13 on blr, for example. Watch out for context switching. CR2-CR4 are non-volatile, rest of CR is volatile -> dropped on blr. - R5-R12 are volatile -> dropped on blr. + R5-R12 are volatile -> dropped on blr. * classic inlining across calls. Low hanging fruit: @@ -149,22 +159,20 @@ ps_adds1 #if !__has_builtin(__builtin_ia32_rdtsc) static inline uint64_t __rdtsc() { - uint32_t lo, hi; + uint32_t lo, hi; #ifdef _LP64 - __asm__ __volatile__("xorl %%eax,%%eax \n cpuid" - ::: "%rax", "%rbx", "%rcx", "%rdx"); - __asm__ __volatile__("rdtsc" : "=a" (lo), "=d" (hi)); - return (uint64_t)hi << 32 | lo; + __asm__ __volatile__("xorl %%eax,%%eax \n cpuid" ::: "%rax", "%rbx", "%rcx", "%rdx"); + __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); + return (uint64_t)hi << 32 | lo; #else - __asm__ __volatile__( - "xor %%eax,%%eax;" - "push %%ebx;" - "cpuid;" - "pop %%ebx;" - ::: "%eax", "%ecx", "%edx"); - __asm__ __volatile__("rdtsc" : "=a" (lo), "=d" (hi)); + __asm__ __volatile__("xor %%eax,%%eax;" + "push %%ebx;" + "cpuid;" + "pop %%ebx;" :: + : "%eax", "%ecx", "%edx"); + __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); #endif - return (uint64_t)hi << 32 | lo; + return (uint64_t)hi << 32 | lo; } #endif #endif @@ -172,146 +180,144 @@ static inline uint64_t __rdtsc() namespace JitILProfiler { - struct Block - { - u32 index; - u64 codeHash; - u64 totalElapsed; - u64 numberOfCalls; +struct Block +{ + u32 index; + u64 codeHash; + u64 totalElapsed; + u64 numberOfCalls; - Block() : index(0), codeHash(0), totalElapsed(0), numberOfCalls(0) - { - } - }; + Block() : index(0), codeHash(0), totalElapsed(0), numberOfCalls(0) {} +}; - static std::vector blocks; - static u32 blockIndex; - static u64 beginTime; - static Block& Add(u64 codeHash) - { - const u32 _blockIndex = (u32)blocks.size(); - blocks.emplace_back(); - Block& block = blocks.back(); - block.index = _blockIndex; - block.codeHash = codeHash; - return block; - } +static std::vector blocks; +static u32 blockIndex; +static u64 beginTime; +static Block& Add(u64 codeHash) +{ + const u32 _blockIndex = (u32)blocks.size(); + blocks.emplace_back(); + Block& block = blocks.back(); + block.index = _blockIndex; + block.codeHash = codeHash; + return block; +} - // These functions need to be static because they are called with - // ABI_CallFunction(). - static void Begin(u32 index) - { - blockIndex = index; - beginTime = __rdtsc(); - } +// These functions need to be static because they are called with +// ABI_CallFunction(). +static void Begin(u32 index) +{ + blockIndex = index; + beginTime = __rdtsc(); +} - static void End() - { - const u64 endTime = __rdtsc(); - const u64 duration = endTime - beginTime; - Block& block = blocks[blockIndex]; - block.totalElapsed += duration; - ++block.numberOfCalls; - } +static void End() +{ + const u64 endTime = __rdtsc(); + const u64 duration = endTime - beginTime; + Block& block = blocks[blockIndex]; + block.totalElapsed += duration; + ++block.numberOfCalls; +} - struct JitILProfilerFinalizer - { - virtual ~JitILProfilerFinalizer() - { - std::string filename = StringFromFormat("JitIL_profiling_%d.csv", (int)time(nullptr)); - File::IOFile file(filename, "w"); - setvbuf(file.GetHandle(), nullptr, _IOFBF, 1024 * 1024); - fprintf(file.GetHandle(), "code hash,total elapsed,number of calls,elapsed per call\n"); - for (auto& block : blocks) - { - const u64 codeHash = block.codeHash; - const u64 totalElapsed = block.totalElapsed; - const u64 numberOfCalls = block.numberOfCalls; - const double elapsedPerCall = totalElapsed / (double)numberOfCalls; - fprintf(file.GetHandle(), "%016" PRIx64 ",%" PRId64 ",%" PRId64 ",%f\n", codeHash, totalElapsed, numberOfCalls, elapsedPerCall); - } - } - }; +struct JitILProfilerFinalizer +{ + virtual ~JitILProfilerFinalizer() + { + std::string filename = StringFromFormat("JitIL_profiling_%d.csv", (int)time(nullptr)); + File::IOFile file(filename, "w"); + setvbuf(file.GetHandle(), nullptr, _IOFBF, 1024 * 1024); + fprintf(file.GetHandle(), "code hash,total elapsed,number of calls,elapsed per call\n"); + for (auto& block : blocks) + { + const u64 codeHash = block.codeHash; + const u64 totalElapsed = block.totalElapsed; + const u64 numberOfCalls = block.numberOfCalls; + const double elapsedPerCall = totalElapsed / (double)numberOfCalls; + fprintf(file.GetHandle(), "%016" PRIx64 ",%" PRId64 ",%" PRId64 ",%f\n", codeHash, + totalElapsed, numberOfCalls, elapsedPerCall); + } + } +}; - static std::unique_ptr finalizer; - static void Init() - { - finalizer = std::make_unique(); - } +static std::unique_ptr finalizer; +static void Init() +{ + finalizer = std::make_unique(); +} - static void Shutdown() - { - finalizer.reset(); - } +static void Shutdown() +{ + finalizer.reset(); +} }; void JitIL::Init() { - EnableBlockLink(); + EnableBlockLink(); - jo.optimizeGatherPipe = true; - jo.accurateSinglePrecision = false; - UpdateMemoryOptions(); + jo.optimizeGatherPipe = true; + jo.accurateSinglePrecision = false; + UpdateMemoryOptions(); - trampolines.Init(jo.memcheck ? TRAMPOLINE_CODE_SIZE_MMU : TRAMPOLINE_CODE_SIZE); - AllocCodeSpace(CODE_SIZE); - blocks.Init(); - asm_routines.Init(nullptr); + trampolines.Init(jo.memcheck ? TRAMPOLINE_CODE_SIZE_MMU : TRAMPOLINE_CODE_SIZE); + AllocCodeSpace(CODE_SIZE); + blocks.Init(); + asm_routines.Init(nullptr); - farcode.Init(jo.memcheck ? FARCODE_SIZE_MMU : FARCODE_SIZE); - Clear(); + farcode.Init(jo.memcheck ? FARCODE_SIZE_MMU : FARCODE_SIZE); + Clear(); - code_block.m_stats = &js.st; - code_block.m_gpa = &js.gpa; - code_block.m_fpa = &js.fpa; + code_block.m_stats = &js.st; + code_block.m_gpa = &js.gpa; + code_block.m_fpa = &js.fpa; - if (SConfig::GetInstance().bJITILTimeProfiling) - { - JitILProfiler::Init(); - } + if (SConfig::GetInstance().bJITILTimeProfiling) + { + JitILProfiler::Init(); + } } void JitIL::ClearCache() { - blocks.Clear(); - trampolines.ClearCodeSpace(); - farcode.ClearCodeSpace(); - ClearCodeSpace(); - Clear(); + blocks.Clear(); + trampolines.ClearCodeSpace(); + farcode.ClearCodeSpace(); + ClearCodeSpace(); + Clear(); } void JitIL::Shutdown() { - if (SConfig::GetInstance().bJITILTimeProfiling) - { - JitILProfiler::Shutdown(); - } + if (SConfig::GetInstance().bJITILTimeProfiling) + { + JitILProfiler::Shutdown(); + } - FreeCodeSpace(); + FreeCodeSpace(); - blocks.Shutdown(); - trampolines.Shutdown(); - asm_routines.Shutdown(); - farcode.Shutdown(); + blocks.Shutdown(); + trampolines.Shutdown(); + asm_routines.Shutdown(); + farcode.Shutdown(); } void JitIL::FallBackToInterpreter(UGeckoInstruction _inst) { - ibuild.EmitFallBackToInterpreter( - ibuild.EmitIntConst(_inst.hex), - ibuild.EmitIntConst(js.compilerPC)); + ibuild.EmitFallBackToInterpreter(ibuild.EmitIntConst(_inst.hex), + ibuild.EmitIntConst(js.compilerPC)); } void JitIL::HLEFunction(UGeckoInstruction _inst) { - ABI_CallFunctionCC((void*)&HLE::Execute, js.compilerPC, _inst.hex); - MOV(32, R(RSCRATCH), PPCSTATE(npc)); - WriteExitDestInOpArg(R(RSCRATCH)); + ABI_CallFunctionCC((void*)&HLE::Execute, js.compilerPC, _inst.hex); + MOV(32, R(RSCRATCH), PPCSTATE(npc)); + WriteExitDestInOpArg(R(RSCRATCH)); } void JitIL::DoNothing(UGeckoInstruction _inst) { - // Yup, just don't do anything. + // Yup, just don't do anything. } static const bool ImHereDebug = false; @@ -320,357 +326,365 @@ static std::map been_here; static void ImHere() { - static File::IOFile f; - if (ImHereLog) - { - if (!f) - { - f.Open("log64.txt", "w"); - } - fprintf(f.GetHandle(), "%08x r0: %08x r5: %08x r6: %08x\n", PC, PowerPC::ppcState.gpr[0], - PowerPC::ppcState.gpr[5], PowerPC::ppcState.gpr[6]); - f.Flush(); - } + static File::IOFile f; + if (ImHereLog) + { + if (!f) + { + f.Open("log64.txt", "w"); + } + fprintf(f.GetHandle(), "%08x r0: %08x r5: %08x r6: %08x\n", PC, PowerPC::ppcState.gpr[0], + PowerPC::ppcState.gpr[5], PowerPC::ppcState.gpr[6]); + f.Flush(); + } - if (been_here.find(PC) != been_here.end()) - { - been_here.find(PC)->second++; - if ((been_here.find(PC)->second) & 1023) - return; - } + if (been_here.find(PC) != been_here.end()) + { + been_here.find(PC)->second++; + if ((been_here.find(PC)->second) & 1023) + return; + } - DEBUG_LOG(DYNA_REC, "I'm here - PC = %08x , LR = %08x", PC, LR); - been_here[PC] = 1; + DEBUG_LOG(DYNA_REC, "I'm here - PC = %08x , LR = %08x", PC, LR); + been_here[PC] = 1; } void JitIL::Cleanup() { - // SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time. - if (MMCR0.Hex || MMCR1.Hex) - ABI_CallFunctionCCC((void *)&PowerPC::UpdatePerformanceMonitor, js.downcountAmount, jit->js.numLoadStoreInst, jit->js.numFloatingPointInst); + // SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time. + if (MMCR0.Hex || MMCR1.Hex) + ABI_CallFunctionCCC((void*)&PowerPC::UpdatePerformanceMonitor, js.downcountAmount, + jit->js.numLoadStoreInst, jit->js.numFloatingPointInst); } void JitIL::WriteExit(u32 destination) { - Cleanup(); - if (SConfig::GetInstance().bJITILTimeProfiling) - { - ABI_CallFunction((void *)JitILProfiler::End); - } - SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); + Cleanup(); + if (SConfig::GetInstance().bJITILTimeProfiling) + { + ABI_CallFunction((void*)JitILProfiler::End); + } + SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); - //If nobody has taken care of this yet (this can be removed when all branches are done) - JitBlock *b = js.curBlock; - JitBlock::LinkData linkData; - linkData.exitAddress = destination; - linkData.exitPtrs = GetWritableCodePtr(); - linkData.linkStatus = false; + // If nobody has taken care of this yet (this can be removed when all branches are done) + JitBlock* b = js.curBlock; + JitBlock::LinkData linkData; + linkData.exitAddress = destination; + linkData.exitPtrs = GetWritableCodePtr(); + linkData.linkStatus = false; - // Link opportunity! - int block; - if (jo.enableBlocklink && (block = blocks.GetBlockNumberFromStartAddress(destination)) >= 0) - { - // It exists! Joy of joy! - JMP(blocks.GetBlock(block)->checkedEntry, true); - linkData.linkStatus = true; - } - else - { - MOV(32, PPCSTATE(pc), Imm32(destination)); - JMP(asm_routines.dispatcher, true); - } - b->linkData.push_back(linkData); + // Link opportunity! + int block; + if (jo.enableBlocklink && (block = blocks.GetBlockNumberFromStartAddress(destination)) >= 0) + { + // It exists! Joy of joy! + JMP(blocks.GetBlock(block)->checkedEntry, true); + linkData.linkStatus = true; + } + else + { + MOV(32, PPCSTATE(pc), Imm32(destination)); + JMP(asm_routines.dispatcher, true); + } + b->linkData.push_back(linkData); } void JitIL::WriteExitDestInOpArg(const OpArg& arg) { - MOV(32, PPCSTATE(pc), arg); - Cleanup(); - if (SConfig::GetInstance().bJITILTimeProfiling) - { - ABI_CallFunction((void *)JitILProfiler::End); - } - SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); - JMP(asm_routines.dispatcher, true); + MOV(32, PPCSTATE(pc), arg); + Cleanup(); + if (SConfig::GetInstance().bJITILTimeProfiling) + { + ABI_CallFunction((void*)JitILProfiler::End); + } + SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); + JMP(asm_routines.dispatcher, true); } void JitIL::WriteRfiExitDestInOpArg(const OpArg& arg) { - MOV(32, PPCSTATE(pc), arg); - MOV(32, PPCSTATE(npc), arg); - Cleanup(); - if (SConfig::GetInstance().bJITILTimeProfiling) - { - ABI_CallFunction((void *)JitILProfiler::End); - } - ABI_CallFunction(reinterpret_cast(&PowerPC::CheckExceptions)); - SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); - JMP(asm_routines.dispatcher, true); + MOV(32, PPCSTATE(pc), arg); + MOV(32, PPCSTATE(npc), arg); + Cleanup(); + if (SConfig::GetInstance().bJITILTimeProfiling) + { + ABI_CallFunction((void*)JitILProfiler::End); + } + ABI_CallFunction(reinterpret_cast(&PowerPC::CheckExceptions)); + SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); + JMP(asm_routines.dispatcher, true); } void JitIL::WriteExceptionExit() { - Cleanup(); - if (SConfig::GetInstance().bJITILTimeProfiling) - { - ABI_CallFunction((void *)JitILProfiler::End); - } - MOV(32, R(EAX), PPCSTATE(pc)); - MOV(32, PPCSTATE(npc), R(EAX)); - ABI_CallFunction(reinterpret_cast(&PowerPC::CheckExceptions)); - SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); - JMP(asm_routines.dispatcher, true); + Cleanup(); + if (SConfig::GetInstance().bJITILTimeProfiling) + { + ABI_CallFunction((void*)JitILProfiler::End); + } + MOV(32, R(EAX), PPCSTATE(pc)); + MOV(32, PPCSTATE(npc), R(EAX)); + ABI_CallFunction(reinterpret_cast(&PowerPC::CheckExceptions)); + SUB(32, PPCSTATE(downcount), Imm32(js.downcountAmount)); + JMP(asm_routines.dispatcher, true); } void JitIL::Run() { - CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode; - pExecAddr(); - //Will return when PowerPC::state changes + CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode; + pExecAddr(); + // Will return when PowerPC::state changes } void JitIL::SingleStep() { - CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode; - pExecAddr(); + CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode; + pExecAddr(); } void JitIL::Trace() { - std::string regs; - std::string fregs; + std::string regs; + std::string fregs; #ifdef JIT_LOG_GPR - for (int i = 0; i < 32; i++) - { - regs += StringFromFormat("r%02d: %08x ", i, PowerPC::ppcState.gpr[i]); - } + for (int i = 0; i < 32; i++) + { + regs += StringFromFormat("r%02d: %08x ", i, PowerPC::ppcState.gpr[i]); + } #endif #ifdef JIT_LOG_FPR - for (int i = 0; i < 32; i++) - { - fregs += StringFromFormat("f%02d: %016x ", i, riPS0(i)); - } + for (int i = 0; i < 32; i++) + { + fregs += StringFromFormat("f%02d: %016x ", i, riPS0(i)); + } #endif - DEBUG_LOG(DYNA_REC, "JITIL PC: %08x SRR0: %08x SRR1: %08x CRval: %016lx%016lx%016lx%016lx%016lx%016lx%016lx%016lx FPSCR: %08x MSR: %08x LR: %08x %s %s", - PC, SRR0, SRR1, (unsigned long) PowerPC::ppcState.cr_val[0], (unsigned long) PowerPC::ppcState.cr_val[1], (unsigned long) PowerPC::ppcState.cr_val[2], - (unsigned long) PowerPC::ppcState.cr_val[3], (unsigned long) PowerPC::ppcState.cr_val[4], (unsigned long) PowerPC::ppcState.cr_val[5], - (unsigned long) PowerPC::ppcState.cr_val[6], (unsigned long) PowerPC::ppcState.cr_val[7], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, - PowerPC::ppcState.spr[8], regs.c_str(), fregs.c_str()); + DEBUG_LOG(DYNA_REC, "JITIL PC: %08x SRR0: %08x SRR1: %08x CRval: " + "%016lx%016lx%016lx%016lx%016lx%016lx%016lx%016lx FPSCR: %08x MSR: %08x LR: " + "%08x %s %s", + PC, SRR0, SRR1, (unsigned long)PowerPC::ppcState.cr_val[0], + (unsigned long)PowerPC::ppcState.cr_val[1], (unsigned long)PowerPC::ppcState.cr_val[2], + (unsigned long)PowerPC::ppcState.cr_val[3], (unsigned long)PowerPC::ppcState.cr_val[4], + (unsigned long)PowerPC::ppcState.cr_val[5], (unsigned long)PowerPC::ppcState.cr_val[6], + (unsigned long)PowerPC::ppcState.cr_val[7], PowerPC::ppcState.fpscr, + PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), fregs.c_str()); } void JitIL::Jit(u32 em_address) { - if (IsAlmostFull() || farcode.IsAlmostFull() || trampolines.IsAlmostFull() || blocks.IsFull() || - SConfig::GetInstance().bJITNoBlockCache) - { - ClearCache(); - } + if (IsAlmostFull() || farcode.IsAlmostFull() || trampolines.IsAlmostFull() || blocks.IsFull() || + SConfig::GetInstance().bJITNoBlockCache) + { + ClearCache(); + } - int blockSize = code_buffer.GetSize(); + int blockSize = code_buffer.GetSize(); - if (SConfig::GetInstance().bEnableDebugging) - { - // We can link blocks as long as we are not single stepping and there are no breakpoints here - EnableBlockLink(); + if (SConfig::GetInstance().bEnableDebugging) + { + // We can link blocks as long as we are not single stepping and there are no breakpoints here + EnableBlockLink(); - // Comment out the following to disable breakpoints (speed-up) - if (!Profiler::g_ProfileBlocks) - { - if (CPU::GetState() == CPU::CPU_STEPPING) - { - blockSize = 1; + // Comment out the following to disable breakpoints (speed-up) + if (!Profiler::g_ProfileBlocks) + { + if (CPU::GetState() == CPU::CPU_STEPPING) + { + blockSize = 1; - // Do not link this block to other blocks While single stepping - jo.enableBlocklink = false; - } - Trace(); - } - } + // Do not link this block to other blocks While single stepping + jo.enableBlocklink = false; + } + Trace(); + } + } - // Analyze the block, collect all instructions it is made of (including inlining, - // if that is enabled), reorder instructions for optimal performance, and join joinable instructions. - u32 nextPC = analyzer.Analyze(em_address, &code_block, &code_buffer, blockSize); + // Analyze the block, collect all instructions it is made of (including inlining, + // if that is enabled), reorder instructions for optimal performance, and join joinable + // instructions. + u32 nextPC = analyzer.Analyze(em_address, &code_block, &code_buffer, blockSize); - if (code_block.m_memory_exception) - { - // Address of instruction could not be translated - NPC = nextPC; - PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; - PowerPC::CheckExceptions(); - WARN_LOG(POWERPC, "ISI exception at 0x%08x", nextPC); - return; - } + if (code_block.m_memory_exception) + { + // Address of instruction could not be translated + NPC = nextPC; + PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; + PowerPC::CheckExceptions(); + WARN_LOG(POWERPC, "ISI exception at 0x%08x", nextPC); + return; + } - int block_num = blocks.AllocateBlock(em_address); - JitBlock *b = blocks.GetBlock(block_num); - blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b, nextPC)); + int block_num = blocks.AllocateBlock(em_address); + JitBlock* b = blocks.GetBlock(block_num); + blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b, nextPC)); } -const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b, u32 nextPC) +const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBlock* b, u32 nextPC) { - js.isLastInstruction = false; - js.blockStart = em_address; - js.fifoBytesThisBlock = 0; - js.curBlock = b; - jit->js.numLoadStoreInst = 0; - jit->js.numFloatingPointInst = 0; + js.isLastInstruction = false; + js.blockStart = em_address; + js.fifoBytesThisBlock = 0; + js.curBlock = b; + jit->js.numLoadStoreInst = 0; + jit->js.numFloatingPointInst = 0; - PPCAnalyst::CodeOp *ops = code_buf->codebuffer; + PPCAnalyst::CodeOp* ops = code_buf->codebuffer; - const u8 *start = AlignCode4(); // TODO: Test if this or AlignCode16 make a difference from GetCodePtr - b->checkedEntry = start; - b->runCount = 0; + const u8* start = + AlignCode4(); // TODO: Test if this or AlignCode16 make a difference from GetCodePtr + b->checkedEntry = start; + b->runCount = 0; - // Downcount flag check. The last block decremented downcounter, and the flag should still be available. - FixupBranch skip = J_CC(CC_NBE); - MOV(32, PPCSTATE(pc), Imm32(js.blockStart)); - JMP(asm_routines.doTiming, true); // downcount hit zero - go doTiming. - SetJumpTarget(skip); + // Downcount flag check. The last block decremented downcounter, and the flag should still be + // available. + FixupBranch skip = J_CC(CC_NBE); + MOV(32, PPCSTATE(pc), Imm32(js.blockStart)); + JMP(asm_routines.doTiming, true); // downcount hit zero - go doTiming. + SetJumpTarget(skip); - const u8 *normalEntry = GetCodePtr(); - b->normalEntry = normalEntry; + const u8* normalEntry = GetCodePtr(); + b->normalEntry = normalEntry; - if (ImHereDebug) - ABI_CallFunction((void *)&ImHere); // Used to get a trace of the last few blocks before a crash, sometimes VERY useful + if (ImHereDebug) + ABI_CallFunction((void*)&ImHere); // Used to get a trace of the last few blocks before a crash, + // sometimes VERY useful - if (js.fpa.any) - { - // This block uses FPU - needs to add FP exception bailout - TEST(32, PPCSTATE(msr), Imm32(1 << 13)); //Test FP enabled bit - FixupBranch b1 = J_CC(CC_NZ); + if (js.fpa.any) + { + // This block uses FPU - needs to add FP exception bailout + TEST(32, PPCSTATE(msr), Imm32(1 << 13)); // Test FP enabled bit + FixupBranch b1 = J_CC(CC_NZ); - // If a FPU exception occurs, the exception handler will read - // from PC. Update PC with the latest value in case that happens. - MOV(32, PPCSTATE(pc), Imm32(js.blockStart)); - OR(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE)); - WriteExceptionExit(); + // If a FPU exception occurs, the exception handler will read + // from PC. Update PC with the latest value in case that happens. + MOV(32, PPCSTATE(pc), Imm32(js.blockStart)); + OR(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE)); + WriteExceptionExit(); - SetJumpTarget(b1); - } + SetJumpTarget(b1); + } - js.rewriteStart = (u8*)GetCodePtr(); + js.rewriteStart = (u8*)GetCodePtr(); - u64 codeHash = -1; - if (SConfig::GetInstance().bJITILTimeProfiling || - SConfig::GetInstance().bJITILOutputIR) - { - // For profiling and IR Writer - for (u32 i = 0; i < code_block.m_num_instructions; i++) - { - const u64 inst = ops[i].inst.hex; - // Ported from boost::hash - codeHash ^= inst + (codeHash << 6) + (codeHash >> 2); - } - } + u64 codeHash = -1; + if (SConfig::GetInstance().bJITILTimeProfiling || SConfig::GetInstance().bJITILOutputIR) + { + // For profiling and IR Writer + for (u32 i = 0; i < code_block.m_num_instructions; i++) + { + const u64 inst = ops[i].inst.hex; + // Ported from boost::hash + codeHash ^= inst + (codeHash << 6) + (codeHash >> 2); + } + } - if (SConfig::GetInstance().bJITILTimeProfiling) - { - JitILProfiler::Block& block = JitILProfiler::Add(codeHash); - ABI_CallFunctionC((void *)JitILProfiler::Begin, block.index); - } + if (SConfig::GetInstance().bJITILTimeProfiling) + { + JitILProfiler::Block& block = JitILProfiler::Add(codeHash); + ABI_CallFunctionC((void*)JitILProfiler::Begin, block.index); + } - // Start up IR builder (structure that collects the - // instruction processed by the JIT routines) - ibuild.Reset(); + // Start up IR builder (structure that collects the + // instruction processed by the JIT routines) + ibuild.Reset(); - js.downcountAmount = 0; - if (!SConfig::GetInstance().bEnableDebugging) - js.downcountAmount += PatchEngine::GetSpeedhackCycles(code_block.m_address); + js.downcountAmount = 0; + if (!SConfig::GetInstance().bEnableDebugging) + js.downcountAmount += PatchEngine::GetSpeedhackCycles(code_block.m_address); - // Translate instructions - for (u32 i = 0; i < code_block.m_num_instructions; i++) - { - js.compilerPC = ops[i].address; - js.op = &ops[i]; - js.instructionNumber = i; - const GekkoOPInfo *opinfo = GetOpInfo(ops[i].inst); - js.downcountAmount += opinfo->numCycles; + // Translate instructions + for (u32 i = 0; i < code_block.m_num_instructions; i++) + { + js.compilerPC = ops[i].address; + js.op = &ops[i]; + js.instructionNumber = i; + const GekkoOPInfo* opinfo = GetOpInfo(ops[i].inst); + js.downcountAmount += opinfo->numCycles; - if (i == (code_block.m_num_instructions - 1)) - js.isLastInstruction = true; + if (i == (code_block.m_num_instructions - 1)) + js.isLastInstruction = true; - u32 function = HLE::GetFunctionIndex(ops[i].address); - if (function != 0) - { - int type = HLE::GetFunctionTypeByIndex(function); - if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE) - { - int flags = HLE::GetFunctionFlagsByIndex(function); - if (HLE::IsEnabled(flags)) - { - HLEFunction(function); - if (type == HLE::HLE_HOOK_REPLACE) - { - MOV(32, R(EAX), PPCSTATE(npc)); - jit->js.downcountAmount += jit->js.st.numCycles; - WriteExitDestInOpArg(R(EAX)); - break; - } - } - } - } + u32 function = HLE::GetFunctionIndex(ops[i].address); + if (function != 0) + { + int type = HLE::GetFunctionTypeByIndex(function); + if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE) + { + int flags = HLE::GetFunctionFlagsByIndex(function); + if (HLE::IsEnabled(flags)) + { + HLEFunction(function); + if (type == HLE::HLE_HOOK_REPLACE) + { + MOV(32, R(EAX), PPCSTATE(npc)); + jit->js.downcountAmount += jit->js.st.numCycles; + WriteExitDestInOpArg(R(EAX)); + break; + } + } + } + } - if (!ops[i].skip) - { - if (jo.memcheck && (opinfo->flags & FL_USE_FPU)) - { - ibuild.EmitFPExceptionCheck(ibuild.EmitIntConst(ops[i].address)); - } + if (!ops[i].skip) + { + if (jo.memcheck && (opinfo->flags & FL_USE_FPU)) + { + ibuild.EmitFPExceptionCheck(ibuild.EmitIntConst(ops[i].address)); + } - if (jit->js.fifoWriteAddresses.find(js.compilerPC) != jit->js.fifoWriteAddresses.end()) - { - ibuild.EmitExtExceptionCheck(ibuild.EmitIntConst(ops[i].address)); - } + if (jit->js.fifoWriteAddresses.find(js.compilerPC) != jit->js.fifoWriteAddresses.end()) + { + ibuild.EmitExtExceptionCheck(ibuild.EmitIntConst(ops[i].address)); + } - if (SConfig::GetInstance().bEnableDebugging && - breakpoints.IsAddressBreakPoint(ops[i].address) && - CPU::GetState() != CPU::CPU_STEPPING) - { - // Turn off block linking if there are breakpoints so that the Step Over command does not link this block. - jo.enableBlocklink = false; + if (SConfig::GetInstance().bEnableDebugging && + breakpoints.IsAddressBreakPoint(ops[i].address) && CPU::GetState() != CPU::CPU_STEPPING) + { + // Turn off block linking if there are breakpoints so that the Step Over command does not + // link this block. + jo.enableBlocklink = false; - ibuild.EmitBreakPointCheck(ibuild.EmitIntConst(ops[i].address)); - } + ibuild.EmitBreakPointCheck(ibuild.EmitIntConst(ops[i].address)); + } - JitILTables::CompileInstruction(ops[i]); + JitILTables::CompileInstruction(ops[i]); - if (jo.memcheck && (opinfo->flags & FL_LOADSTORE)) - { - ibuild.EmitDSIExceptionCheck(ibuild.EmitIntConst(ops[i].address)); - } + if (jo.memcheck && (opinfo->flags & FL_LOADSTORE)) + { + ibuild.EmitDSIExceptionCheck(ibuild.EmitIntConst(ops[i].address)); + } - if (opinfo->flags & FL_LOADSTORE) - ++jit->js.numLoadStoreInst; + if (opinfo->flags & FL_LOADSTORE) + ++jit->js.numLoadStoreInst; - if (opinfo->flags & FL_USE_FPU) - ++jit->js.numFloatingPointInst; - } - } + if (opinfo->flags & FL_USE_FPU) + ++jit->js.numFloatingPointInst; + } + } - // Perform actual code generation - WriteCode(nextPC); + // Perform actual code generation + WriteCode(nextPC); - b->codeSize = (u32)(GetCodePtr() - start); - b->originalSize = code_block.m_num_instructions; + b->codeSize = (u32)(GetCodePtr() - start); + b->originalSize = code_block.m_num_instructions; #ifdef JIT_LOG_X86 - LogGeneratedX86(code_block.m_num_instructions, code_buf, normalEntry, b); + LogGeneratedX86(code_block.m_num_instructions, code_buf, normalEntry, b); #endif - if (SConfig::GetInstance().bJITILOutputIR) - { - ibuild.WriteToFile(codeHash); - } + if (SConfig::GetInstance().bJITILOutputIR) + { + ibuild.WriteToFile(codeHash); + } - return normalEntry; + return normalEntry; } void JitIL::EnableBlockLink() { - jo.enableBlocklink = true; - if (SConfig::GetInstance().bJITNoBlockLinking) - jo.enableBlocklink = false; + jo.enableBlocklink = true; + if (SConfig::GetInstance().bJITNoBlockLinking) + jo.enableBlocklink = false; } diff --git a/Source/Core/Core/PowerPC/Jit64IL/JitIL.h b/Source/Core/Core/PowerPC/Jit64IL/JitIL.h index 3fd7b8d7e2..ac9950883e 100644 --- a/Source/Core/Core/PowerPC/Jit64IL/JitIL.h +++ b/Source/Core/Core/PowerPC/Jit64IL/JitIL.h @@ -19,72 +19,62 @@ #include "Common/CommonTypes.h" #include "Common/x64Emitter.h" #include "Core/PowerPC/Gekko.h" -#include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/Jit64/JitAsm.h" #include "Core/PowerPC/JitCommon/JitBase.h" #include "Core/PowerPC/JitCommon/JitCache.h" #include "Core/PowerPC/JitILCommon/JitILBase.h" +#include "Core/PowerPC/PPCAnalyst.h" class JitIL : public JitILBase { public: - Jit64AsmRoutineManager asm_routines; + Jit64AsmRoutineManager asm_routines; - JitIL() {} - ~JitIL() {} + JitIL() {} + ~JitIL() {} + // Initialization, etc - // Initialization, etc + void Init() override; - void Init() override; + void EnableBlockLink(); - void EnableBlockLink(); + void Shutdown() override; - void Shutdown() override; + // Jit! - // Jit! + void Jit(u32 em_address) override; + const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBlock* b, u32 nextPC); - void Jit(u32 em_address) override; - const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b, u32 nextPC); + void Trace(); - void Trace(); + JitBlockCache* GetBlockCache() override { return &blocks; } + void ClearCache() override; - JitBlockCache *GetBlockCache() override { return &blocks; } + const CommonAsmRoutines* GetAsmRoutines() override { return &asm_routines; } + const char* GetName() override { return "JIT64IL"; } + // Run! + void Run() override; + void SingleStep() override; - void ClearCache() override; + // Utilities for use by opcodes - const CommonAsmRoutines *GetAsmRoutines() override - { - return &asm_routines; - } + void WriteExit(u32 destination); + void WriteExitDestInOpArg(const Gen::OpArg& arg); + void WriteExceptionExit(); + void WriteRfiExitDestInOpArg(const Gen::OpArg& arg); + void Cleanup(); - const char *GetName() override - { - return "JIT64IL"; - } + void WriteCode(u32 exitAddress); - // Run! - void Run() override; - void SingleStep() override; + // OPCODES + using Instruction = void (JitIL::*)(UGeckoInstruction instCode); + void FallBackToInterpreter(UGeckoInstruction _inst) override; + void DoNothing(UGeckoInstruction _inst) override; + void HLEFunction(UGeckoInstruction _inst) override; - // Utilities for use by opcodes - - void WriteExit(u32 destination); - void WriteExitDestInOpArg(const Gen::OpArg& arg); - void WriteExceptionExit(); - void WriteRfiExitDestInOpArg(const Gen::OpArg& arg); - void Cleanup(); - - void WriteCode(u32 exitAddress); - - // OPCODES - using Instruction = void (JitIL::*)(UGeckoInstruction instCode); - void FallBackToInterpreter(UGeckoInstruction _inst) override; - void DoNothing(UGeckoInstruction _inst) override; - void HLEFunction(UGeckoInstruction _inst) override; - - void DynaRunTable4(UGeckoInstruction _inst) override; - void DynaRunTable19(UGeckoInstruction _inst) override; - void DynaRunTable31(UGeckoInstruction _inst) override; - void DynaRunTable59(UGeckoInstruction _inst) override; - void DynaRunTable63(UGeckoInstruction _inst) override; + void DynaRunTable4(UGeckoInstruction _inst) override; + void DynaRunTable19(UGeckoInstruction _inst) override; + void DynaRunTable31(UGeckoInstruction _inst) override; + void DynaRunTable59(UGeckoInstruction _inst) override; + void DynaRunTable63(UGeckoInstruction _inst) override; }; diff --git a/Source/Core/Core/PowerPC/Jit64IL/JitIL_Tables.cpp b/Source/Core/Core/PowerPC/Jit64IL/JitIL_Tables.cpp index 793b5bd5bd..26aa37c642 100644 --- a/Source/Core/Core/PowerPC/Jit64IL/JitIL_Tables.cpp +++ b/Source/Core/Core/PowerPC/Jit64IL/JitIL_Tables.cpp @@ -2,10 +2,10 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Core/PowerPC/Gekko.h" -#include "Core/PowerPC/PPCTables.h" #include "Core/PowerPC/Jit64IL/JitIL.h" +#include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/Jit64IL/JitIL_Tables.h" +#include "Core/PowerPC/PPCTables.h" static JitIL::Instruction dynaOpTable[64]; static JitIL::Instruction dynaOpTable4[1024]; @@ -14,463 +14,484 @@ static JitIL::Instruction dynaOpTable31[1024]; static JitIL::Instruction dynaOpTable59[32]; static JitIL::Instruction dynaOpTable63[1024]; -void JitIL::DynaRunTable4(UGeckoInstruction _inst) {(this->*dynaOpTable4 [_inst.SUBOP10])(_inst);} -void JitIL::DynaRunTable19(UGeckoInstruction _inst) {(this->*dynaOpTable19[_inst.SUBOP10])(_inst);} -void JitIL::DynaRunTable31(UGeckoInstruction _inst) {(this->*dynaOpTable31[_inst.SUBOP10])(_inst);} -void JitIL::DynaRunTable59(UGeckoInstruction _inst) {(this->*dynaOpTable59[_inst.SUBOP5 ])(_inst);} -void JitIL::DynaRunTable63(UGeckoInstruction _inst) {(this->*dynaOpTable63[_inst.SUBOP10])(_inst);} +void JitIL::DynaRunTable4(UGeckoInstruction _inst) +{ + (this->*dynaOpTable4[_inst.SUBOP10])(_inst); +} +void JitIL::DynaRunTable19(UGeckoInstruction _inst) +{ + (this->*dynaOpTable19[_inst.SUBOP10])(_inst); +} +void JitIL::DynaRunTable31(UGeckoInstruction _inst) +{ + (this->*dynaOpTable31[_inst.SUBOP10])(_inst); +} +void JitIL::DynaRunTable59(UGeckoInstruction _inst) +{ + (this->*dynaOpTable59[_inst.SUBOP5])(_inst); +} +void JitIL::DynaRunTable63(UGeckoInstruction _inst) +{ + (this->*dynaOpTable63[_inst.SUBOP10])(_inst); +} struct GekkoOPTemplate { - int opcode; - JitIL::Instruction Inst; + int opcode; + JitIL::Instruction Inst; }; -static GekkoOPTemplate primarytable[] = -{ - {4, &JitIL::DynaRunTable4}, //"RunTable4", OPTYPE_SUBTABLE | (4<<24), 0}}, - {19, &JitIL::DynaRunTable19}, //"RunTable19", OPTYPE_SUBTABLE | (19<<24), 0}}, - {31, &JitIL::DynaRunTable31}, //"RunTable31", OPTYPE_SUBTABLE | (31<<24), 0}}, - {59, &JitIL::DynaRunTable59}, //"RunTable59", OPTYPE_SUBTABLE | (59<<24), 0}}, - {63, &JitIL::DynaRunTable63}, //"RunTable63", OPTYPE_SUBTABLE | (63<<24), 0}}, +static GekkoOPTemplate primarytable[] = { + {4, &JitIL::DynaRunTable4}, //"RunTable4", OPTYPE_SUBTABLE | (4<<24), 0}}, + {19, &JitIL::DynaRunTable19}, //"RunTable19", OPTYPE_SUBTABLE | (19<<24), 0}}, + {31, &JitIL::DynaRunTable31}, //"RunTable31", OPTYPE_SUBTABLE | (31<<24), 0}}, + {59, &JitIL::DynaRunTable59}, //"RunTable59", OPTYPE_SUBTABLE | (59<<24), 0}}, + {63, &JitIL::DynaRunTable63}, //"RunTable63", OPTYPE_SUBTABLE | (63<<24), 0}}, - {16, &JitIL::bcx}, //"bcx", OPTYPE_SYSTEM, FL_ENDBLOCK}}, - {18, &JitIL::bx}, //"bx", OPTYPE_SYSTEM, FL_ENDBLOCK}}, + {16, &JitIL::bcx}, //"bcx", OPTYPE_SYSTEM, FL_ENDBLOCK}}, + {18, &JitIL::bx}, //"bx", OPTYPE_SYSTEM, FL_ENDBLOCK}}, - {3, &JitIL::FallBackToInterpreter}, //"twi", OPTYPE_SYSTEM, 0}}, - {17, &JitIL::sc}, //"sc", OPTYPE_SYSTEM, FL_ENDBLOCK, 1}}, + {3, &JitIL::FallBackToInterpreter}, //"twi", OPTYPE_SYSTEM, 0}}, + {17, &JitIL::sc}, //"sc", OPTYPE_SYSTEM, FL_ENDBLOCK, 1}}, - {7, &JitIL::mulli}, //"mulli", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_RC_BIT, 2}}, - {8, &JitIL::subfic}, //"subfic", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CA}}, - {10, &JitIL::cmpXX}, //"cmpli", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}}, - {11, &JitIL::cmpXX}, //"cmpi", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}}, - {12, &JitIL::reg_imm}, //"addic", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CA}}, - {13, &JitIL::reg_imm}, //"addic_rc", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CR0}}, - {14, &JitIL::reg_imm}, //"addi", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}}, - {15, &JitIL::reg_imm}, //"addis", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}}, + {7, &JitIL::mulli}, //"mulli", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_RC_BIT, 2}}, + {8, &JitIL::subfic}, //"subfic", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CA}}, + {10, &JitIL::cmpXX}, //"cmpli", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}}, + {11, &JitIL::cmpXX}, //"cmpi", OPTYPE_INTEGER, FL_IN_A | FL_SET_CRn}}, + {12, &JitIL::reg_imm}, //"addic", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CA}}, + {13, &JitIL::reg_imm}, //"addic_rc", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_SET_CR0}}, + {14, &JitIL::reg_imm}, //"addi", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}}, + {15, &JitIL::reg_imm}, //"addis", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A0}}, - {20, &JitIL::rlwimix}, //"rlwimix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_A | FL_IN_S | FL_RC_BIT}}, - {21, &JitIL::rlwinmx}, //"rlwinmx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, - {23, &JitIL::rlwnmx}, //"rlwnmx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_IN_B | FL_RC_BIT}}, + {20, + &JitIL::rlwimix}, //"rlwimix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_A | FL_IN_S | FL_RC_BIT}}, + {21, &JitIL::rlwinmx}, //"rlwinmx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, + {23, &JitIL::rlwnmx}, //"rlwnmx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_IN_B | FL_RC_BIT}}, - {24, &JitIL::reg_imm}, //"ori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, - {25, &JitIL::reg_imm}, //"oris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, - {26, &JitIL::reg_imm}, //"xori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, - {27, &JitIL::reg_imm}, //"xoris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, - {28, &JitIL::reg_imm}, //"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, - {29, &JitIL::reg_imm}, //"andis_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, + {24, &JitIL::reg_imm}, //"ori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, + {25, &JitIL::reg_imm}, //"oris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, + {26, &JitIL::reg_imm}, //"xori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, + {27, &JitIL::reg_imm}, //"xoris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, + {28, &JitIL::reg_imm}, //"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, + {29, &JitIL::reg_imm}, //"andis_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, - {32, &JitIL::lXz}, //"lwz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, - {33, &JitIL::lXz}, //"lwzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, - {34, &JitIL::lXz}, //"lbz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, - {35, &JitIL::lbzu}, //"lbzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, - {40, &JitIL::lXz}, //"lhz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, - {41, &JitIL::lXz}, //"lhzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, - {42, &JitIL::lha}, //"lha", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, - {43, &JitIL::lhau}, //"lhau", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, + {32, &JitIL::lXz}, //"lwz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, + {33, &JitIL::lXz}, //"lwzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, + {34, &JitIL::lXz}, //"lbz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, + {35, &JitIL::lbzu}, //"lbzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, + {40, &JitIL::lXz}, //"lhz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, + {41, &JitIL::lXz}, //"lhzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, + {42, &JitIL::lha}, //"lha", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, + {43, &JitIL::lhau}, //"lhau", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, - {44, &JitIL::stX}, //"sth", OPTYPE_STORE, FL_IN_A | FL_IN_S}}, - {45, &JitIL::stX}, //"sthu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}}, - {36, &JitIL::stX}, //"stw", OPTYPE_STORE, FL_IN_A | FL_IN_S}}, - {37, &JitIL::stX}, //"stwu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}}, - {38, &JitIL::stX}, //"stb", OPTYPE_STORE, FL_IN_A | FL_IN_S}}, - {39, &JitIL::stX}, //"stbu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}}, + {44, &JitIL::stX}, //"sth", OPTYPE_STORE, FL_IN_A | FL_IN_S}}, + {45, &JitIL::stX}, //"sthu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}}, + {36, &JitIL::stX}, //"stw", OPTYPE_STORE, FL_IN_A | FL_IN_S}}, + {37, &JitIL::stX}, //"stwu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}}, + {38, &JitIL::stX}, //"stb", OPTYPE_STORE, FL_IN_A | FL_IN_S}}, + {39, &JitIL::stX}, //"stbu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}}, - {46, &JitIL::lmw}, //"lmw", OPTYPE_SYSTEM, FL_EVIL, 10}}, - {47, &JitIL::stmw}, //"stmw", OPTYPE_SYSTEM, FL_EVIL, 10}}, + {46, &JitIL::lmw}, //"lmw", OPTYPE_SYSTEM, FL_EVIL, 10}}, + {47, &JitIL::stmw}, //"stmw", OPTYPE_SYSTEM, FL_EVIL, 10}}, - {48, &JitIL::lfs}, //"lfs", OPTYPE_LOADFP, FL_IN_A}}, - {49, &JitIL::lfsu}, //"lfsu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A}}, - {50, &JitIL::lfd}, //"lfd", OPTYPE_LOADFP, FL_IN_A}}, - {51, &JitIL::lfdu}, //"lfdu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A}}, + {48, &JitIL::lfs}, //"lfs", OPTYPE_LOADFP, FL_IN_A}}, + {49, &JitIL::lfsu}, //"lfsu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A}}, + {50, &JitIL::lfd}, //"lfd", OPTYPE_LOADFP, FL_IN_A}}, + {51, &JitIL::lfdu}, //"lfdu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A}}, - {52, &JitIL::stfs}, //"stfs", OPTYPE_STOREFP, FL_IN_A}}, - {53, &JitIL::stfs}, //"stfsu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}}, - {54, &JitIL::stfd}, //"stfd", OPTYPE_STOREFP, FL_IN_A}}, - {55, &JitIL::stfd}, //"stfdu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}}, + {52, &JitIL::stfs}, //"stfs", OPTYPE_STOREFP, FL_IN_A}}, + {53, &JitIL::stfs}, //"stfsu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}}, + {54, &JitIL::stfd}, //"stfd", OPTYPE_STOREFP, FL_IN_A}}, + {55, &JitIL::stfd}, //"stfdu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}}, - {56, &JitIL::psq_l}, //"psq_l", OPTYPE_PS, FL_IN_A}}, - {57, &JitIL::psq_l}, //"psq_lu", OPTYPE_PS, FL_OUT_A | FL_IN_A}}, - {60, &JitIL::psq_st}, //"psq_st", OPTYPE_PS, FL_IN_A}}, - {61, &JitIL::psq_st}, //"psq_stu", OPTYPE_PS, FL_OUT_A | FL_IN_A}}, + {56, &JitIL::psq_l}, //"psq_l", OPTYPE_PS, FL_IN_A}}, + {57, &JitIL::psq_l}, //"psq_lu", OPTYPE_PS, FL_OUT_A | FL_IN_A}}, + {60, &JitIL::psq_st}, //"psq_st", OPTYPE_PS, FL_IN_A}}, + {61, &JitIL::psq_st}, //"psq_stu", OPTYPE_PS, FL_OUT_A | FL_IN_A}}, - //missing: 0, 1, 2, 5, 6, 9, 22, 30, 62, 58 + // missing: 0, 1, 2, 5, 6, 9, 22, 30, 62, 58 }; -static GekkoOPTemplate table4[] = -{ //SUBOP10 - {0, &JitIL::FallBackToInterpreter}, //"ps_cmpu0", OPTYPE_PS, FL_SET_CRn}}, - {32, &JitIL::FallBackToInterpreter}, //"ps_cmpo0", OPTYPE_PS, FL_SET_CRn}}, - {40, &JitIL::FallBackToInterpreter}, //"ps_neg", OPTYPE_PS, FL_RC_BIT}}, - {136, &JitIL::FallBackToInterpreter}, //"ps_nabs", OPTYPE_PS, FL_RC_BIT}}, - {264, &JitIL::FallBackToInterpreter}, //"ps_abs", OPTYPE_PS, FL_RC_BIT}}, - {64, &JitIL::FallBackToInterpreter}, //"ps_cmpu1", OPTYPE_PS, FL_RC_BIT}}, - {72, &JitIL::FallBackToInterpreter}, //"ps_mr", OPTYPE_PS, FL_RC_BIT}}, - {96, &JitIL::FallBackToInterpreter}, //"ps_cmpo1", OPTYPE_PS, FL_RC_BIT}}, - {528, &JitIL::ps_mergeXX}, //"ps_merge00", OPTYPE_PS, FL_RC_BIT}}, - {560, &JitIL::ps_mergeXX}, //"ps_merge01", OPTYPE_PS, FL_RC_BIT}}, - {592, &JitIL::ps_mergeXX}, //"ps_merge10", OPTYPE_PS, FL_RC_BIT}}, - {624, &JitIL::ps_mergeXX}, //"ps_merge11", OPTYPE_PS, FL_RC_BIT}}, +static GekkoOPTemplate table4[] = { + // SUBOP10 + {0, &JitIL::FallBackToInterpreter}, //"ps_cmpu0", OPTYPE_PS, FL_SET_CRn}}, + {32, &JitIL::FallBackToInterpreter}, //"ps_cmpo0", OPTYPE_PS, FL_SET_CRn}}, + {40, &JitIL::FallBackToInterpreter}, //"ps_neg", OPTYPE_PS, FL_RC_BIT}}, + {136, &JitIL::FallBackToInterpreter}, //"ps_nabs", OPTYPE_PS, FL_RC_BIT}}, + {264, &JitIL::FallBackToInterpreter}, //"ps_abs", OPTYPE_PS, FL_RC_BIT}}, + {64, &JitIL::FallBackToInterpreter}, //"ps_cmpu1", OPTYPE_PS, FL_RC_BIT}}, + {72, &JitIL::FallBackToInterpreter}, //"ps_mr", OPTYPE_PS, FL_RC_BIT}}, + {96, &JitIL::FallBackToInterpreter}, //"ps_cmpo1", OPTYPE_PS, FL_RC_BIT}}, + {528, &JitIL::ps_mergeXX}, //"ps_merge00", OPTYPE_PS, FL_RC_BIT}}, + {560, &JitIL::ps_mergeXX}, //"ps_merge01", OPTYPE_PS, FL_RC_BIT}}, + {592, &JitIL::ps_mergeXX}, //"ps_merge10", OPTYPE_PS, FL_RC_BIT}}, + {624, &JitIL::ps_mergeXX}, //"ps_merge11", OPTYPE_PS, FL_RC_BIT}}, - {1014, &JitIL::FallBackToInterpreter}, //"dcbz_l", OPTYPE_SYSTEM, 0}}, + {1014, &JitIL::FallBackToInterpreter}, //"dcbz_l", OPTYPE_SYSTEM, 0}}, }; -static GekkoOPTemplate table4_2[] = -{ - {10, &JitIL::ps_sum}, //"ps_sum0", OPTYPE_PS, 0}}, - {11, &JitIL::ps_sum}, //"ps_sum1", OPTYPE_PS, 0}}, - {12, &JitIL::ps_muls}, //"ps_muls0", OPTYPE_PS, 0}}, - {13, &JitIL::ps_muls}, //"ps_muls1", OPTYPE_PS, 0}}, - {14, &JitIL::ps_maddXX}, //"ps_madds0", OPTYPE_PS, 0}}, - {15, &JitIL::ps_maddXX}, //"ps_madds1", OPTYPE_PS, 0}}, - {18, &JitIL::ps_arith}, //"ps_div", OPTYPE_PS, 0, 16}}, - {20, &JitIL::ps_arith}, //"ps_sub", OPTYPE_PS, 0}}, - {21, &JitIL::ps_arith}, //"ps_add", OPTYPE_PS, 0}}, - {23, &JitIL::FallBackToInterpreter}, //"ps_sel", OPTYPE_PS, 0}}, - {24, &JitIL::FallBackToInterpreter}, //"ps_res", OPTYPE_PS, 0}}, - {25, &JitIL::ps_arith}, //"ps_mul", OPTYPE_PS, 0}}, - {26, &JitIL::FallBackToInterpreter}, //"ps_rsqrte", OPTYPE_PS, 0, 1}}, - {28, &JitIL::ps_maddXX}, //"ps_msub", OPTYPE_PS, 0}}, - {29, &JitIL::ps_maddXX}, //"ps_madd", OPTYPE_PS, 0}}, - {30, &JitIL::ps_maddXX}, //"ps_nmsub", OPTYPE_PS, 0}}, - {31, &JitIL::ps_maddXX}, //"ps_nmadd", OPTYPE_PS, 0}}, +static GekkoOPTemplate table4_2[] = { + {10, &JitIL::ps_sum}, //"ps_sum0", OPTYPE_PS, 0}}, + {11, &JitIL::ps_sum}, //"ps_sum1", OPTYPE_PS, 0}}, + {12, &JitIL::ps_muls}, //"ps_muls0", OPTYPE_PS, 0}}, + {13, &JitIL::ps_muls}, //"ps_muls1", OPTYPE_PS, 0}}, + {14, &JitIL::ps_maddXX}, //"ps_madds0", OPTYPE_PS, 0}}, + {15, &JitIL::ps_maddXX}, //"ps_madds1", OPTYPE_PS, 0}}, + {18, &JitIL::ps_arith}, //"ps_div", OPTYPE_PS, 0, 16}}, + {20, &JitIL::ps_arith}, //"ps_sub", OPTYPE_PS, 0}}, + {21, &JitIL::ps_arith}, //"ps_add", OPTYPE_PS, 0}}, + {23, &JitIL::FallBackToInterpreter}, //"ps_sel", OPTYPE_PS, 0}}, + {24, &JitIL::FallBackToInterpreter}, //"ps_res", OPTYPE_PS, 0}}, + {25, &JitIL::ps_arith}, //"ps_mul", OPTYPE_PS, 0}}, + {26, &JitIL::FallBackToInterpreter}, //"ps_rsqrte", OPTYPE_PS, 0, 1}}, + {28, &JitIL::ps_maddXX}, //"ps_msub", OPTYPE_PS, 0}}, + {29, &JitIL::ps_maddXX}, //"ps_madd", OPTYPE_PS, 0}}, + {30, &JitIL::ps_maddXX}, //"ps_nmsub", OPTYPE_PS, 0}}, + {31, &JitIL::ps_maddXX}, //"ps_nmadd", OPTYPE_PS, 0}}, }; -static GekkoOPTemplate table4_3[] = -{ - {6, &JitIL::FallBackToInterpreter}, //"psq_lx", OPTYPE_PS, 0}}, - {7, &JitIL::FallBackToInterpreter}, //"psq_stx", OPTYPE_PS, 0}}, - {38, &JitIL::FallBackToInterpreter}, //"psq_lux", OPTYPE_PS, 0}}, - {39, &JitIL::FallBackToInterpreter}, //"psq_stux", OPTYPE_PS, 0}}, +static GekkoOPTemplate table4_3[] = { + {6, &JitIL::FallBackToInterpreter}, //"psq_lx", OPTYPE_PS, 0}}, + {7, &JitIL::FallBackToInterpreter}, //"psq_stx", OPTYPE_PS, 0}}, + {38, &JitIL::FallBackToInterpreter}, //"psq_lux", OPTYPE_PS, 0}}, + {39, &JitIL::FallBackToInterpreter}, //"psq_stux", OPTYPE_PS, 0}}, }; -static GekkoOPTemplate table19[] = -{ - {528, &JitIL::bcctrx}, //"bcctrx", OPTYPE_BRANCH, FL_ENDBLOCK}}, - {16, &JitIL::bclrx}, //"bclrx", OPTYPE_BRANCH, FL_ENDBLOCK}}, - {257, &JitIL::crXX}, //"crand", OPTYPE_CR, FL_EVIL}}, - {129, &JitIL::crXX}, //"crandc", OPTYPE_CR, FL_EVIL}}, - {289, &JitIL::crXX}, //"creqv", OPTYPE_CR, FL_EVIL}}, - {225, &JitIL::crXX}, //"crnand", OPTYPE_CR, FL_EVIL}}, - {33, &JitIL::crXX}, //"crnor", OPTYPE_CR, FL_EVIL}}, - {449, &JitIL::crXX}, //"cror", OPTYPE_CR, FL_EVIL}}, - {417, &JitIL::crXX}, //"crorc", OPTYPE_CR, FL_EVIL}}, - {193, &JitIL::crXX}, //"crxor", OPTYPE_CR, FL_EVIL}}, +static GekkoOPTemplate table19[] = { + {528, &JitIL::bcctrx}, //"bcctrx", OPTYPE_BRANCH, FL_ENDBLOCK}}, + {16, &JitIL::bclrx}, //"bclrx", OPTYPE_BRANCH, FL_ENDBLOCK}}, + {257, &JitIL::crXX}, //"crand", OPTYPE_CR, FL_EVIL}}, + {129, &JitIL::crXX}, //"crandc", OPTYPE_CR, FL_EVIL}}, + {289, &JitIL::crXX}, //"creqv", OPTYPE_CR, FL_EVIL}}, + {225, &JitIL::crXX}, //"crnand", OPTYPE_CR, FL_EVIL}}, + {33, &JitIL::crXX}, //"crnor", OPTYPE_CR, FL_EVIL}}, + {449, &JitIL::crXX}, //"cror", OPTYPE_CR, FL_EVIL}}, + {417, &JitIL::crXX}, //"crorc", OPTYPE_CR, FL_EVIL}}, + {193, &JitIL::crXX}, //"crxor", OPTYPE_CR, FL_EVIL}}, - {150, &JitIL::DoNothing}, //"isync", OPTYPE_ICACHE, FL_EVIL}}, - {0, &JitIL::mcrf}, //"mcrf", OPTYPE_SYSTEM, FL_EVIL}}, + {150, &JitIL::DoNothing}, //"isync", OPTYPE_ICACHE, FL_EVIL}}, + {0, &JitIL::mcrf}, //"mcrf", OPTYPE_SYSTEM, FL_EVIL}}, - {50, &JitIL::rfi}, //"rfi", OPTYPE_SYSTEM, FL_ENDBLOCK | FL_CHECKEXCEPTIONS, 1}}, + {50, &JitIL::rfi}, //"rfi", OPTYPE_SYSTEM, FL_ENDBLOCK | FL_CHECKEXCEPTIONS, 1}}, }; +static GekkoOPTemplate table31[] = { + {266, &JitIL::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, + {778, &JitIL::addx}, //"addox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, + {10, &JitIL::FallBackToInterpreter}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | + //FL_SET_CA | FL_RC_BIT}}, + {522, &JitIL::FallBackToInterpreter}, //"addcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | + //FL_SET_CA | FL_RC_BIT}}, + {138, &JitIL::addex}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA + //| FL_RC_BIT}}, + {650, &JitIL::addex}, //"addeox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA + //| FL_RC_BIT}}, + {234, &JitIL::FallBackToInterpreter}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | + //FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, + {746, &JitIL::FallBackToInterpreter}, //"addmeox" + {202, &JitIL::addzex}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | + //FL_SET_CA | FL_RC_BIT}}, + {714, &JitIL::addzex}, //"addzeox" + {491, &JitIL::FallBackToInterpreter}, //"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | + //FL_RC_BIT, 39}}, + {1003, &JitIL::FallBackToInterpreter}, //"divwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | + //FL_RC_BIT, 39}}, + {459, &JitIL::divwux}, //"divwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}}, + {971, &JitIL::divwux}, //"divwuox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}}, + {75, &JitIL::FallBackToInterpreter}, //"mulhwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | + //FL_RC_BIT, 4}}, + {11, &JitIL::mulhwux}, //"mulhwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, + {235, &JitIL::mullwx}, //"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, + {747, &JitIL::mullwx}, //"mullwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, + {104, &JitIL::negx}, //"negx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, + {616, &JitIL::negx}, //"negox" + {40, &JitIL::subfx}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, + {552, &JitIL::subfx}, //"subfox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, + {8, + &JitIL::subfcx}, //"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, + {520, + &JitIL::subfcx}, //"subfcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, + {136, &JitIL::subfex}, //"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | + //FL_SET_CA | FL_RC_BIT}}, + {648, &JitIL::subfex}, //"subfeox" + {232, &JitIL::FallBackToInterpreter}, //"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | + //FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, + {744, &JitIL::FallBackToInterpreter}, //"subfmeox" + {200, &JitIL::FallBackToInterpreter}, //"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | + //FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, + {712, &JitIL::FallBackToInterpreter}, //"subfzeox" -static GekkoOPTemplate table31[] = -{ - {266, &JitIL::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, - {778, &JitIL::addx}, //"addox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, - {10, &JitIL::FallBackToInterpreter}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, - {522, &JitIL::FallBackToInterpreter}, //"addcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, - {138, &JitIL::addex}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, - {650, &JitIL::addex}, //"addeox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, - {234, &JitIL::FallBackToInterpreter}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, - {746, &JitIL::FallBackToInterpreter}, //"addmeox" - {202, &JitIL::addzex}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, - {714, &JitIL::addzex}, //"addzeox" - {491, &JitIL::FallBackToInterpreter}, //"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}}, - {1003, &JitIL::FallBackToInterpreter}, //"divwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}}, - {459, &JitIL::divwux}, //"divwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}}, - {971, &JitIL::divwux}, //"divwuox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}}, - {75, &JitIL::FallBackToInterpreter}, //"mulhwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, - {11, &JitIL::mulhwux}, //"mulhwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, - {235, &JitIL::mullwx}, //"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, - {747, &JitIL::mullwx}, //"mullwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, - {104, &JitIL::negx}, //"negx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, - {616, &JitIL::negx}, //"negox" - {40, &JitIL::subfx}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, - {552, &JitIL::subfx}, //"subfox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, - {8, &JitIL::subfcx}, //"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, - {520, &JitIL::subfcx}, //"subfcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, - {136, &JitIL::subfex}, //"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, - {648, &JitIL::subfex}, //"subfeox" - {232, &JitIL::FallBackToInterpreter}, //"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, - {744, &JitIL::FallBackToInterpreter}, //"subfmeox" - {200, &JitIL::FallBackToInterpreter}, //"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, - {712, &JitIL::FallBackToInterpreter}, //"subfzeox" + {28, &JitIL::boolX}, //"andx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {60, &JitIL::boolX}, //"andcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {444, &JitIL::boolX}, //"orx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {124, &JitIL::boolX}, //"norx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {316, &JitIL::boolX}, //"xorx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {412, &JitIL::boolX}, //"orcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {476, &JitIL::boolX}, //"nandx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {284, &JitIL::boolX}, //"eqvx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {0, &JitIL::cmpXX}, //"cmp", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, + {32, &JitIL::cmpXX}, //"cmpl", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, + {26, &JitIL::cntlzwx}, //"cntlzwx",OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, + {922, &JitIL::extshx}, //"extshx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, + {954, &JitIL::extsbx}, //"extsbx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, + {536, &JitIL::srwx}, //"srwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, + {792, &JitIL::srawx}, //"srawx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, + {824, &JitIL::srawix}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, + {24, &JitIL::slwx}, //"slwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, - {28, &JitIL::boolX}, //"andx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {60, &JitIL::boolX}, //"andcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {444, &JitIL::boolX}, //"orx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {124, &JitIL::boolX}, //"norx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {316, &JitIL::boolX}, //"xorx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {412, &JitIL::boolX}, //"orcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {476, &JitIL::boolX}, //"nandx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {284, &JitIL::boolX}, //"eqvx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, - {0, &JitIL::cmpXX}, //"cmp", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, - {32, &JitIL::cmpXX}, //"cmpl", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, - {26, &JitIL::cntlzwx}, //"cntlzwx",OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, - {922, &JitIL::extshx}, //"extshx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, - {954, &JitIL::extsbx}, //"extsbx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, - {536, &JitIL::srwx}, //"srwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, - {792, &JitIL::srawx}, //"srawx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, - {824, &JitIL::srawix}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, - {24, &JitIL::slwx}, //"slwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, + {54, &JitIL::dcbst}, //"dcbst", OPTYPE_DCACHE, 0, 4}}, + {86, &JitIL::FallBackToInterpreter}, //"dcbf", OPTYPE_DCACHE, 0, 4}}, + {246, &JitIL::DoNothing}, //"dcbtst", OPTYPE_DCACHE, 0, 1}}, + {278, &JitIL::DoNothing}, //"dcbt", OPTYPE_DCACHE, 0, 1}}, + {470, &JitIL::FallBackToInterpreter}, //"dcbi", OPTYPE_DCACHE, 0, 4}}, + {758, &JitIL::DoNothing}, //"dcba", OPTYPE_DCACHE, 0, 4}}, + {1014, &JitIL::dcbz}, //"dcbz", OPTYPE_DCACHE, 0, 4}}, - {54, &JitIL::dcbst}, //"dcbst", OPTYPE_DCACHE, 0, 4}}, - {86, &JitIL::FallBackToInterpreter}, //"dcbf", OPTYPE_DCACHE, 0, 4}}, - {246, &JitIL::DoNothing}, //"dcbtst", OPTYPE_DCACHE, 0, 1}}, - {278, &JitIL::DoNothing}, //"dcbt", OPTYPE_DCACHE, 0, 1}}, - {470, &JitIL::FallBackToInterpreter}, //"dcbi", OPTYPE_DCACHE, 0, 4}}, - {758, &JitIL::DoNothing}, //"dcba", OPTYPE_DCACHE, 0, 4}}, - {1014, &JitIL::dcbz}, //"dcbz", OPTYPE_DCACHE, 0, 4}}, + // load word + {23, &JitIL::lXzx}, //"lwzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, + {55, &JitIL::lXzx}, //"lwzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, - //load word - {23, &JitIL::lXzx}, //"lwzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - {55, &JitIL::lXzx}, //"lwzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, + // load halfword + {279, &JitIL::lXzx}, //"lhzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, + {311, &JitIL::lXzx}, //"lhzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, - //load halfword - {279, &JitIL::lXzx}, //"lhzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - {311, &JitIL::lXzx}, //"lhzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, + // load halfword signextend + {343, &JitIL::lhax}, //"lhax", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, + {375, &JitIL::lhaux}, //"lhaux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, - //load halfword signextend - {343, &JitIL::lhax}, //"lhax", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - {375, &JitIL::lhaux}, //"lhaux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, + // load byte + {87, &JitIL::lXzx}, //"lbzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, + {119, &JitIL::lXzx}, //"lbzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, - //load byte - {87, &JitIL::lXzx}, //"lbzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - {119, &JitIL::lXzx}, //"lbzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, + // load byte reverse + {534, &JitIL::FallBackToInterpreter}, //"lwbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, + {790, &JitIL::FallBackToInterpreter}, //"lhbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - //load byte reverse - {534, &JitIL::FallBackToInterpreter}, //"lwbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - {790, &JitIL::FallBackToInterpreter}, //"lhbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, + // Conditional load/store (Wii SMP) + {150, &JitIL::FallBackToInterpreter}, //"stwcxd", OPTYPE_STORE, FL_EVIL | FL_SET_CR0}}, + {20, &JitIL::FallBackToInterpreter}, //"lwarx", OPTYPE_LOAD, FL_EVIL | FL_OUT_D | FL_IN_A0B | + //FL_SET_CR0}}, - // Conditional load/store (Wii SMP) - {150, &JitIL::FallBackToInterpreter}, //"stwcxd", OPTYPE_STORE, FL_EVIL | FL_SET_CR0}}, - {20, &JitIL::FallBackToInterpreter}, //"lwarx", OPTYPE_LOAD, FL_EVIL | FL_OUT_D | FL_IN_A0B | FL_SET_CR0}}, + // load string (interpret these) + {533, &JitIL::FallBackToInterpreter}, //"lswx", OPTYPE_LOAD, FL_EVIL | FL_IN_A | FL_OUT_D}}, + {597, &JitIL::FallBackToInterpreter}, //"lswi", OPTYPE_LOAD, FL_EVIL | FL_IN_AB | FL_OUT_D}}, - //load string (interpret these) - {533, &JitIL::FallBackToInterpreter}, //"lswx", OPTYPE_LOAD, FL_EVIL | FL_IN_A | FL_OUT_D}}, - {597, &JitIL::FallBackToInterpreter}, //"lswi", OPTYPE_LOAD, FL_EVIL | FL_IN_AB | FL_OUT_D}}, + // store word + {151, &JitIL::stXx}, //"stwx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, + {183, &JitIL::stXx}, //"stwux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}}, - //store word - {151, &JitIL::stXx}, //"stwx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, - {183, &JitIL::stXx}, //"stwux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}}, + // store halfword + {407, &JitIL::stXx}, //"sthx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, + {439, &JitIL::stXx}, //"sthux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}}, - //store halfword - {407, &JitIL::stXx}, //"sthx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, - {439, &JitIL::stXx}, //"sthux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}}, + // store byte + {215, &JitIL::stXx}, //"stbx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, + {247, &JitIL::stXx}, //"stbux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}}, - //store byte - {215, &JitIL::stXx}, //"stbx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, - {247, &JitIL::stXx}, //"stbux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}}, + // store bytereverse + {662, &JitIL::FallBackToInterpreter}, //"stwbrx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, + {918, &JitIL::FallBackToInterpreter}, //"sthbrx", OPTYPE_STORE, FL_IN_A | FL_IN_B}}, - //store bytereverse - {662, &JitIL::FallBackToInterpreter}, //"stwbrx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, - {918, &JitIL::FallBackToInterpreter}, //"sthbrx", OPTYPE_STORE, FL_IN_A | FL_IN_B}}, + {661, &JitIL::FallBackToInterpreter}, //"stswx", OPTYPE_STORE, FL_EVIL}}, + {725, &JitIL::FallBackToInterpreter}, //"stswi", OPTYPE_STORE, FL_EVIL}}, - {661, &JitIL::FallBackToInterpreter}, //"stswx", OPTYPE_STORE, FL_EVIL}}, - {725, &JitIL::FallBackToInterpreter}, //"stswi", OPTYPE_STORE, FL_EVIL}}, + // fp load/store + {535, &JitIL::lfsx}, //"lfsx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B}}, + {567, &JitIL::FallBackToInterpreter}, //"lfsux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B}}, + {599, &JitIL::FallBackToInterpreter}, //"lfdx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B}}, + {631, &JitIL::FallBackToInterpreter}, //"lfdux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B}}, - // fp load/store - {535, &JitIL::lfsx}, //"lfsx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B}}, - {567, &JitIL::FallBackToInterpreter}, //"lfsux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B}}, - {599, &JitIL::FallBackToInterpreter}, //"lfdx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B}}, - {631, &JitIL::FallBackToInterpreter}, //"lfdux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B}}, + {663, &JitIL::stfsx}, //"stfsx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}}, + {695, &JitIL::FallBackToInterpreter}, //"stfsux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B}}, + {727, &JitIL::FallBackToInterpreter}, //"stfdx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}}, + {759, &JitIL::FallBackToInterpreter}, //"stfdux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B}}, + {983, &JitIL::FallBackToInterpreter}, //"stfiwx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}}, - {663, &JitIL::stfsx}, //"stfsx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}}, - {695, &JitIL::FallBackToInterpreter}, //"stfsux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B}}, - {727, &JitIL::FallBackToInterpreter}, //"stfdx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}}, - {759, &JitIL::FallBackToInterpreter}, //"stfdux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B}}, - {983, &JitIL::FallBackToInterpreter}, //"stfiwx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}}, + {19, &JitIL::mfcr}, //"mfcr", OPTYPE_SYSTEM, FL_OUT_D}}, + {83, &JitIL::mfmsr}, //"mfmsr", OPTYPE_SYSTEM, FL_OUT_D}}, + {144, &JitIL::mtcrf}, //"mtcrf", OPTYPE_SYSTEM, 0}}, + {146, &JitIL::mtmsr}, //"mtmsr", OPTYPE_SYSTEM, FL_ENDBLOCK}}, + {210, &JitIL::FallBackToInterpreter}, //"mtsr", OPTYPE_SYSTEM, 0}}, + {242, &JitIL::FallBackToInterpreter}, //"mtsrin", OPTYPE_SYSTEM, 0}}, + {339, &JitIL::mfspr}, //"mfspr", OPTYPE_SPR, FL_OUT_D}}, + {467, &JitIL::mtspr}, //"mtspr", OPTYPE_SPR, 0, 2}}, + {371, &JitIL::mftb}, //"mftb", OPTYPE_SYSTEM, FL_OUT_D | FL_TIMER}}, + {512, &JitIL::FallBackToInterpreter}, //"mcrxr", OPTYPE_SYSTEM, 0}}, + {595, &JitIL::FallBackToInterpreter}, //"mfsr", OPTYPE_SYSTEM, FL_OUT_D, 2}}, + {659, &JitIL::FallBackToInterpreter}, //"mfsrin", OPTYPE_SYSTEM, FL_OUT_D, 2}}, - {19, &JitIL::mfcr}, //"mfcr", OPTYPE_SYSTEM, FL_OUT_D}}, - {83, &JitIL::mfmsr}, //"mfmsr", OPTYPE_SYSTEM, FL_OUT_D}}, - {144, &JitIL::mtcrf}, //"mtcrf", OPTYPE_SYSTEM, 0}}, - {146, &JitIL::mtmsr}, //"mtmsr", OPTYPE_SYSTEM, FL_ENDBLOCK}}, - {210, &JitIL::FallBackToInterpreter}, //"mtsr", OPTYPE_SYSTEM, 0}}, - {242, &JitIL::FallBackToInterpreter}, //"mtsrin", OPTYPE_SYSTEM, 0}}, - {339, &JitIL::mfspr}, //"mfspr", OPTYPE_SPR, FL_OUT_D}}, - {467, &JitIL::mtspr}, //"mtspr", OPTYPE_SPR, 0, 2}}, - {371, &JitIL::mftb}, //"mftb", OPTYPE_SYSTEM, FL_OUT_D | FL_TIMER}}, - {512, &JitIL::FallBackToInterpreter}, //"mcrxr", OPTYPE_SYSTEM, 0}}, - {595, &JitIL::FallBackToInterpreter}, //"mfsr", OPTYPE_SYSTEM, FL_OUT_D, 2}}, - {659, &JitIL::FallBackToInterpreter}, //"mfsrin", OPTYPE_SYSTEM, FL_OUT_D, 2}}, + {4, &JitIL::FallBackToInterpreter}, //"tw", OPTYPE_SYSTEM, 0, 1}}, + {598, &JitIL::DoNothing}, //"sync", OPTYPE_SYSTEM, 0, 2}}, + {982, &JitIL::icbi}, //"icbi", OPTYPE_SYSTEM, FL_ENDBLOCK, 3}}, - {4, &JitIL::FallBackToInterpreter}, //"tw", OPTYPE_SYSTEM, 0, 1}}, - {598, &JitIL::DoNothing}, //"sync", OPTYPE_SYSTEM, 0, 2}}, - {982, &JitIL::icbi}, //"icbi", OPTYPE_SYSTEM, FL_ENDBLOCK, 3}}, - - // Unused instructions on GC - {310, &JitIL::FallBackToInterpreter}, //"eciwx", OPTYPE_INTEGER, FL_RC_BIT}}, - {438, &JitIL::FallBackToInterpreter}, //"ecowx", OPTYPE_INTEGER, FL_RC_BIT}}, - {854, &JitIL::DoNothing}, //"eieio", OPTYPE_INTEGER, FL_RC_BIT}}, - {306, &JitIL::FallBackToInterpreter}, //"tlbie", OPTYPE_SYSTEM, 0}}, - {566, &JitIL::DoNothing}, //"tlbsync", OPTYPE_SYSTEM, 0}}, + // Unused instructions on GC + {310, &JitIL::FallBackToInterpreter}, //"eciwx", OPTYPE_INTEGER, FL_RC_BIT}}, + {438, &JitIL::FallBackToInterpreter}, //"ecowx", OPTYPE_INTEGER, FL_RC_BIT}}, + {854, &JitIL::DoNothing}, //"eieio", OPTYPE_INTEGER, FL_RC_BIT}}, + {306, &JitIL::FallBackToInterpreter}, //"tlbie", OPTYPE_SYSTEM, 0}}, + {566, &JitIL::DoNothing}, //"tlbsync", OPTYPE_SYSTEM, 0}}, }; -static GekkoOPTemplate table59[] = -{ - {18, &JitIL::FallBackToInterpreter}, //{"fdivsx", OPTYPE_FPU, FL_RC_BIT_F, 16}}, - {20, &JitIL::fp_arith_s}, //"fsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, - {21, &JitIL::fp_arith_s}, //"faddsx", OPTYPE_FPU, FL_RC_BIT_F}}, - {24, &JitIL::FallBackToInterpreter}, //"fresx", OPTYPE_FPU, FL_RC_BIT_F}}, - {25, &JitIL::fp_arith_s}, //"fmulsx", OPTYPE_FPU, FL_RC_BIT_F}}, - {28, &JitIL::fmaddXX}, //"fmsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, - {29, &JitIL::fmaddXX}, //"fmaddsx", OPTYPE_FPU, FL_RC_BIT_F}}, - {30, &JitIL::fmaddXX}, //"fnmsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, - {31, &JitIL::fmaddXX}, //"fnmaddsx", OPTYPE_FPU, FL_RC_BIT_F}}, +static GekkoOPTemplate table59[] = { + {18, &JitIL::FallBackToInterpreter}, //{"fdivsx", OPTYPE_FPU, FL_RC_BIT_F, 16}}, + {20, &JitIL::fp_arith_s}, //"fsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {21, &JitIL::fp_arith_s}, //"faddsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {24, &JitIL::FallBackToInterpreter}, //"fresx", OPTYPE_FPU, FL_RC_BIT_F}}, + {25, &JitIL::fp_arith_s}, //"fmulsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {28, &JitIL::fmaddXX}, //"fmsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {29, &JitIL::fmaddXX}, //"fmaddsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {30, &JitIL::fmaddXX}, //"fnmsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {31, &JitIL::fmaddXX}, //"fnmaddsx", OPTYPE_FPU, FL_RC_BIT_F}}, }; -static GekkoOPTemplate table63[] = -{ - {264, &JitIL::fsign}, //"fabsx", OPTYPE_FPU, FL_RC_BIT_F}}, - {32, &JitIL::fcmpX}, //"fcmpo", OPTYPE_FPU, FL_RC_BIT_F}}, - {0, &JitIL::fcmpX}, //"fcmpu", OPTYPE_FPU, FL_RC_BIT_F}}, - {14, &JitIL::FallBackToInterpreter}, //"fctiwx", OPTYPE_FPU, FL_RC_BIT_F}}, - {15, &JitIL::FallBackToInterpreter}, //"fctiwzx", OPTYPE_FPU, FL_RC_BIT_F}}, - {72, &JitIL::fmrx}, //"fmrx", OPTYPE_FPU, FL_RC_BIT_F}}, - {136, &JitIL::fsign}, //"fnabsx", OPTYPE_FPU, FL_RC_BIT_F}}, - {40, &JitIL::fsign}, //"fnegx", OPTYPE_FPU, FL_RC_BIT_F}}, - {12, &JitIL::FallBackToInterpreter}, //"frspx", OPTYPE_FPU, FL_RC_BIT_F}}, +static GekkoOPTemplate table63[] = { + {264, &JitIL::fsign}, //"fabsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {32, &JitIL::fcmpX}, //"fcmpo", OPTYPE_FPU, FL_RC_BIT_F}}, + {0, &JitIL::fcmpX}, //"fcmpu", OPTYPE_FPU, FL_RC_BIT_F}}, + {14, &JitIL::FallBackToInterpreter}, //"fctiwx", OPTYPE_FPU, FL_RC_BIT_F}}, + {15, &JitIL::FallBackToInterpreter}, //"fctiwzx", OPTYPE_FPU, FL_RC_BIT_F}}, + {72, &JitIL::fmrx}, //"fmrx", OPTYPE_FPU, FL_RC_BIT_F}}, + {136, &JitIL::fsign}, //"fnabsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {40, &JitIL::fsign}, //"fnegx", OPTYPE_FPU, FL_RC_BIT_F}}, + {12, &JitIL::FallBackToInterpreter}, //"frspx", OPTYPE_FPU, FL_RC_BIT_F}}, - {64, &JitIL::FallBackToInterpreter}, //"mcrfs", OPTYPE_SYSTEMFP, 0}}, - {583, &JitIL::FallBackToInterpreter}, //"mffsx", OPTYPE_SYSTEMFP, 0}}, - {70, &JitIL::FallBackToInterpreter}, //"mtfsb0x", OPTYPE_SYSTEMFP, 0, 2}}, - {38, &JitIL::FallBackToInterpreter}, //"mtfsb1x", OPTYPE_SYSTEMFP, 0, 2}}, - {134, &JitIL::FallBackToInterpreter}, //"mtfsfix", OPTYPE_SYSTEMFP, 0, 2}}, - {711, &JitIL::FallBackToInterpreter}, //"mtfsfx", OPTYPE_SYSTEMFP, 0, 2}}, + {64, &JitIL::FallBackToInterpreter}, //"mcrfs", OPTYPE_SYSTEMFP, 0}}, + {583, &JitIL::FallBackToInterpreter}, //"mffsx", OPTYPE_SYSTEMFP, 0}}, + {70, &JitIL::FallBackToInterpreter}, //"mtfsb0x", OPTYPE_SYSTEMFP, 0, 2}}, + {38, &JitIL::FallBackToInterpreter}, //"mtfsb1x", OPTYPE_SYSTEMFP, 0, 2}}, + {134, &JitIL::FallBackToInterpreter}, //"mtfsfix", OPTYPE_SYSTEMFP, 0, 2}}, + {711, &JitIL::FallBackToInterpreter}, //"mtfsfx", OPTYPE_SYSTEMFP, 0, 2}}, }; -static GekkoOPTemplate table63_2[] = -{ - {18, &JitIL::FallBackToInterpreter}, //"fdivx", OPTYPE_FPU, FL_RC_BIT_F, 30}}, - {20, &JitIL::FallBackToInterpreter}, //"fsubx", OPTYPE_FPU, FL_RC_BIT_F}}, - {21, &JitIL::FallBackToInterpreter}, //"faddx", OPTYPE_FPU, FL_RC_BIT_F}}, - {23, &JitIL::FallBackToInterpreter}, //"fselx", OPTYPE_FPU, FL_RC_BIT_F}}, - {25, &JitIL::fp_arith_s}, //"fmulx", OPTYPE_FPU, FL_RC_BIT_F}}, - {26, &JitIL::FallBackToInterpreter}, //"frsqrtex", OPTYPE_FPU, FL_RC_BIT_F}}, - {28, &JitIL::fmaddXX}, //"fmsubx", OPTYPE_FPU, FL_RC_BIT_F}}, - {29, &JitIL::fmaddXX}, //"fmaddx", OPTYPE_FPU, FL_RC_BIT_F}}, - {30, &JitIL::fmaddXX}, //"fnmsubx", OPTYPE_FPU, FL_RC_BIT_F}}, - {31, &JitIL::fmaddXX}, //"fnmaddx", OPTYPE_FPU, FL_RC_BIT_F}}, +static GekkoOPTemplate table63_2[] = { + {18, &JitIL::FallBackToInterpreter}, //"fdivx", OPTYPE_FPU, FL_RC_BIT_F, 30}}, + {20, &JitIL::FallBackToInterpreter}, //"fsubx", OPTYPE_FPU, FL_RC_BIT_F}}, + {21, &JitIL::FallBackToInterpreter}, //"faddx", OPTYPE_FPU, FL_RC_BIT_F}}, + {23, &JitIL::FallBackToInterpreter}, //"fselx", OPTYPE_FPU, FL_RC_BIT_F}}, + {25, &JitIL::fp_arith_s}, //"fmulx", OPTYPE_FPU, FL_RC_BIT_F}}, + {26, &JitIL::FallBackToInterpreter}, //"frsqrtex", OPTYPE_FPU, FL_RC_BIT_F}}, + {28, &JitIL::fmaddXX}, //"fmsubx", OPTYPE_FPU, FL_RC_BIT_F}}, + {29, &JitIL::fmaddXX}, //"fmaddx", OPTYPE_FPU, FL_RC_BIT_F}}, + {30, &JitIL::fmaddXX}, //"fnmsubx", OPTYPE_FPU, FL_RC_BIT_F}}, + {31, &JitIL::fmaddXX}, //"fnmaddx", OPTYPE_FPU, FL_RC_BIT_F}}, }; namespace JitILTables { - -void CompileInstruction(PPCAnalyst::CodeOp & op) +void CompileInstruction(PPCAnalyst::CodeOp& op) { - JitIL *jitil = (JitIL *)jit; - (jitil->*dynaOpTable[op.inst.OPCD])(op.inst); - GekkoOPInfo *info = op.opinfo; - if (info) - { + JitIL* jitil = (JitIL*)jit; + (jitil->*dynaOpTable[op.inst.OPCD])(op.inst); + GekkoOPInfo* info = op.opinfo; + if (info) + { #ifdef OPLOG - if (!strcmp(info->opname, OP_TO_LOG)) // "mcrfs" - { - rsplocations.push_back(jit.js.compilerPC); - } + if (!strcmp(info->opname, OP_TO_LOG)) // "mcrfs" + { + rsplocations.push_back(jit.js.compilerPC); + } #endif - info->compileCount++; - info->lastUse = jit->js.compilerPC; - } - else - { - PanicAlert("Tried to compile illegal (or unknown) instruction %08x, at %08x", op.inst.hex, jit->js.compilerPC); - } + info->compileCount++; + info->lastUse = jit->js.compilerPC; + } + else + { + PanicAlert("Tried to compile illegal (or unknown) instruction %08x, at %08x", op.inst.hex, + jit->js.compilerPC); + } } void InitTables() { - // once initialized, tables are read-only - static bool initialized = false; - if (initialized) - return; + // once initialized, tables are read-only + static bool initialized = false; + if (initialized) + return; - //clear - for (auto& tpl : dynaOpTable) - { - tpl = &JitIL::FallBackToInterpreter; - } + // clear + for (auto& tpl : dynaOpTable) + { + tpl = &JitIL::FallBackToInterpreter; + } - for (auto& tpl : dynaOpTable59) - { - tpl = &JitIL::FallBackToInterpreter; - } + for (auto& tpl : dynaOpTable59) + { + tpl = &JitIL::FallBackToInterpreter; + } - for (int i = 0; i < 1024; i++) - { - dynaOpTable4 [i] = &JitIL::FallBackToInterpreter; - dynaOpTable19[i] = &JitIL::FallBackToInterpreter; - dynaOpTable31[i] = &JitIL::FallBackToInterpreter; - dynaOpTable63[i] = &JitIL::FallBackToInterpreter; - } + for (int i = 0; i < 1024; i++) + { + dynaOpTable4[i] = &JitIL::FallBackToInterpreter; + dynaOpTable19[i] = &JitIL::FallBackToInterpreter; + dynaOpTable31[i] = &JitIL::FallBackToInterpreter; + dynaOpTable63[i] = &JitIL::FallBackToInterpreter; + } - for (auto& tpl : primarytable) - { - dynaOpTable[tpl.opcode] = tpl.Inst; - } + for (auto& tpl : primarytable) + { + dynaOpTable[tpl.opcode] = tpl.Inst; + } - for (int i = 0; i < 32; i++) - { - int fill = i << 5; - for (auto& tpl : table4_2) - { - int op = fill+tpl.opcode; - dynaOpTable4[op] = tpl.Inst; - } - } + for (int i = 0; i < 32; i++) + { + int fill = i << 5; + for (auto& tpl : table4_2) + { + int op = fill + tpl.opcode; + dynaOpTable4[op] = tpl.Inst; + } + } - for (int i = 0; i < 16; i++) - { - int fill = i << 6; - for (auto& tpl : table4_3) - { - int op = fill+tpl.opcode; - dynaOpTable4[op] = tpl.Inst; - } - } + for (int i = 0; i < 16; i++) + { + int fill = i << 6; + for (auto& tpl : table4_3) + { + int op = fill + tpl.opcode; + dynaOpTable4[op] = tpl.Inst; + } + } - for (auto& tpl : table4) - { - int op = tpl.opcode; - dynaOpTable4[op] = tpl.Inst; - } + for (auto& tpl : table4) + { + int op = tpl.opcode; + dynaOpTable4[op] = tpl.Inst; + } - for (auto& tpl : table31) - { - int op = tpl.opcode; - dynaOpTable31[op] = tpl.Inst; - } + for (auto& tpl : table31) + { + int op = tpl.opcode; + dynaOpTable31[op] = tpl.Inst; + } - for (auto& tpl : table19) - { - int op = tpl.opcode; - dynaOpTable19[op] = tpl.Inst; - } + for (auto& tpl : table19) + { + int op = tpl.opcode; + dynaOpTable19[op] = tpl.Inst; + } - for (auto& tpl : table59) - { - int op = tpl.opcode; - dynaOpTable59[op] = tpl.Inst; - } + for (auto& tpl : table59) + { + int op = tpl.opcode; + dynaOpTable59[op] = tpl.Inst; + } - for (auto& tpl : table63) - { - int op = tpl.opcode; - dynaOpTable63[op] = tpl.Inst; - } + for (auto& tpl : table63) + { + int op = tpl.opcode; + dynaOpTable63[op] = tpl.Inst; + } - for (int i = 0; i < 32; i++) - { - int fill = i << 5; - for (auto& tpl : table63_2) - { - int op = fill + tpl.opcode; - dynaOpTable63[op] = tpl.Inst; - } - } + for (int i = 0; i < 32; i++) + { + int fill = i << 5; + for (auto& tpl : table63_2) + { + int op = fill + tpl.opcode; + dynaOpTable63[op] = tpl.Inst; + } + } - initialized = true; + initialized = true; } - } diff --git a/Source/Core/Core/PowerPC/Jit64IL/JitIL_Tables.h b/Source/Core/Core/PowerPC/Jit64IL/JitIL_Tables.h index 79cf143a69..f207cd0680 100644 --- a/Source/Core/Core/PowerPC/Jit64IL/JitIL_Tables.h +++ b/Source/Core/Core/PowerPC/Jit64IL/JitIL_Tables.h @@ -4,10 +4,13 @@ #pragma once -namespace PPCAnalyst { struct CodeOp; } +namespace PPCAnalyst +{ +struct CodeOp; +} namespace JitILTables { - void CompileInstruction(PPCAnalyst::CodeOp& op); - void InitTables(); +void CompileInstruction(PPCAnalyst::CodeOp& op); +void InitTables(); } diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index a8795bb4ed..1139a8dfeb 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -6,633 +6,633 @@ #include "Common/Arm64Emitter.h" #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/MathUtil.h" #include "Common/PerformanceCounter.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/PatchEngine.h" #include "Core/HLE/HLE.h" #include "Core/HW/GPFifo.h" #include "Core/HW/Memmap.h" #include "Core/HW/ProcessorInterface.h" -#include "Core/PowerPC/JitInterface.h" -#include "Core/PowerPC/Profiler.h" +#include "Core/PatchEngine.h" #include "Core/PowerPC/JitArm64/Jit.h" #include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" #include "Core/PowerPC/JitArm64/JitArm64_Tables.h" +#include "Core/PowerPC/JitInterface.h" +#include "Core/PowerPC/Profiler.h" using namespace Arm64Gen; static const int AARCH64_FARCODE_SIZE = 1024 * 1024 * 16; static bool HasCycleCounters() { - // Bit needs to be set to support cycle counters - const u32 PMUSERENR_CR = 0x4; - u32 reg; - asm ("mrs %[val], PMUSERENR_EL0" - : [val] "=r" (reg)); - return !!(reg & PMUSERENR_CR); + // Bit needs to be set to support cycle counters + const u32 PMUSERENR_CR = 0x4; + u32 reg; + asm("mrs %[val], PMUSERENR_EL0" : [val] "=r"(reg)); + return !!(reg & PMUSERENR_CR); } void JitArm64::Init() { - size_t child_code_size = SConfig::GetInstance().bMMU ? FARCODE_SIZE_MMU : AARCH64_FARCODE_SIZE; - AllocCodeSpace(CODE_SIZE + child_code_size); - AddChildCodeSpace(&farcode, child_code_size); - jo.enableBlocklink = true; - jo.optimizeGatherPipe = true; - UpdateMemoryOptions(); - gpr.Init(this); - fpr.Init(this); + size_t child_code_size = SConfig::GetInstance().bMMU ? FARCODE_SIZE_MMU : AARCH64_FARCODE_SIZE; + AllocCodeSpace(CODE_SIZE + child_code_size); + AddChildCodeSpace(&farcode, child_code_size); + jo.enableBlocklink = true; + jo.optimizeGatherPipe = true; + UpdateMemoryOptions(); + gpr.Init(this); + fpr.Init(this); - blocks.Init(); - GenerateAsm(); + blocks.Init(); + GenerateAsm(); - code_block.m_stats = &js.st; - code_block.m_gpa = &js.gpa; - code_block.m_fpa = &js.fpa; - analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE); + code_block.m_stats = &js.st; + code_block.m_gpa = &js.gpa; + code_block.m_fpa = &js.fpa; + analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE); - m_supports_cycle_counter = HasCycleCounters(); + m_supports_cycle_counter = HasCycleCounters(); } void JitArm64::ClearCache() { - m_fault_to_handler.clear(); - m_handler_to_loc.clear(); + m_fault_to_handler.clear(); + m_handler_to_loc.clear(); - blocks.Clear(); - ClearCodeSpace(); - farcode.ClearCodeSpace(); - UpdateMemoryOptions(); + blocks.Clear(); + ClearCodeSpace(); + farcode.ClearCodeSpace(); + UpdateMemoryOptions(); - GenerateAsm(); + GenerateAsm(); } void JitArm64::Shutdown() { - FreeCodeSpace(); - blocks.Shutdown(); + FreeCodeSpace(); + blocks.Shutdown(); } void JitArm64::FallBackToInterpreter(UGeckoInstruction inst) { - gpr.Flush(FlushMode::FLUSH_ALL, js.op); - fpr.Flush(FlushMode::FLUSH_ALL, js.op); + gpr.Flush(FlushMode::FLUSH_ALL, js.op); + fpr.Flush(FlushMode::FLUSH_ALL, js.op); - if (js.op->opinfo->flags & FL_ENDBLOCK) - { - // also flush the program counter - ARM64Reg WA = gpr.GetReg(); - MOVI2R(WA, js.compilerPC); - STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(pc)); - ADD(WA, WA, 4); - STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(npc)); - gpr.Unlock(WA); - } + if (js.op->opinfo->flags & FL_ENDBLOCK) + { + // also flush the program counter + ARM64Reg WA = gpr.GetReg(); + MOVI2R(WA, js.compilerPC); + STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(pc)); + ADD(WA, WA, 4); + STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(npc)); + gpr.Unlock(WA); + } - Interpreter::Instruction instr = GetInterpreterOp(inst); - MOVI2R(W0, inst.hex); - MOVI2R(X30, (u64)instr); - BLR(X30); + Interpreter::Instruction instr = GetInterpreterOp(inst); + MOVI2R(W0, inst.hex); + MOVI2R(X30, (u64)instr); + BLR(X30); - if (js.op->opinfo->flags & FL_ENDBLOCK) - { - if (js.isLastInstruction) - { - ARM64Reg WA = gpr.GetReg(); - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(npc)); - WriteExceptionExit(WA); - } - else - { - // only exit if ppcstate.npc was changed - ARM64Reg WA = gpr.GetReg(); - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(npc)); - ARM64Reg WB = gpr.GetReg(); - MOVI2R(WB, js.compilerPC + 4); - CMP(WB, WA); - gpr.Unlock(WB); - FixupBranch c = B(CC_EQ); - WriteExceptionExit(WA); - SetJumpTarget(c); - } - } + if (js.op->opinfo->flags & FL_ENDBLOCK) + { + if (js.isLastInstruction) + { + ARM64Reg WA = gpr.GetReg(); + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(npc)); + WriteExceptionExit(WA); + } + else + { + // only exit if ppcstate.npc was changed + ARM64Reg WA = gpr.GetReg(); + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(npc)); + ARM64Reg WB = gpr.GetReg(); + MOVI2R(WB, js.compilerPC + 4); + CMP(WB, WA); + gpr.Unlock(WB); + FixupBranch c = B(CC_EQ); + WriteExceptionExit(WA); + SetJumpTarget(c); + } + } } void JitArm64::HLEFunction(UGeckoInstruction inst) { - gpr.Flush(FlushMode::FLUSH_ALL); - fpr.Flush(FlushMode::FLUSH_ALL); + gpr.Flush(FlushMode::FLUSH_ALL); + fpr.Flush(FlushMode::FLUSH_ALL); - MOVI2R(W0, js.compilerPC); - MOVI2R(W1, inst.hex); - MOVI2R(X30, (u64)&HLE::Execute); - BLR(X30); + MOVI2R(W0, js.compilerPC); + MOVI2R(W1, inst.hex); + MOVI2R(X30, (u64)&HLE::Execute); + BLR(X30); - ARM64Reg WA = gpr.GetReg(); - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(npc)); - WriteExit(WA); + ARM64Reg WA = gpr.GetReg(); + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(npc)); + WriteExit(WA); } void JitArm64::DoNothing(UGeckoInstruction inst) { - // Yup, just don't do anything. + // Yup, just don't do anything. } void JitArm64::Break(UGeckoInstruction inst) { - WARN_LOG(DYNA_REC, "Breaking! %08x - Fix me ;)", inst.hex); - exit(0); + WARN_LOG(DYNA_REC, "Breaking! %08x - Fix me ;)", inst.hex); + exit(0); } void JitArm64::Cleanup() { - if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0) - { - gpr.Lock(W0); - MOVI2R(X0, (u64)&GPFifo::FastCheckGatherPipe); - BLR(X0); - gpr.Unlock(W0); - } + if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0) + { + gpr.Lock(W0); + MOVI2R(X0, (u64)&GPFifo::FastCheckGatherPipe); + BLR(X0); + gpr.Unlock(W0); + } } void JitArm64::DoDownCount() { - ARM64Reg WA = gpr.GetReg(); - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(downcount)); - if (js.downcountAmount < 4096) // We can enlarge this if we used rotations - { - SUBS(WA, WA, js.downcountAmount); - STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(downcount)); - } - else - { - ARM64Reg WB = gpr.GetReg(); - MOVI2R(WB, js.downcountAmount); - SUBS(WA, WA, WB); - STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(downcount)); - gpr.Unlock(WB); - } - gpr.Unlock(WA); + ARM64Reg WA = gpr.GetReg(); + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(downcount)); + if (js.downcountAmount < 4096) // We can enlarge this if we used rotations + { + SUBS(WA, WA, js.downcountAmount); + STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(downcount)); + } + else + { + ARM64Reg WB = gpr.GetReg(); + MOVI2R(WB, js.downcountAmount); + SUBS(WA, WA, WB); + STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(downcount)); + gpr.Unlock(WB); + } + gpr.Unlock(WA); } // Exits void JitArm64::WriteExit(u32 destination) { - Cleanup(); - DoDownCount(); + Cleanup(); + DoDownCount(); - if (Profiler::g_ProfileBlocks) - EndTimeProfile(js.curBlock); + if (Profiler::g_ProfileBlocks) + EndTimeProfile(js.curBlock); - //If nobody has taken care of this yet (this can be removed when all branches are done) - JitBlock *b = js.curBlock; - JitBlock::LinkData linkData; - linkData.exitAddress = destination; - linkData.exitPtrs = GetWritableCodePtr(); - linkData.linkStatus = false; - b->linkData.push_back(linkData); + // If nobody has taken care of this yet (this can be removed when all branches are done) + JitBlock* b = js.curBlock; + JitBlock::LinkData linkData; + linkData.exitAddress = destination; + linkData.exitPtrs = GetWritableCodePtr(); + linkData.linkStatus = false; + b->linkData.push_back(linkData); - // the code generated in JitArm64BlockCache::WriteDestroyBlock must fit in this block - MOVI2R(DISPATCHER_PC, destination); - B(dispatcher); + // the code generated in JitArm64BlockCache::WriteDestroyBlock must fit in this block + MOVI2R(DISPATCHER_PC, destination); + B(dispatcher); } void JitArm64::WriteExit(ARM64Reg Reg) { - Cleanup(); - DoDownCount(); + Cleanup(); + DoDownCount(); - if (Reg != DISPATCHER_PC) - MOV(DISPATCHER_PC, Reg); - gpr.Unlock(Reg); + if (Reg != DISPATCHER_PC) + MOV(DISPATCHER_PC, Reg); + gpr.Unlock(Reg); - if (Profiler::g_ProfileBlocks) - EndTimeProfile(js.curBlock); + if (Profiler::g_ProfileBlocks) + EndTimeProfile(js.curBlock); - B(dispatcher); + B(dispatcher); } void JitArm64::WriteExceptionExit(u32 destination, bool only_external) { - Cleanup(); - DoDownCount(); + Cleanup(); + DoDownCount(); - LDR(INDEX_UNSIGNED, W30, PPC_REG, PPCSTATE_OFF(Exceptions)); - MOVI2R(DISPATCHER_PC, destination); - FixupBranch no_exceptions = CBZ(W30); + LDR(INDEX_UNSIGNED, W30, PPC_REG, PPCSTATE_OFF(Exceptions)); + MOVI2R(DISPATCHER_PC, destination); + FixupBranch no_exceptions = CBZ(W30); - STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); - STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(npc)); - if (only_external) - MOVI2R(X30, (u64)&PowerPC::CheckExternalExceptions); - else - MOVI2R(X30, (u64)&PowerPC::CheckExceptions); - BLR(X30); - LDR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(npc)); + STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); + STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(npc)); + if (only_external) + MOVI2R(X30, (u64)&PowerPC::CheckExternalExceptions); + else + MOVI2R(X30, (u64)&PowerPC::CheckExceptions); + BLR(X30); + LDR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(npc)); - SetJumpTarget(no_exceptions); + SetJumpTarget(no_exceptions); - if (Profiler::g_ProfileBlocks) - EndTimeProfile(js.curBlock); + if (Profiler::g_ProfileBlocks) + EndTimeProfile(js.curBlock); - B(dispatcher); + B(dispatcher); } void JitArm64::WriteExceptionExit(ARM64Reg dest, bool only_external) { - Cleanup(); - DoDownCount(); + Cleanup(); + DoDownCount(); - ARM64Reg WA = gpr.GetReg(); - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); - FixupBranch no_exceptions = CBZ(WA); - gpr.Unlock(WA); + ARM64Reg WA = gpr.GetReg(); + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); + FixupBranch no_exceptions = CBZ(WA); + gpr.Unlock(WA); - STR(INDEX_UNSIGNED, dest, PPC_REG, PPCSTATE_OFF(pc)); - STR(INDEX_UNSIGNED, dest, PPC_REG, PPCSTATE_OFF(npc)); - if (only_external) - MOVI2R(EncodeRegTo64(dest), (u64)&PowerPC::CheckExternalExceptions); - else - MOVI2R(EncodeRegTo64(dest), (u64)&PowerPC::CheckExceptions); - BLR(EncodeRegTo64(dest)); - LDR(INDEX_UNSIGNED, dest, PPC_REG, PPCSTATE_OFF(npc)); + STR(INDEX_UNSIGNED, dest, PPC_REG, PPCSTATE_OFF(pc)); + STR(INDEX_UNSIGNED, dest, PPC_REG, PPCSTATE_OFF(npc)); + if (only_external) + MOVI2R(EncodeRegTo64(dest), (u64)&PowerPC::CheckExternalExceptions); + else + MOVI2R(EncodeRegTo64(dest), (u64)&PowerPC::CheckExceptions); + BLR(EncodeRegTo64(dest)); + LDR(INDEX_UNSIGNED, dest, PPC_REG, PPCSTATE_OFF(npc)); - SetJumpTarget(no_exceptions); + SetJumpTarget(no_exceptions); - if (dest != DISPATCHER_PC) - MOV(DISPATCHER_PC, dest); - gpr.Unlock(dest); + if (dest != DISPATCHER_PC) + MOV(DISPATCHER_PC, dest); + gpr.Unlock(dest); - if (Profiler::g_ProfileBlocks) - EndTimeProfile(js.curBlock); + if (Profiler::g_ProfileBlocks) + EndTimeProfile(js.curBlock); - B(dispatcher); + B(dispatcher); } void JitArm64::DumpCode(const u8* start, const u8* end) { - std::string output = ""; - for (u8* code = (u8*)start; code < end; code += 4) - output += StringFromFormat("%08x", Common::swap32(*(u32*)code)); - WARN_LOG(DYNA_REC, "Code dump from %p to %p:\n%s", start, end, output.c_str()); + std::string output = ""; + for (u8* code = (u8*)start; code < end; code += 4) + output += StringFromFormat("%08x", Common::swap32(*(u32*)code)); + WARN_LOG(DYNA_REC, "Code dump from %p to %p:\n%s", start, end, output.c_str()); } void JitArm64::EmitResetCycleCounters() { - const u32 PMCR_EL0_E = 1; - const u32 PMCR_EL0_P = 2; - const u32 PMCR_EL0_C = 4; - const u32 PMCR_EL0_LC = 0x40; - _MSR(FIELD_PMCR_EL0, X0); - MOVI2R(X1, PMCR_EL0_E | - PMCR_EL0_P | - PMCR_EL0_C | - PMCR_EL0_LC); - ORR(X0, X0, X1); - MRS(X0, FIELD_PMCR_EL0); + const u32 PMCR_EL0_E = 1; + const u32 PMCR_EL0_P = 2; + const u32 PMCR_EL0_C = 4; + const u32 PMCR_EL0_LC = 0x40; + _MSR(FIELD_PMCR_EL0, X0); + MOVI2R(X1, PMCR_EL0_E | PMCR_EL0_P | PMCR_EL0_C | PMCR_EL0_LC); + ORR(X0, X0, X1); + MRS(X0, FIELD_PMCR_EL0); } void JitArm64::EmitGetCycles(Arm64Gen::ARM64Reg reg) { - _MSR(FIELD_PMCCNTR_EL0, reg); + _MSR(FIELD_PMCCNTR_EL0, reg); } void JitArm64::BeginTimeProfile(JitBlock* b) { - b->ticCounter = 0; - b->ticStart = 0; - b->ticStop = 0; + b->ticCounter = 0; + b->ticStart = 0; + b->ticStop = 0; - if (m_supports_cycle_counter) - { - EmitResetCycleCounters(); - EmitGetCycles(X1); - MOVI2R(X0, (u64)&b->ticStart); - STR(INDEX_UNSIGNED, X1, X0, 0); - } - else - { - MOVI2R(X1, (u64)QueryPerformanceCounter); - MOVI2R(X0, (u64)&b->ticStart); - BLR(X1); - } + if (m_supports_cycle_counter) + { + EmitResetCycleCounters(); + EmitGetCycles(X1); + MOVI2R(X0, (u64)&b->ticStart); + STR(INDEX_UNSIGNED, X1, X0, 0); + } + else + { + MOVI2R(X1, (u64)QueryPerformanceCounter); + MOVI2R(X0, (u64)&b->ticStart); + BLR(X1); + } } void JitArm64::EndTimeProfile(JitBlock* b) { - if (m_supports_cycle_counter) - { - EmitGetCycles(X2); - MOVI2R(X0, (u64)&b->ticStart); - } - else - { - MOVI2R(X1, (u64)QueryPerformanceCounter); - MOVI2R(X0, (u64)&b->ticStop); - BLR(X1); + if (m_supports_cycle_counter) + { + EmitGetCycles(X2); + MOVI2R(X0, (u64)&b->ticStart); + } + else + { + MOVI2R(X1, (u64)QueryPerformanceCounter); + MOVI2R(X0, (u64)&b->ticStop); + BLR(X1); - MOVI2R(X0, (u64)&b->ticStart); - LDR(INDEX_UNSIGNED, X2, X0, 8); // Stop - } + MOVI2R(X0, (u64)&b->ticStart); + LDR(INDEX_UNSIGNED, X2, X0, 8); // Stop + } - LDR(INDEX_UNSIGNED, X1, X0, 0); // Start - LDR(INDEX_UNSIGNED, X3, X0, 16); // Counter - SUB(X2, X2, X1); - ADD(X3, X3, X2); - STR(INDEX_UNSIGNED, X3, X0, 16); + LDR(INDEX_UNSIGNED, X1, X0, 0); // Start + LDR(INDEX_UNSIGNED, X3, X0, 16); // Counter + SUB(X2, X2, X1); + ADD(X3, X3, X2); + STR(INDEX_UNSIGNED, X3, X0, 16); } void JitArm64::Run() { - CompiledCode pExecAddr = (CompiledCode)enterCode; - pExecAddr(); + CompiledCode pExecAddr = (CompiledCode)enterCode; + pExecAddr(); } void JitArm64::SingleStep() { - CompiledCode pExecAddr = (CompiledCode)enterCode; - pExecAddr(); + CompiledCode pExecAddr = (CompiledCode)enterCode; + pExecAddr(); } void JitArm64::Jit(u32) { - if (IsAlmostFull() || farcode.IsAlmostFull() || blocks.IsFull() || SConfig::GetInstance().bJITNoBlockCache) - { - ClearCache(); - } + if (IsAlmostFull() || farcode.IsAlmostFull() || blocks.IsFull() || + SConfig::GetInstance().bJITNoBlockCache) + { + ClearCache(); + } - int blockSize = code_buffer.GetSize(); - u32 em_address = PowerPC::ppcState.pc; + int blockSize = code_buffer.GetSize(); + u32 em_address = PowerPC::ppcState.pc; - if (SConfig::GetInstance().bEnableDebugging) - { - // Comment out the following to disable breakpoints (speed-up) - blockSize = 1; - } + if (SConfig::GetInstance().bEnableDebugging) + { + // Comment out the following to disable breakpoints (speed-up) + blockSize = 1; + } - // Analyze the block, collect all instructions it is made of (including inlining, - // if that is enabled), reorder instructions for optimal performance, and join joinable instructions. - u32 nextPC = analyzer.Analyze(em_address, &code_block, &code_buffer, blockSize); + // Analyze the block, collect all instructions it is made of (including inlining, + // if that is enabled), reorder instructions for optimal performance, and join joinable + // instructions. + u32 nextPC = analyzer.Analyze(em_address, &code_block, &code_buffer, blockSize); - if (code_block.m_memory_exception) - { - // Address of instruction could not be translated - NPC = nextPC; - PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; - PowerPC::CheckExceptions(); - WARN_LOG(POWERPC, "ISI exception at 0x%08x", nextPC); - return; - } + if (code_block.m_memory_exception) + { + // Address of instruction could not be translated + NPC = nextPC; + PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; + PowerPC::CheckExceptions(); + WARN_LOG(POWERPC, "ISI exception at 0x%08x", nextPC); + return; + } - int block_num = blocks.AllocateBlock(em_address); - JitBlock *b = blocks.GetBlock(block_num); - const u8* BlockPtr = DoJit(em_address, &code_buffer, b, nextPC); - blocks.FinalizeBlock(block_num, jo.enableBlocklink, BlockPtr); + int block_num = blocks.AllocateBlock(em_address); + JitBlock* b = blocks.GetBlock(block_num); + const u8* BlockPtr = DoJit(em_address, &code_buffer, b, nextPC); + blocks.FinalizeBlock(block_num, jo.enableBlocklink, BlockPtr); } -const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b, u32 nextPC) +const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBlock* b, u32 nextPC) { - if (em_address == 0) - { - Core::SetState(Core::CORE_PAUSE); - WARN_LOG(DYNA_REC, "ERROR: Compiling at 0. LR=%08x CTR=%08x", LR, CTR); - } + if (em_address == 0) + { + Core::SetState(Core::CORE_PAUSE); + WARN_LOG(DYNA_REC, "ERROR: Compiling at 0. LR=%08x CTR=%08x", LR, CTR); + } - js.isLastInstruction = false; - js.firstFPInstructionFound = false; - js.assumeNoPairedQuantize = false; - js.blockStart = em_address; - js.fifoBytesThisBlock = 0; - js.downcountAmount = 0; - js.skipInstructions = 0; - js.curBlock = b; + js.isLastInstruction = false; + js.firstFPInstructionFound = false; + js.assumeNoPairedQuantize = false; + js.blockStart = em_address; + js.fifoBytesThisBlock = 0; + js.downcountAmount = 0; + js.skipInstructions = 0; + js.curBlock = b; - PPCAnalyst::CodeOp *ops = code_buf->codebuffer; + PPCAnalyst::CodeOp* ops = code_buf->codebuffer; - const u8 *start = GetCodePtr(); - b->checkedEntry = start; - b->runCount = 0; + const u8* start = GetCodePtr(); + b->checkedEntry = start; + b->runCount = 0; - // Downcount flag check, Only valid for linked blocks - { - FixupBranch bail = B(CC_PL); - MOVI2R(DISPATCHER_PC, js.blockStart); - B(doTiming); - SetJumpTarget(bail); - } + // Downcount flag check, Only valid for linked blocks + { + FixupBranch bail = B(CC_PL); + MOVI2R(DISPATCHER_PC, js.blockStart); + B(doTiming); + SetJumpTarget(bail); + } - // Normal entry doesn't need to check for downcount. - b->normalEntry = GetCodePtr(); + // Normal entry doesn't need to check for downcount. + b->normalEntry = GetCodePtr(); - // Conditionally add profiling code. - if (Profiler::g_ProfileBlocks) - { - ARM64Reg WA = gpr.GetReg(); - ARM64Reg WB = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); - ARM64Reg XB = EncodeRegTo64(WB); - MOVI2R(XA, (u64)&b->runCount); - LDR(INDEX_UNSIGNED, XB, XA, 0); - ADD(XB, XB, 1); - STR(INDEX_UNSIGNED, XB, XA, 0); - gpr.Unlock(WA, WB); - // get start tic - BeginTimeProfile(b); - } + // Conditionally add profiling code. + if (Profiler::g_ProfileBlocks) + { + ARM64Reg WA = gpr.GetReg(); + ARM64Reg WB = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); + ARM64Reg XB = EncodeRegTo64(WB); + MOVI2R(XA, (u64)&b->runCount); + LDR(INDEX_UNSIGNED, XB, XA, 0); + ADD(XB, XB, 1); + STR(INDEX_UNSIGNED, XB, XA, 0); + gpr.Unlock(WA, WB); + // get start tic + BeginTimeProfile(b); + } - if (code_block.m_gqr_used.Count() == 1 && js.pairedQuantizeAddresses.find(js.blockStart) == js.pairedQuantizeAddresses.end()) - { - int gqr = *code_block.m_gqr_used.begin(); - if (!code_block.m_gqr_modified[gqr] && !GQR(gqr)) - { - LDR(INDEX_UNSIGNED, W0, PPC_REG, PPCSTATE_OFF(spr[SPR_GQR0]) + gqr * 4); - FixupBranch no_fail = CBZ(W0); - FixupBranch fail = B(); - SwitchToFarCode(); - SetJumpTarget(fail); - MOVI2R(DISPATCHER_PC, js.blockStart); - STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); - MOVI2R(W0, (u32)JitInterface::ExceptionType::EXCEPTIONS_PAIRED_QUANTIZE); - MOVI2R(X1, (u64)&JitInterface::CompileExceptionCheck); - BLR(X1); - B(dispatcher); - SwitchToNearCode(); - SetJumpTarget(no_fail); - js.assumeNoPairedQuantize = true; - } - } + if (code_block.m_gqr_used.Count() == 1 && + js.pairedQuantizeAddresses.find(js.blockStart) == js.pairedQuantizeAddresses.end()) + { + int gqr = *code_block.m_gqr_used.begin(); + if (!code_block.m_gqr_modified[gqr] && !GQR(gqr)) + { + LDR(INDEX_UNSIGNED, W0, PPC_REG, PPCSTATE_OFF(spr[SPR_GQR0]) + gqr * 4); + FixupBranch no_fail = CBZ(W0); + FixupBranch fail = B(); + SwitchToFarCode(); + SetJumpTarget(fail); + MOVI2R(DISPATCHER_PC, js.blockStart); + STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); + MOVI2R(W0, (u32)JitInterface::ExceptionType::EXCEPTIONS_PAIRED_QUANTIZE); + MOVI2R(X1, (u64)&JitInterface::CompileExceptionCheck); + BLR(X1); + B(dispatcher); + SwitchToNearCode(); + SetJumpTarget(no_fail); + js.assumeNoPairedQuantize = true; + } + } - gpr.Start(js.gpa); - fpr.Start(js.fpa); + gpr.Start(js.gpa); + fpr.Start(js.fpa); - if (!SConfig::GetInstance().bEnableDebugging) - js.downcountAmount += PatchEngine::GetSpeedhackCycles(em_address); + if (!SConfig::GetInstance().bEnableDebugging) + js.downcountAmount += PatchEngine::GetSpeedhackCycles(em_address); - // Translate instructions - for (u32 i = 0; i < code_block.m_num_instructions; i++) - { - js.compilerPC = ops[i].address; - js.op = &ops[i]; - js.instructionNumber = i; - js.instructionsLeft = (code_block.m_num_instructions - 1) - i; - const GekkoOPInfo *opinfo = ops[i].opinfo; - js.downcountAmount += opinfo->numCycles; + // Translate instructions + for (u32 i = 0; i < code_block.m_num_instructions; i++) + { + js.compilerPC = ops[i].address; + js.op = &ops[i]; + js.instructionNumber = i; + js.instructionsLeft = (code_block.m_num_instructions - 1) - i; + const GekkoOPInfo* opinfo = ops[i].opinfo; + js.downcountAmount += opinfo->numCycles; - if (i == (code_block.m_num_instructions - 1)) - { - // WARNING - cmp->branch merging will screw this up. - js.isLastInstruction = true; - } + if (i == (code_block.m_num_instructions - 1)) + { + // WARNING - cmp->branch merging will screw this up. + js.isLastInstruction = true; + } - // Gather pipe writes using a non-immediate address are discovered by profiling. - bool gatherPipeIntCheck = jit->js.fifoWriteAddresses.find(ops[i].address) != jit->js.fifoWriteAddresses.end(); + // Gather pipe writes using a non-immediate address are discovered by profiling. + bool gatherPipeIntCheck = + jit->js.fifoWriteAddresses.find(ops[i].address) != jit->js.fifoWriteAddresses.end(); - if (jo.optimizeGatherPipe && js.fifoBytesThisBlock >= 32) - { - js.fifoBytesThisBlock -= 32; + if (jo.optimizeGatherPipe && js.fifoBytesThisBlock >= 32) + { + js.fifoBytesThisBlock -= 32; - gpr.Lock(W30); - BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); - regs_in_use[W30] = 0; + gpr.Lock(W30); + BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); + regs_in_use[W30] = 0; - FixupBranch Exception = B(); - SwitchToFarCode(); - const u8* done_here = GetCodePtr(); - FixupBranch exit = B(); - SetJumpTarget(Exception); - ABI_PushRegisters(regs_in_use); - MOVI2R(X30, (u64)&GPFifo::FastCheckGatherPipe); - BLR(X30); - ABI_PopRegisters(regs_in_use); + FixupBranch Exception = B(); + SwitchToFarCode(); + const u8* done_here = GetCodePtr(); + FixupBranch exit = B(); + SetJumpTarget(Exception); + ABI_PushRegisters(regs_in_use); + MOVI2R(X30, (u64)&GPFifo::FastCheckGatherPipe); + BLR(X30); + ABI_PopRegisters(regs_in_use); - // Inline exception check - LDR(INDEX_UNSIGNED, W30, PPC_REG, PPCSTATE_OFF(Exceptions)); - TBZ(W30, 3, done_here); // EXCEPTION_EXTERNAL_INT - LDR(INDEX_UNSIGNED, W30, PPC_REG, PPCSTATE_OFF(msr)); - TBZ(W30, 11, done_here); - MOVI2R(X30, (u64)&ProcessorInterface::m_InterruptCause); - LDR(INDEX_UNSIGNED, W30, X30, 0); - TST(W30, 23, 2); - B(CC_EQ, done_here); + // Inline exception check + LDR(INDEX_UNSIGNED, W30, PPC_REG, PPCSTATE_OFF(Exceptions)); + TBZ(W30, 3, done_here); // EXCEPTION_EXTERNAL_INT + LDR(INDEX_UNSIGNED, W30, PPC_REG, PPCSTATE_OFF(msr)); + TBZ(W30, 11, done_here); + MOVI2R(X30, (u64)&ProcessorInterface::m_InterruptCause); + LDR(INDEX_UNSIGNED, W30, X30, 0); + TST(W30, 23, 2); + B(CC_EQ, done_here); - gpr.Flush(FLUSH_MAINTAIN_STATE); - fpr.Flush(FLUSH_MAINTAIN_STATE); - WriteExceptionExit(js.compilerPC, true); - SwitchToNearCode(); - SetJumpTarget(exit); - gpr.Unlock(W30); + gpr.Flush(FLUSH_MAINTAIN_STATE); + fpr.Flush(FLUSH_MAINTAIN_STATE); + WriteExceptionExit(js.compilerPC, true); + SwitchToNearCode(); + SetJumpTarget(exit); + gpr.Unlock(W30); - // So we don't check exceptions twice - gatherPipeIntCheck = false; - } - // Gather pipe writes can generate an exception; add an exception check. - // TODO: This doesn't really match hardware; the CP interrupt is - // asynchronous. - if (jo.optimizeGatherPipe && gatherPipeIntCheck) - { - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); - FixupBranch NoExtException = TBZ(WA, 3); // EXCEPTION_EXTERNAL_INT - FixupBranch Exception = B(); - SwitchToFarCode(); - const u8* done_here = GetCodePtr(); - FixupBranch exit = B(); - SetJumpTarget(Exception); - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(msr)); - TBZ(WA, 11, done_here); - MOVI2R(XA, (u64)&ProcessorInterface::m_InterruptCause); - LDR(INDEX_UNSIGNED, WA, XA, 0); - TST(WA, 23, 2); - B(CC_EQ, done_here); - gpr.Unlock(WA); + // So we don't check exceptions twice + gatherPipeIntCheck = false; + } + // Gather pipe writes can generate an exception; add an exception check. + // TODO: This doesn't really match hardware; the CP interrupt is + // asynchronous. + if (jo.optimizeGatherPipe && gatherPipeIntCheck) + { + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); + FixupBranch NoExtException = TBZ(WA, 3); // EXCEPTION_EXTERNAL_INT + FixupBranch Exception = B(); + SwitchToFarCode(); + const u8* done_here = GetCodePtr(); + FixupBranch exit = B(); + SetJumpTarget(Exception); + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(msr)); + TBZ(WA, 11, done_here); + MOVI2R(XA, (u64)&ProcessorInterface::m_InterruptCause); + LDR(INDEX_UNSIGNED, WA, XA, 0); + TST(WA, 23, 2); + B(CC_EQ, done_here); + gpr.Unlock(WA); - gpr.Flush(FLUSH_MAINTAIN_STATE); - fpr.Flush(FLUSH_MAINTAIN_STATE); - WriteExceptionExit(js.compilerPC, true); - SwitchToNearCode(); - SetJumpTarget(NoExtException); - SetJumpTarget(exit); - } + gpr.Flush(FLUSH_MAINTAIN_STATE); + fpr.Flush(FLUSH_MAINTAIN_STATE); + WriteExceptionExit(js.compilerPC, true); + SwitchToNearCode(); + SetJumpTarget(NoExtException); + SetJumpTarget(exit); + } - if (!ops[i].skip) - { - if ((opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound) - { - //This instruction uses FPU - needs to add FP exception bailout - ARM64Reg WA = gpr.GetReg(); - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(msr)); - FixupBranch b1 = TBNZ(WA, 13); // Test FP enabled bit + if (!ops[i].skip) + { + if ((opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound) + { + // This instruction uses FPU - needs to add FP exception bailout + ARM64Reg WA = gpr.GetReg(); + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(msr)); + FixupBranch b1 = TBNZ(WA, 13); // Test FP enabled bit - FixupBranch far = B(); - SwitchToFarCode(); - SetJumpTarget(far); + FixupBranch far = B(); + SwitchToFarCode(); + SetJumpTarget(far); - gpr.Flush(FLUSH_MAINTAIN_STATE); - fpr.Flush(FLUSH_MAINTAIN_STATE); + gpr.Flush(FLUSH_MAINTAIN_STATE); + fpr.Flush(FLUSH_MAINTAIN_STATE); - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); - ORR(WA, WA, 26, 0); // EXCEPTION_FPU_UNAVAILABLE - STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); + ORR(WA, WA, 26, 0); // EXCEPTION_FPU_UNAVAILABLE + STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); - gpr.Unlock(WA); + gpr.Unlock(WA); - WriteExceptionExit(js.compilerPC); + WriteExceptionExit(js.compilerPC); - SwitchToNearCode(); + SwitchToNearCode(); - SetJumpTarget(b1); + SetJumpTarget(b1); - js.firstFPInstructionFound = true; - } + js.firstFPInstructionFound = true; + } - JitArm64Tables::CompileInstruction(ops[i]); + JitArm64Tables::CompileInstruction(ops[i]); - // If we have a register that will never be used again, flush it. - gpr.StoreRegisters(~ops[i].gprInUse); - fpr.StoreRegisters(~ops[i].fprInUse); + // If we have a register that will never be used again, flush it. + gpr.StoreRegisters(~ops[i].gprInUse); + fpr.StoreRegisters(~ops[i].fprInUse); - if (jo.memcheck && (opinfo->flags & FL_LOADSTORE)) - { - ARM64Reg WA = gpr.GetReg(); - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); - FixupBranch noException = TBZ(WA, IntLog2(EXCEPTION_DSI)); + if (jo.memcheck && (opinfo->flags & FL_LOADSTORE)) + { + ARM64Reg WA = gpr.GetReg(); + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); + FixupBranch noException = TBZ(WA, IntLog2(EXCEPTION_DSI)); - FixupBranch handleException = B(); - SwitchToFarCode(); - SetJumpTarget(handleException); + FixupBranch handleException = B(); + SwitchToFarCode(); + SetJumpTarget(handleException); - gpr.Flush(FLUSH_MAINTAIN_STATE); - fpr.Flush(FLUSH_MAINTAIN_STATE); + gpr.Flush(FLUSH_MAINTAIN_STATE); + fpr.Flush(FLUSH_MAINTAIN_STATE); - WriteExceptionExit(js.compilerPC); + WriteExceptionExit(js.compilerPC); - SwitchToNearCode(); - SetJumpTarget(noException); - gpr.Unlock(WA); - } - } + SwitchToNearCode(); + SetJumpTarget(noException); + gpr.Unlock(WA); + } + } - i += js.skipInstructions; - js.skipInstructions = 0; - } + i += js.skipInstructions; + js.skipInstructions = 0; + } - if (code_block.m_broken) - { - gpr.Flush(FLUSH_ALL); - fpr.Flush(FLUSH_ALL); - WriteExit(nextPC); - } + if (code_block.m_broken) + { + gpr.Flush(FLUSH_ALL); + fpr.Flush(FLUSH_ALL); + WriteExit(nextPC); + } - b->codeSize = (u32)(GetCodePtr() - start); - b->originalSize = code_block.m_num_instructions; + b->codeSize = (u32)(GetCodePtr() - start); + b->originalSize = code_block.m_num_instructions; - FlushIcache(); - farcode.FlushIcache(); - return start; + FlushIcache(); + farcode.FlushIcache(); + return start; } diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h index 6bf30e351a..00181d916d 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h @@ -10,245 +10,236 @@ #include "Common/Arm64Emitter.h" #include "Core/PowerPC/CPUCoreBase.h" -#include "Core/PowerPC/PPCAnalyst.h" -#include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" #include "Core/PowerPC/JitArm64/JitArm64Cache.h" +#include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" #include "Core/PowerPC/JitArmCommon/BackPatch.h" #include "Core/PowerPC/JitCommon/JitAsmCommon.h" #include "Core/PowerPC/JitCommon/JitBase.h" +#include "Core/PowerPC/PPCAnalyst.h" class JitArm64 : public JitBase, public Arm64Gen::ARM64CodeBlock, public CommonAsmRoutinesBase { public: - JitArm64() : code_buffer(32000), m_float_emit(this) {} - ~JitArm64() {} + JitArm64() : code_buffer(32000), m_float_emit(this) {} + ~JitArm64() {} + void Init(); + void Shutdown(); - void Init(); - void Shutdown(); + JitBaseBlockCache* GetBlockCache() { return &blocks; } + bool IsInCodeSpace(u8* ptr) const { return IsInSpace(ptr); } + bool HandleFault(uintptr_t access_address, SContext* ctx) override; - JitBaseBlockCache *GetBlockCache() { return &blocks; } + void ClearCache(); - bool IsInCodeSpace(u8 *ptr) const { return IsInSpace(ptr); } + CommonAsmRoutinesBase* GetAsmRoutines() override { return this; } + void Run(); + void SingleStep(); - bool HandleFault(uintptr_t access_address, SContext* ctx) override; + void Jit(u32); - void ClearCache(); + const char* GetName() { return "JITARM64"; } + // OPCODES + void FallBackToInterpreter(UGeckoInstruction inst); + void DoNothing(UGeckoInstruction inst); + void HLEFunction(UGeckoInstruction inst); - CommonAsmRoutinesBase *GetAsmRoutines() override - { - return this; - } + void DynaRunTable4(UGeckoInstruction inst); + void DynaRunTable19(UGeckoInstruction inst); + void DynaRunTable31(UGeckoInstruction inst); + void DynaRunTable59(UGeckoInstruction inst); + void DynaRunTable63(UGeckoInstruction inst); - void Run(); - void SingleStep(); + // Force break + void Break(UGeckoInstruction inst); - void Jit(u32); + // Branch + void sc(UGeckoInstruction inst); + void rfi(UGeckoInstruction inst); + void bx(UGeckoInstruction inst); + void bcx(UGeckoInstruction inst); + void bcctrx(UGeckoInstruction inst); + void bclrx(UGeckoInstruction inst); - const char *GetName() - { - return "JITARM64"; - } + // Integer + void arith_imm(UGeckoInstruction inst); + void boolX(UGeckoInstruction inst); + void addx(UGeckoInstruction inst); + void addix(UGeckoInstruction inst); + void extsXx(UGeckoInstruction inst); + void cntlzwx(UGeckoInstruction inst); + void negx(UGeckoInstruction inst); + void cmp(UGeckoInstruction inst); + void cmpl(UGeckoInstruction inst); + void cmpi(UGeckoInstruction inst); + void cmpli(UGeckoInstruction inst); + void rlwinmx(UGeckoInstruction inst); + void rlwnmx(UGeckoInstruction inst); + void srawix(UGeckoInstruction inst); + void mullwx(UGeckoInstruction inst); + void mulhwx(UGeckoInstruction inst); + void mulhwux(UGeckoInstruction inst); + void addic(UGeckoInstruction inst); + void mulli(UGeckoInstruction inst); + void addzex(UGeckoInstruction inst); + void subfx(UGeckoInstruction inst); + void addcx(UGeckoInstruction inst); + void slwx(UGeckoInstruction inst); + void srwx(UGeckoInstruction inst); + void rlwimix(UGeckoInstruction inst); + void subfex(UGeckoInstruction inst); + void subfcx(UGeckoInstruction inst); + void subfic(UGeckoInstruction inst); + void addex(UGeckoInstruction inst); + void divwux(UGeckoInstruction inst); - // OPCODES - void FallBackToInterpreter(UGeckoInstruction inst); - void DoNothing(UGeckoInstruction inst); - void HLEFunction(UGeckoInstruction inst); + // System Registers + void mtmsr(UGeckoInstruction inst); + void mfmsr(UGeckoInstruction inst); + void mcrf(UGeckoInstruction inst); + void mfsr(UGeckoInstruction inst); + void mtsr(UGeckoInstruction inst); + void mfsrin(UGeckoInstruction inst); + void mtsrin(UGeckoInstruction inst); + void twx(UGeckoInstruction inst); + void mfspr(UGeckoInstruction inst); + void mftb(UGeckoInstruction inst); + void mtspr(UGeckoInstruction inst); + void crXXX(UGeckoInstruction inst); + void mfcr(UGeckoInstruction inst); + void mtcrf(UGeckoInstruction inst); - void DynaRunTable4(UGeckoInstruction inst); - void DynaRunTable19(UGeckoInstruction inst); - void DynaRunTable31(UGeckoInstruction inst); - void DynaRunTable59(UGeckoInstruction inst); - void DynaRunTable63(UGeckoInstruction inst); + // LoadStore + void lXX(UGeckoInstruction inst); + void stX(UGeckoInstruction inst); + void lmw(UGeckoInstruction inst); + void stmw(UGeckoInstruction inst); + void dcbx(UGeckoInstruction inst); + void dcbt(UGeckoInstruction inst); + void dcbz(UGeckoInstruction inst); - // Force break - void Break(UGeckoInstruction inst); + // LoadStore floating point + void lfXX(UGeckoInstruction inst); + void stfXX(UGeckoInstruction inst); - // Branch - void sc(UGeckoInstruction inst); - void rfi(UGeckoInstruction inst); - void bx(UGeckoInstruction inst); - void bcx(UGeckoInstruction inst); - void bcctrx(UGeckoInstruction inst); - void bclrx(UGeckoInstruction inst); + // Floating point + void fp_arith(UGeckoInstruction inst); + void fp_logic(UGeckoInstruction inst); + void fselx(UGeckoInstruction inst); + void fcmpX(UGeckoInstruction inst); + void frspx(UGeckoInstruction inst); + void fctiwzx(UGeckoInstruction inst); - // Integer - void arith_imm(UGeckoInstruction inst); - void boolX(UGeckoInstruction inst); - void addx(UGeckoInstruction inst); - void addix(UGeckoInstruction inst); - void extsXx(UGeckoInstruction inst); - void cntlzwx(UGeckoInstruction inst); - void negx(UGeckoInstruction inst); - void cmp(UGeckoInstruction inst); - void cmpl(UGeckoInstruction inst); - void cmpi(UGeckoInstruction inst); - void cmpli(UGeckoInstruction inst); - void rlwinmx(UGeckoInstruction inst); - void rlwnmx(UGeckoInstruction inst); - void srawix(UGeckoInstruction inst); - void mullwx(UGeckoInstruction inst); - void mulhwx(UGeckoInstruction inst); - void mulhwux(UGeckoInstruction inst); - void addic(UGeckoInstruction inst); - void mulli(UGeckoInstruction inst); - void addzex(UGeckoInstruction inst); - void subfx(UGeckoInstruction inst); - void addcx(UGeckoInstruction inst); - void slwx(UGeckoInstruction inst); - void srwx(UGeckoInstruction inst); - void rlwimix(UGeckoInstruction inst); - void subfex(UGeckoInstruction inst); - void subfcx(UGeckoInstruction inst); - void subfic(UGeckoInstruction inst); - void addex(UGeckoInstruction inst); - void divwux(UGeckoInstruction inst); + // Paired + void ps_maddXX(UGeckoInstruction inst); + void ps_mergeXX(UGeckoInstruction inst); + void ps_mulsX(UGeckoInstruction inst); + void ps_res(UGeckoInstruction inst); + void ps_sel(UGeckoInstruction inst); + void ps_sumX(UGeckoInstruction inst); - // System Registers - void mtmsr(UGeckoInstruction inst); - void mfmsr(UGeckoInstruction inst); - void mcrf(UGeckoInstruction inst); - void mfsr(UGeckoInstruction inst); - void mtsr(UGeckoInstruction inst); - void mfsrin(UGeckoInstruction inst); - void mtsrin(UGeckoInstruction inst); - void twx(UGeckoInstruction inst); - void mfspr(UGeckoInstruction inst); - void mftb(UGeckoInstruction inst); - void mtspr(UGeckoInstruction inst); - void crXXX(UGeckoInstruction inst); - void mfcr(UGeckoInstruction inst); - void mtcrf(UGeckoInstruction inst); - - // LoadStore - void lXX(UGeckoInstruction inst); - void stX(UGeckoInstruction inst); - void lmw(UGeckoInstruction inst); - void stmw(UGeckoInstruction inst); - void dcbx(UGeckoInstruction inst); - void dcbt(UGeckoInstruction inst); - void dcbz(UGeckoInstruction inst); - - // LoadStore floating point - void lfXX(UGeckoInstruction inst); - void stfXX(UGeckoInstruction inst); - - // Floating point - void fp_arith(UGeckoInstruction inst); - void fp_logic(UGeckoInstruction inst); - void fselx(UGeckoInstruction inst); - void fcmpX(UGeckoInstruction inst); - void frspx(UGeckoInstruction inst); - void fctiwzx(UGeckoInstruction inst); - - // Paired - void ps_maddXX(UGeckoInstruction inst); - void ps_mergeXX(UGeckoInstruction inst); - void ps_mulsX(UGeckoInstruction inst); - void ps_res(UGeckoInstruction inst); - void ps_sel(UGeckoInstruction inst); - void ps_sumX(UGeckoInstruction inst); - - // Loadstore paired - void psq_l(UGeckoInstruction inst); - void psq_st(UGeckoInstruction inst); + // Loadstore paired + void psq_l(UGeckoInstruction inst); + void psq_st(UGeckoInstruction inst); private: - struct SlowmemHandler - { - ARM64Reg dest_reg; - ARM64Reg addr_reg; - BitSet32 gprs; - BitSet32 fprs; - u32 flags; + struct SlowmemHandler + { + ARM64Reg dest_reg; + ARM64Reg addr_reg; + BitSet32 gprs; + BitSet32 fprs; + u32 flags; - bool operator<(const SlowmemHandler& rhs) const - { - return std::tie(dest_reg, addr_reg, gprs, fprs, flags) < - std::tie(rhs.dest_reg, rhs.addr_reg, rhs.gprs, rhs.fprs, rhs.flags); - } - }; + bool operator<(const SlowmemHandler& rhs) const + { + return std::tie(dest_reg, addr_reg, gprs, fprs, flags) < + std::tie(rhs.dest_reg, rhs.addr_reg, rhs.gprs, rhs.fprs, rhs.flags); + } + }; - struct FastmemArea - { - u32 length; - const u8* slowmem_code; - }; + struct FastmemArea + { + u32 length; + const u8* slowmem_code; + }; - // - std::map m_fault_to_handler; - std::map m_handler_to_loc; - Arm64GPRCache gpr; - Arm64FPRCache fpr; + // + std::map m_fault_to_handler; + std::map m_handler_to_loc; + Arm64GPRCache gpr; + Arm64FPRCache fpr; - JitArm64BlockCache blocks; + JitArm64BlockCache blocks; - PPCAnalyst::CodeBuffer code_buffer; + PPCAnalyst::CodeBuffer code_buffer; - ARM64FloatEmitter m_float_emit; + ARM64FloatEmitter m_float_emit; - Arm64Gen::ARM64CodeBlock farcode; - u8* nearcode; // Backed up when we switch to far code. + Arm64Gen::ARM64CodeBlock farcode; + u8* nearcode; // Backed up when we switch to far code. - // Do we support cycle counter profiling? - bool m_supports_cycle_counter; + // Do we support cycle counter profiling? + bool m_supports_cycle_counter; - void EmitResetCycleCounters(); - void EmitGetCycles(Arm64Gen::ARM64Reg reg); + void EmitResetCycleCounters(); + void EmitGetCycles(Arm64Gen::ARM64Reg reg); - // Simple functions to switch between near and far code emitting - void SwitchToFarCode() - { - nearcode = GetWritableCodePtr(); - SetCodePtrUnsafe(farcode.GetWritableCodePtr()); - AlignCode16(); - } + // Simple functions to switch between near and far code emitting + void SwitchToFarCode() + { + nearcode = GetWritableCodePtr(); + SetCodePtrUnsafe(farcode.GetWritableCodePtr()); + AlignCode16(); + } - void SwitchToNearCode() - { - farcode.SetCodePtrUnsafe(GetWritableCodePtr()); - SetCodePtrUnsafe(nearcode); - } + void SwitchToNearCode() + { + farcode.SetCodePtrUnsafe(GetWritableCodePtr()); + SetCodePtrUnsafe(nearcode); + } - // Dump a memory range of code - void DumpCode(const u8* start, const u8* end); + // Dump a memory range of code + void DumpCode(const u8* start, const u8* end); - // Backpatching routines - bool DisasmLoadStore(const u8* ptr, u32* flags, Arm64Gen::ARM64Reg* reg); - void EmitBackpatchRoutine(u32 flags, bool fastmem, bool do_farcode, - Arm64Gen::ARM64Reg RS, Arm64Gen::ARM64Reg addr, - BitSet32 gprs_to_push = BitSet32(0), BitSet32 fprs_to_push = BitSet32(0)); - // Loadstore routines - void SafeLoadToReg(u32 dest, s32 addr, s32 offsetReg, u32 flags, s32 offset, bool update); - void SafeStoreFromReg(s32 dest, u32 value, s32 regOffset, u32 flags, s32 offset); + // Backpatching routines + bool DisasmLoadStore(const u8* ptr, u32* flags, Arm64Gen::ARM64Reg* reg); + void EmitBackpatchRoutine(u32 flags, bool fastmem, bool do_farcode, Arm64Gen::ARM64Reg RS, + Arm64Gen::ARM64Reg addr, BitSet32 gprs_to_push = BitSet32(0), + BitSet32 fprs_to_push = BitSet32(0)); + // Loadstore routines + void SafeLoadToReg(u32 dest, s32 addr, s32 offsetReg, u32 flags, s32 offset, bool update); + void SafeStoreFromReg(s32 dest, u32 value, s32 regOffset, u32 flags, s32 offset); - const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b, u32 nextPC); + const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBlock* b, u32 nextPC); - void DoDownCount(); - void Cleanup(); + void DoDownCount(); + void Cleanup(); - // AsmRoutines - void GenerateAsm(); - void GenerateCommonAsm(); - void GenMfcr(); + // AsmRoutines + void GenerateAsm(); + void GenerateCommonAsm(); + void GenMfcr(); - // Profiling - void BeginTimeProfile(JitBlock* b); - void EndTimeProfile(JitBlock* b); + // Profiling + void BeginTimeProfile(JitBlock* b); + void EndTimeProfile(JitBlock* b); - // Exits - void WriteExit(u32 destination); - void WriteExit(Arm64Gen::ARM64Reg dest); - void WriteExceptionExit(u32 destination, bool only_external = false); - void WriteExceptionExit(Arm64Gen::ARM64Reg dest, bool only_external = false); + // Exits + void WriteExit(u32 destination); + void WriteExit(Arm64Gen::ARM64Reg dest); + void WriteExceptionExit(u32 destination, bool only_external = false); + void WriteExceptionExit(Arm64Gen::ARM64Reg dest, bool only_external = false); - FixupBranch JumpIfCRFieldBit(int field, int bit, bool jump_if_set); + FixupBranch JumpIfCRFieldBit(int field, int bit, bool jump_if_set); - void ComputeRC(Arm64Gen::ARM64Reg reg, int crf = 0, bool needs_sext = true); - void ComputeRC(u64 imm, int crf = 0, bool needs_sext = true); - void ComputeCarry(bool Carry); - void ComputeCarry(); + void ComputeRC(Arm64Gen::ARM64Reg reg, int crf = 0, bool needs_sext = true); + void ComputeRC(u64 imm, int crf = 0, bool needs_sext = true); + void ComputeCarry(bool Carry); + void ComputeCarry(); - typedef u32 (*Operation)(u32, u32); - void reg_imm(u32 d, u32 a, u32 value, Operation do_op, void (ARM64XEmitter::*op)(Arm64Gen::ARM64Reg, Arm64Gen::ARM64Reg, Arm64Gen::ARM64Reg, ArithOption), bool Rc = false); + typedef u32 (*Operation)(u32, u32); + void reg_imm(u32 d, u32 a, u32 value, Operation do_op, + void (ARM64XEmitter::*op)(Arm64Gen::ARM64Reg, Arm64Gen::ARM64Reg, Arm64Gen::ARM64Reg, + ArithOption), + bool Rc = false); }; - diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.cpp index 85664e7bb3..fdacec2c4a 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.cpp @@ -2,38 +2,37 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Common/CommonTypes.h" -#include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/JitArm64/Jit.h" +#include "Common/CommonTypes.h" #include "Core/PowerPC/JitArm64/JitArm64Cache.h" +#include "Core/PowerPC/JitInterface.h" void JitArm64BlockCache::WriteLinkBlock(u8* location, const JitBlock& block) { - ARM64XEmitter emit(location); + ARM64XEmitter emit(location); - // Are we able to jump directly to the normal entry? - s64 distance = ((s64)block.normalEntry - (s64)location) >> 2; - if (distance >= -0x40000 && distance <= 0x3FFFF) - { - emit.B(CC_LE, block.normalEntry); + // Are we able to jump directly to the normal entry? + s64 distance = ((s64)block.normalEntry - (s64)location) >> 2; + if (distance >= -0x40000 && distance <= 0x3FFFF) + { + emit.B(CC_LE, block.normalEntry); - // We can't write DISPATCHER_PC here, as blink linking is only for 8bytes. - // So we'll hit two jumps when calling Advance. - emit.B(block.checkedEntry); - } - else - { - emit.B(block.checkedEntry); - } - emit.FlushIcache(); + // We can't write DISPATCHER_PC here, as blink linking is only for 8bytes. + // So we'll hit two jumps when calling Advance. + emit.B(block.checkedEntry); + } + else + { + emit.B(block.checkedEntry); + } + emit.FlushIcache(); } void JitArm64BlockCache::WriteDestroyBlock(const u8* location, u32 address) { - // must fit within the code generated in JitArm64::WriteExit - ARM64XEmitter emit((u8 *)location); - emit.MOVI2R(DISPATCHER_PC, address); - emit.B(jit->GetAsmRoutines()->dispatcher); - emit.FlushIcache(); + // must fit within the code generated in JitArm64::WriteExit + ARM64XEmitter emit((u8*)location); + emit.MOVI2R(DISPATCHER_PC, address); + emit.B(jit->GetAsmRoutines()->dispatcher); + emit.FlushIcache(); } - diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.h b/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.h index d9029822df..0b29a9b8d8 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.h +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.h @@ -6,12 +6,11 @@ #include "Core/PowerPC/JitCommon/JitCache.h" - typedef void (*CompiledCode)(); class JitArm64BlockCache : public JitBaseBlockCache { private: - void WriteLinkBlock(u8* location, const JitBlock& block); - void WriteDestroyBlock(const u8* location, u32 address); + void WriteLinkBlock(u8* location, const JitBlock& block); + void WriteDestroyBlock(const u8* location, u32 address); }; diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp index dbe4ff43ee..40db52c299 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp @@ -7,329 +7,328 @@ #include "Common/BitSet.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" -#include "Common/StringUtil.h" #include "Common/Logging/Log.h" +#include "Common/StringUtil.h" #include "Core/HW/Memmap.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/JitArm64/Jit.h" #include "Core/PowerPC/JitArmCommon/BackPatch.h" +#include "Core/PowerPC/PowerPC.h" using namespace Arm64Gen; static void DoBacktrace(uintptr_t access_address, SContext* ctx) { - for (int i = 0; i < 30; i += 2) - ERROR_LOG(DYNA_REC, "R%d: 0x%016llx\tR%d: 0x%016llx", i, ctx->CTX_REG(i), i + 1, ctx->CTX_REG(i + 1)); + for (int i = 0; i < 30; i += 2) + ERROR_LOG(DYNA_REC, "R%d: 0x%016llx\tR%d: 0x%016llx", i, ctx->CTX_REG(i), i + 1, + ctx->CTX_REG(i + 1)); - ERROR_LOG(DYNA_REC, "R30: 0x%016llx\tSP: 0x%016llx", ctx->CTX_REG(30), ctx->CTX_SP); + ERROR_LOG(DYNA_REC, "R30: 0x%016llx\tSP: 0x%016llx", ctx->CTX_REG(30), ctx->CTX_SP); - ERROR_LOG(DYNA_REC, "Access Address: 0x%016lx", access_address); - ERROR_LOG(DYNA_REC, "PC: 0x%016llx", ctx->CTX_PC); + ERROR_LOG(DYNA_REC, "Access Address: 0x%016lx", access_address); + ERROR_LOG(DYNA_REC, "PC: 0x%016llx", ctx->CTX_PC); - ERROR_LOG(DYNA_REC, "Memory Around PC"); + ERROR_LOG(DYNA_REC, "Memory Around PC"); - std::string pc_memory = ""; - for (u64 pc = (ctx->CTX_PC - 32); pc < (ctx->CTX_PC + 32); pc += 16) - { - pc_memory += StringFromFormat("%08x%08x%08x%08x", - Common::swap32(*(u32*)pc), Common::swap32(*(u32*)(pc + 4)), - Common::swap32(*(u32*)(pc + 8)), Common::swap32(*(u32*)(pc + 12))); + std::string pc_memory = ""; + for (u64 pc = (ctx->CTX_PC - 32); pc < (ctx->CTX_PC + 32); pc += 16) + { + pc_memory += StringFromFormat("%08x%08x%08x%08x", Common::swap32(*(u32*)pc), + Common::swap32(*(u32*)(pc + 4)), Common::swap32(*(u32*)(pc + 8)), + Common::swap32(*(u32*)(pc + 12))); - ERROR_LOG(DYNA_REC, "0x%016lx: %08x %08x %08x %08x", - pc, *(u32*)pc, *(u32*)(pc + 4), *(u32*)(pc + 8), *(u32*)(pc + 12)); - } + ERROR_LOG(DYNA_REC, "0x%016lx: %08x %08x %08x %08x", pc, *(u32*)pc, *(u32*)(pc + 4), + *(u32*)(pc + 8), *(u32*)(pc + 12)); + } - ERROR_LOG(DYNA_REC, "Full block: %s", pc_memory.c_str()); + ERROR_LOG(DYNA_REC, "Full block: %s", pc_memory.c_str()); } -void JitArm64::EmitBackpatchRoutine(u32 flags, bool fastmem, bool do_farcode, - ARM64Reg RS, ARM64Reg addr, - BitSet32 gprs_to_push, BitSet32 fprs_to_push) +void JitArm64::EmitBackpatchRoutine(u32 flags, bool fastmem, bool do_farcode, ARM64Reg RS, + ARM64Reg addr, BitSet32 gprs_to_push, BitSet32 fprs_to_push) { - bool in_far_code = false; - const u8* fastmem_start = GetCodePtr(); + bool in_far_code = false; + const u8* fastmem_start = GetCodePtr(); - if (fastmem) - { + if (fastmem) + { + if (flags & BackPatchInfo::FLAG_STORE && flags & BackPatchInfo::FLAG_MASK_FLOAT) + { + if (flags & BackPatchInfo::FLAG_SIZE_F32) + { + m_float_emit.FCVT(32, 64, D0, RS); + m_float_emit.REV32(8, D0, D0); + m_float_emit.STR(32, D0, MEM_REG, addr); + } + else if (flags & BackPatchInfo::FLAG_SIZE_F32I) + { + m_float_emit.REV32(8, D0, RS); + m_float_emit.STR(32, D0, MEM_REG, addr); + } + else if (flags & BackPatchInfo::FLAG_SIZE_F32X2) + { + m_float_emit.FCVTN(32, D0, RS); + m_float_emit.REV32(8, D0, D0); + m_float_emit.STR(64, Q0, MEM_REG, addr); + } + else if (flags & BackPatchInfo::FLAG_SIZE_F32X2I) + { + m_float_emit.REV32(8, D0, RS); + m_float_emit.STR(64, Q0, MEM_REG, addr); + } + else + { + m_float_emit.REV64(8, Q0, RS); + m_float_emit.STR(64, Q0, MEM_REG, addr); + } + } + else if (flags & BackPatchInfo::FLAG_LOAD && flags & BackPatchInfo::FLAG_MASK_FLOAT) + { + if (flags & BackPatchInfo::FLAG_SIZE_F32) + { + m_float_emit.LDR(32, EncodeRegToDouble(RS), MEM_REG, addr); + m_float_emit.REV32(8, EncodeRegToDouble(RS), EncodeRegToDouble(RS)); + } + else + { + m_float_emit.LDR(64, EncodeRegToDouble(RS), MEM_REG, addr); + m_float_emit.REV64(8, EncodeRegToDouble(RS), EncodeRegToDouble(RS)); + } + } + else if (flags & BackPatchInfo::FLAG_STORE) + { + ARM64Reg temp = W0; + if (flags & BackPatchInfo::FLAG_SIZE_32) + REV32(temp, RS); + else if (flags & BackPatchInfo::FLAG_SIZE_16) + REV16(temp, RS); - if (flags & BackPatchInfo::FLAG_STORE && - flags & BackPatchInfo::FLAG_MASK_FLOAT) - { - if (flags & BackPatchInfo::FLAG_SIZE_F32) - { - m_float_emit.FCVT(32, 64, D0, RS); - m_float_emit.REV32(8, D0, D0); - m_float_emit.STR(32, D0, MEM_REG, addr); - } - else if (flags & BackPatchInfo::FLAG_SIZE_F32I) - { - m_float_emit.REV32(8, D0, RS); - m_float_emit.STR(32, D0, MEM_REG, addr); - } - else if (flags & BackPatchInfo::FLAG_SIZE_F32X2) - { - m_float_emit.FCVTN(32, D0, RS); - m_float_emit.REV32(8, D0, D0); - m_float_emit.STR(64, Q0, MEM_REG, addr); - } - else if (flags & BackPatchInfo::FLAG_SIZE_F32X2I) - { - m_float_emit.REV32(8, D0, RS); - m_float_emit.STR(64, Q0, MEM_REG, addr); - } - else - { - m_float_emit.REV64(8, Q0, RS); - m_float_emit.STR(64, Q0, MEM_REG, addr); - } - } - else if (flags & BackPatchInfo::FLAG_LOAD && - flags & BackPatchInfo::FLAG_MASK_FLOAT) - { - if (flags & BackPatchInfo::FLAG_SIZE_F32) - { - m_float_emit.LDR(32, EncodeRegToDouble(RS), MEM_REG, addr); - m_float_emit.REV32(8, EncodeRegToDouble(RS), EncodeRegToDouble(RS)); - } - else - { - m_float_emit.LDR(64, EncodeRegToDouble(RS), MEM_REG, addr); - m_float_emit.REV64(8, EncodeRegToDouble(RS), EncodeRegToDouble(RS)); - } - } - else if (flags & BackPatchInfo::FLAG_STORE) - { - ARM64Reg temp = W0; - if (flags & BackPatchInfo::FLAG_SIZE_32) - REV32(temp, RS); - else if (flags & BackPatchInfo::FLAG_SIZE_16) - REV16(temp, RS); + if (flags & BackPatchInfo::FLAG_SIZE_32) + STR(temp, MEM_REG, addr); + else if (flags & BackPatchInfo::FLAG_SIZE_16) + STRH(temp, MEM_REG, addr); + else + STRB(RS, MEM_REG, addr); + } + else if (flags & BackPatchInfo::FLAG_ZERO_256) + { + // This literally only stores 32bytes of zeros to the target address + ADD(addr, addr, MEM_REG); + STP(INDEX_SIGNED, ZR, ZR, addr, 0); + STP(INDEX_SIGNED, ZR, ZR, addr, 16); + } + else + { + if (flags & BackPatchInfo::FLAG_SIZE_32) + LDR(RS, MEM_REG, addr); + else if (flags & BackPatchInfo::FLAG_SIZE_16) + LDRH(RS, MEM_REG, addr); + else if (flags & BackPatchInfo::FLAG_SIZE_8) + LDRB(RS, MEM_REG, addr); - if (flags & BackPatchInfo::FLAG_SIZE_32) - STR(temp, MEM_REG, addr); - else if (flags & BackPatchInfo::FLAG_SIZE_16) - STRH(temp, MEM_REG, addr); - else - STRB(RS, MEM_REG, addr); - } - else if (flags & BackPatchInfo::FLAG_ZERO_256) - { - // This literally only stores 32bytes of zeros to the target address - ADD(addr, addr, MEM_REG); - STP(INDEX_SIGNED, ZR, ZR, addr, 0); - STP(INDEX_SIGNED, ZR, ZR, addr, 16); - } - else - { - if (flags & BackPatchInfo::FLAG_SIZE_32) - LDR(RS, MEM_REG, addr); - else if (flags & BackPatchInfo::FLAG_SIZE_16) - LDRH(RS, MEM_REG, addr); - else if (flags & BackPatchInfo::FLAG_SIZE_8) - LDRB(RS, MEM_REG, addr); + if (!(flags & BackPatchInfo::FLAG_REVERSE)) + { + if (flags & BackPatchInfo::FLAG_SIZE_32) + REV32(RS, RS); + else if (flags & BackPatchInfo::FLAG_SIZE_16) + REV16(RS, RS); + } - if (!(flags & BackPatchInfo::FLAG_REVERSE)) - { - if (flags & BackPatchInfo::FLAG_SIZE_32) - REV32(RS, RS); - else if (flags & BackPatchInfo::FLAG_SIZE_16) - REV16(RS, RS); - } + if (flags & BackPatchInfo::FLAG_EXTEND) + SXTH(RS, RS); + } + } + const u8* fastmem_end = GetCodePtr(); - if (flags & BackPatchInfo::FLAG_EXTEND) - SXTH(RS, RS); - } - } - const u8* fastmem_end = GetCodePtr(); + if (!fastmem || do_farcode) + { + if (fastmem && do_farcode) + { + SlowmemHandler handler; + handler.dest_reg = RS; + handler.addr_reg = addr; + handler.gprs = gprs_to_push; + handler.fprs = fprs_to_push; + handler.flags = flags; - if (!fastmem || do_farcode) - { - if (fastmem && do_farcode) - { - SlowmemHandler handler; - handler.dest_reg = RS; - handler.addr_reg = addr; - handler.gprs = gprs_to_push; - handler.fprs = fprs_to_push; - handler.flags = flags; + FastmemArea* fastmem_area = &m_fault_to_handler[fastmem_start]; + auto handler_loc_iter = m_handler_to_loc.find(handler); - FastmemArea* fastmem_area = &m_fault_to_handler[fastmem_start]; - auto handler_loc_iter = m_handler_to_loc.find(handler); + if (handler_loc_iter == m_handler_to_loc.end()) + { + in_far_code = true; + SwitchToFarCode(); + const u8* handler_loc = GetCodePtr(); + m_handler_to_loc[handler] = handler_loc; + fastmem_area->slowmem_code = handler_loc; + fastmem_area->length = fastmem_end - fastmem_start; + } + else + { + const u8* handler_loc = handler_loc_iter->second; + fastmem_area->slowmem_code = handler_loc; + fastmem_area->length = fastmem_end - fastmem_start; + return; + } + } - if (handler_loc_iter == m_handler_to_loc.end()) - { - in_far_code = true; - SwitchToFarCode(); - const u8* handler_loc = GetCodePtr(); - m_handler_to_loc[handler] = handler_loc; - fastmem_area->slowmem_code = handler_loc; - fastmem_area->length = fastmem_end - fastmem_start; - } - else - { - const u8* handler_loc = handler_loc_iter->second; - fastmem_area->slowmem_code = handler_loc; - fastmem_area->length = fastmem_end - fastmem_start; - return; - } - } + ABI_PushRegisters(gprs_to_push); + m_float_emit.ABI_PushRegisters(fprs_to_push, X30); - ABI_PushRegisters(gprs_to_push); - m_float_emit.ABI_PushRegisters(fprs_to_push, X30); + if (flags & BackPatchInfo::FLAG_STORE && flags & BackPatchInfo::FLAG_MASK_FLOAT) + { + if (flags & BackPatchInfo::FLAG_SIZE_F32) + { + m_float_emit.FCVT(32, 64, D0, RS); + m_float_emit.UMOV(32, W0, Q0, 0); + MOVI2R(X30, (u64)&PowerPC::Write_U32); + BLR(X30); + } + else if (flags & BackPatchInfo::FLAG_SIZE_F32I) + { + m_float_emit.UMOV(32, W0, RS, 0); + MOVI2R(X30, (u64)&PowerPC::Write_U32); + BLR(X30); + } + else if (flags & BackPatchInfo::FLAG_SIZE_F32X2) + { + m_float_emit.FCVTN(32, D0, RS); + m_float_emit.UMOV(64, X0, D0, 0); + ORR(X0, SP, X0, ArithOption(X0, ST_ROR, 32)); + MOVI2R(X30, (u64)PowerPC::Write_U64); + BLR(X30); + } + else if (flags & BackPatchInfo::FLAG_SIZE_F32X2I) + { + m_float_emit.UMOV(64, X0, RS, 0); + ORR(X0, SP, X0, ArithOption(X0, ST_ROR, 32)); + MOVI2R(X30, (u64)PowerPC::Write_U64); + BLR(X30); + } + else + { + MOVI2R(X30, (u64)&PowerPC::Write_U64); + m_float_emit.UMOV(64, X0, RS, 0); + BLR(X30); + } + } + else if (flags & BackPatchInfo::FLAG_LOAD && flags & BackPatchInfo::FLAG_MASK_FLOAT) + { + if (flags & BackPatchInfo::FLAG_SIZE_F32) + { + MOVI2R(X30, (u64)&PowerPC::Read_U32); + BLR(X30); + m_float_emit.INS(32, RS, 0, X0); + } + else + { + MOVI2R(X30, (u64)&PowerPC::Read_F64); + BLR(X30); + m_float_emit.INS(64, RS, 0, X0); + } + } + else if (flags & BackPatchInfo::FLAG_STORE) + { + MOV(W0, RS); - if (flags & BackPatchInfo::FLAG_STORE && - flags & BackPatchInfo::FLAG_MASK_FLOAT) - { - if (flags & BackPatchInfo::FLAG_SIZE_F32) - { - m_float_emit.FCVT(32, 64, D0, RS); - m_float_emit.UMOV(32, W0, Q0, 0); - MOVI2R(X30, (u64)&PowerPC::Write_U32); - BLR(X30); - } - else if (flags & BackPatchInfo::FLAG_SIZE_F32I) - { - m_float_emit.UMOV(32, W0, RS, 0); - MOVI2R(X30, (u64)&PowerPC::Write_U32); - BLR(X30); - } - else if (flags & BackPatchInfo::FLAG_SIZE_F32X2) - { - m_float_emit.FCVTN(32, D0, RS); - m_float_emit.UMOV(64, X0, D0, 0); - ORR(X0, SP, X0, ArithOption(X0, ST_ROR, 32)); - MOVI2R(X30, (u64)PowerPC::Write_U64); - BLR(X30); - } - else if (flags & BackPatchInfo::FLAG_SIZE_F32X2I) - { - m_float_emit.UMOV(64, X0, RS, 0); - ORR(X0, SP, X0, ArithOption(X0, ST_ROR, 32)); - MOVI2R(X30, (u64)PowerPC::Write_U64); - BLR(X30); - } - else - { - MOVI2R(X30, (u64)&PowerPC::Write_U64); - m_float_emit.UMOV(64, X0, RS, 0); - BLR(X30); - } + if (flags & BackPatchInfo::FLAG_SIZE_32) + MOVI2R(X30, (u64)&PowerPC::Write_U32); + else if (flags & BackPatchInfo::FLAG_SIZE_16) + MOVI2R(X30, (u64)&PowerPC::Write_U16); + else + MOVI2R(X30, (u64)&PowerPC::Write_U8); - } - else if (flags & BackPatchInfo::FLAG_LOAD && - flags & BackPatchInfo::FLAG_MASK_FLOAT) - { - if (flags & BackPatchInfo::FLAG_SIZE_F32) - { - MOVI2R(X30, (u64)&PowerPC::Read_U32); - BLR(X30); - m_float_emit.INS(32, RS, 0, X0); - } - else - { - MOVI2R(X30, (u64)&PowerPC::Read_F64); - BLR(X30); - m_float_emit.INS(64, RS, 0, X0); - } - } - else if (flags & BackPatchInfo::FLAG_STORE) - { - MOV(W0, RS); + BLR(X30); + } + else if (flags & BackPatchInfo::FLAG_ZERO_256) + { + MOVI2R(X30, (u64)&PowerPC::ClearCacheLine); + BLR(X30); + } + else + { + if (flags & BackPatchInfo::FLAG_SIZE_32) + MOVI2R(X30, (u64)&PowerPC::Read_U32); + else if (flags & BackPatchInfo::FLAG_SIZE_16) + MOVI2R(X30, (u64)&PowerPC::Read_U16); + else if (flags & BackPatchInfo::FLAG_SIZE_8) + MOVI2R(X30, (u64)&PowerPC::Read_U8); - if (flags & BackPatchInfo::FLAG_SIZE_32) - MOVI2R(X30, (u64)&PowerPC::Write_U32); - else if (flags & BackPatchInfo::FLAG_SIZE_16) - MOVI2R(X30, (u64)&PowerPC::Write_U16); - else - MOVI2R(X30, (u64)&PowerPC::Write_U8); + BLR(X30); - BLR(X30); - } - else if (flags & BackPatchInfo::FLAG_ZERO_256) - { - MOVI2R(X30, (u64)&PowerPC::ClearCacheLine); - BLR(X30); - } - else - { - if (flags & BackPatchInfo::FLAG_SIZE_32) - MOVI2R(X30, (u64)&PowerPC::Read_U32); - else if (flags & BackPatchInfo::FLAG_SIZE_16) - MOVI2R(X30, (u64)&PowerPC::Read_U16); - else if (flags & BackPatchInfo::FLAG_SIZE_8) - MOVI2R(X30, (u64)&PowerPC::Read_U8); + if (!(flags & BackPatchInfo::FLAG_REVERSE)) + { + MOV(RS, W0); + } + else + { + if (flags & BackPatchInfo::FLAG_SIZE_32) + REV32(RS, W0); + else if (flags & BackPatchInfo::FLAG_SIZE_16) + REV16(RS, W0); + } - BLR(X30); + if (flags & BackPatchInfo::FLAG_EXTEND) + SXTH(RS, RS); + } - if (!(flags & BackPatchInfo::FLAG_REVERSE)) - { - MOV(RS, W0); - } - else - { - if (flags & BackPatchInfo::FLAG_SIZE_32) - REV32(RS, W0); - else if (flags & BackPatchInfo::FLAG_SIZE_16) - REV16(RS, W0); - } + m_float_emit.ABI_PopRegisters(fprs_to_push, X30); + ABI_PopRegisters(gprs_to_push); + } - if (flags & BackPatchInfo::FLAG_EXTEND) - SXTH(RS, RS); - } - - m_float_emit.ABI_PopRegisters(fprs_to_push, X30); - ABI_PopRegisters(gprs_to_push); - } - - if (in_far_code) - { - RET(X30); - SwitchToNearCode(); - } + if (in_far_code) + { + RET(X30); + SwitchToNearCode(); + } } bool JitArm64::HandleFault(uintptr_t access_address, SContext* ctx) { - if (!IsInSpace((u8*)ctx->CTX_PC)) - { - ERROR_LOG(DYNA_REC, "Backpatch location not within codespace 0x%016llx(0x%08x)", ctx->CTX_PC, Common::swap32(*(u32*)ctx->CTX_PC)); + if (!IsInSpace((u8*)ctx->CTX_PC)) + { + ERROR_LOG(DYNA_REC, "Backpatch location not within codespace 0x%016llx(0x%08x)", ctx->CTX_PC, + Common::swap32(*(u32*)ctx->CTX_PC)); - DoBacktrace(access_address, ctx); - return false; - } + DoBacktrace(access_address, ctx); + return false; + } - if (!(access_address >= (uintptr_t)Memory::physical_base && access_address < (uintptr_t)Memory::physical_base + 0x100010000) && - !(access_address >= (uintptr_t)Memory::logical_base && access_address < (uintptr_t)Memory::logical_base + 0x100010000)) - { - ERROR_LOG(DYNA_REC, "Exception handler - access below memory space. PC: 0x%016llx 0x%016lx < 0x%016lx", ctx->CTX_PC, access_address, (uintptr_t)Memory::physical_base); + if (!(access_address >= (uintptr_t)Memory::physical_base && + access_address < (uintptr_t)Memory::physical_base + 0x100010000) && + !(access_address >= (uintptr_t)Memory::logical_base && + access_address < (uintptr_t)Memory::logical_base + 0x100010000)) + { + ERROR_LOG(DYNA_REC, + "Exception handler - access below memory space. PC: 0x%016llx 0x%016lx < 0x%016lx", + ctx->CTX_PC, access_address, (uintptr_t)Memory::physical_base); - DoBacktrace(access_address, ctx); - return false; - } + DoBacktrace(access_address, ctx); + return false; + } - auto slow_handler_iter = m_fault_to_handler.upper_bound((const u8*)ctx->CTX_PC); - slow_handler_iter--; + auto slow_handler_iter = m_fault_to_handler.upper_bound((const u8*)ctx->CTX_PC); + slow_handler_iter--; - // no fastmem area found - if (slow_handler_iter == m_fault_to_handler.end()) - return false; + // no fastmem area found + if (slow_handler_iter == m_fault_to_handler.end()) + return false; - // no overlapping fastmem area found - if ((const u8*)ctx->CTX_PC - slow_handler_iter->first > slow_handler_iter->second.length) - return false; + // no overlapping fastmem area found + if ((const u8*)ctx->CTX_PC - slow_handler_iter->first > slow_handler_iter->second.length) + return false; - ARM64XEmitter emitter((u8*) slow_handler_iter->first); + ARM64XEmitter emitter((u8*)slow_handler_iter->first); - emitter.BL(slow_handler_iter->second.slowmem_code); + emitter.BL(slow_handler_iter->second.slowmem_code); - u32 num_insts_max = slow_handler_iter->second.length / 4 - 1; - for (u32 i = 0; i < num_insts_max; ++i) - emitter.HINT(HINT_NOP); + u32 num_insts_max = slow_handler_iter->second.length / 4 - 1; + for (u32 i = 0; i < num_insts_max; ++i) + emitter.HINT(HINT_NOP); - m_fault_to_handler.erase(slow_handler_iter); + m_fault_to_handler.erase(slow_handler_iter); - emitter.FlushIcache(); - ctx->CTX_PC = (u64)slow_handler_iter->first; - return true; + emitter.FlushIcache(); + ctx->CTX_PC = (u64)slow_handler_iter->first; + return true; } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp index 773736a935..03c9738570 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp @@ -8,272 +8,274 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCTables.h" #include "Core/PowerPC/JitArm64/Jit.h" #include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" +#include "Core/PowerPC/PPCTables.h" +#include "Core/PowerPC/PowerPC.h" using namespace Arm64Gen; void JitArm64::sc(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITBranchOff); + INSTRUCTION_START + JITDISABLE(bJITBranchOff); - gpr.Flush(FlushMode::FLUSH_ALL); - fpr.Flush(FlushMode::FLUSH_ALL); + gpr.Flush(FlushMode::FLUSH_ALL); + fpr.Flush(FlushMode::FLUSH_ALL); - ARM64Reg WA = gpr.GetReg(); + ARM64Reg WA = gpr.GetReg(); - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); - ORR(WA, WA, 31, 0); // Same as WA | EXCEPTION_SYSCALL - STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); + ORR(WA, WA, 31, 0); // Same as WA | EXCEPTION_SYSCALL + STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); - gpr.Unlock(WA); + gpr.Unlock(WA); - WriteExceptionExit(js.compilerPC + 4); + WriteExceptionExit(js.compilerPC + 4); } void JitArm64::rfi(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITBranchOff); + INSTRUCTION_START + JITDISABLE(bJITBranchOff); - gpr.Flush(FlushMode::FLUSH_ALL); - fpr.Flush(FlushMode::FLUSH_ALL); + gpr.Flush(FlushMode::FLUSH_ALL); + fpr.Flush(FlushMode::FLUSH_ALL); - // See Interpreter rfi for details - const u32 mask = 0x87C0FFFF; - const u32 clearMSR13 = 0xFFFBFFFF; // Mask used to clear the bit MSR[13] - // MSR = ((MSR & ~mask) | (SRR1 & mask)) & clearMSR13; - // R0 = MSR location - // R1 = MSR contents - // R2 = Mask - // R3 = Mask - ARM64Reg WA = gpr.GetReg(); - ARM64Reg WB = gpr.GetReg(); - ARM64Reg WC = gpr.GetReg(); + // See Interpreter rfi for details + const u32 mask = 0x87C0FFFF; + const u32 clearMSR13 = 0xFFFBFFFF; // Mask used to clear the bit MSR[13] + // MSR = ((MSR & ~mask) | (SRR1 & mask)) & clearMSR13; + // R0 = MSR location + // R1 = MSR contents + // R2 = Mask + // R3 = Mask + ARM64Reg WA = gpr.GetReg(); + ARM64Reg WB = gpr.GetReg(); + ARM64Reg WC = gpr.GetReg(); - MOVI2R(WA, (~mask) & clearMSR13); - MOVI2R(WB, mask & clearMSR13); + MOVI2R(WA, (~mask) & clearMSR13); + MOVI2R(WB, mask & clearMSR13); - LDR(INDEX_UNSIGNED, WC, PPC_REG, PPCSTATE_OFF(msr)); + LDR(INDEX_UNSIGNED, WC, PPC_REG, PPCSTATE_OFF(msr)); - AND(WC, WC, WB, ArithOption(WC, ST_LSL, 0)); // rD = Masked MSR + AND(WC, WC, WB, ArithOption(WC, ST_LSL, 0)); // rD = Masked MSR - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_SRR1])); // rB contains SRR1 here + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_SRR1])); // rB contains SRR1 here - AND(WA, WA, WB, ArithOption(WA, ST_LSL, 0)); // rB contains masked SRR1 here - ORR(WA, WA, WC, ArithOption(WA, ST_LSL, 0)); // rB = Masked MSR OR masked SRR1 + AND(WA, WA, WB, ArithOption(WA, ST_LSL, 0)); // rB contains masked SRR1 here + ORR(WA, WA, WC, ArithOption(WA, ST_LSL, 0)); // rB = Masked MSR OR masked SRR1 - STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(msr)); // STR rB in to rA + STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(msr)); // STR rB in to rA - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_SRR0])); - gpr.Unlock(WB, WC); + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_SRR0])); + gpr.Unlock(WB, WC); - // WA is unlocked in this function - WriteExceptionExit(WA); + // WA is unlocked in this function + WriteExceptionExit(WA); } void JitArm64::bx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITBranchOff); + INSTRUCTION_START + JITDISABLE(bJITBranchOff); - gpr.Flush(FlushMode::FLUSH_ALL); - fpr.Flush(FlushMode::FLUSH_ALL); + gpr.Flush(FlushMode::FLUSH_ALL); + fpr.Flush(FlushMode::FLUSH_ALL); - u32 destination; - if (inst.AA) - destination = SignExt26(inst.LI << 2); - else - destination = js.compilerPC + SignExt26(inst.LI << 2); + u32 destination; + if (inst.AA) + destination = SignExt26(inst.LI << 2); + else + destination = js.compilerPC + SignExt26(inst.LI << 2); - if (inst.LK) - { - ARM64Reg WA = gpr.GetReg(); - MOVI2R(WA, js.compilerPC + 4); - STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_LR])); - gpr.Unlock(WA); - } + if (inst.LK) + { + ARM64Reg WA = gpr.GetReg(); + MOVI2R(WA, js.compilerPC + 4); + STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_LR])); + gpr.Unlock(WA); + } - if (destination == js.compilerPC) - { - // make idle loops go faster - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); + if (destination == js.compilerPC) + { + // make idle loops go faster + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); - MOVI2R(XA, (u64)&CoreTiming::Idle); - BLR(XA); - gpr.Unlock(WA); + MOVI2R(XA, (u64)&CoreTiming::Idle); + BLR(XA); + gpr.Unlock(WA); - WriteExceptionExit(js.compilerPC); - } + WriteExceptionExit(js.compilerPC); + } - WriteExit(destination); + WriteExit(destination); } void JitArm64::bcx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITBranchOff); + INSTRUCTION_START + JITDISABLE(bJITBranchOff); - ARM64Reg WA = gpr.GetReg(); - FixupBranch pCTRDontBranch; - if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR - { - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_CTR])); - SUBS(WA, WA, 1); - STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_CTR])); + ARM64Reg WA = gpr.GetReg(); + FixupBranch pCTRDontBranch; + if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR + { + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_CTR])); + SUBS(WA, WA, 1); + STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_CTR])); - if (inst.BO & BO_BRANCH_IF_CTR_0) - pCTRDontBranch = B(CC_NEQ); - else - pCTRDontBranch = B(CC_EQ); - } + if (inst.BO & BO_BRANCH_IF_CTR_0) + pCTRDontBranch = B(CC_NEQ); + else + pCTRDontBranch = B(CC_EQ); + } - FixupBranch pConditionDontBranch; + FixupBranch pConditionDontBranch; - if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit - { - pConditionDontBranch = JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3), - !(inst.BO_2 & BO_BRANCH_IF_TRUE)); - } + if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit + { + pConditionDontBranch = + JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3), !(inst.BO_2 & BO_BRANCH_IF_TRUE)); + } - FixupBranch far = B(); - SwitchToFarCode(); - SetJumpTarget(far); + FixupBranch far = B(); + SwitchToFarCode(); + SetJumpTarget(far); - if (inst.LK) - { - MOVI2R(WA, js.compilerPC + 4); - STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_LR])); - } - gpr.Unlock(WA); + if (inst.LK) + { + MOVI2R(WA, js.compilerPC + 4); + STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_LR])); + } + gpr.Unlock(WA); - u32 destination; - if (inst.AA) - destination = SignExt16(inst.BD << 2); - else - destination = js.compilerPC + SignExt16(inst.BD << 2); + u32 destination; + if (inst.AA) + destination = SignExt16(inst.BD << 2); + else + destination = js.compilerPC + SignExt16(inst.BD << 2); - gpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE); - fpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE); + gpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE); + fpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE); - WriteExit(destination); + WriteExit(destination); - SwitchToNearCode(); + SwitchToNearCode(); - if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) - SetJumpTarget( pConditionDontBranch ); - if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) - SetJumpTarget( pCTRDontBranch ); + if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) + SetJumpTarget(pConditionDontBranch); + if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) + SetJumpTarget(pCTRDontBranch); - if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) - { - gpr.Flush(FlushMode::FLUSH_ALL); - fpr.Flush(FlushMode::FLUSH_ALL); - WriteExit(js.compilerPC + 4); - } + if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) + { + gpr.Flush(FlushMode::FLUSH_ALL); + fpr.Flush(FlushMode::FLUSH_ALL); + WriteExit(js.compilerPC + 4); + } } void JitArm64::bcctrx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITBranchOff); + INSTRUCTION_START + JITDISABLE(bJITBranchOff); - // Rare condition seen in (just some versions of?) Nintendo's NES Emulator - // BO_2 == 001zy -> b if false - // BO_2 == 011zy -> b if true - FALLBACK_IF(!(inst.BO_2 & BO_DONT_CHECK_CONDITION)); + // Rare condition seen in (just some versions of?) Nintendo's NES Emulator + // BO_2 == 001zy -> b if false + // BO_2 == 011zy -> b if true + FALLBACK_IF(!(inst.BO_2 & BO_DONT_CHECK_CONDITION)); - // bcctrx doesn't decrement and/or test CTR - _assert_msg_(DYNA_REC, inst.BO_2 & BO_DONT_DECREMENT_FLAG, "bcctrx with decrement and test CTR option is invalid!"); + // bcctrx doesn't decrement and/or test CTR + _assert_msg_(DYNA_REC, inst.BO_2 & BO_DONT_DECREMENT_FLAG, + "bcctrx with decrement and test CTR option is invalid!"); - // BO_2 == 1z1zz -> b always + // BO_2 == 1z1zz -> b always - //NPC = CTR & 0xfffffffc; - gpr.Flush(FlushMode::FLUSH_ALL); - fpr.Flush(FlushMode::FLUSH_ALL); + // NPC = CTR & 0xfffffffc; + gpr.Flush(FlushMode::FLUSH_ALL); + fpr.Flush(FlushMode::FLUSH_ALL); - if (inst.LK_3) - { - ARM64Reg WB = gpr.GetReg(); - MOVI2R(WB, js.compilerPC + 4); - STR(INDEX_UNSIGNED, WB, PPC_REG, PPCSTATE_OFF(spr[SPR_LR])); - gpr.Unlock(WB); - } + if (inst.LK_3) + { + ARM64Reg WB = gpr.GetReg(); + MOVI2R(WB, js.compilerPC + 4); + STR(INDEX_UNSIGNED, WB, PPC_REG, PPCSTATE_OFF(spr[SPR_LR])); + gpr.Unlock(WB); + } - ARM64Reg WA = gpr.GetReg(); + ARM64Reg WA = gpr.GetReg(); - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_CTR])); - AND(WA, WA, 30, 29); // Wipe the bottom 2 bits. - WriteExit(WA); + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_CTR])); + AND(WA, WA, 30, 29); // Wipe the bottom 2 bits. + WriteExit(WA); } void JitArm64::bclrx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITBranchOff); + INSTRUCTION_START + JITDISABLE(bJITBranchOff); - bool conditional = (inst.BO & BO_DONT_DECREMENT_FLAG) == 0 || (inst.BO & BO_DONT_CHECK_CONDITION) == 0; + bool conditional = + (inst.BO & BO_DONT_DECREMENT_FLAG) == 0 || (inst.BO & BO_DONT_CHECK_CONDITION) == 0; - ARM64Reg WA = gpr.GetReg(); - FixupBranch pCTRDontBranch; - if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR - { - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_CTR])); - SUBS(WA, WA, 1); - STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_CTR])); + ARM64Reg WA = gpr.GetReg(); + FixupBranch pCTRDontBranch; + if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR + { + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_CTR])); + SUBS(WA, WA, 1); + STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_CTR])); - if (inst.BO & BO_BRANCH_IF_CTR_0) - pCTRDontBranch = B(CC_NEQ); - else - pCTRDontBranch = B(CC_EQ); - } + if (inst.BO & BO_BRANCH_IF_CTR_0) + pCTRDontBranch = B(CC_NEQ); + else + pCTRDontBranch = B(CC_EQ); + } - FixupBranch pConditionDontBranch; - if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit - { - pConditionDontBranch = JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3), - !(inst.BO_2 & BO_BRANCH_IF_TRUE)); - } + FixupBranch pConditionDontBranch; + if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit + { + pConditionDontBranch = + JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3), !(inst.BO_2 & BO_BRANCH_IF_TRUE)); + } - if (conditional) - { - FixupBranch far = B(); - SwitchToFarCode(); - SetJumpTarget(far); - } + if (conditional) + { + FixupBranch far = B(); + SwitchToFarCode(); + SetJumpTarget(far); + } - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_LR])); - AND(WA, WA, 30, 29); // Wipe the bottom 2 bits. + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(spr[SPR_LR])); + AND(WA, WA, 30, 29); // Wipe the bottom 2 bits. - if (inst.LK) - { - ARM64Reg WB = gpr.GetReg(); - MOVI2R(WB, js.compilerPC + 4); - STR(INDEX_UNSIGNED, WB, PPC_REG, PPCSTATE_OFF(spr[SPR_LR])); - gpr.Unlock(WB); - } + if (inst.LK) + { + ARM64Reg WB = gpr.GetReg(); + MOVI2R(WB, js.compilerPC + 4); + STR(INDEX_UNSIGNED, WB, PPC_REG, PPCSTATE_OFF(spr[SPR_LR])); + gpr.Unlock(WB); + } - gpr.Flush(conditional ? FlushMode::FLUSH_MAINTAIN_STATE : FlushMode::FLUSH_ALL); - fpr.Flush(conditional ? FlushMode::FLUSH_MAINTAIN_STATE : FlushMode::FLUSH_ALL); + gpr.Flush(conditional ? FlushMode::FLUSH_MAINTAIN_STATE : FlushMode::FLUSH_ALL); + fpr.Flush(conditional ? FlushMode::FLUSH_MAINTAIN_STATE : FlushMode::FLUSH_ALL); - WriteExit(WA); + WriteExit(WA); - if (conditional) - SwitchToNearCode(); + if (conditional) + SwitchToNearCode(); - if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) - SetJumpTarget( pConditionDontBranch ); - if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) - SetJumpTarget( pCTRDontBranch ); + if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) + SetJumpTarget(pConditionDontBranch); + if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) + SetJumpTarget(pCTRDontBranch); - if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) - { - gpr.Flush(FlushMode::FLUSH_ALL); - fpr.Flush(FlushMode::FLUSH_ALL); - WriteExit(js.compilerPC + 4); - } + if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) + { + gpr.Flush(FlushMode::FLUSH_ALL); + fpr.Flush(FlushMode::FLUSH_ALL); + WriteExit(js.compilerPC + 4); + } } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp index 3df45074e3..3ea2abdaf1 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp @@ -9,293 +9,344 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCTables.h" #include "Core/PowerPC/JitArm64/Jit.h" #include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" +#include "Core/PowerPC/PPCTables.h" +#include "Core/PowerPC/PowerPC.h" using namespace Arm64Gen; void JitArm64::fp_arith(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); - FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF); - u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; - u32 op5 = inst.SUBOP5; + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + u32 op5 = inst.SUBOP5; - bool single = inst.OPCD == 59; - bool packed = inst.OPCD == 4; + bool single = inst.OPCD == 59; + bool packed = inst.OPCD == 4; - bool use_c = op5 >= 25; // fmul and all kind of fmaddXX - bool use_b = op5 != 25; // fmul uses no B + bool use_c = op5 >= 25; // fmul and all kind of fmaddXX + bool use_b = op5 != 25; // fmul uses no B - bool inputs_are_singles = fpr.IsSingle(a, !packed) && (!use_b || fpr.IsSingle(b, !packed)) && (!use_c || fpr.IsSingle(c, !packed)); + bool inputs_are_singles = fpr.IsSingle(a, !packed) && (!use_b || fpr.IsSingle(b, !packed)) && + (!use_c || fpr.IsSingle(c, !packed)); - ARM64Reg VA, VB, VC, VD; + ARM64Reg VA, VB, VC, VD; - if (packed) - { - RegType type = inputs_are_singles ? REG_REG_SINGLE : REG_REG; - u8 size = inputs_are_singles ? 32 : 64; - ARM64Reg (*reg_encoder)(ARM64Reg) = inputs_are_singles ? EncodeRegToDouble : EncodeRegToQuad; + if (packed) + { + RegType type = inputs_are_singles ? REG_REG_SINGLE : REG_REG; + u8 size = inputs_are_singles ? 32 : 64; + ARM64Reg (*reg_encoder)(ARM64Reg) = inputs_are_singles ? EncodeRegToDouble : EncodeRegToQuad; - VA = reg_encoder(fpr.R(a, type)); - if (use_b) - VB = reg_encoder(fpr.R(b, type)); - if (use_c) - VC = reg_encoder(fpr.R(c, type)); - VD = reg_encoder(fpr.RW(d, type)); + VA = reg_encoder(fpr.R(a, type)); + if (use_b) + VB = reg_encoder(fpr.R(b, type)); + if (use_c) + VC = reg_encoder(fpr.R(c, type)); + VD = reg_encoder(fpr.RW(d, type)); - switch (op5) - { - case 18: m_float_emit.FDIV(size, VD, VA, VB); break; - case 20: m_float_emit.FSUB(size, VD, VA, VB); break; - case 21: m_float_emit.FADD(size, VD, VA, VB); break; - case 25: m_float_emit.FMUL(size, VD, VA, VC); break; - default: _assert_msg_(DYNA_REC, 0, "fp_arith"); break; - } - } - else - { - RegType type = (inputs_are_singles && single) ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR; - RegType type_out = single ? (inputs_are_singles ? REG_DUP_SINGLE : REG_DUP) : REG_LOWER_PAIR; - ARM64Reg (*reg_encoder)(ARM64Reg) = (inputs_are_singles && single) ? EncodeRegToSingle : EncodeRegToDouble; + switch (op5) + { + case 18: + m_float_emit.FDIV(size, VD, VA, VB); + break; + case 20: + m_float_emit.FSUB(size, VD, VA, VB); + break; + case 21: + m_float_emit.FADD(size, VD, VA, VB); + break; + case 25: + m_float_emit.FMUL(size, VD, VA, VC); + break; + default: + _assert_msg_(DYNA_REC, 0, "fp_arith"); + break; + } + } + else + { + RegType type = (inputs_are_singles && single) ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR; + RegType type_out = single ? (inputs_are_singles ? REG_DUP_SINGLE : REG_DUP) : REG_LOWER_PAIR; + ARM64Reg (*reg_encoder)(ARM64Reg) = + (inputs_are_singles && single) ? EncodeRegToSingle : EncodeRegToDouble; - VA = reg_encoder(fpr.R(a, type)); - if (use_b) - VB = reg_encoder(fpr.R(b, type)); - if (use_c) - VC = reg_encoder(fpr.R(c, type)); - VD = reg_encoder(fpr.RW(d, type_out)); + VA = reg_encoder(fpr.R(a, type)); + if (use_b) + VB = reg_encoder(fpr.R(b, type)); + if (use_c) + VC = reg_encoder(fpr.R(c, type)); + VD = reg_encoder(fpr.RW(d, type_out)); - switch (op5) - { - case 18: m_float_emit.FDIV(VD, VA, VB); break; - case 20: m_float_emit.FSUB(VD, VA, VB); break; - case 21: m_float_emit.FADD(VD, VA, VB); break; - case 25: m_float_emit.FMUL(VD, VA, VC); break; - case 28: m_float_emit.FNMSUB(VD, VA, VC, VB); break; // fmsub: "D = A*C - B" vs "Vd = (-Va) + Vn*Vm" - case 29: m_float_emit.FMADD(VD, VA, VC, VB); break; // fmadd: "D = A*C + B" vs "Vd = Va + Vn*Vm" - case 30: m_float_emit.FMSUB(VD, VA, VC, VB); break; // fnmsub: "D = -(A*C - B)" vs "Vd = Va + (-Vn)*Vm" - case 31: m_float_emit.FNMADD(VD, VA, VC, VB); break; // fnmadd: "D = -(A*C + B)" vs "Vd = (-Va) + (-Vn)*Vm" - default: _assert_msg_(DYNA_REC, 0, "fp_arith"); break; - } - } + switch (op5) + { + case 18: + m_float_emit.FDIV(VD, VA, VB); + break; + case 20: + m_float_emit.FSUB(VD, VA, VB); + break; + case 21: + m_float_emit.FADD(VD, VA, VB); + break; + case 25: + m_float_emit.FMUL(VD, VA, VC); + break; + case 28: + m_float_emit.FNMSUB(VD, VA, VC, VB); + break; // fmsub: "D = A*C - B" vs "Vd = (-Va) + Vn*Vm" + case 29: + m_float_emit.FMADD(VD, VA, VC, VB); + break; // fmadd: "D = A*C + B" vs "Vd = Va + Vn*Vm" + case 30: + m_float_emit.FMSUB(VD, VA, VC, VB); + break; // fnmsub: "D = -(A*C - B)" vs "Vd = Va + (-Vn)*Vm" + case 31: + m_float_emit.FNMADD(VD, VA, VC, VB); + break; // fnmadd: "D = -(A*C + B)" vs "Vd = (-Va) + (-Vn)*Vm" + default: + _assert_msg_(DYNA_REC, 0, "fp_arith"); + break; + } + } - if (single || packed) - fpr.FixSinglePrecision(d); + if (single || packed) + fpr.FixSinglePrecision(d); } void JitArm64::fp_logic(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); - u32 b = inst.FB, d = inst.FD; - u32 op10 = inst.SUBOP10; + u32 b = inst.FB, d = inst.FD; + u32 op10 = inst.SUBOP10; - bool packed = inst.OPCD == 4; + bool packed = inst.OPCD == 4; - // MR with source === dest => no-op - if (op10 == 72 && b == d) - return; + // MR with source === dest => no-op + if (op10 == 72 && b == d) + return; - bool single = fpr.IsSingle(b, !packed); - u8 size = single ? 32 : 64; + bool single = fpr.IsSingle(b, !packed); + u8 size = single ? 32 : 64; - if (packed) - { - RegType type = single ? REG_REG_SINGLE : REG_REG; - ARM64Reg (*reg_encoder)(ARM64Reg) = single ? EncodeRegToDouble : EncodeRegToQuad; + if (packed) + { + RegType type = single ? REG_REG_SINGLE : REG_REG; + ARM64Reg (*reg_encoder)(ARM64Reg) = single ? EncodeRegToDouble : EncodeRegToQuad; - ARM64Reg VB = reg_encoder(fpr.R(b, type)); - ARM64Reg VD = reg_encoder(fpr.RW(d, type)); + ARM64Reg VB = reg_encoder(fpr.R(b, type)); + ARM64Reg VD = reg_encoder(fpr.RW(d, type)); - switch (op10) - { - case 40: m_float_emit.FNEG(size, VD, VB); break; - case 72: m_float_emit.ORR(VD, VB, VB); break; - case 136: m_float_emit.FABS(size, VD, VB); - m_float_emit.FNEG(size, VD, VD); break; - case 264: m_float_emit.FABS(size, VD, VB); break; - default: _assert_msg_(DYNA_REC, 0, "fp_logic"); break; - } - } - else - { - RegType type = single ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR; - ARM64Reg (*reg_encoder)(ARM64Reg) = single ? EncodeRegToSingle : EncodeRegToDouble; + switch (op10) + { + case 40: + m_float_emit.FNEG(size, VD, VB); + break; + case 72: + m_float_emit.ORR(VD, VB, VB); + break; + case 136: + m_float_emit.FABS(size, VD, VB); + m_float_emit.FNEG(size, VD, VD); + break; + case 264: + m_float_emit.FABS(size, VD, VB); + break; + default: + _assert_msg_(DYNA_REC, 0, "fp_logic"); + break; + } + } + else + { + RegType type = single ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR; + ARM64Reg (*reg_encoder)(ARM64Reg) = single ? EncodeRegToSingle : EncodeRegToDouble; - ARM64Reg VB = fpr.R(b, type); - ARM64Reg VD = fpr.RW(d, type); + ARM64Reg VB = fpr.R(b, type); + ARM64Reg VD = fpr.RW(d, type); - switch (op10) - { - case 40: m_float_emit.FNEG(reg_encoder(VD), reg_encoder(VB)); break; - case 72: m_float_emit.INS(size, VD, 0, VB, 0); break; - case 136: m_float_emit.FABS(reg_encoder(VD), reg_encoder(VB)); - m_float_emit.FNEG(reg_encoder(VD), reg_encoder(VD)); break; - case 264: m_float_emit.FABS(reg_encoder(VD), reg_encoder(VB)); break; - default: _assert_msg_(DYNA_REC, 0, "fp_logic"); break; - } - } + switch (op10) + { + case 40: + m_float_emit.FNEG(reg_encoder(VD), reg_encoder(VB)); + break; + case 72: + m_float_emit.INS(size, VD, 0, VB, 0); + break; + case 136: + m_float_emit.FABS(reg_encoder(VD), reg_encoder(VB)); + m_float_emit.FNEG(reg_encoder(VD), reg_encoder(VD)); + break; + case 264: + m_float_emit.FABS(reg_encoder(VD), reg_encoder(VB)); + break; + default: + _assert_msg_(DYNA_REC, 0, "fp_logic"); + break; + } + } } void JitArm64::fselx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); - u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; - if (fpr.IsSingle(a, true)) - { - ARM64Reg VA = fpr.R(a, REG_LOWER_PAIR_SINGLE); - m_float_emit.FCMPE(EncodeRegToSingle(VA)); - } - else - { - ARM64Reg VA = fpr.R(a, REG_LOWER_PAIR); - m_float_emit.FCMPE(EncodeRegToDouble(VA)); - } + if (fpr.IsSingle(a, true)) + { + ARM64Reg VA = fpr.R(a, REG_LOWER_PAIR_SINGLE); + m_float_emit.FCMPE(EncodeRegToSingle(VA)); + } + else + { + ARM64Reg VA = fpr.R(a, REG_LOWER_PAIR); + m_float_emit.FCMPE(EncodeRegToDouble(VA)); + } - bool single = fpr.IsSingle(b, true) && fpr.IsSingle(c, true); - RegType type = single ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR; - ARM64Reg (*reg_encoder)(ARM64Reg) = single ? EncodeRegToSingle : EncodeRegToDouble; + bool single = fpr.IsSingle(b, true) && fpr.IsSingle(c, true); + RegType type = single ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR; + ARM64Reg (*reg_encoder)(ARM64Reg) = single ? EncodeRegToSingle : EncodeRegToDouble; - ARM64Reg VB = fpr.R(b, type); - ARM64Reg VC = fpr.R(c, type); - ARM64Reg VD = fpr.RW(d, type); + ARM64Reg VB = fpr.R(b, type); + ARM64Reg VC = fpr.R(c, type); + ARM64Reg VD = fpr.RW(d, type); - m_float_emit.FCSEL(reg_encoder(VD), reg_encoder(VC), reg_encoder(VB), CC_GE); + m_float_emit.FCSEL(reg_encoder(VD), reg_encoder(VC), reg_encoder(VB), CC_GE); } void JitArm64::frspx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); - FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); + FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF); - u32 b = inst.FB, d = inst.FD; + u32 b = inst.FB, d = inst.FD; - if (fpr.IsSingle(b, true)) - { - // Source is already in single precision, so no need to do anything but to copy to PSR1. - ARM64Reg VB = fpr.R(b, REG_LOWER_PAIR_SINGLE); - ARM64Reg VD = fpr.RW(d, REG_DUP_SINGLE); + if (fpr.IsSingle(b, true)) + { + // Source is already in single precision, so no need to do anything but to copy to PSR1. + ARM64Reg VB = fpr.R(b, REG_LOWER_PAIR_SINGLE); + ARM64Reg VD = fpr.RW(d, REG_DUP_SINGLE); - if (b != d) - m_float_emit.FMOV(EncodeRegToSingle(VD), EncodeRegToSingle(VB)); - } - else - { - ARM64Reg VB = fpr.R(b, REG_LOWER_PAIR); - ARM64Reg VD = fpr.RW(d, REG_DUP_SINGLE); + if (b != d) + m_float_emit.FMOV(EncodeRegToSingle(VD), EncodeRegToSingle(VB)); + } + else + { + ARM64Reg VB = fpr.R(b, REG_LOWER_PAIR); + ARM64Reg VD = fpr.RW(d, REG_DUP_SINGLE); - m_float_emit.FCVT(32, 64, EncodeRegToDouble(VD), EncodeRegToDouble(VB)); - } + m_float_emit.FCVT(32, 64, EncodeRegToDouble(VD), EncodeRegToDouble(VB)); + } } void JitArm64::fcmpX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF); - u32 a = inst.FA, b = inst.FB; - int crf = inst.CRFD; + u32 a = inst.FA, b = inst.FB; + int crf = inst.CRFD; - bool singles = fpr.IsSingle(a, true) && fpr.IsSingle(b, true); - RegType type = singles ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR; - ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToSingle : EncodeRegToDouble; + bool singles = fpr.IsSingle(a, true) && fpr.IsSingle(b, true); + RegType type = singles ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR; + ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToSingle : EncodeRegToDouble; - ARM64Reg VA = reg_encoder(fpr.R(a, type)); - ARM64Reg VB = reg_encoder(fpr.R(b, type)); + ARM64Reg VA = reg_encoder(fpr.R(a, type)); + ARM64Reg VB = reg_encoder(fpr.R(b, type)); - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); - FixupBranch pNaN, pLesser, pGreater; - FixupBranch continue1, continue2, continue3; - ORR(XA, ZR, 32, 0, true); + FixupBranch pNaN, pLesser, pGreater; + FixupBranch continue1, continue2, continue3; + ORR(XA, ZR, 32, 0, true); - m_float_emit.FCMP(VA, VB); + m_float_emit.FCMP(VA, VB); - if (a != b) - { - // if B > A goto Greater's jump target - pGreater = B(CC_GT); - // if B < A, goto Lesser's jump target - pLesser = B(CC_MI); - } + if (a != b) + { + // if B > A goto Greater's jump target + pGreater = B(CC_GT); + // if B < A, goto Lesser's jump target + pLesser = B(CC_MI); + } - pNaN = B(CC_VS); + pNaN = B(CC_VS); - // A == B - ORR(XA, XA, 64 - 63, 0, true); - continue1 = B(); + // A == B + ORR(XA, XA, 64 - 63, 0, true); + continue1 = B(); - SetJumpTarget(pNaN); + SetJumpTarget(pNaN); - MOVI2R(XA, PPCCRToInternal(CR_SO)); + MOVI2R(XA, PPCCRToInternal(CR_SO)); - if (a != b) - { - continue2 = B(); + if (a != b) + { + continue2 = B(); - SetJumpTarget(pGreater); - ORR(XA, XA, 0, 0, true); + SetJumpTarget(pGreater); + ORR(XA, XA, 0, 0, true); - continue3 = B(); + continue3 = B(); - SetJumpTarget(pLesser); - ORR(XA, XA, 64 - 62, 1, true); - ORR(XA, XA, 0, 0, true); + SetJumpTarget(pLesser); + ORR(XA, XA, 64 - 62, 1, true); + ORR(XA, XA, 0, 0, true); - SetJumpTarget(continue2); - SetJumpTarget(continue3); - } - SetJumpTarget(continue1); + SetJumpTarget(continue2); + SetJumpTarget(continue3); + } + SetJumpTarget(continue1); - STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[0]) + (sizeof(PowerPC::ppcState.cr_val[0]) * crf)); + STR(INDEX_UNSIGNED, XA, PPC_REG, + PPCSTATE_OFF(cr_val[0]) + (sizeof(PowerPC::ppcState.cr_val[0]) * crf)); - gpr.Unlock(WA); + gpr.Unlock(WA); } void JitArm64::fctiwzx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); - u32 b = inst.FB, d = inst.FD; + u32 b = inst.FB, d = inst.FD; - bool single = fpr.IsSingle(b, true); + bool single = fpr.IsSingle(b, true); - ARM64Reg VB = fpr.R(b, single ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR); - ARM64Reg VD = fpr.RW(d); + ARM64Reg VB = fpr.R(b, single ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR); + ARM64Reg VD = fpr.RW(d); - ARM64Reg V0 = fpr.GetReg(); + ARM64Reg V0 = fpr.GetReg(); - // Generate 0xFFF8000000000000ULL - m_float_emit.MOVI(64, EncodeRegToDouble(V0), 0xFFFF000000000000ULL); - m_float_emit.BIC(16, EncodeRegToDouble(V0), 0x7); + // Generate 0xFFF8000000000000ULL + m_float_emit.MOVI(64, EncodeRegToDouble(V0), 0xFFFF000000000000ULL); + m_float_emit.BIC(16, EncodeRegToDouble(V0), 0x7); - if (single) - { - m_float_emit.FCVTS(EncodeRegToSingle(VD), EncodeRegToSingle(VB), ROUND_Z); - } - else - { - m_float_emit.FCVT(32, 64, EncodeRegToDouble(VD), EncodeRegToDouble(VB)); - m_float_emit.FCVTS(EncodeRegToSingle(VD), EncodeRegToSingle(VD), ROUND_Z); - } - m_float_emit.ORR(EncodeRegToDouble(VD), EncodeRegToDouble(VD), EncodeRegToDouble(V0)); - fpr.Unlock(V0); + if (single) + { + m_float_emit.FCVTS(EncodeRegToSingle(VD), EncodeRegToSingle(VB), ROUND_Z); + } + else + { + m_float_emit.FCVT(32, 64, EncodeRegToDouble(VD), EncodeRegToDouble(VB)); + m_float_emit.FCVTS(EncodeRegToSingle(VD), EncodeRegToSingle(VD), ROUND_Z); + } + m_float_emit.ORR(EncodeRegToDouble(VD), EncodeRegToDouble(VD), EncodeRegToDouble(V0)); + fpr.Unlock(V0); } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index 4522b6e780..0144ef3832 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -9,1243 +9,1248 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCTables.h" #include "Core/PowerPC/JitArm64/Jit.h" #include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" +#include "Core/PowerPC/PPCTables.h" +#include "Core/PowerPC/PowerPC.h" using namespace Arm64Gen; void JitArm64::ComputeRC(ARM64Reg reg, int crf, bool needs_sext) { - if (needs_sext) - { - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); + if (needs_sext) + { + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); - SXTW(XA, reg); + SXTW(XA, reg); - STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[crf])); - gpr.Unlock(WA); - } - else - { - STR(INDEX_UNSIGNED, EncodeRegTo64(reg), PPC_REG, PPCSTATE_OFF(cr_val[crf])); - } + STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[crf])); + gpr.Unlock(WA); + } + else + { + STR(INDEX_UNSIGNED, EncodeRegTo64(reg), PPC_REG, PPCSTATE_OFF(cr_val[crf])); + } } void JitArm64::ComputeRC(u64 imm, int crf, bool needs_sext) { - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); - MOVI2R(XA, imm); - if (imm & 0x80000000 && needs_sext) - SXTW(XA, WA); + MOVI2R(XA, imm); + if (imm & 0x80000000 && needs_sext) + SXTW(XA, WA); - STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[crf])); - gpr.Unlock(WA); + STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[crf])); + gpr.Unlock(WA); } void JitArm64::ComputeCarry(bool Carry) { - if (!js.op->wantsCA) - return; + if (!js.op->wantsCA) + return; - if (Carry) - { - ARM64Reg WA = gpr.GetReg(); - MOVI2R(WA, 1); - STRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); - gpr.Unlock(WA); - return; - } + if (Carry) + { + ARM64Reg WA = gpr.GetReg(); + MOVI2R(WA, 1); + STRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); + gpr.Unlock(WA); + return; + } - STRB(INDEX_UNSIGNED, WSP, PPC_REG, PPCSTATE_OFF(xer_ca)); + STRB(INDEX_UNSIGNED, WSP, PPC_REG, PPCSTATE_OFF(xer_ca)); } void JitArm64::ComputeCarry() { - if (!js.op->wantsCA) - return; + if (!js.op->wantsCA) + return; - ARM64Reg WA = gpr.GetReg(); - CSINC(WA, WSP, WSP, CC_CC); - STRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); - gpr.Unlock(WA); + ARM64Reg WA = gpr.GetReg(); + CSINC(WA, WSP, WSP, CC_CC); + STRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); + gpr.Unlock(WA); } // Following static functions are used in conjunction with reg_imm static u32 Or(u32 a, u32 b) { - return a | b; + return a | b; } static u32 And(u32 a, u32 b) { - return a & b; + return a & b; } static u32 Xor(u32 a, u32 b) { - return a ^ b; + return a ^ b; } -void JitArm64::reg_imm(u32 d, u32 a, u32 value, Operation do_op, void (ARM64XEmitter::*op)(ARM64Reg, ARM64Reg, ARM64Reg, ArithOption), bool Rc) +void JitArm64::reg_imm(u32 d, u32 a, u32 value, Operation do_op, + void (ARM64XEmitter::*op)(ARM64Reg, ARM64Reg, ARM64Reg, ArithOption), + bool Rc) { - if (gpr.IsImm(a)) - { - gpr.SetImmediate(d, do_op(gpr.GetImm(a), value)); - if (Rc) - ComputeRC(gpr.GetImm(d)); - } - else - { - gpr.BindToRegister(d, d == a); - ARM64Reg WA = gpr.GetReg(); - MOVI2R(WA, value); - (this->*op)(gpr.R(d), gpr.R(a), WA, ArithOption(WA, ST_LSL, 0)); - gpr.Unlock(WA); + if (gpr.IsImm(a)) + { + gpr.SetImmediate(d, do_op(gpr.GetImm(a), value)); + if (Rc) + ComputeRC(gpr.GetImm(d)); + } + else + { + gpr.BindToRegister(d, d == a); + ARM64Reg WA = gpr.GetReg(); + MOVI2R(WA, value); + (this->*op)(gpr.R(d), gpr.R(a), WA, ArithOption(WA, ST_LSL, 0)); + gpr.Unlock(WA); - if (Rc) - ComputeRC(gpr.R(d), 0); - } + if (Rc) + ComputeRC(gpr.R(d), 0); + } } void JitArm64::arith_imm(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - u32 a = inst.RA, s = inst.RS; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + u32 a = inst.RA, s = inst.RS; - switch (inst.OPCD) - { - case 24: // ori - if (a == 0 && s == 0 && inst.UIMM == 0 && !inst.Rc) //check for nop - { - // NOP - return; - } - reg_imm(a, s, inst.UIMM, Or, &ARM64XEmitter::ORR); - break; - case 25: // oris - reg_imm(a, s, inst.UIMM << 16, Or, &ARM64XEmitter::ORR); - break; - case 28: // andi - reg_imm(a, s, inst.UIMM, And, &ARM64XEmitter::AND, true); - break; - case 29: // andis - reg_imm(a, s, inst.UIMM << 16, And, &ARM64XEmitter::AND, true); - break; - case 26: // xori - reg_imm(a, s, inst.UIMM, Xor, &ARM64XEmitter::EOR); - break; - case 27: // xoris - reg_imm(a, s, inst.UIMM << 16, Xor, &ARM64XEmitter::EOR); - break; - } + switch (inst.OPCD) + { + case 24: // ori + if (a == 0 && s == 0 && inst.UIMM == 0 && !inst.Rc) // check for nop + { + // NOP + return; + } + reg_imm(a, s, inst.UIMM, Or, &ARM64XEmitter::ORR); + break; + case 25: // oris + reg_imm(a, s, inst.UIMM << 16, Or, &ARM64XEmitter::ORR); + break; + case 28: // andi + reg_imm(a, s, inst.UIMM, And, &ARM64XEmitter::AND, true); + break; + case 29: // andis + reg_imm(a, s, inst.UIMM << 16, And, &ARM64XEmitter::AND, true); + break; + case 26: // xori + reg_imm(a, s, inst.UIMM, Xor, &ARM64XEmitter::EOR); + break; + case 27: // xoris + reg_imm(a, s, inst.UIMM << 16, Xor, &ARM64XEmitter::EOR); + break; + } } void JitArm64::addix(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - u32 d = inst.RD, a = inst.RA; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + u32 d = inst.RD, a = inst.RA; - u32 imm = (u32)(s32)inst.SIMM_16; - if (inst.OPCD == 15) - { - imm <<= 16; - } - u32 imm_neg = 0u - imm; + u32 imm = (u32)(s32)inst.SIMM_16; + if (inst.OPCD == 15) + { + imm <<= 16; + } + u32 imm_neg = 0u - imm; - if (a) - { - if (gpr.IsImm(a)) - { - gpr.SetImmediate(d, gpr.GetImm(a) + imm); - } - else - { - gpr.BindToRegister(d, d == a); + if (a) + { + if (gpr.IsImm(a)) + { + gpr.SetImmediate(d, gpr.GetImm(a) + imm); + } + else + { + gpr.BindToRegister(d, d == a); - if (imm < 4096) - { - ADD(gpr.R(d), gpr.R(a), imm); - } - else if (imm % 4096 == 0 && imm < 4096 * 4096) - { - ADD(gpr.R(d), gpr.R(a), imm / 4096, true); - } - else if (imm_neg < 4096) - { - SUB(gpr.R(d), gpr.R(a), imm_neg); - } - else if (imm_neg % 4096 == 0 && imm_neg < 4096 * 4096) - { - SUB(gpr.R(d), gpr.R(a), imm_neg / 4096, true); - } - else - { - ARM64Reg WA = gpr.GetReg(); - MOVI2R(WA, imm); - ADD(gpr.R(d), gpr.R(a), WA); - gpr.Unlock(WA); - } - } - } - else - { - // a == 0, implies zero register - gpr.SetImmediate(d, imm); - } + if (imm < 4096) + { + ADD(gpr.R(d), gpr.R(a), imm); + } + else if (imm % 4096 == 0 && imm < 4096 * 4096) + { + ADD(gpr.R(d), gpr.R(a), imm / 4096, true); + } + else if (imm_neg < 4096) + { + SUB(gpr.R(d), gpr.R(a), imm_neg); + } + else if (imm_neg % 4096 == 0 && imm_neg < 4096 * 4096) + { + SUB(gpr.R(d), gpr.R(a), imm_neg / 4096, true); + } + else + { + ARM64Reg WA = gpr.GetReg(); + MOVI2R(WA, imm); + ADD(gpr.R(d), gpr.R(a), WA); + gpr.Unlock(WA); + } + } + } + else + { + // a == 0, implies zero register + gpr.SetImmediate(d, imm); + } } void JitArm64::boolX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA, s = inst.RS, b = inst.RB; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA, s = inst.RS, b = inst.RB; - if (gpr.IsImm(s) && gpr.IsImm(b)) - { - if (inst.SUBOP10 == 28) // andx - gpr.SetImmediate(a, (u32)gpr.GetImm(s) & (u32)gpr.GetImm(b)); - else if (inst.SUBOP10 == 476) // nandx - gpr.SetImmediate(a, ~((u32)gpr.GetImm(s) & (u32)gpr.GetImm(b))); - else if (inst.SUBOP10 == 60) // andcx - gpr.SetImmediate(a, (u32)gpr.GetImm(s) & (~(u32)gpr.GetImm(b))); - else if (inst.SUBOP10 == 444) // orx - gpr.SetImmediate(a, (u32)gpr.GetImm(s) | (u32)gpr.GetImm(b)); - else if (inst.SUBOP10 == 124) // norx - gpr.SetImmediate(a, ~((u32)gpr.GetImm(s) | (u32)gpr.GetImm(b))); - else if (inst.SUBOP10 == 412) // orcx - gpr.SetImmediate(a, (u32)gpr.GetImm(s) | (~(u32)gpr.GetImm(b))); - else if (inst.SUBOP10 == 316) // xorx - gpr.SetImmediate(a, (u32)gpr.GetImm(s) ^ (u32)gpr.GetImm(b)); - else if (inst.SUBOP10 == 284) // eqvx - gpr.SetImmediate(a, ~((u32)gpr.GetImm(s) ^ (u32)gpr.GetImm(b))); + if (gpr.IsImm(s) && gpr.IsImm(b)) + { + if (inst.SUBOP10 == 28) // andx + gpr.SetImmediate(a, (u32)gpr.GetImm(s) & (u32)gpr.GetImm(b)); + else if (inst.SUBOP10 == 476) // nandx + gpr.SetImmediate(a, ~((u32)gpr.GetImm(s) & (u32)gpr.GetImm(b))); + else if (inst.SUBOP10 == 60) // andcx + gpr.SetImmediate(a, (u32)gpr.GetImm(s) & (~(u32)gpr.GetImm(b))); + else if (inst.SUBOP10 == 444) // orx + gpr.SetImmediate(a, (u32)gpr.GetImm(s) | (u32)gpr.GetImm(b)); + else if (inst.SUBOP10 == 124) // norx + gpr.SetImmediate(a, ~((u32)gpr.GetImm(s) | (u32)gpr.GetImm(b))); + else if (inst.SUBOP10 == 412) // orcx + gpr.SetImmediate(a, (u32)gpr.GetImm(s) | (~(u32)gpr.GetImm(b))); + else if (inst.SUBOP10 == 316) // xorx + gpr.SetImmediate(a, (u32)gpr.GetImm(s) ^ (u32)gpr.GetImm(b)); + else if (inst.SUBOP10 == 284) // eqvx + gpr.SetImmediate(a, ~((u32)gpr.GetImm(s) ^ (u32)gpr.GetImm(b))); - if (inst.Rc) - ComputeRC(gpr.GetImm(a), 0); - } - else if (s == b) - { - if ((inst.SUBOP10 == 28 /* andx */) || (inst.SUBOP10 == 444 /* orx */)) - { - if (a != s) - { - gpr.BindToRegister(a, false); - MOV(gpr.R(a), gpr.R(s)); - } - if (inst.Rc) - ComputeRC(gpr.R(a)); - } - else if ((inst.SUBOP10 == 476 /* nandx */) || (inst.SUBOP10 == 124 /* norx */)) - { - gpr.BindToRegister(a, a == s); - MVN(gpr.R(a), gpr.R(s)); - if (inst.Rc) - ComputeRC(gpr.R(a)); - } - else if ((inst.SUBOP10 == 412 /* orcx */) || (inst.SUBOP10 == 284 /* eqvx */)) - { - gpr.SetImmediate(a, 0xFFFFFFFF); - if (inst.Rc) - ComputeRC(gpr.GetImm(a), 0); - } - else if ((inst.SUBOP10 == 60 /* andcx */) || (inst.SUBOP10 == 316 /* xorx */)) - { - gpr.SetImmediate(a, 0); - if (inst.Rc) - ComputeRC(gpr.GetImm(a), 0); - } - else - { - PanicAlert("WTF!"); - } - } - else - { - gpr.BindToRegister(a, (a == s) || (a == b)); - if (inst.SUBOP10 == 28) // andx - { - AND(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); - } - else if (inst.SUBOP10 == 476) // nandx - { - AND(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); - MVN(gpr.R(a), gpr.R(a)); - } - else if (inst.SUBOP10 == 60) // andcx - { - BIC(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); - } - else if (inst.SUBOP10 == 444) // orx - { - ORR(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); - } - else if (inst.SUBOP10 == 124) // norx - { - ORR(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); - MVN(gpr.R(a), gpr.R(a)); - } - else if (inst.SUBOP10 == 412) // orcx - { - ORN(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); - } - else if (inst.SUBOP10 == 316) // xorx - { - EOR(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); - } - else if (inst.SUBOP10 == 284) // eqvx - { - EON(gpr.R(a), gpr.R(b), gpr.R(s), ArithOption(gpr.R(a), ST_LSL, 0)); - } - else - { - PanicAlert("WTF!"); - } - if (inst.Rc) - ComputeRC(gpr.R(a), 0); - } + if (inst.Rc) + ComputeRC(gpr.GetImm(a), 0); + } + else if (s == b) + { + if ((inst.SUBOP10 == 28 /* andx */) || (inst.SUBOP10 == 444 /* orx */)) + { + if (a != s) + { + gpr.BindToRegister(a, false); + MOV(gpr.R(a), gpr.R(s)); + } + if (inst.Rc) + ComputeRC(gpr.R(a)); + } + else if ((inst.SUBOP10 == 476 /* nandx */) || (inst.SUBOP10 == 124 /* norx */)) + { + gpr.BindToRegister(a, a == s); + MVN(gpr.R(a), gpr.R(s)); + if (inst.Rc) + ComputeRC(gpr.R(a)); + } + else if ((inst.SUBOP10 == 412 /* orcx */) || (inst.SUBOP10 == 284 /* eqvx */)) + { + gpr.SetImmediate(a, 0xFFFFFFFF); + if (inst.Rc) + ComputeRC(gpr.GetImm(a), 0); + } + else if ((inst.SUBOP10 == 60 /* andcx */) || (inst.SUBOP10 == 316 /* xorx */)) + { + gpr.SetImmediate(a, 0); + if (inst.Rc) + ComputeRC(gpr.GetImm(a), 0); + } + else + { + PanicAlert("WTF!"); + } + } + else + { + gpr.BindToRegister(a, (a == s) || (a == b)); + if (inst.SUBOP10 == 28) // andx + { + AND(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); + } + else if (inst.SUBOP10 == 476) // nandx + { + AND(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); + MVN(gpr.R(a), gpr.R(a)); + } + else if (inst.SUBOP10 == 60) // andcx + { + BIC(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); + } + else if (inst.SUBOP10 == 444) // orx + { + ORR(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); + } + else if (inst.SUBOP10 == 124) // norx + { + ORR(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); + MVN(gpr.R(a), gpr.R(a)); + } + else if (inst.SUBOP10 == 412) // orcx + { + ORN(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); + } + else if (inst.SUBOP10 == 316) // xorx + { + EOR(gpr.R(a), gpr.R(s), gpr.R(b), ArithOption(gpr.R(a), ST_LSL, 0)); + } + else if (inst.SUBOP10 == 284) // eqvx + { + EON(gpr.R(a), gpr.R(b), gpr.R(s), ArithOption(gpr.R(a), ST_LSL, 0)); + } + else + { + PanicAlert("WTF!"); + } + if (inst.Rc) + ComputeRC(gpr.R(a), 0); + } } void JitArm64::addx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - FALLBACK_IF(inst.OE); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + FALLBACK_IF(inst.OE); - int a = inst.RA, b = inst.RB, d = inst.RD; + int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.IsImm(a) && gpr.IsImm(b)) - { - s32 i = (s32)gpr.GetImm(a), j = (s32)gpr.GetImm(b); - gpr.SetImmediate(d, i + j); - if (inst.Rc) - ComputeRC(gpr.GetImm(d), 0); - } - else if (gpr.IsImm(a) || gpr.IsImm(b)) - { - int imm_reg = gpr.IsImm(a) ? a : b; - int in_reg = gpr.IsImm(a) ? b : a; - gpr.BindToRegister(d, d == in_reg); - if (gpr.GetImm(imm_reg) < 4096) - { - ADD(gpr.R(d), gpr.R(in_reg), gpr.GetImm(imm_reg)); - } - else - { - ARM64Reg WA = gpr.GetReg(); - MOVI2R(WA, gpr.GetImm(imm_reg)); - ADD(gpr.R(d), gpr.R(in_reg), WA); - gpr.Unlock(WA); - } - if (inst.Rc) - ComputeRC(gpr.R(d), 0); - } - else - { - gpr.BindToRegister(d, d == a || d == b); - ADD(gpr.R(d), gpr.R(a), gpr.R(b)); - if (inst.Rc) - ComputeRC(gpr.R(d), 0); - } + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + s32 i = (s32)gpr.GetImm(a), j = (s32)gpr.GetImm(b); + gpr.SetImmediate(d, i + j); + if (inst.Rc) + ComputeRC(gpr.GetImm(d), 0); + } + else if (gpr.IsImm(a) || gpr.IsImm(b)) + { + int imm_reg = gpr.IsImm(a) ? a : b; + int in_reg = gpr.IsImm(a) ? b : a; + gpr.BindToRegister(d, d == in_reg); + if (gpr.GetImm(imm_reg) < 4096) + { + ADD(gpr.R(d), gpr.R(in_reg), gpr.GetImm(imm_reg)); + } + else + { + ARM64Reg WA = gpr.GetReg(); + MOVI2R(WA, gpr.GetImm(imm_reg)); + ADD(gpr.R(d), gpr.R(in_reg), WA); + gpr.Unlock(WA); + } + if (inst.Rc) + ComputeRC(gpr.R(d), 0); + } + else + { + gpr.BindToRegister(d, d == a || d == b); + ADD(gpr.R(d), gpr.R(a), gpr.R(b)); + if (inst.Rc) + ComputeRC(gpr.R(d), 0); + } } void JitArm64::extsXx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA, s = inst.RS; - int size = inst.SUBOP10 == 922 ? 16 : 8; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA, s = inst.RS; + int size = inst.SUBOP10 == 922 ? 16 : 8; - if (gpr.IsImm(s)) - { - gpr.SetImmediate(a, (u32)(s32)(size == 16 ? (s16)gpr.GetImm(s) : (s8)gpr.GetImm(s))); - if (inst.Rc) - ComputeRC(gpr.GetImm(a), 0); - } - else - { - gpr.BindToRegister(a, a == s); - SBFM(gpr.R(a), gpr.R(s), 0, size - 1); - if (inst.Rc) - ComputeRC(gpr.R(a), 0); - } + if (gpr.IsImm(s)) + { + gpr.SetImmediate(a, (u32)(s32)(size == 16 ? (s16)gpr.GetImm(s) : (s8)gpr.GetImm(s))); + if (inst.Rc) + ComputeRC(gpr.GetImm(a), 0); + } + else + { + gpr.BindToRegister(a, a == s); + SBFM(gpr.R(a), gpr.R(s), 0, size - 1); + if (inst.Rc) + ComputeRC(gpr.R(a), 0); + } } void JitArm64::cntlzwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA; - int s = inst.RS; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA; + int s = inst.RS; - if (gpr.IsImm(s)) - { - gpr.SetImmediate(a, __builtin_clz(gpr.GetImm(s))); - if (inst.Rc) - ComputeRC(gpr.GetImm(a), 0); - } - else - { - gpr.BindToRegister(a, a == s); - CLZ(gpr.R(a), gpr.R(s)); - if (inst.Rc) - ComputeRC(gpr.R(a), 0); - } + if (gpr.IsImm(s)) + { + gpr.SetImmediate(a, __builtin_clz(gpr.GetImm(s))); + if (inst.Rc) + ComputeRC(gpr.GetImm(a), 0); + } + else + { + gpr.BindToRegister(a, a == s); + CLZ(gpr.R(a), gpr.R(s)); + if (inst.Rc) + ComputeRC(gpr.R(a), 0); + } } void JitArm64::negx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int a = inst.RA; - int d = inst.RD; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA; + int d = inst.RD; - FALLBACK_IF(inst.OE); + FALLBACK_IF(inst.OE); - if (gpr.IsImm(a)) - { - gpr.SetImmediate(d, ~((u32)gpr.GetImm(a)) + 1); - if (inst.Rc) - ComputeRC(gpr.GetImm(d), 0); - } - else - { - gpr.BindToRegister(d, d == a); - SUB(gpr.R(d), WSP, gpr.R(a), ArithOption(gpr.R(a), ST_LSL, 0)); - if (inst.Rc) - ComputeRC(gpr.R(d), 0); - } + if (gpr.IsImm(a)) + { + gpr.SetImmediate(d, ~((u32)gpr.GetImm(a)) + 1); + if (inst.Rc) + ComputeRC(gpr.GetImm(d), 0); + } + else + { + gpr.BindToRegister(d, d == a); + SUB(gpr.R(d), WSP, gpr.R(a), ArithOption(gpr.R(a), ST_LSL, 0)); + if (inst.Rc) + ComputeRC(gpr.R(d), 0); + } } void JitArm64::cmp(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - int crf = inst.CRFD; - u32 a = inst.RA, b = inst.RB; + int crf = inst.CRFD; + u32 a = inst.RA, b = inst.RB; - if (gpr.IsImm(a) && gpr.IsImm(b)) - { - ComputeRC((s32)gpr.GetImm(a) - (s32)gpr.GetImm(b), crf); - return; - } + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + ComputeRC((s32)gpr.GetImm(a) - (s32)gpr.GetImm(b), crf); + return; + } - ARM64Reg WA = gpr.GetReg(); - ARM64Reg WB = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); - ARM64Reg XB = EncodeRegTo64(WB); - ARM64Reg RA = gpr.R(a); - ARM64Reg RB = gpr.R(b); - SXTW(XA, RA); - SXTW(XB, RB); + ARM64Reg WA = gpr.GetReg(); + ARM64Reg WB = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); + ARM64Reg XB = EncodeRegTo64(WB); + ARM64Reg RA = gpr.R(a); + ARM64Reg RB = gpr.R(b); + SXTW(XA, RA); + SXTW(XB, RB); - SUB(XA, XA, XB); - STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[0]) + (sizeof(PowerPC::ppcState.cr_val[0]) * crf)); + SUB(XA, XA, XB); + STR(INDEX_UNSIGNED, XA, PPC_REG, + PPCSTATE_OFF(cr_val[0]) + (sizeof(PowerPC::ppcState.cr_val[0]) * crf)); - gpr.Unlock(WA, WB); + gpr.Unlock(WA, WB); } void JitArm64::cmpl(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - int crf = inst.CRFD; - u32 a = inst.RA, b = inst.RB; + int crf = inst.CRFD; + u32 a = inst.RA, b = inst.RB; - if (gpr.IsImm(a) && gpr.IsImm(b)) - { - ComputeRC(gpr.GetImm(a) - gpr.GetImm(b), crf); - return; - } - else if (gpr.IsImm(b) && !gpr.GetImm(b)) - { - ComputeRC(gpr.R(a), crf); - return; - } + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + ComputeRC(gpr.GetImm(a) - gpr.GetImm(b), crf); + return; + } + else if (gpr.IsImm(b) && !gpr.GetImm(b)) + { + ComputeRC(gpr.R(a), crf); + return; + } - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); - SUB(XA, EncodeRegTo64(gpr.R(a)), EncodeRegTo64(gpr.R(b))); - STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[0]) + (sizeof(PowerPC::ppcState.cr_val[0]) * crf)); - gpr.Unlock(WA); + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); + SUB(XA, EncodeRegTo64(gpr.R(a)), EncodeRegTo64(gpr.R(b))); + STR(INDEX_UNSIGNED, XA, PPC_REG, + PPCSTATE_OFF(cr_val[0]) + (sizeof(PowerPC::ppcState.cr_val[0]) * crf)); + gpr.Unlock(WA); } void JitArm64::cmpi(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - u32 a = inst.RA; - int crf = inst.CRFD; - if (gpr.IsImm(a)) - { - ComputeRC((s32)gpr.GetImm(a) - inst.SIMM_16, crf); - return; - } + u32 a = inst.RA; + int crf = inst.CRFD; + if (gpr.IsImm(a)) + { + ComputeRC((s32)gpr.GetImm(a) - inst.SIMM_16, crf); + return; + } - ARM64Reg WA = gpr.GetReg(); + ARM64Reg WA = gpr.GetReg(); - if (inst.SIMM_16 >= 0 && inst.SIMM_16 < 4096) - { - SUB(WA, gpr.R(a), inst.SIMM_16); - } - else - { - MOVI2R(WA, inst.SIMM_16); - SUB(WA, gpr.R(a), WA); - } + if (inst.SIMM_16 >= 0 && inst.SIMM_16 < 4096) + { + SUB(WA, gpr.R(a), inst.SIMM_16); + } + else + { + MOVI2R(WA, inst.SIMM_16); + SUB(WA, gpr.R(a), WA); + } - ComputeRC(WA, crf); + ComputeRC(WA, crf); - gpr.Unlock(WA); + gpr.Unlock(WA); } void JitArm64::cmpli(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - u32 a = inst.RA; - int crf = inst.CRFD; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + u32 a = inst.RA; + int crf = inst.CRFD; - if (gpr.IsImm(a)) - { - ComputeRC((u64)gpr.GetImm(a) - inst.UIMM, crf, false); - return; - } + if (gpr.IsImm(a)) + { + ComputeRC((u64)gpr.GetImm(a) - inst.UIMM, crf, false); + return; + } - if (!inst.UIMM) - { - ComputeRC(gpr.R(a), crf, false); - return; - } + if (!inst.UIMM) + { + ComputeRC(gpr.R(a), crf, false); + return; + } - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); - if (inst.UIMM < 4096) - { - SUB(XA, EncodeRegTo64(gpr.R(a)), inst.UIMM); - } - else - { - MOVI2R(WA, inst.UIMM); - SUB(XA, EncodeRegTo64(gpr.R(a)), XA); - } + if (inst.UIMM < 4096) + { + SUB(XA, EncodeRegTo64(gpr.R(a)), inst.UIMM); + } + else + { + MOVI2R(WA, inst.UIMM); + SUB(XA, EncodeRegTo64(gpr.R(a)), XA); + } - STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[0]) + (sizeof(PowerPC::ppcState.cr_val[0]) * crf)); - gpr.Unlock(WA); + STR(INDEX_UNSIGNED, XA, PPC_REG, + PPCSTATE_OFF(cr_val[0]) + (sizeof(PowerPC::ppcState.cr_val[0]) * crf)); + gpr.Unlock(WA); } void JitArm64::rlwinmx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - u32 a = inst.RA, s = inst.RS; + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + u32 a = inst.RA, s = inst.RS; - u32 mask = Helper_Mask(inst.MB, inst.ME); - if (gpr.IsImm(inst.RS)) - { - gpr.SetImmediate(a, _rotl(gpr.GetImm(s), inst.SH) & mask); - if (inst.Rc) - ComputeRC(gpr.GetImm(a), 0); - return; - } + u32 mask = Helper_Mask(inst.MB, inst.ME); + if (gpr.IsImm(inst.RS)) + { + gpr.SetImmediate(a, _rotl(gpr.GetImm(s), inst.SH) & mask); + if (inst.Rc) + ComputeRC(gpr.GetImm(a), 0); + return; + } - gpr.BindToRegister(a, a == s); + gpr.BindToRegister(a, a == s); - ARM64Reg WA = gpr.GetReg(); - ArithOption Shift(gpr.R(s), ST_ROR, 32 - inst.SH); - MOVI2R(WA, mask); - AND(gpr.R(a), WA, gpr.R(s), Shift); - gpr.Unlock(WA); + ARM64Reg WA = gpr.GetReg(); + ArithOption Shift(gpr.R(s), ST_ROR, 32 - inst.SH); + MOVI2R(WA, mask); + AND(gpr.R(a), WA, gpr.R(s), Shift); + gpr.Unlock(WA); - if (inst.Rc) - ComputeRC(gpr.R(a), 0); + if (inst.Rc) + ComputeRC(gpr.R(a), 0); } void JitArm64::rlwnmx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - u32 a = inst.RA, b = inst.RB, s = inst.RS; - u32 mask = Helper_Mask(inst.MB, inst.ME); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + u32 a = inst.RA, b = inst.RB, s = inst.RS; + u32 mask = Helper_Mask(inst.MB, inst.ME); - if (gpr.IsImm(b) && gpr.IsImm(s)) - { - gpr.SetImmediate(a, _rotl(gpr.GetImm(s), gpr.GetImm(b) & 0x1F) & mask); - if (inst.Rc) - ComputeRC(gpr.GetImm(a), 0); - } - else if (gpr.IsImm(b)) - { - gpr.BindToRegister(a, a == s); - ARM64Reg WA = gpr.GetReg(); - ArithOption Shift(gpr.R(s), ST_ROR, 32 - (gpr.GetImm(b) & 0x1f)); - MOVI2R(WA, mask); - AND(gpr.R(a), WA, gpr.R(s), Shift); - gpr.Unlock(WA); - if (inst.Rc) - ComputeRC(gpr.R(a), 0); - } - else - { - gpr.BindToRegister(a, a == s || a == b); - ARM64Reg WA = gpr.GetReg(); - NEG(WA, gpr.R(b)); - RORV(gpr.R(a), gpr.R(s), WA); - ANDI2R(gpr.R(a), gpr.R(a), mask, WA); - gpr.Unlock(WA); - if (inst.Rc) - ComputeRC(gpr.R(a), 0); - } + if (gpr.IsImm(b) && gpr.IsImm(s)) + { + gpr.SetImmediate(a, _rotl(gpr.GetImm(s), gpr.GetImm(b) & 0x1F) & mask); + if (inst.Rc) + ComputeRC(gpr.GetImm(a), 0); + } + else if (gpr.IsImm(b)) + { + gpr.BindToRegister(a, a == s); + ARM64Reg WA = gpr.GetReg(); + ArithOption Shift(gpr.R(s), ST_ROR, 32 - (gpr.GetImm(b) & 0x1f)); + MOVI2R(WA, mask); + AND(gpr.R(a), WA, gpr.R(s), Shift); + gpr.Unlock(WA); + if (inst.Rc) + ComputeRC(gpr.R(a), 0); + } + else + { + gpr.BindToRegister(a, a == s || a == b); + ARM64Reg WA = gpr.GetReg(); + NEG(WA, gpr.R(b)); + RORV(gpr.R(a), gpr.R(s), WA); + ANDI2R(gpr.R(a), gpr.R(a), mask, WA); + gpr.Unlock(WA); + if (inst.Rc) + ComputeRC(gpr.R(a), 0); + } } void JitArm64::srawix(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - int a = inst.RA; - int s = inst.RS; - int amount = inst.SH; + int a = inst.RA; + int s = inst.RS; + int amount = inst.SH; - if (gpr.IsImm(s)) - { - s32 imm = (s32)gpr.GetImm(s); - gpr.SetImmediate(a, imm >> amount); + if (gpr.IsImm(s)) + { + s32 imm = (s32)gpr.GetImm(s); + gpr.SetImmediate(a, imm >> amount); - if (amount != 0 && (imm < 0) && (imm << (32 - amount))) - ComputeCarry(true); - else - ComputeCarry(false); - } - else if (amount != 0) - { - gpr.BindToRegister(a, a == s); - ARM64Reg RA = gpr.R(a); - ARM64Reg RS = gpr.R(s); - ARM64Reg WA = gpr.GetReg(); + if (amount != 0 && (imm < 0) && (imm << (32 - amount))) + ComputeCarry(true); + else + ComputeCarry(false); + } + else if (amount != 0) + { + gpr.BindToRegister(a, a == s); + ARM64Reg RA = gpr.R(a); + ARM64Reg RS = gpr.R(s); + ARM64Reg WA = gpr.GetReg(); - ORR(WA, WSP, RS, ArithOption(RS, ST_LSL, 32 - amount)); - ORR(RA, WSP, RS, ArithOption(RS, ST_ASR, amount)); - if (inst.Rc) - ComputeRC(RA, 0); + ORR(WA, WSP, RS, ArithOption(RS, ST_LSL, 32 - amount)); + ORR(RA, WSP, RS, ArithOption(RS, ST_ASR, amount)); + if (inst.Rc) + ComputeRC(RA, 0); - ANDS(WSP, WA, RA, ArithOption(RA, ST_LSL, 0)); - CSINC(WA, WSP, WSP, CC_EQ); - STRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); - gpr.Unlock(WA); - } - else - { - gpr.BindToRegister(a, a == s); - ARM64Reg RA = gpr.R(a); - ARM64Reg RS = gpr.R(s); - MOV(RA, RS); - STRB(INDEX_UNSIGNED, WSP, PPC_REG, PPCSTATE_OFF(xer_ca)); - } + ANDS(WSP, WA, RA, ArithOption(RA, ST_LSL, 0)); + CSINC(WA, WSP, WSP, CC_EQ); + STRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); + gpr.Unlock(WA); + } + else + { + gpr.BindToRegister(a, a == s); + ARM64Reg RA = gpr.R(a); + ARM64Reg RS = gpr.R(s); + MOV(RA, RS); + STRB(INDEX_UNSIGNED, WSP, PPC_REG, PPCSTATE_OFF(xer_ca)); + } } void JitArm64::addic(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - int a = inst.RA, d = inst.RD; - bool rc = inst.OPCD == 13; - s32 simm = inst.SIMM_16; - u32 imm = (u32)simm; + int a = inst.RA, d = inst.RD; + bool rc = inst.OPCD == 13; + s32 simm = inst.SIMM_16; + u32 imm = (u32)simm; - if (gpr.IsImm(a)) - { + if (gpr.IsImm(a)) + { + u32 i = gpr.GetImm(a); + gpr.SetImmediate(d, i + imm); - u32 i = gpr.GetImm(a); - gpr.SetImmediate(d, i + imm); + bool has_carry = Interpreter::Helper_Carry(i, imm); + ComputeCarry(has_carry); + if (rc) + ComputeRC(gpr.GetImm(d), 0); + } + else + { + gpr.BindToRegister(d, d == a); + if (imm < 4096) + { + ADDS(gpr.R(d), gpr.R(a), imm); + } + else if (simm > -4096 && simm < 0) + { + SUBS(gpr.R(d), gpr.R(a), std::abs(simm)); + } + else + { + ARM64Reg WA = gpr.GetReg(); + MOVI2R(WA, imm); + ADDS(gpr.R(d), gpr.R(a), WA); + gpr.Unlock(WA); + } - bool has_carry = Interpreter::Helper_Carry(i, imm); - ComputeCarry(has_carry); - if (rc) - ComputeRC(gpr.GetImm(d), 0); - } - else - { - gpr.BindToRegister(d, d == a); - if (imm < 4096) - { - ADDS(gpr.R(d), gpr.R(a), imm); - } - else if (simm > -4096 && simm < 0) - { - SUBS(gpr.R(d), gpr.R(a), std::abs(simm)); - } - else - { - ARM64Reg WA = gpr.GetReg(); - MOVI2R(WA, imm); - ADDS(gpr.R(d), gpr.R(a), WA); - gpr.Unlock(WA); - } - - ComputeCarry(); - if (rc) - ComputeRC(gpr.R(d), 0); - } + ComputeCarry(); + if (rc) + ComputeRC(gpr.R(d), 0); + } } void JitArm64::mulli(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - int a = inst.RA, d = inst.RD; + int a = inst.RA, d = inst.RD; - if (gpr.IsImm(a)) - { - s32 i = (s32)gpr.GetImm(a); - gpr.SetImmediate(d, i * inst.SIMM_16); - } - else - { - gpr.BindToRegister(d, d == a); - ARM64Reg WA = gpr.GetReg(); - MOVI2R(WA, (u32)(s32)inst.SIMM_16); - MUL(gpr.R(d), gpr.R(a), WA); - gpr.Unlock(WA); - } + if (gpr.IsImm(a)) + { + s32 i = (s32)gpr.GetImm(a); + gpr.SetImmediate(d, i * inst.SIMM_16); + } + else + { + gpr.BindToRegister(d, d == a); + ARM64Reg WA = gpr.GetReg(); + MOVI2R(WA, (u32)(s32)inst.SIMM_16); + MUL(gpr.R(d), gpr.R(a), WA); + gpr.Unlock(WA); + } } void JitArm64::mullwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - FALLBACK_IF(inst.OE); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + FALLBACK_IF(inst.OE); - int a = inst.RA, b = inst.RB, d = inst.RD; + int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.IsImm(a) && gpr.IsImm(b)) - { - s32 i = (s32)gpr.GetImm(a), j = (s32)gpr.GetImm(b); - gpr.SetImmediate(d, i * j); - if (inst.Rc) - ComputeRC(gpr.GetImm(d), 0); - } - else - { - gpr.BindToRegister(d, d == a || d == b); - MUL(gpr.R(d), gpr.R(a), gpr.R(b)); - if (inst.Rc) - ComputeRC(gpr.R(d), 0); - } + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + s32 i = (s32)gpr.GetImm(a), j = (s32)gpr.GetImm(b); + gpr.SetImmediate(d, i * j); + if (inst.Rc) + ComputeRC(gpr.GetImm(d), 0); + } + else + { + gpr.BindToRegister(d, d == a || d == b); + MUL(gpr.R(d), gpr.R(a), gpr.R(b)); + if (inst.Rc) + ComputeRC(gpr.R(d), 0); + } } void JitArm64::mulhwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - int a = inst.RA, b = inst.RB, d = inst.RD; + int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.IsImm(a) && gpr.IsImm(b)) - { - s32 i = (s32)gpr.GetImm(a), j = (s32)gpr.GetImm(b); - gpr.SetImmediate(d, (u32)((u64)(((s64)i * (s64)j) ) >> 32)); - if (inst.Rc) - ComputeRC(gpr.GetImm(d), 0); - } - else - { - gpr.BindToRegister(d, d == a || d == b); - SMULL(EncodeRegTo64(gpr.R(d)), gpr.R(a), gpr.R(b)); - LSR(EncodeRegTo64(gpr.R(d)), EncodeRegTo64(gpr.R(d)), 32); + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + s32 i = (s32)gpr.GetImm(a), j = (s32)gpr.GetImm(b); + gpr.SetImmediate(d, (u32)((u64)(((s64)i * (s64)j)) >> 32)); + if (inst.Rc) + ComputeRC(gpr.GetImm(d), 0); + } + else + { + gpr.BindToRegister(d, d == a || d == b); + SMULL(EncodeRegTo64(gpr.R(d)), gpr.R(a), gpr.R(b)); + LSR(EncodeRegTo64(gpr.R(d)), EncodeRegTo64(gpr.R(d)), 32); - if (inst.Rc) - ComputeRC(gpr.R(d), 0); - } + if (inst.Rc) + ComputeRC(gpr.R(d), 0); + } } void JitArm64::mulhwux(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - int a = inst.RA, b = inst.RB, d = inst.RD; + int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.IsImm(a) && gpr.IsImm(b)) - { - u32 i = gpr.GetImm(a), j = gpr.GetImm(b); - gpr.SetImmediate(d, (u32)( ( (u64)i * (u64)j) >> 32) ); - if (inst.Rc) - ComputeRC(gpr.GetImm(d), 0); - } - else - { - gpr.BindToRegister(d, d == a || d == b); - UMULL(EncodeRegTo64(gpr.R(d)), gpr.R(a), gpr.R(b)); - LSR(EncodeRegTo64(gpr.R(d)), EncodeRegTo64(gpr.R(d)), 32); + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + u32 i = gpr.GetImm(a), j = gpr.GetImm(b); + gpr.SetImmediate(d, (u32)(((u64)i * (u64)j) >> 32)); + if (inst.Rc) + ComputeRC(gpr.GetImm(d), 0); + } + else + { + gpr.BindToRegister(d, d == a || d == b); + UMULL(EncodeRegTo64(gpr.R(d)), gpr.R(a), gpr.R(b)); + LSR(EncodeRegTo64(gpr.R(d)), EncodeRegTo64(gpr.R(d)), 32); - if (inst.Rc) - ComputeRC(gpr.R(d), 0); - } + if (inst.Rc) + ComputeRC(gpr.R(d), 0); + } } void JitArm64::addzex(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - FALLBACK_IF(inst.OE); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + FALLBACK_IF(inst.OE); - int a = inst.RA, d = inst.RD; + int a = inst.RA, d = inst.RD; - if (d == a) - { - gpr.BindToRegister(d, true); - ARM64Reg WA = gpr.GetReg(); - LDRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); - ADDS(gpr.R(d), gpr.R(a), WA); - gpr.Unlock(WA); - } - else - { - gpr.BindToRegister(d, false); - LDRB(INDEX_UNSIGNED, gpr.R(d), PPC_REG, PPCSTATE_OFF(xer_ca)); - ADDS(gpr.R(d), gpr.R(a), gpr.R(d)); - } + if (d == a) + { + gpr.BindToRegister(d, true); + ARM64Reg WA = gpr.GetReg(); + LDRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); + ADDS(gpr.R(d), gpr.R(a), WA); + gpr.Unlock(WA); + } + else + { + gpr.BindToRegister(d, false); + LDRB(INDEX_UNSIGNED, gpr.R(d), PPC_REG, PPCSTATE_OFF(xer_ca)); + ADDS(gpr.R(d), gpr.R(a), gpr.R(d)); + } - ComputeCarry(); - if (inst.Rc) - ComputeRC(gpr.R(d), 0); + ComputeCarry(); + if (inst.Rc) + ComputeRC(gpr.R(d), 0); } void JitArm64::subfx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - FALLBACK_IF(inst.OE); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + FALLBACK_IF(inst.OE); - int a = inst.RA, b = inst.RB, d = inst.RD; + int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.IsImm(a) && gpr.IsImm(b)) - { - u32 i = gpr.GetImm(a), j = gpr.GetImm(b); - gpr.SetImmediate(d, j - i); - if (inst.Rc) - ComputeRC(gpr.GetImm(d), 0); - } - else - { - gpr.BindToRegister(d, d == a || d == b); - SUB(gpr.R(d), gpr.R(b), gpr.R(a)); - if (inst.Rc) - ComputeRC(gpr.R(d), 0); - } + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + u32 i = gpr.GetImm(a), j = gpr.GetImm(b); + gpr.SetImmediate(d, j - i); + if (inst.Rc) + ComputeRC(gpr.GetImm(d), 0); + } + else + { + gpr.BindToRegister(d, d == a || d == b); + SUB(gpr.R(d), gpr.R(b), gpr.R(a)); + if (inst.Rc) + ComputeRC(gpr.R(d), 0); + } } void JitArm64::subfex(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - FALLBACK_IF(inst.OE); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + FALLBACK_IF(inst.OE); - int a = inst.RA, b = inst.RB, d = inst.RD; + int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.IsImm(a) && gpr.IsImm(b)) - { - u32 i = gpr.GetImm(a), j = gpr.GetImm(b); + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + u32 i = gpr.GetImm(a), j = gpr.GetImm(b); - gpr.BindToRegister(d, false); - MOVI2R(gpr.R(d), ~i + j); - ARM64Reg WA = gpr.GetReg(); - LDRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); - ADD(gpr.R(d), gpr.R(d), WA); - gpr.Unlock(WA); + gpr.BindToRegister(d, false); + MOVI2R(gpr.R(d), ~i + j); + ARM64Reg WA = gpr.GetReg(); + LDRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); + ADD(gpr.R(d), gpr.R(d), WA); + gpr.Unlock(WA); - bool must_have_carry = Interpreter::Helper_Carry(~i, j); - bool might_have_carry = (~i + j) == 0xFFFFFFFF; + bool must_have_carry = Interpreter::Helper_Carry(~i, j); + bool might_have_carry = (~i + j) == 0xFFFFFFFF; - if (must_have_carry) - { - ComputeCarry(true); - } - else if (might_have_carry) - { - // carry stay as it is - } - else - { - ComputeCarry(false); - } - } - else - { - ARM64Reg WA = gpr.GetReg(); - gpr.BindToRegister(d, d == a || d == b); + if (must_have_carry) + { + ComputeCarry(true); + } + else if (might_have_carry) + { + // carry stay as it is + } + else + { + ComputeCarry(false); + } + } + else + { + ARM64Reg WA = gpr.GetReg(); + gpr.BindToRegister(d, d == a || d == b); - // upload the carry state - LDRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); - CMP(WA, 1); + // upload the carry state + LDRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); + CMP(WA, 1); - // d = ~a + b + carry; - if (gpr.IsImm(a)) - MOVI2R(WA, ~gpr.GetImm(a)); - else - MVN(WA, gpr.R(a)); - ADCS(gpr.R(d), WA, gpr.R(b)); + // d = ~a + b + carry; + if (gpr.IsImm(a)) + MOVI2R(WA, ~gpr.GetImm(a)); + else + MVN(WA, gpr.R(a)); + ADCS(gpr.R(d), WA, gpr.R(b)); - gpr.Unlock(WA); + gpr.Unlock(WA); - ComputeCarry(); - } + ComputeCarry(); + } - if (inst.Rc) - ComputeRC(gpr.R(d), 0); + if (inst.Rc) + ComputeRC(gpr.R(d), 0); } void JitArm64::subfcx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - FALLBACK_IF(inst.OE); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + FALLBACK_IF(inst.OE); - int a = inst.RA, b = inst.RB, d = inst.RD; + int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.IsImm(a) && gpr.IsImm(b)) - { - u32 a_imm = gpr.GetImm(a), b_imm = gpr.GetImm(b); + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + u32 a_imm = gpr.GetImm(a), b_imm = gpr.GetImm(b); - gpr.SetImmediate(d, b_imm - a_imm); - ComputeCarry(a_imm == 0 || Interpreter::Helper_Carry(b_imm, 0u - a_imm)); + gpr.SetImmediate(d, b_imm - a_imm); + ComputeCarry(a_imm == 0 || Interpreter::Helper_Carry(b_imm, 0u - a_imm)); - if (inst.Rc) - ComputeRC(gpr.GetImm(d), 0); - } - else - { - gpr.BindToRegister(d, d == a || d == b); + if (inst.Rc) + ComputeRC(gpr.GetImm(d), 0); + } + else + { + gpr.BindToRegister(d, d == a || d == b); - // d = b - a - SUBS(gpr.R(d), gpr.R(b), gpr.R(a)); + // d = b - a + SUBS(gpr.R(d), gpr.R(b), gpr.R(a)); - ComputeCarry(); + ComputeCarry(); - if (inst.Rc) - ComputeRC(gpr.R(d), 0); - } + if (inst.Rc) + ComputeRC(gpr.R(d), 0); + } } void JitArm64::subfic(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - int a = inst.RA, d = inst.RD; - s32 imm = inst.SIMM_16; + int a = inst.RA, d = inst.RD; + s32 imm = inst.SIMM_16; - if (gpr.IsImm(a)) - { - u32 a_imm = gpr.GetImm(a); + if (gpr.IsImm(a)) + { + u32 a_imm = gpr.GetImm(a); - gpr.SetImmediate(d, imm - a_imm); - ComputeCarry(a_imm == 0 || Interpreter::Helper_Carry(imm, 0u - a_imm)); - } - else - { - gpr.BindToRegister(d, d == a); + gpr.SetImmediate(d, imm - a_imm); + ComputeCarry(a_imm == 0 || Interpreter::Helper_Carry(imm, 0u - a_imm)); + } + else + { + gpr.BindToRegister(d, d == a); - // d = imm - a - ARM64Reg WA = gpr.GetReg(); - MOVI2R(WA, imm); - SUBS(gpr.R(d), WA, gpr.R(a)); - gpr.Unlock(WA); + // d = imm - a + ARM64Reg WA = gpr.GetReg(); + MOVI2R(WA, imm); + SUBS(gpr.R(d), WA, gpr.R(a)); + gpr.Unlock(WA); - ComputeCarry(); - } + ComputeCarry(); + } } void JitArm64::addex(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - FALLBACK_IF(inst.OE); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + FALLBACK_IF(inst.OE); - int a = inst.RA, b = inst.RB, d = inst.RD; + int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.IsImm(a) && gpr.IsImm(b)) - { - u32 i = gpr.GetImm(a), j = gpr.GetImm(b); + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + u32 i = gpr.GetImm(a), j = gpr.GetImm(b); - gpr.BindToRegister(d, false); - MOVI2R(gpr.R(d), i + j); - ARM64Reg WA = gpr.GetReg(); - LDRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); - ADD(gpr.R(d), gpr.R(d), WA); - gpr.Unlock(WA); + gpr.BindToRegister(d, false); + MOVI2R(gpr.R(d), i + j); + ARM64Reg WA = gpr.GetReg(); + LDRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); + ADD(gpr.R(d), gpr.R(d), WA); + gpr.Unlock(WA); - bool must_have_carry = Interpreter::Helper_Carry(i, j); - bool might_have_carry = (i + j) == 0xFFFFFFFF; + bool must_have_carry = Interpreter::Helper_Carry(i, j); + bool might_have_carry = (i + j) == 0xFFFFFFFF; - if (must_have_carry) - { - ComputeCarry(true); - } - else if (might_have_carry) - { - // carry stay as it is - } - else - { - ComputeCarry(false); - } - } - else - { - gpr.BindToRegister(d, d == a || d == b); + if (must_have_carry) + { + ComputeCarry(true); + } + else if (might_have_carry) + { + // carry stay as it is + } + else + { + ComputeCarry(false); + } + } + else + { + gpr.BindToRegister(d, d == a || d == b); - // upload the carry state - ARM64Reg WA = gpr.GetReg(); - LDRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); - CMP(WA, 1); - gpr.Unlock(WA); + // upload the carry state + ARM64Reg WA = gpr.GetReg(); + LDRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); + CMP(WA, 1); + gpr.Unlock(WA); - // d = a + b + carry; - ADCS(gpr.R(d), gpr.R(a), gpr.R(b)); + // d = a + b + carry; + ADCS(gpr.R(d), gpr.R(a), gpr.R(b)); - ComputeCarry(); - } + ComputeCarry(); + } - if (inst.Rc) - ComputeRC(gpr.R(d), 0); + if (inst.Rc) + ComputeRC(gpr.R(d), 0); } void JitArm64::addcx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - FALLBACK_IF(inst.OE); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + FALLBACK_IF(inst.OE); - int a = inst.RA, b = inst.RB, d = inst.RD; + int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.IsImm(a) && gpr.IsImm(b)) - { - u32 i = gpr.GetImm(a), j = gpr.GetImm(b); - gpr.SetImmediate(d, i + j); + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + u32 i = gpr.GetImm(a), j = gpr.GetImm(b); + gpr.SetImmediate(d, i + j); - bool has_carry = Interpreter::Helper_Carry(i, j); - ComputeCarry(has_carry); - if (inst.Rc) - ComputeRC(gpr.GetImm(d), 0); - } - else - { - gpr.BindToRegister(d, d == a || d == b); - ADDS(gpr.R(d), gpr.R(a), gpr.R(b)); + bool has_carry = Interpreter::Helper_Carry(i, j); + ComputeCarry(has_carry); + if (inst.Rc) + ComputeRC(gpr.GetImm(d), 0); + } + else + { + gpr.BindToRegister(d, d == a || d == b); + ADDS(gpr.R(d), gpr.R(a), gpr.R(b)); - ComputeCarry(); - if (inst.Rc) - ComputeRC(gpr.R(d), 0); - } + ComputeCarry(); + if (inst.Rc) + ComputeRC(gpr.R(d), 0); + } } void JitArm64::divwux(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - FALLBACK_IF(inst.OE); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + FALLBACK_IF(inst.OE); - int a = inst.RA, b = inst.RB, d = inst.RD; + int a = inst.RA, b = inst.RB, d = inst.RD; - if (gpr.IsImm(a) && gpr.IsImm(b)) - { - u32 i = gpr.GetImm(a), j = gpr.GetImm(b); - gpr.SetImmediate(d, j == 0 ? 0 : i / j); + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + u32 i = gpr.GetImm(a), j = gpr.GetImm(b); + gpr.SetImmediate(d, j == 0 ? 0 : i / j); - if (inst.Rc) - ComputeRC(gpr.GetImm(d), 0); - } - else - { - gpr.BindToRegister(d, d == a || d == b); + if (inst.Rc) + ComputeRC(gpr.GetImm(d), 0); + } + else + { + gpr.BindToRegister(d, d == a || d == b); - // d = a / b - UDIV(gpr.R(d), gpr.R(a), gpr.R(b)); + // d = a / b + UDIV(gpr.R(d), gpr.R(a), gpr.R(b)); - if (inst.Rc) - ComputeRC(gpr.R(d), 0); - } + if (inst.Rc) + ComputeRC(gpr.R(d), 0); + } } void JitArm64::slwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - int a = inst.RA, b = inst.RB, s = inst.RS; + int a = inst.RA, b = inst.RB, s = inst.RS; - if (gpr.IsImm(b) && gpr.IsImm(s)) - { - u32 i = gpr.GetImm(s), j = gpr.GetImm(b); - gpr.SetImmediate(a, (j & 0x20) ? 0 : i << (j & 0x1F)); + if (gpr.IsImm(b) && gpr.IsImm(s)) + { + u32 i = gpr.GetImm(s), j = gpr.GetImm(b); + gpr.SetImmediate(a, (j & 0x20) ? 0 : i << (j & 0x1F)); - if (inst.Rc) - ComputeRC(gpr.GetImm(a), 0); - } - else if (gpr.IsImm(b)) - { - u32 i = gpr.GetImm(b); - if (i & 0x20) - { - gpr.SetImmediate(a, 0); - if (inst.Rc) - ComputeRC(0, 0); - } - else - { - gpr.BindToRegister(a, a == s); - LSL(gpr.R(a), gpr.R(s), i & 0x1F); - if (inst.Rc) - ComputeRC(gpr.R(a), 0); - } - } - else - { - gpr.BindToRegister(a, a == b || a == s); + if (inst.Rc) + ComputeRC(gpr.GetImm(a), 0); + } + else if (gpr.IsImm(b)) + { + u32 i = gpr.GetImm(b); + if (i & 0x20) + { + gpr.SetImmediate(a, 0); + if (inst.Rc) + ComputeRC(0, 0); + } + else + { + gpr.BindToRegister(a, a == s); + LSL(gpr.R(a), gpr.R(s), i & 0x1F); + if (inst.Rc) + ComputeRC(gpr.R(a), 0); + } + } + else + { + gpr.BindToRegister(a, a == b || a == s); - // PowerPC any shift in the 32-63 register range results in zero - // Since it has 32bit registers - // AArch64 it will use a mask of the register size for determining what shift amount - // So if we use a 64bit so the bits will end up in the high 32bits, and - // Later instructions will just eat high 32bits since it'll run 32bit operations for everything. - LSLV(EncodeRegTo64(gpr.R(a)), EncodeRegTo64(gpr.R(s)), EncodeRegTo64(gpr.R(b))); + // PowerPC any shift in the 32-63 register range results in zero + // Since it has 32bit registers + // AArch64 it will use a mask of the register size for determining what shift amount + // So if we use a 64bit so the bits will end up in the high 32bits, and + // Later instructions will just eat high 32bits since it'll run 32bit operations for everything. + LSLV(EncodeRegTo64(gpr.R(a)), EncodeRegTo64(gpr.R(s)), EncodeRegTo64(gpr.R(b))); - if (inst.Rc) - ComputeRC(gpr.R(a), 0); - } + if (inst.Rc) + ComputeRC(gpr.R(a), 0); + } } void JitArm64::srwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - int a = inst.RA, b = inst.RB, s = inst.RS; + int a = inst.RA, b = inst.RB, s = inst.RS; - if (gpr.IsImm(b) && gpr.IsImm(s)) - { - u32 i = gpr.GetImm(s), amount = gpr.GetImm(b); - gpr.SetImmediate(a, (amount & 0x20) ? 0 : i >> (amount & 0x1F)); + if (gpr.IsImm(b) && gpr.IsImm(s)) + { + u32 i = gpr.GetImm(s), amount = gpr.GetImm(b); + gpr.SetImmediate(a, (amount & 0x20) ? 0 : i >> (amount & 0x1F)); - if (inst.Rc) - ComputeRC(gpr.GetImm(a), 0); - } - else if (gpr.IsImm(b)) - { - u32 amount = gpr.GetImm(b); - if (amount & 0x20) - { - gpr.SetImmediate(a, 0); - if (inst.Rc) - ComputeRC(0, 0); - } - else - { - gpr.BindToRegister(a, a == s); - LSR(gpr.R(a), gpr.R(s), amount & 0x1F); - if (inst.Rc) - ComputeRC(gpr.R(a), 0); - } - } - else - { - gpr.BindToRegister(a, a == b || a == s); + if (inst.Rc) + ComputeRC(gpr.GetImm(a), 0); + } + else if (gpr.IsImm(b)) + { + u32 amount = gpr.GetImm(b); + if (amount & 0x20) + { + gpr.SetImmediate(a, 0); + if (inst.Rc) + ComputeRC(0, 0); + } + else + { + gpr.BindToRegister(a, a == s); + LSR(gpr.R(a), gpr.R(s), amount & 0x1F); + if (inst.Rc) + ComputeRC(gpr.R(a), 0); + } + } + else + { + gpr.BindToRegister(a, a == b || a == s); - // wipe upper bits. TODO: get rid of it, but then no instruction is allowed to emit some higher bits. - MOV(gpr.R(s), gpr.R(s)); + // wipe upper bits. TODO: get rid of it, but then no instruction is allowed to emit some higher + // bits. + MOV(gpr.R(s), gpr.R(s)); - LSRV(EncodeRegTo64(gpr.R(a)), EncodeRegTo64(gpr.R(s)), EncodeRegTo64(gpr.R(b))); + LSRV(EncodeRegTo64(gpr.R(a)), EncodeRegTo64(gpr.R(s)), EncodeRegTo64(gpr.R(b))); - if (inst.Rc) - ComputeRC(gpr.R(a), 0); - } + if (inst.Rc) + ComputeRC(gpr.R(a), 0); + } } void JitArm64::rlwimix(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - int a = inst.RA, s = inst.RS; - u32 mask = Helper_Mask(inst.MB, inst.ME); + int a = inst.RA, s = inst.RS; + u32 mask = Helper_Mask(inst.MB, inst.ME); - if (gpr.IsImm(a) && gpr.IsImm(s)) - { - u32 res = (gpr.GetImm(a) & ~mask) | (_rotl(gpr.GetImm(s), inst.SH) & mask); - gpr.SetImmediate(a, res); - if (inst.Rc) - ComputeRC(res, 0); - } - else - { - if (mask == 0 || (a == s && inst.SH == 0)) - { - // Do Nothing - } - else if (mask == 0xFFFFFFFF) - { - if (inst.SH || a != s) - gpr.BindToRegister(a, a == s); + if (gpr.IsImm(a) && gpr.IsImm(s)) + { + u32 res = (gpr.GetImm(a) & ~mask) | (_rotl(gpr.GetImm(s), inst.SH) & mask); + gpr.SetImmediate(a, res); + if (inst.Rc) + ComputeRC(res, 0); + } + else + { + if (mask == 0 || (a == s && inst.SH == 0)) + { + // Do Nothing + } + else if (mask == 0xFFFFFFFF) + { + if (inst.SH || a != s) + gpr.BindToRegister(a, a == s); - if (inst.SH) - ROR(gpr.R(a), gpr.R(s), 32 - inst.SH); - else if (a != s) - MOV(gpr.R(a), gpr.R(s)); - } - else if (inst.SH == 0 && inst.MB <= inst.ME) - { - // No rotation - // No mask inversion - u32 lsb = 31 - inst.ME; - u32 width = inst.ME - inst.MB + 1; + if (inst.SH) + ROR(gpr.R(a), gpr.R(s), 32 - inst.SH); + else if (a != s) + MOV(gpr.R(a), gpr.R(s)); + } + else if (inst.SH == 0 && inst.MB <= inst.ME) + { + // No rotation + // No mask inversion + u32 lsb = 31 - inst.ME; + u32 width = inst.ME - inst.MB + 1; - gpr.BindToRegister(a, true); - ARM64Reg WA = gpr.GetReg(); - UBFX(WA, gpr.R(s), lsb, width); - BFI(gpr.R(a), WA, lsb, width); - gpr.Unlock(WA); - } - else if (inst.SH && inst.MB <= inst.ME) - { - // No mask inversion - u32 lsb = 31 - inst.ME; - u32 width = inst.ME - inst.MB + 1; + gpr.BindToRegister(a, true); + ARM64Reg WA = gpr.GetReg(); + UBFX(WA, gpr.R(s), lsb, width); + BFI(gpr.R(a), WA, lsb, width); + gpr.Unlock(WA); + } + else if (inst.SH && inst.MB <= inst.ME) + { + // No mask inversion + u32 lsb = 31 - inst.ME; + u32 width = inst.ME - inst.MB + 1; - gpr.BindToRegister(a, true); - ARM64Reg WA = gpr.GetReg(); - ROR(WA, gpr.R(s), 32 - inst.SH); - UBFX(WA, WA, lsb, width); - BFI(gpr.R(a), WA, lsb, width); - gpr.Unlock(WA); - } - else - { - gpr.BindToRegister(a, true); - ARM64Reg WA = gpr.GetReg(); - ARM64Reg WB = gpr.GetReg(); + gpr.BindToRegister(a, true); + ARM64Reg WA = gpr.GetReg(); + ROR(WA, gpr.R(s), 32 - inst.SH); + UBFX(WA, WA, lsb, width); + BFI(gpr.R(a), WA, lsb, width); + gpr.Unlock(WA); + } + else + { + gpr.BindToRegister(a, true); + ARM64Reg WA = gpr.GetReg(); + ARM64Reg WB = gpr.GetReg(); - MOVI2R(WA, mask); - BIC(WB, gpr.R(a), WA); - AND(WA, WA, gpr.R(s), ArithOption(gpr.R(s), ST_ROR, 32 - inst.SH)); - ORR(gpr.R(a), WB, WA); + MOVI2R(WA, mask); + BIC(WB, gpr.R(a), WA); + AND(WA, WA, gpr.R(s), ArithOption(gpr.R(s), ST_ROR, 32 - inst.SH)); + ORR(gpr.R(a), WB, WA); - gpr.Unlock(WA, WB); - } + gpr.Unlock(WA, WB); + } - if (inst.Rc) - ComputeRC(gpr.R(a), 0); - } + if (inst.Rc) + ComputeRC(gpr.R(a), 0); + } } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp index c4053ff779..670cfdc98c 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp @@ -11,868 +11,850 @@ #include "Core/CoreTiming.h" #include "Core/HW/DSP.h" #include "Core/HW/GPFifo.h" -#include "Core/HW/Memmap.h" #include "Core/HW/MMIO.h" -#include "Core/PowerPC/JitInterface.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCTables.h" +#include "Core/HW/Memmap.h" #include "Core/PowerPC/JitArm64/Jit.h" -#include "Core/PowerPC/JitArm64/Jit_Util.h" #include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" +#include "Core/PowerPC/JitArm64/Jit_Util.h" +#include "Core/PowerPC/JitInterface.h" +#include "Core/PowerPC/PPCTables.h" +#include "Core/PowerPC/PowerPC.h" using namespace Arm64Gen; void JitArm64::SafeLoadToReg(u32 dest, s32 addr, s32 offsetReg, u32 flags, s32 offset, bool update) { - // We want to make sure to not get LR as a temp register - gpr.Lock(W0, W30); + // We want to make sure to not get LR as a temp register + gpr.Lock(W0, W30); - gpr.BindToRegister(dest, dest == (u32)addr || dest == (u32)offsetReg); - ARM64Reg dest_reg = gpr.R(dest); - ARM64Reg up_reg = INVALID_REG; - ARM64Reg off_reg = INVALID_REG; + gpr.BindToRegister(dest, dest == (u32)addr || dest == (u32)offsetReg); + ARM64Reg dest_reg = gpr.R(dest); + ARM64Reg up_reg = INVALID_REG; + ARM64Reg off_reg = INVALID_REG; - if (addr != -1 && !gpr.IsImm(addr)) - up_reg = gpr.R(addr); + if (addr != -1 && !gpr.IsImm(addr)) + up_reg = gpr.R(addr); - if (offsetReg != -1 && !gpr.IsImm(offsetReg)) - off_reg = gpr.R(offsetReg); + if (offsetReg != -1 && !gpr.IsImm(offsetReg)) + off_reg = gpr.R(offsetReg); - BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); - BitSet32 fprs_in_use = fpr.GetCallerSavedUsed(); - regs_in_use[W0] = 0; - regs_in_use[dest_reg] = 0; + BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); + BitSet32 fprs_in_use = fpr.GetCallerSavedUsed(); + regs_in_use[W0] = 0; + regs_in_use[dest_reg] = 0; - ARM64Reg addr_reg = W0; - u32 imm_addr = 0; - bool is_immediate = false; + ARM64Reg addr_reg = W0; + u32 imm_addr = 0; + bool is_immediate = false; - if (offsetReg == -1) - { - if (addr != -1) - { - if (gpr.IsImm(addr)) - { - is_immediate = true; - imm_addr = gpr.GetImm(addr) + offset; - } - else - { - if (offset >= 0 && offset < 4096) - { - ADD(addr_reg, up_reg, offset); - } - else if (offset < 0 && offset > -4096) - { - SUB(addr_reg, up_reg, std::abs(offset)); - } - else - { - MOVI2R(addr_reg, offset); - ADD(addr_reg, addr_reg, up_reg); - } - } - } - else - { - is_immediate = true; - imm_addr = offset; - } - } - else - { - if (addr != -1) - { - if (gpr.IsImm(addr) && gpr.IsImm(offsetReg)) - { - is_immediate = true; - imm_addr = gpr.GetImm(addr) + gpr.GetImm(offsetReg); - } - else if (gpr.IsImm(addr) && !gpr.IsImm(offsetReg)) - { - u32 reg_offset = gpr.GetImm(addr); - if (reg_offset < 4096) - { - ADD(addr_reg, off_reg, reg_offset); - } - else - { - MOVI2R(addr_reg, gpr.GetImm(addr)); - ADD(addr_reg, addr_reg, off_reg); - } - } - else if (!gpr.IsImm(addr) && gpr.IsImm(offsetReg)) - { - u32 reg_offset = gpr.GetImm(offsetReg); - if (reg_offset < 4096) - { - ADD(addr_reg, up_reg, reg_offset); - } - else - { - MOVI2R(addr_reg, gpr.GetImm(offsetReg)); - ADD(addr_reg, addr_reg, up_reg); - } - } - else - { - ADD(addr_reg, up_reg, off_reg); - } - } - else - { - if (gpr.IsImm(offsetReg)) - { - is_immediate = true; - imm_addr = gpr.GetImm(offsetReg); - } - else - { - MOV(addr_reg, off_reg); - } - } - } + if (offsetReg == -1) + { + if (addr != -1) + { + if (gpr.IsImm(addr)) + { + is_immediate = true; + imm_addr = gpr.GetImm(addr) + offset; + } + else + { + if (offset >= 0 && offset < 4096) + { + ADD(addr_reg, up_reg, offset); + } + else if (offset < 0 && offset > -4096) + { + SUB(addr_reg, up_reg, std::abs(offset)); + } + else + { + MOVI2R(addr_reg, offset); + ADD(addr_reg, addr_reg, up_reg); + } + } + } + else + { + is_immediate = true; + imm_addr = offset; + } + } + else + { + if (addr != -1) + { + if (gpr.IsImm(addr) && gpr.IsImm(offsetReg)) + { + is_immediate = true; + imm_addr = gpr.GetImm(addr) + gpr.GetImm(offsetReg); + } + else if (gpr.IsImm(addr) && !gpr.IsImm(offsetReg)) + { + u32 reg_offset = gpr.GetImm(addr); + if (reg_offset < 4096) + { + ADD(addr_reg, off_reg, reg_offset); + } + else + { + MOVI2R(addr_reg, gpr.GetImm(addr)); + ADD(addr_reg, addr_reg, off_reg); + } + } + else if (!gpr.IsImm(addr) && gpr.IsImm(offsetReg)) + { + u32 reg_offset = gpr.GetImm(offsetReg); + if (reg_offset < 4096) + { + ADD(addr_reg, up_reg, reg_offset); + } + else + { + MOVI2R(addr_reg, gpr.GetImm(offsetReg)); + ADD(addr_reg, addr_reg, up_reg); + } + } + else + { + ADD(addr_reg, up_reg, off_reg); + } + } + else + { + if (gpr.IsImm(offsetReg)) + { + is_immediate = true; + imm_addr = gpr.GetImm(offsetReg); + } + else + { + MOV(addr_reg, off_reg); + } + } + } - ARM64Reg XA = EncodeRegTo64(addr_reg); + ARM64Reg XA = EncodeRegTo64(addr_reg); - if (is_immediate) - MOVI2R(XA, imm_addr); + if (is_immediate) + MOVI2R(XA, imm_addr); - if (update) - { - gpr.BindToRegister(addr, false); - MOV(gpr.R(addr), addr_reg); - } + if (update) + { + gpr.BindToRegister(addr, false); + MOV(gpr.R(addr), addr_reg); + } - u32 access_size = BackPatchInfo::GetFlagSize(flags); - u32 mmio_address = 0; - if (is_immediate) - mmio_address = PowerPC::IsOptimizableMMIOAccess(imm_addr, access_size); + u32 access_size = BackPatchInfo::GetFlagSize(flags); + u32 mmio_address = 0; + if (is_immediate) + mmio_address = PowerPC::IsOptimizableMMIOAccess(imm_addr, access_size); - if (is_immediate && PowerPC::IsOptimizableRAMAddress(imm_addr)) - { - EmitBackpatchRoutine(flags, true, false, dest_reg, XA, BitSet32(0), BitSet32(0)); - } - else if (mmio_address) - { - MMIOLoadToReg(Memory::mmio_mapping.get(), this, - regs_in_use, fprs_in_use, dest_reg, - mmio_address, flags); - } - else - { - EmitBackpatchRoutine(flags, - jo.fastmem, - jo.fastmem, - dest_reg, XA, - regs_in_use, fprs_in_use); - } + if (is_immediate && PowerPC::IsOptimizableRAMAddress(imm_addr)) + { + EmitBackpatchRoutine(flags, true, false, dest_reg, XA, BitSet32(0), BitSet32(0)); + } + else if (mmio_address) + { + MMIOLoadToReg(Memory::mmio_mapping.get(), this, regs_in_use, fprs_in_use, dest_reg, + mmio_address, flags); + } + else + { + EmitBackpatchRoutine(flags, jo.fastmem, jo.fastmem, dest_reg, XA, regs_in_use, fprs_in_use); + } - gpr.Unlock(W0, W30); + gpr.Unlock(W0, W30); } void JitArm64::SafeStoreFromReg(s32 dest, u32 value, s32 regOffset, u32 flags, s32 offset) { - // We want to make sure to not get LR as a temp register - gpr.Lock(W0, W1, W30); + // We want to make sure to not get LR as a temp register + gpr.Lock(W0, W1, W30); - ARM64Reg RS = gpr.R(value); + ARM64Reg RS = gpr.R(value); - ARM64Reg reg_dest = INVALID_REG; - ARM64Reg reg_off = INVALID_REG; + ARM64Reg reg_dest = INVALID_REG; + ARM64Reg reg_off = INVALID_REG; - if (regOffset != -1 && !gpr.IsImm(regOffset)) - reg_off = gpr.R(regOffset); - if (dest != -1 && !gpr.IsImm(dest)) - reg_dest = gpr.R(dest); + if (regOffset != -1 && !gpr.IsImm(regOffset)) + reg_off = gpr.R(regOffset); + if (dest != -1 && !gpr.IsImm(dest)) + reg_dest = gpr.R(dest); - BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); - BitSet32 fprs_in_use = fpr.GetCallerSavedUsed(); - regs_in_use[W0] = 0; - regs_in_use[W1] = 0; + BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); + BitSet32 fprs_in_use = fpr.GetCallerSavedUsed(); + regs_in_use[W0] = 0; + regs_in_use[W1] = 0; - ARM64Reg addr_reg = W1; + ARM64Reg addr_reg = W1; - u32 imm_addr = 0; - bool is_immediate = false; + u32 imm_addr = 0; + bool is_immediate = false; - if (regOffset == -1) - { - if (dest != -1) - { - if (gpr.IsImm(dest)) - { - is_immediate = true; - imm_addr = gpr.GetImm(dest) + offset; - } - else - { - if (offset >= 0 && offset < 4096) - { - ADD(addr_reg, reg_dest, offset); - } - else if (offset < 0 && offset > -4096) - { - SUB(addr_reg, reg_dest, std::abs(offset)); - } - else - { - MOVI2R(addr_reg, offset); - ADD(addr_reg, addr_reg, reg_dest); - } - } - } - else - { - is_immediate = true; - imm_addr = offset; - } - } - else - { - if (dest != -1) - { - if (gpr.IsImm(dest) && gpr.IsImm(regOffset)) - { - is_immediate = true; - imm_addr = gpr.GetImm(dest) + gpr.GetImm(regOffset); - } - else if (gpr.IsImm(dest) && !gpr.IsImm(regOffset)) - { - u32 reg_offset = gpr.GetImm(dest); - if (reg_offset < 4096) - { - ADD(addr_reg, reg_off, reg_offset); - } - else - { - MOVI2R(addr_reg, reg_offset); - ADD(addr_reg, addr_reg, reg_off); - } - } - else if (!gpr.IsImm(dest) && gpr.IsImm(regOffset)) - { - u32 reg_offset = gpr.GetImm(regOffset); - if (reg_offset < 4096) - { - ADD(addr_reg, reg_dest, reg_offset); - } - else - { - MOVI2R(addr_reg, gpr.GetImm(regOffset)); - ADD(addr_reg, addr_reg, reg_dest); - } - } - else - { - ADD(addr_reg, reg_dest, reg_off); - } - } - else - { - if (gpr.IsImm(regOffset)) - { - is_immediate = true; - imm_addr = gpr.GetImm(regOffset); - } - else - { - MOV(addr_reg, reg_off); - } - } - } + if (regOffset == -1) + { + if (dest != -1) + { + if (gpr.IsImm(dest)) + { + is_immediate = true; + imm_addr = gpr.GetImm(dest) + offset; + } + else + { + if (offset >= 0 && offset < 4096) + { + ADD(addr_reg, reg_dest, offset); + } + else if (offset < 0 && offset > -4096) + { + SUB(addr_reg, reg_dest, std::abs(offset)); + } + else + { + MOVI2R(addr_reg, offset); + ADD(addr_reg, addr_reg, reg_dest); + } + } + } + else + { + is_immediate = true; + imm_addr = offset; + } + } + else + { + if (dest != -1) + { + if (gpr.IsImm(dest) && gpr.IsImm(regOffset)) + { + is_immediate = true; + imm_addr = gpr.GetImm(dest) + gpr.GetImm(regOffset); + } + else if (gpr.IsImm(dest) && !gpr.IsImm(regOffset)) + { + u32 reg_offset = gpr.GetImm(dest); + if (reg_offset < 4096) + { + ADD(addr_reg, reg_off, reg_offset); + } + else + { + MOVI2R(addr_reg, reg_offset); + ADD(addr_reg, addr_reg, reg_off); + } + } + else if (!gpr.IsImm(dest) && gpr.IsImm(regOffset)) + { + u32 reg_offset = gpr.GetImm(regOffset); + if (reg_offset < 4096) + { + ADD(addr_reg, reg_dest, reg_offset); + } + else + { + MOVI2R(addr_reg, gpr.GetImm(regOffset)); + ADD(addr_reg, addr_reg, reg_dest); + } + } + else + { + ADD(addr_reg, reg_dest, reg_off); + } + } + else + { + if (gpr.IsImm(regOffset)) + { + is_immediate = true; + imm_addr = gpr.GetImm(regOffset); + } + else + { + MOV(addr_reg, reg_off); + } + } + } - ARM64Reg XA = EncodeRegTo64(addr_reg); + ARM64Reg XA = EncodeRegTo64(addr_reg); - u32 access_size = BackPatchInfo::GetFlagSize(flags); - u32 mmio_address = 0; - if (is_immediate) - mmio_address = PowerPC::IsOptimizableMMIOAccess(imm_addr, access_size); + u32 access_size = BackPatchInfo::GetFlagSize(flags); + u32 mmio_address = 0; + if (is_immediate) + mmio_address = PowerPC::IsOptimizableMMIOAccess(imm_addr, access_size); - if (is_immediate && jo.optimizeGatherPipe && PowerPC::IsOptimizableGatherPipeWrite(imm_addr)) - { - ARM64Reg WA = INVALID_REG; - int accessSize; - if (flags & BackPatchInfo::FLAG_SIZE_32) - accessSize = 32; - else if (flags & BackPatchInfo::FLAG_SIZE_16) - accessSize = 16; - else - accessSize = 8; + if (is_immediate && jo.optimizeGatherPipe && PowerPC::IsOptimizableGatherPipeWrite(imm_addr)) + { + ARM64Reg WA = INVALID_REG; + int accessSize; + if (flags & BackPatchInfo::FLAG_SIZE_32) + accessSize = 32; + else if (flags & BackPatchInfo::FLAG_SIZE_16) + accessSize = 16; + else + accessSize = 8; - if (accessSize != 8) - WA = gpr.GetReg(); + if (accessSize != 8) + WA = gpr.GetReg(); - u64 base_ptr = std::min((u64)&GPFifo::m_gatherPipeCount, (u64)&GPFifo::m_gatherPipe); - u32 count_off = (u64)&GPFifo::m_gatherPipeCount - base_ptr; - u32 pipe_off = (u64)&GPFifo::m_gatherPipe - base_ptr; + u64 base_ptr = std::min((u64)&GPFifo::m_gatherPipeCount, (u64)&GPFifo::m_gatherPipe); + u32 count_off = (u64)&GPFifo::m_gatherPipeCount - base_ptr; + u32 pipe_off = (u64)&GPFifo::m_gatherPipe - base_ptr; - MOVI2R(X30, base_ptr); + MOVI2R(X30, base_ptr); - if (pipe_off) - ADD(X1, X30, pipe_off); + if (pipe_off) + ADD(X1, X30, pipe_off); - LDR(INDEX_UNSIGNED, W0, X30, count_off); - if (accessSize == 32) - { - REV32(WA, RS); - if (pipe_off) - STR(WA, X1, ArithOption(X0)); - else - STR(WA, X30, ArithOption(X0)); - } - else if (accessSize == 16) - { - REV16(WA, RS); - if (pipe_off) - STRH(WA, X1, ArithOption(X0)); - else - STRH(WA, X30, ArithOption(X0)); - } - else - { - if (pipe_off) - STRB(RS, X1, ArithOption(X0)); - else - STRB(RS, X30, ArithOption(X0)); + LDR(INDEX_UNSIGNED, W0, X30, count_off); + if (accessSize == 32) + { + REV32(WA, RS); + if (pipe_off) + STR(WA, X1, ArithOption(X0)); + else + STR(WA, X30, ArithOption(X0)); + } + else if (accessSize == 16) + { + REV16(WA, RS); + if (pipe_off) + STRH(WA, X1, ArithOption(X0)); + else + STRH(WA, X30, ArithOption(X0)); + } + else + { + if (pipe_off) + STRB(RS, X1, ArithOption(X0)); + else + STRB(RS, X30, ArithOption(X0)); + } + ADD(W0, W0, accessSize >> 3); + STR(INDEX_UNSIGNED, W0, X30, count_off); + js.fifoBytesThisBlock += accessSize >> 3; - } - ADD(W0, W0, accessSize >> 3); - STR(INDEX_UNSIGNED, W0, X30, count_off); - js.fifoBytesThisBlock += accessSize >> 3; + if (accessSize != 8) + gpr.Unlock(WA); + } + else if (is_immediate && PowerPC::IsOptimizableRAMAddress(imm_addr)) + { + MOVI2R(XA, imm_addr); + EmitBackpatchRoutine(flags, true, false, RS, XA, BitSet32(0), BitSet32(0)); + } + else if (mmio_address && !(flags & BackPatchInfo::FLAG_REVERSE)) + { + MMIOWriteRegToAddr(Memory::mmio_mapping.get(), this, regs_in_use, fprs_in_use, RS, mmio_address, + flags); + } + else + { + if (is_immediate) + MOVI2R(XA, imm_addr); - if (accessSize != 8) - gpr.Unlock(WA); - } - else if (is_immediate && PowerPC::IsOptimizableRAMAddress(imm_addr)) - { - MOVI2R(XA, imm_addr); - EmitBackpatchRoutine(flags, true, false, RS, XA, BitSet32(0), BitSet32(0)); - } - else if (mmio_address && !(flags & BackPatchInfo::FLAG_REVERSE)) - { - MMIOWriteRegToAddr(Memory::mmio_mapping.get(), this, - regs_in_use, fprs_in_use, RS, - mmio_address, flags); - } - else - { - if (is_immediate) - MOVI2R(XA, imm_addr); + EmitBackpatchRoutine(flags, jo.fastmem, jo.fastmem, RS, XA, regs_in_use, fprs_in_use); + } - EmitBackpatchRoutine(flags, - jo.fastmem, - jo.fastmem, - RS, XA, - regs_in_use, - fprs_in_use); - } - - gpr.Unlock(W0, W1, W30); + gpr.Unlock(W0, W1, W30); } void JitArm64::lXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); - u32 a = inst.RA, b = inst.RB, d = inst.RD; - s32 offset = inst.SIMM_16; - s32 offsetReg = -1; - u32 flags = BackPatchInfo::FLAG_LOAD; - bool update = false; + u32 a = inst.RA, b = inst.RB, d = inst.RD; + s32 offset = inst.SIMM_16; + s32 offsetReg = -1; + u32 flags = BackPatchInfo::FLAG_LOAD; + bool update = false; - switch (inst.OPCD) - { - case 31: - offsetReg = b; - switch (inst.SUBOP10) - { - case 55: // lwzux - update = true; - case 23: // lwzx - flags |= BackPatchInfo::FLAG_SIZE_32; - break; - case 119: //lbzux - update = true; - case 87: // lbzx - flags |= BackPatchInfo::FLAG_SIZE_8; - break; - case 311: // lhzux - update = true; - case 279: // lhzx - flags |= BackPatchInfo::FLAG_SIZE_16; - break; - case 375: // lhaux - update = true; - case 343: // lhax - flags |= BackPatchInfo::FLAG_EXTEND | - BackPatchInfo::FLAG_SIZE_16; - break; - case 534: // lwbrx - flags |= BackPatchInfo::FLAG_REVERSE | - BackPatchInfo::FLAG_SIZE_32; - break; - case 790: // lhbrx - flags |= BackPatchInfo::FLAG_REVERSE | - BackPatchInfo::FLAG_SIZE_16; - break; - } - break; - case 33: // lwzu - update = true; - case 32: // lwz - flags |= BackPatchInfo::FLAG_SIZE_32; - break; - case 35: // lbzu - update = true; - case 34: // lbz - flags |= BackPatchInfo::FLAG_SIZE_8; - break; - case 41: // lhzu - update = true; - case 40: // lhz - flags |= BackPatchInfo::FLAG_SIZE_16; - break; - case 43: // lhau - update = true; - case 42: // lha - flags |= BackPatchInfo::FLAG_EXTEND | - BackPatchInfo::FLAG_SIZE_16; - break; - } + switch (inst.OPCD) + { + case 31: + offsetReg = b; + switch (inst.SUBOP10) + { + case 55: // lwzux + update = true; + case 23: // lwzx + flags |= BackPatchInfo::FLAG_SIZE_32; + break; + case 119: // lbzux + update = true; + case 87: // lbzx + flags |= BackPatchInfo::FLAG_SIZE_8; + break; + case 311: // lhzux + update = true; + case 279: // lhzx + flags |= BackPatchInfo::FLAG_SIZE_16; + break; + case 375: // lhaux + update = true; + case 343: // lhax + flags |= BackPatchInfo::FLAG_EXTEND | BackPatchInfo::FLAG_SIZE_16; + break; + case 534: // lwbrx + flags |= BackPatchInfo::FLAG_REVERSE | BackPatchInfo::FLAG_SIZE_32; + break; + case 790: // lhbrx + flags |= BackPatchInfo::FLAG_REVERSE | BackPatchInfo::FLAG_SIZE_16; + break; + } + break; + case 33: // lwzu + update = true; + case 32: // lwz + flags |= BackPatchInfo::FLAG_SIZE_32; + break; + case 35: // lbzu + update = true; + case 34: // lbz + flags |= BackPatchInfo::FLAG_SIZE_8; + break; + case 41: // lhzu + update = true; + case 40: // lhz + flags |= BackPatchInfo::FLAG_SIZE_16; + break; + case 43: // lhau + update = true; + case 42: // lha + flags |= BackPatchInfo::FLAG_EXTEND | BackPatchInfo::FLAG_SIZE_16; + break; + } - SafeLoadToReg(d, update ? a : (a ? a : -1), offsetReg, flags, offset, update); + SafeLoadToReg(d, update ? a : (a ? a : -1), offsetReg, flags, offset, update); - // LWZ idle skipping - if (SConfig::GetInstance().bSkipIdle && - inst.OPCD == 32 && MergeAllowedNextInstructions(2) && - (inst.hex & 0xFFFF0000) == 0x800D0000 && // lwz r0, XXXX(r13) - (js.op[1].inst.hex == 0x28000000 || - (SConfig::GetInstance().bWii && js.op[1].inst.hex == 0x2C000000)) && // cmpXwi r0,0 - js.op[2].inst.hex == 0x4182fff8) // beq -8 - { - // if it's still 0, we can wait until the next event - FixupBranch noIdle = CBNZ(gpr.R(d)); + // LWZ idle skipping + if (SConfig::GetInstance().bSkipIdle && inst.OPCD == 32 && MergeAllowedNextInstructions(2) && + (inst.hex & 0xFFFF0000) == 0x800D0000 && // lwz r0, XXXX(r13) + (js.op[1].inst.hex == 0x28000000 || + (SConfig::GetInstance().bWii && js.op[1].inst.hex == 0x2C000000)) && // cmpXwi r0,0 + js.op[2].inst.hex == 0x4182fff8) // beq -8 + { + // if it's still 0, we can wait until the next event + FixupBranch noIdle = CBNZ(gpr.R(d)); - FixupBranch far = B(); - SwitchToFarCode(); - SetJumpTarget(far); + FixupBranch far = B(); + SwitchToFarCode(); + SetJumpTarget(far); - gpr.Flush(FLUSH_MAINTAIN_STATE); - fpr.Flush(FLUSH_MAINTAIN_STATE); + gpr.Flush(FLUSH_MAINTAIN_STATE); + fpr.Flush(FLUSH_MAINTAIN_STATE); - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); - MOVI2R(XA, (u64)&CoreTiming::Idle); - BLR(XA); - gpr.Unlock(WA); + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); + MOVI2R(XA, (u64)&CoreTiming::Idle); + BLR(XA); + gpr.Unlock(WA); - WriteExceptionExit(js.compilerPC); + WriteExceptionExit(js.compilerPC); - SwitchToNearCode(); + SwitchToNearCode(); - SetJumpTarget(noIdle); - } + SetJumpTarget(noIdle); + } } void JitArm64::stX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); - u32 a = inst.RA, b = inst.RB, s = inst.RS; - s32 offset = inst.SIMM_16; - s32 regOffset = -1; - u32 flags = BackPatchInfo::FLAG_STORE; - bool update = false; - switch (inst.OPCD) - { - case 31: - switch (inst.SUBOP10) - { - case 183: // stwux - update = true; - case 151: // stwx - flags |= BackPatchInfo::FLAG_SIZE_32; - regOffset = b; - break; - case 247: // stbux - update = true; - case 215: // stbx - flags |= BackPatchInfo::FLAG_SIZE_8; - regOffset = b; - break; - case 439: // sthux - update = true; - case 407: // sthx - flags |= BackPatchInfo::FLAG_SIZE_16; - regOffset = b; - break; - } - break; - case 37: // stwu - update = true; - case 36: // stw - flags |= BackPatchInfo::FLAG_SIZE_32; - break; - case 39: // stbu - update = true; - case 38: // stb - flags |= BackPatchInfo::FLAG_SIZE_8; - break; - case 45: // sthu - update = true; - case 44: // sth - flags |= BackPatchInfo::FLAG_SIZE_16; - break; + u32 a = inst.RA, b = inst.RB, s = inst.RS; + s32 offset = inst.SIMM_16; + s32 regOffset = -1; + u32 flags = BackPatchInfo::FLAG_STORE; + bool update = false; + switch (inst.OPCD) + { + case 31: + switch (inst.SUBOP10) + { + case 183: // stwux + update = true; + case 151: // stwx + flags |= BackPatchInfo::FLAG_SIZE_32; + regOffset = b; + break; + case 247: // stbux + update = true; + case 215: // stbx + flags |= BackPatchInfo::FLAG_SIZE_8; + regOffset = b; + break; + case 439: // sthux + update = true; + case 407: // sthx + flags |= BackPatchInfo::FLAG_SIZE_16; + regOffset = b; + break; + } + break; + case 37: // stwu + update = true; + case 36: // stw + flags |= BackPatchInfo::FLAG_SIZE_32; + break; + case 39: // stbu + update = true; + case 38: // stb + flags |= BackPatchInfo::FLAG_SIZE_8; + break; + case 45: // sthu + update = true; + case 44: // sth + flags |= BackPatchInfo::FLAG_SIZE_16; + break; + } - } + SafeStoreFromReg(update ? a : (a ? a : -1), s, regOffset, flags, offset); - SafeStoreFromReg(update ? a : (a ? a : -1), s, regOffset, flags, offset); + if (update) + { + gpr.BindToRegister(a, false); - if (update) - { - gpr.BindToRegister(a, false); - - ARM64Reg WA = gpr.GetReg(); - ARM64Reg RB; - ARM64Reg RA = gpr.R(a); - if (regOffset != -1) - RB = gpr.R(regOffset); - if (regOffset == -1) - { - MOVI2R(WA, offset); - ADD(RA, RA, WA); - } - else - { - ADD(RA, RA, RB); - } - gpr.Unlock(WA); - } + ARM64Reg WA = gpr.GetReg(); + ARM64Reg RB; + ARM64Reg RA = gpr.R(a); + if (regOffset != -1) + RB = gpr.R(regOffset); + if (regOffset == -1) + { + MOVI2R(WA, offset); + ADD(RA, RA, WA); + } + else + { + ADD(RA, RA, RB); + } + gpr.Unlock(WA); + } } void JitArm64::lmw(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(!jo.fastmem || jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(!jo.fastmem || jo.memcheck); - u32 a = inst.RA; + u32 a = inst.RA; - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); - if (a) - { - bool add = inst.SIMM_16 >= 0; - u16 off = std::abs(inst.SIMM_16); - if (off < 4096) - { - if (add) - ADD(WA, gpr.R(a), off); - else - SUB(WA, gpr.R(a), off); - } - else - { - u16 remaining = off >> 12; - if (add) - { - ADD(WA, gpr.R(a), off & 0xFFF); - ADD(WA, WA, remaining, true); - } - else - { - SUB(WA, gpr.R(a), off & 0xFFF); - SUB(WA, WA, remaining, true); - } - } - } - else - { - MOVI2R(WA, (u32)(s32)(s16)inst.SIMM_16); - } + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); + if (a) + { + bool add = inst.SIMM_16 >= 0; + u16 off = std::abs(inst.SIMM_16); + if (off < 4096) + { + if (add) + ADD(WA, gpr.R(a), off); + else + SUB(WA, gpr.R(a), off); + } + else + { + u16 remaining = off >> 12; + if (add) + { + ADD(WA, gpr.R(a), off & 0xFFF); + ADD(WA, WA, remaining, true); + } + else + { + SUB(WA, gpr.R(a), off & 0xFFF); + SUB(WA, WA, remaining, true); + } + } + } + else + { + MOVI2R(WA, (u32)(s32)(s16)inst.SIMM_16); + } - ADD(XA, XA, MEM_REG); + ADD(XA, XA, MEM_REG); - for (int i = inst.RD; i < 32; i++) - { - int remaining = 32 - i; - if (remaining >= 4) - { - gpr.BindToRegister(i + 3, false); - gpr.BindToRegister(i + 2, false); - gpr.BindToRegister(i + 1, false); - gpr.BindToRegister(i, false); - ARM64Reg RX4 = gpr.R(i + 3); - ARM64Reg RX3 = gpr.R(i + 2); - ARM64Reg RX2 = gpr.R(i + 1); - ARM64Reg RX1 = gpr.R(i); - LDP(INDEX_POST, EncodeRegTo64(RX1), EncodeRegTo64(RX3), XA, 16); - REV32(EncodeRegTo64(RX1), EncodeRegTo64(RX1)); - REV32(EncodeRegTo64(RX3), EncodeRegTo64(RX3)); - ORR(EncodeRegTo64(RX2), ZR, EncodeRegTo64(RX1), ArithOption(EncodeRegTo64(RX1), ST_LSR, 32)); - ORR(EncodeRegTo64(RX4), ZR, EncodeRegTo64(RX3), ArithOption(EncodeRegTo64(RX3), ST_LSR, 32)); - i+=3; - } - else if (remaining >= 2) - { - gpr.BindToRegister(i + 1, false); - gpr.BindToRegister(i, false); - ARM64Reg RX2 = gpr.R(i + 1); - ARM64Reg RX1 = gpr.R(i); - LDP(INDEX_POST, RX1, RX2, XA, 8); - REV32(RX1, RX1); - REV32(RX2, RX2); - ++i; - } - else - { - gpr.BindToRegister(i, false); - ARM64Reg RX = gpr.R(i); - LDR(INDEX_POST, RX, XA, 4); - REV32(RX, RX); - } - } + for (int i = inst.RD; i < 32; i++) + { + int remaining = 32 - i; + if (remaining >= 4) + { + gpr.BindToRegister(i + 3, false); + gpr.BindToRegister(i + 2, false); + gpr.BindToRegister(i + 1, false); + gpr.BindToRegister(i, false); + ARM64Reg RX4 = gpr.R(i + 3); + ARM64Reg RX3 = gpr.R(i + 2); + ARM64Reg RX2 = gpr.R(i + 1); + ARM64Reg RX1 = gpr.R(i); + LDP(INDEX_POST, EncodeRegTo64(RX1), EncodeRegTo64(RX3), XA, 16); + REV32(EncodeRegTo64(RX1), EncodeRegTo64(RX1)); + REV32(EncodeRegTo64(RX3), EncodeRegTo64(RX3)); + ORR(EncodeRegTo64(RX2), ZR, EncodeRegTo64(RX1), ArithOption(EncodeRegTo64(RX1), ST_LSR, 32)); + ORR(EncodeRegTo64(RX4), ZR, EncodeRegTo64(RX3), ArithOption(EncodeRegTo64(RX3), ST_LSR, 32)); + i += 3; + } + else if (remaining >= 2) + { + gpr.BindToRegister(i + 1, false); + gpr.BindToRegister(i, false); + ARM64Reg RX2 = gpr.R(i + 1); + ARM64Reg RX1 = gpr.R(i); + LDP(INDEX_POST, RX1, RX2, XA, 8); + REV32(RX1, RX1); + REV32(RX2, RX2); + ++i; + } + else + { + gpr.BindToRegister(i, false); + ARM64Reg RX = gpr.R(i); + LDR(INDEX_POST, RX, XA, 4); + REV32(RX, RX); + } + } - gpr.Unlock(WA); + gpr.Unlock(WA); } void JitArm64::stmw(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(!jo.fastmem || jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(!jo.fastmem || jo.memcheck); - u32 a = inst.RA; + u32 a = inst.RA; - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); - ARM64Reg WB = gpr.GetReg(); + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); + ARM64Reg WB = gpr.GetReg(); - if (a) - { - bool add = inst.SIMM_16 >= 0; - u16 off = std::abs(inst.SIMM_16); - if (off < 4096) - { - if (add) - ADD(WA, gpr.R(a), off); - else - SUB(WA, gpr.R(a), off); - } - else - { - u16 remaining = off >> 12; - if (add) - { - ADD(WA, gpr.R(a), off & 0xFFF); - ADD(WA, WA, remaining, true); - } - else - { - SUB(WA, gpr.R(a), off & 0xFFF); - SUB(WA, WA, remaining, true); - } - } - } - else - { - MOVI2R(WA, (u32)(s32)(s16)inst.SIMM_16); - } + if (a) + { + bool add = inst.SIMM_16 >= 0; + u16 off = std::abs(inst.SIMM_16); + if (off < 4096) + { + if (add) + ADD(WA, gpr.R(a), off); + else + SUB(WA, gpr.R(a), off); + } + else + { + u16 remaining = off >> 12; + if (add) + { + ADD(WA, gpr.R(a), off & 0xFFF); + ADD(WA, WA, remaining, true); + } + else + { + SUB(WA, gpr.R(a), off & 0xFFF); + SUB(WA, WA, remaining, true); + } + } + } + else + { + MOVI2R(WA, (u32)(s32)(s16)inst.SIMM_16); + } - u8* base = UReg_MSR(MSR).DR ? Memory::logical_base : Memory::physical_base; - MOVK(XA, ((u64)base >> 32) & 0xFFFF, SHIFT_32); + u8* base = UReg_MSR(MSR).DR ? Memory::logical_base : Memory::physical_base; + MOVK(XA, ((u64)base >> 32) & 0xFFFF, SHIFT_32); - for (int i = inst.RD; i < 32; i++) - { - ARM64Reg RX = gpr.R(i); - REV32(WB, RX); - STR(INDEX_UNSIGNED, WB, XA, (i - inst.RD) * 4); - } + for (int i = inst.RD; i < 32; i++) + { + ARM64Reg RX = gpr.R(i); + REV32(WB, RX); + STR(INDEX_UNSIGNED, WB, XA, (i - inst.RD) * 4); + } - gpr.Unlock(WA, WB); + gpr.Unlock(WA, WB); } void JitArm64::dcbx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); - gpr.Lock(W30); + gpr.Lock(W30); - ARM64Reg addr = gpr.GetReg(); - ARM64Reg value = gpr.GetReg(); - ARM64Reg WA = W30; + ARM64Reg addr = gpr.GetReg(); + ARM64Reg value = gpr.GetReg(); + ARM64Reg WA = W30; - u32 a = inst.RA, b = inst.RB; + u32 a = inst.RA, b = inst.RB; - if (a) - ADD(addr, gpr.R(a), gpr.R(b)); - else - MOV(addr, gpr.R(b)); + if (a) + ADD(addr, gpr.R(a), gpr.R(b)); + else + MOV(addr, gpr.R(b)); - // Check whether a JIT cache line needs to be invalidated. - AND(value, addr, 32 - 10, 28 - 10); // upper three bits and last 10 bit are masked for the bitset of cachelines, 0x1ffffc00 - LSR(value, value, 5 + 5); // >> 5 for cache line size, >> 5 for width of bitset - MOVI2R(EncodeRegTo64(WA), (u64)jit->GetBlockCache()->GetBlockBitSet()); - LDR(value, EncodeRegTo64(WA), ArithOption(EncodeRegTo64(value), true)); + // Check whether a JIT cache line needs to be invalidated. + AND(value, addr, 32 - 10, 28 - 10); // upper three bits and last 10 bit are masked for the bitset + // of cachelines, 0x1ffffc00 + LSR(value, value, 5 + 5); // >> 5 for cache line size, >> 5 for width of bitset + MOVI2R(EncodeRegTo64(WA), (u64)jit->GetBlockCache()->GetBlockBitSet()); + LDR(value, EncodeRegTo64(WA), ArithOption(EncodeRegTo64(value), true)); - LSR(addr, addr, 5); // mask sizeof cacheline, & 0x1f is the position within the bitset + LSR(addr, addr, 5); // mask sizeof cacheline, & 0x1f is the position within the bitset - LSR(value, value, addr); // move current bit to bit 0 + LSR(value, value, addr); // move current bit to bit 0 - FixupBranch bit_not_set = TBZ(value, 0); - FixupBranch far = B(); - SwitchToFarCode(); - SetJumpTarget(far); + FixupBranch bit_not_set = TBZ(value, 0); + FixupBranch far = B(); + SwitchToFarCode(); + SetJumpTarget(far); - BitSet32 gprs_to_push = gpr.GetCallerSavedUsed(); - BitSet32 fprs_to_push = fpr.GetCallerSavedUsed(); + BitSet32 gprs_to_push = gpr.GetCallerSavedUsed(); + BitSet32 fprs_to_push = fpr.GetCallerSavedUsed(); - ABI_PushRegisters(gprs_to_push); - m_float_emit.ABI_PushRegisters(fprs_to_push, X30); + ABI_PushRegisters(gprs_to_push); + m_float_emit.ABI_PushRegisters(fprs_to_push, X30); - LSL(W0, addr, 5); - MOVI2R(X1, 32); - MOVI2R(X2, 0); - MOVI2R(X3, (u64)(void*)JitInterface::InvalidateICache); - BLR(X3); + LSL(W0, addr, 5); + MOVI2R(X1, 32); + MOVI2R(X2, 0); + MOVI2R(X3, (u64)(void*)JitInterface::InvalidateICache); + BLR(X3); - m_float_emit.ABI_PopRegisters(fprs_to_push, X30); - ABI_PopRegisters(gprs_to_push); + m_float_emit.ABI_PopRegisters(fprs_to_push, X30); + ABI_PopRegisters(gprs_to_push); - FixupBranch near = B(); - SwitchToNearCode(); - SetJumpTarget(bit_not_set); - SetJumpTarget(near); + FixupBranch near = B(); + SwitchToNearCode(); + SetJumpTarget(bit_not_set); + SetJumpTarget(near); - // dcbi - if (inst.SUBOP10 == 470) - { - // Flush DSP DMA if DMAState bit is set - MOVI2R(EncodeRegTo64(WA), (u64)&DSP::g_dspState); - LDRH(INDEX_UNSIGNED, WA, EncodeRegTo64(WA), 0); + // dcbi + if (inst.SUBOP10 == 470) + { + // Flush DSP DMA if DMAState bit is set + MOVI2R(EncodeRegTo64(WA), (u64)&DSP::g_dspState); + LDRH(INDEX_UNSIGNED, WA, EncodeRegTo64(WA), 0); - bit_not_set = TBZ(WA, 9); - far = B(); - SwitchToFarCode(); - SetJumpTarget(far); + bit_not_set = TBZ(WA, 9); + far = B(); + SwitchToFarCode(); + SetJumpTarget(far); - ABI_PushRegisters(gprs_to_push); - m_float_emit.ABI_PushRegisters(fprs_to_push, X30); + ABI_PushRegisters(gprs_to_push); + m_float_emit.ABI_PushRegisters(fprs_to_push, X30); - LSL(W0, addr, 5); - MOVI2R(X1, (u64)DSP::FlushInstantDMA); - BLR(X1); + LSL(W0, addr, 5); + MOVI2R(X1, (u64)DSP::FlushInstantDMA); + BLR(X1); - m_float_emit.ABI_PopRegisters(fprs_to_push, X30); - ABI_PopRegisters(gprs_to_push); + m_float_emit.ABI_PopRegisters(fprs_to_push, X30); + ABI_PopRegisters(gprs_to_push); - near = B(); - SwitchToNearCode(); - SetJumpTarget(near); - SetJumpTarget(bit_not_set); - } + near = B(); + SwitchToNearCode(); + SetJumpTarget(near); + SetJumpTarget(bit_not_set); + } - gpr.Unlock(addr, value, W30); + gpr.Unlock(addr, value, W30); } void JitArm64::dcbt(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); - // Prefetch. Since we don't emulate the data cache, we don't need to do anything. + // Prefetch. Since we don't emulate the data cache, we don't need to do anything. - // If a dcbst follows a dcbt, it probably isn't a case of dynamic code - // modification, so don't bother invalidating the jit block cache. - // This is important because invalidating the block cache when we don't - // need to is terrible for performance. - // (Invalidating the jit block cache on dcbst is a heuristic.) - if (MergeAllowedNextInstructions(1) && - js.op[1].inst.OPCD == 31 && js.op[1].inst.SUBOP10 == 54 && - js.op[1].inst.RA == inst.RA && js.op[1].inst.RB == inst.RB) - { - js.skipInstructions = 1; - } + // If a dcbst follows a dcbt, it probably isn't a case of dynamic code + // modification, so don't bother invalidating the jit block cache. + // This is important because invalidating the block cache when we don't + // need to is terrible for performance. + // (Invalidating the jit block cache on dcbst is a heuristic.) + if (MergeAllowedNextInstructions(1) && js.op[1].inst.OPCD == 31 && js.op[1].inst.SUBOP10 == 54 && + js.op[1].inst.RA == inst.RA && js.op[1].inst.RB == inst.RB) + { + js.skipInstructions = 1; + } } void JitArm64::dcbz(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); - int a = inst.RA, b = inst.RB; + int a = inst.RA, b = inst.RB; - u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS; + u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS; - // The following masks the region used by the GC/Wii virtual memory lib - mem_mask |= Memory::ADDR_MASK_MEM1; + // The following masks the region used by the GC/Wii virtual memory lib + mem_mask |= Memory::ADDR_MASK_MEM1; - gpr.Lock(W0); + gpr.Lock(W0); - ARM64Reg addr_reg = W0; + ARM64Reg addr_reg = W0; - if (a) - { - bool is_imm_a, is_imm_b; - is_imm_a = gpr.IsImm(a); - is_imm_b = gpr.IsImm(b); - if (is_imm_a && is_imm_b) - { - // full imm_addr - u32 imm_addr = gpr.GetImm(b) + gpr.GetImm(a); - MOVI2R(addr_reg, imm_addr); - } - else if (is_imm_a || is_imm_b) - { - // Only one register is an immediate - ARM64Reg base = is_imm_a ? gpr.R(b) : gpr.R(a); - u32 imm_offset = is_imm_a ? gpr.GetImm(a) : gpr.GetImm(b); - if (imm_offset < 4096) - { - ADD(addr_reg, base, imm_offset); - } - else - { - MOVI2R(addr_reg, imm_offset); - ADD(addr_reg, addr_reg, base); - } - } - else - { - // Both are registers - ADD(addr_reg, gpr.R(a), gpr.R(b)); - } - } - else - { - // RA isn't used, only RB - if (gpr.IsImm(b)) - { - u32 imm_addr = gpr.GetImm(b); - MOVI2R(addr_reg, imm_addr); - } - else - { - MOV(addr_reg, gpr.R(b)); - } - } + if (a) + { + bool is_imm_a, is_imm_b; + is_imm_a = gpr.IsImm(a); + is_imm_b = gpr.IsImm(b); + if (is_imm_a && is_imm_b) + { + // full imm_addr + u32 imm_addr = gpr.GetImm(b) + gpr.GetImm(a); + MOVI2R(addr_reg, imm_addr); + } + else if (is_imm_a || is_imm_b) + { + // Only one register is an immediate + ARM64Reg base = is_imm_a ? gpr.R(b) : gpr.R(a); + u32 imm_offset = is_imm_a ? gpr.GetImm(a) : gpr.GetImm(b); + if (imm_offset < 4096) + { + ADD(addr_reg, base, imm_offset); + } + else + { + MOVI2R(addr_reg, imm_offset); + ADD(addr_reg, addr_reg, base); + } + } + else + { + // Both are registers + ADD(addr_reg, gpr.R(a), gpr.R(b)); + } + } + else + { + // RA isn't used, only RB + if (gpr.IsImm(b)) + { + u32 imm_addr = gpr.GetImm(b); + MOVI2R(addr_reg, imm_addr); + } + else + { + MOV(addr_reg, gpr.R(b)); + } + } - // We don't care about being /too/ terribly efficient here - // As long as we aren't falling back to interpreter we're winning a lot + // We don't care about being /too/ terribly efficient here + // As long as we aren't falling back to interpreter we're winning a lot - BitSet32 gprs_to_push = gpr.GetCallerSavedUsed(); - BitSet32 fprs_to_push = fpr.GetCallerSavedUsed(); - gprs_to_push[W0] = 0; + BitSet32 gprs_to_push = gpr.GetCallerSavedUsed(); + BitSet32 fprs_to_push = fpr.GetCallerSavedUsed(); + gprs_to_push[W0] = 0; - EmitBackpatchRoutine(BackPatchInfo::FLAG_ZERO_256, true, true, W0, EncodeRegTo64(addr_reg), gprs_to_push, fprs_to_push); - - gpr.Unlock(W0); + EmitBackpatchRoutine(BackPatchInfo::FLAG_ZERO_256, true, true, W0, EncodeRegTo64(addr_reg), + gprs_to_push, fprs_to_push); + gpr.Unlock(W0); } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStoreFloating.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStoreFloating.cpp index 69ed5811d3..256b724c72 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStoreFloating.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStoreFloating.cpp @@ -12,462 +12,458 @@ #include "Core/Core.h" #include "Core/CoreTiming.h" #include "Core/HW/GPFifo.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCTables.h" #include "Core/PowerPC/JitArm64/Jit.h" #include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" +#include "Core/PowerPC/PPCTables.h" +#include "Core/PowerPC/PowerPC.h" using namespace Arm64Gen; void JitArm64::lfXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreFloatingOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreFloatingOff); + FALLBACK_IF(jo.memcheck); - u32 a = inst.RA, b = inst.RB; + u32 a = inst.RA, b = inst.RB; - s32 offset = inst.SIMM_16; - u32 flags = BackPatchInfo::FLAG_LOAD; - bool update = false; - s32 offset_reg = -1; + s32 offset = inst.SIMM_16; + u32 flags = BackPatchInfo::FLAG_LOAD; + bool update = false; + s32 offset_reg = -1; - switch (inst.OPCD) - { - case 31: - switch (inst.SUBOP10) - { - case 567: // lfsux - flags |= BackPatchInfo::FLAG_SIZE_F32; - update = true; - offset_reg = b; - break; - case 535: // lfsx - flags |= BackPatchInfo::FLAG_SIZE_F32; - offset_reg = b; - break; - case 631: // lfdux - flags |= BackPatchInfo::FLAG_SIZE_F64; - update = true; - offset_reg = b; - break; - case 599: // lfdx - flags |= BackPatchInfo::FLAG_SIZE_F64; - offset_reg = b; - break; - } - break; - case 49: // lfsu - flags |= BackPatchInfo::FLAG_SIZE_F32; - update = true; - break; - case 48: // lfs - flags |= BackPatchInfo::FLAG_SIZE_F32; - break; - case 51: // lfdu - flags |= BackPatchInfo::FLAG_SIZE_F64; - update = true; - break; - case 50: // lfd - flags |= BackPatchInfo::FLAG_SIZE_F64; - break; - } + switch (inst.OPCD) + { + case 31: + switch (inst.SUBOP10) + { + case 567: // lfsux + flags |= BackPatchInfo::FLAG_SIZE_F32; + update = true; + offset_reg = b; + break; + case 535: // lfsx + flags |= BackPatchInfo::FLAG_SIZE_F32; + offset_reg = b; + break; + case 631: // lfdux + flags |= BackPatchInfo::FLAG_SIZE_F64; + update = true; + offset_reg = b; + break; + case 599: // lfdx + flags |= BackPatchInfo::FLAG_SIZE_F64; + offset_reg = b; + break; + } + break; + case 49: // lfsu + flags |= BackPatchInfo::FLAG_SIZE_F32; + update = true; + break; + case 48: // lfs + flags |= BackPatchInfo::FLAG_SIZE_F32; + break; + case 51: // lfdu + flags |= BackPatchInfo::FLAG_SIZE_F64; + update = true; + break; + case 50: // lfd + flags |= BackPatchInfo::FLAG_SIZE_F64; + break; + } - u32 imm_addr = 0; - bool is_immediate = false; + u32 imm_addr = 0; + bool is_immediate = false; - RegType type = !!(flags & BackPatchInfo::FLAG_SIZE_F64) ? REG_LOWER_PAIR : REG_DUP_SINGLE; + RegType type = !!(flags & BackPatchInfo::FLAG_SIZE_F64) ? REG_LOWER_PAIR : REG_DUP_SINGLE; - gpr.Lock(W0, W30); - fpr.Lock(Q0); + gpr.Lock(W0, W30); + fpr.Lock(Q0); - ARM64Reg VD = fpr.RW(inst.FD, type); - ARM64Reg addr_reg = W0; + ARM64Reg VD = fpr.RW(inst.FD, type); + ARM64Reg addr_reg = W0; - if (update) - { - // Always uses RA - if (gpr.IsImm(a) && offset_reg == -1) - { - is_immediate = true; - imm_addr = offset + gpr.GetImm(a); - } - else if (gpr.IsImm(a) && offset_reg != -1 && gpr.IsImm(offset_reg)) - { - is_immediate = true; - imm_addr = gpr.GetImm(a) + gpr.GetImm(offset_reg); - } - else - { - if (offset_reg == -1) - { - if (offset >= 0 && offset < 4096) - { - ADD(addr_reg, gpr.R(a), offset); - } - else if (offset < 0 && offset > -4096) - { - SUB(addr_reg, gpr.R(a), std::abs(offset)); - } - else - { - MOVI2R(addr_reg, offset); - ADD(addr_reg, addr_reg, gpr.R(a)); - } } - else - { - ADD(addr_reg, gpr.R(offset_reg), gpr.R(a)); - } - } - } - else - { - if (offset_reg == -1) - { - if (a && gpr.IsImm(a)) - { - is_immediate = true; - imm_addr = gpr.GetImm(a) + offset; - } - else if (a) - { - if (offset >= 0 && offset < 4096) - { - ADD(addr_reg, gpr.R(a), offset); - } - else if (offset < 0 && offset > -4096) - { - SUB(addr_reg, gpr.R(a), std::abs(offset)); - } - else - { - MOVI2R(addr_reg, offset); - ADD(addr_reg, addr_reg, gpr.R(a)); - } } - else - { - is_immediate = true; - imm_addr = offset; - } - } - else - { - if (a && gpr.IsImm(a) && gpr.IsImm(offset_reg)) - { - is_immediate = true; - imm_addr = gpr.GetImm(a) + gpr.GetImm(offset_reg); - } - else if (!a && gpr.IsImm(offset_reg)) - { - is_immediate = true; - imm_addr = gpr.GetImm(offset_reg); - } - else if (a) - { - ADD(addr_reg, gpr.R(a), gpr.R(offset_reg)); - } - else - { - MOV(addr_reg, gpr.R(offset_reg)); - } - } - } + if (update) + { + // Always uses RA + if (gpr.IsImm(a) && offset_reg == -1) + { + is_immediate = true; + imm_addr = offset + gpr.GetImm(a); + } + else if (gpr.IsImm(a) && offset_reg != -1 && gpr.IsImm(offset_reg)) + { + is_immediate = true; + imm_addr = gpr.GetImm(a) + gpr.GetImm(offset_reg); + } + else + { + if (offset_reg == -1) + { + if (offset >= 0 && offset < 4096) + { + ADD(addr_reg, gpr.R(a), offset); + } + else if (offset < 0 && offset > -4096) + { + SUB(addr_reg, gpr.R(a), std::abs(offset)); + } + else + { + MOVI2R(addr_reg, offset); + ADD(addr_reg, addr_reg, gpr.R(a)); + } + } + else + { + ADD(addr_reg, gpr.R(offset_reg), gpr.R(a)); + } + } + } + else + { + if (offset_reg == -1) + { + if (a && gpr.IsImm(a)) + { + is_immediate = true; + imm_addr = gpr.GetImm(a) + offset; + } + else if (a) + { + if (offset >= 0 && offset < 4096) + { + ADD(addr_reg, gpr.R(a), offset); + } + else if (offset < 0 && offset > -4096) + { + SUB(addr_reg, gpr.R(a), std::abs(offset)); + } + else + { + MOVI2R(addr_reg, offset); + ADD(addr_reg, addr_reg, gpr.R(a)); + } + } + else + { + is_immediate = true; + imm_addr = offset; + } + } + else + { + if (a && gpr.IsImm(a) && gpr.IsImm(offset_reg)) + { + is_immediate = true; + imm_addr = gpr.GetImm(a) + gpr.GetImm(offset_reg); + } + else if (!a && gpr.IsImm(offset_reg)) + { + is_immediate = true; + imm_addr = gpr.GetImm(offset_reg); + } + else if (a) + { + ADD(addr_reg, gpr.R(a), gpr.R(offset_reg)); + } + else + { + MOV(addr_reg, gpr.R(offset_reg)); + } + } + } - ARM64Reg XA = EncodeRegTo64(addr_reg); + ARM64Reg XA = EncodeRegTo64(addr_reg); - if (is_immediate) - MOVI2R(XA, imm_addr); + if (is_immediate) + MOVI2R(XA, imm_addr); - if (update) - { - gpr.BindToRegister(a, false); - MOV(gpr.R(a), addr_reg); - } + if (update) + { + gpr.BindToRegister(a, false); + MOV(gpr.R(a), addr_reg); + } - BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); - BitSet32 fprs_in_use = fpr.GetCallerSavedUsed(); - regs_in_use[W0] = 0; - fprs_in_use[0] = 0; // Q0 - fprs_in_use[VD - Q0] = 0; + BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); + BitSet32 fprs_in_use = fpr.GetCallerSavedUsed(); + regs_in_use[W0] = 0; + fprs_in_use[0] = 0; // Q0 + fprs_in_use[VD - Q0] = 0; - if (is_immediate && PowerPC::IsOptimizableRAMAddress(imm_addr)) - { - EmitBackpatchRoutine(flags, true, false, VD, XA, BitSet32(0), BitSet32(0)); - } - else - { - EmitBackpatchRoutine(flags, - jo.fastmem, - jo.fastmem, - VD, XA, - regs_in_use, fprs_in_use); - } + if (is_immediate && PowerPC::IsOptimizableRAMAddress(imm_addr)) + { + EmitBackpatchRoutine(flags, true, false, VD, XA, BitSet32(0), BitSet32(0)); + } + else + { + EmitBackpatchRoutine(flags, jo.fastmem, jo.fastmem, VD, XA, regs_in_use, fprs_in_use); + } - gpr.Unlock(W0, W30); - fpr.Unlock(Q0); + gpr.Unlock(W0, W30); + fpr.Unlock(Q0); } void JitArm64::stfXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreFloatingOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreFloatingOff); + FALLBACK_IF(jo.memcheck); - u32 a = inst.RA, b = inst.RB; + u32 a = inst.RA, b = inst.RB; - s32 offset = inst.SIMM_16; - u32 flags = BackPatchInfo::FLAG_STORE; - bool update = false; - s32 offset_reg = -1; + s32 offset = inst.SIMM_16; + u32 flags = BackPatchInfo::FLAG_STORE; + bool update = false; + s32 offset_reg = -1; - switch (inst.OPCD) - { - case 31: - switch (inst.SUBOP10) - { - case 663: // stfsx - flags |= BackPatchInfo::FLAG_SIZE_F32; - offset_reg = b; - break; - case 695: // stfsux - flags |= BackPatchInfo::FLAG_SIZE_F32; - update = true; - offset_reg = b; - break; - case 727: // stfdx - flags |= BackPatchInfo::FLAG_SIZE_F64; - offset_reg = b; - break; - case 759: // stfdux - flags |= BackPatchInfo::FLAG_SIZE_F64; - update = true; - offset_reg = b; - break; - case 983: // stfiwx - flags |= BackPatchInfo::FLAG_SIZE_F32I; - offset_reg = b; - break; - } - break; - case 53: // stfsu - flags |= BackPatchInfo::FLAG_SIZE_F32; - update = true; - break; - case 52: // stfs - flags |= BackPatchInfo::FLAG_SIZE_F32; - break; - case 55: // stfdu - flags |= BackPatchInfo::FLAG_SIZE_F64; - update = true; - break; - case 54: // stfd - flags |= BackPatchInfo::FLAG_SIZE_F64; - break; - } + switch (inst.OPCD) + { + case 31: + switch (inst.SUBOP10) + { + case 663: // stfsx + flags |= BackPatchInfo::FLAG_SIZE_F32; + offset_reg = b; + break; + case 695: // stfsux + flags |= BackPatchInfo::FLAG_SIZE_F32; + update = true; + offset_reg = b; + break; + case 727: // stfdx + flags |= BackPatchInfo::FLAG_SIZE_F64; + offset_reg = b; + break; + case 759: // stfdux + flags |= BackPatchInfo::FLAG_SIZE_F64; + update = true; + offset_reg = b; + break; + case 983: // stfiwx + flags |= BackPatchInfo::FLAG_SIZE_F32I; + offset_reg = b; + break; + } + break; + case 53: // stfsu + flags |= BackPatchInfo::FLAG_SIZE_F32; + update = true; + break; + case 52: // stfs + flags |= BackPatchInfo::FLAG_SIZE_F32; + break; + case 55: // stfdu + flags |= BackPatchInfo::FLAG_SIZE_F64; + update = true; + break; + case 54: // stfd + flags |= BackPatchInfo::FLAG_SIZE_F64; + break; + } - u32 imm_addr = 0; - bool is_immediate = false; + u32 imm_addr = 0; + bool is_immediate = false; - gpr.Lock(W0, W1, W30); - fpr.Lock(Q0); + gpr.Lock(W0, W1, W30); + fpr.Lock(Q0); - bool single = (flags & BackPatchInfo::FLAG_SIZE_F32) && fpr.IsSingle(inst.FS, true); + bool single = (flags & BackPatchInfo::FLAG_SIZE_F32) && fpr.IsSingle(inst.FS, true); - ARM64Reg V0 = fpr.R(inst.FS, single ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR); + ARM64Reg V0 = fpr.R(inst.FS, single ? REG_LOWER_PAIR_SINGLE : REG_LOWER_PAIR); - if (single) - { - flags &= ~BackPatchInfo::FLAG_SIZE_F32; - flags |= BackPatchInfo::FLAG_SIZE_F32I; - } + if (single) + { + flags &= ~BackPatchInfo::FLAG_SIZE_F32; + flags |= BackPatchInfo::FLAG_SIZE_F32I; + } - ARM64Reg addr_reg = W1; + ARM64Reg addr_reg = W1; - if (update) - { - // Always uses RA - if (gpr.IsImm(a) && offset_reg == -1) - { - is_immediate = true; - imm_addr = offset + gpr.GetImm(a); - } - else if (gpr.IsImm(a) && offset_reg != -1 && gpr.IsImm(offset_reg)) - { - is_immediate = true; - imm_addr = gpr.GetImm(a) + gpr.GetImm(offset_reg); - } - else - { - if (offset_reg == -1) - { - if (offset >= 0 && offset < 4096) - { - ADD(addr_reg, gpr.R(a), offset); - } - else if (offset < 0 && offset > -4096) - { - SUB(addr_reg, gpr.R(a), std::abs(offset)); - } - else - { - MOVI2R(addr_reg, offset); - ADD(addr_reg, addr_reg, gpr.R(a)); - } - } - else - { - ADD(addr_reg, gpr.R(offset_reg), gpr.R(a)); - } - } - } - else - { - if (offset_reg == -1) - { - if (a && gpr.IsImm(a)) - { - is_immediate = true; - imm_addr = gpr.GetImm(a) + offset; - } - else if (a) - { - if (offset >= 0 && offset < 4096) - { - ADD(addr_reg, gpr.R(a), offset); - } - else if (offset < 0 && offset > -4096) - { - SUB(addr_reg, gpr.R(a), std::abs(offset)); - } - else - { - MOVI2R(addr_reg, offset); - ADD(addr_reg, addr_reg, gpr.R(a)); - } } - else - { - is_immediate = true; - imm_addr = offset; - } - } - else - { - if (a && gpr.IsImm(a) && gpr.IsImm(offset_reg)) - { - is_immediate = true; - imm_addr = gpr.GetImm(a) + gpr.GetImm(offset_reg); - } - else if (!a && gpr.IsImm(offset_reg)) - { - is_immediate = true; - imm_addr = gpr.GetImm(offset_reg); - } - else if (a) - { - ADD(addr_reg, gpr.R(a), gpr.R(offset_reg)); - } - else - { - MOV(addr_reg, gpr.R(offset_reg)); - } - } - } + if (update) + { + // Always uses RA + if (gpr.IsImm(a) && offset_reg == -1) + { + is_immediate = true; + imm_addr = offset + gpr.GetImm(a); + } + else if (gpr.IsImm(a) && offset_reg != -1 && gpr.IsImm(offset_reg)) + { + is_immediate = true; + imm_addr = gpr.GetImm(a) + gpr.GetImm(offset_reg); + } + else + { + if (offset_reg == -1) + { + if (offset >= 0 && offset < 4096) + { + ADD(addr_reg, gpr.R(a), offset); + } + else if (offset < 0 && offset > -4096) + { + SUB(addr_reg, gpr.R(a), std::abs(offset)); + } + else + { + MOVI2R(addr_reg, offset); + ADD(addr_reg, addr_reg, gpr.R(a)); + } + } + else + { + ADD(addr_reg, gpr.R(offset_reg), gpr.R(a)); + } + } + } + else + { + if (offset_reg == -1) + { + if (a && gpr.IsImm(a)) + { + is_immediate = true; + imm_addr = gpr.GetImm(a) + offset; + } + else if (a) + { + if (offset >= 0 && offset < 4096) + { + ADD(addr_reg, gpr.R(a), offset); + } + else if (offset < 0 && offset > -4096) + { + SUB(addr_reg, gpr.R(a), std::abs(offset)); + } + else + { + MOVI2R(addr_reg, offset); + ADD(addr_reg, addr_reg, gpr.R(a)); + } + } + else + { + is_immediate = true; + imm_addr = offset; + } + } + else + { + if (a && gpr.IsImm(a) && gpr.IsImm(offset_reg)) + { + is_immediate = true; + imm_addr = gpr.GetImm(a) + gpr.GetImm(offset_reg); + } + else if (!a && gpr.IsImm(offset_reg)) + { + is_immediate = true; + imm_addr = gpr.GetImm(offset_reg); + } + else if (a) + { + ADD(addr_reg, gpr.R(a), gpr.R(offset_reg)); + } + else + { + MOV(addr_reg, gpr.R(offset_reg)); + } + } + } - ARM64Reg XA = EncodeRegTo64(addr_reg); + ARM64Reg XA = EncodeRegTo64(addr_reg); - if (is_immediate && !(jit->jo.optimizeGatherPipe && PowerPC::IsOptimizableGatherPipeWrite(imm_addr))) - { - MOVI2R(XA, imm_addr); + if (is_immediate && + !(jit->jo.optimizeGatherPipe && PowerPC::IsOptimizableGatherPipeWrite(imm_addr))) + { + MOVI2R(XA, imm_addr); - if (update) - { - gpr.BindToRegister(a, false); - MOV(gpr.R(a), addr_reg); - } - } - else if (!is_immediate && update) - { - gpr.BindToRegister(a, false); - MOV(gpr.R(a), addr_reg); - } + if (update) + { + gpr.BindToRegister(a, false); + MOV(gpr.R(a), addr_reg); + } + } + else if (!is_immediate && update) + { + gpr.BindToRegister(a, false); + MOV(gpr.R(a), addr_reg); + } - BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); - BitSet32 fprs_in_use = fpr.GetCallerSavedUsed(); - regs_in_use[W0] = 0; - regs_in_use[W1] = 0; - fprs_in_use[0] = 0; // Q0 + BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); + BitSet32 fprs_in_use = fpr.GetCallerSavedUsed(); + regs_in_use[W0] = 0; + regs_in_use[W1] = 0; + fprs_in_use[0] = 0; // Q0 - if (is_immediate) - { - if (jit->jo.optimizeGatherPipe && PowerPC::IsOptimizableGatherPipeWrite(imm_addr)) - { - int accessSize; - if (flags & BackPatchInfo::FLAG_SIZE_F64) - accessSize = 64; - else - accessSize = 32; + if (is_immediate) + { + if (jit->jo.optimizeGatherPipe && PowerPC::IsOptimizableGatherPipeWrite(imm_addr)) + { + int accessSize; + if (flags & BackPatchInfo::FLAG_SIZE_F64) + accessSize = 64; + else + accessSize = 32; - u64 base_ptr = std::min((u64)&GPFifo::m_gatherPipeCount, (u64)&GPFifo::m_gatherPipe); - u32 count_off = (u64)&GPFifo::m_gatherPipeCount - base_ptr; - u32 pipe_off = (u64)&GPFifo::m_gatherPipe - base_ptr; + u64 base_ptr = std::min((u64)&GPFifo::m_gatherPipeCount, (u64)&GPFifo::m_gatherPipe); + u32 count_off = (u64)&GPFifo::m_gatherPipeCount - base_ptr; + u32 pipe_off = (u64)&GPFifo::m_gatherPipe - base_ptr; - MOVI2R(X30, base_ptr); + MOVI2R(X30, base_ptr); - if (pipe_off) - ADD(X1, X30, pipe_off); + if (pipe_off) + ADD(X1, X30, pipe_off); - LDR(INDEX_UNSIGNED, W0, X30, count_off); - if (flags & BackPatchInfo::FLAG_SIZE_F64) - { - m_float_emit.REV64(8, Q0, V0); - } - else if (flags & BackPatchInfo::FLAG_SIZE_F32) - { - m_float_emit.FCVT(32, 64, D0, EncodeRegToDouble(V0)); - m_float_emit.REV32(8, D0, D0); - } - else if (flags & BackPatchInfo::FLAG_SIZE_F32I) - { - m_float_emit.REV32(8, D0, V0); - } + LDR(INDEX_UNSIGNED, W0, X30, count_off); + if (flags & BackPatchInfo::FLAG_SIZE_F64) + { + m_float_emit.REV64(8, Q0, V0); + } + else if (flags & BackPatchInfo::FLAG_SIZE_F32) + { + m_float_emit.FCVT(32, 64, D0, EncodeRegToDouble(V0)); + m_float_emit.REV32(8, D0, D0); + } + else if (flags & BackPatchInfo::FLAG_SIZE_F32I) + { + m_float_emit.REV32(8, D0, V0); + } - if (pipe_off) - { - m_float_emit.STR(accessSize, accessSize == 64 ? Q0 : D0, X1, ArithOption(X0)); - } - else - { - m_float_emit.STR(accessSize, accessSize == 64 ? Q0 : D0, X30, ArithOption(X0)); - } + if (pipe_off) + { + m_float_emit.STR(accessSize, accessSize == 64 ? Q0 : D0, X1, ArithOption(X0)); + } + else + { + m_float_emit.STR(accessSize, accessSize == 64 ? Q0 : D0, X30, ArithOption(X0)); + } - ADD(W0, W0, accessSize >> 3); - STR(INDEX_UNSIGNED, W0, X30, count_off); - js.fifoBytesThisBlock += accessSize >> 3; + ADD(W0, W0, accessSize >> 3); + STR(INDEX_UNSIGNED, W0, X30, count_off); + js.fifoBytesThisBlock += accessSize >> 3; - if (update) - { - // Chance of this happening is fairly low, but support it - gpr.BindToRegister(a, false); - MOVI2R(gpr.R(a), imm_addr); - } - } - else if (PowerPC::IsOptimizableRAMAddress(imm_addr)) - { - EmitBackpatchRoutine(flags, true, false, V0, XA, BitSet32(0), BitSet32(0)); - } - else - { - EmitBackpatchRoutine(flags, false, false, V0, XA, regs_in_use, fprs_in_use); - } - } - else - { - EmitBackpatchRoutine(flags, - jo.fastmem, - jo.fastmem, - V0, XA, - regs_in_use, fprs_in_use); - } - gpr.Unlock(W0, W1, W30); - fpr.Unlock(Q0); + if (update) + { + // Chance of this happening is fairly low, but support it + gpr.BindToRegister(a, false); + MOVI2R(gpr.R(a), imm_addr); + } + } + else if (PowerPC::IsOptimizableRAMAddress(imm_addr)) + { + EmitBackpatchRoutine(flags, true, false, V0, XA, BitSet32(0), BitSet32(0)); + } + else + { + EmitBackpatchRoutine(flags, false, false, V0, XA, regs_in_use, fprs_in_use); + } + } + else + { + EmitBackpatchRoutine(flags, jo.fastmem, jo.fastmem, V0, XA, regs_in_use, fprs_in_use); + } + gpr.Unlock(W0, W1, W30); + fpr.Unlock(Q0); } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStorePaired.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStorePaired.cpp index 60f1faac9a..40faf8da57 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStorePaired.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStorePaired.cpp @@ -10,207 +10,202 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCTables.h" #include "Core/PowerPC/JitArm64/Jit.h" #include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" +#include "Core/PowerPC/PPCTables.h" +#include "Core/PowerPC/PowerPC.h" using namespace Arm64Gen; void JitArm64::psq_l(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStorePairedOff); - FALLBACK_IF(jo.memcheck || !jo.fastmem); + INSTRUCTION_START + JITDISABLE(bJITLoadStorePairedOff); + FALLBACK_IF(jo.memcheck || !jo.fastmem); - // X30 is LR - // X0 contains the scale - // X1 is the address - // X2 is a temporary - // Q0 is the return register - // Q1 is a temporary - bool update = inst.OPCD == 57; - s32 offset = inst.SIMM_12; + // X30 is LR + // X0 contains the scale + // X1 is the address + // X2 is a temporary + // Q0 is the return register + // Q1 is a temporary + bool update = inst.OPCD == 57; + s32 offset = inst.SIMM_12; - gpr.Lock(W0, W1, W2, W30); - fpr.Lock(Q0, Q1); + gpr.Lock(W0, W1, W2, W30); + fpr.Lock(Q0, Q1); - ARM64Reg arm_addr = gpr.R(inst.RA); - ARM64Reg scale_reg = W0; - ARM64Reg addr_reg = W1; - ARM64Reg type_reg = W2; - ARM64Reg VS; + ARM64Reg arm_addr = gpr.R(inst.RA); + ARM64Reg scale_reg = W0; + ARM64Reg addr_reg = W1; + ARM64Reg type_reg = W2; + ARM64Reg VS; - if (inst.RA || update) // Always uses the register on update - { - if (offset >= 0) - ADD(addr_reg, arm_addr, offset); - else - SUB(addr_reg, arm_addr, std::abs(offset)); - } - else - { - MOVI2R(addr_reg, (u32)offset); - } + if (inst.RA || update) // Always uses the register on update + { + if (offset >= 0) + ADD(addr_reg, arm_addr, offset); + else + SUB(addr_reg, arm_addr, std::abs(offset)); + } + else + { + MOVI2R(addr_reg, (u32)offset); + } - if (update) - { - gpr.BindToRegister(inst.RA, REG_REG); - MOV(arm_addr, addr_reg); - } + if (update) + { + gpr.BindToRegister(inst.RA, REG_REG); + MOV(arm_addr, addr_reg); + } - if (js.assumeNoPairedQuantize) - { - VS = fpr.RW(inst.RS, REG_REG_SINGLE); - if (!inst.W) - { - ADD(EncodeRegTo64(addr_reg), EncodeRegTo64(addr_reg), MEM_REG); - m_float_emit.LD1(32, 1, EncodeRegToDouble(VS), EncodeRegTo64(addr_reg)); - } - else - { - m_float_emit.LDR(32, VS, EncodeRegTo64(addr_reg), MEM_REG); - } - m_float_emit.REV32(8, EncodeRegToDouble(VS), EncodeRegToDouble(VS)); - } - else - { - LDR(INDEX_UNSIGNED, scale_reg, PPC_REG, PPCSTATE_OFF(spr[SPR_GQR0 + inst.I])); - UBFM(type_reg, scale_reg, 16, 18); // Type - UBFM(scale_reg, scale_reg, 24, 29); // Scale + if (js.assumeNoPairedQuantize) + { + VS = fpr.RW(inst.RS, REG_REG_SINGLE); + if (!inst.W) + { + ADD(EncodeRegTo64(addr_reg), EncodeRegTo64(addr_reg), MEM_REG); + m_float_emit.LD1(32, 1, EncodeRegToDouble(VS), EncodeRegTo64(addr_reg)); + } + else + { + m_float_emit.LDR(32, VS, EncodeRegTo64(addr_reg), MEM_REG); + } + m_float_emit.REV32(8, EncodeRegToDouble(VS), EncodeRegToDouble(VS)); + } + else + { + LDR(INDEX_UNSIGNED, scale_reg, PPC_REG, PPCSTATE_OFF(spr[SPR_GQR0 + inst.I])); + UBFM(type_reg, scale_reg, 16, 18); // Type + UBFM(scale_reg, scale_reg, 24, 29); // Scale - MOVI2R(X30, (u64)&pairedLoadQuantized[inst.W * 8]); - LDR(X30, X30, ArithOption(EncodeRegTo64(type_reg), true)); - BLR(X30); + MOVI2R(X30, (u64)&pairedLoadQuantized[inst.W * 8]); + LDR(X30, X30, ArithOption(EncodeRegTo64(type_reg), true)); + BLR(X30); - VS = fpr.RW(inst.RS, REG_REG_SINGLE); - m_float_emit.ORR(EncodeRegToDouble(VS), D0, D0); - } + VS = fpr.RW(inst.RS, REG_REG_SINGLE); + m_float_emit.ORR(EncodeRegToDouble(VS), D0, D0); + } - if (inst.W) - { - m_float_emit.FMOV(S0, 0x70); // 1.0 as a Single - m_float_emit.INS(32, VS, 1, Q0, 0); - } + if (inst.W) + { + m_float_emit.FMOV(S0, 0x70); // 1.0 as a Single + m_float_emit.INS(32, VS, 1, Q0, 0); + } - gpr.Unlock(W0, W1, W2, W30); - fpr.Unlock(Q0, Q1); + gpr.Unlock(W0, W1, W2, W30); + fpr.Unlock(Q0, Q1); } void JitArm64::psq_st(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStorePairedOff); - FALLBACK_IF(jo.memcheck || !jo.fastmem); + INSTRUCTION_START + JITDISABLE(bJITLoadStorePairedOff); + FALLBACK_IF(jo.memcheck || !jo.fastmem); - // X30 is LR - // X0 contains the scale - // X1 is the address - // Q0 is the store register + // X30 is LR + // X0 contains the scale + // X1 is the address + // Q0 is the store register - bool update = inst.OPCD == 61; - s32 offset = inst.SIMM_12; + bool update = inst.OPCD == 61; + s32 offset = inst.SIMM_12; - gpr.Lock(W0, W1, W2, W30); - fpr.Lock(Q0, Q1); + gpr.Lock(W0, W1, W2, W30); + fpr.Lock(Q0, Q1); - bool single = fpr.IsSingle(inst.RS); + bool single = fpr.IsSingle(inst.RS); - ARM64Reg arm_addr = gpr.R(inst.RA); - ARM64Reg VS = fpr.R(inst.RS, single ? REG_REG_SINGLE : REG_REG); + ARM64Reg arm_addr = gpr.R(inst.RA); + ARM64Reg VS = fpr.R(inst.RS, single ? REG_REG_SINGLE : REG_REG); - ARM64Reg scale_reg = W0; - ARM64Reg addr_reg = W1; - ARM64Reg type_reg = W2; + ARM64Reg scale_reg = W0; + ARM64Reg addr_reg = W1; + ARM64Reg type_reg = W2; - BitSet32 gprs_in_use = gpr.GetCallerSavedUsed(); - BitSet32 fprs_in_use = fpr.GetCallerSavedUsed(); + BitSet32 gprs_in_use = gpr.GetCallerSavedUsed(); + BitSet32 fprs_in_use = fpr.GetCallerSavedUsed(); - // Wipe the registers we are using as temporaries - gprs_in_use &= BitSet32(~7); - fprs_in_use &= BitSet32(~3); + // Wipe the registers we are using as temporaries + gprs_in_use &= BitSet32(~7); + fprs_in_use &= BitSet32(~3); - if (inst.RA || update) // Always uses the register on update - { - if (offset >= 0) - ADD(addr_reg, gpr.R(inst.RA), offset); - else - SUB(addr_reg, gpr.R(inst.RA), std::abs(offset)); - } - else - { - MOVI2R(addr_reg, (u32)offset); - } + if (inst.RA || update) // Always uses the register on update + { + if (offset >= 0) + ADD(addr_reg, gpr.R(inst.RA), offset); + else + SUB(addr_reg, gpr.R(inst.RA), std::abs(offset)); + } + else + { + MOVI2R(addr_reg, (u32)offset); + } - if (update) - { - gpr.BindToRegister(inst.RA, REG_REG); - MOV(arm_addr, addr_reg); - } + if (update) + { + gpr.BindToRegister(inst.RA, REG_REG); + MOV(arm_addr, addr_reg); + } - if (js.assumeNoPairedQuantize) - { - u32 flags = BackPatchInfo::FLAG_STORE; + if (js.assumeNoPairedQuantize) + { + u32 flags = BackPatchInfo::FLAG_STORE; - if (single) - flags |= (inst.W ? BackPatchInfo::FLAG_SIZE_F32I : BackPatchInfo::FLAG_SIZE_F32X2I); - else - flags |= (inst.W ? BackPatchInfo::FLAG_SIZE_F32 : BackPatchInfo::FLAG_SIZE_F32X2); + if (single) + flags |= (inst.W ? BackPatchInfo::FLAG_SIZE_F32I : BackPatchInfo::FLAG_SIZE_F32X2I); + else + flags |= (inst.W ? BackPatchInfo::FLAG_SIZE_F32 : BackPatchInfo::FLAG_SIZE_F32X2); - EmitBackpatchRoutine(flags, - jo.fastmem, - jo.fastmem, - VS, EncodeRegTo64(addr_reg), - gprs_in_use, - fprs_in_use); - } - else - { - if (single) - { - m_float_emit.ORR(D0, VS, VS); - } - else - { - if (inst.W) - m_float_emit.FCVT(32, 64, D0, VS); - else - m_float_emit.FCVTN(32, D0, VS); - } + EmitBackpatchRoutine(flags, jo.fastmem, jo.fastmem, VS, EncodeRegTo64(addr_reg), gprs_in_use, + fprs_in_use); + } + else + { + if (single) + { + m_float_emit.ORR(D0, VS, VS); + } + else + { + if (inst.W) + m_float_emit.FCVT(32, 64, D0, VS); + else + m_float_emit.FCVTN(32, D0, VS); + } - LDR(INDEX_UNSIGNED, scale_reg, PPC_REG, PPCSTATE_OFF(spr[SPR_GQR0 + inst.I])); - UBFM(type_reg, scale_reg, 0, 2); // Type - UBFM(scale_reg, scale_reg, 8, 13); // Scale + LDR(INDEX_UNSIGNED, scale_reg, PPC_REG, PPCSTATE_OFF(spr[SPR_GQR0 + inst.I])); + UBFM(type_reg, scale_reg, 0, 2); // Type + UBFM(scale_reg, scale_reg, 8, 13); // Scale - // Inline address check - TST(addr_reg, 6, 1); - FixupBranch pass = B(CC_EQ); - FixupBranch fail = B(); + // Inline address check + TST(addr_reg, 6, 1); + FixupBranch pass = B(CC_EQ); + FixupBranch fail = B(); - SwitchToFarCode(); - SetJumpTarget(fail); - // Slow - MOVI2R(X30, (u64)&pairedStoreQuantized[16 + inst.W * 8]); - LDR(EncodeRegTo64(type_reg), X30, ArithOption(EncodeRegTo64(type_reg), true)); + SwitchToFarCode(); + SetJumpTarget(fail); + // Slow + MOVI2R(X30, (u64)&pairedStoreQuantized[16 + inst.W * 8]); + LDR(EncodeRegTo64(type_reg), X30, ArithOption(EncodeRegTo64(type_reg), true)); - ABI_PushRegisters(gprs_in_use); - m_float_emit.ABI_PushRegisters(fprs_in_use, X30); - BLR(EncodeRegTo64(type_reg)); - m_float_emit.ABI_PopRegisters(fprs_in_use, X30); - ABI_PopRegisters(gprs_in_use); - FixupBranch continue1 = B(); - SwitchToNearCode(); - SetJumpTarget(pass); + ABI_PushRegisters(gprs_in_use); + m_float_emit.ABI_PushRegisters(fprs_in_use, X30); + BLR(EncodeRegTo64(type_reg)); + m_float_emit.ABI_PopRegisters(fprs_in_use, X30); + ABI_PopRegisters(gprs_in_use); + FixupBranch continue1 = B(); + SwitchToNearCode(); + SetJumpTarget(pass); - // Fast - MOVI2R(X30, (u64)&pairedStoreQuantized[inst.W * 8]); - LDR(EncodeRegTo64(type_reg), X30, ArithOption(EncodeRegTo64(type_reg), true)); - BLR(EncodeRegTo64(type_reg)); + // Fast + MOVI2R(X30, (u64)&pairedStoreQuantized[inst.W * 8]); + LDR(EncodeRegTo64(type_reg), X30, ArithOption(EncodeRegTo64(type_reg), true)); + BLR(EncodeRegTo64(type_reg)); - SetJumpTarget(continue1); - } + SetJumpTarget(continue1); + } - gpr.Unlock(W0, W1, W2, W30); - fpr.Unlock(Q0, Q1); + gpr.Unlock(W0, W1, W2, W30); + fpr.Unlock(Q0, Q1); } - diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Paired.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Paired.cpp index 7241147b90..0beb25fb93 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Paired.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Paired.cpp @@ -9,245 +9,245 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCTables.h" #include "Core/PowerPC/JitArm64/Jit.h" #include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" +#include "Core/PowerPC/PPCTables.h" +#include "Core/PowerPC/PowerPC.h" using namespace Arm64Gen; void JitArm64::ps_mergeXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITPairedOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); - u32 a = inst.FA, b = inst.FB, d = inst.FD; + u32 a = inst.FA, b = inst.FB, d = inst.FD; - bool singles = fpr.IsSingle(a) && fpr.IsSingle(b); - RegType type = singles ? REG_REG_SINGLE : REG_REG; - u8 size = singles ? 32 : 64; - ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad; + bool singles = fpr.IsSingle(a) && fpr.IsSingle(b); + RegType type = singles ? REG_REG_SINGLE : REG_REG; + u8 size = singles ? 32 : 64; + ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad; - ARM64Reg VA = fpr.R(a, type); - ARM64Reg VB = fpr.R(b, type); - ARM64Reg VD = fpr.RW(d, type); + ARM64Reg VA = fpr.R(a, type); + ARM64Reg VB = fpr.R(b, type); + ARM64Reg VD = fpr.RW(d, type); - switch (inst.SUBOP10) - { - case 528: //00 - m_float_emit.TRN1(size, VD, VA, VB); - break; - case 560: //01 - m_float_emit.INS(size, VD, 0, VA, 0); - m_float_emit.INS(size, VD, 1, VB, 1); - break; - case 592: //10 - if (d != a && d != b) - { - m_float_emit.INS(size, VD, 0, VA, 1); - m_float_emit.INS(size, VD, 1, VB, 0); - } - else - { - ARM64Reg V0 = fpr.GetReg(); - m_float_emit.INS(size, V0, 0, VA, 1); - m_float_emit.INS(size, V0, 1, VB, 0); - m_float_emit.ORR(reg_encoder(VD), reg_encoder(V0), reg_encoder(V0)); - fpr.Unlock(V0); - } - break; - case 624: //11 - m_float_emit.TRN2(size, VD, VA, VB); - break; - default: - _assert_msg_(DYNA_REC, 0, "ps_merge - invalid op"); - break; - } + switch (inst.SUBOP10) + { + case 528: // 00 + m_float_emit.TRN1(size, VD, VA, VB); + break; + case 560: // 01 + m_float_emit.INS(size, VD, 0, VA, 0); + m_float_emit.INS(size, VD, 1, VB, 1); + break; + case 592: // 10 + if (d != a && d != b) + { + m_float_emit.INS(size, VD, 0, VA, 1); + m_float_emit.INS(size, VD, 1, VB, 0); + } + else + { + ARM64Reg V0 = fpr.GetReg(); + m_float_emit.INS(size, V0, 0, VA, 1); + m_float_emit.INS(size, V0, 1, VB, 0); + m_float_emit.ORR(reg_encoder(VD), reg_encoder(V0), reg_encoder(V0)); + fpr.Unlock(V0); + } + break; + case 624: // 11 + m_float_emit.TRN2(size, VD, VA, VB); + break; + default: + _assert_msg_(DYNA_REC, 0, "ps_merge - invalid op"); + break; + } } void JitArm64::ps_mulsX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITPairedOff); - FALLBACK_IF(inst.Rc); - FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF); + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF); - u32 a = inst.FA, c = inst.FC, d = inst.FD; + u32 a = inst.FA, c = inst.FC, d = inst.FD; - bool upper = inst.SUBOP5 == 13; + bool upper = inst.SUBOP5 == 13; - bool singles = fpr.IsSingle(a) && fpr.IsSingle(c); - RegType type = singles ? REG_REG_SINGLE : REG_REG; - u8 size = singles ? 32 : 64; - ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad; + bool singles = fpr.IsSingle(a) && fpr.IsSingle(c); + RegType type = singles ? REG_REG_SINGLE : REG_REG; + u8 size = singles ? 32 : 64; + ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad; - ARM64Reg VA = fpr.R(a, type); - ARM64Reg VC = fpr.R(c, type); - ARM64Reg VD = fpr.RW(d, type); - ARM64Reg V0 = fpr.GetReg(); + ARM64Reg VA = fpr.R(a, type); + ARM64Reg VC = fpr.R(c, type); + ARM64Reg VD = fpr.RW(d, type); + ARM64Reg V0 = fpr.GetReg(); - m_float_emit.DUP(size, reg_encoder(V0), reg_encoder(VC), upper ? 1 : 0); - m_float_emit.FMUL(size, reg_encoder(VD), reg_encoder(VA), reg_encoder(V0)); + m_float_emit.DUP(size, reg_encoder(V0), reg_encoder(VC), upper ? 1 : 0); + m_float_emit.FMUL(size, reg_encoder(VD), reg_encoder(VA), reg_encoder(V0)); - fpr.FixSinglePrecision(d); - fpr.Unlock(V0); + fpr.FixSinglePrecision(d); + fpr.Unlock(V0); } void JitArm64::ps_maddXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITPairedOff); - FALLBACK_IF(inst.Rc); - FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF); + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF); - u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; - u32 op5 = inst.SUBOP5; + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + u32 op5 = inst.SUBOP5; - bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c); - RegType type = singles ? REG_REG_SINGLE : REG_REG; - u8 size = singles ? 32 : 64; - ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad; + bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c); + RegType type = singles ? REG_REG_SINGLE : REG_REG; + u8 size = singles ? 32 : 64; + ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad; - ARM64Reg VA = reg_encoder(fpr.R(a, type)); - ARM64Reg VB = reg_encoder(fpr.R(b, type)); - ARM64Reg VC = reg_encoder(fpr.R(c, type)); - ARM64Reg VD = reg_encoder(fpr.RW(d, type)); - ARM64Reg V0Q = fpr.GetReg(); - ARM64Reg V0 = reg_encoder(V0Q); + ARM64Reg VA = reg_encoder(fpr.R(a, type)); + ARM64Reg VB = reg_encoder(fpr.R(b, type)); + ARM64Reg VC = reg_encoder(fpr.R(c, type)); + ARM64Reg VD = reg_encoder(fpr.RW(d, type)); + ARM64Reg V0Q = fpr.GetReg(); + ARM64Reg V0 = reg_encoder(V0Q); - // TODO: Do FMUL and FADD/FSUB in *one* host call to save accuracy. + // TODO: Do FMUL and FADD/FSUB in *one* host call to save accuracy. - switch (op5) - { - case 14: // ps_madds0 - m_float_emit.DUP(size, V0, VC, 0); - m_float_emit.FMUL(size, V0, V0, VA); - m_float_emit.FADD(size, VD, V0, VB); - break; - case 15: // ps_madds1 - m_float_emit.DUP(size, V0, VC, 1); - m_float_emit.FMUL(size, V0, V0, VA); - m_float_emit.FADD(size, VD, V0, VB); - break; - case 28: // ps_msub - m_float_emit.FMUL(size, V0, VA, VC); - m_float_emit.FSUB(size, VD, V0, VB); - break; - case 29: // ps_madd - m_float_emit.FMUL(size, V0, VA, VC); - m_float_emit.FADD(size, VD, V0, VB); - break; - case 30: // ps_nmsub - m_float_emit.FMUL(size, V0, VA, VC); - m_float_emit.FSUB(size, VD, V0, VB); - m_float_emit.FNEG(size, VD, VD); - break; - case 31: // ps_nmadd - m_float_emit.FMUL(size, V0, VA, VC); - m_float_emit.FADD(size, VD, V0, VB); - m_float_emit.FNEG(size, VD, VD); - break; - default: - _assert_msg_(DYNA_REC, 0, "ps_madd - invalid op"); - break; - } - fpr.FixSinglePrecision(d); + switch (op5) + { + case 14: // ps_madds0 + m_float_emit.DUP(size, V0, VC, 0); + m_float_emit.FMUL(size, V0, V0, VA); + m_float_emit.FADD(size, VD, V0, VB); + break; + case 15: // ps_madds1 + m_float_emit.DUP(size, V0, VC, 1); + m_float_emit.FMUL(size, V0, V0, VA); + m_float_emit.FADD(size, VD, V0, VB); + break; + case 28: // ps_msub + m_float_emit.FMUL(size, V0, VA, VC); + m_float_emit.FSUB(size, VD, V0, VB); + break; + case 29: // ps_madd + m_float_emit.FMUL(size, V0, VA, VC); + m_float_emit.FADD(size, VD, V0, VB); + break; + case 30: // ps_nmsub + m_float_emit.FMUL(size, V0, VA, VC); + m_float_emit.FSUB(size, VD, V0, VB); + m_float_emit.FNEG(size, VD, VD); + break; + case 31: // ps_nmadd + m_float_emit.FMUL(size, V0, VA, VC); + m_float_emit.FADD(size, VD, V0, VB); + m_float_emit.FNEG(size, VD, VD); + break; + default: + _assert_msg_(DYNA_REC, 0, "ps_madd - invalid op"); + break; + } + fpr.FixSinglePrecision(d); - fpr.Unlock(V0Q); + fpr.Unlock(V0Q); } void JitArm64::ps_res(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITPairedOff); - FALLBACK_IF(inst.Rc); - FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF); + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF); - u32 b = inst.FB, d = inst.FD; + u32 b = inst.FB, d = inst.FD; - bool singles = fpr.IsSingle(b); - RegType type = singles ? REG_REG_SINGLE : REG_REG; - u8 size = singles ? 32 : 64; - ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad; + bool singles = fpr.IsSingle(b); + RegType type = singles ? REG_REG_SINGLE : REG_REG; + u8 size = singles ? 32 : 64; + ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad; - ARM64Reg VB = fpr.R(b, type); - ARM64Reg VD = fpr.RW(d, type); + ARM64Reg VB = fpr.R(b, type); + ARM64Reg VD = fpr.RW(d, type); - m_float_emit.FRSQRTE(size, reg_encoder(VD), reg_encoder(VB)); + m_float_emit.FRSQRTE(size, reg_encoder(VD), reg_encoder(VB)); - fpr.FixSinglePrecision(d); + fpr.FixSinglePrecision(d); } void JitArm64::ps_sel(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITPairedOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); - u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; - bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c); - RegType type = singles ? REG_REG_SINGLE : REG_REG; - u8 size = singles ? 32 : 64; - ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad; + bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c); + RegType type = singles ? REG_REG_SINGLE : REG_REG; + u8 size = singles ? 32 : 64; + ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad; - ARM64Reg VA = reg_encoder(fpr.R(a, type)); - ARM64Reg VB = reg_encoder(fpr.R(b, type)); - ARM64Reg VC = reg_encoder(fpr.R(c, type)); - ARM64Reg VD = reg_encoder(fpr.RW(d, type)); + ARM64Reg VA = reg_encoder(fpr.R(a, type)); + ARM64Reg VB = reg_encoder(fpr.R(b, type)); + ARM64Reg VC = reg_encoder(fpr.R(c, type)); + ARM64Reg VD = reg_encoder(fpr.RW(d, type)); - if (d != b && d != c) - { - m_float_emit.FCMGE(size, VD, VA); - m_float_emit.BSL(VD, VC, VB); - } - else - { - ARM64Reg V0Q = fpr.GetReg(); - ARM64Reg V0 = reg_encoder(V0Q); - m_float_emit.FCMGE(size, V0, VA); - m_float_emit.BSL(V0, VC, VB); - m_float_emit.ORR(VD, V0, V0); - fpr.Unlock(V0Q); - } + if (d != b && d != c) + { + m_float_emit.FCMGE(size, VD, VA); + m_float_emit.BSL(VD, VC, VB); + } + else + { + ARM64Reg V0Q = fpr.GetReg(); + ARM64Reg V0 = reg_encoder(V0Q); + m_float_emit.FCMGE(size, V0, VA); + m_float_emit.BSL(V0, VC, VB); + m_float_emit.ORR(VD, V0, V0); + fpr.Unlock(V0Q); + } } void JitArm64::ps_sumX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITPairedOff); - FALLBACK_IF(inst.Rc); - FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF); + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); + FALLBACK_IF(SConfig::GetInstance().bFPRF && js.op->wantsFPRF); - u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; - bool upper = inst.SUBOP5 == 11; + bool upper = inst.SUBOP5 == 11; - bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c); - RegType type = singles ? REG_REG_SINGLE : REG_REG; - u8 size = singles ? 32 : 64; - ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad; + bool singles = fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c); + RegType type = singles ? REG_REG_SINGLE : REG_REG; + u8 size = singles ? 32 : 64; + ARM64Reg (*reg_encoder)(ARM64Reg) = singles ? EncodeRegToDouble : EncodeRegToQuad; - ARM64Reg VA = fpr.R(a, type); - ARM64Reg VB = fpr.R(b, type); - ARM64Reg VC = fpr.R(c, type); - ARM64Reg VD = fpr.RW(d, type); - ARM64Reg V0 = fpr.GetReg(); + ARM64Reg VA = fpr.R(a, type); + ARM64Reg VB = fpr.R(b, type); + ARM64Reg VC = fpr.R(c, type); + ARM64Reg VD = fpr.RW(d, type); + ARM64Reg V0 = fpr.GetReg(); - m_float_emit.DUP(size, reg_encoder(V0), reg_encoder(upper ? VA : VB), upper ? 0 : 1); - if (d != c) - { - m_float_emit.FADD(size, reg_encoder(VD), reg_encoder(V0), reg_encoder(upper ? VB : VA)); - m_float_emit.INS(size, VD, upper ? 0 : 1, VC, upper ? 0 : 1); - } - else - { - m_float_emit.FADD(size, reg_encoder(V0), reg_encoder(V0), reg_encoder(upper ? VB : VA)); - m_float_emit.INS(size, VD, upper ? 1 : 0, V0, upper ? 1 : 0); - } + m_float_emit.DUP(size, reg_encoder(V0), reg_encoder(upper ? VA : VB), upper ? 0 : 1); + if (d != c) + { + m_float_emit.FADD(size, reg_encoder(VD), reg_encoder(V0), reg_encoder(upper ? VB : VA)); + m_float_emit.INS(size, VD, upper ? 0 : 1, VC, upper ? 0 : 1); + } + else + { + m_float_emit.FADD(size, reg_encoder(V0), reg_encoder(V0), reg_encoder(upper ? VB : VA)); + m_float_emit.INS(size, VD, upper ? 1 : 0, V0, upper ? 1 : 0); + } - fpr.FixSinglePrecision(d); + fpr.FixSinglePrecision(d); - fpr.Unlock(V0); + fpr.Unlock(V0); } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp index 09cb1efc5d..d55cd1bc93 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp @@ -2,610 +2,606 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/JitArm64/Jit.h" #include "Common/Assert.h" #include "Common/BitSet.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" -#include "Core/PowerPC/JitArm64/Jit.h" #include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" using namespace Arm64Gen; -void Arm64RegCache::Init(ARM64XEmitter *emitter) +void Arm64RegCache::Init(ARM64XEmitter* emitter) { - m_emit = emitter; - m_float_emit.reset(new ARM64FloatEmitter(m_emit)); - GetAllocationOrder(); + m_emit = emitter; + m_float_emit.reset(new ARM64FloatEmitter(m_emit)); + GetAllocationOrder(); } ARM64Reg Arm64RegCache::GetReg() { - // If we have no registers left, dump the most stale register first - if (!GetUnlockedRegisterCount()) - FlushMostStaleRegister(); + // If we have no registers left, dump the most stale register first + if (!GetUnlockedRegisterCount()) + FlushMostStaleRegister(); - for (auto& it : m_host_registers) - { - if (!it.IsLocked()) - { - it.Lock(); - return it.GetReg(); - } - } - // Holy cow, how did you run out of registers? - // We can't return anything reasonable in this case. Return INVALID_REG and watch the failure happen - WARN_LOG(DYNA_REC, "All available registers are locked dumb dumb"); - return INVALID_REG; + for (auto& it : m_host_registers) + { + if (!it.IsLocked()) + { + it.Lock(); + return it.GetReg(); + } + } + // Holy cow, how did you run out of registers? + // We can't return anything reasonable in this case. Return INVALID_REG and watch the failure + // happen + WARN_LOG(DYNA_REC, "All available registers are locked dumb dumb"); + return INVALID_REG; } u32 Arm64RegCache::GetUnlockedRegisterCount() { - u32 unlocked_registers = 0; - for (auto& it : m_host_registers) - if (!it.IsLocked()) - ++unlocked_registers; - return unlocked_registers; + u32 unlocked_registers = 0; + for (auto& it : m_host_registers) + if (!it.IsLocked()) + ++unlocked_registers; + return unlocked_registers; } void Arm64RegCache::LockRegister(ARM64Reg host_reg) { - auto reg = std::find(m_host_registers.begin(), m_host_registers.end(), host_reg); - _assert_msg_(DYNA_REC, reg != m_host_registers.end(), "Don't try locking a register that isn't in the cache. Reg %d", host_reg); - reg->Lock(); + auto reg = std::find(m_host_registers.begin(), m_host_registers.end(), host_reg); + _assert_msg_(DYNA_REC, reg != m_host_registers.end(), + "Don't try locking a register that isn't in the cache. Reg %d", host_reg); + reg->Lock(); } void Arm64RegCache::UnlockRegister(ARM64Reg host_reg) { - auto reg = std::find(m_host_registers.begin(), m_host_registers.end(), host_reg); - _assert_msg_(DYNA_REC, reg != m_host_registers.end(), "Don't try unlocking a register that isn't in the cache. Reg %d", host_reg); - reg->Unlock(); + auto reg = std::find(m_host_registers.begin(), m_host_registers.end(), host_reg); + _assert_msg_(DYNA_REC, reg != m_host_registers.end(), + "Don't try unlocking a register that isn't in the cache. Reg %d", host_reg); + reg->Unlock(); } void Arm64RegCache::FlushMostStaleRegister() { - u32 most_stale_preg = 0; - u32 most_stale_amount = 0; - for (u32 i = 0; i < 32; ++i) - { - u32 last_used = m_guest_registers[i].GetLastUsed(); - if (last_used > most_stale_amount && - (m_guest_registers[i].GetType() != REG_NOTLOADED && - m_guest_registers[i].GetType() != REG_IMM)) - { - most_stale_preg = i; - most_stale_amount = last_used; - } - } - FlushRegister(most_stale_preg, false); + u32 most_stale_preg = 0; + u32 most_stale_amount = 0; + for (u32 i = 0; i < 32; ++i) + { + u32 last_used = m_guest_registers[i].GetLastUsed(); + if (last_used > most_stale_amount && (m_guest_registers[i].GetType() != REG_NOTLOADED && + m_guest_registers[i].GetType() != REG_IMM)) + { + most_stale_preg = i; + most_stale_amount = last_used; + } + } + FlushRegister(most_stale_preg, false); } // GPR Cache -void Arm64GPRCache::Start(PPCAnalyst::BlockRegStats &stats) +void Arm64GPRCache::Start(PPCAnalyst::BlockRegStats& stats) { } bool Arm64GPRCache::IsCalleeSaved(ARM64Reg reg) { - static std::vector callee_regs = - { - X28, X27, X26, X25, X24, X23, X22, X21, X20, - X19, INVALID_REG, - }; - return std::find(callee_regs.begin(), callee_regs.end(), EncodeRegTo64(reg)) != callee_regs.end(); + static std::vector callee_regs = { + X28, X27, X26, X25, X24, X23, X22, X21, X20, X19, INVALID_REG, + }; + return std::find(callee_regs.begin(), callee_regs.end(), EncodeRegTo64(reg)) != callee_regs.end(); } void Arm64GPRCache::FlushRegister(u32 preg, bool maintain_state) { - OpArg& reg = m_guest_registers[preg]; - if (reg.GetType() == REG_REG) - { - ARM64Reg host_reg = reg.GetReg(); - if (reg.IsDirty()) - m_emit->STR(INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(gpr[preg])); + OpArg& reg = m_guest_registers[preg]; + if (reg.GetType() == REG_REG) + { + ARM64Reg host_reg = reg.GetReg(); + if (reg.IsDirty()) + m_emit->STR(INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(gpr[preg])); - if (!maintain_state) - { - UnlockRegister(host_reg); - reg.Flush(); - } - } - else if (reg.GetType() == REG_IMM) - { - if (!reg.GetImm()) - { - m_emit->STR(INDEX_UNSIGNED, WSP, PPC_REG, PPCSTATE_OFF(gpr[preg])); - } - else - { - ARM64Reg host_reg = GetReg(); + if (!maintain_state) + { + UnlockRegister(host_reg); + reg.Flush(); + } + } + else if (reg.GetType() == REG_IMM) + { + if (!reg.GetImm()) + { + m_emit->STR(INDEX_UNSIGNED, WSP, PPC_REG, PPCSTATE_OFF(gpr[preg])); + } + else + { + ARM64Reg host_reg = GetReg(); - m_emit->MOVI2R(host_reg, reg.GetImm()); - m_emit->STR(INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(gpr[preg])); + m_emit->MOVI2R(host_reg, reg.GetImm()); + m_emit->STR(INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(gpr[preg])); - UnlockRegister(host_reg); - } + UnlockRegister(host_reg); + } - if (!maintain_state) - reg.Flush(); - } + if (!maintain_state) + reg.Flush(); + } } void Arm64GPRCache::FlushRegisters(BitSet32 regs, bool maintain_state) { - for (int i = 0; i < 32; ++i) - { - if (regs[i]) - { - if (i < 31 && regs[i + 1]) - { - // We've got two guest registers in a row to store - OpArg& reg1 = m_guest_registers[i]; - OpArg& reg2 = m_guest_registers[i + 1]; - if (reg1.IsDirty() && reg2.IsDirty() && - reg1.GetType() == REG_REG && reg2.GetType() == REG_REG) - { - ARM64Reg RX1 = R(i); - ARM64Reg RX2 = R(i + 1); + for (int i = 0; i < 32; ++i) + { + if (regs[i]) + { + if (i < 31 && regs[i + 1]) + { + // We've got two guest registers in a row to store + OpArg& reg1 = m_guest_registers[i]; + OpArg& reg2 = m_guest_registers[i + 1]; + if (reg1.IsDirty() && reg2.IsDirty() && reg1.GetType() == REG_REG && + reg2.GetType() == REG_REG) + { + ARM64Reg RX1 = R(i); + ARM64Reg RX2 = R(i + 1); - m_emit->STP(INDEX_SIGNED, RX1, RX2, PPC_REG, PPCSTATE_OFF(gpr[0]) + i * sizeof(u32)); - if (!maintain_state) - { - UnlockRegister(RX1); - UnlockRegister(RX2); - reg1.Flush(); - reg2.Flush(); - } - ++i; - continue; - } - } + m_emit->STP(INDEX_SIGNED, RX1, RX2, PPC_REG, PPCSTATE_OFF(gpr[0]) + i * sizeof(u32)); + if (!maintain_state) + { + UnlockRegister(RX1); + UnlockRegister(RX2); + reg1.Flush(); + reg2.Flush(); + } + ++i; + continue; + } + } - FlushRegister(i, maintain_state); - } - } + FlushRegister(i, maintain_state); + } + } } void Arm64GPRCache::Flush(FlushMode mode, PPCAnalyst::CodeOp* op) { - BitSet32 to_flush; - for (int i = 0; i < 32; ++i) - { - bool flush = true; - if (m_guest_registers[i].GetType() == REG_REG) - { - // Has to be flushed if it isn't in a callee saved register - ARM64Reg host_reg = m_guest_registers[i].GetReg(); - flush = IsCalleeSaved(host_reg) ? flush : true; - } + BitSet32 to_flush; + for (int i = 0; i < 32; ++i) + { + bool flush = true; + if (m_guest_registers[i].GetType() == REG_REG) + { + // Has to be flushed if it isn't in a callee saved register + ARM64Reg host_reg = m_guest_registers[i].GetReg(); + flush = IsCalleeSaved(host_reg) ? flush : true; + } - to_flush[i] = flush; - } - FlushRegisters(to_flush, mode == FLUSH_MAINTAIN_STATE); + to_flush[i] = flush; + } + FlushRegisters(to_flush, mode == FLUSH_MAINTAIN_STATE); } ARM64Reg Arm64GPRCache::R(u32 preg) { - OpArg& reg = m_guest_registers[preg]; - IncrementAllUsed(); - reg.ResetLastUsed(); + OpArg& reg = m_guest_registers[preg]; + IncrementAllUsed(); + reg.ResetLastUsed(); - switch (reg.GetType()) - { - case REG_REG: // already in a reg - return reg.GetReg(); - break; - case REG_IMM: // Is an immediate - { - ARM64Reg host_reg = GetReg(); - m_emit->MOVI2R(host_reg, reg.GetImm()); - reg.Load(host_reg); - reg.SetDirty(true); - return host_reg; - } - break; - case REG_NOTLOADED: // Register isn't loaded at /all/ - { - // This is a bit annoying. We try to keep these preloaded as much as possible - // This can also happen on cases where PPCAnalyst isn't feeing us proper register usage statistics - ARM64Reg host_reg = GetReg(); - reg.Load(host_reg); - reg.SetDirty(false); - m_emit->LDR(INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(gpr[preg])); - return host_reg; - } - break; - default: - ERROR_LOG(DYNA_REC, "Invalid OpArg Type!"); - break; - } - // We've got an issue if we end up here - return INVALID_REG; + switch (reg.GetType()) + { + case REG_REG: // already in a reg + return reg.GetReg(); + break; + case REG_IMM: // Is an immediate + { + ARM64Reg host_reg = GetReg(); + m_emit->MOVI2R(host_reg, reg.GetImm()); + reg.Load(host_reg); + reg.SetDirty(true); + return host_reg; + } + break; + case REG_NOTLOADED: // Register isn't loaded at /all/ + { + // This is a bit annoying. We try to keep these preloaded as much as possible + // This can also happen on cases where PPCAnalyst isn't feeing us proper register usage + // statistics + ARM64Reg host_reg = GetReg(); + reg.Load(host_reg); + reg.SetDirty(false); + m_emit->LDR(INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(gpr[preg])); + return host_reg; + } + break; + default: + ERROR_LOG(DYNA_REC, "Invalid OpArg Type!"); + break; + } + // We've got an issue if we end up here + return INVALID_REG; } void Arm64GPRCache::SetImmediate(u32 preg, u32 imm) { - OpArg& reg = m_guest_registers[preg]; - if (reg.GetType() == REG_REG) - UnlockRegister(reg.GetReg()); - reg.LoadToImm(imm); + OpArg& reg = m_guest_registers[preg]; + if (reg.GetType() == REG_REG) + UnlockRegister(reg.GetReg()); + reg.LoadToImm(imm); } void Arm64GPRCache::BindToRegister(u32 preg, bool do_load) { - OpArg& reg = m_guest_registers[preg]; + OpArg& reg = m_guest_registers[preg]; - reg.ResetLastUsed(); + reg.ResetLastUsed(); - reg.SetDirty(true); - if (reg.GetType() == REG_NOTLOADED) - { - ARM64Reg host_reg = GetReg(); - reg.Load(host_reg); - if (do_load) - m_emit->LDR(INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(gpr[preg])); - } + reg.SetDirty(true); + if (reg.GetType() == REG_NOTLOADED) + { + ARM64Reg host_reg = GetReg(); + reg.Load(host_reg); + if (do_load) + m_emit->LDR(INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(gpr[preg])); + } } void Arm64GPRCache::GetAllocationOrder() { - // Callee saved registers first in hopes that we will keep everything stored there first - const std::vector allocation_order = - { - // Callee saved - W27, W26, W25, W24, W23, W22, W21, W20, - W19, + // Callee saved registers first in hopes that we will keep everything stored there first + const std::vector allocation_order = { + // Callee saved + W27, W26, W25, W24, W23, W22, W21, W20, W19, - // Caller saved - W18, W17, W16, W15, W14, W13, W12, W11, W10, - W9, W8, W7, W6, W5, W4, W3, W2, W1, W0, - W30, - }; + // Caller saved + W18, W17, W16, W15, W14, W13, W12, W11, W10, W9, W8, W7, W6, W5, W4, W3, W2, W1, W0, W30, + }; - for (ARM64Reg reg : allocation_order) - m_host_registers.push_back(HostReg(reg)); + for (ARM64Reg reg : allocation_order) + m_host_registers.push_back(HostReg(reg)); } BitSet32 Arm64GPRCache::GetCallerSavedUsed() { - BitSet32 registers(0); - for (auto& it : m_host_registers) - if (it.IsLocked() && !IsCalleeSaved(it.GetReg())) - registers[it.GetReg()] = 1; - return registers; + BitSet32 registers(0); + for (auto& it : m_host_registers) + if (it.IsLocked() && !IsCalleeSaved(it.GetReg())) + registers[it.GetReg()] = 1; + return registers; } void Arm64GPRCache::FlushByHost(ARM64Reg host_reg) { - for (int i = 0; i < 32; ++i) - { - OpArg& reg = m_guest_registers[i]; - if (reg.GetType() == REG_REG && reg.GetReg() == host_reg) - { - FlushRegister(i, false); - return; - } - } + for (int i = 0; i < 32; ++i) + { + OpArg& reg = m_guest_registers[i]; + if (reg.GetType() == REG_REG && reg.GetReg() == host_reg) + { + FlushRegister(i, false); + return; + } + } } // FPR Cache void Arm64FPRCache::Flush(FlushMode mode, PPCAnalyst::CodeOp* op) { - for (int i = 0; i < 32; ++i) - { - if (m_guest_registers[i].GetType() != REG_NOTLOADED && - m_guest_registers[i].GetType() != REG_IMM) - { - // XXX: Determine if we can keep a register in the lower 64bits - // Which will allow it to be callee saved. - FlushRegister(i, mode == FLUSH_MAINTAIN_STATE); - } - } + for (int i = 0; i < 32; ++i) + { + if (m_guest_registers[i].GetType() != REG_NOTLOADED && + m_guest_registers[i].GetType() != REG_IMM) + { + // XXX: Determine if we can keep a register in the lower 64bits + // Which will allow it to be callee saved. + FlushRegister(i, mode == FLUSH_MAINTAIN_STATE); + } + } } ARM64Reg Arm64FPRCache::R(u32 preg, RegType type) { - OpArg& reg = m_guest_registers[preg]; - IncrementAllUsed(); - reg.ResetLastUsed(); - ARM64Reg host_reg = reg.GetReg(); + OpArg& reg = m_guest_registers[preg]; + IncrementAllUsed(); + reg.ResetLastUsed(); + ARM64Reg host_reg = reg.GetReg(); - switch (reg.GetType()) - { - case REG_REG_SINGLE: - { - // We're asked for singles, so just return the register. - if (type == REG_REG_SINGLE || type == REG_LOWER_PAIR_SINGLE) - return host_reg; + switch (reg.GetType()) + { + case REG_REG_SINGLE: + { + // We're asked for singles, so just return the register. + if (type == REG_REG_SINGLE || type == REG_LOWER_PAIR_SINGLE) + return host_reg; - // Else convert this register back to doubles. - m_float_emit->FCVTL(64, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg)); - reg.Load(host_reg, REG_REG); + // Else convert this register back to doubles. + m_float_emit->FCVTL(64, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg)); + reg.Load(host_reg, REG_REG); - // fall through - } - case REG_REG: // already in a reg - { - return host_reg; - } - case REG_LOWER_PAIR_SINGLE: - { - // We're asked for the lower single, so just return the register. - if (type == REG_LOWER_PAIR_SINGLE) - return host_reg; + // fall through + } + case REG_REG: // already in a reg + { + return host_reg; + } + case REG_LOWER_PAIR_SINGLE: + { + // We're asked for the lower single, so just return the register. + if (type == REG_LOWER_PAIR_SINGLE) + return host_reg; - // Else convert this register back to a double. - m_float_emit->FCVT(64, 32, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg)); - reg.Load(host_reg, REG_LOWER_PAIR); + // Else convert this register back to a double. + m_float_emit->FCVT(64, 32, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg)); + reg.Load(host_reg, REG_LOWER_PAIR); - // fall through - } - case REG_LOWER_PAIR: - { - if (type == REG_REG) - { - // Load the high 64bits from the file and insert them in to the high 64bits of the host register - ARM64Reg tmp_reg = GetReg(); - m_float_emit->LDR(64, INDEX_UNSIGNED, tmp_reg, PPC_REG, PPCSTATE_OFF(ps[preg][1])); - m_float_emit->INS(64, host_reg, 1, tmp_reg, 0); - UnlockRegister(tmp_reg); + // fall through + } + case REG_LOWER_PAIR: + { + if (type == REG_REG) + { + // Load the high 64bits from the file and insert them in to the high 64bits of the host + // register + ARM64Reg tmp_reg = GetReg(); + m_float_emit->LDR(64, INDEX_UNSIGNED, tmp_reg, PPC_REG, PPCSTATE_OFF(ps[preg][1])); + m_float_emit->INS(64, host_reg, 1, tmp_reg, 0); + UnlockRegister(tmp_reg); - // Change it over to a full 128bit register - reg.Load(host_reg, REG_REG); - } - return host_reg; - } - case REG_DUP_SINGLE: - { - if (type == REG_LOWER_PAIR_SINGLE) - return host_reg; + // Change it over to a full 128bit register + reg.Load(host_reg, REG_REG); + } + return host_reg; + } + case REG_DUP_SINGLE: + { + if (type == REG_LOWER_PAIR_SINGLE) + return host_reg; - if (type == REG_REG_SINGLE) - { - // Duplicate to the top and change over - m_float_emit->INS(32, host_reg, 1, host_reg, 0); - reg.Load(host_reg, REG_REG_SINGLE); - return host_reg; - } + if (type == REG_REG_SINGLE) + { + // Duplicate to the top and change over + m_float_emit->INS(32, host_reg, 1, host_reg, 0); + reg.Load(host_reg, REG_REG_SINGLE); + return host_reg; + } - m_float_emit->FCVT(64, 32, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg)); - reg.Load(host_reg, REG_DUP); + m_float_emit->FCVT(64, 32, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg)); + reg.Load(host_reg, REG_DUP); - // fall through - } - case REG_DUP: - { - if (type == REG_REG) - { - // We are requesting a full 128bit register - // but we are only available in the lower 64bits - // Duplicate to the top and change over - m_float_emit->INS(64, host_reg, 1, host_reg, 0); - reg.Load(host_reg, REG_REG); - } - return host_reg; - } - case REG_NOTLOADED: // Register isn't loaded at /all/ - { - host_reg = GetReg(); - u32 load_size; - if (type == REG_REG) - { - load_size = 128; - reg.Load(host_reg, REG_REG); - } - else - { - load_size = 64; - reg.Load(host_reg, REG_LOWER_PAIR); - } - reg.SetDirty(false); - m_float_emit->LDR(load_size, INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(ps[preg][0])); - return host_reg; - } - default: - _dbg_assert_msg_(DYNA_REC, false, "Invalid OpArg Type!"); - break; - } - // We've got an issue if we end up here - return INVALID_REG; + // fall through + } + case REG_DUP: + { + if (type == REG_REG) + { + // We are requesting a full 128bit register + // but we are only available in the lower 64bits + // Duplicate to the top and change over + m_float_emit->INS(64, host_reg, 1, host_reg, 0); + reg.Load(host_reg, REG_REG); + } + return host_reg; + } + case REG_NOTLOADED: // Register isn't loaded at /all/ + { + host_reg = GetReg(); + u32 load_size; + if (type == REG_REG) + { + load_size = 128; + reg.Load(host_reg, REG_REG); + } + else + { + load_size = 64; + reg.Load(host_reg, REG_LOWER_PAIR); + } + reg.SetDirty(false); + m_float_emit->LDR(load_size, INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(ps[preg][0])); + return host_reg; + } + default: + _dbg_assert_msg_(DYNA_REC, false, "Invalid OpArg Type!"); + break; + } + // We've got an issue if we end up here + return INVALID_REG; } ARM64Reg Arm64FPRCache::RW(u32 preg, RegType type) { - OpArg& reg = m_guest_registers[preg]; + OpArg& reg = m_guest_registers[preg]; - bool was_dirty = reg.IsDirty(); + bool was_dirty = reg.IsDirty(); - IncrementAllUsed(); - reg.ResetLastUsed(); + IncrementAllUsed(); + reg.ResetLastUsed(); - reg.SetDirty(true); + reg.SetDirty(true); - // If not loaded at all, just alloc a new one. - if (reg.GetType() == REG_NOTLOADED) - { - reg.Load(GetReg(), type); - return reg.GetReg(); - } + // If not loaded at all, just alloc a new one. + if (reg.GetType() == REG_NOTLOADED) + { + reg.Load(GetReg(), type); + return reg.GetReg(); + } - // Only the lower value will be overwritten, so we must be extra careful to store PSR1 if dirty. - if ((type == REG_LOWER_PAIR || type == REG_LOWER_PAIR_SINGLE) && was_dirty) - { - // We must *not* change host_reg as this register might still be in use. So it's fine to - // store this register, but it's *not* fine to convert it to double. So for double convertion, - // a temporary register needs to be used. - ARM64Reg host_reg = reg.GetReg(); - ARM64Reg flush_reg = host_reg; + // Only the lower value will be overwritten, so we must be extra careful to store PSR1 if dirty. + if ((type == REG_LOWER_PAIR || type == REG_LOWER_PAIR_SINGLE) && was_dirty) + { + // We must *not* change host_reg as this register might still be in use. So it's fine to + // store this register, but it's *not* fine to convert it to double. So for double convertion, + // a temporary register needs to be used. + ARM64Reg host_reg = reg.GetReg(); + ARM64Reg flush_reg = host_reg; - switch (reg.GetType()) - { - case REG_REG_SINGLE: - flush_reg = GetReg(); - m_float_emit->FCVTL(64, EncodeRegToDouble(flush_reg), EncodeRegToDouble(host_reg)); - // fall through - case REG_REG: - // We are doing a full 128bit store because it takes 2 cycles on a Cortex-A57 to do a 128bit store. - // It would take longer to do an insert to a temporary and a 64bit store than to just do this. - m_float_emit->STR(128, INDEX_UNSIGNED, flush_reg, PPC_REG, PPCSTATE_OFF(ps[preg][0])); - break; - case REG_DUP_SINGLE: - flush_reg = GetReg(); - m_float_emit->FCVT(64, 32, EncodeRegToDouble(flush_reg), EncodeRegToDouble(host_reg)); - // fall through - case REG_DUP: - // Store PSR1 (which is equal to PSR0) in memory. - m_float_emit->STR(64, INDEX_UNSIGNED, flush_reg, PPC_REG, PPCSTATE_OFF(ps[preg][1])); - break; - default: - // All other types doesn't store anything in PSR1. - break; - } + switch (reg.GetType()) + { + case REG_REG_SINGLE: + flush_reg = GetReg(); + m_float_emit->FCVTL(64, EncodeRegToDouble(flush_reg), EncodeRegToDouble(host_reg)); + // fall through + case REG_REG: + // We are doing a full 128bit store because it takes 2 cycles on a Cortex-A57 to do a 128bit + // store. + // It would take longer to do an insert to a temporary and a 64bit store than to just do this. + m_float_emit->STR(128, INDEX_UNSIGNED, flush_reg, PPC_REG, PPCSTATE_OFF(ps[preg][0])); + break; + case REG_DUP_SINGLE: + flush_reg = GetReg(); + m_float_emit->FCVT(64, 32, EncodeRegToDouble(flush_reg), EncodeRegToDouble(host_reg)); + // fall through + case REG_DUP: + // Store PSR1 (which is equal to PSR0) in memory. + m_float_emit->STR(64, INDEX_UNSIGNED, flush_reg, PPC_REG, PPCSTATE_OFF(ps[preg][1])); + break; + default: + // All other types doesn't store anything in PSR1. + break; + } - if (host_reg != flush_reg) - Unlock(flush_reg); - } + if (host_reg != flush_reg) + Unlock(flush_reg); + } - reg.Load(reg.GetReg(), type); - return reg.GetReg(); + reg.Load(reg.GetReg(), type); + return reg.GetReg(); } void Arm64FPRCache::GetAllocationOrder() { - const std::vector allocation_order = - { - // Callee saved - Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, + const std::vector allocation_order = {// Callee saved + Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, - // Caller saved - Q16, Q17, Q18, Q19, Q20, Q21, Q22, Q23, - Q24, Q25, Q26, Q27, Q28, Q29, Q30, Q31, - Q7, Q6, Q5, Q4, Q3, Q2, Q1, Q0 - }; + // Caller saved + Q16, Q17, Q18, Q19, Q20, Q21, Q22, Q23, Q24, Q25, + Q26, Q27, Q28, Q29, Q30, Q31, Q7, Q6, Q5, Q4, Q3, + Q2, Q1, Q0}; - for (ARM64Reg reg : allocation_order) - m_host_registers.push_back(HostReg(reg)); + for (ARM64Reg reg : allocation_order) + m_host_registers.push_back(HostReg(reg)); } void Arm64FPRCache::FlushByHost(ARM64Reg host_reg) { - for (int i = 0; i < 32; ++i) - { - OpArg& reg = m_guest_registers[i]; - if ((reg.GetType() != REG_NOTLOADED && reg.GetType() != REG_IMM) && reg.GetReg() == host_reg) - { - FlushRegister(i, false); - return; - } - } - + for (int i = 0; i < 32; ++i) + { + OpArg& reg = m_guest_registers[i]; + if ((reg.GetType() != REG_NOTLOADED && reg.GetType() != REG_IMM) && reg.GetReg() == host_reg) + { + FlushRegister(i, false); + return; + } + } } bool Arm64FPRCache::IsCalleeSaved(ARM64Reg reg) { - static std::vector callee_regs = - { - Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, INVALID_REG, - }; - return std::find(callee_regs.begin(), callee_regs.end(), reg) != callee_regs.end(); + static std::vector callee_regs = { + Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, INVALID_REG, + }; + return std::find(callee_regs.begin(), callee_regs.end(), reg) != callee_regs.end(); } void Arm64FPRCache::FlushRegister(u32 preg, bool maintain_state) { - OpArg& reg = m_guest_registers[preg]; - ARM64Reg host_reg = reg.GetReg(); - RegType type = reg.GetType(); - bool dirty = reg.IsDirty(); + OpArg& reg = m_guest_registers[preg]; + ARM64Reg host_reg = reg.GetReg(); + RegType type = reg.GetType(); + bool dirty = reg.IsDirty(); - // If we're in single mode, just convert it back to a double. - if (type == REG_REG_SINGLE) - { - if (dirty) - m_float_emit->FCVTL(64, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg)); - type = REG_REG; - } - if (type == REG_DUP_SINGLE || type == REG_LOWER_PAIR_SINGLE) - { - if (dirty) - m_float_emit->FCVT(64, 32, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg)); + // If we're in single mode, just convert it back to a double. + if (type == REG_REG_SINGLE) + { + if (dirty) + m_float_emit->FCVTL(64, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg)); + type = REG_REG; + } + if (type == REG_DUP_SINGLE || type == REG_LOWER_PAIR_SINGLE) + { + if (dirty) + m_float_emit->FCVT(64, 32, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg)); - if (type == REG_DUP_SINGLE) - type = REG_DUP; - else - type = REG_LOWER_PAIR; - } + if (type == REG_DUP_SINGLE) + type = REG_DUP; + else + type = REG_LOWER_PAIR; + } - if (type == REG_REG || type == REG_LOWER_PAIR) - { - u32 store_size; - if (type == REG_REG) - store_size = 128; - else - store_size = 64; + if (type == REG_REG || type == REG_LOWER_PAIR) + { + u32 store_size; + if (type == REG_REG) + store_size = 128; + else + store_size = 64; - if (dirty) - m_float_emit->STR(store_size, INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(ps[preg][0])); + if (dirty) + m_float_emit->STR(store_size, INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(ps[preg][0])); - if (!maintain_state) - { - UnlockRegister(host_reg); - reg.Flush(); - } - } - else if (type == REG_DUP) - { - if (dirty) - { - // If the paired registers were at the start of ppcState we could do an STP here. - // Too bad moving them would break savestate compatibility between x86_64 and AArch64 - //m_float_emit->STP(64, INDEX_SIGNED, host_reg, host_reg, PPC_REG, PPCSTATE_OFF(ps[preg][0])); - m_float_emit->STR(64, INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(ps[preg][0])); - m_float_emit->STR(64, INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(ps[preg][1])); - } + if (!maintain_state) + { + UnlockRegister(host_reg); + reg.Flush(); + } + } + else if (type == REG_DUP) + { + if (dirty) + { + // If the paired registers were at the start of ppcState we could do an STP here. + // Too bad moving them would break savestate compatibility between x86_64 and AArch64 + // m_float_emit->STP(64, INDEX_SIGNED, host_reg, host_reg, PPC_REG, + // PPCSTATE_OFF(ps[preg][0])); + m_float_emit->STR(64, INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(ps[preg][0])); + m_float_emit->STR(64, INDEX_UNSIGNED, host_reg, PPC_REG, PPCSTATE_OFF(ps[preg][1])); + } - if (!maintain_state) - { - UnlockRegister(host_reg); - reg.Flush(); - } - } + if (!maintain_state) + { + UnlockRegister(host_reg); + reg.Flush(); + } + } } void Arm64FPRCache::FlushRegisters(BitSet32 regs, bool maintain_state) { - for (int j : regs) - FlushRegister(j, maintain_state); + for (int j : regs) + FlushRegister(j, maintain_state); } BitSet32 Arm64FPRCache::GetCallerSavedUsed() { - BitSet32 registers(0); - for (auto& it : m_host_registers) - if (it.IsLocked()) - registers[it.GetReg() - Q0] = 1; - return registers; + BitSet32 registers(0); + for (auto& it : m_host_registers) + if (it.IsLocked()) + registers[it.GetReg() - Q0] = 1; + return registers; } bool Arm64FPRCache::IsSingle(u32 preg, bool lower_only) { - RegType type = m_guest_registers[preg].GetType(); - return type == REG_REG_SINGLE || type == REG_DUP_SINGLE || (lower_only && type == REG_LOWER_PAIR_SINGLE); + RegType type = m_guest_registers[preg].GetType(); + return type == REG_REG_SINGLE || type == REG_DUP_SINGLE || + (lower_only && type == REG_LOWER_PAIR_SINGLE); } void Arm64FPRCache::FixSinglePrecision(u32 preg) { - OpArg& reg = m_guest_registers[preg]; - ARM64Reg host_reg = reg.GetReg(); - switch (reg.GetType()) - { - case REG_DUP: // only PS0 needs to be converted - m_float_emit->FCVT(32, 64, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg)); - reg.Load(host_reg, REG_DUP_SINGLE); - break; - case REG_REG: // PS0 and PS1 needs to be converted - m_float_emit->FCVTN(32, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg)); - reg.Load(host_reg, REG_REG_SINGLE); - break; - default: - break; - } + OpArg& reg = m_guest_registers[preg]; + ARM64Reg host_reg = reg.GetReg(); + switch (reg.GetType()) + { + case REG_DUP: // only PS0 needs to be converted + m_float_emit->FCVT(32, 64, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg)); + reg.Load(host_reg, REG_DUP_SINGLE); + break; + case REG_REG: // PS0 and PS1 needs to be converted + m_float_emit->FCVTN(32, EncodeRegToDouble(host_reg), EncodeRegToDouble(host_reg)); + reg.Load(host_reg, REG_REG_SINGLE); + break; + default: + break; + } } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h index 2af6281a49..1f5049176d 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h @@ -9,294 +9,268 @@ #include "Common/Arm64Emitter.h" #include "Core/PowerPC/Gekko.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PPCAnalyst.h" +#include "Core/PowerPC/PowerPC.h" using namespace Arm64Gen; // Dedicated host registers -static const ARM64Reg MEM_REG = X28; // memory base register -static const ARM64Reg PPC_REG = X29; // ppcState pointer -static const ARM64Reg DISPATCHER_PC = W26; // register for PC when calling the dispatcher +static const ARM64Reg MEM_REG = X28; // memory base register +static const ARM64Reg PPC_REG = X29; // ppcState pointer +static const ARM64Reg DISPATCHER_PC = W26; // register for PC when calling the dispatcher #define PPCSTATE_OFF(elem) (offsetof(PowerPC::PowerPCState, elem)) // Some asserts to make sure we will be able to load everything static_assert(PPCSTATE_OFF(spr[1023]) <= 16380, "LDR(32bit) can't reach the last SPR"); -static_assert((PPCSTATE_OFF(ps[0][0]) % 8) == 0, "LDR(64bit VFP) requires FPRs to be 8 byte aligned"); +static_assert((PPCSTATE_OFF(ps[0][0]) % 8) == 0, + "LDR(64bit VFP) requires FPRs to be 8 byte aligned"); static_assert(PPCSTATE_OFF(xer_ca) < 4096, "STRB can't store xer_ca!"); static_assert(PPCSTATE_OFF(xer_so_ov) < 4096, "STRB can't store xer_so_ov!"); enum RegType { - REG_NOTLOADED = 0, - REG_REG, // Reg type is register - REG_IMM, // Reg is really a IMM - REG_LOWER_PAIR, // Only the lower pair of a paired register - REG_DUP, // The lower reg is the same as the upper one (physical upper doesn't actually have the duplicated value) - REG_REG_SINGLE, // Both registers are loaded as single - REG_LOWER_PAIR_SINGLE, // Only the lower pair of a paired register, as single - REG_DUP_SINGLE, // The lower one contains both registers, as single + REG_NOTLOADED = 0, + REG_REG, // Reg type is register + REG_IMM, // Reg is really a IMM + REG_LOWER_PAIR, // Only the lower pair of a paired register + REG_DUP, // The lower reg is the same as the upper one (physical upper doesn't actually have the + // duplicated value) + REG_REG_SINGLE, // Both registers are loaded as single + REG_LOWER_PAIR_SINGLE, // Only the lower pair of a paired register, as single + REG_DUP_SINGLE, // The lower one contains both registers, as single }; enum FlushMode { - // Flushes all registers, no exceptions - FLUSH_ALL = 0, - // Flushes registers in a conditional branch - // Doesn't wipe the state of the registers from the cache - FLUSH_MAINTAIN_STATE, + // Flushes all registers, no exceptions + FLUSH_ALL = 0, + // Flushes registers in a conditional branch + // Doesn't wipe the state of the registers from the cache + FLUSH_MAINTAIN_STATE, }; class OpArg { public: - OpArg() - : m_type(REG_NOTLOADED), m_reg(INVALID_REG), - m_value(0), m_last_used(0) - { - } + OpArg() : m_type(REG_NOTLOADED), m_reg(INVALID_REG), m_value(0), m_last_used(0) {} + RegType GetType() const { return m_type; } + ARM64Reg GetReg() const { return m_reg; } + u32 GetImm() const { return m_value; } + void Load(ARM64Reg reg, RegType type = REG_REG) + { + m_type = type; + m_reg = reg; + } + void LoadToImm(u32 imm) + { + m_type = REG_IMM; + m_value = imm; - RegType GetType() const - { - return m_type; - } + m_reg = INVALID_REG; + } + void Flush() + { + // Invalidate any previous information + m_type = REG_NOTLOADED; + m_reg = INVALID_REG; - ARM64Reg GetReg() const - { - return m_reg; - } - u32 GetImm() const - { - return m_value; - } - void Load(ARM64Reg reg, RegType type = REG_REG) - { - m_type = type; - m_reg = reg; - } - void LoadToImm(u32 imm) - { - m_type = REG_IMM; - m_value = imm; - - m_reg = INVALID_REG; - } - void Flush() - { - // Invalidate any previous information - m_type = REG_NOTLOADED; - m_reg = INVALID_REG; - - // Arbitrarily large value that won't roll over on a lot of increments - m_last_used = 0xFFFF; - } - - u32 GetLastUsed() const { return m_last_used; } - void ResetLastUsed() { m_last_used = 0; } - void IncrementLastUsed() { ++m_last_used; } - - void SetDirty(bool dirty) { m_dirty = dirty; } - bool IsDirty() const { return m_dirty; } + // Arbitrarily large value that won't roll over on a lot of increments + m_last_used = 0xFFFF; + } + u32 GetLastUsed() const { return m_last_used; } + void ResetLastUsed() { m_last_used = 0; } + void IncrementLastUsed() { ++m_last_used; } + void SetDirty(bool dirty) { m_dirty = dirty; } + bool IsDirty() const { return m_dirty; } private: - // For REG_REG - RegType m_type; // store type - ARM64Reg m_reg; // host register we are in + // For REG_REG + RegType m_type; // store type + ARM64Reg m_reg; // host register we are in - // For REG_IMM - u32 m_value; // IMM value + // For REG_IMM + u32 m_value; // IMM value - u32 m_last_used; + u32 m_last_used; - bool m_dirty; + bool m_dirty; }; class HostReg { public: - HostReg() : m_reg(INVALID_REG), m_locked(false) {} - HostReg(ARM64Reg reg) : m_reg(reg), m_locked(false) {} - bool IsLocked() const { return m_locked; } - void Lock() { m_locked = true; } - void Unlock() { m_locked = false; } - ARM64Reg GetReg() const { return m_reg; } - - bool operator==(const ARM64Reg& reg) - { - return reg == m_reg; - } - + HostReg() : m_reg(INVALID_REG), m_locked(false) {} + HostReg(ARM64Reg reg) : m_reg(reg), m_locked(false) {} + bool IsLocked() const { return m_locked; } + void Lock() { m_locked = true; } + void Unlock() { m_locked = false; } + ARM64Reg GetReg() const { return m_reg; } + bool operator==(const ARM64Reg& reg) { return reg == m_reg; } private: - ARM64Reg m_reg; - bool m_locked; + ARM64Reg m_reg; + bool m_locked; }; class Arm64RegCache { public: - Arm64RegCache() : m_emit(nullptr), m_float_emit(nullptr), m_reg_stats(nullptr) {}; - virtual ~Arm64RegCache() {}; + Arm64RegCache() : m_emit(nullptr), m_float_emit(nullptr), m_reg_stats(nullptr){}; + virtual ~Arm64RegCache(){}; - void Init(ARM64XEmitter *emitter); + void Init(ARM64XEmitter* emitter); - virtual void Start(PPCAnalyst::BlockRegStats &stats) {} + virtual void Start(PPCAnalyst::BlockRegStats& stats) {} + // Flushes the register cache in different ways depending on the mode + virtual void Flush(FlushMode mode, PPCAnalyst::CodeOp* op) = 0; - // Flushes the register cache in different ways depending on the mode - virtual void Flush(FlushMode mode, PPCAnalyst::CodeOp* op) = 0; + virtual BitSet32 GetCallerSavedUsed() = 0; - virtual BitSet32 GetCallerSavedUsed() = 0; + // Returns a temporary register for use + // Requires unlocking after done + ARM64Reg GetReg(); - // Returns a temporary register for use - // Requires unlocking after done - ARM64Reg GetReg(); + void StoreRegisters(BitSet32 regs) { FlushRegisters(regs, false); } + // Locks a register so a cache cannot use it + // Useful for function calls + template + void Lock(Args... args) + { + for (T reg : {args...}) + { + FlushByHost(reg); + LockRegister(reg); + } + } - void StoreRegisters(BitSet32 regs) { FlushRegisters(regs, false); } - - // Locks a register so a cache cannot use it - // Useful for function calls - template - void Lock(Args... args) - { - for (T reg : {args...}) - { - FlushByHost(reg); - LockRegister(reg); - } - } - - // Unlocks a locked register - // Unlocks registers locked with both GetReg and LockRegister - template - void Unlock(Args... args) - { - for (T reg : {args...}) - { - FlushByHost(reg); - UnlockRegister(reg); - } - } + // Unlocks a locked register + // Unlocks registers locked with both GetReg and LockRegister + template + void Unlock(Args... args) + { + for (T reg : {args...}) + { + FlushByHost(reg); + UnlockRegister(reg); + } + } protected: - // Get the order of the host registers - virtual void GetAllocationOrder() = 0; + // Get the order of the host registers + virtual void GetAllocationOrder() = 0; - // Flushes the most stale register - void FlushMostStaleRegister(); + // Flushes the most stale register + void FlushMostStaleRegister(); - // Lock a register - void LockRegister(ARM64Reg host_reg); + // Lock a register + void LockRegister(ARM64Reg host_reg); - // Unlock a register - void UnlockRegister(ARM64Reg host_reg); + // Unlock a register + void UnlockRegister(ARM64Reg host_reg); - // Flushes a guest register by host provided - virtual void FlushByHost(ARM64Reg host_reg) = 0; + // Flushes a guest register by host provided + virtual void FlushByHost(ARM64Reg host_reg) = 0; - virtual void FlushRegister(u32 preg, bool maintain_state) = 0; + virtual void FlushRegister(u32 preg, bool maintain_state) = 0; - virtual void FlushRegisters(BitSet32 regs, bool maintain_state) = 0; + virtual void FlushRegisters(BitSet32 regs, bool maintain_state) = 0; - // Get available host registers - u32 GetUnlockedRegisterCount(); + // Get available host registers + u32 GetUnlockedRegisterCount(); - void IncrementAllUsed() - { - for (auto& reg : m_guest_registers) - reg.IncrementLastUsed(); - } + void IncrementAllUsed() + { + for (auto& reg : m_guest_registers) + reg.IncrementLastUsed(); + } - // Code emitter - ARM64XEmitter *m_emit; + // Code emitter + ARM64XEmitter* m_emit; - // Float emitter - std::unique_ptr m_float_emit; + // Float emitter + std::unique_ptr m_float_emit; - // Host side registers that hold the host registers in order of use - std::vector m_host_registers; + // Host side registers that hold the host registers in order of use + std::vector m_host_registers; - // Our guest GPRs - // PowerPC has 32 GPRs - // PowerPC also has 32 paired FPRs - OpArg m_guest_registers[32]; + // Our guest GPRs + // PowerPC has 32 GPRs + // PowerPC also has 32 paired FPRs + OpArg m_guest_registers[32]; - // Register stats for the current block - PPCAnalyst::BlockRegStats *m_reg_stats; + // Register stats for the current block + PPCAnalyst::BlockRegStats* m_reg_stats; }; class Arm64GPRCache : public Arm64RegCache { public: - ~Arm64GPRCache() {} + ~Arm64GPRCache() {} + void Start(PPCAnalyst::BlockRegStats& stats); - void Start(PPCAnalyst::BlockRegStats &stats); + // Flushes the register cache in different ways depending on the mode + void Flush(FlushMode mode, PPCAnalyst::CodeOp* op = nullptr); - // Flushes the register cache in different ways depending on the mode - void Flush(FlushMode mode, PPCAnalyst::CodeOp* op = nullptr); + // Returns a guest register inside of a host register + // Will dump an immediate to the host register as well + ARM64Reg R(u32 preg); - // Returns a guest register inside of a host register - // Will dump an immediate to the host register as well - ARM64Reg R(u32 preg); + // Set a register to an immediate + void SetImmediate(u32 preg, u32 imm); - // Set a register to an immediate - void SetImmediate(u32 preg, u32 imm); + // Returns if a register is set as an immediate + bool IsImm(u32 reg) const { return m_guest_registers[reg].GetType() == REG_IMM; } + // Gets the immediate that a register is set to + u32 GetImm(u32 reg) const { return m_guest_registers[reg].GetImm(); } + void BindToRegister(u32 preg, bool do_load); - // Returns if a register is set as an immediate - bool IsImm(u32 reg) const { return m_guest_registers[reg].GetType() == REG_IMM; } - - // Gets the immediate that a register is set to - u32 GetImm(u32 reg) const { return m_guest_registers[reg].GetImm(); } - - void BindToRegister(u32 preg, bool do_load); - - BitSet32 GetCallerSavedUsed() override; + BitSet32 GetCallerSavedUsed() override; protected: - // Get the order of the host registers - void GetAllocationOrder(); + // Get the order of the host registers + void GetAllocationOrder(); - // Flushes a guest register by host provided - void FlushByHost(ARM64Reg host_reg) override; + // Flushes a guest register by host provided + void FlushByHost(ARM64Reg host_reg) override; - void FlushRegister(u32 preg, bool maintain_state) override; + void FlushRegister(u32 preg, bool maintain_state) override; - void FlushRegisters(BitSet32 regs, bool maintain_state) override; + void FlushRegisters(BitSet32 regs, bool maintain_state) override; private: - bool IsCalleeSaved(ARM64Reg reg); - + bool IsCalleeSaved(ARM64Reg reg); }; class Arm64FPRCache : public Arm64RegCache { public: - ~Arm64FPRCache() {} - // Flushes the register cache in different ways depending on the mode - void Flush(FlushMode mode, PPCAnalyst::CodeOp* op = nullptr); + ~Arm64FPRCache() {} + // Flushes the register cache in different ways depending on the mode + void Flush(FlushMode mode, PPCAnalyst::CodeOp* op = nullptr); - // Returns a guest register inside of a host register - // Will dump an immediate to the host register as well - ARM64Reg R(u32 preg, RegType type = REG_LOWER_PAIR); + // Returns a guest register inside of a host register + // Will dump an immediate to the host register as well + ARM64Reg R(u32 preg, RegType type = REG_LOWER_PAIR); - ARM64Reg RW(u32 preg, RegType type = REG_LOWER_PAIR); + ARM64Reg RW(u32 preg, RegType type = REG_LOWER_PAIR); - BitSet32 GetCallerSavedUsed() override; + BitSet32 GetCallerSavedUsed() override; - bool IsSingle(u32 preg, bool lower_only = false); + bool IsSingle(u32 preg, bool lower_only = false); - void FixSinglePrecision(u32 preg); + void FixSinglePrecision(u32 preg); protected: - // Get the order of the host registers - void GetAllocationOrder(); + // Get the order of the host registers + void GetAllocationOrder(); - // Flushes a guest register by host provided - void FlushByHost(ARM64Reg host_reg) override; + // Flushes a guest register by host provided + void FlushByHost(ARM64Reg host_reg) override; - void FlushRegister(u32 preg, bool maintain_state) override; + void FlushRegister(u32 preg, bool maintain_state) override; - void FlushRegisters(BitSet32 regs, bool maintain_state) override; + void FlushRegisters(BitSet32 regs, bool maintain_state) override; private: - bool IsCalleeSaved(ARM64Reg reg); + bool IsCalleeSaved(ARM64Reg reg); }; diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp index 49a869fa13..22ecb11405 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp @@ -9,628 +9,632 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCTables.h" #include "Core/PowerPC/JitArm64/Jit.h" +#include "Core/PowerPC/PPCTables.h" +#include "Core/PowerPC/PowerPC.h" FixupBranch JitArm64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set) { - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); - FixupBranch branch; - switch (bit) - { - case CR_SO_BIT: // check bit 61 set - LDR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[field])); - branch = jump_if_set ? TBNZ(XA, 61) : TBZ(XA, 61); - break; - case CR_EQ_BIT: // check bits 31-0 == 0 - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(cr_val[field])); - branch = jump_if_set ? CBZ(WA) : CBNZ(WA); - break; - case CR_GT_BIT: // check val > 0 - LDR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[field])); - CMP(XA, SP); - branch = B(jump_if_set ? CC_GT : CC_LE); - break; - case CR_LT_BIT: // check bit 62 set - LDR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[field])); - branch = jump_if_set ? TBNZ(XA, 62) : TBZ(XA, 62); - break; - default: - _assert_msg_(DYNA_REC, false, "Invalid CR bit"); - } + FixupBranch branch; + switch (bit) + { + case CR_SO_BIT: // check bit 61 set + LDR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[field])); + branch = jump_if_set ? TBNZ(XA, 61) : TBZ(XA, 61); + break; + case CR_EQ_BIT: // check bits 31-0 == 0 + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(cr_val[field])); + branch = jump_if_set ? CBZ(WA) : CBNZ(WA); + break; + case CR_GT_BIT: // check val > 0 + LDR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[field])); + CMP(XA, SP); + branch = B(jump_if_set ? CC_GT : CC_LE); + break; + case CR_LT_BIT: // check bit 62 set + LDR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[field])); + branch = jump_if_set ? TBNZ(XA, 62) : TBZ(XA, 62); + break; + default: + _assert_msg_(DYNA_REC, false, "Invalid CR bit"); + } - gpr.Unlock(WA); - return branch; + gpr.Unlock(WA); + return branch; } void JitArm64::mtmsr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - gpr.BindToRegister(inst.RS, true); - STR(INDEX_UNSIGNED, gpr.R(inst.RS), PPC_REG, PPCSTATE_OFF(msr)); + gpr.BindToRegister(inst.RS, true); + STR(INDEX_UNSIGNED, gpr.R(inst.RS), PPC_REG, PPCSTATE_OFF(msr)); - gpr.Flush(FlushMode::FLUSH_ALL); - fpr.Flush(FlushMode::FLUSH_ALL); + gpr.Flush(FlushMode::FLUSH_ALL); + fpr.Flush(FlushMode::FLUSH_ALL); - WriteExceptionExit(js.compilerPC + 4, true); + WriteExceptionExit(js.compilerPC + 4, true); } void JitArm64::mfmsr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - gpr.BindToRegister(inst.RD, false); - LDR(INDEX_UNSIGNED, gpr.R(inst.RD), PPC_REG, PPCSTATE_OFF(msr)); + gpr.BindToRegister(inst.RD, false); + LDR(INDEX_UNSIGNED, gpr.R(inst.RD), PPC_REG, PPCSTATE_OFF(msr)); } void JitArm64::mcrf(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - if (inst.CRFS != inst.CRFD) - { - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); - LDR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[inst.CRFS])); - STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[inst.CRFD])); - gpr.Unlock(WA); - } + if (inst.CRFS != inst.CRFD) + { + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); + LDR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[inst.CRFS])); + STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val[inst.CRFD])); + gpr.Unlock(WA); + } } void JitArm64::mfsr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - gpr.BindToRegister(inst.RD, false); - LDR(INDEX_UNSIGNED, gpr.R(inst.RD), PPC_REG, PPCSTATE_OFF(sr[inst.SR])); + gpr.BindToRegister(inst.RD, false); + LDR(INDEX_UNSIGNED, gpr.R(inst.RD), PPC_REG, PPCSTATE_OFF(sr[inst.SR])); } void JitArm64::mtsr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - gpr.BindToRegister(inst.RS, true); - STR(INDEX_UNSIGNED, gpr.R(inst.RS), PPC_REG, PPCSTATE_OFF(sr[inst.SR])); + gpr.BindToRegister(inst.RS, true); + STR(INDEX_UNSIGNED, gpr.R(inst.RS), PPC_REG, PPCSTATE_OFF(sr[inst.SR])); } void JitArm64::mfsrin(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - u32 b = inst.RB, d = inst.RD; - gpr.BindToRegister(d, d == b); + u32 b = inst.RB, d = inst.RD; + gpr.BindToRegister(d, d == b); - ARM64Reg index = gpr.GetReg(); - ARM64Reg index64 = EncodeRegTo64(index); - ARM64Reg RB = gpr.R(b); + ARM64Reg index = gpr.GetReg(); + ARM64Reg index64 = EncodeRegTo64(index); + ARM64Reg RB = gpr.R(b); - UBFM(index, RB, 28, 31); - ADD(index64, PPC_REG, index64, ArithOption(index64, ST_LSL, 2)); - LDR(INDEX_UNSIGNED, gpr.R(d), index64, PPCSTATE_OFF(sr[0])); + UBFM(index, RB, 28, 31); + ADD(index64, PPC_REG, index64, ArithOption(index64, ST_LSL, 2)); + LDR(INDEX_UNSIGNED, gpr.R(d), index64, PPCSTATE_OFF(sr[0])); - gpr.Unlock(index); + gpr.Unlock(index); } void JitArm64::mtsrin(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - u32 b = inst.RB, d = inst.RD; - gpr.BindToRegister(d, d == b); + u32 b = inst.RB, d = inst.RD; + gpr.BindToRegister(d, d == b); - ARM64Reg index = gpr.GetReg(); - ARM64Reg index64 = EncodeRegTo64(index); - ARM64Reg RB = gpr.R(b); + ARM64Reg index = gpr.GetReg(); + ARM64Reg index64 = EncodeRegTo64(index); + ARM64Reg RB = gpr.R(b); - UBFM(index, RB, 28, 31); - ADD(index64, PPC_REG, index64, ArithOption(index64, ST_LSL, 2)); - STR(INDEX_UNSIGNED, gpr.R(d), index64, PPCSTATE_OFF(sr[0])); + UBFM(index, RB, 28, 31); + ADD(index64, PPC_REG, index64, ArithOption(index64, ST_LSL, 2)); + STR(INDEX_UNSIGNED, gpr.R(d), index64, PPCSTATE_OFF(sr[0])); - gpr.Unlock(index); + gpr.Unlock(index); } void JitArm64::twx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - s32 a = inst.RA; + s32 a = inst.RA; - ARM64Reg WA = gpr.GetReg(); + ARM64Reg WA = gpr.GetReg(); - if (inst.OPCD == 3) // twi - { - if (inst.SIMM_16 >= 0 && inst.SIMM_16 < 4096) - { - // Can fit in immediate in to the instruction encoding - CMP(gpr.R(a), inst.SIMM_16); - } - else - { - MOVI2R(WA, (s32)(s16)inst.SIMM_16); - CMP(gpr.R(a), WA); - } - } - else // tw - { - CMP(gpr.R(a), gpr.R(inst.RB)); - } + if (inst.OPCD == 3) // twi + { + if (inst.SIMM_16 >= 0 && inst.SIMM_16 < 4096) + { + // Can fit in immediate in to the instruction encoding + CMP(gpr.R(a), inst.SIMM_16); + } + else + { + MOVI2R(WA, (s32)(s16)inst.SIMM_16); + CMP(gpr.R(a), WA); + } + } + else // tw + { + CMP(gpr.R(a), gpr.R(inst.RB)); + } - std::vector fixups; - CCFlags conditions[] = { CC_LT, CC_GT, CC_EQ, CC_VC, CC_VS }; + std::vector fixups; + CCFlags conditions[] = {CC_LT, CC_GT, CC_EQ, CC_VC, CC_VS}; - for (int i = 0; i < 5; i++) - { - if (inst.TO & (1 << i)) - { - FixupBranch f = B(conditions[i]); - fixups.push_back(f); - } - } - FixupBranch dont_trap = B(); + for (int i = 0; i < 5; i++) + { + if (inst.TO & (1 << i)) + { + FixupBranch f = B(conditions[i]); + fixups.push_back(f); + } + } + FixupBranch dont_trap = B(); - for (const FixupBranch& fixup : fixups) - { - SetJumpTarget(fixup); - } + for (const FixupBranch& fixup : fixups) + { + SetJumpTarget(fixup); + } - FixupBranch far = B(); - SwitchToFarCode(); - SetJumpTarget(far); + FixupBranch far = B(); + SwitchToFarCode(); + SetJumpTarget(far); - gpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE); - fpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE); + gpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE); + fpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE); - LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); - ORR(WA, WA, 24, 0); // Same as WA | EXCEPTION_PROGRAM - STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); - gpr.Unlock(WA); + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); + ORR(WA, WA, 24, 0); // Same as WA | EXCEPTION_PROGRAM + STR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); + gpr.Unlock(WA); - WriteExceptionExit(js.compilerPC); + WriteExceptionExit(js.compilerPC); - SwitchToNearCode(); + SwitchToNearCode(); - SetJumpTarget(dont_trap); + SetJumpTarget(dont_trap); - if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) - { - gpr.Flush(FlushMode::FLUSH_ALL); - fpr.Flush(FlushMode::FLUSH_ALL); - WriteExit(js.compilerPC + 4); - } + if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) + { + gpr.Flush(FlushMode::FLUSH_ALL); + fpr.Flush(FlushMode::FLUSH_ALL); + WriteExit(js.compilerPC + 4); + } } void JitArm64::mfspr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); - int d = inst.RD; - switch (iIndex) - { - case SPR_TL: - case SPR_TU: - { - // The inline implementation here is inaccurate and out of date as of PR3601 - FALLBACK_IF(true); // Fallback to interpreted version. + u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); + int d = inst.RD; + switch (iIndex) + { + case SPR_TL: + case SPR_TU: + { + // The inline implementation here is inaccurate and out of date as of PR3601 + FALLBACK_IF(true); // Fallback to interpreted version. - /* - ARM64Reg WA = gpr.GetReg(); - ARM64Reg WB = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); - ARM64Reg XB = EncodeRegTo64(WB); + /* + ARM64Reg WA = gpr.GetReg(); + ARM64Reg WB = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); + ARM64Reg XB = EncodeRegTo64(WB); - // An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the - // cost of calling out to C for this is actually significant. - MOVI2R(XA, (u64)&CoreTiming::g_globalTimer); - LDR(INDEX_UNSIGNED, XA, XA, 0); - MOVI2R(XB, (u64)&CoreTiming::g_fakeTBStartTicks); - LDR(INDEX_UNSIGNED, XB, XB, 0); - SUB(XA, XA, XB); + // An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the + // cost of calling out to C for this is actually significant. + MOVI2R(XA, (u64)&CoreTiming::g_globalTimer); + LDR(INDEX_UNSIGNED, XA, XA, 0); + MOVI2R(XB, (u64)&CoreTiming::g_fakeTBStartTicks); + LDR(INDEX_UNSIGNED, XB, XB, 0); + SUB(XA, XA, XB); - // It might seem convenient to correct the timer for the block position here for even more accurate - // timing, but as of currently, this can break games. If we end up reading a time *after* the time - // at which an interrupt was supposed to occur, e.g. because we're 100 cycles into a block with only - // 50 downcount remaining, some games don't function correctly, such as Karaoke Party Revolution, - // which won't get past the loading screen. - // a / 12 = (a * 0xAAAAAAAAAAAAAAAB) >> 67 - ORR(XB, SP, 1, 60); - ADD(XB, XB, 1); - UMULH(XA, XA, XB); + // It might seem convenient to correct the timer for the block position here for even more + accurate + // timing, but as of currently, this can break games. If we end up reading a time *after* the + time + // at which an interrupt was supposed to occur, e.g. because we're 100 cycles into a block with + only + // 50 downcount remaining, some games don't function correctly, such as Karaoke Party + Revolution, + // which won't get past the loading screen. + // a / 12 = (a * 0xAAAAAAAAAAAAAAAB) >> 67 + ORR(XB, SP, 1, 60); + ADD(XB, XB, 1); + UMULH(XA, XA, XB); - MOVI2R(XB, (u64)&CoreTiming::g_fakeTBStartValue); - LDR(INDEX_UNSIGNED, XB, XB, 0); - ADD(XA, XB, XA, ArithOption(XA, ST_LSR, 3)); - STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(spr[SPR_TL])); + MOVI2R(XB, (u64)&CoreTiming::g_fakeTBStartValue); + LDR(INDEX_UNSIGNED, XB, XB, 0); + ADD(XA, XB, XA, ArithOption(XA, ST_LSR, 3)); + STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(spr[SPR_TL])); - if (MergeAllowedNextInstructions(1)) - { - const UGeckoInstruction& next = js.op[1].inst; - // Two calls of TU/TL next to each other are extremely common in typical usage, so merge them - // if we can. - u32 nextIndex = (next.SPRU << 5) | (next.SPRL & 0x1F); - // Be careful; the actual opcode is for mftb (371), not mfspr (339) - int n = next.RD; - if (next.OPCD == 31 && next.SUBOP10 == 371 && (nextIndex == SPR_TU || nextIndex == SPR_TL) && n != d) - { - js.downcountAmount++; - js.skipInstructions = 1; - gpr.BindToRegister(d, false); - gpr.BindToRegister(n, false); - if (iIndex == SPR_TL) - MOV(gpr.R(d), WA); - else - ORR(EncodeRegTo64(gpr.R(d)), SP, XA, ArithOption(XA, ST_LSR, 32)); + if (MergeAllowedNextInstructions(1)) + { + const UGeckoInstruction& next = js.op[1].inst; + // Two calls of TU/TL next to each other are extremely common in typical usage, so merge them + // if we can. + u32 nextIndex = (next.SPRU << 5) | (next.SPRL & 0x1F); + // Be careful; the actual opcode is for mftb (371), not mfspr (339) + int n = next.RD; + if (next.OPCD == 31 && next.SUBOP10 == 371 && (nextIndex == SPR_TU || nextIndex == SPR_TL) && + n != d) + { + js.downcountAmount++; + js.skipInstructions = 1; + gpr.BindToRegister(d, false); + gpr.BindToRegister(n, false); + if (iIndex == SPR_TL) + MOV(gpr.R(d), WA); + else + ORR(EncodeRegTo64(gpr.R(d)), SP, XA, ArithOption(XA, ST_LSR, 32)); - if (nextIndex == SPR_TL) - MOV(gpr.R(n), WA); - else - ORR(EncodeRegTo64(gpr.R(n)), SP, XA, ArithOption(XA, ST_LSR, 32)); + if (nextIndex == SPR_TL) + MOV(gpr.R(n), WA); + else + ORR(EncodeRegTo64(gpr.R(n)), SP, XA, ArithOption(XA, ST_LSR, 32)); - gpr.Unlock(WA, WB); - break; - } - } - gpr.BindToRegister(d, false); - if (iIndex == SPR_TU) - ORR(EncodeRegTo64(gpr.R(d)), SP, XA, ArithOption(XA, ST_LSR, 32)); - else - MOV(gpr.R(d), WA); - gpr.Unlock(WA, WB);*/ - } - break; - case SPR_XER: - { - gpr.BindToRegister(d, false); - ARM64Reg RD = gpr.R(d); - ARM64Reg WA = gpr.GetReg(); - LDRH(INDEX_UNSIGNED, RD, PPC_REG, PPCSTATE_OFF(xer_stringctrl)); - LDRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); - ORR(RD, RD, WA, ArithOption(WA, ST_LSL, XER_CA_SHIFT)); - LDRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_so_ov)); - ORR(RD, RD, WA, ArithOption(WA, ST_LSL, XER_OV_SHIFT)); - gpr.Unlock(WA); - } - break; - case SPR_WPAR: - case SPR_DEC: - FALLBACK_IF(true); - default: - gpr.BindToRegister(d, false); - ARM64Reg RD = gpr.R(d); - LDR(INDEX_UNSIGNED, RD, PPC_REG, PPCSTATE_OFF(spr) + iIndex * 4); - break; - } + gpr.Unlock(WA, WB); + break; + } + } + gpr.BindToRegister(d, false); + if (iIndex == SPR_TU) + ORR(EncodeRegTo64(gpr.R(d)), SP, XA, ArithOption(XA, ST_LSR, 32)); + else + MOV(gpr.R(d), WA); + gpr.Unlock(WA, WB);*/ + } + break; + case SPR_XER: + { + gpr.BindToRegister(d, false); + ARM64Reg RD = gpr.R(d); + ARM64Reg WA = gpr.GetReg(); + LDRH(INDEX_UNSIGNED, RD, PPC_REG, PPCSTATE_OFF(xer_stringctrl)); + LDRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); + ORR(RD, RD, WA, ArithOption(WA, ST_LSL, XER_CA_SHIFT)); + LDRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_so_ov)); + ORR(RD, RD, WA, ArithOption(WA, ST_LSL, XER_OV_SHIFT)); + gpr.Unlock(WA); + } + break; + case SPR_WPAR: + case SPR_DEC: + FALLBACK_IF(true); + default: + gpr.BindToRegister(d, false); + ARM64Reg RD = gpr.R(d); + LDR(INDEX_UNSIGNED, RD, PPC_REG, PPCSTATE_OFF(spr) + iIndex * 4); + break; + } } void JitArm64::mftb(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - mfspr(inst); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + mfspr(inst); } void JitArm64::mtspr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); + u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); - switch (iIndex) - { - case SPR_DMAU: + switch (iIndex) + { + case SPR_DMAU: - case SPR_SPRG0: - case SPR_SPRG1: - case SPR_SPRG2: - case SPR_SPRG3: + case SPR_SPRG0: + case SPR_SPRG1: + case SPR_SPRG2: + case SPR_SPRG3: - case SPR_SRR0: - case SPR_SRR1: - // These are safe to do the easy way, see the bottom of this function. - break; + case SPR_SRR0: + case SPR_SRR1: + // These are safe to do the easy way, see the bottom of this function. + break; - case SPR_LR: - case SPR_CTR: - case SPR_GQR0: - case SPR_GQR0 + 1: - case SPR_GQR0 + 2: - case SPR_GQR0 + 3: - case SPR_GQR0 + 4: - case SPR_GQR0 + 5: - case SPR_GQR0 + 6: - case SPR_GQR0 + 7: - // These are safe to do the easy way, see the bottom of this function. - break; - case SPR_XER: - { - ARM64Reg RD = gpr.R(inst.RD); - ARM64Reg WA = gpr.GetReg(); - AND(WA, RD, 24, 30); - STRH(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_stringctrl)); - UBFM(WA, RD, XER_CA_SHIFT, XER_CA_SHIFT + 1); - STRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); - UBFM(WA, RD, XER_OV_SHIFT, 31); // Same as WA = RD >> XER_OV_SHIFT - STRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_so_ov)); - gpr.Unlock(WA); - } - break; - default: - FALLBACK_IF(true); - } + case SPR_LR: + case SPR_CTR: + case SPR_GQR0: + case SPR_GQR0 + 1: + case SPR_GQR0 + 2: + case SPR_GQR0 + 3: + case SPR_GQR0 + 4: + case SPR_GQR0 + 5: + case SPR_GQR0 + 6: + case SPR_GQR0 + 7: + // These are safe to do the easy way, see the bottom of this function. + break; + case SPR_XER: + { + ARM64Reg RD = gpr.R(inst.RD); + ARM64Reg WA = gpr.GetReg(); + AND(WA, RD, 24, 30); + STRH(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_stringctrl)); + UBFM(WA, RD, XER_CA_SHIFT, XER_CA_SHIFT + 1); + STRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_ca)); + UBFM(WA, RD, XER_OV_SHIFT, 31); // Same as WA = RD >> XER_OV_SHIFT + STRB(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(xer_so_ov)); + gpr.Unlock(WA); + } + break; + default: + FALLBACK_IF(true); + } - // OK, this is easy. - ARM64Reg RD = gpr.R(inst.RD); - STR(INDEX_UNSIGNED, RD, PPC_REG, PPCSTATE_OFF(spr) + iIndex * 4); + // OK, this is easy. + ARM64Reg RD = gpr.R(inst.RD); + STR(INDEX_UNSIGNED, RD, PPC_REG, PPCSTATE_OFF(spr) + iIndex * 4); } void JitArm64::crXXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - // Special case: crclr - if (inst.CRBA == inst.CRBB && inst.CRBA == inst.CRBD && inst.SUBOP10 == 193) - { - // Clear CR field bit - int field = inst.CRBD >> 2; - int bit = 3 - (inst.CRBD & 3); + // Special case: crclr + if (inst.CRBA == inst.CRBB && inst.CRBA == inst.CRBD && inst.SUBOP10 == 193) + { + // Clear CR field bit + int field = inst.CRBD >> 2; + int bit = 3 - (inst.CRBD & 3); - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); - LDR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * field); - switch (bit) - { - case CR_SO_BIT: - AND(XA, XA, 64 - 62, 62, true); // XA & ~(1<<61) - break; + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); + LDR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * field); + switch (bit) + { + case CR_SO_BIT: + AND(XA, XA, 64 - 62, 62, true); // XA & ~(1<<61) + break; - case CR_EQ_BIT: - ORR(XA, XA, 0, 0, true); // XA | 1<<0 - break; + case CR_EQ_BIT: + ORR(XA, XA, 0, 0, true); // XA | 1<<0 + break; - case CR_GT_BIT: - ORR(XA, XA, 64 - 63, 0, true); // XA | 1<<63 - break; + case CR_GT_BIT: + ORR(XA, XA, 64 - 63, 0, true); // XA | 1<<63 + break; - case CR_LT_BIT: - AND(XA, XA, 64 - 63, 62, true); // XA & ~(1<<62) - break; - } - STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * field); - gpr.Unlock(WA); - return; - } + case CR_LT_BIT: + AND(XA, XA, 64 - 63, 62, true); // XA & ~(1<<62) + break; + } + STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * field); + gpr.Unlock(WA); + return; + } - // Special case: crset - if (inst.CRBA == inst.CRBB && inst.CRBA == inst.CRBD && inst.SUBOP10 == 289) - { - // SetCRFieldBit - int field = inst.CRBD >> 2; - int bit = 3 - (inst.CRBD & 3); + // Special case: crset + if (inst.CRBA == inst.CRBB && inst.CRBA == inst.CRBD && inst.SUBOP10 == 289) + { + // SetCRFieldBit + int field = inst.CRBD >> 2; + int bit = 3 - (inst.CRBD & 3); - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); - LDR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * field); + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); + LDR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * field); - if (bit != CR_GT_BIT) - { - ARM64Reg WB = gpr.GetReg(); - ARM64Reg XB = EncodeRegTo64(WB); - ORR(XB, XA, 64 - 63, 0, true); // XA | 1<<63 - CMP(XA, ZR); - CSEL(XA, XA, XB, CC_NEQ); - gpr.Unlock(WB); - } + if (bit != CR_GT_BIT) + { + ARM64Reg WB = gpr.GetReg(); + ARM64Reg XB = EncodeRegTo64(WB); + ORR(XB, XA, 64 - 63, 0, true); // XA | 1<<63 + CMP(XA, ZR); + CSEL(XA, XA, XB, CC_NEQ); + gpr.Unlock(WB); + } - switch (bit) - { - case CR_SO_BIT: - ORR(XA, XA, 64 - 61, 0, true); // XA | 1<<61 - break; + switch (bit) + { + case CR_SO_BIT: + ORR(XA, XA, 64 - 61, 0, true); // XA | 1<<61 + break; - case CR_EQ_BIT: - AND(XA, XA, 32, 31, true); // Clear lower 32bits - break; + case CR_EQ_BIT: + AND(XA, XA, 32, 31, true); // Clear lower 32bits + break; - case CR_GT_BIT: - AND(XA, XA, 0, 62, true); // XA & ~(1<<63) - break; + case CR_GT_BIT: + AND(XA, XA, 0, 62, true); // XA & ~(1<<63) + break; - case CR_LT_BIT: - ORR(XA, XA, 64 - 62, 0, true); // XA | 1<<62 - break; - } + case CR_LT_BIT: + ORR(XA, XA, 64 - 62, 0, true); // XA | 1<<62 + break; + } - ORR(XA, XA, 32, 0, true); // XA | 1<<32 + ORR(XA, XA, 32, 0, true); // XA | 1<<32 - STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * field); - gpr.Unlock(WA); - return; - } + STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * field); + gpr.Unlock(WA); + return; + } - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); - ARM64Reg WB = gpr.GetReg(); - ARM64Reg XB = EncodeRegTo64(WB); + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); + ARM64Reg WB = gpr.GetReg(); + ARM64Reg XB = EncodeRegTo64(WB); - // creqv or crnand or crnor - bool negateA = inst.SUBOP10 == 289 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33; - // crandc or crorc or crnand or crnor - bool negateB = inst.SUBOP10 == 129 || inst.SUBOP10 == 417 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33; + // creqv or crnand or crnor + bool negateA = inst.SUBOP10 == 289 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33; + // crandc or crorc or crnand or crnor + bool negateB = + inst.SUBOP10 == 129 || inst.SUBOP10 == 417 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33; - // GetCRFieldBit - for (int i = 0; i < 2; i++) - { - int field = i ? inst.CRBB >> 2 : inst.CRBA >> 2; - int bit = i ? 3 - (inst.CRBB & 3) : 3 - (inst.CRBA & 3); - ARM64Reg out = i ? XB : XA; - bool negate = i ? negateB : negateA; + // GetCRFieldBit + for (int i = 0; i < 2; i++) + { + int field = i ? inst.CRBB >> 2 : inst.CRBA >> 2; + int bit = i ? 3 - (inst.CRBB & 3) : 3 - (inst.CRBA & 3); + ARM64Reg out = i ? XB : XA; + bool negate = i ? negateB : negateA; - ARM64Reg WC = gpr.GetReg(); - ARM64Reg XC = EncodeRegTo64(WC); - LDR(INDEX_UNSIGNED, XC, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * field); - switch (bit) - { - case CR_SO_BIT: // check bit 61 set - UBFX(out, XC, 61, 1); - if (negate) - EOR(out, out, 0, 0, true); // XC ^ 1 - break; + ARM64Reg WC = gpr.GetReg(); + ARM64Reg XC = EncodeRegTo64(WC); + LDR(INDEX_UNSIGNED, XC, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * field); + switch (bit) + { + case CR_SO_BIT: // check bit 61 set + UBFX(out, XC, 61, 1); + if (negate) + EOR(out, out, 0, 0, true); // XC ^ 1 + break; - case CR_EQ_BIT: // check bits 31-0 == 0 - CMP(WC, WZR); - CSET(out, negate ? CC_NEQ : CC_EQ); - break; + case CR_EQ_BIT: // check bits 31-0 == 0 + CMP(WC, WZR); + CSET(out, negate ? CC_NEQ : CC_EQ); + break; - case CR_GT_BIT: // check val > 0 - CMP(XC, ZR); - CSET(out, negate ? CC_LE : CC_GT); - break; + case CR_GT_BIT: // check val > 0 + CMP(XC, ZR); + CSET(out, negate ? CC_LE : CC_GT); + break; - case CR_LT_BIT: // check bit 62 set - UBFX(out, XC, 62, 1); - if (negate) - EOR(out, out, 0, 0, true); // XC ^ 1 - break; + case CR_LT_BIT: // check bit 62 set + UBFX(out, XC, 62, 1); + if (negate) + EOR(out, out, 0, 0, true); // XC ^ 1 + break; - default: - _assert_msg_(DYNA_REC, false, "Invalid CR bit"); - } - gpr.Unlock(WC); - } + default: + _assert_msg_(DYNA_REC, false, "Invalid CR bit"); + } + gpr.Unlock(WC); + } + // Compute combined bit + switch (inst.SUBOP10) + { + case 33: // crnor: ~(A || B) == (~A && ~B) + case 129: // crandc: A && ~B + case 257: // crand: A && B + AND(XA, XA, XB); + break; - // Compute combined bit - switch (inst.SUBOP10) - { - case 33: // crnor: ~(A || B) == (~A && ~B) - case 129: // crandc: A && ~B - case 257: // crand: A && B - AND(XA, XA, XB); - break; + case 193: // crxor: A ^ B + case 289: // creqv: ~(A ^ B) = ~A ^ B + EOR(XA, XA, XB); + break; - case 193: // crxor: A ^ B - case 289: // creqv: ~(A ^ B) = ~A ^ B - EOR(XA, XA, XB); - break; + case 225: // crnand: ~(A && B) == (~A || ~B) + case 417: // crorc: A || ~B + case 449: // cror: A || B + ORR(XA, XA, XB); + break; + } - case 225: // crnand: ~(A && B) == (~A || ~B) - case 417: // crorc: A || ~B - case 449: // cror: A || B - ORR(XA, XA, XB); - break; - } + // Store result bit in CRBD + int field = inst.CRBD >> 2; + int bit = 3 - (inst.CRBD & 3); - // Store result bit in CRBD - int field = inst.CRBD >> 2; - int bit = 3 - (inst.CRBD & 3); + LDR(INDEX_UNSIGNED, XB, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * field); - LDR(INDEX_UNSIGNED, XB, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * field); + // Gross but necessary; if the input is totally zero and we set SO or LT, + // or even just add the (1<<32), GT will suddenly end up set without us + // intending to. This can break actual games, so fix it up. + if (bit != CR_GT_BIT) + { + ARM64Reg WC = gpr.GetReg(); + ARM64Reg XC = EncodeRegTo64(WC); + ORR(XC, XB, 64 - 63, 0, true); // XB | 1<<63 + CMP(XB, ZR); + CSEL(XB, XB, XC, CC_NEQ); + gpr.Unlock(WC); + } - // Gross but necessary; if the input is totally zero and we set SO or LT, - // or even just add the (1<<32), GT will suddenly end up set without us - // intending to. This can break actual games, so fix it up. - if (bit != CR_GT_BIT) - { - ARM64Reg WC = gpr.GetReg(); - ARM64Reg XC = EncodeRegTo64(WC); - ORR(XC, XB, 64 - 63, 0, true); // XB | 1<<63 - CMP(XB, ZR); - CSEL(XB, XB, XC, CC_NEQ); - gpr.Unlock(WC); - } + switch (bit) + { + case CR_SO_BIT: // set bit 61 to input + BFI(XB, XA, 61, 1); + break; - switch (bit) - { - case CR_SO_BIT: // set bit 61 to input - BFI(XB, XA, 61, 1); - break; + case CR_EQ_BIT: // clear low 32 bits, set bit 0 to !input + AND(XB, XB, 32, 31, true); // Clear lower 32bits + EOR(XA, XA, 0, 0); // XA ^ 1<<0 + ORR(XB, XB, XA); + break; - case CR_EQ_BIT: // clear low 32 bits, set bit 0 to !input - AND(XB, XB, 32, 31, true); // Clear lower 32bits - EOR(XA, XA, 0, 0); // XA ^ 1<<0 - ORR(XB, XB, XA); - break; + case CR_GT_BIT: // set bit 63 to !input + EOR(XA, XA, 0, 0); // XA ^ 1<<0 + BFI(XB, XA, 63, 1); + break; - case CR_GT_BIT: // set bit 63 to !input - EOR(XA, XA, 0, 0); // XA ^ 1<<0 - BFI(XB, XA, 63, 1); - break; + case CR_LT_BIT: // set bit 62 to input + BFI(XB, XA, 62, 1); + break; + } - case CR_LT_BIT: // set bit 62 to input - BFI(XB, XA, 62, 1); - break; - } + ORR(XA, XA, 32, 0, true); // XA | 1<<32 + STR(INDEX_UNSIGNED, XB, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * field); - ORR(XA, XA, 32, 0, true); // XA | 1<<32 - STR(INDEX_UNSIGNED, XB, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * field); - - gpr.Unlock(WA); - gpr.Unlock(WB); + gpr.Unlock(WA); + gpr.Unlock(WB); } void JitArm64::mfcr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - gpr.Lock(W0, W1, W2, W30); - BL(GetAsmRoutines()->mfcr); - gpr.Unlock(W1, W2, W30); + gpr.Lock(W0, W1, W2, W30); + BL(GetAsmRoutines()->mfcr); + gpr.Unlock(W1, W2, W30); - gpr.BindToRegister(inst.RD, false); - MOV(gpr.R(inst.RD), W0); + gpr.BindToRegister(inst.RD, false); + MOV(gpr.R(inst.RD), W0); - gpr.Unlock(W0); + gpr.Unlock(W0); } void JitArm64::mtcrf(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - u32 crm = inst.CRM; - if (crm != 0) - { - ARM64Reg RS = gpr.R(inst.RS); - ARM64Reg WA = gpr.GetReg(); - ARM64Reg XA = EncodeRegTo64(WA); - ARM64Reg WB = gpr.GetReg(); - ARM64Reg XB = EncodeRegTo64(WB); - MOVI2R(XB, (u64)m_crTable); - for (int i = 0; i < 8; ++i) - { - if ((crm & (0x80 >> i)) != 0) - { - if (i != 7) - LSR(WA, RS, 28 - i * 4); - if (i != 0) - { - if (i != 7) - UBFX(WA, WA, 0, 4); - else - UBFX(WA, RS, 0, 4); - } + u32 crm = inst.CRM; + if (crm != 0) + { + ARM64Reg RS = gpr.R(inst.RS); + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); + ARM64Reg WB = gpr.GetReg(); + ARM64Reg XB = EncodeRegTo64(WB); + MOVI2R(XB, (u64)m_crTable); + for (int i = 0; i < 8; ++i) + { + if ((crm & (0x80 >> i)) != 0) + { + if (i != 7) + LSR(WA, RS, 28 - i * 4); + if (i != 0) + { + if (i != 7) + UBFX(WA, WA, 0, 4); + else + UBFX(WA, RS, 0, 4); + } - LDR(XA, XB, ArithOption(XA, true)); - STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * i); - } - } - gpr.Unlock(WA, WB); - } + LDR(XA, XB, ArithOption(XA, true)); + STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * i); + } + } + gpr.Unlock(WA, WB); + } } - diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp index cfe4ec9d99..18d05b4abf 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp @@ -2,12 +2,12 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/JitArm64/Jit.h" #include "Core/PowerPC/JitArm64/JitArm64_Tables.h" +#include "Core/PowerPC/JitInterface.h" // Should be moved in to the Jit class -typedef void (JitArm64::*_Instruction) (UGeckoInstruction instCode); +typedef void (JitArm64::*_Instruction)(UGeckoInstruction instCode); static _Instruction dynaOpTable[64]; static _Instruction dynaOpTable4[1024]; @@ -16,462 +16,465 @@ static _Instruction dynaOpTable31[1024]; static _Instruction dynaOpTable59[32]; static _Instruction dynaOpTable63[1024]; -void JitArm64::DynaRunTable4(UGeckoInstruction inst) {(this->*dynaOpTable4 [inst.SUBOP10])(inst);} -void JitArm64::DynaRunTable19(UGeckoInstruction inst) {(this->*dynaOpTable19[inst.SUBOP10])(inst);} -void JitArm64::DynaRunTable31(UGeckoInstruction inst) {(this->*dynaOpTable31[inst.SUBOP10])(inst);} -void JitArm64::DynaRunTable59(UGeckoInstruction inst) {(this->*dynaOpTable59[inst.SUBOP5 ])(inst);} -void JitArm64::DynaRunTable63(UGeckoInstruction inst) {(this->*dynaOpTable63[inst.SUBOP10])(inst);} +void JitArm64::DynaRunTable4(UGeckoInstruction inst) +{ + (this->*dynaOpTable4[inst.SUBOP10])(inst); +} +void JitArm64::DynaRunTable19(UGeckoInstruction inst) +{ + (this->*dynaOpTable19[inst.SUBOP10])(inst); +} +void JitArm64::DynaRunTable31(UGeckoInstruction inst) +{ + (this->*dynaOpTable31[inst.SUBOP10])(inst); +} +void JitArm64::DynaRunTable59(UGeckoInstruction inst) +{ + (this->*dynaOpTable59[inst.SUBOP5])(inst); +} +void JitArm64::DynaRunTable63(UGeckoInstruction inst) +{ + (this->*dynaOpTable63[inst.SUBOP10])(inst); +} struct GekkoOPTemplate { - int opcode; - _Instruction Inst; - //GekkoOPInfo opinfo; // Doesn't need opinfo, Interpreter fills it out + int opcode; + _Instruction Inst; + // GekkoOPInfo opinfo; // Doesn't need opinfo, Interpreter fills it out }; -static GekkoOPTemplate primarytable[] = -{ - {4, &JitArm64::DynaRunTable4}, // RunTable4 - {19, &JitArm64::DynaRunTable19}, // RunTable19 - {31, &JitArm64::DynaRunTable31}, // RunTable31 - {59, &JitArm64::DynaRunTable59}, // RunTable59 - {63, &JitArm64::DynaRunTable63}, // RunTable63 +static GekkoOPTemplate primarytable[] = { + {4, &JitArm64::DynaRunTable4}, // RunTable4 + {19, &JitArm64::DynaRunTable19}, // RunTable19 + {31, &JitArm64::DynaRunTable31}, // RunTable31 + {59, &JitArm64::DynaRunTable59}, // RunTable59 + {63, &JitArm64::DynaRunTable63}, // RunTable63 - {16, &JitArm64::bcx}, // bcx - {18, &JitArm64::bx}, // bx + {16, &JitArm64::bcx}, // bcx + {18, &JitArm64::bx}, // bx - {3, &JitArm64::twx}, // twi - {17, &JitArm64::sc}, // sc + {3, &JitArm64::twx}, // twi + {17, &JitArm64::sc}, // sc - {7, &JitArm64::mulli}, // mulli - {8, &JitArm64::subfic}, // subfic - {10, &JitArm64::cmpli}, // cmpli - {11, &JitArm64::cmpi}, // cmpi - {12, &JitArm64::addic}, // addic - {13, &JitArm64::addic}, // addic_rc - {14, &JitArm64::addix}, // addi - {15, &JitArm64::addix}, // addis + {7, &JitArm64::mulli}, // mulli + {8, &JitArm64::subfic}, // subfic + {10, &JitArm64::cmpli}, // cmpli + {11, &JitArm64::cmpi}, // cmpi + {12, &JitArm64::addic}, // addic + {13, &JitArm64::addic}, // addic_rc + {14, &JitArm64::addix}, // addi + {15, &JitArm64::addix}, // addis - {20, &JitArm64::rlwimix}, // rlwimix - {21, &JitArm64::rlwinmx}, // rlwinmx - {23, &JitArm64::rlwnmx}, // rlwnmx + {20, &JitArm64::rlwimix}, // rlwimix + {21, &JitArm64::rlwinmx}, // rlwinmx + {23, &JitArm64::rlwnmx}, // rlwnmx - {24, &JitArm64::arith_imm}, // ori - {25, &JitArm64::arith_imm}, // oris - {26, &JitArm64::arith_imm}, // xori - {27, &JitArm64::arith_imm}, // xoris - {28, &JitArm64::arith_imm}, // andi_rc - {29, &JitArm64::arith_imm}, // andis_rc + {24, &JitArm64::arith_imm}, // ori + {25, &JitArm64::arith_imm}, // oris + {26, &JitArm64::arith_imm}, // xori + {27, &JitArm64::arith_imm}, // xoris + {28, &JitArm64::arith_imm}, // andi_rc + {29, &JitArm64::arith_imm}, // andis_rc - {32, &JitArm64::lXX}, // lwz - {33, &JitArm64::lXX}, // lwzu - {34, &JitArm64::lXX}, // lbz - {35, &JitArm64::lXX}, // lbzu - {40, &JitArm64::lXX}, // lhz - {41, &JitArm64::lXX}, // lhzu - {42, &JitArm64::lXX}, // lha - {43, &JitArm64::lXX}, // lhau + {32, &JitArm64::lXX}, // lwz + {33, &JitArm64::lXX}, // lwzu + {34, &JitArm64::lXX}, // lbz + {35, &JitArm64::lXX}, // lbzu + {40, &JitArm64::lXX}, // lhz + {41, &JitArm64::lXX}, // lhzu + {42, &JitArm64::lXX}, // lha + {43, &JitArm64::lXX}, // lhau - {44, &JitArm64::stX}, // sth - {45, &JitArm64::stX}, // sthu - {36, &JitArm64::stX}, // stw - {37, &JitArm64::stX}, // stwu - {38, &JitArm64::stX}, // stb - {39, &JitArm64::stX}, // stbu + {44, &JitArm64::stX}, // sth + {45, &JitArm64::stX}, // sthu + {36, &JitArm64::stX}, // stw + {37, &JitArm64::stX}, // stwu + {38, &JitArm64::stX}, // stb + {39, &JitArm64::stX}, // stbu - {46, &JitArm64::lmw}, // lmw - {47, &JitArm64::stmw}, // stmw + {46, &JitArm64::lmw}, // lmw + {47, &JitArm64::stmw}, // stmw - {48, &JitArm64::lfXX}, // lfs - {49, &JitArm64::lfXX}, // lfsu - {50, &JitArm64::lfXX}, // lfd - {51, &JitArm64::lfXX}, // lfdu + {48, &JitArm64::lfXX}, // lfs + {49, &JitArm64::lfXX}, // lfsu + {50, &JitArm64::lfXX}, // lfd + {51, &JitArm64::lfXX}, // lfdu - {52, &JitArm64::stfXX}, // stfs - {53, &JitArm64::stfXX}, // stfsu - {54, &JitArm64::stfXX}, // stfd - {55, &JitArm64::stfXX}, // stfdu + {52, &JitArm64::stfXX}, // stfs + {53, &JitArm64::stfXX}, // stfsu + {54, &JitArm64::stfXX}, // stfd + {55, &JitArm64::stfXX}, // stfdu - {56, &JitArm64::psq_l}, // psq_l - {57, &JitArm64::psq_l}, // psq_lu - {60, &JitArm64::psq_st}, // psq_st - {61, &JitArm64::psq_st}, // psq_stu + {56, &JitArm64::psq_l}, // psq_l + {57, &JitArm64::psq_l}, // psq_lu + {60, &JitArm64::psq_st}, // psq_st + {61, &JitArm64::psq_st}, // psq_stu - //missing: 0, 1, 2, 5, 6, 9, 22, 30, 62, 58 + // missing: 0, 1, 2, 5, 6, 9, 22, 30, 62, 58 }; -static GekkoOPTemplate table4[] = -{ //SUBOP10 - {0, &JitArm64::FallBackToInterpreter}, // ps_cmpu0 - {32, &JitArm64::FallBackToInterpreter}, // ps_cmpo0 - {40, &JitArm64::fp_logic}, // ps_neg - {136, &JitArm64::fp_logic}, // ps_nabs - {264, &JitArm64::fp_logic}, // ps_abs - {64, &JitArm64::FallBackToInterpreter}, // ps_cmpu1 - {72, &JitArm64::fp_logic}, // ps_mr - {96, &JitArm64::FallBackToInterpreter}, // ps_cmpo1 - {528, &JitArm64::ps_mergeXX}, // ps_merge00 - {560, &JitArm64::ps_mergeXX}, // ps_merge01 - {592, &JitArm64::ps_mergeXX}, // ps_merge10 - {624, &JitArm64::ps_mergeXX}, // ps_merge11 +static GekkoOPTemplate table4[] = { + // SUBOP10 + {0, &JitArm64::FallBackToInterpreter}, // ps_cmpu0 + {32, &JitArm64::FallBackToInterpreter}, // ps_cmpo0 + {40, &JitArm64::fp_logic}, // ps_neg + {136, &JitArm64::fp_logic}, // ps_nabs + {264, &JitArm64::fp_logic}, // ps_abs + {64, &JitArm64::FallBackToInterpreter}, // ps_cmpu1 + {72, &JitArm64::fp_logic}, // ps_mr + {96, &JitArm64::FallBackToInterpreter}, // ps_cmpo1 + {528, &JitArm64::ps_mergeXX}, // ps_merge00 + {560, &JitArm64::ps_mergeXX}, // ps_merge01 + {592, &JitArm64::ps_mergeXX}, // ps_merge10 + {624, &JitArm64::ps_mergeXX}, // ps_merge11 - {1014, &JitArm64::FallBackToInterpreter}, // dcbz_l + {1014, &JitArm64::FallBackToInterpreter}, // dcbz_l }; -static GekkoOPTemplate table4_2[] = -{ - {10, &JitArm64::ps_sumX}, // ps_sum0 - {11, &JitArm64::ps_sumX}, // ps_sum1 - {12, &JitArm64::ps_mulsX}, // ps_muls0 - {13, &JitArm64::ps_mulsX}, // ps_muls1 - {14, &JitArm64::ps_maddXX}, // ps_madds0 - {15, &JitArm64::ps_maddXX}, // ps_madds1 - {18, &JitArm64::fp_arith}, // ps_div - {20, &JitArm64::fp_arith}, // ps_sub - {21, &JitArm64::fp_arith}, // ps_add - {23, &JitArm64::ps_sel}, // ps_sel - {24, &JitArm64::ps_res}, // ps_res - {25, &JitArm64::fp_arith}, // ps_mul - {26, &JitArm64::FallBackToInterpreter}, // ps_rsqrte - {28, &JitArm64::ps_maddXX}, // ps_msub - {29, &JitArm64::ps_maddXX}, // ps_madd - {30, &JitArm64::ps_maddXX}, // ps_nmsub - {31, &JitArm64::ps_maddXX}, // ps_nmadd +static GekkoOPTemplate table4_2[] = { + {10, &JitArm64::ps_sumX}, // ps_sum0 + {11, &JitArm64::ps_sumX}, // ps_sum1 + {12, &JitArm64::ps_mulsX}, // ps_muls0 + {13, &JitArm64::ps_mulsX}, // ps_muls1 + {14, &JitArm64::ps_maddXX}, // ps_madds0 + {15, &JitArm64::ps_maddXX}, // ps_madds1 + {18, &JitArm64::fp_arith}, // ps_div + {20, &JitArm64::fp_arith}, // ps_sub + {21, &JitArm64::fp_arith}, // ps_add + {23, &JitArm64::ps_sel}, // ps_sel + {24, &JitArm64::ps_res}, // ps_res + {25, &JitArm64::fp_arith}, // ps_mul + {26, &JitArm64::FallBackToInterpreter}, // ps_rsqrte + {28, &JitArm64::ps_maddXX}, // ps_msub + {29, &JitArm64::ps_maddXX}, // ps_madd + {30, &JitArm64::ps_maddXX}, // ps_nmsub + {31, &JitArm64::ps_maddXX}, // ps_nmadd }; - -static GekkoOPTemplate table4_3[] = -{ - {6, &JitArm64::FallBackToInterpreter}, // psq_lx - {7, &JitArm64::FallBackToInterpreter}, // psq_stx - {38, &JitArm64::FallBackToInterpreter}, // psq_lux - {39, &JitArm64::FallBackToInterpreter}, // psq_stux +static GekkoOPTemplate table4_3[] = { + {6, &JitArm64::FallBackToInterpreter}, // psq_lx + {7, &JitArm64::FallBackToInterpreter}, // psq_stx + {38, &JitArm64::FallBackToInterpreter}, // psq_lux + {39, &JitArm64::FallBackToInterpreter}, // psq_stux }; -static GekkoOPTemplate table19[] = -{ - {528, &JitArm64::bcctrx}, // bcctrx - {16, &JitArm64::bclrx}, // bclrx - {257, &JitArm64::crXXX}, // crand - {129, &JitArm64::crXXX}, // crandc - {289, &JitArm64::crXXX}, // creqv - {225, &JitArm64::crXXX}, // crnand - {33, &JitArm64::crXXX}, // crnor - {449, &JitArm64::crXXX}, // cror - {417, &JitArm64::crXXX}, // crorc - {193, &JitArm64::crXXX}, // crxor +static GekkoOPTemplate table19[] = { + {528, &JitArm64::bcctrx}, // bcctrx + {16, &JitArm64::bclrx}, // bclrx + {257, &JitArm64::crXXX}, // crand + {129, &JitArm64::crXXX}, // crandc + {289, &JitArm64::crXXX}, // creqv + {225, &JitArm64::crXXX}, // crnand + {33, &JitArm64::crXXX}, // crnor + {449, &JitArm64::crXXX}, // cror + {417, &JitArm64::crXXX}, // crorc + {193, &JitArm64::crXXX}, // crxor - {150, &JitArm64::DoNothing}, // isync - {0, &JitArm64::mcrf}, // mcrf + {150, &JitArm64::DoNothing}, // isync + {0, &JitArm64::mcrf}, // mcrf - {50, &JitArm64::rfi}, // rfi + {50, &JitArm64::rfi}, // rfi }; +static GekkoOPTemplate table31[] = { + {266, &JitArm64::addx}, // addx + {778, &JitArm64::addx}, // addox + {10, &JitArm64::addcx}, // addcx + {522, &JitArm64::addcx}, // addcox + {138, &JitArm64::addex}, // addex + {650, &JitArm64::addex}, // addeox + {234, &JitArm64::FallBackToInterpreter}, // addmex + {746, &JitArm64::FallBackToInterpreter}, // addmeox + {202, &JitArm64::addzex}, // addzex + {714, &JitArm64::addzex}, // addzeox + {491, &JitArm64::FallBackToInterpreter}, // divwx + {1003, &JitArm64::FallBackToInterpreter}, // divwox + {459, &JitArm64::divwux}, // divwux + {971, &JitArm64::divwux}, // divwuox + {75, &JitArm64::mulhwx}, // mulhwx + {11, &JitArm64::mulhwux}, // mulhwux + {235, &JitArm64::mullwx}, // mullwx + {747, &JitArm64::mullwx}, // mullwox + {104, &JitArm64::negx}, // negx + {616, &JitArm64::negx}, // negox + {40, &JitArm64::subfx}, // subfx + {552, &JitArm64::subfx}, // subfox + {8, &JitArm64::subfcx}, // subfcx + {520, &JitArm64::subfcx}, // subfcox + {136, &JitArm64::subfex}, // subfex + {648, &JitArm64::subfex}, // subfeox + {232, &JitArm64::FallBackToInterpreter}, // subfmex + {744, &JitArm64::FallBackToInterpreter}, // subfmeox + {200, &JitArm64::FallBackToInterpreter}, // subfzex + {712, &JitArm64::FallBackToInterpreter}, // subfzeox -static GekkoOPTemplate table31[] = -{ - {266, &JitArm64::addx}, // addx - {778, &JitArm64::addx}, // addox - {10, &JitArm64::addcx}, // addcx - {522, &JitArm64::addcx}, // addcox - {138, &JitArm64::addex}, // addex - {650, &JitArm64::addex}, // addeox - {234, &JitArm64::FallBackToInterpreter}, // addmex - {746, &JitArm64::FallBackToInterpreter}, // addmeox - {202, &JitArm64::addzex}, // addzex - {714, &JitArm64::addzex}, // addzeox - {491, &JitArm64::FallBackToInterpreter}, // divwx - {1003, &JitArm64::FallBackToInterpreter}, // divwox - {459, &JitArm64::divwux}, // divwux - {971, &JitArm64::divwux}, // divwuox - {75, &JitArm64::mulhwx}, // mulhwx - {11, &JitArm64::mulhwux}, // mulhwux - {235, &JitArm64::mullwx}, // mullwx - {747, &JitArm64::mullwx}, // mullwox - {104, &JitArm64::negx}, // negx - {616, &JitArm64::negx}, // negox - {40, &JitArm64::subfx}, // subfx - {552, &JitArm64::subfx}, // subfox - {8, &JitArm64::subfcx}, // subfcx - {520, &JitArm64::subfcx}, // subfcox - {136, &JitArm64::subfex}, // subfex - {648, &JitArm64::subfex}, // subfeox - {232, &JitArm64::FallBackToInterpreter}, // subfmex - {744, &JitArm64::FallBackToInterpreter}, // subfmeox - {200, &JitArm64::FallBackToInterpreter}, // subfzex - {712, &JitArm64::FallBackToInterpreter}, // subfzeox + {28, &JitArm64::boolX}, // andx + {60, &JitArm64::boolX}, // andcx + {444, &JitArm64::boolX}, // orx + {124, &JitArm64::boolX}, // norx + {316, &JitArm64::boolX}, // xorx + {412, &JitArm64::boolX}, // orcx + {476, &JitArm64::boolX}, // nandx + {284, &JitArm64::boolX}, // eqvx + {0, &JitArm64::cmp}, // cmp + {32, &JitArm64::cmpl}, // cmpl + {26, &JitArm64::cntlzwx}, // cntlzwx + {922, &JitArm64::extsXx}, // extshx + {954, &JitArm64::extsXx}, // extsbx + {536, &JitArm64::srwx}, // srwx + {792, &JitArm64::FallBackToInterpreter}, // srawx + {824, &JitArm64::srawix}, // srawix + {24, &JitArm64::slwx}, // slwx - {28, &JitArm64::boolX}, // andx - {60, &JitArm64::boolX}, // andcx - {444, &JitArm64::boolX}, // orx - {124, &JitArm64::boolX}, // norx - {316, &JitArm64::boolX}, // xorx - {412, &JitArm64::boolX}, // orcx - {476, &JitArm64::boolX}, // nandx - {284, &JitArm64::boolX}, // eqvx - {0, &JitArm64::cmp}, // cmp - {32, &JitArm64::cmpl}, // cmpl - {26, &JitArm64::cntlzwx}, // cntlzwx - {922, &JitArm64::extsXx}, // extshx - {954, &JitArm64::extsXx}, // extsbx - {536, &JitArm64::srwx}, // srwx - {792, &JitArm64::FallBackToInterpreter}, // srawx - {824, &JitArm64::srawix}, // srawix - {24, &JitArm64::slwx}, // slwx + {54, &JitArm64::dcbx}, // dcbst + {86, &JitArm64::dcbx}, // dcbf + {246, &JitArm64::dcbt}, // dcbtst + {278, &JitArm64::dcbt}, // dcbt + {470, &JitArm64::dcbx}, // dcbi + {758, &JitArm64::DoNothing}, // dcba + {1014, &JitArm64::dcbz}, // dcbz - {54, &JitArm64::dcbx}, // dcbst - {86, &JitArm64::dcbx}, // dcbf - {246, &JitArm64::dcbt}, // dcbtst - {278, &JitArm64::dcbt}, // dcbt - {470, &JitArm64::dcbx}, // dcbi - {758, &JitArm64::DoNothing}, // dcba - {1014, &JitArm64::dcbz}, // dcbz + // load word + {23, &JitArm64::lXX}, // lwzx + {55, &JitArm64::lXX}, // lwzux - //load word - {23, &JitArm64::lXX}, // lwzx - {55, &JitArm64::lXX}, // lwzux + // load halfword + {279, &JitArm64::lXX}, // lhzx + {311, &JitArm64::lXX}, // lhzux - //load halfword - {279, &JitArm64::lXX}, // lhzx - {311, &JitArm64::lXX}, // lhzux + // load halfword signextend + {343, &JitArm64::lXX}, // lhax + {375, &JitArm64::lXX}, // lhaux - //load halfword signextend - {343, &JitArm64::lXX}, // lhax - {375, &JitArm64::lXX}, // lhaux + // load byte + {87, &JitArm64::lXX}, // lbzx + {119, &JitArm64::lXX}, // lbzux - //load byte - {87, &JitArm64::lXX}, // lbzx - {119, &JitArm64::lXX}, // lbzux + // load byte reverse + {534, &JitArm64::lXX}, // lwbrx + {790, &JitArm64::lXX}, // lhbrx - //load byte reverse - {534, &JitArm64::lXX}, // lwbrx - {790, &JitArm64::lXX}, // lhbrx + // Conditional load/store (Wii SMP) + {150, &JitArm64::FallBackToInterpreter}, // stwcxd + {20, &JitArm64::FallBackToInterpreter}, // lwarx - // Conditional load/store (Wii SMP) - {150, &JitArm64::FallBackToInterpreter}, // stwcxd - {20, &JitArm64::FallBackToInterpreter}, // lwarx + // load string (interpret these) + {533, &JitArm64::FallBackToInterpreter}, // lswx + {597, &JitArm64::FallBackToInterpreter}, // lswi - //load string (interpret these) - {533, &JitArm64::FallBackToInterpreter}, // lswx - {597, &JitArm64::FallBackToInterpreter}, // lswi + // store word + {151, &JitArm64::stX}, // stwx + {183, &JitArm64::stX}, // stwux - //store word - {151, &JitArm64::stX}, // stwx - {183, &JitArm64::stX}, // stwux + // store halfword + {407, &JitArm64::stX}, // sthx + {439, &JitArm64::stX}, // sthux - //store halfword - {407, &JitArm64::stX}, // sthx - {439, &JitArm64::stX}, // sthux + // store byte + {215, &JitArm64::stX}, // stbx + {247, &JitArm64::stX}, // stbux - //store byte - {215, &JitArm64::stX}, // stbx - {247, &JitArm64::stX}, // stbux + // store bytereverse + {662, &JitArm64::FallBackToInterpreter}, // stwbrx + {918, &JitArm64::FallBackToInterpreter}, // sthbrx - //store bytereverse - {662, &JitArm64::FallBackToInterpreter}, // stwbrx - {918, &JitArm64::FallBackToInterpreter}, // sthbrx + {661, &JitArm64::FallBackToInterpreter}, // stswx + {725, &JitArm64::FallBackToInterpreter}, // stswi - {661, &JitArm64::FallBackToInterpreter}, // stswx - {725, &JitArm64::FallBackToInterpreter}, // stswi + // fp load/store + {535, &JitArm64::lfXX}, // lfsx + {567, &JitArm64::lfXX}, // lfsux + {599, &JitArm64::lfXX}, // lfdx + {631, &JitArm64::lfXX}, // lfdux - // fp load/store - {535, &JitArm64::lfXX}, // lfsx - {567, &JitArm64::lfXX}, // lfsux - {599, &JitArm64::lfXX}, // lfdx - {631, &JitArm64::lfXX}, // lfdux + {663, &JitArm64::stfXX}, // stfsx + {695, &JitArm64::stfXX}, // stfsux + {727, &JitArm64::stfXX}, // stfdx + {759, &JitArm64::stfXX}, // stfdux + {983, &JitArm64::stfXX}, // stfiwx - {663, &JitArm64::stfXX}, // stfsx - {695, &JitArm64::stfXX}, // stfsux - {727, &JitArm64::stfXX}, // stfdx - {759, &JitArm64::stfXX}, // stfdux - {983, &JitArm64::stfXX}, // stfiwx + {19, &JitArm64::mfcr}, // mfcr + {83, &JitArm64::mfmsr}, // mfmsr + {144, &JitArm64::mtcrf}, // mtcrf + {146, &JitArm64::mtmsr}, // mtmsr + {210, &JitArm64::mtsr}, // mtsr + {242, &JitArm64::mtsrin}, // mtsrin + {339, &JitArm64::mfspr}, // mfspr + {467, &JitArm64::mtspr}, // mtspr + {371, &JitArm64::mftb}, // mftb + {512, &JitArm64::FallBackToInterpreter}, // mcrxr + {595, &JitArm64::mfsr}, // mfsr + {659, &JitArm64::mfsrin}, // mfsrin - {19, &JitArm64::mfcr}, // mfcr - {83, &JitArm64::mfmsr}, // mfmsr - {144, &JitArm64::mtcrf}, // mtcrf - {146, &JitArm64::mtmsr}, // mtmsr - {210, &JitArm64::mtsr}, // mtsr - {242, &JitArm64::mtsrin}, // mtsrin - {339, &JitArm64::mfspr}, // mfspr - {467, &JitArm64::mtspr}, // mtspr - {371, &JitArm64::mftb}, // mftb - {512, &JitArm64::FallBackToInterpreter}, // mcrxr - {595, &JitArm64::mfsr}, // mfsr - {659, &JitArm64::mfsrin}, // mfsrin + {4, &JitArm64::twx}, // tw + {598, &JitArm64::DoNothing}, // sync + {982, &JitArm64::FallBackToInterpreter}, // icbi - {4, &JitArm64::twx}, // tw - {598, &JitArm64::DoNothing}, // sync - {982, &JitArm64::FallBackToInterpreter}, // icbi - - // Unused instructions on GC - {310, &JitArm64::FallBackToInterpreter}, // eciwx - {438, &JitArm64::FallBackToInterpreter}, // ecowx - {854, &JitArm64::DoNothing}, // eieio - {306, &JitArm64::FallBackToInterpreter}, // tlbie - {566, &JitArm64::DoNothing}, // tlbsync + // Unused instructions on GC + {310, &JitArm64::FallBackToInterpreter}, // eciwx + {438, &JitArm64::FallBackToInterpreter}, // ecowx + {854, &JitArm64::DoNothing}, // eieio + {306, &JitArm64::FallBackToInterpreter}, // tlbie + {566, &JitArm64::DoNothing}, // tlbsync }; -static GekkoOPTemplate table59[] = -{ - {18, &JitArm64::fp_arith}, // fdivsx - {20, &JitArm64::fp_arith}, // fsubsx - {21, &JitArm64::fp_arith}, // faddsx - {24, &JitArm64::FallBackToInterpreter}, // fresx - {25, &JitArm64::fp_arith}, // fmulsx - {28, &JitArm64::fp_arith}, // fmsubsx - {29, &JitArm64::fp_arith}, // fmaddsx - {30, &JitArm64::fp_arith}, // fnmsubsx - {31, &JitArm64::fp_arith}, // fnmaddsx +static GekkoOPTemplate table59[] = { + {18, &JitArm64::fp_arith}, // fdivsx + {20, &JitArm64::fp_arith}, // fsubsx + {21, &JitArm64::fp_arith}, // faddsx + {24, &JitArm64::FallBackToInterpreter}, // fresx + {25, &JitArm64::fp_arith}, // fmulsx + {28, &JitArm64::fp_arith}, // fmsubsx + {29, &JitArm64::fp_arith}, // fmaddsx + {30, &JitArm64::fp_arith}, // fnmsubsx + {31, &JitArm64::fp_arith}, // fnmaddsx }; -static GekkoOPTemplate table63[] = -{ - {264, &JitArm64::fp_logic}, // fabsx - {32, &JitArm64::fcmpX}, // fcmpo - {0, &JitArm64::fcmpX}, // fcmpu - {14, &JitArm64::FallBackToInterpreter}, // fctiwx - {15, &JitArm64::fctiwzx}, // fctiwzx - {72, &JitArm64::fp_logic}, // fmrx - {136, &JitArm64::fp_logic}, // fnabsx - {40, &JitArm64::fp_logic}, // fnegx - {12, &JitArm64::frspx}, // frspx +static GekkoOPTemplate table63[] = { + {264, &JitArm64::fp_logic}, // fabsx + {32, &JitArm64::fcmpX}, // fcmpo + {0, &JitArm64::fcmpX}, // fcmpu + {14, &JitArm64::FallBackToInterpreter}, // fctiwx + {15, &JitArm64::fctiwzx}, // fctiwzx + {72, &JitArm64::fp_logic}, // fmrx + {136, &JitArm64::fp_logic}, // fnabsx + {40, &JitArm64::fp_logic}, // fnegx + {12, &JitArm64::frspx}, // frspx - {64, &JitArm64::FallBackToInterpreter}, // mcrfs - {583, &JitArm64::FallBackToInterpreter}, // mffsx - {70, &JitArm64::FallBackToInterpreter}, // mtfsb0x - {38, &JitArm64::FallBackToInterpreter}, // mtfsb1x - {134, &JitArm64::FallBackToInterpreter}, // mtfsfix - {711, &JitArm64::FallBackToInterpreter}, // mtfsfx + {64, &JitArm64::FallBackToInterpreter}, // mcrfs + {583, &JitArm64::FallBackToInterpreter}, // mffsx + {70, &JitArm64::FallBackToInterpreter}, // mtfsb0x + {38, &JitArm64::FallBackToInterpreter}, // mtfsb1x + {134, &JitArm64::FallBackToInterpreter}, // mtfsfix + {711, &JitArm64::FallBackToInterpreter}, // mtfsfx }; -static GekkoOPTemplate table63_2[] = -{ - {18, &JitArm64::fp_arith}, // fdivx - {20, &JitArm64::fp_arith}, // fsubx - {21, &JitArm64::fp_arith}, // faddx - {23, &JitArm64::fselx}, // fselx - {25, &JitArm64::fp_arith}, // fmulx - {26, &JitArm64::FallBackToInterpreter}, // frsqrtex - {28, &JitArm64::fp_arith}, // fmsubx - {29, &JitArm64::fp_arith}, // fmaddx - {30, &JitArm64::fp_arith}, // fnmsubx - {31, &JitArm64::fp_arith}, // fnmaddx +static GekkoOPTemplate table63_2[] = { + {18, &JitArm64::fp_arith}, // fdivx + {20, &JitArm64::fp_arith}, // fsubx + {21, &JitArm64::fp_arith}, // faddx + {23, &JitArm64::fselx}, // fselx + {25, &JitArm64::fp_arith}, // fmulx + {26, &JitArm64::FallBackToInterpreter}, // frsqrtex + {28, &JitArm64::fp_arith}, // fmsubx + {29, &JitArm64::fp_arith}, // fmaddx + {30, &JitArm64::fp_arith}, // fnmsubx + {31, &JitArm64::fp_arith}, // fnmaddx }; - namespace JitArm64Tables { - -void CompileInstruction(PPCAnalyst::CodeOp & op) +void CompileInstruction(PPCAnalyst::CodeOp& op) { - JitArm64 *jitarm = (JitArm64 *)jit; - (jitarm->*dynaOpTable[op.inst.OPCD])(op.inst); - GekkoOPInfo *info = op.opinfo; - if (info) - { + JitArm64* jitarm = (JitArm64*)jit; + (jitarm->*dynaOpTable[op.inst.OPCD])(op.inst); + GekkoOPInfo* info = op.opinfo; + if (info) + { #ifdef OPLOG - if (!strcmp(info->opname, OP_TO_LOG)){ ///"mcrfs" - rsplocations.push_back(jit.js.compilerPC); - } + if (!strcmp(info->opname, OP_TO_LOG)) + { ///"mcrfs" + rsplocations.push_back(jit.js.compilerPC); + } #endif - info->compileCount++; - info->lastUse = jit->js.compilerPC; - } + info->compileCount++; + info->lastUse = jit->js.compilerPC; + } } void InitTables() { - // once initialized, tables are read-only - static bool initialized = false; - if (initialized) - return; + // once initialized, tables are read-only + static bool initialized = false; + if (initialized) + return; - //clear - for (auto& tpl : dynaOpTable) - { - tpl = &JitArm64::FallBackToInterpreter; - } + // clear + for (auto& tpl : dynaOpTable) + { + tpl = &JitArm64::FallBackToInterpreter; + } - for (int i = 0; i < 32; i++) - { - dynaOpTable59[i] = &JitArm64::FallBackToInterpreter; - } + for (int i = 0; i < 32; i++) + { + dynaOpTable59[i] = &JitArm64::FallBackToInterpreter; + } - for (int i = 0; i < 1024; i++) - { - dynaOpTable4 [i] = &JitArm64::FallBackToInterpreter; - dynaOpTable19[i] = &JitArm64::FallBackToInterpreter; - dynaOpTable31[i] = &JitArm64::FallBackToInterpreter; - dynaOpTable63[i] = &JitArm64::FallBackToInterpreter; - } + for (int i = 0; i < 1024; i++) + { + dynaOpTable4[i] = &JitArm64::FallBackToInterpreter; + dynaOpTable19[i] = &JitArm64::FallBackToInterpreter; + dynaOpTable31[i] = &JitArm64::FallBackToInterpreter; + dynaOpTable63[i] = &JitArm64::FallBackToInterpreter; + } - for (int i = 0; i < (int)(sizeof(primarytable) / sizeof(GekkoOPTemplate)); i++) - { - dynaOpTable[primarytable[i].opcode] = primarytable[i].Inst; - } + for (int i = 0; i < (int)(sizeof(primarytable) / sizeof(GekkoOPTemplate)); i++) + { + dynaOpTable[primarytable[i].opcode] = primarytable[i].Inst; + } - for (int i = 0; i < 32; i++) - { - int fill = i << 5; - for (int j = 0; j < (int)(sizeof(table4_2) / sizeof(GekkoOPTemplate)); j++) - { - int op = fill+table4_2[j].opcode; - dynaOpTable4[op] = table4_2[j].Inst; - } - } + for (int i = 0; i < 32; i++) + { + int fill = i << 5; + for (int j = 0; j < (int)(sizeof(table4_2) / sizeof(GekkoOPTemplate)); j++) + { + int op = fill + table4_2[j].opcode; + dynaOpTable4[op] = table4_2[j].Inst; + } + } - for (int i = 0; i < 16; i++) - { - int fill = i << 6; - for (int j = 0; j < (int)(sizeof(table4_3) / sizeof(GekkoOPTemplate)); j++) - { - int op = fill+table4_3[j].opcode; - dynaOpTable4[op] = table4_3[j].Inst; - } - } + for (int i = 0; i < 16; i++) + { + int fill = i << 6; + for (int j = 0; j < (int)(sizeof(table4_3) / sizeof(GekkoOPTemplate)); j++) + { + int op = fill + table4_3[j].opcode; + dynaOpTable4[op] = table4_3[j].Inst; + } + } - for (int i = 0; i < (int)(sizeof(table4) / sizeof(GekkoOPTemplate)); i++) - { - int op = table4[i].opcode; - dynaOpTable4[op] = table4[i].Inst; - } + for (int i = 0; i < (int)(sizeof(table4) / sizeof(GekkoOPTemplate)); i++) + { + int op = table4[i].opcode; + dynaOpTable4[op] = table4[i].Inst; + } - for (int i = 0; i < (int)(sizeof(table31) / sizeof(GekkoOPTemplate)); i++) - { - int op = table31[i].opcode; - dynaOpTable31[op] = table31[i].Inst; - } + for (int i = 0; i < (int)(sizeof(table31) / sizeof(GekkoOPTemplate)); i++) + { + int op = table31[i].opcode; + dynaOpTable31[op] = table31[i].Inst; + } - for (int i = 0; i < (int)(sizeof(table19) / sizeof(GekkoOPTemplate)); i++) - { - int op = table19[i].opcode; - dynaOpTable19[op] = table19[i].Inst; - } + for (int i = 0; i < (int)(sizeof(table19) / sizeof(GekkoOPTemplate)); i++) + { + int op = table19[i].opcode; + dynaOpTable19[op] = table19[i].Inst; + } - for (int i = 0; i < (int)(sizeof(table59) / sizeof(GekkoOPTemplate)); i++) - { - int op = table59[i].opcode; - dynaOpTable59[op] = table59[i].Inst; - } + for (int i = 0; i < (int)(sizeof(table59) / sizeof(GekkoOPTemplate)); i++) + { + int op = table59[i].opcode; + dynaOpTable59[op] = table59[i].Inst; + } - for (int i = 0; i < (int)(sizeof(table63) / sizeof(GekkoOPTemplate)); i++) - { - int op = table63[i].opcode; - dynaOpTable63[op] = table63[i].Inst; - } + for (int i = 0; i < (int)(sizeof(table63) / sizeof(GekkoOPTemplate)); i++) + { + int op = table63[i].opcode; + dynaOpTable63[op] = table63[i].Inst; + } - for (int i = 0; i < 32; i++) - { - int fill = i << 5; - for (int j = 0; j < (int)(sizeof(table63_2) / sizeof(GekkoOPTemplate)); j++) - { - int op = fill + table63_2[j].opcode; - dynaOpTable63[op] = table63_2[j].Inst; - } - } - - initialized = true; + for (int i = 0; i < 32; i++) + { + int fill = i << 5; + for (int j = 0; j < (int)(sizeof(table63_2) / sizeof(GekkoOPTemplate)); j++) + { + int op = fill + table63_2[j].opcode; + dynaOpTable63[op] = table63_2[j].Inst; + } + } + initialized = true; } } // namespace diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.h b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.h index a00c14e075..c92f789a38 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.h +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.h @@ -9,6 +9,6 @@ namespace JitArm64Tables { - void CompileInstruction(PPCAnalyst::CodeOp & op); - void InitTables(); +void CompileInstruction(PPCAnalyst::CodeOp& op); +void InitTables(); } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp b/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp index d9948ac00d..2626ee42f4 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/JitArm64/Jit.h" #include "Common/Arm64Emitter.h" #include "Common/CommonTypes.h" #include "Common/JitRegister.h" @@ -9,637 +10,628 @@ #include "Core/CoreTiming.h" #include "Core/HW/CPU.h" #include "Core/HW/Memmap.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/JitArm64/Jit.h" #include "Core/PowerPC/JitCommon/JitAsmCommon.h" #include "Core/PowerPC/JitCommon/JitCache.h" +#include "Core/PowerPC/PowerPC.h" using namespace Arm64Gen; void JitArm64::GenerateAsm() { - // This value is all of the callee saved registers that we are required to save. - // According to the AACPS64 we need to save R19 ~ R30. - const u32 ALL_CALLEE_SAVED = 0x7FF80000; - BitSet32 regs_to_save(ALL_CALLEE_SAVED); - enterCode = GetCodePtr(); + // This value is all of the callee saved registers that we are required to save. + // According to the AACPS64 we need to save R19 ~ R30. + const u32 ALL_CALLEE_SAVED = 0x7FF80000; + BitSet32 regs_to_save(ALL_CALLEE_SAVED); + enterCode = GetCodePtr(); - ABI_PushRegisters(regs_to_save); + ABI_PushRegisters(regs_to_save); - MOVI2R(PPC_REG, (u64)&PowerPC::ppcState); - MOVI2R(MEM_REG, (u64)Memory::logical_base); + MOVI2R(PPC_REG, (u64)&PowerPC::ppcState); + MOVI2R(MEM_REG, (u64)Memory::logical_base); - // Load the current PC into DISPATCHER_PC - LDR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); + // Load the current PC into DISPATCHER_PC + LDR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); - FixupBranch to_dispatcher = B(); + FixupBranch to_dispatcher = B(); - // If we align the dispatcher to a page then we can load its location with one ADRP instruction - AlignCodePage(); - dispatcher = GetCodePtr(); - WARN_LOG(DYNA_REC, "Dispatcher is %p\n", dispatcher); + // If we align the dispatcher to a page then we can load its location with one ADRP instruction + AlignCodePage(); + dispatcher = GetCodePtr(); + WARN_LOG(DYNA_REC, "Dispatcher is %p\n", dispatcher); - SetJumpTarget(to_dispatcher); + SetJumpTarget(to_dispatcher); - // Downcount Check - // The result of slice decrementation should be in flags if somebody jumped here - // IMPORTANT - We jump on negative, not carry!!! - FixupBranch bail = B(CC_MI); + // Downcount Check + // The result of slice decrementation should be in flags if somebody jumped here + // IMPORTANT - We jump on negative, not carry!!! + FixupBranch bail = B(CC_MI); - dispatcherNoCheck = GetCodePtr(); + dispatcherNoCheck = GetCodePtr(); - FixupBranch exram, vmem, not_exram, not_vmem; - ARM64Reg pc_masked = W25; - ARM64Reg cache_base = X27; + FixupBranch exram, vmem, not_exram, not_vmem; + ARM64Reg pc_masked = W25; + ARM64Reg cache_base = X27; - // VMEM - not_vmem = TBZ(DISPATCHER_PC, IntLog2(JIT_ICACHE_VMEM_BIT)); - ANDI2R(pc_masked, DISPATCHER_PC, JIT_ICACHE_MASK); - MOVI2R(cache_base, (u64)jit->GetBlockCache()->iCacheVMEM.data()); - vmem = B(); - SetJumpTarget(not_vmem); + // VMEM + not_vmem = TBZ(DISPATCHER_PC, IntLog2(JIT_ICACHE_VMEM_BIT)); + ANDI2R(pc_masked, DISPATCHER_PC, JIT_ICACHE_MASK); + MOVI2R(cache_base, (u64)jit->GetBlockCache()->iCacheVMEM.data()); + vmem = B(); + SetJumpTarget(not_vmem); - if (SConfig::GetInstance().bWii) - { - // Wii EX-RAM - not_exram = TBZ(DISPATCHER_PC, IntLog2(JIT_ICACHE_EXRAM_BIT)); - ANDI2R(pc_masked, DISPATCHER_PC, JIT_ICACHEEX_MASK); - MOVI2R(cache_base, (u64)jit->GetBlockCache()->iCacheEx.data()); - exram = B(); - SetJumpTarget(not_exram); - } + if (SConfig::GetInstance().bWii) + { + // Wii EX-RAM + not_exram = TBZ(DISPATCHER_PC, IntLog2(JIT_ICACHE_EXRAM_BIT)); + ANDI2R(pc_masked, DISPATCHER_PC, JIT_ICACHEEX_MASK); + MOVI2R(cache_base, (u64)jit->GetBlockCache()->iCacheEx.data()); + exram = B(); + SetJumpTarget(not_exram); + } - // Common memory - ANDI2R(pc_masked, DISPATCHER_PC, JIT_ICACHE_MASK); - MOVI2R(cache_base, (u64)jit->GetBlockCache()->iCache.data()); + // Common memory + ANDI2R(pc_masked, DISPATCHER_PC, JIT_ICACHE_MASK); + MOVI2R(cache_base, (u64)jit->GetBlockCache()->iCache.data()); - SetJumpTarget(vmem); - if (SConfig::GetInstance().bWii) - SetJumpTarget(exram); + SetJumpTarget(vmem); + if (SConfig::GetInstance().bWii) + SetJumpTarget(exram); - LDR(W27, cache_base, EncodeRegTo64(pc_masked)); + LDR(W27, cache_base, EncodeRegTo64(pc_masked)); - FixupBranch JitBlock = TBNZ(W27, 7); // Test the 7th bit - // Success, it is our Jitblock. - MOVI2R(X30, (u64)jit->GetBlockCache()->GetCodePointers()); - UBFM(X27, X27, 61, 60); // Same as X27 << 3 - LDR(X30, X30, X27); // Load the block address in to R14 - BR(X30); - // No need to jump anywhere after here, the block will go back to dispatcher start + FixupBranch JitBlock = TBNZ(W27, 7); // Test the 7th bit + // Success, it is our Jitblock. + MOVI2R(X30, (u64)jit->GetBlockCache()->GetCodePointers()); + UBFM(X27, X27, 61, 60); // Same as X27 << 3 + LDR(X30, X30, X27); // Load the block address in to R14 + BR(X30); + // No need to jump anywhere after here, the block will go back to dispatcher start - SetJumpTarget(JitBlock); + SetJumpTarget(JitBlock); - STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); - MOVI2R(X30, (u64)&::Jit); - BLR(X30); + STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); + MOVI2R(X30, (u64) & ::Jit); + BLR(X30); - LDR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); + LDR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); - B(dispatcherNoCheck); + B(dispatcherNoCheck); - SetJumpTarget(bail); - doTiming = GetCodePtr(); - // Write the current PC out to PPCSTATE - STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); - STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(npc)); + SetJumpTarget(bail); + doTiming = GetCodePtr(); + // Write the current PC out to PPCSTATE + STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); + STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(npc)); - MOVI2R(X30, (u64)&CoreTiming::Advance); - BLR(X30); + MOVI2R(X30, (u64)&CoreTiming::Advance); + BLR(X30); - // Load the PC back into DISPATCHER_PC (the exception handler might have changed it) - LDR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); + // Load the PC back into DISPATCHER_PC (the exception handler might have changed it) + LDR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); - // Check the state pointer to see if we are exiting - // Gets checked on at the end of every slice - MOVI2R(X0, (u64)CPU::GetStatePtr()); - LDR(INDEX_UNSIGNED, W0, X0, 0); + // Check the state pointer to see if we are exiting + // Gets checked on at the end of every slice + MOVI2R(X0, (u64)CPU::GetStatePtr()); + LDR(INDEX_UNSIGNED, W0, X0, 0); - CMP(W0, 0); - FixupBranch Exit = B(CC_NEQ); + CMP(W0, 0); + FixupBranch Exit = B(CC_NEQ); - B(dispatcher); + B(dispatcher); - SetJumpTarget(Exit); - STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); + SetJumpTarget(Exit); + STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); - ABI_PopRegisters(regs_to_save); - RET(X30); + ABI_PopRegisters(regs_to_save); + RET(X30); - JitRegister::Register(enterCode, GetCodePtr(), "JIT_Dispatcher"); + JitRegister::Register(enterCode, GetCodePtr(), "JIT_Dispatcher"); - GenerateCommonAsm(); + GenerateCommonAsm(); - FlushIcache(); + FlushIcache(); } void JitArm64::GenerateCommonAsm() { - // X0 is the scale - // X1 is address - // X2 is a temporary on stores - // X30 is LR - // Q0 is the return for loads - // is the register for stores - // Q1 is a temporary - ARM64Reg addr_reg = X1; - ARM64Reg scale_reg = X0; - ARM64FloatEmitter float_emit(this); + // X0 is the scale + // X1 is address + // X2 is a temporary on stores + // X30 is LR + // Q0 is the return for loads + // is the register for stores + // Q1 is a temporary + ARM64Reg addr_reg = X1; + ARM64Reg scale_reg = X0; + ARM64FloatEmitter float_emit(this); - const u8* start = GetCodePtr(); - const u8* loadPairedIllegal = GetCodePtr(); - BRK(100); - const u8* loadPairedFloatTwo = GetCodePtr(); - { - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.LD1(32, 1, D0, addr_reg); - float_emit.REV32(8, D0, D0); - RET(X30); - } - const u8* loadPairedU8Two = GetCodePtr(); - { - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0); - float_emit.UXTL(8, D0, D0); - float_emit.UXTL(16, D0, D0); - float_emit.UCVTF(32, D0, D0); + const u8* start = GetCodePtr(); + const u8* loadPairedIllegal = GetCodePtr(); + BRK(100); + const u8* loadPairedFloatTwo = GetCodePtr(); + { + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.LD1(32, 1, D0, addr_reg); + float_emit.REV32(8, D0, D0); + RET(X30); + } + const u8* loadPairedU8Two = GetCodePtr(); + { + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0); + float_emit.UXTL(8, D0, D0); + float_emit.UXTL(16, D0, D0); + float_emit.UCVTF(32, D0, D0); - MOVI2R(addr_reg, (u64)&m_dequantizeTableS); - ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1, 0); - RET(X30); - } - const u8* loadPairedS8Two = GetCodePtr(); - { - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0); - float_emit.SXTL(8, D0, D0); - float_emit.SXTL(16, D0, D0); - float_emit.SCVTF(32, D0, D0); + MOVI2R(addr_reg, (u64)&m_dequantizeTableS); + ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1, 0); + RET(X30); + } + const u8* loadPairedS8Two = GetCodePtr(); + { + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0); + float_emit.SXTL(8, D0, D0); + float_emit.SXTL(16, D0, D0); + float_emit.SCVTF(32, D0, D0); - MOVI2R(addr_reg, (u64)&m_dequantizeTableS); - ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1, 0); - RET(X30); - } - const u8* loadPairedU16Two = GetCodePtr(); - { - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.LD1(16, 1, D0, addr_reg); - float_emit.REV16(8, D0, D0); - float_emit.UXTL(16, D0, D0); - float_emit.UCVTF(32, D0, D0); + MOVI2R(addr_reg, (u64)&m_dequantizeTableS); + ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1, 0); + RET(X30); + } + const u8* loadPairedU16Two = GetCodePtr(); + { + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.LD1(16, 1, D0, addr_reg); + float_emit.REV16(8, D0, D0); + float_emit.UXTL(16, D0, D0); + float_emit.UCVTF(32, D0, D0); - MOVI2R(addr_reg, (u64)&m_dequantizeTableS); - ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1, 0); - RET(X30); - } - const u8* loadPairedS16Two = GetCodePtr(); - { - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.LD1(16, 1, D0, addr_reg); - float_emit.REV16(8, D0, D0); - float_emit.SXTL(16, D0, D0); - float_emit.SCVTF(32, D0, D0); + MOVI2R(addr_reg, (u64)&m_dequantizeTableS); + ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1, 0); + RET(X30); + } + const u8* loadPairedS16Two = GetCodePtr(); + { + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.LD1(16, 1, D0, addr_reg); + float_emit.REV16(8, D0, D0); + float_emit.SXTL(16, D0, D0); + float_emit.SCVTF(32, D0, D0); - MOVI2R(addr_reg, (u64)&m_dequantizeTableS); - ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1, 0); - RET(X30); - } + MOVI2R(addr_reg, (u64)&m_dequantizeTableS); + ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1, 0); + RET(X30); + } - const u8* loadPairedFloatOne = GetCodePtr(); - { - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.LDR(32, INDEX_UNSIGNED, D0, addr_reg, 0); - float_emit.REV32(8, D0, D0); - RET(X30); - } - const u8* loadPairedU8One = GetCodePtr(); - { - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.LDR(8, INDEX_UNSIGNED, D0, addr_reg, 0); - float_emit.UXTL(8, D0, D0); - float_emit.UXTL(16, D0, D0); - float_emit.UCVTF(32, D0, D0); + const u8* loadPairedFloatOne = GetCodePtr(); + { + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.LDR(32, INDEX_UNSIGNED, D0, addr_reg, 0); + float_emit.REV32(8, D0, D0); + RET(X30); + } + const u8* loadPairedU8One = GetCodePtr(); + { + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.LDR(8, INDEX_UNSIGNED, D0, addr_reg, 0); + float_emit.UXTL(8, D0, D0); + float_emit.UXTL(16, D0, D0); + float_emit.UCVTF(32, D0, D0); - MOVI2R(addr_reg, (u64)&m_dequantizeTableS); - ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1, 0); - RET(X30); - } - const u8* loadPairedS8One = GetCodePtr(); - { - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.LDR(8, INDEX_UNSIGNED, D0, addr_reg, 0); - float_emit.SXTL(8, D0, D0); - float_emit.SXTL(16, D0, D0); - float_emit.SCVTF(32, D0, D0); + MOVI2R(addr_reg, (u64)&m_dequantizeTableS); + ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1, 0); + RET(X30); + } + const u8* loadPairedS8One = GetCodePtr(); + { + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.LDR(8, INDEX_UNSIGNED, D0, addr_reg, 0); + float_emit.SXTL(8, D0, D0); + float_emit.SXTL(16, D0, D0); + float_emit.SCVTF(32, D0, D0); - MOVI2R(addr_reg, (u64)&m_dequantizeTableS); - ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1, 0); - RET(X30); - } - const u8* loadPairedU16One = GetCodePtr(); - { - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0); - float_emit.REV16(8, D0, D0); - float_emit.UXTL(16, D0, D0); - float_emit.UCVTF(32, D0, D0); + MOVI2R(addr_reg, (u64)&m_dequantizeTableS); + ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1, 0); + RET(X30); + } + const u8* loadPairedU16One = GetCodePtr(); + { + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0); + float_emit.REV16(8, D0, D0); + float_emit.UXTL(16, D0, D0); + float_emit.UCVTF(32, D0, D0); - MOVI2R(addr_reg, (u64)&m_dequantizeTableS); - ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1, 0); - RET(X30); - } - const u8* loadPairedS16One = GetCodePtr(); - { - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0); - float_emit.REV16(8, D0, D0); - float_emit.SXTL(16, D0, D0); - float_emit.SCVTF(32, D0, D0); + MOVI2R(addr_reg, (u64)&m_dequantizeTableS); + ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1, 0); + RET(X30); + } + const u8* loadPairedS16One = GetCodePtr(); + { + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0); + float_emit.REV16(8, D0, D0); + float_emit.SXTL(16, D0, D0); + float_emit.SCVTF(32, D0, D0); - MOVI2R(addr_reg, (u64)&m_dequantizeTableS); - ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1, 0); - RET(X30); - } + MOVI2R(addr_reg, (u64)&m_dequantizeTableS); + ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1, 0); + RET(X30); + } - JitRegister::Register(start, GetCodePtr(), "JIT_QuantizedLoad"); + JitRegister::Register(start, GetCodePtr(), "JIT_QuantizedLoad"); - pairedLoadQuantized = reinterpret_cast(const_cast(AlignCode16())); - ReserveCodeSpace(16 * sizeof(u8*)); + pairedLoadQuantized = reinterpret_cast(const_cast(AlignCode16())); + ReserveCodeSpace(16 * sizeof(u8*)); - pairedLoadQuantized[0] = loadPairedFloatTwo; - pairedLoadQuantized[1] = loadPairedIllegal; - pairedLoadQuantized[2] = loadPairedIllegal; - pairedLoadQuantized[3] = loadPairedIllegal; - pairedLoadQuantized[4] = loadPairedU8Two; - pairedLoadQuantized[5] = loadPairedU16Two; - pairedLoadQuantized[6] = loadPairedS8Two; - pairedLoadQuantized[7] = loadPairedS16Two; + pairedLoadQuantized[0] = loadPairedFloatTwo; + pairedLoadQuantized[1] = loadPairedIllegal; + pairedLoadQuantized[2] = loadPairedIllegal; + pairedLoadQuantized[3] = loadPairedIllegal; + pairedLoadQuantized[4] = loadPairedU8Two; + pairedLoadQuantized[5] = loadPairedU16Two; + pairedLoadQuantized[6] = loadPairedS8Two; + pairedLoadQuantized[7] = loadPairedS16Two; - pairedLoadQuantized[8] = loadPairedFloatOne; - pairedLoadQuantized[9] = loadPairedIllegal; - pairedLoadQuantized[10] = loadPairedIllegal; - pairedLoadQuantized[11] = loadPairedIllegal; - pairedLoadQuantized[12] = loadPairedU8One; - pairedLoadQuantized[13] = loadPairedU16One; - pairedLoadQuantized[14] = loadPairedS8One; - pairedLoadQuantized[15] = loadPairedS16One; + pairedLoadQuantized[8] = loadPairedFloatOne; + pairedLoadQuantized[9] = loadPairedIllegal; + pairedLoadQuantized[10] = loadPairedIllegal; + pairedLoadQuantized[11] = loadPairedIllegal; + pairedLoadQuantized[12] = loadPairedU8One; + pairedLoadQuantized[13] = loadPairedU16One; + pairedLoadQuantized[14] = loadPairedS8One; + pairedLoadQuantized[15] = loadPairedS16One; - // Stores - start = GetCodePtr(); - const u8* storePairedIllegal = GetCodePtr(); - BRK(0x101); - const u8* storePairedFloat; - const u8* storePairedFloatSlow; - { - storePairedFloat = GetCodePtr(); - float_emit.REV32(8, D0, D0); - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.ST1(64, Q0, 0, addr_reg, SP); - RET(X30); + // Stores + start = GetCodePtr(); + const u8* storePairedIllegal = GetCodePtr(); + BRK(0x101); + const u8* storePairedFloat; + const u8* storePairedFloatSlow; + { + storePairedFloat = GetCodePtr(); + float_emit.REV32(8, D0, D0); + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.ST1(64, Q0, 0, addr_reg, SP); + RET(X30); - storePairedFloatSlow = GetCodePtr(); - float_emit.UMOV(64, X0, Q0, 0); - ORR(X0, SP, X0, ArithOption(X0, ST_ROR, 32)); - MOVI2R(X2, (u64)PowerPC::Write_U64); - BR(X2); - } + storePairedFloatSlow = GetCodePtr(); + float_emit.UMOV(64, X0, Q0, 0); + ORR(X0, SP, X0, ArithOption(X0, ST_ROR, 32)); + MOVI2R(X2, (u64)PowerPC::Write_U64); + BR(X2); + } - const u8* storePairedU8; - const u8* storePairedU8Slow; - { - auto emit_quantize = [this, &float_emit, scale_reg]() - { - MOVI2R(X2, (u64)&m_quantizeTableS); - ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1, 0); + const u8* storePairedU8; + const u8* storePairedU8Slow; + { + auto emit_quantize = [this, &float_emit, scale_reg]() { + MOVI2R(X2, (u64)&m_quantizeTableS); + ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1, 0); - float_emit.FCVTZU(32, D0, D0); - float_emit.UQXTN(16, D0, D0); - float_emit.UQXTN(8, D0, D0); - }; + float_emit.FCVTZU(32, D0, D0); + float_emit.UQXTN(16, D0, D0); + float_emit.UQXTN(8, D0, D0); + }; - storePairedU8 = GetCodePtr(); - emit_quantize(); - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.ST1(16, Q0, 0, addr_reg, SP); - RET(X30); + storePairedU8 = GetCodePtr(); + emit_quantize(); + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.ST1(16, Q0, 0, addr_reg, SP); + RET(X30); - storePairedU8Slow = GetCodePtr(); - emit_quantize(); - float_emit.UMOV(16, W0, Q0, 0); - REV16(W0, W0); - MOVI2R(X2, (u64)PowerPC::Write_U16); - BR(X2); - } - const u8* storePairedS8; - const u8* storePairedS8Slow; - { - auto emit_quantize = [this, &float_emit, scale_reg]() - { - MOVI2R(X2, (u64)&m_quantizeTableS); - ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1, 0); + storePairedU8Slow = GetCodePtr(); + emit_quantize(); + float_emit.UMOV(16, W0, Q0, 0); + REV16(W0, W0); + MOVI2R(X2, (u64)PowerPC::Write_U16); + BR(X2); + } + const u8* storePairedS8; + const u8* storePairedS8Slow; + { + auto emit_quantize = [this, &float_emit, scale_reg]() { + MOVI2R(X2, (u64)&m_quantizeTableS); + ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1, 0); - float_emit.FCVTZS(32, D0, D0); - float_emit.SQXTN(16, D0, D0); - float_emit.SQXTN(8, D0, D0); - }; + float_emit.FCVTZS(32, D0, D0); + float_emit.SQXTN(16, D0, D0); + float_emit.SQXTN(8, D0, D0); + }; - storePairedS8 = GetCodePtr(); - emit_quantize(); - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.ST1(16, Q0, 0, addr_reg, SP); - RET(X30); + storePairedS8 = GetCodePtr(); + emit_quantize(); + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.ST1(16, Q0, 0, addr_reg, SP); + RET(X30); - storePairedS8Slow = GetCodePtr(); - emit_quantize(); - float_emit.UMOV(16, W0, Q0, 0); - REV16(W0, W0); - MOVI2R(X2, (u64)PowerPC::Write_U16); - BR(X2); - } + storePairedS8Slow = GetCodePtr(); + emit_quantize(); + float_emit.UMOV(16, W0, Q0, 0); + REV16(W0, W0); + MOVI2R(X2, (u64)PowerPC::Write_U16); + BR(X2); + } - const u8* storePairedU16; - const u8* storePairedU16Slow; - { - auto emit_quantize = [this, &float_emit, scale_reg]() - { - MOVI2R(X2, (u64)&m_quantizeTableS); - ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1, 0); + const u8* storePairedU16; + const u8* storePairedU16Slow; + { + auto emit_quantize = [this, &float_emit, scale_reg]() { + MOVI2R(X2, (u64)&m_quantizeTableS); + ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1, 0); - float_emit.FCVTZU(32, D0, D0); - float_emit.UQXTN(16, D0, D0); - float_emit.REV16(8, D0, D0); - }; + float_emit.FCVTZU(32, D0, D0); + float_emit.UQXTN(16, D0, D0); + float_emit.REV16(8, D0, D0); + }; - storePairedU16 = GetCodePtr(); - emit_quantize(); - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.ST1(32, Q0, 0, addr_reg, SP); - RET(X30); + storePairedU16 = GetCodePtr(); + emit_quantize(); + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.ST1(32, Q0, 0, addr_reg, SP); + RET(X30); - storePairedU16Slow = GetCodePtr(); - emit_quantize(); - float_emit.REV32(8, D0, D0); - float_emit.UMOV(32, W0, Q0, 0); - MOVI2R(X2, (u64)PowerPC::Write_U32); - BR(X2); - } - const u8* storePairedS16; // Used by Viewtiful Joe's intro movie - const u8* storePairedS16Slow; - { - auto emit_quantize = [this, &float_emit, scale_reg]() - { - MOVI2R(X2, (u64)&m_quantizeTableS); - ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1, 0); + storePairedU16Slow = GetCodePtr(); + emit_quantize(); + float_emit.REV32(8, D0, D0); + float_emit.UMOV(32, W0, Q0, 0); + MOVI2R(X2, (u64)PowerPC::Write_U32); + BR(X2); + } + const u8* storePairedS16; // Used by Viewtiful Joe's intro movie + const u8* storePairedS16Slow; + { + auto emit_quantize = [this, &float_emit, scale_reg]() { + MOVI2R(X2, (u64)&m_quantizeTableS); + ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1, 0); - float_emit.FCVTZS(32, D0, D0); - float_emit.SQXTN(16, D0, D0); - float_emit.REV16(8, D0, D0); - }; + float_emit.FCVTZS(32, D0, D0); + float_emit.SQXTN(16, D0, D0); + float_emit.REV16(8, D0, D0); + }; - storePairedS16 = GetCodePtr(); - emit_quantize(); - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.ST1(32, Q0, 0, addr_reg, SP); - RET(X30); + storePairedS16 = GetCodePtr(); + emit_quantize(); + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.ST1(32, Q0, 0, addr_reg, SP); + RET(X30); - storePairedS16Slow = GetCodePtr(); - emit_quantize(); - float_emit.REV32(8, D0, D0); - float_emit.UMOV(32, W0, Q0, 0); - MOVI2R(X2, (u64)PowerPC::Write_U32); - BR(X2); - } + storePairedS16Slow = GetCodePtr(); + emit_quantize(); + float_emit.REV32(8, D0, D0); + float_emit.UMOV(32, W0, Q0, 0); + MOVI2R(X2, (u64)PowerPC::Write_U32); + BR(X2); + } - const u8* storeSingleFloat; - const u8* storeSingleFloatSlow; - { - storeSingleFloat = GetCodePtr(); - float_emit.REV32(8, D0, D0); - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.STR(32, INDEX_UNSIGNED, D0, addr_reg, 0); - RET(X30); + const u8* storeSingleFloat; + const u8* storeSingleFloatSlow; + { + storeSingleFloat = GetCodePtr(); + float_emit.REV32(8, D0, D0); + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.STR(32, INDEX_UNSIGNED, D0, addr_reg, 0); + RET(X30); - storeSingleFloatSlow = GetCodePtr(); - float_emit.UMOV(32, W0, Q0, 0); - MOVI2R(X2, (u64)&PowerPC::Write_U32); - BR(X2); - } - const u8* storeSingleU8; // Used by MKWii - const u8* storeSingleU8Slow; - { - auto emit_quantize = [this, &float_emit, scale_reg]() - { - MOVI2R(X2, (u64)&m_quantizeTableS); - ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1); + storeSingleFloatSlow = GetCodePtr(); + float_emit.UMOV(32, W0, Q0, 0); + MOVI2R(X2, (u64)&PowerPC::Write_U32); + BR(X2); + } + const u8* storeSingleU8; // Used by MKWii + const u8* storeSingleU8Slow; + { + auto emit_quantize = [this, &float_emit, scale_reg]() { + MOVI2R(X2, (u64)&m_quantizeTableS); + ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1); - float_emit.FCVTZU(32, D0, D0); - float_emit.UQXTN(16, D0, D0); - float_emit.UQXTN(8, D0, D0); - }; + float_emit.FCVTZU(32, D0, D0); + float_emit.UQXTN(16, D0, D0); + float_emit.UQXTN(8, D0, D0); + }; - storeSingleU8 = GetCodePtr(); - emit_quantize(); - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.ST1(8, Q0, 0, addr_reg); - RET(X30); + storeSingleU8 = GetCodePtr(); + emit_quantize(); + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.ST1(8, Q0, 0, addr_reg); + RET(X30); - storeSingleU8Slow = GetCodePtr(); - emit_quantize(); - float_emit.UMOV(8, W0, Q0, 0); - MOVI2R(X2, (u64)&PowerPC::Write_U8); - BR(X2); - } - const u8* storeSingleS8; - const u8* storeSingleS8Slow; - { - auto emit_quantize = [this, &float_emit, scale_reg]() - { - MOVI2R(X2, (u64)&m_quantizeTableS); - ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1); + storeSingleU8Slow = GetCodePtr(); + emit_quantize(); + float_emit.UMOV(8, W0, Q0, 0); + MOVI2R(X2, (u64)&PowerPC::Write_U8); + BR(X2); + } + const u8* storeSingleS8; + const u8* storeSingleS8Slow; + { + auto emit_quantize = [this, &float_emit, scale_reg]() { + MOVI2R(X2, (u64)&m_quantizeTableS); + ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1); - float_emit.FCVTZS(32, D0, D0); - float_emit.SQXTN(16, D0, D0); - float_emit.SQXTN(8, D0, D0); - }; + float_emit.FCVTZS(32, D0, D0); + float_emit.SQXTN(16, D0, D0); + float_emit.SQXTN(8, D0, D0); + }; - storeSingleS8 = GetCodePtr(); - emit_quantize(); - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.ST1(8, Q0, 0, addr_reg); - RET(X30); + storeSingleS8 = GetCodePtr(); + emit_quantize(); + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.ST1(8, Q0, 0, addr_reg); + RET(X30); - storeSingleS8Slow = GetCodePtr(); - emit_quantize(); - float_emit.SMOV(8, W0, Q0, 0); - MOVI2R(X2, (u64)&PowerPC::Write_U8); - BR(X2); - } - const u8* storeSingleU16; // Used by MKWii - const u8* storeSingleU16Slow; - { - auto emit_quantize = [this, &float_emit, scale_reg]() - { - MOVI2R(X2, (u64)&m_quantizeTableS); - ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1); + storeSingleS8Slow = GetCodePtr(); + emit_quantize(); + float_emit.SMOV(8, W0, Q0, 0); + MOVI2R(X2, (u64)&PowerPC::Write_U8); + BR(X2); + } + const u8* storeSingleU16; // Used by MKWii + const u8* storeSingleU16Slow; + { + auto emit_quantize = [this, &float_emit, scale_reg]() { + MOVI2R(X2, (u64)&m_quantizeTableS); + ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1); - float_emit.FCVTZU(32, D0, D0); - float_emit.UQXTN(16, D0, D0); - }; + float_emit.FCVTZU(32, D0, D0); + float_emit.UQXTN(16, D0, D0); + }; - storeSingleU16 = GetCodePtr(); - emit_quantize(); - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.REV16(8, D0, D0); - float_emit.ST1(16, Q0, 0, addr_reg); - RET(X30); + storeSingleU16 = GetCodePtr(); + emit_quantize(); + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.REV16(8, D0, D0); + float_emit.ST1(16, Q0, 0, addr_reg); + RET(X30); - storeSingleU16Slow = GetCodePtr(); - emit_quantize(); - float_emit.UMOV(16, W0, Q0, 0); - MOVI2R(X2, (u64)&PowerPC::Write_U16); - BR(X2); - } - const u8* storeSingleS16; - const u8* storeSingleS16Slow; - { - auto emit_quantize = [this, &float_emit, scale_reg]() - { - MOVI2R(X2, (u64)&m_quantizeTableS); - ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); - float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); - float_emit.FMUL(32, D0, D0, D1); + storeSingleU16Slow = GetCodePtr(); + emit_quantize(); + float_emit.UMOV(16, W0, Q0, 0); + MOVI2R(X2, (u64)&PowerPC::Write_U16); + BR(X2); + } + const u8* storeSingleS16; + const u8* storeSingleS16Slow; + { + auto emit_quantize = [this, &float_emit, scale_reg]() { + MOVI2R(X2, (u64)&m_quantizeTableS); + ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3)); + float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0); + float_emit.FMUL(32, D0, D0, D1); - float_emit.FCVTZS(32, D0, D0); - float_emit.SQXTN(16, D0, D0); - }; + float_emit.FCVTZS(32, D0, D0); + float_emit.SQXTN(16, D0, D0); + }; - storeSingleS16 = GetCodePtr(); - emit_quantize(); - MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); - float_emit.REV16(8, D0, D0); - float_emit.ST1(16, Q0, 0, addr_reg); - RET(X30); + storeSingleS16 = GetCodePtr(); + emit_quantize(); + MOVK(addr_reg, ((u64)Memory::logical_base >> 32) & 0xFFFF, SHIFT_32); + float_emit.REV16(8, D0, D0); + float_emit.ST1(16, Q0, 0, addr_reg); + RET(X30); - storeSingleS16Slow = GetCodePtr(); - emit_quantize(); - float_emit.SMOV(16, W0, Q0, 0); - MOVI2R(X2, (u64)&PowerPC::Write_U16); - BR(X2); - } + storeSingleS16Slow = GetCodePtr(); + emit_quantize(); + float_emit.SMOV(16, W0, Q0, 0); + MOVI2R(X2, (u64)&PowerPC::Write_U16); + BR(X2); + } - JitRegister::Register(start, GetCodePtr(), "JIT_QuantizedStore"); + JitRegister::Register(start, GetCodePtr(), "JIT_QuantizedStore"); - pairedStoreQuantized = reinterpret_cast(const_cast(AlignCode16())); - ReserveCodeSpace(32 * sizeof(u8*)); + pairedStoreQuantized = reinterpret_cast(const_cast(AlignCode16())); + ReserveCodeSpace(32 * sizeof(u8*)); - // Fast - pairedStoreQuantized[0] = storePairedFloat; - pairedStoreQuantized[1] = storePairedIllegal; - pairedStoreQuantized[2] = storePairedIllegal; - pairedStoreQuantized[3] = storePairedIllegal; - pairedStoreQuantized[4] = storePairedU8; - pairedStoreQuantized[5] = storePairedU16; - pairedStoreQuantized[6] = storePairedS8; - pairedStoreQuantized[7] = storePairedS16; + // Fast + pairedStoreQuantized[0] = storePairedFloat; + pairedStoreQuantized[1] = storePairedIllegal; + pairedStoreQuantized[2] = storePairedIllegal; + pairedStoreQuantized[3] = storePairedIllegal; + pairedStoreQuantized[4] = storePairedU8; + pairedStoreQuantized[5] = storePairedU16; + pairedStoreQuantized[6] = storePairedS8; + pairedStoreQuantized[7] = storePairedS16; - pairedStoreQuantized[8] = storeSingleFloat; - pairedStoreQuantized[9] = storePairedIllegal; - pairedStoreQuantized[10] = storePairedIllegal; - pairedStoreQuantized[11] = storePairedIllegal; - pairedStoreQuantized[12] = storeSingleU8; - pairedStoreQuantized[13] = storeSingleU16; - pairedStoreQuantized[14] = storeSingleS8; - pairedStoreQuantized[15] = storeSingleS16; + pairedStoreQuantized[8] = storeSingleFloat; + pairedStoreQuantized[9] = storePairedIllegal; + pairedStoreQuantized[10] = storePairedIllegal; + pairedStoreQuantized[11] = storePairedIllegal; + pairedStoreQuantized[12] = storeSingleU8; + pairedStoreQuantized[13] = storeSingleU16; + pairedStoreQuantized[14] = storeSingleS8; + pairedStoreQuantized[15] = storeSingleS16; - // Slow - pairedStoreQuantized[16] = storePairedFloatSlow; - pairedStoreQuantized[17] = storePairedIllegal; - pairedStoreQuantized[18] = storePairedIllegal; - pairedStoreQuantized[19] = storePairedIllegal; - pairedStoreQuantized[20] = storePairedU8Slow; - pairedStoreQuantized[21] = storePairedU16Slow; - pairedStoreQuantized[22] = storePairedS8Slow; - pairedStoreQuantized[23] = storePairedS16Slow; + // Slow + pairedStoreQuantized[16] = storePairedFloatSlow; + pairedStoreQuantized[17] = storePairedIllegal; + pairedStoreQuantized[18] = storePairedIllegal; + pairedStoreQuantized[19] = storePairedIllegal; + pairedStoreQuantized[20] = storePairedU8Slow; + pairedStoreQuantized[21] = storePairedU16Slow; + pairedStoreQuantized[22] = storePairedS8Slow; + pairedStoreQuantized[23] = storePairedS16Slow; - pairedStoreQuantized[24] = storeSingleFloatSlow; - pairedStoreQuantized[25] = storePairedIllegal; - pairedStoreQuantized[26] = storePairedIllegal; - pairedStoreQuantized[27] = storePairedIllegal; - pairedStoreQuantized[28] = storeSingleU8Slow; - pairedStoreQuantized[29] = storeSingleU16Slow; - pairedStoreQuantized[30] = storeSingleS8Slow; - pairedStoreQuantized[31] = storeSingleS16Slow; + pairedStoreQuantized[24] = storeSingleFloatSlow; + pairedStoreQuantized[25] = storePairedIllegal; + pairedStoreQuantized[26] = storePairedIllegal; + pairedStoreQuantized[27] = storePairedIllegal; + pairedStoreQuantized[28] = storeSingleU8Slow; + pairedStoreQuantized[29] = storeSingleU16Slow; + pairedStoreQuantized[30] = storeSingleS8Slow; + pairedStoreQuantized[31] = storeSingleS16Slow; - GetAsmRoutines()->mfcr = AlignCode16(); - GenMfcr(); + GetAsmRoutines()->mfcr = AlignCode16(); + GenMfcr(); } void JitArm64::GenMfcr() { - // Input: Nothing - // Returns: W0 - // Clobbers: X1, X2 - const u8* start = GetCodePtr(); - for (int i = 0; i < 8; i++) - { - LDR(INDEX_UNSIGNED, X1, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * i); + // Input: Nothing + // Returns: W0 + // Clobbers: X1, X2 + const u8* start = GetCodePtr(); + for (int i = 0; i < 8; i++) + { + LDR(INDEX_UNSIGNED, X1, PPC_REG, PPCSTATE_OFF(cr_val) + 8 * i); - // SO - if (i == 0) - { - UBFX(X0, X1, 61, 1); - } - else - { - ORR(W0, WZR, W0, ArithOption(W0, ST_LSL, 4)); - UBFX(X2, X1, 61, 1); - ORR(X0, X0, X2); - } + // SO + if (i == 0) + { + UBFX(X0, X1, 61, 1); + } + else + { + ORR(W0, WZR, W0, ArithOption(W0, ST_LSL, 4)); + UBFX(X2, X1, 61, 1); + ORR(X0, X0, X2); + } - // EQ - ORR(W2, W0, 32 - 1, 0); // W0 | 1<<1 - CMP(W1, WZR); - CSEL(W0, W2, W0, CC_EQ); + // EQ + ORR(W2, W0, 32 - 1, 0); // W0 | 1<<1 + CMP(W1, WZR); + CSEL(W0, W2, W0, CC_EQ); - // GT - ORR(W2, W0, 32 - 2, 0); // W0 | 1<<2 - CMP(X1, ZR); - CSEL(W0, W2, W0, CC_GT); + // GT + ORR(W2, W0, 32 - 2, 0); // W0 | 1<<2 + CMP(X1, ZR); + CSEL(W0, W2, W0, CC_GT); - // LT - UBFX(X2, X1, 62, 1); - ORR(W0, W0, W2, ArithOption(W2, ST_LSL, 3)); - } + // LT + UBFX(X2, X1, 62, 1); + ORR(W0, W0, W2, ArithOption(W2, ST_LSL, 3)); + } - RET(X30); - JitRegister::Register(start, GetCodePtr(), "JIT_Mfcr"); + RET(X30); + JitRegister::Register(start, GetCodePtr(), "JIT_Mfcr"); } diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit_Util.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit_Util.cpp index 60ea797498..ea5ab0998f 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit_Util.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit_Util.cpp @@ -13,236 +13,223 @@ template class MMIOWriteCodeGenerator : public MMIO::WriteHandlingMethodVisitor { public: - MMIOWriteCodeGenerator(ARM64XEmitter* emit, BitSet32 gprs_in_use, BitSet32 fprs_in_use, - ARM64Reg src_reg, u32 address) - : m_emit(emit), m_gprs_in_use(gprs_in_use), m_fprs_in_use(fprs_in_use), - m_src_reg(src_reg), m_address(address) - { - } + MMIOWriteCodeGenerator(ARM64XEmitter* emit, BitSet32 gprs_in_use, BitSet32 fprs_in_use, + ARM64Reg src_reg, u32 address) + : m_emit(emit), m_gprs_in_use(gprs_in_use), m_fprs_in_use(fprs_in_use), m_src_reg(src_reg), + m_address(address) + { + } - virtual void VisitNop() - { - // Do nothing - } - virtual void VisitDirect(T* addr, u32 mask) - { - WriteRegToAddr(8 * sizeof (T), addr, mask); - } - virtual void VisitComplex(const std::function* lambda) - { - CallLambda(8 * sizeof (T), lambda); - } + virtual void VisitNop() + { + // Do nothing + } + virtual void VisitDirect(T* addr, u32 mask) { WriteRegToAddr(8 * sizeof(T), addr, mask); } + virtual void VisitComplex(const std::function* lambda) + { + CallLambda(8 * sizeof(T), lambda); + } private: + void StoreFromRegister(int sbits, ARM64Reg reg) + { + switch (sbits) + { + case 8: + m_emit->STRB(INDEX_UNSIGNED, reg, X0, 0); + break; + case 16: + m_emit->STRH(INDEX_UNSIGNED, reg, X0, 0); + break; + case 32: + m_emit->STR(INDEX_UNSIGNED, reg, X0, 0); + break; + default: + _assert_msg_(DYNA_REC, false, "Unknown size %d passed to MMIOWriteCodeGenerator!", sbits); + break; + } + } - void StoreFromRegister(int sbits, ARM64Reg reg) - { - switch (sbits) - { - case 8: - m_emit->STRB(INDEX_UNSIGNED, reg, X0, 0); - break; - case 16: - m_emit->STRH(INDEX_UNSIGNED, reg, X0, 0); - break; - case 32: - m_emit->STR(INDEX_UNSIGNED, reg, X0, 0); - break; - default: - _assert_msg_(DYNA_REC, false, "Unknown size %d passed to MMIOWriteCodeGenerator!", sbits); - break; - } - } + void WriteRegToAddr(int sbits, const void* ptr, u32 mask) + { + m_emit->MOVI2R(X0, (u64)ptr); - void WriteRegToAddr(int sbits, const void* ptr, u32 mask) - { - m_emit->MOVI2R(X0, (u64)ptr); + // If we do not need to mask, we can do the sign extend while loading + // from memory. If masking is required, we have to first zero extend, + // then mask, then sign extend if needed (1 instr vs. ~4). + u32 all_ones = (1ULL << sbits) - 1; + if ((all_ones & mask) == all_ones) + { + StoreFromRegister(sbits, m_src_reg); + } + else + { + m_emit->MOVI2R(W1, mask); + m_emit->AND(W1, m_src_reg, W1, ArithOption(W1, ST_LSL, 0)); + StoreFromRegister(sbits, W1); + } + } - // If we do not need to mask, we can do the sign extend while loading - // from memory. If masking is required, we have to first zero extend, - // then mask, then sign extend if needed (1 instr vs. ~4). - u32 all_ones = (1ULL << sbits) - 1; - if ((all_ones & mask) == all_ones) - { - StoreFromRegister(sbits, m_src_reg); - } - else - { - m_emit->MOVI2R(W1, mask); - m_emit->AND(W1, m_src_reg, W1, ArithOption(W1, ST_LSL, 0)); - StoreFromRegister(sbits, W1); - } - } + void CallLambda(int sbits, const std::function* lambda) + { + ARM64FloatEmitter float_emit(m_emit); - void CallLambda(int sbits, const std::function* lambda) - { - ARM64FloatEmitter float_emit(m_emit); + m_emit->ABI_PushRegisters(m_gprs_in_use); + float_emit.ABI_PushRegisters(m_fprs_in_use, X1); + m_emit->MOVI2R(W1, m_address); + m_emit->MOV(W2, m_src_reg); + m_emit->BLR(m_emit->ABI_SetupLambda(lambda)); + float_emit.ABI_PopRegisters(m_fprs_in_use, X1); + m_emit->ABI_PopRegisters(m_gprs_in_use); + } - m_emit->ABI_PushRegisters(m_gprs_in_use); - float_emit.ABI_PushRegisters(m_fprs_in_use, X1); - m_emit->MOVI2R(W1, m_address); - m_emit->MOV(W2, m_src_reg); - m_emit->BLR(m_emit->ABI_SetupLambda(lambda)); - float_emit.ABI_PopRegisters(m_fprs_in_use, X1); - m_emit->ABI_PopRegisters(m_gprs_in_use); - } - - ARM64XEmitter* m_emit; - BitSet32 m_gprs_in_use; - BitSet32 m_fprs_in_use; - ARM64Reg m_src_reg; - u32 m_address; + ARM64XEmitter* m_emit; + BitSet32 m_gprs_in_use; + BitSet32 m_fprs_in_use; + ARM64Reg m_src_reg; + u32 m_address; }; // Visitor that generates code to read a MMIO value. template class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor { public: - MMIOReadCodeGenerator(ARM64XEmitter* emit, BitSet32 gprs_in_use, BitSet32 fprs_in_use, - ARM64Reg dst_reg, u32 address, bool sign_extend) - : m_emit(emit), m_gprs_in_use(gprs_in_use), m_fprs_in_use(fprs_in_use), - m_dst_reg(dst_reg), m_address(address), m_sign_extend(sign_extend) - { - } + MMIOReadCodeGenerator(ARM64XEmitter* emit, BitSet32 gprs_in_use, BitSet32 fprs_in_use, + ARM64Reg dst_reg, u32 address, bool sign_extend) + : m_emit(emit), m_gprs_in_use(gprs_in_use), m_fprs_in_use(fprs_in_use), m_dst_reg(dst_reg), + m_address(address), m_sign_extend(sign_extend) + { + } - virtual void VisitConstant(T value) - { - LoadConstantToReg(8 * sizeof (T), value); - } - virtual void VisitDirect(const T* addr, u32 mask) - { - LoadAddrMaskToReg(8 * sizeof (T), addr, mask); - } - virtual void VisitComplex(const std::function* lambda) - { - CallLambda(8 * sizeof (T), lambda); - } + virtual void VisitConstant(T value) { LoadConstantToReg(8 * sizeof(T), value); } + virtual void VisitDirect(const T* addr, u32 mask) + { + LoadAddrMaskToReg(8 * sizeof(T), addr, mask); + } + virtual void VisitComplex(const std::function* lambda) + { + CallLambda(8 * sizeof(T), lambda); + } private: + void LoadConstantToReg(int sbits, u32 value) + { + m_emit->MOVI2R(m_dst_reg, value); + if (m_sign_extend) + m_emit->SBFM(m_dst_reg, m_dst_reg, 0, sbits - 1); + } - void LoadConstantToReg(int sbits, u32 value) - { - m_emit->MOVI2R(m_dst_reg, value); - if (m_sign_extend) - m_emit->SBFM(m_dst_reg, m_dst_reg, 0, sbits - 1); - } + void LoadToRegister(int sbits, bool dont_extend) + { + switch (sbits) + { + case 8: + if (m_sign_extend && !dont_extend) + m_emit->LDRSB(INDEX_UNSIGNED, m_dst_reg, X0, 0); + else + m_emit->LDRB(INDEX_UNSIGNED, m_dst_reg, X0, 0); + break; + case 16: + if (m_sign_extend && !dont_extend) + m_emit->LDRSH(INDEX_UNSIGNED, m_dst_reg, X0, 0); + else + m_emit->LDRH(INDEX_UNSIGNED, m_dst_reg, X0, 0); + break; + case 32: + m_emit->LDR(INDEX_UNSIGNED, m_dst_reg, X0, 0); + break; + default: + _assert_msg_(DYNA_REC, false, "Unknown size %d passed to MMIOReadCodeGenerator!", sbits); + break; + } + } - void LoadToRegister(int sbits, bool dont_extend) - { - switch (sbits) - { - case 8: - if (m_sign_extend && !dont_extend) - m_emit->LDRSB(INDEX_UNSIGNED, m_dst_reg, X0, 0); - else - m_emit->LDRB(INDEX_UNSIGNED, m_dst_reg, X0, 0); - break; - case 16: - if (m_sign_extend && !dont_extend) - m_emit->LDRSH(INDEX_UNSIGNED, m_dst_reg, X0, 0); - else - m_emit->LDRH(INDEX_UNSIGNED, m_dst_reg, X0, 0); - break; - case 32: - m_emit->LDR(INDEX_UNSIGNED, m_dst_reg, X0, 0); - break; - default: - _assert_msg_(DYNA_REC, false, "Unknown size %d passed to MMIOReadCodeGenerator!", sbits); - break; - } - } + void LoadAddrMaskToReg(int sbits, const void* ptr, u32 mask) + { + m_emit->MOVI2R(X0, (u64)ptr); - void LoadAddrMaskToReg(int sbits, const void* ptr, u32 mask) - { - m_emit->MOVI2R(X0, (u64)ptr); + // If we do not need to mask, we can do the sign extend while loading + // from memory. If masking is required, we have to first zero extend, + // then mask, then sign extend if needed (1 instr vs. ~4). + u32 all_ones = (1ULL << sbits) - 1; + if ((all_ones & mask) == all_ones) + { + LoadToRegister(sbits, false); + } + else + { + LoadToRegister(sbits, true); + m_emit->MOVI2R(W0, mask); + m_emit->AND(m_dst_reg, m_dst_reg, W0, ArithOption(W0, ST_LSL, 0)); + if (m_sign_extend) + m_emit->SBFM(m_dst_reg, m_dst_reg, 0, sbits - 1); + } + } - // If we do not need to mask, we can do the sign extend while loading - // from memory. If masking is required, we have to first zero extend, - // then mask, then sign extend if needed (1 instr vs. ~4). - u32 all_ones = (1ULL << sbits) - 1; - if ((all_ones & mask) == all_ones) - { - LoadToRegister(sbits, false); - } - else - { - LoadToRegister(sbits, true); - m_emit->MOVI2R(W0, mask); - m_emit->AND(m_dst_reg, m_dst_reg, W0, ArithOption(W0, ST_LSL, 0)); - if (m_sign_extend) - m_emit->SBFM(m_dst_reg, m_dst_reg, 0, sbits - 1); - } - } + void CallLambda(int sbits, const std::function* lambda) + { + ARM64FloatEmitter float_emit(m_emit); - void CallLambda(int sbits, const std::function* lambda) - { - ARM64FloatEmitter float_emit(m_emit); + m_emit->ABI_PushRegisters(m_gprs_in_use); + float_emit.ABI_PushRegisters(m_fprs_in_use, X1); + m_emit->MOVI2R(W1, m_address); + m_emit->BLR(m_emit->ABI_SetupLambda(lambda)); + float_emit.ABI_PopRegisters(m_fprs_in_use, X1); + m_emit->ABI_PopRegisters(m_gprs_in_use); - m_emit->ABI_PushRegisters(m_gprs_in_use); - float_emit.ABI_PushRegisters(m_fprs_in_use, X1); - m_emit->MOVI2R(W1, m_address); - m_emit->BLR(m_emit->ABI_SetupLambda(lambda)); - float_emit.ABI_PopRegisters(m_fprs_in_use, X1); - m_emit->ABI_PopRegisters(m_gprs_in_use); + if (m_sign_extend) + m_emit->SBFM(m_dst_reg, W0, 0, sbits - 1); + else + m_emit->UBFM(m_dst_reg, W0, 0, sbits - 1); + } - if (m_sign_extend) - m_emit->SBFM(m_dst_reg, W0, 0, sbits - 1); - else - m_emit->UBFM(m_dst_reg, W0, 0, sbits - 1); - } - - ARM64XEmitter* m_emit; - BitSet32 m_gprs_in_use; - BitSet32 m_fprs_in_use; - ARM64Reg m_dst_reg; - u32 m_address; - bool m_sign_extend; + ARM64XEmitter* m_emit; + BitSet32 m_gprs_in_use; + BitSet32 m_fprs_in_use; + ARM64Reg m_dst_reg; + u32 m_address; + bool m_sign_extend; }; -void MMIOLoadToReg(MMIO::Mapping* mmio, Arm64Gen::ARM64XEmitter* emit, - BitSet32 gprs_in_use, BitSet32 fprs_in_use, - ARM64Reg dst_reg, u32 address, u32 flags) +void MMIOLoadToReg(MMIO::Mapping* mmio, Arm64Gen::ARM64XEmitter* emit, BitSet32 gprs_in_use, + BitSet32 fprs_in_use, ARM64Reg dst_reg, u32 address, u32 flags) { - if (flags & BackPatchInfo::FLAG_SIZE_8) - { - MMIOReadCodeGenerator gen(emit, gprs_in_use, fprs_in_use, dst_reg, - address, flags & BackPatchInfo::FLAG_EXTEND); - mmio->GetHandlerForRead(address).Visit(gen); - } - else if (flags & BackPatchInfo::FLAG_SIZE_16) - { - MMIOReadCodeGenerator gen(emit, gprs_in_use, fprs_in_use, dst_reg, - address, flags & BackPatchInfo::FLAG_EXTEND); - mmio->GetHandlerForRead(address).Visit(gen); - } - else if (flags & BackPatchInfo::FLAG_SIZE_32) - { - MMIOReadCodeGenerator gen(emit, gprs_in_use, fprs_in_use, dst_reg, - address, flags & BackPatchInfo::FLAG_EXTEND); - mmio->GetHandlerForRead(address).Visit(gen); - } + if (flags & BackPatchInfo::FLAG_SIZE_8) + { + MMIOReadCodeGenerator gen(emit, gprs_in_use, fprs_in_use, dst_reg, address, + flags & BackPatchInfo::FLAG_EXTEND); + mmio->GetHandlerForRead(address).Visit(gen); + } + else if (flags & BackPatchInfo::FLAG_SIZE_16) + { + MMIOReadCodeGenerator gen(emit, gprs_in_use, fprs_in_use, dst_reg, address, + flags & BackPatchInfo::FLAG_EXTEND); + mmio->GetHandlerForRead(address).Visit(gen); + } + else if (flags & BackPatchInfo::FLAG_SIZE_32) + { + MMIOReadCodeGenerator gen(emit, gprs_in_use, fprs_in_use, dst_reg, address, + flags & BackPatchInfo::FLAG_EXTEND); + mmio->GetHandlerForRead(address).Visit(gen); + } } -void MMIOWriteRegToAddr(MMIO::Mapping* mmio, Arm64Gen::ARM64XEmitter* emit, - BitSet32 gprs_in_use, BitSet32 fprs_in_use, - ARM64Reg src_reg, u32 address, u32 flags) +void MMIOWriteRegToAddr(MMIO::Mapping* mmio, Arm64Gen::ARM64XEmitter* emit, BitSet32 gprs_in_use, + BitSet32 fprs_in_use, ARM64Reg src_reg, u32 address, u32 flags) { - if (flags & BackPatchInfo::FLAG_SIZE_8) - { - MMIOWriteCodeGenerator gen(emit, gprs_in_use, fprs_in_use, src_reg, - address); - mmio->GetHandlerForWrite(address).Visit(gen); - } - else if (flags & BackPatchInfo::FLAG_SIZE_16) - { - MMIOWriteCodeGenerator gen(emit, gprs_in_use, fprs_in_use, src_reg, - address); - mmio->GetHandlerForWrite(address).Visit(gen); - } - else if (flags & BackPatchInfo::FLAG_SIZE_32) - { - MMIOWriteCodeGenerator gen(emit, gprs_in_use, fprs_in_use, src_reg, - address); - mmio->GetHandlerForWrite(address).Visit(gen); - } + if (flags & BackPatchInfo::FLAG_SIZE_8) + { + MMIOWriteCodeGenerator gen(emit, gprs_in_use, fprs_in_use, src_reg, address); + mmio->GetHandlerForWrite(address).Visit(gen); + } + else if (flags & BackPatchInfo::FLAG_SIZE_16) + { + MMIOWriteCodeGenerator gen(emit, gprs_in_use, fprs_in_use, src_reg, address); + mmio->GetHandlerForWrite(address).Visit(gen); + } + else if (flags & BackPatchInfo::FLAG_SIZE_32) + { + MMIOWriteCodeGenerator gen(emit, gprs_in_use, fprs_in_use, src_reg, address); + mmio->GetHandlerForWrite(address).Visit(gen); + } } diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit_Util.h b/Source/Core/Core/PowerPC/JitArm64/Jit_Util.h index f1d257836b..5545eb9349 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit_Util.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit_Util.h @@ -9,10 +9,8 @@ #include "Core/HW/MMIO.h" -void MMIOLoadToReg(MMIO::Mapping* mmio, Arm64Gen::ARM64XEmitter* emit, - BitSet32 gprs_in_use, BitSet32 fprs_in_use, - ARM64Reg dst_reg, u32 address, u32 flags); +void MMIOLoadToReg(MMIO::Mapping* mmio, Arm64Gen::ARM64XEmitter* emit, BitSet32 gprs_in_use, + BitSet32 fprs_in_use, ARM64Reg dst_reg, u32 address, u32 flags); -void MMIOWriteRegToAddr(MMIO::Mapping* mmio, Arm64Gen::ARM64XEmitter* emit, - BitSet32 gprs_in_use, BitSet32 fprs_in_use, - ARM64Reg src_reg, u32 address, u32 flags); +void MMIOWriteRegToAddr(MMIO::Mapping* mmio, Arm64Gen::ARM64XEmitter* emit, BitSet32 gprs_in_use, + BitSet32 fprs_in_use, ARM64Reg src_reg, u32 address, u32 flags); diff --git a/Source/Core/Core/PowerPC/JitArmCommon/BackPatch.h b/Source/Core/Core/PowerPC/JitArmCommon/BackPatch.h index 4e9f7ca199..58833eb687 100644 --- a/Source/Core/Core/PowerPC/JitArmCommon/BackPatch.h +++ b/Source/Core/Core/PowerPC/JitArmCommon/BackPatch.h @@ -7,42 +7,39 @@ struct BackPatchInfo { - enum - { - FLAG_STORE = (1 << 0), - FLAG_LOAD = (1 << 1), - FLAG_SIZE_8 = (1 << 2), - FLAG_SIZE_16 = (1 << 3), - FLAG_SIZE_32 = (1 << 4), - FLAG_SIZE_F32 = (1 << 5), - FLAG_SIZE_F32X2 = (1 << 6), - FLAG_SIZE_F32X2I = (1 << 7), - FLAG_SIZE_F64 = (1 << 8), - FLAG_REVERSE = (1 << 9), - FLAG_EXTEND = (1 << 10), - FLAG_SIZE_F32I = (1 << 11), - FLAG_ZERO_256 = (1 << 12), - FLAG_MASK_FLOAT = FLAG_SIZE_F32 | - FLAG_SIZE_F32X2 | - FLAG_SIZE_F32X2I | - FLAG_SIZE_F64 | - FLAG_SIZE_F32I, - }; + enum + { + FLAG_STORE = (1 << 0), + FLAG_LOAD = (1 << 1), + FLAG_SIZE_8 = (1 << 2), + FLAG_SIZE_16 = (1 << 3), + FLAG_SIZE_32 = (1 << 4), + FLAG_SIZE_F32 = (1 << 5), + FLAG_SIZE_F32X2 = (1 << 6), + FLAG_SIZE_F32X2I = (1 << 7), + FLAG_SIZE_F64 = (1 << 8), + FLAG_REVERSE = (1 << 9), + FLAG_EXTEND = (1 << 10), + FLAG_SIZE_F32I = (1 << 11), + FLAG_ZERO_256 = (1 << 12), + FLAG_MASK_FLOAT = + FLAG_SIZE_F32 | FLAG_SIZE_F32X2 | FLAG_SIZE_F32X2I | FLAG_SIZE_F64 | FLAG_SIZE_F32I, + }; - static u32 GetFlagSize(u32 flags) - { - if (flags & FLAG_SIZE_8) - return 8; - if (flags & FLAG_SIZE_16) - return 16; - if (flags & FLAG_SIZE_32) - return 32; - if (flags & FLAG_SIZE_F32 || flags & FLAG_SIZE_F32I) - return 32; - if (flags & FLAG_SIZE_F64) - return 64; - if (flags & FLAG_ZERO_256) - return 256; - return 0; - } + static u32 GetFlagSize(u32 flags) + { + if (flags & FLAG_SIZE_8) + return 8; + if (flags & FLAG_SIZE_16) + return 16; + if (flags & FLAG_SIZE_32) + return 32; + if (flags & FLAG_SIZE_F32 || flags & FLAG_SIZE_F32I) + return 32; + if (flags & FLAG_SIZE_F64) + return 64; + if (flags & FLAG_ZERO_256) + return 256; + return 0; + } }; diff --git a/Source/Core/Core/PowerPC/JitCommon/JitAsmCommon.cpp b/Source/Core/Core/PowerPC/JitCommon/JitAsmCommon.cpp index 428e3e5232..6378fe2860 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitAsmCommon.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitAsmCommon.cpp @@ -4,63 +4,77 @@ #include "Core/PowerPC/JitCommon/JitAsmCommon.h" -alignas(16) const u8 pbswapShuffle1x4[16] = { 3, 2, 1, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; -alignas(16) const u8 pbswapShuffle2x4[16] = { 3, 2, 1, 0, 7, 6, 5, 4, 8, 9, 10, 11, 12, 13, 14, 15 }; +alignas(16) const u8 pbswapShuffle1x4[16] = {3, 2, 1, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; +alignas(16) const u8 pbswapShuffle2x4[16] = {3, 2, 1, 0, 7, 6, 5, 4, 8, 9, 10, 11, 12, 13, 14, 15}; -alignas(16) const float m_quantizeTableS[] = -{ - (1ULL << 0), (1ULL << 0), (1ULL << 1), (1ULL << 1), (1ULL << 2), (1ULL << 2), (1ULL << 3), (1ULL << 3), - (1ULL << 4), (1ULL << 4), (1ULL << 5), (1ULL << 5), (1ULL << 6), (1ULL << 6), (1ULL << 7), (1ULL << 7), - (1ULL << 8), (1ULL << 8), (1ULL << 9), (1ULL << 9), (1ULL << 10), (1ULL << 10), (1ULL << 11), (1ULL << 11), - (1ULL << 12), (1ULL << 12), (1ULL << 13), (1ULL << 13), (1ULL << 14), (1ULL << 14), (1ULL << 15), (1ULL << 15), - (1ULL << 16), (1ULL << 16), (1ULL << 17), (1ULL << 17), (1ULL << 18), (1ULL << 18), (1ULL << 19), (1ULL << 19), - (1ULL << 20), (1ULL << 20), (1ULL << 21), (1ULL << 21), (1ULL << 22), (1ULL << 22), (1ULL << 23), (1ULL << 23), - (1ULL << 24), (1ULL << 24), (1ULL << 25), (1ULL << 25), (1ULL << 26), (1ULL << 26), (1ULL << 27), (1ULL << 27), - (1ULL << 28), (1ULL << 28), (1ULL << 29), (1ULL << 29), (1ULL << 30), (1ULL << 30), (1ULL << 31), (1ULL << 31), - 1.0 / (1ULL << 32), 1.0 / (1ULL << 32), 1.0 / (1ULL << 31), 1.0 / (1ULL << 31), - 1.0 / (1ULL << 30), 1.0 / (1ULL << 30), 1.0 / (1ULL << 29), 1.0 / (1ULL << 29), - 1.0 / (1ULL << 28), 1.0 / (1ULL << 28), 1.0 / (1ULL << 27), 1.0 / (1ULL << 27), - 1.0 / (1ULL << 26), 1.0 / (1ULL << 26), 1.0 / (1ULL << 25), 1.0 / (1ULL << 25), - 1.0 / (1ULL << 24), 1.0 / (1ULL << 24), 1.0 / (1ULL << 23), 1.0 / (1ULL << 23), - 1.0 / (1ULL << 22), 1.0 / (1ULL << 22), 1.0 / (1ULL << 21), 1.0 / (1ULL << 21), - 1.0 / (1ULL << 20), 1.0 / (1ULL << 20), 1.0 / (1ULL << 19), 1.0 / (1ULL << 19), - 1.0 / (1ULL << 18), 1.0 / (1ULL << 18), 1.0 / (1ULL << 17), 1.0 / (1ULL << 17), - 1.0 / (1ULL << 16), 1.0 / (1ULL << 16), 1.0 / (1ULL << 15), 1.0 / (1ULL << 15), - 1.0 / (1ULL << 14), 1.0 / (1ULL << 14), 1.0 / (1ULL << 13), 1.0 / (1ULL << 13), - 1.0 / (1ULL << 12), 1.0 / (1ULL << 12), 1.0 / (1ULL << 11), 1.0 / (1ULL << 11), - 1.0 / (1ULL << 10), 1.0 / (1ULL << 10), 1.0 / (1ULL << 9), 1.0 / (1ULL << 9), - 1.0 / (1ULL << 8), 1.0 / (1ULL << 8), 1.0 / (1ULL << 7), 1.0 / (1ULL << 7), - 1.0 / (1ULL << 6), 1.0 / (1ULL << 6), 1.0 / (1ULL << 5), 1.0 / (1ULL << 5), - 1.0 / (1ULL << 4), 1.0 / (1ULL << 4), 1.0 / (1ULL << 3), 1.0 / (1ULL << 3), - 1.0 / (1ULL << 2), 1.0 / (1ULL << 2), 1.0 / (1ULL << 1), 1.0 / (1ULL << 1), +alignas(16) const float m_quantizeTableS[] = { + (1ULL << 0), (1ULL << 0), (1ULL << 1), (1ULL << 1), + (1ULL << 2), (1ULL << 2), (1ULL << 3), (1ULL << 3), + (1ULL << 4), (1ULL << 4), (1ULL << 5), (1ULL << 5), + (1ULL << 6), (1ULL << 6), (1ULL << 7), (1ULL << 7), + (1ULL << 8), (1ULL << 8), (1ULL << 9), (1ULL << 9), + (1ULL << 10), (1ULL << 10), (1ULL << 11), (1ULL << 11), + (1ULL << 12), (1ULL << 12), (1ULL << 13), (1ULL << 13), + (1ULL << 14), (1ULL << 14), (1ULL << 15), (1ULL << 15), + (1ULL << 16), (1ULL << 16), (1ULL << 17), (1ULL << 17), + (1ULL << 18), (1ULL << 18), (1ULL << 19), (1ULL << 19), + (1ULL << 20), (1ULL << 20), (1ULL << 21), (1ULL << 21), + (1ULL << 22), (1ULL << 22), (1ULL << 23), (1ULL << 23), + (1ULL << 24), (1ULL << 24), (1ULL << 25), (1ULL << 25), + (1ULL << 26), (1ULL << 26), (1ULL << 27), (1ULL << 27), + (1ULL << 28), (1ULL << 28), (1ULL << 29), (1ULL << 29), + (1ULL << 30), (1ULL << 30), (1ULL << 31), (1ULL << 31), + 1.0 / (1ULL << 32), 1.0 / (1ULL << 32), 1.0 / (1ULL << 31), 1.0 / (1ULL << 31), + 1.0 / (1ULL << 30), 1.0 / (1ULL << 30), 1.0 / (1ULL << 29), 1.0 / (1ULL << 29), + 1.0 / (1ULL << 28), 1.0 / (1ULL << 28), 1.0 / (1ULL << 27), 1.0 / (1ULL << 27), + 1.0 / (1ULL << 26), 1.0 / (1ULL << 26), 1.0 / (1ULL << 25), 1.0 / (1ULL << 25), + 1.0 / (1ULL << 24), 1.0 / (1ULL << 24), 1.0 / (1ULL << 23), 1.0 / (1ULL << 23), + 1.0 / (1ULL << 22), 1.0 / (1ULL << 22), 1.0 / (1ULL << 21), 1.0 / (1ULL << 21), + 1.0 / (1ULL << 20), 1.0 / (1ULL << 20), 1.0 / (1ULL << 19), 1.0 / (1ULL << 19), + 1.0 / (1ULL << 18), 1.0 / (1ULL << 18), 1.0 / (1ULL << 17), 1.0 / (1ULL << 17), + 1.0 / (1ULL << 16), 1.0 / (1ULL << 16), 1.0 / (1ULL << 15), 1.0 / (1ULL << 15), + 1.0 / (1ULL << 14), 1.0 / (1ULL << 14), 1.0 / (1ULL << 13), 1.0 / (1ULL << 13), + 1.0 / (1ULL << 12), 1.0 / (1ULL << 12), 1.0 / (1ULL << 11), 1.0 / (1ULL << 11), + 1.0 / (1ULL << 10), 1.0 / (1ULL << 10), 1.0 / (1ULL << 9), 1.0 / (1ULL << 9), + 1.0 / (1ULL << 8), 1.0 / (1ULL << 8), 1.0 / (1ULL << 7), 1.0 / (1ULL << 7), + 1.0 / (1ULL << 6), 1.0 / (1ULL << 6), 1.0 / (1ULL << 5), 1.0 / (1ULL << 5), + 1.0 / (1ULL << 4), 1.0 / (1ULL << 4), 1.0 / (1ULL << 3), 1.0 / (1ULL << 3), + 1.0 / (1ULL << 2), 1.0 / (1ULL << 2), 1.0 / (1ULL << 1), 1.0 / (1ULL << 1), }; -alignas(16) const float m_dequantizeTableS[] = -{ - 1.0 / (1ULL << 0), 1.0 / (1ULL << 0), 1.0 / (1ULL << 1), 1.0 / (1ULL << 1), - 1.0 / (1ULL << 2), 1.0 / (1ULL << 2), 1.0 / (1ULL << 3), 1.0 / (1ULL << 3), - 1.0 / (1ULL << 4), 1.0 / (1ULL << 4), 1.0 / (1ULL << 5), 1.0 / (1ULL << 5), - 1.0 / (1ULL << 6), 1.0 / (1ULL << 6), 1.0 / (1ULL << 7), 1.0 / (1ULL << 7), - 1.0 / (1ULL << 8), 1.0 / (1ULL << 8), 1.0 / (1ULL << 9), 1.0 / (1ULL << 9), - 1.0 / (1ULL << 10), 1.0 / (1ULL << 10), 1.0 / (1ULL << 11), 1.0 / (1ULL << 11), - 1.0 / (1ULL << 12), 1.0 / (1ULL << 12), 1.0 / (1ULL << 13), 1.0 / (1ULL << 13), - 1.0 / (1ULL << 14), 1.0 / (1ULL << 14), 1.0 / (1ULL << 15), 1.0 / (1ULL << 15), - 1.0 / (1ULL << 16), 1.0 / (1ULL << 16), 1.0 / (1ULL << 17), 1.0 / (1ULL << 17), - 1.0 / (1ULL << 18), 1.0 / (1ULL << 18), 1.0 / (1ULL << 19), 1.0 / (1ULL << 19), - 1.0 / (1ULL << 20), 1.0 / (1ULL << 20), 1.0 / (1ULL << 21), 1.0 / (1ULL << 21), - 1.0 / (1ULL << 22), 1.0 / (1ULL << 22), 1.0 / (1ULL << 23), 1.0 / (1ULL << 23), - 1.0 / (1ULL << 24), 1.0 / (1ULL << 24), 1.0 / (1ULL << 25), 1.0 / (1ULL << 25), - 1.0 / (1ULL << 26), 1.0 / (1ULL << 26), 1.0 / (1ULL << 27), 1.0 / (1ULL << 27), - 1.0 / (1ULL << 28), 1.0 / (1ULL << 28), 1.0 / (1ULL << 29), 1.0 / (1ULL << 29), - 1.0 / (1ULL << 30), 1.0 / (1ULL << 30), 1.0 / (1ULL << 31), 1.0 / (1ULL << 31), - (1ULL << 32), (1ULL << 32), (1ULL << 31), (1ULL << 31), (1ULL << 30), (1ULL << 30), (1ULL << 29), (1ULL << 29), - (1ULL << 28), (1ULL << 28), (1ULL << 27), (1ULL << 27), (1ULL << 26), (1ULL << 26), (1ULL << 25), (1ULL << 25), - (1ULL << 24), (1ULL << 24), (1ULL << 23), (1ULL << 23), (1ULL << 22), (1ULL << 22), (1ULL << 21), (1ULL << 21), - (1ULL << 20), (1ULL << 20), (1ULL << 19), (1ULL << 19), (1ULL << 18), (1ULL << 18), (1ULL << 17), (1ULL << 17), - (1ULL << 16), (1ULL << 16), (1ULL << 15), (1ULL << 15), (1ULL << 14), (1ULL << 14), (1ULL << 13), (1ULL << 13), - (1ULL << 12), (1ULL << 12), (1ULL << 11), (1ULL << 11), (1ULL << 10), (1ULL << 10), (1ULL << 9), (1ULL << 9), - (1ULL << 8), (1ULL << 8), (1ULL << 7), (1ULL << 7), (1ULL << 6), (1ULL << 6), (1ULL << 5), (1ULL << 5), - (1ULL << 4), (1ULL << 4), (1ULL << 3), (1ULL << 3), (1ULL << 2), (1ULL << 2), (1ULL << 1), (1ULL << 1), +alignas(16) const float m_dequantizeTableS[] = { + 1.0 / (1ULL << 0), 1.0 / (1ULL << 0), 1.0 / (1ULL << 1), 1.0 / (1ULL << 1), + 1.0 / (1ULL << 2), 1.0 / (1ULL << 2), 1.0 / (1ULL << 3), 1.0 / (1ULL << 3), + 1.0 / (1ULL << 4), 1.0 / (1ULL << 4), 1.0 / (1ULL << 5), 1.0 / (1ULL << 5), + 1.0 / (1ULL << 6), 1.0 / (1ULL << 6), 1.0 / (1ULL << 7), 1.0 / (1ULL << 7), + 1.0 / (1ULL << 8), 1.0 / (1ULL << 8), 1.0 / (1ULL << 9), 1.0 / (1ULL << 9), + 1.0 / (1ULL << 10), 1.0 / (1ULL << 10), 1.0 / (1ULL << 11), 1.0 / (1ULL << 11), + 1.0 / (1ULL << 12), 1.0 / (1ULL << 12), 1.0 / (1ULL << 13), 1.0 / (1ULL << 13), + 1.0 / (1ULL << 14), 1.0 / (1ULL << 14), 1.0 / (1ULL << 15), 1.0 / (1ULL << 15), + 1.0 / (1ULL << 16), 1.0 / (1ULL << 16), 1.0 / (1ULL << 17), 1.0 / (1ULL << 17), + 1.0 / (1ULL << 18), 1.0 / (1ULL << 18), 1.0 / (1ULL << 19), 1.0 / (1ULL << 19), + 1.0 / (1ULL << 20), 1.0 / (1ULL << 20), 1.0 / (1ULL << 21), 1.0 / (1ULL << 21), + 1.0 / (1ULL << 22), 1.0 / (1ULL << 22), 1.0 / (1ULL << 23), 1.0 / (1ULL << 23), + 1.0 / (1ULL << 24), 1.0 / (1ULL << 24), 1.0 / (1ULL << 25), 1.0 / (1ULL << 25), + 1.0 / (1ULL << 26), 1.0 / (1ULL << 26), 1.0 / (1ULL << 27), 1.0 / (1ULL << 27), + 1.0 / (1ULL << 28), 1.0 / (1ULL << 28), 1.0 / (1ULL << 29), 1.0 / (1ULL << 29), + 1.0 / (1ULL << 30), 1.0 / (1ULL << 30), 1.0 / (1ULL << 31), 1.0 / (1ULL << 31), + (1ULL << 32), (1ULL << 32), (1ULL << 31), (1ULL << 31), + (1ULL << 30), (1ULL << 30), (1ULL << 29), (1ULL << 29), + (1ULL << 28), (1ULL << 28), (1ULL << 27), (1ULL << 27), + (1ULL << 26), (1ULL << 26), (1ULL << 25), (1ULL << 25), + (1ULL << 24), (1ULL << 24), (1ULL << 23), (1ULL << 23), + (1ULL << 22), (1ULL << 22), (1ULL << 21), (1ULL << 21), + (1ULL << 20), (1ULL << 20), (1ULL << 19), (1ULL << 19), + (1ULL << 18), (1ULL << 18), (1ULL << 17), (1ULL << 17), + (1ULL << 16), (1ULL << 16), (1ULL << 15), (1ULL << 15), + (1ULL << 14), (1ULL << 14), (1ULL << 13), (1ULL << 13), + (1ULL << 12), (1ULL << 12), (1ULL << 11), (1ULL << 11), + (1ULL << 10), (1ULL << 10), (1ULL << 9), (1ULL << 9), + (1ULL << 8), (1ULL << 8), (1ULL << 7), (1ULL << 7), + (1ULL << 6), (1ULL << 6), (1ULL << 5), (1ULL << 5), + (1ULL << 4), (1ULL << 4), (1ULL << 3), (1ULL << 3), + (1ULL << 2), (1ULL << 2), (1ULL << 1), (1ULL << 1), }; -alignas(16) const float m_one[] = { 1.0f, 0.0f, 0.0f, 0.0f }; +alignas(16) const float m_one[] = {1.0f, 0.0f, 0.0f, 0.0f}; diff --git a/Source/Core/Core/PowerPC/JitCommon/JitAsmCommon.h b/Source/Core/Core/PowerPC/JitCommon/JitAsmCommon.h index 66d933687a..f8d997ca57 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitAsmCommon.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitAsmCommon.h @@ -15,40 +15,39 @@ alignas(16) extern const float m_dequantizeTableS[]; class CommonAsmRoutinesBase { public: - const u8 *fifoDirectWrite8; - const u8 *fifoDirectWrite16; - const u8 *fifoDirectWrite32; - const u8 *fifoDirectWrite64; + const u8* fifoDirectWrite8; + const u8* fifoDirectWrite16; + const u8* fifoDirectWrite32; + const u8* fifoDirectWrite64; - const u8 *enterCode; + const u8* enterCode; - const u8 *dispatcherMispredictedBLR; - const u8 *dispatcher; - const u8 *dispatcherNoCheck; + const u8* dispatcherMispredictedBLR; + const u8* dispatcher; + const u8* dispatcherNoCheck; - const u8 *doTiming; + const u8* doTiming; - const u8 *frsqrte; - const u8 *fres; - const u8 *mfcr; + const u8* frsqrte; + const u8* fres; + const u8* mfcr; - // In: array index: GQR to use. - // In: ECX: Address to read from. - // Out: XMM0: Bottom two 32-bit slots hold the read value, - // converted to a pair of floats. - // Trashes: all three RSCRATCH - const u8 **pairedLoadQuantized; + // In: array index: GQR to use. + // In: ECX: Address to read from. + // Out: XMM0: Bottom two 32-bit slots hold the read value, + // converted to a pair of floats. + // Trashes: all three RSCRATCH + const u8** pairedLoadQuantized; - // In: array index: GQR to use. - // In: ECX: Address to write to. - // In: XMM0: Bottom two 32-bit slots hold the pair of floats to be written. - // Out: Nothing. - // Trashes: all three RSCRATCH - const u8 **pairedStoreQuantized; + // In: array index: GQR to use. + // In: ECX: Address to write to. + // In: XMM0: Bottom two 32-bit slots hold the pair of floats to be written. + // Out: Nothing. + // Trashes: all three RSCRATCH + const u8** pairedStoreQuantized; - // In: array index: GQR to use. - // In: ECX: Address to write to. - // In: XMM0: Bottom 32-bit slot holds the float to be written. - const u8 **singleStoreQuantized; + // In: array index: GQR to use. + // In: ECX: Address to write to. + // In: XMM0: Bottom 32-bit slot holds the float to be written. + const u8** singleStoreQuantized; }; - diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBackpatch.cpp b/Source/Core/Core/PowerPC/JitCommon/JitBackpatch.cpp index a9303636cd..33efc2ee18 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBackpatch.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitBackpatch.cpp @@ -19,18 +19,18 @@ using namespace Gen; -static void BackPatchError(const std::string &text, u8 *codePtr, u32 emAddress) +static void BackPatchError(const std::string& text, u8* codePtr, u32 emAddress) { - u64 code_addr = (u64)codePtr; - disassembler disasm; - char disbuf[256]; - memset(disbuf, 0, 256); - disasm.disasm64(0, code_addr, codePtr, disbuf); - PanicAlert("%s\n\n" - "Error encountered accessing emulated address %08x.\n" - "Culprit instruction: \n%s\nat %#" PRIx64, - text.c_str(), emAddress, disbuf, code_addr); - return; + u64 code_addr = (u64)codePtr; + disassembler disasm; + char disbuf[256]; + memset(disbuf, 0, 256); + disasm.disasm64(0, code_addr, codePtr, disbuf); + PanicAlert("%s\n\n" + "Error encountered accessing emulated address %08x.\n" + "Culprit instruction: \n%s\nat %#" PRIx64, + text.c_str(), emAddress, disbuf, code_addr); + return; } // This generates some fairly heavy trampolines, but it doesn't really hurt. @@ -38,163 +38,167 @@ static void BackPatchError(const std::string &text, u8 *codePtr, u32 emAddress) // many of them in a typical program/game. bool Jitx86Base::HandleFault(uintptr_t access_address, SContext* ctx) { - // TODO: do we properly handle off-the-end? - if (access_address >= (uintptr_t)Memory::physical_base && access_address < (uintptr_t)Memory::physical_base + 0x100010000) - return BackPatch((u32)(access_address - (uintptr_t)Memory::physical_base), ctx); - if (access_address >= (uintptr_t)Memory::logical_base && access_address < (uintptr_t)Memory::logical_base + 0x100010000) - return BackPatch((u32)(access_address - (uintptr_t)Memory::logical_base), ctx); + // TODO: do we properly handle off-the-end? + if (access_address >= (uintptr_t)Memory::physical_base && + access_address < (uintptr_t)Memory::physical_base + 0x100010000) + return BackPatch((u32)(access_address - (uintptr_t)Memory::physical_base), ctx); + if (access_address >= (uintptr_t)Memory::logical_base && + access_address < (uintptr_t)Memory::logical_base + 0x100010000) + return BackPatch((u32)(access_address - (uintptr_t)Memory::logical_base), ctx); - - return false; + return false; } bool Jitx86Base::BackPatch(u32 emAddress, SContext* ctx) { - u8* codePtr = (u8*) ctx->CTX_PC; + u8* codePtr = (u8*)ctx->CTX_PC; - if (!IsInSpace(codePtr)) - return false; // this will become a regular crash real soon after this + if (!IsInSpace(codePtr)) + return false; // this will become a regular crash real soon after this - InstructionInfo info = {}; + InstructionInfo info = {}; - if (!DisassembleMov(codePtr, &info)) - { - BackPatchError("BackPatch - failed to disassemble MOV instruction", codePtr, emAddress); - return false; - } + if (!DisassembleMov(codePtr, &info)) + { + BackPatchError("BackPatch - failed to disassemble MOV instruction", codePtr, emAddress); + return false; + } - if (info.otherReg != RMEM) - { - PanicAlert("BackPatch : Base reg not RMEM." - "\n\nAttempted to access %08x.", emAddress); - return false; - } + if (info.otherReg != RMEM) + { + PanicAlert("BackPatch : Base reg not RMEM." + "\n\nAttempted to access %08x.", + emAddress); + return false; + } - if (info.byteSwap && info.instructionSize < BACKPATCH_SIZE) - { - PanicAlert("BackPatch: MOVBE is too small"); - return false; - } + if (info.byteSwap && info.instructionSize < BACKPATCH_SIZE) + { + PanicAlert("BackPatch: MOVBE is too small"); + return false; + } - auto it = registersInUseAtLoc.find(codePtr); - if (it == registersInUseAtLoc.end()) - { - PanicAlert("BackPatch: no register use entry for address %p", codePtr); - return false; - } + auto it = registersInUseAtLoc.find(codePtr); + if (it == registersInUseAtLoc.end()) + { + PanicAlert("BackPatch: no register use entry for address %p", codePtr); + return false; + } - BitSet32 registersInUse = it->second; + BitSet32 registersInUse = it->second; - u8* exceptionHandler = nullptr; - if (jit->jo.memcheck) - { - auto it2 = exceptionHandlerAtLoc.find(codePtr); - if (it2 != exceptionHandlerAtLoc.end()) - exceptionHandler = it2->second; - } + u8* exceptionHandler = nullptr; + if (jit->jo.memcheck) + { + auto it2 = exceptionHandlerAtLoc.find(codePtr); + if (it2 != exceptionHandlerAtLoc.end()) + exceptionHandler = it2->second; + } - // Compute the start and length of the memory operation, including - // any byteswapping. - int totalSize = info.instructionSize; - u8 *start = codePtr; - if (!info.isMemoryWrite) - { - // MOVBE and single bytes don't need to be swapped. - if (!info.byteSwap && info.operandSize > 1) - { - // REX - if ((codePtr[totalSize] & 0xF0) == 0x40) - totalSize++; + // Compute the start and length of the memory operation, including + // any byteswapping. + int totalSize = info.instructionSize; + u8* start = codePtr; + if (!info.isMemoryWrite) + { + // MOVBE and single bytes don't need to be swapped. + if (!info.byteSwap && info.operandSize > 1) + { + // REX + if ((codePtr[totalSize] & 0xF0) == 0x40) + totalSize++; - // BSWAP - if (codePtr[totalSize] == 0x0F && (codePtr[totalSize + 1] & 0xF8) == 0xC8) - totalSize += 2; + // BSWAP + if (codePtr[totalSize] == 0x0F && (codePtr[totalSize + 1] & 0xF8) == 0xC8) + totalSize += 2; - if (info.operandSize == 2) - { - // operand size override - if (codePtr[totalSize] == 0x66) - totalSize++; - // REX - if ((codePtr[totalSize] & 0xF0) == 0x40) - totalSize++; - // SAR/ROL - _assert_(codePtr[totalSize] == 0xC1 && (codePtr[totalSize + 2] == 0x10 || - codePtr[totalSize + 2] == 0x08)); - info.signExtend = (codePtr[totalSize + 1] & 0x10) != 0; - totalSize += 3; - } - } - } - else - { - if (info.byteSwap || info.hasImmediate) - { - // The instruction is a MOVBE but it failed so the value is still in little-endian byte order. - } - else - { - // We entered here with a BSWAP-ed register. We'll have to swap it back. - u64 *ptr = ContextRN(ctx, info.regOperandReg); - int bswapSize = 0; - switch (info.operandSize) - { - case 1: - bswapSize = 0; - break; - case 2: - bswapSize = 4 + (info.regOperandReg >= 8 ? 1 : 0); - *ptr = Common::swap16((u16) *ptr); - break; - case 4: - bswapSize = 2 + (info.regOperandReg >= 8 ? 1 : 0); - *ptr = Common::swap32((u32) *ptr); - break; - case 8: - bswapSize = 3; - *ptr = Common::swap64(*ptr); - break; - } - start = codePtr - bswapSize; - totalSize += bswapSize; - } - } + if (info.operandSize == 2) + { + // operand size override + if (codePtr[totalSize] == 0x66) + totalSize++; + // REX + if ((codePtr[totalSize] & 0xF0) == 0x40) + totalSize++; + // SAR/ROL + _assert_(codePtr[totalSize] == 0xC1 && + (codePtr[totalSize + 2] == 0x10 || codePtr[totalSize + 2] == 0x08)); + info.signExtend = (codePtr[totalSize + 1] & 0x10) != 0; + totalSize += 3; + } + } + } + else + { + if (info.byteSwap || info.hasImmediate) + { + // The instruction is a MOVBE but it failed so the value is still in little-endian byte order. + } + else + { + // We entered here with a BSWAP-ed register. We'll have to swap it back. + u64* ptr = ContextRN(ctx, info.regOperandReg); + int bswapSize = 0; + switch (info.operandSize) + { + case 1: + bswapSize = 0; + break; + case 2: + bswapSize = 4 + (info.regOperandReg >= 8 ? 1 : 0); + *ptr = Common::swap16((u16)*ptr); + break; + case 4: + bswapSize = 2 + (info.regOperandReg >= 8 ? 1 : 0); + *ptr = Common::swap32((u32)*ptr); + break; + case 8: + bswapSize = 3; + *ptr = Common::swap64(*ptr); + break; + } + start = codePtr - bswapSize; + totalSize += bswapSize; + } + } - // In the trampoline code, we jump back into the block at the beginning - // of the next instruction. The next instruction comes immediately - // after the backpatched operation, or BACKPATCH_SIZE bytes after the start - // of the backpatched operation, whichever comes last. (The JIT inserts NOPs - // into the original code if necessary to ensure there is enough space - // to insert the backpatch jump.) - int padding = totalSize > BACKPATCH_SIZE ? totalSize - BACKPATCH_SIZE : 0; - u8* returnPtr = start + 5 + padding; + // In the trampoline code, we jump back into the block at the beginning + // of the next instruction. The next instruction comes immediately + // after the backpatched operation, or BACKPATCH_SIZE bytes after the start + // of the backpatched operation, whichever comes last. (The JIT inserts NOPs + // into the original code if necessary to ensure there is enough space + // to insert the backpatch jump.) + int padding = totalSize > BACKPATCH_SIZE ? totalSize - BACKPATCH_SIZE : 0; + u8* returnPtr = start + 5 + padding; - // Generate the trampoline. - const u8* trampoline; - if (info.isMemoryWrite) - { - // TODO: special case FIFO writes. - auto it3 = pcAtLoc.find(codePtr); - if (it3 == pcAtLoc.end()) - { - PanicAlert("BackPatch: no pc entry for address %p", codePtr); - return false; - } + // Generate the trampoline. + const u8* trampoline; + if (info.isMemoryWrite) + { + // TODO: special case FIFO writes. + auto it3 = pcAtLoc.find(codePtr); + if (it3 == pcAtLoc.end()) + { + PanicAlert("BackPatch: no pc entry for address %p", codePtr); + return false; + } - u32 pc = it3->second; - trampoline = trampolines.GenerateWriteTrampoline(info, registersInUse, exceptionHandler, returnPtr, pc); - } - else - { - trampoline = trampolines.GenerateReadTrampoline(info, registersInUse, exceptionHandler, returnPtr); - } + u32 pc = it3->second; + trampoline = + trampolines.GenerateWriteTrampoline(info, registersInUse, exceptionHandler, returnPtr, pc); + } + else + { + trampoline = + trampolines.GenerateReadTrampoline(info, registersInUse, exceptionHandler, returnPtr); + } - // Patch the original memory operation. - XEmitter emitter(start); - emitter.JMP(trampoline, true); - for (int i = 0; i < padding; ++i) - emitter.INT3(); - ctx->CTX_PC = (u64)start; + // Patch the original memory operation. + XEmitter emitter(start); + emitter.JMP(trampoline, true); + for (int i = 0; i < padding; ++i) + emitter.INT3(); + ctx->CTX_PC = (u64)start; - return true; + return true; } diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp b/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp index 9beb4c8faa..231087bf21 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp @@ -9,86 +9,85 @@ #include "Common/CommonTypes.h" #include "Common/GekkoDisassembler.h" -#include "Common/StringUtil.h" #include "Common/Logging/Log.h" +#include "Common/StringUtil.h" #include "Core/ConfigManager.h" #include "Core/HW/CPU.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/JitCommon/JitBase.h" +#include "Core/PowerPC/PPCAnalyst.h" +#include "Core/PowerPC/PowerPC.h" -JitBase *jit; +JitBase* jit; void Jit(u32 em_address) { - jit->Jit(em_address); + jit->Jit(em_address); } u32 Helper_Mask(u8 mb, u8 me) { - u32 mask = ((u32)-1 >> mb) ^ (me >= 31 ? 0 : (u32)-1 >> (me + 1)); - return mb > me ? ~mask : mask; + u32 mask = ((u32)-1 >> mb) ^ (me >= 31 ? 0 : (u32)-1 >> (me + 1)); + return mb > me ? ~mask : mask; } -void LogGeneratedX86(int size, PPCAnalyst::CodeBuffer *code_buffer, const u8 *normalEntry, JitBlock *b) +void LogGeneratedX86(int size, PPCAnalyst::CodeBuffer* code_buffer, const u8* normalEntry, + JitBlock* b) { - for (int i = 0; i < size; i++) - { - const PPCAnalyst::CodeOp &op = code_buffer->codebuffer[i]; - std::string temp = StringFromFormat("%08x %s", op.address, GekkoDisassembler::Disassemble(op.inst.hex, op.address).c_str()); - DEBUG_LOG(DYNA_REC, "IR_X86 PPC: %s\n", temp.c_str()); - } + for (int i = 0; i < size; i++) + { + const PPCAnalyst::CodeOp& op = code_buffer->codebuffer[i]; + std::string temp = StringFromFormat( + "%08x %s", op.address, GekkoDisassembler::Disassemble(op.inst.hex, op.address).c_str()); + DEBUG_LOG(DYNA_REC, "IR_X86 PPC: %s\n", temp.c_str()); + } - disassembler x64disasm; - x64disasm.set_syntax_intel(); + disassembler x64disasm; + x64disasm.set_syntax_intel(); - u64 disasmPtr = (u64)normalEntry; - const u8 *end = normalEntry + b->codeSize; + u64 disasmPtr = (u64)normalEntry; + const u8* end = normalEntry + b->codeSize; - while ((u8*)disasmPtr < end) - { - char sptr[1000] = ""; - disasmPtr += x64disasm.disasm64(disasmPtr, disasmPtr, (u8*)disasmPtr, sptr); - DEBUG_LOG(DYNA_REC,"IR_X86 x86: %s", sptr); - } + while ((u8*)disasmPtr < end) + { + char sptr[1000] = ""; + disasmPtr += x64disasm.disasm64(disasmPtr, disasmPtr, (u8*)disasmPtr, sptr); + DEBUG_LOG(DYNA_REC, "IR_X86 x86: %s", sptr); + } - if (b->codeSize <= 250) - { - std::stringstream ss; - ss << std::hex; - for (u8 i = 0; i <= b->codeSize; i++) - { - ss.width(2); - ss.fill('0'); - ss << (u32)*(normalEntry + i); - } - DEBUG_LOG(DYNA_REC,"IR_X86 bin: %s\n\n\n", ss.str().c_str()); - } + if (b->codeSize <= 250) + { + std::stringstream ss; + ss << std::hex; + for (u8 i = 0; i <= b->codeSize; i++) + { + ss.width(2); + ss.fill('0'); + ss << (u32) * (normalEntry + i); + } + DEBUG_LOG(DYNA_REC, "IR_X86 bin: %s\n\n\n", ss.str().c_str()); + } } bool JitBase::MergeAllowedNextInstructions(int count) { - if (CPU::GetState() == CPU::CPU_STEPPING || js.instructionsLeft < count) - return false; - // Be careful: a breakpoint kills flags in between instructions - for (int i = 1; i <= count; i++) - { - if (SConfig::GetInstance().bEnableDebugging && - PowerPC::breakpoints.IsAddressBreakPoint(js.op[i].address)) - return false; - if (js.op[i].isBranchTarget) - return false; - } - return true; + if (CPU::GetState() == CPU::CPU_STEPPING || js.instructionsLeft < count) + return false; + // Be careful: a breakpoint kills flags in between instructions + for (int i = 1; i <= count; i++) + { + if (SConfig::GetInstance().bEnableDebugging && + PowerPC::breakpoints.IsAddressBreakPoint(js.op[i].address)) + return false; + if (js.op[i].isBranchTarget) + return false; + } + return true; } void JitBase::UpdateMemoryOptions() { - bool any_watchpoints = PowerPC::memchecks.HasAny(); - jo.fastmem = SConfig::GetInstance().bFastmem && - !any_watchpoints; - jo.memcheck = SConfig::GetInstance().bMMU || - any_watchpoints; - jo.alwaysUseMemFuncs = any_watchpoints; - + bool any_watchpoints = PowerPC::memchecks.HasAny(); + jo.fastmem = SConfig::GetInstance().bFastmem && !any_watchpoints; + jo.memcheck = SConfig::GetInstance().bMMU || any_watchpoints; + jo.alwaysUseMemFuncs = any_watchpoints; } diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.h b/Source/Core/Core/PowerPC/JitCommon/JitBase.h index 39c37caca6..0af9282645 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBase.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.h @@ -15,11 +15,11 @@ #include "Core/ConfigManager.h" #include "Core/MachineContext.h" #include "Core/PowerPC/CPUCoreBase.h" -#include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/Jit64Common/Jit64AsmCommon.h" -#include "Core/PowerPC/JitCommon/Jit_Util.h" #include "Core/PowerPC/JitCommon/JitCache.h" +#include "Core/PowerPC/JitCommon/Jit_Util.h" #include "Core/PowerPC/JitCommon/TrampolineCache.h" +#include "Core/PowerPC/PPCAnalyst.h" // TODO: find a better place for x86-specific stuff // The following register assignments are common to Jit64 and Jit64IL: @@ -41,101 +41,112 @@ // #define INSTRUCTION_START PPCTables::CountInstruction(inst); #define INSTRUCTION_START -#define FALLBACK_IF(cond) do { if (cond) { FallBackToInterpreter(inst); return; } } while (0) +#define FALLBACK_IF(cond) \ + do \ + { \ + if (cond) \ + { \ + FallBackToInterpreter(inst); \ + return; \ + } \ + } while (0) -#define JITDISABLE(setting) FALLBACK_IF(SConfig::GetInstance().bJITOff || \ - SConfig::GetInstance().setting) +#define JITDISABLE(setting) \ + FALLBACK_IF(SConfig::GetInstance().bJITOff || SConfig::GetInstance().setting) class JitBase : public CPUCoreBase { protected: - struct JitOptions - { - bool enableBlocklink; - bool optimizeGatherPipe; - bool accurateSinglePrecision; - bool fastmem; - bool memcheck; - bool alwaysUseMemFuncs; - }; - struct JitState - { - u32 compilerPC; - u32 blockStart; - int instructionNumber; - int instructionsLeft; - int downcountAmount; - u32 numLoadStoreInst; - u32 numFloatingPointInst; - // If this is set, we need to generate an exception handler for the fastmem load. - u8* fastmemLoadStore; - // If this is set, a load or store already prepared a jump to the exception handler for us, - // so just fixup that branch instead of testing for a DSI again. - bool fixupExceptionHandler; - Gen::FixupBranch exceptionHandler; - // If these are set, we've stored the old value of a register which will be loaded in revertLoad, - // which lets us revert it on the exception path. - int revertGprLoad; - int revertFprLoad; + struct JitOptions + { + bool enableBlocklink; + bool optimizeGatherPipe; + bool accurateSinglePrecision; + bool fastmem; + bool memcheck; + bool alwaysUseMemFuncs; + }; + struct JitState + { + u32 compilerPC; + u32 blockStart; + int instructionNumber; + int instructionsLeft; + int downcountAmount; + u32 numLoadStoreInst; + u32 numFloatingPointInst; + // If this is set, we need to generate an exception handler for the fastmem load. + u8* fastmemLoadStore; + // If this is set, a load or store already prepared a jump to the exception handler for us, + // so just fixup that branch instead of testing for a DSI again. + bool fixupExceptionHandler; + Gen::FixupBranch exceptionHandler; + // If these are set, we've stored the old value of a register which will be loaded in + // revertLoad, + // which lets us revert it on the exception path. + int revertGprLoad; + int revertFprLoad; - bool assumeNoPairedQuantize; - bool firstFPInstructionFound; - bool isLastInstruction; - int skipInstructions; - bool carryFlagSet; - bool carryFlagInverted; + bool assumeNoPairedQuantize; + bool firstFPInstructionFound; + bool isLastInstruction; + int skipInstructions; + bool carryFlagSet; + bool carryFlagInverted; - int fifoBytesThisBlock; + int fifoBytesThisBlock; - PPCAnalyst::BlockStats st; - PPCAnalyst::BlockRegStats gpa; - PPCAnalyst::BlockRegStats fpa; - PPCAnalyst::CodeOp* op; - u8* rewriteStart; + PPCAnalyst::BlockStats st; + PPCAnalyst::BlockRegStats gpa; + PPCAnalyst::BlockRegStats fpa; + PPCAnalyst::CodeOp* op; + u8* rewriteStart; - JitBlock *curBlock; + JitBlock* curBlock; - std::unordered_set fifoWriteAddresses; - std::unordered_set pairedQuantizeAddresses; - }; + std::unordered_set fifoWriteAddresses; + std::unordered_set pairedQuantizeAddresses; + }; - PPCAnalyst::CodeBlock code_block; - PPCAnalyst::PPCAnalyzer analyzer; + PPCAnalyst::CodeBlock code_block; + PPCAnalyst::PPCAnalyzer analyzer; - bool MergeAllowedNextInstructions(int count); + bool MergeAllowedNextInstructions(int count); - void UpdateMemoryOptions(); + void UpdateMemoryOptions(); public: - // This should probably be removed from public: - JitOptions jo; - JitState js; + // This should probably be removed from public: + JitOptions jo; + JitState js; - virtual JitBaseBlockCache *GetBlockCache() = 0; + virtual JitBaseBlockCache* GetBlockCache() = 0; - virtual void Jit(u32 em_address) = 0; + virtual void Jit(u32 em_address) = 0; - virtual const CommonAsmRoutinesBase *GetAsmRoutines() = 0; + virtual const CommonAsmRoutinesBase* GetAsmRoutines() = 0; - virtual bool HandleFault(uintptr_t access_address, SContext* ctx) = 0; - virtual bool HandleStackFault() { return false; } + virtual bool HandleFault(uintptr_t access_address, SContext* ctx) = 0; + virtual bool HandleStackFault() { return false; } }; class Jitx86Base : public JitBase, public EmuCodeBlock { protected: - bool BackPatch(u32 emAddress, SContext* ctx); - JitBlockCache blocks; - TrampolineCache trampolines; + bool BackPatch(u32 emAddress, SContext* ctx); + JitBlockCache blocks; + TrampolineCache trampolines; + public: - JitBlockCache *GetBlockCache() override { return &blocks; } - bool HandleFault(uintptr_t access_address, SContext* ctx) override; + JitBlockCache* GetBlockCache() override { return &blocks; } + bool HandleFault(uintptr_t access_address, SContext* ctx) override; }; -extern JitBase *jit; +extern JitBase* jit; void Jit(u32 em_address); // Merged routines that should be moved somewhere better u32 Helper_Mask(u8 mb, u8 me); -void LogGeneratedX86(int size, PPCAnalyst::CodeBuffer *code_buffer, const u8 *normalEntry, JitBlock *b); +void LogGeneratedX86(int size, PPCAnalyst::CodeBuffer* code_buffer, const u8* normalEntry, + JitBlock* b); diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp index 91c2d1a1ac..91c9e10504 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp @@ -17,9 +17,9 @@ #include "Common/JitRegister.h" #include "Core/ConfigManager.h" #include "Core/Core.h" +#include "Core/PowerPC/JitCommon/JitBase.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/JitCommon/JitBase.h" #ifdef _WIN32 #include @@ -27,319 +27,322 @@ using namespace Gen; - bool JitBaseBlockCache::IsFull() const - { - return GetNumBlocks() >= MAX_NUM_BLOCKS - 1; - } +bool JitBaseBlockCache::IsFull() const +{ + return GetNumBlocks() >= MAX_NUM_BLOCKS - 1; +} - void JitBaseBlockCache::Init() - { - if (m_initialized) - { - PanicAlert("JitBaseBlockCache::Init() - iCache is already initialized"); - return; - } +void JitBaseBlockCache::Init() +{ + if (m_initialized) + { + PanicAlert("JitBaseBlockCache::Init() - iCache is already initialized"); + return; + } - JitRegister::Init(SConfig::GetInstance().m_perfDir); + JitRegister::Init(SConfig::GetInstance().m_perfDir); - iCache.fill(JIT_ICACHE_INVALID_BYTE); - iCacheEx.fill(JIT_ICACHE_INVALID_BYTE); - iCacheVMEM.fill(JIT_ICACHE_INVALID_BYTE); - Clear(); + iCache.fill(JIT_ICACHE_INVALID_BYTE); + iCacheEx.fill(JIT_ICACHE_INVALID_BYTE); + iCacheVMEM.fill(JIT_ICACHE_INVALID_BYTE); + Clear(); - m_initialized = true; - } + m_initialized = true; +} - void JitBaseBlockCache::Shutdown() - { - num_blocks = 0; - m_initialized = false; +void JitBaseBlockCache::Shutdown() +{ + num_blocks = 0; + m_initialized = false; - JitRegister::Shutdown(); - } + JitRegister::Shutdown(); +} - // This clears the JIT cache. It's called from JitCache.cpp when the JIT cache - // is full and when saving and loading states. - void JitBaseBlockCache::Clear() - { +// This clears the JIT cache. It's called from JitCache.cpp when the JIT cache +// is full and when saving and loading states. +void JitBaseBlockCache::Clear() +{ #if defined(_DEBUG) || defined(DEBUGFAST) - if (IsFull()) - Core::DisplayMessage("Clearing block cache.", 3000); - else - Core::DisplayMessage("Clearing code cache.", 3000); + if (IsFull()) + Core::DisplayMessage("Clearing block cache.", 3000); + else + Core::DisplayMessage("Clearing code cache.", 3000); #endif - jit->js.fifoWriteAddresses.clear(); - jit->js.pairedQuantizeAddresses.clear(); - for (int i = 0; i < num_blocks; i++) - { - DestroyBlock(i, false); - } - links_to.clear(); - block_map.clear(); + jit->js.fifoWriteAddresses.clear(); + jit->js.pairedQuantizeAddresses.clear(); + for (int i = 0; i < num_blocks; i++) + { + DestroyBlock(i, false); + } + links_to.clear(); + block_map.clear(); - valid_block.ClearAll(); + valid_block.ClearAll(); - num_blocks = 0; - blockCodePointers.fill(nullptr); - } + num_blocks = 0; + blockCodePointers.fill(nullptr); +} - void JitBaseBlockCache::Reset() - { - Shutdown(); - Init(); - } +void JitBaseBlockCache::Reset() +{ + Shutdown(); + Init(); +} - JitBlock *JitBaseBlockCache::GetBlock(int no) - { - return &blocks[no]; - } +JitBlock* JitBaseBlockCache::GetBlock(int no) +{ + return &blocks[no]; +} - int JitBaseBlockCache::GetNumBlocks() const - { - return num_blocks; - } +int JitBaseBlockCache::GetNumBlocks() const +{ + return num_blocks; +} - int JitBaseBlockCache::AllocateBlock(u32 em_address) - { - JitBlock &b = blocks[num_blocks]; - b.invalid = false; - b.originalAddress = em_address; - b.linkData.clear(); - num_blocks++; //commit the current block - return num_blocks - 1; - } +int JitBaseBlockCache::AllocateBlock(u32 em_address) +{ + JitBlock& b = blocks[num_blocks]; + b.invalid = false; + b.originalAddress = em_address; + b.linkData.clear(); + num_blocks++; // commit the current block + return num_blocks - 1; +} - void JitBaseBlockCache::FinalizeBlock(int block_num, bool block_link, const u8 *code_ptr) - { - blockCodePointers[block_num] = code_ptr; - JitBlock &b = blocks[block_num]; +void JitBaseBlockCache::FinalizeBlock(int block_num, bool block_link, const u8* code_ptr) +{ + blockCodePointers[block_num] = code_ptr; + JitBlock& b = blocks[block_num]; - std::memcpy(GetICachePtr(b.originalAddress), &block_num, sizeof(u32)); + std::memcpy(GetICachePtr(b.originalAddress), &block_num, sizeof(u32)); - // Convert the logical address to a physical address for the block map - u32 pAddr = b.originalAddress & 0x1FFFFFFF; + // Convert the logical address to a physical address for the block map + u32 pAddr = b.originalAddress & 0x1FFFFFFF; - for (u32 block = pAddr / 32; block <= (pAddr + (b.originalSize - 1) * 4) / 32; ++block) - valid_block.Set(block); + for (u32 block = pAddr / 32; block <= (pAddr + (b.originalSize - 1) * 4) / 32; ++block) + valid_block.Set(block); - block_map[std::make_pair(pAddr + 4 * b.originalSize - 1, pAddr)] = block_num; + block_map[std::make_pair(pAddr + 4 * b.originalSize - 1, pAddr)] = block_num; - if (block_link) - { - for (const auto& e : b.linkData) - { - links_to.emplace(e.exitAddress, block_num); - } + if (block_link) + { + for (const auto& e : b.linkData) + { + links_to.emplace(e.exitAddress, block_num); + } - LinkBlock(block_num); - LinkBlockExits(block_num); - } + LinkBlock(block_num); + LinkBlockExits(block_num); + } - JitRegister::Register(blockCodePointers[block_num], b.codeSize, - "JIT_PPC_%08x", b.originalAddress); - } + JitRegister::Register(blockCodePointers[block_num], b.codeSize, "JIT_PPC_%08x", + b.originalAddress); +} - const u8 **JitBaseBlockCache::GetCodePointers() - { - return blockCodePointers.data(); - } +const u8** JitBaseBlockCache::GetCodePointers() +{ + return blockCodePointers.data(); +} - u8* JitBaseBlockCache::GetICachePtr(u32 addr) - { - if (addr & JIT_ICACHE_VMEM_BIT) - return &jit->GetBlockCache()->iCacheVMEM[addr & JIT_ICACHE_MASK]; +u8* JitBaseBlockCache::GetICachePtr(u32 addr) +{ + if (addr & JIT_ICACHE_VMEM_BIT) + return &jit->GetBlockCache()->iCacheVMEM[addr & JIT_ICACHE_MASK]; - if (addr & JIT_ICACHE_EXRAM_BIT) - return &jit->GetBlockCache()->iCacheEx[addr & JIT_ICACHEEX_MASK]; + if (addr & JIT_ICACHE_EXRAM_BIT) + return &jit->GetBlockCache()->iCacheEx[addr & JIT_ICACHEEX_MASK]; - return &jit->GetBlockCache()->iCache[addr & JIT_ICACHE_MASK]; - } + return &jit->GetBlockCache()->iCache[addr & JIT_ICACHE_MASK]; +} - int JitBaseBlockCache::GetBlockNumberFromStartAddress(u32 addr) - { - u32 inst; - std::memcpy(&inst, GetICachePtr(addr), sizeof(u32)); +int JitBaseBlockCache::GetBlockNumberFromStartAddress(u32 addr) +{ + u32 inst; + std::memcpy(&inst, GetICachePtr(addr), sizeof(u32)); - if (inst & 0xfc000000) // definitely not a JIT block - return -1; + if (inst & 0xfc000000) // definitely not a JIT block + return -1; - if ((int)inst >= num_blocks) - return -1; + if ((int)inst >= num_blocks) + return -1; - if (blocks[inst].originalAddress != addr) - return -1; + if (blocks[inst].originalAddress != addr) + return -1; - return inst; - } + return inst; +} - CompiledCode JitBaseBlockCache::GetCompiledCodeFromBlock(int block_num) - { - return (CompiledCode)blockCodePointers[block_num]; - } +CompiledCode JitBaseBlockCache::GetCompiledCodeFromBlock(int block_num) +{ + return (CompiledCode)blockCodePointers[block_num]; +} - //Block linker - //Make sure to have as many blocks as possible compiled before calling this - //It's O(N), so it's fast :) - //Can be faster by doing a queue for blocks to link up, and only process those - //Should probably be done +// Block linker +// Make sure to have as many blocks as possible compiled before calling this +// It's O(N), so it's fast :) +// Can be faster by doing a queue for blocks to link up, and only process those +// Should probably be done - void JitBaseBlockCache::LinkBlockExits(int i) - { - JitBlock &b = blocks[i]; - if (b.invalid) - { - // This block is dead. Don't relink it. - return; - } - for (auto& e : b.linkData) - { - if (!e.linkStatus) - { - int destinationBlock = GetBlockNumberFromStartAddress(e.exitAddress); - if (destinationBlock != -1) - { - WriteLinkBlock(e.exitPtrs, blocks[destinationBlock]); - e.linkStatus = true; - } - } - } - } +void JitBaseBlockCache::LinkBlockExits(int i) +{ + JitBlock& b = blocks[i]; + if (b.invalid) + { + // This block is dead. Don't relink it. + return; + } + for (auto& e : b.linkData) + { + if (!e.linkStatus) + { + int destinationBlock = GetBlockNumberFromStartAddress(e.exitAddress); + if (destinationBlock != -1) + { + WriteLinkBlock(e.exitPtrs, blocks[destinationBlock]); + e.linkStatus = true; + } + } + } +} - void JitBaseBlockCache::LinkBlock(int i) - { - LinkBlockExits(i); - JitBlock &b = blocks[i]; - // equal_range(b) returns pair representing the range - // of element with key b - auto ppp = links_to.equal_range(b.originalAddress); +void JitBaseBlockCache::LinkBlock(int i) +{ + LinkBlockExits(i); + JitBlock& b = blocks[i]; + // equal_range(b) returns pair representing the range + // of element with key b + auto ppp = links_to.equal_range(b.originalAddress); - if (ppp.first == ppp.second) - return; + if (ppp.first == ppp.second) + return; - for (auto iter = ppp.first; iter != ppp.second; ++iter) - { - // PanicAlert("Linking block %i to block %i", iter->second, i); - LinkBlockExits(iter->second); - } - } + for (auto iter = ppp.first; iter != ppp.second; ++iter) + { + // PanicAlert("Linking block %i to block %i", iter->second, i); + LinkBlockExits(iter->second); + } +} - void JitBaseBlockCache::UnlinkBlock(int i) - { - JitBlock &b = blocks[i]; - auto ppp = links_to.equal_range(b.originalAddress); +void JitBaseBlockCache::UnlinkBlock(int i) +{ + JitBlock& b = blocks[i]; + auto ppp = links_to.equal_range(b.originalAddress); - if (ppp.first == ppp.second) - return; + if (ppp.first == ppp.second) + return; - for (auto iter = ppp.first; iter != ppp.second; ++iter) - { - JitBlock &sourceBlock = blocks[iter->second]; - for (auto& e : sourceBlock.linkData) - { - if (e.exitAddress == b.originalAddress) - e.linkStatus = false; - } - } - links_to.erase(b.originalAddress); - } + for (auto iter = ppp.first; iter != ppp.second; ++iter) + { + JitBlock& sourceBlock = blocks[iter->second]; + for (auto& e : sourceBlock.linkData) + { + if (e.exitAddress == b.originalAddress) + e.linkStatus = false; + } + } + links_to.erase(b.originalAddress); +} - void JitBaseBlockCache::DestroyBlock(int block_num, bool invalidate) - { - if (block_num < 0 || block_num >= num_blocks) - { - PanicAlert("DestroyBlock: Invalid block number %d", block_num); - return; - } - JitBlock &b = blocks[block_num]; - if (b.invalid) - { - if (invalidate) - PanicAlert("Invalidating invalid block %d", block_num); - return; - } - b.invalid = true; - std::memcpy(GetICachePtr(b.originalAddress), &JIT_ICACHE_INVALID_WORD, sizeof(u32)); +void JitBaseBlockCache::DestroyBlock(int block_num, bool invalidate) +{ + if (block_num < 0 || block_num >= num_blocks) + { + PanicAlert("DestroyBlock: Invalid block number %d", block_num); + return; + } + JitBlock& b = blocks[block_num]; + if (b.invalid) + { + if (invalidate) + PanicAlert("Invalidating invalid block %d", block_num); + return; + } + b.invalid = true; + std::memcpy(GetICachePtr(b.originalAddress), &JIT_ICACHE_INVALID_WORD, sizeof(u32)); - UnlinkBlock(block_num); + UnlinkBlock(block_num); - // Send anyone who tries to run this block back to the dispatcher. - // Not entirely ideal, but .. pretty good. - // Spurious entrances from previously linked blocks can only come through checkedEntry - WriteDestroyBlock(b.checkedEntry, b.originalAddress); - } + // Send anyone who tries to run this block back to the dispatcher. + // Not entirely ideal, but .. pretty good. + // Spurious entrances from previously linked blocks can only come through checkedEntry + WriteDestroyBlock(b.checkedEntry, b.originalAddress); +} - void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool forced) - { - // Convert the logical address to a physical address for the block map - u32 pAddr = address & 0x1FFFFFFF; +void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool forced) +{ + // Convert the logical address to a physical address for the block map + u32 pAddr = address & 0x1FFFFFFF; - // Optimize the common case of length == 32 which is used by Interpreter::dcb* - bool destroy_block = true; - if (length == 32) - { - if (!valid_block.Test(pAddr / 32)) - destroy_block = false; - else - valid_block.Clear(pAddr / 32); - } + // Optimize the common case of length == 32 which is used by Interpreter::dcb* + bool destroy_block = true; + if (length == 32) + { + if (!valid_block.Test(pAddr / 32)) + destroy_block = false; + else + valid_block.Clear(pAddr / 32); + } - // destroy JIT blocks - // !! this works correctly under assumption that any two overlapping blocks end at the same address - if (destroy_block) - { - std::map, u32>::iterator it1 = block_map.lower_bound(std::make_pair(pAddr, 0)), it2 = it1; - while (it2 != block_map.end() && it2->first.second < pAddr + length) - { - JitBlock &b = blocks[it2->second]; - std::memcpy(GetICachePtr(b.originalAddress), &JIT_ICACHE_INVALID_WORD, sizeof(u32)); + // destroy JIT blocks + // !! this works correctly under assumption that any two overlapping blocks end at the same + // address + if (destroy_block) + { + std::map, u32>::iterator it1 = block_map.lower_bound( + std::make_pair(pAddr, 0)), + it2 = it1; + while (it2 != block_map.end() && it2->first.second < pAddr + length) + { + JitBlock& b = blocks[it2->second]; + std::memcpy(GetICachePtr(b.originalAddress), &JIT_ICACHE_INVALID_WORD, sizeof(u32)); - DestroyBlock(it2->second, true); - ++it2; - } - if (it1 != it2) - { - block_map.erase(it1, it2); - } + DestroyBlock(it2->second, true); + ++it2; + } + if (it1 != it2) + { + block_map.erase(it1, it2); + } - // If the code was actually modified, we need to clear the relevant entries from the - // FIFO write address cache, so we don't end up with FIFO checks in places they shouldn't - // be (this can clobber flags, and thus break any optimization that relies on flags - // being in the right place between instructions). - if (!forced) - { - for (u32 i = address; i < address + length; i += 4) - { - jit->js.fifoWriteAddresses.erase(i); - jit->js.pairedQuantizeAddresses.erase(i); - } - } - } - } + // If the code was actually modified, we need to clear the relevant entries from the + // FIFO write address cache, so we don't end up with FIFO checks in places they shouldn't + // be (this can clobber flags, and thus break any optimization that relies on flags + // being in the right place between instructions). + if (!forced) + { + for (u32 i = address; i < address + length; i += 4) + { + jit->js.fifoWriteAddresses.erase(i); + jit->js.pairedQuantizeAddresses.erase(i); + } + } + } +} - void JitBlockCache::WriteLinkBlock(u8* location, const JitBlock& block) - { - const u8* address = block.checkedEntry; - XEmitter emit(location); - if (*location == 0xE8) - { - emit.CALL(address); - } - else - { - // If we're going to link with the next block, there is no need - // to emit JMP. So just NOP out the gap to the next block. - // Support up to 3 additional bytes because of alignment. - s64 offset = address - emit.GetCodePtr(); - if (offset > 0 && offset <= 5 + 3) - emit.NOP(offset); - else - emit.JMP(address, true); - } - } +void JitBlockCache::WriteLinkBlock(u8* location, const JitBlock& block) +{ + const u8* address = block.checkedEntry; + XEmitter emit(location); + if (*location == 0xE8) + { + emit.CALL(address); + } + else + { + // If we're going to link with the next block, there is no need + // to emit JMP. So just NOP out the gap to the next block. + // Support up to 3 additional bytes because of alignment. + s64 offset = address - emit.GetCodePtr(); + if (offset > 0 && offset <= 5 + 3) + emit.NOP(offset); + else + emit.JMP(address, true); + } +} - void JitBlockCache::WriteDestroyBlock(const u8* location, u32 address) - { - XEmitter emit((u8 *)location); - emit.MOV(32, PPCSTATE(pc), Imm32(address)); - emit.JMP(jit->GetAsmRoutines()->dispatcher, true); - } +void JitBlockCache::WriteDestroyBlock(const u8* location, u32 address) +{ + XEmitter emit((u8*)location); + emit.MOV(32, PPCSTATE(pc), Imm32(address)); + emit.JMP(jit->GetAsmRoutines()->dispatcher, true); +} diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/PowerPC/JitCommon/JitCache.h index 1216a8753a..131e0e2d3f 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.h @@ -17,7 +17,7 @@ static const u32 JIT_ICACHE_MASK = 0x1ffffff; static const u32 JIT_ICACHEEX_SIZE = 0x4000000; static const u32 JIT_ICACHEEX_MASK = 0x3ffffff; static const u32 JIT_ICACHE_EXRAM_BIT = 0x10000000; -static const u32 JIT_ICACHE_VMEM_BIT = 0x20000000; +static const u32 JIT_ICACHE_VMEM_BIT = 0x20000000; // This corresponds to opcode 5 which is invalid in PowerPC static const u32 JIT_ICACHE_INVALID_BYTE = 0x80; @@ -25,29 +25,29 @@ static const u32 JIT_ICACHE_INVALID_WORD = 0x80808080; struct JitBlock { - const u8 *checkedEntry; - const u8 *normalEntry; + const u8* checkedEntry; + const u8* normalEntry; - u32 originalAddress; - u32 codeSize; - u32 originalSize; - int runCount; // for profiling. + u32 originalAddress; + u32 codeSize; + u32 originalSize; + int runCount; // for profiling. - bool invalid; + bool invalid; - struct LinkData - { - u8 *exitPtrs; // to be able to rewrite the exit jum - u32 exitAddress; - bool linkStatus; // is it already linked? - }; - std::vector linkData; + struct LinkData + { + u8* exitPtrs; // to be able to rewrite the exit jum + u32 exitAddress; + bool linkStatus; // is it already linked? + }; + std::vector linkData; - // we don't really need to save start and stop - // TODO (mb2): ticStart and ticStop -> "local var" mean "in block" ... low priority ;) - u64 ticStart; // for profiling - time. - u64 ticStop; // for profiling - time. - u64 ticCounter; // for profiling - time. + // we don't really need to save start and stop + // TODO (mb2): ticStart and ticStop -> "local var" mean "in block" ... low priority ;) + u64 ticStart; // for profiling - time. + u64 ticStop; // for profiling - time. + u64 ticCounter; // for profiling - time. }; typedef void (*CompiledCode)(); @@ -57,113 +57,89 @@ typedef void (*CompiledCode)(); class ValidBlockBitSet final { public: - enum - { - VALID_BLOCK_MASK_SIZE = 0x20000000 / 32, - VALID_BLOCK_ALLOC_ELEMENTS = VALID_BLOCK_MASK_SIZE / 32 - }; - // Directly accessed by Jit64. - std::unique_ptr m_valid_block; + enum + { + VALID_BLOCK_MASK_SIZE = 0x20000000 / 32, + VALID_BLOCK_ALLOC_ELEMENTS = VALID_BLOCK_MASK_SIZE / 32 + }; + // Directly accessed by Jit64. + std::unique_ptr m_valid_block; - ValidBlockBitSet() - { - m_valid_block.reset(new u32[VALID_BLOCK_ALLOC_ELEMENTS]); - ClearAll(); - } + ValidBlockBitSet() + { + m_valid_block.reset(new u32[VALID_BLOCK_ALLOC_ELEMENTS]); + ClearAll(); + } - void Set(u32 bit) - { - m_valid_block[bit / 32] |= 1u << (bit % 32); - } - - void Clear(u32 bit) - { - m_valid_block[bit / 32] &= ~(1u << (bit % 32)); - } - - void ClearAll() - { - memset(m_valid_block.get(), 0, sizeof(u32) * VALID_BLOCK_ALLOC_ELEMENTS); - } - - bool Test(u32 bit) - { - return (m_valid_block[bit / 32] & (1u << (bit % 32))) != 0; - } + void Set(u32 bit) { m_valid_block[bit / 32] |= 1u << (bit % 32); } + void Clear(u32 bit) { m_valid_block[bit / 32] &= ~(1u << (bit % 32)); } + void ClearAll() { memset(m_valid_block.get(), 0, sizeof(u32) * VALID_BLOCK_ALLOC_ELEMENTS); } + bool Test(u32 bit) { return (m_valid_block[bit / 32] & (1u << (bit % 32))) != 0; } }; class JitBaseBlockCache { - enum - { - MAX_NUM_BLOCKS = 65536 * 2, - }; + enum + { + MAX_NUM_BLOCKS = 65536 * 2, + }; - std::array blockCodePointers; - std::array blocks; - int num_blocks; - std::multimap links_to; - std::map, u32> block_map; // (end_addr, start_addr) -> number - ValidBlockBitSet valid_block; + std::array blockCodePointers; + std::array blocks; + int num_blocks; + std::multimap links_to; + std::map, u32> block_map; // (end_addr, start_addr) -> number + ValidBlockBitSet valid_block; - bool m_initialized; + bool m_initialized; - void LinkBlockExits(int i); - void LinkBlock(int i); - void UnlinkBlock(int i); + void LinkBlockExits(int i); + void LinkBlock(int i); + void UnlinkBlock(int i); - u8* GetICachePtr(u32 addr); - void DestroyBlock(int block_num, bool invalidate); + u8* GetICachePtr(u32 addr); + void DestroyBlock(int block_num, bool invalidate); - // Virtual for overloaded - virtual void WriteLinkBlock(u8* location, const JitBlock& block) = 0; - virtual void WriteDestroyBlock(const u8* location, u32 address) = 0; + // Virtual for overloaded + virtual void WriteLinkBlock(u8* location, const JitBlock& block) = 0; + virtual void WriteDestroyBlock(const u8* location, u32 address) = 0; public: - JitBaseBlockCache() : num_blocks(0), m_initialized(false) - { - } + JitBaseBlockCache() : num_blocks(0), m_initialized(false) {} + virtual ~JitBaseBlockCache() {} + int AllocateBlock(u32 em_address); + void FinalizeBlock(int block_num, bool block_link, const u8* code_ptr); - virtual ~JitBaseBlockCache() - { - } + void Clear(); + void Init(); + void Shutdown(); + void Reset(); - int AllocateBlock(u32 em_address); - void FinalizeBlock(int block_num, bool block_link, const u8 *code_ptr); + bool IsFull() const; - void Clear(); - void Init(); - void Shutdown(); - void Reset(); + // Code Cache + JitBlock* GetBlock(int block_num); + int GetNumBlocks() const; + const u8** GetCodePointers(); + std::array iCache; + std::array iCacheEx; + std::array iCacheVMEM; - bool IsFull() const; + // Fast way to get a block. Only works on the first ppc instruction of a block. + int GetBlockNumberFromStartAddress(u32 em_address); - // Code Cache - JitBlock *GetBlock(int block_num); - int GetNumBlocks() const; - const u8 **GetCodePointers(); - std::array iCache; - std::array iCacheEx; - std::array iCacheVMEM; + CompiledCode GetCompiledCodeFromBlock(int block_num); - // Fast way to get a block. Only works on the first ppc instruction of a block. - int GetBlockNumberFromStartAddress(u32 em_address); + // DOES NOT WORK CORRECTLY WITH INLINING + void InvalidateICache(u32 address, const u32 length, bool forced); - CompiledCode GetCompiledCodeFromBlock(int block_num); - - // DOES NOT WORK CORRECTLY WITH INLINING - void InvalidateICache(u32 address, const u32 length, bool forced); - - u32* GetBlockBitSet() const - { - return valid_block.m_valid_block.get(); - } + u32* GetBlockBitSet() const { return valid_block.m_valid_block.get(); } }; // x86 BlockCache class JitBlockCache : public JitBaseBlockCache { private: - void WriteLinkBlock(u8* location, const JitBlock& block) override; - void WriteDestroyBlock(const u8* location, u32 address) override; + void WriteLinkBlock(u8* location, const JitBlock& block) override; + void WriteDestroyBlock(const u8* location, u32 address) override; }; diff --git a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp index 51549c69f2..ef4d5f3eef 100644 --- a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp @@ -2,78 +2,81 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/JitCommon/Jit_Util.h" #include "Common/BitSet.h" #include "Common/CommonTypes.h" #include "Common/Intrinsics.h" #include "Common/MathUtil.h" #include "Common/x64ABI.h" #include "Common/x64Emitter.h" -#include "Core/HW/Memmap.h" #include "Core/HW/MMIO.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/JitCommon/Jit_Util.h" +#include "Core/HW/Memmap.h" #include "Core/PowerPC/JitCommon/JitBase.h" +#include "Core/PowerPC/PowerPC.h" using namespace Gen; void EmuCodeBlock::MemoryExceptionCheck() { - if (jit->jo.memcheck && !jit->js.fastmemLoadStore && !jit->js.fixupExceptionHandler) - { - TEST(32, PPCSTATE(Exceptions), Gen::Imm32(EXCEPTION_DSI)); - jit->js.exceptionHandler = J_CC(Gen::CC_NZ, true); - jit->js.fixupExceptionHandler = true; - } + if (jit->jo.memcheck && !jit->js.fastmemLoadStore && !jit->js.fixupExceptionHandler) + { + TEST(32, PPCSTATE(Exceptions), Gen::Imm32(EXCEPTION_DSI)); + jit->js.exceptionHandler = J_CC(Gen::CC_NZ, true); + jit->js.fixupExceptionHandler = true; + } } -void EmuCodeBlock::UnsafeLoadRegToReg(X64Reg reg_addr, X64Reg reg_value, int accessSize, s32 offset, bool signExtend) +void EmuCodeBlock::UnsafeLoadRegToReg(X64Reg reg_addr, X64Reg reg_value, int accessSize, s32 offset, + bool signExtend) { - OpArg src = MComplex(RMEM, reg_addr, SCALE_1, offset); - LoadAndSwap(accessSize, reg_value, src, signExtend); + OpArg src = MComplex(RMEM, reg_addr, SCALE_1, offset); + LoadAndSwap(accessSize, reg_value, src, signExtend); } -void EmuCodeBlock::UnsafeLoadRegToRegNoSwap(X64Reg reg_addr, X64Reg reg_value, int accessSize, s32 offset, bool signExtend) +void EmuCodeBlock::UnsafeLoadRegToRegNoSwap(X64Reg reg_addr, X64Reg reg_value, int accessSize, + s32 offset, bool signExtend) { - if (signExtend) - MOVSX(32, accessSize, reg_value, MComplex(RMEM, reg_addr, SCALE_1, offset)); - else - MOVZX(32, accessSize, reg_value, MComplex(RMEM, reg_addr, SCALE_1, offset)); + if (signExtend) + MOVSX(32, accessSize, reg_value, MComplex(RMEM, reg_addr, SCALE_1, offset)); + else + MOVZX(32, accessSize, reg_value, MComplex(RMEM, reg_addr, SCALE_1, offset)); } -u8 *EmuCodeBlock::UnsafeLoadToReg(X64Reg reg_value, OpArg opAddress, int accessSize, s32 offset, bool signExtend) +u8* EmuCodeBlock::UnsafeLoadToReg(X64Reg reg_value, OpArg opAddress, int accessSize, s32 offset, + bool signExtend) { - u8 *result; - OpArg memOperand; - if (opAddress.IsSimpleReg()) - { - // Deal with potential wraparound. (This is just a heuristic, and it would - // be more correct to actually mirror the first page at the end, but the - // only case where it probably actually matters is JitIL turning adds into - // offsets with the wrong sign, so whatever. Since the original code - // *could* try to wrap an address around, however, this is the correct - // place to address the issue.) - if ((u32) offset >= 0x1000) - { - LEA(32, reg_value, MDisp(opAddress.GetSimpleReg(), offset)); - opAddress = R(reg_value); - offset = 0; - } - memOperand = MComplex(RMEM, opAddress.GetSimpleReg(), SCALE_1, offset); - } - else if (opAddress.IsImm()) - { - MOV(32, R(reg_value), Imm32((u32)(opAddress.Imm32() + offset))); - memOperand = MRegSum(RMEM, reg_value); - } - else - { - MOV(32, R(reg_value), opAddress); - memOperand = MComplex(RMEM, reg_value, SCALE_1, offset); - } + u8* result; + OpArg memOperand; + if (opAddress.IsSimpleReg()) + { + // Deal with potential wraparound. (This is just a heuristic, and it would + // be more correct to actually mirror the first page at the end, but the + // only case where it probably actually matters is JitIL turning adds into + // offsets with the wrong sign, so whatever. Since the original code + // *could* try to wrap an address around, however, this is the correct + // place to address the issue.) + if ((u32)offset >= 0x1000) + { + LEA(32, reg_value, MDisp(opAddress.GetSimpleReg(), offset)); + opAddress = R(reg_value); + offset = 0; + } + memOperand = MComplex(RMEM, opAddress.GetSimpleReg(), SCALE_1, offset); + } + else if (opAddress.IsImm()) + { + MOV(32, R(reg_value), Imm32((u32)(opAddress.Imm32() + offset))); + memOperand = MRegSum(RMEM, reg_value); + } + else + { + MOV(32, R(reg_value), opAddress); + memOperand = MComplex(RMEM, reg_value, SCALE_1, offset); + } - result = GetWritableCodePtr(); - LoadAndSwap(accessSize, reg_value, memOperand, signExtend); - return result; + result = GetWritableCodePtr(); + LoadAndSwap(accessSize, reg_value, memOperand, signExtend); + return result; } // Visitor that generates code to read a MMIO value. @@ -81,618 +84,630 @@ template class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor { public: - MMIOReadCodeGenerator(Gen::X64CodeBlock* code, BitSet32 registers_in_use, - Gen::X64Reg dst_reg, u32 address, bool sign_extend) - : m_code(code), m_registers_in_use(registers_in_use), m_dst_reg(dst_reg), - m_address(address), m_sign_extend(sign_extend) - { - } + MMIOReadCodeGenerator(Gen::X64CodeBlock* code, BitSet32 registers_in_use, Gen::X64Reg dst_reg, + u32 address, bool sign_extend) + : m_code(code), m_registers_in_use(registers_in_use), m_dst_reg(dst_reg), m_address(address), + m_sign_extend(sign_extend) + { + } - void VisitConstant(T value) override - { - LoadConstantToReg(8 * sizeof (T), value); - } - void VisitDirect(const T* addr, u32 mask) override - { - LoadAddrMaskToReg(8 * sizeof (T), addr, mask); - } - void VisitComplex(const std::function* lambda) override - { - CallLambda(8 * sizeof (T), lambda); - } + void VisitConstant(T value) override { LoadConstantToReg(8 * sizeof(T), value); } + void VisitDirect(const T* addr, u32 mask) override + { + LoadAddrMaskToReg(8 * sizeof(T), addr, mask); + } + void VisitComplex(const std::function* lambda) override + { + CallLambda(8 * sizeof(T), lambda); + } private: - // Generates code to load a constant to the destination register. In - // practice it would be better to avoid using a register for this, but it - // would require refactoring a lot of JIT code. - void LoadConstantToReg(int sbits, u32 value) - { - if (m_sign_extend) - { - u32 sign = !!(value & (1 << (sbits - 1))); - value |= sign * ((0xFFFFFFFF >> sbits) << sbits); - } - m_code->MOV(32, R(m_dst_reg), Gen::Imm32(value)); - } + // Generates code to load a constant to the destination register. In + // practice it would be better to avoid using a register for this, but it + // would require refactoring a lot of JIT code. + void LoadConstantToReg(int sbits, u32 value) + { + if (m_sign_extend) + { + u32 sign = !!(value & (1 << (sbits - 1))); + value |= sign * ((0xFFFFFFFF >> sbits) << sbits); + } + m_code->MOV(32, R(m_dst_reg), Gen::Imm32(value)); + } - // Generate the proper MOV instruction depending on whether the read should - // be sign extended or zero extended. - void MoveOpArgToReg(int sbits, const Gen::OpArg& arg) - { - if (m_sign_extend) - m_code->MOVSX(32, sbits, m_dst_reg, arg); - else - m_code->MOVZX(32, sbits, m_dst_reg, arg); - } + // Generate the proper MOV instruction depending on whether the read should + // be sign extended or zero extended. + void MoveOpArgToReg(int sbits, const Gen::OpArg& arg) + { + if (m_sign_extend) + m_code->MOVSX(32, sbits, m_dst_reg, arg); + else + m_code->MOVZX(32, sbits, m_dst_reg, arg); + } - void LoadAddrMaskToReg(int sbits, const void* ptr, u32 mask) - { - m_code->MOV(64, R(RSCRATCH), ImmPtr(ptr)); - // If we do not need to mask, we can do the sign extend while loading - // from memory. If masking is required, we have to first zero extend, - // then mask, then sign extend if needed (1 instr vs. 2/3). - u32 all_ones = (1ULL << sbits) - 1; - if ((all_ones & mask) == all_ones) - { - MoveOpArgToReg(sbits, MatR(RSCRATCH)); - } - else - { - m_code->MOVZX(32, sbits, m_dst_reg, MatR(RSCRATCH)); - m_code->AND(32, R(m_dst_reg), Imm32(mask)); - if (m_sign_extend) - m_code->MOVSX(32, sbits, m_dst_reg, R(m_dst_reg)); - } - } + void LoadAddrMaskToReg(int sbits, const void* ptr, u32 mask) + { + m_code->MOV(64, R(RSCRATCH), ImmPtr(ptr)); + // If we do not need to mask, we can do the sign extend while loading + // from memory. If masking is required, we have to first zero extend, + // then mask, then sign extend if needed (1 instr vs. 2/3). + u32 all_ones = (1ULL << sbits) - 1; + if ((all_ones & mask) == all_ones) + { + MoveOpArgToReg(sbits, MatR(RSCRATCH)); + } + else + { + m_code->MOVZX(32, sbits, m_dst_reg, MatR(RSCRATCH)); + m_code->AND(32, R(m_dst_reg), Imm32(mask)); + if (m_sign_extend) + m_code->MOVSX(32, sbits, m_dst_reg, R(m_dst_reg)); + } + } - void CallLambda(int sbits, const std::function* lambda) - { - m_code->ABI_PushRegistersAndAdjustStack(m_registers_in_use, 0); - m_code->ABI_CallLambdaC(lambda, m_address); - m_code->ABI_PopRegistersAndAdjustStack(m_registers_in_use, 0); - MoveOpArgToReg(sbits, R(ABI_RETURN)); - } + void CallLambda(int sbits, const std::function* lambda) + { + m_code->ABI_PushRegistersAndAdjustStack(m_registers_in_use, 0); + m_code->ABI_CallLambdaC(lambda, m_address); + m_code->ABI_PopRegistersAndAdjustStack(m_registers_in_use, 0); + MoveOpArgToReg(sbits, R(ABI_RETURN)); + } - Gen::X64CodeBlock* m_code; - BitSet32 m_registers_in_use; - Gen::X64Reg m_dst_reg; - u32 m_address; - bool m_sign_extend; + Gen::X64CodeBlock* m_code; + BitSet32 m_registers_in_use; + Gen::X64Reg m_dst_reg; + u32 m_address; + bool m_sign_extend; }; void EmuCodeBlock::MMIOLoadToReg(MMIO::Mapping* mmio, Gen::X64Reg reg_value, - BitSet32 registers_in_use, u32 address, - int access_size, bool sign_extend) + BitSet32 registers_in_use, u32 address, int access_size, + bool sign_extend) { - switch (access_size) - { - case 8: - { - MMIOReadCodeGenerator gen(this, registers_in_use, reg_value, - address, sign_extend); - mmio->GetHandlerForRead(address).Visit(gen); - break; - } - case 16: - { - MMIOReadCodeGenerator gen(this, registers_in_use, reg_value, - address, sign_extend); - mmio->GetHandlerForRead(address).Visit(gen); - break; - } - case 32: - { - MMIOReadCodeGenerator gen(this, registers_in_use, reg_value, - address, sign_extend); - mmio->GetHandlerForRead(address).Visit(gen); - break; - } - } + switch (access_size) + { + case 8: + { + MMIOReadCodeGenerator gen(this, registers_in_use, reg_value, address, sign_extend); + mmio->GetHandlerForRead(address).Visit(gen); + break; + } + case 16: + { + MMIOReadCodeGenerator gen(this, registers_in_use, reg_value, address, sign_extend); + mmio->GetHandlerForRead(address).Visit(gen); + break; + } + case 32: + { + MMIOReadCodeGenerator gen(this, registers_in_use, reg_value, address, sign_extend); + mmio->GetHandlerForRead(address).Visit(gen); + break; + } + } } -FixupBranch EmuCodeBlock::CheckIfSafeAddress(const OpArg& reg_value, X64Reg reg_addr, BitSet32 registers_in_use, u32 mem_mask) +FixupBranch EmuCodeBlock::CheckIfSafeAddress(const OpArg& reg_value, X64Reg reg_addr, + BitSet32 registers_in_use, u32 mem_mask) { - registers_in_use[reg_addr] = true; - if (reg_value.IsSimpleReg()) - registers_in_use[reg_value.GetSimpleReg()] = true; + registers_in_use[reg_addr] = true; + if (reg_value.IsSimpleReg()) + registers_in_use[reg_value.GetSimpleReg()] = true; - // Get ourselves a free register; try to pick one that doesn't involve pushing, if we can. - X64Reg scratch = RSCRATCH; - if (!registers_in_use[RSCRATCH]) - scratch = RSCRATCH; - else if (!registers_in_use[RSCRATCH_EXTRA]) - scratch = RSCRATCH_EXTRA; - else - scratch = reg_addr; + // Get ourselves a free register; try to pick one that doesn't involve pushing, if we can. + X64Reg scratch = RSCRATCH; + if (!registers_in_use[RSCRATCH]) + scratch = RSCRATCH; + else if (!registers_in_use[RSCRATCH_EXTRA]) + scratch = RSCRATCH_EXTRA; + else + scratch = reg_addr; - // On Gamecube games with MMU, do a little bit of extra work to make sure we're not accessing the - // 0x81800000 to 0x83FFFFFF range. - // It's okay to take a shortcut and not check this range on non-MMU games, since we're already - // assuming they'll never do an invalid memory access. - // The slightly more complex check needed for Wii games using the space just above MEM1 isn't - // implemented here yet, since there are no known working Wii MMU games to test it with. - if (jit->jo.memcheck && !SConfig::GetInstance().bWii) - { - if (scratch == reg_addr) - PUSH(scratch); - else - MOV(32, R(scratch), R(reg_addr)); - AND(32, R(scratch), Imm32(0x3FFFFFFF)); - CMP(32, R(scratch), Imm32(0x01800000)); - if (scratch == reg_addr) - POP(scratch); - return J_CC(CC_AE, farcode.Enabled()); - } - else - { - TEST(32, R(reg_addr), Imm32(mem_mask)); - return J_CC(CC_NZ, farcode.Enabled()); - } + // On Gamecube games with MMU, do a little bit of extra work to make sure we're not accessing the + // 0x81800000 to 0x83FFFFFF range. + // It's okay to take a shortcut and not check this range on non-MMU games, since we're already + // assuming they'll never do an invalid memory access. + // The slightly more complex check needed for Wii games using the space just above MEM1 isn't + // implemented here yet, since there are no known working Wii MMU games to test it with. + if (jit->jo.memcheck && !SConfig::GetInstance().bWii) + { + if (scratch == reg_addr) + PUSH(scratch); + else + MOV(32, R(scratch), R(reg_addr)); + AND(32, R(scratch), Imm32(0x3FFFFFFF)); + CMP(32, R(scratch), Imm32(0x01800000)); + if (scratch == reg_addr) + POP(scratch); + return J_CC(CC_AE, farcode.Enabled()); + } + else + { + TEST(32, R(reg_addr), Imm32(mem_mask)); + return J_CC(CC_NZ, farcode.Enabled()); + } } -void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg & opAddress, int accessSize, s32 offset, BitSet32 registersInUse, bool signExtend, int flags) +void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg& opAddress, int accessSize, + s32 offset, BitSet32 registersInUse, bool signExtend, int flags) { - registersInUse[reg_value] = false; - if (jit->jo.fastmem && - !opAddress.IsImm() && - !(flags & (SAFE_LOADSTORE_NO_SWAP | SAFE_LOADSTORE_NO_FASTMEM))) - { - u8 *mov = UnsafeLoadToReg(reg_value, opAddress, accessSize, offset, signExtend); + registersInUse[reg_value] = false; + if (jit->jo.fastmem && !opAddress.IsImm() && + !(flags & (SAFE_LOADSTORE_NO_SWAP | SAFE_LOADSTORE_NO_FASTMEM))) + { + u8* mov = UnsafeLoadToReg(reg_value, opAddress, accessSize, offset, signExtend); - registersInUseAtLoc[mov] = registersInUse; - jit->js.fastmemLoadStore = mov; - return; - } + registersInUseAtLoc[mov] = registersInUse; + jit->js.fastmemLoadStore = mov; + return; + } - u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS; + u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS; - // The following masks the region used by the GC/Wii virtual memory lib - mem_mask |= Memory::ADDR_MASK_MEM1; + // The following masks the region used by the GC/Wii virtual memory lib + mem_mask |= Memory::ADDR_MASK_MEM1; - if (opAddress.IsImm()) - { - u32 address = opAddress.Imm32() + offset; + if (opAddress.IsImm()) + { + u32 address = opAddress.Imm32() + offset; - // If the address is known to be RAM, just load it directly. - if (PowerPC::IsOptimizableRAMAddress(address)) - { - UnsafeLoadToReg(reg_value, opAddress, accessSize, offset, signExtend); - return; - } + // If the address is known to be RAM, just load it directly. + if (PowerPC::IsOptimizableRAMAddress(address)) + { + UnsafeLoadToReg(reg_value, opAddress, accessSize, offset, signExtend); + return; + } - // If the address maps to an MMIO register, inline MMIO read code. - u32 mmioAddress = PowerPC::IsOptimizableMMIOAccess(address, accessSize); - if (accessSize != 64 && mmioAddress) - { - MMIOLoadToReg(Memory::mmio_mapping.get(), reg_value, registersInUse, - mmioAddress, accessSize, signExtend); - return; - } + // If the address maps to an MMIO register, inline MMIO read code. + u32 mmioAddress = PowerPC::IsOptimizableMMIOAccess(address, accessSize); + if (accessSize != 64 && mmioAddress) + { + MMIOLoadToReg(Memory::mmio_mapping.get(), reg_value, registersInUse, mmioAddress, accessSize, + signExtend); + return; + } - // Fall back to general-case code. - ABI_PushRegistersAndAdjustStack(registersInUse, 0); - switch (accessSize) - { - case 64: ABI_CallFunctionC((void *)&PowerPC::Read_U64, address); break; - case 32: ABI_CallFunctionC((void *)&PowerPC::Read_U32, address); break; - case 16: ABI_CallFunctionC((void *)&PowerPC::Read_U16_ZX, address); break; - case 8: ABI_CallFunctionC((void *)&PowerPC::Read_U8_ZX, address); break; - } - ABI_PopRegistersAndAdjustStack(registersInUse, 0); + // Fall back to general-case code. + ABI_PushRegistersAndAdjustStack(registersInUse, 0); + switch (accessSize) + { + case 64: + ABI_CallFunctionC((void*)&PowerPC::Read_U64, address); + break; + case 32: + ABI_CallFunctionC((void*)&PowerPC::Read_U32, address); + break; + case 16: + ABI_CallFunctionC((void*)&PowerPC::Read_U16_ZX, address); + break; + case 8: + ABI_CallFunctionC((void*)&PowerPC::Read_U8_ZX, address); + break; + } + ABI_PopRegistersAndAdjustStack(registersInUse, 0); - MemoryExceptionCheck(); - if (signExtend && accessSize < 32) - { - // Need to sign extend values coming from the Read_U* functions. - MOVSX(32, accessSize, reg_value, R(ABI_RETURN)); - } - else if (reg_value != ABI_RETURN) - { - MOVZX(64, accessSize, reg_value, R(ABI_RETURN)); - } + MemoryExceptionCheck(); + if (signExtend && accessSize < 32) + { + // Need to sign extend values coming from the Read_U* functions. + MOVSX(32, accessSize, reg_value, R(ABI_RETURN)); + } + else if (reg_value != ABI_RETURN) + { + MOVZX(64, accessSize, reg_value, R(ABI_RETURN)); + } - return; - } + return; + } - _assert_msg_(DYNA_REC, opAddress.IsSimpleReg(), "Incorrect use of SafeLoadToReg (address isn't register or immediate)"); - X64Reg reg_addr = opAddress.GetSimpleReg(); - if (offset) - { - reg_addr = RSCRATCH; - LEA(32, RSCRATCH, MDisp(opAddress.GetSimpleReg(), offset)); - } + _assert_msg_(DYNA_REC, opAddress.IsSimpleReg(), + "Incorrect use of SafeLoadToReg (address isn't register or immediate)"); + X64Reg reg_addr = opAddress.GetSimpleReg(); + if (offset) + { + reg_addr = RSCRATCH; + LEA(32, RSCRATCH, MDisp(opAddress.GetSimpleReg(), offset)); + } - FixupBranch exit; - if (!jit->jo.alwaysUseMemFuncs) - { - FixupBranch slow = CheckIfSafeAddress(R(reg_value), reg_addr, registersInUse, mem_mask); - UnsafeLoadToReg(reg_value, R(reg_addr), accessSize, 0, signExtend); - if (farcode.Enabled()) - SwitchToFarCode(); - else - exit = J(true); - SetJumpTarget(slow); - } - size_t rsp_alignment = (flags & SAFE_LOADSTORE_NO_PROLOG) ? 8 : 0; - ABI_PushRegistersAndAdjustStack(registersInUse, rsp_alignment); - switch (accessSize) - { - case 64: - ABI_CallFunctionR((void *)&PowerPC::Read_U64, reg_addr); - break; - case 32: - ABI_CallFunctionR((void *)&PowerPC::Read_U32, reg_addr); - break; - case 16: - ABI_CallFunctionR((void *)&PowerPC::Read_U16_ZX, reg_addr); - break; - case 8: - ABI_CallFunctionR((void *)&PowerPC::Read_U8_ZX, reg_addr); - break; - } - ABI_PopRegistersAndAdjustStack(registersInUse, rsp_alignment); + FixupBranch exit; + if (!jit->jo.alwaysUseMemFuncs) + { + FixupBranch slow = CheckIfSafeAddress(R(reg_value), reg_addr, registersInUse, mem_mask); + UnsafeLoadToReg(reg_value, R(reg_addr), accessSize, 0, signExtend); + if (farcode.Enabled()) + SwitchToFarCode(); + else + exit = J(true); + SetJumpTarget(slow); + } + size_t rsp_alignment = (flags & SAFE_LOADSTORE_NO_PROLOG) ? 8 : 0; + ABI_PushRegistersAndAdjustStack(registersInUse, rsp_alignment); + switch (accessSize) + { + case 64: + ABI_CallFunctionR((void*)&PowerPC::Read_U64, reg_addr); + break; + case 32: + ABI_CallFunctionR((void*)&PowerPC::Read_U32, reg_addr); + break; + case 16: + ABI_CallFunctionR((void*)&PowerPC::Read_U16_ZX, reg_addr); + break; + case 8: + ABI_CallFunctionR((void*)&PowerPC::Read_U8_ZX, reg_addr); + break; + } + ABI_PopRegistersAndAdjustStack(registersInUse, rsp_alignment); - MemoryExceptionCheck(); - if (signExtend && accessSize < 32) - { - // Need to sign extend values coming from the Read_U* functions. - MOVSX(32, accessSize, reg_value, R(ABI_RETURN)); - } - else if (reg_value != ABI_RETURN) - { - MOVZX(64, accessSize, reg_value, R(ABI_RETURN)); - } + MemoryExceptionCheck(); + if (signExtend && accessSize < 32) + { + // Need to sign extend values coming from the Read_U* functions. + MOVSX(32, accessSize, reg_value, R(ABI_RETURN)); + } + else if (reg_value != ABI_RETURN) + { + MOVZX(64, accessSize, reg_value, R(ABI_RETURN)); + } - if (!jit->jo.alwaysUseMemFuncs) - { - if (farcode.Enabled()) - { - exit = J(true); - SwitchToNearCode(); - } - SetJumpTarget(exit); - } + if (!jit->jo.alwaysUseMemFuncs) + { + if (farcode.Enabled()) + { + exit = J(true); + SwitchToNearCode(); + } + SetJumpTarget(exit); + } } static OpArg SwapImmediate(int accessSize, const OpArg& reg_value) { - if (accessSize == 32) - return Imm32(Common::swap32(reg_value.Imm32())); - else if (accessSize == 16) - return Imm16(Common::swap16(reg_value.Imm16())); - else - return Imm8(reg_value.Imm8()); + if (accessSize == 32) + return Imm32(Common::swap32(reg_value.Imm32())); + else if (accessSize == 16) + return Imm16(Common::swap16(reg_value.Imm16())); + else + return Imm8(reg_value.Imm8()); } -u8 *EmuCodeBlock::UnsafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int accessSize, s32 offset, bool swap) +u8* EmuCodeBlock::UnsafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int accessSize, s32 offset, + bool swap) { - u8* result = GetWritableCodePtr(); - OpArg dest = MComplex(RMEM, reg_addr, SCALE_1, offset); - if (reg_value.IsImm()) - { - if (swap) - reg_value = SwapImmediate(accessSize, reg_value); - MOV(accessSize, dest, reg_value); - } - else if (swap) - { - result = SwapAndStore(accessSize, dest, reg_value.GetSimpleReg()); - } - else - { - MOV(accessSize, dest, reg_value); - } + u8* result = GetWritableCodePtr(); + OpArg dest = MComplex(RMEM, reg_addr, SCALE_1, offset); + if (reg_value.IsImm()) + { + if (swap) + reg_value = SwapImmediate(accessSize, reg_value); + MOV(accessSize, dest, reg_value); + } + else if (swap) + { + result = SwapAndStore(accessSize, dest, reg_value.GetSimpleReg()); + } + else + { + MOV(accessSize, dest, reg_value); + } - return result; + return result; } static OpArg FixImmediate(int accessSize, OpArg arg) { - if (arg.IsImm()) - { - arg = accessSize == 8 ? Imm8((u8)arg.Imm32()) : - accessSize == 16 ? Imm16((u16)arg.Imm32()) : - Imm32((u32)arg.Imm32()); - } - return arg; + if (arg.IsImm()) + { + arg = accessSize == 8 ? Imm8((u8)arg.Imm32()) : accessSize == 16 ? Imm16((u16)arg.Imm32()) : + Imm32((u32)arg.Imm32()); + } + return arg; } void EmuCodeBlock::UnsafeWriteGatherPipe(int accessSize) { - // No need to protect these, they don't touch any state - // question - should we inline them instead? Pro: Lose a CALL Con: Code bloat - switch (accessSize) - { - case 8: - CALL(jit->GetAsmRoutines()->fifoDirectWrite8); - break; - case 16: - CALL(jit->GetAsmRoutines()->fifoDirectWrite16); - break; - case 32: - CALL(jit->GetAsmRoutines()->fifoDirectWrite32); - break; - case 64: - CALL(jit->GetAsmRoutines()->fifoDirectWrite64); - break; - } - jit->js.fifoBytesThisBlock += accessSize >> 3; + // No need to protect these, they don't touch any state + // question - should we inline them instead? Pro: Lose a CALL Con: Code bloat + switch (accessSize) + { + case 8: + CALL(jit->GetAsmRoutines()->fifoDirectWrite8); + break; + case 16: + CALL(jit->GetAsmRoutines()->fifoDirectWrite16); + break; + case 32: + CALL(jit->GetAsmRoutines()->fifoDirectWrite32); + break; + case 64: + CALL(jit->GetAsmRoutines()->fifoDirectWrite64); + break; + } + jit->js.fifoBytesThisBlock += accessSize >> 3; } -bool EmuCodeBlock::WriteToConstAddress(int accessSize, OpArg arg, u32 address, BitSet32 registersInUse) +bool EmuCodeBlock::WriteToConstAddress(int accessSize, OpArg arg, u32 address, + BitSet32 registersInUse) { - arg = FixImmediate(accessSize, arg); + arg = FixImmediate(accessSize, arg); - // If we already know the address through constant folding, we can do some - // fun tricks... - if (jit->jo.optimizeGatherPipe && PowerPC::IsOptimizableGatherPipeWrite(address)) - { - if (!arg.IsSimpleReg(RSCRATCH)) - MOV(accessSize, R(RSCRATCH), arg); + // If we already know the address through constant folding, we can do some + // fun tricks... + if (jit->jo.optimizeGatherPipe && PowerPC::IsOptimizableGatherPipeWrite(address)) + { + if (!arg.IsSimpleReg(RSCRATCH)) + MOV(accessSize, R(RSCRATCH), arg); - UnsafeWriteGatherPipe(accessSize); - return false; - } - else if (PowerPC::IsOptimizableRAMAddress(address)) - { - WriteToConstRamAddress(accessSize, arg, address); - return false; - } - else - { - // Helps external systems know which instruction triggered the write - MOV(32, PPCSTATE(pc), Imm32(jit->js.compilerPC)); + UnsafeWriteGatherPipe(accessSize); + return false; + } + else if (PowerPC::IsOptimizableRAMAddress(address)) + { + WriteToConstRamAddress(accessSize, arg, address); + return false; + } + else + { + // Helps external systems know which instruction triggered the write + MOV(32, PPCSTATE(pc), Imm32(jit->js.compilerPC)); - ABI_PushRegistersAndAdjustStack(registersInUse, 0); - switch (accessSize) - { - case 64: - ABI_CallFunctionAC(64, (void *)&PowerPC::Write_U64, arg, address); - break; - case 32: - ABI_CallFunctionAC(32, (void *)&PowerPC::Write_U32, arg, address); - break; - case 16: - ABI_CallFunctionAC(16, (void *)&PowerPC::Write_U16, arg, address); - break; - case 8: - ABI_CallFunctionAC(8, (void *)&PowerPC::Write_U8, arg, address); - break; - } - ABI_PopRegistersAndAdjustStack(registersInUse, 0); - return true; - } + ABI_PushRegistersAndAdjustStack(registersInUse, 0); + switch (accessSize) + { + case 64: + ABI_CallFunctionAC(64, (void*)&PowerPC::Write_U64, arg, address); + break; + case 32: + ABI_CallFunctionAC(32, (void*)&PowerPC::Write_U32, arg, address); + break; + case 16: + ABI_CallFunctionAC(16, (void*)&PowerPC::Write_U16, arg, address); + break; + case 8: + ABI_CallFunctionAC(8, (void*)&PowerPC::Write_U8, arg, address); + break; + } + ABI_PopRegistersAndAdjustStack(registersInUse, 0); + return true; + } } -void EmuCodeBlock::SafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int accessSize, s32 offset, BitSet32 registersInUse, int flags) +void EmuCodeBlock::SafeWriteRegToReg(OpArg reg_value, X64Reg reg_addr, int accessSize, s32 offset, + BitSet32 registersInUse, int flags) { - // set the correct immediate format - reg_value = FixImmediate(accessSize, reg_value); + // set the correct immediate format + reg_value = FixImmediate(accessSize, reg_value); - // TODO: support byte-swapped non-immediate fastmem stores - if (jit->jo.fastmem && - !(flags & SAFE_LOADSTORE_NO_FASTMEM) && - (reg_value.IsImm() || !(flags & SAFE_LOADSTORE_NO_SWAP))) - { - const u8* backpatchStart = GetCodePtr(); - u8* mov = UnsafeWriteRegToReg(reg_value, reg_addr, accessSize, offset, !(flags & SAFE_LOADSTORE_NO_SWAP)); - ptrdiff_t padding = BACKPATCH_SIZE - (GetCodePtr() - backpatchStart); - if (padding > 0) - { - NOP(padding); - } + // TODO: support byte-swapped non-immediate fastmem stores + if (jit->jo.fastmem && !(flags & SAFE_LOADSTORE_NO_FASTMEM) && + (reg_value.IsImm() || !(flags & SAFE_LOADSTORE_NO_SWAP))) + { + const u8* backpatchStart = GetCodePtr(); + u8* mov = UnsafeWriteRegToReg(reg_value, reg_addr, accessSize, offset, + !(flags & SAFE_LOADSTORE_NO_SWAP)); + ptrdiff_t padding = BACKPATCH_SIZE - (GetCodePtr() - backpatchStart); + if (padding > 0) + { + NOP(padding); + } - registersInUseAtLoc[mov] = registersInUse; - pcAtLoc[mov] = jit->js.compilerPC; - jit->js.fastmemLoadStore = mov; - return; - } + registersInUseAtLoc[mov] = registersInUse; + pcAtLoc[mov] = jit->js.compilerPC; + jit->js.fastmemLoadStore = mov; + return; + } - if (offset) - { - if (flags & SAFE_LOADSTORE_CLOBBER_RSCRATCH_INSTEAD_OF_ADDR) - { - LEA(32, RSCRATCH, MDisp(reg_addr, (u32)offset)); - reg_addr = RSCRATCH; - } - else - { - ADD(32, R(reg_addr), Imm32((u32)offset)); - } - } + if (offset) + { + if (flags & SAFE_LOADSTORE_CLOBBER_RSCRATCH_INSTEAD_OF_ADDR) + { + LEA(32, RSCRATCH, MDisp(reg_addr, (u32)offset)); + reg_addr = RSCRATCH; + } + else + { + ADD(32, R(reg_addr), Imm32((u32)offset)); + } + } - u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS; + u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS; - // The following masks the region used by the GC/Wii virtual memory lib - mem_mask |= Memory::ADDR_MASK_MEM1; + // The following masks the region used by the GC/Wii virtual memory lib + mem_mask |= Memory::ADDR_MASK_MEM1; - bool swap = !(flags & SAFE_LOADSTORE_NO_SWAP); + bool swap = !(flags & SAFE_LOADSTORE_NO_SWAP); - FixupBranch slow, exit; - slow = CheckIfSafeAddress(reg_value, reg_addr, registersInUse, mem_mask); - UnsafeWriteRegToReg(reg_value, reg_addr, accessSize, 0, swap); - if (farcode.Enabled()) - SwitchToFarCode(); - else - exit = J(true); - SetJumpTarget(slow); + FixupBranch slow, exit; + slow = CheckIfSafeAddress(reg_value, reg_addr, registersInUse, mem_mask); + UnsafeWriteRegToReg(reg_value, reg_addr, accessSize, 0, swap); + if (farcode.Enabled()) + SwitchToFarCode(); + else + exit = J(true); + SetJumpTarget(slow); - // PC is used by memory watchpoints (if enabled) or to print accurate PC locations in debug logs - MOV(32, PPCSTATE(pc), Imm32(jit->js.compilerPC)); + // PC is used by memory watchpoints (if enabled) or to print accurate PC locations in debug logs + MOV(32, PPCSTATE(pc), Imm32(jit->js.compilerPC)); - size_t rsp_alignment = (flags & SAFE_LOADSTORE_NO_PROLOG) ? 8 : 0; - ABI_PushRegistersAndAdjustStack(registersInUse, rsp_alignment); + size_t rsp_alignment = (flags & SAFE_LOADSTORE_NO_PROLOG) ? 8 : 0; + ABI_PushRegistersAndAdjustStack(registersInUse, rsp_alignment); - // If the input is an immediate, we need to put it in a register. - X64Reg reg; - if (reg_value.IsImm()) - { - reg = reg_addr == ABI_PARAM1 ? RSCRATCH : ABI_PARAM1; - MOV(accessSize, R(reg), reg_value); - } - else - { - reg = reg_value.GetSimpleReg(); - } + // If the input is an immediate, we need to put it in a register. + X64Reg reg; + if (reg_value.IsImm()) + { + reg = reg_addr == ABI_PARAM1 ? RSCRATCH : ABI_PARAM1; + MOV(accessSize, R(reg), reg_value); + } + else + { + reg = reg_value.GetSimpleReg(); + } - switch (accessSize) - { - case 64: - ABI_CallFunctionRR(swap ? ((void *)&PowerPC::Write_U64) : ((void *)&PowerPC::Write_U64_Swap), reg, reg_addr); - break; - case 32: - ABI_CallFunctionRR(swap ? ((void *)&PowerPC::Write_U32) : ((void *)&PowerPC::Write_U32_Swap), reg, reg_addr); - break; - case 16: - ABI_CallFunctionRR(swap ? ((void *)&PowerPC::Write_U16) : ((void *)&PowerPC::Write_U16_Swap), reg, reg_addr); - break; - case 8: - ABI_CallFunctionRR((void *)&PowerPC::Write_U8, reg, reg_addr); - break; - } - ABI_PopRegistersAndAdjustStack(registersInUse, rsp_alignment); - if (farcode.Enabled()) - { - exit = J(true); - SwitchToNearCode(); - } - SetJumpTarget(exit); + switch (accessSize) + { + case 64: + ABI_CallFunctionRR(swap ? ((void*)&PowerPC::Write_U64) : ((void*)&PowerPC::Write_U64_Swap), reg, + reg_addr); + break; + case 32: + ABI_CallFunctionRR(swap ? ((void*)&PowerPC::Write_U32) : ((void*)&PowerPC::Write_U32_Swap), reg, + reg_addr); + break; + case 16: + ABI_CallFunctionRR(swap ? ((void*)&PowerPC::Write_U16) : ((void*)&PowerPC::Write_U16_Swap), reg, + reg_addr); + break; + case 8: + ABI_CallFunctionRR((void*)&PowerPC::Write_U8, reg, reg_addr); + break; + } + ABI_PopRegistersAndAdjustStack(registersInUse, rsp_alignment); + if (farcode.Enabled()) + { + exit = J(true); + SwitchToNearCode(); + } + SetJumpTarget(exit); } void EmuCodeBlock::WriteToConstRamAddress(int accessSize, OpArg arg, u32 address, bool swap) { - X64Reg reg; - if (arg.IsImm()) - { - arg = SwapImmediate(accessSize, arg); - MOV(32, R(RSCRATCH), Imm32(address)); - MOV(accessSize, MRegSum(RMEM, RSCRATCH), arg); - return; - } + X64Reg reg; + if (arg.IsImm()) + { + arg = SwapImmediate(accessSize, arg); + MOV(32, R(RSCRATCH), Imm32(address)); + MOV(accessSize, MRegSum(RMEM, RSCRATCH), arg); + return; + } - if (!arg.IsSimpleReg() || (!cpu_info.bMOVBE && swap && arg.GetSimpleReg() != RSCRATCH)) - { - MOV(accessSize, R(RSCRATCH), arg); - reg = RSCRATCH; - } - else - { - reg = arg.GetSimpleReg(); - } + if (!arg.IsSimpleReg() || (!cpu_info.bMOVBE && swap && arg.GetSimpleReg() != RSCRATCH)) + { + MOV(accessSize, R(RSCRATCH), arg); + reg = RSCRATCH; + } + else + { + reg = arg.GetSimpleReg(); + } - MOV(32, R(RSCRATCH2), Imm32(address)); - if (swap) - SwapAndStore(accessSize, MRegSum(RMEM, RSCRATCH2), reg); - else - MOV(accessSize, MRegSum(RMEM, RSCRATCH2), R(reg)); + MOV(32, R(RSCRATCH2), Imm32(address)); + if (swap) + SwapAndStore(accessSize, MRegSum(RMEM, RSCRATCH2), reg); + else + MOV(accessSize, MRegSum(RMEM, RSCRATCH2), R(reg)); } -void EmuCodeBlock::ForceSinglePrecision(X64Reg output, const OpArg& input, bool packed, bool duplicate) +void EmuCodeBlock::ForceSinglePrecision(X64Reg output, const OpArg& input, bool packed, + bool duplicate) { - // Most games don't need these. Zelda requires it though - some platforms get stuck without them. - if (jit->jo.accurateSinglePrecision) - { - if (packed) - { - CVTPD2PS(output, input); - CVTPS2PD(output, R(output)); - } - else - { - CVTSD2SS(output, input); - CVTSS2SD(output, R(output)); - if (duplicate) - MOVDDUP(output, R(output)); - } - } - else if (!input.IsSimpleReg(output)) - { - if (duplicate) - MOVDDUP(output, input); - else - MOVAPD(output, input); - } + // Most games don't need these. Zelda requires it though - some platforms get stuck without them. + if (jit->jo.accurateSinglePrecision) + { + if (packed) + { + CVTPD2PS(output, input); + CVTPS2PD(output, R(output)); + } + else + { + CVTSD2SS(output, input); + CVTSS2SD(output, R(output)); + if (duplicate) + MOVDDUP(output, R(output)); + } + } + else if (!input.IsSimpleReg(output)) + { + if (duplicate) + MOVDDUP(output, input); + else + MOVAPD(output, input); + } } // Abstract between AVX and SSE: automatically handle 3-operand instructions -void EmuCodeBlock::avx_op(void (XEmitter::*avxOp)(X64Reg, X64Reg, const OpArg&), void (XEmitter::*sseOp)(X64Reg, const OpArg&), - X64Reg regOp, const OpArg& arg1, const OpArg& arg2, bool packed, bool reversible) +void EmuCodeBlock::avx_op(void (XEmitter::*avxOp)(X64Reg, X64Reg, const OpArg&), + void (XEmitter::*sseOp)(X64Reg, const OpArg&), X64Reg regOp, + const OpArg& arg1, const OpArg& arg2, bool packed, bool reversible) { - if (arg1.IsSimpleReg(regOp)) - { - (this->*sseOp)(regOp, arg2); - } - else if (arg1.IsSimpleReg() && cpu_info.bAVX) - { - (this->*avxOp)(regOp, arg1.GetSimpleReg(), arg2); - } - else if (arg2.IsSimpleReg(regOp)) - { - if (reversible) - { - (this->*sseOp)(regOp, arg1); - } - else - { - // The ugly case: regOp == arg2 without AVX, or with arg1 == memory - if (!arg1.IsSimpleReg(XMM0)) - MOVAPD(XMM0, arg1); - if (cpu_info.bAVX) - { - (this->*avxOp)(regOp, XMM0, arg2); - } - else - { - (this->*sseOp)(XMM0, arg2); - if (packed) - MOVAPD(regOp, R(XMM0)); - else - MOVSD(regOp, R(XMM0)); - } - } - } - else - { - if (packed) - MOVAPD(regOp, arg1); - else - MOVSD(regOp, arg1); - (this->*sseOp)(regOp, arg1 == arg2 ? R(regOp) : arg2); - } + if (arg1.IsSimpleReg(regOp)) + { + (this->*sseOp)(regOp, arg2); + } + else if (arg1.IsSimpleReg() && cpu_info.bAVX) + { + (this->*avxOp)(regOp, arg1.GetSimpleReg(), arg2); + } + else if (arg2.IsSimpleReg(regOp)) + { + if (reversible) + { + (this->*sseOp)(regOp, arg1); + } + else + { + // The ugly case: regOp == arg2 without AVX, or with arg1 == memory + if (!arg1.IsSimpleReg(XMM0)) + MOVAPD(XMM0, arg1); + if (cpu_info.bAVX) + { + (this->*avxOp)(regOp, XMM0, arg2); + } + else + { + (this->*sseOp)(XMM0, arg2); + if (packed) + MOVAPD(regOp, R(XMM0)); + else + MOVSD(regOp, R(XMM0)); + } + } + } + else + { + if (packed) + MOVAPD(regOp, arg1); + else + MOVSD(regOp, arg1); + (this->*sseOp)(regOp, arg1 == arg2 ? R(regOp) : arg2); + } } // Abstract between AVX and SSE: automatically handle 3-operand instructions -void EmuCodeBlock::avx_op(void (XEmitter::*avxOp)(X64Reg, X64Reg, const OpArg&, u8), void (XEmitter::*sseOp)(X64Reg, const OpArg&, u8), - X64Reg regOp, const OpArg& arg1, const OpArg& arg2, u8 imm) +void EmuCodeBlock::avx_op(void (XEmitter::*avxOp)(X64Reg, X64Reg, const OpArg&, u8), + void (XEmitter::*sseOp)(X64Reg, const OpArg&, u8), X64Reg regOp, + const OpArg& arg1, const OpArg& arg2, u8 imm) { - if (arg1.IsSimpleReg(regOp)) - { - (this->*sseOp)(regOp, arg2, imm); - } - else if (arg1.IsSimpleReg() && cpu_info.bAVX) - { - (this->*avxOp)(regOp, arg1.GetSimpleReg(), arg2, imm); - } - else if (arg2.IsSimpleReg(regOp)) - { - // The ugly case: regOp == arg2 without AVX, or with arg1 == memory - if (!arg1.IsSimpleReg(XMM0)) - MOVAPD(XMM0, arg1); - if (cpu_info.bAVX) - { - (this->*avxOp)(regOp, XMM0, arg2, imm); - } - else - { - (this->*sseOp)(XMM0, arg2, imm); - MOVAPD(regOp, R(XMM0)); - } - } - else - { - MOVAPD(regOp, arg1); - (this->*sseOp)(regOp, arg1 == arg2 ? R(regOp) : arg2, imm); - } + if (arg1.IsSimpleReg(regOp)) + { + (this->*sseOp)(regOp, arg2, imm); + } + else if (arg1.IsSimpleReg() && cpu_info.bAVX) + { + (this->*avxOp)(regOp, arg1.GetSimpleReg(), arg2, imm); + } + else if (arg2.IsSimpleReg(regOp)) + { + // The ugly case: regOp == arg2 without AVX, or with arg1 == memory + if (!arg1.IsSimpleReg(XMM0)) + MOVAPD(XMM0, arg1); + if (cpu_info.bAVX) + { + (this->*avxOp)(regOp, XMM0, arg2, imm); + } + else + { + (this->*sseOp)(XMM0, arg2, imm); + MOVAPD(regOp, R(XMM0)); + } + } + else + { + MOVAPD(regOp, arg1); + (this->*sseOp)(regOp, arg1 == arg2 ? R(regOp) : arg2, imm); + } } alignas(16) static const u64 psMantissaTruncate[2] = {0xFFFFFFFFF8000000ULL, 0xFFFFFFFFF8000000ULL}; @@ -704,28 +719,28 @@ alignas(16) static const u64 psRoundBit[2] = {0x8000000, 0x8000000}; // It needs a temp, so let the caller pass that in. void EmuCodeBlock::Force25BitPrecision(X64Reg output, const OpArg& input, X64Reg tmp) { - if (jit->jo.accurateSinglePrecision) - { - // mantissa = (mantissa & ~0xFFFFFFF) + ((mantissa & (1ULL << 27)) << 1); - if (input.IsSimpleReg() && cpu_info.bAVX) - { - VPAND(tmp, input.GetSimpleReg(), M(psRoundBit)); - VPAND(output, input.GetSimpleReg(), M(psMantissaTruncate)); - PADDQ(output, R(tmp)); - } - else - { - if (!input.IsSimpleReg(output)) - MOVAPD(output, input); - avx_op(&XEmitter::VPAND, &XEmitter::PAND, tmp, R(output), M(psRoundBit), true, true); - PAND(output, M(psMantissaTruncate)); - PADDQ(output, R(tmp)); - } - } - else if (!input.IsSimpleReg(output)) - { - MOVAPD(output, input); - } + if (jit->jo.accurateSinglePrecision) + { + // mantissa = (mantissa & ~0xFFFFFFF) + ((mantissa & (1ULL << 27)) << 1); + if (input.IsSimpleReg() && cpu_info.bAVX) + { + VPAND(tmp, input.GetSimpleReg(), M(psRoundBit)); + VPAND(output, input.GetSimpleReg(), M(psMantissaTruncate)); + PADDQ(output, R(tmp)); + } + else + { + if (!input.IsSimpleReg(output)) + MOVAPD(output, input); + avx_op(&XEmitter::VPAND, &XEmitter::PAND, tmp, R(output), M(psRoundBit), true, true); + PAND(output, M(psMantissaTruncate)); + PADDQ(output, R(tmp)); + } + } + else if (!input.IsSimpleReg(output)) + { + MOVAPD(output, input); + } } alignas(16) static u32 temp32; @@ -737,9 +752,11 @@ alignas(16) static u64 temp64; // The x87 FPU doesn't even support flush-to-zero so we can use FLD+FSTP even on denormals. // If the number is a NaN, make sure to set the QNaN bit back to its original value. -// Another problem is that officially, converting doubles to single format results in undefined behavior. +// Another problem is that officially, converting doubles to single format results in undefined +// behavior. // Relying on undefined behavior is a bug so no software should ever do this. -// In case it does happen, phire's more accurate implementation of ConvertDoubleToSingle() is reproduced below. +// In case it does happen, phire's more accurate implementation of ConvertDoubleToSingle() is +// reproduced below. //#define MORE_ACCURATE_DOUBLETOSINGLE #ifdef MORE_ACCURATE_DOUBLETOSINGLE @@ -749,7 +766,7 @@ alignas(16) static const __m128i double_fraction = _mm_set_epi64x(0, 0x000ffffff alignas(16) static const __m128i double_sign_bit = _mm_set_epi64x(0, 0x8000000000000000); alignas(16) static const __m128i double_explicit_top_bit = _mm_set_epi64x(0, 0x0010000000000000); alignas(16) static const __m128i double_top_two_bits = _mm_set_epi64x(0, 0xc000000000000000); -alignas(16) static const __m128i double_bottom_bits = _mm_set_epi64x(0, 0x07ffffffe0000000); +alignas(16) static const __m128i double_bottom_bits = _mm_set_epi64x(0, 0x07ffffffe0000000); // This is the same algorithm used in the interpreter (and actual hardware) // The documentation states that the conversion of a double with an outside the @@ -758,271 +775,287 @@ alignas(16) static const __m128i double_bottom_bits = _mm_set_epi64x(0, 0x07fff // unless the exponent is in the range of 874 to 896. void EmuCodeBlock::ConvertDoubleToSingle(X64Reg dst, X64Reg src) { - MOVSD(XMM1, R(src)); + MOVSD(XMM1, R(src)); - // Grab Exponent - PAND(XMM1, M(&double_exponent)); - PSRLQ(XMM1, 52); - MOVD_xmm(R(RSCRATCH), XMM1); + // Grab Exponent + PAND(XMM1, M(&double_exponent)); + PSRLQ(XMM1, 52); + MOVD_xmm(R(RSCRATCH), XMM1); + // Check if the double is in the range of valid single subnormal + CMP(16, R(RSCRATCH), Imm16(896)); + FixupBranch NoDenormalize = J_CC(CC_G); + CMP(16, R(RSCRATCH), Imm16(874)); + FixupBranch NoDenormalize2 = J_CC(CC_L); - // Check if the double is in the range of valid single subnormal - CMP(16, R(RSCRATCH), Imm16(896)); - FixupBranch NoDenormalize = J_CC(CC_G); - CMP(16, R(RSCRATCH), Imm16(874)); - FixupBranch NoDenormalize2 = J_CC(CC_L); + // Denormalise - // Denormalise + // shift = (905 - Exponent) plus the 21 bit double to single shift + MOV(16, R(RSCRATCH), Imm16(905 + 21)); + MOVD_xmm(XMM0, R(RSCRATCH)); + PSUBQ(XMM0, R(XMM1)); - // shift = (905 - Exponent) plus the 21 bit double to single shift - MOV(16, R(RSCRATCH), Imm16(905 + 21)); - MOVD_xmm(XMM0, R(RSCRATCH)); - PSUBQ(XMM0, R(XMM1)); + // xmm1 = fraction | 0x0010000000000000 + MOVSD(XMM1, R(src)); + PAND(XMM1, M(&double_fraction)); + POR(XMM1, M(&double_explicit_top_bit)); - // xmm1 = fraction | 0x0010000000000000 - MOVSD(XMM1, R(src)); - PAND(XMM1, M(&double_fraction)); - POR(XMM1, M(&double_explicit_top_bit)); + // fraction >> shift + PSRLQ(XMM1, R(XMM0)); - // fraction >> shift - PSRLQ(XMM1, R(XMM0)); + // OR the sign bit in. + MOVSD(XMM0, R(src)); + PAND(XMM0, M(&double_sign_bit)); + PSRLQ(XMM0, 32); + POR(XMM1, R(XMM0)); - // OR the sign bit in. - MOVSD(XMM0, R(src)); - PAND(XMM0, M(&double_sign_bit)); - PSRLQ(XMM0, 32); - POR(XMM1, R(XMM0)); + FixupBranch end = J(false); // Goto end - FixupBranch end = J(false); // Goto end + SetJumpTarget(NoDenormalize); + SetJumpTarget(NoDenormalize2); - SetJumpTarget(NoDenormalize); - SetJumpTarget(NoDenormalize2); + // Don't Denormalize - // Don't Denormalize + // We want bits 0, 1 + MOVSD(XMM1, R(src)); + PAND(XMM1, M(&double_top_two_bits)); + PSRLQ(XMM1, 32); - // We want bits 0, 1 - MOVSD(XMM1, R(src)); - PAND(XMM1, M(&double_top_two_bits)); - PSRLQ(XMM1, 32); + // And 5 through to 34 + MOVSD(XMM0, R(src)); + PAND(XMM0, M(&double_bottom_bits)); + PSRLQ(XMM0, 29); - // And 5 through to 34 - MOVSD(XMM0, R(src)); - PAND(XMM0, M(&double_bottom_bits)); - PSRLQ(XMM0, 29); + // OR them togther + POR(XMM1, R(XMM0)); - // OR them togther - POR(XMM1, R(XMM0)); - - // End - SetJumpTarget(end); - MOVDDUP(dst, R(XMM1)); + // End + SetJumpTarget(end); + MOVDDUP(dst, R(XMM1)); } -#else // MORE_ACCURATE_DOUBLETOSINGLE +#else // MORE_ACCURATE_DOUBLETOSINGLE -alignas(16) static const __m128i double_sign_bit = _mm_set_epi64x(0xffffffffffffffff, 0x7fffffffffffffff); -alignas(16) static const __m128i single_qnan_bit = _mm_set_epi64x(0xffffffffffffffff, 0xffffffffffbfffff); -alignas(16) static const __m128i double_qnan_bit = _mm_set_epi64x(0xffffffffffffffff, 0xfff7ffffffffffff); +alignas(16) static const __m128i double_sign_bit = _mm_set_epi64x(0xffffffffffffffff, + 0x7fffffffffffffff); +alignas(16) static const __m128i single_qnan_bit = _mm_set_epi64x(0xffffffffffffffff, + 0xffffffffffbfffff); +alignas(16) static const __m128i double_qnan_bit = _mm_set_epi64x(0xffffffffffffffff, + 0xfff7ffffffffffff); // Smallest positive double that results in a normalized single. alignas(16) static const double min_norm_single = std::numeric_limits::min(); void EmuCodeBlock::ConvertDoubleToSingle(X64Reg dst, X64Reg src) { - // Most games have flush-to-zero enabled, which causes the single -> double -> single process here to be lossy. - // This is a problem when games use float operations to copy non-float data. - // Changing the FPU mode is very expensive, so we can't do that. - // Here, check to see if the source is small enough that it will result in a denormal, and pass it to the x87 unit - // if it is. - avx_op(&XEmitter::VPAND, &XEmitter::PAND, XMM0, R(src), M(&double_sign_bit), true, true); - UCOMISD(XMM0, M(&min_norm_single)); - FixupBranch nanConversion = J_CC(CC_P, true); - FixupBranch denormalConversion = J_CC(CC_B, true); - CVTSD2SS(dst, R(src)); + // Most games have flush-to-zero enabled, which causes the single -> double -> single process here + // to be lossy. + // This is a problem when games use float operations to copy non-float data. + // Changing the FPU mode is very expensive, so we can't do that. + // Here, check to see if the source is small enough that it will result in a denormal, and pass it + // to the x87 unit + // if it is. + avx_op(&XEmitter::VPAND, &XEmitter::PAND, XMM0, R(src), M(&double_sign_bit), true, true); + UCOMISD(XMM0, M(&min_norm_single)); + FixupBranch nanConversion = J_CC(CC_P, true); + FixupBranch denormalConversion = J_CC(CC_B, true); + CVTSD2SS(dst, R(src)); - SwitchToFarCode(); - SetJumpTarget(nanConversion); - MOVQ_xmm(R(RSCRATCH), src); - // Put the quiet bit into CF. - BT(64, R(RSCRATCH), Imm8(51)); - CVTSD2SS(dst, R(src)); - FixupBranch continue1 = J_CC(CC_C, true); - // Clear the quiet bit of the SNaN, which was 0 (signalling) but got set to 1 (quiet) by conversion. - ANDPS(dst, M(&single_qnan_bit)); - FixupBranch continue2 = J(true); + SwitchToFarCode(); + SetJumpTarget(nanConversion); + MOVQ_xmm(R(RSCRATCH), src); + // Put the quiet bit into CF. + BT(64, R(RSCRATCH), Imm8(51)); + CVTSD2SS(dst, R(src)); + FixupBranch continue1 = J_CC(CC_C, true); + // Clear the quiet bit of the SNaN, which was 0 (signalling) but got set to 1 (quiet) by + // conversion. + ANDPS(dst, M(&single_qnan_bit)); + FixupBranch continue2 = J(true); - SetJumpTarget(denormalConversion); - MOVSD(M(&temp64), src); - FLD(64, M(&temp64)); - FSTP(32, M(&temp32)); - MOVSS(dst, M(&temp32)); - FixupBranch continue3 = J(true); - SwitchToNearCode(); + SetJumpTarget(denormalConversion); + MOVSD(M(&temp64), src); + FLD(64, M(&temp64)); + FSTP(32, M(&temp32)); + MOVSS(dst, M(&temp32)); + FixupBranch continue3 = J(true); + SwitchToNearCode(); - SetJumpTarget(continue1); - SetJumpTarget(continue2); - SetJumpTarget(continue3); - // We'd normally need to MOVDDUP here to put the single in the top half of the output register too, but - // this function is only used to go directly to a following store, so we omit the MOVDDUP here. + SetJumpTarget(continue1); + SetJumpTarget(continue2); + SetJumpTarget(continue3); + // We'd normally need to MOVDDUP here to put the single in the top half of the output register + // too, but + // this function is only used to go directly to a following store, so we omit the MOVDDUP here. } -#endif // MORE_ACCURATE_DOUBLETOSINGLE +#endif // MORE_ACCURATE_DOUBLETOSINGLE // Converting single->double is a bit easier because all single denormals are double normals. void EmuCodeBlock::ConvertSingleToDouble(X64Reg dst, X64Reg src, bool src_is_gpr) { - X64Reg gprsrc = src_is_gpr ? src : RSCRATCH; - if (src_is_gpr) - { - MOVD_xmm(dst, R(src)); - } - else - { - if (dst != src) - MOVAPS(dst, R(src)); - MOVD_xmm(R(RSCRATCH), src); - } + X64Reg gprsrc = src_is_gpr ? src : RSCRATCH; + if (src_is_gpr) + { + MOVD_xmm(dst, R(src)); + } + else + { + if (dst != src) + MOVAPS(dst, R(src)); + MOVD_xmm(R(RSCRATCH), src); + } - UCOMISS(dst, R(dst)); - CVTSS2SD(dst, R(dst)); - FixupBranch nanConversion = J_CC(CC_P, true); + UCOMISS(dst, R(dst)); + CVTSS2SD(dst, R(dst)); + FixupBranch nanConversion = J_CC(CC_P, true); - SwitchToFarCode(); - SetJumpTarget(nanConversion); - TEST(32, R(gprsrc), Imm32(0x00400000)); - FixupBranch continue1 = J_CC(CC_NZ, true); - ANDPD(dst, M(&double_qnan_bit)); - FixupBranch continue2 = J(true); - SwitchToNearCode(); + SwitchToFarCode(); + SetJumpTarget(nanConversion); + TEST(32, R(gprsrc), Imm32(0x00400000)); + FixupBranch continue1 = J_CC(CC_NZ, true); + ANDPD(dst, M(&double_qnan_bit)); + FixupBranch continue2 = J(true); + SwitchToNearCode(); - SetJumpTarget(continue1); - SetJumpTarget(continue2); - MOVDDUP(dst, R(dst)); + SetJumpTarget(continue1); + SetJumpTarget(continue2); + MOVDDUP(dst, R(dst)); } -alignas(16) static const u64 psDoubleExp[2] = {0x7FF0000000000000ULL, 0}; +alignas(16) static const u64 psDoubleExp[2] = {0x7FF0000000000000ULL, 0}; alignas(16) static const u64 psDoubleFrac[2] = {0x000FFFFFFFFFFFFFULL, 0}; alignas(16) static const u64 psDoubleNoSign[2] = {0x7FFFFFFFFFFFFFFFULL, 0}; -// TODO: it might be faster to handle FPRF in the same way as CR is currently handled for integer, storing -// the result of each floating point op and calculating it when needed. This is trickier than for integers -// though, because there's 32 possible FPRF bit combinations but only 9 categories of floating point values, +// TODO: it might be faster to handle FPRF in the same way as CR is currently handled for integer, +// storing +// the result of each floating point op and calculating it when needed. This is trickier than for +// integers +// though, because there's 32 possible FPRF bit combinations but only 9 categories of floating point +// values, // which makes the whole thing rather trickier. -// Fortunately, PPCAnalyzer can optimize out a large portion of FPRF calculations, so maybe this isn't +// Fortunately, PPCAnalyzer can optimize out a large portion of FPRF calculations, so maybe this +// isn't // quite that necessary. void EmuCodeBlock::SetFPRF(Gen::X64Reg xmm) { - AND(32, PPCSTATE(fpscr), Imm32(~FPRF_MASK)); + AND(32, PPCSTATE(fpscr), Imm32(~FPRF_MASK)); - FixupBranch continue1, continue2, continue3, continue4; - if (cpu_info.bSSE4_1) - { - MOVQ_xmm(R(RSCRATCH), xmm); - SHR(64, R(RSCRATCH), Imm8(63)); // Get the sign bit; almost all the branches need it. - PTEST(xmm, M(psDoubleExp)); - FixupBranch maxExponent = J_CC(CC_C); - FixupBranch zeroExponent = J_CC(CC_Z); + FixupBranch continue1, continue2, continue3, continue4; + if (cpu_info.bSSE4_1) + { + MOVQ_xmm(R(RSCRATCH), xmm); + SHR(64, R(RSCRATCH), Imm8(63)); // Get the sign bit; almost all the branches need it. + PTEST(xmm, M(psDoubleExp)); + FixupBranch maxExponent = J_CC(CC_C); + FixupBranch zeroExponent = J_CC(CC_Z); - // Nice normalized number: sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; - LEA(32, RSCRATCH, MScaled(RSCRATCH, MathUtil::PPC_FPCLASS_NN - MathUtil::PPC_FPCLASS_PN, MathUtil::PPC_FPCLASS_PN)); - continue1 = J(); + // Nice normalized number: sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; + LEA(32, RSCRATCH, MScaled(RSCRATCH, MathUtil::PPC_FPCLASS_NN - MathUtil::PPC_FPCLASS_PN, + MathUtil::PPC_FPCLASS_PN)); + continue1 = J(); - SetJumpTarget(maxExponent); - PTEST(xmm, M(psDoubleFrac)); - FixupBranch notNAN = J_CC(CC_Z); + SetJumpTarget(maxExponent); + PTEST(xmm, M(psDoubleFrac)); + FixupBranch notNAN = J_CC(CC_Z); - // Max exponent + mantissa: PPC_FPCLASS_QNAN - MOV(32, R(RSCRATCH), Imm32(MathUtil::PPC_FPCLASS_QNAN)); - continue2 = J(); + // Max exponent + mantissa: PPC_FPCLASS_QNAN + MOV(32, R(RSCRATCH), Imm32(MathUtil::PPC_FPCLASS_QNAN)); + continue2 = J(); - // Max exponent + no mantissa: sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF; - SetJumpTarget(notNAN); - LEA(32, RSCRATCH, MScaled(RSCRATCH, MathUtil::PPC_FPCLASS_NINF - MathUtil::PPC_FPCLASS_PINF, MathUtil::PPC_FPCLASS_PINF)); - continue3 = J(); + // Max exponent + no mantissa: sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF; + SetJumpTarget(notNAN); + LEA(32, RSCRATCH, MScaled(RSCRATCH, MathUtil::PPC_FPCLASS_NINF - MathUtil::PPC_FPCLASS_PINF, + MathUtil::PPC_FPCLASS_PINF)); + continue3 = J(); - SetJumpTarget(zeroExponent); - PTEST(xmm, R(xmm)); - FixupBranch zero = J_CC(CC_Z); + SetJumpTarget(zeroExponent); + PTEST(xmm, R(xmm)); + FixupBranch zero = J_CC(CC_Z); - // No exponent + mantissa: sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; - LEA(32, RSCRATCH, MScaled(RSCRATCH, MathUtil::PPC_FPCLASS_ND - MathUtil::PPC_FPCLASS_PD, MathUtil::PPC_FPCLASS_PD)); - continue4 = J(); + // No exponent + mantissa: sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; + LEA(32, RSCRATCH, MScaled(RSCRATCH, MathUtil::PPC_FPCLASS_ND - MathUtil::PPC_FPCLASS_PD, + MathUtil::PPC_FPCLASS_PD)); + continue4 = J(); - // Zero: sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ; - SetJumpTarget(zero); - SHL(32, R(RSCRATCH), Imm8(4)); - ADD(32, R(RSCRATCH), Imm8(MathUtil::PPC_FPCLASS_PZ)); - } - else - { - MOVQ_xmm(R(RSCRATCH), xmm); - TEST(64, R(RSCRATCH), M(psDoubleExp)); - FixupBranch zeroExponent = J_CC(CC_Z); - AND(64, R(RSCRATCH), M(psDoubleNoSign)); - CMP(64, R(RSCRATCH), M(psDoubleExp)); - FixupBranch nan = J_CC(CC_G); // This works because if the sign bit is set, RSCRATCH is negative - FixupBranch infinity = J_CC(CC_E); - MOVQ_xmm(R(RSCRATCH), xmm); - SHR(64, R(RSCRATCH), Imm8(63)); - LEA(32, RSCRATCH, MScaled(RSCRATCH, MathUtil::PPC_FPCLASS_NN - MathUtil::PPC_FPCLASS_PN, MathUtil::PPC_FPCLASS_PN)); - continue1 = J(); - SetJumpTarget(nan); - MOVQ_xmm(R(RSCRATCH), xmm); - SHR(64, R(RSCRATCH), Imm8(63)); - MOV(32, R(RSCRATCH), Imm32(MathUtil::PPC_FPCLASS_QNAN)); - continue2 = J(); - SetJumpTarget(infinity); - MOVQ_xmm(R(RSCRATCH), xmm); - SHR(64, R(RSCRATCH), Imm8(63)); - LEA(32, RSCRATCH, MScaled(RSCRATCH, MathUtil::PPC_FPCLASS_NINF - MathUtil::PPC_FPCLASS_PINF, MathUtil::PPC_FPCLASS_PINF)); - continue3 = J(); - SetJumpTarget(zeroExponent); - TEST(64, R(RSCRATCH), R(RSCRATCH)); - FixupBranch zero = J_CC(CC_Z); - SHR(64, R(RSCRATCH), Imm8(63)); - LEA(32, RSCRATCH, MScaled(RSCRATCH, MathUtil::PPC_FPCLASS_ND - MathUtil::PPC_FPCLASS_PD, MathUtil::PPC_FPCLASS_PD)); - continue4 = J(); - SetJumpTarget(zero); - SHR(64, R(RSCRATCH), Imm8(63)); - SHL(32, R(RSCRATCH), Imm8(4)); - ADD(32, R(RSCRATCH), Imm8(MathUtil::PPC_FPCLASS_PZ)); - } + // Zero: sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ; + SetJumpTarget(zero); + SHL(32, R(RSCRATCH), Imm8(4)); + ADD(32, R(RSCRATCH), Imm8(MathUtil::PPC_FPCLASS_PZ)); + } + else + { + MOVQ_xmm(R(RSCRATCH), xmm); + TEST(64, R(RSCRATCH), M(psDoubleExp)); + FixupBranch zeroExponent = J_CC(CC_Z); + AND(64, R(RSCRATCH), M(psDoubleNoSign)); + CMP(64, R(RSCRATCH), M(psDoubleExp)); + FixupBranch nan = + J_CC(CC_G); // This works because if the sign bit is set, RSCRATCH is negative + FixupBranch infinity = J_CC(CC_E); + MOVQ_xmm(R(RSCRATCH), xmm); + SHR(64, R(RSCRATCH), Imm8(63)); + LEA(32, RSCRATCH, MScaled(RSCRATCH, MathUtil::PPC_FPCLASS_NN - MathUtil::PPC_FPCLASS_PN, + MathUtil::PPC_FPCLASS_PN)); + continue1 = J(); + SetJumpTarget(nan); + MOVQ_xmm(R(RSCRATCH), xmm); + SHR(64, R(RSCRATCH), Imm8(63)); + MOV(32, R(RSCRATCH), Imm32(MathUtil::PPC_FPCLASS_QNAN)); + continue2 = J(); + SetJumpTarget(infinity); + MOVQ_xmm(R(RSCRATCH), xmm); + SHR(64, R(RSCRATCH), Imm8(63)); + LEA(32, RSCRATCH, MScaled(RSCRATCH, MathUtil::PPC_FPCLASS_NINF - MathUtil::PPC_FPCLASS_PINF, + MathUtil::PPC_FPCLASS_PINF)); + continue3 = J(); + SetJumpTarget(zeroExponent); + TEST(64, R(RSCRATCH), R(RSCRATCH)); + FixupBranch zero = J_CC(CC_Z); + SHR(64, R(RSCRATCH), Imm8(63)); + LEA(32, RSCRATCH, MScaled(RSCRATCH, MathUtil::PPC_FPCLASS_ND - MathUtil::PPC_FPCLASS_PD, + MathUtil::PPC_FPCLASS_PD)); + continue4 = J(); + SetJumpTarget(zero); + SHR(64, R(RSCRATCH), Imm8(63)); + SHL(32, R(RSCRATCH), Imm8(4)); + ADD(32, R(RSCRATCH), Imm8(MathUtil::PPC_FPCLASS_PZ)); + } - SetJumpTarget(continue1); - SetJumpTarget(continue2); - SetJumpTarget(continue3); - SetJumpTarget(continue4); - SHL(32, R(RSCRATCH), Imm8(FPRF_SHIFT)); - OR(32, PPCSTATE(fpscr), R(RSCRATCH)); + SetJumpTarget(continue1); + SetJumpTarget(continue2); + SetJumpTarget(continue3); + SetJumpTarget(continue4); + SHL(32, R(RSCRATCH), Imm8(FPRF_SHIFT)); + OR(32, PPCSTATE(fpscr), R(RSCRATCH)); } void EmuCodeBlock::JitGetAndClearCAOV(bool oe) { - if (oe) - AND(8, PPCSTATE(xer_so_ov), Imm8(~XER_OV_MASK)); //XER.OV = 0 - SHR(8, PPCSTATE(xer_ca), Imm8(1)); //carry = XER.CA, XER.CA = 0 + if (oe) + AND(8, PPCSTATE(xer_so_ov), Imm8(~XER_OV_MASK)); // XER.OV = 0 + SHR(8, PPCSTATE(xer_ca), Imm8(1)); // carry = XER.CA, XER.CA = 0 } void EmuCodeBlock::JitSetCA() { - MOV(8, PPCSTATE(xer_ca), Imm8(1)); //XER.CA = 1 + MOV(8, PPCSTATE(xer_ca), Imm8(1)); // XER.CA = 1 } // Some testing shows CA is set roughly ~1/3 of the time (relative to clears), so // branchless calculation of CA is probably faster in general. void EmuCodeBlock::JitSetCAIf(CCFlags conditionCode) { - SETcc(conditionCode, PPCSTATE(xer_ca)); + SETcc(conditionCode, PPCSTATE(xer_ca)); } void EmuCodeBlock::JitClearCA() { - MOV(8, PPCSTATE(xer_ca), Imm8(0)); + MOV(8, PPCSTATE(xer_ca), Imm8(0)); } void EmuCodeBlock::Clear() { - registersInUseAtLoc.clear(); - pcAtLoc.clear(); - exceptionHandlerAtLoc.clear(); + registersInUseAtLoc.clear(); + pcAtLoc.clear(); + exceptionHandlerAtLoc.clear(); } - diff --git a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h index cc5db24240..e50ad9af6e 100644 --- a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h +++ b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h @@ -11,12 +11,15 @@ #include "Common/x64Emitter.h" #include "Core/PowerPC/PowerPC.h" -namespace MMIO { class Mapping; } +namespace MMIO +{ +class Mapping; +} // We offset by 0x80 because the range of one byte memory offsets is // -0x80..0x7f. -#define PPCSTATE(x) MDisp(RPPCSTATE, \ - (int) ((char *) &PowerPC::ppcState.x - (char *) &PowerPC::ppcState) - 0x80) +#define PPCSTATE(x) \ + MDisp(RPPCSTATE, (int)((char*)&PowerPC::ppcState.x - (char*)&PowerPC::ppcState) - 0x80) // In case you want to disable the ppcstate register: // #define PPCSTATE(x) M(&PowerPC::ppcState.x) #define PPCSTATE_LR PPCSTATE(spr[SPR_LR]) @@ -29,11 +32,20 @@ namespace MMIO { class Mapping; } class FarCodeCache : public Gen::X64CodeBlock { private: - bool m_enabled = false; + bool m_enabled = false; + public: - bool Enabled() const { return m_enabled; } - void Init(int size) { AllocCodeSpace(size); m_enabled = true; } - void Shutdown() { FreeCodeSpace(); m_enabled = false; } + bool Enabled() const { return m_enabled; } + void Init(int size) + { + AllocCodeSpace(size); + m_enabled = true; + } + void Shutdown() + { + FreeCodeSpace(); + m_enabled = false; + } }; static const int CODE_SIZE = 1024 * 1024 * 32; @@ -51,87 +63,102 @@ static const int TRAMPOLINE_CODE_SIZE_MMU = 1024 * 1024 * 32; class EmuCodeBlock : public Gen::X64CodeBlock { public: - FarCodeCache farcode; - u8* nearcode; // Backed up when we switch to far code. + FarCodeCache farcode; + u8* nearcode; // Backed up when we switch to far code. - void MemoryExceptionCheck(); + void MemoryExceptionCheck(); - // Simple functions to switch between near and far code emitting - void SwitchToFarCode() - { - nearcode = GetWritableCodePtr(); - SetCodePtr(farcode.GetWritableCodePtr()); - } + // Simple functions to switch between near and far code emitting + void SwitchToFarCode() + { + nearcode = GetWritableCodePtr(); + SetCodePtr(farcode.GetWritableCodePtr()); + } - void SwitchToNearCode() - { - farcode.SetCodePtr(GetWritableCodePtr()); - SetCodePtr(nearcode); - } + void SwitchToNearCode() + { + farcode.SetCodePtr(GetWritableCodePtr()); + SetCodePtr(nearcode); + } - Gen::FixupBranch CheckIfSafeAddress(const Gen::OpArg& reg_value, Gen::X64Reg reg_addr, BitSet32 registers_in_use, u32 mem_mask); - void UnsafeLoadRegToReg(Gen::X64Reg reg_addr, Gen::X64Reg reg_value, int accessSize, s32 offset = 0, bool signExtend = false); - void UnsafeLoadRegToRegNoSwap(Gen::X64Reg reg_addr, Gen::X64Reg reg_value, int accessSize, s32 offset, bool signExtend = false); - // these return the address of the MOV, for backpatching - u8 *UnsafeWriteRegToReg(Gen::OpArg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset = 0, bool swap = true); - u8 *UnsafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset = 0, bool swap = true) - { - return UnsafeWriteRegToReg(R(reg_value), reg_addr, accessSize, offset, swap); - } - u8 *UnsafeLoadToReg(Gen::X64Reg reg_value, Gen::OpArg opAddress, int accessSize, s32 offset, bool signExtend); - void UnsafeWriteGatherPipe(int accessSize); + Gen::FixupBranch CheckIfSafeAddress(const Gen::OpArg& reg_value, Gen::X64Reg reg_addr, + BitSet32 registers_in_use, u32 mem_mask); + void UnsafeLoadRegToReg(Gen::X64Reg reg_addr, Gen::X64Reg reg_value, int accessSize, + s32 offset = 0, bool signExtend = false); + void UnsafeLoadRegToRegNoSwap(Gen::X64Reg reg_addr, Gen::X64Reg reg_value, int accessSize, + s32 offset, bool signExtend = false); + // these return the address of the MOV, for backpatching + u8* UnsafeWriteRegToReg(Gen::OpArg reg_value, Gen::X64Reg reg_addr, int accessSize, + s32 offset = 0, bool swap = true); + u8* UnsafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, + s32 offset = 0, bool swap = true) + { + return UnsafeWriteRegToReg(R(reg_value), reg_addr, accessSize, offset, swap); + } + u8* UnsafeLoadToReg(Gen::X64Reg reg_value, Gen::OpArg opAddress, int accessSize, s32 offset, + bool signExtend); + void UnsafeWriteGatherPipe(int accessSize); - // Generate a load/write from the MMIO handler for a given address. Only - // call for known addresses in MMIO range (MMIO::IsMMIOAddress). - void MMIOLoadToReg(MMIO::Mapping* mmio, Gen::X64Reg reg_value, BitSet32 registers_in_use, u32 address, int access_size, bool sign_extend); + // Generate a load/write from the MMIO handler for a given address. Only + // call for known addresses in MMIO range (MMIO::IsMMIOAddress). + void MMIOLoadToReg(MMIO::Mapping* mmio, Gen::X64Reg reg_value, BitSet32 registers_in_use, + u32 address, int access_size, bool sign_extend); - enum SafeLoadStoreFlags - { - SAFE_LOADSTORE_NO_SWAP = 1, - SAFE_LOADSTORE_NO_PROLOG = 2, - SAFE_LOADSTORE_NO_FASTMEM = 4, - SAFE_LOADSTORE_CLOBBER_RSCRATCH_INSTEAD_OF_ADDR = 8 - }; + enum SafeLoadStoreFlags + { + SAFE_LOADSTORE_NO_SWAP = 1, + SAFE_LOADSTORE_NO_PROLOG = 2, + SAFE_LOADSTORE_NO_FASTMEM = 4, + SAFE_LOADSTORE_CLOBBER_RSCRATCH_INSTEAD_OF_ADDR = 8 + }; - void SafeLoadToReg(Gen::X64Reg reg_value, const Gen::OpArg & opAddress, int accessSize, s32 offset, BitSet32 registersInUse, bool signExtend, int flags = 0); - // Clobbers RSCRATCH or reg_addr depending on the relevant flag. Preserves - // reg_value if the load fails and js.memcheck is enabled. - // Works with immediate inputs and simple registers only. - void SafeWriteRegToReg(Gen::OpArg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset, BitSet32 registersInUse, int flags = 0); - void SafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset, BitSet32 registersInUse, int flags = 0) - { - SafeWriteRegToReg(R(reg_value), reg_addr, accessSize, offset, registersInUse, flags); - } + void SafeLoadToReg(Gen::X64Reg reg_value, const Gen::OpArg& opAddress, int accessSize, s32 offset, + BitSet32 registersInUse, bool signExtend, int flags = 0); + // Clobbers RSCRATCH or reg_addr depending on the relevant flag. Preserves + // reg_value if the load fails and js.memcheck is enabled. + // Works with immediate inputs and simple registers only. + void SafeWriteRegToReg(Gen::OpArg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset, + BitSet32 registersInUse, int flags = 0); + void SafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset, + BitSet32 registersInUse, int flags = 0) + { + SafeWriteRegToReg(R(reg_value), reg_addr, accessSize, offset, registersInUse, flags); + } - // applies to safe and unsafe WriteRegToReg - bool WriteClobbersRegValue(int accessSize, bool swap) - { - return swap && !cpu_info.bMOVBE && accessSize > 8; - } + // applies to safe and unsafe WriteRegToReg + bool WriteClobbersRegValue(int accessSize, bool swap) + { + return swap && !cpu_info.bMOVBE && accessSize > 8; + } - void WriteToConstRamAddress(int accessSize, Gen::OpArg arg, u32 address, bool swap = true); - // returns true if an exception could have been caused - bool WriteToConstAddress(int accessSize, Gen::OpArg arg, u32 address, BitSet32 registersInUse); - void JitGetAndClearCAOV(bool oe); - void JitSetCA(); - void JitSetCAIf(Gen::CCFlags conditionCode); - void JitClearCA(); + void WriteToConstRamAddress(int accessSize, Gen::OpArg arg, u32 address, bool swap = true); + // returns true if an exception could have been caused + bool WriteToConstAddress(int accessSize, Gen::OpArg arg, u32 address, BitSet32 registersInUse); + void JitGetAndClearCAOV(bool oe); + void JitSetCA(); + void JitSetCAIf(Gen::CCFlags conditionCode); + void JitClearCA(); - void avx_op(void (Gen::XEmitter::*avxOp)(Gen::X64Reg, Gen::X64Reg, const Gen::OpArg&), void (Gen::XEmitter::*sseOp)(Gen::X64Reg, const Gen::OpArg&), - Gen::X64Reg regOp, const Gen::OpArg& arg1, const Gen::OpArg& arg2, bool packed = true, bool reversible = false); - void avx_op(void (Gen::XEmitter::*avxOp)(Gen::X64Reg, Gen::X64Reg, const Gen::OpArg&, u8), void (Gen::XEmitter::*sseOp)(Gen::X64Reg, const Gen::OpArg&, u8), - Gen::X64Reg regOp, const Gen::OpArg& arg1, const Gen::OpArg& arg2, u8 imm); + void avx_op(void (Gen::XEmitter::*avxOp)(Gen::X64Reg, Gen::X64Reg, const Gen::OpArg&), + void (Gen::XEmitter::*sseOp)(Gen::X64Reg, const Gen::OpArg&), Gen::X64Reg regOp, + const Gen::OpArg& arg1, const Gen::OpArg& arg2, bool packed = true, + bool reversible = false); + void avx_op(void (Gen::XEmitter::*avxOp)(Gen::X64Reg, Gen::X64Reg, const Gen::OpArg&, u8), + void (Gen::XEmitter::*sseOp)(Gen::X64Reg, const Gen::OpArg&, u8), Gen::X64Reg regOp, + const Gen::OpArg& arg1, const Gen::OpArg& arg2, u8 imm); - void ForceSinglePrecision(Gen::X64Reg output, const Gen::OpArg& input, bool packed = true, bool duplicate = false); - void Force25BitPrecision(Gen::X64Reg output, const Gen::OpArg& input, Gen::X64Reg tmp); + void ForceSinglePrecision(Gen::X64Reg output, const Gen::OpArg& input, bool packed = true, + bool duplicate = false); + void Force25BitPrecision(Gen::X64Reg output, const Gen::OpArg& input, Gen::X64Reg tmp); + + // RSCRATCH might get trashed + void ConvertSingleToDouble(Gen::X64Reg dst, Gen::X64Reg src, bool src_is_gpr = false); + void ConvertDoubleToSingle(Gen::X64Reg dst, Gen::X64Reg src); + void SetFPRF(Gen::X64Reg xmm); + void Clear(); - // RSCRATCH might get trashed - void ConvertSingleToDouble(Gen::X64Reg dst, Gen::X64Reg src, bool src_is_gpr = false); - void ConvertDoubleToSingle(Gen::X64Reg dst, Gen::X64Reg src); - void SetFPRF(Gen::X64Reg xmm); - void Clear(); protected: - std::unordered_map registersInUseAtLoc; - std::unordered_map pcAtLoc; - std::unordered_map exceptionHandlerAtLoc; + std::unordered_map registersInUseAtLoc; + std::unordered_map pcAtLoc; + std::unordered_map exceptionHandlerAtLoc; }; diff --git a/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp b/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp index efc1add7a8..12b72b1035 100644 --- a/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp @@ -11,173 +11,176 @@ #include "Common/x64ABI.h" #include "Common/x64Analyzer.h" #include "Common/x64Emitter.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/JitCommon/Jit_Util.h" #include "Core/PowerPC/JitCommon/JitBase.h" +#include "Core/PowerPC/JitCommon/Jit_Util.h" #include "Core/PowerPC/JitCommon/TrampolineCache.h" +#include "Core/PowerPC/PowerPC.h" #ifdef _WIN32 - #include +#include #endif - using namespace Gen; void TrampolineCache::Init(int size) { - AllocCodeSpace(size); + AllocCodeSpace(size); } void TrampolineCache::ClearCodeSpace() { - X64CodeBlock::ClearCodeSpace(); + X64CodeBlock::ClearCodeSpace(); } void TrampolineCache::Shutdown() { - FreeCodeSpace(); + FreeCodeSpace(); } -const u8* TrampolineCache::GenerateReadTrampoline(const InstructionInfo &info, BitSet32 registersInUse, u8* exceptionHandler, u8* returnPtr) +const u8* TrampolineCache::GenerateReadTrampoline(const InstructionInfo& info, + BitSet32 registersInUse, u8* exceptionHandler, + u8* returnPtr) { - if (GetSpaceLeft() < 1024) - PanicAlert("Trampoline cache full"); + if (GetSpaceLeft() < 1024) + PanicAlert("Trampoline cache full"); - const u8* trampoline = GetCodePtr(); - X64Reg addrReg = (X64Reg)info.scaledReg; - X64Reg dataReg = (X64Reg)info.regOperandReg; - int stack_offset = 0; - bool push_param1 = registersInUse[ABI_PARAM1]; + const u8* trampoline = GetCodePtr(); + X64Reg addrReg = (X64Reg)info.scaledReg; + X64Reg dataReg = (X64Reg)info.regOperandReg; + int stack_offset = 0; + bool push_param1 = registersInUse[ABI_PARAM1]; - if (push_param1) - { - PUSH(ABI_PARAM1); - stack_offset = 8; - registersInUse[ABI_PARAM1] = 0; - } + if (push_param1) + { + PUSH(ABI_PARAM1); + stack_offset = 8; + registersInUse[ABI_PARAM1] = 0; + } - int dataRegSize = info.operandSize == 8 ? 64 : 32; - if (addrReg != ABI_PARAM1 && info.displacement) - LEA(32, ABI_PARAM1, MDisp(addrReg, info.displacement)); - else if (addrReg != ABI_PARAM1) - MOV(32, R(ABI_PARAM1), R(addrReg)); - else if (info.displacement) - ADD(32, R(ABI_PARAM1), Imm32(info.displacement)); + int dataRegSize = info.operandSize == 8 ? 64 : 32; + if (addrReg != ABI_PARAM1 && info.displacement) + LEA(32, ABI_PARAM1, MDisp(addrReg, info.displacement)); + else if (addrReg != ABI_PARAM1) + MOV(32, R(ABI_PARAM1), R(addrReg)); + else if (info.displacement) + ADD(32, R(ABI_PARAM1), Imm32(info.displacement)); - ABI_PushRegistersAndAdjustStack(registersInUse, stack_offset); + ABI_PushRegistersAndAdjustStack(registersInUse, stack_offset); - switch (info.operandSize) - { - case 8: - CALL((void*)&PowerPC::Read_U64); - break; - case 4: - CALL((void*)&PowerPC::Read_U32); - break; - case 2: - CALL((void*)&PowerPC::Read_U16); - break; - case 1: - CALL((void*)&PowerPC::Read_U8); - break; - } + switch (info.operandSize) + { + case 8: + CALL((void*)&PowerPC::Read_U64); + break; + case 4: + CALL((void*)&PowerPC::Read_U32); + break; + case 2: + CALL((void*)&PowerPC::Read_U16); + break; + case 1: + CALL((void*)&PowerPC::Read_U8); + break; + } - ABI_PopRegistersAndAdjustStack(registersInUse, stack_offset); + ABI_PopRegistersAndAdjustStack(registersInUse, stack_offset); - if (push_param1) - POP(ABI_PARAM1); + if (push_param1) + POP(ABI_PARAM1); - if (exceptionHandler) - { - TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_DSI)); - J_CC(CC_NZ, exceptionHandler); - } + if (exceptionHandler) + { + TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_DSI)); + J_CC(CC_NZ, exceptionHandler); + } - if (info.signExtend) - MOVSX(dataRegSize, info.operandSize * 8, dataReg, R(ABI_RETURN)); - else if (dataReg != ABI_RETURN || info.operandSize < 4) - MOVZX(dataRegSize, info.operandSize * 8, dataReg, R(ABI_RETURN)); + if (info.signExtend) + MOVSX(dataRegSize, info.operandSize * 8, dataReg, R(ABI_RETURN)); + else if (dataReg != ABI_RETURN || info.operandSize < 4) + MOVZX(dataRegSize, info.operandSize * 8, dataReg, R(ABI_RETURN)); - JMP(returnPtr, true); + JMP(returnPtr, true); - JitRegister::Register(trampoline, GetCodePtr(), "JIT_ReadTrampoline"); - return trampoline; + JitRegister::Register(trampoline, GetCodePtr(), "JIT_ReadTrampoline"); + return trampoline; } -const u8* TrampolineCache::GenerateWriteTrampoline(const InstructionInfo &info, BitSet32 registersInUse, u8* exceptionHandler, u8* returnPtr, u32 pc) +const u8* TrampolineCache::GenerateWriteTrampoline(const InstructionInfo& info, + BitSet32 registersInUse, u8* exceptionHandler, + u8* returnPtr, u32 pc) { - if (GetSpaceLeft() < 1024) - PanicAlert("Trampoline cache full"); + if (GetSpaceLeft() < 1024) + PanicAlert("Trampoline cache full"); - const u8* trampoline = GetCodePtr(); + const u8* trampoline = GetCodePtr(); - X64Reg dataReg = (X64Reg)info.regOperandReg; - X64Reg addrReg = (X64Reg)info.scaledReg; + X64Reg dataReg = (X64Reg)info.regOperandReg; + X64Reg addrReg = (X64Reg)info.scaledReg; - // Don't treat FIFO writes specially for now because they require a burst - // check anyway. + // Don't treat FIFO writes specially for now because they require a burst + // check anyway. - // PC is used by memory watchpoints (if enabled) or to print accurate PC locations in debug logs - MOV(32, PPCSTATE(pc), Imm32(pc)); + // PC is used by memory watchpoints (if enabled) or to print accurate PC locations in debug logs + MOV(32, PPCSTATE(pc), Imm32(pc)); - ABI_PushRegistersAndAdjustStack(registersInUse, 0); + ABI_PushRegistersAndAdjustStack(registersInUse, 0); - if (info.hasImmediate) - { - if (addrReg != ABI_PARAM2 && info.displacement) - LEA(32, ABI_PARAM2, MDisp(addrReg, info.displacement)); - else if (addrReg != ABI_PARAM2) - MOV(32, R(ABI_PARAM2), R(addrReg)); - else if (info.displacement) - ADD(32, R(ABI_PARAM2), Imm32(info.displacement)); + if (info.hasImmediate) + { + if (addrReg != ABI_PARAM2 && info.displacement) + LEA(32, ABI_PARAM2, MDisp(addrReg, info.displacement)); + else if (addrReg != ABI_PARAM2) + MOV(32, R(ABI_PARAM2), R(addrReg)); + else if (info.displacement) + ADD(32, R(ABI_PARAM2), Imm32(info.displacement)); - // we have to swap back the immediate to pass it to the write functions - switch (info.operandSize) - { - case 8: - PanicAlert("Invalid 64-bit immediate!"); - break; - case 4: - MOV(32, R(ABI_PARAM1), Imm32(Common::swap32((u32)info.immediate))); - break; - case 2: - MOV(16, R(ABI_PARAM1), Imm16(Common::swap16((u16)info.immediate))); - break; - case 1: - MOV(8, R(ABI_PARAM1), Imm8((u8)info.immediate)); - break; - } - } - else - { - int dataRegSize = info.operandSize == 8 ? 64 : 32; - MOVTwo(dataRegSize, ABI_PARAM2, addrReg, info.displacement, ABI_PARAM1, dataReg); - } + // we have to swap back the immediate to pass it to the write functions + switch (info.operandSize) + { + case 8: + PanicAlert("Invalid 64-bit immediate!"); + break; + case 4: + MOV(32, R(ABI_PARAM1), Imm32(Common::swap32((u32)info.immediate))); + break; + case 2: + MOV(16, R(ABI_PARAM1), Imm16(Common::swap16((u16)info.immediate))); + break; + case 1: + MOV(8, R(ABI_PARAM1), Imm8((u8)info.immediate)); + break; + } + } + else + { + int dataRegSize = info.operandSize == 8 ? 64 : 32; + MOVTwo(dataRegSize, ABI_PARAM2, addrReg, info.displacement, ABI_PARAM1, dataReg); + } - switch (info.operandSize) - { - case 8: - CALL((void *)&PowerPC::Write_U64); - break; - case 4: - CALL((void *)&PowerPC::Write_U32); - break; - case 2: - CALL((void *)&PowerPC::Write_U16); - break; - case 1: - CALL((void *)&PowerPC::Write_U8); - break; - } + switch (info.operandSize) + { + case 8: + CALL((void*)&PowerPC::Write_U64); + break; + case 4: + CALL((void*)&PowerPC::Write_U32); + break; + case 2: + CALL((void*)&PowerPC::Write_U16); + break; + case 1: + CALL((void*)&PowerPC::Write_U8); + break; + } - ABI_PopRegistersAndAdjustStack(registersInUse, 0); - if (exceptionHandler) - { - TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_DSI)); - J_CC(CC_NZ, exceptionHandler); - } - JMP(returnPtr, true); + ABI_PopRegistersAndAdjustStack(registersInUse, 0); + if (exceptionHandler) + { + TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_DSI)); + J_CC(CC_NZ, exceptionHandler); + } + JMP(returnPtr, true); - JitRegister::Register(trampoline, GetCodePtr(), "JIT_WriteTrampoline_%x", pc); - return trampoline; + JitRegister::Register(trampoline, GetCodePtr(), "JIT_WriteTrampoline_%x", pc); + return trampoline; } diff --git a/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.h b/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.h index f6efc5b3b4..7852bae6b9 100644 --- a/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.h +++ b/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.h @@ -16,10 +16,12 @@ const int BACKPATCH_SIZE = 5; class TrampolineCache : public Gen::X64CodeBlock { public: - void Init(int size); - void Shutdown(); + void Init(int size); + void Shutdown(); - const u8* GenerateReadTrampoline(const InstructionInfo &info, BitSet32 registersInUse, u8* exceptionHandler, u8* returnPtr); - const u8* GenerateWriteTrampoline(const InstructionInfo &info, BitSet32 registersInUse, u8* exceptionHandler, u8* returnPtr, u32 pc); - void ClearCodeSpace(); + const u8* GenerateReadTrampoline(const InstructionInfo& info, BitSet32 registersInUse, + u8* exceptionHandler, u8* returnPtr); + const u8* GenerateWriteTrampoline(const InstructionInfo& info, BitSet32 registersInUse, + u8* exceptionHandler, u8* returnPtr, u32 pc); + void ClearCodeSpace(); }; diff --git a/Source/Core/Core/PowerPC/JitILCommon/IR.cpp b/Source/Core/Core/PowerPC/JitILCommon/IR.cpp index f65c852121..02e423672d 100644 --- a/Source/Core/Core/PowerPC/JitILCommon/IR.cpp +++ b/Source/Core/Core/PowerPC/JitILCommon/IR.cpp @@ -116,7 +116,8 @@ TODO (in no particular order): */ #ifdef _MSC_VER -#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned +#pragma warning( \ + disable : 4146) // unary minus operator applied to unsigned type, result still unsigned #endif #include @@ -136,57 +137,56 @@ using namespace Gen; namespace IREmitter { - InstLoc IRBuilder::EmitZeroOp(unsigned Opcode, unsigned extra = 0) { - InstLoc curIndex = InstList.data() + InstList.size(); - InstList.push_back(Opcode | (extra << 8)); - MarkUsed.push_back(false); - return curIndex; + InstLoc curIndex = InstList.data() + InstList.size(); + InstList.push_back(Opcode | (extra << 8)); + MarkUsed.push_back(false); + return curIndex; } InstLoc IRBuilder::EmitUOp(unsigned Opcode, InstLoc Op1, unsigned extra) { - InstLoc curIndex = InstList.data() + InstList.size(); - unsigned backOp1 = (s32)(curIndex - 1 - Op1); - if (backOp1 >= 256) - { - InstList.push_back(Tramp | backOp1 << 8); - MarkUsed.push_back(false); - backOp1 = 0; - curIndex++; - } + InstLoc curIndex = InstList.data() + InstList.size(); + unsigned backOp1 = (s32)(curIndex - 1 - Op1); + if (backOp1 >= 256) + { + InstList.push_back(Tramp | backOp1 << 8); + MarkUsed.push_back(false); + backOp1 = 0; + curIndex++; + } - InstList.push_back(Opcode | (backOp1 << 8) | (extra << 16)); - MarkUsed.push_back(false); - return curIndex; + InstList.push_back(Opcode | (backOp1 << 8) | (extra << 16)); + MarkUsed.push_back(false); + return curIndex; } InstLoc IRBuilder::EmitBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, unsigned extra) { - InstLoc curIndex = InstList.data() + InstList.size(); - unsigned backOp1 = (s32)(curIndex - 1 - Op1); - if (backOp1 >= 255) - { - InstList.push_back(Tramp | backOp1 << 8); - MarkUsed.push_back(false); - backOp1 = 0; - curIndex++; - } + InstLoc curIndex = InstList.data() + InstList.size(); + unsigned backOp1 = (s32)(curIndex - 1 - Op1); + if (backOp1 >= 255) + { + InstList.push_back(Tramp | backOp1 << 8); + MarkUsed.push_back(false); + backOp1 = 0; + curIndex++; + } - unsigned backOp2 = (s32)(curIndex - 1 - Op2); - if (backOp2 >= 256) - { - InstList.push_back(Tramp | backOp2 << 8); - MarkUsed.push_back(false); - backOp2 = 0; - backOp1++; - curIndex++; - } + unsigned backOp2 = (s32)(curIndex - 1 - Op2); + if (backOp2 >= 256) + { + InstList.push_back(Tramp | backOp2 << 8); + MarkUsed.push_back(false); + backOp2 = 0; + backOp1++; + curIndex++; + } - InstList.push_back(Opcode | (backOp1 << 8) | (backOp2 << 16) | (extra << 24)); - MarkUsed.push_back(false); - return curIndex; + InstList.push_back(Opcode | (backOp1 << 8) | (backOp2 << 16) | (extra << 24)); + MarkUsed.push_back(false); + return curIndex; } #if 0 @@ -231,1077 +231,1090 @@ InstLoc IRBuilder::EmitTriOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, InstLoc unsigned IRBuilder::ComputeKnownZeroBits(InstLoc I) const { - switch (getOpcode(*I)) - { - case Load8: - return 0xFFFFFF00; - case Or: - return ComputeKnownZeroBits(getOp1(I)) & - ComputeKnownZeroBits(getOp2(I)); - case And: - return ComputeKnownZeroBits(getOp1(I)) | - ComputeKnownZeroBits(getOp2(I)); - case Shl: - if (isImm(*getOp2(I))) - { - unsigned samt = GetImmValue(getOp2(I)) & 31; - return (ComputeKnownZeroBits(getOp1(I)) << samt) | - ~(-1U << samt); - } - return 0; - case Shrl: - if (isImm(*getOp2(I))) - { - unsigned samt = GetImmValue(getOp2(I)) & 31; - return (ComputeKnownZeroBits(getOp1(I)) >> samt) | - ~(-1U >> samt); - } - return 0; - case Rol: - if (isImm(*getOp2(I))) - { - return _rotl(ComputeKnownZeroBits(getOp1(I)), - GetImmValue(getOp2(I))); - } - default: - return 0; - } + switch (getOpcode(*I)) + { + case Load8: + return 0xFFFFFF00; + case Or: + return ComputeKnownZeroBits(getOp1(I)) & ComputeKnownZeroBits(getOp2(I)); + case And: + return ComputeKnownZeroBits(getOp1(I)) | ComputeKnownZeroBits(getOp2(I)); + case Shl: + if (isImm(*getOp2(I))) + { + unsigned samt = GetImmValue(getOp2(I)) & 31; + return (ComputeKnownZeroBits(getOp1(I)) << samt) | ~(-1U << samt); + } + return 0; + case Shrl: + if (isImm(*getOp2(I))) + { + unsigned samt = GetImmValue(getOp2(I)) & 31; + return (ComputeKnownZeroBits(getOp1(I)) >> samt) | ~(-1U >> samt); + } + return 0; + case Rol: + if (isImm(*getOp2(I))) + { + return _rotl(ComputeKnownZeroBits(getOp1(I)), GetImmValue(getOp2(I))); + } + default: + return 0; + } } InstLoc IRBuilder::FoldZeroOp(unsigned Opcode, unsigned extra) { - if (Opcode == LoadGReg) - { - // Reg load folding: if we already loaded the value, - // load it again - if (!GRegCache[extra]) - GRegCache[extra] = EmitZeroOp(LoadGReg, extra); - return GRegCache[extra]; - } - else if (Opcode == LoadFReg) - { - // Reg load folding: if we already loaded the value, - // load it again - if (!FRegCache[extra]) - FRegCache[extra] = EmitZeroOp(LoadFReg, extra); - return FRegCache[extra]; - } - else if (Opcode == LoadFRegDENToZero) - { - FRegCacheStore[extra] = nullptr; // prevent previous store operation from zapping - FRegCache[extra] = EmitZeroOp(LoadFRegDENToZero, extra); - return FRegCache[extra]; - } - else if (Opcode == LoadCarry) - { - if (!CarryCache) - CarryCache = EmitZeroOp(LoadCarry, extra); - return CarryCache; - } - else if (Opcode == LoadCR) - { - if (!CRCache[extra]) - CRCache[extra] = EmitZeroOp(LoadCR, extra); - return CRCache[extra]; - } - else if (Opcode == LoadCTR) - { - if (!CTRCache) - CTRCache = EmitZeroOp(LoadCTR, extra); - return CTRCache; - } + if (Opcode == LoadGReg) + { + // Reg load folding: if we already loaded the value, + // load it again + if (!GRegCache[extra]) + GRegCache[extra] = EmitZeroOp(LoadGReg, extra); + return GRegCache[extra]; + } + else if (Opcode == LoadFReg) + { + // Reg load folding: if we already loaded the value, + // load it again + if (!FRegCache[extra]) + FRegCache[extra] = EmitZeroOp(LoadFReg, extra); + return FRegCache[extra]; + } + else if (Opcode == LoadFRegDENToZero) + { + FRegCacheStore[extra] = nullptr; // prevent previous store operation from zapping + FRegCache[extra] = EmitZeroOp(LoadFRegDENToZero, extra); + return FRegCache[extra]; + } + else if (Opcode == LoadCarry) + { + if (!CarryCache) + CarryCache = EmitZeroOp(LoadCarry, extra); + return CarryCache; + } + else if (Opcode == LoadCR) + { + if (!CRCache[extra]) + CRCache[extra] = EmitZeroOp(LoadCR, extra); + return CRCache[extra]; + } + else if (Opcode == LoadCTR) + { + if (!CTRCache) + CTRCache = EmitZeroOp(LoadCTR, extra); + return CTRCache; + } - return EmitZeroOp(Opcode, extra); + return EmitZeroOp(Opcode, extra); } InstLoc IRBuilder::FoldUOp(unsigned Opcode, InstLoc Op1, unsigned extra) { - if (Opcode == StoreGReg) - { - // Reg store folding: save the value for load folding. - // If there's a previous store, zap it because it's dead. - GRegCache[extra] = Op1; - if (GRegCacheStore[extra]) - *GRegCacheStore[extra] = 0; + if (Opcode == StoreGReg) + { + // Reg store folding: save the value for load folding. + // If there's a previous store, zap it because it's dead. + GRegCache[extra] = Op1; + if (GRegCacheStore[extra]) + *GRegCacheStore[extra] = 0; - GRegCacheStore[extra] = EmitUOp(StoreGReg, Op1, extra); - return GRegCacheStore[extra]; - } - else if (Opcode == StoreFReg) - { - FRegCache[extra] = Op1; - if (FRegCacheStore[extra]) - *FRegCacheStore[extra] = 0; + GRegCacheStore[extra] = EmitUOp(StoreGReg, Op1, extra); + return GRegCacheStore[extra]; + } + else if (Opcode == StoreFReg) + { + FRegCache[extra] = Op1; + if (FRegCacheStore[extra]) + *FRegCacheStore[extra] = 0; - FRegCacheStore[extra] = EmitUOp(StoreFReg, Op1, extra); - return FRegCacheStore[extra]; - } - else if (Opcode == StoreCarry) - { - CarryCache = Op1; - if (CarryCacheStore) - *CarryCacheStore = 0; + FRegCacheStore[extra] = EmitUOp(StoreFReg, Op1, extra); + return FRegCacheStore[extra]; + } + else if (Opcode == StoreCarry) + { + CarryCache = Op1; + if (CarryCacheStore) + *CarryCacheStore = 0; - CarryCacheStore = EmitUOp(StoreCarry, Op1, extra); - return CarryCacheStore; - } - else if (Opcode == StoreCR) - { - CRCache[extra] = Op1; - if (CRCacheStore[extra]) - *CRCacheStore[extra] = 0; + CarryCacheStore = EmitUOp(StoreCarry, Op1, extra); + return CarryCacheStore; + } + else if (Opcode == StoreCR) + { + CRCache[extra] = Op1; + if (CRCacheStore[extra]) + *CRCacheStore[extra] = 0; - CRCacheStore[extra] = EmitUOp(StoreCR, Op1, extra); - return CRCacheStore[extra]; - } - else if (Opcode == StoreCTR) - { - CTRCache = Op1; - if (CTRCacheStore) - *CTRCacheStore = 0; + CRCacheStore[extra] = EmitUOp(StoreCR, Op1, extra); + return CRCacheStore[extra]; + } + else if (Opcode == StoreCTR) + { + CTRCache = Op1; + if (CTRCacheStore) + *CTRCacheStore = 0; - CTRCacheStore = EmitUOp(StoreCTR, Op1, extra); - return CTRCacheStore; - } - else if (Opcode == CompactMRegToPacked) - { - if (getOpcode(*Op1) == ExpandPackedToMReg) - return getOp1(Op1); - } - else if (Opcode == DoubleToSingle) - { - if (getOpcode(*Op1) == DupSingleToMReg) - return getOp1(Op1); + CTRCacheStore = EmitUOp(StoreCTR, Op1, extra); + return CTRCacheStore; + } + else if (Opcode == CompactMRegToPacked) + { + if (getOpcode(*Op1) == ExpandPackedToMReg) + return getOp1(Op1); + } + else if (Opcode == DoubleToSingle) + { + if (getOpcode(*Op1) == DupSingleToMReg) + return getOp1(Op1); - if (getOpcode(*Op1) >= FDMul && getOpcode(*Op1) <= FDSub) - { - InstLoc OOp1 = getOp1(Op1), OOp2 = getOp2(Op1); - if (getOpcode(*OOp1) == DupSingleToMReg && - getOpcode(*OOp2) == DupSingleToMReg) - { - if (getOpcode(*Op1) == FDMul) - return FoldBiOp(FSMul, getOp1(OOp1), getOp2(OOp2)); - else if (getOpcode(*Op1) == FDAdd) - return FoldBiOp(FSAdd, getOp1(OOp1), getOp2(OOp2)); - else if (getOpcode(*Op1) == FDSub) - return FoldBiOp(FSSub, getOp1(OOp1), getOp2(OOp2)); - } - } - } - else if (Opcode == Not) - { - if (getOpcode(*Op1) == Not) - { - return getOp1(Op1); - } - } - else if (Opcode == FastCRGTSet) - { - if (getOpcode(*Op1) == ICmpCRSigned) - return EmitICmpSgt(getOp1(Op1), getOp2(Op1)); - if (getOpcode(*Op1) == ICmpCRUnsigned) - return EmitICmpUgt(getOp1(Op1), getOp2(Op1)); - if (isImm(*Op1)) - return EmitIntConst((s64)GetImmValue64(Op1) > 0); - } - else if (Opcode == FastCRLTSet) - { - if (getOpcode(*Op1) == ICmpCRSigned) - return EmitICmpSlt(getOp1(Op1), getOp2(Op1)); - if (getOpcode(*Op1) == ICmpCRUnsigned) - return EmitICmpUlt(getOp1(Op1), getOp2(Op1)); - if (isImm(*Op1)) - return EmitIntConst(!!(GetImmValue64(Op1) & (1ull << 62))); - } - else if (Opcode == FastCREQSet) - { - if (getOpcode(*Op1) == ICmpCRSigned || getOpcode(*Op1) == ICmpCRUnsigned) - return EmitICmpEq(getOp1(Op1), getOp2(Op1)); - if (isImm(*Op1)) - return EmitIntConst((GetImmValue64(Op1) & 0xFFFFFFFFU) == 0); - } + if (getOpcode(*Op1) >= FDMul && getOpcode(*Op1) <= FDSub) + { + InstLoc OOp1 = getOp1(Op1), OOp2 = getOp2(Op1); + if (getOpcode(*OOp1) == DupSingleToMReg && getOpcode(*OOp2) == DupSingleToMReg) + { + if (getOpcode(*Op1) == FDMul) + return FoldBiOp(FSMul, getOp1(OOp1), getOp2(OOp2)); + else if (getOpcode(*Op1) == FDAdd) + return FoldBiOp(FSAdd, getOp1(OOp1), getOp2(OOp2)); + else if (getOpcode(*Op1) == FDSub) + return FoldBiOp(FSSub, getOp1(OOp1), getOp2(OOp2)); + } + } + } + else if (Opcode == Not) + { + if (getOpcode(*Op1) == Not) + { + return getOp1(Op1); + } + } + else if (Opcode == FastCRGTSet) + { + if (getOpcode(*Op1) == ICmpCRSigned) + return EmitICmpSgt(getOp1(Op1), getOp2(Op1)); + if (getOpcode(*Op1) == ICmpCRUnsigned) + return EmitICmpUgt(getOp1(Op1), getOp2(Op1)); + if (isImm(*Op1)) + return EmitIntConst((s64)GetImmValue64(Op1) > 0); + } + else if (Opcode == FastCRLTSet) + { + if (getOpcode(*Op1) == ICmpCRSigned) + return EmitICmpSlt(getOp1(Op1), getOp2(Op1)); + if (getOpcode(*Op1) == ICmpCRUnsigned) + return EmitICmpUlt(getOp1(Op1), getOp2(Op1)); + if (isImm(*Op1)) + return EmitIntConst(!!(GetImmValue64(Op1) & (1ull << 62))); + } + else if (Opcode == FastCREQSet) + { + if (getOpcode(*Op1) == ICmpCRSigned || getOpcode(*Op1) == ICmpCRUnsigned) + return EmitICmpEq(getOp1(Op1), getOp2(Op1)); + if (isImm(*Op1)) + return EmitIntConst((GetImmValue64(Op1) & 0xFFFFFFFFU) == 0); + } - return EmitUOp(Opcode, Op1, extra); + return EmitUOp(Opcode, Op1, extra); } // Fold Add opcode. Some rules are ported from LLVM InstLoc IRBuilder::FoldAdd(InstLoc Op1, InstLoc Op2) { - simplifyCommutative(Add, Op1, Op2); + simplifyCommutative(Add, Op1, Op2); - // i0 + i1 => (i0 + i1) - if (isImm(*Op1) && isImm(*Op2)) - { - return EmitIntConst(GetImmValue(Op1) + GetImmValue(Op2)); - } + // i0 + i1 => (i0 + i1) + if (isImm(*Op1) && isImm(*Op2)) + { + return EmitIntConst(GetImmValue(Op1) + GetImmValue(Op2)); + } - // x + 0 => x - if (isImm(*Op2) && GetImmValue(Op2) == 0) - { - return Op1; - } + // x + 0 => x + if (isImm(*Op2) && GetImmValue(Op2) == 0) + { + return Op1; + } - // x + (y - x) --> y - if (getOpcode(*Op2) == Sub && isSameValue(Op1, getOp2(Op2))) - { - return getOp1(Op2); - } + // x + (y - x) --> y + if (getOpcode(*Op2) == Sub && isSameValue(Op1, getOp2(Op2))) + { + return getOp1(Op2); + } - // (x - y) + y => x - if (getOpcode(*Op1) == Sub && isSameValue(getOp2(Op1), Op2)) - { - return getOp1(Op1); - } + // (x - y) + y => x + if (getOpcode(*Op1) == Sub && isSameValue(getOp2(Op1), Op2)) + { + return getOp1(Op1); + } - if (InstLoc negOp1 = isNeg(Op1)) - { - //// TODO: Test the folding below - //// -A + -B --> -(A + B) - //if (InstLoc negOp2 = isNeg(Op2)) - //{ - // return FoldSub(EmitIntConst(0), FoldAdd(negOp1, negOp2)); - //} + if (InstLoc negOp1 = isNeg(Op1)) + { + //// TODO: Test the folding below + //// -A + -B --> -(A + B) + // if (InstLoc negOp2 = isNeg(Op2)) + //{ + // return FoldSub(EmitIntConst(0), FoldAdd(negOp1, negOp2)); + //} - // -A + B --> B - A - return FoldSub(Op2, negOp1); - } + // -A + B --> B - A + return FoldSub(Op2, negOp1); + } - // A + -B --> A - B - if (InstLoc negOp2 = isNeg(Op2)) - { - return FoldSub(Op1, negOp2); - } + // A + -B --> A - B + if (InstLoc negOp2 = isNeg(Op2)) + { + return FoldSub(Op1, negOp2); + } - // (x * i0) + x => x * (i0 + 1) - if (getOpcode(*Op1) == Mul && isImm(*getOp2(Op1)) && isSameValue(getOp1(Op1), Op2)) - { - return FoldMul(getOp1(Op1), EmitIntConst(GetImmValue(getOp2(Op1)) + 1)); - } + // (x * i0) + x => x * (i0 + 1) + if (getOpcode(*Op1) == Mul && isImm(*getOp2(Op1)) && isSameValue(getOp1(Op1), Op2)) + { + return FoldMul(getOp1(Op1), EmitIntConst(GetImmValue(getOp2(Op1)) + 1)); + } - //// TODO: Test the folding below - //// (x * i0) + (x * i1) => x * (i0 + i1) - //if (getOpcode(*Op1) == Mul && getOpcode(*Op2) == Mul && isSameValue(getOp1(Op1), getOp1(Op2)) && isImm(*getOp2(Op1)) && isImm(*getOp2(Op2))) - //{ - // return FoldMul(getOp1(Op1), EmitIntConst(GetImmValue(getOp2(Op1)) + GetImmValue(getOp2(Op2)))); - //} + //// TODO: Test the folding below + //// (x * i0) + (x * i1) => x * (i0 + i1) + // if (getOpcode(*Op1) == Mul && getOpcode(*Op2) == Mul && isSameValue(getOp1(Op1), getOp1(Op2)) + // && isImm(*getOp2(Op1)) && isImm(*getOp2(Op2))) + //{ + // return FoldMul(getOp1(Op1), EmitIntConst(GetImmValue(getOp2(Op1)) + + //GetImmValue(getOp2(Op2)))); + //} - // x + x * i0 => x * (i0 + 1) - if (getOpcode(*Op2) == Mul && isImm(*getOp2(Op2)) && isSameValue(Op1, getOp1(Op2))) - { - return FoldMul(Op1, EmitIntConst(GetImmValue(getOp2(Op2)) + 1)); - } + // x + x * i0 => x * (i0 + 1) + if (getOpcode(*Op2) == Mul && isImm(*getOp2(Op2)) && isSameValue(Op1, getOp1(Op2))) + { + return FoldMul(Op1, EmitIntConst(GetImmValue(getOp2(Op2)) + 1)); + } - // w * x + y * z => w * (x + z) iff w == y - if (getOpcode(*Op1) == Mul && getOpcode(*Op2) == Mul) - { - InstLoc w = getOp1(Op1); - InstLoc x = getOp2(Op1); - InstLoc y = getOp1(Op2); - InstLoc z = getOp2(Op2); + // w * x + y * z => w * (x + z) iff w == y + if (getOpcode(*Op1) == Mul && getOpcode(*Op2) == Mul) + { + InstLoc w = getOp1(Op1); + InstLoc x = getOp2(Op1); + InstLoc y = getOp1(Op2); + InstLoc z = getOp2(Op2); - if (!isSameValue(w, y)) - { - if (isSameValue(w, z)) - { - std::swap(y, z); - } - else if (isSameValue(y, x)) - { - std::swap(w, x); - } - else if (isSameValue(x, z)) - { - std::swap(y, z); - std::swap(w, x); - } - } + if (!isSameValue(w, y)) + { + if (isSameValue(w, z)) + { + std::swap(y, z); + } + else if (isSameValue(y, x)) + { + std::swap(w, x); + } + else if (isSameValue(x, z)) + { + std::swap(y, z); + std::swap(w, x); + } + } - if (isSameValue(w, y)) - { - return FoldMul(w, FoldAdd(x, z)); - } - } + if (isSameValue(w, y)) + { + return FoldMul(w, FoldAdd(x, z)); + } + } - return EmitBiOp(Add, Op1, Op2); + return EmitBiOp(Add, Op1, Op2); } // Fold Sub opcode. Some rules are ported from LLVM InstLoc IRBuilder::FoldSub(InstLoc Op1, InstLoc Op2) { - // (x - x) => 0 - if (isSameValue(Op1, Op2)) - { - return EmitIntConst(0); - } + // (x - x) => 0 + if (isSameValue(Op1, Op2)) + { + return EmitIntConst(0); + } - // x - (-A) => x + A - if (InstLoc negOp2 = isNeg(Op2)) - { - return FoldAdd(Op1, negOp2); - } + // x - (-A) => x + A + if (InstLoc negOp2 = isNeg(Op2)) + { + return FoldAdd(Op1, negOp2); + } - // (x - i0) => x + -i0 - if (isImm(*Op2)) - { - return FoldAdd(Op1, EmitIntConst(-GetImmValue(Op2))); - } + // (x - i0) => x + -i0 + if (isImm(*Op2)) + { + return FoldAdd(Op1, EmitIntConst(-GetImmValue(Op2))); + } - if (getOpcode(*Op2) == Add) - { - // x - (x + y) => -y - if (isSameValue(Op1, getOp1(Op2))) - { - return FoldSub(EmitIntConst(0), getOp2(Op2)); - } + if (getOpcode(*Op2) == Add) + { + // x - (x + y) => -y + if (isSameValue(Op1, getOp1(Op2))) + { + return FoldSub(EmitIntConst(0), getOp2(Op2)); + } - // x - (y + x) => -y - if (isSameValue(Op1, getOp2(Op2))) - { - return FoldSub(EmitIntConst(0), getOp1(Op2)); - } + // x - (y + x) => -y + if (isSameValue(Op1, getOp2(Op2))) + { + return FoldSub(EmitIntConst(0), getOp1(Op2)); + } - // i0 - (x + i1) => (i0 - i1) - x - if (isImm(*Op1) && isImm(*getOp2(Op2))) - { - return FoldSub(EmitIntConst(GetImmValue(Op1) - GetImmValue(getOp2(Op2))), getOp1(Op2)); - } - } + // i0 - (x + i1) => (i0 - i1) - x + if (isImm(*Op1) && isImm(*getOp2(Op2))) + { + return FoldSub(EmitIntConst(GetImmValue(Op1) - GetImmValue(getOp2(Op2))), getOp1(Op2)); + } + } - //// TODO: Test the folding below - //// 0 - (C << X) -> (-C << X) - //if (isImm(*Op1) && GetImmValue(Op1) == 0 && getOpcode(*Op2) == Shl && isImm(*getOp1(Op2))) - //{ - // return FoldShl(EmitIntConst(-GetImmValue(getOp1(Op2))), getOp2(Op2)); - //} + //// TODO: Test the folding below + //// 0 - (C << X) -> (-C << X) + // if (isImm(*Op1) && GetImmValue(Op1) == 0 && getOpcode(*Op2) == Shl && isImm(*getOp1(Op2))) + //{ + // return FoldShl(EmitIntConst(-GetImmValue(getOp1(Op2))), getOp2(Op2)); + //} - //// TODO: Test the folding below - //// x - x * i0 = x * (1 - i0) - //if (getOpcode(*Op2) == Mul && isImm(*getOp2(Op2)) && isSameValue(Op1, getOp1(Op2))) - //{ - // return FoldMul(Op1, EmitIntConst(1 - GetImmValue(getOp2(Op2)))); - //} + //// TODO: Test the folding below + //// x - x * i0 = x * (1 - i0) + // if (getOpcode(*Op2) == Mul && isImm(*getOp2(Op2)) && isSameValue(Op1, getOp1(Op2))) + //{ + // return FoldMul(Op1, EmitIntConst(1 - GetImmValue(getOp2(Op2)))); + //} - if (getOpcode(*Op1) == Add) - { - // (x + y) - x => y - if (isSameValue(getOp1(Op1), Op2)) - { - return getOp2(Op1); - } + if (getOpcode(*Op1) == Add) + { + // (x + y) - x => y + if (isSameValue(getOp1(Op1), Op2)) + { + return getOp2(Op1); + } - // (x + y) - y => x - if (isSameValue(getOp2(Op1), Op2)) - { - return getOp1(Op1); - } - } + // (x + y) - y => x + if (isSameValue(getOp2(Op1), Op2)) + { + return getOp1(Op1); + } + } - //if (getOpcode(*Op1) == Sub) - //{ - // // TODO: Test the folding below - // // (x - y) - x => -y - // if (isSameValue(getOp1(Op1), Op2)) - // { - // return FoldSub(EmitIntConst(0), getOp2(Op1)); - // } - //} + // if (getOpcode(*Op1) == Sub) + //{ + // // TODO: Test the folding below + // // (x - y) - x => -y + // if (isSameValue(getOp1(Op1), Op2)) + // { + // return FoldSub(EmitIntConst(0), getOp2(Op1)); + // } + //} - if (getOpcode(*Op1) == Mul) - { - // x * i0 - x => x * (i0 - 1) - if (isImm(*getOp2(Op1)) && isSameValue(getOp1(Op1), Op2)) - { - return FoldMul(getOp1(Op1), EmitIntConst(GetImmValue(getOp2(Op1)) - 1)); - } + if (getOpcode(*Op1) == Mul) + { + // x * i0 - x => x * (i0 - 1) + if (isImm(*getOp2(Op1)) && isSameValue(getOp1(Op1), Op2)) + { + return FoldMul(getOp1(Op1), EmitIntConst(GetImmValue(getOp2(Op1)) - 1)); + } - //// TODO: Test the folding below - //// x * i0 - x * i1 => x * (i0 - i1) - //if (getOpcode(*Op2) == Mul && isSameValue(getOp1(Op1), getOp1(Op2)) && isImm(*getOp2(Op1)) && isImm(*getOp2(Op2))) - //{ - // return FoldMul(getOp1(Op1), EmitIntConst(GetImmValue(getOp2(Op1)) + GetImmValue(getOp2(Op2)))); - //} - } + //// TODO: Test the folding below + //// x * i0 - x * i1 => x * (i0 - i1) + // if (getOpcode(*Op2) == Mul && isSameValue(getOp1(Op1), getOp1(Op2)) && isImm(*getOp2(Op1)) && + // isImm(*getOp2(Op2))) + //{ + // return FoldMul(getOp1(Op1), EmitIntConst(GetImmValue(getOp2(Op1)) + + //GetImmValue(getOp2(Op2)))); + //} + } - // (x + i0) - (y + i1) => (x - y) + (i0 - i1) - if (getOpcode(*Op1) == Add && getOpcode(*Op2) == Add && isImm(*getOp2(Op1)) && isImm(*getOp2(Op2))) - { - return FoldAdd(FoldSub(getOp1(Op1), getOp1(Op2)), EmitIntConst(GetImmValue(getOp2(Op1)) - GetImmValue(getOp2(Op2)))); - } + // (x + i0) - (y + i1) => (x - y) + (i0 - i1) + if (getOpcode(*Op1) == Add && getOpcode(*Op2) == Add && isImm(*getOp2(Op1)) && + isImm(*getOp2(Op2))) + { + return FoldAdd(FoldSub(getOp1(Op1), getOp1(Op2)), + EmitIntConst(GetImmValue(getOp2(Op1)) - GetImmValue(getOp2(Op2)))); + } - // w * x - y * z => w * (x - z) iff w == y - if (getOpcode(*Op1) == Mul && getOpcode(*Op2) == Mul) - { - InstLoc w = getOp1(Op1); - InstLoc x = getOp2(Op1); - InstLoc y = getOp1(Op2); - InstLoc z = getOp2(Op2); + // w * x - y * z => w * (x - z) iff w == y + if (getOpcode(*Op1) == Mul && getOpcode(*Op2) == Mul) + { + InstLoc w = getOp1(Op1); + InstLoc x = getOp2(Op1); + InstLoc y = getOp1(Op2); + InstLoc z = getOp2(Op2); - if (!isSameValue(w, y)) - { - if (isSameValue(w, z)) - { - std::swap(y, z); - } - else if (isSameValue(y, x)) - { - std::swap(w, x); - } - else if (isSameValue(x, z)) - { - std::swap(y, z); - std::swap(w, x); - } - } + if (!isSameValue(w, y)) + { + if (isSameValue(w, z)) + { + std::swap(y, z); + } + else if (isSameValue(y, x)) + { + std::swap(w, x); + } + else if (isSameValue(x, z)) + { + std::swap(y, z); + std::swap(w, x); + } + } - if (isSameValue(w, y)) - { - return FoldMul(w, FoldSub(x, z)); - } - } + if (isSameValue(w, y)) + { + return FoldMul(w, FoldSub(x, z)); + } + } - return EmitBiOp(Sub, Op1, Op2); + return EmitBiOp(Sub, Op1, Op2); } // Fold Mul opcode. Some rules are ported from LLVM InstLoc IRBuilder::FoldMul(InstLoc Op1, InstLoc Op2) { - simplifyCommutative(Mul, Op1, Op2); + simplifyCommutative(Mul, Op1, Op2); - // i0 * i1 => (i0 * i1) - if (isImm(*Op1) && isImm(*Op2)) - { - return EmitIntConst(GetImmValue(Op1) * GetImmValue(Op2)); - } + // i0 * i1 => (i0 * i1) + if (isImm(*Op1) && isImm(*Op2)) + { + return EmitIntConst(GetImmValue(Op1) * GetImmValue(Op2)); + } - // (x << i0) * i1 => x * (i1 << i0) - if (getOpcode(*Op1) == Shl && isImm(*getOp2(Op1)) && isImm(*Op2)) - { - return FoldMul(getOp1(Op1), EmitIntConst(GetImmValue(Op2) << GetImmValue(getOp2(Op1)))); - } + // (x << i0) * i1 => x * (i1 << i0) + if (getOpcode(*Op1) == Shl && isImm(*getOp2(Op1)) && isImm(*Op2)) + { + return FoldMul(getOp1(Op1), EmitIntConst(GetImmValue(Op2) << GetImmValue(getOp2(Op1)))); + } - if (isImm(*Op2)) - { - const unsigned imm = GetImmValue(Op2); + if (isImm(*Op2)) + { + const unsigned imm = GetImmValue(Op2); - // x * 0 => 0 - if (imm == 0) - { - return EmitIntConst(0); - } + // x * 0 => 0 + if (imm == 0) + { + return EmitIntConst(0); + } - // x * -1 => 0 - x - if (imm == -1U) - { - return FoldSub(EmitIntConst(0), Op1); - } + // x * -1 => 0 - x + if (imm == -1U) + { + return FoldSub(EmitIntConst(0), Op1); + } - for (unsigned i0 = 0; i0 < 30; ++i0) - { - // x * (1 << i0) => x << i0 - // One "shl" is faster than one "imul". - if (imm == (1U << i0)) - { - return FoldShl(Op1, EmitIntConst(i0)); - } - } - } + for (unsigned i0 = 0; i0 < 30; ++i0) + { + // x * (1 << i0) => x << i0 + // One "shl" is faster than one "imul". + if (imm == (1U << i0)) + { + return FoldShl(Op1, EmitIntConst(i0)); + } + } + } - // (x + i0) * i1 => x * i1 + i0 * i1 - // The later format can be folded by other rules, again. - if (getOpcode(*Op1) == Add && isImm(*getOp2(Op1)) && isImm(*Op2)) - { - return FoldAdd(FoldMul(getOp1(Op1), Op2), EmitIntConst(GetImmValue(getOp2(Op1)) * GetImmValue(Op2))); - } + // (x + i0) * i1 => x * i1 + i0 * i1 + // The later format can be folded by other rules, again. + if (getOpcode(*Op1) == Add && isImm(*getOp2(Op1)) && isImm(*Op2)) + { + return FoldAdd(FoldMul(getOp1(Op1), Op2), + EmitIntConst(GetImmValue(getOp2(Op1)) * GetImmValue(Op2))); + } - //// TODO: Test the folding below - //// -X * -Y => X * Y - //if (InstLoc negOp1 = isNeg(Op1)) - //{ - // if (InstLoc negOp2 = isNeg(Op2)) - // { - // return FoldMul(negOp1, negOp2); - // } - //} + //// TODO: Test the folding below + //// -X * -Y => X * Y + // if (InstLoc negOp1 = isNeg(Op1)) + //{ + // if (InstLoc negOp2 = isNeg(Op2)) + // { + // return FoldMul(negOp1, negOp2); + // } + //} - //// TODO: Test the folding below - //// x * (1 << y) => x << y - //if (getOpcode(*Op2) == Shl && isImm(*getOp1(Op2)) && GetImmValue(getOp1(Op2)) == 1) - //{ - // return FoldShl(Op1, getOp2(Op2)); - //} + //// TODO: Test the folding below + //// x * (1 << y) => x << y + // if (getOpcode(*Op2) == Shl && isImm(*getOp1(Op2)) && GetImmValue(getOp1(Op2)) == 1) + //{ + // return FoldShl(Op1, getOp2(Op2)); + //} - //// TODO: Test the folding below - //// (1 << y) * x => x << y - //if (getOpcode(*Op1) == Shl && isImm(*getOp1(Op1)) && GetImmValue(getOp1(Op1)) == 1) - //{ - // return FoldShl(Op2, getOp2(Op1)); - //} + //// TODO: Test the folding below + //// (1 << y) * x => x << y + // if (getOpcode(*Op1) == Shl && isImm(*getOp1(Op1)) && GetImmValue(getOp1(Op1)) == 1) + //{ + // return FoldShl(Op2, getOp2(Op1)); + //} - // x * y (where y is 0 or 1) => (0 - y) & x - if (ComputeKnownZeroBits(Op2) == -2U) - { - return FoldAnd(FoldSub(EmitIntConst(0), Op2), Op1); - } + // x * y (where y is 0 or 1) => (0 - y) & x + if (ComputeKnownZeroBits(Op2) == -2U) + { + return FoldAnd(FoldSub(EmitIntConst(0), Op2), Op1); + } - // x * y (where y is 0 or 1) => (0 - x) & y - if (ComputeKnownZeroBits(Op1) == -2U) - { - return FoldAnd(FoldSub(EmitIntConst(0), Op1), Op2); - } + // x * y (where y is 0 or 1) => (0 - x) & y + if (ComputeKnownZeroBits(Op1) == -2U) + { + return FoldAnd(FoldSub(EmitIntConst(0), Op1), Op2); + } - return EmitBiOp(Mul, Op1, Op2); + return EmitBiOp(Mul, Op1, Op2); } InstLoc IRBuilder::FoldMulHighUnsigned(InstLoc Op1, InstLoc Op2) { - // (i0 * i1) >> 32 - if (isImm(*Op1) && isImm(*Op2)) - { - return EmitIntConst((u32)(((u64)GetImmValue(Op1) * (u64)GetImmValue(Op2)) >> 32)); - } + // (i0 * i1) >> 32 + if (isImm(*Op1) && isImm(*Op2)) + { + return EmitIntConst((u32)(((u64)GetImmValue(Op1) * (u64)GetImmValue(Op2)) >> 32)); + } - if (isImm(*Op1) && !isImm(*Op2)) - { - return FoldMulHighUnsigned(Op2, Op1); - } + if (isImm(*Op1) && !isImm(*Op2)) + { + return FoldMulHighUnsigned(Op2, Op1); + } - if (isImm(*Op2)) - { - const unsigned imm = GetImmValue(Op2); + if (isImm(*Op2)) + { + const unsigned imm = GetImmValue(Op2); - // (x * 0) >> 32 => 0 - if (imm == 0) - { - return EmitIntConst(0); - } + // (x * 0) >> 32 => 0 + if (imm == 0) + { + return EmitIntConst(0); + } - for (unsigned i0 = 0; i0 < 30; ++i0) - { - // (x * (1 << i0)) => x >> (32 - i0) - // One "shl" is faster than one "imul". - if (imm == (1U << i0)) - { - return FoldShrl(Op1, EmitIntConst(32 - i0)); - } - } - } + for (unsigned i0 = 0; i0 < 30; ++i0) + { + // (x * (1 << i0)) => x >> (32 - i0) + // One "shl" is faster than one "imul". + if (imm == (1U << i0)) + { + return FoldShrl(Op1, EmitIntConst(32 - i0)); + } + } + } - return EmitBiOp(MulHighUnsigned, Op1, Op2); + return EmitBiOp(MulHighUnsigned, Op1, Op2); } InstLoc IRBuilder::FoldAnd(InstLoc Op1, InstLoc Op2) { - simplifyCommutative(And, Op1, Op2); + simplifyCommutative(And, Op1, Op2); - if (isImm(*Op1) && isImm(*Op2)) - { - return EmitIntConst(GetImmValue(Op1) & GetImmValue(Op2)); - } + if (isImm(*Op1) && isImm(*Op2)) + { + return EmitIntConst(GetImmValue(Op1) & GetImmValue(Op2)); + } - if (isImm(*Op2)) - { - if (!GetImmValue(Op2)) - return EmitIntConst(0); + if (isImm(*Op2)) + { + if (!GetImmValue(Op2)) + return EmitIntConst(0); - if (GetImmValue(Op2) == -1U) - return Op1; + if (GetImmValue(Op2) == -1U) + return Op1; - if (getOpcode(*Op1) == And && isImm(*getOp2(Op1))) - { - unsigned RHS = GetImmValue(Op2) & GetImmValue(getOp2(Op1)); - return FoldAnd(getOp1(Op1), EmitIntConst(RHS)); - } - else if (getOpcode(*Op1) == Rol && isImm(*getOp2(Op1))) - { - unsigned shiftMask1 = -1U << (GetImmValue(getOp2(Op1)) & 31); + if (getOpcode(*Op1) == And && isImm(*getOp2(Op1))) + { + unsigned RHS = GetImmValue(Op2) & GetImmValue(getOp2(Op1)); + return FoldAnd(getOp1(Op1), EmitIntConst(RHS)); + } + else if (getOpcode(*Op1) == Rol && isImm(*getOp2(Op1))) + { + unsigned shiftMask1 = -1U << (GetImmValue(getOp2(Op1)) & 31); - if (GetImmValue(Op2) == shiftMask1) - return FoldShl(getOp1(Op1), getOp2(Op1)); + if (GetImmValue(Op2) == shiftMask1) + return FoldShl(getOp1(Op1), getOp2(Op1)); - unsigned shiftAmt2 = ((32 - GetImmValue(getOp2(Op1))) & 31); - unsigned shiftMask2 = -1U >> shiftAmt2; + unsigned shiftAmt2 = ((32 - GetImmValue(getOp2(Op1))) & 31); + unsigned shiftMask2 = -1U >> shiftAmt2; - if (GetImmValue(Op2) == shiftMask2) - { - return FoldShrl(getOp1(Op1), EmitIntConst(shiftAmt2)); - } - } + if (GetImmValue(Op2) == shiftMask2) + { + return FoldShrl(getOp1(Op1), EmitIntConst(shiftAmt2)); + } + } - if (!(~ComputeKnownZeroBits(Op1) & ~GetImmValue(Op2))) - { - return Op1; - } + if (!(~ComputeKnownZeroBits(Op1) & ~GetImmValue(Op2))) + { + return Op1; + } - //if (getOpcode(*Op1) == Xor || getOpcode(*Op1) == Or) - //{ - // // TODO: Test the folding below - // // (x op y) & z => (x & z) op y if (y & z) == 0 - // if ((~ComputeKnownZeroBits(getOp2(Op1)) & ~ComputeKnownZeroBits(Op2)) == 0) - // { - // return FoldBiOp(getOpcode(*Op1), FoldAnd(getOp1(Op1), Op2), getOp2(Op1)); - // } + // if (getOpcode(*Op1) == Xor || getOpcode(*Op1) == Or) + //{ + // // TODO: Test the folding below + // // (x op y) & z => (x & z) op y if (y & z) == 0 + // if ((~ComputeKnownZeroBits(getOp2(Op1)) & ~ComputeKnownZeroBits(Op2)) == 0) + // { + // return FoldBiOp(getOpcode(*Op1), FoldAnd(getOp1(Op1), Op2), getOp2(Op1)); + // } - // // TODO: Test the folding below - // // (x op y) & z => (y & z) op x if (x & z) == 0 - // if ((~ComputeKnownZeroBits(getOp1(Op1)) & ~ComputeKnownZeroBits(Op2)) == 0) - // { - // return FoldBiOp(getOpcode(*Op1), FoldAnd(getOp2(Op1), Op2), getOp1(Op1)); - // } - //} - } + // // TODO: Test the folding below + // // (x op y) & z => (y & z) op x if (x & z) == 0 + // if ((~ComputeKnownZeroBits(getOp1(Op1)) & ~ComputeKnownZeroBits(Op2)) == 0) + // { + // return FoldBiOp(getOpcode(*Op1), FoldAnd(getOp2(Op1), Op2), getOp1(Op1)); + // } + //} + } - //// TODO: Test the folding below - //// (x >> z) & (y >> z) => (x & y) >> z - //if (getOpcode(*Op1) == Shrl && getOpcode(*Op2) == Shrl && isSameValue(getOp2(Op1), getOp2(Op2))) - //{ - // return FoldShl(FoldAnd(getOp1(Op1), getOp2(Op1)), getOp2(Op1)); - //} + //// TODO: Test the folding below + //// (x >> z) & (y >> z) => (x & y) >> z + // if (getOpcode(*Op1) == Shrl && getOpcode(*Op2) == Shrl && isSameValue(getOp2(Op1), + // getOp2(Op2))) + //{ + // return FoldShl(FoldAnd(getOp1(Op1), getOp2(Op1)), getOp2(Op1)); + //} - //// TODO: Test the folding below - //// ((A | N) + B) & AndRHS -> (A + B) & AndRHS iff N&AndRHS == 0 - //// ((A ^ N) + B) & AndRHS -> (A + B) & AndRHS iff N&AndRHS == 0 - //// ((A | N) - B) & AndRHS -> (A - B) & AndRHS iff N&AndRHS == 0 - //// ((A ^ N) - B) & AndRHS -> (A - B) & AndRHS iff N&AndRHS == 0 - //if ((getOpcode(*Op1) == Add || getOpcode(*Op1) == Sub) && - // (getOpcode(*getOp1(Op1)) == Or || getOpcode(*getOp1(Op1)) == Xor)) - //{ - // const InstLoc A = getOp1(getOp1(Op1)); - // const InstLoc N = getOp2(getOp1(Op1)); - // const InstLoc B = getOp2(Op1); - // const InstLoc AndRHS = Op2; - // if ((~ComputeKnownZeroBits(N) & ~ComputeKnownZeroBits(AndRHS)) == 0) - // { - // return FoldAnd(FoldBiOp(getOpcode(*Op1), A, B), AndRHS); - // } - //} + //// TODO: Test the folding below + //// ((A | N) + B) & AndRHS -> (A + B) & AndRHS iff N&AndRHS == 0 + //// ((A ^ N) + B) & AndRHS -> (A + B) & AndRHS iff N&AndRHS == 0 + //// ((A | N) - B) & AndRHS -> (A - B) & AndRHS iff N&AndRHS == 0 + //// ((A ^ N) - B) & AndRHS -> (A - B) & AndRHS iff N&AndRHS == 0 + // if ((getOpcode(*Op1) == Add || getOpcode(*Op1) == Sub) && + // (getOpcode(*getOp1(Op1)) == Or || getOpcode(*getOp1(Op1)) == Xor)) + //{ + // const InstLoc A = getOp1(getOp1(Op1)); + // const InstLoc N = getOp2(getOp1(Op1)); + // const InstLoc B = getOp2(Op1); + // const InstLoc AndRHS = Op2; + // if ((~ComputeKnownZeroBits(N) & ~ComputeKnownZeroBits(AndRHS)) == 0) + // { + // return FoldAnd(FoldBiOp(getOpcode(*Op1), A, B), AndRHS); + // } + //} - //// TODO: Test the folding below - //// (~A & ~B) == (~(A | B)) - De Morgan's Law - //if (InstLoc notOp1 = isNot(Op1)) - //{ - // if (InstLoc notOp2 = isNot(Op2)) - // { - // return FoldXor(EmitIntConst(-1U), FoldOr(notOp1, notOp2)); - // } - //} + //// TODO: Test the folding below + //// (~A & ~B) == (~(A | B)) - De Morgan's Law + // if (InstLoc notOp1 = isNot(Op1)) + //{ + // if (InstLoc notOp2 = isNot(Op2)) + // { + // return FoldXor(EmitIntConst(-1U), FoldOr(notOp1, notOp2)); + // } + //} - //// TODO: Test the folding below - //// (X^C)|Y -> (X|Y)^C iff Y&C == 0 - //if (getOpcode(*Op1) == Xor && isImm(*getOp2(Op1)) && (~ComputeKnownZeroBits(Op2) & GetImmValue(getOp2(Op1))) == 0) - //{ - // return FoldXor(FoldOr(getOp1(Op1), Op2), getOp2(Op1)); - //} + //// TODO: Test the folding below + //// (X^C)|Y -> (X|Y)^C iff Y&C == 0 + // if (getOpcode(*Op1) == Xor && isImm(*getOp2(Op1)) && (~ComputeKnownZeroBits(Op2) & + // GetImmValue(getOp2(Op1))) == 0) + //{ + // return FoldXor(FoldOr(getOp1(Op1), Op2), getOp2(Op1)); + //} - if (Op1 == Op2) - return Op1; + if (Op1 == Op2) + return Op1; - return EmitBiOp(And, Op1, Op2); + return EmitBiOp(And, Op1, Op2); } InstLoc IRBuilder::FoldOr(InstLoc Op1, InstLoc Op2) { - simplifyCommutative(Or, Op1, Op2); + simplifyCommutative(Or, Op1, Op2); - if (isImm(*Op1) && isImm(*Op2)) - { - return EmitIntConst(GetImmValue(Op1) | GetImmValue(Op2)); - } + if (isImm(*Op1) && isImm(*Op2)) + { + return EmitIntConst(GetImmValue(Op1) | GetImmValue(Op2)); + } - if (isImm(*Op2)) - { - if (!GetImmValue(Op2)) - return Op1; + if (isImm(*Op2)) + { + if (!GetImmValue(Op2)) + return Op1; - if (GetImmValue(Op2) == -1U) - return EmitIntConst(-1U); + if (GetImmValue(Op2) == -1U) + return EmitIntConst(-1U); - if (getOpcode(*Op1) == Or && isImm(*getOp2(Op1))) - { - unsigned RHS = GetImmValue(Op2) | GetImmValue(getOp2(Op1)); + if (getOpcode(*Op1) == Or && isImm(*getOp2(Op1))) + { + unsigned RHS = GetImmValue(Op2) | GetImmValue(getOp2(Op1)); - return FoldOr(getOp1(Op1), EmitIntConst(RHS)); - } + return FoldOr(getOp1(Op1), EmitIntConst(RHS)); + } - // (X & C1) | C2 --> (X | C2) & (C1|C2) - // iff (C1 & C2) == 0. - if (getOpcode(*Op1) == And && isImm(*getOp2(Op1)) && (GetImmValue(getOp2(Op1)) & GetImmValue(Op2)) == 0) - { - return FoldAnd(FoldOr(getOp1(Op1), Op2), EmitIntConst(GetImmValue(getOp2(Op1)) | GetImmValue(Op2))); - } + // (X & C1) | C2 --> (X | C2) & (C1|C2) + // iff (C1 & C2) == 0. + if (getOpcode(*Op1) == And && isImm(*getOp2(Op1)) && + (GetImmValue(getOp2(Op1)) & GetImmValue(Op2)) == 0) + { + return FoldAnd(FoldOr(getOp1(Op1), Op2), + EmitIntConst(GetImmValue(getOp2(Op1)) | GetImmValue(Op2))); + } - // (X ^ C1) | C2 --> (X | C2) ^ (C1&~C2) - if (getOpcode(*Op1) == Xor && isImm(*getOp2(Op1)) && isImm(*Op2)) - { - return FoldXor(FoldOr(getOp1(Op1), Op2), EmitIntConst(GetImmValue(getOp2(Op1)) & ~GetImmValue(Op2))); - } - } + // (X ^ C1) | C2 --> (X | C2) ^ (C1&~C2) + if (getOpcode(*Op1) == Xor && isImm(*getOp2(Op1)) && isImm(*Op2)) + { + return FoldXor(FoldOr(getOp1(Op1), Op2), + EmitIntConst(GetImmValue(getOp2(Op1)) & ~GetImmValue(Op2))); + } + } - // (~A | ~B) == (~(A & B)) - De Morgan's Law - if (getOpcode(*Op1) == Not && getOpcode(*Op2) == Not) - { - return EmitNot(FoldAnd(getOp1(Op1), getOp1(Op2))); - } + // (~A | ~B) == (~(A & B)) - De Morgan's Law + if (getOpcode(*Op1) == Not && getOpcode(*Op2) == Not) + { + return EmitNot(FoldAnd(getOp1(Op1), getOp1(Op2))); + } - if (Op1 == Op2) - return Op1; + if (Op1 == Op2) + return Op1; - return EmitBiOp(Or, Op1, Op2); + return EmitBiOp(Or, Op1, Op2); } static unsigned ICmpInverseOp(unsigned op) { - switch (op) - { - case ICmpEq: - return ICmpNe; - case ICmpNe: - return ICmpEq; - case ICmpUlt: - return ICmpUge; - case ICmpUgt: - return ICmpUle; - case ICmpUle: - return ICmpUgt; - case ICmpUge: - return ICmpUlt; - case ICmpSlt: - return ICmpSge; - case ICmpSgt: - return ICmpSle; - case ICmpSle: - return ICmpSgt; - case ICmpSge: - return ICmpSlt; - default: - PanicAlert("Bad opcode"); - return Nop; - } + switch (op) + { + case ICmpEq: + return ICmpNe; + case ICmpNe: + return ICmpEq; + case ICmpUlt: + return ICmpUge; + case ICmpUgt: + return ICmpUle; + case ICmpUle: + return ICmpUgt; + case ICmpUge: + return ICmpUlt; + case ICmpSlt: + return ICmpSge; + case ICmpSgt: + return ICmpSle; + case ICmpSle: + return ICmpSgt; + case ICmpSge: + return ICmpSlt; + default: + PanicAlert("Bad opcode"); + return Nop; + } } InstLoc IRBuilder::FoldXor(InstLoc Op1, InstLoc Op2) { - simplifyCommutative(Xor, Op1, Op2); + simplifyCommutative(Xor, Op1, Op2); - if (isImm(*Op1) && isImm(*Op2)) - { - return EmitIntConst(GetImmValue(Op1) ^ GetImmValue(Op2)); - } + if (isImm(*Op1) && isImm(*Op2)) + { + return EmitIntConst(GetImmValue(Op1) ^ GetImmValue(Op2)); + } - if (isImm(*Op2)) - { - if (!GetImmValue(Op2)) - return Op1; + if (isImm(*Op2)) + { + if (!GetImmValue(Op2)) + return Op1; - if (GetImmValue(Op2) == 0xFFFFFFFFU) - { - return EmitNot(Op1); - } + if (GetImmValue(Op2) == 0xFFFFFFFFU) + { + return EmitNot(Op1); + } - if (getOpcode(*Op1) == Xor && isImm(*getOp2(Op1))) - { - unsigned RHS = GetImmValue(Op2) ^ - GetImmValue(getOp2(Op1)); - return FoldXor(getOp1(Op1), EmitIntConst(RHS)); - } + if (getOpcode(*Op1) == Xor && isImm(*getOp2(Op1))) + { + unsigned RHS = GetImmValue(Op2) ^ GetImmValue(getOp2(Op1)); + return FoldXor(getOp1(Op1), EmitIntConst(RHS)); + } - if (isICmp(getOpcode(*Op1)) && GetImmValue(Op2) == 1) - { - return FoldBiOp(ICmpInverseOp(getOpcode(*Op1)), getOp1(Op1), getOp2(Op1)); - } - } + if (isICmp(getOpcode(*Op1)) && GetImmValue(Op2) == 1) + { + return FoldBiOp(ICmpInverseOp(getOpcode(*Op1)), getOp1(Op1), getOp2(Op1)); + } + } - if (Op1 == Op2) - return EmitIntConst(0); + if (Op1 == Op2) + return EmitIntConst(0); - return EmitBiOp(Xor, Op1, Op2); + return EmitBiOp(Xor, Op1, Op2); } InstLoc IRBuilder::FoldShl(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op2)) - { - // Shl x 0 => x - if (!GetImmValue(Op2)) - { - return Op1; - } + if (isImm(*Op2)) + { + // Shl x 0 => x + if (!GetImmValue(Op2)) + { + return Op1; + } - if (isImm(*Op1)) - return EmitIntConst(GetImmValue(Op1) << (GetImmValue(Op2) & 31)); + if (isImm(*Op1)) + return EmitIntConst(GetImmValue(Op1) << (GetImmValue(Op2) & 31)); - // ((x * i0) << i1) == x * (i0 << i1) - if (getOpcode(*Op1) == Mul && isImm(*getOp2(Op1))) - { - return FoldMul(getOp1(Op1), EmitIntConst(GetImmValue(getOp2(Op1)) << GetImmValue(Op2))); - } - } + // ((x * i0) << i1) == x * (i0 << i1) + if (getOpcode(*Op1) == Mul && isImm(*getOp2(Op1))) + { + return FoldMul(getOp1(Op1), EmitIntConst(GetImmValue(getOp2(Op1)) << GetImmValue(Op2))); + } + } - // 0 << x => 0 - if (isImm(*Op1) && GetImmValue(Op1) == 0) - { - return EmitIntConst(0); - } + // 0 << x => 0 + if (isImm(*Op1) && GetImmValue(Op1) == 0) + { + return EmitIntConst(0); + } - return EmitBiOp(Shl, Op1, Op2); + return EmitBiOp(Shl, Op1, Op2); } InstLoc IRBuilder::FoldShrl(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op1) && isImm(*Op2)) - { - return EmitIntConst(GetImmValue(Op1) >> (GetImmValue(Op2) & 31)); - } + if (isImm(*Op1) && isImm(*Op2)) + { + return EmitIntConst(GetImmValue(Op1) >> (GetImmValue(Op2) & 31)); + } - return EmitBiOp(Shrl, Op1, Op2); + return EmitBiOp(Shrl, Op1, Op2); } InstLoc IRBuilder::FoldRol(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op2)) - { - if (isImm(*Op1)) - return EmitIntConst(_rotl(GetImmValue(Op1), GetImmValue(Op2))); + if (isImm(*Op2)) + { + if (isImm(*Op1)) + return EmitIntConst(_rotl(GetImmValue(Op1), GetImmValue(Op2))); - if (!(GetImmValue(Op2) & 31)) - return Op1; - } - return EmitBiOp(Rol, Op1, Op2); + if (!(GetImmValue(Op2) & 31)) + return Op1; + } + return EmitBiOp(Rol, Op1, Op2); } InstLoc IRBuilder::FoldBranchCond(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op1)) - { - if (GetImmValue(Op1)) - return EmitBranchUncond(Op2); + if (isImm(*Op1)) + { + if (GetImmValue(Op1)) + return EmitBranchUncond(Op2); - return nullptr; - } + return nullptr; + } - return EmitBiOp(BranchCond, Op1, Op2); + return EmitBiOp(BranchCond, Op1, Op2); } InstLoc IRBuilder::FoldICmp(unsigned Opcode, InstLoc Op1, InstLoc Op2) { - if (isImm(*Op1)) - { - if (isImm(*Op2)) - { - unsigned result = 0; - switch (Opcode) - { - case ICmpEq: - result = GetImmValue(Op1) == GetImmValue(Op2); - break; - case ICmpNe: - result = GetImmValue(Op1) != GetImmValue(Op2); - break; - case ICmpUgt: - result = GetImmValue(Op1) > GetImmValue(Op2); - break; - case ICmpUlt: - result = GetImmValue(Op1) < GetImmValue(Op2); - break; - case ICmpUge: - result = GetImmValue(Op1) >= GetImmValue(Op2); - break; - case ICmpUle: - result = GetImmValue(Op1) <= GetImmValue(Op2); - break; - case ICmpSgt: - result = (signed)GetImmValue(Op1) > (signed)GetImmValue(Op2); - break; - case ICmpSlt: - result = (signed)GetImmValue(Op1) < (signed)GetImmValue(Op2); - break; - case ICmpSge: - result = (signed)GetImmValue(Op1) >= (signed)GetImmValue(Op2); - break; - case ICmpSle: - result = (signed)GetImmValue(Op1) <= (signed)GetImmValue(Op2); - break; - } - return EmitIntConst(result); - } - switch (Opcode) - { - case ICmpEq: - return FoldICmp(ICmpEq, Op2, Op1); - case ICmpNe: - return FoldICmp(ICmpNe, Op2, Op1); - case ICmpUlt: - return FoldICmp(ICmpUgt, Op2, Op1); - case ICmpUgt: - return FoldICmp(ICmpUlt, Op2, Op1); - case ICmpUle: - return FoldICmp(ICmpUge, Op2, Op1); - case ICmpUge: - return FoldICmp(ICmpUle, Op2, Op1); - case ICmpSlt: - return FoldICmp(ICmpSgt, Op2, Op1); - case ICmpSgt: - return FoldICmp(ICmpSlt, Op2, Op1); - case ICmpSle: - return FoldICmp(ICmpSge, Op2, Op1); - case ICmpSge: - return FoldICmp(ICmpSle, Op2, Op1); - } - } + if (isImm(*Op1)) + { + if (isImm(*Op2)) + { + unsigned result = 0; + switch (Opcode) + { + case ICmpEq: + result = GetImmValue(Op1) == GetImmValue(Op2); + break; + case ICmpNe: + result = GetImmValue(Op1) != GetImmValue(Op2); + break; + case ICmpUgt: + result = GetImmValue(Op1) > GetImmValue(Op2); + break; + case ICmpUlt: + result = GetImmValue(Op1) < GetImmValue(Op2); + break; + case ICmpUge: + result = GetImmValue(Op1) >= GetImmValue(Op2); + break; + case ICmpUle: + result = GetImmValue(Op1) <= GetImmValue(Op2); + break; + case ICmpSgt: + result = (signed)GetImmValue(Op1) > (signed)GetImmValue(Op2); + break; + case ICmpSlt: + result = (signed)GetImmValue(Op1) < (signed)GetImmValue(Op2); + break; + case ICmpSge: + result = (signed)GetImmValue(Op1) >= (signed)GetImmValue(Op2); + break; + case ICmpSle: + result = (signed)GetImmValue(Op1) <= (signed)GetImmValue(Op2); + break; + } + return EmitIntConst(result); + } + switch (Opcode) + { + case ICmpEq: + return FoldICmp(ICmpEq, Op2, Op1); + case ICmpNe: + return FoldICmp(ICmpNe, Op2, Op1); + case ICmpUlt: + return FoldICmp(ICmpUgt, Op2, Op1); + case ICmpUgt: + return FoldICmp(ICmpUlt, Op2, Op1); + case ICmpUle: + return FoldICmp(ICmpUge, Op2, Op1); + case ICmpUge: + return FoldICmp(ICmpUle, Op2, Op1); + case ICmpSlt: + return FoldICmp(ICmpSgt, Op2, Op1); + case ICmpSgt: + return FoldICmp(ICmpSlt, Op2, Op1); + case ICmpSle: + return FoldICmp(ICmpSge, Op2, Op1); + case ICmpSge: + return FoldICmp(ICmpSle, Op2, Op1); + } + } - return EmitBiOp(Opcode, Op1, Op2); + return EmitBiOp(Opcode, Op1, Op2); } InstLoc IRBuilder::FoldICmpCRSigned(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op1) && isImm(*Op2)) - { - s64 diff = (s64)(s32)GetImmValue(Op1) - (s64)(s32)GetImmValue(Op2); - return EmitIntConst64((u64)diff); - } + if (isImm(*Op1) && isImm(*Op2)) + { + s64 diff = (s64)(s32)GetImmValue(Op1) - (s64)(s32)GetImmValue(Op2); + return EmitIntConst64((u64)diff); + } - return EmitBiOp(ICmpCRSigned, Op1, Op2); + return EmitBiOp(ICmpCRSigned, Op1, Op2); } InstLoc IRBuilder::FoldICmpCRUnsigned(InstLoc Op1, InstLoc Op2) { - if (isImm(*Op1) && isImm(*Op2)) - { - u64 diff = (u64)GetImmValue(Op1) - (u64)GetImmValue(Op2); - return EmitIntConst64(diff); - } + if (isImm(*Op1) && isImm(*Op2)) + { + u64 diff = (u64)GetImmValue(Op1) - (u64)GetImmValue(Op2); + return EmitIntConst64(diff); + } - return EmitBiOp(ICmpCRUnsigned, Op1, Op2); + return EmitBiOp(ICmpCRUnsigned, Op1, Op2); } InstLoc IRBuilder::FoldFallBackToInterpreter(InstLoc Op1, InstLoc Op2) { - for (unsigned i = 0; i < 32; i++) - { - GRegCache[i] = nullptr; - GRegCacheStore[i] = nullptr; - FRegCache[i] = nullptr; - FRegCacheStore[i] = nullptr; - } + for (unsigned i = 0; i < 32; i++) + { + GRegCache[i] = nullptr; + GRegCacheStore[i] = nullptr; + FRegCache[i] = nullptr; + FRegCacheStore[i] = nullptr; + } - CarryCache = nullptr; - CarryCacheStore = nullptr; + CarryCache = nullptr; + CarryCacheStore = nullptr; - for (unsigned i = 0; i < 8; i++) - { - CRCache[i] = nullptr; - CRCacheStore[i] = nullptr; - } + for (unsigned i = 0; i < 8; i++) + { + CRCache[i] = nullptr; + CRCacheStore[i] = nullptr; + } - CTRCache = nullptr; - CTRCacheStore = nullptr; - return EmitBiOp(FallBackToInterpreter, Op1, Op2); + CTRCache = nullptr; + CTRCacheStore = nullptr; + return EmitBiOp(FallBackToInterpreter, Op1, Op2); } InstLoc IRBuilder::FoldDoubleBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2) { - if (getOpcode(*Op1) == InsertDoubleInMReg) - { - return FoldDoubleBiOp(Opcode, getOp1(Op1), Op2); - } + if (getOpcode(*Op1) == InsertDoubleInMReg) + { + return FoldDoubleBiOp(Opcode, getOp1(Op1), Op2); + } - if (getOpcode(*Op2) == InsertDoubleInMReg) - { - return FoldDoubleBiOp(Opcode, Op1, getOp1(Op2)); - } + if (getOpcode(*Op2) == InsertDoubleInMReg) + { + return FoldDoubleBiOp(Opcode, Op1, getOp1(Op2)); + } - return EmitBiOp(Opcode, Op1, Op2); + return EmitBiOp(Opcode, Op1, Op2); } InstLoc IRBuilder::FoldBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, unsigned extra) { - switch (Opcode) - { - case Add: - return FoldAdd(Op1, Op2); - case Sub: - return FoldSub(Op1, Op2); - case Mul: - return FoldMul(Op1, Op2); - case MulHighUnsigned: - return FoldMulHighUnsigned(Op1, Op2); - case And: - return FoldAnd(Op1, Op2); - case Or: - return FoldOr(Op1, Op2); - case Xor: - return FoldXor(Op1, Op2); - case Shl: - return FoldShl(Op1, Op2); - case Shrl: - return FoldShrl(Op1, Op2); - case Rol: - return FoldRol(Op1, Op2); - case BranchCond: - return FoldBranchCond(Op1, Op2); - case ICmpEq: case ICmpNe: - case ICmpUgt: case ICmpUlt: case ICmpUge: case ICmpUle: - case ICmpSgt: case ICmpSlt: case ICmpSge: case ICmpSle: - return FoldICmp(Opcode, Op1, Op2); - case ICmpCRSigned: - return FoldICmpCRSigned(Op1, Op2); - case ICmpCRUnsigned: - return FoldICmpCRUnsigned(Op1, Op2); - case FallBackToInterpreter: - return FoldFallBackToInterpreter(Op1, Op2); - case FDMul: - case FDAdd: - case FDSub: - return FoldDoubleBiOp(Opcode, Op1, Op2); - default: - return EmitBiOp(Opcode, Op1, Op2, extra); - } + switch (Opcode) + { + case Add: + return FoldAdd(Op1, Op2); + case Sub: + return FoldSub(Op1, Op2); + case Mul: + return FoldMul(Op1, Op2); + case MulHighUnsigned: + return FoldMulHighUnsigned(Op1, Op2); + case And: + return FoldAnd(Op1, Op2); + case Or: + return FoldOr(Op1, Op2); + case Xor: + return FoldXor(Op1, Op2); + case Shl: + return FoldShl(Op1, Op2); + case Shrl: + return FoldShrl(Op1, Op2); + case Rol: + return FoldRol(Op1, Op2); + case BranchCond: + return FoldBranchCond(Op1, Op2); + case ICmpEq: + case ICmpNe: + case ICmpUgt: + case ICmpUlt: + case ICmpUge: + case ICmpUle: + case ICmpSgt: + case ICmpSlt: + case ICmpSge: + case ICmpSle: + return FoldICmp(Opcode, Op1, Op2); + case ICmpCRSigned: + return FoldICmpCRSigned(Op1, Op2); + case ICmpCRUnsigned: + return FoldICmpCRUnsigned(Op1, Op2); + case FallBackToInterpreter: + return FoldFallBackToInterpreter(Op1, Op2); + case FDMul: + case FDAdd: + case FDSub: + return FoldDoubleBiOp(Opcode, Op1, Op2); + default: + return EmitBiOp(Opcode, Op1, Op2, extra); + } } InstLoc IRBuilder::EmitIntConst64(u64 value) { - InstLoc curIndex = InstList.data() + InstList.size(); - InstList.push_back(CInt32 | ((unsigned int)ConstList.size() << 8)); - MarkUsed.push_back(false); - ConstList.push_back(value); - return curIndex; + InstLoc curIndex = InstList.data() + InstList.size(); + InstList.push_back(CInt32 | ((unsigned int)ConstList.size() << 8)); + MarkUsed.push_back(false); + ConstList.push_back(value); + return curIndex; } u64 IRBuilder::GetImmValue64(InstLoc I) const { - return ConstList[*I >> 8]; + return ConstList[*I >> 8]; } void IRBuilder::SetMarkUsed(InstLoc I) { - const unsigned i = (unsigned)(I - InstList.data()); - MarkUsed[i] = true; + const unsigned i = (unsigned)(I - InstList.data()); + MarkUsed[i] = true; } bool IRBuilder::IsMarkUsed(InstLoc I) const { - const unsigned i = (unsigned)(I - InstList.data()); - return MarkUsed[i]; + const unsigned i = (unsigned)(I - InstList.data()); + return MarkUsed[i]; } bool IRBuilder::isSameValue(InstLoc Op1, InstLoc Op2) const { - if (Op1 == Op2) - { - return true; - } + if (Op1 == Op2) + { + return true; + } - if (isImm(*Op1) && isImm(*Op2) && GetImmValue(Op1) == GetImmValue(Op2)) - { - return true; - } + if (isImm(*Op1) && isImm(*Op2) && GetImmValue(Op1) == GetImmValue(Op2)) + { + return true; + } - if (getNumberOfOperands(Op1) == 2 && getOpcode(*Op1) != StorePaired && getOpcode(*Op1) == getOpcode(*Op2) && - isSameValue(getOp1(Op1), getOp1(Op2)) && isSameValue(getOp2(Op1), getOp2(Op2))) - { - return true; - } + if (getNumberOfOperands(Op1) == 2 && getOpcode(*Op1) != StorePaired && + getOpcode(*Op1) == getOpcode(*Op2) && isSameValue(getOp1(Op1), getOp1(Op2)) && + isSameValue(getOp2(Op1), getOp2(Op2))) + { + return true; + } - return false; + return false; } // Assign a complexity or rank value to Inst @@ -1313,265 +1326,476 @@ bool IRBuilder::isSameValue(InstLoc Op1, InstLoc Op2) const // 4 -> BiOp unsigned IRBuilder::getComplexity(InstLoc I) const { - const unsigned Opcode = getOpcode(*I); - if (Opcode == Nop || Opcode == CInt16 || Opcode == CInt32) - { - return 1; - } + const unsigned Opcode = getOpcode(*I); + if (Opcode == Nop || Opcode == CInt16 || Opcode == CInt32) + { + return 1; + } - const unsigned numberOfOperands = getNumberOfOperands(I); - if (numberOfOperands == -1U) - { - return 0; - } + const unsigned numberOfOperands = getNumberOfOperands(I); + if (numberOfOperands == -1U) + { + return 0; + } - return numberOfOperands + 2; + return numberOfOperands + 2; } - unsigned IRBuilder::getNumberOfOperands(InstLoc I) const { - static unsigned numberOfOperands[256]; - static bool initialized = false; - if (!initialized) - { - initialized = true; - std::fill_n(numberOfOperands, sizeof(numberOfOperands) / sizeof(numberOfOperands[0]), -1U); + static unsigned numberOfOperands[256]; + static bool initialized = false; + if (!initialized) + { + initialized = true; + std::fill_n(numberOfOperands, sizeof(numberOfOperands) / sizeof(numberOfOperands[0]), -1U); - numberOfOperands[Nop] = 0; - numberOfOperands[CInt16] = 0; - numberOfOperands[CInt32] = 0; + numberOfOperands[Nop] = 0; + numberOfOperands[CInt16] = 0; + numberOfOperands[CInt32] = 0; - static unsigned ZeroOp[] = { LoadCR, LoadLink, LoadMSR, LoadGReg, LoadCTR, InterpreterBranch, LoadCarry, RFIExit, LoadFReg, LoadFRegDENToZero, LoadGQR, Int3, }; - static unsigned UOp[] = { StoreLink, BranchUncond, StoreCR, StoreMSR, StoreFPRF, StoreGReg, StoreCTR, Load8, Load16, Load32, SExt16, SExt8, Cntlzw, Not, StoreCarry, SystemCall, ShortIdleLoop, LoadSingle, LoadDouble, LoadPaired, StoreFReg, DupSingleToMReg, DupSingleToPacked, ExpandPackedToMReg, CompactMRegToPacked, FSNeg, FDNeg, FPDup0, FPDup1, FPNeg, DoubleToSingle, StoreGQR, StoreSRR, ConvertFromFastCR, ConvertToFastCR, FastCRSOSet, FastCREQSet, FastCRGTSet, FastCRLTSet, }; - static unsigned BiOp[] = { BranchCond, IdleBranch, And, Xor, Sub, Or, Add, Mul, Rol, Shl, Shrl, Sarl, ICmpEq, ICmpNe, ICmpUgt, ICmpUlt, ICmpSgt, ICmpSlt, ICmpSge, ICmpSle, Store8, Store16, Store32, ICmpCRSigned, ICmpCRUnsigned, FallBackToInterpreter, StoreSingle, StoreDouble, StorePaired, InsertDoubleInMReg, FSMul, FSAdd, FSSub, FDMul, FDAdd, FDSub, FPAdd, FPMul, FPSub, FPMerge00, FPMerge01, FPMerge10, FPMerge11, FDCmpCR, }; - for (auto& op : ZeroOp) - numberOfOperands[op] = 0; + static unsigned ZeroOp[] = { + LoadCR, LoadLink, LoadMSR, LoadGReg, LoadCTR, InterpreterBranch, + LoadCarry, RFIExit, LoadFReg, LoadFRegDENToZero, LoadGQR, Int3, + }; + static unsigned UOp[] = { + StoreLink, + BranchUncond, + StoreCR, + StoreMSR, + StoreFPRF, + StoreGReg, + StoreCTR, + Load8, + Load16, + Load32, + SExt16, + SExt8, + Cntlzw, + Not, + StoreCarry, + SystemCall, + ShortIdleLoop, + LoadSingle, + LoadDouble, + LoadPaired, + StoreFReg, + DupSingleToMReg, + DupSingleToPacked, + ExpandPackedToMReg, + CompactMRegToPacked, + FSNeg, + FDNeg, + FPDup0, + FPDup1, + FPNeg, + DoubleToSingle, + StoreGQR, + StoreSRR, + ConvertFromFastCR, + ConvertToFastCR, + FastCRSOSet, + FastCREQSet, + FastCRGTSet, + FastCRLTSet, + }; + static unsigned BiOp[] = { + BranchCond, + IdleBranch, + And, + Xor, + Sub, + Or, + Add, + Mul, + Rol, + Shl, + Shrl, + Sarl, + ICmpEq, + ICmpNe, + ICmpUgt, + ICmpUlt, + ICmpSgt, + ICmpSlt, + ICmpSge, + ICmpSle, + Store8, + Store16, + Store32, + ICmpCRSigned, + ICmpCRUnsigned, + FallBackToInterpreter, + StoreSingle, + StoreDouble, + StorePaired, + InsertDoubleInMReg, + FSMul, + FSAdd, + FSSub, + FDMul, + FDAdd, + FDSub, + FPAdd, + FPMul, + FPSub, + FPMerge00, + FPMerge01, + FPMerge10, + FPMerge11, + FDCmpCR, + }; + for (auto& op : ZeroOp) + numberOfOperands[op] = 0; - for (auto& op : UOp) - numberOfOperands[op] = 1; + for (auto& op : UOp) + numberOfOperands[op] = 1; - for (auto& op : BiOp) - numberOfOperands[op] = 2; - } + for (auto& op : BiOp) + numberOfOperands[op] = 2; + } - return numberOfOperands[getOpcode(*I)]; + return numberOfOperands[getOpcode(*I)]; } // Performs a few simplifications for commutative operators // Ported from InstructionCombining.cpp in LLVM void IRBuilder::simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2) { - // Order operands such that they are listed from right (least complex) to - // left (most complex). This puts constants before unary operators before - // binary operators. - if (getComplexity(Op1) < getComplexity(Op2)) - { - std::swap(Op1, Op2); - } + // Order operands such that they are listed from right (least complex) to + // left (most complex). This puts constants before unary operators before + // binary operators. + if (getComplexity(Op1) < getComplexity(Op2)) + { + std::swap(Op1, Op2); + } - // Is this associative? - switch (Opcode) - { - case Add: - case Mul: - case And: - case Or: - case Xor: - break; - default: - return; - } + // Is this associative? + switch (Opcode) + { + case Add: + case Mul: + case And: + case Or: + case Xor: + break; + default: + return; + } - // (V op C1) op C2 => V + (C1 + C2) - if (getOpcode(*Op1) == Opcode && isImm(*getOp2(Op1)) && isImm(*Op2)) - { - const InstLoc Op1Old = Op1; - const InstLoc Op2Old = Op2; - Op1 = getOp1(Op1Old); - Op2 = FoldBiOp(Opcode, getOp2(Op1Old), Op2Old); - } + // (V op C1) op C2 => V + (C1 + C2) + if (getOpcode(*Op1) == Opcode && isImm(*getOp2(Op1)) && isImm(*Op2)) + { + const InstLoc Op1Old = Op1; + const InstLoc Op2Old = Op2; + Op1 = getOp1(Op1Old); + Op2 = FoldBiOp(Opcode, getOp2(Op1Old), Op2Old); + } - // ((V1 op C1) op (V2 op C2)) => ((V1 op V2) op (C1 op C2)) - // Transform: (op (op V1, C1), (op V2, C2)) ==> (op (op V1, V2), (op C1,C2)) - if (getOpcode(*Op1) == Opcode && isImm(*getOp2(Op1)) && getOpcode(*Op2) == Opcode && isImm(*getOp2(Op2))) - { - const InstLoc Op1Old = Op1; - const InstLoc Op2Old = Op2; - Op1 = FoldBiOp(Opcode, getOp1(Op1Old), getOp1(Op2Old)); - Op2 = FoldBiOp(Opcode, getOp2(Op1Old), getOp2(Op2Old)); - } + // ((V1 op C1) op (V2 op C2)) => ((V1 op V2) op (C1 op C2)) + // Transform: (op (op V1, C1), (op V2, C2)) ==> (op (op V1, V2), (op C1,C2)) + if (getOpcode(*Op1) == Opcode && isImm(*getOp2(Op1)) && getOpcode(*Op2) == Opcode && + isImm(*getOp2(Op2))) + { + const InstLoc Op1Old = Op1; + const InstLoc Op2Old = Op2; + Op1 = FoldBiOp(Opcode, getOp1(Op1Old), getOp1(Op2Old)); + Op2 = FoldBiOp(Opcode, getOp2(Op1Old), getOp2(Op2Old)); + } - // FIXME: Following code has a bug. - // ((w op x) op (y op z)) => (((w op x) op y) op z) - /* - if (getOpcode(*Op1) == Opcode && getOpcode(*Op2) == Opcode) - { - // Sort the operands where the complexities will be descending order. - std::pair ops[4]; - ops[0] = std::make_pair(getComplexity(getOp1(Op1)), getOp1(Op1)); - ops[1] = std::make_pair(getComplexity(getOp2(Op1)), getOp2(Op1)); - ops[2] = std::make_pair(getComplexity(getOp1(Op2)), getOp1(Op2)); - ops[3] = std::make_pair(getComplexity(getOp2(Op2)), getOp2(Op2)); - std::sort(ops, ops + 4, std::greater >()); + // FIXME: Following code has a bug. + // ((w op x) op (y op z)) => (((w op x) op y) op z) + /* + if (getOpcode(*Op1) == Opcode && getOpcode(*Op2) == Opcode) + { + // Sort the operands where the complexities will be descending order. + std::pair ops[4]; + ops[0] = std::make_pair(getComplexity(getOp1(Op1)), getOp1(Op1)); + ops[1] = std::make_pair(getComplexity(getOp2(Op1)), getOp2(Op1)); + ops[2] = std::make_pair(getComplexity(getOp1(Op2)), getOp1(Op2)); + ops[3] = std::make_pair(getComplexity(getOp2(Op2)), getOp2(Op2)); + std::sort(ops, ops + 4, std::greater >()); - Op1 = FoldBiOp(Opcode, FoldBiOp(Opcode, ops[0].second, ops[1].second), ops[2].second); - Op2 = ops[3].second; - } - */ + Op1 = FoldBiOp(Opcode, FoldBiOp(Opcode, ops[0].second, ops[1].second), ops[2].second); + Op2 = ops[3].second; + } + */ } bool IRBuilder::maskedValueIsZero(InstLoc Op1, InstLoc Op2) const { - return (~ComputeKnownZeroBits(Op1) & ~ComputeKnownZeroBits(Op2)) == 0; + return (~ComputeKnownZeroBits(Op1) & ~ComputeKnownZeroBits(Op2)) == 0; } // Returns I' if I == (0 - I') InstLoc IRBuilder::isNeg(InstLoc I) const { - if (getOpcode(*I) == Sub && isImm(*getOp1(I)) && GetImmValue(getOp1(I)) == 0) - { - return getOp2(I); - } + if (getOpcode(*I) == Sub && isImm(*getOp1(I)) && GetImmValue(getOp1(I)) == 0) + { + return getOp2(I); + } - return nullptr; + return nullptr; } // TODO: Move the following code to a separated file. struct Writer { - File::IOFile file; - Writer() : file(nullptr) - { - std::string filename = StringFromFormat("JitIL_IR_%d.txt", (int)time(nullptr)); - file.Open(filename, "w"); - setvbuf(file.GetHandle(), nullptr, _IOFBF, 1024 * 1024); - } + File::IOFile file; + Writer() : file(nullptr) + { + std::string filename = StringFromFormat("JitIL_IR_%d.txt", (int)time(nullptr)); + file.Open(filename, "w"); + setvbuf(file.GetHandle(), nullptr, _IOFBF, 1024 * 1024); + } - virtual ~Writer() {} + virtual ~Writer() {} }; static std::unique_ptr writer; static const std::string opcodeNames[] = { - "Nop", "LoadGReg", "LoadLink", "LoadCR", "LoadCarry", "LoadCTR", - "LoadMSR", "LoadGQR", "SExt8", "SExt16", "BSwap32", "BSwap16", "Cntlzw", - "Not", "Load8", "Load16", "Load32", "BranchUncond", "ConvertFromFastCR", - "ConvertToFastCR", "StoreGReg", "StoreCR", "StoreLink", "StoreCarry", - "StoreCTR", "StoreMSR", "StoreFPRF", "StoreGQR", "StoreSRR", - "FastCRSOSet", "FastCREQSet", "FastCRGTSet", "FastCRLTSet", - "FallBackToInterpreter", "Add", "Mul", "And", "Or", "Xor", - "MulHighUnsigned", "Sub", "Shl", "Shrl", "Sarl", "Rol", - "ICmpCRSigned", "ICmpCRUnsigned", "ICmpEq", "ICmpNe", "ICmpUgt", - "ICmpUlt", "ICmpUge", "ICmpUle", "ICmpSgt", "ICmpSlt", "ICmpSge", - "ICmpSle", "Store8", "Store16", "Store32", "BranchCond", "FResult_Start", - "LoadSingle", "LoadDouble", "LoadPaired", "DoubleToSingle", - "DupSingleToMReg", "DupSingleToPacked", "InsertDoubleInMReg", - "ExpandPackedToMReg", "CompactMRegToPacked", "LoadFReg", - "LoadFRegDENToZero", "FSMul", "FSAdd", "FSSub", "FSNeg", "FSRSqrt", - "FPAdd", "FPMul", "FPSub", "FPNeg", "FDMul", "FDAdd", "FDSub", "FDNeg", - "FPMerge00", "FPMerge01", "FPMerge10", "FPMerge11", "FPDup0", "FPDup1", - "FResult_End", "StorePaired", "StoreSingle", "StoreDouble", "StoreFReg", - "FDCmpCR", "CInt16", "CInt32", "SystemCall", "RFIExit", - "InterpreterBranch", "IdleBranch", "ShortIdleLoop", - "FPExceptionCheckStart", "FPExceptionCheckEnd", "ExtExceptionCheck", - "Tramp", "BlockStart", "BlockEnd", "Int3", -}; -static const unsigned alwaysUsedList[] = { - FallBackToInterpreter, StoreGReg, StoreCR, StoreLink, StoreCTR, StoreMSR, - StoreGQR, StoreSRR, StoreCarry, StoreFPRF, Load8, Load16, Load32, Store8, - Store16, Store32, StoreSingle, StoreDouble, StorePaired, StoreFReg, FDCmpCR, - BlockStart, BlockEnd, IdleBranch, BranchCond, BranchUncond, ShortIdleLoop, - SystemCall, InterpreterBranch, RFIExit, FPExceptionCheck, - DSIExceptionCheck, ExtExceptionCheck, BreakPointCheck, - Int3, Tramp, Nop + "Nop", + "LoadGReg", + "LoadLink", + "LoadCR", + "LoadCarry", + "LoadCTR", + "LoadMSR", + "LoadGQR", + "SExt8", + "SExt16", + "BSwap32", + "BSwap16", + "Cntlzw", + "Not", + "Load8", + "Load16", + "Load32", + "BranchUncond", + "ConvertFromFastCR", + "ConvertToFastCR", + "StoreGReg", + "StoreCR", + "StoreLink", + "StoreCarry", + "StoreCTR", + "StoreMSR", + "StoreFPRF", + "StoreGQR", + "StoreSRR", + "FastCRSOSet", + "FastCREQSet", + "FastCRGTSet", + "FastCRLTSet", + "FallBackToInterpreter", + "Add", + "Mul", + "And", + "Or", + "Xor", + "MulHighUnsigned", + "Sub", + "Shl", + "Shrl", + "Sarl", + "Rol", + "ICmpCRSigned", + "ICmpCRUnsigned", + "ICmpEq", + "ICmpNe", + "ICmpUgt", + "ICmpUlt", + "ICmpUge", + "ICmpUle", + "ICmpSgt", + "ICmpSlt", + "ICmpSge", + "ICmpSle", + "Store8", + "Store16", + "Store32", + "BranchCond", + "FResult_Start", + "LoadSingle", + "LoadDouble", + "LoadPaired", + "DoubleToSingle", + "DupSingleToMReg", + "DupSingleToPacked", + "InsertDoubleInMReg", + "ExpandPackedToMReg", + "CompactMRegToPacked", + "LoadFReg", + "LoadFRegDENToZero", + "FSMul", + "FSAdd", + "FSSub", + "FSNeg", + "FSRSqrt", + "FPAdd", + "FPMul", + "FPSub", + "FPNeg", + "FDMul", + "FDAdd", + "FDSub", + "FDNeg", + "FPMerge00", + "FPMerge01", + "FPMerge10", + "FPMerge11", + "FPDup0", + "FPDup1", + "FResult_End", + "StorePaired", + "StoreSingle", + "StoreDouble", + "StoreFReg", + "FDCmpCR", + "CInt16", + "CInt32", + "SystemCall", + "RFIExit", + "InterpreterBranch", + "IdleBranch", + "ShortIdleLoop", + "FPExceptionCheckStart", + "FPExceptionCheckEnd", + "ExtExceptionCheck", + "Tramp", + "BlockStart", + "BlockEnd", + "Int3", }; +static const unsigned alwaysUsedList[] = {FallBackToInterpreter, + StoreGReg, + StoreCR, + StoreLink, + StoreCTR, + StoreMSR, + StoreGQR, + StoreSRR, + StoreCarry, + StoreFPRF, + Load8, + Load16, + Load32, + Store8, + Store16, + Store32, + StoreSingle, + StoreDouble, + StorePaired, + StoreFReg, + FDCmpCR, + BlockStart, + BlockEnd, + IdleBranch, + BranchCond, + BranchUncond, + ShortIdleLoop, + SystemCall, + InterpreterBranch, + RFIExit, + FPExceptionCheck, + DSIExceptionCheck, + ExtExceptionCheck, + BreakPointCheck, + Int3, + Tramp, + Nop}; static const unsigned extra8RegList[] = { - LoadGReg, LoadCR, LoadGQR, LoadFReg, LoadFRegDENToZero, + LoadGReg, LoadCR, LoadGQR, LoadFReg, LoadFRegDENToZero, }; static const unsigned extra16RegList[] = { - StoreGReg, StoreCR, StoreGQR, StoreSRR, LoadPaired, StoreFReg, + StoreGReg, StoreCR, StoreGQR, StoreSRR, LoadPaired, StoreFReg, }; static const unsigned extra24RegList[] = { - StorePaired, + StorePaired, }; -static const std::set alwaysUseds(alwaysUsedList, alwaysUsedList + sizeof(alwaysUsedList) / sizeof(alwaysUsedList[0])); -static const std::set extra8Regs(extra8RegList, extra8RegList + sizeof(extra8RegList) / sizeof(extra8RegList[0])); -static const std::set extra16Regs(extra16RegList, extra16RegList + sizeof(extra16RegList) / sizeof(extra16RegList[0])); -static const std::set extra24Regs(extra24RegList, extra24RegList + sizeof(extra24RegList) / sizeof(extra24RegList[0])); +static const std::set alwaysUseds(alwaysUsedList, + alwaysUsedList + + sizeof(alwaysUsedList) / sizeof(alwaysUsedList[0])); +static const std::set + extra8Regs(extra8RegList, extra8RegList + sizeof(extra8RegList) / sizeof(extra8RegList[0])); +static const std::set extra16Regs(extra16RegList, + extra16RegList + + sizeof(extra16RegList) / sizeof(extra16RegList[0])); +static const std::set extra24Regs(extra24RegList, + extra24RegList + + sizeof(extra24RegList) / sizeof(extra24RegList[0])); void IRBuilder::WriteToFile(u64 codeHash) { - _assert_(sizeof(opcodeNames) / sizeof(opcodeNames[0]) == Int3 + 1); + _assert_(sizeof(opcodeNames) / sizeof(opcodeNames[0]) == Int3 + 1); - if (!writer.get()) - { - writer = std::make_unique(); - } + if (!writer.get()) + { + writer = std::make_unique(); + } - FILE* const file = writer->file.GetHandle(); - fprintf(file, "\ncode hash:%016" PRIx64 "\n", codeHash); + FILE* const file = writer->file.GetHandle(); + fprintf(file, "\ncode hash:%016" PRIx64 "\n", codeHash); - const InstLoc lastCurReadPtr = curReadPtr; - StartForwardPass(); - const unsigned numInsts = getNumInsts(); - for (unsigned int i = 0; i < numInsts; ++i) - { - const InstLoc I = ReadForward(); - const unsigned opcode = getOpcode(*I); - const bool thisUsed = IsMarkUsed(I) || - alwaysUseds.find(opcode) != alwaysUseds.end(); + const InstLoc lastCurReadPtr = curReadPtr; + StartForwardPass(); + const unsigned numInsts = getNumInsts(); + for (unsigned int i = 0; i < numInsts; ++i) + { + const InstLoc I = ReadForward(); + const unsigned opcode = getOpcode(*I); + const bool thisUsed = IsMarkUsed(I) || alwaysUseds.find(opcode) != alwaysUseds.end(); - // Line number - fprintf(file, "%4u", i); + // Line number + fprintf(file, "%4u", i); - if (!thisUsed) - fprintf(file, "%*c", 32, ' '); + if (!thisUsed) + fprintf(file, "%*c", 32, ' '); - // Opcode - const std::string& opcodeName = opcodeNames[opcode]; - fprintf(file, " %-20s", opcodeName.c_str()); - const unsigned numberOfOperands = getNumberOfOperands(I); + // Opcode + const std::string& opcodeName = opcodeNames[opcode]; + fprintf(file, " %-20s", opcodeName.c_str()); + const unsigned numberOfOperands = getNumberOfOperands(I); - // Op1 - if (numberOfOperands >= 1) - { - const IREmitter::InstLoc inst = getOp1(I); + // Op1 + if (numberOfOperands >= 1) + { + const IREmitter::InstLoc inst = getOp1(I); - if (isImm(*inst)) - fprintf(file, " 0x%08x", GetImmValue(inst)); - else - fprintf(file, " %10u", i - (unsigned int)(I - inst)); - } + if (isImm(*inst)) + fprintf(file, " 0x%08x", GetImmValue(inst)); + else + fprintf(file, " %10u", i - (unsigned int)(I - inst)); + } - // Op2 - if (numberOfOperands >= 2) - { - const IREmitter::InstLoc inst = getOp2(I); + // Op2 + if (numberOfOperands >= 2) + { + const IREmitter::InstLoc inst = getOp2(I); - if (isImm(*inst)) - fprintf(file, " 0x%08x", GetImmValue(inst)); - else - fprintf(file, " %10u", i - (unsigned int)(I - inst)); - } + if (isImm(*inst)) + fprintf(file, " 0x%08x", GetImmValue(inst)); + else + fprintf(file, " %10u", i - (unsigned int)(I - inst)); + } - if (extra8Regs.count(opcode)) - fprintf(file, " R%d", *I >> 8); + if (extra8Regs.count(opcode)) + fprintf(file, " R%d", *I >> 8); - if (extra16Regs.count(opcode)) - fprintf(file, " R%d", *I >> 16); + if (extra16Regs.count(opcode)) + fprintf(file, " R%d", *I >> 16); - if (extra24Regs.count(opcode)) - fprintf(file, " R%d", *I >> 24); + if (extra24Regs.count(opcode)) + fprintf(file, " R%d", *I >> 24); - if (opcode == CInt32 || opcode == CInt16) - fprintf(file, " 0x%08x", GetImmValue(I)); + if (opcode == CInt32 || opcode == CInt16) + fprintf(file, " 0x%08x", GetImmValue(I)); - fprintf(file, "\n"); - } + fprintf(file, "\n"); + } - curReadPtr = lastCurReadPtr; + curReadPtr = lastCurReadPtr; } - } diff --git a/Source/Core/Core/PowerPC/JitILCommon/IR.h b/Source/Core/Core/PowerPC/JitILCommon/IR.h index 31107ccce9..01a140a0b1 100644 --- a/Source/Core/Core/PowerPC/JitILCommon/IR.h +++ b/Source/Core/Core/PowerPC/JitILCommon/IR.h @@ -10,171 +10,173 @@ namespace IREmitter { - enum Opcode { - Nop = 0, + Nop = 0, - // "Zero-operand" operators - // Register load operators - LoadGReg, - LoadLink, - LoadCR, - LoadCarry, - LoadCTR, - LoadMSR, - LoadGQR, + // "Zero-operand" operators + // Register load operators + LoadGReg, + LoadLink, + LoadCR, + LoadCarry, + LoadCTR, + LoadMSR, + LoadGQR, - // Unary operators - // Integer unary operators - SExt8, - SExt16, - BSwap32, - BSwap16, - Cntlzw, // Count leading zeros - Not, - Load8, // These loads zext - Load16, - Load32, - // CR conversions - ConvertFromFastCR, - ConvertToFastCR, - // Branches - BranchUncond, - // Register store operators - StoreGReg, - StoreCR, - StoreLink, - StoreCarry, - StoreCTR, - StoreMSR, - StoreFPRF, - StoreGQR, - StoreSRR, - // Branch conditions - FastCRSOSet, - FastCREQSet, - FastCRGTSet, - FastCRLTSet, - // Arbitrary interpreter instruction - FallBackToInterpreter, + // Unary operators + // Integer unary operators + SExt8, + SExt16, + BSwap32, + BSwap16, + Cntlzw, // Count leading zeros + Not, + Load8, // These loads zext + Load16, + Load32, + // CR conversions + ConvertFromFastCR, + ConvertToFastCR, + // Branches + BranchUncond, + // Register store operators + StoreGReg, + StoreCR, + StoreLink, + StoreCarry, + StoreCTR, + StoreMSR, + StoreFPRF, + StoreGQR, + StoreSRR, + // Branch conditions + FastCRSOSet, + FastCREQSet, + FastCRGTSet, + FastCRLTSet, + // Arbitrary interpreter instruction + FallBackToInterpreter, - // Binary operators - // Commutative integer operators - Add, - Mul, - And, - Or, - Xor, - // Non-commutative integer operators - MulHighUnsigned, - Sub, - Shl, // Note that shifts ignore bits above the bottom 5 - Shrl, - Sarl, - Rol, - ICmpCRSigned, // CR for signed int compare - ICmpCRUnsigned, // CR for unsigned int compare - ICmpEq, // One if equal, zero otherwise - ICmpNe, - ICmpUgt, // One if op1 > op2, zero otherwise - ICmpUlt, - ICmpUge, - ICmpUle, - ICmpSgt, // One if op1 > op2, zero otherwise - ICmpSlt, - ICmpSge, - ICmpSle, // Opposite of sgt + // Binary operators + // Commutative integer operators + Add, + Mul, + And, + Or, + Xor, + // Non-commutative integer operators + MulHighUnsigned, + Sub, + Shl, // Note that shifts ignore bits above the bottom 5 + Shrl, + Sarl, + Rol, + ICmpCRSigned, // CR for signed int compare + ICmpCRUnsigned, // CR for unsigned int compare + ICmpEq, // One if equal, zero otherwise + ICmpNe, + ICmpUgt, // One if op1 > op2, zero otherwise + ICmpUlt, + ICmpUge, + ICmpUle, + ICmpSgt, // One if op1 > op2, zero otherwise + ICmpSlt, + ICmpSge, + ICmpSle, // Opposite of sgt - // Memory store operators - Store8, - Store16, - Store32, - BranchCond, - // Floating-point - // There are three floating-point formats: single, double, - // and packed. For any operation where the format of the - // operand isn't known, the ForceTo* operations are used; - // these are folded into the appropriate conversion - // (or no conversion) depending on the type of the operand. - // The "mreg" format is a pair of doubles; this is the - // most general possible represenation which is used - // in the register state. - // This might seem like overkill, but the semantics require - // having the different formats. - // FIXME: Check the accuracy of the mapping: - // 1. Is paired arithmetic always rounded to single-precision - // first, or does it do double-to-single like the - // single-precision instructions? - // 2. The implementation of madd is slightly off, and - // the implementation of fmuls is very slightly off; - // likely nothing cares, though. - FResult_Start, - LoadSingle, - LoadDouble, - LoadPaired, // This handles quantizers itself - DoubleToSingle, - DupSingleToMReg, - DupSingleToPacked, - InsertDoubleInMReg, - ExpandPackedToMReg, - CompactMRegToPacked, - LoadFReg, - LoadFRegDENToZero, - FSMul, - FSAdd, - FSSub, - FSNeg, - FPAdd, - FPMul, - FPSub, - FPNeg, - FDMul, - FDAdd, - FDSub, - FDNeg, - FPMerge00, - FPMerge01, - FPMerge10, - FPMerge11, - FPDup0, - FPDup1, - FResult_End, - StorePaired, - StoreSingle, - StoreDouble, - StoreFReg, - FDCmpCR, + // Memory store operators + Store8, + Store16, + Store32, + BranchCond, + // Floating-point + // There are three floating-point formats: single, double, + // and packed. For any operation where the format of the + // operand isn't known, the ForceTo* operations are used; + // these are folded into the appropriate conversion + // (or no conversion) depending on the type of the operand. + // The "mreg" format is a pair of doubles; this is the + // most general possible represenation which is used + // in the register state. + // This might seem like overkill, but the semantics require + // having the different formats. + // FIXME: Check the accuracy of the mapping: + // 1. Is paired arithmetic always rounded to single-precision + // first, or does it do double-to-single like the + // single-precision instructions? + // 2. The implementation of madd is slightly off, and + // the implementation of fmuls is very slightly off; + // likely nothing cares, though. + FResult_Start, + LoadSingle, + LoadDouble, + LoadPaired, // This handles quantizers itself + DoubleToSingle, + DupSingleToMReg, + DupSingleToPacked, + InsertDoubleInMReg, + ExpandPackedToMReg, + CompactMRegToPacked, + LoadFReg, + LoadFRegDENToZero, + FSMul, + FSAdd, + FSSub, + FSNeg, + FPAdd, + FPMul, + FPSub, + FPNeg, + FDMul, + FDAdd, + FDSub, + FDNeg, + FPMerge00, + FPMerge01, + FPMerge10, + FPMerge11, + FPDup0, + FPDup1, + FResult_End, + StorePaired, + StoreSingle, + StoreDouble, + StoreFReg, + FDCmpCR, - // "Trinary" operators - // FIXME: Need to change representation! - //Select, // Equivalent to C "Op1 ? Op2 : Op3" + // "Trinary" operators + // FIXME: Need to change representation! + // Select, // Equivalent to C "Op1 ? Op2 : Op3" - // Integer constants - CInt16, - CInt32, + // Integer constants + CInt16, + CInt32, - // Funny PPC "branches" - SystemCall, - RFIExit, - InterpreterBranch, + // Funny PPC "branches" + SystemCall, + RFIExit, + InterpreterBranch, - IdleBranch, // branch operation belonging to idle loop - ShortIdleLoop, // Idle loop seen in homebrew like Wii mahjong, - // just a branch + IdleBranch, // branch operation belonging to idle loop + ShortIdleLoop, // Idle loop seen in homebrew like Wii mahjong, + // just a branch - // used for exception checking, at least until someone - // has a better idea of integrating it - FPExceptionCheck, DSIExceptionCheck, - ExtExceptionCheck, BreakPointCheck, - // "Opcode" representing a register too far away to - // reference directly; this is a size optimization - Tramp, - // "Opcode"s representing the start and end - BlockStart, BlockEnd, + // used for exception checking, at least until someone + // has a better idea of integrating it + FPExceptionCheck, + DSIExceptionCheck, + ExtExceptionCheck, + BreakPointCheck, + // "Opcode" representing a register too far away to + // reference directly; this is a size optimization + Tramp, + // "Opcode"s representing the start and end + BlockStart, + BlockEnd, - // used for debugging - Int3 + // used for debugging + Int3 }; typedef unsigned Inst; @@ -182,654 +184,284 @@ typedef Inst* InstLoc; unsigned inline getOpcode(Inst i) { - return i & 255; + return i & 255; } unsigned inline isImm(Inst i) { - return getOpcode(i) >= CInt16 && getOpcode(i) <= CInt32; + return getOpcode(i) >= CInt16 && getOpcode(i) <= CInt32; } unsigned inline isICmp(Inst i) { - return getOpcode(i) >= ICmpEq && getOpcode(i) <= ICmpSle; + return getOpcode(i) >= ICmpEq && getOpcode(i) <= ICmpSle; } unsigned inline isFResult(Inst i) { - return getOpcode(i) > FResult_Start && - getOpcode(i) < FResult_End; + return getOpcode(i) > FResult_Start && getOpcode(i) < FResult_End; } InstLoc inline getOp1(InstLoc i) { - i = i - 1 - ((*i >> 8) & 255); + i = i - 1 - ((*i >> 8) & 255); - if (getOpcode(*i) == Tramp) - { - i = i - 1 - (*i >> 8); - } + if (getOpcode(*i) == Tramp) + { + i = i - 1 - (*i >> 8); + } - return i; + return i; } InstLoc inline getOp2(InstLoc i) { - i = i - 1 - ((*i >> 16) & 255); + i = i - 1 - ((*i >> 16) & 255); - if (getOpcode(*i) == Tramp) - { - i = i - 1 - (*i >> 8); - } + if (getOpcode(*i) == Tramp) + { + i = i - 1 - (*i >> 8); + } - return i; + return i; } class IRBuilder { private: - InstLoc EmitZeroOp(unsigned Opcode, unsigned extra); - InstLoc EmitUOp(unsigned OpCode, InstLoc Op1, unsigned extra = 0); - InstLoc EmitBiOp(unsigned OpCode, InstLoc Op1, InstLoc Op2, unsigned extra = 0); + InstLoc EmitZeroOp(unsigned Opcode, unsigned extra); + InstLoc EmitUOp(unsigned OpCode, InstLoc Op1, unsigned extra = 0); + InstLoc EmitBiOp(unsigned OpCode, InstLoc Op1, InstLoc Op2, unsigned extra = 0); - InstLoc FoldAdd(InstLoc Op1, InstLoc Op2); - InstLoc FoldSub(InstLoc Op1, InstLoc Op2); - InstLoc FoldMul(InstLoc Op1, InstLoc Op2); - InstLoc FoldMulHighUnsigned(InstLoc Op1, InstLoc Op2); - InstLoc FoldAnd(InstLoc Op1, InstLoc Op2); - InstLoc FoldOr(InstLoc Op1, InstLoc Op2); - InstLoc FoldRol(InstLoc Op1, InstLoc Op2); - InstLoc FoldShl(InstLoc Op1, InstLoc Op2); - InstLoc FoldShrl(InstLoc Op1, InstLoc Op2); - InstLoc FoldXor(InstLoc Op1, InstLoc Op2); - InstLoc FoldBranchCond(InstLoc Op1, InstLoc Op2); - InstLoc FoldIdleBranch(InstLoc Op1, InstLoc Op2); - InstLoc FoldICmp(unsigned Opcode, InstLoc Op1, InstLoc Op2); - InstLoc FoldICmpCRSigned(InstLoc Op1, InstLoc Op2); - InstLoc FoldICmpCRUnsigned(InstLoc Op1, InstLoc Op2); - InstLoc FoldDoubleBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2); + InstLoc FoldAdd(InstLoc Op1, InstLoc Op2); + InstLoc FoldSub(InstLoc Op1, InstLoc Op2); + InstLoc FoldMul(InstLoc Op1, InstLoc Op2); + InstLoc FoldMulHighUnsigned(InstLoc Op1, InstLoc Op2); + InstLoc FoldAnd(InstLoc Op1, InstLoc Op2); + InstLoc FoldOr(InstLoc Op1, InstLoc Op2); + InstLoc FoldRol(InstLoc Op1, InstLoc Op2); + InstLoc FoldShl(InstLoc Op1, InstLoc Op2); + InstLoc FoldShrl(InstLoc Op1, InstLoc Op2); + InstLoc FoldXor(InstLoc Op1, InstLoc Op2); + InstLoc FoldBranchCond(InstLoc Op1, InstLoc Op2); + InstLoc FoldIdleBranch(InstLoc Op1, InstLoc Op2); + InstLoc FoldICmp(unsigned Opcode, InstLoc Op1, InstLoc Op2); + InstLoc FoldICmpCRSigned(InstLoc Op1, InstLoc Op2); + InstLoc FoldICmpCRUnsigned(InstLoc Op1, InstLoc Op2); + InstLoc FoldDoubleBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2); - InstLoc FoldFallBackToInterpreter(InstLoc Op1, InstLoc Op2); + InstLoc FoldFallBackToInterpreter(InstLoc Op1, InstLoc Op2); - InstLoc FoldZeroOp(unsigned Opcode, unsigned extra); - InstLoc FoldUOp(unsigned OpCode, InstLoc Op1, unsigned extra = 0); - InstLoc FoldBiOp(unsigned OpCode, InstLoc Op1, InstLoc Op2, unsigned extra = 0); + InstLoc FoldZeroOp(unsigned Opcode, unsigned extra); + InstLoc FoldUOp(unsigned OpCode, InstLoc Op1, unsigned extra = 0); + InstLoc FoldBiOp(unsigned OpCode, InstLoc Op1, InstLoc Op2, unsigned extra = 0); - unsigned ComputeKnownZeroBits(InstLoc I) const; + unsigned ComputeKnownZeroBits(InstLoc I) const; public: - InstLoc EmitIntConst(unsigned value) { return EmitIntConst64(value); } - InstLoc EmitIntConst64(u64 value); - - InstLoc EmitStoreLink(InstLoc val) - { - return FoldUOp(StoreLink, val); - } - - InstLoc EmitBranchUncond(InstLoc val) - { - return FoldUOp(BranchUncond, val); - } - - InstLoc EmitBranchCond(InstLoc check, InstLoc dest) - { - return FoldBiOp(BranchCond, check, dest); - } - - InstLoc EmitIdleBranch(InstLoc check, InstLoc dest) - { - return FoldBiOp(IdleBranch, check, dest); - } - - InstLoc EmitLoadCR(unsigned crreg) - { - return FoldZeroOp(LoadCR, crreg); - } - - InstLoc EmitStoreCR(InstLoc value, unsigned crreg) - { - return FoldUOp(StoreCR, value, crreg); - } - - InstLoc EmitLoadLink() - { - return FoldZeroOp(LoadLink, 0); - } - - InstLoc EmitLoadMSR() - { - return FoldZeroOp(LoadMSR, 0); - } - - InstLoc EmitStoreMSR(InstLoc val, InstLoc pc) - { - return FoldBiOp(StoreMSR, val, pc); - } - - InstLoc EmitStoreFPRF(InstLoc value) - { - return FoldUOp(StoreFPRF, value); - } - - InstLoc EmitLoadGReg(unsigned reg) - { - return FoldZeroOp(LoadGReg, reg); - } - - InstLoc EmitStoreGReg(InstLoc value, unsigned reg) - { - return FoldUOp(StoreGReg, value, reg); - } - - InstLoc EmitNot(InstLoc op1) - { - return FoldUOp(Not, op1); - } - - InstLoc EmitAnd(InstLoc op1, InstLoc op2) - { - return FoldBiOp(And, op1, op2); - } - - InstLoc EmitXor(InstLoc op1, InstLoc op2) - { - return FoldBiOp(Xor, op1, op2); - } - - InstLoc EmitSub(InstLoc op1, InstLoc op2) - { - return FoldBiOp(Sub, op1, op2); - } - - InstLoc EmitOr(InstLoc op1, InstLoc op2) - { - return FoldBiOp(Or, op1, op2); - } - - InstLoc EmitAdd(InstLoc op1, InstLoc op2) - { - return FoldBiOp(Add, op1, op2); - } - - InstLoc EmitMul(InstLoc op1, InstLoc op2) - { - return FoldBiOp(Mul, op1, op2); - } - - InstLoc EmitMulHighUnsigned(InstLoc op1, InstLoc op2) - { - return FoldBiOp(MulHighUnsigned, op1, op2); - } - - InstLoc EmitRol(InstLoc op1, InstLoc op2) - { - return FoldBiOp(Rol, op1, op2); - } - - InstLoc EmitShl(InstLoc op1, InstLoc op2) - { - return FoldBiOp(Shl, op1, op2); - } - - InstLoc EmitShrl(InstLoc op1, InstLoc op2) - { - return FoldBiOp(Shrl, op1, op2); - } - - InstLoc EmitSarl(InstLoc op1, InstLoc op2) - { - return FoldBiOp(Sarl, op1, op2); - } - - InstLoc EmitLoadCTR() - { - return FoldZeroOp(LoadCTR, 0); - } - - InstLoc EmitStoreCTR(InstLoc op1) - { - return FoldUOp(StoreCTR, op1); - } - - InstLoc EmitICmpEq(InstLoc op1, InstLoc op2) - { - return FoldBiOp(ICmpEq, op1, op2); - } - - InstLoc EmitICmpNe(InstLoc op1, InstLoc op2) - { - return FoldBiOp(ICmpNe, op1, op2); - } - - InstLoc EmitICmpUgt(InstLoc op1, InstLoc op2) - { - return FoldBiOp(ICmpUgt, op1, op2); - } - - InstLoc EmitICmpUlt(InstLoc op1, InstLoc op2) - { - return FoldBiOp(ICmpUlt, op1, op2); - } - - InstLoc EmitICmpSgt(InstLoc op1, InstLoc op2) - { - return FoldBiOp(ICmpSgt, op1, op2); - } - - InstLoc EmitICmpSlt(InstLoc op1, InstLoc op2) - { - return FoldBiOp(ICmpSlt, op1, op2); - } - - InstLoc EmitICmpSge(InstLoc op1, InstLoc op2) - { - return FoldBiOp(ICmpSge, op1, op2); - } - - InstLoc EmitICmpSle(InstLoc op1, InstLoc op2) - { - return FoldBiOp(ICmpSle, op1, op2); - } - - InstLoc EmitLoad8(InstLoc op1) - { - return FoldUOp(Load8, op1); - } - - InstLoc EmitLoad16(InstLoc op1) - { - return FoldUOp(Load16, op1); - } - - InstLoc EmitLoad32(InstLoc op1) - { - return FoldUOp(Load32, op1); - } - - InstLoc EmitStore8(InstLoc op1, InstLoc op2) - { - return FoldBiOp(Store8, op1, op2); - } - - InstLoc EmitStore16(InstLoc op1, InstLoc op2) - { - return FoldBiOp(Store16, op1, op2); - } - - InstLoc EmitStore32(InstLoc op1, InstLoc op2) - { - return FoldBiOp(Store32, op1, op2); - } - - InstLoc EmitSExt16(InstLoc op1) - { - return FoldUOp(SExt16, op1); - } - - InstLoc EmitSExt8(InstLoc op1) - { - return FoldUOp(SExt8, op1); - } - - InstLoc EmitCntlzw(InstLoc op1) - { - return FoldUOp(Cntlzw, op1); - } - - InstLoc EmitICmpCRSigned(InstLoc op1, InstLoc op2) - { - return FoldBiOp(ICmpCRSigned, op1, op2); - } - - InstLoc EmitICmpCRUnsigned(InstLoc op1, InstLoc op2) - { - return FoldBiOp(ICmpCRUnsigned, op1, op2); - } - - InstLoc EmitConvertFromFastCR(InstLoc op1) - { - return FoldUOp(ConvertFromFastCR, op1); - } - - InstLoc EmitConvertToFastCR(InstLoc op1) - { - return FoldUOp(ConvertToFastCR, op1); - } - - InstLoc EmitFastCRSOSet(InstLoc op1) - { - return FoldUOp(FastCRSOSet, op1); - } - - InstLoc EmitFastCREQSet(InstLoc op1) - { - return FoldUOp(FastCREQSet, op1); - } - - InstLoc EmitFastCRLTSet(InstLoc op1) - { - return FoldUOp(FastCRLTSet, op1); - } - - InstLoc EmitFastCRGTSet(InstLoc op1) - { - return FoldUOp(FastCRGTSet, op1); - } - - InstLoc EmitFallBackToInterpreter(InstLoc op1, InstLoc op2) - { - return FoldBiOp(FallBackToInterpreter, op1, op2); - } - - InstLoc EmitInterpreterBranch() - { - return FoldZeroOp(InterpreterBranch, 0); - } - - InstLoc EmitLoadCarry() - { - return FoldZeroOp(LoadCarry, 0); - } - - InstLoc EmitStoreCarry(InstLoc op1) - { - return FoldUOp(StoreCarry, op1); - } - - InstLoc EmitSystemCall(InstLoc pc) - { - return FoldUOp(SystemCall, pc); - } - - InstLoc EmitFPExceptionCheck(InstLoc pc) - { - return EmitUOp(FPExceptionCheck, pc); - } - - InstLoc EmitDSIExceptionCheck(InstLoc pc) - { - return EmitUOp(DSIExceptionCheck, pc); - } - - InstLoc EmitExtExceptionCheck(InstLoc pc) - { - return EmitUOp(ExtExceptionCheck, pc); - } - - InstLoc EmitBreakPointCheck(InstLoc pc) - { - return EmitUOp(BreakPointCheck, pc); - } - - InstLoc EmitRFIExit() - { - return FoldZeroOp(RFIExit, 0); - } - - InstLoc EmitShortIdleLoop(InstLoc pc) - { - return FoldUOp(ShortIdleLoop, pc); - } - - InstLoc EmitLoadSingle(InstLoc addr) - { - return FoldUOp(LoadSingle, addr); - } - - InstLoc EmitLoadDouble(InstLoc addr) - { - return FoldUOp(LoadDouble, addr); - } - - InstLoc EmitLoadPaired(InstLoc addr, unsigned quantReg) - { - return FoldUOp(LoadPaired, addr, quantReg); - } - - InstLoc EmitStoreSingle(InstLoc value, InstLoc addr) - { - return FoldBiOp(StoreSingle, value, addr); - } - - InstLoc EmitStoreDouble(InstLoc value, InstLoc addr) - { - return FoldBiOp(StoreDouble, value, addr); - } - - InstLoc EmitStorePaired(InstLoc value, InstLoc addr, unsigned quantReg) - { - return FoldBiOp(StorePaired, value, addr, quantReg); - } - - InstLoc EmitLoadFReg(unsigned freg) - { - return FoldZeroOp(LoadFReg, freg); - } - - InstLoc EmitLoadFRegDENToZero(unsigned freg) - { - return FoldZeroOp(LoadFRegDENToZero, freg); - } - - InstLoc EmitStoreFReg(InstLoc val, unsigned freg) - { - return FoldUOp(StoreFReg, val, freg); - } - - InstLoc EmitDupSingleToMReg(InstLoc val) - { - return FoldUOp(DupSingleToMReg, val); - } - - InstLoc EmitDupSingleToPacked(InstLoc val) - { - return FoldUOp(DupSingleToPacked, val); - } - - InstLoc EmitInsertDoubleInMReg(InstLoc val, InstLoc reg) - { - return FoldBiOp(InsertDoubleInMReg, val, reg); - } - - InstLoc EmitExpandPackedToMReg(InstLoc val) - { - return FoldUOp(ExpandPackedToMReg, val); - } - - InstLoc EmitCompactMRegToPacked(InstLoc val) - { - return FoldUOp(CompactMRegToPacked, val); - } - - InstLoc EmitFSMul(InstLoc op1, InstLoc op2) - { - return FoldBiOp(FSMul, op1, op2); - } - - InstLoc EmitFSAdd(InstLoc op1, InstLoc op2) - { - return FoldBiOp(FSAdd, op1, op2); - } - - InstLoc EmitFSSub(InstLoc op1, InstLoc op2) - { - return FoldBiOp(FSSub, op1, op2); - } - - InstLoc EmitFSNeg(InstLoc op1) - { - return FoldUOp(FSNeg, op1); - } - - InstLoc EmitFDMul(InstLoc op1, InstLoc op2) - { - return FoldBiOp(FDMul, op1, op2); - } - - InstLoc EmitFDAdd(InstLoc op1, InstLoc op2) - { - return FoldBiOp(FDAdd, op1, op2); - } - - InstLoc EmitFDSub(InstLoc op1, InstLoc op2) - { - return FoldBiOp(FDSub, op1, op2); - } - - InstLoc EmitFDNeg(InstLoc op1) - { - return FoldUOp(FDNeg, op1); - } - - InstLoc EmitFPAdd(InstLoc op1, InstLoc op2) - { - return FoldBiOp(FPAdd, op1, op2); - } - - InstLoc EmitFPMul(InstLoc op1, InstLoc op2) - { - return FoldBiOp(FPMul, op1, op2); - } - - InstLoc EmitFPSub(InstLoc op1, InstLoc op2) - { - return FoldBiOp(FPSub, op1, op2); - } - - InstLoc EmitFPMerge00(InstLoc op1, InstLoc op2) - { - return FoldBiOp(FPMerge00, op1, op2); - } - - InstLoc EmitFPMerge01(InstLoc op1, InstLoc op2) - { - return FoldBiOp(FPMerge01, op1, op2); - } - - InstLoc EmitFPMerge10(InstLoc op1, InstLoc op2) - { - return FoldBiOp(FPMerge10, op1, op2); - } - - InstLoc EmitFPMerge11(InstLoc op1, InstLoc op2) - { - return FoldBiOp(FPMerge11, op1, op2); - } - - InstLoc EmitFPDup0(InstLoc op1) - { - return FoldUOp(FPDup0, op1); - } - - InstLoc EmitFPDup1(InstLoc op1) - { - return FoldUOp(FPDup1, op1); - } - - InstLoc EmitFPNeg(InstLoc op1) - { - return FoldUOp(FPNeg, op1); - } - - InstLoc EmitDoubleToSingle(InstLoc op1) - { - return FoldUOp(DoubleToSingle, op1); - } - - InstLoc EmitFDCmpCR(InstLoc op1, InstLoc op2, int ordered) - { - return FoldBiOp(FDCmpCR, op1, op2, ordered); - } - - InstLoc EmitLoadGQR(unsigned gqr) - { - return FoldZeroOp(LoadGQR, gqr); - } - - InstLoc EmitStoreGQR(InstLoc op1, unsigned gqr) - { - return FoldUOp(StoreGQR, op1, gqr); - } - - InstLoc EmitStoreSRR(InstLoc op1, unsigned srr) - { - return FoldUOp(StoreSRR, op1, srr); - } - - InstLoc EmitINT3() - { - return FoldZeroOp(Int3, 0); - } - - void StartBackPass() { curReadPtr = InstList.data() + InstList.size(); } - void StartForwardPass() { curReadPtr = InstList.data(); } - InstLoc ReadForward() { return curReadPtr++; } - InstLoc ReadBackward() { return --curReadPtr; } - InstLoc getFirstInst() { return InstList.data(); } - unsigned int getNumInsts() { return (unsigned int)InstList.size(); } - unsigned int ReadInst(InstLoc I) { return *I; } - unsigned int GetImmValue(InstLoc I) const { return (u32)GetImmValue64(I); } - u64 GetImmValue64(InstLoc I) const; - void SetMarkUsed(InstLoc I); - bool IsMarkUsed(InstLoc I) const; - void WriteToFile(u64 codeHash); - - void Reset() - { - InstList.clear(); - InstList.reserve(100000); - MarkUsed.clear(); - MarkUsed.reserve(100000); - - for (unsigned i = 0; i < 32; i++) - { - GRegCache[i] = nullptr; - GRegCacheStore[i] = nullptr; - FRegCache[i] = nullptr; - FRegCacheStore[i] = nullptr; - } - - CarryCache = nullptr; - CarryCacheStore = nullptr; - - for (unsigned i = 0; i < 8; i++) - { - CRCache[i] = nullptr; - CRCacheStore[i] = nullptr; - } - - CTRCache = nullptr; - CTRCacheStore = nullptr; - } - - IRBuilder() - { - Reset(); - } - + InstLoc EmitIntConst(unsigned value) { return EmitIntConst64(value); } + InstLoc EmitIntConst64(u64 value); + + InstLoc EmitStoreLink(InstLoc val) { return FoldUOp(StoreLink, val); } + InstLoc EmitBranchUncond(InstLoc val) { return FoldUOp(BranchUncond, val); } + InstLoc EmitBranchCond(InstLoc check, InstLoc dest) { return FoldBiOp(BranchCond, check, dest); } + InstLoc EmitIdleBranch(InstLoc check, InstLoc dest) { return FoldBiOp(IdleBranch, check, dest); } + InstLoc EmitLoadCR(unsigned crreg) { return FoldZeroOp(LoadCR, crreg); } + InstLoc EmitStoreCR(InstLoc value, unsigned crreg) { return FoldUOp(StoreCR, value, crreg); } + InstLoc EmitLoadLink() { return FoldZeroOp(LoadLink, 0); } + InstLoc EmitLoadMSR() { return FoldZeroOp(LoadMSR, 0); } + InstLoc EmitStoreMSR(InstLoc val, InstLoc pc) { return FoldBiOp(StoreMSR, val, pc); } + InstLoc EmitStoreFPRF(InstLoc value) { return FoldUOp(StoreFPRF, value); } + InstLoc EmitLoadGReg(unsigned reg) { return FoldZeroOp(LoadGReg, reg); } + InstLoc EmitStoreGReg(InstLoc value, unsigned reg) { return FoldUOp(StoreGReg, value, reg); } + InstLoc EmitNot(InstLoc op1) { return FoldUOp(Not, op1); } + InstLoc EmitAnd(InstLoc op1, InstLoc op2) { return FoldBiOp(And, op1, op2); } + InstLoc EmitXor(InstLoc op1, InstLoc op2) { return FoldBiOp(Xor, op1, op2); } + InstLoc EmitSub(InstLoc op1, InstLoc op2) { return FoldBiOp(Sub, op1, op2); } + InstLoc EmitOr(InstLoc op1, InstLoc op2) { return FoldBiOp(Or, op1, op2); } + InstLoc EmitAdd(InstLoc op1, InstLoc op2) { return FoldBiOp(Add, op1, op2); } + InstLoc EmitMul(InstLoc op1, InstLoc op2) { return FoldBiOp(Mul, op1, op2); } + InstLoc EmitMulHighUnsigned(InstLoc op1, InstLoc op2) + { + return FoldBiOp(MulHighUnsigned, op1, op2); + } + + InstLoc EmitRol(InstLoc op1, InstLoc op2) { return FoldBiOp(Rol, op1, op2); } + InstLoc EmitShl(InstLoc op1, InstLoc op2) { return FoldBiOp(Shl, op1, op2); } + InstLoc EmitShrl(InstLoc op1, InstLoc op2) { return FoldBiOp(Shrl, op1, op2); } + InstLoc EmitSarl(InstLoc op1, InstLoc op2) { return FoldBiOp(Sarl, op1, op2); } + InstLoc EmitLoadCTR() { return FoldZeroOp(LoadCTR, 0); } + InstLoc EmitStoreCTR(InstLoc op1) { return FoldUOp(StoreCTR, op1); } + InstLoc EmitICmpEq(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpEq, op1, op2); } + InstLoc EmitICmpNe(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpNe, op1, op2); } + InstLoc EmitICmpUgt(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpUgt, op1, op2); } + InstLoc EmitICmpUlt(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpUlt, op1, op2); } + InstLoc EmitICmpSgt(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpSgt, op1, op2); } + InstLoc EmitICmpSlt(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpSlt, op1, op2); } + InstLoc EmitICmpSge(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpSge, op1, op2); } + InstLoc EmitICmpSle(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpSle, op1, op2); } + InstLoc EmitLoad8(InstLoc op1) { return FoldUOp(Load8, op1); } + InstLoc EmitLoad16(InstLoc op1) { return FoldUOp(Load16, op1); } + InstLoc EmitLoad32(InstLoc op1) { return FoldUOp(Load32, op1); } + InstLoc EmitStore8(InstLoc op1, InstLoc op2) { return FoldBiOp(Store8, op1, op2); } + InstLoc EmitStore16(InstLoc op1, InstLoc op2) { return FoldBiOp(Store16, op1, op2); } + InstLoc EmitStore32(InstLoc op1, InstLoc op2) { return FoldBiOp(Store32, op1, op2); } + InstLoc EmitSExt16(InstLoc op1) { return FoldUOp(SExt16, op1); } + InstLoc EmitSExt8(InstLoc op1) { return FoldUOp(SExt8, op1); } + InstLoc EmitCntlzw(InstLoc op1) { return FoldUOp(Cntlzw, op1); } + InstLoc EmitICmpCRSigned(InstLoc op1, InstLoc op2) { return FoldBiOp(ICmpCRSigned, op1, op2); } + InstLoc EmitICmpCRUnsigned(InstLoc op1, InstLoc op2) + { + return FoldBiOp(ICmpCRUnsigned, op1, op2); + } + + InstLoc EmitConvertFromFastCR(InstLoc op1) { return FoldUOp(ConvertFromFastCR, op1); } + InstLoc EmitConvertToFastCR(InstLoc op1) { return FoldUOp(ConvertToFastCR, op1); } + InstLoc EmitFastCRSOSet(InstLoc op1) { return FoldUOp(FastCRSOSet, op1); } + InstLoc EmitFastCREQSet(InstLoc op1) { return FoldUOp(FastCREQSet, op1); } + InstLoc EmitFastCRLTSet(InstLoc op1) { return FoldUOp(FastCRLTSet, op1); } + InstLoc EmitFastCRGTSet(InstLoc op1) { return FoldUOp(FastCRGTSet, op1); } + InstLoc EmitFallBackToInterpreter(InstLoc op1, InstLoc op2) + { + return FoldBiOp(FallBackToInterpreter, op1, op2); + } + + InstLoc EmitInterpreterBranch() { return FoldZeroOp(InterpreterBranch, 0); } + InstLoc EmitLoadCarry() { return FoldZeroOp(LoadCarry, 0); } + InstLoc EmitStoreCarry(InstLoc op1) { return FoldUOp(StoreCarry, op1); } + InstLoc EmitSystemCall(InstLoc pc) { return FoldUOp(SystemCall, pc); } + InstLoc EmitFPExceptionCheck(InstLoc pc) { return EmitUOp(FPExceptionCheck, pc); } + InstLoc EmitDSIExceptionCheck(InstLoc pc) { return EmitUOp(DSIExceptionCheck, pc); } + InstLoc EmitExtExceptionCheck(InstLoc pc) { return EmitUOp(ExtExceptionCheck, pc); } + InstLoc EmitBreakPointCheck(InstLoc pc) { return EmitUOp(BreakPointCheck, pc); } + InstLoc EmitRFIExit() { return FoldZeroOp(RFIExit, 0); } + InstLoc EmitShortIdleLoop(InstLoc pc) { return FoldUOp(ShortIdleLoop, pc); } + InstLoc EmitLoadSingle(InstLoc addr) { return FoldUOp(LoadSingle, addr); } + InstLoc EmitLoadDouble(InstLoc addr) { return FoldUOp(LoadDouble, addr); } + InstLoc EmitLoadPaired(InstLoc addr, unsigned quantReg) + { + return FoldUOp(LoadPaired, addr, quantReg); + } + + InstLoc EmitStoreSingle(InstLoc value, InstLoc addr) + { + return FoldBiOp(StoreSingle, value, addr); + } + + InstLoc EmitStoreDouble(InstLoc value, InstLoc addr) + { + return FoldBiOp(StoreDouble, value, addr); + } + + InstLoc EmitStorePaired(InstLoc value, InstLoc addr, unsigned quantReg) + { + return FoldBiOp(StorePaired, value, addr, quantReg); + } + + InstLoc EmitLoadFReg(unsigned freg) { return FoldZeroOp(LoadFReg, freg); } + InstLoc EmitLoadFRegDENToZero(unsigned freg) { return FoldZeroOp(LoadFRegDENToZero, freg); } + InstLoc EmitStoreFReg(InstLoc val, unsigned freg) { return FoldUOp(StoreFReg, val, freg); } + InstLoc EmitDupSingleToMReg(InstLoc val) { return FoldUOp(DupSingleToMReg, val); } + InstLoc EmitDupSingleToPacked(InstLoc val) { return FoldUOp(DupSingleToPacked, val); } + InstLoc EmitInsertDoubleInMReg(InstLoc val, InstLoc reg) + { + return FoldBiOp(InsertDoubleInMReg, val, reg); + } + + InstLoc EmitExpandPackedToMReg(InstLoc val) { return FoldUOp(ExpandPackedToMReg, val); } + InstLoc EmitCompactMRegToPacked(InstLoc val) { return FoldUOp(CompactMRegToPacked, val); } + InstLoc EmitFSMul(InstLoc op1, InstLoc op2) { return FoldBiOp(FSMul, op1, op2); } + InstLoc EmitFSAdd(InstLoc op1, InstLoc op2) { return FoldBiOp(FSAdd, op1, op2); } + InstLoc EmitFSSub(InstLoc op1, InstLoc op2) { return FoldBiOp(FSSub, op1, op2); } + InstLoc EmitFSNeg(InstLoc op1) { return FoldUOp(FSNeg, op1); } + InstLoc EmitFDMul(InstLoc op1, InstLoc op2) { return FoldBiOp(FDMul, op1, op2); } + InstLoc EmitFDAdd(InstLoc op1, InstLoc op2) { return FoldBiOp(FDAdd, op1, op2); } + InstLoc EmitFDSub(InstLoc op1, InstLoc op2) { return FoldBiOp(FDSub, op1, op2); } + InstLoc EmitFDNeg(InstLoc op1) { return FoldUOp(FDNeg, op1); } + InstLoc EmitFPAdd(InstLoc op1, InstLoc op2) { return FoldBiOp(FPAdd, op1, op2); } + InstLoc EmitFPMul(InstLoc op1, InstLoc op2) { return FoldBiOp(FPMul, op1, op2); } + InstLoc EmitFPSub(InstLoc op1, InstLoc op2) { return FoldBiOp(FPSub, op1, op2); } + InstLoc EmitFPMerge00(InstLoc op1, InstLoc op2) { return FoldBiOp(FPMerge00, op1, op2); } + InstLoc EmitFPMerge01(InstLoc op1, InstLoc op2) { return FoldBiOp(FPMerge01, op1, op2); } + InstLoc EmitFPMerge10(InstLoc op1, InstLoc op2) { return FoldBiOp(FPMerge10, op1, op2); } + InstLoc EmitFPMerge11(InstLoc op1, InstLoc op2) { return FoldBiOp(FPMerge11, op1, op2); } + InstLoc EmitFPDup0(InstLoc op1) { return FoldUOp(FPDup0, op1); } + InstLoc EmitFPDup1(InstLoc op1) { return FoldUOp(FPDup1, op1); } + InstLoc EmitFPNeg(InstLoc op1) { return FoldUOp(FPNeg, op1); } + InstLoc EmitDoubleToSingle(InstLoc op1) { return FoldUOp(DoubleToSingle, op1); } + InstLoc EmitFDCmpCR(InstLoc op1, InstLoc op2, int ordered) + { + return FoldBiOp(FDCmpCR, op1, op2, ordered); + } + + InstLoc EmitLoadGQR(unsigned gqr) { return FoldZeroOp(LoadGQR, gqr); } + InstLoc EmitStoreGQR(InstLoc op1, unsigned gqr) { return FoldUOp(StoreGQR, op1, gqr); } + InstLoc EmitStoreSRR(InstLoc op1, unsigned srr) { return FoldUOp(StoreSRR, op1, srr); } + InstLoc EmitINT3() { return FoldZeroOp(Int3, 0); } + void StartBackPass() { curReadPtr = InstList.data() + InstList.size(); } + void StartForwardPass() { curReadPtr = InstList.data(); } + InstLoc ReadForward() { return curReadPtr++; } + InstLoc ReadBackward() { return --curReadPtr; } + InstLoc getFirstInst() { return InstList.data(); } + unsigned int getNumInsts() { return (unsigned int)InstList.size(); } + unsigned int ReadInst(InstLoc I) { return *I; } + unsigned int GetImmValue(InstLoc I) const { return (u32)GetImmValue64(I); } + u64 GetImmValue64(InstLoc I) const; + void SetMarkUsed(InstLoc I); + bool IsMarkUsed(InstLoc I) const; + void WriteToFile(u64 codeHash); + + void Reset() + { + InstList.clear(); + InstList.reserve(100000); + MarkUsed.clear(); + MarkUsed.reserve(100000); + + for (unsigned i = 0; i < 32; i++) + { + GRegCache[i] = nullptr; + GRegCacheStore[i] = nullptr; + FRegCache[i] = nullptr; + FRegCacheStore[i] = nullptr; + } + + CarryCache = nullptr; + CarryCacheStore = nullptr; + + for (unsigned i = 0; i < 8; i++) + { + CRCache[i] = nullptr; + CRCacheStore[i] = nullptr; + } + + CTRCache = nullptr; + CTRCacheStore = nullptr; + } + + IRBuilder() { Reset(); } private: - IRBuilder(IRBuilder&); // DO NOT IMPLEMENT - bool isSameValue(InstLoc Op1, InstLoc Op2) const; - unsigned getComplexity(InstLoc I) const; - unsigned getNumberOfOperands(InstLoc I) const; - void simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2); - bool maskedValueIsZero(InstLoc Op1, InstLoc Op2) const; - InstLoc isNeg(InstLoc I) const; + IRBuilder(IRBuilder&); // DO NOT IMPLEMENT + bool isSameValue(InstLoc Op1, InstLoc Op2) const; + unsigned getComplexity(InstLoc I) const; + unsigned getNumberOfOperands(InstLoc I) const; + void simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2); + bool maskedValueIsZero(InstLoc Op1, InstLoc Op2) const; + InstLoc isNeg(InstLoc I) const; - std::vector InstList; // FIXME: We must ensure this is continuous! - std::vector MarkUsed; // Used for IRWriter - std::vector ConstList; - InstLoc curReadPtr; - InstLoc GRegCache[32]; - InstLoc GRegCacheStore[32]; - InstLoc FRegCache[32]; - InstLoc FRegCacheStore[32]; - InstLoc CarryCache; - InstLoc CarryCacheStore; - InstLoc CTRCache; - InstLoc CTRCacheStore; - InstLoc CRCache[8]; - InstLoc CRCacheStore[8]; + std::vector InstList; // FIXME: We must ensure this is continuous! + std::vector MarkUsed; // Used for IRWriter + std::vector ConstList; + InstLoc curReadPtr; + InstLoc GRegCache[32]; + InstLoc GRegCacheStore[32]; + InstLoc FRegCache[32]; + InstLoc FRegCacheStore[32]; + InstLoc CarryCache; + InstLoc CarryCacheStore; + InstLoc CTRCache; + InstLoc CTRCacheStore; + InstLoc CRCache[8]; + InstLoc CRCacheStore[8]; }; - }; diff --git a/Source/Core/Core/PowerPC/JitILCommon/JitILBase.h b/Source/Core/Core/PowerPC/JitILCommon/JitILBase.h index 7c15c1c226..fec6631a40 100644 --- a/Source/Core/Core/PowerPC/JitILCommon/JitILBase.h +++ b/Source/Core/Core/PowerPC/JitILCommon/JitILBase.h @@ -6,127 +6,126 @@ #include "Common/CommonTypes.h" #include "Core/PowerPC/Gekko.h" -#include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/JitCommon/JitBase.h" #include "Core/PowerPC/JitILCommon/IR.h" +#include "Core/PowerPC/PPCAnalyst.h" class JitILBase : public Jitx86Base { protected: - // The default code buffer. We keep it around to not have to alloc/dealloc a - // large chunk of memory for each recompiled block. - PPCAnalyst::CodeBuffer code_buffer; + // The default code buffer. We keep it around to not have to alloc/dealloc a + // large chunk of memory for each recompiled block. + PPCAnalyst::CodeBuffer code_buffer; + public: - JitILBase() : code_buffer(32000) {} - ~JitILBase() {} + JitILBase() : code_buffer(32000) {} + ~JitILBase() {} + IREmitter::IRBuilder ibuild; - IREmitter::IRBuilder ibuild; + virtual void Jit(u32 em_address) = 0; - virtual void Jit(u32 em_address) = 0; + virtual const CommonAsmRoutinesBase* GetAsmRoutines() = 0; - virtual const CommonAsmRoutinesBase *GetAsmRoutines() = 0; + // OPCODES + virtual void FallBackToInterpreter(UGeckoInstruction inst) = 0; + virtual void DoNothing(UGeckoInstruction inst) = 0; + virtual void HLEFunction(UGeckoInstruction inst) = 0; - // OPCODES - virtual void FallBackToInterpreter(UGeckoInstruction inst) = 0; - virtual void DoNothing(UGeckoInstruction inst) = 0; - virtual void HLEFunction(UGeckoInstruction inst) = 0; + virtual void DynaRunTable4(UGeckoInstruction _inst) = 0; + virtual void DynaRunTable19(UGeckoInstruction _inst) = 0; + virtual void DynaRunTable31(UGeckoInstruction _inst) = 0; + virtual void DynaRunTable59(UGeckoInstruction _inst) = 0; + virtual void DynaRunTable63(UGeckoInstruction _inst) = 0; - virtual void DynaRunTable4(UGeckoInstruction _inst) = 0; - virtual void DynaRunTable19(UGeckoInstruction _inst) = 0; - virtual void DynaRunTable31(UGeckoInstruction _inst) = 0; - virtual void DynaRunTable59(UGeckoInstruction _inst) = 0; - virtual void DynaRunTable63(UGeckoInstruction _inst) = 0; + // Branches + void sc(UGeckoInstruction inst); + void rfi(UGeckoInstruction inst); + void bx(UGeckoInstruction inst); + void bcx(UGeckoInstruction inst); + void bcctrx(UGeckoInstruction inst); + void bclrx(UGeckoInstruction inst); - // Branches - void sc(UGeckoInstruction inst); - void rfi(UGeckoInstruction inst); - void bx(UGeckoInstruction inst); - void bcx(UGeckoInstruction inst); - void bcctrx(UGeckoInstruction inst); - void bclrx(UGeckoInstruction inst); + // LoadStore + void lXzx(UGeckoInstruction inst); + void lhax(UGeckoInstruction inst); + void lhaux(UGeckoInstruction inst); + void stXx(UGeckoInstruction inst); + void lmw(UGeckoInstruction inst); + void stmw(UGeckoInstruction inst); + void stX(UGeckoInstruction inst); // stw sth stb + void lXz(UGeckoInstruction inst); + void lbzu(UGeckoInstruction inst); + void lha(UGeckoInstruction inst); + void lhau(UGeckoInstruction inst); - // LoadStore - void lXzx(UGeckoInstruction inst); - void lhax(UGeckoInstruction inst); - void lhaux(UGeckoInstruction inst); - void stXx(UGeckoInstruction inst); - void lmw(UGeckoInstruction inst); - void stmw(UGeckoInstruction inst); - void stX(UGeckoInstruction inst); //stw sth stb - void lXz(UGeckoInstruction inst); - void lbzu(UGeckoInstruction inst); - void lha(UGeckoInstruction inst); - void lhau(UGeckoInstruction inst); + // System Registers + void mtspr(UGeckoInstruction inst); + void mfspr(UGeckoInstruction inst); + void mtmsr(UGeckoInstruction inst); + void mfmsr(UGeckoInstruction inst); + void mftb(UGeckoInstruction inst); + void mtcrf(UGeckoInstruction inst); + void mfcr(UGeckoInstruction inst); + void mcrf(UGeckoInstruction inst); + void crXX(UGeckoInstruction inst); - // System Registers - void mtspr(UGeckoInstruction inst); - void mfspr(UGeckoInstruction inst); - void mtmsr(UGeckoInstruction inst); - void mfmsr(UGeckoInstruction inst); - void mftb(UGeckoInstruction inst); - void mtcrf(UGeckoInstruction inst); - void mfcr(UGeckoInstruction inst); - void mcrf(UGeckoInstruction inst); - void crXX(UGeckoInstruction inst); + void dcbst(UGeckoInstruction inst); + void dcbz(UGeckoInstruction inst); + void icbi(UGeckoInstruction inst); - void dcbst(UGeckoInstruction inst); - void dcbz(UGeckoInstruction inst); - void icbi(UGeckoInstruction inst); + void addx(UGeckoInstruction inst); + void boolX(UGeckoInstruction inst); + void mulli(UGeckoInstruction inst); + void mulhwux(UGeckoInstruction inst); + void mullwx(UGeckoInstruction inst); + void divwux(UGeckoInstruction inst); + void srawix(UGeckoInstruction inst); + void srawx(UGeckoInstruction inst); + void addex(UGeckoInstruction inst); + void addzex(UGeckoInstruction inst); - void addx(UGeckoInstruction inst); - void boolX(UGeckoInstruction inst); - void mulli(UGeckoInstruction inst); - void mulhwux(UGeckoInstruction inst); - void mullwx(UGeckoInstruction inst); - void divwux(UGeckoInstruction inst); - void srawix(UGeckoInstruction inst); - void srawx(UGeckoInstruction inst); - void addex(UGeckoInstruction inst); - void addzex(UGeckoInstruction inst); + void extsbx(UGeckoInstruction inst); + void extshx(UGeckoInstruction inst); - void extsbx(UGeckoInstruction inst); - void extshx(UGeckoInstruction inst); + void reg_imm(UGeckoInstruction inst); - void reg_imm(UGeckoInstruction inst); + void ps_arith(UGeckoInstruction inst); // aggregate + void ps_mergeXX(UGeckoInstruction inst); + void ps_maddXX(UGeckoInstruction inst); + void ps_sum(UGeckoInstruction inst); + void ps_muls(UGeckoInstruction inst); - void ps_arith(UGeckoInstruction inst); //aggregate - void ps_mergeXX(UGeckoInstruction inst); - void ps_maddXX(UGeckoInstruction inst); - void ps_sum(UGeckoInstruction inst); - void ps_muls(UGeckoInstruction inst); + void fp_arith_s(UGeckoInstruction inst); - void fp_arith_s(UGeckoInstruction inst); + void fcmpX(UGeckoInstruction inst); + void fmrx(UGeckoInstruction inst); - void fcmpX(UGeckoInstruction inst); - void fmrx(UGeckoInstruction inst); + void cmpXX(UGeckoInstruction inst); - void cmpXX(UGeckoInstruction inst); + void cntlzwx(UGeckoInstruction inst); - void cntlzwx(UGeckoInstruction inst); + void lfs(UGeckoInstruction inst); + void lfsu(UGeckoInstruction inst); + void lfd(UGeckoInstruction inst); + void lfdu(UGeckoInstruction inst); + void stfd(UGeckoInstruction inst); + void stfs(UGeckoInstruction inst); + void stfsx(UGeckoInstruction inst); + void psq_l(UGeckoInstruction inst); + void psq_st(UGeckoInstruction inst); - void lfs(UGeckoInstruction inst); - void lfsu(UGeckoInstruction inst); - void lfd(UGeckoInstruction inst); - void lfdu(UGeckoInstruction inst); - void stfd(UGeckoInstruction inst); - void stfs(UGeckoInstruction inst); - void stfsx(UGeckoInstruction inst); - void psq_l(UGeckoInstruction inst); - void psq_st(UGeckoInstruction inst); - - void fmaddXX(UGeckoInstruction inst); - void fsign(UGeckoInstruction inst); - void rlwinmx(UGeckoInstruction inst); - void rlwimix(UGeckoInstruction inst); - void rlwnmx(UGeckoInstruction inst); - void negx(UGeckoInstruction inst); - void slwx(UGeckoInstruction inst); - void srwx(UGeckoInstruction inst); - void lfsx(UGeckoInstruction inst); - - void subfic(UGeckoInstruction inst); - void subfcx(UGeckoInstruction inst); - void subfx(UGeckoInstruction inst); - void subfex(UGeckoInstruction inst); + void fmaddXX(UGeckoInstruction inst); + void fsign(UGeckoInstruction inst); + void rlwinmx(UGeckoInstruction inst); + void rlwimix(UGeckoInstruction inst); + void rlwnmx(UGeckoInstruction inst); + void negx(UGeckoInstruction inst); + void slwx(UGeckoInstruction inst); + void srwx(UGeckoInstruction inst); + void lfsx(UGeckoInstruction inst); + void subfic(UGeckoInstruction inst); + void subfcx(UGeckoInstruction inst); + void subfx(UGeckoInstruction inst); + void subfex(UGeckoInstruction inst); }; diff --git a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_Branch.cpp b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_Branch.cpp index f67ff7fe15..b545cf05b8 100644 --- a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_Branch.cpp +++ b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_Branch.cpp @@ -2,12 +2,11 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/JitILCommon/JitILBase.h" #include "Common/CommonTypes.h" #include "Core/ConfigManager.h" #include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/JitILCommon/JitILBase.h" - // The branches are known good, or at least reasonably good. // No need for a disable-mechanism. @@ -25,197 +24,194 @@ void JitILBase::sc(UGeckoInstruction inst) { - ibuild.EmitSystemCall(ibuild.EmitIntConst(js.compilerPC)); + ibuild.EmitSystemCall(ibuild.EmitIntConst(js.compilerPC)); } void JitILBase::rfi(UGeckoInstruction inst) { - ibuild.EmitRFIExit(); + ibuild.EmitRFIExit(); } void JitILBase::bx(UGeckoInstruction inst) { - NORMALBRANCH_START - INSTRUCTION_START; + NORMALBRANCH_START + INSTRUCTION_START; - // We must always process the following sentence - // even if the blocks are merged by PPCAnalyst::Flatten(). - if (inst.LK) - ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); + // We must always process the following sentence + // even if the blocks are merged by PPCAnalyst::Flatten(). + if (inst.LK) + ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); - // If this is not the last instruction of a block, - // we will skip the rest process. - // Because PPCAnalyst::Flatten() merged the blocks. - if (!js.isLastInstruction) - { - return; - } + // If this is not the last instruction of a block, + // we will skip the rest process. + // Because PPCAnalyst::Flatten() merged the blocks. + if (!js.isLastInstruction) + { + return; + } - u32 destination; - if (inst.AA) - destination = SignExt26(inst.LI << 2); - else - destination = js.compilerPC + SignExt26(inst.LI << 2); + u32 destination; + if (inst.AA) + destination = SignExt26(inst.LI << 2); + else + destination = js.compilerPC + SignExt26(inst.LI << 2); - if (destination == js.compilerPC) - { - ibuild.EmitShortIdleLoop(ibuild.EmitIntConst(js.compilerPC)); - return; - } + if (destination == js.compilerPC) + { + ibuild.EmitShortIdleLoop(ibuild.EmitIntConst(js.compilerPC)); + return; + } - ibuild.EmitBranchUncond(ibuild.EmitIntConst(destination)); + ibuild.EmitBranchUncond(ibuild.EmitIntConst(destination)); } static IREmitter::InstLoc EmitCRTest(IREmitter::IRBuilder& ibuild, UGeckoInstruction inst) { - IREmitter::InstLoc CRReg = ibuild.EmitLoadCR(inst.BI >> 2); - IREmitter::InstLoc CRTest = nullptr; - switch (3 - (inst.BI & 3)) - { - case CR_SO_BIT: - CRTest = ibuild.EmitFastCRSOSet(CRReg); - break; - case CR_EQ_BIT: - CRTest = ibuild.EmitFastCREQSet(CRReg); - break; - case CR_GT_BIT: - CRTest = ibuild.EmitFastCRGTSet(CRReg); - break; - case CR_LT_BIT: - CRTest = ibuild.EmitFastCRLTSet(CRReg); - break; - } - if (!(inst.BO & 8)) - CRTest = ibuild.EmitXor(CRTest, ibuild.EmitIntConst(1)); - return CRTest; + IREmitter::InstLoc CRReg = ibuild.EmitLoadCR(inst.BI >> 2); + IREmitter::InstLoc CRTest = nullptr; + switch (3 - (inst.BI & 3)) + { + case CR_SO_BIT: + CRTest = ibuild.EmitFastCRSOSet(CRReg); + break; + case CR_EQ_BIT: + CRTest = ibuild.EmitFastCREQSet(CRReg); + break; + case CR_GT_BIT: + CRTest = ibuild.EmitFastCRGTSet(CRReg); + break; + case CR_LT_BIT: + CRTest = ibuild.EmitFastCRLTSet(CRReg); + break; + } + if (!(inst.BO & 8)) + CRTest = ibuild.EmitXor(CRTest, ibuild.EmitIntConst(1)); + return CRTest; } static IREmitter::InstLoc TestBranch(IREmitter::IRBuilder& ibuild, UGeckoInstruction inst) { - IREmitter::InstLoc CRTest = nullptr, CTRTest = nullptr; - if ((inst.BO & 16) == 0) // Test a CR bit - { - CRTest = EmitCRTest(ibuild, inst); - } + IREmitter::InstLoc CRTest = nullptr, CTRTest = nullptr; + if ((inst.BO & 16) == 0) // Test a CR bit + { + CRTest = EmitCRTest(ibuild, inst); + } - if ((inst.BO & 4) == 0) - { - IREmitter::InstLoc c = ibuild.EmitLoadCTR(); - c = ibuild.EmitSub(c, ibuild.EmitIntConst(1)); - ibuild.EmitStoreCTR(c); + if ((inst.BO & 4) == 0) + { + IREmitter::InstLoc c = ibuild.EmitLoadCTR(); + c = ibuild.EmitSub(c, ibuild.EmitIntConst(1)); + ibuild.EmitStoreCTR(c); - if (inst.BO & 2) - CTRTest = ibuild.EmitICmpEq(c, ibuild.EmitIntConst(0)); - else - CTRTest = c; - } + if (inst.BO & 2) + CTRTest = ibuild.EmitICmpEq(c, ibuild.EmitIntConst(0)); + else + CTRTest = c; + } - IREmitter::InstLoc Test = CRTest; - if (CTRTest) - { - if (Test) - Test = ibuild.EmitAnd(Test, CTRTest); - else - Test = CTRTest; - } + IREmitter::InstLoc Test = CRTest; + if (CTRTest) + { + if (Test) + Test = ibuild.EmitAnd(Test, CTRTest); + else + Test = CTRTest; + } - if (!Test) - { - Test = ibuild.EmitIntConst(1); - } + if (!Test) + { + Test = ibuild.EmitIntConst(1); + } - return Test; + return Test; } void JitILBase::bcx(UGeckoInstruction inst) { - NORMALBRANCH_START - if (inst.LK) - ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); + NORMALBRANCH_START + if (inst.LK) + ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); - IREmitter::InstLoc Test = TestBranch(ibuild, inst); + IREmitter::InstLoc Test = TestBranch(ibuild, inst); - u32 destination; - if (inst.AA) - destination = SignExt16(inst.BD << 2); - else - destination = js.compilerPC + SignExt16(inst.BD << 2); + u32 destination; + if (inst.AA) + destination = SignExt16(inst.BD << 2); + else + destination = js.compilerPC + SignExt16(inst.BD << 2); - // Idle skipping: - // The main Idle skipping is done in the LoadStore code, but there is an optimization here. - // If idle skipping is enabled, then this branch will only be reached when the branch is not - // taken. - // TODO: We shouldn't use debug reads here. - if (SConfig::GetInstance().bSkipIdle && - inst.hex == 0x4182fff8 && - (PowerPC::HostRead_U32(js.compilerPC - 8) & 0xFFFF0000) == 0x800D0000 && - (PowerPC::HostRead_U32(js.compilerPC - 4) == 0x28000000 || - (SConfig::GetInstance().bWii && PowerPC::HostRead_U32(js.compilerPC - 4) == 0x2C000000)) - ) - { - // Uh, Do nothing. - } - else - { - ibuild.EmitBranchCond(Test, ibuild.EmitIntConst(destination)); - } - ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4)); + // Idle skipping: + // The main Idle skipping is done in the LoadStore code, but there is an optimization here. + // If idle skipping is enabled, then this branch will only be reached when the branch is not + // taken. + // TODO: We shouldn't use debug reads here. + if (SConfig::GetInstance().bSkipIdle && inst.hex == 0x4182fff8 && + (PowerPC::HostRead_U32(js.compilerPC - 8) & 0xFFFF0000) == 0x800D0000 && + (PowerPC::HostRead_U32(js.compilerPC - 4) == 0x28000000 || + (SConfig::GetInstance().bWii && PowerPC::HostRead_U32(js.compilerPC - 4) == 0x2C000000))) + { + // Uh, Do nothing. + } + else + { + ibuild.EmitBranchCond(Test, ibuild.EmitIntConst(destination)); + } + ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4)); } void JitILBase::bcctrx(UGeckoInstruction inst) { - NORMALBRANCH_START - if ((inst.BO & 4) == 0) - { - IREmitter::InstLoc c = ibuild.EmitLoadCTR(); - c = ibuild.EmitSub(c, ibuild.EmitIntConst(1)); - ibuild.EmitStoreCTR(c); - } + NORMALBRANCH_START + if ((inst.BO & 4) == 0) + { + IREmitter::InstLoc c = ibuild.EmitLoadCTR(); + c = ibuild.EmitSub(c, ibuild.EmitIntConst(1)); + ibuild.EmitStoreCTR(c); + } - IREmitter::InstLoc test; - if ((inst.BO & 16) == 0) // Test a CR bit - { - test = EmitCRTest(ibuild, inst); - } - else - { - test = ibuild.EmitIntConst(1); - } - test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0)); - ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4)); + IREmitter::InstLoc test; + if ((inst.BO & 16) == 0) // Test a CR bit + { + test = EmitCRTest(ibuild, inst); + } + else + { + test = ibuild.EmitIntConst(1); + } + test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0)); + ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4)); - IREmitter::InstLoc destination = ibuild.EmitLoadCTR(); - destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4)); - if (inst.LK) - ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); - ibuild.EmitBranchUncond(destination); + IREmitter::InstLoc destination = ibuild.EmitLoadCTR(); + destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4)); + if (inst.LK) + ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); + ibuild.EmitBranchUncond(destination); } void JitILBase::bclrx(UGeckoInstruction inst) { - NORMALBRANCH_START + NORMALBRANCH_START - if (!js.isLastInstruction && - (inst.BO & (1 << 4)) && (inst.BO & (1 << 2))) - { - if (inst.LK) - ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); - return; - } + if (!js.isLastInstruction && (inst.BO & (1 << 4)) && (inst.BO & (1 << 2))) + { + if (inst.LK) + ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); + return; + } - if (inst.hex == 0x4e800020) - { - ibuild.EmitBranchUncond(ibuild.EmitLoadLink()); - return; - } + if (inst.hex == 0x4e800020) + { + ibuild.EmitBranchUncond(ibuild.EmitLoadLink()); + return; + } - IREmitter::InstLoc test = TestBranch(ibuild, inst); - test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0)); - ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4)); + IREmitter::InstLoc test = TestBranch(ibuild, inst); + test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0)); + ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4)); - IREmitter::InstLoc destination = ibuild.EmitLoadLink(); - destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4)); - if (inst.LK) - ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); - ibuild.EmitBranchUncond(destination); + IREmitter::InstLoc destination = ibuild.EmitLoadLink(); + destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4)); + if (inst.LK) + ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); + ibuild.EmitBranchUncond(destination); } diff --git a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_FloatingPoint.cpp b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_FloatingPoint.cpp index 82eb3be68f..0d6226941e 100644 --- a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_FloatingPoint.cpp @@ -2,124 +2,124 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/JitILCommon/JitILBase.h" #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/MsgHandler.h" #include "Core/ConfigManager.h" -#include "Core/PowerPC/JitILCommon/JitILBase.h" void JitILBase::fp_arith_s(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc || (inst.SUBOP5 != 25 && inst.SUBOP5 != 20 && inst.SUBOP5 != 21)); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc || (inst.SUBOP5 != 25 && inst.SUBOP5 != 20 && inst.SUBOP5 != 21)); - // Only the interpreter has "proper" support for (some) FP flags - FALLBACK_IF(inst.SUBOP5 == 25 && SConfig::GetInstance().bFPRF); + // Only the interpreter has "proper" support for (some) FP flags + FALLBACK_IF(inst.SUBOP5 == 25 && SConfig::GetInstance().bFPRF); - IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA); - switch (inst.SUBOP5) - { - case 20: //sub - val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB)); - break; - case 21: //add - val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB)); - break; - case 25: //mul - val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC)); - break; - default: - _assert_msg_(DYNA_REC, 0, "fp_arith_s WTF!!!"); - } + IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA); + switch (inst.SUBOP5) + { + case 20: // sub + val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB)); + break; + case 21: // add + val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB)); + break; + case 25: // mul + val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC)); + break; + default: + _assert_msg_(DYNA_REC, 0, "fp_arith_s WTF!!!"); + } - if (inst.OPCD == 59) - { - val = ibuild.EmitDoubleToSingle(val); - val = ibuild.EmitDupSingleToMReg(val); - } - else - { - val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD)); - } - ibuild.EmitStoreFReg(val, inst.FD); + if (inst.OPCD == 59) + { + val = ibuild.EmitDoubleToSingle(val); + val = ibuild.EmitDupSingleToMReg(val); + } + else + { + val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD)); + } + ibuild.EmitStoreFReg(val, inst.FD); } void JitILBase::fmaddXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); - // Only the interpreter has "proper" support for (some) FP flags - FALLBACK_IF(inst.SUBOP5 == 29 && SConfig::GetInstance().bFPRF); + // Only the interpreter has "proper" support for (some) FP flags + FALLBACK_IF(inst.SUBOP5 == 29 && SConfig::GetInstance().bFPRF); - IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA); - val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC)); + IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA); + val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC)); - if (inst.SUBOP5 & 1) - val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB)); - else - val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB)); + if (inst.SUBOP5 & 1) + val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB)); + else + val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB)); - if (inst.SUBOP5 & 2) - val = ibuild.EmitFDNeg(val); + if (inst.SUBOP5 & 2) + val = ibuild.EmitFDNeg(val); - if (inst.OPCD == 59) - { - val = ibuild.EmitDoubleToSingle(val); - val = ibuild.EmitDupSingleToMReg(val); - } - else - { - val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD)); - } + if (inst.OPCD == 59) + { + val = ibuild.EmitDoubleToSingle(val); + val = ibuild.EmitDupSingleToMReg(val); + } + else + { + val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD)); + } - ibuild.EmitStoreFReg(val, inst.FD); + ibuild.EmitStoreFReg(val, inst.FD); } void JitILBase::fmrx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(inst.Rc); - IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FB); - val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD)); - ibuild.EmitStoreFReg(val, inst.FD); + IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FB); + val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD)); + ibuild.EmitStoreFReg(val, inst.FD); } void JitILBase::fcmpX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); - IREmitter::InstLoc lhs, rhs, res; - lhs = ibuild.EmitLoadFReg(inst.FA); - rhs = ibuild.EmitLoadFReg(inst.FB); - int ordered = (inst.SUBOP10 == 32) ? 1 : 0; - res = ibuild.EmitFDCmpCR(lhs, rhs, ordered); - ibuild.EmitStoreFPRF(res); - ibuild.EmitStoreCR(ibuild.EmitConvertToFastCR(res), inst.CRFD); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); + IREmitter::InstLoc lhs, rhs, res; + lhs = ibuild.EmitLoadFReg(inst.FA); + rhs = ibuild.EmitLoadFReg(inst.FB); + int ordered = (inst.SUBOP10 == 32) ? 1 : 0; + res = ibuild.EmitFDCmpCR(lhs, rhs, ordered); + ibuild.EmitStoreFPRF(res); + ibuild.EmitStoreCR(ibuild.EmitConvertToFastCR(res), inst.CRFD); } void JitILBase::fsign(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITFloatingPointOff); + INSTRUCTION_START + JITDISABLE(bJITFloatingPointOff); - FALLBACK_IF(true); + FALLBACK_IF(true); - // TODO - switch (inst.SUBOP10) - { - case 40: // fnegx - break; - case 264: // fabsx - break; - case 136: // fnabs - break; - default: - PanicAlert("fsign bleh"); - break; - } + // TODO + switch (inst.SUBOP10) + { + case 40: // fnegx + break; + case 264: // fabsx + break; + case 136: // fnabs + break; + default: + PanicAlert("fsign bleh"); + break; + } } diff --git a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_Integer.cpp b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_Integer.cpp index a0a6a9abeb..827e0f7a6d 100644 --- a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_Integer.cpp @@ -3,323 +3,323 @@ // Refer to the license.txt file included. #ifdef _MSC_VER -#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned +#pragma warning( \ + disable : 4146) // unary minus operator applied to unsigned type, result still unsigned #endif +#include "Core/PowerPC/JitILCommon/JitILBase.h" #include "Common/CommonTypes.h" #include "Core/ConfigManager.h" -#include "Core/PowerPC/JitILCommon/JitILBase.h" static void ComputeRC(IREmitter::IRBuilder& ibuild, IREmitter::InstLoc val) { - IREmitter::InstLoc res = - ibuild.EmitICmpCRSigned(val, ibuild.EmitIntConst(0)); - ibuild.EmitStoreCR(res, 0); + IREmitter::InstLoc res = ibuild.EmitICmpCRSigned(val, ibuild.EmitIntConst(0)); + ibuild.EmitStoreCR(res, 0); } void JitILBase::reg_imm(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - int d = inst.RD, a = inst.RA, s = inst.RS; - IREmitter::InstLoc val, test, c; - switch (inst.OPCD) - { - case 14: //addi - val = ibuild.EmitIntConst(inst.SIMM_16); - if (a) - val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val); - ibuild.EmitStoreGReg(val, d); - break; - case 15: //addis - val = ibuild.EmitIntConst(inst.SIMM_16 << 16); - if (a) - val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val); - ibuild.EmitStoreGReg(val, d); - break; - case 24: //ori - val = ibuild.EmitIntConst(inst.UIMM); - val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val); - ibuild.EmitStoreGReg(val, a); - break; - case 25: //oris - val = ibuild.EmitIntConst(inst.UIMM << 16); - val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val); - ibuild.EmitStoreGReg(val, a); - break; - case 28: //andi - val = ibuild.EmitIntConst(inst.UIMM); - val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val); - ibuild.EmitStoreGReg(val, a); - ComputeRC(ibuild, val); - break; - case 29: //andis - val = ibuild.EmitIntConst(inst.UIMM << 16); - val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val); - ibuild.EmitStoreGReg(val, a); - ComputeRC(ibuild, val); - break; - case 26: //xori - val = ibuild.EmitIntConst(inst.UIMM); - val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val); - ibuild.EmitStoreGReg(val, a); - break; - case 27: //xoris - val = ibuild.EmitIntConst(inst.UIMM << 16); - val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val); - ibuild.EmitStoreGReg(val, a); - break; - case 12: //addic - case 13: //addic_rc - c = ibuild.EmitIntConst(inst.SIMM_16); - val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), c); - ibuild.EmitStoreGReg(val, d); - test = ibuild.EmitICmpUgt(c, val); - ibuild.EmitStoreCarry(test); - if (inst.OPCD == 13) - ComputeRC(ibuild, val); - break; - default: - FALLBACK_IF(true); - } + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int d = inst.RD, a = inst.RA, s = inst.RS; + IREmitter::InstLoc val, test, c; + switch (inst.OPCD) + { + case 14: // addi + val = ibuild.EmitIntConst(inst.SIMM_16); + if (a) + val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val); + ibuild.EmitStoreGReg(val, d); + break; + case 15: // addis + val = ibuild.EmitIntConst(inst.SIMM_16 << 16); + if (a) + val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val); + ibuild.EmitStoreGReg(val, d); + break; + case 24: // ori + val = ibuild.EmitIntConst(inst.UIMM); + val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val); + ibuild.EmitStoreGReg(val, a); + break; + case 25: // oris + val = ibuild.EmitIntConst(inst.UIMM << 16); + val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val); + ibuild.EmitStoreGReg(val, a); + break; + case 28: // andi + val = ibuild.EmitIntConst(inst.UIMM); + val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val); + ibuild.EmitStoreGReg(val, a); + ComputeRC(ibuild, val); + break; + case 29: // andis + val = ibuild.EmitIntConst(inst.UIMM << 16); + val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val); + ibuild.EmitStoreGReg(val, a); + ComputeRC(ibuild, val); + break; + case 26: // xori + val = ibuild.EmitIntConst(inst.UIMM); + val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val); + ibuild.EmitStoreGReg(val, a); + break; + case 27: // xoris + val = ibuild.EmitIntConst(inst.UIMM << 16); + val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val); + ibuild.EmitStoreGReg(val, a); + break; + case 12: // addic + case 13: // addic_rc + c = ibuild.EmitIntConst(inst.SIMM_16); + val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), c); + ibuild.EmitStoreGReg(val, d); + test = ibuild.EmitICmpUgt(c, val); + ibuild.EmitStoreCarry(test); + if (inst.OPCD == 13) + ComputeRC(ibuild, val); + break; + default: + FALLBACK_IF(true); + } } void JitILBase::cmpXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - IREmitter::InstLoc lhs, rhs, res; - lhs = ibuild.EmitLoadGReg(inst.RA); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + IREmitter::InstLoc lhs, rhs, res; + lhs = ibuild.EmitLoadGReg(inst.RA); - if (inst.OPCD == 31) - { - rhs = ibuild.EmitLoadGReg(inst.RB); - if (inst.SUBOP10 == 32) - { - res = ibuild.EmitICmpCRUnsigned(lhs, rhs); - } - else - { - res = ibuild.EmitICmpCRSigned(lhs, rhs); - } - } - else if (inst.OPCD == 10) - { - rhs = ibuild.EmitIntConst(inst.UIMM); - res = ibuild.EmitICmpCRUnsigned(lhs, rhs); - } - else // inst.OPCD == 11 - { - rhs = ibuild.EmitIntConst(inst.SIMM_16); - res = ibuild.EmitICmpCRSigned(lhs, rhs); - } + if (inst.OPCD == 31) + { + rhs = ibuild.EmitLoadGReg(inst.RB); + if (inst.SUBOP10 == 32) + { + res = ibuild.EmitICmpCRUnsigned(lhs, rhs); + } + else + { + res = ibuild.EmitICmpCRSigned(lhs, rhs); + } + } + else if (inst.OPCD == 10) + { + rhs = ibuild.EmitIntConst(inst.UIMM); + res = ibuild.EmitICmpCRUnsigned(lhs, rhs); + } + else // inst.OPCD == 11 + { + rhs = ibuild.EmitIntConst(inst.SIMM_16); + res = ibuild.EmitICmpCRSigned(lhs, rhs); + } - js.downcountAmount++; //TODO: should this be somewhere else? + js.downcountAmount++; // TODO: should this be somewhere else? - ibuild.EmitStoreCR(res, inst.CRFD); + ibuild.EmitStoreCR(res, inst.CRFD); } void JitILBase::boolX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - IREmitter::InstLoc a = nullptr; - IREmitter::InstLoc s = ibuild.EmitLoadGReg(inst.RS); - IREmitter::InstLoc b = ibuild.EmitLoadGReg(inst.RB); + IREmitter::InstLoc a = nullptr; + IREmitter::InstLoc s = ibuild.EmitLoadGReg(inst.RS); + IREmitter::InstLoc b = ibuild.EmitLoadGReg(inst.RB); - // FIXME: Some instructions does not work well in NSMBW, MP2, etc. - // Refer JitIL_Tables.cpp. - if (inst.SUBOP10 == 28) /* andx */ - { - a = ibuild.EmitAnd(s, b); - } - else if (inst.SUBOP10 == 476) /* nandx */ - { - a = ibuild.EmitNot(ibuild.EmitAnd(s, b)); - } - else if (inst.SUBOP10 == 60) /* andcx */ - { - a = ibuild.EmitAnd(s, ibuild.EmitNot(b)); - } - else if (inst.SUBOP10 == 444) /* orx */ - { - a = ibuild.EmitOr(s, b); - } - else if (inst.SUBOP10 == 124) /* norx */ - { - a = ibuild.EmitNot(ibuild.EmitOr(s, b)); - } - else if (inst.SUBOP10 == 412) /* orcx */ - { - a = ibuild.EmitOr(s, ibuild.EmitNot(b)); - } - else if (inst.SUBOP10 == 316) /* xorx */ - { - a = ibuild.EmitXor(s, b); - } - else if (inst.SUBOP10 == 284) /* eqvx */ - { - a = ibuild.EmitNot(ibuild.EmitXor(s, b)); - } - else - { - PanicAlert("WTF!"); - } + // FIXME: Some instructions does not work well in NSMBW, MP2, etc. + // Refer JitIL_Tables.cpp. + if (inst.SUBOP10 == 28) /* andx */ + { + a = ibuild.EmitAnd(s, b); + } + else if (inst.SUBOP10 == 476) /* nandx */ + { + a = ibuild.EmitNot(ibuild.EmitAnd(s, b)); + } + else if (inst.SUBOP10 == 60) /* andcx */ + { + a = ibuild.EmitAnd(s, ibuild.EmitNot(b)); + } + else if (inst.SUBOP10 == 444) /* orx */ + { + a = ibuild.EmitOr(s, b); + } + else if (inst.SUBOP10 == 124) /* norx */ + { + a = ibuild.EmitNot(ibuild.EmitOr(s, b)); + } + else if (inst.SUBOP10 == 412) /* orcx */ + { + a = ibuild.EmitOr(s, ibuild.EmitNot(b)); + } + else if (inst.SUBOP10 == 316) /* xorx */ + { + a = ibuild.EmitXor(s, b); + } + else if (inst.SUBOP10 == 284) /* eqvx */ + { + a = ibuild.EmitNot(ibuild.EmitXor(s, b)); + } + else + { + PanicAlert("WTF!"); + } - ibuild.EmitStoreGReg(a, inst.RA); - if (inst.Rc) - ComputeRC(ibuild, a); + ibuild.EmitStoreGReg(a, inst.RA); + if (inst.Rc) + ComputeRC(ibuild, a); } void JitILBase::extsbx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); - val = ibuild.EmitSExt8(val); - ibuild.EmitStoreGReg(val, inst.RA); - if (inst.Rc) - ComputeRC(ibuild, val); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); + val = ibuild.EmitSExt8(val); + ibuild.EmitStoreGReg(val, inst.RA); + if (inst.Rc) + ComputeRC(ibuild, val); } void JitILBase::extshx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); - val = ibuild.EmitSExt16(val); - ibuild.EmitStoreGReg(val, inst.RA); - if (inst.Rc) - ComputeRC(ibuild, val); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); + val = ibuild.EmitSExt16(val); + ibuild.EmitStoreGReg(val, inst.RA); + if (inst.Rc) + ComputeRC(ibuild, val); } void JitILBase::subfic(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - IREmitter::InstLoc nota, lhs, val, test; - nota = ibuild.EmitXor(ibuild.EmitLoadGReg(inst.RA), - ibuild.EmitIntConst(-1)); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + IREmitter::InstLoc nota, lhs, val, test; + nota = ibuild.EmitXor(ibuild.EmitLoadGReg(inst.RA), ibuild.EmitIntConst(-1)); - if (inst.SIMM_16 == -1) - { - val = nota; - test = ibuild.EmitIntConst(1); - } - else - { - lhs = ibuild.EmitIntConst(inst.SIMM_16 + 1); - val = ibuild.EmitAdd(nota, lhs); - test = ibuild.EmitICmpUgt(lhs, val); - } + if (inst.SIMM_16 == -1) + { + val = nota; + test = ibuild.EmitIntConst(1); + } + else + { + lhs = ibuild.EmitIntConst(inst.SIMM_16 + 1); + val = ibuild.EmitAdd(nota, lhs); + test = ibuild.EmitICmpUgt(lhs, val); + } - ibuild.EmitStoreGReg(val, inst.RD); - ibuild.EmitStoreCarry(test); + ibuild.EmitStoreGReg(val, inst.RD); + ibuild.EmitStoreCarry(test); } void JitILBase::subfcx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - if (inst.OE) - PanicAlert("OE: subfcx"); + if (inst.OE) + PanicAlert("OE: subfcx"); - IREmitter::InstLoc val, test, lhs, rhs; - lhs = ibuild.EmitLoadGReg(inst.RB); - rhs = ibuild.EmitLoadGReg(inst.RA); - val = ibuild.EmitSub(lhs, rhs); - ibuild.EmitStoreGReg(val, inst.RD); - test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0)); - test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val)); - ibuild.EmitStoreCarry(test); + IREmitter::InstLoc val, test, lhs, rhs; + lhs = ibuild.EmitLoadGReg(inst.RB); + rhs = ibuild.EmitLoadGReg(inst.RA); + val = ibuild.EmitSub(lhs, rhs); + ibuild.EmitStoreGReg(val, inst.RD); + test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0)); + test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val)); + ibuild.EmitStoreCarry(test); - if (inst.Rc) - ComputeRC(ibuild, val); + if (inst.Rc) + ComputeRC(ibuild, val); } void JitILBase::subfex(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - if (inst.OE) - PanicAlert("OE: subfex"); + if (inst.OE) + PanicAlert("OE: subfex"); - IREmitter::InstLoc val, test, lhs, rhs, carry; - rhs = ibuild.EmitLoadGReg(inst.RA); - carry = ibuild.EmitLoadCarry(); - rhs = ibuild.EmitXor(rhs, ibuild.EmitIntConst(-1)); - rhs = ibuild.EmitAdd(rhs, carry); - test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0)); - test = ibuild.EmitAnd(test, carry); - lhs = ibuild.EmitLoadGReg(inst.RB); - val = ibuild.EmitAdd(lhs, rhs); - ibuild.EmitStoreGReg(val, inst.RD); - test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val)); - ibuild.EmitStoreCarry(test); + IREmitter::InstLoc val, test, lhs, rhs, carry; + rhs = ibuild.EmitLoadGReg(inst.RA); + carry = ibuild.EmitLoadCarry(); + rhs = ibuild.EmitXor(rhs, ibuild.EmitIntConst(-1)); + rhs = ibuild.EmitAdd(rhs, carry); + test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0)); + test = ibuild.EmitAnd(test, carry); + lhs = ibuild.EmitLoadGReg(inst.RB); + val = ibuild.EmitAdd(lhs, rhs); + ibuild.EmitStoreGReg(val, inst.RD); + test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val)); + ibuild.EmitStoreCarry(test); - if (inst.Rc) - ComputeRC(ibuild, val); + if (inst.Rc) + ComputeRC(ibuild, val); } void JitILBase::subfx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - if (inst.OE) - PanicAlert("OE: subfx"); + if (inst.OE) + PanicAlert("OE: subfx"); - IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB); - val = ibuild.EmitSub(val, ibuild.EmitLoadGReg(inst.RA)); - ibuild.EmitStoreGReg(val, inst.RD); + IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB); + val = ibuild.EmitSub(val, ibuild.EmitLoadGReg(inst.RA)); + ibuild.EmitStoreGReg(val, inst.RD); - if (inst.Rc) - ComputeRC(ibuild, val); + if (inst.Rc) + ComputeRC(ibuild, val); } void JitILBase::mulli(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA); - val = ibuild.EmitMul(val, ibuild.EmitIntConst(inst.SIMM_16)); - ibuild.EmitStoreGReg(val, inst.RD); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA); + val = ibuild.EmitMul(val, ibuild.EmitIntConst(inst.SIMM_16)); + ibuild.EmitStoreGReg(val, inst.RD); } void JitILBase::mullwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB); - val = ibuild.EmitMul(ibuild.EmitLoadGReg(inst.RA), val); - ibuild.EmitStoreGReg(val, inst.RD); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB); + val = ibuild.EmitMul(ibuild.EmitLoadGReg(inst.RA), val); + ibuild.EmitStoreGReg(val, inst.RD); - if (inst.Rc) - ComputeRC(ibuild, val); + if (inst.Rc) + ComputeRC(ibuild, val); } void JitILBase::mulhwux(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - IREmitter::InstLoc a = ibuild.EmitLoadGReg(inst.RA); - IREmitter::InstLoc b = ibuild.EmitLoadGReg(inst.RB); - IREmitter::InstLoc d = ibuild.EmitMulHighUnsigned(a, b); - ibuild.EmitStoreGReg(d, inst.RD); + IREmitter::InstLoc a = ibuild.EmitLoadGReg(inst.RA); + IREmitter::InstLoc b = ibuild.EmitLoadGReg(inst.RB); + IREmitter::InstLoc d = ibuild.EmitMulHighUnsigned(a, b); + ibuild.EmitStoreGReg(d, inst.RD); - if (inst.Rc) - ComputeRC(ibuild, d); + if (inst.Rc) + ComputeRC(ibuild, d); } -// skipped some of the special handling in here - if we get crashes, let the interpreter handle this op +// skipped some of the special handling in here - if we get crashes, let the interpreter handle this +// op void JitILBase::divwux(UGeckoInstruction inst) { - // FIXME - FALLBACK_IF(true); + // FIXME + FALLBACK_IF(true); #if 0 int a = inst.RA, b = inst.RB, d = inst.RD; @@ -352,210 +352,209 @@ void JitILBase::divwux(UGeckoInstruction inst) void JitILBase::addx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB); - val = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), val); - ibuild.EmitStoreGReg(val, inst.RD); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB); + val = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), val); + ibuild.EmitStoreGReg(val, inst.RD); - if (inst.Rc) - ComputeRC(ibuild, val); + if (inst.Rc) + ComputeRC(ibuild, val); } void JitILBase::addzex(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - IREmitter::InstLoc lhs = ibuild.EmitLoadGReg(inst.RA), val, newcarry; - val = ibuild.EmitAdd(lhs, ibuild.EmitLoadCarry()); - ibuild.EmitStoreGReg(val, inst.RD); - newcarry = ibuild.EmitICmpUlt(val, lhs); - ibuild.EmitStoreCarry(newcarry); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + IREmitter::InstLoc lhs = ibuild.EmitLoadGReg(inst.RA), val, newcarry; + val = ibuild.EmitAdd(lhs, ibuild.EmitLoadCarry()); + ibuild.EmitStoreGReg(val, inst.RD); + newcarry = ibuild.EmitICmpUlt(val, lhs); + ibuild.EmitStoreCarry(newcarry); - if (inst.Rc) - ComputeRC(ibuild, val); + if (inst.Rc) + ComputeRC(ibuild, val); } void JitILBase::addex(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - IREmitter::InstLoc a = ibuild.EmitLoadGReg(inst.RA); - IREmitter::InstLoc b = ibuild.EmitLoadGReg(inst.RB); + IREmitter::InstLoc a = ibuild.EmitLoadGReg(inst.RA); + IREmitter::InstLoc b = ibuild.EmitLoadGReg(inst.RB); - IREmitter::InstLoc ab = ibuild.EmitAdd(a, b); - IREmitter::InstLoc new_carry = ibuild.EmitICmpUlt(ab, a); + IREmitter::InstLoc ab = ibuild.EmitAdd(a, b); + IREmitter::InstLoc new_carry = ibuild.EmitICmpUlt(ab, a); - IREmitter::InstLoc previous_carry = ibuild.EmitLoadCarry(); - IREmitter::InstLoc abc = ibuild.EmitAdd(ab, previous_carry); - new_carry = ibuild.EmitOr(new_carry, ibuild.EmitICmpUlt(abc, ab)); + IREmitter::InstLoc previous_carry = ibuild.EmitLoadCarry(); + IREmitter::InstLoc abc = ibuild.EmitAdd(ab, previous_carry); + new_carry = ibuild.EmitOr(new_carry, ibuild.EmitICmpUlt(abc, ab)); - ibuild.EmitStoreGReg(abc, inst.RD); - ibuild.EmitStoreCarry(new_carry); + ibuild.EmitStoreGReg(abc, inst.RD); + ibuild.EmitStoreCarry(new_carry); - if (inst.OE) - PanicAlert("OE: addex"); + if (inst.OE) + PanicAlert("OE: addex"); - if (inst.Rc) - ComputeRC(ibuild, abc); + if (inst.Rc) + ComputeRC(ibuild, abc); } void JitILBase::rlwinmx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - unsigned mask = Helper_Mask(inst.MB, inst.ME); - IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); - val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH)); - val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask)); - ibuild.EmitStoreGReg(val, inst.RA); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + unsigned mask = Helper_Mask(inst.MB, inst.ME); + IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); + val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH)); + val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask)); + ibuild.EmitStoreGReg(val, inst.RA); - if (inst.Rc) - ComputeRC(ibuild, val); + if (inst.Rc) + ComputeRC(ibuild, val); } - void JitILBase::rlwimix(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - unsigned mask = Helper_Mask(inst.MB, inst.ME); - IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); - val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH)); - val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask)); - IREmitter::InstLoc ival = ibuild.EmitLoadGReg(inst.RA); - ival = ibuild.EmitAnd(ival, ibuild.EmitIntConst(~mask)); - val = ibuild.EmitOr(ival, val); - ibuild.EmitStoreGReg(val, inst.RA); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + unsigned mask = Helper_Mask(inst.MB, inst.ME); + IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); + val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH)); + val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask)); + IREmitter::InstLoc ival = ibuild.EmitLoadGReg(inst.RA); + ival = ibuild.EmitAnd(ival, ibuild.EmitIntConst(~mask)); + val = ibuild.EmitOr(ival, val); + ibuild.EmitStoreGReg(val, inst.RA); - if (inst.Rc) - ComputeRC(ibuild, val); + if (inst.Rc) + ComputeRC(ibuild, val); } void JitILBase::rlwnmx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - unsigned int mask = Helper_Mask(inst.MB, inst.ME); - IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); - val = ibuild.EmitRol(val, ibuild.EmitLoadGReg(inst.RB)); - val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask)); - ibuild.EmitStoreGReg(val, inst.RA); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + unsigned int mask = Helper_Mask(inst.MB, inst.ME); + IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); + val = ibuild.EmitRol(val, ibuild.EmitLoadGReg(inst.RB)); + val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask)); + ibuild.EmitStoreGReg(val, inst.RA); - if (inst.Rc) - ComputeRC(ibuild, val); + if (inst.Rc) + ComputeRC(ibuild, val); } void JitILBase::negx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA); - val = ibuild.EmitSub(ibuild.EmitIntConst(0), val); - ibuild.EmitStoreGReg(val, inst.RD); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA); + val = ibuild.EmitSub(ibuild.EmitIntConst(0), val); + ibuild.EmitStoreGReg(val, inst.RD); - if (inst.Rc) - ComputeRC(ibuild, val); + if (inst.Rc) + ComputeRC(ibuild, val); } void JitILBase::srwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); - IREmitter::InstLoc samt = ibuild.EmitLoadGReg(inst.RB); - IREmitter::InstLoc corr; + IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); + IREmitter::InstLoc samt = ibuild.EmitLoadGReg(inst.RB); + IREmitter::InstLoc corr; - // FIXME: We can do better with a cmov - // FIXME: We can do better on 64-bit - val = ibuild.EmitShrl(val, samt); - corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26)); - corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31)); - corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1)); - val = ibuild.EmitAnd(corr, val); - ibuild.EmitStoreGReg(val, inst.RA); + // FIXME: We can do better with a cmov + // FIXME: We can do better on 64-bit + val = ibuild.EmitShrl(val, samt); + corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26)); + corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31)); + corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1)); + val = ibuild.EmitAnd(corr, val); + ibuild.EmitStoreGReg(val, inst.RA); - if (inst.Rc) - ComputeRC(ibuild, val); + if (inst.Rc) + ComputeRC(ibuild, val); } void JitILBase::slwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); - IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); - IREmitter::InstLoc samt = ibuild.EmitLoadGReg(inst.RB); - IREmitter::InstLoc corr; + IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); + IREmitter::InstLoc samt = ibuild.EmitLoadGReg(inst.RB); + IREmitter::InstLoc corr; - // FIXME: We can do better with a cmov - // FIXME: We can do better on 64-bit - val = ibuild.EmitShl(val, samt); - corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26)); - corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31)); - corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1)); - val = ibuild.EmitAnd(corr, val); - ibuild.EmitStoreGReg(val, inst.RA); + // FIXME: We can do better with a cmov + // FIXME: We can do better on 64-bit + val = ibuild.EmitShl(val, samt); + corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26)); + corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31)); + corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1)); + val = ibuild.EmitAnd(corr, val); + ibuild.EmitStoreGReg(val, inst.RA); - if (inst.Rc) - ComputeRC(ibuild, val); + if (inst.Rc) + ComputeRC(ibuild, val); } void JitILBase::srawx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - // FIXME: We can do a lot better on 64-bit - IREmitter::InstLoc val, samt, mask, mask2, test; - val = ibuild.EmitLoadGReg(inst.RS); - samt = ibuild.EmitLoadGReg(inst.RB); - mask = ibuild.EmitIntConst(-1); - val = ibuild.EmitSarl(val, samt); - mask = ibuild.EmitShl(mask, samt); - samt = ibuild.EmitShl(samt, ibuild.EmitIntConst(26)); - samt = ibuild.EmitSarl(samt, ibuild.EmitIntConst(31)); - samt = ibuild.EmitAnd(samt, ibuild.EmitIntConst(31)); - val = ibuild.EmitSarl(val, samt); - ibuild.EmitStoreGReg(val, inst.RA); - mask = ibuild.EmitShl(mask, samt); - mask2 = ibuild.EmitAnd(mask, ibuild.EmitIntConst(0x7FFFFFFF)); - test = ibuild.EmitOr(val, mask2); - test = ibuild.EmitICmpUgt(test, mask); - ibuild.EmitStoreCarry(test); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + // FIXME: We can do a lot better on 64-bit + IREmitter::InstLoc val, samt, mask, mask2, test; + val = ibuild.EmitLoadGReg(inst.RS); + samt = ibuild.EmitLoadGReg(inst.RB); + mask = ibuild.EmitIntConst(-1); + val = ibuild.EmitSarl(val, samt); + mask = ibuild.EmitShl(mask, samt); + samt = ibuild.EmitShl(samt, ibuild.EmitIntConst(26)); + samt = ibuild.EmitSarl(samt, ibuild.EmitIntConst(31)); + samt = ibuild.EmitAnd(samt, ibuild.EmitIntConst(31)); + val = ibuild.EmitSarl(val, samt); + ibuild.EmitStoreGReg(val, inst.RA); + mask = ibuild.EmitShl(mask, samt); + mask2 = ibuild.EmitAnd(mask, ibuild.EmitIntConst(0x7FFFFFFF)); + test = ibuild.EmitOr(val, mask2); + test = ibuild.EmitICmpUgt(test, mask); + ibuild.EmitStoreCarry(test); - if (inst.Rc) - ComputeRC(ibuild, val); + if (inst.Rc) + ComputeRC(ibuild, val); } void JitILBase::srawix(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - // Shift right by two - IREmitter::InstLoc input = ibuild.EmitLoadGReg(inst.RS); - IREmitter::InstLoc output = ibuild.EmitSarl(input, ibuild.EmitIntConst(inst.SH)); - ibuild.EmitStoreGReg(output, inst.RA); - // Check whether the input is negative and any bits got shifted out. - unsigned int mask = -1u << inst.SH; - IREmitter::InstLoc test = ibuild.EmitOr(input, ibuild.EmitIntConst(mask & 0x7FFFFFFF)); - test = ibuild.EmitICmpUgt(test, ibuild.EmitIntConst(mask)); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + // Shift right by two + IREmitter::InstLoc input = ibuild.EmitLoadGReg(inst.RS); + IREmitter::InstLoc output = ibuild.EmitSarl(input, ibuild.EmitIntConst(inst.SH)); + ibuild.EmitStoreGReg(output, inst.RA); + // Check whether the input is negative and any bits got shifted out. + unsigned int mask = -1u << inst.SH; + IREmitter::InstLoc test = ibuild.EmitOr(input, ibuild.EmitIntConst(mask & 0x7FFFFFFF)); + test = ibuild.EmitICmpUgt(test, ibuild.EmitIntConst(mask)); - ibuild.EmitStoreCarry(test); - if (inst.Rc) - ComputeRC(ibuild, output); + ibuild.EmitStoreCarry(test); + if (inst.Rc) + ComputeRC(ibuild, output); } // count leading zeroes void JitILBase::cntlzwx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); - val = ibuild.EmitCntlzw(val); - ibuild.EmitStoreGReg(val, inst.RA); + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS); + val = ibuild.EmitCntlzw(val); + ibuild.EmitStoreGReg(val, inst.RA); - if (inst.Rc) - ComputeRC(ibuild, val); + if (inst.Rc) + ComputeRC(ibuild, val); } diff --git a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStore.cpp b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStore.cpp index 42aa779724..c698a6ae00 100644 --- a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStore.cpp @@ -2,190 +2,190 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/JitILCommon/JitILBase.h" #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Core/ConfigManager.h" #include "Core/HW/CPU.h" #include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/JitILCommon/JitILBase.h" void JitILBase::lhax(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB); - if (inst.RA) - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB); + if (inst.RA) + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - IREmitter::InstLoc val = ibuild.EmitLoad16(addr); - val = ibuild.EmitSExt16(val); - ibuild.EmitStoreGReg(val, inst.RD); + IREmitter::InstLoc val = ibuild.EmitLoad16(addr); + val = ibuild.EmitSExt16(val); + ibuild.EmitStoreGReg(val, inst.RD); } void JitILBase::lhaux(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB); - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB); + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - IREmitter::InstLoc val = ibuild.EmitLoad16(addr); - val = ibuild.EmitSExt16(val); - ibuild.EmitStoreGReg(val, inst.RD); - ibuild.EmitStoreGReg(addr, inst.RA); + IREmitter::InstLoc val = ibuild.EmitLoad16(addr); + val = ibuild.EmitSExt16(val); + ibuild.EmitStoreGReg(val, inst.RD); + ibuild.EmitStoreGReg(addr, inst.RA); } void JitILBase::lXz(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); - if (inst.RA) - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - if (inst.OPCD & 1) - ibuild.EmitStoreGReg(addr, inst.RA); + IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); + if (inst.RA) + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + if (inst.OPCD & 1) + ibuild.EmitStoreGReg(addr, inst.RA); - IREmitter::InstLoc val; + IREmitter::InstLoc val; - // Idle Skipping. - // TODO: This really should be done somewhere else. Either lower in the IR - // or higher in PPCAnalyst - // TODO: We shouldn't use debug reads here. - if (SConfig::GetInstance().bSkipIdle && - CPU::GetState() != CPU::CPU_STEPPING && - inst.OPCD == 32 && // Lwx - (inst.hex & 0xFFFF0000) == 0x800D0000 && - (PowerPC::HostRead_U32(js.compilerPC + 4) == 0x28000000 || - (SConfig::GetInstance().bWii && PowerPC::HostRead_U32(js.compilerPC + 4) == 0x2C000000)) && - PowerPC::HostRead_U32(js.compilerPC + 8) == 0x4182fff8) - { - val = ibuild.EmitLoad32(addr); - ibuild.EmitIdleBranch(val, ibuild.EmitIntConst(js.compilerPC)); - ibuild.EmitStoreGReg(val, inst.RD); - return; - } + // Idle Skipping. + // TODO: This really should be done somewhere else. Either lower in the IR + // or higher in PPCAnalyst + // TODO: We shouldn't use debug reads here. + if (SConfig::GetInstance().bSkipIdle && CPU::GetState() != CPU::CPU_STEPPING && + inst.OPCD == 32 && // Lwx + (inst.hex & 0xFFFF0000) == 0x800D0000 && + (PowerPC::HostRead_U32(js.compilerPC + 4) == 0x28000000 || + (SConfig::GetInstance().bWii && PowerPC::HostRead_U32(js.compilerPC + 4) == 0x2C000000)) && + PowerPC::HostRead_U32(js.compilerPC + 8) == 0x4182fff8) + { + val = ibuild.EmitLoad32(addr); + ibuild.EmitIdleBranch(val, ibuild.EmitIntConst(js.compilerPC)); + ibuild.EmitStoreGReg(val, inst.RD); + return; + } - switch (inst.OPCD & ~0x1) - { - case 32: // lwz - val = ibuild.EmitLoad32(addr); - break; - case 40: // lhz - val = ibuild.EmitLoad16(addr); - break; - case 34: // lbz - val = ibuild.EmitLoad8(addr); - break; - default: - PanicAlert("lXz: invalid access size"); - val = nullptr; - break; - } + switch (inst.OPCD & ~0x1) + { + case 32: // lwz + val = ibuild.EmitLoad32(addr); + break; + case 40: // lhz + val = ibuild.EmitLoad16(addr); + break; + case 34: // lbz + val = ibuild.EmitLoad8(addr); + break; + default: + PanicAlert("lXz: invalid access size"); + val = nullptr; + break; + } - ibuild.EmitStoreGReg(val, inst.RD); + ibuild.EmitStoreGReg(val, inst.RD); } void JitILBase::lbzu(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - const IREmitter::InstLoc uAddress = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), ibuild.EmitIntConst((int)inst.SIMM_16)); - const IREmitter::InstLoc temp = ibuild.EmitLoad8(uAddress); - ibuild.EmitStoreGReg(temp, inst.RD); - ibuild.EmitStoreGReg(uAddress, inst.RA); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + const IREmitter::InstLoc uAddress = + ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), ibuild.EmitIntConst((int)inst.SIMM_16)); + const IREmitter::InstLoc temp = ibuild.EmitLoad8(uAddress); + ibuild.EmitStoreGReg(temp, inst.RD); + ibuild.EmitStoreGReg(uAddress, inst.RA); } void JitILBase::lha(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitIntConst((s32)(s16)inst.SIMM_16); + IREmitter::InstLoc addr = ibuild.EmitIntConst((s32)(s16)inst.SIMM_16); - if (inst.RA) - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + if (inst.RA) + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - IREmitter::InstLoc val = ibuild.EmitLoad16(addr); - val = ibuild.EmitSExt16(val); - ibuild.EmitStoreGReg(val, inst.RD); + IREmitter::InstLoc val = ibuild.EmitLoad16(addr); + val = ibuild.EmitSExt16(val); + ibuild.EmitStoreGReg(val, inst.RD); } void JitILBase::lhau(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitIntConst((s32)inst.SIMM_16); + IREmitter::InstLoc addr = ibuild.EmitIntConst((s32)inst.SIMM_16); - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - IREmitter::InstLoc val = ibuild.EmitLoad16(addr); - val = ibuild.EmitSExt16(val); - ibuild.EmitStoreGReg(val, inst.RD); - ibuild.EmitStoreGReg(addr, inst.RA); + IREmitter::InstLoc val = ibuild.EmitLoad16(addr); + val = ibuild.EmitSExt16(val); + ibuild.EmitStoreGReg(val, inst.RD); + ibuild.EmitStoreGReg(addr, inst.RA); } void JitILBase::lXzx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB); + IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB); - if (inst.RA) - { - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - if (inst.SUBOP10 & 32) - ibuild.EmitStoreGReg(addr, inst.RA); - } + if (inst.RA) + { + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + if (inst.SUBOP10 & 32) + ibuild.EmitStoreGReg(addr, inst.RA); + } - IREmitter::InstLoc val; - switch (inst.SUBOP10 & ~32) - { - default: - PanicAlert("lXzx: invalid access size"); - case 23: // lwzx - val = ibuild.EmitLoad32(addr); - break; - case 279: // lhzx - val = ibuild.EmitLoad16(addr); - break; - case 87: // lbzx - val = ibuild.EmitLoad8(addr); - break; - } - ibuild.EmitStoreGReg(val, inst.RD); + IREmitter::InstLoc val; + switch (inst.SUBOP10 & ~32) + { + default: + PanicAlert("lXzx: invalid access size"); + case 23: // lwzx + val = ibuild.EmitLoad32(addr); + break; + case 279: // lhzx + val = ibuild.EmitLoad16(addr); + break; + case 87: // lbzx + val = ibuild.EmitLoad8(addr); + break; + } + ibuild.EmitStoreGReg(val, inst.RD); } void JitILBase::dcbst(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); - // If the dcbst instruction is preceded by dcbt, it is flushing a prefetched - // memory location. Do not invalidate the JIT cache in this case as the memory - // will be the same. - // dcbt = 0x7c00022c - // TODO: We shouldn't use a debug read here; it should be possible to get the - // previous instruction from the JIT state. - FALLBACK_IF((PowerPC::HostRead_U32(js.compilerPC - 4) & 0x7c00022c) != 0x7c00022c); + // If the dcbst instruction is preceded by dcbt, it is flushing a prefetched + // memory location. Do not invalidate the JIT cache in this case as the memory + // will be the same. + // dcbt = 0x7c00022c + // TODO: We shouldn't use a debug read here; it should be possible to get the + // previous instruction from the JIT state. + FALLBACK_IF((PowerPC::HostRead_U32(js.compilerPC - 4) & 0x7c00022c) != 0x7c00022c); } // Zero cache line. void JitILBase::dcbz(UGeckoInstruction inst) { - FALLBACK_IF(true); + FALLBACK_IF(true); - // TODO! +// TODO! #if 0 if (SConfig::GetInstance().bJITOff || SConfig::GetInstance().bJITLoadStoreOff) { @@ -205,107 +205,107 @@ void JitILBase::dcbz(UGeckoInstruction inst) void JitILBase::stX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); - IREmitter::InstLoc value = ibuild.EmitLoadGReg(inst.RS); + IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); + IREmitter::InstLoc value = ibuild.EmitLoadGReg(inst.RS); - if (inst.RA) - addr = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), addr); - if (inst.OPCD & 1) - ibuild.EmitStoreGReg(addr, inst.RA); + if (inst.RA) + addr = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), addr); + if (inst.OPCD & 1) + ibuild.EmitStoreGReg(addr, inst.RA); - switch (inst.OPCD & ~1) - { - case 36: // stw - ibuild.EmitStore32(value, addr); - break; - case 44: // sth - ibuild.EmitStore16(value, addr); - break; - case 38: // stb - ibuild.EmitStore8(value, addr); - break; - default: - _assert_msg_(DYNA_REC, 0, "stX: Invalid access size."); - return; - } + switch (inst.OPCD & ~1) + { + case 36: // stw + ibuild.EmitStore32(value, addr); + break; + case 44: // sth + ibuild.EmitStore16(value, addr); + break; + case 38: // stb + ibuild.EmitStore8(value, addr); + break; + default: + _assert_msg_(DYNA_REC, 0, "stX: Invalid access size."); + return; + } } void JitILBase::stXx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB); - IREmitter::InstLoc value = ibuild.EmitLoadGReg(inst.RS); + IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB); + IREmitter::InstLoc value = ibuild.EmitLoadGReg(inst.RS); - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - if (inst.SUBOP10 & 32) - ibuild.EmitStoreGReg(addr, inst.RA); + if (inst.SUBOP10 & 32) + ibuild.EmitStoreGReg(addr, inst.RA); - switch (inst.SUBOP10 & ~32) - { - case 151: // stw - ibuild.EmitStore32(value, addr); - break; - case 407: // sth - ibuild.EmitStore16(value, addr); - break; - case 215: // stb - ibuild.EmitStore8(value, addr); - break; - default: - _assert_msg_(DYNA_REC, 0, "stXx: Invalid store size."); - return; - } + switch (inst.SUBOP10 & ~32) + { + case 151: // stw + ibuild.EmitStore32(value, addr); + break; + case 407: // sth + ibuild.EmitStore16(value, addr); + break; + case 215: // stb + ibuild.EmitStore8(value, addr); + break; + default: + _assert_msg_(DYNA_REC, 0, "stXx: Invalid store size."); + return; + } } // A few games use these heavily in video codecs. (GFZP01 @ 0x80020E18) void JitILBase::lmw(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); + IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); - if (inst.RA) - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + if (inst.RA) + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - for (int i = inst.RD; i < 32; i++) - { - IREmitter::InstLoc val = ibuild.EmitLoad32(addr); - ibuild.EmitStoreGReg(val, i); - addr = ibuild.EmitAdd(addr, ibuild.EmitIntConst(4)); - } + for (int i = inst.RD; i < 32; i++) + { + IREmitter::InstLoc val = ibuild.EmitLoad32(addr); + ibuild.EmitStoreGReg(val, i); + addr = ibuild.EmitAdd(addr, ibuild.EmitIntConst(4)); + } } void JitILBase::stmw(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); + IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); - if (inst.RA) - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + if (inst.RA) + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - for (int i = inst.RD; i < 32; i++) - { - IREmitter::InstLoc val = ibuild.EmitLoadGReg(i); - ibuild.EmitStore32(val, addr); - addr = ibuild.EmitAdd(addr, ibuild.EmitIntConst(4)); - } + for (int i = inst.RD; i < 32; i++) + { + IREmitter::InstLoc val = ibuild.EmitLoadGReg(i); + ibuild.EmitStore32(val, addr); + addr = ibuild.EmitAdd(addr, ibuild.EmitIntConst(4)); + } } void JitILBase::icbi(UGeckoInstruction inst) { - FallBackToInterpreter(inst); - ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4)); + FallBackToInterpreter(inst); + ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4)); } diff --git a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStoreFloating.cpp b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStoreFloating.cpp index 65c5634d30..a9f84636b6 100644 --- a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStoreFloating.cpp +++ b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStoreFloating.cpp @@ -2,142 +2,139 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/JitILCommon/JitILBase.h" #include "Common/CommonTypes.h" #include "Core/ConfigManager.h" -#include "Core/PowerPC/JitILCommon/JitILBase.h" -// TODO: Add peephole optimizations for multiple consecutive lfd/lfs/stfd/stfs since they are so common, +// TODO: Add peephole optimizations for multiple consecutive lfd/lfs/stfd/stfs since they are so +// common, // and pshufb could help a lot. // Also add hacks for things like lfs/stfs the same reg consecutively, that is, simple memory moves. void JitILBase::lfs(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreFloatingOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreFloatingOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); + IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); - if (inst.RA) - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + if (inst.RA) + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - IREmitter::InstLoc val = ibuild.EmitDupSingleToMReg(ibuild.EmitLoadSingle(addr)); - ibuild.EmitStoreFReg(val, inst.FD); + IREmitter::InstLoc val = ibuild.EmitDupSingleToMReg(ibuild.EmitLoadSingle(addr)); + ibuild.EmitStoreFReg(val, inst.FD); } void JitILBase::lfsu(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreFloatingOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreFloatingOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); + IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - IREmitter::InstLoc val = ibuild.EmitDupSingleToMReg(ibuild.EmitLoadSingle(addr)); - ibuild.EmitStoreFReg(val, inst.FD); - ibuild.EmitStoreGReg(addr, inst.RA); + IREmitter::InstLoc val = ibuild.EmitDupSingleToMReg(ibuild.EmitLoadSingle(addr)); + ibuild.EmitStoreFReg(val, inst.FD); + ibuild.EmitStoreGReg(addr, inst.RA); } void JitILBase::lfd(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreFloatingOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreFloatingOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); + IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); - if (inst.RA) - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + if (inst.RA) + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.RD); - val = ibuild.EmitInsertDoubleInMReg(ibuild.EmitLoadDouble(addr), val); - ibuild.EmitStoreFReg(val, inst.RD); + IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.RD); + val = ibuild.EmitInsertDoubleInMReg(ibuild.EmitLoadDouble(addr), val); + ibuild.EmitStoreFReg(val, inst.RD); } void JitILBase::lfdu(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreFloatingOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreFloatingOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); + IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FD); - val = ibuild.EmitInsertDoubleInMReg(ibuild.EmitLoadDouble(addr), val); - ibuild.EmitStoreFReg(val, inst.FD); - ibuild.EmitStoreGReg(addr, inst.RA); + IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FD); + val = ibuild.EmitInsertDoubleInMReg(ibuild.EmitLoadDouble(addr), val); + ibuild.EmitStoreFReg(val, inst.FD); + ibuild.EmitStoreGReg(addr, inst.RA); } void JitILBase::stfd(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreFloatingOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreFloatingOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); - IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.RS); + IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); + IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.RS); - if (inst.RA) - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - if (inst.OPCD & 1) - ibuild.EmitStoreGReg(addr, inst.RA); + if (inst.RA) + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + if (inst.OPCD & 1) + ibuild.EmitStoreGReg(addr, inst.RA); - ibuild.EmitStoreDouble(val, addr); + ibuild.EmitStoreDouble(val, addr); } - void JitILBase::stfs(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreFloatingOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreFloatingOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); - IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.RS); + IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); + IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.RS); - if (inst.RA) - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - if (inst.OPCD & 1) - ibuild.EmitStoreGReg(addr, inst.RA); + if (inst.RA) + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + if (inst.OPCD & 1) + ibuild.EmitStoreGReg(addr, inst.RA); - val = ibuild.EmitDoubleToSingle(val); - ibuild.EmitStoreSingle(val, addr); + val = ibuild.EmitDoubleToSingle(val); + ibuild.EmitStoreSingle(val, addr); } - void JitILBase::stfsx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreFloatingOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreFloatingOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB); - IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.RS); + IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB); + IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.RS); - if (inst.RA) - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + if (inst.RA) + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - val = ibuild.EmitDoubleToSingle(val); - ibuild.EmitStoreSingle(val, addr); + val = ibuild.EmitDoubleToSingle(val); + ibuild.EmitStoreSingle(val, addr); } - void JitILBase::lfsx(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStoreFloatingOff); - FALLBACK_IF(jo.memcheck); + INSTRUCTION_START + JITDISABLE(bJITLoadStoreFloatingOff); + FALLBACK_IF(jo.memcheck); - IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB), val; + IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB), val; - if (inst.RA) - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + if (inst.RA) + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - val = ibuild.EmitDupSingleToMReg(ibuild.EmitLoadSingle(addr)); - ibuild.EmitStoreFReg(val, inst.RD); + val = ibuild.EmitDupSingleToMReg(ibuild.EmitLoadSingle(addr)); + ibuild.EmitStoreFReg(val, inst.RD); } - diff --git a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStorePaired.cpp b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStorePaired.cpp index 4e33912510..a0a048c9bf 100644 --- a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStorePaired.cpp +++ b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_LoadStorePaired.cpp @@ -2,46 +2,48 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/JitILCommon/JitILBase.h" #include "Common/CommonTypes.h" #include "Core/ConfigManager.h" -#include "Core/PowerPC/JitILCommon/JitILBase.h" void JitILBase::psq_st(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStorePairedOff); - FALLBACK_IF(jo.memcheck || inst.W); + INSTRUCTION_START + JITDISABLE(bJITLoadStorePairedOff); + FALLBACK_IF(jo.memcheck || inst.W); - IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_12); - IREmitter::InstLoc val; + IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_12); + IREmitter::InstLoc val; - if (inst.RA) - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + if (inst.RA) + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - if (inst.OPCD == 61) - ibuild.EmitStoreGReg(addr, inst.RA); + if (inst.OPCD == 61) + ibuild.EmitStoreGReg(addr, inst.RA); - val = ibuild.EmitLoadFReg(inst.RS); - val = ibuild.EmitCompactMRegToPacked(val); - ibuild.EmitStorePaired(val, addr, inst.I); + val = ibuild.EmitLoadFReg(inst.RS); + val = ibuild.EmitCompactMRegToPacked(val); + ibuild.EmitStorePaired(val, addr, inst.I); } void JitILBase::psq_l(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITLoadStorePairedOff); - FALLBACK_IF(jo.memcheck || inst.W); + INSTRUCTION_START + JITDISABLE(bJITLoadStorePairedOff); + FALLBACK_IF(jo.memcheck || inst.W); - IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_12); - IREmitter::InstLoc val; + IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_12); + IREmitter::InstLoc val; - if (inst.RA) - addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); + if (inst.RA) + addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); - if (inst.OPCD == 57) - ibuild.EmitStoreGReg(addr, inst.RA); + if (inst.OPCD == 57) + ibuild.EmitStoreGReg(addr, inst.RA); - val = ibuild.EmitLoadPaired(addr, inst.I | (inst.W << 3)); // The lower 3 bits is for GQR index. The next 1 bit is for inst.W - val = ibuild.EmitExpandPackedToMReg(val); - ibuild.EmitStoreFReg(val, inst.RD); + val = ibuild.EmitLoadPaired( + addr, + inst.I | (inst.W << 3)); // The lower 3 bits is for GQR index. The next 1 bit is for inst.W + val = ibuild.EmitExpandPackedToMReg(val); + ibuild.EmitStoreFReg(val, inst.RD); } diff --git a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_Paired.cpp b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_Paired.cpp index d8817eb347..6bc44cbe68 100644 --- a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_Paired.cpp +++ b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_Paired.cpp @@ -2,189 +2,186 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/JitILCommon/JitILBase.h" #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Core/ConfigManager.h" -#include "Core/PowerPC/JitILCommon/JitILBase.h" void JitILBase::ps_arith(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITPairedOff); - FALLBACK_IF(inst.Rc || (inst.SUBOP5 != 21 && inst.SUBOP5 != 20 && inst.SUBOP5 != 25)); + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc || (inst.SUBOP5 != 21 && inst.SUBOP5 != 20 && inst.SUBOP5 != 25)); - IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA); - IREmitter::InstLoc rhs; + IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA); + IREmitter::InstLoc rhs; - if (inst.SUBOP5 == 25) - rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); - else - rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); + if (inst.SUBOP5 == 25) + rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); + else + rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); - val = ibuild.EmitCompactMRegToPacked(val); + val = ibuild.EmitCompactMRegToPacked(val); - switch (inst.SUBOP5) - { - case 20: - val = ibuild.EmitFPSub(val, rhs); - break; - case 21: - val = ibuild.EmitFPAdd(val, rhs); - break; - case 25: - val = ibuild.EmitFPMul(val, rhs); - } + switch (inst.SUBOP5) + { + case 20: + val = ibuild.EmitFPSub(val, rhs); + break; + case 21: + val = ibuild.EmitFPAdd(val, rhs); + break; + case 25: + val = ibuild.EmitFPMul(val, rhs); + } - val = ibuild.EmitExpandPackedToMReg(val); - ibuild.EmitStoreFReg(val, inst.FD); + val = ibuild.EmitExpandPackedToMReg(val); + ibuild.EmitStoreFReg(val, inst.FD); } void JitILBase::ps_sum(UGeckoInstruction inst) { - // TODO: This operation strikes me as a bit strange... - // perhaps we can optimize it depending on the users? - // TODO: ps_sum breaks Sonic Colours (black screen) - FALLBACK_IF(true); + // TODO: This operation strikes me as a bit strange... + // perhaps we can optimize it depending on the users? + // TODO: ps_sum breaks Sonic Colours (black screen) + FALLBACK_IF(true); - INSTRUCTION_START - JITDISABLE(bJITPairedOff); - FALLBACK_IF(inst.Rc || inst.SUBOP5 != 10); + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc || inst.SUBOP5 != 10); - IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA); - IREmitter::InstLoc temp; + IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA); + IREmitter::InstLoc temp; - val = ibuild.EmitCompactMRegToPacked(val); - val = ibuild.EmitFPDup0(val); - temp = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); - val = ibuild.EmitFPAdd(val, temp); - temp = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); - val = ibuild.EmitFPMerge11(val, temp); - val = ibuild.EmitExpandPackedToMReg(val); - ibuild.EmitStoreFReg(val, inst.FD); + val = ibuild.EmitCompactMRegToPacked(val); + val = ibuild.EmitFPDup0(val); + temp = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); + val = ibuild.EmitFPAdd(val, temp); + temp = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); + val = ibuild.EmitFPMerge11(val, temp); + val = ibuild.EmitExpandPackedToMReg(val); + ibuild.EmitStoreFReg(val, inst.FD); } - void JitILBase::ps_muls(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITPairedOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); - IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA); - IREmitter::InstLoc rhs = ibuild.EmitLoadFReg(inst.FC); + IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA); + IREmitter::InstLoc rhs = ibuild.EmitLoadFReg(inst.FC); - val = ibuild.EmitCompactMRegToPacked(val); - rhs = ibuild.EmitCompactMRegToPacked(rhs); + val = ibuild.EmitCompactMRegToPacked(val); + rhs = ibuild.EmitCompactMRegToPacked(rhs); - if (inst.SUBOP5 == 12) - rhs = ibuild.EmitFPDup0(rhs); - else - rhs = ibuild.EmitFPDup1(rhs); + if (inst.SUBOP5 == 12) + rhs = ibuild.EmitFPDup0(rhs); + else + rhs = ibuild.EmitFPDup1(rhs); - val = ibuild.EmitFPMul(val, rhs); - val = ibuild.EmitExpandPackedToMReg(val); - ibuild.EmitStoreFReg(val, inst.FD); + val = ibuild.EmitFPMul(val, rhs); + val = ibuild.EmitExpandPackedToMReg(val); + ibuild.EmitStoreFReg(val, inst.FD); } - -//TODO: find easy cases and optimize them, do a breakout like ps_arith +// TODO: find easy cases and optimize them, do a breakout like ps_arith void JitILBase::ps_mergeXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITPairedOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); - IREmitter::InstLoc val = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FA)); - IREmitter::InstLoc rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); + IREmitter::InstLoc val = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FA)); + IREmitter::InstLoc rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); - switch (inst.SUBOP10) - { - case 528: - val = ibuild.EmitFPMerge00(val, rhs); - break; //00 - case 560: - val = ibuild.EmitFPMerge01(val, rhs); - break; //01 - case 592: - val = ibuild.EmitFPMerge10(val, rhs); - break; //10 - case 624: - val = ibuild.EmitFPMerge11(val, rhs); - break; //11 - default: - _assert_msg_(DYNA_REC, 0, "ps_merge - invalid op"); - } + switch (inst.SUBOP10) + { + case 528: + val = ibuild.EmitFPMerge00(val, rhs); + break; // 00 + case 560: + val = ibuild.EmitFPMerge01(val, rhs); + break; // 01 + case 592: + val = ibuild.EmitFPMerge10(val, rhs); + break; // 10 + case 624: + val = ibuild.EmitFPMerge11(val, rhs); + break; // 11 + default: + _assert_msg_(DYNA_REC, 0, "ps_merge - invalid op"); + } - val = ibuild.EmitExpandPackedToMReg(val); - ibuild.EmitStoreFReg(val, inst.FD); + val = ibuild.EmitExpandPackedToMReg(val); + ibuild.EmitStoreFReg(val, inst.FD); } - void JitILBase::ps_maddXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITPairedOff); - FALLBACK_IF(inst.Rc); + INSTRUCTION_START + JITDISABLE(bJITPairedOff); + FALLBACK_IF(inst.Rc); - IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), op2, op3; - val = ibuild.EmitCompactMRegToPacked(val); + IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), op2, op3; + val = ibuild.EmitCompactMRegToPacked(val); - switch (inst.SUBOP5) - { - case 14: // madds0 - { - op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); - op2 = ibuild.EmitFPDup0(op2); - val = ibuild.EmitFPMul(val, op2); - op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); - val = ibuild.EmitFPAdd(val, op3); - break; - } - case 15: // madds1 - { - op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); - op2 = ibuild.EmitFPDup1(op2); - val = ibuild.EmitFPMul(val, op2); - op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); - val = ibuild.EmitFPAdd(val, op3); - break; - } - case 28: // msub - { - op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); - val = ibuild.EmitFPMul(val, op2); - op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); - val = ibuild.EmitFPSub(val, op3); - break; - } - case 29: // madd - { - op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); - val = ibuild.EmitFPMul(val, op2); - op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); - val = ibuild.EmitFPAdd(val, op3); - break; - } - case 30: // nmsub - { - op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); - val = ibuild.EmitFPMul(val, op2); - op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); - val = ibuild.EmitFPSub(val, op3); - val = ibuild.EmitFPNeg(val); - break; - } - case 31: // nmadd - { - op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); - val = ibuild.EmitFPMul(val, op2); - op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); - val = ibuild.EmitFPAdd(val, op3); - val = ibuild.EmitFPNeg(val); - break; - } - } + switch (inst.SUBOP5) + { + case 14: // madds0 + { + op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); + op2 = ibuild.EmitFPDup0(op2); + val = ibuild.EmitFPMul(val, op2); + op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); + val = ibuild.EmitFPAdd(val, op3); + break; + } + case 15: // madds1 + { + op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); + op2 = ibuild.EmitFPDup1(op2); + val = ibuild.EmitFPMul(val, op2); + op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); + val = ibuild.EmitFPAdd(val, op3); + break; + } + case 28: // msub + { + op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); + val = ibuild.EmitFPMul(val, op2); + op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); + val = ibuild.EmitFPSub(val, op3); + break; + } + case 29: // madd + { + op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); + val = ibuild.EmitFPMul(val, op2); + op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); + val = ibuild.EmitFPAdd(val, op3); + break; + } + case 30: // nmsub + { + op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); + val = ibuild.EmitFPMul(val, op2); + op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); + val = ibuild.EmitFPSub(val, op3); + val = ibuild.EmitFPNeg(val); + break; + } + case 31: // nmadd + { + op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); + val = ibuild.EmitFPMul(val, op2); + op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); + val = ibuild.EmitFPAdd(val, op3); + val = ibuild.EmitFPNeg(val); + break; + } + } - val = ibuild.EmitExpandPackedToMReg(val); - ibuild.EmitStoreFReg(val, inst.FD); + val = ibuild.EmitExpandPackedToMReg(val); + ibuild.EmitStoreFReg(val, inst.FD); } diff --git a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_SystemRegisters.cpp index e30a500111..3cdb8bc7b3 100644 --- a/Source/Core/Core/PowerPC/JitILCommon/JitILBase_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/JitILCommon/JitILBase_SystemRegisters.cpp @@ -2,217 +2,215 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/JitILCommon/JitILBase.h" #include "Common/CommonTypes.h" #include "Common/MsgHandler.h" #include "Core/ConfigManager.h" -#include "Core/PowerPC/JitILCommon/JitILBase.h" void JitILBase::mtspr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); - switch (iIndex) - { - case SPR_TL: - case SPR_TU: - FALLBACK_IF(true); - case SPR_LR: - ibuild.EmitStoreLink(ibuild.EmitLoadGReg(inst.RD)); - return; - case SPR_CTR: - ibuild.EmitStoreCTR(ibuild.EmitLoadGReg(inst.RD)); - return; - case SPR_GQR0: - case SPR_GQR0 + 1: - case SPR_GQR0 + 2: - case SPR_GQR0 + 3: - case SPR_GQR0 + 4: - case SPR_GQR0 + 5: - case SPR_GQR0 + 6: - case SPR_GQR0 + 7: - ibuild.EmitStoreGQR(ibuild.EmitLoadGReg(inst.RD), iIndex - SPR_GQR0); - return; - case SPR_SRR0: - case SPR_SRR1: - ibuild.EmitStoreSRR(ibuild.EmitLoadGReg(inst.RD), iIndex - SPR_SRR0); - return; - default: - FALLBACK_IF(true); - } + switch (iIndex) + { + case SPR_TL: + case SPR_TU: + FALLBACK_IF(true); + case SPR_LR: + ibuild.EmitStoreLink(ibuild.EmitLoadGReg(inst.RD)); + return; + case SPR_CTR: + ibuild.EmitStoreCTR(ibuild.EmitLoadGReg(inst.RD)); + return; + case SPR_GQR0: + case SPR_GQR0 + 1: + case SPR_GQR0 + 2: + case SPR_GQR0 + 3: + case SPR_GQR0 + 4: + case SPR_GQR0 + 5: + case SPR_GQR0 + 6: + case SPR_GQR0 + 7: + ibuild.EmitStoreGQR(ibuild.EmitLoadGReg(inst.RD), iIndex - SPR_GQR0); + return; + case SPR_SRR0: + case SPR_SRR1: + ibuild.EmitStoreSRR(ibuild.EmitLoadGReg(inst.RD), iIndex - SPR_SRR0); + return; + default: + FALLBACK_IF(true); + } } void JitILBase::mfspr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); - switch (iIndex) - { - case SPR_TL: - case SPR_TU: - FALLBACK_IF(true); - case SPR_LR: - ibuild.EmitStoreGReg(ibuild.EmitLoadLink(), inst.RD); - return; - case SPR_CTR: - ibuild.EmitStoreGReg(ibuild.EmitLoadCTR(), inst.RD); - return; - case SPR_GQR0: - case SPR_GQR0 + 1: - case SPR_GQR0 + 2: - case SPR_GQR0 + 3: - case SPR_GQR0 + 4: - case SPR_GQR0 + 5: - case SPR_GQR0 + 6: - case SPR_GQR0 + 7: - ibuild.EmitStoreGReg(ibuild.EmitLoadGQR(iIndex - SPR_GQR0), inst.RD); - return; - default: - FALLBACK_IF(true); - } + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); + switch (iIndex) + { + case SPR_TL: + case SPR_TU: + FALLBACK_IF(true); + case SPR_LR: + ibuild.EmitStoreGReg(ibuild.EmitLoadLink(), inst.RD); + return; + case SPR_CTR: + ibuild.EmitStoreGReg(ibuild.EmitLoadCTR(), inst.RD); + return; + case SPR_GQR0: + case SPR_GQR0 + 1: + case SPR_GQR0 + 2: + case SPR_GQR0 + 3: + case SPR_GQR0 + 4: + case SPR_GQR0 + 5: + case SPR_GQR0 + 6: + case SPR_GQR0 + 7: + ibuild.EmitStoreGReg(ibuild.EmitLoadGQR(iIndex - SPR_GQR0), inst.RD); + return; + default: + FALLBACK_IF(true); + } } - // ======================================================================================= // Don't interpret this, if we do we get thrown out // -------------- void JitILBase::mtmsr(UGeckoInstruction inst) { - ibuild.EmitStoreMSR(ibuild.EmitLoadGReg(inst.RS), ibuild.EmitIntConst(js.compilerPC)); - ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4)); + ibuild.EmitStoreMSR(ibuild.EmitLoadGReg(inst.RS), ibuild.EmitIntConst(js.compilerPC)); + ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4)); } // ============== - void JitILBase::mfmsr(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); - ibuild.EmitStoreGReg(ibuild.EmitLoadMSR(), inst.RD); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + ibuild.EmitStoreGReg(ibuild.EmitLoadMSR(), inst.RD); } void JitILBase::mftb(UGeckoInstruction inst) { - INSTRUCTION_START; - JITDISABLE(bJITSystemRegistersOff); - mfspr(inst); + INSTRUCTION_START; + JITDISABLE(bJITSystemRegistersOff); + mfspr(inst); } void JitILBase::mfcr(UGeckoInstruction inst) { - INSTRUCTION_START; - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START; + JITDISABLE(bJITSystemRegistersOff); - IREmitter::InstLoc d = ibuild.EmitIntConst(0); - for (int i = 0; i < 8; ++i) - { - IREmitter::InstLoc cr = ibuild.EmitLoadCR(i); - cr = ibuild.EmitConvertFromFastCR(cr); - cr = ibuild.EmitShl(cr, ibuild.EmitIntConst(28 - 4 * i)); - d = ibuild.EmitOr(d, cr); - } - ibuild.EmitStoreGReg(d, inst.RD); + IREmitter::InstLoc d = ibuild.EmitIntConst(0); + for (int i = 0; i < 8; ++i) + { + IREmitter::InstLoc cr = ibuild.EmitLoadCR(i); + cr = ibuild.EmitConvertFromFastCR(cr); + cr = ibuild.EmitShl(cr, ibuild.EmitIntConst(28 - 4 * i)); + d = ibuild.EmitOr(d, cr); + } + ibuild.EmitStoreGReg(d, inst.RD); } void JitILBase::mtcrf(UGeckoInstruction inst) { - INSTRUCTION_START; - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START; + JITDISABLE(bJITSystemRegistersOff); - IREmitter::InstLoc s = ibuild.EmitLoadGReg(inst.RS); - for (int i = 0; i < 8; ++i) - { - if (inst.CRM & (0x80 >> i)) - { - IREmitter::InstLoc value; - value = ibuild.EmitShrl(s, ibuild.EmitIntConst(28 - i * 4)); - value = ibuild.EmitAnd(value, ibuild.EmitIntConst(0xF)); - value = ibuild.EmitConvertToFastCR(value); - ibuild.EmitStoreCR(value, i); - } - } + IREmitter::InstLoc s = ibuild.EmitLoadGReg(inst.RS); + for (int i = 0; i < 8; ++i) + { + if (inst.CRM & (0x80 >> i)) + { + IREmitter::InstLoc value; + value = ibuild.EmitShrl(s, ibuild.EmitIntConst(28 - i * 4)); + value = ibuild.EmitAnd(value, ibuild.EmitIntConst(0xF)); + value = ibuild.EmitConvertToFastCR(value); + ibuild.EmitStoreCR(value, i); + } + } } void JitILBase::mcrf(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - if (inst.CRFS != inst.CRFD) - { - ibuild.EmitStoreCR(ibuild.EmitLoadCR(inst.CRFS), inst.CRFD); - } + if (inst.CRFS != inst.CRFD) + { + ibuild.EmitStoreCR(ibuild.EmitLoadCR(inst.CRFS), inst.CRFD); + } } void JitILBase::crXX(UGeckoInstruction inst) { - INSTRUCTION_START - JITDISABLE(bJITSystemRegistersOff); + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); - // Get bit CRBA in EAX aligned with bit CRBD - const int shiftA = (inst.CRBD & 3) - (inst.CRBA & 3); - IREmitter::InstLoc eax = ibuild.EmitLoadCR(inst.CRBA >> 2); - eax = ibuild.EmitConvertFromFastCR(eax); - if (shiftA < 0) - eax = ibuild.EmitShl(eax, ibuild.EmitIntConst(-shiftA)); - else if (shiftA > 0) - eax = ibuild.EmitShrl(eax, ibuild.EmitIntConst(shiftA)); + // Get bit CRBA in EAX aligned with bit CRBD + const int shiftA = (inst.CRBD & 3) - (inst.CRBA & 3); + IREmitter::InstLoc eax = ibuild.EmitLoadCR(inst.CRBA >> 2); + eax = ibuild.EmitConvertFromFastCR(eax); + if (shiftA < 0) + eax = ibuild.EmitShl(eax, ibuild.EmitIntConst(-shiftA)); + else if (shiftA > 0) + eax = ibuild.EmitShrl(eax, ibuild.EmitIntConst(shiftA)); - // Get bit CRBB in ECX aligned with bit CRBD - const int shiftB = (inst.CRBD & 3) - (inst.CRBB & 3); - IREmitter::InstLoc ecx = ibuild.EmitLoadCR(inst.CRBB >> 2); - ecx = ibuild.EmitConvertFromFastCR(ecx); - if (shiftB < 0) - ecx = ibuild.EmitShl(ecx, ibuild.EmitIntConst(-shiftB)); - else if (shiftB > 0) - ecx = ibuild.EmitShrl(ecx, ibuild.EmitIntConst(shiftB)); + // Get bit CRBB in ECX aligned with bit CRBD + const int shiftB = (inst.CRBD & 3) - (inst.CRBB & 3); + IREmitter::InstLoc ecx = ibuild.EmitLoadCR(inst.CRBB >> 2); + ecx = ibuild.EmitConvertFromFastCR(ecx); + if (shiftB < 0) + ecx = ibuild.EmitShl(ecx, ibuild.EmitIntConst(-shiftB)); + else if (shiftB > 0) + ecx = ibuild.EmitShrl(ecx, ibuild.EmitIntConst(shiftB)); - // Compute combined bit - const unsigned subop = inst.SUBOP10; - switch (subop) - { - case 257: // crand - eax = ibuild.EmitAnd(eax, ecx); - break; - case 129: // crandc - ecx = ibuild.EmitNot(ecx); - eax = ibuild.EmitAnd(eax, ecx); - break; - case 289: // creqv - eax = ibuild.EmitXor(eax, ecx); - eax = ibuild.EmitNot(eax); - break; - case 225: // crnand - eax = ibuild.EmitAnd(eax, ecx); - eax = ibuild.EmitNot(eax); - break; - case 33: // crnor - eax = ibuild.EmitOr(eax, ecx); - eax = ibuild.EmitNot(eax); - break; - case 449: // cror - eax = ibuild.EmitOr(eax, ecx); - break; - case 417: // crorc - ecx = ibuild.EmitNot(ecx); - eax = ibuild.EmitOr(eax, ecx); - break; - case 193: // crxor - eax = ibuild.EmitXor(eax, ecx); - break; - default: - PanicAlert("crXX: invalid instruction"); - break; - } + // Compute combined bit + const unsigned subop = inst.SUBOP10; + switch (subop) + { + case 257: // crand + eax = ibuild.EmitAnd(eax, ecx); + break; + case 129: // crandc + ecx = ibuild.EmitNot(ecx); + eax = ibuild.EmitAnd(eax, ecx); + break; + case 289: // creqv + eax = ibuild.EmitXor(eax, ecx); + eax = ibuild.EmitNot(eax); + break; + case 225: // crnand + eax = ibuild.EmitAnd(eax, ecx); + eax = ibuild.EmitNot(eax); + break; + case 33: // crnor + eax = ibuild.EmitOr(eax, ecx); + eax = ibuild.EmitNot(eax); + break; + case 449: // cror + eax = ibuild.EmitOr(eax, ecx); + break; + case 417: // crorc + ecx = ibuild.EmitNot(ecx); + eax = ibuild.EmitOr(eax, ecx); + break; + case 193: // crxor + eax = ibuild.EmitXor(eax, ecx); + break; + default: + PanicAlert("crXX: invalid instruction"); + break; + } - // Store result bit in CRBD - eax = ibuild.EmitAnd(eax, ibuild.EmitIntConst(0x8 >> (inst.CRBD & 3))); - IREmitter::InstLoc bd = ibuild.EmitLoadCR(inst.CRBD >> 2); - bd = ibuild.EmitConvertFromFastCR(bd); - bd = ibuild.EmitAnd(bd, ibuild.EmitIntConst(~(0x8 >> (inst.CRBD & 3)))); - bd = ibuild.EmitOr(bd, eax); - bd = ibuild.EmitConvertToFastCR(bd); - ibuild.EmitStoreCR(bd, inst.CRBD >> 2); + // Store result bit in CRBD + eax = ibuild.EmitAnd(eax, ibuild.EmitIntConst(0x8 >> (inst.CRBD & 3))); + IREmitter::InstLoc bd = ibuild.EmitLoadCR(inst.CRBD >> 2); + bd = ibuild.EmitConvertFromFastCR(bd); + bd = ibuild.EmitAnd(bd, ibuild.EmitIntConst(~(0x8 >> (inst.CRBD & 3)))); + bd = ibuild.EmitOr(bd, eax); + bd = ibuild.EmitConvertToFastCR(bd); + ibuild.EmitStoreCR(bd, inst.CRBD >> 2); } diff --git a/Source/Core/Core/PowerPC/JitInterface.cpp b/Source/Core/Core/PowerPC/JitInterface.cpp index 7f161b5499..000cde0be0 100644 --- a/Source/Core/Core/PowerPC/JitInterface.cpp +++ b/Source/Core/Core/PowerPC/JitInterface.cpp @@ -15,11 +15,11 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/PowerPC/CachedInterpreter.h" -#include "Core/PowerPC/JitInterface.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCSymbolDB.h" -#include "Core/PowerPC/Profiler.h" #include "Core/PowerPC/JitCommon/JitBase.h" +#include "Core/PowerPC/JitInterface.h" +#include "Core/PowerPC/PPCSymbolDB.h" +#include "Core/PowerPC/PowerPC.h" +#include "Core/PowerPC/Profiler.h" #if _M_X86 #include "Core/PowerPC/Jit64/Jit.h" @@ -37,258 +37,259 @@ static bool bFakeVMEM = false; namespace JitInterface { - void DoState(PointerWrap &p) - { - if (jit && p.GetMode() == PointerWrap::MODE_READ) - jit->ClearCache(); - } - CPUCoreBase *InitJitCore(int core) - { - bFakeVMEM = !SConfig::GetInstance().bMMU; - - CPUCoreBase *ptr = nullptr; - switch (core) - { - #if _M_X86 - case PowerPC::CORE_JIT64: - ptr = new Jit64(); - break; - case PowerPC::CORE_JITIL64: - ptr = new JitIL(); - break; - #endif - #if _M_ARM_64 - case PowerPC::CORE_JITARM64: - ptr = new JitArm64(); - break; - #endif - case PowerPC::CORE_CACHEDINTERPRETER: - ptr = new CachedInterpreter(); - break; - - default: - PanicAlert("Unrecognizable cpu_core: %d", core); - jit = nullptr; - return nullptr; - } - jit = static_cast(ptr); - jit->Init(); - return ptr; - } - void InitTables(int core) - { - switch (core) - { - #if _M_X86 - case PowerPC::CORE_JIT64: - Jit64Tables::InitTables(); - break; - case PowerPC::CORE_JITIL64: - JitILTables::InitTables(); - break; - #endif - #if _M_ARM_64 - case PowerPC::CORE_JITARM64: - JitArm64Tables::InitTables(); - break; - #endif - case PowerPC::CORE_CACHEDINTERPRETER: - // has no tables - break; - default: - PanicAlert("Unrecognizable cpu_core: %d", core); - break; - } - } - CPUCoreBase *GetCore() - { - return jit; - } - - void WriteProfileResults(const std::string& filename) - { - ProfileStats prof_stats; - GetProfileResults(&prof_stats); - - File::IOFile f(filename, "w"); - if (!f) - { - PanicAlert("Failed to open %s", filename.c_str()); - return; - } - fprintf(f.GetHandle(), "origAddr\tblkName\trunCount\tcost\ttimeCost\tpercent\ttimePercent\tOvAllinBlkTime(ms)\tblkCodeSize\n"); - for (auto& stat : prof_stats.block_stats) - { - std::string name = g_symbolDB.GetDescription(stat.addr); - double percent = 100.0 * (double)stat.cost / (double)prof_stats.cost_sum; - double timePercent = 100.0 * (double)stat.tick_counter / (double)prof_stats.timecost_sum; - fprintf(f.GetHandle(), "%08x\t%s\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%.2f\t%.2f\t%.2f\t%i\n", - stat.addr, name.c_str(), stat.run_count, stat.cost, - stat.tick_counter, percent, timePercent, - (double)stat.tick_counter*1000.0/(double)prof_stats.countsPerSec, stat.block_size); - } - } - - void GetProfileResults(ProfileStats* prof_stats) - { - // Can't really do this with no jit core available - if (!jit) - return; - - prof_stats->cost_sum = 0; - prof_stats->timecost_sum = 0; - prof_stats->block_stats.clear(); - prof_stats->block_stats.reserve(jit->GetBlockCache()->GetNumBlocks()); - - Core::EState old_state = Core::GetState(); - if (old_state == Core::CORE_RUN) - Core::SetState(Core::CORE_PAUSE); - - QueryPerformanceFrequency((LARGE_INTEGER*)&prof_stats->countsPerSec); - for (int i = 0; i < jit->GetBlockCache()->GetNumBlocks(); i++) - { - const JitBlock *block = jit->GetBlockCache()->GetBlock(i); - // Rough heuristic. Mem instructions should cost more. - u64 cost = block->originalSize * (block->runCount / 4); - u64 timecost = block->ticCounter; - // Todo: tweak. - if (block->runCount >= 1) - prof_stats->block_stats.emplace_back(i, block->originalAddress, - cost, timecost, - block->runCount, block->codeSize); - prof_stats->cost_sum += cost; - prof_stats->timecost_sum += timecost; - } - - sort(prof_stats->block_stats.begin(), prof_stats->block_stats.end()); - if (old_state == Core::CORE_RUN) - Core::SetState(Core::CORE_RUN); - } - - int GetHostCode(u32* address, const u8** code, u32* code_size) - { - if (!jit) - { - *code_size = 0; - return 1; - } - - int block_num = jit->GetBlockCache()->GetBlockNumberFromStartAddress(*address); - if (block_num < 0) - { - for (int i = 0; i < 500; i++) - { - block_num = jit->GetBlockCache()->GetBlockNumberFromStartAddress(*address - 4 * i); - if (block_num >= 0) - break; - } - - if (block_num >= 0) - { - JitBlock* block = jit->GetBlockCache()->GetBlock(block_num); - if (!(block->originalAddress <= *address && - block->originalSize + block->originalAddress >= *address)) - block_num = -1; - } - - // Do not merge this "if" with the above - block_num changes inside it. - if (block_num < 0) - { - *code_size = 0; - return 2; - } - } - - JitBlock* block = jit->GetBlockCache()->GetBlock(block_num); - - *code = block->checkedEntry; - *code_size = block->codeSize; - *address = block->originalAddress; - return 0; - } - - bool HandleFault(uintptr_t access_address, SContext* ctx) - { - // Prevent nullptr dereference on a crash with no JIT present - if (!jit) - { - return false; - } - - return jit->HandleFault(access_address, ctx); - } - - bool HandleStackFault() - { - if (!jit) - { - return false; - } - - return jit->HandleStackFault(); - } - - void ClearCache() - { - if (jit) - jit->ClearCache(); - } - void ClearSafe() - { - // This clear is "safe" in the sense that it's okay to run from - // inside a JIT'ed block: it clears the instruction cache, but not - // the JIT'ed code. - // TODO: There's probably a better way to handle this situation. - if (jit) - jit->GetBlockCache()->Clear(); - } - - void InvalidateICache(u32 address, u32 size, bool forced) - { - if (jit) - jit->GetBlockCache()->InvalidateICache(address, size, forced); - } - - void CompileExceptionCheck(ExceptionType type) - { - if (!jit) - return; - - std::unordered_set* exception_addresses = nullptr; - - switch (type) - { - case ExceptionType::EXCEPTIONS_FIFO_WRITE: - exception_addresses = &jit->js.fifoWriteAddresses; - break; - case ExceptionType::EXCEPTIONS_PAIRED_QUANTIZE: - exception_addresses = &jit->js.pairedQuantizeAddresses; - break; - } - - if (PC != 0 && (exception_addresses->find(PC)) == (exception_addresses->end())) - { - if (type == ExceptionType::EXCEPTIONS_FIFO_WRITE) - { - // Check in case the code has been replaced since: do we need to do this? - int optype = GetOpInfo(PowerPC::HostRead_U32(PC))->type; - if (optype != OPTYPE_STORE && optype != OPTYPE_STOREFP && (optype != OPTYPE_STOREPS)) - return; - } - exception_addresses->insert(PC); - - // Invalidate the JIT block so that it gets recompiled with the external exception check included. - jit->GetBlockCache()->InvalidateICache(PC, 4, true); - } - } - - void Shutdown() - { - if (jit) - { - jit->Shutdown(); - delete jit; - jit = nullptr; - } - } +void DoState(PointerWrap& p) +{ + if (jit && p.GetMode() == PointerWrap::MODE_READ) + jit->ClearCache(); +} +CPUCoreBase* InitJitCore(int core) +{ + bFakeVMEM = !SConfig::GetInstance().bMMU; + + CPUCoreBase* ptr = nullptr; + switch (core) + { +#if _M_X86 + case PowerPC::CORE_JIT64: + ptr = new Jit64(); + break; + case PowerPC::CORE_JITIL64: + ptr = new JitIL(); + break; +#endif +#if _M_ARM_64 + case PowerPC::CORE_JITARM64: + ptr = new JitArm64(); + break; +#endif + case PowerPC::CORE_CACHEDINTERPRETER: + ptr = new CachedInterpreter(); + break; + + default: + PanicAlert("Unrecognizable cpu_core: %d", core); + jit = nullptr; + return nullptr; + } + jit = static_cast(ptr); + jit->Init(); + return ptr; +} +void InitTables(int core) +{ + switch (core) + { +#if _M_X86 + case PowerPC::CORE_JIT64: + Jit64Tables::InitTables(); + break; + case PowerPC::CORE_JITIL64: + JitILTables::InitTables(); + break; +#endif +#if _M_ARM_64 + case PowerPC::CORE_JITARM64: + JitArm64Tables::InitTables(); + break; +#endif + case PowerPC::CORE_CACHEDINTERPRETER: + // has no tables + break; + default: + PanicAlert("Unrecognizable cpu_core: %d", core); + break; + } +} +CPUCoreBase* GetCore() +{ + return jit; +} + +void WriteProfileResults(const std::string& filename) +{ + ProfileStats prof_stats; + GetProfileResults(&prof_stats); + + File::IOFile f(filename, "w"); + if (!f) + { + PanicAlert("Failed to open %s", filename.c_str()); + return; + } + fprintf(f.GetHandle(), "origAddr\tblkName\trunCount\tcost\ttimeCost\tpercent\ttimePercent\tOvAlli" + "nBlkTime(ms)\tblkCodeSize\n"); + for (auto& stat : prof_stats.block_stats) + { + std::string name = g_symbolDB.GetDescription(stat.addr); + double percent = 100.0 * (double)stat.cost / (double)prof_stats.cost_sum; + double timePercent = 100.0 * (double)stat.tick_counter / (double)prof_stats.timecost_sum; + fprintf(f.GetHandle(), + "%08x\t%s\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%.2f\t%.2f\t%.2f\t%i\n", stat.addr, + name.c_str(), stat.run_count, stat.cost, stat.tick_counter, percent, timePercent, + (double)stat.tick_counter * 1000.0 / (double)prof_stats.countsPerSec, stat.block_size); + } +} + +void GetProfileResults(ProfileStats* prof_stats) +{ + // Can't really do this with no jit core available + if (!jit) + return; + + prof_stats->cost_sum = 0; + prof_stats->timecost_sum = 0; + prof_stats->block_stats.clear(); + prof_stats->block_stats.reserve(jit->GetBlockCache()->GetNumBlocks()); + + Core::EState old_state = Core::GetState(); + if (old_state == Core::CORE_RUN) + Core::SetState(Core::CORE_PAUSE); + + QueryPerformanceFrequency((LARGE_INTEGER*)&prof_stats->countsPerSec); + for (int i = 0; i < jit->GetBlockCache()->GetNumBlocks(); i++) + { + const JitBlock* block = jit->GetBlockCache()->GetBlock(i); + // Rough heuristic. Mem instructions should cost more. + u64 cost = block->originalSize * (block->runCount / 4); + u64 timecost = block->ticCounter; + // Todo: tweak. + if (block->runCount >= 1) + prof_stats->block_stats.emplace_back(i, block->originalAddress, cost, timecost, + block->runCount, block->codeSize); + prof_stats->cost_sum += cost; + prof_stats->timecost_sum += timecost; + } + + sort(prof_stats->block_stats.begin(), prof_stats->block_stats.end()); + if (old_state == Core::CORE_RUN) + Core::SetState(Core::CORE_RUN); +} + +int GetHostCode(u32* address, const u8** code, u32* code_size) +{ + if (!jit) + { + *code_size = 0; + return 1; + } + + int block_num = jit->GetBlockCache()->GetBlockNumberFromStartAddress(*address); + if (block_num < 0) + { + for (int i = 0; i < 500; i++) + { + block_num = jit->GetBlockCache()->GetBlockNumberFromStartAddress(*address - 4 * i); + if (block_num >= 0) + break; + } + + if (block_num >= 0) + { + JitBlock* block = jit->GetBlockCache()->GetBlock(block_num); + if (!(block->originalAddress <= *address && + block->originalSize + block->originalAddress >= *address)) + block_num = -1; + } + + // Do not merge this "if" with the above - block_num changes inside it. + if (block_num < 0) + { + *code_size = 0; + return 2; + } + } + + JitBlock* block = jit->GetBlockCache()->GetBlock(block_num); + + *code = block->checkedEntry; + *code_size = block->codeSize; + *address = block->originalAddress; + return 0; +} + +bool HandleFault(uintptr_t access_address, SContext* ctx) +{ + // Prevent nullptr dereference on a crash with no JIT present + if (!jit) + { + return false; + } + + return jit->HandleFault(access_address, ctx); +} + +bool HandleStackFault() +{ + if (!jit) + { + return false; + } + + return jit->HandleStackFault(); +} + +void ClearCache() +{ + if (jit) + jit->ClearCache(); +} +void ClearSafe() +{ + // This clear is "safe" in the sense that it's okay to run from + // inside a JIT'ed block: it clears the instruction cache, but not + // the JIT'ed code. + // TODO: There's probably a better way to handle this situation. + if (jit) + jit->GetBlockCache()->Clear(); +} + +void InvalidateICache(u32 address, u32 size, bool forced) +{ + if (jit) + jit->GetBlockCache()->InvalidateICache(address, size, forced); +} + +void CompileExceptionCheck(ExceptionType type) +{ + if (!jit) + return; + + std::unordered_set* exception_addresses = nullptr; + + switch (type) + { + case ExceptionType::EXCEPTIONS_FIFO_WRITE: + exception_addresses = &jit->js.fifoWriteAddresses; + break; + case ExceptionType::EXCEPTIONS_PAIRED_QUANTIZE: + exception_addresses = &jit->js.pairedQuantizeAddresses; + break; + } + + if (PC != 0 && (exception_addresses->find(PC)) == (exception_addresses->end())) + { + if (type == ExceptionType::EXCEPTIONS_FIFO_WRITE) + { + // Check in case the code has been replaced since: do we need to do this? + int optype = GetOpInfo(PowerPC::HostRead_U32(PC))->type; + if (optype != OPTYPE_STORE && optype != OPTYPE_STOREFP && (optype != OPTYPE_STOREPS)) + return; + } + exception_addresses->insert(PC); + + // Invalidate the JIT block so that it gets recompiled with the external exception check + // included. + jit->GetBlockCache()->InvalidateICache(PC, 4, true); + } +} + +void Shutdown() +{ + if (jit) + { + jit->Shutdown(); + delete jit; + jit = nullptr; + } +} } diff --git a/Source/Core/Core/PowerPC/JitInterface.h b/Source/Core/Core/PowerPC/JitInterface.h index 54249e1a3f..4608f306a1 100644 --- a/Source/Core/Core/PowerPC/JitInterface.h +++ b/Source/Core/Core/PowerPC/JitInterface.h @@ -12,36 +12,36 @@ namespace JitInterface { - enum class ExceptionType - { - EXCEPTIONS_FIFO_WRITE, - EXCEPTIONS_PAIRED_QUANTIZE - }; +enum class ExceptionType +{ + EXCEPTIONS_FIFO_WRITE, + EXCEPTIONS_PAIRED_QUANTIZE +}; - void DoState(PointerWrap &p); +void DoState(PointerWrap& p); - CPUCoreBase *InitJitCore(int core); - void InitTables(int core); - CPUCoreBase *GetCore(); +CPUCoreBase* InitJitCore(int core); +void InitTables(int core); +CPUCoreBase* GetCore(); - // Debugging - void WriteProfileResults(const std::string& filename); - void GetProfileResults(ProfileStats* prof_stats); - int GetHostCode(u32* address, const u8** code, u32* code_size); +// Debugging +void WriteProfileResults(const std::string& filename); +void GetProfileResults(ProfileStats* prof_stats); +int GetHostCode(u32* address, const u8** code, u32* code_size); - // Memory Utilities - bool HandleFault(uintptr_t access_address, SContext* ctx); - bool HandleStackFault(); +// Memory Utilities +bool HandleFault(uintptr_t access_address, SContext* ctx); +bool HandleStackFault(); - // Clearing CodeCache - void ClearCache(); +// Clearing CodeCache +void ClearCache(); - void ClearSafe(); +void ClearSafe(); - // If "forced" is true, a recompile is being requested on code that hasn't been modified. - void InvalidateICache(u32 address, u32 size, bool forced); +// If "forced" is true, a recompile is being requested on code that hasn't been modified. +void InvalidateICache(u32 address, u32 size, bool forced); - void CompileExceptionCheck(ExceptionType type); +void CompileExceptionCheck(ExceptionType type); - void Shutdown(); +void Shutdown(); } diff --git a/Source/Core/Core/PowerPC/MMU.cpp b/Source/Core/Core/PowerPC/MMU.cpp index f44ac3b468..6cb0b43dc6 100644 --- a/Source/Core/Core/PowerPC/MMU.cpp +++ b/Source/Core/Core/PowerPC/MMU.cpp @@ -10,8 +10,8 @@ #include "Core/Core.h" #include "Core/HW/CPU.h" #include "Core/HW/GPFifo.h" -#include "Core/HW/Memmap.h" #include "Core/HW/MMIO.h" +#include "Core/HW/Memmap.h" #include "Core/PowerPC/PowerPC.h" #include "VideoCommon/VideoBackendBase.h" @@ -22,7 +22,6 @@ namespace PowerPC { - #define HW_PAGE_SIZE 4096 // EFB RE @@ -40,338 +39,376 @@ GXPeekZ 80322e0c: blr */ - // ================================= // From Memmap.cpp // ---------------- // Overloaded byteswap functions, for use within the templated functions below. -inline u8 bswap(u8 val) { return val; } -inline s8 bswap(s8 val) { return val; } -inline u16 bswap(u16 val) { return Common::swap16(val); } -inline s16 bswap(s16 val) { return Common::swap16(val); } -inline u32 bswap(u32 val) { return Common::swap32(val); } -inline u64 bswap(u64 val) { return Common::swap64(val); } +inline u8 bswap(u8 val) +{ + return val; +} +inline s8 bswap(s8 val) +{ + return val; +} +inline u16 bswap(u16 val) +{ + return Common::swap16(val); +} +inline s16 bswap(s16 val) +{ + return Common::swap16(val); +} +inline u32 bswap(u32 val) +{ + return Common::swap32(val); +} +inline u64 bswap(u64 val) +{ + return Common::swap64(val); +} // ================= enum XCheckTLBFlag { - FLAG_NO_EXCEPTION, - FLAG_READ, - FLAG_WRITE, - FLAG_OPCODE, + FLAG_NO_EXCEPTION, + FLAG_READ, + FLAG_WRITE, + FLAG_OPCODE, }; -template static u32 TranslateAddress(const u32 address); +template +static u32 TranslateAddress(const u32 address); // Nasty but necessary. Super Mario Galaxy pointer relies on this stuff. static u32 EFB_Read(const u32 addr) { - u32 var = 0; - // Convert address to coordinates. It's possible that this should be done - // differently depending on color depth, especially regarding PEEK_COLOR. - int x = (addr & 0xfff) >> 2; - int y = (addr >> 12) & 0x3ff; + u32 var = 0; + // Convert address to coordinates. It's possible that this should be done + // differently depending on color depth, especially regarding PEEK_COLOR. + int x = (addr & 0xfff) >> 2; + int y = (addr >> 12) & 0x3ff; - if (addr & 0x00800000) - { - ERROR_LOG(MEMMAP, "Unimplemented Z+Color EFB read @ 0x%08x", addr); - } - else if (addr & 0x00400000) - { - var = g_video_backend->Video_AccessEFB(PEEK_Z, x, y, 0); - DEBUG_LOG(MEMMAP, "EFB Z Read @ %i, %i\t= 0x%08x", x, y, var); - } - else - { - var = g_video_backend->Video_AccessEFB(PEEK_COLOR, x, y, 0); - DEBUG_LOG(MEMMAP, "EFB Color Read @ %i, %i\t= 0x%08x", x, y, var); - } + if (addr & 0x00800000) + { + ERROR_LOG(MEMMAP, "Unimplemented Z+Color EFB read @ 0x%08x", addr); + } + else if (addr & 0x00400000) + { + var = g_video_backend->Video_AccessEFB(PEEK_Z, x, y, 0); + DEBUG_LOG(MEMMAP, "EFB Z Read @ %i, %i\t= 0x%08x", x, y, var); + } + else + { + var = g_video_backend->Video_AccessEFB(PEEK_COLOR, x, y, 0); + DEBUG_LOG(MEMMAP, "EFB Color Read @ %i, %i\t= 0x%08x", x, y, var); + } - return var; + return var; } static void EFB_Write(u32 data, u32 addr) { - int x = (addr & 0xfff) >> 2; - int y = (addr >> 12) & 0x3ff; + int x = (addr & 0xfff) >> 2; + int y = (addr >> 12) & 0x3ff; - if (addr & 0x00800000) - { - // It's possible to do a z-tested write to EFB by writing a 64bit value to this address range. - // Not much is known, but let's at least get some loging. - ERROR_LOG(MEMMAP, "Unimplemented Z+Color EFB write. %08x @ 0x%08x", data, addr); - } - else if (addr & 0x00400000) - { - g_video_backend->Video_AccessEFB(POKE_Z, x, y, data); - DEBUG_LOG(MEMMAP, "EFB Z Write %08x @ %i, %i", data, x, y); - } - else - { - g_video_backend->Video_AccessEFB(POKE_COLOR, x, y, data); - DEBUG_LOG(MEMMAP, "EFB Color Write %08x @ %i, %i", data, x, y); - } + if (addr & 0x00800000) + { + // It's possible to do a z-tested write to EFB by writing a 64bit value to this address range. + // Not much is known, but let's at least get some loging. + ERROR_LOG(MEMMAP, "Unimplemented Z+Color EFB write. %08x @ 0x%08x", data, addr); + } + else if (addr & 0x00400000) + { + g_video_backend->Video_AccessEFB(POKE_Z, x, y, data); + DEBUG_LOG(MEMMAP, "EFB Z Write %08x @ %i, %i", data, x, y); + } + else + { + g_video_backend->Video_AccessEFB(POKE_COLOR, x, y, data); + DEBUG_LOG(MEMMAP, "EFB Color Write %08x @ %i, %i", data, x, y); + } } - static void GenerateDSIException(u32 _EffectiveAddress, bool _bWrite); template __forceinline static T ReadFromHardware(const u32 em_address) { - int segment = em_address >> 28; - bool performTranslation = UReg_MSR(MSR).DR; + int segment = em_address >> 28; + bool performTranslation = UReg_MSR(MSR).DR; - // Quick check for an address that can't meet any of the following conditions, - // to speed up the MMU path. - if (!BitSet32(0xCFC)[segment] && performTranslation) - { - // TODO: Figure out the fastest order of tests for both read and write (they are probably different). - if (flag == FLAG_READ && (em_address & 0xF8000000) == 0xC8000000) - { - if (em_address < 0xcc000000) - return EFB_Read(em_address); - else - return (T)Memory::mmio_mapping->Read::type>(em_address & 0x0FFFFFFF); - } - if (segment == 0x0 || segment == 0x8 || segment == 0xC) - { - // Handle RAM; the masking intentionally discards bits (essentially creating - // mirrors of memory). - // TODO: Only the first REALRAM_SIZE is supposed to be backed by actual memory. - return bswap((*(const T*)&Memory::m_pRAM[em_address & Memory::RAM_MASK])); - } - if (Memory::m_pEXRAM && (segment == 0x9 || segment == 0xD) && (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) - { - // Handle EXRAM. - // TODO: Is this supposed to be mirrored like main RAM? - return bswap((*(const T*)&Memory::m_pEXRAM[em_address & 0x0FFFFFFF])); - } - if (segment == 0xE && (em_address < (0xE0000000 + Memory::L1_CACHE_SIZE))) - { - return bswap((*(const T*)&Memory::m_pL1Cache[em_address & 0x0FFFFFFF])); - } - } + // Quick check for an address that can't meet any of the following conditions, + // to speed up the MMU path. + if (!BitSet32(0xCFC)[segment] && performTranslation) + { + // TODO: Figure out the fastest order of tests for both read and write (they are probably + // different). + if (flag == FLAG_READ && (em_address & 0xF8000000) == 0xC8000000) + { + if (em_address < 0xcc000000) + return EFB_Read(em_address); + else + return (T)Memory::mmio_mapping->Read::type>(em_address & + 0x0FFFFFFF); + } + if (segment == 0x0 || segment == 0x8 || segment == 0xC) + { + // Handle RAM; the masking intentionally discards bits (essentially creating + // mirrors of memory). + // TODO: Only the first REALRAM_SIZE is supposed to be backed by actual memory. + return bswap((*(const T*)&Memory::m_pRAM[em_address & Memory::RAM_MASK])); + } + if (Memory::m_pEXRAM && (segment == 0x9 || segment == 0xD) && + (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) + { + // Handle EXRAM. + // TODO: Is this supposed to be mirrored like main RAM? + return bswap((*(const T*)&Memory::m_pEXRAM[em_address & 0x0FFFFFFF])); + } + if (segment == 0xE && (em_address < (0xE0000000 + Memory::L1_CACHE_SIZE))) + { + return bswap((*(const T*)&Memory::m_pL1Cache[em_address & 0x0FFFFFFF])); + } + } - if (Memory::bFakeVMEM && performTranslation && (segment == 0x7 || segment == 0x4)) - { - // fake VMEM - return bswap((*(const T*)&Memory::m_pFakeVMEM[em_address & Memory::FAKEVMEM_MASK])); - } + if (Memory::bFakeVMEM && performTranslation && (segment == 0x7 || segment == 0x4)) + { + // fake VMEM + return bswap((*(const T*)&Memory::m_pFakeVMEM[em_address & Memory::FAKEVMEM_MASK])); + } - if (!performTranslation) - { - if (flag == FLAG_READ && (em_address & 0xF8000000) == 0x08000000) - { - if (em_address < 0x0c000000) - return EFB_Read(em_address); - else - return (T)Memory::mmio_mapping->Read::type>(em_address); - } - if (segment == 0x0) - { - // Handle RAM; the masking intentionally discards bits (essentially creating - // mirrors of memory). - // TODO: Only the first REALRAM_SIZE is supposed to be backed by actual memory. - return bswap((*(const T*)&Memory::m_pRAM[em_address & Memory::RAM_MASK])); - } - if (Memory::m_pEXRAM && segment == 0x1 && (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) - { - return bswap((*(const T*)&Memory::m_pEXRAM[em_address & 0x0FFFFFFF])); - } - PanicAlert("Unable to resolve read address %x PC %x", em_address, PC); - return 0; - } + if (!performTranslation) + { + if (flag == FLAG_READ && (em_address & 0xF8000000) == 0x08000000) + { + if (em_address < 0x0c000000) + return EFB_Read(em_address); + else + return (T)Memory::mmio_mapping->Read::type>(em_address); + } + if (segment == 0x0) + { + // Handle RAM; the masking intentionally discards bits (essentially creating + // mirrors of memory). + // TODO: Only the first REALRAM_SIZE is supposed to be backed by actual memory. + return bswap((*(const T*)&Memory::m_pRAM[em_address & Memory::RAM_MASK])); + } + if (Memory::m_pEXRAM && segment == 0x1 && (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) + { + return bswap((*(const T*)&Memory::m_pEXRAM[em_address & 0x0FFFFFFF])); + } + PanicAlert("Unable to resolve read address %x PC %x", em_address, PC); + return 0; + } - // MMU: Do page table translation - u32 tlb_addr = TranslateAddress(em_address); - if (tlb_addr == 0) - { - if (flag == FLAG_READ) - GenerateDSIException(em_address, false); - return 0; - } + // MMU: Do page table translation + u32 tlb_addr = TranslateAddress(em_address); + if (tlb_addr == 0) + { + if (flag == FLAG_READ) + GenerateDSIException(em_address, false); + return 0; + } - // Handle loads that cross page boundaries (ewwww) - // The alignment check isn't strictly necessary, but since this is a rare slow path, it provides a faster - // (1 instruction on x86) bailout. - if (sizeof(T) > 1 && (em_address & (sizeof(T) - 1)) && (em_address & (HW_PAGE_SIZE - 1)) > HW_PAGE_SIZE - sizeof(T)) - { - // This could be unaligned down to the byte level... hopefully this is rare, so doing it this - // way isn't too terrible. - // TODO: floats on non-word-aligned boundaries should technically cause alignment exceptions. - // Note that "word" means 32-bit, so paired singles or doubles might still be 32-bit aligned! - u32 em_address_next_page = (em_address + sizeof(T) - 1) & ~(HW_PAGE_SIZE - 1); - u32 tlb_addr_next_page = TranslateAddress(em_address_next_page); - if (tlb_addr == 0 || tlb_addr_next_page == 0) - { - if (flag == FLAG_READ) - GenerateDSIException(em_address_next_page, false); - return 0; - } - T var = 0; - for (u32 addr = em_address; addr < em_address + sizeof(T); addr++, tlb_addr++) - { - if (addr == em_address_next_page) - tlb_addr = tlb_addr_next_page; - var = (var << 8) | Memory::physical_base[tlb_addr]; - } - return var; - } + // Handle loads that cross page boundaries (ewwww) + // The alignment check isn't strictly necessary, but since this is a rare slow path, it provides a + // faster + // (1 instruction on x86) bailout. + if (sizeof(T) > 1 && (em_address & (sizeof(T) - 1)) && + (em_address & (HW_PAGE_SIZE - 1)) > HW_PAGE_SIZE - sizeof(T)) + { + // This could be unaligned down to the byte level... hopefully this is rare, so doing it this + // way isn't too terrible. + // TODO: floats on non-word-aligned boundaries should technically cause alignment exceptions. + // Note that "word" means 32-bit, so paired singles or doubles might still be 32-bit aligned! + u32 em_address_next_page = (em_address + sizeof(T) - 1) & ~(HW_PAGE_SIZE - 1); + u32 tlb_addr_next_page = TranslateAddress(em_address_next_page); + if (tlb_addr == 0 || tlb_addr_next_page == 0) + { + if (flag == FLAG_READ) + GenerateDSIException(em_address_next_page, false); + return 0; + } + T var = 0; + for (u32 addr = em_address; addr < em_address + sizeof(T); addr++, tlb_addr++) + { + if (addr == em_address_next_page) + tlb_addr = tlb_addr_next_page; + var = (var << 8) | Memory::physical_base[tlb_addr]; + } + return var; + } - // The easy case! - return bswap(*(const T*)&Memory::physical_base[tlb_addr]); + // The easy case! + return bswap(*(const T*)&Memory::physical_base[tlb_addr]); } - template __forceinline static void WriteToHardware(u32 em_address, const T data) { - int segment = em_address >> 28; - // Quick check for an address that can't meet any of the following conditions, - // to speed up the MMU path. - bool performTranslation = UReg_MSR(MSR).DR; + int segment = em_address >> 28; + // Quick check for an address that can't meet any of the following conditions, + // to speed up the MMU path. + bool performTranslation = UReg_MSR(MSR).DR; - if (!BitSet32(0xCFC)[segment] && performTranslation) - { - // First, let's check for FIFO writes, since they are probably the most common - // reason we end up in this function. - // Note that we must mask the address to correctly emulate certain games; - // Pac-Man World 3 in particular is affected by this. - if (flag == FLAG_WRITE && (em_address & 0xFFFFF000) == 0xCC008000) - { - switch (sizeof(T)) - { - case 1: GPFifo::Write8((u8)data); return; - case 2: GPFifo::Write16((u16)data); return; - case 4: GPFifo::Write32((u32)data); return; - case 8: GPFifo::Write64((u64)data); return; - } - } - if (flag == FLAG_WRITE && (em_address & 0xF8000000) == 0xC8000000) - { - if (em_address < 0xcc000000) - { - // TODO: This only works correctly for 32-bit writes. - EFB_Write((u32)data, em_address); - return; - } - else - { - Memory::mmio_mapping->Write(em_address & 0x0FFFFFFF, data); - return; - } - } - if (segment == 0x0 || segment == 0x8 || segment == 0xC) - { - // Handle RAM; the masking intentionally discards bits (essentially creating - // mirrors of memory). - // TODO: Only the first REALRAM_SIZE is supposed to be backed by actual memory. - *(T*)&Memory::m_pRAM[em_address & Memory::RAM_MASK] = bswap(data); - return; - } - if (Memory::m_pEXRAM && (segment == 0x9 || segment == 0xD) && (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) - { - // Handle EXRAM. - // TODO: Is this supposed to be mirrored like main RAM? - *(T*)&Memory::m_pEXRAM[em_address & 0x0FFFFFFF] = bswap(data); - return; - } - if (segment == 0xE && (em_address < (0xE0000000 + Memory::L1_CACHE_SIZE))) - { - *(T*)&Memory::m_pL1Cache[em_address & 0x0FFFFFFF] = bswap(data); - return; - } - } + if (!BitSet32(0xCFC)[segment] && performTranslation) + { + // First, let's check for FIFO writes, since they are probably the most common + // reason we end up in this function. + // Note that we must mask the address to correctly emulate certain games; + // Pac-Man World 3 in particular is affected by this. + if (flag == FLAG_WRITE && (em_address & 0xFFFFF000) == 0xCC008000) + { + switch (sizeof(T)) + { + case 1: + GPFifo::Write8((u8)data); + return; + case 2: + GPFifo::Write16((u16)data); + return; + case 4: + GPFifo::Write32((u32)data); + return; + case 8: + GPFifo::Write64((u64)data); + return; + } + } + if (flag == FLAG_WRITE && (em_address & 0xF8000000) == 0xC8000000) + { + if (em_address < 0xcc000000) + { + // TODO: This only works correctly for 32-bit writes. + EFB_Write((u32)data, em_address); + return; + } + else + { + Memory::mmio_mapping->Write(em_address & 0x0FFFFFFF, data); + return; + } + } + if (segment == 0x0 || segment == 0x8 || segment == 0xC) + { + // Handle RAM; the masking intentionally discards bits (essentially creating + // mirrors of memory). + // TODO: Only the first REALRAM_SIZE is supposed to be backed by actual memory. + *(T*)&Memory::m_pRAM[em_address & Memory::RAM_MASK] = bswap(data); + return; + } + if (Memory::m_pEXRAM && (segment == 0x9 || segment == 0xD) && + (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) + { + // Handle EXRAM. + // TODO: Is this supposed to be mirrored like main RAM? + *(T*)&Memory::m_pEXRAM[em_address & 0x0FFFFFFF] = bswap(data); + return; + } + if (segment == 0xE && (em_address < (0xE0000000 + Memory::L1_CACHE_SIZE))) + { + *(T*)&Memory::m_pL1Cache[em_address & 0x0FFFFFFF] = bswap(data); + return; + } + } - if (Memory::bFakeVMEM && performTranslation && (segment == 0x7 || segment == 0x4)) - { - // fake VMEM - *(T*)&Memory::m_pFakeVMEM[em_address & Memory::FAKEVMEM_MASK] = bswap(data); - return; - } + if (Memory::bFakeVMEM && performTranslation && (segment == 0x7 || segment == 0x4)) + { + // fake VMEM + *(T*)&Memory::m_pFakeVMEM[em_address & Memory::FAKEVMEM_MASK] = bswap(data); + return; + } - if (!performTranslation) - { - if (flag == FLAG_WRITE && (em_address & 0xFFFFF000) == 0x0C008000) - { - switch (sizeof(T)) - { - case 1: GPFifo::Write8((u8)data); return; - case 2: GPFifo::Write16((u16)data); return; - case 4: GPFifo::Write32((u32)data); return; - case 8: GPFifo::Write64((u64)data); return; - } - } - if (flag == FLAG_WRITE && (em_address & 0xF8000000) == 0x08000000) - { - if (em_address < 0x0c000000) - { - // TODO: This only works correctly for 32-bit writes. - EFB_Write((u32)data, em_address); - return; - } - else - { - Memory::mmio_mapping->Write(em_address, data); - return; - } - } - if (segment == 0x0) - { - // Handle RAM; the masking intentionally discards bits (essentially creating - // mirrors of memory). - // TODO: Only the first REALRAM_SIZE is supposed to be backed by actual memory. - *(T*)&Memory::m_pRAM[em_address & Memory::RAM_MASK] = bswap(data); - return; - } - if (Memory::m_pEXRAM && segment == 0x1 && (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) - { - *(T*)&Memory::m_pEXRAM[em_address & 0x0FFFFFFF] = bswap(data); - return; - } - PanicAlert("Unable to resolve write address %x PC %x", em_address, PC); - return; - } + if (!performTranslation) + { + if (flag == FLAG_WRITE && (em_address & 0xFFFFF000) == 0x0C008000) + { + switch (sizeof(T)) + { + case 1: + GPFifo::Write8((u8)data); + return; + case 2: + GPFifo::Write16((u16)data); + return; + case 4: + GPFifo::Write32((u32)data); + return; + case 8: + GPFifo::Write64((u64)data); + return; + } + } + if (flag == FLAG_WRITE && (em_address & 0xF8000000) == 0x08000000) + { + if (em_address < 0x0c000000) + { + // TODO: This only works correctly for 32-bit writes. + EFB_Write((u32)data, em_address); + return; + } + else + { + Memory::mmio_mapping->Write(em_address, data); + return; + } + } + if (segment == 0x0) + { + // Handle RAM; the masking intentionally discards bits (essentially creating + // mirrors of memory). + // TODO: Only the first REALRAM_SIZE is supposed to be backed by actual memory. + *(T*)&Memory::m_pRAM[em_address & Memory::RAM_MASK] = bswap(data); + return; + } + if (Memory::m_pEXRAM && segment == 0x1 && (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) + { + *(T*)&Memory::m_pEXRAM[em_address & 0x0FFFFFFF] = bswap(data); + return; + } + PanicAlert("Unable to resolve write address %x PC %x", em_address, PC); + return; + } - // MMU: Do page table translation - u32 tlb_addr = TranslateAddress(em_address); - if (tlb_addr == 0) - { - if (flag == FLAG_WRITE) - GenerateDSIException(em_address, true); - return; - } + // MMU: Do page table translation + u32 tlb_addr = TranslateAddress(em_address); + if (tlb_addr == 0) + { + if (flag == FLAG_WRITE) + GenerateDSIException(em_address, true); + return; + } - // Handle stores that cross page boundaries (ewwww) - if (sizeof(T) > 1 && (em_address & (sizeof(T) - 1)) && (em_address & (HW_PAGE_SIZE - 1)) > HW_PAGE_SIZE - sizeof(T)) - { - T val = bswap(data); + // Handle stores that cross page boundaries (ewwww) + if (sizeof(T) > 1 && (em_address & (sizeof(T) - 1)) && + (em_address & (HW_PAGE_SIZE - 1)) > HW_PAGE_SIZE - sizeof(T)) + { + T val = bswap(data); - // We need to check both addresses before writing in case there's a DSI. - u32 em_address_next_page = (em_address + sizeof(T) - 1) & ~(HW_PAGE_SIZE - 1); - u32 tlb_addr_next_page = TranslateAddress(em_address_next_page); - if (tlb_addr_next_page == 0) - { - if (flag == FLAG_WRITE) - GenerateDSIException(em_address_next_page, true); - return; - } - for (u32 addr = em_address; addr < em_address + sizeof(T); addr++, tlb_addr++, val >>= 8) - { - if (addr == em_address_next_page) - tlb_addr = tlb_addr_next_page; - Memory::physical_base[tlb_addr] = (u8)val; - } - return; - } + // We need to check both addresses before writing in case there's a DSI. + u32 em_address_next_page = (em_address + sizeof(T) - 1) & ~(HW_PAGE_SIZE - 1); + u32 tlb_addr_next_page = TranslateAddress(em_address_next_page); + if (tlb_addr_next_page == 0) + { + if (flag == FLAG_WRITE) + GenerateDSIException(em_address_next_page, true); + return; + } + for (u32 addr = em_address; addr < em_address + sizeof(T); addr++, tlb_addr++, val >>= 8) + { + if (addr == em_address_next_page) + tlb_addr = tlb_addr_next_page; + Memory::physical_base[tlb_addr] = (u8)val; + } + return; + } - // The easy case! - *(T*)&Memory::physical_base[tlb_addr] = bswap(data); + // The easy case! + *(T*)&Memory::physical_base[tlb_addr] = bswap(data); } // ===================== - // ================================= /* These functions are primarily called by the Interpreter functions and are routed to the correct location through ReadFromHardware and WriteToHardware */ @@ -381,424 +418,422 @@ static void GenerateISIException(u32 effective_address); u32 Read_Opcode(u32 address) { - TryReadInstResult result = TryReadInstruction(address); - if (!result.valid) - { - GenerateISIException(address); - return 0; - } - return result.hex; + TryReadInstResult result = TryReadInstruction(address); + if (!result.valid) + { + GenerateISIException(address); + return 0; + } + return result.hex; } TryReadInstResult TryReadInstruction(u32 address) { - bool from_bat = true; - if (UReg_MSR(MSR).IR) - { - // TODO: Use real translation. - if (SConfig::GetInstance().bMMU && (address & Memory::ADDR_MASK_MEM1)) - { - u32 tlb_addr = TranslateAddress(address); - if (tlb_addr == 0) - { - return TryReadInstResult{ false, false, 0 }; - } - else - { - address = tlb_addr; - from_bat = false; - } - } - else - { - int segment = address >> 28; - if ((segment == 0x8 || segment == 0x0) && (address & 0x0FFFFFFF) < Memory::REALRAM_SIZE) - { - address = address & 0x3FFFFFFF; - } - else if (segment == 0x9 && (address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) - { - address = address & 0x3FFFFFFF; - } - else if (Memory::bFakeVMEM && (segment == 0x7 || segment == 0x4)) - { - u32 hex = bswap((*(const u32*)&Memory::m_pFakeVMEM[address & Memory::FAKEVMEM_MASK])); - return TryReadInstResult{ true, true, hex }; - } - else - { - return TryReadInstResult{ false, false, 0 }; - } - } - } - else - { - if (address & 0xC0000000) - ERROR_LOG(MEMMAP, "Strange program counter with address translation off: 0x%08x", address); - } + bool from_bat = true; + if (UReg_MSR(MSR).IR) + { + // TODO: Use real translation. + if (SConfig::GetInstance().bMMU && (address & Memory::ADDR_MASK_MEM1)) + { + u32 tlb_addr = TranslateAddress(address); + if (tlb_addr == 0) + { + return TryReadInstResult{false, false, 0}; + } + else + { + address = tlb_addr; + from_bat = false; + } + } + else + { + int segment = address >> 28; + if ((segment == 0x8 || segment == 0x0) && (address & 0x0FFFFFFF) < Memory::REALRAM_SIZE) + { + address = address & 0x3FFFFFFF; + } + else if (segment == 0x9 && (address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) + { + address = address & 0x3FFFFFFF; + } + else if (Memory::bFakeVMEM && (segment == 0x7 || segment == 0x4)) + { + u32 hex = bswap((*(const u32*)&Memory::m_pFakeVMEM[address & Memory::FAKEVMEM_MASK])); + return TryReadInstResult{true, true, hex}; + } + else + { + return TryReadInstResult{false, false, 0}; + } + } + } + else + { + if (address & 0xC0000000) + ERROR_LOG(MEMMAP, "Strange program counter with address translation off: 0x%08x", address); + } - u32 hex = PowerPC::ppcState.iCache.ReadInstruction(address); - return TryReadInstResult{ true, from_bat, hex }; + u32 hex = PowerPC::ppcState.iCache.ReadInstruction(address); + return TryReadInstResult{true, from_bat, hex}; } u32 HostRead_Instruction(const u32 address) { - UGeckoInstruction inst = HostRead_U32(address); - return inst.hex; + UGeckoInstruction inst = HostRead_U32(address); + return inst.hex; } static __forceinline void Memcheck(u32 address, u32 var, bool write, int size) { #ifdef ENABLE_MEM_CHECK - TMemCheck *mc = PowerPC::memchecks.GetMemCheck(address); - if (mc) - { - if (CPU::IsStepping()) - { - // Disable when stepping so that resume works. - return; - } - mc->numHits++; - bool pause = mc->Action(&PowerPC::debug_interface, var, address, write, size, PC); - if (pause) - { - CPU::Break(); - // Fake a DSI so that all the code that tests for it in order to skip - // the rest of the instruction will apply. (This means that - // watchpoints will stop the emulator before the offending load/store, - // not after like GDB does, but that's better anyway. Just need to - // make sure resuming after that works.) - // It doesn't matter if ReadFromHardware triggers its own DSI because - // we'll take it after resuming. - PowerPC::ppcState.Exceptions |= EXCEPTION_DSI | EXCEPTION_FAKE_MEMCHECK_HIT; - } - } + TMemCheck* mc = PowerPC::memchecks.GetMemCheck(address); + if (mc) + { + if (CPU::IsStepping()) + { + // Disable when stepping so that resume works. + return; + } + mc->numHits++; + bool pause = mc->Action(&PowerPC::debug_interface, var, address, write, size, PC); + if (pause) + { + CPU::Break(); + // Fake a DSI so that all the code that tests for it in order to skip + // the rest of the instruction will apply. (This means that + // watchpoints will stop the emulator before the offending load/store, + // not after like GDB does, but that's better anyway. Just need to + // make sure resuming after that works.) + // It doesn't matter if ReadFromHardware triggers its own DSI because + // we'll take it after resuming. + PowerPC::ppcState.Exceptions |= EXCEPTION_DSI | EXCEPTION_FAKE_MEMCHECK_HIT; + } + } #endif } u8 Read_U8(const u32 address) { - u8 var = ReadFromHardware(address); - Memcheck(address, var, false, 1); - return (u8)var; + u8 var = ReadFromHardware(address); + Memcheck(address, var, false, 1); + return (u8)var; } u16 Read_U16(const u32 address) { - u16 var = ReadFromHardware(address); - Memcheck(address, var, false, 2); - return (u16)var; + u16 var = ReadFromHardware(address); + Memcheck(address, var, false, 2); + return (u16)var; } u32 Read_U32(const u32 address) { - u32 var = ReadFromHardware(address); - Memcheck(address, var, false, 4); - return var; + u32 var = ReadFromHardware(address); + Memcheck(address, var, false, 4); + return var; } u64 Read_U64(const u32 address) { - u64 var = ReadFromHardware(address); - Memcheck(address, (u32)var, false, 8); - return var; + u64 var = ReadFromHardware(address); + Memcheck(address, (u32)var, false, 8); + return var; } double Read_F64(const u32 address) { - union - { - u64 i; - double d; - } cvt; + union { + u64 i; + double d; + } cvt; - cvt.i = Read_U64(address); - return cvt.d; + cvt.i = Read_U64(address); + return cvt.d; } float Read_F32(const u32 address) { - union - { - u32 i; - float d; - } cvt; + union { + u32 i; + float d; + } cvt; - cvt.i = Read_U32(address); - return cvt.d; + cvt.i = Read_U32(address); + return cvt.d; } u32 Read_U8_ZX(const u32 address) { - return (u32)Read_U8(address); + return (u32)Read_U8(address); } u32 Read_U16_ZX(const u32 address) { - return (u32)Read_U16(address); + return (u32)Read_U16(address); } void Write_U8(const u8 var, const u32 address) { - Memcheck(address, var, true, 1); - WriteToHardware(address, var); + Memcheck(address, var, true, 1); + WriteToHardware(address, var); } void Write_U16(const u16 var, const u32 address) { - Memcheck(address, var, true, 2); - WriteToHardware(address, var); + Memcheck(address, var, true, 2); + WriteToHardware(address, var); } void Write_U16_Swap(const u16 var, const u32 address) { - Memcheck(address, var, true, 2); - Write_U16(Common::swap16(var), address); + Memcheck(address, var, true, 2); + Write_U16(Common::swap16(var), address); } - void Write_U32(const u32 var, const u32 address) { - Memcheck(address, var, true, 4); - WriteToHardware(address, var); + Memcheck(address, var, true, 4); + WriteToHardware(address, var); } void Write_U32_Swap(const u32 var, const u32 address) { - Memcheck(address, var, true, 4); - Write_U32(Common::swap32(var), address); + Memcheck(address, var, true, 4); + Write_U32(Common::swap32(var), address); } void Write_U64(const u64 var, const u32 address) { - Memcheck(address, (u32)var, true, 8); - WriteToHardware(address, var); + Memcheck(address, (u32)var, true, 8); + WriteToHardware(address, var); } void Write_U64_Swap(const u64 var, const u32 address) { - Memcheck(address, (u32)var, true, 8); - Write_U64(Common::swap64(var), address); + Memcheck(address, (u32)var, true, 8); + Write_U64(Common::swap64(var), address); } void Write_F64(const double var, const u32 address) { - union - { - u64 i; - double d; - } cvt; - cvt.d = var; - Write_U64(cvt.i, address); + union { + u64 i; + double d; + } cvt; + cvt.d = var; + Write_U64(cvt.i, address); } u8 HostRead_U8(const u32 address) { - u8 var = ReadFromHardware(address); - return var; + u8 var = ReadFromHardware(address); + return var; } u16 HostRead_U16(const u32 address) { - u16 var = ReadFromHardware(address); - return var; + u16 var = ReadFromHardware(address); + return var; } u32 HostRead_U32(const u32 address) { - u32 var = ReadFromHardware(address); - return var; + u32 var = ReadFromHardware(address); + return var; } void HostWrite_U8(const u8 var, const u32 address) { - WriteToHardware(address, var); + WriteToHardware(address, var); } void HostWrite_U16(const u16 var, const u32 address) { - WriteToHardware(address, var); + WriteToHardware(address, var); } void HostWrite_U32(const u32 var, const u32 address) { - WriteToHardware(address, var); + WriteToHardware(address, var); } void HostWrite_U64(const u64 var, const u32 address) { - WriteToHardware(address, var); + WriteToHardware(address, var); } std::string HostGetString(u32 address, size_t size) { - std::string s; - do - { - if (!HostIsRAMAddress(address)) - break; - u8 res = HostRead_U8(address); - if (!res) - break; - s += static_cast(res); - ++address; - } while (size == 0 || s.length() < size); - return s; + std::string s; + do + { + if (!HostIsRAMAddress(address)) + break; + u8 res = HostRead_U8(address); + if (!res) + break; + s += static_cast(res); + ++address; + } while (size == 0 || s.length() < size); + return s; } bool IsOptimizableRAMAddress(const u32 address) { #ifdef ENABLE_MEM_CHECK - return false; + return false; #endif - if (!UReg_MSR(MSR).DR) - return false; + if (!UReg_MSR(MSR).DR) + return false; - int segment = address >> 28; + int segment = address >> 28; - return (((segment == 0x8 || segment == 0xC || segment == 0x0) && (address & 0x0FFFFFFF) < Memory::REALRAM_SIZE) || - (Memory::m_pEXRAM && (segment == 0x9 || segment == 0xD) && (address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) || - (segment == 0xE && (address < (0xE0000000 + Memory::L1_CACHE_SIZE)))); + return (((segment == 0x8 || segment == 0xC || segment == 0x0) && + (address & 0x0FFFFFFF) < Memory::REALRAM_SIZE) || + (Memory::m_pEXRAM && (segment == 0x9 || segment == 0xD) && + (address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) || + (segment == 0xE && (address < (0xE0000000 + Memory::L1_CACHE_SIZE)))); } bool HostIsRAMAddress(u32 address) { - // TODO: This needs to be rewritten; it makes incorrect assumptions - // about BATs and page tables. - bool performTranslation = UReg_MSR(MSR).DR; - int segment = address >> 28; - if (performTranslation) - { - if ((segment == 0x8 || segment == 0xC || segment == 0x0) && (address & 0x0FFFFFFF) < Memory::REALRAM_SIZE) - return true; - else if (Memory::m_pEXRAM && (segment == 0x9 || segment == 0xD) && (address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) - return true; - else if (Memory::bFakeVMEM && (segment == 0x7 || segment == 0x4)) - return true; - else if (segment == 0xE && (address < (0xE0000000 + Memory::L1_CACHE_SIZE))) - return true; - - address = TranslateAddress(address); - if (!address) - return false; - } - - if (segment == 0x0 && (address & 0x0FFFFFFF) < Memory::REALRAM_SIZE) - return true; - else if (Memory::m_pEXRAM && segment == 0x1 && (address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) - return true; - return false; + // TODO: This needs to be rewritten; it makes incorrect assumptions + // about BATs and page tables. + bool performTranslation = UReg_MSR(MSR).DR; + int segment = address >> 28; + if (performTranslation) + { + if ((segment == 0x8 || segment == 0xC || segment == 0x0) && + (address & 0x0FFFFFFF) < Memory::REALRAM_SIZE) + return true; + else if (Memory::m_pEXRAM && (segment == 0x9 || segment == 0xD) && + (address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) + return true; + else if (Memory::bFakeVMEM && (segment == 0x7 || segment == 0x4)) + return true; + else if (segment == 0xE && (address < (0xE0000000 + Memory::L1_CACHE_SIZE))) + return true; + address = TranslateAddress(address); + if (!address) + return false; + } + if (segment == 0x0 && (address & 0x0FFFFFFF) < Memory::REALRAM_SIZE) + return true; + else if (Memory::m_pEXRAM && segment == 0x1 && (address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) + return true; + return false; } void DMA_LCToMemory(const u32 memAddr, const u32 cacheAddr, const u32 numBlocks) { - // TODO: It's not completely clear this is the right spot for this code; - // what would happen if, for example, the DVD drive tried to write to the EFB? - // TODO: This is terribly slow. - // TODO: Refactor. - // Avatar: The Last Airbender (GC) uses this for videos. - if ((memAddr & 0x0F000000) == 0x08000000) - { - for (u32 i = 0; i < 32 * numBlocks; i += 4) - { - u32 data = bswap(*(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF))); - EFB_Write(data, memAddr + i); - } - return; - } + // TODO: It's not completely clear this is the right spot for this code; + // what would happen if, for example, the DVD drive tried to write to the EFB? + // TODO: This is terribly slow. + // TODO: Refactor. + // Avatar: The Last Airbender (GC) uses this for videos. + if ((memAddr & 0x0F000000) == 0x08000000) + { + for (u32 i = 0; i < 32 * numBlocks; i += 4) + { + u32 data = bswap(*(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF))); + EFB_Write(data, memAddr + i); + } + return; + } - // No known game uses this; here for completeness. - // TODO: Refactor. - if ((memAddr & 0x0F000000) == 0x0C000000) - { - for (u32 i = 0; i < 32 * numBlocks; i += 4) - { - u32 data = bswap(*(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF))); - Memory::mmio_mapping->Write(memAddr + i, data); - } - return; - } + // No known game uses this; here for completeness. + // TODO: Refactor. + if ((memAddr & 0x0F000000) == 0x0C000000) + { + for (u32 i = 0; i < 32 * numBlocks; i += 4) + { + u32 data = bswap(*(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF))); + Memory::mmio_mapping->Write(memAddr + i, data); + } + return; + } - const u8* src = Memory::m_pL1Cache + (cacheAddr & 0x3FFFF); - u8* dst = Memory::GetPointer(memAddr); - if (dst == nullptr) - return; + const u8* src = Memory::m_pL1Cache + (cacheAddr & 0x3FFFF); + u8* dst = Memory::GetPointer(memAddr); + if (dst == nullptr) + return; - memcpy(dst, src, 32 * numBlocks); + memcpy(dst, src, 32 * numBlocks); } void DMA_MemoryToLC(const u32 cacheAddr, const u32 memAddr, const u32 numBlocks) { - const u8* src = Memory::GetPointer(memAddr); - u8* dst = Memory::m_pL1Cache + (cacheAddr & 0x3FFFF); + const u8* src = Memory::GetPointer(memAddr); + u8* dst = Memory::m_pL1Cache + (cacheAddr & 0x3FFFF); - // No known game uses this; here for completeness. - // TODO: Refactor. - if ((memAddr & 0x0F000000) == 0x08000000) - { - for (u32 i = 0; i < 32 * numBlocks; i += 4) - { - u32 data = EFB_Read(memAddr + i); - *(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF)) = bswap(data); - } - return; - } + // No known game uses this; here for completeness. + // TODO: Refactor. + if ((memAddr & 0x0F000000) == 0x08000000) + { + for (u32 i = 0; i < 32 * numBlocks; i += 4) + { + u32 data = EFB_Read(memAddr + i); + *(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF)) = bswap(data); + } + return; + } - // No known game uses this. - // TODO: Refactor. - if ((memAddr & 0x0F000000) == 0x0C000000) - { - for (u32 i = 0; i < 32 * numBlocks; i += 4) - { - u32 data = Memory::mmio_mapping->Read(memAddr + i); - *(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF)) = bswap(data); - } - return; - } + // No known game uses this. + // TODO: Refactor. + if ((memAddr & 0x0F000000) == 0x0C000000) + { + for (u32 i = 0; i < 32 * numBlocks; i += 4) + { + u32 data = Memory::mmio_mapping->Read(memAddr + i); + *(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF)) = bswap(data); + } + return; + } - if (src == nullptr) - return; + if (src == nullptr) + return; - memcpy(dst, src, 32 * numBlocks); + memcpy(dst, src, 32 * numBlocks); } void ClearCacheLine(const u32 address) { - // FIXME: does this do the right thing if dcbz is run on hardware memory, e.g. - // the FIFO? Do games even do that? Probably not, but we should try to be correct... - for (u32 i = 0; i < 32; i += 8) - Write_U64(0, address + i); + // FIXME: does this do the right thing if dcbz is run on hardware memory, e.g. + // the FIFO? Do games even do that? Probably not, but we should try to be correct... + for (u32 i = 0; i < 32; i += 8) + Write_U64(0, address + i); } u32 IsOptimizableMMIOAccess(u32 address, u32 accessSize) { #ifdef ENABLE_MEM_CHECK - return 0; + return 0; #endif - if (!UReg_MSR(MSR).DR) - return 0; + if (!UReg_MSR(MSR).DR) + return 0; - if ((address & 0xF0000000) != 0xC0000000) - return 0; + if ((address & 0xF0000000) != 0xC0000000) + return 0; - unsigned translated = address & 0x0FFFFFFF; - bool aligned = (translated & ((accessSize >> 3) - 1)) == 0; - if (!aligned || !MMIO::IsMMIOAddress(translated)) - return 0; - return translated; + unsigned translated = address & 0x0FFFFFFF; + bool aligned = (translated & ((accessSize >> 3) - 1)) == 0; + if (!aligned || !MMIO::IsMMIOAddress(translated)) + return 0; + return translated; } bool IsOptimizableGatherPipeWrite(u32 address) { #ifdef ENABLE_MEM_CHECK - return false; + return false; #endif - if (!UReg_MSR(MSR).DR) - return false; + if (!UReg_MSR(MSR).DR) + return false; - return address == 0xCC008000; + return address == 0xCC008000; } // ********************************************************************************* @@ -831,275 +866,284 @@ bool IsOptimizableGatherPipeWrite(u32 address) * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define PPC_EXC_DSISR_PAGE (1 << 30) +#define PPC_EXC_DSISR_PROT (1 << 27) +#define PPC_EXC_DSISR_STORE (1 << 25) -#define PPC_EXC_DSISR_PAGE (1<<30) -#define PPC_EXC_DSISR_PROT (1<<27) -#define PPC_EXC_DSISR_STORE (1<<25) - -#define SDR1_HTABORG(v) (((v)>>16)&0xffff) +#define SDR1_HTABORG(v) (((v) >> 16) & 0xffff) #define SDR1_HTABMASK(v) ((v)&0x1ff) #define SDR1_PAGETABLE_BASE(v) ((v)&0xffff) -#define SR_T (1<<31) -#define SR_Ks (1<<30) -#define SR_Kp (1<<29) -#define SR_N (1<<28) -#define SR_VSID(v) ((v)&0xffffff) -#define SR_BUID(v) (((v)>>20)&0x1ff) +#define SR_T (1 << 31) +#define SR_Ks (1 << 30) +#define SR_Kp (1 << 29) +#define SR_N (1 << 28) +#define SR_VSID(v) ((v)&0xffffff) +#define SR_BUID(v) (((v) >> 20) & 0x1ff) #define SR_CNTRL_SPEC(v) ((v)&0xfffff) -#define EA_SR(v) (((v)>>28)&0xf) -#define EA_PageIndex(v) (((v)>>12)&0xffff) -#define EA_Offset(v) ((v)&0xfff) -#define EA_API(v) (((v)>>22)&0x3f) +#define EA_SR(v) (((v) >> 28) & 0xf) +#define EA_PageIndex(v) (((v) >> 12) & 0xffff) +#define EA_Offset(v) ((v)&0xfff) +#define EA_API(v) (((v) >> 22) & 0x3f) -#define PA_RPN(v) (((v)>>12)&0xfffff) -#define PA_Offset(v) ((v)&0xfff) +#define PA_RPN(v) (((v) >> 12) & 0xfffff) +#define PA_Offset(v) ((v)&0xfff) -#define PTE1_V (1<<31) -#define PTE1_VSID(v) (((v)>>7)&0xffffff) -#define PTE1_H (1<<6) -#define PTE1_API(v) ((v)&0x3f) +#define PTE1_V (1 << 31) +#define PTE1_VSID(v) (((v) >> 7) & 0xffffff) +#define PTE1_H (1 << 6) +#define PTE1_API(v) ((v)&0x3f) -#define PTE2_RPN(v) ((v)&0xfffff000) -#define PTE2_R (1<<8) -#define PTE2_C (1<<7) -#define PTE2_WIMG(v) (((v)>>3)&0xf) -#define PTE2_PP(v) ((v)&3) +#define PTE2_RPN(v) ((v)&0xfffff000) +#define PTE2_R (1 << 8) +#define PTE2_C (1 << 7) +#define PTE2_WIMG(v) (((v) >> 3) & 0xf) +#define PTE2_PP(v) ((v)&3) // Hey! these duplicate a structure in Gekko.h -union UPTE1 -{ - struct - { - u32 API : 6; - u32 H : 1; - u32 VSID : 24; - u32 V : 1; - }; - u32 Hex; +union UPTE1 { + struct + { + u32 API : 6; + u32 H : 1; + u32 VSID : 24; + u32 V : 1; + }; + u32 Hex; }; -union UPTE2 -{ - struct - { - u32 PP : 2; - u32 : 1; - u32 WIMG : 4; - u32 C : 1; - u32 R : 1; - u32 : 3; - u32 RPN : 20; - }; - u32 Hex; +union UPTE2 { + struct + { + u32 PP : 2; + u32 : 1; + u32 WIMG : 4; + u32 C : 1; + u32 R : 1; + u32 : 3; + u32 RPN : 20; + }; + u32 Hex; }; static void GenerateDSIException(u32 effectiveAddress, bool write) { - // DSI exceptions are only supported in MMU mode. - if (!SConfig::GetInstance().bMMU) - { - PanicAlert("Invalid %s 0x%08x, PC = 0x%08x ", write ? "write to" : "read from", effectiveAddress, PC); - return; - } + // DSI exceptions are only supported in MMU mode. + if (!SConfig::GetInstance().bMMU) + { + PanicAlert("Invalid %s 0x%08x, PC = 0x%08x ", write ? "write to" : "read from", + effectiveAddress, PC); + return; + } - if (effectiveAddress) - PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE | PPC_EXC_DSISR_STORE; - else - PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE; + if (effectiveAddress) + PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE | PPC_EXC_DSISR_STORE; + else + PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE; - PowerPC::ppcState.spr[SPR_DAR] = effectiveAddress; + PowerPC::ppcState.spr[SPR_DAR] = effectiveAddress; - PowerPC::ppcState.Exceptions |= EXCEPTION_DSI; + PowerPC::ppcState.Exceptions |= EXCEPTION_DSI; } - static void GenerateISIException(u32 _EffectiveAddress) { - // Address of instruction could not be translated - NPC = _EffectiveAddress; + // Address of instruction could not be translated + NPC = _EffectiveAddress; - PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; + PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; } - void SDRUpdated() { - u32 htabmask = SDR1_HTABMASK(PowerPC::ppcState.spr[SPR_SDR]); - u32 x = 1; - u32 xx = 0; - int n = 0; - while ((htabmask & x) && (n < 9)) - { - n++; - xx|=x; - x<<=1; - } - if (htabmask & ~xx) - { - return; - } - u32 htaborg = SDR1_HTABORG(PowerPC::ppcState.spr[SPR_SDR]); - if (htaborg & xx) - { - return; - } - PowerPC::ppcState.pagetable_base = htaborg<<16; - PowerPC::ppcState.pagetable_hashmask = ((xx<<10)|0x3ff); + u32 htabmask = SDR1_HTABMASK(PowerPC::ppcState.spr[SPR_SDR]); + u32 x = 1; + u32 xx = 0; + int n = 0; + while ((htabmask & x) && (n < 9)) + { + n++; + xx |= x; + x <<= 1; + } + if (htabmask & ~xx) + { + return; + } + u32 htaborg = SDR1_HTABORG(PowerPC::ppcState.spr[SPR_SDR]); + if (htaborg & xx) + { + return; + } + PowerPC::ppcState.pagetable_base = htaborg << 16; + PowerPC::ppcState.pagetable_hashmask = ((xx << 10) | 0x3ff); } enum TLBLookupResult { - TLB_FOUND, - TLB_NOTFOUND, - TLB_UPDATE_C + TLB_FOUND, + TLB_NOTFOUND, + TLB_UPDATE_C }; -static __forceinline TLBLookupResult LookupTLBPageAddress(const XCheckTLBFlag flag, const u32 vpa, u32 *paddr) +static __forceinline TLBLookupResult LookupTLBPageAddress(const XCheckTLBFlag flag, const u32 vpa, + u32* paddr) { - u32 tag = vpa >> HW_PAGE_INDEX_SHIFT; - PowerPC::tlb_entry *tlbe = &PowerPC::ppcState.tlb[flag == FLAG_OPCODE][tag & HW_PAGE_INDEX_MASK]; - if (tlbe->tag[0] == tag) - { - // Check if C bit requires updating - if (flag == FLAG_WRITE) - { - UPTE2 PTE2; - PTE2.Hex = tlbe->pte[0]; - if (PTE2.C == 0) - { - PTE2.C = 1; - tlbe->pte[0] = PTE2.Hex; - return TLB_UPDATE_C; - } - } + u32 tag = vpa >> HW_PAGE_INDEX_SHIFT; + PowerPC::tlb_entry* tlbe = &PowerPC::ppcState.tlb[flag == FLAG_OPCODE][tag & HW_PAGE_INDEX_MASK]; + if (tlbe->tag[0] == tag) + { + // Check if C bit requires updating + if (flag == FLAG_WRITE) + { + UPTE2 PTE2; + PTE2.Hex = tlbe->pte[0]; + if (PTE2.C == 0) + { + PTE2.C = 1; + tlbe->pte[0] = PTE2.Hex; + return TLB_UPDATE_C; + } + } - if (flag != FLAG_NO_EXCEPTION) - tlbe->recent = 0; + if (flag != FLAG_NO_EXCEPTION) + tlbe->recent = 0; - *paddr = tlbe->paddr[0] | (vpa & 0xfff); + *paddr = tlbe->paddr[0] | (vpa & 0xfff); - return TLB_FOUND; - } - if (tlbe->tag[1] == tag) - { - // Check if C bit requires updating - if (flag == FLAG_WRITE) - { - UPTE2 PTE2; - PTE2.Hex = tlbe->pte[1]; - if (PTE2.C == 0) - { - PTE2.C = 1; - tlbe->pte[1] = PTE2.Hex; - return TLB_UPDATE_C; - } - } + return TLB_FOUND; + } + if (tlbe->tag[1] == tag) + { + // Check if C bit requires updating + if (flag == FLAG_WRITE) + { + UPTE2 PTE2; + PTE2.Hex = tlbe->pte[1]; + if (PTE2.C == 0) + { + PTE2.C = 1; + tlbe->pte[1] = PTE2.Hex; + return TLB_UPDATE_C; + } + } - if (flag != FLAG_NO_EXCEPTION) - tlbe->recent = 1; + if (flag != FLAG_NO_EXCEPTION) + tlbe->recent = 1; - *paddr = tlbe->paddr[1] | (vpa & 0xfff); + *paddr = tlbe->paddr[1] | (vpa & 0xfff); - return TLB_FOUND; - } - return TLB_NOTFOUND; + return TLB_FOUND; + } + return TLB_NOTFOUND; } static __forceinline void UpdateTLBEntry(const XCheckTLBFlag flag, UPTE2 PTE2, const u32 address) { - if (flag == FLAG_NO_EXCEPTION) - return; + if (flag == FLAG_NO_EXCEPTION) + return; - int tag = address >> HW_PAGE_INDEX_SHIFT; - PowerPC::tlb_entry *tlbe = &PowerPC::ppcState.tlb[flag == FLAG_OPCODE][tag & HW_PAGE_INDEX_MASK]; - int index = tlbe->recent == 0 && tlbe->tag[0] != TLB_TAG_INVALID; - tlbe->recent = index; - tlbe->paddr[index] = PTE2.RPN << HW_PAGE_INDEX_SHIFT; - tlbe->pte[index] = PTE2.Hex; - tlbe->tag[index] = tag; + int tag = address >> HW_PAGE_INDEX_SHIFT; + PowerPC::tlb_entry* tlbe = &PowerPC::ppcState.tlb[flag == FLAG_OPCODE][tag & HW_PAGE_INDEX_MASK]; + int index = tlbe->recent == 0 && tlbe->tag[0] != TLB_TAG_INVALID; + tlbe->recent = index; + tlbe->paddr[index] = PTE2.RPN << HW_PAGE_INDEX_SHIFT; + tlbe->pte[index] = PTE2.Hex; + tlbe->tag[index] = tag; } void InvalidateTLBEntry(u32 address) { - PowerPC::tlb_entry *tlbe = &PowerPC::ppcState.tlb[0][(address >> HW_PAGE_INDEX_SHIFT) & HW_PAGE_INDEX_MASK]; - tlbe->tag[0] = TLB_TAG_INVALID; - tlbe->tag[1] = TLB_TAG_INVALID; - PowerPC::tlb_entry *tlbe_i = &PowerPC::ppcState.tlb[1][(address >> HW_PAGE_INDEX_SHIFT) & HW_PAGE_INDEX_MASK]; - tlbe_i->tag[0] = TLB_TAG_INVALID; - tlbe_i->tag[1] = TLB_TAG_INVALID; + PowerPC::tlb_entry* tlbe = + &PowerPC::ppcState.tlb[0][(address >> HW_PAGE_INDEX_SHIFT) & HW_PAGE_INDEX_MASK]; + tlbe->tag[0] = TLB_TAG_INVALID; + tlbe->tag[1] = TLB_TAG_INVALID; + PowerPC::tlb_entry* tlbe_i = + &PowerPC::ppcState.tlb[1][(address >> HW_PAGE_INDEX_SHIFT) & HW_PAGE_INDEX_MASK]; + tlbe_i->tag[0] = TLB_TAG_INVALID; + tlbe_i->tag[1] = TLB_TAG_INVALID; } // Page Address Translation static __forceinline u32 TranslatePageAddress(const u32 address, const XCheckTLBFlag flag) { - // TLB cache - // This catches 99%+ of lookups in practice, so the actual page table entry code below doesn't benefit - // much from optimization. - u32 translatedAddress = 0; - TLBLookupResult res = LookupTLBPageAddress(flag , address, &translatedAddress); - if (res == TLB_FOUND) - return translatedAddress; + // TLB cache + // This catches 99%+ of lookups in practice, so the actual page table entry code below doesn't + // benefit + // much from optimization. + u32 translatedAddress = 0; + TLBLookupResult res = LookupTLBPageAddress(flag, address, &translatedAddress); + if (res == TLB_FOUND) + return translatedAddress; - u32 sr = PowerPC::ppcState.sr[EA_SR(address)]; + u32 sr = PowerPC::ppcState.sr[EA_SR(address)]; - u32 offset = EA_Offset(address); // 12 bit - u32 page_index = EA_PageIndex(address); // 16 bit - u32 VSID = SR_VSID(sr); // 24 bit - u32 api = EA_API(address); // 6 bit (part of page_index) + u32 offset = EA_Offset(address); // 12 bit + u32 page_index = EA_PageIndex(address); // 16 bit + u32 VSID = SR_VSID(sr); // 24 bit + u32 api = EA_API(address); // 6 bit (part of page_index) - // hash function no 1 "xor" .360 - u32 hash = (VSID ^ page_index); - u32 pte1 = bswap((VSID << 7) | api | PTE1_V); + // hash function no 1 "xor" .360 + u32 hash = (VSID ^ page_index); + u32 pte1 = bswap((VSID << 7) | api | PTE1_V); - for (int hash_func = 0; hash_func < 2; hash_func++) - { - // hash function no 2 "not" .360 - if (hash_func == 1) - { - hash = ~hash; - pte1 |= PTE1_H << 24; - } + for (int hash_func = 0; hash_func < 2; hash_func++) + { + // hash function no 2 "not" .360 + if (hash_func == 1) + { + hash = ~hash; + pte1 |= PTE1_H << 24; + } - u32 pteg_addr = ((hash & PowerPC::ppcState.pagetable_hashmask) << 6) | PowerPC::ppcState.pagetable_base; + u32 pteg_addr = + ((hash & PowerPC::ppcState.pagetable_hashmask) << 6) | PowerPC::ppcState.pagetable_base; - for (int i = 0; i < 8; i++, pteg_addr += 8) - { - if (pte1 == *(u32*)&Memory::physical_base[pteg_addr]) - { - UPTE2 PTE2; - PTE2.Hex = bswap((*(u32*)&Memory::physical_base[pteg_addr + 4])); + for (int i = 0; i < 8; i++, pteg_addr += 8) + { + if (pte1 == *(u32*)&Memory::physical_base[pteg_addr]) + { + UPTE2 PTE2; + PTE2.Hex = bswap((*(u32*)&Memory::physical_base[pteg_addr + 4])); - // set the access bits - switch (flag) - { - case FLAG_NO_EXCEPTION: break; - case FLAG_READ: PTE2.R = 1; break; - case FLAG_WRITE: PTE2.R = 1; PTE2.C = 1; break; - case FLAG_OPCODE: PTE2.R = 1; break; - } + // set the access bits + switch (flag) + { + case FLAG_NO_EXCEPTION: + break; + case FLAG_READ: + PTE2.R = 1; + break; + case FLAG_WRITE: + PTE2.R = 1; + PTE2.C = 1; + break; + case FLAG_OPCODE: + PTE2.R = 1; + break; + } - if (flag != FLAG_NO_EXCEPTION) - *(u32*)&Memory::physical_base[pteg_addr + 4] = bswap(PTE2.Hex); + if (flag != FLAG_NO_EXCEPTION) + *(u32*)&Memory::physical_base[pteg_addr + 4] = bswap(PTE2.Hex); - // We already updated the TLB entry if this was caused by a C bit. - if (res != TLB_UPDATE_C) - UpdateTLBEntry(flag, PTE2, address); + // We already updated the TLB entry if this was caused by a C bit. + if (res != TLB_UPDATE_C) + UpdateTLBEntry(flag, PTE2, address); - return (PTE2.RPN << 12) | offset; - } - } - } - return 0; + return (PTE2.RPN << 12) | offset; + } + } + } + return 0; } // Translate effective address using BAT or PAT. Returns 0 if the address cannot be translated. template __forceinline u32 TranslateAddress(const u32 address) { - // TODO: Perform BAT translation. (At the moment, we hardcode an assumed BAT - // configuration, so there's no reason to actually check the registers.) - return TranslatePageAddress(address, flag); + // TODO: Perform BAT translation. (At the moment, we hardcode an assumed BAT + // configuration, so there's no reason to actually check the registers.) + return TranslatePageAddress(address, flag); } -} // namespace +} // namespace diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/PowerPC/PPCAnalyst.cpp index 3743300bbf..43a5f041fe 100644 --- a/Source/Core/Core/PowerPC/PPCAnalyst.cpp +++ b/Source/Core/Core/PowerPC/PPCAnalyst.cpp @@ -9,12 +9,12 @@ #include "Common/CommonTypes.h" #include "Common/StringUtil.h" #include "Core/ConfigManager.h" -#include "Core/PowerPC/PowerPC.h" +#include "Core/PowerPC/JitCommon/JitCache.h" #include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/PPCSymbolDB.h" #include "Core/PowerPC/PPCTables.h" +#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/SignatureDB.h" -#include "Core/PowerPC/JitCommon/JitCache.h" // Analyzes PowerPC code in memory to find functions // After running, for each function we will know what functions it calls @@ -24,7 +24,8 @@ // The results of this analysis is displayed in the code browsing sections at the bottom left // of the disassembly window (debugger). -// It is also useful for finding function boundaries so that we can find, fingerprint and detect library functions. +// It is also useful for finding function boundaries so that we can find, fingerprint and detect +// library functions. // We don't do this much currently. Only for the special case Super Monkey Ball. namespace PPCAnalyst @@ -35,747 +36,753 @@ static const u32 FUNCTION_FOLLOWING_THRESHOLD = 16; CodeBuffer::CodeBuffer(int size) { - codebuffer = new PPCAnalyst::CodeOp[size]; - size_ = size; + codebuffer = new PPCAnalyst::CodeOp[size]; + size_ = size; } CodeBuffer::~CodeBuffer() { - delete[] codebuffer; + delete[] codebuffer; } #define INVALID_TARGET ((u32)-1) static u32 EvaluateBranchTarget(UGeckoInstruction instr, u32 pc) { - switch (instr.OPCD) - { - case 18://branch instruction - { - u32 target = SignExt26(instr.LI<<2); - if (!instr.AA) - target += pc; + switch (instr.OPCD) + { + case 18: // branch instruction + { + u32 target = SignExt26(instr.LI << 2); + if (!instr.AA) + target += pc; - return target; - } - default: - return INVALID_TARGET; - } + return target; + } + default: + return INVALID_TARGET; + } } -//To find the size of each found function, scan -//forward until we hit blr. In the meantime, collect information -//about which functions this function calls. -//Also collect which internal branch goes the farthest -//If any one goes farther than the blr, assume that there is more than -//one blr, and keep scanning. +// To find the size of each found function, scan +// forward until we hit blr. In the meantime, collect information +// about which functions this function calls. +// Also collect which internal branch goes the farthest +// If any one goes farther than the blr, assume that there is more than +// one blr, and keep scanning. -bool AnalyzeFunction(u32 startAddr, Symbol &func, int max_size) +bool AnalyzeFunction(u32 startAddr, Symbol& func, int max_size) { - if (!func.name.size()) - func.name = StringFromFormat("zz_%07x_", startAddr & 0x0FFFFFF); - if (func.analyzed >= 1) - return true; // No error, just already did it. + if (!func.name.size()) + func.name = StringFromFormat("zz_%07x_", startAddr & 0x0FFFFFF); + if (func.analyzed >= 1) + return true; // No error, just already did it. - func.calls.clear(); - func.callers.clear(); - func.size = 0; - func.flags = FFLAG_LEAF; - u32 addr = startAddr; + func.calls.clear(); + func.callers.clear(); + func.size = 0; + func.flags = FFLAG_LEAF; + u32 addr = startAddr; - u32 farthestInternalBranchTarget = startAddr; - int numInternalBranches = 0; - while (true) - { - func.size += 4; - if (func.size >= CODEBUFFER_SIZE * 4) //weird - return false; + u32 farthestInternalBranchTarget = startAddr; + int numInternalBranches = 0; + while (true) + { + func.size += 4; + if (func.size >= CODEBUFFER_SIZE * 4) // weird + return false; - UGeckoInstruction instr = (UGeckoInstruction)PowerPC::HostRead_U32(addr); - if (max_size && func.size > max_size) - { - func.address = startAddr; - func.analyzed = 1; - func.hash = SignatureDB::ComputeCodeChecksum(startAddr, addr); - if (numInternalBranches == 0) - func.flags |= FFLAG_STRAIGHT; - return true; - } - if (PPCTables::IsValidInstruction(instr)) - { - if (instr.hex == 0x4e800020) //4e800021 is blrl, not the end of a function - { - //BLR - if (farthestInternalBranchTarget > addr) - { - //bah, not this one, continue.. - } - else - { - //a final blr! - //We're done! Looks like we have a neat valid function. Perfect. - //Let's calc the checksum and get outta here - func.address = startAddr; - func.analyzed = 1; - func.hash = SignatureDB::ComputeCodeChecksum(startAddr, addr); - if (numInternalBranches == 0) - func.flags |= FFLAG_STRAIGHT; - return true; - } - } - /* - else if ((instr.hex & 0xFC000000) == (0x4b000000 & 0xFC000000) && !instr.LK) - { - u32 target = addr + SignExt26(instr.LI << 2); - if (target < startAddr || (max_size && target > max_size+startAddr)) - { - //block ends by branching away. We're done! - func.size *= 4; // into bytes - func.address = startAddr; - func.analyzed = 1; - func.hash = SignatureDB::ComputeCodeChecksum(startAddr, addr); - if (numInternalBranches == 0) - func.flags |= FFLAG_STRAIGHT; - return true; - } - }*/ - else if (instr.hex == 0x4e800021 || instr.hex == 0x4e800420 || instr.hex == 0x4e800421) - { - func.flags &= ~FFLAG_LEAF; - func.flags |= FFLAG_EVIL; - } - else if (instr.hex == 0x4c000064) - { - func.flags &= ~FFLAG_LEAF; - func.flags |= FFLAG_RFI; - } - else - { - if (instr.OPCD == 16) - { - u32 target = SignExt16(instr.BD << 2); + UGeckoInstruction instr = (UGeckoInstruction)PowerPC::HostRead_U32(addr); + if (max_size && func.size > max_size) + { + func.address = startAddr; + func.analyzed = 1; + func.hash = SignatureDB::ComputeCodeChecksum(startAddr, addr); + if (numInternalBranches == 0) + func.flags |= FFLAG_STRAIGHT; + return true; + } + if (PPCTables::IsValidInstruction(instr)) + { + if (instr.hex == 0x4e800020) // 4e800021 is blrl, not the end of a function + { + // BLR + if (farthestInternalBranchTarget > addr) + { + // bah, not this one, continue.. + } + else + { + // a final blr! + // We're done! Looks like we have a neat valid function. Perfect. + // Let's calc the checksum and get outta here + func.address = startAddr; + func.analyzed = 1; + func.hash = SignatureDB::ComputeCodeChecksum(startAddr, addr); + if (numInternalBranches == 0) + func.flags |= FFLAG_STRAIGHT; + return true; + } + } + /* + else if ((instr.hex & 0xFC000000) == (0x4b000000 & 0xFC000000) && !instr.LK) + { + u32 target = addr + SignExt26(instr.LI << 2); + if (target < startAddr || (max_size && target > max_size+startAddr)) + { + //block ends by branching away. We're done! + func.size *= 4; // into bytes + func.address = startAddr; + func.analyzed = 1; + func.hash = SignatureDB::ComputeCodeChecksum(startAddr, addr); + if (numInternalBranches == 0) + func.flags |= FFLAG_STRAIGHT; + return true; + } + }*/ + else if (instr.hex == 0x4e800021 || instr.hex == 0x4e800420 || instr.hex == 0x4e800421) + { + func.flags &= ~FFLAG_LEAF; + func.flags |= FFLAG_EVIL; + } + else if (instr.hex == 0x4c000064) + { + func.flags &= ~FFLAG_LEAF; + func.flags |= FFLAG_RFI; + } + else + { + if (instr.OPCD == 16) + { + u32 target = SignExt16(instr.BD << 2); - if (!instr.AA) - target += addr; + if (!instr.AA) + target += addr; - if (target > farthestInternalBranchTarget && !instr.LK) - { - farthestInternalBranchTarget = target; - } - numInternalBranches++; - } - else - { - u32 target = EvaluateBranchTarget(instr, addr); - if (target != INVALID_TARGET && instr.LK) - { - //we found a branch-n-link! - func.calls.emplace_back(target, addr); - func.flags &= ~FFLAG_LEAF; - } - } - } - } - else - { - return false; - } - addr += 4; - } + if (target > farthestInternalBranchTarget && !instr.LK) + { + farthestInternalBranchTarget = target; + } + numInternalBranches++; + } + else + { + u32 target = EvaluateBranchTarget(instr, addr); + if (target != INVALID_TARGET && instr.LK) + { + // we found a branch-n-link! + func.calls.emplace_back(target, addr); + func.flags &= ~FFLAG_LEAF; + } + } + } + } + else + { + return false; + } + addr += 4; + } } - // Second pass analysis, done after the first pass is done for all functions // so we have more information to work with -static void AnalyzeFunction2(Symbol *func) +static void AnalyzeFunction2(Symbol* func) { - u32 flags = func->flags; + u32 flags = func->flags; - bool nonleafcall = false; - for (const SCall& c : func->calls) - { - Symbol *called_func = g_symbolDB.GetSymbolFromAddr(c.function); - if (called_func && (called_func->flags & FFLAG_LEAF) == 0) - { - nonleafcall = true; - break; - } - } + bool nonleafcall = false; + for (const SCall& c : func->calls) + { + Symbol* called_func = g_symbolDB.GetSymbolFromAddr(c.function); + if (called_func && (called_func->flags & FFLAG_LEAF) == 0) + { + nonleafcall = true; + break; + } + } - if (nonleafcall && !(flags & FFLAG_EVIL) && !(flags & FFLAG_RFI)) - flags |= FFLAG_ONLYCALLSNICELEAFS; + if (nonleafcall && !(flags & FFLAG_EVIL) && !(flags & FFLAG_RFI)) + flags |= FFLAG_ONLYCALLSNICELEAFS; - func->flags = flags; + func->flags = flags; } -static bool CanSwapAdjacentOps(const CodeOp &a, const CodeOp &b) +static bool CanSwapAdjacentOps(const CodeOp& a, const CodeOp& b) { - const GekkoOPInfo *a_info = a.opinfo; - const GekkoOPInfo *b_info = b.opinfo; - int a_flags = a_info->flags; - int b_flags = b_info->flags; + const GekkoOPInfo* a_info = a.opinfo; + const GekkoOPInfo* b_info = b.opinfo; + int a_flags = a_info->flags; + int b_flags = b_info->flags; - // can't reorder around breakpoints - if (SConfig::GetInstance().bEnableDebugging && - (PowerPC::breakpoints.IsAddressBreakPoint(a.address) || PowerPC::breakpoints.IsAddressBreakPoint(b.address))) - return false; - if (b_flags & (FL_SET_CRx | FL_ENDBLOCK | FL_TIMER | FL_EVIL | FL_SET_OE)) - return false; - if ((b_flags & (FL_RC_BIT | FL_RC_BIT_F)) && (b.inst.Rc)) - return false; - if ((a_flags & (FL_SET_CA | FL_READ_CA)) && (b_flags & (FL_SET_CA | FL_READ_CA))) - return false; + // can't reorder around breakpoints + if (SConfig::GetInstance().bEnableDebugging && + (PowerPC::breakpoints.IsAddressBreakPoint(a.address) || + PowerPC::breakpoints.IsAddressBreakPoint(b.address))) + return false; + if (b_flags & (FL_SET_CRx | FL_ENDBLOCK | FL_TIMER | FL_EVIL | FL_SET_OE)) + return false; + if ((b_flags & (FL_RC_BIT | FL_RC_BIT_F)) && (b.inst.Rc)) + return false; + if ((a_flags & (FL_SET_CA | FL_READ_CA)) && (b_flags & (FL_SET_CA | FL_READ_CA))) + return false; - switch (b.inst.OPCD) - { - case 16: - case 18: - //branches. Do not swap. - case 17: //sc - case 46: //lmw - case 19: //table19 - lots of tricky stuff - return false; - } + switch (b.inst.OPCD) + { + case 16: + case 18: + // branches. Do not swap. + case 17: // sc + case 46: // lmw + case 19: // table19 - lots of tricky stuff + return false; + } - // For now, only integer ops acceptable. Any instruction which can raise an - // interrupt is *not* a possible swap candidate: see [1] for an example of - // a crash caused by this error. - // - // [1] https://bugs.dolphin-emu.org/issues/5864#note-7 - if (b_info->type != OPTYPE_INTEGER) - return false; + // For now, only integer ops acceptable. Any instruction which can raise an + // interrupt is *not* a possible swap candidate: see [1] for an example of + // a crash caused by this error. + // + // [1] https://bugs.dolphin-emu.org/issues/5864#note-7 + if (b_info->type != OPTYPE_INTEGER) + return false; - // And it's possible a might raise an interrupt too (fcmpo/fcmpu) - if (a_info->type != OPTYPE_INTEGER) - return false; + // And it's possible a might raise an interrupt too (fcmpo/fcmpu) + if (a_info->type != OPTYPE_INTEGER) + return false; - // Check that we have no register collisions. - // That is, check that none of b's outputs matches any of a's inputs, - // and that none of a's outputs matches any of b's inputs. - // The latter does not apply if a is a cmp, of course, but doesn't hurt to check. - // register collision: b outputs to one of a's inputs - if (b.regsOut & a.regsIn) - return false; - // register collision: a outputs to one of b's inputs - if (a.regsOut & b.regsIn) - return false; - // register collision: b outputs to one of a's outputs (overwriting it) - if (b.regsOut & a.regsOut) - return false; + // Check that we have no register collisions. + // That is, check that none of b's outputs matches any of a's inputs, + // and that none of a's outputs matches any of b's inputs. + // The latter does not apply if a is a cmp, of course, but doesn't hurt to check. + // register collision: b outputs to one of a's inputs + if (b.regsOut & a.regsIn) + return false; + // register collision: a outputs to one of b's inputs + if (a.regsOut & b.regsIn) + return false; + // register collision: b outputs to one of a's outputs (overwriting it) + if (b.regsOut & a.regsOut) + return false; - return true; + return true; } // Most functions that are relevant to analyze should be // called by another function. Therefore, let's scan the // entire space for bl operations and find what functions // get called. -static void FindFunctionsFromBranches(u32 startAddr, u32 endAddr, SymbolDB *func_db) +static void FindFunctionsFromBranches(u32 startAddr, u32 endAddr, SymbolDB* func_db) { - for (u32 addr = startAddr; addr < endAddr; addr+=4) - { - UGeckoInstruction instr = (UGeckoInstruction)PowerPC::HostRead_U32(addr); + for (u32 addr = startAddr; addr < endAddr; addr += 4) + { + UGeckoInstruction instr = (UGeckoInstruction)PowerPC::HostRead_U32(addr); - if (PPCTables::IsValidInstruction(instr)) - { - switch (instr.OPCD) - { - case 18://branch instruction - { - if (instr.LK) //bl - { - u32 target = SignExt26(instr.LI << 2); - if (!instr.AA) - target += addr; - if (PowerPC::HostIsRAMAddress(target)) - { - func_db->AddFunction(target); - } - } - } - break; - default: - break; - } - } - } + if (PPCTables::IsValidInstruction(instr)) + { + switch (instr.OPCD) + { + case 18: // branch instruction + { + if (instr.LK) // bl + { + u32 target = SignExt26(instr.LI << 2); + if (!instr.AA) + target += addr; + if (PowerPC::HostIsRAMAddress(target)) + { + func_db->AddFunction(target); + } + } + } + break; + default: + break; + } + } + } } -static void FindFunctionsAfterBLR(PPCSymbolDB *func_db) +static void FindFunctionsAfterBLR(PPCSymbolDB* func_db) { - std::vector funcAddrs; + std::vector funcAddrs; - for (const auto& func : func_db->Symbols()) - funcAddrs.push_back(func.second.address + func.second.size); + for (const auto& func : func_db->Symbols()) + funcAddrs.push_back(func.second.address + func.second.size); - for (u32& location : funcAddrs) - { - while (true) - { - // skip zeroes that sometimes pad function to 16 byte boundary (e.g. Donkey Kong Country Returns) - while (PowerPC::HostRead_Instruction(location) == 0 && ((location & 0xf) != 0)) - location += 4; - if (PPCTables::IsValidInstruction(PowerPC::HostRead_Instruction(location))) - { - //check if this function is already mapped - Symbol *f = func_db->AddFunction(location); - if (!f) - break; - else - location += f->size; - } - else - break; - } - } + for (u32& location : funcAddrs) + { + while (true) + { + // skip zeroes that sometimes pad function to 16 byte boundary (e.g. Donkey Kong Country + // Returns) + while (PowerPC::HostRead_Instruction(location) == 0 && ((location & 0xf) != 0)) + location += 4; + if (PPCTables::IsValidInstruction(PowerPC::HostRead_Instruction(location))) + { + // check if this function is already mapped + Symbol* f = func_db->AddFunction(location); + if (!f) + break; + else + location += f->size; + } + else + break; + } + } } -void FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB *func_db) +void FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB* func_db) { - //Step 1: Find all functions - FindFunctionsFromBranches(startAddr, endAddr, func_db); - FindFunctionsAfterBLR(func_db); + // Step 1: Find all functions + FindFunctionsFromBranches(startAddr, endAddr, func_db); + FindFunctionsAfterBLR(func_db); - //Step 2: - func_db->FillInCallers(); + // Step 2: + func_db->FillInCallers(); - int numLeafs = 0, numNice = 0, numUnNice = 0; - int numTimer = 0, numRFI = 0, numStraightLeaf = 0; - int leafSize = 0, niceSize = 0, unniceSize = 0; - for (auto& func : func_db->AccessSymbols()) - { - if (func.second.address == 4) - { - WARN_LOG(OSHLE, "Weird function"); - continue; - } - AnalyzeFunction2(&(func.second)); - Symbol &f = func.second; - if (f.name.substr(0, 3) == "zzz") - { - if (f.flags & FFLAG_LEAF) - f.name += "_leaf"; - if (f.flags & FFLAG_STRAIGHT) - f.name += "_straight"; - } - if (f.flags & FFLAG_LEAF) - { - numLeafs++; - leafSize += f.size; - } - else if (f.flags & FFLAG_ONLYCALLSNICELEAFS) - { - numNice++; - niceSize += f.size; - } - else - { - numUnNice++; - unniceSize += f.size; - } + int numLeafs = 0, numNice = 0, numUnNice = 0; + int numTimer = 0, numRFI = 0, numStraightLeaf = 0; + int leafSize = 0, niceSize = 0, unniceSize = 0; + for (auto& func : func_db->AccessSymbols()) + { + if (func.second.address == 4) + { + WARN_LOG(OSHLE, "Weird function"); + continue; + } + AnalyzeFunction2(&(func.second)); + Symbol& f = func.second; + if (f.name.substr(0, 3) == "zzz") + { + if (f.flags & FFLAG_LEAF) + f.name += "_leaf"; + if (f.flags & FFLAG_STRAIGHT) + f.name += "_straight"; + } + if (f.flags & FFLAG_LEAF) + { + numLeafs++; + leafSize += f.size; + } + else if (f.flags & FFLAG_ONLYCALLSNICELEAFS) + { + numNice++; + niceSize += f.size; + } + else + { + numUnNice++; + unniceSize += f.size; + } - if (f.flags & FFLAG_TIMERINSTRUCTIONS) - numTimer++; - if (f.flags & FFLAG_RFI) - numRFI++; - if ((f.flags & FFLAG_STRAIGHT) && (f.flags & FFLAG_LEAF)) - numStraightLeaf++; - } - if (numLeafs == 0) - leafSize = 0; - else - leafSize /= numLeafs; + if (f.flags & FFLAG_TIMERINSTRUCTIONS) + numTimer++; + if (f.flags & FFLAG_RFI) + numRFI++; + if ((f.flags & FFLAG_STRAIGHT) && (f.flags & FFLAG_LEAF)) + numStraightLeaf++; + } + if (numLeafs == 0) + leafSize = 0; + else + leafSize /= numLeafs; - if (numNice == 0) - niceSize = 0; - else - niceSize /= numNice; + if (numNice == 0) + niceSize = 0; + else + niceSize /= numNice; - if (numUnNice == 0) - unniceSize = 0; - else - unniceSize /= numUnNice; + if (numUnNice == 0) + unniceSize = 0; + else + unniceSize /= numUnNice; - INFO_LOG(OSHLE, "Functions analyzed. %i leafs, %i nice, %i unnice." - "%i timer, %i rfi. %i are branchless leafs.", numLeafs, - numNice, numUnNice, numTimer, numRFI, numStraightLeaf); - INFO_LOG(OSHLE, "Average size: %i (leaf), %i (nice), %i(unnice)", - leafSize, niceSize, unniceSize); + INFO_LOG(OSHLE, "Functions analyzed. %i leafs, %i nice, %i unnice." + "%i timer, %i rfi. %i are branchless leafs.", + numLeafs, numNice, numUnNice, numTimer, numRFI, numStraightLeaf); + INFO_LOG(OSHLE, "Average size: %i (leaf), %i (nice), %i(unnice)", leafSize, niceSize, unniceSize); } static bool isCmp(const CodeOp& a) { - return (a.inst.OPCD == 10 || a.inst.OPCD == 11) || (a.inst.OPCD == 31 && (a.inst.SUBOP10 == 0 || a.inst.SUBOP10 == 32)); + return (a.inst.OPCD == 10 || a.inst.OPCD == 11) || + (a.inst.OPCD == 31 && (a.inst.SUBOP10 == 0 || a.inst.SUBOP10 == 32)); } static bool isCarryOp(const CodeOp& a) { - return (a.opinfo->flags & FL_SET_CA) && !(a.opinfo->flags & FL_SET_OE) && a.opinfo->type == OPTYPE_INTEGER; + return (a.opinfo->flags & FL_SET_CA) && !(a.opinfo->flags & FL_SET_OE) && + a.opinfo->type == OPTYPE_INTEGER; } static bool isCror(const CodeOp& a) { - return a.inst.OPCD == 19 && a.inst.SUBOP10 == 449; + return a.inst.OPCD == 19 && a.inst.SUBOP10 == 449; } -void PPCAnalyzer::ReorderInstructionsCore(u32 instructions, CodeOp* code, bool reverse, ReorderType type) +void PPCAnalyzer::ReorderInstructionsCore(u32 instructions, CodeOp* code, bool reverse, + ReorderType type) { - // Bubbling an instruction sometimes reveals another opportunity to bubble an instruction, so do - // multiple passes. - while (true) - { - // Instruction Reordering Pass - // Carry pass: bubble carry-using instructions as close to each other as possible, so we can avoid - // storing the carry flag. - // Compare pass: bubble compare instructions next to branches, so they can be merged. - bool swapped = false; - int increment = reverse ? -1 : 1; - int start = reverse ? instructions - 1 : 0; - int end = reverse ? 0 : instructions - 1; - for (int i = start; i != end; i += increment) - { - CodeOp &a = code[i]; - CodeOp &b = code[i + increment]; - // Reorder integer compares, rlwinm., and carry-affecting ops - // (if we add more merged branch instructions, add them here!) - if ((type == REORDER_CROR && isCror(a)) || (type == REORDER_CARRY && isCarryOp(a)) || (type == REORDER_CMP && (isCmp(a) || a.outputCR0))) - { - // once we're next to a carry instruction, don't move away! - if (type == REORDER_CARRY && i != start) - { - // if we read the CA flag, and the previous instruction sets it, don't move away. - if (!reverse && (a.opinfo->flags & FL_READ_CA) && (code[i - increment].opinfo->flags & FL_SET_CA)) - continue; - // if we set the CA flag, and the next instruction reads it, don't move away. - if (reverse && (a.opinfo->flags & FL_SET_CA) && (code[i - increment].opinfo->flags & FL_READ_CA)) - continue; - } + // Bubbling an instruction sometimes reveals another opportunity to bubble an instruction, so do + // multiple passes. + while (true) + { + // Instruction Reordering Pass + // Carry pass: bubble carry-using instructions as close to each other as possible, so we can + // avoid + // storing the carry flag. + // Compare pass: bubble compare instructions next to branches, so they can be merged. + bool swapped = false; + int increment = reverse ? -1 : 1; + int start = reverse ? instructions - 1 : 0; + int end = reverse ? 0 : instructions - 1; + for (int i = start; i != end; i += increment) + { + CodeOp& a = code[i]; + CodeOp& b = code[i + increment]; + // Reorder integer compares, rlwinm., and carry-affecting ops + // (if we add more merged branch instructions, add them here!) + if ((type == REORDER_CROR && isCror(a)) || (type == REORDER_CARRY && isCarryOp(a)) || + (type == REORDER_CMP && (isCmp(a) || a.outputCR0))) + { + // once we're next to a carry instruction, don't move away! + if (type == REORDER_CARRY && i != start) + { + // if we read the CA flag, and the previous instruction sets it, don't move away. + if (!reverse && (a.opinfo->flags & FL_READ_CA) && + (code[i - increment].opinfo->flags & FL_SET_CA)) + continue; + // if we set the CA flag, and the next instruction reads it, don't move away. + if (reverse && (a.opinfo->flags & FL_SET_CA) && + (code[i - increment].opinfo->flags & FL_READ_CA)) + continue; + } - if (CanSwapAdjacentOps(a, b)) - { - // Alright, let's bubble it! - std::swap(a, b); - swapped = true; - } - } - } - if (!swapped) - return; - } + if (CanSwapAdjacentOps(a, b)) + { + // Alright, let's bubble it! + std::swap(a, b); + swapped = true; + } + } + } + if (!swapped) + return; + } } -void PPCAnalyzer::ReorderInstructions(u32 instructions, CodeOp *code) +void PPCAnalyzer::ReorderInstructions(u32 instructions, CodeOp* code) { - // Reorder cror instructions upwards (e.g. towards an fcmp). Technically we should be more - // picky about this, but cror seems to almost solely be used for this purpose in real code. - // Additionally, the other boolean ops seem to almost never be used. - if (HasOption(OPTION_CROR_MERGE)) - ReorderInstructionsCore(instructions, code, true, REORDER_CROR); - // For carry, bubble instructions *towards* each other; one direction often isn't enough - // to get pairs like addc/adde next to each other. - if (HasOption(OPTION_CARRY_MERGE)) - { - ReorderInstructionsCore(instructions, code, false, REORDER_CARRY); - ReorderInstructionsCore(instructions, code, true, REORDER_CARRY); - } - if (HasOption(OPTION_BRANCH_MERGE)) - ReorderInstructionsCore(instructions, code, false, REORDER_CMP); + // Reorder cror instructions upwards (e.g. towards an fcmp). Technically we should be more + // picky about this, but cror seems to almost solely be used for this purpose in real code. + // Additionally, the other boolean ops seem to almost never be used. + if (HasOption(OPTION_CROR_MERGE)) + ReorderInstructionsCore(instructions, code, true, REORDER_CROR); + // For carry, bubble instructions *towards* each other; one direction often isn't enough + // to get pairs like addc/adde next to each other. + if (HasOption(OPTION_CARRY_MERGE)) + { + ReorderInstructionsCore(instructions, code, false, REORDER_CARRY); + ReorderInstructionsCore(instructions, code, true, REORDER_CARRY); + } + if (HasOption(OPTION_BRANCH_MERGE)) + ReorderInstructionsCore(instructions, code, false, REORDER_CMP); } -void PPCAnalyzer::SetInstructionStats(CodeBlock *block, CodeOp *code, GekkoOPInfo *opinfo, u32 index) +void PPCAnalyzer::SetInstructionStats(CodeBlock* block, CodeOp* code, GekkoOPInfo* opinfo, + u32 index) { - code->wantsCR0 = false; - code->wantsCR1 = false; + code->wantsCR0 = false; + code->wantsCR1 = false; - if (opinfo->flags & FL_USE_FPU) - block->m_fpa->any = true; + if (opinfo->flags & FL_USE_FPU) + block->m_fpa->any = true; - if (opinfo->flags & FL_TIMER) - block->m_gpa->anyTimer = true; + if (opinfo->flags & FL_TIMER) + block->m_gpa->anyTimer = true; - // Does the instruction output CR0? - if (opinfo->flags & FL_RC_BIT) - code->outputCR0 = code->inst.hex & 1; //todo fix - else if ((opinfo->flags & FL_SET_CRn) && code->inst.CRFD == 0) - code->outputCR0 = true; - else - code->outputCR0 = (opinfo->flags & FL_SET_CR0) ? true : false; + // Does the instruction output CR0? + if (opinfo->flags & FL_RC_BIT) + code->outputCR0 = code->inst.hex & 1; // todo fix + else if ((opinfo->flags & FL_SET_CRn) && code->inst.CRFD == 0) + code->outputCR0 = true; + else + code->outputCR0 = (opinfo->flags & FL_SET_CR0) ? true : false; - // Does the instruction output CR1? - if (opinfo->flags & FL_RC_BIT_F) - code->outputCR1 = code->inst.hex & 1; //todo fix - else if ((opinfo->flags & FL_SET_CRn) && code->inst.CRFD == 1) - code->outputCR1 = true; - else - code->outputCR1 = (opinfo->flags & FL_SET_CR1) ? true : false; + // Does the instruction output CR1? + if (opinfo->flags & FL_RC_BIT_F) + code->outputCR1 = code->inst.hex & 1; // todo fix + else if ((opinfo->flags & FL_SET_CRn) && code->inst.CRFD == 1) + code->outputCR1 = true; + else + code->outputCR1 = (opinfo->flags & FL_SET_CR1) ? true : false; - code->wantsFPRF = (opinfo->flags & FL_READ_FPRF) ? true : false; - code->outputFPRF = (opinfo->flags & FL_SET_FPRF) ? true : false; - code->canEndBlock = (opinfo->flags & FL_ENDBLOCK) ? true : false; + code->wantsFPRF = (opinfo->flags & FL_READ_FPRF) ? true : false; + code->outputFPRF = (opinfo->flags & FL_SET_FPRF) ? true : false; + code->canEndBlock = (opinfo->flags & FL_ENDBLOCK) ? true : false; - code->wantsCA = (opinfo->flags & FL_READ_CA) ? true : false; - code->outputCA = (opinfo->flags & FL_SET_CA) ? true : false; + code->wantsCA = (opinfo->flags & FL_READ_CA) ? true : false; + code->outputCA = (opinfo->flags & FL_SET_CA) ? true : false; - // We're going to try to avoid storing carry in XER if we can avoid it -- keep it in the x86 carry flag! - // If the instruction reads CA but doesn't write it, we still need to store CA in XER; we can't - // leave it in flags. - if (HasOption(OPTION_CARRY_MERGE)) - code->wantsCAInFlags = code->wantsCA && code->outputCA && opinfo->type == OPTYPE_INTEGER; - else - code->wantsCAInFlags = false; + // We're going to try to avoid storing carry in XER if we can avoid it -- keep it in the x86 carry + // flag! + // If the instruction reads CA but doesn't write it, we still need to store CA in XER; we can't + // leave it in flags. + if (HasOption(OPTION_CARRY_MERGE)) + code->wantsCAInFlags = code->wantsCA && code->outputCA && opinfo->type == OPTYPE_INTEGER; + else + code->wantsCAInFlags = false; - // mfspr/mtspr can affect/use XER, so be super careful here - // we need to note specifically that mfspr needs CA in XER, not in the x86 carry flag - if (code->inst.OPCD == 31 && code->inst.SUBOP10 == 339) // mfspr - code->wantsCA = ((code->inst.SPRU << 5) | (code->inst.SPRL & 0x1F)) == SPR_XER; - if (code->inst.OPCD == 31 && code->inst.SUBOP10 == 467) // mtspr - code->outputCA = ((code->inst.SPRU << 5) | (code->inst.SPRL & 0x1F)) == SPR_XER; + // mfspr/mtspr can affect/use XER, so be super careful here + // we need to note specifically that mfspr needs CA in XER, not in the x86 carry flag + if (code->inst.OPCD == 31 && code->inst.SUBOP10 == 339) // mfspr + code->wantsCA = ((code->inst.SPRU << 5) | (code->inst.SPRL & 0x1F)) == SPR_XER; + if (code->inst.OPCD == 31 && code->inst.SUBOP10 == 467) // mtspr + code->outputCA = ((code->inst.SPRU << 5) | (code->inst.SPRL & 0x1F)) == SPR_XER; - code->regsIn = BitSet32(0); - code->regsOut = BitSet32(0); - if (opinfo->flags & FL_OUT_A) - { - code->regsOut[code->inst.RA] = true; - block->m_gpa->SetOutputRegister(code->inst.RA, index); - } - if (opinfo->flags & FL_OUT_D) - { - code->regsOut[code->inst.RD] = true; - block->m_gpa->SetOutputRegister(code->inst.RD, index); - } - if ((opinfo->flags & FL_IN_A) || ((opinfo->flags & FL_IN_A0) && code->inst.RA != 0)) - { - code->regsIn[code->inst.RA] = true; - block->m_gpa->SetInputRegister(code->inst.RA, index); - } - if (opinfo->flags & FL_IN_B) - { - code->regsIn[code->inst.RB] = true; - block->m_gpa->SetInputRegister(code->inst.RB, index); - } - if (opinfo->flags & FL_IN_C) - { - code->regsIn[code->inst.RC] = true; - block->m_gpa->SetInputRegister(code->inst.RC, index); - } - if (opinfo->flags & FL_IN_S) - { - code->regsIn[code->inst.RS] = true; - block->m_gpa->SetInputRegister(code->inst.RS, index); - } - if (code->inst.OPCD == 46) // lmw - { - for (int iReg = code->inst.RD; iReg < 32; ++iReg) - { - code->regsOut[iReg] = true; - block->m_gpa->SetOutputRegister(iReg, index); - } - } - else if (code->inst.OPCD == 47) //stmw - { - for (int iReg = code->inst.RS; iReg < 32; ++iReg) - { - code->regsIn[iReg] = true; - block->m_gpa->SetInputRegister(iReg, index); - } - } + code->regsIn = BitSet32(0); + code->regsOut = BitSet32(0); + if (opinfo->flags & FL_OUT_A) + { + code->regsOut[code->inst.RA] = true; + block->m_gpa->SetOutputRegister(code->inst.RA, index); + } + if (opinfo->flags & FL_OUT_D) + { + code->regsOut[code->inst.RD] = true; + block->m_gpa->SetOutputRegister(code->inst.RD, index); + } + if ((opinfo->flags & FL_IN_A) || ((opinfo->flags & FL_IN_A0) && code->inst.RA != 0)) + { + code->regsIn[code->inst.RA] = true; + block->m_gpa->SetInputRegister(code->inst.RA, index); + } + if (opinfo->flags & FL_IN_B) + { + code->regsIn[code->inst.RB] = true; + block->m_gpa->SetInputRegister(code->inst.RB, index); + } + if (opinfo->flags & FL_IN_C) + { + code->regsIn[code->inst.RC] = true; + block->m_gpa->SetInputRegister(code->inst.RC, index); + } + if (opinfo->flags & FL_IN_S) + { + code->regsIn[code->inst.RS] = true; + block->m_gpa->SetInputRegister(code->inst.RS, index); + } + if (code->inst.OPCD == 46) // lmw + { + for (int iReg = code->inst.RD; iReg < 32; ++iReg) + { + code->regsOut[iReg] = true; + block->m_gpa->SetOutputRegister(iReg, index); + } + } + else if (code->inst.OPCD == 47) // stmw + { + for (int iReg = code->inst.RS; iReg < 32; ++iReg) + { + code->regsIn[iReg] = true; + block->m_gpa->SetInputRegister(iReg, index); + } + } - code->fregOut = -1; - if (opinfo->flags & FL_OUT_FLOAT_D) - code->fregOut = code->inst.FD; + code->fregOut = -1; + if (opinfo->flags & FL_OUT_FLOAT_D) + code->fregOut = code->inst.FD; - code->fregsIn = BitSet32(0); - if (opinfo->flags & FL_IN_FLOAT_A) - code->fregsIn[code->inst.FA] = true; - if (opinfo->flags & FL_IN_FLOAT_B) - code->fregsIn[code->inst.FB] = true; - if (opinfo->flags & FL_IN_FLOAT_C) - code->fregsIn[code->inst.FC] = true; - if (opinfo->flags & FL_IN_FLOAT_D) - code->fregsIn[code->inst.FD] = true; - if (opinfo->flags & FL_IN_FLOAT_S) - code->fregsIn[code->inst.FS] = true; + code->fregsIn = BitSet32(0); + if (opinfo->flags & FL_IN_FLOAT_A) + code->fregsIn[code->inst.FA] = true; + if (opinfo->flags & FL_IN_FLOAT_B) + code->fregsIn[code->inst.FB] = true; + if (opinfo->flags & FL_IN_FLOAT_C) + code->fregsIn[code->inst.FC] = true; + if (opinfo->flags & FL_IN_FLOAT_D) + code->fregsIn[code->inst.FD] = true; + if (opinfo->flags & FL_IN_FLOAT_S) + code->fregsIn[code->inst.FS] = true; - switch (opinfo->type) - { - case OPTYPE_INTEGER: - case OPTYPE_LOAD: - case OPTYPE_STORE: - case OPTYPE_LOADFP: - case OPTYPE_STOREFP: - break; - case OPTYPE_SINGLEFP: - case OPTYPE_DOUBLEFP: - break; - case OPTYPE_BRANCH: - if (code->inst.hex == 0x4e800020) - { - // For analysis purposes, we can assume that blr eats opinfo->flags. - code->outputCR0 = true; - code->outputCR1 = true; - } - break; - case OPTYPE_SYSTEM: - case OPTYPE_SYSTEMFP: - break; - } + switch (opinfo->type) + { + case OPTYPE_INTEGER: + case OPTYPE_LOAD: + case OPTYPE_STORE: + case OPTYPE_LOADFP: + case OPTYPE_STOREFP: + break; + case OPTYPE_SINGLEFP: + case OPTYPE_DOUBLEFP: + break; + case OPTYPE_BRANCH: + if (code->inst.hex == 0x4e800020) + { + // For analysis purposes, we can assume that blr eats opinfo->flags. + code->outputCR0 = true; + code->outputCR1 = true; + } + break; + case OPTYPE_SYSTEM: + case OPTYPE_SYSTEMFP: + break; + } } -u32 PPCAnalyzer::Analyze(u32 address, CodeBlock *block, CodeBuffer *buffer, u32 blockSize) +u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer, u32 blockSize) { - // Clear block stats - memset(block->m_stats, 0, sizeof(BlockStats)); + // Clear block stats + memset(block->m_stats, 0, sizeof(BlockStats)); - // Clear register stats - block->m_gpa->any = true; - block->m_fpa->any = false; + // Clear register stats + block->m_gpa->any = true; + block->m_fpa->any = false; - block->m_gpa->Clear(); - block->m_fpa->Clear(); + block->m_gpa->Clear(); + block->m_fpa->Clear(); - // Set the blocks start address - block->m_address = address; + // Set the blocks start address + block->m_address = address; - // Reset our block state - block->m_broken = false; - block->m_memory_exception = false; - block->m_num_instructions = 0; - block->m_gqr_used = BitSet8(0); + // Reset our block state + block->m_broken = false; + block->m_memory_exception = false; + block->m_num_instructions = 0; + block->m_gqr_used = BitSet8(0); - CodeOp *code = buffer->codebuffer; + CodeOp* code = buffer->codebuffer; - bool found_exit = false; - u32 return_address = 0; - u32 numFollows = 0; - u32 num_inst = 0; - bool prev_inst_from_bat = true; + bool found_exit = false; + u32 return_address = 0; + u32 numFollows = 0; + u32 num_inst = 0; + bool prev_inst_from_bat = true; - for (u32 i = 0; i < blockSize; ++i) - { - auto result = PowerPC::TryReadInstruction(address); - if (!result.valid) - { - if (i == 0) - block->m_memory_exception = true; - break; - } - UGeckoInstruction inst = result.hex; + for (u32 i = 0; i < blockSize; ++i) + { + auto result = PowerPC::TryReadInstruction(address); + if (!result.valid) + { + if (i == 0) + block->m_memory_exception = true; + break; + } + UGeckoInstruction inst = result.hex; - // Slight hack: the JIT block cache currently assumes all blocks end at the same place, - // but broken blocks due to page faults break this assumption. Avoid this by just ending - // all virtual memory instruction blocks at page boundaries. - // FIXME: improve the JIT block cache so we don't need to do this. - if ((!result.from_bat || !prev_inst_from_bat) && i > 0 && (address & 0xfff) == 0) - { - break; - } - prev_inst_from_bat = result.from_bat; + // Slight hack: the JIT block cache currently assumes all blocks end at the same place, + // but broken blocks due to page faults break this assumption. Avoid this by just ending + // all virtual memory instruction blocks at page boundaries. + // FIXME: improve the JIT block cache so we don't need to do this. + if ((!result.from_bat || !prev_inst_from_bat) && i > 0 && (address & 0xfff) == 0) + { + break; + } + prev_inst_from_bat = result.from_bat; - num_inst++; - memset(&code[i], 0, sizeof(CodeOp)); - GekkoOPInfo *opinfo = GetOpInfo(inst); + num_inst++; + memset(&code[i], 0, sizeof(CodeOp)); + GekkoOPInfo* opinfo = GetOpInfo(inst); - code[i].opinfo = opinfo; - code[i].address = address; - code[i].inst = inst; - code[i].branchTo = -1; - code[i].branchToIndex = -1; - code[i].skip = false; - block->m_stats->numCycles += opinfo->numCycles; + code[i].opinfo = opinfo; + code[i].address = address; + code[i].inst = inst; + code[i].branchTo = -1; + code[i].branchToIndex = -1; + code[i].skip = false; + block->m_stats->numCycles += opinfo->numCycles; - SetInstructionStats(block, &code[i], opinfo, i); + SetInstructionStats(block, &code[i], opinfo, i); - bool follow = false; - u32 destination = 0; + bool follow = false; + u32 destination = 0; - bool conditional_continue = false; + bool conditional_continue = false; - // Do we inline leaf functions? - if (HasOption(OPTION_LEAF_INLINE)) - { - if (inst.OPCD == 18 && blockSize > 1) - { - //Is bx - should we inline? yes! - if (inst.AA) - destination = SignExt26(inst.LI << 2); - else - destination = address + SignExt26(inst.LI << 2); - if (destination != block->m_address) - follow = true; - } - else if (inst.OPCD == 19 && inst.SUBOP10 == 16 && - (inst.BO & (1 << 4)) && (inst.BO & (1 << 2)) && - return_address != 0) - { - // bclrx with unconditional branch = return - follow = true; - destination = return_address; - return_address = 0; + // Do we inline leaf functions? + if (HasOption(OPTION_LEAF_INLINE)) + { + if (inst.OPCD == 18 && blockSize > 1) + { + // Is bx - should we inline? yes! + if (inst.AA) + destination = SignExt26(inst.LI << 2); + else + destination = address + SignExt26(inst.LI << 2); + if (destination != block->m_address) + follow = true; + } + else if (inst.OPCD == 19 && inst.SUBOP10 == 16 && (inst.BO & (1 << 4)) && + (inst.BO & (1 << 2)) && return_address != 0) + { + // bclrx with unconditional branch = return + follow = true; + destination = return_address; + return_address = 0; - if (inst.LK) - return_address = address + 4; - } - else if (inst.OPCD == 31 && inst.SUBOP10 == 467) - { - // mtspr - const u32 index = (inst.SPRU << 5) | (inst.SPRL & 0x1F); - if (index == SPR_LR) - { - // We give up to follow the return address - // because we have to check the register usage. - return_address = 0; - } - } + if (inst.LK) + return_address = address + 4; + } + else if (inst.OPCD == 31 && inst.SUBOP10 == 467) + { + // mtspr + const u32 index = (inst.SPRU << 5) | (inst.SPRL & 0x1F); + if (index == SPR_LR) + { + // We give up to follow the return address + // because we have to check the register usage. + return_address = 0; + } + } - // TODO: Find the optimal value for FUNCTION_FOLLOWING_THRESHOLD. - // If it is small, the performance will be down. - // If it is big, the size of generated code will be big and - // cache clearning will happen many times. - // TODO: Investivate the reason why - // "0" is fastest in some games, MP2 for example. - if (numFollows > FUNCTION_FOLLOWING_THRESHOLD) - follow = false; - } + // TODO: Find the optimal value for FUNCTION_FOLLOWING_THRESHOLD. + // If it is small, the performance will be down. + // If it is big, the size of generated code will be big and + // cache clearning will happen many times. + // TODO: Investivate the reason why + // "0" is fastest in some games, MP2 for example. + if (numFollows > FUNCTION_FOLLOWING_THRESHOLD) + follow = false; + } - if (HasOption(OPTION_CONDITIONAL_CONTINUE)) - { - if (inst.OPCD == 16 && - ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0 || (inst.BO & BO_DONT_CHECK_CONDITION) == 0)) - { - // bcx with conditional branch - conditional_continue = true; - } - else if (inst.OPCD == 19 && inst.SUBOP10 == 16 && - ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0 || (inst.BO & BO_DONT_CHECK_CONDITION) == 0)) - { - // bclrx with conditional branch - conditional_continue = true; - } - else if (inst.OPCD == 3 || - (inst.OPCD == 31 && inst.SUBOP10 == 4)) - { - // tw/twi tests and raises an exception - conditional_continue = true; - } - else if (inst.OPCD == 19 && inst.SUBOP10 == 528 && - (inst.BO_2 & BO_DONT_CHECK_CONDITION) == 0) - { - // Rare bcctrx with conditional branch - // Seen in NES games - conditional_continue = true; - } - } + if (HasOption(OPTION_CONDITIONAL_CONTINUE)) + { + if (inst.OPCD == 16 && + ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0 || (inst.BO & BO_DONT_CHECK_CONDITION) == 0)) + { + // bcx with conditional branch + conditional_continue = true; + } + else if (inst.OPCD == 19 && inst.SUBOP10 == 16 && ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0 || + (inst.BO & BO_DONT_CHECK_CONDITION) == 0)) + { + // bclrx with conditional branch + conditional_continue = true; + } + else if (inst.OPCD == 3 || (inst.OPCD == 31 && inst.SUBOP10 == 4)) + { + // tw/twi tests and raises an exception + conditional_continue = true; + } + else if (inst.OPCD == 19 && inst.SUBOP10 == 528 && (inst.BO_2 & BO_DONT_CHECK_CONDITION) == 0) + { + // Rare bcctrx with conditional branch + // Seen in NES games + conditional_continue = true; + } + } - if (!follow) - { - address += 4; - if (!conditional_continue && opinfo->flags & FL_ENDBLOCK) //right now we stop early - { - found_exit = true; - break; - } - } - // XXX: We don't support inlining yet. + if (!follow) + { + address += 4; + if (!conditional_continue && opinfo->flags & FL_ENDBLOCK) // right now we stop early + { + found_exit = true; + break; + } + } +// XXX: We don't support inlining yet. #if 0 else { @@ -787,119 +794,118 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock *block, CodeBuffer *buffer, u32 merged_addresses[size_of_merged_addresses++] = address; } #endif - } + } - block->m_num_instructions = num_inst; + block->m_num_instructions = num_inst; - if (block->m_num_instructions > 1) - ReorderInstructions(block->m_num_instructions, code); + if (block->m_num_instructions > 1) + ReorderInstructions(block->m_num_instructions, code); - if ((!found_exit && num_inst > 0) || blockSize == 1) - { - // We couldn't find an exit - block->m_broken = true; - } + if ((!found_exit && num_inst > 0) || blockSize == 1) + { + // We couldn't find an exit + block->m_broken = true; + } - // Scan for flag dependencies; assume the next block (or any branch that can leave the block) - // wants flags, to be safe. - bool wantsCR0 = true, wantsCR1 = true, wantsFPRF = true, wantsCA = true; - BitSet32 fprInUse, gprInUse, gprInReg, fprInXmm; - for (int i = block->m_num_instructions - 1; i >= 0; i--) - { - bool opWantsCR0 = code[i].wantsCR0; - bool opWantsCR1 = code[i].wantsCR1; - bool opWantsFPRF = code[i].wantsFPRF; - bool opWantsCA = code[i].wantsCA; - code[i].wantsCR0 = wantsCR0 || code[i].canEndBlock; - code[i].wantsCR1 = wantsCR1 || code[i].canEndBlock; - code[i].wantsFPRF = wantsFPRF || code[i].canEndBlock; - code[i].wantsCA = wantsCA || code[i].canEndBlock; - wantsCR0 |= opWantsCR0 || code[i].canEndBlock; - wantsCR1 |= opWantsCR1 || code[i].canEndBlock; - wantsFPRF |= opWantsFPRF || code[i].canEndBlock; - wantsCA |= opWantsCA || code[i].canEndBlock; - wantsCR0 &= !code[i].outputCR0 || opWantsCR0; - wantsCR1 &= !code[i].outputCR1 || opWantsCR1; - wantsFPRF &= !code[i].outputFPRF || opWantsFPRF; - wantsCA &= !code[i].outputCA || opWantsCA; - code[i].gprInUse = gprInUse; - code[i].fprInUse = fprInUse; - code[i].gprInReg = gprInReg; - code[i].fprInXmm = fprInXmm; - // TODO: if there's no possible endblocks or exceptions in between, tell the regcache - // we can throw away a register if it's going to be overwritten later. - gprInUse |= code[i].regsIn; - gprInReg |= code[i].regsIn; - fprInUse |= code[i].fregsIn; - if (strncmp(code[i].opinfo->opname, "stfd", 4)) - fprInXmm |= code[i].fregsIn; - // For now, we need to count output registers as "used" though; otherwise the flush - // will result in a redundant store (e.g. store to regcache, then store again to - // the same location later). - gprInUse |= code[i].regsOut; - if (code[i].fregOut >= 0) - fprInUse[code[i].fregOut] = true; - } + // Scan for flag dependencies; assume the next block (or any branch that can leave the block) + // wants flags, to be safe. + bool wantsCR0 = true, wantsCR1 = true, wantsFPRF = true, wantsCA = true; + BitSet32 fprInUse, gprInUse, gprInReg, fprInXmm; + for (int i = block->m_num_instructions - 1; i >= 0; i--) + { + bool opWantsCR0 = code[i].wantsCR0; + bool opWantsCR1 = code[i].wantsCR1; + bool opWantsFPRF = code[i].wantsFPRF; + bool opWantsCA = code[i].wantsCA; + code[i].wantsCR0 = wantsCR0 || code[i].canEndBlock; + code[i].wantsCR1 = wantsCR1 || code[i].canEndBlock; + code[i].wantsFPRF = wantsFPRF || code[i].canEndBlock; + code[i].wantsCA = wantsCA || code[i].canEndBlock; + wantsCR0 |= opWantsCR0 || code[i].canEndBlock; + wantsCR1 |= opWantsCR1 || code[i].canEndBlock; + wantsFPRF |= opWantsFPRF || code[i].canEndBlock; + wantsCA |= opWantsCA || code[i].canEndBlock; + wantsCR0 &= !code[i].outputCR0 || opWantsCR0; + wantsCR1 &= !code[i].outputCR1 || opWantsCR1; + wantsFPRF &= !code[i].outputFPRF || opWantsFPRF; + wantsCA &= !code[i].outputCA || opWantsCA; + code[i].gprInUse = gprInUse; + code[i].fprInUse = fprInUse; + code[i].gprInReg = gprInReg; + code[i].fprInXmm = fprInXmm; + // TODO: if there's no possible endblocks or exceptions in between, tell the regcache + // we can throw away a register if it's going to be overwritten later. + gprInUse |= code[i].regsIn; + gprInReg |= code[i].regsIn; + fprInUse |= code[i].fregsIn; + if (strncmp(code[i].opinfo->opname, "stfd", 4)) + fprInXmm |= code[i].fregsIn; + // For now, we need to count output registers as "used" though; otherwise the flush + // will result in a redundant store (e.g. store to regcache, then store again to + // the same location later). + gprInUse |= code[i].regsOut; + if (code[i].fregOut >= 0) + fprInUse[code[i].fregOut] = true; + } - // Forward scan, for flags that need the other direction for calculation. - BitSet32 fprIsSingle, fprIsDuplicated, fprIsStoreSafe; - BitSet8 gqrUsed, gqrModified; - for (u32 i = 0; i < block->m_num_instructions; i++) - { - code[i].fprIsSingle = fprIsSingle; - code[i].fprIsDuplicated = fprIsDuplicated; - code[i].fprIsStoreSafe = fprIsStoreSafe; - if (code[i].fregOut >= 0) - { - fprIsSingle[code[i].fregOut] = false; - fprIsDuplicated[code[i].fregOut] = false; - fprIsStoreSafe[code[i].fregOut] = false; - // Single, duplicated, and doesn't need PPC_FP. - if (code[i].opinfo->type == OPTYPE_SINGLEFP) - { - fprIsSingle[code[i].fregOut] = true; - fprIsDuplicated[code[i].fregOut] = true; - fprIsStoreSafe[code[i].fregOut] = true; - } - // Single and duplicated, but might be a denormal (not safe to skip PPC_FP). - // TODO: if we go directly from a load to store, skip conversion entirely? - // TODO: if we go directly from a load to a float instruction, and the value isn't used - // for anything else, we can skip PPC_FP on a load too. - if (!strncmp(code[i].opinfo->opname, "lfs", 3)) - { - fprIsSingle[code[i].fregOut] = true; - fprIsDuplicated[code[i].fregOut] = true; - } - // Paired are still floats, but the top/bottom halves may differ. - if (code[i].opinfo->type == OPTYPE_PS || code[i].opinfo->type == OPTYPE_LOADPS) - { - fprIsSingle[code[i].fregOut] = true; - fprIsStoreSafe[code[i].fregOut] = true; - } - // Careful: changing the float mode in a block breaks this optimization, since - // a previous float op might have had had FTZ off while the later store has FTZ - // on. So, discard all information we have. - if (!strncmp(code[i].opinfo->opname, "mtfs", 4)) - fprIsStoreSafe = BitSet32(0); - } + // Forward scan, for flags that need the other direction for calculation. + BitSet32 fprIsSingle, fprIsDuplicated, fprIsStoreSafe; + BitSet8 gqrUsed, gqrModified; + for (u32 i = 0; i < block->m_num_instructions; i++) + { + code[i].fprIsSingle = fprIsSingle; + code[i].fprIsDuplicated = fprIsDuplicated; + code[i].fprIsStoreSafe = fprIsStoreSafe; + if (code[i].fregOut >= 0) + { + fprIsSingle[code[i].fregOut] = false; + fprIsDuplicated[code[i].fregOut] = false; + fprIsStoreSafe[code[i].fregOut] = false; + // Single, duplicated, and doesn't need PPC_FP. + if (code[i].opinfo->type == OPTYPE_SINGLEFP) + { + fprIsSingle[code[i].fregOut] = true; + fprIsDuplicated[code[i].fregOut] = true; + fprIsStoreSafe[code[i].fregOut] = true; + } + // Single and duplicated, but might be a denormal (not safe to skip PPC_FP). + // TODO: if we go directly from a load to store, skip conversion entirely? + // TODO: if we go directly from a load to a float instruction, and the value isn't used + // for anything else, we can skip PPC_FP on a load too. + if (!strncmp(code[i].opinfo->opname, "lfs", 3)) + { + fprIsSingle[code[i].fregOut] = true; + fprIsDuplicated[code[i].fregOut] = true; + } + // Paired are still floats, but the top/bottom halves may differ. + if (code[i].opinfo->type == OPTYPE_PS || code[i].opinfo->type == OPTYPE_LOADPS) + { + fprIsSingle[code[i].fregOut] = true; + fprIsStoreSafe[code[i].fregOut] = true; + } + // Careful: changing the float mode in a block breaks this optimization, since + // a previous float op might have had had FTZ off while the later store has FTZ + // on. So, discard all information we have. + if (!strncmp(code[i].opinfo->opname, "mtfs", 4)) + fprIsStoreSafe = BitSet32(0); + } - if (code[i].opinfo->type == OPTYPE_STOREPS || code[i].opinfo->type == OPTYPE_LOADPS) - { - int gqr = code[i].inst.OPCD == 4 ? code[i].inst.Ix : code[i].inst.I; - gqrUsed[gqr] = true; - } + if (code[i].opinfo->type == OPTYPE_STOREPS || code[i].opinfo->type == OPTYPE_LOADPS) + { + int gqr = code[i].inst.OPCD == 4 ? code[i].inst.Ix : code[i].inst.I; + gqrUsed[gqr] = true; + } - if (code[i].inst.OPCD == 31 && code[i].inst.SUBOP10 == 467) // mtspr - { - int gqr = ((code[i].inst.SPRU << 5) | code[i].inst.SPRL) - SPR_GQR0; - if (gqr >= 0 && gqr <= 7) - gqrModified[gqr] = true; - } - } - block->m_gqr_used = gqrUsed; - block->m_gqr_modified = gqrModified; - return address; + if (code[i].inst.OPCD == 31 && code[i].inst.SUBOP10 == 467) // mtspr + { + int gqr = ((code[i].inst.SPRU << 5) | code[i].inst.SPRL) - SPR_GQR0; + if (gqr >= 0 && gqr <= 7) + gqrModified[gqr] = true; + } + } + block->m_gqr_used = gqrUsed; + block->m_gqr_modified = gqrModified; + return address; } - } // namespace diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.h b/Source/Core/Core/PowerPC/PPCAnalyst.h index 116a7541aa..2fddaa59f1 100644 --- a/Source/Core/Core/PowerPC/PPCAnalyst.h +++ b/Source/Core/Core/PowerPC/PPCAnalyst.h @@ -19,223 +19,209 @@ struct Symbol; namespace PPCAnalyst { - -struct CodeOp //16B +struct CodeOp // 16B { - UGeckoInstruction inst; - GekkoOPInfo * opinfo; - u32 address; - u32 branchTo; //if 0, not a branch - int branchToIndex; //index of target block - BitSet32 regsOut; - BitSet32 regsIn; - BitSet32 fregsIn; - s8 fregOut; - bool isBranchTarget; - bool wantsCR0; - bool wantsCR1; - bool wantsFPRF; - bool wantsCA; - bool wantsCAInFlags; - bool outputCR0; - bool outputCR1; - bool outputFPRF; - bool outputCA; - bool canEndBlock; - bool skip; // followed BL-s for example - // which registers are still needed after this instruction in this block - BitSet32 fprInUse; - BitSet32 gprInUse; - // just because a register is in use doesn't mean we actually need or want it in an x86 register. - BitSet32 gprInReg; - // we do double stores from GPRs, so we don't want to load a PowerPC floating point register into - // an XMM only to move it again to a GPR afterwards. - BitSet32 fprInXmm; - // whether an fpr is known to be an actual single-precision value at this point in the block. - BitSet32 fprIsSingle; - // whether an fpr is known to have identical top and bottom halves (e.g. due to a single instruction) - BitSet32 fprIsDuplicated; - // whether an fpr is the output of a single-precision arithmetic instruction, i.e. whether we can safely - // skip PPC_FP. - BitSet32 fprIsStoreSafe; + UGeckoInstruction inst; + GekkoOPInfo* opinfo; + u32 address; + u32 branchTo; // if 0, not a branch + int branchToIndex; // index of target block + BitSet32 regsOut; + BitSet32 regsIn; + BitSet32 fregsIn; + s8 fregOut; + bool isBranchTarget; + bool wantsCR0; + bool wantsCR1; + bool wantsFPRF; + bool wantsCA; + bool wantsCAInFlags; + bool outputCR0; + bool outputCR1; + bool outputFPRF; + bool outputCA; + bool canEndBlock; + bool skip; // followed BL-s for example + // which registers are still needed after this instruction in this block + BitSet32 fprInUse; + BitSet32 gprInUse; + // just because a register is in use doesn't mean we actually need or want it in an x86 register. + BitSet32 gprInReg; + // we do double stores from GPRs, so we don't want to load a PowerPC floating point register into + // an XMM only to move it again to a GPR afterwards. + BitSet32 fprInXmm; + // whether an fpr is known to be an actual single-precision value at this point in the block. + BitSet32 fprIsSingle; + // whether an fpr is known to have identical top and bottom halves (e.g. due to a single + // instruction) + BitSet32 fprIsDuplicated; + // whether an fpr is the output of a single-precision arithmetic instruction, i.e. whether we can + // safely + // skip PPC_FP. + BitSet32 fprIsStoreSafe; }; struct BlockStats { - bool isFirstBlockOfFunction; - bool isLastBlockOfFunction; - int numCycles; + bool isFirstBlockOfFunction; + bool isLastBlockOfFunction; + int numCycles; }; struct BlockRegStats { - short firstRead[32]; - short firstWrite[32]; - short lastRead[32]; - short lastWrite[32]; - short numReads[32]; - short numWrites[32]; + short firstRead[32]; + short firstWrite[32]; + short lastRead[32]; + short lastWrite[32]; + short numReads[32]; + short numWrites[32]; - bool any; - bool anyTimer; + bool any; + bool anyTimer; - int GetTotalNumAccesses(int reg) const - { - return numReads[reg] + numWrites[reg]; - } + int GetTotalNumAccesses(int reg) const { return numReads[reg] + numWrites[reg]; } + int GetUseRange(int reg) const + { + return std::max(lastRead[reg], lastWrite[reg]) - std::min(firstRead[reg], firstWrite[reg]); + } - int GetUseRange(int reg) const - { - return std::max(lastRead[reg], lastWrite[reg]) - - std::min(firstRead[reg], firstWrite[reg]); - } + bool IsUsed(int reg) const { return (numReads[reg] + numWrites[reg]) > 0; } + void SetInputRegister(int reg, short opindex) + { + if (firstRead[reg] == -1) + firstRead[reg] = opindex; + lastRead[reg] = opindex; + numReads[reg]++; + } - bool IsUsed(int reg) const - { - return (numReads[reg] + numWrites[reg]) > 0; - } + void SetOutputRegister(int reg, short opindex) + { + if (firstWrite[reg] == -1) + firstWrite[reg] = opindex; + lastWrite[reg] = opindex; + numWrites[reg]++; + } - void SetInputRegister(int reg, short opindex) - { - if (firstRead[reg] == -1) - firstRead[reg] = opindex; - lastRead[reg] = opindex; - numReads[reg]++; - } - - void SetOutputRegister(int reg, short opindex) - { - if (firstWrite[reg] == -1) - firstWrite[reg] = opindex; - lastWrite[reg] = opindex; - numWrites[reg]++; - } - - void Clear() - { - for (int i = 0; i < 32; ++i) - { - firstRead[i] = -1; - firstWrite[i] = -1; - numReads[i] = 0; - numWrites[i] = 0; - } - } + void Clear() + { + for (int i = 0; i < 32; ++i) + { + firstRead[i] = -1; + firstWrite[i] = -1; + numReads[i] = 0; + numWrites[i] = 0; + } + } }; - class CodeBuffer { public: - CodeBuffer(int size); - ~CodeBuffer(); + CodeBuffer(int size); + ~CodeBuffer(); - int GetSize() const { return size_; } - - PPCAnalyst::CodeOp *codebuffer; + int GetSize() const { return size_; } + PPCAnalyst::CodeOp* codebuffer; private: - int size_; + int size_; }; struct CodeBlock { - // Beginning PPC address. - u32 m_address; + // Beginning PPC address. + u32 m_address; - // Number of instructions - // Gives us the size of the block. - u32 m_num_instructions; + // Number of instructions + // Gives us the size of the block. + u32 m_num_instructions; - // Some basic statistics about the block. - BlockStats *m_stats; + // Some basic statistics about the block. + BlockStats* m_stats; - // Register statistics about the block. - BlockRegStats *m_gpa, *m_fpa; + // Register statistics about the block. + BlockRegStats *m_gpa, *m_fpa; - // Are we a broken block? - bool m_broken; + // Are we a broken block? + bool m_broken; - // Did we have a memory_exception? - bool m_memory_exception; + // Did we have a memory_exception? + bool m_memory_exception; - // Which GQRs this block uses, if any. - BitSet8 m_gqr_used; + // Which GQRs this block uses, if any. + BitSet8 m_gqr_used; - // Which GQRs this block modifies, if any. - BitSet8 m_gqr_modified; + // Which GQRs this block modifies, if any. + BitSet8 m_gqr_modified; }; class PPCAnalyzer { private: + enum ReorderType + { + REORDER_CARRY, + REORDER_CMP, + REORDER_CROR + }; - enum ReorderType - { - REORDER_CARRY, - REORDER_CMP, - REORDER_CROR - }; + void ReorderInstructionsCore(u32 instructions, CodeOp* code, bool reverse, ReorderType type); + void ReorderInstructions(u32 instructions, CodeOp* code); + void SetInstructionStats(CodeBlock* block, CodeOp* code, GekkoOPInfo* opinfo, u32 index); - void ReorderInstructionsCore(u32 instructions, CodeOp* code, bool reverse, ReorderType type); - void ReorderInstructions(u32 instructions, CodeOp *code); - void SetInstructionStats(CodeBlock *block, CodeOp *code, GekkoOPInfo *opinfo, u32 index); + // Options + u32 m_options; - // Options - u32 m_options; public: + enum AnalystOption + { + // Conditional branch continuing + // If the JIT core supports conditional branches within the blocks + // Block will end on unconditional branch or other ENDBLOCK flagged instruction. + // Requires JIT support to be enabled. + OPTION_CONDITIONAL_CONTINUE = (1 << 0), - enum AnalystOption - { - // Conditional branch continuing - // If the JIT core supports conditional branches within the blocks - // Block will end on unconditional branch or other ENDBLOCK flagged instruction. - // Requires JIT support to be enabled. - OPTION_CONDITIONAL_CONTINUE = (1 << 0), + // If there is a unconditional branch that jumps to a leaf function then inline it. + // Might require JIT intervention to support it correctly. + // Requires JITBLock support for inlined code + // XXX: NOT COMPLETE + OPTION_LEAF_INLINE = (1 << 1), - // If there is a unconditional branch that jumps to a leaf function then inline it. - // Might require JIT intervention to support it correctly. - // Requires JITBLock support for inlined code - // XXX: NOT COMPLETE - OPTION_LEAF_INLINE = (1 << 1), + // Complex blocks support jumping backwards on to themselves. + // Happens commonly in loops, pretty complex to support. + // May require register caches to use register usage metrics. + // XXX: NOT COMPLETE + OPTION_COMPLEX_BLOCK = (1 << 2), - // Complex blocks support jumping backwards on to themselves. - // Happens commonly in loops, pretty complex to support. - // May require register caches to use register usage metrics. - // XXX: NOT COMPLETE - OPTION_COMPLEX_BLOCK = (1 << 2), + // Similar to complex blocks. + // Instead of jumping backwards, this jumps forwards within the block. + // Requires JIT support to work. + // XXX: NOT COMPLETE + OPTION_FORWARD_JUMP = (1 << 3), - // Similar to complex blocks. - // Instead of jumping backwards, this jumps forwards within the block. - // Requires JIT support to work. - // XXX: NOT COMPLETE - OPTION_FORWARD_JUMP = (1 << 3), + // Reorder compare/Rc instructions next to their associated branches and + // merge in the JIT (for common cases, anyway). + OPTION_BRANCH_MERGE = (1 << 4), - // Reorder compare/Rc instructions next to their associated branches and - // merge in the JIT (for common cases, anyway). - OPTION_BRANCH_MERGE = (1 << 4), + // Reorder carry instructions next to their associated branches and pass + // carry flags in the x86 flags between them, instead of in XER. + OPTION_CARRY_MERGE = (1 << 5), - // Reorder carry instructions next to their associated branches and pass - // carry flags in the x86 flags between them, instead of in XER. - OPTION_CARRY_MERGE = (1 << 5), + // Reorder cror instructions next to their associated fcmp. + OPTION_CROR_MERGE = (1 << 6), + }; - // Reorder cror instructions next to their associated fcmp. - OPTION_CROR_MERGE = (1 << 6), - }; - - - PPCAnalyzer() : m_options(0) {} - - // Option setting/getting - void SetOption(AnalystOption option) { m_options |= option; } - void ClearOption(AnalystOption option) { m_options &= ~(option); } - bool HasOption(AnalystOption option) const { return !!(m_options & option); } - - u32 Analyze(u32 address, CodeBlock *block, CodeBuffer *buffer, u32 blockSize); + PPCAnalyzer() : m_options(0) {} + // Option setting/getting + void SetOption(AnalystOption option) { m_options |= option; } + void ClearOption(AnalystOption option) { m_options &= ~(option); } + bool HasOption(AnalystOption option) const { return !!(m_options & option); } + u32 Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer, u32 blockSize); }; void LogFunctionCall(u32 addr); -void FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB *func_db); -bool AnalyzeFunction(u32 startAddr, Symbol &func, int max_size = 0); +void FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB* func_db); +bool AnalyzeFunction(u32 startAddr, Symbol& func, int max_size = 0); } // namespace diff --git a/Source/Core/Core/PowerPC/PPCCache.cpp b/Source/Core/Core/PowerPC/PPCCache.cpp index f32c585454..33bdf46557 100644 --- a/Source/Core/Core/PowerPC/PPCCache.cpp +++ b/Source/Core/Core/PowerPC/PPCCache.cpp @@ -7,149 +7,145 @@ #include "Common/CommonFuncs.h" #include "Core/HW/Memmap.h" #include "Core/PowerPC/JitInterface.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PPCCache.h" +#include "Core/PowerPC/PowerPC.h" namespace PowerPC { - static const u32 s_plru_mask[8] = {11, 11, 19, 19, 37, 37, 69, 69}; - static const u32 s_plru_value[8] = {11, 3, 17, 1, 36, 4, 64, 0}; +static const u32 s_plru_mask[8] = {11, 11, 19, 19, 37, 37, 69, 69}; +static const u32 s_plru_value[8] = {11, 3, 17, 1, 36, 4, 64, 0}; - InstructionCache::InstructionCache() - { - for (u32 m = 0; m < 0xff; m++) - { - u32 w = 0; - while (m & (1 << w)) - w++; - way_from_valid[m] = w; - } - - for (u32 m = 0; m < 128; m++) - { - u32 b[7]; - for (int i = 0; i < 7; i++) - b[i] = m & (1 << i); - u32 w; - if (b[0]) - if (b[2]) - if (b[6]) - w = 7; - else - w = 6; - else - if (b[5]) - w = 5; - else - w = 4; - else - if (b[1]) - if (b[4]) - w = 3; - else - w = 2; - else - if (b[3]) - w = 1; - else - w = 0; - way_from_plru[m] = w; - } - } - - void InstructionCache::Reset() - { - memset(valid, 0, sizeof(valid)); - memset(plru, 0, sizeof(plru)); - memset(lookup_table, 0xff, sizeof(lookup_table)); - memset(lookup_table_ex, 0xff, sizeof(lookup_table_ex)); - memset(lookup_table_vmem, 0xff, sizeof(lookup_table_vmem)); - JitInterface::ClearSafe(); - } - - void InstructionCache::Init() - { - memset(data, 0, sizeof(data)); - memset(tags, 0, sizeof(tags)); - - Reset(); - } - - void InstructionCache::Invalidate(u32 addr) - { - if (!HID0.ICE) - return; - // invalidates the whole set - u32 set = (addr >> 5) & 0x7f; - for (int i = 0; i < 8; i++) - if (valid[set] & (1 << i)) - { - if (tags[set][i] & (ICACHE_VMEM_BIT >> 12)) - lookup_table_vmem[((tags[set][i] << 7) | set) & 0xfffff] = 0xff; - else if (tags[set][i] & (ICACHE_EXRAM_BIT >> 12)) - lookup_table_ex[((tags[set][i] << 7) | set) & 0x1fffff] = 0xff; - else - lookup_table[((tags[set][i] << 7) | set) & 0xfffff] = 0xff; - } - valid[set] = 0; - JitInterface::InvalidateICache(addr & ~0x1f, 32, false); - } - - u32 InstructionCache::ReadInstruction(u32 addr) - { - if (!HID0.ICE) // instruction cache is disabled - return Memory::Read_U32(addr); - u32 set = (addr >> 5) & 0x7f; - u32 tag = addr >> 12; - - u32 t; - if (addr & ICACHE_VMEM_BIT) - { - t = lookup_table_vmem[(addr >> 5) & 0xfffff]; - } - else if (addr & ICACHE_EXRAM_BIT) - { - t = lookup_table_ex[(addr >> 5) & 0x1fffff]; - } - else - { - t = lookup_table[(addr >> 5) & 0xfffff]; - } - - if (t == 0xff) // load to the cache - { - if (HID0.ILOCK) // instruction cache is locked - return Memory::Read_U32(addr); - // select a way - if (valid[set] != 0xff) - t = way_from_valid[valid[set]]; - else - t = way_from_plru[plru[set]]; - // load - Memory::CopyFromEmu((u8*)data[set][t], (addr & ~0x1f), 32); - if (valid[set] & (1 << t)) - { - if (tags[set][t] & (ICACHE_VMEM_BIT >> 12)) - lookup_table_vmem[((tags[set][t] << 7) | set) & 0xfffff] = 0xff; - else if (tags[set][t] & (ICACHE_EXRAM_BIT >> 12)) - lookup_table_ex[((tags[set][t] << 7) | set) & 0x1fffff] = 0xff; - else - lookup_table[((tags[set][t] << 7) | set) & 0xfffff] = 0xff; - } - - if (addr & ICACHE_VMEM_BIT) - lookup_table_vmem[(addr >> 5) & 0xfffff] = t; - else if (addr & ICACHE_EXRAM_BIT) - lookup_table_ex[(addr >> 5) & 0x1fffff] = t; - else - lookup_table[(addr >> 5) & 0xfffff] = t; - tags[set][t] = tag; - valid[set] |= (1 << t); - } - // update plru - plru[set] = (plru[set] & ~s_plru_mask[t]) | s_plru_value[t]; - u32 res = Common::swap32(data[set][t][(addr >> 2) & 7]); - return res; - } +InstructionCache::InstructionCache() +{ + for (u32 m = 0; m < 0xff; m++) + { + u32 w = 0; + while (m & (1 << w)) + w++; + way_from_valid[m] = w; + } + for (u32 m = 0; m < 128; m++) + { + u32 b[7]; + for (int i = 0; i < 7; i++) + b[i] = m & (1 << i); + u32 w; + if (b[0]) + if (b[2]) + if (b[6]) + w = 7; + else + w = 6; + else if (b[5]) + w = 5; + else + w = 4; + else if (b[1]) + if (b[4]) + w = 3; + else + w = 2; + else if (b[3]) + w = 1; + else + w = 0; + way_from_plru[m] = w; + } +} + +void InstructionCache::Reset() +{ + memset(valid, 0, sizeof(valid)); + memset(plru, 0, sizeof(plru)); + memset(lookup_table, 0xff, sizeof(lookup_table)); + memset(lookup_table_ex, 0xff, sizeof(lookup_table_ex)); + memset(lookup_table_vmem, 0xff, sizeof(lookup_table_vmem)); + JitInterface::ClearSafe(); +} + +void InstructionCache::Init() +{ + memset(data, 0, sizeof(data)); + memset(tags, 0, sizeof(tags)); + + Reset(); +} + +void InstructionCache::Invalidate(u32 addr) +{ + if (!HID0.ICE) + return; + // invalidates the whole set + u32 set = (addr >> 5) & 0x7f; + for (int i = 0; i < 8; i++) + if (valid[set] & (1 << i)) + { + if (tags[set][i] & (ICACHE_VMEM_BIT >> 12)) + lookup_table_vmem[((tags[set][i] << 7) | set) & 0xfffff] = 0xff; + else if (tags[set][i] & (ICACHE_EXRAM_BIT >> 12)) + lookup_table_ex[((tags[set][i] << 7) | set) & 0x1fffff] = 0xff; + else + lookup_table[((tags[set][i] << 7) | set) & 0xfffff] = 0xff; + } + valid[set] = 0; + JitInterface::InvalidateICache(addr & ~0x1f, 32, false); +} + +u32 InstructionCache::ReadInstruction(u32 addr) +{ + if (!HID0.ICE) // instruction cache is disabled + return Memory::Read_U32(addr); + u32 set = (addr >> 5) & 0x7f; + u32 tag = addr >> 12; + + u32 t; + if (addr & ICACHE_VMEM_BIT) + { + t = lookup_table_vmem[(addr >> 5) & 0xfffff]; + } + else if (addr & ICACHE_EXRAM_BIT) + { + t = lookup_table_ex[(addr >> 5) & 0x1fffff]; + } + else + { + t = lookup_table[(addr >> 5) & 0xfffff]; + } + + if (t == 0xff) // load to the cache + { + if (HID0.ILOCK) // instruction cache is locked + return Memory::Read_U32(addr); + // select a way + if (valid[set] != 0xff) + t = way_from_valid[valid[set]]; + else + t = way_from_plru[plru[set]]; + // load + Memory::CopyFromEmu((u8*)data[set][t], (addr & ~0x1f), 32); + if (valid[set] & (1 << t)) + { + if (tags[set][t] & (ICACHE_VMEM_BIT >> 12)) + lookup_table_vmem[((tags[set][t] << 7) | set) & 0xfffff] = 0xff; + else if (tags[set][t] & (ICACHE_EXRAM_BIT >> 12)) + lookup_table_ex[((tags[set][t] << 7) | set) & 0x1fffff] = 0xff; + else + lookup_table[((tags[set][t] << 7) | set) & 0xfffff] = 0xff; + } + + if (addr & ICACHE_VMEM_BIT) + lookup_table_vmem[(addr >> 5) & 0xfffff] = t; + else if (addr & ICACHE_EXRAM_BIT) + lookup_table_ex[(addr >> 5) & 0x1fffff] = t; + else + lookup_table[(addr >> 5) & 0xfffff] = t; + tags[set][t] = tag; + valid[set] |= (1 << t); + } + // update plru + plru[set] = (plru[set] & ~s_plru_mask[t]) | s_plru_value[t]; + u32 res = Common::swap32(data[set][t][(addr >> 2) & 7]); + return res; +} } diff --git a/Source/Core/Core/PowerPC/PPCCache.h b/Source/Core/Core/PowerPC/PPCCache.h index b621f9b094..9dc31667db 100644 --- a/Source/Core/Core/PowerPC/PPCCache.h +++ b/Source/Core/Core/PowerPC/PPCCache.h @@ -8,34 +8,32 @@ namespace PowerPC { +const u32 ICACHE_SETS = 128; +const u32 ICACHE_WAYS = 8; +// size of an instruction cache block in words +const u32 ICACHE_BLOCK_SIZE = 8; - const u32 ICACHE_SETS = 128; - const u32 ICACHE_WAYS = 8; - // size of an instruction cache block in words - const u32 ICACHE_BLOCK_SIZE = 8; +const u32 ICACHE_EXRAM_BIT = 0x10000000; +const u32 ICACHE_VMEM_BIT = 0x20000000; - const u32 ICACHE_EXRAM_BIT = 0x10000000; - const u32 ICACHE_VMEM_BIT = 0x20000000; +struct InstructionCache +{ + u32 data[ICACHE_SETS][ICACHE_WAYS][ICACHE_BLOCK_SIZE]; + u32 tags[ICACHE_SETS][ICACHE_WAYS]; + u32 plru[ICACHE_SETS]; + u32 valid[ICACHE_SETS]; - struct InstructionCache - { - u32 data[ICACHE_SETS][ICACHE_WAYS][ICACHE_BLOCK_SIZE]; - u32 tags[ICACHE_SETS][ICACHE_WAYS]; - u32 plru[ICACHE_SETS]; - u32 valid[ICACHE_SETS]; + u32 way_from_valid[255]; + u32 way_from_plru[128]; - u32 way_from_valid[255]; - u32 way_from_plru[128]; - - u8 lookup_table[1<<20]; - u8 lookup_table_ex[1<<21]; - u8 lookup_table_vmem[1<<20]; - - InstructionCache(); - u32 ReadInstruction(u32 addr); - void Invalidate(u32 addr); - void Init(); - void Reset(); - }; + u8 lookup_table[1 << 20]; + u8 lookup_table_ex[1 << 21]; + u8 lookup_table_vmem[1 << 20]; + InstructionCache(); + u32 ReadInstruction(u32 addr); + void Invalidate(u32 addr); + void Init(); + void Reset(); +}; } diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp index 43f45595f1..310b548538 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp @@ -8,21 +8,20 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/StringUtil.h" #include "Common/Logging/Log.h" +#include "Common/StringUtil.h" #include "Core/ConfigManager.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/PPCSymbolDB.h" +#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/SignatureDB.h" - PPCSymbolDB g_symbolDB; PPCSymbolDB::PPCSymbolDB() { - // Get access to the disasm() fgnction - debugger = &PowerPC::debug_interface; + // Get access to the disasm() fgnction + debugger = &PowerPC::debug_interface; } PPCSymbolDB::~PPCSymbolDB() @@ -30,168 +29,169 @@ PPCSymbolDB::~PPCSymbolDB() } // Adds the function to the list, unless it's already there -Symbol *PPCSymbolDB::AddFunction(u32 startAddr) +Symbol* PPCSymbolDB::AddFunction(u32 startAddr) { - if (startAddr < 0x80000010) - return nullptr; - XFuncMap::iterator iter = functions.find(startAddr); - if (iter != functions.end()) - { - // it's already in the list - return nullptr; - } - else - { - Symbol tempFunc; //the current one we're working on - u32 targetEnd = PPCAnalyst::AnalyzeFunction(startAddr, tempFunc); - if (targetEnd == 0) - return nullptr; //found a dud :( - //LOG(OSHLE, "Symbol found at %08x", startAddr); - functions[startAddr] = tempFunc; - tempFunc.type = Symbol::SYMBOL_FUNCTION; - checksumToFunction[tempFunc.hash] = &(functions[startAddr]); - return &functions[startAddr]; - } + if (startAddr < 0x80000010) + return nullptr; + XFuncMap::iterator iter = functions.find(startAddr); + if (iter != functions.end()) + { + // it's already in the list + return nullptr; + } + else + { + Symbol tempFunc; // the current one we're working on + u32 targetEnd = PPCAnalyst::AnalyzeFunction(startAddr, tempFunc); + if (targetEnd == 0) + return nullptr; // found a dud :( + // LOG(OSHLE, "Symbol found at %08x", startAddr); + functions[startAddr] = tempFunc; + tempFunc.type = Symbol::SYMBOL_FUNCTION; + checksumToFunction[tempFunc.hash] = &(functions[startAddr]); + return &functions[startAddr]; + } } void PPCSymbolDB::AddKnownSymbol(u32 startAddr, u32 size, const std::string& name, int type) { - XFuncMap::iterator iter = functions.find(startAddr); - if (iter != functions.end()) - { - // already got it, let's just update name, checksum & size to be sure. - Symbol *tempfunc = &iter->second; - tempfunc->name = name; - tempfunc->hash = SignatureDB::ComputeCodeChecksum(startAddr, startAddr + size - 4); - tempfunc->type = type; - tempfunc->size = size; - } - else - { - // new symbol. run analyze. - Symbol tf; - tf.name = name; - tf.type = type; - tf.address = startAddr; - if (tf.type == Symbol::SYMBOL_FUNCTION) - { - PPCAnalyst::AnalyzeFunction(startAddr, tf, size); - checksumToFunction[tf.hash] = &(functions[startAddr]); - } - tf.size = size; - functions[startAddr] = tf; - } + XFuncMap::iterator iter = functions.find(startAddr); + if (iter != functions.end()) + { + // already got it, let's just update name, checksum & size to be sure. + Symbol* tempfunc = &iter->second; + tempfunc->name = name; + tempfunc->hash = SignatureDB::ComputeCodeChecksum(startAddr, startAddr + size - 4); + tempfunc->type = type; + tempfunc->size = size; + } + else + { + // new symbol. run analyze. + Symbol tf; + tf.name = name; + tf.type = type; + tf.address = startAddr; + if (tf.type == Symbol::SYMBOL_FUNCTION) + { + PPCAnalyst::AnalyzeFunction(startAddr, tf, size); + checksumToFunction[tf.hash] = &(functions[startAddr]); + } + tf.size = size; + functions[startAddr] = tf; + } } -Symbol *PPCSymbolDB::GetSymbolFromAddr(u32 addr) +Symbol* PPCSymbolDB::GetSymbolFromAddr(u32 addr) { - if (!PowerPC::HostIsRAMAddress(addr)) - return nullptr; + if (!PowerPC::HostIsRAMAddress(addr)) + return nullptr; - XFuncMap::iterator it = functions.find(addr); - if (it != functions.end()) - { - return &it->second; - } - else - { - for (auto& p : functions) - { - if (addr >= p.second.address && addr < p.second.address + p.second.size) - return &p.second; - } - } - return nullptr; + XFuncMap::iterator it = functions.find(addr); + if (it != functions.end()) + { + return &it->second; + } + else + { + for (auto& p : functions) + { + if (addr >= p.second.address && addr < p.second.address + p.second.size) + return &p.second; + } + } + return nullptr; } const std::string PPCSymbolDB::GetDescription(u32 addr) { - Symbol *symbol = GetSymbolFromAddr(addr); - if (symbol) - return symbol->name; - else - return " --- "; + Symbol* symbol = GetSymbolFromAddr(addr); + if (symbol) + return symbol->name; + else + return " --- "; } void PPCSymbolDB::FillInCallers() { - for (auto& p : functions) - { - p.second.callers.clear(); - } + for (auto& p : functions) + { + p.second.callers.clear(); + } - for (auto& entry : functions) - { - Symbol &f = entry.second; - for (const SCall& call : f.calls) - { - SCall NewCall(entry.first, call.callAddress); - u32 FunctionAddress = call.function; + for (auto& entry : functions) + { + Symbol& f = entry.second; + for (const SCall& call : f.calls) + { + SCall NewCall(entry.first, call.callAddress); + u32 FunctionAddress = call.function; - XFuncMap::iterator FuncIterator = functions.find(FunctionAddress); - if (FuncIterator != functions.end()) - { - Symbol& rCalledFunction = FuncIterator->second; - rCalledFunction.callers.push_back(NewCall); - } - else - { - //LOG(OSHLE, "FillInCallers tries to fill data in an unknown function 0x%08x.", FunctionAddress); - // TODO - analyze the function instead. - } - } - } + XFuncMap::iterator FuncIterator = functions.find(FunctionAddress); + if (FuncIterator != functions.end()) + { + Symbol& rCalledFunction = FuncIterator->second; + rCalledFunction.callers.push_back(NewCall); + } + else + { + // LOG(OSHLE, "FillInCallers tries to fill data in an unknown function 0x%08x.", + // FunctionAddress); + // TODO - analyze the function instead. + } + } + } } void PPCSymbolDB::PrintCalls(u32 funcAddr) const { - XFuncMap::const_iterator iter = functions.find(funcAddr); - if (iter != functions.end()) - { - const Symbol &f = iter->second; - INFO_LOG(OSHLE, "The function %s at %08x calls:", f.name.c_str(), f.address); - for (const SCall& call : f.calls) - { - XFuncMap::const_iterator n = functions.find(call.function); - if (n != functions.end()) - { - INFO_LOG(CONSOLE,"* %08x : %s", call.callAddress, n->second.name.c_str()); - } - } - } - else - { - WARN_LOG(CONSOLE, "Symbol does not exist"); - } + XFuncMap::const_iterator iter = functions.find(funcAddr); + if (iter != functions.end()) + { + const Symbol& f = iter->second; + INFO_LOG(OSHLE, "The function %s at %08x calls:", f.name.c_str(), f.address); + for (const SCall& call : f.calls) + { + XFuncMap::const_iterator n = functions.find(call.function); + if (n != functions.end()) + { + INFO_LOG(CONSOLE, "* %08x : %s", call.callAddress, n->second.name.c_str()); + } + } + } + else + { + WARN_LOG(CONSOLE, "Symbol does not exist"); + } } void PPCSymbolDB::PrintCallers(u32 funcAddr) const { - XFuncMap::const_iterator iter = functions.find(funcAddr); - if (iter != functions.end()) - { - const Symbol &f = iter->second; - INFO_LOG(CONSOLE,"The function %s at %08x is called by:",f.name.c_str(),f.address); - for (const SCall& caller : f.callers) - { - XFuncMap::const_iterator n = functions.find(caller.function); - if (n != functions.end()) - { - INFO_LOG(CONSOLE,"* %08x : %s", caller.callAddress, n->second.name.c_str()); - } - } - } + XFuncMap::const_iterator iter = functions.find(funcAddr); + if (iter != functions.end()) + { + const Symbol& f = iter->second; + INFO_LOG(CONSOLE, "The function %s at %08x is called by:", f.name.c_str(), f.address); + for (const SCall& caller : f.callers) + { + XFuncMap::const_iterator n = functions.find(caller.function); + if (n != functions.end()) + { + INFO_LOG(CONSOLE, "* %08x : %s", caller.callAddress, n->second.name.c_str()); + } + } + } } void PPCSymbolDB::LogFunctionCall(u32 addr) { - //u32 from = PC; - XFuncMap::iterator iter = functions.find(addr); - if (iter != functions.end()) - { - Symbol &f = iter->second; - f.numCalls++; - } + // u32 from = PC; + XFuncMap::iterator iter = functions.find(addr); + if (iter != functions.end()) + { + Symbol& f = iter->second; + f.numCalls++; + } } // The use case for handling bad map files is when you have a game with a map file on the disc, @@ -200,15 +200,20 @@ void PPCSymbolDB::LogFunctionCall(u32 addr) // map file are still at the correct locations. Which are both common situations. It will load any // function names and addresses that have a BLR before the start and at the end, but ignore any that // don't, and then tell you how many were good and how many it ignored. That way you either find out -// it is all good and use it, find out it is partly good and use the good part, or find out that only -// a handful of functions lined up by coincidence and then you can clear the symbols. In the future I +// it is all good and use it, find out it is partly good and use the good part, or find out that +// only +// a handful of functions lined up by coincidence and then you can clear the symbols. In the future +// I // want to make it smarter, so it checks that there are no BLRs in the middle of the function // (by checking the code length), and also make it cope with added functions in the middle or work -// based on the order of the functions and their approximate length. Currently that process has to be +// based on the order of the functions and their approximate length. Currently that process has to +// be // done manually and is very tedious. // The use case for separate handling of map files that aren't bad is that you usually want to also -// load names that aren't functions(if included in the map file) without them being rejected as invalid. -// You can see discussion about these kinds of issues here : https://forums.oculus.com/viewtopic.php?f=42&t=11241&start=580 +// load names that aren't functions(if included in the map file) without them being rejected as +// invalid. +// You can see discussion about these kinds of issues here : +// https://forums.oculus.com/viewtopic.php?f=42&t=11241&start=580 // https://m2k2.taigaforum.com/post/metroid_prime_hacking_help_25.html#metroid_prime_hacking_help_25 // This one can load both leftover map files on game discs (like Zelda), and mapfiles @@ -216,230 +221,262 @@ void PPCSymbolDB::LogFunctionCall(u32 addr) // bad=true means carefully load map files that might not be from exactly the right version bool PPCSymbolDB::LoadMap(const std::string& filename, bool bad) { - File::IOFile f(filename, "r"); - if (!f) - return false; + File::IOFile f(filename, "r"); + if (!f) + return false; - // four columns are used in American Mensa Academy map files and perhaps other games - bool started = false, four_columns = false; - int good_count = 0, bad_count = 0; + // four columns are used in American Mensa Academy map files and perhaps other games + bool started = false, four_columns = false; + int good_count = 0, bad_count = 0; - char line[512]; - while (fgets(line, 512, f.GetHandle())) - { - size_t length = strlen(line); - if (length < 4) - continue; + char line[512]; + while (fgets(line, 512, f.GetHandle())) + { + size_t length = strlen(line); + if (length < 4) + continue; - if (length == 34 && strcmp(line, " address Size address offset\n") == 0) - { - four_columns = true; - continue; - } + if (length == 34 && strcmp(line, " address Size address offset\n") == 0) + { + four_columns = true; + continue; + } - char temp[256]; - sscanf(line, "%255s", temp); + char temp[256]; + sscanf(line, "%255s", temp); - if (strcmp(temp, "UNUSED")==0) continue; - if (strcmp(temp, ".text")==0) {started = true; continue;}; - if (strcmp(temp, ".init")==0) {started = true; continue;}; - if (strcmp(temp, "Starting")==0) continue; - if (strcmp(temp, "extab")==0) continue; - if (strcmp(temp, ".ctors")==0) break; //uh? - if (strcmp(temp, ".dtors")==0) break; - if (strcmp(temp, ".rodata")==0) continue; - if (strcmp(temp, ".data")==0) continue; - if (strcmp(temp, ".sbss")==0) continue; - if (strcmp(temp, ".sdata")==0) continue; - if (strcmp(temp, ".sdata2")==0) continue; - if (strcmp(temp, "address")==0) continue; - if (strcmp(temp, "-----------------------")==0) continue; - if (strcmp(temp, ".sbss2")==0) break; - if (temp[1] == ']') continue; + if (strcmp(temp, "UNUSED") == 0) + continue; + if (strcmp(temp, ".text") == 0) + { + started = true; + continue; + }; + if (strcmp(temp, ".init") == 0) + { + started = true; + continue; + }; + if (strcmp(temp, "Starting") == 0) + continue; + if (strcmp(temp, "extab") == 0) + continue; + if (strcmp(temp, ".ctors") == 0) + break; // uh? + if (strcmp(temp, ".dtors") == 0) + break; + if (strcmp(temp, ".rodata") == 0) + continue; + if (strcmp(temp, ".data") == 0) + continue; + if (strcmp(temp, ".sbss") == 0) + continue; + if (strcmp(temp, ".sdata") == 0) + continue; + if (strcmp(temp, ".sdata2") == 0) + continue; + if (strcmp(temp, "address") == 0) + continue; + if (strcmp(temp, "-----------------------") == 0) + continue; + if (strcmp(temp, ".sbss2") == 0) + break; + if (temp[1] == ']') + continue; - if (!started) continue; + if (!started) + continue; - u32 address, vaddress, size, offset, unknown; - char name[512], container[512]; - if (four_columns) - { - // sometimes there is no unknown number, and sometimes it is because it is an entry of something else - if (length > 37 && line[37]==' ') - { - unknown = 0; - sscanf(line, "%08x %08x %08x %08x %511s", &address, &size, &vaddress, &offset, name); - char *s = strstr(line, "(entry of "); - if (s) - { - sscanf(s + 10, "%511s", container); - char *s2 = (strchr(container, ')')); - if (s2 && container[0]!='.') - { - s2[0] = '\0'; - strcat(container, "::"); - strcat(container, name); - strcpy(name, container); - } - } - } - else - { - sscanf(line, "%08x %08x %08x %08x %i %511s", &address, &size, &vaddress, &offset, &unknown, name); - } - } - // some entries in the table have a function name followed by " (entry of " followed by a container name, followed by ")" - // instead of a space followed by a number followed by a space followed by a name - else if (length > 27 && line[27] != ' ' && strstr(line, "(entry of ")) - { - unknown = 0; - sscanf(line, "%08x %08x %08x %511s", &address, &size, &vaddress, name); - char *s = strstr(line, "(entry of "); - if (s) - { - sscanf(s + 10, "%511s", container); - char *s2 = (strchr(container, ')')); - if (s2 && container[0] != '.') - { - s2[0] = '\0'; - strcat(container, "::"); - strcat(container, name); - strcpy(name, container); - } - } - } - else - { - sscanf(line, "%08x %08x %08x %i %511s", &address, &size, &vaddress, &unknown, name); - } + u32 address, vaddress, size, offset, unknown; + char name[512], container[512]; + if (four_columns) + { + // sometimes there is no unknown number, and sometimes it is because it is an entry of + // something else + if (length > 37 && line[37] == ' ') + { + unknown = 0; + sscanf(line, "%08x %08x %08x %08x %511s", &address, &size, &vaddress, &offset, name); + char* s = strstr(line, "(entry of "); + if (s) + { + sscanf(s + 10, "%511s", container); + char* s2 = (strchr(container, ')')); + if (s2 && container[0] != '.') + { + s2[0] = '\0'; + strcat(container, "::"); + strcat(container, name); + strcpy(name, container); + } + } + } + else + { + sscanf(line, "%08x %08x %08x %08x %i %511s", &address, &size, &vaddress, &offset, &unknown, + name); + } + } + // some entries in the table have a function name followed by " (entry of " followed by a + // container name, followed by ")" + // instead of a space followed by a number followed by a space followed by a name + else if (length > 27 && line[27] != ' ' && strstr(line, "(entry of ")) + { + unknown = 0; + sscanf(line, "%08x %08x %08x %511s", &address, &size, &vaddress, name); + char* s = strstr(line, "(entry of "); + if (s) + { + sscanf(s + 10, "%511s", container); + char* s2 = (strchr(container, ')')); + if (s2 && container[0] != '.') + { + s2[0] = '\0'; + strcat(container, "::"); + strcat(container, name); + strcpy(name, container); + } + } + } + else + { + sscanf(line, "%08x %08x %08x %i %511s", &address, &size, &vaddress, &unknown, name); + } - const char *namepos = strstr(line, name); - if (namepos != nullptr) //would be odd if not :P - strcpy(name, namepos); - name[strlen(name) - 1] = 0; + const char* namepos = strstr(line, name); + if (namepos != nullptr) // would be odd if not :P + strcpy(name, namepos); + name[strlen(name) - 1] = 0; - // we want the function names only .... TODO: or do we really? aren't we wasting information here? - for (size_t i = 0; i < strlen(name); i++) - { - if (name[i] == ' ') name[i] = 0x00; - if (name[i] == '(') name[i] = 0x00; - } + // we want the function names only .... TODO: or do we really? aren't we wasting information + // here? + for (size_t i = 0; i < strlen(name); i++) + { + if (name[i] == ' ') + name[i] = 0x00; + if (name[i] == '(') + name[i] = 0x00; + } - // Check if this is a valid entry. - if (strcmp(name, ".text") != 0 && strcmp(name, ".init") != 0 && strlen(name) > 0) - { - vaddress |= 0x80000000; - bool good = !bad; - if (!good) - { - // check for BLR before function - u32 opcode = PowerPC::HostRead_Instruction(vaddress - 4); - if (opcode == 0x4e800020) - { - // check for BLR at end of function - opcode = PowerPC::HostRead_Instruction(vaddress + size - 4); - if (opcode == 0x4e800020) - good = true; - } - } - if (good) - { - ++good_count; - AddKnownSymbol(vaddress | 0x80000000, size, name); // ST_FUNCTION - } - else - { - ++bad_count; - } - } - } + // Check if this is a valid entry. + if (strcmp(name, ".text") != 0 && strcmp(name, ".init") != 0 && strlen(name) > 0) + { + vaddress |= 0x80000000; + bool good = !bad; + if (!good) + { + // check for BLR before function + u32 opcode = PowerPC::HostRead_Instruction(vaddress - 4); + if (opcode == 0x4e800020) + { + // check for BLR at end of function + opcode = PowerPC::HostRead_Instruction(vaddress + size - 4); + if (opcode == 0x4e800020) + good = true; + } + } + if (good) + { + ++good_count; + AddKnownSymbol(vaddress | 0x80000000, size, name); // ST_FUNCTION + } + else + { + ++bad_count; + } + } + } - Index(); - if (bad) - SuccessAlertT("Loaded %d good functions, ignored %d bad functions.", good_count, bad_count); - return true; + Index(); + if (bad) + SuccessAlertT("Loaded %d good functions, ignored %d bad functions.", good_count, bad_count); + return true; } - // =================================================== /* Save the map file and save a code file */ // ---------------- bool PPCSymbolDB::SaveMap(const std::string& filename, bool WithCodes) const { - // Format the name for the codes version - std::string mapFile = filename; - if (WithCodes) - mapFile = mapFile.substr(0, mapFile.find_last_of(".")) + "_code.map"; + // Format the name for the codes version + std::string mapFile = filename; + if (WithCodes) + mapFile = mapFile.substr(0, mapFile.find_last_of(".")) + "_code.map"; - // Check size - const int wxYES_NO = 0x00000002 | 0x00000008; - if (functions.size() == 0) - { - if (!AskYesNo(StringFromFormat( - "No symbol names are generated. Do you want to replace '%s' with a blank file?", - mapFile.c_str()).c_str(), "Confirm", wxYES_NO)) return false; - } + // Check size + const int wxYES_NO = 0x00000002 | 0x00000008; + if (functions.size() == 0) + { + if (!AskYesNo( + StringFromFormat( + "No symbol names are generated. Do you want to replace '%s' with a blank file?", + mapFile.c_str()) + .c_str(), + "Confirm", wxYES_NO)) + return false; + } - // Make a file - File::IOFile f(mapFile, "w"); - if (!f) - return false; + // Make a file + File::IOFile f(mapFile, "w"); + if (!f) + return false; - // -------------------------------------------------------------------- - // Walk through every code row - // ------------------------- - fprintf(f.GetHandle(), ".text\n"); // Write ".text" at the top - XFuncMap::const_iterator itr = functions.begin(); - u32 LastAddress = 0x80004000; - std::string LastSymbolName; - while (itr != functions.end()) - { - // Save a map file - const Symbol &rSymbol = itr->second; - if (!WithCodes) - { - fprintf(f.GetHandle(),"%08x %08x %08x %i %s\n", rSymbol.address, rSymbol.size, rSymbol.address, - 0, rSymbol.name.c_str()); - ++itr; - } + // -------------------------------------------------------------------- + // Walk through every code row + // ------------------------- + fprintf(f.GetHandle(), ".text\n"); // Write ".text" at the top + XFuncMap::const_iterator itr = functions.begin(); + u32 LastAddress = 0x80004000; + std::string LastSymbolName; + while (itr != functions.end()) + { + // Save a map file + const Symbol& rSymbol = itr->second; + if (!WithCodes) + { + fprintf(f.GetHandle(), "%08x %08x %08x %i %s\n", rSymbol.address, rSymbol.size, + rSymbol.address, 0, rSymbol.name.c_str()); + ++itr; + } - // Save a code file - else - { - // Get the current and next address - LastAddress = rSymbol.address; - LastSymbolName = rSymbol.name; - ++itr; + // Save a code file + else + { + // Get the current and next address + LastAddress = rSymbol.address; + LastSymbolName = rSymbol.name; + ++itr; - /* To make nice straight lines we fill out the name with spaces, we also cut off - all names longer than 25 letters */ - std::string TempSym; - for (u32 i = 0; i < 25; i++) - { - if (i < LastSymbolName.size()) - TempSym += LastSymbolName[i]; - else - TempSym += " "; - } + /* To make nice straight lines we fill out the name with spaces, we also cut off + all names longer than 25 letters */ + std::string TempSym; + for (u32 i = 0; i < 25; i++) + { + if (i < LastSymbolName.size()) + TempSym += LastSymbolName[i]; + else + TempSym += " "; + } - // We currently skip the last block because we don't know how long it goes - int space; - if (itr != functions.end()) - space = itr->second.address - LastAddress; - else - space = 0; + // We currently skip the last block because we don't know how long it goes + int space; + if (itr != functions.end()) + space = itr->second.address - LastAddress; + else + space = 0; - for (int i = 0; i < space; i += 4) - { - int Address = LastAddress + i; + for (int i = 0; i < space; i += 4) + { + int Address = LastAddress + i; - std::string disasm = debugger->Disassemble(Address); - fprintf(f.GetHandle(),"%08x %i %20s %s\n", Address, 0, TempSym.c_str(), disasm.c_str()); - } - // Write a blank line after each block - fprintf(f.GetHandle(), "\n"); - } - } + std::string disasm = debugger->Disassemble(Address); + fprintf(f.GetHandle(), "%08x %i %20s %s\n", Address, 0, TempSym.c_str(), disasm.c_str()); + } + // Write a blank line after each block + fprintf(f.GetHandle(), "\n"); + } + } - return true; + return true; } // =========== diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.h b/Source/Core/Core/PowerPC/PPCSymbolDB.h index b238e694f9..80104414f1 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.h +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.h @@ -17,29 +17,30 @@ class PPCSymbolDB : public SymbolDB { private: - DebugInterface* debugger; + DebugInterface* debugger; public: - typedef void (*functionGetterCallback)(Symbol *f); + typedef void (*functionGetterCallback)(Symbol* f); - PPCSymbolDB(); - ~PPCSymbolDB(); + PPCSymbolDB(); + ~PPCSymbolDB(); - Symbol *AddFunction(u32 startAddr) override; - void AddKnownSymbol(u32 startAddr, u32 size, const std::string& name, int type = Symbol::SYMBOL_FUNCTION); + Symbol* AddFunction(u32 startAddr) override; + void AddKnownSymbol(u32 startAddr, u32 size, const std::string& name, + int type = Symbol::SYMBOL_FUNCTION); - Symbol *GetSymbolFromAddr(u32 addr) override; + Symbol* GetSymbolFromAddr(u32 addr) override; - const std::string GetDescription(u32 addr); + const std::string GetDescription(u32 addr); - void FillInCallers(); + void FillInCallers(); - bool LoadMap(const std::string& filename, bool bad = false); - bool SaveMap(const std::string& filename, bool WithCodes = false) const; + bool LoadMap(const std::string& filename, bool bad = false); + bool SaveMap(const std::string& filename, bool WithCodes = false) const; - void PrintCalls(u32 funcAddr) const; - void PrintCallers(u32 funcAddr) const; - void LogFunctionCall(u32 addr); + void PrintCalls(u32 funcAddr) const; + void PrintCallers(u32 funcAddr) const; + void LogFunctionCall(u32 addr); }; extern PPCSymbolDB g_symbolDB; diff --git a/Source/Core/Core/PowerPC/PPCTables.cpp b/Source/Core/Core/PowerPC/PPCTables.cpp index b0d9b0d1e7..b3d433d2f4 100644 --- a/Source/Core/Core/PowerPC/PPCTables.cpp +++ b/Source/Core/Core/PowerPC/PPCTables.cpp @@ -10,194 +10,202 @@ #include "Common/FileUtil.h" #include "Common/StringUtil.h" -#include "Core/PowerPC/JitInterface.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCTables.h" #include "Core/PowerPC/Interpreter/Interpreter.h" #include "Core/PowerPC/Interpreter/Interpreter_Tables.h" +#include "Core/PowerPC/JitInterface.h" +#include "Core/PowerPC/PPCTables.h" +#include "Core/PowerPC/PowerPC.h" -GekkoOPInfo *m_infoTable[64]; -GekkoOPInfo *m_infoTable4[1024]; -GekkoOPInfo *m_infoTable19[1024]; -GekkoOPInfo *m_infoTable31[1024]; -GekkoOPInfo *m_infoTable59[32]; -GekkoOPInfo *m_infoTable63[1024]; +GekkoOPInfo* m_infoTable[64]; +GekkoOPInfo* m_infoTable4[1024]; +GekkoOPInfo* m_infoTable19[1024]; +GekkoOPInfo* m_infoTable31[1024]; +GekkoOPInfo* m_infoTable59[32]; +GekkoOPInfo* m_infoTable63[1024]; -GekkoOPInfo *m_allInstructions[512]; +GekkoOPInfo* m_allInstructions[512]; int m_numInstructions; -const u64 m_crTable[16] = -{ - PPCCRToInternal(0x0), PPCCRToInternal(0x1), PPCCRToInternal(0x2), PPCCRToInternal(0x3), - PPCCRToInternal(0x4), PPCCRToInternal(0x5), PPCCRToInternal(0x6), PPCCRToInternal(0x7), - PPCCRToInternal(0x8), PPCCRToInternal(0x9), PPCCRToInternal(0xA), PPCCRToInternal(0xB), - PPCCRToInternal(0xC), PPCCRToInternal(0xD), PPCCRToInternal(0xE), PPCCRToInternal(0xF), +const u64 m_crTable[16] = { + PPCCRToInternal(0x0), PPCCRToInternal(0x1), PPCCRToInternal(0x2), PPCCRToInternal(0x3), + PPCCRToInternal(0x4), PPCCRToInternal(0x5), PPCCRToInternal(0x6), PPCCRToInternal(0x7), + PPCCRToInternal(0x8), PPCCRToInternal(0x9), PPCCRToInternal(0xA), PPCCRToInternal(0xB), + PPCCRToInternal(0xC), PPCCRToInternal(0xD), PPCCRToInternal(0xE), PPCCRToInternal(0xF), }; -GekkoOPInfo *GetOpInfo(UGeckoInstruction _inst) +GekkoOPInfo* GetOpInfo(UGeckoInstruction _inst) { - GekkoOPInfo *info = m_infoTable[_inst.OPCD]; - if (info->type == OPTYPE_SUBTABLE) - { - switch (_inst.OPCD) - { - case 4: return m_infoTable4[_inst.SUBOP10]; - case 19: return m_infoTable19[_inst.SUBOP10]; - case 31: return m_infoTable31[_inst.SUBOP10]; - case 59: return m_infoTable59[_inst.SUBOP5]; - case 63: return m_infoTable63[_inst.SUBOP10]; - default: - _assert_msg_(POWERPC,0,"GetOpInfo - invalid subtable op %08x @ %08x", _inst.hex, PC); - return nullptr; - } - } - else - { - if (info->type == OPTYPE_INVALID) - { - _assert_msg_(POWERPC,0,"GetOpInfo - invalid op %08x @ %08x", _inst.hex, PC); - return nullptr; - } - return m_infoTable[_inst.OPCD]; - } + GekkoOPInfo* info = m_infoTable[_inst.OPCD]; + if (info->type == OPTYPE_SUBTABLE) + { + switch (_inst.OPCD) + { + case 4: + return m_infoTable4[_inst.SUBOP10]; + case 19: + return m_infoTable19[_inst.SUBOP10]; + case 31: + return m_infoTable31[_inst.SUBOP10]; + case 59: + return m_infoTable59[_inst.SUBOP5]; + case 63: + return m_infoTable63[_inst.SUBOP10]; + default: + _assert_msg_(POWERPC, 0, "GetOpInfo - invalid subtable op %08x @ %08x", _inst.hex, PC); + return nullptr; + } + } + else + { + if (info->type == OPTYPE_INVALID) + { + _assert_msg_(POWERPC, 0, "GetOpInfo - invalid op %08x @ %08x", _inst.hex, PC); + return nullptr; + } + return m_infoTable[_inst.OPCD]; + } } Interpreter::Instruction GetInterpreterOp(UGeckoInstruction _inst) { - const GekkoOPInfo *info = m_infoTable[_inst.OPCD]; - if (info->type == OPTYPE_SUBTABLE) - { - switch (_inst.OPCD) - { - case 4: return Interpreter::m_opTable4[_inst.SUBOP10]; - case 19: return Interpreter::m_opTable19[_inst.SUBOP10]; - case 31: return Interpreter::m_opTable31[_inst.SUBOP10]; - case 59: return Interpreter::m_opTable59[_inst.SUBOP5]; - case 63: return Interpreter::m_opTable63[_inst.SUBOP10]; - default: - _assert_msg_(POWERPC,0,"GetInterpreterOp - invalid subtable op %08x @ %08x", _inst.hex, PC); - return nullptr; - } - } - else - { - if (info->type == OPTYPE_INVALID) - { - _assert_msg_(POWERPC,0,"GetInterpreterOp - invalid op %08x @ %08x", _inst.hex, PC); - return nullptr; - } - return Interpreter::m_opTable[_inst.OPCD]; - } + const GekkoOPInfo* info = m_infoTable[_inst.OPCD]; + if (info->type == OPTYPE_SUBTABLE) + { + switch (_inst.OPCD) + { + case 4: + return Interpreter::m_opTable4[_inst.SUBOP10]; + case 19: + return Interpreter::m_opTable19[_inst.SUBOP10]; + case 31: + return Interpreter::m_opTable31[_inst.SUBOP10]; + case 59: + return Interpreter::m_opTable59[_inst.SUBOP5]; + case 63: + return Interpreter::m_opTable63[_inst.SUBOP10]; + default: + _assert_msg_(POWERPC, 0, "GetInterpreterOp - invalid subtable op %08x @ %08x", _inst.hex, PC); + return nullptr; + } + } + else + { + if (info->type == OPTYPE_INVALID) + { + _assert_msg_(POWERPC, 0, "GetInterpreterOp - invalid op %08x @ %08x", _inst.hex, PC); + return nullptr; + } + return Interpreter::m_opTable[_inst.OPCD]; + } } namespace PPCTables { - bool UsesFPU(UGeckoInstruction inst) { - GekkoOPInfo* const info = GetOpInfo(inst); + GekkoOPInfo* const info = GetOpInfo(inst); - return (info->flags & FL_USE_FPU) != 0; + return (info->flags & FL_USE_FPU) != 0; } void InitTables(int cpu_core) { - // Interpreter ALWAYS needs to be initialized - InterpreterTables::InitTables(); + // Interpreter ALWAYS needs to be initialized + InterpreterTables::InitTables(); - if (cpu_core != PowerPC::CORE_INTERPRETER) - JitInterface::InitTables(cpu_core); + if (cpu_core != PowerPC::CORE_INTERPRETER) + JitInterface::InitTables(cpu_core); } #define OPLOG #define OP_TO_LOG "mtfsb0x" #ifdef OPLOG -namespace { - std::vector rsplocations; +namespace +{ +std::vector rsplocations; } #endif -const char *GetInstructionName(UGeckoInstruction _inst) +const char* GetInstructionName(UGeckoInstruction _inst) { - const GekkoOPInfo *info = GetOpInfo(_inst); - return info ? info->opname : nullptr; + const GekkoOPInfo* info = GetOpInfo(_inst); + return info ? info->opname : nullptr; } bool IsValidInstruction(UGeckoInstruction _inst) { - const GekkoOPInfo *info = GetOpInfo(_inst); - return info != nullptr; + const GekkoOPInfo* info = GetOpInfo(_inst); + return info != nullptr; } void CountInstruction(UGeckoInstruction _inst) { - GekkoOPInfo *info = GetOpInfo(_inst); - if (info) - { - info->runCount++; - } + GekkoOPInfo* info = GetOpInfo(_inst); + if (info) + { + info->runCount++; + } } void PrintInstructionRunCounts() { - typedef std::pair OpInfo; - std::vector temp; - temp.reserve(m_numInstructions); - for (int i = 0; i < m_numInstructions; ++i) - { - GekkoOPInfo *pInst = m_allInstructions[i]; - temp.emplace_back(pInst->opname, pInst->runCount); - } - std::sort(temp.begin(), temp.end(), - [](const OpInfo &a, const OpInfo &b) - { - return a.second > b.second; - }); + typedef std::pair OpInfo; + std::vector temp; + temp.reserve(m_numInstructions); + for (int i = 0; i < m_numInstructions; ++i) + { + GekkoOPInfo* pInst = m_allInstructions[i]; + temp.emplace_back(pInst->opname, pInst->runCount); + } + std::sort(temp.begin(), temp.end(), + [](const OpInfo& a, const OpInfo& b) { return a.second > b.second; }); - for (auto &inst : temp) - { - if (inst.second == 0) - break; + for (auto& inst : temp) + { + if (inst.second == 0) + break; - DEBUG_LOG(POWERPC, "%s : %" PRIu64, inst.first, inst.second); - } + DEBUG_LOG(POWERPC, "%s : %" PRIu64, inst.first, inst.second); + } } void LogCompiledInstructions() { - static unsigned int time = 0; + static unsigned int time = 0; - File::IOFile f(StringFromFormat("%sinst_log%i.txt", File::GetUserPath(D_LOGS_IDX).c_str(), time), "w"); - for (int i = 0; i < m_numInstructions; i++) - { - GekkoOPInfo *pInst = m_allInstructions[i]; - if (pInst->compileCount > 0) - { - fprintf(f.GetHandle(), "%s\t%i\t%" PRId64 "\t%08x\n", pInst->opname, - pInst->compileCount, pInst->runCount, pInst->lastUse); - } - } + File::IOFile f(StringFromFormat("%sinst_log%i.txt", File::GetUserPath(D_LOGS_IDX).c_str(), time), + "w"); + for (int i = 0; i < m_numInstructions; i++) + { + GekkoOPInfo* pInst = m_allInstructions[i]; + if (pInst->compileCount > 0) + { + fprintf(f.GetHandle(), "%s\t%i\t%" PRId64 "\t%08x\n", pInst->opname, pInst->compileCount, + pInst->runCount, pInst->lastUse); + } + } - f.Open(StringFromFormat("%sinst_not%i.txt", File::GetUserPath(D_LOGS_IDX).c_str(), time), "w"); - for (int i = 0; i < m_numInstructions; i++) - { - GekkoOPInfo *pInst = m_allInstructions[i]; - if (pInst->compileCount == 0) - { - fprintf(f.GetHandle(), "%s\t%i\t%" PRId64 "\n", pInst->opname, - pInst->compileCount, pInst->runCount); - } - } + f.Open(StringFromFormat("%sinst_not%i.txt", File::GetUserPath(D_LOGS_IDX).c_str(), time), "w"); + for (int i = 0; i < m_numInstructions; i++) + { + GekkoOPInfo* pInst = m_allInstructions[i]; + if (pInst->compileCount == 0) + { + fprintf(f.GetHandle(), "%s\t%i\t%" PRId64 "\n", pInst->opname, pInst->compileCount, + pInst->runCount); + } + } #ifdef OPLOG - f.Open(StringFromFormat("%s" OP_TO_LOG "_at%i.txt", File::GetUserPath(D_LOGS_IDX).c_str(), time), "w"); - for (auto& rsplocation : rsplocations) - { - fprintf(f.GetHandle(), OP_TO_LOG ": %08x\n", rsplocation); - } + f.Open(StringFromFormat("%s" OP_TO_LOG "_at%i.txt", File::GetUserPath(D_LOGS_IDX).c_str(), time), + "w"); + for (auto& rsplocation : rsplocations) + { + fprintf(f.GetHandle(), OP_TO_LOG ": %08x\n", rsplocation); + } #endif - ++time; + ++time; } } // namespace diff --git a/Source/Core/Core/PowerPC/PPCTables.h b/Source/Core/Core/PowerPC/PPCTables.h index c7bfe1f446..1b564d6475 100644 --- a/Source/Core/Core/PowerPC/PPCTables.h +++ b/Source/Core/Core/PowerPC/PPCTables.h @@ -10,101 +10,104 @@ // Flags that indicate what an instruction can do. enum { - FL_SET_CR0 = (1<<0), // Sets CR0. - FL_SET_CR1 = (1<<1), // Sets CR1. - FL_SET_CRn = (1<<2), // Encoding decides which CR can be set. - FL_SET_CRx = FL_SET_CR0 | FL_SET_CR1 | FL_SET_CRn, - FL_SET_CA = (1<<3), // Sets the carry flag. - FL_READ_CA = (1<<4), // Reads the carry flag. - FL_RC_BIT = (1<<5), // Sets the record bit. - FL_RC_BIT_F = (1<<6), // Sets the record bit. Used for floating point instructions that do this. - FL_ENDBLOCK = (1<<7), // Specifies that the instruction can be used as an exit point for a JIT block. - FL_IN_A = (1<<8), // Uses rA as an input. - FL_IN_A0 = (1<<9), // Uses rA as an input. Indicates that if rA is zero, the value zero is used, not the contents of r0. - FL_IN_B = (1<<10), // Uses rB as an input. - FL_IN_C = (1<<11), // Uses rC as an input. - FL_IN_S = (1<<12), // Uses rS as an input. - FL_IN_AB = FL_IN_A | FL_IN_B, - FL_IN_AC = FL_IN_A | FL_IN_C, - FL_IN_ABC = FL_IN_A | FL_IN_B | FL_IN_C, - FL_IN_SB = FL_IN_S | FL_IN_B, - FL_IN_A0B = FL_IN_A0 | FL_IN_B, - FL_IN_A0BC = FL_IN_A0 | FL_IN_B | FL_IN_C, - FL_OUT_D = (1<<13), // rD is used as a destination. - FL_OUT_A = (1<<14), // rA is used as a destination. - FL_OUT_AD = FL_OUT_A | FL_OUT_D, - FL_TIMER = (1<<15), // Used only for mftb. - FL_CHECKEXCEPTIONS = (1<<16), // Used with rfi/rfid. - FL_EVIL = (1<<17), // Historically used to refer to instructions that messed up Super Monkey Ball. - FL_USE_FPU = (1<<18), // Used to indicate a floating point instruction. - FL_LOADSTORE = (1<<19), // Used to indicate a load/store instruction. - FL_SET_FPRF = (1<<20), // Sets bits in the FPRF. - FL_READ_FPRF = (1<<21), // Reads bits from the FPRF. - FL_SET_OE = (1<<22), // Sets the overflow flag. - FL_IN_FLOAT_A = (1<<23), // frA is used as an input. - FL_IN_FLOAT_B = (1<<24), // frB is used as an input. - FL_IN_FLOAT_C = (1<<25), // frC is used as an input. - FL_IN_FLOAT_S = (1<<26), // frS is used as an input. - FL_IN_FLOAT_D = (1<<27), // frD is used as an input. - FL_IN_FLOAT_AB = FL_IN_FLOAT_A | FL_IN_FLOAT_B, - FL_IN_FLOAT_AC = FL_IN_FLOAT_A | FL_IN_FLOAT_C, - FL_IN_FLOAT_ABC = FL_IN_FLOAT_A | FL_IN_FLOAT_B | FL_IN_FLOAT_C, - FL_OUT_FLOAT_D = (1<<28), // frD is used as a destination. - // Used in the case of double ops (they don't modify the top half of the output) - FL_INOUT_FLOAT_D = FL_IN_FLOAT_D | FL_OUT_FLOAT_D, + FL_SET_CR0 = (1 << 0), // Sets CR0. + FL_SET_CR1 = (1 << 1), // Sets CR1. + FL_SET_CRn = (1 << 2), // Encoding decides which CR can be set. + FL_SET_CRx = FL_SET_CR0 | FL_SET_CR1 | FL_SET_CRn, + FL_SET_CA = (1 << 3), // Sets the carry flag. + FL_READ_CA = (1 << 4), // Reads the carry flag. + FL_RC_BIT = (1 << 5), // Sets the record bit. + FL_RC_BIT_F = + (1 << 6), // Sets the record bit. Used for floating point instructions that do this. + FL_ENDBLOCK = + (1 << 7), // Specifies that the instruction can be used as an exit point for a JIT block. + FL_IN_A = (1 << 8), // Uses rA as an input. + FL_IN_A0 = (1 << 9), // Uses rA as an input. Indicates that if rA is zero, the value zero is + // used, not the contents of r0. + FL_IN_B = (1 << 10), // Uses rB as an input. + FL_IN_C = (1 << 11), // Uses rC as an input. + FL_IN_S = (1 << 12), // Uses rS as an input. + FL_IN_AB = FL_IN_A | FL_IN_B, + FL_IN_AC = FL_IN_A | FL_IN_C, + FL_IN_ABC = FL_IN_A | FL_IN_B | FL_IN_C, + FL_IN_SB = FL_IN_S | FL_IN_B, + FL_IN_A0B = FL_IN_A0 | FL_IN_B, + FL_IN_A0BC = FL_IN_A0 | FL_IN_B | FL_IN_C, + FL_OUT_D = (1 << 13), // rD is used as a destination. + FL_OUT_A = (1 << 14), // rA is used as a destination. + FL_OUT_AD = FL_OUT_A | FL_OUT_D, + FL_TIMER = (1 << 15), // Used only for mftb. + FL_CHECKEXCEPTIONS = (1 << 16), // Used with rfi/rfid. + FL_EVIL = + (1 << 17), // Historically used to refer to instructions that messed up Super Monkey Ball. + FL_USE_FPU = (1 << 18), // Used to indicate a floating point instruction. + FL_LOADSTORE = (1 << 19), // Used to indicate a load/store instruction. + FL_SET_FPRF = (1 << 20), // Sets bits in the FPRF. + FL_READ_FPRF = (1 << 21), // Reads bits from the FPRF. + FL_SET_OE = (1 << 22), // Sets the overflow flag. + FL_IN_FLOAT_A = (1 << 23), // frA is used as an input. + FL_IN_FLOAT_B = (1 << 24), // frB is used as an input. + FL_IN_FLOAT_C = (1 << 25), // frC is used as an input. + FL_IN_FLOAT_S = (1 << 26), // frS is used as an input. + FL_IN_FLOAT_D = (1 << 27), // frD is used as an input. + FL_IN_FLOAT_AB = FL_IN_FLOAT_A | FL_IN_FLOAT_B, + FL_IN_FLOAT_AC = FL_IN_FLOAT_A | FL_IN_FLOAT_C, + FL_IN_FLOAT_ABC = FL_IN_FLOAT_A | FL_IN_FLOAT_B | FL_IN_FLOAT_C, + FL_OUT_FLOAT_D = (1 << 28), // frD is used as a destination. + // Used in the case of double ops (they don't modify the top half of the output) + FL_INOUT_FLOAT_D = FL_IN_FLOAT_D | FL_OUT_FLOAT_D, }; enum { - OPTYPE_INVALID , - OPTYPE_SUBTABLE, - OPTYPE_INTEGER , - OPTYPE_CR , - OPTYPE_SPR , - OPTYPE_SYSTEM , - OPTYPE_SYSTEMFP, - OPTYPE_LOAD , - OPTYPE_STORE , - OPTYPE_LOADFP , - OPTYPE_STOREFP , - OPTYPE_DOUBLEFP, - OPTYPE_SINGLEFP, - OPTYPE_LOADPS , - OPTYPE_STOREPS , - OPTYPE_PS , - OPTYPE_DCACHE , - OPTYPE_ICACHE , - OPTYPE_BRANCH , - OPTYPE_UNKNOWN , + OPTYPE_INVALID, + OPTYPE_SUBTABLE, + OPTYPE_INTEGER, + OPTYPE_CR, + OPTYPE_SPR, + OPTYPE_SYSTEM, + OPTYPE_SYSTEMFP, + OPTYPE_LOAD, + OPTYPE_STORE, + OPTYPE_LOADFP, + OPTYPE_STOREFP, + OPTYPE_DOUBLEFP, + OPTYPE_SINGLEFP, + OPTYPE_LOADPS, + OPTYPE_STOREPS, + OPTYPE_PS, + OPTYPE_DCACHE, + OPTYPE_ICACHE, + OPTYPE_BRANCH, + OPTYPE_UNKNOWN, }; struct GekkoOPInfo { - const char *opname; - int type; - int flags; - int numCycles; - u64 runCount; - int compileCount; - u32 lastUse; + const char* opname; + int type; + int flags; + int numCycles; + u64 runCount; + int compileCount; + u32 lastUse; }; -extern GekkoOPInfo *m_infoTable[64]; -extern GekkoOPInfo *m_infoTable4[1024]; -extern GekkoOPInfo *m_infoTable19[1024]; -extern GekkoOPInfo *m_infoTable31[1024]; -extern GekkoOPInfo *m_infoTable59[32]; -extern GekkoOPInfo *m_infoTable63[1024]; +extern GekkoOPInfo* m_infoTable[64]; +extern GekkoOPInfo* m_infoTable4[1024]; +extern GekkoOPInfo* m_infoTable19[1024]; +extern GekkoOPInfo* m_infoTable31[1024]; +extern GekkoOPInfo* m_infoTable59[32]; +extern GekkoOPInfo* m_infoTable63[1024]; -extern GekkoOPInfo *m_allInstructions[512]; +extern GekkoOPInfo* m_allInstructions[512]; extern int m_numInstructions; -GekkoOPInfo *GetOpInfo(UGeckoInstruction _inst); +GekkoOPInfo* GetOpInfo(UGeckoInstruction _inst); Interpreter::Instruction GetInterpreterOp(UGeckoInstruction _inst); namespace PPCTables { - void InitTables(int cpu_core); bool IsValidInstruction(UGeckoInstruction _instCode); bool UsesFPU(UGeckoInstruction _inst); @@ -112,6 +115,6 @@ bool UsesFPU(UGeckoInstruction _inst); void CountInstruction(UGeckoInstruction _inst); void PrintInstructionRunCounts(); void LogCompiledInstructions(); -const char *GetInstructionName(UGeckoInstruction _inst); +const char* GetInstructionName(UGeckoInstruction _inst); } // namespace diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index 433b94a11b..71ea9a6ee2 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -6,31 +6,29 @@ #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" #include "Common/FPURoundMode.h" -#include "Common/MathUtil.h" #include "Common/Logging/Log.h" +#include "Common/MathUtil.h" #include "Core/ConfigManager.h" -#include "Core/Host.h" #include "Core/HW/CPU.h" #include "Core/HW/Memmap.h" #include "Core/HW/SystemTimers.h" +#include "Core/Host.h" #include "Core/PowerPC/CPUCoreBase.h" -#include "Core/PowerPC/JitInterface.h" -#include "Core/PowerPC/PowerPC.h" -#include "Core/PowerPC/PPCTables.h" #include "Core/PowerPC/Interpreter/Interpreter.h" - +#include "Core/PowerPC/JitInterface.h" +#include "Core/PowerPC/PPCTables.h" +#include "Core/PowerPC/PowerPC.h" namespace PowerPC { - // STATE_TO_SAVE PowerPCState ppcState; -static CPUCoreBase* s_cpu_core_base = nullptr; -static bool s_cpu_core_base_is_injected = false; -Interpreter* const s_interpreter = Interpreter::getInstance(); -static CoreMode s_mode = MODE_INTERPRETER; +static CPUCoreBase* s_cpu_core_base = nullptr; +static bool s_cpu_core_base_is_injected = false; +Interpreter* const s_interpreter = Interpreter::getInstance(); +static CoreMode s_mode = MODE_INTERPRETER; Watches watches; BreakPoints breakpoints; @@ -39,494 +37,496 @@ PPCDebugInterface debug_interface; u32 CompactCR() { - u32 new_cr = 0; - for (int i = 0; i < 8; i++) - { - new_cr |= GetCRField(i) << (28 - i * 4); - } - return new_cr; + u32 new_cr = 0; + for (int i = 0; i < 8; i++) + { + new_cr |= GetCRField(i) << (28 - i * 4); + } + return new_cr; } void ExpandCR(u32 cr) { - for (int i = 0; i < 8; i++) - { - SetCRField(i, (cr >> (28 - i * 4)) & 0xF); - } + for (int i = 0; i < 8; i++) + { + SetCRField(i, (cr >> (28 - i * 4)) & 0xF); + } } -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - // some of this code has been disabled, because - // it changes registers even in MODE_MEASURE (which is suspicious and seems like it could cause desyncs) - // and because the values it's changing have been added to CoreTiming::DoState, so it might conflict to mess with them here. + // some of this code has been disabled, because + // it changes registers even in MODE_MEASURE (which is suspicious and seems like it could cause + // desyncs) + // and because the values it's changing have been added to CoreTiming::DoState, so it might + // conflict to mess with them here. - // rSPR(SPR_DEC) = SystemTimers::GetFakeDecrementer(); - // *((u64 *)&TL) = SystemTimers::GetFakeTimeBase(); //works since we are little endian and TL comes first :) + // rSPR(SPR_DEC) = SystemTimers::GetFakeDecrementer(); + // *((u64 *)&TL) = SystemTimers::GetFakeTimeBase(); //works since we are little endian and TL + // comes first :) - p.DoPOD(ppcState); + p.DoPOD(ppcState); - // SystemTimers::DecrementerSet(); - // SystemTimers::TimeBaseSet(); + // SystemTimers::DecrementerSet(); + // SystemTimers::TimeBaseSet(); - JitInterface::DoState(p); + JitInterface::DoState(p); } static void ResetRegisters() { - memset(ppcState.ps, 0, sizeof(ppcState.ps)); - memset(ppcState.gpr, 0, sizeof(ppcState.gpr)); - memset(ppcState.spr, 0, sizeof(ppcState.spr)); - /* - 0x00080200 = lonestar 2.0 - 0x00088202 = lonestar 2.2 - 0x70000100 = gekko 1.0 - 0x00080100 = gekko 2.0 - 0x00083203 = gekko 2.3a - 0x00083213 = gekko 2.3b - 0x00083204 = gekko 2.4 - 0x00083214 = gekko 2.4e (8SE) - retail HW2 - */ - ppcState.spr[SPR_PVR] = 0x00083214; - ppcState.spr[SPR_HID1] = 0x80000000; // We're running at 3x the bus clock - ppcState.spr[SPR_ECID_U] = 0x0d96e200; - ppcState.spr[SPR_ECID_M] = 0x1840c00d; - ppcState.spr[SPR_ECID_L] = 0x82bb08e8; + memset(ppcState.ps, 0, sizeof(ppcState.ps)); + memset(ppcState.gpr, 0, sizeof(ppcState.gpr)); + memset(ppcState.spr, 0, sizeof(ppcState.spr)); + /* + 0x00080200 = lonestar 2.0 + 0x00088202 = lonestar 2.2 + 0x70000100 = gekko 1.0 + 0x00080100 = gekko 2.0 + 0x00083203 = gekko 2.3a + 0x00083213 = gekko 2.3b + 0x00083204 = gekko 2.4 + 0x00083214 = gekko 2.4e (8SE) - retail HW2 + */ + ppcState.spr[SPR_PVR] = 0x00083214; + ppcState.spr[SPR_HID1] = 0x80000000; // We're running at 3x the bus clock + ppcState.spr[SPR_ECID_U] = 0x0d96e200; + ppcState.spr[SPR_ECID_M] = 0x1840c00d; + ppcState.spr[SPR_ECID_L] = 0x82bb08e8; - ppcState.fpscr = 0; - ppcState.pc = 0; - ppcState.npc = 0; - ppcState.Exceptions = 0; - for (auto& v : ppcState.cr_val) - v = 0x8000000000000001; + ppcState.fpscr = 0; + ppcState.pc = 0; + ppcState.npc = 0; + ppcState.Exceptions = 0; + for (auto& v : ppcState.cr_val) + v = 0x8000000000000001; - TL = 0; - TU = 0; - SystemTimers::TimeBaseSet(); + TL = 0; + TU = 0; + SystemTimers::TimeBaseSet(); - // MSR should be 0x40, but we don't emulate BS1, so it would never be turned off :} - ppcState.msr = 0; - rDEC = 0xFFFFFFFF; - SystemTimers::DecrementerSet(); + // MSR should be 0x40, but we don't emulate BS1, so it would never be turned off :} + ppcState.msr = 0; + rDEC = 0xFFFFFFFF; + SystemTimers::DecrementerSet(); } void Init(int cpu_core) { - // NOTE: This function runs on EmuThread, not the CPU Thread. - // Changing the rounding mode has a limited effect. - FPURoundMode::SetPrecisionMode(FPURoundMode::PREC_53); + // NOTE: This function runs on EmuThread, not the CPU Thread. + // Changing the rounding mode has a limited effect. + FPURoundMode::SetPrecisionMode(FPURoundMode::PREC_53); - memset(ppcState.sr, 0, sizeof(ppcState.sr)); - ppcState.pagetable_base = 0; - ppcState.pagetable_hashmask = 0; + memset(ppcState.sr, 0, sizeof(ppcState.sr)); + ppcState.pagetable_base = 0; + ppcState.pagetable_hashmask = 0; - for (int tlb = 0; tlb < 2; tlb++) - { - for (int set = 0; set < 64; set++) - { - ppcState.tlb[tlb][set].recent = 0; - for (int way = 0; way < 2; way++) - { - ppcState.tlb[tlb][set].paddr[way] = 0; - ppcState.tlb[tlb][set].pte[way] = 0; - ppcState.tlb[tlb][set].tag[way] = TLB_TAG_INVALID; - } - } - } + for (int tlb = 0; tlb < 2; tlb++) + { + for (int set = 0; set < 64; set++) + { + ppcState.tlb[tlb][set].recent = 0; + for (int way = 0; way < 2; way++) + { + ppcState.tlb[tlb][set].paddr[way] = 0; + ppcState.tlb[tlb][set].pte[way] = 0; + ppcState.tlb[tlb][set].tag[way] = TLB_TAG_INVALID; + } + } + } - ResetRegisters(); - PPCTables::InitTables(cpu_core); + ResetRegisters(); + PPCTables::InitTables(cpu_core); - // We initialize the interpreter because - // it is used on boot and code window independently. - s_interpreter->Init(); + // We initialize the interpreter because + // it is used on boot and code window independently. + s_interpreter->Init(); - switch (cpu_core) - { - case PowerPC::CORE_INTERPRETER: - s_cpu_core_base = s_interpreter; - break; + switch (cpu_core) + { + case PowerPC::CORE_INTERPRETER: + s_cpu_core_base = s_interpreter; + break; - default: - s_cpu_core_base = JitInterface::InitJitCore(cpu_core); - if (!s_cpu_core_base) // Handle Situations where JIT core isn't available - { - WARN_LOG(POWERPC, "Jit core %d not available. Defaulting to interpreter.", cpu_core); - s_cpu_core_base = s_interpreter; - } - break; - } + default: + s_cpu_core_base = JitInterface::InitJitCore(cpu_core); + if (!s_cpu_core_base) // Handle Situations where JIT core isn't available + { + WARN_LOG(POWERPC, "Jit core %d not available. Defaulting to interpreter.", cpu_core); + s_cpu_core_base = s_interpreter; + } + break; + } - if (s_cpu_core_base != s_interpreter) - { - s_mode = MODE_JIT; - } - else - { - s_mode = MODE_INTERPRETER; - } + if (s_cpu_core_base != s_interpreter) + { + s_mode = MODE_JIT; + } + else + { + s_mode = MODE_INTERPRETER; + } - ppcState.iCache.Init(); + ppcState.iCache.Init(); - if (SConfig::GetInstance().bEnableDebugging) - breakpoints.ClearAllTemporary(); + if (SConfig::GetInstance().bEnableDebugging) + breakpoints.ClearAllTemporary(); } void Shutdown() { - InjectExternalCPUCore(nullptr); - JitInterface::Shutdown(); - s_interpreter->Shutdown(); - s_cpu_core_base = nullptr; + InjectExternalCPUCore(nullptr); + JitInterface::Shutdown(); + s_interpreter->Shutdown(); + s_cpu_core_base = nullptr; } CoreMode GetMode() { - return !s_cpu_core_base_is_injected ? s_mode : MODE_INTERPRETER; + return !s_cpu_core_base_is_injected ? s_mode : MODE_INTERPRETER; } static void ApplyMode() { - switch (s_mode) - { - case MODE_INTERPRETER: // Switching from JIT to interpreter - s_cpu_core_base = s_interpreter; - break; + switch (s_mode) + { + case MODE_INTERPRETER: // Switching from JIT to interpreter + s_cpu_core_base = s_interpreter; + break; - case MODE_JIT: // Switching from interpreter to JIT. - // Don't really need to do much. It'll work, the cache will refill itself. - s_cpu_core_base = JitInterface::GetCore(); - if (!s_cpu_core_base) // Has a chance to not get a working JIT core if one isn't active on host - s_cpu_core_base = s_interpreter; - break; - } + case MODE_JIT: // Switching from interpreter to JIT. + // Don't really need to do much. It'll work, the cache will refill itself. + s_cpu_core_base = JitInterface::GetCore(); + if (!s_cpu_core_base) // Has a chance to not get a working JIT core if one isn't active on host + s_cpu_core_base = s_interpreter; + break; + } } void SetMode(CoreMode new_mode) { - if (new_mode == s_mode) - return; // We don't need to do anything. + if (new_mode == s_mode) + return; // We don't need to do anything. - s_mode = new_mode; + s_mode = new_mode; - // If we're using an external CPU core implementation then don't do anything. - if (s_cpu_core_base_is_injected) - return; + // If we're using an external CPU core implementation then don't do anything. + if (s_cpu_core_base_is_injected) + return; - ApplyMode(); + ApplyMode(); } const char* GetCPUName() { - return s_cpu_core_base->GetName(); + return s_cpu_core_base->GetName(); } void InjectExternalCPUCore(CPUCoreBase* new_cpu) { - // Previously injected. - if (s_cpu_core_base_is_injected) - s_cpu_core_base->Shutdown(); + // Previously injected. + if (s_cpu_core_base_is_injected) + s_cpu_core_base->Shutdown(); - // nullptr means just remove - if (!new_cpu) - { - if (s_cpu_core_base_is_injected) - { - s_cpu_core_base_is_injected = false; - ApplyMode(); - } - return; - } + // nullptr means just remove + if (!new_cpu) + { + if (s_cpu_core_base_is_injected) + { + s_cpu_core_base_is_injected = false; + ApplyMode(); + } + return; + } - new_cpu->Init(); - s_cpu_core_base = new_cpu; - s_cpu_core_base_is_injected = true; + new_cpu->Init(); + s_cpu_core_base = new_cpu; + s_cpu_core_base_is_injected = true; } void SingleStep() { - s_cpu_core_base->SingleStep(); + s_cpu_core_base->SingleStep(); } void RunLoop() { - Host_UpdateDisasmDialog(); - s_cpu_core_base->Run(); - Host_UpdateDisasmDialog(); + Host_UpdateDisasmDialog(); + s_cpu_core_base->Run(); + Host_UpdateDisasmDialog(); } void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst) { - switch (MMCR0.PMC1SELECT) - { - case 0: // No change - break; - case 1: // Processor cycles - PowerPC::ppcState.spr[SPR_PMC1] += cycles; - break; - default: - break; - } + switch (MMCR0.PMC1SELECT) + { + case 0: // No change + break; + case 1: // Processor cycles + PowerPC::ppcState.spr[SPR_PMC1] += cycles; + break; + default: + break; + } - switch (MMCR0.PMC2SELECT) - { - case 0: // No change - break; - case 1: // Processor cycles - PowerPC::ppcState.spr[SPR_PMC2] += cycles; - break; - case 11: // Number of loads and stores completed - PowerPC::ppcState.spr[SPR_PMC2] += num_load_stores; - break; - default: - break; - } + switch (MMCR0.PMC2SELECT) + { + case 0: // No change + break; + case 1: // Processor cycles + PowerPC::ppcState.spr[SPR_PMC2] += cycles; + break; + case 11: // Number of loads and stores completed + PowerPC::ppcState.spr[SPR_PMC2] += num_load_stores; + break; + default: + break; + } - switch (MMCR1.PMC3SELECT) - { - case 0: // No change - break; - case 1: // Processor cycles - PowerPC::ppcState.spr[SPR_PMC3] += cycles; - break; - case 11: // Number of FPU instructions completed - PowerPC::ppcState.spr[SPR_PMC3] += num_fp_inst; - break; - default: - break; - } + switch (MMCR1.PMC3SELECT) + { + case 0: // No change + break; + case 1: // Processor cycles + PowerPC::ppcState.spr[SPR_PMC3] += cycles; + break; + case 11: // Number of FPU instructions completed + PowerPC::ppcState.spr[SPR_PMC3] += num_fp_inst; + break; + default: + break; + } - switch (MMCR1.PMC4SELECT) - { - case 0: // No change - break; - case 1: // Processor cycles - PowerPC::ppcState.spr[SPR_PMC4] += cycles; - break; - default: - break; - } + switch (MMCR1.PMC4SELECT) + { + case 0: // No change + break; + case 1: // Processor cycles + PowerPC::ppcState.spr[SPR_PMC4] += cycles; + break; + default: + break; + } - if ((MMCR0.PMC1INTCONTROL && (PowerPC::ppcState.spr[SPR_PMC1] & 0x80000000) != 0) || - (MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC2] & 0x80000000) != 0) || - (MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC3] & 0x80000000) != 0) || - (MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC4] & 0x80000000) != 0)) - PowerPC::ppcState.Exceptions |= EXCEPTION_PERFORMANCE_MONITOR; + if ((MMCR0.PMC1INTCONTROL && (PowerPC::ppcState.spr[SPR_PMC1] & 0x80000000) != 0) || + (MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC2] & 0x80000000) != 0) || + (MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC3] & 0x80000000) != 0) || + (MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC4] & 0x80000000) != 0)) + PowerPC::ppcState.Exceptions |= EXCEPTION_PERFORMANCE_MONITOR; } void CheckExceptions() { - u32 exceptions = ppcState.Exceptions; + u32 exceptions = ppcState.Exceptions; - // Example procedure: - // set SRR0 to either PC or NPC - //SRR0 = NPC; - // save specified MSR bits - //SRR1 = MSR & 0x87C0FFFF; - // copy ILE bit to LE - //MSR |= (MSR >> 16) & 1; - // clear MSR as specified - //MSR &= ~0x04EF36; // 0x04FF36 also clears ME (only for machine check exception) - // set to exception type entry point - //NPC = 0x00000x00; + // Example procedure: + // set SRR0 to either PC or NPC + // SRR0 = NPC; + // save specified MSR bits + // SRR1 = MSR & 0x87C0FFFF; + // copy ILE bit to LE + // MSR |= (MSR >> 16) & 1; + // clear MSR as specified + // MSR &= ~0x04EF36; // 0x04FF36 also clears ME (only for machine check exception) + // set to exception type entry point + // NPC = 0x00000x00; - // TODO(delroth): Exception priority is completely wrong here: depending on - // the instruction class, exceptions should be executed in a given order, - // which is very different from the one arbitrarily chosen here. See §6.1.5 - // in 6xx_pem.pdf. + // TODO(delroth): Exception priority is completely wrong here: depending on + // the instruction class, exceptions should be executed in a given order, + // which is very different from the one arbitrarily chosen here. See §6.1.5 + // in 6xx_pem.pdf. - if (exceptions & EXCEPTION_ISI) - { - SRR0 = NPC; - // Page fault occurred - SRR1 = (MSR & 0x87C0FFFF) | (1 << 30); - MSR |= (MSR >> 16) & 1; - MSR &= ~0x04EF36; - PC = NPC = 0x00000400; + if (exceptions & EXCEPTION_ISI) + { + SRR0 = NPC; + // Page fault occurred + SRR1 = (MSR & 0x87C0FFFF) | (1 << 30); + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000400; - INFO_LOG(POWERPC, "EXCEPTION_ISI"); - ppcState.Exceptions &= ~EXCEPTION_ISI; - } - else if (exceptions & EXCEPTION_PROGRAM) - { - SRR0 = PC; - // say that it's a trap exception - SRR1 = (MSR & 0x87C0FFFF) | 0x20000; - MSR |= (MSR >> 16) & 1; - MSR &= ~0x04EF36; - PC = NPC = 0x00000700; + INFO_LOG(POWERPC, "EXCEPTION_ISI"); + ppcState.Exceptions &= ~EXCEPTION_ISI; + } + else if (exceptions & EXCEPTION_PROGRAM) + { + SRR0 = PC; + // say that it's a trap exception + SRR1 = (MSR & 0x87C0FFFF) | 0x20000; + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000700; - INFO_LOG(POWERPC, "EXCEPTION_PROGRAM"); - ppcState.Exceptions &= ~EXCEPTION_PROGRAM; - } - else if (exceptions & EXCEPTION_SYSCALL) - { - SRR0 = NPC; - SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 16) & 1; - MSR &= ~0x04EF36; - PC = NPC = 0x00000C00; + INFO_LOG(POWERPC, "EXCEPTION_PROGRAM"); + ppcState.Exceptions &= ~EXCEPTION_PROGRAM; + } + else if (exceptions & EXCEPTION_SYSCALL) + { + SRR0 = NPC; + SRR1 = MSR & 0x87C0FFFF; + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000C00; - INFO_LOG(POWERPC, "EXCEPTION_SYSCALL (PC=%08x)", PC); - ppcState.Exceptions &= ~EXCEPTION_SYSCALL; - } - else if (exceptions & EXCEPTION_FPU_UNAVAILABLE) - { - //This happens a lot - GameCube OS uses deferred FPU context switching - SRR0 = PC; // re-execute the instruction - SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 16) & 1; - MSR &= ~0x04EF36; - PC = NPC = 0x00000800; + INFO_LOG(POWERPC, "EXCEPTION_SYSCALL (PC=%08x)", PC); + ppcState.Exceptions &= ~EXCEPTION_SYSCALL; + } + else if (exceptions & EXCEPTION_FPU_UNAVAILABLE) + { + // This happens a lot - GameCube OS uses deferred FPU context switching + SRR0 = PC; // re-execute the instruction + SRR1 = MSR & 0x87C0FFFF; + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000800; - INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE"); - ppcState.Exceptions &= ~EXCEPTION_FPU_UNAVAILABLE; - } + INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE"); + ppcState.Exceptions &= ~EXCEPTION_FPU_UNAVAILABLE; + } #ifdef ENABLE_MEM_CHECK - else if (exceptions & EXCEPTION_FAKE_MEMCHECK_HIT) - { - ppcState.Exceptions &= ~EXCEPTION_DSI & ~EXCEPTION_FAKE_MEMCHECK_HIT; - } + else if (exceptions & EXCEPTION_FAKE_MEMCHECK_HIT) + { + ppcState.Exceptions &= ~EXCEPTION_DSI & ~EXCEPTION_FAKE_MEMCHECK_HIT; + } #endif - else if (exceptions & EXCEPTION_DSI) - { - SRR0 = PC; - SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 16) & 1; - MSR &= ~0x04EF36; - PC = NPC = 0x00000300; - //DSISR and DAR regs are changed in GenerateDSIException() + else if (exceptions & EXCEPTION_DSI) + { + SRR0 = PC; + SRR1 = MSR & 0x87C0FFFF; + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000300; + // DSISR and DAR regs are changed in GenerateDSIException() - INFO_LOG(POWERPC, "EXCEPTION_DSI"); - ppcState.Exceptions &= ~EXCEPTION_DSI; - } - else if (exceptions & EXCEPTION_ALIGNMENT) - { - //This never happens ATM - // perhaps we can get dcb* instructions to use this :p - SRR0 = PC; - SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 16) & 1; - MSR &= ~0x04EF36; - PC = NPC = 0x00000600; + INFO_LOG(POWERPC, "EXCEPTION_DSI"); + ppcState.Exceptions &= ~EXCEPTION_DSI; + } + else if (exceptions & EXCEPTION_ALIGNMENT) + { + // This never happens ATM + // perhaps we can get dcb* instructions to use this :p + SRR0 = PC; + SRR1 = MSR & 0x87C0FFFF; + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000600; - //TODO crazy amount of DSISR options to check out + // TODO crazy amount of DSISR options to check out - INFO_LOG(POWERPC, "EXCEPTION_ALIGNMENT"); - ppcState.Exceptions &= ~EXCEPTION_ALIGNMENT; - } + INFO_LOG(POWERPC, "EXCEPTION_ALIGNMENT"); + ppcState.Exceptions &= ~EXCEPTION_ALIGNMENT; + } - // EXTERNAL INTERRUPT - else if (MSR & 0x0008000) // Handling is delayed until MSR.EE=1. - { - if (exceptions & EXCEPTION_EXTERNAL_INT) - { - // Pokemon gets this "too early", it hasn't a handler yet - SRR0 = NPC; - SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 16) & 1; - MSR &= ~0x04EF36; - PC = NPC = 0x00000500; + // EXTERNAL INTERRUPT + else if (MSR & 0x0008000) // Handling is delayed until MSR.EE=1. + { + if (exceptions & EXCEPTION_EXTERNAL_INT) + { + // Pokemon gets this "too early", it hasn't a handler yet + SRR0 = NPC; + SRR1 = MSR & 0x87C0FFFF; + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000500; - INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT"); - ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT; + INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT"); + ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT; - _dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???"); - } - else if (exceptions & EXCEPTION_PERFORMANCE_MONITOR) - { - SRR0 = NPC; - SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 16) & 1; - MSR &= ~0x04EF36; - PC = NPC = 0x00000F00; + _dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???"); + } + else if (exceptions & EXCEPTION_PERFORMANCE_MONITOR) + { + SRR0 = NPC; + SRR1 = MSR & 0x87C0FFFF; + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000F00; - INFO_LOG(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR"); - ppcState.Exceptions &= ~EXCEPTION_PERFORMANCE_MONITOR; - } - else if (exceptions & EXCEPTION_DECREMENTER) - { - SRR0 = NPC; - SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 16) & 1; - MSR &= ~0x04EF36; - PC = NPC = 0x00000900; + INFO_LOG(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR"); + ppcState.Exceptions &= ~EXCEPTION_PERFORMANCE_MONITOR; + } + else if (exceptions & EXCEPTION_DECREMENTER) + { + SRR0 = NPC; + SRR1 = MSR & 0x87C0FFFF; + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000900; - INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER"); - ppcState.Exceptions &= ~EXCEPTION_DECREMENTER; - } - } + INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER"); + ppcState.Exceptions &= ~EXCEPTION_DECREMENTER; + } + } } void CheckExternalExceptions() { - u32 exceptions = ppcState.Exceptions; + u32 exceptions = ppcState.Exceptions; - // EXTERNAL INTERRUPT - if (exceptions && (MSR & 0x0008000)) // Handling is delayed until MSR.EE=1. - { - if (exceptions & EXCEPTION_EXTERNAL_INT) - { - // Pokemon gets this "too early", it hasn't a handler yet - SRR0 = NPC; - SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 16) & 1; - MSR &= ~0x04EF36; - PC = NPC = 0x00000500; + // EXTERNAL INTERRUPT + if (exceptions && (MSR & 0x0008000)) // Handling is delayed until MSR.EE=1. + { + if (exceptions & EXCEPTION_EXTERNAL_INT) + { + // Pokemon gets this "too early", it hasn't a handler yet + SRR0 = NPC; + SRR1 = MSR & 0x87C0FFFF; + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000500; - INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT"); - ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT; + INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT"); + ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT; - _dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???"); - } - else if (exceptions & EXCEPTION_PERFORMANCE_MONITOR) - { - SRR0 = NPC; - SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 16) & 1; - MSR &= ~0x04EF36; - PC = NPC = 0x00000F00; + _dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???"); + } + else if (exceptions & EXCEPTION_PERFORMANCE_MONITOR) + { + SRR0 = NPC; + SRR1 = MSR & 0x87C0FFFF; + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000F00; - INFO_LOG(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR"); - ppcState.Exceptions &= ~EXCEPTION_PERFORMANCE_MONITOR; - } - else if (exceptions & EXCEPTION_DECREMENTER) - { - SRR0 = NPC; - SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 16) & 1; - MSR &= ~0x04EF36; - PC = NPC = 0x00000900; + INFO_LOG(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR"); + ppcState.Exceptions &= ~EXCEPTION_PERFORMANCE_MONITOR; + } + else if (exceptions & EXCEPTION_DECREMENTER) + { + SRR0 = NPC; + SRR1 = MSR & 0x87C0FFFF; + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000900; - INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER"); - ppcState.Exceptions &= ~EXCEPTION_DECREMENTER; - } - else - { - _dbg_assert_msg_(POWERPC, 0, "Unknown EXT interrupt: Exceptions == %08x", exceptions); - ERROR_LOG(POWERPC, "Unknown EXTERNAL INTERRUPT exception: Exceptions == %08x", exceptions); - } - } + INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER"); + ppcState.Exceptions &= ~EXCEPTION_DECREMENTER; + } + else + { + _dbg_assert_msg_(POWERPC, 0, "Unknown EXT interrupt: Exceptions == %08x", exceptions); + ERROR_LOG(POWERPC, "Unknown EXTERNAL INTERRUPT exception: Exceptions == %08x", exceptions); + } + } } void CheckBreakPoints() { - if (PowerPC::breakpoints.IsAddressBreakPoint(PC)) - { - CPU::Break(); - if (PowerPC::breakpoints.IsTempBreakPoint(PC)) - PowerPC::breakpoints.Remove(PC); - } + if (PowerPC::breakpoints.IsAddressBreakPoint(PC)) + { + CPU::Break(); + if (PowerPC::breakpoints.IsTempBreakPoint(PC)) + PowerPC::breakpoints.Remove(PC); + } } } // namespace - // FPSCR update functions void UpdateFPRF(double dvalue) { - FPSCR.FPRF = MathUtil::ClassifyDouble(dvalue); - //if (FPSCR.FPRF == 0x11) - // PanicAlert("QNAN alert"); + FPSCR.FPRF = MathUtil::ClassifyDouble(dvalue); + // if (FPSCR.FPRF == 0x11) + // PanicAlert("QNAN alert"); } diff --git a/Source/Core/Core/PowerPC/PowerPC.h b/Source/Core/Core/PowerPC/PowerPC.h index 5a9fe5842d..33f1f159ad 100644 --- a/Source/Core/Core/PowerPC/PowerPC.h +++ b/Source/Core/Core/PowerPC/PowerPC.h @@ -19,21 +19,20 @@ class PointerWrap; namespace PowerPC { - enum { - CORE_INTERPRETER, - CORE_JIT64, - CORE_JITIL64, - CORE_JITARM, - CORE_JITARM64, - CORE_CACHEDINTERPRETER, + CORE_INTERPRETER, + CORE_JIT64, + CORE_JITIL64, + CORE_JITARM, + CORE_JITARM64, + CORE_CACHEDINTERPRETER, }; enum CoreMode { - MODE_INTERPRETER, - MODE_JIT, + MODE_INTERPRETER, + MODE_JIT, }; // TLB cache @@ -49,82 +48,84 @@ enum CoreMode struct tlb_entry { - u32 tag[TLB_WAYS]; - u32 paddr[TLB_WAYS]; - u32 pte[TLB_WAYS]; - u8 recent; + u32 tag[TLB_WAYS]; + u32 paddr[TLB_WAYS]; + u32 pte[TLB_WAYS]; + u8 recent; }; // This contains the entire state of the emulated PowerPC "Gekko" CPU. struct PowerPCState { - u32 gpr[32]; // General purpose registers. r1 = stack pointer. + u32 gpr[32]; // General purpose registers. r1 = stack pointer. - u32 pc; // program counter - u32 npc; + u32 pc; // program counter + u32 npc; - // Optimized CR implementation. Instead of storing CR in its PowerPC format - // (4 bit value, SO/EQ/LT/GT), we store instead a 64 bit value for each of - // the 8 CR register parts. This 64 bit value follows this format: - // - SO iff. bit 61 is set - // - EQ iff. lower 32 bits == 0 - // - GT iff. (s64)cr_val > 0 - // - LT iff. bit 62 is set - // - // This has the interesting property that sign-extending the result of an - // operation from 32 to 64 bits results in a 64 bit value that works as a - // CR value. Checking each part of CR is also fast, as it is equivalent to - // testing one bit or the low 32 bit part of a register. And CR can still - // be manipulated bit by bit fairly easily. - u64 cr_val[8]; + // Optimized CR implementation. Instead of storing CR in its PowerPC format + // (4 bit value, SO/EQ/LT/GT), we store instead a 64 bit value for each of + // the 8 CR register parts. This 64 bit value follows this format: + // - SO iff. bit 61 is set + // - EQ iff. lower 32 bits == 0 + // - GT iff. (s64)cr_val > 0 + // - LT iff. bit 62 is set + // + // This has the interesting property that sign-extending the result of an + // operation from 32 to 64 bits results in a 64 bit value that works as a + // CR value. Checking each part of CR is also fast, as it is equivalent to + // testing one bit or the low 32 bit part of a register. And CR can still + // be manipulated bit by bit fairly easily. + u64 cr_val[8]; - u32 msr; // machine specific register - u32 fpscr; // floating point flags/status bits + u32 msr; // machine specific register + u32 fpscr; // floating point flags/status bits - // Exception management. - u32 Exceptions; + // Exception management. + u32 Exceptions; - // Downcount for determining when we need to do timing - // This isn't quite the right location for it, but it is here to accelerate the ARM JIT - // This variable should be inside of the CoreTiming namespace if we wanted to be correct. - int downcount; + // Downcount for determining when we need to do timing + // This isn't quite the right location for it, but it is here to accelerate the ARM JIT + // This variable should be inside of the CoreTiming namespace if we wanted to be correct. + int downcount; - // XER, reformatted into byte fields for easier access. - u8 xer_ca; - u8 xer_so_ov; // format: (SO << 1) | OV - // The Broadway CPU implements bits 16-23 of the XER register... even though it doesn't support lscbx - u16 xer_stringctrl; + // XER, reformatted into byte fields for easier access. + u8 xer_ca; + u8 xer_so_ov; // format: (SO << 1) | OV + // The Broadway CPU implements bits 16-23 of the XER register... even though it doesn't support + // lscbx + u16 xer_stringctrl; #if _M_X86_64 - // This member exists for the purpose of an assertion in x86 JitBase.cpp - // that its offset <= 0x100. To minimize code size on x86, we want as much - // useful stuff in the one-byte offset range as possible - which is why ps - // is sitting down here. It currently doesn't make a difference on other - // supported architectures. - std::tuple<> above_fits_in_first_0x100; + // This member exists for the purpose of an assertion in x86 JitBase.cpp + // that its offset <= 0x100. To minimize code size on x86, we want as much + // useful stuff in the one-byte offset range as possible - which is why ps + // is sitting down here. It currently doesn't make a difference on other + // supported architectures. + std::tuple<> above_fits_in_first_0x100; #endif - // The paired singles are strange : PS0 is stored in the full 64 bits of each FPR - // but ps calculations are only done in 32-bit precision, and PS1 is only 32 bits. - // Since we want to use SIMD, SSE2 is the only viable alternative - 2x double. - alignas(16) u64 ps[32][2]; + // The paired singles are strange : PS0 is stored in the full 64 bits of each FPR + // but ps calculations are only done in 32-bit precision, and PS1 is only 32 bits. + // Since we want to use SIMD, SSE2 is the only viable alternative - 2x double. + alignas(16) u64 ps[32][2]; - u32 sr[16]; // Segment registers. + u32 sr[16]; // Segment registers. - // special purpose registers - controls quantizers, DMA, and lots of other misc extensions. - // also for power management, but we don't care about that. - u32 spr[1024]; + // special purpose registers - controls quantizers, DMA, and lots of other misc extensions. + // also for power management, but we don't care about that. + u32 spr[1024]; - tlb_entry tlb[NUM_TLBS][TLB_SIZE / TLB_WAYS]; + tlb_entry tlb[NUM_TLBS][TLB_SIZE / TLB_WAYS]; - u32 pagetable_base; - u32 pagetable_hashmask; + u32 pagetable_base; + u32 pagetable_hashmask; - InstructionCache iCache; + InstructionCache iCache; }; #if _M_X86_64 -static_assert(offsetof(PowerPC::PowerPCState, above_fits_in_first_0x100) <= 0x100, "top of PowerPCState too big"); +static_assert(offsetof(PowerPC::PowerPCState, above_fits_in_first_0x100) <= 0x100, + "top of PowerPCState too big"); #endif extern PowerPCState ppcState; @@ -136,7 +137,7 @@ extern PPCDebugInterface debug_interface; void Init(int cpu_core); void Shutdown(); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); CoreMode GetMode(); // [NOT THREADSAFE] CPU Thread or CPU::PauseAndLock or CORE_UNINITIALIZED @@ -169,30 +170,30 @@ void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst); #define HID0 ((UReg_HID0&)PowerPC::ppcState.spr[SPR_HID0]) #define HID2 ((UReg_HID2&)PowerPC::ppcState.spr[SPR_HID2]) #define HID4 ((UReg_HID4&)PowerPC::ppcState.spr[SPR_HID4]) -#define DMAU (*(UReg_DMAU*)&PowerPC::ppcState.spr[SPR_DMAU]) -#define DMAL (*(UReg_DMAL*)&PowerPC::ppcState.spr[SPR_DMAL]) +#define DMAU (*(UReg_DMAU*)&PowerPC::ppcState.spr[SPR_DMAU]) +#define DMAL (*(UReg_DMAL*)&PowerPC::ppcState.spr[SPR_DMAL]) #define MMCR0 ((UReg_MMCR0&)PowerPC::ppcState.spr[SPR_MMCR0]) #define MMCR1 ((UReg_MMCR1&)PowerPC::ppcState.spr[SPR_MMCR1]) -#define PC PowerPC::ppcState.pc -#define NPC PowerPC::ppcState.npc -#define FPSCR ((UReg_FPSCR&)PowerPC::ppcState.fpscr) -#define MSR PowerPC::ppcState.msr +#define PC PowerPC::ppcState.pc +#define NPC PowerPC::ppcState.npc +#define FPSCR ((UReg_FPSCR&)PowerPC::ppcState.fpscr) +#define MSR PowerPC::ppcState.msr #define GPR(n) PowerPC::ppcState.gpr[n] #define rGPR PowerPC::ppcState.gpr #define rSPR(i) PowerPC::ppcState.spr[i] -#define LR PowerPC::ppcState.spr[SPR_LR] -#define CTR PowerPC::ppcState.spr[SPR_CTR] -#define rDEC PowerPC::ppcState.spr[SPR_DEC] -#define SRR0 PowerPC::ppcState.spr[SPR_SRR0] -#define SRR1 PowerPC::ppcState.spr[SPR_SRR1] -#define SPRG0 PowerPC::ppcState.spr[SPR_SPRG0] -#define SPRG1 PowerPC::ppcState.spr[SPR_SPRG1] -#define SPRG2 PowerPC::ppcState.spr[SPR_SPRG2] -#define SPRG3 PowerPC::ppcState.spr[SPR_SPRG3] -#define GQR(x) PowerPC::ppcState.spr[SPR_GQR0+x] -#define TL PowerPC::ppcState.spr[SPR_TL] -#define TU PowerPC::ppcState.spr[SPR_TU] +#define LR PowerPC::ppcState.spr[SPR_LR] +#define CTR PowerPC::ppcState.spr[SPR_CTR] +#define rDEC PowerPC::ppcState.spr[SPR_DEC] +#define SRR0 PowerPC::ppcState.spr[SPR_SRR0] +#define SRR1 PowerPC::ppcState.spr[SPR_SRR1] +#define SPRG0 PowerPC::ppcState.spr[SPR_SPRG0] +#define SPRG1 PowerPC::ppcState.spr[SPR_SPRG1] +#define SPRG2 PowerPC::ppcState.spr[SPR_SPRG2] +#define SPRG3 PowerPC::ppcState.spr[SPR_SPRG3] +#define GQR(x) PowerPC::ppcState.spr[SPR_GQR0 + x] +#define TL PowerPC::ppcState.spr[SPR_TL] +#define TU PowerPC::ppcState.spr[SPR_TU] #define rPS0(i) (*(double*)(&PowerPC::ppcState.ps[i][0])) #define rPS1(i) (*(double*)(&PowerPC::ppcState.ps[i][1])) @@ -225,13 +226,13 @@ std::string HostGetString(u32 em_address, size_t size = 0); u32 Read_Opcode(const u32 address); struct TryReadInstResult { - bool valid; - bool from_bat; - u32 hex; + bool valid; + bool from_bat; + u32 hex; }; TryReadInstResult TryReadInstruction(const u32 address); -u8 Read_U8(const u32 address); +u8 Read_U8(const u32 address); u16 Read_U16(const u32 address); u32 Read_U32(const u32 address); u64 Read_U64(const u32 address); @@ -258,7 +259,7 @@ void Write_F64(const double var, const u32 address); void DMA_LCToMemory(const u32 memAddr, const u32 cacheAddr, const u32 numBlocks); void DMA_MemoryToLC(const u32 cacheAddr, const u32 memAddr, const u32 numBlocks); -void ClearCacheLine(const u32 address); // Zeroes 32 bytes; address should be 32-byte-aligned +void ClearCacheLine(const u32 address); // Zeroes 32 bytes; address should be 32-byte-aligned // TLB functions void SDRUpdated(); @@ -275,27 +276,27 @@ bool IsOptimizableGatherPipeWrite(u32 address); enum CRBits { - CR_SO = 1, - CR_EQ = 2, - CR_GT = 4, - CR_LT = 8, + CR_SO = 1, + CR_EQ = 2, + CR_GT = 4, + CR_LT = 8, - CR_SO_BIT = 0, - CR_EQ_BIT = 1, - CR_GT_BIT = 2, - CR_LT_BIT = 3, + CR_SO_BIT = 0, + CR_EQ_BIT = 1, + CR_GT_BIT = 2, + CR_LT_BIT = 3, }; // Convert between PPC and internal representation of CR. inline u64 PPCCRToInternal(u8 value) { - u64 cr_val = 0x100000000; - cr_val |= (u64)!!(value & CR_SO) << 61; - cr_val |= (u64)!(value & CR_EQ); - cr_val |= (u64)!(value & CR_GT) << 63; - cr_val |= (u64)!!(value & CR_LT) << 62; + u64 cr_val = 0x100000000; + cr_val |= (u64) !!(value & CR_SO) << 61; + cr_val |= (u64) !(value & CR_EQ); + cr_val |= (u64) !(value & CR_GT) << 63; + cr_val |= (u64) !!(value & CR_LT) << 62; - return cr_val; + return cr_val; } // convert flags into 64-bit CR values with a lookup table @@ -306,84 +307,84 @@ extern const u64 m_crTable[16]; // ppcState.cr_val for more explanations. inline void SetCRField(int cr_field, int value) { - PowerPC::ppcState.cr_val[cr_field] = m_crTable[value]; + PowerPC::ppcState.cr_val[cr_field] = m_crTable[value]; } inline u32 GetCRField(int cr_field) { - u64 cr_val = PowerPC::ppcState.cr_val[cr_field]; - u32 ppc_cr = 0; + u64 cr_val = PowerPC::ppcState.cr_val[cr_field]; + u32 ppc_cr = 0; - // SO - ppc_cr |= !!(cr_val & (1ull << 61)); - // EQ - ppc_cr |= ((cr_val & 0xFFFFFFFF) == 0) << 1; - // GT - ppc_cr |= ((s64)cr_val > 0) << 2; - // LT - ppc_cr |= !!(cr_val & (1ull << 62)) << 3; + // SO + ppc_cr |= !!(cr_val & (1ull << 61)); + // EQ + ppc_cr |= ((cr_val & 0xFFFFFFFF) == 0) << 1; + // GT + ppc_cr |= ((s64)cr_val > 0) << 2; + // LT + ppc_cr |= !!(cr_val & (1ull << 62)) << 3; - return ppc_cr; + return ppc_cr; } inline u32 GetCRBit(int bit) { - return (GetCRField(bit >> 2) >> (3 - (bit & 3))) & 1; + return (GetCRField(bit >> 2) >> (3 - (bit & 3))) & 1; } inline void SetCRBit(int bit, int value) { - if (value & 1) - SetCRField(bit >> 2, GetCRField(bit >> 2) | (0x8 >> (bit & 3))); - else - SetCRField(bit >> 2, GetCRField(bit >> 2) & ~(0x8 >> (bit & 3))); + if (value & 1) + SetCRField(bit >> 2, GetCRField(bit >> 2) | (0x8 >> (bit & 3))); + else + SetCRField(bit >> 2, GetCRField(bit >> 2) & ~(0x8 >> (bit & 3))); } // SetCR and GetCR are fairly slow. Should be avoided if possible. inline void SetCR(u32 new_cr) { - PowerPC::ExpandCR(new_cr); + PowerPC::ExpandCR(new_cr); } inline u32 GetCR() { - return PowerPC::CompactCR(); + return PowerPC::CompactCR(); } inline void SetCarry(int ca) { - PowerPC::ppcState.xer_ca = ca; + PowerPC::ppcState.xer_ca = ca; } inline int GetCarry() { - return PowerPC::ppcState.xer_ca; + return PowerPC::ppcState.xer_ca; } inline UReg_XER GetXER() { - u32 xer = 0; - xer |= PowerPC::ppcState.xer_stringctrl; - xer |= PowerPC::ppcState.xer_ca << XER_CA_SHIFT; - xer |= PowerPC::ppcState.xer_so_ov << XER_OV_SHIFT; - return xer; + u32 xer = 0; + xer |= PowerPC::ppcState.xer_stringctrl; + xer |= PowerPC::ppcState.xer_ca << XER_CA_SHIFT; + xer |= PowerPC::ppcState.xer_so_ov << XER_OV_SHIFT; + return xer; } inline void SetXER(UReg_XER new_xer) { - PowerPC::ppcState.xer_stringctrl = new_xer.BYTE_COUNT + (new_xer.BYTE_CMP << 8); - PowerPC::ppcState.xer_ca = new_xer.CA; - PowerPC::ppcState.xer_so_ov = (new_xer.SO << 1) + new_xer.OV; + PowerPC::ppcState.xer_stringctrl = new_xer.BYTE_COUNT + (new_xer.BYTE_CMP << 8); + PowerPC::ppcState.xer_ca = new_xer.CA; + PowerPC::ppcState.xer_so_ov = (new_xer.SO << 1) + new_xer.OV; } inline int GetXER_SO() { - return PowerPC::ppcState.xer_so_ov >> 1; + return PowerPC::ppcState.xer_so_ov >> 1; } inline void SetXER_SO(int value) { - PowerPC::ppcState.xer_so_ov |= value << 1; + PowerPC::ppcState.xer_so_ov |= value << 1; } void UpdateFPRF(double dvalue); diff --git a/Source/Core/Core/PowerPC/Profiler.cpp b/Source/Core/Core/PowerPC/Profiler.cpp index af54f785df..72d0a3d0e1 100644 --- a/Source/Core/Core/PowerPC/Profiler.cpp +++ b/Source/Core/Core/PowerPC/Profiler.cpp @@ -2,18 +2,17 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "Core/PowerPC/Profiler.h" #include #include "Core/PowerPC/JitInterface.h" -#include "Core/PowerPC/Profiler.h" namespace Profiler { - bool g_ProfileBlocks; void WriteProfileResults(const std::string& filename) { - JitInterface::WriteProfileResults(filename); + JitInterface::WriteProfileResults(filename); } } // namespace diff --git a/Source/Core/Core/PowerPC/Profiler.h b/Source/Core/Core/PowerPC/Profiler.h index 040eb7c88f..f434a1eea4 100644 --- a/Source/Core/Core/PowerPC/Profiler.h +++ b/Source/Core/Core/PowerPC/Profiler.h @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - #pragma once #include @@ -14,24 +13,23 @@ #if defined(_M_X86_64) -#define PROFILER_QUERY_PERFORMANCE_COUNTER(pt) \ - MOV(64, R(ABI_PARAM1), Imm64((u64) pt)); \ - ABI_CallFunction((const void*) QueryPerformanceCounter) +#define PROFILER_QUERY_PERFORMANCE_COUNTER(pt) \ + MOV(64, R(ABI_PARAM1), Imm64((u64)pt)); \ + ABI_CallFunction((const void*)QueryPerformanceCounter) // block->ticCounter += block->ticStop - block->ticStart -#define PROFILER_UPDATE_TIME(block) \ - MOV(64, R(RSCRATCH2), Imm64((u64) block)); \ - MOV(64, R(RSCRATCH), MDisp(RSCRATCH2, offsetof(struct JitBlock, ticStop))); \ - SUB(64, R(RSCRATCH), MDisp(RSCRATCH2, offsetof(struct JitBlock, ticStart))); \ - ADD(64, R(RSCRATCH), MDisp(RSCRATCH2, offsetof(struct JitBlock, ticCounter))); \ - MOV(64, MDisp(RSCRATCH2, offsetof(struct JitBlock, ticCounter)), R(RSCRATCH)); +#define PROFILER_UPDATE_TIME(block) \ + MOV(64, R(RSCRATCH2), Imm64((u64)block)); \ + MOV(64, R(RSCRATCH), MDisp(RSCRATCH2, offsetof(struct JitBlock, ticStop))); \ + SUB(64, R(RSCRATCH), MDisp(RSCRATCH2, offsetof(struct JitBlock, ticStart))); \ + ADD(64, R(RSCRATCH), MDisp(RSCRATCH2, offsetof(struct JitBlock, ticCounter))); \ + MOV(64, MDisp(RSCRATCH2, offsetof(struct JitBlock, ticCounter)), R(RSCRATCH)); -#define PROFILER_VPUSH \ - BitSet32 registersInUse = CallerSavedRegistersInUse(); \ - ABI_PushRegistersAndAdjustStack(registersInUse, 0); +#define PROFILER_VPUSH \ + BitSet32 registersInUse = CallerSavedRegistersInUse(); \ + ABI_PushRegistersAndAdjustStack(registersInUse, 0); -#define PROFILER_VPOP \ - ABI_PopRegistersAndAdjustStack(registersInUse, 0); +#define PROFILER_VPOP ABI_PopRegistersAndAdjustStack(registersInUse, 0); #else @@ -44,24 +42,25 @@ struct BlockStat { - BlockStat(int bn, u32 _addr, u64 c, u64 ticks, u64 run, u32 size) : - blockNum(bn), addr(_addr), cost(c), tick_counter(ticks), run_count(run), block_size(size) {} - int blockNum; - u32 addr; - u64 cost; - u64 tick_counter; - u64 run_count; - u32 block_size; + BlockStat(int bn, u32 _addr, u64 c, u64 ticks, u64 run, u32 size) + : blockNum(bn), addr(_addr), cost(c), tick_counter(ticks), run_count(run), block_size(size) + { + } + int blockNum; + u32 addr; + u64 cost; + u64 tick_counter; + u64 run_count; + u32 block_size; - bool operator <(const BlockStat &other) const - { return cost > other.cost; } + bool operator<(const BlockStat& other) const { return cost > other.cost; } }; struct ProfileStats { - std::vector block_stats; - u64 cost_sum; - u64 timecost_sum; - u64 countsPerSec; + std::vector block_stats; + u64 cost_sum; + u64 timecost_sum; + u64 countsPerSec; }; namespace Profiler diff --git a/Source/Core/Core/PowerPC/SignatureDB.cpp b/Source/Core/Core/PowerPC/SignatureDB.cpp index 34b95b1c7d..b4fadd24a3 100644 --- a/Source/Core/Core/PowerPC/SignatureDB.cpp +++ b/Source/Core/Core/PowerPC/SignatureDB.cpp @@ -7,198 +7,199 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/Logging/Log.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/PPCSymbolDB.h" +#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/SignatureDB.h" namespace { - // On-disk format for SignatureDB entries. struct FuncDesc { - u32 checkSum; - u32 size; - char name[128]; + u32 checkSum; + u32 size; + char name[128]; }; } // namespace bool SignatureDB::Load(const std::string& filename) { - File::IOFile f(filename, "rb"); - if (!f) - return false; - u32 fcount = 0; - f.ReadArray(&fcount, 1); - for (size_t i = 0; i < fcount; i++) - { - FuncDesc temp; - memset(&temp, 0, sizeof(temp)); + File::IOFile f(filename, "rb"); + if (!f) + return false; + u32 fcount = 0; + f.ReadArray(&fcount, 1); + for (size_t i = 0; i < fcount; i++) + { + FuncDesc temp; + memset(&temp, 0, sizeof(temp)); - f.ReadArray(&temp, 1); - temp.name[sizeof(temp.name)-1] = 0; + f.ReadArray(&temp, 1); + temp.name[sizeof(temp.name) - 1] = 0; - DBFunc dbf; - dbf.name = temp.name; - dbf.size = temp.size; - database[temp.checkSum] = dbf; - } + DBFunc dbf; + dbf.name = temp.name; + dbf.size = temp.size; + database[temp.checkSum] = dbf; + } - return true; + return true; } bool SignatureDB::Save(const std::string& filename) { - File::IOFile f(filename, "wb"); - if (!f) - { - ERROR_LOG(OSHLE, "Database save failed"); - return false; - } - u32 fcount = (u32)database.size(); - f.WriteArray(&fcount, 1); - for (const auto& entry : database) - { - FuncDesc temp; - memset(&temp, 0, sizeof(temp)); - temp.checkSum = entry.first; - temp.size = entry.second.size; - strncpy(temp.name, entry.second.name.c_str(), 127); - f.WriteArray(&temp, 1); - } + File::IOFile f(filename, "wb"); + if (!f) + { + ERROR_LOG(OSHLE, "Database save failed"); + return false; + } + u32 fcount = (u32)database.size(); + f.WriteArray(&fcount, 1); + for (const auto& entry : database) + { + FuncDesc temp; + memset(&temp, 0, sizeof(temp)); + temp.checkSum = entry.first; + temp.size = entry.second.size; + strncpy(temp.name, entry.second.name.c_str(), 127); + f.WriteArray(&temp, 1); + } - INFO_LOG(OSHLE, "Database save successful"); - return true; + INFO_LOG(OSHLE, "Database save successful"); + return true; } -//Adds a known function to the hash database +// Adds a known function to the hash database u32 SignatureDB::Add(u32 startAddr, u32 size, const std::string& name) { - u32 hash = ComputeCodeChecksum(startAddr, startAddr + size - 4); + u32 hash = ComputeCodeChecksum(startAddr, startAddr + size - 4); - DBFunc temp_dbfunc; - temp_dbfunc.size = size; - temp_dbfunc.name = name; + DBFunc temp_dbfunc; + temp_dbfunc.size = size; + temp_dbfunc.name = name; - FuncDB::iterator iter = database.find(hash); - if (iter == database.end()) - database[hash] = temp_dbfunc; + FuncDB::iterator iter = database.find(hash); + if (iter == database.end()) + database[hash] = temp_dbfunc; - return hash; + return hash; } void SignatureDB::List() { - for (const auto& entry : database) - { - INFO_LOG(OSHLE, "%s : %i bytes, hash = %08x", entry.second.name.c_str(), entry.second.size, entry.first); - } - INFO_LOG(OSHLE, "%zu functions known in current database.", database.size()); + for (const auto& entry : database) + { + INFO_LOG(OSHLE, "%s : %i bytes, hash = %08x", entry.second.name.c_str(), entry.second.size, + entry.first); + } + INFO_LOG(OSHLE, "%zu functions known in current database.", database.size()); } void SignatureDB::Clear() { - database.clear(); + database.clear(); } -void SignatureDB::Apply(PPCSymbolDB *symbol_db) +void SignatureDB::Apply(PPCSymbolDB* symbol_db) { - for (const auto& entry : database) - { - u32 hash = entry.first; - Symbol *function = symbol_db->GetSymbolFromHash(hash); - if (function) - { - // Found the function. Let's rename it according to the symbol file. - if (entry.second.size == (unsigned int)function->size) - { - function->name = entry.second.name; - INFO_LOG(OSHLE, "Found %s at %08x (size: %08x)!", entry.second.name.c_str(), function->address, function->size); - } - else - { - function->name = entry.second.name; - ERROR_LOG(OSHLE, "Wrong size! Found %s at %08x (size: %08x instead of %08x)!", - entry.second.name.c_str(), function->address, function->size, entry.second.size); - } - } - } - symbol_db->Index(); + for (const auto& entry : database) + { + u32 hash = entry.first; + Symbol* function = symbol_db->GetSymbolFromHash(hash); + if (function) + { + // Found the function. Let's rename it according to the symbol file. + if (entry.second.size == (unsigned int)function->size) + { + function->name = entry.second.name; + INFO_LOG(OSHLE, "Found %s at %08x (size: %08x)!", entry.second.name.c_str(), + function->address, function->size); + } + else + { + function->name = entry.second.name; + ERROR_LOG(OSHLE, "Wrong size! Found %s at %08x (size: %08x instead of %08x)!", + entry.second.name.c_str(), function->address, function->size, entry.second.size); + } + } + } + symbol_db->Index(); } -void SignatureDB::Initialize(PPCSymbolDB *symbol_db, const std::string& prefix) +void SignatureDB::Initialize(PPCSymbolDB* symbol_db, const std::string& prefix) { - for (const auto& symbol : symbol_db->Symbols()) - { - if ((prefix.empty() && (!symbol.second.name.empty()) && symbol.second.name.substr(0, 3) != "zz_" && symbol.second.name.substr(0, 1) != ".") || - ((!prefix.empty()) && symbol.second.name.substr(0, prefix.size()) == prefix)) - { - DBFunc temp_dbfunc; - temp_dbfunc.name = symbol.second.name; - temp_dbfunc.size = symbol.second.size; - database[symbol.second.hash] = temp_dbfunc; - } - } + for (const auto& symbol : symbol_db->Symbols()) + { + if ((prefix.empty() && (!symbol.second.name.empty()) && + symbol.second.name.substr(0, 3) != "zz_" && symbol.second.name.substr(0, 1) != ".") || + ((!prefix.empty()) && symbol.second.name.substr(0, prefix.size()) == prefix)) + { + DBFunc temp_dbfunc; + temp_dbfunc.name = symbol.second.name; + temp_dbfunc.size = symbol.second.size; + database[symbol.second.hash] = temp_dbfunc; + } + } } /*static*/ u32 SignatureDB::ComputeCodeChecksum(u32 offsetStart, u32 offsetEnd) { - u32 sum = 0; - for (u32 offset = offsetStart; offset <= offsetEnd; offset += 4) - { - u32 opcode = PowerPC::HostRead_Instruction(offset); - u32 op = opcode & 0xFC000000; - u32 op2 = 0; - u32 op3 = 0; - u32 auxop = op >> 26; - switch (auxop) - { - case 4: //PS instructions - op2 = opcode & 0x0000003F; - switch ( op2 ) - { - case 0: - case 8: - case 16: - case 21: - case 22: - op3 = opcode & 0x000007C0; - } - break; + u32 sum = 0; + for (u32 offset = offsetStart; offset <= offsetEnd; offset += 4) + { + u32 opcode = PowerPC::HostRead_Instruction(offset); + u32 op = opcode & 0xFC000000; + u32 op2 = 0; + u32 op3 = 0; + u32 auxop = op >> 26; + switch (auxop) + { + case 4: // PS instructions + op2 = opcode & 0x0000003F; + switch (op2) + { + case 0: + case 8: + case 16: + case 21: + case 22: + op3 = opcode & 0x000007C0; + } + break; - case 7: //addi muli etc - case 8: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - op2 = opcode & 0x03FF0000; - break; + case 7: // addi muli etc + case 8: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + op2 = opcode & 0x03FF0000; + break; - case 19: // MCRF?? - case 31: //integer - case 63: //fpu - op2 = opcode & 0x000007FF; - break; - case 59: //fpu - op2 = opcode & 0x0000003F; - if (op2 < 16) - op3 = opcode & 0x000007C0; - break; - default: - if (auxop >= 32 && auxop < 56) - op2 = opcode & 0x03FF0000; - break; - } - // Checksum only uses opcode, not opcode data, because opcode data changes - // in all compilations, but opcodes don't! - sum = ( ( (sum << 17 ) & 0xFFFE0000 ) | ( (sum >> 15) & 0x0001FFFF ) ); - sum = sum ^ (op | op2 | op3); - } - return sum; + case 19: // MCRF?? + case 31: // integer + case 63: // fpu + op2 = opcode & 0x000007FF; + break; + case 59: // fpu + op2 = opcode & 0x0000003F; + if (op2 < 16) + op3 = opcode & 0x000007C0; + break; + default: + if (auxop >= 32 && auxop < 56) + op2 = opcode & 0x03FF0000; + break; + } + // Checksum only uses opcode, not opcode data, because opcode data changes + // in all compilations, but opcodes don't! + sum = (((sum << 17) & 0xFFFE0000) | ((sum >> 15) & 0x0001FFFF)); + sum = sum ^ (op | op2 | op3); + } + return sum; } - diff --git a/Source/Core/Core/PowerPC/SignatureDB.h b/Source/Core/Core/PowerPC/SignatureDB.h index 85f5268e24..6c081aacce 100644 --- a/Source/Core/Core/PowerPC/SignatureDB.h +++ b/Source/Core/Core/PowerPC/SignatureDB.h @@ -15,31 +15,30 @@ class PPCSymbolDB; class SignatureDB { - struct DBFunc - { - std::string name; - u32 size; - DBFunc() : size(0) - { - } - }; + struct DBFunc + { + std::string name; + u32 size; + DBFunc() : size(0) {} + }; - // Map from signature to function. We store the DB in this map because it optimizes the - // most common operation - lookup. We don't care about ordering anyway. - typedef std::map FuncDB; - FuncDB database; + // Map from signature to function. We store the DB in this map because it optimizes the + // most common operation - lookup. We don't care about ordering anyway. + typedef std::map FuncDB; + FuncDB database; public: - // Returns the hash. - u32 Add(u32 startAddr, u32 size, const std::string& name); + // Returns the hash. + u32 Add(u32 startAddr, u32 size, const std::string& name); - bool Load(const std::string& filename); // Does not clear. Remember to clear first if that's what you want. - bool Save(const std::string& filename); - void Clear(); - void List(); + bool Load(const std::string& + filename); // Does not clear. Remember to clear first if that's what you want. + bool Save(const std::string& filename); + void Clear(); + void List(); - void Initialize(PPCSymbolDB *func_db, const std::string& prefix = ""); - void Apply(PPCSymbolDB *func_db); + void Initialize(PPCSymbolDB* func_db, const std::string& prefix = ""); + void Apply(PPCSymbolDB* func_db); - static u32 ComputeCodeChecksum(u32 offsetStart, u32 offsetEnd); + static u32 ComputeCodeChecksum(u32 offsetStart, u32 offsetEnd); }; diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 5f8ffb8acb..4d097d7eb5 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -2,13 +2,13 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #include #include #include #include #include -#include #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" @@ -23,13 +23,13 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" +#include "Core/HW/HW.h" +#include "Core/HW/Wiimote.h" #include "Core/Host.h" #include "Core/Movie.h" #include "Core/NetPlayClient.h" -#include "Core/State.h" -#include "Core/HW/HW.h" -#include "Core/HW/Wiimote.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/State.h" #include "VideoCommon/AVIDump.h" #include "VideoCommon/OnScreenDisplay.h" @@ -37,7 +37,6 @@ namespace State { - #if defined(__LZO_STRICT_16BIT) static const u32 IN_LEN = 8 * 1024u; #elif defined(LZO_ARCH_I086) && !defined(LZO_HAVE_MM_HUGE_ARRAY) @@ -50,8 +49,8 @@ static const u32 OUT_LEN = IN_LEN + (IN_LEN / 16) + 64 + 3; static unsigned char __LZO_MMODEL out[OUT_LEN]; -#define HEAP_ALLOC(var, size) \ - lzo_align_t __LZO_MMODEL var[((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t)] +#define HEAP_ALLOC(var, size) \ + lzo_align_t __LZO_MMODEL var[((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t)] static HEAP_ALLOC(wrkmem, LZO1X_1_MEM_COMPRESS); @@ -71,199 +70,182 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const u32 STATE_VERSION = 54; // Last changed in PR 3782 +static const u32 STATE_VERSION = 54; // Last changed in PR 3782 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list, // beacuse they save the exact Dolphin version to savestates. -static const std::map> s_old_versions = -{ - // The 16 -> 17 change modified the size of StateHeader, - // so version older than that can't even be decompressed anymore - { 17, { "3.5-1311", "3.5-1364" } }, - { 18, { "3.5-1366", "3.5-1371" } }, - { 19, { "3.5-1372", "3.5-1408" } }, - { 20, { "3.5-1409", "4.0-704" } }, - { 21, { "4.0-705", "4.0-889" } }, - { 22, { "4.0-905", "4.0-1871" } }, - { 23, { "4.0-1873", "4.0-1900" } }, - { 24, { "4.0-1902", "4.0-1919" } }, - { 25, { "4.0-1921", "4.0-1936" } }, - { 26, { "4.0-1939", "4.0-1959" } }, - { 27, { "4.0-1961", "4.0-2018" } }, - { 28, { "4.0-2020", "4.0-2291" } }, - { 29, { "4.0-2293", "4.0-2360" } }, - { 30, { "4.0-2362", "4.0-2628" } }, - { 31, { "4.0-2632", "4.0-3331" } }, - { 32, { "4.0-3334", "4.0-3340" } }, - { 33, { "4.0-3342", "4.0-3373" } }, - { 34, { "4.0-3376", "4.0-3402" } }, - { 35, { "4.0-3409", "4.0-3603" } }, - { 36, { "4.0-3610", "4.0-4480" } }, - { 37, { "4.0-4484", "4.0-4943" } }, - { 38, { "4.0-4963", "4.0-5267" } }, - { 39, { "4.0-5279", "4.0-5525" } }, - { 40, { "4.0-5531", "4.0-5809" } }, - { 41, { "4.0-5811", "4.0-5923" } }, - { 42, { "4.0-5925", "4.0-5946" } } -}; +static const std::map> s_old_versions = { + // The 16 -> 17 change modified the size of StateHeader, + // so version older than that can't even be decompressed anymore + {17, {"3.5-1311", "3.5-1364"}}, {18, {"3.5-1366", "3.5-1371"}}, {19, {"3.5-1372", "3.5-1408"}}, + {20, {"3.5-1409", "4.0-704"}}, {21, {"4.0-705", "4.0-889"}}, {22, {"4.0-905", "4.0-1871"}}, + {23, {"4.0-1873", "4.0-1900"}}, {24, {"4.0-1902", "4.0-1919"}}, {25, {"4.0-1921", "4.0-1936"}}, + {26, {"4.0-1939", "4.0-1959"}}, {27, {"4.0-1961", "4.0-2018"}}, {28, {"4.0-2020", "4.0-2291"}}, + {29, {"4.0-2293", "4.0-2360"}}, {30, {"4.0-2362", "4.0-2628"}}, {31, {"4.0-2632", "4.0-3331"}}, + {32, {"4.0-3334", "4.0-3340"}}, {33, {"4.0-3342", "4.0-3373"}}, {34, {"4.0-3376", "4.0-3402"}}, + {35, {"4.0-3409", "4.0-3603"}}, {36, {"4.0-3610", "4.0-4480"}}, {37, {"4.0-4484", "4.0-4943"}}, + {38, {"4.0-4963", "4.0-5267"}}, {39, {"4.0-5279", "4.0-5525"}}, {40, {"4.0-5531", "4.0-5809"}}, + {41, {"4.0-5811", "4.0-5923"}}, {42, {"4.0-5925", "4.0-5946"}}}; enum { - STATE_NONE = 0, - STATE_SAVE = 1, - STATE_LOAD = 2, + STATE_NONE = 0, + STATE_SAVE = 1, + STATE_LOAD = 2, }; static bool g_use_compression = true; void EnableCompression(bool compression) { - g_use_compression = compression; + g_use_compression = compression; } // Returns true if state version matches current Dolphin state version, false otherwise. static bool DoStateVersion(PointerWrap& p, std::string* version_created_by) { - u32 version = STATE_VERSION; - { - static const u32 COOKIE_BASE = 0xBAADBABE; - u32 cookie = version + COOKIE_BASE; - p.Do(cookie); - version = cookie - COOKIE_BASE; - } + u32 version = STATE_VERSION; + { + static const u32 COOKIE_BASE = 0xBAADBABE; + u32 cookie = version + COOKIE_BASE; + p.Do(cookie); + version = cookie - COOKIE_BASE; + } - *version_created_by = scm_rev_str; - if (version > 42) - p.Do(*version_created_by); - else - version_created_by->clear(); + *version_created_by = scm_rev_str; + if (version > 42) + p.Do(*version_created_by); + else + version_created_by->clear(); - if (version != STATE_VERSION) - { - if (version_created_by->empty() && s_old_versions.count(version)) - { - // The savestate is from an old version that doesn't - // save the Dolphin version number to savestates, but - // by looking up the savestate version number, it is possible - // to know approximately which Dolphin version was used. + if (version != STATE_VERSION) + { + if (version_created_by->empty() && s_old_versions.count(version)) + { + // The savestate is from an old version that doesn't + // save the Dolphin version number to savestates, but + // by looking up the savestate version number, it is possible + // to know approximately which Dolphin version was used. - std::pair version_range = s_old_versions.find(version)->second; - std::string oldest_version = version_range.first; - std::string newest_version = version_range.second; + std::pair version_range = s_old_versions.find(version)->second; + std::string oldest_version = version_range.first; + std::string newest_version = version_range.second; - *version_created_by = "Dolphin " + oldest_version + " - " + newest_version; - } + *version_created_by = "Dolphin " + oldest_version + " - " + newest_version; + } - return false; - } + return false; + } - p.DoMarker("Version"); - return true; + p.DoMarker("Version"); + return true; } static std::string DoState(PointerWrap& p) { - std::string version_created_by; - if (!DoStateVersion(p, &version_created_by)) - { - // because the version doesn't match, fail. - // this will trigger an OSD message like "Can't load state from other revisions" - // we could use the version numbers to maintain some level of backward compatibility, but currently don't. - p.SetMode(PointerWrap::MODE_MEASURE); - return version_created_by; - } + std::string version_created_by; + if (!DoStateVersion(p, &version_created_by)) + { + // because the version doesn't match, fail. + // this will trigger an OSD message like "Can't load state from other revisions" + // we could use the version numbers to maintain some level of backward compatibility, but + // currently don't. + p.SetMode(PointerWrap::MODE_MEASURE); + return version_created_by; + } - // Begin with video backend, so that it gets a chance to clear its caches and writeback modified things to RAM - g_video_backend->DoState(p); - p.DoMarker("video_backend"); + // Begin with video backend, so that it gets a chance to clear its caches and writeback modified + // things to RAM + g_video_backend->DoState(p); + p.DoMarker("video_backend"); - if (SConfig::GetInstance().bWii) - Wiimote::DoState(p); - p.DoMarker("Wiimote"); + if (SConfig::GetInstance().bWii) + Wiimote::DoState(p); + p.DoMarker("Wiimote"); - PowerPC::DoState(p); - p.DoMarker("PowerPC"); - // CoreTiming needs to be restored before restoring Hardware because - // the controller code might need to schedule an event if the controller has changed. - CoreTiming::DoState(p); - p.DoMarker("CoreTiming"); - HW::DoState(p); - p.DoMarker("HW"); - Movie::DoState(p); - p.DoMarker("Movie"); + PowerPC::DoState(p); + p.DoMarker("PowerPC"); + // CoreTiming needs to be restored before restoring Hardware because + // the controller code might need to schedule an event if the controller has changed. + CoreTiming::DoState(p); + p.DoMarker("CoreTiming"); + HW::DoState(p); + p.DoMarker("HW"); + Movie::DoState(p); + p.DoMarker("Movie"); -#if defined(HAVE_LIBAV) || defined (_WIN32) - AVIDump::DoState(); +#if defined(HAVE_LIBAV) || defined(_WIN32) + AVIDump::DoState(); #endif - return version_created_by; + return version_created_by; } void LoadFromBuffer(std::vector& buffer) { - if (NetPlay::IsNetPlayRunning()) - { - OSD::AddMessage("Loading savestates is disabled in Netplay to prevent desyncs"); - return; - } + if (NetPlay::IsNetPlayRunning()) + { + OSD::AddMessage("Loading savestates is disabled in Netplay to prevent desyncs"); + return; + } - bool wasUnpaused = Core::PauseAndLock(true); + bool wasUnpaused = Core::PauseAndLock(true); - u8* ptr = &buffer[0]; - PointerWrap p(&ptr, PointerWrap::MODE_READ); - DoState(p); + u8* ptr = &buffer[0]; + PointerWrap p(&ptr, PointerWrap::MODE_READ); + DoState(p); - Core::PauseAndLock(false, wasUnpaused); + Core::PauseAndLock(false, wasUnpaused); } void SaveToBuffer(std::vector& buffer) { - bool wasUnpaused = Core::PauseAndLock(true); + bool wasUnpaused = Core::PauseAndLock(true); - u8* ptr = nullptr; - PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); + u8* ptr = nullptr; + PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); - DoState(p); - const size_t buffer_size = reinterpret_cast(ptr); - buffer.resize(buffer_size); + DoState(p); + const size_t buffer_size = reinterpret_cast(ptr); + buffer.resize(buffer_size); - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_WRITE); - DoState(p); + ptr = &buffer[0]; + p.SetMode(PointerWrap::MODE_WRITE); + DoState(p); - Core::PauseAndLock(false, wasUnpaused); + Core::PauseAndLock(false, wasUnpaused); } void VerifyBuffer(std::vector& buffer) { - bool wasUnpaused = Core::PauseAndLock(true); + bool wasUnpaused = Core::PauseAndLock(true); - u8* ptr = &buffer[0]; - PointerWrap p(&ptr, PointerWrap::MODE_VERIFY); - DoState(p); + u8* ptr = &buffer[0]; + PointerWrap p(&ptr, PointerWrap::MODE_VERIFY); + DoState(p); - Core::PauseAndLock(false, wasUnpaused); + Core::PauseAndLock(false, wasUnpaused); } // return state number not in map static int GetEmptySlot(std::map m) { - for (int i = 1; i <= (int)NUM_STATES; i++) - { - bool found = false; - for (auto& p : m) - { - if (p.second == i) - { - found = true; - break; - } - } - if (!found) - return i; - } - return -1; + for (int i = 1; i <= (int)NUM_STATES; i++) + { + bool found = false; + for (auto& p : m) + { + if (p.second == i) + { + found = true; + break; + } + } + if (!found) + return i; + } + return -1; } static std::string MakeStateFilename(int number); @@ -271,489 +253,490 @@ static std::string MakeStateFilename(int number); // read state timestamps static std::map GetSavedStates() { - StateHeader header; - std::map m; - for (int i = 1; i <= (int)NUM_STATES; i++) - { - std::string filename = MakeStateFilename(i); - if (File::Exists(filename)) - { - if (ReadHeader(filename, header)) - { - double d = Common::Timer::GetDoubleTime() - header.time; + StateHeader header; + std::map m; + for (int i = 1; i <= (int)NUM_STATES; i++) + { + std::string filename = MakeStateFilename(i); + if (File::Exists(filename)) + { + if (ReadHeader(filename, header)) + { + double d = Common::Timer::GetDoubleTime() - header.time; - // increase time until unique value is obtained - while (m.find(d) != m.end()) - d += .001; + // increase time until unique value is obtained + while (m.find(d) != m.end()) + d += .001; - m.emplace(d, i); - } - } - } - return m; + m.emplace(d, i); + } + } + } + return m; } struct CompressAndDumpState_args { - std::vector* buffer_vector; - std::mutex* buffer_mutex; - std::string filename; - bool wait; + std::vector* buffer_vector; + std::mutex* buffer_mutex; + std::string filename; + bool wait; }; static void CompressAndDumpState(CompressAndDumpState_args save_args) { - std::lock_guard lk(*save_args.buffer_mutex); + std::lock_guard lk(*save_args.buffer_mutex); - // ScopeGuard is used here to ensure that g_compressAndDumpStateSyncEvent.Set() - // will be called and that it will happen after the IOFile is closed. - // Both ScopeGuard's and IOFile's finalization occur at respective object destruction time. - // As Local (stack) objects are destructed in the reverse order of construction and "ScopeGuard on_exit" - // is created before the "IOFile f", it is guaranteed that the file will be finalized before - // the ScopeGuard's finalization (i.e. "g_compressAndDumpStateSyncEvent.Set()" call). - Common::ScopeGuard on_exit([]() - { - g_compressAndDumpStateSyncEvent.Set(); - }); - // If it is not required to wait, we call finalizer early (and it won't be called again at destruction). - if (!save_args.wait) - on_exit.Exit(); + // ScopeGuard is used here to ensure that g_compressAndDumpStateSyncEvent.Set() + // will be called and that it will happen after the IOFile is closed. + // Both ScopeGuard's and IOFile's finalization occur at respective object destruction time. + // As Local (stack) objects are destructed in the reverse order of construction and "ScopeGuard + // on_exit" + // is created before the "IOFile f", it is guaranteed that the file will be finalized before + // the ScopeGuard's finalization (i.e. "g_compressAndDumpStateSyncEvent.Set()" call). + Common::ScopeGuard on_exit([]() { g_compressAndDumpStateSyncEvent.Set(); }); + // If it is not required to wait, we call finalizer early (and it won't be called again at + // destruction). + if (!save_args.wait) + on_exit.Exit(); - const u8* const buffer_data = &(*(save_args.buffer_vector))[0]; - const size_t buffer_size = (save_args.buffer_vector)->size(); - std::string& filename = save_args.filename; + const u8* const buffer_data = &(*(save_args.buffer_vector))[0]; + const size_t buffer_size = (save_args.buffer_vector)->size(); + std::string& filename = save_args.filename; - // For easy debugging - Common::SetCurrentThreadName("SaveState thread"); + // For easy debugging + Common::SetCurrentThreadName("SaveState thread"); - // Moving to last overwritten save-state - if (File::Exists(filename)) - { - if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav")) - File::Delete((File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav")); - if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav.dtm")) - File::Delete((File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav.dtm")); + // Moving to last overwritten save-state + if (File::Exists(filename)) + { + if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav")) + File::Delete((File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav")); + if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav.dtm")) + File::Delete((File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav.dtm")); - if (!File::Rename(filename, File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav")) - Core::DisplayMessage("Failed to move previous state to state undo backup", 1000); - else - File::Rename(filename + ".dtm", File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav.dtm"); - } + if (!File::Rename(filename, File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav")) + Core::DisplayMessage("Failed to move previous state to state undo backup", 1000); + else + File::Rename(filename + ".dtm", File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav.dtm"); + } - if ((Movie::IsMovieActive()) && !Movie::IsJustStartingRecordingInputFromSaveState()) - Movie::SaveRecording(filename + ".dtm"); - else if (!Movie::IsMovieActive()) - File::Delete(filename + ".dtm"); + if ((Movie::IsMovieActive()) && !Movie::IsJustStartingRecordingInputFromSaveState()) + Movie::SaveRecording(filename + ".dtm"); + else if (!Movie::IsMovieActive()) + File::Delete(filename + ".dtm"); - File::IOFile f(filename, "wb"); - if (!f) - { - Core::DisplayMessage("Could not save state", 2000); - return; - } + File::IOFile f(filename, "wb"); + if (!f) + { + Core::DisplayMessage("Could not save state", 2000); + return; + } - // Setting up the header - StateHeader header; - strncpy(header.gameID, SConfig::GetInstance().GetUniqueID().c_str(), 6); - header.size = g_use_compression ? (u32)buffer_size : 0; - header.time = Common::Timer::GetDoubleTime(); + // Setting up the header + StateHeader header; + strncpy(header.gameID, SConfig::GetInstance().GetUniqueID().c_str(), 6); + header.size = g_use_compression ? (u32)buffer_size : 0; + header.time = Common::Timer::GetDoubleTime(); - f.WriteArray(&header, 1); + f.WriteArray(&header, 1); - if (header.size != 0) // non-zero header size means the state is compressed - { - lzo_uint i = 0; - while (true) - { - lzo_uint32 cur_len = 0; - lzo_uint out_len = 0; + if (header.size != 0) // non-zero header size means the state is compressed + { + lzo_uint i = 0; + while (true) + { + lzo_uint32 cur_len = 0; + lzo_uint out_len = 0; - if ((i + IN_LEN) >= buffer_size) - { - cur_len = (lzo_uint32)(buffer_size - i); - } - else - { - cur_len = IN_LEN; - } + if ((i + IN_LEN) >= buffer_size) + { + cur_len = (lzo_uint32)(buffer_size - i); + } + else + { + cur_len = IN_LEN; + } - if (lzo1x_1_compress(buffer_data + i, cur_len, out, &out_len, wrkmem) != LZO_E_OK) - PanicAlertT("Internal LZO Error - compression failed"); + if (lzo1x_1_compress(buffer_data + i, cur_len, out, &out_len, wrkmem) != LZO_E_OK) + PanicAlertT("Internal LZO Error - compression failed"); - // The size of the data to write is 'out_len' - f.WriteArray((lzo_uint32*)&out_len, 1); - f.WriteBytes(out, out_len); + // The size of the data to write is 'out_len' + f.WriteArray((lzo_uint32*)&out_len, 1); + f.WriteBytes(out, out_len); - if (cur_len != IN_LEN) - break; + if (cur_len != IN_LEN) + break; - i += cur_len; - } - } - else // uncompressed - { - f.WriteBytes(buffer_data, buffer_size); - } + i += cur_len; + } + } + else // uncompressed + { + f.WriteBytes(buffer_data, buffer_size); + } - Core::DisplayMessage(StringFromFormat("Saved State to %s", filename.c_str()), 2000); - Host_UpdateMainFrame(); + Core::DisplayMessage(StringFromFormat("Saved State to %s", filename.c_str()), 2000); + Host_UpdateMainFrame(); } void SaveAs(const std::string& filename, bool wait) { - // Pause the core while we save the state - bool wasUnpaused = Core::PauseAndLock(true); + // Pause the core while we save the state + bool wasUnpaused = Core::PauseAndLock(true); - // Measure the size of the buffer. - u8 *ptr = nullptr; - PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); - DoState(p); - const size_t buffer_size = reinterpret_cast(ptr); + // Measure the size of the buffer. + u8* ptr = nullptr; + PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); + DoState(p); + const size_t buffer_size = reinterpret_cast(ptr); - // Then actually do the write. - { - std::lock_guard lk(g_cs_current_buffer); - g_current_buffer.resize(buffer_size); - ptr = &g_current_buffer[0]; - p.SetMode(PointerWrap::MODE_WRITE); - DoState(p); - } + // Then actually do the write. + { + std::lock_guard lk(g_cs_current_buffer); + g_current_buffer.resize(buffer_size); + ptr = &g_current_buffer[0]; + p.SetMode(PointerWrap::MODE_WRITE); + DoState(p); + } - if (p.GetMode() == PointerWrap::MODE_WRITE) - { - Core::DisplayMessage("Saving State...", 1000); + if (p.GetMode() == PointerWrap::MODE_WRITE) + { + Core::DisplayMessage("Saving State...", 1000); - CompressAndDumpState_args save_args; - save_args.buffer_vector = &g_current_buffer; - save_args.buffer_mutex = &g_cs_current_buffer; - save_args.filename = filename; - save_args.wait = wait; + CompressAndDumpState_args save_args; + save_args.buffer_vector = &g_current_buffer; + save_args.buffer_mutex = &g_cs_current_buffer; + save_args.filename = filename; + save_args.wait = wait; - Flush(); - g_save_thread = std::thread(CompressAndDumpState, save_args); - g_compressAndDumpStateSyncEvent.Wait(); + Flush(); + g_save_thread = std::thread(CompressAndDumpState, save_args); + g_compressAndDumpStateSyncEvent.Wait(); - g_last_filename = filename; - } - else - { - // someone aborted the save by changing the mode? - Core::DisplayMessage("Unable to save: Internal DoState Error", 4000); - } + g_last_filename = filename; + } + else + { + // someone aborted the save by changing the mode? + Core::DisplayMessage("Unable to save: Internal DoState Error", 4000); + } - // Resume the core and disable stepping - Core::PauseAndLock(false, wasUnpaused); + // Resume the core and disable stepping + Core::PauseAndLock(false, wasUnpaused); } bool ReadHeader(const std::string& filename, StateHeader& header) { - Flush(); - File::IOFile f(filename, "rb"); - if (!f) - { - Core::DisplayMessage("State not found", 2000); - return false; - } + Flush(); + File::IOFile f(filename, "rb"); + if (!f) + { + Core::DisplayMessage("State not found", 2000); + return false; + } - f.ReadArray(&header, 1); - return true; + f.ReadArray(&header, 1); + return true; } std::string GetInfoStringOfSlot(int slot) { - std::string filename = MakeStateFilename(slot); - if (!File::Exists(filename)) - return GetStringT("Empty"); + std::string filename = MakeStateFilename(slot); + if (!File::Exists(filename)) + return GetStringT("Empty"); - State::StateHeader header; - if (!ReadHeader(filename, header)) - return GetStringT("Unknown"); + State::StateHeader header; + if (!ReadHeader(filename, header)) + return GetStringT("Unknown"); - return Common::Timer::GetDateTimeFormatted(header.time); + return Common::Timer::GetDateTimeFormatted(header.time); } static void LoadFileStateData(const std::string& filename, std::vector& ret_data) { - Flush(); - File::IOFile f(filename, "rb"); - if (!f) - { - Core::DisplayMessage("State not found", 2000); - return; - } + Flush(); + File::IOFile f(filename, "rb"); + if (!f) + { + Core::DisplayMessage("State not found", 2000); + return; + } - StateHeader header; - f.ReadArray(&header, 1); + StateHeader header; + f.ReadArray(&header, 1); - if (strncmp(SConfig::GetInstance().GetUniqueID().c_str(), header.gameID, 6)) - { - Core::DisplayMessage(StringFromFormat("State belongs to a different game (ID %.*s)", - 6, header.gameID), 2000); - return; - } + if (strncmp(SConfig::GetInstance().GetUniqueID().c_str(), header.gameID, 6)) + { + Core::DisplayMessage( + StringFromFormat("State belongs to a different game (ID %.*s)", 6, header.gameID), 2000); + return; + } - std::vector buffer; + std::vector buffer; - if (header.size != 0) // non-zero size means the state is compressed - { - Core::DisplayMessage("Decompressing State...", 500); + if (header.size != 0) // non-zero size means the state is compressed + { + Core::DisplayMessage("Decompressing State...", 500); - buffer.resize(header.size); + buffer.resize(header.size); - lzo_uint i = 0; - while (true) - { - lzo_uint32 cur_len = 0; // number of bytes to read - lzo_uint new_len = 0; // number of bytes to write + lzo_uint i = 0; + while (true) + { + lzo_uint32 cur_len = 0; // number of bytes to read + lzo_uint new_len = 0; // number of bytes to write - if (!f.ReadArray(&cur_len, 1)) - break; + if (!f.ReadArray(&cur_len, 1)) + break; - f.ReadBytes(out, cur_len); - const int res = lzo1x_decompress(out, cur_len, &buffer[i], &new_len, nullptr); - if (res != LZO_E_OK) - { - // This doesn't seem to happen anymore. - PanicAlertT("Internal LZO Error - decompression failed (%d) (%li, %li) \n" - "Try loading the state again", res, i, new_len); - return; - } + f.ReadBytes(out, cur_len); + const int res = lzo1x_decompress(out, cur_len, &buffer[i], &new_len, nullptr); + if (res != LZO_E_OK) + { + // This doesn't seem to happen anymore. + PanicAlertT("Internal LZO Error - decompression failed (%d) (%li, %li) \n" + "Try loading the state again", + res, i, new_len); + return; + } - i += new_len; - } - } - else // uncompressed - { - const size_t size = (size_t)(f.GetSize() - sizeof(StateHeader)); - buffer.resize(size); + i += new_len; + } + } + else // uncompressed + { + const size_t size = (size_t)(f.GetSize() - sizeof(StateHeader)); + buffer.resize(size); - if (!f.ReadBytes(&buffer[0], size)) - { - PanicAlert("wtf? reading bytes: %zu", size); - return; - } - } + if (!f.ReadBytes(&buffer[0], size)) + { + PanicAlert("wtf? reading bytes: %zu", size); + return; + } + } - // all good - ret_data.swap(buffer); + // all good + ret_data.swap(buffer); } void LoadAs(const std::string& filename) { - if (!Core::IsRunning()) - { - return; - } - else if (NetPlay::IsNetPlayRunning()) - { - OSD::AddMessage("Loading savestates is disabled in Netplay to prevent desyncs"); - return; - } + if (!Core::IsRunning()) + { + return; + } + else if (NetPlay::IsNetPlayRunning()) + { + OSD::AddMessage("Loading savestates is disabled in Netplay to prevent desyncs"); + return; + } - // Stop the core while we load the state - bool wasUnpaused = Core::PauseAndLock(true); + // Stop the core while we load the state + bool wasUnpaused = Core::PauseAndLock(true); - g_loadDepth++; + g_loadDepth++; - // Save temp buffer for undo load state - if (!Movie::IsJustStartingRecordingInputFromSaveState()) - { - std::lock_guard lk(g_cs_undo_load_buffer); - SaveToBuffer(g_undo_load_buffer); - if (Movie::IsMovieActive()) - Movie::SaveRecording(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm"); - else if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) +"undo.dtm")) - File::Delete(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm"); - } + // Save temp buffer for undo load state + if (!Movie::IsJustStartingRecordingInputFromSaveState()) + { + std::lock_guard lk(g_cs_undo_load_buffer); + SaveToBuffer(g_undo_load_buffer); + if (Movie::IsMovieActive()) + Movie::SaveRecording(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm"); + else if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm")) + File::Delete(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm"); + } - bool loaded = false; - bool loadedSuccessfully = false; - std::string version_created_by; + bool loaded = false; + bool loadedSuccessfully = false; + std::string version_created_by; - // brackets here are so buffer gets freed ASAP - { - std::vector buffer; - LoadFileStateData(filename, buffer); + // brackets here are so buffer gets freed ASAP + { + std::vector buffer; + LoadFileStateData(filename, buffer); - if (!buffer.empty()) - { - u8 *ptr = &buffer[0]; - PointerWrap p(&ptr, PointerWrap::MODE_READ); - version_created_by = DoState(p); - loaded = true; - loadedSuccessfully = (p.GetMode() == PointerWrap::MODE_READ); - } - } + if (!buffer.empty()) + { + u8* ptr = &buffer[0]; + PointerWrap p(&ptr, PointerWrap::MODE_READ); + version_created_by = DoState(p); + loaded = true; + loadedSuccessfully = (p.GetMode() == PointerWrap::MODE_READ); + } + } - if (loaded) - { - if (loadedSuccessfully) - { - Core::DisplayMessage(StringFromFormat("Loaded state from %s", filename.c_str()), 2000); - if (File::Exists(filename + ".dtm")) - Movie::LoadInput(filename + ".dtm"); - else if (!Movie::IsJustStartingRecordingInputFromSaveState() && !Movie::IsJustStartingPlayingInputFromSaveState()) - Movie::EndPlayInput(false); - } - else - { - // failed to load - Core::DisplayMessage("Unable to load: Can't load state from other versions!", 4000); - if (!version_created_by.empty()) - Core::DisplayMessage("The savestate was created using " + version_created_by, 4000); + if (loaded) + { + if (loadedSuccessfully) + { + Core::DisplayMessage(StringFromFormat("Loaded state from %s", filename.c_str()), 2000); + if (File::Exists(filename + ".dtm")) + Movie::LoadInput(filename + ".dtm"); + else if (!Movie::IsJustStartingRecordingInputFromSaveState() && + !Movie::IsJustStartingPlayingInputFromSaveState()) + Movie::EndPlayInput(false); + } + else + { + // failed to load + Core::DisplayMessage("Unable to load: Can't load state from other versions!", 4000); + if (!version_created_by.empty()) + Core::DisplayMessage("The savestate was created using " + version_created_by, 4000); - // since we could be in an inconsistent state now (and might crash or whatever), undo. - if (g_loadDepth < 2) - UndoLoadState(); - } - } + // since we could be in an inconsistent state now (and might crash or whatever), undo. + if (g_loadDepth < 2) + UndoLoadState(); + } + } - if (g_onAfterLoadCb) - g_onAfterLoadCb(); + if (g_onAfterLoadCb) + g_onAfterLoadCb(); - g_loadDepth--; + g_loadDepth--; - // resume dat core - Core::PauseAndLock(false, wasUnpaused); + // resume dat core + Core::PauseAndLock(false, wasUnpaused); } void SetOnAfterLoadCallback(CallbackFunc callback) { - g_onAfterLoadCb = callback; + g_onAfterLoadCb = callback; } void VerifyAt(const std::string& filename) { - bool wasUnpaused = Core::PauseAndLock(true); + bool wasUnpaused = Core::PauseAndLock(true); - std::vector buffer; - LoadFileStateData(filename, buffer); + std::vector buffer; + LoadFileStateData(filename, buffer); - if (!buffer.empty()) - { - u8 *ptr = &buffer[0]; - PointerWrap p(&ptr, PointerWrap::MODE_VERIFY); - DoState(p); + if (!buffer.empty()) + { + u8* ptr = &buffer[0]; + PointerWrap p(&ptr, PointerWrap::MODE_VERIFY); + DoState(p); - if (p.GetMode() == PointerWrap::MODE_VERIFY) - Core::DisplayMessage(StringFromFormat("Verified state at %s", filename.c_str()), 2000); - else - Core::DisplayMessage("Unable to Verify : Can't verify state from other revisions !", 4000); - } + if (p.GetMode() == PointerWrap::MODE_VERIFY) + Core::DisplayMessage(StringFromFormat("Verified state at %s", filename.c_str()), 2000); + else + Core::DisplayMessage("Unable to Verify : Can't verify state from other revisions !", 4000); + } - Core::PauseAndLock(false, wasUnpaused); + Core::PauseAndLock(false, wasUnpaused); } - void Init() { - if (lzo_init() != LZO_E_OK) - PanicAlertT("Internal LZO Error - lzo_init() failed"); + if (lzo_init() != LZO_E_OK) + PanicAlertT("Internal LZO Error - lzo_init() failed"); } void Shutdown() { - Flush(); + Flush(); - // swapping with an empty vector, rather than clear()ing - // this gives a better guarantee to free the allocated memory right NOW (as opposed to, actually, never) - { - std::lock_guard lk(g_cs_current_buffer); - std::vector().swap(g_current_buffer); - } + // swapping with an empty vector, rather than clear()ing + // this gives a better guarantee to free the allocated memory right NOW (as opposed to, actually, + // never) + { + std::lock_guard lk(g_cs_current_buffer); + std::vector().swap(g_current_buffer); + } - { - std::lock_guard lk(g_cs_undo_load_buffer); - std::vector().swap(g_undo_load_buffer); - } + { + std::lock_guard lk(g_cs_undo_load_buffer); + std::vector().swap(g_undo_load_buffer); + } } static std::string MakeStateFilename(int number) { - return StringFromFormat("%s%s.s%02i", File::GetUserPath(D_STATESAVES_IDX).c_str(), - SConfig::GetInstance().GetUniqueID().c_str(), number); + return StringFromFormat("%s%s.s%02i", File::GetUserPath(D_STATESAVES_IDX).c_str(), + SConfig::GetInstance().GetUniqueID().c_str(), number); } void Save(int slot, bool wait) { - SaveAs(MakeStateFilename(slot), wait); + SaveAs(MakeStateFilename(slot), wait); } void Load(int slot) { - LoadAs(MakeStateFilename(slot)); + LoadAs(MakeStateFilename(slot)); } void Verify(int slot) { - VerifyAt(MakeStateFilename(slot)); + VerifyAt(MakeStateFilename(slot)); } void LoadLastSaved(int i) { - std::map savedStates = GetSavedStates(); + std::map savedStates = GetSavedStates(); - if (i > (int)savedStates.size()) - Core::DisplayMessage("State doesn't exist", 2000); - else - { - std::map::iterator it = savedStates.begin(); - std::advance(it, i-1); - Load(it->second); - } + if (i > (int)savedStates.size()) + Core::DisplayMessage("State doesn't exist", 2000); + else + { + std::map::iterator it = savedStates.begin(); + std::advance(it, i - 1); + Load(it->second); + } } // must wait for state to be written because it must know if all slots are taken void SaveFirstSaved() { - std::map savedStates = GetSavedStates(); + std::map savedStates = GetSavedStates(); - // save to an empty slot - if (savedStates.size() < NUM_STATES) - Save(GetEmptySlot(savedStates), true); - // overwrite the oldest state - else - { - std::map::iterator it = savedStates.begin(); - std::advance(it, savedStates.size()-1); - Save(it->second, true); - } + // save to an empty slot + if (savedStates.size() < NUM_STATES) + Save(GetEmptySlot(savedStates), true); + // overwrite the oldest state + else + { + std::map::iterator it = savedStates.begin(); + std::advance(it, savedStates.size() - 1); + Save(it->second, true); + } } void Flush() { - // If already saving state, wait for it to finish - if (g_save_thread.joinable()) - g_save_thread.join(); + // If already saving state, wait for it to finish + if (g_save_thread.joinable()) + g_save_thread.join(); } // Load the last state before loading the state void UndoLoadState() { - std::lock_guard lk(g_cs_undo_load_buffer); - if (!g_undo_load_buffer.empty()) - { - if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm") || (!Movie::IsMovieActive())) - { - LoadFromBuffer(g_undo_load_buffer); - if (Movie::IsMovieActive()) - Movie::LoadInput(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm"); - } - else - { - PanicAlertT("No undo.dtm found, aborting undo load state to prevent movie desyncs"); - } - } - else - { - PanicAlertT("There is nothing to undo!"); - } + std::lock_guard lk(g_cs_undo_load_buffer); + if (!g_undo_load_buffer.empty()) + { + if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm") || (!Movie::IsMovieActive())) + { + LoadFromBuffer(g_undo_load_buffer); + if (Movie::IsMovieActive()) + Movie::LoadInput(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm"); + } + else + { + PanicAlertT("No undo.dtm found, aborting undo load state to prevent movie desyncs"); + } + } + else + { + PanicAlertT("There is nothing to undo!"); + } } // Load the state that the last save state overwritten on void UndoSaveState() { - LoadAs(File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav"); + LoadAs(File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav"); } -} // namespace State +} // namespace State diff --git a/Source/Core/Core/State.h b/Source/Core/Core/State.h index 57a2f0c647..779f7f014e 100644 --- a/Source/Core/Core/State.h +++ b/Source/Core/Core/State.h @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // Emulator state saving support. #pragma once @@ -14,15 +13,14 @@ namespace State { - // number of states static const u32 NUM_STATES = 10; struct StateHeader { - char gameID[6]; - u32 size; - double time; + char gameID[6]; + u32 size; + double time; }; void Init(); @@ -46,9 +44,9 @@ void Save(int slot, bool wait = false); void Load(int slot); void Verify(int slot); -void SaveAs(const std::string &filename, bool wait = false); -void LoadAs(const std::string &filename); -void VerifyAt(const std::string &filename); +void SaveAs(const std::string& filename, bool wait = false); +void LoadAs(const std::string& filename); +void VerifyAt(const std::string& filename); void SaveToBuffer(std::vector& buffer); void LoadFromBuffer(std::vector& buffer); @@ -63,7 +61,6 @@ void UndoLoadState(); void Flush(); // for calling back into UI code without introducing a dependency on it in core -typedef void(*CallbackFunc)(void); +typedef void (*CallbackFunc)(void); void SetOnAfterLoadCallback(CallbackFunc callback); - } diff --git a/Source/Core/Core/ec_wii.cpp b/Source/Core/Core/ec_wii.cpp index a36caf96ae..c814863cc4 100644 --- a/Source/Core/Core/ec_wii.cpp +++ b/Source/Core/Core/ec_wii.cpp @@ -12,8 +12,8 @@ #include -#include "Common/FileUtil.h" #include "Common/Crypto/ec.h" +#include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Core/ec_wii.h" @@ -21,20 +21,19 @@ static u32 default_NG_id = 0x0403AC68; static u32 default_NG_key_id = 0x6AAB8C59; static u8 default_NG_priv[] = { - 0x00, 0xAB, 0xEE, 0xC1, 0xDD, 0xB4, 0xA6, 0x16, 0x6B, 0x70, 0xFD, 0x7E, 0x56, 0x67, 0x70, - 0x57, 0x55, 0x27, 0x38, 0xA3, 0x26, 0xC5, 0x46, 0x16, 0xF7, 0x62, 0xC9, 0xED, 0x73, 0xF2, + 0x00, 0xAB, 0xEE, 0xC1, 0xDD, 0xB4, 0xA6, 0x16, 0x6B, 0x70, 0xFD, 0x7E, 0x56, 0x67, 0x70, + 0x57, 0x55, 0x27, 0x38, 0xA3, 0x26, 0xC5, 0x46, 0x16, 0xF7, 0x62, 0xC9, 0xED, 0x73, 0xF2, }; static u8 default_NG_sig[] = { - // R - 0x00, 0xD8, 0x81, 0x63, 0xB2, 0x00, 0x6B, 0x0B, 0x54, 0x82, 0x88, 0x63, 0x81, 0x1C, 0x00, - 0x71, 0x12, 0xED, 0xB7, 0xFD, 0x21, 0xAB, 0x0E, 0x50, 0x0E, 0x1F, 0xBF, 0x78, 0xAD, 0x37, - // S - 0x00, 0x71, 0x8D, 0x82, 0x41, 0xEE, 0x45, 0x11, 0xC7, 0x3B, 0xAC, 0x08, 0xB6, 0x83, 0xDC, - 0x05, 0xB8, 0xA8, 0x90, 0x1F, 0xA8, 0x2A, 0x0E, 0x4E, 0x76, 0xEF, 0x44, 0x72, 0x99, 0xF8, + // R + 0x00, 0xD8, 0x81, 0x63, 0xB2, 0x00, 0x6B, 0x0B, 0x54, 0x82, 0x88, 0x63, 0x81, 0x1C, 0x00, 0x71, + 0x12, 0xED, 0xB7, 0xFD, 0x21, 0xAB, 0x0E, 0x50, 0x0E, 0x1F, 0xBF, 0x78, 0xAD, 0x37, + // S + 0x00, 0x71, 0x8D, 0x82, 0x41, 0xEE, 0x45, 0x11, 0xC7, 0x3B, 0xAC, 0x08, 0xB6, 0x83, 0xDC, 0x05, + 0xB8, 0xA8, 0x90, 0x1F, 0xA8, 0x2A, 0x0E, 0x4E, 0x76, 0xEF, 0x44, 0x72, 0x99, 0xF8, }; - // get_ng_cert // ng_cert_out is a pointer to a 0x180 byte buffer that will contain the device-unique certificate @@ -46,108 +45,114 @@ static u8 default_NG_sig[] = { // will be used for all of them void get_ng_cert(u8* ng_cert_out, u32 NG_id, u32 NG_key_id, const u8* NG_priv, const u8* NG_sig) { - char name[64]; - if ((NG_id == 0) || (NG_key_id == 0) || (NG_priv == nullptr) || (NG_sig == nullptr)) - { - NG_id = default_NG_id; - NG_key_id = default_NG_key_id; - NG_priv = default_NG_priv; - NG_sig = default_NG_sig; - } + char name[64]; + if ((NG_id == 0) || (NG_key_id == 0) || (NG_priv == nullptr) || (NG_sig == nullptr)) + { + NG_id = default_NG_id; + NG_key_id = default_NG_key_id; + NG_priv = default_NG_priv; + NG_sig = default_NG_sig; + } - sprintf(name, "NG%08x", NG_id); - make_blanksig_ec_cert(ng_cert_out, "Root-CA00000001-MS00000002", name, NG_priv, NG_key_id); - memcpy(ng_cert_out + 4, NG_sig, 60); + sprintf(name, "NG%08x", NG_id); + make_blanksig_ec_cert(ng_cert_out, "Root-CA00000001-MS00000002", name, NG_priv, NG_key_id); + memcpy(ng_cert_out + 4, NG_sig, 60); } - // get_ap_sig_and_cert // sig_out is a pointer to a 0x3c byte buffer which will be filled with the data payload's signature -// ap_cert_out is a pointer to a 0x180 byte buffer which will be filled with the temporal AP certificate +// ap_cert_out is a pointer to a 0x180 byte buffer which will be filled with the temporal AP +// certificate // title_id is the title responsible for the signing // data is a pointer to the buffer of data to sign // data_size is the length of the buffer // NG_priv is the device-unique private key to use // NG_id is the device-unique id to use // if NG_priv is nullptr or NG_id is 0, it will use builtin defaults -void get_ap_sig_and_cert(u8 *sig_out, u8 *ap_cert_out, u64 title_id, u8 *data, u32 data_size, const u8 *NG_priv, u32 NG_id) +void get_ap_sig_and_cert(u8* sig_out, u8* ap_cert_out, u64 title_id, u8* data, u32 data_size, + const u8* NG_priv, u32 NG_id) { - u8 hash[20]; - u8 ap_priv[30]; - char signer[64]; - char name[64]; + u8 hash[20]; + u8 ap_priv[30]; + char signer[64]; + char name[64]; - if ((NG_id == 0) || (NG_priv == nullptr)) - { - NG_priv = default_NG_priv; - NG_id = default_NG_id; - } + if ((NG_id == 0) || (NG_priv == nullptr)) + { + NG_priv = default_NG_priv; + NG_id = default_NG_id; + } + memset(ap_priv, 0, 0x1e); + ap_priv[0x1d] = 1; + // setup random ap_priv here if desired + // get_rand_bytes(ap_priv, 0x1e); + // ap_priv[0] &= 1; - memset(ap_priv, 0, 0x1e); - ap_priv[0x1d] = 1; - // setup random ap_priv here if desired - // get_rand_bytes(ap_priv, 0x1e); - // ap_priv[0] &= 1; + memset(ap_cert_out + 4, 0, 60); - memset(ap_cert_out + 4, 0, 60); + sprintf(signer, "Root-CA00000001-MS00000002-NG%08x", NG_id); + sprintf(name, "AP%08x%08x", (u32)(title_id >> 32), (u32)(title_id & 0xffffffff)); + make_blanksig_ec_cert(ap_cert_out, signer, name, ap_priv, 0); - sprintf(signer, "Root-CA00000001-MS00000002-NG%08x", NG_id); - sprintf(name, "AP%08x%08x", (u32)(title_id >> 32), (u32)(title_id & 0xffffffff)); - make_blanksig_ec_cert(ap_cert_out, signer, name, ap_priv, 0); + mbedtls_sha1(ap_cert_out + 0x80, 0x100, hash); + generate_ecdsa(ap_cert_out + 4, ap_cert_out + 34, NG_priv, hash); - mbedtls_sha1(ap_cert_out + 0x80, 0x100, hash); - generate_ecdsa(ap_cert_out + 4, ap_cert_out + 34, NG_priv, hash); - - mbedtls_sha1(data, data_size, hash); - generate_ecdsa(sig_out, sig_out + 30, ap_priv, hash); + mbedtls_sha1(data, data_size, hash); + generate_ecdsa(sig_out, sig_out + 30, ap_priv, hash); } -void make_blanksig_ec_cert(u8 *cert_out, const char *signer, const char *name, const u8 *private_key, u32 key_id) +void make_blanksig_ec_cert(u8* cert_out, const char* signer, const char* name, + const u8* private_key, u32 key_id) { - memset(cert_out, 0, 0x180); - *(u32*)cert_out = Common::swap32(0x10002); + memset(cert_out, 0, 0x180); + *(u32*)cert_out = Common::swap32(0x10002); - strncpy((char*)cert_out + 0x80, signer, 0x40); - *(u32*)(cert_out + 0xc0) = Common::swap32(2); - strncpy((char*)cert_out + 0xc4, name, 0x40); - *(u32*)(cert_out + 0x104) = Common::swap32(key_id); - ec_priv_to_pub(private_key, cert_out + 0x108); + strncpy((char*)cert_out + 0x80, signer, 0x40); + *(u32*)(cert_out + 0xc0) = Common::swap32(2); + strncpy((char*)cert_out + 0xc4, name, 0x40); + *(u32*)(cert_out + 0x104) = Common::swap32(key_id); + ec_priv_to_pub(private_key, cert_out + 0x108); } EcWii::EcWii() { - bool init = true; - std::string keys_path = File::GetUserPath(D_WIIROOT_IDX) + "/keys.bin"; - if (File::Exists(keys_path)) - { - File::IOFile keys_f(keys_path, "rb"); - if (keys_f.IsOpen()) - { - if (keys_f.ReadBytes(&BootMiiKeysBin, sizeof(BootMiiKeysBin))) - { - init = false; + bool init = true; + std::string keys_path = File::GetUserPath(D_WIIROOT_IDX) + "/keys.bin"; + if (File::Exists(keys_path)) + { + File::IOFile keys_f(keys_path, "rb"); + if (keys_f.IsOpen()) + { + if (keys_f.ReadBytes(&BootMiiKeysBin, sizeof(BootMiiKeysBin))) + { + init = false; - INFO_LOG(WII_IPC_ES, "Successfully loaded keys.bin created by: %s", BootMiiKeysBin.creator); - } - else - { - ERROR_LOG(WII_IPC_ES, "Failed to read keys.bin, check it is the correct size of %08zX bytes.", sizeof(BootMiiKeysBin)); - } - } - else - { - ERROR_LOG(WII_IPC_ES, "Failed to open keys.bin, maybe a permissions error or it is in use?"); - } - } - else - { - ERROR_LOG(WII_IPC_ES, "%s could not be found. Using default values. We recommend you grab keys.bin from BootMii.", keys_path.c_str()); - } + INFO_LOG(WII_IPC_ES, "Successfully loaded keys.bin created by: %s", BootMiiKeysBin.creator); + } + else + { + ERROR_LOG(WII_IPC_ES, + "Failed to read keys.bin, check it is the correct size of %08zX bytes.", + sizeof(BootMiiKeysBin)); + } + } + else + { + ERROR_LOG(WII_IPC_ES, "Failed to open keys.bin, maybe a permissions error or it is in use?"); + } + } + else + { + ERROR_LOG( + WII_IPC_ES, + "%s could not be found. Using default values. We recommend you grab keys.bin from BootMii.", + keys_path.c_str()); + } - if (init) - InitDefaults(); + if (init) + InitDefaults(); } EcWii::~EcWii() @@ -156,17 +161,17 @@ EcWii::~EcWii() void EcWii::InitDefaults() { - memset(&BootMiiKeysBin, 0, sizeof(BootMiiKeysBin)); + memset(&BootMiiKeysBin, 0, sizeof(BootMiiKeysBin)); - BootMiiKeysBin.ng_id = Common::swap32(default_NG_id); - BootMiiKeysBin.ng_key_id = Common::swap32(default_NG_key_id); + BootMiiKeysBin.ng_id = Common::swap32(default_NG_id); + BootMiiKeysBin.ng_key_id = Common::swap32(default_NG_key_id); - memcpy(BootMiiKeysBin.ng_priv, default_NG_priv, sizeof(BootMiiKeysBin.ng_priv)); - memcpy(BootMiiKeysBin.ng_sig, default_NG_sig, sizeof(BootMiiKeysBin.ng_sig)); + memcpy(BootMiiKeysBin.ng_priv, default_NG_priv, sizeof(BootMiiKeysBin.ng_priv)); + memcpy(BootMiiKeysBin.ng_sig, default_NG_sig, sizeof(BootMiiKeysBin.ng_sig)); } EcWii& EcWii::GetInstance() { - static EcWii m_Instance; - return(m_Instance); + static EcWii m_Instance; + return (m_Instance); } diff --git a/Source/Core/Core/ec_wii.h b/Source/Core/Core/ec_wii.h index 03d563cc36..da3348541c 100644 --- a/Source/Core/Core/ec_wii.h +++ b/Source/Core/Core/ec_wii.h @@ -28,86 +28,85 @@ #include "Common/CommonTypes.h" void get_ng_cert(u8* ng_cert_out, u32 NG_id, u32 NG_key_id, const u8* NG_priv, const u8* NG_sig); -void get_ap_sig_and_cert(u8 *sig_out, u8 *ap_cert_out, u64 title_id, u8 *data, u32 data_size, const u8 *NG_priv, u32 NG_id); - -void make_blanksig_ec_cert(u8 *cert_out, const char *signer, const char *name, const u8 *private_key, u32 key_id); +void get_ap_sig_and_cert(u8* sig_out, u8* ap_cert_out, u64 title_id, u8* data, u32 data_size, + const u8* NG_priv, u32 NG_id); +void make_blanksig_ec_cert(u8* cert_out, const char* signer, const char* name, + const u8* private_key, u32 key_id); class EcWii { public: - EcWii(); - ~EcWii(); - static EcWii& GetInstance(); - u32 getNgId() {return Common::swap32(BootMiiKeysBin.ng_id);} - u32 getNgKeyId() {return Common::swap32(BootMiiKeysBin.ng_key_id);} - const u8* getNgPriv() {return BootMiiKeysBin.ng_priv;} - const u8* getNgSig() {return BootMiiKeysBin.ng_sig;} + EcWii(); + ~EcWii(); + static EcWii& GetInstance(); + u32 getNgId() { return Common::swap32(BootMiiKeysBin.ng_id); } + u32 getNgKeyId() { return Common::swap32(BootMiiKeysBin.ng_key_id); } + const u8* getNgPriv() { return BootMiiKeysBin.ng_priv; } + const u8* getNgSig() { return BootMiiKeysBin.ng_sig; } private: - void InitDefaults(); + void InitDefaults(); - #pragma pack(push,1) - typedef struct - { - u8 boot2version; - u8 unknown1; - u8 unknown2; - u8 pad; - u32 update_tag; - u16 checksum; - } +#pragma pack(push, 1) + typedef struct + { + u8 boot2version; + u8 unknown1; + u8 unknown2; + u8 pad; + u32 update_tag; + u16 checksum; + } #ifndef _WIN32 - __attribute__((packed)) + __attribute__((packed)) #endif - eep_ctr_t; + eep_ctr_t; - struct - { - u8 creator [0x100]; // 0x000 - u8 boot1_hash [ 0x14]; // 0x100 - u8 common_key [ 0x10]; // 0x114 - u32 ng_id; // 0x124 - union - { - struct - { - u8 ng_priv [ 0x1e]; // 0x128 - u8 pad1 [ 0x12]; - }; + struct + { + u8 creator[0x100]; // 0x000 + u8 boot1_hash[0x14]; // 0x100 + u8 common_key[0x10]; // 0x114 + u32 ng_id; // 0x124 + union { + struct + { + u8 ng_priv[0x1e]; // 0x128 + u8 pad1[0x12]; + }; - struct - { - u8 pad2 [ 0x1c]; - u8 nand_hmac [ 0x14]; //0x144 - }; - }; - u8 nand_key [ 0x10]; //0x158 - u8 rng_key [ 0x10]; //0x168 - u32 unk1; //0x178 - u32 unk2; //0x17C - u8 eeprom_pad [ 0x80]; //0x180 + struct + { + u8 pad2[0x1c]; + u8 nand_hmac[0x14]; // 0x144 + }; + }; + u8 nand_key[0x10]; // 0x158 + u8 rng_key[0x10]; // 0x168 + u32 unk1; // 0x178 + u32 unk2; // 0x17C + u8 eeprom_pad[0x80]; // 0x180 - u32 ms_id; //0x200 - u32 ca_id; //0x204 - u32 ng_key_id; //0x208 - u8 ng_sig [ 0x3c]; //0x20c - eep_ctr_t counters [ 0x02]; //0x248 - u8 fill [ 0x18]; //0x25c - u8 korean_key [ 0x10]; //0x274 - u8 pad3 [ 0x74]; //0x284 - u16 prng_seed [ 0x02]; //0x2F8 - u8 pad4 [ 0x04]; //0x2FC + u32 ms_id; // 0x200 + u32 ca_id; // 0x204 + u32 ng_key_id; // 0x208 + u8 ng_sig[0x3c]; // 0x20c + eep_ctr_t counters[0x02]; // 0x248 + u8 fill[0x18]; // 0x25c + u8 korean_key[0x10]; // 0x274 + u8 pad3[0x74]; // 0x284 + u16 prng_seed[0x02]; // 0x2F8 + u8 pad4[0x04]; // 0x2FC - u8 crack_pad [0x100]; //0x300 + u8 crack_pad[0x100]; // 0x300 - } + } - #ifndef _WIN32 - __attribute__((packed)) - #endif +#ifndef _WIN32 + __attribute__((packed)) +#endif - BootMiiKeysBin; - - #pragma pack(pop) + BootMiiKeysBin; +#pragma pack(pop) }; diff --git a/Source/Core/DiscIO/Blob.cpp b/Source/Core/DiscIO/Blob.cpp index 0b726c3ffb..32c559b6eb 100644 --- a/Source/Core/DiscIO/Blob.cpp +++ b/Source/Core/DiscIO/Blob.cpp @@ -21,22 +21,21 @@ namespace DiscIO { - void SectorReader::SetSectorSize(int blocksize) { - m_block_size = std::max(blocksize, 0); - for (auto& cache_entry : m_cache) - { - cache_entry.Reset(); - cache_entry.data.resize(m_chunk_blocks * m_block_size); - } + m_block_size = std::max(blocksize, 0); + for (auto& cache_entry : m_cache) + { + cache_entry.Reset(); + cache_entry.data.resize(m_chunk_blocks * m_block_size); + } } void SectorReader::SetChunkSize(int block_cnt) { - m_chunk_blocks = std::max(block_cnt, 1); - // Clear cache and resize the data arrays - SetSectorSize(m_block_size); + m_chunk_blocks = std::max(block_cnt, 1); + // Clear cache and resize the data arrays + SetSectorSize(m_block_size); } SectorReader::~SectorReader() @@ -45,154 +44,149 @@ SectorReader::~SectorReader() const SectorReader::Cache* SectorReader::FindCacheLine(u64 block_num) { - auto itr = std::find_if(m_cache.begin(), m_cache.end(), [&](const Cache& entry) - { - return entry.Contains(block_num); - }); - if (itr == m_cache.end()) - return nullptr; + auto itr = std::find_if(m_cache.begin(), m_cache.end(), + [&](const Cache& entry) { return entry.Contains(block_num); }); + if (itr == m_cache.end()) + return nullptr; - itr->MarkUsed(); - return &*itr; + itr->MarkUsed(); + return &*itr; } SectorReader::Cache* SectorReader::GetEmptyCacheLine() { - Cache* oldest = &m_cache[0]; - // Find the Least Recently Used cache line to replace. - for (auto& cache_entry : m_cache) - { - if (cache_entry.IsLessRecentlyUsedThan(*oldest)) - oldest = &cache_entry; - cache_entry.ShiftLRU(); - } - oldest->Reset(); - return oldest; + Cache* oldest = &m_cache[0]; + // Find the Least Recently Used cache line to replace. + for (auto& cache_entry : m_cache) + { + if (cache_entry.IsLessRecentlyUsedThan(*oldest)) + oldest = &cache_entry; + cache_entry.ShiftLRU(); + } + oldest->Reset(); + return oldest; } const SectorReader::Cache* SectorReader::GetCacheLine(u64 block_num) { - if (auto entry = FindCacheLine(block_num)) - return entry; + if (auto entry = FindCacheLine(block_num)) + return entry; - // Cache miss. Fault in the missing entry. - Cache* cache = GetEmptyCacheLine(); - // We only read aligned chunks, this avoids duplicate overlapping entries. - u64 chunk_idx = block_num / m_chunk_blocks; - u32 blocks_read = ReadChunk(cache->data.data(), chunk_idx); - if (!blocks_read) - return nullptr; - cache->Fill(chunk_idx * m_chunk_blocks, blocks_read); + // Cache miss. Fault in the missing entry. + Cache* cache = GetEmptyCacheLine(); + // We only read aligned chunks, this avoids duplicate overlapping entries. + u64 chunk_idx = block_num / m_chunk_blocks; + u32 blocks_read = ReadChunk(cache->data.data(), chunk_idx); + if (!blocks_read) + return nullptr; + cache->Fill(chunk_idx * m_chunk_blocks, blocks_read); - // Secondary check for out-of-bounds read. - // If we got less than m_chunk_blocks, we may still have missed. - // We do this after the cache fill since the cache line itself is - // fine, the problem is being asked to read past the end of the disk. - return cache->Contains(block_num) ? cache : nullptr; + // Secondary check for out-of-bounds read. + // If we got less than m_chunk_blocks, we may still have missed. + // We do this after the cache fill since the cache line itself is + // fine, the problem is being asked to read past the end of the disk. + return cache->Contains(block_num) ? cache : nullptr; } bool SectorReader::Read(u64 offset, u64 size, u8* out_ptr) { - u64 remain = size; - u64 block = 0; - u32 position_in_block = static_cast(offset % m_block_size); + u64 remain = size; + u64 block = 0; + u32 position_in_block = static_cast(offset % m_block_size); - while (remain > 0) - { - block = offset / m_block_size; + while (remain > 0) + { + block = offset / m_block_size; - const Cache* cache = GetCacheLine(block); - if (!cache) - return false; + const Cache* cache = GetCacheLine(block); + if (!cache) + return false; - // Cache entries are aligned chunks, we may not want to read from the start - u32 read_offset = static_cast(block - cache->block_idx) * m_block_size + position_in_block; - u32 can_read = m_block_size * cache->num_blocks - read_offset; - u32 was_read = static_cast(std::min(can_read, remain)); + // Cache entries are aligned chunks, we may not want to read from the start + u32 read_offset = static_cast(block - cache->block_idx) * m_block_size + position_in_block; + u32 can_read = m_block_size * cache->num_blocks - read_offset; + u32 was_read = static_cast(std::min(can_read, remain)); - std::copy(cache->data.begin() + read_offset, - cache->data.begin() + read_offset + was_read, - out_ptr); + std::copy(cache->data.begin() + read_offset, cache->data.begin() + read_offset + was_read, + out_ptr); - offset += was_read; - out_ptr += was_read; - remain -= was_read; - position_in_block = 0; - } - return true; + offset += was_read; + out_ptr += was_read; + remain -= was_read; + position_in_block = 0; + } + return true; } // Crap default implementation if not overridden. bool SectorReader::ReadMultipleAlignedBlocks(u64 block_num, u64 cnt_blocks, u8* out_ptr) { - for (u64 i = 0; i < cnt_blocks; ++i) - { - if (!GetBlock(block_num + i, out_ptr)) - return false; - out_ptr += m_block_size; - } - return true; + for (u64 i = 0; i < cnt_blocks; ++i) + { + if (!GetBlock(block_num + i, out_ptr)) + return false; + out_ptr += m_block_size; + } + return true; } u32 SectorReader::ReadChunk(u8* buffer, u64 chunk_num) { - u64 block_num = chunk_num * m_chunk_blocks; - u32 cnt_blocks = m_chunk_blocks; + u64 block_num = chunk_num * m_chunk_blocks; + u32 cnt_blocks = m_chunk_blocks; - // If we are reading the end of a disk, there may not be enough blocks to - // read a whole chunk. We need to clamp down in that case. - u64 end_block = (GetDataSize() + m_block_size - 1) / m_block_size; - if (end_block) - cnt_blocks = static_cast(std::min(m_chunk_blocks, end_block - block_num)); + // If we are reading the end of a disk, there may not be enough blocks to + // read a whole chunk. We need to clamp down in that case. + u64 end_block = (GetDataSize() + m_block_size - 1) / m_block_size; + if (end_block) + cnt_blocks = static_cast(std::min(m_chunk_blocks, end_block - block_num)); - if (ReadMultipleAlignedBlocks(block_num, cnt_blocks, buffer)) - { - if (cnt_blocks < m_chunk_blocks) - { - std::fill(buffer + cnt_blocks * m_block_size, - buffer + m_chunk_blocks * m_block_size, - 0u); - } - return cnt_blocks; - } + if (ReadMultipleAlignedBlocks(block_num, cnt_blocks, buffer)) + { + if (cnt_blocks < m_chunk_blocks) + { + std::fill(buffer + cnt_blocks * m_block_size, buffer + m_chunk_blocks * m_block_size, 0u); + } + return cnt_blocks; + } - // end_block may be zero on real disks if we fail to get the media size. - // We have to fallback to probing the disk instead. - if (!end_block) - { - for (u32 i = 0; i < cnt_blocks; ++i) - { - if (!GetBlock(block_num + i, buffer)) - { - std::fill(buffer, buffer + (cnt_blocks - i) * m_block_size, 0u); - return i; - } - buffer += m_block_size; - } - return cnt_blocks; - } - return 0; + // end_block may be zero on real disks if we fail to get the media size. + // We have to fallback to probing the disk instead. + if (!end_block) + { + for (u32 i = 0; i < cnt_blocks; ++i) + { + if (!GetBlock(block_num + i, buffer)) + { + std::fill(buffer, buffer + (cnt_blocks - i) * m_block_size, 0u); + return i; + } + buffer += m_block_size; + } + return cnt_blocks; + } + return 0; } std::unique_ptr CreateBlobReader(const std::string& filename) { - if (cdio_is_cdrom(filename)) - return DriveReader::Create(filename); + if (cdio_is_cdrom(filename)) + return DriveReader::Create(filename); - if (!File::Exists(filename)) - return nullptr; + if (!File::Exists(filename)) + return nullptr; - if (IsWbfsBlob(filename)) - return WbfsFileReader::Create(filename); + if (IsWbfsBlob(filename)) + return WbfsFileReader::Create(filename); - if (IsGCZBlob(filename)) - return CompressedBlobReader::Create(filename); + if (IsGCZBlob(filename)) + return CompressedBlobReader::Create(filename); - if (IsCISOBlob(filename)) - return CISOFileReader::Create(filename); + if (IsCISOBlob(filename)) + return CISOFileReader::Create(filename); - // Still here? Assume plain file - since we know it exists due to the File::Exists check above. - return PlainFileReader::Create(filename); + // Still here? Assume plain file - since we know it exists due to the File::Exists check above. + return PlainFileReader::Create(filename); } } // namespace diff --git a/Source/Core/DiscIO/Blob.h b/Source/Core/DiscIO/Blob.h index bc79effba7..5e16c5d4b8 100644 --- a/Source/Core/DiscIO/Blob.h +++ b/Source/Core/DiscIO/Blob.h @@ -22,159 +22,135 @@ namespace DiscIO { - // Increment CACHE_REVISION if the enum below is modified (ISOFile.cpp & GameFile.cpp) enum class BlobType { - PLAIN, - DRIVE, - DIRECTORY, - GCZ, - CISO, - WBFS + PLAIN, + DRIVE, + DIRECTORY, + GCZ, + CISO, + WBFS }; class IBlobReader { public: - virtual ~IBlobReader() {} - - virtual BlobType GetBlobType() const = 0; - virtual u64 GetRawSize() const = 0; - virtual u64 GetDataSize() const = 0; - // NOT thread-safe - can't call this from multiple threads. - virtual bool Read(u64 offset, u64 size, u8* out_ptr) = 0; + virtual ~IBlobReader() {} + virtual BlobType GetBlobType() const = 0; + virtual u64 GetRawSize() const = 0; + virtual u64 GetDataSize() const = 0; + // NOT thread-safe - can't call this from multiple threads. + virtual bool Read(u64 offset, u64 size, u8* out_ptr) = 0; protected: - IBlobReader() {} + IBlobReader() {} }; - // Provides caching and byte-operation-to-block-operations facilities. // Used for compressed blob and direct drive reading. // NOTE: GetDataSize() is expected to be evenly divisible by the sector size. class SectorReader : public IBlobReader { public: - virtual ~SectorReader() = 0; + virtual ~SectorReader() = 0; - bool Read(u64 offset, u64 size, u8* out_ptr) override; + bool Read(u64 offset, u64 size, u8* out_ptr) override; protected: - void SetSectorSize(int blocksize); - int GetSectorSize() const - { - return m_block_size; - } + void SetSectorSize(int blocksize); + int GetSectorSize() const { return m_block_size; } + // Set the chunk size -> the number of blocks to read at a time. + // Default value is 1 but that is too low for physical devices + // like CDROMs. Setting this to a higher value helps reduce seeking + // and IO overhead by batching reads. Do not set it too high either + // as large reads are slow and will take too long to resolve. + void SetChunkSize(int blocks); + int GetChunkSize() const { return m_chunk_blocks; } + // Read a single block/sector. + virtual bool GetBlock(u64 block_num, u8* out) = 0; - // Set the chunk size -> the number of blocks to read at a time. - // Default value is 1 but that is too low for physical devices - // like CDROMs. Setting this to a higher value helps reduce seeking - // and IO overhead by batching reads. Do not set it too high either - // as large reads are slow and will take too long to resolve. - void SetChunkSize(int blocks); - int GetChunkSize() const - { - return m_chunk_blocks; - } - - // Read a single block/sector. - virtual bool GetBlock(u64 block_num, u8* out) = 0; - - // Read multiple contiguous blocks. - // Default implementation just calls GetBlock in a loop, it should be - // overridden in derived classes where possible. - virtual bool ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8* out_ptr); + // Read multiple contiguous blocks. + // Default implementation just calls GetBlock in a loop, it should be + // overridden in derived classes where possible. + virtual bool ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8* out_ptr); private: - struct Cache - { - std::vector data; - u64 block_idx = 0; - u32 num_blocks = 0; + struct Cache + { + std::vector data; + u64 block_idx = 0; + u32 num_blocks = 0; - // [Pseudo-] Least Recently Used Shift Register - // When an empty cache line is needed, the line with the lowest value - // is taken and reset; the LRU register is then shifted down 1 place - // on all lines (low bit discarded). When a line is used, the high bit - // is set marking it as most recently used. - u32 lru_sreg = 0; + // [Pseudo-] Least Recently Used Shift Register + // When an empty cache line is needed, the line with the lowest value + // is taken and reset; the LRU register is then shifted down 1 place + // on all lines (low bit discarded). When a line is used, the high bit + // is set marking it as most recently used. + u32 lru_sreg = 0; - void Reset() - { - block_idx = 0; - num_blocks = 0; - lru_sreg = 0; - } - void Fill(u64 block, u32 count) - { - block_idx = block; - num_blocks = count; - // NOTE: Setting only the high bit means the newest line will - // be selected for eviction if every line in the cache was - // touched. This gives MRU behavior which is probably - // desirable in that case. - MarkUsed(); - } - bool Contains(u64 block) const - { - return block >= block_idx && block - block_idx < num_blocks; - } - void MarkUsed() - { - lru_sreg |= 0x80000000; - } - void ShiftLRU() - { - lru_sreg >>= 1; - } - bool IsLessRecentlyUsedThan(const Cache& other) const - { - return lru_sreg < other.lru_sreg; - } - }; + void Reset() + { + block_idx = 0; + num_blocks = 0; + lru_sreg = 0; + } + void Fill(u64 block, u32 count) + { + block_idx = block; + num_blocks = count; + // NOTE: Setting only the high bit means the newest line will + // be selected for eviction if every line in the cache was + // touched. This gives MRU behavior which is probably + // desirable in that case. + MarkUsed(); + } + bool Contains(u64 block) const { return block >= block_idx && block - block_idx < num_blocks; } + void MarkUsed() { lru_sreg |= 0x80000000; } + void ShiftLRU() { lru_sreg >>= 1; } + bool IsLessRecentlyUsedThan(const Cache& other) const { return lru_sreg < other.lru_sreg; } + }; - // Gets the cache line that contains the given block, or nullptr. - // NOTE: The cache record only lasts until it expires (next GetEmptyCacheLine) - const Cache* FindCacheLine(u64 block_num); + // Gets the cache line that contains the given block, or nullptr. + // NOTE: The cache record only lasts until it expires (next GetEmptyCacheLine) + const Cache* FindCacheLine(u64 block_num); - // Finds the least recently used cache line, resets and returns it. - Cache* GetEmptyCacheLine(); + // Finds the least recently used cache line, resets and returns it. + Cache* GetEmptyCacheLine(); - // Combines FindCacheLine with GetEmptyCacheLine and ReadChunk. - // Always returns a valid cache line (loading the data if needed). - // May return nullptr only if the cache missed and the read failed. - const Cache* GetCacheLine(u64 block_num); + // Combines FindCacheLine with GetEmptyCacheLine and ReadChunk. + // Always returns a valid cache line (loading the data if needed). + // May return nullptr only if the cache missed and the read failed. + const Cache* GetCacheLine(u64 block_num); - // Read all bytes from a chunk of blocks into a buffer. - // Returns the number of blocks read (may be less than m_chunk_blocks - // if chunk_num is the last chunk on the disk and the disk size is not - // evenly divisible into chunks). Returns zero if it fails. - u32 ReadChunk(u8* buffer, u64 chunk_num); + // Read all bytes from a chunk of blocks into a buffer. + // Returns the number of blocks read (may be less than m_chunk_blocks + // if chunk_num is the last chunk on the disk and the disk size is not + // evenly divisible into chunks). Returns zero if it fails. + u32 ReadChunk(u8* buffer, u64 chunk_num); - static constexpr int CACHE_LINES = 32; - u32 m_block_size = 0; // Bytes in a sector/block - u32 m_chunk_blocks = 1; // Number of sectors/blocks in a chunk - std::array m_cache; + static constexpr int CACHE_LINES = 32; + u32 m_block_size = 0; // Bytes in a sector/block + u32 m_chunk_blocks = 1; // Number of sectors/blocks in a chunk + std::array m_cache; }; class CBlobBigEndianReader { public: - CBlobBigEndianReader(IBlobReader& reader) : m_reader(reader) {} - - template - bool ReadSwapped(u64 offset, T* buffer) const - { - T temp; - if (!m_reader.Read(offset, sizeof(T), reinterpret_cast(&temp))) - return false; - *buffer = Common::FromBigEndian(temp); - return true; - } + CBlobBigEndianReader(IBlobReader& reader) : m_reader(reader) {} + template + bool ReadSwapped(u64 offset, T* buffer) const + { + T temp; + if (!m_reader.Read(offset, sizeof(T), reinterpret_cast(&temp))) + return false; + *buffer = Common::FromBigEndian(temp); + return true; + } private: - IBlobReader& m_reader; + IBlobReader& m_reader; }; // Factory function - examines the path to choose the right type of IBlobReader, and returns one. @@ -182,9 +158,10 @@ std::unique_ptr CreateBlobReader(const std::string& filename); typedef bool (*CompressCB)(const std::string& text, float percent, void* arg); -bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u32 sub_type = 0, int sector_size = 16384, - CompressCB callback = nullptr, void *arg = nullptr); +bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u32 sub_type = 0, + int sector_size = 16384, CompressCB callback = nullptr, + void* arg = nullptr); bool DecompressBlobToFile(const std::string& infile, const std::string& outfile, - CompressCB callback = nullptr, void *arg = nullptr); + CompressCB callback = nullptr, void* arg = nullptr); } // namespace diff --git a/Source/Core/DiscIO/CISOBlob.cpp b/Source/Core/DiscIO/CISOBlob.cpp index 9c7f440cf9..37e427793b 100644 --- a/Source/Core/DiscIO/CISOBlob.cpp +++ b/Source/Core/DiscIO/CISOBlob.cpp @@ -12,84 +12,82 @@ namespace DiscIO { - static const char CISO_MAGIC[] = "CISO"; -CISOFileReader::CISOFileReader(std::FILE* file) - : m_file(file) +CISOFileReader::CISOFileReader(std::FILE* file) : m_file(file) { - m_size = m_file.GetSize(); + m_size = m_file.GetSize(); - CISOHeader header; - m_file.ReadArray(&header, 1); + CISOHeader header; + m_file.ReadArray(&header, 1); - m_block_size = header.block_size; + m_block_size = header.block_size; - MapType count = 0; - for (u32 idx = 0; idx < CISO_MAP_SIZE; ++idx) - m_ciso_map[idx] = (1 == header.map[idx]) ? count++ : UNUSED_BLOCK_ID; + MapType count = 0; + for (u32 idx = 0; idx < CISO_MAP_SIZE; ++idx) + m_ciso_map[idx] = (1 == header.map[idx]) ? count++ : UNUSED_BLOCK_ID; } std::unique_ptr CISOFileReader::Create(const std::string& filename) { - if (IsCISOBlob(filename)) - { - File::IOFile f(filename, "rb"); - return std::unique_ptr(new CISOFileReader(f.ReleaseHandle())); - } + if (IsCISOBlob(filename)) + { + File::IOFile f(filename, "rb"); + return std::unique_ptr(new CISOFileReader(f.ReleaseHandle())); + } - return nullptr; + return nullptr; } u64 CISOFileReader::GetDataSize() const { - return CISO_MAP_SIZE * m_block_size; + return CISO_MAP_SIZE * m_block_size; } u64 CISOFileReader::GetRawSize() const { - return m_size; + return m_size; } bool CISOFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr) { - while (nbytes != 0) - { - u64 const block = offset / m_block_size; - u64 const data_offset = offset % m_block_size; - u64 const bytes_to_read = std::min(m_block_size - data_offset, nbytes); + while (nbytes != 0) + { + u64 const block = offset / m_block_size; + u64 const data_offset = offset % m_block_size; + u64 const bytes_to_read = std::min(m_block_size - data_offset, nbytes); - if (block < CISO_MAP_SIZE && UNUSED_BLOCK_ID != m_ciso_map[block]) - { - // calculate the base address - u64 const file_off = CISO_HEADER_SIZE + m_ciso_map[block] * (u64)m_block_size + data_offset; + if (block < CISO_MAP_SIZE && UNUSED_BLOCK_ID != m_ciso_map[block]) + { + // calculate the base address + u64 const file_off = CISO_HEADER_SIZE + m_ciso_map[block] * (u64)m_block_size + data_offset; - if (!(m_file.Seek(file_off, SEEK_SET) && m_file.ReadArray(out_ptr, bytes_to_read))) - { - m_file.Clear(); - return false; - } - } - else - { - std::fill_n(out_ptr, bytes_to_read, 0); - } + if (!(m_file.Seek(file_off, SEEK_SET) && m_file.ReadArray(out_ptr, bytes_to_read))) + { + m_file.Clear(); + return false; + } + } + else + { + std::fill_n(out_ptr, bytes_to_read, 0); + } - out_ptr += bytes_to_read; - offset += bytes_to_read; - nbytes -= bytes_to_read; - } + out_ptr += bytes_to_read; + offset += bytes_to_read; + nbytes -= bytes_to_read; + } - return true; + return true; } bool IsCISOBlob(const std::string& filename) { - File::IOFile f(filename, "rb"); + File::IOFile f(filename, "rb"); - CISOHeader header; - return (f.ReadArray(&header, 1) && - std::equal(header.magic, header.magic + sizeof(header.magic), CISO_MAGIC)); + CISOHeader header; + return (f.ReadArray(&header, 1) && + std::equal(header.magic, header.magic + sizeof(header.magic), CISO_MAGIC)); } } // namespace diff --git a/Source/Core/DiscIO/CISOBlob.h b/Source/Core/DiscIO/CISOBlob.h index d3ff1be056..9eed0d992a 100644 --- a/Source/Core/DiscIO/CISOBlob.h +++ b/Source/Core/DiscIO/CISOBlob.h @@ -14,7 +14,6 @@ namespace DiscIO { - bool IsCISOBlob(const std::string& filename); static const u32 CISO_HEADER_SIZE = 0x8000; @@ -22,40 +21,39 @@ static const u32 CISO_MAP_SIZE = CISO_HEADER_SIZE - sizeof(u32) - sizeof(char) * struct CISOHeader { - // "CISO" - char magic[4]; + // "CISO" + char magic[4]; - // little endian - u32 block_size; + // little endian + u32 block_size; - // 0=unused, 1=used, others=invalid - u8 map[CISO_MAP_SIZE]; + // 0=unused, 1=used, others=invalid + u8 map[CISO_MAP_SIZE]; }; class CISOFileReader : public IBlobReader { public: - static std::unique_ptr Create(const std::string& filename); + static std::unique_ptr Create(const std::string& filename); - BlobType GetBlobType() const override { return BlobType::CISO; } + BlobType GetBlobType() const override { return BlobType::CISO; } + // The CISO format does not save the original file size. + // This function returns an upper bound. + u64 GetDataSize() const override; - // The CISO format does not save the original file size. - // This function returns an upper bound. - u64 GetDataSize() const override; - - u64 GetRawSize() const override; - bool Read(u64 offset, u64 nbytes, u8* out_ptr) override; + u64 GetRawSize() const override; + bool Read(u64 offset, u64 nbytes, u8* out_ptr) override; private: - CISOFileReader(std::FILE* file); + CISOFileReader(std::FILE* file); - typedef u16 MapType; - static const MapType UNUSED_BLOCK_ID = -1; + typedef u16 MapType; + static const MapType UNUSED_BLOCK_ID = -1; - File::IOFile m_file; - u64 m_size; - u32 m_block_size; - MapType m_ciso_map[CISO_MAP_SIZE]; + File::IOFile m_file; + u64 m_size; + u32 m_block_size; + MapType m_ciso_map[CISO_MAP_SIZE]; }; } // namespace diff --git a/Source/Core/DiscIO/CompressedBlob.cpp b/Source/Core/DiscIO/CompressedBlob.cpp index 3e99890c81..68edf369e6 100644 --- a/Source/Core/DiscIO/CompressedBlob.cpp +++ b/Source/Core/DiscIO/CompressedBlob.cpp @@ -19,47 +19,46 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/Hash.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "DiscIO/Blob.h" #include "DiscIO/CompressedBlob.h" #include "DiscIO/DiscScrubber.h" - namespace DiscIO { - CompressedBlobReader::CompressedBlobReader(const std::string& filename) : m_file_name(filename) { - m_file.Open(filename, "rb"); - m_file_size = File::GetSize(filename); - m_file.ReadArray(&m_header, 1); + m_file.Open(filename, "rb"); + m_file_size = File::GetSize(filename); + m_file.ReadArray(&m_header, 1); - SetSectorSize(m_header.block_size); + SetSectorSize(m_header.block_size); - // cache block pointers and hashes - m_block_pointers.resize(m_header.num_blocks); - m_file.ReadArray(m_block_pointers.data(), m_header.num_blocks); - m_hashes.resize(m_header.num_blocks); - m_file.ReadArray(m_hashes.data(), m_header.num_blocks); + // cache block pointers and hashes + m_block_pointers.resize(m_header.num_blocks); + m_file.ReadArray(m_block_pointers.data(), m_header.num_blocks); + m_hashes.resize(m_header.num_blocks); + m_file.ReadArray(m_hashes.data(), m_header.num_blocks); - m_data_offset = (sizeof(CompressedBlobHeader)) - + (sizeof(u64)) * m_header.num_blocks // skip block pointers - + (sizeof(u32)) * m_header.num_blocks; // skip hashes + m_data_offset = (sizeof(CompressedBlobHeader)) + + (sizeof(u64)) * m_header.num_blocks // skip block pointers + + (sizeof(u32)) * m_header.num_blocks; // skip hashes - // A compressed block is never ever longer than a decompressed block, so just header.block_size should be fine. - // I still add some safety margin. - const u32 zlib_buffer_size = m_header.block_size + 64; - m_zlib_buffer.resize(zlib_buffer_size); + // A compressed block is never ever longer than a decompressed block, so just header.block_size + // should be fine. + // I still add some safety margin. + const u32 zlib_buffer_size = m_header.block_size + 64; + m_zlib_buffer.resize(zlib_buffer_size); } std::unique_ptr CompressedBlobReader::Create(const std::string& filename) { - if (IsGCZBlob(filename)) - return std::unique_ptr(new CompressedBlobReader(filename)); + if (IsGCZBlob(filename)) + return std::unique_ptr(new CompressedBlobReader(filename)); - return nullptr; + return nullptr; } CompressedBlobReader::~CompressedBlobReader() @@ -69,343 +68,343 @@ CompressedBlobReader::~CompressedBlobReader() // IMPORTANT: Calling this function invalidates all earlier pointers gotten from this function. u64 CompressedBlobReader::GetBlockCompressedSize(u64 block_num) const { - u64 start = m_block_pointers[block_num]; - if (block_num < m_header.num_blocks - 1) - return m_block_pointers[block_num + 1] - start; - else if (block_num == m_header.num_blocks - 1) - return m_header.compressed_data_size - start; - else - PanicAlert("GetBlockCompressedSize - illegal block number %i", (int)block_num); - return 0; + u64 start = m_block_pointers[block_num]; + if (block_num < m_header.num_blocks - 1) + return m_block_pointers[block_num + 1] - start; + else if (block_num == m_header.num_blocks - 1) + return m_header.compressed_data_size - start; + else + PanicAlert("GetBlockCompressedSize - illegal block number %i", (int)block_num); + return 0; } -bool CompressedBlobReader::GetBlock(u64 block_num, u8 *out_ptr) +bool CompressedBlobReader::GetBlock(u64 block_num, u8* out_ptr) { - bool uncompressed = false; - u32 comp_block_size = (u32)GetBlockCompressedSize(block_num); - u64 offset = m_block_pointers[block_num] + m_data_offset; + bool uncompressed = false; + u32 comp_block_size = (u32)GetBlockCompressedSize(block_num); + u64 offset = m_block_pointers[block_num] + m_data_offset; - if (offset & (1ULL << 63)) - { - if (comp_block_size != m_header.block_size) - PanicAlert("Uncompressed block with wrong size"); - uncompressed = true; - offset &= ~(1ULL << 63); - } + if (offset & (1ULL << 63)) + { + if (comp_block_size != m_header.block_size) + PanicAlert("Uncompressed block with wrong size"); + uncompressed = true; + offset &= ~(1ULL << 63); + } - // clear unused part of zlib buffer. maybe this can be deleted when it works fully. - memset(&m_zlib_buffer[comp_block_size], 0, m_zlib_buffer.size() - comp_block_size); + // clear unused part of zlib buffer. maybe this can be deleted when it works fully. + memset(&m_zlib_buffer[comp_block_size], 0, m_zlib_buffer.size() - comp_block_size); - m_file.Seek(offset, SEEK_SET); - if (!m_file.ReadBytes(m_zlib_buffer.data(), comp_block_size)) - { - PanicAlertT("The disc image \"%s\" is truncated, some of the data is missing.", - m_file_name.c_str()); - m_file.Clear(); - return false; - } + m_file.Seek(offset, SEEK_SET); + if (!m_file.ReadBytes(m_zlib_buffer.data(), comp_block_size)) + { + PanicAlertT("The disc image \"%s\" is truncated, some of the data is missing.", + m_file_name.c_str()); + m_file.Clear(); + return false; + } - // First, check hash. - u32 block_hash = HashAdler32(m_zlib_buffer.data(), comp_block_size); - if (block_hash != m_hashes[block_num]) - PanicAlertT("The disc image \"%s\" is corrupt.\n" - "Hash of block %" PRIu64 " is %08x instead of %08x.", - m_file_name.c_str(), - block_num, block_hash, m_hashes[block_num]); + // First, check hash. + u32 block_hash = HashAdler32(m_zlib_buffer.data(), comp_block_size); + if (block_hash != m_hashes[block_num]) + PanicAlertT("The disc image \"%s\" is corrupt.\n" + "Hash of block %" PRIu64 " is %08x instead of %08x.", + m_file_name.c_str(), block_num, block_hash, m_hashes[block_num]); - if (uncompressed) - { - std::copy(m_zlib_buffer.begin(), m_zlib_buffer.begin() + comp_block_size, out_ptr); - } - else - { - z_stream z = {}; - z.next_in = m_zlib_buffer.data(); - z.avail_in = comp_block_size; - if (z.avail_in > m_header.block_size) - { - PanicAlert("We have a problem"); - } - z.next_out = out_ptr; - z.avail_out = m_header.block_size; - inflateInit(&z); - int status = inflate(&z, Z_FULL_FLUSH); - u32 uncomp_size = m_header.block_size - z.avail_out; - if (status != Z_STREAM_END) - { - // this seem to fire wrongly from time to time - // to be sure, don't use compressed isos :P - PanicAlert("Failure reading block %" PRIu64 " - out of data and not at end.", block_num); - } - inflateEnd(&z); - if (uncomp_size != m_header.block_size) - { - PanicAlert("Wrong block size"); - return false; - } - } - return true; + if (uncompressed) + { + std::copy(m_zlib_buffer.begin(), m_zlib_buffer.begin() + comp_block_size, out_ptr); + } + else + { + z_stream z = {}; + z.next_in = m_zlib_buffer.data(); + z.avail_in = comp_block_size; + if (z.avail_in > m_header.block_size) + { + PanicAlert("We have a problem"); + } + z.next_out = out_ptr; + z.avail_out = m_header.block_size; + inflateInit(&z); + int status = inflate(&z, Z_FULL_FLUSH); + u32 uncomp_size = m_header.block_size - z.avail_out; + if (status != Z_STREAM_END) + { + // this seem to fire wrongly from time to time + // to be sure, don't use compressed isos :P + PanicAlert("Failure reading block %" PRIu64 " - out of data and not at end.", block_num); + } + inflateEnd(&z); + if (uncomp_size != m_header.block_size) + { + PanicAlert("Wrong block size"); + return false; + } + } + return true; } bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u32 sub_type, - int block_size, CompressCB callback, void* arg) + int block_size, CompressCB callback, void* arg) { - bool scrubbing = false; + bool scrubbing = false; - if (IsGCZBlob(infile)) - { - PanicAlertT("\"%s\" is already compressed! Cannot compress it further.", infile.c_str()); - return false; - } + if (IsGCZBlob(infile)) + { + PanicAlertT("\"%s\" is already compressed! Cannot compress it further.", infile.c_str()); + return false; + } - File::IOFile inf(infile, "rb"); - if (!inf) - { - PanicAlertT("Failed to open the input file \"%s\".", infile.c_str()); - return false; - } + File::IOFile inf(infile, "rb"); + if (!inf) + { + PanicAlertT("Failed to open the input file \"%s\".", infile.c_str()); + return false; + } - File::IOFile f(outfile, "wb"); - if (!f) - { - PanicAlertT("Failed to open the output file \"%s\".\n" - "Check that you have permissions to write the target folder and that the media can be written.", - outfile.c_str()); - return false; - } + File::IOFile f(outfile, "wb"); + if (!f) + { + PanicAlertT("Failed to open the output file \"%s\".\n" + "Check that you have permissions to write the target folder and that the media can " + "be written.", + outfile.c_str()); + return false; + } - if (sub_type == 1) - { - if (!DiscScrubber::SetupScrub(infile, block_size)) - { - PanicAlertT("\"%s\" failed to be scrubbed. Probably the image is corrupt.", infile.c_str()); - return false; - } + if (sub_type == 1) + { + if (!DiscScrubber::SetupScrub(infile, block_size)) + { + PanicAlertT("\"%s\" failed to be scrubbed. Probably the image is corrupt.", infile.c_str()); + return false; + } - scrubbing = true; - } + scrubbing = true; + } - z_stream z = {}; - if (deflateInit(&z, 9) != Z_OK) - { - DiscScrubber::Cleanup(); - return false; - } + z_stream z = {}; + if (deflateInit(&z, 9) != Z_OK) + { + DiscScrubber::Cleanup(); + return false; + } - callback(GetStringT("Files opened, ready to compress."), 0, arg); + callback(GetStringT("Files opened, ready to compress."), 0, arg); - CompressedBlobHeader header; - header.magic_cookie = kBlobCookie; - header.sub_type = sub_type; - header.block_size = block_size; - header.data_size = File::GetSize(infile); + CompressedBlobHeader header; + header.magic_cookie = kBlobCookie; + header.sub_type = sub_type; + header.block_size = block_size; + header.data_size = File::GetSize(infile); - // round upwards! - header.num_blocks = (u32)((header.data_size + (block_size - 1)) / block_size); + // round upwards! + header.num_blocks = (u32)((header.data_size + (block_size - 1)) / block_size); - std::vector offsets(header.num_blocks); - std::vector hashes(header.num_blocks); - std::vector out_buf(block_size); - std::vector in_buf(block_size); + std::vector offsets(header.num_blocks); + std::vector hashes(header.num_blocks); + std::vector out_buf(block_size); + std::vector in_buf(block_size); - // seek past the header (we will write it at the end) - f.Seek(sizeof(CompressedBlobHeader), SEEK_CUR); - // seek past the offset and hash tables (we will write them at the end) - f.Seek((sizeof(u64) + sizeof(u32)) * header.num_blocks, SEEK_CUR); + // seek past the header (we will write it at the end) + f.Seek(sizeof(CompressedBlobHeader), SEEK_CUR); + // seek past the offset and hash tables (we will write them at the end) + f.Seek((sizeof(u64) + sizeof(u32)) * header.num_blocks, SEEK_CUR); - // Now we are ready to write compressed data! - u64 position = 0; - int num_compressed = 0; - int num_stored = 0; - int progress_monitor = std::max(1, header.num_blocks / 1000); - bool success = true; + // Now we are ready to write compressed data! + u64 position = 0; + int num_compressed = 0; + int num_stored = 0; + int progress_monitor = std::max(1, header.num_blocks / 1000); + bool success = true; - for (u32 i = 0; i < header.num_blocks; i++) - { - if (i % progress_monitor == 0) - { - const u64 inpos = inf.Tell(); - int ratio = 0; - if (inpos != 0) - ratio = (int)(100 * position / inpos); + for (u32 i = 0; i < header.num_blocks; i++) + { + if (i % progress_monitor == 0) + { + const u64 inpos = inf.Tell(); + int ratio = 0; + if (inpos != 0) + ratio = (int)(100 * position / inpos); - std::string temp = StringFromFormat(GetStringT("%i of %i blocks. Compression ratio %i%%").c_str(), - i, header.num_blocks, ratio); - bool was_cancelled = !callback(temp, (float)i / (float)header.num_blocks, arg); - if (was_cancelled) - { - success = false; - break; - } - } + std::string temp = + StringFromFormat(GetStringT("%i of %i blocks. Compression ratio %i%%").c_str(), i, + header.num_blocks, ratio); + bool was_cancelled = !callback(temp, (float)i / (float)header.num_blocks, arg); + if (was_cancelled) + { + success = false; + break; + } + } - offsets[i] = position; + offsets[i] = position; - size_t read_bytes; - if (scrubbing) - read_bytes = DiscScrubber::GetNextBlock(inf, in_buf.data()); - else - inf.ReadArray(in_buf.data(), header.block_size, &read_bytes); - if (read_bytes < header.block_size) - std::fill(in_buf.begin() + read_bytes, in_buf.begin() + header.block_size, 0); + size_t read_bytes; + if (scrubbing) + read_bytes = DiscScrubber::GetNextBlock(inf, in_buf.data()); + else + inf.ReadArray(in_buf.data(), header.block_size, &read_bytes); + if (read_bytes < header.block_size) + std::fill(in_buf.begin() + read_bytes, in_buf.begin() + header.block_size, 0); - int retval = deflateReset(&z); - z.next_in = in_buf.data(); - z.avail_in = header.block_size; - z.next_out = out_buf.data(); - z.avail_out = block_size; + int retval = deflateReset(&z); + z.next_in = in_buf.data(); + z.avail_in = header.block_size; + z.next_out = out_buf.data(); + z.avail_out = block_size; - if (retval != Z_OK) - { - ERROR_LOG(DISCIO, "Deflate failed"); - success = false; - break; - } + if (retval != Z_OK) + { + ERROR_LOG(DISCIO, "Deflate failed"); + success = false; + break; + } - int status = deflate(&z, Z_FINISH); - int comp_size = block_size - z.avail_out; + int status = deflate(&z, Z_FINISH); + int comp_size = block_size - z.avail_out; - u8* write_buf; - int write_size; - if ((status != Z_STREAM_END) || (z.avail_out < 10)) - { - //PanicAlert("%i %i Store %i", i*block_size, position, comp_size); - // let's store uncompressed - write_buf = in_buf.data(); - offsets[i] |= 0x8000000000000000ULL; - write_size = block_size; - num_stored++; - } - else - { - // let's store compressed - //PanicAlert("Comp %i to %i", block_size, comp_size); - write_buf = out_buf.data(); - write_size = comp_size; - num_compressed++; - } + u8* write_buf; + int write_size; + if ((status != Z_STREAM_END) || (z.avail_out < 10)) + { + // PanicAlert("%i %i Store %i", i*block_size, position, comp_size); + // let's store uncompressed + write_buf = in_buf.data(); + offsets[i] |= 0x8000000000000000ULL; + write_size = block_size; + num_stored++; + } + else + { + // let's store compressed + // PanicAlert("Comp %i to %i", block_size, comp_size); + write_buf = out_buf.data(); + write_size = comp_size; + num_compressed++; + } - if (!f.WriteBytes(write_buf, write_size)) - { - PanicAlertT( - "Failed to write the output file \"%s\".\n" - "Check that you have enough space available on the target drive.", - outfile.c_str()); - success = false; - break; - } + if (!f.WriteBytes(write_buf, write_size)) + { + PanicAlertT("Failed to write the output file \"%s\".\n" + "Check that you have enough space available on the target drive.", + outfile.c_str()); + success = false; + break; + } - position += write_size; + position += write_size; - hashes[i] = HashAdler32(write_buf, write_size); - } + hashes[i] = HashAdler32(write_buf, write_size); + } - header.compressed_data_size = position; + header.compressed_data_size = position; - if (!success) - { - // Remove the incomplete output file. - f.Close(); - File::Delete(outfile); - } - else - { - // Okay, go back and fill in headers - f.Seek(0, SEEK_SET); - f.WriteArray(&header, 1); - f.WriteArray(offsets.data(), header.num_blocks); - f.WriteArray(hashes.data(), header.num_blocks); - } + if (!success) + { + // Remove the incomplete output file. + f.Close(); + File::Delete(outfile); + } + else + { + // Okay, go back and fill in headers + f.Seek(0, SEEK_SET); + f.WriteArray(&header, 1); + f.WriteArray(offsets.data(), header.num_blocks); + f.WriteArray(hashes.data(), header.num_blocks); + } - // Cleanup - deflateEnd(&z); - DiscScrubber::Cleanup(); + // Cleanup + deflateEnd(&z); + DiscScrubber::Cleanup(); - if (success) - { - callback(GetStringT("Done compressing disc image."), 1.0f, arg); - } - return success; + if (success) + { + callback(GetStringT("Done compressing disc image."), 1.0f, arg); + } + return success; } -bool DecompressBlobToFile(const std::string& infile, const std::string& outfile, CompressCB callback, void* arg) +bool DecompressBlobToFile(const std::string& infile, const std::string& outfile, + CompressCB callback, void* arg) { - if (!IsGCZBlob(infile)) - { - PanicAlertT("File not compressed"); - return false; - } + if (!IsGCZBlob(infile)) + { + PanicAlertT("File not compressed"); + return false; + } - std::unique_ptr reader(CompressedBlobReader::Create(infile)); - if (!reader) - { - PanicAlertT("Failed to open the input file \"%s\".", infile.c_str()); - return false; - } + std::unique_ptr reader(CompressedBlobReader::Create(infile)); + if (!reader) + { + PanicAlertT("Failed to open the input file \"%s\".", infile.c_str()); + return false; + } - File::IOFile f(outfile, "wb"); - if (!f) - { - PanicAlertT( - "Failed to open the output file \"%s\".\n" - "Check that you have permissions to write the target folder and that the media can be written.", - outfile.c_str()); - return false; - } + File::IOFile f(outfile, "wb"); + if (!f) + { + PanicAlertT("Failed to open the output file \"%s\".\n" + "Check that you have permissions to write the target folder and that the media can " + "be written.", + outfile.c_str()); + return false; + } - const CompressedBlobHeader &header = reader->GetHeader(); - static const size_t BUFFER_BLOCKS = 32; - size_t buffer_size = header.block_size * BUFFER_BLOCKS; - size_t last_buffer_size = header.block_size * (header.num_blocks % BUFFER_BLOCKS); - std::vector buffer(buffer_size); - u32 num_buffers = (header.num_blocks + BUFFER_BLOCKS - 1) / BUFFER_BLOCKS; - int progress_monitor = std::max(1, num_buffers / 100); - bool success = true; + const CompressedBlobHeader& header = reader->GetHeader(); + static const size_t BUFFER_BLOCKS = 32; + size_t buffer_size = header.block_size * BUFFER_BLOCKS; + size_t last_buffer_size = header.block_size * (header.num_blocks % BUFFER_BLOCKS); + std::vector buffer(buffer_size); + u32 num_buffers = (header.num_blocks + BUFFER_BLOCKS - 1) / BUFFER_BLOCKS; + int progress_monitor = std::max(1, num_buffers / 100); + bool success = true; - for (u64 i = 0; i < num_buffers; i++) - { - if (i % progress_monitor == 0) - { - bool was_cancelled = !callback(GetStringT("Unpacking"), (float)i / (float)num_buffers, arg); - if (was_cancelled) - { - success = false; - break; - } - } - const size_t sz = i == num_buffers - 1 ? last_buffer_size : buffer_size; - reader->Read(i * buffer_size, sz, buffer.data()); - if (!f.WriteBytes(buffer.data(), sz)) - { - PanicAlertT( - "Failed to write the output file \"%s\".\n" - "Check that you have enough space available on the target drive.", - outfile.c_str()); - success = false; - break; - } - } + for (u64 i = 0; i < num_buffers; i++) + { + if (i % progress_monitor == 0) + { + bool was_cancelled = !callback(GetStringT("Unpacking"), (float)i / (float)num_buffers, arg); + if (was_cancelled) + { + success = false; + break; + } + } + const size_t sz = i == num_buffers - 1 ? last_buffer_size : buffer_size; + reader->Read(i * buffer_size, sz, buffer.data()); + if (!f.WriteBytes(buffer.data(), sz)) + { + PanicAlertT("Failed to write the output file \"%s\".\n" + "Check that you have enough space available on the target drive.", + outfile.c_str()); + success = false; + break; + } + } - if (!success) - { - // Remove the incomplete output file. - f.Close(); - File::Delete(outfile); - } - else - { - f.Resize(header.data_size); - } + if (!success) + { + // Remove the incomplete output file. + f.Close(); + File::Delete(outfile); + } + else + { + f.Resize(header.data_size); + } - return true; + return true; } bool IsGCZBlob(const std::string& filename) { - File::IOFile f(filename, "rb"); + File::IOFile f(filename, "rb"); - CompressedBlobHeader header; - return f.ReadArray(&header, 1) && (header.magic_cookie == kBlobCookie); + CompressedBlobHeader header; + return f.ReadArray(&header, 1) && (header.magic_cookie == kBlobCookie); } } // namespace diff --git a/Source/Core/DiscIO/CompressedBlob.h b/Source/Core/DiscIO/CompressedBlob.h index baca0e24c0..4c33cf85be 100644 --- a/Source/Core/DiscIO/CompressedBlob.h +++ b/Source/Core/DiscIO/CompressedBlob.h @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // WARNING Code not big-endian safe. // To create new compressed BLOBs, use CompressFileToBlob. @@ -24,7 +23,6 @@ namespace DiscIO { - bool IsGCZBlob(const std::string& filename); const u32 kBlobCookie = 0xB10BC001; @@ -35,38 +33,39 @@ const u32 kBlobCookie = 0xB10BC001; // compressed data // Blocks that won't compress to less than 97% of the original size are stored as-is. -struct CompressedBlobHeader // 32 bytes +struct CompressedBlobHeader // 32 bytes { - u32 magic_cookie; //0xB10BB10B - u32 sub_type; // GC image, whatever - u64 compressed_data_size; - u64 data_size; - u32 block_size; - u32 num_blocks; + u32 magic_cookie; // 0xB10BB10B + u32 sub_type; // GC image, whatever + u64 compressed_data_size; + u64 data_size; + u32 block_size; + u32 num_blocks; }; class CompressedBlobReader : public SectorReader { public: - static std::unique_ptr Create(const std::string& filename); - ~CompressedBlobReader(); - const CompressedBlobHeader &GetHeader() const { return m_header; } - BlobType GetBlobType() const override { return BlobType::GCZ; } - u64 GetDataSize() const override { return m_header.data_size; } - u64 GetRawSize() const override { return m_file_size; } - u64 GetBlockCompressedSize(u64 block_num) const; - bool GetBlock(u64 block_num, u8* out_ptr) override; -private: - CompressedBlobReader(const std::string& filename); + static std::unique_ptr Create(const std::string& filename); + ~CompressedBlobReader(); + const CompressedBlobHeader& GetHeader() const { return m_header; } + BlobType GetBlobType() const override { return BlobType::GCZ; } + u64 GetDataSize() const override { return m_header.data_size; } + u64 GetRawSize() const override { return m_file_size; } + u64 GetBlockCompressedSize(u64 block_num) const; + bool GetBlock(u64 block_num, u8* out_ptr) override; - CompressedBlobHeader m_header; - std::vector m_block_pointers; - std::vector m_hashes; - int m_data_offset; - File::IOFile m_file; - u64 m_file_size; - std::vector m_zlib_buffer; - std::string m_file_name; +private: + CompressedBlobReader(const std::string& filename); + + CompressedBlobHeader m_header; + std::vector m_block_pointers; + std::vector m_hashes; + int m_data_offset; + File::IOFile m_file; + u64 m_file_size; + std::vector m_zlib_buffer; + std::string m_file_name; }; } // namespace diff --git a/Source/Core/DiscIO/DiscScrubber.cpp b/Source/Core/DiscIO/DiscScrubber.cpp index b8aac8b091..685a8d7b87 100644 --- a/Source/Core/DiscIO/DiscScrubber.cpp +++ b/Source/Core/DiscIO/DiscScrubber.cpp @@ -20,10 +20,8 @@ namespace DiscIO { - namespace DiscScrubber { - #define CLUSTER_SIZE 0x8000 static u8* m_FreeTable = nullptr; @@ -38,40 +36,39 @@ static std::unique_ptr s_disc; struct SPartitionHeader { - u8* Ticket[0x2a4]; - u32 TMDSize; - u64 TMDOffset; - u32 CertChainSize; - u64 CertChainOffset; - // H3Size is always 0x18000 - u64 H3Offset; - u64 DataOffset; - u64 DataSize; - // TMD would be here - u64 DOLOffset; - u64 DOLSize; - u64 FSTOffset; - u64 FSTSize; - u32 ApploaderSize; - u32 ApploaderTrailerSize; + u8* Ticket[0x2a4]; + u32 TMDSize; + u64 TMDOffset; + u32 CertChainSize; + u64 CertChainOffset; + // H3Size is always 0x18000 + u64 H3Offset; + u64 DataOffset; + u64 DataSize; + // TMD would be here + u64 DOLOffset; + u64 DOLSize; + u64 FSTOffset; + u64 FSTSize; + u32 ApploaderSize; + u32 ApploaderTrailerSize; }; struct SPartition { - u32 GroupNumber; - u32 Number; - u64 Offset; - u32 Type; - SPartitionHeader Header; + u32 GroupNumber; + u32 Number; + u64 Offset; + u32 Type; + SPartitionHeader Header; }; struct SPartitionGroup { - u32 numPartitions; - u64 PartitionsOffset; - std::vector PartitionsVec; + u32 numPartitions; + u64 PartitionsOffset; + std::vector PartitionsVec; }; static SPartitionGroup PartitionGroup[4]; - void MarkAsUsed(u64 _Offset, u64 _Size); void MarkAsUsedE(u64 _PartitionDataOffset, u64 _Offset, u64 _Size); bool ReadFromVolume(u64 _Offset, u32& _Buffer, bool _Decrypt); @@ -79,257 +76,255 @@ bool ReadFromVolume(u64 _Offset, u64& _Buffer, bool _Decrypt); bool ParseDisc(); bool ParsePartitionData(SPartition& _rPartition); - bool SetupScrub(const std::string& filename, int block_size) { - bool success = true; - m_Filename = filename; - m_BlockSize = block_size; + bool success = true; + m_Filename = filename; + m_BlockSize = block_size; - if (CLUSTER_SIZE % m_BlockSize != 0) - { - ERROR_LOG(DISCIO, "Block size %i is not a factor of 0x8000, scrubbing not possible", m_BlockSize); - return false; - } + if (CLUSTER_SIZE % m_BlockSize != 0) + { + ERROR_LOG(DISCIO, "Block size %i is not a factor of 0x8000, scrubbing not possible", + m_BlockSize); + return false; + } - m_BlocksPerCluster = CLUSTER_SIZE / m_BlockSize; + m_BlocksPerCluster = CLUSTER_SIZE / m_BlockSize; - s_disc = CreateVolumeFromFilename(filename); - if (!s_disc) - return false; + s_disc = CreateVolumeFromFilename(filename); + if (!s_disc) + return false; - m_FileSize = s_disc->GetSize(); + m_FileSize = s_disc->GetSize(); - u32 numClusters = (u32)(m_FileSize / CLUSTER_SIZE); + u32 numClusters = (u32)(m_FileSize / CLUSTER_SIZE); - // Warn if not DVD5 or DVD9 size - if (numClusters != 0x23048 && numClusters != 0x46090) - WARN_LOG(DISCIO, "%s is not a standard sized Wii disc! (%x blocks)", filename.c_str(), numClusters); + // Warn if not DVD5 or DVD9 size + if (numClusters != 0x23048 && numClusters != 0x46090) + WARN_LOG(DISCIO, "%s is not a standard sized Wii disc! (%x blocks)", filename.c_str(), + numClusters); - // Table of free blocks - m_FreeTable = new u8[numClusters]; - std::fill(m_FreeTable, m_FreeTable + numClusters, 1); + // Table of free blocks + m_FreeTable = new u8[numClusters]; + std::fill(m_FreeTable, m_FreeTable + numClusters, 1); - // Fill out table of free blocks - success = ParseDisc(); + // Fill out table of free blocks + success = ParseDisc(); - // Done with it; need it closed for the next part - s_disc.reset(); - m_BlockCount = 0; + // Done with it; need it closed for the next part + s_disc.reset(); + m_BlockCount = 0; - // Let's not touch the file if we've failed up to here :p - if (!success) - Cleanup(); + // Let's not touch the file if we've failed up to here :p + if (!success) + Cleanup(); - m_isScrubbing = success; - return success; + m_isScrubbing = success; + return success; } size_t GetNextBlock(File::IOFile& in, u8* buffer) { - u64 CurrentOffset = m_BlockCount * m_BlockSize; - u64 i = CurrentOffset / CLUSTER_SIZE; + u64 CurrentOffset = m_BlockCount * m_BlockSize; + u64 i = CurrentOffset / CLUSTER_SIZE; - size_t ReadBytes = 0; - if (m_isScrubbing && m_FreeTable[i]) - { - DEBUG_LOG(DISCIO, "Freeing 0x%016" PRIx64, CurrentOffset); - std::fill(buffer, buffer + m_BlockSize, 0xFF); - in.Seek(m_BlockSize, SEEK_CUR); - ReadBytes = m_BlockSize; - } - else - { - DEBUG_LOG(DISCIO, "Used 0x%016" PRIx64, CurrentOffset); - in.ReadArray(buffer, m_BlockSize, &ReadBytes); - } + size_t ReadBytes = 0; + if (m_isScrubbing && m_FreeTable[i]) + { + DEBUG_LOG(DISCIO, "Freeing 0x%016" PRIx64, CurrentOffset); + std::fill(buffer, buffer + m_BlockSize, 0xFF); + in.Seek(m_BlockSize, SEEK_CUR); + ReadBytes = m_BlockSize; + } + else + { + DEBUG_LOG(DISCIO, "Used 0x%016" PRIx64, CurrentOffset); + in.ReadArray(buffer, m_BlockSize, &ReadBytes); + } - m_BlockCount++; - return ReadBytes; + m_BlockCount++; + return ReadBytes; } void Cleanup() { - if (m_FreeTable) delete[] m_FreeTable; - m_FreeTable = nullptr; - m_FileSize = 0; - m_BlockCount = 0; - m_BlockSize = 0; - m_BlocksPerCluster = 0; - m_isScrubbing = false; + if (m_FreeTable) + delete[] m_FreeTable; + m_FreeTable = nullptr; + m_FileSize = 0; + m_BlockCount = 0; + m_BlockSize = 0; + m_BlocksPerCluster = 0; + m_isScrubbing = false; } void MarkAsUsed(u64 _Offset, u64 _Size) { - u64 CurrentOffset = _Offset; - u64 EndOffset = CurrentOffset + _Size; + u64 CurrentOffset = _Offset; + u64 EndOffset = CurrentOffset + _Size; - DEBUG_LOG(DISCIO, "Marking 0x%016" PRIx64 " - 0x%016" PRIx64 " as used", _Offset, EndOffset); + DEBUG_LOG(DISCIO, "Marking 0x%016" PRIx64 " - 0x%016" PRIx64 " as used", _Offset, EndOffset); - while ((CurrentOffset < EndOffset) && (CurrentOffset < m_FileSize)) - { - m_FreeTable[CurrentOffset / CLUSTER_SIZE] = 0; - CurrentOffset += CLUSTER_SIZE; - } + while ((CurrentOffset < EndOffset) && (CurrentOffset < m_FileSize)) + { + m_FreeTable[CurrentOffset / CLUSTER_SIZE] = 0; + CurrentOffset += CLUSTER_SIZE; + } } // Compensate for 0x400(SHA-1) per 0x8000(cluster) void MarkAsUsedE(u64 _PartitionDataOffset, u64 _Offset, u64 _Size) { - u64 Offset; - u64 Size; + u64 Offset; + u64 Size; - Offset = _Offset / 0x7c00; - Offset = Offset * CLUSTER_SIZE; - Offset += _PartitionDataOffset; + Offset = _Offset / 0x7c00; + Offset = Offset * CLUSTER_SIZE; + Offset += _PartitionDataOffset; - Size = _Size / 0x7c00; - Size = (Size + 1) * CLUSTER_SIZE; + Size = _Size / 0x7c00; + Size = (Size + 1) * CLUSTER_SIZE; - // Add on the offset in the first block for the case where data straddles blocks - Size += _Offset % 0x7c00; + // Add on the offset in the first block for the case where data straddles blocks + Size += _Offset % 0x7c00; - MarkAsUsed(Offset, Size); + MarkAsUsed(Offset, Size); } // Helper functions for reading the BE volume bool ReadFromVolume(u64 _Offset, u32& _Buffer, bool _Decrypt) { - return s_disc->ReadSwapped(_Offset, &_Buffer, _Decrypt); + return s_disc->ReadSwapped(_Offset, &_Buffer, _Decrypt); } bool ReadFromVolume(u64 _Offset, u64& _Buffer, bool _Decrypt) { - u32 temp_buffer; - if (!s_disc->ReadSwapped(_Offset, &temp_buffer, _Decrypt)) - return false; - _Buffer = static_cast(temp_buffer) << 2; - return true; + u32 temp_buffer; + if (!s_disc->ReadSwapped(_Offset, &temp_buffer, _Decrypt)) + return false; + _Buffer = static_cast(temp_buffer) << 2; + return true; } bool ParseDisc() { - // Mark the header as used - it's mostly 0s anyways - MarkAsUsed(0, 0x50000); + // Mark the header as used - it's mostly 0s anyways + MarkAsUsed(0, 0x50000); - for (int x = 0; x < 4; x++) - { - if (!ReadFromVolume(0x40000 + (x * 8) + 0, PartitionGroup[x].numPartitions, false) || - !ReadFromVolume(0x40000 + (x * 8) + 4, PartitionGroup[x].PartitionsOffset, false)) - return false; + for (int x = 0; x < 4; x++) + { + if (!ReadFromVolume(0x40000 + (x * 8) + 0, PartitionGroup[x].numPartitions, false) || + !ReadFromVolume(0x40000 + (x * 8) + 4, PartitionGroup[x].PartitionsOffset, false)) + return false; - // Read all partitions - for (u32 i = 0; i < PartitionGroup[x].numPartitions; i++) - { - SPartition Partition; + // Read all partitions + for (u32 i = 0; i < PartitionGroup[x].numPartitions; i++) + { + SPartition Partition; - Partition.GroupNumber = x; - Partition.Number = i; + Partition.GroupNumber = x; + Partition.Number = i; - if (!ReadFromVolume(PartitionGroup[x].PartitionsOffset + (i * 8) + 0, Partition.Offset, false) || - !ReadFromVolume(PartitionGroup[x].PartitionsOffset + (i * 8) + 4, Partition.Type, false) || - !ReadFromVolume(Partition.Offset + 0x2a4, Partition.Header.TMDSize, false) || - !ReadFromVolume(Partition.Offset + 0x2a8, Partition.Header.TMDOffset, false) || - !ReadFromVolume(Partition.Offset + 0x2ac, Partition.Header.CertChainSize, false) || - !ReadFromVolume(Partition.Offset + 0x2b0, Partition.Header.CertChainOffset, false) || - !ReadFromVolume(Partition.Offset + 0x2b4, Partition.Header.H3Offset, false) || - !ReadFromVolume(Partition.Offset + 0x2b8, Partition.Header.DataOffset, false) || - !ReadFromVolume(Partition.Offset + 0x2bc, Partition.Header.DataSize, false)) - return false; + if (!ReadFromVolume(PartitionGroup[x].PartitionsOffset + (i * 8) + 0, Partition.Offset, + false) || + !ReadFromVolume(PartitionGroup[x].PartitionsOffset + (i * 8) + 4, Partition.Type, + false) || + !ReadFromVolume(Partition.Offset + 0x2a4, Partition.Header.TMDSize, false) || + !ReadFromVolume(Partition.Offset + 0x2a8, Partition.Header.TMDOffset, false) || + !ReadFromVolume(Partition.Offset + 0x2ac, Partition.Header.CertChainSize, false) || + !ReadFromVolume(Partition.Offset + 0x2b0, Partition.Header.CertChainOffset, false) || + !ReadFromVolume(Partition.Offset + 0x2b4, Partition.Header.H3Offset, false) || + !ReadFromVolume(Partition.Offset + 0x2b8, Partition.Header.DataOffset, false) || + !ReadFromVolume(Partition.Offset + 0x2bc, Partition.Header.DataSize, false)) + return false; - PartitionGroup[x].PartitionsVec.push_back(Partition); - } + PartitionGroup[x].PartitionsVec.push_back(Partition); + } - for (auto& rPartition : PartitionGroup[x].PartitionsVec) - { - const SPartitionHeader& rHeader = rPartition.Header; + for (auto& rPartition : PartitionGroup[x].PartitionsVec) + { + const SPartitionHeader& rHeader = rPartition.Header; - MarkAsUsed(rPartition.Offset, 0x2c0); + MarkAsUsed(rPartition.Offset, 0x2c0); - MarkAsUsed(rPartition.Offset + rHeader.TMDOffset, rHeader.TMDSize); - MarkAsUsed(rPartition.Offset + rHeader.CertChainOffset, rHeader.CertChainSize); - MarkAsUsed(rPartition.Offset + rHeader.H3Offset, 0x18000); - // This would mark the whole (encrypted) data area - // we need to parse FST and other crap to find what's free within it! - //MarkAsUsed(rPartition.Offset + rHeader.DataOffset, rHeader.DataSize); + MarkAsUsed(rPartition.Offset + rHeader.TMDOffset, rHeader.TMDSize); + MarkAsUsed(rPartition.Offset + rHeader.CertChainOffset, rHeader.CertChainSize); + MarkAsUsed(rPartition.Offset + rHeader.H3Offset, 0x18000); + // This would mark the whole (encrypted) data area + // we need to parse FST and other crap to find what's free within it! + // MarkAsUsed(rPartition.Offset + rHeader.DataOffset, rHeader.DataSize); - // Parse Data! This is where the big gain is - if (!ParsePartitionData(rPartition)) - return false; - } - } + // Parse Data! This is where the big gain is + if (!ParsePartitionData(rPartition)) + return false; + } + } - return true; + return true; } // Operations dealing with encrypted space are done here - the volume is swapped to allow this bool ParsePartitionData(SPartition& partition) { - bool parsed_ok = true; + bool parsed_ok = true; - // Switch out the main volume temporarily - std::unique_ptr old_volume; - s_disc.swap(old_volume); + // Switch out the main volume temporarily + std::unique_ptr old_volume; + s_disc.swap(old_volume); - // Ready some stuff - s_disc = CreateVolumeFromFilename(m_Filename, partition.GroupNumber, partition.Number); - if (s_disc == nullptr) - { - ERROR_LOG(DISCIO, "Failed to create volume from file %s", m_Filename.c_str()); - s_disc.swap(old_volume); - return false; - } + // Ready some stuff + s_disc = CreateVolumeFromFilename(m_Filename, partition.GroupNumber, partition.Number); + if (s_disc == nullptr) + { + ERROR_LOG(DISCIO, "Failed to create volume from file %s", m_Filename.c_str()); + s_disc.swap(old_volume); + return false; + } - std::unique_ptr filesystem(CreateFileSystem(s_disc.get())); - if (!filesystem) - { - ERROR_LOG(DISCIO, "Failed to create filesystem for group %d partition %u", partition.GroupNumber, partition.Number); - parsed_ok = false; - } - else - { - // Mark things as used which are not in the filesystem - // Header, Header Information, Apploader - parsed_ok = parsed_ok && ReadFromVolume(0x2440 + 0x14, partition.Header.ApploaderSize, true); - parsed_ok = parsed_ok && ReadFromVolume(0x2440 + 0x18, partition.Header.ApploaderTrailerSize, true); - MarkAsUsedE(partition.Offset - + partition.Header.DataOffset - , 0 - , 0x2440 - + partition.Header.ApploaderSize - + partition.Header.ApploaderTrailerSize); + std::unique_ptr filesystem(CreateFileSystem(s_disc.get())); + if (!filesystem) + { + ERROR_LOG(DISCIO, "Failed to create filesystem for group %d partition %u", + partition.GroupNumber, partition.Number); + parsed_ok = false; + } + else + { + // Mark things as used which are not in the filesystem + // Header, Header Information, Apploader + parsed_ok = parsed_ok && ReadFromVolume(0x2440 + 0x14, partition.Header.ApploaderSize, true); + parsed_ok = + parsed_ok && ReadFromVolume(0x2440 + 0x18, partition.Header.ApploaderTrailerSize, true); + MarkAsUsedE(partition.Offset + partition.Header.DataOffset, 0, + 0x2440 + partition.Header.ApploaderSize + partition.Header.ApploaderTrailerSize); - // DOL - partition.Header.DOLOffset = filesystem->GetBootDOLOffset(); - partition.Header.DOLSize = filesystem->GetBootDOLSize(partition.Header.DOLOffset); - parsed_ok = parsed_ok && partition.Header.DOLOffset && partition.Header.DOLSize; - MarkAsUsedE(partition.Offset - + partition.Header.DataOffset - , partition.Header.DOLOffset - , partition.Header.DOLSize); + // DOL + partition.Header.DOLOffset = filesystem->GetBootDOLOffset(); + partition.Header.DOLSize = filesystem->GetBootDOLSize(partition.Header.DOLOffset); + parsed_ok = parsed_ok && partition.Header.DOLOffset && partition.Header.DOLSize; + MarkAsUsedE(partition.Offset + partition.Header.DataOffset, partition.Header.DOLOffset, + partition.Header.DOLSize); - // FST - parsed_ok = parsed_ok && ReadFromVolume(0x424, partition.Header.FSTOffset, true); - parsed_ok = parsed_ok && ReadFromVolume(0x428, partition.Header.FSTSize, true); - MarkAsUsedE(partition.Offset - + partition.Header.DataOffset - , partition.Header.FSTOffset - , partition.Header.FSTSize); + // FST + parsed_ok = parsed_ok && ReadFromVolume(0x424, partition.Header.FSTOffset, true); + parsed_ok = parsed_ok && ReadFromVolume(0x428, partition.Header.FSTSize, true); + MarkAsUsedE(partition.Offset + partition.Header.DataOffset, partition.Header.FSTOffset, + partition.Header.FSTSize); - // Go through the filesystem and mark entries as used - for (SFileInfo file : filesystem->GetFileList()) - { - DEBUG_LOG(DISCIO, "%s", file.m_FullPath.empty() ? "/" : file.m_FullPath.c_str()); - if ((file.m_NameOffset & 0x1000000) == 0) - MarkAsUsedE(partition.Offset + partition.Header.DataOffset, file.m_Offset, file.m_FileSize); - } - } + // Go through the filesystem and mark entries as used + for (SFileInfo file : filesystem->GetFileList()) + { + DEBUG_LOG(DISCIO, "%s", file.m_FullPath.empty() ? "/" : file.m_FullPath.c_str()); + if ((file.m_NameOffset & 0x1000000) == 0) + MarkAsUsedE(partition.Offset + partition.Header.DataOffset, file.m_Offset, file.m_FileSize); + } + } - // Swap back - s_disc.swap(old_volume); + // Swap back + s_disc.swap(old_volume); - return parsed_ok; + return parsed_ok; } -} // namespace DiscScrubber +} // namespace DiscScrubber -} // namespace DiscIO +} // namespace DiscIO diff --git a/Source/Core/DiscIO/DiscScrubber.h b/Source/Core/DiscIO/DiscScrubber.h index b03dfc1bc5..6bf6c1b84f 100644 --- a/Source/Core/DiscIO/DiscScrubber.h +++ b/Source/Core/DiscIO/DiscScrubber.h @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // DiscScrubber removes the garbage data from discs (currently Wii only) which // is on the disc due to encryption @@ -16,18 +15,19 @@ #include #include "Common/CommonTypes.h" -namespace File { class IOFile; } +namespace File +{ +class IOFile; +} namespace DiscIO { - namespace DiscScrubber { - bool SetupScrub(const std::string& filename, int block_size); size_t GetNextBlock(File::IOFile& in, u8* buffer); void Cleanup(); -} // namespace DiscScrubber +} // namespace DiscScrubber -} // namespace DiscIO +} // namespace DiscIO diff --git a/Source/Core/DiscIO/DriveBlob.cpp b/Source/Core/DiscIO/DriveBlob.cpp index 7aaefc402d..f522923f33 100644 --- a/Source/Core/DiscIO/DriveBlob.cpp +++ b/Source/Core/DiscIO/DriveBlob.cpp @@ -11,154 +11,148 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "DiscIO/Blob.h" #include "DiscIO/DriveBlob.h" #ifdef _WIN32 #include "Common/StringUtil.h" #else +#include // fileno #include -#include // fileno #if defined __linux__ -#include // BLKGETSIZE64 +#include // BLKGETSIZE64 #elif defined __FreeBSD__ -#include // DIOCGMEDIASIZE +#include // DIOCGMEDIASIZE #elif defined __APPLE__ -#include // DKIOCGETBLOCKCOUNT / DKIOCGETBLOCKSIZE +#include // DKIOCGETBLOCKCOUNT / DKIOCGETBLOCKSIZE #endif #endif namespace DiscIO { - DriveReader::DriveReader(const std::string& drive) { - // 32 sectors is roughly the optimal amount a CD Drive can read in - // a single IO cycle. Larger values yield no performance improvement - // and just cause IO stalls from the read delay. Smaller values allow - // the OS IO and seeking overhead to ourstrip the time actually spent - // transferring bytes from the media. - SetChunkSize(32); // 32*2048 = 64KiB - SetSectorSize(2048); + // 32 sectors is roughly the optimal amount a CD Drive can read in + // a single IO cycle. Larger values yield no performance improvement + // and just cause IO stalls from the read delay. Smaller values allow + // the OS IO and seeking overhead to ourstrip the time actually spent + // transferring bytes from the media. + SetChunkSize(32); // 32*2048 = 64KiB + SetSectorSize(2048); #ifdef _WIN32 - auto const path = UTF8ToTStr(std::string("\\\\.\\") + drive); - m_disc_handle = CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, - nullptr, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, nullptr); - if (IsOK()) - { - // Do a test read to make sure everything is OK, since it seems you can get - // handles to empty drives. - DWORD not_used; - std::vector buffer(GetSectorSize()); - if (!ReadFile(m_disc_handle, buffer.data(), GetSectorSize(), ¬_used, nullptr)) - { - // OK, something is wrong. - CloseHandle(m_disc_handle); - m_disc_handle = INVALID_HANDLE_VALUE; - } - } - if (IsOK()) - { - // Initialize m_size by querying the volume capacity. - STORAGE_READ_CAPACITY storage_size; - storage_size.Version = sizeof(storage_size); - DWORD bytes = 0; - DeviceIoControl(m_disc_handle, IOCTL_STORAGE_READ_CAPACITY, nullptr, 0, - &storage_size, sizeof(storage_size), &bytes, nullptr); - m_size = bytes ? storage_size.DiskLength.QuadPart : 0; + auto const path = UTF8ToTStr(std::string("\\\\.\\") + drive); + m_disc_handle = CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, nullptr); + if (IsOK()) + { + // Do a test read to make sure everything is OK, since it seems you can get + // handles to empty drives. + DWORD not_used; + std::vector buffer(GetSectorSize()); + if (!ReadFile(m_disc_handle, buffer.data(), GetSectorSize(), ¬_used, nullptr)) + { + // OK, something is wrong. + CloseHandle(m_disc_handle); + m_disc_handle = INVALID_HANDLE_VALUE; + } + } + if (IsOK()) + { + // Initialize m_size by querying the volume capacity. + STORAGE_READ_CAPACITY storage_size; + storage_size.Version = sizeof(storage_size); + DWORD bytes = 0; + DeviceIoControl(m_disc_handle, IOCTL_STORAGE_READ_CAPACITY, nullptr, 0, &storage_size, + sizeof(storage_size), &bytes, nullptr); + m_size = bytes ? storage_size.DiskLength.QuadPart : 0; - #ifdef _LOCKDRIVE // Do we want to lock the drive? - // Lock the compact disc in the CD-ROM drive to prevent accidental - // removal while reading from it. - m_lock_cdrom.PreventMediaRemoval = TRUE; - DeviceIoControl(m_disc_handle, IOCTL_CDROM_MEDIA_REMOVAL, - &m_lock_cdrom, sizeof(m_lock_cdrom), nullptr, - 0, &dwNotUsed, nullptr); - #endif +#ifdef _LOCKDRIVE // Do we want to lock the drive? + // Lock the compact disc in the CD-ROM drive to prevent accidental + // removal while reading from it. + m_lock_cdrom.PreventMediaRemoval = TRUE; + DeviceIoControl(m_disc_handle, IOCTL_CDROM_MEDIA_REMOVAL, &m_lock_cdrom, sizeof(m_lock_cdrom), + nullptr, 0, &dwNotUsed, nullptr); +#endif #else - m_file.Open(drive, "rb"); - if (m_file) - { - int fd = fileno(m_file.GetHandle()); + m_file.Open(drive, "rb"); + if (m_file) + { + int fd = fileno(m_file.GetHandle()); #if defined __linux__ - // NOTE: Doesn't matter if it fails, m_size was initialized to zero - ioctl(fd, BLKGETSIZE64, &m_size); // u64* + // NOTE: Doesn't matter if it fails, m_size was initialized to zero + ioctl(fd, BLKGETSIZE64, &m_size); // u64* #elif defined __FreeBSD__ - off_t size = 0; - ioctl(fd, DIOCGMEDIASIZE, &size); // off_t* - m_size = size; + off_t size = 0; + ioctl(fd, DIOCGMEDIASIZE, &size); // off_t* + m_size = size; #elif defined __APPLE__ - u64 count = 0; - u32 block_size = 0; - ioctl(fd, DKIOCGETBLOCKCOUNT, &count); // u64* - ioctl(fd, DKIOCGETBLOCKSIZE, &block_size); // u32* - m_size = count * block_size; + u64 count = 0; + u32 block_size = 0; + ioctl(fd, DKIOCGETBLOCKCOUNT, &count); // u64* + ioctl(fd, DKIOCGETBLOCKSIZE, &block_size); // u32* + m_size = count * block_size; #endif #endif - } - else - { - NOTICE_LOG(DISCIO, "Load from DVD backup failed or no disc in drive %s", drive.c_str()); - } + } + else { NOTICE_LOG(DISCIO, "Load from DVD backup failed or no disc in drive %s", drive.c_str()); } } DriveReader::~DriveReader() { #ifdef _WIN32 -#ifdef _LOCKDRIVE // Do we want to lock the drive? - // Unlock the disc in the CD-ROM drive. - m_lock_cdrom.PreventMediaRemoval = FALSE; - DeviceIoControl (m_disc_handle, IOCTL_CDROM_MEDIA_REMOVAL, - &m_lock_cdrom, sizeof(m_lock_cdrom), nullptr, - 0, &dwNotUsed, nullptr); +#ifdef _LOCKDRIVE // Do we want to lock the drive? + // Unlock the disc in the CD-ROM drive. + m_lock_cdrom.PreventMediaRemoval = FALSE; + DeviceIoControl(m_disc_handle, IOCTL_CDROM_MEDIA_REMOVAL, &m_lock_cdrom, sizeof(m_lock_cdrom), + nullptr, 0, &dwNotUsed, nullptr); #endif - if (m_disc_handle != INVALID_HANDLE_VALUE) - { - CloseHandle(m_disc_handle); - m_disc_handle = INVALID_HANDLE_VALUE; - } + if (m_disc_handle != INVALID_HANDLE_VALUE) + { + CloseHandle(m_disc_handle); + m_disc_handle = INVALID_HANDLE_VALUE; + } #else - m_file.Close(); + m_file.Close(); #endif } std::unique_ptr DriveReader::Create(const std::string& drive) { - auto reader = std::unique_ptr(new DriveReader(drive)); + auto reader = std::unique_ptr(new DriveReader(drive)); - if (!reader->IsOK()) - reader.reset(); + if (!reader->IsOK()) + reader.reset(); - return reader; + return reader; } bool DriveReader::GetBlock(u64 block_num, u8* out_ptr) { - return DriveReader::ReadMultipleAlignedBlocks(block_num, 1, out_ptr); + return DriveReader::ReadMultipleAlignedBlocks(block_num, 1, out_ptr); } bool DriveReader::ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8* out_ptr) { #ifdef _WIN32 - LARGE_INTEGER offset; - offset.QuadPart = GetSectorSize() * block_num; - SetFilePointerEx(m_disc_handle, offset, nullptr, FILE_BEGIN); - DWORD bytes_read; - if (!ReadFile(m_disc_handle, out_ptr, static_cast(GetSectorSize() * num_blocks), - &bytes_read, nullptr)) - { - PanicAlertT("Disc Read Error"); - return false; - } - return bytes_read == GetSectorSize() * num_blocks; + LARGE_INTEGER offset; + offset.QuadPart = GetSectorSize() * block_num; + SetFilePointerEx(m_disc_handle, offset, nullptr, FILE_BEGIN); + DWORD bytes_read; + if (!ReadFile(m_disc_handle, out_ptr, static_cast(GetSectorSize() * num_blocks), + &bytes_read, nullptr)) + { + PanicAlertT("Disc Read Error"); + return false; + } + return bytes_read == GetSectorSize() * num_blocks; #else - m_file.Seek(GetSectorSize() * block_num, SEEK_SET); - if (m_file.ReadBytes(out_ptr, num_blocks * GetSectorSize())) - return true; - m_file.Clear(); - return false; + m_file.Seek(GetSectorSize() * block_num, SEEK_SET); + if (m_file.ReadBytes(out_ptr, num_blocks * GetSectorSize())) + return true; + m_file.Clear(); + return false; #endif } diff --git a/Source/Core/DiscIO/DriveBlob.h b/Source/Core/DiscIO/DriveBlob.h index fd9126fa65..01ef409111 100644 --- a/Source/Core/DiscIO/DriveBlob.h +++ b/Source/Core/DiscIO/DriveBlob.h @@ -18,30 +18,28 @@ namespace DiscIO { - class DriveReader : public SectorReader { public: - static std::unique_ptr Create(const std::string& drive); - ~DriveReader(); - BlobType GetBlobType() const override { return BlobType::DRIVE; } - u64 GetDataSize() const override { return m_size; } - u64 GetRawSize() const override { return m_size; } - + static std::unique_ptr Create(const std::string& drive); + ~DriveReader(); + BlobType GetBlobType() const override { return BlobType::DRIVE; } + u64 GetDataSize() const override { return m_size; } + u64 GetRawSize() const override { return m_size; } private: - DriveReader(const std::string& drive); - bool GetBlock(u64 block_num, u8 *out_ptr) override; - bool ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8* out_ptr) override; + DriveReader(const std::string& drive); + bool GetBlock(u64 block_num, u8* out_ptr) override; + bool ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8* out_ptr) override; #ifdef _WIN32 - HANDLE m_disc_handle = INVALID_HANDLE_VALUE; - PREVENT_MEDIA_REMOVAL m_lock_cdrom; - bool IsOK() const { return m_disc_handle != INVALID_HANDLE_VALUE; } + HANDLE m_disc_handle = INVALID_HANDLE_VALUE; + PREVENT_MEDIA_REMOVAL m_lock_cdrom; + bool IsOK() const { return m_disc_handle != INVALID_HANDLE_VALUE; } #else - File::IOFile m_file; - bool IsOK() const { return m_file.IsOpen() && m_file.IsGood(); } + File::IOFile m_file; + bool IsOK() const { return m_file.IsOpen() && m_file.IsGood(); } #endif - u64 m_size = 0; + u64 m_size = 0; }; } // namespace diff --git a/Source/Core/DiscIO/FileBlob.cpp b/Source/Core/DiscIO/FileBlob.cpp index 79b66b37bc..7d1dabe198 100644 --- a/Source/Core/DiscIO/FileBlob.cpp +++ b/Source/Core/DiscIO/FileBlob.cpp @@ -2,39 +2,37 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "DiscIO/FileBlob.h" #include #include -#include "DiscIO/FileBlob.h" namespace DiscIO { - -PlainFileReader::PlainFileReader(std::FILE* file) - : m_file(file) +PlainFileReader::PlainFileReader(std::FILE* file) : m_file(file) { - m_size = m_file.GetSize(); + m_size = m_file.GetSize(); } std::unique_ptr PlainFileReader::Create(const std::string& filename) { - File::IOFile f(filename, "rb"); - if (f) - return std::unique_ptr(new PlainFileReader(f.ReleaseHandle())); + File::IOFile f(filename, "rb"); + if (f) + return std::unique_ptr(new PlainFileReader(f.ReleaseHandle())); - return nullptr; + return nullptr; } bool PlainFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr) { - if (m_file.Seek(offset, SEEK_SET) && m_file.ReadBytes(out_ptr, nbytes)) - { - return true; - } - else - { - m_file.Clear(); - return false; - } + if (m_file.Seek(offset, SEEK_SET) && m_file.ReadBytes(out_ptr, nbytes)) + { + return true; + } + else + { + m_file.Clear(); + return false; + } } } // namespace diff --git a/Source/Core/DiscIO/FileBlob.h b/Source/Core/DiscIO/FileBlob.h index 581f155e16..3a85799651 100644 --- a/Source/Core/DiscIO/FileBlob.h +++ b/Source/Core/DiscIO/FileBlob.h @@ -14,22 +14,21 @@ namespace DiscIO { - class PlainFileReader : public IBlobReader { public: - static std::unique_ptr Create(const std::string& filename); + static std::unique_ptr Create(const std::string& filename); - BlobType GetBlobType() const override { return BlobType::PLAIN; } - u64 GetDataSize() const override { return m_size; } - u64 GetRawSize() const override { return m_size; } - bool Read(u64 offset, u64 nbytes, u8* out_ptr) override; + BlobType GetBlobType() const override { return BlobType::PLAIN; } + u64 GetDataSize() const override { return m_size; } + u64 GetRawSize() const override { return m_size; } + bool Read(u64 offset, u64 nbytes, u8* out_ptr) override; private: - PlainFileReader(std::FILE* file); + PlainFileReader(std::FILE* file); - File::IOFile m_file; - s64 m_size; + File::IOFile m_file; + s64 m_size; }; } // namespace diff --git a/Source/Core/DiscIO/FileMonitor.cpp b/Source/Core/DiscIO/FileMonitor.cpp index 469fa4d460..6ef23fb088 100644 --- a/Source/Core/DiscIO/FileMonitor.cpp +++ b/Source/Core/DiscIO/FileMonitor.cpp @@ -11,12 +11,12 @@ #include #include "Common/CommonTypes.h" -#include "Common/StringUtil.h" #include "Common/Logging/LogManager.h" +#include "Common/StringUtil.h" +#include "Core/Boot/Boot.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/Boot/Boot.h" #include "DiscIO/FileMonitor.h" #include "DiscIO/Filesystem.h" @@ -25,7 +25,6 @@ namespace FileMon { - static std::unique_ptr s_open_iso; static std::unique_ptr s_filesystem; static std::string ISOFile = "", CurrentFile = ""; @@ -34,121 +33,118 @@ static bool FileAccess = true; // Filtered files bool IsSoundFile(const std::string& filename) { - std::string extension; - SplitPath(filename, nullptr, nullptr, &extension); - std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); + std::string extension; + SplitPath(filename, nullptr, nullptr, &extension); + std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - static std::unordered_set extensions = { - ".adp", // 1080 Avalanche, Crash Bandicoot, etc. - ".adx", // Sonic Adventure 2 Battle, etc. - ".afc", // Zelda WW - ".ast", // Zelda TP, Mario Kart - ".brstm", // Wii Sports, Wario Land, etc. - ".dsp", // Metroid Prime - ".hps", // SSB Melee - ".ogg", // Tony Hawk's Underground 2 - ".sad", // Disaster - ".snd", // Tales of Symphonia - ".song", // Tales of Symphonia - ".ssm", // Custom Robo, Kirby Air Ride, etc. - ".str", // Harry Potter & the Sorcerer's Stone - }; + static std::unordered_set extensions = { + ".adp", // 1080 Avalanche, Crash Bandicoot, etc. + ".adx", // Sonic Adventure 2 Battle, etc. + ".afc", // Zelda WW + ".ast", // Zelda TP, Mario Kart + ".brstm", // Wii Sports, Wario Land, etc. + ".dsp", // Metroid Prime + ".hps", // SSB Melee + ".ogg", // Tony Hawk's Underground 2 + ".sad", // Disaster + ".snd", // Tales of Symphonia + ".song", // Tales of Symphonia + ".ssm", // Custom Robo, Kirby Air Ride, etc. + ".str", // Harry Potter & the Sorcerer's Stone + }; - return extensions.find(extension) != extensions.end(); + return extensions.find(extension) != extensions.end(); } - // Read the file system void ReadFileSystem(const std::string& filename) { - // Should have an actual Shutdown procedure or something - s_open_iso.reset(); - s_filesystem.reset(); + // Should have an actual Shutdown procedure or something + s_open_iso.reset(); + s_filesystem.reset(); - s_open_iso = DiscIO::CreateVolumeFromFilename(filename); - if (!s_open_iso) - return; + s_open_iso = DiscIO::CreateVolumeFromFilename(filename); + if (!s_open_iso) + return; - if (s_open_iso->GetVolumeType() != DiscIO::IVolume::WII_WAD) - { - s_filesystem = DiscIO::CreateFileSystem(s_open_iso.get()); + if (s_open_iso->GetVolumeType() != DiscIO::IVolume::WII_WAD) + { + s_filesystem = DiscIO::CreateFileSystem(s_open_iso.get()); - if (!s_filesystem) - return; - } + if (!s_filesystem) + return; + } - FileAccess = true; + FileAccess = true; } // Logs a file if it passes a few checks void CheckFile(const std::string& file, u64 size) { - // Don't do anything if the log is unselected - if (!LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON, LogTypes::LWARNING)) - return; - // Do nothing if we found the same file again - if (CurrentFile == file) - return; + // Don't do anything if the log is unselected + if (!LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON, LogTypes::LWARNING)) + return; + // Do nothing if we found the same file again + if (CurrentFile == file) + return; - if (size > 0) - size = (size / 1000); + if (size > 0) + size = (size / 1000); - std::string str = StringFromFormat("%s kB %s", ThousandSeparate(size, 7).c_str(), file.c_str()); - if (IsSoundFile(file)) - { - INFO_LOG(FILEMON, "%s", str.c_str()); - } - else - { - WARN_LOG(FILEMON, "%s", str.c_str()); - } + std::string str = StringFromFormat("%s kB %s", ThousandSeparate(size, 7).c_str(), file.c_str()); + if (IsSoundFile(file)) + { + INFO_LOG(FILEMON, "%s", str.c_str()); + } + else + { + WARN_LOG(FILEMON, "%s", str.c_str()); + } - // Update the current file - CurrentFile = file; + // Update the current file + CurrentFile = file; } - // Find the filename void FindFilename(u64 offset) { - // Don't do anything if a game is not running - if (Core::GetState() != Core::CORE_RUN) - return; + // Don't do anything if a game is not running + if (Core::GetState() != Core::CORE_RUN) + return; - // Or if the log is unselected - if (!LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON, LogTypes::LWARNING)) - return; + // Or if the log is unselected + if (!LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON, LogTypes::LWARNING)) + return; - // Or if we don't have file access - if (!FileAccess) - return; + // Or if we don't have file access + if (!FileAccess) + return; - if (!s_filesystem || ISOFile != SConfig::GetInstance().m_LastFilename) - { - FileAccess = false; - ReadFileSystem(SConfig::GetInstance().m_LastFilename); - ISOFile = SConfig::GetInstance().m_LastFilename; - INFO_LOG(FILEMON, "Opening '%s'", ISOFile.c_str()); - return; - } + if (!s_filesystem || ISOFile != SConfig::GetInstance().m_LastFilename) + { + FileAccess = false; + ReadFileSystem(SConfig::GetInstance().m_LastFilename); + ISOFile = SConfig::GetInstance().m_LastFilename; + INFO_LOG(FILEMON, "Opening '%s'", ISOFile.c_str()); + return; + } - const std::string filename = s_filesystem->GetFileName(offset); + const std::string filename = s_filesystem->GetFileName(offset); - if (filename.empty()) - return; + if (filename.empty()) + return; - CheckFile(filename, s_filesystem->GetFileSize(filename)); + CheckFile(filename, s_filesystem->GetFileSize(filename)); } void Close() { - s_open_iso.reset(); - s_filesystem.reset(); + s_open_iso.reset(); + s_filesystem.reset(); - ISOFile = ""; - CurrentFile = ""; - FileAccess = true; + ISOFile = ""; + CurrentFile = ""; + FileAccess = true; } - -} // FileMon +} // FileMon diff --git a/Source/Core/DiscIO/FileMonitor.h b/Source/Core/DiscIO/FileMonitor.h index 38ece7265b..0e73152947 100644 --- a/Source/Core/DiscIO/FileMonitor.h +++ b/Source/Core/DiscIO/FileMonitor.h @@ -10,11 +10,9 @@ namespace FileMon { - bool IsSoundFile(const std::string& filename); void ReadFileSystem(const std::string& file); void CheckFile(const std::string& file, u64 size); void FindFilename(u64 offset); void Close(); - } diff --git a/Source/Core/DiscIO/FileSystemGCWii.cpp b/Source/Core/DiscIO/FileSystemGCWii.cpp index f721173346..9e27e6f70e 100644 --- a/Source/Core/DiscIO/FileSystemGCWii.cpp +++ b/Source/Core/DiscIO/FileSystemGCWii.cpp @@ -11,347 +11,349 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" -#include "DiscIO/Filesystem.h" #include "DiscIO/FileSystemGCWii.h" +#include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" namespace DiscIO { -CFileSystemGCWii::CFileSystemGCWii(const IVolume *_rVolume) - : IFileSystem(_rVolume) - , m_Initialized(false) - , m_Valid(false) - , m_Wii(false) +CFileSystemGCWii::CFileSystemGCWii(const IVolume* _rVolume) + : IFileSystem(_rVolume), m_Initialized(false), m_Valid(false), m_Wii(false) { - m_Valid = DetectFileSystem(); + m_Valid = DetectFileSystem(); } CFileSystemGCWii::~CFileSystemGCWii() { - m_FileInfoVector.clear(); + m_FileInfoVector.clear(); } u64 CFileSystemGCWii::GetFileSize(const std::string& _rFullPath) { - if (!m_Initialized) - InitFileSystem(); + if (!m_Initialized) + InitFileSystem(); - const SFileInfo* pFileInfo = FindFileInfo(_rFullPath); + const SFileInfo* pFileInfo = FindFileInfo(_rFullPath); - if (pFileInfo != nullptr && !pFileInfo->IsDirectory()) - return pFileInfo->m_FileSize; + if (pFileInfo != nullptr && !pFileInfo->IsDirectory()) + return pFileInfo->m_FileSize; - return 0; + return 0; } const std::string CFileSystemGCWii::GetFileName(u64 _Address) { - if (!m_Initialized) - InitFileSystem(); + if (!m_Initialized) + InitFileSystem(); - for (auto& fileInfo : m_FileInfoVector) - { - if ((fileInfo.m_Offset <= _Address) && - ((fileInfo.m_Offset + fileInfo.m_FileSize) > _Address)) - { - return fileInfo.m_FullPath; - } - } + for (auto& fileInfo : m_FileInfoVector) + { + if ((fileInfo.m_Offset <= _Address) && ((fileInfo.m_Offset + fileInfo.m_FileSize) > _Address)) + { + return fileInfo.m_FullPath; + } + } - return ""; + return ""; } -u64 CFileSystemGCWii::ReadFile(const std::string& _rFullPath, u8* _pBuffer, u64 _MaxBufferSize, u64 _OffsetInFile) +u64 CFileSystemGCWii::ReadFile(const std::string& _rFullPath, u8* _pBuffer, u64 _MaxBufferSize, + u64 _OffsetInFile) { - if (!m_Initialized) - InitFileSystem(); + if (!m_Initialized) + InitFileSystem(); - const SFileInfo* pFileInfo = FindFileInfo(_rFullPath); - if (pFileInfo == nullptr) - return 0; + const SFileInfo* pFileInfo = FindFileInfo(_rFullPath); + if (pFileInfo == nullptr) + return 0; - if (_OffsetInFile >= pFileInfo->m_FileSize) - return 0; + if (_OffsetInFile >= pFileInfo->m_FileSize) + return 0; - u64 read_length = std::min(_MaxBufferSize, pFileInfo->m_FileSize - _OffsetInFile); + u64 read_length = std::min(_MaxBufferSize, pFileInfo->m_FileSize - _OffsetInFile); - DEBUG_LOG(DISCIO, "Reading %" PRIx64 " bytes at %" PRIx64 " from file %s. Offset: %" PRIx64 " Size: %" PRIx64, - read_length, _OffsetInFile, _rFullPath.c_str(), pFileInfo->m_Offset, pFileInfo->m_FileSize); + DEBUG_LOG(DISCIO, "Reading %" PRIx64 " bytes at %" PRIx64 " from file %s. Offset: %" PRIx64 + " Size: %" PRIx64, + read_length, _OffsetInFile, _rFullPath.c_str(), pFileInfo->m_Offset, + pFileInfo->m_FileSize); - m_rVolume->Read(pFileInfo->m_Offset + _OffsetInFile, read_length, _pBuffer, m_Wii); - return read_length; + m_rVolume->Read(pFileInfo->m_Offset + _OffsetInFile, read_length, _pBuffer, m_Wii); + return read_length; } -bool CFileSystemGCWii::ExportFile(const std::string& _rFullPath, const std::string& _rExportFilename) +bool CFileSystemGCWii::ExportFile(const std::string& _rFullPath, + const std::string& _rExportFilename) { - if (!m_Initialized) - InitFileSystem(); + if (!m_Initialized) + InitFileSystem(); - const SFileInfo* pFileInfo = FindFileInfo(_rFullPath); + const SFileInfo* pFileInfo = FindFileInfo(_rFullPath); - if (!pFileInfo) - return false; + if (!pFileInfo) + return false; - u64 remainingSize = pFileInfo->m_FileSize; - u64 fileOffset = pFileInfo->m_Offset; + u64 remainingSize = pFileInfo->m_FileSize; + u64 fileOffset = pFileInfo->m_Offset; - File::IOFile f(_rExportFilename, "wb"); - if (!f) - return false; + File::IOFile f(_rExportFilename, "wb"); + if (!f) + return false; - bool result = true; + bool result = true; - while (remainingSize) - { - // Limit read size to 128 MB - size_t readSize = (size_t)std::min(remainingSize, (u64)0x08000000); + while (remainingSize) + { + // Limit read size to 128 MB + size_t readSize = (size_t)std::min(remainingSize, (u64)0x08000000); - std::vector buffer(readSize); + std::vector buffer(readSize); - result = m_rVolume->Read(fileOffset, readSize, &buffer[0], m_Wii); + result = m_rVolume->Read(fileOffset, readSize, &buffer[0], m_Wii); - if (!result) - break; + if (!result) + break; - f.WriteBytes(&buffer[0], readSize); + f.WriteBytes(&buffer[0], readSize); - remainingSize -= readSize; - fileOffset += readSize; - } + remainingSize -= readSize; + fileOffset += readSize; + } - return result; + return result; } bool CFileSystemGCWii::ExportApploader(const std::string& _rExportFolder) const { - u32 apploader_size; - u32 trailer_size; - const u32 header_size = 0x20; - if (!m_rVolume->ReadSwapped(0x2440 + 0x14, &apploader_size, m_Wii) || - !m_rVolume->ReadSwapped(0x2440 + 0x18, &trailer_size, m_Wii)) - return false; - apploader_size += trailer_size + header_size; - DEBUG_LOG(DISCIO, "Apploader size -> %x", apploader_size); + u32 apploader_size; + u32 trailer_size; + const u32 header_size = 0x20; + if (!m_rVolume->ReadSwapped(0x2440 + 0x14, &apploader_size, m_Wii) || + !m_rVolume->ReadSwapped(0x2440 + 0x18, &trailer_size, m_Wii)) + return false; + apploader_size += trailer_size + header_size; + DEBUG_LOG(DISCIO, "Apploader size -> %x", apploader_size); - std::vector buffer(apploader_size); - if (m_rVolume->Read(0x2440, apploader_size, buffer.data(), m_Wii)) - { - std::string exportName(_rExportFolder + "/apploader.img"); + std::vector buffer(apploader_size); + if (m_rVolume->Read(0x2440, apploader_size, buffer.data(), m_Wii)) + { + std::string exportName(_rExportFolder + "/apploader.img"); - File::IOFile AppFile(exportName, "wb"); - if (AppFile) - { - AppFile.WriteBytes(buffer.data(), apploader_size); - return true; - } - } + File::IOFile AppFile(exportName, "wb"); + if (AppFile) + { + AppFile.WriteBytes(buffer.data(), apploader_size); + return true; + } + } - return false; + return false; } u64 CFileSystemGCWii::GetBootDOLOffset() const { - u32 offset = 0; - m_rVolume->ReadSwapped(0x420, &offset, m_Wii); - return static_cast(offset) << GetOffsetShift(); + u32 offset = 0; + m_rVolume->ReadSwapped(0x420, &offset, m_Wii); + return static_cast(offset) << GetOffsetShift(); } u32 CFileSystemGCWii::GetBootDOLSize(u64 dol_offset) const { - // The dol_offset value is usually obtained by calling GetBootDOLOffset. - // If GetBootDOLOffset fails by returning 0, GetBootDOLSize should also fail. - if (dol_offset == 0) - return 0; + // The dol_offset value is usually obtained by calling GetBootDOLOffset. + // If GetBootDOLOffset fails by returning 0, GetBootDOLSize should also fail. + if (dol_offset == 0) + return 0; - u32 dol_size = 0; - u32 offset = 0; - u32 size = 0; + u32 dol_size = 0; + u32 offset = 0; + u32 size = 0; - // Iterate through the 7 code segments - for (u8 i = 0; i < 7; i++) - { - if (!m_rVolume->ReadSwapped(dol_offset + 0x00 + i * 4, &offset, m_Wii) || - !m_rVolume->ReadSwapped(dol_offset + 0x90 + i * 4, &size, m_Wii)) - return 0; - dol_size = std::max(offset + size, dol_size); - } + // Iterate through the 7 code segments + for (u8 i = 0; i < 7; i++) + { + if (!m_rVolume->ReadSwapped(dol_offset + 0x00 + i * 4, &offset, m_Wii) || + !m_rVolume->ReadSwapped(dol_offset + 0x90 + i * 4, &size, m_Wii)) + return 0; + dol_size = std::max(offset + size, dol_size); + } - // Iterate through the 11 data segments - for (u8 i = 0; i < 11; i++) - { - if (!m_rVolume->ReadSwapped(dol_offset + 0x1c + i * 4, &offset, m_Wii) || - !m_rVolume->ReadSwapped(dol_offset + 0xac + i * 4, &size, m_Wii)) - return 0; - dol_size = std::max(offset + size, dol_size); - } + // Iterate through the 11 data segments + for (u8 i = 0; i < 11; i++) + { + if (!m_rVolume->ReadSwapped(dol_offset + 0x1c + i * 4, &offset, m_Wii) || + !m_rVolume->ReadSwapped(dol_offset + 0xac + i * 4, &size, m_Wii)) + return 0; + dol_size = std::max(offset + size, dol_size); + } - return dol_size; + return dol_size; } bool CFileSystemGCWii::ExportDOL(const std::string& _rExportFolder) const { - u64 DolOffset = GetBootDOLOffset(); - u32 DolSize = GetBootDOLSize(DolOffset); + u64 DolOffset = GetBootDOLOffset(); + u32 DolSize = GetBootDOLSize(DolOffset); - if (DolOffset == 0 || DolSize == 0) - return false; + if (DolOffset == 0 || DolSize == 0) + return false; - std::vector buffer(DolSize); - if (m_rVolume->Read(DolOffset, DolSize, &buffer[0], m_Wii)) - { - std::string exportName(_rExportFolder + "/boot.dol"); + std::vector buffer(DolSize); + if (m_rVolume->Read(DolOffset, DolSize, &buffer[0], m_Wii)) + { + std::string exportName(_rExportFolder + "/boot.dol"); - File::IOFile DolFile(exportName, "wb"); - if (DolFile) - { - DolFile.WriteBytes(&buffer[0], DolSize); - return true; - } - } + File::IOFile DolFile(exportName, "wb"); + if (DolFile) + { + DolFile.WriteBytes(&buffer[0], DolSize); + return true; + } + } - return false; + return false; } std::string CFileSystemGCWii::GetStringFromOffset(u64 _Offset) const { - std::string data(255, 0x00); - m_rVolume->Read(_Offset, data.size(), (u8*)&data[0], m_Wii); - data.erase(std::find(data.begin(), data.end(), 0x00), data.end()); + std::string data(255, 0x00); + m_rVolume->Read(_Offset, data.size(), (u8*)&data[0], m_Wii); + data.erase(std::find(data.begin(), data.end(), 0x00), data.end()); - // TODO: Should we really always use SHIFT-JIS? - // It makes some filenames in Pikmin (NTSC-U) sane, but is it correct? - return SHIFTJISToUTF8(data); + // TODO: Should we really always use SHIFT-JIS? + // It makes some filenames in Pikmin (NTSC-U) sane, but is it correct? + return SHIFTJISToUTF8(data); } const std::vector& CFileSystemGCWii::GetFileList() { - if (!m_Initialized) - InitFileSystem(); + if (!m_Initialized) + InitFileSystem(); - return m_FileInfoVector; + return m_FileInfoVector; } const SFileInfo* CFileSystemGCWii::FindFileInfo(const std::string& _rFullPath) { - if (!m_Initialized) - InitFileSystem(); + if (!m_Initialized) + InitFileSystem(); - for (auto& fileInfo : m_FileInfoVector) - { - if (!strcasecmp(fileInfo.m_FullPath.c_str(), _rFullPath.c_str())) - return &fileInfo; - } + for (auto& fileInfo : m_FileInfoVector) + { + if (!strcasecmp(fileInfo.m_FullPath.c_str(), _rFullPath.c_str())) + return &fileInfo; + } - return nullptr; + return nullptr; } bool CFileSystemGCWii::DetectFileSystem() { - u32 magic_bytes; - if (m_rVolume->ReadSwapped(0x18, &magic_bytes, false) && magic_bytes == 0x5D1C9EA3) - { - m_Wii = true; - return true; - } - else if (m_rVolume->ReadSwapped(0x1c, &magic_bytes, false) && magic_bytes == 0xC2339F3D) - { - m_Wii = false; - return true; - } + u32 magic_bytes; + if (m_rVolume->ReadSwapped(0x18, &magic_bytes, false) && magic_bytes == 0x5D1C9EA3) + { + m_Wii = true; + return true; + } + else if (m_rVolume->ReadSwapped(0x1c, &magic_bytes, false) && magic_bytes == 0xC2339F3D) + { + m_Wii = false; + return true; + } - return false; + return false; } void CFileSystemGCWii::InitFileSystem() { - m_Initialized = true; - u32 const shift = GetOffsetShift(); + m_Initialized = true; + u32 const shift = GetOffsetShift(); - // read the whole FST - u32 fst_offset_unshifted; - if (!m_rVolume->ReadSwapped(0x424, &fst_offset_unshifted, m_Wii)) - return; - u64 FSTOffset = static_cast(fst_offset_unshifted) << shift; + // read the whole FST + u32 fst_offset_unshifted; + if (!m_rVolume->ReadSwapped(0x424, &fst_offset_unshifted, m_Wii)) + return; + u64 FSTOffset = static_cast(fst_offset_unshifted) << shift; - // read all fileinfos - u32 name_offset, offset, size; - if (!m_rVolume->ReadSwapped(FSTOffset + 0x0, &name_offset, m_Wii) || - !m_rVolume->ReadSwapped(FSTOffset + 0x4, &offset, m_Wii) || - !m_rVolume->ReadSwapped(FSTOffset + 0x8, &size, m_Wii)) - return; - SFileInfo root = { name_offset, static_cast(offset) << shift, size }; + // read all fileinfos + u32 name_offset, offset, size; + if (!m_rVolume->ReadSwapped(FSTOffset + 0x0, &name_offset, m_Wii) || + !m_rVolume->ReadSwapped(FSTOffset + 0x4, &offset, m_Wii) || + !m_rVolume->ReadSwapped(FSTOffset + 0x8, &size, m_Wii)) + return; + SFileInfo root = {name_offset, static_cast(offset) << shift, size}; - if (!root.IsDirectory()) - return; + if (!root.IsDirectory()) + return; - // 12 bytes (the size of a file entry) times 10 * 1024 * 1024 is 120 MiB, - // more than total RAM in a Wii. No file system should use anywhere near that much. - static const u32 ARBITRARY_FILE_SYSTEM_SIZE_LIMIT = 10 * 1024 * 1024; - if (root.m_FileSize > ARBITRARY_FILE_SYSTEM_SIZE_LIMIT) - { - // Without this check, Dolphin can crash by trying to allocate too much - // memory when loading the file systems of certain malformed disc images. + // 12 bytes (the size of a file entry) times 10 * 1024 * 1024 is 120 MiB, + // more than total RAM in a Wii. No file system should use anywhere near that much. + static const u32 ARBITRARY_FILE_SYSTEM_SIZE_LIMIT = 10 * 1024 * 1024; + if (root.m_FileSize > ARBITRARY_FILE_SYSTEM_SIZE_LIMIT) + { + // Without this check, Dolphin can crash by trying to allocate too much + // memory when loading the file systems of certain malformed disc images. - ERROR_LOG(DISCIO, "File system is abnormally large! Aborting loading"); - return; - } + ERROR_LOG(DISCIO, "File system is abnormally large! Aborting loading"); + return; + } - if (m_FileInfoVector.size()) - PanicAlert("Wtf?"); - u64 NameTableOffset = FSTOffset; + if (m_FileInfoVector.size()) + PanicAlert("Wtf?"); + u64 NameTableOffset = FSTOffset; - m_FileInfoVector.reserve((size_t)root.m_FileSize); - for (u32 i = 0; i < root.m_FileSize; i++) - { - const u64 read_offset = FSTOffset + (i * 0xC); - name_offset = 0; - m_rVolume->ReadSwapped(read_offset + 0x0, &name_offset, m_Wii); - offset = 0; - m_rVolume->ReadSwapped(read_offset + 0x4, &offset, m_Wii); - size = 0; - m_rVolume->ReadSwapped(read_offset + 0x8, &size, m_Wii); - m_FileInfoVector.emplace_back(name_offset, static_cast(offset) << shift, size); - NameTableOffset += 0xC; - } + m_FileInfoVector.reserve((size_t)root.m_FileSize); + for (u32 i = 0; i < root.m_FileSize; i++) + { + const u64 read_offset = FSTOffset + (i * 0xC); + name_offset = 0; + m_rVolume->ReadSwapped(read_offset + 0x0, &name_offset, m_Wii); + offset = 0; + m_rVolume->ReadSwapped(read_offset + 0x4, &offset, m_Wii); + size = 0; + m_rVolume->ReadSwapped(read_offset + 0x8, &size, m_Wii); + m_FileInfoVector.emplace_back(name_offset, static_cast(offset) << shift, size); + NameTableOffset += 0xC; + } - BuildFilenames(1, m_FileInfoVector.size(), "", NameTableOffset); + BuildFilenames(1, m_FileInfoVector.size(), "", NameTableOffset); } -size_t CFileSystemGCWii::BuildFilenames(const size_t _FirstIndex, const size_t _LastIndex, const std::string& _szDirectory, u64 _NameTableOffset) +size_t CFileSystemGCWii::BuildFilenames(const size_t _FirstIndex, const size_t _LastIndex, + const std::string& _szDirectory, u64 _NameTableOffset) { - size_t CurrentIndex = _FirstIndex; + size_t CurrentIndex = _FirstIndex; - while (CurrentIndex < _LastIndex) - { - SFileInfo& rFileInfo = m_FileInfoVector[CurrentIndex]; - u64 const uOffset = _NameTableOffset + (rFileInfo.m_NameOffset & 0xFFFFFF); - std::string const offset_str { GetStringFromOffset(uOffset) }; - bool const is_dir = rFileInfo.IsDirectory(); - rFileInfo.m_FullPath.reserve(_szDirectory.size() + offset_str.size()); + while (CurrentIndex < _LastIndex) + { + SFileInfo& rFileInfo = m_FileInfoVector[CurrentIndex]; + u64 const uOffset = _NameTableOffset + (rFileInfo.m_NameOffset & 0xFFFFFF); + std::string const offset_str{GetStringFromOffset(uOffset)}; + bool const is_dir = rFileInfo.IsDirectory(); + rFileInfo.m_FullPath.reserve(_szDirectory.size() + offset_str.size()); - rFileInfo.m_FullPath.append(_szDirectory.data(), _szDirectory.size()) - .append(offset_str.data(), offset_str.size()) - .append("/", size_t(is_dir)); + rFileInfo.m_FullPath.append(_szDirectory.data(), _szDirectory.size()) + .append(offset_str.data(), offset_str.size()) + .append("/", size_t(is_dir)); - if (!is_dir) - { - ++CurrentIndex; - continue; - } + if (!is_dir) + { + ++CurrentIndex; + continue; + } - // check next index - CurrentIndex = BuildFilenames(CurrentIndex + 1, (size_t) rFileInfo.m_FileSize, rFileInfo.m_FullPath, _NameTableOffset); - } + // check next index + CurrentIndex = BuildFilenames(CurrentIndex + 1, (size_t)rFileInfo.m_FileSize, + rFileInfo.m_FullPath, _NameTableOffset); + } - return CurrentIndex; + return CurrentIndex; } u32 CFileSystemGCWii::GetOffsetShift() const { - return m_Wii ? 2 : 0; + return m_Wii ? 2 : 0; } } // namespace diff --git a/Source/Core/DiscIO/FileSystemGCWii.h b/Source/Core/DiscIO/FileSystemGCWii.h index f9bfa5f5b1..0418557cde 100644 --- a/Source/Core/DiscIO/FileSystemGCWii.h +++ b/Source/Core/DiscIO/FileSystemGCWii.h @@ -13,38 +13,39 @@ namespace DiscIO { - class IVolume; class CFileSystemGCWii : public IFileSystem { public: - CFileSystemGCWii(const IVolume* _rVolume); - virtual ~CFileSystemGCWii(); + CFileSystemGCWii(const IVolume* _rVolume); + virtual ~CFileSystemGCWii(); - bool IsValid() const override { return m_Valid; } - u64 GetFileSize(const std::string& _rFullPath) override; - const std::vector& GetFileList() override; - const std::string GetFileName(u64 _Address) override; - u64 ReadFile(const std::string& _rFullPath, u8* _pBuffer, u64 _MaxBufferSize, u64 _OffsetInFile) override; - bool ExportFile(const std::string& _rFullPath, const std::string&_rExportFilename) override; - bool ExportApploader(const std::string& _rExportFolder) const override; - bool ExportDOL(const std::string& _rExportFolder) const override; - u64 GetBootDOLOffset() const override; - u32 GetBootDOLSize(u64 dol_offset) const override; + bool IsValid() const override { return m_Valid; } + u64 GetFileSize(const std::string& _rFullPath) override; + const std::vector& GetFileList() override; + const std::string GetFileName(u64 _Address) override; + u64 ReadFile(const std::string& _rFullPath, u8* _pBuffer, u64 _MaxBufferSize, + u64 _OffsetInFile) override; + bool ExportFile(const std::string& _rFullPath, const std::string& _rExportFilename) override; + bool ExportApploader(const std::string& _rExportFolder) const override; + bool ExportDOL(const std::string& _rExportFolder) const override; + u64 GetBootDOLOffset() const override; + u32 GetBootDOLSize(u64 dol_offset) const override; private: - bool m_Initialized; - bool m_Valid; - bool m_Wii; - std::vector m_FileInfoVector; + bool m_Initialized; + bool m_Valid; + bool m_Wii; + std::vector m_FileInfoVector; - std::string GetStringFromOffset(u64 _Offset) const; - const SFileInfo* FindFileInfo(const std::string& _rFullPath); - bool DetectFileSystem(); - void InitFileSystem(); - size_t BuildFilenames(const size_t _FirstIndex, const size_t _LastIndex, const std::string& _szDirectory, u64 _NameTableOffset); - u32 GetOffsetShift() const; + std::string GetStringFromOffset(u64 _Offset) const; + const SFileInfo* FindFileInfo(const std::string& _rFullPath); + bool DetectFileSystem(); + void InitFileSystem(); + size_t BuildFilenames(const size_t _FirstIndex, const size_t _LastIndex, + const std::string& _szDirectory, u64 _NameTableOffset); + u32 GetOffsetShift() const; }; -} // namespace +} // namespace diff --git a/Source/Core/DiscIO/Filesystem.cpp b/Source/Core/DiscIO/Filesystem.cpp index 3ca1f70f04..48da2b6e23 100644 --- a/Source/Core/DiscIO/Filesystem.cpp +++ b/Source/Core/DiscIO/Filesystem.cpp @@ -2,33 +2,31 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include #include "DiscIO/Filesystem.h" +#include #include "DiscIO/FileSystemGCWii.h" namespace DiscIO { - -IFileSystem::IFileSystem(const IVolume *_rVolume) - : m_rVolume(_rVolume) -{} - +IFileSystem::IFileSystem(const IVolume* _rVolume) : m_rVolume(_rVolume) +{ +} IFileSystem::~IFileSystem() -{} - +{ +} std::unique_ptr CreateFileSystem(const IVolume* volume) { - std::unique_ptr filesystem = std::make_unique(volume); + std::unique_ptr filesystem = std::make_unique(volume); - if (!filesystem) - return nullptr; + if (!filesystem) + return nullptr; - if (!filesystem->IsValid()) - filesystem.reset(); + if (!filesystem->IsValid()) + filesystem.reset(); - return filesystem; + return filesystem; } -} // namespace +} // namespace diff --git a/Source/Core/DiscIO/Filesystem.h b/Source/Core/DiscIO/Filesystem.h index 36fb9916a8..b168597c38 100644 --- a/Source/Core/DiscIO/Filesystem.h +++ b/Source/Core/DiscIO/Filesystem.h @@ -12,50 +12,48 @@ namespace DiscIO { - class IVolume; // file info of an FST entry struct SFileInfo { - u64 m_NameOffset = 0u; - u64 m_Offset = 0u; - u64 m_FileSize = 0u; - std::string m_FullPath; + u64 m_NameOffset = 0u; + u64 m_Offset = 0u; + u64 m_FileSize = 0u; + std::string m_FullPath; - bool IsDirectory() const { return (m_NameOffset & 0xFF000000) != 0; } + bool IsDirectory() const { return (m_NameOffset & 0xFF000000) != 0; } + SFileInfo(u64 name_offset, u64 offset, u64 filesize) + : m_NameOffset(name_offset), m_Offset(offset), m_FileSize(filesize) + { + } - SFileInfo(u64 name_offset, u64 offset, u64 filesize) : - m_NameOffset(name_offset), - m_Offset(offset), - m_FileSize(filesize) - { } - - SFileInfo (SFileInfo const&) = default; - SFileInfo () = default; + SFileInfo(SFileInfo const&) = default; + SFileInfo() = default; }; class IFileSystem { public: - IFileSystem(const IVolume *_rVolume); + IFileSystem(const IVolume* _rVolume); - virtual ~IFileSystem(); - virtual bool IsValid() const = 0; - virtual const std::vector& GetFileList() = 0; - virtual u64 GetFileSize(const std::string& _rFullPath) = 0; - virtual u64 ReadFile(const std::string& _rFullPath, u8* _pBuffer, u64 _MaxBufferSize, u64 _OffsetInFile = 0) = 0; - virtual bool ExportFile(const std::string& _rFullPath, const std::string& _rExportFilename) = 0; - virtual bool ExportApploader(const std::string& _rExportFolder) const = 0; - virtual bool ExportDOL(const std::string& _rExportFolder) const = 0; - virtual const std::string GetFileName(u64 _Address) = 0; - virtual u64 GetBootDOLOffset() const = 0; - virtual u32 GetBootDOLSize(u64 dol_offset) const = 0; + virtual ~IFileSystem(); + virtual bool IsValid() const = 0; + virtual const std::vector& GetFileList() = 0; + virtual u64 GetFileSize(const std::string& _rFullPath) = 0; + virtual u64 ReadFile(const std::string& _rFullPath, u8* _pBuffer, u64 _MaxBufferSize, + u64 _OffsetInFile = 0) = 0; + virtual bool ExportFile(const std::string& _rFullPath, const std::string& _rExportFilename) = 0; + virtual bool ExportApploader(const std::string& _rExportFolder) const = 0; + virtual bool ExportDOL(const std::string& _rExportFolder) const = 0; + virtual const std::string GetFileName(u64 _Address) = 0; + virtual u64 GetBootDOLOffset() const = 0; + virtual u32 GetBootDOLSize(u64 dol_offset) const = 0; protected: - const IVolume *m_rVolume; + const IVolume* m_rVolume; }; std::unique_ptr CreateFileSystem(const IVolume* volume); -} // namespace +} // namespace diff --git a/Source/Core/DiscIO/NANDContentLoader.cpp b/Source/Core/DiscIO/NANDContentLoader.cpp index b7f5deb9c1..36f672b026 100644 --- a/Source/Core/DiscIO/NANDContentLoader.cpp +++ b/Source/Core/DiscIO/NANDContentLoader.cpp @@ -9,19 +9,19 @@ #include #include #include +#include #include #include #include -#include #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" +#include "Common/Logging/Log.h" #include "Common/MathUtil.h" #include "Common/MsgHandler.h" #include "Common/NandPaths.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "DiscIO/NANDContentLoader.h" #include "DiscIO/Volume.h" @@ -29,132 +29,129 @@ namespace DiscIO { - CSharedContent::CSharedContent() { - UpdateLocation(); + UpdateLocation(); } void CSharedContent::UpdateLocation() { - m_Elements.clear(); - m_LastID = 0; - m_ContentMap = StringFromFormat("%s/shared1/content.map", File::GetUserPath(D_WIIROOT_IDX).c_str()); + m_Elements.clear(); + m_LastID = 0; + m_ContentMap = + StringFromFormat("%s/shared1/content.map", File::GetUserPath(D_WIIROOT_IDX).c_str()); - File::IOFile pFile(m_ContentMap, "rb"); - SElement Element; - while (pFile.ReadArray(&Element, 1)) - { - m_Elements.push_back(Element); - m_LastID++; - } + File::IOFile pFile(m_ContentMap, "rb"); + SElement Element; + while (pFile.ReadArray(&Element, 1)) + { + m_Elements.push_back(Element); + m_LastID++; + } } CSharedContent::~CSharedContent() -{} +{ +} std::string CSharedContent::GetFilenameFromSHA1(const u8* hash) { - for (auto& Element : m_Elements) - { - if (memcmp(hash, Element.SHA1Hash, 20) == 0) - { - return StringFromFormat("%s/shared1/%c%c%c%c%c%c%c%c.app", File::GetUserPath(D_WIIROOT_IDX).c_str(), - Element.FileName[0], Element.FileName[1], Element.FileName[2], Element.FileName[3], - Element.FileName[4], Element.FileName[5], Element.FileName[6], Element.FileName[7]); - } - } - return "unk"; + for (auto& Element : m_Elements) + { + if (memcmp(hash, Element.SHA1Hash, 20) == 0) + { + return StringFromFormat( + "%s/shared1/%c%c%c%c%c%c%c%c.app", File::GetUserPath(D_WIIROOT_IDX).c_str(), + Element.FileName[0], Element.FileName[1], Element.FileName[2], Element.FileName[3], + Element.FileName[4], Element.FileName[5], Element.FileName[6], Element.FileName[7]); + } + } + return "unk"; } std::string CSharedContent::AddSharedContent(const u8* hash) { - std::string filename = GetFilenameFromSHA1(hash); + std::string filename = GetFilenameFromSHA1(hash); - if (strcasecmp(filename.c_str(), "unk") == 0) - { - std::string id = StringFromFormat("%08x", m_LastID); - SElement Element; - memcpy(Element.FileName, id.c_str(), 8); - memcpy(Element.SHA1Hash, hash, 20); - m_Elements.push_back(Element); + if (strcasecmp(filename.c_str(), "unk") == 0) + { + std::string id = StringFromFormat("%08x", m_LastID); + SElement Element; + memcpy(Element.FileName, id.c_str(), 8); + memcpy(Element.SHA1Hash, hash, 20); + m_Elements.push_back(Element); - File::CreateFullPath(m_ContentMap); + File::CreateFullPath(m_ContentMap); - File::IOFile pFile(m_ContentMap, "ab"); - pFile.WriteArray(&Element, 1); + File::IOFile pFile(m_ContentMap, "ab"); + pFile.WriteArray(&Element, 1); - filename = StringFromFormat("%s/shared1/%s.app", File::GetUserPath(D_WIIROOT_IDX).c_str(), id.c_str()); - m_LastID++; - } + filename = + StringFromFormat("%s/shared1/%s.app", File::GetUserPath(D_WIIROOT_IDX).c_str(), id.c_str()); + m_LastID++; + } - return filename; + return filename; } void CNANDContentDataFile::EnsureOpen() { - if (!m_file) - m_file = std::make_unique(m_filename, "rb"); - else if (!m_file->IsOpen()) - m_file->Open(m_filename, "rb"); + if (!m_file) + m_file = std::make_unique(m_filename, "rb"); + else if (!m_file->IsOpen()) + m_file->Open(m_filename, "rb"); } void CNANDContentDataFile::Open() { - EnsureOpen(); + EnsureOpen(); } const std::vector CNANDContentDataFile::Get() { - std::vector result; - EnsureOpen(); - if (!m_file->IsGood()) - return result; + std::vector result; + EnsureOpen(); + if (!m_file->IsGood()) + return result; - u64 size = m_file->GetSize(); - if (size == 0) - return result; + u64 size = m_file->GetSize(); + if (size == 0) + return result; - result.resize(size); - m_file->ReadBytes(result.data(), result.size()); + result.resize(size); + m_file->ReadBytes(result.data(), result.size()); - return result; + return result; } bool CNANDContentDataFile::GetRange(u32 start, u32 size, u8* buffer) { - EnsureOpen(); - if (!m_file->IsGood()) - return false; + EnsureOpen(); + if (!m_file->IsGood()) + return false; - if (!m_file->Seek(start, SEEK_SET)) - return false; + if (!m_file->Seek(start, SEEK_SET)) + return false; - return m_file->ReadBytes(buffer, static_cast(size)); + return m_file->ReadBytes(buffer, static_cast(size)); } void CNANDContentDataFile::Close() { - if (m_file && m_file->IsOpen()) - m_file->Close(); + if (m_file && m_file->IsOpen()) + m_file->Close(); } - bool CNANDContentDataBuffer::GetRange(u32 start, u32 size, u8* buffer) { - if (start + size > m_buffer.size()) - return false; + if (start + size > m_buffer.size()) + return false; - std::copy(&m_buffer[start], &m_buffer[start + size], buffer); - return true; + std::copy(&m_buffer[start], &m_buffer[start + size], buffer); + return true; } - CNANDContentLoader::CNANDContentLoader(const std::string& content_name) - : m_Valid(false) - , m_IsWAD(false) - , m_TitleID(-1) - , m_IosVersion(0x09) - , m_BootIndex(-1) + : m_Valid(false), m_IsWAD(false), m_TitleID(-1), m_IosVersion(0x09), m_BootIndex(-1) { - m_Valid = Initialize(content_name); + m_Valid = Initialize(content_name); } CNANDContentLoader::~CNANDContentLoader() @@ -163,363 +160,373 @@ CNANDContentLoader::~CNANDContentLoader() const SNANDContent* CNANDContentLoader::GetContentByIndex(int index) const { - for (auto& Content : m_Content) - { - if (Content.m_Index == index) - { - return &Content; - } - } - return nullptr; + for (auto& Content : m_Content) + { + if (Content.m_Index == index) + { + return &Content; + } + } + return nullptr; } bool CNANDContentLoader::Initialize(const std::string& name) { - if (name.empty()) - return false; + if (name.empty()) + return false; - m_Path = name; + m_Path = name; - WiiWAD wad(name); - std::vector data_app; - std::vector tmd; - std::vector decrypted_title_key; + WiiWAD wad(name); + std::vector data_app; + std::vector tmd; + std::vector decrypted_title_key; - if (wad.IsValid()) - { - m_IsWAD = true; - m_Ticket = wad.GetTicket(); - decrypted_title_key = GetKeyFromTicket(m_Ticket); - tmd = wad.GetTMD(); - data_app = wad.GetDataApp(); - } - else - { - std::string tmd_filename(m_Path); + if (wad.IsValid()) + { + m_IsWAD = true; + m_Ticket = wad.GetTicket(); + decrypted_title_key = GetKeyFromTicket(m_Ticket); + tmd = wad.GetTMD(); + data_app = wad.GetDataApp(); + } + else + { + std::string tmd_filename(m_Path); - if (tmd_filename.back() == '/') - tmd_filename += "title.tmd"; - else - m_Path = tmd_filename.substr(0, tmd_filename.find("title.tmd")); + if (tmd_filename.back() == '/') + tmd_filename += "title.tmd"; + else + m_Path = tmd_filename.substr(0, tmd_filename.find("title.tmd")); - File::IOFile tmd_file(tmd_filename, "rb"); - if (!tmd_file) - { - WARN_LOG(DISCIO, "CreateFromDirectory: error opening %s", tmd_filename.c_str()); - return false; - } + File::IOFile tmd_file(tmd_filename, "rb"); + if (!tmd_file) + { + WARN_LOG(DISCIO, "CreateFromDirectory: error opening %s", tmd_filename.c_str()); + return false; + } - tmd.resize(static_cast(File::GetSize(tmd_filename))); - tmd_file.ReadBytes(tmd.data(), tmd.size()); - } + tmd.resize(static_cast(File::GetSize(tmd_filename))); + tmd_file.ReadBytes(tmd.data(), tmd.size()); + } - std::copy(&tmd[0], &tmd[TMD_HEADER_SIZE], m_TMDHeader); - std::copy(&tmd[0x180], &tmd[0x180 + TMD_VIEW_SIZE], m_TMDView); + std::copy(&tmd[0], &tmd[TMD_HEADER_SIZE], m_TMDHeader); + std::copy(&tmd[0x180], &tmd[0x180 + TMD_VIEW_SIZE], m_TMDView); - m_TitleVersion = Common::swap16(&tmd[0x01DC]); - m_NumEntries = Common::swap16(&tmd[0x01DE]); - m_BootIndex = Common::swap16(&tmd[0x01E0]); - m_TitleID = Common::swap64(&tmd[0x018C]); - m_IosVersion = Common::swap16(&tmd[0x018A]); - m_Country = static_cast(m_TitleID & 0xFF); + m_TitleVersion = Common::swap16(&tmd[0x01DC]); + m_NumEntries = Common::swap16(&tmd[0x01DE]); + m_BootIndex = Common::swap16(&tmd[0x01E0]); + m_TitleID = Common::swap64(&tmd[0x018C]); + m_IosVersion = Common::swap16(&tmd[0x018A]); + m_Country = static_cast(m_TitleID & 0xFF); - if (m_Country == 2) // SYSMENU - m_Country = GetSysMenuRegion(m_TitleVersion); + if (m_Country == 2) // SYSMENU + m_Country = GetSysMenuRegion(m_TitleVersion); - InitializeContentEntries(tmd, decrypted_title_key, data_app); - return true; + InitializeContentEntries(tmd, decrypted_title_key, data_app); + return true; } -void CNANDContentLoader::InitializeContentEntries(const std::vector& tmd, const std::vector& decrypted_title_key, const std::vector& data_app) +void CNANDContentLoader::InitializeContentEntries(const std::vector& tmd, + const std::vector& decrypted_title_key, + const std::vector& data_app) { - m_Content.resize(m_NumEntries); + m_Content.resize(m_NumEntries); - std::array iv; - u32 data_app_offset = 0; + std::array iv; + u32 data_app_offset = 0; - for (u32 i = 0; i < m_NumEntries; i++) - { - const u32 entry_offset = 0x24 * i; + for (u32 i = 0; i < m_NumEntries; i++) + { + const u32 entry_offset = 0x24 * i; - SNANDContent& content = m_Content[i]; - content.m_ContentID = Common::swap32(&tmd[entry_offset + 0x01E4]); - content.m_Index = Common::swap16(&tmd[entry_offset + 0x01E8]); - content.m_Type = Common::swap16(&tmd[entry_offset + 0x01EA]); - content.m_Size = static_cast(Common::swap64(&tmd[entry_offset + 0x01EC])); + SNANDContent& content = m_Content[i]; + content.m_ContentID = Common::swap32(&tmd[entry_offset + 0x01E4]); + content.m_Index = Common::swap16(&tmd[entry_offset + 0x01E8]); + content.m_Type = Common::swap16(&tmd[entry_offset + 0x01EA]); + content.m_Size = static_cast(Common::swap64(&tmd[entry_offset + 0x01EC])); - const auto header_begin = std::next(tmd.begin(), entry_offset + 0x01E4); - const auto header_end = std::next(header_begin, ArraySize(content.m_Header)); - std::copy(header_begin, header_end, content.m_Header); + const auto header_begin = std::next(tmd.begin(), entry_offset + 0x01E4); + const auto header_end = std::next(header_begin, ArraySize(content.m_Header)); + std::copy(header_begin, header_end, content.m_Header); - const auto hash_begin = std::next(tmd.begin(), entry_offset + 0x01F4); - const auto hash_end = std::next(hash_begin, ArraySize(content.m_SHA1Hash)); - std::copy(hash_begin, hash_end, content.m_SHA1Hash); + const auto hash_begin = std::next(tmd.begin(), entry_offset + 0x01F4); + const auto hash_end = std::next(hash_begin, ArraySize(content.m_SHA1Hash)); + std::copy(hash_begin, hash_end, content.m_SHA1Hash); - if (m_IsWAD) - { - u32 rounded_size = ROUND_UP(content.m_Size, 0x40); + if (m_IsWAD) + { + u32 rounded_size = ROUND_UP(content.m_Size, 0x40); - iv.fill(0); - std::copy(&tmd[entry_offset + 0x01E8], &tmd[entry_offset + 0x01E8 + 2], iv.begin()); + iv.fill(0); + std::copy(&tmd[entry_offset + 0x01E8], &tmd[entry_offset + 0x01E8 + 2], iv.begin()); - content.m_Data = std::make_unique(AESDecode(decrypted_title_key.data(), iv.data(), &data_app[data_app_offset], rounded_size)); + content.m_Data = std::make_unique(AESDecode( + decrypted_title_key.data(), iv.data(), &data_app[data_app_offset], rounded_size)); - data_app_offset += rounded_size; - continue; - } + data_app_offset += rounded_size; + continue; + } - std::string filename; - if (content.m_Type & 0x8000) // shared app - filename = CSharedContent::AccessInstance().GetFilenameFromSHA1(content.m_SHA1Hash); - else - filename = StringFromFormat("%s/%08x.app", m_Path.c_str(), content.m_ContentID); + std::string filename; + if (content.m_Type & 0x8000) // shared app + filename = CSharedContent::AccessInstance().GetFilenameFromSHA1(content.m_SHA1Hash); + else + filename = StringFromFormat("%s/%08x.app", m_Path.c_str(), content.m_ContentID); - content.m_Data = std::make_unique(filename); + content.m_Data = std::make_unique(filename); - // Be graceful about incorrect TMDs. - if (File::Exists(filename)) - content.m_Size = static_cast(File::GetSize(filename)); - } + // Be graceful about incorrect TMDs. + if (File::Exists(filename)) + content.m_Size = static_cast(File::GetSize(filename)); + } } std::vector CNANDContentLoader::AESDecode(const u8* key, u8* iv, const u8* src, u32 size) { - mbedtls_aes_context aes_ctx; - std::vector buffer(size); + mbedtls_aes_context aes_ctx; + std::vector buffer(size); - mbedtls_aes_setkey_dec(&aes_ctx, key, 128); - mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, size, iv, src, buffer.data()); + mbedtls_aes_setkey_dec(&aes_ctx, key, 128); + mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, size, iv, src, buffer.data()); - return buffer; + return buffer; } std::vector CNANDContentLoader::GetKeyFromTicket(const std::vector& ticket) { - const u8 common_key[16] = {0xeb,0xe4,0x2a,0x22,0x5e,0x85,0x93,0xe4,0x48,0xd9,0xc5,0x45,0x73,0x81,0xaa,0xf7}; - u8 iv[16] = {}; + const u8 common_key[16] = {0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4, + 0x48, 0xd9, 0xc5, 0x45, 0x73, 0x81, 0xaa, 0xf7}; + u8 iv[16] = {}; - std::copy(&ticket[0x01DC], &ticket[0x01DC + 8], iv); - return AESDecode(common_key, iv, &ticket[0x01BF], 16); + std::copy(&ticket[0x01DC], &ticket[0x01DC + 8], iv); + return AESDecode(common_key, iv, &ticket[0x01BF], 16); } - DiscIO::IVolume::ECountry CNANDContentLoader::GetCountry() const { - if (!IsValid()) - return DiscIO::IVolume::COUNTRY_UNKNOWN; + if (!IsValid()) + return DiscIO::IVolume::COUNTRY_UNKNOWN; - return CountrySwitch(m_Country); + return CountrySwitch(m_Country); } - CNANDContentManager::~CNANDContentManager() { } const CNANDContentLoader& CNANDContentManager::GetNANDLoader(const std::string& content_path) { - auto it = m_map.find(content_path); - if (it != m_map.end()) - return *it->second; - return *m_map.emplace_hint(it, std::make_pair(content_path, std::make_unique(content_path)))->second; + auto it = m_map.find(content_path); + if (it != m_map.end()) + return *it->second; + return *m_map + .emplace_hint(it, std::make_pair(content_path, + std::make_unique(content_path))) + ->second; } -const CNANDContentLoader& CNANDContentManager::GetNANDLoader(u64 title_id, Common::FromWhichRoot from) +const CNANDContentLoader& CNANDContentManager::GetNANDLoader(u64 title_id, + Common::FromWhichRoot from) { - std::string path = Common::GetTitleContentPath(title_id, from); - return GetNANDLoader(path); + std::string path = Common::GetTitleContentPath(title_id, from); + return GetNANDLoader(path); } bool CNANDContentManager::RemoveTitle(u64 title_id, Common::FromWhichRoot from) { - auto& loader = GetNANDLoader(title_id, from); - if (!loader.IsValid()) - return false; - loader.RemoveTitle(); - return GetNANDLoader(title_id, from).IsValid(); + auto& loader = GetNANDLoader(title_id, from); + if (!loader.IsValid()) + return false; + loader.RemoveTitle(); + return GetNANDLoader(title_id, from).IsValid(); } void CNANDContentManager::ClearCache() { - m_map.clear(); + m_map.clear(); } void CNANDContentLoader::RemoveTitle() const { - INFO_LOG(DISCIO, "RemoveTitle %08x/%08x", (u32)(m_TitleID >> 32), (u32)m_TitleID); - if (IsValid()) - { - // remove TMD? - for (u32 i = 0; i < m_NumEntries; i++) - { - if (!(m_Content[i].m_Type & 0x8000)) // skip shared apps - { - std::string filename = StringFromFormat("%s/%08x.app", m_Path.c_str(), m_Content[i].m_ContentID); - INFO_LOG(DISCIO, "Delete %s", filename.c_str()); - File::Delete(filename); - } - } - CNANDContentManager::Access().ClearCache(); // deletes 'this' - } + INFO_LOG(DISCIO, "RemoveTitle %08x/%08x", (u32)(m_TitleID >> 32), (u32)m_TitleID); + if (IsValid()) + { + // remove TMD? + for (u32 i = 0; i < m_NumEntries; i++) + { + if (!(m_Content[i].m_Type & 0x8000)) // skip shared apps + { + std::string filename = + StringFromFormat("%s/%08x.app", m_Path.c_str(), m_Content[i].m_ContentID); + INFO_LOG(DISCIO, "Delete %s", filename.c_str()); + File::Delete(filename); + } + } + CNANDContentManager::Access().ClearCache(); // deletes 'this' + } } cUIDsys::cUIDsys() { - UpdateLocation(); + UpdateLocation(); } void cUIDsys::UpdateLocation() { - m_Elements.clear(); - m_LastUID = 0x00001000; - m_UidSys = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/sys/uid.sys"; + m_Elements.clear(); + m_LastUID = 0x00001000; + m_UidSys = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/sys/uid.sys"; - File::IOFile pFile(m_UidSys, "rb"); - SElement Element; - while (pFile.ReadArray(&Element, 1)) - { - *(u32*)&(Element.UID) = Common::swap32(m_LastUID++); - m_Elements.push_back(Element); - } - pFile.Close(); + File::IOFile pFile(m_UidSys, "rb"); + SElement Element; + while (pFile.ReadArray(&Element, 1)) + { + *(u32*)&(Element.UID) = Common::swap32(m_LastUID++); + m_Elements.push_back(Element); + } + pFile.Close(); - if (m_Elements.empty()) - { - *(u64*)&(Element.titleID) = Common::swap64(TITLEID_SYSMENU); - *(u32*)&(Element.UID) = Common::swap32(m_LastUID++); + if (m_Elements.empty()) + { + *(u64*)&(Element.titleID) = Common::swap64(TITLEID_SYSMENU); + *(u32*)&(Element.UID) = Common::swap32(m_LastUID++); - File::CreateFullPath(m_UidSys); - pFile.Open(m_UidSys, "wb"); - if (!pFile.WriteArray(&Element, 1)) - ERROR_LOG(DISCIO, "Failed to write to %s", m_UidSys.c_str()); - } + File::CreateFullPath(m_UidSys); + pFile.Open(m_UidSys, "wb"); + if (!pFile.WriteArray(&Element, 1)) + ERROR_LOG(DISCIO, "Failed to write to %s", m_UidSys.c_str()); + } } cUIDsys::~cUIDsys() -{} +{ +} u32 cUIDsys::GetUIDFromTitle(u64 title_id) { - for (auto& Element : m_Elements) - { - if (Common::swap64(title_id) == *(u64*)&(Element.titleID)) - { - return Common::swap32(Element.UID); - } - } - return 0; + for (auto& Element : m_Elements) + { + if (Common::swap64(title_id) == *(u64*)&(Element.titleID)) + { + return Common::swap32(Element.UID); + } + } + return 0; } void cUIDsys::AddTitle(u64 title_id) { - if (GetUIDFromTitle(title_id)) - { - INFO_LOG(DISCIO, "Title %08x%08x, already exists in uid.sys", (u32)(title_id >> 32), (u32)title_id); - return; - } + if (GetUIDFromTitle(title_id)) + { + INFO_LOG(DISCIO, "Title %08x%08x, already exists in uid.sys", (u32)(title_id >> 32), + (u32)title_id); + return; + } - SElement Element; - *(u64*)&(Element.titleID) = Common::swap64(title_id); - *(u32*)&(Element.UID) = Common::swap32(m_LastUID++); - m_Elements.push_back(Element); + SElement Element; + *(u64*)&(Element.titleID) = Common::swap64(title_id); + *(u32*)&(Element.UID) = Common::swap32(m_LastUID++); + m_Elements.push_back(Element); - File::CreateFullPath(m_UidSys); - File::IOFile pFile(m_UidSys, "ab"); + File::CreateFullPath(m_UidSys); + File::IOFile pFile(m_UidSys, "ab"); - if (!pFile.WriteArray(&Element, 1)) - ERROR_LOG(DISCIO, "fwrite failed"); + if (!pFile.WriteArray(&Element, 1)) + ERROR_LOG(DISCIO, "fwrite failed"); } void cUIDsys::GetTitleIDs(std::vector& title_ids, bool owned) { - for (auto& Element : m_Elements) - { - if ((owned && Common::CheckTitleTIK(Common::swap64(Element.titleID), Common::FROM_SESSION_ROOT)) || - (!owned && Common::CheckTitleTMD(Common::swap64(Element.titleID), Common::FROM_SESSION_ROOT))) - title_ids.push_back(Common::swap64(Element.titleID)); - } + for (auto& Element : m_Elements) + { + if ((owned && + Common::CheckTitleTIK(Common::swap64(Element.titleID), Common::FROM_SESSION_ROOT)) || + (!owned && + Common::CheckTitleTMD(Common::swap64(Element.titleID), Common::FROM_SESSION_ROOT))) + title_ids.push_back(Common::swap64(Element.titleID)); + } } u64 CNANDContentManager::Install_WiiWAD(const std::string& filename) { - if (filename.find(".wad") == std::string::npos) - return 0; - const CNANDContentLoader& content_loader = GetNANDLoader(filename); - if (content_loader.IsValid() == false) - return 0; + if (filename.find(".wad") == std::string::npos) + return 0; + const CNANDContentLoader& content_loader = GetNANDLoader(filename); + if (content_loader.IsValid() == false) + return 0; - u64 title_id = content_loader.GetTitleID(); + u64 title_id = content_loader.GetTitleID(); - //copy WAD's TMD header and contents to content directory + // copy WAD's TMD header and contents to content directory - std::string content_path(Common::GetTitleContentPath(title_id, Common::FROM_CONFIGURED_ROOT)); - std::string tmd_filename(Common::GetTMDFileName(title_id, Common::FROM_CONFIGURED_ROOT)); - File::CreateFullPath(tmd_filename); + std::string content_path(Common::GetTitleContentPath(title_id, Common::FROM_CONFIGURED_ROOT)); + std::string tmd_filename(Common::GetTMDFileName(title_id, Common::FROM_CONFIGURED_ROOT)); + File::CreateFullPath(tmd_filename); - File::IOFile tmd_file(tmd_filename, "wb"); - if (!tmd_file) - { - PanicAlertT("WAD installation failed: error creating %s", tmd_filename.c_str()); - return 0; - } + File::IOFile tmd_file(tmd_filename, "wb"); + if (!tmd_file) + { + PanicAlertT("WAD installation failed: error creating %s", tmd_filename.c_str()); + return 0; + } - tmd_file.WriteBytes(content_loader.GetTMDHeader(), CNANDContentLoader::TMD_HEADER_SIZE); + tmd_file.WriteBytes(content_loader.GetTMDHeader(), CNANDContentLoader::TMD_HEADER_SIZE); - for (u32 i = 0; i < content_loader.GetContentSize(); i++) - { - const SNANDContent& content = content_loader.GetContent()[i]; + for (u32 i = 0; i < content_loader.GetContentSize(); i++) + { + const SNANDContent& content = content_loader.GetContent()[i]; - tmd_file.WriteBytes(content.m_Header, CNANDContentLoader::CONTENT_HEADER_SIZE); + tmd_file.WriteBytes(content.m_Header, CNANDContentLoader::CONTENT_HEADER_SIZE); - std::string app_filename; - if (content.m_Type & 0x8000) //shared - app_filename = CSharedContent::AccessInstance().AddSharedContent(content.m_SHA1Hash); - else - app_filename = StringFromFormat("%s%08x.app", content_path.c_str(), content.m_ContentID); + std::string app_filename; + if (content.m_Type & 0x8000) // shared + app_filename = CSharedContent::AccessInstance().AddSharedContent(content.m_SHA1Hash); + else + app_filename = StringFromFormat("%s%08x.app", content_path.c_str(), content.m_ContentID); - if (!File::Exists(app_filename)) - { - File::CreateFullPath(app_filename); - File::IOFile app_file(app_filename, "wb"); - if (!app_file) - { - PanicAlertT("WAD installation failed: error creating %s", app_filename.c_str()); - return 0; - } + if (!File::Exists(app_filename)) + { + File::CreateFullPath(app_filename); + File::IOFile app_file(app_filename, "wb"); + if (!app_file) + { + PanicAlertT("WAD installation failed: error creating %s", app_filename.c_str()); + return 0; + } - app_file.WriteBytes(content.m_Data->Get().data(), content.m_Size); - } - else - { - INFO_LOG(DISCIO, "Content %s already exists.", app_filename.c_str()); - } - } + app_file.WriteBytes(content.m_Data->Get().data(), content.m_Size); + } + else + { + INFO_LOG(DISCIO, "Content %s already exists.", app_filename.c_str()); + } + } - //Extract and copy WAD's ticket to ticket directory - if (!AddTicket(title_id, content_loader.GetTicket())) - { - PanicAlertT("WAD installation failed: error creating ticket"); - return 0; - } + // Extract and copy WAD's ticket to ticket directory + if (!AddTicket(title_id, content_loader.GetTicket())) + { + PanicAlertT("WAD installation failed: error creating ticket"); + return 0; + } - cUIDsys::AccessInstance().AddTitle(title_id); + cUIDsys::AccessInstance().AddTitle(title_id); - ClearCache(); + ClearCache(); - return title_id; + return title_id; } bool AddTicket(u64 title_id, const std::vector& ticket) { - std::string ticket_filename = Common::GetTicketFileName(title_id, Common::FROM_CONFIGURED_ROOT); - File::CreateFullPath(ticket_filename); + std::string ticket_filename = Common::GetTicketFileName(title_id, Common::FROM_CONFIGURED_ROOT); + File::CreateFullPath(ticket_filename); - File::IOFile ticket_file(ticket_filename, "wb"); - if (!ticket_file) - return false; + File::IOFile ticket_file(ticket_filename, "wb"); + if (!ticket_file) + return false; - return ticket_file.WriteBytes(ticket.data(), ticket.size()); + return ticket_file.WriteBytes(ticket.data(), ticket.size()); } -} // namespace end - +} // namespace end diff --git a/Source/Core/DiscIO/NANDContentLoader.h b/Source/Core/DiscIO/NANDContentLoader.h index 85b6de5117..f627db0de6 100644 --- a/Source/Core/DiscIO/NANDContentLoader.h +++ b/Source/Core/DiscIO/NANDContentLoader.h @@ -20,186 +20,197 @@ bool AddTicket(u64 title_id, const std::vector& ticket); class CNANDContentData { public: - virtual void Open() { }; - virtual const std::vector Get() = 0; - virtual bool GetRange(u32 start, u32 size, u8* buffer) = 0; - virtual void Close() { }; + virtual void Open(){}; + virtual const std::vector Get() = 0; + virtual bool GetRange(u32 start, u32 size, u8* buffer) = 0; + virtual void Close(){}; }; class CNANDContentDataFile final : public CNANDContentData { public: - CNANDContentDataFile(const std::string& filename) : m_filename(filename) { }; + CNANDContentDataFile(const std::string& filename) : m_filename(filename){}; + + void Open() override; + const std::vector Get() override; + bool GetRange(u32 start, u32 size, u8* buffer) override; + void Close() override; - void Open() override; - const std::vector Get() override; - bool GetRange(u32 start, u32 size, u8* buffer) override; - void Close() override; private: - void EnsureOpen(); + void EnsureOpen(); - const std::string m_filename; - std::unique_ptr m_file; + const std::string m_filename; + std::unique_ptr m_file; }; class CNANDContentDataBuffer final : public CNANDContentData { public: - CNANDContentDataBuffer(const std::vector& buffer) : m_buffer(buffer) { }; + CNANDContentDataBuffer(const std::vector& buffer) : m_buffer(buffer){}; + + const std::vector Get() override { return m_buffer; }; + bool GetRange(u32 start, u32 size, u8* buffer) override; - const std::vector Get() override { return m_buffer; }; - bool GetRange(u32 start, u32 size, u8* buffer) override; private: - const std::vector m_buffer; + const std::vector m_buffer; }; struct SNANDContent { - u32 m_ContentID; - u16 m_Index; - u16 m_Type; - u32 m_Size; - u8 m_SHA1Hash[20]; - u8 m_Header[36]; //all of the above + u32 m_ContentID; + u16 m_Index; + u16 m_Type; + u32 m_Size; + u8 m_SHA1Hash[20]; + u8 m_Header[36]; // all of the above - std::unique_ptr m_Data; + std::unique_ptr m_Data; }; // Instances of this class must be created by CNANDContentManager class CNANDContentLoader final { public: - CNANDContentLoader(const std::string& content_name); - virtual ~CNANDContentLoader(); + CNANDContentLoader(const std::string& content_name); + virtual ~CNANDContentLoader(); - bool IsValid() const { return m_Valid; } - void RemoveTitle() const; - u64 GetTitleID() const { return m_TitleID; } - u16 GetIosVersion() const { return m_IosVersion; } - u32 GetBootIndex() const { return m_BootIndex; } - size_t GetContentSize() const { return m_Content.size(); } - const SNANDContent* GetContentByIndex(int index) const; - const u8* GetTMDView() const { return m_TMDView; } - const u8* GetTMDHeader() const { return m_TMDHeader; } - const std::vector& GetTicket() const { return m_Ticket; } - - const std::vector& GetContent() const { return m_Content; } - - u16 GetTitleVersion() const { return m_TitleVersion; } - u16 GetNumEntries() const { return m_NumEntries; } - DiscIO::IVolume::ECountry GetCountry() const; - u8 GetCountryChar() const { return m_Country; } - - enum - { - TMD_VIEW_SIZE = 0x58, - TMD_HEADER_SIZE = 0x1E4, - CONTENT_HEADER_SIZE = 0x24, - TICKET_SIZE = 0x2A4 - }; + bool IsValid() const { return m_Valid; } + void RemoveTitle() const; + u64 GetTitleID() const { return m_TitleID; } + u16 GetIosVersion() const { return m_IosVersion; } + u32 GetBootIndex() const { return m_BootIndex; } + size_t GetContentSize() const { return m_Content.size(); } + const SNANDContent* GetContentByIndex(int index) const; + const u8* GetTMDView() const { return m_TMDView; } + const u8* GetTMDHeader() const { return m_TMDHeader; } + const std::vector& GetTicket() const { return m_Ticket; } + const std::vector& GetContent() const { return m_Content; } + u16 GetTitleVersion() const { return m_TitleVersion; } + u16 GetNumEntries() const { return m_NumEntries; } + DiscIO::IVolume::ECountry GetCountry() const; + u8 GetCountryChar() const { return m_Country; } + enum + { + TMD_VIEW_SIZE = 0x58, + TMD_HEADER_SIZE = 0x1E4, + CONTENT_HEADER_SIZE = 0x24, + TICKET_SIZE = 0x2A4 + }; private: - bool Initialize(const std::string& name); - void InitializeContentEntries(const std::vector& tmd, const std::vector& decrypted_title_key, const std::vector& data_app); + bool Initialize(const std::string& name); + void InitializeContentEntries(const std::vector& tmd, + const std::vector& decrypted_title_key, + const std::vector& data_app); - static std::vector AESDecode(const u8* key, u8* iv, const u8* src, u32 size); - static std::vector GetKeyFromTicket(const std::vector& ticket); + static std::vector AESDecode(const u8* key, u8* iv, const u8* src, u32 size); + static std::vector GetKeyFromTicket(const std::vector& ticket); - bool m_Valid; - bool m_IsWAD; - std::string m_Path; - u64 m_TitleID; - u16 m_IosVersion; - u32 m_BootIndex; - u16 m_NumEntries; - u16 m_TitleVersion; - u8 m_TMDView[TMD_VIEW_SIZE]; - u8 m_TMDHeader[TMD_HEADER_SIZE]; - std::vector m_Ticket; - u8 m_Country; + bool m_Valid; + bool m_IsWAD; + std::string m_Path; + u64 m_TitleID; + u16 m_IosVersion; + u32 m_BootIndex; + u16 m_NumEntries; + u16 m_TitleVersion; + u8 m_TMDView[TMD_VIEW_SIZE]; + u8 m_TMDHeader[TMD_HEADER_SIZE]; + std::vector m_Ticket; + u8 m_Country; - std::vector m_Content; + std::vector m_Content; }; - // we open the NAND Content files too often... let's cache them class CNANDContentManager { public: - static CNANDContentManager& Access() { static CNANDContentManager instance; return instance; } - u64 Install_WiiWAD(const std::string& fileName); + static CNANDContentManager& Access() + { + static CNANDContentManager instance; + return instance; + } + u64 Install_WiiWAD(const std::string& fileName); - const CNANDContentLoader& GetNANDLoader(const std::string& content_path); - const CNANDContentLoader& GetNANDLoader(u64 title_id, Common::FromWhichRoot from); - bool RemoveTitle(u64 title_id, Common::FromWhichRoot from); - void ClearCache(); + const CNANDContentLoader& GetNANDLoader(const std::string& content_path); + const CNANDContentLoader& GetNANDLoader(u64 title_id, Common::FromWhichRoot from); + bool RemoveTitle(u64 title_id, Common::FromWhichRoot from); + void ClearCache(); private: - CNANDContentManager() {} - ~CNANDContentManager(); + CNANDContentManager() {} + ~CNANDContentManager(); - CNANDContentManager(CNANDContentManager const&) = delete; - void operator=(CNANDContentManager const&) = delete; + CNANDContentManager(CNANDContentManager const&) = delete; + void operator=(CNANDContentManager const&) = delete; - std::unordered_map> m_map; + std::unordered_map> m_map; }; class CSharedContent { public: - static CSharedContent& AccessInstance() { static CSharedContent instance; return instance; } + static CSharedContent& AccessInstance() + { + static CSharedContent instance; + return instance; + } - std::string GetFilenameFromSHA1(const u8* hash); - std::string AddSharedContent(const u8* hash); - void UpdateLocation(); + std::string GetFilenameFromSHA1(const u8* hash); + std::string AddSharedContent(const u8* hash); + void UpdateLocation(); private: - CSharedContent(); - virtual ~CSharedContent(); + CSharedContent(); + virtual ~CSharedContent(); - CSharedContent(CSharedContent const&) = delete; - void operator=(CSharedContent const&) = delete; + CSharedContent(CSharedContent const&) = delete; + void operator=(CSharedContent const&) = delete; -#pragma pack(push,1) - struct SElement - { - u8 FileName[8]; - u8 SHA1Hash[20]; - }; +#pragma pack(push, 1) + struct SElement + { + u8 FileName[8]; + u8 SHA1Hash[20]; + }; #pragma pack(pop) - u32 m_LastID; - std::string m_ContentMap; - std::vector m_Elements; + u32 m_LastID; + std::string m_ContentMap; + std::vector m_Elements; }; class cUIDsys { public: - static cUIDsys& AccessInstance() { static cUIDsys instance; return instance; } + static cUIDsys& AccessInstance() + { + static cUIDsys instance; + return instance; + } - u32 GetUIDFromTitle(u64 title_id); - void AddTitle(u64 title_id); - void GetTitleIDs(std::vector& title_ids, bool owned = false); - void UpdateLocation(); + u32 GetUIDFromTitle(u64 title_id); + void AddTitle(u64 title_id); + void GetTitleIDs(std::vector& title_ids, bool owned = false); + void UpdateLocation(); private: - cUIDsys(); - virtual ~cUIDsys(); + cUIDsys(); + virtual ~cUIDsys(); - cUIDsys(cUIDsys const&) = delete; - void operator=(cUIDsys const&) = delete; + cUIDsys(cUIDsys const&) = delete; + void operator=(cUIDsys const&) = delete; -#pragma pack(push,1) - struct SElement - { - u8 titleID[8]; - u8 UID[4]; - }; +#pragma pack(push, 1) + struct SElement + { + u8 titleID[8]; + u8 UID[4]; + }; #pragma pack(pop) - u32 m_LastUID; - std::string m_UidSys; - std::vector m_Elements; + u32 m_LastUID; + std::string m_UidSys; + std::vector m_Elements; }; - } diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h index 0b7edf61fb..190376a19d 100644 --- a/Source/Core/DiscIO/Volume.h +++ b/Source/Core/DiscIO/Volume.h @@ -19,119 +19,119 @@ namespace DiscIO class IVolume { public: - // Increment CACHE_REVISION if the enums below are modified (ISOFile.cpp & GameFile.cpp) - enum EPlatform - { - GAMECUBE_DISC = 0, - WII_DISC, - WII_WAD, - ELF_DOL, - NUMBER_OF_PLATFORMS - }; + // Increment CACHE_REVISION if the enums below are modified (ISOFile.cpp & GameFile.cpp) + enum EPlatform + { + GAMECUBE_DISC = 0, + WII_DISC, + WII_WAD, + ELF_DOL, + NUMBER_OF_PLATFORMS + }; - enum ECountry - { - COUNTRY_EUROPE = 0, - COUNTRY_JAPAN, - COUNTRY_USA, - COUNTRY_AUSTRALIA, - COUNTRY_FRANCE, - COUNTRY_GERMANY, - COUNTRY_ITALY, - COUNTRY_KOREA, - COUNTRY_NETHERLANDS, - COUNTRY_RUSSIA, - COUNTRY_SPAIN, - COUNTRY_TAIWAN, - COUNTRY_WORLD, - COUNTRY_UNKNOWN, - NUMBER_OF_COUNTRIES - }; + enum ECountry + { + COUNTRY_EUROPE = 0, + COUNTRY_JAPAN, + COUNTRY_USA, + COUNTRY_AUSTRALIA, + COUNTRY_FRANCE, + COUNTRY_GERMANY, + COUNTRY_ITALY, + COUNTRY_KOREA, + COUNTRY_NETHERLANDS, + COUNTRY_RUSSIA, + COUNTRY_SPAIN, + COUNTRY_TAIWAN, + COUNTRY_WORLD, + COUNTRY_UNKNOWN, + NUMBER_OF_COUNTRIES + }; - // Languages 0 - 9 match the official Wii language numbering. - // Languages 1 - 6 match the official GC PAL languages 0 - 5. - enum ELanguage - { - LANGUAGE_JAPANESE = 0, - LANGUAGE_ENGLISH = 1, - LANGUAGE_GERMAN = 2, - LANGUAGE_FRENCH = 3, - LANGUAGE_SPANISH = 4, - LANGUAGE_ITALIAN = 5, - LANGUAGE_DUTCH = 6, - LANGUAGE_SIMPLIFIED_CHINESE = 7, - LANGUAGE_TRADITIONAL_CHINESE = 8, - LANGUAGE_KOREAN = 9, - LANGUAGE_UNKNOWN - }; + // Languages 0 - 9 match the official Wii language numbering. + // Languages 1 - 6 match the official GC PAL languages 0 - 5. + enum ELanguage + { + LANGUAGE_JAPANESE = 0, + LANGUAGE_ENGLISH = 1, + LANGUAGE_GERMAN = 2, + LANGUAGE_FRENCH = 3, + LANGUAGE_SPANISH = 4, + LANGUAGE_ITALIAN = 5, + LANGUAGE_DUTCH = 6, + LANGUAGE_SIMPLIFIED_CHINESE = 7, + LANGUAGE_TRADITIONAL_CHINESE = 8, + LANGUAGE_KOREAN = 9, + LANGUAGE_UNKNOWN + }; - IVolume() {} - virtual ~IVolume() {} + IVolume() {} + virtual ~IVolume() {} + // decrypt parameter must be false if not reading a Wii disc + virtual bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt) const = 0; + template + bool ReadSwapped(u64 offset, T* buffer, bool decrypt) const + { + T temp; + if (!Read(offset, sizeof(T), reinterpret_cast(&temp), decrypt)) + return false; + *buffer = Common::FromBigEndian(temp); + return true; + } - // decrypt parameter must be false if not reading a Wii disc - virtual bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt) const = 0; - template - bool ReadSwapped(u64 offset, T* buffer, bool decrypt) const - { - T temp; - if (!Read(offset, sizeof(T), reinterpret_cast(&temp), decrypt)) - return false; - *buffer = Common::FromBigEndian(temp); - return true; - } + virtual bool GetTitleID(u64*) const { return false; } + virtual std::vector GetTMD() const { return {}; } + virtual std::string GetUniqueID() const = 0; + virtual std::string GetMakerID() const = 0; + virtual u16 GetRevision() const = 0; + virtual std::string GetInternalName() const = 0; + virtual std::map GetNames(bool prefer_long) const = 0; + virtual std::map GetDescriptions() const + { + return std::map(); + } + virtual std::string GetCompany() const { return std::string(); } + virtual std::vector GetBanner(int* width, int* height) const = 0; + virtual u64 GetFSTSize() const = 0; + virtual std::string GetApploaderDate() const = 0; + // 0 is the first disc, 1 is the second disc + virtual u8 GetDiscNumber() const { return 0; } + virtual EPlatform GetVolumeType() const = 0; + virtual bool SupportsIntegrityCheck() const { return false; } + virtual bool CheckIntegrity() const { return false; } + virtual bool ChangePartition(u64 offset) { return false; } + virtual ECountry GetCountry() const = 0; + virtual BlobType GetBlobType() const = 0; + // Size of virtual disc (not always accurate) + virtual u64 GetSize() const = 0; + // Size on disc (compressed size) + virtual u64 GetRawSize() const = 0; - virtual bool GetTitleID(u64*) const { return false; } - virtual std::vector GetTMD() const { return {}; } - virtual std::string GetUniqueID() const = 0; - virtual std::string GetMakerID() const = 0; - virtual u16 GetRevision() const = 0; - virtual std::string GetInternalName() const = 0; - virtual std::map GetNames(bool prefer_long) const = 0; - virtual std::map GetDescriptions() const { return std::map(); } - virtual std::string GetCompany() const { return std::string(); } - virtual std::vector GetBanner(int* width, int* height) const = 0; - virtual u64 GetFSTSize() const = 0; - virtual std::string GetApploaderDate() const = 0; - // 0 is the first disc, 1 is the second disc - virtual u8 GetDiscNumber() const { return 0; } - - virtual EPlatform GetVolumeType() const = 0; - virtual bool SupportsIntegrityCheck() const { return false; } - virtual bool CheckIntegrity() const { return false; } - virtual bool ChangePartition(u64 offset) { return false; } - - virtual ECountry GetCountry() const = 0; - virtual BlobType GetBlobType() const = 0; - // Size of virtual disc (not always accurate) - virtual u64 GetSize() const = 0; - // Size on disc (compressed size) - virtual u64 GetRawSize() const = 0; - - static std::vector GetWiiBanner(int* width, int* height, u64 title_id); + static std::vector GetWiiBanner(int* width, int* height, u64 title_id); protected: - template - std::string DecodeString(const char(&data)[N]) const - { - // strnlen to trim NULLs - std::string string(data, strnlen(data, sizeof(data))); + template + std::string DecodeString(const char (&data)[N]) const + { + // strnlen to trim NULLs + std::string string(data, strnlen(data, sizeof(data))); - // There don't seem to be any GC discs with the country set to Taiwan... - // But maybe they would use Shift_JIS if they existed? Not sure - bool use_shift_jis = (COUNTRY_JAPAN == GetCountry() || COUNTRY_TAIWAN == GetCountry()); + // There don't seem to be any GC discs with the country set to Taiwan... + // But maybe they would use Shift_JIS if they existed? Not sure + bool use_shift_jis = (COUNTRY_JAPAN == GetCountry() || COUNTRY_TAIWAN == GetCountry()); - if (use_shift_jis) - return SHIFTJISToUTF8(string); - else - return CP1252ToUTF8(string); - } + if (use_shift_jis) + return SHIFTJISToUTF8(string); + else + return CP1252ToUTF8(string); + } - static std::map ReadWiiNames(const std::vector& data); + static std::map ReadWiiNames(const std::vector& data); - static const size_t NUMBER_OF_LANGUAGES = 10; - static const size_t NAME_STRING_LENGTH = 42; - static const size_t NAME_BYTES_LENGTH = NAME_STRING_LENGTH * sizeof(u16); - static const size_t NAMES_TOTAL_BYTES = NAME_BYTES_LENGTH * NUMBER_OF_LANGUAGES; + static const size_t NUMBER_OF_LANGUAGES = 10; + static const size_t NAME_STRING_LENGTH = 42; + static const size_t NAME_BYTES_LENGTH = NAME_STRING_LENGTH * sizeof(u16); + static const size_t NAMES_TOTAL_BYTES = NAME_BYTES_LENGTH * NUMBER_OF_LANGUAGES; }; // Generic Switch function for all volumes @@ -139,4 +139,4 @@ IVolume::ECountry CountrySwitch(u8 country_code); u8 GetSysMenuRegion(u16 _TitleVersion); std::string GetCompanyFromID(const std::string& company_id); -} // namespace +} // namespace diff --git a/Source/Core/DiscIO/VolumeCommon.cpp b/Source/Core/DiscIO/VolumeCommon.cpp index 39fac55997..24f395733a 100644 --- a/Source/Core/DiscIO/VolumeCommon.cpp +++ b/Source/Core/DiscIO/VolumeCommon.cpp @@ -12,13 +12,12 @@ #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/StringUtil.h" #include "Common/Logging/Log.h" +#include "Common/StringUtil.h" #include "DiscIO/Volume.h" namespace DiscIO { - static const unsigned int WII_BANNER_WIDTH = 192; static const unsigned int WII_BANNER_HEIGHT = 64; static const unsigned int WII_BANNER_SIZE = WII_BANNER_WIDTH * WII_BANNER_HEIGHT * 2; @@ -26,542 +25,569 @@ static const unsigned int WII_BANNER_OFFSET = 0xA0; std::vector IVolume::GetWiiBanner(int* width, int* height, u64 title_id) { - *width = 0; - *height = 0; + *width = 0; + *height = 0; - std::string file_name = StringFromFormat("%s/title/%08x/%08x/data/banner.bin", - File::GetUserPath(D_WIIROOT_IDX).c_str(), (u32)(title_id >> 32), (u32)title_id); - if (!File::Exists(file_name)) - return std::vector(); + std::string file_name = StringFromFormat("%s/title/%08x/%08x/data/banner.bin", + File::GetUserPath(D_WIIROOT_IDX).c_str(), + (u32)(title_id >> 32), (u32)title_id); + if (!File::Exists(file_name)) + return std::vector(); - if (File::GetSize(file_name) < WII_BANNER_OFFSET + WII_BANNER_SIZE) - return std::vector(); + if (File::GetSize(file_name) < WII_BANNER_OFFSET + WII_BANNER_SIZE) + return std::vector(); - File::IOFile file(file_name, "rb"); - if (!file.Seek(WII_BANNER_OFFSET, SEEK_SET)) - return std::vector(); + File::IOFile file(file_name, "rb"); + if (!file.Seek(WII_BANNER_OFFSET, SEEK_SET)) + return std::vector(); - std::vector banner_file(WII_BANNER_SIZE); - if (!file.ReadBytes(banner_file.data(), banner_file.size())) - return std::vector(); + std::vector banner_file(WII_BANNER_SIZE); + if (!file.ReadBytes(banner_file.data(), banner_file.size())) + return std::vector(); - std::vector image_buffer(WII_BANNER_WIDTH * WII_BANNER_HEIGHT); - ColorUtil::decode5A3image(image_buffer.data(), (u16*)banner_file.data(), WII_BANNER_WIDTH, WII_BANNER_HEIGHT); + std::vector image_buffer(WII_BANNER_WIDTH * WII_BANNER_HEIGHT); + ColorUtil::decode5A3image(image_buffer.data(), (u16*)banner_file.data(), WII_BANNER_WIDTH, + WII_BANNER_HEIGHT); - *width = WII_BANNER_WIDTH; - *height = WII_BANNER_HEIGHT; - return image_buffer; + *width = WII_BANNER_WIDTH; + *height = WII_BANNER_HEIGHT; + return image_buffer; } std::map IVolume::ReadWiiNames(const std::vector& data) { - std::map names; - for (size_t i = 0; i < NUMBER_OF_LANGUAGES; ++i) - { - size_t name_start = NAME_BYTES_LENGTH * i; - size_t name_end = name_start + NAME_BYTES_LENGTH; - if (data.size() >= name_end) - { - u16* temp = (u16*)(data.data() + name_start); - std::wstring out_temp(NAME_STRING_LENGTH, '\0'); - std::transform(temp, temp + out_temp.size(), out_temp.begin(), (u16(&)(u16))Common::swap16); - out_temp.erase(std::find(out_temp.begin(), out_temp.end(), 0x00), out_temp.end()); - std::string name = UTF16ToUTF8(out_temp); - if (!name.empty()) - names[(IVolume::ELanguage)i] = name; - } - } - return names; + std::map names; + for (size_t i = 0; i < NUMBER_OF_LANGUAGES; ++i) + { + size_t name_start = NAME_BYTES_LENGTH * i; + size_t name_end = name_start + NAME_BYTES_LENGTH; + if (data.size() >= name_end) + { + u16* temp = (u16*)(data.data() + name_start); + std::wstring out_temp(NAME_STRING_LENGTH, '\0'); + std::transform(temp, temp + out_temp.size(), out_temp.begin(), (u16(&)(u16))Common::swap16); + out_temp.erase(std::find(out_temp.begin(), out_temp.end(), 0x00), out_temp.end()); + std::string name = UTF16ToUTF8(out_temp); + if (!name.empty()) + names[(IVolume::ELanguage)i] = name; + } + } + return names; } // Increment CACHE_REVISION if the code below is modified (ISOFile.cpp & GameFile.cpp) IVolume::ECountry CountrySwitch(u8 country_code) { - switch (country_code) - { - // Worldwide - case 'A': - return IVolume::COUNTRY_WORLD; + switch (country_code) + { + // Worldwide + case 'A': + return IVolume::COUNTRY_WORLD; - // PAL - case 'D': - return IVolume::COUNTRY_GERMANY; + // PAL + case 'D': + return IVolume::COUNTRY_GERMANY; - case 'X': // Used by a couple PAL games - case 'Y': // German, French - case 'L': // Japanese import to PAL regions - case 'M': // Japanese import to PAL regions - case 'P': - return IVolume::COUNTRY_EUROPE; + case 'X': // Used by a couple PAL games + case 'Y': // German, French + case 'L': // Japanese import to PAL regions + case 'M': // Japanese import to PAL regions + case 'P': + return IVolume::COUNTRY_EUROPE; - case 'U': - return IVolume::COUNTRY_AUSTRALIA; + case 'U': + return IVolume::COUNTRY_AUSTRALIA; - case 'F': - return IVolume::COUNTRY_FRANCE; + case 'F': + return IVolume::COUNTRY_FRANCE; - case 'I': - return IVolume::COUNTRY_ITALY; + case 'I': + return IVolume::COUNTRY_ITALY; - case 'H': - return IVolume::COUNTRY_NETHERLANDS; + case 'H': + return IVolume::COUNTRY_NETHERLANDS; - case 'R': - return IVolume::COUNTRY_RUSSIA; + case 'R': + return IVolume::COUNTRY_RUSSIA; - case 'S': - return IVolume::COUNTRY_SPAIN; + case 'S': + return IVolume::COUNTRY_SPAIN; - // NTSC - case 'E': - case 'N': // Japanese import to USA and other NTSC regions - case 'Z': // Prince of Persia - The Forgotten Sands (Wii) - case 'B': // Ufouria: The Saga (Virtual Console) - return IVolume::COUNTRY_USA; + // NTSC + case 'E': + case 'N': // Japanese import to USA and other NTSC regions + case 'Z': // Prince of Persia - The Forgotten Sands (Wii) + case 'B': // Ufouria: The Saga (Virtual Console) + return IVolume::COUNTRY_USA; - case 'J': - return IVolume::COUNTRY_JAPAN; + case 'J': + return IVolume::COUNTRY_JAPAN; - case 'K': - case 'Q': // Korea with Japanese language - case 'T': // Korea with English language - return IVolume::COUNTRY_KOREA; + case 'K': + case 'Q': // Korea with Japanese language + case 'T': // Korea with English language + return IVolume::COUNTRY_KOREA; - case 'W': - return IVolume::COUNTRY_TAIWAN; + case 'W': + return IVolume::COUNTRY_TAIWAN; - default: - if (country_code > 'A') // Silently ignore IOS wads - WARN_LOG(DISCIO, "Unknown Country Code! %c", country_code); - return IVolume::COUNTRY_UNKNOWN; - } + default: + if (country_code > 'A') // Silently ignore IOS wads + WARN_LOG(DISCIO, "Unknown Country Code! %c", country_code); + return IVolume::COUNTRY_UNKNOWN; + } } u8 GetSysMenuRegion(u16 _TitleVersion) { - switch (_TitleVersion) - { - case 128: case 192: case 224: case 256: - case 288: case 352: case 384: case 416: - case 448: case 480: case 512: - return 'J'; - case 97: case 193: case 225: case 257: - case 289: case 353: case 385: case 417: - case 449: case 481: case 513: - return 'E'; - case 130: case 162: case 194: case 226: - case 258: case 290: case 354: case 386: - case 418: case 450: case 482: case 514: - return 'P'; - case 326: case 390: case 454: case 486: - case 518: - return 'K'; - default: - return 'A'; - } + switch (_TitleVersion) + { + case 128: + case 192: + case 224: + case 256: + case 288: + case 352: + case 384: + case 416: + case 448: + case 480: + case 512: + return 'J'; + case 97: + case 193: + case 225: + case 257: + case 289: + case 353: + case 385: + case 417: + case 449: + case 481: + case 513: + return 'E'; + case 130: + case 162: + case 194: + case 226: + case 258: + case 290: + case 354: + case 386: + case 418: + case 450: + case 482: + case 514: + return 'P'; + case 326: + case 390: + case 454: + case 486: + case 518: + return 'K'; + default: + return 'A'; + } } std::string GetCompanyFromID(const std::string& company_id) { - static const std::map companies = - { - { "01", "Nintendo" }, - { "02", "Rocket Games / Ajinomoto" }, - { "03", "Imagineer-Zoom" }, - { "04", "Gray Matter" }, - { "05", "Zamuse" }, - { "06", "Falcom" }, - { "07", "Enix" }, - { "08", "Capcom" }, - { "09", "Hot B Co." }, - { "0A", "Jaleco" }, - { "0B", "Coconuts Japan" }, - { "0C", "Coconuts Japan / GX Media" }, - { "0D", "Micronet" }, - { "0E", "Technos" }, - { "0F", "Mebio Software" }, - { "0G", "Shouei System" }, - { "0H", "Starfish" }, - { "0J", "Mitsui Fudosan / Dentsu" }, - { "0L", "Warashi Inc." }, - { "0N", "Nowpro" }, - { "0P", "Game Village" }, - { "0Q", "IE Institute" }, - { "12", "Infocom" }, - { "13", "Electronic Arts Japan" }, - { "15", "Cobra Team" }, - { "16", "Human / Field" }, - { "17", "KOEI" }, - { "18", "Hudson Soft" }, - { "19", "S.C.P." }, - { "1A", "Yanoman" }, - { "1C", "Tecmo Products" }, - { "1D", "Japan Glary Business" }, - { "1E", "Forum / OpenSystem" }, - { "1F", "Virgin Games (Japan)" }, - { "1G", "SMDE" }, - { "1J", "Daikokudenki" }, - { "1P", "Creatures Inc." }, - { "1Q", "TDK Deep Impresion" }, - { "20", "Zoo" }, - { "21", "Sunsoft / Tokai Engineering" }, - { "22", "Planning Office Wada / VR1 Japan" }, - { "23", "Micro World" }, - { "25", "San-X" }, - { "26", "Enix" }, - { "27", "Loriciel / Electro Brain" }, - { "28", "Kemco Japan" }, - { "29", "Seta" }, - { "2A", "Culture Brain" }, - { "2C", "Palsoft" }, - { "2D", "Visit Co., Ltd." }, - { "2E", "Intec" }, - { "2F", "System Sacom" }, - { "2G", "Poppo" }, - { "2H", "Ubisoft Japan" }, - { "2J", "Media Works" }, - { "2K", "NEC InterChannel" }, - { "2L", "Tam" }, - { "2M", "Jordan" }, - { "2N", "Smilesoft / Rocket" }, - { "2Q", "Mediakite" }, - { "30", "Viacom" }, - { "31", "Carrozzeria" }, - { "32", "Dynamic" }, - { "34", "Magifact" }, - { "35", "Hect" }, - { "36", "Codemasters" }, - { "37", "Taito / GAGA Communications" }, - { "38", "Laguna" }, - { "39", "Telstar / Event / Taito " }, - { "3B", "Arcade Zone Ltd." }, - { "3C", "Entertainment International / Empire Software" }, - { "3D", "Loriciel" }, - { "3E", "Gremlin Graphics" }, - { "3F", "K. Amusement Leasing Co." }, - { "40", "Seika Corp." }, - { "41", "Ubisoft Entertainment" }, - { "42", "Sunsoft US" }, - { "44", "Life Fitness" }, - { "46", "System 3" }, - { "47", "Spectrum Holobyte" }, - { "49", "IREM" }, - { "4B", "Raya Systems" }, - { "4C", "Renovation Products" }, - { "4D", "Malibu Games" }, - { "4F", "Eidos" }, - { "4G", "Playmates Interactive" }, - { "4J", "Fox Interactive" }, - { "4K", "Time Warner Interactive" }, - { "4Q", "Disney Interactive" }, - { "4S", "Black Pearl" }, - { "4U", "Advanced Productions" }, - { "4X", "GT Interactive" }, - { "4Y", "Rare" }, - { "4Z", "Crave Entertainment" }, - { "50", "Absolute Entertainment" }, - { "51", "Acclaim" }, - { "52", "Activision" }, - { "53", "American Sammy" }, - { "54", "Take 2 Interactive / GameTek" }, - { "55", "Hi Tech" }, - { "56", "LJN Ltd." }, - { "58", "Mattel" }, - { "5A", "Mindscape / Red Orb Entertainment" }, - { "5B", "Romstar" }, - { "5C", "Taxan" }, - { "5D", "Midway / Tradewest" }, - { "5F", "American Softworks" }, - { "5G", "Majesco Sales Inc." }, - { "5H", "3DO" }, - { "5K", "Hasbro" }, - { "5L", "NewKidCo" }, - { "5M", "Telegames" }, - { "5N", "Metro3D" }, - { "5P", "Vatical Entertainment" }, - { "5Q", "LEGO Media" }, - { "5S", "Xicat Interactive" }, - { "5T", "Cryo Interactive" }, - { "5W", "Red Storm Entertainment" }, - { "5X", "Microids" }, - { "5Z", "Data Design / Conspiracy / Swing" }, - { "60", "Titus" }, - { "61", "Virgin Interactive" }, - { "62", "Maxis" }, - { "64", "LucasArts Entertainment" }, - { "67", "Ocean" }, - { "68", "Bethesda Softworks" }, - { "69", "Electronic Arts" }, - { "6B", "Laser Beam" }, - { "6E", "Elite Systems" }, - { "6F", "Electro Brain" }, - { "6G", "The Learning Company" }, - { "6H", "BBC" }, - { "6J", "Software 2000" }, - { "6K", "UFO Interactive Games" }, - { "6L", "BAM! Entertainment" }, - { "6M", "Studio 3" }, - { "6Q", "Classified Games" }, - { "6S", "TDK Mediactive" }, - { "6U", "DreamCatcher" }, - { "6V", "JoWood Produtions" }, - { "6W", "Sega" }, - { "6X", "Wannado Edition" }, - { "6Y", "LSP (Light & Shadow Prod.)" }, - { "6Z", "ITE Media" }, - { "70", "Atari (Infogrames)" }, - { "71", "Interplay" }, - { "72", "JVC (US)" }, - { "73", "Parker Brothers" }, - { "75", "Sales Curve (Storm / SCI)" }, - { "78", "THQ" }, - { "79", "Accolade" }, - { "7A", "Triffix Entertainment" }, - { "7C", "Microprose Software" }, - { "7D", "Sierra / Universal Interactive" }, - { "7F", "Kemco" }, - { "7G", "Rage Software" }, - { "7H", "Encore" }, - { "7J", "Zoo" }, - { "7K", "Kiddinx" }, - { "7L", "Simon & Schuster Interactive" }, - { "7M", "Asmik Ace Entertainment Inc." }, - { "7N", "Empire Interactive" }, - { "7Q", "Jester Interactive" }, - { "7S", "Rockstar Games" }, - { "7T", "Scholastic" }, - { "7U", "Ignition Entertainment" }, - { "7V", "Summitsoft" }, - { "7W", "Stadlbauer" }, - { "80", "Misawa" }, - { "81", "Teichiku" }, - { "82", "Namco Ltd." }, - { "83", "LOZC" }, - { "84", "KOEI" }, - { "86", "Tokuma Shoten Intermedia" }, - { "87", "Tsukuda Original" }, - { "88", "DATAM-Polystar" }, - { "8B", "Bullet-Proof Software" }, - { "8C", "Vic Tokai Inc." }, - { "8E", "Character Soft" }, - { "8F", "I'Max" }, - { "8G", "Saurus" }, - { "8J", "General Entertainment" }, - { "8N", "Success" }, - { "8P", "Sega Japan" }, - { "90", "Takara Amusement" }, - { "91", "Chunsoft" }, - { "92", "Video System / Mc O' River" }, - { "93", "BEC" }, - { "95", "Varie" }, - { "96", "Yonezawa / S'pal" }, - { "97", "Kaneko" }, - { "99", "Marvelous Entertainment" }, - { "9A", "Nichibutsu / Nihon Bussan" }, - { "9B", "Tecmo" }, - { "9C", "Imagineer" }, - { "9F", "Nova" }, - { "9G", "Take2 / Den'Z / Global Star" }, - { "9H", "Bottom Up" }, - { "9J", "Technical Group Laboratory" }, - { "9L", "Hasbro Japan" }, - { "9N", "Marvelous Entertainment" }, - { "9P", "Keynet Inc." }, - { "9Q", "Hands-On Entertainment" }, - { "A0", "Telenet" }, - { "A1", "Hori" }, - { "A4", "Konami" }, - { "A5", "K. Amusement Leasing Co." }, - { "A6", "Kawada" }, - { "A7", "Takara" }, - { "A9", "Technos Japan Corp." }, - { "AA", "JVC / Victor" }, - { "AC", "Toei Animation" }, - { "AD", "Toho" }, - { "AF", "Namco" }, - { "AG", "Media Rings Corporation" }, - { "AH", "J-Wing" }, - { "AJ", "Pioneer LDC" }, - { "AK", "KID" }, - { "AL", "Mediafactory" }, - { "AP", "Infogrames / Hudson" }, - { "AQ", "Kiratto Ludic Inc." }, - { "B0", "Acclaim Japan" }, - { "B1", "ASCII" }, - { "B2", "Bandai" }, - { "B4", "Enix" }, - { "B6", "HAL Laboratory" }, - { "B7", "SNK" }, - { "B9", "Pony Canyon" }, - { "BA", "Culture Brain" }, - { "BB", "Sunsoft" }, - { "BC", "Toshiba EMI" }, - { "BD", "Sony Imagesoft" }, - { "BF", "Sammy" }, - { "BG", "Magical" }, - { "BH", "Visco" }, - { "BJ", "Compile" }, - { "BL", "MTO Inc." }, - { "BN", "Sunrise Interactive" }, - { "BP", "Global A Entertainment" }, - { "BQ", "Fuuki" }, - { "C0", "Taito" }, - { "C2", "Kemco" }, - { "C3", "Square" }, - { "C4", "Tokuma Shoten" }, - { "C5", "Data East" }, - { "C6", "Tonkin House / Tokyo Shoseki" }, - { "C8", "Koei" }, - { "CA", "Konami / Ultra / Palcom" }, - { "CB", "NTVIC / VAP" }, - { "CC", "Use Co., Ltd." }, - { "CD", "Meldac" }, - { "CE", "Pony Canyon / FCI " }, - { "CF", "Angel / Sotsu Agency / Sunrise" }, - { "CG", "Yumedia / Aroma Co., Ltd" }, - { "CJ", "Boss" }, - { "CK", "Axela / Crea-Tech" }, - { "CL", "Sekaibunka-Sha / Sumire Kobo / Marigul Management Inc." }, - { "CM", "Konami Computer Entertainment Osaka" }, - { "CN", "NEC Interchannel" }, - { "CP", "Enterbrain" }, - { "CQ", "From Software" }, - { "D0", "Taito / Disco" }, - { "D1", "Sofel" }, - { "D2", "Quest / Bothtec" }, - { "D3", "Sigma" }, - { "D4", "Ask Kodansha" }, - { "D6", "Naxat" }, - { "D7", "Copya System" }, - { "D8", "Capcom Co., Ltd." }, - { "D9", "Banpresto" }, - { "DA", "Tomy" }, - { "DB", "LJN Japan" }, - { "DD", "NCS" }, - { "DE", "Human Entertainment" }, - { "DF", "Altron" }, - { "DG", "Jaleco" }, - { "DH", "Gaps Inc." }, - { "DN", "Elf" }, - { "DQ", "Compile Heart" }, - { "E0", "Jaleco" }, - { "E2", "Yutaka" }, - { "E3", "Varie" }, - { "E4", "T&E Soft" }, - { "E5", "Epoch" }, - { "E7", "Athena" }, - { "E8", "Asmik" }, - { "E9", "Natsume" }, - { "EA", "King Records" }, - { "EB", "Atlus" }, - { "EC", "Epic / Sony Records" }, - { "EE", "Information Global Service" }, - { "EG", "Chatnoir" }, - { "EH", "Right Stuff" }, - { "EL", "Spike" }, - { "EM", "Konami Computer Entertainment Tokyo" }, - { "EN", "Alphadream Corporation" }, - { "EP", "Sting" }, - { "ES", "Star-Fish" }, - { "F0", "A Wave" }, - { "F1", "Motown Software" }, - { "F2", "Left Field Entertainment" }, - { "F3", "Extreme Ent. Grp." }, - { "F4", "TecMagik" }, - { "F9", "Cybersoft" }, - { "FB", "Psygnosis" }, - { "FE", "Davidson / Western Tech." }, - { "FK", "The Game Factory" }, - { "FL", "Hip Games" }, - { "FM", "Aspyr" }, - { "FP", "Mastiff" }, - { "FQ", "iQue" }, - { "FR", "Digital Tainment Pool" }, - { "FS", "XS Games / Jack Of All Games" }, - { "FT", "Daiwon" }, - { "G0", "Alpha Unit" }, - { "G1", "PCCW Japan" }, - { "G2", "Yuke's Media Creations" }, - { "G4", "KiKi Co., Ltd." }, - { "G5", "Open Sesame Inc." }, - { "G6", "Sims" }, - { "G7", "Broccoli" }, - { "G8", "Avex" }, - { "G9", "D3 Publisher" }, - { "GB", "Konami Computer Entertainment Japan" }, - { "GD", "Square-Enix" }, - { "GE", "KSG" }, - { "GF", "Micott & Basara Inc." }, - { "GH", "Orbital Media" }, - { "GJ", "Detn8 Games" }, - { "GL", "Gameloft / Ubisoft" }, - { "GM", "Gamecock Media Group" }, - { "GN", "Oxygen Games" }, - { "GT", "505 Games" }, - { "GY", "The Game Factory" }, - { "H1", "Treasure" }, - { "H2", "Aruze" }, - { "H3", "Ertain" }, - { "H4", "SNK Playmore" }, - { "HF", "Level-5" }, - { "HJ", "Genius Products" }, - { "HY", "Reef Entertainment" }, - { "HZ", "Nordcurrent" }, - { "IH", "Yojigen" }, - { "J9", "AQ Interactive" }, - { "JF", "Arc System Works" }, - { "JJ", "Deep Silver" }, - { "JW", "Atari" }, - { "K6", "Nihon System" }, - { "KB", "NIS America" }, - { "KM", "Deep Silver" }, - { "KP", "Purple Hills" }, - { "LH", "Trend Verlag / East Entertainment" }, - { "LT", "Legacy Interactive" }, - { "MJ", "Mumbo Jumbo" }, - { "MR", "Mindscape" }, - { "MS", "Milestone / UFO Interactive" }, - { "MT", "Blast!" }, - { "N9", "Terabox" }, - { "NG", "Nordic Games" }, - { "NK", "Neko Entertainment / Diffusion / Naps team" }, - { "NP", "Nobilis" }, - { "NQ", "Namco Bandai" }, - { "NR", "Data Design / Destineer Studios" }, - { "NS", "NIS America"}, - { "PL", "Playlogic" }, - { "QC", "Kadokawa Shoten"}, - { "RM", "Rondomedia" }, - { "RS", "Warner Bros. Interactive Entertainment Inc." }, - { "RT", "RTL Games" }, - { "RW", "RealNetworks" }, - { "S5", "Southpeak Interactive" }, - { "SP", "Blade Interactive Studios" }, - { "SV", "SevenGames" }, - { "SZ", "Storm City" }, - { "TK", "Tasuke / Works" }, - { "TV", "Tivola" }, - { "UG", "Metro 3D / Data Design" }, - { "VN", "Valcon Games" }, - { "VP", "Virgin Play" }, - { "VZ", "Little Orbit" }, - { "WR", "Warner Bros. Interactive Entertainment Inc." }, - { "XJ", "Xseed Games" }, - { "XS", "Aksys Games" }, - { "YT", "Valcon Games" }, - { "Z4", "Ntreev Soft" }, - { "ZA", "WBA Interactive" }, - { "ZH", "Internal Engine" }, - { "ZS", "Zinkia" }, - { "ZW", "Judo Baby" }, - { "ZX", "Topware Interactive" } - }; + static const std::map companies = { + {"01", "Nintendo"}, + {"02", "Rocket Games / Ajinomoto"}, + {"03", "Imagineer-Zoom"}, + {"04", "Gray Matter"}, + {"05", "Zamuse"}, + {"06", "Falcom"}, + {"07", "Enix"}, + {"08", "Capcom"}, + {"09", "Hot B Co."}, + {"0A", "Jaleco"}, + {"0B", "Coconuts Japan"}, + {"0C", "Coconuts Japan / GX Media"}, + {"0D", "Micronet"}, + {"0E", "Technos"}, + {"0F", "Mebio Software"}, + {"0G", "Shouei System"}, + {"0H", "Starfish"}, + {"0J", "Mitsui Fudosan / Dentsu"}, + {"0L", "Warashi Inc."}, + {"0N", "Nowpro"}, + {"0P", "Game Village"}, + {"0Q", "IE Institute"}, + {"12", "Infocom"}, + {"13", "Electronic Arts Japan"}, + {"15", "Cobra Team"}, + {"16", "Human / Field"}, + {"17", "KOEI"}, + {"18", "Hudson Soft"}, + {"19", "S.C.P."}, + {"1A", "Yanoman"}, + {"1C", "Tecmo Products"}, + {"1D", "Japan Glary Business"}, + {"1E", "Forum / OpenSystem"}, + {"1F", "Virgin Games (Japan)"}, + {"1G", "SMDE"}, + {"1J", "Daikokudenki"}, + {"1P", "Creatures Inc."}, + {"1Q", "TDK Deep Impresion"}, + {"20", "Zoo"}, + {"21", "Sunsoft / Tokai Engineering"}, + {"22", "Planning Office Wada / VR1 Japan"}, + {"23", "Micro World"}, + {"25", "San-X"}, + {"26", "Enix"}, + {"27", "Loriciel / Electro Brain"}, + {"28", "Kemco Japan"}, + {"29", "Seta"}, + {"2A", "Culture Brain"}, + {"2C", "Palsoft"}, + {"2D", "Visit Co., Ltd."}, + {"2E", "Intec"}, + {"2F", "System Sacom"}, + {"2G", "Poppo"}, + {"2H", "Ubisoft Japan"}, + {"2J", "Media Works"}, + {"2K", "NEC InterChannel"}, + {"2L", "Tam"}, + {"2M", "Jordan"}, + {"2N", "Smilesoft / Rocket"}, + {"2Q", "Mediakite"}, + {"30", "Viacom"}, + {"31", "Carrozzeria"}, + {"32", "Dynamic"}, + {"34", "Magifact"}, + {"35", "Hect"}, + {"36", "Codemasters"}, + {"37", "Taito / GAGA Communications"}, + {"38", "Laguna"}, + {"39", "Telstar / Event / Taito "}, + {"3B", "Arcade Zone Ltd."}, + {"3C", "Entertainment International / Empire Software"}, + {"3D", "Loriciel"}, + {"3E", "Gremlin Graphics"}, + {"3F", "K. Amusement Leasing Co."}, + {"40", "Seika Corp."}, + {"41", "Ubisoft Entertainment"}, + {"42", "Sunsoft US"}, + {"44", "Life Fitness"}, + {"46", "System 3"}, + {"47", "Spectrum Holobyte"}, + {"49", "IREM"}, + {"4B", "Raya Systems"}, + {"4C", "Renovation Products"}, + {"4D", "Malibu Games"}, + {"4F", "Eidos"}, + {"4G", "Playmates Interactive"}, + {"4J", "Fox Interactive"}, + {"4K", "Time Warner Interactive"}, + {"4Q", "Disney Interactive"}, + {"4S", "Black Pearl"}, + {"4U", "Advanced Productions"}, + {"4X", "GT Interactive"}, + {"4Y", "Rare"}, + {"4Z", "Crave Entertainment"}, + {"50", "Absolute Entertainment"}, + {"51", "Acclaim"}, + {"52", "Activision"}, + {"53", "American Sammy"}, + {"54", "Take 2 Interactive / GameTek"}, + {"55", "Hi Tech"}, + {"56", "LJN Ltd."}, + {"58", "Mattel"}, + {"5A", "Mindscape / Red Orb Entertainment"}, + {"5B", "Romstar"}, + {"5C", "Taxan"}, + {"5D", "Midway / Tradewest"}, + {"5F", "American Softworks"}, + {"5G", "Majesco Sales Inc."}, + {"5H", "3DO"}, + {"5K", "Hasbro"}, + {"5L", "NewKidCo"}, + {"5M", "Telegames"}, + {"5N", "Metro3D"}, + {"5P", "Vatical Entertainment"}, + {"5Q", "LEGO Media"}, + {"5S", "Xicat Interactive"}, + {"5T", "Cryo Interactive"}, + {"5W", "Red Storm Entertainment"}, + {"5X", "Microids"}, + {"5Z", "Data Design / Conspiracy / Swing"}, + {"60", "Titus"}, + {"61", "Virgin Interactive"}, + {"62", "Maxis"}, + {"64", "LucasArts Entertainment"}, + {"67", "Ocean"}, + {"68", "Bethesda Softworks"}, + {"69", "Electronic Arts"}, + {"6B", "Laser Beam"}, + {"6E", "Elite Systems"}, + {"6F", "Electro Brain"}, + {"6G", "The Learning Company"}, + {"6H", "BBC"}, + {"6J", "Software 2000"}, + {"6K", "UFO Interactive Games"}, + {"6L", "BAM! Entertainment"}, + {"6M", "Studio 3"}, + {"6Q", "Classified Games"}, + {"6S", "TDK Mediactive"}, + {"6U", "DreamCatcher"}, + {"6V", "JoWood Produtions"}, + {"6W", "Sega"}, + {"6X", "Wannado Edition"}, + {"6Y", "LSP (Light & Shadow Prod.)"}, + {"6Z", "ITE Media"}, + {"70", "Atari (Infogrames)"}, + {"71", "Interplay"}, + {"72", "JVC (US)"}, + {"73", "Parker Brothers"}, + {"75", "Sales Curve (Storm / SCI)"}, + {"78", "THQ"}, + {"79", "Accolade"}, + {"7A", "Triffix Entertainment"}, + {"7C", "Microprose Software"}, + {"7D", "Sierra / Universal Interactive"}, + {"7F", "Kemco"}, + {"7G", "Rage Software"}, + {"7H", "Encore"}, + {"7J", "Zoo"}, + {"7K", "Kiddinx"}, + {"7L", "Simon & Schuster Interactive"}, + {"7M", "Asmik Ace Entertainment Inc."}, + {"7N", "Empire Interactive"}, + {"7Q", "Jester Interactive"}, + {"7S", "Rockstar Games"}, + {"7T", "Scholastic"}, + {"7U", "Ignition Entertainment"}, + {"7V", "Summitsoft"}, + {"7W", "Stadlbauer"}, + {"80", "Misawa"}, + {"81", "Teichiku"}, + {"82", "Namco Ltd."}, + {"83", "LOZC"}, + {"84", "KOEI"}, + {"86", "Tokuma Shoten Intermedia"}, + {"87", "Tsukuda Original"}, + {"88", "DATAM-Polystar"}, + {"8B", "Bullet-Proof Software"}, + {"8C", "Vic Tokai Inc."}, + {"8E", "Character Soft"}, + {"8F", "I'Max"}, + {"8G", "Saurus"}, + {"8J", "General Entertainment"}, + {"8N", "Success"}, + {"8P", "Sega Japan"}, + {"90", "Takara Amusement"}, + {"91", "Chunsoft"}, + {"92", "Video System / Mc O' River"}, + {"93", "BEC"}, + {"95", "Varie"}, + {"96", "Yonezawa / S'pal"}, + {"97", "Kaneko"}, + {"99", "Marvelous Entertainment"}, + {"9A", "Nichibutsu / Nihon Bussan"}, + {"9B", "Tecmo"}, + {"9C", "Imagineer"}, + {"9F", "Nova"}, + {"9G", "Take2 / Den'Z / Global Star"}, + {"9H", "Bottom Up"}, + {"9J", "Technical Group Laboratory"}, + {"9L", "Hasbro Japan"}, + {"9N", "Marvelous Entertainment"}, + {"9P", "Keynet Inc."}, + {"9Q", "Hands-On Entertainment"}, + {"A0", "Telenet"}, + {"A1", "Hori"}, + {"A4", "Konami"}, + {"A5", "K. Amusement Leasing Co."}, + {"A6", "Kawada"}, + {"A7", "Takara"}, + {"A9", "Technos Japan Corp."}, + {"AA", "JVC / Victor"}, + {"AC", "Toei Animation"}, + {"AD", "Toho"}, + {"AF", "Namco"}, + {"AG", "Media Rings Corporation"}, + {"AH", "J-Wing"}, + {"AJ", "Pioneer LDC"}, + {"AK", "KID"}, + {"AL", "Mediafactory"}, + {"AP", "Infogrames / Hudson"}, + {"AQ", "Kiratto Ludic Inc."}, + {"B0", "Acclaim Japan"}, + {"B1", "ASCII"}, + {"B2", "Bandai"}, + {"B4", "Enix"}, + {"B6", "HAL Laboratory"}, + {"B7", "SNK"}, + {"B9", "Pony Canyon"}, + {"BA", "Culture Brain"}, + {"BB", "Sunsoft"}, + {"BC", "Toshiba EMI"}, + {"BD", "Sony Imagesoft"}, + {"BF", "Sammy"}, + {"BG", "Magical"}, + {"BH", "Visco"}, + {"BJ", "Compile"}, + {"BL", "MTO Inc."}, + {"BN", "Sunrise Interactive"}, + {"BP", "Global A Entertainment"}, + {"BQ", "Fuuki"}, + {"C0", "Taito"}, + {"C2", "Kemco"}, + {"C3", "Square"}, + {"C4", "Tokuma Shoten"}, + {"C5", "Data East"}, + {"C6", "Tonkin House / Tokyo Shoseki"}, + {"C8", "Koei"}, + {"CA", "Konami / Ultra / Palcom"}, + {"CB", "NTVIC / VAP"}, + {"CC", "Use Co., Ltd."}, + {"CD", "Meldac"}, + {"CE", "Pony Canyon / FCI "}, + {"CF", "Angel / Sotsu Agency / Sunrise"}, + {"CG", "Yumedia / Aroma Co., Ltd"}, + {"CJ", "Boss"}, + {"CK", "Axela / Crea-Tech"}, + {"CL", "Sekaibunka-Sha / Sumire Kobo / Marigul Management Inc."}, + {"CM", "Konami Computer Entertainment Osaka"}, + {"CN", "NEC Interchannel"}, + {"CP", "Enterbrain"}, + {"CQ", "From Software"}, + {"D0", "Taito / Disco"}, + {"D1", "Sofel"}, + {"D2", "Quest / Bothtec"}, + {"D3", "Sigma"}, + {"D4", "Ask Kodansha"}, + {"D6", "Naxat"}, + {"D7", "Copya System"}, + {"D8", "Capcom Co., Ltd."}, + {"D9", "Banpresto"}, + {"DA", "Tomy"}, + {"DB", "LJN Japan"}, + {"DD", "NCS"}, + {"DE", "Human Entertainment"}, + {"DF", "Altron"}, + {"DG", "Jaleco"}, + {"DH", "Gaps Inc."}, + {"DN", "Elf"}, + {"DQ", "Compile Heart"}, + {"E0", "Jaleco"}, + {"E2", "Yutaka"}, + {"E3", "Varie"}, + {"E4", "T&E Soft"}, + {"E5", "Epoch"}, + {"E7", "Athena"}, + {"E8", "Asmik"}, + {"E9", "Natsume"}, + {"EA", "King Records"}, + {"EB", "Atlus"}, + {"EC", "Epic / Sony Records"}, + {"EE", "Information Global Service"}, + {"EG", "Chatnoir"}, + {"EH", "Right Stuff"}, + {"EL", "Spike"}, + {"EM", "Konami Computer Entertainment Tokyo"}, + {"EN", "Alphadream Corporation"}, + {"EP", "Sting"}, + {"ES", "Star-Fish"}, + {"F0", "A Wave"}, + {"F1", "Motown Software"}, + {"F2", "Left Field Entertainment"}, + {"F3", "Extreme Ent. Grp."}, + {"F4", "TecMagik"}, + {"F9", "Cybersoft"}, + {"FB", "Psygnosis"}, + {"FE", "Davidson / Western Tech."}, + {"FK", "The Game Factory"}, + {"FL", "Hip Games"}, + {"FM", "Aspyr"}, + {"FP", "Mastiff"}, + {"FQ", "iQue"}, + {"FR", "Digital Tainment Pool"}, + {"FS", "XS Games / Jack Of All Games"}, + {"FT", "Daiwon"}, + {"G0", "Alpha Unit"}, + {"G1", "PCCW Japan"}, + {"G2", "Yuke's Media Creations"}, + {"G4", "KiKi Co., Ltd."}, + {"G5", "Open Sesame Inc."}, + {"G6", "Sims"}, + {"G7", "Broccoli"}, + {"G8", "Avex"}, + {"G9", "D3 Publisher"}, + {"GB", "Konami Computer Entertainment Japan"}, + {"GD", "Square-Enix"}, + {"GE", "KSG"}, + {"GF", "Micott & Basara Inc."}, + {"GH", "Orbital Media"}, + {"GJ", "Detn8 Games"}, + {"GL", "Gameloft / Ubisoft"}, + {"GM", "Gamecock Media Group"}, + {"GN", "Oxygen Games"}, + {"GT", "505 Games"}, + {"GY", "The Game Factory"}, + {"H1", "Treasure"}, + {"H2", "Aruze"}, + {"H3", "Ertain"}, + {"H4", "SNK Playmore"}, + {"HF", "Level-5"}, + {"HJ", "Genius Products"}, + {"HY", "Reef Entertainment"}, + {"HZ", "Nordcurrent"}, + {"IH", "Yojigen"}, + {"J9", "AQ Interactive"}, + {"JF", "Arc System Works"}, + {"JJ", "Deep Silver"}, + {"JW", "Atari"}, + {"K6", "Nihon System"}, + {"KB", "NIS America"}, + {"KM", "Deep Silver"}, + {"KP", "Purple Hills"}, + {"LH", "Trend Verlag / East Entertainment"}, + {"LT", "Legacy Interactive"}, + {"MJ", "Mumbo Jumbo"}, + {"MR", "Mindscape"}, + {"MS", "Milestone / UFO Interactive"}, + {"MT", "Blast!"}, + {"N9", "Terabox"}, + {"NG", "Nordic Games"}, + {"NK", "Neko Entertainment / Diffusion / Naps team"}, + {"NP", "Nobilis"}, + {"NQ", "Namco Bandai"}, + {"NR", "Data Design / Destineer Studios"}, + {"NS", "NIS America"}, + {"PL", "Playlogic"}, + {"QC", "Kadokawa Shoten"}, + {"RM", "Rondomedia"}, + {"RS", "Warner Bros. Interactive Entertainment Inc."}, + {"RT", "RTL Games"}, + {"RW", "RealNetworks"}, + {"S5", "Southpeak Interactive"}, + {"SP", "Blade Interactive Studios"}, + {"SV", "SevenGames"}, + {"SZ", "Storm City"}, + {"TK", "Tasuke / Works"}, + {"TV", "Tivola"}, + {"UG", "Metro 3D / Data Design"}, + {"VN", "Valcon Games"}, + {"VP", "Virgin Play"}, + {"VZ", "Little Orbit"}, + {"WR", "Warner Bros. Interactive Entertainment Inc."}, + {"XJ", "Xseed Games"}, + {"XS", "Aksys Games"}, + {"YT", "Valcon Games"}, + {"Z4", "Ntreev Soft"}, + {"ZA", "WBA Interactive"}, + {"ZH", "Internal Engine"}, + {"ZS", "Zinkia"}, + {"ZW", "Judo Baby"}, + {"ZX", "Topware Interactive"}}; - auto iterator = companies.find(company_id); - if (iterator != companies.end()) - return iterator->second; - else - return ""; + auto iterator = companies.find(company_id); + if (iterator != companies.end()) + return iterator->second; + else + return ""; } - } diff --git a/Source/Core/DiscIO/VolumeCreator.cpp b/Source/Core/DiscIO/VolumeCreator.cpp index a5cd74cb23..365032d280 100644 --- a/Source/Core/DiscIO/VolumeCreator.cpp +++ b/Source/Core/DiscIO/VolumeCreator.cpp @@ -12,8 +12,8 @@ #include #include "Common/CommonTypes.h" -#include "Common/StringUtil.h" #include "Common/Logging/Log.h" +#include "Common/StringUtil.h" #include "DiscIO/Blob.h" #include "DiscIO/Volume.h" #include "DiscIO/VolumeCreator.h" @@ -22,192 +22,197 @@ #include "DiscIO/VolumeWad.h" #include "DiscIO/VolumeWiiCrypted.h" - namespace DiscIO { enum EDiscType { - DISC_TYPE_UNK, - DISC_TYPE_WII, - DISC_TYPE_WII_CONTAINER, - DISC_TYPE_GC, - DISC_TYPE_WAD + DISC_TYPE_UNK, + DISC_TYPE_WII, + DISC_TYPE_WII_CONTAINER, + DISC_TYPE_GC, + DISC_TYPE_WAD }; -static const unsigned char s_master_key[16] = { - 0xeb,0xe4,0x2a,0x22,0x5e,0x85,0x93,0xe4, - 0x48,0xd9,0xc5,0x45,0x73,0x81,0xaa,0xf7 -}; +static const unsigned char s_master_key[16] = {0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4, + 0x48, 0xd9, 0xc5, 0x45, 0x73, 0x81, 0xaa, 0xf7}; static const unsigned char s_master_key_korean[16] = { - 0x63,0xb8,0x2b,0xb4,0xf4,0x61,0x4e,0x2e, - 0x13,0xf2,0xfe,0xfb,0xba,0x4c,0x9b,0x7e -}; + 0x63, 0xb8, 0x2b, 0xb4, 0xf4, 0x61, 0x4e, 0x2e, 0x13, 0xf2, 0xfe, 0xfb, 0xba, 0x4c, 0x9b, 0x7e}; -static std::unique_ptr CreateVolumeFromCryptedWiiImage(std::unique_ptr reader, u32 partition_group, u32 volume_type, u32 volume_number); +static std::unique_ptr CreateVolumeFromCryptedWiiImage(std::unique_ptr reader, + u32 partition_group, + u32 volume_type, u32 volume_number); EDiscType GetDiscType(IBlobReader& _rReader); -std::unique_ptr CreateVolumeFromFilename(const std::string& filename, u32 partition_group, u32 volume_number) +std::unique_ptr CreateVolumeFromFilename(const std::string& filename, u32 partition_group, + u32 volume_number) { - std::unique_ptr reader(CreateBlobReader(filename)); - if (reader == nullptr) - return nullptr; + std::unique_ptr reader(CreateBlobReader(filename)); + if (reader == nullptr) + return nullptr; - switch (GetDiscType(*reader)) - { - case DISC_TYPE_WII: - case DISC_TYPE_GC: - return std::make_unique(std::move(reader)); + switch (GetDiscType(*reader)) + { + case DISC_TYPE_WII: + case DISC_TYPE_GC: + return std::make_unique(std::move(reader)); - case DISC_TYPE_WAD: - return std::make_unique(std::move(reader)); + case DISC_TYPE_WAD: + return std::make_unique(std::move(reader)); - case DISC_TYPE_WII_CONTAINER: - return CreateVolumeFromCryptedWiiImage(std::move(reader), partition_group, 0, volume_number); + case DISC_TYPE_WII_CONTAINER: + return CreateVolumeFromCryptedWiiImage(std::move(reader), partition_group, 0, volume_number); - case DISC_TYPE_UNK: - default: - std::string name, extension; - SplitPath(filename, nullptr, &name, &extension); - name += extension; - NOTICE_LOG(DISCIO, "%s does not have the Magic word for a gcm, wiidisc or wad file\n" - "Set Log Verbosity to Warning and attempt to load the game again to view the values", name.c_str()); - } + case DISC_TYPE_UNK: + default: + std::string name, extension; + SplitPath(filename, nullptr, &name, &extension); + name += extension; + NOTICE_LOG(DISCIO, + "%s does not have the Magic word for a gcm, wiidisc or wad file\n" + "Set Log Verbosity to Warning and attempt to load the game again to view the values", + name.c_str()); + } - return nullptr; + return nullptr; } -std::unique_ptr CreateVolumeFromDirectory(const std::string& directory, bool is_wii, const std::string& apploader, const std::string& dol) +std::unique_ptr CreateVolumeFromDirectory(const std::string& directory, bool is_wii, + const std::string& apploader, + const std::string& dol) { - if (CVolumeDirectory::IsValidDirectory(directory)) - return std::make_unique(directory, is_wii, apploader, dol); + if (CVolumeDirectory::IsValidDirectory(directory)) + return std::make_unique(directory, is_wii, apploader, dol); - return nullptr; + return nullptr; } void VolumeKeyForPartition(IBlobReader& _rReader, u64 offset, u8* VolumeKey) { - u8 SubKey[16]; - _rReader.Read(offset + 0x1bf, 16, SubKey); + u8 SubKey[16]; + _rReader.Read(offset + 0x1bf, 16, SubKey); - u8 IV[16]; - memset(IV, 0, 16); - _rReader.Read(offset + 0x44c, 8, IV); + u8 IV[16]; + memset(IV, 0, 16); + _rReader.Read(offset + 0x44c, 8, IV); - // Issue: 6813 - // Magic value is at partition's offset + 0x1f1 (1byte) - // If encrypted with the Korean key, the magic value would be 1 - // Otherwise it is zero - u8 using_korean_key = 0; - _rReader.Read(offset + 0x1f1, sizeof(u8), &using_korean_key); - u8 region = 0; - _rReader.Read(0x3, sizeof(u8), ®ion); + // Issue: 6813 + // Magic value is at partition's offset + 0x1f1 (1byte) + // If encrypted with the Korean key, the magic value would be 1 + // Otherwise it is zero + u8 using_korean_key = 0; + _rReader.Read(offset + 0x1f1, sizeof(u8), &using_korean_key); + u8 region = 0; + _rReader.Read(0x3, sizeof(u8), ®ion); - mbedtls_aes_context AES_ctx; - mbedtls_aes_setkey_dec(&AES_ctx, (using_korean_key == 1 && region == 'K' ? s_master_key_korean : s_master_key), 128); + mbedtls_aes_context AES_ctx; + mbedtls_aes_setkey_dec( + &AES_ctx, (using_korean_key == 1 && region == 'K' ? s_master_key_korean : s_master_key), 128); - mbedtls_aes_crypt_cbc(&AES_ctx, MBEDTLS_AES_DECRYPT, 16, IV, SubKey, VolumeKey); + mbedtls_aes_crypt_cbc(&AES_ctx, MBEDTLS_AES_DECRYPT, 16, IV, SubKey, VolumeKey); } -static std::unique_ptr CreateVolumeFromCryptedWiiImage(std::unique_ptr reader, u32 partition_group, u32 volume_type, u32 volume_number) +static std::unique_ptr CreateVolumeFromCryptedWiiImage(std::unique_ptr reader, + u32 partition_group, + u32 volume_type, u32 volume_number) { - CBlobBigEndianReader big_endian_reader(*reader); + CBlobBigEndianReader big_endian_reader(*reader); - u32 num_partitions; - if (!big_endian_reader.ReadSwapped(0x40000 + (partition_group * 8), &num_partitions)) - return nullptr; + u32 num_partitions; + if (!big_endian_reader.ReadSwapped(0x40000 + (partition_group * 8), &num_partitions)) + return nullptr; - // Check if we're looking for a valid partition - if ((int)volume_number != -1 && volume_number > num_partitions) - return nullptr; + // Check if we're looking for a valid partition + if ((int)volume_number != -1 && volume_number > num_partitions) + return nullptr; - u32 partitions_offset_unshifted; - if (!big_endian_reader.ReadSwapped(0x40000 + (partition_group * 8) + 4, &partitions_offset_unshifted)) - return nullptr; - u64 partitions_offset = (u64)partitions_offset_unshifted << 2; + u32 partitions_offset_unshifted; + if (!big_endian_reader.ReadSwapped(0x40000 + (partition_group * 8) + 4, + &partitions_offset_unshifted)) + return nullptr; + u64 partitions_offset = (u64)partitions_offset_unshifted << 2; - struct SPartition - { - SPartition(u64 offset_, u32 type_) : offset(offset_), type(type_) {} + struct SPartition + { + SPartition(u64 offset_, u32 type_) : offset(offset_), type(type_) {} + u64 offset; + u32 type; + }; - u64 offset; - u32 type; - }; + struct SPartitionGroup + { + u32 num_partitions; + u64 partitions_offset; + std::vector partitions; + }; + SPartitionGroup partition_groups[4]; - struct SPartitionGroup - { - u32 num_partitions; - u64 partitions_offset; - std::vector partitions; - }; - SPartitionGroup partition_groups[4]; + // Read all partitions + for (SPartitionGroup& group : partition_groups) + { + for (u32 i = 0; i < num_partitions; i++) + { + u32 partition_offset, partition_type; + if (big_endian_reader.ReadSwapped(partitions_offset + (i * 8) + 0, &partition_offset) && + big_endian_reader.ReadSwapped(partitions_offset + (i * 8) + 4, &partition_type)) + { + group.partitions.emplace_back((u64)partition_offset << 2, partition_type); + } + } + } - // Read all partitions - for (SPartitionGroup& group : partition_groups) - { - for (u32 i = 0; i < num_partitions; i++) - { - u32 partition_offset, partition_type; - if (big_endian_reader.ReadSwapped(partitions_offset + (i * 8) + 0, &partition_offset) && - big_endian_reader.ReadSwapped(partitions_offset + (i * 8) + 4, &partition_type)) - { - group.partitions.emplace_back((u64)partition_offset << 2, partition_type); - } - } - } + // Return the partition type specified or number + // types: 0 = game, 1 = firmware update, 2 = channel installer + // some partitions on SSBB use the ASCII title id of the demo VC game they hold... + for (size_t i = 0; i < partition_groups[partition_group].partitions.size(); i++) + { + const SPartition& partition = partition_groups[partition_group].partitions.at(i); - // Return the partition type specified or number - // types: 0 = game, 1 = firmware update, 2 = channel installer - // some partitions on SSBB use the ASCII title id of the demo VC game they hold... - for (size_t i = 0; i < partition_groups[partition_group].partitions.size(); i++) - { - const SPartition& partition = partition_groups[partition_group].partitions.at(i); + if ((partition.type == volume_type && (int)volume_number == -1) || i == volume_number) + { + u8 volume_key[16]; + VolumeKeyForPartition(*reader, partition.offset, volume_key); + return std::make_unique(std::move(reader), partition.offset, volume_key); + } + } - if ((partition.type == volume_type && (int)volume_number == -1) || i == volume_number) - { - u8 volume_key[16]; - VolumeKeyForPartition(*reader, partition.offset, volume_key); - return std::make_unique(std::move(reader), partition.offset, volume_key); - } - } - - return nullptr; + return nullptr; } EDiscType GetDiscType(IBlobReader& _rReader) { - CBlobBigEndianReader Reader(_rReader); + CBlobBigEndianReader Reader(_rReader); - // Check for Wii - u32 WiiMagic = 0; - Reader.ReadSwapped(0x18, &WiiMagic); - u32 WiiContainerMagic = 0; - Reader.ReadSwapped(0x60, &WiiContainerMagic); - if (WiiMagic == 0x5D1C9EA3 && WiiContainerMagic != 0) - return DISC_TYPE_WII; - if (WiiMagic == 0x5D1C9EA3 && WiiContainerMagic == 0) - return DISC_TYPE_WII_CONTAINER; + // Check for Wii + u32 WiiMagic = 0; + Reader.ReadSwapped(0x18, &WiiMagic); + u32 WiiContainerMagic = 0; + Reader.ReadSwapped(0x60, &WiiContainerMagic); + if (WiiMagic == 0x5D1C9EA3 && WiiContainerMagic != 0) + return DISC_TYPE_WII; + if (WiiMagic == 0x5D1C9EA3 && WiiContainerMagic == 0) + return DISC_TYPE_WII_CONTAINER; - // Check for WAD - // 0x206962 for boot2 wads - u32 WADMagic = 0; - Reader.ReadSwapped(0x02, &WADMagic); - if (WADMagic == 0x00204973 || WADMagic == 0x00206962) - return DISC_TYPE_WAD; + // Check for WAD + // 0x206962 for boot2 wads + u32 WADMagic = 0; + Reader.ReadSwapped(0x02, &WADMagic); + if (WADMagic == 0x00204973 || WADMagic == 0x00206962) + return DISC_TYPE_WAD; - // Check for GC - u32 GCMagic = 0; - Reader.ReadSwapped(0x1C, &GCMagic); - if (GCMagic == 0xC2339F3D) - return DISC_TYPE_GC; + // Check for GC + u32 GCMagic = 0; + Reader.ReadSwapped(0x1C, &GCMagic); + if (GCMagic == 0xC2339F3D) + return DISC_TYPE_GC; - WARN_LOG(DISCIO, "No known magic words found"); - WARN_LOG(DISCIO, "Wii offset: 0x18 value: 0x%08x", WiiMagic); - WARN_LOG(DISCIO, "WiiC offset: 0x60 value: 0x%08x", WiiContainerMagic); - WARN_LOG(DISCIO, "WAD offset: 0x02 value: 0x%08x", WADMagic); - WARN_LOG(DISCIO, "GC offset: 0x1C value: 0x%08x", GCMagic); + WARN_LOG(DISCIO, "No known magic words found"); + WARN_LOG(DISCIO, "Wii offset: 0x18 value: 0x%08x", WiiMagic); + WARN_LOG(DISCIO, "WiiC offset: 0x60 value: 0x%08x", WiiContainerMagic); + WARN_LOG(DISCIO, "WAD offset: 0x02 value: 0x%08x", WADMagic); + WARN_LOG(DISCIO, "GC offset: 0x1C value: 0x%08x", GCMagic); - return DISC_TYPE_UNK; + return DISC_TYPE_UNK; } } // namespace diff --git a/Source/Core/DiscIO/VolumeCreator.h b/Source/Core/DiscIO/VolumeCreator.h index 4f3f0d80af..6b185b4b81 100644 --- a/Source/Core/DiscIO/VolumeCreator.h +++ b/Source/Core/DiscIO/VolumeCreator.h @@ -11,12 +11,14 @@ namespace DiscIO { - class IVolume; class IBlobReader; -std::unique_ptr CreateVolumeFromFilename(const std::string& filename, u32 partition_group = 0, u32 volume_number = -1); -std::unique_ptr CreateVolumeFromDirectory(const std::string& directory, bool is_wii, const std::string& apploader = "", const std::string& dol = ""); +std::unique_ptr CreateVolumeFromFilename(const std::string& filename, + u32 partition_group = 0, u32 volume_number = -1); +std::unique_ptr CreateVolumeFromDirectory(const std::string& directory, bool is_wii, + const std::string& apploader = "", + const std::string& dol = ""); void VolumeKeyForPartition(IBlobReader& _rReader, u64 offset, u8* VolumeKey); -} // namespace +} // namespace diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/VolumeDirectory.cpp index 6aa29d62e3..8fe2e65cf0 100644 --- a/Source/Core/DiscIO/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/VolumeDirectory.cpp @@ -14,8 +14,8 @@ #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/MathUtil.h" #include "Common/Logging/Log.h" +#include "Common/MathUtil.h" #include "DiscIO/Blob.h" #include "DiscIO/FileMonitor.h" #include "DiscIO/Volume.h" @@ -23,35 +23,30 @@ namespace DiscIO { - const size_t CVolumeDirectory::MAX_NAME_LENGTH; const size_t CVolumeDirectory::MAX_ID_LENGTH; CVolumeDirectory::CVolumeDirectory(const std::string& _rDirectory, bool _bIsWii, - const std::string& _rApploader, const std::string& _rDOL) - : m_totalNameSize(0) - , m_dataStartAddress(-1) - , m_diskHeader(DISKHEADERINFO_ADDRESS) - , m_diskHeaderInfo(std::make_unique()) - , m_fst_address(0) - , m_dol_address(0) + const std::string& _rApploader, const std::string& _rDOL) + : m_totalNameSize(0), m_dataStartAddress(-1), m_diskHeader(DISKHEADERINFO_ADDRESS), + m_diskHeaderInfo(std::make_unique()), m_fst_address(0), m_dol_address(0) { - m_rootDirectory = ExtractDirectoryName(_rDirectory); + m_rootDirectory = ExtractDirectoryName(_rDirectory); - // create the default disk header - SetUniqueID("AGBJ01"); - SetName("Default name"); + // create the default disk header + SetUniqueID("AGBJ01"); + SetName("Default name"); - if (_bIsWii) - SetDiskTypeWii(); - else - SetDiskTypeGC(); + if (_bIsWii) + SetDiskTypeWii(); + else + SetDiskTypeGC(); - // Don't load the DOL if we don't have an apploader - if (SetApploader(_rApploader)) - SetDOL(_rDOL); + // Don't load the DOL if we don't have an apploader + if (SetApploader(_rApploader)) + SetDOL(_rDOL); - BuildFST(); + BuildFST(); } CVolumeDirectory::~CVolumeDirectory() @@ -60,437 +55,446 @@ CVolumeDirectory::~CVolumeDirectory() bool CVolumeDirectory::IsValidDirectory(const std::string& _rDirectory) { - return File::IsDirectory(ExtractDirectoryName(_rDirectory)); + return File::IsDirectory(ExtractDirectoryName(_rDirectory)); } bool CVolumeDirectory::Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt) const { - if (!decrypt && (_Offset + _Length >= 0x400) && m_is_wii) - { - // Fully supporting this would require re-encrypting every file that's read. - // Only supporting the areas that IOS allows software to read could be more feasible. - // Currently, only the header (up to 0x400) is supported, though we're cheating a bit - // with it by reading the header inside the current partition instead. Supporting the - // header is enough for booting games, but not for running things like the Disc Channel. - return false; - } + if (!decrypt && (_Offset + _Length >= 0x400) && m_is_wii) + { + // Fully supporting this would require re-encrypting every file that's read. + // Only supporting the areas that IOS allows software to read could be more feasible. + // Currently, only the header (up to 0x400) is supported, though we're cheating a bit + // with it by reading the header inside the current partition instead. Supporting the + // header is enough for booting games, but not for running things like the Disc Channel. + return false; + } - if (decrypt && !m_is_wii) - PanicAlertT("Tried to decrypt data from a non-Wii volume"); + if (decrypt && !m_is_wii) + PanicAlertT("Tried to decrypt data from a non-Wii volume"); - // header - if (_Offset < DISKHEADERINFO_ADDRESS) - { - WriteToBuffer(DISKHEADER_ADDRESS, DISKHEADERINFO_ADDRESS, m_diskHeader.data(), _Offset, _Length, _pBuffer); - } - // header info - if (_Offset >= DISKHEADERINFO_ADDRESS && _Offset < APPLOADER_ADDRESS) - { - WriteToBuffer(DISKHEADERINFO_ADDRESS, sizeof(m_diskHeaderInfo), (u8*)m_diskHeaderInfo.get(), _Offset, _Length, _pBuffer); - } - // apploader - if (_Offset >= APPLOADER_ADDRESS && _Offset < APPLOADER_ADDRESS + m_apploader.size()) - { - WriteToBuffer(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data(), _Offset, _Length, _pBuffer); - } - // dol - if (_Offset >= m_dol_address && _Offset < m_dol_address + m_DOL.size()) - { - WriteToBuffer(m_dol_address, m_DOL.size(), m_DOL.data(), _Offset, _Length, _pBuffer); - } - // fst - if (_Offset >= m_fst_address && _Offset < m_dataStartAddress) - { - WriteToBuffer(m_fst_address, m_FSTData.size(), m_FSTData.data(), _Offset, _Length, _pBuffer); - } + // header + if (_Offset < DISKHEADERINFO_ADDRESS) + { + WriteToBuffer(DISKHEADER_ADDRESS, DISKHEADERINFO_ADDRESS, m_diskHeader.data(), _Offset, _Length, + _pBuffer); + } + // header info + if (_Offset >= DISKHEADERINFO_ADDRESS && _Offset < APPLOADER_ADDRESS) + { + WriteToBuffer(DISKHEADERINFO_ADDRESS, sizeof(m_diskHeaderInfo), (u8*)m_diskHeaderInfo.get(), + _Offset, _Length, _pBuffer); + } + // apploader + if (_Offset >= APPLOADER_ADDRESS && _Offset < APPLOADER_ADDRESS + m_apploader.size()) + { + WriteToBuffer(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data(), _Offset, _Length, + _pBuffer); + } + // dol + if (_Offset >= m_dol_address && _Offset < m_dol_address + m_DOL.size()) + { + WriteToBuffer(m_dol_address, m_DOL.size(), m_DOL.data(), _Offset, _Length, _pBuffer); + } + // fst + if (_Offset >= m_fst_address && _Offset < m_dataStartAddress) + { + WriteToBuffer(m_fst_address, m_FSTData.size(), m_FSTData.data(), _Offset, _Length, _pBuffer); + } - if (m_virtualDisk.empty()) - return true; + if (m_virtualDisk.empty()) + return true; - // Determine which file the offset refers to - std::map::const_iterator fileIter = m_virtualDisk.lower_bound(_Offset); - if (fileIter->first > _Offset && fileIter != m_virtualDisk.begin()) - --fileIter; + // Determine which file the offset refers to + std::map::const_iterator fileIter = m_virtualDisk.lower_bound(_Offset); + if (fileIter->first > _Offset && fileIter != m_virtualDisk.begin()) + --fileIter; - // zero fill to start of file data - PadToAddress(fileIter->first, _Offset, _Length, _pBuffer); + // zero fill to start of file data + PadToAddress(fileIter->first, _Offset, _Length, _pBuffer); - while (fileIter != m_virtualDisk.end() && _Length > 0) - { - _dbg_assert_(DVDINTERFACE, fileIter->first <= _Offset); - u64 fileOffset = _Offset - fileIter->first; - const std::string fileName = fileIter->second; + while (fileIter != m_virtualDisk.end() && _Length > 0) + { + _dbg_assert_(DVDINTERFACE, fileIter->first <= _Offset); + u64 fileOffset = _Offset - fileIter->first; + const std::string fileName = fileIter->second; - File::IOFile file(fileName, "rb"); - if (!file) - return false; + File::IOFile file(fileName, "rb"); + if (!file) + return false; - u64 fileSize = file.GetSize(); + u64 fileSize = file.GetSize(); - FileMon::CheckFile(fileName, fileSize); + FileMon::CheckFile(fileName, fileSize); - if (fileOffset < fileSize) - { - u64 fileBytes = std::min(fileSize - fileOffset, _Length); + if (fileOffset < fileSize) + { + u64 fileBytes = std::min(fileSize - fileOffset, _Length); - if (!file.Seek(fileOffset, SEEK_SET)) - return false; - if (!file.ReadBytes(_pBuffer, fileBytes)) - return false; + if (!file.Seek(fileOffset, SEEK_SET)) + return false; + if (!file.ReadBytes(_pBuffer, fileBytes)) + return false; - _Length -= fileBytes; - _pBuffer += fileBytes; - _Offset += fileBytes; - } + _Length -= fileBytes; + _pBuffer += fileBytes; + _Offset += fileBytes; + } - ++fileIter; + ++fileIter; - if (fileIter != m_virtualDisk.end()) - { - _dbg_assert_(DVDINTERFACE, fileIter->first >= _Offset); - PadToAddress(fileIter->first, _Offset, _Length, _pBuffer); - } - } + if (fileIter != m_virtualDisk.end()) + { + _dbg_assert_(DVDINTERFACE, fileIter->first >= _Offset); + PadToAddress(fileIter->first, _Offset, _Length, _pBuffer); + } + } - return true; + return true; } std::string CVolumeDirectory::GetUniqueID() const { - return std::string(m_diskHeader.begin(), m_diskHeader.begin() + MAX_ID_LENGTH); + return std::string(m_diskHeader.begin(), m_diskHeader.begin() + MAX_ID_LENGTH); } void CVolumeDirectory::SetUniqueID(const std::string& id) { - memcpy(m_diskHeader.data(), id.c_str(), std::min(id.length(), MAX_ID_LENGTH)); + memcpy(m_diskHeader.data(), id.c_str(), std::min(id.length(), MAX_ID_LENGTH)); } IVolume::ECountry CVolumeDirectory::GetCountry() const { - return CountrySwitch(m_diskHeader[3]); + return CountrySwitch(m_diskHeader[3]); } std::string CVolumeDirectory::GetMakerID() const { - // Not implemented - return "00"; + // Not implemented + return "00"; } std::string CVolumeDirectory::GetInternalName() const { - char name[0x60]; - if (Read(0x20, 0x60, (u8*)name, false)) - return DecodeString(name); - else - return ""; + char name[0x60]; + if (Read(0x20, 0x60, (u8*)name, false)) + return DecodeString(name); + else + return ""; } std::map CVolumeDirectory::GetNames(bool prefer_long) const { - std::string name = GetInternalName(); - if (name.empty()) - return { { } }; - return { { IVolume::LANGUAGE_UNKNOWN, name } }; + std::string name = GetInternalName(); + if (name.empty()) + return {{}}; + return {{IVolume::LANGUAGE_UNKNOWN, name}}; } std::vector CVolumeDirectory::GetBanner(int* width, int* height) const { - // Not implemented - *width = 0; - *height = 0; - return std::vector(); + // Not implemented + *width = 0; + *height = 0; + return std::vector(); } void CVolumeDirectory::SetName(const std::string& name) { - size_t length = std::min(name.length(), MAX_NAME_LENGTH); - memcpy(&m_diskHeader[0x20], name.c_str(), length); - m_diskHeader[length + 0x20] = 0; + size_t length = std::min(name.length(), MAX_NAME_LENGTH); + memcpy(&m_diskHeader[0x20], name.c_str(), length); + m_diskHeader[length + 0x20] = 0; } u64 CVolumeDirectory::GetFSTSize() const { - // Not implemented - return 0; + // Not implemented + return 0; } std::string CVolumeDirectory::GetApploaderDate() const { - // Not implemented - return "VOID"; + // Not implemented + return "VOID"; } IVolume::EPlatform CVolumeDirectory::GetVolumeType() const { - return m_is_wii ? WII_DISC : GAMECUBE_DISC; + return m_is_wii ? WII_DISC : GAMECUBE_DISC; } BlobType CVolumeDirectory::GetBlobType() const { - // VolumeDirectory isn't actually a blob, but it sort of acts - // like one, so it makes sense that it has its own blob type. - // It should be made into a proper blob in the future. - return BlobType::DIRECTORY; + // VolumeDirectory isn't actually a blob, but it sort of acts + // like one, so it makes sense that it has its own blob type. + // It should be made into a proper blob in the future. + return BlobType::DIRECTORY; } u64 CVolumeDirectory::GetSize() const { - // Not implemented - return 0; + // Not implemented + return 0; } u64 CVolumeDirectory::GetRawSize() const { - // Not implemented - return 0; + // Not implemented + return 0; } std::string CVolumeDirectory::ExtractDirectoryName(const std::string& _rDirectory) { - std::string directoryName = _rDirectory; + std::string directoryName = _rDirectory; - size_t lastSep = directoryName.find_last_of(DIR_SEP_CHR); + size_t lastSep = directoryName.find_last_of(DIR_SEP_CHR); - if (lastSep != directoryName.size() - 1) - { - // TODO: This assumes that file names will always have a dot in them - // and directory names never will; both assumptions are often - // right but in general wrong. - size_t extensionStart = directoryName.find_last_of('.'); - if (extensionStart != std::string::npos && extensionStart > lastSep) - { - directoryName.resize(lastSep); - } - } - else - { - directoryName.resize(lastSep); - } + if (lastSep != directoryName.size() - 1) + { + // TODO: This assumes that file names will always have a dot in them + // and directory names never will; both assumptions are often + // right but in general wrong. + size_t extensionStart = directoryName.find_last_of('.'); + if (extensionStart != std::string::npos && extensionStart > lastSep) + { + directoryName.resize(lastSep); + } + } + else + { + directoryName.resize(lastSep); + } - return directoryName; + return directoryName; } void CVolumeDirectory::SetDiskTypeWii() { - Write32(0x5d1c9ea3, 0x18, &m_diskHeader); - memset(&m_diskHeader[0x1c], 0, 4); + Write32(0x5d1c9ea3, 0x18, &m_diskHeader); + memset(&m_diskHeader[0x1c], 0, 4); - m_is_wii = true; - m_addressShift = 2; + m_is_wii = true; + m_addressShift = 2; } void CVolumeDirectory::SetDiskTypeGC() { - memset(&m_diskHeader[0x18], 0, 4); - Write32(0xc2339f3d, 0x1c, &m_diskHeader); + memset(&m_diskHeader[0x18], 0, 4); + Write32(0xc2339f3d, 0x1c, &m_diskHeader); - m_is_wii = false; - m_addressShift = 0; + m_is_wii = false; + m_addressShift = 0; } bool CVolumeDirectory::SetApploader(const std::string& _rApploader) { - if (!_rApploader.empty()) - { - std::string data; - if (!File::ReadFileToString(_rApploader, data)) - { - PanicAlertT("Apploader unable to load from file"); - return false; - } - size_t apploaderSize = 0x20 + Common::swap32(*(u32*)&data.data()[0x14]) + Common::swap32(*(u32*)&data.data()[0x18]); - if (apploaderSize != data.size()) - { - PanicAlertT("Apploader is the wrong size...is it really an apploader?"); - return false; - } - m_apploader.resize(apploaderSize); - std::copy(data.begin(), data.end(), m_apploader.begin()); + if (!_rApploader.empty()) + { + std::string data; + if (!File::ReadFileToString(_rApploader, data)) + { + PanicAlertT("Apploader unable to load from file"); + return false; + } + size_t apploaderSize = 0x20 + Common::swap32(*(u32*)&data.data()[0x14]) + + Common::swap32(*(u32*)&data.data()[0x18]); + if (apploaderSize != data.size()) + { + PanicAlertT("Apploader is the wrong size...is it really an apploader?"); + return false; + } + m_apploader.resize(apploaderSize); + std::copy(data.begin(), data.end(), m_apploader.begin()); - // 32byte aligned (plus 0x20 padding) - m_dol_address = ROUND_UP(APPLOADER_ADDRESS + m_apploader.size() + 0x20, 0x20ull); - return true; - } - else - { - m_apploader.resize(0x20); - // Make sure BS2 HLE doesn't try to run the apploader - *(u32*)&m_apploader[0x10] = (u32)-1; - return false; - } + // 32byte aligned (plus 0x20 padding) + m_dol_address = ROUND_UP(APPLOADER_ADDRESS + m_apploader.size() + 0x20, 0x20ull); + return true; + } + else + { + m_apploader.resize(0x20); + // Make sure BS2 HLE doesn't try to run the apploader + *(u32*)&m_apploader[0x10] = (u32)-1; + return false; + } } void CVolumeDirectory::SetDOL(const std::string& rDOL) { - if (!rDOL.empty()) - { - std::string data; - File::ReadFileToString(rDOL, data); - m_DOL.resize(data.size()); - std::copy(data.begin(), data.end(), m_DOL.begin()); + if (!rDOL.empty()) + { + std::string data; + File::ReadFileToString(rDOL, data); + m_DOL.resize(data.size()); + std::copy(data.begin(), data.end(), m_DOL.begin()); - Write32((u32)(m_dol_address >> m_addressShift), 0x0420, &m_diskHeader); + Write32((u32)(m_dol_address >> m_addressShift), 0x0420, &m_diskHeader); - // 32byte aligned (plus 0x20 padding) - m_fst_address = ROUND_UP(m_dol_address + m_DOL.size() + 0x20, 0x20ull); - } + // 32byte aligned (plus 0x20 padding) + m_fst_address = ROUND_UP(m_dol_address + m_DOL.size() + 0x20, 0x20ull); + } } void CVolumeDirectory::BuildFST() { - m_FSTData.clear(); + m_FSTData.clear(); - File::FSTEntry rootEntry; + File::FSTEntry rootEntry; - // read data from physical disk to rootEntry - u64 totalEntries = AddDirectoryEntries(m_rootDirectory, rootEntry) + 1; + // read data from physical disk to rootEntry + u64 totalEntries = AddDirectoryEntries(m_rootDirectory, rootEntry) + 1; - m_fstNameOffset = totalEntries * ENTRY_SIZE; // offset in FST nameTable - m_FSTData.resize(m_fstNameOffset + m_totalNameSize); + m_fstNameOffset = totalEntries * ENTRY_SIZE; // offset in FST nameTable + m_FSTData.resize(m_fstNameOffset + m_totalNameSize); - // if FST hasn't been assigned (ie no apploader/dol setup), set to default - if (m_fst_address == 0) - m_fst_address = APPLOADER_ADDRESS + 0x2000; + // if FST hasn't been assigned (ie no apploader/dol setup), set to default + if (m_fst_address == 0) + m_fst_address = APPLOADER_ADDRESS + 0x2000; - // 4 byte aligned start of data on disk - m_dataStartAddress = ROUND_UP(m_fst_address + m_FSTData.size(), 0x8000ull); - u64 curDataAddress = m_dataStartAddress; + // 4 byte aligned start of data on disk + m_dataStartAddress = ROUND_UP(m_fst_address + m_FSTData.size(), 0x8000ull); + u64 curDataAddress = m_dataStartAddress; - u32 fstOffset = 0; // Offset within FST data - u32 nameOffset = 0; // Offset within name table - u32 rootOffset = 0; // Offset of root of FST + u32 fstOffset = 0; // Offset within FST data + u32 nameOffset = 0; // Offset within name table + u32 rootOffset = 0; // Offset of root of FST - // write root entry - WriteEntryData(fstOffset, DIRECTORY_ENTRY, 0, 0, totalEntries); + // write root entry + WriteEntryData(fstOffset, DIRECTORY_ENTRY, 0, 0, totalEntries); - for (auto& entry : rootEntry.children) - { - WriteEntry(entry, fstOffset, nameOffset, curDataAddress, rootOffset); - } + for (auto& entry : rootEntry.children) + { + WriteEntry(entry, fstOffset, nameOffset, curDataAddress, rootOffset); + } - // overflow check - _dbg_assert_(DVDINTERFACE, nameOffset == m_totalNameSize); + // overflow check + _dbg_assert_(DVDINTERFACE, nameOffset == m_totalNameSize); - // write FST size and location - Write32((u32)(m_fst_address >> m_addressShift), 0x0424, &m_diskHeader); - Write32((u32)(m_FSTData.size() >> m_addressShift), 0x0428, &m_diskHeader); - Write32((u32)(m_FSTData.size() >> m_addressShift), 0x042c, &m_diskHeader); + // write FST size and location + Write32((u32)(m_fst_address >> m_addressShift), 0x0424, &m_diskHeader); + Write32((u32)(m_FSTData.size() >> m_addressShift), 0x0428, &m_diskHeader); + Write32((u32)(m_FSTData.size() >> m_addressShift), 0x042c, &m_diskHeader); } void CVolumeDirectory::WriteToBuffer(u64 _SrcStartAddress, u64 _SrcLength, const u8* _Src, - u64& _Address, u64& _Length, u8*& _pBuffer) const + u64& _Address, u64& _Length, u8*& _pBuffer) const { - if (_Length == 0) - return; + if (_Length == 0) + return; - _dbg_assert_(DVDINTERFACE, _Address >= _SrcStartAddress); + _dbg_assert_(DVDINTERFACE, _Address >= _SrcStartAddress); - u64 srcOffset = _Address - _SrcStartAddress; + u64 srcOffset = _Address - _SrcStartAddress; - if (srcOffset < _SrcLength) - { - u64 srcBytes = std::min(_SrcLength - srcOffset, _Length); + if (srcOffset < _SrcLength) + { + u64 srcBytes = std::min(_SrcLength - srcOffset, _Length); - memcpy(_pBuffer, _Src + srcOffset, (size_t)srcBytes); + memcpy(_pBuffer, _Src + srcOffset, (size_t)srcBytes); - _Length -= srcBytes; - _pBuffer += srcBytes; - _Address += srcBytes; - } + _Length -= srcBytes; + _pBuffer += srcBytes; + _Address += srcBytes; + } } -void CVolumeDirectory::PadToAddress(u64 _StartAddress, u64& _Address, u64& _Length, u8*& _pBuffer) const +void CVolumeDirectory::PadToAddress(u64 _StartAddress, u64& _Address, u64& _Length, + u8*& _pBuffer) const { - if (_StartAddress > _Address && _Length > 0) - { - u64 padBytes = std::min(_StartAddress - _Address, _Length); - memset(_pBuffer, 0, (size_t)padBytes); - _Length -= padBytes; - _pBuffer += padBytes; - _Address += padBytes; - } + if (_StartAddress > _Address && _Length > 0) + { + u64 padBytes = std::min(_StartAddress - _Address, _Length); + memset(_pBuffer, 0, (size_t)padBytes); + _Length -= padBytes; + _pBuffer += padBytes; + _Address += padBytes; + } } void CVolumeDirectory::Write32(u32 data, u32 offset, std::vector* const buffer) { - (*buffer)[offset++] = (data >> 24); - (*buffer)[offset++] = (data >> 16) & 0xff; - (*buffer)[offset++] = (data >> 8) & 0xff; - (*buffer)[offset] = (data) & 0xff; + (*buffer)[offset++] = (data >> 24); + (*buffer)[offset++] = (data >> 16) & 0xff; + (*buffer)[offset++] = (data >> 8) & 0xff; + (*buffer)[offset] = (data)&0xff; } -void CVolumeDirectory::WriteEntryData(u32& entryOffset, u8 type, u32 nameOffset, u64 dataOffset, u64 length) +void CVolumeDirectory::WriteEntryData(u32& entryOffset, u8 type, u32 nameOffset, u64 dataOffset, + u64 length) { - m_FSTData[entryOffset++] = type; + m_FSTData[entryOffset++] = type; - m_FSTData[entryOffset++] = (nameOffset >> 16) & 0xff; - m_FSTData[entryOffset++] = (nameOffset >> 8) & 0xff; - m_FSTData[entryOffset++] = (nameOffset) & 0xff; + m_FSTData[entryOffset++] = (nameOffset >> 16) & 0xff; + m_FSTData[entryOffset++] = (nameOffset >> 8) & 0xff; + m_FSTData[entryOffset++] = (nameOffset)&0xff; - Write32((u32)(dataOffset >> m_addressShift), entryOffset, &m_FSTData); - entryOffset += 4; + Write32((u32)(dataOffset >> m_addressShift), entryOffset, &m_FSTData); + entryOffset += 4; - Write32((u32)length, entryOffset, &m_FSTData); - entryOffset += 4; + Write32((u32)length, entryOffset, &m_FSTData); + entryOffset += 4; } void CVolumeDirectory::WriteEntryName(u32& nameOffset, const std::string& name) { - strncpy((char*)&m_FSTData[nameOffset + m_fstNameOffset], name.c_str(), name.length() + 1); + strncpy((char*)&m_FSTData[nameOffset + m_fstNameOffset], name.c_str(), name.length() + 1); - nameOffset += (u32)(name.length() + 1); + nameOffset += (u32)(name.length() + 1); } -void CVolumeDirectory::WriteEntry(const File::FSTEntry& entry, u32& fstOffset, u32& nameOffset, u64& dataOffset, u32 parentEntryNum) +void CVolumeDirectory::WriteEntry(const File::FSTEntry& entry, u32& fstOffset, u32& nameOffset, + u64& dataOffset, u32 parentEntryNum) { - if (entry.isDirectory) - { - u32 myOffset = fstOffset; - u32 myEntryNum = myOffset / ENTRY_SIZE; - WriteEntryData(fstOffset, DIRECTORY_ENTRY, nameOffset, parentEntryNum, myEntryNum + entry.size + 1); - WriteEntryName(nameOffset, entry.virtualName); + if (entry.isDirectory) + { + u32 myOffset = fstOffset; + u32 myEntryNum = myOffset / ENTRY_SIZE; + WriteEntryData(fstOffset, DIRECTORY_ENTRY, nameOffset, parentEntryNum, + myEntryNum + entry.size + 1); + WriteEntryName(nameOffset, entry.virtualName); - for (const auto& child : entry.children) - { - WriteEntry(child, fstOffset, nameOffset, dataOffset, myEntryNum); - } - } - else - { - // put entry in FST - WriteEntryData(fstOffset, FILE_ENTRY, nameOffset, dataOffset, entry.size); - WriteEntryName(nameOffset, entry.virtualName); + for (const auto& child : entry.children) + { + WriteEntry(child, fstOffset, nameOffset, dataOffset, myEntryNum); + } + } + else + { + // put entry in FST + WriteEntryData(fstOffset, FILE_ENTRY, nameOffset, dataOffset, entry.size); + WriteEntryName(nameOffset, entry.virtualName); - // write entry to virtual disk - _dbg_assert_(DVDINTERFACE, m_virtualDisk.find(dataOffset) == m_virtualDisk.end()); - m_virtualDisk.emplace(dataOffset, entry.physicalName); + // write entry to virtual disk + _dbg_assert_(DVDINTERFACE, m_virtualDisk.find(dataOffset) == m_virtualDisk.end()); + m_virtualDisk.emplace(dataOffset, entry.physicalName); - // 4 byte aligned - dataOffset = ROUND_UP(dataOffset + std::max(entry.size, 1ull), 0x8000ull); - } + // 4 byte aligned + dataOffset = ROUND_UP(dataOffset + std::max(entry.size, 1ull), 0x8000ull); + } } static u32 ComputeNameSize(const File::FSTEntry& parentEntry) { - u32 nameSize = 0; - const std::vector& children = parentEntry.children; - for (auto it = children.cbegin(); it != children.cend(); ++it) - { - const File::FSTEntry& entry = *it; - if (entry.isDirectory) - { - nameSize += ComputeNameSize(entry); - } - nameSize += (u32)entry.virtualName.length() + 1; - } - return nameSize; + u32 nameSize = 0; + const std::vector& children = parentEntry.children; + for (auto it = children.cbegin(); it != children.cend(); ++it) + { + const File::FSTEntry& entry = *it; + if (entry.isDirectory) + { + nameSize += ComputeNameSize(entry); + } + nameSize += (u32)entry.virtualName.length() + 1; + } + return nameSize; } -u64 CVolumeDirectory::AddDirectoryEntries(const std::string& _Directory, File::FSTEntry& parentEntry) +u64 CVolumeDirectory::AddDirectoryEntries(const std::string& _Directory, + File::FSTEntry& parentEntry) { - parentEntry = File::ScanDirectoryTree(_Directory, true); - m_totalNameSize += ComputeNameSize(parentEntry); - return parentEntry.size; + parentEntry = File::ScanDirectoryTree(_Directory, true); + m_totalNameSize += ComputeNameSize(parentEntry); + return parentEntry.size; } -} // namespace +} // namespace diff --git a/Source/Core/DiscIO/VolumeDirectory.h b/Source/Core/DiscIO/VolumeDirectory.h index d4aa682533..496f1119cb 100644 --- a/Source/Core/DiscIO/VolumeDirectory.h +++ b/Source/Core/DiscIO/VolumeDirectory.h @@ -13,7 +13,10 @@ #include "DiscIO/Blob.h" #include "DiscIO/Volume.h" -namespace File { struct FSTEntry; } +namespace File +{ +struct FSTEntry; +} // // --- this volume type is used for reading files directly from the hard drive --- @@ -21,133 +24,132 @@ namespace File { struct FSTEntry; } namespace DiscIO { - class CVolumeDirectory : public IVolume { public: + CVolumeDirectory(const std::string& _rDirectory, bool _bIsWii, + const std::string& _rApploader = "", const std::string& _rDOL = ""); - CVolumeDirectory(const std::string& _rDirectory, bool _bIsWii, - const std::string& _rApploader = "", const std::string& _rDOL = ""); + ~CVolumeDirectory(); - ~CVolumeDirectory(); + static bool IsValidDirectory(const std::string& _rDirectory); - static bool IsValidDirectory(const std::string& _rDirectory); + bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt) const override; - bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt) const override; + std::string GetUniqueID() const override; + void SetUniqueID(const std::string& _ID); - std::string GetUniqueID() const override; - void SetUniqueID(const std::string& _ID); + std::string GetMakerID() const override; - std::string GetMakerID() const override; + u16 GetRevision() const override { return 0; } + std::string GetInternalName() const override; + std::map GetNames(bool prefer_long) const override; + std::vector GetBanner(int* width, int* height) const override; + void SetName(const std::string&); - u16 GetRevision() const override { return 0; } - std::string GetInternalName() const override; - std::map GetNames(bool prefer_long) const override; - std::vector GetBanner(int* width, int* height) const override; - void SetName(const std::string&); + u64 GetFSTSize() const override; - u64 GetFSTSize() const override; + std::string GetApploaderDate() const override; + EPlatform GetVolumeType() const override; - std::string GetApploaderDate() const override; - EPlatform GetVolumeType() const override; + ECountry GetCountry() const override; - ECountry GetCountry() const override; + BlobType GetBlobType() const override; + u64 GetSize() const override; + u64 GetRawSize() const override; - BlobType GetBlobType() const override; - u64 GetSize() const override; - u64 GetRawSize() const override; - - void BuildFST(); + void BuildFST(); private: - static std::string ExtractDirectoryName(const std::string& _rDirectory); + static std::string ExtractDirectoryName(const std::string& _rDirectory); - void SetDiskTypeWii(); - void SetDiskTypeGC(); + void SetDiskTypeWii(); + void SetDiskTypeGC(); - bool SetApploader(const std::string& _rApploader); + bool SetApploader(const std::string& _rApploader); - void SetDOL(const std::string& _rDOL); + void SetDOL(const std::string& _rDOL); - // writing to read buffer - void WriteToBuffer(u64 _SrcStartAddress, u64 _SrcLength, const u8* _Src, - u64& _Address, u64& _Length, u8*& _pBuffer) const; + // writing to read buffer + void WriteToBuffer(u64 _SrcStartAddress, u64 _SrcLength, const u8* _Src, u64& _Address, + u64& _Length, u8*& _pBuffer) const; - void PadToAddress(u64 _StartAddress, u64& _Address, u64& _Length, u8*& _pBuffer) const; + void PadToAddress(u64 _StartAddress, u64& _Address, u64& _Length, u8*& _pBuffer) const; - void Write32(u32 data, u32 offset, std::vector* const buffer); + void Write32(u32 data, u32 offset, std::vector* const buffer); - // FST creation - void WriteEntryData(u32& entryOffset, u8 type, u32 nameOffset, u64 dataOffset, u64 length); - void WriteEntryName(u32& nameOffset, const std::string& name); - void WriteEntry(const File::FSTEntry& entry, u32& fstOffset, u32& nameOffset, u64& dataOffset, u32 parentEntryNum); + // FST creation + void WriteEntryData(u32& entryOffset, u8 type, u32 nameOffset, u64 dataOffset, u64 length); + void WriteEntryName(u32& nameOffset, const std::string& name); + void WriteEntry(const File::FSTEntry& entry, u32& fstOffset, u32& nameOffset, u64& dataOffset, + u32 parentEntryNum); - // returns number of entries found in _Directory - u64 AddDirectoryEntries(const std::string& _Directory, File::FSTEntry& parentEntry); + // returns number of entries found in _Directory + u64 AddDirectoryEntries(const std::string& _Directory, File::FSTEntry& parentEntry); - std::string m_rootDirectory; + std::string m_rootDirectory; - std::map m_virtualDisk; + std::map m_virtualDisk; - u32 m_totalNameSize; + u32 m_totalNameSize; - bool m_is_wii; + bool m_is_wii; - // GameCube has no shift, Wii has 2 bit shift - u32 m_addressShift; + // GameCube has no shift, Wii has 2 bit shift + u32 m_addressShift; - // first address on disk containing file data - u64 m_dataStartAddress; + // first address on disk containing file data + u64 m_dataStartAddress; - u64 m_fstNameOffset; - std::vector m_FSTData; + u64 m_fstNameOffset; + std::vector m_FSTData; - std::vector m_diskHeader; + std::vector m_diskHeader; - #pragma pack(push, 1) - struct SDiskHeaderInfo - { - u32 debug_mntr_size; - u32 simulated_mem_size; - u32 arg_offset; - u32 debug_flag; - u32 track_location; - u32 track_size; - u32 country_code; - u32 unknown; - u32 unknown2; +#pragma pack(push, 1) + struct SDiskHeaderInfo + { + u32 debug_mntr_size; + u32 simulated_mem_size; + u32 arg_offset; + u32 debug_flag; + u32 track_location; + u32 track_size; + u32 country_code; + u32 unknown; + u32 unknown2; - // All the data is byteswapped - SDiskHeaderInfo() - { - debug_mntr_size = 0; - simulated_mem_size = 0; - arg_offset = 0; - debug_flag = 0; - track_location = 0; - track_size = 0; - country_code = 0; - unknown = 0; - unknown2 = 0; - } - }; - #pragma pack(pop) - std::unique_ptr m_diskHeaderInfo; + // All the data is byteswapped + SDiskHeaderInfo() + { + debug_mntr_size = 0; + simulated_mem_size = 0; + arg_offset = 0; + debug_flag = 0; + track_location = 0; + track_size = 0; + country_code = 0; + unknown = 0; + unknown2 = 0; + } + }; +#pragma pack(pop) + std::unique_ptr m_diskHeaderInfo; - std::vector m_apploader; - std::vector m_DOL; + std::vector m_apploader; + std::vector m_DOL; - u64 m_fst_address; - u64 m_dol_address; + u64 m_fst_address; + u64 m_dol_address; - static constexpr u8 ENTRY_SIZE = 0x0c; - static constexpr u8 FILE_ENTRY = 0; - static constexpr u8 DIRECTORY_ENTRY = 1; - static constexpr u64 DISKHEADER_ADDRESS = 0; - static constexpr u64 DISKHEADERINFO_ADDRESS = 0x440; - static constexpr u64 APPLOADER_ADDRESS = 0x2440; - static const size_t MAX_NAME_LENGTH = 0x3df; - static const size_t MAX_ID_LENGTH = 6; + static constexpr u8 ENTRY_SIZE = 0x0c; + static constexpr u8 FILE_ENTRY = 0; + static constexpr u8 DIRECTORY_ENTRY = 1; + static constexpr u64 DISKHEADER_ADDRESS = 0; + static constexpr u64 DISKHEADERINFO_ADDRESS = 0x440; + static constexpr u64 APPLOADER_ADDRESS = 0x2440; + static const size_t MAX_NAME_LENGTH = 0x3df; + static const size_t MAX_ID_LENGTH = 6; }; -} // namespace +} // namespace diff --git a/Source/Core/DiscIO/VolumeGC.cpp b/Source/Core/DiscIO/VolumeGC.cpp index 63ed9d4354..2930c6cd33 100644 --- a/Source/Core/DiscIO/VolumeGC.cpp +++ b/Source/Core/DiscIO/VolumeGC.cpp @@ -11,9 +11,9 @@ #include "Common/ColorUtil.h" #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "DiscIO/Blob.h" #include "DiscIO/FileMonitor.h" #include "DiscIO/Filesystem.h" @@ -22,9 +22,9 @@ namespace DiscIO { -CVolumeGC::CVolumeGC(std::unique_ptr reader) - : m_pReader(std::move(reader)) -{} +CVolumeGC::CVolumeGC(std::unique_ptr reader) : m_pReader(std::move(reader)) +{ +} CVolumeGC::~CVolumeGC() { @@ -32,269 +32,271 @@ CVolumeGC::~CVolumeGC() bool CVolumeGC::Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt) const { - if (decrypt) - PanicAlertT("Tried to decrypt data from a non-Wii volume"); + if (decrypt) + PanicAlertT("Tried to decrypt data from a non-Wii volume"); - if (m_pReader == nullptr) - return false; + if (m_pReader == nullptr) + return false; - FileMon::FindFilename(_Offset); + FileMon::FindFilename(_Offset); - return m_pReader->Read(_Offset, _Length, _pBuffer); + return m_pReader->Read(_Offset, _Length, _pBuffer); } std::string CVolumeGC::GetUniqueID() const { - static const std::string NO_UID("NO_UID"); - if (m_pReader == nullptr) - return NO_UID; + static const std::string NO_UID("NO_UID"); + if (m_pReader == nullptr) + return NO_UID; - char ID[6]; + char ID[6]; - if (!Read(0, sizeof(ID), reinterpret_cast(ID))) - { - PanicAlertT("Failed to read unique ID from disc image"); - return NO_UID; - } + if (!Read(0, sizeof(ID), reinterpret_cast(ID))) + { + PanicAlertT("Failed to read unique ID from disc image"); + return NO_UID; + } - return DecodeString(ID); + return DecodeString(ID); } IVolume::ECountry CVolumeGC::GetCountry() const { - if (!m_pReader) - return COUNTRY_UNKNOWN; + if (!m_pReader) + return COUNTRY_UNKNOWN; - u8 country_code; - m_pReader->Read(3, 1, &country_code); + u8 country_code; + m_pReader->Read(3, 1, &country_code); - return CountrySwitch(country_code); + return CountrySwitch(country_code); } std::string CVolumeGC::GetMakerID() const { - if (m_pReader == nullptr) - return std::string(); + if (m_pReader == nullptr) + return std::string(); - char makerID[2]; - if (!Read(0x4, 0x2, (u8*)&makerID)) - return std::string(); + char makerID[2]; + if (!Read(0x4, 0x2, (u8*)&makerID)) + return std::string(); - return DecodeString(makerID); + return DecodeString(makerID); } u16 CVolumeGC::GetRevision() const { - if (!m_pReader) - return 0; + if (!m_pReader) + return 0; - u8 revision; - if (!Read(7, 1, &revision)) - return 0; + u8 revision; + if (!Read(7, 1, &revision)) + return 0; - return revision; + return revision; } std::string CVolumeGC::GetInternalName() const { - char name[0x60]; - if (m_pReader != nullptr && Read(0x20, 0x60, (u8*)name)) - return DecodeString(name); - else - return ""; + char name[0x60]; + if (m_pReader != nullptr && Read(0x20, 0x60, (u8*)name)) + return DecodeString(name); + else + return ""; } std::map CVolumeGC::GetNames(bool prefer_long) const { - return ReadMultiLanguageStrings(false, prefer_long); + return ReadMultiLanguageStrings(false, prefer_long); } std::map CVolumeGC::GetDescriptions() const { - return ReadMultiLanguageStrings(true); + return ReadMultiLanguageStrings(true); } std::string CVolumeGC::GetCompany() const { - if (!LoadBannerFile()) - return ""; + if (!LoadBannerFile()) + return ""; - std::string company = DecodeString(m_banner_file.comment[0].longMaker); + std::string company = DecodeString(m_banner_file.comment[0].longMaker); - if (company.empty()) - company = DecodeString(m_banner_file.comment[0].shortMaker); + if (company.empty()) + company = DecodeString(m_banner_file.comment[0].shortMaker); - return company; + return company; } std::vector CVolumeGC::GetBanner(int* width, int* height) const { - if (!LoadBannerFile()) - { - *width = 0; - *height = 0; - return std::vector(); - } + if (!LoadBannerFile()) + { + *width = 0; + *height = 0; + return std::vector(); + } - std::vector image_buffer(GC_BANNER_WIDTH * GC_BANNER_HEIGHT); - ColorUtil::decode5A3image(image_buffer.data(), m_banner_file.image, GC_BANNER_WIDTH, GC_BANNER_HEIGHT); - *width = GC_BANNER_WIDTH; - *height = GC_BANNER_HEIGHT; - return image_buffer; + std::vector image_buffer(GC_BANNER_WIDTH * GC_BANNER_HEIGHT); + ColorUtil::decode5A3image(image_buffer.data(), m_banner_file.image, GC_BANNER_WIDTH, + GC_BANNER_HEIGHT); + *width = GC_BANNER_WIDTH; + *height = GC_BANNER_HEIGHT; + return image_buffer; } u64 CVolumeGC::GetFSTSize() const { - if (m_pReader == nullptr) - return 0; + if (m_pReader == nullptr) + return 0; - u32 size; - if (!Read(0x428, 0x4, (u8*)&size)) - return 0; + u32 size; + if (!Read(0x428, 0x4, (u8*)&size)) + return 0; - return Common::swap32(size); + return Common::swap32(size); } std::string CVolumeGC::GetApploaderDate() const { - if (m_pReader == nullptr) - return std::string(); + if (m_pReader == nullptr) + return std::string(); - char date[16]; - if (!Read(0x2440, 0x10, (u8*)&date)) - return std::string(); + char date[16]; + if (!Read(0x2440, 0x10, (u8*)&date)) + return std::string(); - return DecodeString(date); + return DecodeString(date); } BlobType CVolumeGC::GetBlobType() const { - return m_pReader ? m_pReader->GetBlobType() : BlobType::PLAIN; + return m_pReader ? m_pReader->GetBlobType() : BlobType::PLAIN; } u64 CVolumeGC::GetSize() const { - if (m_pReader) - return m_pReader->GetDataSize(); - else - return 0; + if (m_pReader) + return m_pReader->GetDataSize(); + else + return 0; } u64 CVolumeGC::GetRawSize() const { - if (m_pReader) - return m_pReader->GetRawSize(); - else - return 0; + if (m_pReader) + return m_pReader->GetRawSize(); + else + return 0; } u8 CVolumeGC::GetDiscNumber() const { - u8 disc_number; - Read(6, 1, &disc_number); - return disc_number; + u8 disc_number; + Read(6, 1, &disc_number); + return disc_number; } IVolume::EPlatform CVolumeGC::GetVolumeType() const { - return GAMECUBE_DISC; + return GAMECUBE_DISC; } // Returns true if the loaded banner file is valid, // regardless of whether it was loaded by the current call bool CVolumeGC::LoadBannerFile() const { - // The methods ReadMultiLanguageStrings, GetCompany and GetBanner - // need to access the opening.bnr file. These methods are - // usually called one after another. The file is cached in - // RAM to avoid reading it from the disc several times, but - // if none of these methods are called, the file is never loaded. + // The methods ReadMultiLanguageStrings, GetCompany and GetBanner + // need to access the opening.bnr file. These methods are + // usually called one after another. The file is cached in + // RAM to avoid reading it from the disc several times, but + // if none of these methods are called, the file is never loaded. - // If opening.bnr has been loaded already, return immediately - if (m_banner_file_type != BANNER_NOT_LOADED) - return m_banner_file_type != BANNER_INVALID; + // If opening.bnr has been loaded already, return immediately + if (m_banner_file_type != BANNER_NOT_LOADED) + return m_banner_file_type != BANNER_INVALID; - std::unique_ptr file_system(CreateFileSystem(this)); - size_t file_size = (size_t)file_system->GetFileSize("opening.bnr"); - if (file_size == BNR1_SIZE || file_size == BNR2_SIZE) - { - file_system->ReadFile("opening.bnr", reinterpret_cast(&m_banner_file), file_size); + std::unique_ptr file_system(CreateFileSystem(this)); + size_t file_size = (size_t)file_system->GetFileSize("opening.bnr"); + if (file_size == BNR1_SIZE || file_size == BNR2_SIZE) + { + file_system->ReadFile("opening.bnr", reinterpret_cast(&m_banner_file), file_size); - if (file_size == BNR1_SIZE && m_banner_file.id == 0x31524e42) // "BNR1" - { - m_banner_file_type = BANNER_BNR1; - } - else if (file_size == BNR2_SIZE && m_banner_file.id == 0x32524e42) // "BNR2" - { - m_banner_file_type = BANNER_BNR2; - } - else - { - m_banner_file_type = BANNER_INVALID; - WARN_LOG(DISCIO, "Invalid opening.bnr. Type: %0x Size: %0zx", m_banner_file.id, file_size); - } - } - else - { - m_banner_file_type = BANNER_INVALID; - WARN_LOG(DISCIO, "Invalid opening.bnr. Size: %0zx", file_size); - } + if (file_size == BNR1_SIZE && m_banner_file.id == 0x31524e42) // "BNR1" + { + m_banner_file_type = BANNER_BNR1; + } + else if (file_size == BNR2_SIZE && m_banner_file.id == 0x32524e42) // "BNR2" + { + m_banner_file_type = BANNER_BNR2; + } + else + { + m_banner_file_type = BANNER_INVALID; + WARN_LOG(DISCIO, "Invalid opening.bnr. Type: %0x Size: %0zx", m_banner_file.id, file_size); + } + } + else + { + m_banner_file_type = BANNER_INVALID; + WARN_LOG(DISCIO, "Invalid opening.bnr. Size: %0zx", file_size); + } - return m_banner_file_type != BANNER_INVALID; + return m_banner_file_type != BANNER_INVALID; } -std::map CVolumeGC::ReadMultiLanguageStrings(bool description, bool prefer_long) const +std::map +CVolumeGC::ReadMultiLanguageStrings(bool description, bool prefer_long) const { - std::map strings; + std::map strings; - if (!LoadBannerFile()) - return strings; + if (!LoadBannerFile()) + return strings; - u32 number_of_languages = 0; - ELanguage start_language = LANGUAGE_UNKNOWN; - bool is_japanese = GetCountry() == ECountry::COUNTRY_JAPAN; + u32 number_of_languages = 0; + ELanguage start_language = LANGUAGE_UNKNOWN; + bool is_japanese = GetCountry() == ECountry::COUNTRY_JAPAN; - switch (m_banner_file_type) - { - case BANNER_BNR1: // NTSC - number_of_languages = 1; - start_language = is_japanese ? ELanguage::LANGUAGE_JAPANESE : ELanguage::LANGUAGE_ENGLISH; - break; + switch (m_banner_file_type) + { + case BANNER_BNR1: // NTSC + number_of_languages = 1; + start_language = is_japanese ? ELanguage::LANGUAGE_JAPANESE : ELanguage::LANGUAGE_ENGLISH; + break; - case BANNER_BNR2: // PAL - number_of_languages = 6; - start_language = ELanguage::LANGUAGE_ENGLISH; - break; + case BANNER_BNR2: // PAL + number_of_languages = 6; + start_language = ELanguage::LANGUAGE_ENGLISH; + break; - // Shouldn't happen - case BANNER_INVALID: - case BANNER_NOT_LOADED: - break; - } + // Shouldn't happen + case BANNER_INVALID: + case BANNER_NOT_LOADED: + break; + } - for (u32 i = 0; i < number_of_languages; ++i) - { - const GCBannerComment& comment = m_banner_file.comment[i]; - std::string string; + for (u32 i = 0; i < number_of_languages; ++i) + { + const GCBannerComment& comment = m_banner_file.comment[i]; + std::string string; - if (description) - { - string = DecodeString(comment.comment); - } - else // Title - { - if (prefer_long) - string = DecodeString(comment.longTitle); + if (description) + { + string = DecodeString(comment.comment); + } + else // Title + { + if (prefer_long) + string = DecodeString(comment.longTitle); - if (string.empty()) - string = DecodeString(comment.shortTitle); - } + if (string.empty()) + string = DecodeString(comment.shortTitle); + } - if (!string.empty()) - strings[(ELanguage)(start_language + i)] = string; - } + if (!string.empty()) + strings[(ELanguage)(start_language + i)] = string; + } - return strings; + return strings; } -} // namespace +} // namespace diff --git a/Source/Core/DiscIO/VolumeGC.h b/Source/Core/DiscIO/VolumeGC.h index 6e98e942c0..0842736d08 100644 --- a/Source/Core/DiscIO/VolumeGC.h +++ b/Source/Core/DiscIO/VolumeGC.h @@ -17,71 +17,71 @@ namespace DiscIO { - class CVolumeGC : public IVolume { public: - CVolumeGC(std::unique_ptr reader); - ~CVolumeGC(); - bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt = false) const override; - std::string GetUniqueID() const override; - std::string GetMakerID() const override; - u16 GetRevision() const override; - std::string GetInternalName() const override; - std::map GetNames(bool prefer_long) const override; - std::map GetDescriptions() const override; - std::string GetCompany() const override; - std::vector GetBanner(int* width, int* height) const override; - u64 GetFSTSize() const override; - std::string GetApploaderDate() const override; - u8 GetDiscNumber() const override; + CVolumeGC(std::unique_ptr reader); + ~CVolumeGC(); + bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt = false) const override; + std::string GetUniqueID() const override; + std::string GetMakerID() const override; + u16 GetRevision() const override; + std::string GetInternalName() const override; + std::map GetNames(bool prefer_long) const override; + std::map GetDescriptions() const override; + std::string GetCompany() const override; + std::vector GetBanner(int* width, int* height) const override; + u64 GetFSTSize() const override; + std::string GetApploaderDate() const override; + u8 GetDiscNumber() const override; - EPlatform GetVolumeType() const override; - ECountry GetCountry() const override; - BlobType GetBlobType() const override; - u64 GetSize() const override; - u64 GetRawSize() const override; + EPlatform GetVolumeType() const override; + ECountry GetCountry() const override; + BlobType GetBlobType() const override; + u64 GetSize() const override; + u64 GetRawSize() const override; private: - bool LoadBannerFile() const; - std::map ReadMultiLanguageStrings(bool description, bool prefer_long = true) const; + bool LoadBannerFile() const; + std::map ReadMultiLanguageStrings(bool description, + bool prefer_long = true) const; - static const int GC_BANNER_WIDTH = 96; - static const int GC_BANNER_HEIGHT = 32; + static const int GC_BANNER_WIDTH = 96; + static const int GC_BANNER_HEIGHT = 32; - // Banner Comment - struct GCBannerComment - { - char shortTitle[32]; // Short game title shown in IPL menu - char shortMaker[32]; // Short developer, publisher names shown in IPL menu - char longTitle[64]; // Long game title shown in IPL game start screen - char longMaker[64]; // Long developer, publisher names shown in IPL game start screen - char comment[128]; // Game description shown in IPL game start screen in two lines. - }; + // Banner Comment + struct GCBannerComment + { + char shortTitle[32]; // Short game title shown in IPL menu + char shortMaker[32]; // Short developer, publisher names shown in IPL menu + char longTitle[64]; // Long game title shown in IPL game start screen + char longMaker[64]; // Long developer, publisher names shown in IPL game start screen + char comment[128]; // Game description shown in IPL game start screen in two lines. + }; - struct GCBanner - { - u32 id; // "BNR1" for NTSC, "BNR2" for PAL - u32 padding[7]; - u16 image[GC_BANNER_WIDTH * GC_BANNER_HEIGHT]; // RGB5A3 96x32 image - GCBannerComment comment[6]; // Comments in six languages (only one for BNR1 type) - }; + struct GCBanner + { + u32 id; // "BNR1" for NTSC, "BNR2" for PAL + u32 padding[7]; + u16 image[GC_BANNER_WIDTH * GC_BANNER_HEIGHT]; // RGB5A3 96x32 image + GCBannerComment comment[6]; // Comments in six languages (only one for BNR1 type) + }; - static const size_t BNR1_SIZE = sizeof(GCBanner) - sizeof(GCBannerComment) * 5; - static const size_t BNR2_SIZE = sizeof(GCBanner); + static const size_t BNR1_SIZE = sizeof(GCBanner) - sizeof(GCBannerComment) * 5; + static const size_t BNR2_SIZE = sizeof(GCBanner); - enum BannerFileType - { - BANNER_NOT_LOADED, - BANNER_INVALID, - BANNER_BNR1, - BANNER_BNR2 - }; + enum BannerFileType + { + BANNER_NOT_LOADED, + BANNER_INVALID, + BANNER_BNR1, + BANNER_BNR2 + }; - mutable BannerFileType m_banner_file_type = BANNER_NOT_LOADED; - mutable GCBanner m_banner_file; + mutable BannerFileType m_banner_file_type = BANNER_NOT_LOADED; + mutable GCBanner m_banner_file; - std::unique_ptr m_pReader; + std::unique_ptr m_pReader; }; -} // namespace +} // namespace diff --git a/Source/Core/DiscIO/VolumeWad.cpp b/Source/Core/DiscIO/VolumeWad.cpp index db6dc440a5..c86c490ed4 100644 --- a/Source/Core/DiscIO/VolumeWad.cpp +++ b/Source/Core/DiscIO/VolumeWad.cpp @@ -11,10 +11,10 @@ #include #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/MathUtil.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "DiscIO/Blob.h" #include "DiscIO/Volume.h" #include "DiscIO/VolumeWad.h" @@ -24,19 +24,19 @@ namespace DiscIO { CVolumeWAD::CVolumeWAD(std::unique_ptr reader) - : m_pReader(std::move(reader)), m_offset(0), m_tmd_offset(0), m_opening_bnr_offset(0), - m_hdr_size(0), m_cert_size(0), m_tick_size(0), m_tmd_size(0), m_data_size(0) + : m_pReader(std::move(reader)), m_offset(0), m_tmd_offset(0), m_opening_bnr_offset(0), + m_hdr_size(0), m_cert_size(0), m_tick_size(0), m_tmd_size(0), m_data_size(0) { - // Source: http://wiibrew.org/wiki/WAD_files - Read(0x00, 4, (u8*)&m_hdr_size); - Read(0x08, 4, (u8*)&m_cert_size); - Read(0x10, 4, (u8*)&m_tick_size); - Read(0x14, 4, (u8*)&m_tmd_size); - Read(0x18, 4, (u8*)&m_data_size); + // Source: http://wiibrew.org/wiki/WAD_files + Read(0x00, 4, (u8*)&m_hdr_size); + Read(0x08, 4, (u8*)&m_cert_size); + Read(0x10, 4, (u8*)&m_tick_size); + Read(0x14, 4, (u8*)&m_tmd_size); + Read(0x18, 4, (u8*)&m_data_size); - m_offset = ALIGN_40(m_hdr_size) + ALIGN_40(m_cert_size); - m_tmd_offset = ALIGN_40(m_hdr_size) + ALIGN_40(m_cert_size) + ALIGN_40(m_tick_size); - m_opening_bnr_offset = m_tmd_offset + ALIGN_40(m_tmd_size) + ALIGN_40(m_data_size); + m_offset = ALIGN_40(m_hdr_size) + ALIGN_40(m_cert_size); + m_tmd_offset = ALIGN_40(m_hdr_size) + ALIGN_40(m_cert_size) + ALIGN_40(m_tick_size); + m_opening_bnr_offset = m_tmd_offset + ALIGN_40(m_tmd_size) + ALIGN_40(m_data_size); } CVolumeWAD::~CVolumeWAD() @@ -45,119 +45,119 @@ CVolumeWAD::~CVolumeWAD() bool CVolumeWAD::Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt) const { - if (decrypt) - PanicAlertT("Tried to decrypt data from a non-Wii volume"); + if (decrypt) + PanicAlertT("Tried to decrypt data from a non-Wii volume"); - if (m_pReader == nullptr) - return false; + if (m_pReader == nullptr) + return false; - return m_pReader->Read(_Offset, _Length, _pBuffer); + return m_pReader->Read(_Offset, _Length, _pBuffer); } IVolume::ECountry CVolumeWAD::GetCountry() const { - if (!m_pReader) - return COUNTRY_UNKNOWN; + if (!m_pReader) + return COUNTRY_UNKNOWN; - // read the last digit of the titleID in the ticket - u8 country_code; - Read(m_tmd_offset + 0x0193, 1, &country_code); + // read the last digit of the titleID in the ticket + u8 country_code; + Read(m_tmd_offset + 0x0193, 1, &country_code); - if (country_code == 2) // SYSMENU - { - u16 title_version = 0; - Read(m_tmd_offset + 0x01dc, 2, (u8*)&title_version); - country_code = GetSysMenuRegion(Common::swap16(title_version)); - } + if (country_code == 2) // SYSMENU + { + u16 title_version = 0; + Read(m_tmd_offset + 0x01dc, 2, (u8*)&title_version); + country_code = GetSysMenuRegion(Common::swap16(title_version)); + } - return CountrySwitch(country_code); + return CountrySwitch(country_code); } std::string CVolumeWAD::GetUniqueID() const { - char GameCode[6]; - if (!Read(m_offset + 0x01E0, 4, (u8*)GameCode)) - return "0"; + char GameCode[6]; + if (!Read(m_offset + 0x01E0, 4, (u8*)GameCode)) + return "0"; - std::string temp = GetMakerID(); - GameCode[4] = temp.at(0); - GameCode[5] = temp.at(1); + std::string temp = GetMakerID(); + GameCode[4] = temp.at(0); + GameCode[5] = temp.at(1); - return DecodeString(GameCode); + return DecodeString(GameCode); } std::string CVolumeWAD::GetMakerID() const { - char temp[2] = {1}; - // Some weird channels use 0x0000 in place of the MakerID, so we need a check there - if (!Read(0x198 + m_tmd_offset, 2, (u8*)temp) || temp[0] == 0 || temp[1] == 0) - return "00"; + char temp[2] = {1}; + // Some weird channels use 0x0000 in place of the MakerID, so we need a check there + if (!Read(0x198 + m_tmd_offset, 2, (u8*)temp) || temp[0] == 0 || temp[1] == 0) + return "00"; - return DecodeString(temp); + return DecodeString(temp); } bool CVolumeWAD::GetTitleID(u64* buffer) const { - if (!Read(m_offset + 0x01DC, sizeof(u64), reinterpret_cast(buffer))) - return false; + if (!Read(m_offset + 0x01DC, sizeof(u64), reinterpret_cast(buffer))) + return false; - *buffer = Common::swap64(*buffer); - return true; + *buffer = Common::swap64(*buffer); + return true; } u16 CVolumeWAD::GetRevision() const { - u16 revision; - if (!m_pReader->Read(m_tmd_offset + 0x1dc, 2, (u8*)&revision)) - return 0; + u16 revision; + if (!m_pReader->Read(m_tmd_offset + 0x1dc, 2, (u8*)&revision)) + return 0; - return Common::swap16(revision); + return Common::swap16(revision); } IVolume::EPlatform CVolumeWAD::GetVolumeType() const { - return WII_WAD; + return WII_WAD; } std::map CVolumeWAD::GetNames(bool prefer_long) const { - std::vector name_data(NAMES_TOTAL_BYTES); - if (!Read(m_opening_bnr_offset + 0x9C, NAMES_TOTAL_BYTES, name_data.data())) - return std::map(); - return ReadWiiNames(name_data); + std::vector name_data(NAMES_TOTAL_BYTES); + if (!Read(m_opening_bnr_offset + 0x9C, NAMES_TOTAL_BYTES, name_data.data())) + return std::map(); + return ReadWiiNames(name_data); } std::vector CVolumeWAD::GetBanner(int* width, int* height) const { - *width = 0; - *height = 0; + *width = 0; + *height = 0; - u64 title_id; - if (!GetTitleID(&title_id)) - return std::vector(); + u64 title_id; + if (!GetTitleID(&title_id)) + return std::vector(); - return GetWiiBanner(width, height, title_id); + return GetWiiBanner(width, height, title_id); } BlobType CVolumeWAD::GetBlobType() const { - return m_pReader ? m_pReader->GetBlobType() : BlobType::PLAIN; + return m_pReader ? m_pReader->GetBlobType() : BlobType::PLAIN; } u64 CVolumeWAD::GetSize() const { - if (m_pReader) - return m_pReader->GetDataSize(); - else - return 0; + if (m_pReader) + return m_pReader->GetDataSize(); + else + return 0; } u64 CVolumeWAD::GetRawSize() const { - if (m_pReader) - return m_pReader->GetRawSize(); - else - return 0; + if (m_pReader) + return m_pReader->GetRawSize(); + else + return 0; } -} // namespace +} // namespace diff --git a/Source/Core/DiscIO/VolumeWad.h b/Source/Core/DiscIO/VolumeWad.h index ee0379fe5c..1b522a5a83 100644 --- a/Source/Core/DiscIO/VolumeWad.h +++ b/Source/Core/DiscIO/VolumeWad.h @@ -19,40 +19,38 @@ namespace DiscIO { - class CVolumeWAD : public IVolume { public: - CVolumeWAD(std::unique_ptr reader); - ~CVolumeWAD(); - bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt = false) const override; - bool GetTitleID(u64* buffer) const override; - std::string GetUniqueID() const override; - std::string GetMakerID() const override; - u16 GetRevision() const override; - std::string GetInternalName() const override { return ""; } - std::map GetNames(bool prefer_long) const override; - std::vector GetBanner(int* width, int* height) const override; - u64 GetFSTSize() const override { return 0; } - std::string GetApploaderDate() const override { return ""; } + CVolumeWAD(std::unique_ptr reader); + ~CVolumeWAD(); + bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt = false) const override; + bool GetTitleID(u64* buffer) const override; + std::string GetUniqueID() const override; + std::string GetMakerID() const override; + u16 GetRevision() const override; + std::string GetInternalName() const override { return ""; } + std::map GetNames(bool prefer_long) const override; + std::vector GetBanner(int* width, int* height) const override; + u64 GetFSTSize() const override { return 0; } + std::string GetApploaderDate() const override { return ""; } + EPlatform GetVolumeType() const override; + ECountry GetCountry() const override; - EPlatform GetVolumeType() const override; - ECountry GetCountry() const override; - - BlobType GetBlobType() const override; - u64 GetSize() const override; - u64 GetRawSize() const override; + BlobType GetBlobType() const override; + u64 GetSize() const override; + u64 GetRawSize() const override; private: - std::unique_ptr m_pReader; - u32 m_offset; - u32 m_tmd_offset; - u32 m_opening_bnr_offset; - u32 m_hdr_size; - u32 m_cert_size; - u32 m_tick_size; - u32 m_tmd_size; - u32 m_data_size; + std::unique_ptr m_pReader; + u32 m_offset; + u32 m_tmd_offset; + u32 m_opening_bnr_offset; + u32 m_hdr_size; + u32 m_cert_size; + u32 m_tick_size; + u32 m_tmd_size; + u32 m_data_size; }; -} // namespace +} // namespace diff --git a/Source/Core/DiscIO/VolumeWiiCrypted.cpp b/Source/Core/DiscIO/VolumeWiiCrypted.cpp index 3b06a45db2..fb0b14ec43 100644 --- a/Source/Core/DiscIO/VolumeWiiCrypted.cpp +++ b/Source/Core/DiscIO/VolumeWiiCrypted.cpp @@ -5,17 +5,17 @@ #include #include #include +#include +#include #include #include #include #include -#include -#include #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "DiscIO/Blob.h" #include "DiscIO/FileMonitor.h" #include "DiscIO/Filesystem.h" @@ -26,27 +26,23 @@ namespace DiscIO { - CVolumeWiiCrypted::CVolumeWiiCrypted(std::unique_ptr reader, u64 _VolumeOffset, - const unsigned char* _pVolumeKey) - : m_pReader(std::move(reader)), - m_AES_ctx(std::make_unique()), - m_VolumeOffset(_VolumeOffset), - m_dataOffset(0x20000), - m_LastDecryptedBlockOffset(-1) + const unsigned char* _pVolumeKey) + : m_pReader(std::move(reader)), m_AES_ctx(std::make_unique()), + m_VolumeOffset(_VolumeOffset), m_dataOffset(0x20000), m_LastDecryptedBlockOffset(-1) { - mbedtls_aes_setkey_dec(m_AES_ctx.get(), _pVolumeKey, 128); + mbedtls_aes_setkey_dec(m_AES_ctx.get(), _pVolumeKey, 128); } bool CVolumeWiiCrypted::ChangePartition(u64 offset) { - m_VolumeOffset = offset; - m_LastDecryptedBlockOffset = -1; + m_VolumeOffset = offset; + m_LastDecryptedBlockOffset = -1; - u8 volume_key[16]; - DiscIO::VolumeKeyForPartition(*m_pReader, offset, volume_key); - mbedtls_aes_setkey_dec(m_AES_ctx.get(), volume_key, 128); - return true; + u8 volume_key[16]; + DiscIO::VolumeKeyForPartition(*m_pReader, offset, volume_key); + mbedtls_aes_setkey_dec(m_AES_ctx.get(), volume_key, 128); + return true; } CVolumeWiiCrypted::~CVolumeWiiCrypted() @@ -55,334 +51,337 @@ CVolumeWiiCrypted::~CVolumeWiiCrypted() bool CVolumeWiiCrypted::Read(u64 _ReadOffset, u64 _Length, u8* _pBuffer, bool decrypt) const { - if (m_pReader == nullptr) - return false; + if (m_pReader == nullptr) + return false; - if (!decrypt) - return m_pReader->Read(_ReadOffset, _Length, _pBuffer); + if (!decrypt) + return m_pReader->Read(_ReadOffset, _Length, _pBuffer); - FileMon::FindFilename(_ReadOffset); + FileMon::FindFilename(_ReadOffset); - std::vector read_buffer(s_block_total_size); - while (_Length > 0) - { - // Calculate block offset - u64 Block = _ReadOffset / s_block_data_size; - u64 Offset = _ReadOffset % s_block_data_size; + std::vector read_buffer(s_block_total_size); + while (_Length > 0) + { + // Calculate block offset + u64 Block = _ReadOffset / s_block_data_size; + u64 Offset = _ReadOffset % s_block_data_size; - if (m_LastDecryptedBlockOffset != Block) - { - // Read the current block - if (!m_pReader->Read(m_VolumeOffset + m_dataOffset + Block * s_block_total_size, s_block_total_size, read_buffer.data())) - return false; + if (m_LastDecryptedBlockOffset != Block) + { + // Read the current block + if (!m_pReader->Read(m_VolumeOffset + m_dataOffset + Block * s_block_total_size, + s_block_total_size, read_buffer.data())) + return false; - // Decrypt the block's data. - // 0x3D0 - 0x3DF in m_pBuffer will be overwritten, - // but that won't affect anything, because we won't - // use the content of m_pBuffer anymore after this - mbedtls_aes_crypt_cbc(m_AES_ctx.get(), MBEDTLS_AES_DECRYPT, s_block_data_size, &read_buffer[0x3D0], - &read_buffer[s_block_header_size], m_LastDecryptedBlock); - m_LastDecryptedBlockOffset = Block; + // Decrypt the block's data. + // 0x3D0 - 0x3DF in m_pBuffer will be overwritten, + // but that won't affect anything, because we won't + // use the content of m_pBuffer anymore after this + mbedtls_aes_crypt_cbc(m_AES_ctx.get(), MBEDTLS_AES_DECRYPT, s_block_data_size, + &read_buffer[0x3D0], &read_buffer[s_block_header_size], + m_LastDecryptedBlock); + m_LastDecryptedBlockOffset = Block; - // The only thing we currently use from the 0x000 - 0x3FF part - // of the block is the IV (at 0x3D0), but it also contains SHA-1 - // hashes that IOS uses to check that discs aren't tampered with. - // http://wiibrew.org/wiki/Wii_Disc#Encrypted - } + // The only thing we currently use from the 0x000 - 0x3FF part + // of the block is the IV (at 0x3D0), but it also contains SHA-1 + // hashes that IOS uses to check that discs aren't tampered with. + // http://wiibrew.org/wiki/Wii_Disc#Encrypted + } - // Copy the decrypted data - u64 MaxSizeToCopy = s_block_data_size - Offset; - u64 CopySize = (_Length > MaxSizeToCopy) ? MaxSizeToCopy : _Length; - memcpy(_pBuffer, &m_LastDecryptedBlock[Offset], (size_t)CopySize); + // Copy the decrypted data + u64 MaxSizeToCopy = s_block_data_size - Offset; + u64 CopySize = (_Length > MaxSizeToCopy) ? MaxSizeToCopy : _Length; + memcpy(_pBuffer, &m_LastDecryptedBlock[Offset], (size_t)CopySize); - // Update offsets - _Length -= CopySize; - _pBuffer += CopySize; - _ReadOffset += CopySize; - } + // Update offsets + _Length -= CopySize; + _pBuffer += CopySize; + _ReadOffset += CopySize; + } - return true; + return true; } bool CVolumeWiiCrypted::GetTitleID(u64* buffer) const { - // Tik is at m_VolumeOffset size 0x2A4 - // TitleID offset in tik is 0x1DC - if (!Read(m_VolumeOffset + 0x1DC, sizeof(u64), reinterpret_cast(buffer), false)) - return false; + // Tik is at m_VolumeOffset size 0x2A4 + // TitleID offset in tik is 0x1DC + if (!Read(m_VolumeOffset + 0x1DC, sizeof(u64), reinterpret_cast(buffer), false)) + return false; - *buffer = Common::swap64(*buffer); - return true; + *buffer = Common::swap64(*buffer); + return true; } std::vector CVolumeWiiCrypted::GetTMD() const { - u32 tmd_size; - u32 tmd_address; + u32 tmd_size; + u32 tmd_address; - Read(m_VolumeOffset + 0x2a4, sizeof(u32), (u8*)&tmd_size, false); - Read(m_VolumeOffset + 0x2a8, sizeof(u32), (u8*)&tmd_address, false); - tmd_size = Common::swap32(tmd_size); - tmd_address = Common::swap32(tmd_address) << 2; + Read(m_VolumeOffset + 0x2a4, sizeof(u32), (u8*)&tmd_size, false); + Read(m_VolumeOffset + 0x2a8, sizeof(u32), (u8*)&tmd_address, false); + tmd_size = Common::swap32(tmd_size); + tmd_address = Common::swap32(tmd_address) << 2; - if (tmd_size > 1024 * 1024 * 4) - { - // The size is checked so that a malicious or corrupt ISO - // can't force Dolphin to allocate up to 4 GiB of memory. - // 4 MiB should be much bigger than the size of TMDs and much smaller - // than the amount of RAM in a computer that can run Dolphin. - PanicAlert("TMD > 4 MiB"); - tmd_size = 1024 * 1024 * 4; - } + if (tmd_size > 1024 * 1024 * 4) + { + // The size is checked so that a malicious or corrupt ISO + // can't force Dolphin to allocate up to 4 GiB of memory. + // 4 MiB should be much bigger than the size of TMDs and much smaller + // than the amount of RAM in a computer that can run Dolphin. + PanicAlert("TMD > 4 MiB"); + tmd_size = 1024 * 1024 * 4; + } - std::vector buffer(tmd_size); - Read(m_VolumeOffset + tmd_address, tmd_size, buffer.data(), false); + std::vector buffer(tmd_size); + Read(m_VolumeOffset + tmd_address, tmd_size, buffer.data(), false); - return buffer; + return buffer; } std::string CVolumeWiiCrypted::GetUniqueID() const { - if (m_pReader == nullptr) - return std::string(); + if (m_pReader == nullptr) + return std::string(); - char ID[6]; + char ID[6]; - if (!Read(0, 6, (u8*)ID, false)) - return std::string(); + if (!Read(0, 6, (u8*)ID, false)) + return std::string(); - return DecodeString(ID); + return DecodeString(ID); } - IVolume::ECountry CVolumeWiiCrypted::GetCountry() const { - if (!m_pReader) - return COUNTRY_UNKNOWN; + if (!m_pReader) + return COUNTRY_UNKNOWN; - u8 country_byte; - if (!m_pReader->Read(3, 1, &country_byte)) - { - return COUNTRY_UNKNOWN; - } + u8 country_byte; + if (!m_pReader->Read(3, 1, &country_byte)) + { + return COUNTRY_UNKNOWN; + } - IVolume::ECountry country_value = CountrySwitch(country_byte); + IVolume::ECountry country_value = CountrySwitch(country_byte); - u32 region_code; - if (!ReadSwapped(0x4E000, ®ion_code, false)) - { - return country_value; - } + u32 region_code; + if (!ReadSwapped(0x4E000, ®ion_code, false)) + { + return country_value; + } - switch (region_code) - { - case 0: - switch (country_value) - { - case IVolume::COUNTRY_TAIWAN: - return IVolume::COUNTRY_TAIWAN; - default: - return IVolume::COUNTRY_JAPAN; - } - case 1: - return IVolume::COUNTRY_USA; - case 2: - switch (country_value) - { - case IVolume::COUNTRY_FRANCE: - case IVolume::COUNTRY_GERMANY: - case IVolume::COUNTRY_ITALY: - case IVolume::COUNTRY_NETHERLANDS: - case IVolume::COUNTRY_RUSSIA: - case IVolume::COUNTRY_SPAIN: - case IVolume::COUNTRY_AUSTRALIA: - return country_value; - default: - return IVolume::COUNTRY_EUROPE; - } - case 4: - return IVolume::COUNTRY_KOREA; - default: - return country_value; - } + switch (region_code) + { + case 0: + switch (country_value) + { + case IVolume::COUNTRY_TAIWAN: + return IVolume::COUNTRY_TAIWAN; + default: + return IVolume::COUNTRY_JAPAN; + } + case 1: + return IVolume::COUNTRY_USA; + case 2: + switch (country_value) + { + case IVolume::COUNTRY_FRANCE: + case IVolume::COUNTRY_GERMANY: + case IVolume::COUNTRY_ITALY: + case IVolume::COUNTRY_NETHERLANDS: + case IVolume::COUNTRY_RUSSIA: + case IVolume::COUNTRY_SPAIN: + case IVolume::COUNTRY_AUSTRALIA: + return country_value; + default: + return IVolume::COUNTRY_EUROPE; + } + case 4: + return IVolume::COUNTRY_KOREA; + default: + return country_value; + } } std::string CVolumeWiiCrypted::GetMakerID() const { - if (m_pReader == nullptr) - return std::string(); + if (m_pReader == nullptr) + return std::string(); - char makerID[2]; + char makerID[2]; - if (!Read(0x4, 0x2, (u8*)&makerID, false)) - return std::string(); + if (!Read(0x4, 0x2, (u8*)&makerID, false)) + return std::string(); - return DecodeString(makerID); + return DecodeString(makerID); } u16 CVolumeWiiCrypted::GetRevision() const { - if (!m_pReader) - return 0; + if (!m_pReader) + return 0; - u8 revision; - if (!m_pReader->Read(7, 1, &revision)) - return 0; + u8 revision; + if (!m_pReader->Read(7, 1, &revision)) + return 0; - return revision; + return revision; } std::string CVolumeWiiCrypted::GetInternalName() const { - char name_buffer[0x60]; - if (m_pReader != nullptr && Read(0x20, 0x60, (u8*)&name_buffer, false)) - return DecodeString(name_buffer); + char name_buffer[0x60]; + if (m_pReader != nullptr && Read(0x20, 0x60, (u8*)&name_buffer, false)) + return DecodeString(name_buffer); - return ""; + return ""; } std::map CVolumeWiiCrypted::GetNames(bool prefer_long) const { - std::unique_ptr file_system(CreateFileSystem(this)); - std::vector opening_bnr(NAMES_TOTAL_BYTES); - opening_bnr.resize(file_system->ReadFile("opening.bnr", opening_bnr.data(), opening_bnr.size(), 0x5C)); - return ReadWiiNames(opening_bnr); + std::unique_ptr file_system(CreateFileSystem(this)); + std::vector opening_bnr(NAMES_TOTAL_BYTES); + opening_bnr.resize( + file_system->ReadFile("opening.bnr", opening_bnr.data(), opening_bnr.size(), 0x5C)); + return ReadWiiNames(opening_bnr); } std::vector CVolumeWiiCrypted::GetBanner(int* width, int* height) const { - *width = 0; - *height = 0; + *width = 0; + *height = 0; - u64 title_id; - if (!GetTitleID(&title_id)) - return std::vector(); + u64 title_id; + if (!GetTitleID(&title_id)) + return std::vector(); - return GetWiiBanner(width, height, title_id); + return GetWiiBanner(width, height, title_id); } u64 CVolumeWiiCrypted::GetFSTSize() const { - if (m_pReader == nullptr) - return 0; + if (m_pReader == nullptr) + return 0; - u32 size; + u32 size; - if (!Read(0x428, 0x4, (u8*)&size, true)) - return 0; + if (!Read(0x428, 0x4, (u8*)&size, true)) + return 0; - return (u64)Common::swap32(size) << 2; + return (u64)Common::swap32(size) << 2; } std::string CVolumeWiiCrypted::GetApploaderDate() const { - if (m_pReader == nullptr) - return std::string(); + if (m_pReader == nullptr) + return std::string(); - char date[16]; + char date[16]; - if (!Read(0x2440, 0x10, (u8*)&date, true)) - return std::string(); + if (!Read(0x2440, 0x10, (u8*)&date, true)) + return std::string(); - return DecodeString(date); + return DecodeString(date); } IVolume::EPlatform CVolumeWiiCrypted::GetVolumeType() const { - return WII_DISC; + return WII_DISC; } u8 CVolumeWiiCrypted::GetDiscNumber() const { - u8 disc_number; - m_pReader->Read(6, 1, &disc_number); - return disc_number; + u8 disc_number; + m_pReader->Read(6, 1, &disc_number); + return disc_number; } BlobType CVolumeWiiCrypted::GetBlobType() const { - return m_pReader ? m_pReader->GetBlobType() : BlobType::PLAIN; + return m_pReader ? m_pReader->GetBlobType() : BlobType::PLAIN; } u64 CVolumeWiiCrypted::GetSize() const { - if (m_pReader) - return m_pReader->GetDataSize(); - else - return 0; + if (m_pReader) + return m_pReader->GetDataSize(); + else + return 0; } u64 CVolumeWiiCrypted::GetRawSize() const { - if (m_pReader) - return m_pReader->GetRawSize(); - else - return 0; + if (m_pReader) + return m_pReader->GetRawSize(); + else + return 0; } bool CVolumeWiiCrypted::CheckIntegrity() const { - // Get partition data size - u32 partSizeDiv4; - Read(m_VolumeOffset + 0x2BC, 4, (u8*)&partSizeDiv4, false); - u64 partDataSize = (u64)Common::swap32(partSizeDiv4) * 4; + // Get partition data size + u32 partSizeDiv4; + Read(m_VolumeOffset + 0x2BC, 4, (u8*)&partSizeDiv4, false); + u64 partDataSize = (u64)Common::swap32(partSizeDiv4) * 4; - u32 nClusters = (u32)(partDataSize / 0x8000); - for (u32 clusterID = 0; clusterID < nClusters; ++clusterID) - { - u64 clusterOff = m_VolumeOffset + m_dataOffset + (u64)clusterID * 0x8000; + u32 nClusters = (u32)(partDataSize / 0x8000); + for (u32 clusterID = 0; clusterID < nClusters; ++clusterID) + { + u64 clusterOff = m_VolumeOffset + m_dataOffset + (u64)clusterID * 0x8000; - // Read and decrypt the cluster metadata - u8 clusterMDCrypted[0x400]; - u8 clusterMD[0x400]; - u8 IV[16] = { 0 }; - if (!m_pReader->Read(clusterOff, 0x400, clusterMDCrypted)) - { - NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: could not read metadata", clusterID); - return false; - } - mbedtls_aes_crypt_cbc(m_AES_ctx.get(), MBEDTLS_AES_DECRYPT, 0x400, IV, clusterMDCrypted, clusterMD); + // Read and decrypt the cluster metadata + u8 clusterMDCrypted[0x400]; + u8 clusterMD[0x400]; + u8 IV[16] = {0}; + if (!m_pReader->Read(clusterOff, 0x400, clusterMDCrypted)) + { + NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: could not read metadata", clusterID); + return false; + } + mbedtls_aes_crypt_cbc(m_AES_ctx.get(), MBEDTLS_AES_DECRYPT, 0x400, IV, clusterMDCrypted, + clusterMD); + // Some clusters have invalid data and metadata because they aren't + // meant to be read by the game (for example, holes between files). To + // try to avoid reporting errors because of these clusters, we check + // the 0x00 paddings in the metadata. + // + // This may cause some false negatives though: some bad clusters may be + // skipped because they are *too* bad and are not even recognized as + // valid clusters. To be improved. + bool meaningless = false; + for (u32 idx = 0x26C; idx < 0x280; ++idx) + if (clusterMD[idx] != 0) + meaningless = true; - // Some clusters have invalid data and metadata because they aren't - // meant to be read by the game (for example, holes between files). To - // try to avoid reporting errors because of these clusters, we check - // the 0x00 paddings in the metadata. - // - // This may cause some false negatives though: some bad clusters may be - // skipped because they are *too* bad and are not even recognized as - // valid clusters. To be improved. - bool meaningless = false; - for (u32 idx = 0x26C; idx < 0x280; ++idx) - if (clusterMD[idx] != 0) - meaningless = true; + if (meaningless) + continue; - if (meaningless) - continue; + u8 clusterData[0x7C00]; + if (!Read((u64)clusterID * 0x7C00, 0x7C00, clusterData, true)) + { + NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: could not read data", clusterID); + return false; + } - u8 clusterData[0x7C00]; - if (!Read((u64)clusterID * 0x7C00, 0x7C00, clusterData, true)) - { - NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: could not read data", clusterID); - return false; - } + for (u32 hashID = 0; hashID < 31; ++hashID) + { + u8 hash[20]; - for (u32 hashID = 0; hashID < 31; ++hashID) - { - u8 hash[20]; + mbedtls_sha1(clusterData + hashID * 0x400, 0x400, hash); - mbedtls_sha1(clusterData + hashID * 0x400, 0x400, hash); + // Note that we do not use strncmp here + if (memcmp(hash, clusterMD + hashID * 20, 20)) + { + NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: hash %d is invalid", clusterID, + hashID); + return false; + } + } + } - // Note that we do not use strncmp here - if (memcmp(hash, clusterMD + hashID * 20, 20)) - { - NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: hash %d is invalid", clusterID, hashID); - return false; - } - } - } - - return true; + return true; } -} // namespace +} // namespace diff --git a/Source/Core/DiscIO/VolumeWiiCrypted.h b/Source/Core/DiscIO/VolumeWiiCrypted.h index 8e0b2d88f8..34bc46b029 100644 --- a/Source/Core/DiscIO/VolumeWiiCrypted.h +++ b/Source/Core/DiscIO/VolumeWiiCrypted.h @@ -5,10 +5,10 @@ #pragma once #include +#include #include #include #include -#include #include "Common/CommonTypes.h" #include "DiscIO/Blob.h" @@ -18,48 +18,48 @@ namespace DiscIO { - class CVolumeWiiCrypted : public IVolume { public: - CVolumeWiiCrypted(std::unique_ptr reader, u64 _VolumeOffset, const unsigned char* _pVolumeKey); - ~CVolumeWiiCrypted(); - bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt) const override; - bool GetTitleID(u64* buffer) const override; - std::vector GetTMD() const override; - std::string GetUniqueID() const override; - std::string GetMakerID() const override; - u16 GetRevision() const override; - std::string GetInternalName() const override; - std::map GetNames(bool prefer_long) const override; - std::vector GetBanner(int* width, int* height) const override; - u64 GetFSTSize() const override; - std::string GetApploaderDate() const override; - u8 GetDiscNumber() const override; + CVolumeWiiCrypted(std::unique_ptr reader, u64 _VolumeOffset, + const unsigned char* _pVolumeKey); + ~CVolumeWiiCrypted(); + bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt) const override; + bool GetTitleID(u64* buffer) const override; + std::vector GetTMD() const override; + std::string GetUniqueID() const override; + std::string GetMakerID() const override; + u16 GetRevision() const override; + std::string GetInternalName() const override; + std::map GetNames(bool prefer_long) const override; + std::vector GetBanner(int* width, int* height) const override; + u64 GetFSTSize() const override; + std::string GetApploaderDate() const override; + u8 GetDiscNumber() const override; - EPlatform GetVolumeType() const override; - bool SupportsIntegrityCheck() const override { return true; } - bool CheckIntegrity() const override; - bool ChangePartition(u64 offset) override; + EPlatform GetVolumeType() const override; + bool SupportsIntegrityCheck() const override { return true; } + bool CheckIntegrity() const override; + bool ChangePartition(u64 offset) override; - ECountry GetCountry() const override; - BlobType GetBlobType() const override; - u64 GetSize() const override; - u64 GetRawSize() const override; + ECountry GetCountry() const override; + BlobType GetBlobType() const override; + u64 GetSize() const override; + u64 GetRawSize() const override; private: - static const unsigned int s_block_header_size = 0x0400; - static const unsigned int s_block_data_size = 0x7C00; - static const unsigned int s_block_total_size = s_block_header_size + s_block_data_size; + static const unsigned int s_block_header_size = 0x0400; + static const unsigned int s_block_data_size = 0x7C00; + static const unsigned int s_block_total_size = s_block_header_size + s_block_data_size; - std::unique_ptr m_pReader; - std::unique_ptr m_AES_ctx; + std::unique_ptr m_pReader; + std::unique_ptr m_AES_ctx; - u64 m_VolumeOffset; - u64 m_dataOffset; + u64 m_VolumeOffset; + u64 m_dataOffset; - mutable u64 m_LastDecryptedBlockOffset; - mutable unsigned char m_LastDecryptedBlock[s_block_data_size]; + mutable u64 m_LastDecryptedBlockOffset; + mutable unsigned char m_LastDecryptedBlock[s_block_data_size]; }; -} // namespace +} // namespace diff --git a/Source/Core/DiscIO/WbfsBlob.cpp b/Source/Core/DiscIO/WbfsBlob.cpp index ae0299f0f8..af244d9e68 100644 --- a/Source/Core/DiscIO/WbfsBlob.cpp +++ b/Source/Core/DiscIO/WbfsBlob.cpp @@ -12,8 +12,8 @@ #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "DiscIO/WbfsBlob.h" namespace DiscIO @@ -24,24 +24,25 @@ static const u64 WII_DISC_HEADER_SIZE = 256; static inline u64 align(u64 value, u64 bounds) { - return (value + (bounds - 1)) & (~(bounds - 1)); + return (value + (bounds - 1)) & (~(bounds - 1)); } WbfsFileReader::WbfsFileReader(const std::string& filename) - : m_total_files(0), m_size(0), m_good(true) + : m_total_files(0), m_size(0), m_good(true) { - if (filename.length() < 4 || !OpenFiles(filename) || !ReadHeader()) - { - m_good = false; - return; - } + if (filename.length() < 4 || !OpenFiles(filename) || !ReadHeader()) + { + m_good = false; + return; + } - // Grab disc info (assume slot 0, checked in ReadHeader()) - m_wlba_table.resize(m_blocks_per_disc); - m_files[0]->file.Seek(m_hd_sector_size + WII_DISC_HEADER_SIZE /*+ i * m_disc_info_size*/, SEEK_SET); - m_files[0]->file.ReadBytes(m_wlba_table.data(), m_blocks_per_disc * sizeof(u16)); - for (size_t i = 0; i < m_blocks_per_disc; i++) - m_wlba_table[i] = Common::swap16(m_wlba_table[i]); + // Grab disc info (assume slot 0, checked in ReadHeader()) + m_wlba_table.resize(m_blocks_per_disc); + m_files[0]->file.Seek(m_hd_sector_size + WII_DISC_HEADER_SIZE /*+ i * m_disc_info_size*/, + SEEK_SET); + m_files[0]->file.ReadBytes(m_wlba_table.data(), m_blocks_per_disc * sizeof(u16)); + for (size_t i = 0; i < m_blocks_per_disc; i++) + m_wlba_table[i] = Common::swap16(m_wlba_table[i]); } WbfsFileReader::~WbfsFileReader() @@ -50,140 +51,139 @@ WbfsFileReader::~WbfsFileReader() u64 WbfsFileReader::GetDataSize() const { - return WII_SECTOR_COUNT * WII_SECTOR_SIZE; + return WII_SECTOR_COUNT * WII_SECTOR_SIZE; } bool WbfsFileReader::OpenFiles(const std::string& filename) { - m_total_files = 0; + m_total_files = 0; - while (true) - { - auto new_entry = std::make_unique(); + while (true) + { + auto new_entry = std::make_unique(); - // Replace last character with index (e.g. wbfs = wbf1) - std::string path = filename; - if (m_total_files != 0) - { - path[path.length() - 1] = '0' + m_total_files; - } + // Replace last character with index (e.g. wbfs = wbf1) + std::string path = filename; + if (m_total_files != 0) + { + path[path.length() - 1] = '0' + m_total_files; + } - if (!new_entry->file.Open(path, "rb")) - { - return m_total_files != 0; - } + if (!new_entry->file.Open(path, "rb")) + { + return m_total_files != 0; + } - new_entry->base_address = m_size; - new_entry->size = new_entry->file.GetSize(); - m_size += new_entry->size; + new_entry->base_address = m_size; + new_entry->size = new_entry->file.GetSize(); + m_size += new_entry->size; - m_total_files++; - m_files.emplace_back(std::move(new_entry)); - } + m_total_files++; + m_files.emplace_back(std::move(new_entry)); + } } bool WbfsFileReader::ReadHeader() { - // Read hd size info - m_files[0]->file.ReadBytes(&m_header, sizeof(WbfsHeader)); - m_header.hd_sector_count = Common::swap32(m_header.hd_sector_count); + // Read hd size info + m_files[0]->file.ReadBytes(&m_header, sizeof(WbfsHeader)); + m_header.hd_sector_count = Common::swap32(m_header.hd_sector_count); - m_hd_sector_size = 1ull << m_header.hd_sector_shift; + m_hd_sector_size = 1ull << m_header.hd_sector_shift; - if (m_size != (m_header.hd_sector_count * m_hd_sector_size)) - return false; + if (m_size != (m_header.hd_sector_count * m_hd_sector_size)) + return false; - // Read wbfs cluster info - m_wbfs_sector_size = 1ull << m_header.wbfs_sector_shift; - m_wbfs_sector_count = m_size / m_wbfs_sector_size; + // Read wbfs cluster info + m_wbfs_sector_size = 1ull << m_header.wbfs_sector_shift; + m_wbfs_sector_count = m_size / m_wbfs_sector_size; - if (m_wbfs_sector_size < WII_SECTOR_SIZE) - return false; + if (m_wbfs_sector_size < WII_SECTOR_SIZE) + return false; - m_blocks_per_disc = (WII_SECTOR_COUNT * WII_SECTOR_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size; - m_disc_info_size = align(WII_DISC_HEADER_SIZE + m_blocks_per_disc * sizeof(u16), m_hd_sector_size); + m_blocks_per_disc = + (WII_SECTOR_COUNT * WII_SECTOR_SIZE + m_wbfs_sector_size - 1) / m_wbfs_sector_size; + m_disc_info_size = + align(WII_DISC_HEADER_SIZE + m_blocks_per_disc * sizeof(u16), m_hd_sector_size); - return m_header.disc_table[0] != 0; + return m_header.disc_table[0] != 0; } bool WbfsFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr) { - while (nbytes) - { - u64 read_size; - File::IOFile& data_file = SeekToCluster(offset, &read_size); - if (read_size == 0) - return false; - read_size = std::min(read_size, nbytes); + while (nbytes) + { + u64 read_size; + File::IOFile& data_file = SeekToCluster(offset, &read_size); + if (read_size == 0) + return false; + read_size = std::min(read_size, nbytes); - if (!data_file.ReadBytes(out_ptr, read_size)) - { - data_file.Clear(); - return false; - } + if (!data_file.ReadBytes(out_ptr, read_size)) + { + data_file.Clear(); + return false; + } - out_ptr += read_size; - nbytes -= read_size; - offset += read_size; - } + out_ptr += read_size; + nbytes -= read_size; + offset += read_size; + } - return true; + return true; } File::IOFile& WbfsFileReader::SeekToCluster(u64 offset, u64* available) { - u64 base_cluster = (offset >> m_header.wbfs_sector_shift); - if (base_cluster < m_blocks_per_disc) - { - u64 cluster_address = m_wbfs_sector_size * m_wlba_table[base_cluster]; - u64 cluster_offset = offset & (m_wbfs_sector_size - 1); - u64 final_address = cluster_address + cluster_offset; + u64 base_cluster = (offset >> m_header.wbfs_sector_shift); + if (base_cluster < m_blocks_per_disc) + { + u64 cluster_address = m_wbfs_sector_size * m_wlba_table[base_cluster]; + u64 cluster_offset = offset & (m_wbfs_sector_size - 1); + u64 final_address = cluster_address + cluster_offset; - for (u32 i = 0; i != m_total_files; i++) - { - if (final_address < (m_files[i]->base_address + m_files[i]->size)) - { - m_files[i]->file.Seek(final_address - m_files[i]->base_address, SEEK_SET); - if (available) - { - u64 till_end_of_file = m_files[i]->size - (final_address - m_files[i]->base_address); - u64 till_end_of_sector = m_wbfs_sector_size - cluster_offset; - *available = std::min(till_end_of_file, till_end_of_sector); - } + for (u32 i = 0; i != m_total_files; i++) + { + if (final_address < (m_files[i]->base_address + m_files[i]->size)) + { + m_files[i]->file.Seek(final_address - m_files[i]->base_address, SEEK_SET); + if (available) + { + u64 till_end_of_file = m_files[i]->size - (final_address - m_files[i]->base_address); + u64 till_end_of_sector = m_wbfs_sector_size - cluster_offset; + *available = std::min(till_end_of_file, till_end_of_sector); + } - return m_files[i]->file; - } - } - } + return m_files[i]->file; + } + } + } - PanicAlert("Read beyond end of disc"); - if (available) - *available = 0; - m_files[0]->file.Seek(0, SEEK_SET); - return m_files[0]->file; + PanicAlert("Read beyond end of disc"); + if (available) + *available = 0; + m_files[0]->file.Seek(0, SEEK_SET); + return m_files[0]->file; } std::unique_ptr WbfsFileReader::Create(const std::string& filename) { - auto reader = std::unique_ptr(new WbfsFileReader(filename)); + auto reader = std::unique_ptr(new WbfsFileReader(filename)); - if (!reader->IsGood()) - reader.reset(); + if (!reader->IsGood()) + reader.reset(); - return reader; + return reader; } bool IsWbfsBlob(const std::string& filename) { - File::IOFile f(filename, "rb"); + File::IOFile f(filename, "rb"); - u8 magic[4] = {0, 0, 0, 0}; - f.ReadBytes(&magic, 4); + u8 magic[4] = {0, 0, 0, 0}; + f.ReadBytes(&magic, 4); - return (magic[0] == 'W') && - (magic[1] == 'B') && - (magic[2] == 'F') && - (magic[3] == 'S'); + return (magic[0] == 'W') && (magic[1] == 'B') && (magic[2] == 'F') && (magic[3] == 'S'); } } // namespace diff --git a/Source/Core/DiscIO/WbfsBlob.h b/Source/Core/DiscIO/WbfsBlob.h index c3ae86a067..b7b2323950 100644 --- a/Source/Core/DiscIO/WbfsBlob.h +++ b/Source/Core/DiscIO/WbfsBlob.h @@ -14,70 +14,65 @@ namespace DiscIO { - class WbfsFileReader : public IBlobReader { public: - ~WbfsFileReader(); + ~WbfsFileReader(); - static std::unique_ptr Create(const std::string& filename); + static std::unique_ptr Create(const std::string& filename); - BlobType GetBlobType() const override { return BlobType::WBFS; } + BlobType GetBlobType() const override { return BlobType::WBFS; } + // The WBFS format does not save the original file size. + // This function returns a constant upper bound + // (the size of a double-layer Wii disc). + u64 GetDataSize() const override; - // The WBFS format does not save the original file size. - // This function returns a constant upper bound - // (the size of a double-layer Wii disc). - u64 GetDataSize() const override; - - u64 GetRawSize() const override { return m_size; } - bool Read(u64 offset, u64 nbytes, u8* out_ptr) override; + u64 GetRawSize() const override { return m_size; } + bool Read(u64 offset, u64 nbytes, u8* out_ptr) override; private: - WbfsFileReader(const std::string& filename); + WbfsFileReader(const std::string& filename); - bool OpenFiles(const std::string& filename); - bool ReadHeader(); + bool OpenFiles(const std::string& filename); + bool ReadHeader(); - File::IOFile& SeekToCluster(u64 offset, u64* available); - bool IsGood() {return m_good;} + File::IOFile& SeekToCluster(u64 offset, u64* available); + bool IsGood() { return m_good; } + struct file_entry + { + File::IOFile file; + u64 base_address; + u64 size; + }; + std::vector> m_files; - struct file_entry - { - File::IOFile file; - u64 base_address; - u64 size; - }; + u32 m_total_files; + u64 m_size; - std::vector> m_files; - - u32 m_total_files; - u64 m_size; - - u64 m_hd_sector_size; - u64 m_wbfs_sector_size; - u64 m_wbfs_sector_count; - u64 m_disc_info_size; + u64 m_hd_sector_size; + u64 m_wbfs_sector_size; + u64 m_wbfs_sector_count; + u64 m_disc_info_size; #pragma pack(1) - struct WbfsHeader - { - char magic[4]; - u32 hd_sector_count; - u8 hd_sector_shift; - u8 wbfs_sector_shift; - u8 padding[2]; - u8 disc_table[500]; - } m_header; + struct WbfsHeader + { + char magic[4]; + u32 hd_sector_count; + u8 hd_sector_shift; + u8 wbfs_sector_shift; + u8 padding[2]; + u8 disc_table[500]; + } m_header; #pragma pack() - std::vector m_wlba_table; - u64 m_blocks_per_disc; + std::vector m_wlba_table; + u64 m_blocks_per_disc; - bool m_good; + bool m_good; }; bool IsWbfsBlob(const std::string& filename); - } // namespace diff --git a/Source/Core/DiscIO/WiiWad.cpp b/Source/Core/DiscIO/WiiWad.cpp index 28c824237a..5e0894926d 100644 --- a/Source/Core/DiscIO/WiiWad.cpp +++ b/Source/Core/DiscIO/WiiWad.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - #include #include #include @@ -10,24 +9,23 @@ #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/MathUtil.h" #include "Common/Logging/Log.h" +#include "Common/MathUtil.h" #include "DiscIO/Blob.h" #include "DiscIO/WiiWad.h" namespace DiscIO { - WiiWAD::WiiWAD(const std::string& name) { - std::unique_ptr reader(CreateBlobReader(name)); - if (reader == nullptr || File::IsDirectory(name)) - { - m_valid = false; - return; - } + std::unique_ptr reader(CreateBlobReader(name)); + if (reader == nullptr || File::IsDirectory(name)) + { + m_valid = false; + return; + } - m_valid = ParseWAD(*reader); + m_valid = ParseWAD(*reader); } WiiWAD::~WiiWAD() @@ -36,63 +34,67 @@ WiiWAD::~WiiWAD() std::vector WiiWAD::CreateWADEntry(IBlobReader& reader, u32 size, u64 offset) { - if (size == 0) - return {}; + if (size == 0) + return {}; - std::vector buffer(size); + std::vector buffer(size); - if (!reader.Read(offset, size, buffer.data())) - { - ERROR_LOG(DISCIO, "WiiWAD: Could not read from file"); - PanicAlertT("WiiWAD: Could not read from file"); - } + if (!reader.Read(offset, size, buffer.data())) + { + ERROR_LOG(DISCIO, "WiiWAD: Could not read from file"); + PanicAlertT("WiiWAD: Could not read from file"); + } - return buffer; + return buffer; } - bool WiiWAD::ParseWAD(IBlobReader& reader) { - CBlobBigEndianReader big_endian_reader(reader); + CBlobBigEndianReader big_endian_reader(reader); - if (!IsWiiWAD(big_endian_reader)) - return false; + if (!IsWiiWAD(big_endian_reader)) + return false; - u32 certificate_chain_size; - u32 reserved; - u32 ticket_size; - u32 tmd_size; - u32 data_app_size; - u32 footer_size; + u32 certificate_chain_size; + u32 reserved; + u32 ticket_size; + u32 tmd_size; + u32 data_app_size; + u32 footer_size; - if (!big_endian_reader.ReadSwapped(0x08, &certificate_chain_size) || - !big_endian_reader.ReadSwapped(0x0C, &reserved) || - !big_endian_reader.ReadSwapped(0x10, &ticket_size) || - !big_endian_reader.ReadSwapped(0x14, &tmd_size) || - !big_endian_reader.ReadSwapped(0x18, &data_app_size) || - !big_endian_reader.ReadSwapped(0x1C, &footer_size)) - return false; + if (!big_endian_reader.ReadSwapped(0x08, &certificate_chain_size) || + !big_endian_reader.ReadSwapped(0x0C, &reserved) || + !big_endian_reader.ReadSwapped(0x10, &ticket_size) || + !big_endian_reader.ReadSwapped(0x14, &tmd_size) || + !big_endian_reader.ReadSwapped(0x18, &data_app_size) || + !big_endian_reader.ReadSwapped(0x1C, &footer_size)) + return false; - if (MAX_LOGLEVEL >= LogTypes::LOG_LEVELS::LDEBUG) - _dbg_assert_msg_(BOOT, reserved == 0x00, "WiiWAD: Reserved must be 0x00"); + if (MAX_LOGLEVEL >= LogTypes::LOG_LEVELS::LDEBUG) + _dbg_assert_msg_(BOOT, reserved == 0x00, "WiiWAD: Reserved must be 0x00"); - u32 offset = 0x40; - m_certificate_chain = CreateWADEntry(reader, certificate_chain_size, offset); offset += ROUND_UP(certificate_chain_size, 0x40); - m_ticket = CreateWADEntry(reader, ticket_size, offset); offset += ROUND_UP(ticket_size, 0x40); - m_tmd = CreateWADEntry(reader, tmd_size, offset); offset += ROUND_UP(tmd_size, 0x40); - m_data_app = CreateWADEntry(reader, data_app_size, offset); offset += ROUND_UP(data_app_size, 0x40); - m_footer = CreateWADEntry(reader, footer_size, offset); offset += ROUND_UP(footer_size, 0x40); + u32 offset = 0x40; + m_certificate_chain = CreateWADEntry(reader, certificate_chain_size, offset); + offset += ROUND_UP(certificate_chain_size, 0x40); + m_ticket = CreateWADEntry(reader, ticket_size, offset); + offset += ROUND_UP(ticket_size, 0x40); + m_tmd = CreateWADEntry(reader, tmd_size, offset); + offset += ROUND_UP(tmd_size, 0x40); + m_data_app = CreateWADEntry(reader, data_app_size, offset); + offset += ROUND_UP(data_app_size, 0x40); + m_footer = CreateWADEntry(reader, footer_size, offset); + offset += ROUND_UP(footer_size, 0x40); - return true; + return true; } bool WiiWAD::IsWiiWAD(const CBlobBigEndianReader& reader) { - u32 header_size = 0; - u32 header_type = 0; - reader.ReadSwapped(0x0, &header_size); - reader.ReadSwapped(0x4, &header_type); - return header_size == 0x20 && (header_type == 0x49730000 || header_type == 0x69620000); + u32 header_size = 0; + u32 header_type = 0; + reader.ReadSwapped(0x0, &header_size); + reader.ReadSwapped(0x4, &header_type); + return header_size == 0x20 && (header_type == 0x49730000 || header_type == 0x69620000); } -} // namespace end +} // namespace end diff --git a/Source/Core/DiscIO/WiiWad.h b/Source/Core/DiscIO/WiiWad.h index 466f17b970..454454a71f 100644 --- a/Source/Core/DiscIO/WiiWad.h +++ b/Source/Core/DiscIO/WiiWad.h @@ -11,36 +11,32 @@ namespace DiscIO { - class IBlobReader; class CBlobBigEndianReader; class WiiWAD { public: - WiiWAD(const std::string& name); - ~WiiWAD(); - - bool IsValid() const { return m_valid; } - - const std::vector& GetCertificateChain() const { return m_certificate_chain; } - const std::vector& GetTicket() const { return m_ticket; } - const std::vector& GetTMD() const { return m_tmd; } - const std::vector& GetDataApp() const { return m_data_app; } - const std::vector& GetFooter() const { return m_footer; } + WiiWAD(const std::string& name); + ~WiiWAD(); + bool IsValid() const { return m_valid; } + const std::vector& GetCertificateChain() const { return m_certificate_chain; } + const std::vector& GetTicket() const { return m_ticket; } + const std::vector& GetTMD() const { return m_tmd; } + const std::vector& GetDataApp() const { return m_data_app; } + const std::vector& GetFooter() const { return m_footer; } private: - bool ParseWAD(IBlobReader& reader); - static std::vector CreateWADEntry(IBlobReader& reader, u32 size, u64 offset); - static bool IsWiiWAD(const CBlobBigEndianReader& reader); + bool ParseWAD(IBlobReader& reader); + static std::vector CreateWADEntry(IBlobReader& reader, u32 size, u64 offset); + static bool IsWiiWAD(const CBlobBigEndianReader& reader); - bool m_valid; + bool m_valid; - std::vector m_certificate_chain; - std::vector m_ticket; - std::vector m_tmd; - std::vector m_data_app; - std::vector m_footer; + std::vector m_certificate_chain; + std::vector m_ticket; + std::vector m_tmd; + std::vector m_data_app; + std::vector m_footer; }; - } diff --git a/Source/Core/DolphinQt2/AboutDialog.cpp b/Source/Core/DolphinQt2/AboutDialog.cpp index bc7d988feb..b6bb1e06e2 100644 --- a/Source/Core/DolphinQt2/AboutDialog.cpp +++ b/Source/Core/DolphinQt2/AboutDialog.cpp @@ -10,59 +10,67 @@ #include "DolphinQt2/AboutDialog.h" #include "DolphinQt2/Resources.h" -AboutDialog::AboutDialog(QWidget* parent) - : QDialog(parent) +AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent) { - setWindowTitle(tr("About Dolphin")); - setAttribute(Qt::WA_DeleteOnClose); + setWindowTitle(tr("About Dolphin")); + setAttribute(Qt::WA_DeleteOnClose); - QString text = QStringLiteral(""); - QString small = QStringLiteral("

"); - QString medium = QStringLiteral("

"); + QString text = QStringLiteral(""); + QString small = QStringLiteral("

"); + QString medium = QStringLiteral("

"); - text.append(QStringLiteral("

") + - tr("Dolphin") + QStringLiteral("

")); - text.append(QStringLiteral("

%1

") - .arg(QString::fromUtf8(scm_desc_str.c_str()))); + text.append(QStringLiteral("

") + + tr("Dolphin") + QStringLiteral("

")); + text.append(QStringLiteral("

%1

") + .arg(QString::fromUtf8(scm_desc_str.c_str()))); - text.append(small + tr("Branch: ") + QString::fromUtf8(scm_branch_str.c_str()) + QStringLiteral("

")); - text.append(small + tr("Revision: ") + QString::fromUtf8(scm_rev_git_str.c_str()) + QStringLiteral("

")); - text.append(small + tr("Compiled: ") + QStringLiteral(__DATE__ " " __TIME__ "

")); + text.append(small + tr("Branch: ") + QString::fromUtf8(scm_branch_str.c_str()) + + QStringLiteral("

")); + text.append(small + tr("Revision: ") + QString::fromUtf8(scm_rev_git_str.c_str()) + + QStringLiteral("

")); + text.append(small + tr("Compiled: ") + QStringLiteral(__DATE__ " " __TIME__ "

")); - text.append(medium + tr("Check for updates: ") + - QStringLiteral("dolphin-emu.org/download

")); - text.append(medium + tr("Dolphin is a free and open-source GameCube and Wii emulator.") + QStringLiteral("

")); - text.append(medium + tr("This software should not be used to play games you do not legally own.") + QStringLiteral("

")); - text.append(medium + QStringLiteral( - "%1 | " - "%2 | " - "%3

" - ).arg(tr("Licence")).arg(tr("Authors")).arg(tr("Support"))); + text.append(medium + tr("Check for updates: ") + + QStringLiteral( + "dolphin-emu.org/download

")); + text.append(medium + tr("Dolphin is a free and open-source GameCube and Wii emulator.") + + QStringLiteral("

")); + text.append(medium + + tr("This software should not be used to play games you do not legally own.") + + QStringLiteral("

")); + text.append( + medium + + QStringLiteral( + "%1 | " + "%2 | " + "%3

") + .arg(tr("Licence")) + .arg(tr("Authors")) + .arg(tr("Support"))); - QLabel* text_label = new QLabel(text); - text_label->setTextInteractionFlags(Qt::TextBrowserInteraction); - text_label->setOpenExternalLinks(true); + QLabel* text_label = new QLabel(text); + text_label->setTextInteractionFlags(Qt::TextBrowserInteraction); + text_label->setOpenExternalLinks(true); - QLabel* copyright = new QLabel(tr( - "© 2003-%1 Dolphin Team. “GameCube” and “Wii” are" - " trademarks of Nintendo. Dolphin is not affiliated with Nintendo in any way." - ).arg(QStringLiteral(__DATE__).right(4))); + QLabel* copyright = + new QLabel(tr("© 2003-%1 Dolphin Team. “GameCube” and “Wii” are" + " trademarks of Nintendo. Dolphin is not affiliated with Nintendo in any way.") + .arg(QStringLiteral(__DATE__).right(4))); - QLabel* logo = new QLabel(); - logo->setPixmap(Resources::GetMisc(Resources::LOGO_LARGE)); - logo->setContentsMargins(30, 0, 30, 0); + QLabel* logo = new QLabel(); + logo->setPixmap(Resources::GetMisc(Resources::LOGO_LARGE)); + logo->setContentsMargins(30, 0, 30, 0); - QVBoxLayout* main_layout = new QVBoxLayout; - QHBoxLayout* h_layout = new QHBoxLayout; + QVBoxLayout* main_layout = new QVBoxLayout; + QHBoxLayout* h_layout = new QHBoxLayout; - setLayout(main_layout); - main_layout->addLayout(h_layout); - main_layout->addWidget(copyright); - copyright->setAlignment(Qt::AlignCenter); - copyright->setContentsMargins(0, 15, 0, 0); + setLayout(main_layout); + main_layout->addLayout(h_layout); + main_layout->addWidget(copyright); + copyright->setAlignment(Qt::AlignCenter); + copyright->setContentsMargins(0, 15, 0, 0); - h_layout->setAlignment(Qt::AlignLeft); - h_layout->addWidget(logo); - h_layout->addWidget(text_label); + h_layout->setAlignment(Qt::AlignLeft); + h_layout->addWidget(logo); + h_layout->addWidget(text_label); } - diff --git a/Source/Core/DolphinQt2/AboutDialog.h b/Source/Core/DolphinQt2/AboutDialog.h index 812e6ce807..fdb27530c0 100644 --- a/Source/Core/DolphinQt2/AboutDialog.h +++ b/Source/Core/DolphinQt2/AboutDialog.h @@ -8,8 +8,7 @@ class AboutDialog final : public QDialog { - Q_OBJECT + Q_OBJECT public: - explicit AboutDialog(QWidget* parent = nullptr); + explicit AboutDialog(QWidget* parent = nullptr); }; - diff --git a/Source/Core/DolphinQt2/Config/PathDialog.cpp b/Source/Core/DolphinQt2/Config/PathDialog.cpp index 112baaf0b0..1f0a73a635 100644 --- a/Source/Core/DolphinQt2/Config/PathDialog.cpp +++ b/Source/Core/DolphinQt2/Config/PathDialog.cpp @@ -14,171 +14,163 @@ #include #include -#include "DolphinQt2/Settings.h" #include "DolphinQt2/Config/PathDialog.h" +#include "DolphinQt2/Settings.h" -PathDialog::PathDialog(QWidget* parent) - : QDialog(parent) +PathDialog::PathDialog(QWidget* parent) : QDialog(parent) { - setWindowTitle(tr("Paths")); + setWindowTitle(tr("Paths")); - QVBoxLayout* layout = new QVBoxLayout; - layout->addWidget(MakeGameFolderBox()); - layout->addLayout(MakePathsLayout()); + QVBoxLayout* layout = new QVBoxLayout; + layout->addWidget(MakeGameFolderBox()); + layout->addLayout(MakePathsLayout()); - QDialogButtonBox* ok_box = new QDialogButtonBox(QDialogButtonBox::Ok); - connect(ok_box, &QDialogButtonBox::accepted, this, &PathDialog::accept); - layout->addWidget(ok_box); + QDialogButtonBox* ok_box = new QDialogButtonBox(QDialogButtonBox::Ok); + connect(ok_box, &QDialogButtonBox::accepted, this, &PathDialog::accept); + layout->addWidget(ok_box); - setLayout(layout); + setLayout(layout); } void PathDialog::Browse() { - QString dir = QFileDialog::getExistingDirectory(this, - tr("Select a Directory"), - QDir::currentPath()); - if (!dir.isEmpty()) - { - Settings settings; - QStringList game_folders = settings.GetPaths(); - if (!game_folders.contains(dir)) - { - game_folders << dir; - settings.SetPaths(game_folders); - m_path_list->addItem(dir); - emit PathAdded(dir); - } - } + QString dir = + QFileDialog::getExistingDirectory(this, tr("Select a Directory"), QDir::currentPath()); + if (!dir.isEmpty()) + { + Settings settings; + QStringList game_folders = settings.GetPaths(); + if (!game_folders.contains(dir)) + { + game_folders << dir; + settings.SetPaths(game_folders); + m_path_list->addItem(dir); + emit PathAdded(dir); + } + } } void PathDialog::BrowseDefaultGame() { - QString file = QFileDialog::getOpenFileName(this, - tr("Select a Game"), - QDir::currentPath(), - tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.wbfs *.ciso *.gcz *.wad);;" - "All Files (*)")); - if (!file.isEmpty()) - { - m_game_edit->setText(file); - Settings().SetDefaultGame(file); - } + QString file = QFileDialog::getOpenFileName( + this, tr("Select a Game"), QDir::currentPath(), + tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.wbfs *.ciso *.gcz *.wad);;" + "All Files (*)")); + if (!file.isEmpty()) + { + m_game_edit->setText(file); + Settings().SetDefaultGame(file); + } } void PathDialog::BrowseDVDRoot() { - QString dir = QFileDialog::getExistingDirectory(this, - tr("Select DVD Root"), - QDir::currentPath()); - if (!dir.isEmpty()) - { - m_dvd_edit->setText(dir); - Settings().SetDVDRoot(dir); - } + QString dir = QFileDialog::getExistingDirectory(this, tr("Select DVD Root"), QDir::currentPath()); + if (!dir.isEmpty()) + { + m_dvd_edit->setText(dir); + Settings().SetDVDRoot(dir); + } } void PathDialog::BrowseApploader() { - QString file = QFileDialog::getOpenFileName(this, - tr("Select an Apploader"), - QDir::currentPath(), - tr("Apploaders (*.img)")); - if (!file.isEmpty()) - { - m_app_edit->setText(file); - Settings().SetApploader(file); - } + QString file = QFileDialog::getOpenFileName(this, tr("Select an Apploader"), QDir::currentPath(), + tr("Apploaders (*.img)")); + if (!file.isEmpty()) + { + m_app_edit->setText(file); + Settings().SetApploader(file); + } } void PathDialog::BrowseWiiNAND() { - QString dir = QFileDialog::getExistingDirectory(this, - tr("Select Wii NAND Root"), - QDir::currentPath()); - if (!dir.isEmpty()) - { - m_nand_edit->setText(dir); - Settings().SetWiiNAND(dir); - } + QString dir = + QFileDialog::getExistingDirectory(this, tr("Select Wii NAND Root"), QDir::currentPath()); + if (!dir.isEmpty()) + { + m_nand_edit->setText(dir); + Settings().SetWiiNAND(dir); + } } QGroupBox* PathDialog::MakeGameFolderBox() { - QGroupBox* game_box = new QGroupBox(tr("Game Folders")); - game_box->setMinimumSize(QSize(400, 250)); - QVBoxLayout* vlayout = new QVBoxLayout; + QGroupBox* game_box = new QGroupBox(tr("Game Folders")); + game_box->setMinimumSize(QSize(400, 250)); + QVBoxLayout* vlayout = new QVBoxLayout; - m_path_list = new QListWidget; - m_path_list->insertItems(0, Settings().GetPaths()); - m_path_list->setSpacing(1); - vlayout->addWidget(m_path_list); + m_path_list = new QListWidget; + m_path_list->insertItems(0, Settings().GetPaths()); + m_path_list->setSpacing(1); + vlayout->addWidget(m_path_list); - QHBoxLayout* hlayout = new QHBoxLayout; + QHBoxLayout* hlayout = new QHBoxLayout; - hlayout->addStretch(); - QPushButton* add = new QPushButton(tr("Add")); - QPushButton* remove = new QPushButton(tr("Remove")); - hlayout->addWidget(add); - hlayout->addWidget(remove); - vlayout->addLayout(hlayout); + hlayout->addStretch(); + QPushButton* add = new QPushButton(tr("Add")); + QPushButton* remove = new QPushButton(tr("Remove")); + hlayout->addWidget(add); + hlayout->addWidget(remove); + vlayout->addLayout(hlayout); - connect(add, &QPushButton::clicked, this, &PathDialog::Browse); - connect(remove, &QPushButton::clicked, this, &PathDialog::RemovePath); + connect(add, &QPushButton::clicked, this, &PathDialog::Browse); + connect(remove, &QPushButton::clicked, this, &PathDialog::RemovePath); - game_box->setLayout(vlayout); - return game_box; + game_box->setLayout(vlayout); + return game_box; } QGridLayout* PathDialog::MakePathsLayout() { - QGridLayout* layout = new QGridLayout; - layout->setColumnStretch(1, 1); + QGridLayout* layout = new QGridLayout; + layout->setColumnStretch(1, 1); - m_game_edit = new QLineEdit(Settings().GetDefaultGame()); - connect(m_game_edit, &QLineEdit::editingFinished, - [=]{ Settings().SetDefaultGame(m_game_edit->text()); }); - QPushButton* game_open = new QPushButton; - connect(game_open, &QPushButton::clicked, this, &PathDialog::BrowseDefaultGame); - layout->addWidget(new QLabel(tr("Default Game")), 0, 0); - layout->addWidget(m_game_edit, 0, 1); - layout->addWidget(game_open, 0, 2); + m_game_edit = new QLineEdit(Settings().GetDefaultGame()); + connect(m_game_edit, &QLineEdit::editingFinished, + [=] { Settings().SetDefaultGame(m_game_edit->text()); }); + QPushButton* game_open = new QPushButton; + connect(game_open, &QPushButton::clicked, this, &PathDialog::BrowseDefaultGame); + layout->addWidget(new QLabel(tr("Default Game")), 0, 0); + layout->addWidget(m_game_edit, 0, 1); + layout->addWidget(game_open, 0, 2); - m_dvd_edit = new QLineEdit(Settings().GetDVDRoot()); - connect(m_dvd_edit, &QLineEdit::editingFinished, - [=]{ Settings().SetDVDRoot(m_dvd_edit->text()); }); - QPushButton* dvd_open = new QPushButton; - connect(dvd_open, &QPushButton::clicked, this, &PathDialog::BrowseDVDRoot); - layout->addWidget(new QLabel(tr("DVD Root")), 1, 0); - layout->addWidget(m_dvd_edit, 1, 1); - layout->addWidget(dvd_open, 1, 2); + m_dvd_edit = new QLineEdit(Settings().GetDVDRoot()); + connect(m_dvd_edit, &QLineEdit::editingFinished, + [=] { Settings().SetDVDRoot(m_dvd_edit->text()); }); + QPushButton* dvd_open = new QPushButton; + connect(dvd_open, &QPushButton::clicked, this, &PathDialog::BrowseDVDRoot); + layout->addWidget(new QLabel(tr("DVD Root")), 1, 0); + layout->addWidget(m_dvd_edit, 1, 1); + layout->addWidget(dvd_open, 1, 2); - m_app_edit = new QLineEdit(Settings().GetApploader()); - connect(m_app_edit, &QLineEdit::editingFinished, - [=]{ Settings().SetApploader(m_app_edit->text()); }); - QPushButton* app_open = new QPushButton; - connect(app_open, &QPushButton::clicked, this, &PathDialog::BrowseApploader); - layout->addWidget(new QLabel(tr("Apploader")), 2, 0); - layout->addWidget(m_app_edit, 2, 1); - layout->addWidget(app_open, 2, 2); + m_app_edit = new QLineEdit(Settings().GetApploader()); + connect(m_app_edit, &QLineEdit::editingFinished, + [=] { Settings().SetApploader(m_app_edit->text()); }); + QPushButton* app_open = new QPushButton; + connect(app_open, &QPushButton::clicked, this, &PathDialog::BrowseApploader); + layout->addWidget(new QLabel(tr("Apploader")), 2, 0); + layout->addWidget(m_app_edit, 2, 1); + layout->addWidget(app_open, 2, 2); - m_nand_edit = new QLineEdit(Settings().GetWiiNAND()); - connect(m_nand_edit, &QLineEdit::editingFinished, - [=]{ Settings().SetWiiNAND(m_nand_edit->text()); }); - QPushButton* nand_open = new QPushButton; - connect(nand_open, &QPushButton::clicked, this, &PathDialog::BrowseWiiNAND); - layout->addWidget(new QLabel(tr("Wii NAND Root")), 3, 0); - layout->addWidget(m_nand_edit, 3, 1); - layout->addWidget(nand_open, 3, 2); + m_nand_edit = new QLineEdit(Settings().GetWiiNAND()); + connect(m_nand_edit, &QLineEdit::editingFinished, + [=] { Settings().SetWiiNAND(m_nand_edit->text()); }); + QPushButton* nand_open = new QPushButton; + connect(nand_open, &QPushButton::clicked, this, &PathDialog::BrowseWiiNAND); + layout->addWidget(new QLabel(tr("Wii NAND Root")), 3, 0); + layout->addWidget(m_nand_edit, 3, 1); + layout->addWidget(nand_open, 3, 2); - return layout; + return layout; } void PathDialog::RemovePath() { - int row = m_path_list->currentRow(); - if (row < 0) - return; - emit PathRemoved(m_path_list->takeItem(row)->text()); - Settings().RemovePath(row); + int row = m_path_list->currentRow(); + if (row < 0) + return; + emit PathRemoved(m_path_list->takeItem(row)->text()); + Settings().RemovePath(row); } diff --git a/Source/Core/DolphinQt2/Config/PathDialog.h b/Source/Core/DolphinQt2/Config/PathDialog.h index f7202d4b81..a486889680 100644 --- a/Source/Core/DolphinQt2/Config/PathDialog.h +++ b/Source/Core/DolphinQt2/Config/PathDialog.h @@ -12,29 +12,29 @@ class PathDialog final : public QDialog { - Q_OBJECT + Q_OBJECT public: - explicit PathDialog(QWidget* parent = nullptr); + explicit PathDialog(QWidget* parent = nullptr); public slots: - void Browse(); - void BrowseDefaultGame(); - void BrowseDVDRoot(); - void BrowseApploader(); - void BrowseWiiNAND(); + void Browse(); + void BrowseDefaultGame(); + void BrowseDVDRoot(); + void BrowseApploader(); + void BrowseWiiNAND(); signals: - void PathAdded(QString path); - void PathRemoved(QString path); + void PathAdded(QString path); + void PathRemoved(QString path); private: - QGroupBox* MakeGameFolderBox(); - QGridLayout* MakePathsLayout(); - void RemovePath(); + QGroupBox* MakeGameFolderBox(); + QGridLayout* MakePathsLayout(); + void RemovePath(); - QListWidget* m_path_list; - QLineEdit* m_game_edit; - QLineEdit* m_dvd_edit; - QLineEdit* m_app_edit; - QLineEdit* m_nand_edit; + QListWidget* m_path_list; + QLineEdit* m_game_edit; + QLineEdit* m_dvd_edit; + QLineEdit* m_app_edit; + QLineEdit* m_nand_edit; }; diff --git a/Source/Core/DolphinQt2/Config/SettingsWindow.cpp b/Source/Core/DolphinQt2/Config/SettingsWindow.cpp index 03c6b93c92..5992dcfdfe 100644 --- a/Source/Core/DolphinQt2/Config/SettingsWindow.cpp +++ b/Source/Core/DolphinQt2/Config/SettingsWindow.cpp @@ -5,89 +5,87 @@ #include "DolphinQt2/Settings.h" #include "DolphinQt2/Config/SettingsWindow.h" -SettingsWindow::SettingsWindow(QWidget* parent) - : QDialog(parent) +SettingsWindow::SettingsWindow(QWidget* parent) : QDialog(parent) { - // Set Window Properties - setWindowTitle(tr("Settings")); - resize(720, 600); + // Set Window Properties + setWindowTitle(tr("Settings")); + resize(720, 600); - // Main Layout - QVBoxLayout* layout = new QVBoxLayout; - QHBoxLayout* content = new QHBoxLayout; - QVBoxLayout* content_inner = new QVBoxLayout; - // Content's widgets - { - // Category list - MakeCategoryList(); - content->addWidget(m_categories); + // Main Layout + QVBoxLayout* layout = new QVBoxLayout; + QHBoxLayout* content = new QHBoxLayout; + QVBoxLayout* content_inner = new QVBoxLayout; + // Content's widgets + { + // Category list + MakeCategoryList(); + content->addWidget(m_categories); - // Actual Settings UI - SetupSettingsWidget(); + // Actual Settings UI + SetupSettingsWidget(); - MakeUnfinishedWarning(); + MakeUnfinishedWarning(); - content_inner->addWidget(m_warning_group); - content_inner->addWidget(m_settings_outer); + content_inner->addWidget(m_warning_group); + content_inner->addWidget(m_settings_outer); - content->addLayout(content_inner); - } + content->addLayout(content_inner); + } - // Add content to layout before dialog buttons. - layout->addLayout(content); + // Add content to layout before dialog buttons. + layout->addLayout(content); - // Dialog box buttons - QDialogButtonBox* ok_box = new QDialogButtonBox(QDialogButtonBox::Ok); - connect(ok_box, &QDialogButtonBox::accepted, this, &SettingsWindow::accept); - layout->addWidget(ok_box); + // Dialog box buttons + QDialogButtonBox* ok_box = new QDialogButtonBox(QDialogButtonBox::Ok); + connect(ok_box, &QDialogButtonBox::accepted, this, &SettingsWindow::accept); + layout->addWidget(ok_box); - setLayout(layout); + setLayout(layout); } void SettingsWindow::SetupSettingsWidget() { - m_settings_outer = new QStackedWidget; - m_settings_outer->setCurrentIndex(0); + m_settings_outer = new QStackedWidget; + m_settings_outer->setCurrentIndex(0); } void SettingsWindow::MakeUnfinishedWarning() { - m_warning_group = new QGroupBox(tr("Warning")); - QHBoxLayout* m_warning_group_layout = new QHBoxLayout; - QLabel* warning_text = new QLabel( - tr("Some categories and settings will not work.\n" - "This Settings Window is under active development.")); - m_warning_group_layout->addWidget(warning_text); - m_warning_group->setLayout(m_warning_group_layout); + m_warning_group = new QGroupBox(tr("Warning")); + QHBoxLayout* m_warning_group_layout = new QHBoxLayout; + QLabel* warning_text = new QLabel(tr("Some categories and settings will not work.\n" + "This Settings Window is under active development.")); + m_warning_group_layout->addWidget(warning_text); + m_warning_group->setLayout(m_warning_group_layout); } void SettingsWindow::AddCategoryToList(const QString& title, const QString& icon) { - QListWidgetItem* button = new QListWidgetItem(); - button->setIcon(QIcon(icon)); - button->setText(title); - button->setTextAlignment(Qt::AlignVCenter); - button->setSizeHint(QSize(28, 28)); - button->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - m_categories->addItem(button); + QListWidgetItem* button = new QListWidgetItem(); + button->setIcon(QIcon(icon)); + button->setText(title); + button->setTextAlignment(Qt::AlignVCenter); + button->setSizeHint(QSize(28, 28)); + button->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + m_categories->addItem(button); } void SettingsWindow::MakeCategoryList() { - QString dir = Settings().GetThemeDir(); + QString dir = Settings().GetThemeDir(); - m_categories = new QListWidget; - m_categories->setMaximumWidth(175); - m_categories->setIconSize(QSize(32, 32)); - m_categories->setMovement(QListView::Static); - m_categories->setSpacing(0); + m_categories = new QListWidget; + m_categories->setMaximumWidth(175); + m_categories->setIconSize(QSize(32, 32)); + m_categories->setMovement(QListView::Static); + m_categories->setSpacing(0); - connect(m_categories, &QListWidget::currentItemChanged, this, &SettingsWindow::changePage); + connect(m_categories, &QListWidget::currentItemChanged, this, &SettingsWindow::changePage); } void SettingsWindow::changePage(QListWidgetItem* current, QListWidgetItem* previous) { - if (!current) - current = previous; - m_settings_outer->setCurrentIndex(m_categories->row(current)); + if (!current) + current = previous; + m_settings_outer->setCurrentIndex(m_categories->row(current)); } diff --git a/Source/Core/DolphinQt2/Config/SettingsWindow.h b/Source/Core/DolphinQt2/Config/SettingsWindow.h index 889c9cee8b..6187ba5ab8 100644 --- a/Source/Core/DolphinQt2/Config/SettingsWindow.h +++ b/Source/Core/DolphinQt2/Config/SettingsWindow.h @@ -19,19 +19,19 @@ class SettingsWindow final : public QDialog { - Q_OBJECT + Q_OBJECT public: - explicit SettingsWindow(QWidget* parent = nullptr); + explicit SettingsWindow(QWidget* parent = nullptr); public slots: - void changePage(QListWidgetItem* current, QListWidgetItem* previous); + void changePage(QListWidgetItem* current, QListWidgetItem* previous); private: - void MakeCategoryList(); - void MakeUnfinishedWarning(); - void AddCategoryToList(const QString& title, const QString& icon); - void SetupSettingsWidget(); - QStackedWidget* m_settings_outer; - QListWidget* m_categories; - QGroupBox* m_warning_group; + void MakeCategoryList(); + void MakeUnfinishedWarning(); + void AddCategoryToList(const QString& title, const QString& icon); + void SetupSettingsWidget(); + QStackedWidget* m_settings_outer; + QListWidget* m_categories; + QGroupBox* m_warning_group; }; diff --git a/Source/Core/DolphinQt2/GameList/GameFile.cpp b/Source/Core/DolphinQt2/GameList/GameFile.cpp index 23ec7971c4..8efb267e24 100644 --- a/Source/Core/DolphinQt2/GameList/GameFile.cpp +++ b/Source/Core/DolphinQt2/GameList/GameFile.cpp @@ -13,193 +13,190 @@ #include "Common/FileUtil.h" #include "Core/ConfigManager.h" #include "DiscIO/VolumeCreator.h" +#include "DolphinQt2/GameList/GameFile.h" #include "DolphinQt2/Resources.h" #include "DolphinQt2/Settings.h" -#include "DolphinQt2/GameList/GameFile.h" -static const int CACHE_VERSION = 13; // Last changed in PR #3261 +static const int CACHE_VERSION = 13; // Last changed in PR #3261 static const int DATASTREAM_VERSION = QDataStream::Qt_5_5; -static QMap ConvertLanguageMap( - const std::map& map) +static QMap +ConvertLanguageMap(const std::map& map) { - QMap result; - for (auto entry : map) - result.insert(entry.first, QString::fromStdString(entry.second).trimmed()); - return result; + QMap result; + for (auto entry : map) + result.insert(entry.first, QString::fromStdString(entry.second).trimmed()); + return result; } GameFile::GameFile(const QString& path) : m_path(path) { - m_valid = false; + m_valid = false; - if (!LoadFileInfo(path)) - return; + if (!LoadFileInfo(path)) + return; - if (!TryLoadCache()) - { - if (TryLoadVolume()) - { - LoadState(); - } - else if (!TryLoadElfDol()) - { - return; - } - } + if (!TryLoadCache()) + { + if (TryLoadVolume()) + { + LoadState(); + } + else if (!TryLoadElfDol()) + { + return; + } + } - m_valid = true; + m_valid = true; } QString GameFile::GetCacheFileName() const { - QString folder = QString::fromStdString(File::GetUserPath(D_CACHE_IDX)); - // Append a hash of the full path to prevent name clashes between - // files with the same names in different folders. - QString hash = QString::fromUtf8( - QCryptographicHash::hash(m_path.toUtf8(), - QCryptographicHash::Md5).toHex()); - return folder + m_file_name + hash; + QString folder = QString::fromStdString(File::GetUserPath(D_CACHE_IDX)); + // Append a hash of the full path to prevent name clashes between + // files with the same names in different folders. + QString hash = + QString::fromUtf8(QCryptographicHash::hash(m_path.toUtf8(), QCryptographicHash::Md5).toHex()); + return folder + m_file_name + hash; } void GameFile::ReadBanner(const DiscIO::IVolume& volume) { - int width, height; - std::vector buffer = volume.GetBanner(&width, &height); - QImage banner(width, height, QImage::Format_RGB888); - for (int i = 0; i < width * height; i++) - { - int x = i % width, y = i / width; - banner.setPixel(x, y, qRgb((buffer[i] & 0xFF0000) >> 16, - (buffer[i] & 0x00FF00) >> 8, - (buffer[i] & 0x0000FF) >> 0)); - } + int width, height; + std::vector buffer = volume.GetBanner(&width, &height); + QImage banner(width, height, QImage::Format_RGB888); + for (int i = 0; i < width * height; i++) + { + int x = i % width, y = i / width; + banner.setPixel(x, y, qRgb((buffer[i] & 0xFF0000) >> 16, (buffer[i] & 0x00FF00) >> 8, + (buffer[i] & 0x0000FF) >> 0)); + } - if (!banner.isNull()) - m_banner = QPixmap::fromImage(banner); - else - m_banner = Resources::GetMisc(Resources::BANNER_MISSING); + if (!banner.isNull()) + m_banner = QPixmap::fromImage(banner); + else + m_banner = Resources::GetMisc(Resources::BANNER_MISSING); } bool GameFile::LoadFileInfo(const QString& path) { - QFileInfo info(path); - if (!info.exists() || !info.isReadable()) - return false; + QFileInfo info(path); + if (!info.exists() || !info.isReadable()) + return false; - m_file_name = info.fileName(); - m_extension = info.suffix(); - m_folder = info.dir().dirName(); - m_last_modified = info.lastModified(); - m_size = info.size(); + m_file_name = info.fileName(); + m_extension = info.suffix(); + m_folder = info.dir().dirName(); + m_last_modified = info.lastModified(); + m_size = info.size(); - return true; + return true; } void GameFile::LoadState() { - IniFile ini = SConfig::LoadGameIni(m_unique_id.toStdString(), m_revision); - std::string issues_temp; - ini.GetIfExists("EmuState", "EmulationStateId", &m_rating); - ini.GetIfExists("EmuState", "EmulationIssues", &issues_temp); - m_issues = QString::fromStdString(issues_temp); + IniFile ini = SConfig::LoadGameIni(m_unique_id.toStdString(), m_revision); + std::string issues_temp; + ini.GetIfExists("EmuState", "EmulationStateId", &m_rating); + ini.GetIfExists("EmuState", "EmulationIssues", &issues_temp); + m_issues = QString::fromStdString(issues_temp); } bool GameFile::IsElfOrDol() { - return m_extension == QStringLiteral("elf") || - m_extension == QStringLiteral("dol"); + return m_extension == QStringLiteral("elf") || m_extension == QStringLiteral("dol"); } bool GameFile::TryLoadCache() { - QFile cache(GetCacheFileName()); - if (!cache.exists()) - return false; - if (!cache.open(QIODevice::ReadOnly)) - return false; - if (QFileInfo(cache).lastModified() < m_last_modified) - return false; + QFile cache(GetCacheFileName()); + if (!cache.exists()) + return false; + if (!cache.open(QIODevice::ReadOnly)) + return false; + if (QFileInfo(cache).lastModified() < m_last_modified) + return false; - QDataStream in(&cache); - in.setVersion(DATASTREAM_VERSION); + QDataStream in(&cache); + in.setVersion(DATASTREAM_VERSION); - int cache_version; - in >> cache_version; - if (cache_version != CACHE_VERSION) - return false; + int cache_version; + in >> cache_version; + if (cache_version != CACHE_VERSION) + return false; - return false; + return false; } bool GameFile::TryLoadVolume() { - QSharedPointer volume( - DiscIO::CreateVolumeFromFilename(m_path.toStdString()).release()); - if (volume == nullptr) - return false; + QSharedPointer volume( + DiscIO::CreateVolumeFromFilename(m_path.toStdString()).release()); + if (volume == nullptr) + return false; - m_unique_id = QString::fromStdString(volume->GetUniqueID()); - m_maker_id = QString::fromStdString(volume->GetMakerID()); - m_revision = volume->GetRevision(); - m_internal_name = QString::fromStdString(volume->GetInternalName()); - m_short_names = ConvertLanguageMap(volume->GetNames(false)); - m_long_names = ConvertLanguageMap(volume->GetNames(true)); - m_descriptions = ConvertLanguageMap(volume->GetDescriptions()); - m_company = QString::fromStdString(volume->GetCompany()); - m_disc_number = volume->GetDiscNumber(); - m_platform = volume->GetVolumeType(); - m_country = volume->GetCountry(); - m_blob_type = volume->GetBlobType(); - m_raw_size = volume->GetRawSize(); + m_unique_id = QString::fromStdString(volume->GetUniqueID()); + m_maker_id = QString::fromStdString(volume->GetMakerID()); + m_revision = volume->GetRevision(); + m_internal_name = QString::fromStdString(volume->GetInternalName()); + m_short_names = ConvertLanguageMap(volume->GetNames(false)); + m_long_names = ConvertLanguageMap(volume->GetNames(true)); + m_descriptions = ConvertLanguageMap(volume->GetDescriptions()); + m_company = QString::fromStdString(volume->GetCompany()); + m_disc_number = volume->GetDiscNumber(); + m_platform = volume->GetVolumeType(); + m_country = volume->GetCountry(); + m_blob_type = volume->GetBlobType(); + m_raw_size = volume->GetRawSize(); - if (m_company.isEmpty() && m_unique_id.size() >= 6) - m_company = QString::fromStdString( - DiscIO::GetCompanyFromID(m_unique_id.mid(4, 2).toStdString())); + if (m_company.isEmpty() && m_unique_id.size() >= 6) + m_company = + QString::fromStdString(DiscIO::GetCompanyFromID(m_unique_id.mid(4, 2).toStdString())); - ReadBanner(*volume); + ReadBanner(*volume); - SaveCache(); - return true; + SaveCache(); + return true; } bool GameFile::TryLoadElfDol() { - if (!IsElfOrDol()) - return false; + if (!IsElfOrDol()) + return false; - m_revision = 0; - m_long_names[DiscIO::IVolume::LANGUAGE_ENGLISH] = m_file_name; - m_platform = DiscIO::IVolume::ELF_DOL; - m_country = DiscIO::IVolume::COUNTRY_UNKNOWN; - m_blob_type = DiscIO::BlobType::DIRECTORY; - m_raw_size = m_size; - m_banner = Resources::GetMisc(Resources::BANNER_MISSING); - m_rating = 0; + m_revision = 0; + m_long_names[DiscIO::IVolume::LANGUAGE_ENGLISH] = m_file_name; + m_platform = DiscIO::IVolume::ELF_DOL; + m_country = DiscIO::IVolume::COUNTRY_UNKNOWN; + m_blob_type = DiscIO::BlobType::DIRECTORY; + m_raw_size = m_size; + m_banner = Resources::GetMisc(Resources::BANNER_MISSING); + m_rating = 0; - return true; + return true; } void GameFile::SaveCache() { - // TODO + // TODO } QString GameFile::GetLanguageString(const QMap& m) const { - // Try the settings language, then English, then just pick one. - if (m.isEmpty()) - return QString(); + // Try the settings language, then English, then just pick one. + if (m.isEmpty()) + return QString(); - bool wii = m_platform != DiscIO::IVolume::GAMECUBE_DISC; - DiscIO::IVolume::ELanguage current_lang; - if (wii) - current_lang = Settings().GetWiiSystemLanguage(); - else - current_lang = Settings().GetGCSystemLanguage(); + bool wii = m_platform != DiscIO::IVolume::GAMECUBE_DISC; + DiscIO::IVolume::ELanguage current_lang; + if (wii) + current_lang = Settings().GetWiiSystemLanguage(); + else + current_lang = Settings().GetGCSystemLanguage(); - if (m.contains(current_lang)) - return m[current_lang]; - if (m.contains(DiscIO::IVolume::LANGUAGE_ENGLISH)) - return m[DiscIO::IVolume::LANGUAGE_ENGLISH]; - return m.first(); + if (m.contains(current_lang)) + return m[current_lang]; + if (m.contains(DiscIO::IVolume::LANGUAGE_ENGLISH)) + return m[DiscIO::IVolume::LANGUAGE_ENGLISH]; + return m.first(); } diff --git a/Source/Core/DolphinQt2/GameList/GameFile.h b/Source/Core/DolphinQt2/GameList/GameFile.h index 28037dbaca..c1daed88db 100644 --- a/Source/Core/DolphinQt2/GameList/GameFile.h +++ b/Source/Core/DolphinQt2/GameList/GameFile.h @@ -15,87 +15,71 @@ class GameFile final { public: - explicit GameFile(const QString& path); - - bool IsValid() const { return m_valid; } - - // These will be properly initialized before we try to load the file. - QString GetPath() const { return m_path; } - QString GetFileName() const { return m_file_name; } - QString GetExtension() const { return m_extension; } - QString GetFolder() const { return m_folder; } - qint64 GetFileSize() const { return m_size; } - - // The rest will not. - QString GetUniqueID() const { return m_unique_id; } - QString GetMakerID() const { return m_maker_id; } - u16 GetRevision() const { return m_revision; } - QString GetInternalName() const { return m_internal_name; } - QString GetCompany() const { return m_company; } - u8 GetDiscNumber() const { return m_disc_number; } - u64 GetRawSize() const { return m_raw_size; } - QPixmap GetBanner() const { return m_banner; } - QString GetIssues() const { return m_issues; } - int GetRating() const { return m_rating; } - - DiscIO::IVolume::EPlatform GetPlatform() const { return m_platform; } - DiscIO::IVolume::ECountry GetCountry() const { return m_country; } - DiscIO::BlobType GetBlobType() const { return m_blob_type; } - - QString GetShortName() const { return GetLanguageString(m_short_names); } - QString GetShortName(DiscIO::IVolume::ELanguage lang) const - { - return m_short_names[lang]; - } - - QString GetLongName() const { return GetLanguageString(m_long_names); } - QString GetLongName(DiscIO::IVolume::ELanguage lang) const - { - return m_long_names[lang]; - } - - QString GetDescription() const { return GetLanguageString(m_descriptions); } - QString GetDescription(DiscIO::IVolume::ELanguage lang) const - { - return m_descriptions[lang]; - } + explicit GameFile(const QString& path); + bool IsValid() const { return m_valid; } + // These will be properly initialized before we try to load the file. + QString GetPath() const { return m_path; } + QString GetFileName() const { return m_file_name; } + QString GetExtension() const { return m_extension; } + QString GetFolder() const { return m_folder; } + qint64 GetFileSize() const { return m_size; } + // The rest will not. + QString GetUniqueID() const { return m_unique_id; } + QString GetMakerID() const { return m_maker_id; } + u16 GetRevision() const { return m_revision; } + QString GetInternalName() const { return m_internal_name; } + QString GetCompany() const { return m_company; } + u8 GetDiscNumber() const { return m_disc_number; } + u64 GetRawSize() const { return m_raw_size; } + QPixmap GetBanner() const { return m_banner; } + QString GetIssues() const { return m_issues; } + int GetRating() const { return m_rating; } + DiscIO::IVolume::EPlatform GetPlatform() const { return m_platform; } + DiscIO::IVolume::ECountry GetCountry() const { return m_country; } + DiscIO::BlobType GetBlobType() const { return m_blob_type; } + QString GetShortName() const { return GetLanguageString(m_short_names); } + QString GetShortName(DiscIO::IVolume::ELanguage lang) const { return m_short_names[lang]; } + QString GetLongName() const { return GetLanguageString(m_long_names); } + QString GetLongName(DiscIO::IVolume::ELanguage lang) const { return m_long_names[lang]; } + QString GetDescription() const { return GetLanguageString(m_descriptions); } + QString GetDescription(DiscIO::IVolume::ELanguage lang) const { return m_descriptions[lang]; } private: - DiscIO::IVolume::ELanguage GetDefaultLanguage() const; - QString GetLanguageString(const QMap& m) const; + DiscIO::IVolume::ELanguage GetDefaultLanguage() const; + QString GetLanguageString(const QMap& m) const; - QString GetCacheFileName() const; - void ReadBanner(const DiscIO::IVolume& volume); - bool LoadFileInfo(const QString& path); - void LoadState(); - bool IsElfOrDol(); - bool TryLoadElfDol(); - bool TryLoadCache(); - bool TryLoadVolume(); - void SaveCache(); + QString GetCacheFileName() const; + void ReadBanner(const DiscIO::IVolume& volume); + bool LoadFileInfo(const QString& path); + void LoadState(); + bool IsElfOrDol(); + bool TryLoadElfDol(); + bool TryLoadCache(); + bool TryLoadVolume(); + void SaveCache(); - bool m_valid; - QString m_path; - QString m_file_name; - QString m_extension; - QString m_folder; - QDateTime m_last_modified; - qint64 m_size = 0; + bool m_valid; + QString m_path; + QString m_file_name; + QString m_extension; + QString m_folder; + QDateTime m_last_modified; + qint64 m_size = 0; - QString m_unique_id; - QString m_maker_id; - u16 m_revision = 0; - QString m_internal_name; - QMap m_short_names; - QMap m_long_names; - QMap m_descriptions; - QString m_company; - u8 m_disc_number = 0; - DiscIO::IVolume::EPlatform m_platform; - DiscIO::IVolume::ECountry m_country; - DiscIO::BlobType m_blob_type; - u64 m_raw_size = 0; - QPixmap m_banner; - QString m_issues; - int m_rating = 0; + QString m_unique_id; + QString m_maker_id; + u16 m_revision = 0; + QString m_internal_name; + QMap m_short_names; + QMap m_long_names; + QMap m_descriptions; + QString m_company; + u8 m_disc_number = 0; + DiscIO::IVolume::EPlatform m_platform; + DiscIO::IVolume::ECountry m_country; + DiscIO::BlobType m_blob_type; + u64 m_raw_size = 0; + QPixmap m_banner; + QString m_issues; + int m_rating = 0; }; diff --git a/Source/Core/DolphinQt2/GameList/GameList.cpp b/Source/Core/DolphinQt2/GameList/GameList.cpp index 8663668d6f..8c407b846c 100644 --- a/Source/Core/DolphinQt2/GameList/GameList.cpp +++ b/Source/Core/DolphinQt2/GameList/GameList.cpp @@ -8,167 +8,167 @@ #include #include -#include "DolphinQt2/Settings.h" #include "DolphinQt2/GameList/GameList.h" #include "DolphinQt2/GameList/ListProxyModel.h" #include "DolphinQt2/GameList/TableDelegate.h" +#include "DolphinQt2/Settings.h" -GameList::GameList(QWidget* parent): QStackedWidget(parent) +GameList::GameList(QWidget* parent) : QStackedWidget(parent) { - m_model = new GameListModel(this); - m_table_proxy = new QSortFilterProxyModel(this); - m_table_proxy->setSourceModel(m_model); - m_list_proxy = new ListProxyModel(this); - m_list_proxy->setSourceModel(m_model); + m_model = new GameListModel(this); + m_table_proxy = new QSortFilterProxyModel(this); + m_table_proxy->setSourceModel(m_model); + m_list_proxy = new ListProxyModel(this); + m_list_proxy->setSourceModel(m_model); - m_delegate = new TableDelegate(this); + m_delegate = new TableDelegate(this); - MakeTableView(); - MakeListView(); - MakeEmptyView(); + MakeTableView(); + MakeListView(); + MakeEmptyView(); - connect(m_table, &QTableView::doubleClicked, this, &GameList::GameSelected); - connect(m_list, &QListView::doubleClicked, this, &GameList::GameSelected); - connect(this, &GameList::DirectoryAdded, m_model, &GameListModel::DirectoryAdded); - connect(this, &GameList::DirectoryRemoved, m_model, &GameListModel::DirectoryRemoved); - connect(m_model, &QAbstractItemModel::rowsInserted, this, &GameList::ConsiderViewChange); - connect(m_model, &QAbstractItemModel::rowsRemoved, this, &GameList::ConsiderViewChange); + connect(m_table, &QTableView::doubleClicked, this, &GameList::GameSelected); + connect(m_list, &QListView::doubleClicked, this, &GameList::GameSelected); + connect(this, &GameList::DirectoryAdded, m_model, &GameListModel::DirectoryAdded); + connect(this, &GameList::DirectoryRemoved, m_model, &GameListModel::DirectoryRemoved); + connect(m_model, &QAbstractItemModel::rowsInserted, this, &GameList::ConsiderViewChange); + connect(m_model, &QAbstractItemModel::rowsRemoved, this, &GameList::ConsiderViewChange); - addWidget(m_table); - addWidget(m_list); - addWidget(m_empty); - m_prefer_table = Settings().GetPreferredView(); - ConsiderViewChange(); + addWidget(m_table); + addWidget(m_list); + addWidget(m_empty); + m_prefer_table = Settings().GetPreferredView(); + ConsiderViewChange(); } void GameList::MakeTableView() { - m_table = new QTableView(this); - m_table->setModel(m_table_proxy); - m_table->setItemDelegate(m_delegate); - m_table->setSelectionMode(QAbstractItemView::SingleSelection); - m_table->setSelectionBehavior(QAbstractItemView::SelectRows); - m_table->setAlternatingRowColors(true); - m_table->setShowGrid(false); - m_table->setSortingEnabled(true); - m_table->setCurrentIndex(QModelIndex()); - m_table->setContextMenuPolicy(Qt::CustomContextMenu); - connect(m_table, &QTableView::customContextMenuRequested, this, &GameList::ShowContextMenu); + m_table = new QTableView(this); + m_table->setModel(m_table_proxy); + m_table->setItemDelegate(m_delegate); + m_table->setSelectionMode(QAbstractItemView::SingleSelection); + m_table->setSelectionBehavior(QAbstractItemView::SelectRows); + m_table->setAlternatingRowColors(true); + m_table->setShowGrid(false); + m_table->setSortingEnabled(true); + m_table->setCurrentIndex(QModelIndex()); + m_table->setContextMenuPolicy(Qt::CustomContextMenu); + connect(m_table, &QTableView::customContextMenuRequested, this, &GameList::ShowContextMenu); - // TODO load from config - m_table->setColumnHidden(GameListModel::COL_PLATFORM, false); - m_table->setColumnHidden(GameListModel::COL_ID, true); - m_table->setColumnHidden(GameListModel::COL_BANNER, false); - m_table->setColumnHidden(GameListModel::COL_TITLE, false); - m_table->setColumnHidden(GameListModel::COL_DESCRIPTION, true); - m_table->setColumnHidden(GameListModel::COL_MAKER, false); - m_table->setColumnHidden(GameListModel::COL_SIZE, false); - m_table->setColumnHidden(GameListModel::COL_COUNTRY, false); - m_table->setColumnHidden(GameListModel::COL_RATING, false); + // TODO load from config + m_table->setColumnHidden(GameListModel::COL_PLATFORM, false); + m_table->setColumnHidden(GameListModel::COL_ID, true); + m_table->setColumnHidden(GameListModel::COL_BANNER, false); + m_table->setColumnHidden(GameListModel::COL_TITLE, false); + m_table->setColumnHidden(GameListModel::COL_DESCRIPTION, true); + m_table->setColumnHidden(GameListModel::COL_MAKER, false); + m_table->setColumnHidden(GameListModel::COL_SIZE, false); + m_table->setColumnHidden(GameListModel::COL_COUNTRY, false); + m_table->setColumnHidden(GameListModel::COL_RATING, false); - QHeaderView* hor_header = m_table->horizontalHeader(); - hor_header->setSectionResizeMode(GameListModel::COL_PLATFORM, QHeaderView::ResizeToContents); - hor_header->setSectionResizeMode(GameListModel::COL_COUNTRY, QHeaderView::ResizeToContents); - hor_header->setSectionResizeMode(GameListModel::COL_ID, QHeaderView::ResizeToContents); - hor_header->setSectionResizeMode(GameListModel::COL_BANNER, QHeaderView::ResizeToContents); - hor_header->setSectionResizeMode(GameListModel::COL_TITLE, QHeaderView::Stretch); - hor_header->setSectionResizeMode(GameListModel::COL_MAKER, QHeaderView::Stretch); - hor_header->setSectionResizeMode(GameListModel::COL_SIZE, QHeaderView::ResizeToContents); - hor_header->setSectionResizeMode(GameListModel::COL_DESCRIPTION, QHeaderView::Stretch); - hor_header->setSectionResizeMode(GameListModel::COL_RATING, QHeaderView::ResizeToContents); + QHeaderView* hor_header = m_table->horizontalHeader(); + hor_header->setSectionResizeMode(GameListModel::COL_PLATFORM, QHeaderView::ResizeToContents); + hor_header->setSectionResizeMode(GameListModel::COL_COUNTRY, QHeaderView::ResizeToContents); + hor_header->setSectionResizeMode(GameListModel::COL_ID, QHeaderView::ResizeToContents); + hor_header->setSectionResizeMode(GameListModel::COL_BANNER, QHeaderView::ResizeToContents); + hor_header->setSectionResizeMode(GameListModel::COL_TITLE, QHeaderView::Stretch); + hor_header->setSectionResizeMode(GameListModel::COL_MAKER, QHeaderView::Stretch); + hor_header->setSectionResizeMode(GameListModel::COL_SIZE, QHeaderView::ResizeToContents); + hor_header->setSectionResizeMode(GameListModel::COL_DESCRIPTION, QHeaderView::Stretch); + hor_header->setSectionResizeMode(GameListModel::COL_RATING, QHeaderView::ResizeToContents); - QHeaderView* ver_header = m_table->verticalHeader(); - ver_header->setSectionResizeMode(QHeaderView::ResizeToContents); + QHeaderView* ver_header = m_table->verticalHeader(); + ver_header->setSectionResizeMode(QHeaderView::ResizeToContents); } void GameList::MakeEmptyView() { - m_empty = new QLabel(this); - m_empty->setText(tr("Dolphin did not find any game files.\n" - "Open the Paths dialog to add game folders.")); - m_empty->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + m_empty = new QLabel(this); + m_empty->setText(tr("Dolphin did not find any game files.\n" + "Open the Paths dialog to add game folders.")); + m_empty->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); } void GameList::MakeListView() { - m_list = new QListView(this); - m_list->setModel(m_list_proxy); - m_list->setViewMode(QListView::IconMode); - m_list->setResizeMode(QListView::Adjust); - m_list->setUniformItemSizes(true); - m_list->setContextMenuPolicy(Qt::CustomContextMenu); - connect(m_list, &QTableView::customContextMenuRequested, this, &GameList::ShowContextMenu); + m_list = new QListView(this); + m_list->setModel(m_list_proxy); + m_list->setViewMode(QListView::IconMode); + m_list->setResizeMode(QListView::Adjust); + m_list->setUniformItemSizes(true); + m_list->setContextMenuPolicy(Qt::CustomContextMenu); + connect(m_list, &QTableView::customContextMenuRequested, this, &GameList::ShowContextMenu); } void GameList::ShowContextMenu(const QPoint&) { - QMenu* menu = new QMenu(this); - menu->addAction(tr("Properties")); - menu->addAction(tr("Open Wiki Page"), this, SLOT(OpenWiki())); - menu->addAction(tr("Set as Default ISO"), this, SLOT(SetDefaultISO())); - menu->exec(QCursor::pos()); + QMenu* menu = new QMenu(this); + menu->addAction(tr("Properties")); + menu->addAction(tr("Open Wiki Page"), this, SLOT(OpenWiki())); + menu->addAction(tr("Set as Default ISO"), this, SLOT(SetDefaultISO())); + menu->exec(QCursor::pos()); } void GameList::OpenWiki() { - QString game_id = GameFile(GetSelectedGame()).GetUniqueID(); - QString url = QStringLiteral("https://wiki.dolphin-emu.org/index.php?title=").append(game_id); - QDesktopServices::openUrl(QUrl(url)); + QString game_id = GameFile(GetSelectedGame()).GetUniqueID(); + QString url = QStringLiteral("https://wiki.dolphin-emu.org/index.php?title=").append(game_id); + QDesktopServices::openUrl(QUrl(url)); } void GameList::SetDefaultISO() { - Settings().SetDefaultGame(GetSelectedGame()); + Settings().SetDefaultGame(GetSelectedGame()); } QString GameList::GetSelectedGame() const { - QAbstractItemView* view; - QSortFilterProxyModel* proxy; - if (currentWidget() == m_table) - { - view = m_table; - proxy = m_table_proxy; - } - else - { - view = m_list; - proxy = m_list_proxy; - } - QItemSelectionModel* sel_model = view->selectionModel(); - if (sel_model->hasSelection()) - { - QModelIndex model_index = proxy->mapToSource(sel_model->selectedIndexes()[0]); - return m_model->GetPath(model_index.row()); - } - return QStringLiteral(""); + QAbstractItemView* view; + QSortFilterProxyModel* proxy; + if (currentWidget() == m_table) + { + view = m_table; + proxy = m_table_proxy; + } + else + { + view = m_list; + proxy = m_list_proxy; + } + QItemSelectionModel* sel_model = view->selectionModel(); + if (sel_model->hasSelection()) + { + QModelIndex model_index = proxy->mapToSource(sel_model->selectedIndexes()[0]); + return m_model->GetPath(model_index.row()); + } + return QStringLiteral(""); } void GameList::SetPreferredView(bool table) { - m_prefer_table = table; - Settings().SetPreferredView(table); - ConsiderViewChange(); + m_prefer_table = table; + Settings().SetPreferredView(table); + ConsiderViewChange(); } void GameList::ConsiderViewChange() { - if (m_model->rowCount(QModelIndex()) > 0) - { - if (m_prefer_table) - setCurrentWidget(m_table); - else - setCurrentWidget(m_list); - } - else - { - setCurrentWidget(m_empty); - } + if (m_model->rowCount(QModelIndex()) > 0) + { + if (m_prefer_table) + setCurrentWidget(m_table); + else + setCurrentWidget(m_list); + } + else + { + setCurrentWidget(m_empty); + } } void GameList::keyReleaseEvent(QKeyEvent* event) { - if (event->key() == Qt::Key_Return) - emit GameSelected(); - else - QStackedWidget::keyReleaseEvent(event); + if (event->key() == Qt::Key_Return) + emit GameSelected(); + else + QStackedWidget::keyReleaseEvent(event); } diff --git a/Source/Core/DolphinQt2/GameList/GameList.h b/Source/Core/DolphinQt2/GameList/GameList.h index 0f0d8aea4d..2ba457b950 100644 --- a/Source/Core/DolphinQt2/GameList/GameList.h +++ b/Source/Core/DolphinQt2/GameList/GameList.h @@ -17,44 +17,44 @@ class TableDelegate; class GameList final : public QStackedWidget { - Q_OBJECT + Q_OBJECT public: - explicit GameList(QWidget* parent = nullptr); - QString GetSelectedGame() const; + explicit GameList(QWidget* parent = nullptr); + QString GetSelectedGame() const; public slots: - void SetTableView() { SetPreferredView(true); } - void SetListView() { SetPreferredView(false); } - void SetViewColumn(int col, bool view) { m_table->setColumnHidden(col, !view); } - + void SetTableView() { SetPreferredView(true); } + void SetListView() { SetPreferredView(false); } + void SetViewColumn(int col, bool view) { m_table->setColumnHidden(col, !view); } private slots: - void ShowContextMenu(const QPoint&); - void OpenWiki(); - void SetDefaultISO(); + void ShowContextMenu(const QPoint&); + void OpenWiki(); + void SetDefaultISO(); signals: - void GameSelected(); - void DirectoryAdded(const QString& dir); - void DirectoryRemoved(const QString& dir); + void GameSelected(); + void DirectoryAdded(const QString& dir); + void DirectoryRemoved(const QString& dir); private: - void MakeTableView(); - void MakeListView(); - void MakeEmptyView(); - // We only have two views, just use a bool to distinguish. - void SetPreferredView(bool table); - void ConsiderViewChange(); + void MakeTableView(); + void MakeListView(); + void MakeEmptyView(); + // We only have two views, just use a bool to distinguish. + void SetPreferredView(bool table); + void ConsiderViewChange(); - GameListModel* m_model; - TableDelegate* m_delegate; - QSortFilterProxyModel* m_table_proxy; - QSortFilterProxyModel* m_list_proxy; + GameListModel* m_model; + TableDelegate* m_delegate; + QSortFilterProxyModel* m_table_proxy; + QSortFilterProxyModel* m_list_proxy; + + QListView* m_list; + QTableView* m_table; + QLabel* m_empty; + bool m_prefer_table; - QListView* m_list; - QTableView* m_table; - QLabel* m_empty; - bool m_prefer_table; protected: - void keyReleaseEvent(QKeyEvent* event) override; + void keyReleaseEvent(QKeyEvent* event) override; }; diff --git a/Source/Core/DolphinQt2/GameList/GameListModel.cpp b/Source/Core/DolphinQt2/GameList/GameListModel.cpp index e9f015218a..dac4881432 100644 --- a/Source/Core/DolphinQt2/GameList/GameListModel.cpp +++ b/Source/Core/DolphinQt2/GameList/GameListModel.cpp @@ -2,102 +2,117 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "DolphinQt2/Resources.h" #include "DolphinQt2/GameList/GameListModel.h" +#include "DolphinQt2/Resources.h" -GameListModel::GameListModel(QObject* parent) - : QAbstractTableModel(parent) +GameListModel::GameListModel(QObject* parent) : QAbstractTableModel(parent) { - connect(&m_tracker, &GameTracker::GameLoaded, this, &GameListModel::UpdateGame); - connect(&m_tracker, &GameTracker::GameRemoved, this, &GameListModel::RemoveGame); - connect(this, &GameListModel::DirectoryAdded, &m_tracker, &GameTracker::AddDirectory); - connect(this, &GameListModel::DirectoryRemoved, &m_tracker, &GameTracker::RemoveDirectory); + connect(&m_tracker, &GameTracker::GameLoaded, this, &GameListModel::UpdateGame); + connect(&m_tracker, &GameTracker::GameRemoved, this, &GameListModel::RemoveGame); + connect(this, &GameListModel::DirectoryAdded, &m_tracker, &GameTracker::AddDirectory); + connect(this, &GameListModel::DirectoryRemoved, &m_tracker, &GameTracker::RemoveDirectory); } QVariant GameListModel::data(const QModelIndex& index, int role) const { - if (!index.isValid()) - return QVariant(); + if (!index.isValid()) + return QVariant(); - QSharedPointer game = m_games[index.row()]; - if (role == Qt::DisplayRole) - { - switch (index.column()) - { - case COL_PLATFORM: return game->GetPlatform(); - case COL_BANNER: return game->GetBanner(); - case COL_TITLE: return game->GetLongName(); - case COL_ID: return game->GetUniqueID(); - case COL_DESCRIPTION: return game->GetDescription(); - case COL_MAKER: return game->GetCompany(); - case COL_SIZE: return game->GetFileSize(); - case COL_COUNTRY: return game->GetCountry(); - case COL_RATING: return game->GetRating(); - } - } - return QVariant(); + QSharedPointer game = m_games[index.row()]; + if (role == Qt::DisplayRole) + { + switch (index.column()) + { + case COL_PLATFORM: + return game->GetPlatform(); + case COL_BANNER: + return game->GetBanner(); + case COL_TITLE: + return game->GetLongName(); + case COL_ID: + return game->GetUniqueID(); + case COL_DESCRIPTION: + return game->GetDescription(); + case COL_MAKER: + return game->GetCompany(); + case COL_SIZE: + return game->GetFileSize(); + case COL_COUNTRY: + return game->GetCountry(); + case COL_RATING: + return game->GetRating(); + } + } + return QVariant(); } QVariant GameListModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (orientation == Qt::Vertical || role != Qt::DisplayRole) - return QVariant(); + if (orientation == Qt::Vertical || role != Qt::DisplayRole) + return QVariant(); - switch (section) - { - case COL_TITLE: return tr("Title"); - case COL_ID: return tr("ID"); - case COL_BANNER: return tr("Banner"); - case COL_DESCRIPTION: return tr("Description"); - case COL_MAKER: return tr("Maker"); - case COL_SIZE: return tr("Size"); - case COL_RATING: return tr("Quality"); - } - return QVariant(); + switch (section) + { + case COL_TITLE: + return tr("Title"); + case COL_ID: + return tr("ID"); + case COL_BANNER: + return tr("Banner"); + case COL_DESCRIPTION: + return tr("Description"); + case COL_MAKER: + return tr("Maker"); + case COL_SIZE: + return tr("Size"); + case COL_RATING: + return tr("Quality"); + } + return QVariant(); } int GameListModel::rowCount(const QModelIndex& parent) const { - if (parent.isValid()) - return 0; - return m_games.size(); + if (parent.isValid()) + return 0; + return m_games.size(); } int GameListModel::columnCount(const QModelIndex& parent) const { - return NUM_COLS; + return NUM_COLS; } void GameListModel::UpdateGame(QSharedPointer game) { - QString path = game->GetPath(); + QString path = game->GetPath(); - int entry = FindGame(path); - if (entry < 0) - entry = m_games.size(); + int entry = FindGame(path); + if (entry < 0) + entry = m_games.size(); - beginInsertRows(QModelIndex(), entry, entry); - m_games.insert(entry, game); - endInsertRows(); + beginInsertRows(QModelIndex(), entry, entry); + m_games.insert(entry, game); + endInsertRows(); } void GameListModel::RemoveGame(const QString& path) { - int entry = FindGame(path); - if (entry < 0) - return; + int entry = FindGame(path); + if (entry < 0) + return; - beginRemoveRows(QModelIndex(), entry, entry); - m_games.removeAt(entry); - endRemoveRows(); + beginRemoveRows(QModelIndex(), entry, entry); + m_games.removeAt(entry); + endRemoveRows(); } int GameListModel::FindGame(const QString& path) const { - for (int i = 0; i < m_games.size(); i++) - { - if (m_games[i]->GetPath() == path) - return i; - } - return -1; + for (int i = 0; i < m_games.size(); i++) + { + if (m_games[i]->GetPath() == path) + return i; + } + return -1; } diff --git a/Source/Core/DolphinQt2/GameList/GameListModel.h b/Source/Core/DolphinQt2/GameList/GameListModel.h index 0193d0312f..4637d7e0f2 100644 --- a/Source/Core/DolphinQt2/GameList/GameListModel.h +++ b/Source/Core/DolphinQt2/GameList/GameListModel.h @@ -12,46 +12,46 @@ class GameListModel final : public QAbstractTableModel { - Q_OBJECT + Q_OBJECT public: - explicit GameListModel(QObject* parent = nullptr); + explicit GameListModel(QObject* parent = nullptr); - // Qt's Model/View stuff uses these overrides. - QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; - int rowCount(const QModelIndex& parent) const override; - int columnCount(const QModelIndex& parent) const override; + // Qt's Model/View stuff uses these overrides. + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex& parent) const override; + int columnCount(const QModelIndex& parent) const override; - // Path of the Game at the specified index. - QString GetPath(int index) const { return m_games[index]->GetPath(); } - - enum - { - COL_PLATFORM = 0, - COL_ID, - COL_BANNER, - COL_TITLE, - COL_DESCRIPTION, - COL_MAKER, - COL_SIZE, - COL_COUNTRY, - COL_RATING, - NUM_COLS - }; + // Path of the Game at the specified index. + QString GetPath(int index) const { return m_games[index]->GetPath(); } + enum + { + COL_PLATFORM = 0, + COL_ID, + COL_BANNER, + COL_TITLE, + COL_DESCRIPTION, + COL_MAKER, + COL_SIZE, + COL_COUNTRY, + COL_RATING, + NUM_COLS + }; public slots: - void UpdateGame(QSharedPointer game); - void RemoveGame(const QString& path); + void UpdateGame(QSharedPointer game); + void RemoveGame(const QString& path); signals: - void DirectoryAdded(const QString& dir); - void DirectoryRemoved(const QString& dir); + void DirectoryAdded(const QString& dir); + void DirectoryRemoved(const QString& dir); private: - // Index in m_games, or -1 if it isn't found - int FindGame(const QString& path) const; + // Index in m_games, or -1 if it isn't found + int FindGame(const QString& path) const; - GameTracker m_tracker; - QList> m_games; + GameTracker m_tracker; + QList> m_games; }; diff --git a/Source/Core/DolphinQt2/GameList/GameTracker.cpp b/Source/Core/DolphinQt2/GameList/GameTracker.cpp index ef42f01cc6..93adfbb8c8 100644 --- a/Source/Core/DolphinQt2/GameList/GameTracker.cpp +++ b/Source/Core/DolphinQt2/GameList/GameTracker.cpp @@ -6,101 +6,94 @@ #include #include -#include "DolphinQt2/Settings.h" #include "DolphinQt2/GameList/GameTracker.h" +#include "DolphinQt2/Settings.h" -static const QStringList game_filters{ - QStringLiteral("*.gcm"), - QStringLiteral("*.iso"), - QStringLiteral("*.ciso"), - QStringLiteral("*.gcz"), - QStringLiteral("*.wbfs"), - QStringLiteral("*.wad"), - QStringLiteral("*.elf"), - QStringLiteral("*.dol") -}; +static const QStringList game_filters{QStringLiteral("*.gcm"), QStringLiteral("*.iso"), + QStringLiteral("*.ciso"), QStringLiteral("*.gcz"), + QStringLiteral("*.wbfs"), QStringLiteral("*.wad"), + QStringLiteral("*.elf"), QStringLiteral("*.dol")}; -GameTracker::GameTracker(QObject* parent) - : QFileSystemWatcher(parent) +GameTracker::GameTracker(QObject* parent) : QFileSystemWatcher(parent) { - m_loader = new GameLoader; - m_loader->moveToThread(&m_loader_thread); + m_loader = new GameLoader; + m_loader->moveToThread(&m_loader_thread); - qRegisterMetaType>(); - connect(&m_loader_thread, &QThread::finished, m_loader, &QObject::deleteLater); - connect(this, &QFileSystemWatcher::directoryChanged, this, &GameTracker::UpdateDirectory); - connect(this, &QFileSystemWatcher::fileChanged, this, &GameTracker::UpdateFile); - connect(this, &GameTracker::PathChanged, m_loader, &GameLoader::LoadGame); - connect(m_loader, &GameLoader::GameLoaded, this, &GameTracker::GameLoaded); + qRegisterMetaType>(); + connect(&m_loader_thread, &QThread::finished, m_loader, &QObject::deleteLater); + connect(this, &QFileSystemWatcher::directoryChanged, this, &GameTracker::UpdateDirectory); + connect(this, &QFileSystemWatcher::fileChanged, this, &GameTracker::UpdateFile); + connect(this, &GameTracker::PathChanged, m_loader, &GameLoader::LoadGame); + connect(m_loader, &GameLoader::GameLoaded, this, &GameTracker::GameLoaded); - m_loader_thread.start(); + m_loader_thread.start(); - for (QString dir : Settings().GetPaths()) - AddDirectory(dir); + for (QString dir : Settings().GetPaths()) + AddDirectory(dir); } GameTracker::~GameTracker() { - m_loader_thread.quit(); - m_loader_thread.wait(); + m_loader_thread.quit(); + m_loader_thread.wait(); } void GameTracker::AddDirectory(const QString& dir) { - if (!QFileInfo(dir).exists()) - return; - addPath(dir); - UpdateDirectory(dir); + if (!QFileInfo(dir).exists()) + return; + addPath(dir); + UpdateDirectory(dir); } void GameTracker::RemoveDirectory(const QString& dir) { - removePath(dir); - QDirIterator it(dir, game_filters, QDir::NoFilter, QDirIterator::Subdirectories); - while (it.hasNext()) - { - QString path = QFileInfo(it.next()).canonicalFilePath(); - if (m_tracked_files.contains(path)) - { - m_tracked_files[path]--; - if (m_tracked_files[path] == 0) - { - removePath(path); - m_tracked_files.remove(path); - emit GameRemoved(path); - } - } - } + removePath(dir); + QDirIterator it(dir, game_filters, QDir::NoFilter, QDirIterator::Subdirectories); + while (it.hasNext()) + { + QString path = QFileInfo(it.next()).canonicalFilePath(); + if (m_tracked_files.contains(path)) + { + m_tracked_files[path]--; + if (m_tracked_files[path] == 0) + { + removePath(path); + m_tracked_files.remove(path); + emit GameRemoved(path); + } + } + } } void GameTracker::UpdateDirectory(const QString& dir) { - QDirIterator it(dir, game_filters, QDir::NoFilter, QDirIterator::Subdirectories); - while (it.hasNext()) - { - QString path = QFileInfo(it.next()).canonicalFilePath(); - if (m_tracked_files.contains(path)) - { - m_tracked_files[path]++; - } - else - { - addPath(path); - m_tracked_files[path] = 1; - emit PathChanged(path); - } - } + QDirIterator it(dir, game_filters, QDir::NoFilter, QDirIterator::Subdirectories); + while (it.hasNext()) + { + QString path = QFileInfo(it.next()).canonicalFilePath(); + if (m_tracked_files.contains(path)) + { + m_tracked_files[path]++; + } + else + { + addPath(path); + m_tracked_files[path] = 1; + emit PathChanged(path); + } + } } void GameTracker::UpdateFile(const QString& file) { - if (QFileInfo(file).exists()) - { - emit PathChanged(file); - } - else if (removePath(file)) - { - m_tracked_files.remove(file); - emit GameRemoved(file); - } + if (QFileInfo(file).exists()) + { + emit PathChanged(file); + } + else if (removePath(file)) + { + m_tracked_files.remove(file); + emit GameRemoved(file); + } } diff --git a/Source/Core/DolphinQt2/GameList/GameTracker.h b/Source/Core/DolphinQt2/GameList/GameTracker.h index b3493cc522..2a39bbdf14 100644 --- a/Source/Core/DolphinQt2/GameList/GameTracker.h +++ b/Source/Core/DolphinQt2/GameList/GameTracker.h @@ -23,46 +23,46 @@ class GameLoader; // private. class GameTracker final : public QFileSystemWatcher { - Q_OBJECT + Q_OBJECT public: - explicit GameTracker(QObject* parent = nullptr); - ~GameTracker(); + explicit GameTracker(QObject* parent = nullptr); + ~GameTracker(); public slots: - void AddDirectory(const QString& dir); - void RemoveDirectory(const QString& dir); + void AddDirectory(const QString& dir); + void RemoveDirectory(const QString& dir); signals: - void GameLoaded(QSharedPointer game); - void GameRemoved(const QString& path); + void GameLoaded(QSharedPointer game); + void GameRemoved(const QString& path); - void PathChanged(const QString& path); + void PathChanged(const QString& path); private: - void UpdateDirectory(const QString& dir); - void UpdateFile(const QString& path); + void UpdateDirectory(const QString& dir); + void UpdateFile(const QString& path); - // game path -> number of directories that track it - QMap m_tracked_files; - QThread m_loader_thread; - GameLoader* m_loader; + // game path -> number of directories that track it + QMap m_tracked_files; + QThread m_loader_thread; + GameLoader* m_loader; }; class GameLoader final : public QObject { - Q_OBJECT + Q_OBJECT public slots: - void LoadGame(const QString& path) - { - GameFile* game = new GameFile(path); - if (game->IsValid()) - emit GameLoaded(QSharedPointer(game)); - } + void LoadGame(const QString& path) + { + GameFile* game = new GameFile(path); + if (game->IsValid()) + emit GameLoaded(QSharedPointer(game)); + } signals: - void GameLoaded(QSharedPointer game); + void GameLoaded(QSharedPointer game); }; Q_DECLARE_METATYPE(QSharedPointer) diff --git a/Source/Core/DolphinQt2/GameList/ListProxyModel.cpp b/Source/Core/DolphinQt2/GameList/ListProxyModel.cpp index 46712de8ba..f8c9a9463d 100644 --- a/Source/Core/DolphinQt2/GameList/ListProxyModel.cpp +++ b/Source/Core/DolphinQt2/GameList/ListProxyModel.cpp @@ -9,30 +9,26 @@ static QSize LARGE_BANNER_SIZE(144, 48); -ListProxyModel::ListProxyModel(QObject* parent) - : QSortFilterProxyModel(parent) +ListProxyModel::ListProxyModel(QObject* parent) : QSortFilterProxyModel(parent) { - setSortCaseSensitivity(Qt::CaseInsensitive); - sort(GameListModel::COL_TITLE); + setSortCaseSensitivity(Qt::CaseInsensitive); + sort(GameListModel::COL_TITLE); } QVariant ListProxyModel::data(const QModelIndex& i, int role) const { - QModelIndex source_index = mapToSource(i); - if (role == Qt::DisplayRole) - { - return sourceModel()->data( - sourceModel()->index(source_index.row(), GameListModel::COL_TITLE), - Qt::DisplayRole); - } - else if (role == Qt::DecorationRole) - { - return sourceModel()->data( - sourceModel()->index(source_index.row(), GameListModel::COL_BANNER), - Qt::DisplayRole).value().scaled( - LARGE_BANNER_SIZE, - Qt::KeepAspectRatio, - Qt::SmoothTransformation); - } - return QVariant(); + QModelIndex source_index = mapToSource(i); + if (role == Qt::DisplayRole) + { + return sourceModel()->data(sourceModel()->index(source_index.row(), GameListModel::COL_TITLE), + Qt::DisplayRole); + } + else if (role == Qt::DecorationRole) + { + return sourceModel() + ->data(sourceModel()->index(source_index.row(), GameListModel::COL_BANNER), Qt::DisplayRole) + .value() + .scaled(LARGE_BANNER_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } + return QVariant(); } diff --git a/Source/Core/DolphinQt2/GameList/ListProxyModel.h b/Source/Core/DolphinQt2/GameList/ListProxyModel.h index 422a6e2d11..85213baf46 100644 --- a/Source/Core/DolphinQt2/GameList/ListProxyModel.h +++ b/Source/Core/DolphinQt2/GameList/ListProxyModel.h @@ -8,9 +8,9 @@ // single-column large icon + name to be displayed in a QListView. class ListProxyModel final : public QSortFilterProxyModel { - Q_OBJECT + Q_OBJECT public: - explicit ListProxyModel(QObject* parent = nullptr); - QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + explicit ListProxyModel(QObject* parent = nullptr); + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; }; diff --git a/Source/Core/DolphinQt2/GameList/TableDelegate.cpp b/Source/Core/DolphinQt2/GameList/TableDelegate.cpp index 26951cbf67..c6df5bfc72 100644 --- a/Source/Core/DolphinQt2/GameList/TableDelegate.cpp +++ b/Source/Core/DolphinQt2/GameList/TableDelegate.cpp @@ -4,91 +4,87 @@ #include -#include "DolphinQt2/Resources.h" #include "DolphinQt2/GameList/GameListModel.h" #include "DolphinQt2/GameList/TableDelegate.h" +#include "DolphinQt2/Resources.h" static QSize NORMAL_BANNER_SIZE(96, 32); // Convert an integer size to a friendly string representation. static QString FormatSize(qint64 size) { - QStringList units{ - QStringLiteral("KB"), - QStringLiteral("MB"), - QStringLiteral("GB"), - QStringLiteral("TB") - }; - QStringListIterator i(units); - QString unit = QStringLiteral("B"); - double num = (double) size; - while (num > 1024.0 && i.hasNext()) - { - unit = i.next(); - num /= 1024.0; - } - return QStringLiteral("%1 %2").arg(QString::number(num, 'f', 1)).arg(unit); + QStringList units{QStringLiteral("KB"), QStringLiteral("MB"), QStringLiteral("GB"), + QStringLiteral("TB")}; + QStringListIterator i(units); + QString unit = QStringLiteral("B"); + double num = (double)size; + while (num > 1024.0 && i.hasNext()) + { + unit = i.next(); + num /= 1024.0; + } + return QStringLiteral("%1 %2").arg(QString::number(num, 'f', 1)).arg(unit); } TableDelegate::TableDelegate(QWidget* parent) : QStyledItemDelegate(parent) { } -void TableDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +void TableDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const { - QVariant data = index.data(Qt::DisplayRole); - switch (index.column()) - { - case GameListModel::COL_PLATFORM: - DrawPixmap(painter, option.rect, Resources::GetPlatform(data.toInt())); - break; - case GameListModel::COL_COUNTRY: - DrawPixmap(painter, option.rect, Resources::GetCountry(data.toInt())); - break; - case GameListModel::COL_RATING: - DrawPixmap(painter, option.rect, Resources::GetRating(data.toInt())); - break; - case GameListModel::COL_BANNER: - DrawPixmap(painter, option.rect, data.value().scaled( - NORMAL_BANNER_SIZE, - Qt::KeepAspectRatio, - Qt::SmoothTransformation)); - break; - case GameListModel::COL_SIZE: - painter->drawText(option.rect, Qt::AlignCenter, FormatSize(data.toULongLong())); - break; - // Fall through. - case GameListModel::COL_ID: - case GameListModel::COL_TITLE: - case GameListModel::COL_DESCRIPTION: - case GameListModel::COL_MAKER: - painter->drawText(option.rect, Qt::AlignVCenter, data.toString()); - break; - default: break; - } + QVariant data = index.data(Qt::DisplayRole); + switch (index.column()) + { + case GameListModel::COL_PLATFORM: + DrawPixmap(painter, option.rect, Resources::GetPlatform(data.toInt())); + break; + case GameListModel::COL_COUNTRY: + DrawPixmap(painter, option.rect, Resources::GetCountry(data.toInt())); + break; + case GameListModel::COL_RATING: + DrawPixmap(painter, option.rect, Resources::GetRating(data.toInt())); + break; + case GameListModel::COL_BANNER: + DrawPixmap(painter, option.rect, + data.value().scaled(NORMAL_BANNER_SIZE, Qt::KeepAspectRatio, + Qt::SmoothTransformation)); + break; + case GameListModel::COL_SIZE: + painter->drawText(option.rect, Qt::AlignCenter, FormatSize(data.toULongLong())); + break; + // Fall through. + case GameListModel::COL_ID: + case GameListModel::COL_TITLE: + case GameListModel::COL_DESCRIPTION: + case GameListModel::COL_MAKER: + painter->drawText(option.rect, Qt::AlignVCenter, data.toString()); + break; + default: + break; + } } QSize TableDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { - switch (index.column()) - { - case GameListModel::COL_PLATFORM: - return Resources::GetPlatform(0).size(); - case GameListModel::COL_COUNTRY: - return Resources::GetCountry(0).size(); - case GameListModel::COL_RATING: - return Resources::GetRating(0).size(); - case GameListModel::COL_BANNER: - return NORMAL_BANNER_SIZE; - default: return QSize(0, 0); - } + switch (index.column()) + { + case GameListModel::COL_PLATFORM: + return Resources::GetPlatform(0).size(); + case GameListModel::COL_COUNTRY: + return Resources::GetCountry(0).size(); + case GameListModel::COL_RATING: + return Resources::GetRating(0).size(); + case GameListModel::COL_BANNER: + return NORMAL_BANNER_SIZE; + default: + return QSize(0, 0); + } } void TableDelegate::DrawPixmap(QPainter* painter, const QRect& rect, const QPixmap& pixmap) const { - // We don't want to stretch the pixmap out, so center it in the rect. - painter->drawPixmap( - rect.left() + (rect.width() - pixmap.width()) / 2, - rect.top() + (rect.height() - pixmap.height()) / 2, - pixmap); + // We don't want to stretch the pixmap out, so center it in the rect. + painter->drawPixmap(rect.left() + (rect.width() - pixmap.width()) / 2, + rect.top() + (rect.height() - pixmap.height()) / 2, pixmap); } diff --git a/Source/Core/DolphinQt2/GameList/TableDelegate.h b/Source/Core/DolphinQt2/GameList/TableDelegate.h index bf40438371..f44c13fe10 100644 --- a/Source/Core/DolphinQt2/GameList/TableDelegate.h +++ b/Source/Core/DolphinQt2/GameList/TableDelegate.h @@ -8,13 +8,13 @@ class TableDelegate final : public QStyledItemDelegate { - Q_OBJECT + Q_OBJECT public: - explicit TableDelegate(QWidget* parent = nullptr); - void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; - QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; + explicit TableDelegate(QWidget* parent = nullptr); + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; private: - void DrawPixmap(QPainter* painter, const QRect& rect, const QPixmap& pixmap) const; + void DrawPixmap(QPainter* painter, const QRect& rect, const QPixmap& pixmap) const; }; diff --git a/Source/Core/DolphinQt2/Host.cpp b/Source/Core/DolphinQt2/Host.cpp index db74d88b39..c13e5a376b 100644 --- a/Source/Core/DolphinQt2/Host.cpp +++ b/Source/Core/DolphinQt2/Host.cpp @@ -15,92 +15,116 @@ Host* Host::m_instance = nullptr; Host* Host::GetInstance() { - if (m_instance == nullptr) - m_instance = new Host(); - return m_instance; + if (m_instance == nullptr) + m_instance = new Host(); + return m_instance; } void* Host::GetRenderHandle() { - QMutexLocker locker(&m_lock); - return m_render_handle; + QMutexLocker locker(&m_lock); + return m_render_handle; } void Host::SetRenderHandle(void* handle) { - QMutexLocker locker(&m_lock); - m_render_handle = handle; + QMutexLocker locker(&m_lock); + m_render_handle = handle; } bool Host::GetRenderFocus() { - QMutexLocker locker(&m_lock); - return m_render_focus; + QMutexLocker locker(&m_lock); + return m_render_focus; } void Host::SetRenderFocus(bool focus) { - QMutexLocker locker(&m_lock); - m_render_focus = focus; + QMutexLocker locker(&m_lock); + m_render_focus = focus; } bool Host::GetRenderFullscreen() { - QMutexLocker locker(&m_lock); - return m_render_fullscreen; + QMutexLocker locker(&m_lock); + return m_render_fullscreen; } void Host::SetRenderFullscreen(bool fullscreen) { - QMutexLocker locker(&m_lock); - m_render_fullscreen = fullscreen; + QMutexLocker locker(&m_lock); + m_render_fullscreen = fullscreen; } void Host_Message(int id) { - if (id == WM_USER_STOP) - { - emit Host::GetInstance()->RequestStop(); - } - else if (id == WM_USER_JOB_DISPATCH) - { - // Just poke the main thread to get it to wake up, job dispatch - // will happen automatically before it goes back to sleep again. - QAbstractEventDispatcher::instance(qApp->thread())->wakeUp(); - } + if (id == WM_USER_STOP) + { + emit Host::GetInstance()->RequestStop(); + } + else if (id == WM_USER_JOB_DISPATCH) + { + // Just poke the main thread to get it to wake up, job dispatch + // will happen automatically before it goes back to sleep again. + QAbstractEventDispatcher::instance(qApp->thread())->wakeUp(); + } } void Host_UpdateTitle(const std::string& title) { - emit Host::GetInstance()->RequestTitle(QString::fromStdString(title)); + emit Host::GetInstance()->RequestTitle(QString::fromStdString(title)); } void* Host_GetRenderHandle() { - return Host::GetInstance()->GetRenderHandle(); + return Host::GetInstance()->GetRenderHandle(); } bool Host_RendererHasFocus() { - return Host::GetInstance()->GetRenderFocus(); + return Host::GetInstance()->GetRenderFocus(); } -bool Host_RendererIsFullscreen() { - return Host::GetInstance()->GetRenderFullscreen(); +bool Host_RendererIsFullscreen() +{ + return Host::GetInstance()->GetRenderFullscreen(); } // We ignore these, and their purpose should be questioned individually. // In particular, RequestRenderWindowSize, RequestFullscreen, and // UpdateMainFrame should almost certainly be removed. -void Host_UpdateMainFrame() {} -void Host_RequestFullscreen(bool enable) {} -void Host_RequestRenderWindowSize(int w, int h) {} -bool Host_UIHasFocus() { return false; } -void Host_NotifyMapLoaded() {} -void Host_UpdateDisasmDialog() {} -void Host_SetStartupDebuggingParameters() {} -void Host_SetWiiMoteConnectionState(int state) {} -void Host_ConnectWiimote(int wm_idx, bool connect) {} +void Host_UpdateMainFrame() +{ +} +void Host_RequestFullscreen(bool enable) +{ +} +void Host_RequestRenderWindowSize(int w, int h) +{ +} +bool Host_UIHasFocus() +{ + return false; +} +void Host_NotifyMapLoaded() +{ +} +void Host_UpdateDisasmDialog() +{ +} +void Host_SetStartupDebuggingParameters() +{ +} +void Host_SetWiiMoteConnectionState(int state) +{ +} +void Host_ConnectWiimote(int wm_idx, bool connect) +{ +} void Host_ShowVideoConfig(void* parent, const std::string& backend_name, - const std::string& config_name) {} -void Host_RefreshDSPDebuggerWindow() {} + const std::string& config_name) +{ +} +void Host_RefreshDSPDebuggerWindow() +{ +} diff --git a/Source/Core/DolphinQt2/Host.h b/Source/Core/DolphinQt2/Host.h index 64630a8874..325e682384 100644 --- a/Source/Core/DolphinQt2/Host.h +++ b/Source/Core/DolphinQt2/Host.h @@ -15,31 +15,31 @@ // Many of the Host_* functions are ignored, and some shouldn't exist. class Host final : public QObject { - Q_OBJECT + Q_OBJECT public: - static Host* GetInstance(); + static Host* GetInstance(); - void* GetRenderHandle(); - bool GetRenderFocus(); - bool GetRenderFullscreen(); + void* GetRenderHandle(); + bool GetRenderFocus(); + bool GetRenderFullscreen(); public slots: - void SetRenderHandle(void* handle); - void SetRenderFocus(bool focus); - void SetRenderFullscreen(bool fullscreen); + void SetRenderHandle(void* handle); + void SetRenderFocus(bool focus); + void SetRenderFullscreen(bool fullscreen); signals: - void RequestTitle(const QString& title); - void RequestStop(); - void RequestRenderSize(int w, int h); + void RequestTitle(const QString& title); + void RequestStop(); + void RequestRenderSize(int w, int h); private: - Host() {} - static Host* m_instance; - QMutex m_lock; + Host() {} + static Host* m_instance; + QMutex m_lock; - void* m_render_handle; - bool m_render_focus; - bool m_render_fullscreen; + void* m_render_handle; + bool m_render_focus; + bool m_render_fullscreen; }; diff --git a/Source/Core/DolphinQt2/Main.cpp b/Source/Core/DolphinQt2/Main.cpp index 12963caf59..3f32763951 100644 --- a/Source/Core/DolphinQt2/Main.cpp +++ b/Source/Core/DolphinQt2/Main.cpp @@ -14,27 +14,26 @@ int main(int argc, char* argv[]) { - QApplication app(argc, argv); + QApplication app(argc, argv); - UICommon::SetUserDirectory(""); - UICommon::CreateDirectories(); - UICommon::Init(); - Resources::Init(); + UICommon::SetUserDirectory(""); + UICommon::CreateDirectories(); + UICommon::Init(); + Resources::Init(); - // Whenever the event loop is about to go to sleep, dispatch the jobs - // queued in the Core first. - QObject::connect(QAbstractEventDispatcher::instance(), - &QAbstractEventDispatcher::aboutToBlock, - &app, &Core::HostDispatchJobs); + // Whenever the event loop is about to go to sleep, dispatch the jobs + // queued in the Core first. + QObject::connect(QAbstractEventDispatcher::instance(), &QAbstractEventDispatcher::aboutToBlock, + &app, &Core::HostDispatchJobs); - MainWindow win; - win.show(); - int retval = app.exec(); + MainWindow win; + win.show(); + int retval = app.exec(); - BootManager::Stop(); - Core::Shutdown(); - UICommon::Shutdown(); - Host::GetInstance()->deleteLater(); + BootManager::Stop(); + Core::Shutdown(); + UICommon::Shutdown(); + Host::GetInstance()->deleteLater(); - return retval; + return retval; } diff --git a/Source/Core/DolphinQt2/MainWindow.cpp b/Source/Core/DolphinQt2/MainWindow.cpp index 7d6138bc1f..10b434b499 100644 --- a/Source/Core/DolphinQt2/MainWindow.cpp +++ b/Source/Core/DolphinQt2/MainWindow.cpp @@ -9,372 +9,371 @@ #include "Core/BootManager.h" #include "Core/Core.h" +#include "Core/HW/ProcessorInterface.h" #include "Core/Movie.h" #include "Core/State.h" -#include "Core/HW/ProcessorInterface.h" #include "DolphinQt2/AboutDialog.h" +#include "DolphinQt2/Config/PathDialog.h" +#include "DolphinQt2/Config/SettingsWindow.h" #include "DolphinQt2/Host.h" #include "DolphinQt2/MainWindow.h" #include "DolphinQt2/Resources.h" #include "DolphinQt2/Settings.h" -#include "DolphinQt2/Config/PathDialog.h" -#include "DolphinQt2/Config/SettingsWindow.h" MainWindow::MainWindow() : QMainWindow(nullptr) { - setWindowTitle(tr("Dolphin")); - setWindowIcon(QIcon(Resources::GetMisc(Resources::LOGO_SMALL))); - setUnifiedTitleAndToolBarOnMac(true); + setWindowTitle(tr("Dolphin")); + setWindowIcon(QIcon(Resources::GetMisc(Resources::LOGO_SMALL))); + setUnifiedTitleAndToolBarOnMac(true); - CreateComponents(); + CreateComponents(); - ConnectGameList(); - ConnectPathsDialog(); - ConnectToolBar(); - ConnectRenderWidget(); - ConnectStack(); - ConnectMenuBar(); + ConnectGameList(); + ConnectPathsDialog(); + ConnectToolBar(); + ConnectRenderWidget(); + ConnectStack(); + ConnectMenuBar(); } MainWindow::~MainWindow() { - m_render_widget->deleteLater(); + m_render_widget->deleteLater(); } void MainWindow::CreateComponents() { - m_menu_bar = new MenuBar(this); - m_tool_bar = new ToolBar(this); - m_game_list = new GameList(this); - m_render_widget = new RenderWidget; - m_stack = new QStackedWidget(this); - m_paths_dialog = new PathDialog(this); - m_settings_window = new SettingsWindow(this); + m_menu_bar = new MenuBar(this); + m_tool_bar = new ToolBar(this); + m_game_list = new GameList(this); + m_render_widget = new RenderWidget; + m_stack = new QStackedWidget(this); + m_paths_dialog = new PathDialog(this); + m_settings_window = new SettingsWindow(this); } void MainWindow::ConnectMenuBar() { - setMenuBar(m_menu_bar); - // File - connect(m_menu_bar, &MenuBar::Open, this, &MainWindow::Open); - connect(m_menu_bar, &MenuBar::Exit, this, &MainWindow::close); + setMenuBar(m_menu_bar); + // File + connect(m_menu_bar, &MenuBar::Open, this, &MainWindow::Open); + connect(m_menu_bar, &MenuBar::Exit, this, &MainWindow::close); - // Emulation - connect(m_menu_bar, &MenuBar::Pause, this, &MainWindow::Pause); - connect(m_menu_bar, &MenuBar::Play, this, &MainWindow::Play); - connect(m_menu_bar, &MenuBar::Stop, this, &MainWindow::Stop); - connect(m_menu_bar, &MenuBar::Reset, this, &MainWindow::Reset); - connect(m_menu_bar, &MenuBar::Fullscreen, this, &MainWindow::FullScreen); - connect(m_menu_bar, &MenuBar::FrameAdvance, this, &MainWindow::FrameAdvance); - connect(m_menu_bar, &MenuBar::Screenshot, this, &MainWindow::ScreenShot); - connect(m_menu_bar, &MenuBar::StateLoad, this, &MainWindow::StateLoad); - connect(m_menu_bar, &MenuBar::StateSave, this, &MainWindow::StateSave); - connect(m_menu_bar, &MenuBar::StateLoadSlot, this, &MainWindow::StateLoadSlot); - connect(m_menu_bar, &MenuBar::StateSaveSlot, this, &MainWindow::StateSaveSlot); - connect(m_menu_bar, &MenuBar::StateLoadSlotAt, this, &MainWindow::StateLoadSlotAt); - connect(m_menu_bar, &MenuBar::StateSaveSlotAt, this, &MainWindow::StateSaveSlotAt); - connect(m_menu_bar, &MenuBar::StateLoadUndo, this, &MainWindow::StateLoadUndo); - connect(m_menu_bar, &MenuBar::StateSaveUndo, this, &MainWindow::StateSaveUndo); - connect(m_menu_bar, &MenuBar::StateSaveOldest, this, &MainWindow::StateSaveOldest); - connect(m_menu_bar, &MenuBar::SetStateSlot, this, &MainWindow::SetStateSlot); + // Emulation + connect(m_menu_bar, &MenuBar::Pause, this, &MainWindow::Pause); + connect(m_menu_bar, &MenuBar::Play, this, &MainWindow::Play); + connect(m_menu_bar, &MenuBar::Stop, this, &MainWindow::Stop); + connect(m_menu_bar, &MenuBar::Reset, this, &MainWindow::Reset); + connect(m_menu_bar, &MenuBar::Fullscreen, this, &MainWindow::FullScreen); + connect(m_menu_bar, &MenuBar::FrameAdvance, this, &MainWindow::FrameAdvance); + connect(m_menu_bar, &MenuBar::Screenshot, this, &MainWindow::ScreenShot); + connect(m_menu_bar, &MenuBar::StateLoad, this, &MainWindow::StateLoad); + connect(m_menu_bar, &MenuBar::StateSave, this, &MainWindow::StateSave); + connect(m_menu_bar, &MenuBar::StateLoadSlot, this, &MainWindow::StateLoadSlot); + connect(m_menu_bar, &MenuBar::StateSaveSlot, this, &MainWindow::StateSaveSlot); + connect(m_menu_bar, &MenuBar::StateLoadSlotAt, this, &MainWindow::StateLoadSlotAt); + connect(m_menu_bar, &MenuBar::StateSaveSlotAt, this, &MainWindow::StateSaveSlotAt); + connect(m_menu_bar, &MenuBar::StateLoadUndo, this, &MainWindow::StateLoadUndo); + connect(m_menu_bar, &MenuBar::StateSaveUndo, this, &MainWindow::StateSaveUndo); + connect(m_menu_bar, &MenuBar::StateSaveOldest, this, &MainWindow::StateSaveOldest); + connect(m_menu_bar, &MenuBar::SetStateSlot, this, &MainWindow::SetStateSlot); - // View - connect(m_menu_bar, &MenuBar::ShowTable, m_game_list, &GameList::SetTableView); - connect(m_menu_bar, &MenuBar::ShowList, m_game_list, &GameList::SetListView); - connect(m_menu_bar, &MenuBar::ShowAboutDialog, this, &MainWindow::ShowAboutDialog); + // View + connect(m_menu_bar, &MenuBar::ShowTable, m_game_list, &GameList::SetTableView); + connect(m_menu_bar, &MenuBar::ShowList, m_game_list, &GameList::SetListView); + connect(m_menu_bar, &MenuBar::ShowAboutDialog, this, &MainWindow::ShowAboutDialog); - connect(this, &MainWindow::EmulationStarted, m_menu_bar, &MenuBar::EmulationStarted); - connect(this, &MainWindow::EmulationPaused, m_menu_bar, &MenuBar::EmulationPaused); - connect(this, &MainWindow::EmulationStopped, m_menu_bar, &MenuBar::EmulationStopped); + connect(this, &MainWindow::EmulationStarted, m_menu_bar, &MenuBar::EmulationStarted); + connect(this, &MainWindow::EmulationPaused, m_menu_bar, &MenuBar::EmulationPaused); + connect(this, &MainWindow::EmulationStopped, m_menu_bar, &MenuBar::EmulationStopped); } void MainWindow::ConnectToolBar() { - addToolBar(m_tool_bar); - connect(m_tool_bar, &ToolBar::OpenPressed, this, &MainWindow::Open); - connect(m_tool_bar, &ToolBar::PlayPressed, this, &MainWindow::Play); - connect(m_tool_bar, &ToolBar::PausePressed, this, &MainWindow::Pause); - connect(m_tool_bar, &ToolBar::StopPressed, this, &MainWindow::Stop); - connect(m_tool_bar, &ToolBar::FullScreenPressed, this, &MainWindow::FullScreen); - connect(m_tool_bar, &ToolBar::ScreenShotPressed, this, &MainWindow::ScreenShot); - connect(m_tool_bar, &ToolBar::PathsPressed, this, &MainWindow::ShowPathsDialog); - connect(m_tool_bar, &ToolBar::SettingsPressed, this, &MainWindow::ShowSettingsWindow); + addToolBar(m_tool_bar); + connect(m_tool_bar, &ToolBar::OpenPressed, this, &MainWindow::Open); + connect(m_tool_bar, &ToolBar::PlayPressed, this, &MainWindow::Play); + connect(m_tool_bar, &ToolBar::PausePressed, this, &MainWindow::Pause); + connect(m_tool_bar, &ToolBar::StopPressed, this, &MainWindow::Stop); + connect(m_tool_bar, &ToolBar::FullScreenPressed, this, &MainWindow::FullScreen); + connect(m_tool_bar, &ToolBar::ScreenShotPressed, this, &MainWindow::ScreenShot); + connect(m_tool_bar, &ToolBar::PathsPressed, this, &MainWindow::ShowPathsDialog); + connect(m_tool_bar, &ToolBar::SettingsPressed, this, &MainWindow::ShowSettingsWindow); - connect(this, &MainWindow::EmulationStarted, m_tool_bar, &ToolBar::EmulationStarted); - connect(this, &MainWindow::EmulationPaused, m_tool_bar, &ToolBar::EmulationPaused); - connect(this, &MainWindow::EmulationStopped, m_tool_bar, &ToolBar::EmulationStopped); + connect(this, &MainWindow::EmulationStarted, m_tool_bar, &ToolBar::EmulationStarted); + connect(this, &MainWindow::EmulationPaused, m_tool_bar, &ToolBar::EmulationPaused); + connect(this, &MainWindow::EmulationStopped, m_tool_bar, &ToolBar::EmulationStopped); } void MainWindow::ConnectGameList() { - connect(m_game_list, &GameList::GameSelected, this, &MainWindow::Play); + connect(m_game_list, &GameList::GameSelected, this, &MainWindow::Play); } void MainWindow::ConnectRenderWidget() { - m_rendering_to_main = false; - m_render_widget->hide(); - connect(m_render_widget, &RenderWidget::EscapePressed, this, &MainWindow::Stop); - connect(m_render_widget, &RenderWidget::Closed, this, &MainWindow::ForceStop); + m_rendering_to_main = false; + m_render_widget->hide(); + connect(m_render_widget, &RenderWidget::EscapePressed, this, &MainWindow::Stop); + connect(m_render_widget, &RenderWidget::Closed, this, &MainWindow::ForceStop); } void MainWindow::ConnectStack() { - m_stack->setMinimumSize(800, 600); - m_stack->addWidget(m_game_list); - setCentralWidget(m_stack); + m_stack->setMinimumSize(800, 600); + m_stack->addWidget(m_game_list); + setCentralWidget(m_stack); } void MainWindow::ConnectPathsDialog() { - connect(m_paths_dialog, &PathDialog::PathAdded, m_game_list, &GameList::DirectoryAdded); - connect(m_paths_dialog, &PathDialog::PathRemoved, m_game_list, &GameList::DirectoryRemoved); + connect(m_paths_dialog, &PathDialog::PathAdded, m_game_list, &GameList::DirectoryAdded); + connect(m_paths_dialog, &PathDialog::PathRemoved, m_game_list, &GameList::DirectoryRemoved); } void MainWindow::Open() { - QString file = QFileDialog::getOpenFileName(this, - tr("Select a File"), - QDir::currentPath(), - tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.wbfs *.ciso *.gcz *.wad);;" - "All Files (*)")); - if (!file.isEmpty()) - StartGame(file); + QString file = QFileDialog::getOpenFileName( + this, tr("Select a File"), QDir::currentPath(), + tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.wbfs *.ciso *.gcz *.wad);;" + "All Files (*)")); + if (!file.isEmpty()) + StartGame(file); } void MainWindow::Play() { - // If we're in a paused game, start it up again. - // Otherwise, play the selected game, if there is one. - // Otherwise, play the default game. - // Otherwise, play the last played game, if there is one. - // Otherwise, prompt for a new game. - if (Core::GetState() == Core::CORE_PAUSE) - { - Core::SetState(Core::CORE_RUN); - emit EmulationStarted(); - } - else - { - QString selection = m_game_list->GetSelectedGame(); - if (selection.length() > 0) - { - StartGame(selection); - } - else - { - QString default_path = Settings().GetDefaultGame(); - if (!default_path.isEmpty() && QFile::exists(default_path)) - { - StartGame(default_path); - } - else - { - QString last_path = Settings().GetLastGame(); - if (!last_path.isEmpty() && QFile::exists(last_path)) - StartGame(last_path); - else - Open(); - } - } - } + // If we're in a paused game, start it up again. + // Otherwise, play the selected game, if there is one. + // Otherwise, play the default game. + // Otherwise, play the last played game, if there is one. + // Otherwise, prompt for a new game. + if (Core::GetState() == Core::CORE_PAUSE) + { + Core::SetState(Core::CORE_RUN); + emit EmulationStarted(); + } + else + { + QString selection = m_game_list->GetSelectedGame(); + if (selection.length() > 0) + { + StartGame(selection); + } + else + { + QString default_path = Settings().GetDefaultGame(); + if (!default_path.isEmpty() && QFile::exists(default_path)) + { + StartGame(default_path); + } + else + { + QString last_path = Settings().GetLastGame(); + if (!last_path.isEmpty() && QFile::exists(last_path)) + StartGame(last_path); + else + Open(); + } + } + } } void MainWindow::Pause() { - Core::SetState(Core::CORE_PAUSE); - emit EmulationPaused(); + Core::SetState(Core::CORE_PAUSE); + emit EmulationPaused(); } bool MainWindow::Stop() { - bool stop = true; - if (Settings().GetConfirmStop()) - { - // We could pause the game here and resume it if they say no. - QMessageBox::StandardButton confirm; - confirm = QMessageBox::question(m_render_widget, tr("Confirm"), tr("Stop emulation?")); - stop = (confirm == QMessageBox::Yes); - } + bool stop = true; + if (Settings().GetConfirmStop()) + { + // We could pause the game here and resume it if they say no. + QMessageBox::StandardButton confirm; + confirm = QMessageBox::question(m_render_widget, tr("Confirm"), tr("Stop emulation?")); + stop = (confirm == QMessageBox::Yes); + } - if (stop) - ForceStop(); + if (stop) + ForceStop(); - return stop; + return stop; } void MainWindow::ForceStop() { - BootManager::Stop(); - HideRenderWidget(); - emit EmulationStopped(); + BootManager::Stop(); + HideRenderWidget(); + emit EmulationStopped(); } void MainWindow::Reset() { - if (Movie::IsRecordingInput()) - Movie::g_bReset = true; - ProcessorInterface::ResetButton_Tap(); + if (Movie::IsRecordingInput()) + Movie::g_bReset = true; + ProcessorInterface::ResetButton_Tap(); } void MainWindow::FrameAdvance() { - Movie::DoFrameStep(); - EmulationPaused(); + Movie::DoFrameStep(); + EmulationPaused(); } void MainWindow::FullScreen() { - // If the render widget is fullscreen we want to reset it to whatever is in - // settings. If it's set to be fullscreen then it just remakes the window, - // which probably isn't ideal. - bool was_fullscreen = m_render_widget->isFullScreen(); - HideRenderWidget(); - if (was_fullscreen) - ShowRenderWidget(); - else - m_render_widget->showFullScreen(); + // If the render widget is fullscreen we want to reset it to whatever is in + // settings. If it's set to be fullscreen then it just remakes the window, + // which probably isn't ideal. + bool was_fullscreen = m_render_widget->isFullScreen(); + HideRenderWidget(); + if (was_fullscreen) + ShowRenderWidget(); + else + m_render_widget->showFullScreen(); } void MainWindow::ScreenShot() { - Core::SaveScreenShot(); + Core::SaveScreenShot(); } void MainWindow::StartGame(const QString& path) { - // If we're running, only start a new game once we've stopped the last. - if (Core::GetState() != Core::CORE_UNINITIALIZED) - { - if (!Stop()) - return; - } - // Boot up, show an error if it fails to load the game. - if (!BootManager::BootCore(path.toStdString())) - { - QMessageBox::critical(this, tr("Error"), tr("Failed to init core"), QMessageBox::Ok); - return; - } - Settings().SetLastGame(path); - ShowRenderWidget(); - emit EmulationStarted(); + // If we're running, only start a new game once we've stopped the last. + if (Core::GetState() != Core::CORE_UNINITIALIZED) + { + if (!Stop()) + return; + } + // Boot up, show an error if it fails to load the game. + if (!BootManager::BootCore(path.toStdString())) + { + QMessageBox::critical(this, tr("Error"), tr("Failed to init core"), QMessageBox::Ok); + return; + } + Settings().SetLastGame(path); + ShowRenderWidget(); + emit EmulationStarted(); } void MainWindow::ShowRenderWidget() { - Settings settings; - if (settings.GetRenderToMain()) - { - // If we're rendering to main, add it to the stack and update our title when necessary. - m_rendering_to_main = true; - m_stack->setCurrentIndex(m_stack->addWidget(m_render_widget)); - connect(Host::GetInstance(), &Host::RequestTitle, this, &MainWindow::setWindowTitle); - } - else - { - // Otherwise, just show it. - m_rendering_to_main = false; - if (settings.GetFullScreen()) - { - m_render_widget->showFullScreen(); - } - else - { - m_render_widget->setFixedSize(settings.GetRenderWindowSize()); - m_render_widget->showNormal(); - } - } + Settings settings; + if (settings.GetRenderToMain()) + { + // If we're rendering to main, add it to the stack and update our title when necessary. + m_rendering_to_main = true; + m_stack->setCurrentIndex(m_stack->addWidget(m_render_widget)); + connect(Host::GetInstance(), &Host::RequestTitle, this, &MainWindow::setWindowTitle); + } + else + { + // Otherwise, just show it. + m_rendering_to_main = false; + if (settings.GetFullScreen()) + { + m_render_widget->showFullScreen(); + } + else + { + m_render_widget->setFixedSize(settings.GetRenderWindowSize()); + m_render_widget->showNormal(); + } + } } void MainWindow::HideRenderWidget() { - if (m_rendering_to_main) - { - // Remove the widget from the stack and reparent it to nullptr, so that it can draw - // itself in a new window if it wants. Disconnect the title updates. - m_stack->removeWidget(m_render_widget); - m_render_widget->setParent(nullptr); - m_rendering_to_main = false; - disconnect(Host::GetInstance(), &Host::RequestTitle, this, &MainWindow::setWindowTitle); - setWindowTitle(tr("Dolphin")); - } - m_render_widget->hide(); + if (m_rendering_to_main) + { + // Remove the widget from the stack and reparent it to nullptr, so that it can draw + // itself in a new window if it wants. Disconnect the title updates. + m_stack->removeWidget(m_render_widget); + m_render_widget->setParent(nullptr); + m_rendering_to_main = false; + disconnect(Host::GetInstance(), &Host::RequestTitle, this, &MainWindow::setWindowTitle); + setWindowTitle(tr("Dolphin")); + } + m_render_widget->hide(); } void MainWindow::ShowPathsDialog() { - m_paths_dialog->show(); - m_paths_dialog->raise(); - m_paths_dialog->activateWindow(); + m_paths_dialog->show(); + m_paths_dialog->raise(); + m_paths_dialog->activateWindow(); } void MainWindow::ShowSettingsWindow() { - m_settings_window->show(); - m_settings_window->raise(); - m_settings_window->activateWindow(); + m_settings_window->show(); + m_settings_window->raise(); + m_settings_window->activateWindow(); } void MainWindow::ShowAboutDialog() { - AboutDialog* about = new AboutDialog(this); - about->show(); + AboutDialog* about = new AboutDialog(this); + about->show(); } void MainWindow::StateLoad() { - QString path = QFileDialog::getOpenFileName(this, tr("Select a File"), QDir::currentPath(), - tr("All Save States (*.sav *.s##);; All Files (*)")); - State::LoadAs(path.toStdString()); + QString path = QFileDialog::getOpenFileName(this, tr("Select a File"), QDir::currentPath(), + tr("All Save States (*.sav *.s##);; All Files (*)")); + State::LoadAs(path.toStdString()); } void MainWindow::StateSave() { - QString path = QFileDialog::getSaveFileName(this, tr("Select a File"), QDir::currentPath(), - tr("All Save States (*.sav *.s##);; All Files (*)")); - State::SaveAs(path.toStdString()); + QString path = QFileDialog::getSaveFileName(this, tr("Select a File"), QDir::currentPath(), + tr("All Save States (*.sav *.s##);; All Files (*)")); + State::SaveAs(path.toStdString()); } void MainWindow::StateLoadSlot() { - State::Load(m_state_slot); + State::Load(m_state_slot); } void MainWindow::StateSaveSlot() { - State::Save(m_state_slot, true); - m_menu_bar->UpdateStateSlotMenu(); + State::Save(m_state_slot, true); + m_menu_bar->UpdateStateSlotMenu(); } void MainWindow::StateLoadSlotAt(int slot) { - State::Load(slot); + State::Load(slot); } void MainWindow::StateSaveSlotAt(int slot) { - State::Save(slot, true); - m_menu_bar->UpdateStateSlotMenu(); + State::Save(slot, true); + m_menu_bar->UpdateStateSlotMenu(); } void MainWindow::StateLoadUndo() { - State::UndoLoadState(); + State::UndoLoadState(); } void MainWindow::StateSaveUndo() { - State::UndoSaveState(); + State::UndoSaveState(); } void MainWindow::StateSaveOldest() { - State::SaveFirstSaved(); + State::SaveFirstSaved(); } void MainWindow::SetStateSlot(int slot) { - Settings().SetStateSlot(slot); - m_state_slot = slot; + Settings().SetStateSlot(slot); + m_state_slot = slot; } diff --git a/Source/Core/DolphinQt2/MainWindow.h b/Source/Core/DolphinQt2/MainWindow.h index 94c46acd23..665748ba6e 100644 --- a/Source/Core/DolphinQt2/MainWindow.h +++ b/Source/Core/DolphinQt2/MainWindow.h @@ -9,77 +9,77 @@ #include #include +#include "DolphinQt2/GameList/GameList.h" #include "DolphinQt2/MenuBar.h" #include "DolphinQt2/RenderWidget.h" #include "DolphinQt2/ToolBar.h" -#include "DolphinQt2/GameList/GameList.h" class PathDialog; class SettingsWindow; class MainWindow final : public QMainWindow { - Q_OBJECT + Q_OBJECT public: - explicit MainWindow(); - ~MainWindow(); + explicit MainWindow(); + ~MainWindow(); signals: - void EmulationStarted(); - void EmulationPaused(); - void EmulationStopped(); + void EmulationStarted(); + void EmulationPaused(); + void EmulationStopped(); private slots: - void Open(); - void Play(); - void Pause(); + void Open(); + void Play(); + void Pause(); - // May ask for confirmation. Returns whether or not it actually stopped. - bool Stop(); - void ForceStop(); - void Reset(); - void FrameAdvance(); - void StateLoad(); - void StateSave(); - void StateLoadSlot(); - void StateSaveSlot(); - void StateLoadSlotAt(int slot); - void StateSaveSlotAt(int slot); - void StateLoadUndo(); - void StateSaveUndo(); - void StateSaveOldest(); - void SetStateSlot(int slot); + // May ask for confirmation. Returns whether or not it actually stopped. + bool Stop(); + void ForceStop(); + void Reset(); + void FrameAdvance(); + void StateLoad(); + void StateSave(); + void StateLoadSlot(); + void StateSaveSlot(); + void StateLoadSlotAt(int slot); + void StateSaveSlotAt(int slot); + void StateLoadUndo(); + void StateSaveUndo(); + void StateSaveOldest(); + void SetStateSlot(int slot); - void FullScreen(); - void ScreenShot(); + void FullScreen(); + void ScreenShot(); private: - void CreateComponents(); + void CreateComponents(); - void ConnectGameList(); - void ConnectMenuBar(); - void ConnectRenderWidget(); - void ConnectStack(); - void ConnectToolBar(); - void ConnectPathsDialog(); + void ConnectGameList(); + void ConnectMenuBar(); + void ConnectRenderWidget(); + void ConnectStack(); + void ConnectToolBar(); + void ConnectPathsDialog(); - void StartGame(const QString& path); - void ShowRenderWidget(); - void HideRenderWidget(); + void StartGame(const QString& path); + void ShowRenderWidget(); + void HideRenderWidget(); - void ShowPathsDialog(); - void ShowSettingsWindow(); - void ShowAboutDialog(); + void ShowPathsDialog(); + void ShowSettingsWindow(); + void ShowAboutDialog(); - QStackedWidget* m_stack; - ToolBar* m_tool_bar; - MenuBar* m_menu_bar; - GameList* m_game_list; - RenderWidget* m_render_widget; - bool m_rendering_to_main; - int m_state_slot = 1; + QStackedWidget* m_stack; + ToolBar* m_tool_bar; + MenuBar* m_menu_bar; + GameList* m_game_list; + RenderWidget* m_render_widget; + bool m_rendering_to_main; + int m_state_slot = 1; - PathDialog* m_paths_dialog; - SettingsWindow* m_settings_window; + PathDialog* m_paths_dialog; + SettingsWindow* m_settings_window; }; diff --git a/Source/Core/DolphinQt2/MenuBar.cpp b/Source/Core/DolphinQt2/MenuBar.cpp index 29bb0644a1..790afdf38d 100644 --- a/Source/Core/DolphinQt2/MenuBar.cpp +++ b/Source/Core/DolphinQt2/MenuBar.cpp @@ -11,215 +11,198 @@ #include "DolphinQt2/MenuBar.h" #include "DolphinQt2/Settings.h" -MenuBar::MenuBar(QWidget* parent) - : QMenuBar(parent) +MenuBar::MenuBar(QWidget* parent) : QMenuBar(parent) { - AddFileMenu(); - AddEmulationMenu(); - addMenu(tr("Movie")); - addMenu(tr("Options")); - addMenu(tr("Tools")); - AddViewMenu(); - AddHelpMenu(); + AddFileMenu(); + AddEmulationMenu(); + addMenu(tr("Movie")); + addMenu(tr("Options")); + addMenu(tr("Tools")); + AddViewMenu(); + AddHelpMenu(); - EmulationStopped(); + EmulationStopped(); } void MenuBar::EmulationStarted() { - // Emulation - m_play_action->setEnabled(false); - m_play_action->setVisible(false); - m_pause_action->setEnabled(true); - m_pause_action->setVisible(true); - m_stop_action->setEnabled(true); - m_reset_action->setEnabled(true); - m_fullscreen_action->setEnabled(true); - m_frame_advance_action->setEnabled(true); - m_screenshot_action->setEnabled(true); - m_state_load_menu->setEnabled(true); - m_state_save_menu->setEnabled(true); - UpdateStateSlotMenu(); + // Emulation + m_play_action->setEnabled(false); + m_play_action->setVisible(false); + m_pause_action->setEnabled(true); + m_pause_action->setVisible(true); + m_stop_action->setEnabled(true); + m_reset_action->setEnabled(true); + m_fullscreen_action->setEnabled(true); + m_frame_advance_action->setEnabled(true); + m_screenshot_action->setEnabled(true); + m_state_load_menu->setEnabled(true); + m_state_save_menu->setEnabled(true); + UpdateStateSlotMenu(); } void MenuBar::EmulationPaused() { - m_play_action->setEnabled(true); - m_play_action->setVisible(true); - m_pause_action->setEnabled(false); - m_pause_action->setVisible(false); + m_play_action->setEnabled(true); + m_play_action->setVisible(true); + m_pause_action->setEnabled(false); + m_pause_action->setVisible(false); } void MenuBar::EmulationStopped() { - // Emulation - m_play_action->setEnabled(true); - m_play_action->setVisible(true); - m_pause_action->setEnabled(false); - m_pause_action->setVisible(false); - m_stop_action->setEnabled(false); - m_reset_action->setEnabled(false); - m_fullscreen_action->setEnabled(false); - m_frame_advance_action->setEnabled(false); - m_screenshot_action->setEnabled(false); - m_state_load_menu->setEnabled(false); - m_state_save_menu->setEnabled(false); - UpdateStateSlotMenu(); + // Emulation + m_play_action->setEnabled(true); + m_play_action->setVisible(true); + m_pause_action->setEnabled(false); + m_pause_action->setVisible(false); + m_stop_action->setEnabled(false); + m_reset_action->setEnabled(false); + m_fullscreen_action->setEnabled(false); + m_frame_advance_action->setEnabled(false); + m_screenshot_action->setEnabled(false); + m_state_load_menu->setEnabled(false); + m_state_save_menu->setEnabled(false); + UpdateStateSlotMenu(); } void MenuBar::AddFileMenu() { - QMenu* file_menu = addMenu(tr("File")); - m_open_action = file_menu->addAction(tr("Open"), this, SIGNAL(Open())); - m_exit_action = file_menu->addAction(tr("Exit"), this, SIGNAL(Exit())); + QMenu* file_menu = addMenu(tr("File")); + m_open_action = file_menu->addAction(tr("Open"), this, SIGNAL(Open())); + m_exit_action = file_menu->addAction(tr("Exit"), this, SIGNAL(Exit())); } void MenuBar::AddEmulationMenu() { - QMenu* emu_menu = addMenu(tr("Emulation")); - m_play_action = emu_menu->addAction(tr("Play"), this, SIGNAL(Play())); - m_pause_action = emu_menu->addAction(tr("Pause"), this, SIGNAL(Pause())); - m_stop_action = emu_menu->addAction(tr("Stop"), this, SIGNAL(Stop())); - m_reset_action = emu_menu->addAction(tr("Reset"), this, SIGNAL(Reset())); - m_fullscreen_action = emu_menu->addAction(tr("Fullscreen"), this, SIGNAL(Fullscreen())); - m_frame_advance_action = emu_menu->addAction(tr("Frame Advance"), this, SIGNAL(FrameAdvance())); - m_screenshot_action = emu_menu->addAction(tr("Take Screenshot"), this, SIGNAL(Screenshot())); - AddStateLoadMenu(emu_menu); - AddStateSaveMenu(emu_menu); - AddStateSlotMenu(emu_menu); - UpdateStateSlotMenu(); + QMenu* emu_menu = addMenu(tr("Emulation")); + m_play_action = emu_menu->addAction(tr("Play"), this, SIGNAL(Play())); + m_pause_action = emu_menu->addAction(tr("Pause"), this, SIGNAL(Pause())); + m_stop_action = emu_menu->addAction(tr("Stop"), this, SIGNAL(Stop())); + m_reset_action = emu_menu->addAction(tr("Reset"), this, SIGNAL(Reset())); + m_fullscreen_action = emu_menu->addAction(tr("Fullscreen"), this, SIGNAL(Fullscreen())); + m_frame_advance_action = emu_menu->addAction(tr("Frame Advance"), this, SIGNAL(FrameAdvance())); + m_screenshot_action = emu_menu->addAction(tr("Take Screenshot"), this, SIGNAL(Screenshot())); + AddStateLoadMenu(emu_menu); + AddStateSaveMenu(emu_menu); + AddStateSlotMenu(emu_menu); + UpdateStateSlotMenu(); } void MenuBar::AddStateLoadMenu(QMenu* emu_menu) { - m_state_load_menu = emu_menu->addMenu(tr("Load State")); - m_state_load_menu->addAction(tr("Load State from File"), this, SIGNAL(StateLoad())); - m_state_load_menu->addAction(tr("Load State from Selected Slot"), this, SIGNAL(StateLoadSlot())); - m_state_load_slots_menu = m_state_load_menu->addMenu(tr("Load State from Slot")); - m_state_load_menu->addAction(tr("Undo Load State"), this, SIGNAL(StateLoadUndo())); + m_state_load_menu = emu_menu->addMenu(tr("Load State")); + m_state_load_menu->addAction(tr("Load State from File"), this, SIGNAL(StateLoad())); + m_state_load_menu->addAction(tr("Load State from Selected Slot"), this, SIGNAL(StateLoadSlot())); + m_state_load_slots_menu = m_state_load_menu->addMenu(tr("Load State from Slot")); + m_state_load_menu->addAction(tr("Undo Load State"), this, SIGNAL(StateLoadUndo())); - for (int i = 1; i <= 10; i++) - { - QAction* action = m_state_load_slots_menu->addAction(QStringLiteral("")); + for (int i = 1; i <= 10; i++) + { + QAction* action = m_state_load_slots_menu->addAction(QStringLiteral("")); - connect(action, &QAction::triggered, this, [=]() { - emit StateLoadSlotAt(i); - }); - } + connect(action, &QAction::triggered, this, [=]() { emit StateLoadSlotAt(i); }); + } } void MenuBar::AddStateSaveMenu(QMenu* emu_menu) { - m_state_save_menu = emu_menu->addMenu(tr("Save State")); - m_state_save_menu->addAction(tr("Save State to File"), this, SIGNAL(StateSave())); - m_state_save_menu->addAction(tr("Save State to Selected Slot"), this, SIGNAL(StateSaveSlot())); - m_state_save_menu->addAction(tr("Save State to Oldest Slot"), this, SIGNAL(StateSaveOldest())); - m_state_save_slots_menu = m_state_save_menu->addMenu(tr("Save State to Slot")); - m_state_save_menu->addAction(tr("Undo Save State"), this, SIGNAL(StateSaveUndo())); + m_state_save_menu = emu_menu->addMenu(tr("Save State")); + m_state_save_menu->addAction(tr("Save State to File"), this, SIGNAL(StateSave())); + m_state_save_menu->addAction(tr("Save State to Selected Slot"), this, SIGNAL(StateSaveSlot())); + m_state_save_menu->addAction(tr("Save State to Oldest Slot"), this, SIGNAL(StateSaveOldest())); + m_state_save_slots_menu = m_state_save_menu->addMenu(tr("Save State to Slot")); + m_state_save_menu->addAction(tr("Undo Save State"), this, SIGNAL(StateSaveUndo())); - for (int i = 1; i <= 10; i++) - { - QAction* action = m_state_save_slots_menu->addAction(QStringLiteral("")); + for (int i = 1; i <= 10; i++) + { + QAction* action = m_state_save_slots_menu->addAction(QStringLiteral("")); - connect(action, &QAction::triggered, this, [=]() { - emit StateSaveSlotAt(i); - }); - } + connect(action, &QAction::triggered, this, [=]() { emit StateSaveSlotAt(i); }); + } } void MenuBar::AddStateSlotMenu(QMenu* emu_menu) { - m_state_slot_menu = emu_menu->addMenu(tr("Select State Slot")); - m_state_slots = new QActionGroup(this); + m_state_slot_menu = emu_menu->addMenu(tr("Select State Slot")); + m_state_slots = new QActionGroup(this); - for (int i = 1; i <= 10; i++) - { - QAction* action = m_state_slot_menu->addAction(QStringLiteral("")); - action->setCheckable(true); - action->setActionGroup(m_state_slots); - if (Settings().GetStateSlot() == i) - action->setChecked(true); + for (int i = 1; i <= 10; i++) + { + QAction* action = m_state_slot_menu->addAction(QStringLiteral("")); + action->setCheckable(true); + action->setActionGroup(m_state_slots); + if (Settings().GetStateSlot() == i) + action->setChecked(true); - connect(action, &QAction::triggered, this, [=]() { - emit SetStateSlot(i); - }); - } + connect(action, &QAction::triggered, this, [=]() { emit SetStateSlot(i); }); + } } void MenuBar::UpdateStateSlotMenu() { - QList actions_slot = m_state_slots->actions(); - QList actions_load = m_state_load_slots_menu->actions(); - QList actions_save = m_state_save_slots_menu->actions(); - for (int i = 0; i < actions_slot.length(); i++) - { - int slot = i + 1; - QString info = QString::fromStdString(State::GetInfoStringOfSlot(slot)); - QString action_string = tr(" Slot %1 - %2").arg(slot).arg(info); - actions_load.at(i)->setText(tr("Load from") + action_string); - actions_save.at(i)->setText(tr("Save to") + action_string); - actions_slot.at(i)->setText(tr("Select") + action_string); - } + QList actions_slot = m_state_slots->actions(); + QList actions_load = m_state_load_slots_menu->actions(); + QList actions_save = m_state_save_slots_menu->actions(); + for (int i = 0; i < actions_slot.length(); i++) + { + int slot = i + 1; + QString info = QString::fromStdString(State::GetInfoStringOfSlot(slot)); + QString action_string = tr(" Slot %1 - %2").arg(slot).arg(info); + actions_load.at(i)->setText(tr("Load from") + action_string); + actions_save.at(i)->setText(tr("Save to") + action_string); + actions_slot.at(i)->setText(tr("Select") + action_string); + } } void MenuBar::AddViewMenu() { - QMenu* view_menu = addMenu(tr("View")); - AddGameListTypeSection(view_menu); - view_menu->addSeparator(); - AddTableColumnsMenu(view_menu); + QMenu* view_menu = addMenu(tr("View")); + AddGameListTypeSection(view_menu); + view_menu->addSeparator(); + AddTableColumnsMenu(view_menu); } void MenuBar::AddHelpMenu() { - QMenu* help_menu = addMenu(tr("Help")); - QAction* documentation = help_menu->addAction(tr("Online Documentation")); - connect(documentation, &QAction::triggered, this, [=]() { - QDesktopServices::openUrl(QUrl(QStringLiteral("https://dolphin-emu.org/docs/guides"))); - }); - help_menu->addAction(tr("About"), this, SIGNAL(ShowAboutDialog())); + QMenu* help_menu = addMenu(tr("Help")); + QAction* documentation = help_menu->addAction(tr("Online Documentation")); + connect(documentation, &QAction::triggered, this, [=]() { + QDesktopServices::openUrl(QUrl(QStringLiteral("https://dolphin-emu.org/docs/guides"))); + }); + help_menu->addAction(tr("About"), this, SIGNAL(ShowAboutDialog())); } - void MenuBar::AddGameListTypeSection(QMenu* view_menu) { - QAction* table_view = view_menu->addAction(tr("Table")); - table_view->setCheckable(true); + QAction* table_view = view_menu->addAction(tr("Table")); + table_view->setCheckable(true); - QAction* list_view = view_menu->addAction(tr("List")); - list_view->setCheckable(true); + QAction* list_view = view_menu->addAction(tr("List")); + list_view->setCheckable(true); - QActionGroup* list_group = new QActionGroup(this); - list_group->addAction(table_view); - list_group->addAction(list_view); + QActionGroup* list_group = new QActionGroup(this); + list_group->addAction(table_view); + list_group->addAction(list_view); - bool prefer_table = Settings().GetPreferredView(); - table_view->setChecked(prefer_table); - list_view->setChecked(!prefer_table); + bool prefer_table = Settings().GetPreferredView(); + table_view->setChecked(prefer_table); + list_view->setChecked(!prefer_table); - connect(table_view, &QAction::triggered, this, &MenuBar::ShowTable); - connect(list_view, &QAction::triggered, this, &MenuBar::ShowList); + connect(table_view, &QAction::triggered, this, &MenuBar::ShowTable); + connect(list_view, &QAction::triggered, this, &MenuBar::ShowList); } // TODO implement this void MenuBar::AddTableColumnsMenu(QMenu* view_menu) { - QActionGroup* column_group = new QActionGroup(this); - QMenu* cols_menu = view_menu->addMenu(tr("Table Columns")); - column_group->setExclusive(false); + QActionGroup* column_group = new QActionGroup(this); + QMenu* cols_menu = view_menu->addMenu(tr("Table Columns")); + column_group->setExclusive(false); - QStringList col_names{ - tr("Platform"), - tr("ID"), - tr("Banner"), - tr("Title"), - tr("Description"), - tr("Maker"), - tr("Size"), - tr("Country"), - tr("Quality") - }; - for (int i = 0; i < col_names.count(); i++) - { - QAction* action = column_group->addAction(cols_menu->addAction(col_names[i])); - action->setCheckable(true); - } + QStringList col_names{tr("Platform"), tr("ID"), tr("Banner"), tr("Title"), tr("Description"), + tr("Maker"), tr("Size"), tr("Country"), tr("Quality")}; + for (int i = 0; i < col_names.count(); i++) + { + QAction* action = column_group->addAction(cols_menu->addAction(col_names[i])); + action->setCheckable(true); + } } diff --git a/Source/Core/DolphinQt2/MenuBar.h b/Source/Core/DolphinQt2/MenuBar.h index 0e5f139bb0..c0084ea257 100644 --- a/Source/Core/DolphinQt2/MenuBar.h +++ b/Source/Core/DolphinQt2/MenuBar.h @@ -9,77 +9,77 @@ class MenuBar final : public QMenuBar { - Q_OBJECT + Q_OBJECT public: - explicit MenuBar(QWidget* parent = nullptr); + explicit MenuBar(QWidget* parent = nullptr); signals: - // File - void Open(); - void Exit(); + // File + void Open(); + void Exit(); - // Emulation - void Play(); - void Pause(); - void Stop(); - void Reset(); - void Fullscreen(); - void FrameAdvance(); - void Screenshot(); - void StateLoad(); - void StateSave(); - void StateLoadSlot(); - void StateSaveSlot(); - void StateLoadSlotAt(int slot); - void StateSaveSlotAt(int slot); - void StateLoadUndo(); - void StateSaveUndo(); - void StateSaveOldest(); - void SetStateSlot(int slot); + // Emulation + void Play(); + void Pause(); + void Stop(); + void Reset(); + void Fullscreen(); + void FrameAdvance(); + void Screenshot(); + void StateLoad(); + void StateSave(); + void StateLoadSlot(); + void StateSaveSlot(); + void StateLoadSlotAt(int slot); + void StateSaveSlotAt(int slot); + void StateLoadUndo(); + void StateSaveUndo(); + void StateSaveOldest(); + void SetStateSlot(int slot); - // View - void ShowTable(); - void ShowList(); + // View + void ShowTable(); + void ShowList(); - void ShowAboutDialog(); + void ShowAboutDialog(); public slots: - void EmulationStarted(); - void EmulationPaused(); - void EmulationStopped(); - void UpdateStateSlotMenu(); + void EmulationStarted(); + void EmulationPaused(); + void EmulationStopped(); + void UpdateStateSlotMenu(); private: - void AddFileMenu(); + void AddFileMenu(); - void AddEmulationMenu(); - void AddStateLoadMenu(QMenu* emu_menu); - void AddStateSaveMenu(QMenu* emu_menu); - void AddStateSlotMenu(QMenu* emu_menu); + void AddEmulationMenu(); + void AddStateLoadMenu(QMenu* emu_menu); + void AddStateSaveMenu(QMenu* emu_menu); + void AddStateSlotMenu(QMenu* emu_menu); - void AddViewMenu(); - void AddGameListTypeSection(QMenu* view_menu); - void AddTableColumnsMenu(QMenu* view_menu); + void AddViewMenu(); + void AddGameListTypeSection(QMenu* view_menu); + void AddTableColumnsMenu(QMenu* view_menu); - void AddHelpMenu(); + void AddHelpMenu(); - // File - QAction* m_open_action; - QAction* m_exit_action; + // File + QAction* m_open_action; + QAction* m_exit_action; - // Emulation - QAction* m_play_action; - QAction* m_pause_action; - QAction* m_stop_action; - QAction* m_reset_action; - QAction* m_fullscreen_action; - QAction* m_frame_advance_action; - QAction* m_screenshot_action; - QMenu* m_state_load_menu; - QMenu* m_state_save_menu; - QMenu* m_state_slot_menu; - QActionGroup* m_state_slots; - QMenu* m_state_load_slots_menu; - QMenu* m_state_save_slots_menu; + // Emulation + QAction* m_play_action; + QAction* m_pause_action; + QAction* m_stop_action; + QAction* m_reset_action; + QAction* m_fullscreen_action; + QAction* m_frame_advance_action; + QAction* m_screenshot_action; + QMenu* m_state_load_menu; + QMenu* m_state_save_menu; + QMenu* m_state_slot_menu; + QActionGroup* m_state_slots; + QMenu* m_state_load_slots_menu; + QMenu* m_state_save_slots_menu; }; diff --git a/Source/Core/DolphinQt2/RenderWidget.cpp b/Source/Core/DolphinQt2/RenderWidget.cpp index bacaf00f7c..7d5d7caeb5 100644 --- a/Source/Core/DolphinQt2/RenderWidget.cpp +++ b/Source/Core/DolphinQt2/RenderWidget.cpp @@ -7,45 +7,44 @@ #include "DolphinQt2/Host.h" #include "DolphinQt2/RenderWidget.h" -RenderWidget::RenderWidget(QWidget* parent) - : QWidget(parent) +RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent) { - setAttribute(Qt::WA_OpaquePaintEvent, true); - setAttribute(Qt::WA_NoSystemBackground, true); + setAttribute(Qt::WA_OpaquePaintEvent, true); + setAttribute(Qt::WA_NoSystemBackground, true); - connect(Host::GetInstance(), &Host::RequestTitle, this, &RenderWidget::setWindowTitle); - connect(this, &RenderWidget::FocusChanged, Host::GetInstance(), &Host::SetRenderFocus); - connect(this, &RenderWidget::StateChanged, Host::GetInstance(), &Host::SetRenderFullscreen); - connect(this, &RenderWidget::HandleChanged, Host::GetInstance(), &Host::SetRenderHandle); - emit HandleChanged((void*) winId()); + connect(Host::GetInstance(), &Host::RequestTitle, this, &RenderWidget::setWindowTitle); + connect(this, &RenderWidget::FocusChanged, Host::GetInstance(), &Host::SetRenderFocus); + connect(this, &RenderWidget::StateChanged, Host::GetInstance(), &Host::SetRenderFullscreen); + connect(this, &RenderWidget::HandleChanged, Host::GetInstance(), &Host::SetRenderHandle); + emit HandleChanged((void*)winId()); } bool RenderWidget::event(QEvent* event) { - switch (event->type()) - { - case QEvent::KeyPress: - { - QKeyEvent* ke = static_cast(event); - if (ke->key() == Qt::Key_Escape) - emit EscapePressed(); - break; - } - case QEvent::WinIdChange: - emit HandleChanged((void*) winId()); - break; - case QEvent::FocusIn: - case QEvent::FocusOut: - emit FocusChanged(hasFocus()); - break; - case QEvent::WindowStateChange: - emit StateChanged(isFullScreen()); - break; - case QEvent::Close: - emit Closed(); - break; - default: - break; - } - return QWidget::event(event); + switch (event->type()) + { + case QEvent::KeyPress: + { + QKeyEvent* ke = static_cast(event); + if (ke->key() == Qt::Key_Escape) + emit EscapePressed(); + break; + } + case QEvent::WinIdChange: + emit HandleChanged((void*)winId()); + break; + case QEvent::FocusIn: + case QEvent::FocusOut: + emit FocusChanged(hasFocus()); + break; + case QEvent::WindowStateChange: + emit StateChanged(isFullScreen()); + break; + case QEvent::Close: + emit Closed(); + break; + default: + break; + } + return QWidget::event(event); } diff --git a/Source/Core/DolphinQt2/RenderWidget.h b/Source/Core/DolphinQt2/RenderWidget.h index dcd2b8a6a9..1225571661 100644 --- a/Source/Core/DolphinQt2/RenderWidget.h +++ b/Source/Core/DolphinQt2/RenderWidget.h @@ -9,17 +9,17 @@ class RenderWidget final : public QWidget { - Q_OBJECT + Q_OBJECT public: - explicit RenderWidget(QWidget* parent = nullptr); + explicit RenderWidget(QWidget* parent = nullptr); - bool event(QEvent* event); + bool event(QEvent* event); signals: - void EscapePressed(); - void Closed(); - void HandleChanged(void* handle); - void FocusChanged(bool focus); - void StateChanged(bool fullscreen); + void EscapePressed(); + void Closed(); + void HandleChanged(void* handle); + void FocusChanged(bool focus); + void StateChanged(bool fullscreen); }; diff --git a/Source/Core/DolphinQt2/Resources.cpp b/Source/Core/DolphinQt2/Resources.cpp index 44dd2f9ef3..ed96ffb04f 100644 --- a/Source/Core/DolphinQt2/Resources.cpp +++ b/Source/Core/DolphinQt2/Resources.cpp @@ -15,68 +15,51 @@ QList Resources::m_misc; void Resources::Init() { - QString sys_dir = QString::fromStdString(File::GetSysDirectory() + RESOURCES_DIR + DIR_SEP); + QString sys_dir = QString::fromStdString(File::GetSysDirectory() + RESOURCES_DIR + DIR_SEP); - QStringList platforms{ - QStringLiteral("Platform_Gamecube.png"), - QStringLiteral("Platform_Wii.png"), - QStringLiteral("Platform_Wad.png"), - QStringLiteral("Platform_File.png") - }; - for (QString platform : platforms) - m_platforms.append(QPixmap(platform.prepend(sys_dir))); + QStringList platforms{QStringLiteral("Platform_Gamecube.png"), QStringLiteral("Platform_Wii.png"), + QStringLiteral("Platform_Wad.png"), QStringLiteral("Platform_File.png")}; + for (QString platform : platforms) + m_platforms.append(QPixmap(platform.prepend(sys_dir))); - QStringList countries{ - QStringLiteral("Flag_Europe.png"), - QStringLiteral("Flag_Japan.png"), - QStringLiteral("Flag_USA.png"), - QStringLiteral("Flag_Australia.png"), - QStringLiteral("Flag_France.png"), - QStringLiteral("Flag_Germany.png"), - QStringLiteral("Flag_Italy.png"), - QStringLiteral("Flag_Korea.png"), - QStringLiteral("Flag_Netherlands.png"), - QStringLiteral("Flag_Russia.png"), - QStringLiteral("Flag_Spain.png"), - QStringLiteral("Flag_Taiwan.png"), - QStringLiteral("Flag_International.png"), - QStringLiteral("Flag_Unknown.png") - }; - for (QString country : countries) - m_countries.append(QPixmap(country.prepend(sys_dir))); + QStringList countries{ + QStringLiteral("Flag_Europe.png"), QStringLiteral("Flag_Japan.png"), + QStringLiteral("Flag_USA.png"), QStringLiteral("Flag_Australia.png"), + QStringLiteral("Flag_France.png"), QStringLiteral("Flag_Germany.png"), + QStringLiteral("Flag_Italy.png"), QStringLiteral("Flag_Korea.png"), + QStringLiteral("Flag_Netherlands.png"), QStringLiteral("Flag_Russia.png"), + QStringLiteral("Flag_Spain.png"), QStringLiteral("Flag_Taiwan.png"), + QStringLiteral("Flag_International.png"), QStringLiteral("Flag_Unknown.png")}; + for (QString country : countries) + m_countries.append(QPixmap(country.prepend(sys_dir))); - QStringList ratings{ - QStringLiteral("rating0.png"), - QStringLiteral("rating1.png"), - QStringLiteral("rating2.png"), - QStringLiteral("rating3.png"), - QStringLiteral("rating4.png"), - QStringLiteral("rating5.png") - }; - for (QString rating : ratings) - m_ratings.append(QPixmap(rating.prepend(sys_dir))); + QStringList ratings{QStringLiteral("rating0.png"), QStringLiteral("rating1.png"), + QStringLiteral("rating2.png"), QStringLiteral("rating3.png"), + QStringLiteral("rating4.png"), QStringLiteral("rating5.png")}; + for (QString rating : ratings) + m_ratings.append(QPixmap(rating.prepend(sys_dir))); - m_misc.append(QPixmap(QStringLiteral("nobanner.png").prepend(sys_dir))); - m_misc.append(QPixmap(QStringLiteral("dolphin_logo.png").prepend(sys_dir))); - m_misc.append(QPixmap(QStringLiteral("Dolphin.png").prepend(sys_dir))); + m_misc.append(QPixmap(QStringLiteral("nobanner.png").prepend(sys_dir))); + m_misc.append(QPixmap(QStringLiteral("dolphin_logo.png").prepend(sys_dir))); + m_misc.append(QPixmap(QStringLiteral("Dolphin.png").prepend(sys_dir))); } QPixmap Resources::GetPlatform(int platform) { - return m_platforms[platform]; + return m_platforms[platform]; } QPixmap Resources::GetCountry(int country) { - return m_countries[country]; + return m_countries[country]; } QPixmap Resources::GetRating(int rating) { - return m_ratings[rating]; + return m_ratings[rating]; } QPixmap Resources::GetMisc(int id) { - return m_misc[id]; + return m_misc[id]; } diff --git a/Source/Core/DolphinQt2/Resources.h b/Source/Core/DolphinQt2/Resources.h index 322f7880b3..a6631da550 100644 --- a/Source/Core/DolphinQt2/Resources.h +++ b/Source/Core/DolphinQt2/Resources.h @@ -11,26 +11,25 @@ class Resources final { public: - static void Init(); + static void Init(); - static QPixmap GetPlatform(int platform); - static QPixmap GetCountry(int country); - static QPixmap GetRating(int rating); + static QPixmap GetPlatform(int platform); + static QPixmap GetCountry(int country); + static QPixmap GetRating(int rating); - static QPixmap GetMisc(int id); + static QPixmap GetMisc(int id); - enum - { - BANNER_MISSING, - LOGO_LARGE, - LOGO_SMALL - }; + enum + { + BANNER_MISSING, + LOGO_LARGE, + LOGO_SMALL + }; private: - Resources() {} - - static QList m_platforms; - static QList m_countries; - static QList m_ratings; - static QList m_misc; + Resources() {} + static QList m_platforms; + static QList m_countries; + static QList m_ratings; + static QList m_misc; }; diff --git a/Source/Core/DolphinQt2/Settings.cpp b/Source/Core/DolphinQt2/Settings.cpp index f65327ff42..291f56dee6 100644 --- a/Source/Core/DolphinQt2/Settings.cpp +++ b/Source/Core/DolphinQt2/Settings.cpp @@ -10,137 +10,136 @@ static QString GetSettingsPath() { - return QString::fromStdString(File::GetUserPath(D_CONFIG_IDX)) + QStringLiteral("/UI.ini"); + return QString::fromStdString(File::GetUserPath(D_CONFIG_IDX)) + QStringLiteral("/UI.ini"); } -Settings::Settings(QObject* parent) - : QSettings(GetSettingsPath(), QSettings::IniFormat, parent) +Settings::Settings(QObject* parent) : QSettings(GetSettingsPath(), QSettings::IniFormat, parent) { } QString Settings::GetThemeDir() const { - QString theme_name = value(QStringLiteral("Theme"), QStringLiteral("Clean")).toString(); - return QString::fromStdString(File::GetThemeDir(theme_name.toStdString())); + QString theme_name = value(QStringLiteral("Theme"), QStringLiteral("Clean")).toString(); + return QString::fromStdString(File::GetThemeDir(theme_name.toStdString())); } QString Settings::GetLastGame() const { - return value(QStringLiteral("GameList/LastGame")).toString(); + return value(QStringLiteral("GameList/LastGame")).toString(); } void Settings::SetLastGame(const QString& path) { - setValue(QStringLiteral("GameList/LastGame"), path); + setValue(QStringLiteral("GameList/LastGame"), path); } QStringList Settings::GetPaths() const { - return value(QStringLiteral("GameList/Paths")).toStringList(); + return value(QStringLiteral("GameList/Paths")).toStringList(); } void Settings::SetPaths(const QStringList& paths) { - setValue(QStringLiteral("GameList/Paths"), paths); + setValue(QStringLiteral("GameList/Paths"), paths); } void Settings::RemovePath(int i) { - QStringList paths = GetPaths(); - paths.removeAt(i); - SetPaths(paths); + QStringList paths = GetPaths(); + paths.removeAt(i); + SetPaths(paths); } QString Settings::GetDefaultGame() const { - return QString::fromStdString(SConfig::GetInstance().m_strDefaultISO); + return QString::fromStdString(SConfig::GetInstance().m_strDefaultISO); } void Settings::SetDefaultGame(const QString& path) { - SConfig::GetInstance().m_strDefaultISO = path.toStdString(); - SConfig::GetInstance().SaveSettings(); + SConfig::GetInstance().m_strDefaultISO = path.toStdString(); + SConfig::GetInstance().SaveSettings(); } QString Settings::GetDVDRoot() const { - return QString::fromStdString(SConfig::GetInstance().m_strDVDRoot); + return QString::fromStdString(SConfig::GetInstance().m_strDVDRoot); } void Settings::SetDVDRoot(const QString& path) { - SConfig::GetInstance().m_strDVDRoot = path.toStdString(); - SConfig::GetInstance().SaveSettings(); + SConfig::GetInstance().m_strDVDRoot = path.toStdString(); + SConfig::GetInstance().SaveSettings(); } QString Settings::GetApploader() const { - return QString::fromStdString(SConfig::GetInstance().m_strApploader); + return QString::fromStdString(SConfig::GetInstance().m_strApploader); } void Settings::SetApploader(const QString& path) { - SConfig::GetInstance().m_strApploader = path.toStdString(); - SConfig::GetInstance().SaveSettings(); + SConfig::GetInstance().m_strApploader = path.toStdString(); + SConfig::GetInstance().SaveSettings(); } QString Settings::GetWiiNAND() const { - return QString::fromStdString(SConfig::GetInstance().m_NANDPath); + return QString::fromStdString(SConfig::GetInstance().m_NANDPath); } void Settings::SetWiiNAND(const QString& path) { - SConfig::GetInstance().m_NANDPath = path.toStdString(); - SConfig::GetInstance().SaveSettings(); + SConfig::GetInstance().m_NANDPath = path.toStdString(); + SConfig::GetInstance().SaveSettings(); } DiscIO::IVolume::ELanguage Settings::GetWiiSystemLanguage() const { - return SConfig::GetInstance().GetCurrentLanguage(true); + return SConfig::GetInstance().GetCurrentLanguage(true); } DiscIO::IVolume::ELanguage Settings::GetGCSystemLanguage() const { - return SConfig::GetInstance().GetCurrentLanguage(false); + return SConfig::GetInstance().GetCurrentLanguage(false); } bool Settings::GetPreferredView() const { - return value(QStringLiteral("PreferredView"), true).toBool(); + return value(QStringLiteral("PreferredView"), true).toBool(); } void Settings::SetPreferredView(bool table) { - setValue(QStringLiteral("PreferredView"), table); + setValue(QStringLiteral("PreferredView"), table); } bool Settings::GetConfirmStop() const { - return value(QStringLiteral("Emulation/ConfirmStop"), true).toBool(); + return value(QStringLiteral("Emulation/ConfirmStop"), true).toBool(); } int Settings::GetStateSlot() const { - return value(QStringLiteral("Emulation/StateSlot"), 1).toInt(); + return value(QStringLiteral("Emulation/StateSlot"), 1).toInt(); } void Settings::SetStateSlot(int slot) { - setValue(QStringLiteral("Emulation/StateSlot"), slot); + setValue(QStringLiteral("Emulation/StateSlot"), slot); } bool Settings::GetRenderToMain() const { - return value(QStringLiteral("Graphics/RenderToMain"), false).toBool(); + return value(QStringLiteral("Graphics/RenderToMain"), false).toBool(); } bool Settings::GetFullScreen() const { - return value(QStringLiteral("Graphics/FullScreen"), false).toBool(); + return value(QStringLiteral("Graphics/FullScreen"), false).toBool(); } QSize Settings::GetRenderWindowSize() const { - return value(QStringLiteral("Graphics/RenderWindowSize"), QSize(640, 480)).toSize(); + return value(QStringLiteral("Graphics/RenderWindowSize"), QSize(640, 480)).toSize(); } diff --git a/Source/Core/DolphinQt2/Settings.h b/Source/Core/DolphinQt2/Settings.h index 0533171271..9ecacdf6f1 100644 --- a/Source/Core/DolphinQt2/Settings.h +++ b/Source/Core/DolphinQt2/Settings.h @@ -11,40 +11,40 @@ // UI settings to be stored in the config directory. class Settings final : public QSettings { - Q_OBJECT + Q_OBJECT public: - explicit Settings(QObject* parent = nullptr); + explicit Settings(QObject* parent = nullptr); - // UI - QString GetThemeDir() const; + // UI + QString GetThemeDir() const; - // GameList - QString GetLastGame() const; - void SetLastGame(const QString& path); - QStringList GetPaths() const; - void SetPaths(const QStringList& paths); - void RemovePath(int i); - QString GetDefaultGame() const; - void SetDefaultGame(const QString& path); - QString GetDVDRoot() const; - void SetDVDRoot(const QString& path); - QString GetApploader() const; - void SetApploader(const QString& path); - QString GetWiiNAND() const; - void SetWiiNAND(const QString& path); - DiscIO::IVolume::ELanguage GetWiiSystemLanguage() const; - DiscIO::IVolume::ELanguage GetGCSystemLanguage() const; - bool GetPreferredView() const; - void SetPreferredView(bool table); + // GameList + QString GetLastGame() const; + void SetLastGame(const QString& path); + QStringList GetPaths() const; + void SetPaths(const QStringList& paths); + void RemovePath(int i); + QString GetDefaultGame() const; + void SetDefaultGame(const QString& path); + QString GetDVDRoot() const; + void SetDVDRoot(const QString& path); + QString GetApploader() const; + void SetApploader(const QString& path); + QString GetWiiNAND() const; + void SetWiiNAND(const QString& path); + DiscIO::IVolume::ELanguage GetWiiSystemLanguage() const; + DiscIO::IVolume::ELanguage GetGCSystemLanguage() const; + bool GetPreferredView() const; + void SetPreferredView(bool table); - // Emulation - bool GetConfirmStop() const; - int GetStateSlot() const; - void SetStateSlot(int); + // Emulation + bool GetConfirmStop() const; + int GetStateSlot() const; + void SetStateSlot(int); - // Graphics - bool GetRenderToMain() const; - bool GetFullScreen() const; - QSize GetRenderWindowSize() const; + // Graphics + bool GetRenderToMain() const; + bool GetFullScreen() const; + QSize GetRenderWindowSize() const; }; diff --git a/Source/Core/DolphinQt2/ToolBar.cpp b/Source/Core/DolphinQt2/ToolBar.cpp index ae62b61397..1832a2b817 100644 --- a/Source/Core/DolphinQt2/ToolBar.cpp +++ b/Source/Core/DolphinQt2/ToolBar.cpp @@ -9,78 +9,76 @@ static QSize ICON_SIZE(32, 32); -ToolBar::ToolBar(QWidget* parent) - : QToolBar(parent) +ToolBar::ToolBar(QWidget* parent) : QToolBar(parent) { - setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - setMovable(false); - setFloatable(false); - setIconSize(ICON_SIZE); + setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + setMovable(false); + setFloatable(false); + setIconSize(ICON_SIZE); - MakeActions(); - UpdateIcons(); + MakeActions(); + UpdateIcons(); - EmulationStopped(); + EmulationStopped(); } void ToolBar::EmulationStarted() { - m_play_action->setEnabled(false); - m_play_action->setVisible(false); - m_pause_action->setEnabled(true); - m_pause_action->setVisible(true); - m_fullscreen_action->setEnabled(true); - m_screenshot_action->setEnabled(true); + m_play_action->setEnabled(false); + m_play_action->setVisible(false); + m_pause_action->setEnabled(true); + m_pause_action->setVisible(true); + m_fullscreen_action->setEnabled(true); + m_screenshot_action->setEnabled(true); } void ToolBar::EmulationPaused() { - m_play_action->setEnabled(true); - m_play_action->setVisible(true); - m_pause_action->setEnabled(false); - m_pause_action->setVisible(false); + m_play_action->setEnabled(true); + m_play_action->setVisible(true); + m_pause_action->setEnabled(false); + m_pause_action->setVisible(false); } void ToolBar::EmulationStopped() { - m_play_action->setEnabled(true); - m_play_action->setVisible(true); - m_pause_action->setEnabled(false); - m_pause_action->setVisible(false); - m_stop_action->setEnabled(false); - m_fullscreen_action->setEnabled(false); - m_screenshot_action->setEnabled(false); + m_play_action->setEnabled(true); + m_play_action->setVisible(true); + m_pause_action->setEnabled(false); + m_pause_action->setVisible(false); + m_stop_action->setEnabled(false); + m_fullscreen_action->setEnabled(false); + m_screenshot_action->setEnabled(false); } void ToolBar::MakeActions() { - m_open_action = addAction(tr("Open"), this, SIGNAL(OpenPressed())); - m_play_action = addAction(tr("Play"), this, SIGNAL(PlayPressed())); - m_pause_action = addAction(tr("Pause"), this, SIGNAL(PausePressed())); - m_stop_action = addAction(tr("Stop"), this, SIGNAL(StopPressed())); - m_fullscreen_action = addAction(tr("Full Screen"), this, SIGNAL(FullScreenPressed())); - m_screenshot_action = addAction(tr("Screen Shot"), this, SIGNAL(ScreenShotPressed())); + m_open_action = addAction(tr("Open"), this, SIGNAL(OpenPressed())); + m_play_action = addAction(tr("Play"), this, SIGNAL(PlayPressed())); + m_pause_action = addAction(tr("Pause"), this, SIGNAL(PausePressed())); + m_stop_action = addAction(tr("Stop"), this, SIGNAL(StopPressed())); + m_fullscreen_action = addAction(tr("Full Screen"), this, SIGNAL(FullScreenPressed())); + m_screenshot_action = addAction(tr("Screen Shot"), this, SIGNAL(ScreenShotPressed())); - addSeparator(); + addSeparator(); - m_paths_action = addAction(tr("Paths"), this, SIGNAL(PathsPressed())); - m_config_action = addAction(tr("Settings"), this, SIGNAL(SettingsPressed())); - m_controllers_action = addAction(tr("Controllers")); - m_controllers_action->setEnabled(false); + m_paths_action = addAction(tr("Paths"), this, SIGNAL(PathsPressed())); + m_config_action = addAction(tr("Settings"), this, SIGNAL(SettingsPressed())); + m_controllers_action = addAction(tr("Controllers")); + m_controllers_action->setEnabled(false); } void ToolBar::UpdateIcons() { - QString dir = Settings().GetThemeDir(); + QString dir = Settings().GetThemeDir(); - m_open_action->setIcon(QIcon(QStringLiteral("open.png").prepend(dir))); - m_paths_action->setIcon(QIcon(QStringLiteral("browse.png").prepend(dir))); - m_play_action->setIcon(QIcon(QStringLiteral("play.png").prepend(dir))); - m_pause_action->setIcon(QIcon(QStringLiteral("pause.png").prepend(dir))); - m_stop_action->setIcon(QIcon(QStringLiteral("stop.png").prepend(dir))); - m_fullscreen_action->setIcon(QIcon(QStringLiteral("fullscreen.png").prepend(dir))); - m_screenshot_action->setIcon(QIcon(QStringLiteral("screenshot.png").prepend(dir))); - m_config_action->setIcon(QIcon(QStringLiteral("config.png").prepend(dir))); - m_controllers_action->setIcon(QIcon(QStringLiteral("classic.png").prepend(dir))); + m_open_action->setIcon(QIcon(QStringLiteral("open.png").prepend(dir))); + m_paths_action->setIcon(QIcon(QStringLiteral("browse.png").prepend(dir))); + m_play_action->setIcon(QIcon(QStringLiteral("play.png").prepend(dir))); + m_pause_action->setIcon(QIcon(QStringLiteral("pause.png").prepend(dir))); + m_stop_action->setIcon(QIcon(QStringLiteral("stop.png").prepend(dir))); + m_fullscreen_action->setIcon(QIcon(QStringLiteral("fullscreen.png").prepend(dir))); + m_screenshot_action->setIcon(QIcon(QStringLiteral("screenshot.png").prepend(dir))); + m_config_action->setIcon(QIcon(QStringLiteral("config.png").prepend(dir))); + m_controllers_action->setIcon(QIcon(QStringLiteral("classic.png").prepend(dir))); } - diff --git a/Source/Core/DolphinQt2/ToolBar.h b/Source/Core/DolphinQt2/ToolBar.h index 705d5a4e09..52c1e73d25 100644 --- a/Source/Core/DolphinQt2/ToolBar.h +++ b/Source/Core/DolphinQt2/ToolBar.h @@ -10,37 +10,38 @@ class ToolBar final : public QToolBar { - Q_OBJECT + Q_OBJECT public: - explicit ToolBar(QWidget* parent = nullptr); + explicit ToolBar(QWidget* parent = nullptr); public slots: - void EmulationStarted(); - void EmulationPaused(); - void EmulationStopped(); + void EmulationStarted(); + void EmulationPaused(); + void EmulationStopped(); signals: - void OpenPressed(); - void PlayPressed(); - void PausePressed(); - void StopPressed(); - void FullScreenPressed(); - void ScreenShotPressed(); + void OpenPressed(); + void PlayPressed(); + void PausePressed(); + void StopPressed(); + void FullScreenPressed(); + void ScreenShotPressed(); + + void PathsPressed(); + void SettingsPressed(); - void PathsPressed(); - void SettingsPressed(); private: - void MakeActions(); - void UpdateIcons(); + void MakeActions(); + void UpdateIcons(); - QAction* m_open_action; - QAction* m_play_action; - QAction* m_pause_action; - QAction* m_stop_action; - QAction* m_fullscreen_action; - QAction* m_screenshot_action; - QAction* m_paths_action; - QAction* m_config_action; - QAction* m_controllers_action; + QAction* m_open_action; + QAction* m_play_action; + QAction* m_pause_action; + QAction* m_stop_action; + QAction* m_fullscreen_action; + QAction* m_screenshot_action; + QAction* m_paths_action; + QAction* m_config_action; + QAction* m_controllers_action; }; diff --git a/Source/Core/DolphinWX/ARCodeAddEdit.cpp b/Source/Core/DolphinWX/ARCodeAddEdit.cpp index e5f721c754..c756b00d02 100644 --- a/Source/Core/DolphinWX/ARCodeAddEdit.cpp +++ b/Source/Core/DolphinWX/ARCodeAddEdit.cpp @@ -16,172 +16,173 @@ #include #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" -#include "Core/ActionReplay.h" #include "Core/ARDecrypt.h" +#include "Core/ActionReplay.h" #include "DolphinWX/ARCodeAddEdit.h" #include "DolphinWX/WxUtils.h" -CARCodeAddEdit::CARCodeAddEdit(int _selection, std::vector* _arCodes, wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& position, const wxSize& size, long style) - : wxDialog(parent, id, title, position, size, style) - , arCodes(_arCodes) - , selection(_selection) +CARCodeAddEdit::CARCodeAddEdit(int _selection, std::vector* _arCodes, + wxWindow* parent, wxWindowID id, const wxString& title, + const wxPoint& position, const wxSize& size, long style) + : wxDialog(parent, id, title, position, size, style), arCodes(_arCodes), selection(_selection) { - Bind(wxEVT_BUTTON, &CARCodeAddEdit::SaveCheatData, this, wxID_OK); + Bind(wxEVT_BUTTON, &CARCodeAddEdit::SaveCheatData, this, wxID_OK); - ActionReplay::ARCode tempEntries; - wxString currentName; + ActionReplay::ARCode tempEntries; + wxString currentName; - if (selection == wxNOT_FOUND) - { - tempEntries.name = ""; - } - else - { - currentName = StrToWxStr(arCodes->at(selection).name); - tempEntries = arCodes->at(selection); - } + if (selection == wxNOT_FOUND) + { + tempEntries.name = ""; + } + else + { + currentName = StrToWxStr(arCodes->at(selection).name); + tempEntries = arCodes->at(selection); + } - wxBoxSizer* sEditCheat = new wxBoxSizer(wxVERTICAL); - wxStaticBoxSizer* sbEntry = new wxStaticBoxSizer(wxVERTICAL, this, _("Cheat Code")); - wxGridBagSizer* sgEntry = new wxGridBagSizer(0, 0); + wxBoxSizer* sEditCheat = new wxBoxSizer(wxVERTICAL); + wxStaticBoxSizer* sbEntry = new wxStaticBoxSizer(wxVERTICAL, this, _("Cheat Code")); + wxGridBagSizer* sgEntry = new wxGridBagSizer(0, 0); - wxStaticText* EditCheatNameText = new wxStaticText(this, wxID_ANY, _("Name:")); - wxStaticText* EditCheatCodeText = new wxStaticText(this, wxID_ANY, _("Code:")); + wxStaticText* EditCheatNameText = new wxStaticText(this, wxID_ANY, _("Name:")); + wxStaticText* EditCheatCodeText = new wxStaticText(this, wxID_ANY, _("Code:")); - EditCheatName = new wxTextCtrl(this, wxID_ANY, wxEmptyString); - EditCheatName->SetValue(currentName); + EditCheatName = new wxTextCtrl(this, wxID_ANY, wxEmptyString); + EditCheatName->SetValue(currentName); - EntrySelection = new wxSpinButton(this); - EntrySelection->SetRange(1, std::max((int)arCodes->size(), 1)); - EntrySelection->SetValue((int)(arCodes->size() - selection)); - EntrySelection->Bind(wxEVT_SPIN, &CARCodeAddEdit::ChangeEntry, this); + EntrySelection = new wxSpinButton(this); + EntrySelection->SetRange(1, std::max((int)arCodes->size(), 1)); + EntrySelection->SetValue((int)(arCodes->size() - selection)); + EntrySelection->Bind(wxEVT_SPIN, &CARCodeAddEdit::ChangeEntry, this); - EditCheatCode = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300, 100), wxTE_MULTILINE); + EditCheatCode = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300, 100), + wxTE_MULTILINE); - UpdateTextCtrl(tempEntries); + UpdateTextCtrl(tempEntries); - sgEntry->Add(EditCheatNameText, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER | wxALL, 5); - sgEntry->Add(EditCheatCodeText, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER | wxALL, 5); - sgEntry->Add(EditCheatName, wxGBPosition(0, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5); - sgEntry->Add(EntrySelection, wxGBPosition(0, 2), wxGBSpan(2, 1), wxEXPAND | wxALL, 5); - sgEntry->Add(EditCheatCode, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5); - sgEntry->AddGrowableCol(1); - sgEntry->AddGrowableRow(1); - sbEntry->Add(sgEntry, 1, wxEXPAND | wxALL); + sgEntry->Add(EditCheatNameText, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER | wxALL, 5); + sgEntry->Add(EditCheatCodeText, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER | wxALL, 5); + sgEntry->Add(EditCheatName, wxGBPosition(0, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5); + sgEntry->Add(EntrySelection, wxGBPosition(0, 2), wxGBSpan(2, 1), wxEXPAND | wxALL, 5); + sgEntry->Add(EditCheatCode, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5); + sgEntry->AddGrowableCol(1); + sgEntry->AddGrowableRow(1); + sbEntry->Add(sgEntry, 1, wxEXPAND | wxALL); - sEditCheat->Add(sbEntry, 1, wxEXPAND | wxALL, 5); - sEditCheat->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxALL, 5); + sEditCheat->Add(sbEntry, 1, wxEXPAND | wxALL, 5); + sEditCheat->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxALL, 5); - SetSizerAndFit(sEditCheat); - SetFocus(); + SetSizerAndFit(sEditCheat); + SetFocus(); } void CARCodeAddEdit::ChangeEntry(wxSpinEvent& event) { - ActionReplay::ARCode currentCode = arCodes->at((int)arCodes->size() - event.GetPosition()); - EditCheatName->SetValue(StrToWxStr(currentCode.name)); - UpdateTextCtrl(currentCode); + ActionReplay::ARCode currentCode = arCodes->at((int)arCodes->size() - event.GetPosition()); + EditCheatName->SetValue(StrToWxStr(currentCode.name)); + UpdateTextCtrl(currentCode); } void CARCodeAddEdit::SaveCheatData(wxCommandEvent& WXUNUSED(event)) { - std::vector decryptedLines; - std::vector encryptedLines; + std::vector decryptedLines; + std::vector encryptedLines; - // Split the entered cheat into lines. - std::vector userInputLines; - SplitString(WxStrToStr(EditCheatCode->GetValue()), '\n', userInputLines); + // Split the entered cheat into lines. + std::vector userInputLines; + SplitString(WxStrToStr(EditCheatCode->GetValue()), '\n', userInputLines); - for (size_t i = 0; i < userInputLines.size(); i++) - { - // Make sure to ignore unneeded whitespace characters. - std::string line_str = StripSpaces(userInputLines[i]); + for (size_t i = 0; i < userInputLines.size(); i++) + { + // Make sure to ignore unneeded whitespace characters. + std::string line_str = StripSpaces(userInputLines[i]); - if (line_str == "") - continue; + if (line_str == "") + continue; - // Let's parse the current line. Is it in encrypted or decrypted form? - std::vector pieces; - SplitString(line_str, ' ', pieces); + // Let's parse the current line. Is it in encrypted or decrypted form? + std::vector pieces; + SplitString(line_str, ' ', pieces); - if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8) - { - // Decrypted code line. - u32 addr = std::stoul(pieces[0], nullptr, 16); - u32 value = std::stoul(pieces[1], nullptr, 16); + if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8) + { + // Decrypted code line. + u32 addr = std::stoul(pieces[0], nullptr, 16); + u32 value = std::stoul(pieces[1], nullptr, 16); - decryptedLines.emplace_back(addr, value); - continue; - } - else if (pieces.size() == 1) - { - SplitString(line_str, '-', pieces); + decryptedLines.emplace_back(addr, value); + continue; + } + else if (pieces.size() == 1) + { + SplitString(line_str, '-', pieces); - if (pieces.size() == 3 && pieces[0].size() == 4 && pieces[1].size() == 4 && pieces[2].size() == 5) - { - // Encrypted code line. We'll have to decode it later. - encryptedLines.push_back(pieces[0] + pieces[1] + pieces[2]); - continue; - } - } + if (pieces.size() == 3 && pieces[0].size() == 4 && pieces[1].size() == 4 && + pieces[2].size() == 5) + { + // Encrypted code line. We'll have to decode it later. + encryptedLines.push_back(pieces[0] + pieces[1] + pieces[2]); + continue; + } + } - // If the above-mentioned conditions weren't met, then something went wrong. - if (!PanicYesNoT("Unable to parse line %u of the entered AR code as a valid " - "encrypted or decrypted code. Make sure you typed it correctly.\n" - "Would you like to ignore this line and continue parsing?", (unsigned)(i + 1))) - { - return; - } - } + // If the above-mentioned conditions weren't met, then something went wrong. + if (!PanicYesNoT("Unable to parse line %u of the entered AR code as a valid " + "encrypted or decrypted code. Make sure you typed it correctly.\n" + "Would you like to ignore this line and continue parsing?", + (unsigned)(i + 1))) + { + return; + } + } - // If the entered code was in encrypted form, we decode it here. - if (encryptedLines.size()) - { - // TODO: what if both decrypted AND encrypted lines are entered into a single AR code? - ActionReplay::DecryptARCode(encryptedLines, decryptedLines); - } + // If the entered code was in encrypted form, we decode it here. + if (encryptedLines.size()) + { + // TODO: what if both decrypted AND encrypted lines are entered into a single AR code? + ActionReplay::DecryptARCode(encryptedLines, decryptedLines); + } - // Codes with no lines appear to be deleted/hidden from the list. Let's prevent that. - if (!decryptedLines.size()) - { - WxUtils::ShowErrorDialog(_("The resulting decrypted AR code doesn't contain any lines.")); - return; - } + // Codes with no lines appear to be deleted/hidden from the list. Let's prevent that. + if (!decryptedLines.size()) + { + WxUtils::ShowErrorDialog(_("The resulting decrypted AR code doesn't contain any lines.")); + return; + } + if (selection == wxNOT_FOUND) + { + // Add a new AR cheat code. + ActionReplay::ARCode newCheat; - if (selection == wxNOT_FOUND) - { - // Add a new AR cheat code. - ActionReplay::ARCode newCheat; + newCheat.name = WxStrToStr(EditCheatName->GetValue()); + newCheat.ops = decryptedLines; + newCheat.active = true; + newCheat.user_defined = true; - newCheat.name = WxStrToStr(EditCheatName->GetValue()); - newCheat.ops = decryptedLines; - newCheat.active = true; - newCheat.user_defined = true; + arCodes->push_back(newCheat); + } + else + { + // Update the currently-selected AR cheat code. + arCodes->at(selection).name = WxStrToStr(EditCheatName->GetValue()); + arCodes->at(selection).ops = decryptedLines; + } - arCodes->push_back(newCheat); - } - else - { - // Update the currently-selected AR cheat code. - arCodes->at(selection).name = WxStrToStr(EditCheatName->GetValue()); - arCodes->at(selection).ops = decryptedLines; - } - - AcceptAndClose(); + AcceptAndClose(); } void CARCodeAddEdit::UpdateTextCtrl(ActionReplay::ARCode arCode) { - EditCheatCode->Clear(); + EditCheatCode->Clear(); - if (arCode.name != "") - { - for (auto& op : arCode.ops) - EditCheatCode->AppendText(wxString::Format("%08X %08X\n", op.cmd_addr, op.value)); - } + if (arCode.name != "") + { + for (auto& op : arCode.ops) + EditCheatCode->AppendText(wxString::Format("%08X %08X\n", op.cmd_addr, op.value)); + } } - diff --git a/Source/Core/DolphinWX/ARCodeAddEdit.h b/Source/Core/DolphinWX/ARCodeAddEdit.h index 35aa74f128..5377276f63 100644 --- a/Source/Core/DolphinWX/ARCodeAddEdit.h +++ b/Source/Core/DolphinWX/ARCodeAddEdit.h @@ -10,29 +10,29 @@ class wxSpinButton; class wxSpinEvent; class wxTextCtrl; -namespace ActionReplay { struct ARCode; } +namespace ActionReplay +{ +struct ARCode; +} class CARCodeAddEdit : public wxDialog { public: - CARCodeAddEdit(int _selection, std::vector* _arCodes, - wxWindow* parent, - wxWindowID id = wxID_ANY, - const wxString& title = _("Edit ActionReplay Code"), - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxDEFAULT_DIALOG_STYLE); + CARCodeAddEdit(int _selection, std::vector* _arCodes, wxWindow* parent, + wxWindowID id = wxID_ANY, const wxString& title = _("Edit ActionReplay Code"), + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_DIALOG_STYLE); private: - wxTextCtrl* EditCheatName; - wxSpinButton* EntrySelection; - wxTextCtrl* EditCheatCode; + wxTextCtrl* EditCheatName; + wxSpinButton* EntrySelection; + wxTextCtrl* EditCheatCode; - std::vector* arCodes; + std::vector* arCodes; - void SaveCheatData(wxCommandEvent& event); - void ChangeEntry(wxSpinEvent& event); - void UpdateTextCtrl(ActionReplay::ARCode arCode); + void SaveCheatData(wxCommandEvent& event); + void ChangeEntry(wxSpinEvent& event); + void UpdateTextCtrl(ActionReplay::ARCode arCode); - int selection; + int selection; }; diff --git a/Source/Core/DolphinWX/AboutDolphin.cpp b/Source/Core/DolphinWX/AboutDolphin.cpp index bc6236bb6a..71004e9417 100644 --- a/Source/Core/DolphinWX/AboutDolphin.cpp +++ b/Source/Core/DolphinWX/AboutDolphin.cpp @@ -4,13 +4,13 @@ #include #include +#include #include #include #include #include #include #include -#include #ifdef __APPLE__ #import @@ -20,103 +20,111 @@ #include "DolphinWX/AboutDolphin.h" #include "DolphinWX/WxUtils.h" -AboutDolphin::AboutDolphin(wxWindow *parent, wxWindowID id, - const wxString &title, const wxPoint &position, - const wxSize& size, long style) - : wxDialog(parent, id, title, position, size, style) +AboutDolphin::AboutDolphin(wxWindow* parent, wxWindowID id, const wxString& title, + const wxPoint& position, const wxSize& size, long style) + : wxDialog(parent, id, title, position, size, style) { - wxGenericStaticBitmap* const sbDolphinLogo = new wxGenericStaticBitmap(this, wxID_ANY, - WxUtils::LoadResourceBitmap("dolphin_logo")); + wxGenericStaticBitmap* const sbDolphinLogo = + new wxGenericStaticBitmap(this, wxID_ANY, WxUtils::LoadResourceBitmap("dolphin_logo")); - const wxString DolphinText = _("Dolphin"); - const wxString RevisionText = scm_desc_str; - const wxString CopyrightText = _("(c) 2003-2015+ Dolphin Team. \"GameCube\" and \"Wii\" are trademarks of Nintendo. Dolphin is not affiliated with Nintendo in any way."); - const wxString BranchText = wxString::Format(_("Branch: %s"), scm_branch_str.c_str()); - const wxString BranchRevText = wxString::Format(_("Revision: %s"), scm_rev_git_str.c_str()); - const wxString CheckUpdateText = _("Check for updates: "); - const wxString Text = _("\n" - "Dolphin is a free and open-source GameCube and Wii emulator.\n" - "\n" - "This software should not be used to play games you do not legally own.\n"); - const wxString LicenseText = _("License"); - const wxString AuthorsText = _("Authors"); - const wxString SupportText = _("Support"); + const wxString DolphinText = _("Dolphin"); + const wxString RevisionText = scm_desc_str; + const wxString CopyrightText = + _("(c) 2003-2015+ Dolphin Team. \"GameCube\" and \"Wii\" are trademarks of Nintendo. Dolphin " + "is not affiliated with Nintendo in any way."); + const wxString BranchText = wxString::Format(_("Branch: %s"), scm_branch_str.c_str()); + const wxString BranchRevText = wxString::Format(_("Revision: %s"), scm_rev_git_str.c_str()); + const wxString CheckUpdateText = _("Check for updates: "); + const wxString Text = + _("\n" + "Dolphin is a free and open-source GameCube and Wii emulator.\n" + "\n" + "This software should not be used to play games you do not legally own.\n"); + const wxString LicenseText = _("License"); + const wxString AuthorsText = _("Authors"); + const wxString SupportText = _("Support"); - wxStaticText* const Dolphin = new wxStaticText(this, wxID_ANY, DolphinText); - wxStaticText* const Revision = new wxStaticText(this, wxID_ANY, RevisionText); + wxStaticText* const Dolphin = new wxStaticText(this, wxID_ANY, DolphinText); + wxStaticText* const Revision = new wxStaticText(this, wxID_ANY, RevisionText); - wxStaticText* const Copyright = new wxStaticText(this, wxID_ANY, CopyrightText); - wxStaticText* const Branch = new wxStaticText(this, wxID_ANY, BranchText + "\n" + BranchRevText + "\n"); - wxStaticText* const Message = new wxStaticText(this, wxID_ANY, Text); - wxStaticText* const UpdateText = new wxStaticText(this, wxID_ANY, CheckUpdateText); - wxStaticText* const FirstSpacer = new wxStaticText(this, wxID_ANY, " | "); - wxStaticText* const SecondSpacer = new wxStaticText(this, wxID_ANY, " | "); - wxHyperlinkCtrl* const Download = new wxHyperlinkCtrl(this, wxID_ANY, "dolphin-emu.org/download", "https://dolphin-emu.org/download/"); - wxHyperlinkCtrl* const License = new wxHyperlinkCtrl(this, wxID_ANY, LicenseText, "https://github.com/dolphin-emu/dolphin/blob/master/license.txt"); - wxHyperlinkCtrl* const Authors = new wxHyperlinkCtrl(this, wxID_ANY, AuthorsText, "https://github.com/dolphin-emu/dolphin/graphs/contributors"); - wxHyperlinkCtrl* const Support = new wxHyperlinkCtrl(this, wxID_ANY, SupportText, "https://forums.dolphin-emu.org/"); + wxStaticText* const Copyright = new wxStaticText(this, wxID_ANY, CopyrightText); + wxStaticText* const Branch = + new wxStaticText(this, wxID_ANY, BranchText + "\n" + BranchRevText + "\n"); + wxStaticText* const Message = new wxStaticText(this, wxID_ANY, Text); + wxStaticText* const UpdateText = new wxStaticText(this, wxID_ANY, CheckUpdateText); + wxStaticText* const FirstSpacer = new wxStaticText(this, wxID_ANY, " | "); + wxStaticText* const SecondSpacer = new wxStaticText(this, wxID_ANY, " | "); + wxHyperlinkCtrl* const Download = new wxHyperlinkCtrl(this, wxID_ANY, "dolphin-emu.org/download", + "https://dolphin-emu.org/download/"); + wxHyperlinkCtrl* const License = + new wxHyperlinkCtrl(this, wxID_ANY, LicenseText, + "https://github.com/dolphin-emu/dolphin/blob/master/license.txt"); + wxHyperlinkCtrl* const Authors = new wxHyperlinkCtrl( + this, wxID_ANY, AuthorsText, "https://github.com/dolphin-emu/dolphin/graphs/contributors"); + wxHyperlinkCtrl* const Support = + new wxHyperlinkCtrl(this, wxID_ANY, SupportText, "https://forums.dolphin-emu.org/"); - wxFont DolphinFont = Dolphin->GetFont(); - wxFont RevisionFont = Revision->GetFont(); - wxFont CopyrightFont = Copyright->GetFont(); - wxFont BranchFont = Branch->GetFont(); + wxFont DolphinFont = Dolphin->GetFont(); + wxFont RevisionFont = Revision->GetFont(); + wxFont CopyrightFont = Copyright->GetFont(); + wxFont BranchFont = Branch->GetFont(); - DolphinFont.SetPointSize(36); - Dolphin->SetFont(DolphinFont); + DolphinFont.SetPointSize(36); + Dolphin->SetFont(DolphinFont); - RevisionFont.SetWeight(wxFONTWEIGHT_BOLD); - Revision->SetFont(RevisionFont); + RevisionFont.SetWeight(wxFONTWEIGHT_BOLD); + Revision->SetFont(RevisionFont); - BranchFont.SetPointSize(7); - Branch->SetFont(BranchFont); + BranchFont.SetPointSize(7); + Branch->SetFont(BranchFont); - CopyrightFont.SetPointSize(7); - Copyright->SetFont(CopyrightFont); - Copyright->SetFocus(); + CopyrightFont.SetPointSize(7); + Copyright->SetFont(CopyrightFont); + Copyright->SetFocus(); - wxBoxSizer* const sCheckUpdates = new wxBoxSizer(wxHORIZONTAL); - sCheckUpdates->Add(UpdateText); - sCheckUpdates->Add(Download); + wxBoxSizer* const sCheckUpdates = new wxBoxSizer(wxHORIZONTAL); + sCheckUpdates->Add(UpdateText); + sCheckUpdates->Add(Download); - wxBoxSizer* const sLinks = new wxBoxSizer(wxHORIZONTAL); - sLinks->Add(License); - sLinks->Add(FirstSpacer); - sLinks->Add(Authors); - sLinks->Add(SecondSpacer); - sLinks->Add(Support); + wxBoxSizer* const sLinks = new wxBoxSizer(wxHORIZONTAL); + sLinks->Add(License); + sLinks->Add(FirstSpacer); + sLinks->Add(Authors); + sLinks->Add(SecondSpacer); + sLinks->Add(Support); - wxBoxSizer* const sInfo = new wxBoxSizer(wxVERTICAL); - sInfo->Add(Dolphin); - sInfo->AddSpacer(5); - sInfo->Add(Revision); - sInfo->AddSpacer(10); - sInfo->Add(Branch); - sInfo->Add(sCheckUpdates); - sInfo->Add(Message); - sInfo->Add(sLinks); + wxBoxSizer* const sInfo = new wxBoxSizer(wxVERTICAL); + sInfo->Add(Dolphin); + sInfo->AddSpacer(5); + sInfo->Add(Revision); + sInfo->AddSpacer(10); + sInfo->Add(Branch); + sInfo->Add(sCheckUpdates); + sInfo->Add(Message); + sInfo->Add(sLinks); - wxBoxSizer* const sLogo = new wxBoxSizer(wxVERTICAL); - sLogo->AddSpacer(75); - sLogo->Add(sbDolphinLogo); - sLogo->AddSpacer(40); + wxBoxSizer* const sLogo = new wxBoxSizer(wxVERTICAL); + sLogo->AddSpacer(75); + sLogo->Add(sbDolphinLogo); + sLogo->AddSpacer(40); - wxBoxSizer* const sMainHor = new wxBoxSizer(wxHORIZONTAL); - sMainHor->AddSpacer(30); - sMainHor->Add(sLogo); - sMainHor->AddSpacer(30); - sMainHor->Add(sInfo); - sMainHor->AddSpacer(30); + wxBoxSizer* const sMainHor = new wxBoxSizer(wxHORIZONTAL); + sMainHor->AddSpacer(30); + sMainHor->Add(sLogo); + sMainHor->AddSpacer(30); + sMainHor->Add(sInfo); + sMainHor->AddSpacer(30); - wxBoxSizer* const sFooter = new wxBoxSizer(wxVERTICAL); - sFooter->AddSpacer(15); - sFooter->Add(Copyright, 0, wxALIGN_BOTTOM | wxALIGN_CENTER_HORIZONTAL); - sFooter->AddSpacer(5); + wxBoxSizer* const sFooter = new wxBoxSizer(wxVERTICAL); + sFooter->AddSpacer(15); + sFooter->Add(Copyright, 0, wxALIGN_BOTTOM | wxALIGN_CENTER_HORIZONTAL); + sFooter->AddSpacer(5); - wxBoxSizer* const sMain = new wxBoxSizer(wxVERTICAL); - sMain->Add(sMainHor, 1, wxEXPAND); - sMain->Add(sFooter, 0, wxEXPAND); + wxBoxSizer* const sMain = new wxBoxSizer(wxVERTICAL); + sMain->Add(sMainHor, 1, wxEXPAND); + sMain->Add(sFooter, 0, wxEXPAND); - SetSizerAndFit(sMain); - Center(); - SetFocus(); + SetSizerAndFit(sMain); + Center(); + SetFocus(); } diff --git a/Source/Core/DolphinWX/AboutDolphin.h b/Source/Core/DolphinWX/AboutDolphin.h index 6f40c4b632..cf3d0f2fc2 100644 --- a/Source/Core/DolphinWX/AboutDolphin.h +++ b/Source/Core/DolphinWX/AboutDolphin.h @@ -9,10 +9,7 @@ class AboutDolphin : public wxDialog { public: - AboutDolphin(wxWindow *parent, - wxWindowID id = wxID_ANY, - const wxString &title = _("About Dolphin"), - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxDEFAULT_DIALOG_STYLE); + AboutDolphin(wxWindow* parent, wxWindowID id = wxID_ANY, + const wxString& title = _("About Dolphin"), const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE); }; diff --git a/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp b/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp index 57a5db53c5..25ad5860e5 100644 --- a/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp +++ b/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp @@ -23,328 +23,329 @@ #include "Core/ActionReplay.h" #include "Core/Core.h" #include "Core/HW/Memmap.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Cheats/CheatSearchTab.h" #include "DolphinWX/Cheats/CreateCodeDialog.h" +#include "DolphinWX/WxUtils.h" namespace { - const unsigned int MAX_CHEAT_SEARCH_RESULTS_DISPLAY = 1024; +const unsigned int MAX_CHEAT_SEARCH_RESULTS_DISPLAY = 1024; } -CheatSearchTab::CheatSearchTab(wxWindow* const parent) - : wxPanel(parent) +CheatSearchTab::CheatSearchTab(wxWindow* const parent) : wxPanel(parent) { - m_update_timer.SetOwner(this); - Bind(wxEVT_TIMER, &CheatSearchTab::OnTimerUpdate, this); + m_update_timer.SetOwner(this); + Bind(wxEVT_TIMER, &CheatSearchTab::OnTimerUpdate, this); - // first scan button - m_btn_init_scan = new wxButton(this, wxID_ANY, _("New Scan")); - m_btn_init_scan->Bind(wxEVT_BUTTON, &CheatSearchTab::OnNewScanClicked, this); + // first scan button + m_btn_init_scan = new wxButton(this, wxID_ANY, _("New Scan")); + m_btn_init_scan->Bind(wxEVT_BUTTON, &CheatSearchTab::OnNewScanClicked, this); - // next scan button - m_btn_next_scan = new wxButton(this, wxID_ANY, _("Next Scan")); - m_btn_next_scan->Bind(wxEVT_BUTTON, &CheatSearchTab::OnNextScanClicked, this); - m_btn_next_scan->Disable(); + // next scan button + m_btn_next_scan = new wxButton(this, wxID_ANY, _("Next Scan")); + m_btn_next_scan->Bind(wxEVT_BUTTON, &CheatSearchTab::OnNextScanClicked, this); + m_btn_next_scan->Disable(); - // data sizes radiobox - std::array data_size_names = { { _("8-bit"), _("16-bit"), _("32-bit") } }; - m_data_sizes = new wxRadioBox(this, wxID_ANY, _("Data Size"), wxDefaultPosition, wxDefaultSize, static_cast(data_size_names.size()), data_size_names.data()); + // data sizes radiobox + std::array data_size_names = {{_("8-bit"), _("16-bit"), _("32-bit")}}; + m_data_sizes = new wxRadioBox(this, wxID_ANY, _("Data Size"), wxDefaultPosition, wxDefaultSize, + static_cast(data_size_names.size()), data_size_names.data()); - // ListView for search results - m_lview_search_results = new wxListView(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL); - ResetListViewColumns(); + // ListView for search results + m_lview_search_results = new wxListView(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxLC_REPORT | wxLC_SINGLE_SEL); + ResetListViewColumns(); - // Result count - m_label_results_count = new wxStaticText(this, wxID_ANY, _("Count:")); + // Result count + m_label_results_count = new wxStaticText(this, wxID_ANY, _("Count:")); - // create AR code button - wxButton* const button_cheat_search_copy_address = new wxButton(this, wxID_ANY, _("Create AR Code")); - button_cheat_search_copy_address->Bind(wxEVT_BUTTON, &CheatSearchTab::OnCreateARCodeClicked, this); + // create AR code button + wxButton* const button_cheat_search_copy_address = + new wxButton(this, wxID_ANY, _("Create AR Code")); + button_cheat_search_copy_address->Bind(wxEVT_BUTTON, &CheatSearchTab::OnCreateARCodeClicked, + this); - // results groupbox - wxStaticBoxSizer* const sizer_cheat_search_results = new wxStaticBoxSizer(wxVERTICAL, this, _("Results")); - sizer_cheat_search_results->Add(m_label_results_count, 0, wxALIGN_LEFT | wxALL, 5); - sizer_cheat_search_results->Add(m_lview_search_results, 1, wxEXPAND | wxALL, 5); - sizer_cheat_search_results->Add(button_cheat_search_copy_address, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5); + // results groupbox + wxStaticBoxSizer* const sizer_cheat_search_results = + new wxStaticBoxSizer(wxVERTICAL, this, _("Results")); + sizer_cheat_search_results->Add(m_label_results_count, 0, wxALIGN_LEFT | wxALL, 5); + sizer_cheat_search_results->Add(m_lview_search_results, 1, wxEXPAND | wxALL, 5); + sizer_cheat_search_results->Add(button_cheat_search_copy_address, 0, + wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5); - // search value textbox - m_textctrl_value_x = new wxTextCtrl(this, wxID_ANY, "0x0", wxDefaultPosition, wxSize(96, -1)); + // search value textbox + m_textctrl_value_x = new wxTextCtrl(this, wxID_ANY, "0x0", wxDefaultPosition, wxSize(96, -1)); - wxBoxSizer* const sizer_cheat_filter_text = new wxBoxSizer(wxHORIZONTAL); - sizer_cheat_filter_text->Add(m_textctrl_value_x, 1, wxALIGN_CENTER_VERTICAL, 5); + wxBoxSizer* const sizer_cheat_filter_text = new wxBoxSizer(wxHORIZONTAL); + sizer_cheat_filter_text->Add(m_textctrl_value_x, 1, wxALIGN_CENTER_VERTICAL, 5); - // Filter types in the compare dropdown - // TODO: Implement between search - wxArrayString filters; - filters.Add(_("Unknown")); - filters.Add(_("Not Equal")); - filters.Add(_("Equal")); - filters.Add(_("Greater Than")); - filters.Add(_("Less Than")); + // Filter types in the compare dropdown + // TODO: Implement between search + wxArrayString filters; + filters.Add(_("Unknown")); + filters.Add(_("Not Equal")); + filters.Add(_("Equal")); + filters.Add(_("Greater Than")); + filters.Add(_("Less Than")); - m_search_type = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, filters); - m_search_type->Select(0); + m_search_type = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, filters); + m_search_type->Select(0); - wxStaticBoxSizer* const sizer_cheat_search_filter = new wxStaticBoxSizer(wxVERTICAL, this, _("Search (clear to use previous value)")); - sizer_cheat_search_filter->Add(sizer_cheat_filter_text, 0, wxALL | wxEXPAND, 5); - sizer_cheat_search_filter->Add(m_search_type, 0, wxALL, 5); + wxStaticBoxSizer* const sizer_cheat_search_filter = + new wxStaticBoxSizer(wxVERTICAL, this, _("Search (clear to use previous value)")); + sizer_cheat_search_filter->Add(sizer_cheat_filter_text, 0, wxALL | wxEXPAND, 5); + sizer_cheat_search_filter->Add(m_search_type, 0, wxALL, 5); - // left sizer - wxBoxSizer* const sizer_left = new wxBoxSizer(wxVERTICAL); - sizer_left->Add(sizer_cheat_search_results, 1, wxEXPAND, 5); + // left sizer + wxBoxSizer* const sizer_left = new wxBoxSizer(wxVERTICAL); + sizer_left->Add(sizer_cheat_search_results, 1, wxEXPAND, 5); - // button sizer - wxBoxSizer* boxButtons = new wxBoxSizer(wxHORIZONTAL); - boxButtons->Add(m_btn_init_scan, 1, wxRIGHT, 5); - boxButtons->Add(m_btn_next_scan, 1); + // button sizer + wxBoxSizer* boxButtons = new wxBoxSizer(wxHORIZONTAL); + boxButtons->Add(m_btn_init_scan, 1, wxRIGHT, 5); + boxButtons->Add(m_btn_next_scan, 1); - // right sizer - wxBoxSizer* const sizer_right = new wxBoxSizer(wxVERTICAL); - sizer_right->Add(m_data_sizes, 0, wxEXPAND | wxBOTTOM, 5); - sizer_right->Add(sizer_cheat_search_filter, 0, wxEXPAND | wxBOTTOM, 5); - sizer_right->AddStretchSpacer(1); - sizer_right->Add(boxButtons, 0, wxTOP | wxEXPAND, 5); + // right sizer + wxBoxSizer* const sizer_right = new wxBoxSizer(wxVERTICAL); + sizer_right->Add(m_data_sizes, 0, wxEXPAND | wxBOTTOM, 5); + sizer_right->Add(sizer_cheat_search_filter, 0, wxEXPAND | wxBOTTOM, 5); + sizer_right->AddStretchSpacer(1); + sizer_right->Add(boxButtons, 0, wxTOP | wxEXPAND, 5); - // main sizer - wxBoxSizer* const sizer_main = new wxBoxSizer(wxHORIZONTAL); - sizer_main->Add(sizer_left, 1, wxEXPAND | wxALL, 5); - sizer_main->Add(sizer_right, 0, wxEXPAND | wxALL, 5); + // main sizer + wxBoxSizer* const sizer_main = new wxBoxSizer(wxHORIZONTAL); + sizer_main->Add(sizer_left, 1, wxEXPAND | wxALL, 5); + sizer_main->Add(sizer_right, 0, wxEXPAND | wxALL, 5); - SetSizerAndFit(sizer_main); + SetSizerAndFit(sizer_main); } void CheatSearchTab::OnNewScanClicked(wxCommandEvent& WXUNUSED(event)) { - if (!Core::IsRunningAndStarted()) - { - WxUtils::ShowErrorDialog(_("A game is not currently running.")); - return; - } + if (!Core::IsRunningAndStarted()) + { + WxUtils::ShowErrorDialog(_("A game is not currently running.")); + return; + } - // Determine the user-selected data size for this search. - m_search_type_size = (1 << m_data_sizes->GetSelection()); + // Determine the user-selected data size for this search. + m_search_type_size = (1 << m_data_sizes->GetSelection()); - // Set up the search results efficiently to prevent automatic re-allocations. - m_search_results.clear(); - m_search_results.reserve(Memory::RAM_SIZE / m_search_type_size); + // Set up the search results efficiently to prevent automatic re-allocations. + m_search_results.clear(); + m_search_results.reserve(Memory::RAM_SIZE / m_search_type_size); - // Enable the "Next Scan" button. - m_btn_next_scan->Enable(); + // Enable the "Next Scan" button. + m_btn_next_scan->Enable(); - CheatSearchResult r; - // can I assume cheatable values will be aligned like this? - for (u32 addr = 0; addr != Memory::RAM_SIZE; addr += m_search_type_size) - { - r.address = addr; - memcpy(&r.old_value, &Memory::m_pRAM[addr], m_search_type_size); - m_search_results.push_back(r); - } + CheatSearchResult r; + // can I assume cheatable values will be aligned like this? + for (u32 addr = 0; addr != Memory::RAM_SIZE; addr += m_search_type_size) + { + r.address = addr; + memcpy(&r.old_value, &Memory::m_pRAM[addr], m_search_type_size); + m_search_results.push_back(r); + } - UpdateCheatSearchResultsList(); + UpdateCheatSearchResultsList(); } void CheatSearchTab::OnNextScanClicked(wxCommandEvent&) { - if (!Core::IsRunningAndStarted()) - { - WxUtils::ShowErrorDialog(_("A game is not currently running.")); - return; - } + if (!Core::IsRunningAndStarted()) + { + WxUtils::ShowErrorDialog(_("A game is not currently running.")); + return; + } - u32 user_x_val = 0; - bool blank_user_value = m_textctrl_value_x->IsEmpty(); - if (!blank_user_value) - { - if (!ParseUserEnteredValue(&user_x_val)) - return; - } + u32 user_x_val = 0; + bool blank_user_value = m_textctrl_value_x->IsEmpty(); + if (!blank_user_value) + { + if (!ParseUserEnteredValue(&user_x_val)) + return; + } - FilterCheatSearchResults(user_x_val, blank_user_value); + FilterCheatSearchResults(user_x_val, blank_user_value); - UpdateCheatSearchResultsList(); + UpdateCheatSearchResultsList(); } void CheatSearchTab::OnCreateARCodeClicked(wxCommandEvent&) { - long idx = m_lview_search_results->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (idx == wxNOT_FOUND) - return; + long idx = m_lview_search_results->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (idx == wxNOT_FOUND) + return; - const u32 address = m_search_results[idx].address | ((m_search_type_size & ~1) << 24); + const u32 address = m_search_results[idx].address | ((m_search_type_size & ~1) << 24); - CreateCodeDialog arcode_dlg(this, address); - arcode_dlg.ShowModal(); + CreateCodeDialog arcode_dlg(this, address); + arcode_dlg.ShowModal(); } void CheatSearchTab::OnTimerUpdate(wxTimerEvent&) { - if (Core::GetState() != Core::CORE_RUN) - return; + if (Core::GetState() != Core::CORE_RUN) + return; - // Only update the currently visible list rows. - long first = m_lview_search_results->GetTopItem(); - long last = std::min(m_lview_search_results->GetItemCount(), m_lview_search_results->GetCountPerPage()); + // Only update the currently visible list rows. + long first = m_lview_search_results->GetTopItem(); + long last = + std::min(m_lview_search_results->GetItemCount(), m_lview_search_results->GetCountPerPage()); - m_lview_search_results->Freeze(); + m_lview_search_results->Freeze(); - while (first < last) - { - UpdateCheatSearchResultItem(first); - first++; - } + while (first < last) + { + UpdateCheatSearchResultItem(first); + first++; + } - m_lview_search_results->Thaw(); + m_lview_search_results->Thaw(); } void CheatSearchTab::UpdateCheatSearchResultsList() { - m_update_timer.Stop(); - m_lview_search_results->ClearAll(); - ResetListViewColumns(); + m_update_timer.Stop(); + m_lview_search_results->ClearAll(); + ResetListViewColumns(); - wxString count_label = wxString::Format(_("Count: %lu"), - (unsigned long)m_search_results.size()); - if (m_search_results.size() > MAX_CHEAT_SEARCH_RESULTS_DISPLAY) - { - count_label += _(" (too many to display)"); - } - else - { - m_lview_search_results->Freeze(); + wxString count_label = wxString::Format(_("Count: %lu"), (unsigned long)m_search_results.size()); + if (m_search_results.size() > MAX_CHEAT_SEARCH_RESULTS_DISPLAY) + { + count_label += _(" (too many to display)"); + } + else + { + m_lview_search_results->Freeze(); - for (size_t i = 0; i < m_search_results.size(); i++) - { - // Insert into the list control. - wxString address_string = wxString::Format("0x%08X", m_search_results[i].address); - long index = m_lview_search_results->InsertItem(static_cast(i), address_string); + for (size_t i = 0; i < m_search_results.size(); i++) + { + // Insert into the list control. + wxString address_string = wxString::Format("0x%08X", m_search_results[i].address); + long index = m_lview_search_results->InsertItem(static_cast(i), address_string); - UpdateCheatSearchResultItem(index); - } + UpdateCheatSearchResultItem(index); + } - m_lview_search_results->Thaw(); + m_lview_search_results->Thaw(); - // Half-second update interval - m_update_timer.Start(500); - } + // Half-second update interval + m_update_timer.Start(500); + } - m_label_results_count->SetLabel(count_label); + m_label_results_count->SetLabel(count_label); } void CheatSearchTab::UpdateCheatSearchResultItem(long index) { - u32 address_value = 0; - std::memcpy(&address_value, &Memory::m_pRAM[m_search_results[index].address], m_search_type_size); + u32 address_value = 0; + std::memcpy(&address_value, &Memory::m_pRAM[m_search_results[index].address], m_search_type_size); - u32 display_value = SwapValue(address_value); + u32 display_value = SwapValue(address_value); - wxString buf; - buf.Printf("0x%08X", display_value); - m_lview_search_results->SetItem(index, 1, buf); + wxString buf; + buf.Printf("0x%08X", display_value); + m_lview_search_results->SetItem(index, 1, buf); - float display_value_float = 0.0f; - std::memcpy(&display_value_float, &display_value, sizeof(u32)); - buf.Printf("%e", display_value_float); - m_lview_search_results->SetItem(index, 2, buf); + float display_value_float = 0.0f; + std::memcpy(&display_value_float, &display_value, sizeof(u32)); + buf.Printf("%e", display_value_float); + m_lview_search_results->SetItem(index, 2, buf); - double display_value_double = 0.0; - std::memcpy(&display_value_double, &display_value, sizeof(u32)); - buf.Printf("%e", display_value_double); - m_lview_search_results->SetItem(index, 3, buf); + double display_value_double = 0.0; + std::memcpy(&display_value_double, &display_value, sizeof(u32)); + buf.Printf("%e", display_value_double); + m_lview_search_results->SetItem(index, 3, buf); } enum class ComparisonMask { - EQUAL = 0x1, - GREATER_THAN = 0x2, - LESS_THAN = 0x4 + EQUAL = 0x1, + GREATER_THAN = 0x2, + LESS_THAN = 0x4 }; -static ComparisonMask operator | (ComparisonMask comp1, ComparisonMask comp2) +static ComparisonMask operator|(ComparisonMask comp1, ComparisonMask comp2) { - return static_cast(static_cast(comp1) | - static_cast(comp2)); + return static_cast(static_cast(comp1) | static_cast(comp2)); } -static ComparisonMask operator & (ComparisonMask comp1, ComparisonMask comp2) +static ComparisonMask operator&(ComparisonMask comp1, ComparisonMask comp2) { - return static_cast(static_cast(comp1) & - static_cast(comp2)); + return static_cast(static_cast(comp1) & static_cast(comp2)); } void CheatSearchTab::FilterCheatSearchResults(u32 value, bool prev) { - static const std::array filters{{ - ComparisonMask::EQUAL | ComparisonMask::GREATER_THAN | ComparisonMask::LESS_THAN, // Unknown - ComparisonMask::GREATER_THAN | ComparisonMask::LESS_THAN, // Not Equal - ComparisonMask::EQUAL, - ComparisonMask::GREATER_THAN, - ComparisonMask::LESS_THAN - }}; - ComparisonMask filter_mask = filters[m_search_type->GetSelection()]; + static const std::array filters{ + {ComparisonMask::EQUAL | ComparisonMask::GREATER_THAN | ComparisonMask::LESS_THAN, // Unknown + ComparisonMask::GREATER_THAN | ComparisonMask::LESS_THAN, // Not Equal + ComparisonMask::EQUAL, ComparisonMask::GREATER_THAN, ComparisonMask::LESS_THAN}}; + ComparisonMask filter_mask = filters[m_search_type->GetSelection()]; - std::vector filtered_results; - filtered_results.reserve(m_search_results.size()); + std::vector filtered_results; + filtered_results.reserve(m_search_results.size()); - for (CheatSearchResult& result : m_search_results) - { - if (prev) - value = result.old_value; + for (CheatSearchResult& result : m_search_results) + { + if (prev) + value = result.old_value; - // with big endian, can just use memcmp for ><= comparison - int cmp_result = std::memcmp(&Memory::m_pRAM[result.address], &value, m_search_type_size); - ComparisonMask cmp_mask; - if (cmp_result < 0) - cmp_mask = ComparisonMask::LESS_THAN; - else if (cmp_result) - cmp_mask = ComparisonMask::GREATER_THAN; - else - cmp_mask = ComparisonMask::EQUAL; + // with big endian, can just use memcmp for ><= comparison + int cmp_result = std::memcmp(&Memory::m_pRAM[result.address], &value, m_search_type_size); + ComparisonMask cmp_mask; + if (cmp_result < 0) + cmp_mask = ComparisonMask::LESS_THAN; + else if (cmp_result) + cmp_mask = ComparisonMask::GREATER_THAN; + else + cmp_mask = ComparisonMask::EQUAL; - if (static_cast(cmp_mask & filter_mask)) - { - std::memcpy(&result.old_value, &Memory::m_pRAM[result.address], m_search_type_size); - filtered_results.push_back(result); - } - } + if (static_cast(cmp_mask & filter_mask)) + { + std::memcpy(&result.old_value, &Memory::m_pRAM[result.address], m_search_type_size); + filtered_results.push_back(result); + } + } - m_search_results.swap(filtered_results); + m_search_results.swap(filtered_results); } void CheatSearchTab::ResetListViewColumns() { - m_lview_search_results->AppendColumn(_("Address")); - m_lview_search_results->AppendColumn(_("Value")); - m_lview_search_results->AppendColumn(_("Value (float)")); - m_lview_search_results->AppendColumn(_("Value (double)")); + m_lview_search_results->AppendColumn(_("Address")); + m_lview_search_results->AppendColumn(_("Value")); + m_lview_search_results->AppendColumn(_("Value (float)")); + m_lview_search_results->AppendColumn(_("Value (double)")); } bool CheatSearchTab::ParseUserEnteredValue(u32* out) const { - unsigned long parsed_x_val = 0; - wxString x_val = m_textctrl_value_x->GetValue(); + unsigned long parsed_x_val = 0; + wxString x_val = m_textctrl_value_x->GetValue(); - if (!x_val.ToULong(&parsed_x_val, 0)) - { - WxUtils::ShowErrorDialog(_("You must enter a valid decimal, hexadecimal or octal value.")); - return false; - } + if (!x_val.ToULong(&parsed_x_val, 0)) + { + WxUtils::ShowErrorDialog(_("You must enter a valid decimal, hexadecimal or octal value.")); + return false; + } - *out = SwapValue(static_cast(parsed_x_val)); - return true; + *out = SwapValue(static_cast(parsed_x_val)); + return true; } u32 CheatSearchTab::SwapValue(u32 value) const { - switch (m_search_type_size) - { - case 2: - *(u16*)&value = Common::swap16((u8*)&value); - break; - case 4: - value = Common::swap32(value); - break; - } + switch (m_search_type_size) + { + case 2: + *(u16*)&value = Common::swap16((u8*)&value); + break; + case 4: + value = Common::swap32(value); + break; + } - return value; + return value; } diff --git a/Source/Core/DolphinWX/Cheats/CheatSearchTab.h b/Source/Core/DolphinWX/Cheats/CheatSearchTab.h index 56fcc39e53..119eb88e47 100644 --- a/Source/Core/DolphinWX/Cheats/CheatSearchTab.h +++ b/Source/Core/DolphinWX/Cheats/CheatSearchTab.h @@ -20,42 +20,41 @@ class wxTextCtrl; class CheatSearchTab final : public wxPanel { public: - CheatSearchTab(wxWindow* const parent); + CheatSearchTab(wxWindow* const parent); private: - class CheatSearchResult final - { - public: - CheatSearchResult() : address(0), old_value(0) {} + class CheatSearchResult final + { + public: + CheatSearchResult() : address(0), old_value(0) {} + u32 address; + u32 old_value; + }; - u32 address; - u32 old_value; - }; + void UpdateCheatSearchResultsList(); + void UpdateCheatSearchResultItem(long index); + void FilterCheatSearchResults(u32 value, bool prev); + void ResetListViewColumns(); + bool ParseUserEnteredValue(u32* out) const; + u32 SwapValue(u32 value) const; - void UpdateCheatSearchResultsList(); - void UpdateCheatSearchResultItem(long index); - void FilterCheatSearchResults(u32 value, bool prev); - void ResetListViewColumns(); - bool ParseUserEnteredValue(u32* out) const; - u32 SwapValue(u32 value) const; + void OnNewScanClicked(wxCommandEvent&); + void OnNextScanClicked(wxCommandEvent&); + void OnCreateARCodeClicked(wxCommandEvent&); + void OnTimerUpdate(wxTimerEvent&); - void OnNewScanClicked(wxCommandEvent&); - void OnNextScanClicked(wxCommandEvent&); - void OnCreateARCodeClicked(wxCommandEvent&); - void OnTimerUpdate(wxTimerEvent&); + std::vector m_search_results; + unsigned int m_search_type_size; - std::vector m_search_results; - unsigned int m_search_type_size; + wxChoice* m_search_type; + wxListView* m_lview_search_results; + wxStaticText* m_label_results_count; + wxTextCtrl* m_textctrl_value_x; - wxChoice* m_search_type; - wxListView* m_lview_search_results; - wxStaticText* m_label_results_count; - wxTextCtrl* m_textctrl_value_x; + wxButton* m_btn_init_scan; + wxButton* m_btn_next_scan; - wxButton* m_btn_init_scan; - wxButton* m_btn_next_scan; + wxRadioBox* m_data_sizes; - wxRadioBox* m_data_sizes; - - wxTimer m_update_timer; + wxTimer m_update_timer; }; diff --git a/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp b/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp index 8d040a23e6..ef96aaa601 100644 --- a/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp +++ b/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp @@ -32,281 +32,291 @@ #include "Core/Core.h" #include "Core/GeckoCode.h" #include "Core/GeckoCodeConfig.h" -#include "DolphinWX/Frame.h" -#include "DolphinWX/Globals.h" -#include "DolphinWX/Main.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Cheats/CheatSearchTab.h" #include "DolphinWX/Cheats/CheatsWindow.h" #include "DolphinWX/Cheats/CreateCodeDialog.h" #include "DolphinWX/Cheats/GeckoCodeDiag.h" +#include "DolphinWX/Frame.h" +#include "DolphinWX/Globals.h" +#include "DolphinWX/Main.h" +#include "DolphinWX/WxUtils.h" wxDEFINE_EVENT(DOLPHIN_EVT_ADD_NEW_ACTION_REPLAY_CODE, wxCommandEvent); struct wxCheatsWindow::CodeData : public wxClientData { - ActionReplay::ARCode code; + ActionReplay::ARCode code; }; wxCheatsWindow::wxCheatsWindow(wxWindow* const parent) - : wxDialog(parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX | wxMINIMIZE_BOX | wxDIALOG_NO_PARENT) + : wxDialog(parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX | wxMINIMIZE_BOX | + wxDIALOG_NO_PARENT) { - // Create the GUI controls - Init_ChildControls(); + // Create the GUI controls + Init_ChildControls(); - // load codes - UpdateGUI(); - wxTheApp->Bind(DOLPHIN_EVT_LOCAL_INI_CHANGED, &wxCheatsWindow::OnEvent_CheatsList_Update, this); + // load codes + UpdateGUI(); + wxTheApp->Bind(DOLPHIN_EVT_LOCAL_INI_CHANGED, &wxCheatsWindow::OnEvent_CheatsList_Update, this); - SetSize(wxSize(-1, 600)); - Center(); - Show(); + SetSize(wxSize(-1, 600)); + Center(); + Show(); } wxCheatsWindow::~wxCheatsWindow() { - main_frame->g_CheatsWindow = nullptr; + main_frame->g_CheatsWindow = nullptr; } void wxCheatsWindow::Init_ChildControls() { - // Main Notebook - m_notebook_main = new wxNotebook(this, wxID_ANY); + // Main Notebook + m_notebook_main = new wxNotebook(this, wxID_ANY); - // --- Tabs --- - // Cheats List Tab - m_tab_cheats = new wxPanel(m_notebook_main, wxID_ANY); + // --- Tabs --- + // Cheats List Tab + m_tab_cheats = new wxPanel(m_notebook_main, wxID_ANY); - m_checklistbox_cheats_list = new wxCheckListBox(m_tab_cheats, wxID_ANY, wxDefaultPosition, wxSize(300, 0), 0, nullptr, wxLB_HSCROLL); - m_checklistbox_cheats_list->Bind(wxEVT_LISTBOX, &wxCheatsWindow::OnEvent_CheatsList_ItemSelected, this); + m_checklistbox_cheats_list = new wxCheckListBox(m_tab_cheats, wxID_ANY, wxDefaultPosition, + wxSize(300, 0), 0, nullptr, wxLB_HSCROLL); + m_checklistbox_cheats_list->Bind(wxEVT_LISTBOX, &wxCheatsWindow::OnEvent_CheatsList_ItemSelected, + this); - m_label_code_name = new wxStaticText(m_tab_cheats, wxID_ANY, _("Name: "), wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE); - m_groupbox_info = new wxStaticBox(m_tab_cheats, wxID_ANY, _("Code Info")); + m_label_code_name = new wxStaticText(m_tab_cheats, wxID_ANY, _("Name: "), wxDefaultPosition, + wxDefaultSize, wxST_NO_AUTORESIZE); + m_groupbox_info = new wxStaticBox(m_tab_cheats, wxID_ANY, _("Code Info")); - m_label_num_codes = new wxStaticText(m_tab_cheats, wxID_ANY, _("Number Of Codes: ")); - m_listbox_codes_list = new wxListBox(m_tab_cheats, wxID_ANY, wxDefaultPosition, wxSize(120, 150), 0, nullptr, wxLB_HSCROLL); + m_label_num_codes = new wxStaticText(m_tab_cheats, wxID_ANY, _("Number Of Codes: ")); + m_listbox_codes_list = new wxListBox(m_tab_cheats, wxID_ANY, wxDefaultPosition, wxSize(120, 150), + 0, nullptr, wxLB_HSCROLL); - wxStaticBoxSizer* sGroupBoxInfo = new wxStaticBoxSizer(m_groupbox_info, wxVERTICAL); - sGroupBoxInfo->Add(m_label_code_name, 0, wxEXPAND | wxALL, 5); - sGroupBoxInfo->Add(m_label_num_codes, 0, wxALL, 5); - sGroupBoxInfo->Add(m_listbox_codes_list, 1, wxALL, 5); + wxStaticBoxSizer* sGroupBoxInfo = new wxStaticBoxSizer(m_groupbox_info, wxVERTICAL); + sGroupBoxInfo->Add(m_label_code_name, 0, wxEXPAND | wxALL, 5); + sGroupBoxInfo->Add(m_label_num_codes, 0, wxALL, 5); + sGroupBoxInfo->Add(m_listbox_codes_list, 1, wxALL, 5); - wxBoxSizer* sizer_tab_cheats = new wxBoxSizer(wxHORIZONTAL); - sizer_tab_cheats->Add(m_checklistbox_cheats_list, 1, wxEXPAND | wxTOP | wxBOTTOM | wxLEFT, 10); - sizer_tab_cheats->Add(sGroupBoxInfo, 0, wxALIGN_LEFT | wxEXPAND | wxALL, 5); + wxBoxSizer* sizer_tab_cheats = new wxBoxSizer(wxHORIZONTAL); + sizer_tab_cheats->Add(m_checklistbox_cheats_list, 1, wxEXPAND | wxTOP | wxBOTTOM | wxLEFT, 10); + sizer_tab_cheats->Add(sGroupBoxInfo, 0, wxALIGN_LEFT | wxEXPAND | wxALL, 5); - m_tab_cheats->SetSizerAndFit(sizer_tab_cheats); + m_tab_cheats->SetSizerAndFit(sizer_tab_cheats); - // Cheat Search Tab - wxPanel* const tab_cheat_search = new CheatSearchTab(m_notebook_main); + // Cheat Search Tab + wxPanel* const tab_cheat_search = new CheatSearchTab(m_notebook_main); - // Log Tab - m_tab_log = new wxPanel(m_notebook_main, wxID_ANY); + // Log Tab + m_tab_log = new wxPanel(m_notebook_main, wxID_ANY); - wxButton* const button_updatelog = new wxButton(m_tab_log, wxID_ANY, _("Update")); - button_updatelog->Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ButtonUpdateLog_Press, this); - wxButton* const button_clearlog = new wxButton(m_tab_log, wxID_ANY, _("Clear")); - button_clearlog->Bind(wxEVT_BUTTON, &wxCheatsWindow::OnClearActionReplayLog, this); + wxButton* const button_updatelog = new wxButton(m_tab_log, wxID_ANY, _("Update")); + button_updatelog->Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ButtonUpdateLog_Press, this); + wxButton* const button_clearlog = new wxButton(m_tab_log, wxID_ANY, _("Clear")); + button_clearlog->Bind(wxEVT_BUTTON, &wxCheatsWindow::OnClearActionReplayLog, this); - m_checkbox_log_ar = new wxCheckBox(m_tab_log, wxID_ANY, _("Enable AR Logging")); - m_checkbox_log_ar->Bind(wxEVT_CHECKBOX, &wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange, this); + m_checkbox_log_ar = new wxCheckBox(m_tab_log, wxID_ANY, _("Enable AR Logging")); + m_checkbox_log_ar->Bind(wxEVT_CHECKBOX, + &wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange, this); - m_checkbox_log_ar->SetValue(ActionReplay::IsSelfLogging()); - m_textctrl_log = new wxTextCtrl(m_tab_log, wxID_ANY, "", wxDefaultPosition, wxSize(100, -1), wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP); + m_checkbox_log_ar->SetValue(ActionReplay::IsSelfLogging()); + m_textctrl_log = new wxTextCtrl(m_tab_log, wxID_ANY, "", wxDefaultPosition, wxSize(100, -1), + wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP); - wxBoxSizer *HStrip1 = new wxBoxSizer(wxHORIZONTAL); - HStrip1->Add(m_checkbox_log_ar, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); - HStrip1->Add(button_updatelog, 0, wxALL, 5); - HStrip1->Add(button_clearlog, 0, wxALL, 5); + wxBoxSizer* HStrip1 = new wxBoxSizer(wxHORIZONTAL); + HStrip1->Add(m_checkbox_log_ar, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + HStrip1->Add(button_updatelog, 0, wxALL, 5); + HStrip1->Add(button_clearlog, 0, wxALL, 5); - wxBoxSizer *sTabLog = new wxBoxSizer(wxVERTICAL); - sTabLog->Add(HStrip1, 0, wxALL, 5); - sTabLog->Add(m_textctrl_log, 1, wxALL | wxEXPAND, 5); + wxBoxSizer* sTabLog = new wxBoxSizer(wxVERTICAL); + sTabLog->Add(HStrip1, 0, wxALL, 5); + sTabLog->Add(m_textctrl_log, 1, wxALL | wxEXPAND, 5); - m_tab_log->SetSizerAndFit(sTabLog); + m_tab_log->SetSizerAndFit(sTabLog); - // Add Tabs to Notebook - m_notebook_main->AddPage(m_tab_cheats, _("AR Codes")); - m_geckocode_panel = new Gecko::CodeConfigPanel(m_notebook_main); - m_notebook_main->AddPage(m_geckocode_panel, _("Gecko Codes")); - m_notebook_main->AddPage(tab_cheat_search, _("Cheat Search")); - m_notebook_main->AddPage(m_tab_log, _("Logging")); + // Add Tabs to Notebook + m_notebook_main->AddPage(m_tab_cheats, _("AR Codes")); + m_geckocode_panel = new Gecko::CodeConfigPanel(m_notebook_main); + m_notebook_main->AddPage(m_geckocode_panel, _("Gecko Codes")); + m_notebook_main->AddPage(tab_cheat_search, _("Cheat Search")); + m_notebook_main->AddPage(m_tab_log, _("Logging")); - Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ApplyChanges_Press, this, wxID_APPLY); - Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ButtonClose_Press, this, wxID_CANCEL); - Bind(wxEVT_CLOSE_WINDOW, &wxCheatsWindow::OnEvent_Close, this); - Bind(DOLPHIN_EVT_ADD_NEW_ACTION_REPLAY_CODE, &wxCheatsWindow::OnNewARCodeCreated, this); + Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ApplyChanges_Press, this, wxID_APPLY); + Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ButtonClose_Press, this, wxID_CANCEL); + Bind(wxEVT_CLOSE_WINDOW, &wxCheatsWindow::OnEvent_Close, this); + Bind(DOLPHIN_EVT_ADD_NEW_ACTION_REPLAY_CODE, &wxCheatsWindow::OnNewARCodeCreated, this); - wxStdDialogButtonSizer* const sButtons = CreateStdDialogButtonSizer(wxAPPLY | wxCANCEL); - m_button_apply = sButtons->GetApplyButton(); - SetEscapeId(wxID_CANCEL); - SetAffirmativeId(wxID_CANCEL); + wxStdDialogButtonSizer* const sButtons = CreateStdDialogButtonSizer(wxAPPLY | wxCANCEL); + m_button_apply = sButtons->GetApplyButton(); + SetEscapeId(wxID_CANCEL); + SetAffirmativeId(wxID_CANCEL); - wxBoxSizer* const sMain = new wxBoxSizer(wxVERTICAL); - sMain->Add(m_notebook_main, 1, wxEXPAND | wxALL, 5); - sMain->Add(sButtons, 0, wxRIGHT | wxBOTTOM | wxALIGN_RIGHT, 5); - SetSizerAndFit(sMain); + wxBoxSizer* const sMain = new wxBoxSizer(wxVERTICAL); + sMain->Add(m_notebook_main, 1, wxEXPAND | wxALL, 5); + sMain->Add(sButtons, 0, wxRIGHT | wxBOTTOM | wxALIGN_RIGHT, 5); + SetSizerAndFit(sMain); } void wxCheatsWindow::OnEvent_ButtonClose_Press(wxCommandEvent& WXUNUSED(event)) { - Close(); + Close(); } void wxCheatsWindow::OnEvent_Close(wxCloseEvent& ev) { - Destroy(); + Destroy(); } // load codes for a new ISO ID void wxCheatsWindow::UpdateGUI() { - // load code - const SConfig& parameters = SConfig::GetInstance(); - m_gameini_default = parameters.LoadDefaultGameIni(); - m_gameini_local = parameters.LoadLocalGameIni(); - m_game_id = parameters.GetUniqueID(); - m_game_revision = parameters.m_revision; - m_gameini_local_path = File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini"; - Load_ARCodes(); - Load_GeckoCodes(); + // load code + const SConfig& parameters = SConfig::GetInstance(); + m_gameini_default = parameters.LoadDefaultGameIni(); + m_gameini_local = parameters.LoadLocalGameIni(); + m_game_id = parameters.GetUniqueID(); + m_game_revision = parameters.m_revision; + m_gameini_local_path = File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini"; + Load_ARCodes(); + Load_GeckoCodes(); - // enable controls - m_button_apply->Enable(Core::IsRunning()); + // enable controls + m_button_apply->Enable(Core::IsRunning()); - wxString title = _("Cheat Manager"); + wxString title = _("Cheat Manager"); - // write the ISO name in the title - if (Core::IsRunning()) - SetTitle(title + StrToWxStr(": " + m_game_id + " - " + parameters.m_strName)); - else - SetTitle(title); + // write the ISO name in the title + if (Core::IsRunning()) + SetTitle(title + StrToWxStr(": " + m_game_id + " - " + parameters.m_strName)); + else + SetTitle(title); } void wxCheatsWindow::Load_ARCodes() { - m_checklistbox_cheats_list->Clear(); + m_checklistbox_cheats_list->Clear(); - if (!Core::IsRunning()) - return; + if (!Core::IsRunning()) + return; - m_checklistbox_cheats_list->Freeze(); - for (auto& code : ActionReplay::LoadCodes(m_gameini_default, m_gameini_local)) - { - CodeData* cd = new CodeData(); - cd->code = std::move(code); - int index = m_checklistbox_cheats_list->Append(wxCheckListBox::EscapeMnemonics(StrToWxStr(cd->code.name)), - cd); - m_checklistbox_cheats_list->Check(index, cd->code.active); - } - m_checklistbox_cheats_list->Thaw(); + m_checklistbox_cheats_list->Freeze(); + for (auto& code : ActionReplay::LoadCodes(m_gameini_default, m_gameini_local)) + { + CodeData* cd = new CodeData(); + cd->code = std::move(code); + int index = m_checklistbox_cheats_list->Append( + wxCheckListBox::EscapeMnemonics(StrToWxStr(cd->code.name)), cd); + m_checklistbox_cheats_list->Check(index, cd->code.active); + } + m_checklistbox_cheats_list->Thaw(); } void wxCheatsWindow::Load_GeckoCodes() { - m_geckocode_panel->LoadCodes(m_gameini_default, m_gameini_local, SConfig::GetInstance().GetUniqueID(), true); + m_geckocode_panel->LoadCodes(m_gameini_default, m_gameini_local, + SConfig::GetInstance().GetUniqueID(), true); } void wxCheatsWindow::OnNewARCodeCreated(wxCommandEvent& ev) { - auto code = static_cast(ev.GetClientData()); - ActionReplay::AddCode(*code); + auto code = static_cast(ev.GetClientData()); + ActionReplay::AddCode(*code); - CodeData* cd = new CodeData(); - cd->code = *code; - int idx = m_checklistbox_cheats_list->Append(wxCheckListBox::EscapeMnemonics(StrToWxStr(code->name)), - cd); - m_checklistbox_cheats_list->Check(idx, code->active); + CodeData* cd = new CodeData(); + cd->code = *code; + int idx = m_checklistbox_cheats_list->Append( + wxCheckListBox::EscapeMnemonics(StrToWxStr(code->name)), cd); + m_checklistbox_cheats_list->Check(idx, code->active); } void wxCheatsWindow::OnEvent_CheatsList_ItemSelected(wxCommandEvent& event) { - CodeData* cd = static_cast(event.GetClientObject()); + CodeData* cd = static_cast(event.GetClientObject()); - m_label_code_name->SetLabelText(_("Name: ") + StrToWxStr(cd->code.name)); - m_label_code_name->Wrap(m_label_code_name->GetSize().GetWidth()); - m_label_code_name->InvalidateBestSize(); - m_label_num_codes->SetLabelText(wxString::Format("%s%zu", _("Number Of Codes: "), cd->code.ops.size())); + m_label_code_name->SetLabelText(_("Name: ") + StrToWxStr(cd->code.name)); + m_label_code_name->Wrap(m_label_code_name->GetSize().GetWidth()); + m_label_code_name->InvalidateBestSize(); + m_label_num_codes->SetLabelText( + wxString::Format("%s%zu", _("Number Of Codes: "), cd->code.ops.size())); - m_listbox_codes_list->Freeze(); - m_listbox_codes_list->Clear(); - for (const ActionReplay::AREntry& entry : cd->code.ops) - { - m_listbox_codes_list->Append(wxString::Format("%08x %08x", entry.cmd_addr, entry.value)); - } - m_listbox_codes_list->Thaw(); + m_listbox_codes_list->Freeze(); + m_listbox_codes_list->Clear(); + for (const ActionReplay::AREntry& entry : cd->code.ops) + { + m_listbox_codes_list->Append(wxString::Format("%08x %08x", entry.cmd_addr, entry.value)); + } + m_listbox_codes_list->Thaw(); - m_tab_cheats->Layout(); + m_tab_cheats->Layout(); } void wxCheatsWindow::OnEvent_CheatsList_Update(wxCommandEvent& ev) { - ev.Skip(); - if (WxStrToStr(ev.GetString()) != m_game_id) - return; - if (m_ignore_ini_callback) - { - m_ignore_ini_callback = false; - return; - } - UpdateGUI(); + ev.Skip(); + if (WxStrToStr(ev.GetString()) != m_game_id) + return; + if (m_ignore_ini_callback) + { + m_ignore_ini_callback = false; + return; + } + UpdateGUI(); } void wxCheatsWindow::OnEvent_ApplyChanges_Press(wxCommandEvent& ev) { - // Convert embedded metadata back into ARCode vector and update active states - std::vector code_vec; - code_vec.reserve(m_checklistbox_cheats_list->GetCount()); - for (unsigned int i = 0; i < m_checklistbox_cheats_list->GetCount(); ++i) - { - CodeData* cd = static_cast(m_checklistbox_cheats_list->GetClientObject(i)); - cd->code.active = m_checklistbox_cheats_list->IsChecked(i); - code_vec.push_back(cd->code); - } + // Convert embedded metadata back into ARCode vector and update active states + std::vector code_vec; + code_vec.reserve(m_checklistbox_cheats_list->GetCount()); + for (unsigned int i = 0; i < m_checklistbox_cheats_list->GetCount(); ++i) + { + CodeData* cd = static_cast(m_checklistbox_cheats_list->GetClientObject(i)); + cd->code.active = m_checklistbox_cheats_list->IsChecked(i); + code_vec.push_back(cd->code); + } - // Apply Action Replay code changes - ActionReplay::ApplyCodes(code_vec); + // Apply Action Replay code changes + ActionReplay::ApplyCodes(code_vec); - // Apply Gecko Code changes - Gecko::SetActiveCodes(m_geckocode_panel->GetCodes()); + // Apply Gecko Code changes + Gecko::SetActiveCodes(m_geckocode_panel->GetCodes()); - // Save gameini, with changed codes - if (m_gameini_local_path.size()) - { - ActionReplay::SaveCodes(&m_gameini_local, code_vec); - Gecko::SaveCodes(m_gameini_local, m_geckocode_panel->GetCodes()); - m_gameini_local.Save(m_gameini_local_path); + // Save gameini, with changed codes + if (m_gameini_local_path.size()) + { + ActionReplay::SaveCodes(&m_gameini_local, code_vec); + Gecko::SaveCodes(m_gameini_local, m_geckocode_panel->GetCodes()); + m_gameini_local.Save(m_gameini_local_path); - wxCommandEvent ini_changed(DOLPHIN_EVT_LOCAL_INI_CHANGED); - ini_changed.SetString(StrToWxStr(m_game_id)); - ini_changed.SetInt(m_game_revision); - m_ignore_ini_callback = true; - wxTheApp->ProcessEvent(ini_changed); - } + wxCommandEvent ini_changed(DOLPHIN_EVT_LOCAL_INI_CHANGED); + ini_changed.SetString(StrToWxStr(m_game_id)); + ini_changed.SetInt(m_game_revision); + m_ignore_ini_callback = true; + wxTheApp->ProcessEvent(ini_changed); + } - ev.Skip(); + ev.Skip(); } void wxCheatsWindow::OnEvent_ButtonUpdateLog_Press(wxCommandEvent& WXUNUSED(event)) { - wxBeginBusyCursor(); - m_textctrl_log->Freeze(); - m_textctrl_log->Clear(); - for (const std::string& text : ActionReplay::GetSelfLog()) - { - m_textctrl_log->AppendText(StrToWxStr(text)); - } - m_textctrl_log->Thaw(); - wxEndBusyCursor(); + wxBeginBusyCursor(); + m_textctrl_log->Freeze(); + m_textctrl_log->Clear(); + for (const std::string& text : ActionReplay::GetSelfLog()) + { + m_textctrl_log->AppendText(StrToWxStr(text)); + } + m_textctrl_log->Thaw(); + wxEndBusyCursor(); } void wxCheatsWindow::OnClearActionReplayLog(wxCommandEvent& event) { - ActionReplay::ClearSelfLog(); - OnEvent_ButtonUpdateLog_Press(event); + ActionReplay::ClearSelfLog(); + OnEvent_ButtonUpdateLog_Press(event); } void wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange(wxCommandEvent& WXUNUSED(event)) { - ActionReplay::EnableSelfLogging(m_checkbox_log_ar->IsChecked()); + ActionReplay::EnableSelfLogging(m_checkbox_log_ar->IsChecked()); } diff --git a/Source/Core/DolphinWX/Cheats/CheatsWindow.h b/Source/Core/DolphinWX/Cheats/CheatsWindow.h index a3f3d8ef06..252b0c890b 100644 --- a/Source/Core/DolphinWX/Cheats/CheatsWindow.h +++ b/Source/Core/DolphinWX/Cheats/CheatsWindow.h @@ -26,7 +26,7 @@ class wxTextCtrl; namespace Gecko { - class CodeConfigPanel; +class CodeConfigPanel; } wxDECLARE_EVENT(DOLPHIN_EVT_ADD_NEW_ACTION_REPLAY_CODE, wxCommandEvent); @@ -34,66 +34,66 @@ wxDECLARE_EVENT(DOLPHIN_EVT_ADD_NEW_ACTION_REPLAY_CODE, wxCommandEvent); class wxCheatsWindow final : public wxDialog { public: - wxCheatsWindow(wxWindow* const parent); - ~wxCheatsWindow(); - void UpdateGUI(); + wxCheatsWindow(wxWindow* const parent); + ~wxCheatsWindow(); + void UpdateGUI(); private: - struct CodeData; + struct CodeData; - // --- GUI Controls --- - wxButton* m_button_apply; - wxNotebook* m_notebook_main; + // --- GUI Controls --- + wxButton* m_button_apply; + wxNotebook* m_notebook_main; - wxPanel* m_tab_cheats; - wxPanel* m_tab_log; + wxPanel* m_tab_cheats; + wxPanel* m_tab_log; - wxCheckBox* m_checkbox_log_ar; + wxCheckBox* m_checkbox_log_ar; - wxStaticText* m_label_code_name; - wxStaticText* m_label_num_codes; + wxStaticText* m_label_code_name; + wxStaticText* m_label_num_codes; - wxCheckListBox* m_checklistbox_cheats_list; + wxCheckListBox* m_checklistbox_cheats_list; - wxTextCtrl* m_textctrl_log; + wxTextCtrl* m_textctrl_log; - wxListBox* m_listbox_codes_list; + wxListBox* m_listbox_codes_list; - wxStaticBox* m_groupbox_info; + wxStaticBox* m_groupbox_info; - Gecko::CodeConfigPanel* m_geckocode_panel; - IniFile m_gameini_default; - IniFile m_gameini_local; - std::string m_gameini_local_path; - std::string m_game_id; - u32 m_game_revision; + Gecko::CodeConfigPanel* m_geckocode_panel; + IniFile m_gameini_default; + IniFile m_gameini_local; + std::string m_gameini_local_path; + std::string m_game_id; + u32 m_game_revision; - bool m_ignore_ini_callback = false; + bool m_ignore_ini_callback = false; - void Init_ChildControls(); + void Init_ChildControls(); - void Load_ARCodes(); - void Load_GeckoCodes(); + void Load_ARCodes(); + void Load_GeckoCodes(); - // --- Wx Events Handlers --- - // Cheat Search - void OnNewARCodeCreated(wxCommandEvent& ev); + // --- Wx Events Handlers --- + // Cheat Search + void OnNewARCodeCreated(wxCommandEvent& ev); - // Close Button - void OnEvent_ButtonClose_Press(wxCommandEvent& event); - void OnEvent_Close(wxCloseEvent& ev); + // Close Button + void OnEvent_ButtonClose_Press(wxCommandEvent& event); + void OnEvent_Close(wxCloseEvent& ev); - // Cheats List - void OnEvent_CheatsList_ItemSelected(wxCommandEvent& event); - void OnEvent_CheatsList_Update(wxCommandEvent& event); + // Cheats List + void OnEvent_CheatsList_ItemSelected(wxCommandEvent& event); + void OnEvent_CheatsList_Update(wxCommandEvent& event); - // Apply Changes Button - void OnEvent_ApplyChanges_Press(wxCommandEvent& event); + // Apply Changes Button + void OnEvent_ApplyChanges_Press(wxCommandEvent& event); - // Update Log Button - void OnEvent_ButtonUpdateLog_Press(wxCommandEvent& event); - void OnClearActionReplayLog(wxCommandEvent& event); + // Update Log Button + void OnEvent_ButtonUpdateLog_Press(wxCommandEvent& event); + void OnClearActionReplayLog(wxCommandEvent& event); - // Enable Logging Checkbox - void OnEvent_CheckBoxEnableLogging_StateChange(wxCommandEvent& event); + // Enable Logging Checkbox + void OnEvent_CheckBoxEnableLogging_StateChange(wxCommandEvent& event); }; diff --git a/Source/Core/DolphinWX/Cheats/CreateCodeDialog.cpp b/Source/Core/DolphinWX/Cheats/CreateCodeDialog.cpp index 34b6baac82..32b4ac09a9 100644 --- a/Source/Core/DolphinWX/Cheats/CreateCodeDialog.cpp +++ b/Source/Core/DolphinWX/Cheats/CreateCodeDialog.cpp @@ -10,87 +10,87 @@ #include "Core/ActionReplay.h" #include "Core/ConfigManager.h" -#include "DolphinWX/ISOProperties.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Cheats/CheatsWindow.h" #include "DolphinWX/Cheats/CreateCodeDialog.h" +#include "DolphinWX/ISOProperties.h" +#include "DolphinWX/WxUtils.h" CreateCodeDialog::CreateCodeDialog(wxWindow* const parent, const u32 address) - : wxDialog(parent, wxID_ANY, _("Create AR Code")) - , m_code_address(address) + : wxDialog(parent, wxID_ANY, _("Create AR Code")), m_code_address(address) { - wxStaticText* const label_name = new wxStaticText(this, wxID_ANY, _("Name: ")); - m_textctrl_name = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(256, -1)); + wxStaticText* const label_name = new wxStaticText(this, wxID_ANY, _("Name: ")); + m_textctrl_name = + new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(256, -1)); - wxStaticText* const label_code = new wxStaticText(this, wxID_ANY, _("Code: ")); - m_textctrl_code = new wxTextCtrl(this, wxID_ANY, wxString::Format("0x%08x", address)); - m_textctrl_code->Disable(); + wxStaticText* const label_code = new wxStaticText(this, wxID_ANY, _("Code: ")); + m_textctrl_code = new wxTextCtrl(this, wxID_ANY, wxString::Format("0x%08x", address)); + m_textctrl_code->Disable(); - wxStaticText* const label_value = new wxStaticText(this, wxID_ANY, _("Value: ")); - m_textctrl_value = new wxTextCtrl(this, wxID_ANY, "0"); + wxStaticText* const label_value = new wxStaticText(this, wxID_ANY, _("Value: ")); + m_textctrl_value = new wxTextCtrl(this, wxID_ANY, "0"); - m_checkbox_use_hex = new wxCheckBox(this, wxID_ANY, _("Use Hex")); - m_checkbox_use_hex->SetValue(true); + m_checkbox_use_hex = new wxCheckBox(this, wxID_ANY, _("Use Hex")); + m_checkbox_use_hex->SetValue(true); - wxBoxSizer* const sizer_value_label = new wxBoxSizer(wxHORIZONTAL); - sizer_value_label->Add(label_value, 0, wxRIGHT, 5); - sizer_value_label->Add(m_checkbox_use_hex); + wxBoxSizer* const sizer_value_label = new wxBoxSizer(wxHORIZONTAL); + sizer_value_label->Add(label_value, 0, wxRIGHT, 5); + sizer_value_label->Add(m_checkbox_use_hex); - // main sizer - wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL); - sizer_main->Add(label_name, 0, wxALL, 5); - sizer_main->Add(m_textctrl_name, 0, wxALL, 5); - sizer_main->Add(label_code, 0, wxALL, 5); - sizer_main->Add(m_textctrl_code, 0, wxALL, 5); - sizer_main->Add(sizer_value_label, 0, wxALL, 5); - sizer_main->Add(m_textctrl_value, 0, wxALL, 5); - sizer_main->Add(CreateButtonSizer(wxOK | wxCANCEL | wxNO_DEFAULT), 0, wxALL, 5); + // main sizer + wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL); + sizer_main->Add(label_name, 0, wxALL, 5); + sizer_main->Add(m_textctrl_name, 0, wxALL, 5); + sizer_main->Add(label_code, 0, wxALL, 5); + sizer_main->Add(m_textctrl_code, 0, wxALL, 5); + sizer_main->Add(sizer_value_label, 0, wxALL, 5); + sizer_main->Add(m_textctrl_value, 0, wxALL, 5); + sizer_main->Add(CreateButtonSizer(wxOK | wxCANCEL | wxNO_DEFAULT), 0, wxALL, 5); - Bind(wxEVT_BUTTON, &CreateCodeDialog::PressOK, this, wxID_OK); - Bind(wxEVT_BUTTON, &CreateCodeDialog::PressCancel, this, wxID_CANCEL); - Bind(wxEVT_CLOSE_WINDOW, &CreateCodeDialog::OnEvent_Close, this); + Bind(wxEVT_BUTTON, &CreateCodeDialog::PressOK, this, wxID_OK); + Bind(wxEVT_BUTTON, &CreateCodeDialog::PressCancel, this, wxID_CANCEL); + Bind(wxEVT_CLOSE_WINDOW, &CreateCodeDialog::OnEvent_Close, this); - SetSizerAndFit(sizer_main); - SetFocus(); + SetSizerAndFit(sizer_main); + SetFocus(); } void CreateCodeDialog::PressOK(wxCommandEvent& ev) { - const wxString code_name = m_textctrl_name->GetValue(); - if (code_name.empty()) - { - WxUtils::ShowErrorDialog(_("You must enter a name.")); - return; - } + const wxString code_name = m_textctrl_name->GetValue(); + if (code_name.empty()) + { + WxUtils::ShowErrorDialog(_("You must enter a name.")); + return; + } - long code_value; - int base = m_checkbox_use_hex->IsChecked() ? 16 : 10; - if (!m_textctrl_value->GetValue().ToLong(&code_value, base)) - { - WxUtils::ShowErrorDialog(_("Invalid value.")); - return; - } + long code_value; + int base = m_checkbox_use_hex->IsChecked() ? 16 : 10; + if (!m_textctrl_value->GetValue().ToLong(&code_value, base)) + { + WxUtils::ShowErrorDialog(_("Invalid value.")); + return; + } - // create the new code - ActionReplay::ARCode new_cheat; - new_cheat.active = false; - new_cheat.user_defined = true; - new_cheat.name = WxStrToStr(code_name); - new_cheat.ops.emplace_back(ActionReplay::AREntry(m_code_address, code_value)); + // create the new code + ActionReplay::ARCode new_cheat; + new_cheat.active = false; + new_cheat.user_defined = true; + new_cheat.name = WxStrToStr(code_name); + new_cheat.ops.emplace_back(ActionReplay::AREntry(m_code_address, code_value)); - wxCommandEvent add_event(DOLPHIN_EVT_ADD_NEW_ACTION_REPLAY_CODE, GetId()); - add_event.SetClientData(&new_cheat); - GetParent()->GetEventHandler()->ProcessEvent(add_event); + wxCommandEvent add_event(DOLPHIN_EVT_ADD_NEW_ACTION_REPLAY_CODE, GetId()); + add_event.SetClientData(&new_cheat); + GetParent()->GetEventHandler()->ProcessEvent(add_event); - Close(); + Close(); } void CreateCodeDialog::PressCancel(wxCommandEvent& ev) { - Close(); + Close(); } void CreateCodeDialog::OnEvent_Close(wxCloseEvent& ev) { - Destroy(); + Destroy(); } diff --git a/Source/Core/DolphinWX/Cheats/CreateCodeDialog.h b/Source/Core/DolphinWX/Cheats/CreateCodeDialog.h index bc9ca0ad2b..8eae79e564 100644 --- a/Source/Core/DolphinWX/Cheats/CreateCodeDialog.h +++ b/Source/Core/DolphinWX/Cheats/CreateCodeDialog.h @@ -15,17 +15,17 @@ class wxTextCtrl; class CreateCodeDialog final : public wxDialog { public: - CreateCodeDialog(wxWindow* const parent, const u32 address); + CreateCodeDialog(wxWindow* const parent, const u32 address); private: - const u32 m_code_address; + const u32 m_code_address; - wxTextCtrl* m_textctrl_name; - wxTextCtrl* m_textctrl_code; - wxTextCtrl* m_textctrl_value; - wxCheckBox* m_checkbox_use_hex; + wxTextCtrl* m_textctrl_name; + wxTextCtrl* m_textctrl_code; + wxTextCtrl* m_textctrl_value; + wxCheckBox* m_checkbox_use_hex; - void PressOK(wxCommandEvent&); - void PressCancel(wxCommandEvent&); - void OnEvent_Close(wxCloseEvent& ev); + void PressOK(wxCommandEvent&); + void PressCancel(wxCommandEvent&); + void OnEvent_Close(wxCloseEvent& ev); }; diff --git a/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.cpp b/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.cpp index 5aad07b697..9ef181354a 100644 --- a/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.cpp +++ b/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.cpp @@ -2,10 +2,10 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #include #include -#include #include #include #include @@ -20,287 +20,284 @@ #include "Core/Core.h" #include "Core/GeckoCode.h" #include "Core/GeckoCodeConfig.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Cheats/GeckoCodeDiag.h" +#include "DolphinWX/WxUtils.h" namespace Gecko { +static const wxString wxstr_name(wxTRANSLATE("Name: ")), wxstr_notes(wxTRANSLATE("Notes: ")), + wxstr_creator(wxTRANSLATE("Creator: ")); -static const wxString wxstr_name(wxTRANSLATE("Name: ")), - wxstr_notes(wxTRANSLATE("Notes: ")), - wxstr_creator(wxTRANSLATE("Creator: ")); - -CodeConfigPanel::CodeConfigPanel(wxWindow* const parent) - : wxPanel(parent) +CodeConfigPanel::CodeConfigPanel(wxWindow* const parent) : wxPanel(parent) { - m_listbox_gcodes = new wxCheckListBox(this, wxID_ANY); - m_listbox_gcodes->Bind(wxEVT_LISTBOX, &CodeConfigPanel::UpdateInfoBox, this); - m_listbox_gcodes->Bind(wxEVT_CHECKLISTBOX, &CodeConfigPanel::ToggleCode, this); + m_listbox_gcodes = new wxCheckListBox(this, wxID_ANY); + m_listbox_gcodes->Bind(wxEVT_LISTBOX, &CodeConfigPanel::UpdateInfoBox, this); + m_listbox_gcodes->Bind(wxEVT_CHECKLISTBOX, &CodeConfigPanel::ToggleCode, this); - m_infobox.label_name = new wxStaticText(this, wxID_ANY, wxGetTranslation(wxstr_name)); - m_infobox.label_creator = new wxStaticText(this, wxID_ANY, wxGetTranslation(wxstr_creator)); - m_infobox.label_notes = new wxStaticText(this, wxID_ANY, wxGetTranslation(wxstr_notes)); - m_infobox.textctrl_notes = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(64, -1), wxTE_MULTILINE | wxTE_READONLY); - m_infobox.listbox_codes = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 64)); + m_infobox.label_name = new wxStaticText(this, wxID_ANY, wxGetTranslation(wxstr_name)); + m_infobox.label_creator = new wxStaticText(this, wxID_ANY, wxGetTranslation(wxstr_creator)); + m_infobox.label_notes = new wxStaticText(this, wxID_ANY, wxGetTranslation(wxstr_notes)); + m_infobox.textctrl_notes = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, + wxSize(64, -1), wxTE_MULTILINE | wxTE_READONLY); + m_infobox.listbox_codes = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 64)); - // TODO: buttons to add/edit codes + // TODO: buttons to add/edit codes - // sizers - wxBoxSizer* const sizer_infobox = new wxBoxSizer(wxVERTICAL); - sizer_infobox->Add(m_infobox.label_name, 0, wxBOTTOM, 5); - sizer_infobox->Add(m_infobox.label_creator, 0, wxBOTTOM, 5); - sizer_infobox->Add(m_infobox.label_notes, 0, wxBOTTOM, 5); - sizer_infobox->Add(m_infobox.textctrl_notes, 0, wxBOTTOM | wxEXPAND, 5); - sizer_infobox->Add(m_infobox.listbox_codes, 1, wxEXPAND, 5); + // sizers + wxBoxSizer* const sizer_infobox = new wxBoxSizer(wxVERTICAL); + sizer_infobox->Add(m_infobox.label_name, 0, wxBOTTOM, 5); + sizer_infobox->Add(m_infobox.label_creator, 0, wxBOTTOM, 5); + sizer_infobox->Add(m_infobox.label_notes, 0, wxBOTTOM, 5); + sizer_infobox->Add(m_infobox.textctrl_notes, 0, wxBOTTOM | wxEXPAND, 5); + sizer_infobox->Add(m_infobox.listbox_codes, 1, wxEXPAND, 5); - // button sizer - wxBoxSizer* const sizer_buttons = new wxBoxSizer(wxHORIZONTAL); - btn_download = new wxButton(this, wxID_ANY, _("Download Codes (WiiRD Database)"), wxDefaultPosition, wxSize(128, -1)); - btn_download->Disable(); - btn_download->Bind(wxEVT_BUTTON, &CodeConfigPanel::DownloadCodes, this); - sizer_buttons->AddStretchSpacer(1); - sizer_buttons->Add(btn_download, 1, wxEXPAND); + // button sizer + wxBoxSizer* const sizer_buttons = new wxBoxSizer(wxHORIZONTAL); + btn_download = new wxButton(this, wxID_ANY, _("Download Codes (WiiRD Database)"), + wxDefaultPosition, wxSize(128, -1)); + btn_download->Disable(); + btn_download->Bind(wxEVT_BUTTON, &CodeConfigPanel::DownloadCodes, this); + sizer_buttons->AddStretchSpacer(1); + sizer_buttons->Add(btn_download, 1, wxEXPAND); - // horizontal sizer - wxBoxSizer* const sizer_vert = new wxBoxSizer(wxVERTICAL); - sizer_vert->Add(sizer_infobox, 1, wxEXPAND); - sizer_vert->Add(sizer_buttons, 0, wxEXPAND | wxTOP, 5); + // horizontal sizer + wxBoxSizer* const sizer_vert = new wxBoxSizer(wxVERTICAL); + sizer_vert->Add(sizer_infobox, 1, wxEXPAND); + sizer_vert->Add(sizer_buttons, 0, wxEXPAND | wxTOP, 5); - wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL); - sizer_main->Add(m_listbox_gcodes, 1, wxALL | wxEXPAND, 5); - sizer_main->Add(sizer_vert, 0, wxALL | wxEXPAND, 5); + wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL); + sizer_main->Add(m_listbox_gcodes, 1, wxALL | wxEXPAND, 5); + sizer_main->Add(sizer_vert, 0, wxALL | wxEXPAND, 5); - SetSizerAndFit(sizer_main); + SetSizerAndFit(sizer_main); } void CodeConfigPanel::UpdateCodeList(bool checkRunning) { - // disable the button if it doesn't have an effect - btn_download->Enable((!checkRunning || Core::IsRunning()) && !m_gameid.empty()); + // disable the button if it doesn't have an effect + btn_download->Enable((!checkRunning || Core::IsRunning()) && !m_gameid.empty()); - m_listbox_gcodes->Clear(); - // add the codes to the listbox - for (const GeckoCode& code : m_gcodes) - { - m_listbox_gcodes->Append(StrToWxStr(code.name)); - if (code.enabled) - { - m_listbox_gcodes->Check(m_listbox_gcodes->GetCount()-1, true); - } - } + m_listbox_gcodes->Clear(); + // add the codes to the listbox + for (const GeckoCode& code : m_gcodes) + { + m_listbox_gcodes->Append(StrToWxStr(code.name)); + if (code.enabled) + { + m_listbox_gcodes->Check(m_listbox_gcodes->GetCount() - 1, true); + } + } - wxCommandEvent evt; - UpdateInfoBox(evt); + wxCommandEvent evt; + UpdateInfoBox(evt); } -void CodeConfigPanel::LoadCodes(const IniFile& globalIni, const IniFile& localIni, const std::string& gameid, bool checkRunning) +void CodeConfigPanel::LoadCodes(const IniFile& globalIni, const IniFile& localIni, + const std::string& gameid, bool checkRunning) { - m_gameid = gameid; + m_gameid = gameid; - m_gcodes.clear(); - if (!checkRunning || Core::IsRunning()) - Gecko::LoadCodes(globalIni, localIni, m_gcodes); + m_gcodes.clear(); + if (!checkRunning || Core::IsRunning()) + Gecko::LoadCodes(globalIni, localIni, m_gcodes); - UpdateCodeList(checkRunning); + UpdateCodeList(checkRunning); } void CodeConfigPanel::ToggleCode(wxCommandEvent& evt) { - const int sel = evt.GetInt(); // this right? - if (sel > -1) - m_gcodes[sel].enabled = m_listbox_gcodes->IsChecked(sel); + const int sel = evt.GetInt(); // this right? + if (sel > -1) + m_gcodes[sel].enabled = m_listbox_gcodes->IsChecked(sel); } void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&) { - m_infobox.listbox_codes->Clear(); - const int sel = m_listbox_gcodes->GetSelection(); + m_infobox.listbox_codes->Clear(); + const int sel = m_listbox_gcodes->GetSelection(); - if (sel > -1) - { - m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name) + StrToWxStr(m_gcodes[sel].name)); + if (sel > -1) + { + m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name) + StrToWxStr(m_gcodes[sel].name)); - // notes textctrl - m_infobox.textctrl_notes->Clear(); - for (const std::string& note : m_gcodes[sel].notes) - { - m_infobox.textctrl_notes->AppendText(StrToWxStr(note)); - } - m_infobox.textctrl_notes->ScrollLines(-99); // silly + // notes textctrl + m_infobox.textctrl_notes->Clear(); + for (const std::string& note : m_gcodes[sel].notes) + { + m_infobox.textctrl_notes->AppendText(StrToWxStr(note)); + } + m_infobox.textctrl_notes->ScrollLines(-99); // silly - m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator) + StrToWxStr(m_gcodes[sel].creator)); + m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator) + + StrToWxStr(m_gcodes[sel].creator)); - // add codes to info listbox - for (const GeckoCode::Code& code : m_gcodes[sel].codes) - { - m_infobox.listbox_codes->Append(wxString::Format("%08X %08X", code.address, code.data)); - } - } - else - { - m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name)); - m_infobox.textctrl_notes->Clear(); - m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator)); - } + // add codes to info listbox + for (const GeckoCode::Code& code : m_gcodes[sel].codes) + { + m_infobox.listbox_codes->Append(wxString::Format("%08X %08X", code.address, code.data)); + } + } + else + { + m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name)); + m_infobox.textctrl_notes->Clear(); + m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator)); + } } void CodeConfigPanel::DownloadCodes(wxCommandEvent&) { - if (m_gameid.empty()) - return; + if (m_gameid.empty()) + return; - std::string gameid = m_gameid; + std::string gameid = m_gameid; + switch (m_gameid[0]) + { + case 'R': + case 'S': + case 'G': + break; + default: + // All channels (WiiWare, VirtualConsole, etc) are identified by their first four characters + gameid = m_gameid.substr(0, 4); + break; + } - switch (m_gameid[0]) - { - case 'R': - case 'S': - case 'G': - break; - default: - // All channels (WiiWare, VirtualConsole, etc) are identified by their first four characters - gameid = m_gameid.substr(0, 4); - break; - } + sf::Http::Request req; + req.setUri("/txt.php?txt=" + gameid); - sf::Http::Request req; - req.setUri("/txt.php?txt=" + gameid); + sf::Http http; + http.setHost("geckocodes.org"); - sf::Http http; - http.setHost("geckocodes.org"); + const sf::Http::Response resp = http.sendRequest(req, sf::seconds(5)); - const sf::Http::Response resp = http.sendRequest(req, sf::seconds(5)); + if (sf::Http::Response::Ok == resp.getStatus()) + { + // temp vector containing parsed codes + std::vector gcodes; - if (sf::Http::Response::Ok == resp.getStatus()) - { - // temp vector containing parsed codes - std::vector gcodes; + // parse the codes + std::istringstream ss(resp.getBody()); - // parse the codes - std::istringstream ss(resp.getBody()); + std::string line; - std::string line; + // seek past the header, get to the first code + std::getline(ss, line); + std::getline(ss, line); + std::getline(ss, line); - // seek past the header, get to the first code - std::getline(ss, line); - std::getline(ss, line); - std::getline(ss, line); + int read_state = 0; + GeckoCode gcode; - int read_state = 0; - GeckoCode gcode; + while ((std::getline(ss, line).good())) + { + // Remove \r at the end of the line for files using windows line endings, std::getline only + // removes \n + line = StripSpaces(line); - while ((std::getline(ss, line).good())) - { - // Remove \r at the end of the line for files using windows line endings, std::getline only removes \n - line = StripSpaces(line); + if (line.empty()) + { + // add the code + if (gcode.codes.size()) + gcodes.push_back(gcode); + gcode = GeckoCode(); + read_state = 0; + continue; + } - if (line.empty()) - { - // add the code - if (gcode.codes.size()) - gcodes.push_back(gcode); - gcode = GeckoCode(); - read_state = 0; - continue; - } + switch (read_state) + { + // read new code + case 0: + { + std::istringstream ssline(line); + // stop at [ character (beginning of contributor name) + std::getline(ssline, gcode.name, '['); + gcode.name = StripSpaces(gcode.name); + gcode.user_defined = true; + // read the code creator name + std::getline(ssline, gcode.creator, ']'); + read_state = 1; + } + break; - switch (read_state) - { - // read new code - case 0 : - { - std::istringstream ssline(line); - // stop at [ character (beginning of contributor name) - std::getline(ssline, gcode.name, '['); - gcode.name = StripSpaces(gcode.name); - gcode.user_defined = true; - // read the code creator name - std::getline(ssline, gcode.creator, ']'); - read_state = 1; - } - break; + // read code lines + case 1: + { + std::istringstream ssline(line); + std::string addr, data; + ssline >> addr >> data; + ssline.seekg(0); - // read code lines - case 1 : - { - std::istringstream ssline(line); - std::string addr, data; - ssline >> addr >> data; - ssline.seekg(0); + // check if this line a code, silly, but the dumb txt file comment lines can start with + // valid hex chars :/ + if (8 == addr.length() && 8 == data.length()) + { + GeckoCode::Code new_code; + new_code.original_line = line; + ssline >> std::hex >> new_code.address >> new_code.data; + gcode.codes.push_back(new_code); + } + else + { + gcode.notes.push_back(line); + read_state = 2; // start reading comments + } + } + break; - // check if this line a code, silly, but the dumb txt file comment lines can start with valid hex chars :/ - if (8 == addr.length() && 8 == data.length()) - { - GeckoCode::Code new_code; - new_code.original_line = line; - ssline >> std::hex >> new_code.address >> new_code.data; - gcode.codes.push_back(new_code); - } - else - { - gcode.notes.push_back(line); - read_state = 2; // start reading comments - } + // read comment lines + case 2: + // append comment line + gcode.notes.push_back(line); + break; + } + } - } - break; + // add the last code + if (gcode.codes.size()) + gcodes.push_back(gcode); - // read comment lines - case 2 : - // append comment line - gcode.notes.push_back(line); - break; + if (gcodes.size()) + { + unsigned long added_count = 0; - } - } + // append the codes to the code list + for (const GeckoCode& code : gcodes) + { + // only add codes which do not already exist + std::vector::const_iterator existing_gcodes_iter = m_gcodes.begin(), + existing_gcodes_end = m_gcodes.end(); + for (;; ++existing_gcodes_iter) + { + if (existing_gcodes_end == existing_gcodes_iter) + { + m_gcodes.push_back(code); + ++added_count; + break; + } - // add the last code - if (gcode.codes.size()) - gcodes.push_back(gcode); + // code exists + if (existing_gcodes_iter->Compare(code)) + break; + } + } - if (gcodes.size()) - { - unsigned long added_count = 0; + wxMessageBox(wxString::Format(_("Downloaded %lu codes. (added %lu)"), + (unsigned long)gcodes.size(), added_count)); - // append the codes to the code list - for (const GeckoCode& code : gcodes) - { - // only add codes which do not already exist - std::vector::const_iterator - existing_gcodes_iter = m_gcodes.begin(), - existing_gcodes_end = m_gcodes.end(); - for (;; ++existing_gcodes_iter) - { - if (existing_gcodes_end == existing_gcodes_iter) - { - m_gcodes.push_back(code); - ++added_count; - break; - } - - // code exists - if (existing_gcodes_iter->Compare(code)) - break; - } - } - - wxMessageBox(wxString::Format(_("Downloaded %lu codes. (added %lu)"), - (unsigned long)gcodes.size(), added_count)); - - // refresh the list - UpdateCodeList(); - } - else - { - wxMessageBox(_("File contained no codes.")); - } - } - else - { - WxUtils::ShowErrorDialog(_("Failed to download codes.")); - } + // refresh the list + UpdateCodeList(); + } + else + { + wxMessageBox(_("File contained no codes.")); + } + } + else + { + WxUtils::ShowErrorDialog(_("Failed to download codes.")); + } } - } - diff --git a/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.h b/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.h index c2ac384f3c..317f84f205 100644 --- a/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.h +++ b/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.h @@ -19,39 +19,35 @@ class wxTextCtrl; namespace Gecko { - - class CodeConfigPanel : public wxPanel { public: - CodeConfigPanel(wxWindow* const parent); - - - void LoadCodes(const IniFile& globalIni, const IniFile& localIni, const std::string& gameid = "", bool checkRunning = false); - const std::vector& GetCodes() const { return m_gcodes; } + CodeConfigPanel(wxWindow* const parent); + void LoadCodes(const IniFile& globalIni, const IniFile& localIni, const std::string& gameid = "", + bool checkRunning = false); + const std::vector& GetCodes() const { return m_gcodes; } protected: - void UpdateInfoBox(wxCommandEvent&); - void ToggleCode(wxCommandEvent& evt); - void DownloadCodes(wxCommandEvent&); - //void ApplyChanges(wxCommandEvent&); + void UpdateInfoBox(wxCommandEvent&); + void ToggleCode(wxCommandEvent& evt); + void DownloadCodes(wxCommandEvent&); + // void ApplyChanges(wxCommandEvent&); - void UpdateCodeList(bool checkRunning = false); + void UpdateCodeList(bool checkRunning = false); private: - std::vector m_gcodes; + std::vector m_gcodes; - std::string m_gameid; + std::string m_gameid; - // wxwidgets stuff - wxCheckListBox* m_listbox_gcodes; - struct - { - wxStaticText* label_name, *label_notes, *label_creator; - wxTextCtrl* textctrl_notes; - wxListBox* listbox_codes; - } m_infobox; - wxButton* btn_download; + // wxwidgets stuff + wxCheckListBox* m_listbox_gcodes; + struct + { + wxStaticText *label_name, *label_notes, *label_creator; + wxTextCtrl* textctrl_notes; + wxListBox* listbox_codes; + } m_infobox; + wxButton* btn_download; }; - } diff --git a/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp b/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp index 79c193b239..b5e70c82aa 100644 --- a/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp @@ -12,88 +12,93 @@ #include "Core/ConfigManager.h" #include "DolphinWX/Config/AdvancedConfigPane.h" -AdvancedConfigPane::AdvancedConfigPane(wxWindow* parent, wxWindowID id) - : wxPanel(parent, id) +AdvancedConfigPane::AdvancedConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id) { - InitializeGUI(); - LoadGUIValues(); + InitializeGUI(); + LoadGUIValues(); } void AdvancedConfigPane::InitializeGUI() { - m_clock_override_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable CPU Clock Override")); - m_clock_override_slider = new wxSlider(this, wxID_ANY, 100, 0, 150, wxDefaultPosition, wxSize(200,-1)); - m_clock_override_text = new wxStaticText(this, wxID_ANY, ""); + m_clock_override_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable CPU Clock Override")); + m_clock_override_slider = + new wxSlider(this, wxID_ANY, 100, 0, 150, wxDefaultPosition, wxSize(200, -1)); + m_clock_override_text = new wxStaticText(this, wxID_ANY, ""); - m_clock_override_checkbox->Bind(wxEVT_CHECKBOX, &AdvancedConfigPane::OnClockOverrideCheckBoxChanged, this); - m_clock_override_slider->Bind(wxEVT_SLIDER, &AdvancedConfigPane::OnClockOverrideSliderChanged, this); + m_clock_override_checkbox->Bind(wxEVT_CHECKBOX, + &AdvancedConfigPane::OnClockOverrideCheckBoxChanged, this); + m_clock_override_slider->Bind(wxEVT_SLIDER, &AdvancedConfigPane::OnClockOverrideSliderChanged, + this); - wxStaticText* const clock_override_description = new wxStaticText(this, wxID_ANY, - _("Higher values can make variable-framerate games " - "run at a higher framerate, at the expense of CPU. " - "Lower values can make variable-framerate games " - "run at a lower framerate, saving CPU.\n\n" - "WARNING: Changing this from the default (100%) " - "can and will break games and cause glitches. " - "Do so at your own risk. Please do not report " - "bugs that occur with a non-default clock. ")); + wxStaticText* const clock_override_description = + new wxStaticText(this, wxID_ANY, _("Higher values can make variable-framerate games " + "run at a higher framerate, at the expense of CPU. " + "Lower values can make variable-framerate games " + "run at a lower framerate, saving CPU.\n\n" + "WARNING: Changing this from the default (100%) " + "can and will break games and cause glitches. " + "Do so at your own risk. Please do not report " + "bugs that occur with a non-default clock. ")); #ifdef __APPLE__ - clock_override_description->Wrap(550); + clock_override_description->Wrap(550); #else - clock_override_description->Wrap(400); + clock_override_description->Wrap(400); #endif - wxBoxSizer* const clock_override_checkbox_sizer = new wxBoxSizer(wxHORIZONTAL); - clock_override_checkbox_sizer->Add(m_clock_override_checkbox, 1, wxALL, 5); + wxBoxSizer* const clock_override_checkbox_sizer = new wxBoxSizer(wxHORIZONTAL); + clock_override_checkbox_sizer->Add(m_clock_override_checkbox, 1, wxALL, 5); - wxBoxSizer* const clock_override_slider_sizer = new wxBoxSizer(wxHORIZONTAL); - clock_override_slider_sizer->Add(m_clock_override_slider, 1, wxALL, 5); - clock_override_slider_sizer->Add(m_clock_override_text, 1, wxALL, 5); + wxBoxSizer* const clock_override_slider_sizer = new wxBoxSizer(wxHORIZONTAL); + clock_override_slider_sizer->Add(m_clock_override_slider, 1, wxALL, 5); + clock_override_slider_sizer->Add(m_clock_override_text, 1, wxALL, 5); - wxBoxSizer* const clock_override_description_sizer = new wxBoxSizer(wxHORIZONTAL); - clock_override_description_sizer->Add(clock_override_description, 1, wxALL, 5); + wxBoxSizer* const clock_override_description_sizer = new wxBoxSizer(wxHORIZONTAL); + clock_override_description_sizer->Add(clock_override_description, 1, wxALL, 5); - wxStaticBoxSizer* const cpu_options_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("CPU Options")); - cpu_options_sizer->Add(clock_override_checkbox_sizer); - cpu_options_sizer->Add(clock_override_slider_sizer); - cpu_options_sizer->Add(clock_override_description_sizer); + wxStaticBoxSizer* const cpu_options_sizer = + new wxStaticBoxSizer(wxVERTICAL, this, _("CPU Options")); + cpu_options_sizer->Add(clock_override_checkbox_sizer); + cpu_options_sizer->Add(clock_override_slider_sizer); + cpu_options_sizer->Add(clock_override_description_sizer); - wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); - main_sizer->Add(cpu_options_sizer , 0, wxEXPAND | wxALL, 5); + wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); + main_sizer->Add(cpu_options_sizer, 0, wxEXPAND | wxALL, 5); - SetSizer(main_sizer); + SetSizer(main_sizer); } void AdvancedConfigPane::LoadGUIValues() { - int ocFactor = (int)(std::log2f(SConfig::GetInstance().m_OCFactor) * 25.f + 100.f + 0.5f); - bool oc_enabled = SConfig::GetInstance().m_OCEnable; - m_clock_override_checkbox->SetValue(oc_enabled); - m_clock_override_slider ->SetValue(ocFactor); - m_clock_override_slider->Enable(oc_enabled); - UpdateCPUClock(); + int ocFactor = (int)(std::log2f(SConfig::GetInstance().m_OCFactor) * 25.f + 100.f + 0.5f); + bool oc_enabled = SConfig::GetInstance().m_OCEnable; + m_clock_override_checkbox->SetValue(oc_enabled); + m_clock_override_slider->SetValue(ocFactor); + m_clock_override_slider->Enable(oc_enabled); + UpdateCPUClock(); } void AdvancedConfigPane::OnClockOverrideCheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().m_OCEnable = m_clock_override_checkbox->IsChecked(); - m_clock_override_slider->Enable(SConfig::GetInstance().m_OCEnable); - UpdateCPUClock(); + SConfig::GetInstance().m_OCEnable = m_clock_override_checkbox->IsChecked(); + m_clock_override_slider->Enable(SConfig::GetInstance().m_OCEnable); + UpdateCPUClock(); } void AdvancedConfigPane::OnClockOverrideSliderChanged(wxCommandEvent& event) { - // Vaguely exponential scaling? - SConfig::GetInstance().m_OCFactor = std::exp2f((m_clock_override_slider->GetValue() - 100.f) / 25.f); - UpdateCPUClock(); + // Vaguely exponential scaling? + SConfig::GetInstance().m_OCFactor = + std::exp2f((m_clock_override_slider->GetValue() - 100.f) / 25.f); + UpdateCPUClock(); } void AdvancedConfigPane::UpdateCPUClock() { - bool wii = SConfig::GetInstance().bWii; - int percent = (int)(std::roundf(SConfig::GetInstance().m_OCFactor * 100.f)); - int clock = (int)(std::roundf(SConfig::GetInstance().m_OCFactor * (wii ? 729.f : 486.f))); + bool wii = SConfig::GetInstance().bWii; + int percent = (int)(std::roundf(SConfig::GetInstance().m_OCFactor * 100.f)); + int clock = (int)(std::roundf(SConfig::GetInstance().m_OCFactor * (wii ? 729.f : 486.f))); - m_clock_override_text->SetLabel(SConfig::GetInstance().m_OCEnable ? wxString::Format("%d %% (%d mhz)", percent, clock) : ""); + m_clock_override_text->SetLabel( + SConfig::GetInstance().m_OCEnable ? wxString::Format("%d %% (%d mhz)", percent, clock) : ""); } diff --git a/Source/Core/DolphinWX/Config/AdvancedConfigPane.h b/Source/Core/DolphinWX/Config/AdvancedConfigPane.h index 3e5d7f07e0..114ddc2265 100644 --- a/Source/Core/DolphinWX/Config/AdvancedConfigPane.h +++ b/Source/Core/DolphinWX/Config/AdvancedConfigPane.h @@ -13,18 +13,18 @@ class wxStaticText; class AdvancedConfigPane final : public wxPanel { public: - AdvancedConfigPane(wxWindow* parent, wxWindowID id); + AdvancedConfigPane(wxWindow* parent, wxWindowID id); private: - void InitializeGUI(); - void LoadGUIValues(); + void InitializeGUI(); + void LoadGUIValues(); - void OnClockOverrideCheckBoxChanged(wxCommandEvent&); - void OnClockOverrideSliderChanged(wxCommandEvent&); + void OnClockOverrideCheckBoxChanged(wxCommandEvent&); + void OnClockOverrideSliderChanged(wxCommandEvent&); - void UpdateCPUClock(); + void UpdateCPUClock(); - wxCheckBox* m_clock_override_checkbox; - wxSlider* m_clock_override_slider; - wxStaticText* m_clock_override_text; + wxCheckBox* m_clock_override_checkbox; + wxSlider* m_clock_override_slider; + wxStaticText* m_clock_override_text; }; diff --git a/Source/Core/DolphinWX/Config/AudioConfigPane.cpp b/Source/Core/DolphinWX/Config/AudioConfigPane.cpp index cc4d646803..97dc4ca145 100644 --- a/Source/Core/DolphinWX/Config/AudioConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/AudioConfigPane.cpp @@ -17,163 +17,179 @@ #include "Common/Common.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Config/AudioConfigPane.h" +#include "DolphinWX/WxUtils.h" -AudioConfigPane::AudioConfigPane(wxWindow* parent, wxWindowID id) - : wxPanel(parent, id) +AudioConfigPane::AudioConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id) { - InitializeGUI(); - LoadGUIValues(); - RefreshGUI(); + InitializeGUI(); + LoadGUIValues(); + RefreshGUI(); } void AudioConfigPane::InitializeGUI() { - m_dsp_engine_strings.Add(_("DSP HLE emulation (fast)")); - m_dsp_engine_strings.Add(_("DSP LLE recompiler")); - m_dsp_engine_strings.Add(_("DSP LLE interpreter (slow)")); + m_dsp_engine_strings.Add(_("DSP HLE emulation (fast)")); + m_dsp_engine_strings.Add(_("DSP LLE recompiler")); + m_dsp_engine_strings.Add(_("DSP LLE interpreter (slow)")); - m_dsp_engine_radiobox = new wxRadioBox(this, wxID_ANY, _("DSP Emulator Engine"), wxDefaultPosition, wxDefaultSize, m_dsp_engine_strings, 0, wxRA_SPECIFY_ROWS); - m_dpl2_decoder_checkbox = new wxCheckBox(this, wxID_ANY, _("Dolby Pro Logic II decoder")); - m_volume_slider = new wxSlider(this, wxID_ANY, 0, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_VERTICAL | wxSL_INVERSE); - m_volume_text = new wxStaticText(this, wxID_ANY, ""); - m_audio_backend_choice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_audio_backend_strings); - m_audio_latency_spinctrl = new wxSpinCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 30); + m_dsp_engine_radiobox = + new wxRadioBox(this, wxID_ANY, _("DSP Emulator Engine"), wxDefaultPosition, wxDefaultSize, + m_dsp_engine_strings, 0, wxRA_SPECIFY_ROWS); + m_dpl2_decoder_checkbox = new wxCheckBox(this, wxID_ANY, _("Dolby Pro Logic II decoder")); + m_volume_slider = new wxSlider(this, wxID_ANY, 0, 0, 100, wxDefaultPosition, wxDefaultSize, + wxSL_VERTICAL | wxSL_INVERSE); + m_volume_text = new wxStaticText(this, wxID_ANY, ""); + m_audio_backend_choice = + new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_audio_backend_strings); + m_audio_latency_spinctrl = + new wxSpinCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 30); - m_dsp_engine_radiobox->Bind(wxEVT_RADIOBOX, &AudioConfigPane::OnDSPEngineRadioBoxChanged, this); - m_dpl2_decoder_checkbox->Bind(wxEVT_CHECKBOX, &AudioConfigPane::OnDPL2DecoderCheckBoxChanged, this); - m_volume_slider->Bind(wxEVT_SLIDER, &AudioConfigPane::OnVolumeSliderChanged, this); - m_audio_backend_choice->Bind(wxEVT_CHOICE, &AudioConfigPane::OnAudioBackendChanged, this); - m_audio_latency_spinctrl->Bind(wxEVT_SPINCTRL, &AudioConfigPane::OnLatencySpinCtrlChanged, this); + m_dsp_engine_radiobox->Bind(wxEVT_RADIOBOX, &AudioConfigPane::OnDSPEngineRadioBoxChanged, this); + m_dpl2_decoder_checkbox->Bind(wxEVT_CHECKBOX, &AudioConfigPane::OnDPL2DecoderCheckBoxChanged, + this); + m_volume_slider->Bind(wxEVT_SLIDER, &AudioConfigPane::OnVolumeSliderChanged, this); + m_audio_backend_choice->Bind(wxEVT_CHOICE, &AudioConfigPane::OnAudioBackendChanged, this); + m_audio_latency_spinctrl->Bind(wxEVT_SPINCTRL, &AudioConfigPane::OnLatencySpinCtrlChanged, this); - m_audio_backend_choice->SetToolTip(_("Changing this will have no effect while the emulator is running.")); - m_audio_latency_spinctrl->SetToolTip(_("Sets the latency (in ms). Higher values may reduce audio crackling. OpenAL backend only.")); + m_audio_backend_choice->SetToolTip( + _("Changing this will have no effect while the emulator is running.")); + m_audio_latency_spinctrl->SetToolTip(_( + "Sets the latency (in ms). Higher values may reduce audio crackling. OpenAL backend only.")); #if defined(__APPLE__) - m_dpl2_decoder_checkbox->SetToolTip(_("Enables Dolby Pro Logic II emulation using 5.1 surround. Not available on OS X.")); + m_dpl2_decoder_checkbox->SetToolTip( + _("Enables Dolby Pro Logic II emulation using 5.1 surround. Not available on OS X.")); #else - m_dpl2_decoder_checkbox->SetToolTip(_("Enables Dolby Pro Logic II emulation using 5.1 surround. OpenAL or Pulse backends only.")); + m_dpl2_decoder_checkbox->SetToolTip( + _("Enables Dolby Pro Logic II emulation using 5.1 surround. OpenAL or Pulse backends only.")); #endif - wxStaticBoxSizer* const dsp_engine_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Sound Settings")); - dsp_engine_sizer->Add(m_dsp_engine_radiobox, 0, wxALL | wxEXPAND, 5); - dsp_engine_sizer->Add(m_dpl2_decoder_checkbox, 0, wxALL, 5); + wxStaticBoxSizer* const dsp_engine_sizer = + new wxStaticBoxSizer(wxVERTICAL, this, _("Sound Settings")); + dsp_engine_sizer->Add(m_dsp_engine_radiobox, 0, wxALL | wxEXPAND, 5); + dsp_engine_sizer->Add(m_dpl2_decoder_checkbox, 0, wxALL, 5); - wxStaticBoxSizer* const volume_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Volume")); - volume_sizer->Add(m_volume_slider, 1, wxLEFT | wxRIGHT, 13); - volume_sizer->Add(m_volume_text, 0, wxALIGN_CENTER | wxALL, 5); + wxStaticBoxSizer* const volume_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Volume")); + volume_sizer->Add(m_volume_slider, 1, wxLEFT | wxRIGHT, 13); + volume_sizer->Add(m_volume_text, 0, wxALIGN_CENTER | wxALL, 5); - wxGridBagSizer* const backend_grid_sizer = new wxGridBagSizer(); - backend_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Audio Backend:")), wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); - backend_grid_sizer->Add(m_audio_backend_choice, wxGBPosition(0, 1), wxDefaultSpan, wxALL, 5); - backend_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Latency:")), wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); - backend_grid_sizer->Add(m_audio_latency_spinctrl, wxGBPosition(1, 1), wxDefaultSpan, wxALL, 5); + wxGridBagSizer* const backend_grid_sizer = new wxGridBagSizer(); + backend_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Audio Backend:")), wxGBPosition(0, 0), + wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); + backend_grid_sizer->Add(m_audio_backend_choice, wxGBPosition(0, 1), wxDefaultSpan, wxALL, 5); + backend_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Latency:")), wxGBPosition(1, 0), + wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); + backend_grid_sizer->Add(m_audio_latency_spinctrl, wxGBPosition(1, 1), wxDefaultSpan, wxALL, 5); - wxStaticBoxSizer* const backend_static_box_sizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Backend Settings")); - backend_static_box_sizer->Add(backend_grid_sizer, 0, wxEXPAND); + wxStaticBoxSizer* const backend_static_box_sizer = + new wxStaticBoxSizer(wxHORIZONTAL, this, _("Backend Settings")); + backend_static_box_sizer->Add(backend_grid_sizer, 0, wxEXPAND); - wxBoxSizer* const dsp_audio_sizer = new wxBoxSizer(wxHORIZONTAL); - dsp_audio_sizer->Add(dsp_engine_sizer, 1, wxEXPAND | wxALL, 5); - dsp_audio_sizer->Add(volume_sizer, 0, wxEXPAND | wxALL, 5); + wxBoxSizer* const dsp_audio_sizer = new wxBoxSizer(wxHORIZONTAL); + dsp_audio_sizer->Add(dsp_engine_sizer, 1, wxEXPAND | wxALL, 5); + dsp_audio_sizer->Add(volume_sizer, 0, wxEXPAND | wxALL, 5); - wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); - main_sizer->Add(dsp_audio_sizer, 0, wxALL | wxEXPAND); - main_sizer->Add(backend_static_box_sizer, 0, wxALL | wxEXPAND, 5); + wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); + main_sizer->Add(dsp_audio_sizer, 0, wxALL | wxEXPAND); + main_sizer->Add(backend_static_box_sizer, 0, wxALL | wxEXPAND, 5); - SetSizerAndFit(main_sizer); + SetSizerAndFit(main_sizer); } void AudioConfigPane::LoadGUIValues() { - PopulateBackendChoiceBox(); + PopulateBackendChoiceBox(); - const SConfig& startup_params = SConfig::GetInstance(); + const SConfig& startup_params = SConfig::GetInstance(); - // Audio DSP Engine - if (startup_params.bDSPHLE) - m_dsp_engine_radiobox->SetSelection(0); - else - m_dsp_engine_radiobox->SetSelection(SConfig::GetInstance().m_DSPEnableJIT ? 1 : 2); + // Audio DSP Engine + if (startup_params.bDSPHLE) + m_dsp_engine_radiobox->SetSelection(0); + else + m_dsp_engine_radiobox->SetSelection(SConfig::GetInstance().m_DSPEnableJIT ? 1 : 2); - m_volume_slider->Enable(SupportsVolumeChanges(SConfig::GetInstance().sBackend)); - m_volume_slider->SetValue(SConfig::GetInstance().m_Volume); + m_volume_slider->Enable(SupportsVolumeChanges(SConfig::GetInstance().sBackend)); + m_volume_slider->SetValue(SConfig::GetInstance().m_Volume); - m_volume_text->SetLabel(wxString::Format("%d %%", SConfig::GetInstance().m_Volume)); + m_volume_text->SetLabel(wxString::Format("%d %%", SConfig::GetInstance().m_Volume)); - m_dpl2_decoder_checkbox->Enable(std::string(SConfig::GetInstance().sBackend) == BACKEND_OPENAL - || std::string(SConfig::GetInstance().sBackend) == BACKEND_PULSEAUDIO); - m_dpl2_decoder_checkbox->SetValue(startup_params.bDPL2Decoder); + m_dpl2_decoder_checkbox->Enable(std::string(SConfig::GetInstance().sBackend) == BACKEND_OPENAL || + std::string(SConfig::GetInstance().sBackend) == + BACKEND_PULSEAUDIO); + m_dpl2_decoder_checkbox->SetValue(startup_params.bDPL2Decoder); - m_audio_latency_spinctrl->Enable(std::string(SConfig::GetInstance().sBackend) == BACKEND_OPENAL); - m_audio_latency_spinctrl->SetValue(startup_params.iLatency); + m_audio_latency_spinctrl->Enable(std::string(SConfig::GetInstance().sBackend) == BACKEND_OPENAL); + m_audio_latency_spinctrl->SetValue(startup_params.iLatency); } void AudioConfigPane::RefreshGUI() { - if (Core::IsRunning()) - { - m_audio_latency_spinctrl->Disable(); - m_audio_backend_choice->Disable(); - m_dpl2_decoder_checkbox->Disable(); - m_dsp_engine_radiobox->Disable(); - } + if (Core::IsRunning()) + { + m_audio_latency_spinctrl->Disable(); + m_audio_backend_choice->Disable(); + m_dpl2_decoder_checkbox->Disable(); + m_dsp_engine_radiobox->Disable(); + } } void AudioConfigPane::OnDSPEngineRadioBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().bDSPHLE = m_dsp_engine_radiobox->GetSelection() == 0; - SConfig::GetInstance().m_DSPEnableJIT = m_dsp_engine_radiobox->GetSelection() == 1; - AudioCommon::UpdateSoundStream(); + SConfig::GetInstance().bDSPHLE = m_dsp_engine_radiobox->GetSelection() == 0; + SConfig::GetInstance().m_DSPEnableJIT = m_dsp_engine_radiobox->GetSelection() == 1; + AudioCommon::UpdateSoundStream(); } void AudioConfigPane::OnDPL2DecoderCheckBoxChanged(wxCommandEvent&) { - SConfig::GetInstance().bDPL2Decoder = m_dpl2_decoder_checkbox->IsChecked(); + SConfig::GetInstance().bDPL2Decoder = m_dpl2_decoder_checkbox->IsChecked(); } void AudioConfigPane::OnVolumeSliderChanged(wxCommandEvent& event) { - SConfig::GetInstance().m_Volume = m_volume_slider->GetValue(); - AudioCommon::UpdateSoundStream(); - m_volume_text->SetLabel(wxString::Format("%d %%", m_volume_slider->GetValue())); + SConfig::GetInstance().m_Volume = m_volume_slider->GetValue(); + AudioCommon::UpdateSoundStream(); + m_volume_text->SetLabel(wxString::Format("%d %%", m_volume_slider->GetValue())); } void AudioConfigPane::OnAudioBackendChanged(wxCommandEvent& event) { - m_volume_slider->Enable(SupportsVolumeChanges(WxStrToStr(m_audio_backend_choice->GetStringSelection()))); - m_audio_latency_spinctrl->Enable(WxStrToStr(m_audio_backend_choice->GetStringSelection()) == BACKEND_OPENAL); - m_dpl2_decoder_checkbox->Enable(WxStrToStr(m_audio_backend_choice->GetStringSelection()) == BACKEND_OPENAL || - WxStrToStr(m_audio_backend_choice->GetStringSelection()) == BACKEND_PULSEAUDIO); + m_volume_slider->Enable( + SupportsVolumeChanges(WxStrToStr(m_audio_backend_choice->GetStringSelection()))); + m_audio_latency_spinctrl->Enable(WxStrToStr(m_audio_backend_choice->GetStringSelection()) == + BACKEND_OPENAL); + m_dpl2_decoder_checkbox->Enable( + WxStrToStr(m_audio_backend_choice->GetStringSelection()) == BACKEND_OPENAL || + WxStrToStr(m_audio_backend_choice->GetStringSelection()) == BACKEND_PULSEAUDIO); - // Don't save the translated BACKEND_NULLSOUND string - SConfig::GetInstance().sBackend = m_audio_backend_choice->GetSelection() ? - WxStrToStr(m_audio_backend_choice->GetStringSelection()) : BACKEND_NULLSOUND; + // Don't save the translated BACKEND_NULLSOUND string + SConfig::GetInstance().sBackend = m_audio_backend_choice->GetSelection() ? + WxStrToStr(m_audio_backend_choice->GetStringSelection()) : + BACKEND_NULLSOUND; - AudioCommon::UpdateSoundStream(); + AudioCommon::UpdateSoundStream(); } void AudioConfigPane::OnLatencySpinCtrlChanged(wxCommandEvent& event) { - SConfig::GetInstance().iLatency = m_audio_latency_spinctrl->GetValue(); + SConfig::GetInstance().iLatency = m_audio_latency_spinctrl->GetValue(); } void AudioConfigPane::PopulateBackendChoiceBox() { - for (const std::string& backend : AudioCommon::GetSoundBackends()) - { - m_audio_backend_choice->Append(wxGetTranslation(StrToWxStr(backend))); + for (const std::string& backend : AudioCommon::GetSoundBackends()) + { + m_audio_backend_choice->Append(wxGetTranslation(StrToWxStr(backend))); - int num = m_audio_backend_choice->FindString(StrToWxStr(SConfig::GetInstance().sBackend)); - m_audio_backend_choice->SetSelection(num); - } + int num = m_audio_backend_choice->FindString(StrToWxStr(SConfig::GetInstance().sBackend)); + m_audio_backend_choice->SetSelection(num); + } } bool AudioConfigPane::SupportsVolumeChanges(const std::string& backend) { - //FIXME: this one should ask the backend whether it supports it. - // but getting the backend from string etc. is probably - // too much just to enable/disable a stupid slider... - return (backend == BACKEND_COREAUDIO || - backend == BACKEND_OPENAL || - backend == BACKEND_XAUDIO2); + // FIXME: this one should ask the backend whether it supports it. + // but getting the backend from string etc. is probably + // too much just to enable/disable a stupid slider... + return (backend == BACKEND_COREAUDIO || backend == BACKEND_OPENAL || backend == BACKEND_XAUDIO2); } diff --git a/Source/Core/DolphinWX/Config/AudioConfigPane.h b/Source/Core/DolphinWX/Config/AudioConfigPane.h index dd17919d27..b2a988371c 100644 --- a/Source/Core/DolphinWX/Config/AudioConfigPane.h +++ b/Source/Core/DolphinWX/Config/AudioConfigPane.h @@ -18,29 +18,29 @@ class wxStaticText; class AudioConfigPane final : public wxPanel { public: - AudioConfigPane(wxWindow* parent, wxWindowID id); + AudioConfigPane(wxWindow* parent, wxWindowID id); private: - void InitializeGUI(); - void LoadGUIValues(); - void RefreshGUI(); + void InitializeGUI(); + void LoadGUIValues(); + void RefreshGUI(); - void PopulateBackendChoiceBox(); - static bool SupportsVolumeChanges(const std::string&); + void PopulateBackendChoiceBox(); + static bool SupportsVolumeChanges(const std::string&); - void OnDSPEngineRadioBoxChanged(wxCommandEvent&); - void OnDPL2DecoderCheckBoxChanged(wxCommandEvent&); - void OnVolumeSliderChanged(wxCommandEvent&); - void OnAudioBackendChanged(wxCommandEvent&); - void OnLatencySpinCtrlChanged(wxCommandEvent&); + void OnDSPEngineRadioBoxChanged(wxCommandEvent&); + void OnDPL2DecoderCheckBoxChanged(wxCommandEvent&); + void OnVolumeSliderChanged(wxCommandEvent&); + void OnAudioBackendChanged(wxCommandEvent&); + void OnLatencySpinCtrlChanged(wxCommandEvent&); - wxArrayString m_dsp_engine_strings; - wxArrayString m_audio_backend_strings; + wxArrayString m_dsp_engine_strings; + wxArrayString m_audio_backend_strings; - wxRadioBox* m_dsp_engine_radiobox; - wxCheckBox* m_dpl2_decoder_checkbox; - wxSlider* m_volume_slider; - wxStaticText* m_volume_text; - wxChoice* m_audio_backend_choice; - wxSpinCtrl* m_audio_latency_spinctrl; + wxRadioBox* m_dsp_engine_radiobox; + wxCheckBox* m_dpl2_decoder_checkbox; + wxSlider* m_volume_slider; + wxStaticText* m_volume_text; + wxChoice* m_audio_backend_choice; + wxSpinCtrl* m_audio_latency_spinctrl; }; diff --git a/Source/Core/DolphinWX/Config/ConfigMain.cpp b/Source/Core/DolphinWX/Config/ConfigMain.cpp index ecd5af12f4..a238f41373 100644 --- a/Source/Core/DolphinWX/Config/ConfigMain.cpp +++ b/Source/Core/DolphinWX/Config/ConfigMain.cpp @@ -11,7 +11,6 @@ #include "Core/ConfigManager.h" #include "Core/Movie.h" #include "Core/NetPlayProto.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Config/AdvancedConfigPane.h" #include "DolphinWX/Config/AudioConfigPane.h" #include "DolphinWX/Config/ConfigMain.h" @@ -20,23 +19,24 @@ #include "DolphinWX/Config/InterfaceConfigPane.h" #include "DolphinWX/Config/PathConfigPane.h" #include "DolphinWX/Config/WiiConfigPane.h" +#include "DolphinWX/WxUtils.h" // Sent by child panes to signify that the game list should // be updated when this modal dialog closes. wxDEFINE_EVENT(wxDOLPHIN_CFG_REFRESH_LIST, wxCommandEvent); CConfigMain::CConfigMain(wxWindow* parent, wxWindowID id, const wxString& title, - const wxPoint& position, const wxSize& size, long style) - : wxDialog(parent, id, title, position, size, style) + const wxPoint& position, const wxSize& size, long style) + : wxDialog(parent, id, title, position, size, style) { - // Control refreshing of the ISOs list - m_refresh_game_list_on_close = false; + // Control refreshing of the ISOs list + m_refresh_game_list_on_close = false; - Bind(wxEVT_CLOSE_WINDOW, &CConfigMain::OnClose, this); - Bind(wxEVT_BUTTON, &CConfigMain::OnOk, this, wxID_OK); - Bind(wxDOLPHIN_CFG_REFRESH_LIST, &CConfigMain::OnSetRefreshGameListOnClose, this); + Bind(wxEVT_CLOSE_WINDOW, &CConfigMain::OnClose, this); + Bind(wxEVT_BUTTON, &CConfigMain::OnOk, this, wxID_OK); + Bind(wxDOLPHIN_CFG_REFRESH_LIST, &CConfigMain::OnSetRefreshGameListOnClose, this); - CreateGUIControls(); + CreateGUIControls(); } CConfigMain::~CConfigMain() @@ -45,67 +45,67 @@ CConfigMain::~CConfigMain() void CConfigMain::SetSelectedTab(int tab) { - // TODO : this is just a quick and dirty way to do it, possible cleanup + // TODO : this is just a quick and dirty way to do it, possible cleanup - switch (tab) - { - case ID_AUDIOPAGE: - Notebook->SetSelection(2); - break; - } + switch (tab) + { + case ID_AUDIOPAGE: + Notebook->SetSelection(2); + break; + } } void CConfigMain::CreateGUIControls() { - // Create the notebook and pages - Notebook = new wxNotebook(this, ID_NOTEBOOK); - wxPanel* const general_pane = new GeneralConfigPane(Notebook, ID_GENERALPAGE); - wxPanel* const interface_pane = new InterfaceConfigPane(Notebook, ID_DISPLAYPAGE); - wxPanel* const audio_pane = new AudioConfigPane(Notebook, ID_AUDIOPAGE); - wxPanel* const gamecube_pane = new GameCubeConfigPane(Notebook, ID_GAMECUBEPAGE); - wxPanel* const wii_pane = new WiiConfigPane(Notebook, ID_WIIPAGE); - wxPanel* const path_pane = new PathConfigPane(Notebook, ID_PATHSPAGE); - wxPanel* const advanced_pane = new AdvancedConfigPane(Notebook, ID_ADVANCEDPAGE); + // Create the notebook and pages + Notebook = new wxNotebook(this, ID_NOTEBOOK); + wxPanel* const general_pane = new GeneralConfigPane(Notebook, ID_GENERALPAGE); + wxPanel* const interface_pane = new InterfaceConfigPane(Notebook, ID_DISPLAYPAGE); + wxPanel* const audio_pane = new AudioConfigPane(Notebook, ID_AUDIOPAGE); + wxPanel* const gamecube_pane = new GameCubeConfigPane(Notebook, ID_GAMECUBEPAGE); + wxPanel* const wii_pane = new WiiConfigPane(Notebook, ID_WIIPAGE); + wxPanel* const path_pane = new PathConfigPane(Notebook, ID_PATHSPAGE); + wxPanel* const advanced_pane = new AdvancedConfigPane(Notebook, ID_ADVANCEDPAGE); - Notebook->AddPage(general_pane, _("General")); - Notebook->AddPage(interface_pane, _("Interface")); - Notebook->AddPage(audio_pane, _("Audio")); - Notebook->AddPage(gamecube_pane, _("GameCube")); - Notebook->AddPage(wii_pane, _("Wii")); - Notebook->AddPage(path_pane, _("Paths")); - Notebook->AddPage(advanced_pane, _("Advanced")); - if (Movie::IsMovieActive() || NetPlay::IsNetPlayRunning()) - advanced_pane->Disable(); + Notebook->AddPage(general_pane, _("General")); + Notebook->AddPage(interface_pane, _("Interface")); + Notebook->AddPage(audio_pane, _("Audio")); + Notebook->AddPage(gamecube_pane, _("GameCube")); + Notebook->AddPage(wii_pane, _("Wii")); + Notebook->AddPage(path_pane, _("Paths")); + Notebook->AddPage(advanced_pane, _("Advanced")); + if (Movie::IsMovieActive() || NetPlay::IsNetPlayRunning()) + advanced_pane->Disable(); - wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); - main_sizer->Add(Notebook, 1, wxEXPAND | wxALL, 5); - main_sizer->Add(CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); + main_sizer->Add(Notebook, 1, wxEXPAND | wxALL, 5); + main_sizer->Add(CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); #ifdef __APPLE__ - main_sizer->SetMinSize(550, 0); + main_sizer->SetMinSize(550, 0); #else - main_sizer->SetMinSize(400, 0); + main_sizer->SetMinSize(400, 0); #endif - SetSizerAndFit(main_sizer); - Center(); - SetFocus(); + SetSizerAndFit(main_sizer); + Center(); + SetFocus(); } void CConfigMain::OnClose(wxCloseEvent& WXUNUSED(event)) { - EndModal((m_refresh_game_list_on_close) ? wxID_OK : wxID_CANCEL); + EndModal((m_refresh_game_list_on_close) ? wxID_OK : wxID_CANCEL); } void CConfigMain::OnOk(wxCommandEvent& WXUNUSED(event)) { - Close(); + Close(); - // Save the config. Dolphin crashes too often to only save the settings on closing - SConfig::GetInstance().SaveSettings(); + // Save the config. Dolphin crashes too often to only save the settings on closing + SConfig::GetInstance().SaveSettings(); } void CConfigMain::OnSetRefreshGameListOnClose(wxCommandEvent& WXUNUSED(event)) { - m_refresh_game_list_on_close = true; + m_refresh_game_list_on_close = true; } diff --git a/Source/Core/DolphinWX/Config/ConfigMain.h b/Source/Core/DolphinWX/Config/ConfigMain.h index 931f39d17c..d7334682e7 100644 --- a/Source/Core/DolphinWX/Config/ConfigMain.h +++ b/Source/Core/DolphinWX/Config/ConfigMain.h @@ -15,35 +15,33 @@ wxDECLARE_EVENT(wxDOLPHIN_CFG_REFRESH_LIST, wxCommandEvent); class CConfigMain : public wxDialog { public: - CConfigMain(wxWindow* parent, - wxWindowID id = wxID_ANY, - const wxString& title = _("Dolphin Configuration"), - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxDEFAULT_DIALOG_STYLE); - virtual ~CConfigMain(); + CConfigMain(wxWindow* parent, wxWindowID id = wxID_ANY, + const wxString& title = _("Dolphin Configuration"), + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_DIALOG_STYLE); + virtual ~CConfigMain(); - void SetSelectedTab(int tab); + void SetSelectedTab(int tab); - enum - { - ID_NOTEBOOK = 1000, - ID_GENERALPAGE, - ID_DISPLAYPAGE, - ID_AUDIOPAGE, - ID_GAMECUBEPAGE, - ID_WIIPAGE, - ID_PATHSPAGE, - ID_ADVANCEDPAGE, - }; + enum + { + ID_NOTEBOOK = 1000, + ID_GENERALPAGE, + ID_DISPLAYPAGE, + ID_AUDIOPAGE, + ID_GAMECUBEPAGE, + ID_WIIPAGE, + ID_PATHSPAGE, + ID_ADVANCEDPAGE, + }; private: - void CreateGUIControls(); - void OnClose(wxCloseEvent& event); - void OnOk(wxCommandEvent& event); - void OnSetRefreshGameListOnClose(wxCommandEvent& event); + void CreateGUIControls(); + void OnClose(wxCloseEvent& event); + void OnOk(wxCommandEvent& event); + void OnSetRefreshGameListOnClose(wxCommandEvent& event); - wxNotebook* Notebook; + wxNotebook* Notebook; - bool m_refresh_game_list_on_close; + bool m_refresh_game_list_on_close; }; diff --git a/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp b/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp index c1090cae70..8cbc8b1cec 100644 --- a/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp +++ b/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp @@ -13,65 +13,64 @@ wxDEFINE_EVENT(wxEVT_ADAPTER_UPDATE, wxCommandEvent); - -GCAdapterConfigDiag::GCAdapterConfigDiag(wxWindow* const parent, const wxString& name, const int tab_num) - : wxDialog(parent, wxID_ANY, name, wxPoint(128,-1)), m_pad_id(tab_num) +GCAdapterConfigDiag::GCAdapterConfigDiag(wxWindow* const parent, const wxString& name, + const int tab_num) + : wxDialog(parent, wxID_ANY, name, wxPoint(128, -1)), m_pad_id(tab_num) { - wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL); + wxCheckBox* const gamecube_rumble = new wxCheckBox(this, wxID_ANY, _("Rumble")); + gamecube_rumble->SetValue(SConfig::GetInstance().m_AdapterRumble[m_pad_id]); + gamecube_rumble->Bind(wxEVT_CHECKBOX, &GCAdapterConfigDiag::OnAdapterRumble, this); - wxCheckBox* const gamecube_rumble = new wxCheckBox(this, wxID_ANY, _("Rumble")); - gamecube_rumble->SetValue(SConfig::GetInstance().m_AdapterRumble[m_pad_id]); - gamecube_rumble->Bind(wxEVT_CHECKBOX, &GCAdapterConfigDiag::OnAdapterRumble, this); + wxCheckBox* const gamecube_konga = new wxCheckBox(this, wxID_ANY, _("Simulate DK Bongos")); + gamecube_konga->SetValue(SConfig::GetInstance().m_AdapterKonga[m_pad_id]); + gamecube_konga->Bind(wxEVT_CHECKBOX, &GCAdapterConfigDiag::OnAdapterKonga, this); - wxCheckBox* const gamecube_konga = new wxCheckBox(this, wxID_ANY, _("Simulate DK Bongos")); - gamecube_konga->SetValue(SConfig::GetInstance().m_AdapterKonga[m_pad_id]); - gamecube_konga->Bind(wxEVT_CHECKBOX, &GCAdapterConfigDiag::OnAdapterKonga, this); + m_adapter_status = new wxStaticText(this, wxID_ANY, _("Adapter Not Detected")); - m_adapter_status = new wxStaticText(this, wxID_ANY, _("Adapter Not Detected")); + if (!GCAdapter::IsDetected()) + { + if (!GCAdapter::IsDriverDetected()) + { + m_adapter_status->SetLabelText(_("Driver Not Detected")); + gamecube_rumble->Disable(); + } + } + else + { + m_adapter_status->SetLabelText(_("Adapter Detected")); + } + GCAdapter::SetAdapterCallback(std::bind(&GCAdapterConfigDiag::ScheduleAdapterUpdate, this)); - if (!GCAdapter::IsDetected()) - { - if (!GCAdapter::IsDriverDetected()) - { - m_adapter_status->SetLabelText(_("Driver Not Detected")); - gamecube_rumble->Disable(); - } - } - else - { - m_adapter_status->SetLabelText(_("Adapter Detected")); - } - GCAdapter::SetAdapterCallback(std::bind(&GCAdapterConfigDiag::ScheduleAdapterUpdate, this)); + szr->Add(m_adapter_status, 0, wxEXPAND); + szr->Add(gamecube_rumble, 0, wxEXPAND); + szr->Add(gamecube_konga, 0, wxEXPAND); + szr->Add(CreateButtonSizer(wxOK | wxNO_DEFAULT), 0, wxEXPAND | wxALL, 5); - szr->Add(m_adapter_status, 0, wxEXPAND); - szr->Add(gamecube_rumble, 0, wxEXPAND); - szr->Add(gamecube_konga, 0, wxEXPAND); - szr->Add(CreateButtonSizer(wxOK | wxNO_DEFAULT), 0, wxEXPAND|wxALL, 5); + SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED); + SetSizerAndFit(szr); + Center(); - SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED); - SetSizerAndFit(szr); - Center(); - - Bind(wxEVT_ADAPTER_UPDATE, &GCAdapterConfigDiag::UpdateAdapter, this); + Bind(wxEVT_ADAPTER_UPDATE, &GCAdapterConfigDiag::UpdateAdapter, this); } void GCAdapterConfigDiag::ScheduleAdapterUpdate() { - wxQueueEvent(this, new wxCommandEvent(wxEVT_ADAPTER_UPDATE)); + wxQueueEvent(this, new wxCommandEvent(wxEVT_ADAPTER_UPDATE)); } void GCAdapterConfigDiag::UpdateAdapter(wxCommandEvent& ev) { - bool unpause = Core::PauseAndLock(true); - if (GCAdapter::IsDetected()) - m_adapter_status->SetLabelText(_("Adapter Detected")); - else - m_adapter_status->SetLabelText(_("Adapter Not Detected")); - Core::PauseAndLock(false, unpause); + bool unpause = Core::PauseAndLock(true); + if (GCAdapter::IsDetected()) + m_adapter_status->SetLabelText(_("Adapter Detected")); + else + m_adapter_status->SetLabelText(_("Adapter Not Detected")); + Core::PauseAndLock(false, unpause); } GCAdapterConfigDiag::~GCAdapterConfigDiag() { - GCAdapter::SetAdapterCallback(nullptr); + GCAdapter::SetAdapterCallback(nullptr); } diff --git a/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.h b/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.h index 4c86f55a2e..233d4085ef 100644 --- a/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.h +++ b/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.h @@ -18,23 +18,23 @@ class GCAdapterConfigDiag : public wxDialog { public: - GCAdapterConfigDiag(wxWindow* const parent, const wxString& name, const int tab_num = 0); - ~GCAdapterConfigDiag(); + GCAdapterConfigDiag(wxWindow* const parent, const wxString& name, const int tab_num = 0); + ~GCAdapterConfigDiag(); - void ScheduleAdapterUpdate(); - void UpdateAdapter(wxCommandEvent& ev); + void ScheduleAdapterUpdate(); + void UpdateAdapter(wxCommandEvent& ev); private: - wxStaticText* m_adapter_status; - int m_pad_id; + wxStaticText* m_adapter_status; + int m_pad_id; - void OnAdapterRumble(wxCommandEvent& event) - { - SConfig::GetInstance().m_AdapterRumble[m_pad_id] = event.IsChecked(); - } + void OnAdapterRumble(wxCommandEvent& event) + { + SConfig::GetInstance().m_AdapterRumble[m_pad_id] = event.IsChecked(); + } - void OnAdapterKonga(wxCommandEvent& event) - { - SConfig::GetInstance().m_AdapterKonga[m_pad_id] = event.IsChecked(); - } + void OnAdapterKonga(wxCommandEvent& event) + { + SConfig::GetInstance().m_AdapterKonga[m_pad_id] = event.IsChecked(); + } }; diff --git a/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp b/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp index db6a22751f..b0ce583181 100644 --- a/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp @@ -18,369 +18,380 @@ #include "Common/FileUtil.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/NetPlayProto.h" #include "Core/HW/EXI.h" #include "Core/HW/GCMemcard.h" -#include "DolphinWX/WxUtils.h" +#include "Core/NetPlayProto.h" #include "DolphinWX/Config/ConfigMain.h" #include "DolphinWX/Config/GameCubeConfigPane.h" +#include "DolphinWX/WxUtils.h" -#define DEV_NONE_STR _trans("") -#define DEV_DUMMY_STR _trans("Dummy") +#define DEV_NONE_STR _trans("") +#define DEV_DUMMY_STR _trans("Dummy") -#define EXIDEV_MEMCARD_STR _trans("Memory Card") -#define EXIDEV_MEMDIR_STR _trans("GCI Folder") -#define EXIDEV_MIC_STR _trans("Microphone") -#define EXIDEV_BBA_STR _trans("Broadband Adapter") -#define EXIDEV_AGP_STR _trans("Advance Game Port") -#define EXIDEV_AM_BB_STR _trans("AM Baseboard") -#define EXIDEV_GECKO_STR _trans("USB Gecko") +#define EXIDEV_MEMCARD_STR _trans("Memory Card") +#define EXIDEV_MEMDIR_STR _trans("GCI Folder") +#define EXIDEV_MIC_STR _trans("Microphone") +#define EXIDEV_BBA_STR _trans("Broadband Adapter") +#define EXIDEV_AGP_STR _trans("Advance Game Port") +#define EXIDEV_AM_BB_STR _trans("AM Baseboard") +#define EXIDEV_GECKO_STR _trans("USB Gecko") -GameCubeConfigPane::GameCubeConfigPane(wxWindow* parent, wxWindowID id) - : wxPanel(parent, id) +GameCubeConfigPane::GameCubeConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id) { - InitializeGUI(); - LoadGUIValues(); - RefreshGUI(); + InitializeGUI(); + LoadGUIValues(); + RefreshGUI(); } void GameCubeConfigPane::InitializeGUI() { - m_ipl_language_strings.Add(_("English")); - m_ipl_language_strings.Add(_("German")); - m_ipl_language_strings.Add(_("French")); - m_ipl_language_strings.Add(_("Spanish")); - m_ipl_language_strings.Add(_("Italian")); - m_ipl_language_strings.Add(_("Dutch")); + m_ipl_language_strings.Add(_("English")); + m_ipl_language_strings.Add(_("German")); + m_ipl_language_strings.Add(_("French")); + m_ipl_language_strings.Add(_("Spanish")); + m_ipl_language_strings.Add(_("Italian")); + m_ipl_language_strings.Add(_("Dutch")); - m_system_lang_choice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_ipl_language_strings); - m_system_lang_choice->SetToolTip(_("Sets the GameCube system language.")); - m_system_lang_choice->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSystemLanguageChange, this); + m_system_lang_choice = + new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_ipl_language_strings); + m_system_lang_choice->SetToolTip(_("Sets the GameCube system language.")); + m_system_lang_choice->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSystemLanguageChange, this); - m_override_lang_checkbox = new wxCheckBox(this, wxID_ANY, _("Override Language on NTSC Games")); - m_override_lang_checkbox->SetToolTip(_("Lets the system language be set to values that games were not designed for. This can allow the use of extra translations for a few games, but can also lead to text display issues.")); - m_override_lang_checkbox->Bind(wxEVT_CHECKBOX, &GameCubeConfigPane::OnOverrideLanguageCheckBoxChanged, this); + m_override_lang_checkbox = new wxCheckBox(this, wxID_ANY, _("Override Language on NTSC Games")); + m_override_lang_checkbox->SetToolTip(_( + "Lets the system language be set to values that games were not designed for. This can allow " + "the use of extra translations for a few games, but can also lead to text display issues.")); + m_override_lang_checkbox->Bind(wxEVT_CHECKBOX, + &GameCubeConfigPane::OnOverrideLanguageCheckBoxChanged, this); - m_skip_bios_checkbox = new wxCheckBox(this, wxID_ANY, _("Skip BIOS")); - m_skip_bios_checkbox->Bind(wxEVT_CHECKBOX, &GameCubeConfigPane::OnSkipBiosCheckBoxChanged, this); + m_skip_bios_checkbox = new wxCheckBox(this, wxID_ANY, _("Skip BIOS")); + m_skip_bios_checkbox->Bind(wxEVT_CHECKBOX, &GameCubeConfigPane::OnSkipBiosCheckBoxChanged, this); - if (!File::Exists(File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + USA_DIR + DIR_SEP GC_IPL) && - !File::Exists(File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + USA_DIR + DIR_SEP GC_IPL) && - !File::Exists(File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + JAP_DIR + DIR_SEP GC_IPL) && - !File::Exists(File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + JAP_DIR + DIR_SEP GC_IPL) && - !File::Exists(File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + EUR_DIR + DIR_SEP GC_IPL) && - !File::Exists(File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + EUR_DIR + DIR_SEP GC_IPL)) - { - m_skip_bios_checkbox->Disable(); - m_skip_bios_checkbox->SetToolTip(_("Put BIOS roms in User/GC/{region}.")); - } + if (!File::Exists(File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + USA_DIR + DIR_SEP GC_IPL) && + !File::Exists(File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + USA_DIR + DIR_SEP GC_IPL) && + !File::Exists(File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + JAP_DIR + DIR_SEP GC_IPL) && + !File::Exists(File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + JAP_DIR + DIR_SEP GC_IPL) && + !File::Exists(File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + EUR_DIR + DIR_SEP GC_IPL) && + !File::Exists(File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + EUR_DIR + DIR_SEP GC_IPL)) + { + m_skip_bios_checkbox->Disable(); + m_skip_bios_checkbox->SetToolTip(_("Put BIOS roms in User/GC/{region}.")); + } - // Device settings - // EXI Devices - wxStaticText* GCEXIDeviceText[3] = { - new wxStaticText(this, wxID_ANY, _("Slot A")), - new wxStaticText(this, wxID_ANY, _("Slot B")), - new wxStaticText(this, wxID_ANY, "SP1"), - }; + // Device settings + // EXI Devices + wxStaticText* GCEXIDeviceText[3] = { + new wxStaticText(this, wxID_ANY, _("Slot A")), new wxStaticText(this, wxID_ANY, _("Slot B")), + new wxStaticText(this, wxID_ANY, "SP1"), + }; - m_exi_devices[0] = new wxChoice(this, wxID_ANY); - m_exi_devices[0]->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSlotAChanged, this); - m_exi_devices[1] = new wxChoice(this, wxID_ANY); - m_exi_devices[1]->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSlotBChanged, this); - m_exi_devices[2] = new wxChoice(this, wxID_ANY); - m_exi_devices[2]->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSP1Changed, this); - m_exi_devices[2]->SetToolTip(_("Serial Port 1 - This is the port which devices such as the net adapter use.")); + m_exi_devices[0] = new wxChoice(this, wxID_ANY); + m_exi_devices[0]->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSlotAChanged, this); + m_exi_devices[1] = new wxChoice(this, wxID_ANY); + m_exi_devices[1]->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSlotBChanged, this); + m_exi_devices[2] = new wxChoice(this, wxID_ANY); + m_exi_devices[2]->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSP1Changed, this); + m_exi_devices[2]->SetToolTip( + _("Serial Port 1 - This is the port which devices such as the net adapter use.")); - m_memcard_path[0] = new wxButton(this, wxID_ANY, "...", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - m_memcard_path[0]->Bind(wxEVT_BUTTON, &GameCubeConfigPane::OnSlotAButtonClick, this); - m_memcard_path[1] = new wxButton(this, wxID_ANY, "...", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - m_memcard_path[1]->Bind(wxEVT_BUTTON, &GameCubeConfigPane::OnSlotBButtonClick, this); + m_memcard_path[0] = + new wxButton(this, wxID_ANY, "...", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + m_memcard_path[0]->Bind(wxEVT_BUTTON, &GameCubeConfigPane::OnSlotAButtonClick, this); + m_memcard_path[1] = + new wxButton(this, wxID_ANY, "...", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + m_memcard_path[1]->Bind(wxEVT_BUTTON, &GameCubeConfigPane::OnSlotBButtonClick, this); - // Populate the GameCube page - wxGridBagSizer* const sGamecubeIPLSettings = new wxGridBagSizer(); - sGamecubeIPLSettings->Add(m_skip_bios_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2), wxALL, 5); - sGamecubeIPLSettings->Add(new wxStaticText(this, wxID_ANY, _("System Language:")), - wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxBOTTOM, 5); - sGamecubeIPLSettings->Add(m_system_lang_choice, wxGBPosition(1, 1), wxDefaultSpan, wxLEFT | wxRIGHT | wxBOTTOM, 5); - sGamecubeIPLSettings->Add(m_override_lang_checkbox, wxGBPosition(2, 0), wxGBSpan(1, 2), wxALL, 5); + // Populate the GameCube page + wxGridBagSizer* const sGamecubeIPLSettings = new wxGridBagSizer(); + sGamecubeIPLSettings->Add(m_skip_bios_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2), wxALL, 5); + sGamecubeIPLSettings->Add(new wxStaticText(this, wxID_ANY, _("System Language:")), + wxGBPosition(1, 0), wxDefaultSpan, + wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxBOTTOM, 5); + sGamecubeIPLSettings->Add(m_system_lang_choice, wxGBPosition(1, 1), wxDefaultSpan, + wxLEFT | wxRIGHT | wxBOTTOM, 5); + sGamecubeIPLSettings->Add(m_override_lang_checkbox, wxGBPosition(2, 0), wxGBSpan(1, 2), wxALL, 5); - wxStaticBoxSizer* const sbGamecubeIPLSettings = new wxStaticBoxSizer(wxVERTICAL, this, _("IPL Settings")); - sbGamecubeIPLSettings->Add(sGamecubeIPLSettings); - wxStaticBoxSizer* const sbGamecubeDeviceSettings = new wxStaticBoxSizer(wxVERTICAL, this, _("Device Settings")); - wxGridBagSizer* const sbGamecubeEXIDevSettings = new wxGridBagSizer(10, 10); + wxStaticBoxSizer* const sbGamecubeIPLSettings = + new wxStaticBoxSizer(wxVERTICAL, this, _("IPL Settings")); + sbGamecubeIPLSettings->Add(sGamecubeIPLSettings); + wxStaticBoxSizer* const sbGamecubeDeviceSettings = + new wxStaticBoxSizer(wxVERTICAL, this, _("Device Settings")); + wxGridBagSizer* const sbGamecubeEXIDevSettings = new wxGridBagSizer(10, 10); - for (int i = 0; i < 3; ++i) - { - sbGamecubeEXIDevSettings->Add(GCEXIDeviceText[i], wxGBPosition(i, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); - sbGamecubeEXIDevSettings->Add(m_exi_devices[i], wxGBPosition(i, 1), wxGBSpan(1, (i < 2) ? 1 : 2), wxALIGN_CENTER_VERTICAL); + for (int i = 0; i < 3; ++i) + { + sbGamecubeEXIDevSettings->Add(GCEXIDeviceText[i], wxGBPosition(i, 0), wxDefaultSpan, + wxALIGN_CENTER_VERTICAL); + sbGamecubeEXIDevSettings->Add(m_exi_devices[i], wxGBPosition(i, 1), + wxGBSpan(1, (i < 2) ? 1 : 2), wxALIGN_CENTER_VERTICAL); - if (i < 2) - sbGamecubeEXIDevSettings->Add(m_memcard_path[i], wxGBPosition(i, 2), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); + if (i < 2) + sbGamecubeEXIDevSettings->Add(m_memcard_path[i], wxGBPosition(i, 2), wxDefaultSpan, + wxALIGN_CENTER_VERTICAL); - if (NetPlay::IsNetPlayRunning()) - m_exi_devices[i]->Disable(); - } - sbGamecubeDeviceSettings->Add(sbGamecubeEXIDevSettings, 0, wxALL, 5); + if (NetPlay::IsNetPlayRunning()) + m_exi_devices[i]->Disable(); + } + sbGamecubeDeviceSettings->Add(sbGamecubeEXIDevSettings, 0, wxALL, 5); - wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); - main_sizer->Add(sbGamecubeIPLSettings, 0, wxEXPAND | wxALL, 5); - main_sizer->Add(sbGamecubeDeviceSettings, 0, wxEXPAND | wxALL, 5); + wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); + main_sizer->Add(sbGamecubeIPLSettings, 0, wxEXPAND | wxALL, 5); + main_sizer->Add(sbGamecubeDeviceSettings, 0, wxEXPAND | wxALL, 5); - SetSizer(main_sizer); + SetSizer(main_sizer); } void GameCubeConfigPane::LoadGUIValues() { - const SConfig& startup_params = SConfig::GetInstance(); + const SConfig& startup_params = SConfig::GetInstance(); - m_system_lang_choice->SetSelection(startup_params.SelectedLanguage); - m_skip_bios_checkbox->SetValue(startup_params.bHLE_BS2); - m_override_lang_checkbox->SetValue(startup_params.bOverrideGCLanguage); + m_system_lang_choice->SetSelection(startup_params.SelectedLanguage); + m_skip_bios_checkbox->SetValue(startup_params.bHLE_BS2); + m_override_lang_checkbox->SetValue(startup_params.bOverrideGCLanguage); - wxArrayString slot_devices; - slot_devices.Add(_(DEV_NONE_STR)); - slot_devices.Add(_(DEV_DUMMY_STR)); - slot_devices.Add(_(EXIDEV_MEMCARD_STR)); - slot_devices.Add(_(EXIDEV_MEMDIR_STR)); - slot_devices.Add(_(EXIDEV_GECKO_STR)); - slot_devices.Add(_(EXIDEV_AGP_STR)); + wxArrayString slot_devices; + slot_devices.Add(_(DEV_NONE_STR)); + slot_devices.Add(_(DEV_DUMMY_STR)); + slot_devices.Add(_(EXIDEV_MEMCARD_STR)); + slot_devices.Add(_(EXIDEV_MEMDIR_STR)); + slot_devices.Add(_(EXIDEV_GECKO_STR)); + slot_devices.Add(_(EXIDEV_AGP_STR)); #if HAVE_PORTAUDIO - slot_devices.Add(_(EXIDEV_MIC_STR)); + slot_devices.Add(_(EXIDEV_MIC_STR)); #endif - wxArrayString sp1_devices; - sp1_devices.Add(_(DEV_NONE_STR)); - sp1_devices.Add(_(DEV_DUMMY_STR)); - sp1_devices.Add(_(EXIDEV_BBA_STR)); - sp1_devices.Add(_(EXIDEV_AM_BB_STR)); + wxArrayString sp1_devices; + sp1_devices.Add(_(DEV_NONE_STR)); + sp1_devices.Add(_(DEV_DUMMY_STR)); + sp1_devices.Add(_(EXIDEV_BBA_STR)); + sp1_devices.Add(_(EXIDEV_AM_BB_STR)); - for (int i = 0; i < 3; ++i) - { - bool isMemcard = false; + for (int i = 0; i < 3; ++i) + { + bool isMemcard = false; - // Add strings to the wxChoice list, the third wxChoice is the SP1 slot - if (i == 2) - m_exi_devices[i]->Append(sp1_devices); - else - m_exi_devices[i]->Append(slot_devices); + // Add strings to the wxChoice list, the third wxChoice is the SP1 slot + if (i == 2) + m_exi_devices[i]->Append(sp1_devices); + else + m_exi_devices[i]->Append(slot_devices); - switch (SConfig::GetInstance().m_EXIDevice[i]) - { - case EXIDEVICE_NONE: - m_exi_devices[i]->SetStringSelection(slot_devices[0]); - break; - case EXIDEVICE_MEMORYCARD: - isMemcard = m_exi_devices[i]->SetStringSelection(slot_devices[2]); - break; - case EXIDEVICE_MEMORYCARDFOLDER: - m_exi_devices[i]->SetStringSelection(slot_devices[3]); - break; - case EXIDEVICE_GECKO: - m_exi_devices[i]->SetStringSelection(slot_devices[4]); - break; - case EXIDEVICE_AGP: - isMemcard = m_exi_devices[i]->SetStringSelection(slot_devices[5]); - break; - case EXIDEVICE_MIC: - m_exi_devices[i]->SetStringSelection(slot_devices[6]); - break; - case EXIDEVICE_ETH: - m_exi_devices[i]->SetStringSelection(sp1_devices[2]); - break; - case EXIDEVICE_AM_BASEBOARD: - m_exi_devices[i]->SetStringSelection(sp1_devices[3]); - break; - case EXIDEVICE_DUMMY: - default: - m_exi_devices[i]->SetStringSelection(slot_devices[1]); - break; - } + switch (SConfig::GetInstance().m_EXIDevice[i]) + { + case EXIDEVICE_NONE: + m_exi_devices[i]->SetStringSelection(slot_devices[0]); + break; + case EXIDEVICE_MEMORYCARD: + isMemcard = m_exi_devices[i]->SetStringSelection(slot_devices[2]); + break; + case EXIDEVICE_MEMORYCARDFOLDER: + m_exi_devices[i]->SetStringSelection(slot_devices[3]); + break; + case EXIDEVICE_GECKO: + m_exi_devices[i]->SetStringSelection(slot_devices[4]); + break; + case EXIDEVICE_AGP: + isMemcard = m_exi_devices[i]->SetStringSelection(slot_devices[5]); + break; + case EXIDEVICE_MIC: + m_exi_devices[i]->SetStringSelection(slot_devices[6]); + break; + case EXIDEVICE_ETH: + m_exi_devices[i]->SetStringSelection(sp1_devices[2]); + break; + case EXIDEVICE_AM_BASEBOARD: + m_exi_devices[i]->SetStringSelection(sp1_devices[3]); + break; + case EXIDEVICE_DUMMY: + default: + m_exi_devices[i]->SetStringSelection(slot_devices[1]); + break; + } - if (!isMemcard && i < 2) - m_memcard_path[i]->Disable(); - } + if (!isMemcard && i < 2) + m_memcard_path[i]->Disable(); + } } void GameCubeConfigPane::RefreshGUI() { - if (Core::IsRunning()) - { - m_system_lang_choice->Disable(); - m_override_lang_checkbox->Disable(); - m_skip_bios_checkbox->Disable(); - } + if (Core::IsRunning()) + { + m_system_lang_choice->Disable(); + m_override_lang_checkbox->Disable(); + m_skip_bios_checkbox->Disable(); + } } void GameCubeConfigPane::OnSystemLanguageChange(wxCommandEvent& event) { - SConfig::GetInstance().SelectedLanguage = m_system_lang_choice->GetSelection(); + SConfig::GetInstance().SelectedLanguage = m_system_lang_choice->GetSelection(); - AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST)); + AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST)); } void GameCubeConfigPane::OnOverrideLanguageCheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().bOverrideGCLanguage = m_override_lang_checkbox->IsChecked(); + SConfig::GetInstance().bOverrideGCLanguage = m_override_lang_checkbox->IsChecked(); - AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST)); + AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST)); } void GameCubeConfigPane::OnSkipBiosCheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().bHLE_BS2 = m_skip_bios_checkbox->IsChecked(); + SConfig::GetInstance().bHLE_BS2 = m_skip_bios_checkbox->IsChecked(); } void GameCubeConfigPane::OnSlotAChanged(wxCommandEvent& event) { - ChooseEXIDevice(event.GetString(), 0); + ChooseEXIDevice(event.GetString(), 0); } void GameCubeConfigPane::OnSlotBChanged(wxCommandEvent& event) { - ChooseEXIDevice(event.GetString(), 1); + ChooseEXIDevice(event.GetString(), 1); } void GameCubeConfigPane::OnSP1Changed(wxCommandEvent& event) { - ChooseEXIDevice(event.GetString(), 2); + ChooseEXIDevice(event.GetString(), 2); } void GameCubeConfigPane::OnSlotAButtonClick(wxCommandEvent& event) { - ChooseSlotPath(true, SConfig::GetInstance().m_EXIDevice[0]); + ChooseSlotPath(true, SConfig::GetInstance().m_EXIDevice[0]); } void GameCubeConfigPane::OnSlotBButtonClick(wxCommandEvent& event) { - ChooseSlotPath(false, SConfig::GetInstance().m_EXIDevice[1]); + ChooseSlotPath(false, SConfig::GetInstance().m_EXIDevice[1]); } void GameCubeConfigPane::ChooseEXIDevice(const wxString& deviceName, int deviceNum) { - TEXIDevices tempType; + TEXIDevices tempType; - if (!deviceName.compare(_(EXIDEV_MEMCARD_STR))) - tempType = EXIDEVICE_MEMORYCARD; - else if (!deviceName.compare(_(EXIDEV_MEMDIR_STR))) - tempType = EXIDEVICE_MEMORYCARDFOLDER; - else if (!deviceName.compare(_(EXIDEV_MIC_STR))) - tempType = EXIDEVICE_MIC; - else if (!deviceName.compare(EXIDEV_BBA_STR)) - tempType = EXIDEVICE_ETH; - else if (!deviceName.compare(EXIDEV_AGP_STR)) - tempType = EXIDEVICE_AGP; - else if (!deviceName.compare(_(EXIDEV_AM_BB_STR))) - tempType = EXIDEVICE_AM_BASEBOARD; - else if (!deviceName.compare(EXIDEV_GECKO_STR)) - tempType = EXIDEVICE_GECKO; - else if (!deviceName.compare(_(DEV_NONE_STR))) - tempType = EXIDEVICE_NONE; - else - tempType = EXIDEVICE_DUMMY; + if (!deviceName.compare(_(EXIDEV_MEMCARD_STR))) + tempType = EXIDEVICE_MEMORYCARD; + else if (!deviceName.compare(_(EXIDEV_MEMDIR_STR))) + tempType = EXIDEVICE_MEMORYCARDFOLDER; + else if (!deviceName.compare(_(EXIDEV_MIC_STR))) + tempType = EXIDEVICE_MIC; + else if (!deviceName.compare(EXIDEV_BBA_STR)) + tempType = EXIDEVICE_ETH; + else if (!deviceName.compare(EXIDEV_AGP_STR)) + tempType = EXIDEVICE_AGP; + else if (!deviceName.compare(_(EXIDEV_AM_BB_STR))) + tempType = EXIDEVICE_AM_BASEBOARD; + else if (!deviceName.compare(EXIDEV_GECKO_STR)) + tempType = EXIDEVICE_GECKO; + else if (!deviceName.compare(_(DEV_NONE_STR))) + tempType = EXIDEVICE_NONE; + else + tempType = EXIDEVICE_DUMMY; - // Gray out the memcard path button if we're not on a memcard or AGP - if (tempType == EXIDEVICE_MEMORYCARD || tempType == EXIDEVICE_AGP) - m_memcard_path[deviceNum]->Enable(); - else if (deviceNum == 0 || deviceNum == 1) - m_memcard_path[deviceNum]->Disable(); + // Gray out the memcard path button if we're not on a memcard or AGP + if (tempType == EXIDEVICE_MEMORYCARD || tempType == EXIDEVICE_AGP) + m_memcard_path[deviceNum]->Enable(); + else if (deviceNum == 0 || deviceNum == 1) + m_memcard_path[deviceNum]->Disable(); - SConfig::GetInstance().m_EXIDevice[deviceNum] = tempType; + SConfig::GetInstance().m_EXIDevice[deviceNum] = tempType; - if (Core::IsRunning()) - { - // Change plugged device! :D - ExpansionInterface::ChangeDevice( - (deviceNum == 1) ? 1 : 0, // SlotB is on channel 1, slotA and SP1 are on 0 - tempType, // The device enum to change to - (deviceNum == 2) ? 2 : 0); // SP1 is device 2, slots are device 0 - } + if (Core::IsRunning()) + { + // Change plugged device! :D + ExpansionInterface::ChangeDevice( + (deviceNum == 1) ? 1 : 0, // SlotB is on channel 1, slotA and SP1 are on 0 + tempType, // The device enum to change to + (deviceNum == 2) ? 2 : 0); // SP1 is device 2, slots are device 0 + } } void GameCubeConfigPane::ChooseSlotPath(bool is_slot_a, TEXIDevices device_type) { - bool memcard = (device_type == EXIDEVICE_MEMORYCARD); - std::string path; - std::string cardname; - std::string ext; - std::string pathA = SConfig::GetInstance().m_strMemoryCardA; - std::string pathB = SConfig::GetInstance().m_strMemoryCardB; - if (!memcard) - { - pathA = SConfig::GetInstance().m_strGbaCartA; - pathB = SConfig::GetInstance().m_strGbaCartB; - } - SplitPath(is_slot_a ? pathA : pathB, &path, &cardname, &ext); - std::string filename = WxStrToStr(wxFileSelector( - _("Choose a file to open"), - StrToWxStr(path), - StrToWxStr(cardname), - StrToWxStr(ext), - memcard ? _("GameCube Memory Cards (*.raw,*.gcp)") + "|*.raw;*.gcp" : _("Game Boy Advance Carts (*.gba)") + "|*.gba")); + bool memcard = (device_type == EXIDEVICE_MEMORYCARD); + std::string path; + std::string cardname; + std::string ext; + std::string pathA = SConfig::GetInstance().m_strMemoryCardA; + std::string pathB = SConfig::GetInstance().m_strMemoryCardB; + if (!memcard) + { + pathA = SConfig::GetInstance().m_strGbaCartA; + pathB = SConfig::GetInstance().m_strGbaCartB; + } + SplitPath(is_slot_a ? pathA : pathB, &path, &cardname, &ext); + std::string filename = WxStrToStr(wxFileSelector( + _("Choose a file to open"), StrToWxStr(path), StrToWxStr(cardname), StrToWxStr(ext), + memcard ? _("GameCube Memory Cards (*.raw,*.gcp)") + "|*.raw;*.gcp" : + _("Game Boy Advance Carts (*.gba)") + "|*.gba")); - if (!filename.empty()) - { - if (File::Exists(filename)) - { - if (memcard) - { - GCMemcard memorycard(filename); - if (!memorycard.IsValid()) - { - WxUtils::ShowErrorDialog(wxString::Format(_("Cannot use that file as a memory card.\n%s\n" \ - "is not a valid GameCube memory card file"), filename.c_str())); - return; - } - } - } + if (!filename.empty()) + { + if (File::Exists(filename)) + { + if (memcard) + { + GCMemcard memorycard(filename); + if (!memorycard.IsValid()) + { + WxUtils::ShowErrorDialog(wxString::Format(_("Cannot use that file as a memory card.\n%s\n" + "is not a valid GameCube memory card file"), + filename.c_str())); + return; + } + } + } - wxFileName newFilename(filename); - newFilename.MakeAbsolute(); - filename = newFilename.GetFullPath(); + wxFileName newFilename(filename); + newFilename.MakeAbsolute(); + filename = newFilename.GetFullPath(); #ifdef _WIN32 - // If the Memory Card file is within the Exe dir, we can assume that the user wants it to be stored relative - // to the executable, so it stays set correctly when the probably portable Exe dir is moved. - // TODO: Replace this with a cleaner, non-wx solution once std::filesystem is standard - std::string exeDir = File::GetExeDirectory() + '\\'; - if (wxString(filename).Lower().StartsWith(wxString(exeDir).Lower())) - filename.erase(0, exeDir.size()); + // If the Memory Card file is within the Exe dir, we can assume that the user wants it to be + // stored relative + // to the executable, so it stays set correctly when the probably portable Exe dir is moved. + // TODO: Replace this with a cleaner, non-wx solution once std::filesystem is standard + std::string exeDir = File::GetExeDirectory() + '\\'; + if (wxString(filename).Lower().StartsWith(wxString(exeDir).Lower())) + filename.erase(0, exeDir.size()); - std::replace(filename.begin(), filename.end(), '\\', '/'); + std::replace(filename.begin(), filename.end(), '\\', '/'); #endif - // also check that the path isn't used for the other memcard... - wxFileName otherFilename(is_slot_a ? pathB : pathA); - otherFilename.MakeAbsolute(); - if (newFilename.GetFullPath().compare(otherFilename.GetFullPath()) != 0) - { - if (memcard) - { - if (is_slot_a) - SConfig::GetInstance().m_strMemoryCardA = filename; - else - SConfig::GetInstance().m_strMemoryCardB = filename; - } - else - { - if (is_slot_a) - SConfig::GetInstance().m_strGbaCartA = filename; - else - SConfig::GetInstance().m_strGbaCartB = filename; - } + // also check that the path isn't used for the other memcard... + wxFileName otherFilename(is_slot_a ? pathB : pathA); + otherFilename.MakeAbsolute(); + if (newFilename.GetFullPath().compare(otherFilename.GetFullPath()) != 0) + { + if (memcard) + { + if (is_slot_a) + SConfig::GetInstance().m_strMemoryCardA = filename; + else + SConfig::GetInstance().m_strMemoryCardB = filename; + } + else + { + if (is_slot_a) + SConfig::GetInstance().m_strGbaCartA = filename; + else + SConfig::GetInstance().m_strGbaCartB = filename; + } - if (Core::IsRunning()) - { - // Change memcard to the new file - ExpansionInterface::ChangeDevice( - is_slot_a ? 0 : 1, // SlotA: channel 0, SlotB channel 1 - device_type, - 0); // SP1 is device 2, slots are device 0 - } - } - else - { - WxUtils::ShowErrorDialog(_("Are you trying to use the same file in both slots?")); - } - } + if (Core::IsRunning()) + { + // Change memcard to the new file + ExpansionInterface::ChangeDevice(is_slot_a ? 0 : 1, // SlotA: channel 0, SlotB channel 1 + device_type, + 0); // SP1 is device 2, slots are device 0 + } + } + else + { + WxUtils::ShowErrorDialog(_("Are you trying to use the same file in both slots?")); + } + } } diff --git a/Source/Core/DolphinWX/Config/GameCubeConfigPane.h b/Source/Core/DolphinWX/Config/GameCubeConfigPane.h index f2d3284da7..73e4d5c75e 100644 --- a/Source/Core/DolphinWX/Config/GameCubeConfigPane.h +++ b/Source/Core/DolphinWX/Config/GameCubeConfigPane.h @@ -15,30 +15,30 @@ class wxString; class GameCubeConfigPane final : public wxPanel { public: - GameCubeConfigPane(wxWindow* parent, wxWindowID id); + GameCubeConfigPane(wxWindow* parent, wxWindowID id); private: - void InitializeGUI(); - void LoadGUIValues(); - void RefreshGUI(); + void InitializeGUI(); + void LoadGUIValues(); + void RefreshGUI(); - void OnSystemLanguageChange(wxCommandEvent&); - void OnOverrideLanguageCheckBoxChanged(wxCommandEvent&); - void OnSkipBiosCheckBoxChanged(wxCommandEvent&); - void OnSlotAChanged(wxCommandEvent&); - void OnSlotBChanged(wxCommandEvent&); - void OnSP1Changed(wxCommandEvent&); - void OnSlotAButtonClick(wxCommandEvent&); - void OnSlotBButtonClick(wxCommandEvent&); + void OnSystemLanguageChange(wxCommandEvent&); + void OnOverrideLanguageCheckBoxChanged(wxCommandEvent&); + void OnSkipBiosCheckBoxChanged(wxCommandEvent&); + void OnSlotAChanged(wxCommandEvent&); + void OnSlotBChanged(wxCommandEvent&); + void OnSP1Changed(wxCommandEvent&); + void OnSlotAButtonClick(wxCommandEvent&); + void OnSlotBButtonClick(wxCommandEvent&); - void ChooseEXIDevice(const wxString& device_name, int device_id); - void ChooseSlotPath(bool is_slot_a, TEXIDevices device_type); + void ChooseEXIDevice(const wxString& device_name, int device_id); + void ChooseSlotPath(bool is_slot_a, TEXIDevices device_type); - wxArrayString m_ipl_language_strings; + wxArrayString m_ipl_language_strings; - wxChoice* m_system_lang_choice; - wxCheckBox* m_override_lang_checkbox; - wxCheckBox* m_skip_bios_checkbox; - wxChoice* m_exi_devices[3]; - wxButton* m_memcard_path[2]; + wxChoice* m_system_lang_choice; + wxCheckBox* m_override_lang_checkbox; + wxCheckBox* m_skip_bios_checkbox; + wxChoice* m_exi_devices[3]; + wxButton* m_memcard_path[2]; }; diff --git a/Source/Core/DolphinWX/Config/GeneralConfigPane.cpp b/Source/Core/DolphinWX/Config/GeneralConfigPane.cpp index 8e322175c9..454fb3a59f 100644 --- a/Source/Core/DolphinWX/Config/GeneralConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/GeneralConfigPane.cpp @@ -16,183 +16,203 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/PowerPC/PowerPC.h" -#include "DolphinWX/Frame.h" -#include "DolphinWX/Main.h" #include "DolphinWX/Config/GeneralConfigPane.h" #include "DolphinWX/Debugger/CodeWindow.h" +#include "DolphinWX/Frame.h" +#include "DolphinWX/Main.h" -GeneralConfigPane::GeneralConfigPane(wxWindow* parent, wxWindowID id) - : wxPanel(parent, id) +GeneralConfigPane::GeneralConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id) { - cpu_cores = { - { PowerPC::CORE_INTERPRETER, _("Interpreter (slowest)") }, - { PowerPC::CORE_CACHEDINTERPRETER, _("Cached Interpreter (slower)") }, + cpu_cores = { + {PowerPC::CORE_INTERPRETER, _("Interpreter (slowest)")}, + {PowerPC::CORE_CACHEDINTERPRETER, _("Cached Interpreter (slower)")}, #ifdef _M_X86_64 - { PowerPC::CORE_JIT64, _("JIT Recompiler (recommended)") }, - { PowerPC::CORE_JITIL64, _("JITIL Recompiler (slow, experimental)") }, + {PowerPC::CORE_JIT64, _("JIT Recompiler (recommended)")}, + {PowerPC::CORE_JITIL64, _("JITIL Recompiler (slow, experimental)")}, #elif defined(_M_ARM_64) - { PowerPC::CORE_JITARM64, _("JIT Arm64 (experimental)") }, + {PowerPC::CORE_JITARM64, _("JIT Arm64 (experimental)")}, #endif - }; + }; - InitializeGUI(); - LoadGUIValues(); - RefreshGUI(); + InitializeGUI(); + LoadGUIValues(); + RefreshGUI(); } void GeneralConfigPane::InitializeGUI() { - m_throttler_array_string.Add(_("Unlimited")); - for (int i = 10; i <= 200; i += 10) // from 10% to 200% - { - if (i == 100) - m_throttler_array_string.Add(wxString::Format(_("%i%% (Normal Speed)"), i)); - else - m_throttler_array_string.Add(wxString::Format(_("%i%%"), i)); - } + m_throttler_array_string.Add(_("Unlimited")); + for (int i = 10; i <= 200; i += 10) // from 10% to 200% + { + if (i == 100) + m_throttler_array_string.Add(wxString::Format(_("%i%% (Normal Speed)"), i)); + else + m_throttler_array_string.Add(wxString::Format(_("%i%%"), i)); + } - for (const CPUCore& cpu_core : cpu_cores) - m_cpu_engine_array_string.Add(cpu_core.name); + for (const CPUCore& cpu_core : cpu_cores) + m_cpu_engine_array_string.Add(cpu_core.name); - m_dual_core_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Dual Core (speedup)")); - m_idle_skip_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Idle Skipping (speedup)")); - m_cheats_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Cheats")); - m_force_ntscj_checkbox = new wxCheckBox(this, wxID_ANY, _("Force Console as NTSC-J")); - m_analytics_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Usage Statistics Reporting")); + m_dual_core_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Dual Core (speedup)")); + m_idle_skip_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Idle Skipping (speedup)")); + m_cheats_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Cheats")); + m_force_ntscj_checkbox = new wxCheckBox(this, wxID_ANY, _("Force Console as NTSC-J")); + m_analytics_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Usage Statistics Reporting")); #ifdef __APPLE__ - m_analytics_new_id = new wxButton(this, wxID_ANY, _("Generate a New Statistics Identity"), wxDefaultPosition, wxSize(350, 25)); + m_analytics_new_id = new wxButton(this, wxID_ANY, _("Generate a New Statistics Identity"), + wxDefaultPosition, wxSize(350, 25)); #else - m_analytics_new_id = new wxButton(this, wxID_ANY, _("Generate a New Statistics Identity")); + m_analytics_new_id = new wxButton(this, wxID_ANY, _("Generate a New Statistics Identity")); #endif - m_throttler_choice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_throttler_array_string); - m_cpu_engine_radiobox = new wxRadioBox(this, wxID_ANY, _("CPU Emulator Engine"), wxDefaultPosition, wxDefaultSize, m_cpu_engine_array_string, 0, wxRA_SPECIFY_ROWS); + m_throttler_choice = + new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_throttler_array_string); + m_cpu_engine_radiobox = + new wxRadioBox(this, wxID_ANY, _("CPU Emulator Engine"), wxDefaultPosition, wxDefaultSize, + m_cpu_engine_array_string, 0, wxRA_SPECIFY_ROWS); - m_dual_core_checkbox->SetToolTip(_("Splits the CPU and GPU threads so they can be run on separate cores.\nProvides major speed improvements on most modern PCs, but can cause occasional crashes/glitches.")); - m_idle_skip_checkbox->SetToolTip(_("Attempt to detect and skip wait-loops.\nIf unsure, leave this checked.")); - m_cheats_checkbox->SetToolTip(_("Enables the use of Action Replay and Gecko cheats.")); - m_force_ntscj_checkbox->SetToolTip(_("Forces NTSC-J mode for using the Japanese ROM font.\nIf left unchecked, Dolphin defaults to NTSC-U and automatically enables this setting when playing Japanese games.")); - m_analytics_checkbox->SetToolTip(_("Enables the collection and sharing of usage statistics data with the Dolphin development team. This data is used to improve the emulator and help us understand how our users interact with the system. No private data is ever collected.")); - m_analytics_new_id->SetToolTip(_("Usage statistics reporting uses a unique random per-machine identifier to distinguish users from one another. This button generates a new random identifier for this machine which is dissociated from the previous one.")); - m_throttler_choice->SetToolTip(_("Limits the emulation speed to the specified percentage.\nNote that raising or lowering the emulation speed will also raise or lower the audio pitch to prevent audio from stuttering.")); + m_dual_core_checkbox->SetToolTip( + _("Splits the CPU and GPU threads so they can be run on separate cores.\nProvides major " + "speed improvements on most modern PCs, but can cause occasional crashes/glitches.")); + m_idle_skip_checkbox->SetToolTip( + _("Attempt to detect and skip wait-loops.\nIf unsure, leave this checked.")); + m_cheats_checkbox->SetToolTip(_("Enables the use of Action Replay and Gecko cheats.")); + m_force_ntscj_checkbox->SetToolTip( + _("Forces NTSC-J mode for using the Japanese ROM font.\nIf left unchecked, Dolphin defaults " + "to NTSC-U and automatically enables this setting when playing Japanese games.")); + m_analytics_checkbox->SetToolTip( + _("Enables the collection and sharing of usage statistics data with the Dolphin development " + "team. This data is used to improve the emulator and help us understand how our users " + "interact with the system. No private data is ever collected.")); + m_analytics_new_id->SetToolTip( + _("Usage statistics reporting uses a unique random per-machine identifier to distinguish " + "users from one another. This button generates a new random identifier for this machine " + "which is dissociated from the previous one.")); + m_throttler_choice->SetToolTip(_("Limits the emulation speed to the specified percentage.\nNote " + "that raising or lowering the emulation speed will also raise " + "or lower the audio pitch to prevent audio from stuttering.")); - m_dual_core_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnDualCoreCheckBoxChanged, this); - m_idle_skip_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnIdleSkipCheckBoxChanged, this); - m_cheats_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnCheatCheckBoxChanged, this); - m_force_ntscj_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnForceNTSCJCheckBoxChanged, this); - m_analytics_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnAnalyticsCheckBoxChanged, this); - m_analytics_new_id->Bind(wxEVT_BUTTON, &GeneralConfigPane::OnAnalyticsNewIdButtonClick, this); - m_throttler_choice->Bind(wxEVT_CHOICE, &GeneralConfigPane::OnThrottlerChoiceChanged, this); - m_cpu_engine_radiobox->Bind(wxEVT_RADIOBOX, &GeneralConfigPane::OnCPUEngineRadioBoxChanged, this); + m_dual_core_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnDualCoreCheckBoxChanged, this); + m_idle_skip_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnIdleSkipCheckBoxChanged, this); + m_cheats_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnCheatCheckBoxChanged, this); + m_force_ntscj_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnForceNTSCJCheckBoxChanged, + this); + m_analytics_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnAnalyticsCheckBoxChanged, this); + m_analytics_new_id->Bind(wxEVT_BUTTON, &GeneralConfigPane::OnAnalyticsNewIdButtonClick, this); + m_throttler_choice->Bind(wxEVT_CHOICE, &GeneralConfigPane::OnThrottlerChoiceChanged, this); + m_cpu_engine_radiobox->Bind(wxEVT_RADIOBOX, &GeneralConfigPane::OnCPUEngineRadioBoxChanged, this); - wxBoxSizer* const throttler_sizer = new wxBoxSizer(wxHORIZONTAL); - throttler_sizer->Add(new wxStaticText(this, wxID_ANY, _("Speed Limit:")), 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxBOTTOM, 5); - throttler_sizer->Add(m_throttler_choice, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5); + wxBoxSizer* const throttler_sizer = new wxBoxSizer(wxHORIZONTAL); + throttler_sizer->Add(new wxStaticText(this, wxID_ANY, _("Speed Limit:")), 0, + wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxBOTTOM, 5); + throttler_sizer->Add(m_throttler_choice, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5); - wxStaticBoxSizer* const basic_settings_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Basic Settings")); - basic_settings_sizer->Add(m_dual_core_checkbox, 0, wxALL, 5); - basic_settings_sizer->Add(m_idle_skip_checkbox, 0, wxALL, 5); - basic_settings_sizer->Add(m_cheats_checkbox, 0, wxALL, 5); - basic_settings_sizer->Add(throttler_sizer); + wxStaticBoxSizer* const basic_settings_sizer = + new wxStaticBoxSizer(wxVERTICAL, this, _("Basic Settings")); + basic_settings_sizer->Add(m_dual_core_checkbox, 0, wxALL, 5); + basic_settings_sizer->Add(m_idle_skip_checkbox, 0, wxALL, 5); + basic_settings_sizer->Add(m_cheats_checkbox, 0, wxALL, 5); + basic_settings_sizer->Add(throttler_sizer); - wxStaticBoxSizer* const analytics_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Usage Statistics Reporting Settings")); - analytics_sizer->Add(m_analytics_checkbox, 0, wxALL, 5); - analytics_sizer->Add(m_analytics_new_id, 0, wxALL, 5); + wxStaticBoxSizer* const analytics_sizer = + new wxStaticBoxSizer(wxVERTICAL, this, _("Usage Statistics Reporting Settings")); + analytics_sizer->Add(m_analytics_checkbox, 0, wxALL, 5); + analytics_sizer->Add(m_analytics_new_id, 0, wxALL, 5); - wxStaticBoxSizer* const advanced_settings_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Advanced Settings")); - advanced_settings_sizer->Add(m_cpu_engine_radiobox, 0, wxALL, 5); - advanced_settings_sizer->Add(m_force_ntscj_checkbox, 0, wxALL, 5); + wxStaticBoxSizer* const advanced_settings_sizer = + new wxStaticBoxSizer(wxVERTICAL, this, _("Advanced Settings")); + advanced_settings_sizer->Add(m_cpu_engine_radiobox, 0, wxALL, 5); + advanced_settings_sizer->Add(m_force_ntscj_checkbox, 0, wxALL, 5); - wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); - main_sizer->Add(basic_settings_sizer, 0, wxEXPAND | wxALL, 5); - main_sizer->Add(analytics_sizer, 0, wxEXPAND | wxALL, 5); - main_sizer->Add(advanced_settings_sizer, 0, wxEXPAND | wxALL, 5); + wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); + main_sizer->Add(basic_settings_sizer, 0, wxEXPAND | wxALL, 5); + main_sizer->Add(analytics_sizer, 0, wxEXPAND | wxALL, 5); + main_sizer->Add(advanced_settings_sizer, 0, wxEXPAND | wxALL, 5); - SetSizer(main_sizer); + SetSizer(main_sizer); } void GeneralConfigPane::LoadGUIValues() { - const SConfig& startup_params = SConfig::GetInstance(); + const SConfig& startup_params = SConfig::GetInstance(); - m_dual_core_checkbox->SetValue(startup_params.bCPUThread); - m_idle_skip_checkbox->SetValue(startup_params.bSkipIdle); - m_cheats_checkbox->SetValue(startup_params.bEnableCheats); - m_force_ntscj_checkbox->SetValue(startup_params.bForceNTSCJ); - m_analytics_checkbox->SetValue(startup_params.m_analytics_enabled); - u32 selection = std::lround(startup_params.m_EmulationSpeed * 10.0f); - if (selection < m_throttler_array_string.size()) - m_throttler_choice->SetSelection(selection); + m_dual_core_checkbox->SetValue(startup_params.bCPUThread); + m_idle_skip_checkbox->SetValue(startup_params.bSkipIdle); + m_cheats_checkbox->SetValue(startup_params.bEnableCheats); + m_force_ntscj_checkbox->SetValue(startup_params.bForceNTSCJ); + m_analytics_checkbox->SetValue(startup_params.m_analytics_enabled); + u32 selection = std::lround(startup_params.m_EmulationSpeed * 10.0f); + if (selection < m_throttler_array_string.size()) + m_throttler_choice->SetSelection(selection); - for (size_t i = 0; i < cpu_cores.size(); ++i) - { - if (cpu_cores[i].CPUid == startup_params.iCPUCore) - m_cpu_engine_radiobox->SetSelection(i); - } + for (size_t i = 0; i < cpu_cores.size(); ++i) + { + if (cpu_cores[i].CPUid == startup_params.iCPUCore) + m_cpu_engine_radiobox->SetSelection(i); + } } void GeneralConfigPane::RefreshGUI() { - if (Core::IsRunning()) - { - m_dual_core_checkbox->Disable(); - m_idle_skip_checkbox->Disable(); - m_cheats_checkbox->Disable(); - m_force_ntscj_checkbox->Disable(); - m_cpu_engine_radiobox->Disable(); - } + if (Core::IsRunning()) + { + m_dual_core_checkbox->Disable(); + m_idle_skip_checkbox->Disable(); + m_cheats_checkbox->Disable(); + m_force_ntscj_checkbox->Disable(); + m_cpu_engine_radiobox->Disable(); + } } void GeneralConfigPane::OnDualCoreCheckBoxChanged(wxCommandEvent& event) { - if (Core::IsRunning()) - return; + if (Core::IsRunning()) + return; - SConfig::GetInstance().bCPUThread = m_dual_core_checkbox->IsChecked(); + SConfig::GetInstance().bCPUThread = m_dual_core_checkbox->IsChecked(); } void GeneralConfigPane::OnIdleSkipCheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().bSkipIdle = m_idle_skip_checkbox->IsChecked(); + SConfig::GetInstance().bSkipIdle = m_idle_skip_checkbox->IsChecked(); } void GeneralConfigPane::OnCheatCheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().bEnableCheats = m_cheats_checkbox->IsChecked(); + SConfig::GetInstance().bEnableCheats = m_cheats_checkbox->IsChecked(); } void GeneralConfigPane::OnForceNTSCJCheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().bForceNTSCJ = m_force_ntscj_checkbox->IsChecked(); + SConfig::GetInstance().bForceNTSCJ = m_force_ntscj_checkbox->IsChecked(); } void GeneralConfigPane::OnThrottlerChoiceChanged(wxCommandEvent& event) { - if (m_throttler_choice->GetSelection() != wxNOT_FOUND) - SConfig::GetInstance().m_EmulationSpeed = m_throttler_choice->GetSelection() * 0.1f; + if (m_throttler_choice->GetSelection() != wxNOT_FOUND) + SConfig::GetInstance().m_EmulationSpeed = m_throttler_choice->GetSelection() * 0.1f; } void GeneralConfigPane::OnCPUEngineRadioBoxChanged(wxCommandEvent& event) { - const int selection = m_cpu_engine_radiobox->GetSelection(); + const int selection = m_cpu_engine_radiobox->GetSelection(); - if (main_frame->g_pCodeWindow) - { + if (main_frame->g_pCodeWindow) + { + bool using_interp = (SConfig::GetInstance().iCPUCore == PowerPC::CORE_INTERPRETER); + main_frame->g_pCodeWindow->GetMenuBar()->Check(IDM_INTERPRETER, using_interp); + } - bool using_interp = (SConfig::GetInstance().iCPUCore == PowerPC::CORE_INTERPRETER); - main_frame->g_pCodeWindow->GetMenuBar()->Check(IDM_INTERPRETER, using_interp); - } - - SConfig::GetInstance().iCPUCore = cpu_cores[selection].CPUid; + SConfig::GetInstance().iCPUCore = cpu_cores[selection].CPUid; } void GeneralConfigPane::OnAnalyticsCheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().m_analytics_enabled = m_analytics_checkbox->IsChecked(); - DolphinAnalytics::Instance()->ReloadConfig(); + SConfig::GetInstance().m_analytics_enabled = m_analytics_checkbox->IsChecked(); + DolphinAnalytics::Instance()->ReloadConfig(); } void GeneralConfigPane::OnAnalyticsNewIdButtonClick(wxCommandEvent& event) { - DolphinAnalytics::Instance()->GenerateNewIdentity(); - wxMessageBox(_("New identity generated."), _("Identity generation"), wxICON_INFORMATION); + DolphinAnalytics::Instance()->GenerateNewIdentity(); + wxMessageBox(_("New identity generated."), _("Identity generation"), wxICON_INFORMATION); } diff --git a/Source/Core/DolphinWX/Config/GeneralConfigPane.h b/Source/Core/DolphinWX/Config/GeneralConfigPane.h index d8ed32977b..f185319b7a 100644 --- a/Source/Core/DolphinWX/Config/GeneralConfigPane.h +++ b/Source/Core/DolphinWX/Config/GeneralConfigPane.h @@ -15,41 +15,40 @@ class wxRadioBox; class GeneralConfigPane final : public wxPanel { public: - GeneralConfigPane(wxWindow* parent, wxWindowID id); + GeneralConfigPane(wxWindow* parent, wxWindowID id); private: + struct CPUCore + { + int CPUid; + wxString name; + }; + std::vector cpu_cores; + void InitializeGUI(); + void LoadGUIValues(); + void RefreshGUI(); - struct CPUCore - { - int CPUid; - wxString name; - }; - std::vector cpu_cores; - void InitializeGUI(); - void LoadGUIValues(); - void RefreshGUI(); + void OnDualCoreCheckBoxChanged(wxCommandEvent&); + void OnIdleSkipCheckBoxChanged(wxCommandEvent&); + void OnCheatCheckBoxChanged(wxCommandEvent&); + void OnForceNTSCJCheckBoxChanged(wxCommandEvent&); + void OnThrottlerChoiceChanged(wxCommandEvent&); + void OnCPUEngineRadioBoxChanged(wxCommandEvent&); + void OnAnalyticsCheckBoxChanged(wxCommandEvent&); + void OnAnalyticsNewIdButtonClick(wxCommandEvent&); - void OnDualCoreCheckBoxChanged(wxCommandEvent&); - void OnIdleSkipCheckBoxChanged(wxCommandEvent&); - void OnCheatCheckBoxChanged(wxCommandEvent&); - void OnForceNTSCJCheckBoxChanged(wxCommandEvent&); - void OnThrottlerChoiceChanged(wxCommandEvent&); - void OnCPUEngineRadioBoxChanged(wxCommandEvent&); - void OnAnalyticsCheckBoxChanged(wxCommandEvent&); - void OnAnalyticsNewIdButtonClick(wxCommandEvent&); + wxArrayString m_throttler_array_string; + wxArrayString m_cpu_engine_array_string; - wxArrayString m_throttler_array_string; - wxArrayString m_cpu_engine_array_string; + wxCheckBox* m_dual_core_checkbox; + wxCheckBox* m_idle_skip_checkbox; + wxCheckBox* m_cheats_checkbox; + wxCheckBox* m_force_ntscj_checkbox; - wxCheckBox* m_dual_core_checkbox; - wxCheckBox* m_idle_skip_checkbox; - wxCheckBox* m_cheats_checkbox; - wxCheckBox* m_force_ntscj_checkbox; + wxCheckBox* m_analytics_checkbox; + wxButton* m_analytics_new_id; - wxCheckBox* m_analytics_checkbox; - wxButton* m_analytics_new_id; + wxChoice* m_throttler_choice; - wxChoice* m_throttler_choice; - - wxRadioBox* m_cpu_engine_radiobox; + wxRadioBox* m_cpu_engine_radiobox; }; diff --git a/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp b/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp index f4359684bf..a3934c9b8f 100644 --- a/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp @@ -17,208 +17,225 @@ #include "Common/FileUtil.h" #include "Core/ConfigManager.h" #include "Core/HotkeyManager.h" +#include "DolphinWX/Config/InterfaceConfigPane.h" #include "DolphinWX/Frame.h" #include "DolphinWX/InputConfigDiag.h" #include "DolphinWX/Main.h" #include "DolphinWX/WxUtils.h" -#include "DolphinWX/Config/InterfaceConfigPane.h" #if defined(HAVE_XRANDR) && HAVE_XRANDR #include "DolphinWX/X11Utils.h" #endif -static const wxLanguage language_ids[] = -{ - wxLANGUAGE_DEFAULT, +static const wxLanguage language_ids[] = { + wxLANGUAGE_DEFAULT, - wxLANGUAGE_MALAY, - wxLANGUAGE_CATALAN, - wxLANGUAGE_CZECH, - wxLANGUAGE_DANISH, - wxLANGUAGE_GERMAN, - wxLANGUAGE_ENGLISH, - wxLANGUAGE_SPANISH, - wxLANGUAGE_FRENCH, - wxLANGUAGE_CROATIAN, - wxLANGUAGE_ITALIAN, - wxLANGUAGE_HUNGARIAN, - wxLANGUAGE_DUTCH, - wxLANGUAGE_NORWEGIAN_BOKMAL, - wxLANGUAGE_POLISH, - wxLANGUAGE_PORTUGUESE, - wxLANGUAGE_PORTUGUESE_BRAZILIAN, - wxLANGUAGE_ROMANIAN, - wxLANGUAGE_SERBIAN, - wxLANGUAGE_SWEDISH, - wxLANGUAGE_TURKISH, + wxLANGUAGE_MALAY, + wxLANGUAGE_CATALAN, + wxLANGUAGE_CZECH, + wxLANGUAGE_DANISH, + wxLANGUAGE_GERMAN, + wxLANGUAGE_ENGLISH, + wxLANGUAGE_SPANISH, + wxLANGUAGE_FRENCH, + wxLANGUAGE_CROATIAN, + wxLANGUAGE_ITALIAN, + wxLANGUAGE_HUNGARIAN, + wxLANGUAGE_DUTCH, + wxLANGUAGE_NORWEGIAN_BOKMAL, + wxLANGUAGE_POLISH, + wxLANGUAGE_PORTUGUESE, + wxLANGUAGE_PORTUGUESE_BRAZILIAN, + wxLANGUAGE_ROMANIAN, + wxLANGUAGE_SERBIAN, + wxLANGUAGE_SWEDISH, + wxLANGUAGE_TURKISH, - wxLANGUAGE_GREEK, - wxLANGUAGE_RUSSIAN, - wxLANGUAGE_ARABIC, - wxLANGUAGE_FARSI, - wxLANGUAGE_KOREAN, - wxLANGUAGE_JAPANESE, - wxLANGUAGE_CHINESE_SIMPLIFIED, - wxLANGUAGE_CHINESE_TRADITIONAL, + wxLANGUAGE_GREEK, + wxLANGUAGE_RUSSIAN, + wxLANGUAGE_ARABIC, + wxLANGUAGE_FARSI, + wxLANGUAGE_KOREAN, + wxLANGUAGE_JAPANESE, + wxLANGUAGE_CHINESE_SIMPLIFIED, + wxLANGUAGE_CHINESE_TRADITIONAL, }; -InterfaceConfigPane::InterfaceConfigPane(wxWindow* parent, wxWindowID id) - : wxPanel(parent, id) +InterfaceConfigPane::InterfaceConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id) { - InitializeGUI(); - LoadGUIValues(); + InitializeGUI(); + LoadGUIValues(); } void InterfaceConfigPane::InitializeGUI() { - // GUI language arrayStrings - // keep these in sync with the language_ids array at the beginning of this file - m_interface_lang_strings.Add(_("")); + // GUI language arrayStrings + // keep these in sync with the language_ids array at the beginning of this file + m_interface_lang_strings.Add(_("")); - m_interface_lang_strings.Add(L"Bahasa Melayu"); // Malay - m_interface_lang_strings.Add(L"Catal\u00E0"); // Catalan - m_interface_lang_strings.Add(L"\u010Ce\u0161tina"); // Czech - m_interface_lang_strings.Add(L"Dansk"); // Danish - m_interface_lang_strings.Add(L"Deutsch"); // German - m_interface_lang_strings.Add(L"English"); // English - m_interface_lang_strings.Add(L"Espa\u00F1ol"); // Spanish - m_interface_lang_strings.Add(L"Fran\u00E7ais"); // French - m_interface_lang_strings.Add(L"Hrvatski"); // Croatian - m_interface_lang_strings.Add(L"Italiano"); // Italian - m_interface_lang_strings.Add(L"Magyar"); // Hungarian - m_interface_lang_strings.Add(L"Nederlands"); // Dutch - m_interface_lang_strings.Add(L"Norsk bokm\u00E5l"); // Norwegian - m_interface_lang_strings.Add(L"Polski"); // Polish - m_interface_lang_strings.Add(L"Portugu\u00EAs"); // Portuguese - m_interface_lang_strings.Add(L"Portugu\u00EAs (Brasil)"); // Portuguese (Brazil) - m_interface_lang_strings.Add(L"Rom\u00E2n\u0103"); // Romanian - m_interface_lang_strings.Add(L"Srpski"); // Serbian - m_interface_lang_strings.Add(L"Svenska"); // Swedish - m_interface_lang_strings.Add(L"T\u00FCrk\u00E7e"); // Turkish + m_interface_lang_strings.Add(L"Bahasa Melayu"); // Malay + m_interface_lang_strings.Add(L"Catal\u00E0"); // Catalan + m_interface_lang_strings.Add(L"\u010Ce\u0161tina"); // Czech + m_interface_lang_strings.Add(L"Dansk"); // Danish + m_interface_lang_strings.Add(L"Deutsch"); // German + m_interface_lang_strings.Add(L"English"); // English + m_interface_lang_strings.Add(L"Espa\u00F1ol"); // Spanish + m_interface_lang_strings.Add(L"Fran\u00E7ais"); // French + m_interface_lang_strings.Add(L"Hrvatski"); // Croatian + m_interface_lang_strings.Add(L"Italiano"); // Italian + m_interface_lang_strings.Add(L"Magyar"); // Hungarian + m_interface_lang_strings.Add(L"Nederlands"); // Dutch + m_interface_lang_strings.Add(L"Norsk bokm\u00E5l"); // Norwegian + m_interface_lang_strings.Add(L"Polski"); // Polish + m_interface_lang_strings.Add(L"Portugu\u00EAs"); // Portuguese + m_interface_lang_strings.Add(L"Portugu\u00EAs (Brasil)"); // Portuguese (Brazil) + m_interface_lang_strings.Add(L"Rom\u00E2n\u0103"); // Romanian + m_interface_lang_strings.Add(L"Srpski"); // Serbian + m_interface_lang_strings.Add(L"Svenska"); // Swedish + m_interface_lang_strings.Add(L"T\u00FCrk\u00E7e"); // Turkish - m_interface_lang_strings.Add(L"\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC"); // Greek - m_interface_lang_strings.Add(L"\u0420\u0443\u0441\u0441\u043A\u0438\u0439"); // Russian - m_interface_lang_strings.Add(L"\u0627\u0644\u0639\u0631\u0628\u064A\u0629"); // Arabic - m_interface_lang_strings.Add(L"\u0641\u0627\u0631\u0633\u06CC"); // Farsi - m_interface_lang_strings.Add(L"\uD55C\uAD6D\uC5B4"); // Korean - m_interface_lang_strings.Add(L"\u65E5\u672C\u8A9E"); // Japanese - m_interface_lang_strings.Add(L"\u7B80\u4F53\u4E2D\u6587"); // Simplified Chinese - m_interface_lang_strings.Add(L"\u7E41\u9AD4\u4E2D\u6587"); // Traditional Chinese + m_interface_lang_strings.Add(L"\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC"); // Greek + m_interface_lang_strings.Add(L"\u0420\u0443\u0441\u0441\u043A\u0438\u0439"); // Russian + m_interface_lang_strings.Add(L"\u0627\u0644\u0639\u0631\u0628\u064A\u0629"); // Arabic + m_interface_lang_strings.Add(L"\u0641\u0627\u0631\u0633\u06CC"); // Farsi + m_interface_lang_strings.Add(L"\uD55C\uAD6D\uC5B4"); // Korean + m_interface_lang_strings.Add(L"\u65E5\u672C\u8A9E"); // Japanese + m_interface_lang_strings.Add(L"\u7B80\u4F53\u4E2D\u6587"); // Simplified Chinese + m_interface_lang_strings.Add(L"\u7E41\u9AD4\u4E2D\u6587"); // Traditional Chinese - m_confirm_stop_checkbox = new wxCheckBox(this, wxID_ANY, _("Confirm on Stop")); - m_panic_handlers_checkbox = new wxCheckBox(this, wxID_ANY, _("Use Panic Handlers")); - m_osd_messages_checkbox = new wxCheckBox(this, wxID_ANY, _("On-Screen Display Messages")); - m_pause_focus_lost_checkbox = new wxCheckBox(this, wxID_ANY, _("Pause on Focus Lost")); - m_interface_lang_choice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_interface_lang_strings); - m_theme_choice = new wxChoice(this, wxID_ANY); + m_confirm_stop_checkbox = new wxCheckBox(this, wxID_ANY, _("Confirm on Stop")); + m_panic_handlers_checkbox = new wxCheckBox(this, wxID_ANY, _("Use Panic Handlers")); + m_osd_messages_checkbox = new wxCheckBox(this, wxID_ANY, _("On-Screen Display Messages")); + m_pause_focus_lost_checkbox = new wxCheckBox(this, wxID_ANY, _("Pause on Focus Lost")); + m_interface_lang_choice = + new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_interface_lang_strings); + m_theme_choice = new wxChoice(this, wxID_ANY); - m_confirm_stop_checkbox->Bind(wxEVT_CHECKBOX, &InterfaceConfigPane::OnConfirmStopCheckBoxChanged, this); - m_panic_handlers_checkbox->Bind(wxEVT_CHECKBOX, &InterfaceConfigPane::OnPanicHandlersCheckBoxChanged, this); - m_osd_messages_checkbox->Bind(wxEVT_CHECKBOX, &InterfaceConfigPane::OnOSDMessagesCheckBoxChanged, this); - m_pause_focus_lost_checkbox->Bind(wxEVT_CHECKBOX, &InterfaceConfigPane::OnPauseOnFocusLostCheckBoxChanged, this); - m_interface_lang_choice->Bind(wxEVT_CHOICE, &InterfaceConfigPane::OnInterfaceLanguageChoiceChanged, this); - m_theme_choice->Bind(wxEVT_CHOICE, &InterfaceConfigPane::OnThemeSelected, this); + m_confirm_stop_checkbox->Bind(wxEVT_CHECKBOX, &InterfaceConfigPane::OnConfirmStopCheckBoxChanged, + this); + m_panic_handlers_checkbox->Bind(wxEVT_CHECKBOX, + &InterfaceConfigPane::OnPanicHandlersCheckBoxChanged, this); + m_osd_messages_checkbox->Bind(wxEVT_CHECKBOX, &InterfaceConfigPane::OnOSDMessagesCheckBoxChanged, + this); + m_pause_focus_lost_checkbox->Bind(wxEVT_CHECKBOX, + &InterfaceConfigPane::OnPauseOnFocusLostCheckBoxChanged, this); + m_interface_lang_choice->Bind(wxEVT_CHOICE, + &InterfaceConfigPane::OnInterfaceLanguageChoiceChanged, this); + m_theme_choice->Bind(wxEVT_CHOICE, &InterfaceConfigPane::OnThemeSelected, this); - m_confirm_stop_checkbox->SetToolTip(_("Show a confirmation box before stopping a game.")); - m_panic_handlers_checkbox->SetToolTip(_("Show a message box when a potentially serious error has occurred.\nDisabling this may avoid annoying and non-fatal messages, but it may result in major crashes having no explanation at all.")); - m_osd_messages_checkbox->SetToolTip(_("Display messages over the emulation screen area.\nThese messages include memory card writes, video backend and CPU information, and JIT cache clearing.")); - m_pause_focus_lost_checkbox->SetToolTip(_("Pauses the emulator when focus is taken away from the emulation window.")); - m_interface_lang_choice->SetToolTip(_("Change the language of the user interface.\nRequires restart.")); + m_confirm_stop_checkbox->SetToolTip(_("Show a confirmation box before stopping a game.")); + m_panic_handlers_checkbox->SetToolTip( + _("Show a message box when a potentially serious error has occurred.\nDisabling this may " + "avoid annoying and non-fatal messages, but it may result in major crashes having no " + "explanation at all.")); + m_osd_messages_checkbox->SetToolTip( + _("Display messages over the emulation screen area.\nThese messages include memory card " + "writes, video backend and CPU information, and JIT cache clearing.")); + m_pause_focus_lost_checkbox->SetToolTip( + _("Pauses the emulator when focus is taken away from the emulation window.")); + m_interface_lang_choice->SetToolTip( + _("Change the language of the user interface.\nRequires restart.")); - wxGridBagSizer* const language_and_theme_grid_sizer = new wxGridBagSizer(); - language_and_theme_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Language:")), wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); - language_and_theme_grid_sizer->Add(m_interface_lang_choice, wxGBPosition(0, 1), wxDefaultSpan, wxALL, 5); - language_and_theme_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Theme:")), wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); - language_and_theme_grid_sizer->Add(m_theme_choice, wxGBPosition(1, 1), wxDefaultSpan, wxALL, 5); + wxGridBagSizer* const language_and_theme_grid_sizer = new wxGridBagSizer(); + language_and_theme_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Language:")), + wxGBPosition(0, 0), wxDefaultSpan, + wxALIGN_CENTER_VERTICAL | wxALL, 5); + language_and_theme_grid_sizer->Add(m_interface_lang_choice, wxGBPosition(0, 1), wxDefaultSpan, + wxALL, 5); + language_and_theme_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Theme:")), + wxGBPosition(1, 0), wxDefaultSpan, + wxALIGN_CENTER_VERTICAL | wxALL, 5); + language_and_theme_grid_sizer->Add(m_theme_choice, wxGBPosition(1, 1), wxDefaultSpan, wxALL, 5); - wxStaticBoxSizer* const main_static_box_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Interface Settings")); - main_static_box_sizer->Add(m_confirm_stop_checkbox, 0, wxALL, 5); - main_static_box_sizer->Add(m_panic_handlers_checkbox, 0, wxALL, 5); - main_static_box_sizer->Add(m_osd_messages_checkbox, 0, wxALL, 5); - main_static_box_sizer->Add(m_pause_focus_lost_checkbox, 0, wxALL, 5); - main_static_box_sizer->Add(language_and_theme_grid_sizer, 0, wxEXPAND | wxALL, 0); + wxStaticBoxSizer* const main_static_box_sizer = + new wxStaticBoxSizer(wxVERTICAL, this, _("Interface Settings")); + main_static_box_sizer->Add(m_confirm_stop_checkbox, 0, wxALL, 5); + main_static_box_sizer->Add(m_panic_handlers_checkbox, 0, wxALL, 5); + main_static_box_sizer->Add(m_osd_messages_checkbox, 0, wxALL, 5); + main_static_box_sizer->Add(m_pause_focus_lost_checkbox, 0, wxALL, 5); + main_static_box_sizer->Add(language_and_theme_grid_sizer, 0, wxEXPAND | wxALL, 0); - wxBoxSizer* const main_box_sizer = new wxBoxSizer(wxVERTICAL); - main_box_sizer->Add(main_static_box_sizer, 0, wxEXPAND | wxALL, 5); + wxBoxSizer* const main_box_sizer = new wxBoxSizer(wxVERTICAL); + main_box_sizer->Add(main_static_box_sizer, 0, wxEXPAND | wxALL, 5); - SetSizer(main_box_sizer); + SetSizer(main_box_sizer); } void InterfaceConfigPane::LoadGUIValues() { - const SConfig& startup_params = SConfig::GetInstance(); + const SConfig& startup_params = SConfig::GetInstance(); - m_confirm_stop_checkbox->SetValue(startup_params.bConfirmStop); - m_panic_handlers_checkbox->SetValue(startup_params.bUsePanicHandlers); - m_osd_messages_checkbox->SetValue(startup_params.bOnScreenDisplayMessages); - m_pause_focus_lost_checkbox->SetValue(SConfig::GetInstance().m_PauseOnFocusLost); + m_confirm_stop_checkbox->SetValue(startup_params.bConfirmStop); + m_panic_handlers_checkbox->SetValue(startup_params.bUsePanicHandlers); + m_osd_messages_checkbox->SetValue(startup_params.bOnScreenDisplayMessages); + m_pause_focus_lost_checkbox->SetValue(SConfig::GetInstance().m_PauseOnFocusLost); - for (size_t i = 0; i < sizeof(language_ids) / sizeof(wxLanguage); i++) - { - if (language_ids [i] == SConfig::GetInstance().m_InterfaceLanguage) - { - m_interface_lang_choice->SetSelection(i); - break; - } - } + for (size_t i = 0; i < sizeof(language_ids) / sizeof(wxLanguage); i++) + { + if (language_ids[i] == SConfig::GetInstance().m_InterfaceLanguage) + { + m_interface_lang_choice->SetSelection(i); + break; + } + } - LoadThemes(); + LoadThemes(); } void InterfaceConfigPane::LoadThemes() { - auto sv = DoFileSearch({""}, { - File::GetUserPath(D_THEMES_IDX), - File::GetSysDirectory() + THEMES_DIR - }, /*recursive*/ false); - for (const std::string& filename : sv) - { - std::string name, ext; - SplitPath(filename, nullptr, &name, &ext); + auto sv = + DoFileSearch({""}, {File::GetUserPath(D_THEMES_IDX), File::GetSysDirectory() + THEMES_DIR}, + /*recursive*/ false); + for (const std::string& filename : sv) + { + std::string name, ext; + SplitPath(filename, nullptr, &name, &ext); - name += ext; - const wxString wxname = StrToWxStr(name); - if (-1 == m_theme_choice->FindString(wxname)) - m_theme_choice->Append(wxname); - } + name += ext; + const wxString wxname = StrToWxStr(name); + if (-1 == m_theme_choice->FindString(wxname)) + m_theme_choice->Append(wxname); + } - m_theme_choice->SetStringSelection(StrToWxStr(SConfig::GetInstance().theme_name)); + m_theme_choice->SetStringSelection(StrToWxStr(SConfig::GetInstance().theme_name)); } void InterfaceConfigPane::OnConfirmStopCheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().bConfirmStop = m_confirm_stop_checkbox->IsChecked(); + SConfig::GetInstance().bConfirmStop = m_confirm_stop_checkbox->IsChecked(); } void InterfaceConfigPane::OnPanicHandlersCheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().bUsePanicHandlers = m_panic_handlers_checkbox->IsChecked(); - SetEnableAlert(m_panic_handlers_checkbox->IsChecked()); + SConfig::GetInstance().bUsePanicHandlers = m_panic_handlers_checkbox->IsChecked(); + SetEnableAlert(m_panic_handlers_checkbox->IsChecked()); } void InterfaceConfigPane::OnOSDMessagesCheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().bOnScreenDisplayMessages = m_osd_messages_checkbox->IsChecked(); + SConfig::GetInstance().bOnScreenDisplayMessages = m_osd_messages_checkbox->IsChecked(); } void InterfaceConfigPane::OnInterfaceLanguageChoiceChanged(wxCommandEvent& event) { - if (SConfig::GetInstance().m_InterfaceLanguage != language_ids[m_interface_lang_choice->GetSelection()]) - SuccessAlertT("You must restart Dolphin in order for the change to take effect."); + if (SConfig::GetInstance().m_InterfaceLanguage != + language_ids[m_interface_lang_choice->GetSelection()]) + SuccessAlertT("You must restart Dolphin in order for the change to take effect."); - SConfig::GetInstance().m_InterfaceLanguage = language_ids[m_interface_lang_choice->GetSelection()]; + SConfig::GetInstance().m_InterfaceLanguage = + language_ids[m_interface_lang_choice->GetSelection()]; } void InterfaceConfigPane::OnPauseOnFocusLostCheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().m_PauseOnFocusLost = m_pause_focus_lost_checkbox->IsChecked(); + SConfig::GetInstance().m_PauseOnFocusLost = m_pause_focus_lost_checkbox->IsChecked(); } void InterfaceConfigPane::OnThemeSelected(wxCommandEvent& event) { - SConfig::GetInstance().theme_name = WxStrToStr(m_theme_choice->GetStringSelection()); + SConfig::GetInstance().theme_name = WxStrToStr(m_theme_choice->GetStringSelection()); - main_frame->InitBitmaps(); - main_frame->UpdateGameList(); + main_frame->InitBitmaps(); + main_frame->UpdateGameList(); } - diff --git a/Source/Core/DolphinWX/Config/InterfaceConfigPane.h b/Source/Core/DolphinWX/Config/InterfaceConfigPane.h index 6be6cb91e7..258aff05a7 100644 --- a/Source/Core/DolphinWX/Config/InterfaceConfigPane.h +++ b/Source/Core/DolphinWX/Config/InterfaceConfigPane.h @@ -14,26 +14,26 @@ class wxChoice; class InterfaceConfigPane final : public wxPanel { public: - InterfaceConfigPane(wxWindow* parent, wxWindowID id); + InterfaceConfigPane(wxWindow* parent, wxWindowID id); private: - void InitializeGUI(); - void LoadGUIValues(); - void LoadThemes(); + void InitializeGUI(); + void LoadGUIValues(); + void LoadThemes(); - void OnConfirmStopCheckBoxChanged(wxCommandEvent&); - void OnPanicHandlersCheckBoxChanged(wxCommandEvent&); - void OnOSDMessagesCheckBoxChanged(wxCommandEvent&); - void OnInterfaceLanguageChoiceChanged(wxCommandEvent&); - void OnPauseOnFocusLostCheckBoxChanged(wxCommandEvent&); - void OnThemeSelected(wxCommandEvent&); + void OnConfirmStopCheckBoxChanged(wxCommandEvent&); + void OnPanicHandlersCheckBoxChanged(wxCommandEvent&); + void OnOSDMessagesCheckBoxChanged(wxCommandEvent&); + void OnInterfaceLanguageChoiceChanged(wxCommandEvent&); + void OnPauseOnFocusLostCheckBoxChanged(wxCommandEvent&); + void OnThemeSelected(wxCommandEvent&); - wxArrayString m_interface_lang_strings; + wxArrayString m_interface_lang_strings; - wxCheckBox* m_confirm_stop_checkbox; - wxCheckBox* m_panic_handlers_checkbox; - wxCheckBox* m_osd_messages_checkbox; - wxCheckBox* m_pause_focus_lost_checkbox; - wxChoice* m_interface_lang_choice; - wxChoice* m_theme_choice; + wxCheckBox* m_confirm_stop_checkbox; + wxCheckBox* m_panic_handlers_checkbox; + wxCheckBox* m_osd_messages_checkbox; + wxCheckBox* m_pause_focus_lost_checkbox; + wxChoice* m_interface_lang_choice; + wxChoice* m_theme_choice; }; diff --git a/Source/Core/DolphinWX/Config/PathConfigPane.cpp b/Source/Core/DolphinWX/Config/PathConfigPane.cpp index 4c4ad7909d..5dcdd9f4f7 100644 --- a/Source/Core/DolphinWX/Config/PathConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/PathConfigPane.cpp @@ -17,181 +17,193 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "DiscIO/NANDContentLoader.h" +#include "DolphinWX/Config/ConfigMain.h" +#include "DolphinWX/Config/PathConfigPane.h" #include "DolphinWX/Frame.h" #include "DolphinWX/Main.h" #include "DolphinWX/WxUtils.h" -#include "DolphinWX/Config/ConfigMain.h" -#include "DolphinWX/Config/PathConfigPane.h" -PathConfigPane::PathConfigPane(wxWindow* panel, wxWindowID id) - : wxPanel(panel, id) +PathConfigPane::PathConfigPane(wxWindow* panel, wxWindowID id) : wxPanel(panel, id) { - InitializeGUI(); - LoadGUIValues(); - RefreshGUI(); + InitializeGUI(); + LoadGUIValues(); + RefreshGUI(); } void PathConfigPane::InitializeGUI() { - m_iso_paths_listbox = new wxListBox(this, wxID_ANY); - m_recursive_iso_paths_checkbox = new wxCheckBox(this, wxID_ANY, _("Search Subfolders")); - m_add_iso_path_button = new wxButton(this, wxID_ANY, _("Add...")); - m_remove_iso_path_button = new wxButton(this, wxID_ANY, _("Remove")); - m_remove_iso_path_button->Disable(); + m_iso_paths_listbox = new wxListBox(this, wxID_ANY); + m_recursive_iso_paths_checkbox = new wxCheckBox(this, wxID_ANY, _("Search Subfolders")); + m_add_iso_path_button = new wxButton(this, wxID_ANY, _("Add...")); + m_remove_iso_path_button = new wxButton(this, wxID_ANY, _("Remove")); + m_remove_iso_path_button->Disable(); - m_default_iso_filepicker = new wxFilePickerCtrl(this, wxID_ANY, wxEmptyString, _("Choose a default ISO:"), - _("All GC/Wii files (elf, dol, gcm, iso, wbfs, ciso, gcz, wad)") + wxString::Format("|*.elf;*.dol;*.gcm;*.iso;*.wbfs;*.ciso;*.gcz;*.wad|%s", wxGetTranslation(wxALL_FILES)), - wxDefaultPosition, wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN | wxFLP_SMALL); - m_dvd_root_dirpicker = new wxDirPickerCtrl(this, wxID_ANY, wxEmptyString, _("Choose a DVD root directory:"), wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL | wxDIRP_SMALL); - m_apploader_path_filepicker = new wxFilePickerCtrl(this, wxID_ANY, wxEmptyString, _("Choose file to use as apploader: (applies to discs constructed from directories only)"), - _("apploader (.img)") + wxString::Format("|*.img|%s", wxGetTranslation(wxALL_FILES)), - wxDefaultPosition, wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN | wxFLP_SMALL); - m_nand_root_dirpicker = new wxDirPickerCtrl(this, wxID_ANY, wxEmptyString, _("Choose a NAND root directory:"), wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL | wxDIRP_SMALL); + m_default_iso_filepicker = new wxFilePickerCtrl( + this, wxID_ANY, wxEmptyString, _("Choose a default ISO:"), + _("All GC/Wii files (elf, dol, gcm, iso, wbfs, ciso, gcz, wad)") + + wxString::Format("|*.elf;*.dol;*.gcm;*.iso;*.wbfs;*.ciso;*.gcz;*.wad|%s", + wxGetTranslation(wxALL_FILES)), + wxDefaultPosition, wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN | wxFLP_SMALL); + m_dvd_root_dirpicker = + new wxDirPickerCtrl(this, wxID_ANY, wxEmptyString, _("Choose a DVD root directory:"), + wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL | wxDIRP_SMALL); + m_apploader_path_filepicker = new wxFilePickerCtrl( + this, wxID_ANY, wxEmptyString, + _("Choose file to use as apploader: (applies to discs constructed from directories only)"), + _("apploader (.img)") + wxString::Format("|*.img|%s", wxGetTranslation(wxALL_FILES)), + wxDefaultPosition, wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN | wxFLP_SMALL); + m_nand_root_dirpicker = + new wxDirPickerCtrl(this, wxID_ANY, wxEmptyString, _("Choose a NAND root directory:"), + wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL | wxDIRP_SMALL); - m_iso_paths_listbox->Bind(wxEVT_LISTBOX, &PathConfigPane::OnISOPathSelectionChanged, this); - m_recursive_iso_paths_checkbox->Bind(wxEVT_CHECKBOX, &PathConfigPane::OnRecursiveISOCheckBoxChanged, this); - m_add_iso_path_button->Bind(wxEVT_BUTTON, &PathConfigPane::OnAddISOPath, this); - m_remove_iso_path_button->Bind(wxEVT_BUTTON, &PathConfigPane::OnRemoveISOPath, this); - m_default_iso_filepicker->Bind(wxEVT_FILEPICKER_CHANGED, &PathConfigPane::OnDefaultISOChanged, this); - m_dvd_root_dirpicker->Bind(wxEVT_DIRPICKER_CHANGED, &PathConfigPane::OnDVDRootChanged, this); - m_apploader_path_filepicker->Bind(wxEVT_FILEPICKER_CHANGED, &PathConfigPane::OnApploaderPathChanged, this); - m_nand_root_dirpicker->Bind(wxEVT_DIRPICKER_CHANGED, &PathConfigPane::OnNANDRootChanged, this); + m_iso_paths_listbox->Bind(wxEVT_LISTBOX, &PathConfigPane::OnISOPathSelectionChanged, this); + m_recursive_iso_paths_checkbox->Bind(wxEVT_CHECKBOX, + &PathConfigPane::OnRecursiveISOCheckBoxChanged, this); + m_add_iso_path_button->Bind(wxEVT_BUTTON, &PathConfigPane::OnAddISOPath, this); + m_remove_iso_path_button->Bind(wxEVT_BUTTON, &PathConfigPane::OnRemoveISOPath, this); + m_default_iso_filepicker->Bind(wxEVT_FILEPICKER_CHANGED, &PathConfigPane::OnDefaultISOChanged, + this); + m_dvd_root_dirpicker->Bind(wxEVT_DIRPICKER_CHANGED, &PathConfigPane::OnDVDRootChanged, this); + m_apploader_path_filepicker->Bind(wxEVT_FILEPICKER_CHANGED, + &PathConfigPane::OnApploaderPathChanged, this); + m_nand_root_dirpicker->Bind(wxEVT_DIRPICKER_CHANGED, &PathConfigPane::OnNANDRootChanged, this); - wxBoxSizer* const iso_button_sizer = new wxBoxSizer(wxHORIZONTAL); - iso_button_sizer->Add(m_recursive_iso_paths_checkbox, 0, wxALL | wxALIGN_CENTER); - iso_button_sizer->AddStretchSpacer(); - iso_button_sizer->Add(m_add_iso_path_button, 0, wxALL); - iso_button_sizer->Add(m_remove_iso_path_button, 0, wxALL); + wxBoxSizer* const iso_button_sizer = new wxBoxSizer(wxHORIZONTAL); + iso_button_sizer->Add(m_recursive_iso_paths_checkbox, 0, wxALL | wxALIGN_CENTER); + iso_button_sizer->AddStretchSpacer(); + iso_button_sizer->Add(m_add_iso_path_button, 0, wxALL); + iso_button_sizer->Add(m_remove_iso_path_button, 0, wxALL); - wxStaticBoxSizer* const iso_listbox_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("ISO Directories")); - iso_listbox_sizer->Add(m_iso_paths_listbox, 1, wxEXPAND | wxALL, 0); - iso_listbox_sizer->Add(iso_button_sizer, 0, wxEXPAND | wxALL, 5); + wxStaticBoxSizer* const iso_listbox_sizer = + new wxStaticBoxSizer(wxVERTICAL, this, _("ISO Directories")); + iso_listbox_sizer->Add(m_iso_paths_listbox, 1, wxEXPAND | wxALL, 0); + iso_listbox_sizer->Add(iso_button_sizer, 0, wxEXPAND | wxALL, 5); - wxGridBagSizer* const picker_sizer = new wxGridBagSizer(); - picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Default ISO:")), - wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); - picker_sizer->Add(m_default_iso_filepicker, wxGBPosition(0, 1), wxDefaultSpan, wxEXPAND | wxALL, 5); - picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("DVD Root:")), - wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); - picker_sizer->Add(m_dvd_root_dirpicker, wxGBPosition(1, 1), wxDefaultSpan, wxEXPAND | wxALL, 5); - picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Apploader:")), - wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); - picker_sizer->Add(m_apploader_path_filepicker, wxGBPosition(2, 1), wxDefaultSpan, wxEXPAND | wxALL, 5); - picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Wii NAND Root:")), - wxGBPosition(3, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); - picker_sizer->Add(m_nand_root_dirpicker, wxGBPosition(3, 1), wxDefaultSpan, wxEXPAND | wxALL, 5); - picker_sizer->AddGrowableCol(1); + wxGridBagSizer* const picker_sizer = new wxGridBagSizer(); + picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Default ISO:")), wxGBPosition(0, 0), + wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); + picker_sizer->Add(m_default_iso_filepicker, wxGBPosition(0, 1), wxDefaultSpan, wxEXPAND | wxALL, + 5); + picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("DVD Root:")), wxGBPosition(1, 0), + wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); + picker_sizer->Add(m_dvd_root_dirpicker, wxGBPosition(1, 1), wxDefaultSpan, wxEXPAND | wxALL, 5); + picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Apploader:")), wxGBPosition(2, 0), + wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); + picker_sizer->Add(m_apploader_path_filepicker, wxGBPosition(2, 1), wxDefaultSpan, + wxEXPAND | wxALL, 5); + picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Wii NAND Root:")), wxGBPosition(3, 0), + wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); + picker_sizer->Add(m_nand_root_dirpicker, wxGBPosition(3, 1), wxDefaultSpan, wxEXPAND | wxALL, 5); + picker_sizer->AddGrowableCol(1); - // Populate the Paths page - wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); - main_sizer->Add(iso_listbox_sizer, 1, wxEXPAND | wxALL, 5); - main_sizer->Add(picker_sizer, 0, wxEXPAND | wxALL, 5); + // Populate the Paths page + wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); + main_sizer->Add(iso_listbox_sizer, 1, wxEXPAND | wxALL, 5); + main_sizer->Add(picker_sizer, 0, wxEXPAND | wxALL, 5); - SetSizer(main_sizer); + SetSizer(main_sizer); } void PathConfigPane::LoadGUIValues() { - const SConfig& startup_params = SConfig::GetInstance(); + const SConfig& startup_params = SConfig::GetInstance(); - m_recursive_iso_paths_checkbox->SetValue(SConfig::GetInstance().m_RecursiveISOFolder); - m_default_iso_filepicker->SetPath(StrToWxStr(startup_params.m_strDefaultISO)); - m_dvd_root_dirpicker->SetPath(StrToWxStr(startup_params.m_strDVDRoot)); - m_apploader_path_filepicker->SetPath(StrToWxStr(startup_params.m_strApploader)); - m_nand_root_dirpicker->SetPath(StrToWxStr(SConfig::GetInstance().m_NANDPath)); + m_recursive_iso_paths_checkbox->SetValue(SConfig::GetInstance().m_RecursiveISOFolder); + m_default_iso_filepicker->SetPath(StrToWxStr(startup_params.m_strDefaultISO)); + m_dvd_root_dirpicker->SetPath(StrToWxStr(startup_params.m_strDVDRoot)); + m_apploader_path_filepicker->SetPath(StrToWxStr(startup_params.m_strApploader)); + m_nand_root_dirpicker->SetPath(StrToWxStr(SConfig::GetInstance().m_NANDPath)); - // Update selected ISO paths - for (const std::string& folder : SConfig::GetInstance().m_ISOFolder) - m_iso_paths_listbox->Append(StrToWxStr(folder)); + // Update selected ISO paths + for (const std::string& folder : SConfig::GetInstance().m_ISOFolder) + m_iso_paths_listbox->Append(StrToWxStr(folder)); } void PathConfigPane::RefreshGUI() { - if (Core::IsRunning()) - Disable(); + if (Core::IsRunning()) + Disable(); } void PathConfigPane::OnISOPathSelectionChanged(wxCommandEvent& event) { - m_remove_iso_path_button->Enable(m_iso_paths_listbox->GetSelection() != wxNOT_FOUND); + m_remove_iso_path_button->Enable(m_iso_paths_listbox->GetSelection() != wxNOT_FOUND); } void PathConfigPane::OnRecursiveISOCheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().m_RecursiveISOFolder = m_recursive_iso_paths_checkbox->IsChecked(); + SConfig::GetInstance().m_RecursiveISOFolder = m_recursive_iso_paths_checkbox->IsChecked(); - AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST)); + AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST)); } void PathConfigPane::OnAddISOPath(wxCommandEvent& event) { - wxDirDialog dialog(this, _("Choose a directory to add"), wxGetHomeDir(), - wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST); + wxDirDialog dialog(this, _("Choose a directory to add"), wxGetHomeDir(), + wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST); - if (dialog.ShowModal() == wxID_OK) - { - if (m_iso_paths_listbox->FindString(dialog.GetPath()) != wxNOT_FOUND) - { - WxUtils::ShowErrorDialog(_("The chosen directory is already in the list.")); - } - else - { - AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST)); - m_iso_paths_listbox->Append(dialog.GetPath()); - } - } + if (dialog.ShowModal() == wxID_OK) + { + if (m_iso_paths_listbox->FindString(dialog.GetPath()) != wxNOT_FOUND) + { + WxUtils::ShowErrorDialog(_("The chosen directory is already in the list.")); + } + else + { + AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST)); + m_iso_paths_listbox->Append(dialog.GetPath()); + } + } - SaveISOPathChanges(); + SaveISOPathChanges(); } void PathConfigPane::OnRemoveISOPath(wxCommandEvent& event) { - AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST)); - m_iso_paths_listbox->Delete(m_iso_paths_listbox->GetSelection()); + AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST)); + m_iso_paths_listbox->Delete(m_iso_paths_listbox->GetSelection()); - // This seems to not be activated on Windows when it should be. wxw bug? +// This seems to not be activated on Windows when it should be. wxw bug? #ifdef _WIN32 - OnISOPathSelectionChanged(wxCommandEvent()); + OnISOPathSelectionChanged(wxCommandEvent()); #endif - SaveISOPathChanges(); + SaveISOPathChanges(); } void PathConfigPane::OnDefaultISOChanged(wxCommandEvent& event) { - SConfig::GetInstance().m_strDefaultISO = WxStrToStr(m_default_iso_filepicker->GetPath()); + SConfig::GetInstance().m_strDefaultISO = WxStrToStr(m_default_iso_filepicker->GetPath()); } void PathConfigPane::OnDVDRootChanged(wxCommandEvent& event) { - SConfig::GetInstance().m_strDVDRoot = WxStrToStr(m_dvd_root_dirpicker->GetPath()); + SConfig::GetInstance().m_strDVDRoot = WxStrToStr(m_dvd_root_dirpicker->GetPath()); } void PathConfigPane::OnApploaderPathChanged(wxCommandEvent& event) { - SConfig::GetInstance().m_strApploader = WxStrToStr(m_apploader_path_filepicker->GetPath()); + SConfig::GetInstance().m_strApploader = WxStrToStr(m_apploader_path_filepicker->GetPath()); } void PathConfigPane::OnNANDRootChanged(wxCommandEvent& event) { - std::string nand_path = - SConfig::GetInstance().m_NANDPath = - WxStrToStr(m_nand_root_dirpicker->GetPath()); + std::string nand_path = SConfig::GetInstance().m_NANDPath = + WxStrToStr(m_nand_root_dirpicker->GetPath()); - File::SetUserPath(D_WIIROOT_IDX, nand_path); - m_nand_root_dirpicker->SetPath(StrToWxStr(nand_path)); + File::SetUserPath(D_WIIROOT_IDX, nand_path); + m_nand_root_dirpicker->SetPath(StrToWxStr(nand_path)); - SConfig::GetInstance().m_SYSCONF->UpdateLocation(); - DiscIO::CNANDContentManager::Access().ClearCache(); + SConfig::GetInstance().m_SYSCONF->UpdateLocation(); + DiscIO::CNANDContentManager::Access().ClearCache(); - main_frame->UpdateWiiMenuChoice(); + main_frame->UpdateWiiMenuChoice(); } void PathConfigPane::SaveISOPathChanges() { - SConfig::GetInstance().m_ISOFolder.clear(); + SConfig::GetInstance().m_ISOFolder.clear(); - for (unsigned int i = 0; i < m_iso_paths_listbox->GetCount(); i++) - SConfig::GetInstance().m_ISOFolder.push_back(WxStrToStr(m_iso_paths_listbox->GetStrings()[i])); + for (unsigned int i = 0; i < m_iso_paths_listbox->GetCount(); i++) + SConfig::GetInstance().m_ISOFolder.push_back(WxStrToStr(m_iso_paths_listbox->GetStrings()[i])); } - diff --git a/Source/Core/DolphinWX/Config/PathConfigPane.h b/Source/Core/DolphinWX/Config/PathConfigPane.h index 3c46bcc206..f726506f17 100644 --- a/Source/Core/DolphinWX/Config/PathConfigPane.h +++ b/Source/Core/DolphinWX/Config/PathConfigPane.h @@ -15,31 +15,31 @@ class wxFilePickerCtrl; class PathConfigPane final : public wxPanel { public: - PathConfigPane(wxWindow* parent, wxWindowID id); + PathConfigPane(wxWindow* parent, wxWindowID id); private: - void InitializeGUI(); - void LoadGUIValues(); - void RefreshGUI(); + void InitializeGUI(); + void LoadGUIValues(); + void RefreshGUI(); - void OnISOPathSelectionChanged(wxCommandEvent&); - void OnRecursiveISOCheckBoxChanged(wxCommandEvent&); - void OnAddISOPath(wxCommandEvent&); - void OnRemoveISOPath(wxCommandEvent&); - void OnDefaultISOChanged(wxCommandEvent&); - void OnDVDRootChanged(wxCommandEvent&); - void OnApploaderPathChanged(wxCommandEvent&); - void OnNANDRootChanged(wxCommandEvent&); + void OnISOPathSelectionChanged(wxCommandEvent&); + void OnRecursiveISOCheckBoxChanged(wxCommandEvent&); + void OnAddISOPath(wxCommandEvent&); + void OnRemoveISOPath(wxCommandEvent&); + void OnDefaultISOChanged(wxCommandEvent&); + void OnDVDRootChanged(wxCommandEvent&); + void OnApploaderPathChanged(wxCommandEvent&); + void OnNANDRootChanged(wxCommandEvent&); - void SaveISOPathChanges(); + void SaveISOPathChanges(); - wxListBox* m_iso_paths_listbox; - wxCheckBox* m_recursive_iso_paths_checkbox; - wxButton* m_add_iso_path_button; - wxButton* m_remove_iso_path_button; + wxListBox* m_iso_paths_listbox; + wxCheckBox* m_recursive_iso_paths_checkbox; + wxButton* m_add_iso_path_button; + wxButton* m_remove_iso_path_button; - wxDirPickerCtrl* m_dvd_root_dirpicker; - wxDirPickerCtrl* m_nand_root_dirpicker; - wxFilePickerCtrl* m_default_iso_filepicker; - wxFilePickerCtrl* m_apploader_path_filepicker; + wxDirPickerCtrl* m_dvd_root_dirpicker; + wxDirPickerCtrl* m_nand_root_dirpicker; + wxFilePickerCtrl* m_default_iso_filepicker; + wxFilePickerCtrl* m_apploader_path_filepicker; }; diff --git a/Source/Core/DolphinWX/Config/WiiConfigPane.cpp b/Source/Core/DolphinWX/Config/WiiConfigPane.cpp index 6ab2814585..d162f12abb 100644 --- a/Source/Core/DolphinWX/Config/WiiConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/WiiConfigPane.cpp @@ -12,163 +12,176 @@ #include "Core/Core.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" #include "DiscIO/Volume.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Config/WiiConfigPane.h" +#include "DolphinWX/WxUtils.h" -WiiConfigPane::WiiConfigPane(wxWindow* parent, wxWindowID id) - : wxPanel(parent, id) +WiiConfigPane::WiiConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id) { - InitializeGUI(); - LoadGUIValues(); - RefreshGUI(); + InitializeGUI(); + LoadGUIValues(); + RefreshGUI(); } void WiiConfigPane::InitializeGUI() { - m_aspect_ratio_strings.Add("4:3"); - m_aspect_ratio_strings.Add("16:9"); + m_aspect_ratio_strings.Add("4:3"); + m_aspect_ratio_strings.Add("16:9"); - m_system_language_strings.Add(_("Japanese")); - m_system_language_strings.Add(_("English")); - m_system_language_strings.Add(_("German")); - m_system_language_strings.Add(_("French")); - m_system_language_strings.Add(_("Spanish")); - m_system_language_strings.Add(_("Italian")); - m_system_language_strings.Add(_("Dutch")); - m_system_language_strings.Add(_("Simplified Chinese")); - m_system_language_strings.Add(_("Traditional Chinese")); - m_system_language_strings.Add(_("Korean")); + m_system_language_strings.Add(_("Japanese")); + m_system_language_strings.Add(_("English")); + m_system_language_strings.Add(_("German")); + m_system_language_strings.Add(_("French")); + m_system_language_strings.Add(_("Spanish")); + m_system_language_strings.Add(_("Italian")); + m_system_language_strings.Add(_("Dutch")); + m_system_language_strings.Add(_("Simplified Chinese")); + m_system_language_strings.Add(_("Traditional Chinese")); + m_system_language_strings.Add(_("Korean")); - m_screensaver_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Screen Saver")); - m_pal60_mode_checkbox = new wxCheckBox(this, wxID_ANY, _("Use PAL60 Mode (EuRGB60)")); - m_aspect_ratio_choice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_aspect_ratio_strings); - m_system_language_choice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_system_language_strings); - m_sd_card_checkbox = new wxCheckBox(this, wxID_ANY, _("Insert SD Card")); - m_connect_keyboard_checkbox = new wxCheckBox(this, wxID_ANY, _("Connect USB Keyboard")); + m_screensaver_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Screen Saver")); + m_pal60_mode_checkbox = new wxCheckBox(this, wxID_ANY, _("Use PAL60 Mode (EuRGB60)")); + m_aspect_ratio_choice = + new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_aspect_ratio_strings); + m_system_language_choice = + new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_system_language_strings); + m_sd_card_checkbox = new wxCheckBox(this, wxID_ANY, _("Insert SD Card")); + m_connect_keyboard_checkbox = new wxCheckBox(this, wxID_ANY, _("Connect USB Keyboard")); - m_screensaver_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnScreenSaverCheckBoxChanged, this); - m_pal60_mode_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnPAL60CheckBoxChanged, this); - m_aspect_ratio_choice->Bind(wxEVT_CHOICE, &WiiConfigPane::OnAspectRatioChoiceChanged, this); - m_system_language_choice->Bind(wxEVT_CHOICE, &WiiConfigPane::OnSystemLanguageChoiceChanged, this); - m_sd_card_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnSDCardCheckBoxChanged, this); - m_connect_keyboard_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnConnectKeyboardCheckBoxChanged, this); + m_screensaver_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnScreenSaverCheckBoxChanged, this); + m_pal60_mode_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnPAL60CheckBoxChanged, this); + m_aspect_ratio_choice->Bind(wxEVT_CHOICE, &WiiConfigPane::OnAspectRatioChoiceChanged, this); + m_system_language_choice->Bind(wxEVT_CHOICE, &WiiConfigPane::OnSystemLanguageChoiceChanged, this); + m_sd_card_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnSDCardCheckBoxChanged, this); + m_connect_keyboard_checkbox->Bind(wxEVT_CHECKBOX, + &WiiConfigPane::OnConnectKeyboardCheckBoxChanged, this); - m_screensaver_checkbox->SetToolTip(_("Dims the screen after five minutes of inactivity.")); - m_pal60_mode_checkbox->SetToolTip(_("Sets the Wii display mode to 60Hz (480i) instead of 50Hz (576i) for PAL games.\nMay not work for all games.")); - m_system_language_choice->SetToolTip(_("Sets the Wii system language.")); - m_sd_card_checkbox->SetToolTip(_("Saved to /Wii/sd.raw (default size is 128mb)")); - m_connect_keyboard_checkbox->SetToolTip(_("May cause slow down in Wii Menu and some games.")); + m_screensaver_checkbox->SetToolTip(_("Dims the screen after five minutes of inactivity.")); + m_pal60_mode_checkbox->SetToolTip(_("Sets the Wii display mode to 60Hz (480i) instead of 50Hz " + "(576i) for PAL games.\nMay not work for all games.")); + m_system_language_choice->SetToolTip(_("Sets the Wii system language.")); + m_sd_card_checkbox->SetToolTip(_("Saved to /Wii/sd.raw (default size is 128mb)")); + m_connect_keyboard_checkbox->SetToolTip(_("May cause slow down in Wii Menu and some games.")); - wxGridBagSizer* const misc_settings_grid_sizer = new wxGridBagSizer(); - misc_settings_grid_sizer->Add(m_screensaver_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2), wxALL, 5); - misc_settings_grid_sizer->Add(m_pal60_mode_checkbox, wxGBPosition(1, 0), wxGBSpan(1, 2), wxALL, 5); - misc_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Aspect Ratio:")), wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); - misc_settings_grid_sizer->Add(m_aspect_ratio_choice, wxGBPosition(2, 1), wxDefaultSpan, wxALL, 5); - misc_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("System Language:")), wxGBPosition(3, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); - misc_settings_grid_sizer->Add(m_system_language_choice, wxGBPosition(3, 1), wxDefaultSpan, wxALL, 5); + wxGridBagSizer* const misc_settings_grid_sizer = new wxGridBagSizer(); + misc_settings_grid_sizer->Add(m_screensaver_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2), wxALL, + 5); + misc_settings_grid_sizer->Add(m_pal60_mode_checkbox, wxGBPosition(1, 0), wxGBSpan(1, 2), wxALL, + 5); + misc_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Aspect Ratio:")), + wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, + 5); + misc_settings_grid_sizer->Add(m_aspect_ratio_choice, wxGBPosition(2, 1), wxDefaultSpan, wxALL, 5); + misc_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("System Language:")), + wxGBPosition(3, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, + 5); + misc_settings_grid_sizer->Add(m_system_language_choice, wxGBPosition(3, 1), wxDefaultSpan, wxALL, + 5); - wxStaticBoxSizer* const misc_settings_static_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Misc Settings")); - misc_settings_static_sizer->Add(misc_settings_grid_sizer); + wxStaticBoxSizer* const misc_settings_static_sizer = + new wxStaticBoxSizer(wxVERTICAL, this, _("Misc Settings")); + misc_settings_static_sizer->Add(misc_settings_grid_sizer); - wxStaticBoxSizer* const device_settings_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Device Settings")); - device_settings_sizer->Add(m_sd_card_checkbox, 0, wxALL, 5); - device_settings_sizer->Add(m_connect_keyboard_checkbox, 0, wxALL, 5); + wxStaticBoxSizer* const device_settings_sizer = + new wxStaticBoxSizer(wxVERTICAL, this, _("Device Settings")); + device_settings_sizer->Add(m_sd_card_checkbox, 0, wxALL, 5); + device_settings_sizer->Add(m_connect_keyboard_checkbox, 0, wxALL, 5); - wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); - main_sizer->Add(misc_settings_static_sizer, 0, wxEXPAND | wxALL, 5); - main_sizer->Add(device_settings_sizer, 0, wxEXPAND | wxALL, 5); + wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); + main_sizer->Add(misc_settings_static_sizer, 0, wxEXPAND | wxALL, 5); + main_sizer->Add(device_settings_sizer, 0, wxEXPAND | wxALL, 5); - SetSizer(main_sizer); + SetSizer(main_sizer); } void WiiConfigPane::LoadGUIValues() { - m_screensaver_checkbox->SetValue(!!SConfig::GetInstance().m_SYSCONF->GetData("IPL.SSV")); - m_pal60_mode_checkbox->SetValue(SConfig::GetInstance().bPAL60); - m_aspect_ratio_choice->SetSelection(SConfig::GetInstance().m_SYSCONF->GetData("IPL.AR")); - m_system_language_choice->SetSelection(SConfig::GetInstance().m_SYSCONF->GetData("IPL.LNG")); + m_screensaver_checkbox->SetValue(!!SConfig::GetInstance().m_SYSCONF->GetData("IPL.SSV")); + m_pal60_mode_checkbox->SetValue(SConfig::GetInstance().bPAL60); + m_aspect_ratio_choice->SetSelection(SConfig::GetInstance().m_SYSCONF->GetData("IPL.AR")); + m_system_language_choice->SetSelection(SConfig::GetInstance().m_SYSCONF->GetData("IPL.LNG")); - m_sd_card_checkbox->SetValue(SConfig::GetInstance().m_WiiSDCard); - m_connect_keyboard_checkbox->SetValue(SConfig::GetInstance().m_WiiKeyboard); + m_sd_card_checkbox->SetValue(SConfig::GetInstance().m_WiiSDCard); + m_connect_keyboard_checkbox->SetValue(SConfig::GetInstance().m_WiiKeyboard); } void WiiConfigPane::RefreshGUI() { - if (Core::IsRunning()) - { - m_screensaver_checkbox->Disable(); - m_pal60_mode_checkbox->Disable(); - m_aspect_ratio_choice->Disable(); - m_system_language_choice->Disable(); - } + if (Core::IsRunning()) + { + m_screensaver_checkbox->Disable(); + m_pal60_mode_checkbox->Disable(); + m_aspect_ratio_choice->Disable(); + m_system_language_choice->Disable(); + } } void WiiConfigPane::OnScreenSaverCheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().m_SYSCONF->SetData("IPL.SSV", m_screensaver_checkbox->IsChecked()); + SConfig::GetInstance().m_SYSCONF->SetData("IPL.SSV", m_screensaver_checkbox->IsChecked()); } void WiiConfigPane::OnPAL60CheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().bPAL60 = m_pal60_mode_checkbox->IsChecked(); - SConfig::GetInstance().m_SYSCONF->SetData("IPL.E60", m_pal60_mode_checkbox->IsChecked()); + SConfig::GetInstance().bPAL60 = m_pal60_mode_checkbox->IsChecked(); + SConfig::GetInstance().m_SYSCONF->SetData("IPL.E60", m_pal60_mode_checkbox->IsChecked()); } void WiiConfigPane::OnSDCardCheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().m_WiiSDCard = m_sd_card_checkbox->IsChecked(); - WII_IPC_HLE_Interface::SDIO_EventNotify(); + SConfig::GetInstance().m_WiiSDCard = m_sd_card_checkbox->IsChecked(); + WII_IPC_HLE_Interface::SDIO_EventNotify(); } void WiiConfigPane::OnConnectKeyboardCheckBoxChanged(wxCommandEvent& event) { - SConfig::GetInstance().m_WiiKeyboard = m_connect_keyboard_checkbox->IsChecked(); + SConfig::GetInstance().m_WiiKeyboard = m_connect_keyboard_checkbox->IsChecked(); } void WiiConfigPane::OnSystemLanguageChoiceChanged(wxCommandEvent& event) { - DiscIO::IVolume::ELanguage wii_system_lang = (DiscIO::IVolume::ELanguage)m_system_language_choice->GetSelection(); - SConfig::GetInstance().m_SYSCONF->SetData("IPL.LNG", wii_system_lang); - u8 country_code = GetSADRCountryCode(wii_system_lang); + DiscIO::IVolume::ELanguage wii_system_lang = + (DiscIO::IVolume::ELanguage)m_system_language_choice->GetSelection(); + SConfig::GetInstance().m_SYSCONF->SetData("IPL.LNG", wii_system_lang); + u8 country_code = GetSADRCountryCode(wii_system_lang); - if (!SConfig::GetInstance().m_SYSCONF->SetArrayData("IPL.SADR", &country_code, 1)) - WxUtils::ShowErrorDialog(_("Failed to update country code in SYSCONF")); + if (!SConfig::GetInstance().m_SYSCONF->SetArrayData("IPL.SADR", &country_code, 1)) + WxUtils::ShowErrorDialog(_("Failed to update country code in SYSCONF")); } void WiiConfigPane::OnAspectRatioChoiceChanged(wxCommandEvent& event) { - SConfig::GetInstance().m_SYSCONF->SetData("IPL.AR", m_aspect_ratio_choice->GetSelection()); + SConfig::GetInstance().m_SYSCONF->SetData("IPL.AR", m_aspect_ratio_choice->GetSelection()); } // Change from IPL.LNG value to IPL.SADR country code. // http://wiibrew.org/wiki/Country_Codes u8 WiiConfigPane::GetSADRCountryCode(DiscIO::IVolume::ELanguage language) { - switch (language) - { - case DiscIO::IVolume::LANGUAGE_JAPANESE: - return 1; // Japan - case DiscIO::IVolume::LANGUAGE_ENGLISH: - return 49; // USA - case DiscIO::IVolume::LANGUAGE_GERMAN: - return 78; // Germany - case DiscIO::IVolume::LANGUAGE_FRENCH: - return 77; // France - case DiscIO::IVolume::LANGUAGE_SPANISH: - return 105; // Spain - case DiscIO::IVolume::LANGUAGE_ITALIAN: - return 83; // Italy - case DiscIO::IVolume::LANGUAGE_DUTCH: - return 94; // Netherlands - case DiscIO::IVolume::LANGUAGE_SIMPLIFIED_CHINESE: - case DiscIO::IVolume::LANGUAGE_TRADITIONAL_CHINESE: - return 157; // China - case DiscIO::IVolume::LANGUAGE_KOREAN: - return 136; // Korea - case DiscIO::IVolume::LANGUAGE_UNKNOWN: - break; - } + switch (language) + { + case DiscIO::IVolume::LANGUAGE_JAPANESE: + return 1; // Japan + case DiscIO::IVolume::LANGUAGE_ENGLISH: + return 49; // USA + case DiscIO::IVolume::LANGUAGE_GERMAN: + return 78; // Germany + case DiscIO::IVolume::LANGUAGE_FRENCH: + return 77; // France + case DiscIO::IVolume::LANGUAGE_SPANISH: + return 105; // Spain + case DiscIO::IVolume::LANGUAGE_ITALIAN: + return 83; // Italy + case DiscIO::IVolume::LANGUAGE_DUTCH: + return 94; // Netherlands + case DiscIO::IVolume::LANGUAGE_SIMPLIFIED_CHINESE: + case DiscIO::IVolume::LANGUAGE_TRADITIONAL_CHINESE: + return 157; // China + case DiscIO::IVolume::LANGUAGE_KOREAN: + return 136; // Korea + case DiscIO::IVolume::LANGUAGE_UNKNOWN: + break; + } - PanicAlert("Invalid language. Defaulting to Japanese."); - return 1; + PanicAlert("Invalid language. Defaulting to Japanese."); + return 1; } diff --git a/Source/Core/DolphinWX/Config/WiiConfigPane.h b/Source/Core/DolphinWX/Config/WiiConfigPane.h index 2793f6629b..a2c7e865d3 100644 --- a/Source/Core/DolphinWX/Config/WiiConfigPane.h +++ b/Source/Core/DolphinWX/Config/WiiConfigPane.h @@ -15,29 +15,29 @@ class wxChoice; class WiiConfigPane final : public wxPanel { public: - WiiConfigPane(wxWindow* parent, wxWindowID id); + WiiConfigPane(wxWindow* parent, wxWindowID id); private: - void InitializeGUI(); - void LoadGUIValues(); - void RefreshGUI(); + void InitializeGUI(); + void LoadGUIValues(); + void RefreshGUI(); - void OnScreenSaverCheckBoxChanged(wxCommandEvent&); - void OnPAL60CheckBoxChanged(wxCommandEvent&); - void OnSDCardCheckBoxChanged(wxCommandEvent&); - void OnConnectKeyboardCheckBoxChanged(wxCommandEvent&); - void OnSystemLanguageChoiceChanged(wxCommandEvent&); - void OnAspectRatioChoiceChanged(wxCommandEvent&); + void OnScreenSaverCheckBoxChanged(wxCommandEvent&); + void OnPAL60CheckBoxChanged(wxCommandEvent&); + void OnSDCardCheckBoxChanged(wxCommandEvent&); + void OnConnectKeyboardCheckBoxChanged(wxCommandEvent&); + void OnSystemLanguageChoiceChanged(wxCommandEvent&); + void OnAspectRatioChoiceChanged(wxCommandEvent&); - static u8 GetSADRCountryCode(DiscIO::IVolume::ELanguage language); + static u8 GetSADRCountryCode(DiscIO::IVolume::ELanguage language); - wxArrayString m_system_language_strings; - wxArrayString m_aspect_ratio_strings; + wxArrayString m_system_language_strings; + wxArrayString m_aspect_ratio_strings; - wxCheckBox* m_screensaver_checkbox; - wxCheckBox* m_pal60_mode_checkbox; - wxCheckBox* m_sd_card_checkbox; - wxCheckBox* m_connect_keyboard_checkbox; - wxChoice* m_system_language_choice; - wxChoice* m_aspect_ratio_choice; + wxCheckBox* m_screensaver_checkbox; + wxCheckBox* m_pal60_mode_checkbox; + wxCheckBox* m_sd_card_checkbox; + wxCheckBox* m_connect_keyboard_checkbox; + wxChoice* m_system_language_choice; + wxChoice* m_aspect_ratio_choice; }; diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.cpp b/Source/Core/DolphinWX/ControllerConfigDiag.cpp index c8e80510d8..8a0de34024 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.cpp +++ b/Source/Core/DolphinWX/ControllerConfigDiag.cpp @@ -20,17 +20,17 @@ #include "Common/SysConf.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/HotkeyManager.h" -#include "Core/Movie.h" -#include "Core/NetPlayProto.h" #include "Core/HW/GCKeyboard.h" #include "Core/HW/GCPad.h" #include "Core/HW/SI.h" #include "Core/HW/Wiimote.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" +#include "Core/HotkeyManager.h" +#include "Core/Movie.h" +#include "Core/NetPlayProto.h" +#include "DolphinWX/Config/GCAdapterConfigDiag.h" #include "DolphinWX/ControllerConfigDiag.h" #include "DolphinWX/InputConfigDiag.h" -#include "DolphinWX/Config/GCAdapterConfigDiag.h" #include "InputCommon/GCAdapter.h" #if defined(HAVE_XRANDR) && HAVE_XRANDR @@ -38,487 +38,499 @@ #endif ControllerConfigDiag::ControllerConfigDiag(wxWindow* const parent) - : wxDialog(parent, wxID_ANY, _("Dolphin Controller Configuration")) + : wxDialog(parent, wxID_ANY, _("Dolphin Controller Configuration")) { - m_gc_pad_type_strs = {{ - _("None"), - _("Standard Controller"), - _("GameCube Adapter for Wii U"), - _("Steering Wheel"), - _("Dance Mat"), - _("DK Bongos"), - _("GBA"), - _("Keyboard"), - _("AM Baseboard") - }}; + m_gc_pad_type_strs = {{_("None"), _("Standard Controller"), _("GameCube Adapter for Wii U"), + _("Steering Wheel"), _("Dance Mat"), _("DK Bongos"), _("GBA"), + _("Keyboard"), _("AM Baseboard")}}; - wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL); - // Combine all UI controls into their own encompassing sizer. - wxBoxSizer* control_sizer = new wxBoxSizer(wxVERTICAL); - control_sizer->Add(CreateGamecubeSizer(), 0, wxEXPAND | wxALL, 5); - control_sizer->Add(CreateWiimoteConfigSizer(), 0, wxEXPAND | wxALL, 5); + // Combine all UI controls into their own encompassing sizer. + wxBoxSizer* control_sizer = new wxBoxSizer(wxVERTICAL); + control_sizer->Add(CreateGamecubeSizer(), 0, wxEXPAND | wxALL, 5); + control_sizer->Add(CreateWiimoteConfigSizer(), 0, wxEXPAND | wxALL, 5); - main_sizer->Add(control_sizer, 0, wxEXPAND); - main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + main_sizer->Add(control_sizer, 0, wxEXPAND); + main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - Bind(wxEVT_BUTTON, &ControllerConfigDiag::Save, this, wxID_OK); - Bind(wxEVT_BUTTON, &ControllerConfigDiag::Cancel, this, wxID_CANCEL); + Bind(wxEVT_BUTTON, &ControllerConfigDiag::Save, this, wxID_OK); + Bind(wxEVT_BUTTON, &ControllerConfigDiag::Cancel, this, wxID_CANCEL); - SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED); - SetSizerAndFit(main_sizer); - Center(); + SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED); + SetSizerAndFit(main_sizer); + Center(); } wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() { - wxStaticBoxSizer* const gamecube_static_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("GameCube Controllers")); - wxFlexGridSizer* const gamecube_flex_sizer = new wxFlexGridSizer(3, 5, 5); + wxStaticBoxSizer* const gamecube_static_sizer = + new wxStaticBoxSizer(wxVERTICAL, this, _("GameCube Controllers")); + wxFlexGridSizer* const gamecube_flex_sizer = new wxFlexGridSizer(3, 5, 5); - wxStaticText* pad_labels[4]; - wxChoice* pad_type_choices[4]; + wxStaticText* pad_labels[4]; + wxChoice* pad_type_choices[4]; - for (int i = 0; i < 4; i++) - { - pad_labels[i] = new wxStaticText(this, wxID_ANY, wxString::Format(_("Port %i"), i + 1)); + for (int i = 0; i < 4; i++) + { + pad_labels[i] = new wxStaticText(this, wxID_ANY, wxString::Format(_("Port %i"), i + 1)); - // Create an ID for the config button. - const wxWindowID button_id = wxWindow::NewControlId(); - m_gc_port_config_ids.emplace(button_id, i); - gamecube_configure_bt[i] = new wxButton(this, button_id, _("Configure"), wxDefaultPosition, wxSize(100, 25)); - gamecube_configure_bt[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnGameCubeConfigButton, this); + // Create an ID for the config button. + const wxWindowID button_id = wxWindow::NewControlId(); + m_gc_port_config_ids.emplace(button_id, i); + gamecube_configure_bt[i] = + new wxButton(this, button_id, _("Configure"), wxDefaultPosition, wxSize(100, 25)); + gamecube_configure_bt[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnGameCubeConfigButton, + this); - // Create a control ID for the choice boxes on the fly. - const wxWindowID choice_id = wxWindow::NewControlId(); - m_gc_port_choice_ids.emplace(choice_id, i); + // Create a control ID for the choice boxes on the fly. + const wxWindowID choice_id = wxWindow::NewControlId(); + m_gc_port_choice_ids.emplace(choice_id, i); - // Only add AM-Baseboard to the first pad. - if (i == 0) - pad_type_choices[i] = new wxChoice(this, choice_id, wxDefaultPosition, wxDefaultSize, m_gc_pad_type_strs.size(), m_gc_pad_type_strs.data()); - else - pad_type_choices[i] = new wxChoice(this, choice_id, wxDefaultPosition, wxDefaultSize, m_gc_pad_type_strs.size() - 1, m_gc_pad_type_strs.data()); + // Only add AM-Baseboard to the first pad. + if (i == 0) + pad_type_choices[i] = new wxChoice(this, choice_id, wxDefaultPosition, wxDefaultSize, + m_gc_pad_type_strs.size(), m_gc_pad_type_strs.data()); + else + pad_type_choices[i] = new wxChoice(this, choice_id, wxDefaultPosition, wxDefaultSize, + m_gc_pad_type_strs.size() - 1, m_gc_pad_type_strs.data()); - pad_type_choices[i]->Bind(wxEVT_CHOICE, &ControllerConfigDiag::OnGameCubePortChanged, this); + pad_type_choices[i]->Bind(wxEVT_CHOICE, &ControllerConfigDiag::OnGameCubePortChanged, this); - // Disable controller type selection for certain circumstances. - if (NetPlay::IsNetPlayRunning() || Movie::IsMovieActive()) - pad_type_choices[i]->Disable(); + // Disable controller type selection for certain circumstances. + if (NetPlay::IsNetPlayRunning() || Movie::IsMovieActive()) + pad_type_choices[i]->Disable(); - // Set the saved pad type as the default choice. - switch (SConfig::GetInstance().m_SIDevice[i]) - { - case SIDEVICE_GC_CONTROLLER: - pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[1]); - break; - case SIDEVICE_WIIU_ADAPTER: - pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[2]); - break; - case SIDEVICE_GC_STEERING: - pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[3]); - break; - case SIDEVICE_DANCEMAT: - pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[4]); - break; - case SIDEVICE_GC_TARUKONGA: - pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[5]); - break; - case SIDEVICE_GC_GBA: - pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[6]); - gamecube_configure_bt[i]->Disable(); - break; - case SIDEVICE_GC_KEYBOARD: - pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[7]); - break; - case SIDEVICE_AM_BASEBOARD: - pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[8]); - break; - default: - pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[0]); - gamecube_configure_bt[i]->Disable(); - break; - } + // Set the saved pad type as the default choice. + switch (SConfig::GetInstance().m_SIDevice[i]) + { + case SIDEVICE_GC_CONTROLLER: + pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[1]); + break; + case SIDEVICE_WIIU_ADAPTER: + pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[2]); + break; + case SIDEVICE_GC_STEERING: + pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[3]); + break; + case SIDEVICE_DANCEMAT: + pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[4]); + break; + case SIDEVICE_GC_TARUKONGA: + pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[5]); + break; + case SIDEVICE_GC_GBA: + pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[6]); + gamecube_configure_bt[i]->Disable(); + break; + case SIDEVICE_GC_KEYBOARD: + pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[7]); + break; + case SIDEVICE_AM_BASEBOARD: + pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[8]); + break; + default: + pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[0]); + gamecube_configure_bt[i]->Disable(); + break; + } - // Add to the sizer - gamecube_flex_sizer->Add(pad_labels[i], 0, wxALIGN_CENTER_VERTICAL); - gamecube_flex_sizer->Add(pad_type_choices[i], 0, wxALIGN_CENTER_VERTICAL); - gamecube_flex_sizer->Add(gamecube_configure_bt[i], 1, wxEXPAND); - } + // Add to the sizer + gamecube_flex_sizer->Add(pad_labels[i], 0, wxALIGN_CENTER_VERTICAL); + gamecube_flex_sizer->Add(pad_type_choices[i], 0, wxALIGN_CENTER_VERTICAL); + gamecube_flex_sizer->Add(gamecube_configure_bt[i], 1, wxEXPAND); + } - gamecube_static_sizer->Add(gamecube_flex_sizer, 1, wxEXPAND, 5); - gamecube_static_sizer->AddSpacer(5); + gamecube_static_sizer->Add(gamecube_flex_sizer, 1, wxEXPAND, 5); + gamecube_static_sizer->AddSpacer(5); - return gamecube_static_sizer; + return gamecube_static_sizer; } wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer() { - wxStaticText* wiimote_label[4]; - wxChoice* wiimote_source_ch[4]; + wxStaticText* wiimote_label[4]; + wxChoice* wiimote_source_ch[4]; - for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) - { - wxString wiimote_str = wxString::Format(_("Wiimote %i"), i + 1); + for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) + { + wxString wiimote_str = wxString::Format(_("Wiimote %i"), i + 1); - static const std::array src_choices = {{ - _("None"), _("Emulated Wiimote"), _("Real Wiimote"), _("Hybrid Wiimote") - }}; + static const std::array src_choices = { + {_("None"), _("Emulated Wiimote"), _("Real Wiimote"), _("Hybrid Wiimote")}}; - // reserve four ids, so that we can calculate the index from the ids later on - // Stupid wx 2.8 doesn't support reserving sequential IDs, so we need to do that more complicated.. - int source_ctrl_id = wxWindow::NewControlId(); - m_wiimote_index_from_ctrl_id.emplace(source_ctrl_id, i); + // reserve four ids, so that we can calculate the index from the ids later on + // Stupid wx 2.8 doesn't support reserving sequential IDs, so we need to do that more + // complicated.. + int source_ctrl_id = wxWindow::NewControlId(); + m_wiimote_index_from_ctrl_id.emplace(source_ctrl_id, i); - int config_bt_id = wxWindow::NewControlId(); - m_wiimote_index_from_conf_bt_id.emplace(config_bt_id, i); + int config_bt_id = wxWindow::NewControlId(); + m_wiimote_index_from_conf_bt_id.emplace(config_bt_id, i); - wiimote_label[i] = new wxStaticText(this, wxID_ANY, wiimote_str); - wiimote_source_ch[i] = new wxChoice(this, source_ctrl_id, wxDefaultPosition, wxDefaultSize, src_choices.size(), src_choices.data()); - wiimote_source_ch[i]->Bind(wxEVT_CHOICE, &ControllerConfigDiag::SelectSource, this); - wiimote_configure_bt[i] = new wxButton(this, config_bt_id, _("Configure"), wxDefaultPosition, wxSize(80, 25)); - wiimote_configure_bt[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::ConfigEmulatedWiimote, this); + wiimote_label[i] = new wxStaticText(this, wxID_ANY, wiimote_str); + wiimote_source_ch[i] = new wxChoice(this, source_ctrl_id, wxDefaultPosition, wxDefaultSize, + src_choices.size(), src_choices.data()); + wiimote_source_ch[i]->Bind(wxEVT_CHOICE, &ControllerConfigDiag::SelectSource, this); + wiimote_configure_bt[i] = + new wxButton(this, config_bt_id, _("Configure"), wxDefaultPosition, wxSize(80, 25)); + wiimote_configure_bt[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::ConfigEmulatedWiimote, this); - // Disable controller type selection for certain circumstances. - bool wii_game_started = SConfig::GetInstance().bWii || Core::GetState() == Core::CORE_UNINITIALIZED; - if (NetPlay::IsNetPlayRunning() || Movie::IsMovieActive() || !wii_game_started) - wiimote_source_ch[i]->Disable(); + // Disable controller type selection for certain circumstances. + bool wii_game_started = + SConfig::GetInstance().bWii || Core::GetState() == Core::CORE_UNINITIALIZED; + if (NetPlay::IsNetPlayRunning() || Movie::IsMovieActive() || !wii_game_started) + wiimote_source_ch[i]->Disable(); - m_orig_wiimote_sources[i] = g_wiimote_sources[i]; - wiimote_source_ch[i]->Select(m_orig_wiimote_sources[i]); - if (!wii_game_started || (m_orig_wiimote_sources[i] != WIIMOTE_SRC_EMU && m_orig_wiimote_sources[i] != WIIMOTE_SRC_HYBRID)) - wiimote_configure_bt[i]->Disable(); - } + m_orig_wiimote_sources[i] = g_wiimote_sources[i]; + wiimote_source_ch[i]->Select(m_orig_wiimote_sources[i]); + if (!wii_game_started || (m_orig_wiimote_sources[i] != WIIMOTE_SRC_EMU && + m_orig_wiimote_sources[i] != WIIMOTE_SRC_HYBRID)) + wiimote_configure_bt[i]->Disable(); + } - // "Wiimotes" layout - wxStaticBoxSizer* const wiimote_group = new wxStaticBoxSizer(wxVERTICAL,this, _("Wiimotes")); - wxBoxSizer* const wiimote_control_section = new wxBoxSizer(wxHORIZONTAL); - wxFlexGridSizer* const wiimote_sizer = new wxFlexGridSizer(3, 5, 5); - for (unsigned int i = 0; i < 4; ++i) - { - wiimote_sizer->Add(wiimote_label[i], 0, wxALIGN_CENTER_VERTICAL); - wiimote_sizer->Add(wiimote_source_ch[i], 0, wxALIGN_CENTER_VERTICAL); - wiimote_sizer->Add(wiimote_configure_bt[i]); - } - wiimote_control_section->Add(wiimote_sizer, 1, wxEXPAND, 5 ); + // "Wiimotes" layout + wxStaticBoxSizer* const wiimote_group = new wxStaticBoxSizer(wxVERTICAL, this, _("Wiimotes")); + wxBoxSizer* const wiimote_control_section = new wxBoxSizer(wxHORIZONTAL); + wxFlexGridSizer* const wiimote_sizer = new wxFlexGridSizer(3, 5, 5); + for (unsigned int i = 0; i < 4; ++i) + { + wiimote_sizer->Add(wiimote_label[i], 0, wxALIGN_CENTER_VERTICAL); + wiimote_sizer->Add(wiimote_source_ch[i], 0, wxALIGN_CENTER_VERTICAL); + wiimote_sizer->Add(wiimote_configure_bt[i]); + } + wiimote_control_section->Add(wiimote_sizer, 1, wxEXPAND, 5); - // Disable some controls when emulation is running - if (Core::GetState() != Core::CORE_UNINITIALIZED && NetPlay::IsNetPlayRunning()) - { - for (int i = 0; i < 4; ++i) - { - wiimote_label[i]->Disable(); - wiimote_source_ch[i]->Disable(); - } - } + // Disable some controls when emulation is running + if (Core::GetState() != Core::CORE_UNINITIALIZED && NetPlay::IsNetPlayRunning()) + { + for (int i = 0; i < 4; ++i) + { + wiimote_label[i]->Disable(); + wiimote_source_ch[i]->Disable(); + } + } - wiimote_group->Add(wiimote_control_section, 0, wxEXPAND); - wiimote_group->AddSpacer(5); - wiimote_group->Add(CreateBalanceBoardSizer(), 0, wxEXPAND); - wiimote_group->AddSpacer(5); - wiimote_group->Add(CreateRealWiimoteSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM); - wiimote_group->AddSpacer(5); - wiimote_group->Add(CreateGeneralWiimoteSettingsSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM); + wiimote_group->Add(wiimote_control_section, 0, wxEXPAND); + wiimote_group->AddSpacer(5); + wiimote_group->Add(CreateBalanceBoardSizer(), 0, wxEXPAND); + wiimote_group->AddSpacer(5); + wiimote_group->Add(CreateRealWiimoteSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM); + wiimote_group->AddSpacer(5); + wiimote_group->Add(CreateGeneralWiimoteSettingsSizer(), 0, + wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM); - return wiimote_group; + return wiimote_group; } wxStaticBoxSizer* ControllerConfigDiag::CreateBalanceBoardSizer() { - wxStaticBoxSizer* const bb_group = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Balance Board")); - wxFlexGridSizer* const bb_sizer = new wxFlexGridSizer(1, 5, 5); - int source_ctrl_id = wxWindow::NewControlId(); + wxStaticBoxSizer* const bb_group = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Balance Board")); + wxFlexGridSizer* const bb_sizer = new wxFlexGridSizer(1, 5, 5); + int source_ctrl_id = wxWindow::NewControlId(); - m_wiimote_index_from_ctrl_id.emplace(source_ctrl_id, WIIMOTE_BALANCE_BOARD); + m_wiimote_index_from_ctrl_id.emplace(source_ctrl_id, WIIMOTE_BALANCE_BOARD); - static const std::array src_choices = {{ - _("None"), _("Real Balance Board") - }}; + static const std::array src_choices = {{_("None"), _("Real Balance Board")}}; - wxChoice* const bb_source = new wxChoice(this, source_ctrl_id, wxDefaultPosition, wxDefaultSize, src_choices.size(), src_choices.data()); - bb_source->Bind(wxEVT_CHOICE, &ControllerConfigDiag::SelectSource, this); + wxChoice* const bb_source = new wxChoice(this, source_ctrl_id, wxDefaultPosition, wxDefaultSize, + src_choices.size(), src_choices.data()); + bb_source->Bind(wxEVT_CHOICE, &ControllerConfigDiag::SelectSource, this); - m_orig_wiimote_sources[WIIMOTE_BALANCE_BOARD] = g_wiimote_sources[WIIMOTE_BALANCE_BOARD]; - bb_source->Select(m_orig_wiimote_sources[WIIMOTE_BALANCE_BOARD] ? 1 : 0); + m_orig_wiimote_sources[WIIMOTE_BALANCE_BOARD] = g_wiimote_sources[WIIMOTE_BALANCE_BOARD]; + bb_source->Select(m_orig_wiimote_sources[WIIMOTE_BALANCE_BOARD] ? 1 : 0); - bb_sizer->Add(bb_source, 0, wxALIGN_CENTER_VERTICAL); + bb_sizer->Add(bb_source, 0, wxALIGN_CENTER_VERTICAL); - bb_group->Add(bb_sizer, 1, wxEXPAND, 5); + bb_group->Add(bb_sizer, 1, wxEXPAND, 5); - // Disable when emulation is running. - if (Core::GetState() != Core::CORE_UNINITIALIZED) - bb_source->Disable(); + // Disable when emulation is running. + if (Core::GetState() != Core::CORE_UNINITIALIZED) + bb_source->Disable(); - return bb_group; + return bb_group; } wxStaticBoxSizer* ControllerConfigDiag::CreateRealWiimoteSizer() { - // "Real wiimotes" controls - wxButton* const refresh_btn = new wxButton(this, wxID_ANY, _("Refresh")); - refresh_btn->Bind(wxEVT_BUTTON, &ControllerConfigDiag::RefreshRealWiimotes, this); + // "Real wiimotes" controls + wxButton* const refresh_btn = new wxButton(this, wxID_ANY, _("Refresh")); + refresh_btn->Bind(wxEVT_BUTTON, &ControllerConfigDiag::RefreshRealWiimotes, this); - wxStaticBoxSizer* const real_wiimotes_group = new wxStaticBoxSizer(wxVERTICAL, this, _("Real Wiimotes")); - wxBoxSizer* const real_wiimotes_sizer = new wxBoxSizer(wxHORIZONTAL); + wxStaticBoxSizer* const real_wiimotes_group = + new wxStaticBoxSizer(wxVERTICAL, this, _("Real Wiimotes")); + wxBoxSizer* const real_wiimotes_sizer = new wxBoxSizer(wxHORIZONTAL); - if (!WiimoteReal::g_wiimote_scanner.IsReady()) - real_wiimotes_group->Add(new wxStaticText(this, wxID_ANY, _("A supported Bluetooth device could not be found.\n" - "You must manually connect your Wiimotes.")), 0, wxALIGN_CENTER | wxALL, 5); + if (!WiimoteReal::g_wiimote_scanner.IsReady()) + real_wiimotes_group->Add( + new wxStaticText(this, wxID_ANY, _("A supported Bluetooth device could not be found.\n" + "You must manually connect your Wiimotes.")), + 0, wxALIGN_CENTER | wxALL, 5); - wxCheckBox* const continuous_scanning = new wxCheckBox(this, wxID_ANY, _("Continuous Scanning")); - continuous_scanning->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnContinuousScanning, this); - continuous_scanning->SetValue(SConfig::GetInstance().m_WiimoteContinuousScanning); + wxCheckBox* const continuous_scanning = new wxCheckBox(this, wxID_ANY, _("Continuous Scanning")); + continuous_scanning->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnContinuousScanning, this); + continuous_scanning->SetValue(SConfig::GetInstance().m_WiimoteContinuousScanning); - real_wiimotes_sizer->Add(continuous_scanning, 0, wxALIGN_CENTER_VERTICAL); - real_wiimotes_sizer->AddStretchSpacer(); - real_wiimotes_sizer->Add(refresh_btn, 0, wxALL | wxALIGN_CENTER, 5); + real_wiimotes_sizer->Add(continuous_scanning, 0, wxALIGN_CENTER_VERTICAL); + real_wiimotes_sizer->AddStretchSpacer(); + real_wiimotes_sizer->Add(refresh_btn, 0, wxALL | wxALIGN_CENTER, 5); - real_wiimotes_group->Add(real_wiimotes_sizer, 0, wxEXPAND); + real_wiimotes_group->Add(real_wiimotes_sizer, 0, wxEXPAND); - return real_wiimotes_group; + return real_wiimotes_group; } wxStaticBoxSizer* ControllerConfigDiag::CreateGeneralWiimoteSettingsSizer() { - const wxString str[] = { _("Bottom"), _("Top") }; - wxChoice* const WiiSensBarPos = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 2, str); - wxSlider* const WiiSensBarSens = new wxSlider(this, wxID_ANY, 0, 0, 4); - wxSlider* const WiimoteSpkVolume = new wxSlider(this, wxID_ANY, 0, 0, 127); - wxCheckBox* const WiimoteMotor = new wxCheckBox(this, wxID_ANY, _("Wiimote Motor")); + const wxString str[] = {_("Bottom"), _("Top")}; + wxChoice* const WiiSensBarPos = + new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 2, str); + wxSlider* const WiiSensBarSens = new wxSlider(this, wxID_ANY, 0, 0, 4); + wxSlider* const WiimoteSpkVolume = new wxSlider(this, wxID_ANY, 0, 0, 127); + wxCheckBox* const WiimoteMotor = new wxCheckBox(this, wxID_ANY, _("Wiimote Motor")); - auto wiimote_speaker = new wxCheckBox(this, wxID_ANY, _("Enable Speaker Data")); - wiimote_speaker->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnEnableSpeaker, this); - wiimote_speaker->SetValue(SConfig::GetInstance().m_WiimoteEnableSpeaker); + auto wiimote_speaker = new wxCheckBox(this, wxID_ANY, _("Enable Speaker Data")); + wiimote_speaker->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnEnableSpeaker, this); + wiimote_speaker->SetValue(SConfig::GetInstance().m_WiimoteEnableSpeaker); - wxStaticText* const WiiSensBarPosText = new wxStaticText(this, wxID_ANY, _("Sensor Bar Position:")); - wxStaticText* const WiiSensBarSensText = new wxStaticText(this, wxID_ANY, _("IR Sensitivity:")); - wxStaticText* const WiiSensBarSensMinText = new wxStaticText(this, wxID_ANY, _("Min")); - wxStaticText* const WiiSensBarSensMaxText = new wxStaticText(this, wxID_ANY, _("Max")); - wxStaticText* const WiimoteSpkVolumeText = new wxStaticText(this, wxID_ANY, _("Speaker Volume:")); - wxStaticText* const WiimoteSpkVolumeMinText = new wxStaticText(this, wxID_ANY, _("Min")); - wxStaticText* const WiimoteSpkVolumeMaxText = new wxStaticText(this, wxID_ANY, _("Max")); + wxStaticText* const WiiSensBarPosText = + new wxStaticText(this, wxID_ANY, _("Sensor Bar Position:")); + wxStaticText* const WiiSensBarSensText = new wxStaticText(this, wxID_ANY, _("IR Sensitivity:")); + wxStaticText* const WiiSensBarSensMinText = new wxStaticText(this, wxID_ANY, _("Min")); + wxStaticText* const WiiSensBarSensMaxText = new wxStaticText(this, wxID_ANY, _("Max")); + wxStaticText* const WiimoteSpkVolumeText = new wxStaticText(this, wxID_ANY, _("Speaker Volume:")); + wxStaticText* const WiimoteSpkVolumeMinText = new wxStaticText(this, wxID_ANY, _("Min")); + wxStaticText* const WiimoteSpkVolumeMaxText = new wxStaticText(this, wxID_ANY, _("Max")); - // With some GTK themes, no minimum size will be applied - so do this manually here - WiiSensBarSens->SetMinSize(wxSize(100,-1)); - WiimoteSpkVolume->SetMinSize(wxSize(100,-1)); + // With some GTK themes, no minimum size will be applied - so do this manually here + WiiSensBarSens->SetMinSize(wxSize(100, -1)); + WiimoteSpkVolume->SetMinSize(wxSize(100, -1)); - // Disable some controls when emulation is running - if (Core::GetState() != Core::CORE_UNINITIALIZED) - { - WiiSensBarPos->Disable(); - WiiSensBarSens->Disable(); - WiimoteSpkVolume->Disable(); - WiimoteMotor->Disable(); - WiiSensBarPosText->Disable(); - WiiSensBarSensText->Disable(); - WiiSensBarSensMinText->Disable(); - WiiSensBarSensMaxText->Disable(); - WiimoteSpkVolumeText->Disable(); - WiimoteSpkVolumeMinText->Disable(); - WiimoteSpkVolumeMaxText->Disable(); - } + // Disable some controls when emulation is running + if (Core::GetState() != Core::CORE_UNINITIALIZED) + { + WiiSensBarPos->Disable(); + WiiSensBarSens->Disable(); + WiimoteSpkVolume->Disable(); + WiimoteMotor->Disable(); + WiiSensBarPosText->Disable(); + WiiSensBarSensText->Disable(); + WiiSensBarSensMinText->Disable(); + WiiSensBarSensMaxText->Disable(); + WiimoteSpkVolumeText->Disable(); + WiimoteSpkVolumeMinText->Disable(); + WiimoteSpkVolumeMaxText->Disable(); + } - // "General Settings" initialization - WiiSensBarPos->SetSelection(SConfig::GetInstance().m_SYSCONF->GetData("BT.BAR")); - WiiSensBarSens->SetValue(SConfig::GetInstance().m_SYSCONF->GetData("BT.SENS")); - WiimoteSpkVolume->SetValue(SConfig::GetInstance().m_SYSCONF->GetData("BT.SPKV")); - WiimoteMotor->SetValue(SConfig::GetInstance().m_SYSCONF->GetData("BT.MOT")); + // "General Settings" initialization + WiiSensBarPos->SetSelection(SConfig::GetInstance().m_SYSCONF->GetData("BT.BAR")); + WiiSensBarSens->SetValue(SConfig::GetInstance().m_SYSCONF->GetData("BT.SENS")); + WiimoteSpkVolume->SetValue(SConfig::GetInstance().m_SYSCONF->GetData("BT.SPKV")); + WiimoteMotor->SetValue(SConfig::GetInstance().m_SYSCONF->GetData("BT.MOT")); - WiiSensBarPos->Bind(wxEVT_CHOICE, &ControllerConfigDiag::OnSensorBarPos, this); - WiiSensBarSens->Bind(wxEVT_SLIDER, &ControllerConfigDiag::OnSensorBarSensitivity, this); - WiimoteSpkVolume->Bind(wxEVT_SLIDER, &ControllerConfigDiag::OnSpeakerVolume, this); - WiimoteMotor->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnMotor, this); + WiiSensBarPos->Bind(wxEVT_CHOICE, &ControllerConfigDiag::OnSensorBarPos, this); + WiiSensBarSens->Bind(wxEVT_SLIDER, &ControllerConfigDiag::OnSensorBarSensitivity, this); + WiimoteSpkVolume->Bind(wxEVT_SLIDER, &ControllerConfigDiag::OnSpeakerVolume, this); + WiimoteMotor->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnMotor, this); - // "General Settings" layout - wxStaticBoxSizer* const general_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("General Settings")); - wxFlexGridSizer* const choice_sizer = new wxFlexGridSizer(2, 5, 5); + // "General Settings" layout + wxStaticBoxSizer* const general_sizer = + new wxStaticBoxSizer(wxVERTICAL, this, _("General Settings")); + wxFlexGridSizer* const choice_sizer = new wxFlexGridSizer(2, 5, 5); - wxBoxSizer* const sensbarsens_sizer = new wxBoxSizer(wxHORIZONTAL); - sensbarsens_sizer->Add(WiiSensBarSensMinText, 0, wxALIGN_CENTER_VERTICAL); - sensbarsens_sizer->Add(WiiSensBarSens); - sensbarsens_sizer->Add(WiiSensBarSensMaxText, 0, wxALIGN_CENTER_VERTICAL); + wxBoxSizer* const sensbarsens_sizer = new wxBoxSizer(wxHORIZONTAL); + sensbarsens_sizer->Add(WiiSensBarSensMinText, 0, wxALIGN_CENTER_VERTICAL); + sensbarsens_sizer->Add(WiiSensBarSens); + sensbarsens_sizer->Add(WiiSensBarSensMaxText, 0, wxALIGN_CENTER_VERTICAL); - wxBoxSizer* const spkvol_sizer = new wxBoxSizer(wxHORIZONTAL); - spkvol_sizer->Add(WiimoteSpkVolumeMinText, 0, wxALIGN_CENTER_VERTICAL); - spkvol_sizer->Add(WiimoteSpkVolume); - spkvol_sizer->Add(WiimoteSpkVolumeMaxText, 0, wxALIGN_CENTER_VERTICAL); + wxBoxSizer* const spkvol_sizer = new wxBoxSizer(wxHORIZONTAL); + spkvol_sizer->Add(WiimoteSpkVolumeMinText, 0, wxALIGN_CENTER_VERTICAL); + spkvol_sizer->Add(WiimoteSpkVolume); + spkvol_sizer->Add(WiimoteSpkVolumeMaxText, 0, wxALIGN_CENTER_VERTICAL); - choice_sizer->Add(WiiSensBarPosText, 0, wxALIGN_CENTER_VERTICAL); - choice_sizer->Add(WiiSensBarPos); - choice_sizer->Add(WiiSensBarSensText, 0, wxALIGN_CENTER_VERTICAL); - choice_sizer->Add(sensbarsens_sizer); - choice_sizer->Add(WiimoteSpkVolumeText, 0, wxALIGN_CENTER_VERTICAL); - choice_sizer->Add(spkvol_sizer); + choice_sizer->Add(WiiSensBarPosText, 0, wxALIGN_CENTER_VERTICAL); + choice_sizer->Add(WiiSensBarPos); + choice_sizer->Add(WiiSensBarSensText, 0, wxALIGN_CENTER_VERTICAL); + choice_sizer->Add(sensbarsens_sizer); + choice_sizer->Add(WiimoteSpkVolumeText, 0, wxALIGN_CENTER_VERTICAL); + choice_sizer->Add(spkvol_sizer); - wxGridSizer* const general_wiimote_sizer = new wxGridSizer(1, 5, 5); - general_wiimote_sizer->Add(WiimoteMotor); - general_wiimote_sizer->Add(wiimote_speaker); + wxGridSizer* const general_wiimote_sizer = new wxGridSizer(1, 5, 5); + general_wiimote_sizer->Add(WiimoteMotor); + general_wiimote_sizer->Add(wiimote_speaker); - general_sizer->Add(choice_sizer); - general_sizer->Add(general_wiimote_sizer); + general_sizer->Add(choice_sizer); + general_sizer->Add(general_wiimote_sizer); - return general_sizer; + return general_sizer; } - void ControllerConfigDiag::ConfigEmulatedWiimote(wxCommandEvent& ev) { - InputConfig* const wiimote_plugin = Wiimote::GetConfig(); + InputConfig* const wiimote_plugin = Wiimote::GetConfig(); - HotkeyManagerEmu::Enable(false); + HotkeyManagerEmu::Enable(false); - InputConfigDialog m_ConfigFrame(this, *wiimote_plugin, _("Dolphin Emulated Wiimote Configuration"), m_wiimote_index_from_conf_bt_id[ev.GetId()]); - m_ConfigFrame.ShowModal(); + InputConfigDialog m_ConfigFrame(this, *wiimote_plugin, + _("Dolphin Emulated Wiimote Configuration"), + m_wiimote_index_from_conf_bt_id[ev.GetId()]); + m_ConfigFrame.ShowModal(); - HotkeyManagerEmu::Enable(true); + HotkeyManagerEmu::Enable(true); } void ControllerConfigDiag::RefreshRealWiimotes(wxCommandEvent&) { - WiimoteReal::Refresh(); + WiimoteReal::Refresh(); } void ControllerConfigDiag::SelectSource(wxCommandEvent& event) { - // This needs to be changed now in order for refresh to work right. - // Revert if the dialog is canceled. - int index = m_wiimote_index_from_ctrl_id[event.GetId()]; + // This needs to be changed now in order for refresh to work right. + // Revert if the dialog is canceled. + int index = m_wiimote_index_from_ctrl_id[event.GetId()]; - if (index != WIIMOTE_BALANCE_BOARD) - { - WiimoteReal::ChangeWiimoteSource(index, event.GetInt()); - if (g_wiimote_sources[index] != WIIMOTE_SRC_EMU && g_wiimote_sources[index] != WIIMOTE_SRC_HYBRID) - wiimote_configure_bt[index]->Disable(); - else - wiimote_configure_bt[index]->Enable(); - } - else - { - WiimoteReal::ChangeWiimoteSource(index, event.GetInt() ? WIIMOTE_SRC_REAL : WIIMOTE_SRC_NONE); - } + if (index != WIIMOTE_BALANCE_BOARD) + { + WiimoteReal::ChangeWiimoteSource(index, event.GetInt()); + if (g_wiimote_sources[index] != WIIMOTE_SRC_EMU && + g_wiimote_sources[index] != WIIMOTE_SRC_HYBRID) + wiimote_configure_bt[index]->Disable(); + else + wiimote_configure_bt[index]->Enable(); + } + else + { + WiimoteReal::ChangeWiimoteSource(index, event.GetInt() ? WIIMOTE_SRC_REAL : WIIMOTE_SRC_NONE); + } } void ControllerConfigDiag::RevertSource() { - for (int i = 0; i < MAX_BBMOTES; ++i) - g_wiimote_sources[i] = m_orig_wiimote_sources[i]; + for (int i = 0; i < MAX_BBMOTES; ++i) + g_wiimote_sources[i] = m_orig_wiimote_sources[i]; } void ControllerConfigDiag::Save(wxCommandEvent& event) { - std::string ini_filename = File::GetUserPath(D_CONFIG_IDX) + WIIMOTE_INI_NAME ".ini"; + std::string ini_filename = File::GetUserPath(D_CONFIG_IDX) + WIIMOTE_INI_NAME ".ini"; - IniFile inifile; - inifile.Load(ini_filename); + IniFile inifile; + inifile.Load(ini_filename); - for (unsigned int i=0; iEnable(); - } - else if (device_name == m_gc_pad_type_strs[2]) - { - tempType = SIDEVICE_WIIU_ADAPTER; - gamecube_configure_bt[device_num]->Enable(); - } - else if (device_name == m_gc_pad_type_strs[3]) - { - tempType = SIDEVICE_GC_STEERING; - gamecube_configure_bt[device_num]->Enable(); - } - else if (device_name == m_gc_pad_type_strs[4]) - { - tempType = SIDEVICE_DANCEMAT; - gamecube_configure_bt[device_num]->Enable(); - } - else if (device_name == m_gc_pad_type_strs[5]) - { - tempType = SIDEVICE_GC_TARUKONGA; - gamecube_configure_bt[device_num]->Enable(); - } - else if (device_name == m_gc_pad_type_strs[6]) - { - tempType = SIDEVICE_GC_GBA; - gamecube_configure_bt[device_num]->Disable(); - } - else if (device_name == m_gc_pad_type_strs[7]) - { - tempType = SIDEVICE_GC_KEYBOARD; - gamecube_configure_bt[device_num]->Enable(); - } - else if (device_name == m_gc_pad_type_strs[8]) - { - tempType = SIDEVICE_AM_BASEBOARD; - gamecube_configure_bt[device_num]->Enable(); - } - else - { - tempType = SIDEVICE_NONE; - gamecube_configure_bt[device_num]->Disable(); - } + SIDevices tempType; + if (device_name == m_gc_pad_type_strs[1]) + { + tempType = SIDEVICE_GC_CONTROLLER; + gamecube_configure_bt[device_num]->Enable(); + } + else if (device_name == m_gc_pad_type_strs[2]) + { + tempType = SIDEVICE_WIIU_ADAPTER; + gamecube_configure_bt[device_num]->Enable(); + } + else if (device_name == m_gc_pad_type_strs[3]) + { + tempType = SIDEVICE_GC_STEERING; + gamecube_configure_bt[device_num]->Enable(); + } + else if (device_name == m_gc_pad_type_strs[4]) + { + tempType = SIDEVICE_DANCEMAT; + gamecube_configure_bt[device_num]->Enable(); + } + else if (device_name == m_gc_pad_type_strs[5]) + { + tempType = SIDEVICE_GC_TARUKONGA; + gamecube_configure_bt[device_num]->Enable(); + } + else if (device_name == m_gc_pad_type_strs[6]) + { + tempType = SIDEVICE_GC_GBA; + gamecube_configure_bt[device_num]->Disable(); + } + else if (device_name == m_gc_pad_type_strs[7]) + { + tempType = SIDEVICE_GC_KEYBOARD; + gamecube_configure_bt[device_num]->Enable(); + } + else if (device_name == m_gc_pad_type_strs[8]) + { + tempType = SIDEVICE_AM_BASEBOARD; + gamecube_configure_bt[device_num]->Enable(); + } + else + { + tempType = SIDEVICE_NONE; + gamecube_configure_bt[device_num]->Disable(); + } - SConfig::GetInstance().m_SIDevice[device_num] = tempType; + SConfig::GetInstance().m_SIDevice[device_num] = tempType; - if (GCAdapter::UseAdapter()) - GCAdapter::StartScanThread(); - else - GCAdapter::StopScanThread(); + if (GCAdapter::UseAdapter()) + GCAdapter::StartScanThread(); + else + GCAdapter::StopScanThread(); - if (Core::IsRunning()) - SerialInterface::ChangeDevice(tempType, device_num); + if (Core::IsRunning()) + SerialInterface::ChangeDevice(tempType, device_num); } void ControllerConfigDiag::OnGameCubeConfigButton(wxCommandEvent& event) { - InputConfig* const pad_plugin = Pad::GetConfig(); - InputConfig* const key_plugin = Keyboard::GetConfig(); - const int port_num = m_gc_port_config_ids[event.GetId()]; + InputConfig* const pad_plugin = Pad::GetConfig(); + InputConfig* const key_plugin = Keyboard::GetConfig(); + const int port_num = m_gc_port_config_ids[event.GetId()]; - HotkeyManagerEmu::Enable(false); + HotkeyManagerEmu::Enable(false); - if (SConfig::GetInstance().m_SIDevice[port_num] == SIDEVICE_GC_KEYBOARD) - { - InputConfigDialog m_ConfigFrame(this, *key_plugin, _("GameCube Controller Configuration"), port_num); - m_ConfigFrame.ShowModal(); - } - else if (SConfig::GetInstance().m_SIDevice[port_num] == SIDEVICE_WIIU_ADAPTER) - { - GCAdapterConfigDiag m_ConfigFramg(this, _("Wii U Gamecube Controller Adapter Configuration"), port_num); - m_ConfigFramg.ShowModal(); - } - else - { - InputConfigDialog m_ConfigFrame(this, *pad_plugin, _("GameCube Controller Configuration"), port_num); - m_ConfigFrame.ShowModal(); - } + if (SConfig::GetInstance().m_SIDevice[port_num] == SIDEVICE_GC_KEYBOARD) + { + InputConfigDialog m_ConfigFrame(this, *key_plugin, _("GameCube Controller Configuration"), + port_num); + m_ConfigFrame.ShowModal(); + } + else if (SConfig::GetInstance().m_SIDevice[port_num] == SIDEVICE_WIIU_ADAPTER) + { + GCAdapterConfigDiag m_ConfigFramg(this, _("Wii U Gamecube Controller Adapter Configuration"), + port_num); + m_ConfigFramg.ShowModal(); + } + else + { + InputConfigDialog m_ConfigFrame(this, *pad_plugin, _("GameCube Controller Configuration"), + port_num); + m_ConfigFrame.ShowModal(); + } - HotkeyManagerEmu::Enable(true); + HotkeyManagerEmu::Enable(true); } diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.h b/Source/Core/DolphinWX/ControllerConfigDiag.h index 8646396b2b..98c7a1af47 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.h +++ b/Source/Core/DolphinWX/ControllerConfigDiag.h @@ -20,73 +20,73 @@ class wxStaticBoxSizer; class ControllerConfigDiag : public wxDialog { public: - ControllerConfigDiag(wxWindow* const parent); + ControllerConfigDiag(wxWindow* const parent); private: - void RefreshRealWiimotes(wxCommandEvent& event); + void RefreshRealWiimotes(wxCommandEvent& event); - void ConfigEmulatedWiimote(wxCommandEvent& event); + void ConfigEmulatedWiimote(wxCommandEvent& event); - void SelectSource(wxCommandEvent& event); - void RevertSource(); + void SelectSource(wxCommandEvent& event); + void RevertSource(); - void Save(wxCommandEvent& event); + void Save(wxCommandEvent& event); - void OnSensorBarPos(wxCommandEvent& event) - { - SConfig::GetInstance().m_SYSCONF->SetData("BT.BAR", event.GetInt()); - event.Skip(); - } + void OnSensorBarPos(wxCommandEvent& event) + { + SConfig::GetInstance().m_SYSCONF->SetData("BT.BAR", event.GetInt()); + event.Skip(); + } - void OnSensorBarSensitivity(wxCommandEvent& event) - { - SConfig::GetInstance().m_SYSCONF->SetData("BT.SENS", event.GetInt()); - event.Skip(); - } + void OnSensorBarSensitivity(wxCommandEvent& event) + { + SConfig::GetInstance().m_SYSCONF->SetData("BT.SENS", event.GetInt()); + event.Skip(); + } - void OnSpeakerVolume(wxCommandEvent& event) - { - SConfig::GetInstance().m_SYSCONF->SetData("BT.SPKV", event.GetInt()); - event.Skip(); - } + void OnSpeakerVolume(wxCommandEvent& event) + { + SConfig::GetInstance().m_SYSCONF->SetData("BT.SPKV", event.GetInt()); + event.Skip(); + } - void OnMotor(wxCommandEvent& event) - { - SConfig::GetInstance().m_SYSCONF->SetData("BT.MOT", event.GetInt()); - event.Skip(); - } + void OnMotor(wxCommandEvent& event) + { + SConfig::GetInstance().m_SYSCONF->SetData("BT.MOT", event.GetInt()); + event.Skip(); + } - void OnContinuousScanning(wxCommandEvent& event) - { - SConfig::GetInstance().m_WiimoteContinuousScanning = event.IsChecked(); - WiimoteReal::Initialize(); - event.Skip(); - } + void OnContinuousScanning(wxCommandEvent& event) + { + SConfig::GetInstance().m_WiimoteContinuousScanning = event.IsChecked(); + WiimoteReal::Initialize(); + event.Skip(); + } - void OnEnableSpeaker(wxCommandEvent& event) - { - SConfig::GetInstance().m_WiimoteEnableSpeaker = event.IsChecked(); - event.Skip(); - } + void OnEnableSpeaker(wxCommandEvent& event) + { + SConfig::GetInstance().m_WiimoteEnableSpeaker = event.IsChecked(); + event.Skip(); + } - wxStaticBoxSizer* CreateGamecubeSizer(); - wxStaticBoxSizer* CreateWiimoteConfigSizer(); - wxStaticBoxSizer* CreateBalanceBoardSizer(); - wxStaticBoxSizer* CreateRealWiimoteSizer(); - wxStaticBoxSizer* CreateGeneralWiimoteSettingsSizer(); + wxStaticBoxSizer* CreateGamecubeSizer(); + wxStaticBoxSizer* CreateWiimoteConfigSizer(); + wxStaticBoxSizer* CreateBalanceBoardSizer(); + wxStaticBoxSizer* CreateRealWiimoteSizer(); + wxStaticBoxSizer* CreateGeneralWiimoteSettingsSizer(); - void Cancel(wxCommandEvent& event); - void OnGameCubePortChanged(wxCommandEvent& event); - void OnGameCubeConfigButton(wxCommandEvent& event); + void Cancel(wxCommandEvent& event); + void OnGameCubePortChanged(wxCommandEvent& event); + void OnGameCubeConfigButton(wxCommandEvent& event); - std::map m_gc_port_choice_ids; - std::map m_gc_port_config_ids; - std::array m_gc_pad_type_strs; + std::map m_gc_port_choice_ids; + std::map m_gc_port_config_ids; + std::array m_gc_pad_type_strs; - std::map m_wiimote_index_from_ctrl_id; - unsigned int m_orig_wiimote_sources[MAX_BBMOTES]; + std::map m_wiimote_index_from_ctrl_id; + unsigned int m_orig_wiimote_sources[MAX_BBMOTES]; - wxButton* wiimote_configure_bt[MAX_WIIMOTES]; - wxButton* gamecube_configure_bt[4]; - std::map m_wiimote_index_from_conf_bt_id; + wxButton* wiimote_configure_bt[MAX_WIIMOTES]; + wxButton* gamecube_configure_bt[4]; + std::map m_wiimote_index_from_conf_bt_id; }; diff --git a/Source/Core/DolphinWX/Debugger/BreakpointDlg.cpp b/Source/Core/DolphinWX/Debugger/BreakpointDlg.cpp index bbef9f6a06..9665bb271e 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointDlg.cpp +++ b/Source/Core/DolphinWX/Debugger/BreakpointDlg.cpp @@ -12,40 +12,40 @@ #include "Common/CommonTypes.h" #include "Common/StringUtil.h" #include "Core/PowerPC/PowerPC.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Debugger/BreakpointDlg.h" #include "DolphinWX/Debugger/BreakpointWindow.h" +#include "DolphinWX/WxUtils.h" -BreakPointDlg::BreakPointDlg(CBreakPointWindow *_Parent) - : wxDialog(_Parent, wxID_ANY, _("Add Breakpoint")) - , Parent(_Parent) +BreakPointDlg::BreakPointDlg(CBreakPointWindow* _Parent) + : wxDialog(_Parent, wxID_ANY, _("Add Breakpoint")), Parent(_Parent) { - Bind(wxEVT_BUTTON, &BreakPointDlg::OnOK, this, wxID_OK); + Bind(wxEVT_BUTTON, &BreakPointDlg::OnOK, this, wxID_OK); - m_pEditAddress = new wxTextCtrl(this, wxID_ANY, "80000000"); + m_pEditAddress = new wxTextCtrl(this, wxID_ANY, "80000000"); - wxBoxSizer *sMainSizer = new wxBoxSizer(wxVERTICAL); - sMainSizer->Add(m_pEditAddress, 0, wxEXPAND | wxALL, 5); - sMainSizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALL, 5); + wxBoxSizer* sMainSizer = new wxBoxSizer(wxVERTICAL); + sMainSizer->Add(m_pEditAddress, 0, wxEXPAND | wxALL, 5); + sMainSizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALL, 5); - SetSizerAndFit(sMainSizer); - SetFocus(); + SetSizerAndFit(sMainSizer); + SetFocus(); } void BreakPointDlg::OnOK(wxCommandEvent& event) { - wxString AddressString = m_pEditAddress->GetLineText(0); - u32 Address = 0; - if (AsciiToHex(WxStrToStr(AddressString), Address)) - { - PowerPC::breakpoints.Add(Address); - Parent->NotifyUpdate(); - Close(); - } - else - { - WxUtils::ShowErrorDialog(wxString::Format(_("The address %s is invalid."), WxStrToStr(AddressString).c_str())); - } + wxString AddressString = m_pEditAddress->GetLineText(0); + u32 Address = 0; + if (AsciiToHex(WxStrToStr(AddressString), Address)) + { + PowerPC::breakpoints.Add(Address); + Parent->NotifyUpdate(); + Close(); + } + else + { + WxUtils::ShowErrorDialog( + wxString::Format(_("The address %s is invalid."), WxStrToStr(AddressString).c_str())); + } - event.Skip(); + event.Skip(); } diff --git a/Source/Core/DolphinWX/Debugger/BreakpointDlg.h b/Source/Core/DolphinWX/Debugger/BreakpointDlg.h index 6ea0b1450a..6918f4d614 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointDlg.h +++ b/Source/Core/DolphinWX/Debugger/BreakpointDlg.h @@ -12,11 +12,11 @@ class wxTextCtrl; class BreakPointDlg : public wxDialog { public: - BreakPointDlg(CBreakPointWindow *_Parent); + BreakPointDlg(CBreakPointWindow* _Parent); private: - CBreakPointWindow *Parent; - wxTextCtrl *m_pEditAddress; + CBreakPointWindow* Parent; + wxTextCtrl* m_pEditAddress; - void OnOK(wxCommandEvent& event); + void OnOK(wxCommandEvent& event); }; diff --git a/Source/Core/DolphinWX/Debugger/BreakpointView.cpp b/Source/Core/DolphinWX/Debugger/BreakpointView.cpp index 07908b6cf0..743bfec2b8 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointView.cpp +++ b/Source/Core/DolphinWX/Debugger/BreakpointView.cpp @@ -10,92 +10,94 @@ #include "Common/BreakPoints.h" #include "Common/CommonTypes.h" #include "Common/StringUtil.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PPCSymbolDB.h" -#include "DolphinWX/WxUtils.h" +#include "Core/PowerPC/PowerPC.h" #include "DolphinWX/Debugger/BreakpointView.h" #include "DolphinWX/Debugger/DebuggerUIUtil.h" +#include "DolphinWX/WxUtils.h" CBreakPointView::CBreakPointView(wxWindow* parent, const wxWindowID id) - : wxListCtrl(parent, id, wxDefaultPosition, wxDefaultSize, - wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT | wxLC_SINGLE_SEL | wxLC_SORT_ASCENDING) + : wxListCtrl(parent, id, wxDefaultPosition, wxDefaultSize, + wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT | wxLC_SINGLE_SEL | + wxLC_SORT_ASCENDING) { - SetFont(DebuggerFont); - Refresh(); + SetFont(DebuggerFont); + Refresh(); } void CBreakPointView::Update() { - ClearAll(); + ClearAll(); - InsertColumn(0, _("Active")); - InsertColumn(1, _("Type")); - InsertColumn(2, _("Function")); - InsertColumn(3, _("Address")); - InsertColumn(4, _("Flags")); + InsertColumn(0, _("Active")); + InsertColumn(1, _("Type")); + InsertColumn(2, _("Function")); + InsertColumn(3, _("Address")); + InsertColumn(4, _("Flags")); - const BreakPoints::TBreakPoints& rBreakPoints = PowerPC::breakpoints.GetBreakPoints(); - for (const auto& rBP : rBreakPoints) - { - if (!rBP.bTemporary) - { - wxString breakpoint_enabled_str = StrToWxStr(rBP.bOn ? "on" : " "); - int item = InsertItem(0, breakpoint_enabled_str); - SetItem(item, 1, StrToWxStr("BP")); + const BreakPoints::TBreakPoints& rBreakPoints = PowerPC::breakpoints.GetBreakPoints(); + for (const auto& rBP : rBreakPoints) + { + if (!rBP.bTemporary) + { + wxString breakpoint_enabled_str = StrToWxStr(rBP.bOn ? "on" : " "); + int item = InsertItem(0, breakpoint_enabled_str); + SetItem(item, 1, StrToWxStr("BP")); - Symbol *symbol = g_symbolDB.GetSymbolFromAddr(rBP.iAddress); - if (symbol) - { - wxString symbol_description = StrToWxStr(g_symbolDB.GetDescription(rBP.iAddress)); - SetItem(item, 2, symbol_description); - } + Symbol* symbol = g_symbolDB.GetSymbolFromAddr(rBP.iAddress); + if (symbol) + { + wxString symbol_description = StrToWxStr(g_symbolDB.GetDescription(rBP.iAddress)); + SetItem(item, 2, symbol_description); + } - std::string address = StringFromFormat("%08x", rBP.iAddress); - SetItem(item, 3, StrToWxStr(address)); + std::string address = StringFromFormat("%08x", rBP.iAddress); + SetItem(item, 3, StrToWxStr(address)); - SetItemData(item, rBP.iAddress); - } - } + SetItemData(item, rBP.iAddress); + } + } - const MemChecks::TMemChecks& rMemChecks = PowerPC::memchecks.GetMemChecks(); - for (const auto& rMemCheck : rMemChecks) - { - wxString memcheck_on_str = StrToWxStr((rMemCheck.Break || rMemCheck.Log) ? "on" : " "); - int item = InsertItem(0, memcheck_on_str); - SetItem(item, 1, StrToWxStr("MC")); + const MemChecks::TMemChecks& rMemChecks = PowerPC::memchecks.GetMemChecks(); + for (const auto& rMemCheck : rMemChecks) + { + wxString memcheck_on_str = StrToWxStr((rMemCheck.Break || rMemCheck.Log) ? "on" : " "); + int item = InsertItem(0, memcheck_on_str); + SetItem(item, 1, StrToWxStr("MC")); - Symbol *symbol = g_symbolDB.GetSymbolFromAddr(rMemCheck.StartAddress); - if (symbol) - { - wxString memcheck_start_addr = StrToWxStr(g_symbolDB.GetDescription(rMemCheck.StartAddress)); - SetItem(item, 2, memcheck_start_addr); - } + Symbol* symbol = g_symbolDB.GetSymbolFromAddr(rMemCheck.StartAddress); + if (symbol) + { + wxString memcheck_start_addr = StrToWxStr(g_symbolDB.GetDescription(rMemCheck.StartAddress)); + SetItem(item, 2, memcheck_start_addr); + } - std::string address_range_str = StringFromFormat("%08x to %08x", rMemCheck.StartAddress, rMemCheck.EndAddress); - SetItem(item, 3, StrToWxStr(address_range_str)); + std::string address_range_str = + StringFromFormat("%08x to %08x", rMemCheck.StartAddress, rMemCheck.EndAddress); + SetItem(item, 3, StrToWxStr(address_range_str)); - std::string mode; - if (rMemCheck.OnRead) - mode += 'r'; - if (rMemCheck.OnWrite) - mode += 'w'; + std::string mode; + if (rMemCheck.OnRead) + mode += 'r'; + if (rMemCheck.OnWrite) + mode += 'w'; - SetItem(item, 4, StrToWxStr(mode)); + SetItem(item, 4, StrToWxStr(mode)); - SetItemData(item, rMemCheck.StartAddress); - } + SetItemData(item, rMemCheck.StartAddress); + } - Refresh(); + Refresh(); } void CBreakPointView::DeleteCurrentSelection() { - int item = GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (item >= 0) - { - u32 Address = (u32)GetItemData(item); - PowerPC::breakpoints.Remove(Address); - PowerPC::memchecks.Remove(Address); - Update(); - } + int item = GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (item >= 0) + { + u32 Address = (u32)GetItemData(item); + PowerPC::breakpoints.Remove(Address); + PowerPC::memchecks.Remove(Address); + Update(); + } } diff --git a/Source/Core/DolphinWX/Debugger/BreakpointView.h b/Source/Core/DolphinWX/Debugger/BreakpointView.h index 380855c5cd..a7d37bb5bb 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointView.h +++ b/Source/Core/DolphinWX/Debugger/BreakpointView.h @@ -9,8 +9,8 @@ class CBreakPointView : public wxListCtrl { public: - CBreakPointView(wxWindow* parent, const wxWindowID id); + CBreakPointView(wxWindow* parent, const wxWindowID id); - void Update() override; - void DeleteCurrentSelection(); + void Update() override; + void DeleteCurrentSelection(); }; diff --git a/Source/Core/DolphinWX/Debugger/BreakpointWindow.cpp b/Source/Core/DolphinWX/Debugger/BreakpointWindow.cpp index a86920cf09..30dd67ead1 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/BreakpointWindow.cpp @@ -2,12 +2,12 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include +#include #include #include #include #include -#include -#include #include "Common/BreakPoints.h" #include "Common/CommonTypes.h" @@ -16,189 +16,195 @@ #include "Core/ConfigManager.h" #include "Core/HW/Memmap.h" #include "Core/PowerPC/PowerPC.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Debugger/BreakpointDlg.h" #include "DolphinWX/Debugger/BreakpointView.h" #include "DolphinWX/Debugger/BreakpointWindow.h" #include "DolphinWX/Debugger/CodeWindow.h" #include "DolphinWX/Debugger/MemoryCheckDlg.h" +#include "DolphinWX/WxUtils.h" class CBreakPointBar : public wxAuiToolBar { public: - CBreakPointBar(CBreakPointWindow* parent, const wxWindowID id) - : wxAuiToolBar(parent, id, wxDefaultPosition, wxDefaultSize, - wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_TEXT) - { - SetToolBitmapSize(wxSize(24, 24)); + CBreakPointBar(CBreakPointWindow* parent, const wxWindowID id) + : wxAuiToolBar(parent, id, wxDefaultPosition, wxDefaultSize, + wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_TEXT) + { + SetToolBitmapSize(wxSize(24, 24)); - m_Bitmaps[Toolbar_Delete] = WxUtils::LoadResourceBitmap("toolbar_debugger_delete"); - m_Bitmaps[Toolbar_Add_BP] = WxUtils::LoadResourceBitmap("toolbar_add_breakpoint"); - m_Bitmaps[Toolbar_Add_MC] = WxUtils::LoadResourceBitmap("toolbar_add_memorycheck"); + m_Bitmaps[Toolbar_Delete] = WxUtils::LoadResourceBitmap("toolbar_debugger_delete"); + m_Bitmaps[Toolbar_Add_BP] = WxUtils::LoadResourceBitmap("toolbar_add_breakpoint"); + m_Bitmaps[Toolbar_Add_MC] = WxUtils::LoadResourceBitmap("toolbar_add_memorycheck"); - AddTool(ID_DELETE, _("Delete"), m_Bitmaps[Toolbar_Delete]); - Bind(wxEVT_TOOL, &CBreakPointWindow::OnDelete, parent, ID_DELETE); + AddTool(ID_DELETE, _("Delete"), m_Bitmaps[Toolbar_Delete]); + Bind(wxEVT_TOOL, &CBreakPointWindow::OnDelete, parent, ID_DELETE); - AddTool(ID_CLEAR, _("Clear"), m_Bitmaps[Toolbar_Delete]); - Bind(wxEVT_TOOL, &CBreakPointWindow::OnClear, parent, ID_CLEAR); + AddTool(ID_CLEAR, _("Clear"), m_Bitmaps[Toolbar_Delete]); + Bind(wxEVT_TOOL, &CBreakPointWindow::OnClear, parent, ID_CLEAR); - AddTool(ID_ADDBP, "+BP", m_Bitmaps[Toolbar_Add_BP]); - Bind(wxEVT_TOOL, &CBreakPointWindow::OnAddBreakPoint, parent, ID_ADDBP); + AddTool(ID_ADDBP, "+BP", m_Bitmaps[Toolbar_Add_BP]); + Bind(wxEVT_TOOL, &CBreakPointWindow::OnAddBreakPoint, parent, ID_ADDBP); - // Add memory breakpoints if you can use them - if (Memory::AreMemoryBreakpointsActivated()) - { - AddTool(ID_ADDMC, "+MC", m_Bitmaps[Toolbar_Add_MC]); - Bind(wxEVT_TOOL, &CBreakPointWindow::OnAddMemoryCheck, parent, ID_ADDMC); - } + // Add memory breakpoints if you can use them + if (Memory::AreMemoryBreakpointsActivated()) + { + AddTool(ID_ADDMC, "+MC", m_Bitmaps[Toolbar_Add_MC]); + Bind(wxEVT_TOOL, &CBreakPointWindow::OnAddMemoryCheck, parent, ID_ADDMC); + } - AddTool(ID_LOAD, _("Load"), m_Bitmaps[Toolbar_Delete]); - Bind(wxEVT_TOOL, &CBreakPointWindow::Event_LoadAll, parent, ID_LOAD); + AddTool(ID_LOAD, _("Load"), m_Bitmaps[Toolbar_Delete]); + Bind(wxEVT_TOOL, &CBreakPointWindow::Event_LoadAll, parent, ID_LOAD); - AddTool(ID_SAVE, _("Save"), m_Bitmaps[Toolbar_Delete]); - Bind(wxEVT_TOOL, &CBreakPointWindow::Event_SaveAll, parent, ID_SAVE); - } + AddTool(ID_SAVE, _("Save"), m_Bitmaps[Toolbar_Delete]); + Bind(wxEVT_TOOL, &CBreakPointWindow::Event_SaveAll, parent, ID_SAVE); + } private: + enum + { + Toolbar_Delete, + Toolbar_Add_BP, + Toolbar_Add_MC, + Num_Bitmaps + }; - enum - { - Toolbar_Delete, - Toolbar_Add_BP, - Toolbar_Add_MC, - Num_Bitmaps - }; + enum + { + ID_DELETE = 2000, + ID_CLEAR, + ID_ADDBP, + ID_ADDMC, + ID_LOAD, + ID_SAVE + }; - enum - { - ID_DELETE = 2000, - ID_CLEAR, - ID_ADDBP, - ID_ADDMC, - ID_LOAD, - ID_SAVE - }; - - wxBitmap m_Bitmaps[Num_Bitmaps]; + wxBitmap m_Bitmaps[Num_Bitmaps]; }; -CBreakPointWindow::CBreakPointWindow(CCodeWindow* _pCodeWindow, wxWindow* parent, - wxWindowID id, const wxString& title, const wxPoint& position, - const wxSize& size, long style) - : wxPanel(parent, id, position, size, style, title) - , m_pCodeWindow(_pCodeWindow) +CBreakPointWindow::CBreakPointWindow(CCodeWindow* _pCodeWindow, wxWindow* parent, wxWindowID id, + const wxString& title, const wxPoint& position, + const wxSize& size, long style) + : wxPanel(parent, id, position, size, style, title), m_pCodeWindow(_pCodeWindow) { - Bind(wxEVT_CLOSE_WINDOW, &CBreakPointWindow::OnClose, this); + Bind(wxEVT_CLOSE_WINDOW, &CBreakPointWindow::OnClose, this); - m_mgr.SetManagedWindow(this); - m_mgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE); + m_mgr.SetManagedWindow(this); + m_mgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE); - m_BreakPointListView = new CBreakPointView(this, wxID_ANY); - m_BreakPointListView->Bind(wxEVT_LIST_ITEM_SELECTED, &CBreakPointWindow::OnSelectBP, this); + m_BreakPointListView = new CBreakPointView(this, wxID_ANY); + m_BreakPointListView->Bind(wxEVT_LIST_ITEM_SELECTED, &CBreakPointWindow::OnSelectBP, this); - m_mgr.AddPane(new CBreakPointBar(this, wxID_ANY), wxAuiPaneInfo().ToolbarPane().Top(). - LeftDockable(true).RightDockable(true).BottomDockable(false).Floatable(false)); - m_mgr.AddPane(m_BreakPointListView, wxAuiPaneInfo().CenterPane()); - m_mgr.Update(); + m_mgr.AddPane(new CBreakPointBar(this, wxID_ANY), wxAuiPaneInfo() + .ToolbarPane() + .Top() + .LeftDockable(true) + .RightDockable(true) + .BottomDockable(false) + .Floatable(false)); + m_mgr.AddPane(m_BreakPointListView, wxAuiPaneInfo().CenterPane()); + m_mgr.Update(); } CBreakPointWindow::~CBreakPointWindow() { - m_mgr.UnInit(); + m_mgr.UnInit(); } void CBreakPointWindow::OnClose(wxCloseEvent& event) { - SaveAll(); - event.Skip(); + SaveAll(); + event.Skip(); } void CBreakPointWindow::NotifyUpdate() { - m_BreakPointListView->Update(); + m_BreakPointListView->Update(); } void CBreakPointWindow::OnDelete(wxCommandEvent& WXUNUSED(event)) { - m_BreakPointListView->DeleteCurrentSelection(); + m_BreakPointListView->DeleteCurrentSelection(); } // jump to begin addr void CBreakPointWindow::OnSelectBP(wxListEvent& event) { - long Index = event.GetIndex(); - if (Index >= 0) - { - u32 Address = (u32)m_BreakPointListView->GetItemData(Index); - if (m_pCodeWindow) - m_pCodeWindow->JumpToAddress(Address); - } + long Index = event.GetIndex(); + if (Index >= 0) + { + u32 Address = (u32)m_BreakPointListView->GetItemData(Index); + if (m_pCodeWindow) + m_pCodeWindow->JumpToAddress(Address); + } } // Clear all breakpoints and memchecks void CBreakPointWindow::OnClear(wxCommandEvent& WXUNUSED(event)) { - PowerPC::debug_interface.ClearAllBreakpoints(); - PowerPC::debug_interface.ClearAllMemChecks(); + PowerPC::debug_interface.ClearAllBreakpoints(); + PowerPC::debug_interface.ClearAllMemChecks(); - NotifyUpdate(); + NotifyUpdate(); } void CBreakPointWindow::OnAddBreakPoint(wxCommandEvent& WXUNUSED(event)) { - BreakPointDlg bpDlg(this); - bpDlg.ShowModal(); + BreakPointDlg bpDlg(this); + bpDlg.ShowModal(); } void CBreakPointWindow::OnAddMemoryCheck(wxCommandEvent& WXUNUSED(event)) { - MemoryCheckDlg memDlg(this); - memDlg.ShowModal(); + MemoryCheckDlg memDlg(this); + memDlg.ShowModal(); } void CBreakPointWindow::Event_SaveAll(wxCommandEvent& WXUNUSED(event)) { - SaveAll(); + SaveAll(); } void CBreakPointWindow::SaveAll() { - // simply dump all to bp/mc files in a way we can read again - IniFile ini; - ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetUniqueID() + ".ini", false); - ini.SetLines("BreakPoints", PowerPC::breakpoints.GetStrings()); - ini.SetLines("MemoryChecks", PowerPC::memchecks.GetStrings()); - ini.Save(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetUniqueID() + ".ini"); + // simply dump all to bp/mc files in a way we can read again + IniFile ini; + ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetUniqueID() + ".ini", + false); + ini.SetLines("BreakPoints", PowerPC::breakpoints.GetStrings()); + ini.SetLines("MemoryChecks", PowerPC::memchecks.GetStrings()); + ini.Save(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetUniqueID() + ".ini"); } void CBreakPointWindow::Event_LoadAll(wxCommandEvent& WXUNUSED(event)) { - LoadAll(); - return; + LoadAll(); + return; } void CBreakPointWindow::LoadAll() { - IniFile ini; - BreakPoints::TBreakPointsStr newbps; - MemChecks::TMemChecksStr newmcs; + IniFile ini; + BreakPoints::TBreakPointsStr newbps; + MemChecks::TMemChecksStr newmcs; - if (!ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetUniqueID() + ".ini", false)) - { - return; - } + if (!ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetUniqueID() + + ".ini", + false)) + { + return; + } - if (ini.GetLines("BreakPoints", &newbps, false)) - { - PowerPC::breakpoints.Clear(); - PowerPC::breakpoints.AddFromStrings(newbps); - } + if (ini.GetLines("BreakPoints", &newbps, false)) + { + PowerPC::breakpoints.Clear(); + PowerPC::breakpoints.AddFromStrings(newbps); + } - if (ini.GetLines("MemoryChecks", &newmcs, false)) - { - PowerPC::memchecks.Clear(); - PowerPC::memchecks.AddFromStrings(newmcs); - } + if (ini.GetLines("MemoryChecks", &newmcs, false)) + { + PowerPC::memchecks.Clear(); + PowerPC::memchecks.AddFromStrings(newmcs); + } - NotifyUpdate(); + NotifyUpdate(); } diff --git a/Source/Core/DolphinWX/Debugger/BreakpointWindow.h b/Source/Core/DolphinWX/Debugger/BreakpointWindow.h index cfdbe6ef80..67b8cb912f 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointWindow.h +++ b/Source/Core/DolphinWX/Debugger/BreakpointWindow.h @@ -4,8 +4,8 @@ #pragma once -#include #include +#include class CBreakPointView; class CCodeWindow; @@ -14,32 +14,28 @@ class wxListEvent; class CBreakPointWindow : public wxPanel { public: + CBreakPointWindow(CCodeWindow* _pCodeWindow, wxWindow* parent, wxWindowID id = wxID_ANY, + const wxString& title = _("Breakpoints"), + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxTAB_TRAVERSAL | wxBORDER_NONE); + ~CBreakPointWindow(); - CBreakPointWindow(CCodeWindow* _pCodeWindow, - wxWindow* parent, - wxWindowID id = wxID_ANY, - const wxString& title = _("Breakpoints"), - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxTAB_TRAVERSAL | wxBORDER_NONE); - ~CBreakPointWindow(); + void NotifyUpdate(); - void NotifyUpdate(); - - void OnDelete(wxCommandEvent& WXUNUSED(event)); - void OnClear(wxCommandEvent& WXUNUSED(event)); - void OnAddBreakPoint(wxCommandEvent& WXUNUSED(event)); - void OnAddMemoryCheck(wxCommandEvent& WXUNUSED(event)); - void Event_SaveAll(wxCommandEvent& WXUNUSED(event)); - void SaveAll(); - void Event_LoadAll(wxCommandEvent& WXUNUSED(event)); - void LoadAll(); + void OnDelete(wxCommandEvent& WXUNUSED(event)); + void OnClear(wxCommandEvent& WXUNUSED(event)); + void OnAddBreakPoint(wxCommandEvent& WXUNUSED(event)); + void OnAddMemoryCheck(wxCommandEvent& WXUNUSED(event)); + void Event_SaveAll(wxCommandEvent& WXUNUSED(event)); + void SaveAll(); + void Event_LoadAll(wxCommandEvent& WXUNUSED(event)); + void LoadAll(); private: - wxAuiManager m_mgr; - CBreakPointView* m_BreakPointListView; - CCodeWindow* m_pCodeWindow; + wxAuiManager m_mgr; + CBreakPointView* m_BreakPointListView; + CCodeWindow* m_pCodeWindow; - void OnClose(wxCloseEvent& event); - void OnSelectBP(wxListEvent& event); + void OnClose(wxCloseEvent& event); + void OnSelectBP(wxListEvent& event); }; diff --git a/Source/Core/DolphinWX/Debugger/CodeView.cpp b/Source/Core/DolphinWX/Debugger/CodeView.cpp index 4ec232ee89..2eb9ad093d 100644 --- a/Source/Core/DolphinWX/Debugger/CodeView.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeView.cpp @@ -25,576 +25,570 @@ #include "Common/SymbolDB.h" #include "Core/Core.h" #include "Core/Host.h" -#include "DolphinWX/Globals.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Debugger/CodeView.h" #include "DolphinWX/Debugger/DebuggerUIUtil.h" +#include "DolphinWX/Globals.h" +#include "DolphinWX/WxUtils.h" wxDEFINE_EVENT(wxEVT_CODEVIEW_CHANGE, wxCommandEvent); enum { - IDM_GOTOINMEMVIEW = 12000, - IDM_COPYADDRESS, - IDM_COPYHEX, - IDM_COPYCODE, - IDM_INSERTBLR, IDM_INSERTNOP, - IDM_RUNTOHERE, - IDM_JITRESULTS, - IDM_FOLLOWBRANCH, - IDM_RENAMESYMBOL, - IDM_PATCHALERT, - IDM_COPYFUNCTION, - IDM_ADDFUNCTION, + IDM_GOTOINMEMVIEW = 12000, + IDM_COPYADDRESS, + IDM_COPYHEX, + IDM_COPYCODE, + IDM_INSERTBLR, + IDM_INSERTNOP, + IDM_RUNTOHERE, + IDM_JITRESULTS, + IDM_FOLLOWBRANCH, + IDM_RENAMESYMBOL, + IDM_PATCHALERT, + IDM_COPYFUNCTION, + IDM_ADDFUNCTION, }; -CCodeView::CCodeView(DebugInterface* debuginterface, SymbolDB *symboldb, - wxWindow* parent, wxWindowID Id) - : wxControl(parent, Id), - m_debugger(debuginterface), - m_symbol_db(symboldb), - m_plain(false), - m_curAddress(debuginterface->GetPC()), - m_align(debuginterface->GetInstructionSize(0)), - m_rowHeight(13), - m_selection(0), - m_oldSelection(0), - m_selecting(false), - m_lx(-1), - m_ly(-1) +CCodeView::CCodeView(DebugInterface* debuginterface, SymbolDB* symboldb, wxWindow* parent, + wxWindowID Id) + : wxControl(parent, Id), m_debugger(debuginterface), m_symbol_db(symboldb), m_plain(false), + m_curAddress(debuginterface->GetPC()), m_align(debuginterface->GetInstructionSize(0)), + m_rowHeight(13), m_selection(0), m_oldSelection(0), m_selecting(false), m_lx(-1), m_ly(-1) { - Bind(wxEVT_ERASE_BACKGROUND, &CCodeView::OnErase, this); - Bind(wxEVT_PAINT, &CCodeView::OnPaint, this); - Bind(wxEVT_MOUSEWHEEL, &CCodeView::OnScrollWheel, this); - Bind(wxEVT_LEFT_DOWN, &CCodeView::OnMouseDown, this); - Bind(wxEVT_LEFT_UP, &CCodeView::OnMouseUpL, this); - Bind(wxEVT_MOTION, &CCodeView::OnMouseMove, this); - Bind(wxEVT_RIGHT_DOWN, &CCodeView::OnMouseDown, this); - Bind(wxEVT_RIGHT_UP, &CCodeView::OnMouseUpR, this); - Bind(wxEVT_MENU, &CCodeView::OnPopupMenu, this); - Bind(wxEVT_SIZE, &CCodeView::OnResize, this); + Bind(wxEVT_ERASE_BACKGROUND, &CCodeView::OnErase, this); + Bind(wxEVT_PAINT, &CCodeView::OnPaint, this); + Bind(wxEVT_MOUSEWHEEL, &CCodeView::OnScrollWheel, this); + Bind(wxEVT_LEFT_DOWN, &CCodeView::OnMouseDown, this); + Bind(wxEVT_LEFT_UP, &CCodeView::OnMouseUpL, this); + Bind(wxEVT_MOTION, &CCodeView::OnMouseMove, this); + Bind(wxEVT_RIGHT_DOWN, &CCodeView::OnMouseDown, this); + Bind(wxEVT_RIGHT_UP, &CCodeView::OnMouseUpR, this); + Bind(wxEVT_MENU, &CCodeView::OnPopupMenu, this); + Bind(wxEVT_SIZE, &CCodeView::OnResize, this); } int CCodeView::YToAddress(int y) { - wxRect rc = GetClientRect(); - int ydiff = y - rc.height / 2 - m_rowHeight / 2; - ydiff = (int)(floorf((float)ydiff / (float)m_rowHeight)) + 1; - return m_curAddress + ydiff * m_align; + wxRect rc = GetClientRect(); + int ydiff = y - rc.height / 2 - m_rowHeight / 2; + ydiff = (int)(floorf((float)ydiff / (float)m_rowHeight)) + 1; + return m_curAddress + ydiff * m_align; } void CCodeView::OnMouseDown(wxMouseEvent& event) { - int x = event.m_x; - int y = event.m_y; + int x = event.m_x; + int y = event.m_y; - if (x > 16) - { - m_oldSelection = m_selection; - m_selection = YToAddress(y); - // SetCapture(wnd); - bool oldselecting = m_selecting; - m_selecting = true; + if (x > 16) + { + m_oldSelection = m_selection; + m_selection = YToAddress(y); + // SetCapture(wnd); + bool oldselecting = m_selecting; + m_selecting = true; - if (!oldselecting || (m_selection != m_oldSelection)) - Refresh(); - } - else - { - ToggleBreakpoint(YToAddress(y)); - } + if (!oldselecting || (m_selection != m_oldSelection)) + Refresh(); + } + else + { + ToggleBreakpoint(YToAddress(y)); + } - event.Skip(); + event.Skip(); } void CCodeView::OnScrollWheel(wxMouseEvent& event) { - const bool scroll_down = (event.GetWheelRotation() < 0); - const int num_lines = event.GetLinesPerAction(); + const bool scroll_down = (event.GetWheelRotation() < 0); + const int num_lines = event.GetLinesPerAction(); - if (scroll_down) - { - m_curAddress += num_lines * 4; - } - else - { - m_curAddress -= num_lines * 4; - } + if (scroll_down) + { + m_curAddress += num_lines * 4; + } + else + { + m_curAddress -= num_lines * 4; + } - Refresh(); - event.Skip(); + Refresh(); + event.Skip(); } void CCodeView::ToggleBreakpoint(u32 address) { - m_debugger->ToggleBreakpoint(address); - Refresh(); + m_debugger->ToggleBreakpoint(address); + Refresh(); - // Propagate back to the parent window to update the breakpoint list. - wxCommandEvent evt(wxEVT_HOST_COMMAND, IDM_UPDATE_BREAKPOINTS); - GetEventHandler()->AddPendingEvent(evt); + // Propagate back to the parent window to update the breakpoint list. + wxCommandEvent evt(wxEVT_HOST_COMMAND, IDM_UPDATE_BREAKPOINTS); + GetEventHandler()->AddPendingEvent(evt); } void CCodeView::OnMouseMove(wxMouseEvent& event) { - wxRect rc = GetClientRect(); + wxRect rc = GetClientRect(); - if (event.m_leftDown && event.m_x > 16) - { - if (event.m_y < 0) - { - m_curAddress -= m_align; - Refresh(); - } - else if (event.m_y > rc.height) - { - m_curAddress += m_align; - Refresh(); - } - else - { - OnMouseDown(event); - } - } + if (event.m_leftDown && event.m_x > 16) + { + if (event.m_y < 0) + { + m_curAddress -= m_align; + Refresh(); + } + else if (event.m_y > rc.height) + { + m_curAddress += m_align; + Refresh(); + } + else + { + OnMouseDown(event); + } + } - event.Skip(); + event.Skip(); } void CCodeView::RaiseEvent() { - wxCommandEvent ev(wxEVT_CODEVIEW_CHANGE, GetId()); - ev.SetEventObject(this); - ev.SetInt(m_selection); - GetEventHandler()->ProcessEvent(ev); + wxCommandEvent ev(wxEVT_CODEVIEW_CHANGE, GetId()); + ev.SetEventObject(this); + ev.SetInt(m_selection); + GetEventHandler()->ProcessEvent(ev); } void CCodeView::OnMouseUpL(wxMouseEvent& event) { - if (event.m_x > 16) - { - m_curAddress = YToAddress(event.m_y); - m_selecting = false; - Refresh(); - } + if (event.m_x > 16) + { + m_curAddress = YToAddress(event.m_y); + m_selecting = false; + Refresh(); + } - RaiseEvent(); - event.Skip(); + RaiseEvent(); + event.Skip(); } u32 CCodeView::AddrToBranch(u32 addr) { - std::string disasm = m_debugger->Disassemble(addr); - size_t pos = disasm.find("->0x"); + std::string disasm = m_debugger->Disassemble(addr); + size_t pos = disasm.find("->0x"); - if (pos != std::string::npos) - { - std::string hex = disasm.substr(pos + 2); - return std::stoul(hex, nullptr, 16); - } + if (pos != std::string::npos) + { + std::string hex = disasm.substr(pos + 2); + return std::stoul(hex, nullptr, 16); + } - return 0; + return 0; } void CCodeView::InsertBlrNop(int Blr) { - // Check if this address has been modified - int find = -1; - for (u32 i = 0; i < m_blrList.size(); i++) - { - if (m_blrList.at(i).address == m_selection) - { - find = i; - break; - } - } + // Check if this address has been modified + int find = -1; + for (u32 i = 0; i < m_blrList.size(); i++) + { + if (m_blrList.at(i).address == m_selection) + { + find = i; + break; + } + } - // Save the old value - if (find >= 0) - { - m_debugger->WriteExtraMemory(0, m_blrList.at(find).oldValue, m_selection); - m_blrList.erase(m_blrList.begin() + find); - } - else - { - BlrStruct temp; - temp.address = m_selection; - temp.oldValue = m_debugger->ReadMemory(m_selection); - m_blrList.push_back(temp); - if (Blr == 0) - m_debugger->InsertBLR(m_selection, 0x4e800020); - else - m_debugger->InsertBLR(m_selection, 0x60000000); - } - Refresh(); + // Save the old value + if (find >= 0) + { + m_debugger->WriteExtraMemory(0, m_blrList.at(find).oldValue, m_selection); + m_blrList.erase(m_blrList.begin() + find); + } + else + { + BlrStruct temp; + temp.address = m_selection; + temp.oldValue = m_debugger->ReadMemory(m_selection); + m_blrList.push_back(temp); + if (Blr == 0) + m_debugger->InsertBLR(m_selection, 0x4e800020); + else + m_debugger->InsertBLR(m_selection, 0x60000000); + } + Refresh(); } void CCodeView::OnPopupMenu(wxCommandEvent& event) { #if wxUSE_CLIPBOARD - wxTheClipboard->Open(); + wxTheClipboard->Open(); #endif - switch (event.GetId()) - { - case IDM_GOTOINMEMVIEW: - // CMemoryDlg::Goto(selection); - break; + switch (event.GetId()) + { + case IDM_GOTOINMEMVIEW: + // CMemoryDlg::Goto(selection); + break; #if wxUSE_CLIPBOARD - case IDM_COPYADDRESS: - wxTheClipboard->SetData(new wxTextDataObject(wxString::Format("%08x", m_selection))); - break; + case IDM_COPYADDRESS: + wxTheClipboard->SetData(new wxTextDataObject(wxString::Format("%08x", m_selection))); + break; - case IDM_COPYCODE: - { - std::string disasm = m_debugger->Disassemble(m_selection); - wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(disasm))); - } - break; + case IDM_COPYCODE: + { + std::string disasm = m_debugger->Disassemble(m_selection); + wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(disasm))); + } + break; - case IDM_COPYHEX: - { - std::string temp = StringFromFormat("%08x", m_debugger->ReadInstruction(m_selection)); - wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(temp))); - } - break; + case IDM_COPYHEX: + { + std::string temp = StringFromFormat("%08x", m_debugger->ReadInstruction(m_selection)); + wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(temp))); + } + break; - - case IDM_COPYFUNCTION: - { - Symbol *symbol = m_symbol_db->GetSymbolFromAddr(m_selection); - if (symbol) - { - std::string text; - text = text + symbol->name + "\r\n"; - // we got a function - u32 start = symbol->address; - u32 end = start + symbol->size; - for (u32 addr = start; addr != end; addr += 4) - { - std::string disasm = m_debugger->Disassemble(addr); - text += StringFromFormat("%08x: ", addr) + disasm + "\r\n"; - } - wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(text))); - } - } - break; + case IDM_COPYFUNCTION: + { + Symbol* symbol = m_symbol_db->GetSymbolFromAddr(m_selection); + if (symbol) + { + std::string text; + text = text + symbol->name + "\r\n"; + // we got a function + u32 start = symbol->address; + u32 end = start + symbol->size; + for (u32 addr = start; addr != end; addr += 4) + { + std::string disasm = m_debugger->Disassemble(addr); + text += StringFromFormat("%08x: ", addr) + disasm + "\r\n"; + } + wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(text))); + } + } + break; #endif - case IDM_RUNTOHERE: - m_debugger->SetBreakpoint(m_selection); - m_debugger->RunToBreakpoint(); - Refresh(); - break; + case IDM_RUNTOHERE: + m_debugger->SetBreakpoint(m_selection); + m_debugger->RunToBreakpoint(); + Refresh(); + break; - // Insert blr or restore old value - case IDM_INSERTBLR: - InsertBlrNop(0); - Refresh(); - break; - case IDM_INSERTNOP: - InsertBlrNop(1); - Refresh(); - break; + // Insert blr or restore old value + case IDM_INSERTBLR: + InsertBlrNop(0); + Refresh(); + break; + case IDM_INSERTNOP: + InsertBlrNop(1); + Refresh(); + break; - case IDM_JITRESULTS: - { - // Propagate back to the parent window and tell it - // to flip to the JIT tab for the current address. - wxCommandEvent jit_event(wxEVT_HOST_COMMAND, IDM_UPDATE_JIT_PANE); - GetEventHandler()->AddPendingEvent(jit_event); - } - break; + case IDM_JITRESULTS: + { + // Propagate back to the parent window and tell it + // to flip to the JIT tab for the current address. + wxCommandEvent jit_event(wxEVT_HOST_COMMAND, IDM_UPDATE_JIT_PANE); + GetEventHandler()->AddPendingEvent(jit_event); + } + break; - case IDM_FOLLOWBRANCH: - { - u32 dest = AddrToBranch(m_selection); - if (dest) - { - Center(dest); - RaiseEvent(); - } - } - break; + case IDM_FOLLOWBRANCH: + { + u32 dest = AddrToBranch(m_selection); + if (dest) + { + Center(dest); + RaiseEvent(); + } + } + break; - case IDM_ADDFUNCTION: - m_symbol_db->AddFunction(m_selection); - Host_NotifyMapLoaded(); - break; + case IDM_ADDFUNCTION: + m_symbol_db->AddFunction(m_selection); + Host_NotifyMapLoaded(); + break; - case IDM_RENAMESYMBOL: - { - Symbol *symbol = m_symbol_db->GetSymbolFromAddr(m_selection); - if (symbol) - { - wxTextEntryDialog input_symbol(this, _("Rename symbol:"), - wxGetTextFromUserPromptStr, - StrToWxStr(symbol->name)); - if (input_symbol.ShowModal() == wxID_OK) - { - symbol->name = WxStrToStr(input_symbol.GetValue()); - Refresh(); // Redraw to show the renamed symbol - } - Host_NotifyMapLoaded(); - } - } - break; + case IDM_RENAMESYMBOL: + { + Symbol* symbol = m_symbol_db->GetSymbolFromAddr(m_selection); + if (symbol) + { + wxTextEntryDialog input_symbol(this, _("Rename symbol:"), wxGetTextFromUserPromptStr, + StrToWxStr(symbol->name)); + if (input_symbol.ShowModal() == wxID_OK) + { + symbol->name = WxStrToStr(input_symbol.GetValue()); + Refresh(); // Redraw to show the renamed symbol + } + Host_NotifyMapLoaded(); + } + } + break; - case IDM_PATCHALERT: - break; - } + case IDM_PATCHALERT: + break; + } #if wxUSE_CLIPBOARD - wxTheClipboard->Close(); + wxTheClipboard->Close(); #endif - event.Skip(); + event.Skip(); } void CCodeView::OnMouseUpR(wxMouseEvent& event) { - bool isSymbol = m_symbol_db->GetSymbolFromAddr(m_selection) != nullptr; - // popup menu - wxMenu menu; - //menu->Append(IDM_GOTOINMEMVIEW, "&Goto in mem view"); - menu.Append(IDM_FOLLOWBRANCH, _("&Follow branch"))->Enable(AddrToBranch(m_selection) ? true : false); - menu.AppendSeparator(); + bool isSymbol = m_symbol_db->GetSymbolFromAddr(m_selection) != nullptr; + // popup menu + wxMenu menu; + // menu->Append(IDM_GOTOINMEMVIEW, "&Goto in mem view"); + menu.Append(IDM_FOLLOWBRANCH, _("&Follow branch")) + ->Enable(AddrToBranch(m_selection) ? true : false); + menu.AppendSeparator(); #if wxUSE_CLIPBOARD - menu.Append(IDM_COPYADDRESS, _("Copy &address")); - menu.Append(IDM_COPYFUNCTION, _("Copy &function"))->Enable(isSymbol); - menu.Append(IDM_COPYCODE, _("Copy &code line")); - menu.Append(IDM_COPYHEX, _("Copy &hex")); - menu.AppendSeparator(); + menu.Append(IDM_COPYADDRESS, _("Copy &address")); + menu.Append(IDM_COPYFUNCTION, _("Copy &function"))->Enable(isSymbol); + menu.Append(IDM_COPYCODE, _("Copy &code line")); + menu.Append(IDM_COPYHEX, _("Copy &hex")); + menu.AppendSeparator(); #endif - menu.Append(IDM_RENAMESYMBOL, _("Rename &symbol"))->Enable(isSymbol); - menu.AppendSeparator(); - menu.Append(IDM_RUNTOHERE, _("&Run To Here"))->Enable(Core::IsRunning()); - menu.Append(IDM_ADDFUNCTION, _("&Add function"))->Enable(Core::IsRunning()); - menu.Append(IDM_JITRESULTS, _("PPC vs X86"))->Enable(Core::IsRunning()); - menu.Append(IDM_INSERTBLR, _("Insert &blr"))->Enable(Core::IsRunning()); - menu.Append(IDM_INSERTNOP, _("Insert &nop"))->Enable(Core::IsRunning()); - menu.Append(IDM_PATCHALERT, _("Patch alert"))->Enable(Core::IsRunning()); - PopupMenu(&menu); - event.Skip(); + menu.Append(IDM_RENAMESYMBOL, _("Rename &symbol"))->Enable(isSymbol); + menu.AppendSeparator(); + menu.Append(IDM_RUNTOHERE, _("&Run To Here"))->Enable(Core::IsRunning()); + menu.Append(IDM_ADDFUNCTION, _("&Add function"))->Enable(Core::IsRunning()); + menu.Append(IDM_JITRESULTS, _("PPC vs X86"))->Enable(Core::IsRunning()); + menu.Append(IDM_INSERTBLR, _("Insert &blr"))->Enable(Core::IsRunning()); + menu.Append(IDM_INSERTNOP, _("Insert &nop"))->Enable(Core::IsRunning()); + menu.Append(IDM_PATCHALERT, _("Patch alert"))->Enable(Core::IsRunning()); + PopupMenu(&menu); + event.Skip(); } void CCodeView::OnErase(wxEraseEvent& event) -{} +{ +} void CCodeView::OnPaint(wxPaintEvent& event) { - // ------------------------- - // General settings - // ------------------------- - std::unique_ptr ctx(wxGraphicsContext::Create(wxPaintDC(this))); - wxRect rc = GetClientRect(); + // ------------------------- + // General settings + // ------------------------- + std::unique_ptr ctx(wxGraphicsContext::Create(wxPaintDC(this))); + wxRect rc = GetClientRect(); - ctx->SetFont(DebuggerFont, *wxBLACK); + ctx->SetFont(DebuggerFont, *wxBLACK); - wxDouble w,h; - ctx->GetTextExtent("0WJyq", &w, &h); + wxDouble w, h; + ctx->GetTextExtent("0WJyq", &w, &h); - if (h > m_rowHeight) - m_rowHeight = h; + if (h > m_rowHeight) + m_rowHeight = h; - ctx->GetTextExtent("W", &w, &h); - int charWidth = w; + ctx->GetTextExtent("W", &w, &h); + int charWidth = w; - struct branch - { - int src, dst, srcAddr; - }; + struct branch + { + int src, dst, srcAddr; + }; - branch branches[256]; - int numBranches = 0; - // TODO: Add any drawing code here... - int width = rc.width; - int numRows = ((rc.height / m_rowHeight) / 2) + 2; - // ------------ + branch branches[256]; + int numBranches = 0; + // TODO: Add any drawing code here... + int width = rc.width; + int numRows = ((rc.height / m_rowHeight) / 2) + 2; + // ------------ - // ------------------------- - // Colors and brushes - // ------------------------- + // ------------------------- + // Colors and brushes + // ------------------------- - const wxColour bgColor = *wxWHITE; - wxPen nullPen(bgColor); - wxPen currentPen(*wxBLACK_PEN); - wxPen selPen(*wxGREY_PEN); - nullPen.SetStyle(wxTRANSPARENT); - currentPen.SetStyle(wxSOLID); - wxBrush currentBrush(*wxLIGHT_GREY_BRUSH); - wxBrush pcBrush(*wxGREEN_BRUSH); - wxBrush bpBrush(*wxRED_BRUSH); + const wxColour bgColor = *wxWHITE; + wxPen nullPen(bgColor); + wxPen currentPen(*wxBLACK_PEN); + wxPen selPen(*wxGREY_PEN); + nullPen.SetStyle(wxTRANSPARENT); + currentPen.SetStyle(wxSOLID); + wxBrush currentBrush(*wxLIGHT_GREY_BRUSH); + wxBrush pcBrush(*wxGREEN_BRUSH); + wxBrush bpBrush(*wxRED_BRUSH); - wxBrush bgBrush(bgColor); - wxBrush nullBrush(bgColor); - nullBrush.SetStyle(wxTRANSPARENT); + wxBrush bgBrush(bgColor); + wxBrush nullBrush(bgColor); + nullBrush.SetStyle(wxTRANSPARENT); - ctx->SetPen(nullPen); - ctx->SetBrush(bgBrush); - ctx->DrawRectangle(0, 0, 16, rc.height); - ctx->DrawRectangle(0, 0, rc.width, 5); - // ------------ + ctx->SetPen(nullPen); + ctx->SetBrush(bgBrush); + ctx->DrawRectangle(0, 0, 16, rc.height); + ctx->DrawRectangle(0, 0, rc.width, 5); + // ------------ - // ----------------------------- - // Walk through all visible rows - // ----------------------------- - for (int i = -numRows; i <= numRows; i++) - { - unsigned int address = m_curAddress + (i * m_align); + // ----------------------------- + // Walk through all visible rows + // ----------------------------- + for (int i = -numRows; i <= numRows; i++) + { + unsigned int address = m_curAddress + (i * m_align); - int rowY1 = (rc.height / 2) + (m_rowHeight * i) - (m_rowHeight / 2); - int rowY2 = (rc.height / 2) + (m_rowHeight * i) + (m_rowHeight / 2); + int rowY1 = (rc.height / 2) + (m_rowHeight * i) - (m_rowHeight / 2); + int rowY2 = (rc.height / 2) + (m_rowHeight * i) + (m_rowHeight / 2); - wxString temp = wxString::Format("%08x", address); - u32 color = m_debugger->GetColor(address); - wxBrush rowBrush(wxColour(color >> 16, color >> 8, color)); - ctx->SetBrush(nullBrush); - ctx->SetPen(nullPen); - ctx->DrawRectangle(0, rowY1, 16, rowY2 - rowY1 + 2); + wxString temp = wxString::Format("%08x", address); + u32 color = m_debugger->GetColor(address); + wxBrush rowBrush(wxColour(color >> 16, color >> 8, color)); + ctx->SetBrush(nullBrush); + ctx->SetPen(nullPen); + ctx->DrawRectangle(0, rowY1, 16, rowY2 - rowY1 + 2); - if (m_selecting && (address == m_selection)) - ctx->SetPen(selPen); - else - ctx->SetPen(i == 0 ? currentPen : nullPen); + if (m_selecting && (address == m_selection)) + ctx->SetPen(selPen); + else + ctx->SetPen(i == 0 ? currentPen : nullPen); - if (address == m_debugger->GetPC()) - ctx->SetBrush(pcBrush); - else - ctx->SetBrush(rowBrush); + if (address == m_debugger->GetPC()) + ctx->SetBrush(pcBrush); + else + ctx->SetBrush(rowBrush); - ctx->DrawRectangle(16, rowY1, width, rowY2 - rowY1 + 1); - ctx->SetBrush(currentBrush); - if (!m_plain) - { - // the address text is dark red - ctx->SetFont(DebuggerFont, wxColour("#600000")); - ctx->DrawText(temp, 17, rowY1); - ctx->SetFont(DebuggerFont, *wxBLACK); - } + ctx->DrawRectangle(16, rowY1, width, rowY2 - rowY1 + 1); + ctx->SetBrush(currentBrush); + if (!m_plain) + { + // the address text is dark red + ctx->SetFont(DebuggerFont, wxColour("#600000")); + ctx->DrawText(temp, 17, rowY1); + ctx->SetFont(DebuggerFont, *wxBLACK); + } - // If running - if (m_debugger->IsAlive()) - { - std::vector dis; - SplitString(m_debugger->Disassemble(address), '\t', dis); - dis.resize(2); + // If running + if (m_debugger->IsAlive()) + { + std::vector dis; + SplitString(m_debugger->Disassemble(address), '\t', dis); + dis.resize(2); - static const size_t VALID_BRANCH_LENGTH = 10; - const std::string& opcode = dis[0]; - const std::string& operands = dis[1]; - std::string desc; + static const size_t VALID_BRANCH_LENGTH = 10; + const std::string& opcode = dis[0]; + const std::string& operands = dis[1]; + std::string desc; - // look for hex strings to decode branches - std::string hex_str; - size_t pos = operands.find("0x8"); - if (pos != std::string::npos) - { - hex_str = operands.substr(pos); - } + // look for hex strings to decode branches + std::string hex_str; + size_t pos = operands.find("0x8"); + if (pos != std::string::npos) + { + hex_str = operands.substr(pos); + } - if (hex_str.length() == VALID_BRANCH_LENGTH) - { - u32 offs = std::stoul(hex_str, nullptr, 16); + if (hex_str.length() == VALID_BRANCH_LENGTH) + { + u32 offs = std::stoul(hex_str, nullptr, 16); - branches[numBranches].src = rowY1 + (m_rowHeight / 2); - branches[numBranches].srcAddr = (address / m_align); - branches[numBranches++].dst = (int)(rowY1 + ((s64)(u32)offs - (s64)(u32)address) * m_rowHeight / m_align + m_rowHeight / 2); - desc = StringFromFormat("-->%s", m_debugger->GetDescription(offs).c_str()); + branches[numBranches].src = rowY1 + (m_rowHeight / 2); + branches[numBranches].srcAddr = (address / m_align); + branches[numBranches++].dst = + (int)(rowY1 + ((s64)(u32)offs - (s64)(u32)address) * m_rowHeight / m_align + + m_rowHeight / 2); + desc = StringFromFormat("-->%s", m_debugger->GetDescription(offs).c_str()); - // the -> arrow illustrations are purple - ctx->SetFont(DebuggerFont, wxTheColourDatabase->Find("PURPLE")); - } - else - { - ctx->SetFont(DebuggerFont, *wxBLACK); - } + // the -> arrow illustrations are purple + ctx->SetFont(DebuggerFont, wxTheColourDatabase->Find("PURPLE")); + } + else + { + ctx->SetFont(DebuggerFont, *wxBLACK); + } - ctx->DrawText(StrToWxStr(operands), 17 + 17*charWidth, rowY1); - // ------------ + ctx->DrawText(StrToWxStr(operands), 17 + 17 * charWidth, rowY1); + // ------------ - // Show blr as its' own color - if (opcode == "blr") - ctx->SetFont(DebuggerFont, wxTheColourDatabase->Find("DARK GREEN")); - else - ctx->SetFont(DebuggerFont, wxTheColourDatabase->Find("VIOLET")); + // Show blr as its' own color + if (opcode == "blr") + ctx->SetFont(DebuggerFont, wxTheColourDatabase->Find("DARK GREEN")); + else + ctx->SetFont(DebuggerFont, wxTheColourDatabase->Find("VIOLET")); - ctx->DrawText(StrToWxStr(opcode), 17 + (m_plain ? 1*charWidth : 9*charWidth), rowY1); + ctx->DrawText(StrToWxStr(opcode), 17 + (m_plain ? 1 * charWidth : 9 * charWidth), rowY1); - if (desc.empty()) - { - desc = m_debugger->GetDescription(address); - } + if (desc.empty()) + { + desc = m_debugger->GetDescription(address); + } - if (!m_plain) - { - ctx->SetFont(DebuggerFont, *wxBLUE); + if (!m_plain) + { + ctx->SetFont(DebuggerFont, *wxBLUE); - //char temp[256]; - //UnDecorateSymbolName(desc,temp,255,UNDNAME_COMPLETE); - if (!desc.empty()) - { - ctx->DrawText(StrToWxStr(desc), 17 + 35 * charWidth, rowY1); - } - } + // char temp[256]; + // UnDecorateSymbolName(desc,temp,255,UNDNAME_COMPLETE); + if (!desc.empty()) + { + ctx->DrawText(StrToWxStr(desc), 17 + 35 * charWidth, rowY1); + } + } - // Show red breakpoint dot - if (m_debugger->IsBreakpoint(address)) - { - ctx->SetBrush(bpBrush); - ctx->DrawRectangle(2, rowY1 + 1, 11, 11); - } - } - } // end of for - // ------------ + // Show red breakpoint dot + if (m_debugger->IsBreakpoint(address)) + { + ctx->SetBrush(bpBrush); + ctx->DrawRectangle(2, rowY1 + 1, 11, 11); + } + } + } // end of for + // ------------ - // ------------------------- - // Colors and brushes - // ------------------------- - ctx->SetPen(currentPen); + // ------------------------- + // Colors and brushes + // ------------------------- + ctx->SetPen(currentPen); - for (int i = 0; i < numBranches; i++) - { - int x = 17 + 49 * charWidth + (branches[i].srcAddr % 9) * 8; - MoveTo(x-2, branches[i].src); + for (int i = 0; i < numBranches; i++) + { + int x = 17 + 49 * charWidth + (branches[i].srcAddr % 9) * 8; + MoveTo(x - 2, branches[i].src); - if (branches[i].dst < rc.height + 400 && branches[i].dst > -400) - { - LineTo(ctx, x+2, branches[i].src); - LineTo(ctx, x+2, branches[i].dst); - LineTo(ctx, x-4, branches[i].dst); + if (branches[i].dst < rc.height + 400 && branches[i].dst > -400) + { + LineTo(ctx, x + 2, branches[i].src); + LineTo(ctx, x + 2, branches[i].dst); + LineTo(ctx, x - 4, branches[i].dst); - MoveTo(x, branches[i].dst - 4); - LineTo(ctx, x-4, branches[i].dst); - LineTo(ctx, x+1, branches[i].dst+5); - } - //else - //{ - // This can be re-enabled when there is a scrollbar or - // something on the codeview (the lines are too long) + MoveTo(x, branches[i].dst - 4); + LineTo(ctx, x - 4, branches[i].dst); + LineTo(ctx, x + 1, branches[i].dst + 5); + } + // else + //{ + // This can be re-enabled when there is a scrollbar or + // something on the codeview (the lines are too long) - //LineTo(ctx, x+4, branches[i].src); - //MoveTo(x+2, branches[i].dst-4); - //LineTo(ctx, x+6, branches[i].dst); - //LineTo(ctx, x+1, branches[i].dst+5); - //} + // LineTo(ctx, x+4, branches[i].src); + // MoveTo(x+2, branches[i].dst-4); + // LineTo(ctx, x+6, branches[i].dst); + // LineTo(ctx, x+1, branches[i].dst+5); + //} - //LineTo(ctx, x, branches[i].dst+4); - //LineTo(ctx, x-2, branches[i].dst); - } - // ------------ + // LineTo(ctx, x, branches[i].dst+4); + // LineTo(ctx, x-2, branches[i].dst); + } + // ------------ } void CCodeView::LineTo(std::unique_ptr& ctx, int x, int y) { - std::vector points { wxPoint2DDouble(m_lx, m_ly), wxPoint2DDouble(x, y) }; + std::vector points{wxPoint2DDouble(m_lx, m_ly), wxPoint2DDouble(x, y)}; - ctx->DrawLines(points.size(), points.data()); - m_lx = x; - m_ly = y; + ctx->DrawLines(points.size(), points.data()); + m_lx = x; + m_ly = y; } void CCodeView::OnResize(wxSizeEvent& event) { - Refresh(); - event.Skip(); + Refresh(); + event.Skip(); } diff --git a/Source/Core/DolphinWX/Debugger/CodeView.h b/Source/Core/DolphinWX/Debugger/CodeView.h index 37993648a6..a29053dd1f 100644 --- a/Source/Core/DolphinWX/Debugger/CodeView.h +++ b/Source/Core/DolphinWX/Debugger/CodeView.h @@ -24,72 +24,64 @@ class wxPaintDC; class CCodeView : public wxControl { public: - CCodeView(DebugInterface* debuginterface, SymbolDB *symbol_db, - wxWindow* parent, wxWindowID Id = wxID_ANY); + CCodeView(DebugInterface* debuginterface, SymbolDB* symbol_db, wxWindow* parent, + wxWindowID Id = wxID_ANY); - void ToggleBreakpoint(u32 address); + void ToggleBreakpoint(u32 address); - u32 GetSelection() const - { - return m_selection; - } - - void Center(u32 addr) - { - m_curAddress = addr; - m_selection = addr; - Refresh(); - } - - void SetPlain() - { - m_plain = true; - } + u32 GetSelection() const { return m_selection; } + void Center(u32 addr) + { + m_curAddress = addr; + m_selection = addr; + Refresh(); + } + void SetPlain() { m_plain = true; } private: - void OnPaint(wxPaintEvent& event); - void OnErase(wxEraseEvent& event); - void OnScrollWheel(wxMouseEvent& event); - void OnMouseDown(wxMouseEvent& event); - void OnMouseMove(wxMouseEvent& event); - void OnMouseUpL(wxMouseEvent& event); - void OnMouseUpR(wxMouseEvent& event); - void OnPopupMenu(wxCommandEvent& event); - void InsertBlrNop(int); + void OnPaint(wxPaintEvent& event); + void OnErase(wxEraseEvent& event); + void OnScrollWheel(wxMouseEvent& event); + void OnMouseDown(wxMouseEvent& event); + void OnMouseMove(wxMouseEvent& event); + void OnMouseUpL(wxMouseEvent& event); + void OnMouseUpR(wxMouseEvent& event); + void OnPopupMenu(wxCommandEvent& event); + void InsertBlrNop(int); - void RaiseEvent(); - int YToAddress(int y); + void RaiseEvent(); + int YToAddress(int y); - u32 AddrToBranch(u32 addr); - void OnResize(wxSizeEvent& event); + u32 AddrToBranch(u32 addr); + void OnResize(wxSizeEvent& event); - void MoveTo(int x, int y) - { - m_lx = x; - m_ly = y; - } + void MoveTo(int x, int y) + { + m_lx = x; + m_ly = y; + } - void LineTo(std::unique_ptr& dc, int x, int y); + void LineTo(std::unique_ptr& dc, int x, int y); - struct BlrStruct // for IDM_INSERTBLR - { - u32 address; - u32 oldValue; - }; - std::vector m_blrList; + struct BlrStruct // for IDM_INSERTBLR + { + u32 address; + u32 oldValue; + }; + std::vector m_blrList; - DebugInterface* m_debugger; - SymbolDB* m_symbol_db; + DebugInterface* m_debugger; + SymbolDB* m_symbol_db; - bool m_plain; + bool m_plain; - int m_curAddress; - int m_align; - int m_rowHeight; + int m_curAddress; + int m_align; + int m_rowHeight; - u32 m_selection; - u32 m_oldSelection; - bool m_selecting; + u32 m_selection; + u32 m_oldSelection; + bool m_selecting; - int m_lx, m_ly; + int m_lx, m_ly; }; diff --git a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp index 4e5581ca8e..3bdcdbe397 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -16,27 +17,23 @@ #include #include #include -#include #include "Common/BreakPoints.h" #include "Common/CommonTypes.h" #include "Common/StringUtil.h" #include "Common/SymbolDB.h" #include "Core/Core.h" -#include "Core/Host.h" #include "Core/Debugger/Debugger_SymbolMap.h" #include "Core/Debugger/PPCDebugInterface.h" #include "Core/HW/CPU.h" #include "Core/HW/Memmap.h" #include "Core/HW/SystemTimers.h" +#include "Core/Host.h" #include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/JitInterface.h" -#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PPCSymbolDB.h" #include "Core/PowerPC/PPCTables.h" -#include "DolphinWX/Frame.h" -#include "DolphinWX/Globals.h" -#include "DolphinWX/WxUtils.h" +#include "Core/PowerPC/PowerPC.h" #include "DolphinWX/Debugger/BreakpointWindow.h" #include "DolphinWX/Debugger/CodeView.h" #include "DolphinWX/Debugger/CodeWindow.h" @@ -44,84 +41,92 @@ #include "DolphinWX/Debugger/JitWindow.h" #include "DolphinWX/Debugger/RegisterWindow.h" #include "DolphinWX/Debugger/WatchWindow.h" +#include "DolphinWX/Frame.h" +#include "DolphinWX/Globals.h" +#include "DolphinWX/WxUtils.h" -CCodeWindow::CCodeWindow(const SConfig& _LocalCoreStartupParameter, CFrame *parent, - wxWindowID id, const wxPoint& position, const wxSize& size, long style, const wxString& name) - : wxPanel(parent, id, position, size, style, name) - , Parent(parent) - , m_RegisterWindow(nullptr) - , m_WatchWindow(nullptr) - , m_BreakpointWindow(nullptr) - , m_MemoryWindow(nullptr) - , m_JitWindow(nullptr) - , m_SoundWindow(nullptr) - , m_VideoWindow(nullptr) - , codeview(nullptr) +CCodeWindow::CCodeWindow(const SConfig& _LocalCoreStartupParameter, CFrame* parent, wxWindowID id, + const wxPoint& position, const wxSize& size, long style, + const wxString& name) + : wxPanel(parent, id, position, size, style, name), Parent(parent), m_RegisterWindow(nullptr), + m_WatchWindow(nullptr), m_BreakpointWindow(nullptr), m_MemoryWindow(nullptr), + m_JitWindow(nullptr), m_SoundWindow(nullptr), m_VideoWindow(nullptr), codeview(nullptr) { - InitBitmaps(); + InitBitmaps(); - DebugInterface* di = &PowerPC::debug_interface; + DebugInterface* di = &PowerPC::debug_interface; - codeview = new CCodeView(di, &g_symbolDB, this, wxID_ANY); + codeview = new CCodeView(di, &g_symbolDB, this, wxID_ANY); - callstack = new wxListBox(this, wxID_ANY); - callstack->Bind(wxEVT_LISTBOX, &CCodeWindow::OnCallstackListChange, this); + callstack = new wxListBox(this, wxID_ANY); + callstack->Bind(wxEVT_LISTBOX, &CCodeWindow::OnCallstackListChange, this); - symbols = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT); - symbols->Bind(wxEVT_LISTBOX, &CCodeWindow::OnSymbolListChange, this); + symbols = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT); + symbols->Bind(wxEVT_LISTBOX, &CCodeWindow::OnSymbolListChange, this); - calls = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT); - calls->Bind(wxEVT_LISTBOX, &CCodeWindow::OnCallsListChange, this); + calls = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT); + calls->Bind(wxEVT_LISTBOX, &CCodeWindow::OnCallsListChange, this); - callers = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT); - callers->Bind(wxEVT_LISTBOX, &CCodeWindow::OnCallersListChange, this); + callers = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT); + callers->Bind(wxEVT_LISTBOX, &CCodeWindow::OnCallersListChange, this); - m_aui_toolbar = new wxAuiToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_TB_HORIZONTAL | wxAUI_TB_PLAIN_BACKGROUND); + m_aui_toolbar = new wxAuiToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxAUI_TB_HORIZONTAL | wxAUI_TB_PLAIN_BACKGROUND); - wxSearchCtrl* const address_searchctrl = new wxSearchCtrl(m_aui_toolbar, IDM_ADDRBOX); - address_searchctrl->Bind(wxEVT_TEXT, &CCodeWindow::OnAddrBoxChange, this); - address_searchctrl->SetDescriptiveText(_("Search Address")); + wxSearchCtrl* const address_searchctrl = new wxSearchCtrl(m_aui_toolbar, IDM_ADDRBOX); + address_searchctrl->Bind(wxEVT_TEXT, &CCodeWindow::OnAddrBoxChange, this); + address_searchctrl->SetDescriptiveText(_("Search Address")); - m_aui_toolbar->AddControl(address_searchctrl); - m_aui_toolbar->Realize(); + m_aui_toolbar->AddControl(address_searchctrl); + m_aui_toolbar->Realize(); - m_aui_manager.SetManagedWindow(this); - m_aui_manager.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE); - m_aui_manager.AddPane(m_aui_toolbar, wxAuiPaneInfo().MinSize(150, -1).ToolbarPane().Top().Floatable(false)); - m_aui_manager.AddPane(callstack, wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption(_("Callstack"))); - m_aui_manager.AddPane(symbols, wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption(_("Symbols"))); - m_aui_manager.AddPane(calls, wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption(_("Function calls"))); - m_aui_manager.AddPane(callers, wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption(_("Function callers"))); - m_aui_manager.AddPane(codeview, wxAuiPaneInfo().CenterPane().CloseButton(false).Floatable(false)); - m_aui_manager.Update(); + m_aui_manager.SetManagedWindow(this); + m_aui_manager.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE); + m_aui_manager.AddPane(m_aui_toolbar, + wxAuiPaneInfo().MinSize(150, -1).ToolbarPane().Top().Floatable(false)); + m_aui_manager.AddPane( + callstack, + wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption( + _("Callstack"))); + m_aui_manager.AddPane( + symbols, wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption( + _("Symbols"))); + m_aui_manager.AddPane( + calls, wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption( + _("Function calls"))); + m_aui_manager.AddPane( + callers, wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption( + _("Function callers"))); + m_aui_manager.AddPane(codeview, wxAuiPaneInfo().CenterPane().CloseButton(false).Floatable(false)); + m_aui_manager.Update(); - // Menu - Bind(wxEVT_MENU, &CCodeWindow::OnCPUMode, this, IDM_INTERPRETER, IDM_JIT_SR_OFF); - Bind(wxEVT_MENU, &CCodeWindow::OnChangeFont, this, IDM_FONT_PICKER); - Bind(wxEVT_MENU, &CCodeWindow::OnJitMenu, this, IDM_CLEAR_CODE_CACHE, IDM_SEARCH_INSTRUCTION); - Bind(wxEVT_MENU, &CCodeWindow::OnSymbolsMenu, this, IDM_CLEAR_SYMBOLS, IDM_PATCH_HLE_FUNCTIONS); - Bind(wxEVT_MENU, &CCodeWindow::OnProfilerMenu, this, IDM_PROFILE_BLOCKS, IDM_WRITE_PROFILE); + // Menu + Bind(wxEVT_MENU, &CCodeWindow::OnCPUMode, this, IDM_INTERPRETER, IDM_JIT_SR_OFF); + Bind(wxEVT_MENU, &CCodeWindow::OnChangeFont, this, IDM_FONT_PICKER); + Bind(wxEVT_MENU, &CCodeWindow::OnJitMenu, this, IDM_CLEAR_CODE_CACHE, IDM_SEARCH_INSTRUCTION); + Bind(wxEVT_MENU, &CCodeWindow::OnSymbolsMenu, this, IDM_CLEAR_SYMBOLS, IDM_PATCH_HLE_FUNCTIONS); + Bind(wxEVT_MENU, &CCodeWindow::OnProfilerMenu, this, IDM_PROFILE_BLOCKS, IDM_WRITE_PROFILE); - // Toolbar - Bind(wxEVT_MENU, &CCodeWindow::OnCodeStep, this, IDM_STEP, IDM_GOTOPC); + // Toolbar + Bind(wxEVT_MENU, &CCodeWindow::OnCodeStep, this, IDM_STEP, IDM_GOTOPC); - // Other - Bind(wxEVT_HOST_COMMAND, &CCodeWindow::OnHostMessage, this); + // Other + Bind(wxEVT_HOST_COMMAND, &CCodeWindow::OnHostMessage, this); } CCodeWindow::~CCodeWindow() { - m_aui_manager.UnInit(); + m_aui_manager.UnInit(); } -wxMenuBar *CCodeWindow::GetMenuBar() +wxMenuBar* CCodeWindow::GetMenuBar() { - return Parent->GetMenuBar(); + return Parent->GetMenuBar(); } -wxToolBar *CCodeWindow::GetToolBar() +wxToolBar* CCodeWindow::GetToolBar() { - return Parent->m_ToolBar; + return Parent->m_ToolBar; } // ---------- @@ -129,639 +134,646 @@ wxToolBar *CCodeWindow::GetToolBar() void CCodeWindow::OnHostMessage(wxCommandEvent& event) { - switch (event.GetId()) - { - case IDM_NOTIFY_MAP_LOADED: - NotifyMapLoaded(); - if (m_BreakpointWindow) m_BreakpointWindow->NotifyUpdate(); - break; + switch (event.GetId()) + { + case IDM_NOTIFY_MAP_LOADED: + NotifyMapLoaded(); + if (m_BreakpointWindow) + m_BreakpointWindow->NotifyUpdate(); + break; - case IDM_UPDATE_DISASM_DIALOG: - Update(); - if (codeview) codeview->Center(PC); - if (m_RegisterWindow) m_RegisterWindow->NotifyUpdate(); - if (m_WatchWindow) m_WatchWindow->NotifyUpdate(); - break; + case IDM_UPDATE_DISASM_DIALOG: + Update(); + if (codeview) + codeview->Center(PC); + if (m_RegisterWindow) + m_RegisterWindow->NotifyUpdate(); + if (m_WatchWindow) + m_WatchWindow->NotifyUpdate(); + break; - case IDM_UPDATE_BREAKPOINTS: - Update(); - if (m_BreakpointWindow) m_BreakpointWindow->NotifyUpdate(); - break; + case IDM_UPDATE_BREAKPOINTS: + Update(); + if (m_BreakpointWindow) + m_BreakpointWindow->NotifyUpdate(); + break; - case IDM_UPDATE_JIT_PANE: - // Check if the JIT pane is in the AUI notebook. If not, add it and switch to it. - if (!m_JitWindow) - ToggleJitWindow(true); - m_JitWindow->ViewAddr(codeview->GetSelection()); - break; - } + case IDM_UPDATE_JIT_PANE: + // Check if the JIT pane is in the AUI notebook. If not, add it and switch to it. + if (!m_JitWindow) + ToggleJitWindow(true); + m_JitWindow->ViewAddr(codeview->GetSelection()); + break; + } } // The Play, Stop, Step, Skip, Go to PC and Show PC buttons go here void CCodeWindow::OnCodeStep(wxCommandEvent& event) { - switch (event.GetId()) - { - case IDM_STEP: - SingleStep(); - break; + switch (event.GetId()) + { + case IDM_STEP: + SingleStep(); + break; - case IDM_STEPOVER: - StepOver(); - break; + case IDM_STEPOVER: + StepOver(); + break; - case IDM_STEPOUT: - StepOut(); - break; + case IDM_STEPOUT: + StepOut(); + break; - case IDM_TOGGLE_BREAKPOINT: - ToggleBreakpoint(); - break; + case IDM_TOGGLE_BREAKPOINT: + ToggleBreakpoint(); + break; - case IDM_SKIP: - PC += 4; - Update(); - break; + case IDM_SKIP: + PC += 4; + Update(); + break; - case IDM_SETPC: - PC = codeview->GetSelection(); - Update(); - break; + case IDM_SETPC: + PC = codeview->GetSelection(); + Update(); + break; - case IDM_GOTOPC: - JumpToAddress(PC); - break; - } + case IDM_GOTOPC: + JumpToAddress(PC); + break; + } - UpdateButtonStates(); - // Update all toolbars in the aui manager - Parent->UpdateGUI(); + UpdateButtonStates(); + // Update all toolbars in the aui manager + Parent->UpdateGUI(); } bool CCodeWindow::JumpToAddress(u32 address) { - // Jump to anywhere in memory - if (address <= 0xFFFFFFFF) - { - codeview->Center(address); - UpdateLists(); + // Jump to anywhere in memory + if (address <= 0xFFFFFFFF) + { + codeview->Center(address); + UpdateLists(); - return true; - } + return true; + } - return false; + return false; } -void CCodeWindow::OnCodeViewChange(wxCommandEvent &event) +void CCodeWindow::OnCodeViewChange(wxCommandEvent& event) { - UpdateLists(); + UpdateLists(); } void CCodeWindow::OnAddrBoxChange(wxCommandEvent& event) { - wxSearchCtrl* pAddrCtrl = (wxSearchCtrl*)m_aui_toolbar->FindControl(IDM_ADDRBOX); + wxSearchCtrl* pAddrCtrl = (wxSearchCtrl*)m_aui_toolbar->FindControl(IDM_ADDRBOX); - // Trim leading and trailing whitespace. - wxString txt = pAddrCtrl->GetValue().Trim().Trim(false); + // Trim leading and trailing whitespace. + wxString txt = pAddrCtrl->GetValue().Trim().Trim(false); - bool success = false; - unsigned long addr; - if (txt.ToULong(&addr, 16)) - { - if (JumpToAddress(addr)) - success = true; - } + bool success = false; + unsigned long addr; + if (txt.ToULong(&addr, 16)) + { + if (JumpToAddress(addr)) + success = true; + } - if (success) - pAddrCtrl->SetBackgroundColour(wxNullColour); - else if (!txt.empty()) - pAddrCtrl->SetBackgroundColour(*wxRED); + if (success) + pAddrCtrl->SetBackgroundColour(wxNullColour); + else if (!txt.empty()) + pAddrCtrl->SetBackgroundColour(*wxRED); - pAddrCtrl->Refresh(); + pAddrCtrl->Refresh(); - event.Skip(); + event.Skip(); } void CCodeWindow::OnCallstackListChange(wxCommandEvent& event) { - int index = callstack->GetSelection(); - if (index >= 0) - { - u32 address = (u32)(u64)(callstack->GetClientData(index)); - if (address) - JumpToAddress(address); - } + int index = callstack->GetSelection(); + if (index >= 0) + { + u32 address = (u32)(u64)(callstack->GetClientData(index)); + if (address) + JumpToAddress(address); + } } void CCodeWindow::OnCallersListChange(wxCommandEvent& event) { - int index = callers->GetSelection(); - if (index >= 0) - { - u32 address = (u32)(u64)(callers->GetClientData(index)); - if (address) - JumpToAddress(address); - } + int index = callers->GetSelection(); + if (index >= 0) + { + u32 address = (u32)(u64)(callers->GetClientData(index)); + if (address) + JumpToAddress(address); + } } void CCodeWindow::OnCallsListChange(wxCommandEvent& event) { - int index = calls->GetSelection(); - if (index >= 0) - { - u32 address = (u32)(u64)(calls->GetClientData(index)); - if (address) - JumpToAddress(address); - } + int index = calls->GetSelection(); + if (index >= 0) + { + u32 address = (u32)(u64)(calls->GetClientData(index)); + if (address) + JumpToAddress(address); + } } void CCodeWindow::SingleStep() { - if (CPU::IsStepping()) - { - PowerPC::breakpoints.ClearAllTemporary(); - JitInterface::InvalidateICache(PC, 4, true); - CPU::StepOpcode(&sync_event); - wxThread::Sleep(20); - // need a short wait here - JumpToAddress(PC); - Update(); - } + if (CPU::IsStepping()) + { + PowerPC::breakpoints.ClearAllTemporary(); + JitInterface::InvalidateICache(PC, 4, true); + CPU::StepOpcode(&sync_event); + wxThread::Sleep(20); + // need a short wait here + JumpToAddress(PC); + Update(); + } } void CCodeWindow::StepOver() { - if (CPU::IsStepping()) - { - UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC); - if (inst.LK) - { - PowerPC::breakpoints.ClearAllTemporary(); - PowerPC::breakpoints.Add(PC + 4, true); - CPU::EnableStepping(false); - JumpToAddress(PC); - Update(); - } - else - { - SingleStep(); - } + if (CPU::IsStepping()) + { + UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC); + if (inst.LK) + { + PowerPC::breakpoints.ClearAllTemporary(); + PowerPC::breakpoints.Add(PC + 4, true); + CPU::EnableStepping(false); + JumpToAddress(PC); + Update(); + } + else + { + SingleStep(); + } - UpdateButtonStates(); - // Update all toolbars in the aui manager - Parent->UpdateGUI(); - } + UpdateButtonStates(); + // Update all toolbars in the aui manager + Parent->UpdateGUI(); + } } void CCodeWindow::StepOut() { - if (CPU::IsStepping()) - { - CPU::PauseAndLock(true, false); - PowerPC::breakpoints.ClearAllTemporary(); + if (CPU::IsStepping()) + { + CPU::PauseAndLock(true, false); + PowerPC::breakpoints.ClearAllTemporary(); - // Keep stepping until the next blr or timeout after one second - u64 timeout = SystemTimers::GetTicksPerSecond(); - u64 steps = 0; - PowerPC::CoreMode oldMode = PowerPC::GetMode(); - PowerPC::SetMode(PowerPC::MODE_INTERPRETER); - UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC); - while (inst.hex != 0x4e800020 && steps < timeout) // check for blr - { - if (inst.LK) - { - // Step over branches - u32 next_pc = PC + 4; - while (PC != next_pc && steps < timeout) - { - PowerPC::SingleStep(); - ++steps; - } - } - else - { - PowerPC::SingleStep(); - ++steps; - } - inst = PowerPC::HostRead_Instruction(PC); - } + // Keep stepping until the next blr or timeout after one second + u64 timeout = SystemTimers::GetTicksPerSecond(); + u64 steps = 0; + PowerPC::CoreMode oldMode = PowerPC::GetMode(); + PowerPC::SetMode(PowerPC::MODE_INTERPRETER); + UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC); + while (inst.hex != 0x4e800020 && steps < timeout) // check for blr + { + if (inst.LK) + { + // Step over branches + u32 next_pc = PC + 4; + while (PC != next_pc && steps < timeout) + { + PowerPC::SingleStep(); + ++steps; + } + } + else + { + PowerPC::SingleStep(); + ++steps; + } + inst = PowerPC::HostRead_Instruction(PC); + } - PowerPC::SingleStep(); - PowerPC::SetMode(oldMode); - CPU::PauseAndLock(false, false); + PowerPC::SingleStep(); + PowerPC::SetMode(oldMode); + CPU::PauseAndLock(false, false); - JumpToAddress(PC); - Update(); + JumpToAddress(PC); + Update(); - UpdateButtonStates(); - // Update all toolbars in the aui manager - Parent->UpdateGUI(); - } + UpdateButtonStates(); + // Update all toolbars in the aui manager + Parent->UpdateGUI(); + } } void CCodeWindow::ToggleBreakpoint() { - if (CPU::IsStepping()) - { - if (codeview) codeview->ToggleBreakpoint(codeview->GetSelection()); - Update(); - } + if (CPU::IsStepping()) + { + if (codeview) + codeview->ToggleBreakpoint(codeview->GetSelection()); + Update(); + } } void CCodeWindow::UpdateLists() { - callers->Clear(); - u32 addr = codeview->GetSelection(); - Symbol *symbol = g_symbolDB.GetSymbolFromAddr(addr); - if (!symbol) - return; + callers->Clear(); + u32 addr = codeview->GetSelection(); + Symbol* symbol = g_symbolDB.GetSymbolFromAddr(addr); + if (!symbol) + return; - for (auto& call : symbol->callers) - { - u32 caller_addr = call.callAddress; - Symbol *caller_symbol = g_symbolDB.GetSymbolFromAddr(caller_addr); - if (caller_symbol) - { - int idx = callers->Append(StrToWxStr(StringFromFormat - ("< %s (%08x)", caller_symbol->name.c_str(), caller_addr).c_str())); - callers->SetClientData(idx, (void*)(u64)caller_addr); - } - } + for (auto& call : symbol->callers) + { + u32 caller_addr = call.callAddress; + Symbol* caller_symbol = g_symbolDB.GetSymbolFromAddr(caller_addr); + if (caller_symbol) + { + int idx = callers->Append(StrToWxStr( + StringFromFormat("< %s (%08x)", caller_symbol->name.c_str(), caller_addr).c_str())); + callers->SetClientData(idx, (void*)(u64)caller_addr); + } + } - calls->Clear(); - for (auto& call : symbol->calls) - { - u32 call_addr = call.function; - Symbol *call_symbol = g_symbolDB.GetSymbolFromAddr(call_addr); - if (call_symbol) - { - int idx = calls->Append(StrToWxStr(StringFromFormat - ("> %s (%08x)", call_symbol->name.c_str(), call_addr).c_str())); - calls->SetClientData(idx, (void*)(u64)call_addr); - } - } + calls->Clear(); + for (auto& call : symbol->calls) + { + u32 call_addr = call.function; + Symbol* call_symbol = g_symbolDB.GetSymbolFromAddr(call_addr); + if (call_symbol) + { + int idx = calls->Append(StrToWxStr( + StringFromFormat("> %s (%08x)", call_symbol->name.c_str(), call_addr).c_str())); + calls->SetClientData(idx, (void*)(u64)call_addr); + } + } } void CCodeWindow::UpdateCallstack() { - if (Core::GetState() == Core::CORE_STOPPING) return; + if (Core::GetState() == Core::CORE_STOPPING) + return; - callstack->Clear(); + callstack->Clear(); - std::vector stack; + std::vector stack; - bool ret = Dolphin_Debugger::GetCallstack(stack); + bool ret = Dolphin_Debugger::GetCallstack(stack); - for (auto& frame : stack) - { - int idx = callstack->Append(StrToWxStr(frame.Name)); - callstack->SetClientData(idx, (void*)(u64)frame.vAddress); - } + for (auto& frame : stack) + { + int idx = callstack->Append(StrToWxStr(frame.Name)); + callstack->SetClientData(idx, (void*)(u64)frame.vAddress); + } - if (!ret) - callstack->Append(StrToWxStr("invalid callstack")); + if (!ret) + callstack->Append(StrToWxStr("invalid callstack")); } // Create CPU Mode menus -void CCodeWindow::CreateMenu(const SConfig& core_startup_parameter, wxMenuBar *pMenuBar) +void CCodeWindow::CreateMenu(const SConfig& core_startup_parameter, wxMenuBar* pMenuBar) { - // CPU Mode - wxMenu* pCoreMenu = new wxMenu; + // CPU Mode + wxMenu* pCoreMenu = new wxMenu; - wxMenuItem* interpreter = pCoreMenu->Append(IDM_INTERPRETER, _("&Interpreter core"), - _("This is necessary to get break points" - " and stepping to work as explained in the Developer Documentation. But it can be very" - " slow, perhaps slower than 1 fps."), - wxITEM_CHECK); - interpreter->Check(core_startup_parameter.iCPUCore == PowerPC::CORE_INTERPRETER); - pCoreMenu->AppendSeparator(); + wxMenuItem* interpreter = pCoreMenu->Append( + IDM_INTERPRETER, _("&Interpreter core"), + _("This is necessary to get break points" + " and stepping to work as explained in the Developer Documentation. But it can be very" + " slow, perhaps slower than 1 fps."), + wxITEM_CHECK); + interpreter->Check(core_startup_parameter.iCPUCore == PowerPC::CORE_INTERPRETER); + pCoreMenu->AppendSeparator(); - pCoreMenu->Append(IDM_JIT_NO_BLOCK_LINKING, _("&JIT Block Linking off"), - _("Provide safer execution by not linking the JIT blocks."), - wxITEM_CHECK); + pCoreMenu->Append(IDM_JIT_NO_BLOCK_LINKING, _("&JIT Block Linking off"), + _("Provide safer execution by not linking the JIT blocks."), wxITEM_CHECK); - pCoreMenu->Append(IDM_JIT_NO_BLOCK_CACHE, _("&Disable JIT Cache"), - _("Avoid any involuntary JIT cache clearing, this may prevent Zelda TP from crashing.\n[This option must be selected before a game is started.]"), - wxITEM_CHECK); - pCoreMenu->Append(IDM_CLEAR_CODE_CACHE, _("&Clear JIT cache")); + pCoreMenu->Append(IDM_JIT_NO_BLOCK_CACHE, _("&Disable JIT Cache"), + _("Avoid any involuntary JIT cache clearing, this may prevent Zelda TP from " + "crashing.\n[This option must be selected before a game is started.]"), + wxITEM_CHECK); + pCoreMenu->Append(IDM_CLEAR_CODE_CACHE, _("&Clear JIT cache")); - pCoreMenu->AppendSeparator(); - pCoreMenu->Append(IDM_LOG_INSTRUCTIONS, _("&Log JIT instruction coverage")); - pCoreMenu->Append(IDM_SEARCH_INSTRUCTION, _("&Search for an op")); + pCoreMenu->AppendSeparator(); + pCoreMenu->Append(IDM_LOG_INSTRUCTIONS, _("&Log JIT instruction coverage")); + pCoreMenu->Append(IDM_SEARCH_INSTRUCTION, _("&Search for an op")); - pCoreMenu->AppendSeparator(); - pCoreMenu->Append(IDM_JIT_OFF, _("&JIT off (JIT core)"), - _("Turn off all JIT functions, but still use the JIT core from Jit.cpp"), - wxITEM_CHECK); - pCoreMenu->Append(IDM_JIT_LS_OFF, _("&JIT LoadStore off"), - wxEmptyString, wxITEM_CHECK); - pCoreMenu->Append(IDM_JIT_LSLBZX_OFF, _(" &JIT LoadStore lbzx off"), - wxEmptyString, wxITEM_CHECK); - pCoreMenu->Append(IDM_JIT_LSLXZ_OFF, _(" &JIT LoadStore lXz off"), - wxEmptyString, wxITEM_CHECK); - pCoreMenu->Append(IDM_JIT_LSLWZ_OFF, _("&JIT LoadStore lwz off"), - wxEmptyString, wxITEM_CHECK); - pCoreMenu->Append(IDM_JIT_LSF_OFF, _("&JIT LoadStore Floating off"), - wxEmptyString, wxITEM_CHECK); - pCoreMenu->Append(IDM_JIT_LSP_OFF, _("&JIT LoadStore Paired off"), - wxEmptyString, wxITEM_CHECK); - pCoreMenu->Append(IDM_JIT_FP_OFF, _("&JIT FloatingPoint off"), - wxEmptyString, wxITEM_CHECK); - pCoreMenu->Append(IDM_JIT_I_OFF, _("&JIT Integer off"), - wxEmptyString, wxITEM_CHECK); - pCoreMenu->Append(IDM_JIT_P_OFF, _("&JIT Paired off"), - wxEmptyString, wxITEM_CHECK); - pCoreMenu->Append(IDM_JIT_SR_OFF, _("&JIT SystemRegisters off"), - wxEmptyString, wxITEM_CHECK); + pCoreMenu->AppendSeparator(); + pCoreMenu->Append(IDM_JIT_OFF, _("&JIT off (JIT core)"), + _("Turn off all JIT functions, but still use the JIT core from Jit.cpp"), + wxITEM_CHECK); + pCoreMenu->Append(IDM_JIT_LS_OFF, _("&JIT LoadStore off"), wxEmptyString, wxITEM_CHECK); + pCoreMenu->Append(IDM_JIT_LSLBZX_OFF, _(" &JIT LoadStore lbzx off"), wxEmptyString, + wxITEM_CHECK); + pCoreMenu->Append(IDM_JIT_LSLXZ_OFF, _(" &JIT LoadStore lXz off"), wxEmptyString, + wxITEM_CHECK); + pCoreMenu->Append(IDM_JIT_LSLWZ_OFF, _("&JIT LoadStore lwz off"), wxEmptyString, wxITEM_CHECK); + pCoreMenu->Append(IDM_JIT_LSF_OFF, _("&JIT LoadStore Floating off"), wxEmptyString, wxITEM_CHECK); + pCoreMenu->Append(IDM_JIT_LSP_OFF, _("&JIT LoadStore Paired off"), wxEmptyString, wxITEM_CHECK); + pCoreMenu->Append(IDM_JIT_FP_OFF, _("&JIT FloatingPoint off"), wxEmptyString, wxITEM_CHECK); + pCoreMenu->Append(IDM_JIT_I_OFF, _("&JIT Integer off"), wxEmptyString, wxITEM_CHECK); + pCoreMenu->Append(IDM_JIT_P_OFF, _("&JIT Paired off"), wxEmptyString, wxITEM_CHECK); + pCoreMenu->Append(IDM_JIT_SR_OFF, _("&JIT SystemRegisters off"), wxEmptyString, wxITEM_CHECK); - pMenuBar->Append(pCoreMenu, _("&JIT")); + pMenuBar->Append(pCoreMenu, _("&JIT")); + // Debug Menu + wxMenu* pDebugMenu = new wxMenu; - // Debug Menu - wxMenu* pDebugMenu = new wxMenu; + pDebugMenu->Append(IDM_STEP, _("Step &Into\tF11")); + pDebugMenu->Append(IDM_STEPOVER, _("Step &Over\tF10")); + pDebugMenu->Append(IDM_STEPOUT, _("Step O&ut\tSHIFT+F11")); + pDebugMenu->Append(IDM_TOGGLE_BREAKPOINT, _("Toggle &Breakpoint\tF9")); + pDebugMenu->AppendSeparator(); - pDebugMenu->Append(IDM_STEP, _("Step &Into\tF11")); - pDebugMenu->Append(IDM_STEPOVER, _("Step &Over\tF10")); - pDebugMenu->Append(IDM_STEPOUT, _("Step O&ut\tSHIFT+F11")); - pDebugMenu->Append(IDM_TOGGLE_BREAKPOINT, _("Toggle &Breakpoint\tF9")); - pDebugMenu->AppendSeparator(); + wxMenu* pPerspectives = new wxMenu; + Parent->m_SavedPerspectives = new wxMenu; + pDebugMenu->AppendSubMenu(pPerspectives, _("Perspectives"), _("Edit Perspectives")); + pPerspectives->Append(IDM_SAVE_PERSPECTIVE, _("Save perspectives"), + _("Save currently-toggled perspectives")); + pPerspectives->Append(IDM_EDIT_PERSPECTIVES, _("Edit perspectives"), + _("Toggle editing of perspectives"), wxITEM_CHECK); + pPerspectives->AppendSeparator(); + pPerspectives->Append(IDM_ADD_PERSPECTIVE, _("Create new perspective")); + pPerspectives->AppendSubMenu(Parent->m_SavedPerspectives, _("Saved perspectives")); + Parent->PopulateSavedPerspectives(); + pPerspectives->AppendSeparator(); + wxMenu* pAddPane = new wxMenu; + pPerspectives->AppendSubMenu(pAddPane, _("Add new pane to")); + pAddPane->Append(IDM_PERSPECTIVES_ADD_PANE_TOP, _("Top")); + pAddPane->Append(IDM_PERSPECTIVES_ADD_PANE_BOTTOM, _("Bottom")); + pAddPane->Append(IDM_PERSPECTIVES_ADD_PANE_LEFT, _("Left")); + pAddPane->Append(IDM_PERSPECTIVES_ADD_PANE_RIGHT, _("Right")); + pAddPane->Append(IDM_PERSPECTIVES_ADD_PANE_CENTER, _("Center")); + pPerspectives->Append(IDM_TAB_SPLIT, _("Tab split"), "", wxITEM_CHECK); + pPerspectives->Append(IDM_NO_DOCKING, _("Disable docking"), + "Disable docking of perspective panes to main window", wxITEM_CHECK); - wxMenu* pPerspectives = new wxMenu; - Parent->m_SavedPerspectives = new wxMenu; - pDebugMenu->AppendSubMenu(pPerspectives, _("Perspectives"), _("Edit Perspectives")); - pPerspectives->Append(IDM_SAVE_PERSPECTIVE, _("Save perspectives"), _("Save currently-toggled perspectives")); - pPerspectives->Append(IDM_EDIT_PERSPECTIVES, _("Edit perspectives"), _("Toggle editing of perspectives"), wxITEM_CHECK); - pPerspectives->AppendSeparator(); - pPerspectives->Append(IDM_ADD_PERSPECTIVE, _("Create new perspective")); - pPerspectives->AppendSubMenu(Parent->m_SavedPerspectives, _("Saved perspectives")); - Parent->PopulateSavedPerspectives(); - pPerspectives->AppendSeparator(); - wxMenu* pAddPane = new wxMenu; - pPerspectives->AppendSubMenu(pAddPane, _("Add new pane to")); - pAddPane->Append(IDM_PERSPECTIVES_ADD_PANE_TOP, _("Top")); - pAddPane->Append(IDM_PERSPECTIVES_ADD_PANE_BOTTOM, _("Bottom")); - pAddPane->Append(IDM_PERSPECTIVES_ADD_PANE_LEFT, _("Left")); - pAddPane->Append(IDM_PERSPECTIVES_ADD_PANE_RIGHT, _("Right")); - pAddPane->Append(IDM_PERSPECTIVES_ADD_PANE_CENTER, _("Center")); - pPerspectives->Append(IDM_TAB_SPLIT, _("Tab split"), "", wxITEM_CHECK); - pPerspectives->Append(IDM_NO_DOCKING, _("Disable docking"), "Disable docking of perspective panes to main window", wxITEM_CHECK); + pMenuBar->Append(pDebugMenu, _("&Debug")); - - pMenuBar->Append(pDebugMenu, _("&Debug")); - - CreateMenuSymbols(pMenuBar); + CreateMenuSymbols(pMenuBar); } void CCodeWindow::CreateMenuOptions(wxMenu* pMenu) { - wxMenuItem* boottopause = pMenu->Append(IDM_BOOT_TO_PAUSE, _("Boot to pause"), - _("Start the game directly instead of booting to pause"), - wxITEM_CHECK); - boottopause->Check(bBootToPause); + wxMenuItem* boottopause = + pMenu->Append(IDM_BOOT_TO_PAUSE, _("Boot to pause"), + _("Start the game directly instead of booting to pause"), wxITEM_CHECK); + boottopause->Check(bBootToPause); - wxMenuItem* automaticstart = pMenu->Append(IDM_AUTOMATIC_START, _("&Automatic start"), - _( - "Automatically load the Default ISO when Dolphin starts, or the last game you loaded," - " if you have not given it an elf file with the --elf command line. [This can be" - " convenient if you are bug-testing with a certain game and want to rebuild" - " and retry it several times, either with changes to Dolphin or if you are" - " developing a homebrew game.]"), - wxITEM_CHECK); - automaticstart->Check(bAutomaticStart); + wxMenuItem* automaticstart = pMenu->Append( + IDM_AUTOMATIC_START, _("&Automatic start"), + _("Automatically load the Default ISO when Dolphin starts, or the last game you loaded," + " if you have not given it an elf file with the --elf command line. [This can be" + " convenient if you are bug-testing with a certain game and want to rebuild" + " and retry it several times, either with changes to Dolphin or if you are" + " developing a homebrew game.]"), + wxITEM_CHECK); + automaticstart->Check(bAutomaticStart); - pMenu->Append(IDM_FONT_PICKER, _("&Font...")); + pMenu->Append(IDM_FONT_PICKER, _("&Font...")); } // CPU Mode and JIT Menu void CCodeWindow::OnCPUMode(wxCommandEvent& event) { - switch (event.GetId()) - { - case IDM_INTERPRETER: - PowerPC::SetMode(UseInterpreter() ? PowerPC::MODE_INTERPRETER : PowerPC::MODE_JIT); - break; - case IDM_BOOT_TO_PAUSE: - bBootToPause = !bBootToPause; - return; - case IDM_AUTOMATIC_START: - bAutomaticStart = !bAutomaticStart; - return; - case IDM_JIT_OFF: - SConfig::GetInstance().bJITOff = event.IsChecked(); - break; - case IDM_JIT_LS_OFF: - SConfig::GetInstance().bJITLoadStoreOff = event.IsChecked(); - break; - case IDM_JIT_LSLXZ_OFF: - SConfig::GetInstance().bJITLoadStorelXzOff = event.IsChecked(); - break; - case IDM_JIT_LSLWZ_OFF: - SConfig::GetInstance().bJITLoadStorelwzOff = event.IsChecked(); - break; - case IDM_JIT_LSLBZX_OFF: - SConfig::GetInstance().bJITLoadStorelbzxOff = event.IsChecked(); - break; - case IDM_JIT_LSF_OFF: - SConfig::GetInstance().bJITLoadStoreFloatingOff = event.IsChecked(); - break; - case IDM_JIT_LSP_OFF: - SConfig::GetInstance().bJITLoadStorePairedOff = event.IsChecked(); - break; - case IDM_JIT_FP_OFF: - SConfig::GetInstance().bJITFloatingPointOff = event.IsChecked(); - break; - case IDM_JIT_I_OFF: - SConfig::GetInstance().bJITIntegerOff = event.IsChecked(); - break; - case IDM_JIT_P_OFF: - SConfig::GetInstance().bJITPairedOff = event.IsChecked(); - break; - case IDM_JIT_SR_OFF: - SConfig::GetInstance().bJITSystemRegistersOff = event.IsChecked(); - break; - } + switch (event.GetId()) + { + case IDM_INTERPRETER: + PowerPC::SetMode(UseInterpreter() ? PowerPC::MODE_INTERPRETER : PowerPC::MODE_JIT); + break; + case IDM_BOOT_TO_PAUSE: + bBootToPause = !bBootToPause; + return; + case IDM_AUTOMATIC_START: + bAutomaticStart = !bAutomaticStart; + return; + case IDM_JIT_OFF: + SConfig::GetInstance().bJITOff = event.IsChecked(); + break; + case IDM_JIT_LS_OFF: + SConfig::GetInstance().bJITLoadStoreOff = event.IsChecked(); + break; + case IDM_JIT_LSLXZ_OFF: + SConfig::GetInstance().bJITLoadStorelXzOff = event.IsChecked(); + break; + case IDM_JIT_LSLWZ_OFF: + SConfig::GetInstance().bJITLoadStorelwzOff = event.IsChecked(); + break; + case IDM_JIT_LSLBZX_OFF: + SConfig::GetInstance().bJITLoadStorelbzxOff = event.IsChecked(); + break; + case IDM_JIT_LSF_OFF: + SConfig::GetInstance().bJITLoadStoreFloatingOff = event.IsChecked(); + break; + case IDM_JIT_LSP_OFF: + SConfig::GetInstance().bJITLoadStorePairedOff = event.IsChecked(); + break; + case IDM_JIT_FP_OFF: + SConfig::GetInstance().bJITFloatingPointOff = event.IsChecked(); + break; + case IDM_JIT_I_OFF: + SConfig::GetInstance().bJITIntegerOff = event.IsChecked(); + break; + case IDM_JIT_P_OFF: + SConfig::GetInstance().bJITPairedOff = event.IsChecked(); + break; + case IDM_JIT_SR_OFF: + SConfig::GetInstance().bJITSystemRegistersOff = event.IsChecked(); + break; + } - // Clear the JIT cache to enable these changes - JitInterface::ClearCache(); + // Clear the JIT cache to enable these changes + JitInterface::ClearCache(); - // Update - UpdateButtonStates(); + // Update + UpdateButtonStates(); } void CCodeWindow::OnJitMenu(wxCommandEvent& event) { - switch (event.GetId()) - { - case IDM_LOG_INSTRUCTIONS: - PPCTables::LogCompiledInstructions(); - break; + switch (event.GetId()) + { + case IDM_LOG_INSTRUCTIONS: + PPCTables::LogCompiledInstructions(); + break; - case IDM_CLEAR_CODE_CACHE: - JitInterface::ClearCache(); - break; + case IDM_CLEAR_CODE_CACHE: + JitInterface::ClearCache(); + break; - case IDM_SEARCH_INSTRUCTION: - { - wxString str = wxGetTextFromUser("", _("Op?"), wxEmptyString, this); - auto const wx_name = WxStrToStr(str); - bool found = false; - for (u32 addr = 0x80000000; addr < 0x80180000; addr += 4) - { - const char *name = PPCTables::GetInstructionName(PowerPC::HostRead_U32(addr)); - if (name && (wx_name == name)) - { - NOTICE_LOG(POWERPC, "Found %s at %08x", wx_name.c_str(), addr); - found = true; - } - } - if (!found) - NOTICE_LOG(POWERPC, "Opcode %s not found", wx_name.c_str()); - break; - } - } + case IDM_SEARCH_INSTRUCTION: + { + wxString str = wxGetTextFromUser("", _("Op?"), wxEmptyString, this); + auto const wx_name = WxStrToStr(str); + bool found = false; + for (u32 addr = 0x80000000; addr < 0x80180000; addr += 4) + { + const char* name = PPCTables::GetInstructionName(PowerPC::HostRead_U32(addr)); + if (name && (wx_name == name)) + { + NOTICE_LOG(POWERPC, "Found %s at %08x", wx_name.c_str(), addr); + found = true; + } + } + if (!found) + NOTICE_LOG(POWERPC, "Opcode %s not found", wx_name.c_str()); + break; + } + } } // Shortcuts bool CCodeWindow::UseInterpreter() { - return GetMenuBar()->IsChecked(IDM_INTERPRETER); + return GetMenuBar()->IsChecked(IDM_INTERPRETER); } bool CCodeWindow::BootToPause() { - return GetMenuBar()->IsChecked(IDM_BOOT_TO_PAUSE); + return GetMenuBar()->IsChecked(IDM_BOOT_TO_PAUSE); } bool CCodeWindow::AutomaticStart() { - return GetMenuBar()->IsChecked(IDM_AUTOMATIC_START); + return GetMenuBar()->IsChecked(IDM_AUTOMATIC_START); } bool CCodeWindow::JITNoBlockCache() { - return GetMenuBar()->IsChecked(IDM_JIT_NO_BLOCK_CACHE); + return GetMenuBar()->IsChecked(IDM_JIT_NO_BLOCK_CACHE); } bool CCodeWindow::JITNoBlockLinking() { - return GetMenuBar()->IsChecked(IDM_JIT_NO_BLOCK_LINKING); + return GetMenuBar()->IsChecked(IDM_JIT_NO_BLOCK_LINKING); } // Toolbar void CCodeWindow::InitBitmaps() { - m_Bitmaps[Toolbar_Step] = WxUtils::LoadResourceBitmap("toolbar_debugger_step"); - m_Bitmaps[Toolbar_StepOver] = WxUtils::LoadResourceBitmap("toolbar_debugger_step_over"); - m_Bitmaps[Toolbar_StepOut] = WxUtils::LoadResourceBitmap("toolbar_debugger_step_out"); - m_Bitmaps[Toolbar_Skip] = WxUtils::LoadResourceBitmap("toolbar_debugger_skip"); - m_Bitmaps[Toolbar_GotoPC] = WxUtils::LoadResourceBitmap("toolbar_debugger_goto_pc"); - m_Bitmaps[Toolbar_SetPC] = WxUtils::LoadResourceBitmap("toolbar_debugger_set_pc"); + m_Bitmaps[Toolbar_Step] = WxUtils::LoadResourceBitmap("toolbar_debugger_step"); + m_Bitmaps[Toolbar_StepOver] = WxUtils::LoadResourceBitmap("toolbar_debugger_step_over"); + m_Bitmaps[Toolbar_StepOut] = WxUtils::LoadResourceBitmap("toolbar_debugger_step_out"); + m_Bitmaps[Toolbar_Skip] = WxUtils::LoadResourceBitmap("toolbar_debugger_skip"); + m_Bitmaps[Toolbar_GotoPC] = WxUtils::LoadResourceBitmap("toolbar_debugger_goto_pc"); + m_Bitmaps[Toolbar_SetPC] = WxUtils::LoadResourceBitmap("toolbar_debugger_set_pc"); } void CCodeWindow::PopulateToolbar(wxToolBar* toolBar) { - int w = m_Bitmaps[0].GetWidth(), - h = m_Bitmaps[0].GetHeight(); + int w = m_Bitmaps[0].GetWidth(), h = m_Bitmaps[0].GetHeight(); - toolBar->SetToolBitmapSize(wxSize(w, h)); - WxUtils::AddToolbarButton(toolBar, IDM_STEP, _("Step"), m_Bitmaps[Toolbar_Step], _("Step into the next instruction")); - WxUtils::AddToolbarButton(toolBar, IDM_STEPOVER, _("Step Over"), m_Bitmaps[Toolbar_StepOver], _("Step over the next instruction")); - WxUtils::AddToolbarButton(toolBar, IDM_STEPOUT, _("Step Out"), m_Bitmaps[Toolbar_StepOut], _("Step out of the current function")); - WxUtils::AddToolbarButton(toolBar, IDM_SKIP, _("Skip"), m_Bitmaps[Toolbar_Skip], _("Skips the next instruction completely")); - toolBar->AddSeparator(); - WxUtils::AddToolbarButton(toolBar, IDM_GOTOPC, _("Show PC"), m_Bitmaps[Toolbar_GotoPC], _("Go to the current instruction")); - WxUtils::AddToolbarButton(toolBar, IDM_SETPC, _("Set PC"), m_Bitmaps[Toolbar_SetPC], _("Set the current instruction")); + toolBar->SetToolBitmapSize(wxSize(w, h)); + WxUtils::AddToolbarButton(toolBar, IDM_STEP, _("Step"), m_Bitmaps[Toolbar_Step], + _("Step into the next instruction")); + WxUtils::AddToolbarButton(toolBar, IDM_STEPOVER, _("Step Over"), m_Bitmaps[Toolbar_StepOver], + _("Step over the next instruction")); + WxUtils::AddToolbarButton(toolBar, IDM_STEPOUT, _("Step Out"), m_Bitmaps[Toolbar_StepOut], + _("Step out of the current function")); + WxUtils::AddToolbarButton(toolBar, IDM_SKIP, _("Skip"), m_Bitmaps[Toolbar_Skip], + _("Skips the next instruction completely")); + toolBar->AddSeparator(); + WxUtils::AddToolbarButton(toolBar, IDM_GOTOPC, _("Show PC"), m_Bitmaps[Toolbar_GotoPC], + _("Go to the current instruction")); + WxUtils::AddToolbarButton(toolBar, IDM_SETPC, _("Set PC"), m_Bitmaps[Toolbar_SetPC], + _("Set the current instruction")); } // Update GUI void CCodeWindow::Update() { - if (!codeview) return; + if (!codeview) + return; - codeview->Refresh(); - UpdateCallstack(); - UpdateButtonStates(); + codeview->Refresh(); + UpdateCallstack(); + UpdateButtonStates(); - // Do not automatically show the current PC position when a breakpoint is hit or - // when we pause since this can be called at other times too. - //codeview->Center(PC); + // Do not automatically show the current PC position when a breakpoint is hit or + // when we pause since this can be called at other times too. + // codeview->Center(PC); } void CCodeWindow::UpdateButtonStates() { - bool Initialized = (Core::GetState() != Core::CORE_UNINITIALIZED); - bool Pause = (Core::GetState() == Core::CORE_PAUSE); - bool Stepping = CPU::IsStepping(); - wxToolBar* ToolBar = GetToolBar(); + bool Initialized = (Core::GetState() != Core::CORE_UNINITIALIZED); + bool Pause = (Core::GetState() == Core::CORE_PAUSE); + bool Stepping = CPU::IsStepping(); + wxToolBar* ToolBar = GetToolBar(); - // Toolbar - if (!ToolBar) - return; + // Toolbar + if (!ToolBar) + return; - if (!Initialized) - { - ToolBar->EnableTool(IDM_STEPOVER, false); - ToolBar->EnableTool(IDM_STEPOUT, false); - ToolBar->EnableTool(IDM_SKIP, false); - } - else - { - if (!Stepping) - { - ToolBar->EnableTool(IDM_STEPOVER, false); - ToolBar->EnableTool(IDM_STEPOUT, false); - ToolBar->EnableTool(IDM_SKIP, false); - } - else - { - ToolBar->EnableTool(IDM_STEPOVER, true); - ToolBar->EnableTool(IDM_STEPOUT, true); - ToolBar->EnableTool(IDM_SKIP, true); - } - } + if (!Initialized) + { + ToolBar->EnableTool(IDM_STEPOVER, false); + ToolBar->EnableTool(IDM_STEPOUT, false); + ToolBar->EnableTool(IDM_SKIP, false); + } + else + { + if (!Stepping) + { + ToolBar->EnableTool(IDM_STEPOVER, false); + ToolBar->EnableTool(IDM_STEPOUT, false); + ToolBar->EnableTool(IDM_SKIP, false); + } + else + { + ToolBar->EnableTool(IDM_STEPOVER, true); + ToolBar->EnableTool(IDM_STEPOUT, true); + ToolBar->EnableTool(IDM_SKIP, true); + } + } - ToolBar->EnableTool(IDM_STEP, Initialized && Stepping); - ToolBar->Realize(); + ToolBar->EnableTool(IDM_STEP, Initialized && Stepping); + ToolBar->Realize(); - // Menu bar - // ------------------ - GetMenuBar()->Enable(IDM_INTERPRETER, Pause); // CPU Mode + // Menu bar + // ------------------ + GetMenuBar()->Enable(IDM_INTERPRETER, Pause); // CPU Mode - GetMenuBar()->Enable(IDM_JIT_NO_BLOCK_CACHE, !Initialized); + GetMenuBar()->Enable(IDM_JIT_NO_BLOCK_CACHE, !Initialized); - GetMenuBar()->Enable(IDM_JIT_OFF, Pause); - GetMenuBar()->Enable(IDM_JIT_LS_OFF, Pause); - GetMenuBar()->Enable(IDM_JIT_LSLXZ_OFF, Pause); - GetMenuBar()->Enable(IDM_JIT_LSLWZ_OFF, Pause); - GetMenuBar()->Enable(IDM_JIT_LSLBZX_OFF, Pause); - GetMenuBar()->Enable(IDM_JIT_LSF_OFF, Pause); - GetMenuBar()->Enable(IDM_JIT_LSP_OFF, Pause); - GetMenuBar()->Enable(IDM_JIT_FP_OFF, Pause); - GetMenuBar()->Enable(IDM_JIT_I_OFF, Pause); - GetMenuBar()->Enable(IDM_JIT_P_OFF, Pause); - GetMenuBar()->Enable(IDM_JIT_SR_OFF, Pause); + GetMenuBar()->Enable(IDM_JIT_OFF, Pause); + GetMenuBar()->Enable(IDM_JIT_LS_OFF, Pause); + GetMenuBar()->Enable(IDM_JIT_LSLXZ_OFF, Pause); + GetMenuBar()->Enable(IDM_JIT_LSLWZ_OFF, Pause); + GetMenuBar()->Enable(IDM_JIT_LSLBZX_OFF, Pause); + GetMenuBar()->Enable(IDM_JIT_LSF_OFF, Pause); + GetMenuBar()->Enable(IDM_JIT_LSP_OFF, Pause); + GetMenuBar()->Enable(IDM_JIT_FP_OFF, Pause); + GetMenuBar()->Enable(IDM_JIT_I_OFF, Pause); + GetMenuBar()->Enable(IDM_JIT_P_OFF, Pause); + GetMenuBar()->Enable(IDM_JIT_SR_OFF, Pause); - GetMenuBar()->Enable(IDM_CLEAR_CODE_CACHE, Pause); // JIT Menu - GetMenuBar()->Enable(IDM_SEARCH_INSTRUCTION, Initialized); + GetMenuBar()->Enable(IDM_CLEAR_CODE_CACHE, Pause); // JIT Menu + GetMenuBar()->Enable(IDM_SEARCH_INSTRUCTION, Initialized); - GetMenuBar()->Enable(IDM_CLEAR_SYMBOLS, Initialized); // Symbols menu - GetMenuBar()->Enable(IDM_SCAN_FUNCTIONS, Initialized); - GetMenuBar()->Enable(IDM_LOAD_MAP_FILE, Initialized); - GetMenuBar()->Enable(IDM_SAVEMAPFILE, Initialized); - GetMenuBar()->Enable(IDM_LOAD_MAP_FILE_AS, Initialized); - GetMenuBar()->Enable(IDM_SAVE_MAP_FILE_AS, Initialized); - GetMenuBar()->Enable(IDM_LOAD_BAD_MAP_FILE, Initialized); - GetMenuBar()->Enable(IDM_SAVE_MAP_FILE_WITH_CODES, Initialized); - GetMenuBar()->Enable(IDM_CREATE_SIGNATURE_FILE, Initialized); - GetMenuBar()->Enable(IDM_APPEND_SIGNATURE_FILE, Initialized); - GetMenuBar()->Enable(IDM_COMBINE_SIGNATURE_FILES, Initialized); - GetMenuBar()->Enable(IDM_RENAME_SYMBOLS, Initialized); - GetMenuBar()->Enable(IDM_USE_SIGNATURE_FILE, Initialized); - GetMenuBar()->Enable(IDM_PATCH_HLE_FUNCTIONS, Initialized); + GetMenuBar()->Enable(IDM_CLEAR_SYMBOLS, Initialized); // Symbols menu + GetMenuBar()->Enable(IDM_SCAN_FUNCTIONS, Initialized); + GetMenuBar()->Enable(IDM_LOAD_MAP_FILE, Initialized); + GetMenuBar()->Enable(IDM_SAVEMAPFILE, Initialized); + GetMenuBar()->Enable(IDM_LOAD_MAP_FILE_AS, Initialized); + GetMenuBar()->Enable(IDM_SAVE_MAP_FILE_AS, Initialized); + GetMenuBar()->Enable(IDM_LOAD_BAD_MAP_FILE, Initialized); + GetMenuBar()->Enable(IDM_SAVE_MAP_FILE_WITH_CODES, Initialized); + GetMenuBar()->Enable(IDM_CREATE_SIGNATURE_FILE, Initialized); + GetMenuBar()->Enable(IDM_APPEND_SIGNATURE_FILE, Initialized); + GetMenuBar()->Enable(IDM_COMBINE_SIGNATURE_FILES, Initialized); + GetMenuBar()->Enable(IDM_RENAME_SYMBOLS, Initialized); + GetMenuBar()->Enable(IDM_USE_SIGNATURE_FILE, Initialized); + GetMenuBar()->Enable(IDM_PATCH_HLE_FUNCTIONS, Initialized); - // Update Fonts - callstack->SetFont(DebuggerFont); - symbols->SetFont(DebuggerFont); - callers->SetFont(DebuggerFont); - calls->SetFont(DebuggerFont); + // Update Fonts + callstack->SetFont(DebuggerFont); + symbols->SetFont(DebuggerFont); + callers->SetFont(DebuggerFont); + calls->SetFont(DebuggerFont); } diff --git a/Source/Core/DolphinWX/Debugger/CodeWindow.h b/Source/Core/DolphinWX/Debugger/CodeWindow.h index bafed76fec..25d1b4fa30 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindow.h +++ b/Source/Core/DolphinWX/Debugger/CodeWindow.h @@ -4,9 +4,9 @@ #pragma once +#include #include #include -#include #include "Common/CommonTypes.h" #include "Common/Event.h" @@ -32,101 +32,98 @@ class wxToolBar; class CCodeWindow : public wxPanel { public: - CCodeWindow(const SConfig& _LocalCoreStartupParameter, - CFrame * parent, - wxWindowID id = wxID_ANY, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxTAB_TRAVERSAL | wxBORDER_NONE, - const wxString& name = _("Code")); - ~CCodeWindow(); + CCodeWindow(const SConfig& _LocalCoreStartupParameter, CFrame* parent, wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxTAB_TRAVERSAL | wxBORDER_NONE, const wxString& name = _("Code")); + ~CCodeWindow(); - void Load(); - void Save(); + void Load(); + void Save(); - // Parent interaction - CFrame *Parent; - wxMenuBar * GetMenuBar(); - wxToolBar * GetToolBar(); - wxBitmap m_Bitmaps[Toolbar_Debug_Bitmap_Max]; + // Parent interaction + CFrame* Parent; + wxMenuBar* GetMenuBar(); + wxToolBar* GetToolBar(); + wxBitmap m_Bitmaps[Toolbar_Debug_Bitmap_Max]; - bool UseInterpreter(); - bool BootToPause(); - bool AutomaticStart(); - bool JITNoBlockCache(); - bool JITNoBlockLinking(); - bool JumpToAddress(u32 address); + bool UseInterpreter(); + bool BootToPause(); + bool AutomaticStart(); + bool JITNoBlockCache(); + bool JITNoBlockLinking(); + bool JumpToAddress(u32 address); - void Update() override; - void NotifyMapLoaded(); - void CreateMenu(const SConfig& _LocalCoreStartupParameter, wxMenuBar *pMenuBar); - void CreateMenuOptions(wxMenu *pMenu); - void CreateMenuSymbols(wxMenuBar *pMenuBar); - void PopulateToolbar(wxToolBar* toolBar); - void UpdateButtonStates(); - void OpenPages(); + void Update() override; + void NotifyMapLoaded(); + void CreateMenu(const SConfig& _LocalCoreStartupParameter, wxMenuBar* pMenuBar); + void CreateMenuOptions(wxMenu* pMenu); + void CreateMenuSymbols(wxMenuBar* pMenuBar); + void PopulateToolbar(wxToolBar* toolBar); + void UpdateButtonStates(); + void OpenPages(); - // Menu bar - void ToggleCodeWindow(bool bShow); - void ToggleRegisterWindow(bool bShow); - void ToggleWatchWindow(bool bShow); - void ToggleBreakPointWindow(bool bShow); - void ToggleMemoryWindow(bool bShow); - void ToggleJitWindow(bool bShow); - void ToggleSoundWindow(bool bShow); - void ToggleVideoWindow(bool bShow); + // Menu bar + void ToggleCodeWindow(bool bShow); + void ToggleRegisterWindow(bool bShow); + void ToggleWatchWindow(bool bShow); + void ToggleBreakPointWindow(bool bShow); + void ToggleMemoryWindow(bool bShow); + void ToggleJitWindow(bool bShow); + void ToggleSoundWindow(bool bShow); + void ToggleVideoWindow(bool bShow); - // Sub dialogs - CRegisterWindow* m_RegisterWindow; - CWatchWindow* m_WatchWindow; - CBreakPointWindow* m_BreakpointWindow; - CMemoryWindow* m_MemoryWindow; - CJitWindow* m_JitWindow; - DSPDebuggerLLE* m_SoundWindow; - GFXDebuggerPanel* m_VideoWindow; + // Sub dialogs + CRegisterWindow* m_RegisterWindow; + CWatchWindow* m_WatchWindow; + CBreakPointWindow* m_BreakpointWindow; + CMemoryWindow* m_MemoryWindow; + CJitWindow* m_JitWindow; + DSPDebuggerLLE* m_SoundWindow; + GFXDebuggerPanel* m_VideoWindow; - // Settings - bool bAutomaticStart; bool bBootToPause; - bool bShowOnStart[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW + 1]; - int iNbAffiliation[IDM_CODE_WINDOW - IDM_LOG_WINDOW + 1]; + // Settings + bool bAutomaticStart; + bool bBootToPause; + bool bShowOnStart[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW + 1]; + int iNbAffiliation[IDM_CODE_WINDOW - IDM_LOG_WINDOW + 1]; private: - void OnCPUMode(wxCommandEvent& event); + void OnCPUMode(wxCommandEvent& event); - void OnChangeFont(wxCommandEvent& event); + void OnChangeFont(wxCommandEvent& event); - void OnCodeStep(wxCommandEvent& event); - void OnAddrBoxChange(wxCommandEvent& event); - void OnSymbolsMenu(wxCommandEvent& event); - void OnJitMenu(wxCommandEvent& event); - void OnProfilerMenu(wxCommandEvent& event); + void OnCodeStep(wxCommandEvent& event); + void OnAddrBoxChange(wxCommandEvent& event); + void OnSymbolsMenu(wxCommandEvent& event); + void OnJitMenu(wxCommandEvent& event); + void OnProfilerMenu(wxCommandEvent& event); - void OnSymbolListChange(wxCommandEvent& event); - void OnSymbolListContextMenu(wxContextMenuEvent& event); - void OnCallstackListChange(wxCommandEvent& event); - void OnCallersListChange(wxCommandEvent& event); - void OnCallsListChange(wxCommandEvent& event); - void OnCodeViewChange(wxCommandEvent &event); - void OnHostMessage(wxCommandEvent& event); + void OnSymbolListChange(wxCommandEvent& event); + void OnSymbolListContextMenu(wxContextMenuEvent& event); + void OnCallstackListChange(wxCommandEvent& event); + void OnCallersListChange(wxCommandEvent& event); + void OnCallsListChange(wxCommandEvent& event); + void OnCodeViewChange(wxCommandEvent& event); + void OnHostMessage(wxCommandEvent& event); - // Debugger functions - void SingleStep(); - void StepOver(); - void StepOut(); - void ToggleBreakpoint(); + // Debugger functions + void SingleStep(); + void StepOver(); + void StepOut(); + void ToggleBreakpoint(); - void UpdateLists(); - void UpdateCallstack(); + void UpdateLists(); + void UpdateCallstack(); - void InitBitmaps(); + void InitBitmaps(); - CCodeView* codeview; - wxListBox* callstack; - wxListBox* symbols; - wxListBox* callers; - wxListBox* calls; - Common::Event sync_event; + CCodeView* codeview; + wxListBox* callstack; + wxListBox* symbols; + wxListBox* callers; + wxListBox* calls; + Common::Event sync_event; - wxAuiManager m_aui_manager; - wxAuiToolBar* m_aui_toolbar; + wxAuiManager m_aui_manager; + wxAuiToolBar* m_aui_toolbar; }; diff --git a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp index c894c6b9ce..d46ca84432 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp @@ -22,494 +22,480 @@ #include "Common/IniFile.h" #include "Common/SymbolDB.h" -#include "Core/Core.h" -#include "Core/Host.h" #include "Core/Boot/Boot.h" +#include "Core/Core.h" #include "Core/HLE/HLE.h" -#include "Core/PowerPC/PowerPC.h" +#include "Core/Host.h" +#include "Core/PowerPC/JitCommon/JitBase.h" #include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/PPCSymbolDB.h" +#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/Profiler.h" #include "Core/PowerPC/SignatureDB.h" -#include "Core/PowerPC/JitCommon/JitBase.h" -#include "DolphinWX/Frame.h" -#include "DolphinWX/Globals.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Debugger/BreakpointWindow.h" #include "DolphinWX/Debugger/CodeWindow.h" +#include "DolphinWX/Debugger/DSPDebugWindow.h" #include "DolphinWX/Debugger/DebuggerPanel.h" #include "DolphinWX/Debugger/DebuggerUIUtil.h" -#include "DolphinWX/Debugger/DSPDebugWindow.h" #include "DolphinWX/Debugger/JitWindow.h" #include "DolphinWX/Debugger/MemoryWindow.h" #include "DolphinWX/Debugger/RegisterWindow.h" #include "DolphinWX/Debugger/WatchWindow.h" - +#include "DolphinWX/Frame.h" +#include "DolphinWX/Globals.h" +#include "DolphinWX/WxUtils.h" // Save and load settings // ----------------------------- void CCodeWindow::Load() { - IniFile ini; - ini.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); + IniFile ini; + ini.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); - // The font to override DebuggerFont with - std::string fontDesc; + // The font to override DebuggerFont with + std::string fontDesc; - IniFile::Section* general = ini.GetOrCreateSection("General"); - general->Get("DebuggerFont", &fontDesc); - general->Get("AutomaticStart", &bAutomaticStart, false); - general->Get("BootToPause", &bBootToPause, true); + IniFile::Section* general = ini.GetOrCreateSection("General"); + general->Get("DebuggerFont", &fontDesc); + general->Get("AutomaticStart", &bAutomaticStart, false); + general->Get("BootToPause", &bBootToPause, true); - if (!fontDesc.empty()) - DebuggerFont.SetNativeFontInfoUserDesc(StrToWxStr(fontDesc)); + if (!fontDesc.empty()) + DebuggerFont.SetNativeFontInfoUserDesc(StrToWxStr(fontDesc)); - const char* SettingName[] = { - "Log", - "LogConfig", - "Console", - "Registers", - "Breakpoints", - "Memory", - "JIT", - "Sound", - "Video", - "Code" - }; + const char* SettingName[] = {"Log", "LogConfig", "Console", "Registers", "Breakpoints", + "Memory", "JIT", "Sound", "Video", "Code"}; - // Decide what windows to show - for (int i = 0; i <= IDM_VIDEO_WINDOW - IDM_LOG_WINDOW; i++) - ini.GetOrCreateSection("ShowOnStart")->Get(SettingName[i], &bShowOnStart[i], false); + // Decide what windows to show + for (int i = 0; i <= IDM_VIDEO_WINDOW - IDM_LOG_WINDOW; i++) + ini.GetOrCreateSection("ShowOnStart")->Get(SettingName[i], &bShowOnStart[i], false); - // Get notebook affiliation - std::string section = "P - " + - ((Parent->ActivePerspective < Parent->Perspectives.size()) - ? Parent->Perspectives[Parent->ActivePerspective].Name : "Perspective 1"); + // Get notebook affiliation + std::string section = "P - " + ((Parent->ActivePerspective < Parent->Perspectives.size()) ? + Parent->Perspectives[Parent->ActivePerspective].Name : + "Perspective 1"); - for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++) - ini.GetOrCreateSection(section)->Get(SettingName[i], &iNbAffiliation[i], 0); + for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++) + ini.GetOrCreateSection(section)->Get(SettingName[i], &iNbAffiliation[i], 0); - // Get floating setting - for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++) - ini.GetOrCreateSection("Float")->Get(SettingName[i], &Parent->bFloatWindow[i], false); + // Get floating setting + for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++) + ini.GetOrCreateSection("Float")->Get(SettingName[i], &Parent->bFloatWindow[i], false); } void CCodeWindow::Save() { - IniFile ini; - ini.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); + IniFile ini; + ini.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); - IniFile::Section* general = ini.GetOrCreateSection("General"); - general->Set("DebuggerFont", WxStrToStr(DebuggerFont.GetNativeFontInfoUserDesc())); - general->Set("AutomaticStart", GetMenuBar()->IsChecked(IDM_AUTOMATIC_START)); - general->Set("BootToPause", GetMenuBar()->IsChecked(IDM_BOOT_TO_PAUSE)); + IniFile::Section* general = ini.GetOrCreateSection("General"); + general->Set("DebuggerFont", WxStrToStr(DebuggerFont.GetNativeFontInfoUserDesc())); + general->Set("AutomaticStart", GetMenuBar()->IsChecked(IDM_AUTOMATIC_START)); + general->Set("BootToPause", GetMenuBar()->IsChecked(IDM_BOOT_TO_PAUSE)); - const char* SettingName[] = { - "Log", - "LogConfig", - "Console", - "Registers", - "Breakpoints", - "Memory", - "JIT", - "Sound", - "Video", - "Code" - }; + const char* SettingName[] = {"Log", "LogConfig", "Console", "Registers", "Breakpoints", + "Memory", "JIT", "Sound", "Video", "Code"}; - // Save windows settings - for (int i = IDM_LOG_WINDOW; i <= IDM_VIDEO_WINDOW; i++) - ini.GetOrCreateSection("ShowOnStart")->Set(SettingName[i - IDM_LOG_WINDOW], GetMenuBar()->IsChecked(i)); + // Save windows settings + for (int i = IDM_LOG_WINDOW; i <= IDM_VIDEO_WINDOW; i++) + ini.GetOrCreateSection("ShowOnStart") + ->Set(SettingName[i - IDM_LOG_WINDOW], GetMenuBar()->IsChecked(i)); - // Save notebook affiliations - std::string section = "P - " + Parent->Perspectives[Parent->ActivePerspective].Name; - for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++) - ini.GetOrCreateSection(section)->Set(SettingName[i], iNbAffiliation[i]); + // Save notebook affiliations + std::string section = "P - " + Parent->Perspectives[Parent->ActivePerspective].Name; + for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++) + ini.GetOrCreateSection(section)->Set(SettingName[i], iNbAffiliation[i]); - // Save floating setting - for (int i = IDM_LOG_WINDOW_PARENT; i <= IDM_CODE_WINDOW_PARENT; i++) - ini.GetOrCreateSection("Float")->Set(SettingName[i - IDM_LOG_WINDOW_PARENT], !!FindWindowById(i)); + // Save floating setting + for (int i = IDM_LOG_WINDOW_PARENT; i <= IDM_CODE_WINDOW_PARENT; i++) + ini.GetOrCreateSection("Float")->Set(SettingName[i - IDM_LOG_WINDOW_PARENT], + !!FindWindowById(i)); - ini.Save(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); + ini.Save(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); } // Symbols, JIT, Profiler // ---------------- -void CCodeWindow::CreateMenuSymbols(wxMenuBar *pMenuBar) +void CCodeWindow::CreateMenuSymbols(wxMenuBar* pMenuBar) { - wxMenu *pSymbolsMenu = new wxMenu; - pSymbolsMenu->Append(IDM_CLEAR_SYMBOLS, _("&Clear symbols"), - _("Remove names from all functions and variables.")); - pSymbolsMenu->Append(IDM_SCAN_FUNCTIONS, _("&Generate symbol map"), - _("Recognise standard functions from sys\\totaldb.dsy, and use generic zz_ names for other functions.")); - pSymbolsMenu->AppendSeparator(); - pSymbolsMenu->Append(IDM_LOAD_MAP_FILE, _("&Load symbol map"), - _("Try to load this game's function names automatically - but doesn't check .map files stored on the disc image yet.")); - pSymbolsMenu->Append(IDM_SAVEMAPFILE, _("&Save symbol map"), - _("Save the function names for each address to a .map file in your user settings map folder, named after the title id.")); - pSymbolsMenu->AppendSeparator(); - pSymbolsMenu->Append(IDM_LOAD_MAP_FILE_AS, _("Load &other map file..."), - _("Load any .map file containing the function names and addresses for this game.")); - pSymbolsMenu->Append(IDM_LOAD_BAD_MAP_FILE, _("Load &bad map file..."), - _("Try to load a .map file that might be from a slightly different version.")); - pSymbolsMenu->Append(IDM_SAVE_MAP_FILE_AS, _("Save symbol map &as..."), - _("Save the function names and addresses for this game as a .map file. If you want to open it in IDA pro, use the .idc script.")); - pSymbolsMenu->AppendSeparator(); - pSymbolsMenu->Append(IDM_SAVE_MAP_FILE_WITH_CODES, _("Save code"), - _("Save the entire disassembled code. This may take a several seconds" - " and may require between 50 and 100 MB of hard drive space. It will only save code" - " that are in the first 4 MB of memory, if you are debugging a game that load .rel" - " files with code to memory you may want to increase that to perhaps 8 MB, you can do" - " that from SymbolDB::SaveMap().") - ); + wxMenu* pSymbolsMenu = new wxMenu; + pSymbolsMenu->Append(IDM_CLEAR_SYMBOLS, _("&Clear symbols"), + _("Remove names from all functions and variables.")); + pSymbolsMenu->Append(IDM_SCAN_FUNCTIONS, _("&Generate symbol map"), + _("Recognise standard functions from sys\\totaldb.dsy, and use generic zz_ " + "names for other functions.")); + pSymbolsMenu->AppendSeparator(); + pSymbolsMenu->Append(IDM_LOAD_MAP_FILE, _("&Load symbol map"), + _("Try to load this game's function names automatically - but doesn't check " + ".map files stored on the disc image yet.")); + pSymbolsMenu->Append(IDM_SAVEMAPFILE, _("&Save symbol map"), + _("Save the function names for each address to a .map file in your user " + "settings map folder, named after the title id.")); + pSymbolsMenu->AppendSeparator(); + pSymbolsMenu->Append( + IDM_LOAD_MAP_FILE_AS, _("Load &other map file..."), + _("Load any .map file containing the function names and addresses for this game.")); + pSymbolsMenu->Append( + IDM_LOAD_BAD_MAP_FILE, _("Load &bad map file..."), + _("Try to load a .map file that might be from a slightly different version.")); + pSymbolsMenu->Append(IDM_SAVE_MAP_FILE_AS, _("Save symbol map &as..."), + _("Save the function names and addresses for this game as a .map file. If " + "you want to open it in IDA pro, use the .idc script.")); + pSymbolsMenu->AppendSeparator(); + pSymbolsMenu->Append( + IDM_SAVE_MAP_FILE_WITH_CODES, _("Save code"), + _("Save the entire disassembled code. This may take a several seconds" + " and may require between 50 and 100 MB of hard drive space. It will only save code" + " that are in the first 4 MB of memory, if you are debugging a game that load .rel" + " files with code to memory you may want to increase that to perhaps 8 MB, you can do" + " that from SymbolDB::SaveMap().")); - pSymbolsMenu->AppendSeparator(); - pSymbolsMenu->Append(IDM_CREATE_SIGNATURE_FILE, _("&Create signature file..."), - _("Create a .dsy file that can be used to recognise these same functions in other games.")); - pSymbolsMenu->Append(IDM_APPEND_SIGNATURE_FILE, _("Append to &existing signature file..."), - _("Add any named functions missing from a .dsy file, so it can also recognise these additional functions in other games.")); - pSymbolsMenu->Append(IDM_COMBINE_SIGNATURE_FILES, _("Combine two signature files..."), - _("Make a new .dsy file which can recognise more functions, by combining two existing files. The first input file has priority.")); - pSymbolsMenu->Append(IDM_USE_SIGNATURE_FILE, _("Apply signat&ure file..."), - _("Must use Generate symbol map first! Recognise names of any standard library functions used in multiple games, by loading them from a .dsy file.")); - pSymbolsMenu->AppendSeparator(); - pSymbolsMenu->Append(IDM_PATCH_HLE_FUNCTIONS, _("&Patch HLE functions")); - pSymbolsMenu->Append(IDM_RENAME_SYMBOLS, _("&Rename symbols from file...")); - pMenuBar->Append(pSymbolsMenu, _("&Symbols")); + pSymbolsMenu->AppendSeparator(); + pSymbolsMenu->Append( + IDM_CREATE_SIGNATURE_FILE, _("&Create signature file..."), + _("Create a .dsy file that can be used to recognise these same functions in other games.")); + pSymbolsMenu->Append(IDM_APPEND_SIGNATURE_FILE, _("Append to &existing signature file..."), + _("Add any named functions missing from a .dsy file, so it can also " + "recognise these additional functions in other games.")); + pSymbolsMenu->Append(IDM_COMBINE_SIGNATURE_FILES, _("Combine two signature files..."), + _("Make a new .dsy file which can recognise more functions, by combining " + "two existing files. The first input file has priority.")); + pSymbolsMenu->Append( + IDM_USE_SIGNATURE_FILE, _("Apply signat&ure file..."), + _("Must use Generate symbol map first! Recognise names of any standard library functions " + "used in multiple games, by loading them from a .dsy file.")); + pSymbolsMenu->AppendSeparator(); + pSymbolsMenu->Append(IDM_PATCH_HLE_FUNCTIONS, _("&Patch HLE functions")); + pSymbolsMenu->Append(IDM_RENAME_SYMBOLS, _("&Rename symbols from file...")); + pMenuBar->Append(pSymbolsMenu, _("&Symbols")); - wxMenu *pProfilerMenu = new wxMenu; - pProfilerMenu->Append(IDM_PROFILE_BLOCKS, _("&Profile blocks"), wxEmptyString, wxITEM_CHECK); - pProfilerMenu->AppendSeparator(); - pProfilerMenu->Append(IDM_WRITE_PROFILE, _("&Write to profile.txt, show")); - pMenuBar->Append(pProfilerMenu, _("&Profiler")); + wxMenu* pProfilerMenu = new wxMenu; + pProfilerMenu->Append(IDM_PROFILE_BLOCKS, _("&Profile blocks"), wxEmptyString, wxITEM_CHECK); + pProfilerMenu->AppendSeparator(); + pProfilerMenu->Append(IDM_WRITE_PROFILE, _("&Write to profile.txt, show")); + pMenuBar->Append(pProfilerMenu, _("&Profiler")); } void CCodeWindow::OnProfilerMenu(wxCommandEvent& event) { - switch (event.GetId()) - { - case IDM_PROFILE_BLOCKS: - Core::SetState(Core::CORE_PAUSE); - if (jit != nullptr) - jit->ClearCache(); - Profiler::g_ProfileBlocks = GetMenuBar()->IsChecked(IDM_PROFILE_BLOCKS); - Core::SetState(Core::CORE_RUN); - break; - case IDM_WRITE_PROFILE: - if (Core::GetState() == Core::CORE_RUN) - Core::SetState(Core::CORE_PAUSE); + switch (event.GetId()) + { + case IDM_PROFILE_BLOCKS: + Core::SetState(Core::CORE_PAUSE); + if (jit != nullptr) + jit->ClearCache(); + Profiler::g_ProfileBlocks = GetMenuBar()->IsChecked(IDM_PROFILE_BLOCKS); + Core::SetState(Core::CORE_RUN); + break; + case IDM_WRITE_PROFILE: + if (Core::GetState() == Core::CORE_RUN) + Core::SetState(Core::CORE_PAUSE); - if (Core::GetState() == Core::CORE_PAUSE && PowerPC::GetMode() == PowerPC::MODE_JIT) - { - if (jit != nullptr) - { - std::string filename = File::GetUserPath(D_DUMP_IDX) + "Debug/profiler.txt"; - File::CreateFullPath(filename); - Profiler::WriteProfileResults(filename); + if (Core::GetState() == Core::CORE_PAUSE && PowerPC::GetMode() == PowerPC::MODE_JIT) + { + if (jit != nullptr) + { + std::string filename = File::GetUserPath(D_DUMP_IDX) + "Debug/profiler.txt"; + File::CreateFullPath(filename); + Profiler::WriteProfileResults(filename); - wxFileType* filetype = nullptr; - if (!(filetype = wxTheMimeTypesManager->GetFileTypeFromExtension("txt"))) - { - // From extension failed, trying with MIME type now - if (!(filetype = wxTheMimeTypesManager->GetFileTypeFromMimeType("text/plain"))) - // MIME type failed, aborting mission - break; - } - wxString OpenCommand; - OpenCommand = filetype->GetOpenCommand(StrToWxStr(filename)); - if (!OpenCommand.IsEmpty()) - wxExecute(OpenCommand, wxEXEC_SYNC); - } - } - break; - } + wxFileType* filetype = nullptr; + if (!(filetype = wxTheMimeTypesManager->GetFileTypeFromExtension("txt"))) + { + // From extension failed, trying with MIME type now + if (!(filetype = wxTheMimeTypesManager->GetFileTypeFromMimeType("text/plain"))) + // MIME type failed, aborting mission + break; + } + wxString OpenCommand; + OpenCommand = filetype->GetOpenCommand(StrToWxStr(filename)); + if (!OpenCommand.IsEmpty()) + wxExecute(OpenCommand, wxEXEC_SYNC); + } + } + break; + } } void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event) { - Parent->ClearStatusBar(); + Parent->ClearStatusBar(); - if (!Core::IsRunning()) return; + if (!Core::IsRunning()) + return; - std::string existing_map_file, writable_map_file, title_id_str; - bool map_exists = CBoot::FindMapFile(&existing_map_file, - &writable_map_file, - &title_id_str); - switch (event.GetId()) - { - case IDM_CLEAR_SYMBOLS: - if (!AskYesNoT("Do you want to clear the list of symbol names?")) return; - g_symbolDB.Clear(); - Host_NotifyMapLoaded(); - break; - case IDM_SCAN_FUNCTIONS: - { - PPCAnalyst::FindFunctions(0x80000000, 0x81800000, &g_symbolDB); - SignatureDB db; - if (db.Load(File::GetSysDirectory() + TOTALDB)) - { - db.Apply(&g_symbolDB); - Parent->StatusBarMessage("Generated symbol names from '%s'", TOTALDB); - db.List(); - } - else - { - Parent->StatusBarMessage("'%s' not found, no symbol names generated", TOTALDB); - } - // HLE::PatchFunctions(); - // Update GUI - NotifyMapLoaded(); - break; - } - case IDM_LOAD_MAP_FILE: - if (!map_exists) - { - g_symbolDB.Clear(); - PPCAnalyst::FindFunctions(0x81300000, 0x81800000, &g_symbolDB); - SignatureDB db; - if (db.Load(File::GetSysDirectory() + TOTALDB)) - db.Apply(&g_symbolDB); - Parent->StatusBarMessage("'%s' not found, scanning for common functions instead", writable_map_file.c_str()); - } - else - { - g_symbolDB.LoadMap(existing_map_file); - Parent->StatusBarMessage("Loaded symbols from '%s'", existing_map_file.c_str()); - } - HLE::PatchFunctions(); - NotifyMapLoaded(); - break; - case IDM_LOAD_MAP_FILE_AS: - { - const wxString path = wxFileSelector( - _("Load map file"), File::GetUserPath(D_MAPS_IDX), - title_id_str + ".map", ".map", - _("Dolphin Map File (*.map)") + "|*.map|" + wxGetTranslation(wxALL_FILES), - wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); + std::string existing_map_file, writable_map_file, title_id_str; + bool map_exists = CBoot::FindMapFile(&existing_map_file, &writable_map_file, &title_id_str); + switch (event.GetId()) + { + case IDM_CLEAR_SYMBOLS: + if (!AskYesNoT("Do you want to clear the list of symbol names?")) + return; + g_symbolDB.Clear(); + Host_NotifyMapLoaded(); + break; + case IDM_SCAN_FUNCTIONS: + { + PPCAnalyst::FindFunctions(0x80000000, 0x81800000, &g_symbolDB); + SignatureDB db; + if (db.Load(File::GetSysDirectory() + TOTALDB)) + { + db.Apply(&g_symbolDB); + Parent->StatusBarMessage("Generated symbol names from '%s'", TOTALDB); + db.List(); + } + else + { + Parent->StatusBarMessage("'%s' not found, no symbol names generated", TOTALDB); + } + // HLE::PatchFunctions(); + // Update GUI + NotifyMapLoaded(); + break; + } + case IDM_LOAD_MAP_FILE: + if (!map_exists) + { + g_symbolDB.Clear(); + PPCAnalyst::FindFunctions(0x81300000, 0x81800000, &g_symbolDB); + SignatureDB db; + if (db.Load(File::GetSysDirectory() + TOTALDB)) + db.Apply(&g_symbolDB); + Parent->StatusBarMessage("'%s' not found, scanning for common functions instead", + writable_map_file.c_str()); + } + else + { + g_symbolDB.LoadMap(existing_map_file); + Parent->StatusBarMessage("Loaded symbols from '%s'", existing_map_file.c_str()); + } + HLE::PatchFunctions(); + NotifyMapLoaded(); + break; + case IDM_LOAD_MAP_FILE_AS: + { + const wxString path = wxFileSelector( + _("Load map file"), File::GetUserPath(D_MAPS_IDX), title_id_str + ".map", ".map", + _("Dolphin Map File (*.map)") + "|*.map|" + wxGetTranslation(wxALL_FILES), + wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); - if (!path.IsEmpty()) - { - g_symbolDB.LoadMap(WxStrToStr(path)); - Parent->StatusBarMessage("Loaded symbols from '%s'", WxStrToStr(path).c_str()); - } - HLE::PatchFunctions(); - NotifyMapLoaded(); - } - break; - case IDM_LOAD_BAD_MAP_FILE: - { - const wxString path = wxFileSelector( - _("Load bad map file"), File::GetUserPath(D_MAPS_IDX), - title_id_str + ".map", ".map", - _("Dolphin Map File (*.map)") + "|*.map|" + wxGetTranslation(wxALL_FILES), - wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); + if (!path.IsEmpty()) + { + g_symbolDB.LoadMap(WxStrToStr(path)); + Parent->StatusBarMessage("Loaded symbols from '%s'", WxStrToStr(path).c_str()); + } + HLE::PatchFunctions(); + NotifyMapLoaded(); + } + break; + case IDM_LOAD_BAD_MAP_FILE: + { + const wxString path = wxFileSelector( + _("Load bad map file"), File::GetUserPath(D_MAPS_IDX), title_id_str + ".map", ".map", + _("Dolphin Map File (*.map)") + "|*.map|" + wxGetTranslation(wxALL_FILES), + wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); - if (!path.IsEmpty()) - { - g_symbolDB.LoadMap(WxStrToStr(path), true); - Parent->StatusBarMessage("Loaded symbols from '%s'", WxStrToStr(path).c_str()); - } - HLE::PatchFunctions(); - NotifyMapLoaded(); - } - break; - case IDM_SAVEMAPFILE: - g_symbolDB.SaveMap(writable_map_file); - break; - case IDM_SAVE_MAP_FILE_AS: - { - const wxString path = wxFileSelector( - _("Save map file as"), File::GetUserPath(D_MAPS_IDX), - title_id_str + ".map", ".map", - _("Dolphin Map File (*.map)") + "|*.map|" + wxGetTranslation(wxALL_FILES), - wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this); + if (!path.IsEmpty()) + { + g_symbolDB.LoadMap(WxStrToStr(path), true); + Parent->StatusBarMessage("Loaded symbols from '%s'", WxStrToStr(path).c_str()); + } + HLE::PatchFunctions(); + NotifyMapLoaded(); + } + break; + case IDM_SAVEMAPFILE: + g_symbolDB.SaveMap(writable_map_file); + break; + case IDM_SAVE_MAP_FILE_AS: + { + const wxString path = wxFileSelector( + _("Save map file as"), File::GetUserPath(D_MAPS_IDX), title_id_str + ".map", ".map", + _("Dolphin Map File (*.map)") + "|*.map|" + wxGetTranslation(wxALL_FILES), + wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this); - if (!path.IsEmpty()) - g_symbolDB.SaveMap(WxStrToStr(path)); - } - break; - case IDM_SAVE_MAP_FILE_WITH_CODES: - g_symbolDB.SaveMap(writable_map_file, true); - break; + if (!path.IsEmpty()) + g_symbolDB.SaveMap(WxStrToStr(path)); + } + break; + case IDM_SAVE_MAP_FILE_WITH_CODES: + g_symbolDB.SaveMap(writable_map_file, true); + break; - case IDM_RENAME_SYMBOLS: - { - const wxString path = wxFileSelector( - _("Apply signature file"), wxEmptyString, - wxEmptyString, wxEmptyString, - _("Dolphin Symbol Rename File (*.sym)") + "|*.sym|" + wxGetTranslation(wxALL_FILES), - wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); + case IDM_RENAME_SYMBOLS: + { + const wxString path = wxFileSelector( + _("Apply signature file"), wxEmptyString, wxEmptyString, wxEmptyString, + _("Dolphin Symbol Rename File (*.sym)") + "|*.sym|" + wxGetTranslation(wxALL_FILES), + wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); - if (!path.IsEmpty()) - { - std::ifstream f; - OpenFStream(f, WxStrToStr(path), std::ios_base::in); + if (!path.IsEmpty()) + { + std::ifstream f; + OpenFStream(f, WxStrToStr(path), std::ios_base::in); - std::string line; - while (std::getline(f, line)) - { - if (line.length() < 12) - continue; + std::string line; + while (std::getline(f, line)) + { + if (line.length() < 12) + continue; - u32 address, type; - std::string name; + u32 address, type; + std::string name; - std::istringstream ss(line); - ss >> std::hex >> address >> std::dec >> type >> name; + std::istringstream ss(line); + ss >> std::hex >> address >> std::dec >> type >> name; - Symbol *symbol = g_symbolDB.GetSymbolFromAddr(address); - if (symbol) - symbol->name = line.substr(12); - } + Symbol* symbol = g_symbolDB.GetSymbolFromAddr(address); + if (symbol) + symbol->name = line.substr(12); + } - Host_NotifyMapLoaded(); - } - } - break; + Host_NotifyMapLoaded(); + } + } + break; - case IDM_CREATE_SIGNATURE_FILE: - { - wxTextEntryDialog input_prefix( - this, - _("Only export symbols with prefix:\n(Blank for all symbols)"), - wxGetTextFromUserPromptStr, - wxEmptyString); + case IDM_CREATE_SIGNATURE_FILE: + { + wxTextEntryDialog input_prefix(this, + _("Only export symbols with prefix:\n(Blank for all symbols)"), + wxGetTextFromUserPromptStr, wxEmptyString); - if (input_prefix.ShowModal() == wxID_OK) - { - std::string prefix(WxStrToStr(input_prefix.GetValue())); + if (input_prefix.ShowModal() == wxID_OK) + { + std::string prefix(WxStrToStr(input_prefix.GetValue())); - wxString path = wxFileSelector( - _("Save signature as"), File::GetSysDirectory(), wxEmptyString, wxEmptyString, - _("Dolphin Signature File (*.dsy)") + "|*.dsy|" + wxGetTranslation(wxALL_FILES), - wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this); - if (!path.IsEmpty()) - { - SignatureDB db; - db.Initialize(&g_symbolDB, prefix); - db.Save(WxStrToStr(path)); - db.List(); - } - } - } - break; - case IDM_APPEND_SIGNATURE_FILE: - { - wxTextEntryDialog input_prefix( - this, - _("Only export symbols with prefix:\n(Blank for all symbols)"), - wxGetTextFromUserPromptStr, - wxEmptyString); + wxString path = wxFileSelector(_("Save signature as"), File::GetSysDirectory(), wxEmptyString, + wxEmptyString, _("Dolphin Signature File (*.dsy)") + + "|*.dsy|" + wxGetTranslation(wxALL_FILES), + wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this); + if (!path.IsEmpty()) + { + SignatureDB db; + db.Initialize(&g_symbolDB, prefix); + db.Save(WxStrToStr(path)); + db.List(); + } + } + } + break; + case IDM_APPEND_SIGNATURE_FILE: + { + wxTextEntryDialog input_prefix(this, + _("Only export symbols with prefix:\n(Blank for all symbols)"), + wxGetTextFromUserPromptStr, wxEmptyString); - if (input_prefix.ShowModal() == wxID_OK) - { - std::string prefix(WxStrToStr(input_prefix.GetValue())); + if (input_prefix.ShowModal() == wxID_OK) + { + std::string prefix(WxStrToStr(input_prefix.GetValue())); - wxString path = wxFileSelector( - _("Append signature to"), File::GetSysDirectory(), wxEmptyString, wxEmptyString, - _("Dolphin Signature File (*.dsy)") + "|*.dsy|" + wxGetTranslation(wxALL_FILES), - wxFD_SAVE, this); - if (!path.IsEmpty()) - { - SignatureDB db; - db.Initialize(&g_symbolDB, prefix); - db.List(); - db.Load(WxStrToStr(path)); - db.Save(WxStrToStr(path)); - db.List(); - } - } - } - break; - case IDM_USE_SIGNATURE_FILE: - { - wxString path = wxFileSelector( - _("Apply signature file"), File::GetSysDirectory(), wxEmptyString, wxEmptyString, - _("Dolphin Signature File (*.dsy)") + "|*.dsy|" + wxGetTranslation(wxALL_FILES), - wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); - if (!path.IsEmpty()) - { - SignatureDB db; - db.Load(WxStrToStr(path)); - db.Apply(&g_symbolDB); - db.List(); - NotifyMapLoaded(); - } - } - break; - case IDM_COMBINE_SIGNATURE_FILES: - { - wxString path1 = wxFileSelector( - _("Choose priority input file"), File::GetSysDirectory(), wxEmptyString, wxEmptyString, - _("Dolphin Signature File (*.dsy)") + "|*.dsy|" + wxGetTranslation(wxALL_FILES), - wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); - if (!path1.IsEmpty()) - { - SignatureDB db; - wxString path2 = wxFileSelector( - _("Choose secondary input file"), File::GetSysDirectory(), wxEmptyString, wxEmptyString, - _("Dolphin Signature File (*.dsy)") + "|*.dsy|" + wxGetTranslation(wxALL_FILES), - wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); - if (!path2.IsEmpty()) - { - db.Load(WxStrToStr(path2)); - db.Load(WxStrToStr(path1)); + wxString path = wxFileSelector( + _("Append signature to"), File::GetSysDirectory(), wxEmptyString, wxEmptyString, + _("Dolphin Signature File (*.dsy)") + "|*.dsy|" + wxGetTranslation(wxALL_FILES), + wxFD_SAVE, this); + if (!path.IsEmpty()) + { + SignatureDB db; + db.Initialize(&g_symbolDB, prefix); + db.List(); + db.Load(WxStrToStr(path)); + db.Save(WxStrToStr(path)); + db.List(); + } + } + } + break; + case IDM_USE_SIGNATURE_FILE: + { + wxString path = wxFileSelector( + _("Apply signature file"), File::GetSysDirectory(), wxEmptyString, wxEmptyString, + _("Dolphin Signature File (*.dsy)") + "|*.dsy|" + wxGetTranslation(wxALL_FILES), + wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); + if (!path.IsEmpty()) + { + SignatureDB db; + db.Load(WxStrToStr(path)); + db.Apply(&g_symbolDB); + db.List(); + NotifyMapLoaded(); + } + } + break; + case IDM_COMBINE_SIGNATURE_FILES: + { + wxString path1 = wxFileSelector( + _("Choose priority input file"), File::GetSysDirectory(), wxEmptyString, wxEmptyString, + _("Dolphin Signature File (*.dsy)") + "|*.dsy|" + wxGetTranslation(wxALL_FILES), + wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); + if (!path1.IsEmpty()) + { + SignatureDB db; + wxString path2 = wxFileSelector( + _("Choose secondary input file"), File::GetSysDirectory(), wxEmptyString, wxEmptyString, + _("Dolphin Signature File (*.dsy)") + "|*.dsy|" + wxGetTranslation(wxALL_FILES), + wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); + if (!path2.IsEmpty()) + { + db.Load(WxStrToStr(path2)); + db.Load(WxStrToStr(path1)); - path2 = wxFileSelector( - _("Save combined output file as"), File::GetSysDirectory(), wxEmptyString, ".dsy", - _("Dolphin Signature File (*.dsy)") + "|*.dsy|" + wxGetTranslation(wxALL_FILES), - wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this); - db.Save(WxStrToStr(path2)); - db.List(); - } - } - } - break; - case IDM_PATCH_HLE_FUNCTIONS: - HLE::PatchFunctions(); - Update(); - break; - } + path2 = wxFileSelector(_("Save combined output file as"), File::GetSysDirectory(), + wxEmptyString, ".dsy", _("Dolphin Signature File (*.dsy)") + + "|*.dsy|" + wxGetTranslation(wxALL_FILES), + wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this); + db.Save(WxStrToStr(path2)); + db.List(); + } + } + } + break; + case IDM_PATCH_HLE_FUNCTIONS: + HLE::PatchFunctions(); + Update(); + break; + } } void CCodeWindow::NotifyMapLoaded() { - if (!codeview) return; + if (!codeview) + return; - g_symbolDB.FillInCallers(); - //symbols->Show(false); // hide it for faster filling - symbols->Freeze(); // HyperIris: wx style fast filling - symbols->Clear(); - for (const auto& symbol : g_symbolDB.Symbols()) - { - int idx = symbols->Append(StrToWxStr(symbol.second.name)); - symbols->SetClientData(idx, (void*)&symbol.second); - } - symbols->Thaw(); - //symbols->Show(true); - Update(); + g_symbolDB.FillInCallers(); + // symbols->Show(false); // hide it for faster filling + symbols->Freeze(); // HyperIris: wx style fast filling + symbols->Clear(); + for (const auto& symbol : g_symbolDB.Symbols()) + { + int idx = symbols->Append(StrToWxStr(symbol.second.name)); + symbols->SetClientData(idx, (void*)&symbol.second); + } + symbols->Thaw(); + // symbols->Show(true); + Update(); } void CCodeWindow::OnSymbolListChange(wxCommandEvent& event) { - int index = symbols->GetSelection(); - if (index >= 0) - { - Symbol* pSymbol = static_cast(symbols->GetClientData(index)); - if (pSymbol != nullptr) - { - if (pSymbol->type == Symbol::SYMBOL_DATA) - { - if (m_MemoryWindow)// && m_MemoryWindow->IsVisible()) - m_MemoryWindow->JumpToAddress(pSymbol->address); - } - else - { - JumpToAddress(pSymbol->address); - } - } - } + int index = symbols->GetSelection(); + if (index >= 0) + { + Symbol* pSymbol = static_cast(symbols->GetClientData(index)); + if (pSymbol != nullptr) + { + if (pSymbol->type == Symbol::SYMBOL_DATA) + { + if (m_MemoryWindow) // && m_MemoryWindow->IsVisible()) + m_MemoryWindow->JumpToAddress(pSymbol->address); + } + else + { + JumpToAddress(pSymbol->address); + } + } + } } void CCodeWindow::OnSymbolListContextMenu(wxContextMenuEvent& event) @@ -519,172 +505,163 @@ void CCodeWindow::OnSymbolListContextMenu(wxContextMenuEvent& event) // Change the global DebuggerFont void CCodeWindow::OnChangeFont(wxCommandEvent& event) { - wxFontData data; - data.SetInitialFont(DebuggerFont); + wxFontData data; + data.SetInitialFont(DebuggerFont); - wxFontDialog dialog(this, data); - if ( dialog.ShowModal() == wxID_OK ) - DebuggerFont = dialog.GetFontData().GetChosenFont(); + wxFontDialog dialog(this, data); + if (dialog.ShowModal() == wxID_OK) + DebuggerFont = dialog.GetFontData().GetChosenFont(); } // Toggle windows void CCodeWindow::OpenPages() { - ToggleCodeWindow(true); - if (bShowOnStart[0]) - Parent->ToggleLogWindow(true); - if (bShowOnStart[IDM_LOG_CONFIG_WINDOW - IDM_LOG_WINDOW]) - Parent->ToggleLogConfigWindow(true); - if (bShowOnStart[IDM_REGISTER_WINDOW - IDM_LOG_WINDOW]) - ToggleRegisterWindow(true); - if (bShowOnStart[IDM_WATCH_WINDOW - IDM_LOG_WINDOW]) - ToggleWatchWindow(true); - if (bShowOnStart[IDM_BREAKPOINT_WINDOW - IDM_LOG_WINDOW]) - ToggleBreakPointWindow(true); - if (bShowOnStart[IDM_MEMORY_WINDOW - IDM_LOG_WINDOW]) - ToggleMemoryWindow(true); - if (bShowOnStart[IDM_JIT_WINDOW - IDM_LOG_WINDOW]) - ToggleJitWindow(true); - if (bShowOnStart[IDM_SOUND_WINDOW - IDM_LOG_WINDOW]) - ToggleSoundWindow(true); - if (bShowOnStart[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW]) - ToggleVideoWindow(true); + ToggleCodeWindow(true); + if (bShowOnStart[0]) + Parent->ToggleLogWindow(true); + if (bShowOnStart[IDM_LOG_CONFIG_WINDOW - IDM_LOG_WINDOW]) + Parent->ToggleLogConfigWindow(true); + if (bShowOnStart[IDM_REGISTER_WINDOW - IDM_LOG_WINDOW]) + ToggleRegisterWindow(true); + if (bShowOnStart[IDM_WATCH_WINDOW - IDM_LOG_WINDOW]) + ToggleWatchWindow(true); + if (bShowOnStart[IDM_BREAKPOINT_WINDOW - IDM_LOG_WINDOW]) + ToggleBreakPointWindow(true); + if (bShowOnStart[IDM_MEMORY_WINDOW - IDM_LOG_WINDOW]) + ToggleMemoryWindow(true); + if (bShowOnStart[IDM_JIT_WINDOW - IDM_LOG_WINDOW]) + ToggleJitWindow(true); + if (bShowOnStart[IDM_SOUND_WINDOW - IDM_LOG_WINDOW]) + ToggleSoundWindow(true); + if (bShowOnStart[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW]) + ToggleVideoWindow(true); } void CCodeWindow::ToggleCodeWindow(bool bShow) { - if (bShow) - Parent->DoAddPage(this, - iNbAffiliation[IDM_CODE_WINDOW - IDM_LOG_WINDOW], - Parent->bFloatWindow[IDM_CODE_WINDOW - IDM_LOG_WINDOW]); - else // Hide - Parent->DoRemovePage(this); + if (bShow) + Parent->DoAddPage(this, iNbAffiliation[IDM_CODE_WINDOW - IDM_LOG_WINDOW], + Parent->bFloatWindow[IDM_CODE_WINDOW - IDM_LOG_WINDOW]); + else // Hide + Parent->DoRemovePage(this); } void CCodeWindow::ToggleRegisterWindow(bool bShow) { - GetMenuBar()->FindItem(IDM_REGISTER_WINDOW)->Check(bShow); - if (bShow) - { - if (!m_RegisterWindow) - m_RegisterWindow = new CRegisterWindow(Parent, IDM_REGISTER_WINDOW); - Parent->DoAddPage(m_RegisterWindow, - iNbAffiliation[IDM_REGISTER_WINDOW - IDM_LOG_WINDOW], - Parent->bFloatWindow[IDM_REGISTER_WINDOW - IDM_LOG_WINDOW]); - } - else // Close - { - Parent->DoRemovePage(m_RegisterWindow, false); - m_RegisterWindow = nullptr; - } + GetMenuBar()->FindItem(IDM_REGISTER_WINDOW)->Check(bShow); + if (bShow) + { + if (!m_RegisterWindow) + m_RegisterWindow = new CRegisterWindow(Parent, IDM_REGISTER_WINDOW); + Parent->DoAddPage(m_RegisterWindow, iNbAffiliation[IDM_REGISTER_WINDOW - IDM_LOG_WINDOW], + Parent->bFloatWindow[IDM_REGISTER_WINDOW - IDM_LOG_WINDOW]); + } + else // Close + { + Parent->DoRemovePage(m_RegisterWindow, false); + m_RegisterWindow = nullptr; + } } void CCodeWindow::ToggleWatchWindow(bool bShow) { - GetMenuBar()->FindItem(IDM_WATCH_WINDOW)->Check(bShow); - if (bShow) - { - if (!m_WatchWindow) - m_WatchWindow = new CWatchWindow(Parent, IDM_WATCH_WINDOW); - Parent->DoAddPage(m_WatchWindow, - iNbAffiliation[IDM_WATCH_WINDOW - IDM_LOG_WINDOW], - Parent->bFloatWindow[IDM_WATCH_WINDOW - IDM_LOG_WINDOW]); - } - else // Close - { - Parent->DoRemovePage(m_WatchWindow, false); - m_WatchWindow = nullptr; - } + GetMenuBar()->FindItem(IDM_WATCH_WINDOW)->Check(bShow); + if (bShow) + { + if (!m_WatchWindow) + m_WatchWindow = new CWatchWindow(Parent, IDM_WATCH_WINDOW); + Parent->DoAddPage(m_WatchWindow, iNbAffiliation[IDM_WATCH_WINDOW - IDM_LOG_WINDOW], + Parent->bFloatWindow[IDM_WATCH_WINDOW - IDM_LOG_WINDOW]); + } + else // Close + { + Parent->DoRemovePage(m_WatchWindow, false); + m_WatchWindow = nullptr; + } } void CCodeWindow::ToggleBreakPointWindow(bool bShow) { - GetMenuBar()->FindItem(IDM_BREAKPOINT_WINDOW)->Check(bShow); - if (bShow) - { - if (!m_BreakpointWindow) - m_BreakpointWindow = new CBreakPointWindow(this, Parent, IDM_BREAKPOINT_WINDOW); - Parent->DoAddPage(m_BreakpointWindow, - iNbAffiliation[IDM_BREAKPOINT_WINDOW - IDM_LOG_WINDOW], - Parent->bFloatWindow[IDM_BREAKPOINT_WINDOW - IDM_LOG_WINDOW]); - } - else // Close - { - Parent->DoRemovePage(m_BreakpointWindow, false); - m_BreakpointWindow = nullptr; - } + GetMenuBar()->FindItem(IDM_BREAKPOINT_WINDOW)->Check(bShow); + if (bShow) + { + if (!m_BreakpointWindow) + m_BreakpointWindow = new CBreakPointWindow(this, Parent, IDM_BREAKPOINT_WINDOW); + Parent->DoAddPage(m_BreakpointWindow, iNbAffiliation[IDM_BREAKPOINT_WINDOW - IDM_LOG_WINDOW], + Parent->bFloatWindow[IDM_BREAKPOINT_WINDOW - IDM_LOG_WINDOW]); + } + else // Close + { + Parent->DoRemovePage(m_BreakpointWindow, false); + m_BreakpointWindow = nullptr; + } } void CCodeWindow::ToggleMemoryWindow(bool bShow) { - GetMenuBar()->FindItem(IDM_MEMORY_WINDOW)->Check(bShow); - if (bShow) - { - if (!m_MemoryWindow) - m_MemoryWindow = new CMemoryWindow(Parent, IDM_MEMORY_WINDOW); - Parent->DoAddPage(m_MemoryWindow, - iNbAffiliation[IDM_MEMORY_WINDOW - IDM_LOG_WINDOW], - Parent->bFloatWindow[IDM_MEMORY_WINDOW - IDM_LOG_WINDOW]); - } - else // Close - { - Parent->DoRemovePage(m_MemoryWindow, false); - m_MemoryWindow = nullptr; - } + GetMenuBar()->FindItem(IDM_MEMORY_WINDOW)->Check(bShow); + if (bShow) + { + if (!m_MemoryWindow) + m_MemoryWindow = new CMemoryWindow(Parent, IDM_MEMORY_WINDOW); + Parent->DoAddPage(m_MemoryWindow, iNbAffiliation[IDM_MEMORY_WINDOW - IDM_LOG_WINDOW], + Parent->bFloatWindow[IDM_MEMORY_WINDOW - IDM_LOG_WINDOW]); + } + else // Close + { + Parent->DoRemovePage(m_MemoryWindow, false); + m_MemoryWindow = nullptr; + } } void CCodeWindow::ToggleJitWindow(bool bShow) { - GetMenuBar()->FindItem(IDM_JIT_WINDOW)->Check(bShow); - if (bShow) - { - if (!m_JitWindow) - m_JitWindow = new CJitWindow(Parent, IDM_JIT_WINDOW); - Parent->DoAddPage(m_JitWindow, - iNbAffiliation[IDM_JIT_WINDOW - IDM_LOG_WINDOW], - Parent->bFloatWindow[IDM_JIT_WINDOW - IDM_LOG_WINDOW]); - } - else // Close - { - Parent->DoRemovePage(m_JitWindow, false); - m_JitWindow = nullptr; - } + GetMenuBar()->FindItem(IDM_JIT_WINDOW)->Check(bShow); + if (bShow) + { + if (!m_JitWindow) + m_JitWindow = new CJitWindow(Parent, IDM_JIT_WINDOW); + Parent->DoAddPage(m_JitWindow, iNbAffiliation[IDM_JIT_WINDOW - IDM_LOG_WINDOW], + Parent->bFloatWindow[IDM_JIT_WINDOW - IDM_LOG_WINDOW]); + } + else // Close + { + Parent->DoRemovePage(m_JitWindow, false); + m_JitWindow = nullptr; + } } - void CCodeWindow::ToggleSoundWindow(bool bShow) { - GetMenuBar()->FindItem(IDM_SOUND_WINDOW)->Check(bShow); - if (bShow) - { - if (!m_SoundWindow) - m_SoundWindow = new DSPDebuggerLLE(Parent, IDM_SOUND_WINDOW); - Parent->DoAddPage(m_SoundWindow, - iNbAffiliation[IDM_SOUND_WINDOW - IDM_LOG_WINDOW], - Parent->bFloatWindow[IDM_SOUND_WINDOW - IDM_LOG_WINDOW]); - } - else // Close - { - Parent->DoRemovePage(m_SoundWindow, false); - m_SoundWindow = nullptr; - } + GetMenuBar()->FindItem(IDM_SOUND_WINDOW)->Check(bShow); + if (bShow) + { + if (!m_SoundWindow) + m_SoundWindow = new DSPDebuggerLLE(Parent, IDM_SOUND_WINDOW); + Parent->DoAddPage(m_SoundWindow, iNbAffiliation[IDM_SOUND_WINDOW - IDM_LOG_WINDOW], + Parent->bFloatWindow[IDM_SOUND_WINDOW - IDM_LOG_WINDOW]); + } + else // Close + { + Parent->DoRemovePage(m_SoundWindow, false); + m_SoundWindow = nullptr; + } } void CCodeWindow::ToggleVideoWindow(bool bShow) { - GetMenuBar()->FindItem(IDM_VIDEO_WINDOW)->Check(bShow); - if (bShow) - { - if (!m_VideoWindow) - m_VideoWindow = new GFXDebuggerPanel(Parent, IDM_VIDEO_WINDOW); - Parent->DoAddPage(m_VideoWindow, - iNbAffiliation[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW], - Parent->bFloatWindow[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW]); - } - else // Close - { - Parent->DoRemovePage(m_VideoWindow, false); - m_VideoWindow = nullptr; - } + GetMenuBar()->FindItem(IDM_VIDEO_WINDOW)->Check(bShow); + if (bShow) + { + if (!m_VideoWindow) + m_VideoWindow = new GFXDebuggerPanel(Parent, IDM_VIDEO_WINDOW); + Parent->DoAddPage(m_VideoWindow, iNbAffiliation[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW], + Parent->bFloatWindow[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW]); + } + else // Close + { + Parent->DoRemovePage(m_VideoWindow, false); + m_VideoWindow = nullptr; + } } diff --git a/Source/Core/DolphinWX/Debugger/DSPDebugWindow.cpp b/Source/Core/DolphinWX/Debugger/DSPDebugWindow.cpp index ce65c0834c..7b4909a4e8 100644 --- a/Source/Core/DolphinWX/Debugger/DSPDebugWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/DSPDebugWindow.cpp @@ -4,236 +4,232 @@ #include #include +#include +#include +#include #include #include #include #include #include -#include -#include -#include #include "Common/CommonTypes.h" #include "Common/StringUtil.h" #include "Common/SymbolDB.h" -#include "Core/Host.h" #include "Core/DSP/DSPCore.h" #include "Core/HW/DSPLLE/DSPDebugInterface.h" #include "Core/HW/DSPLLE/DSPSymbols.h" -#include "DolphinWX/WxUtils.h" +#include "Core/Host.h" #include "DolphinWX/Debugger/CodeView.h" #include "DolphinWX/Debugger/DSPDebugWindow.h" #include "DolphinWX/Debugger/DSPRegisterView.h" #include "DolphinWX/Debugger/MemoryView.h" +#include "DolphinWX/WxUtils.h" static DSPDebuggerLLE* m_DebuggerFrame = nullptr; DSPDebuggerLLE::DSPDebuggerLLE(wxWindow* parent, wxWindowID id) - : wxPanel(parent, id, wxDefaultPosition, wxDefaultSize, - wxTAB_TRAVERSAL, _("DSP LLE Debugger")) - , m_CachedStepCounter(-1) + : wxPanel(parent, id, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _("DSP LLE Debugger")), + m_CachedStepCounter(-1) { - Bind(wxEVT_CLOSE_WINDOW, &DSPDebuggerLLE::OnClose, this); - Bind(wxEVT_MENU, &DSPDebuggerLLE::OnChangeState, this, ID_RUNTOOL, ID_SHOWPCTOOL); + Bind(wxEVT_CLOSE_WINDOW, &DSPDebuggerLLE::OnClose, this); + Bind(wxEVT_MENU, &DSPDebuggerLLE::OnChangeState, this, ID_RUNTOOL, ID_SHOWPCTOOL); - m_DebuggerFrame = this; + m_DebuggerFrame = this; - // notify wxAUI which frame to use - m_mgr.SetManagedWindow(this); - m_mgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE); + // notify wxAUI which frame to use + m_mgr.SetManagedWindow(this); + m_mgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE); - m_Toolbar = new wxAuiToolBar(this, ID_TOOLBAR, - wxDefaultPosition, wxDefaultSize, wxAUI_TB_HORZ_TEXT); - m_Toolbar->AddTool(ID_RUNTOOL, _("Pause"), - wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_OTHER, wxSize(10,10))); - m_Toolbar->AddTool(ID_STEPTOOL, _("Step"), - wxArtProvider::GetBitmap(wxART_GO_DOWN, wxART_OTHER, wxSize(10,10))); - m_Toolbar->AddTool(ID_SHOWPCTOOL, _("Show PC"), - wxArtProvider::GetBitmap(wxART_GO_TO_PARENT, wxART_OTHER, wxSize(10,10))); - m_Toolbar->AddSeparator(); + m_Toolbar = + new wxAuiToolBar(this, ID_TOOLBAR, wxDefaultPosition, wxDefaultSize, wxAUI_TB_HORZ_TEXT); + m_Toolbar->AddTool(ID_RUNTOOL, _("Pause"), + wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_OTHER, wxSize(10, 10))); + m_Toolbar->AddTool(ID_STEPTOOL, _("Step"), + wxArtProvider::GetBitmap(wxART_GO_DOWN, wxART_OTHER, wxSize(10, 10))); + m_Toolbar->AddTool(ID_SHOWPCTOOL, _("Show PC"), + wxArtProvider::GetBitmap(wxART_GO_TO_PARENT, wxART_OTHER, wxSize(10, 10))); + m_Toolbar->AddSeparator(); - m_addr_txtctrl = new wxTextCtrl(m_Toolbar, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); - m_addr_txtctrl->Bind(wxEVT_TEXT_ENTER, &DSPDebuggerLLE::OnAddrBoxChange, this); + m_addr_txtctrl = new wxTextCtrl(m_Toolbar, wxID_ANY, wxEmptyString, wxDefaultPosition, + wxDefaultSize, wxTE_PROCESS_ENTER); + m_addr_txtctrl->Bind(wxEVT_TEXT_ENTER, &DSPDebuggerLLE::OnAddrBoxChange, this); - m_Toolbar->AddControl(m_addr_txtctrl); - m_Toolbar->Realize(); + m_Toolbar->AddControl(m_addr_txtctrl); + m_Toolbar->Realize(); - m_SymbolList = new wxListBox(this, wxID_ANY, wxDefaultPosition, - wxSize(140, 100), 0, nullptr, wxLB_SORT); - m_SymbolList->Bind(wxEVT_LISTBOX, &DSPDebuggerLLE::OnSymbolListChange, this); + m_SymbolList = + new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(140, 100), 0, nullptr, wxLB_SORT); + m_SymbolList->Bind(wxEVT_LISTBOX, &DSPDebuggerLLE::OnSymbolListChange, this); - m_MainNotebook = new wxAuiNotebook(this, wxID_ANY, - wxDefaultPosition, wxDefaultSize, - wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE); + m_MainNotebook = new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE); - wxPanel *code_panel = new wxPanel(m_MainNotebook, wxID_ANY); - wxBoxSizer *code_sizer = new wxBoxSizer(wxVERTICAL); - m_CodeView = new CCodeView(&debug_interface, &DSPSymbols::g_dsp_symbol_db, code_panel); - m_CodeView->SetPlain(); - code_sizer->Add(m_CodeView, 1, wxALL | wxEXPAND); - code_panel->SetSizer(code_sizer); - m_MainNotebook->AddPage(code_panel, _("Disassembly"), true); + wxPanel* code_panel = new wxPanel(m_MainNotebook, wxID_ANY); + wxBoxSizer* code_sizer = new wxBoxSizer(wxVERTICAL); + m_CodeView = new CCodeView(&debug_interface, &DSPSymbols::g_dsp_symbol_db, code_panel); + m_CodeView->SetPlain(); + code_sizer->Add(m_CodeView, 1, wxALL | wxEXPAND); + code_panel->SetSizer(code_sizer); + m_MainNotebook->AddPage(code_panel, _("Disassembly"), true); - wxPanel *mem_panel = new wxPanel(m_MainNotebook, wxID_ANY); - wxBoxSizer *mem_sizer = new wxBoxSizer(wxVERTICAL); - // TODO insert memViewer class - m_MemView = new CMemoryView(&debug_interface, mem_panel); - mem_sizer->Add(m_MemView, 1, wxALL | wxEXPAND); - mem_panel->SetSizer(mem_sizer); - m_MainNotebook->AddPage(mem_panel, _("Memory")); + wxPanel* mem_panel = new wxPanel(m_MainNotebook, wxID_ANY); + wxBoxSizer* mem_sizer = new wxBoxSizer(wxVERTICAL); + // TODO insert memViewer class + m_MemView = new CMemoryView(&debug_interface, mem_panel); + mem_sizer->Add(m_MemView, 1, wxALL | wxEXPAND); + mem_panel->SetSizer(mem_sizer); + m_MainNotebook->AddPage(mem_panel, _("Memory")); - m_Regs = new DSPRegisterView(this); + m_Regs = new DSPRegisterView(this); - // add the panes to the manager - m_mgr.AddPane(m_Toolbar, wxAuiPaneInfo(). - ToolbarPane().Top(). - LeftDockable(false).RightDockable(false)); + // add the panes to the manager + m_mgr.AddPane(m_Toolbar, + wxAuiPaneInfo().ToolbarPane().Top().LeftDockable(false).RightDockable(false)); - m_mgr.AddPane(m_SymbolList, wxAuiPaneInfo(). - Left().CloseButton(false). - Caption(_("Symbols")).Dockable(true)); + m_mgr.AddPane(m_SymbolList, + wxAuiPaneInfo().Left().CloseButton(false).Caption(_("Symbols")).Dockable(true)); - m_mgr.AddPane(m_MainNotebook, wxAuiPaneInfo(). - Name("m_MainNotebook").Center(). - CloseButton(false).MaximizeButton(true)); + m_mgr.AddPane( + m_MainNotebook, + wxAuiPaneInfo().Name("m_MainNotebook").Center().CloseButton(false).MaximizeButton(true)); - m_mgr.AddPane(m_Regs, wxAuiPaneInfo().Right(). - CloseButton(false).Caption(_("Registers")). - Dockable(true)); + m_mgr.AddPane(m_Regs, + wxAuiPaneInfo().Right().CloseButton(false).Caption(_("Registers")).Dockable(true)); - UpdateState(); + UpdateState(); - m_mgr.Update(); + m_mgr.Update(); } DSPDebuggerLLE::~DSPDebuggerLLE() { - m_mgr.UnInit(); - m_DebuggerFrame = nullptr; + m_mgr.UnInit(); + m_DebuggerFrame = nullptr; } void DSPDebuggerLLE::OnClose(wxCloseEvent& event) { - event.Skip(); + event.Skip(); } void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event) { - if (DSPCore_GetState() == DSPCORE_STOP) - return; + if (DSPCore_GetState() == DSPCORE_STOP) + return; - switch (event.GetId()) - { - case ID_RUNTOOL: - if (DSPCore_GetState() == DSPCORE_RUNNING) - DSPCore_SetState(DSPCORE_STEPPING); - else - DSPCore_SetState(DSPCORE_RUNNING); - break; + switch (event.GetId()) + { + case ID_RUNTOOL: + if (DSPCore_GetState() == DSPCORE_RUNNING) + DSPCore_SetState(DSPCORE_STEPPING); + else + DSPCore_SetState(DSPCORE_RUNNING); + break; - case ID_STEPTOOL: - if (DSPCore_GetState() == DSPCORE_STEPPING) - { - DSPCore_Step(); - Update(); - } - break; + case ID_STEPTOOL: + if (DSPCore_GetState() == DSPCORE_STEPPING) + { + DSPCore_Step(); + Update(); + } + break; - case ID_SHOWPCTOOL: - FocusOnPC(); - break; - } + case ID_SHOWPCTOOL: + FocusOnPC(); + break; + } - UpdateState(); - m_mgr.Update(); + UpdateState(); + m_mgr.Update(); } void Host_RefreshDSPDebuggerWindow() { - if (m_DebuggerFrame) - m_DebuggerFrame->Update(); + if (m_DebuggerFrame) + m_DebuggerFrame->Update(); } void DSPDebuggerLLE::Update() { #if defined __WXGTK__ - if (!wxIsMainThread()) - wxMutexGuiEnter(); + if (!wxIsMainThread()) + wxMutexGuiEnter(); #endif - UpdateSymbolMap(); - UpdateDisAsmListView(); - UpdateRegisterFlags(); - UpdateState(); + UpdateSymbolMap(); + UpdateDisAsmListView(); + UpdateRegisterFlags(); + UpdateState(); #if defined __WXGTK__ - if (!wxIsMainThread()) - wxMutexGuiLeave(); + if (!wxIsMainThread()) + wxMutexGuiLeave(); #endif } void DSPDebuggerLLE::FocusOnPC() { - JumpToAddress(g_dsp.pc); + JumpToAddress(g_dsp.pc); } void DSPDebuggerLLE::UpdateState() { - if (DSPCore_GetState() == DSPCORE_RUNNING) - { - m_Toolbar->SetToolLabel(ID_RUNTOOL, _("Pause")); - m_Toolbar->SetToolBitmap(ID_RUNTOOL, - wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_OTHER, wxSize(10,10))); - m_Toolbar->EnableTool(ID_STEPTOOL, false); - } - else - { - m_Toolbar->SetToolLabel(ID_RUNTOOL, _("Run")); - m_Toolbar->SetToolBitmap(ID_RUNTOOL, - wxArtProvider::GetBitmap(wxART_GO_FORWARD, wxART_OTHER, wxSize(10,10))); - m_Toolbar->EnableTool(ID_STEPTOOL, true); - } - m_Toolbar->Realize(); + if (DSPCore_GetState() == DSPCORE_RUNNING) + { + m_Toolbar->SetToolLabel(ID_RUNTOOL, _("Pause")); + m_Toolbar->SetToolBitmap( + ID_RUNTOOL, wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_OTHER, wxSize(10, 10))); + m_Toolbar->EnableTool(ID_STEPTOOL, false); + } + else + { + m_Toolbar->SetToolLabel(ID_RUNTOOL, _("Run")); + m_Toolbar->SetToolBitmap( + ID_RUNTOOL, wxArtProvider::GetBitmap(wxART_GO_FORWARD, wxART_OTHER, wxSize(10, 10))); + m_Toolbar->EnableTool(ID_STEPTOOL, true); + } + m_Toolbar->Realize(); } void DSPDebuggerLLE::UpdateDisAsmListView() { - if (m_CachedStepCounter == g_dsp.step_counter) - return; + if (m_CachedStepCounter == g_dsp.step_counter) + return; - // show PC - FocusOnPC(); - m_CachedStepCounter = g_dsp.step_counter; - m_Regs->Update(); + // show PC + FocusOnPC(); + m_CachedStepCounter = g_dsp.step_counter; + m_Regs->Update(); } void DSPDebuggerLLE::UpdateSymbolMap() { - if (g_dsp.dram == nullptr) - return; + if (g_dsp.dram == nullptr) + return; - m_SymbolList->Freeze(); // HyperIris: wx style fast filling - m_SymbolList->Clear(); - for (const auto& symbol : DSPSymbols::g_dsp_symbol_db.Symbols()) - { - int idx = m_SymbolList->Append(StrToWxStr(symbol.second.name)); - m_SymbolList->SetClientData(idx, (void*)&symbol.second); - } - m_SymbolList->Thaw(); + m_SymbolList->Freeze(); // HyperIris: wx style fast filling + m_SymbolList->Clear(); + for (const auto& symbol : DSPSymbols::g_dsp_symbol_db.Symbols()) + { + int idx = m_SymbolList->Append(StrToWxStr(symbol.second.name)); + m_SymbolList->SetClientData(idx, (void*)&symbol.second); + } + m_SymbolList->Thaw(); } void DSPDebuggerLLE::OnSymbolListChange(wxCommandEvent& event) { - int index = m_SymbolList->GetSelection(); - if (index >= 0) - { - Symbol* pSymbol = static_cast(m_SymbolList->GetClientData(index)); - if (pSymbol != nullptr) - { - if (pSymbol->type == Symbol::SYMBOL_FUNCTION) - { - JumpToAddress(pSymbol->address); - } - } - } + int index = m_SymbolList->GetSelection(); + if (index >= 0) + { + Symbol* pSymbol = static_cast(m_SymbolList->GetClientData(index)); + if (pSymbol != nullptr) + { + if (pSymbol->type == Symbol::SYMBOL_FUNCTION) + { + JumpToAddress(pSymbol->address); + } + } + } } void DSPDebuggerLLE::UpdateRegisterFlags() @@ -242,45 +238,44 @@ void DSPDebuggerLLE::UpdateRegisterFlags() void DSPDebuggerLLE::OnAddrBoxChange(wxCommandEvent& event) { - wxString txt = m_addr_txtctrl->GetValue(); + wxString txt = m_addr_txtctrl->GetValue(); - auto text = StripSpaces(WxStrToStr(txt)); - if (text.size()) - { - u32 addr; - sscanf(text.c_str(), "%04x", &addr); - if (JumpToAddress(addr)) - m_addr_txtctrl->SetBackgroundColour(*wxWHITE); - else - m_addr_txtctrl->SetBackgroundColour(*wxRED); - } - event.Skip(); + auto text = StripSpaces(WxStrToStr(txt)); + if (text.size()) + { + u32 addr; + sscanf(text.c_str(), "%04x", &addr); + if (JumpToAddress(addr)) + m_addr_txtctrl->SetBackgroundColour(*wxWHITE); + else + m_addr_txtctrl->SetBackgroundColour(*wxRED); + } + event.Skip(); } bool DSPDebuggerLLE::JumpToAddress(u16 addr) { - int page = m_MainNotebook->GetSelection(); - if (page == 0) - { - // Center on valid instruction in IRAM/IROM - int new_line = DSPSymbols::Addr2Line(addr); - if (new_line >= 0) - { - m_CodeView->Center(new_line); - return true; - } - } - else if (page == 1) - { - // Center on any location in any valid ROM/RAM - int seg = addr >> 12; - if (seg == 0 || seg == 1 || - seg == 8 || seg == 0xf) - { - m_MemView->Center(addr); - return true; - } - } + int page = m_MainNotebook->GetSelection(); + if (page == 0) + { + // Center on valid instruction in IRAM/IROM + int new_line = DSPSymbols::Addr2Line(addr); + if (new_line >= 0) + { + m_CodeView->Center(new_line); + return true; + } + } + else if (page == 1) + { + // Center on any location in any valid ROM/RAM + int seg = addr >> 12; + if (seg == 0 || seg == 1 || seg == 8 || seg == 0xf) + { + m_MemView->Center(addr); + return true; + } + } - return false; + return false; } diff --git a/Source/Core/DolphinWX/Debugger/DSPDebugWindow.h b/Source/Core/DolphinWX/Debugger/DSPDebugWindow.h index b3c7e6d720..7f1215bfb7 100644 --- a/Source/Core/DolphinWX/Debugger/DSPDebugWindow.h +++ b/Source/Core/DolphinWX/Debugger/DSPDebugWindow.h @@ -4,8 +4,8 @@ #pragma once -#include #include +#include #include "Common/CommonTypes.h" #include "Core/HW/DSPLLE/DSPDebugInterface.h" @@ -20,49 +20,48 @@ class wxListBox; class DSPDebuggerLLE : public wxPanel { public: - DSPDebuggerLLE(wxWindow *parent, wxWindowID id = wxID_ANY); - virtual ~DSPDebuggerLLE(); + DSPDebuggerLLE(wxWindow* parent, wxWindowID id = wxID_ANY); + virtual ~DSPDebuggerLLE(); - void Update() override; + void Update() override; private: - enum - { - ID_TOOLBAR = 1000, - ID_RUNTOOL, - ID_STEPTOOL, - ID_SHOWPCTOOL, - }; + enum + { + ID_TOOLBAR = 1000, + ID_RUNTOOL, + ID_STEPTOOL, + ID_SHOWPCTOOL, + }; - DSPDebugInterface debug_interface; - u64 m_CachedStepCounter; + DSPDebugInterface debug_interface; + u64 m_CachedStepCounter; - // GUI updaters - void UpdateDisAsmListView(); - void UpdateRegisterFlags(); - void UpdateSymbolMap(); - void UpdateState(); + // GUI updaters + void UpdateDisAsmListView(); + void UpdateRegisterFlags(); + void UpdateSymbolMap(); + void UpdateState(); - // GUI items - wxAuiManager m_mgr; - wxAuiToolBar* m_Toolbar; - CCodeView* m_CodeView; - CMemoryView* m_MemView; - DSPRegisterView* m_Regs; - wxListBox* m_SymbolList; - wxTextCtrl* m_addr_txtctrl; - wxAuiNotebook* m_MainNotebook; + // GUI items + wxAuiManager m_mgr; + wxAuiToolBar* m_Toolbar; + CCodeView* m_CodeView; + CMemoryView* m_MemView; + DSPRegisterView* m_Regs; + wxListBox* m_SymbolList; + wxTextCtrl* m_addr_txtctrl; + wxAuiNotebook* m_MainNotebook; - void OnClose(wxCloseEvent& event); - void OnChangeState(wxCommandEvent& event); - //void OnRightClick(wxListEvent& event); - //void OnDoubleClick(wxListEvent& event); - void OnAddrBoxChange(wxCommandEvent& event); - void OnSymbolListChange(wxCommandEvent& event); + void OnClose(wxCloseEvent& event); + void OnChangeState(wxCommandEvent& event); + // void OnRightClick(wxListEvent& event); + // void OnDoubleClick(wxListEvent& event); + void OnAddrBoxChange(wxCommandEvent& event); + void OnSymbolListChange(wxCommandEvent& event); - bool JumpToAddress(u16 addr); + bool JumpToAddress(u16 addr); - void FocusOnPC(); - //void UnselectAll(); + void FocusOnPC(); + // void UnselectAll(); }; - diff --git a/Source/Core/DolphinWX/Debugger/DSPRegisterView.cpp b/Source/Core/DolphinWX/Debugger/DSPRegisterView.cpp index fac8e450ca..5caa406d25 100644 --- a/Source/Core/DolphinWX/Debugger/DSPRegisterView.cpp +++ b/Source/Core/DolphinWX/Debugger/DSPRegisterView.cpp @@ -8,81 +8,83 @@ #include "Common/CommonTypes.h" #include "Core/DSP/DSPCore.h" #include "Core/DSP/DSPTables.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Debugger/DSPRegisterView.h" - +#include "DolphinWX/WxUtils.h" wxString CDSPRegTable::GetValue(int row, int col) { - if (row < 32) // 32 "normal" regs - { - switch (col) - { - case 0: return StrToWxStr(pdregname(row)); - case 1: return wxString::Format("0x%04x", DSPCore_ReadRegister(row)); - default: return wxEmptyString; - } - } - return wxEmptyString; + if (row < 32) // 32 "normal" regs + { + switch (col) + { + case 0: + return StrToWxStr(pdregname(row)); + case 1: + return wxString::Format("0x%04x", DSPCore_ReadRegister(row)); + default: + return wxEmptyString; + } + } + return wxEmptyString; } -void CDSPRegTable::SetValue(int, int, const wxString &) +void CDSPRegTable::SetValue(int, int, const wxString&) { } void CDSPRegTable::UpdateCachedRegs() { - if (m_CachedCounter == g_dsp.step_counter) - { - return; - } + if (m_CachedCounter == g_dsp.step_counter) + { + return; + } - m_CachedCounter = g_dsp.step_counter; + m_CachedCounter = g_dsp.step_counter; - for (int i = 0; i < 32; ++i) - { - m_CachedRegHasChanged[i] = (m_CachedRegs[i] != DSPCore_ReadRegister(i)); - m_CachedRegs[i] = DSPCore_ReadRegister(i); - } + for (int i = 0; i < 32; ++i) + { + m_CachedRegHasChanged[i] = (m_CachedRegs[i] != DSPCore_ReadRegister(i)); + m_CachedRegs[i] = DSPCore_ReadRegister(i); + } } -wxGridCellAttr *CDSPRegTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind) +wxGridCellAttr* CDSPRegTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind) { - wxGridCellAttr *attr = new wxGridCellAttr(); + wxGridCellAttr* attr = new wxGridCellAttr(); - attr->SetBackgroundColour(*wxWHITE); + attr->SetBackgroundColour(*wxWHITE); - switch (col) - { - case 1: - attr->SetAlignment(wxALIGN_CENTER, wxALIGN_CENTER); - break; - default: - attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER); - break; - } + switch (col) + { + case 1: + attr->SetAlignment(wxALIGN_CENTER, wxALIGN_CENTER); + break; + default: + attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER); + break; + } - if (col == 1) - attr->SetTextColour(m_CachedRegHasChanged[row] ? *wxRED : *wxBLACK); + if (col == 1) + attr->SetTextColour(m_CachedRegHasChanged[row] ? *wxRED : *wxBLACK); - return attr; + return attr; } -DSPRegisterView::DSPRegisterView(wxWindow *parent, wxWindowID id) - : wxGrid(parent, id, wxDefaultPosition, wxSize(130, 120)) +DSPRegisterView::DSPRegisterView(wxWindow* parent, wxWindowID id) + : wxGrid(parent, id, wxDefaultPosition, wxSize(130, 120)) { - m_register_table = new CDSPRegTable(); + m_register_table = new CDSPRegTable(); - SetTable(m_register_table, true); - SetRowLabelSize(0); - SetColLabelSize(0); - DisableDragRowSize(); + SetTable(m_register_table, true); + SetRowLabelSize(0); + SetColLabelSize(0); + DisableDragRowSize(); - AutoSizeColumns(); + AutoSizeColumns(); } void DSPRegisterView::Update() { - m_register_table->UpdateCachedRegs(); - ForceRefresh(); + m_register_table->UpdateCachedRegs(); + ForceRefresh(); } diff --git a/Source/Core/DolphinWX/Debugger/DSPRegisterView.h b/Source/Core/DolphinWX/Debugger/DSPRegisterView.h index 8a000b34c3..a8ad3fd60d 100644 --- a/Source/Core/DolphinWX/Debugger/DSPRegisterView.h +++ b/Source/Core/DolphinWX/Debugger/DSPRegisterView.h @@ -12,35 +12,35 @@ class CDSPRegTable : public wxGridTableBase { private: - u64 m_CachedCounter; - u16 m_CachedRegs[32]; - bool m_CachedRegHasChanged[32]; + u64 m_CachedCounter; + u16 m_CachedRegs[32]; + bool m_CachedRegHasChanged[32]; - DECLARE_NO_COPY_CLASS(CDSPRegTable); + DECLARE_NO_COPY_CLASS(CDSPRegTable); public: - CDSPRegTable() - { - memset(m_CachedRegs, 0, sizeof(m_CachedRegs)); - memset(m_CachedRegHasChanged, 0, sizeof(m_CachedRegHasChanged)); - } + CDSPRegTable() + { + memset(m_CachedRegs, 0, sizeof(m_CachedRegs)); + memset(m_CachedRegHasChanged, 0, sizeof(m_CachedRegHasChanged)); + } - int GetNumberCols() override { return 2; } - int GetNumberRows() override { return 32; } - bool IsEmptyCell(int row, int col) override { return false; } - wxString GetValue(int row, int col) override; - void SetValue(int row, int col, const wxString &) override; - wxGridCellAttr *GetAttr(int, int, wxGridCellAttr::wxAttrKind) override; - void UpdateCachedRegs(); + int GetNumberCols() override { return 2; } + int GetNumberRows() override { return 32; } + bool IsEmptyCell(int row, int col) override { return false; } + wxString GetValue(int row, int col) override; + void SetValue(int row, int col, const wxString&) override; + wxGridCellAttr* GetAttr(int, int, wxGridCellAttr::wxAttrKind) override; + void UpdateCachedRegs(); }; class DSPRegisterView : public wxGrid { public: - DSPRegisterView(wxWindow* parent, wxWindowID id = wxID_ANY); - void Update() override; + DSPRegisterView(wxWindow* parent, wxWindowID id = wxID_ANY); + void Update() override; private: - // Owned by wx. Deleted implicitly upon destruction. - CDSPRegTable* m_register_table; + // Owned by wx. Deleted implicitly upon destruction. + CDSPRegTable* m_register_table; }; diff --git a/Source/Core/DolphinWX/Debugger/DebuggerPanel.cpp b/Source/Core/DolphinWX/Debugger/DebuggerPanel.cpp index cc818de1ed..c1a6a90eca 100644 --- a/Source/Core/DolphinWX/Debugger/DebuggerPanel.cpp +++ b/Source/Core/DolphinWX/Debugger/DebuggerPanel.cpp @@ -14,346 +14,360 @@ #include "Common/FileUtil.h" #include "Common/IniFile.h" #include "Core/ConfigManager.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Debugger/DebuggerPanel.h" +#include "DolphinWX/WxUtils.h" #include "VideoCommon/Debugger.h" #include "VideoCommon/TextureCacheBase.h" -GFXDebuggerPanel::GFXDebuggerPanel(wxWindow *parent, wxWindowID id, const wxPoint &position, - const wxSize& size, long style, const wxString &title) - : wxPanel(parent, id, position, size, style, title) +GFXDebuggerPanel::GFXDebuggerPanel(wxWindow* parent, wxWindowID id, const wxPoint& position, + const wxSize& size, long style, const wxString& title) + : wxPanel(parent, id, position, size, style, title) { - g_pdebugger = this; + g_pdebugger = this; - CreateGUIControls(); + CreateGUIControls(); - Bind(wxEVT_CLOSE_WINDOW, &GFXDebuggerPanel::OnClose, this); + Bind(wxEVT_CLOSE_WINDOW, &GFXDebuggerPanel::OnClose, this); - LoadSettings(); + LoadSettings(); } GFXDebuggerPanel::~GFXDebuggerPanel() { - g_pdebugger = nullptr; - GFXDebuggerPauseFlag = false; + g_pdebugger = nullptr; + GFXDebuggerPauseFlag = false; } void GFXDebuggerPanel::OnClose(wxCloseEvent& event) { - // save the window position when we hide the window - SaveSettings(); + // save the window position when we hide the window + SaveSettings(); - event.Skip(); + event.Skip(); } void GFXDebuggerPanel::SaveSettings() const { - IniFile file; - file.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); + IniFile file; + file.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); - // TODO: make this work when we close the entire program too, currently on total close we get - // weird values, perhaps because of some conflict with the rendering window + // TODO: make this work when we close the entire program too, currently on total close we get + // weird values, perhaps because of some conflict with the rendering window - // TODO: get the screen resolution and make limits from that - if (GetPosition().x < 1000 && - GetPosition().y < 1000 && - GetSize().GetWidth() < 1000 && - GetSize().GetHeight() < 1000) - { - IniFile::Section* video_window = file.GetOrCreateSection("VideoWindow"); - video_window->Set("x", GetPosition().x); - video_window->Set("y", GetPosition().y); - video_window->Set("w", GetSize().GetWidth()); - video_window->Set("h", GetSize().GetHeight()); - } + // TODO: get the screen resolution and make limits from that + if (GetPosition().x < 1000 && GetPosition().y < 1000 && GetSize().GetWidth() < 1000 && + GetSize().GetHeight() < 1000) + { + IniFile::Section* video_window = file.GetOrCreateSection("VideoWindow"); + video_window->Set("x", GetPosition().x); + video_window->Set("y", GetPosition().y); + video_window->Set("w", GetSize().GetWidth()); + video_window->Set("h", GetSize().GetHeight()); + } - file.Save(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); + file.Save(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); } void GFXDebuggerPanel::LoadSettings() { - IniFile file; - file.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); + IniFile file; + file.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); - int x = 100; - int y = 100; - int w = 100; - int h = 100; + int x = 100; + int y = 100; + int w = 100; + int h = 100; - IniFile::Section* video_window = file.GetOrCreateSection("VideoWindow"); - video_window->Get("x", &x, GetPosition().x); - video_window->Get("y", &y, GetPosition().y); - video_window->Get("w", &w, GetSize().GetWidth()); - video_window->Get("h", &h, GetSize().GetHeight()); + IniFile::Section* video_window = file.GetOrCreateSection("VideoWindow"); + video_window->Get("x", &x, GetPosition().x); + video_window->Get("y", &y, GetPosition().y); + video_window->Get("w", &w, GetSize().GetWidth()); + video_window->Get("h", &h, GetSize().GetHeight()); - SetSize(x, y, w, h); + SetSize(x, y, w, h); } struct PauseEventMap { - PauseEvent event; - const wxString ListStr; + PauseEvent event; + const wxString ListStr; }; static PauseEventMap* pauseEventMap; void GFXDebuggerPanel::CreateGUIControls() { - static PauseEventMap map[] = { - {NEXT_FRAME, _("Frame")}, - {NEXT_FLUSH, _("Flush")}, + static PauseEventMap map[] = {{NEXT_FRAME, _("Frame")}, + {NEXT_FLUSH, _("Flush")}, - {NEXT_PIXEL_SHADER_CHANGE, _("Pixel Shader")}, - {NEXT_VERTEX_SHADER_CHANGE, _("Vertex Shader")}, - {NEXT_TEXTURE_CHANGE, _("Texture")}, - {NEXT_NEW_TEXTURE, _("New Texture")}, + {NEXT_PIXEL_SHADER_CHANGE, _("Pixel Shader")}, + {NEXT_VERTEX_SHADER_CHANGE, _("Vertex Shader")}, + {NEXT_TEXTURE_CHANGE, _("Texture")}, + {NEXT_NEW_TEXTURE, _("New Texture")}, - {NEXT_XFB_CMD, _("XFB Cmd")}, - {NEXT_EFB_CMD, _("EFB Cmd")}, + {NEXT_XFB_CMD, _("XFB Cmd")}, + {NEXT_EFB_CMD, _("EFB Cmd")}, - {NEXT_MATRIX_CMD, _("Matrix Cmd")}, - {NEXT_VERTEX_CMD, _("Vertex Cmd")}, - {NEXT_TEXTURE_CMD, _("Texture Cmd")}, - {NEXT_LIGHT_CMD, _("Light Cmd")}, - {NEXT_FOG_CMD, _("Fog Cmd")}, + {NEXT_MATRIX_CMD, _("Matrix Cmd")}, + {NEXT_VERTEX_CMD, _("Vertex Cmd")}, + {NEXT_TEXTURE_CMD, _("Texture Cmd")}, + {NEXT_LIGHT_CMD, _("Light Cmd")}, + {NEXT_FOG_CMD, _("Fog Cmd")}, - {NEXT_SET_TLUT, _("TLUT Cmd")}, + {NEXT_SET_TLUT, _("TLUT Cmd")}, - {NEXT_ERROR, _("Error")} - }; - pauseEventMap = map; - const int numPauseEventMap = sizeof(map)/sizeof(PauseEventMap); + {NEXT_ERROR, _("Error")}}; + pauseEventMap = map; + const int numPauseEventMap = sizeof(map) / sizeof(PauseEventMap); - // Basic settings - CenterOnParent(); + // Basic settings + CenterOnParent(); - m_pButtonPause = new wxButton(this, wxID_ANY, _("Pause"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Pause")); - m_pButtonPause->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnPauseButton, this); + m_pButtonPause = new wxButton(this, wxID_ANY, _("Pause"), wxDefaultPosition, wxDefaultSize, 0, + wxDefaultValidator, _("Pause")); + m_pButtonPause->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnPauseButton, this); - m_pButtonPauseAtNext = new wxButton(this, wxID_ANY, _("Pause After"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Pause At Next")); - m_pButtonPauseAtNext->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnPauseAtNextButton, this); + m_pButtonPauseAtNext = new wxButton(this, wxID_ANY, _("Pause After"), wxDefaultPosition, + wxDefaultSize, 0, wxDefaultValidator, _("Pause At Next")); + m_pButtonPauseAtNext->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnPauseAtNextButton, this); - m_pButtonPauseAtNextFrame = new wxButton(this, wxID_ANY, _("Go to Next Frame"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Next Frame")); - m_pButtonPauseAtNextFrame->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnPauseAtNextFrameButton, this); + m_pButtonPauseAtNextFrame = new wxButton(this, wxID_ANY, _("Go to Next Frame"), wxDefaultPosition, + wxDefaultSize, 0, wxDefaultValidator, _("Next Frame")); + m_pButtonPauseAtNextFrame->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnPauseAtNextFrameButton, this); - m_pButtonCont = new wxButton(this, wxID_ANY, _("Continue"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Continue")); - m_pButtonCont->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnContButton, this); + m_pButtonCont = new wxButton(this, wxID_ANY, _("Continue"), wxDefaultPosition, wxDefaultSize, 0, + wxDefaultValidator, _("Continue")); + m_pButtonCont->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnContButton, this); - m_pCount = new wxTextCtrl(this, wxID_ANY, "1", wxDefaultPosition, wxSize(50,25), wxTE_RIGHT, wxDefaultValidator, _("Count")); + m_pCount = new wxTextCtrl(this, wxID_ANY, "1", wxDefaultPosition, wxSize(50, 25), wxTE_RIGHT, + wxDefaultValidator, _("Count")); - m_pPauseAtList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxSize(100,25), 0, nullptr,0,wxDefaultValidator, _("PauseAtList")); - for (int i=0; iAppend(pauseEventMap[i].ListStr); - } - m_pPauseAtList->SetSelection(0); + m_pPauseAtList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxSize(100, 25), 0, nullptr, 0, + wxDefaultValidator, _("PauseAtList")); + for (int i = 0; i < numPauseEventMap; i++) + { + m_pPauseAtList->Append(pauseEventMap[i].ListStr); + } + m_pPauseAtList->SetSelection(0); - m_pButtonDump = new wxButton(this, wxID_ANY, _("Dump"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Dump")); - m_pButtonDump->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnDumpButton, this); + m_pButtonDump = new wxButton(this, wxID_ANY, _("Dump"), wxDefaultPosition, wxDefaultSize, 0, + wxDefaultValidator, _("Dump")); + m_pButtonDump->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnDumpButton, this); - m_pButtonUpdateScreen = new wxButton(this, wxID_ANY, _("Update Screen"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Update Screen")); - m_pButtonUpdateScreen->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnUpdateScreenButton, this); + m_pButtonUpdateScreen = new wxButton(this, wxID_ANY, _("Update Screen"), wxDefaultPosition, + wxDefaultSize, 0, wxDefaultValidator, _("Update Screen")); + m_pButtonUpdateScreen->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnUpdateScreenButton, this); - m_pButtonClearScreen = new wxButton(this, wxID_ANY, _("Clear Screen"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Clear Screen")); - m_pButtonClearScreen->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnClearScreenButton, this); + m_pButtonClearScreen = new wxButton(this, wxID_ANY, _("Clear Screen"), wxDefaultPosition, + wxDefaultSize, 0, wxDefaultValidator, _("Clear Screen")); + m_pButtonClearScreen->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnClearScreenButton, this); - m_pButtonClearTextureCache = new wxButton(this, wxID_ANY, _("Clear Textures"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Clear Textures")); - m_pButtonClearTextureCache->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnClearTextureCacheButton, this); + m_pButtonClearTextureCache = + new wxButton(this, wxID_ANY, _("Clear Textures"), wxDefaultPosition, wxDefaultSize, 0, + wxDefaultValidator, _("Clear Textures")); + m_pButtonClearTextureCache->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnClearTextureCacheButton, + this); - m_pButtonClearVertexShaderCache = new wxButton(this, wxID_ANY, _("Clear V Shaders"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Clear V Shaders")); - m_pButtonClearVertexShaderCache->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnClearVertexShaderCacheButton, this); + m_pButtonClearVertexShaderCache = + new wxButton(this, wxID_ANY, _("Clear V Shaders"), wxDefaultPosition, wxDefaultSize, 0, + wxDefaultValidator, _("Clear V Shaders")); + m_pButtonClearVertexShaderCache->Bind(wxEVT_BUTTON, + &GFXDebuggerPanel::OnClearVertexShaderCacheButton, this); - m_pButtonClearPixelShaderCache = new wxButton(this, wxID_ANY, _("Clear P Shaders"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _("Clear P Shaders")); - m_pButtonClearPixelShaderCache->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnClearPixelShaderCacheButton, this); + m_pButtonClearPixelShaderCache = + new wxButton(this, wxID_ANY, _("Clear P Shaders"), wxDefaultPosition, wxDefaultSize, 0, + wxDefaultValidator, _("Clear P Shaders")); + m_pButtonClearPixelShaderCache->Bind(wxEVT_BUTTON, + &GFXDebuggerPanel::OnClearPixelShaderCacheButton, this); - m_pDumpList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxSize(120,25), 0, nullptr, 0 ,wxDefaultValidator, _("DumpList")); - m_pDumpList->Insert(_("Pixel Shader"),0); - m_pDumpList->Append(_("Vertex Shader")); - m_pDumpList->Append(_("Pixel Shader Constants")); - m_pDumpList->Append(_("Vertex Shader Constants")); - m_pDumpList->Append(_("Textures")); - m_pDumpList->Append(_("Frame Buffer")); - m_pDumpList->Append(_("Geometry data")); - m_pDumpList->Append(_("Vertex Description")); - m_pDumpList->Append(_("Vertex Matrices")); - m_pDumpList->Append(_("Statistics")); - m_pDumpList->SetSelection(0); + m_pDumpList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxSize(120, 25), 0, nullptr, 0, + wxDefaultValidator, _("DumpList")); + m_pDumpList->Insert(_("Pixel Shader"), 0); + m_pDumpList->Append(_("Vertex Shader")); + m_pDumpList->Append(_("Pixel Shader Constants")); + m_pDumpList->Append(_("Vertex Shader Constants")); + m_pDumpList->Append(_("Textures")); + m_pDumpList->Append(_("Frame Buffer")); + m_pDumpList->Append(_("Geometry data")); + m_pDumpList->Append(_("Vertex Description")); + m_pDumpList->Append(_("Vertex Matrices")); + m_pDumpList->Append(_("Statistics")); + m_pDumpList->SetSelection(0); - wxBoxSizer *sMain = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); - wxStaticBoxSizer* const pFlowCtrlBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Flow Control")); - wxBoxSizer* const pPauseAtNextSzr = new wxBoxSizer(wxHORIZONTAL); - pFlowCtrlBox->Add(m_pButtonPause); - pPauseAtNextSzr->Add(m_pButtonPauseAtNext); - pPauseAtNextSzr->Add(m_pCount); - pPauseAtNextSzr->Add(m_pPauseAtList); - pFlowCtrlBox->Add(pPauseAtNextSzr); - pFlowCtrlBox->Add(m_pButtonPauseAtNextFrame); - pFlowCtrlBox->Add(m_pButtonCont); + wxStaticBoxSizer* const pFlowCtrlBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Flow Control")); + wxBoxSizer* const pPauseAtNextSzr = new wxBoxSizer(wxHORIZONTAL); + pFlowCtrlBox->Add(m_pButtonPause); + pPauseAtNextSzr->Add(m_pButtonPauseAtNext); + pPauseAtNextSzr->Add(m_pCount); + pPauseAtNextSzr->Add(m_pPauseAtList); + pFlowCtrlBox->Add(pPauseAtNextSzr); + pFlowCtrlBox->Add(m_pButtonPauseAtNextFrame); + pFlowCtrlBox->Add(m_pButtonCont); - wxStaticBoxSizer* const pDebugBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Debugging")); - wxBoxSizer* const pDumpSzr = new wxBoxSizer(wxHORIZONTAL); - pDumpSzr->Add(m_pButtonDump); - pDumpSzr->Add(m_pDumpList); - pDebugBox->Add(pDumpSzr); - wxGridSizer* const pDbgGrid = new wxGridSizer(2, 5, 5); - pDbgGrid->Add(m_pButtonUpdateScreen); - pDbgGrid->Add(m_pButtonClearScreen); - pDbgGrid->Add(m_pButtonClearTextureCache); - pDbgGrid->Add(m_pButtonClearVertexShaderCache); - pDbgGrid->Add(m_pButtonClearPixelShaderCache); - pDebugBox->Add(pDbgGrid); + wxStaticBoxSizer* const pDebugBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Debugging")); + wxBoxSizer* const pDumpSzr = new wxBoxSizer(wxHORIZONTAL); + pDumpSzr->Add(m_pButtonDump); + pDumpSzr->Add(m_pDumpList); + pDebugBox->Add(pDumpSzr); + wxGridSizer* const pDbgGrid = new wxGridSizer(2, 5, 5); + pDbgGrid->Add(m_pButtonUpdateScreen); + pDbgGrid->Add(m_pButtonClearScreen); + pDbgGrid->Add(m_pButtonClearTextureCache); + pDbgGrid->Add(m_pButtonClearVertexShaderCache); + pDbgGrid->Add(m_pButtonClearPixelShaderCache); + pDebugBox->Add(pDbgGrid); - sMain->Add(pFlowCtrlBox, 0, 0, 5); - sMain->Add(pDebugBox, 0, 0, 5); - SetSizerAndFit(sMain); + sMain->Add(pFlowCtrlBox, 0, 0, 5); + sMain->Add(pDebugBox, 0, 0, 5); + SetSizerAndFit(sMain); - OnContinue(); + OnContinue(); } void GFXDebuggerPanel::OnPause() { - m_pButtonDump->Enable(); - m_pDumpList->Enable(); - m_pButtonUpdateScreen->Enable(); - m_pButtonClearScreen->Enable(); - m_pButtonClearTextureCache->Enable(); - m_pButtonClearVertexShaderCache->Enable(); - m_pButtonClearPixelShaderCache->Enable(); + m_pButtonDump->Enable(); + m_pDumpList->Enable(); + m_pButtonUpdateScreen->Enable(); + m_pButtonClearScreen->Enable(); + m_pButtonClearTextureCache->Enable(); + m_pButtonClearVertexShaderCache->Enable(); + m_pButtonClearPixelShaderCache->Enable(); } void GFXDebuggerPanel::OnContinue() { - m_pButtonDump->Disable(); - m_pDumpList->Disable(); - m_pButtonUpdateScreen->Disable(); - m_pButtonClearScreen->Disable(); - m_pButtonClearTextureCache->Disable(); - m_pButtonClearVertexShaderCache->Disable(); - m_pButtonClearPixelShaderCache->Disable(); + m_pButtonDump->Disable(); + m_pDumpList->Disable(); + m_pButtonUpdateScreen->Disable(); + m_pButtonClearScreen->Disable(); + m_pButtonClearTextureCache->Disable(); + m_pButtonClearVertexShaderCache->Disable(); + m_pButtonClearPixelShaderCache->Disable(); } - // General settings void GFXDebuggerPanel::GeneralSettings(wxCommandEvent& event) { - SaveSettings(); + SaveSettings(); } void GFXDebuggerPanel::OnPauseButton(wxCommandEvent& event) { - GFXDebuggerPauseFlag = true; + GFXDebuggerPauseFlag = true; } void GFXDebuggerPanel::OnPauseAtNextButton(wxCommandEvent& event) { - GFXDebuggerPauseFlag = false; - GFXDebuggerToPauseAtNext = pauseEventMap[m_pPauseAtList->GetSelection()].event; - wxString val = m_pCount->GetValue(); - long value; - if (val.ToLong(&value)) - GFXDebuggerEventToPauseCount = value; - else - GFXDebuggerEventToPauseCount = 1; + GFXDebuggerPauseFlag = false; + GFXDebuggerToPauseAtNext = pauseEventMap[m_pPauseAtList->GetSelection()].event; + wxString val = m_pCount->GetValue(); + long value; + if (val.ToLong(&value)) + GFXDebuggerEventToPauseCount = value; + else + GFXDebuggerEventToPauseCount = 1; } void GFXDebuggerPanel::OnPauseAtNextFrameButton(wxCommandEvent& event) { - GFXDebuggerPauseFlag = false; - GFXDebuggerToPauseAtNext = NEXT_FRAME; - GFXDebuggerEventToPauseCount = 1; + GFXDebuggerPauseFlag = false; + GFXDebuggerToPauseAtNext = NEXT_FRAME; + GFXDebuggerEventToPauseCount = 1; } void GFXDebuggerPanel::OnDumpButton(wxCommandEvent& event) { - std::string dump_path = File::GetUserPath(D_DUMP_IDX) + "Debug/" + - SConfig::GetInstance().m_strUniqueID + "/"; - if (!File::CreateFullPath(dump_path)) - return; + std::string dump_path = + File::GetUserPath(D_DUMP_IDX) + "Debug/" + SConfig::GetInstance().m_strUniqueID + "/"; + if (!File::CreateFullPath(dump_path)) + return; - switch (m_pDumpList->GetSelection()) - { - case 0: // Pixel Shader - DumpPixelShader(dump_path); - break; + switch (m_pDumpList->GetSelection()) + { + case 0: // Pixel Shader + DumpPixelShader(dump_path); + break; - case 1: // Vertex Shader - DumpVertexShader(dump_path); - break; + case 1: // Vertex Shader + DumpVertexShader(dump_path); + break; - case 2: // Pixel Shader Constants - DumpPixelShaderConstants(dump_path); - WxUtils::ShowErrorDialog(_("Not implemented")); - break; + case 2: // Pixel Shader Constants + DumpPixelShaderConstants(dump_path); + WxUtils::ShowErrorDialog(_("Not implemented")); + break; - case 3: // Vertex Shader Constants - DumpVertexShaderConstants(dump_path); - WxUtils::ShowErrorDialog(_("Not implemented")); - break; + case 3: // Vertex Shader Constants + DumpVertexShaderConstants(dump_path); + WxUtils::ShowErrorDialog(_("Not implemented")); + break; - case 4: // Textures - DumpTextures(dump_path); - WxUtils::ShowErrorDialog(_("Not implemented")); - break; + case 4: // Textures + DumpTextures(dump_path); + WxUtils::ShowErrorDialog(_("Not implemented")); + break; - case 5: // Frame Buffer - DumpFrameBuffer(dump_path); - WxUtils::ShowErrorDialog(_("Not implemented")); - break; + case 5: // Frame Buffer + DumpFrameBuffer(dump_path); + WxUtils::ShowErrorDialog(_("Not implemented")); + break; - case 6: // Geometry - DumpGeometry(dump_path); - WxUtils::ShowErrorDialog(_("Not implemented")); - break; + case 6: // Geometry + DumpGeometry(dump_path); + WxUtils::ShowErrorDialog(_("Not implemented")); + break; - case 7: // Vertex Description - DumpVertexDecl(dump_path); - WxUtils::ShowErrorDialog(_("Not implemented")); - break; + case 7: // Vertex Description + DumpVertexDecl(dump_path); + WxUtils::ShowErrorDialog(_("Not implemented")); + break; - case 8: // Vertex Matrices - DumpMatrices(dump_path); - WxUtils::ShowErrorDialog(_("Not implemented")); - break; + case 8: // Vertex Matrices + DumpMatrices(dump_path); + WxUtils::ShowErrorDialog(_("Not implemented")); + break; - case 9: // Statistics - DumpStats(dump_path); - WxUtils::ShowErrorDialog(_("Not implemented")); - break; - } + case 9: // Statistics + DumpStats(dump_path); + WxUtils::ShowErrorDialog(_("Not implemented")); + break; + } } void GFXDebuggerPanel::OnContButton(wxCommandEvent& event) { - GFXDebuggerToPauseAtNext = NOT_PAUSE; - GFXDebuggerPauseFlag = false; + GFXDebuggerToPauseAtNext = NOT_PAUSE; + GFXDebuggerPauseFlag = false; } void GFXDebuggerPanel::OnClearScreenButton(wxCommandEvent& event) { - // TODO - WxUtils::ShowErrorDialog(_("Not implemented")); + // TODO + WxUtils::ShowErrorDialog(_("Not implemented")); } void GFXDebuggerPanel::OnClearTextureCacheButton(wxCommandEvent& event) { - TextureCacheBase::Invalidate(); + TextureCacheBase::Invalidate(); } void GFXDebuggerPanel::OnClearVertexShaderCacheButton(wxCommandEvent& event) { - // TODO - WxUtils::ShowErrorDialog(_("Not implemented")); + // TODO + WxUtils::ShowErrorDialog(_("Not implemented")); } void GFXDebuggerPanel::OnClearPixelShaderCacheButton(wxCommandEvent& event) { - // TODO - WxUtils::ShowErrorDialog(_("Not implemented")); + // TODO + WxUtils::ShowErrorDialog(_("Not implemented")); } void GFXDebuggerPanel::OnUpdateScreenButton(wxCommandEvent& event) { - WxUtils::ShowErrorDialog(_("Not implemented")); - GFXDebuggerUpdateScreen(); + WxUtils::ShowErrorDialog(_("Not implemented")); + GFXDebuggerUpdateScreen(); } diff --git a/Source/Core/DolphinWX/Debugger/DebuggerPanel.h b/Source/Core/DolphinWX/Debugger/DebuggerPanel.h index 8a70d93c87..cc30037366 100644 --- a/Source/Core/DolphinWX/Debugger/DebuggerPanel.h +++ b/Source/Core/DolphinWX/Debugger/DebuggerPanel.h @@ -14,62 +14,60 @@ class wxTextCtrl; class GFXDebuggerPanel : public wxPanel, public GFXDebuggerBase { public: - GFXDebuggerPanel(wxWindow* parent, - wxWindowID id = wxID_ANY, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxTAB_TRAVERSAL, - const wxString &title = _("GFX Debugger")); + GFXDebuggerPanel(wxWindow* parent, wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxTAB_TRAVERSAL, const wxString& title = _("GFX Debugger")); - virtual ~GFXDebuggerPanel(); + virtual ~GFXDebuggerPanel(); - void SaveSettings() const; - void LoadSettings(); + void SaveSettings() const; + void LoadSettings(); - bool bInfoLog; - bool bPrimLog; - bool bSaveTextures; - bool bSaveTargets; - bool bSaveShaders; + bool bInfoLog; + bool bPrimLog; + bool bSaveTextures; + bool bSaveTargets; + bool bSaveShaders; - void OnPause() override; + void OnPause() override; - // Called from GFX thread once the GFXDebuggerPauseFlag spin lock has finished - void OnContinue() override; + // Called from GFX thread once the GFXDebuggerPauseFlag spin lock has finished + void OnContinue() override; private: - wxButton* m_pButtonPause; - wxButton* m_pButtonPauseAtNext; - wxButton* m_pButtonPauseAtNextFrame; - wxButton* m_pButtonCont; - wxChoice* m_pPauseAtList; - wxButton* m_pButtonDump; - wxChoice* m_pDumpList; - wxButton* m_pButtonUpdateScreen; - wxButton* m_pButtonClearScreen; - wxButton* m_pButtonClearTextureCache; - wxButton* m_pButtonClearVertexShaderCache; - wxButton* m_pButtonClearPixelShaderCache; - wxTextCtrl* m_pCount; + wxButton* m_pButtonPause; + wxButton* m_pButtonPauseAtNext; + wxButton* m_pButtonPauseAtNextFrame; + wxButton* m_pButtonCont; + wxChoice* m_pPauseAtList; + wxButton* m_pButtonDump; + wxChoice* m_pDumpList; + wxButton* m_pButtonUpdateScreen; + wxButton* m_pButtonClearScreen; + wxButton* m_pButtonClearTextureCache; + wxButton* m_pButtonClearVertexShaderCache; + wxButton* m_pButtonClearPixelShaderCache; + wxTextCtrl* m_pCount; - void OnClose(wxCloseEvent& event); - void CreateGUIControls(); + void OnClose(wxCloseEvent& event); + void CreateGUIControls(); - void GeneralSettings(wxCommandEvent& event); + void GeneralSettings(wxCommandEvent& event); - // These set GFXDebuggerPauseFlag to true (either immediately or once the specified event has occurred) - void OnPauseButton(wxCommandEvent& event); - void OnPauseAtNextButton(wxCommandEvent& event); + // These set GFXDebuggerPauseFlag to true (either immediately or once the specified event has + // occurred) + void OnPauseButton(wxCommandEvent& event); + void OnPauseAtNextButton(wxCommandEvent& event); - void OnPauseAtNextFrameButton(wxCommandEvent& event); - void OnDumpButton(wxCommandEvent& event); + void OnPauseAtNextFrameButton(wxCommandEvent& event); + void OnDumpButton(wxCommandEvent& event); - // sets GFXDebuggerPauseFlag to false - void OnContButton(wxCommandEvent& event); + // sets GFXDebuggerPauseFlag to false + void OnContButton(wxCommandEvent& event); - void OnUpdateScreenButton(wxCommandEvent& event); - void OnClearScreenButton(wxCommandEvent& event); - void OnClearTextureCacheButton(wxCommandEvent& event); - void OnClearVertexShaderCacheButton(wxCommandEvent& event); - void OnClearPixelShaderCacheButton(wxCommandEvent& event); + void OnUpdateScreenButton(wxCommandEvent& event); + void OnClearScreenButton(wxCommandEvent& event); + void OnClearTextureCacheButton(wxCommandEvent& event); + void OnClearVertexShaderCacheButton(wxCommandEvent& event); + void OnClearPixelShaderCacheButton(wxCommandEvent& event); }; diff --git a/Source/Core/DolphinWX/Debugger/DebuggerUIUtil.cpp b/Source/Core/DolphinWX/Debugger/DebuggerUIUtil.cpp index e3a399aa92..1dc7d4547a 100644 --- a/Source/Core/DolphinWX/Debugger/DebuggerUIUtil.cpp +++ b/Source/Core/DolphinWX/Debugger/DebuggerUIUtil.cpp @@ -2,9 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include #include "DolphinWX/Debugger/DebuggerUIUtil.h" +#include // The default font wxFont DebuggerFont = wxFont(9, wxMODERN, wxNORMAL, wxNORMAL, false, "monospace"); - diff --git a/Source/Core/DolphinWX/Debugger/JitWindow.cpp b/Source/Core/DolphinWX/Debugger/JitWindow.cpp index a86afee4f9..4bc9dfedb9 100644 --- a/Source/Core/DolphinWX/Debugger/JitWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/JitWindow.cpp @@ -4,7 +4,7 @@ #include #include -#include // Bochs +#include // Bochs #include #include @@ -17,134 +17,136 @@ #include "Common/GekkoDisassembler.h" #include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/PPCAnalyst.h" +#include "DolphinWX/Debugger/JitWindow.h" #include "DolphinWX/Globals.h" #include "DolphinWX/WxUtils.h" -#include "DolphinWX/Debugger/JitWindow.h" #include "UICommon/Disassembler.h" -CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos, - const wxSize& size, long style, const wxString& name) -: wxPanel(parent, id, pos, size, style, name) +CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, + long style, const wxString& name) + : wxPanel(parent, id, pos, size, style, name) { - wxBoxSizer* sizerBig = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sizerSplit = new wxBoxSizer(wxHORIZONTAL); - sizerSplit->Add(ppc_box = new wxTextCtrl(this, wxID_ANY, "(ppc)", - wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE), 1, wxEXPAND); - sizerSplit->Add(x86_box = new wxTextCtrl(this, wxID_ANY, "(x86)", - wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE), 1, wxEXPAND); - sizerBig->Add(block_list = new JitBlockList(this, wxID_ANY, - wxDefaultPosition, wxSize(100, 140), - wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT | wxLC_SINGLE_SEL | wxLC_SORT_ASCENDING), - 0, wxEXPAND); - sizerBig->Add(sizerSplit, 2, wxEXPAND); + wxBoxSizer* sizerBig = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizerSplit = new wxBoxSizer(wxHORIZONTAL); + sizerSplit->Add(ppc_box = new wxTextCtrl(this, wxID_ANY, "(ppc)", wxDefaultPosition, + wxDefaultSize, wxTE_MULTILINE), + 1, wxEXPAND); + sizerSplit->Add(x86_box = new wxTextCtrl(this, wxID_ANY, "(x86)", wxDefaultPosition, + wxDefaultSize, wxTE_MULTILINE), + 1, wxEXPAND); + sizerBig->Add(block_list = new JitBlockList(this, wxID_ANY, wxDefaultPosition, wxSize(100, 140), + wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT | + wxLC_SINGLE_SEL | wxLC_SORT_ASCENDING), + 0, wxEXPAND); + sizerBig->Add(sizerSplit, 2, wxEXPAND); - sizerBig->Add(button_refresh = new wxButton(this, wxID_ANY, _("&Refresh"))); - button_refresh->Bind(wxEVT_BUTTON, &CJitWindow::OnRefresh, this); + sizerBig->Add(button_refresh = new wxButton(this, wxID_ANY, _("&Refresh"))); + button_refresh->Bind(wxEVT_BUTTON, &CJitWindow::OnRefresh, this); - SetSizer(sizerBig); + SetSizer(sizerBig); - sizerSplit->Fit(this); - sizerBig->Fit(this); + sizerSplit->Fit(this); + sizerBig->Fit(this); #if defined(_M_X86) - m_disassembler.reset(GetNewDisassembler("x86")); + m_disassembler.reset(GetNewDisassembler("x86")); #elif defined(_M_ARM_64) - m_disassembler.reset(GetNewDisassembler("aarch64")); + m_disassembler.reset(GetNewDisassembler("aarch64")); #else - m_disassembler.reset(GetNewDisassembler("UNK")); + m_disassembler.reset(GetNewDisassembler("UNK")); #endif } void CJitWindow::OnRefresh(wxCommandEvent& /*event*/) { - block_list->Update(); + block_list->Update(); } void CJitWindow::ViewAddr(u32 em_address) { - Show(true); - Compare(em_address); - SetFocus(); + Show(true); + Compare(em_address); + SetFocus(); } void CJitWindow::Compare(u32 em_address) { - // Get host side code disassembly - u32 host_instructions_count = 0; - u32 host_code_size = 0; - std::string host_instructions_disasm; - host_instructions_disasm = DisassembleBlock(m_disassembler.get(), &em_address, &host_instructions_count, &host_code_size); + // Get host side code disassembly + u32 host_instructions_count = 0; + u32 host_code_size = 0; + std::string host_instructions_disasm; + host_instructions_disasm = DisassembleBlock(m_disassembler.get(), &em_address, + &host_instructions_count, &host_code_size); - x86_box->SetValue(host_instructions_disasm); + x86_box->SetValue(host_instructions_disasm); - // == Fill in ppc box - u32 ppc_addr = em_address; - PPCAnalyst::CodeBuffer code_buffer(32000); - PPCAnalyst::BlockStats st; - PPCAnalyst::BlockRegStats gpa; - PPCAnalyst::BlockRegStats fpa; - PPCAnalyst::CodeBlock code_block; - PPCAnalyst::PPCAnalyzer analyzer; - analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE); + // == Fill in ppc box + u32 ppc_addr = em_address; + PPCAnalyst::CodeBuffer code_buffer(32000); + PPCAnalyst::BlockStats st; + PPCAnalyst::BlockRegStats gpa; + PPCAnalyst::BlockRegStats fpa; + PPCAnalyst::CodeBlock code_block; + PPCAnalyst::PPCAnalyzer analyzer; + analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE); - code_block.m_stats = &st; - code_block.m_gpa = &gpa; - code_block.m_fpa = &fpa; + code_block.m_stats = &st; + code_block.m_gpa = &gpa; + code_block.m_fpa = &fpa; - if (analyzer.Analyze(ppc_addr, &code_block, &code_buffer, 32000) != 0xFFFFFFFF) - { - std::ostringstream ppc_disasm; - for (u32 i = 0; i < code_block.m_num_instructions; i++) - { - const PPCAnalyst::CodeOp &op = code_buffer.codebuffer[i]; - std::string opcode = GekkoDisassembler::Disassemble(op.inst.hex, op.address); - ppc_disasm << std::setfill('0') << std::setw(8) << std::hex << op.address; - ppc_disasm << " " << opcode << std::endl; - } + if (analyzer.Analyze(ppc_addr, &code_block, &code_buffer, 32000) != 0xFFFFFFFF) + { + std::ostringstream ppc_disasm; + for (u32 i = 0; i < code_block.m_num_instructions; i++) + { + const PPCAnalyst::CodeOp& op = code_buffer.codebuffer[i]; + std::string opcode = GekkoDisassembler::Disassemble(op.inst.hex, op.address); + ppc_disasm << std::setfill('0') << std::setw(8) << std::hex << op.address; + ppc_disasm << " " << opcode << std::endl; + } - // Add stats to the end of the ppc box since it's generally the shortest. - ppc_disasm << std::dec << std::endl; + // Add stats to the end of the ppc box since it's generally the shortest. + ppc_disasm << std::dec << std::endl; - // Add some generic analysis - if (st.isFirstBlockOfFunction) - ppc_disasm << "(first block of function)" << std::endl; - if (st.isLastBlockOfFunction) - ppc_disasm << "(last block of function)" << std::endl; + // Add some generic analysis + if (st.isFirstBlockOfFunction) + ppc_disasm << "(first block of function)" << std::endl; + if (st.isLastBlockOfFunction) + ppc_disasm << "(last block of function)" << std::endl; - ppc_disasm << st.numCycles << " estimated cycles" << std::endl; + ppc_disasm << st.numCycles << " estimated cycles" << std::endl; - ppc_disasm << "Num instr: PPC: " << code_block.m_num_instructions - << " x86: " << host_instructions_count - << " (blowup: " << 100 * host_instructions_count / code_block.m_num_instructions - 100 - << "%)" << std::endl; + ppc_disasm << "Num instr: PPC: " << code_block.m_num_instructions + << " x86: " << host_instructions_count << " (blowup: " + << 100 * host_instructions_count / code_block.m_num_instructions - 100 << "%)" + << std::endl; - ppc_disasm << "Num bytes: PPC: " << code_block.m_num_instructions * 4 - << " x86: " << host_code_size - << " (blowup: " << 100 * host_code_size / (4 * code_block.m_num_instructions) - 100 - << "%)" << std::endl; + ppc_disasm << "Num bytes: PPC: " << code_block.m_num_instructions * 4 + << " x86: " << host_code_size + << " (blowup: " << 100 * host_code_size / (4 * code_block.m_num_instructions) - 100 + << "%)" << std::endl; - ppc_box->SetValue(ppc_disasm.str()); - } - else - { - ppc_box->SetValue(StringFromFormat("(non-code address: %08x)", em_address)); - x86_box->SetValue("---"); - } + ppc_box->SetValue(ppc_disasm.str()); + } + else + { + ppc_box->SetValue(StringFromFormat("(non-code address: %08x)", em_address)); + x86_box->SetValue("---"); + } } void CJitWindow::Update() { - } void CJitWindow::OnHostMessage(wxCommandEvent& event) { - switch (event.GetId()) - { - case IDM_NOTIFY_MAP_LOADED: - //NotifyMapLoaded(); - break; - } + switch (event.GetId()) + { + case IDM_NOTIFY_MAP_LOADED: + // NotifyMapLoaded(); + break; + } } // JitBlockList @@ -152,31 +154,31 @@ void CJitWindow::OnHostMessage(wxCommandEvent& event) enum { - COLUMN_ADDRESS, - COLUMN_PPCSIZE, - COLUMN_X86SIZE, - COLUMN_NAME, - COLUMN_FLAGS, - COLUMN_NUMEXEC, - COLUMN_COST, // (estimated as x86size * numexec) + COLUMN_ADDRESS, + COLUMN_PPCSIZE, + COLUMN_X86SIZE, + COLUMN_NAME, + COLUMN_FLAGS, + COLUMN_NUMEXEC, + COLUMN_COST, // (estimated as x86size * numexec) }; -JitBlockList::JitBlockList(wxWindow* parent, const wxWindowID id, - const wxPoint& pos, const wxSize& size, long style) - : wxListCtrl(parent, id, pos, size, style) // | wxLC_VIRTUAL) +JitBlockList::JitBlockList(wxWindow* parent, const wxWindowID id, const wxPoint& pos, + const wxSize& size, long style) + : wxListCtrl(parent, id, pos, size, style) // | wxLC_VIRTUAL) { - Init(); + Init(); } void JitBlockList::Init() { - InsertColumn(COLUMN_ADDRESS, _("Address")); - InsertColumn(COLUMN_PPCSIZE, _("PPC Size")); - InsertColumn(COLUMN_X86SIZE, _("x86 Size")); - InsertColumn(COLUMN_NAME, _("Symbol")); - InsertColumn(COLUMN_FLAGS, _("Flags")); - InsertColumn(COLUMN_NUMEXEC, _("NumExec")); - InsertColumn(COLUMN_COST, _("Cost")); + InsertColumn(COLUMN_ADDRESS, _("Address")); + InsertColumn(COLUMN_PPCSIZE, _("PPC Size")); + InsertColumn(COLUMN_X86SIZE, _("x86 Size")); + InsertColumn(COLUMN_NAME, _("Symbol")); + InsertColumn(COLUMN_FLAGS, _("Flags")); + InsertColumn(COLUMN_NUMEXEC, _("NumExec")); + InsertColumn(COLUMN_COST, _("Cost")); } void JitBlockList::Update() diff --git a/Source/Core/DolphinWX/Debugger/JitWindow.h b/Source/Core/DolphinWX/Debugger/JitWindow.h index b548052122..5bfd31d0a8 100644 --- a/Source/Core/DolphinWX/Debugger/JitWindow.h +++ b/Source/Core/DolphinWX/Debugger/JitWindow.h @@ -19,33 +19,31 @@ class wxTextCtrl; class JitBlockList : public wxListCtrl { public: - JitBlockList(wxWindow* parent, const wxWindowID id, const wxPoint& pos, const wxSize& size, long style); - void Init(); - void Update() override; + JitBlockList(wxWindow* parent, const wxWindowID id, const wxPoint& pos, const wxSize& size, + long style); + void Init(); + void Update() override; }; class CJitWindow : public wxPanel { public: - CJitWindow(wxWindow* parent, - wxWindowID id = wxID_ANY, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxTAB_TRAVERSAL | wxBORDER_NONE, - const wxString& name = _("JIT Block Viewer")); + CJitWindow(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL | wxBORDER_NONE, + const wxString& name = _("JIT Block Viewer")); - void ViewAddr(u32 em_address); - void Update() override; + void ViewAddr(u32 em_address); + void Update() override; private: - void OnRefresh(wxCommandEvent& /*event*/); - void Compare(u32 em_address); + void OnRefresh(wxCommandEvent& /*event*/); + void Compare(u32 em_address); - JitBlockList* block_list; - std::unique_ptr m_disassembler; - wxButton* button_refresh; - wxTextCtrl* ppc_box; - wxTextCtrl* x86_box; + JitBlockList* block_list; + std::unique_ptr m_disassembler; + wxButton* button_refresh; + wxTextCtrl* ppc_box; + wxTextCtrl* x86_box; - void OnHostMessage(wxCommandEvent& event); + void OnHostMessage(wxCommandEvent& event); }; diff --git a/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.cpp b/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.cpp index 06bce154ea..bef78872c1 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.cpp +++ b/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.cpp @@ -13,88 +13,87 @@ #include "Common/CommonTypes.h" #include "Common/StringUtil.h" #include "Core/PowerPC/PowerPC.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Debugger/BreakpointWindow.h" #include "DolphinWX/Debugger/MemoryCheckDlg.h" +#include "DolphinWX/WxUtils.h" #define TEXT_BOX(text) new wxStaticText(this, wxID_ANY, _(text)) -MemoryCheckDlg::MemoryCheckDlg(CBreakPointWindow *parent) - : wxDialog(parent, wxID_ANY, _("Memory Check")) - , m_parent(parent) +MemoryCheckDlg::MemoryCheckDlg(CBreakPointWindow* parent) + : wxDialog(parent, wxID_ANY, _("Memory Check")), m_parent(parent) { - Bind(wxEVT_BUTTON, &MemoryCheckDlg::OnOK, this, wxID_OK); + Bind(wxEVT_BUTTON, &MemoryCheckDlg::OnOK, this, wxID_OK); - m_pEditStartAddress = new wxTextCtrl(this, wxID_ANY, ""); - m_pEditEndAddress = new wxTextCtrl(this, wxID_ANY, ""); - m_pWriteFlag = new wxCheckBox(this, wxID_ANY, _("Write")); - m_pWriteFlag->SetValue(true); - m_pReadFlag = new wxCheckBox(this, wxID_ANY, _("Read")); + m_pEditStartAddress = new wxTextCtrl(this, wxID_ANY, ""); + m_pEditEndAddress = new wxTextCtrl(this, wxID_ANY, ""); + m_pWriteFlag = new wxCheckBox(this, wxID_ANY, _("Write")); + m_pWriteFlag->SetValue(true); + m_pReadFlag = new wxCheckBox(this, wxID_ANY, _("Read")); - m_log_flag = new wxCheckBox(this, wxID_ANY, _("Log")); - m_log_flag->SetValue(true); - m_break_flag = new wxCheckBox(this, wxID_ANY, _("Break")); + m_log_flag = new wxCheckBox(this, wxID_ANY, _("Log")); + m_log_flag->SetValue(true); + m_break_flag = new wxCheckBox(this, wxID_ANY, _("Break")); - wxStaticBoxSizer *sAddressRangeBox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Address Range")); - sAddressRangeBox->Add(TEXT_BOX("Start"), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5); - sAddressRangeBox->Add(m_pEditStartAddress, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10); - sAddressRangeBox->Add(TEXT_BOX("End"), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5); - sAddressRangeBox->Add(m_pEditEndAddress, 1, wxALIGN_CENTER_VERTICAL); + wxStaticBoxSizer* sAddressRangeBox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Address Range")); + sAddressRangeBox->Add(TEXT_BOX("Start"), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5); + sAddressRangeBox->Add(m_pEditStartAddress, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10); + sAddressRangeBox->Add(TEXT_BOX("End"), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5); + sAddressRangeBox->Add(m_pEditEndAddress, 1, wxALIGN_CENTER_VERTICAL); - wxStaticBoxSizer *sActionBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Action")); - sActionBox->Add(m_pWriteFlag); - sActionBox->Add(m_pReadFlag); + wxStaticBoxSizer* sActionBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Action")); + sActionBox->Add(m_pWriteFlag); + sActionBox->Add(m_pReadFlag); - wxBoxSizer* sFlags = new wxStaticBoxSizer(wxVERTICAL, this, _("Flags")); - sFlags->Add(m_log_flag); - sFlags->Add(m_break_flag); + wxBoxSizer* sFlags = new wxStaticBoxSizer(wxVERTICAL, this, _("Flags")); + sFlags->Add(m_log_flag); + sFlags->Add(m_break_flag); - wxBoxSizer *sControls = new wxBoxSizer(wxHORIZONTAL); - sControls->Add(sAddressRangeBox, 0, wxEXPAND); - sControls->Add(sActionBox, 0, wxEXPAND); - sControls->Add(sFlags, 0, wxEXPAND); + wxBoxSizer* sControls = new wxBoxSizer(wxHORIZONTAL); + sControls->Add(sAddressRangeBox, 0, wxEXPAND); + sControls->Add(sActionBox, 0, wxEXPAND); + sControls->Add(sFlags, 0, wxEXPAND); - wxBoxSizer *sMainSizer = new wxBoxSizer(wxVERTICAL); - sMainSizer->Add(sControls, 0, wxEXPAND | wxALL, 5); - sMainSizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + wxBoxSizer* sMainSizer = new wxBoxSizer(wxVERTICAL); + sMainSizer->Add(sControls, 0, wxEXPAND | wxALL, 5); + sMainSizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - SetSizerAndFit(sMainSizer); - SetFocus(); + SetSizerAndFit(sMainSizer); + SetFocus(); } void MemoryCheckDlg::OnOK(wxCommandEvent& event) { - wxString StartAddressString = m_pEditStartAddress->GetLineText(0); - wxString EndAddressString = m_pEditEndAddress->GetLineText(0); - bool OnRead = m_pReadFlag->GetValue(); - bool OnWrite = m_pWriteFlag->GetValue(); - bool Log = m_log_flag->GetValue(); - bool Break = m_break_flag->GetValue(); + wxString StartAddressString = m_pEditStartAddress->GetLineText(0); + wxString EndAddressString = m_pEditEndAddress->GetLineText(0); + bool OnRead = m_pReadFlag->GetValue(); + bool OnWrite = m_pWriteFlag->GetValue(); + bool Log = m_log_flag->GetValue(); + bool Break = m_break_flag->GetValue(); - u32 StartAddress, EndAddress; - bool EndAddressOK = EndAddressString.Len() && - AsciiToHex(WxStrToStr(EndAddressString), EndAddress); + u32 StartAddress, EndAddress; + bool EndAddressOK = + EndAddressString.Len() && AsciiToHex(WxStrToStr(EndAddressString), EndAddress); - if (AsciiToHex(WxStrToStr(StartAddressString), StartAddress) && - (OnRead || OnWrite) && (Log || Break)) - { - TMemCheck MemCheck; + if (AsciiToHex(WxStrToStr(StartAddressString), StartAddress) && (OnRead || OnWrite) && + (Log || Break)) + { + TMemCheck MemCheck; - if (!EndAddressOK) - EndAddress = StartAddress; + if (!EndAddressOK) + EndAddress = StartAddress; - MemCheck.StartAddress = StartAddress; - MemCheck.EndAddress = EndAddress; - MemCheck.bRange = StartAddress != EndAddress; - MemCheck.OnRead = OnRead; - MemCheck.OnWrite = OnWrite; - MemCheck.Log = Log; - MemCheck.Break = Break; + MemCheck.StartAddress = StartAddress; + MemCheck.EndAddress = EndAddress; + MemCheck.bRange = StartAddress != EndAddress; + MemCheck.OnRead = OnRead; + MemCheck.OnWrite = OnWrite; + MemCheck.Log = Log; + MemCheck.Break = Break; - PowerPC::memchecks.Add(MemCheck); - m_parent->NotifyUpdate(); - Close(); - } + PowerPC::memchecks.Add(MemCheck); + m_parent->NotifyUpdate(); + Close(); + } - event.Skip(); + event.Skip(); } diff --git a/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.h b/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.h index 9a9581ef6b..135ff489ba 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.h +++ b/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.h @@ -13,16 +13,16 @@ class wxTextCtrl; class MemoryCheckDlg : public wxDialog { public: - MemoryCheckDlg(CBreakPointWindow *parent); + MemoryCheckDlg(CBreakPointWindow* parent); private: - CBreakPointWindow *m_parent; - wxCheckBox* m_pReadFlag; - wxCheckBox* m_pWriteFlag; - wxCheckBox* m_log_flag; - wxCheckBox* m_break_flag; - wxTextCtrl* m_pEditEndAddress; - wxTextCtrl* m_pEditStartAddress; + CBreakPointWindow* m_parent; + wxCheckBox* m_pReadFlag; + wxCheckBox* m_pWriteFlag; + wxCheckBox* m_log_flag; + wxCheckBox* m_break_flag; + wxTextCtrl* m_pEditEndAddress; + wxTextCtrl* m_pEditStartAddress; - void OnOK(wxCommandEvent& event); + void OnOK(wxCommandEvent& event); }; diff --git a/Source/Core/DolphinWX/Debugger/MemoryView.cpp b/Source/Core/DolphinWX/Debugger/MemoryView.cpp index 0fcd5a069f..2af3dba977 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryView.cpp +++ b/Source/Core/DolphinWX/Debugger/MemoryView.cpp @@ -18,407 +18,388 @@ #include "Common/DebugInterface.h" #include "Common/StringUtil.h" #include "Core/PowerPC/PowerPC.h" -#include "DolphinWX/Frame.h" -#include "DolphinWX/Globals.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Debugger/CodeWindow.h" #include "DolphinWX/Debugger/DebuggerUIUtil.h" #include "DolphinWX/Debugger/MemoryView.h" #include "DolphinWX/Debugger/WatchWindow.h" +#include "DolphinWX/Frame.h" +#include "DolphinWX/Globals.h" +#include "DolphinWX/WxUtils.h" enum { - IDM_GOTOINMEMVIEW = 12000, - IDM_COPYADDRESS, - IDM_COPYHEX, - IDM_COPYCODE, - IDM_RUNTOHERE, - IDM_DYNARECRESULTS, - IDM_WATCHADDRESS, - IDM_TOGGLEMEMORY, - IDM_VIEWASFP, - IDM_VIEWASASCII, - IDM_VIEWASHEX, + IDM_GOTOINMEMVIEW = 12000, + IDM_COPYADDRESS, + IDM_COPYHEX, + IDM_COPYCODE, + IDM_RUNTOHERE, + IDM_DYNARECRESULTS, + IDM_WATCHADDRESS, + IDM_TOGGLEMEMORY, + IDM_VIEWASFP, + IDM_VIEWASASCII, + IDM_VIEWASHEX, }; CMemoryView::CMemoryView(DebugInterface* debuginterface, wxWindow* parent) - : wxControl(parent, wxID_ANY) - , debugger(debuginterface) - , align(debuginterface->GetInstructionSize(0)) - , rowHeight(13) - , selection(0) - , oldSelection(0) - , selecting(false) - , memory(0) - , curAddress(debuginterface->GetPC()) - , dataType(MemoryDataType::U8) - , viewAsType(VIEWAS_FP) + : wxControl(parent, wxID_ANY), debugger(debuginterface), + align(debuginterface->GetInstructionSize(0)), rowHeight(13), selection(0), oldSelection(0), + selecting(false), memory(0), curAddress(debuginterface->GetPC()), + dataType(MemoryDataType::U8), viewAsType(VIEWAS_FP) { - Bind(wxEVT_PAINT, &CMemoryView::OnPaint, this); - Bind(wxEVT_LEFT_DOWN, &CMemoryView::OnMouseDownL, this); - Bind(wxEVT_LEFT_UP, &CMemoryView::OnMouseUpL, this); - Bind(wxEVT_MOTION, &CMemoryView::OnMouseMove, this); - Bind(wxEVT_RIGHT_DOWN, &CMemoryView::OnMouseDownR, this); - Bind(wxEVT_MOUSEWHEEL, &CMemoryView::OnScrollWheel, this); - Bind(wxEVT_MENU, &CMemoryView::OnPopupMenu, this); - Bind(wxEVT_SIZE, &CMemoryView::OnResize, this); + Bind(wxEVT_PAINT, &CMemoryView::OnPaint, this); + Bind(wxEVT_LEFT_DOWN, &CMemoryView::OnMouseDownL, this); + Bind(wxEVT_LEFT_UP, &CMemoryView::OnMouseUpL, this); + Bind(wxEVT_MOTION, &CMemoryView::OnMouseMove, this); + Bind(wxEVT_RIGHT_DOWN, &CMemoryView::OnMouseDownR, this); + Bind(wxEVT_MOUSEWHEEL, &CMemoryView::OnScrollWheel, this); + Bind(wxEVT_MENU, &CMemoryView::OnPopupMenu, this); + Bind(wxEVT_SIZE, &CMemoryView::OnResize, this); } int CMemoryView::YToAddress(int y) { - wxRect rc = GetClientRect(); - int ydiff = y - rc.height / 2 - rowHeight / 2; - ydiff = (int)(floorf((float)ydiff / (float)rowHeight)) + 1; - return curAddress + ydiff * align; + wxRect rc = GetClientRect(); + int ydiff = y - rc.height / 2 - rowHeight / 2; + ydiff = (int)(floorf((float)ydiff / (float)rowHeight)) + 1; + return curAddress + ydiff * align; } void CMemoryView::OnMouseDownL(wxMouseEvent& event) { - int x = event.m_x; - int y = event.m_y; + int x = event.m_x; + int y = event.m_y; - if (x > 16) - { - oldSelection = selection; - selection = YToAddress(y); - bool oldselecting = selecting; - selecting = true; + if (x > 16) + { + oldSelection = selection; + selection = YToAddress(y); + bool oldselecting = selecting; + selecting = true; - if (!oldselecting || (selection != oldSelection)) - Refresh(); - } - else - { - debugger->ToggleMemCheck(YToAddress(y)); + if (!oldselecting || (selection != oldSelection)) + Refresh(); + } + else + { + debugger->ToggleMemCheck(YToAddress(y)); - Refresh(); + Refresh(); - // Propagate back to the parent window to update the breakpoint list. - wxCommandEvent evt(wxEVT_HOST_COMMAND, IDM_UPDATE_BREAKPOINTS); - GetEventHandler()->AddPendingEvent(evt); - } + // Propagate back to the parent window to update the breakpoint list. + wxCommandEvent evt(wxEVT_HOST_COMMAND, IDM_UPDATE_BREAKPOINTS); + GetEventHandler()->AddPendingEvent(evt); + } - event.Skip(); + event.Skip(); } void CMemoryView::OnMouseMove(wxMouseEvent& event) { - wxRect rc = GetClientRect(); + wxRect rc = GetClientRect(); - if (event.m_leftDown && event.m_x > 16) - { - if (event.m_y < 0) - { - curAddress -= align; - Refresh(); - } - else if (event.m_y > rc.height) - { - curAddress += align; - Refresh(); - } - else - OnMouseDownL(event); - } + if (event.m_leftDown && event.m_x > 16) + { + if (event.m_y < 0) + { + curAddress -= align; + Refresh(); + } + else if (event.m_y > rc.height) + { + curAddress += align; + Refresh(); + } + else + OnMouseDownL(event); + } - event.Skip(); + event.Skip(); } void CMemoryView::OnMouseUpL(wxMouseEvent& event) { - if (event.m_x > 16) - { - curAddress = YToAddress(event.m_y); - selecting = false; - Refresh(); - } + if (event.m_x > 16) + { + curAddress = YToAddress(event.m_y); + selecting = false; + Refresh(); + } - event.Skip(); + event.Skip(); } void CMemoryView::OnScrollWheel(wxMouseEvent& event) { - const bool scroll_down = (event.GetWheelRotation() < 0); - const int num_lines = event.GetLinesPerAction(); + const bool scroll_down = (event.GetWheelRotation() < 0); + const int num_lines = event.GetLinesPerAction(); - if (scroll_down) - { - curAddress += num_lines * 4; - } - else - { - curAddress -= num_lines * 4; - } + if (scroll_down) + { + curAddress += num_lines * 4; + } + else + { + curAddress -= num_lines * 4; + } - Refresh(); - event.Skip(); + Refresh(); + event.Skip(); } void CMemoryView::OnPopupMenu(wxCommandEvent& event) { - CFrame* main_frame = static_cast(GetGrandParent()->GetParent()); - CCodeWindow* code_window = main_frame->g_pCodeWindow; - CWatchWindow* watch_window = code_window->m_WatchWindow; + CFrame* main_frame = static_cast(GetGrandParent()->GetParent()); + CCodeWindow* code_window = main_frame->g_pCodeWindow; + CWatchWindow* watch_window = code_window->m_WatchWindow; #if wxUSE_CLIPBOARD - wxTheClipboard->Open(); + wxTheClipboard->Open(); #endif - switch (event.GetId()) - { + switch (event.GetId()) + { #if wxUSE_CLIPBOARD - case IDM_COPYADDRESS: - wxTheClipboard->SetData(new wxTextDataObject(wxString::Format("%08x", selection))); - break; + case IDM_COPYADDRESS: + wxTheClipboard->SetData(new wxTextDataObject(wxString::Format("%08x", selection))); + break; - case IDM_COPYHEX: - { - std::string temp = StringFromFormat("%08x", debugger->ReadExtraMemory(memory, selection)); - wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(temp))); - } - break; + case IDM_COPYHEX: + { + std::string temp = StringFromFormat("%08x", debugger->ReadExtraMemory(memory, selection)); + wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(temp))); + } + break; #endif - case IDM_WATCHADDRESS: - debugger->AddWatch(selection); - if (watch_window) - watch_window->NotifyUpdate(); - Refresh(); - break; + case IDM_WATCHADDRESS: + debugger->AddWatch(selection); + if (watch_window) + watch_window->NotifyUpdate(); + Refresh(); + break; - case IDM_TOGGLEMEMORY: - memory ^= 1; - Refresh(); - break; + case IDM_TOGGLEMEMORY: + memory ^= 1; + Refresh(); + break; - case IDM_VIEWASFP: - viewAsType = VIEWAS_FP; - Refresh(); - break; + case IDM_VIEWASFP: + viewAsType = VIEWAS_FP; + Refresh(); + break; - case IDM_VIEWASASCII: - viewAsType = VIEWAS_ASCII; - Refresh(); - break; - case IDM_VIEWASHEX: - viewAsType = VIEWAS_HEX; - Refresh(); - break; - } + case IDM_VIEWASASCII: + viewAsType = VIEWAS_ASCII; + Refresh(); + break; + case IDM_VIEWASHEX: + viewAsType = VIEWAS_HEX; + Refresh(); + break; + } #if wxUSE_CLIPBOARD - wxTheClipboard->Close(); + wxTheClipboard->Close(); #endif - event.Skip(); + event.Skip(); } void CMemoryView::OnMouseDownR(wxMouseEvent& event) { - // popup menu - wxMenu menu; - //menu.Append(IDM_GOTOINMEMVIEW, _("&Goto in mem view")); + // popup menu + wxMenu menu; +// menu.Append(IDM_GOTOINMEMVIEW, _("&Goto in mem view")); #if wxUSE_CLIPBOARD - menu.Append(IDM_COPYADDRESS, _("Copy &address")); - menu.Append(IDM_COPYHEX, _("Copy &hex")); + menu.Append(IDM_COPYADDRESS, _("Copy &address")); + menu.Append(IDM_COPYHEX, _("Copy &hex")); #endif - menu.Append(IDM_WATCHADDRESS, _("Add to &watch")); - menu.Append(IDM_TOGGLEMEMORY, _("Toggle &memory")); + menu.Append(IDM_WATCHADDRESS, _("Add to &watch")); + menu.Append(IDM_TOGGLEMEMORY, _("Toggle &memory")); - wxMenu* viewAsSubMenu = new wxMenu; - viewAsSubMenu->Append(IDM_VIEWASFP, _("FP value")); - viewAsSubMenu->Append(IDM_VIEWASASCII, "ASCII"); - viewAsSubMenu->Append(IDM_VIEWASHEX, _("Hex")); - menu.AppendSubMenu(viewAsSubMenu, _("View As:")); + wxMenu* viewAsSubMenu = new wxMenu; + viewAsSubMenu->Append(IDM_VIEWASFP, _("FP value")); + viewAsSubMenu->Append(IDM_VIEWASASCII, "ASCII"); + viewAsSubMenu->Append(IDM_VIEWASHEX, _("Hex")); + menu.AppendSubMenu(viewAsSubMenu, _("View As:")); - PopupMenu(&menu); + PopupMenu(&menu); } void CMemoryView::OnPaint(wxPaintEvent& event) { - wxPaintDC dc(this); - wxRect rc = GetClientRect(); - wxFont hFont("Courier"); - hFont.SetFamily(wxFONTFAMILY_TELETYPE); + wxPaintDC dc(this); + wxRect rc = GetClientRect(); + wxFont hFont("Courier"); + hFont.SetFamily(wxFONTFAMILY_TELETYPE); - wxCoord w,h; - dc.GetTextExtent("0WJyq", &w, &h, nullptr, nullptr, &hFont); - if (h > rowHeight) - rowHeight = h; - dc.GetTextExtent("0WJyq", &w, &h, nullptr, nullptr, &DebuggerFont); - if (h > rowHeight) - rowHeight = h; + wxCoord w, h; + dc.GetTextExtent("0WJyq", &w, &h, nullptr, nullptr, &hFont); + if (h > rowHeight) + rowHeight = h; + dc.GetTextExtent("0WJyq", &w, &h, nullptr, nullptr, &DebuggerFont); + if (h > rowHeight) + rowHeight = h; - if (viewAsType==VIEWAS_HEX) - dc.SetFont(hFont); - else - dc.SetFont(DebuggerFont); + if (viewAsType == VIEWAS_HEX) + dc.SetFont(hFont); + else + dc.SetFont(DebuggerFont); - dc.GetTextExtent("W", &w, &h); - int fontSize = w; - int textPlacement = 17 + 9 * fontSize; + dc.GetTextExtent("W", &w, &h); + int fontSize = w; + int textPlacement = 17 + 9 * fontSize; - // TODO: Add any drawing code here... - int width = rc.width; - int numRows = (rc.height / rowHeight) / 2 + 2; - dc.SetBackgroundMode(wxTRANSPARENT); - const wxColour bgColor = *wxWHITE; - wxPen nullPen(bgColor); - wxPen currentPen(*wxBLACK_PEN); - wxPen selPen(*wxGREY_PEN); - nullPen.SetStyle(wxTRANSPARENT); + // TODO: Add any drawing code here... + int width = rc.width; + int numRows = (rc.height / rowHeight) / 2 + 2; + dc.SetBackgroundMode(wxTRANSPARENT); + const wxColour bgColor = *wxWHITE; + wxPen nullPen(bgColor); + wxPen currentPen(*wxBLACK_PEN); + wxPen selPen(*wxGREY_PEN); + nullPen.SetStyle(wxTRANSPARENT); - wxBrush currentBrush(*wxLIGHT_GREY_BRUSH); - wxBrush pcBrush(*wxGREEN_BRUSH); - wxBrush mcBrush(*wxBLUE_BRUSH); - wxBrush bgBrush(bgColor); - wxBrush nullBrush(bgColor); - nullBrush.SetStyle(wxTRANSPARENT); + wxBrush currentBrush(*wxLIGHT_GREY_BRUSH); + wxBrush pcBrush(*wxGREEN_BRUSH); + wxBrush mcBrush(*wxBLUE_BRUSH); + wxBrush bgBrush(bgColor); + wxBrush nullBrush(bgColor); + nullBrush.SetStyle(wxTRANSPARENT); - dc.SetPen(nullPen); - dc.SetBrush(bgBrush); - dc.DrawRectangle(0, 0, 16, rc.height); - dc.DrawRectangle(0, 0, rc.width, 5+8); + dc.SetPen(nullPen); + dc.SetBrush(bgBrush); + dc.DrawRectangle(0, 0, 16, rc.height); + dc.DrawRectangle(0, 0, rc.width, 5 + 8); - // TODO - clean up this freaking mess!!!!! - for (int row = -numRows; row <= numRows; row++) - { - unsigned int address = curAddress + row * align; + // TODO - clean up this freaking mess!!!!! + for (int row = -numRows; row <= numRows; row++) + { + unsigned int address = curAddress + row * align; - int rowY1 = rc.height / 2 + rowHeight * row - rowHeight / 2; - int rowY2 = rc.height / 2 + rowHeight * row + rowHeight / 2; + int rowY1 = rc.height / 2 + rowHeight * row - rowHeight / 2; + int rowY2 = rc.height / 2 + rowHeight * row + rowHeight / 2; - wxString temp = wxString::Format("%08x", address); - u32 col = debugger->GetColor(address); - wxBrush rowBrush(wxColour(col >> 16, col >> 8, col)); - dc.SetBrush(nullBrush); - dc.SetPen(nullPen); - dc.DrawRectangle(0, rowY1, 16, rowY2); + wxString temp = wxString::Format("%08x", address); + u32 col = debugger->GetColor(address); + wxBrush rowBrush(wxColour(col >> 16, col >> 8, col)); + dc.SetBrush(nullBrush); + dc.SetPen(nullPen); + dc.DrawRectangle(0, rowY1, 16, rowY2); - if (selecting && (address == selection)) - dc.SetPen(selPen); - else - dc.SetPen(row == 0 ? currentPen : nullPen); + if (selecting && (address == selection)) + dc.SetPen(selPen); + else + dc.SetPen(row == 0 ? currentPen : nullPen); - if (address == debugger->GetPC()) - dc.SetBrush(pcBrush); - else - dc.SetBrush(rowBrush); + if (address == debugger->GetPC()) + dc.SetBrush(pcBrush); + else + dc.SetBrush(rowBrush); - dc.DrawRectangle(16, rowY1, width, rowY2 - 1); - dc.SetBrush(currentBrush); - dc.SetTextForeground("#600000"); // Dark red - dc.DrawText(temp, 17, rowY1); + dc.DrawRectangle(16, rowY1, width, rowY2 - 1); + dc.SetBrush(currentBrush); + dc.SetTextForeground("#600000"); // Dark red + dc.DrawText(temp, 17, rowY1); - if (viewAsType != VIEWAS_HEX) - { - char mem[256]; - debugger->GetRawMemoryString(memory, address, mem, 256); - dc.SetTextForeground(wxTheColourDatabase->Find("NAVY")); - dc.DrawText(StrToWxStr(mem), 17+fontSize*(8), rowY1); - dc.SetTextForeground(*wxBLACK); - } + if (viewAsType != VIEWAS_HEX) + { + char mem[256]; + debugger->GetRawMemoryString(memory, address, mem, 256); + dc.SetTextForeground(wxTheColourDatabase->Find("NAVY")); + dc.DrawText(StrToWxStr(mem), 17 + fontSize * (8), rowY1); + dc.SetTextForeground(*wxBLACK); + } - if (!PowerPC::HostIsRAMAddress(address)) - continue; + if (!PowerPC::HostIsRAMAddress(address)) + continue; - if (debugger->IsAlive()) - { - std::string dis; - u32 mem_data = debugger->ReadExtraMemory(memory, address); + if (debugger->IsAlive()) + { + std::string dis; + u32 mem_data = debugger->ReadExtraMemory(memory, address); - if (viewAsType == VIEWAS_FP) - { - float flt = *(float *)(&mem_data); - dis = StringFromFormat("f: %f", flt); - } - else if (viewAsType == VIEWAS_ASCII) - { - u32 a[4] = { - (mem_data & 0xff000000) >> 24, - (mem_data & 0xff0000) >> 16, - (mem_data & 0xff00) >> 8, - (mem_data & 0xff) - }; + if (viewAsType == VIEWAS_FP) + { + float flt = *(float*)(&mem_data); + dis = StringFromFormat("f: %f", flt); + } + else if (viewAsType == VIEWAS_ASCII) + { + u32 a[4] = {(mem_data & 0xff000000) >> 24, (mem_data & 0xff0000) >> 16, + (mem_data & 0xff00) >> 8, (mem_data & 0xff)}; - for (auto& word : a) - { - if (word == '\0') - word = ' '; - } + for (auto& word : a) + { + if (word == '\0') + word = ' '; + } - dis = StringFromFormat("%c%c%c%c", a[0], a[1], a[2], a[3]); - } - else if (viewAsType == VIEWAS_HEX) - { - u32 mema[8] = { - debugger->ReadExtraMemory(memory, address), - debugger->ReadExtraMemory(memory, address+4), - debugger->ReadExtraMemory(memory, address+8), - debugger->ReadExtraMemory(memory, address+12), - debugger->ReadExtraMemory(memory, address+16), - debugger->ReadExtraMemory(memory, address+20), - debugger->ReadExtraMemory(memory, address+24), - debugger->ReadExtraMemory(memory, address+28) - }; + dis = StringFromFormat("%c%c%c%c", a[0], a[1], a[2], a[3]); + } + else if (viewAsType == VIEWAS_HEX) + { + u32 mema[8] = {debugger->ReadExtraMemory(memory, address), + debugger->ReadExtraMemory(memory, address + 4), + debugger->ReadExtraMemory(memory, address + 8), + debugger->ReadExtraMemory(memory, address + 12), + debugger->ReadExtraMemory(memory, address + 16), + debugger->ReadExtraMemory(memory, address + 20), + debugger->ReadExtraMemory(memory, address + 24), + debugger->ReadExtraMemory(memory, address + 28)}; - for (auto& word : mema) - { - switch (dataType) - { - case MemoryDataType::U8: - dis += StringFromFormat(" %02X %02X %02X %02X", - ((word & 0xff000000) >> 24) & 0xFF, - ((word & 0xff0000) >> 16) & 0xFF, - ((word & 0xff00) >> 8) & 0xFF, - word & 0xff); - break; - case MemoryDataType::U16: - dis += StringFromFormat(" %02X%02X %02X%02X", - ((word & 0xff000000) >> 24) & 0xFF, - ((word & 0xff0000) >> 16) & 0xFF, - ((word & 0xff00) >> 8) & 0xFF, - word & 0xff); - break; - case MemoryDataType::U32: - dis += StringFromFormat(" %02X%02X%02X%02X", - ((word & 0xff000000) >> 24) & 0xFF, - ((word & 0xff0000) >> 16) & 0xFF, - ((word & 0xff00) >> 8) & 0xFF, - word & 0xff); - break; - } - } - } - else - { - dis = "INVALID VIEWAS TYPE"; - } + for (auto& word : mema) + { + switch (dataType) + { + case MemoryDataType::U8: + dis += StringFromFormat(" %02X %02X %02X %02X", ((word & 0xff000000) >> 24) & 0xFF, + ((word & 0xff0000) >> 16) & 0xFF, ((word & 0xff00) >> 8) & 0xFF, + word & 0xff); + break; + case MemoryDataType::U16: + dis += StringFromFormat(" %02X%02X %02X%02X", ((word & 0xff000000) >> 24) & 0xFF, + ((word & 0xff0000) >> 16) & 0xFF, ((word & 0xff00) >> 8) & 0xFF, + word & 0xff); + break; + case MemoryDataType::U32: + dis += StringFromFormat(" %02X%02X%02X%02X", ((word & 0xff000000) >> 24) & 0xFF, + ((word & 0xff0000) >> 16) & 0xFF, ((word & 0xff00) >> 8) & 0xFF, + word & 0xff); + break; + } + } + } + else + { + dis = "INVALID VIEWAS TYPE"; + } - if (viewAsType != VIEWAS_HEX) - dc.DrawText(StrToWxStr(dis), textPlacement + fontSize*(8 + 8), rowY1); - else - dc.DrawText(StrToWxStr(dis), textPlacement, rowY1); + if (viewAsType != VIEWAS_HEX) + dc.DrawText(StrToWxStr(dis), textPlacement + fontSize * (8 + 8), rowY1); + else + dc.DrawText(StrToWxStr(dis), textPlacement, rowY1); - dc.SetTextForeground(*wxBLUE); + dc.SetTextForeground(*wxBLUE); - std::string desc = debugger->GetDescription(address); - if (!desc.empty()) - dc.DrawText(StrToWxStr(desc), 17+fontSize*((8+8+8+30)*2), rowY1); + std::string desc = debugger->GetDescription(address); + if (!desc.empty()) + dc.DrawText(StrToWxStr(desc), 17 + fontSize * ((8 + 8 + 8 + 30) * 2), rowY1); - // Show blue memory check dot - if (debugger->IsMemCheck(address)) - { - dc.SetBrush(mcBrush); - dc.DrawRectangle(8, rowY1 + 1, 11, 11); - } - } - } + // Show blue memory check dot + if (debugger->IsMemCheck(address)) + { + dc.SetBrush(mcBrush); + dc.DrawRectangle(8, rowY1 + 1, 11, 11); + } + } + } - dc.SetPen(currentPen); + dc.SetPen(currentPen); } void CMemoryView::OnResize(wxSizeEvent& event) { - Refresh(); - event.Skip(); + Refresh(); + event.Skip(); } diff --git a/Source/Core/DolphinWX/Debugger/MemoryView.h b/Source/Core/DolphinWX/Debugger/MemoryView.h index 42adc677c0..c540e96c70 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryView.h +++ b/Source/Core/DolphinWX/Debugger/MemoryView.h @@ -11,60 +11,61 @@ class DebugInterface; enum class MemoryDataType { - U8, U16, U32 + U8, + U16, + U32 }; class CMemoryView : public wxControl { public: - CMemoryView(DebugInterface* debuginterface, wxWindow* parent); + CMemoryView(DebugInterface* debuginterface, wxWindow* parent); - u32 GetSelection() const { return selection ; } - int GetMemoryType() const { return memory; } + u32 GetSelection() const { return selection; } + int GetMemoryType() const { return memory; } + void Center(u32 addr) + { + curAddress = addr; + Refresh(); + } - void Center(u32 addr) - { - curAddress = addr; - Refresh(); - } - - void SetDataType(MemoryDataType data_type) - { - dataType = data_type; - Refresh(); - } + void SetDataType(MemoryDataType data_type) + { + dataType = data_type; + Refresh(); + } private: - void OnPaint(wxPaintEvent& event); - void OnMouseDownL(wxMouseEvent& event); - void OnMouseMove(wxMouseEvent& event); - void OnMouseUpL(wxMouseEvent& event); - void OnMouseDownR(wxMouseEvent& event); - void OnScrollWheel(wxMouseEvent& event); - void OnPopupMenu(wxCommandEvent& event); + void OnPaint(wxPaintEvent& event); + void OnMouseDownL(wxMouseEvent& event); + void OnMouseMove(wxMouseEvent& event); + void OnMouseUpL(wxMouseEvent& event); + void OnMouseDownR(wxMouseEvent& event); + void OnScrollWheel(wxMouseEvent& event); + void OnPopupMenu(wxCommandEvent& event); - int YToAddress(int y); - void OnResize(wxSizeEvent& event); + int YToAddress(int y); + void OnResize(wxSizeEvent& event); - DebugInterface* debugger; + DebugInterface* debugger; - int align; - int rowHeight; + int align; + int rowHeight; - u32 selection; - u32 oldSelection; - bool selecting; + u32 selection; + u32 oldSelection; + bool selecting; - int memory; - int curAddress; - MemoryDataType dataType; + int memory; + int curAddress; + MemoryDataType dataType; - enum EViewAsType - { - VIEWAS_ASCII = 0, - VIEWAS_FP, - VIEWAS_HEX, - }; + enum EViewAsType + { + VIEWAS_ASCII = 0, + VIEWAS_FP, + VIEWAS_HEX, + }; - EViewAsType viewAsType; + EViewAsType viewAsType; }; diff --git a/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp b/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp index a23eda647f..24188a65ea 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp @@ -26,418 +26,420 @@ #include "Core/HW/DSP.h" #include "Core/HW/Memmap.h" #include "Core/PowerPC/PowerPC.h" -#include "DolphinWX/Globals.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Debugger/MemoryView.h" #include "DolphinWX/Debugger/MemoryWindow.h" +#include "DolphinWX/Globals.h" +#include "DolphinWX/WxUtils.h" enum { - IDM_MEM_ADDRBOX, - IDM_SYMBOLLIST, - IDM_SETVALBUTTON, - IDM_DUMP_MEMORY, - IDM_DUMP_MEM2, - IDM_DUMP_FAKEVMEM, - IDM_VALBOX, - IDM_U8, - IDM_U16, - IDM_U32, - IDM_SEARCH, - IDM_ASCII, - IDM_HEX + IDM_MEM_ADDRBOX, + IDM_SYMBOLLIST, + IDM_SETVALBUTTON, + IDM_DUMP_MEMORY, + IDM_DUMP_MEM2, + IDM_DUMP_FAKEVMEM, + IDM_VALBOX, + IDM_U8, + IDM_U16, + IDM_U32, + IDM_SEARCH, + IDM_ASCII, + IDM_HEX }; BEGIN_EVENT_TABLE(CMemoryWindow, wxPanel) - EVT_LISTBOX(IDM_SYMBOLLIST, CMemoryWindow::OnSymbolListChange) - EVT_HOST_COMMAND(wxID_ANY, CMemoryWindow::OnHostMessage) - EVT_BUTTON(IDM_SETVALBUTTON, CMemoryWindow::SetMemoryValue) - EVT_BUTTON(IDM_DUMP_MEMORY, CMemoryWindow::OnDumpMemory) - EVT_BUTTON(IDM_DUMP_MEM2, CMemoryWindow::OnDumpMem2) - EVT_BUTTON(IDM_DUMP_FAKEVMEM, CMemoryWindow::OnDumpFakeVMEM) - EVT_CHECKBOX(IDM_U8, CMemoryWindow::U8) - EVT_CHECKBOX(IDM_U16, CMemoryWindow::U16) - EVT_CHECKBOX(IDM_U32, CMemoryWindow::U32) - EVT_BUTTON(IDM_SEARCH, CMemoryWindow::onSearch) - EVT_CHECKBOX(IDM_ASCII, CMemoryWindow::onAscii) - EVT_CHECKBOX(IDM_HEX, CMemoryWindow::onHex) +EVT_LISTBOX(IDM_SYMBOLLIST, CMemoryWindow::OnSymbolListChange) +EVT_HOST_COMMAND(wxID_ANY, CMemoryWindow::OnHostMessage) +EVT_BUTTON(IDM_SETVALBUTTON, CMemoryWindow::SetMemoryValue) +EVT_BUTTON(IDM_DUMP_MEMORY, CMemoryWindow::OnDumpMemory) +EVT_BUTTON(IDM_DUMP_MEM2, CMemoryWindow::OnDumpMem2) +EVT_BUTTON(IDM_DUMP_FAKEVMEM, CMemoryWindow::OnDumpFakeVMEM) +EVT_CHECKBOX(IDM_U8, CMemoryWindow::U8) +EVT_CHECKBOX(IDM_U16, CMemoryWindow::U16) +EVT_CHECKBOX(IDM_U32, CMemoryWindow::U32) +EVT_BUTTON(IDM_SEARCH, CMemoryWindow::onSearch) +EVT_CHECKBOX(IDM_ASCII, CMemoryWindow::onAscii) +EVT_CHECKBOX(IDM_HEX, CMemoryWindow::onHex) END_EVENT_TABLE() -CMemoryWindow::CMemoryWindow(wxWindow* parent, wxWindowID id, - const wxPoint& pos, const wxSize& size, long style, const wxString& name) - : wxPanel(parent, id, pos, size, style, name) +CMemoryWindow::CMemoryWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos, + const wxSize& size, long style, const wxString& name) + : wxPanel(parent, id, pos, size, style, name) { - DebugInterface* di = &PowerPC::debug_interface; + DebugInterface* di = &PowerPC::debug_interface; - memview = new CMemoryView(di, this); + memview = new CMemoryView(di, this); - addrbox = new wxSearchCtrl(this, IDM_MEM_ADDRBOX); - addrbox->Bind(wxEVT_TEXT, &CMemoryWindow::OnAddrBoxChange, this); - addrbox->SetDescriptiveText(_("Search Address")); + addrbox = new wxSearchCtrl(this, IDM_MEM_ADDRBOX); + addrbox->Bind(wxEVT_TEXT, &CMemoryWindow::OnAddrBoxChange, this); + addrbox->SetDescriptiveText(_("Search Address")); - valbox = new wxTextCtrl(this, IDM_VALBOX, "", wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); - valbox->Bind(wxEVT_TEXT_ENTER, &CMemoryWindow::SetMemoryValueFromValBox, this); + valbox = + new wxTextCtrl(this, IDM_VALBOX, "", wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); + valbox->Bind(wxEVT_TEXT_ENTER, &CMemoryWindow::SetMemoryValueFromValBox, this); - wxGridSizer* const search_sizer = new wxGridSizer(1); - search_sizer->Add(addrbox); - search_sizer->Add(valbox, 0, wxEXPAND); - search_sizer->Add(new wxButton(this, IDM_SETVALBUTTON, _("Set Value"))); + wxGridSizer* const search_sizer = new wxGridSizer(1); + search_sizer->Add(addrbox); + search_sizer->Add(valbox, 0, wxEXPAND); + search_sizer->Add(new wxButton(this, IDM_SETVALBUTTON, _("Set Value"))); - wxGridSizer* const dump_sizer = new wxGridSizer(1); - dump_sizer->Add(new wxButton(this, IDM_DUMP_MEMORY, _("Dump MRAM")), 0, wxEXPAND); - dump_sizer->Add(new wxButton(this, IDM_DUMP_MEM2, _("Dump EXRAM")), 0, wxEXPAND); - if (!SConfig::GetInstance().bMMU) - dump_sizer->Add(new wxButton(this, IDM_DUMP_FAKEVMEM, _("Dump FakeVMEM")), 0, wxEXPAND); + wxGridSizer* const dump_sizer = new wxGridSizer(1); + dump_sizer->Add(new wxButton(this, IDM_DUMP_MEMORY, _("Dump MRAM")), 0, wxEXPAND); + dump_sizer->Add(new wxButton(this, IDM_DUMP_MEM2, _("Dump EXRAM")), 0, wxEXPAND); + if (!SConfig::GetInstance().bMMU) + dump_sizer->Add(new wxButton(this, IDM_DUMP_FAKEVMEM, _("Dump FakeVMEM")), 0, wxEXPAND); - wxStaticBoxSizer* const sizerSearchType = new wxStaticBoxSizer(wxVERTICAL, this, _("Search")); - sizerSearchType->Add(btnSearch = new wxButton(this, IDM_SEARCH, _("Search"))); - sizerSearchType->Add(chkAscii = new wxCheckBox(this, IDM_ASCII, "Ascii ")); - sizerSearchType->Add(chkHex = new wxCheckBox(this, IDM_HEX, _("Hex"))); + wxStaticBoxSizer* const sizerSearchType = new wxStaticBoxSizer(wxVERTICAL, this, _("Search")); + sizerSearchType->Add(btnSearch = new wxButton(this, IDM_SEARCH, _("Search"))); + sizerSearchType->Add(chkAscii = new wxCheckBox(this, IDM_ASCII, "Ascii ")); + sizerSearchType->Add(chkHex = new wxCheckBox(this, IDM_HEX, _("Hex"))); - wxStaticBoxSizer* const sizerDataTypes = new wxStaticBoxSizer(wxVERTICAL, this, _("Data Type")); - sizerDataTypes->SetMinSize(74, 40); - sizerDataTypes->Add(chk8 = new wxCheckBox(this, IDM_U8, "U8")); - sizerDataTypes->Add(chk16 = new wxCheckBox(this, IDM_U16, "U16")); - sizerDataTypes->Add(chk32 = new wxCheckBox(this, IDM_U32, "U32")); + wxStaticBoxSizer* const sizerDataTypes = new wxStaticBoxSizer(wxVERTICAL, this, _("Data Type")); + sizerDataTypes->SetMinSize(74, 40); + sizerDataTypes->Add(chk8 = new wxCheckBox(this, IDM_U8, "U8")); + sizerDataTypes->Add(chk16 = new wxCheckBox(this, IDM_U16, "U16")); + sizerDataTypes->Add(chk32 = new wxCheckBox(this, IDM_U32, "U32")); - wxBoxSizer* const sizerRight = new wxBoxSizer(wxVERTICAL); - sizerRight->Add(search_sizer); - sizerRight->AddSpacer(5); - sizerRight->Add(dump_sizer); - sizerRight->Add(sizerSearchType); - sizerRight->Add(sizerDataTypes); + wxBoxSizer* const sizerRight = new wxBoxSizer(wxVERTICAL); + sizerRight->Add(search_sizer); + sizerRight->AddSpacer(5); + sizerRight->Add(dump_sizer); + sizerRight->Add(sizerSearchType); + sizerRight->Add(sizerDataTypes); - wxBoxSizer* const sizerBig = new wxBoxSizer(wxHORIZONTAL); - sizerBig->Add(memview, 20, wxEXPAND); - sizerBig->Add(sizerRight, 0, wxEXPAND | wxALL, 3); + wxBoxSizer* const sizerBig = new wxBoxSizer(wxHORIZONTAL); + sizerBig->Add(memview, 20, wxEXPAND); + sizerBig->Add(sizerRight, 0, wxEXPAND | wxALL, 3); - SetSizer(sizerBig); - chkHex->SetValue(1); //Set defaults - chk8->SetValue(1); + SetSizer(sizerBig); + chkHex->SetValue(1); // Set defaults + chk8->SetValue(1); - sizerRight->Fit(this); - sizerBig->Fit(this); + sizerRight->Fit(this); + sizerBig->Fit(this); } void CMemoryWindow::Save(IniFile& ini) const { - // Prevent these bad values that can happen after a crash or hanging - if (GetPosition().x != -32000 && GetPosition().y != -32000) - { - IniFile::Section* mem_window = ini.GetOrCreateSection("MemoryWindow"); - mem_window->Set("x", GetPosition().x); - mem_window->Set("y", GetPosition().y); - mem_window->Set("w", GetSize().GetWidth()); - mem_window->Set("h", GetSize().GetHeight()); - } + // Prevent these bad values that can happen after a crash or hanging + if (GetPosition().x != -32000 && GetPosition().y != -32000) + { + IniFile::Section* mem_window = ini.GetOrCreateSection("MemoryWindow"); + mem_window->Set("x", GetPosition().x); + mem_window->Set("y", GetPosition().y); + mem_window->Set("w", GetSize().GetWidth()); + mem_window->Set("h", GetSize().GetHeight()); + } } void CMemoryWindow::Load(IniFile& ini) { - int x, y, w, h; + int x, y, w, h; - IniFile::Section* mem_window = ini.GetOrCreateSection("MemoryWindow"); - mem_window->Get("x", &x, GetPosition().x); - mem_window->Get("y", &y, GetPosition().y); - mem_window->Get("w", &w, GetSize().GetWidth()); - mem_window->Get("h", &h, GetSize().GetHeight()); + IniFile::Section* mem_window = ini.GetOrCreateSection("MemoryWindow"); + mem_window->Get("x", &x, GetPosition().x); + mem_window->Get("y", &y, GetPosition().y); + mem_window->Get("w", &w, GetSize().GetWidth()); + mem_window->Get("h", &h, GetSize().GetHeight()); - SetSize(x, y, w, h); + SetSize(x, y, w, h); } void CMemoryWindow::JumpToAddress(u32 _Address) { - memview->Center(_Address); + memview->Center(_Address); } void CMemoryWindow::SetMemoryValueFromValBox(wxCommandEvent& event) { - SetMemoryValue(event); - valbox->SetFocus(); - + SetMemoryValue(event); + valbox->SetFocus(); } void CMemoryWindow::SetMemoryValue(wxCommandEvent& event) { - if (!Memory::IsInitialized()) - { - WxUtils::ShowErrorDialog(_("Cannot set uninitialized memory.")); - return; - } + if (!Memory::IsInitialized()) + { + WxUtils::ShowErrorDialog(_("Cannot set uninitialized memory.")); + return; + } - std::string str_addr = WxStrToStr(addrbox->GetValue()); - std::string str_val = WxStrToStr(valbox->GetValue()); - u32 addr; - u32 val; + std::string str_addr = WxStrToStr(addrbox->GetValue()); + std::string str_val = WxStrToStr(valbox->GetValue()); + u32 addr; + u32 val; - if (!TryParse(std::string("0x") + str_addr, &addr)) - { - WxUtils::ShowErrorDialog(wxString::Format(_("Invalid address: %s"), str_addr.c_str())); - return; - } + if (!TryParse(std::string("0x") + str_addr, &addr)) + { + WxUtils::ShowErrorDialog(wxString::Format(_("Invalid address: %s"), str_addr.c_str())); + return; + } - if (!TryParse(std::string("0x") + str_val, &val)) - { - WxUtils::ShowErrorDialog(wxString::Format(_("Invalid value: %s"), str_val.c_str())); - return; - } + if (!TryParse(std::string("0x") + str_val, &val)) + { + WxUtils::ShowErrorDialog(wxString::Format(_("Invalid value: %s"), str_val.c_str())); + return; + } - PowerPC::HostWrite_U32(val, addr); - memview->Refresh(); + PowerPC::HostWrite_U32(val, addr); + memview->Refresh(); } void CMemoryWindow::OnAddrBoxChange(wxCommandEvent& event) { - wxString txt = addrbox->GetValue(); - if (txt.size()) - { - u32 addr; - sscanf(WxStrToStr(txt).c_str(), "%08x", &addr); - memview->Center(addr & ~3); - } + wxString txt = addrbox->GetValue(); + if (txt.size()) + { + u32 addr; + sscanf(WxStrToStr(txt).c_str(), "%08x", &addr); + memview->Center(addr & ~3); + } - event.Skip(); + event.Skip(); } void CMemoryWindow::Update() { - memview->Refresh(); - memview->Center(PC); + memview->Refresh(); + memview->Center(PC); } void CMemoryWindow::NotifyMapLoaded() { - symbols->Show(false); // hide it for faster filling - symbols->Clear(); + symbols->Show(false); // hide it for faster filling + symbols->Clear(); #if 0 - #ifdef _WIN32 +#ifdef _WIN32 const FunctionDB::XFuncMap &syms = g_symbolDB.Symbols(); for (FuntionDB::XFuncMap::iterator iter = syms.begin(); iter != syms.end(); ++iter) { int idx = symbols->Append(iter->second.name.c_str()); symbols->SetClientData(idx, (void*)&iter->second); } - #endif #endif - symbols->Show(true); - Update(); +#endif + symbols->Show(true); + Update(); } void CMemoryWindow::OnSymbolListChange(wxCommandEvent& event) { - int index = symbols->GetSelection(); - if (index >= 0) - { - Symbol* pSymbol = static_cast(symbols->GetClientData(index)); - if (pSymbol != nullptr) - { - memview->Center(pSymbol->address); - } - } + int index = symbols->GetSelection(); + if (index >= 0) + { + Symbol* pSymbol = static_cast(symbols->GetClientData(index)); + if (pSymbol != nullptr) + { + memview->Center(pSymbol->address); + } + } } void CMemoryWindow::OnHostMessage(wxCommandEvent& event) { - switch (event.GetId()) - { - case IDM_NOTIFY_MAP_LOADED: - NotifyMapLoaded(); - break; - } + switch (event.GetId()) + { + case IDM_NOTIFY_MAP_LOADED: + NotifyMapLoaded(); + break; + } } static void DumpArray(const std::string& filename, const u8* data, size_t length) { - if (data) - { - File::IOFile f(filename, "wb"); - f.WriteBytes(data, length); - } + if (data) + { + File::IOFile f(filename, "wb"); + f.WriteBytes(data, length); + } } // Write mram to file -void CMemoryWindow::OnDumpMemory( wxCommandEvent& event ) +void CMemoryWindow::OnDumpMemory(wxCommandEvent& event) { - DumpArray(File::GetUserPath(F_RAMDUMP_IDX), Memory::m_pRAM, Memory::REALRAM_SIZE); + DumpArray(File::GetUserPath(F_RAMDUMP_IDX), Memory::m_pRAM, Memory::REALRAM_SIZE); } // Write exram (aram or mem2) to file -void CMemoryWindow::OnDumpMem2( wxCommandEvent& event ) +void CMemoryWindow::OnDumpMem2(wxCommandEvent& event) { - if (SConfig::GetInstance().bWii) - { - DumpArray(File::GetUserPath(F_ARAMDUMP_IDX), Memory::m_pEXRAM, Memory::EXRAM_SIZE); - } - else - { - DumpArray(File::GetUserPath(F_ARAMDUMP_IDX), DSP::GetARAMPtr(), DSP::ARAM_SIZE); - } + if (SConfig::GetInstance().bWii) + { + DumpArray(File::GetUserPath(F_ARAMDUMP_IDX), Memory::m_pEXRAM, Memory::EXRAM_SIZE); + } + else + { + DumpArray(File::GetUserPath(F_ARAMDUMP_IDX), DSP::GetARAMPtr(), DSP::ARAM_SIZE); + } } // Write fake vmem to file -void CMemoryWindow::OnDumpFakeVMEM( wxCommandEvent& event ) +void CMemoryWindow::OnDumpFakeVMEM(wxCommandEvent& event) { - DumpArray(File::GetUserPath(F_FAKEVMEMDUMP_IDX), Memory::m_pFakeVMEM, Memory::FAKEVMEM_SIZE); + DumpArray(File::GetUserPath(F_FAKEVMEMDUMP_IDX), Memory::m_pFakeVMEM, Memory::FAKEVMEM_SIZE); } void CMemoryWindow::U8(wxCommandEvent& event) { - chk16->SetValue(0); - chk32->SetValue(0); - memview->SetDataType(MemoryDataType::U8); + chk16->SetValue(0); + chk32->SetValue(0); + memview->SetDataType(MemoryDataType::U8); } void CMemoryWindow::U16(wxCommandEvent& event) { - chk8->SetValue(0); - chk32->SetValue(0); - memview->SetDataType(MemoryDataType::U16); + chk8->SetValue(0); + chk32->SetValue(0); + memview->SetDataType(MemoryDataType::U16); } void CMemoryWindow::U32(wxCommandEvent& event) { - chk16->SetValue(0); - chk8->SetValue(0); - memview->SetDataType(MemoryDataType::U32); + chk16->SetValue(0); + chk8->SetValue(0); + memview->SetDataType(MemoryDataType::U32); } void CMemoryWindow::onSearch(wxCommandEvent& event) { - u8* TheRAM = nullptr; - u32 szRAM = 0; - switch (memview->GetMemoryType()) - { - case 0: - default: - if (Memory::m_pRAM) - { - TheRAM = Memory::m_pRAM; - szRAM = Memory::REALRAM_SIZE; - } - break; - case 1: - { - u8* aram = DSP::GetARAMPtr(); - if (aram) - { - TheRAM = aram; - szRAM = DSP::ARAM_SIZE; - } - } - break; - } - //Now we have memory to look in - //Are we looking for ASCII string, or hex? - //memview->cu - wxString rawData = valbox->GetValue(); - std::vector Dest; //May need a better name - u32 size = 0; - int pad = rawData.size()%2; //If it's uneven - unsigned int i = 0; - long count = 0; - char copy[3] = {0}; - long newsize = 0; - unsigned char *tmp2 = nullptr; - char* tmpstr = nullptr; + u8* TheRAM = nullptr; + u32 szRAM = 0; + switch (memview->GetMemoryType()) + { + case 0: + default: + if (Memory::m_pRAM) + { + TheRAM = Memory::m_pRAM; + szRAM = Memory::REALRAM_SIZE; + } + break; + case 1: + { + u8* aram = DSP::GetARAMPtr(); + if (aram) + { + TheRAM = aram; + szRAM = DSP::ARAM_SIZE; + } + } + break; + } + // Now we have memory to look in + // Are we looking for ASCII string, or hex? + // memview->cu + wxString rawData = valbox->GetValue(); + std::vector Dest; // May need a better name + u32 size = 0; + int pad = rawData.size() % 2; // If it's uneven + unsigned int i = 0; + long count = 0; + char copy[3] = {0}; + long newsize = 0; + unsigned char* tmp2 = nullptr; + char* tmpstr = nullptr; - if (chkHex->GetValue()) - { - //We are looking for hex - //If it's uneven - size = (rawData.size()/2) + pad; - Dest.resize(size+32); - newsize = rawData.size(); + if (chkHex->GetValue()) + { + // We are looking for hex + // If it's uneven + size = (rawData.size() / 2) + pad; + Dest.resize(size + 32); + newsize = rawData.size(); - if (pad) - { - tmpstr = new char[newsize + 2]; - memset(tmpstr, 0, newsize + 2); - tmpstr[0] = '0'; - } - else - { - tmpstr = new char[newsize + 1]; - memset(tmpstr, 0, newsize + 1); - } - strcat(tmpstr, WxStrToStr(rawData).c_str()); - tmp2 = &Dest.front(); - count = 0; - for (i = 0; i < strlen(tmpstr); i++) - { - copy[0] = tmpstr[i]; - copy[1] = tmpstr[i+1]; - copy[2] = 0; - int tmpint; - sscanf(copy, "%02x", &tmpint); - tmp2[count++] = tmpint; - // Dest[count] should now be the hex of what the two chars were! - // Also should add a check to make sure it's A-F only - //sscanf(copy, "%02x", &tmp2[count++]); - i += 1; - } - delete[] tmpstr; - } - else - { - //Looking for an ascii string - size = rawData.size(); - Dest.resize(size+1); - tmpstr = new char[size+1]; + if (pad) + { + tmpstr = new char[newsize + 2]; + memset(tmpstr, 0, newsize + 2); + tmpstr[0] = '0'; + } + else + { + tmpstr = new char[newsize + 1]; + memset(tmpstr, 0, newsize + 1); + } + strcat(tmpstr, WxStrToStr(rawData).c_str()); + tmp2 = &Dest.front(); + count = 0; + for (i = 0; i < strlen(tmpstr); i++) + { + copy[0] = tmpstr[i]; + copy[1] = tmpstr[i + 1]; + copy[2] = 0; + int tmpint; + sscanf(copy, "%02x", &tmpint); + tmp2[count++] = tmpint; + // Dest[count] should now be the hex of what the two chars were! + // Also should add a check to make sure it's A-F only + // sscanf(copy, "%02x", &tmp2[count++]); + i += 1; + } + delete[] tmpstr; + } + else + { + // Looking for an ascii string + size = rawData.size(); + Dest.resize(size + 1); + tmpstr = new char[size + 1]; - tmp2 = &Dest.front(); - sprintf(tmpstr, "%s", WxStrToStr(rawData).c_str()); + tmp2 = &Dest.front(); + sprintf(tmpstr, "%s", WxStrToStr(rawData).c_str()); - for (i = 0; i < size; i++) - tmp2[i] = tmpstr[i]; + for (i = 0; i < size; i++) + tmp2[i] = tmpstr[i]; - delete[] tmpstr; - } + delete[] tmpstr; + } - if (size) - { - unsigned char* pnt = &Dest.front(); - unsigned int k = 0; - //grab - wxString txt = addrbox->GetValue(); - u32 addr = 0; - if (txt.size()) - { - sscanf(WxStrToStr(txt).c_str(), "%08x", &addr); - } - i = addr+4; - for ( ; i < szRAM; ++i) - { - for (k = 0; k < size; ++k) - { - if (i + k > szRAM) break; - if (k > size) break; - if (pnt[k] != TheRAM[i+k]) - { - k = 0; - break; - } - } - if (k == size) - { - //Match was found - wxMessageBox(_("A match was found. Placing viewer at the offset.")); - addrbox->SetValue(wxString::Format("%08x", i)); - //memview->curAddress = i; - //memview->Refresh(); - OnAddrBoxChange(event); - return; - } - } - wxMessageBox(_("No match was found.")); - } + if (size) + { + unsigned char* pnt = &Dest.front(); + unsigned int k = 0; + // grab + wxString txt = addrbox->GetValue(); + u32 addr = 0; + if (txt.size()) + { + sscanf(WxStrToStr(txt).c_str(), "%08x", &addr); + } + i = addr + 4; + for (; i < szRAM; ++i) + { + for (k = 0; k < size; ++k) + { + if (i + k > szRAM) + break; + if (k > size) + break; + if (pnt[k] != TheRAM[i + k]) + { + k = 0; + break; + } + } + if (k == size) + { + // Match was found + wxMessageBox(_("A match was found. Placing viewer at the offset.")); + addrbox->SetValue(wxString::Format("%08x", i)); + // memview->curAddress = i; + // memview->Refresh(); + OnAddrBoxChange(event); + return; + } + } + wxMessageBox(_("No match was found.")); + } } void CMemoryWindow::onAscii(wxCommandEvent& event) { - chkHex->SetValue(0); + chkHex->SetValue(0); } void CMemoryWindow::onHex(wxCommandEvent& event) { - chkAscii->SetValue(0); + chkAscii->SetValue(0); } diff --git a/Source/Core/DolphinWX/Debugger/MemoryWindow.h b/Source/Core/DolphinWX/Debugger/MemoryWindow.h index 596cef6fd5..c2f94677ca 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryWindow.h +++ b/Source/Core/DolphinWX/Debugger/MemoryWindow.h @@ -18,49 +18,46 @@ class wxTextCtrl; class CMemoryWindow : public wxPanel { public: - CMemoryWindow(wxWindow* parent, - wxWindowID id = wxID_ANY, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxTAB_TRAVERSAL | wxBORDER_NONE, - const wxString& name = _("Memory")); + CMemoryWindow(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL | wxBORDER_NONE, + const wxString& name = _("Memory")); - void Save(IniFile& _IniFile) const; - void Load(IniFile& _IniFile); + void Save(IniFile& _IniFile) const; + void Load(IniFile& _IniFile); - void Update() override; - void NotifyMapLoaded(); + void Update() override; + void NotifyMapLoaded(); - void JumpToAddress(u32 _Address); + void JumpToAddress(u32 _Address); private: - DECLARE_EVENT_TABLE() + DECLARE_EVENT_TABLE() - void U8(wxCommandEvent& event); - void U16(wxCommandEvent& event); - void U32(wxCommandEvent& event); - void onSearch(wxCommandEvent& event); - void onAscii(wxCommandEvent& event); - void onHex(wxCommandEvent& event); - void OnSymbolListChange(wxCommandEvent& event); - void OnAddrBoxChange(wxCommandEvent& event); - void OnHostMessage(wxCommandEvent& event); - void SetMemoryValueFromValBox(wxCommandEvent& event); - void SetMemoryValue(wxCommandEvent& event); - void OnDumpMemory(wxCommandEvent& event); - void OnDumpMem2(wxCommandEvent& event); - void OnDumpFakeVMEM(wxCommandEvent& event); + void U8(wxCommandEvent& event); + void U16(wxCommandEvent& event); + void U32(wxCommandEvent& event); + void onSearch(wxCommandEvent& event); + void onAscii(wxCommandEvent& event); + void onHex(wxCommandEvent& event); + void OnSymbolListChange(wxCommandEvent& event); + void OnAddrBoxChange(wxCommandEvent& event); + void OnHostMessage(wxCommandEvent& event); + void SetMemoryValueFromValBox(wxCommandEvent& event); + void SetMemoryValue(wxCommandEvent& event); + void OnDumpMemory(wxCommandEvent& event); + void OnDumpMem2(wxCommandEvent& event); + void OnDumpFakeVMEM(wxCommandEvent& event); - wxCheckBox* chk8; - wxCheckBox* chk16; - wxCheckBox* chk32; - wxButton* btnSearch; - wxCheckBox* chkAscii; - wxCheckBox* chkHex; + wxCheckBox* chk8; + wxCheckBox* chk16; + wxCheckBox* chk32; + wxButton* btnSearch; + wxCheckBox* chkAscii; + wxCheckBox* chkHex; - CMemoryView* memview; - wxListBox* symbols; + CMemoryView* memview; + wxListBox* symbols; - wxSearchCtrl* addrbox; - wxTextCtrl* valbox; + wxSearchCtrl* addrbox; + wxTextCtrl* valbox; }; diff --git a/Source/Core/DolphinWX/Debugger/RegisterView.cpp b/Source/Core/DolphinWX/Debugger/RegisterView.cpp index 6f13ce0586..3a65dd2c42 100644 --- a/Source/Core/DolphinWX/Debugger/RegisterView.cpp +++ b/Source/Core/DolphinWX/Debugger/RegisterView.cpp @@ -12,291 +12,349 @@ #include "Core/HW/ProcessorInterface.h" #include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/PowerPC.h" -#include "DolphinWX/Frame.h" -#include "DolphinWX/Globals.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Debugger/CodeWindow.h" #include "DolphinWX/Debugger/DebuggerUIUtil.h" #include "DolphinWX/Debugger/MemoryWindow.h" #include "DolphinWX/Debugger/RegisterView.h" #include "DolphinWX/Debugger/WatchWindow.h" +#include "DolphinWX/Frame.h" +#include "DolphinWX/Globals.h" +#include "DolphinWX/WxUtils.h" // F-zero 80005e60 wtf?? enum { - IDM_WATCHADDRESS, - IDM_VIEWMEMORY, - IDM_VIEWCODE + IDM_WATCHADDRESS, + IDM_VIEWMEMORY, + IDM_VIEWCODE }; -static const char *special_reg_names[] = { - "PC", "LR", "CTR", "CR", "FPSCR", "MSR", "SRR0", "SRR1", "Exceptions", "Int Mask", "Int Cause", "DSISR", "DAR", "PT hashmask" -}; +static const char* special_reg_names[] = {"PC", "LR", "CTR", "CR", "FPSCR", + "MSR", "SRR0", "SRR1", "Exceptions", "Int Mask", + "Int Cause", "DSISR", "DAR", "PT hashmask"}; static u32 GetSpecialRegValue(int reg) { - switch (reg) - { - case 0: return PowerPC::ppcState.pc; - case 1: return PowerPC::ppcState.spr[SPR_LR]; - case 2: return PowerPC::ppcState.spr[SPR_CTR]; - case 3: return GetCR(); - case 4: return PowerPC::ppcState.fpscr; - case 5: return PowerPC::ppcState.msr; - case 6: return PowerPC::ppcState.spr[SPR_SRR0]; - case 7: return PowerPC::ppcState.spr[SPR_SRR1]; - case 8: return PowerPC::ppcState.Exceptions; - case 9: return ProcessorInterface::GetMask(); - case 10: return ProcessorInterface::GetCause(); - case 11: return PowerPC::ppcState.spr[SPR_DSISR]; - case 12: return PowerPC::ppcState.spr[SPR_DAR]; - case 13: return (PowerPC::ppcState.pagetable_hashmask << 6) | PowerPC::ppcState.pagetable_base; - default: return 0; - } + switch (reg) + { + case 0: + return PowerPC::ppcState.pc; + case 1: + return PowerPC::ppcState.spr[SPR_LR]; + case 2: + return PowerPC::ppcState.spr[SPR_CTR]; + case 3: + return GetCR(); + case 4: + return PowerPC::ppcState.fpscr; + case 5: + return PowerPC::ppcState.msr; + case 6: + return PowerPC::ppcState.spr[SPR_SRR0]; + case 7: + return PowerPC::ppcState.spr[SPR_SRR1]; + case 8: + return PowerPC::ppcState.Exceptions; + case 9: + return ProcessorInterface::GetMask(); + case 10: + return ProcessorInterface::GetCause(); + case 11: + return PowerPC::ppcState.spr[SPR_DSISR]; + case 12: + return PowerPC::ppcState.spr[SPR_DAR]; + case 13: + return (PowerPC::ppcState.pagetable_hashmask << 6) | PowerPC::ppcState.pagetable_base; + default: + return 0; + } } static wxString GetValueByRowCol(int row, int col) { - if (row < 32) - { - switch (col) - { - case 0: return StrToWxStr(GekkoDisassembler::GetGPRName(row)); - case 1: return wxString::Format("%08x", GPR(row)); - case 2: return StrToWxStr(GekkoDisassembler::GetFPRName(row)); - case 3: return wxString::Format("%016llx", riPS0(row)); - case 4: return wxString::Format("%016llx", riPS1(row)); - case 5: - { - if (row < 4) - return wxString::Format("DBAT%01d", row); + if (row < 32) + { + switch (col) + { + case 0: + return StrToWxStr(GekkoDisassembler::GetGPRName(row)); + case 1: + return wxString::Format("%08x", GPR(row)); + case 2: + return StrToWxStr(GekkoDisassembler::GetFPRName(row)); + case 3: + return wxString::Format("%016llx", riPS0(row)); + case 4: + return wxString::Format("%016llx", riPS1(row)); + case 5: + { + if (row < 4) + return wxString::Format("DBAT%01d", row); - if (row < 8) - return wxString::Format("IBAT%01d", row - 4); + if (row < 8) + return wxString::Format("IBAT%01d", row - 4); - if (row < 12) - return wxString::Format("DBAT%01d", row - 4); + if (row < 12) + return wxString::Format("DBAT%01d", row - 4); - if (row < 16) - return wxString::Format("IBAT%01d", row - 8); + if (row < 16) + return wxString::Format("IBAT%01d", row - 8); - break; - } - case 6: - { - if (row < 4) - return wxString::Format("%016llx", (u64)PowerPC::ppcState.spr[SPR_DBAT0U + row * 2] << 32 | PowerPC::ppcState.spr[SPR_DBAT0L + row * 2]); + break; + } + case 6: + { + if (row < 4) + return wxString::Format("%016llx", (u64)PowerPC::ppcState.spr[SPR_DBAT0U + row * 2] << 32 | + PowerPC::ppcState.spr[SPR_DBAT0L + row * 2]); - if (row < 8) - return wxString::Format("%016llx", (u64)PowerPC::ppcState.spr[SPR_IBAT0U + (row - 4) * 2] << 32 | PowerPC::ppcState.spr[SPR_IBAT0L + (row - 4) * 2]); + if (row < 8) + return wxString::Format("%016llx", (u64)PowerPC::ppcState.spr[SPR_IBAT0U + (row - 4) * 2] + << 32 | + PowerPC::ppcState.spr[SPR_IBAT0L + (row - 4) * 2]); - if (row < 12) - return wxString::Format("%016llx", (u64)PowerPC::ppcState.spr[SPR_DBAT4U + (row - 12) * 2] << 32 | PowerPC::ppcState.spr[SPR_DBAT4L + (row - 12) * 2]); + if (row < 12) + return wxString::Format("%016llx", (u64)PowerPC::ppcState.spr[SPR_DBAT4U + (row - 12) * 2] + << 32 | + PowerPC::ppcState.spr[SPR_DBAT4L + (row - 12) * 2]); - if (row < 16) - return wxString::Format("%016llx", (u64)PowerPC::ppcState.spr[SPR_IBAT4U + (row - 16) * 2] << 32 | PowerPC::ppcState.spr[SPR_IBAT4L + (row - 16) * 2]); + if (row < 16) + return wxString::Format("%016llx", (u64)PowerPC::ppcState.spr[SPR_IBAT4U + (row - 16) * 2] + << 32 | + PowerPC::ppcState.spr[SPR_IBAT4L + (row - 16) * 2]); - break; - } - case 7: - { - if (row < 16) - return wxString::Format("SR%02d", row); + break; + } + case 7: + { + if (row < 16) + return wxString::Format("SR%02d", row); - break; - } - case 8: - { - if (row < 16) - return wxString::Format("%08x", PowerPC::ppcState.sr[row]); + break; + } + case 8: + { + if (row < 16) + return wxString::Format("%08x", PowerPC::ppcState.sr[row]); - break; - } - default: return wxEmptyString; - } - } - else - { - if (row - 32 < NUM_SPECIALS) - { - switch (col) - { - case 0: return StrToWxStr(special_reg_names[row - 32]); - case 1: return wxString::Format("%08x", GetSpecialRegValue(row - 32)); - default: return wxEmptyString; - } - } - } - return wxEmptyString; + break; + } + default: + return wxEmptyString; + } + } + else + { + if (row - 32 < NUM_SPECIALS) + { + switch (col) + { + case 0: + return StrToWxStr(special_reg_names[row - 32]); + case 1: + return wxString::Format("%08x", GetSpecialRegValue(row - 32)); + default: + return wxEmptyString; + } + } + } + return wxEmptyString; } wxString CRegTable::GetValue(int row, int col) { - return GetValueByRowCol(row, col); + return GetValueByRowCol(row, col); } static void SetSpecialRegValue(int reg, u32 value) { - switch (reg) - { - case 0: PowerPC::ppcState.pc = value; break; - case 1: PowerPC::ppcState.spr[SPR_LR] = value; break; - case 2: PowerPC::ppcState.spr[SPR_CTR] = value; break; - case 3: SetCR(value); break; - case 4: PowerPC::ppcState.fpscr = value; break; - case 5: PowerPC::ppcState.msr = value; break; - case 6: PowerPC::ppcState.spr[SPR_SRR0] = value; break; - case 7: PowerPC::ppcState.spr[SPR_SRR1] = value; break; - case 8: PowerPC::ppcState.Exceptions = value; break; - // Should we just change the value, or use ProcessorInterface::SetInterrupt() to make the system aware? - // case 9: return ProcessorInterface::GetMask(); - // case 10: return ProcessorInterface::GetCause(); - case 11: PowerPC::ppcState.spr[SPR_DSISR] = value; break; - case 12: PowerPC::ppcState.spr[SPR_DAR] = value; break; - //case 13: (PowerPC::ppcState.pagetable_hashmask << 6) | PowerPC::ppcState.pagetable_base; - default: return; - } + switch (reg) + { + case 0: + PowerPC::ppcState.pc = value; + break; + case 1: + PowerPC::ppcState.spr[SPR_LR] = value; + break; + case 2: + PowerPC::ppcState.spr[SPR_CTR] = value; + break; + case 3: + SetCR(value); + break; + case 4: + PowerPC::ppcState.fpscr = value; + break; + case 5: + PowerPC::ppcState.msr = value; + break; + case 6: + PowerPC::ppcState.spr[SPR_SRR0] = value; + break; + case 7: + PowerPC::ppcState.spr[SPR_SRR1] = value; + break; + case 8: + PowerPC::ppcState.Exceptions = value; + break; + // Should we just change the value, or use ProcessorInterface::SetInterrupt() to make the system + // aware? + // case 9: return ProcessorInterface::GetMask(); + // case 10: return ProcessorInterface::GetCause(); + case 11: + PowerPC::ppcState.spr[SPR_DSISR] = value; + break; + case 12: + PowerPC::ppcState.spr[SPR_DAR] = value; + break; + // case 13: (PowerPC::ppcState.pagetable_hashmask << 6) | PowerPC::ppcState.pagetable_base; + default: + return; + } } void CRegTable::SetValue(int row, int col, const wxString& strNewVal) { - u32 newVal = 0; - if (TryParse("0x" + WxStrToStr(strNewVal), &newVal)) - { - if (row < 32) - { - if (col == 1) - GPR(row) = newVal; - else if (col == 3) - riPS0(row) = newVal; - else if (col == 4) - riPS1(row) = newVal; - } - else - { - if ((row - 32 < NUM_SPECIALS) && (col == 1)) - { - SetSpecialRegValue(row - 32, newVal); - } - } - } + u32 newVal = 0; + if (TryParse("0x" + WxStrToStr(strNewVal), &newVal)) + { + if (row < 32) + { + if (col == 1) + GPR(row) = newVal; + else if (col == 3) + riPS0(row) = newVal; + else if (col == 4) + riPS1(row) = newVal; + } + else + { + if ((row - 32 < NUM_SPECIALS) && (col == 1)) + { + SetSpecialRegValue(row - 32, newVal); + } + } + } } void CRegTable::UpdateCachedRegs() { - for (int i = 0; i < 32; ++i) - { - m_CachedRegHasChanged[i] = (m_CachedRegs[i] != GPR(i)); - m_CachedRegs[i] = GPR(i); + for (int i = 0; i < 32; ++i) + { + m_CachedRegHasChanged[i] = (m_CachedRegs[i] != GPR(i)); + m_CachedRegs[i] = GPR(i); - m_CachedFRegHasChanged[i][0] = (m_CachedFRegs[i][0] != riPS0(i)); - m_CachedFRegs[i][0] = riPS0(i); - m_CachedFRegHasChanged[i][1] = (m_CachedFRegs[i][1] != riPS1(i)); - m_CachedFRegs[i][1] = riPS1(i); - } - for (int i = 0; i < NUM_SPECIALS; ++i) - { - m_CachedSpecialRegHasChanged[i] = (m_CachedSpecialRegs[i] != GetSpecialRegValue(i)); - m_CachedSpecialRegs[i] = GetSpecialRegValue(i); - } + m_CachedFRegHasChanged[i][0] = (m_CachedFRegs[i][0] != riPS0(i)); + m_CachedFRegs[i][0] = riPS0(i); + m_CachedFRegHasChanged[i][1] = (m_CachedFRegs[i][1] != riPS1(i)); + m_CachedFRegs[i][1] = riPS1(i); + } + for (int i = 0; i < NUM_SPECIALS; ++i) + { + m_CachedSpecialRegHasChanged[i] = (m_CachedSpecialRegs[i] != GetSpecialRegValue(i)); + m_CachedSpecialRegs[i] = GetSpecialRegValue(i); + } } -wxGridCellAttr *CRegTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind) +wxGridCellAttr* CRegTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind) { - wxGridCellAttr *attr = new wxGridCellAttr(); + wxGridCellAttr* attr = new wxGridCellAttr(); - attr->SetBackgroundColour(*wxWHITE); - attr->SetFont(DebuggerFont); + attr->SetBackgroundColour(*wxWHITE); + attr->SetFont(DebuggerFont); - switch (col) - { - case 1: - attr->SetAlignment(wxALIGN_CENTER, wxALIGN_CENTER); - break; - case 3: - case 4: - attr->SetAlignment(wxALIGN_RIGHT, wxALIGN_CENTER); - break; - default: - attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER); - break; - } + switch (col) + { + case 1: + attr->SetAlignment(wxALIGN_CENTER, wxALIGN_CENTER); + break; + case 3: + case 4: + attr->SetAlignment(wxALIGN_RIGHT, wxALIGN_CENTER); + break; + default: + attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER); + break; + } - bool red = false; - switch (col) - { - case 1: red = row < 32 ? m_CachedRegHasChanged[row] : m_CachedSpecialRegHasChanged[row-32]; break; - case 3: - case 4: red = row < 32 ? m_CachedFRegHasChanged[row][col-3] : false; break; - } + bool red = false; + switch (col) + { + case 1: + red = row < 32 ? m_CachedRegHasChanged[row] : m_CachedSpecialRegHasChanged[row - 32]; + break; + case 3: + case 4: + red = row < 32 ? m_CachedFRegHasChanged[row][col - 3] : false; + break; + } - attr->SetTextColour(red ? *wxRED : *wxBLACK); - return attr; + attr->SetTextColour(red ? *wxRED : *wxBLACK); + return attr; } -CRegisterView::CRegisterView(wxWindow *parent, wxWindowID id) - : wxGrid(parent, id) +CRegisterView::CRegisterView(wxWindow* parent, wxWindowID id) : wxGrid(parent, id) { - m_register_table = new CRegTable(); + m_register_table = new CRegTable(); - SetTable(m_register_table, true); - SetRowLabelSize(0); - SetColLabelSize(0); - DisableDragRowSize(); + SetTable(m_register_table, true); + SetRowLabelSize(0); + SetColLabelSize(0); + DisableDragRowSize(); - Bind(wxEVT_GRID_CELL_RIGHT_CLICK, &CRegisterView::OnMouseDownR, this); - Bind(wxEVT_MENU, &CRegisterView::OnPopupMenu, this); + Bind(wxEVT_GRID_CELL_RIGHT_CLICK, &CRegisterView::OnMouseDownR, this); + Bind(wxEVT_MENU, &CRegisterView::OnPopupMenu, this); - AutoSizeColumns(); + AutoSizeColumns(); } void CRegisterView::Update() { - m_register_table->UpdateCachedRegs(); - ForceRefresh(); + m_register_table->UpdateCachedRegs(); + ForceRefresh(); } void CRegisterView::OnMouseDownR(wxGridEvent& event) { - // popup menu - int row = event.GetRow(); - int col = event.GetCol(); + // popup menu + int row = event.GetRow(); + int col = event.GetCol(); - wxString strNewVal = GetValueByRowCol(row, col); - TryParse("0x" + WxStrToStr(strNewVal), &m_selectedAddress); + wxString strNewVal = GetValueByRowCol(row, col); + TryParse("0x" + WxStrToStr(strNewVal), &m_selectedAddress); - wxMenu menu; - menu.Append(IDM_WATCHADDRESS, _("Add to &watch")); - menu.Append(IDM_VIEWMEMORY, _("View &memory")); - menu.Append(IDM_VIEWCODE, _("View &code")); - PopupMenu(&menu); + wxMenu menu; + menu.Append(IDM_WATCHADDRESS, _("Add to &watch")); + menu.Append(IDM_VIEWMEMORY, _("View &memory")); + menu.Append(IDM_VIEWCODE, _("View &code")); + PopupMenu(&menu); } void CRegisterView::OnPopupMenu(wxCommandEvent& event) { - CFrame* main_frame = static_cast(GetGrandParent()->GetParent()); - CCodeWindow* code_window = main_frame->g_pCodeWindow; - CWatchWindow* watch_window = code_window->m_WatchWindow; - CMemoryWindow* memory_window = code_window->m_MemoryWindow; + CFrame* main_frame = static_cast(GetGrandParent()->GetParent()); + CCodeWindow* code_window = main_frame->g_pCodeWindow; + CWatchWindow* watch_window = code_window->m_WatchWindow; + CMemoryWindow* memory_window = code_window->m_MemoryWindow; - switch (event.GetId()) - { - case IDM_WATCHADDRESS: - PowerPC::watches.Add(m_selectedAddress); - if (watch_window) - watch_window->NotifyUpdate(); - Refresh(); - break; - case IDM_VIEWMEMORY: - if (memory_window) - memory_window->JumpToAddress(m_selectedAddress); - Refresh(); - break; - case IDM_VIEWCODE: - code_window->JumpToAddress(m_selectedAddress); - Refresh(); - break; - } - event.Skip(); + switch (event.GetId()) + { + case IDM_WATCHADDRESS: + PowerPC::watches.Add(m_selectedAddress); + if (watch_window) + watch_window->NotifyUpdate(); + Refresh(); + break; + case IDM_VIEWMEMORY: + if (memory_window) + memory_window->JumpToAddress(m_selectedAddress); + Refresh(); + break; + case IDM_VIEWCODE: + code_window->JumpToAddress(m_selectedAddress); + Refresh(); + break; + } + event.Skip(); } diff --git a/Source/Core/DolphinWX/Debugger/RegisterView.h b/Source/Core/DolphinWX/Debugger/RegisterView.h index 96d03e11c7..33ba8ad097 100644 --- a/Source/Core/DolphinWX/Debugger/RegisterView.h +++ b/Source/Core/DolphinWX/Debugger/RegisterView.h @@ -29,50 +29,48 @@ class CRegTable : public wxGridTableBase { - public: + CRegTable() + { + memset(m_CachedRegs, 0, sizeof(m_CachedRegs)); + memset(m_CachedSpecialRegs, 0, sizeof(m_CachedSpecialRegs)); + memset(m_CachedFRegs, 0, sizeof(m_CachedFRegs)); + memset(m_CachedRegHasChanged, 0, sizeof(m_CachedRegHasChanged)); + memset(m_CachedSpecialRegHasChanged, 0, sizeof(m_CachedSpecialRegHasChanged)); + memset(m_CachedFRegHasChanged, 0, sizeof(m_CachedFRegHasChanged)); + } - CRegTable() - { - memset(m_CachedRegs, 0, sizeof(m_CachedRegs)); - memset(m_CachedSpecialRegs, 0, sizeof(m_CachedSpecialRegs)); - memset(m_CachedFRegs, 0, sizeof(m_CachedFRegs)); - memset(m_CachedRegHasChanged, 0, sizeof(m_CachedRegHasChanged)); - memset(m_CachedSpecialRegHasChanged, 0, sizeof(m_CachedSpecialRegHasChanged)); - memset(m_CachedFRegHasChanged, 0, sizeof(m_CachedFRegHasChanged)); - } - - int GetNumberCols() override { return 9; } - int GetNumberRows() override { return 32 + NUM_SPECIALS; } - bool IsEmptyCell(int row, int col) override { return row > 31 && col > 2; } - wxString GetValue(int row, int col) override; - void SetValue(int row, int col, const wxString &) override; - wxGridCellAttr *GetAttr(int, int, wxGridCellAttr::wxAttrKind) override; - void UpdateCachedRegs(); + int GetNumberCols() override { return 9; } + int GetNumberRows() override { return 32 + NUM_SPECIALS; } + bool IsEmptyCell(int row, int col) override { return row > 31 && col > 2; } + wxString GetValue(int row, int col) override; + void SetValue(int row, int col, const wxString&) override; + wxGridCellAttr* GetAttr(int, int, wxGridCellAttr::wxAttrKind) override; + void UpdateCachedRegs(); private: - u32 m_CachedRegs[32]; - u32 m_CachedSpecialRegs[NUM_SPECIALS]; - u64 m_CachedFRegs[32][2]; - bool m_CachedRegHasChanged[32]; - bool m_CachedSpecialRegHasChanged[NUM_SPECIALS]; - bool m_CachedFRegHasChanged[32][2]; + u32 m_CachedRegs[32]; + u32 m_CachedSpecialRegs[NUM_SPECIALS]; + u64 m_CachedFRegs[32][2]; + bool m_CachedRegHasChanged[32]; + bool m_CachedSpecialRegHasChanged[NUM_SPECIALS]; + bool m_CachedFRegHasChanged[32][2]; - DECLARE_NO_COPY_CLASS(CRegTable); + DECLARE_NO_COPY_CLASS(CRegTable); }; class CRegisterView : public wxGrid { public: - CRegisterView(wxWindow* parent, wxWindowID id = wxID_ANY); - void Update() override; + CRegisterView(wxWindow* parent, wxWindowID id = wxID_ANY); + void Update() override; private: - void OnMouseDownR(wxGridEvent& event); - void OnPopupMenu(wxCommandEvent& event); + void OnMouseDownR(wxGridEvent& event); + void OnPopupMenu(wxCommandEvent& event); - u32 m_selectedAddress = 0; + u32 m_selectedAddress = 0; - // Owned by wx. Deleted implicitly upon destruction. - CRegTable* m_register_table; + // Owned by wx. Deleted implicitly upon destruction. + CRegTable* m_register_table; }; diff --git a/Source/Core/DolphinWX/Debugger/RegisterWindow.cpp b/Source/Core/DolphinWX/Debugger/RegisterWindow.cpp index f9ec364204..03d1afbab8 100644 --- a/Source/Core/DolphinWX/Debugger/RegisterWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/RegisterWindow.cpp @@ -10,27 +10,25 @@ #include "DolphinWX/Debugger/RegisterView.h" #include "DolphinWX/Debugger/RegisterWindow.h" -CRegisterWindow::CRegisterWindow(wxWindow* parent, wxWindowID id, - const wxPoint& position, const wxSize& size, - long style, const wxString& name) - : wxPanel(parent, id, position, size, style, name) - , m_GPRGridView(nullptr) +CRegisterWindow::CRegisterWindow(wxWindow* parent, wxWindowID id, const wxPoint& position, + const wxSize& size, long style, const wxString& name) + : wxPanel(parent, id, position, size, style, name), m_GPRGridView(nullptr) { - CreateGUIControls(); + CreateGUIControls(); } void CRegisterWindow::CreateGUIControls() { - wxBoxSizer *sGrid = new wxBoxSizer(wxVERTICAL); - m_GPRGridView = new CRegisterView(this); - sGrid->Add(m_GPRGridView, 1, wxGROW); - SetSizer(sGrid); + wxBoxSizer* sGrid = new wxBoxSizer(wxVERTICAL); + m_GPRGridView = new CRegisterView(this); + sGrid->Add(m_GPRGridView, 1, wxGROW); + SetSizer(sGrid); - NotifyUpdate(); + NotifyUpdate(); } void CRegisterWindow::NotifyUpdate() { - if (m_GPRGridView != nullptr) - m_GPRGridView->Update(); + if (m_GPRGridView != nullptr) + m_GPRGridView->Update(); } diff --git a/Source/Core/DolphinWX/Debugger/RegisterWindow.h b/Source/Core/DolphinWX/Debugger/RegisterWindow.h index c7518639d2..096e590737 100644 --- a/Source/Core/DolphinWX/Debugger/RegisterWindow.h +++ b/Source/Core/DolphinWX/Debugger/RegisterWindow.h @@ -11,16 +11,14 @@ class CRegisterView; class CRegisterWindow : public wxPanel { public: - CRegisterWindow(wxWindow* parent, - wxWindowID id = wxID_ANY, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxTAB_TRAVERSAL | wxNO_BORDER, - const wxString& name = _("Registers")); + CRegisterWindow(wxWindow* parent, wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxTAB_TRAVERSAL | wxNO_BORDER, + const wxString& name = _("Registers")); - void NotifyUpdate(); + void NotifyUpdate(); private: - CRegisterView* m_GPRGridView; - void CreateGUIControls(); + CRegisterView* m_GPRGridView; + void CreateGUIControls(); }; diff --git a/Source/Core/DolphinWX/Debugger/WatchView.cpp b/Source/Core/DolphinWX/Debugger/WatchView.cpp index 4f46c8aab2..72c4a37332 100644 --- a/Source/Core/DolphinWX/Debugger/WatchView.cpp +++ b/Source/Core/DolphinWX/Debugger/WatchView.cpp @@ -10,8 +10,6 @@ #include "Core/Core.h" #include "Core/HW/Memmap.h" #include "Core/PowerPC/PowerPC.h" -#include "DolphinWX/Frame.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Debugger/BreakpointWindow.h" #include "DolphinWX/Debugger/CodeWindow.h" #include "DolphinWX/Debugger/DebuggerUIUtil.h" @@ -19,289 +17,300 @@ #include "DolphinWX/Debugger/RegisterView.h" #include "DolphinWX/Debugger/WatchView.h" #include "DolphinWX/Debugger/WatchWindow.h" +#include "DolphinWX/Frame.h" +#include "DolphinWX/WxUtils.h" enum { - IDM_DELETEWATCH = 1, - IDM_ADDMEMCHECK, - IDM_VIEWMEMORY, + IDM_DELETEWATCH = 1, + IDM_ADDMEMCHECK, + IDM_VIEWMEMORY, }; - static std::string GetWatchName(int count) { - return PowerPC::watches.GetWatches().at(count - 1).name; + return PowerPC::watches.GetWatches().at(count - 1).name; } static u32 GetWatchAddr(int count) { - return PowerPC::watches.GetWatches().at(count - 1).iAddress; + return PowerPC::watches.GetWatches().at(count - 1).iAddress; } static u32 GetWatchValue(int count) { - return PowerPC::HostRead_U32(GetWatchAddr(count)); + return PowerPC::HostRead_U32(GetWatchAddr(count)); } static void AddWatchAddr(int count, u32 value) { - PowerPC::watches.Add(value); + PowerPC::watches.Add(value); } static void UpdateWatchAddr(int count, u32 value) { - PowerPC::watches.Update(count - 1, value); + PowerPC::watches.Update(count - 1, value); } static void SetWatchName(int count, const std::string& value) { - if ((count - 1) < (int)PowerPC::watches.GetWatches().size()) - { - PowerPC::watches.UpdateName(count - 1, value); - } - else - { - PowerPC::watches.Add(0); - PowerPC::watches.UpdateName(PowerPC::watches.GetWatches().size() - 1, value); - } + if ((count - 1) < (int)PowerPC::watches.GetWatches().size()) + { + PowerPC::watches.UpdateName(count - 1, value); + } + else + { + PowerPC::watches.Add(0); + PowerPC::watches.UpdateName(PowerPC::watches.GetWatches().size() - 1, value); + } } static void SetWatchValue(int count, u32 value) { - PowerPC::HostWrite_U32(value, GetWatchAddr(count)); + PowerPC::HostWrite_U32(value, GetWatchAddr(count)); } static wxString GetValueByRowCol(int row, int col) { - if (row == 0) - { - // Column Labels - switch (col) - { - case 0: return _("Label"); - case 1: return _("Address"); - case 2: return _("Hexadecimal"); - case 3: return _("Decimal"); - case 4: return _("String"); - default: return wxEmptyString; - } - } - else if (row <= (int)PowerPC::watches.GetWatches().size()) - { - if (Core::IsRunning()) - { - switch (col) - { - case 0: return wxString::Format("%s", GetWatchName(row)); - case 1: return wxString::Format("%08x", GetWatchAddr(row)); - case 2: return wxString::Format("%08x", GetWatchValue(row)); - case 3: return wxString::Format("%u", GetWatchValue(row)); - case 4: - { - u32 addr = GetWatchAddr(row); - if (PowerPC::HostIsRAMAddress(addr)) - return PowerPC::HostGetString(addr, 32).c_str(); - else - return wxEmptyString; - } - default: return wxEmptyString; - } - } - } - return wxEmptyString; + if (row == 0) + { + // Column Labels + switch (col) + { + case 0: + return _("Label"); + case 1: + return _("Address"); + case 2: + return _("Hexadecimal"); + case 3: + return _("Decimal"); + case 4: + return _("String"); + default: + return wxEmptyString; + } + } + else if (row <= (int)PowerPC::watches.GetWatches().size()) + { + if (Core::IsRunning()) + { + switch (col) + { + case 0: + return wxString::Format("%s", GetWatchName(row)); + case 1: + return wxString::Format("%08x", GetWatchAddr(row)); + case 2: + return wxString::Format("%08x", GetWatchValue(row)); + case 3: + return wxString::Format("%u", GetWatchValue(row)); + case 4: + { + u32 addr = GetWatchAddr(row); + if (PowerPC::HostIsRAMAddress(addr)) + return PowerPC::HostGetString(addr, 32).c_str(); + else + return wxEmptyString; + } + default: + return wxEmptyString; + } + } + } + return wxEmptyString; } wxString CWatchTable::GetValue(int row, int col) { - return GetValueByRowCol(row, col); + return GetValueByRowCol(row, col); } void CWatchTable::SetValue(int row, int col, const wxString& strNewVal) { - u32 newVal = 0; - if (col == 0 || TryParse("0x" + WxStrToStr(strNewVal), &newVal)) - { - if (row > 0) - { - switch (col) - { - case 0: - { - SetWatchName(row, std::string(WxStrToStr(strNewVal))); - break; - } - case 1: - { - if (row > (int)PowerPC::watches.GetWatches().size()) - { - AddWatchAddr(row, newVal); - row = (int)PowerPC::watches.GetWatches().size(); - } - else - { - UpdateWatchAddr(row, newVal); - } - break; - } - case 2: - { - SetWatchValue(row, newVal); - break; - } - default: - break; - } - } - } + u32 newVal = 0; + if (col == 0 || TryParse("0x" + WxStrToStr(strNewVal), &newVal)) + { + if (row > 0) + { + switch (col) + { + case 0: + { + SetWatchName(row, std::string(WxStrToStr(strNewVal))); + break; + } + case 1: + { + if (row > (int)PowerPC::watches.GetWatches().size()) + { + AddWatchAddr(row, newVal); + row = (int)PowerPC::watches.GetWatches().size(); + } + else + { + UpdateWatchAddr(row, newVal); + } + break; + } + case 2: + { + SetWatchValue(row, newVal); + break; + } + default: + break; + } + } + } } void CWatchTable::UpdateWatch() { - for (int i = 0; i < (int)PowerPC::watches.GetWatches().size(); ++i) - { - m_CachedWatchHasChanged[i] = (m_CachedWatch[i] != GetWatchValue(i + 1)); - m_CachedWatch[i] = GetWatchValue(i + 1); - } + for (int i = 0; i < (int)PowerPC::watches.GetWatches().size(); ++i) + { + m_CachedWatchHasChanged[i] = (m_CachedWatch[i] != GetWatchValue(i + 1)); + m_CachedWatch[i] = GetWatchValue(i + 1); + } } wxGridCellAttr* CWatchTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind) { - wxGridCellAttr* attr = new wxGridCellAttr(); + wxGridCellAttr* attr = new wxGridCellAttr(); - attr->SetBackgroundColour(*wxWHITE); - attr->SetFont(DebuggerFont); + attr->SetBackgroundColour(*wxWHITE); + attr->SetFont(DebuggerFont); - switch (col) - { - case 1: - attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER); - break; - case 3: - case 4: - attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER); - break; - default: - attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER); - break; - } + switch (col) + { + case 1: + attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER); + break; + case 3: + case 4: + attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER); + break; + default: + attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER); + break; + } - if (row == 0) - { - attr->SetReadOnly(true); - attr->SetBackgroundColour(*wxBLACK); - attr->SetTextColour(*wxWHITE); - } - else - { - bool red = false; - if (col == 1) - red = m_CachedWatchHasChanged[row]; + if (row == 0) + { + attr->SetReadOnly(true); + attr->SetBackgroundColour(*wxBLACK); + attr->SetTextColour(*wxWHITE); + } + else + { + bool red = false; + if (col == 1) + red = m_CachedWatchHasChanged[row]; - attr->SetTextColour(red ? *wxRED : *wxBLACK); + attr->SetTextColour(red ? *wxRED : *wxBLACK); - if (row > (int)(PowerPC::watches.GetWatches().size() + 1) || !Core::IsRunning()) - { - attr->SetReadOnly(true); - attr->SetBackgroundColour(*wxLIGHT_GREY); - } - } + if (row > (int)(PowerPC::watches.GetWatches().size() + 1) || !Core::IsRunning()) + { + attr->SetReadOnly(true); + attr->SetBackgroundColour(*wxLIGHT_GREY); + } + } - return attr; + return attr; } -CWatchView::CWatchView(wxWindow* parent, wxWindowID id) - : wxGrid(parent, id) +CWatchView::CWatchView(wxWindow* parent, wxWindowID id) : wxGrid(parent, id) { - m_watch_table = new CWatchTable(); + m_watch_table = new CWatchTable(); - SetTable(m_watch_table, true); - SetRowLabelSize(0); - SetColLabelSize(0); - DisableDragRowSize(); + SetTable(m_watch_table, true); + SetRowLabelSize(0); + SetColLabelSize(0); + DisableDragRowSize(); - Bind(wxEVT_GRID_CELL_RIGHT_CLICK, &CWatchView::OnMouseDownR, this); - Bind(wxEVT_MENU, &CWatchView::OnPopupMenu, this); + Bind(wxEVT_GRID_CELL_RIGHT_CLICK, &CWatchView::OnMouseDownR, this); + Bind(wxEVT_MENU, &CWatchView::OnPopupMenu, this); } void CWatchView::Update() { - if (Core::IsRunning()) - { - m_watch_table->UpdateWatch(); - ForceRefresh(); - } + if (Core::IsRunning()) + { + m_watch_table->UpdateWatch(); + ForceRefresh(); + } } void CWatchView::OnMouseDownR(wxGridEvent& event) { - // popup menu - int row = event.GetRow(); - int col = event.GetCol(); + // popup menu + int row = event.GetRow(); + int col = event.GetCol(); - m_selectedRow = row; + m_selectedRow = row; - if (col == 1 || col == 2) - { - wxString strNewVal = GetValueByRowCol(row, col); - TryParse("0x" + WxStrToStr(strNewVal), &m_selectedAddress); - } + if (col == 1 || col == 2) + { + wxString strNewVal = GetValueByRowCol(row, col); + TryParse("0x" + WxStrToStr(strNewVal), &m_selectedAddress); + } - wxMenu menu; - if (row != 0 && row != (int)(PowerPC::watches.GetWatches().size() + 1)) - menu.Append(IDM_DELETEWATCH, _("&Delete watch")); + wxMenu menu; + if (row != 0 && row != (int)(PowerPC::watches.GetWatches().size() + 1)) + menu.Append(IDM_DELETEWATCH, _("&Delete watch")); - if (row != 0 && row != (int)(PowerPC::watches.GetWatches().size() + 1) && (col == 1 || col == 2)) - { + if (row != 0 && row != (int)(PowerPC::watches.GetWatches().size() + 1) && (col == 1 || col == 2)) + { #ifdef ENABLE_MEM_CHECK - menu.Append(IDM_ADDMEMCHECK, _("Add memory &breakpoint")); + menu.Append(IDM_ADDMEMCHECK, _("Add memory &breakpoint")); #endif - menu.Append(IDM_VIEWMEMORY, _("View &memory")); - } - PopupMenu(&menu); + menu.Append(IDM_VIEWMEMORY, _("View &memory")); + } + PopupMenu(&menu); } void CWatchView::OnPopupMenu(wxCommandEvent& event) { - CFrame* main_frame = static_cast(GetGrandParent()->GetParent()); - CCodeWindow* code_window = main_frame->g_pCodeWindow; - CWatchWindow* watch_window = code_window->m_WatchWindow; - CMemoryWindow* memory_window = code_window->m_MemoryWindow; - CBreakPointWindow* breakpoint_window = code_window->m_BreakpointWindow; + CFrame* main_frame = static_cast(GetGrandParent()->GetParent()); + CCodeWindow* code_window = main_frame->g_pCodeWindow; + CWatchWindow* watch_window = code_window->m_WatchWindow; + CMemoryWindow* memory_window = code_window->m_MemoryWindow; + CBreakPointWindow* breakpoint_window = code_window->m_BreakpointWindow; - wxString strNewVal; - TMemCheck MemCheck; + wxString strNewVal; + TMemCheck MemCheck; - switch (event.GetId()) - { - case IDM_DELETEWATCH: - strNewVal = GetValueByRowCol(m_selectedRow, 1); - if (TryParse("0x" + WxStrToStr(strNewVal), &m_selectedAddress)) - { - PowerPC::watches.Remove(m_selectedAddress); - if (watch_window) - watch_window->NotifyUpdate(); - Refresh(); - } - break; - case IDM_ADDMEMCHECK: - MemCheck.StartAddress = m_selectedAddress; - MemCheck.EndAddress = m_selectedAddress; - MemCheck.bRange = false; - MemCheck.OnRead = true; - MemCheck.OnWrite = true; - MemCheck.Log = true; - MemCheck.Break = true; - PowerPC::memchecks.Add(MemCheck); + switch (event.GetId()) + { + case IDM_DELETEWATCH: + strNewVal = GetValueByRowCol(m_selectedRow, 1); + if (TryParse("0x" + WxStrToStr(strNewVal), &m_selectedAddress)) + { + PowerPC::watches.Remove(m_selectedAddress); + if (watch_window) + watch_window->NotifyUpdate(); + Refresh(); + } + break; + case IDM_ADDMEMCHECK: + MemCheck.StartAddress = m_selectedAddress; + MemCheck.EndAddress = m_selectedAddress; + MemCheck.bRange = false; + MemCheck.OnRead = true; + MemCheck.OnWrite = true; + MemCheck.Log = true; + MemCheck.Break = true; + PowerPC::memchecks.Add(MemCheck); - if (breakpoint_window) - breakpoint_window->NotifyUpdate(); - Refresh(); - break; - case IDM_VIEWMEMORY: - if (memory_window) - memory_window->JumpToAddress(m_selectedAddress); - Refresh(); - break; - } - event.Skip(); + if (breakpoint_window) + breakpoint_window->NotifyUpdate(); + Refresh(); + break; + case IDM_VIEWMEMORY: + if (memory_window) + memory_window->JumpToAddress(m_selectedAddress); + Refresh(); + break; + } + event.Skip(); } diff --git a/Source/Core/DolphinWX/Debugger/WatchView.h b/Source/Core/DolphinWX/Debugger/WatchView.h index 2a8ebab2a9..b00c290a0b 100644 --- a/Source/Core/DolphinWX/Debugger/WatchView.h +++ b/Source/Core/DolphinWX/Debugger/WatchView.h @@ -12,41 +12,38 @@ class CWatchTable : public wxGridTableBase { - enum - { - MAX_SPECIALS = 256, - }; + enum + { + MAX_SPECIALS = 256, + }; public: - CWatchTable() - { - } - - int GetNumberCols() override { return 5; } - int GetNumberRows() override { return MAX_SPECIALS; } - wxString GetValue(int row, int col) override; - void SetValue(int row, int col, const wxString&) override; - wxGridCellAttr* GetAttr(int, int, wxGridCellAttr::wxAttrKind) override; - void UpdateWatch(); + CWatchTable() {} + int GetNumberCols() override { return 5; } + int GetNumberRows() override { return MAX_SPECIALS; } + wxString GetValue(int row, int col) override; + void SetValue(int row, int col, const wxString&) override; + wxGridCellAttr* GetAttr(int, int, wxGridCellAttr::wxAttrKind) override; + void UpdateWatch(); private: - std::array m_CachedWatch; - std::array m_CachedWatchHasChanged; + std::array m_CachedWatch; + std::array m_CachedWatchHasChanged; - DECLARE_NO_COPY_CLASS(CWatchTable); + DECLARE_NO_COPY_CLASS(CWatchTable); }; class CWatchView : public wxGrid { public: - CWatchView(wxWindow* parent, wxWindowID id = wxID_ANY); - void Update() override; + CWatchView(wxWindow* parent, wxWindowID id = wxID_ANY); + void Update() override; private: - void OnMouseDownR(wxGridEvent& event); - void OnPopupMenu(wxCommandEvent& event); + void OnMouseDownR(wxGridEvent& event); + void OnPopupMenu(wxCommandEvent& event); - u32 m_selectedAddress = 0; - u32 m_selectedRow = 0; - CWatchTable* m_watch_table; + u32 m_selectedAddress = 0; + u32 m_selectedRow = 0; + CWatchTable* m_watch_table; }; diff --git a/Source/Core/DolphinWX/Debugger/WatchWindow.cpp b/Source/Core/DolphinWX/Debugger/WatchWindow.cpp index 6e6be9bfde..915a244f48 100644 --- a/Source/Core/DolphinWX/Debugger/WatchWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/WatchWindow.cpp @@ -4,114 +4,119 @@ #include +#include #include #include -#include #include "Common/FileUtil.h" #include "Common/IniFile.h" #include "Core/ConfigManager.h" #include "Core/PowerPC/PowerPC.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/Debugger/WatchView.h" #include "DolphinWX/Debugger/WatchWindow.h" +#include "DolphinWX/WxUtils.h" class CWatchToolbar : public wxAuiToolBar { public: -CWatchToolbar(CWatchWindow* parent, const wxWindowID id) - : wxAuiToolBar(parent, id, wxDefaultPosition, wxDefaultSize, - wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_TEXT) -{ - SetToolBitmapSize(wxSize(16, 16)); + CWatchToolbar(CWatchWindow* parent, const wxWindowID id) + : wxAuiToolBar(parent, id, wxDefaultPosition, wxDefaultSize, + wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_TEXT) + { + SetToolBitmapSize(wxSize(16, 16)); - m_Bitmaps[Toolbar_File] = WxUtils::LoadResourceBitmap("toolbar_debugger_delete"); + m_Bitmaps[Toolbar_File] = WxUtils::LoadResourceBitmap("toolbar_debugger_delete"); - AddTool(ID_LOAD, _("Load"), m_Bitmaps[Toolbar_File]); - Bind(wxEVT_TOOL, &CWatchWindow::Event_LoadAll, parent, ID_LOAD); + AddTool(ID_LOAD, _("Load"), m_Bitmaps[Toolbar_File]); + Bind(wxEVT_TOOL, &CWatchWindow::Event_LoadAll, parent, ID_LOAD); - AddTool(ID_SAVE, _("Save"), m_Bitmaps[Toolbar_File]); - Bind(wxEVT_TOOL, &CWatchWindow::Event_SaveAll, parent, ID_SAVE); -} + AddTool(ID_SAVE, _("Save"), m_Bitmaps[Toolbar_File]); + Bind(wxEVT_TOOL, &CWatchWindow::Event_SaveAll, parent, ID_SAVE); + } private: + enum + { + Toolbar_File, + Num_Bitmaps + }; - enum - { - Toolbar_File, - Num_Bitmaps - }; + enum + { + ID_LOAD, + ID_SAVE + }; - enum - { - ID_LOAD, - ID_SAVE - }; - - wxBitmap m_Bitmaps[Num_Bitmaps]; + wxBitmap m_Bitmaps[Num_Bitmaps]; }; -CWatchWindow::CWatchWindow(wxWindow* parent, wxWindowID id, - const wxPoint& position, const wxSize& size, - long style, const wxString& name) - : wxPanel(parent, id, position, size, style, name) - , m_GPRGridView(nullptr) +CWatchWindow::CWatchWindow(wxWindow* parent, wxWindowID id, const wxPoint& position, + const wxSize& size, long style, const wxString& name) + : wxPanel(parent, id, position, size, style, name), m_GPRGridView(nullptr) { - m_mgr.SetManagedWindow(this); - m_mgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE); + m_mgr.SetManagedWindow(this); + m_mgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE); - m_GPRGridView = new CWatchView(this); + m_GPRGridView = new CWatchView(this); - m_mgr.AddPane(new CWatchToolbar(this, wxID_ANY), wxAuiPaneInfo().ToolbarPane().Top(). - LeftDockable(true).RightDockable(true).BottomDockable(false).Floatable(false)); - m_mgr.AddPane(m_GPRGridView, wxAuiPaneInfo().CenterPane()); - m_mgr.Update(); + m_mgr.AddPane(new CWatchToolbar(this, wxID_ANY), wxAuiPaneInfo() + .ToolbarPane() + .Top() + .LeftDockable(true) + .RightDockable(true) + .BottomDockable(false) + .Floatable(false)); + m_mgr.AddPane(m_GPRGridView, wxAuiPaneInfo().CenterPane()); + m_mgr.Update(); } CWatchWindow::~CWatchWindow() { - m_mgr.UnInit(); + m_mgr.UnInit(); } void CWatchWindow::NotifyUpdate() { - if (m_GPRGridView != nullptr) - m_GPRGridView->Update(); + if (m_GPRGridView != nullptr) + m_GPRGridView->Update(); } void CWatchWindow::Event_SaveAll(wxCommandEvent& WXUNUSED(event)) { - SaveAll(); + SaveAll(); } void CWatchWindow::SaveAll() { - IniFile ini; - ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetUniqueID() + ".ini", false); - ini.SetLines("Watches", PowerPC::watches.GetStrings()); - ini.Save(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetUniqueID() + ".ini"); + IniFile ini; + ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetUniqueID() + ".ini", + false); + ini.SetLines("Watches", PowerPC::watches.GetStrings()); + ini.Save(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetUniqueID() + ".ini"); } void CWatchWindow::Event_LoadAll(wxCommandEvent& WXUNUSED(event)) { - LoadAll(); + LoadAll(); } void CWatchWindow::LoadAll() { - IniFile ini; - Watches::TWatchesStr watches; + IniFile ini; + Watches::TWatchesStr watches; - if (!ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetUniqueID() + ".ini", false)) - { - return; - } + if (!ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetUniqueID() + + ".ini", + false)) + { + return; + } - if (ini.GetLines("Watches", &watches, false)) - { - PowerPC::watches.Clear(); - PowerPC::watches.AddFromStrings(watches); - } + if (ini.GetLines("Watches", &watches, false)) + { + PowerPC::watches.Clear(); + PowerPC::watches.AddFromStrings(watches); + } - NotifyUpdate(); + NotifyUpdate(); } diff --git a/Source/Core/DolphinWX/Debugger/WatchWindow.h b/Source/Core/DolphinWX/Debugger/WatchWindow.h index fd5ce94672..927f605c80 100644 --- a/Source/Core/DolphinWX/Debugger/WatchWindow.h +++ b/Source/Core/DolphinWX/Debugger/WatchWindow.h @@ -4,31 +4,28 @@ #pragma once -#include #include +#include class CWatchView; class CWatchWindow : public wxPanel { public: - CWatchWindow(wxWindow* parent, - wxWindowID id = wxID_ANY, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxTAB_TRAVERSAL | wxNO_BORDER, - const wxString& name = _("Watch")); - ~CWatchWindow(); + CWatchWindow(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL | wxNO_BORDER, + const wxString& name = _("Watch")); + ~CWatchWindow(); - void NotifyUpdate(); - void Event_SaveAll(wxCommandEvent& WXUNUSED(event)); - void SaveAll(); - void Event_LoadAll(wxCommandEvent& WXUNUSED(event)); - void LoadAll(); + void NotifyUpdate(); + void Event_SaveAll(wxCommandEvent& WXUNUSED(event)); + void SaveAll(); + void Event_LoadAll(wxCommandEvent& WXUNUSED(event)); + void LoadAll(); private: - wxAuiManager m_mgr; + wxAuiManager m_mgr; - // Owned by wx. Deleted implicitly upon destruction. - CWatchView* m_GPRGridView; + // Owned by wx. Deleted implicitly upon destruction. + CWatchView* m_GPRGridView; }; diff --git a/Source/Core/DolphinWX/FifoPlayerDlg.cpp b/Source/Core/DolphinWX/FifoPlayerDlg.cpp index 06138c5ec7..818b9547d2 100644 --- a/Source/Core/DolphinWX/FifoPlayerDlg.cpp +++ b/Source/Core/DolphinWX/FifoPlayerDlg.cpp @@ -40,949 +40,972 @@ wxDEFINE_EVENT(RECORDING_FINISHED_EVENT, wxCommandEvent); wxDEFINE_EVENT(FRAME_WRITTEN_EVENT, wxCommandEvent); static std::recursive_mutex sMutex; -wxEvtHandler *volatile FifoPlayerDlg::m_EvtHandler = nullptr; +wxEvtHandler* volatile FifoPlayerDlg::m_EvtHandler = nullptr; -FifoPlayerDlg::FifoPlayerDlg(wxWindow * const parent) : - wxDialog(parent, wxID_ANY, _("FIFO Player")), - m_search_result_idx(0), m_FramesToRecord(1) +FifoPlayerDlg::FifoPlayerDlg(wxWindow* const parent) + : wxDialog(parent, wxID_ANY, _("FIFO Player")), m_search_result_idx(0), m_FramesToRecord(1) { - CreateGUIControls(); + CreateGUIControls(); - sMutex.lock(); - m_EvtHandler = GetEventHandler(); - sMutex.unlock(); + sMutex.lock(); + m_EvtHandler = GetEventHandler(); + sMutex.unlock(); - FifoPlayer::GetInstance().SetFileLoadedCallback(FileLoaded); - FifoPlayer::GetInstance().SetFrameWrittenCallback(FrameWritten); + FifoPlayer::GetInstance().SetFileLoadedCallback(FileLoaded); + FifoPlayer::GetInstance().SetFrameWrittenCallback(FrameWritten); } FifoPlayerDlg::~FifoPlayerDlg() { - FifoPlayer::GetInstance().SetFrameWrittenCallback(nullptr); + FifoPlayer::GetInstance().SetFrameWrittenCallback(nullptr); - sMutex.lock(); - m_EvtHandler = nullptr; - sMutex.unlock(); + sMutex.lock(); + m_EvtHandler = nullptr; + sMutex.unlock(); } void FifoPlayerDlg::CreateGUIControls() { - wxBoxSizer* sMain; - sMain = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sMain; + sMain = new wxBoxSizer(wxVERTICAL); - m_Notebook = new wxNotebook(this, wxID_ANY); + m_Notebook = new wxNotebook(this, wxID_ANY); - { - m_PlayPage = new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); - wxBoxSizer* sPlayPage; - sPlayPage = new wxBoxSizer(wxVERTICAL); + { + m_PlayPage = + new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + wxBoxSizer* sPlayPage; + sPlayPage = new wxBoxSizer(wxVERTICAL); - wxStaticBoxSizer* sPlayInfo; - sPlayInfo = new wxStaticBoxSizer(new wxStaticBox(m_PlayPage, wxID_ANY, _("File Info")), wxVERTICAL); + wxStaticBoxSizer* sPlayInfo; + sPlayInfo = + new wxStaticBoxSizer(new wxStaticBox(m_PlayPage, wxID_ANY, _("File Info")), wxVERTICAL); - m_NumFramesLabel = new wxStaticText(m_PlayPage, wxID_ANY, wxEmptyString); - m_NumFramesLabel->Wrap(-1); - sPlayInfo->Add(m_NumFramesLabel, 0, wxALL, 5); + m_NumFramesLabel = new wxStaticText(m_PlayPage, wxID_ANY, wxEmptyString); + m_NumFramesLabel->Wrap(-1); + sPlayInfo->Add(m_NumFramesLabel, 0, wxALL, 5); - m_CurrentFrameLabel = new wxStaticText(m_PlayPage, wxID_ANY, wxEmptyString); - m_CurrentFrameLabel->Wrap(-1); - sPlayInfo->Add(m_CurrentFrameLabel, 0, wxALL, 5); + m_CurrentFrameLabel = new wxStaticText(m_PlayPage, wxID_ANY, wxEmptyString); + m_CurrentFrameLabel->Wrap(-1); + sPlayInfo->Add(m_CurrentFrameLabel, 0, wxALL, 5); - m_NumObjectsLabel = new wxStaticText(m_PlayPage, wxID_ANY, wxEmptyString); - m_NumObjectsLabel->Wrap(-1); - sPlayInfo->Add(m_NumObjectsLabel, 0, wxALL, 5); + m_NumObjectsLabel = new wxStaticText(m_PlayPage, wxID_ANY, wxEmptyString); + m_NumObjectsLabel->Wrap(-1); + sPlayInfo->Add(m_NumObjectsLabel, 0, wxALL, 5); - sPlayPage->Add(sPlayInfo, 1, wxEXPAND, 5); + sPlayPage->Add(sPlayInfo, 1, wxEXPAND, 5); - wxStaticBoxSizer* sFrameRange; - sFrameRange = new wxStaticBoxSizer(new wxStaticBox(m_PlayPage, wxID_ANY, _("Frame Range")), wxHORIZONTAL); + wxStaticBoxSizer* sFrameRange; + sFrameRange = + new wxStaticBoxSizer(new wxStaticBox(m_PlayPage, wxID_ANY, _("Frame Range")), wxHORIZONTAL); - m_FrameFromLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("From")); - m_FrameFromLabel->Wrap(-1); - sFrameRange->Add(m_FrameFromLabel, 0, wxALL, 5); + m_FrameFromLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("From")); + m_FrameFromLabel->Wrap(-1); + sFrameRange->Add(m_FrameFromLabel, 0, wxALL, 5); - m_FrameFromCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 10, 0); - sFrameRange->Add(m_FrameFromCtrl, 0, wxALL, 5); + m_FrameFromCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition, + wxDefaultSize, wxSP_ARROW_KEYS, 0, 10, 0); + sFrameRange->Add(m_FrameFromCtrl, 0, wxALL, 5); - m_FrameToLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("To")); - m_FrameToLabel->Wrap(-1); - sFrameRange->Add(m_FrameToLabel, 0, wxALL, 5); + m_FrameToLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("To")); + m_FrameToLabel->Wrap(-1); + sFrameRange->Add(m_FrameToLabel, 0, wxALL, 5); - m_FrameToCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1, -1), wxSP_ARROW_KEYS, 0, 10, 0); - sFrameRange->Add(m_FrameToCtrl, 0, wxALL, 5); + m_FrameToCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition, + wxSize(-1, -1), wxSP_ARROW_KEYS, 0, 10, 0); + sFrameRange->Add(m_FrameToCtrl, 0, wxALL, 5); - sPlayPage->Add(sFrameRange, 0, wxEXPAND, 5); + sPlayPage->Add(sFrameRange, 0, wxEXPAND, 5); - wxStaticBoxSizer* sObjectRange; - sObjectRange = new wxStaticBoxSizer(new wxStaticBox(m_PlayPage, wxID_ANY, _("Object Range")), wxHORIZONTAL); + wxStaticBoxSizer* sObjectRange; + sObjectRange = new wxStaticBoxSizer(new wxStaticBox(m_PlayPage, wxID_ANY, _("Object Range")), + wxHORIZONTAL); - m_ObjectFromLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("From")); - m_ObjectFromLabel->Wrap(-1); - sObjectRange->Add(m_ObjectFromLabel, 0, wxALL, 5); + m_ObjectFromLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("From")); + m_ObjectFromLabel->Wrap(-1); + sObjectRange->Add(m_ObjectFromLabel, 0, wxALL, 5); - m_ObjectFromCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 10000, 0); - sObjectRange->Add(m_ObjectFromCtrl, 0, wxALL, 5); + m_ObjectFromCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition, + wxDefaultSize, wxSP_ARROW_KEYS, 0, 10000, 0); + sObjectRange->Add(m_ObjectFromCtrl, 0, wxALL, 5); - m_ObjectToLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("To")); - m_ObjectToLabel->Wrap(-1); - sObjectRange->Add(m_ObjectToLabel, 0, wxALL, 5); + m_ObjectToLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("To")); + m_ObjectToLabel->Wrap(-1); + sObjectRange->Add(m_ObjectToLabel, 0, wxALL, 5); - m_ObjectToCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 10000, 0); - sObjectRange->Add(m_ObjectToCtrl, 0, wxALL, 5); + m_ObjectToCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition, + wxDefaultSize, wxSP_ARROW_KEYS, 0, 10000, 0); + sObjectRange->Add(m_ObjectToCtrl, 0, wxALL, 5); - sPlayPage->Add(sObjectRange, 0, wxEXPAND, 5); + sPlayPage->Add(sObjectRange, 0, wxEXPAND, 5); - wxStaticBoxSizer* sPlayOptions; - sPlayOptions = new wxStaticBoxSizer(new wxStaticBox(m_PlayPage, wxID_ANY, _("Playback Options")), wxVERTICAL); + wxStaticBoxSizer* sPlayOptions; + sPlayOptions = new wxStaticBoxSizer( + new wxStaticBox(m_PlayPage, wxID_ANY, _("Playback Options")), wxVERTICAL); - m_EarlyMemoryUpdates = new wxCheckBox(m_PlayPage, wxID_ANY, _("Early Memory Updates")); - sPlayOptions->Add(m_EarlyMemoryUpdates, 0, wxALL, 5); + m_EarlyMemoryUpdates = new wxCheckBox(m_PlayPage, wxID_ANY, _("Early Memory Updates")); + sPlayOptions->Add(m_EarlyMemoryUpdates, 0, wxALL, 5); - sPlayPage->Add(sPlayOptions, 0, wxEXPAND, 5); - sPlayPage->AddStretchSpacer(); + sPlayPage->Add(sPlayOptions, 0, wxEXPAND, 5); + sPlayPage->AddStretchSpacer(); - m_PlayPage->SetSizer(sPlayPage); - m_PlayPage->Layout(); - sPlayPage->Fit(m_PlayPage); - m_Notebook->AddPage(m_PlayPage, _("Play"), true); - } + m_PlayPage->SetSizer(sPlayPage); + m_PlayPage->Layout(); + sPlayPage->Fit(m_PlayPage); + m_Notebook->AddPage(m_PlayPage, _("Play"), true); + } - { - m_RecordPage = new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); - wxBoxSizer* sRecordPage; - sRecordPage = new wxBoxSizer(wxVERTICAL); + { + m_RecordPage = + new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + wxBoxSizer* sRecordPage; + sRecordPage = new wxBoxSizer(wxVERTICAL); - wxStaticBoxSizer* sRecordInfo; - sRecordInfo = new wxStaticBoxSizer(new wxStaticBox(m_RecordPage, wxID_ANY, _("Recording Info")), wxVERTICAL); + wxStaticBoxSizer* sRecordInfo; + sRecordInfo = new wxStaticBoxSizer(new wxStaticBox(m_RecordPage, wxID_ANY, _("Recording Info")), + wxVERTICAL); - m_RecordingFifoSizeLabel = new wxStaticText(m_RecordPage, wxID_ANY, wxEmptyString); - m_RecordingFifoSizeLabel->Wrap(-1); - sRecordInfo->Add(m_RecordingFifoSizeLabel, 0, wxALL, 5); + m_RecordingFifoSizeLabel = new wxStaticText(m_RecordPage, wxID_ANY, wxEmptyString); + m_RecordingFifoSizeLabel->Wrap(-1); + sRecordInfo->Add(m_RecordingFifoSizeLabel, 0, wxALL, 5); - m_RecordingMemSizeLabel = new wxStaticText(m_RecordPage, wxID_ANY, wxEmptyString); - m_RecordingMemSizeLabel->Wrap(-1); - sRecordInfo->Add(m_RecordingMemSizeLabel, 0, wxALL, 5); + m_RecordingMemSizeLabel = new wxStaticText(m_RecordPage, wxID_ANY, wxEmptyString); + m_RecordingMemSizeLabel->Wrap(-1); + sRecordInfo->Add(m_RecordingMemSizeLabel, 0, wxALL, 5); - m_RecordingFramesLabel = new wxStaticText(m_RecordPage, wxID_ANY, wxEmptyString); - m_RecordingFramesLabel->Wrap(-1); - sRecordInfo->Add(m_RecordingFramesLabel, 0, wxALL, 5); + m_RecordingFramesLabel = new wxStaticText(m_RecordPage, wxID_ANY, wxEmptyString); + m_RecordingFramesLabel->Wrap(-1); + sRecordInfo->Add(m_RecordingFramesLabel, 0, wxALL, 5); - sRecordPage->Add(sRecordInfo, 0, wxEXPAND, 5); + sRecordPage->Add(sRecordInfo, 0, wxEXPAND, 5); - wxBoxSizer* sRecordButtons; - sRecordButtons = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sRecordButtons; + sRecordButtons = new wxBoxSizer(wxHORIZONTAL); - m_RecordStop = new wxButton(m_RecordPage, wxID_ANY, _("Record")); - sRecordButtons->Add(m_RecordStop, 0, wxALL, 5); + m_RecordStop = new wxButton(m_RecordPage, wxID_ANY, _("Record")); + sRecordButtons->Add(m_RecordStop, 0, wxALL, 5); - m_Save = new wxButton(m_RecordPage, wxID_ANY, _("Save")); - sRecordButtons->Add(m_Save, 0, wxALL, 5); + m_Save = new wxButton(m_RecordPage, wxID_ANY, _("Save")); + sRecordButtons->Add(m_Save, 0, wxALL, 5); - sRecordPage->Add(sRecordButtons, 0, wxEXPAND, 5); + sRecordPage->Add(sRecordButtons, 0, wxEXPAND, 5); - wxStaticBoxSizer* sRecordingOptions; - sRecordingOptions = new wxStaticBoxSizer(new wxStaticBox(m_RecordPage, wxID_ANY, _("Recording Options")), wxHORIZONTAL); + wxStaticBoxSizer* sRecordingOptions; + sRecordingOptions = new wxStaticBoxSizer( + new wxStaticBox(m_RecordPage, wxID_ANY, _("Recording Options")), wxHORIZONTAL); - m_FramesToRecordLabel = new wxStaticText(m_RecordPage, wxID_ANY, _("Frames To Record")); - m_FramesToRecordLabel->Wrap(-1); - sRecordingOptions->Add(m_FramesToRecordLabel, 0, wxALL, 5); + m_FramesToRecordLabel = new wxStaticText(m_RecordPage, wxID_ANY, _("Frames To Record")); + m_FramesToRecordLabel->Wrap(-1); + sRecordingOptions->Add(m_FramesToRecordLabel, 0, wxALL, 5); - wxString initialNum = wxString::Format("%d", m_FramesToRecord); - m_FramesToRecordCtrl = new wxSpinCtrl(m_RecordPage, wxID_ANY, initialNum, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 10000, 1); - sRecordingOptions->Add(m_FramesToRecordCtrl, 0, wxALL, 5); + wxString initialNum = wxString::Format("%d", m_FramesToRecord); + m_FramesToRecordCtrl = new wxSpinCtrl(m_RecordPage, wxID_ANY, initialNum, wxDefaultPosition, + wxDefaultSize, wxSP_ARROW_KEYS, 0, 10000, 1); + sRecordingOptions->Add(m_FramesToRecordCtrl, 0, wxALL, 5); - sRecordPage->Add(sRecordingOptions, 0, wxEXPAND, 5); - sRecordPage->AddStretchSpacer(); + sRecordPage->Add(sRecordingOptions, 0, wxEXPAND, 5); + sRecordPage->AddStretchSpacer(); - m_RecordPage->SetSizer(sRecordPage); - m_RecordPage->Layout(); - sRecordPage->Fit(m_RecordPage); - m_Notebook->AddPage(m_RecordPage, _("Record"), false); - } + m_RecordPage->SetSizer(sRecordPage); + m_RecordPage->Layout(); + sRecordPage->Fit(m_RecordPage); + m_Notebook->AddPage(m_RecordPage, _("Record"), false); + } - // Analyze page - { - m_AnalyzePage = new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); - wxBoxSizer* sAnalyzePage; - sAnalyzePage = new wxBoxSizer(wxVERTICAL); + // Analyze page + { + m_AnalyzePage = + new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + wxBoxSizer* sAnalyzePage; + sAnalyzePage = new wxBoxSizer(wxVERTICAL); - wxStaticBoxSizer* sFrameInfoSizer; - sFrameInfoSizer = new wxStaticBoxSizer(new wxStaticBox(m_AnalyzePage, wxID_ANY, _("Frame Info")), wxVERTICAL); + wxStaticBoxSizer* sFrameInfoSizer; + sFrameInfoSizer = + new wxStaticBoxSizer(new wxStaticBox(m_AnalyzePage, wxID_ANY, _("Frame Info")), wxVERTICAL); - wxBoxSizer* sListsSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sListsSizer = new wxBoxSizer(wxHORIZONTAL); - m_framesList = new wxListBox(m_AnalyzePage, wxID_ANY); - m_framesList->SetMinSize(wxSize(100, 250)); - sListsSizer->Add(m_framesList, 0, wxALL, 5); + m_framesList = new wxListBox(m_AnalyzePage, wxID_ANY); + m_framesList->SetMinSize(wxSize(100, 250)); + sListsSizer->Add(m_framesList, 0, wxALL, 5); - m_objectsList = new wxListBox(m_AnalyzePage, wxID_ANY); - m_objectsList->SetMinSize(wxSize(110, 250)); - sListsSizer->Add(m_objectsList, 0, wxALL, 5); + m_objectsList = new wxListBox(m_AnalyzePage, wxID_ANY); + m_objectsList->SetMinSize(wxSize(110, 250)); + sListsSizer->Add(m_objectsList, 0, wxALL, 5); - m_objectCmdList = new wxListBox(m_AnalyzePage, wxID_ANY); - m_objectCmdList->SetMinSize(wxSize(175, 250)); - sListsSizer->Add(m_objectCmdList, 0, wxALL, 5); + m_objectCmdList = new wxListBox(m_AnalyzePage, wxID_ANY); + m_objectCmdList->SetMinSize(wxSize(175, 250)); + sListsSizer->Add(m_objectCmdList, 0, wxALL, 5); - sFrameInfoSizer->Add(sListsSizer, 0, wxALL, 5); + sFrameInfoSizer->Add(sListsSizer, 0, wxALL, 5); - m_objectCmdInfo = new wxStaticText(m_AnalyzePage, wxID_ANY, wxString()); - sFrameInfoSizer->Add(m_objectCmdInfo, 0, wxALL, 5); + m_objectCmdInfo = new wxStaticText(m_AnalyzePage, wxID_ANY, wxString()); + sFrameInfoSizer->Add(m_objectCmdInfo, 0, wxALL, 5); - sAnalyzePage->Add(sFrameInfoSizer, 0, wxEXPAND, 5); + sAnalyzePage->Add(sFrameInfoSizer, 0, wxEXPAND, 5); - wxStaticBoxSizer* sSearchSizer = new wxStaticBoxSizer(new wxStaticBox(m_AnalyzePage, wxID_ANY, _("Search current Object")), wxVERTICAL); + wxStaticBoxSizer* sSearchSizer = new wxStaticBoxSizer( + new wxStaticBox(m_AnalyzePage, wxID_ANY, _("Search current Object")), wxVERTICAL); - wxBoxSizer* sSearchField = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sSearchField = new wxBoxSizer(wxHORIZONTAL); - sSearchField->Add(new wxStaticText(m_AnalyzePage, wxID_ANY, _("Search for hex Value:")), 0, wxALIGN_CENTER_VERTICAL, 5); - // TODO: ugh, wxValidator sucks - but we should use it anyway. - m_searchField = new wxTextCtrl(m_AnalyzePage, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); - m_numResultsText = new wxStaticText(m_AnalyzePage, wxID_ANY, wxEmptyString); + sSearchField->Add(new wxStaticText(m_AnalyzePage, wxID_ANY, _("Search for hex Value:")), 0, + wxALIGN_CENTER_VERTICAL, 5); + // TODO: ugh, wxValidator sucks - but we should use it anyway. + m_searchField = new wxTextCtrl(m_AnalyzePage, wxID_ANY, wxEmptyString, wxDefaultPosition, + wxDefaultSize, wxTE_PROCESS_ENTER); + m_numResultsText = new wxStaticText(m_AnalyzePage, wxID_ANY, wxEmptyString); - sSearchField->Add(m_searchField, 0, wxALL, 5); - sSearchField->Add(m_numResultsText, 0, wxALIGN_CENTER_VERTICAL, 5); + sSearchField->Add(m_searchField, 0, wxALL, 5); + sSearchField->Add(m_numResultsText, 0, wxALIGN_CENTER_VERTICAL, 5); - wxBoxSizer* sSearchButtons = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sSearchButtons = new wxBoxSizer(wxHORIZONTAL); - m_beginSearch = new wxButton(m_AnalyzePage, wxID_ANY, _("Search")); - m_findNext = new wxButton(m_AnalyzePage, wxID_ANY, _("Find next")); - m_findPrevious = new wxButton(m_AnalyzePage, wxID_ANY, _("Find previous")); + m_beginSearch = new wxButton(m_AnalyzePage, wxID_ANY, _("Search")); + m_findNext = new wxButton(m_AnalyzePage, wxID_ANY, _("Find next")); + m_findPrevious = new wxButton(m_AnalyzePage, wxID_ANY, _("Find previous")); - ResetSearch(); + ResetSearch(); - sSearchButtons->Add(m_beginSearch, 0, wxALL, 5); - sSearchButtons->Add(m_findNext, 0, wxALL, 5); - sSearchButtons->Add(m_findPrevious, 0, wxALL, 5); + sSearchButtons->Add(m_beginSearch, 0, wxALL, 5); + sSearchButtons->Add(m_findNext, 0, wxALL, 5); + sSearchButtons->Add(m_findPrevious, 0, wxALL, 5); - sSearchSizer->Add(sSearchField, 0, wxEXPAND, 5); - sSearchSizer->Add(sSearchButtons, 0, wxEXPAND, 5); + sSearchSizer->Add(sSearchField, 0, wxEXPAND, 5); + sSearchSizer->Add(sSearchButtons, 0, wxEXPAND, 5); - sAnalyzePage->Add(sSearchSizer, 0, wxEXPAND, 5); - sAnalyzePage->AddStretchSpacer(); + sAnalyzePage->Add(sSearchSizer, 0, wxEXPAND, 5); + sAnalyzePage->AddStretchSpacer(); - m_AnalyzePage->SetSizer(sAnalyzePage); - m_AnalyzePage->Layout(); - sAnalyzePage->Fit(m_AnalyzePage); - m_Notebook->AddPage(m_AnalyzePage, _("Analyze"), false); - } + m_AnalyzePage->SetSizer(sAnalyzePage); + m_AnalyzePage->Layout(); + sAnalyzePage->Fit(m_AnalyzePage); + m_Notebook->AddPage(m_AnalyzePage, _("Analyze"), false); + } - sMain->Add(m_Notebook, 1, wxEXPAND | wxALL, 5); + sMain->Add(m_Notebook, 1, wxEXPAND | wxALL, 5); - wxBoxSizer* sButtons; - sButtons = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sButtons; + sButtons = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sCloseButtonExpander; - sCloseButtonExpander = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sCloseButtonExpander; + sCloseButtonExpander = new wxBoxSizer(wxHORIZONTAL); - sButtons->Add(sCloseButtonExpander, 1, wxEXPAND, 5); + sButtons->Add(sCloseButtonExpander, 1, wxEXPAND, 5); - m_Close = new wxButton(this, wxID_ANY, _("Close")); - sButtons->Add(m_Close, 0, wxALL, 5); + m_Close = new wxButton(this, wxID_ANY, _("Close")); + sButtons->Add(m_Close, 0, wxALL, 5); - sMain->Add(sButtons, 0, wxEXPAND, 5); + sMain->Add(sButtons, 0, wxEXPAND, 5); - SetSizer(sMain); - Layout(); - sMain->Fit(this); + SetSizer(sMain); + Layout(); + sMain->Fit(this); - Center(wxBOTH); + Center(wxBOTH); - // Connect Events - Bind(wxEVT_PAINT, &FifoPlayerDlg::OnPaint, this); - m_FrameFromCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnFrameFrom, this); - m_FrameToCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnFrameTo, this); - m_ObjectFromCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnObjectFrom, this); - m_ObjectToCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnObjectTo, this); - m_EarlyMemoryUpdates->Bind(wxEVT_CHECKBOX, &FifoPlayerDlg::OnCheckEarlyMemoryUpdates, this); - m_RecordStop->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnRecordStop, this); - m_Save->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnSaveFile, this); - m_FramesToRecordCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnNumFramesToRecord, this); - Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnCloseClick, this); + // Connect Events + Bind(wxEVT_PAINT, &FifoPlayerDlg::OnPaint, this); + m_FrameFromCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnFrameFrom, this); + m_FrameToCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnFrameTo, this); + m_ObjectFromCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnObjectFrom, this); + m_ObjectToCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnObjectTo, this); + m_EarlyMemoryUpdates->Bind(wxEVT_CHECKBOX, &FifoPlayerDlg::OnCheckEarlyMemoryUpdates, this); + m_RecordStop->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnRecordStop, this); + m_Save->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnSaveFile, this); + m_FramesToRecordCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnNumFramesToRecord, this); + Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnCloseClick, this); - m_framesList->Bind(wxEVT_LISTBOX, &FifoPlayerDlg::OnFrameListSelectionChanged, this); - m_objectsList->Bind(wxEVT_LISTBOX, &FifoPlayerDlg::OnObjectListSelectionChanged, this); - m_objectCmdList->Bind(wxEVT_LISTBOX, &FifoPlayerDlg::OnObjectCmdListSelectionChanged, this); + m_framesList->Bind(wxEVT_LISTBOX, &FifoPlayerDlg::OnFrameListSelectionChanged, this); + m_objectsList->Bind(wxEVT_LISTBOX, &FifoPlayerDlg::OnObjectListSelectionChanged, this); + m_objectCmdList->Bind(wxEVT_LISTBOX, &FifoPlayerDlg::OnObjectCmdListSelectionChanged, this); - m_beginSearch->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnBeginSearch, this); - m_findNext->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnFindNextClick, this); - m_findPrevious->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnFindPreviousClick, this); + m_beginSearch->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnBeginSearch, this); + m_findNext->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnFindNextClick, this); + m_findPrevious->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnFindPreviousClick, this); - m_searchField->Bind(wxEVT_TEXT_ENTER, &FifoPlayerDlg::OnBeginSearch, this); - m_searchField->Bind(wxEVT_TEXT, &FifoPlayerDlg::OnSearchFieldTextChanged, this); + m_searchField->Bind(wxEVT_TEXT_ENTER, &FifoPlayerDlg::OnBeginSearch, this); + m_searchField->Bind(wxEVT_TEXT, &FifoPlayerDlg::OnSearchFieldTextChanged, this); - // Setup command copying - wxAcceleratorEntry entry; - entry.Set(wxACCEL_CTRL, (int)'C', wxID_COPY); - wxAcceleratorTable accel(1, &entry); - m_objectCmdList->SetAcceleratorTable(accel); - m_objectCmdList->Bind(wxEVT_MENU, &FifoPlayerDlg::OnObjectCmdListSelectionCopy, this, wxID_COPY); + // Setup command copying + wxAcceleratorEntry entry; + entry.Set(wxACCEL_CTRL, (int)'C', wxID_COPY); + wxAcceleratorTable accel(1, &entry); + m_objectCmdList->SetAcceleratorTable(accel); + m_objectCmdList->Bind(wxEVT_MENU, &FifoPlayerDlg::OnObjectCmdListSelectionCopy, this, wxID_COPY); - Bind(RECORDING_FINISHED_EVENT, &FifoPlayerDlg::OnRecordingFinished, this); - Bind(FRAME_WRITTEN_EVENT, &FifoPlayerDlg::OnFrameWritten, this); + Bind(RECORDING_FINISHED_EVENT, &FifoPlayerDlg::OnRecordingFinished, this); + Bind(FRAME_WRITTEN_EVENT, &FifoPlayerDlg::OnFrameWritten, this); - Show(); + Show(); } void FifoPlayerDlg::OnPaint(wxPaintEvent& event) { - UpdatePlayGui(); - UpdateRecorderGui(); - UpdateAnalyzerGui(); + UpdatePlayGui(); + UpdateRecorderGui(); + UpdateAnalyzerGui(); - event.Skip(); + event.Skip(); } void FifoPlayerDlg::OnFrameFrom(wxSpinEvent& event) { - FifoPlayer &player = FifoPlayer::GetInstance(); + FifoPlayer& player = FifoPlayer::GetInstance(); - player.SetFrameRangeStart(event.GetPosition()); + player.SetFrameRangeStart(event.GetPosition()); - m_FrameFromCtrl->SetValue(player.GetFrameRangeStart()); - m_FrameToCtrl->SetValue(player.GetFrameRangeEnd()); + m_FrameFromCtrl->SetValue(player.GetFrameRangeStart()); + m_FrameToCtrl->SetValue(player.GetFrameRangeEnd()); } void FifoPlayerDlg::OnFrameTo(wxSpinEvent& event) { - FifoPlayer &player = FifoPlayer::GetInstance(); - player.SetFrameRangeEnd(event.GetPosition()); + FifoPlayer& player = FifoPlayer::GetInstance(); + player.SetFrameRangeEnd(event.GetPosition()); - m_FrameFromCtrl->SetValue(player.GetFrameRangeStart()); - m_FrameToCtrl->SetValue(player.GetFrameRangeEnd()); + m_FrameFromCtrl->SetValue(player.GetFrameRangeStart()); + m_FrameToCtrl->SetValue(player.GetFrameRangeEnd()); } void FifoPlayerDlg::OnObjectFrom(wxSpinEvent& event) { - FifoPlayer::GetInstance().SetObjectRangeStart(event.GetPosition()); + FifoPlayer::GetInstance().SetObjectRangeStart(event.GetPosition()); } void FifoPlayerDlg::OnObjectTo(wxSpinEvent& event) { - FifoPlayer::GetInstance().SetObjectRangeEnd(event.GetPosition()); + FifoPlayer::GetInstance().SetObjectRangeEnd(event.GetPosition()); } void FifoPlayerDlg::OnCheckEarlyMemoryUpdates(wxCommandEvent& event) { - FifoPlayer::GetInstance().SetEarlyMemoryUpdates(event.IsChecked()); + FifoPlayer::GetInstance().SetEarlyMemoryUpdates(event.IsChecked()); } void FifoPlayerDlg::OnSaveFile(wxCommandEvent& WXUNUSED(event)) { - // Pointer to the file data that was created as a result of recording. - FifoDataFile *file = FifoRecorder::GetInstance().GetRecordedFile(); + // Pointer to the file data that was created as a result of recording. + FifoDataFile* file = FifoRecorder::GetInstance().GetRecordedFile(); - if (file) - { - // Bring up a save file dialog. The location the user chooses will be assigned to this variable. - wxString path = wxSaveFileSelector(_("Dolphin FIFO"), "dff", wxEmptyString, this); + if (file) + { + // Bring up a save file dialog. The location the user chooses will be assigned to this variable. + wxString path = wxSaveFileSelector(_("Dolphin FIFO"), "dff", wxEmptyString, this); - // Has a valid file path - if (!path.empty()) - { - // Attempt to save the file to the path the user chose - wxBeginBusyCursor(); - bool result = file->Save(WxStrToStr(path)); - wxEndBusyCursor(); + // Has a valid file path + if (!path.empty()) + { + // Attempt to save the file to the path the user chose + wxBeginBusyCursor(); + bool result = file->Save(WxStrToStr(path)); + wxEndBusyCursor(); - // Wasn't able to save the file, shit's whack, yo. - if (!result) - WxUtils::ShowErrorDialog(_("Error saving file.")); - } - } + // Wasn't able to save the file, shit's whack, yo. + if (!result) + WxUtils::ShowErrorDialog(_("Error saving file.")); + } + } } void FifoPlayerDlg::OnRecordStop(wxCommandEvent& WXUNUSED(event)) { - FifoRecorder& recorder = FifoRecorder::GetInstance(); + FifoRecorder& recorder = FifoRecorder::GetInstance(); - // Recorder is still recording - if (recorder.IsRecording()) - { - // Then stop recording - recorder.StopRecording(); + // Recorder is still recording + if (recorder.IsRecording()) + { + // Then stop recording + recorder.StopRecording(); - // and change the button label accordingly. - m_RecordStop->SetLabel(_("Record")); - } - else // Recorder is actually about to start recording - { - // So start recording - recorder.StartRecording(m_FramesToRecord, RecordingFinished); + // and change the button label accordingly. + m_RecordStop->SetLabel(_("Record")); + } + else // Recorder is actually about to start recording + { + // So start recording + recorder.StartRecording(m_FramesToRecord, RecordingFinished); - // and change the button label accordingly. - m_RecordStop->SetLabel(_("Stop")); - } + // and change the button label accordingly. + m_RecordStop->SetLabel(_("Stop")); + } } void FifoPlayerDlg::OnNumFramesToRecord(wxSpinEvent& event) { - m_FramesToRecord = event.GetPosition(); + m_FramesToRecord = event.GetPosition(); - // Entering 0 frames in the control indicates infinite frames to record - // The fifo recorder takes any value < 0 to be infinite frames - if (m_FramesToRecord < 1) - m_FramesToRecord = -1; + // Entering 0 frames in the control indicates infinite frames to record + // The fifo recorder takes any value < 0 to be infinite frames + if (m_FramesToRecord < 1) + m_FramesToRecord = -1; } void FifoPlayerDlg::OnBeginSearch(wxCommandEvent& event) { - wxString str_search_val = m_searchField->GetValue(); + wxString str_search_val = m_searchField->GetValue(); - if (m_framesList->GetSelection() == -1) - return; + if (m_framesList->GetSelection() == -1) + return; - // TODO: Limited to even str lengths... - if (!str_search_val.empty() && str_search_val.length() % 2) - { - m_numResultsText->SetLabel(_("Invalid search string (only even string lengths supported)")); - return; - } + // TODO: Limited to even str lengths... + if (!str_search_val.empty() && str_search_val.length() % 2) + { + m_numResultsText->SetLabel(_("Invalid search string (only even string lengths supported)")); + return; + } - unsigned int const val_length = str_search_val.length() / 2; - std::vector search_val(val_length); - for (unsigned int i = 0; i < val_length; ++i) - { - wxString char_str = str_search_val.Mid(2*i, 2); - unsigned long val = 0; - if (!char_str.ToULong(&val, 16)) - { - m_numResultsText->SetLabel(_("Invalid search string (couldn't convert to number)")); - return; - } - search_val[i] = (u8)val; - } - search_results.clear(); + unsigned int const val_length = str_search_val.length() / 2; + std::vector search_val(val_length); + for (unsigned int i = 0; i < val_length; ++i) + { + wxString char_str = str_search_val.Mid(2 * i, 2); + unsigned long val = 0; + if (!char_str.ToULong(&val, 16)) + { + m_numResultsText->SetLabel(_("Invalid search string (couldn't convert to number)")); + return; + } + search_val[i] = (u8)val; + } + search_results.clear(); - int const frame_idx = m_framesList->GetSelection(); - FifoPlayer& player = FifoPlayer::GetInstance(); - const AnalyzedFrameInfo& frame = player.GetAnalyzedFrameInfo(frame_idx); - const FifoFrameInfo& fifo_frame = player.GetFile()->GetFrame(frame_idx); + int const frame_idx = m_framesList->GetSelection(); + FifoPlayer& player = FifoPlayer::GetInstance(); + const AnalyzedFrameInfo& frame = player.GetAnalyzedFrameInfo(frame_idx); + const FifoFrameInfo& fifo_frame = player.GetFile()->GetFrame(frame_idx); - // TODO: Support searching through the last object... How do we know were the cmd data ends? - // TODO: Support searching for bit patterns - int obj_idx = m_objectsList->GetSelection(); - if (obj_idx == -1) - { - m_numResultsText->SetLabel(_("Invalid search parameters (no object selected)")); - return; - } + // TODO: Support searching through the last object... How do we know were the cmd data ends? + // TODO: Support searching for bit patterns + int obj_idx = m_objectsList->GetSelection(); + if (obj_idx == -1) + { + m_numResultsText->SetLabel(_("Invalid search parameters (no object selected)")); + return; + } - const u8* const start_ptr = &fifo_frame.fifoData[frame.objectStarts[obj_idx]]; - const u8* const end_ptr = &fifo_frame.fifoData[frame.objectStarts[obj_idx + 1]]; + const u8* const start_ptr = &fifo_frame.fifoData[frame.objectStarts[obj_idx]]; + const u8* const end_ptr = &fifo_frame.fifoData[frame.objectStarts[obj_idx + 1]]; - for (const u8* ptr = start_ptr; ptr < end_ptr - val_length + 1; ++ptr) - { - if (std::equal(search_val.begin(), search_val.end(), ptr)) - { - SearchResult result; - result.frame_idx = frame_idx; + for (const u8* ptr = start_ptr; ptr < end_ptr - val_length + 1; ++ptr) + { + if (std::equal(search_val.begin(), search_val.end(), ptr)) + { + SearchResult result; + result.frame_idx = frame_idx; - result.obj_idx = m_objectsList->GetSelection(); - result.cmd_idx = 0; - for (unsigned int cmd_idx = 1; cmd_idx < m_objectCmdOffsets.size(); ++cmd_idx) - { - if (ptr < start_ptr + m_objectCmdOffsets[cmd_idx]) - { - result.cmd_idx = cmd_idx - 1; - break; - } - } - search_results.push_back(result); - } - } + result.obj_idx = m_objectsList->GetSelection(); + result.cmd_idx = 0; + for (unsigned int cmd_idx = 1; cmd_idx < m_objectCmdOffsets.size(); ++cmd_idx) + { + if (ptr < start_ptr + m_objectCmdOffsets[cmd_idx]) + { + result.cmd_idx = cmd_idx - 1; + break; + } + } + search_results.push_back(result); + } + } - ChangeSearchResult(0); - m_beginSearch->Disable(); - m_numResultsText->SetLabel(wxString::Format(_("Found %u results for \'"), (u32)search_results.size()) + m_searchField->GetValue() + "\'"); + ChangeSearchResult(0); + m_beginSearch->Disable(); + m_numResultsText->SetLabel( + wxString::Format(_("Found %u results for \'"), (u32)search_results.size()) + + m_searchField->GetValue() + "\'"); } void FifoPlayerDlg::OnSearchFieldTextChanged(wxCommandEvent& event) { - ResetSearch(); + ResetSearch(); } void FifoPlayerDlg::OnFindNextClick(wxCommandEvent& event) { - int cur_cmd_index = m_objectCmdList->GetSelection(); - if (cur_cmd_index == -1) - { - ChangeSearchResult(0); - return; - } + int cur_cmd_index = m_objectCmdList->GetSelection(); + if (cur_cmd_index == -1) + { + ChangeSearchResult(0); + return; + } - for (auto it = search_results.begin(); it != search_results.end(); ++it) - { - if (it->cmd_idx > cur_cmd_index) - { - ChangeSearchResult(it - search_results.begin()); - return; - } - } + for (auto it = search_results.begin(); it != search_results.end(); ++it) + { + if (it->cmd_idx > cur_cmd_index) + { + ChangeSearchResult(it - search_results.begin()); + return; + } + } } void FifoPlayerDlg::OnFindPreviousClick(wxCommandEvent& event) { - int cur_cmd_index = m_objectCmdList->GetSelection(); - if (cur_cmd_index == -1) - { - ChangeSearchResult(search_results.size() - 1); - return; - } + int cur_cmd_index = m_objectCmdList->GetSelection(); + if (cur_cmd_index == -1) + { + ChangeSearchResult(search_results.size() - 1); + return; + } - for (auto it = search_results.rbegin(); it != search_results.rend(); ++it) - { - if (it->cmd_idx < cur_cmd_index) - { - ChangeSearchResult(search_results.size() - 1 - (it - search_results.rbegin())); - return; - } - } + for (auto it = search_results.rbegin(); it != search_results.rend(); ++it) + { + if (it->cmd_idx < cur_cmd_index) + { + ChangeSearchResult(search_results.size() - 1 - (it - search_results.rbegin())); + return; + } + } } void FifoPlayerDlg::ChangeSearchResult(unsigned int result_idx) { - if (result_idx < search_results.size()) // if index is valid - { - m_search_result_idx = result_idx; - int prev_frame = m_framesList->GetSelection(); - int prev_obj = m_objectsList->GetSelection(); - int prev_cmd = m_objectCmdList->GetSelection(); - m_framesList->SetSelection(search_results[result_idx].frame_idx); - m_objectsList->SetSelection(search_results[result_idx].obj_idx); - m_objectCmdList->SetSelection(search_results[result_idx].cmd_idx); + if (result_idx < search_results.size()) // if index is valid + { + m_search_result_idx = result_idx; + int prev_frame = m_framesList->GetSelection(); + int prev_obj = m_objectsList->GetSelection(); + int prev_cmd = m_objectCmdList->GetSelection(); + m_framesList->SetSelection(search_results[result_idx].frame_idx); + m_objectsList->SetSelection(search_results[result_idx].obj_idx); + m_objectCmdList->SetSelection(search_results[result_idx].cmd_idx); - wxCommandEvent ev(wxEVT_LISTBOX); - if (prev_frame != m_framesList->GetSelection()) - { - ev.SetInt(m_framesList->GetSelection()); - OnFrameListSelectionChanged(ev); - } - if (prev_obj != m_objectsList->GetSelection()) - { - ev.SetInt(m_objectsList->GetSelection()); - OnObjectListSelectionChanged(ev); - } - if (prev_cmd != m_objectCmdList->GetSelection()) - { - ev.SetInt(m_objectCmdList->GetSelection()); - OnObjectCmdListSelectionChanged(ev); - } + wxCommandEvent ev(wxEVT_LISTBOX); + if (prev_frame != m_framesList->GetSelection()) + { + ev.SetInt(m_framesList->GetSelection()); + OnFrameListSelectionChanged(ev); + } + if (prev_obj != m_objectsList->GetSelection()) + { + ev.SetInt(m_objectsList->GetSelection()); + OnObjectListSelectionChanged(ev); + } + if (prev_cmd != m_objectCmdList->GetSelection()) + { + ev.SetInt(m_objectCmdList->GetSelection()); + OnObjectCmdListSelectionChanged(ev); + } - m_findNext->Enable(result_idx + 1 < search_results.size()); - m_findPrevious->Enable(result_idx != 0); - } - else if (search_results.size()) - { - ChangeSearchResult(search_results.size() - 1); - } + m_findNext->Enable(result_idx + 1 < search_results.size()); + m_findPrevious->Enable(result_idx != 0); + } + else if (search_results.size()) + { + ChangeSearchResult(search_results.size() - 1); + } } void FifoPlayerDlg::ResetSearch() { - m_beginSearch->Enable(m_searchField->GetLineLength(0) > 0); - m_findNext->Disable(); - m_findPrevious->Disable(); + m_beginSearch->Enable(m_searchField->GetLineLength(0) > 0); + m_findNext->Disable(); + m_findPrevious->Disable(); - search_results.clear(); + search_results.clear(); } void FifoPlayerDlg::OnFrameListSelectionChanged(wxCommandEvent& event) { - FifoPlayer& player = FifoPlayer::GetInstance(); + FifoPlayer& player = FifoPlayer::GetInstance(); - m_objectsList->Clear(); - if (event.GetInt() != -1) - { - size_t num_objects = player.GetAnalyzedFrameInfo(event.GetInt()).objectStarts.size(); - for (size_t i = 0; i < num_objects; ++i) - m_objectsList->Append(wxString::Format(_("Object %zu"), i)); - } + m_objectsList->Clear(); + if (event.GetInt() != -1) + { + size_t num_objects = player.GetAnalyzedFrameInfo(event.GetInt()).objectStarts.size(); + for (size_t i = 0; i < num_objects; ++i) + m_objectsList->Append(wxString::Format(_("Object %zu"), i)); + } - // Update object list - wxCommandEvent ev = wxCommandEvent(wxEVT_LISTBOX); - ev.SetInt(-1); - OnObjectListSelectionChanged(ev); + // Update object list + wxCommandEvent ev = wxCommandEvent(wxEVT_LISTBOX); + ev.SetInt(-1); + OnObjectListSelectionChanged(ev); - ResetSearch(); + ResetSearch(); } void FifoPlayerDlg::OnObjectListSelectionChanged(wxCommandEvent& event) { - FifoPlayer& player = FifoPlayer::GetInstance(); + FifoPlayer& player = FifoPlayer::GetInstance(); - int frame_idx = m_framesList->GetSelection(); - int object_idx = event.GetInt(); + int frame_idx = m_framesList->GetSelection(); + int object_idx = event.GetInt(); - m_objectCmdList->Clear(); - m_objectCmdOffsets.clear(); - if (frame_idx != -1 && object_idx != -1) - { - const AnalyzedFrameInfo& frame = player.GetAnalyzedFrameInfo(frame_idx); - const FifoFrameInfo& fifo_frame = player.GetFile()->GetFrame(frame_idx); - const u8* objectdata_start = &fifo_frame.fifoData[frame.objectStarts[object_idx]]; - const u8* objectdata_end = &fifo_frame.fifoData[frame.objectEnds[object_idx]]; - u8* objectdata = (u8*)objectdata_start; - const int obj_offset = objectdata_start - &fifo_frame.fifoData[frame.objectStarts[0]]; + m_objectCmdList->Clear(); + m_objectCmdOffsets.clear(); + if (frame_idx != -1 && object_idx != -1) + { + const AnalyzedFrameInfo& frame = player.GetAnalyzedFrameInfo(frame_idx); + const FifoFrameInfo& fifo_frame = player.GetFile()->GetFrame(frame_idx); + const u8* objectdata_start = &fifo_frame.fifoData[frame.objectStarts[object_idx]]; + const u8* objectdata_end = &fifo_frame.fifoData[frame.objectEnds[object_idx]]; + u8* objectdata = (u8*)objectdata_start; + const int obj_offset = objectdata_start - &fifo_frame.fifoData[frame.objectStarts[0]]; - int cmd = *objectdata++; - int stream_size = Common::swap16(objectdata); - objectdata += 2; - wxString newLabel = wxString::Format("%08X: %02X %04X ", obj_offset, cmd, stream_size); - if (stream_size && ((objectdata_end - objectdata) % stream_size)) - newLabel += _("NOTE: Stream size doesn't match actual data length\n"); + int cmd = *objectdata++; + int stream_size = Common::swap16(objectdata); + objectdata += 2; + wxString newLabel = wxString::Format("%08X: %02X %04X ", obj_offset, cmd, stream_size); + if (stream_size && ((objectdata_end - objectdata) % stream_size)) + newLabel += _("NOTE: Stream size doesn't match actual data length\n"); - while (objectdata < objectdata_end) - { - newLabel += wxString::Format("%02X", *objectdata++); - } - m_objectCmdList->Append(newLabel); - m_objectCmdOffsets.push_back(0); + while (objectdata < objectdata_end) + { + newLabel += wxString::Format("%02X", *objectdata++); + } + m_objectCmdList->Append(newLabel); + m_objectCmdOffsets.push_back(0); + // Between objectdata_end and next_objdata_start, there are register setting commands + if (object_idx + 1 < (int)frame.objectStarts.size()) + { + const u8* next_objdata_start = &fifo_frame.fifoData[frame.objectStarts[object_idx + 1]]; + while (objectdata < next_objdata_start) + { + m_objectCmdOffsets.push_back(objectdata - objectdata_start); + int new_offset = objectdata - &fifo_frame.fifoData[frame.objectStarts[0]]; + int command = *objectdata++; + switch (command) + { + case GX_NOP: + newLabel = "NOP"; + break; - // Between objectdata_end and next_objdata_start, there are register setting commands - if (object_idx + 1 < (int)frame.objectStarts.size()) - { - const u8* next_objdata_start = &fifo_frame.fifoData[frame.objectStarts[object_idx+1]]; - while (objectdata < next_objdata_start) - { - m_objectCmdOffsets.push_back(objectdata - objectdata_start); - int new_offset = objectdata - &fifo_frame.fifoData[frame.objectStarts[0]]; - int command = *objectdata++; - switch (command) - { - case GX_NOP: - newLabel = "NOP"; - break; + case 0x44: + newLabel = "0x44"; + break; - case 0x44: - newLabel = "0x44"; - break; + case GX_CMD_INVL_VC: + newLabel = "GX_CMD_INVL_VC"; + break; - case GX_CMD_INVL_VC: - newLabel = "GX_CMD_INVL_VC"; - break; + case GX_LOAD_CP_REG: + { + u32 cmd2 = *objectdata++; + u32 value = Common::swap32(objectdata); + objectdata += 4; - case GX_LOAD_CP_REG: - { - u32 cmd2 = *objectdata++; - u32 value = Common::swap32(objectdata); - objectdata += 4; + newLabel = wxString::Format("CP %02X %08X", cmd2, value); + } + break; - newLabel = wxString::Format("CP %02X %08X", cmd2, value); - } - break; + case GX_LOAD_XF_REG: + { + u32 cmd2 = Common::swap32(objectdata); + objectdata += 4; - case GX_LOAD_XF_REG: - { - u32 cmd2 = Common::swap32(objectdata); - objectdata += 4; + u8 streamSize = ((cmd2 >> 16) & 15) + 1; - u8 streamSize = ((cmd2 >> 16) & 15) + 1; + const u8* stream_start = objectdata; + const u8* stream_end = stream_start + streamSize * 4; - const u8* stream_start = objectdata; - const u8* stream_end = stream_start + streamSize * 4; + newLabel = wxString::Format("XF %08X ", cmd2); + while (objectdata < stream_end) + { + newLabel += wxString::Format("%02X", *objectdata++); - newLabel = wxString::Format("XF %08X ", cmd2); - while (objectdata < stream_end) - { - newLabel += wxString::Format("%02X", *objectdata++); + if (((objectdata - stream_start) % 4) == 0) + newLabel += " "; + } + } + break; - if (((objectdata - stream_start) % 4) == 0) - newLabel += " "; - } - } - break; + case GX_LOAD_INDX_A: + case GX_LOAD_INDX_B: + case GX_LOAD_INDX_C: + case GX_LOAD_INDX_D: + objectdata += 4; + newLabel = wxString::Format("LOAD INDX %s", (command == GX_LOAD_INDX_A) ? + "A" : + (command == GX_LOAD_INDX_B) ? + "B" : + (command == GX_LOAD_INDX_C) ? "C" : "D"); + break; - case GX_LOAD_INDX_A: - case GX_LOAD_INDX_B: - case GX_LOAD_INDX_C: - case GX_LOAD_INDX_D: - objectdata += 4; - newLabel = wxString::Format("LOAD INDX %s", (command == GX_LOAD_INDX_A) ? "A" : - (command == GX_LOAD_INDX_B) ? "B" : - (command == GX_LOAD_INDX_C) ? "C" : "D"); - break; + case GX_CMD_CALL_DL: + // The recorder should have expanded display lists into the fifo stream and skipped the + // call to start them + // That is done to make it easier to track where memory is updated + _assert_(false); + objectdata += 8; + newLabel = wxString::Format("CALL DL"); + break; - case GX_CMD_CALL_DL: - // The recorder should have expanded display lists into the fifo stream and skipped the call to start them - // That is done to make it easier to track where memory is updated - _assert_(false); - objectdata += 8; - newLabel = wxString::Format("CALL DL"); - break; + case GX_LOAD_BP_REG: + { + u32 cmd2 = Common::swap32(objectdata); + objectdata += 4; + newLabel = wxString::Format("BP %02X %06X", cmd2 >> 24, cmd2 & 0xFFFFFF); + } + break; - case GX_LOAD_BP_REG: - { - u32 cmd2 = Common::swap32(objectdata); - objectdata += 4; - newLabel = wxString::Format("BP %02X %06X", cmd2 >> 24, cmd2 & 0xFFFFFF); - } - break; + default: + newLabel = _("Unexpected 0x80 call? Aborting..."); + objectdata = (u8*)next_objdata_start; + break; + } + newLabel = wxString::Format("%08X: ", new_offset) + newLabel; + m_objectCmdList->Append(newLabel); + } + } + } + // Update command list + wxCommandEvent ev = wxCommandEvent(wxEVT_LISTBOX); + ev.SetInt(-1); + OnObjectCmdListSelectionChanged(ev); - default: - newLabel = _("Unexpected 0x80 call? Aborting..."); - objectdata = (u8*)next_objdata_start; - break; - } - newLabel = wxString::Format("%08X: ", new_offset) + newLabel; - m_objectCmdList->Append(newLabel); - } - } - } - // Update command list - wxCommandEvent ev = wxCommandEvent(wxEVT_LISTBOX); - ev.SetInt(-1); - OnObjectCmdListSelectionChanged(ev); - - ResetSearch(); + ResetSearch(); } void FifoPlayerDlg::OnObjectCmdListSelectionChanged(wxCommandEvent& event) { - const int frame_idx = m_framesList->GetSelection(); - const int object_idx = m_objectsList->GetSelection(); + const int frame_idx = m_framesList->GetSelection(); + const int object_idx = m_objectsList->GetSelection(); - if (event.GetInt() == -1 || frame_idx == -1 || object_idx == -1) - { - m_objectCmdInfo->SetLabel(wxEmptyString); - return; - } + if (event.GetInt() == -1 || frame_idx == -1 || object_idx == -1) + { + m_objectCmdInfo->SetLabel(wxEmptyString); + return; + } - FifoPlayer& player = FifoPlayer::GetInstance(); - const AnalyzedFrameInfo& frame = player.GetAnalyzedFrameInfo(frame_idx); - const FifoFrameInfo& fifo_frame = player.GetFile()->GetFrame(frame_idx); - const u8* cmddata = &fifo_frame.fifoData[frame.objectStarts[object_idx]] + m_objectCmdOffsets[event.GetInt()]; + FifoPlayer& player = FifoPlayer::GetInstance(); + const AnalyzedFrameInfo& frame = player.GetAnalyzedFrameInfo(frame_idx); + const FifoFrameInfo& fifo_frame = player.GetFile()->GetFrame(frame_idx); + const u8* cmddata = + &fifo_frame.fifoData[frame.objectStarts[object_idx]] + m_objectCmdOffsets[event.GetInt()]; - // TODO: Not sure whether we should bother translating the descriptions - wxString newLabel; - if (*cmddata == GX_LOAD_BP_REG) - { - std::string name; - std::string desc; - GetBPRegInfo(cmddata + 1, &name, &desc); + // TODO: Not sure whether we should bother translating the descriptions + wxString newLabel; + if (*cmddata == GX_LOAD_BP_REG) + { + std::string name; + std::string desc; + GetBPRegInfo(cmddata + 1, &name, &desc); - newLabel = _("BP register "); - newLabel += (name.empty()) ? wxString::Format(_("UNKNOWN_%02X"), *(cmddata + 1)) : StrToWxStr(name); - newLabel += ":\n"; + newLabel = _("BP register "); + newLabel += + (name.empty()) ? wxString::Format(_("UNKNOWN_%02X"), *(cmddata + 1)) : StrToWxStr(name); + newLabel += ":\n"; - if (desc.empty()) - newLabel += _("No description available"); - else - newLabel += StrToWxStr(desc); - } - else if (*cmddata == GX_LOAD_CP_REG) - { - newLabel = _("CP register "); - } - else if (*cmddata == GX_LOAD_XF_REG) - { - newLabel = _("XF register "); - } - else - { - newLabel = _("No description available"); - } + if (desc.empty()) + newLabel += _("No description available"); + else + newLabel += StrToWxStr(desc); + } + else if (*cmddata == GX_LOAD_CP_REG) + { + newLabel = _("CP register "); + } + else if (*cmddata == GX_LOAD_XF_REG) + { + newLabel = _("XF register "); + } + else + { + newLabel = _("No description available"); + } - m_objectCmdInfo->SetLabel(newLabel); - Layout(); - Fit(); + m_objectCmdInfo->SetLabel(newLabel); + Layout(); + Fit(); } void FifoPlayerDlg::OnObjectCmdListSelectionCopy(wxCommandEvent& WXUNUSED(event)) { - if (wxTheClipboard->Open()) - { - wxTheClipboard->SetData(new wxTextDataObject(m_objectCmdList->GetStringSelection())); - wxTheClipboard->Close(); - } + if (wxTheClipboard->Open()) + { + wxTheClipboard->SetData(new wxTextDataObject(m_objectCmdList->GetStringSelection())); + wxTheClipboard->Close(); + } } void FifoPlayerDlg::OnCloseClick(wxCommandEvent& WXUNUSED(event)) { - Hide(); + Hide(); } void FifoPlayerDlg::OnRecordingFinished(wxEvent&) { - m_RecordStop->SetLabel(_("Record")); - m_RecordStop->Enable(); + m_RecordStop->SetLabel(_("Record")); + m_RecordStop->Enable(); - UpdateRecorderGui(); + UpdateRecorderGui(); } void FifoPlayerDlg::OnFrameWritten(wxEvent&) { - m_CurrentFrameLabel->SetLabel(CreateCurrentFrameLabel()); - m_NumObjectsLabel->SetLabel(CreateFileObjectCountLabel()); + m_CurrentFrameLabel->SetLabel(CreateCurrentFrameLabel()); + m_NumObjectsLabel->SetLabel(CreateFileObjectCountLabel()); } void FifoPlayerDlg::UpdatePlayGui() { - m_NumFramesLabel->SetLabel(CreateFileFrameCountLabel()); - m_CurrentFrameLabel->SetLabel(CreateCurrentFrameLabel()); - m_NumObjectsLabel->SetLabel(CreateFileObjectCountLabel()); + m_NumFramesLabel->SetLabel(CreateFileFrameCountLabel()); + m_CurrentFrameLabel->SetLabel(CreateCurrentFrameLabel()); + m_NumObjectsLabel->SetLabel(CreateFileObjectCountLabel()); - FifoPlayer &player = FifoPlayer::GetInstance(); - FifoDataFile *file = player.GetFile(); - u32 frameCount = 0; - if (file) - frameCount = file->GetFrameCount(); + FifoPlayer& player = FifoPlayer::GetInstance(); + FifoDataFile* file = player.GetFile(); + u32 frameCount = 0; + if (file) + frameCount = file->GetFrameCount(); - m_FrameFromCtrl->SetRange(0, frameCount); - m_FrameFromCtrl->SetValue(player.GetFrameRangeStart()); + m_FrameFromCtrl->SetRange(0, frameCount); + m_FrameFromCtrl->SetValue(player.GetFrameRangeStart()); - m_FrameToCtrl->SetRange(0, frameCount); - m_FrameToCtrl->SetValue(player.GetFrameRangeEnd()); + m_FrameToCtrl->SetRange(0, frameCount); + m_FrameToCtrl->SetValue(player.GetFrameRangeEnd()); - m_ObjectFromCtrl->SetValue(player.GetObjectRangeStart()); - m_ObjectToCtrl->SetValue(player.GetObjectRangeEnd()); + m_ObjectFromCtrl->SetValue(player.GetObjectRangeStart()); + m_ObjectToCtrl->SetValue(player.GetObjectRangeEnd()); } void FifoPlayerDlg::UpdateRecorderGui() { - m_RecordingFifoSizeLabel->SetLabel(CreateRecordingFifoSizeLabel()); - m_RecordingMemSizeLabel->SetLabel(CreateRecordingMemSizeLabel()); - m_RecordingFramesLabel->SetLabel(CreateRecordingFrameCountLabel()); - m_Save->Enable(GetSaveButtonEnabled()); + m_RecordingFifoSizeLabel->SetLabel(CreateRecordingFifoSizeLabel()); + m_RecordingMemSizeLabel->SetLabel(CreateRecordingMemSizeLabel()); + m_RecordingFramesLabel->SetLabel(CreateRecordingFrameCountLabel()); + m_Save->Enable(GetSaveButtonEnabled()); } void FifoPlayerDlg::UpdateAnalyzerGui() { - FifoPlayer &player = FifoPlayer::GetInstance(); - FifoDataFile* file = player.GetFile(); + FifoPlayer& player = FifoPlayer::GetInstance(); + FifoDataFile* file = player.GetFile(); - size_t num_frames = (file) ? player.GetFile()->GetFrameCount() : 0U; - if (m_framesList->GetCount() != num_frames) - { - m_framesList->Clear(); + size_t num_frames = (file) ? player.GetFile()->GetFrameCount() : 0U; + if (m_framesList->GetCount() != num_frames) + { + m_framesList->Clear(); - for (size_t i = 0; i < num_frames; ++i) - { - m_framesList->Append(wxString::Format(_("Frame %zu"), i)); - } + for (size_t i = 0; i < num_frames; ++i) + { + m_framesList->Append(wxString::Format(_("Frame %zu"), i)); + } - wxCommandEvent ev = wxCommandEvent(wxEVT_LISTBOX); - ev.SetInt(-1); - OnFrameListSelectionChanged(ev); - } + wxCommandEvent ev = wxCommandEvent(wxEVT_LISTBOX); + ev.SetInt(-1); + OnFrameListSelectionChanged(ev); + } } wxString FifoPlayerDlg::CreateFileFrameCountLabel() const { - FifoDataFile *file = FifoPlayer::GetInstance().GetFile(); + FifoDataFile* file = FifoPlayer::GetInstance().GetFile(); - if (file) - return wxString::Format(_("%u frames"), file->GetFrameCount()); + if (file) + return wxString::Format(_("%u frames"), file->GetFrameCount()); - return _("No file loaded"); + return _("No file loaded"); } wxString FifoPlayerDlg::CreateCurrentFrameLabel() const { - FifoDataFile *file = FifoPlayer::GetInstance().GetFile(); + FifoDataFile* file = FifoPlayer::GetInstance().GetFile(); - if (file) - return wxString::Format(_("Frame %u"), FifoPlayer::GetInstance().GetCurrentFrameNum()); + if (file) + return wxString::Format(_("Frame %u"), FifoPlayer::GetInstance().GetCurrentFrameNum()); - return wxEmptyString; + return wxEmptyString; } wxString FifoPlayerDlg::CreateFileObjectCountLabel() const { - FifoDataFile *file = FifoPlayer::GetInstance().GetFile(); + FifoDataFile* file = FifoPlayer::GetInstance().GetFile(); - if (file) - return wxString::Format(_("%u objects"), FifoPlayer::GetInstance().GetFrameObjectCount()); + if (file) + return wxString::Format(_("%u objects"), FifoPlayer::GetInstance().GetFrameObjectCount()); - return wxEmptyString; + return wxEmptyString; } wxString FifoPlayerDlg::CreateRecordingFifoSizeLabel() const { - FifoDataFile *file = FifoRecorder::GetInstance().GetRecordedFile(); + FifoDataFile* file = FifoRecorder::GetInstance().GetRecordedFile(); - if (file) - { - size_t fifoBytes = 0; - for (size_t i = 0; i < file->GetFrameCount(); ++i) - fifoBytes += file->GetFrame(i).fifoDataSize; + if (file) + { + size_t fifoBytes = 0; + for (size_t i = 0; i < file->GetFrameCount(); ++i) + fifoBytes += file->GetFrame(i).fifoDataSize; - return wxString::Format(_("%zu FIFO bytes"), fifoBytes); - } + return wxString::Format(_("%zu FIFO bytes"), fifoBytes); + } - return _("No recorded file"); + return _("No recorded file"); } wxString FifoPlayerDlg::CreateRecordingMemSizeLabel() const { - FifoDataFile *file = FifoRecorder::GetInstance().GetRecordedFile(); + FifoDataFile* file = FifoRecorder::GetInstance().GetRecordedFile(); - if (file) - { - size_t memBytes = 0; - for (size_t frameNum = 0; frameNum < file->GetFrameCount(); ++frameNum) - { - const std::vector& memUpdates = file->GetFrame(frameNum).memoryUpdates; - for (auto& memUpdate : memUpdates) - memBytes += memUpdate.size; - } + if (file) + { + size_t memBytes = 0; + for (size_t frameNum = 0; frameNum < file->GetFrameCount(); ++frameNum) + { + const std::vector& memUpdates = file->GetFrame(frameNum).memoryUpdates; + for (auto& memUpdate : memUpdates) + memBytes += memUpdate.size; + } - return wxString::Format(_("%zu memory bytes"), memBytes); - } + return wxString::Format(_("%zu memory bytes"), memBytes); + } - return wxEmptyString; + return wxEmptyString; } wxString FifoPlayerDlg::CreateRecordingFrameCountLabel() const { - FifoDataFile *file = FifoRecorder::GetInstance().GetRecordedFile(); + FifoDataFile* file = FifoRecorder::GetInstance().GetRecordedFile(); - if (file) - return wxString::Format(_("%u frames"), file->GetFrameCount()); + if (file) + return wxString::Format(_("%u frames"), file->GetFrameCount()); - return wxEmptyString; + return wxEmptyString; } bool FifoPlayerDlg::GetSaveButtonEnabled() const { - return (FifoRecorder::GetInstance().GetRecordedFile() != nullptr); + return (FifoRecorder::GetInstance().GetRecordedFile() != nullptr); } void FifoPlayerDlg::RecordingFinished() { - sMutex.lock(); + sMutex.lock(); - if (m_EvtHandler) - { - wxCommandEvent event(RECORDING_FINISHED_EVENT); - m_EvtHandler->AddPendingEvent(event); - } + if (m_EvtHandler) + { + wxCommandEvent event(RECORDING_FINISHED_EVENT); + m_EvtHandler->AddPendingEvent(event); + } - sMutex.unlock(); + sMutex.unlock(); } void FifoPlayerDlg::FileLoaded() { - sMutex.lock(); + sMutex.lock(); - if (m_EvtHandler) - { - wxPaintEvent event; - m_EvtHandler->AddPendingEvent(event); - } + if (m_EvtHandler) + { + wxPaintEvent event; + m_EvtHandler->AddPendingEvent(event); + } - sMutex.unlock(); + sMutex.unlock(); } void FifoPlayerDlg::FrameWritten() { - sMutex.lock(); + sMutex.lock(); - if (m_EvtHandler) - { - wxCommandEvent event(FRAME_WRITTEN_EVENT); - m_EvtHandler->AddPendingEvent(event); - } + if (m_EvtHandler) + { + wxCommandEvent event(FRAME_WRITTEN_EVENT); + m_EvtHandler->AddPendingEvent(event); + } - sMutex.unlock(); + sMutex.unlock(); } diff --git a/Source/Core/DolphinWX/FifoPlayerDlg.h b/Source/Core/DolphinWX/FifoPlayerDlg.h index 153a506ab7..d4974cb1f4 100644 --- a/Source/Core/DolphinWX/FifoPlayerDlg.h +++ b/Source/Core/DolphinWX/FifoPlayerDlg.h @@ -24,103 +24,104 @@ class wxTextCtrl; class FifoPlayerDlg : public wxDialog { public: - FifoPlayerDlg(wxWindow* parent); - ~FifoPlayerDlg(); + FifoPlayerDlg(wxWindow* parent); + ~FifoPlayerDlg(); private: - void CreateGUIControls(); + void CreateGUIControls(); - void OnPaint(wxPaintEvent& event); - void OnFrameFrom(wxSpinEvent& event); - void OnFrameTo(wxSpinEvent& event); - void OnObjectFrom(wxSpinEvent& event); - void OnObjectTo(wxSpinEvent& event); - void OnCheckEarlyMemoryUpdates(wxCommandEvent& event); - void OnRecordStop(wxCommandEvent& event); - void OnSaveFile(wxCommandEvent& event); - void OnNumFramesToRecord(wxSpinEvent& event); - void OnCloseClick(wxCommandEvent& event); + void OnPaint(wxPaintEvent& event); + void OnFrameFrom(wxSpinEvent& event); + void OnFrameTo(wxSpinEvent& event); + void OnObjectFrom(wxSpinEvent& event); + void OnObjectTo(wxSpinEvent& event); + void OnCheckEarlyMemoryUpdates(wxCommandEvent& event); + void OnRecordStop(wxCommandEvent& event); + void OnSaveFile(wxCommandEvent& event); + void OnNumFramesToRecord(wxSpinEvent& event); + void OnCloseClick(wxCommandEvent& event); - void OnBeginSearch(wxCommandEvent& event); - void OnFindNextClick(wxCommandEvent& event); - void OnFindPreviousClick(wxCommandEvent& event); - void OnSearchFieldTextChanged(wxCommandEvent& event); - void ChangeSearchResult(unsigned int result_idx); - void ResetSearch(); + void OnBeginSearch(wxCommandEvent& event); + void OnFindNextClick(wxCommandEvent& event); + void OnFindPreviousClick(wxCommandEvent& event); + void OnSearchFieldTextChanged(wxCommandEvent& event); + void ChangeSearchResult(unsigned int result_idx); + void ResetSearch(); - void OnRecordingFinished(wxEvent& event); - void OnFrameWritten(wxEvent& event); + void OnRecordingFinished(wxEvent& event); + void OnFrameWritten(wxEvent& event); - void OnFrameListSelectionChanged(wxCommandEvent& event); - void OnObjectListSelectionChanged(wxCommandEvent& event); - void OnObjectCmdListSelectionChanged(wxCommandEvent& event); - void OnObjectCmdListSelectionCopy(wxCommandEvent& WXUNUSED(event)); + void OnFrameListSelectionChanged(wxCommandEvent& event); + void OnObjectListSelectionChanged(wxCommandEvent& event); + void OnObjectCmdListSelectionChanged(wxCommandEvent& event); + void OnObjectCmdListSelectionCopy(wxCommandEvent& WXUNUSED(event)); - void UpdatePlayGui(); - void UpdateRecorderGui(); - void UpdateAnalyzerGui(); + void UpdatePlayGui(); + void UpdateRecorderGui(); + void UpdateAnalyzerGui(); - wxString CreateFileFrameCountLabel() const; - wxString CreateCurrentFrameLabel() const; - wxString CreateFileObjectCountLabel() const; - wxString CreateRecordingFifoSizeLabel() const; - wxString CreateRecordingMemSizeLabel() const; - wxString CreateRecordingFrameCountLabel() const; + wxString CreateFileFrameCountLabel() const; + wxString CreateCurrentFrameLabel() const; + wxString CreateFileObjectCountLabel() const; + wxString CreateRecordingFifoSizeLabel() const; + wxString CreateRecordingMemSizeLabel() const; + wxString CreateRecordingFrameCountLabel() const; - bool GetSaveButtonEnabled() const; + bool GetSaveButtonEnabled() const; - // Called from a non-GUI thread - static void RecordingFinished(); - static void FileLoaded(); - static void FrameWritten(); + // Called from a non-GUI thread + static void RecordingFinished(); + static void FileLoaded(); + static void FrameWritten(); - static wxEvtHandler *volatile m_EvtHandler; + static wxEvtHandler* volatile m_EvtHandler; - wxNotebook* m_Notebook; - wxPanel* m_PlayPage; - wxStaticText* m_NumFramesLabel; - wxStaticText* m_CurrentFrameLabel; - wxStaticText* m_NumObjectsLabel; - wxStaticText* m_FrameFromLabel; - wxSpinCtrl* m_FrameFromCtrl; - wxStaticText* m_FrameToLabel; - wxSpinCtrl* m_FrameToCtrl; - wxStaticText* m_ObjectFromLabel; - wxSpinCtrl* m_ObjectFromCtrl; - wxStaticText* m_ObjectToLabel; - wxSpinCtrl* m_ObjectToCtrl; - wxCheckBox* m_EarlyMemoryUpdates; - wxPanel* m_RecordPage; - wxStaticText* m_RecordingFifoSizeLabel; - wxStaticText* m_RecordingMemSizeLabel; - wxStaticText* m_RecordingFramesLabel; - wxButton* m_RecordStop; - wxButton* m_Save; - wxStaticText* m_FramesToRecordLabel; - wxSpinCtrl* m_FramesToRecordCtrl; + wxNotebook* m_Notebook; + wxPanel* m_PlayPage; + wxStaticText* m_NumFramesLabel; + wxStaticText* m_CurrentFrameLabel; + wxStaticText* m_NumObjectsLabel; + wxStaticText* m_FrameFromLabel; + wxSpinCtrl* m_FrameFromCtrl; + wxStaticText* m_FrameToLabel; + wxSpinCtrl* m_FrameToCtrl; + wxStaticText* m_ObjectFromLabel; + wxSpinCtrl* m_ObjectFromCtrl; + wxStaticText* m_ObjectToLabel; + wxSpinCtrl* m_ObjectToCtrl; + wxCheckBox* m_EarlyMemoryUpdates; + wxPanel* m_RecordPage; + wxStaticText* m_RecordingFifoSizeLabel; + wxStaticText* m_RecordingMemSizeLabel; + wxStaticText* m_RecordingFramesLabel; + wxButton* m_RecordStop; + wxButton* m_Save; + wxStaticText* m_FramesToRecordLabel; + wxSpinCtrl* m_FramesToRecordCtrl; - wxPanel* m_AnalyzePage; - wxListBox* m_framesList; - wxListBox* m_objectsList; - wxListBox* m_objectCmdList; - std::vector m_objectCmdOffsets; - wxStaticText* m_objectCmdInfo; + wxPanel* m_AnalyzePage; + wxListBox* m_framesList; + wxListBox* m_objectsList; + wxListBox* m_objectCmdList; + std::vector m_objectCmdOffsets; + wxStaticText* m_objectCmdInfo; - wxTextCtrl* m_searchField; - wxButton* m_beginSearch; - wxButton* m_findNext; - wxButton* m_findPrevious; - wxStaticText* m_numResultsText; + wxTextCtrl* m_searchField; + wxButton* m_beginSearch; + wxButton* m_findNext; + wxButton* m_findPrevious; + wxStaticText* m_numResultsText; - struct SearchResult { - int frame_idx; - int obj_idx; - int cmd_idx; - }; - std::vector search_results; - unsigned int m_search_result_idx; + struct SearchResult + { + int frame_idx; + int obj_idx; + int cmd_idx; + }; + std::vector search_results; + unsigned int m_search_result_idx; - wxButton* m_Close; + wxButton* m_Close; - s32 m_FramesToRecord; + s32 m_FramesToRecord; }; diff --git a/Source/Core/DolphinWX/Frame.cpp b/Source/Core/DolphinWX/Frame.cpp index 4056ed4f90..b853384b22 100644 --- a/Source/Core/DolphinWX/Frame.cpp +++ b/Source/Core/DolphinWX/Frame.cpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -22,26 +24,25 @@ #include #include #include -#include -#include #include "AudioCommon/AudioCommon.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/Thread.h" #include "Common/Logging/ConsoleListener.h" +#include "Common/Thread.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/HotkeyManager.h" -#include "Core/Movie.h" -#include "Core/State.h" #include "Core/HW/DVDInterface.h" #include "Core/HW/GCKeyboard.h" #include "Core/HW/GCPad.h" #include "Core/HW/Wiimote.h" +#include "Core/HotkeyManager.h" +#include "Core/Movie.h" +#include "Core/State.h" +#include "DolphinWX/Debugger/CodeWindow.h" #include "DolphinWX/Frame.h" #include "DolphinWX/GameListCtrl.h" #include "DolphinWX/Globals.h" @@ -49,7 +50,6 @@ #include "DolphinWX/Main.h" #include "DolphinWX/TASInputDlg.h" #include "DolphinWX/WxUtils.h" -#include "DolphinWX/Debugger/CodeWindow.h" #include "InputCommon/GCPadStatus.h" @@ -62,160 +62,160 @@ int g_saveSlot = 1; #if defined(HAVE_X11) && HAVE_X11 // X11Utils nastiness that's only used here -namespace X11Utils { - -Window XWindowFromHandle(void *Handle) +namespace X11Utils { - return GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(Handle))); +Window XWindowFromHandle(void* Handle) +{ + return GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(Handle))); } -Display *XDisplayFromHandle(void *Handle) +Display* XDisplayFromHandle(void* Handle) { - return GDK_WINDOW_XDISPLAY(gtk_widget_get_window(GTK_WIDGET(Handle))); + return GDK_WINDOW_XDISPLAY(gtk_widget_get_window(GTK_WIDGET(Handle))); } - } #endif CRenderFrame::CRenderFrame(wxFrame* parent, wxWindowID id, const wxString& title, - const wxPoint& pos, const wxSize& size, long style) - : wxFrame(parent, id, title, pos, size, style) + const wxPoint& pos, const wxSize& size, long style) + : wxFrame(parent, id, title, pos, size, style) { - // Give it an icon - wxIcon IconTemp; - IconTemp.CopyFromBitmap(WxUtils::LoadResourceBitmap("Dolphin")); - SetIcon(IconTemp); + // Give it an icon + wxIcon IconTemp; + IconTemp.CopyFromBitmap(WxUtils::LoadResourceBitmap("Dolphin")); + SetIcon(IconTemp); - DragAcceptFiles(true); - Bind(wxEVT_DROP_FILES, &CRenderFrame::OnDropFiles, this); + DragAcceptFiles(true); + Bind(wxEVT_DROP_FILES, &CRenderFrame::OnDropFiles, this); } void CRenderFrame::OnDropFiles(wxDropFilesEvent& event) { - if (event.GetNumberOfFiles() != 1) - return; - if (File::IsDirectory(WxStrToStr(event.GetFiles()[0]))) - return; + if (event.GetNumberOfFiles() != 1) + return; + if (File::IsDirectory(WxStrToStr(event.GetFiles()[0]))) + return; - wxFileName file = event.GetFiles()[0]; - const std::string filepath = WxStrToStr(file.GetFullPath()); + wxFileName file = event.GetFiles()[0]; + const std::string filepath = WxStrToStr(file.GetFullPath()); - if (file.GetExt() == "dtm") - { - if (Core::IsRunning()) - return; + if (file.GetExt() == "dtm") + { + if (Core::IsRunning()) + return; - if (!Movie::IsReadOnly()) - { - // let's make the read-only flag consistent at the start of a movie. - Movie::SetReadOnly(true); - main_frame->GetMenuBar()->FindItem(IDM_RECORD_READ_ONLY)->Check(true); - } + if (!Movie::IsReadOnly()) + { + // let's make the read-only flag consistent at the start of a movie. + Movie::SetReadOnly(true); + main_frame->GetMenuBar()->FindItem(IDM_RECORD_READ_ONLY)->Check(true); + } - if (Movie::PlayInput(filepath)) - main_frame->BootGame(""); - } - else if (!Core::IsRunning()) - { - main_frame->BootGame(filepath); - } - else if (IsValidSavestateDropped(filepath) && Core::IsRunning()) - { - State::LoadAs(filepath); - } - else - { - DVDInterface::ChangeDisc(filepath); - } + if (Movie::PlayInput(filepath)) + main_frame->BootGame(""); + } + else if (!Core::IsRunning()) + { + main_frame->BootGame(filepath); + } + else if (IsValidSavestateDropped(filepath) && Core::IsRunning()) + { + State::LoadAs(filepath); + } + else + { + DVDInterface::ChangeDisc(filepath); + } } bool CRenderFrame::IsValidSavestateDropped(const std::string& filepath) { - const int game_id_length = 6; - std::ifstream file(filepath, std::ios::in | std::ios::binary); + const int game_id_length = 6; + std::ifstream file(filepath, std::ios::in | std::ios::binary); - if (!file) - return false; + if (!file) + return false; - std::string internal_game_id(game_id_length, ' '); - file.read(&internal_game_id[0], game_id_length); + std::string internal_game_id(game_id_length, ' '); + file.read(&internal_game_id[0], game_id_length); - return internal_game_id == SConfig::GetInstance().GetUniqueID(); + return internal_game_id == SConfig::GetInstance().GetUniqueID(); } #ifdef _WIN32 WXLRESULT CRenderFrame::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) { - switch (nMsg) - { - case WM_SYSCOMMAND: - switch (wParam) - { - case SC_SCREENSAVE: - case SC_MONITORPOWER: - if (Core::GetState() == Core::CORE_RUN && SConfig::GetInstance().bDisableScreenSaver) - break; - default: - return wxFrame::MSWWindowProc(nMsg, wParam, lParam); - } - break; + switch (nMsg) + { + case WM_SYSCOMMAND: + switch (wParam) + { + case SC_SCREENSAVE: + case SC_MONITORPOWER: + if (Core::GetState() == Core::CORE_RUN && SConfig::GetInstance().bDisableScreenSaver) + break; + default: + return wxFrame::MSWWindowProc(nMsg, wParam, lParam); + } + break; - case WM_USER: - switch (wParam) - { - case WM_USER_STOP: - main_frame->DoStop(); - break; + case WM_USER: + switch (wParam) + { + case WM_USER_STOP: + main_frame->DoStop(); + break; - case WM_USER_SETCURSOR: - if (SConfig::GetInstance().bHideCursor && - main_frame->RendererHasFocus() && Core::GetState() == Core::CORE_RUN) - SetCursor(wxCURSOR_BLANK); - else - SetCursor(wxNullCursor); - break; - } - break; + case WM_USER_SETCURSOR: + if (SConfig::GetInstance().bHideCursor && main_frame->RendererHasFocus() && + Core::GetState() == Core::CORE_RUN) + SetCursor(wxCURSOR_BLANK); + else + SetCursor(wxNullCursor); + break; + } + break; - case WM_CLOSE: - // Let Core finish initializing before accepting any WM_CLOSE messages - if (!Core::IsRunning()) break; - // Use default action otherwise + case WM_CLOSE: + // Let Core finish initializing before accepting any WM_CLOSE messages + if (!Core::IsRunning()) + break; + // Use default action otherwise - default: - // By default let wxWidgets do what it normally does with this event - return wxFrame::MSWWindowProc(nMsg, wParam, lParam); - } - return 0; + default: + // By default let wxWidgets do what it normally does with this event + return wxFrame::MSWWindowProc(nMsg, wParam, lParam); + } + return 0; } #endif bool CRenderFrame::ShowFullScreen(bool show, long style) { #if defined WIN32 - if (show && !g_Config.bBorderlessFullscreen) - { - // OpenGL requires the pop-up style to activate exclusive mode. - SetWindowStyle((GetWindowStyle() & ~wxDEFAULT_FRAME_STYLE) | wxPOPUP_WINDOW); + if (show && !g_Config.bBorderlessFullscreen) + { + // OpenGL requires the pop-up style to activate exclusive mode. + SetWindowStyle((GetWindowStyle() & ~wxDEFAULT_FRAME_STYLE) | wxPOPUP_WINDOW); - // Some backends don't support exclusive fullscreen, so we - // can't tell exactly when exclusive mode is activated. - if (!g_Config.backend_info.bSupportsExclusiveFullscreen) - OSD::AddMessage("Entered exclusive fullscreen."); - } + // Some backends don't support exclusive fullscreen, so we + // can't tell exactly when exclusive mode is activated. + if (!g_Config.backend_info.bSupportsExclusiveFullscreen) + OSD::AddMessage("Entered exclusive fullscreen."); + } #endif - bool result = wxTopLevelWindow::ShowFullScreen(show, style); + bool result = wxTopLevelWindow::ShowFullScreen(show, style); #if defined WIN32 - if (!show) - { - // Restore the default style. - SetWindowStyle((GetWindowStyle() & ~wxPOPUP_WINDOW) | wxDEFAULT_FRAME_STYLE); - } + if (!show) + { + // Restore the default style. + SetWindowStyle((GetWindowStyle() & ~wxPOPUP_WINDOW) | wxDEFAULT_FRAME_STYLE); + } #endif - return result; + return result; } // event tables @@ -332,288 +332,287 @@ END_EVENT_TABLE() // --------------- // Creation and close, quit functions - bool CFrame::InitControllers() { - if (!g_controller_interface.IsInit()) - { + if (!g_controller_interface.IsInit()) + { #if defined(HAVE_X11) && HAVE_X11 - Window win = X11Utils::XWindowFromHandle(GetHandle()); - Pad::Initialize(reinterpret_cast(win)); - Keyboard::Initialize(reinterpret_cast(win)); - Wiimote::Initialize(reinterpret_cast(win)); - HotkeyManagerEmu::Initialize(reinterpret_cast(win)); + Window win = X11Utils::XWindowFromHandle(GetHandle()); + Pad::Initialize(reinterpret_cast(win)); + Keyboard::Initialize(reinterpret_cast(win)); + Wiimote::Initialize(reinterpret_cast(win)); + HotkeyManagerEmu::Initialize(reinterpret_cast(win)); #else - Pad::Initialize(reinterpret_cast(GetHandle())); - Keyboard::Initialize(reinterpret_cast(GetHandle())); - Wiimote::Initialize(reinterpret_cast(GetHandle())); - HotkeyManagerEmu::Initialize(reinterpret_cast(GetHandle())); + Pad::Initialize(reinterpret_cast(GetHandle())); + Keyboard::Initialize(reinterpret_cast(GetHandle())); + Wiimote::Initialize(reinterpret_cast(GetHandle())); + HotkeyManagerEmu::Initialize(reinterpret_cast(GetHandle())); #endif - return true; - } - return false; + return true; + } + return false; } -CFrame::CFrame(wxFrame* parent, - wxWindowID id, - const wxString& title, - const wxPoint& pos, - const wxSize& size, - bool _UseDebugger, - bool _BatchMode, - bool ShowLogWindow, - long style) - : CRenderFrame(parent, id, title, pos, size, style) - , g_pCodeWindow(nullptr), g_NetPlaySetupDiag(nullptr), g_CheatsWindow(nullptr) - , m_SavedPerspectives(nullptr), m_ToolBar(nullptr) - , m_GameListCtrl(nullptr), m_Panel(nullptr) - , m_RenderFrame(nullptr), m_RenderParent(nullptr) - , m_LogWindow(nullptr), m_LogConfigWindow(nullptr) - , m_FifoPlayerDlg(nullptr), UseDebugger(_UseDebugger) - , m_bBatchMode(_BatchMode), m_bEdit(false), m_bTabSplit(false), m_bNoDocking(false) - , m_bGameLoading(false), m_bClosing(false), m_confirmStop(false), m_menubar_shadow(nullptr) +CFrame::CFrame(wxFrame* parent, wxWindowID id, const wxString& title, const wxPoint& pos, + const wxSize& size, bool _UseDebugger, bool _BatchMode, bool ShowLogWindow, + long style) + : CRenderFrame(parent, id, title, pos, size, style), g_pCodeWindow(nullptr), + g_NetPlaySetupDiag(nullptr), g_CheatsWindow(nullptr), m_SavedPerspectives(nullptr), + m_ToolBar(nullptr), m_GameListCtrl(nullptr), m_Panel(nullptr), m_RenderFrame(nullptr), + m_RenderParent(nullptr), m_LogWindow(nullptr), m_LogConfigWindow(nullptr), + m_FifoPlayerDlg(nullptr), UseDebugger(_UseDebugger), m_bBatchMode(_BatchMode), m_bEdit(false), + m_bTabSplit(false), m_bNoDocking(false), m_bGameLoading(false), m_bClosing(false), + m_confirmStop(false), m_menubar_shadow(nullptr) { - for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++) - bFloatWindow[i] = false; + for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++) + bFloatWindow[i] = false; - if (ShowLogWindow) - SConfig::GetInstance().m_InterfaceLogWindow = true; + if (ShowLogWindow) + SConfig::GetInstance().m_InterfaceLogWindow = true; - // Start debugging maximized - if (UseDebugger) - this->Maximize(true); + // Start debugging maximized + if (UseDebugger) + this->Maximize(true); - // Debugger class - if (UseDebugger) - { - g_pCodeWindow = new CCodeWindow(SConfig::GetInstance(), this, IDM_CODE_WINDOW); - LoadIniPerspectives(); - g_pCodeWindow->Load(); - } + // Debugger class + if (UseDebugger) + { + g_pCodeWindow = new CCodeWindow(SConfig::GetInstance(), this, IDM_CODE_WINDOW); + LoadIniPerspectives(); + g_pCodeWindow->Load(); + } - // Create toolbar bitmaps - InitBitmaps(); + // Create toolbar bitmaps + InitBitmaps(); - // Give it a status bar - SetStatusBar(CreateStatusBar(2, wxST_SIZEGRIP, ID_STATUSBAR)); - if (!SConfig::GetInstance().m_InterfaceStatusbar) - GetStatusBar()->Hide(); + // Give it a status bar + SetStatusBar(CreateStatusBar(2, wxST_SIZEGRIP, ID_STATUSBAR)); + if (!SConfig::GetInstance().m_InterfaceStatusbar) + GetStatusBar()->Hide(); - // Give it a menu bar - wxMenuBar* menubar_active = CreateMenu(); - SetMenuBar(menubar_active); - // Create a menubar to service requests while the real menubar is hidden from the screen - m_menubar_shadow = CreateMenu(); + // Give it a menu bar + wxMenuBar* menubar_active = CreateMenu(); + SetMenuBar(menubar_active); + // Create a menubar to service requests while the real menubar is hidden from the screen + m_menubar_shadow = CreateMenu(); - // --------------- - // Main panel - // This panel is the parent for rendering and it holds the gamelistctrl - m_Panel = new wxPanel(this, IDM_MPANEL, wxDefaultPosition, wxDefaultSize, 0); + // --------------- + // Main panel + // This panel is the parent for rendering and it holds the gamelistctrl + m_Panel = new wxPanel(this, IDM_MPANEL, wxDefaultPosition, wxDefaultSize, 0); - m_GameListCtrl = new CGameListCtrl(m_Panel, wxID_ANY, - wxDefaultPosition, wxDefaultSize, - wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT); - m_GameListCtrl->Bind(wxEVT_LIST_ITEM_ACTIVATED, &CFrame::OnGameListCtrlItemActivated, this); + m_GameListCtrl = new CGameListCtrl(m_Panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT); + m_GameListCtrl->Bind(wxEVT_LIST_ITEM_ACTIVATED, &CFrame::OnGameListCtrlItemActivated, this); - wxBoxSizer *sizerPanel = new wxBoxSizer(wxHORIZONTAL); - sizerPanel->Add(m_GameListCtrl, 1, wxEXPAND | wxALL); - m_Panel->SetSizer(sizerPanel); - // --------------- + wxBoxSizer* sizerPanel = new wxBoxSizer(wxHORIZONTAL); + sizerPanel->Add(m_GameListCtrl, 1, wxEXPAND | wxALL); + m_Panel->SetSizer(sizerPanel); + // --------------- - // Manager - m_Mgr = new wxAuiManager(this, wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE); + // Manager + m_Mgr = new wxAuiManager(this, wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE); - m_Mgr->AddPane(m_Panel, wxAuiPaneInfo() - .Name("Pane 0").Caption("Pane 0").PaneBorder(false) - .CaptionVisible(false).Layer(0).Center().Show()); - if (!g_pCodeWindow) - m_Mgr->AddPane(CreateEmptyNotebook(), wxAuiPaneInfo() - .Name("Pane 1").Caption(_("Logging")).CaptionVisible(true) - .Layer(0).FloatingSize(wxSize(600, 350)).CloseButton(true).Hide()); - AuiFullscreen = m_Mgr->SavePerspective(); + m_Mgr->AddPane(m_Panel, wxAuiPaneInfo() + .Name("Pane 0") + .Caption("Pane 0") + .PaneBorder(false) + .CaptionVisible(false) + .Layer(0) + .Center() + .Show()); + if (!g_pCodeWindow) + m_Mgr->AddPane(CreateEmptyNotebook(), wxAuiPaneInfo() + .Name("Pane 1") + .Caption(_("Logging")) + .CaptionVisible(true) + .Layer(0) + .FloatingSize(wxSize(600, 350)) + .CloseButton(true) + .Hide()); + AuiFullscreen = m_Mgr->SavePerspective(); - // Create toolbar - RecreateToolbar(); - if (!SConfig::GetInstance().m_InterfaceToolbar) DoToggleToolbar(false); + // Create toolbar + RecreateToolbar(); + if (!SConfig::GetInstance().m_InterfaceToolbar) + DoToggleToolbar(false); - m_LogWindow = new CLogWindow(this, IDM_LOG_WINDOW); - m_LogWindow->Hide(); - m_LogWindow->Disable(); + m_LogWindow = new CLogWindow(this, IDM_LOG_WINDOW); + m_LogWindow->Hide(); + m_LogWindow->Disable(); - for (int i = 0; i < 8; ++i) - g_TASInputDlg[i] = new TASInputDlg(this); + for (int i = 0; i < 8; ++i) + g_TASInputDlg[i] = new TASInputDlg(this); - Movie::SetGCInputManip(GCTASManipFunction); - Movie::SetWiiInputManip(WiiTASManipFunction); + Movie::SetGCInputManip(GCTASManipFunction); + Movie::SetWiiInputManip(WiiTASManipFunction); - State::SetOnAfterLoadCallback(OnAfterLoadCallback); - Core::SetOnStoppedCallback(OnStoppedCallback); + State::SetOnAfterLoadCallback(OnAfterLoadCallback); + Core::SetOnStoppedCallback(OnStoppedCallback); - // Setup perspectives - if (g_pCodeWindow) - { - // Load perspective - DoLoadPerspective(); - } - else - { - if (SConfig::GetInstance().m_InterfaceLogWindow) - ToggleLogWindow(true); - if (SConfig::GetInstance().m_InterfaceLogConfigWindow) - ToggleLogConfigWindow(true); - } + // Setup perspectives + if (g_pCodeWindow) + { + // Load perspective + DoLoadPerspective(); + } + else + { + if (SConfig::GetInstance().m_InterfaceLogWindow) + ToggleLogWindow(true); + if (SConfig::GetInstance().m_InterfaceLogConfigWindow) + ToggleLogConfigWindow(true); + } - // Set the size of the window after the UI has been built, but before we show it - SetSize(size); + // Set the size of the window after the UI has been built, but before we show it + SetSize(size); - // Show window - Show(); + // Show window + Show(); - // Commit - m_Mgr->Update(); + // Commit + m_Mgr->Update(); - #ifdef _WIN32 - SetToolTip(""); - GetToolTip()->SetAutoPop(25000); - #endif +#ifdef _WIN32 + SetToolTip(""); + GetToolTip()->SetAutoPop(25000); +#endif - #if defined(HAVE_XRANDR) && HAVE_XRANDR - m_XRRConfig = new X11Utils::XRRConfiguration(X11Utils::XDisplayFromHandle(GetHandle()), - X11Utils::XWindowFromHandle(GetHandle())); - #endif +#if defined(HAVE_XRANDR) && HAVE_XRANDR + m_XRRConfig = new X11Utils::XRRConfiguration(X11Utils::XDisplayFromHandle(GetHandle()), + X11Utils::XWindowFromHandle(GetHandle())); +#endif - // ------------------------- - // Connect event handlers + // ------------------------- + // Connect event handlers - m_Mgr->Bind(wxEVT_AUI_RENDER, &CFrame::OnManagerResize, this); - // ---------- + m_Mgr->Bind(wxEVT_AUI_RENDER, &CFrame::OnManagerResize, this); + // ---------- - // Update controls - UpdateGUI(); - if (g_pCodeWindow) - g_pCodeWindow->UpdateButtonStates(); + // Update controls + UpdateGUI(); + if (g_pCodeWindow) + g_pCodeWindow->UpdateButtonStates(); - // check if game is running - InitControllers(); + // check if game is running + InitControllers(); - m_poll_hotkey_timer.SetOwner(this); - Bind(wxEVT_TIMER, &CFrame::PollHotkeys, this); - m_poll_hotkey_timer.Start(1000 / 60, wxTIMER_CONTINUOUS); + m_poll_hotkey_timer.SetOwner(this); + Bind(wxEVT_TIMER, &CFrame::PollHotkeys, this); + m_poll_hotkey_timer.Start(1000 / 60, wxTIMER_CONTINUOUS); } // Destructor CFrame::~CFrame() { - Wiimote::Shutdown(); - Keyboard::Shutdown(); - Pad::Shutdown(); - HotkeyManagerEmu::Shutdown(); + Wiimote::Shutdown(); + Keyboard::Shutdown(); + Pad::Shutdown(); + HotkeyManagerEmu::Shutdown(); - drives.clear(); + drives.clear(); - #if defined(HAVE_XRANDR) && HAVE_XRANDR - delete m_XRRConfig; - #endif +#if defined(HAVE_XRANDR) && HAVE_XRANDR + delete m_XRRConfig; +#endif - ClosePages(); + ClosePages(); - delete m_Mgr; + delete m_Mgr; - // This object is owned by us, not wxw - m_menubar_shadow->Destroy(); - m_menubar_shadow = nullptr; + // This object is owned by us, not wxw + m_menubar_shadow->Destroy(); + m_menubar_shadow = nullptr; } bool CFrame::RendererIsFullscreen() { - bool fullscreen = false; + bool fullscreen = false; - if (Core::GetState() == Core::CORE_RUN || Core::GetState() == Core::CORE_PAUSE) - { - fullscreen = m_RenderFrame->IsFullScreen(); - } + if (Core::GetState() == Core::CORE_RUN || Core::GetState() == Core::CORE_PAUSE) + { + fullscreen = m_RenderFrame->IsFullScreen(); + } #if defined(__APPLE__) - if (m_RenderFrame != nullptr) - { - NSView *view = (NSView *) m_RenderFrame->GetHandle(); - NSWindow *window = [view window]; + if (m_RenderFrame != nullptr) + { + NSView* view = (NSView*)m_RenderFrame->GetHandle(); + NSWindow* window = [view window]; - fullscreen = (([window styleMask] & NSFullScreenWindowMask) == NSFullScreenWindowMask); - } + fullscreen = (([window styleMask] & NSFullScreenWindowMask) == NSFullScreenWindowMask); + } #endif - return fullscreen; + return fullscreen; } -void CFrame::OnQuit(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) { - Close(true); + Close(true); } // -------- // Events void CFrame::OnActive(wxActivateEvent& event) { - if (Core::GetState() == Core::CORE_RUN || Core::GetState() == Core::CORE_PAUSE) - { - if (event.GetActive() && event.GetEventObject() == m_RenderFrame) - { - if (SConfig::GetInstance().bRenderToMain) - m_RenderParent->SetFocus(); + if (Core::GetState() == Core::CORE_RUN || Core::GetState() == Core::CORE_PAUSE) + { + if (event.GetActive() && event.GetEventObject() == m_RenderFrame) + { + if (SConfig::GetInstance().bRenderToMain) + m_RenderParent->SetFocus(); - if (SConfig::GetInstance().bHideCursor && - Core::GetState() == Core::CORE_RUN) - m_RenderParent->SetCursor(wxCURSOR_BLANK); - } - else - { - if (SConfig::GetInstance().bHideCursor) - m_RenderParent->SetCursor(wxNullCursor); - } - } - event.Skip(); + if (SConfig::GetInstance().bHideCursor && Core::GetState() == Core::CORE_RUN) + m_RenderParent->SetCursor(wxCURSOR_BLANK); + } + else + { + if (SConfig::GetInstance().bHideCursor) + m_RenderParent->SetCursor(wxNullCursor); + } + } + event.Skip(); } void CFrame::OnClose(wxCloseEvent& event) { - // Before closing the window we need to shut down the emulation core. - // We'll try to close this window again once that is done. - if (Core::GetState() != Core::CORE_UNINITIALIZED) - { - DoStop(); - if (event.CanVeto()) - { - event.Veto(); - } - // Tell OnStopped to resubmit the Close event - if (m_confirmStop) - m_bClosing = true; - return; - } + // Before closing the window we need to shut down the emulation core. + // We'll try to close this window again once that is done. + if (Core::GetState() != Core::CORE_UNINITIALIZED) + { + DoStop(); + if (event.CanVeto()) + { + event.Veto(); + } + // Tell OnStopped to resubmit the Close event + if (m_confirmStop) + m_bClosing = true; + return; + } - // Stop Dolphin from saving the minimized Xpos and Ypos - if (main_frame->IsIconized()) - main_frame->Iconize(false); + // Stop Dolphin from saving the minimized Xpos and Ypos + if (main_frame->IsIconized()) + main_frame->Iconize(false); - // Don't forget the skip or the window won't be destroyed - event.Skip(); + // Don't forget the skip or the window won't be destroyed + event.Skip(); - // Save GUI settings - if (g_pCodeWindow) - { - SaveIniPerspectives(); - } - else - { - // Close the log window now so that its settings are saved - if (m_LogWindow) - m_LogWindow->Close(); - m_LogWindow = nullptr; - } + // Save GUI settings + if (g_pCodeWindow) + { + SaveIniPerspectives(); + } + else + { + // Close the log window now so that its settings are saved + if (m_LogWindow) + m_LogWindow->Close(); + m_LogWindow = nullptr; + } - - // Uninit - m_Mgr->UnInit(); + // Uninit + m_Mgr->UnInit(); } // Post events @@ -621,51 +620,45 @@ void CFrame::OnClose(wxCloseEvent& event) // Warning: This may cause an endless loop if the event is propagated back to its parent void CFrame::PostEvent(wxCommandEvent& event) { - if (g_pCodeWindow && - event.GetId() >= IDM_INTERPRETER && - event.GetId() <= IDM_ADDRBOX) - { - event.StopPropagation(); - g_pCodeWindow->GetEventHandler()->AddPendingEvent(event); - } - else - { - event.Skip(); - } + if (g_pCodeWindow && event.GetId() >= IDM_INTERPRETER && event.GetId() <= IDM_ADDRBOX) + { + event.StopPropagation(); + g_pCodeWindow->GetEventHandler()->AddPendingEvent(event); + } + else + { + event.Skip(); + } } void CFrame::OnMove(wxMoveEvent& event) { - event.Skip(); + event.Skip(); - if (!IsMaximized() && - !(SConfig::GetInstance().bRenderToMain && RendererIsFullscreen())) - { - SConfig::GetInstance().iPosX = GetPosition().x; - SConfig::GetInstance().iPosY = GetPosition().y; - } + if (!IsMaximized() && !(SConfig::GetInstance().bRenderToMain && RendererIsFullscreen())) + { + SConfig::GetInstance().iPosX = GetPosition().x; + SConfig::GetInstance().iPosY = GetPosition().y; + } } void CFrame::OnResize(wxSizeEvent& event) { - event.Skip(); + event.Skip(); - if (!IsMaximized() && - !(SConfig::GetInstance().bRenderToMain && RendererIsFullscreen()) && - !(Core::GetState() != Core::CORE_UNINITIALIZED && - SConfig::GetInstance().bRenderToMain && - SConfig::GetInstance().bRenderWindowAutoSize)) - { - SConfig::GetInstance().iWidth = GetSize().GetWidth(); - SConfig::GetInstance().iHeight = GetSize().GetHeight(); - } + if (!IsMaximized() && !(SConfig::GetInstance().bRenderToMain && RendererIsFullscreen()) && + !(Core::GetState() != Core::CORE_UNINITIALIZED && SConfig::GetInstance().bRenderToMain && + SConfig::GetInstance().bRenderWindowAutoSize)) + { + SConfig::GetInstance().iWidth = GetSize().GetWidth(); + SConfig::GetInstance().iHeight = GetSize().GetHeight(); + } - // Make sure the logger pane is a sane size - if (!g_pCodeWindow && m_LogWindow && m_Mgr->GetPane("Pane 1").IsShown() && - !m_Mgr->GetPane("Pane 1").IsFloating() && - (m_LogWindow->x > GetClientRect().GetWidth() || - m_LogWindow->y > GetClientRect().GetHeight())) - ShowResizePane(); + // Make sure the logger pane is a sane size + if (!g_pCodeWindow && m_LogWindow && m_Mgr->GetPane("Pane 1").IsShown() && + !m_Mgr->GetPane("Pane 1").IsFloating() && + (m_LogWindow->x > GetClientRect().GetWidth() || m_LogWindow->y > GetClientRect().GetHeight())) + ShowResizePane(); } // Host messages @@ -673,945 +666,1016 @@ void CFrame::OnResize(wxSizeEvent& event) #ifdef _WIN32 WXLRESULT CFrame::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) { - if (WM_SYSCOMMAND == nMsg && (SC_SCREENSAVE == wParam || SC_MONITORPOWER == wParam)) - { - return 0; - } - else if (nMsg == WM_QUERYENDSESSION) - { - // Indicate that the application will be able to close - return 1; - } - else if (nMsg == WM_ENDSESSION) - { - // Actually trigger the close now - Close(true); - return 0; - } - else - { - return wxFrame::MSWWindowProc(nMsg, wParam, lParam); - } + if (WM_SYSCOMMAND == nMsg && (SC_SCREENSAVE == wParam || SC_MONITORPOWER == wParam)) + { + return 0; + } + else if (nMsg == WM_QUERYENDSESSION) + { + // Indicate that the application will be able to close + return 1; + } + else if (nMsg == WM_ENDSESSION) + { + // Actually trigger the close now + Close(true); + return 0; + } + else + { + return wxFrame::MSWWindowProc(nMsg, wParam, lParam); + } } #endif -void CFrame::UpdateTitle(const std::string &str) +void CFrame::UpdateTitle(const std::string& str) { - if (SConfig::GetInstance().bRenderToMain && - SConfig::GetInstance().m_InterfaceStatusbar) - { - GetStatusBar()->SetStatusText(str, 0); - m_RenderFrame->SetTitle(scm_rev_str); - } - else - { - std::string titleStr = StringFromFormat("%s | %s", scm_rev_str.c_str(), str.c_str()); - m_RenderFrame->SetTitle(titleStr); - } + if (SConfig::GetInstance().bRenderToMain && SConfig::GetInstance().m_InterfaceStatusbar) + { + GetStatusBar()->SetStatusText(str, 0); + m_RenderFrame->SetTitle(scm_rev_str); + } + else + { + std::string titleStr = StringFromFormat("%s | %s", scm_rev_str.c_str(), str.c_str()); + m_RenderFrame->SetTitle(titleStr); + } } void CFrame::OnHostMessage(wxCommandEvent& event) { - switch (event.GetId()) - { - case IDM_UPDATE_GUI: - UpdateGUI(); - break; + switch (event.GetId()) + { + case IDM_UPDATE_GUI: + UpdateGUI(); + break; - case IDM_UPDATE_STATUS_BAR: - if (GetStatusBar() != nullptr) - GetStatusBar()->SetStatusText(event.GetString(), event.GetInt()); - break; + case IDM_UPDATE_STATUS_BAR: + if (GetStatusBar() != nullptr) + GetStatusBar()->SetStatusText(event.GetString(), event.GetInt()); + break; - case IDM_UPDATE_TITLE: - UpdateTitle(WxStrToStr(event.GetString())); - break; + case IDM_UPDATE_TITLE: + UpdateTitle(WxStrToStr(event.GetString())); + break; - case IDM_WINDOW_SIZE_REQUEST: - { - std::pair *win_size = (std::pair *)(event.GetClientData()); - OnRenderWindowSizeRequest(win_size->first, win_size->second); - delete win_size; - } - break; + case IDM_WINDOW_SIZE_REQUEST: + { + std::pair* win_size = (std::pair*)(event.GetClientData()); + OnRenderWindowSizeRequest(win_size->first, win_size->second); + delete win_size; + } + break; - case IDM_FULLSCREEN_REQUEST: - { - bool enable_fullscreen = event.GetInt() == 0 ? false : true; - ToggleDisplayMode(enable_fullscreen); - if (m_RenderFrame != nullptr) - m_RenderFrame->ShowFullScreen(enable_fullscreen); + case IDM_FULLSCREEN_REQUEST: + { + bool enable_fullscreen = event.GetInt() == 0 ? false : true; + ToggleDisplayMode(enable_fullscreen); + if (m_RenderFrame != nullptr) + m_RenderFrame->ShowFullScreen(enable_fullscreen); - // If the stop dialog initiated this fullscreen switch then we need - // to pause the emulator after we've completed the switch. - // TODO: Allow the renderer to switch fullscreen modes while paused. - if (m_confirmStop) - Core::SetState(Core::CORE_PAUSE); - } - break; + // If the stop dialog initiated this fullscreen switch then we need + // to pause the emulator after we've completed the switch. + // TODO: Allow the renderer to switch fullscreen modes while paused. + if (m_confirmStop) + Core::SetState(Core::CORE_PAUSE); + } + break; - case WM_USER_CREATE: - if (SConfig::GetInstance().bHideCursor) - m_RenderParent->SetCursor(wxCURSOR_BLANK); - break; + case WM_USER_CREATE: + if (SConfig::GetInstance().bHideCursor) + m_RenderParent->SetCursor(wxCURSOR_BLANK); + break; #ifdef __WXGTK__ - case IDM_PANIC: - { - wxString caption = event.GetString().BeforeFirst(':'); - wxString text = event.GetString().AfterFirst(':'); - bPanicResult = (wxYES == wxMessageBox(text, - caption, event.GetInt() ? wxYES_NO : wxOK, wxWindow::FindFocus())); - panic_event.Set(); - } - break; + case IDM_PANIC: + { + wxString caption = event.GetString().BeforeFirst(':'); + wxString text = event.GetString().AfterFirst(':'); + bPanicResult = (wxYES == wxMessageBox(text, caption, event.GetInt() ? wxYES_NO : wxOK, + wxWindow::FindFocus())); + panic_event.Set(); + } + break; #endif - case WM_USER_STOP: - DoStop(); - break; + case WM_USER_STOP: + DoStop(); + break; - case IDM_STOPPED: - OnStopped(); - break; + case IDM_STOPPED: + OnStopped(); + break; - case IDM_FORCE_CONNECT_WIIMOTE1: - case IDM_FORCE_CONNECT_WIIMOTE2: - case IDM_FORCE_CONNECT_WIIMOTE3: - case IDM_FORCE_CONNECT_WIIMOTE4: - case IDM_FORCE_CONNECT_BALANCEBOARD: - ConnectWiimote(event.GetId() - IDM_FORCE_CONNECT_WIIMOTE1, true); - break; + case IDM_FORCE_CONNECT_WIIMOTE1: + case IDM_FORCE_CONNECT_WIIMOTE2: + case IDM_FORCE_CONNECT_WIIMOTE3: + case IDM_FORCE_CONNECT_WIIMOTE4: + case IDM_FORCE_CONNECT_BALANCEBOARD: + ConnectWiimote(event.GetId() - IDM_FORCE_CONNECT_WIIMOTE1, true); + break; - case IDM_FORCE_DISCONNECT_WIIMOTE1: - case IDM_FORCE_DISCONNECT_WIIMOTE2: - case IDM_FORCE_DISCONNECT_WIIMOTE3: - case IDM_FORCE_DISCONNECT_WIIMOTE4: - case IDM_FORCE_DISCONNECT_BALANCEBOARD: - ConnectWiimote(event.GetId() - IDM_FORCE_DISCONNECT_WIIMOTE1, false); - break; - } + case IDM_FORCE_DISCONNECT_WIIMOTE1: + case IDM_FORCE_DISCONNECT_WIIMOTE2: + case IDM_FORCE_DISCONNECT_WIIMOTE3: + case IDM_FORCE_DISCONNECT_WIIMOTE4: + case IDM_FORCE_DISCONNECT_BALANCEBOARD: + ConnectWiimote(event.GetId() - IDM_FORCE_DISCONNECT_WIIMOTE1, false); + break; + } } void CFrame::OnRenderWindowSizeRequest(int width, int height) { - if (!Core::IsRunning() || - !SConfig::GetInstance().bRenderWindowAutoSize || - RendererIsFullscreen() || m_RenderFrame->IsMaximized()) - return; + if (!Core::IsRunning() || !SConfig::GetInstance().bRenderWindowAutoSize || + RendererIsFullscreen() || m_RenderFrame->IsMaximized()) + return; - int old_width, old_height, log_width = 0, log_height = 0; - m_RenderFrame->GetClientSize(&old_width, &old_height); + int old_width, old_height, log_width = 0, log_height = 0; + m_RenderFrame->GetClientSize(&old_width, &old_height); - // Add space for the log/console/debugger window - if (SConfig::GetInstance().bRenderToMain && - (SConfig::GetInstance().m_InterfaceLogWindow || - SConfig::GetInstance().m_InterfaceLogConfigWindow) && - !m_Mgr->GetPane("Pane 1").IsFloating()) - { - switch (m_Mgr->GetPane("Pane 1").dock_direction) - { - case wxAUI_DOCK_LEFT: - case wxAUI_DOCK_RIGHT: - log_width = m_Mgr->GetPane("Pane 1").rect.GetWidth(); - break; - case wxAUI_DOCK_TOP: - case wxAUI_DOCK_BOTTOM: - log_height = m_Mgr->GetPane("Pane 1").rect.GetHeight(); - break; - } - } + // Add space for the log/console/debugger window + if (SConfig::GetInstance().bRenderToMain && (SConfig::GetInstance().m_InterfaceLogWindow || + SConfig::GetInstance().m_InterfaceLogConfigWindow) && + !m_Mgr->GetPane("Pane 1").IsFloating()) + { + switch (m_Mgr->GetPane("Pane 1").dock_direction) + { + case wxAUI_DOCK_LEFT: + case wxAUI_DOCK_RIGHT: + log_width = m_Mgr->GetPane("Pane 1").rect.GetWidth(); + break; + case wxAUI_DOCK_TOP: + case wxAUI_DOCK_BOTTOM: + log_height = m_Mgr->GetPane("Pane 1").rect.GetHeight(); + break; + } + } - if (old_width != width + log_width || old_height != height + log_height) - m_RenderFrame->SetClientSize(width + log_width, height + log_height); + if (old_width != width + log_width || old_height != height + log_height) + m_RenderFrame->SetClientSize(width + log_width, height + log_height); } bool CFrame::RendererHasFocus() { - if (m_RenderParent == nullptr) - return false; + if (m_RenderParent == nullptr) + return false; #ifdef _WIN32 - HWND window = GetForegroundWindow(); - if (window == nullptr) - return false; + HWND window = GetForegroundWindow(); + if (window == nullptr) + return false; - if (m_RenderFrame->GetHWND() == window) - return true; + if (m_RenderFrame->GetHWND() == window) + return true; #else - wxWindow *window = wxWindow::FindFocus(); - if (window == nullptr) - return false; - // Why these different cases? - if (m_RenderParent == window || - m_RenderParent == window->GetParent() || - m_RenderParent->GetParent() == window->GetParent()) - { - return true; - } + wxWindow* window = wxWindow::FindFocus(); + if (window == nullptr) + return false; + // Why these different cases? + if (m_RenderParent == window || m_RenderParent == window->GetParent() || + m_RenderParent->GetParent() == window->GetParent()) + { + return true; + } #endif - return false; + return false; } bool CFrame::UIHasFocus() { - // UIHasFocus should return true any time any one of our UI - // windows has the focus, including any dialogs or other windows. - // - // wxWindow::FindFocus() returns the current wxWindow which has - // focus. If it's not one of our windows, then it will return - // null. + // UIHasFocus should return true any time any one of our UI + // windows has the focus, including any dialogs or other windows. + // + // wxWindow::FindFocus() returns the current wxWindow which has + // focus. If it's not one of our windows, then it will return + // null. - wxWindow *focusWindow = wxWindow::FindFocus(); - return (focusWindow != nullptr); + wxWindow* focusWindow = wxWindow::FindFocus(); + return (focusWindow != nullptr); } void CFrame::OnGameListCtrlItemActivated(wxListEvent& WXUNUSED(event)) { - // Show all platforms and regions if... - // 1. All platforms are set to hide - // 2. All Regions are set to hide - // Otherwise call BootGame to either... - // 1. Boot the selected iso - // 2. Boot the default or last loaded iso. - // 3. Call BrowseForDirectory if the gamelist is empty - if (!m_GameListCtrl->GetISO(0) && CGameListCtrl::IsHidingItems()) - { - SConfig::GetInstance().m_ListGC = - SConfig::GetInstance().m_ListWii = - SConfig::GetInstance().m_ListWad = - SConfig::GetInstance().m_ListElfDol = - SConfig::GetInstance().m_ListJap = - SConfig::GetInstance().m_ListUsa = - SConfig::GetInstance().m_ListPal = - SConfig::GetInstance().m_ListAustralia = - SConfig::GetInstance().m_ListFrance = - SConfig::GetInstance().m_ListGermany = - SConfig::GetInstance().m_ListItaly = - SConfig::GetInstance().m_ListKorea = - SConfig::GetInstance().m_ListNetherlands = - SConfig::GetInstance().m_ListRussia = - SConfig::GetInstance().m_ListSpain = - SConfig::GetInstance().m_ListTaiwan = - SConfig::GetInstance().m_ListWorld = - SConfig::GetInstance().m_ListUnknown = true; + // Show all platforms and regions if... + // 1. All platforms are set to hide + // 2. All Regions are set to hide + // Otherwise call BootGame to either... + // 1. Boot the selected iso + // 2. Boot the default or last loaded iso. + // 3. Call BrowseForDirectory if the gamelist is empty + if (!m_GameListCtrl->GetISO(0) && CGameListCtrl::IsHidingItems()) + { + SConfig::GetInstance().m_ListGC = SConfig::GetInstance().m_ListWii = + SConfig::GetInstance().m_ListWad = SConfig::GetInstance().m_ListElfDol = + SConfig::GetInstance().m_ListJap = SConfig::GetInstance().m_ListUsa = + SConfig::GetInstance().m_ListPal = SConfig::GetInstance().m_ListAustralia = + SConfig::GetInstance().m_ListFrance = SConfig::GetInstance().m_ListGermany = + SConfig::GetInstance().m_ListItaly = SConfig::GetInstance().m_ListKorea = + SConfig::GetInstance().m_ListNetherlands = + SConfig::GetInstance().m_ListRussia = + SConfig::GetInstance().m_ListSpain = + SConfig::GetInstance().m_ListTaiwan = + SConfig::GetInstance().m_ListWorld = + SConfig::GetInstance().m_ListUnknown = true; - GetMenuBar()->FindItem(IDM_LIST_GC)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_WII)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_WAD)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_JAP)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_USA)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_PAL)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_AUSTRALIA)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_FRANCE)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_GERMANY)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_ITALY)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_KOREA)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_NETHERLANDS)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_RUSSIA)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_SPAIN)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_TAIWAN)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_WORLD)->Check(true); - GetMenuBar()->FindItem(IDM_LIST_UNKNOWN)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_GC)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_WII)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_WAD)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_JAP)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_USA)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_PAL)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_AUSTRALIA)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_FRANCE)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_GERMANY)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_ITALY)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_KOREA)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_NETHERLANDS)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_RUSSIA)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_SPAIN)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_TAIWAN)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_WORLD)->Check(true); + GetMenuBar()->FindItem(IDM_LIST_UNKNOWN)->Check(true); - m_GameListCtrl->Update(); - } - else if (!m_GameListCtrl->GetISO(0)) - { - m_GameListCtrl->BrowseForDirectory(); - } - else - { - // Game started by double click - BootGame(""); - } + m_GameListCtrl->Update(); + } + else if (!m_GameListCtrl->GetISO(0)) + { + m_GameListCtrl->BrowseForDirectory(); + } + else + { + // Game started by double click + BootGame(""); + } } static bool IsHotkey(int id, bool held = false) { - return HotkeyManagerEmu::IsPressed(id, held); + return HotkeyManagerEmu::IsPressed(id, held); } int GetCmdForHotkey(unsigned int key) { - switch (key) - { - case HK_OPEN: return wxID_OPEN; - case HK_CHANGE_DISC: return IDM_CHANGE_DISC; - case HK_REFRESH_LIST: return wxID_REFRESH; - case HK_PLAY_PAUSE: return IDM_PLAY; - case HK_STOP: return IDM_STOP; - case HK_RESET: return IDM_RESET; - case HK_FRAME_ADVANCE: return IDM_FRAMESTEP; - case HK_START_RECORDING: return IDM_RECORD; - case HK_PLAY_RECORDING: return IDM_PLAY_RECORD; - case HK_EXPORT_RECORDING: return IDM_RECORD_EXPORT; - case HK_READ_ONLY_MODE: return IDM_RECORD_READ_ONLY; - case HK_FULLSCREEN: return IDM_TOGGLE_FULLSCREEN; - case HK_SCREENSHOT: return IDM_SCREENSHOT; - case HK_EXIT: return wxID_EXIT; + switch (key) + { + case HK_OPEN: + return wxID_OPEN; + case HK_CHANGE_DISC: + return IDM_CHANGE_DISC; + case HK_REFRESH_LIST: + return wxID_REFRESH; + case HK_PLAY_PAUSE: + return IDM_PLAY; + case HK_STOP: + return IDM_STOP; + case HK_RESET: + return IDM_RESET; + case HK_FRAME_ADVANCE: + return IDM_FRAMESTEP; + case HK_START_RECORDING: + return IDM_RECORD; + case HK_PLAY_RECORDING: + return IDM_PLAY_RECORD; + case HK_EXPORT_RECORDING: + return IDM_RECORD_EXPORT; + case HK_READ_ONLY_MODE: + return IDM_RECORD_READ_ONLY; + case HK_FULLSCREEN: + return IDM_TOGGLE_FULLSCREEN; + case HK_SCREENSHOT: + return IDM_SCREENSHOT; + case HK_EXIT: + return wxID_EXIT; - case HK_WIIMOTE1_CONNECT: return IDM_CONNECT_WIIMOTE1; - case HK_WIIMOTE2_CONNECT: return IDM_CONNECT_WIIMOTE2; - case HK_WIIMOTE3_CONNECT: return IDM_CONNECT_WIIMOTE3; - case HK_WIIMOTE4_CONNECT: return IDM_CONNECT_WIIMOTE4; - case HK_BALANCEBOARD_CONNECT: return IDM_CONNECT_BALANCEBOARD; + case HK_WIIMOTE1_CONNECT: + return IDM_CONNECT_WIIMOTE1; + case HK_WIIMOTE2_CONNECT: + return IDM_CONNECT_WIIMOTE2; + case HK_WIIMOTE3_CONNECT: + return IDM_CONNECT_WIIMOTE3; + case HK_WIIMOTE4_CONNECT: + return IDM_CONNECT_WIIMOTE4; + case HK_BALANCEBOARD_CONNECT: + return IDM_CONNECT_BALANCEBOARD; - case HK_LOAD_STATE_SLOT_1: return IDM_LOAD_SLOT_1; - case HK_LOAD_STATE_SLOT_2: return IDM_LOAD_SLOT_2; - case HK_LOAD_STATE_SLOT_3: return IDM_LOAD_SLOT_3; - case HK_LOAD_STATE_SLOT_4: return IDM_LOAD_SLOT_4; - case HK_LOAD_STATE_SLOT_5: return IDM_LOAD_SLOT_5; - case HK_LOAD_STATE_SLOT_6: return IDM_LOAD_SLOT_6; - case HK_LOAD_STATE_SLOT_7: return IDM_LOAD_SLOT_7; - case HK_LOAD_STATE_SLOT_8: return IDM_LOAD_SLOT_8; - case HK_LOAD_STATE_SLOT_9: return IDM_LOAD_SLOT_9; - case HK_LOAD_STATE_SLOT_10: return IDM_LOAD_SLOT_10; + case HK_LOAD_STATE_SLOT_1: + return IDM_LOAD_SLOT_1; + case HK_LOAD_STATE_SLOT_2: + return IDM_LOAD_SLOT_2; + case HK_LOAD_STATE_SLOT_3: + return IDM_LOAD_SLOT_3; + case HK_LOAD_STATE_SLOT_4: + return IDM_LOAD_SLOT_4; + case HK_LOAD_STATE_SLOT_5: + return IDM_LOAD_SLOT_5; + case HK_LOAD_STATE_SLOT_6: + return IDM_LOAD_SLOT_6; + case HK_LOAD_STATE_SLOT_7: + return IDM_LOAD_SLOT_7; + case HK_LOAD_STATE_SLOT_8: + return IDM_LOAD_SLOT_8; + case HK_LOAD_STATE_SLOT_9: + return IDM_LOAD_SLOT_9; + case HK_LOAD_STATE_SLOT_10: + return IDM_LOAD_SLOT_10; - case HK_SAVE_STATE_SLOT_1: return IDM_SAVE_SLOT_1; - case HK_SAVE_STATE_SLOT_2: return IDM_SAVE_SLOT_2; - case HK_SAVE_STATE_SLOT_3: return IDM_SAVE_SLOT_3; - case HK_SAVE_STATE_SLOT_4: return IDM_SAVE_SLOT_4; - case HK_SAVE_STATE_SLOT_5: return IDM_SAVE_SLOT_5; - case HK_SAVE_STATE_SLOT_6: return IDM_SAVE_SLOT_6; - case HK_SAVE_STATE_SLOT_7: return IDM_SAVE_SLOT_7; - case HK_SAVE_STATE_SLOT_8: return IDM_SAVE_SLOT_8; - case HK_SAVE_STATE_SLOT_9: return IDM_SAVE_SLOT_9; - case HK_SAVE_STATE_SLOT_10: return IDM_SAVE_SLOT_10; + case HK_SAVE_STATE_SLOT_1: + return IDM_SAVE_SLOT_1; + case HK_SAVE_STATE_SLOT_2: + return IDM_SAVE_SLOT_2; + case HK_SAVE_STATE_SLOT_3: + return IDM_SAVE_SLOT_3; + case HK_SAVE_STATE_SLOT_4: + return IDM_SAVE_SLOT_4; + case HK_SAVE_STATE_SLOT_5: + return IDM_SAVE_SLOT_5; + case HK_SAVE_STATE_SLOT_6: + return IDM_SAVE_SLOT_6; + case HK_SAVE_STATE_SLOT_7: + return IDM_SAVE_SLOT_7; + case HK_SAVE_STATE_SLOT_8: + return IDM_SAVE_SLOT_8; + case HK_SAVE_STATE_SLOT_9: + return IDM_SAVE_SLOT_9; + case HK_SAVE_STATE_SLOT_10: + return IDM_SAVE_SLOT_10; - case HK_LOAD_LAST_STATE_1: return IDM_LOAD_LAST_1; - case HK_LOAD_LAST_STATE_2: return IDM_LOAD_LAST_2; - case HK_LOAD_LAST_STATE_3: return IDM_LOAD_LAST_3; - case HK_LOAD_LAST_STATE_4: return IDM_LOAD_LAST_4; - case HK_LOAD_LAST_STATE_5: return IDM_LOAD_LAST_5; - case HK_LOAD_LAST_STATE_6: return IDM_LOAD_LAST_6; - case HK_LOAD_LAST_STATE_7: return IDM_LOAD_LAST_7; - case HK_LOAD_LAST_STATE_8: return IDM_LOAD_LAST_8; - case HK_LOAD_LAST_STATE_9: return IDM_LOAD_LAST_9; - case HK_LOAD_LAST_STATE_10: return IDM_LOAD_LAST_10; + case HK_LOAD_LAST_STATE_1: + return IDM_LOAD_LAST_1; + case HK_LOAD_LAST_STATE_2: + return IDM_LOAD_LAST_2; + case HK_LOAD_LAST_STATE_3: + return IDM_LOAD_LAST_3; + case HK_LOAD_LAST_STATE_4: + return IDM_LOAD_LAST_4; + case HK_LOAD_LAST_STATE_5: + return IDM_LOAD_LAST_5; + case HK_LOAD_LAST_STATE_6: + return IDM_LOAD_LAST_6; + case HK_LOAD_LAST_STATE_7: + return IDM_LOAD_LAST_7; + case HK_LOAD_LAST_STATE_8: + return IDM_LOAD_LAST_8; + case HK_LOAD_LAST_STATE_9: + return IDM_LOAD_LAST_9; + case HK_LOAD_LAST_STATE_10: + return IDM_LOAD_LAST_10; - case HK_SAVE_FIRST_STATE: return IDM_SAVE_FIRST_STATE; - case HK_UNDO_LOAD_STATE: return IDM_UNDO_LOAD_STATE; - case HK_UNDO_SAVE_STATE: return IDM_UNDO_SAVE_STATE; - case HK_LOAD_STATE_FILE: return IDM_LOAD_STATE_FILE; - case HK_SAVE_STATE_FILE: return IDM_SAVE_STATE_FILE; + case HK_SAVE_FIRST_STATE: + return IDM_SAVE_FIRST_STATE; + case HK_UNDO_LOAD_STATE: + return IDM_UNDO_LOAD_STATE; + case HK_UNDO_SAVE_STATE: + return IDM_UNDO_SAVE_STATE; + case HK_LOAD_STATE_FILE: + return IDM_LOAD_STATE_FILE; + case HK_SAVE_STATE_FILE: + return IDM_SAVE_STATE_FILE; - case HK_SELECT_STATE_SLOT_1: return IDM_SELECT_SLOT_1; - case HK_SELECT_STATE_SLOT_2: return IDM_SELECT_SLOT_2; - case HK_SELECT_STATE_SLOT_3: return IDM_SELECT_SLOT_3; - case HK_SELECT_STATE_SLOT_4: return IDM_SELECT_SLOT_4; - case HK_SELECT_STATE_SLOT_5: return IDM_SELECT_SLOT_5; - case HK_SELECT_STATE_SLOT_6: return IDM_SELECT_SLOT_6; - case HK_SELECT_STATE_SLOT_7: return IDM_SELECT_SLOT_7; - case HK_SELECT_STATE_SLOT_8: return IDM_SELECT_SLOT_8; - case HK_SELECT_STATE_SLOT_9: return IDM_SELECT_SLOT_9; - case HK_SELECT_STATE_SLOT_10: return IDM_SELECT_SLOT_10; - case HK_SAVE_STATE_SLOT_SELECTED: return IDM_SAVE_SELECTED_SLOT; - case HK_LOAD_STATE_SLOT_SELECTED: return IDM_LOAD_SELECTED_SLOT; + case HK_SELECT_STATE_SLOT_1: + return IDM_SELECT_SLOT_1; + case HK_SELECT_STATE_SLOT_2: + return IDM_SELECT_SLOT_2; + case HK_SELECT_STATE_SLOT_3: + return IDM_SELECT_SLOT_3; + case HK_SELECT_STATE_SLOT_4: + return IDM_SELECT_SLOT_4; + case HK_SELECT_STATE_SLOT_5: + return IDM_SELECT_SLOT_5; + case HK_SELECT_STATE_SLOT_6: + return IDM_SELECT_SLOT_6; + case HK_SELECT_STATE_SLOT_7: + return IDM_SELECT_SLOT_7; + case HK_SELECT_STATE_SLOT_8: + return IDM_SELECT_SLOT_8; + case HK_SELECT_STATE_SLOT_9: + return IDM_SELECT_SLOT_9; + case HK_SELECT_STATE_SLOT_10: + return IDM_SELECT_SLOT_10; + case HK_SAVE_STATE_SLOT_SELECTED: + return IDM_SAVE_SELECTED_SLOT; + case HK_LOAD_STATE_SLOT_SELECTED: + return IDM_LOAD_SELECTED_SLOT; - case HK_FREELOOK_DECREASE_SPEED: return IDM_FREELOOK_DECREASE_SPEED; - case HK_FREELOOK_INCREASE_SPEED: return IDM_FREELOOK_INCREASE_SPEED; - case HK_FREELOOK_RESET_SPEED: return IDM_FREELOOK_RESET_SPEED; - case HK_FREELOOK_LEFT: return IDM_FREELOOK_LEFT; - case HK_FREELOOK_RIGHT: return IDM_FREELOOK_RIGHT; - case HK_FREELOOK_UP: return IDM_FREELOOK_UP; - case HK_FREELOOK_DOWN: return IDM_FREELOOK_DOWN; - case HK_FREELOOK_ZOOM_IN: return IDM_FREELOOK_ZOOM_IN; - case HK_FREELOOK_ZOOM_OUT: return IDM_FREELOOK_ZOOM_OUT; - case HK_FREELOOK_RESET: return IDM_FREELOOK_RESET; - } + case HK_FREELOOK_DECREASE_SPEED: + return IDM_FREELOOK_DECREASE_SPEED; + case HK_FREELOOK_INCREASE_SPEED: + return IDM_FREELOOK_INCREASE_SPEED; + case HK_FREELOOK_RESET_SPEED: + return IDM_FREELOOK_RESET_SPEED; + case HK_FREELOOK_LEFT: + return IDM_FREELOOK_LEFT; + case HK_FREELOOK_RIGHT: + return IDM_FREELOOK_RIGHT; + case HK_FREELOOK_UP: + return IDM_FREELOOK_UP; + case HK_FREELOOK_DOWN: + return IDM_FREELOOK_DOWN; + case HK_FREELOOK_ZOOM_IN: + return IDM_FREELOOK_ZOOM_IN; + case HK_FREELOOK_ZOOM_OUT: + return IDM_FREELOOK_ZOOM_OUT; + case HK_FREELOOK_RESET: + return IDM_FREELOOK_RESET; + } - return -1; + return -1; } void OnAfterLoadCallback() { - // warning: this gets called from the CPU thread, so we should only queue things to do on the proper thread - if (main_frame) - { - wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_UPDATE_GUI); - main_frame->GetEventHandler()->AddPendingEvent(event); - } + // warning: this gets called from the CPU thread, so we should only queue things to do on the + // proper thread + if (main_frame) + { + wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_UPDATE_GUI); + main_frame->GetEventHandler()->AddPendingEvent(event); + } } void OnStoppedCallback() { - // warning: this gets called from the EmuThread, so we should only queue things to do on the proper thread - if (main_frame) - { - wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_STOPPED); - main_frame->GetEventHandler()->AddPendingEvent(event); - } + // warning: this gets called from the EmuThread, so we should only queue things to do on the + // proper thread + if (main_frame) + { + wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_STOPPED); + main_frame->GetEventHandler()->AddPendingEvent(event); + } } void GCTASManipFunction(GCPadStatus* PadStatus, int controllerID) { - if (main_frame) - main_frame->g_TASInputDlg[controllerID]->GetValues(PadStatus); + if (main_frame) + main_frame->g_TASInputDlg[controllerID]->GetValues(PadStatus); } -void WiiTASManipFunction(u8* data, WiimoteEmu::ReportFeatures rptf, int controllerID, int ext, const wiimote_key key) +void WiiTASManipFunction(u8* data, WiimoteEmu::ReportFeatures rptf, int controllerID, int ext, + const wiimote_key key) { - if (main_frame) - { - main_frame->g_TASInputDlg[controllerID + 4]->GetValues(data, rptf, ext, key); - } + if (main_frame) + { + main_frame->g_TASInputDlg[controllerID + 4]->GetValues(data, rptf, ext, key); + } } void CFrame::OnKeyDown(wxKeyEvent& event) { - // On OS X, we claim all keyboard events while - // emulation is running to avoid wxWidgets sounding - // the system beep for unhandled key events when - // receiving pad/Wiimote keypresses which take an - // entirely different path through the HID subsystem. +// On OS X, we claim all keyboard events while +// emulation is running to avoid wxWidgets sounding +// the system beep for unhandled key events when +// receiving pad/Wiimote keypresses which take an +// entirely different path through the HID subsystem. #ifndef __APPLE__ - // On other platforms, we leave the key event alone - // so it can be passed on to the windowing system. - event.Skip(); + // On other platforms, we leave the key event alone + // so it can be passed on to the windowing system. + event.Skip(); #endif } void CFrame::OnMouse(wxMouseEvent& event) { - // next handlers are all for FreeLook, so we don't need to check them if disabled - if (!g_Config.bFreeLook) - { - event.Skip(); - return; - } + // next handlers are all for FreeLook, so we don't need to check them if disabled + if (!g_Config.bFreeLook) + { + event.Skip(); + return; + } - // Free look variables - static bool mouseLookEnabled = false; - static bool mouseMoveEnabled = false; - static float lastMouse[2]; + // Free look variables + static bool mouseLookEnabled = false; + static bool mouseMoveEnabled = false; + static float lastMouse[2]; - if (event.MiddleDown()) - { - lastMouse[0] = event.GetX(); - lastMouse[1] = event.GetY(); - mouseMoveEnabled = true; - } - else if (event.RightDown()) - { - lastMouse[0] = event.GetX(); - lastMouse[1] = event.GetY(); - mouseLookEnabled = true; - } - else if (event.MiddleUp()) - { - mouseMoveEnabled = false; - } - else if (event.RightUp()) - { - mouseLookEnabled = false; - } - // no button, so it's a move event - else if (event.GetButton() == wxMOUSE_BTN_NONE) - { - if (mouseLookEnabled) - { - VertexShaderManager::RotateView((event.GetX() - lastMouse[0]) / 200.0f, - (event.GetY() - lastMouse[1]) / 200.0f); - lastMouse[0] = event.GetX(); - lastMouse[1] = event.GetY(); - } + if (event.MiddleDown()) + { + lastMouse[0] = event.GetX(); + lastMouse[1] = event.GetY(); + mouseMoveEnabled = true; + } + else if (event.RightDown()) + { + lastMouse[0] = event.GetX(); + lastMouse[1] = event.GetY(); + mouseLookEnabled = true; + } + else if (event.MiddleUp()) + { + mouseMoveEnabled = false; + } + else if (event.RightUp()) + { + mouseLookEnabled = false; + } + // no button, so it's a move event + else if (event.GetButton() == wxMOUSE_BTN_NONE) + { + if (mouseLookEnabled) + { + VertexShaderManager::RotateView((event.GetX() - lastMouse[0]) / 200.0f, + (event.GetY() - lastMouse[1]) / 200.0f); + lastMouse[0] = event.GetX(); + lastMouse[1] = event.GetY(); + } - if (mouseMoveEnabled) - { - VertexShaderManager::TranslateView((event.GetX() - lastMouse[0]) / 50.0f, - (event.GetY() - lastMouse[1]) / 50.0f); - lastMouse[0] = event.GetX(); - lastMouse[1] = event.GetY(); - } - } + if (mouseMoveEnabled) + { + VertexShaderManager::TranslateView((event.GetX() - lastMouse[0]) / 50.0f, + (event.GetY() - lastMouse[1]) / 50.0f); + lastMouse[0] = event.GetX(); + lastMouse[1] = event.GetY(); + } + } - event.Skip(); + event.Skip(); } void CFrame::OnFocusChange(wxFocusEvent& event) { - if (SConfig::GetInstance().m_PauseOnFocusLost && Core::IsRunningAndStarted()) - { - if (RendererHasFocus()) - { - if (Core::GetState() == Core::CORE_PAUSE) - { - Core::SetState(Core::CORE_RUN); - if (SConfig::GetInstance().bHideCursor) - m_RenderParent->SetCursor(wxCURSOR_BLANK); - } - } - else - { - if (Core::GetState() == Core::CORE_RUN) - { - Core::SetState(Core::CORE_PAUSE); - if (SConfig::GetInstance().bHideCursor) - m_RenderParent->SetCursor(wxNullCursor); - Core::UpdateTitle(); - } - } - UpdateGUI(); - } + if (SConfig::GetInstance().m_PauseOnFocusLost && Core::IsRunningAndStarted()) + { + if (RendererHasFocus()) + { + if (Core::GetState() == Core::CORE_PAUSE) + { + Core::SetState(Core::CORE_RUN); + if (SConfig::GetInstance().bHideCursor) + m_RenderParent->SetCursor(wxCURSOR_BLANK); + } + } + else + { + if (Core::GetState() == Core::CORE_RUN) + { + Core::SetState(Core::CORE_PAUSE); + if (SConfig::GetInstance().bHideCursor) + m_RenderParent->SetCursor(wxNullCursor); + Core::UpdateTitle(); + } + } + UpdateGUI(); + } - event.Skip(); + event.Skip(); } void CFrame::DoFullscreen(bool enable_fullscreen) { - if (g_Config.bExclusiveMode && Core::GetState() == Core::CORE_PAUSE) - { - // A responsive renderer is required for exclusive fullscreen, but the - // renderer can only respond in the running state. Therefore we ignore - // fullscreen switches if we are in exclusive fullscreen, but the - // renderer is not running. - // TODO: Allow the renderer to switch fullscreen modes while paused. - return; - } + if (g_Config.bExclusiveMode && Core::GetState() == Core::CORE_PAUSE) + { + // A responsive renderer is required for exclusive fullscreen, but the + // renderer can only respond in the running state. Therefore we ignore + // fullscreen switches if we are in exclusive fullscreen, but the + // renderer is not running. + // TODO: Allow the renderer to switch fullscreen modes while paused. + return; + } - ToggleDisplayMode(enable_fullscreen); + ToggleDisplayMode(enable_fullscreen); #if defined(__APPLE__) - NSView *view = (NSView *)m_RenderFrame->GetHandle(); - NSWindow *window = [view window]; + NSView* view = (NSView*)m_RenderFrame->GetHandle(); + NSWindow* window = [view window]; - if (enable_fullscreen != RendererIsFullscreen()) - { - [window toggleFullScreen : nil]; - } + if (enable_fullscreen != RendererIsFullscreen()) + { + [window toggleFullScreen:nil]; + } #else - if (enable_fullscreen) - { - m_RenderFrame->ShowFullScreen(true, wxFULLSCREEN_ALL); - } - else if (!g_Config.bExclusiveMode) - { - // Exiting exclusive fullscreen should be done from a Renderer callback. - // Therefore we don't exit fullscreen from here if we are in exclusive mode. - m_RenderFrame->ShowFullScreen(false, wxFULLSCREEN_ALL); - } + if (enable_fullscreen) + { + m_RenderFrame->ShowFullScreen(true, wxFULLSCREEN_ALL); + } + else if (!g_Config.bExclusiveMode) + { + // Exiting exclusive fullscreen should be done from a Renderer callback. + // Therefore we don't exit fullscreen from here if we are in exclusive mode. + m_RenderFrame->ShowFullScreen(false, wxFULLSCREEN_ALL); + } #endif - if (SConfig::GetInstance().bRenderToMain) - { - if (enable_fullscreen) - { - // Save the current mode before going to fullscreen - AuiCurrent = m_Mgr->SavePerspective(); - m_Mgr->LoadPerspective(AuiFullscreen, true); + if (SConfig::GetInstance().bRenderToMain) + { + if (enable_fullscreen) + { + // Save the current mode before going to fullscreen + AuiCurrent = m_Mgr->SavePerspective(); + m_Mgr->LoadPerspective(AuiFullscreen, true); - // Hide toolbar - DoToggleToolbar(false); + // Hide toolbar + DoToggleToolbar(false); - // Hide menubar (by having wxwidgets delete it) - SetMenuBar(nullptr); + // Hide menubar (by having wxwidgets delete it) + SetMenuBar(nullptr); - // Hide the statusbar if enabled - if (GetStatusBar()->IsShown()) - { - GetStatusBar()->Hide(); - this->SendSizeEvent(); - } - } - else - { - // Restore saved perspective - m_Mgr->LoadPerspective(AuiCurrent, true); + // Hide the statusbar if enabled + if (GetStatusBar()->IsShown()) + { + GetStatusBar()->Hide(); + this->SendSizeEvent(); + } + } + else + { + // Restore saved perspective + m_Mgr->LoadPerspective(AuiCurrent, true); - // Restore toolbar to the status it was at before going fullscreen. - DoToggleToolbar(SConfig::GetInstance().m_InterfaceToolbar); + // Restore toolbar to the status it was at before going fullscreen. + DoToggleToolbar(SConfig::GetInstance().m_InterfaceToolbar); - // Recreate the menubar if needed. - if (wxFrame::GetMenuBar() == nullptr) - { - SetMenuBar(CreateMenu()); - } + // Recreate the menubar if needed. + if (wxFrame::GetMenuBar() == nullptr) + { + SetMenuBar(CreateMenu()); + } - // Show statusbar if enabled - if (SConfig::GetInstance().m_InterfaceStatusbar) - { - GetStatusBar()->Show(); - this->SendSizeEvent(); - } - } - } - else - { - m_RenderFrame->Raise(); - } + // Show statusbar if enabled + if (SConfig::GetInstance().m_InterfaceStatusbar) + { + GetStatusBar()->Show(); + this->SendSizeEvent(); + } + } + } + else + { + m_RenderFrame->Raise(); + } - g_Config.bFullscreen = enable_fullscreen; + g_Config.bFullscreen = enable_fullscreen; } -const CGameListCtrl *CFrame::GetGameListCtrl() const +const CGameListCtrl* CFrame::GetGameListCtrl() const { - return m_GameListCtrl; + return m_GameListCtrl; } void CFrame::PollHotkeys(wxTimerEvent& event) { - if (!HotkeyManagerEmu::IsEnabled()) - return; + if (!HotkeyManagerEmu::IsEnabled()) + return; - if (Core::GetState() == Core::CORE_UNINITIALIZED || Core::GetState() == Core::CORE_PAUSE) - g_controller_interface.UpdateInput(); + if (Core::GetState() == Core::CORE_UNINITIALIZED || Core::GetState() == Core::CORE_PAUSE) + g_controller_interface.UpdateInput(); - if (Core::GetState() != Core::CORE_STOPPING) - { - HotkeyManagerEmu::GetStatus(); - ParseHotkeys(); - } + if (Core::GetState() != Core::CORE_STOPPING) + { + HotkeyManagerEmu::GetStatus(); + ParseHotkeys(); + } } void CFrame::ParseHotkeys() { - for (int i = 0; i < NUM_HOTKEYS; i++) - { - switch (i) - { - case HK_OPEN: - case HK_CHANGE_DISC: - case HK_REFRESH_LIST: - case HK_RESET: - case HK_START_RECORDING: - case HK_PLAY_RECORDING: - case HK_EXPORT_RECORDING: - case HK_READ_ONLY_MODE: + for (int i = 0; i < NUM_HOTKEYS; i++) + { + switch (i) + { + case HK_OPEN: + case HK_CHANGE_DISC: + case HK_REFRESH_LIST: + case HK_RESET: + case HK_START_RECORDING: + case HK_PLAY_RECORDING: + case HK_EXPORT_RECORDING: + case HK_READ_ONLY_MODE: - case HK_LOAD_STATE_FILE: - case HK_SAVE_STATE_FILE: - case HK_LOAD_STATE_SLOT_SELECTED: + case HK_LOAD_STATE_FILE: + case HK_SAVE_STATE_FILE: + case HK_LOAD_STATE_SLOT_SELECTED: - if (IsHotkey(i)) - { - int cmd = GetCmdForHotkey(i); - if (cmd >= 0) - { - wxCommandEvent evt(wxEVT_MENU, cmd); - wxMenuItem* item = GetMenuBar()->FindItem(cmd); - if (item && item->IsCheckable()) - { - item->wxMenuItemBase::Toggle(); - evt.SetInt(item->IsChecked()); - } - GetEventHandler()->AddPendingEvent(evt); - } - } - default: - break; - // do nothing - } - } + if (IsHotkey(i)) + { + int cmd = GetCmdForHotkey(i); + if (cmd >= 0) + { + wxCommandEvent evt(wxEVT_MENU, cmd); + wxMenuItem* item = GetMenuBar()->FindItem(cmd); + if (item && item->IsCheckable()) + { + item->wxMenuItemBase::Toggle(); + evt.SetInt(item->IsChecked()); + } + GetEventHandler()->AddPendingEvent(evt); + } + } + default: + break; + // do nothing + } + } - if (!Core::IsRunningAndStarted()) - { - return; - } + if (!Core::IsRunningAndStarted()) + { + return; + } - // Toggle fullscreen - if (IsHotkey(HK_FULLSCREEN)) - DoFullscreen(!RendererIsFullscreen()); - // Pause and Unpause - if (IsHotkey(HK_PLAY_PAUSE)) - DoPause(); - // Frame advance - HandleFrameSkipHotkeys(); - // Stop - if (IsHotkey(HK_STOP)) - DoStop(); - // Screenshot hotkey - if (IsHotkey(HK_SCREENSHOT)) - Core::SaveScreenShot(); - if (IsHotkey(HK_EXIT)) - wxPostEvent(this, wxCommandEvent(wxEVT_MENU, wxID_EXIT)); - if (IsHotkey(HK_VOLUME_DOWN)) - AudioCommon::DecreaseVolume(3); - if (IsHotkey(HK_VOLUME_UP)) - AudioCommon::IncreaseVolume(3); - if (IsHotkey(HK_VOLUME_TOGGLE_MUTE)) - AudioCommon::ToggleMuteVolume(); + // Toggle fullscreen + if (IsHotkey(HK_FULLSCREEN)) + DoFullscreen(!RendererIsFullscreen()); + // Pause and Unpause + if (IsHotkey(HK_PLAY_PAUSE)) + DoPause(); + // Frame advance + HandleFrameSkipHotkeys(); + // Stop + if (IsHotkey(HK_STOP)) + DoStop(); + // Screenshot hotkey + if (IsHotkey(HK_SCREENSHOT)) + Core::SaveScreenShot(); + if (IsHotkey(HK_EXIT)) + wxPostEvent(this, wxCommandEvent(wxEVT_MENU, wxID_EXIT)); + if (IsHotkey(HK_VOLUME_DOWN)) + AudioCommon::DecreaseVolume(3); + if (IsHotkey(HK_VOLUME_UP)) + AudioCommon::IncreaseVolume(3); + if (IsHotkey(HK_VOLUME_TOGGLE_MUTE)) + AudioCommon::ToggleMuteVolume(); - // Wiimote connect and disconnect hotkeys - int WiimoteId = -1; - if (IsHotkey(HK_WIIMOTE1_CONNECT)) - WiimoteId = 0; - if (IsHotkey(HK_WIIMOTE2_CONNECT)) - WiimoteId = 1; - if (IsHotkey(HK_WIIMOTE3_CONNECT)) - WiimoteId = 2; - if (IsHotkey(HK_WIIMOTE4_CONNECT)) - WiimoteId = 3; - if (IsHotkey(HK_BALANCEBOARD_CONNECT)) - WiimoteId = 4; + // Wiimote connect and disconnect hotkeys + int WiimoteId = -1; + if (IsHotkey(HK_WIIMOTE1_CONNECT)) + WiimoteId = 0; + if (IsHotkey(HK_WIIMOTE2_CONNECT)) + WiimoteId = 1; + if (IsHotkey(HK_WIIMOTE3_CONNECT)) + WiimoteId = 2; + if (IsHotkey(HK_WIIMOTE4_CONNECT)) + WiimoteId = 3; + if (IsHotkey(HK_BALANCEBOARD_CONNECT)) + WiimoteId = 4; - // Actually perform the Wiimote connection or disconnection - if (WiimoteId >= 0 && SConfig::GetInstance().bWii) - { - wxCommandEvent evt; - evt.SetId(IDM_CONNECT_WIIMOTE1 + WiimoteId); - OnConnectWiimote(evt); - } + // Actually perform the Wiimote connection or disconnection + if (WiimoteId >= 0 && SConfig::GetInstance().bWii) + { + wxCommandEvent evt; + evt.SetId(IDM_CONNECT_WIIMOTE1 + WiimoteId); + OnConnectWiimote(evt); + } - if (IsHotkey(HK_INCREASE_IR)) - { - OSDChoice = 1; - ++g_Config.iEFBScale; - } - if (IsHotkey(HK_DECREASE_IR)) - { - OSDChoice = 1; - if (--g_Config.iEFBScale < SCALE_AUTO) - g_Config.iEFBScale = SCALE_AUTO; - } - if (IsHotkey(HK_TOGGLE_CROP)) - { - g_Config.bCrop = !g_Config.bCrop; - } - if (IsHotkey(HK_TOGGLE_AR)) - { - OSDChoice = 2; - // Toggle aspect ratio - g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3; - } - if (IsHotkey(HK_TOGGLE_EFBCOPIES)) - { - OSDChoice = 3; - // Toggle EFB copies between EFB2RAM and EFB2Texture - g_Config.bSkipEFBCopyToRam = !g_Config.bSkipEFBCopyToRam; - } - if (IsHotkey(HK_TOGGLE_FOG)) - { - OSDChoice = 4; - g_Config.bDisableFog = !g_Config.bDisableFog; - } - Core::SetIsThrottlerTempDisabled(IsHotkey(HK_TOGGLE_THROTTLE, true)); - if (IsHotkey(HK_DECREASE_EMULATION_SPEED)) - { - OSDChoice = 5; + if (IsHotkey(HK_INCREASE_IR)) + { + OSDChoice = 1; + ++g_Config.iEFBScale; + } + if (IsHotkey(HK_DECREASE_IR)) + { + OSDChoice = 1; + if (--g_Config.iEFBScale < SCALE_AUTO) + g_Config.iEFBScale = SCALE_AUTO; + } + if (IsHotkey(HK_TOGGLE_CROP)) + { + g_Config.bCrop = !g_Config.bCrop; + } + if (IsHotkey(HK_TOGGLE_AR)) + { + OSDChoice = 2; + // Toggle aspect ratio + g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3; + } + if (IsHotkey(HK_TOGGLE_EFBCOPIES)) + { + OSDChoice = 3; + // Toggle EFB copies between EFB2RAM and EFB2Texture + g_Config.bSkipEFBCopyToRam = !g_Config.bSkipEFBCopyToRam; + } + if (IsHotkey(HK_TOGGLE_FOG)) + { + OSDChoice = 4; + g_Config.bDisableFog = !g_Config.bDisableFog; + } + Core::SetIsThrottlerTempDisabled(IsHotkey(HK_TOGGLE_THROTTLE, true)); + if (IsHotkey(HK_DECREASE_EMULATION_SPEED)) + { + OSDChoice = 5; - if (SConfig::GetInstance().m_EmulationSpeed <= 0.0f) - SConfig::GetInstance().m_EmulationSpeed = 1.0f; - else if (SConfig::GetInstance().m_EmulationSpeed >= 0.2f) - SConfig::GetInstance().m_EmulationSpeed -= 0.1f; - else - SConfig::GetInstance().m_EmulationSpeed = 0.1f; + if (SConfig::GetInstance().m_EmulationSpeed <= 0.0f) + SConfig::GetInstance().m_EmulationSpeed = 1.0f; + else if (SConfig::GetInstance().m_EmulationSpeed >= 0.2f) + SConfig::GetInstance().m_EmulationSpeed -= 0.1f; + else + SConfig::GetInstance().m_EmulationSpeed = 0.1f; - if (SConfig::GetInstance().m_EmulationSpeed >= 0.95f && SConfig::GetInstance().m_EmulationSpeed <= 1.05f) - SConfig::GetInstance().m_EmulationSpeed = 1.0f; - } - if (IsHotkey(HK_INCREASE_EMULATION_SPEED)) - { - OSDChoice = 5; + if (SConfig::GetInstance().m_EmulationSpeed >= 0.95f && + SConfig::GetInstance().m_EmulationSpeed <= 1.05f) + SConfig::GetInstance().m_EmulationSpeed = 1.0f; + } + if (IsHotkey(HK_INCREASE_EMULATION_SPEED)) + { + OSDChoice = 5; - if (SConfig::GetInstance().m_EmulationSpeed > 0.0f) - SConfig::GetInstance().m_EmulationSpeed += 0.1f; + if (SConfig::GetInstance().m_EmulationSpeed > 0.0f) + SConfig::GetInstance().m_EmulationSpeed += 0.1f; - if (SConfig::GetInstance().m_EmulationSpeed >= 0.95f && SConfig::GetInstance().m_EmulationSpeed <= 1.05f) - SConfig::GetInstance().m_EmulationSpeed = 1.0f; - } - if (IsHotkey(HK_SAVE_STATE_SLOT_SELECTED)) - { - State::Save(g_saveSlot); - } - if (IsHotkey(HK_LOAD_STATE_SLOT_SELECTED)) - { - State::Load(g_saveSlot); - } + if (SConfig::GetInstance().m_EmulationSpeed >= 0.95f && + SConfig::GetInstance().m_EmulationSpeed <= 1.05f) + SConfig::GetInstance().m_EmulationSpeed = 1.0f; + } + if (IsHotkey(HK_SAVE_STATE_SLOT_SELECTED)) + { + State::Save(g_saveSlot); + } + if (IsHotkey(HK_LOAD_STATE_SLOT_SELECTED)) + { + State::Load(g_saveSlot); + } - if (IsHotkey(HK_TOGGLE_STEREO_SBS)) - { - if (g_Config.iStereoMode != STEREO_SBS) - { - // Current implementation of anaglyph stereoscopy uses a - // post-processing shader. Thus the shader needs to be to be - // turned off when selecting other stereoscopy modes. - if (g_Config.sPostProcessingShader == "dubois") - { - g_Config.sPostProcessingShader = ""; - } - g_Config.iStereoMode = STEREO_SBS; - } - else - { - g_Config.iStereoMode = STEREO_OFF; - } - } - if (IsHotkey(HK_TOGGLE_STEREO_TAB)) - { - if (g_Config.iStereoMode != STEREO_TAB) - { - if (g_Config.sPostProcessingShader == "dubois") - { - g_Config.sPostProcessingShader = ""; - } - g_Config.iStereoMode = STEREO_TAB; - } - else - { - g_Config.iStereoMode = STEREO_OFF; - } - } - if (IsHotkey(HK_TOGGLE_STEREO_ANAGLYPH)) - { - if (g_Config.iStereoMode != STEREO_ANAGLYPH) - { - // Setting the anaglyph mode also requires a specific - // post-processing shader to be activated. - g_Config.iStereoMode = STEREO_ANAGLYPH; - g_Config.sPostProcessingShader = "dubois"; - } - else - { - g_Config.iStereoMode = STEREO_OFF; - g_Config.sPostProcessingShader = ""; - } - } - if (IsHotkey(HK_TOGGLE_STEREO_3DVISION)) - { - if (g_Config.iStereoMode != STEREO_3DVISION) - { - if (g_Config.sPostProcessingShader == "dubois") - { - g_Config.sPostProcessingShader = ""; - } - g_Config.iStereoMode = STEREO_3DVISION; - } - else - { - g_Config.iStereoMode = STEREO_OFF; - } - } + if (IsHotkey(HK_TOGGLE_STEREO_SBS)) + { + if (g_Config.iStereoMode != STEREO_SBS) + { + // Current implementation of anaglyph stereoscopy uses a + // post-processing shader. Thus the shader needs to be to be + // turned off when selecting other stereoscopy modes. + if (g_Config.sPostProcessingShader == "dubois") + { + g_Config.sPostProcessingShader = ""; + } + g_Config.iStereoMode = STEREO_SBS; + } + else + { + g_Config.iStereoMode = STEREO_OFF; + } + } + if (IsHotkey(HK_TOGGLE_STEREO_TAB)) + { + if (g_Config.iStereoMode != STEREO_TAB) + { + if (g_Config.sPostProcessingShader == "dubois") + { + g_Config.sPostProcessingShader = ""; + } + g_Config.iStereoMode = STEREO_TAB; + } + else + { + g_Config.iStereoMode = STEREO_OFF; + } + } + if (IsHotkey(HK_TOGGLE_STEREO_ANAGLYPH)) + { + if (g_Config.iStereoMode != STEREO_ANAGLYPH) + { + // Setting the anaglyph mode also requires a specific + // post-processing shader to be activated. + g_Config.iStereoMode = STEREO_ANAGLYPH; + g_Config.sPostProcessingShader = "dubois"; + } + else + { + g_Config.iStereoMode = STEREO_OFF; + g_Config.sPostProcessingShader = ""; + } + } + if (IsHotkey(HK_TOGGLE_STEREO_3DVISION)) + { + if (g_Config.iStereoMode != STEREO_3DVISION) + { + if (g_Config.sPostProcessingShader == "dubois") + { + g_Config.sPostProcessingShader = ""; + } + g_Config.iStereoMode = STEREO_3DVISION; + } + else + { + g_Config.iStereoMode = STEREO_OFF; + } + } - if (IsHotkey(HK_DECREASE_DEPTH, true)) - { - if (--g_Config.iStereoDepth < 0) - g_Config.iStereoDepth = 0; - } - if (IsHotkey(HK_INCREASE_DEPTH, true)) - { - if (++g_Config.iStereoDepth > 100) - g_Config.iStereoDepth = 100; - } - if (IsHotkey(HK_DECREASE_CONVERGENCE, true)) - { - g_Config.iStereoConvergence -= 5; - if (g_Config.iStereoConvergence < 0) - g_Config.iStereoConvergence = 0; - } - if (IsHotkey(HK_INCREASE_CONVERGENCE, true)) - { - g_Config.iStereoConvergence += 5; - if (g_Config.iStereoConvergence > 500) - g_Config.iStereoConvergence = 500; - } + if (IsHotkey(HK_DECREASE_DEPTH, true)) + { + if (--g_Config.iStereoDepth < 0) + g_Config.iStereoDepth = 0; + } + if (IsHotkey(HK_INCREASE_DEPTH, true)) + { + if (++g_Config.iStereoDepth > 100) + g_Config.iStereoDepth = 100; + } + if (IsHotkey(HK_DECREASE_CONVERGENCE, true)) + { + g_Config.iStereoConvergence -= 5; + if (g_Config.iStereoConvergence < 0) + g_Config.iStereoConvergence = 0; + } + if (IsHotkey(HK_INCREASE_CONVERGENCE, true)) + { + g_Config.iStereoConvergence += 5; + if (g_Config.iStereoConvergence > 500) + g_Config.iStereoConvergence = 500; + } - static float debugSpeed = 1.0f; - if (IsHotkey(HK_FREELOOK_DECREASE_SPEED, true)) - debugSpeed /= 1.1f; - if (IsHotkey(HK_FREELOOK_INCREASE_SPEED, true)) - debugSpeed *= 1.1f; - if (IsHotkey(HK_FREELOOK_RESET_SPEED, true)) - debugSpeed = 1.0f; - if (IsHotkey(HK_FREELOOK_UP, true)) - VertexShaderManager::TranslateView(0.0f, 0.0f, -debugSpeed); - if (IsHotkey(HK_FREELOOK_DOWN, true)) - VertexShaderManager::TranslateView(0.0f, 0.0f, debugSpeed); - if (IsHotkey(HK_FREELOOK_LEFT, true)) - VertexShaderManager::TranslateView(debugSpeed, 0.0f); - if (IsHotkey(HK_FREELOOK_RIGHT, true)) - VertexShaderManager::TranslateView(-debugSpeed, 0.0f); - if (IsHotkey(HK_FREELOOK_ZOOM_IN, true)) - VertexShaderManager::TranslateView(0.0f, debugSpeed); - if (IsHotkey(HK_FREELOOK_ZOOM_OUT, true)) - VertexShaderManager::TranslateView(0.0f, -debugSpeed); - if (IsHotkey(HK_FREELOOK_RESET, true)) - VertexShaderManager::ResetView(); + static float debugSpeed = 1.0f; + if (IsHotkey(HK_FREELOOK_DECREASE_SPEED, true)) + debugSpeed /= 1.1f; + if (IsHotkey(HK_FREELOOK_INCREASE_SPEED, true)) + debugSpeed *= 1.1f; + if (IsHotkey(HK_FREELOOK_RESET_SPEED, true)) + debugSpeed = 1.0f; + if (IsHotkey(HK_FREELOOK_UP, true)) + VertexShaderManager::TranslateView(0.0f, 0.0f, -debugSpeed); + if (IsHotkey(HK_FREELOOK_DOWN, true)) + VertexShaderManager::TranslateView(0.0f, 0.0f, debugSpeed); + if (IsHotkey(HK_FREELOOK_LEFT, true)) + VertexShaderManager::TranslateView(debugSpeed, 0.0f); + if (IsHotkey(HK_FREELOOK_RIGHT, true)) + VertexShaderManager::TranslateView(-debugSpeed, 0.0f); + if (IsHotkey(HK_FREELOOK_ZOOM_IN, true)) + VertexShaderManager::TranslateView(0.0f, debugSpeed); + if (IsHotkey(HK_FREELOOK_ZOOM_OUT, true)) + VertexShaderManager::TranslateView(0.0f, -debugSpeed); + if (IsHotkey(HK_FREELOOK_RESET, true)) + VertexShaderManager::ResetView(); - // Savestates - for (u32 i = 0; i < State::NUM_STATES; i++) - { - if (IsHotkey(HK_LOAD_STATE_SLOT_1 + i)) - State::Load(1 + i); + // Savestates + for (u32 i = 0; i < State::NUM_STATES; i++) + { + if (IsHotkey(HK_LOAD_STATE_SLOT_1 + i)) + State::Load(1 + i); - if (IsHotkey(HK_SAVE_STATE_SLOT_1 + i)) - State::Save(1 + i); + if (IsHotkey(HK_SAVE_STATE_SLOT_1 + i)) + State::Save(1 + i); - if (IsHotkey(HK_LOAD_LAST_STATE_1 + i)) - State::LoadLastSaved(1 + i); + if (IsHotkey(HK_LOAD_LAST_STATE_1 + i)) + State::LoadLastSaved(1 + i); - if (IsHotkey(HK_SELECT_STATE_SLOT_1 + i)) - { - wxCommandEvent slot_event; - slot_event.SetId(IDM_SELECT_SLOT_1 + i); - CFrame::OnSelectSlot(slot_event); - } - } - if (IsHotkey(HK_SAVE_FIRST_STATE)) - State::SaveFirstSaved(); - if (IsHotkey(HK_UNDO_LOAD_STATE)) - State::UndoLoadState(); - if (IsHotkey(HK_UNDO_SAVE_STATE)) - State::UndoSaveState(); + if (IsHotkey(HK_SELECT_STATE_SLOT_1 + i)) + { + wxCommandEvent slot_event; + slot_event.SetId(IDM_SELECT_SLOT_1 + i); + CFrame::OnSelectSlot(slot_event); + } + } + if (IsHotkey(HK_SAVE_FIRST_STATE)) + State::SaveFirstSaved(); + if (IsHotkey(HK_UNDO_LOAD_STATE)) + State::UndoLoadState(); + if (IsHotkey(HK_UNDO_SAVE_STATE)) + State::UndoSaveState(); } void CFrame::HandleFrameSkipHotkeys() { - static const int MAX_FRAME_SKIP_DELAY = 60; - static int frameStepCount = 0; - static const int FRAME_STEP_DELAY = 30; - static int holdFrameStepDelay = 1; - static int holdFrameStepDelayCount = 0; - static bool holdFrameStep = false; + static const int MAX_FRAME_SKIP_DELAY = 60; + static int frameStepCount = 0; + static const int FRAME_STEP_DELAY = 30; + static int holdFrameStepDelay = 1; + static int holdFrameStepDelayCount = 0; + static bool holdFrameStep = false; - if (IsHotkey(HK_FRAME_ADVANCE_DECREASE_SPEED)) - { - ++holdFrameStepDelay; - if (holdFrameStepDelay > MAX_FRAME_SKIP_DELAY) - holdFrameStepDelay = MAX_FRAME_SKIP_DELAY; - } - else if (IsHotkey(HK_FRAME_ADVANCE_INCREASE_SPEED)) - { - --holdFrameStepDelay; - if (holdFrameStepDelay < 0) - holdFrameStepDelay = 0; - } - else if (IsHotkey(HK_FRAME_ADVANCE_RESET_SPEED)) - { - holdFrameStepDelay = 1; - } - else if (IsHotkey(HK_FRAME_ADVANCE, true)) - { - if (holdFrameStepDelayCount < holdFrameStepDelay && holdFrameStep) - ++holdFrameStepDelayCount; + if (IsHotkey(HK_FRAME_ADVANCE_DECREASE_SPEED)) + { + ++holdFrameStepDelay; + if (holdFrameStepDelay > MAX_FRAME_SKIP_DELAY) + holdFrameStepDelay = MAX_FRAME_SKIP_DELAY; + } + else if (IsHotkey(HK_FRAME_ADVANCE_INCREASE_SPEED)) + { + --holdFrameStepDelay; + if (holdFrameStepDelay < 0) + holdFrameStepDelay = 0; + } + else if (IsHotkey(HK_FRAME_ADVANCE_RESET_SPEED)) + { + holdFrameStepDelay = 1; + } + else if (IsHotkey(HK_FRAME_ADVANCE, true)) + { + if (holdFrameStepDelayCount < holdFrameStepDelay && holdFrameStep) + ++holdFrameStepDelayCount; - if ((frameStepCount == 0 || frameStepCount == FRAME_STEP_DELAY) && !holdFrameStep) - { - wxCommandEvent evt; - evt.SetId(IDM_FRAMESTEP); - CFrame::OnFrameStep(evt); - if (holdFrameStepDelay > 0) - holdFrameStep = true; - } + if ((frameStepCount == 0 || frameStepCount == FRAME_STEP_DELAY) && !holdFrameStep) + { + wxCommandEvent evt; + evt.SetId(IDM_FRAMESTEP); + CFrame::OnFrameStep(evt); + if (holdFrameStepDelay > 0) + holdFrameStep = true; + } - if (frameStepCount < FRAME_STEP_DELAY) - { - ++frameStepCount; - if (holdFrameStep) - holdFrameStep = false; - } + if (frameStepCount < FRAME_STEP_DELAY) + { + ++frameStepCount; + if (holdFrameStep) + holdFrameStep = false; + } - if (frameStepCount == FRAME_STEP_DELAY && holdFrameStep && holdFrameStepDelayCount >= holdFrameStepDelay) - { - holdFrameStep = false; - holdFrameStepDelayCount = 0; - } - } - else if (frameStepCount > 0) - { - // Reset values of frame advance to default - frameStepCount = 0; - holdFrameStep = false; - holdFrameStepDelayCount = 0; - } + if (frameStepCount == FRAME_STEP_DELAY && holdFrameStep && + holdFrameStepDelayCount >= holdFrameStepDelay) + { + holdFrameStep = false; + holdFrameStepDelayCount = 0; + } + } + else if (frameStepCount > 0) + { + // Reset values of frame advance to default + frameStepCount = 0; + holdFrameStep = false; + holdFrameStepDelayCount = 0; + } } - diff --git a/Source/Core/DolphinWX/Frame.h b/Source/Core/DolphinWX/Frame.h index 80c4b79a54..e4fc6d5556 100644 --- a/Source/Core/DolphinWX/Frame.h +++ b/Source/Core/DolphinWX/Frame.h @@ -43,306 +43,296 @@ class wxMenuItem; class CRenderFrame : public wxFrame { - public: - CRenderFrame(wxFrame* parent, - wxWindowID id = wxID_ANY, - const wxString& title = "Dolphin", - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE); +public: + CRenderFrame(wxFrame* parent, wxWindowID id = wxID_ANY, const wxString& title = "Dolphin", + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE); - bool ShowFullScreen(bool show, long style = wxFULLSCREEN_ALL) override; - - private: - void OnDropFiles(wxDropFilesEvent& event); - static bool IsValidSavestateDropped(const std::string& filepath); - #ifdef _WIN32 - // Receive WndProc messages - WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam); - #endif + bool ShowFullScreen(bool show, long style = wxFULLSCREEN_ALL) override; +private: + void OnDropFiles(wxDropFilesEvent& event); + static bool IsValidSavestateDropped(const std::string& filepath); +#ifdef _WIN32 + // Receive WndProc messages + WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam); +#endif }; class CFrame : public CRenderFrame { public: - CFrame(wxFrame* parent, - wxWindowID id = wxID_ANY, - const wxString& title = "Dolphin", - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - bool _UseDebugger = false, - bool _BatchMode = false, - bool ShowLogWindow = false, - long style = wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE); + CFrame(wxFrame* parent, wxWindowID id = wxID_ANY, const wxString& title = "Dolphin", + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + bool _UseDebugger = false, bool _BatchMode = false, bool ShowLogWindow = false, + long style = wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE); - virtual ~CFrame(); + virtual ~CFrame(); - void* GetRenderHandle() - { - #if defined(HAVE_X11) && HAVE_X11 - return reinterpret_cast(X11Utils::XWindowFromHandle(m_RenderParent->GetHandle())); - #else - return reinterpret_cast(m_RenderParent->GetHandle()); - #endif - } + void* GetRenderHandle() + { +#if defined(HAVE_X11) && HAVE_X11 + return reinterpret_cast(X11Utils::XWindowFromHandle(m_RenderParent->GetHandle())); +#else + return reinterpret_cast(m_RenderParent->GetHandle()); +#endif + } - // These have to be public - CCodeWindow* g_pCodeWindow; - NetPlaySetupFrame* g_NetPlaySetupDiag; - wxCheatsWindow* g_CheatsWindow; - TASInputDlg* g_TASInputDlg[8]; + // These have to be public + CCodeWindow* g_pCodeWindow; + NetPlaySetupFrame* g_NetPlaySetupDiag; + wxCheatsWindow* g_CheatsWindow; + TASInputDlg* g_TASInputDlg[8]; - void InitBitmaps(); - void DoPause(); - void DoStop(); - void OnStopped(); - void DoRecordingSave(); - void UpdateGUI(); - void UpdateGameList(); - void ToggleLogWindow(bool bShow); - void ToggleLogConfigWindow(bool bShow); - void PostEvent(wxCommandEvent& event); - void StatusBarMessage(const char * Text, ...); - void ClearStatusBar(); - void OnRenderWindowSizeRequest(int width, int height); - void BootGame(const std::string& filename); - void OnRenderParentClose(wxCloseEvent& event); - void OnRenderParentMove(wxMoveEvent& event); - bool RendererHasFocus(); - bool UIHasFocus(); - bool RendererIsFullscreen(); - void DoFullscreen(bool bF); - void ToggleDisplayMode (bool bFullscreen); - void UpdateWiiMenuChoice(wxMenuItem *WiiMenuItem=nullptr); - void PopulateSavedPerspectives(); - static void ConnectWiimote(int wm_idx, bool connect); - void UpdateTitle(const std::string &str); + void InitBitmaps(); + void DoPause(); + void DoStop(); + void OnStopped(); + void DoRecordingSave(); + void UpdateGUI(); + void UpdateGameList(); + void ToggleLogWindow(bool bShow); + void ToggleLogConfigWindow(bool bShow); + void PostEvent(wxCommandEvent& event); + void StatusBarMessage(const char* Text, ...); + void ClearStatusBar(); + void OnRenderWindowSizeRequest(int width, int height); + void BootGame(const std::string& filename); + void OnRenderParentClose(wxCloseEvent& event); + void OnRenderParentMove(wxMoveEvent& event); + bool RendererHasFocus(); + bool UIHasFocus(); + bool RendererIsFullscreen(); + void DoFullscreen(bool bF); + void ToggleDisplayMode(bool bFullscreen); + void UpdateWiiMenuChoice(wxMenuItem* WiiMenuItem = nullptr); + void PopulateSavedPerspectives(); + static void ConnectWiimote(int wm_idx, bool connect); + void UpdateTitle(const std::string& str); - const CGameListCtrl *GetGameListCtrl() const; - wxMenuBar* GetMenuBar() const override; + const CGameListCtrl* GetGameListCtrl() const; + wxMenuBar* GetMenuBar() const override; #ifdef __WXGTK__ - Common::Event panic_event; - bool bPanicResult; - std::recursive_mutex keystate_lock; + Common::Event panic_event; + bool bPanicResult; + std::recursive_mutex keystate_lock; #endif #if defined(HAVE_XRANDR) && HAVE_XRANDR - X11Utils::XRRConfiguration *m_XRRConfig; + X11Utils::XRRConfiguration* m_XRRConfig; #endif - wxMenu* m_SavedPerspectives; + wxMenu* m_SavedPerspectives; - wxToolBar *m_ToolBar; - // AUI - wxAuiManager *m_Mgr; - bool bFloatWindow[IDM_CODE_WINDOW - IDM_LOG_WINDOW + 1]; + wxToolBar* m_ToolBar; + // AUI + wxAuiManager* m_Mgr; + bool bFloatWindow[IDM_CODE_WINDOW - IDM_LOG_WINDOW + 1]; - // Perspectives (Should find a way to make all of this private) - void DoAddPage(wxWindow *Win, int i, bool Float); - void DoRemovePage(wxWindow *, bool bHide = true); - struct SPerspectives - { - std::string Name; - wxString Perspective; - std::vector Width, Height; - }; - std::vector Perspectives; - u32 ActivePerspective; + // Perspectives (Should find a way to make all of this private) + void DoAddPage(wxWindow* Win, int i, bool Float); + void DoRemovePage(wxWindow*, bool bHide = true); + struct SPerspectives + { + std::string Name; + wxString Perspective; + std::vector Width, Height; + }; + std::vector Perspectives; + u32 ActivePerspective; private: - CGameListCtrl* m_GameListCtrl; - wxPanel* m_Panel; - CRenderFrame* m_RenderFrame; - wxWindow* m_RenderParent; - CLogWindow* m_LogWindow; - LogConfigWindow* m_LogConfigWindow; - FifoPlayerDlg* m_FifoPlayerDlg; - bool UseDebugger; - bool m_bBatchMode; - bool m_bEdit; - bool m_bTabSplit; - bool m_bNoDocking; - bool m_bGameLoading; - bool m_bClosing; - bool m_confirmStop; + CGameListCtrl* m_GameListCtrl; + wxPanel* m_Panel; + CRenderFrame* m_RenderFrame; + wxWindow* m_RenderParent; + CLogWindow* m_LogWindow; + LogConfigWindow* m_LogConfigWindow; + FifoPlayerDlg* m_FifoPlayerDlg; + bool UseDebugger; + bool m_bBatchMode; + bool m_bEdit; + bool m_bTabSplit; + bool m_bNoDocking; + bool m_bGameLoading; + bool m_bClosing; + bool m_confirmStop; - std::vector drives; + std::vector drives; - enum EToolbar - { - Toolbar_FileOpen, - Toolbar_Refresh, - Toolbar_Play, - Toolbar_Stop, - Toolbar_Pause, - Toolbar_Screenshot, - Toolbar_FullScreen, - Toolbar_ConfigMain, - Toolbar_ConfigGFX, - Toolbar_Controller, - EToolbar_Max - }; + enum EToolbar + { + Toolbar_FileOpen, + Toolbar_Refresh, + Toolbar_Play, + Toolbar_Stop, + Toolbar_Pause, + Toolbar_Screenshot, + Toolbar_FullScreen, + Toolbar_ConfigMain, + Toolbar_ConfigGFX, + Toolbar_Controller, + EToolbar_Max + }; - enum - { - ADD_PANE_TOP, - ADD_PANE_BOTTOM, - ADD_PANE_LEFT, - ADD_PANE_RIGHT, - ADD_PANE_CENTER - }; + enum + { + ADD_PANE_TOP, + ADD_PANE_BOTTOM, + ADD_PANE_LEFT, + ADD_PANE_RIGHT, + ADD_PANE_CENTER + }; - wxTimer m_poll_hotkey_timer; + wxTimer m_poll_hotkey_timer; - wxBitmap m_Bitmaps[EToolbar_Max]; + wxBitmap m_Bitmaps[EToolbar_Max]; - wxMenuBar* m_menubar_shadow; + wxMenuBar* m_menubar_shadow; - void PopulateToolbar(wxToolBar* toolBar); - void RecreateToolbar(); - wxMenuBar* CreateMenu(); + void PopulateToolbar(wxToolBar* toolBar); + void RecreateToolbar(); + wxMenuBar* CreateMenu(); - // Utility - wxString GetMenuLabel(int Id); - wxWindow * GetNotebookPageFromId(wxWindowID Id); - wxAuiNotebook * GetNotebookFromId(u32 NBId); - int GetNotebookCount(); - wxAuiNotebook *CreateEmptyNotebook(); - void HandleFrameSkipHotkeys(); + // Utility + wxString GetMenuLabel(int Id); + wxWindow* GetNotebookPageFromId(wxWindowID Id); + wxAuiNotebook* GetNotebookFromId(u32 NBId); + int GetNotebookCount(); + wxAuiNotebook* CreateEmptyNotebook(); + void HandleFrameSkipHotkeys(); - // Perspectives - void AddRemoveBlankPage(); - void OnNotebookPageClose(wxAuiNotebookEvent& event); - void OnAllowNotebookDnD(wxAuiNotebookEvent& event); - void OnNotebookPageChanged(wxAuiNotebookEvent& event); - void OnFloatWindow(wxCommandEvent& event); - void ToggleFloatWindow(int Id); - void OnTab(wxAuiNotebookEvent& event); - int GetNotebookAffiliation(wxWindowID Id); - void ClosePages(); - void CloseAllNotebooks(); - void ShowResizePane(); - void TogglePane(); - void SetPaneSize(); - void TogglePaneStyle(bool On, int EventId); - void ToggleNotebookStyle(bool On, long Style); - // Float window - void DoUnfloatPage(int Id); - void OnFloatingPageClosed(wxCloseEvent& event); - void OnFloatingPageSize(wxSizeEvent& event); - void DoFloatNotebookPage(wxWindowID Id); - wxFrame * CreateParentFrame(wxWindowID Id = wxID_ANY, - const wxString& title = "", - wxWindow * = nullptr); - wxString AuiFullscreen, AuiCurrent; - void AddPane(int dir); - void UpdateCurrentPerspective(); - void SaveIniPerspectives(); - void LoadIniPerspectives(); - void OnPaneClose(wxAuiManagerEvent& evt); - void ReloadPanes(); - void DoLoadPerspective(); - void OnPerspectiveMenu(wxCommandEvent& event); - void OnSelectPerspective(wxCommandEvent& event); + // Perspectives + void AddRemoveBlankPage(); + void OnNotebookPageClose(wxAuiNotebookEvent& event); + void OnAllowNotebookDnD(wxAuiNotebookEvent& event); + void OnNotebookPageChanged(wxAuiNotebookEvent& event); + void OnFloatWindow(wxCommandEvent& event); + void ToggleFloatWindow(int Id); + void OnTab(wxAuiNotebookEvent& event); + int GetNotebookAffiliation(wxWindowID Id); + void ClosePages(); + void CloseAllNotebooks(); + void ShowResizePane(); + void TogglePane(); + void SetPaneSize(); + void TogglePaneStyle(bool On, int EventId); + void ToggleNotebookStyle(bool On, long Style); + // Float window + void DoUnfloatPage(int Id); + void OnFloatingPageClosed(wxCloseEvent& event); + void OnFloatingPageSize(wxSizeEvent& event); + void DoFloatNotebookPage(wxWindowID Id); + wxFrame* CreateParentFrame(wxWindowID Id = wxID_ANY, const wxString& title = "", + wxWindow* = nullptr); + wxString AuiFullscreen, AuiCurrent; + void AddPane(int dir); + void UpdateCurrentPerspective(); + void SaveIniPerspectives(); + void LoadIniPerspectives(); + void OnPaneClose(wxAuiManagerEvent& evt); + void ReloadPanes(); + void DoLoadPerspective(); + void OnPerspectiveMenu(wxCommandEvent& event); + void OnSelectPerspective(wxCommandEvent& event); #ifdef _WIN32 - // Override window proc for tricks like screensaver disabling - WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam); + // Override window proc for tricks like screensaver disabling + WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam); #endif - // Event functions - void OnQuit(wxCommandEvent& event); - void OnHelp(wxCommandEvent& event); + // Event functions + void OnQuit(wxCommandEvent& event); + void OnHelp(wxCommandEvent& event); - void OnOpen(wxCommandEvent& event); // File menu - void DoOpen(bool Boot); - void OnRefresh(wxCommandEvent& event); - void OnBootDrive(wxCommandEvent& event); + void OnOpen(wxCommandEvent& event); // File menu + void DoOpen(bool Boot); + void OnRefresh(wxCommandEvent& event); + void OnBootDrive(wxCommandEvent& event); - void OnPlay(wxCommandEvent& event); // Emulation - void OnStop(wxCommandEvent& event); - void OnReset(wxCommandEvent& event); - void OnRecord(wxCommandEvent& event); - void OnPlayRecording(wxCommandEvent& event); - void OnRecordExport(wxCommandEvent& event); - void OnRecordReadOnly(wxCommandEvent& event); - void OnTASInput(wxCommandEvent& event); - void OnTogglePauseMovie(wxCommandEvent& event); - void OnToggleDumpFrames(wxCommandEvent& event); - void OnToggleDumpAudio(wxCommandEvent& event); - void OnShowLag(wxCommandEvent& event); - void OnShowFrameCount(wxCommandEvent& event); - void OnShowInputDisplay(wxCommandEvent& event); - void OnChangeDisc(wxCommandEvent& event); - void OnScreenshot(wxCommandEvent& event); - void OnActive(wxActivateEvent& event); - void OnClose(wxCloseEvent &event); - void OnLoadState(wxCommandEvent& event); - void OnSaveState(wxCommandEvent& event); - void OnLoadStateFromFile(wxCommandEvent& event); - void OnSaveStateToFile(wxCommandEvent& event); - void OnLoadLastState(wxCommandEvent& event); - void OnSaveFirstState(wxCommandEvent& event); - void OnUndoLoadState(wxCommandEvent& event); - void OnUndoSaveState(wxCommandEvent& event); + void OnPlay(wxCommandEvent& event); // Emulation + void OnStop(wxCommandEvent& event); + void OnReset(wxCommandEvent& event); + void OnRecord(wxCommandEvent& event); + void OnPlayRecording(wxCommandEvent& event); + void OnRecordExport(wxCommandEvent& event); + void OnRecordReadOnly(wxCommandEvent& event); + void OnTASInput(wxCommandEvent& event); + void OnTogglePauseMovie(wxCommandEvent& event); + void OnToggleDumpFrames(wxCommandEvent& event); + void OnToggleDumpAudio(wxCommandEvent& event); + void OnShowLag(wxCommandEvent& event); + void OnShowFrameCount(wxCommandEvent& event); + void OnShowInputDisplay(wxCommandEvent& event); + void OnChangeDisc(wxCommandEvent& event); + void OnScreenshot(wxCommandEvent& event); + void OnActive(wxActivateEvent& event); + void OnClose(wxCloseEvent& event); + void OnLoadState(wxCommandEvent& event); + void OnSaveState(wxCommandEvent& event); + void OnLoadStateFromFile(wxCommandEvent& event); + void OnSaveStateToFile(wxCommandEvent& event); + void OnLoadLastState(wxCommandEvent& event); + void OnSaveFirstState(wxCommandEvent& event); + void OnUndoLoadState(wxCommandEvent& event); + void OnUndoSaveState(wxCommandEvent& event); - void OnFrameSkip(wxCommandEvent& event); - void OnFrameStep(wxCommandEvent& event); + void OnFrameSkip(wxCommandEvent& event); + void OnFrameStep(wxCommandEvent& event); - void OnConfigMain(wxCommandEvent& event); // Options - void OnConfigGFX(wxCommandEvent& event); - void OnConfigAudio(wxCommandEvent& event); - void OnConfigControllers(wxCommandEvent& event); - void OnConfigHotkey(wxCommandEvent& event); + void OnConfigMain(wxCommandEvent& event); // Options + void OnConfigGFX(wxCommandEvent& event); + void OnConfigAudio(wxCommandEvent& event); + void OnConfigControllers(wxCommandEvent& event); + void OnConfigHotkey(wxCommandEvent& event); - void OnToggleFullscreen(wxCommandEvent& event); - void OnToggleDualCore(wxCommandEvent& event); - void OnToggleSkipIdle(wxCommandEvent& event); - void OnManagerResize(wxAuiManagerEvent& event); - void OnMove(wxMoveEvent& event); - void OnResize(wxSizeEvent& event); - void OnToggleToolbar(wxCommandEvent& event); - void DoToggleToolbar(bool); - void OnToggleStatusbar(wxCommandEvent& event); - void OnToggleWindow(wxCommandEvent& event); + void OnToggleFullscreen(wxCommandEvent& event); + void OnToggleDualCore(wxCommandEvent& event); + void OnToggleSkipIdle(wxCommandEvent& event); + void OnManagerResize(wxAuiManagerEvent& event); + void OnMove(wxMoveEvent& event); + void OnResize(wxSizeEvent& event); + void OnToggleToolbar(wxCommandEvent& event); + void DoToggleToolbar(bool); + void OnToggleStatusbar(wxCommandEvent& event); + void OnToggleWindow(wxCommandEvent& event); - void OnKeyDown(wxKeyEvent& event); // Keyboard - void OnMouse(wxMouseEvent& event); // Mouse + void OnKeyDown(wxKeyEvent& event); // Keyboard + void OnMouse(wxMouseEvent& event); // Mouse - void OnFocusChange(wxFocusEvent& event); + void OnFocusChange(wxFocusEvent& event); - void OnHostMessage(wxCommandEvent& event); + void OnHostMessage(wxCommandEvent& event); - void OnMemcard(wxCommandEvent& event); // Misc - void OnImportSave(wxCommandEvent& event); - void OnExportAllSaves(wxCommandEvent& event); + void OnMemcard(wxCommandEvent& event); // Misc + void OnImportSave(wxCommandEvent& event); + void OnExportAllSaves(wxCommandEvent& event); - void OnNetPlay(wxCommandEvent& event); + void OnNetPlay(wxCommandEvent& event); - void OnShowCheatsWindow(wxCommandEvent& event); - void OnLoadWiiMenu(wxCommandEvent& event); - void OnInstallWAD(wxCommandEvent& event); - void OnFifoPlayer(wxCommandEvent& event); - void OnConnectWiimote(wxCommandEvent& event); - void GameListChanged(wxCommandEvent& event); + void OnShowCheatsWindow(wxCommandEvent& event); + void OnLoadWiiMenu(wxCommandEvent& event); + void OnInstallWAD(wxCommandEvent& event); + void OnFifoPlayer(wxCommandEvent& event); + void OnConnectWiimote(wxCommandEvent& event); + void GameListChanged(wxCommandEvent& event); - void OnGameListCtrlItemActivated(wxListEvent& event); - void OnRenderParentResize(wxSizeEvent& event); - void StartGame(const std::string& filename); - void OnChangeColumnsVisible(wxCommandEvent& event); + void OnGameListCtrlItemActivated(wxListEvent& event); + void OnRenderParentResize(wxSizeEvent& event); + void StartGame(const std::string& filename); + void OnChangeColumnsVisible(wxCommandEvent& event); - void OnSelectSlot(wxCommandEvent& event); - void OnSaveCurrentSlot(wxCommandEvent& event); - void OnLoadCurrentSlot(wxCommandEvent& event); + void OnSelectSlot(wxCommandEvent& event); + void OnSaveCurrentSlot(wxCommandEvent& event); + void OnLoadCurrentSlot(wxCommandEvent& event); - void PollHotkeys(wxTimerEvent&); - void ParseHotkeys(); + void PollHotkeys(wxTimerEvent&); + void ParseHotkeys(); - bool InitControllers(); + bool InitControllers(); - // Event table - DECLARE_EVENT_TABLE(); + // Event table + DECLARE_EVENT_TABLE(); }; int GetCmdForHotkey(unsigned int key); @@ -352,5 +342,6 @@ void OnStoppedCallback(); // For TASInputDlg void GCTASManipFunction(GCPadStatus* PadStatus, int controllerID); -void WiiTASManipFunction(u8* data, WiimoteEmu::ReportFeatures rptf, int controllerID, int ext, const wiimote_key key); +void WiiTASManipFunction(u8* data, WiimoteEmu::ReportFeatures rptf, int controllerID, int ext, + const wiimote_key key); extern int g_saveSlot; diff --git a/Source/Core/DolphinWX/FrameAui.cpp b/Source/Core/DolphinWX/FrameAui.cpp index d48476eee4..e4b341e414 100644 --- a/Source/Core/DolphinWX/FrameAui.cpp +++ b/Source/Core/DolphinWX/FrameAui.cpp @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -15,1023 +18,1021 @@ #include #include #include -#include -#include -#include #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/IniFile.h" +#include "Common/Logging/ConsoleListener.h" #include "Common/MathUtil.h" #include "Common/StringUtil.h" -#include "Common/Logging/ConsoleListener.h" #include "Core/ConfigManager.h" +#include "DolphinWX/Debugger/CodeWindow.h" #include "DolphinWX/Frame.h" #include "DolphinWX/Globals.h" #include "DolphinWX/LogConfigWindow.h" #include "DolphinWX/LogWindow.h" #include "DolphinWX/WxUtils.h" -#include "DolphinWX/Debugger/CodeWindow.h" // ------------ // Aui events void CFrame::OnManagerResize(wxAuiManagerEvent& event) { - if (!g_pCodeWindow && m_LogWindow && - m_Mgr->GetPane("Pane 1").IsShown() && - !m_Mgr->GetPane("Pane 1").IsFloating()) - { - m_LogWindow->x = m_Mgr->GetPane("Pane 1").rect.GetWidth(); - m_LogWindow->y = m_Mgr->GetPane("Pane 1").rect.GetHeight(); - m_LogWindow->winpos = m_Mgr->GetPane("Pane 1").dock_direction; - } - event.Skip(); + if (!g_pCodeWindow && m_LogWindow && m_Mgr->GetPane("Pane 1").IsShown() && + !m_Mgr->GetPane("Pane 1").IsFloating()) + { + m_LogWindow->x = m_Mgr->GetPane("Pane 1").rect.GetWidth(); + m_LogWindow->y = m_Mgr->GetPane("Pane 1").rect.GetHeight(); + m_LogWindow->winpos = m_Mgr->GetPane("Pane 1").dock_direction; + } + event.Skip(); } void CFrame::OnPaneClose(wxAuiManagerEvent& event) { - event.Veto(); + event.Veto(); - wxAuiNotebook * nb = (wxAuiNotebook*)event.pane->window; - if (!nb) return; + wxAuiNotebook* nb = (wxAuiNotebook*)event.pane->window; + if (!nb) + return; - if (!g_pCodeWindow) - { - if (nb->GetPage(0)->GetId() == IDM_LOG_WINDOW || - nb->GetPage(0)->GetId() == IDM_LOG_CONFIG_WINDOW) - { + if (!g_pCodeWindow) + { + if (nb->GetPage(0)->GetId() == IDM_LOG_WINDOW || + nb->GetPage(0)->GetId() == IDM_LOG_CONFIG_WINDOW) + { + SConfig::GetInstance().m_InterfaceLogWindow = false; + SConfig::GetInstance().m_InterfaceLogConfigWindow = false; + ToggleLogWindow(false); + ToggleLogConfigWindow(false); + } + } + else + { + if (GetNotebookCount() == 1) + { + wxMessageBox(_("At least one pane must remain open."), _("Notice"), wxOK, this); + } + else if (nb->GetPageCount() != 0 && !nb->GetPageText(0).IsSameAs("<>")) + { + wxMessageBox(_("You can't close panes that have pages in them."), _("Notice"), wxOK, this); + } + else + { + // Detach and delete the empty notebook + event.pane->DestroyOnClose(true); + m_Mgr->ClosePane(*event.pane); + } + } - SConfig::GetInstance().m_InterfaceLogWindow = false; - SConfig::GetInstance().m_InterfaceLogConfigWindow = false; - ToggleLogWindow(false); - ToggleLogConfigWindow(false); - } - } - else - { - if (GetNotebookCount() == 1) - { - wxMessageBox(_("At least one pane must remain open."), - _("Notice"), wxOK, this); - } - else if (nb->GetPageCount() != 0 && !nb->GetPageText(0).IsSameAs("<>")) - { - wxMessageBox(_("You can't close panes that have pages in them."), - _("Notice"), wxOK, this); - } - else - { - // Detach and delete the empty notebook - event.pane->DestroyOnClose(true); - m_Mgr->ClosePane(*event.pane); - } - } - - m_Mgr->Update(); + m_Mgr->Update(); } void CFrame::ToggleLogWindow(bool bShow) { - if (!m_LogWindow) - return; + if (!m_LogWindow) + return; - GetMenuBar()->FindItem(IDM_LOG_WINDOW)->Check(bShow); + GetMenuBar()->FindItem(IDM_LOG_WINDOW)->Check(bShow); - if (bShow) - { - // Create a new log window if it doesn't exist. - if (!m_LogWindow) - { - m_LogWindow = new CLogWindow(this, IDM_LOG_WINDOW); - } + if (bShow) + { + // Create a new log window if it doesn't exist. + if (!m_LogWindow) + { + m_LogWindow = new CLogWindow(this, IDM_LOG_WINDOW); + } - m_LogWindow->Enable(); + m_LogWindow->Enable(); - DoAddPage(m_LogWindow, - g_pCodeWindow ? g_pCodeWindow->iNbAffiliation[0] : 0, - g_pCodeWindow ? bFloatWindow[0] : false); - } - else - { - // Hiding the log window, so disable it and remove it. - m_LogWindow->Disable(); - DoRemovePage(m_LogWindow, true); - } + DoAddPage(m_LogWindow, g_pCodeWindow ? g_pCodeWindow->iNbAffiliation[0] : 0, + g_pCodeWindow ? bFloatWindow[0] : false); + } + else + { + // Hiding the log window, so disable it and remove it. + m_LogWindow->Disable(); + DoRemovePage(m_LogWindow, true); + } - // Hide or Show the pane - if (!g_pCodeWindow) - TogglePane(); + // Hide or Show the pane + if (!g_pCodeWindow) + TogglePane(); } void CFrame::ToggleLogConfigWindow(bool bShow) { - GetMenuBar()->FindItem(IDM_LOG_CONFIG_WINDOW)->Check(bShow); + GetMenuBar()->FindItem(IDM_LOG_CONFIG_WINDOW)->Check(bShow); - if (bShow) - { - if (!m_LogConfigWindow) - m_LogConfigWindow = new LogConfigWindow(this, IDM_LOG_CONFIG_WINDOW); + if (bShow) + { + if (!m_LogConfigWindow) + m_LogConfigWindow = new LogConfigWindow(this, IDM_LOG_CONFIG_WINDOW); - const int nbIndex = IDM_LOG_CONFIG_WINDOW - IDM_LOG_WINDOW; - DoAddPage(m_LogConfigWindow, - g_pCodeWindow ? g_pCodeWindow->iNbAffiliation[nbIndex] : 0, - g_pCodeWindow ? bFloatWindow[nbIndex] : false); - } - else - { - DoRemovePage(m_LogConfigWindow, false); - m_LogConfigWindow = nullptr; - } + const int nbIndex = IDM_LOG_CONFIG_WINDOW - IDM_LOG_WINDOW; + DoAddPage(m_LogConfigWindow, g_pCodeWindow ? g_pCodeWindow->iNbAffiliation[nbIndex] : 0, + g_pCodeWindow ? bFloatWindow[nbIndex] : false); + } + else + { + DoRemovePage(m_LogConfigWindow, false); + m_LogConfigWindow = nullptr; + } - // Hide or Show the pane - if (!g_pCodeWindow) - TogglePane(); + // Hide or Show the pane + if (!g_pCodeWindow) + TogglePane(); } void CFrame::OnToggleWindow(wxCommandEvent& event) { - bool bShow = GetMenuBar()->IsChecked(event.GetId()); + bool bShow = GetMenuBar()->IsChecked(event.GetId()); - switch (event.GetId()) - { - case IDM_LOG_WINDOW: - if (!g_pCodeWindow) - SConfig::GetInstance().m_InterfaceLogWindow = bShow; - ToggleLogWindow(bShow); - break; - case IDM_LOG_CONFIG_WINDOW: - if (!g_pCodeWindow) - SConfig::GetInstance().m_InterfaceLogConfigWindow = bShow; - ToggleLogConfigWindow(bShow); - break; - case IDM_REGISTER_WINDOW: - g_pCodeWindow->ToggleRegisterWindow(bShow); - break; - case IDM_WATCH_WINDOW: - g_pCodeWindow->ToggleWatchWindow(bShow); - break; - case IDM_BREAKPOINT_WINDOW: - g_pCodeWindow->ToggleBreakPointWindow(bShow); - break; - case IDM_MEMORY_WINDOW: - g_pCodeWindow->ToggleMemoryWindow(bShow); - break; - case IDM_JIT_WINDOW: - g_pCodeWindow->ToggleJitWindow(bShow); - break; - case IDM_SOUND_WINDOW: - g_pCodeWindow->ToggleSoundWindow(bShow); - break; - case IDM_VIDEO_WINDOW: - g_pCodeWindow->ToggleVideoWindow(bShow); - break; - } + switch (event.GetId()) + { + case IDM_LOG_WINDOW: + if (!g_pCodeWindow) + SConfig::GetInstance().m_InterfaceLogWindow = bShow; + ToggleLogWindow(bShow); + break; + case IDM_LOG_CONFIG_WINDOW: + if (!g_pCodeWindow) + SConfig::GetInstance().m_InterfaceLogConfigWindow = bShow; + ToggleLogConfigWindow(bShow); + break; + case IDM_REGISTER_WINDOW: + g_pCodeWindow->ToggleRegisterWindow(bShow); + break; + case IDM_WATCH_WINDOW: + g_pCodeWindow->ToggleWatchWindow(bShow); + break; + case IDM_BREAKPOINT_WINDOW: + g_pCodeWindow->ToggleBreakPointWindow(bShow); + break; + case IDM_MEMORY_WINDOW: + g_pCodeWindow->ToggleMemoryWindow(bShow); + break; + case IDM_JIT_WINDOW: + g_pCodeWindow->ToggleJitWindow(bShow); + break; + case IDM_SOUND_WINDOW: + g_pCodeWindow->ToggleSoundWindow(bShow); + break; + case IDM_VIDEO_WINDOW: + g_pCodeWindow->ToggleVideoWindow(bShow); + break; + } } // Notebooks // --------------------- void CFrame::ClosePages() { - ToggleLogWindow(false); - ToggleLogConfigWindow(false); + ToggleLogWindow(false); + ToggleLogConfigWindow(false); - if (g_pCodeWindow) - { - g_pCodeWindow->ToggleCodeWindow(false); - g_pCodeWindow->ToggleRegisterWindow(false); - g_pCodeWindow->ToggleWatchWindow(false); - g_pCodeWindow->ToggleBreakPointWindow(false); - g_pCodeWindow->ToggleMemoryWindow(false); - g_pCodeWindow->ToggleJitWindow(false); - g_pCodeWindow->ToggleSoundWindow(false); - g_pCodeWindow->ToggleVideoWindow(false); - } + if (g_pCodeWindow) + { + g_pCodeWindow->ToggleCodeWindow(false); + g_pCodeWindow->ToggleRegisterWindow(false); + g_pCodeWindow->ToggleWatchWindow(false); + g_pCodeWindow->ToggleBreakPointWindow(false); + g_pCodeWindow->ToggleMemoryWindow(false); + g_pCodeWindow->ToggleJitWindow(false); + g_pCodeWindow->ToggleSoundWindow(false); + g_pCodeWindow->ToggleVideoWindow(false); + } } void CFrame::OnNotebookPageChanged(wxAuiNotebookEvent& event) { - event.Skip(); + event.Skip(); - if (!g_pCodeWindow) - return; + if (!g_pCodeWindow) + return; - // Remove the blank page if any - AddRemoveBlankPage(); + // Remove the blank page if any + AddRemoveBlankPage(); - // Update the notebook affiliation - for (int i = IDM_LOG_WINDOW; i <= IDM_CODE_WINDOW; i++) - { - if (GetNotebookAffiliation(i) >= 0) - g_pCodeWindow->iNbAffiliation[i - IDM_LOG_WINDOW] = GetNotebookAffiliation(i); - } + // Update the notebook affiliation + for (int i = IDM_LOG_WINDOW; i <= IDM_CODE_WINDOW; i++) + { + if (GetNotebookAffiliation(i) >= 0) + g_pCodeWindow->iNbAffiliation[i - IDM_LOG_WINDOW] = GetNotebookAffiliation(i); + } } void CFrame::OnNotebookPageClose(wxAuiNotebookEvent& event) { - // Override event - event.Veto(); + // Override event + event.Veto(); - wxAuiNotebook* Ctrl = (wxAuiNotebook*)event.GetEventObject(); + wxAuiNotebook* Ctrl = (wxAuiNotebook*)event.GetEventObject(); - if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_LOG_WINDOW) - ToggleLogWindow(false); - if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_LOG_CONFIG_WINDOW) - ToggleLogConfigWindow(false); - if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_REGISTER_WINDOW) - g_pCodeWindow->ToggleRegisterWindow(false); - if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_WATCH_WINDOW) - g_pCodeWindow->ToggleWatchWindow(false); - if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_BREAKPOINT_WINDOW) - g_pCodeWindow->ToggleBreakPointWindow(false); - if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_JIT_WINDOW) - g_pCodeWindow->ToggleJitWindow(false); - if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_MEMORY_WINDOW) - g_pCodeWindow->ToggleMemoryWindow(false); - if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_SOUND_WINDOW) - g_pCodeWindow->ToggleSoundWindow(false); - if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_VIDEO_WINDOW) - g_pCodeWindow->ToggleVideoWindow(false); + if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_LOG_WINDOW) + ToggleLogWindow(false); + if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_LOG_CONFIG_WINDOW) + ToggleLogConfigWindow(false); + if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_REGISTER_WINDOW) + g_pCodeWindow->ToggleRegisterWindow(false); + if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_WATCH_WINDOW) + g_pCodeWindow->ToggleWatchWindow(false); + if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_BREAKPOINT_WINDOW) + g_pCodeWindow->ToggleBreakPointWindow(false); + if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_JIT_WINDOW) + g_pCodeWindow->ToggleJitWindow(false); + if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_MEMORY_WINDOW) + g_pCodeWindow->ToggleMemoryWindow(false); + if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_SOUND_WINDOW) + g_pCodeWindow->ToggleSoundWindow(false); + if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_VIDEO_WINDOW) + g_pCodeWindow->ToggleVideoWindow(false); } void CFrame::OnFloatingPageClosed(wxCloseEvent& event) { - ToggleFloatWindow(event.GetId() - IDM_LOG_WINDOW_PARENT + IDM_FLOAT_LOG_WINDOW); + ToggleFloatWindow(event.GetId() - IDM_LOG_WINDOW_PARENT + IDM_FLOAT_LOG_WINDOW); } void CFrame::OnFloatingPageSize(wxSizeEvent& event) { - event.Skip(); + event.Skip(); } void CFrame::OnFloatWindow(wxCommandEvent& event) { - ToggleFloatWindow(event.GetId()); + ToggleFloatWindow(event.GetId()); } void CFrame::ToggleFloatWindow(int Id) { - wxWindowID WinId = Id - IDM_FLOAT_LOG_WINDOW + IDM_LOG_WINDOW; - if (GetNotebookPageFromId(WinId)) - { - DoFloatNotebookPage(WinId); - bFloatWindow[WinId - IDM_LOG_WINDOW] = true; - } - else - { - if (FindWindowById(WinId)) - DoUnfloatPage(WinId - IDM_LOG_WINDOW + IDM_LOG_WINDOW_PARENT); - bFloatWindow[WinId - IDM_LOG_WINDOW] = false; - } + wxWindowID WinId = Id - IDM_FLOAT_LOG_WINDOW + IDM_LOG_WINDOW; + if (GetNotebookPageFromId(WinId)) + { + DoFloatNotebookPage(WinId); + bFloatWindow[WinId - IDM_LOG_WINDOW] = true; + } + else + { + if (FindWindowById(WinId)) + DoUnfloatPage(WinId - IDM_LOG_WINDOW + IDM_LOG_WINDOW_PARENT); + bFloatWindow[WinId - IDM_LOG_WINDOW] = false; + } } void CFrame::DoFloatNotebookPage(wxWindowID Id) { - wxPanel *Win = (wxPanel*)FindWindowById(Id); - if (!Win) return; + wxPanel* Win = (wxPanel*)FindWindowById(Id); + if (!Win) + return; - for (int i = 0; i < GetNotebookCount(); i++) - { - wxAuiNotebook *nb = GetNotebookFromId(i); - if (nb->GetPageIndex(Win) != wxNOT_FOUND) - { - nb->RemovePage(nb->GetPageIndex(Win)); - // Create the parent frame and reparent the window - CreateParentFrame(Win->GetId() + IDM_LOG_WINDOW_PARENT - IDM_LOG_WINDOW, - Win->GetName(), Win); - if (nb->GetPageCount() == 0) - AddRemoveBlankPage(); - } - } + for (int i = 0; i < GetNotebookCount(); i++) + { + wxAuiNotebook* nb = GetNotebookFromId(i); + if (nb->GetPageIndex(Win) != wxNOT_FOUND) + { + nb->RemovePage(nb->GetPageIndex(Win)); + // Create the parent frame and reparent the window + CreateParentFrame(Win->GetId() + IDM_LOG_WINDOW_PARENT - IDM_LOG_WINDOW, Win->GetName(), Win); + if (nb->GetPageCount() == 0) + AddRemoveBlankPage(); + } + } } void CFrame::DoUnfloatPage(int Id) { - wxFrame * Win = (wxFrame*)FindWindowById(Id); - if (!Win) return; + wxFrame* Win = (wxFrame*)FindWindowById(Id); + if (!Win) + return; - wxWindow * Child = Win->GetChildren().Item(0)->GetData(); - Child->Reparent(this); - DoAddPage(Child, g_pCodeWindow->iNbAffiliation[Child->GetId() - IDM_LOG_WINDOW], false); - Win->Destroy(); + wxWindow* Child = Win->GetChildren().Item(0)->GetData(); + Child->Reparent(this); + DoAddPage(Child, g_pCodeWindow->iNbAffiliation[Child->GetId() - IDM_LOG_WINDOW], false); + Win->Destroy(); } void CFrame::OnTab(wxAuiNotebookEvent& event) { - event.Skip(); - if (!g_pCodeWindow) return; + event.Skip(); + if (!g_pCodeWindow) + return; - // Create the popup menu - wxMenu MenuPopup; + // Create the popup menu + wxMenu MenuPopup; - wxMenuItem* Item = new wxMenuItem(&MenuPopup, wxID_ANY, _("Select floating windows")); - MenuPopup.Append(Item); - Item->Enable(false); - MenuPopup.Append(new wxMenuItem(&MenuPopup)); + wxMenuItem* Item = new wxMenuItem(&MenuPopup, wxID_ANY, _("Select floating windows")); + MenuPopup.Append(Item); + Item->Enable(false); + MenuPopup.Append(new wxMenuItem(&MenuPopup)); - for (int i = IDM_LOG_WINDOW; i <= IDM_CODE_WINDOW; i++) - { - wxWindow *Win = FindWindowById(i); - if (Win && Win->IsEnabled()) - { - Item = new wxMenuItem(&MenuPopup, i + IDM_FLOAT_LOG_WINDOW - IDM_LOG_WINDOW, - Win->GetName(), "", wxITEM_CHECK); - MenuPopup.Append(Item); - Item->Check(!!FindWindowById(i + IDM_LOG_WINDOW_PARENT - IDM_LOG_WINDOW)); - } - } + for (int i = IDM_LOG_WINDOW; i <= IDM_CODE_WINDOW; i++) + { + wxWindow* Win = FindWindowById(i); + if (Win && Win->IsEnabled()) + { + Item = new wxMenuItem(&MenuPopup, i + IDM_FLOAT_LOG_WINDOW - IDM_LOG_WINDOW, Win->GetName(), + "", wxITEM_CHECK); + MenuPopup.Append(Item); + Item->Check(!!FindWindowById(i + IDM_LOG_WINDOW_PARENT - IDM_LOG_WINDOW)); + } + } - // Line up our menu with the cursor - wxPoint Pt = ::wxGetMousePosition(); - Pt = ScreenToClient(Pt); + // Line up our menu with the cursor + wxPoint Pt = ::wxGetMousePosition(); + Pt = ScreenToClient(Pt); - // Show - PopupMenu(&MenuPopup, Pt); + // Show + PopupMenu(&MenuPopup, Pt); } void CFrame::OnAllowNotebookDnD(wxAuiNotebookEvent& event) { - event.Skip(); - event.Allow(); + event.Skip(); + event.Allow(); } void CFrame::ShowResizePane() { - if (!m_LogWindow) return; + if (!m_LogWindow) + return; - // Make sure the size is sane - if (m_LogWindow->x > GetClientRect().GetWidth()) - m_LogWindow->x = GetClientRect().GetWidth() / 2; - if (m_LogWindow->y > GetClientRect().GetHeight()) - m_LogWindow->y = GetClientRect().GetHeight() / 2; + // Make sure the size is sane + if (m_LogWindow->x > GetClientRect().GetWidth()) + m_LogWindow->x = GetClientRect().GetWidth() / 2; + if (m_LogWindow->y > GetClientRect().GetHeight()) + m_LogWindow->y = GetClientRect().GetHeight() / 2; - wxAuiPaneInfo &pane = m_Mgr->GetPane("Pane 1"); + wxAuiPaneInfo& pane = m_Mgr->GetPane("Pane 1"); - // Hide first otherwise a resize doesn't work - pane.Hide(); - m_Mgr->Update(); + // Hide first otherwise a resize doesn't work + pane.Hide(); + m_Mgr->Update(); - pane.BestSize(m_LogWindow->x, m_LogWindow->y) - .MinSize(m_LogWindow->x, m_LogWindow->y) - .Direction(m_LogWindow->winpos).Show(); - m_Mgr->Update(); + pane.BestSize(m_LogWindow->x, m_LogWindow->y) + .MinSize(m_LogWindow->x, m_LogWindow->y) + .Direction(m_LogWindow->winpos) + .Show(); + m_Mgr->Update(); - // Reset the minimum size of the pane - pane.MinSize(-1, -1); - m_Mgr->Update(); + // Reset the minimum size of the pane + pane.MinSize(-1, -1); + m_Mgr->Update(); } void CFrame::TogglePane() { - // Get the first notebook - wxAuiNotebook * NB = nullptr; - for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) - { - if (m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiNotebook))) - NB = (wxAuiNotebook*)m_Mgr->GetAllPanes()[i].window; - } + // Get the first notebook + wxAuiNotebook* NB = nullptr; + for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) + { + if (m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiNotebook))) + NB = (wxAuiNotebook*)m_Mgr->GetAllPanes()[i].window; + } - if (NB) - { - if (NB->GetPageCount() == 0) - { - m_Mgr->GetPane("Pane 1").Hide(); - m_Mgr->Update(); - } - else - { - ShowResizePane(); - } - } + if (NB) + { + if (NB->GetPageCount() == 0) + { + m_Mgr->GetPane("Pane 1").Hide(); + m_Mgr->Update(); + } + else + { + ShowResizePane(); + } + } } -void CFrame::DoRemovePage(wxWindow *Win, bool bHide) +void CFrame::DoRemovePage(wxWindow* Win, bool bHide) { - if (!Win) return; + if (!Win) + return; - wxWindow *Parent = FindWindowById(Win->GetId() + - IDM_LOG_WINDOW_PARENT - IDM_LOG_WINDOW); + wxWindow* Parent = FindWindowById(Win->GetId() + IDM_LOG_WINDOW_PARENT - IDM_LOG_WINDOW); - if (Parent) - { - if (bHide) - { - Win->Hide(); - Win->Reparent(this); - } - else - { - Win->Destroy(); - } + if (Parent) + { + if (bHide) + { + Win->Hide(); + Win->Reparent(this); + } + else + { + Win->Destroy(); + } - Parent->Destroy(); - } - else - { - for (int i = 0; i < GetNotebookCount(); i++) - { - int PageIndex = GetNotebookFromId(i)->GetPageIndex(Win); - if (PageIndex != wxNOT_FOUND) - { - GetNotebookFromId(i)->RemovePage(PageIndex); - if (bHide) - { - Win->Hide(); - Win->Reparent(this); - } - else - { - Win->Destroy(); - } - } - } - } + Parent->Destroy(); + } + else + { + for (int i = 0; i < GetNotebookCount(); i++) + { + int PageIndex = GetNotebookFromId(i)->GetPageIndex(Win); + if (PageIndex != wxNOT_FOUND) + { + GetNotebookFromId(i)->RemovePage(PageIndex); + if (bHide) + { + Win->Hide(); + Win->Reparent(this); + } + else + { + Win->Destroy(); + } + } + } + } - if (g_pCodeWindow) - AddRemoveBlankPage(); + if (g_pCodeWindow) + AddRemoveBlankPage(); } -void CFrame::DoAddPage(wxWindow *Win, int i, bool Float) +void CFrame::DoAddPage(wxWindow* Win, int i, bool Float) { - if (!Win) return; + if (!Win) + return; - // Ensure accessor remains within valid bounds. - if (i < 0 || i > GetNotebookCount() - 1) - i = 0; + // Ensure accessor remains within valid bounds. + if (i < 0 || i > GetNotebookCount() - 1) + i = 0; - // The page was already previously added, no need to add it again. - if (Win && GetNotebookFromId(i)->GetPageIndex(Win) != wxNOT_FOUND) - return; + // The page was already previously added, no need to add it again. + if (Win && GetNotebookFromId(i)->GetPageIndex(Win) != wxNOT_FOUND) + return; - if (!Float) - GetNotebookFromId(i)->AddPage(Win, Win->GetName(), true); - else - CreateParentFrame(Win->GetId() + IDM_LOG_WINDOW_PARENT - IDM_LOG_WINDOW, - Win->GetName(), Win); + if (!Float) + GetNotebookFromId(i)->AddPage(Win, Win->GetName(), true); + else + CreateParentFrame(Win->GetId() + IDM_LOG_WINDOW_PARENT - IDM_LOG_WINDOW, Win->GetName(), Win); } void CFrame::PopulateSavedPerspectives() { - // If the perspective submenu hasn't been created yet, return - if (!m_SavedPerspectives) return; + // If the perspective submenu hasn't been created yet, return + if (!m_SavedPerspectives) + return; - // Delete all saved perspective menu items - while (m_SavedPerspectives->GetMenuItemCount() != 0) - { - // Delete the first menu item in the list (while there are menu items) - m_SavedPerspectives->Delete(m_SavedPerspectives->FindItemByPosition(0)); - } + // Delete all saved perspective menu items + while (m_SavedPerspectives->GetMenuItemCount() != 0) + { + // Delete the first menu item in the list (while there are menu items) + m_SavedPerspectives->Delete(m_SavedPerspectives->FindItemByPosition(0)); + } - if (Perspectives.size() > 0) - { - for (u32 i = 0; i < Perspectives.size(); i++) - { - wxMenuItem* mItem = new wxMenuItem(m_SavedPerspectives, IDM_PERSPECTIVES_0 + i, - StrToWxStr(Perspectives[i].Name), "", wxITEM_CHECK); + if (Perspectives.size() > 0) + { + for (u32 i = 0; i < Perspectives.size(); i++) + { + wxMenuItem* mItem = new wxMenuItem(m_SavedPerspectives, IDM_PERSPECTIVES_0 + i, + StrToWxStr(Perspectives[i].Name), "", wxITEM_CHECK); - m_SavedPerspectives->Append(mItem); + m_SavedPerspectives->Append(mItem); - if (i == ActivePerspective) - { - mItem->Check(true); - } - } - } + if (i == ActivePerspective) + { + mItem->Check(true); + } + } + } } void CFrame::OnPerspectiveMenu(wxCommandEvent& event) { - ClearStatusBar(); + ClearStatusBar(); - switch (event.GetId()) - { - case IDM_SAVE_PERSPECTIVE: - if (Perspectives.size() == 0) - { - wxMessageBox(_("Please create a perspective before saving"), - _("Notice"), wxOK, this); - return; - } - SaveIniPerspectives(); - GetStatusBar()->SetStatusText(StrToWxStr(std::string - ("Saved " + Perspectives[ActivePerspective].Name)), 0); - break; - case IDM_PERSPECTIVES_ADD_PANE_TOP: - AddPane(ADD_PANE_TOP); - break; - case IDM_PERSPECTIVES_ADD_PANE_BOTTOM: - AddPane(ADD_PANE_BOTTOM); - break; - case IDM_PERSPECTIVES_ADD_PANE_LEFT: - AddPane(ADD_PANE_LEFT); - break; - case IDM_PERSPECTIVES_ADD_PANE_RIGHT: - AddPane(ADD_PANE_RIGHT); - break; - case IDM_PERSPECTIVES_ADD_PANE_CENTER: - AddPane(ADD_PANE_CENTER); - break; - case IDM_EDIT_PERSPECTIVES: - m_bEdit = event.IsChecked(); - TogglePaneStyle(m_bEdit, IDM_EDIT_PERSPECTIVES); - break; - case IDM_ADD_PERSPECTIVE: - { - wxTextEntryDialog dlg(this, - _("Enter a name for the new perspective:"), - _("Create new perspective")); - wxString DefaultValue = wxString::Format(_("Perspective %d"), (int)(Perspectives.size() + 1)); - dlg.SetValue(DefaultValue); + switch (event.GetId()) + { + case IDM_SAVE_PERSPECTIVE: + if (Perspectives.size() == 0) + { + wxMessageBox(_("Please create a perspective before saving"), _("Notice"), wxOK, this); + return; + } + SaveIniPerspectives(); + GetStatusBar()->SetStatusText( + StrToWxStr(std::string("Saved " + Perspectives[ActivePerspective].Name)), 0); + break; + case IDM_PERSPECTIVES_ADD_PANE_TOP: + AddPane(ADD_PANE_TOP); + break; + case IDM_PERSPECTIVES_ADD_PANE_BOTTOM: + AddPane(ADD_PANE_BOTTOM); + break; + case IDM_PERSPECTIVES_ADD_PANE_LEFT: + AddPane(ADD_PANE_LEFT); + break; + case IDM_PERSPECTIVES_ADD_PANE_RIGHT: + AddPane(ADD_PANE_RIGHT); + break; + case IDM_PERSPECTIVES_ADD_PANE_CENTER: + AddPane(ADD_PANE_CENTER); + break; + case IDM_EDIT_PERSPECTIVES: + m_bEdit = event.IsChecked(); + TogglePaneStyle(m_bEdit, IDM_EDIT_PERSPECTIVES); + break; + case IDM_ADD_PERSPECTIVE: + { + wxTextEntryDialog dlg(this, _("Enter a name for the new perspective:"), + _("Create new perspective")); + wxString DefaultValue = wxString::Format(_("Perspective %d"), (int)(Perspectives.size() + 1)); + dlg.SetValue(DefaultValue); - int Return = 0; - bool DlgOk = false; + int Return = 0; + bool DlgOk = false; - while (!DlgOk) - { - Return = dlg.ShowModal(); - if (Return == wxID_CANCEL) - { - return; - } - else if (dlg.GetValue().Find(",") != -1) - { - wxMessageBox(_("The name cannot contain the character ','"), - _("Notice"), wxOK, this); - wxString Str = dlg.GetValue(); - Str.Replace(",", "", true); - dlg.SetValue(Str); - } - else if (dlg.GetValue().IsSameAs("")) - { - wxMessageBox(_("The name cannot be empty"), - _("Notice"), wxOK, this); - dlg.SetValue(DefaultValue); - } - else - { - DlgOk = true; - } - } + while (!DlgOk) + { + Return = dlg.ShowModal(); + if (Return == wxID_CANCEL) + { + return; + } + else if (dlg.GetValue().Find(",") != -1) + { + wxMessageBox(_("The name cannot contain the character ','"), _("Notice"), wxOK, this); + wxString Str = dlg.GetValue(); + Str.Replace(",", "", true); + dlg.SetValue(Str); + } + else if (dlg.GetValue().IsSameAs("")) + { + wxMessageBox(_("The name cannot be empty"), _("Notice"), wxOK, this); + dlg.SetValue(DefaultValue); + } + else + { + DlgOk = true; + } + } - SPerspectives Tmp; - Tmp.Name = WxStrToStr(dlg.GetValue()); - Tmp.Perspective = m_Mgr->SavePerspective(); + SPerspectives Tmp; + Tmp.Name = WxStrToStr(dlg.GetValue()); + Tmp.Perspective = m_Mgr->SavePerspective(); - ActivePerspective = (u32)Perspectives.size(); - Perspectives.push_back(Tmp); + ActivePerspective = (u32)Perspectives.size(); + Perspectives.push_back(Tmp); - UpdateCurrentPerspective(); - PopulateSavedPerspectives(); - } - break; - case IDM_TAB_SPLIT: - m_bTabSplit = event.IsChecked(); - ToggleNotebookStyle(m_bTabSplit, wxAUI_NB_TAB_SPLIT); - break; - case IDM_NO_DOCKING: - m_bNoDocking = event.IsChecked(); - TogglePaneStyle(m_bNoDocking, IDM_NO_DOCKING); - break; - } + UpdateCurrentPerspective(); + PopulateSavedPerspectives(); + } + break; + case IDM_TAB_SPLIT: + m_bTabSplit = event.IsChecked(); + ToggleNotebookStyle(m_bTabSplit, wxAUI_NB_TAB_SPLIT); + break; + case IDM_NO_DOCKING: + m_bNoDocking = event.IsChecked(); + TogglePaneStyle(m_bNoDocking, IDM_NO_DOCKING); + break; + } } void CFrame::TogglePaneStyle(bool On, int EventId) { - wxAuiPaneInfoArray& AllPanes = m_Mgr->GetAllPanes(); - for (u32 i = 0; i < AllPanes.GetCount(); ++i) - { - wxAuiPaneInfo& Pane = AllPanes[i]; - if (Pane.window->IsKindOf(CLASSINFO(wxAuiNotebook))) - { - // Default - Pane.CloseButton(true); - Pane.MaximizeButton(true); - Pane.MinimizeButton(true); - Pane.PinButton(true); - Pane.Show(); + wxAuiPaneInfoArray& AllPanes = m_Mgr->GetAllPanes(); + for (u32 i = 0; i < AllPanes.GetCount(); ++i) + { + wxAuiPaneInfo& Pane = AllPanes[i]; + if (Pane.window->IsKindOf(CLASSINFO(wxAuiNotebook))) + { + // Default + Pane.CloseButton(true); + Pane.MaximizeButton(true); + Pane.MinimizeButton(true); + Pane.PinButton(true); + Pane.Show(); - switch (EventId) - { - case IDM_EDIT_PERSPECTIVES: - Pane.CaptionVisible(On); - Pane.Movable(On); - Pane.Floatable(On); - Pane.Dockable(On); - break; - } - Pane.Dockable(!m_bNoDocking); - } - } - m_Mgr->Update(); + switch (EventId) + { + case IDM_EDIT_PERSPECTIVES: + Pane.CaptionVisible(On); + Pane.Movable(On); + Pane.Floatable(On); + Pane.Dockable(On); + break; + } + Pane.Dockable(!m_bNoDocking); + } + } + m_Mgr->Update(); } void CFrame::ToggleNotebookStyle(bool On, long Style) { - wxAuiPaneInfoArray& AllPanes = m_Mgr->GetAllPanes(); - for (int i = 0, Count = (int)AllPanes.GetCount(); i < Count; ++i) - { - wxAuiPaneInfo& Pane = AllPanes[i]; - if (Pane.window->IsKindOf(CLASSINFO(wxAuiNotebook))) - { - wxAuiNotebook* NB = (wxAuiNotebook*)Pane.window; + wxAuiPaneInfoArray& AllPanes = m_Mgr->GetAllPanes(); + for (int i = 0, Count = (int)AllPanes.GetCount(); i < Count; ++i) + { + wxAuiPaneInfo& Pane = AllPanes[i]; + if (Pane.window->IsKindOf(CLASSINFO(wxAuiNotebook))) + { + wxAuiNotebook* NB = (wxAuiNotebook*)Pane.window; - if (On) - NB->SetWindowStyleFlag(NB->GetWindowStyleFlag() | Style); - else - NB->SetWindowStyleFlag(NB->GetWindowStyleFlag() &~ Style); + if (On) + NB->SetWindowStyleFlag(NB->GetWindowStyleFlag() | Style); + else + NB->SetWindowStyleFlag(NB->GetWindowStyleFlag() & ~Style); - NB->Refresh(); - } - } + NB->Refresh(); + } + } } void CFrame::OnSelectPerspective(wxCommandEvent& event) { - u32 _Selection = event.GetId() - IDM_PERSPECTIVES_0; - if (Perspectives.size() <= _Selection) _Selection = 0; - ActivePerspective = _Selection; - DoLoadPerspective(); + u32 _Selection = event.GetId() - IDM_PERSPECTIVES_0; + if (Perspectives.size() <= _Selection) + _Selection = 0; + ActivePerspective = _Selection; + DoLoadPerspective(); } void CFrame::SetPaneSize() { - if (Perspectives.size() <= ActivePerspective) - return; + if (Perspectives.size() <= ActivePerspective) + return; - int iClientX = GetSize().GetX(); - int iClientY = GetSize().GetY(); + int iClientX = GetSize().GetX(); + int iClientY = GetSize().GetY(); - for (u32 i = 0, j = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) - { - if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiToolBar))) - { - if (!m_Mgr->GetAllPanes()[i].IsOk()) - return; + for (u32 i = 0, j = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) + { + if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiToolBar))) + { + if (!m_Mgr->GetAllPanes()[i].IsOk()) + return; - if (Perspectives[ActivePerspective].Width.size() <= j || - Perspectives[ActivePerspective].Height.size() <= j) - continue; + if (Perspectives[ActivePerspective].Width.size() <= j || + Perspectives[ActivePerspective].Height.size() <= j) + continue; - // Width and height of the active perspective - u32 W = Perspectives[ActivePerspective].Width[j], - H = Perspectives[ActivePerspective].Height[j]; + // Width and height of the active perspective + u32 W = Perspectives[ActivePerspective].Width[j], + H = Perspectives[ActivePerspective].Height[j]; - // Check limits - W = MathUtil::Clamp(W, 5, 95); - H = MathUtil::Clamp(H, 5, 95); + // Check limits + W = MathUtil::Clamp(W, 5, 95); + H = MathUtil::Clamp(H, 5, 95); - // Convert percentages to pixel lengths - W = (W * iClientX) / 100; - H = (H * iClientY) / 100; - m_Mgr->GetAllPanes()[i].BestSize(W, H).MinSize(W, H); + // Convert percentages to pixel lengths + W = (W * iClientX) / 100; + H = (H * iClientY) / 100; + m_Mgr->GetAllPanes()[i].BestSize(W, H).MinSize(W, H); - j++; - } - } - m_Mgr->Update(); + j++; + } + } + m_Mgr->Update(); - for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) - { - if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiToolBar))) - { - m_Mgr->GetAllPanes()[i].MinSize(-1, -1); - } - } + for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) + { + if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiToolBar))) + { + m_Mgr->GetAllPanes()[i].MinSize(-1, -1); + } + } } void CFrame::ReloadPanes() { - // Close all pages - ClosePages(); + // Close all pages + ClosePages(); - CloseAllNotebooks(); + CloseAllNotebooks(); - // Create new panes with notebooks - for (u32 i = 0; i < Perspectives[ActivePerspective].Width.size() - 1; i++) - { - wxString PaneName = wxString::Format("Pane %i", i + 1); - m_Mgr->AddPane(CreateEmptyNotebook(), wxAuiPaneInfo().Hide() - .CaptionVisible(m_bEdit).Dockable(!m_bNoDocking).Position(i) - .Name(PaneName).Caption(PaneName)); - } + // Create new panes with notebooks + for (u32 i = 0; i < Perspectives[ActivePerspective].Width.size() - 1; i++) + { + wxString PaneName = wxString::Format("Pane %i", i + 1); + m_Mgr->AddPane(CreateEmptyNotebook(), wxAuiPaneInfo() + .Hide() + .CaptionVisible(m_bEdit) + .Dockable(!m_bNoDocking) + .Position(i) + .Name(PaneName) + .Caption(PaneName)); + } - // Perspectives - m_Mgr->LoadPerspective(Perspectives[ActivePerspective].Perspective, false); - // Restore settings - TogglePaneStyle(m_bNoDocking, IDM_NO_DOCKING); - TogglePaneStyle(m_bEdit, IDM_EDIT_PERSPECTIVES); + // Perspectives + m_Mgr->LoadPerspective(Perspectives[ActivePerspective].Perspective, false); + // Restore settings + TogglePaneStyle(m_bNoDocking, IDM_NO_DOCKING); + TogglePaneStyle(m_bEdit, IDM_EDIT_PERSPECTIVES); - // Load GUI settings - g_pCodeWindow->Load(); - // Open notebook pages - AddRemoveBlankPage(); - g_pCodeWindow->OpenPages(); + // Load GUI settings + g_pCodeWindow->Load(); + // Open notebook pages + AddRemoveBlankPage(); + g_pCodeWindow->OpenPages(); - // Repopulate perspectives - PopulateSavedPerspectives(); + // Repopulate perspectives + PopulateSavedPerspectives(); } void CFrame::DoLoadPerspective() { - ReloadPanes(); - // Restore the exact window sizes, which LoadPerspective doesn't always do - SetPaneSize(); + ReloadPanes(); + // Restore the exact window sizes, which LoadPerspective doesn't always do + SetPaneSize(); - m_Mgr->Update(); + m_Mgr->Update(); } // Update the local perspectives array void CFrame::LoadIniPerspectives() { - Perspectives.clear(); - std::vector VPerspectives; - std::string _Perspectives; + Perspectives.clear(); + std::vector VPerspectives; + std::string _Perspectives; - IniFile ini; - ini.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); + IniFile ini; + ini.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); - IniFile::Section* perspectives = ini.GetOrCreateSection("Perspectives"); - perspectives->Get("Perspectives", &_Perspectives, "Perspective 1"); - perspectives->Get("Active", &ActivePerspective, 0); - SplitString(_Perspectives, ',', VPerspectives); + IniFile::Section* perspectives = ini.GetOrCreateSection("Perspectives"); + perspectives->Get("Perspectives", &_Perspectives, "Perspective 1"); + perspectives->Get("Active", &ActivePerspective, 0); + SplitString(_Perspectives, ',', VPerspectives); - for (auto& VPerspective : VPerspectives) - { - SPerspectives Tmp; - std::string _Section, _Perspective, _Widths, _Heights; - std::vector _SWidth, _SHeight; - Tmp.Name = VPerspective; + for (auto& VPerspective : VPerspectives) + { + SPerspectives Tmp; + std::string _Section, _Perspective, _Widths, _Heights; + std::vector _SWidth, _SHeight; + Tmp.Name = VPerspective; - // Don't save a blank perspective - if (Tmp.Name.empty()) - { - continue; - } + // Don't save a blank perspective + if (Tmp.Name.empty()) + { + continue; + } - _Section = StringFromFormat("P - %s", Tmp.Name.c_str()); + _Section = StringFromFormat("P - %s", Tmp.Name.c_str()); - IniFile::Section* perspec_section = ini.GetOrCreateSection(_Section); - perspec_section->Get("Perspective", &_Perspective, - "layout2|" - "name=Pane 0;caption=Pane 0;state=768;dir=5;prop=100000;|" - "name=Pane 1;caption=Pane 1;state=31458108;dir=4;prop=100000;|" - "dock_size(5,0,0)=22|dock_size(4,0,0)=333|"); - perspec_section->Get("Width", &_Widths, "70,25"); - perspec_section->Get("Height", &_Heights, "80,80"); + IniFile::Section* perspec_section = ini.GetOrCreateSection(_Section); + perspec_section->Get("Perspective", &_Perspective, + "layout2|" + "name=Pane 0;caption=Pane 0;state=768;dir=5;prop=100000;|" + "name=Pane 1;caption=Pane 1;state=31458108;dir=4;prop=100000;|" + "dock_size(5,0,0)=22|dock_size(4,0,0)=333|"); + perspec_section->Get("Width", &_Widths, "70,25"); + perspec_section->Get("Height", &_Heights, "80,80"); - Tmp.Perspective = StrToWxStr(_Perspective); + Tmp.Perspective = StrToWxStr(_Perspective); - SplitString(_Widths, ',', _SWidth); - SplitString(_Heights, ',', _SHeight); - for (auto& Width : _SWidth) - { - int _Tmp; - if (TryParse(Width, &_Tmp)) - Tmp.Width.push_back(_Tmp); - } - for (auto& Height : _SHeight) - { - int _Tmp; - if (TryParse(Height, &_Tmp)) - Tmp.Height.push_back(_Tmp); - } - Perspectives.push_back(Tmp); - } + SplitString(_Widths, ',', _SWidth); + SplitString(_Heights, ',', _SHeight); + for (auto& Width : _SWidth) + { + int _Tmp; + if (TryParse(Width, &_Tmp)) + Tmp.Width.push_back(_Tmp); + } + for (auto& Height : _SHeight) + { + int _Tmp; + if (TryParse(Height, &_Tmp)) + Tmp.Height.push_back(_Tmp); + } + Perspectives.push_back(Tmp); + } } void CFrame::UpdateCurrentPerspective() { - SPerspectives *current = &Perspectives[ActivePerspective]; - current->Perspective = m_Mgr->SavePerspective(); + SPerspectives* current = &Perspectives[ActivePerspective]; + current->Perspective = m_Mgr->SavePerspective(); - // Get client size - int iClientX = GetSize().GetX(), iClientY = GetSize().GetY(); - current->Width.clear(); - current->Height.clear(); - for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) - { - if (!m_Mgr->GetAllPanes()[i].window-> - IsKindOf(CLASSINFO(wxAuiToolBar))) - { - // Save width and height as a percentage of the client width and height - current->Width.push_back( - (m_Mgr->GetAllPanes()[i].window->GetClientSize().GetX() * 100) / - iClientX); - current->Height.push_back( - (m_Mgr->GetAllPanes()[i].window->GetClientSize().GetY() * 100) / - iClientY); - } - } + // Get client size + int iClientX = GetSize().GetX(), iClientY = GetSize().GetY(); + current->Width.clear(); + current->Height.clear(); + for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) + { + if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiToolBar))) + { + // Save width and height as a percentage of the client width and height + current->Width.push_back((m_Mgr->GetAllPanes()[i].window->GetClientSize().GetX() * 100) / + iClientX); + current->Height.push_back((m_Mgr->GetAllPanes()[i].window->GetClientSize().GetY() * 100) / + iClientY); + } + } } void CFrame::SaveIniPerspectives() { - if (Perspectives.size() == 0) return; - if (ActivePerspective >= Perspectives.size()) ActivePerspective = 0; + if (Perspectives.size() == 0) + return; + if (ActivePerspective >= Perspectives.size()) + ActivePerspective = 0; - // Turn off edit before saving - TogglePaneStyle(false, IDM_EDIT_PERSPECTIVES); + // Turn off edit before saving + TogglePaneStyle(false, IDM_EDIT_PERSPECTIVES); - UpdateCurrentPerspective(); + UpdateCurrentPerspective(); - IniFile ini; - ini.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); + IniFile ini; + ini.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); - // Save perspective names - std::string STmp = ""; - for (auto& Perspective : Perspectives) - { - STmp += Perspective.Name + ","; - } - STmp = STmp.substr(0, STmp.length() - 1); + // Save perspective names + std::string STmp = ""; + for (auto& Perspective : Perspectives) + { + STmp += Perspective.Name + ","; + } + STmp = STmp.substr(0, STmp.length() - 1); - IniFile::Section* perspectives = ini.GetOrCreateSection("Perspectives"); - perspectives->Set("Perspectives", STmp); - perspectives->Set("Active", ActivePerspective); + IniFile::Section* perspectives = ini.GetOrCreateSection("Perspectives"); + perspectives->Set("Perspectives", STmp); + perspectives->Set("Active", ActivePerspective); - // Save the perspectives - for (auto& Perspective : Perspectives) - { - std::string _Section = "P - " + Perspective.Name; - IniFile::Section* perspec_section = ini.GetOrCreateSection(_Section); - perspec_section->Set("Perspective", WxStrToStr(Perspective.Perspective)); + // Save the perspectives + for (auto& Perspective : Perspectives) + { + std::string _Section = "P - " + Perspective.Name; + IniFile::Section* perspec_section = ini.GetOrCreateSection(_Section); + perspec_section->Set("Perspective", WxStrToStr(Perspective.Perspective)); - std::string SWidth = "", SHeight = ""; - for (u32 j = 0; j < Perspective.Width.size(); j++) - { - SWidth += StringFromFormat("%i,", Perspective.Width[j]); - SHeight += StringFromFormat("%i,", Perspective.Height[j]); - } - // Remove the ending "," - SWidth = SWidth.substr(0, SWidth.length() - 1); - SHeight = SHeight.substr(0, SHeight.length() - 1); + std::string SWidth = "", SHeight = ""; + for (u32 j = 0; j < Perspective.Width.size(); j++) + { + SWidth += StringFromFormat("%i,", Perspective.Width[j]); + SHeight += StringFromFormat("%i,", Perspective.Height[j]); + } + // Remove the ending "," + SWidth = SWidth.substr(0, SWidth.length() - 1); + SHeight = SHeight.substr(0, SHeight.length() - 1); - perspec_section->Set("Width", SWidth); - perspec_section->Set("Height", SHeight); - } + perspec_section->Set("Width", SWidth); + perspec_section->Set("Height", SHeight); + } - ini.Save(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); + ini.Save(File::GetUserPath(F_DEBUGGERCONFIG_IDX)); - // Save notebook affiliations - g_pCodeWindow->Save(); + // Save notebook affiliations + g_pCodeWindow->Save(); - TogglePaneStyle(m_bEdit, IDM_EDIT_PERSPECTIVES); + TogglePaneStyle(m_bEdit, IDM_EDIT_PERSPECTIVES); } void CFrame::AddPane(int dir) { - int PaneNum = GetNotebookCount() + 1; - wxString PaneName = wxString::Format("Pane %i", PaneNum); - wxAuiPaneInfo PaneInfo = wxAuiPaneInfo() - .CaptionVisible(m_bEdit).Dockable(!m_bNoDocking) - .Name(PaneName).Caption(PaneName) - .Position(GetNotebookCount()); + int PaneNum = GetNotebookCount() + 1; + wxString PaneName = wxString::Format("Pane %i", PaneNum); + wxAuiPaneInfo PaneInfo = wxAuiPaneInfo() + .CaptionVisible(m_bEdit) + .Dockable(!m_bNoDocking) + .Name(PaneName) + .Caption(PaneName) + .Position(GetNotebookCount()); - switch (dir) - { - case ADD_PANE_TOP: - PaneInfo = PaneInfo.Top(); - break; - case ADD_PANE_BOTTOM: - PaneInfo = PaneInfo.Bottom(); - break; - case ADD_PANE_LEFT: - PaneInfo = PaneInfo.Left(); - break; - case ADD_PANE_RIGHT: - PaneInfo = PaneInfo.Right(); - break; - case ADD_PANE_CENTER: - PaneInfo = PaneInfo.Center(); - break; - default: - break; - } + switch (dir) + { + case ADD_PANE_TOP: + PaneInfo = PaneInfo.Top(); + break; + case ADD_PANE_BOTTOM: + PaneInfo = PaneInfo.Bottom(); + break; + case ADD_PANE_LEFT: + PaneInfo = PaneInfo.Left(); + break; + case ADD_PANE_RIGHT: + PaneInfo = PaneInfo.Right(); + break; + case ADD_PANE_CENTER: + PaneInfo = PaneInfo.Center(); + break; + default: + break; + } - m_Mgr->AddPane(CreateEmptyNotebook(), PaneInfo); + m_Mgr->AddPane(CreateEmptyNotebook(), PaneInfo); - AddRemoveBlankPage(); - m_Mgr->Update(); + AddRemoveBlankPage(); + m_Mgr->Update(); } -wxWindow * CFrame::GetNotebookPageFromId(wxWindowID Id) +wxWindow* CFrame::GetNotebookPageFromId(wxWindowID Id) { - for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) - { - if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiNotebook))) - continue; + for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) + { + if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiNotebook))) + continue; - wxAuiNotebook * NB = (wxAuiNotebook*)m_Mgr->GetAllPanes()[i].window; - for (u32 j = 0; j < NB->GetPageCount(); j++) - { - if (NB->GetPage(j)->GetId() == Id) - return NB->GetPage(j); - } - } - return nullptr; + wxAuiNotebook* NB = (wxAuiNotebook*)m_Mgr->GetAllPanes()[i].window; + for (u32 j = 0; j < NB->GetPageCount(); j++) + { + if (NB->GetPage(j)->GetId() == Id) + return NB->GetPage(j); + } + } + return nullptr; } wxFrame* CFrame::CreateParentFrame(wxWindowID Id, const wxString& Title, wxWindow* Child) { - wxFrame* Frame = new wxFrame(this, Id, Title); + wxFrame* Frame = new wxFrame(this, Id, Title); - Child->Reparent(Frame); + Child->Reparent(Frame); - wxBoxSizer* m_MainSizer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* m_MainSizer = new wxBoxSizer(wxHORIZONTAL); - m_MainSizer->Add(Child, 1, wxEXPAND); + m_MainSizer->Add(Child, 1, wxEXPAND); - Frame->Bind(wxEVT_CLOSE_WINDOW, &CFrame::OnFloatingPageClosed, this); + Frame->Bind(wxEVT_CLOSE_WINDOW, &CFrame::OnFloatingPageClosed, this); - // Main sizer - Frame->SetSizer(m_MainSizer); - // Minimum frame size - Frame->SetMinSize(wxSize(200, 200)); - Frame->Show(); - return Frame; + // Main sizer + Frame->SetSizer(m_MainSizer); + // Minimum frame size + Frame->SetMinSize(wxSize(200, 200)); + Frame->Show(); + return Frame; } wxAuiNotebook* CFrame::CreateEmptyNotebook() { - const long NOTEBOOK_STYLE = wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | - wxAUI_NB_TAB_MOVE | - wxAUI_NB_TAB_EXTERNAL_MOVE | wxAUI_NB_SCROLL_BUTTONS | - wxAUI_NB_WINDOWLIST_BUTTON | wxNO_BORDER; + const long NOTEBOOK_STYLE = wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE | + wxAUI_NB_TAB_EXTERNAL_MOVE | wxAUI_NB_SCROLL_BUTTONS | + wxAUI_NB_WINDOWLIST_BUTTON | wxNO_BORDER; - return new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, NOTEBOOK_STYLE); + return new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, NOTEBOOK_STYLE); } void CFrame::AddRemoveBlankPage() { - for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) - { - if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiNotebook))) - continue; + for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) + { + if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiNotebook))) + continue; - wxAuiNotebook * NB = (wxAuiNotebook*)m_Mgr->GetAllPanes()[i].window; - for (u32 j = 0; j < NB->GetPageCount(); j++) - { - if (NB->GetPageText(j).IsSameAs("<>") && NB->GetPageCount() > 1) - NB->DeletePage(j); - } + wxAuiNotebook* NB = (wxAuiNotebook*)m_Mgr->GetAllPanes()[i].window; + for (u32 j = 0; j < NB->GetPageCount(); j++) + { + if (NB->GetPageText(j).IsSameAs("<>") && NB->GetPageCount() > 1) + NB->DeletePage(j); + } - if (NB->GetPageCount() == 0) - NB->AddPage(new wxPanel(this, wxID_ANY), "<>", true); - } + if (NB->GetPageCount() == 0) + NB->AddPage(new wxPanel(this, wxID_ANY), "<>", true); + } } int CFrame::GetNotebookAffiliation(wxWindowID Id) { - for (u32 i = 0, j = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) - { - if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiNotebook))) - continue; + for (u32 i = 0, j = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) + { + if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiNotebook))) + continue; - wxAuiNotebook * NB = (wxAuiNotebook*)m_Mgr->GetAllPanes()[i].window; - for (u32 k = 0; k < NB->GetPageCount(); k++) - { - if (NB->GetPage(k)->GetId() == Id) - return j; - } - j++; - } - return -1; + wxAuiNotebook* NB = (wxAuiNotebook*)m_Mgr->GetAllPanes()[i].window; + for (u32 k = 0; k < NB->GetPageCount(); k++) + { + if (NB->GetPage(k)->GetId() == Id) + return j; + } + j++; + } + return -1; } // Close all panes with notebooks void CFrame::CloseAllNotebooks() { - wxAuiPaneInfoArray AllPanes = m_Mgr->GetAllPanes(); - for (u32 i = 0; i < AllPanes.GetCount(); i++) - { - if (AllPanes[i].window->IsKindOf(CLASSINFO(wxAuiNotebook))) - { - AllPanes[i].DestroyOnClose(true); - m_Mgr->ClosePane(AllPanes[i]); - } - } + wxAuiPaneInfoArray AllPanes = m_Mgr->GetAllPanes(); + for (u32 i = 0; i < AllPanes.GetCount(); i++) + { + if (AllPanes[i].window->IsKindOf(CLASSINFO(wxAuiNotebook))) + { + AllPanes[i].DestroyOnClose(true); + m_Mgr->ClosePane(AllPanes[i]); + } + } } int CFrame::GetNotebookCount() { - int Ret = 0; - for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) - { - if (m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiNotebook))) - Ret++; - } - return Ret; + int Ret = 0; + for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) + { + if (m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiNotebook))) + Ret++; + } + return Ret; } -wxAuiNotebook * CFrame::GetNotebookFromId(u32 NBId) +wxAuiNotebook* CFrame::GetNotebookFromId(u32 NBId) { - for (u32 i = 0, j = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) - { - if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiNotebook))) - continue; - if (j == NBId) - return (wxAuiNotebook*)m_Mgr->GetAllPanes()[i].window; - j++; - } - return nullptr; + for (u32 i = 0, j = 0; i < m_Mgr->GetAllPanes().GetCount(); i++) + { + if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiNotebook))) + continue; + if (j == NBId) + return (wxAuiNotebook*)m_Mgr->GetAllPanes()[i].window; + j++; + } + return nullptr; } diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index e35b730040..44de0e8e99 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #ifdef __APPLE__ #include @@ -34,45 +34,45 @@ #include "Core/BootManager.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/Host.h" -#include "Core/HotkeyManager.h" -#include "Core/Movie.h" -#include "Core/State.h" #include "Core/HW/CPU.h" #include "Core/HW/DVDInterface.h" #include "Core/HW/GCKeyboard.h" #include "Core/HW/GCPad.h" #include "Core/HW/ProcessorInterface.h" #include "Core/HW/SI_Device.h" -#include "Core/HW/Wiimote.h" #include "Core/HW/WiiSaveCrypted.h" +#include "Core/HW/Wiimote.h" +#include "Core/Host.h" +#include "Core/HotkeyManager.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" #include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h" -#include "Core/PowerPC/PowerPC.h" +#include "Core/Movie.h" #include "Core/PowerPC/PPCSymbolDB.h" +#include "Core/PowerPC/PowerPC.h" +#include "Core/State.h" #include "DiscIO/NANDContentLoader.h" #include "DolphinWX/AboutDolphin.h" +#include "DolphinWX/Cheats/CheatsWindow.h" +#include "DolphinWX/Config/ConfigMain.h" #include "DolphinWX/ControllerConfigDiag.h" +#include "DolphinWX/Debugger/BreakpointWindow.h" +#include "DolphinWX/Debugger/CodeWindow.h" +#include "DolphinWX/Debugger/WatchWindow.h" #include "DolphinWX/FifoPlayerDlg.h" #include "DolphinWX/Frame.h" #include "DolphinWX/GameListCtrl.h" #include "DolphinWX/Globals.h" -#include "DolphinWX/InputConfigDiag.h" #include "DolphinWX/ISOFile.h" +#include "DolphinWX/InputConfigDiag.h" #include "DolphinWX/LogWindow.h" #include "DolphinWX/MemcardManager.h" +#include "DolphinWX/NetPlay/NetPlaySetupFrame.h" +#include "DolphinWX/NetPlay/NetWindow.h" #include "DolphinWX/TASInputDlg.h" #include "DolphinWX/WXInputBase.h" #include "DolphinWX/WxUtils.h" -#include "DolphinWX/Cheats/CheatsWindow.h" -#include "DolphinWX/Config/ConfigMain.h" -#include "DolphinWX/Debugger/BreakpointWindow.h" -#include "DolphinWX/Debugger/CodeWindow.h" -#include "DolphinWX/Debugger/WatchWindow.h" -#include "DolphinWX/NetPlay/NetPlaySetupFrame.h" -#include "DolphinWX/NetPlay/NetWindow.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" @@ -100,505 +100,502 @@ class wxFrame; // This override allows returning a fake menubar object while removing the real one from the screen wxMenuBar* CFrame::GetMenuBar() const { - if (m_frameMenuBar) - { - return m_frameMenuBar; - } - else - { - return m_menubar_shadow; - } + if (m_frameMenuBar) + { + return m_frameMenuBar; + } + else + { + return m_menubar_shadow; + } } // Create menu items // --------------------- wxMenuBar* CFrame::CreateMenu() { - wxMenuBar* menubar = new wxMenuBar(); + wxMenuBar* menubar = new wxMenuBar(); - // file menu - wxMenu* fileMenu = new wxMenu; - fileMenu->Append(wxID_OPEN, GetMenuLabel(HK_OPEN)); - fileMenu->Append(IDM_CHANGE_DISC, GetMenuLabel(HK_CHANGE_DISC)); + // file menu + wxMenu* fileMenu = new wxMenu; + fileMenu->Append(wxID_OPEN, GetMenuLabel(HK_OPEN)); + fileMenu->Append(IDM_CHANGE_DISC, GetMenuLabel(HK_CHANGE_DISC)); - wxMenu *externalDrive = new wxMenu; - fileMenu->Append(IDM_DRIVES, _("&Boot from DVD Backup..."), externalDrive); + wxMenu* externalDrive = new wxMenu; + fileMenu->Append(IDM_DRIVES, _("&Boot from DVD Backup..."), externalDrive); - drives = cdio_get_devices(); - // Windows Limitation of 24 character drives - for (unsigned int i = 0; i < drives.size() && i < 24; i++) - { - externalDrive->Append(IDM_DRIVE1 + i, StrToWxStr(drives[i])); - } + drives = cdio_get_devices(); + // Windows Limitation of 24 character drives + for (unsigned int i = 0; i < drives.size() && i < 24; i++) + { + externalDrive->Append(IDM_DRIVE1 + i, StrToWxStr(drives[i])); + } - fileMenu->AppendSeparator(); - fileMenu->Append(wxID_REFRESH, GetMenuLabel(HK_REFRESH_LIST)); - fileMenu->AppendSeparator(); - fileMenu->Append(wxID_EXIT, _("E&xit") + wxString("\tAlt+F4")); - menubar->Append(fileMenu, _("&File")); + fileMenu->AppendSeparator(); + fileMenu->Append(wxID_REFRESH, GetMenuLabel(HK_REFRESH_LIST)); + fileMenu->AppendSeparator(); + fileMenu->Append(wxID_EXIT, _("E&xit") + wxString("\tAlt+F4")); + menubar->Append(fileMenu, _("&File")); - // Emulation menu - wxMenu* emulationMenu = new wxMenu; - emulationMenu->Append(IDM_PLAY, GetMenuLabel(HK_PLAY_PAUSE)); - emulationMenu->Append(IDM_STOP, GetMenuLabel(HK_STOP)); - emulationMenu->Append(IDM_RESET, GetMenuLabel(HK_RESET)); - emulationMenu->AppendSeparator(); - emulationMenu->Append(IDM_TOGGLE_FULLSCREEN, GetMenuLabel(HK_FULLSCREEN)); - emulationMenu->Append(IDM_FRAMESTEP, GetMenuLabel(HK_FRAME_ADVANCE), wxEmptyString); + // Emulation menu + wxMenu* emulationMenu = new wxMenu; + emulationMenu->Append(IDM_PLAY, GetMenuLabel(HK_PLAY_PAUSE)); + emulationMenu->Append(IDM_STOP, GetMenuLabel(HK_STOP)); + emulationMenu->Append(IDM_RESET, GetMenuLabel(HK_RESET)); + emulationMenu->AppendSeparator(); + emulationMenu->Append(IDM_TOGGLE_FULLSCREEN, GetMenuLabel(HK_FULLSCREEN)); + emulationMenu->Append(IDM_FRAMESTEP, GetMenuLabel(HK_FRAME_ADVANCE), wxEmptyString); - wxMenu *skippingMenu = new wxMenu; - emulationMenu->AppendSubMenu(skippingMenu, _("Frame S&kipping")); - for (int i = 0; i < 10; i++) - skippingMenu->AppendRadioItem(IDM_FRAME_SKIP_0 + i, wxString::Format("%i", i)); - skippingMenu->Check(IDM_FRAME_SKIP_0 + SConfig::GetInstance().m_FrameSkip, true); - Movie::SetFrameSkipping(SConfig::GetInstance().m_FrameSkip); + wxMenu* skippingMenu = new wxMenu; + emulationMenu->AppendSubMenu(skippingMenu, _("Frame S&kipping")); + for (int i = 0; i < 10; i++) + skippingMenu->AppendRadioItem(IDM_FRAME_SKIP_0 + i, wxString::Format("%i", i)); + skippingMenu->Check(IDM_FRAME_SKIP_0 + SConfig::GetInstance().m_FrameSkip, true); + Movie::SetFrameSkipping(SConfig::GetInstance().m_FrameSkip); - emulationMenu->AppendSeparator(); - emulationMenu->Append(IDM_SCREENSHOT, GetMenuLabel(HK_SCREENSHOT)); + emulationMenu->AppendSeparator(); + emulationMenu->Append(IDM_SCREENSHOT, GetMenuLabel(HK_SCREENSHOT)); - emulationMenu->AppendSeparator(); - wxMenu *saveMenu = new wxMenu; - wxMenu *loadMenu = new wxMenu; - wxMenu *slotSelectMenu = new wxMenu; - emulationMenu->Append(IDM_LOAD_STATE, _("&Load State"), loadMenu); - emulationMenu->Append(IDM_SAVE_STATE, _("Sa&ve State"), saveMenu); - emulationMenu->Append(IDM_SELECT_SLOT, _("Select State Slot"), slotSelectMenu); + emulationMenu->AppendSeparator(); + wxMenu* saveMenu = new wxMenu; + wxMenu* loadMenu = new wxMenu; + wxMenu* slotSelectMenu = new wxMenu; + emulationMenu->Append(IDM_LOAD_STATE, _("&Load State"), loadMenu); + emulationMenu->Append(IDM_SAVE_STATE, _("Sa&ve State"), saveMenu); + emulationMenu->Append(IDM_SELECT_SLOT, _("Select State Slot"), slotSelectMenu); - saveMenu->Append(IDM_SAVE_STATE_FILE, GetMenuLabel(HK_SAVE_STATE_FILE)); - saveMenu->Append(IDM_SAVE_SELECTED_SLOT, GetMenuLabel(HK_SAVE_STATE_SLOT_SELECTED)); - saveMenu->Append(IDM_SAVE_FIRST_STATE, GetMenuLabel(HK_SAVE_FIRST_STATE)); - saveMenu->Append(IDM_UNDO_SAVE_STATE, GetMenuLabel(HK_UNDO_SAVE_STATE)); - saveMenu->AppendSeparator(); + saveMenu->Append(IDM_SAVE_STATE_FILE, GetMenuLabel(HK_SAVE_STATE_FILE)); + saveMenu->Append(IDM_SAVE_SELECTED_SLOT, GetMenuLabel(HK_SAVE_STATE_SLOT_SELECTED)); + saveMenu->Append(IDM_SAVE_FIRST_STATE, GetMenuLabel(HK_SAVE_FIRST_STATE)); + saveMenu->Append(IDM_UNDO_SAVE_STATE, GetMenuLabel(HK_UNDO_SAVE_STATE)); + saveMenu->AppendSeparator(); - loadMenu->Append(IDM_LOAD_STATE_FILE, GetMenuLabel(HK_LOAD_STATE_FILE)); - loadMenu->Append(IDM_LOAD_SELECTED_SLOT, GetMenuLabel(HK_LOAD_STATE_SLOT_SELECTED)); - loadMenu->Append(IDM_UNDO_LOAD_STATE, GetMenuLabel(HK_UNDO_LOAD_STATE)); - loadMenu->AppendSeparator(); + loadMenu->Append(IDM_LOAD_STATE_FILE, GetMenuLabel(HK_LOAD_STATE_FILE)); + loadMenu->Append(IDM_LOAD_SELECTED_SLOT, GetMenuLabel(HK_LOAD_STATE_SLOT_SELECTED)); + loadMenu->Append(IDM_UNDO_LOAD_STATE, GetMenuLabel(HK_UNDO_LOAD_STATE)); + loadMenu->AppendSeparator(); - for (unsigned int i = 0; i < State::NUM_STATES; i++) - { - loadMenu->Append(IDM_LOAD_SLOT_1 + i, GetMenuLabel(HK_LOAD_STATE_SLOT_1 + i)); - saveMenu->Append(IDM_SAVE_SLOT_1 + i, GetMenuLabel(HK_SAVE_STATE_SLOT_1 + i)); - slotSelectMenu->Append(IDM_SELECT_SLOT_1 + i, GetMenuLabel(HK_SELECT_STATE_SLOT_1 + i)); - } + for (unsigned int i = 0; i < State::NUM_STATES; i++) + { + loadMenu->Append(IDM_LOAD_SLOT_1 + i, GetMenuLabel(HK_LOAD_STATE_SLOT_1 + i)); + saveMenu->Append(IDM_SAVE_SLOT_1 + i, GetMenuLabel(HK_SAVE_STATE_SLOT_1 + i)); + slotSelectMenu->Append(IDM_SELECT_SLOT_1 + i, GetMenuLabel(HK_SELECT_STATE_SLOT_1 + i)); + } - loadMenu->AppendSeparator(); - for (unsigned int i = 0; i < State::NUM_STATES; i++) - loadMenu->Append(IDM_LOAD_LAST_1 + i, GetMenuLabel(HK_LOAD_LAST_STATE_1 + i)); + loadMenu->AppendSeparator(); + for (unsigned int i = 0; i < State::NUM_STATES; i++) + loadMenu->Append(IDM_LOAD_LAST_1 + i, GetMenuLabel(HK_LOAD_LAST_STATE_1 + i)); - menubar->Append(emulationMenu, _("&Emulation")); + menubar->Append(emulationMenu, _("&Emulation")); - // Movie menu - wxMenu* movieMenu = new wxMenu; - movieMenu->Append(IDM_RECORD, GetMenuLabel(HK_START_RECORDING)); - movieMenu->Append(IDM_PLAY_RECORD, GetMenuLabel(HK_PLAY_RECORDING)); - movieMenu->Append(IDM_RECORD_EXPORT, GetMenuLabel(HK_EXPORT_RECORDING)); - movieMenu->Append(IDM_RECORD_READ_ONLY, GetMenuLabel(HK_READ_ONLY_MODE), wxEmptyString, wxITEM_CHECK); - movieMenu->Append(IDM_TAS_INPUT, _("TAS Input")); - movieMenu->AppendSeparator(); - movieMenu->AppendCheckItem(IDM_TOGGLE_PAUSE_MOVIE, _("Pause at End of Movie")); - movieMenu->Check(IDM_TOGGLE_PAUSE_MOVIE, SConfig::GetInstance().m_PauseMovie); - movieMenu->AppendCheckItem(IDM_SHOW_LAG, _("Show Lag Counter")); - movieMenu->Check(IDM_SHOW_LAG, SConfig::GetInstance().m_ShowLag); - movieMenu->AppendCheckItem(IDM_SHOW_FRAME_COUNT, _("Show Frame Counter")); - movieMenu->Check(IDM_SHOW_FRAME_COUNT, SConfig::GetInstance().m_ShowFrameCount); - movieMenu->Check(IDM_RECORD_READ_ONLY, true); - movieMenu->AppendCheckItem(IDM_SHOW_INPUT_DISPLAY, _("Show Input Display")); - movieMenu->Check(IDM_SHOW_INPUT_DISPLAY, SConfig::GetInstance().m_ShowInputDisplay); - movieMenu->AppendSeparator(); - movieMenu->AppendCheckItem(IDM_TOGGLE_DUMP_FRAMES, _("Dump Frames")); - movieMenu->Check(IDM_TOGGLE_DUMP_FRAMES, SConfig::GetInstance().m_DumpFrames); - movieMenu->AppendCheckItem(IDM_TOGGLE_DUMP_AUDIO, _("Dump Audio")); - movieMenu->Check(IDM_TOGGLE_DUMP_AUDIO, SConfig::GetInstance().m_DumpAudio); - menubar->Append(movieMenu, _("&Movie")); + // Movie menu + wxMenu* movieMenu = new wxMenu; + movieMenu->Append(IDM_RECORD, GetMenuLabel(HK_START_RECORDING)); + movieMenu->Append(IDM_PLAY_RECORD, GetMenuLabel(HK_PLAY_RECORDING)); + movieMenu->Append(IDM_RECORD_EXPORT, GetMenuLabel(HK_EXPORT_RECORDING)); + movieMenu->Append(IDM_RECORD_READ_ONLY, GetMenuLabel(HK_READ_ONLY_MODE), wxEmptyString, + wxITEM_CHECK); + movieMenu->Append(IDM_TAS_INPUT, _("TAS Input")); + movieMenu->AppendSeparator(); + movieMenu->AppendCheckItem(IDM_TOGGLE_PAUSE_MOVIE, _("Pause at End of Movie")); + movieMenu->Check(IDM_TOGGLE_PAUSE_MOVIE, SConfig::GetInstance().m_PauseMovie); + movieMenu->AppendCheckItem(IDM_SHOW_LAG, _("Show Lag Counter")); + movieMenu->Check(IDM_SHOW_LAG, SConfig::GetInstance().m_ShowLag); + movieMenu->AppendCheckItem(IDM_SHOW_FRAME_COUNT, _("Show Frame Counter")); + movieMenu->Check(IDM_SHOW_FRAME_COUNT, SConfig::GetInstance().m_ShowFrameCount); + movieMenu->Check(IDM_RECORD_READ_ONLY, true); + movieMenu->AppendCheckItem(IDM_SHOW_INPUT_DISPLAY, _("Show Input Display")); + movieMenu->Check(IDM_SHOW_INPUT_DISPLAY, SConfig::GetInstance().m_ShowInputDisplay); + movieMenu->AppendSeparator(); + movieMenu->AppendCheckItem(IDM_TOGGLE_DUMP_FRAMES, _("Dump Frames")); + movieMenu->Check(IDM_TOGGLE_DUMP_FRAMES, SConfig::GetInstance().m_DumpFrames); + movieMenu->AppendCheckItem(IDM_TOGGLE_DUMP_AUDIO, _("Dump Audio")); + movieMenu->Check(IDM_TOGGLE_DUMP_AUDIO, SConfig::GetInstance().m_DumpAudio); + menubar->Append(movieMenu, _("&Movie")); - // Options menu - wxMenu* pOptionsMenu = new wxMenu; - pOptionsMenu->Append(wxID_PREFERENCES, _("Co&nfigure...")); - pOptionsMenu->AppendSeparator(); - pOptionsMenu->Append(IDM_CONFIG_GFX_BACKEND, _("&Graphics Settings")); - pOptionsMenu->Append(IDM_CONFIG_AUDIO, _("&Audio Settings")); - pOptionsMenu->Append(IDM_CONFIG_CONTROLLERS, _("&Controller Settings")); - pOptionsMenu->Append(IDM_CONFIG_HOTKEYS, _("&Hotkey Settings")); - if (g_pCodeWindow) - { - pOptionsMenu->AppendSeparator(); - g_pCodeWindow->CreateMenuOptions(pOptionsMenu); - } - menubar->Append(pOptionsMenu, _("&Options")); + // Options menu + wxMenu* pOptionsMenu = new wxMenu; + pOptionsMenu->Append(wxID_PREFERENCES, _("Co&nfigure...")); + pOptionsMenu->AppendSeparator(); + pOptionsMenu->Append(IDM_CONFIG_GFX_BACKEND, _("&Graphics Settings")); + pOptionsMenu->Append(IDM_CONFIG_AUDIO, _("&Audio Settings")); + pOptionsMenu->Append(IDM_CONFIG_CONTROLLERS, _("&Controller Settings")); + pOptionsMenu->Append(IDM_CONFIG_HOTKEYS, _("&Hotkey Settings")); + if (g_pCodeWindow) + { + pOptionsMenu->AppendSeparator(); + g_pCodeWindow->CreateMenuOptions(pOptionsMenu); + } + menubar->Append(pOptionsMenu, _("&Options")); - // Tools menu - wxMenu* toolsMenu = new wxMenu; - toolsMenu->Append(IDM_MEMCARD, _("&Memcard Manager (GC)")); - toolsMenu->Append(IDM_IMPORT_SAVE, _("Import Wii Save")); - toolsMenu->Append(IDM_EXPORT_ALL_SAVE, _("Export All Wii Saves")); - toolsMenu->Append(IDM_CHEATS, _("&Cheat Manager")); + // Tools menu + wxMenu* toolsMenu = new wxMenu; + toolsMenu->Append(IDM_MEMCARD, _("&Memcard Manager (GC)")); + toolsMenu->Append(IDM_IMPORT_SAVE, _("Import Wii Save")); + toolsMenu->Append(IDM_EXPORT_ALL_SAVE, _("Export All Wii Saves")); + toolsMenu->Append(IDM_CHEATS, _("&Cheat Manager")); - toolsMenu->Append(IDM_NETPLAY, _("Start &NetPlay")); + toolsMenu->Append(IDM_NETPLAY, _("Start &NetPlay")); - toolsMenu->Append(IDM_MENU_INSTALL_WAD, _("Install WAD")); - UpdateWiiMenuChoice(toolsMenu->Append(IDM_LOAD_WII_MENU, "Dummy string to keep wxw happy")); + toolsMenu->Append(IDM_MENU_INSTALL_WAD, _("Install WAD")); + UpdateWiiMenuChoice(toolsMenu->Append(IDM_LOAD_WII_MENU, "Dummy string to keep wxw happy")); - toolsMenu->Append(IDM_FIFOPLAYER, _("FIFO Player")); + toolsMenu->Append(IDM_FIFOPLAYER, _("FIFO Player")); - toolsMenu->AppendSeparator(); - wxMenu* wiimoteMenu = new wxMenu; - toolsMenu->AppendSubMenu(wiimoteMenu, _("Connect Wiimotes")); - wiimoteMenu->AppendCheckItem(IDM_CONNECT_WIIMOTE1, GetMenuLabel(HK_WIIMOTE1_CONNECT)); - wiimoteMenu->AppendCheckItem(IDM_CONNECT_WIIMOTE2, GetMenuLabel(HK_WIIMOTE2_CONNECT)); - wiimoteMenu->AppendCheckItem(IDM_CONNECT_WIIMOTE3, GetMenuLabel(HK_WIIMOTE3_CONNECT)); - wiimoteMenu->AppendCheckItem(IDM_CONNECT_WIIMOTE4, GetMenuLabel(HK_WIIMOTE4_CONNECT)); - wiimoteMenu->AppendSeparator(); - wiimoteMenu->AppendCheckItem(IDM_CONNECT_BALANCEBOARD, GetMenuLabel(HK_BALANCEBOARD_CONNECT)); + toolsMenu->AppendSeparator(); + wxMenu* wiimoteMenu = new wxMenu; + toolsMenu->AppendSubMenu(wiimoteMenu, _("Connect Wiimotes")); + wiimoteMenu->AppendCheckItem(IDM_CONNECT_WIIMOTE1, GetMenuLabel(HK_WIIMOTE1_CONNECT)); + wiimoteMenu->AppendCheckItem(IDM_CONNECT_WIIMOTE2, GetMenuLabel(HK_WIIMOTE2_CONNECT)); + wiimoteMenu->AppendCheckItem(IDM_CONNECT_WIIMOTE3, GetMenuLabel(HK_WIIMOTE3_CONNECT)); + wiimoteMenu->AppendCheckItem(IDM_CONNECT_WIIMOTE4, GetMenuLabel(HK_WIIMOTE4_CONNECT)); + wiimoteMenu->AppendSeparator(); + wiimoteMenu->AppendCheckItem(IDM_CONNECT_BALANCEBOARD, GetMenuLabel(HK_BALANCEBOARD_CONNECT)); - menubar->Append(toolsMenu, _("&Tools")); + menubar->Append(toolsMenu, _("&Tools")); - wxMenu* viewMenu = new wxMenu; - viewMenu->AppendCheckItem(IDM_TOGGLE_TOOLBAR, _("Show &Toolbar")); - viewMenu->Check(IDM_TOGGLE_TOOLBAR, SConfig::GetInstance().m_InterfaceToolbar); - viewMenu->AppendCheckItem(IDM_TOGGLE_STATUSBAR, _("Show &Status Bar")); - viewMenu->Check(IDM_TOGGLE_STATUSBAR, SConfig::GetInstance().m_InterfaceStatusbar); - viewMenu->AppendSeparator(); - viewMenu->AppendCheckItem(IDM_LOG_WINDOW, _("Show &Log")); - viewMenu->AppendCheckItem(IDM_LOG_CONFIG_WINDOW, _("Show Log &Configuration")); - viewMenu->AppendSeparator(); + wxMenu* viewMenu = new wxMenu; + viewMenu->AppendCheckItem(IDM_TOGGLE_TOOLBAR, _("Show &Toolbar")); + viewMenu->Check(IDM_TOGGLE_TOOLBAR, SConfig::GetInstance().m_InterfaceToolbar); + viewMenu->AppendCheckItem(IDM_TOGGLE_STATUSBAR, _("Show &Status Bar")); + viewMenu->Check(IDM_TOGGLE_STATUSBAR, SConfig::GetInstance().m_InterfaceStatusbar); + viewMenu->AppendSeparator(); + viewMenu->AppendCheckItem(IDM_LOG_WINDOW, _("Show &Log")); + viewMenu->AppendCheckItem(IDM_LOG_CONFIG_WINDOW, _("Show Log &Configuration")); + viewMenu->AppendSeparator(); - if (g_pCodeWindow) - { - viewMenu->Check(IDM_LOG_WINDOW, g_pCodeWindow->bShowOnStart[0]); + if (g_pCodeWindow) + { + viewMenu->Check(IDM_LOG_WINDOW, g_pCodeWindow->bShowOnStart[0]); - static const wxString menu_text[] = { - _("&Registers"), - _("&Watch"), - _("&Breakpoints"), - _("&Memory"), - _("&JIT"), - _("&Sound"), - _("&Video") - }; + static const wxString menu_text[] = {_("&Registers"), _("&Watch"), _("&Breakpoints"), + _("&Memory"), _("&JIT"), _("&Sound"), + _("&Video")}; - for (int i = IDM_REGISTER_WINDOW; i <= IDM_VIDEO_WINDOW; i++) - { - viewMenu->AppendCheckItem(i, menu_text[i - IDM_REGISTER_WINDOW]); - viewMenu->Check(i, g_pCodeWindow->bShowOnStart[i - IDM_LOG_WINDOW]); - } + for (int i = IDM_REGISTER_WINDOW; i <= IDM_VIDEO_WINDOW; i++) + { + viewMenu->AppendCheckItem(i, menu_text[i - IDM_REGISTER_WINDOW]); + viewMenu->Check(i, g_pCodeWindow->bShowOnStart[i - IDM_LOG_WINDOW]); + } - viewMenu->AppendSeparator(); - } - else - { - viewMenu->Check(IDM_LOG_WINDOW, SConfig::GetInstance().m_InterfaceLogWindow); - viewMenu->Check(IDM_LOG_CONFIG_WINDOW, SConfig::GetInstance().m_InterfaceLogConfigWindow); - } + viewMenu->AppendSeparator(); + } + else + { + viewMenu->Check(IDM_LOG_WINDOW, SConfig::GetInstance().m_InterfaceLogWindow); + viewMenu->Check(IDM_LOG_CONFIG_WINDOW, SConfig::GetInstance().m_InterfaceLogConfigWindow); + } - wxMenu *platformMenu = new wxMenu; - viewMenu->AppendSubMenu(platformMenu, _("Show Platforms")); - platformMenu->AppendCheckItem(IDM_LIST_WII, _("Show Wii")); - platformMenu->Check(IDM_LIST_WII, SConfig::GetInstance().m_ListWii); - platformMenu->AppendCheckItem(IDM_LIST_GC, _("Show GameCube")); - platformMenu->Check(IDM_LIST_GC, SConfig::GetInstance().m_ListGC); - platformMenu->AppendCheckItem(IDM_LIST_WAD, _("Show WAD")); - platformMenu->Check(IDM_LIST_WAD, SConfig::GetInstance().m_ListWad); - platformMenu->AppendCheckItem(IDM_LIST_ELFDOL, _("Show ELF/DOL")); - platformMenu->Check(IDM_LIST_ELFDOL, SConfig::GetInstance().m_ListElfDol); + wxMenu* platformMenu = new wxMenu; + viewMenu->AppendSubMenu(platformMenu, _("Show Platforms")); + platformMenu->AppendCheckItem(IDM_LIST_WII, _("Show Wii")); + platformMenu->Check(IDM_LIST_WII, SConfig::GetInstance().m_ListWii); + platformMenu->AppendCheckItem(IDM_LIST_GC, _("Show GameCube")); + platformMenu->Check(IDM_LIST_GC, SConfig::GetInstance().m_ListGC); + platformMenu->AppendCheckItem(IDM_LIST_WAD, _("Show WAD")); + platformMenu->Check(IDM_LIST_WAD, SConfig::GetInstance().m_ListWad); + platformMenu->AppendCheckItem(IDM_LIST_ELFDOL, _("Show ELF/DOL")); + platformMenu->Check(IDM_LIST_ELFDOL, SConfig::GetInstance().m_ListElfDol); - wxMenu *regionMenu = new wxMenu; - viewMenu->AppendSubMenu(regionMenu, _("Show Regions")); - regionMenu->AppendCheckItem(IDM_LIST_JAP, _("Show JAP")); - regionMenu->Check(IDM_LIST_JAP, SConfig::GetInstance().m_ListJap); - regionMenu->AppendCheckItem(IDM_LIST_PAL, _("Show PAL")); - regionMenu->Check(IDM_LIST_PAL, SConfig::GetInstance().m_ListPal); - regionMenu->AppendCheckItem(IDM_LIST_USA, _("Show USA")); - regionMenu->Check(IDM_LIST_USA, SConfig::GetInstance().m_ListUsa); - regionMenu->AppendSeparator(); - regionMenu->AppendCheckItem(IDM_LIST_AUSTRALIA, _("Show Australia")); - regionMenu->Check(IDM_LIST_AUSTRALIA, SConfig::GetInstance().m_ListAustralia); - regionMenu->AppendCheckItem(IDM_LIST_FRANCE, _("Show France")); - regionMenu->Check(IDM_LIST_FRANCE, SConfig::GetInstance().m_ListFrance); - regionMenu->AppendCheckItem(IDM_LIST_GERMANY, _("Show Germany")); - regionMenu->Check(IDM_LIST_GERMANY, SConfig::GetInstance().m_ListGermany); - regionMenu->AppendCheckItem(IDM_LIST_ITALY, _("Show Italy")); - regionMenu->Check(IDM_LIST_ITALY, SConfig::GetInstance().m_ListItaly); - regionMenu->AppendCheckItem(IDM_LIST_KOREA, _("Show Korea")); - regionMenu->Check(IDM_LIST_KOREA, SConfig::GetInstance().m_ListKorea); - regionMenu->AppendCheckItem(IDM_LIST_NETHERLANDS, _("Show Netherlands")); - regionMenu->Check(IDM_LIST_NETHERLANDS, SConfig::GetInstance().m_ListNetherlands); - regionMenu->AppendCheckItem(IDM_LIST_RUSSIA, _("Show Russia")); - regionMenu->Check(IDM_LIST_RUSSIA, SConfig::GetInstance().m_ListRussia); - regionMenu->AppendCheckItem(IDM_LIST_SPAIN, _("Show Spain")); - regionMenu->Check(IDM_LIST_SPAIN, SConfig::GetInstance().m_ListSpain); - regionMenu->AppendCheckItem(IDM_LIST_TAIWAN, _("Show Taiwan")); - regionMenu->Check(IDM_LIST_TAIWAN, SConfig::GetInstance().m_ListTaiwan); - regionMenu->AppendCheckItem(IDM_LIST_WORLD, _("Show World")); - regionMenu->Check(IDM_LIST_WORLD, SConfig::GetInstance().m_ListWorld); - regionMenu->AppendCheckItem(IDM_LIST_UNKNOWN, _("Show Unknown")); - regionMenu->Check(IDM_LIST_UNKNOWN, SConfig::GetInstance().m_ListUnknown); + wxMenu* regionMenu = new wxMenu; + viewMenu->AppendSubMenu(regionMenu, _("Show Regions")); + regionMenu->AppendCheckItem(IDM_LIST_JAP, _("Show JAP")); + regionMenu->Check(IDM_LIST_JAP, SConfig::GetInstance().m_ListJap); + regionMenu->AppendCheckItem(IDM_LIST_PAL, _("Show PAL")); + regionMenu->Check(IDM_LIST_PAL, SConfig::GetInstance().m_ListPal); + regionMenu->AppendCheckItem(IDM_LIST_USA, _("Show USA")); + regionMenu->Check(IDM_LIST_USA, SConfig::GetInstance().m_ListUsa); + regionMenu->AppendSeparator(); + regionMenu->AppendCheckItem(IDM_LIST_AUSTRALIA, _("Show Australia")); + regionMenu->Check(IDM_LIST_AUSTRALIA, SConfig::GetInstance().m_ListAustralia); + regionMenu->AppendCheckItem(IDM_LIST_FRANCE, _("Show France")); + regionMenu->Check(IDM_LIST_FRANCE, SConfig::GetInstance().m_ListFrance); + regionMenu->AppendCheckItem(IDM_LIST_GERMANY, _("Show Germany")); + regionMenu->Check(IDM_LIST_GERMANY, SConfig::GetInstance().m_ListGermany); + regionMenu->AppendCheckItem(IDM_LIST_ITALY, _("Show Italy")); + regionMenu->Check(IDM_LIST_ITALY, SConfig::GetInstance().m_ListItaly); + regionMenu->AppendCheckItem(IDM_LIST_KOREA, _("Show Korea")); + regionMenu->Check(IDM_LIST_KOREA, SConfig::GetInstance().m_ListKorea); + regionMenu->AppendCheckItem(IDM_LIST_NETHERLANDS, _("Show Netherlands")); + regionMenu->Check(IDM_LIST_NETHERLANDS, SConfig::GetInstance().m_ListNetherlands); + regionMenu->AppendCheckItem(IDM_LIST_RUSSIA, _("Show Russia")); + regionMenu->Check(IDM_LIST_RUSSIA, SConfig::GetInstance().m_ListRussia); + regionMenu->AppendCheckItem(IDM_LIST_SPAIN, _("Show Spain")); + regionMenu->Check(IDM_LIST_SPAIN, SConfig::GetInstance().m_ListSpain); + regionMenu->AppendCheckItem(IDM_LIST_TAIWAN, _("Show Taiwan")); + regionMenu->Check(IDM_LIST_TAIWAN, SConfig::GetInstance().m_ListTaiwan); + regionMenu->AppendCheckItem(IDM_LIST_WORLD, _("Show World")); + regionMenu->Check(IDM_LIST_WORLD, SConfig::GetInstance().m_ListWorld); + regionMenu->AppendCheckItem(IDM_LIST_UNKNOWN, _("Show Unknown")); + regionMenu->Check(IDM_LIST_UNKNOWN, SConfig::GetInstance().m_ListUnknown); - viewMenu->AppendCheckItem(IDM_LIST_DRIVES, _("Show Drives")); - viewMenu->Check(IDM_LIST_DRIVES, SConfig::GetInstance().m_ListDrives); - viewMenu->Append(IDM_PURGE_GAME_LIST_CACHE, _("Purge Game List Cache")); + viewMenu->AppendCheckItem(IDM_LIST_DRIVES, _("Show Drives")); + viewMenu->Check(IDM_LIST_DRIVES, SConfig::GetInstance().m_ListDrives); + viewMenu->Append(IDM_PURGE_GAME_LIST_CACHE, _("Purge Game List Cache")); - wxMenu *columnsMenu = new wxMenu; - viewMenu->AppendSubMenu(columnsMenu, _("Select Columns")); - columnsMenu->AppendCheckItem(IDM_SHOW_SYSTEM, _("Platform")); - columnsMenu->Check(IDM_SHOW_SYSTEM, SConfig::GetInstance().m_showSystemColumn); - columnsMenu->AppendCheckItem(IDM_SHOW_BANNER, _("Banner")); - columnsMenu->Check(IDM_SHOW_BANNER, SConfig::GetInstance().m_showBannerColumn); - columnsMenu->AppendCheckItem(IDM_SHOW_MAKER, _("Maker")); - columnsMenu->Check(IDM_SHOW_MAKER, SConfig::GetInstance().m_showMakerColumn); - columnsMenu->AppendCheckItem(IDM_SHOW_FILENAME, _("File Name")); - columnsMenu->Check(IDM_SHOW_FILENAME, SConfig::GetInstance().m_showFileNameColumn); - columnsMenu->AppendCheckItem(IDM_SHOW_ID, _("Game ID")); - columnsMenu->Check(IDM_SHOW_ID, SConfig::GetInstance().m_showIDColumn); - columnsMenu->AppendCheckItem(IDM_SHOW_REGION, _("Region")); - columnsMenu->Check(IDM_SHOW_REGION, SConfig::GetInstance().m_showRegionColumn); - columnsMenu->AppendCheckItem(IDM_SHOW_SIZE, _("File Size")); - columnsMenu->Check(IDM_SHOW_SIZE, SConfig::GetInstance().m_showSizeColumn); - columnsMenu->AppendCheckItem(IDM_SHOW_STATE, _("State")); - columnsMenu->Check(IDM_SHOW_STATE, SConfig::GetInstance().m_showStateColumn); + wxMenu* columnsMenu = new wxMenu; + viewMenu->AppendSubMenu(columnsMenu, _("Select Columns")); + columnsMenu->AppendCheckItem(IDM_SHOW_SYSTEM, _("Platform")); + columnsMenu->Check(IDM_SHOW_SYSTEM, SConfig::GetInstance().m_showSystemColumn); + columnsMenu->AppendCheckItem(IDM_SHOW_BANNER, _("Banner")); + columnsMenu->Check(IDM_SHOW_BANNER, SConfig::GetInstance().m_showBannerColumn); + columnsMenu->AppendCheckItem(IDM_SHOW_MAKER, _("Maker")); + columnsMenu->Check(IDM_SHOW_MAKER, SConfig::GetInstance().m_showMakerColumn); + columnsMenu->AppendCheckItem(IDM_SHOW_FILENAME, _("File Name")); + columnsMenu->Check(IDM_SHOW_FILENAME, SConfig::GetInstance().m_showFileNameColumn); + columnsMenu->AppendCheckItem(IDM_SHOW_ID, _("Game ID")); + columnsMenu->Check(IDM_SHOW_ID, SConfig::GetInstance().m_showIDColumn); + columnsMenu->AppendCheckItem(IDM_SHOW_REGION, _("Region")); + columnsMenu->Check(IDM_SHOW_REGION, SConfig::GetInstance().m_showRegionColumn); + columnsMenu->AppendCheckItem(IDM_SHOW_SIZE, _("File Size")); + columnsMenu->Check(IDM_SHOW_SIZE, SConfig::GetInstance().m_showSizeColumn); + columnsMenu->AppendCheckItem(IDM_SHOW_STATE, _("State")); + columnsMenu->Check(IDM_SHOW_STATE, SConfig::GetInstance().m_showStateColumn); + menubar->Append(viewMenu, _("&View")); + if (g_pCodeWindow) + { + g_pCodeWindow->CreateMenu(SConfig::GetInstance(), menubar); + } - menubar->Append(viewMenu, _("&View")); + // Help menu + wxMenu* helpMenu = new wxMenu; + // Re-enable when there's something useful to display */ + // helpMenu->Append(wxID_HELP, _("&Help")); + helpMenu->Append(IDM_HELP_WEBSITE, _("&Website")); + helpMenu->Append(IDM_HELP_ONLINE_DOCS, _("Online &Documentation")); + helpMenu->Append(IDM_HELP_GITHUB, _("&GitHub Repository")); + helpMenu->AppendSeparator(); + helpMenu->Append(wxID_ABOUT, _("&About...")); + menubar->Append(helpMenu, _("&Help")); - if (g_pCodeWindow) - { - g_pCodeWindow->CreateMenu(SConfig::GetInstance(), menubar); - } - - // Help menu - wxMenu* helpMenu = new wxMenu; - // Re-enable when there's something useful to display */ - // helpMenu->Append(wxID_HELP, _("&Help")); - helpMenu->Append(IDM_HELP_WEBSITE, _("&Website")); - helpMenu->Append(IDM_HELP_ONLINE_DOCS, _("Online &Documentation")); - helpMenu->Append(IDM_HELP_GITHUB, _("&GitHub Repository")); - helpMenu->AppendSeparator(); - helpMenu->Append(wxID_ABOUT, _("&About...")); - menubar->Append(helpMenu, _("&Help")); - - return menubar; + return menubar; } wxString CFrame::GetMenuLabel(int Id) { - wxString Label; + wxString Label; - switch (Id) - { - case HK_OPEN: - Label = _("&Open..."); - break; - case HK_CHANGE_DISC: - Label = _("Change &Disc..."); - break; - case HK_REFRESH_LIST: - Label = _("&Refresh List"); - break; + switch (Id) + { + case HK_OPEN: + Label = _("&Open..."); + break; + case HK_CHANGE_DISC: + Label = _("Change &Disc..."); + break; + case HK_REFRESH_LIST: + Label = _("&Refresh List"); + break; - case HK_PLAY_PAUSE: - if (Core::GetState() == Core::CORE_RUN) - Label = _("&Pause"); - else - Label = _("&Play"); - break; - case HK_STOP: - Label = _("&Stop"); - break; - case HK_RESET: - Label = _("&Reset"); - break; - case HK_FRAME_ADVANCE: - Label = _("&Frame Advance"); - break; + case HK_PLAY_PAUSE: + if (Core::GetState() == Core::CORE_RUN) + Label = _("&Pause"); + else + Label = _("&Play"); + break; + case HK_STOP: + Label = _("&Stop"); + break; + case HK_RESET: + Label = _("&Reset"); + break; + case HK_FRAME_ADVANCE: + Label = _("&Frame Advance"); + break; - case HK_START_RECORDING: - Label = _("Start Re&cording Input"); - break; - case HK_PLAY_RECORDING: - Label = _("P&lay Input Recording..."); - break; - case HK_EXPORT_RECORDING: - Label = _("Export Recording..."); - break; - case HK_READ_ONLY_MODE: - Label = _("&Read-Only Mode"); - break; + case HK_START_RECORDING: + Label = _("Start Re&cording Input"); + break; + case HK_PLAY_RECORDING: + Label = _("P&lay Input Recording..."); + break; + case HK_EXPORT_RECORDING: + Label = _("Export Recording..."); + break; + case HK_READ_ONLY_MODE: + Label = _("&Read-Only Mode"); + break; - case HK_FULLSCREEN: - Label = _("&Fullscreen"); - break; - case HK_SCREENSHOT: - Label = _("Take Screenshot"); - break; - case HK_EXIT: - Label = _("Exit"); - break; + case HK_FULLSCREEN: + Label = _("&Fullscreen"); + break; + case HK_SCREENSHOT: + Label = _("Take Screenshot"); + break; + case HK_EXIT: + Label = _("Exit"); + break; - case HK_WIIMOTE1_CONNECT: - case HK_WIIMOTE2_CONNECT: - case HK_WIIMOTE3_CONNECT: - case HK_WIIMOTE4_CONNECT: - Label = wxString::Format(_("Connect Wiimote %i"), - Id - HK_WIIMOTE1_CONNECT + 1); - break; - case HK_BALANCEBOARD_CONNECT: - Label = _("Connect Balance Board"); - break; - case HK_LOAD_STATE_SLOT_1: - case HK_LOAD_STATE_SLOT_2: - case HK_LOAD_STATE_SLOT_3: - case HK_LOAD_STATE_SLOT_4: - case HK_LOAD_STATE_SLOT_5: - case HK_LOAD_STATE_SLOT_6: - case HK_LOAD_STATE_SLOT_7: - case HK_LOAD_STATE_SLOT_8: - case HK_LOAD_STATE_SLOT_9: - case HK_LOAD_STATE_SLOT_10: - Label = wxString::Format(_("Slot %i - %s"), - Id - HK_LOAD_STATE_SLOT_1 + 1, - StrToWxStr(State::GetInfoStringOfSlot(Id - HK_LOAD_STATE_SLOT_1 + 1))); - break; + case HK_WIIMOTE1_CONNECT: + case HK_WIIMOTE2_CONNECT: + case HK_WIIMOTE3_CONNECT: + case HK_WIIMOTE4_CONNECT: + Label = wxString::Format(_("Connect Wiimote %i"), Id - HK_WIIMOTE1_CONNECT + 1); + break; + case HK_BALANCEBOARD_CONNECT: + Label = _("Connect Balance Board"); + break; + case HK_LOAD_STATE_SLOT_1: + case HK_LOAD_STATE_SLOT_2: + case HK_LOAD_STATE_SLOT_3: + case HK_LOAD_STATE_SLOT_4: + case HK_LOAD_STATE_SLOT_5: + case HK_LOAD_STATE_SLOT_6: + case HK_LOAD_STATE_SLOT_7: + case HK_LOAD_STATE_SLOT_8: + case HK_LOAD_STATE_SLOT_9: + case HK_LOAD_STATE_SLOT_10: + Label = wxString::Format(_("Slot %i - %s"), Id - HK_LOAD_STATE_SLOT_1 + 1, + StrToWxStr(State::GetInfoStringOfSlot(Id - HK_LOAD_STATE_SLOT_1 + 1))); + break; - case HK_SAVE_STATE_SLOT_1: - case HK_SAVE_STATE_SLOT_2: - case HK_SAVE_STATE_SLOT_3: - case HK_SAVE_STATE_SLOT_4: - case HK_SAVE_STATE_SLOT_5: - case HK_SAVE_STATE_SLOT_6: - case HK_SAVE_STATE_SLOT_7: - case HK_SAVE_STATE_SLOT_8: - case HK_SAVE_STATE_SLOT_9: - case HK_SAVE_STATE_SLOT_10: - Label = wxString::Format(_("Slot %i - %s"), - Id - HK_SAVE_STATE_SLOT_1 + 1, - StrToWxStr(State::GetInfoStringOfSlot(Id - HK_SAVE_STATE_SLOT_1 + 1))); - break; - case HK_SAVE_STATE_FILE: - Label = _("Save State..."); - break; + case HK_SAVE_STATE_SLOT_1: + case HK_SAVE_STATE_SLOT_2: + case HK_SAVE_STATE_SLOT_3: + case HK_SAVE_STATE_SLOT_4: + case HK_SAVE_STATE_SLOT_5: + case HK_SAVE_STATE_SLOT_6: + case HK_SAVE_STATE_SLOT_7: + case HK_SAVE_STATE_SLOT_8: + case HK_SAVE_STATE_SLOT_9: + case HK_SAVE_STATE_SLOT_10: + Label = wxString::Format(_("Slot %i - %s"), Id - HK_SAVE_STATE_SLOT_1 + 1, + StrToWxStr(State::GetInfoStringOfSlot(Id - HK_SAVE_STATE_SLOT_1 + 1))); + break; + case HK_SAVE_STATE_FILE: + Label = _("Save State..."); + break; - case HK_LOAD_LAST_STATE_1: - case HK_LOAD_LAST_STATE_2: - case HK_LOAD_LAST_STATE_3: - case HK_LOAD_LAST_STATE_4: - case HK_LOAD_LAST_STATE_5: - case HK_LOAD_LAST_STATE_6: - case HK_LOAD_LAST_STATE_7: - case HK_LOAD_LAST_STATE_8: - case HK_LOAD_LAST_STATE_9: - case HK_LOAD_LAST_STATE_10: - Label = wxString::Format(_("Last %i"), - Id - HK_LOAD_LAST_STATE_1 + 1); - break; - case HK_LOAD_STATE_FILE: - Label = _("Load State..."); - break; + case HK_LOAD_LAST_STATE_1: + case HK_LOAD_LAST_STATE_2: + case HK_LOAD_LAST_STATE_3: + case HK_LOAD_LAST_STATE_4: + case HK_LOAD_LAST_STATE_5: + case HK_LOAD_LAST_STATE_6: + case HK_LOAD_LAST_STATE_7: + case HK_LOAD_LAST_STATE_8: + case HK_LOAD_LAST_STATE_9: + case HK_LOAD_LAST_STATE_10: + Label = wxString::Format(_("Last %i"), Id - HK_LOAD_LAST_STATE_1 + 1); + break; + case HK_LOAD_STATE_FILE: + Label = _("Load State..."); + break; - case HK_SAVE_FIRST_STATE: Label = _("Save Oldest State"); break; - case HK_UNDO_LOAD_STATE: Label = _("Undo Load State"); break; - case HK_UNDO_SAVE_STATE: Label = _("Undo Save State"); break; + case HK_SAVE_FIRST_STATE: + Label = _("Save Oldest State"); + break; + case HK_UNDO_LOAD_STATE: + Label = _("Undo Load State"); + break; + case HK_UNDO_SAVE_STATE: + Label = _("Undo Save State"); + break; - case HK_SAVE_STATE_SLOT_SELECTED: - Label = _("Save state to selected slot"); - break; + case HK_SAVE_STATE_SLOT_SELECTED: + Label = _("Save state to selected slot"); + break; - case HK_LOAD_STATE_SLOT_SELECTED: - Label = _("Load state from selected slot"); - break; + case HK_LOAD_STATE_SLOT_SELECTED: + Label = _("Load state from selected slot"); + break; - case HK_SELECT_STATE_SLOT_1: - case HK_SELECT_STATE_SLOT_2: - case HK_SELECT_STATE_SLOT_3: - case HK_SELECT_STATE_SLOT_4: - case HK_SELECT_STATE_SLOT_5: - case HK_SELECT_STATE_SLOT_6: - case HK_SELECT_STATE_SLOT_7: - case HK_SELECT_STATE_SLOT_8: - case HK_SELECT_STATE_SLOT_9: - case HK_SELECT_STATE_SLOT_10: - Label = wxString::Format(_("Select Slot %i - %s"), - Id - HK_SELECT_STATE_SLOT_1 + 1, - StrToWxStr(State::GetInfoStringOfSlot(Id - HK_SELECT_STATE_SLOT_1 + 1))); - break; + case HK_SELECT_STATE_SLOT_1: + case HK_SELECT_STATE_SLOT_2: + case HK_SELECT_STATE_SLOT_3: + case HK_SELECT_STATE_SLOT_4: + case HK_SELECT_STATE_SLOT_5: + case HK_SELECT_STATE_SLOT_6: + case HK_SELECT_STATE_SLOT_7: + case HK_SELECT_STATE_SLOT_8: + case HK_SELECT_STATE_SLOT_9: + case HK_SELECT_STATE_SLOT_10: + Label = + wxString::Format(_("Select Slot %i - %s"), Id - HK_SELECT_STATE_SLOT_1 + 1, + StrToWxStr(State::GetInfoStringOfSlot(Id - HK_SELECT_STATE_SLOT_1 + 1))); + break; + default: + Label = wxString::Format(_("Undefined %i"), Id); + } - default: - Label = wxString::Format(_("Undefined %i"), Id); - } - - return Label; + return Label; } - // Create toolbar items // --------------------- void CFrame::PopulateToolbar(wxToolBar* ToolBar) { - int w = m_Bitmaps[Toolbar_FileOpen].GetWidth(), - h = m_Bitmaps[Toolbar_FileOpen].GetHeight(); - ToolBar->SetToolBitmapSize(wxSize(w, h)); + int w = m_Bitmaps[Toolbar_FileOpen].GetWidth(), h = m_Bitmaps[Toolbar_FileOpen].GetHeight(); + ToolBar->SetToolBitmapSize(wxSize(w, h)); - - WxUtils::AddToolbarButton(ToolBar, wxID_OPEN, _("Open"), m_Bitmaps[Toolbar_FileOpen], _("Open file...")); - WxUtils::AddToolbarButton(ToolBar, wxID_REFRESH, _("Refresh"), m_Bitmaps[Toolbar_Refresh], _("Refresh game list")); - ToolBar->AddSeparator(); - WxUtils::AddToolbarButton(ToolBar, IDM_PLAY, _("Play"), m_Bitmaps[Toolbar_Play], _("Play")); - WxUtils::AddToolbarButton(ToolBar, IDM_STOP, _("Stop"), m_Bitmaps[Toolbar_Stop], _("Stop")); - WxUtils::AddToolbarButton(ToolBar, IDM_TOGGLE_FULLSCREEN, _("FullScr"), m_Bitmaps[Toolbar_FullScreen], _("Toggle fullscreen")); - WxUtils::AddToolbarButton(ToolBar, IDM_SCREENSHOT, _("ScrShot"), m_Bitmaps[Toolbar_Screenshot], _("Take screenshot")); - ToolBar->AddSeparator(); - WxUtils::AddToolbarButton(ToolBar, wxID_PREFERENCES, _("Config"), m_Bitmaps[Toolbar_ConfigMain], _("Configure...")); - WxUtils::AddToolbarButton(ToolBar, IDM_CONFIG_GFX_BACKEND, _("Graphics"), m_Bitmaps[Toolbar_ConfigGFX], _("Graphics settings")); - WxUtils::AddToolbarButton(ToolBar, IDM_CONFIG_CONTROLLERS, _("Controllers"), m_Bitmaps[Toolbar_Controller], _("Controller settings")); + WxUtils::AddToolbarButton(ToolBar, wxID_OPEN, _("Open"), m_Bitmaps[Toolbar_FileOpen], + _("Open file...")); + WxUtils::AddToolbarButton(ToolBar, wxID_REFRESH, _("Refresh"), m_Bitmaps[Toolbar_Refresh], + _("Refresh game list")); + ToolBar->AddSeparator(); + WxUtils::AddToolbarButton(ToolBar, IDM_PLAY, _("Play"), m_Bitmaps[Toolbar_Play], _("Play")); + WxUtils::AddToolbarButton(ToolBar, IDM_STOP, _("Stop"), m_Bitmaps[Toolbar_Stop], _("Stop")); + WxUtils::AddToolbarButton(ToolBar, IDM_TOGGLE_FULLSCREEN, _("FullScr"), + m_Bitmaps[Toolbar_FullScreen], _("Toggle fullscreen")); + WxUtils::AddToolbarButton(ToolBar, IDM_SCREENSHOT, _("ScrShot"), m_Bitmaps[Toolbar_Screenshot], + _("Take screenshot")); + ToolBar->AddSeparator(); + WxUtils::AddToolbarButton(ToolBar, wxID_PREFERENCES, _("Config"), m_Bitmaps[Toolbar_ConfigMain], + _("Configure...")); + WxUtils::AddToolbarButton(ToolBar, IDM_CONFIG_GFX_BACKEND, _("Graphics"), + m_Bitmaps[Toolbar_ConfigGFX], _("Graphics settings")); + WxUtils::AddToolbarButton(ToolBar, IDM_CONFIG_CONTROLLERS, _("Controllers"), + m_Bitmaps[Toolbar_Controller], _("Controller settings")); } - // Delete and recreate the toolbar void CFrame::RecreateToolbar() { - static const long TOOLBAR_STYLE = wxTB_DEFAULT_STYLE | wxTB_TEXT; + static const long TOOLBAR_STYLE = wxTB_DEFAULT_STYLE | wxTB_TEXT; - if (m_ToolBar != nullptr) - { - m_ToolBar->Destroy(); - m_ToolBar = nullptr; - } + if (m_ToolBar != nullptr) + { + m_ToolBar->Destroy(); + m_ToolBar = nullptr; + } - m_ToolBar = CreateToolBar(TOOLBAR_STYLE, wxID_ANY); + m_ToolBar = CreateToolBar(TOOLBAR_STYLE, wxID_ANY); - if (g_pCodeWindow) - { - g_pCodeWindow->PopulateToolbar(m_ToolBar); - m_ToolBar->AddSeparator(); - } + if (g_pCodeWindow) + { + g_pCodeWindow->PopulateToolbar(m_ToolBar); + m_ToolBar->AddSeparator(); + } - PopulateToolbar(m_ToolBar); - // after adding the buttons to the toolbar, must call Realize() to reflect - // the changes - m_ToolBar->Realize(); + PopulateToolbar(m_ToolBar); + // after adding the buttons to the toolbar, must call Realize() to reflect + // the changes + m_ToolBar->Realize(); - UpdateGUI(); + UpdateGUI(); } void CFrame::InitBitmaps() { - auto const dir = StrToWxStr(File::GetThemeDir(SConfig::GetInstance().theme_name)); + auto const dir = StrToWxStr(File::GetThemeDir(SConfig::GetInstance().theme_name)); - m_Bitmaps[Toolbar_FileOpen ].LoadFile(dir + "open.png", wxBITMAP_TYPE_PNG); - m_Bitmaps[Toolbar_Refresh ].LoadFile(dir + "refresh.png", wxBITMAP_TYPE_PNG); - m_Bitmaps[Toolbar_Play ].LoadFile(dir + "play.png", wxBITMAP_TYPE_PNG); - m_Bitmaps[Toolbar_Stop ].LoadFile(dir + "stop.png", wxBITMAP_TYPE_PNG); - m_Bitmaps[Toolbar_Pause ].LoadFile(dir + "pause.png", wxBITMAP_TYPE_PNG); - m_Bitmaps[Toolbar_ConfigMain ].LoadFile(dir + "config.png", wxBITMAP_TYPE_PNG); - m_Bitmaps[Toolbar_ConfigGFX ].LoadFile(dir + "graphics.png", wxBITMAP_TYPE_PNG); - m_Bitmaps[Toolbar_Controller ].LoadFile(dir + "classic.png", wxBITMAP_TYPE_PNG); - m_Bitmaps[Toolbar_Screenshot ].LoadFile(dir + "screenshot.png", wxBITMAP_TYPE_PNG); - m_Bitmaps[Toolbar_FullScreen ].LoadFile(dir + "fullscreen.png", wxBITMAP_TYPE_PNG); + m_Bitmaps[Toolbar_FileOpen].LoadFile(dir + "open.png", wxBITMAP_TYPE_PNG); + m_Bitmaps[Toolbar_Refresh].LoadFile(dir + "refresh.png", wxBITMAP_TYPE_PNG); + m_Bitmaps[Toolbar_Play].LoadFile(dir + "play.png", wxBITMAP_TYPE_PNG); + m_Bitmaps[Toolbar_Stop].LoadFile(dir + "stop.png", wxBITMAP_TYPE_PNG); + m_Bitmaps[Toolbar_Pause].LoadFile(dir + "pause.png", wxBITMAP_TYPE_PNG); + m_Bitmaps[Toolbar_ConfigMain].LoadFile(dir + "config.png", wxBITMAP_TYPE_PNG); + m_Bitmaps[Toolbar_ConfigGFX].LoadFile(dir + "graphics.png", wxBITMAP_TYPE_PNG); + m_Bitmaps[Toolbar_Controller].LoadFile(dir + "classic.png", wxBITMAP_TYPE_PNG); + m_Bitmaps[Toolbar_Screenshot].LoadFile(dir + "screenshot.png", wxBITMAP_TYPE_PNG); + m_Bitmaps[Toolbar_FullScreen].LoadFile(dir + "fullscreen.png", wxBITMAP_TYPE_PNG); - // Update in case the bitmap has been updated - if (m_ToolBar != nullptr) - RecreateToolbar(); + // Update in case the bitmap has been updated + if (m_ToolBar != nullptr) + RecreateToolbar(); } // Menu items @@ -610,1405 +607,1397 @@ void CFrame::InitBitmaps() // 3. Boot last selected game void CFrame::BootGame(const std::string& filename) { - std::string bootfile = filename; - SConfig& StartUp = SConfig::GetInstance(); + std::string bootfile = filename; + SConfig& StartUp = SConfig::GetInstance(); - if (Core::GetState() != Core::CORE_UNINITIALIZED) - return; + if (Core::GetState() != Core::CORE_UNINITIALIZED) + return; - // Start filename if non empty. - // Start the selected ISO, or try one of the saved paths. - // If all that fails, ask to add a dir and don't boot - if (bootfile.empty()) - { - if (m_GameListCtrl->GetSelectedISO() != nullptr) - { - if (m_GameListCtrl->GetSelectedISO()->IsValid()) - bootfile = m_GameListCtrl->GetSelectedISO()->GetFileName(); - } - else if (!StartUp.m_strDefaultISO.empty() && - File::Exists(StartUp.m_strDefaultISO)) - { - bootfile = StartUp.m_strDefaultISO; - } - else - { - if (!SConfig::GetInstance().m_LastFilename.empty() && - File::Exists(SConfig::GetInstance().m_LastFilename)) - { - bootfile = SConfig::GetInstance().m_LastFilename; - } - else - { - m_GameListCtrl->BrowseForDirectory(); - return; - } - } - } - if (!bootfile.empty()) - { - StartGame(bootfile); - if (UseDebugger && g_pCodeWindow) - { - if (g_pCodeWindow->m_WatchWindow) - g_pCodeWindow->m_WatchWindow->LoadAll(); - if (g_pCodeWindow->m_BreakpointWindow) - g_pCodeWindow->m_BreakpointWindow->LoadAll(); - } - } + // Start filename if non empty. + // Start the selected ISO, or try one of the saved paths. + // If all that fails, ask to add a dir and don't boot + if (bootfile.empty()) + { + if (m_GameListCtrl->GetSelectedISO() != nullptr) + { + if (m_GameListCtrl->GetSelectedISO()->IsValid()) + bootfile = m_GameListCtrl->GetSelectedISO()->GetFileName(); + } + else if (!StartUp.m_strDefaultISO.empty() && File::Exists(StartUp.m_strDefaultISO)) + { + bootfile = StartUp.m_strDefaultISO; + } + else + { + if (!SConfig::GetInstance().m_LastFilename.empty() && + File::Exists(SConfig::GetInstance().m_LastFilename)) + { + bootfile = SConfig::GetInstance().m_LastFilename; + } + else + { + m_GameListCtrl->BrowseForDirectory(); + return; + } + } + } + if (!bootfile.empty()) + { + StartGame(bootfile); + if (UseDebugger && g_pCodeWindow) + { + if (g_pCodeWindow->m_WatchWindow) + g_pCodeWindow->m_WatchWindow->LoadAll(); + if (g_pCodeWindow->m_BreakpointWindow) + g_pCodeWindow->m_BreakpointWindow->LoadAll(); + } + } } // Open file to boot -void CFrame::OnOpen(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnOpen(wxCommandEvent& WXUNUSED(event)) { - if (Core::GetState() == Core::CORE_UNINITIALIZED) - DoOpen(true); + if (Core::GetState() == Core::CORE_UNINITIALIZED) + DoOpen(true); } void CFrame::DoOpen(bool Boot) { - std::string currentDir = File::GetCurrentDir(); + std::string currentDir = File::GetCurrentDir(); - wxString path = wxFileSelector( - _("Select the file to load"), - wxEmptyString, wxEmptyString, wxEmptyString, - _("All GC/Wii files (elf, dol, gcm, iso, wbfs, ciso, gcz, wad)") + - wxString::Format("|*.elf;*.dol;*.gcm;*.iso;*.wbfs;*.ciso;*.gcz;*.wad;*.dff;*.tmd|%s", - wxGetTranslation(wxALL_FILES)), - wxFD_OPEN | wxFD_FILE_MUST_EXIST, - this); + wxString path = wxFileSelector( + _("Select the file to load"), wxEmptyString, wxEmptyString, wxEmptyString, + _("All GC/Wii files (elf, dol, gcm, iso, wbfs, ciso, gcz, wad)") + + wxString::Format("|*.elf;*.dol;*.gcm;*.iso;*.wbfs;*.ciso;*.gcz;*.wad;*.dff;*.tmd|%s", + wxGetTranslation(wxALL_FILES)), + wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); - if (path.IsEmpty()) - return; + if (path.IsEmpty()) + return; - std::string currentDir2 = File::GetCurrentDir(); + std::string currentDir2 = File::GetCurrentDir(); - if (currentDir != currentDir2) - { - PanicAlertT("Current directory changed from %s to %s after wxFileSelector!", - currentDir.c_str(), currentDir2.c_str()); - File::SetCurrentDir(currentDir); - } + if (currentDir != currentDir2) + { + PanicAlertT("Current directory changed from %s to %s after wxFileSelector!", currentDir.c_str(), + currentDir2.c_str()); + File::SetCurrentDir(currentDir); + } - // Should we boot a new game or just change the disc? - if (Boot && !path.IsEmpty()) - { - BootGame(WxStrToStr(path)); - } - else - { - DVDInterface::ChangeDisc(WxStrToStr(path)); - } + // Should we boot a new game or just change the disc? + if (Boot && !path.IsEmpty()) + { + BootGame(WxStrToStr(path)); + } + else + { + DVDInterface::ChangeDisc(WxStrToStr(path)); + } } void CFrame::OnRecordReadOnly(wxCommandEvent& event) { - Movie::SetReadOnly(event.IsChecked()); + Movie::SetReadOnly(event.IsChecked()); } void CFrame::OnTASInput(wxCommandEvent& event) { - for (int i = 0; i < 4; ++i) - { - if (SConfig::GetInstance().m_SIDevice[i] != SIDEVICE_NONE && SConfig::GetInstance().m_SIDevice[i] != SIDEVICE_GC_GBA) - { - g_TASInputDlg[i]->CreateGCLayout(); - g_TASInputDlg[i]->Show(); - g_TASInputDlg[i]->SetTitle(wxString::Format(_("TAS Input - Controller %d"), i + 1)); - } + for (int i = 0; i < 4; ++i) + { + if (SConfig::GetInstance().m_SIDevice[i] != SIDEVICE_NONE && + SConfig::GetInstance().m_SIDevice[i] != SIDEVICE_GC_GBA) + { + g_TASInputDlg[i]->CreateGCLayout(); + g_TASInputDlg[i]->Show(); + g_TASInputDlg[i]->SetTitle(wxString::Format(_("TAS Input - Controller %d"), i + 1)); + } - if (g_wiimote_sources[i] == WIIMOTE_SRC_EMU && !(Core::IsRunning() && !SConfig::GetInstance().bWii)) - { - g_TASInputDlg[i+4]->CreateWiiLayout(i); - g_TASInputDlg[i+4]->Show(); - g_TASInputDlg[i+4]->SetTitle(wxString::Format(_("TAS Input - Wiimote %d"), i + 1)); - } - } + if (g_wiimote_sources[i] == WIIMOTE_SRC_EMU && + !(Core::IsRunning() && !SConfig::GetInstance().bWii)) + { + g_TASInputDlg[i + 4]->CreateWiiLayout(i); + g_TASInputDlg[i + 4]->Show(); + g_TASInputDlg[i + 4]->SetTitle(wxString::Format(_("TAS Input - Wiimote %d"), i + 1)); + } + } } -void CFrame::OnTogglePauseMovie(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnTogglePauseMovie(wxCommandEvent& WXUNUSED(event)) { - SConfig::GetInstance().m_PauseMovie = !SConfig::GetInstance().m_PauseMovie; - SConfig::GetInstance().SaveSettings(); + SConfig::GetInstance().m_PauseMovie = !SConfig::GetInstance().m_PauseMovie; + SConfig::GetInstance().SaveSettings(); } void CFrame::OnToggleDumpFrames(wxCommandEvent& WXUNUSED(event)) { - SConfig::GetInstance().m_DumpFrames = !SConfig::GetInstance().m_DumpFrames; - SConfig::GetInstance().SaveSettings(); + SConfig::GetInstance().m_DumpFrames = !SConfig::GetInstance().m_DumpFrames; + SConfig::GetInstance().SaveSettings(); } void CFrame::OnToggleDumpAudio(wxCommandEvent& WXUNUSED(event)) { - SConfig::GetInstance().m_DumpAudio = !SConfig::GetInstance().m_DumpAudio; + SConfig::GetInstance().m_DumpAudio = !SConfig::GetInstance().m_DumpAudio; } -void CFrame::OnShowLag(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnShowLag(wxCommandEvent& WXUNUSED(event)) { - SConfig::GetInstance().m_ShowLag = !SConfig::GetInstance().m_ShowLag; - SConfig::GetInstance().SaveSettings(); + SConfig::GetInstance().m_ShowLag = !SConfig::GetInstance().m_ShowLag; + SConfig::GetInstance().SaveSettings(); } -void CFrame::OnShowFrameCount(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnShowFrameCount(wxCommandEvent& WXUNUSED(event)) { - SConfig::GetInstance().m_ShowFrameCount = !SConfig::GetInstance().m_ShowFrameCount; - SConfig::GetInstance().SaveSettings(); + SConfig::GetInstance().m_ShowFrameCount = !SConfig::GetInstance().m_ShowFrameCount; + SConfig::GetInstance().SaveSettings(); } void CFrame::OnShowInputDisplay(wxCommandEvent& WXUNUSED(event)) { - SConfig::GetInstance().m_ShowInputDisplay = !SConfig::GetInstance().m_ShowInputDisplay; - SConfig::GetInstance().SaveSettings(); + SConfig::GetInstance().m_ShowInputDisplay = !SConfig::GetInstance().m_ShowInputDisplay; + SConfig::GetInstance().SaveSettings(); } void CFrame::OnFrameStep(wxCommandEvent& event) { - bool wasPaused = (Core::GetState() == Core::CORE_PAUSE); + bool wasPaused = (Core::GetState() == Core::CORE_PAUSE); - Movie::DoFrameStep(); + Movie::DoFrameStep(); - bool isPaused = (Core::GetState() == Core::CORE_PAUSE); - if (isPaused && !wasPaused) // don't update on unpause, otherwise the status would be wrong when pausing next frame - UpdateGUI(); + bool isPaused = (Core::GetState() == Core::CORE_PAUSE); + if (isPaused && !wasPaused) // don't update on unpause, otherwise the status would be wrong when + // pausing next frame + UpdateGUI(); } -void CFrame::OnChangeDisc(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnChangeDisc(wxCommandEvent& WXUNUSED(event)) { - DoOpen(false); + DoOpen(false); } -void CFrame::OnRecord(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnRecord(wxCommandEvent& WXUNUSED(event)) { - if ((!Core::IsRunningAndStarted() && Core::IsRunning()) || Movie::IsRecordingInput() || Movie::IsPlayingInput()) - return; + if ((!Core::IsRunningAndStarted() && Core::IsRunning()) || Movie::IsRecordingInput() || + Movie::IsPlayingInput()) + return; - int controllers = 0; + int controllers = 0; - if (Movie::IsReadOnly()) - { - // The user just chose to record a movie, so that should take precedence - Movie::SetReadOnly(false); - GetMenuBar()->FindItem(IDM_RECORD_READ_ONLY)->Check(false); - } + if (Movie::IsReadOnly()) + { + // The user just chose to record a movie, so that should take precedence + Movie::SetReadOnly(false); + GetMenuBar()->FindItem(IDM_RECORD_READ_ONLY)->Check(false); + } - for (int i = 0; i < 4; i++) - { - if (SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i])) - controllers |= (1 << i); + for (int i = 0; i < 4; i++) + { + if (SIDevice_IsGCController(SConfig::GetInstance().m_SIDevice[i])) + controllers |= (1 << i); - if (g_wiimote_sources[i] != WIIMOTE_SRC_NONE) - controllers |= (1 << (i + 4)); - } + if (g_wiimote_sources[i] != WIIMOTE_SRC_NONE) + controllers |= (1 << (i + 4)); + } - if (Movie::BeginRecordingInput(controllers)) - BootGame(""); + if (Movie::BeginRecordingInput(controllers)) + BootGame(""); } -void CFrame::OnPlayRecording(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnPlayRecording(wxCommandEvent& WXUNUSED(event)) { - wxString path = wxFileSelector( - _("Select The Recording File"), - wxEmptyString, wxEmptyString, wxEmptyString, - _("Dolphin TAS Movies (*.dtm)") + - wxString::Format("|*.dtm|%s", wxGetTranslation(wxALL_FILES)), - wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, - this); + wxString path = + wxFileSelector(_("Select The Recording File"), wxEmptyString, wxEmptyString, wxEmptyString, + _("Dolphin TAS Movies (*.dtm)") + + wxString::Format("|*.dtm|%s", wxGetTranslation(wxALL_FILES)), + wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, this); - if (path.IsEmpty()) - return; + if (path.IsEmpty()) + return; - if (!Movie::IsReadOnly()) - { - // let's make the read-only flag consistent at the start of a movie. - Movie::SetReadOnly(true); - GetMenuBar()->FindItem(IDM_RECORD_READ_ONLY)->Check(); - } + if (!Movie::IsReadOnly()) + { + // let's make the read-only flag consistent at the start of a movie. + Movie::SetReadOnly(true); + GetMenuBar()->FindItem(IDM_RECORD_READ_ONLY)->Check(); + } - if (Movie::PlayInput(WxStrToStr(path))) - BootGame(""); + if (Movie::PlayInput(WxStrToStr(path))) + BootGame(""); } -void CFrame::OnRecordExport(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnRecordExport(wxCommandEvent& WXUNUSED(event)) { - DoRecordingSave(); + DoRecordingSave(); } -void CFrame::OnPlay(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnPlay(wxCommandEvent& WXUNUSED(event)) { - if (Core::IsRunning()) - { - // Core is initialized and emulator is running - if (UseDebugger) - { - CPU::EnableStepping(!CPU::IsStepping()); + if (Core::IsRunning()) + { + // Core is initialized and emulator is running + if (UseDebugger) + { + CPU::EnableStepping(!CPU::IsStepping()); - wxThread::Sleep(20); - g_pCodeWindow->JumpToAddress(PC); - g_pCodeWindow->Update(); - // Update toolbar with Play/Pause status - UpdateGUI(); - } - else - { - DoPause(); - } - } - else - { - // Core is uninitialized, start the game - BootGame(""); - } + wxThread::Sleep(20); + g_pCodeWindow->JumpToAddress(PC); + g_pCodeWindow->Update(); + // Update toolbar with Play/Pause status + UpdateGUI(); + } + else + { + DoPause(); + } + } + else + { + // Core is uninitialized, start the game + BootGame(""); + } } void CFrame::OnRenderParentClose(wxCloseEvent& event) { - // Before closing the window we need to shut down the emulation core. - // We'll try to close this window again once that is done. - if (Core::GetState() != Core::CORE_UNINITIALIZED) - { - DoStop(); - if (event.CanVeto()) - { - event.Veto(); - } - return; - } + // Before closing the window we need to shut down the emulation core. + // We'll try to close this window again once that is done. + if (Core::GetState() != Core::CORE_UNINITIALIZED) + { + DoStop(); + if (event.CanVeto()) + { + event.Veto(); + } + return; + } - event.Skip(); + event.Skip(); } void CFrame::OnRenderParentMove(wxMoveEvent& event) { - if (Core::GetState() != Core::CORE_UNINITIALIZED && - !RendererIsFullscreen() && !m_RenderFrame->IsMaximized() && !m_RenderFrame->IsIconized()) - { - SConfig::GetInstance().iRenderWindowXPos = m_RenderFrame->GetPosition().x; - SConfig::GetInstance().iRenderWindowYPos = m_RenderFrame->GetPosition().y; - } - event.Skip(); + if (Core::GetState() != Core::CORE_UNINITIALIZED && !RendererIsFullscreen() && + !m_RenderFrame->IsMaximized() && !m_RenderFrame->IsIconized()) + { + SConfig::GetInstance().iRenderWindowXPos = m_RenderFrame->GetPosition().x; + SConfig::GetInstance().iRenderWindowYPos = m_RenderFrame->GetPosition().y; + } + event.Skip(); } void CFrame::OnRenderParentResize(wxSizeEvent& event) { - if (Core::GetState() != Core::CORE_UNINITIALIZED) - { - int width, height; - if (!SConfig::GetInstance().bRenderToMain && - !RendererIsFullscreen() && !m_RenderFrame->IsMaximized() && !m_RenderFrame->IsIconized()) - { - m_RenderFrame->GetClientSize(&width, &height); - SConfig::GetInstance().iRenderWindowWidth = width; - SConfig::GetInstance().iRenderWindowHeight = height; - } - m_LogWindow->Refresh(); - m_LogWindow->Update(); - } - event.Skip(); + if (Core::GetState() != Core::CORE_UNINITIALIZED) + { + int width, height; + if (!SConfig::GetInstance().bRenderToMain && !RendererIsFullscreen() && + !m_RenderFrame->IsMaximized() && !m_RenderFrame->IsIconized()) + { + m_RenderFrame->GetClientSize(&width, &height); + SConfig::GetInstance().iRenderWindowWidth = width; + SConfig::GetInstance().iRenderWindowHeight = height; + } + m_LogWindow->Refresh(); + m_LogWindow->Update(); + } + event.Skip(); } void CFrame::ToggleDisplayMode(bool bFullscreen) { #ifdef _WIN32 - if (bFullscreen && SConfig::GetInstance().strFullscreenResolution != "Auto") - { - DEVMODE dmScreenSettings; - memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); - dmScreenSettings.dmSize = sizeof(dmScreenSettings); - sscanf(SConfig::GetInstance().strFullscreenResolution.c_str(), - "%dx%d", &dmScreenSettings.dmPelsWidth, &dmScreenSettings.dmPelsHeight); - dmScreenSettings.dmBitsPerPel = 32; - dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + if (bFullscreen && SConfig::GetInstance().strFullscreenResolution != "Auto") + { + DEVMODE dmScreenSettings; + memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); + dmScreenSettings.dmSize = sizeof(dmScreenSettings); + sscanf(SConfig::GetInstance().strFullscreenResolution.c_str(), "%dx%d", + &dmScreenSettings.dmPelsWidth, &dmScreenSettings.dmPelsHeight); + dmScreenSettings.dmBitsPerPel = 32; + dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; - // Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar. - ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN); - } - else - { - // Change to default resolution - ChangeDisplaySettings(nullptr, CDS_FULLSCREEN); - } + // Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar. + ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN); + } + else + { + // Change to default resolution + ChangeDisplaySettings(nullptr, CDS_FULLSCREEN); + } #elif defined(HAVE_XRANDR) && HAVE_XRANDR - if (SConfig::GetInstance().strFullscreenResolution != "Auto") - m_XRRConfig->ToggleDisplayMode(bFullscreen); + if (SConfig::GetInstance().strFullscreenResolution != "Auto") + m_XRRConfig->ToggleDisplayMode(bFullscreen); #endif } // Prepare the GUI to start the game. void CFrame::StartGame(const std::string& filename) { - if (m_bGameLoading) - return; - m_bGameLoading = true; + if (m_bGameLoading) + return; + m_bGameLoading = true; - if (m_ToolBar) - m_ToolBar->EnableTool(IDM_PLAY, false); - GetMenuBar()->FindItem(IDM_PLAY)->Enable(false); + if (m_ToolBar) + m_ToolBar->EnableTool(IDM_PLAY, false); + GetMenuBar()->FindItem(IDM_PLAY)->Enable(false); - if (SConfig::GetInstance().bRenderToMain) - { - // Game has been started, hide the game list - m_GameListCtrl->Disable(); - m_GameListCtrl->Hide(); + if (SConfig::GetInstance().bRenderToMain) + { + // Game has been started, hide the game list + m_GameListCtrl->Disable(); + m_GameListCtrl->Hide(); - m_RenderParent = m_Panel; - m_RenderFrame = this; - if (SConfig::GetInstance().bKeepWindowOnTop) - m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() | wxSTAY_ON_TOP); - else - m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP); + m_RenderParent = m_Panel; + m_RenderFrame = this; + if (SConfig::GetInstance().bKeepWindowOnTop) + m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() | wxSTAY_ON_TOP); + else + m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP); - // No, I really don't want TAB_TRAVERSAL being set behind my back, - // thanks. (Note that calling DisableSelfFocus would prevent this flag - // from being set for new children, but wouldn't reset the existing - // flag.) - m_RenderParent->SetWindowStyle(m_RenderParent->GetWindowStyle() & ~wxTAB_TRAVERSAL); - } - else - { - wxPoint position(SConfig::GetInstance().iRenderWindowXPos, - SConfig::GetInstance().iRenderWindowYPos); + // No, I really don't want TAB_TRAVERSAL being set behind my back, + // thanks. (Note that calling DisableSelfFocus would prevent this flag + // from being set for new children, but wouldn't reset the existing + // flag.) + m_RenderParent->SetWindowStyle(m_RenderParent->GetWindowStyle() & ~wxTAB_TRAVERSAL); + } + else + { + wxPoint position(SConfig::GetInstance().iRenderWindowXPos, + SConfig::GetInstance().iRenderWindowYPos); #ifdef __APPLE__ - // On OS X, the render window's title bar is not visible, - // and the window therefore not easily moved, when the - // position is 0,0. Weed out the 0's from existing configs. - if (position == wxPoint(0, 0)) - position = wxDefaultPosition; + // On OS X, the render window's title bar is not visible, + // and the window therefore not easily moved, when the + // position is 0,0. Weed out the 0's from existing configs. + if (position == wxPoint(0, 0)) + position = wxDefaultPosition; #endif - wxSize size(SConfig::GetInstance().iRenderWindowWidth, - SConfig::GetInstance().iRenderWindowHeight); + wxSize size(SConfig::GetInstance().iRenderWindowWidth, + SConfig::GetInstance().iRenderWindowHeight); #ifdef _WIN32 - // Out of desktop check - int leftPos = GetSystemMetrics(SM_XVIRTUALSCREEN); - int topPos = GetSystemMetrics(SM_YVIRTUALSCREEN); - int width = GetSystemMetrics(SM_CXVIRTUALSCREEN); - int height = GetSystemMetrics(SM_CYVIRTUALSCREEN); - if ((leftPos + width) < (position.x + size.GetWidth()) || leftPos > position.x || (topPos + height) < (position.y + size.GetHeight()) || topPos > position.y) - position.x = position.y = wxDefaultCoord; + // Out of desktop check + int leftPos = GetSystemMetrics(SM_XVIRTUALSCREEN); + int topPos = GetSystemMetrics(SM_YVIRTUALSCREEN); + int width = GetSystemMetrics(SM_CXVIRTUALSCREEN); + int height = GetSystemMetrics(SM_CYVIRTUALSCREEN); + if ((leftPos + width) < (position.x + size.GetWidth()) || leftPos > position.x || + (topPos + height) < (position.y + size.GetHeight()) || topPos > position.y) + position.x = position.y = wxDefaultCoord; #endif - m_RenderFrame = new CRenderFrame((wxFrame*)this, wxID_ANY, _("Dolphin"), position); - if (SConfig::GetInstance().bKeepWindowOnTop) - m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() | wxSTAY_ON_TOP); - else - m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP); + m_RenderFrame = new CRenderFrame((wxFrame*)this, wxID_ANY, _("Dolphin"), position); + if (SConfig::GetInstance().bKeepWindowOnTop) + m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() | wxSTAY_ON_TOP); + else + m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP); - m_RenderFrame->SetBackgroundColour(*wxBLACK); - m_RenderFrame->SetClientSize(size.GetWidth(), size.GetHeight()); - m_RenderFrame->Bind(wxEVT_CLOSE_WINDOW, &CFrame::OnRenderParentClose, this); - m_RenderFrame->Bind(wxEVT_ACTIVATE, &CFrame::OnActive, this); - m_RenderFrame->Bind(wxEVT_MOVE, &CFrame::OnRenderParentMove, this); + m_RenderFrame->SetBackgroundColour(*wxBLACK); + m_RenderFrame->SetClientSize(size.GetWidth(), size.GetHeight()); + m_RenderFrame->Bind(wxEVT_CLOSE_WINDOW, &CFrame::OnRenderParentClose, this); + m_RenderFrame->Bind(wxEVT_ACTIVATE, &CFrame::OnActive, this); + m_RenderFrame->Bind(wxEVT_MOVE, &CFrame::OnRenderParentMove, this); #ifdef _WIN32 - // The renderer should use a top-level window for exclusive fullscreen support. - m_RenderParent = m_RenderFrame; + // The renderer should use a top-level window for exclusive fullscreen support. + m_RenderParent = m_RenderFrame; #else - // To capture key events on Linux and Mac OS X the frame needs at least one child. - m_RenderParent = new wxPanel(m_RenderFrame, IDM_MPANEL, wxDefaultPosition, wxDefaultSize, 0); + // To capture key events on Linux and Mac OS X the frame needs at least one child. + m_RenderParent = new wxPanel(m_RenderFrame, IDM_MPANEL, wxDefaultPosition, wxDefaultSize, 0); #endif - m_RenderFrame->Show(); - } + m_RenderFrame->Show(); + } #if defined(__APPLE__) - NSView *view = (NSView *) m_RenderFrame->GetHandle(); - NSWindow *window = [view window]; + NSView* view = (NSView*)m_RenderFrame->GetHandle(); + NSWindow* window = [view window]; - [window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; + [window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; #endif - wxBeginBusyCursor(); + wxBeginBusyCursor(); - DoFullscreen(SConfig::GetInstance().bFullscreen); + DoFullscreen(SConfig::GetInstance().bFullscreen); - if (!BootManager::BootCore(filename)) - { - DoFullscreen(false); - // Destroy the renderer frame when not rendering to main - if (!SConfig::GetInstance().bRenderToMain) - m_RenderFrame->Destroy(); - m_RenderParent = nullptr; - m_bGameLoading = false; - UpdateGUI(); - } - else - { + if (!BootManager::BootCore(filename)) + { + DoFullscreen(false); + // Destroy the renderer frame when not rendering to main + if (!SConfig::GetInstance().bRenderToMain) + m_RenderFrame->Destroy(); + m_RenderParent = nullptr; + m_bGameLoading = false; + UpdateGUI(); + } + else + { #if defined(HAVE_X11) && HAVE_X11 - if (SConfig::GetInstance().bDisableScreenSaver) - X11Utils::InhibitScreensaver(X11Utils::XDisplayFromHandle(GetHandle()), - X11Utils::XWindowFromHandle(GetHandle()), true); + if (SConfig::GetInstance().bDisableScreenSaver) + X11Utils::InhibitScreensaver(X11Utils::XDisplayFromHandle(GetHandle()), + X11Utils::XWindowFromHandle(GetHandle()), true); #endif - m_RenderParent->SetFocus(); + m_RenderParent->SetFocus(); - wxTheApp->Bind(wxEVT_KEY_DOWN, &CFrame::OnKeyDown, this); - wxTheApp->Bind(wxEVT_RIGHT_DOWN, &CFrame::OnMouse, this); - wxTheApp->Bind(wxEVT_RIGHT_UP, &CFrame::OnMouse, this); - wxTheApp->Bind(wxEVT_MIDDLE_DOWN, &CFrame::OnMouse, this); - wxTheApp->Bind(wxEVT_MIDDLE_UP, &CFrame::OnMouse, this); - wxTheApp->Bind(wxEVT_MOTION, &CFrame::OnMouse, this); - wxTheApp->Bind(wxEVT_SET_FOCUS, &CFrame::OnFocusChange, this); - wxTheApp->Bind(wxEVT_KILL_FOCUS, &CFrame::OnFocusChange, this); - m_RenderParent->Bind(wxEVT_SIZE, &CFrame::OnRenderParentResize, this); - } + wxTheApp->Bind(wxEVT_KEY_DOWN, &CFrame::OnKeyDown, this); + wxTheApp->Bind(wxEVT_RIGHT_DOWN, &CFrame::OnMouse, this); + wxTheApp->Bind(wxEVT_RIGHT_UP, &CFrame::OnMouse, this); + wxTheApp->Bind(wxEVT_MIDDLE_DOWN, &CFrame::OnMouse, this); + wxTheApp->Bind(wxEVT_MIDDLE_UP, &CFrame::OnMouse, this); + wxTheApp->Bind(wxEVT_MOTION, &CFrame::OnMouse, this); + wxTheApp->Bind(wxEVT_SET_FOCUS, &CFrame::OnFocusChange, this); + wxTheApp->Bind(wxEVT_KILL_FOCUS, &CFrame::OnFocusChange, this); + m_RenderParent->Bind(wxEVT_SIZE, &CFrame::OnRenderParentResize, this); + } - wxEndBusyCursor(); + wxEndBusyCursor(); } void CFrame::OnBootDrive(wxCommandEvent& event) { - BootGame(drives[event.GetId()-IDM_DRIVE1]); + BootGame(drives[event.GetId() - IDM_DRIVE1]); } // Refresh the file list and browse for a favorites directory -void CFrame::OnRefresh(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnRefresh(wxCommandEvent& WXUNUSED(event)) { - if (m_GameListCtrl) - { - m_GameListCtrl->Update(); - } + if (m_GameListCtrl) + { + m_GameListCtrl->Update(); + } } // Create screenshot -void CFrame::OnScreenshot(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnScreenshot(wxCommandEvent& WXUNUSED(event)) { - Core::SaveScreenShot(); + Core::SaveScreenShot(); } // Pause the emulation void CFrame::DoPause() { - if (Core::GetState() == Core::CORE_RUN) - { - Core::SetState(Core::CORE_PAUSE); - if (SConfig::GetInstance().bHideCursor) - m_RenderParent->SetCursor(wxNullCursor); - Core::UpdateTitle(); - } - else - { - Core::SetState(Core::CORE_RUN); - if (SConfig::GetInstance().bHideCursor && - RendererHasFocus()) - m_RenderParent->SetCursor(wxCURSOR_BLANK); - } - UpdateGUI(); + if (Core::GetState() == Core::CORE_RUN) + { + Core::SetState(Core::CORE_PAUSE); + if (SConfig::GetInstance().bHideCursor) + m_RenderParent->SetCursor(wxNullCursor); + Core::UpdateTitle(); + } + else + { + Core::SetState(Core::CORE_RUN); + if (SConfig::GetInstance().bHideCursor && RendererHasFocus()) + m_RenderParent->SetCursor(wxCURSOR_BLANK); + } + UpdateGUI(); } // Stop the emulation void CFrame::DoStop() { - if (!Core::IsRunningAndStarted()) - return; - if (m_confirmStop) - return; + if (!Core::IsRunningAndStarted()) + return; + if (m_confirmStop) + return; - // don't let this function run again until it finishes, or is aborted. - m_confirmStop = true; + // don't let this function run again until it finishes, or is aborted. + m_confirmStop = true; - m_bGameLoading = false; - if (Core::GetState() != Core::CORE_UNINITIALIZED || - m_RenderParent != nullptr) - { + m_bGameLoading = false; + if (Core::GetState() != Core::CORE_UNINITIALIZED || m_RenderParent != nullptr) + { #if defined __WXGTK__ - wxMutexGuiLeave(); - std::lock_guard lk(keystate_lock); - wxMutexGuiEnter(); + wxMutexGuiLeave(); + std::lock_guard lk(keystate_lock); + wxMutexGuiEnter(); #endif - // Ask for confirmation in case the user accidentally clicked Stop / Escape - if (SConfig::GetInstance().bConfirmStop) - { - // Exit fullscreen to ensure it does not cover the stop dialog. - DoFullscreen(false); + // Ask for confirmation in case the user accidentally clicked Stop / Escape + if (SConfig::GetInstance().bConfirmStop) + { + // Exit fullscreen to ensure it does not cover the stop dialog. + DoFullscreen(false); - // Pause the state during confirmation and restore it afterwards - Core::EState state = Core::GetState(); + // Pause the state during confirmation and restore it afterwards + Core::EState state = Core::GetState(); - // If exclusive fullscreen is not enabled then we can pause the emulation - // before we've exited fullscreen. If not then we need to exit fullscreen first. - if (!RendererIsFullscreen() || !g_Config.ExclusiveFullscreenEnabled() || - SConfig::GetInstance().bRenderToMain) - { - Core::SetState(Core::CORE_PAUSE); - } + // If exclusive fullscreen is not enabled then we can pause the emulation + // before we've exited fullscreen. If not then we need to exit fullscreen first. + if (!RendererIsFullscreen() || !g_Config.ExclusiveFullscreenEnabled() || + SConfig::GetInstance().bRenderToMain) + { + Core::SetState(Core::CORE_PAUSE); + } - wxMessageDialog m_StopDlg( - this, - _("Do you want to stop the current emulation?"), - _("Please confirm..."), - wxYES_NO | wxSTAY_ON_TOP | wxICON_EXCLAMATION, - wxDefaultPosition); + wxMessageDialog m_StopDlg(this, _("Do you want to stop the current emulation?"), + _("Please confirm..."), + wxYES_NO | wxSTAY_ON_TOP | wxICON_EXCLAMATION, wxDefaultPosition); - HotkeyManagerEmu::Enable(false); - int Ret = m_StopDlg.ShowModal(); - HotkeyManagerEmu::Enable(true); - if (Ret != wxID_YES) - { - Core::SetState(state); - m_confirmStop = false; - return; - } - } + HotkeyManagerEmu::Enable(false); + int Ret = m_StopDlg.ShowModal(); + HotkeyManagerEmu::Enable(true); + if (Ret != wxID_YES) + { + Core::SetState(state); + m_confirmStop = false; + return; + } + } - if (UseDebugger && g_pCodeWindow) - { - if (g_pCodeWindow->m_WatchWindow) - { - g_pCodeWindow->m_WatchWindow->SaveAll(); - PowerPC::watches.Clear(); - } - if (g_pCodeWindow->m_BreakpointWindow) - { - g_pCodeWindow->m_BreakpointWindow->SaveAll(); - PowerPC::breakpoints.Clear(); - PowerPC::memchecks.Clear(); - g_pCodeWindow->m_BreakpointWindow->NotifyUpdate(); - } - g_symbolDB.Clear(); - Host_NotifyMapLoaded(); - } + if (UseDebugger && g_pCodeWindow) + { + if (g_pCodeWindow->m_WatchWindow) + { + g_pCodeWindow->m_WatchWindow->SaveAll(); + PowerPC::watches.Clear(); + } + if (g_pCodeWindow->m_BreakpointWindow) + { + g_pCodeWindow->m_BreakpointWindow->SaveAll(); + PowerPC::breakpoints.Clear(); + PowerPC::memchecks.Clear(); + g_pCodeWindow->m_BreakpointWindow->NotifyUpdate(); + } + g_symbolDB.Clear(); + Host_NotifyMapLoaded(); + } - // TODO: Show the author/description dialog here - if (Movie::IsRecordingInput()) - DoRecordingSave(); - if (Movie::IsMovieActive()) - Movie::EndPlayInput(false); + // TODO: Show the author/description dialog here + if (Movie::IsRecordingInput()) + DoRecordingSave(); + if (Movie::IsMovieActive()) + Movie::EndPlayInput(false); - if (NetPlayDialog::GetNetPlayClient()) - NetPlayDialog::GetNetPlayClient()->Stop(); + if (NetPlayDialog::GetNetPlayClient()) + NetPlayDialog::GetNetPlayClient()->Stop(); - BootManager::Stop(); - UpdateGUI(); - } + BootManager::Stop(); + UpdateGUI(); + } } void CFrame::OnStopped() { - m_confirmStop = false; + m_confirmStop = false; #if defined(HAVE_X11) && HAVE_X11 - if (SConfig::GetInstance().bDisableScreenSaver) - X11Utils::InhibitScreensaver(X11Utils::XDisplayFromHandle(GetHandle()), - X11Utils::XWindowFromHandle(GetHandle()), false); + if (SConfig::GetInstance().bDisableScreenSaver) + X11Utils::InhibitScreensaver(X11Utils::XDisplayFromHandle(GetHandle()), + X11Utils::XWindowFromHandle(GetHandle()), false); #endif - m_RenderFrame->SetTitle(StrToWxStr(scm_rev_str)); + m_RenderFrame->SetTitle(StrToWxStr(scm_rev_str)); - // Destroy the renderer frame when not rendering to main - m_RenderParent->Unbind(wxEVT_SIZE, &CFrame::OnRenderParentResize, this); + // Destroy the renderer frame when not rendering to main + m_RenderParent->Unbind(wxEVT_SIZE, &CFrame::OnRenderParentResize, this); - // Mouse - wxTheApp->Unbind(wxEVT_RIGHT_DOWN, &CFrame::OnMouse, this); - wxTheApp->Unbind(wxEVT_RIGHT_UP, &CFrame::OnMouse, this); - wxTheApp->Unbind(wxEVT_MIDDLE_DOWN, &CFrame::OnMouse, this); - wxTheApp->Unbind(wxEVT_MIDDLE_UP, &CFrame::OnMouse, this); - wxTheApp->Unbind(wxEVT_MOTION, &CFrame::OnMouse, this); - if (SConfig::GetInstance().bHideCursor) - m_RenderParent->SetCursor(wxNullCursor); - DoFullscreen(false); - if (!SConfig::GetInstance().bRenderToMain) - { - m_RenderFrame->Destroy(); - } - else - { + // Mouse + wxTheApp->Unbind(wxEVT_RIGHT_DOWN, &CFrame::OnMouse, this); + wxTheApp->Unbind(wxEVT_RIGHT_UP, &CFrame::OnMouse, this); + wxTheApp->Unbind(wxEVT_MIDDLE_DOWN, &CFrame::OnMouse, this); + wxTheApp->Unbind(wxEVT_MIDDLE_UP, &CFrame::OnMouse, this); + wxTheApp->Unbind(wxEVT_MOTION, &CFrame::OnMouse, this); + if (SConfig::GetInstance().bHideCursor) + m_RenderParent->SetCursor(wxNullCursor); + DoFullscreen(false); + if (!SConfig::GetInstance().bRenderToMain) + { + m_RenderFrame->Destroy(); + } + else + { #if defined(__APPLE__) - // Disable the full screen button when not in a game. - NSView *view = (NSView *)m_RenderFrame->GetHandle(); - NSWindow *window = [view window]; + // Disable the full screen button when not in a game. + NSView* view = (NSView*)m_RenderFrame->GetHandle(); + NSWindow* window = [view window]; - [window setCollectionBehavior : NSWindowCollectionBehaviorDefault]; + [window setCollectionBehavior:NSWindowCollectionBehaviorDefault]; #endif - // Make sure the window is not longer set to stay on top - m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP); - } - m_RenderParent = nullptr; + // Make sure the window is not longer set to stay on top + m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP); + } + m_RenderParent = nullptr; - // Clean framerate indications from the status bar. - GetStatusBar()->SetStatusText(" ", 0); + // Clean framerate indications from the status bar. + GetStatusBar()->SetStatusText(" ", 0); - // Clear wiimote connection status from the status bar. - GetStatusBar()->SetStatusText(" ", 1); + // Clear wiimote connection status from the status bar. + GetStatusBar()->SetStatusText(" ", 1); - // If batch mode was specified on the command-line or we were already closing, exit now. - if (m_bBatchMode || m_bClosing) - Close(true); + // If batch mode was specified on the command-line or we were already closing, exit now. + if (m_bBatchMode || m_bClosing) + Close(true); - // If using auto size with render to main, reset the application size. - if (SConfig::GetInstance().bRenderToMain && - SConfig::GetInstance().bRenderWindowAutoSize) - SetSize(SConfig::GetInstance().iWidth, - SConfig::GetInstance().iHeight); + // If using auto size with render to main, reset the application size. + if (SConfig::GetInstance().bRenderToMain && SConfig::GetInstance().bRenderWindowAutoSize) + SetSize(SConfig::GetInstance().iWidth, SConfig::GetInstance().iHeight); - m_GameListCtrl->Enable(); - m_GameListCtrl->Show(); - m_GameListCtrl->SetFocus(); - UpdateGUI(); + m_GameListCtrl->Enable(); + m_GameListCtrl->Show(); + m_GameListCtrl->SetFocus(); + UpdateGUI(); } void CFrame::DoRecordingSave() { - bool paused = (Core::GetState() == Core::CORE_PAUSE); + bool paused = (Core::GetState() == Core::CORE_PAUSE); - if (!paused) - DoPause(); + if (!paused) + DoPause(); - wxString path = wxFileSelector( - _("Select The Recording File"), - wxEmptyString, wxEmptyString, wxEmptyString, - _("Dolphin TAS Movies (*.dtm)") + - wxString::Format("|*.dtm|%s", wxGetTranslation(wxALL_FILES)), - wxFD_SAVE | wxFD_PREVIEW | wxFD_OVERWRITE_PROMPT, - this); + wxString path = + wxFileSelector(_("Select The Recording File"), wxEmptyString, wxEmptyString, wxEmptyString, + _("Dolphin TAS Movies (*.dtm)") + + wxString::Format("|*.dtm|%s", wxGetTranslation(wxALL_FILES)), + wxFD_SAVE | wxFD_PREVIEW | wxFD_OVERWRITE_PROMPT, this); - if (path.IsEmpty()) - return; + if (path.IsEmpty()) + return; - Movie::SaveRecording(WxStrToStr(path)); + Movie::SaveRecording(WxStrToStr(path)); - if (!paused) - DoPause(); + if (!paused) + DoPause(); } -void CFrame::OnStop(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnStop(wxCommandEvent& WXUNUSED(event)) { - DoStop(); + DoStop(); } -void CFrame::OnReset(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnReset(wxCommandEvent& WXUNUSED(event)) { - if (Movie::IsRecordingInput()) - Movie::g_bReset = true; - ProcessorInterface::ResetButton_Tap(); + if (Movie::IsRecordingInput()) + Movie::g_bReset = true; + ProcessorInterface::ResetButton_Tap(); } -void CFrame::OnConfigMain(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnConfigMain(wxCommandEvent& WXUNUSED(event)) { - CConfigMain ConfigMain(this); - HotkeyManagerEmu::Enable(false); - if (ConfigMain.ShowModal() == wxID_OK) - m_GameListCtrl->Update(); - HotkeyManagerEmu::Enable(true); - UpdateGUI(); + CConfigMain ConfigMain(this); + HotkeyManagerEmu::Enable(false); + if (ConfigMain.ShowModal() == wxID_OK) + m_GameListCtrl->Update(); + HotkeyManagerEmu::Enable(true); + UpdateGUI(); } -void CFrame::OnConfigGFX(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnConfigGFX(wxCommandEvent& WXUNUSED(event)) { - HotkeyManagerEmu::Enable(false); - if (g_video_backend) - g_video_backend->ShowConfig(this); - HotkeyManagerEmu::Enable(true); + HotkeyManagerEmu::Enable(false); + if (g_video_backend) + g_video_backend->ShowConfig(this); + HotkeyManagerEmu::Enable(true); } -void CFrame::OnConfigAudio(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnConfigAudio(wxCommandEvent& WXUNUSED(event)) { - CConfigMain ConfigMain(this); - ConfigMain.SetSelectedTab(CConfigMain::ID_AUDIOPAGE); - HotkeyManagerEmu::Enable(false); - if (ConfigMain.ShowModal() == wxID_OK) - m_GameListCtrl->Update(); - HotkeyManagerEmu::Enable(true); + CConfigMain ConfigMain(this); + ConfigMain.SetSelectedTab(CConfigMain::ID_AUDIOPAGE); + HotkeyManagerEmu::Enable(false); + if (ConfigMain.ShowModal() == wxID_OK) + m_GameListCtrl->Update(); + HotkeyManagerEmu::Enable(true); } -void CFrame::OnConfigControllers(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnConfigControllers(wxCommandEvent& WXUNUSED(event)) { - ControllerConfigDiag config_dlg(this); - HotkeyManagerEmu::Enable(false); - config_dlg.ShowModal(); - HotkeyManagerEmu::Enable(true); + ControllerConfigDiag config_dlg(this); + HotkeyManagerEmu::Enable(false); + config_dlg.ShowModal(); + HotkeyManagerEmu::Enable(true); } -void CFrame::OnConfigHotkey(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnConfigHotkey(wxCommandEvent& WXUNUSED(event)) { - InputConfig* const hotkey_plugin = HotkeyManagerEmu::GetConfig(); + InputConfig* const hotkey_plugin = HotkeyManagerEmu::GetConfig(); - // check if game is running - bool game_running = false; - if (Core::GetState() == Core::CORE_RUN) - { - Core::SetState(Core::CORE_PAUSE); - game_running = true; - } + // check if game is running + bool game_running = false; + if (Core::GetState() == Core::CORE_RUN) + { + Core::SetState(Core::CORE_PAUSE); + game_running = true; + } - HotkeyManagerEmu::Enable(false); + HotkeyManagerEmu::Enable(false); - InputConfigDialog m_ConfigFrame(this, *hotkey_plugin, _("Dolphin Hotkeys")); - m_ConfigFrame.ShowModal(); + InputConfigDialog m_ConfigFrame(this, *hotkey_plugin, _("Dolphin Hotkeys")); + m_ConfigFrame.ShowModal(); - // Update references in case controllers were refreshed - Wiimote::LoadConfig(); - Keyboard::LoadConfig(); - Pad::LoadConfig(); - HotkeyManagerEmu::LoadConfig(); + // Update references in case controllers were refreshed + Wiimote::LoadConfig(); + Keyboard::LoadConfig(); + Pad::LoadConfig(); + HotkeyManagerEmu::LoadConfig(); - HotkeyManagerEmu::Enable(true); + HotkeyManagerEmu::Enable(true); - // if game isn't running - if (game_running) - { - Core::SetState(Core::CORE_RUN); - } + // if game isn't running + if (game_running) + { + Core::SetState(Core::CORE_RUN); + } - // Update the GUI in case menu accelerators were changed - UpdateGUI(); + // Update the GUI in case menu accelerators were changed + UpdateGUI(); } void CFrame::OnHelp(wxCommandEvent& event) { - switch (event.GetId()) - { - case wxID_ABOUT: - { - AboutDolphin frame(this); - HotkeyManagerEmu::Enable(false); - frame.ShowModal(); - HotkeyManagerEmu::Enable(true); - } - break; - case IDM_HELP_WEBSITE: - WxUtils::Launch("https://dolphin-emu.org/"); - break; - case IDM_HELP_ONLINE_DOCS: - WxUtils::Launch("https://dolphin-emu.org/docs/guides/"); - break; - case IDM_HELP_GITHUB: - WxUtils::Launch("https://github.com/dolphin-emu/dolphin"); - break; - } + switch (event.GetId()) + { + case wxID_ABOUT: + { + AboutDolphin frame(this); + HotkeyManagerEmu::Enable(false); + frame.ShowModal(); + HotkeyManagerEmu::Enable(true); + } + break; + case IDM_HELP_WEBSITE: + WxUtils::Launch("https://dolphin-emu.org/"); + break; + case IDM_HELP_ONLINE_DOCS: + WxUtils::Launch("https://dolphin-emu.org/docs/guides/"); + break; + case IDM_HELP_GITHUB: + WxUtils::Launch("https://github.com/dolphin-emu/dolphin"); + break; + } } void CFrame::ClearStatusBar() { - if (this->GetStatusBar()->IsEnabled()) - { - this->GetStatusBar()->SetStatusText("", 0); - } + if (this->GetStatusBar()->IsEnabled()) + { + this->GetStatusBar()->SetStatusText("", 0); + } } -void CFrame::StatusBarMessage(const char * Text, ...) +void CFrame::StatusBarMessage(const char* Text, ...) { - const int MAX_BYTES = 1024 * 10; - char Str[MAX_BYTES]; - va_list ArgPtr; - va_start(ArgPtr, Text); - vsnprintf(Str, MAX_BYTES, Text, ArgPtr); - va_end(ArgPtr); + const int MAX_BYTES = 1024 * 10; + char Str[MAX_BYTES]; + va_list ArgPtr; + va_start(ArgPtr, Text); + vsnprintf(Str, MAX_BYTES, Text, ArgPtr); + va_end(ArgPtr); - if (this->GetStatusBar()->IsEnabled()) - { - this->GetStatusBar()->SetStatusText(StrToWxStr(Str), 0); - } + if (this->GetStatusBar()->IsEnabled()) + { + this->GetStatusBar()->SetStatusText(StrToWxStr(Str), 0); + } } - // Miscellaneous menus // --------------------- // NetPlay stuff -void CFrame::OnNetPlay(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnNetPlay(wxCommandEvent& WXUNUSED(event)) { - if (!g_NetPlaySetupDiag) - { - if (NetPlayDialog::GetInstance() != nullptr) - NetPlayDialog::GetInstance()->Raise(); - else - g_NetPlaySetupDiag = new NetPlaySetupFrame(this, m_GameListCtrl); - } - else - { - g_NetPlaySetupDiag->Raise(); - } + if (!g_NetPlaySetupDiag) + { + if (NetPlayDialog::GetInstance() != nullptr) + NetPlayDialog::GetInstance()->Raise(); + else + g_NetPlaySetupDiag = new NetPlaySetupFrame(this, m_GameListCtrl); + } + else + { + g_NetPlaySetupDiag->Raise(); + } } -void CFrame::OnMemcard(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnMemcard(wxCommandEvent& WXUNUSED(event)) { - CMemcardManager MemcardManager(this); - HotkeyManagerEmu::Enable(false); - MemcardManager.ShowModal(); - HotkeyManagerEmu::Enable(true); + CMemcardManager MemcardManager(this); + HotkeyManagerEmu::Enable(false); + MemcardManager.ShowModal(); + HotkeyManagerEmu::Enable(true); } -void CFrame::OnExportAllSaves(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnExportAllSaves(wxCommandEvent& WXUNUSED(event)) { - CWiiSaveCrypted::ExportAllSaves(); + CWiiSaveCrypted::ExportAllSaves(); } -void CFrame::OnImportSave(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnImportSave(wxCommandEvent& WXUNUSED(event)) { - wxString path = wxFileSelector(_("Select the save file"), - wxEmptyString, wxEmptyString, wxEmptyString, - _("Wii save files (*.bin)") + "|*.bin|" + wxGetTranslation(wxALL_FILES), - wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, - this); + wxString path = + wxFileSelector(_("Select the save file"), wxEmptyString, wxEmptyString, wxEmptyString, + _("Wii save files (*.bin)") + "|*.bin|" + wxGetTranslation(wxALL_FILES), + wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, this); - if (!path.IsEmpty()) - CWiiSaveCrypted::ImportWiiSave(WxStrToStr(path)); + if (!path.IsEmpty()) + CWiiSaveCrypted::ImportWiiSave(WxStrToStr(path)); } -void CFrame::OnShowCheatsWindow(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnShowCheatsWindow(wxCommandEvent& WXUNUSED(event)) { - if (!g_CheatsWindow) - g_CheatsWindow = new wxCheatsWindow(this); - else - g_CheatsWindow->Raise(); + if (!g_CheatsWindow) + g_CheatsWindow = new wxCheatsWindow(this); + else + g_CheatsWindow->Raise(); } void CFrame::OnLoadWiiMenu(wxCommandEvent& WXUNUSED(event)) { - BootGame(Common::GetTitleContentPath(TITLEID_SYSMENU, Common::FROM_CONFIGURED_ROOT)); + BootGame(Common::GetTitleContentPath(TITLEID_SYSMENU, Common::FROM_CONFIGURED_ROOT)); } void CFrame::OnInstallWAD(wxCommandEvent& event) { - std::string fileName; + std::string fileName; - switch (event.GetId()) - { - case IDM_LIST_INSTALL_WAD: - { - const GameListItem *iso = m_GameListCtrl->GetSelectedISO(); - if (!iso) - return; - fileName = iso->GetFileName(); - break; - } - case IDM_MENU_INSTALL_WAD: - { - wxString path = wxFileSelector( - _("Select a Wii WAD file to install"), - wxEmptyString, wxEmptyString, wxEmptyString, - _("Wii WAD files (*.wad)") + "|*.wad|" + wxGetTranslation(wxALL_FILES), - wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, - this); - fileName = WxStrToStr(path); - break; - } - default: - return; - } + switch (event.GetId()) + { + case IDM_LIST_INSTALL_WAD: + { + const GameListItem* iso = m_GameListCtrl->GetSelectedISO(); + if (!iso) + return; + fileName = iso->GetFileName(); + break; + } + case IDM_MENU_INSTALL_WAD: + { + wxString path = wxFileSelector( + _("Select a Wii WAD file to install"), wxEmptyString, wxEmptyString, wxEmptyString, + _("Wii WAD files (*.wad)") + "|*.wad|" + wxGetTranslation(wxALL_FILES), + wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, this); + fileName = WxStrToStr(path); + break; + } + default: + return; + } - wxProgressDialog dialog(_("Installing WAD..."), - _("Working..."), - 1000, - this, - wxPD_APP_MODAL | - wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | - wxPD_SMOOTH - ); + wxProgressDialog dialog(_("Installing WAD..."), _("Working..."), 1000, this, + wxPD_APP_MODAL | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | + wxPD_REMAINING_TIME | wxPD_SMOOTH); - u64 titleID = DiscIO::CNANDContentManager::Access().Install_WiiWAD(fileName); - if (titleID == TITLEID_SYSMENU) - { - UpdateWiiMenuChoice(); - } + u64 titleID = DiscIO::CNANDContentManager::Access().Install_WiiWAD(fileName); + if (titleID == TITLEID_SYSMENU) + { + UpdateWiiMenuChoice(); + } } - -void CFrame::UpdateWiiMenuChoice(wxMenuItem *WiiMenuItem) +void CFrame::UpdateWiiMenuChoice(wxMenuItem* WiiMenuItem) { - if (!WiiMenuItem) - { - WiiMenuItem = GetMenuBar()->FindItem(IDM_LOAD_WII_MENU); - } + if (!WiiMenuItem) + { + WiiMenuItem = GetMenuBar()->FindItem(IDM_LOAD_WII_MENU); + } - const DiscIO::CNANDContentLoader & SysMenu_Loader = DiscIO::CNANDContentManager::Access().GetNANDLoader(TITLEID_SYSMENU, Common::FROM_CONFIGURED_ROOT); - if (SysMenu_Loader.IsValid()) - { - int sysmenuVersion = SysMenu_Loader.GetTitleVersion(); - char sysmenuRegion = SysMenu_Loader.GetCountryChar(); - WiiMenuItem->Enable(); - WiiMenuItem->SetItemLabel(wxString::Format(_("Load Wii System Menu %d%c"), sysmenuVersion, sysmenuRegion)); - } - else - { - WiiMenuItem->Enable(false); - WiiMenuItem->SetItemLabel(_("Load Wii System Menu")); - } + const DiscIO::CNANDContentLoader& SysMenu_Loader = + DiscIO::CNANDContentManager::Access().GetNANDLoader(TITLEID_SYSMENU, + Common::FROM_CONFIGURED_ROOT); + if (SysMenu_Loader.IsValid()) + { + int sysmenuVersion = SysMenu_Loader.GetTitleVersion(); + char sysmenuRegion = SysMenu_Loader.GetCountryChar(); + WiiMenuItem->Enable(); + WiiMenuItem->SetItemLabel( + wxString::Format(_("Load Wii System Menu %d%c"), sysmenuVersion, sysmenuRegion)); + } + else + { + WiiMenuItem->Enable(false); + WiiMenuItem->SetItemLabel(_("Load Wii System Menu")); + } } -void CFrame::OnFifoPlayer(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnFifoPlayer(wxCommandEvent& WXUNUSED(event)) { - if (m_FifoPlayerDlg) - { - m_FifoPlayerDlg->Show(); - m_FifoPlayerDlg->SetFocus(); - } - else - { - m_FifoPlayerDlg = new FifoPlayerDlg(this); - } + if (m_FifoPlayerDlg) + { + m_FifoPlayerDlg->Show(); + m_FifoPlayerDlg->SetFocus(); + } + else + { + m_FifoPlayerDlg = new FifoPlayerDlg(this); + } } void CFrame::ConnectWiimote(int wm_idx, bool connect) { - if (Core::IsRunning() && SConfig::GetInstance().bWii) - { - bool was_unpaused = Core::PauseAndLock(true); - GetUsbPointer()->AccessWiiMote(wm_idx | 0x100)->Activate(connect); - wxString msg(wxString::Format(_("Wiimote %i %s"), wm_idx + 1, - connect ? _("Connected") : _("Disconnected"))); - Core::DisplayMessage(WxStrToStr(msg), 3000); - Host_UpdateMainFrame(); - Core::PauseAndLock(false, was_unpaused); - } + if (Core::IsRunning() && SConfig::GetInstance().bWii) + { + bool was_unpaused = Core::PauseAndLock(true); + GetUsbPointer()->AccessWiiMote(wm_idx | 0x100)->Activate(connect); + wxString msg(wxString::Format(_("Wiimote %i %s"), wm_idx + 1, + connect ? _("Connected") : _("Disconnected"))); + Core::DisplayMessage(WxStrToStr(msg), 3000); + Host_UpdateMainFrame(); + Core::PauseAndLock(false, was_unpaused); + } } void CFrame::OnConnectWiimote(wxCommandEvent& event) { - bool was_unpaused = Core::PauseAndLock(true); - ConnectWiimote(event.GetId() - IDM_CONNECT_WIIMOTE1, !GetUsbPointer()->AccessWiiMote((event.GetId() - IDM_CONNECT_WIIMOTE1) | 0x100)->IsConnected()); - Core::PauseAndLock(false, was_unpaused); + bool was_unpaused = Core::PauseAndLock(true); + ConnectWiimote(event.GetId() - IDM_CONNECT_WIIMOTE1, + !GetUsbPointer() + ->AccessWiiMote((event.GetId() - IDM_CONNECT_WIIMOTE1) | 0x100) + ->IsConnected()); + Core::PauseAndLock(false, was_unpaused); } -// Toggle fullscreen. In Windows the fullscreen mode is accomplished by expanding the m_Panel to cover +// Toggle fullscreen. In Windows the fullscreen mode is accomplished by expanding the m_Panel to +// cover // the entire screen (when we render to the main window). -void CFrame::OnToggleFullscreen(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnToggleFullscreen(wxCommandEvent& WXUNUSED(event)) { - DoFullscreen(!RendererIsFullscreen()); + DoFullscreen(!RendererIsFullscreen()); } -void CFrame::OnToggleDualCore(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnToggleDualCore(wxCommandEvent& WXUNUSED(event)) { - SConfig::GetInstance().bCPUThread = !SConfig::GetInstance().bCPUThread; - SConfig::GetInstance().SaveSettings(); + SConfig::GetInstance().bCPUThread = !SConfig::GetInstance().bCPUThread; + SConfig::GetInstance().SaveSettings(); } -void CFrame::OnToggleSkipIdle(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnToggleSkipIdle(wxCommandEvent& WXUNUSED(event)) { - SConfig::GetInstance().bSkipIdle = !SConfig::GetInstance().bSkipIdle; - SConfig::GetInstance().SaveSettings(); + SConfig::GetInstance().bSkipIdle = !SConfig::GetInstance().bSkipIdle; + SConfig::GetInstance().SaveSettings(); } -void CFrame::OnLoadStateFromFile(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnLoadStateFromFile(wxCommandEvent& WXUNUSED(event)) { - wxString path = wxFileSelector( - _("Select the state to load"), - wxEmptyString, wxEmptyString, wxEmptyString, - _("All Save States (sav, s##)") + - wxString::Format("|*.sav;*.s??|%s", wxGetTranslation(wxALL_FILES)), - wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, - this); + wxString path = + wxFileSelector(_("Select the state to load"), wxEmptyString, wxEmptyString, wxEmptyString, + _("All Save States (sav, s##)") + + wxString::Format("|*.sav;*.s??|%s", wxGetTranslation(wxALL_FILES)), + wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, this); - if (!path.IsEmpty()) - State::LoadAs(WxStrToStr(path)); + if (!path.IsEmpty()) + State::LoadAs(WxStrToStr(path)); } -void CFrame::OnSaveStateToFile(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnSaveStateToFile(wxCommandEvent& WXUNUSED(event)) { - wxString path = wxFileSelector( - _("Select the state to save"), - wxEmptyString, wxEmptyString, wxEmptyString, - _("All Save States (sav, s##)") + - wxString::Format("|*.sav;*.s??|%s", wxGetTranslation(wxALL_FILES)), - wxFD_SAVE, - this); + wxString path = + wxFileSelector(_("Select the state to save"), wxEmptyString, wxEmptyString, wxEmptyString, + _("All Save States (sav, s##)") + + wxString::Format("|*.sav;*.s??|%s", wxGetTranslation(wxALL_FILES)), + wxFD_SAVE, this); - if (!path.IsEmpty()) - State::SaveAs(WxStrToStr(path)); + if (!path.IsEmpty()) + State::SaveAs(WxStrToStr(path)); } void CFrame::OnLoadLastState(wxCommandEvent& event) { - if (Core::IsRunningAndStarted()) - { - int id = event.GetId(); - int slot = id - IDM_LOAD_LAST_1 + 1; - State::LoadLastSaved(slot); - } + if (Core::IsRunningAndStarted()) + { + int id = event.GetId(); + int slot = id - IDM_LOAD_LAST_1 + 1; + State::LoadLastSaved(slot); + } } void CFrame::OnSaveFirstState(wxCommandEvent& WXUNUSED(event)) { - if (Core::IsRunningAndStarted()) - State::SaveFirstSaved(); + if (Core::IsRunningAndStarted()) + State::SaveFirstSaved(); } -void CFrame::OnUndoLoadState(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnUndoLoadState(wxCommandEvent& WXUNUSED(event)) { - if (Core::IsRunningAndStarted()) - State::UndoLoadState(); + if (Core::IsRunningAndStarted()) + State::UndoLoadState(); } -void CFrame::OnUndoSaveState(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnUndoSaveState(wxCommandEvent& WXUNUSED(event)) { - if (Core::IsRunningAndStarted()) - State::UndoSaveState(); + if (Core::IsRunningAndStarted()) + State::UndoSaveState(); } - void CFrame::OnLoadState(wxCommandEvent& event) { - if (Core::IsRunningAndStarted()) - { - int id = event.GetId(); - int slot = id - IDM_LOAD_SLOT_1 + 1; - State::Load(slot); - } + if (Core::IsRunningAndStarted()) + { + int id = event.GetId(); + int slot = id - IDM_LOAD_SLOT_1 + 1; + State::Load(slot); + } } void CFrame::OnSaveState(wxCommandEvent& event) { - if (Core::IsRunningAndStarted()) - { - int id = event.GetId(); - int slot = id - IDM_SAVE_SLOT_1 + 1; - State::Save(slot); - } + if (Core::IsRunningAndStarted()) + { + int id = event.GetId(); + int slot = id - IDM_SAVE_SLOT_1 + 1; + State::Save(slot); + } } void CFrame::OnFrameSkip(wxCommandEvent& event) { - int amount = event.GetId() - IDM_FRAME_SKIP_0; + int amount = event.GetId() - IDM_FRAME_SKIP_0; - Movie::SetFrameSkipping((unsigned int)amount); - SConfig::GetInstance().m_FrameSkip = amount; + Movie::SetFrameSkipping((unsigned int)amount); + SConfig::GetInstance().m_FrameSkip = amount; } void CFrame::OnSelectSlot(wxCommandEvent& event) { - g_saveSlot = event.GetId() - IDM_SELECT_SLOT_1 + 1; - Core::DisplayMessage(StringFromFormat("Selected slot %d - %s", g_saveSlot, State::GetInfoStringOfSlot(g_saveSlot).c_str()), 2500); + g_saveSlot = event.GetId() - IDM_SELECT_SLOT_1 + 1; + Core::DisplayMessage(StringFromFormat("Selected slot %d - %s", g_saveSlot, + State::GetInfoStringOfSlot(g_saveSlot).c_str()), + 2500); } void CFrame::OnLoadCurrentSlot(wxCommandEvent& event) { - if (Core::IsRunningAndStarted()) - { - State::Load(g_saveSlot); - } + if (Core::IsRunningAndStarted()) + { + State::Load(g_saveSlot); + } } void CFrame::OnSaveCurrentSlot(wxCommandEvent& event) { - if (Core::IsRunningAndStarted()) - { - State::Save(g_saveSlot); - } + if (Core::IsRunningAndStarted()) + { + State::Save(g_saveSlot); + } } - - // GUI // --------------------- // Update the enabled/disabled status void CFrame::UpdateGUI() { - // Save status - bool Initialized = Core::IsRunning(); - bool Running = Core::GetState() == Core::CORE_RUN; - bool Paused = Core::GetState() == Core::CORE_PAUSE; - bool Stopping = Core::GetState() == Core::CORE_STOPPING; - bool RunningWii = Initialized && SConfig::GetInstance().bWii; + // Save status + bool Initialized = Core::IsRunning(); + bool Running = Core::GetState() == Core::CORE_RUN; + bool Paused = Core::GetState() == Core::CORE_PAUSE; + bool Stopping = Core::GetState() == Core::CORE_STOPPING; + bool RunningWii = Initialized && SConfig::GetInstance().bWii; - // Make sure that we have a toolbar - if (m_ToolBar) - { - // Enable/disable the Config and Stop buttons - m_ToolBar->EnableTool(wxID_OPEN, !Initialized); - // Don't allow refresh when we don't show the list - m_ToolBar->EnableTool(wxID_REFRESH, !Initialized); - m_ToolBar->EnableTool(IDM_STOP, Running || Paused); - m_ToolBar->EnableTool(IDM_TOGGLE_FULLSCREEN, Running || Paused); - m_ToolBar->EnableTool(IDM_SCREENSHOT, Running || Paused); - } + // Make sure that we have a toolbar + if (m_ToolBar) + { + // Enable/disable the Config and Stop buttons + m_ToolBar->EnableTool(wxID_OPEN, !Initialized); + // Don't allow refresh when we don't show the list + m_ToolBar->EnableTool(wxID_REFRESH, !Initialized); + m_ToolBar->EnableTool(IDM_STOP, Running || Paused); + m_ToolBar->EnableTool(IDM_TOGGLE_FULLSCREEN, Running || Paused); + m_ToolBar->EnableTool(IDM_SCREENSHOT, Running || Paused); + } - // File - GetMenuBar()->FindItem(wxID_OPEN)->Enable(!Initialized); - GetMenuBar()->FindItem(IDM_DRIVES)->Enable(!Initialized); - GetMenuBar()->FindItem(wxID_REFRESH)->Enable(!Initialized); + // File + GetMenuBar()->FindItem(wxID_OPEN)->Enable(!Initialized); + GetMenuBar()->FindItem(IDM_DRIVES)->Enable(!Initialized); + GetMenuBar()->FindItem(wxID_REFRESH)->Enable(!Initialized); - // Emulation - GetMenuBar()->FindItem(IDM_STOP)->Enable(Running || Paused); - GetMenuBar()->FindItem(IDM_RESET)->Enable(Running || Paused); - GetMenuBar()->FindItem(IDM_RECORD)->Enable(!Movie::IsRecordingInput()); - GetMenuBar()->FindItem(IDM_PLAY_RECORD)->Enable(!Initialized); - GetMenuBar()->FindItem(IDM_RECORD_EXPORT)->Enable(Movie::IsMovieActive()); - GetMenuBar()->FindItem(IDM_FRAMESTEP)->Enable(Running || Paused); - GetMenuBar()->FindItem(IDM_SCREENSHOT)->Enable(Running || Paused); - GetMenuBar()->FindItem(IDM_TOGGLE_FULLSCREEN)->Enable(Running || Paused); + // Emulation + GetMenuBar()->FindItem(IDM_STOP)->Enable(Running || Paused); + GetMenuBar()->FindItem(IDM_RESET)->Enable(Running || Paused); + GetMenuBar()->FindItem(IDM_RECORD)->Enable(!Movie::IsRecordingInput()); + GetMenuBar()->FindItem(IDM_PLAY_RECORD)->Enable(!Initialized); + GetMenuBar()->FindItem(IDM_RECORD_EXPORT)->Enable(Movie::IsMovieActive()); + GetMenuBar()->FindItem(IDM_FRAMESTEP)->Enable(Running || Paused); + GetMenuBar()->FindItem(IDM_SCREENSHOT)->Enable(Running || Paused); + GetMenuBar()->FindItem(IDM_TOGGLE_FULLSCREEN)->Enable(Running || Paused); - // Update Key Shortcuts - for (unsigned int i = 0; i < NUM_HOTKEYS; i++) - { - if (GetCmdForHotkey(i) == -1) - continue; - if (GetMenuBar()->FindItem(GetCmdForHotkey(i))) - GetMenuBar()->FindItem(GetCmdForHotkey(i))->SetItemLabel(GetMenuLabel(i)); - } + // Update Key Shortcuts + for (unsigned int i = 0; i < NUM_HOTKEYS; i++) + { + if (GetCmdForHotkey(i) == -1) + continue; + if (GetMenuBar()->FindItem(GetCmdForHotkey(i))) + GetMenuBar()->FindItem(GetCmdForHotkey(i))->SetItemLabel(GetMenuLabel(i)); + } - GetMenuBar()->FindItem(IDM_LOAD_STATE)->Enable(Initialized); - GetMenuBar()->FindItem(IDM_SAVE_STATE)->Enable(Initialized); - // Misc - GetMenuBar()->FindItem(IDM_CHANGE_DISC)->Enable(Initialized); - if (DiscIO::CNANDContentManager::Access().GetNANDLoader(TITLEID_SYSMENU, Common::FROM_CONFIGURED_ROOT).IsValid()) - GetMenuBar()->FindItem(IDM_LOAD_WII_MENU)->Enable(!Initialized); + GetMenuBar()->FindItem(IDM_LOAD_STATE)->Enable(Initialized); + GetMenuBar()->FindItem(IDM_SAVE_STATE)->Enable(Initialized); + // Misc + GetMenuBar()->FindItem(IDM_CHANGE_DISC)->Enable(Initialized); + if (DiscIO::CNANDContentManager::Access() + .GetNANDLoader(TITLEID_SYSMENU, Common::FROM_CONFIGURED_ROOT) + .IsValid()) + GetMenuBar()->FindItem(IDM_LOAD_WII_MENU)->Enable(!Initialized); - // Tools - GetMenuBar()->FindItem(IDM_CHEATS)->Enable(SConfig::GetInstance().bEnableCheats); + // Tools + GetMenuBar()->FindItem(IDM_CHEATS)->Enable(SConfig::GetInstance().bEnableCheats); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)->Enable(RunningWii); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE2)->Enable(RunningWii); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE3)->Enable(RunningWii); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE4)->Enable(RunningWii); - GetMenuBar()->FindItem(IDM_CONNECT_BALANCEBOARD)->Enable(RunningWii); - if (RunningWii) - { - bool was_unpaused = Core::PauseAndLock(true); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)->Check(GetUsbPointer()-> - AccessWiiMote(0x0100)->IsConnected()); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE2)->Check(GetUsbPointer()-> - AccessWiiMote(0x0101)->IsConnected()); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE3)->Check(GetUsbPointer()-> - AccessWiiMote(0x0102)->IsConnected()); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE4)->Check(GetUsbPointer()-> - AccessWiiMote(0x0103)->IsConnected()); - GetMenuBar()->FindItem(IDM_CONNECT_BALANCEBOARD)->Check(GetUsbPointer()-> - AccessWiiMote(0x0104)->IsConnected()); - Core::PauseAndLock(false, was_unpaused); - } + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)->Enable(RunningWii); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE2)->Enable(RunningWii); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE3)->Enable(RunningWii); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE4)->Enable(RunningWii); + GetMenuBar()->FindItem(IDM_CONNECT_BALANCEBOARD)->Enable(RunningWii); + if (RunningWii) + { + bool was_unpaused = Core::PauseAndLock(true); + GetMenuBar() + ->FindItem(IDM_CONNECT_WIIMOTE1) + ->Check(GetUsbPointer()->AccessWiiMote(0x0100)->IsConnected()); + GetMenuBar() + ->FindItem(IDM_CONNECT_WIIMOTE2) + ->Check(GetUsbPointer()->AccessWiiMote(0x0101)->IsConnected()); + GetMenuBar() + ->FindItem(IDM_CONNECT_WIIMOTE3) + ->Check(GetUsbPointer()->AccessWiiMote(0x0102)->IsConnected()); + GetMenuBar() + ->FindItem(IDM_CONNECT_WIIMOTE4) + ->Check(GetUsbPointer()->AccessWiiMote(0x0103)->IsConnected()); + GetMenuBar() + ->FindItem(IDM_CONNECT_BALANCEBOARD) + ->Check(GetUsbPointer()->AccessWiiMote(0x0104)->IsConnected()); + Core::PauseAndLock(false, was_unpaused); + } - if (m_ToolBar) - { - // Get the tool that controls pausing/playing - wxToolBarToolBase * PlayTool = m_ToolBar->FindById(IDM_PLAY); + if (m_ToolBar) + { + // Get the tool that controls pausing/playing + wxToolBarToolBase* PlayTool = m_ToolBar->FindById(IDM_PLAY); - if (PlayTool) - { - int position = m_ToolBar->GetToolPos(IDM_PLAY); + if (PlayTool) + { + int position = m_ToolBar->GetToolPos(IDM_PLAY); - if (Running) - { - m_ToolBar->DeleteTool(IDM_PLAY); - m_ToolBar->InsertTool(position, IDM_PLAY, _("Pause"), m_Bitmaps[Toolbar_Pause], - WxUtils::CreateDisabledButtonBitmap(m_Bitmaps[Toolbar_Pause]), - wxITEM_NORMAL, _("Pause")); - } - else - { - m_ToolBar->DeleteTool(IDM_PLAY); - m_ToolBar->InsertTool(position, IDM_PLAY, _("Play"), m_Bitmaps[Toolbar_Play], - WxUtils::CreateDisabledButtonBitmap(m_Bitmaps[Toolbar_Play]), - wxITEM_NORMAL, _("Play")); - } - m_ToolBar->Realize(); - } - } + if (Running) + { + m_ToolBar->DeleteTool(IDM_PLAY); + m_ToolBar->InsertTool(position, IDM_PLAY, _("Pause"), m_Bitmaps[Toolbar_Pause], + WxUtils::CreateDisabledButtonBitmap(m_Bitmaps[Toolbar_Pause]), + wxITEM_NORMAL, _("Pause")); + } + else + { + m_ToolBar->DeleteTool(IDM_PLAY); + m_ToolBar->InsertTool(position, IDM_PLAY, _("Play"), m_Bitmaps[Toolbar_Play], + WxUtils::CreateDisabledButtonBitmap(m_Bitmaps[Toolbar_Play]), + wxITEM_NORMAL, _("Play")); + } + m_ToolBar->Realize(); + } + } - GetMenuBar()->FindItem(IDM_RECORD_READ_ONLY)->Enable(Running || Paused); + GetMenuBar()->FindItem(IDM_RECORD_READ_ONLY)->Enable(Running || Paused); - if (!Initialized && !m_bGameLoading) - { - if (m_GameListCtrl->IsEnabled()) - { - // Prepare to load Default ISO, enable play button - if (!SConfig::GetInstance().m_strDefaultISO.empty()) - { - if (m_ToolBar) - m_ToolBar->EnableTool(IDM_PLAY, true); - GetMenuBar()->FindItem(IDM_PLAY)->Enable(); - GetMenuBar()->FindItem(IDM_RECORD)->Enable(); - GetMenuBar()->FindItem(IDM_PLAY_RECORD)->Enable(); - } - // Prepare to load last selected file, enable play button - else if (!SConfig::GetInstance().m_LastFilename.empty() && - File::Exists(SConfig::GetInstance().m_LastFilename)) - { - if (m_ToolBar) - m_ToolBar->EnableTool(IDM_PLAY, true); - GetMenuBar()->FindItem(IDM_PLAY)->Enable(); - GetMenuBar()->FindItem(IDM_RECORD)->Enable(); - GetMenuBar()->FindItem(IDM_PLAY_RECORD)->Enable(); - } - else - { - // No game has been selected yet, disable play button - if (m_ToolBar) - m_ToolBar->EnableTool(IDM_PLAY, false); - GetMenuBar()->FindItem(IDM_PLAY)->Enable(false); - GetMenuBar()->FindItem(IDM_RECORD)->Enable(false); - GetMenuBar()->FindItem(IDM_PLAY_RECORD)->Enable(false); - } - } + if (!Initialized && !m_bGameLoading) + { + if (m_GameListCtrl->IsEnabled()) + { + // Prepare to load Default ISO, enable play button + if (!SConfig::GetInstance().m_strDefaultISO.empty()) + { + if (m_ToolBar) + m_ToolBar->EnableTool(IDM_PLAY, true); + GetMenuBar()->FindItem(IDM_PLAY)->Enable(); + GetMenuBar()->FindItem(IDM_RECORD)->Enable(); + GetMenuBar()->FindItem(IDM_PLAY_RECORD)->Enable(); + } + // Prepare to load last selected file, enable play button + else if (!SConfig::GetInstance().m_LastFilename.empty() && + File::Exists(SConfig::GetInstance().m_LastFilename)) + { + if (m_ToolBar) + m_ToolBar->EnableTool(IDM_PLAY, true); + GetMenuBar()->FindItem(IDM_PLAY)->Enable(); + GetMenuBar()->FindItem(IDM_RECORD)->Enable(); + GetMenuBar()->FindItem(IDM_PLAY_RECORD)->Enable(); + } + else + { + // No game has been selected yet, disable play button + if (m_ToolBar) + m_ToolBar->EnableTool(IDM_PLAY, false); + GetMenuBar()->FindItem(IDM_PLAY)->Enable(false); + GetMenuBar()->FindItem(IDM_RECORD)->Enable(false); + GetMenuBar()->FindItem(IDM_PLAY_RECORD)->Enable(false); + } + } - // Game has not started, show game list - if (!m_GameListCtrl->IsShown()) - { - m_GameListCtrl->Enable(); - m_GameListCtrl->Show(); - } - // Game has been selected but not started, enable play button - if (m_GameListCtrl->GetSelectedISO() != nullptr && m_GameListCtrl->IsEnabled()) - { - if (m_ToolBar) - m_ToolBar->EnableTool(IDM_PLAY, true); - GetMenuBar()->FindItem(IDM_PLAY)->Enable(); - GetMenuBar()->FindItem(IDM_RECORD)->Enable(); - GetMenuBar()->FindItem(IDM_PLAY_RECORD)->Enable(); - } - } - else if (Initialized) - { - // Game has been loaded, enable the pause button - if (m_ToolBar) - m_ToolBar->EnableTool(IDM_PLAY, !Stopping); - GetMenuBar()->FindItem(IDM_PLAY)->Enable(!Stopping); + // Game has not started, show game list + if (!m_GameListCtrl->IsShown()) + { + m_GameListCtrl->Enable(); + m_GameListCtrl->Show(); + } + // Game has been selected but not started, enable play button + if (m_GameListCtrl->GetSelectedISO() != nullptr && m_GameListCtrl->IsEnabled()) + { + if (m_ToolBar) + m_ToolBar->EnableTool(IDM_PLAY, true); + GetMenuBar()->FindItem(IDM_PLAY)->Enable(); + GetMenuBar()->FindItem(IDM_RECORD)->Enable(); + GetMenuBar()->FindItem(IDM_PLAY_RECORD)->Enable(); + } + } + else if (Initialized) + { + // Game has been loaded, enable the pause button + if (m_ToolBar) + m_ToolBar->EnableTool(IDM_PLAY, !Stopping); + GetMenuBar()->FindItem(IDM_PLAY)->Enable(!Stopping); - // Reset game loading flag - m_bGameLoading = false; - } + // Reset game loading flag + m_bGameLoading = false; + } - // Refresh toolbar - if (m_ToolBar) - { - m_ToolBar->Refresh(); - } + // Refresh toolbar + if (m_ToolBar) + { + m_ToolBar->Refresh(); + } - // Commit changes to manager - m_Mgr->Update(); + // Commit changes to manager + m_Mgr->Update(); - // Update non-modal windows - if (g_CheatsWindow) - { - if (SConfig::GetInstance().bEnableCheats) - g_CheatsWindow->UpdateGUI(); - else - g_CheatsWindow->Close(); - } + // Update non-modal windows + if (g_CheatsWindow) + { + if (SConfig::GetInstance().bEnableCheats) + g_CheatsWindow->UpdateGUI(); + else + g_CheatsWindow->Close(); + } } void CFrame::UpdateGameList() { - m_GameListCtrl->Update(); + m_GameListCtrl->Update(); } void CFrame::GameListChanged(wxCommandEvent& event) { - switch (event.GetId()) - { - case IDM_LIST_WII: - SConfig::GetInstance().m_ListWii = event.IsChecked(); - break; - case IDM_LIST_GC: - SConfig::GetInstance().m_ListGC = event.IsChecked(); - break; - case IDM_LIST_WAD: - SConfig::GetInstance().m_ListWad = event.IsChecked(); - break; - case IDM_LIST_ELFDOL: - SConfig::GetInstance().m_ListElfDol = event.IsChecked(); - break; - case IDM_LIST_JAP: - SConfig::GetInstance().m_ListJap = event.IsChecked(); - break; - case IDM_LIST_PAL: - SConfig::GetInstance().m_ListPal = event.IsChecked(); - break; - case IDM_LIST_USA: - SConfig::GetInstance().m_ListUsa = event.IsChecked(); - break; - case IDM_LIST_AUSTRALIA: - SConfig::GetInstance().m_ListAustralia = event.IsChecked(); - break; - case IDM_LIST_FRANCE: - SConfig::GetInstance().m_ListFrance = event.IsChecked(); - break; - case IDM_LIST_GERMANY: - SConfig::GetInstance().m_ListGermany = event.IsChecked(); - break; - case IDM_LIST_ITALY: - SConfig::GetInstance().m_ListItaly = event.IsChecked(); - break; - case IDM_LIST_KOREA: - SConfig::GetInstance().m_ListKorea = event.IsChecked(); - break; - case IDM_LIST_NETHERLANDS: - SConfig::GetInstance().m_ListNetherlands = event.IsChecked(); - break; - case IDM_LIST_RUSSIA: - SConfig::GetInstance().m_ListRussia = event.IsChecked(); - break; - case IDM_LIST_SPAIN: - SConfig::GetInstance().m_ListSpain = event.IsChecked(); - break; - case IDM_LIST_TAIWAN: - SConfig::GetInstance().m_ListTaiwan = event.IsChecked(); - break; - case IDM_LIST_WORLD: - SConfig::GetInstance().m_ListWorld = event.IsChecked(); - break; - case IDM_LIST_UNKNOWN: - SConfig::GetInstance().m_ListUnknown = event.IsChecked(); - break; - case IDM_LIST_DRIVES: - SConfig::GetInstance().m_ListDrives = event.IsChecked(); - break; - case IDM_PURGE_GAME_LIST_CACHE: - std::vector rFilenames = DoFileSearch({".cache"}, {File::GetUserPath(D_CACHE_IDX)}); + switch (event.GetId()) + { + case IDM_LIST_WII: + SConfig::GetInstance().m_ListWii = event.IsChecked(); + break; + case IDM_LIST_GC: + SConfig::GetInstance().m_ListGC = event.IsChecked(); + break; + case IDM_LIST_WAD: + SConfig::GetInstance().m_ListWad = event.IsChecked(); + break; + case IDM_LIST_ELFDOL: + SConfig::GetInstance().m_ListElfDol = event.IsChecked(); + break; + case IDM_LIST_JAP: + SConfig::GetInstance().m_ListJap = event.IsChecked(); + break; + case IDM_LIST_PAL: + SConfig::GetInstance().m_ListPal = event.IsChecked(); + break; + case IDM_LIST_USA: + SConfig::GetInstance().m_ListUsa = event.IsChecked(); + break; + case IDM_LIST_AUSTRALIA: + SConfig::GetInstance().m_ListAustralia = event.IsChecked(); + break; + case IDM_LIST_FRANCE: + SConfig::GetInstance().m_ListFrance = event.IsChecked(); + break; + case IDM_LIST_GERMANY: + SConfig::GetInstance().m_ListGermany = event.IsChecked(); + break; + case IDM_LIST_ITALY: + SConfig::GetInstance().m_ListItaly = event.IsChecked(); + break; + case IDM_LIST_KOREA: + SConfig::GetInstance().m_ListKorea = event.IsChecked(); + break; + case IDM_LIST_NETHERLANDS: + SConfig::GetInstance().m_ListNetherlands = event.IsChecked(); + break; + case IDM_LIST_RUSSIA: + SConfig::GetInstance().m_ListRussia = event.IsChecked(); + break; + case IDM_LIST_SPAIN: + SConfig::GetInstance().m_ListSpain = event.IsChecked(); + break; + case IDM_LIST_TAIWAN: + SConfig::GetInstance().m_ListTaiwan = event.IsChecked(); + break; + case IDM_LIST_WORLD: + SConfig::GetInstance().m_ListWorld = event.IsChecked(); + break; + case IDM_LIST_UNKNOWN: + SConfig::GetInstance().m_ListUnknown = event.IsChecked(); + break; + case IDM_LIST_DRIVES: + SConfig::GetInstance().m_ListDrives = event.IsChecked(); + break; + case IDM_PURGE_GAME_LIST_CACHE: + std::vector rFilenames = + DoFileSearch({".cache"}, {File::GetUserPath(D_CACHE_IDX)}); - for (const std::string& rFilename : rFilenames) - { - File::Delete(rFilename); - } - break; - } + for (const std::string& rFilename : rFilenames) + { + File::Delete(rFilename); + } + break; + } - // Update gamelist - if (m_GameListCtrl) - { - m_GameListCtrl->Update(); - } + // Update gamelist + if (m_GameListCtrl) + { + m_GameListCtrl->Update(); + } } // Enable and disable the toolbar void CFrame::OnToggleToolbar(wxCommandEvent& event) { - SConfig::GetInstance().m_InterfaceToolbar = event.IsChecked(); - DoToggleToolbar(event.IsChecked()); + SConfig::GetInstance().m_InterfaceToolbar = event.IsChecked(); + DoToggleToolbar(event.IsChecked()); } void CFrame::DoToggleToolbar(bool _show) { - GetToolBar()->Show(_show); - m_Mgr->Update(); + GetToolBar()->Show(_show); + m_Mgr->Update(); } // Enable and disable the status bar void CFrame::OnToggleStatusbar(wxCommandEvent& event) { - SConfig::GetInstance().m_InterfaceStatusbar = event.IsChecked(); + SConfig::GetInstance().m_InterfaceStatusbar = event.IsChecked(); - GetStatusBar()->Show(event.IsChecked()); + GetStatusBar()->Show(event.IsChecked()); - SendSizeEvent(); + SendSizeEvent(); } void CFrame::OnChangeColumnsVisible(wxCommandEvent& event) { - switch (event.GetId()) - { - case IDM_SHOW_SYSTEM: - SConfig::GetInstance().m_showSystemColumn = !SConfig::GetInstance().m_showSystemColumn; - break; - case IDM_SHOW_BANNER: - SConfig::GetInstance().m_showBannerColumn = !SConfig::GetInstance().m_showBannerColumn; - break; - case IDM_SHOW_MAKER: - SConfig::GetInstance().m_showMakerColumn = !SConfig::GetInstance().m_showMakerColumn; - break; - case IDM_SHOW_FILENAME: - SConfig::GetInstance().m_showFileNameColumn = !SConfig::GetInstance().m_showFileNameColumn; - break; - case IDM_SHOW_ID: - SConfig::GetInstance().m_showIDColumn = !SConfig::GetInstance().m_showIDColumn; - break; - case IDM_SHOW_REGION: - SConfig::GetInstance().m_showRegionColumn = !SConfig::GetInstance().m_showRegionColumn; - break; - case IDM_SHOW_SIZE: - SConfig::GetInstance().m_showSizeColumn = !SConfig::GetInstance().m_showSizeColumn; - break; - case IDM_SHOW_STATE: - SConfig::GetInstance().m_showStateColumn = !SConfig::GetInstance().m_showStateColumn; - break; - default: return; - } - m_GameListCtrl->Update(); - SConfig::GetInstance().SaveSettings(); + switch (event.GetId()) + { + case IDM_SHOW_SYSTEM: + SConfig::GetInstance().m_showSystemColumn = !SConfig::GetInstance().m_showSystemColumn; + break; + case IDM_SHOW_BANNER: + SConfig::GetInstance().m_showBannerColumn = !SConfig::GetInstance().m_showBannerColumn; + break; + case IDM_SHOW_MAKER: + SConfig::GetInstance().m_showMakerColumn = !SConfig::GetInstance().m_showMakerColumn; + break; + case IDM_SHOW_FILENAME: + SConfig::GetInstance().m_showFileNameColumn = !SConfig::GetInstance().m_showFileNameColumn; + break; + case IDM_SHOW_ID: + SConfig::GetInstance().m_showIDColumn = !SConfig::GetInstance().m_showIDColumn; + break; + case IDM_SHOW_REGION: + SConfig::GetInstance().m_showRegionColumn = !SConfig::GetInstance().m_showRegionColumn; + break; + case IDM_SHOW_SIZE: + SConfig::GetInstance().m_showSizeColumn = !SConfig::GetInstance().m_showSizeColumn; + break; + case IDM_SHOW_STATE: + SConfig::GetInstance().m_showStateColumn = !SConfig::GetInstance().m_showStateColumn; + break; + default: + return; + } + m_GameListCtrl->Update(); + SConfig::GetInstance().SaveSettings(); } diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp index ef2ca15d18..db2eede260 100644 --- a/Source/Core/DolphinWX/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/GameListCtrl.cpp @@ -38,12 +38,12 @@ #include "Common/MathUtil.h" #include "Common/StringUtil.h" #include "Common/SysConf.h" +#include "Core/Boot/Boot.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/Movie.h" -#include "Core/Boot/Boot.h" #include "Core/HW/DVDInterface.h" #include "Core/HW/WiiSaveCrypted.h" +#include "Core/Movie.h" #include "DiscIO/Blob.h" #include "DiscIO/Volume.h" #include "DiscIO/VolumeCreator.h" @@ -58,14 +58,17 @@ struct CompressionProgress final { public: - CompressionProgress(int items_done_, int items_total_, const std::string& current_filename_, wxProgressDialog* dialog_) - : items_done(items_done_), items_total(items_total_), current_filename(current_filename_), dialog(dialog_) - { } + CompressionProgress(int items_done_, int items_total_, const std::string& current_filename_, + wxProgressDialog* dialog_) + : items_done(items_done_), items_total(items_total_), current_filename(current_filename_), + dialog(dialog_) + { + } - int items_done; - int items_total; - std::string current_filename; - wxProgressDialog* dialog; + int items_done; + int items_total; + std::string current_filename; + wxProgressDialog* dialog; }; static bool sorted = false; @@ -73,1346 +76,1324 @@ static bool sorted = false; static int CompareGameListItems(const GameListItem* iso1, const GameListItem* iso2, long sortData = CGameListCtrl::COLUMN_TITLE) { - int t = 1; + int t = 1; - if (sortData < 0) - { - t = -1; - sortData = -sortData; - } + if (sortData < 0) + { + t = -1; + sortData = -sortData; + } - switch (sortData) - { - case CGameListCtrl::COLUMN_TITLE: - if (!strcasecmp(iso1->GetName().c_str(), iso2->GetName().c_str())) - { - if (iso1->GetUniqueID() != iso2->GetUniqueID()) - return t * (iso1->GetUniqueID() > iso2->GetUniqueID() ? 1 : -1); - if (iso1->GetRevision() != iso2->GetRevision()) - return t * (iso1->GetRevision() > iso2->GetRevision() ? 1 : -1); - if (iso1->GetDiscNumber() != iso2->GetDiscNumber()) - return t * (iso1->GetDiscNumber() > iso2->GetDiscNumber() ? 1 : -1); + switch (sortData) + { + case CGameListCtrl::COLUMN_TITLE: + if (!strcasecmp(iso1->GetName().c_str(), iso2->GetName().c_str())) + { + if (iso1->GetUniqueID() != iso2->GetUniqueID()) + return t * (iso1->GetUniqueID() > iso2->GetUniqueID() ? 1 : -1); + if (iso1->GetRevision() != iso2->GetRevision()) + return t * (iso1->GetRevision() > iso2->GetRevision() ? 1 : -1); + if (iso1->GetDiscNumber() != iso2->GetDiscNumber()) + return t * (iso1->GetDiscNumber() > iso2->GetDiscNumber() ? 1 : -1); - wxString iso1_filename = wxFileNameFromPath(iso1->GetFileName()); - wxString iso2_filename = wxFileNameFromPath(iso2->GetFileName()); + wxString iso1_filename = wxFileNameFromPath(iso1->GetFileName()); + wxString iso2_filename = wxFileNameFromPath(iso2->GetFileName()); - if (iso1_filename != iso2_filename) - return t * wxStricmp(iso1_filename, iso2_filename); - } - return strcasecmp(iso1->GetName().c_str(), iso2->GetName().c_str()) * t; - case CGameListCtrl::COLUMN_MAKER: - return strcasecmp(iso1->GetCompany().c_str(), iso2->GetCompany().c_str()) * t; - case CGameListCtrl::COLUMN_FILENAME: - return wxStricmp(wxFileNameFromPath(iso1->GetFileName()), - wxFileNameFromPath(iso2->GetFileName())) * t; - case CGameListCtrl::COLUMN_ID: - return strcasecmp(iso1->GetUniqueID().c_str(), iso2->GetUniqueID().c_str()) * t; - case CGameListCtrl::COLUMN_COUNTRY: - if (iso1->GetCountry() > iso2->GetCountry()) - return 1 * t; - if (iso1->GetCountry() < iso2->GetCountry()) - return -1 * t; - return 0; - case CGameListCtrl::COLUMN_SIZE: - if (iso1->GetFileSize() > iso2->GetFileSize()) - return 1 * t; - if (iso1->GetFileSize() < iso2->GetFileSize()) - return -1 * t; - return 0; - case CGameListCtrl::COLUMN_PLATFORM: - if (iso1->GetPlatform() > iso2->GetPlatform()) - return 1 * t; - if (iso1->GetPlatform() < iso2->GetPlatform()) - return -1 * t; - return 0; + if (iso1_filename != iso2_filename) + return t * wxStricmp(iso1_filename, iso2_filename); + } + return strcasecmp(iso1->GetName().c_str(), iso2->GetName().c_str()) * t; + case CGameListCtrl::COLUMN_MAKER: + return strcasecmp(iso1->GetCompany().c_str(), iso2->GetCompany().c_str()) * t; + case CGameListCtrl::COLUMN_FILENAME: + return wxStricmp(wxFileNameFromPath(iso1->GetFileName()), + wxFileNameFromPath(iso2->GetFileName())) * + t; + case CGameListCtrl::COLUMN_ID: + return strcasecmp(iso1->GetUniqueID().c_str(), iso2->GetUniqueID().c_str()) * t; + case CGameListCtrl::COLUMN_COUNTRY: + if (iso1->GetCountry() > iso2->GetCountry()) + return 1 * t; + if (iso1->GetCountry() < iso2->GetCountry()) + return -1 * t; + return 0; + case CGameListCtrl::COLUMN_SIZE: + if (iso1->GetFileSize() > iso2->GetFileSize()) + return 1 * t; + if (iso1->GetFileSize() < iso2->GetFileSize()) + return -1 * t; + return 0; + case CGameListCtrl::COLUMN_PLATFORM: + if (iso1->GetPlatform() > iso2->GetPlatform()) + return 1 * t; + if (iso1->GetPlatform() < iso2->GetPlatform()) + return -1 * t; + return 0; - case CGameListCtrl::COLUMN_EMULATION_STATE: - { - const int - nState1 = iso1->GetEmuState(), - nState2 = iso2->GetEmuState(); + case CGameListCtrl::COLUMN_EMULATION_STATE: + { + const int nState1 = iso1->GetEmuState(), nState2 = iso2->GetEmuState(); - if (nState1 > nState2) - return 1 * t; - if (nState1 < nState2) - return -1 * t; - else - return 0; - } - break; - } + if (nState1 > nState2) + return 1 * t; + if (nState1 < nState2) + return -1 * t; + else + return 0; + } + break; + } - return 0; + return 0; } -CGameListCtrl::CGameListCtrl(wxWindow* parent, const wxWindowID id, const - wxPoint& pos, const wxSize& size, long style) - : wxListCtrl(parent, id, pos, size, style), toolTip(nullptr) +CGameListCtrl::CGameListCtrl(wxWindow* parent, const wxWindowID id, const wxPoint& pos, + const wxSize& size, long style) + : wxListCtrl(parent, id, pos, size, style), toolTip(nullptr) { - Bind(wxEVT_SIZE, &CGameListCtrl::OnSize, this); - Bind(wxEVT_RIGHT_DOWN, &CGameListCtrl::OnRightClick, this); - Bind(wxEVT_LEFT_DOWN, &CGameListCtrl::OnLeftClick, this); - Bind(wxEVT_MOTION, &CGameListCtrl::OnMouseMotion, this); - Bind(wxEVT_LIST_KEY_DOWN, &CGameListCtrl::OnKeyPress, this); - Bind(wxEVT_LIST_COL_BEGIN_DRAG, &CGameListCtrl::OnColBeginDrag, this); - Bind(wxEVT_LIST_COL_CLICK, &CGameListCtrl::OnColumnClick, this); + Bind(wxEVT_SIZE, &CGameListCtrl::OnSize, this); + Bind(wxEVT_RIGHT_DOWN, &CGameListCtrl::OnRightClick, this); + Bind(wxEVT_LEFT_DOWN, &CGameListCtrl::OnLeftClick, this); + Bind(wxEVT_MOTION, &CGameListCtrl::OnMouseMotion, this); + Bind(wxEVT_LIST_KEY_DOWN, &CGameListCtrl::OnKeyPress, this); + Bind(wxEVT_LIST_COL_BEGIN_DRAG, &CGameListCtrl::OnColBeginDrag, this); + Bind(wxEVT_LIST_COL_CLICK, &CGameListCtrl::OnColumnClick, this); - Bind(wxEVT_MENU, &CGameListCtrl::OnProperties, this, IDM_PROPERTIES); - Bind(wxEVT_MENU, &CGameListCtrl::OnWiki, this, IDM_GAME_WIKI); - Bind(wxEVT_MENU, &CGameListCtrl::OnOpenContainingFolder, this, IDM_OPEN_CONTAINING_FOLDER); - Bind(wxEVT_MENU, &CGameListCtrl::OnOpenSaveFolder, this, IDM_OPEN_SAVE_FOLDER); - Bind(wxEVT_MENU, &CGameListCtrl::OnExportSave, this, IDM_EXPORT_SAVE); - Bind(wxEVT_MENU, &CGameListCtrl::OnSetDefaultISO, this, IDM_SET_DEFAULT_ISO); - Bind(wxEVT_MENU, &CGameListCtrl::OnCompressISO, this, IDM_COMPRESS_ISO); - Bind(wxEVT_MENU, &CGameListCtrl::OnMultiCompressISO, this, IDM_MULTI_COMPRESS_ISO); - Bind(wxEVT_MENU, &CGameListCtrl::OnMultiDecompressISO, this, IDM_MULTI_DECOMPRESS_ISO); - Bind(wxEVT_MENU, &CGameListCtrl::OnDeleteISO, this, IDM_DELETE_ISO); - Bind(wxEVT_MENU, &CGameListCtrl::OnChangeDisc, this, IDM_LIST_CHANGE_DISC); + Bind(wxEVT_MENU, &CGameListCtrl::OnProperties, this, IDM_PROPERTIES); + Bind(wxEVT_MENU, &CGameListCtrl::OnWiki, this, IDM_GAME_WIKI); + Bind(wxEVT_MENU, &CGameListCtrl::OnOpenContainingFolder, this, IDM_OPEN_CONTAINING_FOLDER); + Bind(wxEVT_MENU, &CGameListCtrl::OnOpenSaveFolder, this, IDM_OPEN_SAVE_FOLDER); + Bind(wxEVT_MENU, &CGameListCtrl::OnExportSave, this, IDM_EXPORT_SAVE); + Bind(wxEVT_MENU, &CGameListCtrl::OnSetDefaultISO, this, IDM_SET_DEFAULT_ISO); + Bind(wxEVT_MENU, &CGameListCtrl::OnCompressISO, this, IDM_COMPRESS_ISO); + Bind(wxEVT_MENU, &CGameListCtrl::OnMultiCompressISO, this, IDM_MULTI_COMPRESS_ISO); + Bind(wxEVT_MENU, &CGameListCtrl::OnMultiDecompressISO, this, IDM_MULTI_DECOMPRESS_ISO); + Bind(wxEVT_MENU, &CGameListCtrl::OnDeleteISO, this, IDM_DELETE_ISO); + Bind(wxEVT_MENU, &CGameListCtrl::OnChangeDisc, this, IDM_LIST_CHANGE_DISC); - wxTheApp->Bind(DOLPHIN_EVT_LOCAL_INI_CHANGED, &CGameListCtrl::OnLocalIniModified, this); + wxTheApp->Bind(DOLPHIN_EVT_LOCAL_INI_CHANGED, &CGameListCtrl::OnLocalIniModified, this); } CGameListCtrl::~CGameListCtrl() { - ClearIsoFiles(); + ClearIsoFiles(); } void CGameListCtrl::InitBitmaps() { - wxSize size(96, 32); - wxImageList* img_list = new wxImageList(96, 32); - AssignImageList(img_list, wxIMAGE_LIST_SMALL); + wxSize size(96, 32); + wxImageList* img_list = new wxImageList(96, 32); + AssignImageList(img_list, wxIMAGE_LIST_SMALL); - m_FlagImageIndex.resize(DiscIO::IVolume::NUMBER_OF_COUNTRIES); - m_FlagImageIndex[DiscIO::IVolume::COUNTRY_JAPAN] = img_list->Add(WxUtils::LoadResourceBitmap("Flag_Japan", size)); - m_FlagImageIndex[DiscIO::IVolume::COUNTRY_EUROPE] = img_list->Add(WxUtils::LoadResourceBitmap("Flag_Europe", size)); - m_FlagImageIndex[DiscIO::IVolume::COUNTRY_USA] = img_list->Add(WxUtils::LoadResourceBitmap("Flag_USA", size)); - m_FlagImageIndex[DiscIO::IVolume::COUNTRY_AUSTRALIA] = img_list->Add(WxUtils::LoadResourceBitmap("Flag_Australia", size)); - m_FlagImageIndex[DiscIO::IVolume::COUNTRY_FRANCE] = img_list->Add(WxUtils::LoadResourceBitmap("Flag_France", size)); - m_FlagImageIndex[DiscIO::IVolume::COUNTRY_GERMANY] = img_list->Add(WxUtils::LoadResourceBitmap("Flag_Germany", size)); - m_FlagImageIndex[DiscIO::IVolume::COUNTRY_ITALY] = img_list->Add(WxUtils::LoadResourceBitmap("Flag_Italy", size)); - m_FlagImageIndex[DiscIO::IVolume::COUNTRY_KOREA] = img_list->Add(WxUtils::LoadResourceBitmap("Flag_Korea", size)); - m_FlagImageIndex[DiscIO::IVolume::COUNTRY_NETHERLANDS] = img_list->Add(WxUtils::LoadResourceBitmap("Flag_Netherlands", size)); - m_FlagImageIndex[DiscIO::IVolume::COUNTRY_RUSSIA] = img_list->Add(WxUtils::LoadResourceBitmap("Flag_Russia", size)); - m_FlagImageIndex[DiscIO::IVolume::COUNTRY_SPAIN] = img_list->Add(WxUtils::LoadResourceBitmap("Flag_Spain", size)); - m_FlagImageIndex[DiscIO::IVolume::COUNTRY_TAIWAN] = img_list->Add(WxUtils::LoadResourceBitmap("Flag_Taiwan", size)); - m_FlagImageIndex[DiscIO::IVolume::COUNTRY_WORLD] = img_list->Add(WxUtils::LoadResourceBitmap("Flag_International", size)); - m_FlagImageIndex[DiscIO::IVolume::COUNTRY_UNKNOWN] = img_list->Add(WxUtils::LoadResourceBitmap("Flag_Unknown", size)); + m_FlagImageIndex.resize(DiscIO::IVolume::NUMBER_OF_COUNTRIES); + m_FlagImageIndex[DiscIO::IVolume::COUNTRY_JAPAN] = + img_list->Add(WxUtils::LoadResourceBitmap("Flag_Japan", size)); + m_FlagImageIndex[DiscIO::IVolume::COUNTRY_EUROPE] = + img_list->Add(WxUtils::LoadResourceBitmap("Flag_Europe", size)); + m_FlagImageIndex[DiscIO::IVolume::COUNTRY_USA] = + img_list->Add(WxUtils::LoadResourceBitmap("Flag_USA", size)); + m_FlagImageIndex[DiscIO::IVolume::COUNTRY_AUSTRALIA] = + img_list->Add(WxUtils::LoadResourceBitmap("Flag_Australia", size)); + m_FlagImageIndex[DiscIO::IVolume::COUNTRY_FRANCE] = + img_list->Add(WxUtils::LoadResourceBitmap("Flag_France", size)); + m_FlagImageIndex[DiscIO::IVolume::COUNTRY_GERMANY] = + img_list->Add(WxUtils::LoadResourceBitmap("Flag_Germany", size)); + m_FlagImageIndex[DiscIO::IVolume::COUNTRY_ITALY] = + img_list->Add(WxUtils::LoadResourceBitmap("Flag_Italy", size)); + m_FlagImageIndex[DiscIO::IVolume::COUNTRY_KOREA] = + img_list->Add(WxUtils::LoadResourceBitmap("Flag_Korea", size)); + m_FlagImageIndex[DiscIO::IVolume::COUNTRY_NETHERLANDS] = + img_list->Add(WxUtils::LoadResourceBitmap("Flag_Netherlands", size)); + m_FlagImageIndex[DiscIO::IVolume::COUNTRY_RUSSIA] = + img_list->Add(WxUtils::LoadResourceBitmap("Flag_Russia", size)); + m_FlagImageIndex[DiscIO::IVolume::COUNTRY_SPAIN] = + img_list->Add(WxUtils::LoadResourceBitmap("Flag_Spain", size)); + m_FlagImageIndex[DiscIO::IVolume::COUNTRY_TAIWAN] = + img_list->Add(WxUtils::LoadResourceBitmap("Flag_Taiwan", size)); + m_FlagImageIndex[DiscIO::IVolume::COUNTRY_WORLD] = + img_list->Add(WxUtils::LoadResourceBitmap("Flag_International", size)); + m_FlagImageIndex[DiscIO::IVolume::COUNTRY_UNKNOWN] = + img_list->Add(WxUtils::LoadResourceBitmap("Flag_Unknown", size)); - m_PlatformImageIndex.resize(4); - m_PlatformImageIndex[DiscIO::IVolume::GAMECUBE_DISC] = img_list->Add(WxUtils::LoadResourceBitmap("Platform_Gamecube", size)); - m_PlatformImageIndex[DiscIO::IVolume::WII_DISC] = img_list->Add(WxUtils::LoadResourceBitmap("Platform_Wii", size)); - m_PlatformImageIndex[DiscIO::IVolume::WII_WAD] = img_list->Add(WxUtils::LoadResourceBitmap("Platform_Wad", size)); - m_PlatformImageIndex[DiscIO::IVolume::ELF_DOL] = img_list->Add(WxUtils::LoadResourceBitmap("Platform_File", size)); + m_PlatformImageIndex.resize(4); + m_PlatformImageIndex[DiscIO::IVolume::GAMECUBE_DISC] = + img_list->Add(WxUtils::LoadResourceBitmap("Platform_Gamecube", size)); + m_PlatformImageIndex[DiscIO::IVolume::WII_DISC] = + img_list->Add(WxUtils::LoadResourceBitmap("Platform_Wii", size)); + m_PlatformImageIndex[DiscIO::IVolume::WII_WAD] = + img_list->Add(WxUtils::LoadResourceBitmap("Platform_Wad", size)); + m_PlatformImageIndex[DiscIO::IVolume::ELF_DOL] = + img_list->Add(WxUtils::LoadResourceBitmap("Platform_File", size)); - m_EmuStateImageIndex.resize(6); - m_EmuStateImageIndex[0] = img_list->Add(WxUtils::LoadResourceBitmap("rating0", size)); - m_EmuStateImageIndex[1] = img_list->Add(WxUtils::LoadResourceBitmap("rating1", size)); - m_EmuStateImageIndex[2] = img_list->Add(WxUtils::LoadResourceBitmap("rating2", size)); - m_EmuStateImageIndex[3] = img_list->Add(WxUtils::LoadResourceBitmap("rating3", size)); - m_EmuStateImageIndex[4] = img_list->Add(WxUtils::LoadResourceBitmap("rating4", size)); - m_EmuStateImageIndex[5] = img_list->Add(WxUtils::LoadResourceBitmap("rating5", size)); + m_EmuStateImageIndex.resize(6); + m_EmuStateImageIndex[0] = img_list->Add(WxUtils::LoadResourceBitmap("rating0", size)); + m_EmuStateImageIndex[1] = img_list->Add(WxUtils::LoadResourceBitmap("rating1", size)); + m_EmuStateImageIndex[2] = img_list->Add(WxUtils::LoadResourceBitmap("rating2", size)); + m_EmuStateImageIndex[3] = img_list->Add(WxUtils::LoadResourceBitmap("rating3", size)); + m_EmuStateImageIndex[4] = img_list->Add(WxUtils::LoadResourceBitmap("rating4", size)); + m_EmuStateImageIndex[5] = img_list->Add(WxUtils::LoadResourceBitmap("rating5", size)); } void CGameListCtrl::BrowseForDirectory() { - wxString dirHome; - wxGetHomeDir(&dirHome); + wxString dirHome; + wxGetHomeDir(&dirHome); - // browse - wxDirDialog dialog(this, _("Browse for a directory to add"), dirHome, - wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST); + // browse + wxDirDialog dialog(this, _("Browse for a directory to add"), dirHome, + wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST); - if (dialog.ShowModal() == wxID_OK) - { - std::string sPath(WxStrToStr(dialog.GetPath())); - std::vector::iterator itResult = std::find( - SConfig::GetInstance().m_ISOFolder.begin(), - SConfig::GetInstance().m_ISOFolder.end(), sPath); + if (dialog.ShowModal() == wxID_OK) + { + std::string sPath(WxStrToStr(dialog.GetPath())); + std::vector::iterator itResult = + std::find(SConfig::GetInstance().m_ISOFolder.begin(), + SConfig::GetInstance().m_ISOFolder.end(), sPath); - if (itResult == SConfig::GetInstance().m_ISOFolder.end()) - { - SConfig::GetInstance().m_ISOFolder.push_back(sPath); - SConfig::GetInstance().SaveSettings(); - } + if (itResult == SConfig::GetInstance().m_ISOFolder.end()) + { + SConfig::GetInstance().m_ISOFolder.push_back(sPath); + SConfig::GetInstance().SaveSettings(); + } - Update(); - } + Update(); + } } void CGameListCtrl::Update() { - int scrollPos = wxWindow::GetScrollPos(wxVERTICAL); - // Don't let the user refresh it while a game is running - if (Core::GetState() != Core::CORE_UNINITIALIZED) - return; + int scrollPos = wxWindow::GetScrollPos(wxVERTICAL); + // Don't let the user refresh it while a game is running + if (Core::GetState() != Core::CORE_UNINITIALIZED) + return; - ScanForISOs(); + ScanForISOs(); - Freeze(); - ClearAll(); + Freeze(); + ClearAll(); - if (m_ISOFiles.size() != 0) - { - // Don't load bitmaps unless there are games to list - InitBitmaps(); + if (m_ISOFiles.size() != 0) + { + // Don't load bitmaps unless there are games to list + InitBitmaps(); - // add columns - InsertColumn(COLUMN_DUMMY, ""); - InsertColumn(COLUMN_PLATFORM, ""); - InsertColumn(COLUMN_BANNER, _("Banner")); - InsertColumn(COLUMN_TITLE, _("Title")); + // add columns + InsertColumn(COLUMN_DUMMY, ""); + InsertColumn(COLUMN_PLATFORM, ""); + InsertColumn(COLUMN_BANNER, _("Banner")); + InsertColumn(COLUMN_TITLE, _("Title")); - InsertColumn(COLUMN_MAKER, _("Maker")); - InsertColumn(COLUMN_FILENAME, _("File")); - InsertColumn(COLUMN_ID, _("ID")); - InsertColumn(COLUMN_COUNTRY, ""); - InsertColumn(COLUMN_SIZE, _("Size")); - InsertColumn(COLUMN_EMULATION_STATE, _("State")); + InsertColumn(COLUMN_MAKER, _("Maker")); + InsertColumn(COLUMN_FILENAME, _("File")); + InsertColumn(COLUMN_ID, _("ID")); + InsertColumn(COLUMN_COUNTRY, ""); + InsertColumn(COLUMN_SIZE, _("Size")); + InsertColumn(COLUMN_EMULATION_STATE, _("State")); #ifdef __WXMSW__ - const int platform_padding = 0; + const int platform_padding = 0; #else - const int platform_padding = 8; + const int platform_padding = 8; #endif - const int platform_icon_padding = 1; + const int platform_icon_padding = 1; - // set initial sizes for columns - SetColumnWidth(COLUMN_DUMMY, 0); - SetColumnWidth(COLUMN_PLATFORM, SConfig::GetInstance().m_showSystemColumn ? 32 + platform_icon_padding + platform_padding : 0); - SetColumnWidth(COLUMN_BANNER, SConfig::GetInstance().m_showBannerColumn ? 96 + platform_padding : 0); - SetColumnWidth(COLUMN_TITLE, 175 + platform_padding); - SetColumnWidth(COLUMN_MAKER, SConfig::GetInstance().m_showMakerColumn ? 150 + platform_padding : 0); - SetColumnWidth(COLUMN_FILENAME, SConfig::GetInstance().m_showFileNameColumn ? 100 + platform_padding : 0); - SetColumnWidth(COLUMN_ID, SConfig::GetInstance().m_showIDColumn ? 75 + platform_padding : 0); - SetColumnWidth(COLUMN_COUNTRY, SConfig::GetInstance().m_showRegionColumn ? 32 + platform_padding : 0); - SetColumnWidth(COLUMN_EMULATION_STATE, SConfig::GetInstance().m_showStateColumn ? 48 + platform_padding : 0); + // set initial sizes for columns + SetColumnWidth(COLUMN_DUMMY, 0); + SetColumnWidth(COLUMN_PLATFORM, SConfig::GetInstance().m_showSystemColumn ? + 32 + platform_icon_padding + platform_padding : + 0); + SetColumnWidth(COLUMN_BANNER, + SConfig::GetInstance().m_showBannerColumn ? 96 + platform_padding : 0); + SetColumnWidth(COLUMN_TITLE, 175 + platform_padding); + SetColumnWidth(COLUMN_MAKER, + SConfig::GetInstance().m_showMakerColumn ? 150 + platform_padding : 0); + SetColumnWidth(COLUMN_FILENAME, + SConfig::GetInstance().m_showFileNameColumn ? 100 + platform_padding : 0); + SetColumnWidth(COLUMN_ID, SConfig::GetInstance().m_showIDColumn ? 75 + platform_padding : 0); + SetColumnWidth(COLUMN_COUNTRY, + SConfig::GetInstance().m_showRegionColumn ? 32 + platform_padding : 0); + SetColumnWidth(COLUMN_EMULATION_STATE, + SConfig::GetInstance().m_showStateColumn ? 48 + platform_padding : 0); - // add all items - for (int i = 0; i < (int)m_ISOFiles.size(); i++) - { - InsertItemInReportView(i); - if (SConfig::GetInstance().m_ColorCompressed && m_ISOFiles[i]->IsCompressed()) - SetItemTextColour(i, wxColour(0xFF0000)); - } + // add all items + for (int i = 0; i < (int)m_ISOFiles.size(); i++) + { + InsertItemInReportView(i); + if (SConfig::GetInstance().m_ColorCompressed && m_ISOFiles[i]->IsCompressed()) + SetItemTextColour(i, wxColour(0xFF0000)); + } - // Sort items by Title - if (!sorted) - last_column = 0; - sorted = false; - wxListEvent event; - event.m_col = SConfig::GetInstance().m_ListSort2; - OnColumnClick(event); + // Sort items by Title + if (!sorted) + last_column = 0; + sorted = false; + wxListEvent event; + event.m_col = SConfig::GetInstance().m_ListSort2; + OnColumnClick(event); - event.m_col = SConfig::GetInstance().m_ListSort; - OnColumnClick(event); - sorted = true; + event.m_col = SConfig::GetInstance().m_ListSort; + OnColumnClick(event); + sorted = true; - SetColumnWidth(COLUMN_SIZE, SConfig::GetInstance().m_showSizeColumn ? wxLIST_AUTOSIZE : 0); - } - else - { - // Remove existing image list and replace it with the smallest possible one. - // The list needs an image list because it reserves screen pixels for the - // image even if we aren't going to use one. It uses the dimensions of the - // last non-null list so assigning nullptr doesn't work. - AssignImageList(new wxImageList(1, 1), wxIMAGE_LIST_SMALL); + SetColumnWidth(COLUMN_SIZE, SConfig::GetInstance().m_showSizeColumn ? wxLIST_AUTOSIZE : 0); + } + else + { + // Remove existing image list and replace it with the smallest possible one. + // The list needs an image list because it reserves screen pixels for the + // image even if we aren't going to use one. It uses the dimensions of the + // last non-null list so assigning nullptr doesn't work. + AssignImageList(new wxImageList(1, 1), wxIMAGE_LIST_SMALL); - wxString errorString; - // We just check for one hide setting to be enabled, as we may only - // have GC games for example, and hide them, so we should show the - // first message instead - if (IsHidingItems()) - { - errorString = _("Dolphin is currently set to hide all games. Double-click here to show all games..."); - } - else - { - errorString = _("Dolphin could not find any GameCube/Wii ISOs or WADs. Double-click here to set a games directory..."); - } - InsertColumn(0, ""); - long index = InsertItem(0, errorString); - SetItemFont(index, *wxITALIC_FONT); - SetColumnWidth(0, wxLIST_AUTOSIZE); - } - if (GetSelectedISO() == nullptr) - main_frame->UpdateGUI(); - // Thaw before calling AutomaticColumnWidth so that GetClientSize will - // correctly account for the width of scrollbars if they appear. - Thaw(); + wxString errorString; + // We just check for one hide setting to be enabled, as we may only + // have GC games for example, and hide them, so we should show the + // first message instead + if (IsHidingItems()) + { + errorString = + _("Dolphin is currently set to hide all games. Double-click here to show all games..."); + } + else + { + errorString = _("Dolphin could not find any GameCube/Wii ISOs or WADs. Double-click here to " + "set a games directory..."); + } + InsertColumn(0, ""); + long index = InsertItem(0, errorString); + SetItemFont(index, *wxITALIC_FONT); + SetColumnWidth(0, wxLIST_AUTOSIZE); + } + if (GetSelectedISO() == nullptr) + main_frame->UpdateGUI(); + // Thaw before calling AutomaticColumnWidth so that GetClientSize will + // correctly account for the width of scrollbars if they appear. + Thaw(); - AutomaticColumnWidth(); - ScrollLines(scrollPos); - SetFocus(); + AutomaticColumnWidth(); + ScrollLines(scrollPos); + SetFocus(); } static wxString NiceSizeFormat(u64 size) { - // Return a pretty filesize string from byte count. - // e.g. 1134278 -> "1.08 MiB" + // Return a pretty filesize string from byte count. + // e.g. 1134278 -> "1.08 MiB" - const char* const unit_symbols[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" }; + const char* const unit_symbols[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}; - // Find largest power of 2 less than size. - // div 10 to get largest named unit less than size - // 10 == log2(1024) (number of B in a KiB, KiB in a MiB, etc) - // Max value is 63 / 10 = 6 - const int unit = IntLog2(std::max(size, 1)) / 10; + // Find largest power of 2 less than size. + // div 10 to get largest named unit less than size + // 10 == log2(1024) (number of B in a KiB, KiB in a MiB, etc) + // Max value is 63 / 10 = 6 + const int unit = IntLog2(std::max(size, 1)) / 10; - // Don't need exact values, only 5 most significant digits - double unit_size = std::pow(2, unit * 10); - return wxString::Format("%.2f %s", size / unit_size, unit_symbols[unit]); + // Don't need exact values, only 5 most significant digits + double unit_size = std::pow(2, unit * 10); + return wxString::Format("%.2f %s", size / unit_size, unit_symbols[unit]); } // Update the column content of the item at _Index void CGameListCtrl::UpdateItemAtColumn(long _Index, int column) { - GameListItem& rISOFile = *m_ISOFiles[GetItemData(_Index)]; + GameListItem& rISOFile = *m_ISOFiles[GetItemData(_Index)]; - switch(column) - { - case COLUMN_PLATFORM: - { - SetItemColumnImage(_Index, COLUMN_PLATFORM, - m_PlatformImageIndex[rISOFile.GetPlatform()]); - break; - } - case COLUMN_BANNER: - { - int ImageIndex = -1; + switch (column) + { + case COLUMN_PLATFORM: + { + SetItemColumnImage(_Index, COLUMN_PLATFORM, m_PlatformImageIndex[rISOFile.GetPlatform()]); + break; + } + case COLUMN_BANNER: + { + int ImageIndex = -1; - if (rISOFile.GetBitmap().IsOk()) - ImageIndex = GetImageList(wxIMAGE_LIST_SMALL)->Add(rISOFile.GetBitmap()); + if (rISOFile.GetBitmap().IsOk()) + ImageIndex = GetImageList(wxIMAGE_LIST_SMALL)->Add(rISOFile.GetBitmap()); - SetItemColumnImage(_Index, COLUMN_BANNER, ImageIndex); - break; - } - case COLUMN_TITLE: - { - wxString name = StrToWxStr(rISOFile.GetName()); - int disc_number = rISOFile.GetDiscNumber() + 1; + SetItemColumnImage(_Index, COLUMN_BANNER, ImageIndex); + break; + } + case COLUMN_TITLE: + { + wxString name = StrToWxStr(rISOFile.GetName()); + int disc_number = rISOFile.GetDiscNumber() + 1; - if (disc_number > 1 && - name.Lower().find(wxString::Format("disc %i", disc_number)) == std::string::npos && - name.Lower().find(wxString::Format("disc%i", disc_number)) == std::string::npos) - { - name = wxString::Format(_("%s (Disc %i)"), name.c_str(), disc_number); - } + if (disc_number > 1 && + name.Lower().find(wxString::Format("disc %i", disc_number)) == std::string::npos && + name.Lower().find(wxString::Format("disc%i", disc_number)) == std::string::npos) + { + name = wxString::Format(_("%s (Disc %i)"), name.c_str(), disc_number); + } - SetItem(_Index, COLUMN_TITLE, name, -1); - break; - } - case COLUMN_MAKER: - SetItem(_Index, COLUMN_MAKER, StrToWxStr(rISOFile.GetCompany()), -1); - break; - case COLUMN_FILENAME: - SetItem(_Index, COLUMN_FILENAME, - wxFileNameFromPath(StrToWxStr(rISOFile.GetFileName())), -1); - break; - case COLUMN_EMULATION_STATE: - SetItemColumnImage(_Index, COLUMN_EMULATION_STATE, - m_EmuStateImageIndex[rISOFile.GetEmuState()]); - break; - case COLUMN_COUNTRY: - SetItemColumnImage(_Index, COLUMN_COUNTRY, - m_FlagImageIndex[rISOFile.GetCountry()]); - break; - case COLUMN_SIZE: - SetItem(_Index, COLUMN_SIZE, NiceSizeFormat(rISOFile.GetFileSize()), -1); - break; - case COLUMN_ID: - SetItem(_Index, COLUMN_ID, rISOFile.GetUniqueID(), -1); - break; - } + SetItem(_Index, COLUMN_TITLE, name, -1); + break; + } + case COLUMN_MAKER: + SetItem(_Index, COLUMN_MAKER, StrToWxStr(rISOFile.GetCompany()), -1); + break; + case COLUMN_FILENAME: + SetItem(_Index, COLUMN_FILENAME, wxFileNameFromPath(StrToWxStr(rISOFile.GetFileName())), -1); + break; + case COLUMN_EMULATION_STATE: + SetItemColumnImage(_Index, COLUMN_EMULATION_STATE, + m_EmuStateImageIndex[rISOFile.GetEmuState()]); + break; + case COLUMN_COUNTRY: + SetItemColumnImage(_Index, COLUMN_COUNTRY, m_FlagImageIndex[rISOFile.GetCountry()]); + break; + case COLUMN_SIZE: + SetItem(_Index, COLUMN_SIZE, NiceSizeFormat(rISOFile.GetFileSize()), -1); + break; + case COLUMN_ID: + SetItem(_Index, COLUMN_ID, rISOFile.GetUniqueID(), -1); + break; + } } void CGameListCtrl::InsertItemInReportView(long index) { - // When using wxListCtrl, there is no hope of per-column text colors. - // But for reference, here are the old colors that were used: (BGR) - // title: 0xFF0000 - // company: 0x007030 + // When using wxListCtrl, there is no hope of per-column text colors. + // But for reference, here are the old colors that were used: (BGR) + // title: 0xFF0000 + // company: 0x007030 - // Insert a first column with nothing in it, that will be used as the Index - long item_index; - { - wxListItem li; - li.SetId(index); - li.SetData(index); - li.SetMask(wxLIST_MASK_DATA); - item_index = InsertItem(li); - } + // Insert a first column with nothing in it, that will be used as the Index + long item_index; + { + wxListItem li; + li.SetId(index); + li.SetData(index); + li.SetMask(wxLIST_MASK_DATA); + item_index = InsertItem(li); + } - // Iterate over all columns and fill them with content if they are visible - for (int i = 1; i < NUMBER_OF_COLUMN; i++) - { - if (GetColumnWidth(i) != 0) - UpdateItemAtColumn(item_index, i); - } + // Iterate over all columns and fill them with content if they are visible + for (int i = 1; i < NUMBER_OF_COLUMN; i++) + { + if (GetColumnWidth(i) != 0) + UpdateItemAtColumn(item_index, i); + } - // Background color - SetBackgroundColor(); + // Background color + SetBackgroundColor(); } static wxColour blend50(const wxColour& c1, const wxColour& c2) { - unsigned char r,g,b,a; - r = c1.Red()/2 + c2.Red()/2; - g = c1.Green()/2 + c2.Green()/2; - b = c1.Blue()/2 + c2.Blue()/2; - a = c1.Alpha()/2 + c2.Alpha()/2; - return a << 24 | b << 16 | g << 8 | r; + unsigned char r, g, b, a; + r = c1.Red() / 2 + c2.Red() / 2; + g = c1.Green() / 2 + c2.Green() / 2; + b = c1.Blue() / 2 + c2.Blue() / 2; + a = c1.Alpha() / 2 + c2.Alpha() / 2; + return a << 24 | b << 16 | g << 8 | r; } void CGameListCtrl::SetBackgroundColor() { - for (long i = 0; i < GetItemCount(); i++) - { - wxColour color = (i & 1) ? - blend50(wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT), - wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)) : - wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); - CGameListCtrl::SetItemBackgroundColour(i, color); - } + for (long i = 0; i < GetItemCount(); i++) + { + wxColour color = (i & 1) ? blend50(wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT), + wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)) : + wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); + CGameListCtrl::SetItemBackgroundColour(i, color); + } } void CGameListCtrl::ScanForISOs() { - ClearIsoFiles(); + ClearIsoFiles(); - // Load custom game titles from titles.txt - // http://www.gametdb.com/Wii/Downloads - std::unordered_map custom_title_map; - std::ifstream titlestxt; - OpenFStream(titlestxt, File::GetUserPath(D_LOAD_IDX) + "titles.txt", std::ios::in); + // Load custom game titles from titles.txt + // http://www.gametdb.com/Wii/Downloads + std::unordered_map custom_title_map; + std::ifstream titlestxt; + OpenFStream(titlestxt, File::GetUserPath(D_LOAD_IDX) + "titles.txt", std::ios::in); - if (!titlestxt.is_open()) - OpenFStream(titlestxt, File::GetUserPath(D_LOAD_IDX) + "wiitdb.txt", std::ios::in); + if (!titlestxt.is_open()) + OpenFStream(titlestxt, File::GetUserPath(D_LOAD_IDX) + "wiitdb.txt", std::ios::in); - if (titlestxt.is_open()) - { - std::string line; - while (!titlestxt.eof() && std::getline(titlestxt, line)) - { - const size_t equals_index = line.find('='); - if (equals_index != std::string::npos) - custom_title_map.emplace(StripSpaces(line.substr(0, equals_index)), - StripSpaces(line.substr(equals_index + 1))); - } - titlestxt.close(); - } + if (titlestxt.is_open()) + { + std::string line; + while (!titlestxt.eof() && std::getline(titlestxt, line)) + { + const size_t equals_index = line.find('='); + if (equals_index != std::string::npos) + custom_title_map.emplace(StripSpaces(line.substr(0, equals_index)), + StripSpaces(line.substr(equals_index + 1))); + } + titlestxt.close(); + } - std::vector Extensions; + std::vector Extensions; - if (SConfig::GetInstance().m_ListGC) - Extensions.push_back(".gcm"); - if (SConfig::GetInstance().m_ListWii || SConfig::GetInstance().m_ListGC) - { - Extensions.push_back(".iso"); - Extensions.push_back(".ciso"); - Extensions.push_back(".gcz"); - Extensions.push_back(".wbfs"); - } - if (SConfig::GetInstance().m_ListWad) - Extensions.push_back(".wad"); - if (SConfig::GetInstance().m_ListElfDol) - { - Extensions.push_back(".dol"); - Extensions.push_back(".elf"); - } + if (SConfig::GetInstance().m_ListGC) + Extensions.push_back(".gcm"); + if (SConfig::GetInstance().m_ListWii || SConfig::GetInstance().m_ListGC) + { + Extensions.push_back(".iso"); + Extensions.push_back(".ciso"); + Extensions.push_back(".gcz"); + Extensions.push_back(".wbfs"); + } + if (SConfig::GetInstance().m_ListWad) + Extensions.push_back(".wad"); + if (SConfig::GetInstance().m_ListElfDol) + { + Extensions.push_back(".dol"); + Extensions.push_back(".elf"); + } - auto rFilenames = DoFileSearch(Extensions, SConfig::GetInstance().m_ISOFolder, SConfig::GetInstance().m_RecursiveISOFolder); + auto rFilenames = DoFileSearch(Extensions, SConfig::GetInstance().m_ISOFolder, + SConfig::GetInstance().m_RecursiveISOFolder); - if (rFilenames.size() > 0) - { - wxProgressDialog dialog( - _("Scanning for ISOs"), - _("Scanning..."), - (int)rFilenames.size() - 1, - this, - wxPD_APP_MODAL | - wxPD_AUTO_HIDE | - wxPD_CAN_ABORT | - wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | - wxPD_SMOOTH // - makes updates as small as possible (down to 1px) - ); + if (rFilenames.size() > 0) + { + wxProgressDialog dialog( + _("Scanning for ISOs"), _("Scanning..."), (int)rFilenames.size() - 1, this, + wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | + wxPD_REMAINING_TIME | wxPD_SMOOTH // - makes updates as small as possible (down to 1px) + ); - for (u32 i = 0; i < rFilenames.size(); i++) - { - std::string FileName; - SplitPath(rFilenames[i], nullptr, &FileName, nullptr); + for (u32 i = 0; i < rFilenames.size(); i++) + { + std::string FileName; + SplitPath(rFilenames[i], nullptr, &FileName, nullptr); - // Update with the progress (i) and the message - dialog.Update(i, wxString::Format(_("Scanning %s"), - StrToWxStr(FileName))); - if (dialog.WasCancelled()) - break; + // Update with the progress (i) and the message + dialog.Update(i, wxString::Format(_("Scanning %s"), StrToWxStr(FileName))); + if (dialog.WasCancelled()) + break; - auto iso_file = std::make_unique(rFilenames[i], custom_title_map); + auto iso_file = std::make_unique(rFilenames[i], custom_title_map); - if (iso_file->IsValid()) - { - bool list = true; + if (iso_file->IsValid()) + { + bool list = true; - switch(iso_file->GetPlatform()) - { - case DiscIO::IVolume::WII_DISC: - if (!SConfig::GetInstance().m_ListWii) - list = false; - break; - case DiscIO::IVolume::WII_WAD: - if (!SConfig::GetInstance().m_ListWad) - list = false; - break; - case DiscIO::IVolume::ELF_DOL: - if (!SConfig::GetInstance().m_ListElfDol) - list = false; - break; - default: - if (!SConfig::GetInstance().m_ListGC) - list = false; - break; - } + switch (iso_file->GetPlatform()) + { + case DiscIO::IVolume::WII_DISC: + if (!SConfig::GetInstance().m_ListWii) + list = false; + break; + case DiscIO::IVolume::WII_WAD: + if (!SConfig::GetInstance().m_ListWad) + list = false; + break; + case DiscIO::IVolume::ELF_DOL: + if (!SConfig::GetInstance().m_ListElfDol) + list = false; + break; + default: + if (!SConfig::GetInstance().m_ListGC) + list = false; + break; + } - switch(iso_file->GetCountry()) - { - case DiscIO::IVolume::COUNTRY_AUSTRALIA: - if (!SConfig::GetInstance().m_ListAustralia) - list = false; - break; - case DiscIO::IVolume::COUNTRY_EUROPE: - if (!SConfig::GetInstance().m_ListPal) - list = false; - break; - case DiscIO::IVolume::COUNTRY_FRANCE: - if (!SConfig::GetInstance().m_ListFrance) - list = false; - break; - case DiscIO::IVolume::COUNTRY_GERMANY: - if (!SConfig::GetInstance().m_ListGermany) - list = false; - break; - case DiscIO::IVolume::COUNTRY_ITALY: - if (!SConfig::GetInstance().m_ListItaly) - list = false; - break; - case DiscIO::IVolume::COUNTRY_JAPAN: - if (!SConfig::GetInstance().m_ListJap) - list = false; - break; - case DiscIO::IVolume::COUNTRY_KOREA: - if (!SConfig::GetInstance().m_ListKorea) - list = false; - break; - case DiscIO::IVolume::COUNTRY_NETHERLANDS: - if (!SConfig::GetInstance().m_ListNetherlands) - list = false; - break; - case DiscIO::IVolume::COUNTRY_RUSSIA: - if (!SConfig::GetInstance().m_ListRussia) - list = false; - break; - case DiscIO::IVolume::COUNTRY_SPAIN: - if (!SConfig::GetInstance().m_ListSpain) - list = false; - break; - case DiscIO::IVolume::COUNTRY_TAIWAN: - if (!SConfig::GetInstance().m_ListTaiwan) - list = false; - break; - case DiscIO::IVolume::COUNTRY_USA: - if (!SConfig::GetInstance().m_ListUsa) - list = false; - break; - case DiscIO::IVolume::COUNTRY_WORLD: - if (!SConfig::GetInstance().m_ListWorld) - list = false; - break; - case DiscIO::IVolume::COUNTRY_UNKNOWN: - default: - if (!SConfig::GetInstance().m_ListUnknown) - list = false; - break; - } + switch (iso_file->GetCountry()) + { + case DiscIO::IVolume::COUNTRY_AUSTRALIA: + if (!SConfig::GetInstance().m_ListAustralia) + list = false; + break; + case DiscIO::IVolume::COUNTRY_EUROPE: + if (!SConfig::GetInstance().m_ListPal) + list = false; + break; + case DiscIO::IVolume::COUNTRY_FRANCE: + if (!SConfig::GetInstance().m_ListFrance) + list = false; + break; + case DiscIO::IVolume::COUNTRY_GERMANY: + if (!SConfig::GetInstance().m_ListGermany) + list = false; + break; + case DiscIO::IVolume::COUNTRY_ITALY: + if (!SConfig::GetInstance().m_ListItaly) + list = false; + break; + case DiscIO::IVolume::COUNTRY_JAPAN: + if (!SConfig::GetInstance().m_ListJap) + list = false; + break; + case DiscIO::IVolume::COUNTRY_KOREA: + if (!SConfig::GetInstance().m_ListKorea) + list = false; + break; + case DiscIO::IVolume::COUNTRY_NETHERLANDS: + if (!SConfig::GetInstance().m_ListNetherlands) + list = false; + break; + case DiscIO::IVolume::COUNTRY_RUSSIA: + if (!SConfig::GetInstance().m_ListRussia) + list = false; + break; + case DiscIO::IVolume::COUNTRY_SPAIN: + if (!SConfig::GetInstance().m_ListSpain) + list = false; + break; + case DiscIO::IVolume::COUNTRY_TAIWAN: + if (!SConfig::GetInstance().m_ListTaiwan) + list = false; + break; + case DiscIO::IVolume::COUNTRY_USA: + if (!SConfig::GetInstance().m_ListUsa) + list = false; + break; + case DiscIO::IVolume::COUNTRY_WORLD: + if (!SConfig::GetInstance().m_ListWorld) + list = false; + break; + case DiscIO::IVolume::COUNTRY_UNKNOWN: + default: + if (!SConfig::GetInstance().m_ListUnknown) + list = false; + break; + } - if (list) - m_ISOFiles.push_back(iso_file.release()); - } - } - } + if (list) + m_ISOFiles.push_back(iso_file.release()); + } + } + } - if (SConfig::GetInstance().m_ListDrives) - { - const std::vector drives = cdio_get_devices(); + if (SConfig::GetInstance().m_ListDrives) + { + const std::vector drives = cdio_get_devices(); - for (const auto& drive : drives) - { - auto gli = std::make_unique(drive, custom_title_map); + for (const auto& drive : drives) + { + auto gli = std::make_unique(drive, custom_title_map); - if (gli->IsValid()) - m_ISOFiles.push_back(gli.release()); - } - } + if (gli->IsValid()) + m_ISOFiles.push_back(gli.release()); + } + } - std::sort(m_ISOFiles.begin(), m_ISOFiles.end()); + std::sort(m_ISOFiles.begin(), m_ISOFiles.end()); } void CGameListCtrl::OnLocalIniModified(wxCommandEvent& ev) { - ev.Skip(); - std::string game_id = WxStrToStr(ev.GetString()); - // NOTE: The same game may occur multiple times if there are multiple - // physical copies in the search paths. - for (std::size_t i = 0; i < m_ISOFiles.size(); ++i) - { - if (m_ISOFiles[i]->GetUniqueID() != game_id) - continue; - m_ISOFiles[i]->ReloadINI(); + ev.Skip(); + std::string game_id = WxStrToStr(ev.GetString()); + // NOTE: The same game may occur multiple times if there are multiple + // physical copies in the search paths. + for (std::size_t i = 0; i < m_ISOFiles.size(); ++i) + { + if (m_ISOFiles[i]->GetUniqueID() != game_id) + continue; + m_ISOFiles[i]->ReloadINI(); - // The indexes in m_ISOFiles and the list do not line up. - // We need to find the corresponding item in the list (if it exists) - long item_id = 0; - for (; item_id < GetItemCount(); ++item_id) - { - if (i == static_cast(GetItemData(item_id))) - break; - } - // If the item is not currently being displayed then we're done. - if (item_id == GetItemCount()) - continue; + // The indexes in m_ISOFiles and the list do not line up. + // We need to find the corresponding item in the list (if it exists) + long item_id = 0; + for (; item_id < GetItemCount(); ++item_id) + { + if (i == static_cast(GetItemData(item_id))) + break; + } + // If the item is not currently being displayed then we're done. + if (item_id == GetItemCount()) + continue; - // Update all the columns - for (int j = 1; j < NUMBER_OF_COLUMN; ++j) - { - // NOTE: Banner is not modified by the INI and updating it will - // duplicate it in memory which is not wanted. - if (j != COLUMN_BANNER && GetColumnWidth(j) != 0) - UpdateItemAtColumn(item_id, j); - } - } + // Update all the columns + for (int j = 1; j < NUMBER_OF_COLUMN; ++j) + { + // NOTE: Banner is not modified by the INI and updating it will + // duplicate it in memory which is not wanted. + if (j != COLUMN_BANNER && GetColumnWidth(j) != 0) + UpdateItemAtColumn(item_id, j); + } + } } void CGameListCtrl::OnColBeginDrag(wxListEvent& event) { - const int column_id = event.GetColumn(); + const int column_id = event.GetColumn(); - if (column_id != COLUMN_TITLE && column_id != COLUMN_MAKER && column_id != COLUMN_FILENAME) - event.Veto(); + if (column_id != COLUMN_TITLE && column_id != COLUMN_MAKER && column_id != COLUMN_FILENAME) + event.Veto(); } const GameListItem* CGameListCtrl::GetISO(size_t index) const { - if (index < m_ISOFiles.size()) - return m_ISOFiles[index]; - else - return nullptr; + if (index < m_ISOFiles.size()) + return m_ISOFiles[index]; + else + return nullptr; } static CGameListCtrl* caller; static int wxCALLBACK wxListCompare(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData) { - // return 1 if item1 > item2 - // return -1 if item1 < item2 - // return 0 for identity - const GameListItem* iso1 = caller->GetISO(item1); - const GameListItem* iso2 = caller->GetISO(item2); + // return 1 if item1 > item2 + // return -1 if item1 < item2 + // return 0 for identity + const GameListItem* iso1 = caller->GetISO(item1); + const GameListItem* iso2 = caller->GetISO(item2); - return CompareGameListItems(iso1, iso2, sortData); + return CompareGameListItems(iso1, iso2, sortData); } void CGameListCtrl::OnColumnClick(wxListEvent& event) { - if (event.GetColumn() != COLUMN_BANNER) - { - int current_column = event.GetColumn(); - if (sorted) - { - if (last_column == current_column) - { - last_sort = -last_sort; - } - else - { - SConfig::GetInstance().m_ListSort2 = last_sort; - last_column = current_column; - last_sort = current_column; - } - SConfig::GetInstance().m_ListSort = last_sort; - } - else - { - last_sort = current_column; - last_column = current_column; - } - caller = this; - SortItems(wxListCompare, last_sort); - } + if (event.GetColumn() != COLUMN_BANNER) + { + int current_column = event.GetColumn(); + if (sorted) + { + if (last_column == current_column) + { + last_sort = -last_sort; + } + else + { + SConfig::GetInstance().m_ListSort2 = last_sort; + last_column = current_column; + last_sort = current_column; + } + SConfig::GetInstance().m_ListSort = last_sort; + } + else + { + last_sort = current_column; + last_column = current_column; + } + caller = this; + SortItems(wxListCompare, last_sort); + } - SetBackgroundColor(); + SetBackgroundColor(); - event.Skip(); + event.Skip(); } // This is used by keyboard gamelist search void CGameListCtrl::OnKeyPress(wxListEvent& event) { - static int lastKey = 0, sLoop = 0; - int Loop = 0; + static int lastKey = 0, sLoop = 0; + int Loop = 0; - for (int i = 0; i < (int)m_ISOFiles.size(); i++) - { - // Easy way to get game string - wxListItem bleh; - bleh.SetId(i); - bleh.SetColumn(COLUMN_TITLE); - bleh.SetMask(wxLIST_MASK_TEXT); - GetItem(bleh); + for (int i = 0; i < (int)m_ISOFiles.size(); i++) + { + // Easy way to get game string + wxListItem bleh; + bleh.SetId(i); + bleh.SetColumn(COLUMN_TITLE); + bleh.SetMask(wxLIST_MASK_TEXT); + GetItem(bleh); - wxString text = bleh.GetText(); + wxString text = bleh.GetText(); - if (text.MakeUpper()[0] == event.GetKeyCode()) - { - if (lastKey == event.GetKeyCode() && Loop < sLoop) - { - Loop++; - if (i+1 == (int)m_ISOFiles.size()) - i = -1; - continue; - } - else if (lastKey != event.GetKeyCode()) - { - sLoop = 0; - } + if (text.MakeUpper()[0] == event.GetKeyCode()) + { + if (lastKey == event.GetKeyCode() && Loop < sLoop) + { + Loop++; + if (i + 1 == (int)m_ISOFiles.size()) + i = -1; + continue; + } + else if (lastKey != event.GetKeyCode()) + { + sLoop = 0; + } - lastKey = event.GetKeyCode(); - sLoop++; + lastKey = event.GetKeyCode(); + sLoop++; - UnselectAll(); - SetItemState(i, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, - wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED); - EnsureVisible(i); - break; - } + UnselectAll(); + SetItemState(i, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED, + wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); + EnsureVisible(i); + break; + } - // If we get past the last game in the list, - // we'll have to go back to the first one. - if (i+1 == (int)m_ISOFiles.size() && sLoop > 0 && Loop > 0) - i = -1; - } + // If we get past the last game in the list, + // we'll have to go back to the first one. + if (i + 1 == (int)m_ISOFiles.size() && sLoop > 0 && Loop > 0) + i = -1; + } - event.Skip(); + event.Skip(); } // This shows a little tooltip with the current Game's emulation state void CGameListCtrl::OnMouseMotion(wxMouseEvent& event) { - int flags; - long subitem = 0; - const long item = HitTest(event.GetPosition(), flags, &subitem); - static int lastItem = -1; + int flags; + long subitem = 0; + const long item = HitTest(event.GetPosition(), flags, &subitem); + static int lastItem = -1; - if (GetColumnCount() <= 1) - return; + if (GetColumnCount() <= 1) + return; - if (item != wxNOT_FOUND) - { - wxRect Rect; + if (item != wxNOT_FOUND) + { + wxRect Rect; #ifdef __WXMSW__ - if (subitem == COLUMN_EMULATION_STATE) + if (subitem == COLUMN_EMULATION_STATE) #else - // The subitem parameter of HitTest is only implemented for wxMSW. On - // all other platforms it will always be -1. Check the x position - // instead. - GetItemRect(item, Rect); - if (Rect.GetX() + Rect.GetWidth() - GetColumnWidth(COLUMN_EMULATION_STATE) < event.GetX()) + // The subitem parameter of HitTest is only implemented for wxMSW. On + // all other platforms it will always be -1. Check the x position + // instead. + GetItemRect(item, Rect); + if (Rect.GetX() + Rect.GetWidth() - GetColumnWidth(COLUMN_EMULATION_STATE) < event.GetX()) #endif - { - if (toolTip || lastItem == item || this != FindFocus()) - { - if (lastItem != item) lastItem = -1; - event.Skip(); - return; - } + { + if (toolTip || lastItem == item || this != FindFocus()) + { + if (lastItem != item) + lastItem = -1; + event.Skip(); + return; + } - // Emulation status - static const char* const emuState[] = { "Broken", "Intro", "In-Game", "Playable", "Perfect" }; + // Emulation status + static const char* const emuState[] = {"Broken", "Intro", "In-Game", "Playable", "Perfect"}; - const GameListItem& rISO = *m_ISOFiles[GetItemData(item)]; + const GameListItem& rISO = *m_ISOFiles[GetItemData(item)]; - const int emu_state = rISO.GetEmuState(); - const std::string& issues = rISO.GetIssues(); + const int emu_state = rISO.GetEmuState(); + const std::string& issues = rISO.GetIssues(); - // Show a tooltip containing the EmuState and the state description - if (emu_state > 0 && emu_state < 6) - { - char temp[2048]; - sprintf(temp, "^ %s%s%s", emuState[emu_state - 1], - issues.size() > 0 ? " :\n" : "", issues.c_str()); - toolTip = new wxEmuStateTip(this, StrToWxStr(temp), &toolTip); - } - else - { - toolTip = new wxEmuStateTip(this, _("Not Set"), &toolTip); - } + // Show a tooltip containing the EmuState and the state description + if (emu_state > 0 && emu_state < 6) + { + char temp[2048]; + sprintf(temp, "^ %s%s%s", emuState[emu_state - 1], issues.size() > 0 ? " :\n" : "", + issues.c_str()); + toolTip = new wxEmuStateTip(this, StrToWxStr(temp), &toolTip); + } + else + { + toolTip = new wxEmuStateTip(this, _("Not Set"), &toolTip); + } - // Get item Coords - GetItemRect(item, Rect); - int mx = Rect.GetWidth(); - int my = Rect.GetY(); + // Get item Coords + GetItemRect(item, Rect); + int mx = Rect.GetWidth(); + int my = Rect.GetY(); #ifndef __WXMSW__ - // For some reason the y position does not account for the header - // row, so subtract the y position of the first visible item. - GetItemRect(GetTopItem(), Rect); - my -= Rect.GetY(); + // For some reason the y position does not account for the header + // row, so subtract the y position of the first visible item. + GetItemRect(GetTopItem(), Rect); + my -= Rect.GetY(); #endif - // Convert to screen coordinates - ClientToScreen(&mx, &my); - toolTip->SetBoundingRect(wxRect(mx - GetColumnWidth(COLUMN_EMULATION_STATE), - my, GetColumnWidth(COLUMN_EMULATION_STATE), Rect.GetHeight())); - toolTip->SetPosition(wxPoint(mx - GetColumnWidth(COLUMN_EMULATION_STATE), - my - 5 + Rect.GetHeight())); - lastItem = item; - } - } - if (!toolTip) - lastItem = -1; + // Convert to screen coordinates + ClientToScreen(&mx, &my); + toolTip->SetBoundingRect(wxRect(mx - GetColumnWidth(COLUMN_EMULATION_STATE), my, + GetColumnWidth(COLUMN_EMULATION_STATE), Rect.GetHeight())); + toolTip->SetPosition( + wxPoint(mx - GetColumnWidth(COLUMN_EMULATION_STATE), my - 5 + Rect.GetHeight())); + lastItem = item; + } + } + if (!toolTip) + lastItem = -1; - event.Skip(); + event.Skip(); } void CGameListCtrl::OnLeftClick(wxMouseEvent& event) { - // Focus the clicked item. - int flags; - long item = HitTest(event.GetPosition(), flags); - if ((item != wxNOT_FOUND) && (GetSelectedItemCount() == 0) && - (!event.ControlDown()) && (!event.ShiftDown())) - { - SetItemState(item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); - SetItemState(item, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED); - wxGetApp().GetCFrame()->UpdateGUI(); - } + // Focus the clicked item. + int flags; + long item = HitTest(event.GetPosition(), flags); + if ((item != wxNOT_FOUND) && (GetSelectedItemCount() == 0) && (!event.ControlDown()) && + (!event.ShiftDown())) + { + SetItemState(item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + SetItemState(item, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED); + wxGetApp().GetCFrame()->UpdateGUI(); + } - event.Skip(); + event.Skip(); } void CGameListCtrl::OnRightClick(wxMouseEvent& event) { - // Focus the clicked item. - int flags; - long item = HitTest(event.GetPosition(), flags); - if (item != wxNOT_FOUND) - { - if (GetItemState(item, wxLIST_STATE_SELECTED) != wxLIST_STATE_SELECTED) - { - UnselectAll(); - SetItemState(item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); - } - SetItemState(item, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED); - } - if (GetSelectedItemCount() == 1) - { - const GameListItem* selected_iso = GetSelectedISO(); - if (selected_iso) - { - wxMenu popupMenu; - DiscIO::IVolume::EPlatform platform = selected_iso->GetPlatform(); + // Focus the clicked item. + int flags; + long item = HitTest(event.GetPosition(), flags); + if (item != wxNOT_FOUND) + { + if (GetItemState(item, wxLIST_STATE_SELECTED) != wxLIST_STATE_SELECTED) + { + UnselectAll(); + SetItemState(item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + } + SetItemState(item, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED); + } + if (GetSelectedItemCount() == 1) + { + const GameListItem* selected_iso = GetSelectedISO(); + if (selected_iso) + { + wxMenu popupMenu; + DiscIO::IVolume::EPlatform platform = selected_iso->GetPlatform(); - if (platform != DiscIO::IVolume::ELF_DOL) - { - popupMenu.Append(IDM_PROPERTIES, _("&Properties")); - popupMenu.Append(IDM_GAME_WIKI, _("&Wiki")); - popupMenu.AppendSeparator(); - } - if (platform == DiscIO::IVolume::WII_DISC || platform == DiscIO::IVolume::WII_WAD) - { - popupMenu.Append(IDM_OPEN_SAVE_FOLDER, _("Open Wii &save folder")); - popupMenu.Append(IDM_EXPORT_SAVE, _("Export Wii save (Experimental)")); - } - popupMenu.Append(IDM_OPEN_CONTAINING_FOLDER, _("Open &containing folder")); + if (platform != DiscIO::IVolume::ELF_DOL) + { + popupMenu.Append(IDM_PROPERTIES, _("&Properties")); + popupMenu.Append(IDM_GAME_WIKI, _("&Wiki")); + popupMenu.AppendSeparator(); + } + if (platform == DiscIO::IVolume::WII_DISC || platform == DiscIO::IVolume::WII_WAD) + { + popupMenu.Append(IDM_OPEN_SAVE_FOLDER, _("Open Wii &save folder")); + popupMenu.Append(IDM_EXPORT_SAVE, _("Export Wii save (Experimental)")); + } + popupMenu.Append(IDM_OPEN_CONTAINING_FOLDER, _("Open &containing folder")); - if (platform != DiscIO::IVolume::ELF_DOL) - popupMenu.AppendCheckItem(IDM_SET_DEFAULT_ISO, _("Set as &default ISO")); + if (platform != DiscIO::IVolume::ELF_DOL) + popupMenu.AppendCheckItem(IDM_SET_DEFAULT_ISO, _("Set as &default ISO")); - // First we have to decide a starting value when we append it - if (platform == SConfig::GetInstance().m_strDefaultISO) - popupMenu.FindItem(IDM_SET_DEFAULT_ISO)->Check(); + // First we have to decide a starting value when we append it + if (platform == SConfig::GetInstance().m_strDefaultISO) + popupMenu.FindItem(IDM_SET_DEFAULT_ISO)->Check(); - popupMenu.AppendSeparator(); - popupMenu.Append(IDM_DELETE_ISO, _("&Delete File...")); + popupMenu.AppendSeparator(); + popupMenu.Append(IDM_DELETE_ISO, _("&Delete File...")); - if (platform == DiscIO::IVolume::GAMECUBE_DISC || platform == DiscIO::IVolume::WII_DISC) - { - if (selected_iso->GetBlobType() == DiscIO::BlobType::GCZ) - popupMenu.Append(IDM_COMPRESS_ISO, _("Decompress ISO...")); - else if (selected_iso->GetBlobType() == DiscIO::BlobType::PLAIN) - popupMenu.Append(IDM_COMPRESS_ISO, _("Compress ISO...")); + if (platform == DiscIO::IVolume::GAMECUBE_DISC || platform == DiscIO::IVolume::WII_DISC) + { + if (selected_iso->GetBlobType() == DiscIO::BlobType::GCZ) + popupMenu.Append(IDM_COMPRESS_ISO, _("Decompress ISO...")); + else if (selected_iso->GetBlobType() == DiscIO::BlobType::PLAIN) + popupMenu.Append(IDM_COMPRESS_ISO, _("Compress ISO...")); - wxMenuItem* changeDiscItem = popupMenu.Append(IDM_LIST_CHANGE_DISC, _("Change &Disc")); - changeDiscItem->Enable(Core::IsRunning()); - } + wxMenuItem* changeDiscItem = popupMenu.Append(IDM_LIST_CHANGE_DISC, _("Change &Disc")); + changeDiscItem->Enable(Core::IsRunning()); + } - if (platform == DiscIO::IVolume::WII_WAD) - popupMenu.Append(IDM_LIST_INSTALL_WAD, _("Install to Wii Menu")); + if (platform == DiscIO::IVolume::WII_WAD) + popupMenu.Append(IDM_LIST_INSTALL_WAD, _("Install to Wii Menu")); - PopupMenu(&popupMenu); - } - } - else if (GetSelectedItemCount() > 1) - { - wxMenu popupMenu; - popupMenu.Append(IDM_DELETE_ISO, _("&Delete selected ISOs...")); - popupMenu.AppendSeparator(); - popupMenu.Append(IDM_MULTI_COMPRESS_ISO, _("Compress selected ISOs...")); - popupMenu.Append(IDM_MULTI_DECOMPRESS_ISO, _("Decompress selected ISOs...")); - PopupMenu(&popupMenu); - } + PopupMenu(&popupMenu); + } + } + else if (GetSelectedItemCount() > 1) + { + wxMenu popupMenu; + popupMenu.Append(IDM_DELETE_ISO, _("&Delete selected ISOs...")); + popupMenu.AppendSeparator(); + popupMenu.Append(IDM_MULTI_COMPRESS_ISO, _("Compress selected ISOs...")); + popupMenu.Append(IDM_MULTI_DECOMPRESS_ISO, _("Decompress selected ISOs...")); + PopupMenu(&popupMenu); + } } const GameListItem* CGameListCtrl::GetSelectedISO() const { - if (m_ISOFiles.size() == 0) - { - return nullptr; - } - else if (GetSelectedItemCount() == 0) - { - return nullptr; - } - else - { - long item = GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (item == wxNOT_FOUND) - return nullptr; - return m_ISOFiles[GetItemData(item)]; - } + if (m_ISOFiles.size() == 0) + { + return nullptr; + } + else if (GetSelectedItemCount() == 0) + { + return nullptr; + } + else + { + long item = GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (item == wxNOT_FOUND) + return nullptr; + return m_ISOFiles[GetItemData(item)]; + } } std::vector CGameListCtrl::GetAllSelectedISOs() const { - std::vector result; - long item = -1; - while (true) - { - item = GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (item == wxNOT_FOUND) - return result; - result.push_back(m_ISOFiles[GetItemData(item)]); - } + std::vector result; + long item = -1; + while (true) + { + item = GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (item == wxNOT_FOUND) + return result; + result.push_back(m_ISOFiles[GetItemData(item)]); + } } bool CGameListCtrl::IsHidingItems() { - return !(SConfig::GetInstance().m_ListGC && - SConfig::GetInstance().m_ListWii && - SConfig::GetInstance().m_ListWad && - SConfig::GetInstance().m_ListElfDol && - SConfig::GetInstance().m_ListJap && - SConfig::GetInstance().m_ListUsa && - SConfig::GetInstance().m_ListPal && - SConfig::GetInstance().m_ListAustralia && - SConfig::GetInstance().m_ListFrance && - SConfig::GetInstance().m_ListGermany && - SConfig::GetInstance().m_ListItaly && - SConfig::GetInstance().m_ListKorea && - SConfig::GetInstance().m_ListNetherlands && - SConfig::GetInstance().m_ListRussia && - SConfig::GetInstance().m_ListSpain && - SConfig::GetInstance().m_ListTaiwan && - SConfig::GetInstance().m_ListWorld && - SConfig::GetInstance().m_ListUnknown); + return !(SConfig::GetInstance().m_ListGC && SConfig::GetInstance().m_ListWii && + SConfig::GetInstance().m_ListWad && SConfig::GetInstance().m_ListElfDol && + SConfig::GetInstance().m_ListJap && SConfig::GetInstance().m_ListUsa && + SConfig::GetInstance().m_ListPal && SConfig::GetInstance().m_ListAustralia && + SConfig::GetInstance().m_ListFrance && SConfig::GetInstance().m_ListGermany && + SConfig::GetInstance().m_ListItaly && SConfig::GetInstance().m_ListKorea && + SConfig::GetInstance().m_ListNetherlands && SConfig::GetInstance().m_ListRussia && + SConfig::GetInstance().m_ListSpain && SConfig::GetInstance().m_ListTaiwan && + SConfig::GetInstance().m_ListWorld && SConfig::GetInstance().m_ListUnknown); } -void CGameListCtrl::OnOpenContainingFolder(wxCommandEvent& WXUNUSED (event)) +void CGameListCtrl::OnOpenContainingFolder(wxCommandEvent& WXUNUSED(event)) { - const GameListItem* iso = GetSelectedISO(); - if (!iso) - return; + const GameListItem* iso = GetSelectedISO(); + if (!iso) + return; - wxFileName path = wxFileName::FileName(StrToWxStr(iso->GetFileName())); - path.MakeAbsolute(); - WxUtils::Explore(WxStrToStr(path.GetPath())); + wxFileName path = wxFileName::FileName(StrToWxStr(iso->GetFileName())); + path.MakeAbsolute(); + WxUtils::Explore(WxStrToStr(path.GetPath())); } -void CGameListCtrl::OnOpenSaveFolder(wxCommandEvent& WXUNUSED (event)) +void CGameListCtrl::OnOpenSaveFolder(wxCommandEvent& WXUNUSED(event)) { - const GameListItem* iso = GetSelectedISO(); - if (!iso) - return; - std::string path = iso->GetWiiFSPath(); - if (!path.empty()) - WxUtils::Explore(path); + const GameListItem* iso = GetSelectedISO(); + if (!iso) + return; + std::string path = iso->GetWiiFSPath(); + if (!path.empty()) + WxUtils::Explore(path); } -void CGameListCtrl::OnExportSave(wxCommandEvent& WXUNUSED (event)) +void CGameListCtrl::OnExportSave(wxCommandEvent& WXUNUSED(event)) { - const GameListItem* iso = GetSelectedISO(); - if (!iso) - return; + const GameListItem* iso = GetSelectedISO(); + if (!iso) + return; - u64 title_id; - std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(iso->GetFileName())); - if (volume && volume->GetTitleID(&title_id)) - { - CWiiSaveCrypted::ExportWiiSave(title_id); - } + u64 title_id; + std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(iso->GetFileName())); + if (volume && volume->GetTitleID(&title_id)) + { + CWiiSaveCrypted::ExportWiiSave(title_id); + } } // Save this file as the default file void CGameListCtrl::OnSetDefaultISO(wxCommandEvent& event) { - const GameListItem* iso = GetSelectedISO(); - if (!iso) return; + const GameListItem* iso = GetSelectedISO(); + if (!iso) + return; - if (event.IsChecked()) - { - // Write the new default value and save it the ini file - SConfig::GetInstance().m_strDefaultISO = - iso->GetFileName(); - SConfig::GetInstance().SaveSettings(); - } - else - { - // Otherwise blank the value and save it - SConfig::GetInstance().m_strDefaultISO = ""; - SConfig::GetInstance().SaveSettings(); - } + if (event.IsChecked()) + { + // Write the new default value and save it the ini file + SConfig::GetInstance().m_strDefaultISO = iso->GetFileName(); + SConfig::GetInstance().SaveSettings(); + } + else + { + // Otherwise blank the value and save it + SConfig::GetInstance().m_strDefaultISO = ""; + SConfig::GetInstance().SaveSettings(); + } } -void CGameListCtrl::OnDeleteISO(wxCommandEvent& WXUNUSED (event)) +void CGameListCtrl::OnDeleteISO(wxCommandEvent& WXUNUSED(event)) { - const wxString message = GetSelectedItemCount() == 1 ? - _("Are you sure you want to delete this file? It will be gone forever!") : - _("Are you sure you want to delete these files? They will be gone forever!"); + const wxString message = + GetSelectedItemCount() == 1 ? + _("Are you sure you want to delete this file? It will be gone forever!") : + _("Are you sure you want to delete these files? They will be gone forever!"); - if (wxMessageBox(message, _("Warning"), wxYES_NO | wxICON_EXCLAMATION) == wxYES) - { - for (const GameListItem* iso : GetAllSelectedISOs()) - File::Delete(iso->GetFileName()); - Update(); - } + if (wxMessageBox(message, _("Warning"), wxYES_NO | wxICON_EXCLAMATION) == wxYES) + { + for (const GameListItem* iso : GetAllSelectedISOs()) + File::Delete(iso->GetFileName()); + Update(); + } } -void CGameListCtrl::OnProperties(wxCommandEvent& WXUNUSED (event)) +void CGameListCtrl::OnProperties(wxCommandEvent& WXUNUSED(event)) { - const GameListItem* iso = GetSelectedISO(); - if (!iso) - return; + const GameListItem* iso = GetSelectedISO(); + if (!iso) + return; - CISOProperties* ISOProperties = new CISOProperties(*iso, this); - ISOProperties->Show(); + CISOProperties* ISOProperties = new CISOProperties(*iso, this); + ISOProperties->Show(); } -void CGameListCtrl::OnWiki(wxCommandEvent& WXUNUSED (event)) +void CGameListCtrl::OnWiki(wxCommandEvent& WXUNUSED(event)) { - const GameListItem* iso = GetSelectedISO(); - if (!iso) - return; + const GameListItem* iso = GetSelectedISO(); + if (!iso) + return; - std::string wikiUrl = "https://wiki.dolphin-emu.org/dolphin-redirect.php?gameid=" + iso->GetUniqueID(); - WxUtils::Launch(wikiUrl); + std::string wikiUrl = + "https://wiki.dolphin-emu.org/dolphin-redirect.php?gameid=" + iso->GetUniqueID(); + WxUtils::Launch(wikiUrl); } bool CGameListCtrl::MultiCompressCB(const std::string& text, float percent, void* arg) { - CompressionProgress* progress = static_cast(arg); + CompressionProgress* progress = static_cast(arg); - float total_percent = ((float)progress->items_done + percent) / (float)progress->items_total; - wxString text_string(StrToWxStr(StringFromFormat("%s (%i/%i) - %s", - progress->current_filename.c_str(), progress->items_done + 1, - progress->items_total, text.c_str()))); + float total_percent = ((float)progress->items_done + percent) / (float)progress->items_total; + wxString text_string( + StrToWxStr(StringFromFormat("%s (%i/%i) - %s", progress->current_filename.c_str(), + progress->items_done + 1, progress->items_total, text.c_str()))); - return progress->dialog->Update(total_percent * progress->dialog->GetRange(), text_string); + return progress->dialog->Update(total_percent * progress->dialog->GetRange(), text_string); } void CGameListCtrl::OnMultiCompressISO(wxCommandEvent& /*event*/) { - CompressSelection(true); + CompressSelection(true); } void CGameListCtrl::OnMultiDecompressISO(wxCommandEvent& /*event*/) { - CompressSelection(false); + CompressSelection(false); } void CGameListCtrl::CompressSelection(bool _compress) { - std::vector items_to_compress; - bool wii_compression_warning_accepted = false; - for (const GameListItem* iso : GetAllSelectedISOs()) - { - // Don't include items that we can't do anything with - if (iso->GetPlatform() != DiscIO::IVolume::GAMECUBE_DISC && iso->GetPlatform() != DiscIO::IVolume::WII_DISC) - continue; - if (iso->GetBlobType() != DiscIO::BlobType::PLAIN && iso->GetBlobType() != DiscIO::BlobType::GCZ) - continue; + std::vector items_to_compress; + bool wii_compression_warning_accepted = false; + for (const GameListItem* iso : GetAllSelectedISOs()) + { + // Don't include items that we can't do anything with + if (iso->GetPlatform() != DiscIO::IVolume::GAMECUBE_DISC && + iso->GetPlatform() != DiscIO::IVolume::WII_DISC) + continue; + if (iso->GetBlobType() != DiscIO::BlobType::PLAIN && + iso->GetBlobType() != DiscIO::BlobType::GCZ) + continue; - items_to_compress.push_back(iso); + items_to_compress.push_back(iso); - // Show the Wii compression warning if it's relevant and it hasn't been shown already - if (!wii_compression_warning_accepted && _compress && - !iso->IsCompressed() && iso->GetPlatform() == DiscIO::IVolume::WII_DISC) - { - if (WiiCompressWarning()) - wii_compression_warning_accepted = true; - else - return; - } - } + // Show the Wii compression warning if it's relevant and it hasn't been shown already + if (!wii_compression_warning_accepted && _compress && !iso->IsCompressed() && + iso->GetPlatform() == DiscIO::IVolume::WII_DISC) + { + if (WiiCompressWarning()) + wii_compression_warning_accepted = true; + else + return; + } + } - wxString dirHome; - wxGetHomeDir(&dirHome); + wxString dirHome; + wxGetHomeDir(&dirHome); - wxDirDialog browseDialog(this, _("Browse for output directory"), dirHome, - wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST); - if (browseDialog.ShowModal() != wxID_OK) - return; + wxDirDialog browseDialog(this, _("Browse for output directory"), dirHome, + wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST); + if (browseDialog.ShowModal() != wxID_OK) + return; - bool all_good = true; + bool all_good = true; - { - wxProgressDialog progressDialog( - _compress ? _("Compressing ISO") : _("Decompressing ISO"), - _("Working..."), - 1000, // Arbitrary number that's larger than the dialog's width in pixels - this, - wxPD_APP_MODAL | - wxPD_CAN_ABORT | - wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | - wxPD_SMOOTH - ); + { + wxProgressDialog progressDialog( + _compress ? _("Compressing ISO") : _("Decompressing ISO"), _("Working..."), + 1000, // Arbitrary number that's larger than the dialog's width in pixels + this, wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | + wxPD_REMAINING_TIME | wxPD_SMOOTH); - CompressionProgress progress(0, items_to_compress.size(), "", &progressDialog); + CompressionProgress progress(0, items_to_compress.size(), "", &progressDialog); - for (const GameListItem* iso : items_to_compress) - { - if (!iso->IsCompressed() && _compress) - { - std::string FileName; - SplitPath(iso->GetFileName(), nullptr, &FileName, nullptr); - progress.current_filename = FileName; - FileName.append(".gcz"); + for (const GameListItem* iso : items_to_compress) + { + if (!iso->IsCompressed() && _compress) + { + std::string FileName; + SplitPath(iso->GetFileName(), nullptr, &FileName, nullptr); + progress.current_filename = FileName; + FileName.append(".gcz"); - std::string OutputFileName; - BuildCompleteFilename(OutputFileName, - WxStrToStr(browseDialog.GetPath()), - FileName); + std::string OutputFileName; + BuildCompleteFilename(OutputFileName, WxStrToStr(browseDialog.GetPath()), FileName); - if (File::Exists(OutputFileName) && - wxMessageBox( - wxString::Format(_("The file %s already exists.\nDo you wish to replace it?"), - StrToWxStr(OutputFileName)), - _("Confirm File Overwrite"), - wxYES_NO) == wxNO) - continue; + if (File::Exists(OutputFileName) && + wxMessageBox( + wxString::Format(_("The file %s already exists.\nDo you wish to replace it?"), + StrToWxStr(OutputFileName)), + _("Confirm File Overwrite"), wxYES_NO) == wxNO) + continue; - all_good &= DiscIO::CompressFileToBlob(iso->GetFileName(), - OutputFileName, - (iso->GetPlatform() == DiscIO::IVolume::WII_DISC) ? 1 : 0, - 16384, &MultiCompressCB, &progress); - } - else if (iso->IsCompressed() && !_compress) - { - std::string FileName; - SplitPath(iso->GetFileName(), nullptr, &FileName, nullptr); - progress.current_filename = FileName; - if (iso->GetPlatform() == DiscIO::IVolume::WII_DISC) - FileName.append(".iso"); - else - FileName.append(".gcm"); + all_good &= + DiscIO::CompressFileToBlob(iso->GetFileName(), OutputFileName, + (iso->GetPlatform() == DiscIO::IVolume::WII_DISC) ? 1 : 0, + 16384, &MultiCompressCB, &progress); + } + else if (iso->IsCompressed() && !_compress) + { + std::string FileName; + SplitPath(iso->GetFileName(), nullptr, &FileName, nullptr); + progress.current_filename = FileName; + if (iso->GetPlatform() == DiscIO::IVolume::WII_DISC) + FileName.append(".iso"); + else + FileName.append(".gcm"); - std::string OutputFileName; - BuildCompleteFilename(OutputFileName, - WxStrToStr(browseDialog.GetPath()), - FileName); + std::string OutputFileName; + BuildCompleteFilename(OutputFileName, WxStrToStr(browseDialog.GetPath()), FileName); - if (File::Exists(OutputFileName) && - wxMessageBox( - wxString::Format(_("The file %s already exists.\nDo you wish to replace it?"), - StrToWxStr(OutputFileName)), - _("Confirm File Overwrite"), - wxYES_NO) == wxNO) - continue; + if (File::Exists(OutputFileName) && + wxMessageBox( + wxString::Format(_("The file %s already exists.\nDo you wish to replace it?"), + StrToWxStr(OutputFileName)), + _("Confirm File Overwrite"), wxYES_NO) == wxNO) + continue; - all_good &= DiscIO::DecompressBlobToFile(iso->GetFileName().c_str(), - OutputFileName.c_str(), &MultiCompressCB, &progress); - } + all_good &= DiscIO::DecompressBlobToFile(iso->GetFileName().c_str(), OutputFileName.c_str(), + &MultiCompressCB, &progress); + } - progress.items_done++; - } - } + progress.items_done++; + } + } - if (!all_good) - WxUtils::ShowErrorDialog(_("Dolphin was unable to complete the requested action.")); + if (!all_good) + WxUtils::ShowErrorDialog(_("Dolphin was unable to complete the requested action.")); - Update(); + Update(); } bool CGameListCtrl::CompressCB(const std::string& text, float percent, void* arg) { - return ((wxProgressDialog*)arg)-> - Update((int)(percent * 1000), StrToWxStr(text)); + return ((wxProgressDialog*)arg)->Update((int)(percent * 1000), StrToWxStr(text)); } -void CGameListCtrl::OnCompressISO(wxCommandEvent& WXUNUSED (event)) +void CGameListCtrl::OnCompressISO(wxCommandEvent& WXUNUSED(event)) { - const GameListItem* iso = GetSelectedISO(); - if (!iso) - return; + const GameListItem* iso = GetSelectedISO(); + if (!iso) + return; - bool is_compressed = iso->GetBlobType() == DiscIO::BlobType::GCZ; - wxString path; + bool is_compressed = iso->GetBlobType() == DiscIO::BlobType::GCZ; + wxString path; - std::string FileName, FilePath, FileExtension; - SplitPath(iso->GetFileName(), &FilePath, &FileName, &FileExtension); + std::string FileName, FilePath, FileExtension; + SplitPath(iso->GetFileName(), &FilePath, &FileName, &FileExtension); - do - { - if (is_compressed) - { - wxString FileType; - if (iso->GetPlatform() == DiscIO::IVolume::WII_DISC) - FileType = _("All Wii ISO files (iso)") + "|*.iso"; - else - FileType = _("All GameCube GCM files (gcm)") + "|*.gcm"; + do + { + if (is_compressed) + { + wxString FileType; + if (iso->GetPlatform() == DiscIO::IVolume::WII_DISC) + FileType = _("All Wii ISO files (iso)") + "|*.iso"; + else + FileType = _("All GameCube GCM files (gcm)") + "|*.gcm"; - path = wxFileSelector( - _("Save decompressed GCM/ISO"), - StrToWxStr(FilePath), - StrToWxStr(FileName) + FileType.After('*'), - wxEmptyString, - FileType + "|" + wxGetTranslation(wxALL_FILES), - wxFD_SAVE, - this); - } - else - { - if (iso->GetPlatform() == DiscIO::IVolume::WII_DISC && !WiiCompressWarning()) - return; + path = wxFileSelector(_("Save decompressed GCM/ISO"), StrToWxStr(FilePath), + StrToWxStr(FileName) + FileType.After('*'), wxEmptyString, + FileType + "|" + wxGetTranslation(wxALL_FILES), wxFD_SAVE, this); + } + else + { + if (iso->GetPlatform() == DiscIO::IVolume::WII_DISC && !WiiCompressWarning()) + return; - path = wxFileSelector( - _("Save compressed GCM/ISO"), - StrToWxStr(FilePath), - StrToWxStr(FileName) + ".gcz", - wxEmptyString, - _("All compressed GC/Wii ISO files (gcz)") + - wxString::Format("|*.gcz|%s", wxGetTranslation(wxALL_FILES)), - wxFD_SAVE, - this); - } - if (!path) - return; - } while (wxFileExists(path) && - wxMessageBox( - wxString::Format(_("The file %s already exists.\nDo you wish to replace it?"), path.c_str()), - _("Confirm File Overwrite"), - wxYES_NO) == wxNO); + path = wxFileSelector(_("Save compressed GCM/ISO"), StrToWxStr(FilePath), + StrToWxStr(FileName) + ".gcz", wxEmptyString, + _("All compressed GC/Wii ISO files (gcz)") + + wxString::Format("|*.gcz|%s", wxGetTranslation(wxALL_FILES)), + wxFD_SAVE, this); + } + if (!path) + return; + } while ( + wxFileExists(path) && + wxMessageBox(wxString::Format(_("The file %s already exists.\nDo you wish to replace it?"), + path.c_str()), + _("Confirm File Overwrite"), wxYES_NO) == wxNO); - bool all_good = false; + bool all_good = false; - { - wxProgressDialog dialog( - is_compressed ? _("Decompressing ISO") : _("Compressing ISO"), - _("Working..."), - 1000, - this, - wxPD_APP_MODAL | - wxPD_CAN_ABORT | - wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | - wxPD_SMOOTH - ); + { + wxProgressDialog dialog(is_compressed ? _("Decompressing ISO") : _("Compressing ISO"), + _("Working..."), 1000, this, + wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME | + wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_SMOOTH); + if (is_compressed) + all_good = + DiscIO::DecompressBlobToFile(iso->GetFileName(), WxStrToStr(path), &CompressCB, &dialog); + else + all_good = DiscIO::CompressFileToBlob( + iso->GetFileName(), WxStrToStr(path), + (iso->GetPlatform() == DiscIO::IVolume::WII_DISC) ? 1 : 0, 16384, &CompressCB, &dialog); + } - if (is_compressed) - all_good = DiscIO::DecompressBlobToFile(iso->GetFileName(), - WxStrToStr(path), &CompressCB, &dialog); - else - all_good = DiscIO::CompressFileToBlob(iso->GetFileName(), - WxStrToStr(path), - (iso->GetPlatform() == DiscIO::IVolume::WII_DISC) ? 1 : 0, - 16384, &CompressCB, &dialog); - } + if (!all_good) + WxUtils::ShowErrorDialog(_("Dolphin was unable to complete the requested action.")); - if (!all_good) - WxUtils::ShowErrorDialog(_("Dolphin was unable to complete the requested action.")); - - Update(); + Update(); } void CGameListCtrl::OnChangeDisc(wxCommandEvent& WXUNUSED(event)) { - const GameListItem* iso = GetSelectedISO(); - if (!iso || !Core::IsRunning()) - return; - DVDInterface::ChangeDisc(WxStrToStr(iso->GetFileName())); + const GameListItem* iso = GetSelectedISO(); + if (!iso || !Core::IsRunning()) + return; + DVDInterface::ChangeDisc(WxStrToStr(iso->GetFileName())); } void CGameListCtrl::OnSize(wxSizeEvent& event) { - event.Skip(); - if (lastpos == event.GetSize()) - return; + event.Skip(); + if (lastpos == event.GetSize()) + return; - lastpos = event.GetSize(); - AutomaticColumnWidth(); + lastpos = event.GetSize(); + AutomaticColumnWidth(); } void CGameListCtrl::AutomaticColumnWidth() { - wxRect rc(GetClientRect()); + wxRect rc(GetClientRect()); - Freeze(); - if (GetColumnCount() == 1) - { - SetColumnWidth(0, rc.GetWidth()); - } - else if (GetColumnCount() > 0) - { - int resizable = rc.GetWidth() - ( - GetColumnWidth(COLUMN_PLATFORM) - + GetColumnWidth(COLUMN_BANNER) - + GetColumnWidth(COLUMN_ID) - + GetColumnWidth(COLUMN_COUNTRY) - + GetColumnWidth(COLUMN_SIZE) - + GetColumnWidth(COLUMN_EMULATION_STATE)); + Freeze(); + if (GetColumnCount() == 1) + { + SetColumnWidth(0, rc.GetWidth()); + } + else if (GetColumnCount() > 0) + { + int resizable = + rc.GetWidth() - (GetColumnWidth(COLUMN_PLATFORM) + GetColumnWidth(COLUMN_BANNER) + + GetColumnWidth(COLUMN_ID) + GetColumnWidth(COLUMN_COUNTRY) + + GetColumnWidth(COLUMN_SIZE) + GetColumnWidth(COLUMN_EMULATION_STATE)); - if (SConfig::GetInstance().m_showMakerColumn && - SConfig::GetInstance().m_showFileNameColumn) - { - SetColumnWidth(COLUMN_TITLE, resizable / 3); - SetColumnWidth(COLUMN_MAKER, resizable / 3); - SetColumnWidth(COLUMN_FILENAME, resizable / 3); - } - else if (SConfig::GetInstance().m_showMakerColumn) - { - SetColumnWidth(COLUMN_TITLE, resizable / 2); - SetColumnWidth(COLUMN_MAKER, resizable / 2); - } - else if (SConfig::GetInstance().m_showFileNameColumn) - { - SetColumnWidth(COLUMN_TITLE, resizable / 2); - SetColumnWidth(COLUMN_FILENAME, resizable / 2); - } - else - { - SetColumnWidth(COLUMN_TITLE, resizable); - } - } - Thaw(); + if (SConfig::GetInstance().m_showMakerColumn && SConfig::GetInstance().m_showFileNameColumn) + { + SetColumnWidth(COLUMN_TITLE, resizable / 3); + SetColumnWidth(COLUMN_MAKER, resizable / 3); + SetColumnWidth(COLUMN_FILENAME, resizable / 3); + } + else if (SConfig::GetInstance().m_showMakerColumn) + { + SetColumnWidth(COLUMN_TITLE, resizable / 2); + SetColumnWidth(COLUMN_MAKER, resizable / 2); + } + else if (SConfig::GetInstance().m_showFileNameColumn) + { + SetColumnWidth(COLUMN_TITLE, resizable / 2); + SetColumnWidth(COLUMN_FILENAME, resizable / 2); + } + else + { + SetColumnWidth(COLUMN_TITLE, resizable); + } + } + Thaw(); } void CGameListCtrl::UnselectAll() { - for (int i = 0; i < GetItemCount(); i++) - { - SetItemState(i, 0, wxLIST_STATE_SELECTED); - } + for (int i = 0; i < GetItemCount(); i++) + { + SetItemState(i, 0, wxLIST_STATE_SELECTED); + } } bool CGameListCtrl::WiiCompressWarning() { - return wxMessageBox( - _("Compressing a Wii disc image will irreversibly change the compressed copy by removing padding data. Your disc image will still work. Continue?"), - _("Warning"), - wxYES_NO) == wxYES; + return wxMessageBox(_("Compressing a Wii disc image will irreversibly change the compressed copy " + "by removing padding data. Your disc image will still work. Continue?"), + _("Warning"), wxYES_NO) == wxYES; } diff --git a/Source/Core/DolphinWX/GameListCtrl.h b/Source/Core/DolphinWX/GameListCtrl.h index 6914d23fb6..4c23aa5941 100644 --- a/Source/Core/DolphinWX/GameListCtrl.h +++ b/Source/Core/DolphinWX/GameListCtrl.h @@ -16,99 +16,102 @@ class wxEmuStateTip : public wxTipWindow { public: - wxEmuStateTip(wxWindow* parent, const wxString& text, wxEmuStateTip** windowPtr) - : wxTipWindow(parent, text, 70, (wxTipWindow**)windowPtr) - { - Bind(wxEVT_KEY_DOWN, &wxEmuStateTip::OnKeyDown, this); - } + wxEmuStateTip(wxWindow* parent, const wxString& text, wxEmuStateTip** windowPtr) + : wxTipWindow(parent, text, 70, (wxTipWindow**)windowPtr) + { + Bind(wxEVT_KEY_DOWN, &wxEmuStateTip::OnKeyDown, this); + } - // wxTipWindow doesn't correctly handle KeyEvents and crashes... we must overload that. - void OnKeyDown(wxKeyEvent& event) { event.StopPropagation(); Close(); } + // wxTipWindow doesn't correctly handle KeyEvents and crashes... we must overload that. + void OnKeyDown(wxKeyEvent& event) + { + event.StopPropagation(); + Close(); + } }; class CGameListCtrl : public wxListCtrl { public: + CGameListCtrl(wxWindow* parent, const wxWindowID id, const wxPoint& pos, const wxSize& size, + long style); + ~CGameListCtrl(); - CGameListCtrl(wxWindow* parent, const wxWindowID id, const wxPoint& pos, const wxSize& size, long style); - ~CGameListCtrl(); + void Update() override; - void Update() override; + void BrowseForDirectory(); + const GameListItem* GetISO(size_t index) const; + const GameListItem* GetSelectedISO() const; + std::vector GetAllSelectedISOs() const; - void BrowseForDirectory(); - const GameListItem* GetISO(size_t index) const; - const GameListItem* GetSelectedISO() const; - std::vector GetAllSelectedISOs() const; + static bool IsHidingItems(); - static bool IsHidingItems(); - - enum - { - COLUMN_DUMMY = 0, - COLUMN_PLATFORM, - COLUMN_BANNER, - COLUMN_TITLE, - COLUMN_MAKER, - COLUMN_FILENAME, - COLUMN_ID, - COLUMN_COUNTRY, - COLUMN_SIZE, - COLUMN_EMULATION_STATE, - NUMBER_OF_COLUMN - }; + enum + { + COLUMN_DUMMY = 0, + COLUMN_PLATFORM, + COLUMN_BANNER, + COLUMN_TITLE, + COLUMN_MAKER, + COLUMN_FILENAME, + COLUMN_ID, + COLUMN_COUNTRY, + COLUMN_SIZE, + COLUMN_EMULATION_STATE, + NUMBER_OF_COLUMN + }; private: + std::vector m_FlagImageIndex; + std::vector m_PlatformImageIndex; + std::vector m_EmuStateImageIndex; + std::vector m_ISOFiles; - std::vector m_FlagImageIndex; - std::vector m_PlatformImageIndex; - std::vector m_EmuStateImageIndex; - std::vector m_ISOFiles; + void ClearIsoFiles() + { + while (!m_ISOFiles.empty()) // so lazy + { + delete m_ISOFiles.back(); + m_ISOFiles.pop_back(); + } + } - void ClearIsoFiles() - { - while (!m_ISOFiles.empty()) // so lazy - { - delete m_ISOFiles.back(); - m_ISOFiles.pop_back(); - } - } + int last_column; + int last_sort; + wxSize lastpos; + wxEmuStateTip* toolTip; + void InitBitmaps(); + void UpdateItemAtColumn(long _Index, int column); + void InsertItemInReportView(long _Index); + void SetBackgroundColor(); + void ScanForISOs(); - int last_column; - int last_sort; - wxSize lastpos; - wxEmuStateTip *toolTip; - void InitBitmaps(); - void UpdateItemAtColumn(long _Index, int column); - void InsertItemInReportView(long _Index); - void SetBackgroundColor(); - void ScanForISOs(); + // events + void OnLeftClick(wxMouseEvent& event); + void OnRightClick(wxMouseEvent& event); + void OnMouseMotion(wxMouseEvent& event); + void OnColumnClick(wxListEvent& event); + void OnColBeginDrag(wxListEvent& event); + void OnKeyPress(wxListEvent& event); + void OnSize(wxSizeEvent& event); + void OnProperties(wxCommandEvent& event); + void OnWiki(wxCommandEvent& event); + void OnOpenContainingFolder(wxCommandEvent& event); + void OnOpenSaveFolder(wxCommandEvent& event); + void OnExportSave(wxCommandEvent& event); + void OnSetDefaultISO(wxCommandEvent& event); + void OnDeleteISO(wxCommandEvent& event); + void OnCompressISO(wxCommandEvent& event); + void OnMultiCompressISO(wxCommandEvent& event); + void OnMultiDecompressISO(wxCommandEvent& event); + void OnChangeDisc(wxCommandEvent& event); + void OnLocalIniModified(wxCommandEvent& event); - // events - void OnLeftClick(wxMouseEvent& event); - void OnRightClick(wxMouseEvent& event); - void OnMouseMotion(wxMouseEvent& event); - void OnColumnClick(wxListEvent& event); - void OnColBeginDrag(wxListEvent& event); - void OnKeyPress(wxListEvent& event); - void OnSize(wxSizeEvent& event); - void OnProperties(wxCommandEvent& event); - void OnWiki(wxCommandEvent& event); - void OnOpenContainingFolder(wxCommandEvent& event); - void OnOpenSaveFolder(wxCommandEvent& event); - void OnExportSave(wxCommandEvent& event); - void OnSetDefaultISO(wxCommandEvent& event); - void OnDeleteISO(wxCommandEvent& event); - void OnCompressISO(wxCommandEvent& event); - void OnMultiCompressISO(wxCommandEvent& event); - void OnMultiDecompressISO(wxCommandEvent& event); - void OnChangeDisc(wxCommandEvent& event); - void OnLocalIniModified(wxCommandEvent& event); + void CompressSelection(bool _compress); + void AutomaticColumnWidth(); + void UnselectAll(); - void CompressSelection(bool _compress); - void AutomaticColumnWidth(); - void UnselectAll(); - - static bool CompressCB(const std::string& text, float percent, void* arg); - static bool MultiCompressCB(const std::string& text, float percent, void* arg); - static bool WiiCompressWarning(); + static bool CompressCB(const std::string& text, float percent, void* arg); + static bool MultiCompressCB(const std::string& text, float percent, void* arg); + static bool WiiCompressWarning(); }; diff --git a/Source/Core/DolphinWX/Globals.h b/Source/Core/DolphinWX/Globals.h index ef41b61e79..f5364e7e6b 100644 --- a/Source/Core/DolphinWX/Globals.h +++ b/Source/Core/DolphinWX/Globals.h @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // This file holds global data for DolphinWx and DebuggerWx #pragma once @@ -12,326 +11,335 @@ enum { - Toolbar_Step, - Toolbar_StepOver, - Toolbar_StepOut, - Toolbar_Skip, - Toolbar_GotoPC, - Toolbar_SetPC, - Toolbar_Debug_Bitmap_Max + Toolbar_Step, + Toolbar_StepOver, + Toolbar_StepOut, + Toolbar_Skip, + Toolbar_GotoPC, + Toolbar_SetPC, + Toolbar_Debug_Bitmap_Max }; enum { - // Emulation menu - IDM_LOAD_STATE = 200, - IDM_SAVE_STATE, - IDM_SELECT_SLOT, - IDM_SAVE_FIRST_STATE, - IDM_UNDO_LOAD_STATE, - IDM_UNDO_SAVE_STATE, - IDM_LOAD_STATE_FILE, - IDM_SAVE_STATE_FILE, - IDM_SAVE_SLOT_1, - IDM_SAVE_SLOT_2, - IDM_SAVE_SLOT_3, - IDM_SAVE_SLOT_4, - IDM_SAVE_SLOT_5, - IDM_SAVE_SLOT_6, - IDM_SAVE_SLOT_7, - IDM_SAVE_SLOT_8, - IDM_SAVE_SLOT_9, - IDM_SAVE_SLOT_10, - IDM_LOAD_SLOT_1, - IDM_LOAD_SLOT_2, - IDM_LOAD_SLOT_3, - IDM_LOAD_SLOT_4, - IDM_LOAD_SLOT_5, - IDM_LOAD_SLOT_6, - IDM_LOAD_SLOT_7, - IDM_LOAD_SLOT_8, - IDM_LOAD_SLOT_9, - IDM_LOAD_SLOT_10, - IDM_LOAD_LAST_1, - IDM_LOAD_LAST_2, - IDM_LOAD_LAST_3, - IDM_LOAD_LAST_4, - IDM_LOAD_LAST_5, - IDM_LOAD_LAST_6, - IDM_LOAD_LAST_7, - IDM_LOAD_LAST_8, - IDM_LOAD_LAST_9, - IDM_LOAD_LAST_10, - IDM_SELECT_SLOT_1, - IDM_SELECT_SLOT_2, - IDM_SELECT_SLOT_3, - IDM_SELECT_SLOT_4, - IDM_SELECT_SLOT_5, - IDM_SELECT_SLOT_6, - IDM_SELECT_SLOT_7, - IDM_SELECT_SLOT_8, - IDM_SELECT_SLOT_9, - IDM_SELECT_SLOT_10, - IDM_SAVE_SELECTED_SLOT, - IDM_LOAD_SELECTED_SLOT, - IDM_FRAME_SKIP_0, - IDM_FRAME_SKIP_1, - IDM_FRAME_SKIP_2, - IDM_FRAME_SKIP_3, - IDM_FRAME_SKIP_4, - IDM_FRAME_SKIP_5, - IDM_FRAME_SKIP_6, - IDM_FRAME_SKIP_7, - IDM_FRAME_SKIP_8, - IDM_FRAME_SKIP_9, - IDM_PLAY, - IDM_STOP, - IDM_RESET, - IDM_TOGGLE_FULLSCREEN, + // Emulation menu + IDM_LOAD_STATE = 200, + IDM_SAVE_STATE, + IDM_SELECT_SLOT, + IDM_SAVE_FIRST_STATE, + IDM_UNDO_LOAD_STATE, + IDM_UNDO_SAVE_STATE, + IDM_LOAD_STATE_FILE, + IDM_SAVE_STATE_FILE, + IDM_SAVE_SLOT_1, + IDM_SAVE_SLOT_2, + IDM_SAVE_SLOT_3, + IDM_SAVE_SLOT_4, + IDM_SAVE_SLOT_5, + IDM_SAVE_SLOT_6, + IDM_SAVE_SLOT_7, + IDM_SAVE_SLOT_8, + IDM_SAVE_SLOT_9, + IDM_SAVE_SLOT_10, + IDM_LOAD_SLOT_1, + IDM_LOAD_SLOT_2, + IDM_LOAD_SLOT_3, + IDM_LOAD_SLOT_4, + IDM_LOAD_SLOT_5, + IDM_LOAD_SLOT_6, + IDM_LOAD_SLOT_7, + IDM_LOAD_SLOT_8, + IDM_LOAD_SLOT_9, + IDM_LOAD_SLOT_10, + IDM_LOAD_LAST_1, + IDM_LOAD_LAST_2, + IDM_LOAD_LAST_3, + IDM_LOAD_LAST_4, + IDM_LOAD_LAST_5, + IDM_LOAD_LAST_6, + IDM_LOAD_LAST_7, + IDM_LOAD_LAST_8, + IDM_LOAD_LAST_9, + IDM_LOAD_LAST_10, + IDM_SELECT_SLOT_1, + IDM_SELECT_SLOT_2, + IDM_SELECT_SLOT_3, + IDM_SELECT_SLOT_4, + IDM_SELECT_SLOT_5, + IDM_SELECT_SLOT_6, + IDM_SELECT_SLOT_7, + IDM_SELECT_SLOT_8, + IDM_SELECT_SLOT_9, + IDM_SELECT_SLOT_10, + IDM_SAVE_SELECTED_SLOT, + IDM_LOAD_SELECTED_SLOT, + IDM_FRAME_SKIP_0, + IDM_FRAME_SKIP_1, + IDM_FRAME_SKIP_2, + IDM_FRAME_SKIP_3, + IDM_FRAME_SKIP_4, + IDM_FRAME_SKIP_5, + IDM_FRAME_SKIP_6, + IDM_FRAME_SKIP_7, + IDM_FRAME_SKIP_8, + IDM_FRAME_SKIP_9, + IDM_PLAY, + IDM_STOP, + IDM_RESET, + IDM_TOGGLE_FULLSCREEN, - // Movie menu - IDM_RECORD, - IDM_PLAY_RECORD, - IDM_RECORD_EXPORT, - IDM_RECORD_READ_ONLY, - IDM_TAS_INPUT, - IDM_TOGGLE_PAUSE_MOVIE, - IDM_SHOW_LAG, - IDM_SHOW_FRAME_COUNT, - IDM_SHOW_INPUT_DISPLAY, - IDM_FRAMESTEP, - IDM_SCREENSHOT, - IDM_TOGGLE_DUMP_FRAMES, - IDM_TOGGLE_DUMP_AUDIO, + // Movie menu + IDM_RECORD, + IDM_PLAY_RECORD, + IDM_RECORD_EXPORT, + IDM_RECORD_READ_ONLY, + IDM_TAS_INPUT, + IDM_TOGGLE_PAUSE_MOVIE, + IDM_SHOW_LAG, + IDM_SHOW_FRAME_COUNT, + IDM_SHOW_INPUT_DISPLAY, + IDM_FRAMESTEP, + IDM_SCREENSHOT, + IDM_TOGGLE_DUMP_FRAMES, + IDM_TOGGLE_DUMP_AUDIO, - // File menu - IDM_DRIVES, - IDM_DRIVE1, - IDM_DRIVE24 = IDM_DRIVE1 + 23,//248, + // File menu + IDM_DRIVES, + IDM_DRIVE1, + IDM_DRIVE24 = IDM_DRIVE1 + 23, // 248, - // Tools menu - IDM_MEMCARD, - IDM_CHEATS, - IDM_NETPLAY, - IDM_RESTART, - IDM_CHANGE_DISC, - IDM_LIST_CHANGE_DISC, - IDM_PROPERTIES, - IDM_GAME_WIKI, - IDM_LOAD_WII_MENU, - IDM_MENU_INSTALL_WAD, - IDM_LIST_INSTALL_WAD, - IDM_FIFOPLAYER, - IDM_CONNECT_WIIMOTE1, - IDM_CONNECT_WIIMOTE2, - IDM_CONNECT_WIIMOTE3, - IDM_CONNECT_WIIMOTE4, - IDM_CONNECT_BALANCEBOARD, + // Tools menu + IDM_MEMCARD, + IDM_CHEATS, + IDM_NETPLAY, + IDM_RESTART, + IDM_CHANGE_DISC, + IDM_LIST_CHANGE_DISC, + IDM_PROPERTIES, + IDM_GAME_WIKI, + IDM_LOAD_WII_MENU, + IDM_MENU_INSTALL_WAD, + IDM_LIST_INSTALL_WAD, + IDM_FIFOPLAYER, + IDM_CONNECT_WIIMOTE1, + IDM_CONNECT_WIIMOTE2, + IDM_CONNECT_WIIMOTE3, + IDM_CONNECT_WIIMOTE4, + IDM_CONNECT_BALANCEBOARD, - // View menu - IDM_LIST_WAD, - IDM_LIST_WII, - IDM_LIST_GC, - IDM_LIST_ELFDOL, - IDM_LIST_JAP, - IDM_LIST_PAL, - IDM_LIST_USA, - IDM_LIST_AUSTRALIA, - IDM_LIST_FRANCE, - IDM_LIST_GERMANY, - IDM_LIST_ITALY, - IDM_LIST_KOREA, - IDM_LIST_NETHERLANDS, - IDM_LIST_RUSSIA, - IDM_LIST_SPAIN, - IDM_LIST_TAIWAN, - IDM_LIST_WORLD, - IDM_LIST_UNKNOWN, - IDM_LIST_DRIVES, - IDM_PURGE_GAME_LIST_CACHE, + // View menu + IDM_LIST_WAD, + IDM_LIST_WII, + IDM_LIST_GC, + IDM_LIST_ELFDOL, + IDM_LIST_JAP, + IDM_LIST_PAL, + IDM_LIST_USA, + IDM_LIST_AUSTRALIA, + IDM_LIST_FRANCE, + IDM_LIST_GERMANY, + IDM_LIST_ITALY, + IDM_LIST_KOREA, + IDM_LIST_NETHERLANDS, + IDM_LIST_RUSSIA, + IDM_LIST_SPAIN, + IDM_LIST_TAIWAN, + IDM_LIST_WORLD, + IDM_LIST_UNKNOWN, + IDM_LIST_DRIVES, + IDM_PURGE_GAME_LIST_CACHE, - // Help menu - IDM_HELP_WEBSITE, - IDM_HELP_ONLINE_DOCS, - IDM_HELP_GITHUB, + // Help menu + IDM_HELP_WEBSITE, + IDM_HELP_ONLINE_DOCS, + IDM_HELP_GITHUB, - // Options menu - IDM_CONFIG_GFX_BACKEND, - IDM_CONFIG_AUDIO, - IDM_CONFIG_CONTROLLERS, - IDM_CONFIG_HOTKEYS, - IDM_CONFIG_LOGGER, + // Options menu + IDM_CONFIG_GFX_BACKEND, + IDM_CONFIG_AUDIO, + IDM_CONFIG_CONTROLLERS, + IDM_CONFIG_HOTKEYS, + IDM_CONFIG_LOGGER, - // Views - IDM_LOG_WINDOW, - IDM_LOG_CONFIG_WINDOW, - IDM_REGISTER_WINDOW, - IDM_WATCH_WINDOW, - IDM_BREAKPOINT_WINDOW, - IDM_MEMORY_WINDOW, - IDM_JIT_WINDOW, - IDM_SOUND_WINDOW, - IDM_VIDEO_WINDOW, - IDM_CODE_WINDOW, + // Views + IDM_LOG_WINDOW, + IDM_LOG_CONFIG_WINDOW, + IDM_REGISTER_WINDOW, + IDM_WATCH_WINDOW, + IDM_BREAKPOINT_WINDOW, + IDM_MEMORY_WINDOW, + IDM_JIT_WINDOW, + IDM_SOUND_WINDOW, + IDM_VIDEO_WINDOW, + IDM_CODE_WINDOW, - // List Column Title Toggles - IDM_SHOW_SYSTEM, - IDM_SHOW_BANNER, - IDM_SHOW_MAKER, - IDM_SHOW_FILENAME, - IDM_SHOW_ID, - IDM_SHOW_REGION, - IDM_SHOW_SIZE, - IDM_SHOW_STATE, + // List Column Title Toggles + IDM_SHOW_SYSTEM, + IDM_SHOW_BANNER, + IDM_SHOW_MAKER, + IDM_SHOW_FILENAME, + IDM_SHOW_ID, + IDM_SHOW_REGION, + IDM_SHOW_SIZE, + IDM_SHOW_STATE, + // Float Window IDs + IDM_LOG_WINDOW_PARENT, + IDM_LOG_CONFIG_WINDOW_PARENT, + IDM_REGISTER_WINDOW_PARENT, + IDM_BREAKPOINT_WINDOW_PARENT, + IDM_MEMORY_WINDOW_PARENT, + IDM_JIT_WINDOW_PARENT, + IDM_SOUND_WINDOW_PARENT, + IDM_VIDEO_WINDOW_PARENT, + IDM_CODE_WINDOW_PARENT, - // Float Window IDs - IDM_LOG_WINDOW_PARENT, - IDM_LOG_CONFIG_WINDOW_PARENT, - IDM_REGISTER_WINDOW_PARENT, - IDM_BREAKPOINT_WINDOW_PARENT, - IDM_MEMORY_WINDOW_PARENT, - IDM_JIT_WINDOW_PARENT, - IDM_SOUND_WINDOW_PARENT, - IDM_VIDEO_WINDOW_PARENT, - IDM_CODE_WINDOW_PARENT, + // Float popup menu IDs + IDM_FLOAT_LOG_WINDOW, + IDM_FLOAT_LOG_CONFIG_WINDOW, + IDM_FLOAT_REGISTER_WINDOW, + IDM_FLOAT_BREAKPOINT_WINDOW, + IDM_FLOAT_MEMORY_WINDOW, + IDM_FLOAT_JIT_WINDOW, + IDM_FLOAT_SOUND_WINDOW, + IDM_FLOAT_VIDEO_WINDOW, + IDM_FLOAT_CODE_WINDOW, - // Float popup menu IDs - IDM_FLOAT_LOG_WINDOW, - IDM_FLOAT_LOG_CONFIG_WINDOW, - IDM_FLOAT_REGISTER_WINDOW, - IDM_FLOAT_BREAKPOINT_WINDOW, - IDM_FLOAT_MEMORY_WINDOW, - IDM_FLOAT_JIT_WINDOW, - IDM_FLOAT_SOUND_WINDOW, - IDM_FLOAT_VIDEO_WINDOW, - IDM_FLOAT_CODE_WINDOW, + // -------------------------------------------------------------- + // Debugger Menu Entries + // -------------------- + // CPU Mode + IDM_INTERPRETER, + IDM_AUTOMATIC_START, + IDM_BOOT_TO_PAUSE, + IDM_JIT_NO_BLOCK_CACHE, + IDM_JIT_NO_BLOCK_LINKING, // JIT + IDM_JIT_OFF, + IDM_JIT_LS_OFF, + IDM_JIT_LSLXZ_OFF, + IDM_JIT_LSLWZ_OFF, + IDM_JIT_LSLBZX_OFF, + IDM_JIT_LSP_OFF, + IDM_JIT_LSF_OFF, + IDM_JIT_I_OFF, + IDM_JIT_FP_OFF, + IDM_JIT_P_OFF, + IDM_JIT_SR_OFF, + IDM_FONT_PICKER, - // -------------------------------------------------------------- - // Debugger Menu Entries - // -------------------- - // CPU Mode - IDM_INTERPRETER, - IDM_AUTOMATIC_START, IDM_BOOT_TO_PAUSE, - IDM_JIT_NO_BLOCK_CACHE, IDM_JIT_NO_BLOCK_LINKING, // JIT - IDM_JIT_OFF, - IDM_JIT_LS_OFF, IDM_JIT_LSLXZ_OFF, IDM_JIT_LSLWZ_OFF, IDM_JIT_LSLBZX_OFF, - IDM_JIT_LSP_OFF, IDM_JIT_LSF_OFF, - IDM_JIT_I_OFF, - IDM_JIT_FP_OFF, - IDM_JIT_P_OFF, - IDM_JIT_SR_OFF, - IDM_FONT_PICKER, + // Symbols + IDM_CLEAR_SYMBOLS, + IDM_SCAN_FUNCTIONS, + IDM_LOAD_MAP_FILE, + IDM_LOAD_MAP_FILE_AS, + IDM_LOAD_BAD_MAP_FILE, + IDM_SAVEMAPFILE, + IDM_SAVE_MAP_FILE_WITH_CODES, + IDM_SAVE_MAP_FILE_AS, + IDM_CREATE_SIGNATURE_FILE, + IDM_APPEND_SIGNATURE_FILE, + IDM_COMBINE_SIGNATURE_FILES, + IDM_RENAME_SYMBOLS, + IDM_USE_SIGNATURE_FILE, + IDM_PATCH_HLE_FUNCTIONS, - // Symbols - IDM_CLEAR_SYMBOLS, - IDM_SCAN_FUNCTIONS, - IDM_LOAD_MAP_FILE, IDM_LOAD_MAP_FILE_AS, IDM_LOAD_BAD_MAP_FILE, - IDM_SAVEMAPFILE, IDM_SAVE_MAP_FILE_WITH_CODES, IDM_SAVE_MAP_FILE_AS, - IDM_CREATE_SIGNATURE_FILE, - IDM_APPEND_SIGNATURE_FILE, - IDM_COMBINE_SIGNATURE_FILES, - IDM_RENAME_SYMBOLS, - IDM_USE_SIGNATURE_FILE, - IDM_PATCH_HLE_FUNCTIONS, + // JIT + IDM_CLEAR_CODE_CACHE, + IDM_LOG_INSTRUCTIONS, + IDM_SEARCH_INSTRUCTION, - // JIT - IDM_CLEAR_CODE_CACHE, - IDM_LOG_INSTRUCTIONS, - IDM_SEARCH_INSTRUCTION, + // Profiler + IDM_PROFILE_BLOCKS, + IDM_WRITE_PROFILE, + // -------------------------------------------------------------- - // Profiler - IDM_PROFILE_BLOCKS, - IDM_WRITE_PROFILE, - // -------------------------------------------------------------- + // -------------------------------------------------------------- + // Debugger Toolbar + // -------------------- + ID_TOOLBAR_DEBUG, + IDM_STEP, + IDM_STEPOVER, + IDM_STEPOUT, + IDM_TOGGLE_BREAKPOINT, + IDM_SKIP, + IDM_SETPC, + IDM_GOTOPC, + IDM_ADDRBOX, - // -------------------------------------------------------------- - // Debugger Toolbar - // -------------------- - ID_TOOLBAR_DEBUG, - IDM_STEP, - IDM_STEPOVER, - IDM_STEPOUT, - IDM_TOGGLE_BREAKPOINT, - IDM_SKIP, - IDM_SETPC, - IDM_GOTOPC, - IDM_ADDRBOX, + ID_TOOLBAR_AUI, + IDM_SAVE_PERSPECTIVE, + IDM_ADD_PERSPECTIVE, + IDM_PERSPECTIVES_ADD_PANE_TOP, + IDM_PERSPECTIVES_ADD_PANE_BOTTOM, + IDM_PERSPECTIVES_ADD_PANE_LEFT, + IDM_PERSPECTIVES_ADD_PANE_RIGHT, + IDM_PERSPECTIVES_ADD_PANE_CENTER, + IDM_EDIT_PERSPECTIVES, + IDM_TAB_SPLIT, + IDM_NO_DOCKING, + IDM_PERSPECTIVES_0, + IDM_PERSPECTIVES_100 = IDM_PERSPECTIVES_0 + 100, + // -------------------------------------------------------------- - ID_TOOLBAR_AUI, - IDM_SAVE_PERSPECTIVE, - IDM_ADD_PERSPECTIVE, - IDM_PERSPECTIVES_ADD_PANE_TOP, - IDM_PERSPECTIVES_ADD_PANE_BOTTOM, - IDM_PERSPECTIVES_ADD_PANE_LEFT, - IDM_PERSPECTIVES_ADD_PANE_RIGHT, - IDM_PERSPECTIVES_ADD_PANE_CENTER, - IDM_EDIT_PERSPECTIVES, - IDM_TAB_SPLIT, - IDM_NO_DOCKING, - IDM_PERSPECTIVES_0, - IDM_PERSPECTIVES_100 = IDM_PERSPECTIVES_0 + 100, - // -------------------------------------------------------------- + IDM_TOGGLE_DUAL_CORE, // Other + IDM_TOGGLE_SKIP_IDLE, + IDM_TOGGLE_TOOLBAR, + IDM_TOGGLE_STATUSBAR, + IDM_NOTIFY_MAP_LOADED, + IDM_OPEN_CONTAINING_FOLDER, + IDM_OPEN_SAVE_FOLDER, + IDM_EXPORT_SAVE, + IDM_IMPORT_SAVE, + IDM_EXPORT_ALL_SAVE, + IDM_SET_DEFAULT_ISO, + IDM_DELETE_ISO, + IDM_COMPRESS_ISO, + IDM_MULTI_COMPRESS_ISO, + IDM_MULTI_DECOMPRESS_ISO, + IDM_UPDATE_DISASM_DIALOG, + IDM_UPDATE_GUI, + IDM_UPDATE_STATUS_BAR, + IDM_UPDATE_TITLE, + IDM_UPDATE_BREAKPOINTS, + IDM_UPDATE_JIT_PANE, + IDM_PANIC, + IDM_KEYSTATE, + IDM_WINDOW_SIZE_REQUEST, + IDM_STOPPED, + IDM_HOST_MESSAGE, + IDM_FULLSCREEN_REQUEST, - IDM_TOGGLE_DUAL_CORE, // Other - IDM_TOGGLE_SKIP_IDLE, - IDM_TOGGLE_TOOLBAR, - IDM_TOGGLE_STATUSBAR, - IDM_NOTIFY_MAP_LOADED, - IDM_OPEN_CONTAINING_FOLDER, - IDM_OPEN_SAVE_FOLDER, - IDM_EXPORT_SAVE, - IDM_IMPORT_SAVE, - IDM_EXPORT_ALL_SAVE, - IDM_SET_DEFAULT_ISO, - IDM_DELETE_ISO, - IDM_COMPRESS_ISO, - IDM_MULTI_COMPRESS_ISO, - IDM_MULTI_DECOMPRESS_ISO, - IDM_UPDATE_DISASM_DIALOG, - IDM_UPDATE_GUI, - IDM_UPDATE_STATUS_BAR, - IDM_UPDATE_TITLE, - IDM_UPDATE_BREAKPOINTS, - IDM_UPDATE_JIT_PANE, - IDM_PANIC, - IDM_KEYSTATE, - IDM_WINDOW_SIZE_REQUEST, - IDM_STOPPED, - IDM_HOST_MESSAGE, - IDM_FULLSCREEN_REQUEST, + // Used for Host_ConnectWiimote() + IDM_FORCE_CONNECT_WIIMOTE1, + IDM_FORCE_CONNECT_WIIMOTE2, + IDM_FORCE_CONNECT_WIIMOTE3, + IDM_FORCE_CONNECT_WIIMOTE4, + IDM_FORCE_CONNECT_BALANCEBOARD, + IDM_FORCE_DISCONNECT_WIIMOTE1, + IDM_FORCE_DISCONNECT_WIIMOTE2, + IDM_FORCE_DISCONNECT_WIIMOTE3, + IDM_FORCE_DISCONNECT_WIIMOTE4, + IDM_FORCE_DISCONNECT_BALANCEBOARD, - // Used for Host_ConnectWiimote() - IDM_FORCE_CONNECT_WIIMOTE1, - IDM_FORCE_CONNECT_WIIMOTE2, - IDM_FORCE_CONNECT_WIIMOTE3, - IDM_FORCE_CONNECT_WIIMOTE4, - IDM_FORCE_CONNECT_BALANCEBOARD, - IDM_FORCE_DISCONNECT_WIIMOTE1, - IDM_FORCE_DISCONNECT_WIIMOTE2, - IDM_FORCE_DISCONNECT_WIIMOTE3, - IDM_FORCE_DISCONNECT_WIIMOTE4, - IDM_FORCE_DISCONNECT_BALANCEBOARD, + IDM_MPANEL, + ID_STATUSBAR, - IDM_MPANEL, ID_STATUSBAR, + IDM_FREELOOK_DECREASE_SPEED, + IDM_FREELOOK_INCREASE_SPEED, + IDM_FREELOOK_RESET_SPEED, + IDM_FREELOOK_UP, + IDM_FREELOOK_DOWN, + IDM_FREELOOK_LEFT, + IDM_FREELOOK_RIGHT, + IDM_FREELOOK_ZOOM_IN, + IDM_FREELOOK_ZOOM_OUT, + IDM_FREELOOK_RESET, - IDM_FREELOOK_DECREASE_SPEED, - IDM_FREELOOK_INCREASE_SPEED, - IDM_FREELOOK_RESET_SPEED, - IDM_FREELOOK_UP, - IDM_FREELOOK_DOWN, - IDM_FREELOOK_LEFT, - IDM_FREELOOK_RIGHT, - IDM_FREELOOK_ZOOM_IN, - IDM_FREELOOK_ZOOM_OUT, - IDM_FREELOOK_RESET, - - ID_TOOLBAR = 500, + ID_TOOLBAR = 500, }; // custom message macro -#define EVT_HOST_COMMAND(id, fn) \ - EVT_COMMAND(id, wxEVT_HOST_COMMAND, fn) +#define EVT_HOST_COMMAND(id, fn) EVT_COMMAND(id, wxEVT_HOST_COMMAND, fn) wxDECLARE_EVENT(wxEVT_HOST_COMMAND, wxCommandEvent); diff --git a/Source/Core/DolphinWX/ISOFile.cpp b/Source/Core/DolphinWX/ISOFile.cpp index 886837af52..e61fb9875f 100644 --- a/Source/Core/DolphinWX/ISOFile.cpp +++ b/Source/Core/DolphinWX/ISOFile.cpp @@ -25,8 +25,8 @@ #include "Common/IniFile.h" #include "Common/StringUtil.h" -#include "Core/ConfigManager.h" #include "Core/Boot/Boot.h" +#include "Core/ConfigManager.h" #include "DiscIO/Volume.h" #include "DiscIO/VolumeCreator.h" @@ -34,141 +34,137 @@ #include "DolphinWX/ISOFile.h" #include "DolphinWX/WxUtils.h" -static const u32 CACHE_REVISION = 0x127; // Last changed in PR 3309 +static const u32 CACHE_REVISION = 0x127; // Last changed in PR 3309 #define DVD_BANNER_WIDTH 96 #define DVD_BANNER_HEIGHT 32 -static std::string GetLanguageString(DiscIO::IVolume::ELanguage language, std::map strings) +static std::string GetLanguageString(DiscIO::IVolume::ELanguage language, + std::map strings) { - auto end = strings.end(); - auto it = strings.find(language); - if (it != end) - return it->second; + auto end = strings.end(); + auto it = strings.find(language); + if (it != end) + return it->second; - // English tends to be a good fallback when the requested language isn't available - if (language != DiscIO::IVolume::ELanguage::LANGUAGE_ENGLISH) - { - it = strings.find(DiscIO::IVolume::ELanguage::LANGUAGE_ENGLISH); - if (it != end) - return it->second; - } + // English tends to be a good fallback when the requested language isn't available + if (language != DiscIO::IVolume::ELanguage::LANGUAGE_ENGLISH) + { + it = strings.find(DiscIO::IVolume::ELanguage::LANGUAGE_ENGLISH); + if (it != end) + return it->second; + } - // If English isn't available either, just pick something - if (!strings.empty()) - return strings.cbegin()->second; + // If English isn't available either, just pick something + if (!strings.empty()) + return strings.cbegin()->second; - return ""; + return ""; } -GameListItem::GameListItem(const std::string& _rFileName, const std::unordered_map& custom_titles) - : m_FileName(_rFileName) - , m_title_id(0) - , m_emu_state(0) - , m_FileSize(0) - , m_Country(DiscIO::IVolume::COUNTRY_UNKNOWN) - , m_Revision(0) - , m_Valid(false) - , m_ImageWidth(0) - , m_ImageHeight(0) - , m_disc_number(0) - , m_has_custom_name(false) +GameListItem::GameListItem(const std::string& _rFileName, + const std::unordered_map& custom_titles) + : m_FileName(_rFileName), m_title_id(0), m_emu_state(0), m_FileSize(0), + m_Country(DiscIO::IVolume::COUNTRY_UNKNOWN), m_Revision(0), m_Valid(false), m_ImageWidth(0), + m_ImageHeight(0), m_disc_number(0), m_has_custom_name(false) { - if (LoadFromCache()) - { - m_Valid = true; + if (LoadFromCache()) + { + m_Valid = true; - // Wii banners can only be read if there is a savefile, - // so sometimes caches don't contain banners. Let's check - // if a banner has become available after the cache was made. - if (m_pImage.empty()) - { - std::vector buffer = DiscIO::IVolume::GetWiiBanner(&m_ImageWidth, &m_ImageHeight, m_title_id); - ReadVolumeBanner(buffer, m_ImageWidth, m_ImageHeight); - if (!m_pImage.empty()) - SaveToCache(); - } - } - else - { - std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(_rFileName)); + // Wii banners can only be read if there is a savefile, + // so sometimes caches don't contain banners. Let's check + // if a banner has become available after the cache was made. + if (m_pImage.empty()) + { + std::vector buffer = + DiscIO::IVolume::GetWiiBanner(&m_ImageWidth, &m_ImageHeight, m_title_id); + ReadVolumeBanner(buffer, m_ImageWidth, m_ImageHeight); + if (!m_pImage.empty()) + SaveToCache(); + } + } + else + { + std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(_rFileName)); - if (volume != nullptr) - { - m_Platform = volume->GetVolumeType(); + if (volume != nullptr) + { + m_Platform = volume->GetVolumeType(); - m_names = volume->GetNames(true); - m_descriptions = volume->GetDescriptions(); - m_company = volume->GetCompany(); + m_names = volume->GetNames(true); + m_descriptions = volume->GetDescriptions(); + m_company = volume->GetCompany(); - m_Country = volume->GetCountry(); - m_blob_type = volume->GetBlobType(); - m_FileSize = volume->GetRawSize(); - m_VolumeSize = volume->GetSize(); + m_Country = volume->GetCountry(); + m_blob_type = volume->GetBlobType(); + m_FileSize = volume->GetRawSize(); + m_VolumeSize = volume->GetSize(); - m_UniqueID = volume->GetUniqueID(); - volume->GetTitleID(&m_title_id); - m_disc_number = volume->GetDiscNumber(); - m_Revision = volume->GetRevision(); + m_UniqueID = volume->GetUniqueID(); + volume->GetTitleID(&m_title_id); + m_disc_number = volume->GetDiscNumber(); + m_Revision = volume->GetRevision(); - std::vector buffer = volume->GetBanner(&m_ImageWidth, &m_ImageHeight); - ReadVolumeBanner(buffer, m_ImageWidth, m_ImageHeight); + std::vector buffer = volume->GetBanner(&m_ImageWidth, &m_ImageHeight); + ReadVolumeBanner(buffer, m_ImageWidth, m_ImageHeight); - m_Valid = true; - SaveToCache(); - } - } + m_Valid = true; + SaveToCache(); + } + } - if (m_company.empty() && m_UniqueID.size() >= 6) - m_company = DiscIO::GetCompanyFromID(m_UniqueID.substr(4, 2)); + if (m_company.empty() && m_UniqueID.size() >= 6) + m_company = DiscIO::GetCompanyFromID(m_UniqueID.substr(4, 2)); - if (IsValid()) - { - std::string game_id = m_UniqueID; + if (IsValid()) + { + std::string game_id = m_UniqueID; - // Ignore publisher ID for WAD files - if (m_Platform == DiscIO::IVolume::WII_WAD && game_id.size() > 4) - game_id.erase(4); + // Ignore publisher ID for WAD files + if (m_Platform == DiscIO::IVolume::WII_WAD && game_id.size() > 4) + game_id.erase(4); - auto it = custom_titles.find(game_id); - if (it != custom_titles.end()) - { - m_custom_name_titles_txt = it->second; - } + auto it = custom_titles.find(game_id); + if (it != custom_titles.end()) + { + m_custom_name_titles_txt = it->second; + } - ReloadINI(); - } + ReloadINI(); + } - if (!IsValid() && IsElfOrDol()) - { - m_Valid = true; - m_FileSize = File::GetSize(_rFileName); - m_Platform = DiscIO::IVolume::ELF_DOL; - m_blob_type = DiscIO::BlobType::DIRECTORY; - } + if (!IsValid() && IsElfOrDol()) + { + m_Valid = true; + m_FileSize = File::GetSize(_rFileName); + m_Platform = DiscIO::IVolume::ELF_DOL; + m_blob_type = DiscIO::BlobType::DIRECTORY; + } - std::string path, name; - SplitPath(m_FileName, &path, &name, nullptr); + std::string path, name; + SplitPath(m_FileName, &path, &name, nullptr); - // A bit like the Homebrew Channel icon, except there can be multiple files in a folder with their own icons. - // Useful for those who don't want to have a Homebrew Channel-style folder structure. - if (ReadPNGBanner(path + name + ".png")) - return; + // A bit like the Homebrew Channel icon, except there can be multiple files in a folder with their + // own icons. + // Useful for those who don't want to have a Homebrew Channel-style folder structure. + if (ReadPNGBanner(path + name + ".png")) + return; - // Homebrew Channel icon. Typical for DOLs and ELFs, but can be also used with volumes. - if (ReadPNGBanner(path + "icon.png")) - return; + // Homebrew Channel icon. Typical for DOLs and ELFs, but can be also used with volumes. + if (ReadPNGBanner(path + "icon.png")) + return; - // Volume banner. Typical for everything that isn't a DOL or ELF. - if (!m_pImage.empty()) - { - wxImage image(m_ImageWidth, m_ImageHeight, &m_pImage[0], true); - m_Bitmap = ScaleBanner(&image); - return; - } + // Volume banner. Typical for everything that isn't a DOL or ELF. + if (!m_pImage.empty()) + { + wxImage image(m_ImageWidth, m_ImageHeight, &m_pImage[0], true); + m_Bitmap = ScaleBanner(&image); + return; + } - // Fallback in case no banner is available. - ReadPNGBanner(File::GetSysDirectory() + RESOURCES_DIR + DIR_SEP + "nobanner.png"); + // Fallback in case no banner is available. + ReadPNGBanner(File::GetSysDirectory() + RESOURCES_DIR + DIR_SEP + "nobanner.png"); } GameListItem::~GameListItem() @@ -177,184 +173,189 @@ GameListItem::~GameListItem() void GameListItem::ReloadINI() { - if (!IsValid()) - return; + if (!IsValid()) + return; - IniFile ini = SConfig::LoadGameIni(m_UniqueID, m_Revision); - ini.GetIfExists("EmuState", "EmulationStateId", &m_emu_state, 0); - ini.GetIfExists("EmuState", "EmulationIssues", &m_issues, std::string()); + IniFile ini = SConfig::LoadGameIni(m_UniqueID, m_Revision); + ini.GetIfExists("EmuState", "EmulationStateId", &m_emu_state, 0); + ini.GetIfExists("EmuState", "EmulationIssues", &m_issues, std::string()); - m_custom_name.clear(); - m_has_custom_name = ini.GetIfExists("EmuState", "Title", &m_custom_name); - if (!m_has_custom_name && !m_custom_name_titles_txt.empty()) - { - m_custom_name = m_custom_name_titles_txt; - m_has_custom_name = true; - } + m_custom_name.clear(); + m_has_custom_name = ini.GetIfExists("EmuState", "Title", &m_custom_name); + if (!m_has_custom_name && !m_custom_name_titles_txt.empty()) + { + m_custom_name = m_custom_name_titles_txt; + m_has_custom_name = true; + } } bool GameListItem::LoadFromCache() { - return CChunkFileReader::Load(CreateCacheFilename(), CACHE_REVISION, *this); + return CChunkFileReader::Load(CreateCacheFilename(), CACHE_REVISION, *this); } void GameListItem::SaveToCache() { - if (!File::IsDirectory(File::GetUserPath(D_CACHE_IDX))) - File::CreateDir(File::GetUserPath(D_CACHE_IDX)); + if (!File::IsDirectory(File::GetUserPath(D_CACHE_IDX))) + File::CreateDir(File::GetUserPath(D_CACHE_IDX)); - CChunkFileReader::Save(CreateCacheFilename(), CACHE_REVISION, *this); + CChunkFileReader::Save(CreateCacheFilename(), CACHE_REVISION, *this); } -void GameListItem::DoState(PointerWrap &p) +void GameListItem::DoState(PointerWrap& p) { - p.Do(m_names); - p.Do(m_descriptions); - p.Do(m_company); - p.Do(m_UniqueID); - p.Do(m_title_id); - p.Do(m_FileSize); - p.Do(m_VolumeSize); - p.Do(m_Country); - p.Do(m_blob_type); - p.Do(m_pImage); - p.Do(m_ImageWidth); - p.Do(m_ImageHeight); - p.Do(m_Platform); - p.Do(m_disc_number); - p.Do(m_Revision); + p.Do(m_names); + p.Do(m_descriptions); + p.Do(m_company); + p.Do(m_UniqueID); + p.Do(m_title_id); + p.Do(m_FileSize); + p.Do(m_VolumeSize); + p.Do(m_Country); + p.Do(m_blob_type); + p.Do(m_pImage); + p.Do(m_ImageWidth); + p.Do(m_ImageHeight); + p.Do(m_Platform); + p.Do(m_disc_number); + p.Do(m_Revision); } bool GameListItem::IsElfOrDol() const { - if (m_FileName.size() < 4) - return false; + if (m_FileName.size() < 4) + return false; - std::string name_end = m_FileName.substr(m_FileName.size() - 4); - std::transform(name_end.begin(), name_end.end(), name_end.begin(), ::tolower); - return name_end == ".elf" || name_end == ".dol"; + std::string name_end = m_FileName.substr(m_FileName.size() - 4); + std::transform(name_end.begin(), name_end.end(), name_end.begin(), ::tolower); + return name_end == ".elf" || name_end == ".dol"; } std::string GameListItem::CreateCacheFilename() const { - std::string Filename, LegalPathname, extension; - SplitPath(m_FileName, &LegalPathname, &Filename, &extension); + std::string Filename, LegalPathname, extension; + SplitPath(m_FileName, &LegalPathname, &Filename, &extension); - if (Filename.empty()) return Filename; // Disc Drive + if (Filename.empty()) + return Filename; // Disc Drive - // Filename.extension_HashOfFolderPath_Size.cache - // Append hash to prevent ISO name-clashing in different folders. - Filename.append(StringFromFormat("%s_%x_%" PRIx64 ".cache", - extension.c_str(), HashFletcher((const u8 *)LegalPathname.c_str(), LegalPathname.size()), - File::GetSize(m_FileName))); + // Filename.extension_HashOfFolderPath_Size.cache + // Append hash to prevent ISO name-clashing in different folders. + Filename.append( + StringFromFormat("%s_%x_%" PRIx64 ".cache", extension.c_str(), + HashFletcher((const u8*)LegalPathname.c_str(), LegalPathname.size()), + File::GetSize(m_FileName))); - std::string fullname(File::GetUserPath(D_CACHE_IDX)); - fullname += Filename; - return fullname; + std::string fullname(File::GetUserPath(D_CACHE_IDX)); + fullname += Filename; + return fullname; } // Outputs to m_pImage void GameListItem::ReadVolumeBanner(const std::vector& buffer, int width, int height) { - m_pImage.resize(width * height * 3); - for (int i = 0; i < width * height; i++) - { - m_pImage[i * 3 + 0] = (buffer[i] & 0xFF0000) >> 16; - m_pImage[i * 3 + 1] = (buffer[i] & 0x00FF00) >> 8; - m_pImage[i * 3 + 2] = (buffer[i] & 0x0000FF) >> 0; - } + m_pImage.resize(width * height * 3); + for (int i = 0; i < width * height; i++) + { + m_pImage[i * 3 + 0] = (buffer[i] & 0xFF0000) >> 16; + m_pImage[i * 3 + 1] = (buffer[i] & 0x00FF00) >> 8; + m_pImage[i * 3 + 2] = (buffer[i] & 0x0000FF) >> 0; + } } // Outputs to m_Bitmap bool GameListItem::ReadPNGBanner(const std::string& path) { - if (!File::Exists(path)) - return false; + if (!File::Exists(path)) + return false; - wxImage image(StrToWxStr(path), wxBITMAP_TYPE_PNG); - m_Bitmap = ScaleBanner(&image); - return true; + wxImage image(StrToWxStr(path), wxBITMAP_TYPE_PNG); + m_Bitmap = ScaleBanner(&image); + return true; } wxBitmap GameListItem::ScaleBanner(wxImage* image) { - const double gui_scale = wxTheApp->GetTopWindow()->GetContentScaleFactor(); - const double target_width = DVD_BANNER_WIDTH * gui_scale; - const double target_height = DVD_BANNER_HEIGHT * gui_scale; - const double banner_scale = std::min(target_width / image->GetWidth(), target_height / image->GetHeight()); - image->Rescale(image->GetWidth() * banner_scale, image->GetHeight() * banner_scale, wxIMAGE_QUALITY_HIGH); - image->Resize(wxSize(target_width, target_height), wxPoint(), 0xFF, 0xFF, 0xFF); + const double gui_scale = wxTheApp->GetTopWindow()->GetContentScaleFactor(); + const double target_width = DVD_BANNER_WIDTH * gui_scale; + const double target_height = DVD_BANNER_HEIGHT * gui_scale; + const double banner_scale = + std::min(target_width / image->GetWidth(), target_height / image->GetHeight()); + image->Rescale(image->GetWidth() * banner_scale, image->GetHeight() * banner_scale, + wxIMAGE_QUALITY_HIGH); + image->Resize(wxSize(target_width, target_height), wxPoint(), 0xFF, 0xFF, 0xFF); #ifdef __APPLE__ - return wxBitmap(*image, -1, gui_scale); + return wxBitmap(*image, -1, gui_scale); #else - return wxBitmap(*image, -1); + return wxBitmap(*image, -1); #endif } std::string GameListItem::GetDescription(DiscIO::IVolume::ELanguage language) const { - return GetLanguageString(language, m_descriptions); + return GetLanguageString(language, m_descriptions); } std::string GameListItem::GetDescription() const { - bool wii = m_Platform != DiscIO::IVolume::GAMECUBE_DISC; - return GetDescription(SConfig::GetInstance().GetCurrentLanguage(wii)); + bool wii = m_Platform != DiscIO::IVolume::GAMECUBE_DISC; + return GetDescription(SConfig::GetInstance().GetCurrentLanguage(wii)); } std::string GameListItem::GetName(DiscIO::IVolume::ELanguage language) const { - return GetLanguageString(language, m_names); + return GetLanguageString(language, m_names); } std::string GameListItem::GetName() const { - if (m_has_custom_name) - return m_custom_name; + if (m_has_custom_name) + return m_custom_name; - bool wii = m_Platform != DiscIO::IVolume::GAMECUBE_DISC; - std::string name = GetName(SConfig::GetInstance().GetCurrentLanguage(wii)); - if (!name.empty()) - return name; + bool wii = m_Platform != DiscIO::IVolume::GAMECUBE_DISC; + std::string name = GetName(SConfig::GetInstance().GetCurrentLanguage(wii)); + if (!name.empty()) + return name; - // No usable name, return filename (better than nothing) - std::string ext; - SplitPath(GetFileName(), nullptr, &name, &ext); - return name + ext; + // No usable name, return filename (better than nothing) + std::string ext; + SplitPath(GetFileName(), nullptr, &name, &ext); + return name + ext; } std::vector GameListItem::GetLanguages() const { - std::vector languages; - for (std::pair name : m_names) - languages.push_back(name.first); - return languages; + std::vector languages; + for (std::pair name : m_names) + languages.push_back(name.first); + return languages; } const std::string GameListItem::GetWiiFSPath() const { - std::unique_ptr iso(DiscIO::CreateVolumeFromFilename(m_FileName)); - std::string ret; + std::unique_ptr iso(DiscIO::CreateVolumeFromFilename(m_FileName)); + std::string ret; - if (iso == nullptr) - return ret; + if (iso == nullptr) + return ret; - if (iso->GetVolumeType() != DiscIO::IVolume::GAMECUBE_DISC) - { - u64 title_id = 0; - iso->GetTitleID(&title_id); + if (iso->GetVolumeType() != DiscIO::IVolume::GAMECUBE_DISC) + { + u64 title_id = 0; + iso->GetTitleID(&title_id); - const std::string path = StringFromFormat("%s/title/%08x/%08x/data/", - File::GetUserPath(D_WIIROOT_IDX).c_str(), (u32)(title_id >> 32), (u32)title_id); + const std::string path = + StringFromFormat("%s/title/%08x/%08x/data/", File::GetUserPath(D_WIIROOT_IDX).c_str(), + (u32)(title_id >> 32), (u32)title_id); - if (!File::Exists(path)) - File::CreateFullPath(path); + if (!File::Exists(path)) + File::CreateFullPath(path); - if (path[0] == '.') - ret = WxStrToStr(wxGetCwd()) + path.substr(strlen(ROOT_DIR)); - else - ret = path; - } + if (path[0] == '.') + ret = WxStrToStr(wxGetCwd()) + path.substr(strlen(ROOT_DIR)); + else + ret = path; + } - return ret; + return ret; } diff --git a/Source/Core/DolphinWX/ISOFile.h b/Source/Core/DolphinWX/ISOFile.h index a814820ec0..63660529be 100644 --- a/Source/Core/DolphinWX/ISOFile.h +++ b/Source/Core/DolphinWX/ISOFile.h @@ -14,95 +14,95 @@ #include "DiscIO/Volume.h" #if defined(HAVE_WX) && HAVE_WX -#include #include +#include #endif class PointerWrap; class GameListItem { public: - GameListItem(const std::string& _rFileName, const std::unordered_map& custom_titles); - ~GameListItem(); + GameListItem(const std::string& _rFileName, + const std::unordered_map& custom_titles); + ~GameListItem(); - // Reload settings after INI changes - void ReloadINI(); - - bool IsValid() const {return m_Valid;} - const std::string& GetFileName() const {return m_FileName;} - std::string GetName(DiscIO::IVolume::ELanguage language) const; - std::string GetName() const; - std::string GetDescription(DiscIO::IVolume::ELanguage language) const; - std::string GetDescription() const; - std::vector GetLanguages() const; - std::string GetCompany() const { return m_company; } - u16 GetRevision() const { return m_Revision; } - const std::string& GetUniqueID() const {return m_UniqueID;} - const std::string GetWiiFSPath() const; - DiscIO::IVolume::ECountry GetCountry() const {return m_Country;} - DiscIO::IVolume::EPlatform GetPlatform() const { return m_Platform; } - DiscIO::BlobType GetBlobType() const { return m_blob_type; } - const std::string& GetIssues() const { return m_issues; } - int GetEmuState() const { return m_emu_state; } - bool IsCompressed() const - { - return m_blob_type == DiscIO::BlobType::GCZ || m_blob_type == DiscIO::BlobType::CISO || - m_blob_type == DiscIO::BlobType::WBFS; - } - u64 GetFileSize() const {return m_FileSize;} - u64 GetVolumeSize() const {return m_VolumeSize;} - // 0 is the first disc, 1 is the second disc - u8 GetDiscNumber() const { return m_disc_number; } + // Reload settings after INI changes + void ReloadINI(); + bool IsValid() const { return m_Valid; } + const std::string& GetFileName() const { return m_FileName; } + std::string GetName(DiscIO::IVolume::ELanguage language) const; + std::string GetName() const; + std::string GetDescription(DiscIO::IVolume::ELanguage language) const; + std::string GetDescription() const; + std::vector GetLanguages() const; + std::string GetCompany() const { return m_company; } + u16 GetRevision() const { return m_Revision; } + const std::string& GetUniqueID() const { return m_UniqueID; } + const std::string GetWiiFSPath() const; + DiscIO::IVolume::ECountry GetCountry() const { return m_Country; } + DiscIO::IVolume::EPlatform GetPlatform() const { return m_Platform; } + DiscIO::BlobType GetBlobType() const { return m_blob_type; } + const std::string& GetIssues() const { return m_issues; } + int GetEmuState() const { return m_emu_state; } + bool IsCompressed() const + { + return m_blob_type == DiscIO::BlobType::GCZ || m_blob_type == DiscIO::BlobType::CISO || + m_blob_type == DiscIO::BlobType::WBFS; + } + u64 GetFileSize() const { return m_FileSize; } + u64 GetVolumeSize() const { return m_VolumeSize; } + // 0 is the first disc, 1 is the second disc + u8 GetDiscNumber() const { return m_disc_number; } #if defined(HAVE_WX) && HAVE_WX - const wxBitmap& GetBitmap() const {return m_Bitmap;} + const wxBitmap& GetBitmap() const { return m_Bitmap; } #endif - void DoState(PointerWrap &p); + void DoState(PointerWrap& p); private: - std::string m_FileName; + std::string m_FileName; - std::map m_names; - std::map m_descriptions; - std::string m_company; + std::map m_names; + std::map m_descriptions; + std::string m_company; - std::string m_UniqueID; - u64 m_title_id; + std::string m_UniqueID; + u64 m_title_id; - std::string m_issues; - int m_emu_state; + std::string m_issues; + int m_emu_state; - u64 m_FileSize; - u64 m_VolumeSize; + u64 m_FileSize; + u64 m_VolumeSize; - DiscIO::IVolume::ECountry m_Country; - DiscIO::IVolume::EPlatform m_Platform; - DiscIO::BlobType m_blob_type; - u16 m_Revision; + DiscIO::IVolume::ECountry m_Country; + DiscIO::IVolume::EPlatform m_Platform; + DiscIO::BlobType m_blob_type; + u16 m_Revision; #if defined(HAVE_WX) && HAVE_WX - wxBitmap m_Bitmap; + wxBitmap m_Bitmap; #endif - bool m_Valid; - std::vector m_pImage; - int m_ImageWidth, m_ImageHeight; - u8 m_disc_number; + bool m_Valid; + std::vector m_pImage; + int m_ImageWidth, m_ImageHeight; + u8 m_disc_number; - std::string m_custom_name_titles_txt; // Custom title from titles.txt - std::string m_custom_name; // Custom title from INI or titles.txt - bool m_has_custom_name; + std::string m_custom_name_titles_txt; // Custom title from titles.txt + std::string m_custom_name; // Custom title from INI or titles.txt + bool m_has_custom_name; - bool LoadFromCache(); - void SaveToCache(); + bool LoadFromCache(); + void SaveToCache(); - bool IsElfOrDol() const; - std::string CreateCacheFilename() const; + bool IsElfOrDol() const; + std::string CreateCacheFilename() const; - // Outputs to m_pImage - void ReadVolumeBanner(const std::vector& buffer, int width, int height); - // Outputs to m_Bitmap - bool ReadPNGBanner(const std::string& path); + // Outputs to m_pImage + void ReadVolumeBanner(const std::vector& buffer, int width, int height); + // Outputs to m_Bitmap + bool ReadPNGBanner(const std::string& path); - static wxBitmap ScaleBanner(wxImage* image); + static wxBitmap ScaleBanner(wxImage* image); }; diff --git a/Source/Core/DolphinWX/ISOProperties.cpp b/Source/Core/DolphinWX/ISOProperties.cpp index 39b4e2c041..a50945d72c 100644 --- a/Source/Core/DolphinWX/ISOProperties.cpp +++ b/Source/Core/DolphinWX/ISOProperties.cpp @@ -11,11 +11,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -54,1449 +54,1516 @@ #include "Common/StringUtil.h" #include "Common/SysConf.h" #include "Core/ActionReplay.h" +#include "Core/Boot/Boot.h" #include "Core/ConfigManager.h" #include "Core/GeckoCodeConfig.h" #include "Core/PatchEngine.h" -#include "Core/Boot/Boot.h" #include "DiscIO/Blob.h" #include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" #include "DiscIO/VolumeCreator.h" #include "DolphinWX/ARCodeAddEdit.h" +#include "DolphinWX/Cheats/GeckoCodeDiag.h" #include "DolphinWX/Globals.h" #include "DolphinWX/ISOFile.h" #include "DolphinWX/ISOProperties.h" #include "DolphinWX/PatchAddEdit.h" #include "DolphinWX/WxUtils.h" -#include "DolphinWX/Cheats/GeckoCodeDiag.h" BEGIN_EVENT_TABLE(CISOProperties, wxDialog) - EVT_CLOSE(CISOProperties::OnClose) - EVT_BUTTON(wxID_OK, CISOProperties::OnCloseClick) - EVT_BUTTON(ID_EDITCONFIG, CISOProperties::OnEditConfig) - EVT_BUTTON(ID_MD5SUMCOMPUTE, CISOProperties::OnComputeMD5Sum) - EVT_BUTTON(ID_SHOWDEFAULTCONFIG, CISOProperties::OnShowDefaultConfig) - EVT_CHOICE(ID_EMUSTATE, CISOProperties::OnEmustateChanged) - EVT_LISTBOX(ID_PATCHES_LIST, CISOProperties::ListSelectionChanged) - EVT_BUTTON(ID_EDITPATCH, CISOProperties::PatchButtonClicked) - EVT_BUTTON(ID_ADDPATCH, CISOProperties::PatchButtonClicked) - EVT_BUTTON(ID_REMOVEPATCH, CISOProperties::PatchButtonClicked) - EVT_LISTBOX(ID_CHEATS_LIST, CISOProperties::ListSelectionChanged) - EVT_BUTTON(ID_EDITCHEAT, CISOProperties::ActionReplayButtonClicked) - EVT_BUTTON(ID_ADDCHEAT, CISOProperties::ActionReplayButtonClicked) - EVT_BUTTON(ID_REMOVECHEAT, CISOProperties::ActionReplayButtonClicked) - EVT_MENU(IDM_BNRSAVEAS, CISOProperties::OnBannerImageSave) - EVT_TREE_ITEM_RIGHT_CLICK(ID_TREECTRL, CISOProperties::OnRightClickOnTree) - EVT_MENU(IDM_EXTRACTFILE, CISOProperties::OnExtractFile) - EVT_MENU(IDM_EXTRACTDIR, CISOProperties::OnExtractDir) - EVT_MENU(IDM_EXTRACTALL, CISOProperties::OnExtractDir) - EVT_MENU(IDM_EXTRACTAPPLOADER, CISOProperties::OnExtractDataFromHeader) - EVT_MENU(IDM_EXTRACTDOL, CISOProperties::OnExtractDataFromHeader) - EVT_MENU(IDM_CHECKINTEGRITY, CISOProperties::CheckPartitionIntegrity) - EVT_CHOICE(ID_LANG, CISOProperties::OnChangeBannerLang) - EVT_CHECKLISTBOX(ID_CHEATS_LIST, CISOProperties::OnActionReplayCodeChecked) +EVT_CLOSE(CISOProperties::OnClose) +EVT_BUTTON(wxID_OK, CISOProperties::OnCloseClick) +EVT_BUTTON(ID_EDITCONFIG, CISOProperties::OnEditConfig) +EVT_BUTTON(ID_MD5SUMCOMPUTE, CISOProperties::OnComputeMD5Sum) +EVT_BUTTON(ID_SHOWDEFAULTCONFIG, CISOProperties::OnShowDefaultConfig) +EVT_CHOICE(ID_EMUSTATE, CISOProperties::OnEmustateChanged) +EVT_LISTBOX(ID_PATCHES_LIST, CISOProperties::ListSelectionChanged) +EVT_BUTTON(ID_EDITPATCH, CISOProperties::PatchButtonClicked) +EVT_BUTTON(ID_ADDPATCH, CISOProperties::PatchButtonClicked) +EVT_BUTTON(ID_REMOVEPATCH, CISOProperties::PatchButtonClicked) +EVT_LISTBOX(ID_CHEATS_LIST, CISOProperties::ListSelectionChanged) +EVT_BUTTON(ID_EDITCHEAT, CISOProperties::ActionReplayButtonClicked) +EVT_BUTTON(ID_ADDCHEAT, CISOProperties::ActionReplayButtonClicked) +EVT_BUTTON(ID_REMOVECHEAT, CISOProperties::ActionReplayButtonClicked) +EVT_MENU(IDM_BNRSAVEAS, CISOProperties::OnBannerImageSave) +EVT_TREE_ITEM_RIGHT_CLICK(ID_TREECTRL, CISOProperties::OnRightClickOnTree) +EVT_MENU(IDM_EXTRACTFILE, CISOProperties::OnExtractFile) +EVT_MENU(IDM_EXTRACTDIR, CISOProperties::OnExtractDir) +EVT_MENU(IDM_EXTRACTALL, CISOProperties::OnExtractDir) +EVT_MENU(IDM_EXTRACTAPPLOADER, CISOProperties::OnExtractDataFromHeader) +EVT_MENU(IDM_EXTRACTDOL, CISOProperties::OnExtractDataFromHeader) +EVT_MENU(IDM_CHECKINTEGRITY, CISOProperties::CheckPartitionIntegrity) +EVT_CHOICE(ID_LANG, CISOProperties::OnChangeBannerLang) +EVT_CHECKLISTBOX(ID_CHEATS_LIST, CISOProperties::OnActionReplayCodeChecked) END_EVENT_TABLE() -CISOProperties::CISOProperties(const GameListItem& game_list_item, wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& position, const wxSize& size, long style) - : wxDialog(parent, id, title, position, size, style) - , OpenGameListItem(game_list_item) +CISOProperties::CISOProperties(const GameListItem& game_list_item, wxWindow* parent, wxWindowID id, + const wxString& title, const wxPoint& position, const wxSize& size, + long style) + : wxDialog(parent, id, title, position, size, style), OpenGameListItem(game_list_item) { - // Load ISO data - m_open_iso = DiscIO::CreateVolumeFromFilename(OpenGameListItem.GetFileName()); + // Load ISO data + m_open_iso = DiscIO::CreateVolumeFromFilename(OpenGameListItem.GetFileName()); - game_id = m_open_iso->GetUniqueID(); + game_id = m_open_iso->GetUniqueID(); - // Load game INIs - GameIniFileLocal = File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini"; - GameIniDefault = SConfig::LoadDefaultGameIni(game_id, m_open_iso->GetRevision()); - GameIniLocal = SConfig::LoadLocalGameIni(game_id, m_open_iso->GetRevision()); + // Load game INIs + GameIniFileLocal = File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini"; + GameIniDefault = SConfig::LoadDefaultGameIni(game_id, m_open_iso->GetRevision()); + GameIniLocal = SConfig::LoadLocalGameIni(game_id, m_open_iso->GetRevision()); - // Setup GUI - CreateGUIControls(); + // Setup GUI + CreateGUIControls(); - LoadGameConfig(); + LoadGameConfig(); - // Disk header and apploader + // Disk header and apploader - m_InternalName->SetValue(StrToWxStr(m_open_iso->GetInternalName())); - m_GameID->SetValue(StrToWxStr(m_open_iso->GetUniqueID())); - switch (m_open_iso->GetCountry()) - { - case DiscIO::IVolume::COUNTRY_AUSTRALIA: - m_Country->SetValue(_("Australia")); - break; - case DiscIO::IVolume::COUNTRY_EUROPE: - m_Country->SetValue(_("Europe")); - break; - case DiscIO::IVolume::COUNTRY_FRANCE: - m_Country->SetValue(_("France")); - break; - case DiscIO::IVolume::COUNTRY_ITALY: - m_Country->SetValue(_("Italy")); - break; - case DiscIO::IVolume::COUNTRY_GERMANY: - m_Country->SetValue(_("Germany")); - break; - case DiscIO::IVolume::COUNTRY_NETHERLANDS: - m_Country->SetValue(_("Netherlands")); - break; - case DiscIO::IVolume::COUNTRY_RUSSIA: - m_Country->SetValue(_("Russia")); - break; - case DiscIO::IVolume::COUNTRY_SPAIN: - m_Country->SetValue(_("Spain")); - break; - case DiscIO::IVolume::COUNTRY_USA: - m_Country->SetValue(_("USA")); - break; - case DiscIO::IVolume::COUNTRY_JAPAN: - m_Country->SetValue(_("Japan")); - break; - case DiscIO::IVolume::COUNTRY_KOREA: - m_Country->SetValue(_("Korea")); - break; - case DiscIO::IVolume::COUNTRY_TAIWAN: - m_Country->SetValue(_("Taiwan")); - break; - case DiscIO::IVolume::COUNTRY_WORLD: - m_Country->SetValue(_("World")); - break; - case DiscIO::IVolume::COUNTRY_UNKNOWN: - default: - m_Country->SetValue(_("Unknown")); - break; - } + m_InternalName->SetValue(StrToWxStr(m_open_iso->GetInternalName())); + m_GameID->SetValue(StrToWxStr(m_open_iso->GetUniqueID())); + switch (m_open_iso->GetCountry()) + { + case DiscIO::IVolume::COUNTRY_AUSTRALIA: + m_Country->SetValue(_("Australia")); + break; + case DiscIO::IVolume::COUNTRY_EUROPE: + m_Country->SetValue(_("Europe")); + break; + case DiscIO::IVolume::COUNTRY_FRANCE: + m_Country->SetValue(_("France")); + break; + case DiscIO::IVolume::COUNTRY_ITALY: + m_Country->SetValue(_("Italy")); + break; + case DiscIO::IVolume::COUNTRY_GERMANY: + m_Country->SetValue(_("Germany")); + break; + case DiscIO::IVolume::COUNTRY_NETHERLANDS: + m_Country->SetValue(_("Netherlands")); + break; + case DiscIO::IVolume::COUNTRY_RUSSIA: + m_Country->SetValue(_("Russia")); + break; + case DiscIO::IVolume::COUNTRY_SPAIN: + m_Country->SetValue(_("Spain")); + break; + case DiscIO::IVolume::COUNTRY_USA: + m_Country->SetValue(_("USA")); + break; + case DiscIO::IVolume::COUNTRY_JAPAN: + m_Country->SetValue(_("Japan")); + break; + case DiscIO::IVolume::COUNTRY_KOREA: + m_Country->SetValue(_("Korea")); + break; + case DiscIO::IVolume::COUNTRY_TAIWAN: + m_Country->SetValue(_("Taiwan")); + break; + case DiscIO::IVolume::COUNTRY_WORLD: + m_Country->SetValue(_("World")); + break; + case DiscIO::IVolume::COUNTRY_UNKNOWN: + default: + m_Country->SetValue(_("Unknown")); + break; + } - wxString temp = "0x" + StrToWxStr(m_open_iso->GetMakerID()); - m_MakerID->SetValue(temp); - m_Revision->SetValue(StrToWxStr(std::to_string(m_open_iso->GetRevision()))); - m_Date->SetValue(StrToWxStr(m_open_iso->GetApploaderDate())); - m_FST->SetValue(StrToWxStr(std::to_string(m_open_iso->GetFSTSize()))); + wxString temp = "0x" + StrToWxStr(m_open_iso->GetMakerID()); + m_MakerID->SetValue(temp); + m_Revision->SetValue(StrToWxStr(std::to_string(m_open_iso->GetRevision()))); + m_Date->SetValue(StrToWxStr(m_open_iso->GetApploaderDate())); + m_FST->SetValue(StrToWxStr(std::to_string(m_open_iso->GetFSTSize()))); - // Here we set all the info to be shown + we set the window title - bool wii = m_open_iso->GetVolumeType() != DiscIO::IVolume::GAMECUBE_DISC; - ChangeBannerDetails(SConfig::GetInstance().GetCurrentLanguage(wii)); + // Here we set all the info to be shown + we set the window title + bool wii = m_open_iso->GetVolumeType() != DiscIO::IVolume::GAMECUBE_DISC; + ChangeBannerDetails(SConfig::GetInstance().GetCurrentLanguage(wii)); - m_Banner->SetBitmap(OpenGameListItem.GetBitmap()); - m_Banner->Bind(wxEVT_RIGHT_DOWN, &CISOProperties::RightClickOnBanner, this); + m_Banner->SetBitmap(OpenGameListItem.GetBitmap()); + m_Banner->Bind(wxEVT_RIGHT_DOWN, &CISOProperties::RightClickOnBanner, this); - // Filesystem browser/dumper - // TODO : Should we add a way to browse the wad file ? - if (m_open_iso->GetVolumeType() != DiscIO::IVolume::WII_WAD) - { - if (m_open_iso->GetVolumeType() == DiscIO::IVolume::WII_DISC) - { - int partition_count = 0; - for (int group = 0; group < 4; group++) - { - for (u32 i = 0; i < 0xFFFFFFFF; i++) // yes, technically there can be OVER NINE THOUSAND partitions... - { - std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(OpenGameListItem.GetFileName(), group, i)); - if (volume != nullptr) - { - std::unique_ptr file_system(DiscIO::CreateFileSystem(volume.get())); - if (file_system != nullptr) - { - WiiPartition* const partition = new WiiPartition(std::move(volume), std::move(file_system)); + // Filesystem browser/dumper + // TODO : Should we add a way to browse the wad file ? + if (m_open_iso->GetVolumeType() != DiscIO::IVolume::WII_WAD) + { + if (m_open_iso->GetVolumeType() == DiscIO::IVolume::WII_DISC) + { + int partition_count = 0; + for (int group = 0; group < 4; group++) + { + for (u32 i = 0; i < 0xFFFFFFFF; + i++) // yes, technically there can be OVER NINE THOUSAND partitions... + { + std::unique_ptr volume( + DiscIO::CreateVolumeFromFilename(OpenGameListItem.GetFileName(), group, i)); + if (volume != nullptr) + { + std::unique_ptr file_system( + DiscIO::CreateFileSystem(volume.get())); + if (file_system != nullptr) + { + WiiPartition* const partition = + new WiiPartition(std::move(volume), std::move(file_system)); - wxTreeItemId PartitionRoot = - m_Treectrl->AppendItem(RootId, wxString::Format(_("Partition %i"), partition_count), 0, 0); + wxTreeItemId PartitionRoot = m_Treectrl->AppendItem( + RootId, wxString::Format(_("Partition %i"), partition_count), 0, 0); - m_Treectrl->SetItemData(PartitionRoot, partition); - CreateDirectoryTree(PartitionRoot, partition->FileSystem->GetFileList()); + m_Treectrl->SetItemData(PartitionRoot, partition); + CreateDirectoryTree(PartitionRoot, partition->FileSystem->GetFileList()); - if (partition_count == 1) - m_Treectrl->Expand(PartitionRoot); + if (partition_count == 1) + m_Treectrl->Expand(PartitionRoot); - partition_count++; - } - } - else - { - break; - } - } - } - } - else - { - m_filesystem = DiscIO::CreateFileSystem(m_open_iso.get()); - if (m_filesystem) - CreateDirectoryTree(RootId, m_filesystem->GetFileList()); - } + partition_count++; + } + } + else + { + break; + } + } + } + } + else + { + m_filesystem = DiscIO::CreateFileSystem(m_open_iso.get()); + if (m_filesystem) + CreateDirectoryTree(RootId, m_filesystem->GetFileList()); + } - m_Treectrl->Expand(RootId); - } + m_Treectrl->Expand(RootId); + } - wxTheApp->Bind(DOLPHIN_EVT_LOCAL_INI_CHANGED, &CISOProperties::OnLocalIniModified, this); + wxTheApp->Bind(DOLPHIN_EVT_LOCAL_INI_CHANGED, &CISOProperties::OnLocalIniModified, this); } CISOProperties::~CISOProperties() { } -size_t CISOProperties::CreateDirectoryTree(wxTreeItemId& parent, const std::vector& fileInfos) +size_t CISOProperties::CreateDirectoryTree(wxTreeItemId& parent, + const std::vector& fileInfos) { - if (fileInfos.empty()) - return 0; - else - return CreateDirectoryTree(parent, fileInfos, 1, fileInfos.at(0).m_FileSize); + if (fileInfos.empty()) + return 0; + else + return CreateDirectoryTree(parent, fileInfos, 1, fileInfos.at(0).m_FileSize); } size_t CISOProperties::CreateDirectoryTree(wxTreeItemId& parent, - const std::vector& fileInfos, - const size_t _FirstIndex, - const size_t _LastIndex) + const std::vector& fileInfos, + const size_t _FirstIndex, const size_t _LastIndex) { - size_t CurrentIndex = _FirstIndex; + size_t CurrentIndex = _FirstIndex; - while (CurrentIndex < _LastIndex) - { - const DiscIO::SFileInfo rFileInfo = fileInfos[CurrentIndex]; - std::string filePath = rFileInfo.m_FullPath; + while (CurrentIndex < _LastIndex) + { + const DiscIO::SFileInfo rFileInfo = fileInfos[CurrentIndex]; + std::string filePath = rFileInfo.m_FullPath; - // Trim the trailing '/' if it exists. - if (filePath[filePath.length() - 1] == DIR_SEP_CHR) - { - filePath.pop_back(); - } + // Trim the trailing '/' if it exists. + if (filePath[filePath.length() - 1] == DIR_SEP_CHR) + { + filePath.pop_back(); + } - // Cut off the path up to the actual filename or folder. - // Say we have "/music/stream/stream1.strm", the result will be "stream1.strm". - size_t dirSepIndex = filePath.find_last_of(DIR_SEP_CHR); - if (dirSepIndex != std::string::npos) - { - filePath = filePath.substr(dirSepIndex + 1); - } + // Cut off the path up to the actual filename or folder. + // Say we have "/music/stream/stream1.strm", the result will be "stream1.strm". + size_t dirSepIndex = filePath.find_last_of(DIR_SEP_CHR); + if (dirSepIndex != std::string::npos) + { + filePath = filePath.substr(dirSepIndex + 1); + } - // check next index - if (rFileInfo.IsDirectory()) - { - wxTreeItemId item = m_Treectrl->AppendItem(parent, StrToWxStr(filePath), 1, 1); - CurrentIndex = CreateDirectoryTree(item, fileInfos, CurrentIndex + 1, (size_t)rFileInfo.m_FileSize); - } - else - { - m_Treectrl->AppendItem(parent, StrToWxStr(filePath), 2, 2); - CurrentIndex++; - } - } + // check next index + if (rFileInfo.IsDirectory()) + { + wxTreeItemId item = m_Treectrl->AppendItem(parent, StrToWxStr(filePath), 1, 1); + CurrentIndex = + CreateDirectoryTree(item, fileInfos, CurrentIndex + 1, (size_t)rFileInfo.m_FileSize); + } + else + { + m_Treectrl->AppendItem(parent, StrToWxStr(filePath), 2, 2); + CurrentIndex++; + } + } - return CurrentIndex; + return CurrentIndex; } long CISOProperties::GetElementStyle(const char* section, const char* key) { - // Disable 3rd state if default gameini overrides the setting - if (GameIniDefault.Exists(section, key)) - return 0; + // Disable 3rd state if default gameini overrides the setting + if (GameIniDefault.Exists(section, key)) + return 0; - return wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER; + return wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER; } void CISOProperties::CreateGUIControls() { - wxButton* const EditConfig = new wxButton(this, ID_EDITCONFIG, _("Edit Config")); - EditConfig->SetToolTip(_("This will let you manually edit the INI config file.")); + wxButton* const EditConfig = new wxButton(this, ID_EDITCONFIG, _("Edit Config")); + EditConfig->SetToolTip(_("This will let you manually edit the INI config file.")); - wxButton* const EditConfigDefault = new wxButton(this, ID_SHOWDEFAULTCONFIG, _("Show Defaults")); - EditConfigDefault->SetToolTip(_("Opens the default (read-only) configuration for this game in an external text editor.")); + wxButton* const EditConfigDefault = new wxButton(this, ID_SHOWDEFAULTCONFIG, _("Show Defaults")); + EditConfigDefault->SetToolTip( + _("Opens the default (read-only) configuration for this game in an external text editor.")); - // Notebook - wxNotebook* const m_Notebook = new wxNotebook(this, ID_NOTEBOOK); - wxPanel* const m_GameConfig = new wxPanel(m_Notebook, ID_GAMECONFIG); - m_Notebook->AddPage(m_GameConfig, _("GameConfig")); - wxPanel* const m_PatchPage = new wxPanel(m_Notebook, ID_PATCH_PAGE); - m_Notebook->AddPage(m_PatchPage, _("Patches")); - wxPanel* const m_CheatPage = new wxPanel(m_Notebook, ID_ARCODE_PAGE); - m_Notebook->AddPage(m_CheatPage, _("AR Codes")); - m_geckocode_panel = new Gecko::CodeConfigPanel(m_Notebook); - m_Notebook->AddPage(m_geckocode_panel, _("Gecko Codes")); - wxPanel* const m_Information = new wxPanel(m_Notebook, ID_INFORMATION); - m_Notebook->AddPage(m_Information, _("Info")); + // Notebook + wxNotebook* const m_Notebook = new wxNotebook(this, ID_NOTEBOOK); + wxPanel* const m_GameConfig = new wxPanel(m_Notebook, ID_GAMECONFIG); + m_Notebook->AddPage(m_GameConfig, _("GameConfig")); + wxPanel* const m_PatchPage = new wxPanel(m_Notebook, ID_PATCH_PAGE); + m_Notebook->AddPage(m_PatchPage, _("Patches")); + wxPanel* const m_CheatPage = new wxPanel(m_Notebook, ID_ARCODE_PAGE); + m_Notebook->AddPage(m_CheatPage, _("AR Codes")); + m_geckocode_panel = new Gecko::CodeConfigPanel(m_Notebook); + m_Notebook->AddPage(m_geckocode_panel, _("Gecko Codes")); + wxPanel* const m_Information = new wxPanel(m_Notebook, ID_INFORMATION); + m_Notebook->AddPage(m_Information, _("Info")); - // GameConfig editing - Overrides and emulation state - wxStaticText* const OverrideText = new wxStaticText(m_GameConfig, wxID_ANY, _("These settings override core Dolphin settings.\nUndetermined means the game uses Dolphin's setting.")); + // GameConfig editing - Overrides and emulation state + wxStaticText* const OverrideText = new wxStaticText( + m_GameConfig, wxID_ANY, _("These settings override core Dolphin settings.\nUndetermined " + "means the game uses Dolphin's setting.")); - // Core - CPUThread = new wxCheckBox(m_GameConfig, ID_USEDUALCORE, _("Enable Dual Core"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "CPUThread")); - SkipIdle = new wxCheckBox(m_GameConfig, ID_IDLESKIP, _("Enable Idle Skipping"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "SkipIdle")); - MMU = new wxCheckBox(m_GameConfig, ID_MMU, _("Enable MMU"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "MMU")); - MMU->SetToolTip(_("Enables the Memory Management Unit, needed for some games. (ON = Compatible, OFF = Fast)")); - DCBZOFF = new wxCheckBox(m_GameConfig, ID_DCBZOFF, _("Skip DCBZ clearing"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "DCBZ")); - DCBZOFF->SetToolTip(_("Bypass the clearing of the data cache by the DCBZ instruction. Usually leave this option disabled.")); - FPRF = new wxCheckBox(m_GameConfig, ID_FPRF, _("Enable FPRF"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "FPRF")); - FPRF->SetToolTip(_("Enables Floating Point Result Flag calculation, needed for a few games. (ON = Compatible, OFF = Fast)")); - SyncGPU = new wxCheckBox(m_GameConfig, ID_SYNCGPU, _("Synchronize GPU thread"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "SyncGPU")); - SyncGPU->SetToolTip(_("Synchronizes the GPU and CPU threads to help prevent random freezes in Dual Core mode. (ON = Compatible, OFF = Fast)")); - FastDiscSpeed = new wxCheckBox(m_GameConfig, ID_DISCSPEED, _("Speed up Disc Transfer Rate"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "FastDiscSpeed")); - FastDiscSpeed->SetToolTip(_("Enable fast disc access. This can cause crashes and other problems in some games. (ON = Fast, OFF = Compatible)")); - DSPHLE = new wxCheckBox(m_GameConfig, ID_AUDIO_DSP_HLE, _("DSP HLE emulation (fast)"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "DSPHLE")); + // Core + CPUThread = new wxCheckBox(m_GameConfig, ID_USEDUALCORE, _("Enable Dual Core"), wxDefaultPosition, + wxDefaultSize, GetElementStyle("Core", "CPUThread")); + SkipIdle = new wxCheckBox(m_GameConfig, ID_IDLESKIP, _("Enable Idle Skipping"), wxDefaultPosition, + wxDefaultSize, GetElementStyle("Core", "SkipIdle")); + MMU = new wxCheckBox(m_GameConfig, ID_MMU, _("Enable MMU"), wxDefaultPosition, wxDefaultSize, + GetElementStyle("Core", "MMU")); + MMU->SetToolTip(_( + "Enables the Memory Management Unit, needed for some games. (ON = Compatible, OFF = Fast)")); + DCBZOFF = new wxCheckBox(m_GameConfig, ID_DCBZOFF, _("Skip DCBZ clearing"), wxDefaultPosition, + wxDefaultSize, GetElementStyle("Core", "DCBZ")); + DCBZOFF->SetToolTip(_("Bypass the clearing of the data cache by the DCBZ instruction. Usually " + "leave this option disabled.")); + FPRF = new wxCheckBox(m_GameConfig, ID_FPRF, _("Enable FPRF"), wxDefaultPosition, wxDefaultSize, + GetElementStyle("Core", "FPRF")); + FPRF->SetToolTip(_("Enables Floating Point Result Flag calculation, needed for a few games. (ON " + "= Compatible, OFF = Fast)")); + SyncGPU = new wxCheckBox(m_GameConfig, ID_SYNCGPU, _("Synchronize GPU thread"), wxDefaultPosition, + wxDefaultSize, GetElementStyle("Core", "SyncGPU")); + SyncGPU->SetToolTip(_("Synchronizes the GPU and CPU threads to help prevent random freezes in " + "Dual Core mode. (ON = Compatible, OFF = Fast)")); + FastDiscSpeed = + new wxCheckBox(m_GameConfig, ID_DISCSPEED, _("Speed up Disc Transfer Rate"), + wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "FastDiscSpeed")); + FastDiscSpeed->SetToolTip(_("Enable fast disc access. This can cause crashes and other problems " + "in some games. (ON = Fast, OFF = Compatible)")); + DSPHLE = new wxCheckBox(m_GameConfig, ID_AUDIO_DSP_HLE, _("DSP HLE emulation (fast)"), + wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "DSPHLE")); - wxBoxSizer* const sGPUDeterminism = new wxBoxSizer(wxHORIZONTAL); - wxStaticText* const GPUDeterminismText = new wxStaticText(m_GameConfig, wxID_ANY, _("Deterministic dual core: ")); - arrayStringFor_GPUDeterminism.Add(_("Not Set")); - arrayStringFor_GPUDeterminism.Add(_("auto")); - arrayStringFor_GPUDeterminism.Add(_("none")); - arrayStringFor_GPUDeterminism.Add(_("fake-completion")); - GPUDeterminism = new wxChoice(m_GameConfig, ID_GPUDETERMINISM, wxDefaultPosition, wxDefaultSize, arrayStringFor_GPUDeterminism); - sGPUDeterminism->Add(GPUDeterminismText); - sGPUDeterminism->Add(GPUDeterminism); + wxBoxSizer* const sGPUDeterminism = new wxBoxSizer(wxHORIZONTAL); + wxStaticText* const GPUDeterminismText = + new wxStaticText(m_GameConfig, wxID_ANY, _("Deterministic dual core: ")); + arrayStringFor_GPUDeterminism.Add(_("Not Set")); + arrayStringFor_GPUDeterminism.Add(_("auto")); + arrayStringFor_GPUDeterminism.Add(_("none")); + arrayStringFor_GPUDeterminism.Add(_("fake-completion")); + GPUDeterminism = new wxChoice(m_GameConfig, ID_GPUDETERMINISM, wxDefaultPosition, wxDefaultSize, + arrayStringFor_GPUDeterminism); + sGPUDeterminism->Add(GPUDeterminismText); + sGPUDeterminism->Add(GPUDeterminism); - // Wii Console - EnableWideScreen = new wxCheckBox(m_GameConfig, ID_ENABLEWIDESCREEN, _("Enable WideScreen"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Wii", "Widescreen")); + // Wii Console + EnableWideScreen = + new wxCheckBox(m_GameConfig, ID_ENABLEWIDESCREEN, _("Enable WideScreen"), wxDefaultPosition, + wxDefaultSize, GetElementStyle("Wii", "Widescreen")); - // Stereoscopy - wxBoxSizer* const sDepthPercentage = new wxBoxSizer(wxHORIZONTAL); - wxStaticText* const DepthPercentageText = new wxStaticText(m_GameConfig, wxID_ANY, _("Depth Percentage: ")); - DepthPercentage = new wxSlider(m_GameConfig, ID_DEPTHPERCENTAGE, 100, 0, 200); - DepthPercentage->SetToolTip(_("This value is multiplied with the depth set in the graphics configuration.")); - sDepthPercentage->Add(DepthPercentageText); - sDepthPercentage->Add(DepthPercentage); + // Stereoscopy + wxBoxSizer* const sDepthPercentage = new wxBoxSizer(wxHORIZONTAL); + wxStaticText* const DepthPercentageText = + new wxStaticText(m_GameConfig, wxID_ANY, _("Depth Percentage: ")); + DepthPercentage = new wxSlider(m_GameConfig, ID_DEPTHPERCENTAGE, 100, 0, 200); + DepthPercentage->SetToolTip( + _("This value is multiplied with the depth set in the graphics configuration.")); + sDepthPercentage->Add(DepthPercentageText); + sDepthPercentage->Add(DepthPercentage); - wxBoxSizer* const sConvergence = new wxBoxSizer(wxHORIZONTAL); - wxStaticText* const ConvergenceText = new wxStaticText(m_GameConfig, wxID_ANY, _("Convergence: ")); - Convergence = new wxSpinCtrl(m_GameConfig, ID_CONVERGENCE); - Convergence->SetRange(0, INT32_MAX); - Convergence->SetToolTip(_("This value is added to the convergence value set in the graphics configuration.")); - sConvergence->Add(ConvergenceText); - sConvergence->Add(Convergence); + wxBoxSizer* const sConvergence = new wxBoxSizer(wxHORIZONTAL); + wxStaticText* const ConvergenceText = + new wxStaticText(m_GameConfig, wxID_ANY, _("Convergence: ")); + Convergence = new wxSpinCtrl(m_GameConfig, ID_CONVERGENCE); + Convergence->SetRange(0, INT32_MAX); + Convergence->SetToolTip( + _("This value is added to the convergence value set in the graphics configuration.")); + sConvergence->Add(ConvergenceText); + sConvergence->Add(Convergence); - MonoDepth = new wxCheckBox(m_GameConfig, ID_MONODEPTH, _("Monoscopic Shadows"), wxDefaultPosition, wxDefaultSize, GetElementStyle("Video_Stereoscopy", "StereoEFBMonoDepth")); - MonoDepth->SetToolTip(_("Use a single depth buffer for both eyes. Needed for a few games.")); + MonoDepth = + new wxCheckBox(m_GameConfig, ID_MONODEPTH, _("Monoscopic Shadows"), wxDefaultPosition, + wxDefaultSize, GetElementStyle("Video_Stereoscopy", "StereoEFBMonoDepth")); + MonoDepth->SetToolTip(_("Use a single depth buffer for both eyes. Needed for a few games.")); - wxBoxSizer* const sEmuState = new wxBoxSizer(wxHORIZONTAL); - wxStaticText* const EmuStateText = new wxStaticText(m_GameConfig, wxID_ANY, _("Emulation State: ")); - arrayStringFor_EmuState.Add(_("Not Set")); - arrayStringFor_EmuState.Add(_("Broken")); - arrayStringFor_EmuState.Add(_("Intro")); - arrayStringFor_EmuState.Add(_("In Game")); - arrayStringFor_EmuState.Add(_("Playable")); - arrayStringFor_EmuState.Add(_("Perfect")); - EmuState = new wxChoice(m_GameConfig, ID_EMUSTATE, wxDefaultPosition, wxDefaultSize, arrayStringFor_EmuState); - EmuIssues = new wxTextCtrl(m_GameConfig, ID_EMU_ISSUES, wxEmptyString); + wxBoxSizer* const sEmuState = new wxBoxSizer(wxHORIZONTAL); + wxStaticText* const EmuStateText = + new wxStaticText(m_GameConfig, wxID_ANY, _("Emulation State: ")); + arrayStringFor_EmuState.Add(_("Not Set")); + arrayStringFor_EmuState.Add(_("Broken")); + arrayStringFor_EmuState.Add(_("Intro")); + arrayStringFor_EmuState.Add(_("In Game")); + arrayStringFor_EmuState.Add(_("Playable")); + arrayStringFor_EmuState.Add(_("Perfect")); + EmuState = new wxChoice(m_GameConfig, ID_EMUSTATE, wxDefaultPosition, wxDefaultSize, + arrayStringFor_EmuState); + EmuIssues = new wxTextCtrl(m_GameConfig, ID_EMU_ISSUES, wxEmptyString); - wxBoxSizer* const sConfigPage = new wxBoxSizer(wxVERTICAL); - wxStaticBoxSizer* const sbCoreOverrides = - new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Core")); - sbCoreOverrides->Add(CPUThread, 0, wxLEFT, 5); - sbCoreOverrides->Add(SkipIdle, 0, wxLEFT, 5); - sbCoreOverrides->Add(MMU, 0, wxLEFT, 5); - sbCoreOverrides->Add(DCBZOFF, 0, wxLEFT, 5); - sbCoreOverrides->Add(FPRF, 0, wxLEFT, 5); - sbCoreOverrides->Add(SyncGPU, 0, wxLEFT, 5); - sbCoreOverrides->Add(FastDiscSpeed, 0, wxLEFT, 5); - sbCoreOverrides->Add(DSPHLE, 0, wxLEFT, 5); - sbCoreOverrides->Add(sGPUDeterminism, 0, wxEXPAND|wxALL, 5); + wxBoxSizer* const sConfigPage = new wxBoxSizer(wxVERTICAL); + wxStaticBoxSizer* const sbCoreOverrides = + new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Core")); + sbCoreOverrides->Add(CPUThread, 0, wxLEFT, 5); + sbCoreOverrides->Add(SkipIdle, 0, wxLEFT, 5); + sbCoreOverrides->Add(MMU, 0, wxLEFT, 5); + sbCoreOverrides->Add(DCBZOFF, 0, wxLEFT, 5); + sbCoreOverrides->Add(FPRF, 0, wxLEFT, 5); + sbCoreOverrides->Add(SyncGPU, 0, wxLEFT, 5); + sbCoreOverrides->Add(FastDiscSpeed, 0, wxLEFT, 5); + sbCoreOverrides->Add(DSPHLE, 0, wxLEFT, 5); + sbCoreOverrides->Add(sGPUDeterminism, 0, wxEXPAND | wxALL, 5); - wxStaticBoxSizer * const sbWiiOverrides = new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Wii Console")); - if (m_open_iso->GetVolumeType() == DiscIO::IVolume::GAMECUBE_DISC) - { - sbWiiOverrides->ShowItems(false); - EnableWideScreen->Hide(); - } - sbWiiOverrides->Add(EnableWideScreen, 0, wxLEFT, 5); + wxStaticBoxSizer* const sbWiiOverrides = + new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Wii Console")); + if (m_open_iso->GetVolumeType() == DiscIO::IVolume::GAMECUBE_DISC) + { + sbWiiOverrides->ShowItems(false); + EnableWideScreen->Hide(); + } + sbWiiOverrides->Add(EnableWideScreen, 0, wxLEFT, 5); - wxStaticBoxSizer* const sbStereoOverrides = - new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Stereoscopy")); - sbStereoOverrides->Add(sDepthPercentage); - sbStereoOverrides->Add(sConvergence); - sbStereoOverrides->Add(MonoDepth); + wxStaticBoxSizer* const sbStereoOverrides = + new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Stereoscopy")); + sbStereoOverrides->Add(sDepthPercentage); + sbStereoOverrides->Add(sConvergence); + sbStereoOverrides->Add(MonoDepth); - wxStaticBoxSizer * const sbGameConfig = new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Game-Specific Settings")); - sbGameConfig->Add(OverrideText, 0, wxEXPAND|wxALL, 5); - sbGameConfig->Add(sbCoreOverrides, 0, wxEXPAND); - sbGameConfig->Add(sbWiiOverrides, 0, wxEXPAND); - sbGameConfig->Add(sbStereoOverrides, 0, wxEXPAND); - sConfigPage->Add(sbGameConfig, 0, wxEXPAND|wxALL, 5); - sEmuState->Add(EmuStateText, 0, wxALIGN_CENTER_VERTICAL); - sEmuState->Add(EmuState, 0, wxEXPAND); - sEmuState->Add(EmuIssues, 1, wxEXPAND); - sConfigPage->Add(sEmuState, 0, wxEXPAND|wxALL, 5); - m_GameConfig->SetSizer(sConfigPage); + wxStaticBoxSizer* const sbGameConfig = + new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Game-Specific Settings")); + sbGameConfig->Add(OverrideText, 0, wxEXPAND | wxALL, 5); + sbGameConfig->Add(sbCoreOverrides, 0, wxEXPAND); + sbGameConfig->Add(sbWiiOverrides, 0, wxEXPAND); + sbGameConfig->Add(sbStereoOverrides, 0, wxEXPAND); + sConfigPage->Add(sbGameConfig, 0, wxEXPAND | wxALL, 5); + sEmuState->Add(EmuStateText, 0, wxALIGN_CENTER_VERTICAL); + sEmuState->Add(EmuState, 0, wxEXPAND); + sEmuState->Add(EmuIssues, 1, wxEXPAND); + sConfigPage->Add(sEmuState, 0, wxEXPAND | wxALL, 5); + m_GameConfig->SetSizer(sConfigPage); + // Patches + wxBoxSizer* const sPatches = new wxBoxSizer(wxVERTICAL); + Patches = new wxCheckListBox(m_PatchPage, ID_PATCHES_LIST, wxDefaultPosition, wxDefaultSize, 0, + nullptr, wxLB_HSCROLL); + wxBoxSizer* const sPatchButtons = new wxBoxSizer(wxHORIZONTAL); + EditPatch = new wxButton(m_PatchPage, ID_EDITPATCH, _("Edit...")); + wxButton* const AddPatch = new wxButton(m_PatchPage, ID_ADDPATCH, _("Add...")); + RemovePatch = new wxButton(m_PatchPage, ID_REMOVEPATCH, _("Remove")); + EditPatch->Disable(); + RemovePatch->Disable(); - // Patches - wxBoxSizer* const sPatches = new wxBoxSizer(wxVERTICAL); - Patches = new wxCheckListBox(m_PatchPage, ID_PATCHES_LIST, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_HSCROLL); - wxBoxSizer* const sPatchButtons = new wxBoxSizer(wxHORIZONTAL); - EditPatch = new wxButton(m_PatchPage, ID_EDITPATCH, _("Edit...")); - wxButton* const AddPatch = new wxButton(m_PatchPage, ID_ADDPATCH, _("Add...")); - RemovePatch = new wxButton(m_PatchPage, ID_REMOVEPATCH, _("Remove")); - EditPatch->Disable(); - RemovePatch->Disable(); + wxBoxSizer* sPatchPage = new wxBoxSizer(wxVERTICAL); + sPatches->Add(Patches, 1, wxEXPAND | wxALL, 0); + sPatchButtons->Add(EditPatch, 0, wxEXPAND | wxALL, 0); + sPatchButtons->AddStretchSpacer(); + sPatchButtons->Add(AddPatch, 0, wxEXPAND | wxALL, 0); + sPatchButtons->Add(RemovePatch, 0, wxEXPAND | wxALL, 0); + sPatches->Add(sPatchButtons, 0, wxEXPAND | wxALL, 0); + sPatchPage->Add(sPatches, 1, wxEXPAND | wxALL, 5); + m_PatchPage->SetSizer(sPatchPage); - wxBoxSizer* sPatchPage = new wxBoxSizer(wxVERTICAL); - sPatches->Add(Patches, 1, wxEXPAND|wxALL, 0); - sPatchButtons->Add(EditPatch, 0, wxEXPAND|wxALL, 0); - sPatchButtons->AddStretchSpacer(); - sPatchButtons->Add(AddPatch, 0, wxEXPAND|wxALL, 0); - sPatchButtons->Add(RemovePatch, 0, wxEXPAND|wxALL, 0); - sPatches->Add(sPatchButtons, 0, wxEXPAND|wxALL, 0); - sPatchPage->Add(sPatches, 1, wxEXPAND|wxALL, 5); - m_PatchPage->SetSizer(sPatchPage); + // Action Replay Cheats + wxBoxSizer* const sCheats = new wxBoxSizer(wxVERTICAL); + Cheats = new wxCheckListBox(m_CheatPage, ID_CHEATS_LIST, wxDefaultPosition, wxDefaultSize, 0, + nullptr, wxLB_HSCROLL); + wxBoxSizer* const sCheatButtons = new wxBoxSizer(wxHORIZONTAL); + EditCheat = new wxButton(m_CheatPage, ID_EDITCHEAT, _("Edit...")); + wxButton* const AddCheat = new wxButton(m_CheatPage, ID_ADDCHEAT, _("Add...")); + RemoveCheat = new wxButton(m_CheatPage, ID_REMOVECHEAT, _("Remove")); + EditCheat->Disable(); + RemoveCheat->Disable(); + wxBoxSizer* sCheatPage = new wxBoxSizer(wxVERTICAL); + sCheats->Add(Cheats, 1, wxEXPAND | wxALL, 0); + sCheatButtons->Add(EditCheat, 0, wxEXPAND | wxALL, 0); + sCheatButtons->AddStretchSpacer(); + sCheatButtons->Add(AddCheat, 0, wxEXPAND | wxALL, 0); + sCheatButtons->Add(RemoveCheat, 0, wxEXPAND | wxALL, 0); + sCheats->Add(sCheatButtons, 0, wxEXPAND | wxALL, 0); + sCheatPage->Add(sCheats, 1, wxEXPAND | wxALL, 5); + m_CheatPage->SetSizer(sCheatPage); - // Action Replay Cheats - wxBoxSizer * const sCheats = new wxBoxSizer(wxVERTICAL); - Cheats = new wxCheckListBox(m_CheatPage, ID_CHEATS_LIST, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_HSCROLL); - wxBoxSizer * const sCheatButtons = new wxBoxSizer(wxHORIZONTAL); - EditCheat = new wxButton(m_CheatPage, ID_EDITCHEAT, _("Edit...")); - wxButton * const AddCheat = new wxButton(m_CheatPage, ID_ADDCHEAT, _("Add...")); - RemoveCheat = new wxButton(m_CheatPage, ID_REMOVECHEAT, _("Remove")); - EditCheat->Disable(); - RemoveCheat->Disable(); + wxStaticText* const m_InternalNameText = + new wxStaticText(m_Information, wxID_ANY, _("Internal Name:")); + m_InternalName = new wxTextCtrl(m_Information, ID_NAME, wxEmptyString, wxDefaultPosition, + wxDefaultSize, wxTE_READONLY); + wxStaticText* const m_GameIDText = new wxStaticText(m_Information, wxID_ANY, _("Game ID:")); + m_GameID = new wxTextCtrl(m_Information, ID_GAMEID, wxEmptyString, wxDefaultPosition, + wxDefaultSize, wxTE_READONLY); + wxStaticText* const m_CountryText = new wxStaticText(m_Information, wxID_ANY, _("Country:")); + m_Country = new wxTextCtrl(m_Information, ID_COUNTRY, wxEmptyString, wxDefaultPosition, + wxDefaultSize, wxTE_READONLY); + wxStaticText* const m_MakerIDText = new wxStaticText(m_Information, wxID_ANY, _("Maker ID:")); + m_MakerID = new wxTextCtrl(m_Information, ID_MAKERID, wxEmptyString, wxDefaultPosition, + wxDefaultSize, wxTE_READONLY); + wxStaticText* const m_RevisionText = new wxStaticText(m_Information, wxID_ANY, _("Revision:")); + m_Revision = new wxTextCtrl(m_Information, ID_REVISION, wxEmptyString, wxDefaultPosition, + wxDefaultSize, wxTE_READONLY); + wxStaticText* const m_DateText = new wxStaticText(m_Information, wxID_ANY, _("Apploader Date:")); + m_Date = new wxTextCtrl(m_Information, ID_DATE, wxEmptyString, wxDefaultPosition, wxDefaultSize, + wxTE_READONLY); + wxStaticText* const m_FSTText = new wxStaticText(m_Information, wxID_ANY, _("FST Size:")); + m_FST = new wxTextCtrl(m_Information, ID_FST, wxEmptyString, wxDefaultPosition, wxDefaultSize, + wxTE_READONLY); + wxStaticText* const m_MD5SumText = new wxStaticText(m_Information, wxID_ANY, _("MD5 Checksum:")); + m_MD5Sum = new wxTextCtrl(m_Information, ID_MD5SUM, wxEmptyString, wxDefaultPosition, + wxDefaultSize, wxTE_READONLY); + m_MD5SumCompute = new wxButton(m_Information, ID_MD5SUMCOMPUTE, _("Compute")); - wxBoxSizer* sCheatPage = new wxBoxSizer(wxVERTICAL); - sCheats->Add(Cheats, 1, wxEXPAND|wxALL, 0); - sCheatButtons->Add(EditCheat, 0, wxEXPAND|wxALL, 0); - sCheatButtons->AddStretchSpacer(); - sCheatButtons->Add(AddCheat, 0, wxEXPAND|wxALL, 0); - sCheatButtons->Add(RemoveCheat, 0, wxEXPAND|wxALL, 0); - sCheats->Add(sCheatButtons, 0, wxEXPAND|wxALL, 0); - sCheatPage->Add(sCheats, 1, wxEXPAND|wxALL, 5); - m_CheatPage->SetSizer(sCheatPage); + wxStaticText* const m_LangText = new wxStaticText(m_Information, wxID_ANY, _("Show Language:")); + bool wii = m_open_iso->GetVolumeType() != DiscIO::IVolume::GAMECUBE_DISC; + DiscIO::IVolume::ELanguage preferred_language = SConfig::GetInstance().GetCurrentLanguage(wii); - wxStaticText* const m_InternalNameText = new wxStaticText(m_Information, wxID_ANY, _("Internal Name:")); - m_InternalName = new wxTextCtrl(m_Information, ID_NAME, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY); - wxStaticText* const m_GameIDText = new wxStaticText(m_Information, wxID_ANY, _("Game ID:")); - m_GameID = new wxTextCtrl(m_Information, ID_GAMEID, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY); - wxStaticText* const m_CountryText = new wxStaticText(m_Information, wxID_ANY, _("Country:")); - m_Country = new wxTextCtrl(m_Information, ID_COUNTRY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY); - wxStaticText* const m_MakerIDText = new wxStaticText(m_Information, wxID_ANY, _("Maker ID:")); - m_MakerID = new wxTextCtrl(m_Information, ID_MAKERID, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY); - wxStaticText* const m_RevisionText = new wxStaticText(m_Information, wxID_ANY, _("Revision:")); - m_Revision = new wxTextCtrl(m_Information, ID_REVISION, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY); - wxStaticText* const m_DateText = new wxStaticText(m_Information, wxID_ANY, _("Apploader Date:")); - m_Date = new wxTextCtrl(m_Information, ID_DATE, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY); - wxStaticText* const m_FSTText = new wxStaticText(m_Information, wxID_ANY, _("FST Size:")); - m_FST = new wxTextCtrl(m_Information, ID_FST, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY); - wxStaticText* const m_MD5SumText = new wxStaticText(m_Information, wxID_ANY, _("MD5 Checksum:")); - m_MD5Sum = new wxTextCtrl(m_Information, ID_MD5SUM, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY); - m_MD5SumCompute = new wxButton(m_Information, ID_MD5SUMCOMPUTE, _("Compute")); + std::vector languages = OpenGameListItem.GetLanguages(); + int preferred_language_index = 0; + for (size_t i = 0; i < languages.size(); ++i) + { + if (languages[i] == preferred_language) + preferred_language_index = i; - wxStaticText* const m_LangText = new wxStaticText(m_Information, wxID_ANY, _("Show Language:")); + switch (languages[i]) + { + case DiscIO::IVolume::LANGUAGE_JAPANESE: + arrayStringFor_Lang.Add(_("Japanese")); + break; + case DiscIO::IVolume::LANGUAGE_ENGLISH: + arrayStringFor_Lang.Add(_("English")); + break; + case DiscIO::IVolume::LANGUAGE_GERMAN: + arrayStringFor_Lang.Add(_("German")); + break; + case DiscIO::IVolume::LANGUAGE_FRENCH: + arrayStringFor_Lang.Add(_("French")); + break; + case DiscIO::IVolume::LANGUAGE_SPANISH: + arrayStringFor_Lang.Add(_("Spanish")); + break; + case DiscIO::IVolume::LANGUAGE_ITALIAN: + arrayStringFor_Lang.Add(_("Italian")); + break; + case DiscIO::IVolume::LANGUAGE_DUTCH: + arrayStringFor_Lang.Add(_("Dutch")); + break; + case DiscIO::IVolume::LANGUAGE_SIMPLIFIED_CHINESE: + arrayStringFor_Lang.Add(_("Simplified Chinese")); + break; + case DiscIO::IVolume::LANGUAGE_TRADITIONAL_CHINESE: + arrayStringFor_Lang.Add(_("Traditional Chinese")); + break; + case DiscIO::IVolume::LANGUAGE_KOREAN: + arrayStringFor_Lang.Add(_("Korean")); + break; + case DiscIO::IVolume::LANGUAGE_UNKNOWN: + default: + arrayStringFor_Lang.Add(_("Unknown")); + break; + } + } + m_Lang = + new wxChoice(m_Information, ID_LANG, wxDefaultPosition, wxDefaultSize, arrayStringFor_Lang); + m_Lang->SetSelection(preferred_language_index); + if (arrayStringFor_Lang.size() <= 1) + m_Lang->Disable(); - bool wii = m_open_iso->GetVolumeType() != DiscIO::IVolume::GAMECUBE_DISC; - DiscIO::IVolume::ELanguage preferred_language = SConfig::GetInstance().GetCurrentLanguage(wii); + wxStaticText* const m_NameText = new wxStaticText(m_Information, wxID_ANY, _("Name:")); + m_Name = new wxTextCtrl(m_Information, ID_SHORTNAME, wxEmptyString, wxDefaultPosition, + wxDefaultSize, wxTE_READONLY); + wxStaticText* const m_MakerText = new wxStaticText(m_Information, wxID_ANY, _("Maker:")); + m_Maker = new wxTextCtrl(m_Information, ID_MAKER, wxEmptyString, wxDefaultPosition, wxDefaultSize, + wxTE_READONLY); + wxStaticText* const m_CommentText = new wxStaticText(m_Information, wxID_ANY, _("Description:")); + m_Comment = new wxTextCtrl(m_Information, ID_COMMENT, wxEmptyString, wxDefaultPosition, + wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY); + wxStaticText* const m_BannerText = new wxStaticText(m_Information, wxID_ANY, _("Banner:")); + m_Banner = + new wxStaticBitmap(m_Information, ID_BANNER, wxNullBitmap, wxDefaultPosition, wxSize(96, 32)); - std::vector languages = OpenGameListItem.GetLanguages(); - int preferred_language_index = 0; - for (size_t i = 0; i < languages.size(); ++i) - { - if (languages[i] == preferred_language) - preferred_language_index = i; + // ISO Details + wxGridBagSizer* const sISODetails = new wxGridBagSizer(0, 0); + sISODetails->Add(m_InternalNameText, wxGBPosition(0, 0), wxGBSpan(1, 1), + wxALIGN_CENTER_VERTICAL | wxALL, 5); + sISODetails->Add(m_InternalName, wxGBPosition(0, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5); + sISODetails->Add(m_GameIDText, wxGBPosition(1, 0), wxGBSpan(1, 1), + wxALIGN_CENTER_VERTICAL | wxALL, 5); + sISODetails->Add(m_GameID, wxGBPosition(1, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5); + sISODetails->Add(m_CountryText, wxGBPosition(2, 0), wxGBSpan(1, 1), + wxALIGN_CENTER_VERTICAL | wxALL, 5); + sISODetails->Add(m_Country, wxGBPosition(2, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5); + sISODetails->Add(m_MakerIDText, wxGBPosition(3, 0), wxGBSpan(1, 1), + wxALIGN_CENTER_VERTICAL | wxALL, 5); + sISODetails->Add(m_MakerID, wxGBPosition(3, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5); + sISODetails->Add(m_RevisionText, wxGBPosition(4, 0), wxGBSpan(1, 1), + wxALIGN_CENTER_VERTICAL | wxALL, 5); + sISODetails->Add(m_Revision, wxGBPosition(4, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5); + sISODetails->Add(m_DateText, wxGBPosition(5, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL | wxALL, + 5); + sISODetails->Add(m_Date, wxGBPosition(5, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5); + sISODetails->Add(m_FSTText, wxGBPosition(6, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL | wxALL, + 5); + sISODetails->Add(m_FST, wxGBPosition(6, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5); + sISODetails->Add(m_MD5SumText, wxGBPosition(7, 0), wxGBSpan(1, 1), + wxALIGN_CENTER_VERTICAL | wxALL, 5); + sISODetails->Add(m_MD5Sum, wxGBPosition(7, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5); + wxSizer* sMD5SumButtonSizer = CreateButtonSizer(wxNO_DEFAULT); + sMD5SumButtonSizer->Add(m_MD5SumCompute); + sISODetails->Add(sMD5SumButtonSizer, wxGBPosition(7, 2), wxGBSpan(1, 1), wxEXPAND | wxALL, 5); - switch (languages[i]) - { - case DiscIO::IVolume::LANGUAGE_JAPANESE: - arrayStringFor_Lang.Add(_("Japanese")); - break; - case DiscIO::IVolume::LANGUAGE_ENGLISH: - arrayStringFor_Lang.Add(_("English")); - break; - case DiscIO::IVolume::LANGUAGE_GERMAN: - arrayStringFor_Lang.Add(_("German")); - break; - case DiscIO::IVolume::LANGUAGE_FRENCH: - arrayStringFor_Lang.Add(_("French")); - break; - case DiscIO::IVolume::LANGUAGE_SPANISH: - arrayStringFor_Lang.Add(_("Spanish")); - break; - case DiscIO::IVolume::LANGUAGE_ITALIAN: - arrayStringFor_Lang.Add(_("Italian")); - break; - case DiscIO::IVolume::LANGUAGE_DUTCH: - arrayStringFor_Lang.Add(_("Dutch")); - break; - case DiscIO::IVolume::LANGUAGE_SIMPLIFIED_CHINESE: - arrayStringFor_Lang.Add(_("Simplified Chinese")); - break; - case DiscIO::IVolume::LANGUAGE_TRADITIONAL_CHINESE: - arrayStringFor_Lang.Add(_("Traditional Chinese")); - break; - case DiscIO::IVolume::LANGUAGE_KOREAN: - arrayStringFor_Lang.Add(_("Korean")); - break; - case DiscIO::IVolume::LANGUAGE_UNKNOWN: - default: - arrayStringFor_Lang.Add(_("Unknown")); - break; - } - } - m_Lang = new wxChoice(m_Information, ID_LANG, wxDefaultPosition, wxDefaultSize, arrayStringFor_Lang); - m_Lang->SetSelection(preferred_language_index); - if (arrayStringFor_Lang.size() <= 1) - m_Lang->Disable(); + sISODetails->AddGrowableCol(1); + wxStaticBoxSizer* const sbISODetails = + new wxStaticBoxSizer(wxVERTICAL, m_Information, _("ISO Details")); + sbISODetails->Add(sISODetails, 0, wxEXPAND, 5); - wxStaticText* const m_NameText = new wxStaticText(m_Information, wxID_ANY, _("Name:")); - m_Name = new wxTextCtrl(m_Information, ID_SHORTNAME, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY); - wxStaticText* const m_MakerText = new wxStaticText(m_Information, wxID_ANY, _("Maker:")); - m_Maker = new wxTextCtrl(m_Information, ID_MAKER, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY); - wxStaticText* const m_CommentText = new wxStaticText(m_Information, wxID_ANY, _("Description:")); - m_Comment = new wxTextCtrl(m_Information, ID_COMMENT, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY); - wxStaticText* const m_BannerText = new wxStaticText(m_Information, wxID_ANY, _("Banner:")); - m_Banner = new wxStaticBitmap(m_Information, ID_BANNER, wxNullBitmap, wxDefaultPosition, wxSize(96, 32)); + // Banner Details + wxGridBagSizer* const sBannerDetails = new wxGridBagSizer(0, 0); + sBannerDetails->Add(m_LangText, wxGBPosition(0, 0), wxGBSpan(1, 1), + wxALIGN_CENTER_VERTICAL | wxALL, 5); + sBannerDetails->Add(m_Lang, wxGBPosition(0, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5); + sBannerDetails->Add(m_NameText, wxGBPosition(1, 0), wxGBSpan(1, 1), + wxALIGN_CENTER_VERTICAL | wxALL, 5); + sBannerDetails->Add(m_Name, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5); + sBannerDetails->Add(m_MakerText, wxGBPosition(2, 0), wxGBSpan(1, 1), + wxALIGN_CENTER_VERTICAL | wxALL, 5); + sBannerDetails->Add(m_Maker, wxGBPosition(2, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5); + sBannerDetails->Add(m_CommentText, wxGBPosition(3, 0), wxGBSpan(1, 1), wxALL, 5); + sBannerDetails->Add(m_Comment, wxGBPosition(3, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5); + sBannerDetails->Add(m_BannerText, wxGBPosition(4, 0), wxGBSpan(1, 1), wxALL, 5); + sBannerDetails->Add(m_Banner, wxGBPosition(4, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5); + sBannerDetails->AddGrowableCol(1); + wxStaticBoxSizer* const sbBannerDetails = + new wxStaticBoxSizer(wxVERTICAL, m_Information, _("Banner Details")); + sbBannerDetails->Add(sBannerDetails, 0, wxEXPAND, 5); - // ISO Details - wxGridBagSizer* const sISODetails = new wxGridBagSizer(0, 0); - sISODetails->Add(m_InternalNameText, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); - sISODetails->Add(m_InternalName, wxGBPosition(0, 1), wxGBSpan(1, 2), wxEXPAND|wxALL, 5); - sISODetails->Add(m_GameIDText, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); - sISODetails->Add(m_GameID, wxGBPosition(1, 1), wxGBSpan(1, 2), wxEXPAND|wxALL, 5); - sISODetails->Add(m_CountryText, wxGBPosition(2, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); - sISODetails->Add(m_Country, wxGBPosition(2, 1), wxGBSpan(1, 2), wxEXPAND|wxALL, 5); - sISODetails->Add(m_MakerIDText, wxGBPosition(3, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); - sISODetails->Add(m_MakerID, wxGBPosition(3, 1), wxGBSpan(1, 2), wxEXPAND|wxALL, 5); - sISODetails->Add(m_RevisionText, wxGBPosition(4, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); - sISODetails->Add(m_Revision, wxGBPosition(4, 1), wxGBSpan(1, 2), wxEXPAND|wxALL, 5); - sISODetails->Add(m_DateText, wxGBPosition(5, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); - sISODetails->Add(m_Date, wxGBPosition(5, 1), wxGBSpan(1, 2), wxEXPAND|wxALL, 5); - sISODetails->Add(m_FSTText, wxGBPosition(6, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); - sISODetails->Add(m_FST, wxGBPosition(6, 1), wxGBSpan(1, 2), wxEXPAND|wxALL, 5); - sISODetails->Add(m_MD5SumText, wxGBPosition(7, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); - sISODetails->Add(m_MD5Sum, wxGBPosition(7, 1), wxGBSpan(1, 1), wxEXPAND|wxALL, 5); - wxSizer* sMD5SumButtonSizer = CreateButtonSizer(wxNO_DEFAULT); - sMD5SumButtonSizer->Add(m_MD5SumCompute); - sISODetails->Add(sMD5SumButtonSizer, wxGBPosition(7, 2), wxGBSpan(1, 1), wxEXPAND|wxALL, 5); + wxBoxSizer* const sInfoPage = new wxBoxSizer(wxVERTICAL); + sInfoPage->Add(sbISODetails, 0, wxEXPAND | wxALL, 5); + sInfoPage->Add(sbBannerDetails, 0, wxEXPAND | wxALL, 5); + m_Information->SetSizer(sInfoPage); - sISODetails->AddGrowableCol(1); - wxStaticBoxSizer* const sbISODetails = - new wxStaticBoxSizer(wxVERTICAL, m_Information, _("ISO Details")); - sbISODetails->Add(sISODetails, 0, wxEXPAND, 5); + if (m_open_iso->GetVolumeType() != DiscIO::IVolume::WII_WAD) + { + wxPanel* const filesystem_panel = new wxPanel(m_Notebook, ID_FILESYSTEM); + m_Notebook->AddPage(filesystem_panel, _("Filesystem")); - // Banner Details - wxGridBagSizer* const sBannerDetails = new wxGridBagSizer(0, 0); - sBannerDetails->Add(m_LangText, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); - sBannerDetails->Add(m_Lang, wxGBPosition(0, 1), wxGBSpan(1, 1), wxEXPAND|wxALL, 5); - sBannerDetails->Add(m_NameText, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); - sBannerDetails->Add(m_Name, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND|wxALL, 5); - sBannerDetails->Add(m_MakerText, wxGBPosition(2, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL|wxALL, 5); - sBannerDetails->Add(m_Maker, wxGBPosition(2, 1), wxGBSpan(1, 1), wxEXPAND|wxALL, 5); - sBannerDetails->Add(m_CommentText, wxGBPosition(3, 0), wxGBSpan(1, 1), wxALL, 5); - sBannerDetails->Add(m_Comment, wxGBPosition(3, 1), wxGBSpan(1, 1), wxEXPAND|wxALL, 5); - sBannerDetails->Add(m_BannerText, wxGBPosition(4, 0), wxGBSpan(1, 1), wxALL, 5); - sBannerDetails->Add(m_Banner, wxGBPosition(4, 1), wxGBSpan(1, 1), wxEXPAND|wxALL, 5); - sBannerDetails->AddGrowableCol(1); - wxStaticBoxSizer* const sbBannerDetails = - new wxStaticBoxSizer(wxVERTICAL, m_Information, _("Banner Details")); - sbBannerDetails->Add(sBannerDetails, 0, wxEXPAND, 5); + // Filesystem icons + wxImageList* const m_iconList = new wxImageList(16, 16); + m_iconList->Add(WxUtils::LoadResourceBitmap("isoproperties_disc")); // 0 + m_iconList->Add(WxUtils::LoadResourceBitmap("isoproperties_folder")); // 1 + m_iconList->Add(WxUtils::LoadResourceBitmap("isoproperties_file")); // 2 - wxBoxSizer* const sInfoPage = new wxBoxSizer(wxVERTICAL); - sInfoPage->Add(sbISODetails, 0, wxEXPAND|wxALL, 5); - sInfoPage->Add(sbBannerDetails, 0, wxEXPAND|wxALL, 5); - m_Information->SetSizer(sInfoPage); + // Filesystem tree + m_Treectrl = new wxTreeCtrl(filesystem_panel, ID_TREECTRL); + m_Treectrl->AssignImageList(m_iconList); + RootId = m_Treectrl->AddRoot(_("Disc"), 0, 0, nullptr); - if (m_open_iso->GetVolumeType() != DiscIO::IVolume::WII_WAD) - { - wxPanel* const filesystem_panel = new wxPanel(m_Notebook, ID_FILESYSTEM); - m_Notebook->AddPage(filesystem_panel, _("Filesystem")); + wxBoxSizer* sTreePage = new wxBoxSizer(wxVERTICAL); + sTreePage->Add(m_Treectrl, 1, wxEXPAND | wxALL, 5); + filesystem_panel->SetSizer(sTreePage); + } - // Filesystem icons - wxImageList* const m_iconList = new wxImageList(16, 16); - m_iconList->Add(WxUtils::LoadResourceBitmap("isoproperties_disc")); // 0 - m_iconList->Add(WxUtils::LoadResourceBitmap("isoproperties_folder")); // 1 - m_iconList->Add(WxUtils::LoadResourceBitmap("isoproperties_file")); // 2 + wxSizer* sButtons = CreateButtonSizer(wxNO_DEFAULT); + sButtons->Prepend(EditConfigDefault); + sButtons->Prepend(EditConfig); + sButtons->Add(new wxButton(this, wxID_OK, _("Close"))); - // Filesystem tree - m_Treectrl = new wxTreeCtrl(filesystem_panel, ID_TREECTRL); - m_Treectrl->AssignImageList(m_iconList); - RootId = m_Treectrl->AddRoot(_("Disc"), 0, 0, nullptr); + // If there is no default gameini, disable the button. + bool game_ini_exists = false; + for (const std::string& ini_filename : + SConfig::GetGameIniFilenames(game_id, m_open_iso->GetRevision())) + { + if (File::Exists(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + ini_filename)) + { + game_ini_exists = true; + break; + } + } + if (!game_ini_exists) + EditConfigDefault->Disable(); - wxBoxSizer* sTreePage = new wxBoxSizer(wxVERTICAL); - sTreePage->Add(m_Treectrl, 1, wxEXPAND|wxALL, 5); - filesystem_panel->SetSizer(sTreePage); - } + // Add notebook and buttons to the dialog + wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); + sMain->Add(m_Notebook, 1, wxEXPAND | wxALL, 5); + sMain->Add(sButtons, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + sMain->SetMinSize(wxSize(500, -1)); - wxSizer* sButtons = CreateButtonSizer(wxNO_DEFAULT); - sButtons->Prepend(EditConfigDefault); - sButtons->Prepend(EditConfig); - sButtons->Add(new wxButton(this, wxID_OK, _("Close"))); - - // If there is no default gameini, disable the button. - bool game_ini_exists = false; - for (const std::string& ini_filename : SConfig::GetGameIniFilenames(game_id, m_open_iso->GetRevision())) - { - if (File::Exists(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + ini_filename)) - { - game_ini_exists = true; - break; - } - } - if (!game_ini_exists) - EditConfigDefault->Disable(); - - // Add notebook and buttons to the dialog - wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); - sMain->Add(m_Notebook, 1, wxEXPAND|wxALL, 5); - sMain->Add(sButtons, 0, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, 5); - sMain->SetMinSize(wxSize(500, -1)); - - SetSizerAndFit(sMain); - Center(); - SetFocus(); + SetSizerAndFit(sMain); + Center(); + SetFocus(); } -void CISOProperties::OnClose(wxCloseEvent& WXUNUSED (event)) +void CISOProperties::OnClose(wxCloseEvent& WXUNUSED(event)) { - if (!SaveGameConfig()) - WxUtils::ShowErrorDialog(wxString::Format(_("Could not save %s."), GameIniFileLocal.c_str())); - Destroy(); + if (!SaveGameConfig()) + WxUtils::ShowErrorDialog(wxString::Format(_("Could not save %s."), GameIniFileLocal.c_str())); + Destroy(); } -void CISOProperties::OnCloseClick(wxCommandEvent& WXUNUSED (event)) +void CISOProperties::OnCloseClick(wxCommandEvent& WXUNUSED(event)) { - Close(); + Close(); } void CISOProperties::RightClickOnBanner(wxMouseEvent& event) { - wxMenu popupMenu; - popupMenu.Append(IDM_BNRSAVEAS, _("Save as...")); - PopupMenu(&popupMenu); + wxMenu popupMenu; + popupMenu.Append(IDM_BNRSAVEAS, _("Save as...")); + PopupMenu(&popupMenu); - event.Skip(); + event.Skip(); } -void CISOProperties::OnBannerImageSave(wxCommandEvent& WXUNUSED (event)) +void CISOProperties::OnBannerImageSave(wxCommandEvent& WXUNUSED(event)) { - wxString dirHome; + wxString dirHome; - wxFileDialog dialog(this, _("Save as..."), wxGetHomeDir(&dirHome), wxString::Format("%s.png", m_GameID->GetValue().c_str()), - wxALL_FILES_PATTERN, wxFD_SAVE|wxFD_OVERWRITE_PROMPT); - if (dialog.ShowModal() == wxID_OK) - { - m_Banner->GetBitmap().ConvertToImage().SaveFile(dialog.GetPath()); - } - Raise(); + wxFileDialog dialog(this, _("Save as..."), wxGetHomeDir(&dirHome), + wxString::Format("%s.png", m_GameID->GetValue().c_str()), wxALL_FILES_PATTERN, + wxFD_SAVE | wxFD_OVERWRITE_PROMPT); + if (dialog.ShowModal() == wxID_OK) + { + m_Banner->GetBitmap().ConvertToImage().SaveFile(dialog.GetPath()); + } + Raise(); } void CISOProperties::OnRightClickOnTree(wxTreeEvent& event) { - m_Treectrl->SelectItem(event.GetItem()); + m_Treectrl->SelectItem(event.GetItem()); - wxMenu popupMenu; + wxMenu popupMenu; - if (m_Treectrl->GetItemImage(m_Treectrl->GetSelection()) == 0 && - m_Treectrl->GetFirstVisibleItem() != m_Treectrl->GetSelection()) - { - popupMenu.Append(IDM_EXTRACTDIR, _("Extract Partition...")); - } - else if (m_Treectrl->GetItemImage(m_Treectrl->GetSelection()) == 1) - { - popupMenu.Append(IDM_EXTRACTDIR, _("Extract Directory...")); - } - else if (m_Treectrl->GetItemImage(m_Treectrl->GetSelection()) == 2) - { - popupMenu.Append(IDM_EXTRACTFILE, _("Extract File...")); - } + if (m_Treectrl->GetItemImage(m_Treectrl->GetSelection()) == 0 && + m_Treectrl->GetFirstVisibleItem() != m_Treectrl->GetSelection()) + { + popupMenu.Append(IDM_EXTRACTDIR, _("Extract Partition...")); + } + else if (m_Treectrl->GetItemImage(m_Treectrl->GetSelection()) == 1) + { + popupMenu.Append(IDM_EXTRACTDIR, _("Extract Directory...")); + } + else if (m_Treectrl->GetItemImage(m_Treectrl->GetSelection()) == 2) + { + popupMenu.Append(IDM_EXTRACTFILE, _("Extract File...")); + } - popupMenu.Append(IDM_EXTRACTALL, _("Extract All Files...")); + popupMenu.Append(IDM_EXTRACTALL, _("Extract All Files...")); - if (m_open_iso->GetVolumeType() != DiscIO::IVolume::WII_DISC || - (m_Treectrl->GetItemImage(m_Treectrl->GetSelection()) == 0 && - m_Treectrl->GetFirstVisibleItem() != m_Treectrl->GetSelection())) - { - popupMenu.AppendSeparator(); - popupMenu.Append(IDM_EXTRACTAPPLOADER, _("Extract Apploader...")); - popupMenu.Append(IDM_EXTRACTDOL, _("Extract DOL...")); - } + if (m_open_iso->GetVolumeType() != DiscIO::IVolume::WII_DISC || + (m_Treectrl->GetItemImage(m_Treectrl->GetSelection()) == 0 && + m_Treectrl->GetFirstVisibleItem() != m_Treectrl->GetSelection())) + { + popupMenu.AppendSeparator(); + popupMenu.Append(IDM_EXTRACTAPPLOADER, _("Extract Apploader...")); + popupMenu.Append(IDM_EXTRACTDOL, _("Extract DOL...")); + } - if (m_Treectrl->GetItemImage(m_Treectrl->GetSelection()) == 0 && - m_Treectrl->GetFirstVisibleItem() != m_Treectrl->GetSelection()) - { - popupMenu.AppendSeparator(); - popupMenu.Append(IDM_CHECKINTEGRITY, _("Check Partition Integrity")); - } + if (m_Treectrl->GetItemImage(m_Treectrl->GetSelection()) == 0 && + m_Treectrl->GetFirstVisibleItem() != m_Treectrl->GetSelection()) + { + popupMenu.AppendSeparator(); + popupMenu.Append(IDM_CHECKINTEGRITY, _("Check Partition Integrity")); + } - PopupMenu(&popupMenu); + PopupMenu(&popupMenu); - event.Skip(); + event.Skip(); } -void CISOProperties::OnExtractFile(wxCommandEvent& WXUNUSED (event)) +void CISOProperties::OnExtractFile(wxCommandEvent& WXUNUSED(event)) { - wxString File = m_Treectrl->GetItemText(m_Treectrl->GetSelection()); + wxString File = m_Treectrl->GetItemText(m_Treectrl->GetSelection()); - wxString Path = wxFileSelector( - _("Export File"), - wxEmptyString, File, wxEmptyString, - wxGetTranslation(wxALL_FILES), - wxFD_SAVE, - this); + wxString Path = wxFileSelector(_("Export File"), wxEmptyString, File, wxEmptyString, + wxGetTranslation(wxALL_FILES), wxFD_SAVE, this); - if (!Path || !File) - return; + if (!Path || !File) + return; - while (m_Treectrl->GetItemParent(m_Treectrl->GetSelection()) != m_Treectrl->GetRootItem()) - { - wxString temp = m_Treectrl->GetItemText(m_Treectrl->GetItemParent(m_Treectrl->GetSelection())); - File = temp + DIR_SEP_CHR + File; + while (m_Treectrl->GetItemParent(m_Treectrl->GetSelection()) != m_Treectrl->GetRootItem()) + { + wxString temp = m_Treectrl->GetItemText(m_Treectrl->GetItemParent(m_Treectrl->GetSelection())); + File = temp + DIR_SEP_CHR + File; - m_Treectrl->SelectItem(m_Treectrl->GetItemParent(m_Treectrl->GetSelection())); - } + m_Treectrl->SelectItem(m_Treectrl->GetItemParent(m_Treectrl->GetSelection())); + } - if (m_open_iso->GetVolumeType() == DiscIO::IVolume::WII_DISC) - { - const wxTreeItemId tree_selection = m_Treectrl->GetSelection(); - WiiPartition* partition = reinterpret_cast(m_Treectrl->GetItemData(tree_selection)); - File.erase(0, m_Treectrl->GetItemText(tree_selection).length() + 1); // Remove "Partition x/" + if (m_open_iso->GetVolumeType() == DiscIO::IVolume::WII_DISC) + { + const wxTreeItemId tree_selection = m_Treectrl->GetSelection(); + WiiPartition* partition = + reinterpret_cast(m_Treectrl->GetItemData(tree_selection)); + File.erase(0, m_Treectrl->GetItemText(tree_selection).length() + 1); // Remove "Partition x/" - partition->FileSystem->ExportFile(WxStrToStr(File), WxStrToStr(Path)); - } - else - { - m_filesystem->ExportFile(WxStrToStr(File), WxStrToStr(Path)); - } + partition->FileSystem->ExportFile(WxStrToStr(File), WxStrToStr(Path)); + } + else + { + m_filesystem->ExportFile(WxStrToStr(File), WxStrToStr(Path)); + } } -void CISOProperties::ExportDir(const std::string& _rFullPath, const std::string& _rExportFolder, const WiiPartition* partition) +void CISOProperties::ExportDir(const std::string& _rFullPath, const std::string& _rExportFolder, + const WiiPartition* partition) { - DiscIO::IFileSystem* const fs = m_open_iso->GetVolumeType() == DiscIO::IVolume::WII_DISC ? partition->FileSystem.get() : m_filesystem.get(); + DiscIO::IFileSystem* const fs = m_open_iso->GetVolumeType() == DiscIO::IVolume::WII_DISC ? + partition->FileSystem.get() : + m_filesystem.get(); - const std::vector& fst = fs->GetFileList(); + const std::vector& fst = fs->GetFileList(); - u32 index = 0; - u32 size = 0; + u32 index = 0; + u32 size = 0; - // Extract all - if (_rFullPath.empty()) - { - index = 0; - size = (u32)fst.size(); + // Extract all + if (_rFullPath.empty()) + { + index = 0; + size = (u32)fst.size(); - fs->ExportApploader(_rExportFolder); - if (m_open_iso->GetVolumeType() != DiscIO::IVolume::WII_DISC) - fs->ExportDOL(_rExportFolder); - } - else - { - // Look for the dir we are going to extract - for (index = 0; index != fst.size(); ++index) - { - if (fst[index].m_FullPath == _rFullPath) - { - DEBUG_LOG(DISCIO, "Found the directory at %u", index); - size = (u32)fst[index].m_FileSize; - break; - } - } + fs->ExportApploader(_rExportFolder); + if (m_open_iso->GetVolumeType() != DiscIO::IVolume::WII_DISC) + fs->ExportDOL(_rExportFolder); + } + else + { + // Look for the dir we are going to extract + for (index = 0; index != fst.size(); ++index) + { + if (fst[index].m_FullPath == _rFullPath) + { + DEBUG_LOG(DISCIO, "Found the directory at %u", index); + size = (u32)fst[index].m_FileSize; + break; + } + } - DEBUG_LOG(DISCIO,"Directory found from %u to %u\nextracting to:\n%s", index , size, _rExportFolder.c_str()); - } + DEBUG_LOG(DISCIO, "Directory found from %u to %u\nextracting to:\n%s", index, size, + _rExportFolder.c_str()); + } - wxString dialogTitle = (index != 0) ? _("Extracting Directory") : _("Extracting All Files"); - wxProgressDialog dialog( - dialogTitle, - _("Extracting..."), - size - 1, - this, - wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT | - wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | - wxPD_SMOOTH - ); + wxString dialogTitle = (index != 0) ? _("Extracting Directory") : _("Extracting All Files"); + wxProgressDialog dialog(dialogTitle, _("Extracting..."), size - 1, this, + wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME | + wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_SMOOTH); - // Extraction - for (u32 i = index; i < size; i++) - { - dialog.SetTitle(wxString::Format("%s : %d%%", dialogTitle.c_str(), - (u32)(((float)(i - index) / (float)(size - index)) * 100))); + // Extraction + for (u32 i = index; i < size; i++) + { + dialog.SetTitle(wxString::Format("%s : %d%%", dialogTitle.c_str(), + (u32)(((float)(i - index) / (float)(size - index)) * 100))); - dialog.Update(i, wxString::Format(_("Extracting %s"), StrToWxStr(fst[i].m_FullPath))); + dialog.Update(i, wxString::Format(_("Extracting %s"), StrToWxStr(fst[i].m_FullPath))); - if (dialog.WasCancelled()) - break; + if (dialog.WasCancelled()) + break; - if (fst[i].IsDirectory()) - { - const std::string exportName = StringFromFormat("%s/%s/", _rExportFolder.c_str(), fst[i].m_FullPath.c_str()); - DEBUG_LOG(DISCIO, "%s", exportName.c_str()); + if (fst[i].IsDirectory()) + { + const std::string exportName = + StringFromFormat("%s/%s/", _rExportFolder.c_str(), fst[i].m_FullPath.c_str()); + DEBUG_LOG(DISCIO, "%s", exportName.c_str()); - if (!File::Exists(exportName) && !File::CreateFullPath(exportName)) - { - ERROR_LOG(DISCIO, "Could not create the path %s", exportName.c_str()); - } - else - { - if (!File::IsDirectory(exportName)) - ERROR_LOG(DISCIO, "%s already exists and is not a directory", exportName.c_str()); + if (!File::Exists(exportName) && !File::CreateFullPath(exportName)) + { + ERROR_LOG(DISCIO, "Could not create the path %s", exportName.c_str()); + } + else + { + if (!File::IsDirectory(exportName)) + ERROR_LOG(DISCIO, "%s already exists and is not a directory", exportName.c_str()); - DEBUG_LOG(DISCIO, "Folder %s already exists", exportName.c_str()); - } - } - else - { - const std::string exportName = StringFromFormat("%s/%s", _rExportFolder.c_str(), fst[i].m_FullPath.c_str()); - DEBUG_LOG(DISCIO, "%s", exportName.c_str()); + DEBUG_LOG(DISCIO, "Folder %s already exists", exportName.c_str()); + } + } + else + { + const std::string exportName = + StringFromFormat("%s/%s", _rExportFolder.c_str(), fst[i].m_FullPath.c_str()); + DEBUG_LOG(DISCIO, "%s", exportName.c_str()); - if (!File::Exists(exportName) && !fs->ExportFile(fst[i].m_FullPath, exportName)) - { - ERROR_LOG(DISCIO, "Could not export %s", exportName.c_str()); - } - else - { - DEBUG_LOG(DISCIO, "%s already exists", exportName.c_str()); - } - } - } + if (!File::Exists(exportName) && !fs->ExportFile(fst[i].m_FullPath, exportName)) + { + ERROR_LOG(DISCIO, "Could not export %s", exportName.c_str()); + } + else + { + DEBUG_LOG(DISCIO, "%s already exists", exportName.c_str()); + } + } + } } void CISOProperties::OnExtractDir(wxCommandEvent& event) { - wxString Directory = m_Treectrl->GetItemText(m_Treectrl->GetSelection()); - wxString Path = wxDirSelector(_("Choose the folder to extract to")); + wxString Directory = m_Treectrl->GetItemText(m_Treectrl->GetSelection()); + wxString Path = wxDirSelector(_("Choose the folder to extract to")); - if (!Path || !Directory) - return; + if (!Path || !Directory) + return; - if (event.GetId() == IDM_EXTRACTALL) - { - if (m_open_iso->GetVolumeType() == DiscIO::IVolume::WII_DISC) - { - wxTreeItemIdValue cookie; - wxTreeItemId root = m_Treectrl->GetRootItem(); - wxTreeItemId item = m_Treectrl->GetFirstChild(root, cookie); - while (item.IsOk()) - { - ExportDir("", WxStrToStr(Path), reinterpret_cast(m_Treectrl->GetItemData(item))); - item = m_Treectrl->GetNextChild(root, cookie); - } - } - else - { - ExportDir("", WxStrToStr(Path)); - } + if (event.GetId() == IDM_EXTRACTALL) + { + if (m_open_iso->GetVolumeType() == DiscIO::IVolume::WII_DISC) + { + wxTreeItemIdValue cookie; + wxTreeItemId root = m_Treectrl->GetRootItem(); + wxTreeItemId item = m_Treectrl->GetFirstChild(root, cookie); + while (item.IsOk()) + { + ExportDir("", WxStrToStr(Path), + reinterpret_cast(m_Treectrl->GetItemData(item))); + item = m_Treectrl->GetNextChild(root, cookie); + } + } + else + { + ExportDir("", WxStrToStr(Path)); + } - return; - } + return; + } - while (m_Treectrl->GetItemParent(m_Treectrl->GetSelection()) != m_Treectrl->GetRootItem()) - { - wxString temp = m_Treectrl->GetItemText(m_Treectrl->GetItemParent(m_Treectrl->GetSelection())); - Directory = temp + DIR_SEP_CHR + Directory; + while (m_Treectrl->GetItemParent(m_Treectrl->GetSelection()) != m_Treectrl->GetRootItem()) + { + wxString temp = m_Treectrl->GetItemText(m_Treectrl->GetItemParent(m_Treectrl->GetSelection())); + Directory = temp + DIR_SEP_CHR + Directory; - m_Treectrl->SelectItem(m_Treectrl->GetItemParent(m_Treectrl->GetSelection())); - } + m_Treectrl->SelectItem(m_Treectrl->GetItemParent(m_Treectrl->GetSelection())); + } - Directory += DIR_SEP_CHR; + Directory += DIR_SEP_CHR; - if (m_open_iso->GetVolumeType() == DiscIO::IVolume::WII_DISC) - { - const wxTreeItemId tree_selection = m_Treectrl->GetSelection(); - WiiPartition* partition = reinterpret_cast(m_Treectrl->GetItemData(tree_selection)); - Directory.erase(0, m_Treectrl->GetItemText(tree_selection).length() + 1); // Remove "Partition x/" + if (m_open_iso->GetVolumeType() == DiscIO::IVolume::WII_DISC) + { + const wxTreeItemId tree_selection = m_Treectrl->GetSelection(); + WiiPartition* partition = + reinterpret_cast(m_Treectrl->GetItemData(tree_selection)); + Directory.erase(0, + m_Treectrl->GetItemText(tree_selection).length() + 1); // Remove "Partition x/" - ExportDir(WxStrToStr(Directory), WxStrToStr(Path), partition); - } - else - { - ExportDir(WxStrToStr(Directory), WxStrToStr(Path)); - } + ExportDir(WxStrToStr(Directory), WxStrToStr(Path), partition); + } + else + { + ExportDir(WxStrToStr(Directory), WxStrToStr(Path)); + } } void CISOProperties::OnExtractDataFromHeader(wxCommandEvent& event) { - DiscIO::IFileSystem *FS = nullptr; - wxString Path = wxDirSelector(_("Choose the folder to extract to")); + DiscIO::IFileSystem* FS = nullptr; + wxString Path = wxDirSelector(_("Choose the folder to extract to")); - if (Path.empty()) - return; + if (Path.empty()) + return; - if (m_open_iso->GetVolumeType() == DiscIO::IVolume::WII_DISC) - { - WiiPartition* partition = reinterpret_cast(m_Treectrl->GetItemData(m_Treectrl->GetSelection())); - FS = partition->FileSystem.get(); - } - else - { - FS = m_filesystem.get(); - } + if (m_open_iso->GetVolumeType() == DiscIO::IVolume::WII_DISC) + { + WiiPartition* partition = + reinterpret_cast(m_Treectrl->GetItemData(m_Treectrl->GetSelection())); + FS = partition->FileSystem.get(); + } + else + { + FS = m_filesystem.get(); + } - bool ret = false; - if (event.GetId() == IDM_EXTRACTAPPLOADER) - { - ret = FS->ExportApploader(WxStrToStr(Path)); - } - else if (event.GetId() == IDM_EXTRACTDOL) - { - ret = FS->ExportDOL(WxStrToStr(Path)); - } + bool ret = false; + if (event.GetId() == IDM_EXTRACTAPPLOADER) + { + ret = FS->ExportApploader(WxStrToStr(Path)); + } + else if (event.GetId() == IDM_EXTRACTDOL) + { + ret = FS->ExportDOL(WxStrToStr(Path)); + } - if (!ret) - WxUtils::ShowErrorDialog(wxString::Format(_("Failed to extract to %s!"), WxStrToStr(Path).c_str())); + if (!ret) + WxUtils::ShowErrorDialog( + wxString::Format(_("Failed to extract to %s!"), WxStrToStr(Path).c_str())); } class IntegrityCheckThread : public wxThread { public: - IntegrityCheckThread(const WiiPartition& Partition) - : wxThread(wxTHREAD_JOINABLE), m_Partition(Partition) - { - Create(); - } - - ExitCode Entry() override - { - return (ExitCode)m_Partition.Partition->CheckIntegrity(); - } + IntegrityCheckThread(const WiiPartition& Partition) + : wxThread(wxTHREAD_JOINABLE), m_Partition(Partition) + { + Create(); + } + ExitCode Entry() override { return (ExitCode)m_Partition.Partition->CheckIntegrity(); } private: - const WiiPartition& m_Partition; + const WiiPartition& m_Partition; }; void CISOProperties::CheckPartitionIntegrity(wxCommandEvent& event) { - // Normally we can't enter this function if we aren't analyzing a Wii disc - // anyway, but let's still check to be sure. - if (m_open_iso->GetVolumeType() != DiscIO::IVolume::WII_DISC) - return; + // Normally we can't enter this function if we aren't analyzing a Wii disc + // anyway, but let's still check to be sure. + if (m_open_iso->GetVolumeType() != DiscIO::IVolume::WII_DISC) + return; - wxProgressDialog dialog(_("Checking integrity..."), _("Working..."), 1000, this, - wxPD_APP_MODAL | wxPD_ELAPSED_TIME | wxPD_SMOOTH - ); + wxProgressDialog dialog(_("Checking integrity..."), _("Working..."), 1000, this, + wxPD_APP_MODAL | wxPD_ELAPSED_TIME | wxPD_SMOOTH); - WiiPartition* partition = reinterpret_cast(m_Treectrl->GetItemData(m_Treectrl->GetSelection())); - IntegrityCheckThread thread(*partition); - thread.Run(); + WiiPartition* partition = + reinterpret_cast(m_Treectrl->GetItemData(m_Treectrl->GetSelection())); + IntegrityCheckThread thread(*partition); + thread.Run(); - while (thread.IsAlive()) - { - dialog.Pulse(); - wxThread::Sleep(50); - } + while (thread.IsAlive()) + { + dialog.Pulse(); + wxThread::Sleep(50); + } - dialog.Destroy(); + dialog.Destroy(); - if (!thread.Wait()) - { - wxMessageBox( - wxString::Format(_("Integrity check for %s failed. The disc image is most " - "likely corrupted or has been patched incorrectly."), - m_Treectrl->GetItemText(m_Treectrl->GetSelection())), - _("Integrity Check Error"), wxOK | wxICON_ERROR, this - ); - } - else - { - wxMessageBox(_("Integrity check completed. No errors have been found."), - _("Integrity check completed"), wxOK | wxICON_INFORMATION, this); - } + if (!thread.Wait()) + { + wxMessageBox(wxString::Format(_("Integrity check for %s failed. The disc image is most " + "likely corrupted or has been patched incorrectly."), + m_Treectrl->GetItemText(m_Treectrl->GetSelection())), + _("Integrity Check Error"), wxOK | wxICON_ERROR, this); + } + else + { + wxMessageBox(_("Integrity check completed. No errors have been found."), + _("Integrity check completed"), wxOK | wxICON_INFORMATION, this); + } } void CISOProperties::OnEmustateChanged(wxCommandEvent& event) { - EmuIssues->Enable(event.GetSelection() != 0); + EmuIssues->Enable(event.GetSelection() != 0); } -void CISOProperties::SetCheckboxValueFromGameini(const char* section, const char* key, wxCheckBox* checkbox) +void CISOProperties::SetCheckboxValueFromGameini(const char* section, const char* key, + wxCheckBox* checkbox) { - // Prefer local gameini value over default gameini value. - bool value; - if (GameIniLocal.GetOrCreateSection(section)->Get(key, &value)) - checkbox->Set3StateValue((wxCheckBoxState)value); - else if (GameIniDefault.GetOrCreateSection(section)->Get(key, &value)) - checkbox->Set3StateValue((wxCheckBoxState)value); - else - checkbox->Set3StateValue(wxCHK_UNDETERMINED); + // Prefer local gameini value over default gameini value. + bool value; + if (GameIniLocal.GetOrCreateSection(section)->Get(key, &value)) + checkbox->Set3StateValue((wxCheckBoxState)value); + else if (GameIniDefault.GetOrCreateSection(section)->Get(key, &value)) + checkbox->Set3StateValue((wxCheckBoxState)value); + else + checkbox->Set3StateValue(wxCHK_UNDETERMINED); } void CISOProperties::LoadGameConfig() { - SetCheckboxValueFromGameini("Core", "CPUThread", CPUThread); - SetCheckboxValueFromGameini("Core", "SkipIdle", SkipIdle); - SetCheckboxValueFromGameini("Core", "MMU", MMU); - SetCheckboxValueFromGameini("Core", "DCBZ", DCBZOFF); - SetCheckboxValueFromGameini("Core", "FPRF", FPRF); - SetCheckboxValueFromGameini("Core", "SyncGPU", SyncGPU); - SetCheckboxValueFromGameini("Core", "FastDiscSpeed", FastDiscSpeed); - SetCheckboxValueFromGameini("Core", "DSPHLE", DSPHLE); - SetCheckboxValueFromGameini("Wii", "Widescreen", EnableWideScreen); - SetCheckboxValueFromGameini("Video_Stereoscopy", "StereoEFBMonoDepth", MonoDepth); + SetCheckboxValueFromGameini("Core", "CPUThread", CPUThread); + SetCheckboxValueFromGameini("Core", "SkipIdle", SkipIdle); + SetCheckboxValueFromGameini("Core", "MMU", MMU); + SetCheckboxValueFromGameini("Core", "DCBZ", DCBZOFF); + SetCheckboxValueFromGameini("Core", "FPRF", FPRF); + SetCheckboxValueFromGameini("Core", "SyncGPU", SyncGPU); + SetCheckboxValueFromGameini("Core", "FastDiscSpeed", FastDiscSpeed); + SetCheckboxValueFromGameini("Core", "DSPHLE", DSPHLE); + SetCheckboxValueFromGameini("Wii", "Widescreen", EnableWideScreen); + SetCheckboxValueFromGameini("Video_Stereoscopy", "StereoEFBMonoDepth", MonoDepth); - IniFile::Section* default_video = GameIniDefault.GetOrCreateSection("Video"); + IniFile::Section* default_video = GameIniDefault.GetOrCreateSection("Video"); - int iTemp; - default_video->Get("ProjectionHack", &iTemp); - default_video->Get("PH_SZNear", &m_PHack_Data.PHackSZNear); - if (GameIniLocal.GetIfExists("Video", "PH_SZNear", &iTemp)) - m_PHack_Data.PHackSZNear = !!iTemp; - default_video->Get("PH_SZFar", &m_PHack_Data.PHackSZFar); - if (GameIniLocal.GetIfExists("Video", "PH_SZFar", &iTemp)) - m_PHack_Data.PHackSZFar = !!iTemp; + int iTemp; + default_video->Get("ProjectionHack", &iTemp); + default_video->Get("PH_SZNear", &m_PHack_Data.PHackSZNear); + if (GameIniLocal.GetIfExists("Video", "PH_SZNear", &iTemp)) + m_PHack_Data.PHackSZNear = !!iTemp; + default_video->Get("PH_SZFar", &m_PHack_Data.PHackSZFar); + if (GameIniLocal.GetIfExists("Video", "PH_SZFar", &iTemp)) + m_PHack_Data.PHackSZFar = !!iTemp; - std::string sTemp; - default_video->Get("PH_ZNear", &m_PHack_Data.PHZNear); - if (GameIniLocal.GetIfExists("Video", "PH_ZNear", &sTemp)) - m_PHack_Data.PHZNear = sTemp; - default_video->Get("PH_ZFar", &m_PHack_Data.PHZFar); - if (GameIniLocal.GetIfExists("Video", "PH_ZFar", &sTemp)) - m_PHack_Data.PHZFar = sTemp; + std::string sTemp; + default_video->Get("PH_ZNear", &m_PHack_Data.PHZNear); + if (GameIniLocal.GetIfExists("Video", "PH_ZNear", &sTemp)) + m_PHack_Data.PHZNear = sTemp; + default_video->Get("PH_ZFar", &m_PHack_Data.PHZFar); + if (GameIniLocal.GetIfExists("Video", "PH_ZFar", &sTemp)) + m_PHack_Data.PHZFar = sTemp; - IniFile::Section* default_emustate = GameIniDefault.GetOrCreateSection("EmuState"); - default_emustate->Get("EmulationStateId", &iTemp, 0/*Not Set*/); - EmuState->SetSelection(iTemp); - if (GameIniLocal.GetIfExists("EmuState", "EmulationStateId", &iTemp)) - EmuState->SetSelection(iTemp); + IniFile::Section* default_emustate = GameIniDefault.GetOrCreateSection("EmuState"); + default_emustate->Get("EmulationStateId", &iTemp, 0 /*Not Set*/); + EmuState->SetSelection(iTemp); + if (GameIniLocal.GetIfExists("EmuState", "EmulationStateId", &iTemp)) + EmuState->SetSelection(iTemp); - default_emustate->Get("EmulationIssues", &sTemp); - if (!sTemp.empty()) - EmuIssues->SetValue(StrToWxStr(sTemp)); - if (GameIniLocal.GetIfExists("EmuState", "EmulationIssues", &sTemp)) - EmuIssues->SetValue(StrToWxStr(sTemp)); + default_emustate->Get("EmulationIssues", &sTemp); + if (!sTemp.empty()) + EmuIssues->SetValue(StrToWxStr(sTemp)); + if (GameIniLocal.GetIfExists("EmuState", "EmulationIssues", &sTemp)) + EmuIssues->SetValue(StrToWxStr(sTemp)); - EmuIssues->Enable(EmuState->GetSelection() != 0); + EmuIssues->Enable(EmuState->GetSelection() != 0); - sTemp = ""; - if (!GameIniLocal.GetIfExists("Core", "GPUDeterminismMode", &sTemp)) - GameIniDefault.GetIfExists("Core", "GPUDeterminismMode", &sTemp); + sTemp = ""; + if (!GameIniLocal.GetIfExists("Core", "GPUDeterminismMode", &sTemp)) + GameIniDefault.GetIfExists("Core", "GPUDeterminismMode", &sTemp); - if (sTemp == "") - GPUDeterminism->SetSelection(0); - else if (sTemp == "auto") - GPUDeterminism->SetSelection(1); - else if (sTemp == "none") - GPUDeterminism->SetSelection(2); - else if (sTemp == "fake-completion") - GPUDeterminism->SetSelection(3); + if (sTemp == "") + GPUDeterminism->SetSelection(0); + else if (sTemp == "auto") + GPUDeterminism->SetSelection(1); + else if (sTemp == "none") + GPUDeterminism->SetSelection(2); + else if (sTemp == "fake-completion") + GPUDeterminism->SetSelection(3); - IniFile::Section* default_stereoscopy = GameIniDefault.GetOrCreateSection("Video_Stereoscopy"); - default_stereoscopy->Get("StereoDepthPercentage", &iTemp, 100); - GameIniLocal.GetIfExists("Video_Stereoscopy", "StereoDepthPercentage", &iTemp); - DepthPercentage->SetValue(iTemp); - default_stereoscopy->Get("StereoConvergence", &iTemp, 0); - GameIniLocal.GetIfExists("Video_Stereoscopy", "StereoConvergence", &iTemp); - Convergence->SetValue(iTemp); + IniFile::Section* default_stereoscopy = GameIniDefault.GetOrCreateSection("Video_Stereoscopy"); + default_stereoscopy->Get("StereoDepthPercentage", &iTemp, 100); + GameIniLocal.GetIfExists("Video_Stereoscopy", "StereoDepthPercentage", &iTemp); + DepthPercentage->SetValue(iTemp); + default_stereoscopy->Get("StereoConvergence", &iTemp, 0); + GameIniLocal.GetIfExists("Video_Stereoscopy", "StereoConvergence", &iTemp); + Convergence->SetValue(iTemp); - PatchList_Load(); - ActionReplayList_Load(); - m_geckocode_panel->LoadCodes(GameIniDefault, GameIniLocal, m_open_iso->GetUniqueID()); + PatchList_Load(); + ActionReplayList_Load(); + m_geckocode_panel->LoadCodes(GameIniDefault, GameIniLocal, m_open_iso->GetUniqueID()); } -void CISOProperties::SaveGameIniValueFrom3StateCheckbox(const char* section, const char* key, wxCheckBox* checkbox) +void CISOProperties::SaveGameIniValueFrom3StateCheckbox(const char* section, const char* key, + wxCheckBox* checkbox) { - // Delete any existing entries from the local gameini if checkbox is undetermined. - // Otherwise, write the current value to the local gameini if the value differs from the default gameini values. - // Delete any existing entry from the local gameini if the value does not differ from the default gameini value. - bool checkbox_val = (checkbox->Get3StateValue() == wxCHK_CHECKED); + // Delete any existing entries from the local gameini if checkbox is undetermined. + // Otherwise, write the current value to the local gameini if the value differs from the default + // gameini values. + // Delete any existing entry from the local gameini if the value does not differ from the default + // gameini value. + bool checkbox_val = (checkbox->Get3StateValue() == wxCHK_CHECKED); - if (checkbox->Get3StateValue() == wxCHK_UNDETERMINED) - GameIniLocal.DeleteKey(section, key); - else if (!GameIniDefault.Exists(section, key)) - GameIniLocal.GetOrCreateSection(section)->Set(key, checkbox_val); - else - { - bool default_value; - GameIniDefault.GetOrCreateSection(section)->Get(key, &default_value); - if (default_value != checkbox_val) - GameIniLocal.GetOrCreateSection(section)->Set(key, checkbox_val); - else - GameIniLocal.DeleteKey(section, key); - } + if (checkbox->Get3StateValue() == wxCHK_UNDETERMINED) + GameIniLocal.DeleteKey(section, key); + else if (!GameIniDefault.Exists(section, key)) + GameIniLocal.GetOrCreateSection(section)->Set(key, checkbox_val); + else + { + bool default_value; + GameIniDefault.GetOrCreateSection(section)->Get(key, &default_value); + if (default_value != checkbox_val) + GameIniLocal.GetOrCreateSection(section)->Set(key, checkbox_val); + else + GameIniLocal.DeleteKey(section, key); + } } bool CISOProperties::SaveGameConfig() { - SaveGameIniValueFrom3StateCheckbox("Core", "CPUThread", CPUThread); - SaveGameIniValueFrom3StateCheckbox("Core", "SkipIdle", SkipIdle); - SaveGameIniValueFrom3StateCheckbox("Core", "MMU", MMU); - SaveGameIniValueFrom3StateCheckbox("Core", "DCBZ", DCBZOFF); - SaveGameIniValueFrom3StateCheckbox("Core", "FPRF", FPRF); - SaveGameIniValueFrom3StateCheckbox("Core", "SyncGPU", SyncGPU); - SaveGameIniValueFrom3StateCheckbox("Core", "FastDiscSpeed", FastDiscSpeed); - SaveGameIniValueFrom3StateCheckbox("Core", "DSPHLE", DSPHLE); - SaveGameIniValueFrom3StateCheckbox("Wii", "Widescreen", EnableWideScreen); - SaveGameIniValueFrom3StateCheckbox("Video_Stereoscopy", "StereoEFBMonoDepth", MonoDepth); + SaveGameIniValueFrom3StateCheckbox("Core", "CPUThread", CPUThread); + SaveGameIniValueFrom3StateCheckbox("Core", "SkipIdle", SkipIdle); + SaveGameIniValueFrom3StateCheckbox("Core", "MMU", MMU); + SaveGameIniValueFrom3StateCheckbox("Core", "DCBZ", DCBZOFF); + SaveGameIniValueFrom3StateCheckbox("Core", "FPRF", FPRF); + SaveGameIniValueFrom3StateCheckbox("Core", "SyncGPU", SyncGPU); + SaveGameIniValueFrom3StateCheckbox("Core", "FastDiscSpeed", FastDiscSpeed); + SaveGameIniValueFrom3StateCheckbox("Core", "DSPHLE", DSPHLE); + SaveGameIniValueFrom3StateCheckbox("Wii", "Widescreen", EnableWideScreen); + SaveGameIniValueFrom3StateCheckbox("Video_Stereoscopy", "StereoEFBMonoDepth", MonoDepth); - #define SAVE_IF_NOT_DEFAULT(section, key, val, def) do { \ - if (GameIniDefault.Exists((section), (key))) { \ - std::remove_reference::type tmp__; \ - GameIniDefault.GetOrCreateSection((section))->Get((key), &tmp__); \ - if ((val) != tmp__) \ - GameIniLocal.GetOrCreateSection((section))->Set((key), (val)); \ - else \ - GameIniLocal.DeleteKey((section), (key)); \ - } else if ((val) != (def)) \ - GameIniLocal.GetOrCreateSection((section))->Set((key), (val)); \ - else \ - GameIniLocal.DeleteKey((section), (key)); \ - } while (0) +#define SAVE_IF_NOT_DEFAULT(section, key, val, def) \ + do \ + { \ + if (GameIniDefault.Exists((section), (key))) \ + { \ + std::remove_reference::type tmp__; \ + GameIniDefault.GetOrCreateSection((section))->Get((key), &tmp__); \ + if ((val) != tmp__) \ + GameIniLocal.GetOrCreateSection((section))->Set((key), (val)); \ + else \ + GameIniLocal.DeleteKey((section), (key)); \ + } \ + else if ((val) != (def)) \ + GameIniLocal.GetOrCreateSection((section))->Set((key), (val)); \ + else \ + GameIniLocal.DeleteKey((section), (key)); \ + } while (0) - SAVE_IF_NOT_DEFAULT("Video", "PH_SZNear", (m_PHack_Data.PHackSZNear ? 1 : 0), 0); - SAVE_IF_NOT_DEFAULT("Video", "PH_SZFar", (m_PHack_Data.PHackSZFar ? 1 : 0), 0); - SAVE_IF_NOT_DEFAULT("Video", "PH_ZNear", m_PHack_Data.PHZNear, ""); - SAVE_IF_NOT_DEFAULT("Video", "PH_ZFar", m_PHack_Data.PHZFar, ""); - SAVE_IF_NOT_DEFAULT("EmuState", "EmulationStateId", EmuState->GetSelection(), 0); + SAVE_IF_NOT_DEFAULT("Video", "PH_SZNear", (m_PHack_Data.PHackSZNear ? 1 : 0), 0); + SAVE_IF_NOT_DEFAULT("Video", "PH_SZFar", (m_PHack_Data.PHackSZFar ? 1 : 0), 0); + SAVE_IF_NOT_DEFAULT("Video", "PH_ZNear", m_PHack_Data.PHZNear, ""); + SAVE_IF_NOT_DEFAULT("Video", "PH_ZFar", m_PHack_Data.PHZFar, ""); + SAVE_IF_NOT_DEFAULT("EmuState", "EmulationStateId", EmuState->GetSelection(), 0); - std::string emu_issues = EmuIssues->GetValue().ToStdString(); - SAVE_IF_NOT_DEFAULT("EmuState", "EmulationIssues", emu_issues, ""); + std::string emu_issues = EmuIssues->GetValue().ToStdString(); + SAVE_IF_NOT_DEFAULT("EmuState", "EmulationIssues", emu_issues, ""); - std::string tmp; - if (GPUDeterminism->GetSelection() == 0) - tmp = "Not Set"; - else if (GPUDeterminism->GetSelection() == 1) - tmp = "auto"; - else if (GPUDeterminism->GetSelection() == 2) - tmp = "none"; - else if (GPUDeterminism->GetSelection() == 3) - tmp = "fake-completion"; + std::string tmp; + if (GPUDeterminism->GetSelection() == 0) + tmp = "Not Set"; + else if (GPUDeterminism->GetSelection() == 1) + tmp = "auto"; + else if (GPUDeterminism->GetSelection() == 2) + tmp = "none"; + else if (GPUDeterminism->GetSelection() == 3) + tmp = "fake-completion"; - SAVE_IF_NOT_DEFAULT("Core", "GPUDeterminismMode", tmp, "Not Set"); + SAVE_IF_NOT_DEFAULT("Core", "GPUDeterminismMode", tmp, "Not Set"); - int depth = DepthPercentage->GetValue() > 0 ? DepthPercentage->GetValue() : 100; - SAVE_IF_NOT_DEFAULT("Video_Stereoscopy", "StereoDepthPercentage", depth, 100); - SAVE_IF_NOT_DEFAULT("Video_Stereoscopy", "StereoConvergence", Convergence->GetValue(), 0); + int depth = DepthPercentage->GetValue() > 0 ? DepthPercentage->GetValue() : 100; + SAVE_IF_NOT_DEFAULT("Video_Stereoscopy", "StereoDepthPercentage", depth, 100); + SAVE_IF_NOT_DEFAULT("Video_Stereoscopy", "StereoConvergence", Convergence->GetValue(), 0); - PatchList_Save(); - ActionReplayList_Save(); - Gecko::SaveCodes(GameIniLocal, m_geckocode_panel->GetCodes()); + PatchList_Save(); + ActionReplayList_Save(); + Gecko::SaveCodes(GameIniLocal, m_geckocode_panel->GetCodes()); - bool success = GameIniLocal.Save(GameIniFileLocal); + bool success = GameIniLocal.Save(GameIniFileLocal); - // If the resulting file is empty, delete it. Kind of a hack, but meh. - if (success && File::GetSize(GameIniFileLocal) == 0) - File::Delete(GameIniFileLocal); + // If the resulting file is empty, delete it. Kind of a hack, but meh. + if (success && File::GetSize(GameIniFileLocal) == 0) + File::Delete(GameIniFileLocal); - if (success) - GenerateLocalIniModified(); + if (success) + GenerateLocalIniModified(); - return success; + return success; } void CISOProperties::LaunchExternalEditor(const std::string& filename, bool wait_until_closed) { #ifdef __APPLE__ - // wxTheMimeTypesManager is not yet implemented for wxCocoa - [[NSWorkspace sharedWorkspace] openFile: - [NSString stringWithUTF8String: filename.c_str()] - withApplication: @"TextEdit"]; + // wxTheMimeTypesManager is not yet implemented for wxCocoa + [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithUTF8String:filename.c_str()] + withApplication:@"TextEdit"]; #else - wxFileType* filetype = wxTheMimeTypesManager->GetFileTypeFromExtension("ini"); - if (filetype == nullptr) // From extension failed, trying with MIME type now - { - filetype = wxTheMimeTypesManager->GetFileTypeFromMimeType("text/plain"); - if (filetype == nullptr) // MIME type failed, aborting mission - { - WxUtils::ShowErrorDialog(_("Filetype 'ini' is unknown! Will not open!")); - return; - } - } + wxFileType* filetype = wxTheMimeTypesManager->GetFileTypeFromExtension("ini"); + if (filetype == nullptr) // From extension failed, trying with MIME type now + { + filetype = wxTheMimeTypesManager->GetFileTypeFromMimeType("text/plain"); + if (filetype == nullptr) // MIME type failed, aborting mission + { + WxUtils::ShowErrorDialog(_("Filetype 'ini' is unknown! Will not open!")); + return; + } + } - wxString OpenCommand = filetype->GetOpenCommand(StrToWxStr(filename)); - if (OpenCommand.IsEmpty()) - { - WxUtils::ShowErrorDialog(_("Couldn't find open command for extension 'ini'!")); - return; - } + wxString OpenCommand = filetype->GetOpenCommand(StrToWxStr(filename)); + if (OpenCommand.IsEmpty()) + { + WxUtils::ShowErrorDialog(_("Couldn't find open command for extension 'ini'!")); + return; + } - long result; + long result; - if (wait_until_closed) - result = wxExecute(OpenCommand, wxEXEC_SYNC); - else - result = wxExecute(OpenCommand); + if (wait_until_closed) + result = wxExecute(OpenCommand, wxEXEC_SYNC); + else + result = wxExecute(OpenCommand); - if (result == -1) - { - WxUtils::ShowErrorDialog(_("wxExecute returned -1 on application run!")); - return; - } + if (result == -1) + { + WxUtils::ShowErrorDialog(_("wxExecute returned -1 on application run!")); + return; + } #endif } void CISOProperties::GenerateLocalIniModified() { - wxCommandEvent event_update(DOLPHIN_EVT_LOCAL_INI_CHANGED); - event_update.SetString(StrToWxStr(game_id)); - event_update.SetInt(OpenGameListItem.GetRevision()); - wxTheApp->ProcessEvent(event_update); + wxCommandEvent event_update(DOLPHIN_EVT_LOCAL_INI_CHANGED); + event_update.SetString(StrToWxStr(game_id)); + event_update.SetInt(OpenGameListItem.GetRevision()); + wxTheApp->ProcessEvent(event_update); } void CISOProperties::OnLocalIniModified(wxCommandEvent& ev) { - ev.Skip(); - if (WxStrToStr(ev.GetString()) != game_id) - return; + ev.Skip(); + if (WxStrToStr(ev.GetString()) != game_id) + return; - GameIniLocal.Load(GameIniFileLocal); - LoadGameConfig(); + GameIniLocal.Load(GameIniFileLocal); + LoadGameConfig(); } -void CISOProperties::OnEditConfig(wxCommandEvent& WXUNUSED (event)) +void CISOProperties::OnEditConfig(wxCommandEvent& WXUNUSED(event)) { - SaveGameConfig(); - // Create blank file to prevent editor from prompting to create it. - if (!File::Exists(GameIniFileLocal)) - { - std::fstream blankFile(GameIniFileLocal, std::ios::out); - blankFile.close(); - } - LaunchExternalEditor(GameIniFileLocal, true); - GenerateLocalIniModified(); + SaveGameConfig(); + // Create blank file to prevent editor from prompting to create it. + if (!File::Exists(GameIniFileLocal)) + { + std::fstream blankFile(GameIniFileLocal, std::ios::out); + blankFile.close(); + } + LaunchExternalEditor(GameIniFileLocal, true); + GenerateLocalIniModified(); } -void CISOProperties::OnComputeMD5Sum(wxCommandEvent& WXUNUSED (event)) +void CISOProperties::OnComputeMD5Sum(wxCommandEvent& WXUNUSED(event)) { - u8 output[16]; - std::string output_string; - std::vector data(8 * 1024 * 1024); - u64 read_offset = 0; - mbedtls_md5_context ctx; + u8 output[16]; + std::string output_string; + std::vector data(8 * 1024 * 1024); + u64 read_offset = 0; + mbedtls_md5_context ctx; - std::unique_ptr file(DiscIO::CreateBlobReader(OpenGameListItem.GetFileName())); - u64 game_size = file->GetDataSize(); + std::unique_ptr file( + DiscIO::CreateBlobReader(OpenGameListItem.GetFileName())); + u64 game_size = file->GetDataSize(); - wxProgressDialog progressDialog( - _("Computing MD5 checksum"), - _("Working..."), - 1000, - this, - wxPD_APP_MODAL | wxPD_CAN_ABORT | - wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | - wxPD_SMOOTH - ); + wxProgressDialog progressDialog(_("Computing MD5 checksum"), _("Working..."), 1000, this, + wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME | + wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_SMOOTH); - mbedtls_md5_starts(&ctx); + mbedtls_md5_starts(&ctx); - while(read_offset < game_size) - { - if (!progressDialog.Update((int)((double)read_offset / (double)game_size * 1000))) - return; + while (read_offset < game_size) + { + if (!progressDialog.Update((int)((double)read_offset / (double)game_size * 1000))) + return; - size_t read_size = std::min((u64)data.size(), game_size - read_offset); - if (!file->Read(read_offset, read_size, data.data())) - return; + size_t read_size = std::min((u64)data.size(), game_size - read_offset); + if (!file->Read(read_offset, read_size, data.data())) + return; - mbedtls_md5_update(&ctx, data.data(), read_size); - read_offset += read_size; - } + mbedtls_md5_update(&ctx, data.data(), read_size); + read_offset += read_size; + } - mbedtls_md5_finish(&ctx, output); + mbedtls_md5_finish(&ctx, output); - // Convert to hex - for (int a = 0; a < 16; ++a) - output_string += StringFromFormat("%02x", output[a]); + // Convert to hex + for (int a = 0; a < 16; ++a) + output_string += StringFromFormat("%02x", output[a]); - m_MD5Sum->SetValue(output_string); + m_MD5Sum->SetValue(output_string); } // Opens all pre-defined INIs for the game. If there are multiple ones, // they will all be opened, but there is usually only one -void CISOProperties::OnShowDefaultConfig(wxCommandEvent& WXUNUSED (event)) +void CISOProperties::OnShowDefaultConfig(wxCommandEvent& WXUNUSED(event)) { - for (const std::string& filename : SConfig::GetGameIniFilenames(game_id, m_open_iso->GetRevision())) - { - std::string path = File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename; - if (File::Exists(path)) - LaunchExternalEditor(path, false); - } + for (const std::string& filename : + SConfig::GetGameIniFilenames(game_id, m_open_iso->GetRevision())) + { + std::string path = File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename; + if (File::Exists(path)) + LaunchExternalEditor(path, false); + } } void CISOProperties::ListSelectionChanged(wxCommandEvent& event) { - switch (event.GetId()) - { - case ID_PATCHES_LIST: - if (Patches->GetSelection() == wxNOT_FOUND || - DefaultPatches.find(Patches->GetString(Patches->GetSelection()).ToStdString()) != DefaultPatches.end()) - { - EditPatch->Disable(); - RemovePatch->Disable(); - } - else - { - EditPatch->Enable(); - RemovePatch->Enable(); - } - break; - case ID_CHEATS_LIST: - if (Cheats->GetSelection() == wxNOT_FOUND || - DefaultCheats.find(Cheats->RemoveMnemonics(Cheats->GetString(Cheats->GetSelection())).ToStdString()) != DefaultCheats.end()) - { - EditCheat->Disable(); - RemoveCheat->Disable(); - } - else - { - EditCheat->Enable(); - RemoveCheat->Enable(); - } - break; - } + switch (event.GetId()) + { + case ID_PATCHES_LIST: + if (Patches->GetSelection() == wxNOT_FOUND || + DefaultPatches.find(Patches->GetString(Patches->GetSelection()).ToStdString()) != + DefaultPatches.end()) + { + EditPatch->Disable(); + RemovePatch->Disable(); + } + else + { + EditPatch->Enable(); + RemovePatch->Enable(); + } + break; + case ID_CHEATS_LIST: + if (Cheats->GetSelection() == wxNOT_FOUND || + DefaultCheats.find( + Cheats->RemoveMnemonics(Cheats->GetString(Cheats->GetSelection())).ToStdString()) != + DefaultCheats.end()) + { + EditCheat->Disable(); + RemoveCheat->Disable(); + } + else + { + EditCheat->Enable(); + RemoveCheat->Enable(); + } + break; + } } void CISOProperties::OnActionReplayCodeChecked(wxCommandEvent& event) { - arCodes[event.GetSelection()].active = Cheats->IsChecked(event.GetSelection()); + arCodes[event.GetSelection()].active = Cheats->IsChecked(event.GetSelection()); } void CISOProperties::PatchList_Load() { - onFrame.clear(); - Patches->Clear(); + onFrame.clear(); + Patches->Clear(); - PatchEngine::LoadPatchSection("OnFrame", onFrame, GameIniDefault, GameIniLocal); + PatchEngine::LoadPatchSection("OnFrame", onFrame, GameIniDefault, GameIniLocal); - u32 index = 0; - for (PatchEngine::Patch& p : onFrame) - { - Patches->Append(StrToWxStr(p.name)); - Patches->Check(index, p.active); - if (!p.user_defined) - DefaultPatches.insert(p.name); - ++index; - } + u32 index = 0; + for (PatchEngine::Patch& p : onFrame) + { + Patches->Append(StrToWxStr(p.name)); + Patches->Check(index, p.active); + if (!p.user_defined) + DefaultPatches.insert(p.name); + ++index; + } } void CISOProperties::PatchList_Save() { - std::vector lines; - std::vector enabledLines; - u32 index = 0; - for (PatchEngine::Patch& p : onFrame) - { - if (Patches->IsChecked(index)) - enabledLines.push_back("$" + p.name); + std::vector lines; + std::vector enabledLines; + u32 index = 0; + for (PatchEngine::Patch& p : onFrame) + { + if (Patches->IsChecked(index)) + enabledLines.push_back("$" + p.name); - // Do not save default patches. - if (DefaultPatches.find(p.name) == DefaultPatches.end()) - { - lines.push_back("$" + p.name); - for (const PatchEngine::PatchEntry& entry : p.entries) - { - std::string temp = StringFromFormat("0x%08X:%s:0x%08X", entry.address, PatchEngine::PatchTypeStrings[entry.type], entry.value); - lines.push_back(temp); - } - } - ++index; - } - GameIniLocal.SetLines("OnFrame_Enabled", enabledLines); - GameIniLocal.SetLines("OnFrame", lines); + // Do not save default patches. + if (DefaultPatches.find(p.name) == DefaultPatches.end()) + { + lines.push_back("$" + p.name); + for (const PatchEngine::PatchEntry& entry : p.entries) + { + std::string temp = StringFromFormat("0x%08X:%s:0x%08X", entry.address, + PatchEngine::PatchTypeStrings[entry.type], entry.value); + lines.push_back(temp); + } + } + ++index; + } + GameIniLocal.SetLines("OnFrame_Enabled", enabledLines); + GameIniLocal.SetLines("OnFrame", lines); } void CISOProperties::PatchButtonClicked(wxCommandEvent& event) { - int selection = Patches->GetSelection(); + int selection = Patches->GetSelection(); - switch (event.GetId()) - { - case ID_EDITPATCH: - { - CPatchAddEdit dlg(selection, &onFrame, this); - dlg.ShowModal(); - Raise(); - } - break; - case ID_ADDPATCH: - { - CPatchAddEdit dlg(-1, &onFrame, this, 1, _("Add Patch")); - int res = dlg.ShowModal(); - Raise(); - if (res == wxID_OK) - { - Patches->Append(StrToWxStr(onFrame.back().name)); - Patches->Check((unsigned int)(onFrame.size() - 1), onFrame.back().active); - } - } - break; - case ID_REMOVEPATCH: - onFrame.erase(onFrame.begin() + Patches->GetSelection()); - Patches->Delete(Patches->GetSelection()); - break; - } + switch (event.GetId()) + { + case ID_EDITPATCH: + { + CPatchAddEdit dlg(selection, &onFrame, this); + dlg.ShowModal(); + Raise(); + } + break; + case ID_ADDPATCH: + { + CPatchAddEdit dlg(-1, &onFrame, this, 1, _("Add Patch")); + int res = dlg.ShowModal(); + Raise(); + if (res == wxID_OK) + { + Patches->Append(StrToWxStr(onFrame.back().name)); + Patches->Check((unsigned int)(onFrame.size() - 1), onFrame.back().active); + } + } + break; + case ID_REMOVEPATCH: + onFrame.erase(onFrame.begin() + Patches->GetSelection()); + Patches->Delete(Patches->GetSelection()); + break; + } - PatchList_Save(); - Patches->Clear(); - PatchList_Load(); + PatchList_Save(); + Patches->Clear(); + PatchList_Load(); - EditPatch->Disable(); - RemovePatch->Disable(); + EditPatch->Disable(); + RemovePatch->Disable(); } void CISOProperties::ActionReplayList_Load() { - arCodes = ActionReplay::LoadCodes(GameIniDefault, GameIniLocal); - DefaultCheats.clear(); + arCodes = ActionReplay::LoadCodes(GameIniDefault, GameIniLocal); + DefaultCheats.clear(); - Cheats->Freeze(); - Cheats->Clear(); - for (const ActionReplay::ARCode& arCode : arCodes) - { - int idx = Cheats->Append(Cheats->EscapeMnemonics(StrToWxStr(arCode.name))); - Cheats->Check(idx, arCode.active); - if (!arCode.user_defined) - DefaultCheats.insert(arCode.name); - } - Cheats->Thaw(); + Cheats->Freeze(); + Cheats->Clear(); + for (const ActionReplay::ARCode& arCode : arCodes) + { + int idx = Cheats->Append(Cheats->EscapeMnemonics(StrToWxStr(arCode.name))); + Cheats->Check(idx, arCode.active); + if (!arCode.user_defined) + DefaultCheats.insert(arCode.name); + } + Cheats->Thaw(); } void CISOProperties::ActionReplayList_Save() { - ActionReplay::SaveCodes(&GameIniLocal, arCodes); + ActionReplay::SaveCodes(&GameIniLocal, arCodes); } void CISOProperties::ActionReplayButtonClicked(wxCommandEvent& event) { - int selection = Cheats->GetSelection(); + int selection = Cheats->GetSelection(); - switch (event.GetId()) - { - case ID_EDITCHEAT: - { - CARCodeAddEdit dlg(selection, &arCodes, this); - dlg.ShowModal(); - Raise(); - } - break; - case ID_ADDCHEAT: - { - CARCodeAddEdit dlg(-1, &arCodes, this, 1, _("Add ActionReplay Code")); - int res = dlg.ShowModal(); - Raise(); - if (res == wxID_OK) - { - Cheats->Append(StrToWxStr(arCodes.back().name)); - Cheats->Check((unsigned int)(arCodes.size() - 1), arCodes.back().active); - } - } - break; - case ID_REMOVECHEAT: - arCodes.erase(arCodes.begin() + Cheats->GetSelection()); - Cheats->Delete(Cheats->GetSelection()); - break; - } + switch (event.GetId()) + { + case ID_EDITCHEAT: + { + CARCodeAddEdit dlg(selection, &arCodes, this); + dlg.ShowModal(); + Raise(); + } + break; + case ID_ADDCHEAT: + { + CARCodeAddEdit dlg(-1, &arCodes, this, 1, _("Add ActionReplay Code")); + int res = dlg.ShowModal(); + Raise(); + if (res == wxID_OK) + { + Cheats->Append(StrToWxStr(arCodes.back().name)); + Cheats->Check((unsigned int)(arCodes.size() - 1), arCodes.back().active); + } + } + break; + case ID_REMOVECHEAT: + arCodes.erase(arCodes.begin() + Cheats->GetSelection()); + Cheats->Delete(Cheats->GetSelection()); + break; + } - ActionReplayList_Save(); - Cheats->Clear(); - ActionReplayList_Load(); + ActionReplayList_Save(); + Cheats->Clear(); + ActionReplayList_Load(); - EditCheat->Disable(); - RemoveCheat->Disable(); + EditCheat->Disable(); + RemoveCheat->Disable(); } void CISOProperties::OnChangeBannerLang(wxCommandEvent& event) { - ChangeBannerDetails(OpenGameListItem.GetLanguages()[event.GetSelection()]); + ChangeBannerDetails(OpenGameListItem.GetLanguages()[event.GetSelection()]); } void CISOProperties::ChangeBannerDetails(DiscIO::IVolume::ELanguage language) { - wxString const name = StrToWxStr(OpenGameListItem.GetName(language)); - wxString const comment = StrToWxStr(OpenGameListItem.GetDescription(language)); - wxString const maker = StrToWxStr(OpenGameListItem.GetCompany()); + wxString const name = StrToWxStr(OpenGameListItem.GetName(language)); + wxString const comment = StrToWxStr(OpenGameListItem.GetDescription(language)); + wxString const maker = StrToWxStr(OpenGameListItem.GetCompany()); - // Updates the information shown in the window - m_Name->SetValue(name); - m_Comment->SetValue(comment); - m_Maker->SetValue(maker);//dev too + // Updates the information shown in the window + m_Name->SetValue(name); + m_Comment->SetValue(comment); + m_Maker->SetValue(maker); // dev too - std::string path, filename, extension; - SplitPath(OpenGameListItem.GetFileName(), &path, &filename, &extension); - // Real disk drives don't have filenames on Windows - if (filename.empty() && extension.empty()) - filename = path + ' '; - // Also sets the window's title - SetTitle(StrToWxStr(StringFromFormat("%s%s: %s - ", filename.c_str(), - extension.c_str(), OpenGameListItem.GetUniqueID().c_str())) + name); + std::string path, filename, extension; + SplitPath(OpenGameListItem.GetFileName(), &path, &filename, &extension); + // Real disk drives don't have filenames on Windows + if (filename.empty() && extension.empty()) + filename = path + ' '; + // Also sets the window's title + SetTitle(StrToWxStr(StringFromFormat("%s%s: %s - ", filename.c_str(), extension.c_str(), + OpenGameListItem.GetUniqueID().c_str())) + + name); } diff --git a/Source/Core/DolphinWX/ISOProperties.h b/Source/Core/DolphinWX/ISOProperties.h index a702d8e256..e8539fc8a8 100644 --- a/Source/Core/DolphinWX/ISOProperties.h +++ b/Source/Core/DolphinWX/ISOProperties.h @@ -33,217 +33,219 @@ class wxStaticBitmap; class wxTextCtrl; class wxTreeCtrl; -namespace DiscIO { struct SFileInfo; } -namespace Gecko { class CodeConfigPanel; } +namespace DiscIO +{ +struct SFileInfo; +} +namespace Gecko +{ +class CodeConfigPanel; +} class WiiPartition final : public wxTreeItemData { public: - WiiPartition(std::unique_ptr partition, std::unique_ptr file_system) - : Partition(std::move(partition)), FileSystem(std::move(file_system)) - { - } + WiiPartition(std::unique_ptr partition, + std::unique_ptr file_system) + : Partition(std::move(partition)), FileSystem(std::move(file_system)) + { + } - std::unique_ptr Partition; - std::unique_ptr FileSystem; + std::unique_ptr Partition; + std::unique_ptr FileSystem; }; struct PHackData { - bool PHackSZNear; - bool PHackSZFar; - std::string PHZNear; - std::string PHZFar; + bool PHackSZNear; + bool PHackSZFar; + std::string PHZNear; + std::string PHZFar; }; class CISOProperties : public wxDialog { public: - CISOProperties(const GameListItem& game_list_item, - wxWindow* parent, - wxWindowID id = wxID_ANY, - const wxString& title = _("Properties"), - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); - virtual ~CISOProperties(); + CISOProperties(const GameListItem& game_list_item, wxWindow* parent, wxWindowID id = wxID_ANY, + const wxString& title = _("Properties"), const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); + virtual ~CISOProperties(); private: - DECLARE_EVENT_TABLE(); + DECLARE_EVENT_TABLE(); - std::unique_ptr m_open_iso; - std::unique_ptr m_filesystem; + std::unique_ptr m_open_iso; + std::unique_ptr m_filesystem; - std::vector onFrame; - std::vector arCodes; - PHackData m_PHack_Data; + std::vector onFrame; + std::vector arCodes; + PHackData m_PHack_Data; - // Core - wxCheckBox *CPUThread, *SkipIdle, *MMU, *DCBZOFF, *FPRF; - wxCheckBox *SyncGPU, *FastDiscSpeed, *DSPHLE; + // Core + wxCheckBox *CPUThread, *SkipIdle, *MMU, *DCBZOFF, *FPRF; + wxCheckBox *SyncGPU, *FastDiscSpeed, *DSPHLE; - wxArrayString arrayStringFor_GPUDeterminism; - wxChoice* GPUDeterminism; - // Wii - wxCheckBox* EnableWideScreen; + wxArrayString arrayStringFor_GPUDeterminism; + wxChoice* GPUDeterminism; + // Wii + wxCheckBox* EnableWideScreen; - // Stereoscopy - wxSlider* DepthPercentage; - wxSpinCtrl* Convergence; - wxCheckBox* MonoDepth; + // Stereoscopy + wxSlider* DepthPercentage; + wxSpinCtrl* Convergence; + wxCheckBox* MonoDepth; - wxArrayString arrayStringFor_EmuState; - wxChoice* EmuState; - wxTextCtrl* EmuIssues; + wxArrayString arrayStringFor_EmuState; + wxChoice* EmuState; + wxTextCtrl* EmuIssues; - wxCheckListBox* Patches; - wxButton* EditPatch; - wxButton* RemovePatch; + wxCheckListBox* Patches; + wxButton* EditPatch; + wxButton* RemovePatch; - wxCheckListBox* Cheats; - wxButton* EditCheat; - wxButton* RemoveCheat; + wxCheckListBox* Cheats; + wxButton* EditCheat; + wxButton* RemoveCheat; - wxTextCtrl* m_InternalName; - wxTextCtrl* m_GameID; - wxTextCtrl* m_Country; - wxTextCtrl* m_MakerID; - wxTextCtrl* m_Revision; - wxTextCtrl* m_Date; - wxTextCtrl* m_FST; - wxTextCtrl* m_MD5Sum; - wxButton* m_MD5SumCompute; - wxArrayString arrayStringFor_Lang; - wxChoice* m_Lang; - wxTextCtrl* m_Name; - wxTextCtrl* m_Maker; - wxTextCtrl* m_Comment; - wxStaticBitmap* m_Banner; + wxTextCtrl* m_InternalName; + wxTextCtrl* m_GameID; + wxTextCtrl* m_Country; + wxTextCtrl* m_MakerID; + wxTextCtrl* m_Revision; + wxTextCtrl* m_Date; + wxTextCtrl* m_FST; + wxTextCtrl* m_MD5Sum; + wxButton* m_MD5SumCompute; + wxArrayString arrayStringFor_Lang; + wxChoice* m_Lang; + wxTextCtrl* m_Name; + wxTextCtrl* m_Maker; + wxTextCtrl* m_Comment; + wxStaticBitmap* m_Banner; - wxTreeCtrl* m_Treectrl; - wxTreeItemId RootId; + wxTreeCtrl* m_Treectrl; + wxTreeItemId RootId; - Gecko::CodeConfigPanel* m_geckocode_panel; + Gecko::CodeConfigPanel* m_geckocode_panel; - enum - { - ID_TREECTRL = 1000, + enum + { + ID_TREECTRL = 1000, - ID_NOTEBOOK, - ID_GAMECONFIG, - ID_PATCH_PAGE, - ID_ARCODE_PAGE, - ID_SPEEDHACK_PAGE, - ID_INFORMATION, - ID_FILESYSTEM, + ID_NOTEBOOK, + ID_GAMECONFIG, + ID_PATCH_PAGE, + ID_ARCODE_PAGE, + ID_SPEEDHACK_PAGE, + ID_INFORMATION, + ID_FILESYSTEM, - ID_USEDUALCORE, - ID_IDLESKIP, - ID_MMU, - ID_DCBZOFF, - ID_FPRF, - ID_SYNCGPU, - ID_DISCSPEED, - ID_AUDIO_DSP_HLE, - ID_USE_BBOX, - ID_ENABLEPROGRESSIVESCAN, - ID_ENABLEWIDESCREEN, - ID_EDITCONFIG, - ID_SHOWDEFAULTCONFIG, - ID_EMUSTATE, - ID_EMU_ISSUES, - ID_PATCHES_LIST, - ID_EDITPATCH, - ID_ADDPATCH, - ID_REMOVEPATCH, - ID_CHEATS_LIST, - ID_EDITCHEAT, - ID_ADDCHEAT, - ID_REMOVECHEAT, - ID_GPUDETERMINISM, - ID_DEPTHPERCENTAGE, - ID_CONVERGENCE, - ID_MONODEPTH, + ID_USEDUALCORE, + ID_IDLESKIP, + ID_MMU, + ID_DCBZOFF, + ID_FPRF, + ID_SYNCGPU, + ID_DISCSPEED, + ID_AUDIO_DSP_HLE, + ID_USE_BBOX, + ID_ENABLEPROGRESSIVESCAN, + ID_ENABLEWIDESCREEN, + ID_EDITCONFIG, + ID_SHOWDEFAULTCONFIG, + ID_EMUSTATE, + ID_EMU_ISSUES, + ID_PATCHES_LIST, + ID_EDITPATCH, + ID_ADDPATCH, + ID_REMOVEPATCH, + ID_CHEATS_LIST, + ID_EDITCHEAT, + ID_ADDCHEAT, + ID_REMOVECHEAT, + ID_GPUDETERMINISM, + ID_DEPTHPERCENTAGE, + ID_CONVERGENCE, + ID_MONODEPTH, - ID_NAME, - ID_GAMEID, - ID_COUNTRY, - ID_MAKERID, - ID_REVISION, - ID_DATE, - ID_FST, - ID_MD5SUM, - ID_MD5SUMCOMPUTE, - ID_VERSION, - ID_LANG, - ID_SHORTNAME, - ID_LONGNAME, - ID_MAKER, - ID_COMMENT, - ID_BANNER, - IDM_EXTRACTDIR, - IDM_EXTRACTALL, - IDM_EXTRACTFILE, - IDM_EXTRACTAPPLOADER, - IDM_EXTRACTDOL, - IDM_CHECKINTEGRITY, - IDM_BNRSAVEAS - }; + ID_NAME, + ID_GAMEID, + ID_COUNTRY, + ID_MAKERID, + ID_REVISION, + ID_DATE, + ID_FST, + ID_MD5SUM, + ID_MD5SUMCOMPUTE, + ID_VERSION, + ID_LANG, + ID_SHORTNAME, + ID_LONGNAME, + ID_MAKER, + ID_COMMENT, + ID_BANNER, + IDM_EXTRACTDIR, + IDM_EXTRACTALL, + IDM_EXTRACTFILE, + IDM_EXTRACTAPPLOADER, + IDM_EXTRACTDOL, + IDM_CHECKINTEGRITY, + IDM_BNRSAVEAS + }; - void LaunchExternalEditor(const std::string& filename, bool wait_until_closed); + void LaunchExternalEditor(const std::string& filename, bool wait_until_closed); - void CreateGUIControls(); - void OnClose(wxCloseEvent& event); - void OnCloseClick(wxCommandEvent& event); - void OnEditConfig(wxCommandEvent& event); - void OnComputeMD5Sum(wxCommandEvent& event); - void OnShowDefaultConfig(wxCommandEvent& event); - void ListSelectionChanged(wxCommandEvent& event); - void OnActionReplayCodeChecked(wxCommandEvent& event); - void PatchButtonClicked(wxCommandEvent& event); - void ActionReplayButtonClicked(wxCommandEvent& event); - void RightClickOnBanner(wxMouseEvent& event); - void OnBannerImageSave(wxCommandEvent& event); - void OnRightClickOnTree(wxTreeEvent& event); - void OnExtractFile(wxCommandEvent& event); - void OnExtractDir(wxCommandEvent& event); - void OnExtractDataFromHeader(wxCommandEvent& event); - void CheckPartitionIntegrity(wxCommandEvent& event); - void OnEmustateChanged(wxCommandEvent& event); - void OnChangeBannerLang(wxCommandEvent& event); + void CreateGUIControls(); + void OnClose(wxCloseEvent& event); + void OnCloseClick(wxCommandEvent& event); + void OnEditConfig(wxCommandEvent& event); + void OnComputeMD5Sum(wxCommandEvent& event); + void OnShowDefaultConfig(wxCommandEvent& event); + void ListSelectionChanged(wxCommandEvent& event); + void OnActionReplayCodeChecked(wxCommandEvent& event); + void PatchButtonClicked(wxCommandEvent& event); + void ActionReplayButtonClicked(wxCommandEvent& event); + void RightClickOnBanner(wxMouseEvent& event); + void OnBannerImageSave(wxCommandEvent& event); + void OnRightClickOnTree(wxTreeEvent& event); + void OnExtractFile(wxCommandEvent& event); + void OnExtractDir(wxCommandEvent& event); + void OnExtractDataFromHeader(wxCommandEvent& event); + void CheckPartitionIntegrity(wxCommandEvent& event); + void OnEmustateChanged(wxCommandEvent& event); + void OnChangeBannerLang(wxCommandEvent& event); - const GameListItem OpenGameListItem; + const GameListItem OpenGameListItem; - typedef std::vector::iterator fileIter; + typedef std::vector::iterator fileIter; - size_t CreateDirectoryTree(wxTreeItemId& parent, - const std::vector& fileInfos); - size_t CreateDirectoryTree(wxTreeItemId& parent, - const std::vector& fileInfos, - const size_t _FirstIndex, - const size_t _LastIndex); - void ExportDir(const std::string& _rFullPath, const std::string& _rExportFilename, - const WiiPartition* partition = nullptr); + size_t CreateDirectoryTree(wxTreeItemId& parent, const std::vector& fileInfos); + size_t CreateDirectoryTree(wxTreeItemId& parent, const std::vector& fileInfos, + const size_t _FirstIndex, const size_t _LastIndex); + void ExportDir(const std::string& _rFullPath, const std::string& _rExportFilename, + const WiiPartition* partition = nullptr); - IniFile GameIniDefault; - IniFile GameIniLocal; - std::string GameIniFileLocal; - std::string game_id; + IniFile GameIniDefault; + IniFile GameIniLocal; + std::string GameIniFileLocal; + std::string game_id; - std::set DefaultPatches; - std::set DefaultCheats; + std::set DefaultPatches; + std::set DefaultCheats; - void LoadGameConfig(); - bool SaveGameConfig(); - void OnLocalIniModified(wxCommandEvent& ev); - void GenerateLocalIniModified(); - void PatchList_Load(); - void PatchList_Save(); - void ActionReplayList_Load(); - void ActionReplayList_Save(); - void ChangeBannerDetails(DiscIO::IVolume::ELanguage language); + void LoadGameConfig(); + bool SaveGameConfig(); + void OnLocalIniModified(wxCommandEvent& ev); + void GenerateLocalIniModified(); + void PatchList_Load(); + void PatchList_Save(); + void ActionReplayList_Load(); + void ActionReplayList_Save(); + void ChangeBannerDetails(DiscIO::IVolume::ELanguage language); - long GetElementStyle(const char* section, const char* key); - void SetCheckboxValueFromGameini(const char* section, const char* key, wxCheckBox* checkbox); - void SaveGameIniValueFrom3StateCheckbox(const char* section, const char* key, wxCheckBox* checkbox); + long GetElementStyle(const char* section, const char* key); + void SetCheckboxValueFromGameini(const char* section, const char* key, wxCheckBox* checkbox); + void SaveGameIniValueFrom3StateCheckbox(const char* section, const char* key, + wxCheckBox* checkbox); }; diff --git a/Source/Core/DolphinWX/InputConfigDiag.cpp b/Source/Core/DolphinWX/InputConfigDiag.cpp index 215134526e..46e79413ad 100644 --- a/Source/Core/DolphinWX/InputConfigDiag.cpp +++ b/Source/Core/DolphinWX/InputConfigDiag.cpp @@ -36,1060 +36,1089 @@ #include "Common/IniFile.h" #include "Common/MsgHandler.h" #include "Core/Core.h" -#include "Core/HotkeyManager.h" #include "Core/HW/GCKeyboard.h" #include "Core/HW/GCPad.h" #include "Core/HW/Wiimote.h" +#include "Core/HotkeyManager.h" #include "DolphinWX/InputConfigDiag.h" #include "DolphinWX/WxUtils.h" #include "InputCommon/ControllerEmu.h" -#include "InputCommon/InputConfig.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/ControllerInterface/Device.h" #include "InputCommon/ControllerInterface/ExpressionParser.h" +#include "InputCommon/InputConfig.h" using namespace ciface::ExpressionParser; void GamepadPage::ConfigExtension(wxCommandEvent& event) { - ControllerEmu::Extension* const ex = ((ExtensionButton*)event.GetEventObject())->extension; + ControllerEmu::Extension* const ex = ((ExtensionButton*)event.GetEventObject())->extension; - // show config diag, if "none" isn't selected - if (ex->switch_extension) - { - wxDialog dlg(this, wxID_ANY, - wxGetTranslation(StrToWxStr(ex->attachments[ex->switch_extension]->GetName()))); + // show config diag, if "none" isn't selected + if (ex->switch_extension) + { + wxDialog dlg(this, wxID_ANY, + wxGetTranslation(StrToWxStr(ex->attachments[ex->switch_extension]->GetName()))); - wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); - const std::size_t orig_size = control_groups.size(); + wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); + const std::size_t orig_size = control_groups.size(); - ControlGroupsSizer* const szr = new ControlGroupsSizer(ex->attachments[ex->switch_extension].get(), &dlg, this, &control_groups); - main_szr->Add(szr, 0, wxLEFT, 5); - main_szr->Add(dlg.CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - dlg.SetSizerAndFit(main_szr); - dlg.Center(); + ControlGroupsSizer* const szr = new ControlGroupsSizer( + ex->attachments[ex->switch_extension].get(), &dlg, this, &control_groups); + main_szr->Add(szr, 0, wxLEFT, 5); + main_szr->Add(dlg.CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + dlg.SetSizerAndFit(main_szr); + dlg.Center(); - dlg.ShowModal(); + dlg.ShowModal(); - // remove the new groups that were just added, now that the window closed - control_groups.resize(orig_size); - } + // remove the new groups that were just added, now that the window closed + control_groups.resize(orig_size); + } } -PadSettingExtension::PadSettingExtension(wxWindow* const parent, ControllerEmu::Extension* const ext) - : PadSetting(new wxChoice(parent, wxID_ANY)) - , extension(ext) +PadSettingExtension::PadSettingExtension(wxWindow* const parent, + ControllerEmu::Extension* const ext) + : PadSetting(new wxChoice(parent, wxID_ANY)), extension(ext) { - for (auto& attachment : extension->attachments) - { - ((wxChoice*)wxcontrol)->Append(wxGetTranslation(StrToWxStr(attachment->GetName()))); - } + for (auto& attachment : extension->attachments) + { + ((wxChoice*)wxcontrol)->Append(wxGetTranslation(StrToWxStr(attachment->GetName()))); + } - UpdateGUI(); + UpdateGUI(); } void PadSettingExtension::UpdateGUI() { - ((wxChoice*)wxcontrol)->Select(extension->switch_extension); + ((wxChoice*)wxcontrol)->Select(extension->switch_extension); } void PadSettingExtension::UpdateValue() { - extension->switch_extension = ((wxChoice*)wxcontrol)->GetSelection(); + extension->switch_extension = ((wxChoice*)wxcontrol)->GetSelection(); } -PadSettingCheckBox::PadSettingCheckBox(wxWindow* const parent, ControllerEmu::ControlGroup::Setting* const _setting) - : PadSetting(new wxCheckBox(parent, wxID_ANY, wxGetTranslation(StrToWxStr(_setting->name)))) - , setting(_setting) +PadSettingCheckBox::PadSettingCheckBox(wxWindow* const parent, + ControllerEmu::ControlGroup::Setting* const _setting) + : PadSetting(new wxCheckBox(parent, wxID_ANY, wxGetTranslation(StrToWxStr(_setting->name)))), + setting(_setting) { - UpdateGUI(); + UpdateGUI(); } void PadSettingCheckBox::UpdateGUI() { - ((wxCheckBox*)wxcontrol)->SetValue(!!setting->GetValue()); + ((wxCheckBox*)wxcontrol)->SetValue(!!setting->GetValue()); } void PadSettingCheckBox::UpdateValue() { - // 0.01 so its saved to the ini file as just 1. :( - setting->SetValue(0.01 * ((wxCheckBox*)wxcontrol)->GetValue()); + // 0.01 so its saved to the ini file as just 1. :( + setting->SetValue(0.01 * ((wxCheckBox*)wxcontrol)->GetValue()); } void PadSettingSpin::UpdateGUI() { - ((wxSpinCtrl*)wxcontrol)->SetValue((int)(setting->GetValue() * 100)); + ((wxSpinCtrl*)wxcontrol)->SetValue((int)(setting->GetValue() * 100)); } void PadSettingSpin::UpdateValue() { - setting->SetValue(ControlState(((wxSpinCtrl*)wxcontrol)->GetValue()) / 100); + setting->SetValue(ControlState(((wxSpinCtrl*)wxcontrol)->GetValue()) / 100); } -ControlDialog::ControlDialog(GamepadPage* const parent, InputConfig& config, ControllerInterface::ControlReference* const ref) - : wxDialog(parent, wxID_ANY, _("Configure Control"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) - , control_reference(ref) - , m_config(config) - , m_parent(parent) +ControlDialog::ControlDialog(GamepadPage* const parent, InputConfig& config, + ControllerInterface::ControlReference* const ref) + : wxDialog(parent, wxID_ANY, _("Configure Control"), wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), + control_reference(ref), m_config(config), m_parent(parent) { - m_devq = m_parent->controller->default_device; + m_devq = m_parent->controller->default_device; - // GetStrings() sounds slow :/ - //device_cbox = new wxComboBox(this, wxID_ANY, StrToWxStr(ref->device_qualifier.ToString()), wxDefaultPosition, wxSize(256,-1), parent->device_cbox->GetStrings(), wxTE_PROCESS_ENTER); - device_cbox = new wxComboBox(this, wxID_ANY, StrToWxStr(m_devq.ToString()), wxDefaultPosition, wxSize(256, -1), parent->device_cbox->GetStrings(), wxTE_PROCESS_ENTER); + // GetStrings() sounds slow :/ + // device_cbox = new wxComboBox(this, wxID_ANY, StrToWxStr(ref->device_qualifier.ToString()), + // wxDefaultPosition, wxSize(256,-1), parent->device_cbox->GetStrings(), wxTE_PROCESS_ENTER); + device_cbox = + new wxComboBox(this, wxID_ANY, StrToWxStr(m_devq.ToString()), wxDefaultPosition, + wxSize(256, -1), parent->device_cbox->GetStrings(), wxTE_PROCESS_ENTER); - device_cbox->Bind(wxEVT_COMBOBOX, &ControlDialog::SetDevice, this); - device_cbox->Bind(wxEVT_TEXT_ENTER, &ControlDialog::SetDevice, this); + device_cbox->Bind(wxEVT_COMBOBOX, &ControlDialog::SetDevice, this); + device_cbox->Bind(wxEVT_TEXT_ENTER, &ControlDialog::SetDevice, this); - wxStaticBoxSizer* const control_chooser = CreateControlChooser(parent); + wxStaticBoxSizer* const control_chooser = CreateControlChooser(parent); - wxStaticBoxSizer* const d_szr = new wxStaticBoxSizer(wxVERTICAL, this, _("Device")); - d_szr->Add(device_cbox, 0, wxEXPAND|wxALL, 5); + wxStaticBoxSizer* const d_szr = new wxStaticBoxSizer(wxVERTICAL, this, _("Device")); + d_szr->Add(device_cbox, 0, wxEXPAND | wxALL, 5); - wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL); - szr->Add(d_szr, 0, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5); - szr->Add(control_chooser, 1, wxEXPAND|wxALL, 5); + wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL); + szr->Add(d_szr, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5); + szr->Add(control_chooser, 1, wxEXPAND | wxALL, 5); - SetSizerAndFit(szr); // needed + SetSizerAndFit(szr); // needed - UpdateGUI(); - SetFocus(); + UpdateGUI(); + SetFocus(); } -ControlButton::ControlButton(wxWindow* const parent, ControllerInterface::ControlReference* const _ref, const unsigned int width, const std::string& label) -: wxButton(parent, wxID_ANY, "", wxDefaultPosition, wxSize(width,20)) -, control_reference(_ref) +ControlButton::ControlButton(wxWindow* const parent, + ControllerInterface::ControlReference* const _ref, + const unsigned int width, const std::string& label) + : wxButton(parent, wxID_ANY, "", wxDefaultPosition, wxSize(width, 20)), control_reference(_ref) { - if (label.empty()) - SetLabel(StrToWxStr(_ref->expression)); - else - SetLabel(StrToWxStr(label)); + if (label.empty()) + SetLabel(StrToWxStr(_ref->expression)); + else + SetLabel(StrToWxStr(label)); } void InputConfigDialog::UpdateProfileComboBox() { - std::string pname(File::GetUserPath(D_CONFIG_IDX)); - pname += PROFILES_PATH; - pname += m_config.GetProfileName(); + std::string pname(File::GetUserPath(D_CONFIG_IDX)); + pname += PROFILES_PATH; + pname += m_config.GetProfileName(); - std::vector sv = DoFileSearch({".ini"}, {pname}); + std::vector sv = DoFileSearch({".ini"}, {pname}); - wxArrayString strs; - for (const std::string& filename : sv) - { - std::string base; - SplitPath(filename, nullptr, &base, nullptr); - strs.push_back(StrToWxStr(base)); - } + wxArrayString strs; + for (const std::string& filename : sv) + { + std::string base; + SplitPath(filename, nullptr, &base, nullptr); + strs.push_back(StrToWxStr(base)); + } - for (GamepadPage* page : m_padpages) - { - page->profile_cbox->Clear(); - page->profile_cbox->Append(strs); - } + for (GamepadPage* page : m_padpages) + { + page->profile_cbox->Clear(); + page->profile_cbox->Append(strs); + } } void InputConfigDialog::UpdateControlReferences() { - for (GamepadPage* page : m_padpages) - { - page->controller->UpdateReferences(g_controller_interface); - } + for (GamepadPage* page : m_padpages) + { + page->controller->UpdateReferences(g_controller_interface); + } } void InputConfigDialog::ClickSave(wxCommandEvent& event) { - m_config.SaveConfig(); - event.Skip(); + m_config.SaveConfig(); + event.Skip(); } int ControlDialog::GetRangeSliderValue() const { - return range_slider->GetValue(); + return range_slider->GetValue(); } void ControlDialog::UpdateListContents() { - control_lbox->Clear(); + control_lbox->Clear(); - ciface::Core::Device* const dev = g_controller_interface.FindDevice(m_devq); - if (dev) - { - if (control_reference->is_input) - { - for (ciface::Core::Device::Input* input : dev->Inputs()) - { - control_lbox->Append(StrToWxStr(input->GetName())); - } - } - else // It's an output - { - for (ciface::Core::Device::Output* output : dev->Outputs()) - { - control_lbox->Append(StrToWxStr(output->GetName())); - } - } - } + ciface::Core::Device* const dev = g_controller_interface.FindDevice(m_devq); + if (dev) + { + if (control_reference->is_input) + { + for (ciface::Core::Device::Input* input : dev->Inputs()) + { + control_lbox->Append(StrToWxStr(input->GetName())); + } + } + else // It's an output + { + for (ciface::Core::Device::Output* output : dev->Outputs()) + { + control_lbox->Append(StrToWxStr(output->GetName())); + } + } + } } void ControlDialog::SelectControl(const std::string& name) { - //UpdateGUI(); + // UpdateGUI(); - const int f = control_lbox->FindString(StrToWxStr(name)); - if (f >= 0) - control_lbox->Select(f); + const int f = control_lbox->FindString(StrToWxStr(name)); + if (f >= 0) + control_lbox->Select(f); } void ControlDialog::UpdateGUI() { - // update textbox - textctrl->SetValue(StrToWxStr(control_reference->expression)); + // update textbox + textctrl->SetValue(StrToWxStr(control_reference->expression)); - // updates the "bound controls:" label - m_bound_label->SetLabel(wxString::Format(_("Bound Controls: %lu"), - (unsigned long)control_reference->BoundCount())); + // updates the "bound controls:" label + m_bound_label->SetLabel( + wxString::Format(_("Bound Controls: %lu"), (unsigned long)control_reference->BoundCount())); - switch (control_reference->parse_error) - { - case EXPRESSION_PARSE_SYNTAX_ERROR: - m_error_label->SetLabel(_("Syntax error")); - break; - case EXPRESSION_PARSE_NO_DEVICE: - m_error_label->SetLabel(_("Device not found")); - break; - default: - m_error_label->SetLabel(""); - } + switch (control_reference->parse_error) + { + case EXPRESSION_PARSE_SYNTAX_ERROR: + m_error_label->SetLabel(_("Syntax error")); + break; + case EXPRESSION_PARSE_NO_DEVICE: + m_error_label->SetLabel(_("Device not found")); + break; + default: + m_error_label->SetLabel(""); + } }; void GamepadPage::UpdateGUI() { - device_cbox->SetValue(StrToWxStr(controller->default_device.ToString())); + device_cbox->SetValue(StrToWxStr(controller->default_device.ToString())); - for (ControlGroupBox* cgBox : control_groups) - { - for (ControlButton* button : cgBox->control_buttons) - { - wxString expr = StrToWxStr(button->control_reference->expression); - expr.Replace("&", "&&"); - button->SetLabel(expr); - } + for (ControlGroupBox* cgBox : control_groups) + { + for (ControlButton* button : cgBox->control_buttons) + { + wxString expr = StrToWxStr(button->control_reference->expression); + expr.Replace("&", "&&"); + button->SetLabel(expr); + } - for (PadSetting* padSetting : cgBox->options) - { - padSetting->UpdateGUI(); - } - } + for (PadSetting* padSetting : cgBox->options) + { + padSetting->UpdateGUI(); + } + } } void GamepadPage::ClearAll(wxCommandEvent&) { - // just load an empty ini section to clear everything :P - IniFile::Section section; - controller->LoadConfig(§ion); + // just load an empty ini section to clear everything :P + IniFile::Section section; + controller->LoadConfig(§ion); - // no point in using the real ControllerInterface i guess - ControllerInterface face; + // no point in using the real ControllerInterface i guess + ControllerInterface face; - controller->UpdateReferences(face); + controller->UpdateReferences(face); - UpdateGUI(); + UpdateGUI(); } void GamepadPage::LoadDefaults(wxCommandEvent&) { - controller->LoadDefaults(g_controller_interface); + controller->LoadDefaults(g_controller_interface); - controller->UpdateReferences(g_controller_interface); + controller->UpdateReferences(g_controller_interface); - UpdateGUI(); + UpdateGUI(); } bool ControlDialog::Validate() { - control_reference->expression = WxStrToStr(textctrl->GetValue()); + control_reference->expression = WxStrToStr(textctrl->GetValue()); - g_controller_interface.UpdateReference(control_reference, m_parent->controller->default_device); + g_controller_interface.UpdateReference(control_reference, m_parent->controller->default_device); - UpdateGUI(); + UpdateGUI(); - return (control_reference->parse_error == EXPRESSION_PARSE_SUCCESS); + return (control_reference->parse_error == EXPRESSION_PARSE_SUCCESS); } void GamepadPage::SetDevice(wxCommandEvent&) { - controller->default_device.FromString(WxStrToStr(device_cbox->GetValue())); + controller->default_device.FromString(WxStrToStr(device_cbox->GetValue())); - // show user what it was validated as - device_cbox->SetValue(StrToWxStr(controller->default_device.ToString())); + // show user what it was validated as + device_cbox->SetValue(StrToWxStr(controller->default_device.ToString())); - // this will set all the controls to this default device - controller->UpdateDefaultDevice(); + // this will set all the controls to this default device + controller->UpdateDefaultDevice(); - // update references - controller->UpdateReferences(g_controller_interface); + // update references + controller->UpdateReferences(g_controller_interface); } void ControlDialog::SetDevice(wxCommandEvent&) { - m_devq.FromString(WxStrToStr(device_cbox->GetValue())); + m_devq.FromString(WxStrToStr(device_cbox->GetValue())); - // show user what it was validated as - device_cbox->SetValue(StrToWxStr(m_devq.ToString())); + // show user what it was validated as + device_cbox->SetValue(StrToWxStr(m_devq.ToString())); - // update gui - UpdateListContents(); + // update gui + UpdateListContents(); } void ControlDialog::ClearControl(wxCommandEvent&) { - control_reference->expression.clear(); + control_reference->expression.clear(); - g_controller_interface.UpdateReference(control_reference, m_parent->controller->default_device); + g_controller_interface.UpdateReference(control_reference, m_parent->controller->default_device); - UpdateGUI(); + UpdateGUI(); } -inline bool IsAlphabetic(wxString &str) +inline bool IsAlphabetic(wxString& str) { - for (wxUniChar c : str) - if (!isalpha(c)) - return false; + for (wxUniChar c : str) + if (!isalpha(c)) + return false; - return true; + return true; } -inline void GetExpressionForControl(wxString &expr, - wxString &control_name, - ciface::Core::DeviceQualifier *control_device = nullptr, - ciface::Core::DeviceQualifier *default_device = nullptr) +inline void GetExpressionForControl(wxString& expr, wxString& control_name, + ciface::Core::DeviceQualifier* control_device = nullptr, + ciface::Core::DeviceQualifier* default_device = nullptr) { - expr = ""; + expr = ""; - // non-default device - if (control_device && default_device && !(*control_device == *default_device)) - { - expr += control_device->ToString(); - expr += ":"; - } + // non-default device + if (control_device && default_device && !(*control_device == *default_device)) + { + expr += control_device->ToString(); + expr += ":"; + } - // append the control name - expr += control_name; + // append the control name + expr += control_name; - if (!IsAlphabetic(expr)) - expr = wxString::Format("`%s`", expr); + if (!IsAlphabetic(expr)) + expr = wxString::Format("`%s`", expr); } -bool ControlDialog::GetExpressionForSelectedControl(wxString &expr) +bool ControlDialog::GetExpressionForSelectedControl(wxString& expr) { - const int num = control_lbox->GetSelection(); + const int num = control_lbox->GetSelection(); - if (num < 0) - return false; + if (num < 0) + return false; - wxString control_name = control_lbox->GetString(num); - GetExpressionForControl(expr, - control_name, - &m_devq, - &m_parent->controller->default_device); + wxString control_name = control_lbox->GetString(num); + GetExpressionForControl(expr, control_name, &m_devq, &m_parent->controller->default_device); - return true; + return true; } void ControlDialog::SetSelectedControl(wxCommandEvent&) { - wxString expr; + wxString expr; - if (!GetExpressionForSelectedControl(expr)) - return; + if (!GetExpressionForSelectedControl(expr)) + return; - textctrl->WriteText(expr); - control_reference->expression = textctrl->GetValue(); + textctrl->WriteText(expr); + control_reference->expression = textctrl->GetValue(); - g_controller_interface.UpdateReference(control_reference, m_parent->controller->default_device); + g_controller_interface.UpdateReference(control_reference, m_parent->controller->default_device); - UpdateGUI(); + UpdateGUI(); } void ControlDialog::AppendControl(wxCommandEvent& event) { - wxString device_expr, expr; + wxString device_expr, expr; - const wxString lbl = ((wxButton*)event.GetEventObject())->GetLabel(); - char op = lbl[0]; + const wxString lbl = ((wxButton*)event.GetEventObject())->GetLabel(); + char op = lbl[0]; - if (!GetExpressionForSelectedControl(device_expr)) - return; + if (!GetExpressionForSelectedControl(device_expr)) + return; - // Unary ops (that is, '!') are a special case. When there's a selection, - // put parens around it and prepend it with a '!', but when there's nothing, - // just add a '!device'. - if (op == '!') - { - wxString selection = textctrl->GetStringSelection(); - if (selection == "") - expr = wxString::Format("%c%s", op, device_expr); - else - expr = wxString::Format("%c(%s)", op, selection); - } - else - { - expr = wxString::Format(" %c %s", op, device_expr); - } + // Unary ops (that is, '!') are a special case. When there's a selection, + // put parens around it and prepend it with a '!', but when there's nothing, + // just add a '!device'. + if (op == '!') + { + wxString selection = textctrl->GetStringSelection(); + if (selection == "") + expr = wxString::Format("%c%s", op, device_expr); + else + expr = wxString::Format("%c(%s)", op, selection); + } + else + { + expr = wxString::Format(" %c %s", op, device_expr); + } - textctrl->WriteText(expr); - control_reference->expression = textctrl->GetValue(); + textctrl->WriteText(expr); + control_reference->expression = textctrl->GetValue(); - g_controller_interface.UpdateReference(control_reference, m_parent->controller->default_device); + g_controller_interface.UpdateReference(control_reference, m_parent->controller->default_device); - UpdateGUI(); + UpdateGUI(); } void GamepadPage::AdjustSetting(wxCommandEvent& event) { - ((PadSetting*)((wxControl*)event.GetEventObject())->GetClientData())->UpdateValue(); + ((PadSetting*)((wxControl*)event.GetEventObject())->GetClientData())->UpdateValue(); } void GamepadPage::AdjustSettingUI(wxCommandEvent& event) { - m_iterate = !m_iterate; - ((PadSetting*)((wxControl*)event.GetEventObject())->GetClientData())->UpdateValue(); + m_iterate = !m_iterate; + ((PadSetting*)((wxControl*)event.GetEventObject())->GetClientData())->UpdateValue(); } void GamepadPage::AdjustControlOption(wxCommandEvent&) { - m_control_dialog->control_reference->range = (ControlState)(m_control_dialog->GetRangeSliderValue()) / SLIDER_TICK_COUNT; + m_control_dialog->control_reference->range = + (ControlState)(m_control_dialog->GetRangeSliderValue()) / SLIDER_TICK_COUNT; } void GamepadPage::ConfigControl(wxEvent& event) { - m_control_dialog = new ControlDialog(this, m_config, ((ControlButton*)event.GetEventObject())->control_reference); - m_control_dialog->ShowModal(); - m_control_dialog->Destroy(); + m_control_dialog = new ControlDialog(this, m_config, + ((ControlButton*)event.GetEventObject())->control_reference); + m_control_dialog->ShowModal(); + m_control_dialog->Destroy(); - // update changes that were made in the dialog - UpdateGUI(); + // update changes that were made in the dialog + UpdateGUI(); } void GamepadPage::ClearControl(wxEvent& event) { - ControlButton* const btn = (ControlButton*)event.GetEventObject(); - btn->control_reference->expression.clear(); - btn->control_reference->range = 1.0; + ControlButton* const btn = (ControlButton*)event.GetEventObject(); + btn->control_reference->expression.clear(); + btn->control_reference->range = 1.0; - controller->UpdateReferences(g_controller_interface); + controller->UpdateReferences(g_controller_interface); - // update changes - UpdateGUI(); + // update changes + UpdateGUI(); } void ControlDialog::DetectControl(wxCommandEvent& event) { - wxButton* const btn = (wxButton*)event.GetEventObject(); - const wxString lbl = btn->GetLabel(); + wxButton* const btn = (wxButton*)event.GetEventObject(); + const wxString lbl = btn->GetLabel(); - ciface::Core::Device* const dev = g_controller_interface.FindDevice(m_devq); - if (dev) - { - m_event_filter.BlockEvents(true); - btn->SetLabel(_("[ waiting ]")); + ciface::Core::Device* const dev = g_controller_interface.FindDevice(m_devq); + if (dev) + { + m_event_filter.BlockEvents(true); + btn->SetLabel(_("[ waiting ]")); - // This makes the "waiting" text work on Linux. true (only if needed) prevents crash on Windows - wxTheApp->Yield(true); + // This makes the "waiting" text work on Linux. true (only if needed) prevents crash on Windows + wxTheApp->Yield(true); - ciface::Core::Device::Control* const ctrl = control_reference->Detect(DETECT_WAIT_TIME, dev); + ciface::Core::Device::Control* const ctrl = control_reference->Detect(DETECT_WAIT_TIME, dev); - // if we got input, select it in the list - if (ctrl) - SelectControl(ctrl->GetName()); + // if we got input, select it in the list + if (ctrl) + SelectControl(ctrl->GetName()); - btn->SetLabel(lbl); + btn->SetLabel(lbl); - // This lets the input events be sent to the filter and discarded before unblocking - wxTheApp->Yield(true); - m_event_filter.BlockEvents(false); - } + // This lets the input events be sent to the filter and discarded before unblocking + wxTheApp->Yield(true); + m_event_filter.BlockEvents(false); + } } void GamepadPage::DetectControl(wxCommandEvent& event) { - ControlButton* btn = (ControlButton*)event.GetEventObject(); - if (DetectButton(btn) && m_iterate == true) - { - auto it = std::find(control_buttons.begin(), control_buttons.end(), btn); + ControlButton* btn = (ControlButton*)event.GetEventObject(); + if (DetectButton(btn) && m_iterate == true) + { + auto it = std::find(control_buttons.begin(), control_buttons.end(), btn); - // std find will never return end since btn will always be found in control_buttons - ++it; - for (; it != control_buttons.end(); ++it) - { - if (!DetectButton(*it)) - break; - } - } + // std find will never return end since btn will always be found in control_buttons + ++it; + for (; it != control_buttons.end(); ++it) + { + if (!DetectButton(*it)) + break; + } + } } bool GamepadPage::DetectButton(ControlButton* button) { - bool success = false; - // find device :/ - ciface::Core::Device* const dev = g_controller_interface.FindDevice(controller->default_device); - if (dev) - { - m_event_filter.BlockEvents(true); - button->SetLabel(_("[ waiting ]")); + bool success = false; + // find device :/ + ciface::Core::Device* const dev = g_controller_interface.FindDevice(controller->default_device); + if (dev) + { + m_event_filter.BlockEvents(true); + button->SetLabel(_("[ waiting ]")); - // This makes the "waiting" text work on Linux. true (only if needed) prevents crash on Windows - wxTheApp->Yield(true); + // This makes the "waiting" text work on Linux. true (only if needed) prevents crash on Windows + wxTheApp->Yield(true); - ciface::Core::Device::Control* const ctrl = button->control_reference->Detect(DETECT_WAIT_TIME, dev); + ciface::Core::Device::Control* const ctrl = + button->control_reference->Detect(DETECT_WAIT_TIME, dev); - // if we got input, update expression and reference - if (ctrl) - { - wxString control_name = ctrl->GetName(); - wxString expr; - GetExpressionForControl(expr, control_name); - button->control_reference->expression = expr; - g_controller_interface.UpdateReference(button->control_reference, controller->default_device); - success = true; - } + // if we got input, update expression and reference + if (ctrl) + { + wxString control_name = ctrl->GetName(); + wxString expr; + GetExpressionForControl(expr, control_name); + button->control_reference->expression = expr; + g_controller_interface.UpdateReference(button->control_reference, controller->default_device); + success = true; + } - // This lets the input events be sent to the filter and discarded before unblocking - wxTheApp->Yield(true); - m_event_filter.BlockEvents(false); - } + // This lets the input events be sent to the filter and discarded before unblocking + wxTheApp->Yield(true); + m_event_filter.BlockEvents(false); + } - UpdateGUI(); + UpdateGUI(); - return success; + return success; } wxStaticBoxSizer* ControlDialog::CreateControlChooser(GamepadPage* const parent) { - wxStaticBoxSizer* const main_szr = new wxStaticBoxSizer(wxVERTICAL, this, control_reference->is_input ? _("Input") : _("Output")); + wxStaticBoxSizer* const main_szr = new wxStaticBoxSizer( + wxVERTICAL, this, control_reference->is_input ? _("Input") : _("Output")); - textctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1, 48), wxTE_MULTILINE | wxTE_RICH2); - wxFont font = textctrl->GetFont(); - font.SetFamily(wxFONTFAMILY_MODERN); - textctrl->SetFont(font); + textctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1, 48), + wxTE_MULTILINE | wxTE_RICH2); + wxFont font = textctrl->GetFont(); + font.SetFamily(wxFONTFAMILY_MODERN); + textctrl->SetFont(font); - wxButton* const detect_button = new wxButton(this, wxID_ANY, control_reference->is_input ? _("Detect") : _("Test")); + wxButton* const detect_button = + new wxButton(this, wxID_ANY, control_reference->is_input ? _("Detect") : _("Test")); - wxButton* const clear_button = new wxButton(this, wxID_ANY, _("Clear")); + wxButton* const clear_button = new wxButton(this, wxID_ANY, _("Clear")); - wxButton* const select_button = new wxButton(this, wxID_ANY, _("Select")); - select_button->Bind(wxEVT_BUTTON, &ControlDialog::SetSelectedControl, this); + wxButton* const select_button = new wxButton(this, wxID_ANY, _("Select")); + select_button->Bind(wxEVT_BUTTON, &ControlDialog::SetSelectedControl, this); - wxButton* const or_button = new wxButton(this, wxID_ANY, _("| OR")); - or_button->Bind(wxEVT_BUTTON, &ControlDialog::AppendControl, this); + wxButton* const or_button = new wxButton(this, wxID_ANY, _("| OR")); + or_button->Bind(wxEVT_BUTTON, &ControlDialog::AppendControl, this); - control_lbox = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 64)); + control_lbox = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 64)); - wxBoxSizer* const button_sizer = new wxBoxSizer(wxVERTICAL); - button_sizer->Add(detect_button, 1, 0, 5); - button_sizer->Add(select_button, 1, 0, 5); - button_sizer->Add(or_button, 1, 0, 5); + wxBoxSizer* const button_sizer = new wxBoxSizer(wxVERTICAL); + button_sizer->Add(detect_button, 1, 0, 5); + button_sizer->Add(select_button, 1, 0, 5); + button_sizer->Add(or_button, 1, 0, 5); - if (control_reference->is_input) - { - // TODO: check if && is good on other OS - wxButton* const and_button = new wxButton(this, wxID_ANY, _("&& AND")); - wxButton* const not_button = new wxButton(this, wxID_ANY, _("! NOT")); - wxButton* const add_button = new wxButton(this, wxID_ANY, _("+ ADD")); + if (control_reference->is_input) + { + // TODO: check if && is good on other OS + wxButton* const and_button = new wxButton(this, wxID_ANY, _("&& AND")); + wxButton* const not_button = new wxButton(this, wxID_ANY, _("! NOT")); + wxButton* const add_button = new wxButton(this, wxID_ANY, _("+ ADD")); - and_button->Bind(wxEVT_BUTTON, &ControlDialog::AppendControl, this); - not_button->Bind(wxEVT_BUTTON, &ControlDialog::AppendControl, this); - add_button->Bind(wxEVT_BUTTON, &ControlDialog::AppendControl, this); + and_button->Bind(wxEVT_BUTTON, &ControlDialog::AppendControl, this); + not_button->Bind(wxEVT_BUTTON, &ControlDialog::AppendControl, this); + add_button->Bind(wxEVT_BUTTON, &ControlDialog::AppendControl, this); - button_sizer->Add(and_button, 1, 0, 5); - button_sizer->Add(not_button, 1, 0, 5); - button_sizer->Add(add_button, 1, 0, 5); - } + button_sizer->Add(and_button, 1, 0, 5); + button_sizer->Add(not_button, 1, 0, 5); + button_sizer->Add(add_button, 1, 0, 5); + } - range_slider = new wxSlider(this, wxID_ANY, SLIDER_TICK_COUNT, -SLIDER_TICK_COUNT * 5, SLIDER_TICK_COUNT * 5, wxDefaultPosition, wxDefaultSize, wxSL_TOP | wxSL_LABELS /*| wxSL_AUTOTICKS*/); + range_slider = + new wxSlider(this, wxID_ANY, SLIDER_TICK_COUNT, -SLIDER_TICK_COUNT * 5, SLIDER_TICK_COUNT * 5, + wxDefaultPosition, wxDefaultSize, wxSL_TOP | wxSL_LABELS /*| wxSL_AUTOTICKS*/); - range_slider->SetValue((int)(control_reference->range * SLIDER_TICK_COUNT)); + range_slider->SetValue((int)(control_reference->range * SLIDER_TICK_COUNT)); - detect_button->Bind(wxEVT_BUTTON, &ControlDialog::DetectControl, this); - clear_button->Bind(wxEVT_BUTTON, &ControlDialog::ClearControl, this); + detect_button->Bind(wxEVT_BUTTON, &ControlDialog::DetectControl, this); + clear_button->Bind(wxEVT_BUTTON, &ControlDialog::ClearControl, this); - range_slider->Bind(wxEVT_SCROLL_CHANGED, &GamepadPage::AdjustControlOption, parent); - wxStaticText* const range_label = new wxStaticText(this, wxID_ANY, _("Range")); + range_slider->Bind(wxEVT_SCROLL_CHANGED, &GamepadPage::AdjustControlOption, parent); + wxStaticText* const range_label = new wxStaticText(this, wxID_ANY, _("Range")); - m_bound_label = new wxStaticText(this, wxID_ANY, ""); - m_error_label = new wxStaticText(this, wxID_ANY, ""); + m_bound_label = new wxStaticText(this, wxID_ANY, ""); + m_error_label = new wxStaticText(this, wxID_ANY, ""); - wxBoxSizer* const range_sizer = new wxBoxSizer(wxHORIZONTAL); - range_sizer->Add(range_label, 0, wxCENTER|wxLEFT, 5); - range_sizer->Add(range_slider, 1, wxEXPAND|wxLEFT, 5); + wxBoxSizer* const range_sizer = new wxBoxSizer(wxHORIZONTAL); + range_sizer->Add(range_label, 0, wxCENTER | wxLEFT, 5); + range_sizer->Add(range_slider, 1, wxEXPAND | wxLEFT, 5); - wxBoxSizer* const ctrls_sizer = new wxBoxSizer(wxHORIZONTAL); - ctrls_sizer->Add(control_lbox, 1, wxEXPAND, 0); - ctrls_sizer->Add(button_sizer, 0, wxEXPAND, 0); + wxBoxSizer* const ctrls_sizer = new wxBoxSizer(wxHORIZONTAL); + ctrls_sizer->Add(control_lbox, 1, wxEXPAND, 0); + ctrls_sizer->Add(button_sizer, 0, wxEXPAND, 0); - wxSizer* const bottom_btns_sizer = CreateButtonSizer(wxOK|wxAPPLY); - bottom_btns_sizer->Prepend(clear_button, 0, wxLEFT, 5); + wxSizer* const bottom_btns_sizer = CreateButtonSizer(wxOK | wxAPPLY); + bottom_btns_sizer->Prepend(clear_button, 0, wxLEFT, 5); - main_szr->Add(range_sizer, 0, wxEXPAND|wxLEFT|wxRIGHT, 5); - main_szr->Add(ctrls_sizer, 0, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, 5); - main_szr->Add(textctrl, 1, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, 5); - main_szr->Add(bottom_btns_sizer, 0, wxEXPAND|wxBOTTOM|wxRIGHT, 5); - main_szr->Add(m_bound_label, 0, wxCENTER, 0); - main_szr->Add(m_error_label, 0, wxCENTER, 0); + main_szr->Add(range_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 5); + main_szr->Add(ctrls_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + main_szr->Add(textctrl, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + main_szr->Add(bottom_btns_sizer, 0, wxEXPAND | wxBOTTOM | wxRIGHT, 5); + main_szr->Add(m_bound_label, 0, wxCENTER, 0); + main_szr->Add(m_error_label, 0, wxCENTER, 0); - UpdateListContents(); + UpdateListContents(); - return main_szr; + return main_szr; } void GamepadPage::GetProfilePath(std::string& path) { - const wxString& name = profile_cbox->GetValue(); - if (!name.empty()) - { - // TODO: check for dumb characters maybe + const wxString& name = profile_cbox->GetValue(); + if (!name.empty()) + { + // TODO: check for dumb characters maybe - path = File::GetUserPath(D_CONFIG_IDX); - path += PROFILES_PATH; - path += m_config.GetProfileName(); - path += '/'; - path += WxStrToStr(profile_cbox->GetValue()); - path += ".ini"; - } + path = File::GetUserPath(D_CONFIG_IDX); + path += PROFILES_PATH; + path += m_config.GetProfileName(); + path += '/'; + path += WxStrToStr(profile_cbox->GetValue()); + path += ".ini"; + } } void GamepadPage::LoadProfile(wxCommandEvent&) { - std::string fname; - GamepadPage::GetProfilePath(fname); + std::string fname; + GamepadPage::GetProfilePath(fname); - if (!File::Exists(fname)) - return; + if (!File::Exists(fname)) + return; - IniFile inifile; - inifile.Load(fname); + IniFile inifile; + inifile.Load(fname); - controller->LoadConfig(inifile.GetOrCreateSection("Profile")); - controller->UpdateReferences(g_controller_interface); + controller->LoadConfig(inifile.GetOrCreateSection("Profile")); + controller->UpdateReferences(g_controller_interface); - UpdateGUI(); + UpdateGUI(); } void GamepadPage::SaveProfile(wxCommandEvent&) { - std::string fname; - GamepadPage::GetProfilePath(fname); - File::CreateFullPath(fname); + std::string fname; + GamepadPage::GetProfilePath(fname); + File::CreateFullPath(fname); - if (!fname.empty()) - { - IniFile inifile; - controller->SaveConfig(inifile.GetOrCreateSection("Profile")); - inifile.Save(fname); + if (!fname.empty()) + { + IniFile inifile; + controller->SaveConfig(inifile.GetOrCreateSection("Profile")); + inifile.Save(fname); - m_config_dialog->UpdateProfileComboBox(); - } - else - { - WxUtils::ShowErrorDialog(_("You must enter a valid profile name.")); - } + m_config_dialog->UpdateProfileComboBox(); + } + else + { + WxUtils::ShowErrorDialog(_("You must enter a valid profile name.")); + } } void GamepadPage::DeleteProfile(wxCommandEvent&) { - std::string fname; - GamepadPage::GetProfilePath(fname); + std::string fname; + GamepadPage::GetProfilePath(fname); - const char* const fnamecstr = fname.c_str(); + const char* const fnamecstr = fname.c_str(); - if (File::Exists(fnamecstr) && - AskYesNoT("Are you sure you want to delete \"%s\"?", - WxStrToStr(profile_cbox->GetValue()).c_str())) - { - File::Delete(fnamecstr); + if (File::Exists(fnamecstr) && AskYesNoT("Are you sure you want to delete \"%s\"?", + WxStrToStr(profile_cbox->GetValue()).c_str())) + { + File::Delete(fnamecstr); - m_config_dialog->UpdateProfileComboBox(); - } + m_config_dialog->UpdateProfileComboBox(); + } } void InputConfigDialog::UpdateDeviceComboBox() { - ciface::Core::DeviceQualifier dq; - for (GamepadPage* page : m_padpages) - { - page->device_cbox->Clear(); + ciface::Core::DeviceQualifier dq; + for (GamepadPage* page : m_padpages) + { + page->device_cbox->Clear(); - for (ciface::Core::Device* d : g_controller_interface.Devices()) - { - dq.FromDevice(d); - page->device_cbox->Append(StrToWxStr(dq.ToString())); - } + for (ciface::Core::Device* d : g_controller_interface.Devices()) + { + dq.FromDevice(d); + page->device_cbox->Append(StrToWxStr(dq.ToString())); + } - page->device_cbox->SetValue(StrToWxStr(page->controller->default_device.ToString())); - } + page->device_cbox->SetValue(StrToWxStr(page->controller->default_device.ToString())); + } } void GamepadPage::RefreshDevices(wxCommandEvent&) { - bool was_unpaused = Core::PauseAndLock(true); + bool was_unpaused = Core::PauseAndLock(true); - // refresh devices - g_controller_interface.Reinitialize(); + // refresh devices + g_controller_interface.Reinitialize(); - // update all control references - m_config_dialog->UpdateControlReferences(); + // update all control references + m_config_dialog->UpdateControlReferences(); - // update device cbox - m_config_dialog->UpdateDeviceComboBox(); + // update device cbox + m_config_dialog->UpdateDeviceComboBox(); - Wiimote::LoadConfig(); - Keyboard::LoadConfig(); - Pad::LoadConfig(); - HotkeyManagerEmu::LoadConfig(); + Wiimote::LoadConfig(); + Keyboard::LoadConfig(); + Pad::LoadConfig(); + HotkeyManagerEmu::LoadConfig(); - Core::PauseAndLock(false, was_unpaused); + Core::PauseAndLock(false, was_unpaused); } ControlGroupBox::~ControlGroupBox() { - for (PadSetting* padSetting : options) - delete padSetting; + for (PadSetting* padSetting : options) + delete padSetting; } -ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWindow* const parent, GamepadPage* const eventsink) - : wxBoxSizer(wxVERTICAL) - , control_group(group) +ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWindow* const parent, + GamepadPage* const eventsink) + : wxBoxSizer(wxVERTICAL), control_group(group) { - static_bitmap = nullptr; - const std::vector exclude_buttons = {"Mic", "Modifier"}; - const std::vector exclude_groups = {"IR", "Swing", "Tilt", "Shake", "UDP Wiimote", "Extension", "Rumble"}; + static_bitmap = nullptr; + const std::vector exclude_buttons = {"Mic", "Modifier"}; + const std::vector exclude_groups = {"IR", "Swing", "Tilt", "Shake", + "UDP Wiimote", "Extension", "Rumble"}; - wxFont m_SmallFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); - for (auto& control : group->controls) - { - wxStaticText* const label = new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(control->name))); + wxFont m_SmallFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); + for (auto& control : group->controls) + { + wxStaticText* const label = + new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(control->name))); - ControlButton* const control_button = new ControlButton(parent, control->control_ref.get(), 80); - control_button->SetFont(m_SmallFont); + ControlButton* const control_button = new ControlButton(parent, control->control_ref.get(), 80); + control_button->SetFont(m_SmallFont); - control_buttons.push_back(control_button); - if (std::find(exclude_groups.begin(), exclude_groups.end(), control_group->name) == exclude_groups.end() && - std::find(exclude_buttons.begin(), exclude_buttons.end(), control->name) == exclude_buttons.end()) - eventsink->control_buttons.push_back(control_button); + control_buttons.push_back(control_button); + if (std::find(exclude_groups.begin(), exclude_groups.end(), control_group->name) == + exclude_groups.end() && + std::find(exclude_buttons.begin(), exclude_buttons.end(), control->name) == + exclude_buttons.end()) + eventsink->control_buttons.push_back(control_button); + if (control->control_ref->is_input) + { + control_button->SetToolTip( + _("Left-click to detect input.\nMiddle-click to clear.\nRight-click for more options.")); + control_button->Bind(wxEVT_BUTTON, &GamepadPage::DetectControl, eventsink); + } + else + { + control_button->SetToolTip(_("Left/Right-click for more options.\nMiddle-click to clear.")); + control_button->Bind(wxEVT_BUTTON, &GamepadPage::ConfigControl, eventsink); + } - if (control->control_ref->is_input) - { - control_button->SetToolTip(_("Left-click to detect input.\nMiddle-click to clear.\nRight-click for more options.")); - control_button->Bind(wxEVT_BUTTON, &GamepadPage::DetectControl, eventsink); - } - else - { - control_button->SetToolTip(_("Left/Right-click for more options.\nMiddle-click to clear.")); - control_button->Bind(wxEVT_BUTTON, &GamepadPage::ConfigControl, eventsink); - } + control_button->Bind(wxEVT_MIDDLE_DOWN, &GamepadPage::ClearControl, eventsink); + control_button->Bind(wxEVT_RIGHT_UP, &GamepadPage::ConfigControl, eventsink); - control_button->Bind(wxEVT_MIDDLE_DOWN, &GamepadPage::ClearControl, eventsink); - control_button->Bind(wxEVT_RIGHT_UP, &GamepadPage::ConfigControl, eventsink); + wxBoxSizer* const control_sizer = new wxBoxSizer(wxHORIZONTAL); + control_sizer->AddStretchSpacer(1); + control_sizer->Add(label, 0, wxCENTER | wxRIGHT, 3); + control_sizer->Add(control_button, 0, 0, 0); - wxBoxSizer* const control_sizer = new wxBoxSizer(wxHORIZONTAL); - control_sizer->AddStretchSpacer(1); - control_sizer->Add(label, 0, wxCENTER | wxRIGHT, 3); - control_sizer->Add(control_button, 0, 0, 0); + Add(control_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 3); + } - Add(control_sizer, 0, wxEXPAND|wxLEFT|wxRIGHT, 3); + wxMemoryDC dc; - } + switch (group->type) + { + case GROUP_TYPE_STICK: + case GROUP_TYPE_TILT: + case GROUP_TYPE_CURSOR: + case GROUP_TYPE_FORCE: + { + wxBitmap bitmap(64, 64); + dc.SelectObject(bitmap); + dc.Clear(); + static_bitmap = new wxStaticBitmap(parent, wxID_ANY, bitmap, wxDefaultPosition, wxDefaultSize, + wxBITMAP_TYPE_BMP); - wxMemoryDC dc; + wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL); + for (auto& groupSetting : group->settings) + { + PadSettingSpin* setting = new PadSettingSpin(parent, groupSetting.get()); + setting->wxcontrol->Bind(wxEVT_SPINCTRL, &GamepadPage::AdjustSetting, eventsink); + options.push_back(setting); + szr->Add( + new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(groupSetting->name)))); + szr->Add(setting->wxcontrol, 0, wxLEFT, 0); + } - switch (group->type) - { - case GROUP_TYPE_STICK: - case GROUP_TYPE_TILT: - case GROUP_TYPE_CURSOR: - case GROUP_TYPE_FORCE: - { - wxBitmap bitmap(64, 64); - dc.SelectObject(bitmap); - dc.Clear(); - static_bitmap = new wxStaticBitmap(parent, wxID_ANY, bitmap, wxDefaultPosition, wxDefaultSize, wxBITMAP_TYPE_BMP); + wxBoxSizer* const h_szr = new wxBoxSizer(wxHORIZONTAL); + h_szr->Add(szr, 1, 0, 5); + h_szr->Add(static_bitmap, 0, wxALL | wxCENTER, 3); - wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL); - for (auto& groupSetting : group->settings) - { - PadSettingSpin* setting = new PadSettingSpin(parent, groupSetting.get()); - setting->wxcontrol->Bind(wxEVT_SPINCTRL, &GamepadPage::AdjustSetting, eventsink); - options.push_back(setting); - szr->Add(new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(groupSetting->name)))); - szr->Add(setting->wxcontrol, 0, wxLEFT, 0); - } + Add(h_szr, 0, wxEXPAND | wxLEFT | wxCENTER | wxTOP, 3); + } + break; + case GROUP_TYPE_BUTTONS: + { + // Draw buttons in rows of 8 + unsigned int button_cols = group->controls.size() > 8 ? 8 : group->controls.size(); + unsigned int button_rows = ceil((float)group->controls.size() / 8.0f); + wxBitmap bitmap(int(12 * button_cols + 1), (11 * button_rows) + 1); - wxBoxSizer* const h_szr = new wxBoxSizer(wxHORIZONTAL); - h_szr->Add(szr, 1, 0, 5); - h_szr->Add(static_bitmap, 0, wxALL|wxCENTER, 3); + dc.SelectObject(bitmap); + dc.Clear(); + static_bitmap = new wxStaticBitmap(parent, wxID_ANY, bitmap, wxDefaultPosition, wxDefaultSize, + wxBITMAP_TYPE_BMP); - Add(h_szr, 0, wxEXPAND|wxLEFT|wxCENTER|wxTOP, 3); - } - break; - case GROUP_TYPE_BUTTONS: - { - // Draw buttons in rows of 8 - unsigned int button_cols = group->controls.size() > 8 ? 8 : group->controls.size(); - unsigned int button_rows = ceil((float)group->controls.size() / 8.0f); - wxBitmap bitmap(int(12 * button_cols + 1), (11 * button_rows) + 1); + PadSettingSpin* const threshold_cbox = new PadSettingSpin(parent, group->settings[0].get()); + threshold_cbox->wxcontrol->Bind(wxEVT_SPINCTRL, &GamepadPage::AdjustSetting, eventsink); - dc.SelectObject(bitmap); - dc.Clear(); - static_bitmap = new wxStaticBitmap(parent, wxID_ANY, bitmap, wxDefaultPosition, wxDefaultSize, wxBITMAP_TYPE_BMP); + threshold_cbox->wxcontrol->SetToolTip( + _("Adjust the analog control pressure required to activate buttons.")); - PadSettingSpin* const threshold_cbox = new PadSettingSpin(parent, group->settings[0].get()); - threshold_cbox->wxcontrol->Bind(wxEVT_SPINCTRL, &GamepadPage::AdjustSetting, eventsink); + options.push_back(threshold_cbox); - threshold_cbox->wxcontrol->SetToolTip(_("Adjust the analog control pressure required to activate buttons.")); + wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL); + szr->Add( + new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(group->settings[0]->name))), + 0, wxCENTER | wxRIGHT, 3); + szr->Add(threshold_cbox->wxcontrol, 0, wxRIGHT, 3); - options.push_back(threshold_cbox); + Add(szr, 0, wxALL | wxCENTER, 3); + Add(static_bitmap, 0, wxALL | wxCENTER, 3); + } + break; + case GROUP_TYPE_MIXED_TRIGGERS: + case GROUP_TYPE_TRIGGERS: + case GROUP_TYPE_SLIDER: + { + int height = (int)(12 * group->controls.size()); + int width = 64; - wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL); - szr->Add(new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(group->settings[0]->name))), - 0, wxCENTER|wxRIGHT, 3); - szr->Add(threshold_cbox->wxcontrol, 0, wxRIGHT, 3); + if (GROUP_TYPE_MIXED_TRIGGERS == group->type) + width = 64 + 12 + 1; - Add(szr, 0, wxALL|wxCENTER, 3); - Add(static_bitmap, 0, wxALL|wxCENTER, 3); - } - break; - case GROUP_TYPE_MIXED_TRIGGERS: - case GROUP_TYPE_TRIGGERS: - case GROUP_TYPE_SLIDER: - { - int height = (int)(12 * group->controls.size()); - int width = 64; + if (GROUP_TYPE_TRIGGERS != group->type) + height /= 2; - if (GROUP_TYPE_MIXED_TRIGGERS == group->type) - width = 64+12+1; + wxBitmap bitmap(width, height + 1); + dc.SelectObject(bitmap); + dc.Clear(); + static_bitmap = new wxStaticBitmap(parent, wxID_ANY, bitmap, wxDefaultPosition, wxDefaultSize, + wxBITMAP_TYPE_BMP); - if (GROUP_TYPE_TRIGGERS != group->type) - height /= 2; + for (auto& groupSetting : group->settings) + { + PadSettingSpin* setting = new PadSettingSpin(parent, groupSetting.get()); + setting->wxcontrol->Bind(wxEVT_SPINCTRL, &GamepadPage::AdjustSetting, eventsink); + options.push_back(setting); + wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL); + szr->Add(new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(groupSetting->name))), + 0, wxCENTER | wxRIGHT, 3); + szr->Add(setting->wxcontrol, 0, wxRIGHT, 3); + Add(szr, 0, wxALL | wxCENTER, 3); + } - wxBitmap bitmap(width, height+1); - dc.SelectObject(bitmap); - dc.Clear(); - static_bitmap = new wxStaticBitmap(parent, wxID_ANY, bitmap, wxDefaultPosition, wxDefaultSize, wxBITMAP_TYPE_BMP); + Add(static_bitmap, 0, wxALL | wxCENTER, 3); + } + break; + case GROUP_TYPE_EXTENSION: + { + PadSettingExtension* const attachments = + new PadSettingExtension(parent, (ControllerEmu::Extension*)group); + wxButton* const configure_btn = new ExtensionButton(parent, (ControllerEmu::Extension*)group); - for (auto& groupSetting : group->settings) - { - PadSettingSpin* setting = new PadSettingSpin(parent, groupSetting.get()); - setting->wxcontrol->Bind(wxEVT_SPINCTRL, &GamepadPage::AdjustSetting, eventsink); - options.push_back(setting); - wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL); - szr->Add(new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(groupSetting->name))), 0, wxCENTER | wxRIGHT, 3); - szr->Add(setting->wxcontrol, 0, wxRIGHT, 3); - Add(szr, 0, wxALL|wxCENTER, 3); - } + options.push_back(attachments); - Add(static_bitmap, 0, wxALL|wxCENTER, 3); - } - break; - case GROUP_TYPE_EXTENSION: - { - PadSettingExtension* const attachments = new PadSettingExtension(parent, (ControllerEmu::Extension*)group); - wxButton* const configure_btn = new ExtensionButton(parent, (ControllerEmu::Extension*)group); + attachments->wxcontrol->Bind(wxEVT_CHOICE, &GamepadPage::AdjustSetting, eventsink); + configure_btn->Bind(wxEVT_BUTTON, &GamepadPage::ConfigExtension, eventsink); - options.push_back(attachments); + Add(attachments->wxcontrol, 0, wxTOP | wxLEFT | wxRIGHT | wxEXPAND, 3); + Add(configure_btn, 0, wxALL | wxEXPAND, 3); + } + break; + default: + { + // options + for (auto& groupSetting : group->settings) + { + if (groupSetting->high == DEFAULT_HIGH_VALUE) + { + PadSettingCheckBox* setting_cbox = new PadSettingCheckBox(parent, groupSetting.get()); + if (groupSetting->is_iterate == true) + { + setting_cbox->wxcontrol->Bind(wxEVT_CHECKBOX, &GamepadPage::AdjustSettingUI, eventsink); + groupSetting->value = 0; + } + else + { + setting_cbox->wxcontrol->Bind(wxEVT_CHECKBOX, &GamepadPage::AdjustSetting, eventsink); + } + options.push_back(setting_cbox); + Add(setting_cbox->wxcontrol, 0, wxALL | wxLEFT, 5); + } + else + { + PadSettingSpin* setting = new PadSettingSpin(parent, groupSetting.get()); + setting->wxcontrol->Bind(wxEVT_SPINCTRL, &GamepadPage::AdjustSetting, eventsink); + options.push_back(setting); + wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL); + szr->Add( + new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(groupSetting->name))), 0, + wxCENTER | wxRIGHT, 3); + szr->Add(setting->wxcontrol, 0, wxRIGHT, 3); + Add(szr, 0, wxALL | wxCENTER, 3); + } + } + } + break; + } - attachments->wxcontrol->Bind(wxEVT_CHOICE, &GamepadPage::AdjustSetting, eventsink); - configure_btn->Bind(wxEVT_BUTTON, &GamepadPage::ConfigExtension, eventsink); + dc.SelectObject(wxNullBitmap); - Add(attachments->wxcontrol, 0, wxTOP|wxLEFT|wxRIGHT|wxEXPAND, 3); - Add(configure_btn, 0, wxALL|wxEXPAND, 3); - } - break; - default: - { - //options - for (auto& groupSetting : group->settings) - { - if (groupSetting->high == DEFAULT_HIGH_VALUE) - { - PadSettingCheckBox* setting_cbox = new PadSettingCheckBox(parent, groupSetting.get()); - if (groupSetting->is_iterate == true) - { - setting_cbox->wxcontrol->Bind(wxEVT_CHECKBOX, &GamepadPage::AdjustSettingUI, eventsink); - groupSetting->value = 0; - } - else - { - setting_cbox->wxcontrol->Bind(wxEVT_CHECKBOX, &GamepadPage::AdjustSetting, eventsink); - } - options.push_back(setting_cbox); - Add(setting_cbox->wxcontrol, 0, wxALL | wxLEFT, 5); - } - else - { - PadSettingSpin* setting = new PadSettingSpin(parent, groupSetting.get()); - setting->wxcontrol->Bind(wxEVT_SPINCTRL, &GamepadPage::AdjustSetting, eventsink); - options.push_back(setting); - wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL); - szr->Add(new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(groupSetting->name))), 0, wxCENTER | wxRIGHT, 3); - szr->Add(setting->wxcontrol, 0, wxRIGHT, 3); - Add(szr, 0, wxALL | wxCENTER, 3); - } - } - } - break; - } - - dc.SelectObject(wxNullBitmap); - - //AddStretchSpacer(0); + // AddStretchSpacer(0); } -ControlGroupsSizer::ControlGroupsSizer(ControllerEmu* const controller, wxWindow* const parent, GamepadPage* const eventsink, std::vector* groups) - : wxBoxSizer(wxHORIZONTAL) +ControlGroupsSizer::ControlGroupsSizer(ControllerEmu* const controller, wxWindow* const parent, + GamepadPage* const eventsink, + std::vector* groups) + : wxBoxSizer(wxHORIZONTAL) { - size_t col_size = 0; + size_t col_size = 0; - wxBoxSizer* stacked_groups = nullptr; - for (auto& group : controller->groups) - { - ControlGroupBox* control_group_box = new ControlGroupBox(group.get(), parent, eventsink); - wxStaticBoxSizer *control_group = - new wxStaticBoxSizer(wxVERTICAL, parent, wxGetTranslation(StrToWxStr(group->ui_name))); - control_group->Add(control_group_box); + wxBoxSizer* stacked_groups = nullptr; + for (auto& group : controller->groups) + { + ControlGroupBox* control_group_box = new ControlGroupBox(group.get(), parent, eventsink); + wxStaticBoxSizer* control_group = + new wxStaticBoxSizer(wxVERTICAL, parent, wxGetTranslation(StrToWxStr(group->ui_name))); + control_group->Add(control_group_box); - const size_t grp_size = group->controls.size() + group->settings.size(); - col_size += grp_size; - if (col_size > 8 || nullptr == stacked_groups) - { - if (stacked_groups) - Add(stacked_groups, 0, /*wxEXPAND|*/wxBOTTOM|wxRIGHT, 5); + const size_t grp_size = group->controls.size() + group->settings.size(); + col_size += grp_size; + if (col_size > 8 || nullptr == stacked_groups) + { + if (stacked_groups) + Add(stacked_groups, 0, /*wxEXPAND|*/ wxBOTTOM | wxRIGHT, 5); - stacked_groups = new wxBoxSizer(wxVERTICAL); - stacked_groups->Add(control_group, 0, wxEXPAND); + stacked_groups = new wxBoxSizer(wxVERTICAL); + stacked_groups->Add(control_group, 0, wxEXPAND); - col_size = grp_size; - } - else - { - stacked_groups->Add(control_group, 0, wxEXPAND); - } + col_size = grp_size; + } + else + { + stacked_groups->Add(control_group, 0, wxEXPAND); + } - if (groups) - groups->push_back(control_group_box); - } + if (groups) + groups->push_back(control_group_box); + } - if (stacked_groups) - Add(stacked_groups, 0, /*wxEXPAND|*/wxBOTTOM|wxRIGHT, 5); + if (stacked_groups) + Add(stacked_groups, 0, /*wxEXPAND|*/ wxBOTTOM | wxRIGHT, 5); } -GamepadPage::GamepadPage(wxWindow* parent, InputConfig& config, const int pad_num, InputConfigDialog* const config_dialog) - : wxPanel(parent, wxID_ANY) - , controller(config.GetController(pad_num)) - , m_config_dialog(config_dialog) - , m_config(config) +GamepadPage::GamepadPage(wxWindow* parent, InputConfig& config, const int pad_num, + InputConfigDialog* const config_dialog) + : wxPanel(parent, wxID_ANY), controller(config.GetController(pad_num)), + m_config_dialog(config_dialog), m_config(config) { + wxBoxSizer* control_group_sizer = new ControlGroupsSizer(controller, this, this, &control_groups); - wxBoxSizer* control_group_sizer = new ControlGroupsSizer(controller, this, this, &control_groups); + wxStaticBoxSizer* profile_sbox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Profile")); - wxStaticBoxSizer* profile_sbox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Profile")); + // device chooser - // device chooser + wxStaticBoxSizer* const device_sbox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Device")); - wxStaticBoxSizer* const device_sbox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Device")); + device_cbox = new wxComboBox(this, wxID_ANY, "", wxDefaultPosition, wxSize(64, -1)); + device_cbox->ToggleWindowStyle(wxTE_PROCESS_ENTER); - device_cbox = new wxComboBox(this, wxID_ANY, "", wxDefaultPosition, wxSize(64, -1)); - device_cbox->ToggleWindowStyle(wxTE_PROCESS_ENTER); + wxButton* refresh_button = + new wxButton(this, wxID_ANY, _("Refresh"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - wxButton* refresh_button = new wxButton(this, wxID_ANY, _("Refresh"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + device_cbox->Bind(wxEVT_COMBOBOX, &GamepadPage::SetDevice, this); + device_cbox->Bind(wxEVT_TEXT_ENTER, &GamepadPage::SetDevice, this); + refresh_button->Bind(wxEVT_BUTTON, &GamepadPage::RefreshDevices, this); - device_cbox->Bind(wxEVT_COMBOBOX, &GamepadPage::SetDevice, this); - device_cbox->Bind(wxEVT_TEXT_ENTER, &GamepadPage::SetDevice, this); - refresh_button->Bind(wxEVT_BUTTON, &GamepadPage::RefreshDevices, this); + device_sbox->Add(device_cbox, 1, wxLEFT | wxRIGHT, 3); + device_sbox->Add(refresh_button, 0, wxRIGHT | wxBOTTOM, 3); - device_sbox->Add(device_cbox, 1, wxLEFT|wxRIGHT, 3); - device_sbox->Add(refresh_button, 0, wxRIGHT|wxBOTTOM, 3); + wxButton* const default_button = + new wxButton(this, wxID_ANY, _("Default"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + wxButton* const clearall_button = + new wxButton(this, wxID_ANY, _("Clear"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - wxButton* const default_button = new wxButton(this, wxID_ANY, _("Default"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - wxButton* const clearall_button = new wxButton(this, wxID_ANY, _("Clear"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + wxStaticBoxSizer* const clear_sbox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Reset")); + clear_sbox->Add(default_button, 1, wxLEFT, 3); + clear_sbox->Add(clearall_button, 1, wxRIGHT, 3); - wxStaticBoxSizer* const clear_sbox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Reset")); - clear_sbox->Add(default_button, 1, wxLEFT, 3); - clear_sbox->Add(clearall_button, 1, wxRIGHT, 3); + clearall_button->Bind(wxEVT_BUTTON, &GamepadPage::ClearAll, this); + default_button->Bind(wxEVT_BUTTON, &GamepadPage::LoadDefaults, this); - clearall_button->Bind(wxEVT_BUTTON, &GamepadPage::ClearAll, this); - default_button->Bind(wxEVT_BUTTON, &GamepadPage::LoadDefaults, this); + profile_cbox = new wxComboBox(this, wxID_ANY, "", wxDefaultPosition, wxSize(64, -1)); - profile_cbox = new wxComboBox(this, wxID_ANY, "", wxDefaultPosition, wxSize(64, -1)); + wxButton* const pload_btn = + new wxButton(this, wxID_ANY, _("Load"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + wxButton* const psave_btn = + new wxButton(this, wxID_ANY, _("Save"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + wxButton* const pdelete_btn = + new wxButton(this, wxID_ANY, _("Delete"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - wxButton* const pload_btn = new wxButton(this, wxID_ANY, _("Load"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - wxButton* const psave_btn = new wxButton(this, wxID_ANY, _("Save"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - wxButton* const pdelete_btn = new wxButton(this, wxID_ANY, _("Delete"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + pload_btn->Bind(wxEVT_BUTTON, &GamepadPage::LoadProfile, this); + psave_btn->Bind(wxEVT_BUTTON, &GamepadPage::SaveProfile, this); + pdelete_btn->Bind(wxEVT_BUTTON, &GamepadPage::DeleteProfile, this); - pload_btn->Bind(wxEVT_BUTTON, &GamepadPage::LoadProfile, this); - psave_btn->Bind(wxEVT_BUTTON, &GamepadPage::SaveProfile, this); - pdelete_btn->Bind(wxEVT_BUTTON, &GamepadPage::DeleteProfile, this); + profile_sbox->Add(profile_cbox, 1, wxLEFT, 3); + profile_sbox->Add(pload_btn, 0, wxLEFT, 3); + profile_sbox->Add(psave_btn, 0, 0, 3); + profile_sbox->Add(pdelete_btn, 0, wxRIGHT | wxBOTTOM, 3); - profile_sbox->Add(profile_cbox, 1, wxLEFT, 3); - profile_sbox->Add(pload_btn, 0, wxLEFT, 3); - profile_sbox->Add(psave_btn, 0, 0, 3); - profile_sbox->Add(pdelete_btn, 0, wxRIGHT|wxBOTTOM, 3); + wxBoxSizer* const dio = new wxBoxSizer(wxHORIZONTAL); + dio->Add(device_sbox, 1, wxEXPAND | wxRIGHT, 5); + dio->Add(clear_sbox, 0, wxEXPAND | wxRIGHT, 5); + dio->Add(profile_sbox, 1, wxEXPAND | wxRIGHT, 5); - wxBoxSizer* const dio = new wxBoxSizer(wxHORIZONTAL); - dio->Add(device_sbox, 1, wxEXPAND|wxRIGHT, 5); - dio->Add(clear_sbox, 0, wxEXPAND|wxRIGHT, 5); - dio->Add(profile_sbox, 1, wxEXPAND|wxRIGHT, 5); + wxBoxSizer* const mapping = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* const mapping = new wxBoxSizer(wxVERTICAL); + mapping->Add(dio, 1, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 5); + mapping->Add(control_group_sizer, 0, wxLEFT | wxEXPAND, 5); - mapping->Add(dio, 1, wxEXPAND|wxLEFT|wxTOP|wxBOTTOM, 5); - mapping->Add(control_group_sizer, 0, wxLEFT|wxEXPAND, 5); + UpdateGUI(); - UpdateGUI(); - - SetSizerAndFit(mapping); // needed - Layout(); + SetSizerAndFit(mapping); // needed + Layout(); }; - -InputConfigDialog::InputConfigDialog(wxWindow* const parent, InputConfig& config, const wxString& name, const int tab_num) - : wxDialog(parent, wxID_ANY, name, wxPoint(128,-1)) - , m_config(config) +InputConfigDialog::InputConfigDialog(wxWindow* const parent, InputConfig& config, + const wxString& name, const int tab_num) + : wxDialog(parent, wxID_ANY, name, wxPoint(128, -1)), m_config(config) { - m_pad_notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_DEFAULT); - GamepadPage* gp = new GamepadPage(m_pad_notebook, m_config, tab_num, this); - m_padpages.push_back(gp); - m_pad_notebook->AddPage(gp, wxString::Format("%s [%u]", wxGetTranslation(StrToWxStr(m_config.GetGUIName())), 1 + tab_num)); + m_pad_notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_DEFAULT); + GamepadPage* gp = new GamepadPage(m_pad_notebook, m_config, tab_num, this); + m_padpages.push_back(gp); + m_pad_notebook->AddPage(gp, wxString::Format("%s [%u]", + wxGetTranslation(StrToWxStr(m_config.GetGUIName())), + 1 + tab_num)); - m_pad_notebook->SetSelection(0); + m_pad_notebook->SetSelection(0); - UpdateDeviceComboBox(); - UpdateProfileComboBox(); + UpdateDeviceComboBox(); + UpdateProfileComboBox(); - Bind(wxEVT_BUTTON, &InputConfigDialog::ClickSave, this, wxID_OK); + Bind(wxEVT_BUTTON, &InputConfigDialog::ClickSave, this, wxID_OK); - wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL); - szr->Add(m_pad_notebook, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5); - szr->Add(CreateButtonSizer(wxOK | wxCANCEL | wxNO_DEFAULT), 0, wxEXPAND|wxALL, 5); + wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL); + szr->Add(m_pad_notebook, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5); + szr->Add(CreateButtonSizer(wxOK | wxCANCEL | wxNO_DEFAULT), 0, wxEXPAND | wxALL, 5); - SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED); - SetSizerAndFit(szr); - Center(); + SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED); + SetSizerAndFit(szr); + Center(); - // live preview update timer - m_update_timer.SetOwner(this); - Bind(wxEVT_TIMER, &InputConfigDialog::UpdateBitmaps, this); - m_update_timer.Start(PREVIEW_UPDATE_TIME, wxTIMER_CONTINUOUS); + // live preview update timer + m_update_timer.SetOwner(this); + Bind(wxEVT_TIMER, &InputConfigDialog::UpdateBitmaps, this); + m_update_timer.Start(PREVIEW_UPDATE_TIME, wxTIMER_CONTINUOUS); } int InputEventFilter::FilterEvent(wxEvent& event) { - if (m_block && ShouldCatchEventType(event.GetEventType())) - { - event.StopPropagation(); - return Event_Processed; - } + if (m_block && ShouldCatchEventType(event.GetEventType())) + { + event.StopPropagation(); + return Event_Processed; + } - return Event_Skip; + return Event_Skip; } diff --git a/Source/Core/DolphinWX/InputConfigDiag.h b/Source/Core/DolphinWX/InputConfigDiag.h index 9d85e2fb42..995240e4d7 100644 --- a/Source/Core/DolphinWX/InputConfigDiag.h +++ b/Source/Core/DolphinWX/InputConfigDiag.h @@ -4,13 +4,13 @@ #pragma once -#define SLIDER_TICK_COUNT 100 -#define DETECT_WAIT_TIME 2500 -#define PREVIEW_UPDATE_TIME 25 -#define DEFAULT_HIGH_VALUE 100 +#define SLIDER_TICK_COUNT 100 +#define DETECT_WAIT_TIME 2500 +#define PREVIEW_UPDATE_TIME 25 +#define DEFAULT_HIGH_VALUE 100 // might have to change this setup for Wiimote -#define PROFILES_PATH "Profiles/" +#define PROFILES_PATH "Profiles/" #include #include @@ -39,79 +39,70 @@ class wxTextCtrl; class PadSetting { protected: - PadSetting(wxControl* const _control) : wxcontrol(_control) { wxcontrol->SetClientData(this); } - + PadSetting(wxControl* const _control) : wxcontrol(_control) { wxcontrol->SetClientData(this); } public: - virtual void UpdateGUI() = 0; - virtual void UpdateValue() = 0; + virtual void UpdateGUI() = 0; + virtual void UpdateValue() = 0; - virtual ~PadSetting() {} - - wxControl* const wxcontrol; + virtual ~PadSetting() {} + wxControl* const wxcontrol; }; class PadSettingExtension : public PadSetting { public: - PadSettingExtension(wxWindow* const parent, ControllerEmu::Extension* const ext); - void UpdateGUI() override; - void UpdateValue() override; + PadSettingExtension(wxWindow* const parent, ControllerEmu::Extension* const ext); + void UpdateGUI() override; + void UpdateValue() override; - ControllerEmu::Extension* const extension; + ControllerEmu::Extension* const extension; }; class PadSettingSpin : public PadSetting { public: - PadSettingSpin(wxWindow* const parent, ControllerEmu::ControlGroup::Setting* const _setting) - : PadSetting(new wxSpinCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, - wxSize(54, -1), 0, _setting->low, _setting->high, (int)(_setting->value * 100))) - , setting(_setting) {} + PadSettingSpin(wxWindow* const parent, ControllerEmu::ControlGroup::Setting* const _setting) + : PadSetting(new wxSpinCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, + wxSize(54, -1), 0, _setting->low, _setting->high, + (int)(_setting->value * 100))), + setting(_setting) + { + } - void UpdateGUI() override; - void UpdateValue() override; + void UpdateGUI() override; + void UpdateValue() override; - ControllerEmu::ControlGroup::Setting* const setting; + ControllerEmu::ControlGroup::Setting* const setting; }; class PadSettingCheckBox : public PadSetting { public: - PadSettingCheckBox(wxWindow* const parent, ControllerEmu::ControlGroup::Setting* const setting); - void UpdateGUI() override; - void UpdateValue() override; + PadSettingCheckBox(wxWindow* const parent, ControllerEmu::ControlGroup::Setting* const setting); + void UpdateGUI() override; + void UpdateValue() override; - ControllerEmu::ControlGroup::Setting* const setting; + ControllerEmu::ControlGroup::Setting* const setting; }; class InputEventFilter : public wxEventFilter { public: - InputEventFilter() - { - wxEvtHandler::AddFilter(this); - } - - ~InputEventFilter() - { - wxEvtHandler::RemoveFilter(this); - } - - int FilterEvent(wxEvent& event) override; - - void BlockEvents(bool block) { m_block = block; } + InputEventFilter() { wxEvtHandler::AddFilter(this); } + ~InputEventFilter() { wxEvtHandler::RemoveFilter(this); } + int FilterEvent(wxEvent& event) override; + void BlockEvents(bool block) { m_block = block; } private: - static bool ShouldCatchEventType(wxEventType type) - { - return type == wxEVT_KEY_DOWN || type == wxEVT_KEY_UP || - type == wxEVT_CHAR || type == wxEVT_CHAR_HOOK || - type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_UP || - type == wxEVT_MIDDLE_DOWN || type == wxEVT_MIDDLE_UP || - type == wxEVT_RIGHT_DOWN || type == wxEVT_RIGHT_UP; - } + static bool ShouldCatchEventType(wxEventType type) + { + return type == wxEVT_KEY_DOWN || type == wxEVT_KEY_UP || type == wxEVT_CHAR || + type == wxEVT_CHAR_HOOK || type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_UP || + type == wxEVT_MIDDLE_DOWN || type == wxEVT_MIDDLE_UP || type == wxEVT_RIGHT_DOWN || + type == wxEVT_RIGHT_UP; + } - bool m_block = false; + bool m_block = false; }; class GamepadPage; @@ -119,152 +110,157 @@ class GamepadPage; class ControlDialog : public wxDialog { public: - ControlDialog(GamepadPage* const parent, InputConfig& config, ControllerInterface::ControlReference* const ref); + ControlDialog(GamepadPage* const parent, InputConfig& config, + ControllerInterface::ControlReference* const ref); - bool Validate() override; + bool Validate() override; - int GetRangeSliderValue() const; + int GetRangeSliderValue() const; - ControllerInterface::ControlReference* const control_reference; - InputConfig& m_config; + ControllerInterface::ControlReference* const control_reference; + InputConfig& m_config; private: - wxStaticBoxSizer* CreateControlChooser(GamepadPage* const parent); + wxStaticBoxSizer* CreateControlChooser(GamepadPage* const parent); - void UpdateGUI(); - void UpdateListContents(); - void SelectControl(const std::string& name); + void UpdateGUI(); + void UpdateListContents(); + void SelectControl(const std::string& name); - void DetectControl(wxCommandEvent& event); - void ClearControl(wxCommandEvent& event); - void SetDevice(wxCommandEvent& event); + void DetectControl(wxCommandEvent& event); + void ClearControl(wxCommandEvent& event); + void SetDevice(wxCommandEvent& event); - void SetSelectedControl(wxCommandEvent& event); - void AppendControl(wxCommandEvent& event); + void SetSelectedControl(wxCommandEvent& event); + void AppendControl(wxCommandEvent& event); - bool GetExpressionForSelectedControl(wxString &expr); + bool GetExpressionForSelectedControl(wxString& expr); - GamepadPage* const m_parent; - wxComboBox* device_cbox; - wxTextCtrl* textctrl; - wxListBox* control_lbox; - wxSlider* range_slider; - wxStaticText* m_bound_label; - wxStaticText* m_error_label; - InputEventFilter m_event_filter; - ciface::Core::DeviceQualifier m_devq; + GamepadPage* const m_parent; + wxComboBox* device_cbox; + wxTextCtrl* textctrl; + wxListBox* control_lbox; + wxSlider* range_slider; + wxStaticText* m_bound_label; + wxStaticText* m_error_label; + InputEventFilter m_event_filter; + ciface::Core::DeviceQualifier m_devq; }; class ExtensionButton : public wxButton { public: - ExtensionButton(wxWindow* const parent, ControllerEmu::Extension* const ext) - : wxButton(parent, wxID_ANY, _("Configure"), wxDefaultPosition) - , extension(ext) {} + ExtensionButton(wxWindow* const parent, ControllerEmu::Extension* const ext) + : wxButton(parent, wxID_ANY, _("Configure"), wxDefaultPosition), extension(ext) + { + } - ControllerEmu::Extension* const extension; + ControllerEmu::Extension* const extension; }; class ControlButton : public wxButton { public: - ControlButton(wxWindow* const parent, ControllerInterface::ControlReference* const _ref, const unsigned int width, const std::string& label = ""); + ControlButton(wxWindow* const parent, ControllerInterface::ControlReference* const _ref, + const unsigned int width, const std::string& label = ""); - ControllerInterface::ControlReference* const control_reference; + ControllerInterface::ControlReference* const control_reference; }; class ControlGroupBox : public wxBoxSizer { public: - ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWindow* const parent, GamepadPage* const eventsink); - ~ControlGroupBox(); + ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWindow* const parent, + GamepadPage* const eventsink); + ~ControlGroupBox(); - std::vector options; + std::vector options; - ControllerEmu::ControlGroup* const control_group; - wxStaticBitmap* static_bitmap; - std::vector control_buttons; + ControllerEmu::ControlGroup* const control_group; + wxStaticBitmap* static_bitmap; + std::vector control_buttons; }; class ControlGroupsSizer : public wxBoxSizer { public: - ControlGroupsSizer(ControllerEmu* const controller, wxWindow* const parent, GamepadPage* const eventsink, std::vector* const groups = nullptr); + ControlGroupsSizer(ControllerEmu* const controller, wxWindow* const parent, + GamepadPage* const eventsink, + std::vector* const groups = nullptr); }; class InputConfigDialog; class GamepadPage : public wxPanel { - friend class InputConfigDialog; - friend class ControlDialog; + friend class InputConfigDialog; + friend class ControlDialog; public: - GamepadPage(wxWindow* parent, InputConfig& config, const int pad_num, InputConfigDialog* const config_dialog); + GamepadPage(wxWindow* parent, InputConfig& config, const int pad_num, + InputConfigDialog* const config_dialog); - void UpdateGUI(); + void UpdateGUI(); - void RefreshDevices(wxCommandEvent& event); + void RefreshDevices(wxCommandEvent& event); - void LoadProfile(wxCommandEvent& event); - void SaveProfile(wxCommandEvent& event); - void DeleteProfile(wxCommandEvent& event); + void LoadProfile(wxCommandEvent& event); + void SaveProfile(wxCommandEvent& event); + void DeleteProfile(wxCommandEvent& event); - void ConfigControl(wxEvent& event); - void ClearControl(wxEvent& event); - void DetectControl(wxCommandEvent& event); + void ConfigControl(wxEvent& event); + void ClearControl(wxEvent& event); + void DetectControl(wxCommandEvent& event); - void ConfigExtension(wxCommandEvent& event); + void ConfigExtension(wxCommandEvent& event); - void SetDevice(wxCommandEvent& event); + void SetDevice(wxCommandEvent& event); - void ClearAll(wxCommandEvent& event); - void LoadDefaults(wxCommandEvent& event); + void ClearAll(wxCommandEvent& event); + void LoadDefaults(wxCommandEvent& event); - void AdjustControlOption(wxCommandEvent& event); - void AdjustSetting(wxCommandEvent& event); - void AdjustSettingUI(wxCommandEvent& event); + void AdjustControlOption(wxCommandEvent& event); + void AdjustSetting(wxCommandEvent& event); + void AdjustSettingUI(wxCommandEvent& event); - void GetProfilePath(std::string& path); + void GetProfilePath(std::string& path); - wxComboBox* profile_cbox; - wxComboBox* device_cbox; + wxComboBox* profile_cbox; + wxComboBox* device_cbox; - std::vector control_groups; - std::vector control_buttons; + std::vector control_groups; + std::vector control_buttons; protected: - - ControllerEmu* const controller; + ControllerEmu* const controller; private: + ControlDialog* m_control_dialog; + InputConfigDialog* const m_config_dialog; + InputConfig& m_config; + InputEventFilter m_event_filter; - ControlDialog* m_control_dialog; - InputConfigDialog* const m_config_dialog; - InputConfig& m_config; - InputEventFilter m_event_filter; - - bool DetectButton(ControlButton* button); - bool m_iterate = false; + bool DetectButton(ControlButton* button); + bool m_iterate = false; }; class InputConfigDialog : public wxDialog { public: - InputConfigDialog(wxWindow* const parent, InputConfig& config, const wxString& name, const int tab_num = 0); + InputConfigDialog(wxWindow* const parent, InputConfig& config, const wxString& name, + const int tab_num = 0); - void ClickSave(wxCommandEvent& event); + void ClickSave(wxCommandEvent& event); - void UpdateDeviceComboBox(); - void UpdateProfileComboBox(); + void UpdateDeviceComboBox(); + void UpdateProfileComboBox(); - void UpdateControlReferences(); - void UpdateBitmaps(wxTimerEvent&); + void UpdateControlReferences(); + void UpdateBitmaps(wxTimerEvent&); private: - - wxNotebook* m_pad_notebook; - std::vector m_padpages; - InputConfig& m_config; - wxTimer m_update_timer; + wxNotebook* m_pad_notebook; + std::vector m_padpages; + InputConfig& m_config; + wxTimer m_update_timer; }; diff --git a/Source/Core/DolphinWX/InputConfigDiagBitmaps.cpp b/Source/Core/DolphinWX/InputConfigDiagBitmaps.cpp index 8494663a7f..3f1d0e18e7 100644 --- a/Source/Core/DolphinWX/InputConfigDiagBitmaps.cpp +++ b/Source/Core/DolphinWX/InputConfigDiagBitmaps.cpp @@ -25,69 +25,81 @@ struct ShapePosition { - double max; - double diag; - double box; - double scale; + double max; + double diag; + double box; + double scale; - double dz; - double range; + double dz; + double range; - wxCoord offset; + wxCoord offset; }; // regular octagon static void DrawOctagon(wxDC* dc, ShapePosition p) { - const int vertices = 8; - double radius = p.max; + const int vertices = 8; + double radius = p.max; - wxPoint point[vertices]; + wxPoint point[vertices]; - double angle = 2.0 * M_PI / vertices; + double angle = 2.0 * M_PI / vertices; - for (int i = 0; i < vertices; i++) - { - double a = (angle * i); - double x = radius * cos(a); - double y = radius * sin(a); - point[i].x = x; - point[i].y = y; - } + for (int i = 0; i < vertices; i++) + { + double a = (angle * i); + double x = radius * cos(a); + double y = radius * sin(a); + point[i].x = x; + point[i].y = y; + } - dc->DrawPolygon(vertices, point, p.offset, p.offset); + dc->DrawPolygon(vertices, point, p.offset, p.offset); } // irregular dodecagon static void DrawDodecagon(wxDC* dc, ShapePosition p) { - const int vertices = 12; + const int vertices = 12; - wxPoint point[vertices]; - point[0].x = p.dz; point[0].y = p.max; - point[1].x = p.diag; point[1].y = p.diag; - point[2].x = p.max; point[2].y = p.dz; + wxPoint point[vertices]; + point[0].x = p.dz; + point[0].y = p.max; + point[1].x = p.diag; + point[1].y = p.diag; + point[2].x = p.max; + point[2].y = p.dz; - point[3].x = p.max; point[3].y = -p.dz; - point[4].x = p.diag; point[4].y = -p.diag; - point[5].x = p.dz; point[5].y = -p.max; + point[3].x = p.max; + point[3].y = -p.dz; + point[4].x = p.diag; + point[4].y = -p.diag; + point[5].x = p.dz; + point[5].y = -p.max; - point[6].x = -p.dz; point[6].y = -p.max; - point[7].x = -p.diag; point[7].y = -p.diag; - point[8].x = -p.max; point[8].y = -p.dz; + point[6].x = -p.dz; + point[6].y = -p.max; + point[7].x = -p.diag; + point[7].y = -p.diag; + point[8].x = -p.max; + point[8].y = -p.dz; - point[9].x = -p.max; point[9].y = p.dz; - point[10].x = -p.diag; point[10].y = p.diag; - point[11].x = -p.dz; point[11].y = p.max; + point[9].x = -p.max; + point[9].y = p.dz; + point[10].x = -p.diag; + point[10].y = p.diag; + point[11].x = -p.dz; + point[11].y = p.max; - dc->DrawPolygon(vertices, point, p.offset, p.offset); + dc->DrawPolygon(vertices, point, p.offset, p.offset); } -static void DrawCenteredRectangle(wxDC &dc, int x, int y, int w, int h) +static void DrawCenteredRectangle(wxDC& dc, int x, int y, int w, int h) { - x -= w / 2; - y -= h / 2; - dc.DrawRectangle(x, y, w, h); + x -= w / 2; + y -= h / 2; + dc.DrawRectangle(x, y, w, h); } #define VIS_BITMAP_SIZE 64 @@ -97,387 +109,389 @@ static void DrawCenteredRectangle(wxDC &dc, int x, int y, int w, int h) #define COORD_VIS_SIZE 4 -static void DrawCoordinate(wxDC &dc, ControlState x, ControlState y) +static void DrawCoordinate(wxDC& dc, ControlState x, ControlState y) { - int xc = VIS_COORD(x); - int yc = VIS_COORD(y); - DrawCenteredRectangle(dc, xc, yc, COORD_VIS_SIZE, COORD_VIS_SIZE); + int xc = VIS_COORD(x); + int yc = VIS_COORD(y); + DrawCenteredRectangle(dc, xc, yc, COORD_VIS_SIZE, COORD_VIS_SIZE); } -static void DrawButton(unsigned int* const bitmasks, unsigned int buttons, unsigned int n, wxDC& dc, ControlGroupBox* g, unsigned int row) +static void DrawButton(unsigned int* const bitmasks, unsigned int buttons, unsigned int n, wxDC& dc, + ControlGroupBox* g, unsigned int row) { - if (buttons & bitmasks[(row * 8) + n]) - { - dc.SetBrush(*wxRED_BRUSH); - } - else - { - unsigned char amt = 255 - g->control_group->controls[(row * 8) + n]->control_ref->State() * 128; - dc.SetBrush(wxBrush(wxColour(amt, amt, amt))); - } - dc.DrawRectangle(n * 12, (row == 0) ? 0 : (row * 11), 14, 12); + if (buttons & bitmasks[(row * 8) + n]) + { + dc.SetBrush(*wxRED_BRUSH); + } + else + { + unsigned char amt = 255 - g->control_group->controls[(row * 8) + n]->control_ref->State() * 128; + dc.SetBrush(wxBrush(wxColour(amt, amt, amt))); + } + dc.DrawRectangle(n * 12, (row == 0) ? 0 : (row * 11), 14, 12); - // text - const std::string name = g->control_group->controls[(row * 8) + n]->name; - // bit of hax so ZL, ZR show up as L, R - dc.DrawText(StrToWxStr(std::string(1, (name[1] && name[1] < 'a') ? name[1] : name[0])), n * 12 + 2, 1 + ((row == 0) ? 0 : (row * 11))); + // text + const std::string name = g->control_group->controls[(row * 8) + n]->name; + // bit of hax so ZL, ZR show up as L, R + dc.DrawText(StrToWxStr(std::string(1, (name[1] && name[1] < 'a') ? name[1] : name[0])), + n * 12 + 2, 1 + ((row == 0) ? 0 : (row * 11))); } -static void DrawControlGroupBox(wxDC &dc, ControlGroupBox *g) +static void DrawControlGroupBox(wxDC& dc, ControlGroupBox* g) { - switch (g->control_group->type) - { - case GROUP_TYPE_TILT : - case GROUP_TYPE_STICK : - case GROUP_TYPE_CURSOR : - { - // this is starting to be a mess combining all these in one case + switch (g->control_group->type) + { + case GROUP_TYPE_TILT: + case GROUP_TYPE_STICK: + case GROUP_TYPE_CURSOR: + { + // this is starting to be a mess combining all these in one case - ControlState x = 0, y = 0, z = 0; + ControlState x = 0, y = 0, z = 0; - switch (g->control_group->type) - { - case GROUP_TYPE_STICK : - ((ControllerEmu::AnalogStick*)g->control_group)->GetState(&x, &y); - break; - case GROUP_TYPE_TILT : - ((ControllerEmu::Tilt*)g->control_group)->GetState(&x, &y); - break; - case GROUP_TYPE_CURSOR : - ((ControllerEmu::Cursor*)g->control_group)->GetState(&x, &y, &z); - break; - } + switch (g->control_group->type) + { + case GROUP_TYPE_STICK: + ((ControllerEmu::AnalogStick*)g->control_group)->GetState(&x, &y); + break; + case GROUP_TYPE_TILT: + ((ControllerEmu::Tilt*)g->control_group)->GetState(&x, &y); + break; + case GROUP_TYPE_CURSOR: + ((ControllerEmu::Cursor*)g->control_group)->GetState(&x, &y, &z); + break; + } - // ir cursor forward movement - if (GROUP_TYPE_CURSOR == g->control_group->type) - { - if (z) - { - dc.SetPen(*wxRED_PEN); - dc.SetBrush(*wxRED_BRUSH); - } - else - { - dc.SetPen(*wxGREY_PEN); - dc.SetBrush(*wxGREY_BRUSH); - } - dc.DrawRectangle(0, 31 - z*31, 64, 2); - } + // ir cursor forward movement + if (GROUP_TYPE_CURSOR == g->control_group->type) + { + if (z) + { + dc.SetPen(*wxRED_PEN); + dc.SetBrush(*wxRED_BRUSH); + } + else + { + dc.SetPen(*wxGREY_PEN); + dc.SetBrush(*wxGREY_BRUSH); + } + dc.DrawRectangle(0, 31 - z * 31, 64, 2); + } - // input zone - dc.SetPen(*wxLIGHT_GREY_PEN); - dc.SetBrush(*wxWHITE_BRUSH); - if (GROUP_TYPE_STICK == g->control_group->type) - { - // outline and fill colors - wxBrush LightGrayBrush("#dddddd"); - wxPen LightGrayPen("#bfbfbf"); - dc.SetBrush(LightGrayBrush); - dc.SetPen(LightGrayPen); + // input zone + dc.SetPen(*wxLIGHT_GREY_PEN); + dc.SetBrush(*wxWHITE_BRUSH); + if (GROUP_TYPE_STICK == g->control_group->type) + { + // outline and fill colors + wxBrush LightGrayBrush("#dddddd"); + wxPen LightGrayPen("#bfbfbf"); + dc.SetBrush(LightGrayBrush); + dc.SetPen(LightGrayPen); - ShapePosition p; - p.box = 64; - p.offset = p.box / 2; - p.range = 256; - p.scale = p.box / p.range; - p.dz = 15 * p.scale; - bool octagon = false; + ShapePosition p; + p.box = 64; + p.offset = p.box / 2; + p.range = 256; + p.scale = p.box / p.range; + p.dz = 15 * p.scale; + bool octagon = false; - if (g->control_group->name == "Main Stick") - { - p.max = 87 * p.scale; - p.diag = 55 * p.scale; - } - else if (g->control_group->name == "C-Stick") - { - p.max = 74 * p.scale; - p.diag = 46 * p.scale; - } - else - { - p.scale = 1; - p.max = 32; - octagon = true; - } + if (g->control_group->name == "Main Stick") + { + p.max = 87 * p.scale; + p.diag = 55 * p.scale; + } + else if (g->control_group->name == "C-Stick") + { + p.max = 74 * p.scale; + p.diag = 46 * p.scale; + } + else + { + p.scale = 1; + p.max = 32; + octagon = true; + } - if (octagon) - DrawOctagon(&dc, p); - else - DrawDodecagon(&dc, p); - } - else - { - dc.DrawRectangle(16, 16, 32, 32); - } + if (octagon) + DrawOctagon(&dc, p); + else + DrawDodecagon(&dc, p); + } + else + { + dc.DrawRectangle(16, 16, 32, 32); + } - if (GROUP_TYPE_CURSOR != g->control_group->type) - { - // deadzone circle - dc.SetBrush(*wxLIGHT_GREY_BRUSH); - dc.DrawCircle(32, 32, g->control_group->settings[SETTING_DEADZONE]->value * 32); - } + if (GROUP_TYPE_CURSOR != g->control_group->type) + { + // deadzone circle + dc.SetBrush(*wxLIGHT_GREY_BRUSH); + dc.DrawCircle(32, 32, g->control_group->settings[SETTING_DEADZONE]->value * 32); + } - // raw dot - { - ControlState xx, yy; - xx = g->control_group->controls[3]->control_ref->State(); - xx -= g->control_group->controls[2]->control_ref->State(); - yy = g->control_group->controls[1]->control_ref->State(); - yy -= g->control_group->controls[0]->control_ref->State(); + // raw dot + { + ControlState xx, yy; + xx = g->control_group->controls[3]->control_ref->State(); + xx -= g->control_group->controls[2]->control_ref->State(); + yy = g->control_group->controls[1]->control_ref->State(); + yy -= g->control_group->controls[0]->control_ref->State(); - dc.SetPen(*wxGREY_PEN); - dc.SetBrush(*wxGREY_BRUSH); - DrawCoordinate(dc, xx, yy); - } + dc.SetPen(*wxGREY_PEN); + dc.SetBrush(*wxGREY_BRUSH); + DrawCoordinate(dc, xx, yy); + } - // adjusted dot - if (x != 0 || y != 0) - { - dc.SetPen(*wxRED_PEN); - dc.SetBrush(*wxRED_BRUSH); - // XXX: The adjusted values flip the Y axis to be in the format - // the Wii expects. Should this be in WiimoteEmu.cpp instead? - DrawCoordinate(dc, x, -y); - } - } - break; - case GROUP_TYPE_FORCE : - { - ControlState raw_dot[3]; - ControlState adj_dot[3]; - const ControlState deadzone = g->control_group->settings[0]->value; + // adjusted dot + if (x != 0 || y != 0) + { + dc.SetPen(*wxRED_PEN); + dc.SetBrush(*wxRED_BRUSH); + // XXX: The adjusted values flip the Y axis to be in the format + // the Wii expects. Should this be in WiimoteEmu.cpp instead? + DrawCoordinate(dc, x, -y); + } + } + break; + case GROUP_TYPE_FORCE: + { + ControlState raw_dot[3]; + ControlState adj_dot[3]; + const ControlState deadzone = g->control_group->settings[0]->value; - // adjusted - ((ControllerEmu::Force*)g->control_group)->GetState(adj_dot); + // adjusted + ((ControllerEmu::Force*)g->control_group)->GetState(adj_dot); - // raw - for (unsigned int i=0; i<3; ++i) - { - raw_dot[i] = (g->control_group->controls[i*2 + 1]->control_ref->State() - - g->control_group->controls[i*2]->control_ref->State()); - } + // raw + for (unsigned int i = 0; i < 3; ++i) + { + raw_dot[i] = (g->control_group->controls[i * 2 + 1]->control_ref->State() - + g->control_group->controls[i * 2]->control_ref->State()); + } - // deadzone rect for forward/backward visual - dc.SetBrush(*wxLIGHT_GREY_BRUSH); - dc.SetPen(*wxLIGHT_GREY_PEN); - int deadzone_height = deadzone * VIS_BITMAP_SIZE; - DrawCenteredRectangle(dc, 0, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE, deadzone_height); + // deadzone rect for forward/backward visual + dc.SetBrush(*wxLIGHT_GREY_BRUSH); + dc.SetPen(*wxLIGHT_GREY_PEN); + int deadzone_height = deadzone * VIS_BITMAP_SIZE; + DrawCenteredRectangle(dc, 0, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE, deadzone_height); #define LINE_HEIGHT 2 - int line_y; + int line_y; - // raw forward/background line - dc.SetPen(*wxGREY_PEN); - dc.SetBrush(*wxGREY_BRUSH); - line_y = VIS_COORD(raw_dot[2]); - DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, line_y, VIS_BITMAP_SIZE, LINE_HEIGHT); + // raw forward/background line + dc.SetPen(*wxGREY_PEN); + dc.SetBrush(*wxGREY_BRUSH); + line_y = VIS_COORD(raw_dot[2]); + DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, line_y, VIS_BITMAP_SIZE, LINE_HEIGHT); - // adjusted forward/background line - if (adj_dot[2] != 0.0) - { - dc.SetPen(*wxRED_PEN); - dc.SetBrush(*wxRED_BRUSH); - line_y = VIS_COORD(adj_dot[2]); - DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, line_y, VIS_BITMAP_SIZE, LINE_HEIGHT); - } + // adjusted forward/background line + if (adj_dot[2] != 0.0) + { + dc.SetPen(*wxRED_PEN); + dc.SetBrush(*wxRED_BRUSH); + line_y = VIS_COORD(adj_dot[2]); + DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, line_y, VIS_BITMAP_SIZE, LINE_HEIGHT); + } #define DEADZONE_RECT_SIZE 32 - // empty deadzone square - dc.SetBrush(*wxWHITE_BRUSH); - dc.SetPen(*wxLIGHT_GREY_PEN); - DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2, DEADZONE_RECT_SIZE, DEADZONE_RECT_SIZE); + // empty deadzone square + dc.SetBrush(*wxWHITE_BRUSH); + dc.SetPen(*wxLIGHT_GREY_PEN); + DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2, DEADZONE_RECT_SIZE, + DEADZONE_RECT_SIZE); - // deadzone square - dc.SetBrush(*wxLIGHT_GREY_BRUSH); - int dz_size = (deadzone * DEADZONE_RECT_SIZE); - DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2, dz_size, dz_size); + // deadzone square + dc.SetBrush(*wxLIGHT_GREY_BRUSH); + int dz_size = (deadzone * DEADZONE_RECT_SIZE); + DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2, dz_size, dz_size); - // raw dot - dc.SetPen(*wxGREY_PEN); - dc.SetBrush(*wxGREY_BRUSH); - DrawCoordinate(dc, raw_dot[1], raw_dot[0]); + // raw dot + dc.SetPen(*wxGREY_PEN); + dc.SetBrush(*wxGREY_BRUSH); + DrawCoordinate(dc, raw_dot[1], raw_dot[0]); - // adjusted dot - if (adj_dot[1] != 0 && adj_dot[0] != 0) - { - dc.SetPen(*wxRED_PEN); - dc.SetBrush(*wxRED_BRUSH); - DrawCoordinate(dc, adj_dot[1], adj_dot[0]); - } + // adjusted dot + if (adj_dot[1] != 0 && adj_dot[0] != 0) + { + dc.SetPen(*wxRED_PEN); + dc.SetBrush(*wxRED_BRUSH); + DrawCoordinate(dc, adj_dot[1], adj_dot[0]); + } + } + break; + case GROUP_TYPE_BUTTONS: + { + unsigned int button_count = ((unsigned int)g->control_group->controls.size()); - } - break; - case GROUP_TYPE_BUTTONS : - { - unsigned int button_count = ((unsigned int)g->control_group->controls.size()); + // draw the shit + dc.SetPen(*wxGREY_PEN); - // draw the shit - dc.SetPen(*wxGREY_PEN); + unsigned int* const bitmasks = new unsigned int[button_count]; + for (unsigned int n = 0; n < button_count; ++n) + bitmasks[n] = (1 << n); - unsigned int* const bitmasks = new unsigned int[button_count]; - for (unsigned int n = 0; ncontrol_group)->GetState(&buttons, bitmasks); - unsigned int buttons = 0; - ((ControllerEmu::Buttons*)g->control_group)->GetState(&buttons, bitmasks); + // Draw buttons in rows of 8 + for (unsigned int row = 0; row < ceil((float)button_count / 8.0f); row++) + { + unsigned int buttons_to_draw = 8; + if ((button_count - row * 8) <= 8) + buttons_to_draw = button_count - row * 8; - // Draw buttons in rows of 8 - for (unsigned int row = 0; row < ceil((float)button_count / 8.0f); row++) - { - unsigned int buttons_to_draw = 8; - if ((button_count - row * 8) <= 8) - buttons_to_draw = button_count - row * 8; + for (unsigned int n = 0; n < buttons_to_draw; ++n) + { + DrawButton(bitmasks, buttons, n, dc, g, row); + } + } - for (unsigned int n = 0; n < buttons_to_draw; ++n) - { - DrawButton(bitmasks, buttons, n, dc, g, row); - } - } + delete[] bitmasks; + } + break; + case GROUP_TYPE_TRIGGERS: + { + const unsigned int trigger_count = ((unsigned int)(g->control_group->controls.size())); - delete[] bitmasks; + // draw the shit + dc.SetPen(*wxGREY_PEN); + ControlState deadzone = g->control_group->settings[0]->value; - } - break; - case GROUP_TYPE_TRIGGERS : - { - const unsigned int trigger_count = ((unsigned int)(g->control_group->controls.size())); + ControlState* const trigs = new ControlState[trigger_count]; + ((ControllerEmu::Triggers*)g->control_group)->GetState(trigs); - // draw the shit - dc.SetPen(*wxGREY_PEN); - ControlState deadzone = g->control_group->settings[0]->value; + for (unsigned int n = 0; n < trigger_count; ++n) + { + ControlState trig_r = g->control_group->controls[n]->control_ref->State(); - ControlState* const trigs = new ControlState[trigger_count]; - ((ControllerEmu::Triggers*)g->control_group)->GetState(trigs); + // outline + dc.SetPen(*wxGREY_PEN); + dc.SetBrush(*wxWHITE_BRUSH); + dc.DrawRectangle(0, n * 12, 64, 14); - for (unsigned int n = 0; n < trigger_count; ++n) - { - ControlState trig_r = g->control_group->controls[n]->control_ref->State(); + // raw + dc.SetBrush(*wxGREY_BRUSH); + dc.DrawRectangle(0, n * 12, trig_r * 64, 14); - // outline - dc.SetPen(*wxGREY_PEN); - dc.SetBrush(*wxWHITE_BRUSH); - dc.DrawRectangle(0, n*12, 64, 14); + // deadzone affected + dc.SetBrush(*wxRED_BRUSH); + dc.DrawRectangle(0, n * 12, trigs[n] * 64, 14); - // raw - dc.SetBrush(*wxGREY_BRUSH); - dc.DrawRectangle(0, n*12, trig_r*64, 14); + // text + dc.DrawText(StrToWxStr(g->control_group->controls[n]->name), 3, n * 12 + 1); + } - // deadzone affected - dc.SetBrush(*wxRED_BRUSH); - dc.DrawRectangle(0, n*12, trigs[n]*64, 14); + delete[] trigs; - // text - dc.DrawText(StrToWxStr(g->control_group->controls[n]->name), 3, n*12 + 1); - } + // deadzone box + dc.SetPen(*wxLIGHT_GREY_PEN); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRectangle(0, 0, deadzone * 64, trigger_count * 14); + } + break; + case GROUP_TYPE_MIXED_TRIGGERS: + { + const unsigned int trigger_count = ((unsigned int)(g->control_group->controls.size() / 2)); - delete[] trigs; + // draw the shit + dc.SetPen(*wxGREY_PEN); + ControlState thresh = g->control_group->settings[0]->value; - // deadzone box - dc.SetPen(*wxLIGHT_GREY_PEN); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRectangle(0, 0, deadzone*64, trigger_count*14); + for (unsigned int n = 0; n < trigger_count; ++n) + { + dc.SetBrush(*wxRED_BRUSH); + ControlState trig_d = g->control_group->controls[n]->control_ref->State(); - } - break; - case GROUP_TYPE_MIXED_TRIGGERS : - { - const unsigned int trigger_count = ((unsigned int)(g->control_group->controls.size() / 2)); + ControlState trig_a = + trig_d > thresh ? 1 : g->control_group->controls[n + trigger_count]->control_ref->State(); - // draw the shit - dc.SetPen(*wxGREY_PEN); - ControlState thresh = g->control_group->settings[0]->value; + dc.DrawRectangle(0, n * 12, 64 + 20, 14); + if (trig_d <= thresh) + dc.SetBrush(*wxWHITE_BRUSH); + dc.DrawRectangle(trig_a * 64, n * 12, 64 + 20, 14); + dc.DrawRectangle(64, n * 12, 32, 14); - for (unsigned int n = 0; n < trigger_count; ++n) - { - dc.SetBrush(*wxRED_BRUSH); - ControlState trig_d = g->control_group->controls[n]->control_ref->State(); + // text + dc.DrawText(StrToWxStr(g->control_group->controls[n + trigger_count]->name), 3, n * 12 + 1); + dc.DrawText(StrToWxStr(std::string(1, g->control_group->controls[n]->name[0])), 64 + 3, + n * 12 + 1); + } - ControlState trig_a = trig_d > thresh ? 1 - : g->control_group->controls[n+trigger_count]->control_ref->State(); + // threshold box + dc.SetPen(*wxLIGHT_GREY_PEN); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRectangle(thresh * 64, 0, 128, trigger_count * 14); + } + break; + case GROUP_TYPE_SLIDER: + { + const ControlState deadzone = g->control_group->settings[0]->value; - dc.DrawRectangle(0, n*12, 64+20, 14); - if (trig_d <= thresh) - dc.SetBrush(*wxWHITE_BRUSH); - dc.DrawRectangle(trig_a*64, n*12, 64+20, 14); - dc.DrawRectangle(64, n*12, 32, 14); + ControlState state = g->control_group->controls[1]->control_ref->State() - + g->control_group->controls[0]->control_ref->State(); + dc.SetPen(*wxGREY_PEN); + dc.SetBrush(*wxGREY_BRUSH); + dc.DrawRectangle(31 + state * 30, 0, 2, 14); - // text - dc.DrawText(StrToWxStr(g->control_group->controls[n+trigger_count]->name), 3, n*12 + 1); - dc.DrawText(StrToWxStr(std::string(1, g->control_group->controls[n]->name[0])), 64 + 3, n*12 + 1); - } + ControlState adj_state; + ((ControllerEmu::Slider*)g->control_group)->GetState(&adj_state); + if (state) + { + dc.SetPen(*wxRED_PEN); + dc.SetBrush(*wxRED_BRUSH); + dc.DrawRectangle(31 + adj_state * 30, 0, 2, 14); + } - // threshold box - dc.SetPen(*wxLIGHT_GREY_PEN); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRectangle(thresh*64, 0, 128, trigger_count*14); - - } - break; - case GROUP_TYPE_SLIDER: - { - const ControlState deadzone = g->control_group->settings[0]->value; - - ControlState state = g->control_group->controls[1]->control_ref->State() - g->control_group->controls[0]->control_ref->State(); - dc.SetPen(*wxGREY_PEN); - dc.SetBrush(*wxGREY_BRUSH); - dc.DrawRectangle(31 + state * 30, 0, 2, 14); - - ControlState adj_state; - ((ControllerEmu::Slider*)g->control_group)->GetState(&adj_state); - if (state) - { - dc.SetPen(*wxRED_PEN); - dc.SetBrush(*wxRED_BRUSH); - dc.DrawRectangle(31 + adj_state * 30, 0, 2, 14); - } - - // deadzone box - dc.SetPen(*wxLIGHT_GREY_PEN); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRectangle(32 - deadzone * 32, 0, deadzone * 64, 14); - } - break; - default: - break; - } + // deadzone box + dc.SetPen(*wxLIGHT_GREY_PEN); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRectangle(32 - deadzone * 32, 0, deadzone * 64, 14); + } + break; + default: + break; + } } void InputConfigDialog::UpdateBitmaps(wxTimerEvent& WXUNUSED(event)) { - wxFont small_font(6, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD); + wxFont small_font(6, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD); - g_controller_interface.UpdateInput(); + g_controller_interface.UpdateInput(); - GamepadPage* const current_page = (GamepadPage*)m_pad_notebook->GetPage(m_pad_notebook->GetSelection()); + GamepadPage* const current_page = + (GamepadPage*)m_pad_notebook->GetPage(m_pad_notebook->GetSelection()); - for (ControlGroupBox* g : current_page->control_groups) - { - // if this control group has a bitmap - if (g->static_bitmap) - { - wxMemoryDC dc; - wxBitmap bitmap(g->static_bitmap->GetBitmap()); - dc.SelectObject(bitmap); - dc.Clear(); + for (ControlGroupBox* g : current_page->control_groups) + { + // if this control group has a bitmap + if (g->static_bitmap) + { + wxMemoryDC dc; + wxBitmap bitmap(g->static_bitmap->GetBitmap()); + dc.SelectObject(bitmap); + dc.Clear(); - dc.SetFont(small_font); - dc.SetTextForeground(0xC0C0C0); + dc.SetFont(small_font); + dc.SetTextForeground(0xC0C0C0); - DrawControlGroupBox(dc, g); + DrawControlGroupBox(dc, g); - // box outline - // Windows XP color - dc.SetPen(wxPen("#7f9db9")); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRectangle(0, 0, bitmap.GetWidth(), bitmap.GetHeight()); + // box outline + // Windows XP color + dc.SetPen(wxPen("#7f9db9")); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRectangle(0, 0, bitmap.GetWidth(), bitmap.GetHeight()); - // label for sticks and stuff - if (64 == bitmap.GetHeight()) - dc.DrawText(StrToWxStr(g->control_group->name).Upper(), 4, 2); + // label for sticks and stuff + if (64 == bitmap.GetHeight()) + dc.DrawText(StrToWxStr(g->control_group->name).Upper(), 4, 2); - dc.SelectObject(wxNullBitmap); - g->static_bitmap->SetBitmap(bitmap); - } - } + dc.SelectObject(wxNullBitmap); + g->static_bitmap->SetBitmap(bitmap); + } + } } diff --git a/Source/Core/DolphinWX/LogConfigWindow.cpp b/Source/Core/DolphinWX/LogConfigWindow.cpp index a8761daa59..d6c6b76860 100644 --- a/Source/Core/DolphinWX/LogConfigWindow.cpp +++ b/Source/Core/DolphinWX/LogConfigWindow.cpp @@ -21,228 +21,230 @@ #include "DolphinWX/WxUtils.h" LogConfigWindow::LogConfigWindow(wxWindow* parent, wxWindowID id) - : wxPanel(parent, id, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _("Log Configuration")) - , enableAll(true) + : wxPanel(parent, id, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, + _("Log Configuration")), + enableAll(true) { - SetMinSize(wxSize(100, 100)); - m_LogManager = LogManager::GetInstance(); - CreateGUIControls(); - LoadSettings(); + SetMinSize(wxSize(100, 100)); + m_LogManager = LogManager::GetInstance(); + CreateGUIControls(); + LoadSettings(); } LogConfigWindow::~LogConfigWindow() { - SaveSettings(); + SaveSettings(); } void LogConfigWindow::CreateGUIControls() { - // Verbosity - wxArrayString wxLevels, wxLevelsUse; - wxLevels.Add(_("Notice")); - wxLevels.Add(_("Error")); - wxLevels.Add(_("Warning")); - wxLevels.Add(_("Info")); - wxLevels.Add(_("Debug")); - for (int i = 0; i < MAX_LOGLEVEL; ++i) - wxLevelsUse.Add(wxLevels[i]); - m_verbosity = new wxRadioBox(this, wxID_ANY, _("Verbosity"), - wxDefaultPosition, wxDefaultSize, wxLevelsUse, 0, wxRA_SPECIFY_ROWS); - m_verbosity->Bind(wxEVT_RADIOBOX, &LogConfigWindow::OnVerbosityChange, this); + // Verbosity + wxArrayString wxLevels, wxLevelsUse; + wxLevels.Add(_("Notice")); + wxLevels.Add(_("Error")); + wxLevels.Add(_("Warning")); + wxLevels.Add(_("Info")); + wxLevels.Add(_("Debug")); + for (int i = 0; i < MAX_LOGLEVEL; ++i) + wxLevelsUse.Add(wxLevels[i]); + m_verbosity = new wxRadioBox(this, wxID_ANY, _("Verbosity"), wxDefaultPosition, wxDefaultSize, + wxLevelsUse, 0, wxRA_SPECIFY_ROWS); + m_verbosity->Bind(wxEVT_RADIOBOX, &LogConfigWindow::OnVerbosityChange, this); - // Options - m_writeFileCB = new wxCheckBox(this, wxID_ANY, _("Write to File")); - m_writeFileCB->Bind(wxEVT_CHECKBOX, &LogConfigWindow::OnWriteFileChecked, this); - m_writeConsoleCB = new wxCheckBox(this, wxID_ANY, _("Write to Console")); - m_writeConsoleCB->Bind(wxEVT_CHECKBOX, &LogConfigWindow::OnWriteConsoleChecked, this); - m_writeWindowCB = new wxCheckBox(this, wxID_ANY, _("Write to Window")); - m_writeWindowCB->Bind(wxEVT_CHECKBOX, &LogConfigWindow::OnWriteWindowChecked, this); + // Options + m_writeFileCB = new wxCheckBox(this, wxID_ANY, _("Write to File")); + m_writeFileCB->Bind(wxEVT_CHECKBOX, &LogConfigWindow::OnWriteFileChecked, this); + m_writeConsoleCB = new wxCheckBox(this, wxID_ANY, _("Write to Console")); + m_writeConsoleCB->Bind(wxEVT_CHECKBOX, &LogConfigWindow::OnWriteConsoleChecked, this); + m_writeWindowCB = new wxCheckBox(this, wxID_ANY, _("Write to Window")); + m_writeWindowCB->Bind(wxEVT_CHECKBOX, &LogConfigWindow::OnWriteWindowChecked, this); - wxButton *btn_toggle_all = new wxButton(this, wxID_ANY, _("Toggle All Log Types"), - wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - btn_toggle_all->Bind(wxEVT_BUTTON, &LogConfigWindow::OnToggleAll, this); - m_checks = new wxCheckListBox(this, wxID_ANY); - m_checks->Bind(wxEVT_CHECKLISTBOX, &LogConfigWindow::OnLogCheck, this); - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) - m_checks->Append(StrToWxStr(m_LogManager->GetFullName((LogTypes::LOG_TYPE)i))); + wxButton* btn_toggle_all = new wxButton(this, wxID_ANY, _("Toggle All Log Types"), + wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + btn_toggle_all->Bind(wxEVT_BUTTON, &LogConfigWindow::OnToggleAll, this); + m_checks = new wxCheckListBox(this, wxID_ANY); + m_checks->Bind(wxEVT_CHECKLISTBOX, &LogConfigWindow::OnLogCheck, this); + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) + m_checks->Append(StrToWxStr(m_LogManager->GetFullName((LogTypes::LOG_TYPE)i))); - // Sizers - wxStaticBoxSizer* sbOutputs = new wxStaticBoxSizer(wxVERTICAL, this, _("Logger Outputs")); - sbOutputs->Add(m_writeFileCB, 0, wxDOWN, 1); - sbOutputs->Add(m_writeConsoleCB, 0, wxDOWN, 1); - sbOutputs->Add(m_writeWindowCB, 0); + // Sizers + wxStaticBoxSizer* sbOutputs = new wxStaticBoxSizer(wxVERTICAL, this, _("Logger Outputs")); + sbOutputs->Add(m_writeFileCB, 0, wxDOWN, 1); + sbOutputs->Add(m_writeConsoleCB, 0, wxDOWN, 1); + sbOutputs->Add(m_writeWindowCB, 0); - wxStaticBoxSizer* sbLogTypes = new wxStaticBoxSizer(wxVERTICAL, this, _("Log Types")); - sbLogTypes->Add(m_checks, 1, wxEXPAND); + wxStaticBoxSizer* sbLogTypes = new wxStaticBoxSizer(wxVERTICAL, this, _("Log Types")); + sbLogTypes->Add(m_checks, 1, wxEXPAND); - wxBoxSizer *sMain = new wxBoxSizer(wxVERTICAL); - sMain->Add(m_verbosity, 0, wxEXPAND | wxLEFT | wxRIGHT, 5); - sMain->Add(sbOutputs, 0, wxEXPAND | wxLEFT | wxRIGHT, 5); - sMain->Add(btn_toggle_all, 0, wxEXPAND | wxLEFT | wxRIGHT, 5); - sMain->Add(sbLogTypes, 1, wxEXPAND | wxLEFT | wxRIGHT, 5); + wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); + sMain->Add(m_verbosity, 0, wxEXPAND | wxLEFT | wxRIGHT, 5); + sMain->Add(sbOutputs, 0, wxEXPAND | wxLEFT | wxRIGHT, 5); + sMain->Add(btn_toggle_all, 0, wxEXPAND | wxLEFT | wxRIGHT, 5); + sMain->Add(sbLogTypes, 1, wxEXPAND | wxLEFT | wxRIGHT, 5); - SetSizer(sMain); - Layout(); + SetSizer(sMain); + Layout(); } void LogConfigWindow::LoadSettings() { - IniFile ini; - ini.Load(File::GetUserPath(F_LOGGERCONFIG_IDX)); + IniFile ini; + ini.Load(File::GetUserPath(F_LOGGERCONFIG_IDX)); - IniFile::Section* options = ini.GetOrCreateSection("Options"); + IniFile::Section* options = ini.GetOrCreateSection("Options"); - // Retrieve the verbosity value from the config ini file. - int verbosity; - options->Get("Verbosity", &verbosity, 0); + // Retrieve the verbosity value from the config ini file. + int verbosity; + options->Get("Verbosity", &verbosity, 0); - // Ensure the verbosity level is valid. - if (verbosity < 1) - verbosity = 1; - if (verbosity > MAX_LOGLEVEL) - verbosity = MAX_LOGLEVEL; + // Ensure the verbosity level is valid. + if (verbosity < 1) + verbosity = 1; + if (verbosity > MAX_LOGLEVEL) + verbosity = MAX_LOGLEVEL; - // Actually set the logging verbosity. - m_verbosity->SetSelection(verbosity - 1); + // Actually set the logging verbosity. + m_verbosity->SetSelection(verbosity - 1); - // Get the logger output settings from the config ini file. - options->Get("WriteToFile", &m_writeFile, false); - m_writeFileCB->SetValue(m_writeFile); - options->Get("WriteToConsole", &m_writeConsole, true); - m_writeConsoleCB->SetValue(m_writeConsole); - options->Get("WriteToWindow", &m_writeWindow, true); - m_writeWindowCB->SetValue(m_writeWindow); + // Get the logger output settings from the config ini file. + options->Get("WriteToFile", &m_writeFile, false); + m_writeFileCB->SetValue(m_writeFile); + options->Get("WriteToConsole", &m_writeConsole, true); + m_writeConsoleCB->SetValue(m_writeConsole); + options->Get("WriteToWindow", &m_writeWindow, true); + m_writeWindowCB->SetValue(m_writeWindow); - // Run through all of the log types and check each checkbox for each logging type - // depending on its set value within the config ini. - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) - { - bool log_enabled; - ini.GetOrCreateSection("Logs")->Get(m_LogManager->GetShortName((LogTypes::LOG_TYPE)i), &log_enabled, false); + // Run through all of the log types and check each checkbox for each logging type + // depending on its set value within the config ini. + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) + { + bool log_enabled; + ini.GetOrCreateSection("Logs")->Get(m_LogManager->GetShortName((LogTypes::LOG_TYPE)i), + &log_enabled, false); - if (log_enabled) - enableAll = false; + if (log_enabled) + enableAll = false; - m_checks->Check(i, log_enabled); - } + m_checks->Check(i, log_enabled); + } } void LogConfigWindow::SaveSettings() { - IniFile ini; - ini.Load(File::GetUserPath(F_LOGGERCONFIG_IDX)); + IniFile ini; + ini.Load(File::GetUserPath(F_LOGGERCONFIG_IDX)); - IniFile::Section* options = ini.GetOrCreateSection("Options"); - options->Set("Verbosity", m_verbosity->GetSelection() + 1); - options->Set("WriteToFile", m_writeFile); - options->Set("WriteToConsole", m_writeConsole); - options->Set("WriteToWindow", m_writeWindow); + IniFile::Section* options = ini.GetOrCreateSection("Options"); + options->Set("Verbosity", m_verbosity->GetSelection() + 1); + options->Set("WriteToFile", m_writeFile); + options->Set("WriteToConsole", m_writeConsole); + options->Set("WriteToWindow", m_writeWindow); - // Save all enabled/disabled states of the log types to the config ini. - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) - { - ini.GetOrCreateSection("Logs")->Set(m_LogManager->GetShortName((LogTypes::LOG_TYPE)i), m_checks->IsChecked(i)); - } + // Save all enabled/disabled states of the log types to the config ini. + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) + { + ini.GetOrCreateSection("Logs")->Set(m_LogManager->GetShortName((LogTypes::LOG_TYPE)i), + m_checks->IsChecked(i)); + } - ini.Save(File::GetUserPath(F_LOGGERCONFIG_IDX)); + ini.Save(File::GetUserPath(F_LOGGERCONFIG_IDX)); } // If the verbosity changes while logging void LogConfigWindow::OnVerbosityChange(wxCommandEvent& event) { - // Get the new verbosity - int v = m_verbosity->GetSelection() + 1; + // Get the new verbosity + int v = m_verbosity->GetSelection() + 1; - // Set all log types to that verbosity level - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) - { - m_LogManager->SetLogLevel((LogTypes::LOG_TYPE)i, (LogTypes::LOG_LEVELS)v); - } + // Set all log types to that verbosity level + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) + { + m_LogManager->SetLogLevel((LogTypes::LOG_TYPE)i, (LogTypes::LOG_LEVELS)v); + } - event.Skip(); + event.Skip(); } void LogConfigWindow::OnWriteFileChecked(wxCommandEvent& event) { - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) - { - m_writeFile = event.IsChecked(); - if (m_checks->IsChecked(i)) - { - if (m_writeFile) - m_LogManager->AddListener((LogTypes::LOG_TYPE)i, LogListener::FILE_LISTENER); - else - m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, LogListener::FILE_LISTENER); - } - } + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) + { + m_writeFile = event.IsChecked(); + if (m_checks->IsChecked(i)) + { + if (m_writeFile) + m_LogManager->AddListener((LogTypes::LOG_TYPE)i, LogListener::FILE_LISTENER); + else + m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, LogListener::FILE_LISTENER); + } + } } void LogConfigWindow::OnWriteConsoleChecked(wxCommandEvent& event) { - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) - { - m_writeConsole = event.IsChecked(); - if (m_checks->IsChecked(i)) - { - if (m_writeConsole) - m_LogManager->AddListener((LogTypes::LOG_TYPE)i, LogListener::CONSOLE_LISTENER); - else - m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, LogListener::CONSOLE_LISTENER); - } - } + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) + { + m_writeConsole = event.IsChecked(); + if (m_checks->IsChecked(i)) + { + if (m_writeConsole) + m_LogManager->AddListener((LogTypes::LOG_TYPE)i, LogListener::CONSOLE_LISTENER); + else + m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, LogListener::CONSOLE_LISTENER); + } + } } void LogConfigWindow::OnWriteWindowChecked(wxCommandEvent& event) { - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) - { - m_writeWindow = event.IsChecked(); - if (m_checks->IsChecked(i)) - { - if (m_writeWindow) - m_LogManager->AddListener((LogTypes::LOG_TYPE)i, LogListener::LOG_WINDOW_LISTENER); - else - m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, LogListener::LOG_WINDOW_LISTENER); - } - } + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) + { + m_writeWindow = event.IsChecked(); + if (m_checks->IsChecked(i)) + { + if (m_writeWindow) + m_LogManager->AddListener((LogTypes::LOG_TYPE)i, LogListener::LOG_WINDOW_LISTENER); + else + m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, LogListener::LOG_WINDOW_LISTENER); + } + } } void LogConfigWindow::OnToggleAll(wxCommandEvent& WXUNUSED(event)) { - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) - ToggleLog(i, enableAll); + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) + ToggleLog(i, enableAll); - enableAll = !enableAll; + enableAll = !enableAll; } void LogConfigWindow::ToggleLog(int _logType, bool enable) { - LogTypes::LOG_TYPE logType = (LogTypes::LOG_TYPE)_logType; + LogTypes::LOG_TYPE logType = (LogTypes::LOG_TYPE)_logType; - m_checks->Check(_logType, enable); + m_checks->Check(_logType, enable); - m_LogManager->SetEnable(logType, enable); + m_LogManager->SetEnable(logType, enable); - if (enable) - { - if (m_writeWindow) - m_LogManager->AddListener(logType, LogListener::LOG_WINDOW_LISTENER); - if (m_writeFile) - m_LogManager->AddListener(logType, LogListener::FILE_LISTENER); - if (m_writeConsole) - m_LogManager->AddListener(logType, LogListener::CONSOLE_LISTENER); - } - else - { - m_LogManager->RemoveListener(logType, LogListener::LOG_WINDOW_LISTENER); - m_LogManager->RemoveListener(logType, LogListener::FILE_LISTENER); - m_LogManager->RemoveListener(logType, LogListener::CONSOLE_LISTENER); - } + if (enable) + { + if (m_writeWindow) + m_LogManager->AddListener(logType, LogListener::LOG_WINDOW_LISTENER); + if (m_writeFile) + m_LogManager->AddListener(logType, LogListener::FILE_LISTENER); + if (m_writeConsole) + m_LogManager->AddListener(logType, LogListener::CONSOLE_LISTENER); + } + else + { + m_LogManager->RemoveListener(logType, LogListener::LOG_WINDOW_LISTENER); + m_LogManager->RemoveListener(logType, LogListener::FILE_LISTENER); + m_LogManager->RemoveListener(logType, LogListener::CONSOLE_LISTENER); + } } void LogConfigWindow::OnLogCheck(wxCommandEvent& event) { - int i = event.GetInt(); - ToggleLog(i, m_checks->IsChecked(i)); + int i = event.GetInt(); + ToggleLog(i, m_checks->IsChecked(i)); } - diff --git a/Source/Core/DolphinWX/LogConfigWindow.h b/Source/Core/DolphinWX/LogConfigWindow.h index a2ec418f3d..f9a3a4806d 100644 --- a/Source/Core/DolphinWX/LogConfigWindow.h +++ b/Source/Core/DolphinWX/LogConfigWindow.h @@ -14,28 +14,28 @@ class wxRadioBox; class LogConfigWindow : public wxPanel { public: - LogConfigWindow(wxWindow* parent, wxWindowID id = wxID_ANY); - ~LogConfigWindow(); + LogConfigWindow(wxWindow* parent, wxWindowID id = wxID_ANY); + ~LogConfigWindow(); - void SaveSettings(); - void LoadSettings(); + void SaveSettings(); + void LoadSettings(); private: - LogManager *m_LogManager; - bool m_writeFile, m_writeConsole, m_writeWindow; - bool enableAll; + LogManager* m_LogManager; + bool m_writeFile, m_writeConsole, m_writeWindow; + bool enableAll; - // Controls - wxCheckBox *m_writeFileCB, *m_writeConsoleCB, *m_writeWindowCB; - wxCheckListBox* m_checks; - wxRadioBox *m_verbosity; + // Controls + wxCheckBox *m_writeFileCB, *m_writeConsoleCB, *m_writeWindowCB; + wxCheckListBox* m_checks; + wxRadioBox* m_verbosity; - void CreateGUIControls(); - void OnVerbosityChange(wxCommandEvent& event); - void OnWriteFileChecked(wxCommandEvent& event); - void OnWriteConsoleChecked(wxCommandEvent& event); - void OnWriteWindowChecked(wxCommandEvent& event); - void OnToggleAll(wxCommandEvent& event); - void ToggleLog(int _logType, bool enable); - void OnLogCheck(wxCommandEvent& event); + void CreateGUIControls(); + void OnVerbosityChange(wxCommandEvent& event); + void OnWriteFileChecked(wxCommandEvent& event); + void OnWriteConsoleChecked(wxCommandEvent& event); + void OnWriteWindowChecked(wxCommandEvent& event); + void OnToggleAll(wxCommandEvent& event); + void ToggleLog(int _logType, bool enable); + void OnLogCheck(wxCommandEvent& event); }; diff --git a/Source/Core/DolphinWX/LogWindow.cpp b/Source/Core/DolphinWX/LogWindow.cpp index 6622b42d38..940c647da1 100644 --- a/Source/Core/DolphinWX/LogWindow.cpp +++ b/Source/Core/DolphinWX/LogWindow.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -17,337 +18,340 @@ #include #include #include -#include #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/IniFile.h" #include "Common/Logging/ConsoleListener.h" #include "Common/Logging/LogManager.h" +#include "DolphinWX/Debugger/DebuggerUIUtil.h" #include "DolphinWX/Frame.h" #include "DolphinWX/LogWindow.h" #include "DolphinWX/WxUtils.h" -#include "DolphinWX/Debugger/DebuggerUIUtil.h" // Milliseconds between msgQueue flushes to wxTextCtrl #define UPDATETIME 200 // Max size of msgQueue, old messages will be discarded when there are too many. #define MSGQUEUE_MAX_SIZE 100 -CLogWindow::CLogWindow(CFrame *parent, wxWindowID id, const wxPoint& pos, - const wxSize& size, long style, const wxString& name) - : wxPanel(parent, id, pos, size, style, name) - , x(0), y(0), winpos(0) - , Parent(parent), m_LogAccess(true) - , m_Log(nullptr), m_cmdline(nullptr), m_FontChoice(nullptr) +CLogWindow::CLogWindow(CFrame* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, + long style, const wxString& name) + : wxPanel(parent, id, pos, size, style, name), x(0), y(0), winpos(0), Parent(parent), + m_LogAccess(true), m_Log(nullptr), m_cmdline(nullptr), m_FontChoice(nullptr) { - Bind(wxEVT_CLOSE_WINDOW, &CLogWindow::OnClose, this); - Bind(wxEVT_TIMER, &CLogWindow::OnLogTimer, this); + Bind(wxEVT_CLOSE_WINDOW, &CLogWindow::OnClose, this); + Bind(wxEVT_TIMER, &CLogWindow::OnLogTimer, this); - m_LogManager = LogManager::GetInstance(); - m_LogManager->RegisterListener(LogListener::LOG_WINDOW_LISTENER, this); + m_LogManager = LogManager::GetInstance(); + m_LogManager->RegisterListener(LogListener::LOG_WINDOW_LISTENER, this); - CreateGUIControls(); + CreateGUIControls(); - m_LogTimer.SetOwner(this); - m_LogTimer.Start(UPDATETIME); + m_LogTimer.SetOwner(this); + m_LogTimer.Start(UPDATETIME); } void CLogWindow::CreateGUIControls() { - IniFile ini; - ini.Load(File::GetUserPath(F_LOGGERCONFIG_IDX)); + IniFile ini; + ini.Load(File::GetUserPath(F_LOGGERCONFIG_IDX)); - IniFile::Section* options = ini.GetOrCreateSection("Options"); - IniFile::Section* log_window = ini.GetOrCreateSection("LogWindow"); - log_window->Get("x", &x, Parent->GetSize().GetX() / 2); - log_window->Get("y", &y, Parent->GetSize().GetY()); - log_window->Get("pos", &winpos, wxAUI_DOCK_RIGHT); + IniFile::Section* options = ini.GetOrCreateSection("Options"); + IniFile::Section* log_window = ini.GetOrCreateSection("LogWindow"); + log_window->Get("x", &x, Parent->GetSize().GetX() / 2); + log_window->Get("y", &y, Parent->GetSize().GetY()); + log_window->Get("pos", &winpos, wxAUI_DOCK_RIGHT); - // Set up log listeners - int verbosity; - options->Get("Verbosity", &verbosity, 0); + // Set up log listeners + int verbosity; + options->Get("Verbosity", &verbosity, 0); - // Ensure the verbosity level is valid - if (verbosity < 1) - verbosity = 1; - if (verbosity > MAX_LOGLEVEL) - verbosity = MAX_LOGLEVEL; + // Ensure the verbosity level is valid + if (verbosity < 1) + verbosity = 1; + if (verbosity > MAX_LOGLEVEL) + verbosity = MAX_LOGLEVEL; - // Get the logger output settings from the config ini file. - options->Get("WriteToFile", &m_writeFile, false); - options->Get("WriteToWindow", &m_writeWindow, true); + // Get the logger output settings from the config ini file. + options->Get("WriteToFile", &m_writeFile, false); + options->Get("WriteToWindow", &m_writeWindow, true); - IniFile::Section* logs = ini.GetOrCreateSection("Logs"); - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) - { - bool enable; - logs->Get(m_LogManager->GetShortName((LogTypes::LOG_TYPE)i), &enable, false); + IniFile::Section* logs = ini.GetOrCreateSection("Logs"); + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) + { + bool enable; + logs->Get(m_LogManager->GetShortName((LogTypes::LOG_TYPE)i), &enable, false); - if (m_writeWindow && enable) - m_LogManager->AddListener((LogTypes::LOG_TYPE)i, LogListener::LOG_WINDOW_LISTENER); - else - m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, LogListener::LOG_WINDOW_LISTENER); + if (m_writeWindow && enable) + m_LogManager->AddListener((LogTypes::LOG_TYPE)i, LogListener::LOG_WINDOW_LISTENER); + else + m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, LogListener::LOG_WINDOW_LISTENER); - if (m_writeFile && enable) - m_LogManager->AddListener((LogTypes::LOG_TYPE)i, LogListener::FILE_LISTENER); - else - m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, LogListener::FILE_LISTENER); + if (m_writeFile && enable) + m_LogManager->AddListener((LogTypes::LOG_TYPE)i, LogListener::FILE_LISTENER); + else + m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, LogListener::FILE_LISTENER); - m_LogManager->SetLogLevel((LogTypes::LOG_TYPE)i, (LogTypes::LOG_LEVELS)(verbosity)); - } + m_LogManager->SetLogLevel((LogTypes::LOG_TYPE)i, (LogTypes::LOG_LEVELS)(verbosity)); + } - // Font - m_FontChoice = new wxChoice(this, wxID_ANY); - m_FontChoice->Bind(wxEVT_CHOICE, &CLogWindow::OnFontChange, this); - m_FontChoice->Append(_("Default font")); - m_FontChoice->Append(_("Monospaced font")); - m_FontChoice->Append(_("Selected font")); + // Font + m_FontChoice = new wxChoice(this, wxID_ANY); + m_FontChoice->Bind(wxEVT_CHOICE, &CLogWindow::OnFontChange, this); + m_FontChoice->Append(_("Default font")); + m_FontChoice->Append(_("Monospaced font")); + m_FontChoice->Append(_("Selected font")); - DefaultFont = GetFont(); - MonoSpaceFont.SetNativeFontInfoUserDesc("lucida console windows-1252"); - LogFont.push_back(DefaultFont); - LogFont.push_back(MonoSpaceFont); - LogFont.push_back(DebuggerFont); + DefaultFont = GetFont(); + MonoSpaceFont.SetNativeFontInfoUserDesc("lucida console windows-1252"); + LogFont.push_back(DefaultFont); + LogFont.push_back(MonoSpaceFont); + LogFont.push_back(DebuggerFont); - int font; - options->Get("Font", &font, 0); - m_FontChoice->SetSelection(font); + int font; + options->Get("Font", &font, 0); + m_FontChoice->SetSelection(font); - // Word wrap - bool wrap_lines; - options->Get("WrapLines", &wrap_lines, false); - m_WrapLine = new wxCheckBox(this, wxID_ANY, _("Word Wrap")); - m_WrapLine->Bind(wxEVT_CHECKBOX, &CLogWindow::OnWrapLineCheck, this); - m_WrapLine->SetValue(wrap_lines); + // Word wrap + bool wrap_lines; + options->Get("WrapLines", &wrap_lines, false); + m_WrapLine = new wxCheckBox(this, wxID_ANY, _("Word Wrap")); + m_WrapLine->Bind(wxEVT_CHECKBOX, &CLogWindow::OnWrapLineCheck, this); + m_WrapLine->SetValue(wrap_lines); - // Log viewer - m_Log = CreateTextCtrl(this, wxID_ANY, wxTE_RICH | wxTE_MULTILINE | wxTE_READONLY | - (wrap_lines ? wxTE_WORDWRAP : wxTE_DONTWRAP)); + // Log viewer + m_Log = CreateTextCtrl(this, wxID_ANY, wxTE_RICH | wxTE_MULTILINE | wxTE_READONLY | + (wrap_lines ? wxTE_WORDWRAP : wxTE_DONTWRAP)); - // submit row - m_cmdline = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, - wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB); + // submit row + m_cmdline = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, + wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB); - // Clear log button - m_clear_log_btn = new wxButton(this, wxID_ANY, _("Clear"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - m_clear_log_btn->Bind(wxEVT_BUTTON, &CLogWindow::OnClear, this); + // Clear log button + m_clear_log_btn = + new wxButton(this, wxID_ANY, _("Clear"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + m_clear_log_btn->Bind(wxEVT_BUTTON, &CLogWindow::OnClear, this); - // Sizers - wxBoxSizer* sTop = new wxBoxSizer(wxHORIZONTAL); - sTop->Add(m_clear_log_btn); - sTop->Add(m_FontChoice, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 3); - sTop->Add(m_WrapLine, 0, wxALIGN_CENTER_VERTICAL); + // Sizers + wxBoxSizer* sTop = new wxBoxSizer(wxHORIZONTAL); + sTop->Add(m_clear_log_btn); + sTop->Add(m_FontChoice, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 3); + sTop->Add(m_WrapLine, 0, wxALIGN_CENTER_VERTICAL); - sBottom = new wxBoxSizer(wxVERTICAL); - PopulateBottom(); + sBottom = new wxBoxSizer(wxVERTICAL); + PopulateBottom(); - wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); - sMain->Add(sTop, 0, wxEXPAND); - sMain->Add(sBottom, 1, wxEXPAND); - SetSizer(sMain); + wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); + sMain->Add(sTop, 0, wxEXPAND); + sMain->Add(sBottom, 1, wxEXPAND); + SetSizer(sMain); - m_cmdline->SetFocus(); + m_cmdline->SetFocus(); } CLogWindow::~CLogWindow() { - for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) - { - m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, LogListener::LOG_WINDOW_LISTENER); - } + for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) + { + m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, LogListener::LOG_WINDOW_LISTENER); + } } void CLogWindow::OnClose(wxCloseEvent& event) { - SaveSettings(); - event.Skip(); + SaveSettings(); + event.Skip(); } void CLogWindow::SaveSettings() { - IniFile ini; - ini.Load(File::GetUserPath(F_LOGGERCONFIG_IDX)); + IniFile ini; + ini.Load(File::GetUserPath(F_LOGGERCONFIG_IDX)); - if (!Parent->g_pCodeWindow) - { - IniFile::Section* log_window = ini.GetOrCreateSection("LogWindow"); - log_window->Set("x", x); - log_window->Set("y", y); - log_window->Set("pos", winpos); - } + if (!Parent->g_pCodeWindow) + { + IniFile::Section* log_window = ini.GetOrCreateSection("LogWindow"); + log_window->Set("x", x); + log_window->Set("y", y); + log_window->Set("pos", winpos); + } - IniFile::Section* options = ini.GetOrCreateSection("Options"); - options->Set("Font", m_FontChoice->GetSelection()); - options->Set("WrapLines", m_WrapLine->IsChecked()); + IniFile::Section* options = ini.GetOrCreateSection("Options"); + options->Set("Font", m_FontChoice->GetSelection()); + options->Set("WrapLines", m_WrapLine->IsChecked()); - ini.Save(File::GetUserPath(F_LOGGERCONFIG_IDX)); + ini.Save(File::GetUserPath(F_LOGGERCONFIG_IDX)); } -void CLogWindow::OnClear(wxCommandEvent& WXUNUSED (event)) +void CLogWindow::OnClear(wxCommandEvent& WXUNUSED(event)) { - m_Log->Clear(); + m_Log->Clear(); - { - std::lock_guard lk(m_LogSection); - while (!msgQueue.empty()) - msgQueue.pop(); - } + { + std::lock_guard lk(m_LogSection); + while (!msgQueue.empty()) + msgQueue.pop(); + } } void CLogWindow::UnPopulateBottom() { - sBottom->Detach(m_Log); - sBottom->Detach(m_cmdline); + sBottom->Detach(m_Log); + sBottom->Detach(m_cmdline); } void CLogWindow::PopulateBottom() { - sBottom->Add(m_Log, 1, wxEXPAND | wxSHRINK); - sBottom->Add(m_cmdline, 0, wxEXPAND); - Layout(); + sBottom->Add(m_Log, 1, wxEXPAND | wxSHRINK); + sBottom->Add(m_cmdline, 0, wxEXPAND); + Layout(); } wxTextCtrl* CLogWindow::CreateTextCtrl(wxPanel* parent, wxWindowID id, long Style) { - wxTextCtrl* TC = new wxTextCtrl(parent, id, wxEmptyString, wxDefaultPosition, wxDefaultSize, Style); + wxTextCtrl* TC = + new wxTextCtrl(parent, id, wxEmptyString, wxDefaultPosition, wxDefaultSize, Style); #ifdef __APPLE__ - TC->SetBackgroundColour(*wxLIGHT_GREY); + TC->SetBackgroundColour(*wxLIGHT_GREY); #else - TC->SetBackgroundColour(*wxBLACK); + TC->SetBackgroundColour(*wxBLACK); #endif - if (m_FontChoice && m_FontChoice->GetSelection() < (int)LogFont.size() && m_FontChoice->GetSelection() >= 0) - TC->SetDefaultStyle(wxTextAttr(wxNullColour, wxNullColour, LogFont[m_FontChoice->GetSelection()])); + if (m_FontChoice && m_FontChoice->GetSelection() < (int)LogFont.size() && + m_FontChoice->GetSelection() >= 0) + TC->SetDefaultStyle( + wxTextAttr(wxNullColour, wxNullColour, LogFont[m_FontChoice->GetSelection()])); - return TC; + return TC; } void CLogWindow::OnFontChange(wxCommandEvent& event) { - // Update selected font - LogFont[LogFont.size()-1] = DebuggerFont; - m_Log->SetStyle(0, m_Log->GetLastPosition(), - wxTextAttr(wxNullColour, wxNullColour, LogFont[event.GetSelection()])); - m_Log->SetDefaultStyle(wxTextAttr(wxNullColour, wxNullColour, LogFont[event.GetSelection()])); + // Update selected font + LogFont[LogFont.size() - 1] = DebuggerFont; + m_Log->SetStyle(0, m_Log->GetLastPosition(), + wxTextAttr(wxNullColour, wxNullColour, LogFont[event.GetSelection()])); + m_Log->SetDefaultStyle(wxTextAttr(wxNullColour, wxNullColour, LogFont[event.GetSelection()])); - SaveSettings(); + SaveSettings(); } void CLogWindow::OnWrapLineCheck(wxCommandEvent& event) { #ifdef __WXGTK__ - // Clear the old word wrap state and set the new - m_Log->SetWindowStyleFlag(m_Log->GetWindowStyleFlag() ^ (wxTE_WORDWRAP | wxTE_DONTWRAP)); + // Clear the old word wrap state and set the new + m_Log->SetWindowStyleFlag(m_Log->GetWindowStyleFlag() ^ (wxTE_WORDWRAP | wxTE_DONTWRAP)); #else - wxString Text; - // Unfortunately wrapping styles can only be changed dynamically with wxGTK - // Notice: To retain the colors when changing word wrapping we need to - // loop through every letter with GetStyle and then reapply them letter by letter - // Prevent m_Log access while it's being destroyed - m_LogAccess = false; - UnPopulateBottom(); - Text = m_Log->GetValue(); - m_Log->Destroy(); - if (event.IsChecked()) - m_Log = CreateTextCtrl(this, wxID_ANY, wxTE_RICH | wxTE_MULTILINE | wxTE_READONLY | wxTE_WORDWRAP); - else - m_Log = CreateTextCtrl(this, wxID_ANY, wxTE_RICH | wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP); - m_Log->SetDefaultStyle(wxTextAttr(*wxWHITE)); - m_Log->AppendText(Text); - PopulateBottom(); - m_LogAccess = true; + wxString Text; + // Unfortunately wrapping styles can only be changed dynamically with wxGTK + // Notice: To retain the colors when changing word wrapping we need to + // loop through every letter with GetStyle and then reapply them letter by letter + // Prevent m_Log access while it's being destroyed + m_LogAccess = false; + UnPopulateBottom(); + Text = m_Log->GetValue(); + m_Log->Destroy(); + if (event.IsChecked()) + m_Log = + CreateTextCtrl(this, wxID_ANY, wxTE_RICH | wxTE_MULTILINE | wxTE_READONLY | wxTE_WORDWRAP); + else + m_Log = + CreateTextCtrl(this, wxID_ANY, wxTE_RICH | wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP); + m_Log->SetDefaultStyle(wxTextAttr(*wxWHITE)); + m_Log->AppendText(Text); + PopulateBottom(); + m_LogAccess = true; #endif - SaveSettings(); + SaveSettings(); } void CLogWindow::OnLogTimer(wxTimerEvent& WXUNUSED(event)) { - if (!m_LogAccess) - return; + if (!m_LogAccess) + return; - UpdateLog(); + UpdateLog(); - // Scroll to the last line - if (!msgQueue.empty()) - { - m_Log->ScrollLines(1); - m_Log->ShowPosition( m_Log->GetLastPosition() ); - } + // Scroll to the last line + if (!msgQueue.empty()) + { + m_Log->ScrollLines(1); + m_Log->ShowPosition(m_Log->GetLastPosition()); + } } void CLogWindow::UpdateLog() { - if (!m_LogAccess || !m_Log || msgQueue.empty()) - return; + if (!m_LogAccess || !m_Log || msgQueue.empty()) + return; - m_LogTimer.Stop(); + m_LogTimer.Stop(); - // This function runs on the main gui thread, and needs to finish in a finite time otherwise - // the GUI will lock up, which could be an issue if new messages are flooding in faster than - // this function can render them to the screen. - // So we limit this function to processing MSGQUEUE_MAX_SIZE messages each time it's called. - for (int num = 0; num < MSGQUEUE_MAX_SIZE; num++) - { - u8 log_level; - wxString log_msg; + // This function runs on the main gui thread, and needs to finish in a finite time otherwise + // the GUI will lock up, which could be an issue if new messages are flooding in faster than + // this function can render them to the screen. + // So we limit this function to processing MSGQUEUE_MAX_SIZE messages each time it's called. + for (int num = 0; num < MSGQUEUE_MAX_SIZE; num++) + { + u8 log_level; + wxString log_msg; - // We can't hold this mutex while calling Wx functions, due to deadlocks - { - std::lock_guard lk(m_LogSection); + // We can't hold this mutex while calling Wx functions, due to deadlocks + { + std::lock_guard lk(m_LogSection); - if (msgQueue.empty()) - break; + if (msgQueue.empty()) + break; - log_level = msgQueue.front().first; - log_msg = std::move(msgQueue.front().second); - msgQueue.pop(); - } + log_level = msgQueue.front().first; + log_msg = std::move(msgQueue.front().second); + msgQueue.pop(); + } - switch (log_level) - { - case LogTypes::LOG_LEVELS::LERROR: - m_Log->SetDefaultStyle(wxTextAttr(*wxRED)); - break; + switch (log_level) + { + case LogTypes::LOG_LEVELS::LERROR: + m_Log->SetDefaultStyle(wxTextAttr(*wxRED)); + break; - case LogTypes::LOG_LEVELS::LWARNING: - m_Log->SetDefaultStyle(wxTextAttr(*wxYELLOW)); - break; + case LogTypes::LOG_LEVELS::LWARNING: + m_Log->SetDefaultStyle(wxTextAttr(*wxYELLOW)); + break; - case LogTypes::LOG_LEVELS::LNOTICE: - m_Log->SetDefaultStyle(wxTextAttr(*wxGREEN)); - break; + case LogTypes::LOG_LEVELS::LNOTICE: + m_Log->SetDefaultStyle(wxTextAttr(*wxGREEN)); + break; - case LogTypes::LOG_LEVELS::LINFO: - m_Log->SetDefaultStyle(wxTextAttr(*wxCYAN)); - break; + case LogTypes::LOG_LEVELS::LINFO: + m_Log->SetDefaultStyle(wxTextAttr(*wxCYAN)); + break; - case LogTypes::LOG_LEVELS::LDEBUG: - m_Log->SetDefaultStyle(wxTextAttr(*wxLIGHT_GREY)); - break; + case LogTypes::LOG_LEVELS::LDEBUG: + m_Log->SetDefaultStyle(wxTextAttr(*wxLIGHT_GREY)); + break; - default: - m_Log->SetDefaultStyle(wxTextAttr(*wxWHITE)); - break; - } + default: + m_Log->SetDefaultStyle(wxTextAttr(*wxWHITE)); + break; + } - if (log_msg.size()) - { - int i = m_Log->GetLastPosition(); - m_Log->AppendText(log_msg); - // White timestamp - m_Log->SetStyle(i, i + 9, wxTextAttr(*wxWHITE)); - } - } + if (log_msg.size()) + { + int i = m_Log->GetLastPosition(); + m_Log->AppendText(log_msg); + // White timestamp + m_Log->SetStyle(i, i + 9, wxTextAttr(*wxWHITE)); + } + } - m_LogTimer.Start(); + m_LogTimer.Start(); } -void CLogWindow::Log(LogTypes::LOG_LEVELS level, const char *text) +void CLogWindow::Log(LogTypes::LOG_LEVELS level, const char* text) { - std::lock_guard lk(m_LogSection); + std::lock_guard lk(m_LogSection); - if (msgQueue.size() >= MSGQUEUE_MAX_SIZE) - msgQueue.pop(); + if (msgQueue.size() >= MSGQUEUE_MAX_SIZE) + msgQueue.pop(); - msgQueue.push(std::make_pair(u8(level), StrToWxStr(text))); + msgQueue.push(std::make_pair(u8(level), StrToWxStr(text))); } diff --git a/Source/Core/DolphinWX/LogWindow.h b/Source/Core/DolphinWX/LogWindow.h index cbd8f26cb2..c3236acd3e 100644 --- a/Source/Core/DolphinWX/LogWindow.h +++ b/Source/Core/DolphinWX/LogWindow.h @@ -25,47 +25,43 @@ class wxTextCtrl; class CLogWindow : public wxPanel, LogListener { public: - CLogWindow(CFrame* parent, - wxWindowID id = wxID_ANY, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxTAB_TRAVERSAL, - const wxString& name = _("Log") - ); - ~CLogWindow(); + CLogWindow(CFrame* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL, + const wxString& name = _("Log")); + ~CLogWindow(); - void SaveSettings(); - void Log(LogTypes::LOG_LEVELS, const char *text) override; + void SaveSettings(); + void Log(LogTypes::LOG_LEVELS, const char* text) override; - int x, y, winpos; + int x, y, winpos; private: - CFrame* Parent; - wxFont DefaultFont, MonoSpaceFont; - std::vector LogFont; - wxTimer m_LogTimer; - LogManager* m_LogManager; - std::queue > msgQueue; - bool m_writeFile, m_writeWindow, m_LogAccess; + CFrame* Parent; + wxFont DefaultFont, MonoSpaceFont; + std::vector LogFont; + wxTimer m_LogTimer; + LogManager* m_LogManager; + std::queue> msgQueue; + bool m_writeFile, m_writeWindow, m_LogAccess; - // Controls - wxBoxSizer* sBottom; - wxTextCtrl* m_Log; - wxTextCtrl* m_cmdline; - wxChoice* m_FontChoice; - wxCheckBox* m_WrapLine; - wxButton* m_clear_log_btn; + // Controls + wxBoxSizer* sBottom; + wxTextCtrl* m_Log; + wxTextCtrl* m_cmdline; + wxChoice* m_FontChoice; + wxCheckBox* m_WrapLine; + wxButton* m_clear_log_btn; - std::mutex m_LogSection; + std::mutex m_LogSection; - wxTextCtrl* CreateTextCtrl(wxPanel* parent, wxWindowID id, long Style); - void CreateGUIControls(); - void PopulateBottom(); - void UnPopulateBottom(); - void OnClose(wxCloseEvent& event); - void OnFontChange(wxCommandEvent& event); - void OnWrapLineCheck(wxCommandEvent& event); - void OnClear(wxCommandEvent& event); - void OnLogTimer(wxTimerEvent& WXUNUSED(event)); - void UpdateLog(); + wxTextCtrl* CreateTextCtrl(wxPanel* parent, wxWindowID id, long Style); + void CreateGUIControls(); + void PopulateBottom(); + void UnPopulateBottom(); + void OnClose(wxCloseEvent& event); + void OnFontChange(wxCommandEvent& event); + void OnWrapLineCheck(wxCommandEvent& event); + void OnClear(wxCommandEvent& event); + void OnLogTimer(wxTimerEvent& WXUNUSED(event)); + void UpdateLog(); }; diff --git a/Source/Core/DolphinWX/Main.cpp b/Source/Core/DolphinWX/Main.cpp index 6b9599bdcf..81df10255b 100644 --- a/Source/Core/DolphinWX/Main.cpp +++ b/Source/Core/DolphinWX/Main.cpp @@ -20,30 +20,30 @@ #include #include +#include "Common/CPUDetect.h" #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" -#include "Common/CPUDetect.h" #include "Common/FileUtil.h" #include "Common/IniFile.h" -#include "Common/Thread.h" #include "Common/Logging/LogManager.h" +#include "Common/Thread.h" #include "Core/Analytics.h" #include "Core/ConfigManager.h" #include "Core/Core.h" +#include "Core/HW/Wiimote.h" #include "Core/Host.h" #include "Core/Movie.h" -#include "Core/HW/Wiimote.h" +#include "DolphinWX/Debugger/CodeWindow.h" +#include "DolphinWX/Debugger/JitWindow.h" #include "DolphinWX/Frame.h" #include "DolphinWX/Globals.h" #include "DolphinWX/Main.h" +#include "DolphinWX/NetPlay/NetWindow.h" #include "DolphinWX/SoftwareVideoConfigDialog.h" #include "DolphinWX/VideoConfigDiag.h" #include "DolphinWX/WxUtils.h" -#include "DolphinWX/Debugger/CodeWindow.h" -#include "DolphinWX/Debugger/JitWindow.h" -#include "DolphinWX/NetPlay/NetWindow.h" #include "UICommon/UICommon.h" @@ -82,316 +82,284 @@ class wxFrame; IMPLEMENT_APP(DolphinApp) bool wxMsgAlert(const char*, const char*, bool, int); -std::string wxStringTranslator(const char *); +std::string wxStringTranslator(const char*); CFrame* main_frame = nullptr; -bool DolphinApp::Initialize(int& c, wxChar **v) +bool DolphinApp::Initialize(int& c, wxChar** v) { #if defined HAVE_X11 && HAVE_X11 - XInitThreads(); + XInitThreads(); #endif - return wxApp::Initialize(c, v); + return wxApp::Initialize(c, v); } // The 'main program' equivalent that creates the main window and return the main frame bool DolphinApp::OnInit() { - if (!wxApp::OnInit()) - return false; + if (!wxApp::OnInit()) + return false; - Bind(wxEVT_QUERY_END_SESSION, &DolphinApp::OnEndSession, this); - Bind(wxEVT_END_SESSION, &DolphinApp::OnEndSession, this); - Bind(wxEVT_IDLE, &DolphinApp::OnIdle, this); + Bind(wxEVT_QUERY_END_SESSION, &DolphinApp::OnEndSession, this); + Bind(wxEVT_END_SESSION, &DolphinApp::OnEndSession, this); + Bind(wxEVT_IDLE, &DolphinApp::OnIdle, this); - // Register message box and translation handlers - RegisterMsgAlertHandler(&wxMsgAlert); - RegisterStringTranslator(&wxStringTranslator); + // Register message box and translation handlers + RegisterMsgAlertHandler(&wxMsgAlert); + RegisterStringTranslator(&wxStringTranslator); #if wxUSE_ON_FATAL_EXCEPTION - wxHandleFatalExceptions(true); + wxHandleFatalExceptions(true); #endif - UICommon::SetUserDirectory(m_user_path.ToStdString()); - UICommon::CreateDirectories(); - InitLanguageSupport(); // The language setting is loaded from the user directory - UICommon::Init(); + UICommon::SetUserDirectory(m_user_path.ToStdString()); + UICommon::CreateDirectories(); + InitLanguageSupport(); // The language setting is loaded from the user directory + UICommon::Init(); - if (m_select_video_backend && !m_video_backend_name.empty()) - SConfig::GetInstance().m_strVideoBackend = WxStrToStr(m_video_backend_name); + if (m_select_video_backend && !m_video_backend_name.empty()) + SConfig::GetInstance().m_strVideoBackend = WxStrToStr(m_video_backend_name); - if (m_select_audio_emulation) - SConfig::GetInstance().bDSPHLE = (m_audio_emulation_name.Upper() == "HLE"); + if (m_select_audio_emulation) + SConfig::GetInstance().bDSPHLE = (m_audio_emulation_name.Upper() == "HLE"); - VideoBackendBase::ActivateBackend(SConfig::GetInstance().m_strVideoBackend); + VideoBackendBase::ActivateBackend(SConfig::GetInstance().m_strVideoBackend); - DolphinAnalytics::Instance()->ReportDolphinStart("wx"); + DolphinAnalytics::Instance()->ReportDolphinStart("wx"); - // Enable the PNG image handler for screenshots - wxImage::AddHandler(new wxPNGHandler); + // Enable the PNG image handler for screenshots + wxImage::AddHandler(new wxPNGHandler); - int x = SConfig::GetInstance().iPosX; - int y = SConfig::GetInstance().iPosY; - int w = SConfig::GetInstance().iWidth; - int h = SConfig::GetInstance().iHeight; + int x = SConfig::GetInstance().iPosX; + int y = SConfig::GetInstance().iPosY; + int w = SConfig::GetInstance().iWidth; + int h = SConfig::GetInstance().iHeight; - // The following is not needed with X11, where window managers - // do not allow windows to be created off the desktop. +// The following is not needed with X11, where window managers +// do not allow windows to be created off the desktop. #ifdef _WIN32 - // Out of desktop check - int leftPos = GetSystemMetrics(SM_XVIRTUALSCREEN); - int topPos = GetSystemMetrics(SM_YVIRTUALSCREEN); - int width = GetSystemMetrics(SM_CXVIRTUALSCREEN); - int height = GetSystemMetrics(SM_CYVIRTUALSCREEN); - if ((leftPos + width) < (x + w) || leftPos > x || (topPos + height) < (y + h) || topPos > y) - x = y = wxDefaultCoord; + // Out of desktop check + int leftPos = GetSystemMetrics(SM_XVIRTUALSCREEN); + int topPos = GetSystemMetrics(SM_YVIRTUALSCREEN); + int width = GetSystemMetrics(SM_CXVIRTUALSCREEN); + int height = GetSystemMetrics(SM_CYVIRTUALSCREEN); + if ((leftPos + width) < (x + w) || leftPos > x || (topPos + height) < (y + h) || topPos > y) + x = y = wxDefaultCoord; #elif defined __APPLE__ - if (y < 1) - y = wxDefaultCoord; + if (y < 1) + y = wxDefaultCoord; #endif - main_frame = new CFrame(nullptr, wxID_ANY, - StrToWxStr(scm_rev_str), - wxPoint(x, y), wxSize(w, h), - m_use_debugger, m_batch_mode, m_use_logger); + main_frame = new CFrame(nullptr, wxID_ANY, StrToWxStr(scm_rev_str), wxPoint(x, y), wxSize(w, h), + m_use_debugger, m_batch_mode, m_use_logger); - SetTopWindow(main_frame); - main_frame->SetMinSize(wxSize(400, 300)); + SetTopWindow(main_frame); + main_frame->SetMinSize(wxSize(400, 300)); - AfterInit(); + AfterInit(); - return true; + return true; } void DolphinApp::OnInitCmdLine(wxCmdLineParser& parser) { - static const wxCmdLineEntryDesc desc[] = - { - { - wxCMD_LINE_SWITCH, "h", "help", - "Show this help message", - wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP - }, - { - wxCMD_LINE_SWITCH, "d", "debugger", - "Opens the debugger", - wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL - }, - { - wxCMD_LINE_SWITCH, "l", "logger", - "Opens the logger", - wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL - }, - { - wxCMD_LINE_OPTION, "e", "exec", - "Loads the specified file (ELF, DOL, GCM, ISO, WBFS, CISO, GCZ, WAD)", - wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL - }, - { - wxCMD_LINE_SWITCH, "b", "batch", - "Exit Dolphin with emulator", - wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL - }, - { - wxCMD_LINE_OPTION, "c", "confirm", - "Set Confirm on Stop", - wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL - }, - { - wxCMD_LINE_OPTION, "v", "video_backend", - "Specify a video backend", - wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL - }, - { - wxCMD_LINE_OPTION, "a", "audio_emulation", - "Low level (LLE) or high level (HLE) audio", - wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL - }, - { - wxCMD_LINE_OPTION, "m", "movie", - "Play a movie file", - wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL - }, - { - wxCMD_LINE_OPTION, "u", "user", - "User folder path", - wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL - }, - { - wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 - } - }; + static const wxCmdLineEntryDesc desc[] = { + {wxCMD_LINE_SWITCH, "h", "help", "Show this help message", wxCMD_LINE_VAL_NONE, + wxCMD_LINE_OPTION_HELP}, + {wxCMD_LINE_SWITCH, "d", "debugger", "Opens the debugger", wxCMD_LINE_VAL_NONE, + wxCMD_LINE_PARAM_OPTIONAL}, + {wxCMD_LINE_SWITCH, "l", "logger", "Opens the logger", wxCMD_LINE_VAL_NONE, + wxCMD_LINE_PARAM_OPTIONAL}, + {wxCMD_LINE_OPTION, "e", "exec", + "Loads the specified file (ELF, DOL, GCM, ISO, WBFS, CISO, GCZ, WAD)", wxCMD_LINE_VAL_STRING, + wxCMD_LINE_PARAM_OPTIONAL}, + {wxCMD_LINE_SWITCH, "b", "batch", "Exit Dolphin with emulator", wxCMD_LINE_VAL_NONE, + wxCMD_LINE_PARAM_OPTIONAL}, + {wxCMD_LINE_OPTION, "c", "confirm", "Set Confirm on Stop", wxCMD_LINE_VAL_STRING, + wxCMD_LINE_PARAM_OPTIONAL}, + {wxCMD_LINE_OPTION, "v", "video_backend", "Specify a video backend", wxCMD_LINE_VAL_STRING, + wxCMD_LINE_PARAM_OPTIONAL}, + {wxCMD_LINE_OPTION, "a", "audio_emulation", "Low level (LLE) or high level (HLE) audio", + wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL}, + {wxCMD_LINE_OPTION, "m", "movie", "Play a movie file", wxCMD_LINE_VAL_STRING, + wxCMD_LINE_PARAM_OPTIONAL}, + {wxCMD_LINE_OPTION, "u", "user", "User folder path", wxCMD_LINE_VAL_STRING, + wxCMD_LINE_PARAM_OPTIONAL}, + {wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0}}; - parser.SetDesc(desc); + parser.SetDesc(desc); } bool DolphinApp::OnCmdLineParsed(wxCmdLineParser& parser) { - if (argc == 2 && File::Exists(argv[1].ToUTF8().data())) - { - m_load_file = true; - m_file_to_load = argv[1]; - } - else if (parser.Parse() != 0) - { - return false; - } + if (argc == 2 && File::Exists(argv[1].ToUTF8().data())) + { + m_load_file = true; + m_file_to_load = argv[1]; + } + else if (parser.Parse() != 0) + { + return false; + } - if (!m_load_file) - m_load_file = parser.Found("exec", &m_file_to_load); + if (!m_load_file) + m_load_file = parser.Found("exec", &m_file_to_load); - m_use_debugger = parser.Found("debugger"); - m_use_logger = parser.Found("logger"); - m_batch_mode = parser.Found("batch"); - m_confirm_stop = parser.Found("confirm", &m_confirm_setting); - m_select_video_backend = parser.Found("video_backend", &m_video_backend_name); - m_select_audio_emulation = parser.Found("audio_emulation", &m_audio_emulation_name); - m_play_movie = parser.Found("movie", &m_movie_file); - parser.Found("user", &m_user_path); + m_use_debugger = parser.Found("debugger"); + m_use_logger = parser.Found("logger"); + m_batch_mode = parser.Found("batch"); + m_confirm_stop = parser.Found("confirm", &m_confirm_setting); + m_select_video_backend = parser.Found("video_backend", &m_video_backend_name); + m_select_audio_emulation = parser.Found("audio_emulation", &m_audio_emulation_name); + m_play_movie = parser.Found("movie", &m_movie_file); + parser.Found("user", &m_user_path); - return true; + return true; } #ifdef __APPLE__ void DolphinApp::MacOpenFile(const wxString& fileName) { - m_file_to_load = fileName; - m_load_file = true; - main_frame->BootGame(WxStrToStr(m_file_to_load)); + m_file_to_load = fileName; + m_load_file = true; + main_frame->BootGame(WxStrToStr(m_file_to_load)); } #endif void DolphinApp::AfterInit() { - if (!m_batch_mode) - main_frame->UpdateGameList(); + if (!m_batch_mode) + main_frame->UpdateGameList(); - if (!SConfig::GetInstance().m_analytics_permission_asked) - { - int answer = wxMessageBox( - _("If authorized, Dolphin can collect data on its performance, " - "feature usage, and configuration, as well as data on your system's " - "hardware and operating system.\n\n" - "No private data is ever collected. This data helps us understand " - "how people and emulated games use Dolphin and prioritize our " - "efforts. It also helps us identify rare configurations that are " - "causing bugs, performance and stability issues.\n" - "This authorization can be revoked at any time through Dolphin's " - "settings.\n\n" - "Do you authorize Dolphin to report this information to Dolphin's " - "developers?"), - _("Usage statistics reporting"), - wxYES_NO, main_frame); + if (!SConfig::GetInstance().m_analytics_permission_asked) + { + int answer = + wxMessageBox(_("If authorized, Dolphin can collect data on its performance, " + "feature usage, and configuration, as well as data on your system's " + "hardware and operating system.\n\n" + "No private data is ever collected. This data helps us understand " + "how people and emulated games use Dolphin and prioritize our " + "efforts. It also helps us identify rare configurations that are " + "causing bugs, performance and stability issues.\n" + "This authorization can be revoked at any time through Dolphin's " + "settings.\n\n" + "Do you authorize Dolphin to report this information to Dolphin's " + "developers?"), + _("Usage statistics reporting"), wxYES_NO, main_frame); - SConfig::GetInstance().m_analytics_permission_asked = true; - SConfig::GetInstance().m_analytics_enabled = (answer == wxYES); - SConfig::GetInstance().SaveSettings(); + SConfig::GetInstance().m_analytics_permission_asked = true; + SConfig::GetInstance().m_analytics_enabled = (answer == wxYES); + SConfig::GetInstance().SaveSettings(); - DolphinAnalytics::Instance()->ReloadConfig(); - } + DolphinAnalytics::Instance()->ReloadConfig(); + } - if (m_confirm_stop) - { - if (m_confirm_setting.Upper() == "TRUE") - SConfig::GetInstance().bConfirmStop = true; - else if (m_confirm_setting.Upper() == "FALSE") - SConfig::GetInstance().bConfirmStop = false; - } + if (m_confirm_stop) + { + if (m_confirm_setting.Upper() == "TRUE") + SConfig::GetInstance().bConfirmStop = true; + else if (m_confirm_setting.Upper() == "FALSE") + SConfig::GetInstance().bConfirmStop = false; + } - if (m_play_movie && !m_movie_file.empty()) - { - if (Movie::PlayInput(WxStrToStr(m_movie_file))) - { - if (m_load_file && !m_file_to_load.empty()) - { - main_frame->BootGame(WxStrToStr(m_file_to_load)); - } - else - { - main_frame->BootGame(""); - } - } - } - // First check if we have an exec command line. - else if (m_load_file && !m_file_to_load.empty()) - { - main_frame->BootGame(WxStrToStr(m_file_to_load)); - } - // If we have selected Automatic Start, start the default ISO, - // or if no default ISO exists, start the last loaded ISO - else if (main_frame->g_pCodeWindow) - { - if (main_frame->g_pCodeWindow->AutomaticStart()) - { - main_frame->BootGame(""); - } - } + if (m_play_movie && !m_movie_file.empty()) + { + if (Movie::PlayInput(WxStrToStr(m_movie_file))) + { + if (m_load_file && !m_file_to_load.empty()) + { + main_frame->BootGame(WxStrToStr(m_file_to_load)); + } + else + { + main_frame->BootGame(""); + } + } + } + // First check if we have an exec command line. + else if (m_load_file && !m_file_to_load.empty()) + { + main_frame->BootGame(WxStrToStr(m_file_to_load)); + } + // If we have selected Automatic Start, start the default ISO, + // or if no default ISO exists, start the last loaded ISO + else if (main_frame->g_pCodeWindow) + { + if (main_frame->g_pCodeWindow->AutomaticStart()) + { + main_frame->BootGame(""); + } + } } void DolphinApp::InitLanguageSupport() { - unsigned int language = 0; + unsigned int language = 0; - IniFile ini; - ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); - ini.GetOrCreateSection("Interface")->Get("Language", &language, wxLANGUAGE_DEFAULT); + IniFile ini; + ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); + ini.GetOrCreateSection("Interface")->Get("Language", &language, wxLANGUAGE_DEFAULT); - // Load language if possible, fall back to system default otherwise - if (wxLocale::IsAvailable(language)) - { - m_locale.reset(new wxLocale(language)); + // Load language if possible, fall back to system default otherwise + if (wxLocale::IsAvailable(language)) + { + m_locale.reset(new wxLocale(language)); - // Specify where dolphins *.gmo files are located on each operating system +// Specify where dolphins *.gmo files are located on each operating system #ifdef _WIN32 - m_locale->AddCatalogLookupPathPrefix(StrToWxStr(File::GetExeDirectory() + DIR_SEP "Languages")); + m_locale->AddCatalogLookupPathPrefix(StrToWxStr(File::GetExeDirectory() + DIR_SEP "Languages")); #elif defined(__LINUX__) - m_locale->AddCatalogLookupPathPrefix(StrToWxStr(DATA_DIR "../locale")); + m_locale->AddCatalogLookupPathPrefix(StrToWxStr(DATA_DIR "../locale")); #elif defined(__APPLE__) - m_locale->AddCatalogLookupPathPrefix(StrToWxStr(File::GetBundleDirectory() + "Contents/Resources")); + m_locale->AddCatalogLookupPathPrefix( + StrToWxStr(File::GetBundleDirectory() + "Contents/Resources")); #endif - m_locale->AddCatalog("dolphin-emu"); + m_locale->AddCatalog("dolphin-emu"); - if (!m_locale->IsOk()) - { - wxMessageBox(_("Error loading selected language. Falling back to system default."), _("Error")); - m_locale.reset(new wxLocale(wxLANGUAGE_DEFAULT)); - } - } - else - { - wxMessageBox(_("The selected language is not supported by your system. Falling back to system default."), _("Error")); - m_locale.reset(new wxLocale(wxLANGUAGE_DEFAULT)); - } + if (!m_locale->IsOk()) + { + wxMessageBox(_("Error loading selected language. Falling back to system default."), + _("Error")); + m_locale.reset(new wxLocale(wxLANGUAGE_DEFAULT)); + } + } + else + { + wxMessageBox( + _("The selected language is not supported by your system. Falling back to system default."), + _("Error")); + m_locale.reset(new wxLocale(wxLANGUAGE_DEFAULT)); + } } void DolphinApp::OnEndSession(wxCloseEvent& event) { - // Close if we've received wxEVT_END_SESSION (ignore wxEVT_QUERY_END_SESSION) - if (!event.CanVeto()) - { - main_frame->Close(true); - } + // Close if we've received wxEVT_END_SESSION (ignore wxEVT_QUERY_END_SESSION) + if (!event.CanVeto()) + { + main_frame->Close(true); + } } int DolphinApp::OnExit() { - Core::Shutdown(); - UICommon::Shutdown(); + Core::Shutdown(); + UICommon::Shutdown(); - return wxApp::OnExit(); + return wxApp::OnExit(); } void DolphinApp::OnFatalException() { - WiimoteReal::Shutdown(); + WiimoteReal::Shutdown(); } void DolphinApp::OnIdle(wxIdleEvent& ev) { - ev.Skip(); - Core::HostDispatchJobs(); + ev.Skip(); + Core::HostDispatchJobs(); } // ------------ @@ -400,198 +368,205 @@ void DolphinApp::OnIdle(wxIdleEvent& ev) bool wxMsgAlert(const char* caption, const char* text, bool yes_no, int /*Style*/) { #ifdef __WXGTK__ - if (wxIsMainThread()) - { + if (wxIsMainThread()) + { #endif - NetPlayDialog*& npd = NetPlayDialog::GetInstance(); - if (npd == nullptr) - { - return wxYES == wxMessageBox(StrToWxStr(text), StrToWxStr(caption), - (yes_no) ? wxYES_NO : wxOK, wxWindow::FindFocus()); - } - else - { - npd->AppendChat("/!\\ " + std::string{text}); - return true; - } + NetPlayDialog*& npd = NetPlayDialog::GetInstance(); + if (npd == nullptr) + { + return wxYES == wxMessageBox(StrToWxStr(text), StrToWxStr(caption), + (yes_no) ? wxYES_NO : wxOK, wxWindow::FindFocus()); + } + else + { + npd->AppendChat("/!\\ " + std::string{text}); + return true; + } #ifdef __WXGTK__ - } - else - { - wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_PANIC); - event.SetString(StrToWxStr(caption) + ":" + StrToWxStr(text)); - event.SetInt(yes_no); - main_frame->GetEventHandler()->AddPendingEvent(event); - main_frame->panic_event.Wait(); - return main_frame->bPanicResult; - } + } + else + { + wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_PANIC); + event.SetString(StrToWxStr(caption) + ":" + StrToWxStr(text)); + event.SetInt(yes_no); + main_frame->GetEventHandler()->AddPendingEvent(event); + main_frame->panic_event.Wait(); + return main_frame->bPanicResult; + } #endif } -std::string wxStringTranslator(const char *text) +std::string wxStringTranslator(const char* text) { - return WxStrToStr(wxGetTranslation(wxString::FromUTF8(text))); + return WxStrToStr(wxGetTranslation(wxString::FromUTF8(text))); } // Accessor for the main window class CFrame* DolphinApp::GetCFrame() { - return main_frame; + return main_frame; } void Host_Message(int Id) { - if (Id == WM_USER_JOB_DISPATCH) - { - // Trigger a wxEVT_IDLE - wxWakeUpIdle(); - return; - } - wxCommandEvent event(wxEVT_HOST_COMMAND, Id); - main_frame->GetEventHandler()->AddPendingEvent(event); + if (Id == WM_USER_JOB_DISPATCH) + { + // Trigger a wxEVT_IDLE + wxWakeUpIdle(); + return; + } + wxCommandEvent event(wxEVT_HOST_COMMAND, Id); + main_frame->GetEventHandler()->AddPendingEvent(event); } void* Host_GetRenderHandle() { - return main_frame->GetRenderHandle(); + return main_frame->GetRenderHandle(); } // OK, this thread boundary is DANGEROUS on Linux // wxPostEvent / wxAddPendingEvent is the solution. void Host_NotifyMapLoaded() { - wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_NOTIFY_MAP_LOADED); - main_frame->GetEventHandler()->AddPendingEvent(event); + wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_NOTIFY_MAP_LOADED); + main_frame->GetEventHandler()->AddPendingEvent(event); - if (main_frame->g_pCodeWindow) - { - main_frame->g_pCodeWindow->GetEventHandler()->AddPendingEvent(event); - } + if (main_frame->g_pCodeWindow) + { + main_frame->g_pCodeWindow->GetEventHandler()->AddPendingEvent(event); + } } void Host_UpdateDisasmDialog() { - wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_UPDATE_DISASM_DIALOG); - main_frame->GetEventHandler()->AddPendingEvent(event); + wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_UPDATE_DISASM_DIALOG); + main_frame->GetEventHandler()->AddPendingEvent(event); - if (main_frame->g_pCodeWindow) - { - main_frame->g_pCodeWindow->GetEventHandler()->AddPendingEvent(event); - } + if (main_frame->g_pCodeWindow) + { + main_frame->g_pCodeWindow->GetEventHandler()->AddPendingEvent(event); + } } void Host_UpdateMainFrame() { - wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_UPDATE_GUI); - main_frame->GetEventHandler()->AddPendingEvent(event); + wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_UPDATE_GUI); + main_frame->GetEventHandler()->AddPendingEvent(event); - if (main_frame->g_pCodeWindow) - { - main_frame->g_pCodeWindow->GetEventHandler()->AddPendingEvent(event); - } + if (main_frame->g_pCodeWindow) + { + main_frame->g_pCodeWindow->GetEventHandler()->AddPendingEvent(event); + } } void Host_UpdateTitle(const std::string& title) { - wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_UPDATE_TITLE); - event.SetString(StrToWxStr(title)); - main_frame->GetEventHandler()->AddPendingEvent(event); + wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_UPDATE_TITLE); + event.SetString(StrToWxStr(title)); + main_frame->GetEventHandler()->AddPendingEvent(event); } void Host_RequestRenderWindowSize(int width, int height) { - wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_WINDOW_SIZE_REQUEST); - event.SetClientData(new std::pair(width, height)); - main_frame->GetEventHandler()->AddPendingEvent(event); + wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_WINDOW_SIZE_REQUEST); + event.SetClientData(new std::pair(width, height)); + main_frame->GetEventHandler()->AddPendingEvent(event); } void Host_RequestFullscreen(bool enable_fullscreen) { - wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_FULLSCREEN_REQUEST); - event.SetInt(enable_fullscreen ? 1 : 0); - main_frame->GetEventHandler()->AddPendingEvent(event); + wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_FULLSCREEN_REQUEST); + event.SetInt(enable_fullscreen ? 1 : 0); + main_frame->GetEventHandler()->AddPendingEvent(event); } void Host_SetStartupDebuggingParameters() { - SConfig& StartUp = SConfig::GetInstance(); - if (main_frame->g_pCodeWindow) - { - StartUp.bBootToPause = main_frame->g_pCodeWindow->BootToPause(); - StartUp.bAutomaticStart = main_frame->g_pCodeWindow->AutomaticStart(); - StartUp.bJITNoBlockCache = main_frame->g_pCodeWindow->JITNoBlockCache(); - StartUp.bJITNoBlockLinking = main_frame->g_pCodeWindow->JITNoBlockLinking(); - } - else - { - StartUp.bBootToPause = false; - } - StartUp.bEnableDebugging = main_frame->g_pCodeWindow ? true : false; // RUNNING_DEBUG + SConfig& StartUp = SConfig::GetInstance(); + if (main_frame->g_pCodeWindow) + { + StartUp.bBootToPause = main_frame->g_pCodeWindow->BootToPause(); + StartUp.bAutomaticStart = main_frame->g_pCodeWindow->AutomaticStart(); + StartUp.bJITNoBlockCache = main_frame->g_pCodeWindow->JITNoBlockCache(); + StartUp.bJITNoBlockLinking = main_frame->g_pCodeWindow->JITNoBlockLinking(); + } + else + { + StartUp.bBootToPause = false; + } + StartUp.bEnableDebugging = main_frame->g_pCodeWindow ? true : false; // RUNNING_DEBUG } void Host_SetWiiMoteConnectionState(int _State) { - static int currentState = -1; - if (_State == currentState) - return; - currentState = _State; + static int currentState = -1; + if (_State == currentState) + return; + currentState = _State; - wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_UPDATE_STATUS_BAR); + wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_UPDATE_STATUS_BAR); - switch (_State) - { - case 0: event.SetString(_("Not connected")); break; - case 1: event.SetString(_("Connecting...")); break; - case 2: event.SetString(_("Wiimote Connected")); break; - } - // Update field 1 or 2 - event.SetInt(1); + switch (_State) + { + case 0: + event.SetString(_("Not connected")); + break; + case 1: + event.SetString(_("Connecting...")); + break; + case 2: + event.SetString(_("Wiimote Connected")); + break; + } + // Update field 1 or 2 + event.SetInt(1); - NOTICE_LOG(WIIMOTE, "%s", static_cast(event.GetString().c_str())); + NOTICE_LOG(WIIMOTE, "%s", static_cast(event.GetString().c_str())); - main_frame->GetEventHandler()->AddPendingEvent(event); + main_frame->GetEventHandler()->AddPendingEvent(event); } bool Host_UIHasFocus() { - return main_frame->UIHasFocus(); + return main_frame->UIHasFocus(); } bool Host_RendererHasFocus() { - return main_frame->RendererHasFocus(); + return main_frame->RendererHasFocus(); } bool Host_RendererIsFullscreen() { - return main_frame->RendererIsFullscreen(); + return main_frame->RendererIsFullscreen(); } void Host_ConnectWiimote(int wm_idx, bool connect) { - if (connect) - { - wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_FORCE_CONNECT_WIIMOTE1 + wm_idx); - main_frame->GetEventHandler()->AddPendingEvent(event); - } - else - { - wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_FORCE_DISCONNECT_WIIMOTE1 + wm_idx); - main_frame->GetEventHandler()->AddPendingEvent(event); - } + if (connect) + { + wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_FORCE_CONNECT_WIIMOTE1 + wm_idx); + main_frame->GetEventHandler()->AddPendingEvent(event); + } + else + { + wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_FORCE_DISCONNECT_WIIMOTE1 + wm_idx); + main_frame->GetEventHandler()->AddPendingEvent(event); + } } void Host_ShowVideoConfig(void* parent, const std::string& backend_name, const std::string& config_name) { - if (backend_name == "Direct3D 11" || backend_name == "Direct3D 12 (experimental)" || backend_name == "OpenGL") - { - VideoConfigDiag diag((wxWindow*)parent, backend_name, config_name); - diag.ShowModal(); - } - else if (backend_name == "Software Renderer") - { - SoftwareVideoConfigDialog diag((wxWindow*)parent, backend_name, config_name); - diag.ShowModal(); - } + if (backend_name == "Direct3D 11" || backend_name == "Direct3D 12 (experimental)" || + backend_name == "OpenGL") + { + VideoConfigDiag diag((wxWindow*)parent, backend_name, config_name); + diag.ShowModal(); + } + else if (backend_name == "Software Renderer") + { + SoftwareVideoConfigDialog diag((wxWindow*)parent, backend_name, config_name); + diag.ShowModal(); + } } diff --git a/Source/Core/DolphinWX/Main.h b/Source/Core/DolphinWX/Main.h index 7e9e3f56ff..803ee3baa9 100644 --- a/Source/Core/DolphinWX/Main.h +++ b/Source/Core/DolphinWX/Main.h @@ -16,40 +16,40 @@ extern CFrame* main_frame; class DolphinApp : public wxApp { public: - CFrame* GetCFrame(); + CFrame* GetCFrame(); private: - bool OnInit() override; - int OnExit() override; - void OnInitCmdLine(wxCmdLineParser& parser) override; - bool OnCmdLineParsed(wxCmdLineParser& parser) override; - void OnFatalException() override; - bool Initialize(int& c, wxChar** v) override; + bool OnInit() override; + int OnExit() override; + void OnInitCmdLine(wxCmdLineParser& parser) override; + bool OnCmdLineParsed(wxCmdLineParser& parser) override; + void OnFatalException() override; + bool Initialize(int& c, wxChar** v) override; #ifdef __APPLE__ - void MacOpenFile(const wxString &fileName) override; + void MacOpenFile(const wxString& fileName) override; #endif - void OnEndSession(wxCloseEvent& event); - void InitLanguageSupport(); - void AfterInit(); - void OnIdle(wxIdleEvent&); + void OnEndSession(wxCloseEvent& event); + void InitLanguageSupport(); + void AfterInit(); + void OnIdle(wxIdleEvent&); - bool m_batch_mode = false; - bool m_confirm_stop = false; - bool m_load_file = false; - bool m_play_movie = false; - bool m_use_debugger = false; - bool m_use_logger = false; - bool m_select_video_backend = false; - bool m_select_audio_emulation = false; - wxString m_confirm_setting; - wxString m_video_backend_name; - wxString m_audio_emulation_name; - wxString m_user_path; - wxString m_file_to_load; - wxString m_movie_file; - std::unique_ptr m_locale; + bool m_batch_mode = false; + bool m_confirm_stop = false; + bool m_load_file = false; + bool m_play_movie = false; + bool m_use_debugger = false; + bool m_use_logger = false; + bool m_select_video_backend = false; + bool m_select_audio_emulation = false; + wxString m_confirm_setting; + wxString m_video_backend_name; + wxString m_audio_emulation_name; + wxString m_user_path; + wxString m_file_to_load; + wxString m_movie_file; + std::unique_ptr m_locale; }; DECLARE_APP(DolphinApp); diff --git a/Source/Core/DolphinWX/MainNoGUI.cpp b/Source/Core/DolphinWX/MainNoGUI.cpp index 01994fea60..445a6c9fac 100644 --- a/Source/Core/DolphinWX/MainNoGUI.cpp +++ b/Source/Core/DolphinWX/MainNoGUI.cpp @@ -12,18 +12,18 @@ #include "Common/CommonTypes.h" #include "Common/Event.h" -#include "Common/MsgHandler.h" #include "Common/Logging/LogManager.h" +#include "Common/MsgHandler.h" #include "Core/Analytics.h" #include "Core/BootManager.h" #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/Host.h" -#include "Core/State.h" #include "Core/HW/Wiimote.h" +#include "Core/Host.h" #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h" #include "Core/IPC_HLE/WII_IPC_HLE_WiiMote.h" +#include "Core/State.h" #include "UICommon/UICommon.h" @@ -36,96 +36,109 @@ static bool running = true; class Platform { public: - virtual void Init() {} - virtual void SetTitle(const std::string &title) {} - virtual void MainLoop() - { - while (running) - { - Core::HostDispatchJobs(); - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - } - virtual void Shutdown() {} - virtual ~Platform() {} + virtual void Init() {} + virtual void SetTitle(const std::string& title) {} + virtual void MainLoop() + { + while (running) + { + Core::HostDispatchJobs(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } + virtual void Shutdown() {} + virtual ~Platform() {} }; static Platform* platform; -void Host_NotifyMapLoaded() {} -void Host_RefreshDSPDebuggerWindow() {} +void Host_NotifyMapLoaded() +{ +} +void Host_RefreshDSPDebuggerWindow() +{ +} static Common::Event updateMainFrameEvent; void Host_Message(int Id) { - if (Id == WM_USER_STOP) - { - running = false; - updateMainFrameEvent.Set(); - } + if (Id == WM_USER_STOP) + { + running = false; + updateMainFrameEvent.Set(); + } } static void* s_window_handle = nullptr; void* Host_GetRenderHandle() { - return s_window_handle; + return s_window_handle; } void Host_UpdateTitle(const std::string& title) { - platform->SetTitle(title); + platform->SetTitle(title); } -void Host_UpdateDisasmDialog(){} +void Host_UpdateDisasmDialog() +{ +} void Host_UpdateMainFrame() { - updateMainFrameEvent.Set(); + updateMainFrameEvent.Set(); } -void Host_RequestRenderWindowSize(int width, int height) {} +void Host_RequestRenderWindowSize(int width, int height) +{ +} -void Host_RequestFullscreen(bool enable_fullscreen) {} +void Host_RequestFullscreen(bool enable_fullscreen) +{ +} void Host_SetStartupDebuggingParameters() { - SConfig& StartUp = SConfig::GetInstance(); - StartUp.bEnableDebugging = false; - StartUp.bBootToPause = false; + SConfig& StartUp = SConfig::GetInstance(); + StartUp.bEnableDebugging = false; + StartUp.bBootToPause = false; } bool Host_UIHasFocus() { - return false; + return false; } bool Host_RendererHasFocus() { - return rendererHasFocus; + return rendererHasFocus; } bool Host_RendererIsFullscreen() { - return rendererIsFullscreen; + return rendererIsFullscreen; } void Host_ConnectWiimote(int wm_idx, bool connect) { - if (Core::IsRunning() && SConfig::GetInstance().bWii) - { - Core::QueueHostJob([=] - { - bool was_unpaused = Core::PauseAndLock(true); - GetUsbPointer()->AccessWiiMote(wm_idx | 0x100)->Activate(connect); - Host_UpdateMainFrame(); - Core::PauseAndLock(false, was_unpaused); - }); - } + if (Core::IsRunning() && SConfig::GetInstance().bWii) + { + Core::QueueHostJob([=] { + bool was_unpaused = Core::PauseAndLock(true); + GetUsbPointer()->AccessWiiMote(wm_idx | 0x100)->Activate(connect); + Host_UpdateMainFrame(); + Core::PauseAndLock(false, was_unpaused); + }); + } } -void Host_SetWiiMoteConnectionState(int _State) {} +void Host_SetWiiMoteConnectionState(int _State) +{ +} -void Host_ShowVideoConfig(void*, const std::string&, const std::string&) {} +void Host_ShowVideoConfig(void*, const std::string&, const std::string&) +{ +} #if HAVE_X11 #include @@ -133,259 +146,249 @@ void Host_ShowVideoConfig(void*, const std::string&, const std::string&) {} class PlatformX11 : public Platform { - Display *dpy; - Window win; - Cursor blankCursor = None; + Display* dpy; + Window win; + Cursor blankCursor = None; #if defined(HAVE_XRANDR) && HAVE_XRANDR - X11Utils::XRRConfiguration *XRRConfig; + X11Utils::XRRConfiguration* XRRConfig; #endif - void Init() override - { - XInitThreads(); - dpy = XOpenDisplay(nullptr); - if (!dpy) - { - PanicAlert("No X11 display found"); - exit(1); - } + void Init() override + { + XInitThreads(); + dpy = XOpenDisplay(nullptr); + if (!dpy) + { + PanicAlert("No X11 display found"); + exit(1); + } - win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), - SConfig::GetInstance().iRenderWindowXPos, - SConfig::GetInstance().iRenderWindowYPos, - SConfig::GetInstance().iRenderWindowWidth, - SConfig::GetInstance().iRenderWindowHeight, - 0, 0, BlackPixel(dpy, 0)); - XSelectInput(dpy, win, KeyPressMask | FocusChangeMask); - Atom wmProtocols[1]; - wmProtocols[0] = XInternAtom(dpy, "WM_DELETE_WINDOW", True); - XSetWMProtocols(dpy, win, wmProtocols, 1); - XMapRaised(dpy, win); - XFlush(dpy); - s_window_handle = (void*)win; + win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), SConfig::GetInstance().iRenderWindowXPos, + SConfig::GetInstance().iRenderWindowYPos, + SConfig::GetInstance().iRenderWindowWidth, + SConfig::GetInstance().iRenderWindowHeight, 0, 0, BlackPixel(dpy, 0)); + XSelectInput(dpy, win, KeyPressMask | FocusChangeMask); + Atom wmProtocols[1]; + wmProtocols[0] = XInternAtom(dpy, "WM_DELETE_WINDOW", True); + XSetWMProtocols(dpy, win, wmProtocols, 1); + XMapRaised(dpy, win); + XFlush(dpy); + s_window_handle = (void*)win; - if (SConfig::GetInstance().bDisableScreenSaver) - X11Utils::InhibitScreensaver(dpy, win, true); + if (SConfig::GetInstance().bDisableScreenSaver) + X11Utils::InhibitScreensaver(dpy, win, true); #if defined(HAVE_XRANDR) && HAVE_XRANDR - XRRConfig = new X11Utils::XRRConfiguration(dpy, win); + XRRConfig = new X11Utils::XRRConfiguration(dpy, win); #endif - if (SConfig::GetInstance().bHideCursor) - { - // make a blank cursor - Pixmap Blank; - XColor DummyColor; - char ZeroData[1] = { 0 }; - Blank = XCreateBitmapFromData(dpy, win, ZeroData, 1, 1); - blankCursor = XCreatePixmapCursor(dpy, Blank, Blank, &DummyColor, &DummyColor, 0, 0); - XFreePixmap(dpy, Blank); - XDefineCursor(dpy, win, blankCursor); - } - } + if (SConfig::GetInstance().bHideCursor) + { + // make a blank cursor + Pixmap Blank; + XColor DummyColor; + char ZeroData[1] = {0}; + Blank = XCreateBitmapFromData(dpy, win, ZeroData, 1, 1); + blankCursor = XCreatePixmapCursor(dpy, Blank, Blank, &DummyColor, &DummyColor, 0, 0); + XFreePixmap(dpy, Blank); + XDefineCursor(dpy, win, blankCursor); + } + } - void SetTitle(const std::string &string) override - { - XStoreName(dpy, win, string.c_str()); - } + void SetTitle(const std::string& string) override { XStoreName(dpy, win, string.c_str()); } + void MainLoop() override + { + bool fullscreen = SConfig::GetInstance().bFullscreen; - void MainLoop() override - { - bool fullscreen = SConfig::GetInstance().bFullscreen; - - if (fullscreen) - { - rendererIsFullscreen = X11Utils::ToggleFullscreen(dpy, win); + if (fullscreen) + { + rendererIsFullscreen = X11Utils::ToggleFullscreen(dpy, win); #if defined(HAVE_XRANDR) && HAVE_XRANDR - XRRConfig->ToggleDisplayMode(True); + XRRConfig->ToggleDisplayMode(True); #endif - } + } - // The actual loop - while (running) - { - XEvent event; - KeySym key; - for (int num_events = XPending(dpy); num_events > 0; num_events--) - { - XNextEvent(dpy, &event); - switch (event.type) - { - case KeyPress: - key = XLookupKeysym((XKeyEvent*)&event, 0); - if (key == XK_Escape) - { - if (Core::GetState() == Core::CORE_RUN) - { - if (SConfig::GetInstance().bHideCursor) - XUndefineCursor(dpy, win); - Core::SetState(Core::CORE_PAUSE); - } - else - { - if (SConfig::GetInstance().bHideCursor) - XDefineCursor(dpy, win, blankCursor); - Core::SetState(Core::CORE_RUN); - } - } - else if ((key == XK_Return) && (event.xkey.state & Mod1Mask)) - { - fullscreen = !fullscreen; - X11Utils::ToggleFullscreen(dpy, win); + // The actual loop + while (running) + { + XEvent event; + KeySym key; + for (int num_events = XPending(dpy); num_events > 0; num_events--) + { + XNextEvent(dpy, &event); + switch (event.type) + { + case KeyPress: + key = XLookupKeysym((XKeyEvent*)&event, 0); + if (key == XK_Escape) + { + if (Core::GetState() == Core::CORE_RUN) + { + if (SConfig::GetInstance().bHideCursor) + XUndefineCursor(dpy, win); + Core::SetState(Core::CORE_PAUSE); + } + else + { + if (SConfig::GetInstance().bHideCursor) + XDefineCursor(dpy, win, blankCursor); + Core::SetState(Core::CORE_RUN); + } + } + else if ((key == XK_Return) && (event.xkey.state & Mod1Mask)) + { + fullscreen = !fullscreen; + X11Utils::ToggleFullscreen(dpy, win); #if defined(HAVE_XRANDR) && HAVE_XRANDR - XRRConfig->ToggleDisplayMode(fullscreen); + XRRConfig->ToggleDisplayMode(fullscreen); #endif - } - else if (key >= XK_F1 && key <= XK_F8) - { - int slot_number = key - XK_F1 + 1; - if (event.xkey.state & ShiftMask) - State::Save(slot_number); - else - State::Load(slot_number); - } - else if (key == XK_F9) - Core::SaveScreenShot(); - else if (key == XK_F11) - State::LoadLastSaved(); - else if (key == XK_F12) - { - if (event.xkey.state & ShiftMask) - State::UndoLoadState(); - else - State::UndoSaveState(); - } - break; - case FocusIn: - rendererHasFocus = true; - if (SConfig::GetInstance().bHideCursor && - Core::GetState() != Core::CORE_PAUSE) - XDefineCursor(dpy, win, blankCursor); - break; - case FocusOut: - rendererHasFocus = false; - if (SConfig::GetInstance().bHideCursor) - XUndefineCursor(dpy, win); - break; - case ClientMessage: - if ((unsigned long) event.xclient.data.l[0] == XInternAtom(dpy, "WM_DELETE_WINDOW", False)) - running = false; - break; - } - } - if (!fullscreen) - { - Window winDummy; - unsigned int borderDummy, depthDummy; - XGetGeometry(dpy, win, &winDummy, - &SConfig::GetInstance().iRenderWindowXPos, - &SConfig::GetInstance().iRenderWindowYPos, - (unsigned int *)&SConfig::GetInstance().iRenderWindowWidth, - (unsigned int *)&SConfig::GetInstance().iRenderWindowHeight, - &borderDummy, &depthDummy); - rendererIsFullscreen = false; - } - Core::HostDispatchJobs(); - usleep(100000); - } - } + } + else if (key >= XK_F1 && key <= XK_F8) + { + int slot_number = key - XK_F1 + 1; + if (event.xkey.state & ShiftMask) + State::Save(slot_number); + else + State::Load(slot_number); + } + else if (key == XK_F9) + Core::SaveScreenShot(); + else if (key == XK_F11) + State::LoadLastSaved(); + else if (key == XK_F12) + { + if (event.xkey.state & ShiftMask) + State::UndoLoadState(); + else + State::UndoSaveState(); + } + break; + case FocusIn: + rendererHasFocus = true; + if (SConfig::GetInstance().bHideCursor && Core::GetState() != Core::CORE_PAUSE) + XDefineCursor(dpy, win, blankCursor); + break; + case FocusOut: + rendererHasFocus = false; + if (SConfig::GetInstance().bHideCursor) + XUndefineCursor(dpy, win); + break; + case ClientMessage: + if ((unsigned long)event.xclient.data.l[0] == XInternAtom(dpy, "WM_DELETE_WINDOW", False)) + running = false; + break; + } + } + if (!fullscreen) + { + Window winDummy; + unsigned int borderDummy, depthDummy; + XGetGeometry(dpy, win, &winDummy, &SConfig::GetInstance().iRenderWindowXPos, + &SConfig::GetInstance().iRenderWindowYPos, + (unsigned int*)&SConfig::GetInstance().iRenderWindowWidth, + (unsigned int*)&SConfig::GetInstance().iRenderWindowHeight, &borderDummy, + &depthDummy); + rendererIsFullscreen = false; + } + Core::HostDispatchJobs(); + usleep(100000); + } + } - void Shutdown() override - { + void Shutdown() override + { #if defined(HAVE_XRANDR) && HAVE_XRANDR - delete XRRConfig; + delete XRRConfig; #endif - if (SConfig::GetInstance().bHideCursor) - XFreeCursor(dpy, blankCursor); + if (SConfig::GetInstance().bHideCursor) + XFreeCursor(dpy, blankCursor); - XCloseDisplay(dpy); - } + XCloseDisplay(dpy); + } }; #endif static Platform* GetPlatform() { #if defined(USE_EGL) && defined(USE_HEADLESS) - return new Platform(); + return new Platform(); #elif HAVE_X11 - return new PlatformX11(); + return new PlatformX11(); #endif - return nullptr; + return nullptr; } int main(int argc, char* argv[]) { - int ch, help = 0; - struct option longopts[] = { - { "exec", no_argument, nullptr, 'e' }, - { "help", no_argument, nullptr, 'h' }, - { "version", no_argument, nullptr, 'v' }, - { nullptr, 0, nullptr, 0 } - }; + int ch, help = 0; + struct option longopts[] = {{"exec", no_argument, nullptr, 'e'}, + {"help", no_argument, nullptr, 'h'}, + {"version", no_argument, nullptr, 'v'}, + {nullptr, 0, nullptr, 0}}; - while ((ch = getopt_long(argc, argv, "eh?v", longopts, 0)) != -1) - { - switch (ch) - { - case 'e': - break; - case 'h': - case '?': - help = 1; - break; - case 'v': - fprintf(stderr, "%s\n", scm_rev_str.c_str()); - return 1; - } - } + while ((ch = getopt_long(argc, argv, "eh?v", longopts, 0)) != -1) + { + switch (ch) + { + case 'e': + break; + case 'h': + case '?': + help = 1; + break; + case 'v': + fprintf(stderr, "%s\n", scm_rev_str.c_str()); + return 1; + } + } - if (help == 1 || argc == optind) - { - fprintf(stderr, "%s\n\n", scm_rev_str.c_str()); - fprintf(stderr, "A multi-platform GameCube/Wii emulator\n\n"); - fprintf(stderr, "Usage: %s [-e ] [-h] [-v]\n", argv[0]); - fprintf(stderr, " -e, --exec Load the specified file\n"); - fprintf(stderr, " -h, --help Show this help message\n"); - fprintf(stderr, " -v, --version Print version and exit\n"); - return 1; - } + if (help == 1 || argc == optind) + { + fprintf(stderr, "%s\n\n", scm_rev_str.c_str()); + fprintf(stderr, "A multi-platform GameCube/Wii emulator\n\n"); + fprintf(stderr, "Usage: %s [-e ] [-h] [-v]\n", argv[0]); + fprintf(stderr, " -e, --exec Load the specified file\n"); + fprintf(stderr, " -h, --help Show this help message\n"); + fprintf(stderr, " -v, --version Print version and exit\n"); + return 1; + } - platform = GetPlatform(); - if (!platform) - { - fprintf(stderr, "No platform found\n"); - return 1; - } + platform = GetPlatform(); + if (!platform) + { + fprintf(stderr, "No platform found\n"); + return 1; + } - UICommon::SetUserDirectory(""); // Auto-detect user folder - UICommon::Init(); + UICommon::SetUserDirectory(""); // Auto-detect user folder + UICommon::Init(); - platform->Init(); + platform->Init(); - DolphinAnalytics::Instance()->ReportDolphinStart("nogui"); + DolphinAnalytics::Instance()->ReportDolphinStart("nogui"); - if (!BootManager::BootCore(argv[optind])) - { - fprintf(stderr, "Could not boot %s\n", argv[optind]); - return 1; - } + if (!BootManager::BootCore(argv[optind])) + { + fprintf(stderr, "Could not boot %s\n", argv[optind]); + return 1; + } - while (!Core::IsRunning() && running) - { - Core::HostDispatchJobs(); - updateMainFrameEvent.Wait(); - } + while (!Core::IsRunning() && running) + { + Core::HostDispatchJobs(); + updateMainFrameEvent.Wait(); + } - if (running) - platform->MainLoop(); - Core::Stop(); + if (running) + platform->MainLoop(); + Core::Stop(); - Core::Shutdown(); - platform->Shutdown(); - UICommon::Shutdown(); + Core::Shutdown(); + platform->Shutdown(); + UICommon::Shutdown(); - delete platform; + delete platform; - return 0; + return 0; } diff --git a/Source/Core/DolphinWX/MemcardManager.cpp b/Source/Core/DolphinWX/MemcardManager.cpp index 009f055699..d181e1da07 100644 --- a/Source/Core/DolphinWX/MemcardManager.cpp +++ b/Source/Core/DolphinWX/MemcardManager.cpp @@ -24,9 +24,9 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/IniFile.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "Core/HW/GCMemcard.h" #include "DolphinWX/MemcardManager.h" #include "DolphinWX/WxUtils.h" @@ -36,812 +36,808 @@ static wxBitmap wxBitmapFromMemoryRGBA(const unsigned char* data, u32 width, u32 height) { - static const std::array header = {{ - 0x42, 0x4D, - 0x38, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x36, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, // Width - 0x20, 0x00, 0x00, 0x00, // Height - 0x01, 0x00, - 0x20, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x02, 0x30, 0x00, 0x00, // Data size - 0x12, 0x0B, 0x00, 0x00, - 0x12, 0x0B, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }}; + static const std::array header = { + {0x42, 0x4D, 0x38, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // Width + 0x20, 0x00, 0x00, 0x00, // Height + 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, // Data size + 0x12, 0x0B, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}}; - u32 stride = (4 * width); + u32 stride = (4 * width); - u32 bytes = (stride * height) + header.size(); - bytes = (bytes + 3) & ~3; + u32 bytes = (stride * height) + header.size(); + bytes = (bytes + 3) & ~3; - u32 data_length = bytes - header.size(); + u32 data_length = bytes - header.size(); - std::vector pdata(bytes); - std::copy(header.begin(), header.end(), pdata.begin()); + std::vector pdata(bytes); + std::copy(header.begin(), header.end(), pdata.begin()); - u8* const pixelData = &pdata[header.size()]; + u8* const pixelData = &pdata[header.size()]; - for (u32 y = 0; y < height; y++) - std::memcpy(&pixelData[y * stride], &data[(height - y - 1) * stride], stride); + for (u32 y = 0; y < height; y++) + std::memcpy(&pixelData[y * stride], &data[(height - y - 1) * stride], stride); - std::memcpy(&pdata[18], &width, sizeof(u32)); - std::memcpy(&pdata[22], &height, sizeof(u32)); - std::memcpy(&pdata[34], &data_length, sizeof(u32)); + std::memcpy(&pdata[18], &width, sizeof(u32)); + std::memcpy(&pdata[22], &height, sizeof(u32)); + std::memcpy(&pdata[34], &data_length, sizeof(u32)); - wxMemoryInputStream is(pdata.data(), bytes); - return wxBitmap(wxImage(is, wxBITMAP_TYPE_BMP)); + wxMemoryInputStream is(pdata.data(), bytes); + return wxBitmap(wxImage(is, wxBITMAP_TYPE_BMP)); } BEGIN_EVENT_TABLE(CMemcardManager, wxDialog) - EVT_BUTTON(ID_COPYFROM_A,CMemcardManager::CopyDeleteClick) - EVT_BUTTON(ID_COPYFROM_B,CMemcardManager::CopyDeleteClick) - EVT_BUTTON(ID_DELETE_A,CMemcardManager::CopyDeleteClick) - EVT_BUTTON(ID_DELETE_B,CMemcardManager::CopyDeleteClick) - EVT_BUTTON(ID_SAVEIMPORT_B,CMemcardManager::CopyDeleteClick) - EVT_BUTTON(ID_SAVEEXPORT_B,CMemcardManager::CopyDeleteClick) - EVT_BUTTON(ID_SAVEIMPORT_A,CMemcardManager::CopyDeleteClick) - EVT_BUTTON(ID_SAVEEXPORT_A,CMemcardManager::CopyDeleteClick) - EVT_BUTTON(ID_CONVERTTOGCI,CMemcardManager::CopyDeleteClick) - EVT_BUTTON(ID_PREVPAGE_A, CMemcardManager::OnPageChange) - EVT_BUTTON(ID_NEXTPAGE_A, CMemcardManager::OnPageChange) - EVT_BUTTON(ID_PREVPAGE_B, CMemcardManager::OnPageChange) - EVT_BUTTON(ID_NEXTPAGE_B, CMemcardManager::OnPageChange) +EVT_BUTTON(ID_COPYFROM_A, CMemcardManager::CopyDeleteClick) +EVT_BUTTON(ID_COPYFROM_B, CMemcardManager::CopyDeleteClick) +EVT_BUTTON(ID_DELETE_A, CMemcardManager::CopyDeleteClick) +EVT_BUTTON(ID_DELETE_B, CMemcardManager::CopyDeleteClick) +EVT_BUTTON(ID_SAVEIMPORT_B, CMemcardManager::CopyDeleteClick) +EVT_BUTTON(ID_SAVEEXPORT_B, CMemcardManager::CopyDeleteClick) +EVT_BUTTON(ID_SAVEIMPORT_A, CMemcardManager::CopyDeleteClick) +EVT_BUTTON(ID_SAVEEXPORT_A, CMemcardManager::CopyDeleteClick) +EVT_BUTTON(ID_CONVERTTOGCI, CMemcardManager::CopyDeleteClick) +EVT_BUTTON(ID_PREVPAGE_A, CMemcardManager::OnPageChange) +EVT_BUTTON(ID_NEXTPAGE_A, CMemcardManager::OnPageChange) +EVT_BUTTON(ID_PREVPAGE_B, CMemcardManager::OnPageChange) +EVT_BUTTON(ID_NEXTPAGE_B, CMemcardManager::OnPageChange) - EVT_FILEPICKER_CHANGED(ID_MEMCARDPATH_A,CMemcardManager::OnPathChange) - EVT_FILEPICKER_CHANGED(ID_MEMCARDPATH_B,CMemcardManager::OnPathChange) +EVT_FILEPICKER_CHANGED(ID_MEMCARDPATH_A, CMemcardManager::OnPathChange) +EVT_FILEPICKER_CHANGED(ID_MEMCARDPATH_B, CMemcardManager::OnPathChange) - EVT_MENU_RANGE(ID_MEMCARDPATH_A, ID_USEPAGES, CMemcardManager::OnMenuChange) - EVT_MENU_RANGE(ID_COPYFROM_A, ID_CONVERTTOGCI, CMemcardManager::CopyDeleteClick) - EVT_MENU_RANGE(ID_NEXTPAGE_A, ID_PREVPAGE_B, CMemcardManager::OnPageChange) - EVT_MENU_RANGE(COLUMN_BANNER, NUMBER_OF_COLUMN, CMemcardManager::OnMenuChange) +EVT_MENU_RANGE(ID_MEMCARDPATH_A, ID_USEPAGES, CMemcardManager::OnMenuChange) +EVT_MENU_RANGE(ID_COPYFROM_A, ID_CONVERTTOGCI, CMemcardManager::CopyDeleteClick) +EVT_MENU_RANGE(ID_NEXTPAGE_A, ID_PREVPAGE_B, CMemcardManager::OnPageChange) +EVT_MENU_RANGE(COLUMN_BANNER, NUMBER_OF_COLUMN, CMemcardManager::OnMenuChange) END_EVENT_TABLE() CMemcardManager::CMemcardManager(wxWindow* parent) - : wxDialog(parent, wxID_ANY, _("Memory Card Manager"), wxDefaultPosition, wxDefaultSize, - wxCAPTION | wxSYSTEM_MENU | wxDIALOG_NO_PARENT | wxCLOSE_BOX | wxRESIZE_BORDER | wxMAXIMIZE_BOX) + : wxDialog(parent, wxID_ANY, _("Memory Card Manager"), wxDefaultPosition, wxDefaultSize, + wxCAPTION | wxSYSTEM_MENU | wxDIALOG_NO_PARENT | wxCLOSE_BOX | wxRESIZE_BORDER | + wxMAXIMIZE_BOX) { - memoryCard[SLOT_A] = nullptr; - memoryCard[SLOT_B] = nullptr; + memoryCard[SLOT_A] = nullptr; + memoryCard[SLOT_B] = nullptr; - mcmSettings.twoCardsLoaded = false; - if (!LoadSettings()) - { - itemsPerPage = 16; - mcmSettings.usePages = true; - for (int i = COLUMN_BANNER; i < NUMBER_OF_COLUMN; i++) - { - mcmSettings.column[i] = (i <= COLUMN_FIRSTBLOCK) ? true : false; - } - } - maxPages = (128 / itemsPerPage) - 1; - CreateGUIControls(); + mcmSettings.twoCardsLoaded = false; + if (!LoadSettings()) + { + itemsPerPage = 16; + mcmSettings.usePages = true; + for (int i = COLUMN_BANNER; i < NUMBER_OF_COLUMN; i++) + { + mcmSettings.column[i] = (i <= COLUMN_FIRSTBLOCK) ? true : false; + } + } + maxPages = (128 / itemsPerPage) - 1; + CreateGUIControls(); } CMemcardManager::~CMemcardManager() { - if (memoryCard[SLOT_A]) - { - delete memoryCard[SLOT_A]; - memoryCard[SLOT_A] = nullptr; - } - if (memoryCard[SLOT_B]) - { - delete memoryCard[SLOT_B]; - memoryCard[SLOT_B] = nullptr; - } - SaveSettings(); + if (memoryCard[SLOT_A]) + { + delete memoryCard[SLOT_A]; + memoryCard[SLOT_A] = nullptr; + } + if (memoryCard[SLOT_B]) + { + delete memoryCard[SLOT_B]; + memoryCard[SLOT_B] = nullptr; + } + SaveSettings(); } bool CMemcardManager::LoadSettings() { - if (MemcardManagerIni.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX))) - { - iniMemcardSection = MemcardManagerIni.GetOrCreateSection("MemcardManager"); - iniMemcardSection->Get("Items per page", &itemsPerPage, 16); - iniMemcardSection->Get("DefaultMemcardA", &(DefaultMemcard[SLOT_A]), ""); - iniMemcardSection->Get("DefaultMemcardB", &(DefaultMemcard[SLOT_B]), ""); - iniMemcardSection->Get("DefaultIOFolder", &DefaultIOPath, "/Users/GC"); + if (MemcardManagerIni.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX))) + { + iniMemcardSection = MemcardManagerIni.GetOrCreateSection("MemcardManager"); + iniMemcardSection->Get("Items per page", &itemsPerPage, 16); + iniMemcardSection->Get("DefaultMemcardA", &(DefaultMemcard[SLOT_A]), ""); + iniMemcardSection->Get("DefaultMemcardB", &(DefaultMemcard[SLOT_B]), ""); + iniMemcardSection->Get("DefaultIOFolder", &DefaultIOPath, "/Users/GC"); - iniMemcardSection->Get("Use Pages", &mcmSettings.usePages, true); - iniMemcardSection->Get("cBanner", &mcmSettings.column[COLUMN_BANNER], true); - iniMemcardSection->Get("cTitle", &mcmSettings.column[COLUMN_TITLE], true); - iniMemcardSection->Get("cComment", &mcmSettings.column[COLUMN_COMMENT], true); - iniMemcardSection->Get("cIcon", &mcmSettings.column[COLUMN_ICON], true); - iniMemcardSection->Get("cBlocks", &mcmSettings.column[COLUMN_BLOCKS], true); - iniMemcardSection->Get("cFirst Block", &mcmSettings.column[COLUMN_FIRSTBLOCK], true); + iniMemcardSection->Get("Use Pages", &mcmSettings.usePages, true); + iniMemcardSection->Get("cBanner", &mcmSettings.column[COLUMN_BANNER], true); + iniMemcardSection->Get("cTitle", &mcmSettings.column[COLUMN_TITLE], true); + iniMemcardSection->Get("cComment", &mcmSettings.column[COLUMN_COMMENT], true); + iniMemcardSection->Get("cIcon", &mcmSettings.column[COLUMN_ICON], true); + iniMemcardSection->Get("cBlocks", &mcmSettings.column[COLUMN_BLOCKS], true); + iniMemcardSection->Get("cFirst Block", &mcmSettings.column[COLUMN_FIRSTBLOCK], true); - mcmSettings.column[NUMBER_OF_COLUMN] = false; + mcmSettings.column[NUMBER_OF_COLUMN] = false; - for (int i = COLUMN_GAMECODE; i < NUMBER_OF_COLUMN; i++) - { - mcmSettings.column[i] = mcmSettings.column[NUMBER_OF_COLUMN]; - } - return true; - } - return false; + for (int i = COLUMN_GAMECODE; i < NUMBER_OF_COLUMN; i++) + { + mcmSettings.column[i] = mcmSettings.column[NUMBER_OF_COLUMN]; + } + return true; + } + return false; } bool CMemcardManager::SaveSettings() { - MemcardManagerIni.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); - iniMemcardSection = MemcardManagerIni.GetOrCreateSection("MemcardManager"); - iniMemcardSection->Set("Items per page", itemsPerPage, 16); - iniMemcardSection->Set("DefaultMemcardA", DefaultMemcard[SLOT_A], ""); - iniMemcardSection->Set("DefaultMemcardB", DefaultMemcard[SLOT_B], ""); + MemcardManagerIni.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); + iniMemcardSection = MemcardManagerIni.GetOrCreateSection("MemcardManager"); + iniMemcardSection->Set("Items per page", itemsPerPage, 16); + iniMemcardSection->Set("DefaultMemcardA", DefaultMemcard[SLOT_A], ""); + iniMemcardSection->Set("DefaultMemcardB", DefaultMemcard[SLOT_B], ""); - iniMemcardSection->Set("Use Pages", mcmSettings.usePages, true); - iniMemcardSection->Set("cBanner", mcmSettings.column[COLUMN_BANNER], true); - iniMemcardSection->Set("cTitle", mcmSettings.column[COLUMN_TITLE], true); - iniMemcardSection->Set("cComment", mcmSettings.column[COLUMN_COMMENT], true); - iniMemcardSection->Set("cIcon", mcmSettings.column[COLUMN_ICON], true); - iniMemcardSection->Set("cBlocks", mcmSettings.column[COLUMN_BLOCKS], true); - iniMemcardSection->Set("cFirst Block", mcmSettings.column[COLUMN_FIRSTBLOCK], true); + iniMemcardSection->Set("Use Pages", mcmSettings.usePages, true); + iniMemcardSection->Set("cBanner", mcmSettings.column[COLUMN_BANNER], true); + iniMemcardSection->Set("cTitle", mcmSettings.column[COLUMN_TITLE], true); + iniMemcardSection->Set("cComment", mcmSettings.column[COLUMN_COMMENT], true); + iniMemcardSection->Set("cIcon", mcmSettings.column[COLUMN_ICON], true); + iniMemcardSection->Set("cBlocks", mcmSettings.column[COLUMN_BLOCKS], true); + iniMemcardSection->Set("cFirst Block", mcmSettings.column[COLUMN_FIRSTBLOCK], true); - return MemcardManagerIni.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX)); + return MemcardManagerIni.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX)); } void CMemcardManager::CreateGUIControls() { - // Create the controls for both memcards + // Create the controls for both memcards - const char* ARROW[2] = { "<-", "->" }; + const char* ARROW[2] = {"<-", "->"}; - m_ConvertToGci = new wxButton(this, ID_CONVERTTOGCI, _("Convert to GCI")); + m_ConvertToGci = new wxButton(this, ID_CONVERTTOGCI, _("Convert to GCI")); - wxStaticBoxSizer *sMemcard[2]; + wxStaticBoxSizer* sMemcard[2]; - for (int slot = SLOT_A; slot <= SLOT_B; slot++) - { - m_CopyFrom[slot] = new wxButton(this, ID_COPYFROM_A + slot, - wxString::Format(_("%1$sCopy%1$s"), ARROW[slot ? 0 : 1])); - m_SaveImport[slot] = new wxButton(this, ID_SAVEIMPORT_A + slot, - wxString::Format(_("%sImport GCI%s"), ARROWS)); - m_SaveExport[slot] = new wxButton(this, ID_SAVEEXPORT_A + slot, - wxString::Format(_("%sExport GCI%s"), ARROWS)); - m_Delete[slot] = new wxButton(this, ID_DELETE_A + slot, - wxString::Format(_("%sDelete%s"), ARROWS)); + for (int slot = SLOT_A; slot <= SLOT_B; slot++) + { + m_CopyFrom[slot] = new wxButton(this, ID_COPYFROM_A + slot, + wxString::Format(_("%1$sCopy%1$s"), ARROW[slot ? 0 : 1])); + m_SaveImport[slot] = + new wxButton(this, ID_SAVEIMPORT_A + slot, wxString::Format(_("%sImport GCI%s"), ARROWS)); + m_SaveExport[slot] = + new wxButton(this, ID_SAVEEXPORT_A + slot, wxString::Format(_("%sExport GCI%s"), ARROWS)); + m_Delete[slot] = + new wxButton(this, ID_DELETE_A + slot, wxString::Format(_("%sDelete%s"), ARROWS)); + m_PrevPage[slot] = new wxButton(this, ID_PREVPAGE_A + slot, _("Prev Page")); + m_NextPage[slot] = new wxButton(this, ID_NEXTPAGE_A + slot, _("Next Page")); - m_PrevPage[slot] = new wxButton(this, ID_PREVPAGE_A + slot, _("Prev Page")); - m_NextPage[slot] = new wxButton(this, ID_NEXTPAGE_A + slot, _("Next Page")); + t_Status[slot] = new wxStaticText(this, 0, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, + wxEmptyString); - t_Status[slot] = new wxStaticText(this, 0, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxEmptyString); + wxBoxSizer* const sPages = new wxBoxSizer(wxHORIZONTAL); + sPages->Add(m_PrevPage[slot], 0, wxEXPAND | wxALL, 1); + sPages->Add(t_Status[slot], 0, wxEXPAND | wxALL, 5); + sPages->Add(0, 0, 1, wxEXPAND | wxALL, 0); + sPages->Add(m_NextPage[slot], 0, wxEXPAND | wxALL, 1); - wxBoxSizer * const sPages = new wxBoxSizer(wxHORIZONTAL); - sPages->Add(m_PrevPage[slot], 0, wxEXPAND | wxALL, 1); - sPages->Add(t_Status[slot], 0, wxEXPAND | wxALL, 5); - sPages->Add(0, 0, 1, wxEXPAND|wxALL, 0); - sPages->Add(m_NextPage[slot], 0, wxEXPAND | wxALL, 1); + m_MemcardPath[slot] = new wxFilePickerCtrl( + this, ID_MEMCARDPATH_A + slot, StrToWxStr(File::GetUserPath(D_GCUSER_IDX)), + _("Choose a memory card:"), + _("GameCube Memory Cards (*.raw,*.gcp)") + wxString("|*.raw;*.gcp"), wxDefaultPosition, + wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN); - m_MemcardPath[slot] = new wxFilePickerCtrl(this, ID_MEMCARDPATH_A + slot, - StrToWxStr(File::GetUserPath(D_GCUSER_IDX)), _("Choose a memory card:"), - _("GameCube Memory Cards (*.raw,*.gcp)") + wxString("|*.raw;*.gcp"), wxDefaultPosition, wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN); + m_MemcardList[slot] = new CMemcardListCtrl( + this, ID_MEMCARDLIST_A + slot, wxDefaultPosition, wxSize(350, 400), + wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT | wxLC_SINGLE_SEL, mcmSettings); - m_MemcardList[slot] = new CMemcardListCtrl(this, ID_MEMCARDLIST_A + slot, wxDefaultPosition, wxSize(350, 400), - wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT | wxLC_SINGLE_SEL, mcmSettings); + m_MemcardList[slot]->AssignImageList(new wxImageList(96, 32), wxIMAGE_LIST_SMALL); - m_MemcardList[slot]->AssignImageList(new wxImageList(96, 32), wxIMAGE_LIST_SMALL); + sMemcard[slot] = new wxStaticBoxSizer(wxVERTICAL, this, + _("Memory Card") + wxString::Format(" %c", 'A' + slot)); + sMemcard[slot]->Add(m_MemcardPath[slot], 0, wxEXPAND | wxALL, 5); + sMemcard[slot]->Add(m_MemcardList[slot], 1, wxEXPAND | wxALL, 5); + sMemcard[slot]->Add(sPages, 0, wxEXPAND | wxALL, 1); + } - sMemcard[slot] = new wxStaticBoxSizer(wxVERTICAL, this, _("Memory Card") + wxString::Format(" %c", 'A' + slot)); - sMemcard[slot]->Add(m_MemcardPath[slot], 0, wxEXPAND | wxALL, 5); - sMemcard[slot]->Add(m_MemcardList[slot], 1, wxEXPAND | wxALL, 5); - sMemcard[slot]->Add(sPages, 0, wxEXPAND | wxALL, 1); - } + wxBoxSizer* const sButtons = new wxBoxSizer(wxVERTICAL); + sButtons->AddStretchSpacer(2); + sButtons->Add(m_CopyFrom[SLOT_B], 0, wxEXPAND, 5); + sButtons->Add(m_CopyFrom[SLOT_A], 0, wxEXPAND, 5); + sButtons->AddStretchSpacer(1); + sButtons->Add(m_SaveImport[SLOT_A], 0, wxEXPAND, 5); + sButtons->Add(m_SaveExport[SLOT_A], 0, wxEXPAND, 5); + sButtons->AddStretchSpacer(1); + sButtons->Add(m_ConvertToGci, 0, wxEXPAND, 5); + sButtons->AddStretchSpacer(1); + sButtons->Add(m_SaveImport[SLOT_B], 0, wxEXPAND, 5); + sButtons->Add(m_SaveExport[SLOT_B], 0, wxEXPAND, 5); + sButtons->AddStretchSpacer(1); + sButtons->Add(m_Delete[SLOT_A], 0, wxEXPAND, 5); + sButtons->Add(m_Delete[SLOT_B], 0, wxEXPAND, 5); + sButtons->AddStretchSpacer(); + sButtons->Add(new wxButton(this, wxID_OK, _("Close")), 0, wxEXPAND, 5); + sButtons->AddStretchSpacer(); - wxBoxSizer * const sButtons = new wxBoxSizer(wxVERTICAL); - sButtons->AddStretchSpacer(2); - sButtons->Add(m_CopyFrom[SLOT_B], 0, wxEXPAND, 5); - sButtons->Add(m_CopyFrom[SLOT_A], 0, wxEXPAND, 5); - sButtons->AddStretchSpacer(1); - sButtons->Add(m_SaveImport[SLOT_A], 0, wxEXPAND, 5); - sButtons->Add(m_SaveExport[SLOT_A], 0, wxEXPAND, 5); - sButtons->AddStretchSpacer(1); - sButtons->Add(m_ConvertToGci, 0, wxEXPAND, 5); - sButtons->AddStretchSpacer(1); - sButtons->Add(m_SaveImport[SLOT_B], 0, wxEXPAND, 5); - sButtons->Add(m_SaveExport[SLOT_B], 0, wxEXPAND, 5); - sButtons->AddStretchSpacer(1); - sButtons->Add(m_Delete[SLOT_A], 0, wxEXPAND, 5); - sButtons->Add(m_Delete[SLOT_B], 0, wxEXPAND, 5); - sButtons->AddStretchSpacer(); - sButtons->Add(new wxButton(this, wxID_OK, _("Close")), 0, wxEXPAND, 5); - sButtons->AddStretchSpacer(); + wxBoxSizer* const sMain = new wxBoxSizer(wxHORIZONTAL); + sMain->Add(sMemcard[SLOT_A], 1, wxEXPAND | wxALL, 5); + sMain->Add(sButtons, 0, wxEXPAND, 0); + sMain->Add(sMemcard[SLOT_B], 1, wxEXPAND | wxALL, 5); - wxBoxSizer * const sMain = new wxBoxSizer(wxHORIZONTAL); - sMain->Add(sMemcard[SLOT_A], 1, wxEXPAND | wxALL, 5); - sMain->Add(sButtons, 0, wxEXPAND, 0); - sMain->Add(sMemcard[SLOT_B], 1, wxEXPAND | wxALL, 5); + SetSizerAndFit(sMain); + Center(); - SetSizerAndFit(sMain); - Center(); - - for (int i = SLOT_A; i <= SLOT_B; i++) - { - m_PrevPage[i]->Disable(); - m_NextPage[i]->Disable(); - m_CopyFrom[i]->Disable(); - m_SaveImport[i]->Disable(); - m_SaveExport[i]->Disable(); - m_Delete[i]->Disable(); - if (DefaultMemcard[i].length()) - { - m_MemcardPath[i]->SetPath(StrToWxStr(DefaultMemcard[i])); - ChangePath(i); - } - } + for (int i = SLOT_A; i <= SLOT_B; i++) + { + m_PrevPage[i]->Disable(); + m_NextPage[i]->Disable(); + m_CopyFrom[i]->Disable(); + m_SaveImport[i]->Disable(); + m_SaveExport[i]->Disable(); + m_Delete[i]->Disable(); + if (DefaultMemcard[i].length()) + { + m_MemcardPath[i]->SetPath(StrToWxStr(DefaultMemcard[i])); + ChangePath(i); + } + } } void CMemcardManager::OnPathChange(wxFileDirPickerEvent& event) { - ChangePath(event.GetId() - ID_MEMCARDPATH_A); + ChangePath(event.GetId() - ID_MEMCARDPATH_A); } void CMemcardManager::ChangePath(int slot) { - int slot2 = (slot == SLOT_A) ? SLOT_B : SLOT_A; - page[slot] = FIRSTPAGE; - if (mcmSettings.usePages && m_PrevPage[slot]->IsEnabled()) - { - m_PrevPage[slot]->Disable(); - m_MemcardList[slot]->prevPage = false; - } - if (!m_MemcardPath[SLOT_A]->GetPath().CmpNoCase(m_MemcardPath[SLOT_B]->GetPath())) - { - if (m_MemcardPath[slot]->GetPath().length()) - wxMessageBox(_("Memcard already opened")); - } - else - { - if (m_MemcardPath[slot]->GetPath().length() && ReloadMemcard(WxStrToStr(m_MemcardPath[slot]->GetPath()), slot)) - { - if (memoryCard[slot2]) - { - mcmSettings.twoCardsLoaded = true; - } - m_SaveImport[slot]->Enable(); - m_SaveExport[slot]->Enable(); - m_Delete[slot]->Enable(); - } - else - { - if (memoryCard[slot]) - { - delete memoryCard[slot]; - memoryCard[slot] = nullptr; - } - mcmSettings.twoCardsLoaded = false; - m_MemcardPath[slot]->SetPath(wxEmptyString); - m_MemcardList[slot]->ClearAll(); - t_Status[slot]->SetLabel(wxEmptyString); - m_SaveImport[slot]->Disable(); - m_SaveExport[slot]->Disable(); - m_Delete[slot]->Disable(); - if (mcmSettings.usePages) - { - m_PrevPage[slot]->Disable(); - m_NextPage[slot]->Disable(); - } - } - } + int slot2 = (slot == SLOT_A) ? SLOT_B : SLOT_A; + page[slot] = FIRSTPAGE; + if (mcmSettings.usePages && m_PrevPage[slot]->IsEnabled()) + { + m_PrevPage[slot]->Disable(); + m_MemcardList[slot]->prevPage = false; + } + if (!m_MemcardPath[SLOT_A]->GetPath().CmpNoCase(m_MemcardPath[SLOT_B]->GetPath())) + { + if (m_MemcardPath[slot]->GetPath().length()) + wxMessageBox(_("Memcard already opened")); + } + else + { + if (m_MemcardPath[slot]->GetPath().length() && + ReloadMemcard(WxStrToStr(m_MemcardPath[slot]->GetPath()), slot)) + { + if (memoryCard[slot2]) + { + mcmSettings.twoCardsLoaded = true; + } + m_SaveImport[slot]->Enable(); + m_SaveExport[slot]->Enable(); + m_Delete[slot]->Enable(); + } + else + { + if (memoryCard[slot]) + { + delete memoryCard[slot]; + memoryCard[slot] = nullptr; + } + mcmSettings.twoCardsLoaded = false; + m_MemcardPath[slot]->SetPath(wxEmptyString); + m_MemcardList[slot]->ClearAll(); + t_Status[slot]->SetLabel(wxEmptyString); + m_SaveImport[slot]->Disable(); + m_SaveExport[slot]->Disable(); + m_Delete[slot]->Disable(); + if (mcmSettings.usePages) + { + m_PrevPage[slot]->Disable(); + m_NextPage[slot]->Disable(); + } + } + } - m_CopyFrom[SLOT_A]->Enable(mcmSettings.twoCardsLoaded); - m_CopyFrom[SLOT_B]->Enable(mcmSettings.twoCardsLoaded); + m_CopyFrom[SLOT_A]->Enable(mcmSettings.twoCardsLoaded); + m_CopyFrom[SLOT_B]->Enable(mcmSettings.twoCardsLoaded); } void CMemcardManager::OnPageChange(wxCommandEvent& event) { - int slot = SLOT_B; - switch (event.GetId()) - { - case ID_NEXTPAGE_A: - slot = SLOT_A; - case ID_NEXTPAGE_B: - if (!m_PrevPage[slot]->IsEnabled()) - { - m_PrevPage[slot]->Enable(); - m_MemcardList[slot]->prevPage = true; - } - page[slot]++; - if (page[slot] == maxPages) - { - m_NextPage[slot]->Disable(); - m_MemcardList[slot]->nextPage = false; - } - ReloadMemcard(WxStrToStr(m_MemcardPath[slot]->GetPath()), slot); - break; - case ID_PREVPAGE_A: - slot = SLOT_A; - case ID_PREVPAGE_B: - if (!m_NextPage[slot]->IsEnabled()) - { - m_NextPage[slot]->Enable(); - m_MemcardList[slot]->nextPage = true; - } - page[slot]--; - if (!page[slot]) - { - m_PrevPage[slot]->Disable(); - m_MemcardList[slot]->prevPage = false; - } - ReloadMemcard(WxStrToStr(m_MemcardPath[slot]->GetPath()), slot); - break; - } + int slot = SLOT_B; + switch (event.GetId()) + { + case ID_NEXTPAGE_A: + slot = SLOT_A; + case ID_NEXTPAGE_B: + if (!m_PrevPage[slot]->IsEnabled()) + { + m_PrevPage[slot]->Enable(); + m_MemcardList[slot]->prevPage = true; + } + page[slot]++; + if (page[slot] == maxPages) + { + m_NextPage[slot]->Disable(); + m_MemcardList[slot]->nextPage = false; + } + ReloadMemcard(WxStrToStr(m_MemcardPath[slot]->GetPath()), slot); + break; + case ID_PREVPAGE_A: + slot = SLOT_A; + case ID_PREVPAGE_B: + if (!m_NextPage[slot]->IsEnabled()) + { + m_NextPage[slot]->Enable(); + m_MemcardList[slot]->nextPage = true; + } + page[slot]--; + if (!page[slot]) + { + m_PrevPage[slot]->Disable(); + m_MemcardList[slot]->prevPage = false; + } + ReloadMemcard(WxStrToStr(m_MemcardPath[slot]->GetPath()), slot); + break; + } } void CMemcardManager::OnMenuChange(wxCommandEvent& event) { - int _id = event.GetId(); - switch (_id) - { - case ID_MEMCARDPATH_A: - case ID_MEMCARDPATH_B: - DefaultMemcard[_id - ID_MEMCARDPATH_A] = WxStrToStr(m_MemcardPath[_id - ID_MEMCARDPATH_A]->GetPath()); - return; - case ID_USEPAGES: - mcmSettings.usePages = !mcmSettings.usePages; - if (!mcmSettings.usePages) - { - m_PrevPage[SLOT_A]->Disable(); - m_PrevPage[SLOT_B]->Disable(); - m_NextPage[SLOT_A]->Disable(); - m_NextPage[SLOT_B]->Disable(); - m_MemcardList[SLOT_A]->prevPage = - m_MemcardList[SLOT_B]->prevPage = false; - page[SLOT_A] = - page[SLOT_B] = FIRSTPAGE; - } - break; - case NUMBER_OF_COLUMN: - for (int i = COLUMN_GAMECODE; i <= NUMBER_OF_COLUMN; i++) - { - mcmSettings.column[i] = !mcmSettings.column[i]; - } - break; - default: - mcmSettings.column[_id] = !mcmSettings.column[_id]; - break; - } + int _id = event.GetId(); + switch (_id) + { + case ID_MEMCARDPATH_A: + case ID_MEMCARDPATH_B: + DefaultMemcard[_id - ID_MEMCARDPATH_A] = + WxStrToStr(m_MemcardPath[_id - ID_MEMCARDPATH_A]->GetPath()); + return; + case ID_USEPAGES: + mcmSettings.usePages = !mcmSettings.usePages; + if (!mcmSettings.usePages) + { + m_PrevPage[SLOT_A]->Disable(); + m_PrevPage[SLOT_B]->Disable(); + m_NextPage[SLOT_A]->Disable(); + m_NextPage[SLOT_B]->Disable(); + m_MemcardList[SLOT_A]->prevPage = m_MemcardList[SLOT_B]->prevPage = false; + page[SLOT_A] = page[SLOT_B] = FIRSTPAGE; + } + break; + case NUMBER_OF_COLUMN: + for (int i = COLUMN_GAMECODE; i <= NUMBER_OF_COLUMN; i++) + { + mcmSettings.column[i] = !mcmSettings.column[i]; + } + break; + default: + mcmSettings.column[_id] = !mcmSettings.column[_id]; + break; + } - if (memoryCard[SLOT_A]) ReloadMemcard(WxStrToStr(m_MemcardPath[SLOT_A]->GetPath()), SLOT_A); - if (memoryCard[SLOT_B]) ReloadMemcard(WxStrToStr(m_MemcardPath[SLOT_B]->GetPath()), SLOT_B); + if (memoryCard[SLOT_A]) + ReloadMemcard(WxStrToStr(m_MemcardPath[SLOT_A]->GetPath()), SLOT_A); + if (memoryCard[SLOT_B]) + ReloadMemcard(WxStrToStr(m_MemcardPath[SLOT_B]->GetPath()), SLOT_B); } bool CMemcardManager::CopyDeleteSwitch(u32 error, int slot) { - switch (error) - { - case GCS: - wxMessageBox(_("File converted to .gci")); - break; - case SUCCESS: - if (slot != -1) - { - memoryCard[slot]->FixChecksums(); - if (!memoryCard[slot]->Save()) PanicAlertT("File write failed"); - page[slot] = FIRSTPAGE; - ReloadMemcard(WxStrToStr(m_MemcardPath[slot]->GetPath()), slot); - } - break; - case NOMEMCARD: - WxUtils::ShowErrorDialog(_("File is not recognized as a memcard")); - break; - case OPENFAIL: - WxUtils::ShowErrorDialog(_("File could not be opened\nor does not have a valid extension")); - break; - case OUTOFBLOCKS: - if (slot == -1) - { - WxUtils::ShowErrorDialog(_("Unknown memory card error")); - break; - } - wxMessageBox(wxString::Format(_("Only %d blocks available"), memoryCard[slot]->GetFreeBlocks())); - break; - case OUTOFDIRENTRIES: - WxUtils::ShowErrorDialog(_("No free directory index entries.")); - break; - case LENGTHFAIL: - WxUtils::ShowErrorDialog(_("Imported file has invalid length.")); - break; - case INVALIDFILESIZE: - WxUtils::ShowErrorDialog(_("The save you are trying to copy has an invalid file size.")); - break; - case TITLEPRESENT: - WxUtils::ShowErrorDialog(_("Memcard already has a save for this title.")); - break; - case SAVFAIL: - WxUtils::ShowErrorDialog(_("Imported file has sav extension\nbut does not have a correct header.")); - break; - case GCSFAIL: - WxUtils::ShowErrorDialog(_("Imported file has gsc extension\nbut does not have a correct header.")); - break; - case FAIL: - if (slot == -1) - { - WxUtils::ShowErrorDialog(_("Export failed")); - return false; - } - WxUtils::ShowErrorDialog(_("Invalid bat.map or dir entry.")); - break; - case WRITEFAIL: - WxUtils::ShowErrorDialog(_("File write failed")); - break; - case DELETE_FAIL: - WxUtils::ShowErrorDialog(_("Order of files in the File Directory do not match the block order\n" - "Right click and export all of the saves,\nand import the saves to a new memcard\n")); - break; - default: - WxUtils::ShowErrorDialog(_("Unknown memory card error")); - break; - } - SetFocus(); - return true; + switch (error) + { + case GCS: + wxMessageBox(_("File converted to .gci")); + break; + case SUCCESS: + if (slot != -1) + { + memoryCard[slot]->FixChecksums(); + if (!memoryCard[slot]->Save()) + PanicAlertT("File write failed"); + page[slot] = FIRSTPAGE; + ReloadMemcard(WxStrToStr(m_MemcardPath[slot]->GetPath()), slot); + } + break; + case NOMEMCARD: + WxUtils::ShowErrorDialog(_("File is not recognized as a memcard")); + break; + case OPENFAIL: + WxUtils::ShowErrorDialog(_("File could not be opened\nor does not have a valid extension")); + break; + case OUTOFBLOCKS: + if (slot == -1) + { + WxUtils::ShowErrorDialog(_("Unknown memory card error")); + break; + } + wxMessageBox( + wxString::Format(_("Only %d blocks available"), memoryCard[slot]->GetFreeBlocks())); + break; + case OUTOFDIRENTRIES: + WxUtils::ShowErrorDialog(_("No free directory index entries.")); + break; + case LENGTHFAIL: + WxUtils::ShowErrorDialog(_("Imported file has invalid length.")); + break; + case INVALIDFILESIZE: + WxUtils::ShowErrorDialog(_("The save you are trying to copy has an invalid file size.")); + break; + case TITLEPRESENT: + WxUtils::ShowErrorDialog(_("Memcard already has a save for this title.")); + break; + case SAVFAIL: + WxUtils::ShowErrorDialog( + _("Imported file has sav extension\nbut does not have a correct header.")); + break; + case GCSFAIL: + WxUtils::ShowErrorDialog( + _("Imported file has gsc extension\nbut does not have a correct header.")); + break; + case FAIL: + if (slot == -1) + { + WxUtils::ShowErrorDialog(_("Export failed")); + return false; + } + WxUtils::ShowErrorDialog(_("Invalid bat.map or dir entry.")); + break; + case WRITEFAIL: + WxUtils::ShowErrorDialog(_("File write failed")); + break; + case DELETE_FAIL: + WxUtils::ShowErrorDialog( + _("Order of files in the File Directory do not match the block order\n" + "Right click and export all of the saves,\nand import the saves to a new memcard\n")); + break; + default: + WxUtils::ShowErrorDialog(_("Unknown memory card error")); + break; + } + SetFocus(); + return true; } void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) { - int index_A = m_MemcardList[SLOT_A]->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - int index_B = m_MemcardList[SLOT_B]->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - int slot = SLOT_B; - int slot2 = SLOT_A; - std::string fileName2(""); + int index_A = m_MemcardList[SLOT_A]->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + int index_B = m_MemcardList[SLOT_B]->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + int slot = SLOT_B; + int slot2 = SLOT_A; + std::string fileName2(""); - if (index_A != wxNOT_FOUND && page[SLOT_A]) index_A += itemsPerPage * page[SLOT_A]; - if (index_B != wxNOT_FOUND && page[SLOT_B]) index_B += itemsPerPage * page[SLOT_B]; + if (index_A != wxNOT_FOUND && page[SLOT_A]) + index_A += itemsPerPage * page[SLOT_A]; + if (index_B != wxNOT_FOUND && page[SLOT_B]) + index_B += itemsPerPage * page[SLOT_B]; - int index = index_B; - switch (event.GetId()) - { - case ID_COPYFROM_B: - slot = SLOT_A; - slot2 = SLOT_B; - case ID_COPYFROM_A: - index = slot2 ? index_B : index_A; - index = memoryCard[slot2]->GetFileIndex(index); - if ((index != wxNOT_FOUND)) - { - CopyDeleteSwitch(memoryCard[slot]->CopyFrom(*memoryCard[slot2], index), slot); - } - break; - case ID_FIXCHECKSUM_A: - slot = SLOT_A; - case ID_FIXCHECKSUM_B: - if (memoryCard[slot]->FixChecksums() && memoryCard[slot]->Save()) - { - wxMessageBox(_("The checksum was successfully fixed.")); - } - else - { - WxUtils::ShowErrorDialog(_("File write failed")); - } - break; - case ID_CONVERTTOGCI: - fileName2 = "convert"; - case ID_SAVEIMPORT_A: - slot = SLOT_A; - case ID_SAVEIMPORT_B: - { - wxString fileName = wxFileSelector( - _("Select a save file to import"), - (strcmp(DefaultIOPath.c_str(), "/Users/GC") == 0) - ? StrToWxStr("") - : StrToWxStr(DefaultIOPath), - wxEmptyString, wxEmptyString, - _("GameCube Savegame files(*.gci;*.gcs;*.sav)") + wxString("|*.gci;*.gcs;*.sav|") + - _("Native GCI files(*.gci)") + wxString("|*.gci|") + - _("MadCatz Gameshark files(*.gcs)") + wxString("|*.gcs|") + - _("Datel MaxDrive/Pro files(*.sav)") + wxString("|*.sav"), - wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); - if (!fileName.empty() && !fileName2.empty()) - { - wxString temp2 = wxFileSelector(_("Save GCI as..."), - wxEmptyString, wxEmptyString, ".gci", - _("GCI File(*.gci)") + wxString("|*.gci"), - wxFD_OVERWRITE_PROMPT | wxFD_SAVE, this); + int index = index_B; + switch (event.GetId()) + { + case ID_COPYFROM_B: + slot = SLOT_A; + slot2 = SLOT_B; + case ID_COPYFROM_A: + index = slot2 ? index_B : index_A; + index = memoryCard[slot2]->GetFileIndex(index); + if ((index != wxNOT_FOUND)) + { + CopyDeleteSwitch(memoryCard[slot]->CopyFrom(*memoryCard[slot2], index), slot); + } + break; + case ID_FIXCHECKSUM_A: + slot = SLOT_A; + case ID_FIXCHECKSUM_B: + if (memoryCard[slot]->FixChecksums() && memoryCard[slot]->Save()) + { + wxMessageBox(_("The checksum was successfully fixed.")); + } + else + { + WxUtils::ShowErrorDialog(_("File write failed")); + } + break; + case ID_CONVERTTOGCI: + fileName2 = "convert"; + case ID_SAVEIMPORT_A: + slot = SLOT_A; + case ID_SAVEIMPORT_B: + { + wxString fileName = wxFileSelector( + _("Select a save file to import"), + (strcmp(DefaultIOPath.c_str(), "/Users/GC") == 0) ? StrToWxStr("") : + StrToWxStr(DefaultIOPath), + wxEmptyString, wxEmptyString, + _("GameCube Savegame files(*.gci;*.gcs;*.sav)") + wxString("|*.gci;*.gcs;*.sav|") + + _("Native GCI files(*.gci)") + wxString("|*.gci|") + + _("MadCatz Gameshark files(*.gcs)") + wxString("|*.gcs|") + + _("Datel MaxDrive/Pro files(*.sav)") + wxString("|*.sav"), + wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); + if (!fileName.empty() && !fileName2.empty()) + { + wxString temp2 = wxFileSelector(_("Save GCI as..."), wxEmptyString, wxEmptyString, ".gci", + _("GCI File(*.gci)") + wxString("|*.gci"), + wxFD_OVERWRITE_PROMPT | wxFD_SAVE, this); - if (temp2.empty()) - break; + if (temp2.empty()) + break; - fileName2 = WxStrToStr(temp2); - } - if (fileName.length() > 0) - { - CopyDeleteSwitch(memoryCard[slot]->ImportGci(WxStrToStr(fileName), fileName2), slot); - } - } - break; - case ID_SAVEEXPORT_A: - slot = SLOT_A; - index = index_A; - case ID_SAVEEXPORT_B: - index = memoryCard[slot]->GetFileIndex(index); - if (index != wxNOT_FOUND) - { - std::string gciFilename; - if (!memoryCard[slot]->GCI_FileName(index, gciFilename)) - { - wxMessageBox(_("Invalid index"), _("Error")); - return; - } - wxString fileName = wxFileSelector( - _("Export save as..."), - StrToWxStr(DefaultIOPath), - StrToWxStr(gciFilename), ".gci", - _("Native GCI files(*.gci)") + wxString("|*.gci|") + - _("MadCatz Gameshark files(*.gcs)") + wxString("|*.gcs|") + - _("Datel MaxDrive/Pro files(*.sav)") + wxString("|*.sav"), - wxFD_OVERWRITE_PROMPT | wxFD_SAVE, this); + fileName2 = WxStrToStr(temp2); + } + if (fileName.length() > 0) + { + CopyDeleteSwitch(memoryCard[slot]->ImportGci(WxStrToStr(fileName), fileName2), slot); + } + } + break; + case ID_SAVEEXPORT_A: + slot = SLOT_A; + index = index_A; + case ID_SAVEEXPORT_B: + index = memoryCard[slot]->GetFileIndex(index); + if (index != wxNOT_FOUND) + { + std::string gciFilename; + if (!memoryCard[slot]->GCI_FileName(index, gciFilename)) + { + wxMessageBox(_("Invalid index"), _("Error")); + return; + } + wxString fileName = wxFileSelector( + _("Export save as..."), StrToWxStr(DefaultIOPath), StrToWxStr(gciFilename), ".gci", + _("Native GCI files(*.gci)") + wxString("|*.gci|") + _("MadCatz Gameshark files(*.gcs)") + + wxString("|*.gcs|") + _("Datel MaxDrive/Pro files(*.sav)") + wxString("|*.sav"), + wxFD_OVERWRITE_PROMPT | wxFD_SAVE, this); - if (fileName.length() > 0) - { - if (!CopyDeleteSwitch(memoryCard[slot]->ExportGci(index, WxStrToStr(fileName), ""), -1)) - { - File::Delete(WxStrToStr(fileName)); - } - } - } - break; - case ID_EXPORTALL_A: - slot = SLOT_A; - case ID_EXPORTALL_B: - { - std::string path1, path2, mpath; - mpath = WxStrToStr(m_MemcardPath[slot]->GetPath()); - SplitPath(mpath, &path1, &path2, nullptr); - path1 += path2; - File::CreateDir(path1); + if (fileName.length() > 0) + { + if (!CopyDeleteSwitch(memoryCard[slot]->ExportGci(index, WxStrToStr(fileName), ""), -1)) + { + File::Delete(WxStrToStr(fileName)); + } + } + } + break; + case ID_EXPORTALL_A: + slot = SLOT_A; + case ID_EXPORTALL_B: + { + std::string path1, path2, mpath; + mpath = WxStrToStr(m_MemcardPath[slot]->GetPath()); + SplitPath(mpath, &path1, &path2, nullptr); + path1 += path2; + File::CreateDir(path1); - int answer = wxMessageBox(wxString::Format(_("Warning: This will overwrite any existing saves that are in the folder:\n" - "%s\nand have the same name as a file on your memcard\nContinue?"), path1.c_str()), _("Warning"), wxYES_NO); - if (answer == wxYES) - { - for (int i = 0; i < DIRLEN; i++) - { - CopyDeleteSwitch(memoryCard[slot]->ExportGci(i, "", path1), -1); - } - } + int answer = wxMessageBox( + wxString::Format( + _("Warning: This will overwrite any existing saves that are in the folder:\n" + "%s\nand have the same name as a file on your memcard\nContinue?"), + path1.c_str()), + _("Warning"), wxYES_NO); + if (answer == wxYES) + { + for (int i = 0; i < DIRLEN; i++) + { + CopyDeleteSwitch(memoryCard[slot]->ExportGci(i, "", path1), -1); + } + } - break; - } - case ID_DELETE_A: - slot = SLOT_A; - index = index_A; - case ID_DELETE_B: - index = memoryCard[slot]->GetFileIndex(index); - if (index != wxNOT_FOUND) - { - CopyDeleteSwitch(memoryCard[slot]->RemoveFile(index), slot); - } - break; - } + break; + } + case ID_DELETE_A: + slot = SLOT_A; + index = index_A; + case ID_DELETE_B: + index = memoryCard[slot]->GetFileIndex(index); + if (index != wxNOT_FOUND) + { + CopyDeleteSwitch(memoryCard[slot]->RemoveFile(index), slot); + } + break; + } } bool CMemcardManager::ReloadMemcard(const std::string& fileName, int card) { - if (memoryCard[card]) delete memoryCard[card]; + if (memoryCard[card]) + delete memoryCard[card]; - // TODO: add error checking and animate icons - memoryCard[card] = new GCMemcard(fileName); + // TODO: add error checking and animate icons + memoryCard[card] = new GCMemcard(fileName); - if (!memoryCard[card]->IsValid()) - return false; + if (!memoryCard[card]->IsValid()) + return false; - int j; + int j; - wxString wxTitle, - wxComment, - wxBlock, - wxFirstBlock, - wxLabel; + wxString wxTitle, wxComment, wxBlock, wxFirstBlock, wxLabel; + m_MemcardList[card]->Hide(); + m_MemcardList[card]->ClearAll(); - m_MemcardList[card]->Hide(); - m_MemcardList[card]->ClearAll(); + m_MemcardList[card]->InsertColumn(COLUMN_BANNER, _("Banner")); + m_MemcardList[card]->InsertColumn(COLUMN_TITLE, _("Title")); + m_MemcardList[card]->InsertColumn(COLUMN_COMMENT, _("Comment")); + m_MemcardList[card]->InsertColumn(COLUMN_ICON, _("Icon")); + m_MemcardList[card]->InsertColumn(COLUMN_BLOCKS, _("Blocks")); + m_MemcardList[card]->InsertColumn(COLUMN_FIRSTBLOCK, _("First Block")); - m_MemcardList[card]->InsertColumn(COLUMN_BANNER, _("Banner")); - m_MemcardList[card]->InsertColumn(COLUMN_TITLE, _("Title")); - m_MemcardList[card]->InsertColumn(COLUMN_COMMENT, _("Comment")); - m_MemcardList[card]->InsertColumn(COLUMN_ICON, _("Icon")); - m_MemcardList[card]->InsertColumn(COLUMN_BLOCKS, _("Blocks")); - m_MemcardList[card]->InsertColumn(COLUMN_FIRSTBLOCK, _("First Block")); + wxImageList* list = m_MemcardList[card]->GetImageList(wxIMAGE_LIST_SMALL); + list->RemoveAll(); - wxImageList *list = m_MemcardList[card]->GetImageList(wxIMAGE_LIST_SMALL); - list->RemoveAll(); + u8 nFiles = memoryCard[card]->GetNumFiles(); + std::vector images(nFiles * 2); - u8 nFiles = memoryCard[card]->GetNumFiles(); - std::vector images(nFiles * 2); + for (u8 i = 0; i < nFiles; i++) + { + static u32 pxdata[96 * 32]; + static u8 animDelay[8]; + static u32 animData[32 * 32 * 8]; - for (u8 i = 0; i < nFiles; i++) - { - static u32 pxdata[96*32]; - static u8 animDelay[8]; - static u32 animData[32*32*8]; + u8 fileIndex = memoryCard[card]->GetFileIndex(i); + int numFrames = memoryCard[card]->ReadAnimRGBA8(fileIndex, animData, animDelay); - u8 fileIndex = memoryCard[card]->GetFileIndex(i); - int numFrames = memoryCard[card]->ReadAnimRGBA8(fileIndex, animData, animDelay); + if (!memoryCard[card]->ReadBannerRGBA8(fileIndex, pxdata)) + { + memset(pxdata, 0, 96 * 32 * 4); - if (!memoryCard[card]->ReadBannerRGBA8(fileIndex, pxdata)) - { - memset(pxdata, 0, 96*32*4); + if (numFrames > 0) // Just use the first one + { + u32* icdata = animData; - if (numFrames > 0) // Just use the first one - { - u32 *icdata = animData; + for (int y = 0; y < 32; y++) + { + for (int x = 0; x < 32; x++) + { + pxdata[y * 96 + x + 32] = icdata[y * 32 + x]; // | 0xFF000000 + } + } + } + } - for (int y = 0; y < 32; y++) - { - for (int x = 0; x < 32; x++) - { - pxdata[y*96 + x + 32] = icdata[y*32 + x];// | 0xFF000000 - } - } - } - } + wxBitmap map = wxBitmapFromMemoryRGBA((u8*)pxdata, 96, 32); + images[i * 2] = list->Add(map); - wxBitmap map = wxBitmapFromMemoryRGBA((u8*)pxdata, 96, 32); - images[i*2] = list->Add(map); + if (numFrames > 0) + { + memset(pxdata, 0, 96 * 32 * 4); + int frames = 3; - if (numFrames > 0) - { - memset(pxdata, 0, 96*32*4); - int frames = 3; + if (numFrames < frames) + frames = numFrames; - if (numFrames < frames) - frames = numFrames; + for (int f = 0; f < frames; f++) + { + for (int y = 0; y < 32; y++) + { + for (int x = 0; x < 32; x++) + { + pxdata[y * 96 + x + 32 * f] = animData[f * 32 * 32 + y * 32 + x]; + } + } + } + wxBitmap icon = wxBitmapFromMemoryRGBA((u8*)pxdata, 96, 32); + images[i * 2 + 1] = list->Add(icon); + } + } - for (int f = 0; f < frames; f++) - { - for (int y = 0; y < 32; y++) - { - for (int x = 0; x < 32; x++) - { - pxdata[y*96 + x + 32*f] = animData[f*32*32 + y*32 + x]; - } - } - } - wxBitmap icon = wxBitmapFromMemoryRGBA((u8*)pxdata, 96, 32); - images[i*2 + 1] = list->Add(icon); - } - } + int pagesMax = (mcmSettings.usePages) ? (page[card] + 1) * itemsPerPage : 128; - int pagesMax = (mcmSettings.usePages) ? - (page[card] + 1) * itemsPerPage : 128; + for (j = page[card] * itemsPerPage; (j < nFiles) && (j < pagesMax); j++) + { + u16 blocks; + u16 firstblock; + u8 fileIndex = memoryCard[card]->GetFileIndex(j); - for (j = page[card] * itemsPerPage; (j < nFiles) && (j < pagesMax); j++) - { - u16 blocks; - u16 firstblock; - u8 fileIndex = memoryCard[card]->GetFileIndex(j); + int index = m_MemcardList[card]->InsertItem(j, wxEmptyString); + m_MemcardList[card]->SetItem(index, COLUMN_BANNER, wxEmptyString); - int index = m_MemcardList[card]->InsertItem(j, wxEmptyString); + std::string title = memoryCard[card]->GetSaveComment1(fileIndex); + std::string comment = memoryCard[card]->GetSaveComment2(fileIndex); - m_MemcardList[card]->SetItem(index, COLUMN_BANNER, wxEmptyString); + auto const string_decoder = memoryCard[card]->IsAsciiEncoding() ? CP1252ToUTF8 : SHIFTJISToUTF8; - std::string title = memoryCard[card]->GetSaveComment1(fileIndex); - std::string comment = memoryCard[card]->GetSaveComment2(fileIndex); + wxTitle = StrToWxStr(string_decoder(title)); + wxComment = StrToWxStr(string_decoder(comment)); - auto const string_decoder = memoryCard[card]->IsAsciiEncoding() ? - CP1252ToUTF8 : SHIFTJISToUTF8; + m_MemcardList[card]->SetItem(index, COLUMN_TITLE, wxTitle); + m_MemcardList[card]->SetItem(index, COLUMN_COMMENT, wxComment); - wxTitle = StrToWxStr(string_decoder(title)); - wxComment = StrToWxStr(string_decoder(comment)); + blocks = memoryCard[card]->DEntry_BlockCount(fileIndex); - m_MemcardList[card]->SetItem(index, COLUMN_TITLE, wxTitle); - m_MemcardList[card]->SetItem(index, COLUMN_COMMENT, wxComment); + if (blocks == 0xFFFF) + blocks = 0; - blocks = memoryCard[card]->DEntry_BlockCount(fileIndex); + wxBlock.Printf("%10d", blocks); + m_MemcardList[card]->SetItem(index, COLUMN_BLOCKS, wxBlock); + firstblock = memoryCard[card]->DEntry_FirstBlock(fileIndex); + // if (firstblock == 0xFFFF) firstblock = 3; // to make firstblock -1 + wxFirstBlock.Printf("%15d", firstblock); + m_MemcardList[card]->SetItem(index, COLUMN_FIRSTBLOCK, wxFirstBlock); + m_MemcardList[card]->SetItem(index, COLUMN_ICON, wxEmptyString); - if (blocks == 0xFFFF) - blocks = 0; + if (images[j] >= 0) + { + m_MemcardList[card]->SetItemImage(index, images[j * 2]); + m_MemcardList[card]->SetItemColumnImage(index, COLUMN_ICON, images[j * 2 + 1]); + } + } - wxBlock.Printf("%10d", blocks); - m_MemcardList[card]->SetItem(index, COLUMN_BLOCKS, wxBlock); - firstblock = memoryCard[card]->DEntry_FirstBlock(fileIndex); - //if (firstblock == 0xFFFF) firstblock = 3; // to make firstblock -1 - wxFirstBlock.Printf("%15d", firstblock); - m_MemcardList[card]->SetItem(index, COLUMN_FIRSTBLOCK, wxFirstBlock); - m_MemcardList[card]->SetItem(index, COLUMN_ICON, wxEmptyString); + if (mcmSettings.usePages) + { + if (nFiles <= itemsPerPage) + { + m_PrevPage[card]->Disable(); + m_MemcardList[card]->prevPage = false; + } + if (j == nFiles) + { + m_NextPage[card]->Disable(); + m_MemcardList[card]->nextPage = false; + } + else + { + m_NextPage[card]->Enable(); + m_MemcardList[card]->nextPage = true; + } + } - if (images[j] >= 0) - { - m_MemcardList[card]->SetItemImage(index, images[j*2]); - m_MemcardList[card]->SetItemColumnImage(index, COLUMN_ICON, images[j*2 + 1]); - } - } + // Automatic column width and then show the list + for (int i = COLUMN_BANNER; i <= COLUMN_FIRSTBLOCK; i++) + { + if (mcmSettings.column[i]) + m_MemcardList[card]->SetColumnWidth(i, wxLIST_AUTOSIZE); + else + m_MemcardList[card]->SetColumnWidth(i, 0); + } - if (mcmSettings.usePages) - { - if (nFiles <= itemsPerPage) - { - m_PrevPage[card]->Disable(); - m_MemcardList[card]->prevPage = false; - } - if (j == nFiles) - { - m_NextPage[card]->Disable(); - m_MemcardList[card]->nextPage = false; - } - else - { - m_NextPage[card]->Enable(); - m_MemcardList[card]->nextPage = true; - } - } + m_MemcardList[card]->Show(); + wxLabel.Printf(_("%u Free Blocks; %u Free Dir Entries"), memoryCard[card]->GetFreeBlocks(), + DIRLEN - nFiles); + t_Status[card]->SetLabel(wxLabel); - // Automatic column width and then show the list - for (int i = COLUMN_BANNER; i <= COLUMN_FIRSTBLOCK; i++) - { - if (mcmSettings.column[i]) - m_MemcardList[card]->SetColumnWidth(i, wxLIST_AUTOSIZE); - else - m_MemcardList[card]->SetColumnWidth(i, 0); - } + // Done so text doesn't overlap the UI. + this->Fit(); - m_MemcardList[card]->Show(); - wxLabel.Printf(_("%u Free Blocks; %u Free Dir Entries"), - memoryCard[card]->GetFreeBlocks(), DIRLEN - nFiles); - t_Status[card]->SetLabel(wxLabel); - - // Done so text doesn't overlap the UI. - this->Fit(); - - return true; + return true; } void CMemcardManager::CMemcardListCtrl::OnRightClick(wxMouseEvent& event) { - int flags; - long item = HitTest(event.GetPosition(), flags); - wxMenu popupMenu; + int flags; + long item = HitTest(event.GetPosition(), flags); + wxMenu popupMenu; - if (item != wxNOT_FOUND) - { - if (GetItemState(item, wxLIST_STATE_SELECTED) != wxLIST_STATE_SELECTED) - { - SetItemState(item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); - } - SetItemState(item, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED); + if (item != wxNOT_FOUND) + { + if (GetItemState(item, wxLIST_STATE_SELECTED) != wxLIST_STATE_SELECTED) + { + SetItemState(item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + } + SetItemState(item, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED); - int slot = GetId() - ID_MEMCARDLIST_A; - popupMenu.Append(ID_COPYFROM_A + slot, wxString::Format(_("Copy to Memcard %c"), 'B' - slot)); - popupMenu.Append(ID_DELETE_A + slot, _("Delete Save")); - popupMenu.Append(ID_SAVEIMPORT_A + slot, _("Import Save")); - popupMenu.Append(ID_SAVEEXPORT_A + slot, _("Export Save")); - popupMenu.Append(ID_EXPORTALL_A + slot, _("Export all saves")); + int slot = GetId() - ID_MEMCARDLIST_A; + popupMenu.Append(ID_COPYFROM_A + slot, wxString::Format(_("Copy to Memcard %c"), 'B' - slot)); + popupMenu.Append(ID_DELETE_A + slot, _("Delete Save")); + popupMenu.Append(ID_SAVEIMPORT_A + slot, _("Import Save")); + popupMenu.Append(ID_SAVEEXPORT_A + slot, _("Export Save")); + popupMenu.Append(ID_EXPORTALL_A + slot, _("Export all saves")); - popupMenu.FindItem(ID_COPYFROM_A + slot)->Enable(__mcmSettings.twoCardsLoaded); + popupMenu.FindItem(ID_COPYFROM_A + slot)->Enable(__mcmSettings.twoCardsLoaded); - popupMenu.AppendSeparator(); + popupMenu.AppendSeparator(); - popupMenu.Append(ID_FIXCHECKSUM_A + slot, _("Fix Checksums")); - popupMenu.Append(ID_PREVPAGE_A + slot, _("Previous Page")); - popupMenu.Append(ID_NEXTPAGE_A + slot, _("Next Page")); - popupMenu.Append(ID_MEMCARDPATH_A + slot, wxString::Format(_("Set as default Memcard %c"), 'A' + slot)); - popupMenu.AppendCheckItem(ID_USEPAGES, _("Enable pages")); + popupMenu.Append(ID_FIXCHECKSUM_A + slot, _("Fix Checksums")); + popupMenu.Append(ID_PREVPAGE_A + slot, _("Previous Page")); + popupMenu.Append(ID_NEXTPAGE_A + slot, _("Next Page")); + popupMenu.Append(ID_MEMCARDPATH_A + slot, + wxString::Format(_("Set as default Memcard %c"), 'A' + slot)); + popupMenu.AppendCheckItem(ID_USEPAGES, _("Enable pages")); - popupMenu.FindItem(ID_PREVPAGE_A + slot)->Enable(prevPage && __mcmSettings.usePages); - popupMenu.FindItem(ID_NEXTPAGE_A + slot)->Enable(nextPage && __mcmSettings.usePages); - popupMenu.FindItem(ID_USEPAGES)->Check(__mcmSettings.usePages); + popupMenu.FindItem(ID_PREVPAGE_A + slot)->Enable(prevPage && __mcmSettings.usePages); + popupMenu.FindItem(ID_NEXTPAGE_A + slot)->Enable(nextPage && __mcmSettings.usePages); + popupMenu.FindItem(ID_USEPAGES)->Check(__mcmSettings.usePages); - popupMenu.AppendSeparator(); + popupMenu.AppendSeparator(); - // popupMenu->AppendCheckItem(COLUMN_BANNER, _("Show save banner")); - popupMenu.AppendCheckItem(COLUMN_TITLE, _("Show save title")); - popupMenu.AppendCheckItem(COLUMN_COMMENT, _("Show save comment")); - popupMenu.AppendCheckItem(COLUMN_ICON, _("Show save icon")); - popupMenu.AppendCheckItem(COLUMN_BLOCKS, _("Show save blocks")); - popupMenu.AppendCheckItem(COLUMN_FIRSTBLOCK, _("Show first block")); + // popupMenu->AppendCheckItem(COLUMN_BANNER, _("Show save banner")); + popupMenu.AppendCheckItem(COLUMN_TITLE, _("Show save title")); + popupMenu.AppendCheckItem(COLUMN_COMMENT, _("Show save comment")); + popupMenu.AppendCheckItem(COLUMN_ICON, _("Show save icon")); + popupMenu.AppendCheckItem(COLUMN_BLOCKS, _("Show save blocks")); + popupMenu.AppendCheckItem(COLUMN_FIRSTBLOCK, _("Show first block")); - // for (int i = COLUMN_BANNER; i <= COLUMN_FIRSTBLOCK; i++) - for (int i = COLUMN_TITLE; i <= COLUMN_FIRSTBLOCK; i++) - { - popupMenu.FindItem(i)->Check(__mcmSettings.column[i]); - } - } - PopupMenu(&popupMenu); + // for (int i = COLUMN_BANNER; i <= COLUMN_FIRSTBLOCK; i++) + for (int i = COLUMN_TITLE; i <= COLUMN_FIRSTBLOCK; i++) + { + popupMenu.FindItem(i)->Check(__mcmSettings.column[i]); + } + } + PopupMenu(&popupMenu); } - diff --git a/Source/Core/DolphinWX/MemcardManager.h b/Source/Core/DolphinWX/MemcardManager.h index 0f83699384..3f307117b9 100644 --- a/Source/Core/DolphinWX/MemcardManager.h +++ b/Source/Core/DolphinWX/MemcardManager.h @@ -20,120 +20,116 @@ class wxStaticText; class CMemcardManager final : public wxDialog { public: - CMemcardManager(wxWindow* parent); - ~CMemcardManager(); + CMemcardManager(wxWindow* parent); + ~CMemcardManager(); private: - DECLARE_EVENT_TABLE(); + DECLARE_EVENT_TABLE(); - int page[2]; - int itemsPerPage; - int maxPages; - std::string DefaultMemcard[2]; - std::string DefaultIOPath; - IniFile MemcardManagerIni; - IniFile::Section* iniMemcardSection; + int page[2]; + int itemsPerPage; + int maxPages; + std::string DefaultMemcard[2]; + std::string DefaultIOPath; + IniFile MemcardManagerIni; + IniFile::Section* iniMemcardSection; - wxButton* m_CopyFrom[2]; - wxButton* m_SaveImport[2]; - wxButton* m_SaveExport[2]; - wxButton* m_Delete[2]; - wxButton* m_NextPage[2]; - wxButton* m_PrevPage[2]; - wxButton* m_ConvertToGci; - wxFilePickerCtrl *m_MemcardPath[2]; - wxStaticText *t_Status[2]; + wxButton* m_CopyFrom[2]; + wxButton* m_SaveImport[2]; + wxButton* m_SaveExport[2]; + wxButton* m_Delete[2]; + wxButton* m_NextPage[2]; + wxButton* m_PrevPage[2]; + wxButton* m_ConvertToGci; + wxFilePickerCtrl* m_MemcardPath[2]; + wxStaticText* t_Status[2]; - enum - { - ID_COPYFROM_A = 1000, // Do not rearrange these items, - ID_COPYFROM_B, // ID_..._B must be 1 more than ID_..._A - ID_FIXCHECKSUM_A, - ID_FIXCHECKSUM_B, - ID_DELETE_A, - ID_DELETE_B, - ID_SAVEEXPORT_A, - ID_SAVEEXPORT_B, - ID_SAVEIMPORT_A, - ID_SAVEIMPORT_B, - ID_EXPORTALL_A, - ID_EXPORTALL_B, - ID_CONVERTTOGCI, - ID_NEXTPAGE_A, - ID_NEXTPAGE_B, - ID_PREVPAGE_A, - ID_PREVPAGE_B, - ID_MEMCARDLIST_A, - ID_MEMCARDLIST_B, - ID_MEMCARDPATH_A, - ID_MEMCARDPATH_B, - ID_USEPAGES, - ID_DUMMY_VALUE_ //don't remove this value unless you have other enum values - }; + enum + { + ID_COPYFROM_A = 1000, // Do not rearrange these items, + ID_COPYFROM_B, // ID_..._B must be 1 more than ID_..._A + ID_FIXCHECKSUM_A, + ID_FIXCHECKSUM_B, + ID_DELETE_A, + ID_DELETE_B, + ID_SAVEEXPORT_A, + ID_SAVEEXPORT_B, + ID_SAVEIMPORT_A, + ID_SAVEIMPORT_B, + ID_EXPORTALL_A, + ID_EXPORTALL_B, + ID_CONVERTTOGCI, + ID_NEXTPAGE_A, + ID_NEXTPAGE_B, + ID_PREVPAGE_A, + ID_PREVPAGE_B, + ID_MEMCARDLIST_A, + ID_MEMCARDLIST_B, + ID_MEMCARDPATH_A, + ID_MEMCARDPATH_B, + ID_USEPAGES, + ID_DUMMY_VALUE_ // don't remove this value unless you have other enum values + }; - enum - { - COLUMN_BANNER = 0, - COLUMN_TITLE, - COLUMN_COMMENT, - COLUMN_ICON, - COLUMN_BLOCKS, - COLUMN_FIRSTBLOCK, - COLUMN_GAMECODE, - COLUMN_MAKERCODE, - COLUMN_FILENAME, - COLUMN_BIFLAGS, - COLUMN_MODTIME, - COLUMN_IMAGEADD, - COLUMN_ICONFMT, - COLUMN_ANIMSPEED, - COLUMN_PERMISSIONS, - COLUMN_COPYCOUNTER, - COLUMN_COMMENTSADDRESS, - NUMBER_OF_COLUMN - }; + enum + { + COLUMN_BANNER = 0, + COLUMN_TITLE, + COLUMN_COMMENT, + COLUMN_ICON, + COLUMN_BLOCKS, + COLUMN_FIRSTBLOCK, + COLUMN_GAMECODE, + COLUMN_MAKERCODE, + COLUMN_FILENAME, + COLUMN_BIFLAGS, + COLUMN_MODTIME, + COLUMN_IMAGEADD, + COLUMN_ICONFMT, + COLUMN_ANIMSPEED, + COLUMN_PERMISSIONS, + COLUMN_COPYCOUNTER, + COLUMN_COMMENTSADDRESS, + NUMBER_OF_COLUMN + }; - GCMemcard *memoryCard[2]; + GCMemcard* memoryCard[2]; - void CreateGUIControls(); - void CopyDeleteClick(wxCommandEvent& event); - bool ReloadMemcard(const std::string& fileName, int card); - void OnMenuChange(wxCommandEvent& event); - void OnPageChange(wxCommandEvent& event); - void OnPathChange(wxFileDirPickerEvent& event); - void ChangePath(int id); - bool CopyDeleteSwitch(u32 error, int slot); - bool LoadSettings(); - bool SaveSettings(); + void CreateGUIControls(); + void CopyDeleteClick(wxCommandEvent& event); + bool ReloadMemcard(const std::string& fileName, int card); + void OnMenuChange(wxCommandEvent& event); + void OnPageChange(wxCommandEvent& event); + void OnPathChange(wxFileDirPickerEvent& event); + void ChangePath(int id); + bool CopyDeleteSwitch(u32 error, int slot); + bool LoadSettings(); + bool SaveSettings(); - struct _mcmSettings - { - bool twoCardsLoaded; - bool usePages; - bool column[NUMBER_OF_COLUMN + 1]; - } mcmSettings; + struct _mcmSettings + { + bool twoCardsLoaded; + bool usePages; + bool column[NUMBER_OF_COLUMN + 1]; + } mcmSettings; - class CMemcardListCtrl : public wxListCtrl - { - public: - CMemcardListCtrl(wxWindow* parent, const wxWindowID id, - const wxPoint& pos, const wxSize& size, - long style, _mcmSettings& _mcmSetngs) - : wxListCtrl(parent, id, pos, size, style) - , __mcmSettings(_mcmSetngs) - { - Bind(wxEVT_RIGHT_DOWN, &CMemcardListCtrl::OnRightClick, this); - } - ~CMemcardListCtrl() - { - Unbind(wxEVT_RIGHT_DOWN, &CMemcardListCtrl::OnRightClick, this); - } - _mcmSettings & __mcmSettings; - bool prevPage; - bool nextPage; - private: - void OnRightClick(wxMouseEvent& event); - }; + class CMemcardListCtrl : public wxListCtrl + { + public: + CMemcardListCtrl(wxWindow* parent, const wxWindowID id, const wxPoint& pos, const wxSize& size, + long style, _mcmSettings& _mcmSetngs) + : wxListCtrl(parent, id, pos, size, style), __mcmSettings(_mcmSetngs) + { + Bind(wxEVT_RIGHT_DOWN, &CMemcardListCtrl::OnRightClick, this); + } + ~CMemcardListCtrl() { Unbind(wxEVT_RIGHT_DOWN, &CMemcardListCtrl::OnRightClick, this); } + _mcmSettings& __mcmSettings; + bool prevPage; + bool nextPage; - CMemcardListCtrl *m_MemcardList[2]; + private: + void OnRightClick(wxMouseEvent& event); + }; + + CMemcardListCtrl* m_MemcardList[2]; }; diff --git a/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.cpp b/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.cpp index 98f6dec441..4c315ee44b 100644 --- a/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.cpp +++ b/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.cpp @@ -10,31 +10,32 @@ #include "DolphinWX/NetPlay/NetWindow.h" ChangeGameDialog::ChangeGameDialog(wxWindow* parent, const CGameListCtrl* const game_list) - : wxDialog(parent, wxID_ANY, _("Change Game")) + : wxDialog(parent, wxID_ANY, _("Change Game")) { - m_game_lbox = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT); - m_game_lbox->Bind(wxEVT_LISTBOX_DCLICK, &ChangeGameDialog::OnPick, this); + m_game_lbox = + new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT); + m_game_lbox->Bind(wxEVT_LISTBOX_DCLICK, &ChangeGameDialog::OnPick, this); - NetPlayDialog::FillWithGameNames(m_game_lbox, *game_list); + NetPlayDialog::FillWithGameNames(m_game_lbox, *game_list); - wxButton* const ok_btn = new wxButton(this, wxID_OK, _("Change")); - ok_btn->Bind(wxEVT_BUTTON, &ChangeGameDialog::OnPick, this); + wxButton* const ok_btn = new wxButton(this, wxID_OK, _("Change")); + ok_btn->Bind(wxEVT_BUTTON, &ChangeGameDialog::OnPick, this); - wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL); - szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxTOP | wxEXPAND, 5); - szr->Add(ok_btn, 0, wxALL | wxALIGN_RIGHT, 5); + wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL); + szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxTOP | wxEXPAND, 5); + szr->Add(ok_btn, 0, wxALL | wxALIGN_RIGHT, 5); - SetSizerAndFit(szr); - SetFocus(); + SetSizerAndFit(szr); + SetFocus(); } wxString ChangeGameDialog::GetChosenGameName() const { - return m_game_name; + return m_game_name; } void ChangeGameDialog::OnPick(wxCommandEvent& event) { - m_game_name = m_game_lbox->GetStringSelection(); - EndModal(wxID_OK); + m_game_name = m_game_lbox->GetStringSelection(); + EndModal(wxID_OK); } diff --git a/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.h b/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.h index cf530b556d..53c2200fa6 100644 --- a/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.h +++ b/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.h @@ -12,13 +12,13 @@ class wxListBox; class ChangeGameDialog final : public wxDialog { public: - ChangeGameDialog(wxWindow* parent, const CGameListCtrl* const game_list); + ChangeGameDialog(wxWindow* parent, const CGameListCtrl* const game_list); - wxString GetChosenGameName() const; + wxString GetChosenGameName() const; private: - void OnPick(wxCommandEvent& event); + void OnPick(wxCommandEvent& event); - wxListBox* m_game_lbox; - wxString m_game_name; + wxListBox* m_game_lbox; + wxString m_game_name; }; diff --git a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp index 0c3adcdfc1..4f3725e222 100644 --- a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp +++ b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp @@ -19,459 +19,472 @@ #include "Core/NetPlayServer.h" #include "DolphinWX/Frame.h" #include "DolphinWX/Main.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/NetPlay/NetPlaySetupFrame.h" #include "DolphinWX/NetPlay/NetWindow.h" +#include "DolphinWX/WxUtils.h" static void GetTraversalPort(IniFile::Section& section, std::string* port) { - section.Get("TraversalPort", port, "6262"); - port->erase(std::remove(port->begin(), port->end(), ' '), port->end()); - if (port->empty()) - *port = "6262"; + section.Get("TraversalPort", port, "6262"); + port->erase(std::remove(port->begin(), port->end(), ' '), port->end()); + if (port->empty()) + *port = "6262"; } static void GetTraversalServer(IniFile::Section& section, std::string* server) { - section.Get("TraversalServer", server, "stun.dolphin-emu.org"); - server->erase(std::remove(server->begin(), server->end(), ' '), server->end()); - if (server->empty()) - *server = "stun.dolphin-emu.org"; + section.Get("TraversalServer", server, "stun.dolphin-emu.org"); + server->erase(std::remove(server->begin(), server->end(), ' '), server->end()); + if (server->empty()) + *server = "stun.dolphin-emu.org"; } NetPlaySetupFrame::NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl* const game_list) - : wxFrame(parent, wxID_ANY, _("Dolphin NetPlay Setup")) - , m_game_list(game_list) + : wxFrame(parent, wxID_ANY, _("Dolphin NetPlay Setup")), m_game_list(game_list) { - IniFile inifile; - inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"); - IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); + IniFile inifile; + inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"); + IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); - wxPanel* const panel = new wxPanel(this); + wxPanel* const panel = new wxPanel(this); - // top row - wxBoxSizer* const trav_szr = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* const nick_szr = new wxBoxSizer(wxHORIZONTAL); - { - // Connection Config - wxStaticText* const connectiontype_lbl = new wxStaticText(panel, wxID_ANY, _("Connection Type:"), wxDefaultPosition, wxSize(100, -1)); + // top row + wxBoxSizer* const trav_szr = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* const nick_szr = new wxBoxSizer(wxHORIZONTAL); + { + // Connection Config + wxStaticText* const connectiontype_lbl = new wxStaticText( + panel, wxID_ANY, _("Connection Type:"), wxDefaultPosition, wxSize(100, -1)); - m_direct_traversal = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(150, -1)); - m_direct_traversal->Bind(wxEVT_CHOICE, &NetPlaySetupFrame::OnChoice, this); - m_direct_traversal->Append(_("Direct Connection")); - m_direct_traversal->Append(_("Traversal Server")); + m_direct_traversal = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(150, -1)); + m_direct_traversal->Bind(wxEVT_CHOICE, &NetPlaySetupFrame::OnChoice, this); + m_direct_traversal->Append(_("Direct Connection")); + m_direct_traversal->Append(_("Traversal Server")); - trav_szr->Add(connectiontype_lbl, 0, wxCENTER, 5); - trav_szr->AddSpacer(5); - trav_szr->Add(m_direct_traversal, 0, wxCENTER, 5); + trav_szr->Add(connectiontype_lbl, 0, wxCENTER, 5); + trav_szr->AddSpacer(5); + trav_szr->Add(m_direct_traversal, 0, wxCENTER, 5); - m_trav_reset_btn = new wxButton(panel, wxID_ANY, _("Reset Traversal Settings"), wxDefaultPosition, wxSize(-1, 25)); - m_trav_reset_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnResetTraversal, this); + m_trav_reset_btn = new wxButton(panel, wxID_ANY, _("Reset Traversal Settings"), + wxDefaultPosition, wxSize(-1, 25)); + m_trav_reset_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnResetTraversal, this); - trav_szr->AddSpacer(5); + trav_szr->AddSpacer(5); - trav_szr->Add(m_trav_reset_btn, 0, wxRIGHT); + trav_szr->Add(m_trav_reset_btn, 0, wxRIGHT); - // Nickname - wxStaticText* const nick_lbl = new wxStaticText(panel, wxID_ANY, _("Nickname:"), wxDefaultPosition, wxSize(100, -1)); + // Nickname + wxStaticText* const nick_lbl = + new wxStaticText(panel, wxID_ANY, _("Nickname:"), wxDefaultPosition, wxSize(100, -1)); - std::string nickname; - netplay_section.Get("Nickname", &nickname, "Player"); + std::string nickname; + netplay_section.Get("Nickname", &nickname, "Player"); - m_nickname_text = new wxTextCtrl(panel, wxID_ANY, StrToWxStr(nickname), wxDefaultPosition, wxSize(150, -1)); + m_nickname_text = + new wxTextCtrl(panel, wxID_ANY, StrToWxStr(nickname), wxDefaultPosition, wxSize(150, -1)); - nick_szr->Add(nick_lbl, 0, wxCENTER); - nick_szr->Add(m_nickname_text, 0, wxALL, 5); + nick_szr->Add(nick_lbl, 0, wxCENTER); + nick_szr->Add(m_nickname_text, 0, wxALL, 5); - std::string travChoice; - netplay_section.Get("TraversalChoice", &travChoice, "direct"); - if (travChoice == "traversal") - { - m_direct_traversal->Select(1); - } - else - { - m_direct_traversal->Select(0); - } + std::string travChoice; + netplay_section.Get("TraversalChoice", &travChoice, "direct"); + if (travChoice == "traversal") + { + m_direct_traversal->Select(1); + } + else + { + m_direct_traversal->Select(0); + } - std::string centralPort; - GetTraversalPort(netplay_section, ¢ralPort); - std::string centralServer; - GetTraversalServer(netplay_section, ¢ralServer); + std::string centralPort; + GetTraversalPort(netplay_section, ¢ralPort); + std::string centralServer; + GetTraversalServer(netplay_section, ¢ralServer); - m_traversal_lbl = new wxStaticText(panel, wxID_ANY, _("Traversal Server:") + " " + centralServer + ":" + centralPort); - } - // tabs - wxNotebook* const notebook = new wxNotebook(panel, wxID_ANY); - wxPanel* const connect_tab = new wxPanel(notebook, wxID_ANY); - notebook->AddPage(connect_tab, _("Connect")); - wxPanel* const host_tab = new wxPanel(notebook, wxID_ANY); - notebook->AddPage(host_tab, _("Host")); + m_traversal_lbl = new wxStaticText(panel, wxID_ANY, _("Traversal Server:") + " " + + centralServer + ":" + centralPort); + } + // tabs + wxNotebook* const notebook = new wxNotebook(panel, wxID_ANY); + wxPanel* const connect_tab = new wxPanel(notebook, wxID_ANY); + notebook->AddPage(connect_tab, _("Connect")); + wxPanel* const host_tab = new wxPanel(notebook, wxID_ANY); + notebook->AddPage(host_tab, _("Host")); - // connect tab - { - m_ip_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Host Code :")); + // connect tab + { + m_ip_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Host Code :")); - std::string address; - netplay_section.Get("HostCode", &address, "00000000"); - m_connect_ip_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(address)); + std::string address; + netplay_section.Get("HostCode", &address, "00000000"); + m_connect_ip_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(address)); - m_client_port_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Port :")); + m_client_port_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Port :")); - // string? w/e - std::string port; - netplay_section.Get("ConnectPort", &port, "2626"); - m_connect_port_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(port)); + // string? w/e + std::string port; + netplay_section.Get("ConnectPort", &port, "2626"); + m_connect_port_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(port)); - wxButton* const connect_btn = new wxButton(connect_tab, wxID_ANY, _("Connect")); - connect_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnJoin, this); + wxButton* const connect_btn = new wxButton(connect_tab, wxID_ANY, _("Connect")); + connect_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnJoin, this); - wxStaticText* const alert_lbl = new wxStaticText(connect_tab, wxID_ANY, - _("ALERT:\n\n" - "All players must use the same Dolphin version.\n" - "All memory cards, SD cards and cheats must be identical between players or disabled.\n" - "If DSP LLE is used, DSP ROMs must be identical between players.\n" - "If connecting directly, the host must have the chosen UDP port open/forwarded!\n" - "\n" - "Wiimote support is broken in netplay and therefore disabled.\n")); + wxStaticText* const alert_lbl = new wxStaticText( + connect_tab, wxID_ANY, + _("ALERT:\n\n" + "All players must use the same Dolphin version.\n" + "All memory cards, SD cards and cheats must be identical between players or disabled.\n" + "If DSP LLE is used, DSP ROMs must be identical between players.\n" + "If connecting directly, the host must have the chosen UDP port open/forwarded!\n" + "\n" + "Wiimote support is broken in netplay and therefore disabled.\n")); - wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL); - top_szr->Add(m_ip_lbl, 0, wxCENTER | wxRIGHT, 5); - top_szr->Add(m_connect_ip_text, 3); - top_szr->Add(m_client_port_lbl, 0, wxCENTER | wxRIGHT | wxLEFT, 5); - top_szr->Add(m_connect_port_text, 1); + top_szr->Add(m_ip_lbl, 0, wxCENTER | wxRIGHT, 5); + top_szr->Add(m_connect_ip_text, 3); + top_szr->Add(m_client_port_lbl, 0, wxCENTER | wxRIGHT | wxLEFT, 5); + top_szr->Add(m_connect_port_text, 1); - wxBoxSizer* const con_szr = new wxBoxSizer(wxVERTICAL); - con_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5); - con_szr->AddStretchSpacer(1); - con_szr->Add(alert_lbl, 0, wxLEFT | wxRIGHT | wxEXPAND, 5); - con_szr->AddStretchSpacer(1); - con_szr->Add(connect_btn, 0, wxALL | wxALIGN_RIGHT, 5); + wxBoxSizer* const con_szr = new wxBoxSizer(wxVERTICAL); + con_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5); + con_szr->AddStretchSpacer(1); + con_szr->Add(alert_lbl, 0, wxLEFT | wxRIGHT | wxEXPAND, 5); + con_szr->AddStretchSpacer(1); + con_szr->Add(connect_btn, 0, wxALL | wxALIGN_RIGHT, 5); - connect_tab->SetSizerAndFit(con_szr); - } + connect_tab->SetSizerAndFit(con_szr); + } - // host tab - { - m_host_port_lbl = new wxStaticText(host_tab, wxID_ANY, _("Port :")); + // host tab + { + m_host_port_lbl = new wxStaticText(host_tab, wxID_ANY, _("Port :")); - // string? w/e - std::string port; - netplay_section.Get("HostPort", &port, "2626"); - m_host_port_text = new wxTextCtrl(host_tab, wxID_ANY, StrToWxStr(port)); + // string? w/e + std::string port; + netplay_section.Get("HostPort", &port, "2626"); + m_host_port_text = new wxTextCtrl(host_tab, wxID_ANY, StrToWxStr(port)); - m_traversal_listen_port_enabled = new wxCheckBox(host_tab, wxID_ANY, _("Force Listen Port: ")); - m_traversal_listen_port = new wxSpinCtrl(host_tab, wxID_ANY, "", wxDefaultPosition, wxSize(80, -1), wxSP_ARROW_KEYS, 1, 65535); + m_traversal_listen_port_enabled = new wxCheckBox(host_tab, wxID_ANY, _("Force Listen Port: ")); + m_traversal_listen_port = new wxSpinCtrl(host_tab, wxID_ANY, "", wxDefaultPosition, + wxSize(80, -1), wxSP_ARROW_KEYS, 1, 65535); - unsigned int listen_port; - netplay_section.Get("ListenPort", &listen_port, 0); - m_traversal_listen_port_enabled->SetValue(listen_port != 0); - m_traversal_listen_port->Enable(m_traversal_listen_port_enabled->IsChecked()); - m_traversal_listen_port->SetValue(listen_port); + unsigned int listen_port; + netplay_section.Get("ListenPort", &listen_port, 0); + m_traversal_listen_port_enabled->SetValue(listen_port != 0); + m_traversal_listen_port->Enable(m_traversal_listen_port_enabled->IsChecked()); + m_traversal_listen_port->SetValue(listen_port); - m_traversal_listen_port_enabled->Bind(wxEVT_CHECKBOX, &NetPlaySetupFrame::OnTraversalListenPortChanged, this); - m_traversal_listen_port->Bind(wxEVT_TEXT, &NetPlaySetupFrame::OnTraversalListenPortChanged, this); + m_traversal_listen_port_enabled->Bind(wxEVT_CHECKBOX, + &NetPlaySetupFrame::OnTraversalListenPortChanged, this); + m_traversal_listen_port->Bind(wxEVT_TEXT, &NetPlaySetupFrame::OnTraversalListenPortChanged, + this); - wxButton* const host_btn = new wxButton(host_tab, wxID_ANY, _("Host")); - host_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnHost, this); + wxButton* const host_btn = new wxButton(host_tab, wxID_ANY, _("Host")); + host_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnHost, this); - m_game_lbox = new wxListBox(host_tab, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT); - m_game_lbox->Bind(wxEVT_LISTBOX_DCLICK, &NetPlaySetupFrame::OnHost, this); + m_game_lbox = + new wxListBox(host_tab, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT); + m_game_lbox->Bind(wxEVT_LISTBOX_DCLICK, &NetPlaySetupFrame::OnHost, this); - NetPlayDialog::FillWithGameNames(m_game_lbox, *game_list); + NetPlayDialog::FillWithGameNames(m_game_lbox, *game_list); - wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL); - top_szr->Add(m_host_port_lbl, 0, wxCENTER | wxRIGHT, 5); - top_szr->Add(m_host_port_text, 0); + wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL); + top_szr->Add(m_host_port_lbl, 0, wxCENTER | wxRIGHT, 5); + top_szr->Add(m_host_port_text, 0); #ifdef USE_UPNP - m_upnp_chk = new wxCheckBox(host_tab, wxID_ANY, _("Forward port (UPnP)")); - top_szr->Add(m_upnp_chk, 0, wxALL | wxALIGN_RIGHT, 5); + m_upnp_chk = new wxCheckBox(host_tab, wxID_ANY, _("Forward port (UPnP)")); + top_szr->Add(m_upnp_chk, 0, wxALL | wxALIGN_RIGHT, 5); #endif - wxBoxSizer* const bottom_szr = new wxBoxSizer(wxHORIZONTAL); - bottom_szr->Add(m_traversal_listen_port_enabled, 0, wxCENTER | wxLEFT, 5); - bottom_szr->Add(m_traversal_listen_port, 0, wxCENTER, 0); - wxBoxSizer* const host_btn_szr = new wxBoxSizer(wxVERTICAL); - host_btn_szr->Add(host_btn, 0, wxCENTER | wxALIGN_RIGHT, 0); - bottom_szr->Add(host_btn_szr, 1, wxALL, 5); + wxBoxSizer* const bottom_szr = new wxBoxSizer(wxHORIZONTAL); + bottom_szr->Add(m_traversal_listen_port_enabled, 0, wxCENTER | wxLEFT, 5); + bottom_szr->Add(m_traversal_listen_port, 0, wxCENTER, 0); + wxBoxSizer* const host_btn_szr = new wxBoxSizer(wxVERTICAL); + host_btn_szr->Add(host_btn, 0, wxCENTER | wxALIGN_RIGHT, 0); + bottom_szr->Add(host_btn_szr, 1, wxALL, 5); - wxBoxSizer* const host_szr = new wxBoxSizer(wxVERTICAL); - host_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5); - host_szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxEXPAND, 5); - host_szr->Add(bottom_szr, 0, wxEXPAND, 0); + wxBoxSizer* const host_szr = new wxBoxSizer(wxVERTICAL); + host_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5); + host_szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxEXPAND, 5); + host_szr->Add(bottom_szr, 0, wxEXPAND, 0); - host_tab->SetSizerAndFit(host_szr); - } + host_tab->SetSizerAndFit(host_szr); + } - // bottom row - wxButton* const quit_btn = new wxButton(panel, wxID_ANY, _("Quit")); - quit_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnQuit, this); + // bottom row + wxButton* const quit_btn = new wxButton(panel, wxID_ANY, _("Quit")); + quit_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnQuit, this); - // main sizer - wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); - main_szr->Add(trav_szr, 0, wxALL | wxALIGN_LEFT, 5); - main_szr->Add(nick_szr, 0, wxALL | wxALIGN_LEFT, 5); - main_szr->Add(m_traversal_lbl, 0, wxALL | wxALIGN_LEFT, 5); - main_szr->Add(notebook, 1, wxLEFT | wxRIGHT | wxEXPAND, 5); - main_szr->Add(quit_btn, 0, wxALL | wxALIGN_RIGHT, 5); + // main sizer + wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); + main_szr->Add(trav_szr, 0, wxALL | wxALIGN_LEFT, 5); + main_szr->Add(nick_szr, 0, wxALL | wxALIGN_LEFT, 5); + main_szr->Add(m_traversal_lbl, 0, wxALL | wxALIGN_LEFT, 5); + main_szr->Add(notebook, 1, wxLEFT | wxRIGHT | wxEXPAND, 5); + main_szr->Add(quit_btn, 0, wxALL | wxALIGN_RIGHT, 5); - panel->SetSizerAndFit(main_szr); + panel->SetSizerAndFit(main_szr); - //wxBoxSizer* const diag_szr = new wxBoxSizer(wxVERTICAL); - //diag_szr->Add(panel, 1, wxEXPAND); - //SetSizerAndFit(diag_szr); + // wxBoxSizer* const diag_szr = new wxBoxSizer(wxVERTICAL); + // diag_szr->Add(panel, 1, wxEXPAND); + // SetSizerAndFit(diag_szr); - main_szr->SetSizeHints(this); + main_szr->SetSizeHints(this); - Center(); - Show(); + Center(); + Show(); - // Needs to be done last or it set up the spacing on the page correctly - wxCommandEvent ev; - OnChoice(ev); + // Needs to be done last or it set up the spacing on the page correctly + wxCommandEvent ev; + OnChoice(ev); } NetPlaySetupFrame::~NetPlaySetupFrame() { - IniFile inifile; - const std::string dolphin_ini = File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"; - inifile.Load(dolphin_ini); - IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); + IniFile inifile; + const std::string dolphin_ini = File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"; + inifile.Load(dolphin_ini); + IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); - std::string travChoice = "traversal"; - if (m_direct_traversal->GetSelection() == 1) - { - netplay_section.Set("TraversalChoice", travChoice); - } - else - { - travChoice = "direct"; - netplay_section.Set("TraversalChoice", travChoice); - } + std::string travChoice = "traversal"; + if (m_direct_traversal->GetSelection() == 1) + { + netplay_section.Set("TraversalChoice", travChoice); + } + else + { + travChoice = "direct"; + netplay_section.Set("TraversalChoice", travChoice); + } - netplay_section.Set("Nickname", WxStrToStr(m_nickname_text->GetValue())); + netplay_section.Set("Nickname", WxStrToStr(m_nickname_text->GetValue())); - if (m_direct_traversal->GetCurrentSelection() == 0) - { - netplay_section.Set("Address", WxStrToStr(m_connect_ip_text->GetValue())); - } - else - { - netplay_section.Set("HostCode", WxStrToStr(m_connect_ip_text->GetValue())); - } - netplay_section.Set("ConnectPort", WxStrToStr(m_connect_port_text->GetValue())); - netplay_section.Set("HostPort", WxStrToStr(m_host_port_text->GetValue())); - netplay_section.Set("ListenPort", - m_traversal_listen_port_enabled->IsChecked() ? m_traversal_listen_port->GetValue() : 0); + if (m_direct_traversal->GetCurrentSelection() == 0) + { + netplay_section.Set("Address", WxStrToStr(m_connect_ip_text->GetValue())); + } + else + { + netplay_section.Set("HostCode", WxStrToStr(m_connect_ip_text->GetValue())); + } + netplay_section.Set("ConnectPort", WxStrToStr(m_connect_port_text->GetValue())); + netplay_section.Set("HostPort", WxStrToStr(m_host_port_text->GetValue())); + netplay_section.Set("ListenPort", m_traversal_listen_port_enabled->IsChecked() ? + m_traversal_listen_port->GetValue() : + 0); - inifile.Save(dolphin_ini); - main_frame->g_NetPlaySetupDiag = nullptr; + inifile.Save(dolphin_ini); + main_frame->g_NetPlaySetupDiag = nullptr; } -void NetPlaySetupFrame::MakeNetPlayDiag(int port, const std::string &game, bool is_hosting) +void NetPlaySetupFrame::MakeNetPlayDiag(int port, const std::string& game, bool is_hosting) { - NetPlayDialog*& npd = NetPlayDialog::GetInstance(); - NetPlayClient*& netplay_client = NetPlayDialog::GetNetPlayClient(); + NetPlayDialog*& npd = NetPlayDialog::GetInstance(); + NetPlayClient*& netplay_client = NetPlayDialog::GetNetPlayClient(); - std::string ip; - npd = new NetPlayDialog(m_parent, m_game_list, game, is_hosting); - if (is_hosting) - ip = "127.0.0.1"; - else - ip = WxStrToStr(m_connect_ip_text->GetValue()); + std::string ip; + npd = new NetPlayDialog(m_parent, m_game_list, game, is_hosting); + if (is_hosting) + ip = "127.0.0.1"; + else + ip = WxStrToStr(m_connect_ip_text->GetValue()); - bool trav; - if (!is_hosting && m_direct_traversal->GetCurrentSelection() == 1) - trav = true; - else - trav = false; + bool trav; + if (!is_hosting && m_direct_traversal->GetCurrentSelection() == 1) + trav = true; + else + trav = false; - IniFile inifile; - inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"); - IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); + IniFile inifile; + inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"); + IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); - std::string centralPortString; - GetTraversalPort(netplay_section, ¢ralPortString); - unsigned long int centralPort; - StrToWxStr(centralPortString).ToULong(¢ralPort); + std::string centralPortString; + GetTraversalPort(netplay_section, ¢ralPortString); + unsigned long int centralPort; + StrToWxStr(centralPortString).ToULong(¢ralPort); - std::string centralServer; - GetTraversalServer(netplay_section, ¢ralServer); + std::string centralServer; + GetTraversalServer(netplay_section, ¢ralServer); - netplay_client = new NetPlayClient(ip, (u16)port, npd, WxStrToStr(m_nickname_text->GetValue()), trav, centralServer, (u16) centralPort); - if (netplay_client->IsConnected()) - { - npd->Show(); - Destroy(); - } - else - { - npd->Destroy(); - } + netplay_client = new NetPlayClient(ip, (u16)port, npd, WxStrToStr(m_nickname_text->GetValue()), + trav, centralServer, (u16)centralPort); + if (netplay_client->IsConnected()) + { + npd->Show(); + Destroy(); + } + else + { + npd->Destroy(); + } } void NetPlaySetupFrame::OnHost(wxCommandEvent&) { - NetPlayDialog*& npd = NetPlayDialog::GetInstance(); - NetPlayServer*& netplay_server = NetPlayDialog::GetNetPlayServer(); + NetPlayDialog*& npd = NetPlayDialog::GetInstance(); + NetPlayServer*& netplay_server = NetPlayDialog::GetNetPlayServer(); - if (npd) - { - WxUtils::ShowErrorDialog(_("A NetPlay window is already open!")); - return; - } + if (npd) + { + WxUtils::ShowErrorDialog(_("A NetPlay window is already open!")); + return; + } - if (m_game_lbox->GetSelection() == wxNOT_FOUND) - { - WxUtils::ShowErrorDialog(_("You must choose a game!")); - return; - } + if (m_game_lbox->GetSelection() == wxNOT_FOUND) + { + WxUtils::ShowErrorDialog(_("You must choose a game!")); + return; + } - std::string game(WxStrToStr(m_game_lbox->GetStringSelection())); + std::string game(WxStrToStr(m_game_lbox->GetStringSelection())); - bool trav; - unsigned long listen_port = 0; - if (m_direct_traversal->GetCurrentSelection() == 1) - { - trav = true; - listen_port = m_traversal_listen_port_enabled->IsChecked() ? m_traversal_listen_port->GetValue() : 0; - } - else - { - trav = false; - m_host_port_text->GetValue().ToULong(&listen_port); - } + bool trav; + unsigned long listen_port = 0; + if (m_direct_traversal->GetCurrentSelection() == 1) + { + trav = true; + listen_port = + m_traversal_listen_port_enabled->IsChecked() ? m_traversal_listen_port->GetValue() : 0; + } + else + { + trav = false; + m_host_port_text->GetValue().ToULong(&listen_port); + } - IniFile inifile; - inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"); - IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); + IniFile inifile; + inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"); + IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); - std::string centralPortString; - GetTraversalPort(netplay_section, ¢ralPortString); - unsigned long int centralPort; - StrToWxStr(centralPortString).ToULong(¢ralPort); + std::string centralPortString; + GetTraversalPort(netplay_section, ¢ralPortString); + unsigned long int centralPort; + StrToWxStr(centralPortString).ToULong(¢ralPort); - std::string centralServer; - GetTraversalServer(netplay_section, ¢ralServer); + std::string centralServer; + GetTraversalServer(netplay_section, ¢ralServer); - netplay_server = new NetPlayServer((u16)listen_port, trav, centralServer, (u16) centralPort); - if (netplay_server->is_connected) - { - netplay_server->ChangeGame(game); - netplay_server->AdjustPadBufferSize(INITIAL_PAD_BUFFER_SIZE); + netplay_server = new NetPlayServer((u16)listen_port, trav, centralServer, (u16)centralPort); + if (netplay_server->is_connected) + { + netplay_server->ChangeGame(game); + netplay_server->AdjustPadBufferSize(INITIAL_PAD_BUFFER_SIZE); #ifdef USE_UPNP - if (m_upnp_chk->GetValue()) - netplay_server->TryPortmapping(listen_port); + if (m_upnp_chk->GetValue()) + netplay_server->TryPortmapping(listen_port); #endif - MakeNetPlayDiag(netplay_server->GetPort(), game, true); - netplay_server->SetNetPlayUI(NetPlayDialog::GetInstance()); - } - else - { - if (trav && m_traversal_listen_port_enabled->IsChecked()) - WxUtils::ShowErrorDialog( - _("Failed to listen. Someone is probably already listening on the port you specified.")); - else - WxUtils::ShowErrorDialog(_("Failed to listen. Is another instance of the NetPlay server running?")); - } + MakeNetPlayDiag(netplay_server->GetPort(), game, true); + netplay_server->SetNetPlayUI(NetPlayDialog::GetInstance()); + } + else + { + if (trav && m_traversal_listen_port_enabled->IsChecked()) + WxUtils::ShowErrorDialog( + _("Failed to listen. Someone is probably already listening on the port you specified.")); + else + WxUtils::ShowErrorDialog( + _("Failed to listen. Is another instance of the NetPlay server running?")); + } } void NetPlaySetupFrame::OnJoin(wxCommandEvent&) { - NetPlayDialog*& npd = NetPlayDialog::GetInstance(); - if (npd) - { - WxUtils::ShowErrorDialog(_("A NetPlay window is already open!")); - return; - } + NetPlayDialog*& npd = NetPlayDialog::GetInstance(); + if (npd) + { + WxUtils::ShowErrorDialog(_("A NetPlay window is already open!")); + return; + } - unsigned long port = 0; - m_connect_port_text->GetValue().ToULong(&port); - MakeNetPlayDiag(port, "", false); + unsigned long port = 0; + m_connect_port_text->GetValue().ToULong(&port); + MakeNetPlayDiag(port, "", false); } void NetPlaySetupFrame::OnResetTraversal(wxCommandEvent& event) { - IniFile inifile; - const std::string dolphin_ini = File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"; - inifile.Load(dolphin_ini); - IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); - netplay_section.Set("TraversalServer", (std::string) "stun.dolphin-emu.org"); - netplay_section.Set("TraversalPort", (std::string) "6262"); - inifile.Save(dolphin_ini); + IniFile inifile; + const std::string dolphin_ini = File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"; + inifile.Load(dolphin_ini); + IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); + netplay_section.Set("TraversalServer", (std::string) "stun.dolphin-emu.org"); + netplay_section.Set("TraversalPort", (std::string) "6262"); + inifile.Save(dolphin_ini); - m_traversal_lbl->SetLabelText(_("Traversal: ") + "stun.dolphin-emu.org:6262"); + m_traversal_lbl->SetLabelText(_("Traversal: ") + "stun.dolphin-emu.org:6262"); } void NetPlaySetupFrame::OnTraversalListenPortChanged(wxCommandEvent& event) { - m_traversal_listen_port->Enable(m_traversal_listen_port_enabled->IsChecked()); + m_traversal_listen_port->Enable(m_traversal_listen_port_enabled->IsChecked()); } void NetPlaySetupFrame::OnChoice(wxCommandEvent& event) { - int sel = m_direct_traversal->GetSelection(); - IniFile inifile; - inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"); - IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); + int sel = m_direct_traversal->GetSelection(); + IniFile inifile; + inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"); + IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); - if (sel == 1) - { - m_traversal_lbl->Show(); - m_trav_reset_btn->Show(); - //Traversal - //client tab - { - m_ip_lbl->SetLabelText("Host Code: "); + if (sel == 1) + { + m_traversal_lbl->Show(); + m_trav_reset_btn->Show(); + // Traversal + // client tab + { + m_ip_lbl->SetLabelText("Host Code: "); - std::string address; - netplay_section.Get("HostCode", &address, "00000000"); - m_connect_ip_text->SetLabelText(address); + std::string address; + netplay_section.Get("HostCode", &address, "00000000"); + m_connect_ip_text->SetLabelText(address); - m_client_port_lbl->Hide(); - m_connect_port_text->Hide(); - } + m_client_port_lbl->Hide(); + m_connect_port_text->Hide(); + } - //server tab - { - m_host_port_lbl->Hide(); - m_host_port_text->Hide(); - m_traversal_listen_port->Show(); - m_traversal_listen_port_enabled->Show(); + // server tab + { + m_host_port_lbl->Hide(); + m_host_port_text->Hide(); + m_traversal_listen_port->Show(); + m_traversal_listen_port_enabled->Show(); #ifdef USE_UPNP - m_upnp_chk->Hide(); + m_upnp_chk->Hide(); #endif - } - } - else - { - m_traversal_lbl->Hide(); - m_trav_reset_btn->Hide(); - // Direct - // Client tab - { - m_ip_lbl->SetLabelText("IP Address :"); + } + } + else + { + m_traversal_lbl->Hide(); + m_trav_reset_btn->Hide(); + // Direct + // Client tab + { + m_ip_lbl->SetLabelText("IP Address :"); - std::string address; - netplay_section.Get("Address", &address, "127.0.0.1"); - m_connect_ip_text->SetLabelText(address); + std::string address; + netplay_section.Get("Address", &address, "127.0.0.1"); + m_connect_ip_text->SetLabelText(address); - m_client_port_lbl->Show(); - m_connect_port_text->Show(); - } + m_client_port_lbl->Show(); + m_connect_port_text->Show(); + } - // Server tab - m_traversal_listen_port->Hide(); - m_traversal_listen_port_enabled->Hide(); - m_host_port_lbl->Show(); - m_host_port_text->Show(); + // Server tab + m_traversal_listen_port->Hide(); + m_traversal_listen_port_enabled->Hide(); + m_host_port_lbl->Show(); + m_host_port_text->Show(); #ifdef USE_UPNP - m_upnp_chk->Show(); + m_upnp_chk->Show(); #endif - } + } } void NetPlaySetupFrame::OnQuit(wxCommandEvent&) { - Destroy(); + Destroy(); } diff --git a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.h b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.h index d0dc54dea9..c2ddb569e1 100644 --- a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.h +++ b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.h @@ -19,36 +19,36 @@ class wxTextCtrl; class NetPlaySetupFrame final : public wxFrame { public: - NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl* const game_list); - ~NetPlaySetupFrame(); + NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl* const game_list); + ~NetPlaySetupFrame(); private: - void OnJoin(wxCommandEvent& event); - void OnHost(wxCommandEvent& event); - void OnQuit(wxCommandEvent& event); - void OnChoice(wxCommandEvent& event); - void OnResetTraversal(wxCommandEvent& event); - void OnTraversalListenPortChanged(wxCommandEvent& event); + void OnJoin(wxCommandEvent& event); + void OnHost(wxCommandEvent& event); + void OnQuit(wxCommandEvent& event); + void OnChoice(wxCommandEvent& event); + void OnResetTraversal(wxCommandEvent& event); + void OnTraversalListenPortChanged(wxCommandEvent& event); - void MakeNetPlayDiag(int port, const std::string& game, bool is_hosting); + void MakeNetPlayDiag(int port, const std::string& game, bool is_hosting); - wxStaticText* m_ip_lbl; - wxStaticText* m_client_port_lbl; - wxTextCtrl* m_nickname_text; - wxStaticText* m_host_port_lbl; - wxTextCtrl* m_host_port_text; - wxTextCtrl* m_connect_port_text; - wxTextCtrl* m_connect_ip_text; - wxChoice* m_direct_traversal; - wxStaticText* m_traversal_lbl; - wxButton* m_trav_reset_btn; - wxCheckBox* m_traversal_listen_port_enabled; - wxSpinCtrl* m_traversal_listen_port; + wxStaticText* m_ip_lbl; + wxStaticText* m_client_port_lbl; + wxTextCtrl* m_nickname_text; + wxStaticText* m_host_port_lbl; + wxTextCtrl* m_host_port_text; + wxTextCtrl* m_connect_port_text; + wxTextCtrl* m_connect_ip_text; + wxChoice* m_direct_traversal; + wxStaticText* m_traversal_lbl; + wxButton* m_trav_reset_btn; + wxCheckBox* m_traversal_listen_port_enabled; + wxSpinCtrl* m_traversal_listen_port; - wxListBox* m_game_lbox; + wxListBox* m_game_lbox; #ifdef USE_UPNP - wxCheckBox* m_upnp_chk; + wxCheckBox* m_upnp_chk; #endif - const CGameListCtrl* const m_game_list; + const CGameListCtrl* const m_game_list; }; diff --git a/Source/Core/DolphinWX/NetPlay/NetWindow.cpp b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp index 9274b2b9aa..53114a7509 100644 --- a/Source/Core/DolphinWX/NetPlay/NetWindow.cpp +++ b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp @@ -29,574 +29,572 @@ #include "Common/IniFile.h" #include "Core/ConfigManager.h" +#include "Core/HW/EXI_Device.h" #include "Core/NetPlayClient.h" #include "Core/NetPlayProto.h" #include "Core/NetPlayServer.h" -#include "Core/HW/EXI_Device.h" #include "DolphinWX/Frame.h" #include "DolphinWX/GameListCtrl.h" #include "DolphinWX/ISOFile.h" #include "DolphinWX/Main.h" -#include "DolphinWX/WxUtils.h" #include "DolphinWX/NetPlay/ChangeGameDialog.h" #include "DolphinWX/NetPlay/NetWindow.h" #include "DolphinWX/NetPlay/PadMapDialog.h" +#include "DolphinWX/WxUtils.h" NetPlayServer* NetPlayDialog::netplay_server = nullptr; NetPlayClient* NetPlayDialog::netplay_client = nullptr; -NetPlayDialog *NetPlayDialog::npd = nullptr; +NetPlayDialog* NetPlayDialog::npd = nullptr; static wxString FailureReasonStringForHostLabel(int reason) { - switch (reason) - { - case TraversalClient::BadHost: - return _("(Error: Bad host)"); - case TraversalClient::VersionTooOld: - return _("(Error: Dolphin too old)"); - case TraversalClient::ServerForgotAboutUs: - return _("(Error: Disconnected)"); - case TraversalClient::SocketSendError: - return _("(Error: Socket)"); - case TraversalClient::ResendTimeout: - return _("(Error: Timeout)"); - default: - return _("(Error: Unknown)"); - } + switch (reason) + { + case TraversalClient::BadHost: + return _("(Error: Bad host)"); + case TraversalClient::VersionTooOld: + return _("(Error: Dolphin too old)"); + case TraversalClient::ServerForgotAboutUs: + return _("(Error: Disconnected)"); + case TraversalClient::SocketSendError: + return _("(Error: Socket)"); + case TraversalClient::ResendTimeout: + return _("(Error: Timeout)"); + default: + return _("(Error: Unknown)"); + } } static std::string BuildGameName(const GameListItem& game) { - // Lang needs to be consistent - DiscIO::IVolume::ELanguage const lang = DiscIO::IVolume::LANGUAGE_ENGLISH; - std::vector info; - if (!game.GetUniqueID().empty()) - info.push_back(game.GetUniqueID()); - if (game.GetRevision() != 0) - { - std::string rev_str = "Revision "; - info.push_back(rev_str + std::to_string((long long)game.GetRevision())); - } + // Lang needs to be consistent + DiscIO::IVolume::ELanguage const lang = DiscIO::IVolume::LANGUAGE_ENGLISH; + std::vector info; + if (!game.GetUniqueID().empty()) + info.push_back(game.GetUniqueID()); + if (game.GetRevision() != 0) + { + std::string rev_str = "Revision "; + info.push_back(rev_str + std::to_string((long long)game.GetRevision())); + } - std::string name(game.GetName(lang)); - if (name.empty()) - name = game.GetName(); + std::string name(game.GetName(lang)); + if (name.empty()) + name = game.GetName(); - int disc_number = game.GetDiscNumber() + 1; + int disc_number = game.GetDiscNumber() + 1; - std::string lower_name = name; - std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(), ::tolower); - if (disc_number > 1 && - lower_name.find(std::string(wxString::Format("disc %i", disc_number))) == std::string::npos && - lower_name.find(std::string(wxString::Format("disc%i", disc_number))) == std::string::npos) - { - std::string disc_text = "Disc "; - info.push_back(disc_text + std::to_string(disc_number)); - } - if (info.empty()) - return name; - std::ostringstream ss; - std::copy(info.begin(), info.end() -1, std::ostream_iterator(ss, ", ")); - ss << info.back(); - return name + " (" + ss.str() + ")"; + std::string lower_name = name; + std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(), ::tolower); + if (disc_number > 1 && + lower_name.find(std::string(wxString::Format("disc %i", disc_number))) == std::string::npos && + lower_name.find(std::string(wxString::Format("disc%i", disc_number))) == std::string::npos) + { + std::string disc_text = "Disc "; + info.push_back(disc_text + std::to_string(disc_number)); + } + if (info.empty()) + return name; + std::ostringstream ss; + std::copy(info.begin(), info.end() - 1, std::ostream_iterator(ss, ", ")); + ss << info.back(); + return name + " (" + ss.str() + ")"; } void NetPlayDialog::FillWithGameNames(wxListBox* game_lbox, const CGameListCtrl& game_list) { - for (u32 i = 0; auto game = game_list.GetISO(i); ++i) - game_lbox->Append(StrToWxStr(BuildGameName(*game))); + for (u32 i = 0; auto game = game_list.GetISO(i); ++i) + game_lbox->Append(StrToWxStr(BuildGameName(*game))); } NetPlayDialog::NetPlayDialog(wxWindow* const parent, const CGameListCtrl* const game_list, - const std::string& game, const bool is_hosting) - : wxFrame(parent, wxID_ANY, _("Dolphin NetPlay")) - , m_selected_game(game) - , m_start_btn(nullptr) - , m_host_label(nullptr) - , m_host_type_choice(nullptr) - , m_host_copy_btn(nullptr) - , m_host_copy_btn_is_retry(false) - , m_is_hosting(is_hosting) - , m_game_list(game_list) + const std::string& game, const bool is_hosting) + : wxFrame(parent, wxID_ANY, _("Dolphin NetPlay")), m_selected_game(game), m_start_btn(nullptr), + m_host_label(nullptr), m_host_type_choice(nullptr), m_host_copy_btn(nullptr), + m_host_copy_btn_is_retry(false), m_is_hosting(is_hosting), m_game_list(game_list) { - Bind(wxEVT_THREAD, &NetPlayDialog::OnThread, this); + Bind(wxEVT_THREAD, &NetPlayDialog::OnThread, this); - wxPanel* const panel = new wxPanel(this); + wxPanel* const panel = new wxPanel(this); - // top crap - m_game_btn = new wxButton(panel, wxID_ANY, - StrToWxStr(m_selected_game).Prepend(_(" Game : ")), - wxDefaultPosition, wxDefaultSize, wxBU_LEFT); + // top crap + m_game_btn = new wxButton(panel, wxID_ANY, StrToWxStr(m_selected_game).Prepend(_(" Game : ")), + wxDefaultPosition, wxDefaultSize, wxBU_LEFT); - if (m_is_hosting) - m_game_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnChangeGame, this); - else - m_game_btn->Disable(); + if (m_is_hosting) + m_game_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnChangeGame, this); + else + m_game_btn->Disable(); - // middle crap + // middle crap - // chat - m_chat_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString - , wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxTE_MULTILINE); + // chat + m_chat_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, + wxTE_READONLY | wxTE_MULTILINE); - m_chat_msg_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString - , wxDefaultPosition, wxSize(-1, 25), wxTE_PROCESS_ENTER); - m_chat_msg_text->Bind(wxEVT_TEXT_ENTER, &NetPlayDialog::OnChat, this); - m_chat_msg_text->SetMaxLength(2000); + m_chat_msg_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString, wxDefaultPosition, + wxSize(-1, 25), wxTE_PROCESS_ENTER); + m_chat_msg_text->Bind(wxEVT_TEXT_ENTER, &NetPlayDialog::OnChat, this); + m_chat_msg_text->SetMaxLength(2000); - wxButton* const chat_msg_btn = new wxButton(panel, wxID_ANY, _("Send"), wxDefaultPosition, wxSize(-1, 26)); - chat_msg_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnChat, this); + wxButton* const chat_msg_btn = + new wxButton(panel, wxID_ANY, _("Send"), wxDefaultPosition, wxSize(-1, 26)); + chat_msg_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnChat, this); - wxBoxSizer* const chat_msg_szr = new wxBoxSizer(wxHORIZONTAL); - chat_msg_szr->Add(m_chat_msg_text, 1); - chat_msg_szr->Add(chat_msg_btn, 0); + wxBoxSizer* const chat_msg_szr = new wxBoxSizer(wxHORIZONTAL); + chat_msg_szr->Add(m_chat_msg_text, 1); + chat_msg_szr->Add(chat_msg_btn, 0); - wxStaticBoxSizer* const chat_szr = new wxStaticBoxSizer(wxVERTICAL, panel, _("Chat")); - chat_szr->Add(m_chat_text, 1, wxEXPAND); - chat_szr->Add(chat_msg_szr, 0, wxEXPAND | wxTOP, 5); + wxStaticBoxSizer* const chat_szr = new wxStaticBoxSizer(wxVERTICAL, panel, _("Chat")); + chat_szr->Add(m_chat_text, 1, wxEXPAND); + chat_szr->Add(chat_msg_szr, 0, wxEXPAND | wxTOP, 5); - m_player_lbox = new wxListBox(panel, wxID_ANY, wxDefaultPosition, wxSize(256, -1)); + m_player_lbox = new wxListBox(panel, wxID_ANY, wxDefaultPosition, wxSize(256, -1)); - wxStaticBoxSizer* const player_szr = new wxStaticBoxSizer(wxVERTICAL, panel, _("Players")); + wxStaticBoxSizer* const player_szr = new wxStaticBoxSizer(wxVERTICAL, panel, _("Players")); - // player list - if (m_is_hosting && g_TraversalClient) - { - wxBoxSizer* const host_szr = new wxBoxSizer(wxHORIZONTAL); - m_host_type_choice = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(76, -1)); - m_host_type_choice->Bind(wxEVT_CHOICE, &NetPlayDialog::OnChoice, this); - m_host_type_choice->Append(_("Room ID:")); - host_szr->Add(m_host_type_choice); + // player list + if (m_is_hosting && g_TraversalClient) + { + wxBoxSizer* const host_szr = new wxBoxSizer(wxHORIZONTAL); + m_host_type_choice = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(76, -1)); + m_host_type_choice->Bind(wxEVT_CHOICE, &NetPlayDialog::OnChoice, this); + m_host_type_choice->Append(_("Room ID:")); + host_szr->Add(m_host_type_choice); - m_host_label = new wxStaticText(panel, wxID_ANY, "555.555.555.555:55555", wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE | wxALIGN_LEFT); - // Update() should fix this immediately. - m_host_label->SetLabel(""); - host_szr->Add(m_host_label, 1, wxLEFT | wxCENTER, 5); + m_host_label = new wxStaticText(panel, wxID_ANY, "555.555.555.555:55555", wxDefaultPosition, + wxDefaultSize, wxST_NO_AUTORESIZE | wxALIGN_LEFT); + // Update() should fix this immediately. + m_host_label->SetLabel(""); + host_szr->Add(m_host_label, 1, wxLEFT | wxCENTER, 5); - m_host_copy_btn = new wxButton(panel, wxID_ANY, _("Copy")); - m_host_copy_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnCopyIP, this); - m_host_copy_btn->Disable(); - host_szr->Add(m_host_copy_btn, 0, wxLEFT | wxCENTER, 5); - player_szr->Add(host_szr, 0, wxEXPAND | wxBOTTOM, 5); - m_host_type_choice->Select(0); + m_host_copy_btn = new wxButton(panel, wxID_ANY, _("Copy")); + m_host_copy_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnCopyIP, this); + m_host_copy_btn->Disable(); + host_szr->Add(m_host_copy_btn, 0, wxLEFT | wxCENTER, 5); + player_szr->Add(host_szr, 0, wxEXPAND | wxBOTTOM, 5); + m_host_type_choice->Select(0); - UpdateHostLabel(); - } + UpdateHostLabel(); + } - player_szr->Add(m_player_lbox, 1, wxEXPAND); + player_szr->Add(m_player_lbox, 1, wxEXPAND); - if (m_is_hosting) - { - m_player_lbox->Bind(wxEVT_LISTBOX, &NetPlayDialog::OnPlayerSelect, this); - m_kick_btn = new wxButton(panel, wxID_ANY, _("Kick Player")); - m_kick_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnKick, this); - player_szr->Add(m_kick_btn, 0, wxEXPAND | wxTOP, 5); - m_kick_btn->Disable(); + if (m_is_hosting) + { + m_player_lbox->Bind(wxEVT_LISTBOX, &NetPlayDialog::OnPlayerSelect, this); + m_kick_btn = new wxButton(panel, wxID_ANY, _("Kick Player")); + m_kick_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnKick, this); + player_szr->Add(m_kick_btn, 0, wxEXPAND | wxTOP, 5); + m_kick_btn->Disable(); - m_player_config_btn = new wxButton(panel, wxID_ANY, _("Assign Controller Ports")); - m_player_config_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnAssignPads, this); - player_szr->Add(m_player_config_btn, 0, wxEXPAND | wxTOP, 5); - } + m_player_config_btn = new wxButton(panel, wxID_ANY, _("Assign Controller Ports")); + m_player_config_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnAssignPads, this); + player_szr->Add(m_player_config_btn, 0, wxEXPAND | wxTOP, 5); + } - wxBoxSizer* const mid_szr = new wxBoxSizer(wxHORIZONTAL); - mid_szr->Add(chat_szr, 1, wxEXPAND | wxRIGHT, 5); - mid_szr->Add(player_szr, 0, wxEXPAND); + wxBoxSizer* const mid_szr = new wxBoxSizer(wxHORIZONTAL); + mid_szr->Add(chat_szr, 1, wxEXPAND | wxRIGHT, 5); + mid_szr->Add(player_szr, 0, wxEXPAND); - // bottom crap - wxButton* const quit_btn = new wxButton(panel, wxID_ANY, _("Quit Netplay")); - quit_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnQuit, this); + // bottom crap + wxButton* const quit_btn = new wxButton(panel, wxID_ANY, _("Quit Netplay")); + quit_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnQuit, this); - wxBoxSizer* const bottom_szr = new wxBoxSizer(wxHORIZONTAL); - if (is_hosting) - { - m_start_btn = new wxButton(panel, wxID_ANY, _("Start")); - m_start_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnStart, this); - bottom_szr->Add(m_start_btn); + wxBoxSizer* const bottom_szr = new wxBoxSizer(wxHORIZONTAL); + if (is_hosting) + { + m_start_btn = new wxButton(panel, wxID_ANY, _("Start")); + m_start_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnStart, this); + bottom_szr->Add(m_start_btn); - bottom_szr->Add(new wxStaticText(panel, wxID_ANY, _("Buffer:")), 0, wxLEFT | wxCENTER, 5); - wxSpinCtrl* const padbuf_spin = new wxSpinCtrl(panel, wxID_ANY, std::to_string(INITIAL_PAD_BUFFER_SIZE) - , wxDefaultPosition, wxSize(64, -1), wxSP_ARROW_KEYS, 0, 200, INITIAL_PAD_BUFFER_SIZE); - padbuf_spin->Bind(wxEVT_SPINCTRL, &NetPlayDialog::OnAdjustBuffer, this); - bottom_szr->AddSpacer(3); - bottom_szr->Add(padbuf_spin, 0, wxCENTER); - bottom_szr->AddSpacer(5); - m_memcard_write = new wxCheckBox(panel, wxID_ANY, _("Write to memcards/SD")); - bottom_szr->Add(m_memcard_write, 0, wxCENTER); - } + bottom_szr->Add(new wxStaticText(panel, wxID_ANY, _("Buffer:")), 0, wxLEFT | wxCENTER, 5); + wxSpinCtrl* const padbuf_spin = + new wxSpinCtrl(panel, wxID_ANY, std::to_string(INITIAL_PAD_BUFFER_SIZE), wxDefaultPosition, + wxSize(64, -1), wxSP_ARROW_KEYS, 0, 200, INITIAL_PAD_BUFFER_SIZE); + padbuf_spin->Bind(wxEVT_SPINCTRL, &NetPlayDialog::OnAdjustBuffer, this); + bottom_szr->AddSpacer(3); + bottom_szr->Add(padbuf_spin, 0, wxCENTER); + bottom_szr->AddSpacer(5); + m_memcard_write = new wxCheckBox(panel, wxID_ANY, _("Write to memcards/SD")); + bottom_szr->Add(m_memcard_write, 0, wxCENTER); + } - bottom_szr->AddSpacer(5); - m_record_chkbox = new wxCheckBox(panel, wxID_ANY, _("Record inputs")); - bottom_szr->Add(m_record_chkbox, 0, wxCENTER); + bottom_szr->AddSpacer(5); + m_record_chkbox = new wxCheckBox(panel, wxID_ANY, _("Record inputs")); + bottom_szr->Add(m_record_chkbox, 0, wxCENTER); - bottom_szr->AddStretchSpacer(1); - bottom_szr->Add(quit_btn); + bottom_szr->AddStretchSpacer(1); + bottom_szr->Add(quit_btn); - // main sizer - wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); - main_szr->Add(m_game_btn, 0, wxEXPAND | wxALL, 5); - main_szr->Add(mid_szr, 1, wxEXPAND | wxLEFT | wxRIGHT, 5); - main_szr->Add(bottom_szr, 0, wxEXPAND | wxALL, 5); + // main sizer + wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); + main_szr->Add(m_game_btn, 0, wxEXPAND | wxALL, 5); + main_szr->Add(mid_szr, 1, wxEXPAND | wxLEFT | wxRIGHT, 5); + main_szr->Add(bottom_szr, 0, wxEXPAND | wxALL, 5); - panel->SetSizerAndFit(main_szr); + panel->SetSizerAndFit(main_szr); - main_szr->SetSizeHints(this); - SetSize(768, 768 - 128); + main_szr->SetSizeHints(this); + SetSize(768, 768 - 128); - Center(); + Center(); } NetPlayDialog::~NetPlayDialog() { - if (netplay_client) - { - delete netplay_client; - netplay_client = nullptr; - } - if (netplay_server) - { - delete netplay_server; - netplay_server = nullptr; - } - npd = nullptr; + if (netplay_client) + { + delete netplay_client; + netplay_client = nullptr; + } + if (netplay_server) + { + delete netplay_server; + netplay_server = nullptr; + } + npd = nullptr; } void NetPlayDialog::OnChat(wxCommandEvent&) { - wxString text = m_chat_msg_text->GetValue(); + wxString text = m_chat_msg_text->GetValue(); - if (!text.empty()) - { - netplay_client->SendChatMessage(WxStrToStr(text)); - m_chat_text->AppendText(text.Prepend(" >> ").Append('\n')); - m_chat_msg_text->Clear(); - } + if (!text.empty()) + { + netplay_client->SendChatMessage(WxStrToStr(text)); + m_chat_text->AppendText(text.Prepend(" >> ").Append('\n')); + m_chat_msg_text->Clear(); + } } -void NetPlayDialog::GetNetSettings(NetSettings &settings) +void NetPlayDialog::GetNetSettings(NetSettings& settings) { - SConfig &instance = SConfig::GetInstance(); - settings.m_CPUthread = instance.bCPUThread; - settings.m_CPUcore = instance.iCPUCore; - settings.m_SelectedLanguage = instance.SelectedLanguage; - settings.m_OverrideGCLanguage = instance.bOverrideGCLanguage; - settings.m_ProgressiveScan = instance.bProgressive; - settings.m_PAL60 = instance.bPAL60; - settings.m_DSPHLE = instance.bDSPHLE; - settings.m_DSPEnableJIT = instance.m_DSPEnableJIT; - settings.m_WriteToMemcard = m_memcard_write->GetValue(); - settings.m_OCEnable = instance.m_OCEnable; - settings.m_OCFactor = instance.m_OCFactor; - settings.m_EXIDevice[0] = instance.m_EXIDevice[0]; - settings.m_EXIDevice[1] = instance.m_EXIDevice[1]; + SConfig& instance = SConfig::GetInstance(); + settings.m_CPUthread = instance.bCPUThread; + settings.m_CPUcore = instance.iCPUCore; + settings.m_SelectedLanguage = instance.SelectedLanguage; + settings.m_OverrideGCLanguage = instance.bOverrideGCLanguage; + settings.m_ProgressiveScan = instance.bProgressive; + settings.m_PAL60 = instance.bPAL60; + settings.m_DSPHLE = instance.bDSPHLE; + settings.m_DSPEnableJIT = instance.m_DSPEnableJIT; + settings.m_WriteToMemcard = m_memcard_write->GetValue(); + settings.m_OCEnable = instance.m_OCEnable; + settings.m_OCFactor = instance.m_OCFactor; + settings.m_EXIDevice[0] = instance.m_EXIDevice[0]; + settings.m_EXIDevice[1] = instance.m_EXIDevice[1]; } std::string NetPlayDialog::FindGame() { - // find path for selected game, sloppy.. - for (u32 i = 0; auto game = m_game_list->GetISO(i); ++i) - if (m_selected_game == BuildGameName(*game)) - return game->GetFileName(); + // find path for selected game, sloppy.. + for (u32 i = 0; auto game = m_game_list->GetISO(i); ++i) + if (m_selected_game == BuildGameName(*game)) + return game->GetFileName(); - WxUtils::ShowErrorDialog(_("Game not found!")); - return ""; + WxUtils::ShowErrorDialog(_("Game not found!")); + return ""; } void NetPlayDialog::OnStart(wxCommandEvent&) { - NetSettings settings; - GetNetSettings(settings); - netplay_server->SetNetSettings(settings); - netplay_server->StartGame(); + NetSettings settings; + GetNetSettings(settings); + netplay_server->SetNetSettings(settings); + netplay_server->StartGame(); } void NetPlayDialog::BootGame(const std::string& filename) { - main_frame->BootGame(filename); + main_frame->BootGame(filename); } void NetPlayDialog::StopGame() { - main_frame->DoStop(); + main_frame->DoStop(); } // NetPlayUI methods called from ---NETPLAY--- thread void NetPlayDialog::Update() { - wxThreadEvent evt(wxEVT_THREAD, 1); - GetEventHandler()->AddPendingEvent(evt); + wxThreadEvent evt(wxEVT_THREAD, 1); + GetEventHandler()->AddPendingEvent(evt); } void NetPlayDialog::AppendChat(const std::string& msg) { - chat_msgs.Push(msg); - // silly - Update(); + chat_msgs.Push(msg); + // silly + Update(); } void NetPlayDialog::OnMsgChangeGame(const std::string& filename) { - wxThreadEvent* evt = new wxThreadEvent(wxEVT_THREAD, NP_GUI_EVT_CHANGE_GAME); - evt->SetString(StrToWxStr(filename)); - GetEventHandler()->QueueEvent(evt); + wxThreadEvent* evt = new wxThreadEvent(wxEVT_THREAD, NP_GUI_EVT_CHANGE_GAME); + evt->SetString(StrToWxStr(filename)); + GetEventHandler()->QueueEvent(evt); } void NetPlayDialog::OnMsgStartGame() { - wxThreadEvent evt(wxEVT_THREAD, NP_GUI_EVT_START_GAME); - GetEventHandler()->AddPendingEvent(evt); - if (m_is_hosting) - { - m_start_btn->Disable(); - m_memcard_write->Disable(); - m_game_btn->Disable(); - m_player_config_btn->Disable(); - } + wxThreadEvent evt(wxEVT_THREAD, NP_GUI_EVT_START_GAME); + GetEventHandler()->AddPendingEvent(evt); + if (m_is_hosting) + { + m_start_btn->Disable(); + m_memcard_write->Disable(); + m_game_btn->Disable(); + m_player_config_btn->Disable(); + } - m_record_chkbox->Disable(); + m_record_chkbox->Disable(); } void NetPlayDialog::OnMsgStopGame() { - wxThreadEvent evt(wxEVT_THREAD, NP_GUI_EVT_STOP_GAME); - GetEventHandler()->AddPendingEvent(evt); - if (m_is_hosting) - { - m_start_btn->Enable(); - m_memcard_write->Enable(); - m_game_btn->Enable(); - m_player_config_btn->Enable(); - } - m_record_chkbox->Enable(); + wxThreadEvent evt(wxEVT_THREAD, NP_GUI_EVT_STOP_GAME); + GetEventHandler()->AddPendingEvent(evt); + if (m_is_hosting) + { + m_start_btn->Enable(); + m_memcard_write->Enable(); + m_game_btn->Enable(); + m_player_config_btn->Enable(); + } + m_record_chkbox->Enable(); } void NetPlayDialog::OnAdjustBuffer(wxCommandEvent& event) { - const int val = ((wxSpinCtrl*)event.GetEventObject())->GetValue(); - netplay_server->AdjustPadBufferSize(val); + const int val = ((wxSpinCtrl*)event.GetEventObject())->GetValue(); + netplay_server->AdjustPadBufferSize(val); - std::ostringstream ss; - ss << "< Pad Buffer: " << val << " >"; - netplay_client->SendChatMessage(ss.str()); - m_chat_text->AppendText(StrToWxStr(ss.str()).Append('\n')); + std::ostringstream ss; + ss << "< Pad Buffer: " << val << " >"; + netplay_client->SendChatMessage(ss.str()); + m_chat_text->AppendText(StrToWxStr(ss.str()).Append('\n')); } void NetPlayDialog::OnQuit(wxCommandEvent&) { - Destroy(); + Destroy(); } // update gui void NetPlayDialog::OnThread(wxThreadEvent& event) { - if (m_is_hosting && m_host_label && g_TraversalClient) - { - UpdateHostLabel(); - } + if (m_is_hosting && m_host_label && g_TraversalClient) + { + UpdateHostLabel(); + } - // player list - m_playerids.clear(); - std::string tmps; - netplay_client->GetPlayerList(tmps, m_playerids); + // player list + m_playerids.clear(); + std::string tmps; + netplay_client->GetPlayerList(tmps, m_playerids); - wxString selection; - if (m_player_lbox->GetSelection() != wxNOT_FOUND) - selection = m_player_lbox->GetString(m_player_lbox->GetSelection()); + wxString selection; + if (m_player_lbox->GetSelection() != wxNOT_FOUND) + selection = m_player_lbox->GetString(m_player_lbox->GetSelection()); - m_player_lbox->Clear(); - std::istringstream ss(tmps); - while (std::getline(ss, tmps)) - m_player_lbox->Append(StrToWxStr(tmps)); + m_player_lbox->Clear(); + std::istringstream ss(tmps); + while (std::getline(ss, tmps)) + m_player_lbox->Append(StrToWxStr(tmps)); - // remove ping from selection string, in case it has changed - selection.erase(selection.rfind('|') + 1); + // remove ping from selection string, in case it has changed + selection.erase(selection.rfind('|') + 1); - if (!selection.empty()) - { - for (unsigned int i = 0; i < m_player_lbox->GetCount(); ++i) - { - if (selection == m_player_lbox->GetString(i).substr(0, selection.length())) - { - m_player_lbox->SetSelection(i); - break; - } - } - } + if (!selection.empty()) + { + for (unsigned int i = 0; i < m_player_lbox->GetCount(); ++i) + { + if (selection == m_player_lbox->GetString(i).substr(0, selection.length())) + { + m_player_lbox->SetSelection(i); + break; + } + } + } - // flash window in taskbar when someone joins if window isn't active - static u8 numPlayers = 1; - if (netplay_server != nullptr && numPlayers < m_playerids.size() && !HasFocus()) - { - RequestUserAttention(); - } - numPlayers = m_playerids.size(); + // flash window in taskbar when someone joins if window isn't active + static u8 numPlayers = 1; + if (netplay_server != nullptr && numPlayers < m_playerids.size() && !HasFocus()) + { + RequestUserAttention(); + } + numPlayers = m_playerids.size(); - switch (event.GetId()) - { - case NP_GUI_EVT_CHANGE_GAME: - // update selected game :/ - { - m_selected_game = WxStrToStr(event.GetString()); + switch (event.GetId()) + { + case NP_GUI_EVT_CHANGE_GAME: + // update selected game :/ + { + m_selected_game = WxStrToStr(event.GetString()); - wxString button_label = event.GetString(); - m_game_btn->SetLabel(button_label.Prepend(_(" Game : "))); - } - break; - case NP_GUI_EVT_START_GAME: - // client start game :/ - { - netplay_client->StartGame(FindGame()); - } - break; - case NP_GUI_EVT_STOP_GAME: - // client stop game - { - netplay_client->StopGame(); - } - break; - } + wxString button_label = event.GetString(); + m_game_btn->SetLabel(button_label.Prepend(_(" Game : "))); + } + break; + case NP_GUI_EVT_START_GAME: + // client start game :/ + { + netplay_client->StartGame(FindGame()); + } + break; + case NP_GUI_EVT_STOP_GAME: + // client stop game + { + netplay_client->StopGame(); + } + break; + } - // chat messages - while (chat_msgs.Size()) - { - std::string s; - chat_msgs.Pop(s); - //PanicAlert("message: %s", s.c_str()); - m_chat_text->AppendText(StrToWxStr(s).Append('\n')); - } + // chat messages + while (chat_msgs.Size()) + { + std::string s; + chat_msgs.Pop(s); + // PanicAlert("message: %s", s.c_str()); + m_chat_text->AppendText(StrToWxStr(s).Append('\n')); + } } void NetPlayDialog::OnChangeGame(wxCommandEvent&) { - ChangeGameDialog cgd(this, m_game_list); - cgd.ShowModal(); + ChangeGameDialog cgd(this, m_game_list); + cgd.ShowModal(); - wxString game_name = cgd.GetChosenGameName(); - if (game_name.empty()) - return; + wxString game_name = cgd.GetChosenGameName(); + if (game_name.empty()) + return; - m_selected_game = WxStrToStr(game_name); - netplay_server->ChangeGame(m_selected_game); - m_game_btn->SetLabel(game_name.Prepend(_(" Game : "))); + m_selected_game = WxStrToStr(game_name); + netplay_server->ChangeGame(m_selected_game); + m_game_btn->SetLabel(game_name.Prepend(_(" Game : "))); } void NetPlayDialog::OnAssignPads(wxCommandEvent&) { - PadMapDialog pmd(this, netplay_server, netplay_client); - pmd.ShowModal(); + PadMapDialog pmd(this, netplay_server, netplay_client); + pmd.ShowModal(); - netplay_server->SetPadMapping(pmd.GetModifiedPadMappings()); + netplay_server->SetPadMapping(pmd.GetModifiedPadMappings()); } void NetPlayDialog::OnKick(wxCommandEvent&) { - wxString selection = m_player_lbox->GetStringSelection(); - unsigned long player = 0; - selection.substr(selection.rfind('[') + 1, selection.rfind(']')).ToULong(&player); + wxString selection = m_player_lbox->GetStringSelection(); + unsigned long player = 0; + selection.substr(selection.rfind('[') + 1, selection.rfind(']')).ToULong(&player); - netplay_server->KickPlayer((u8)player); + netplay_server->KickPlayer((u8)player); - m_player_lbox->SetSelection(wxNOT_FOUND); - wxCommandEvent event; - OnPlayerSelect(event); + m_player_lbox->SetSelection(wxNOT_FOUND); + wxCommandEvent event; + OnPlayerSelect(event); } void NetPlayDialog::OnPlayerSelect(wxCommandEvent&) { - m_kick_btn->Enable(m_player_lbox->GetSelection() > 0); + m_kick_btn->Enable(m_player_lbox->GetSelection() > 0); } bool NetPlayDialog::IsRecording() { - return m_record_chkbox->GetValue(); + return m_record_chkbox->GetValue(); } void NetPlayDialog::OnCopyIP(wxCommandEvent&) { - if (m_host_copy_btn_is_retry) - { - g_TraversalClient->ReconnectToServer(); - Update(); - } - else - { - if (wxTheClipboard->Open()) - { - wxTheClipboard->SetData(new wxTextDataObject(m_host_label->GetLabel())); - wxTheClipboard->Close(); - } - } + if (m_host_copy_btn_is_retry) + { + g_TraversalClient->ReconnectToServer(); + Update(); + } + else + { + if (wxTheClipboard->Open()) + { + wxTheClipboard->SetData(new wxTextDataObject(m_host_label->GetLabel())); + wxTheClipboard->Close(); + } + } } void NetPlayDialog::OnChoice(wxCommandEvent& event) { - UpdateHostLabel(); + UpdateHostLabel(); } void NetPlayDialog::UpdateHostLabel() { - wxString label = _(" (internal IP)"); - auto DeLabel = [=](wxString str) { - if (str == _("Localhost")) - return std::string("!local!"); - return WxStrToStr(str.Left(str.Len() - label.Len())); - }; - auto EnLabel = [=](std::string str) -> wxString { - if (str == "!local!") - return _("Localhost"); - return StrToWxStr(str) + label; - }; - int sel = m_host_type_choice->GetSelection(); - if (sel == 0) - { - // the traversal ID - switch (g_TraversalClient->m_State) - { - case TraversalClient::Connecting: - m_host_label->SetForegroundColour(*wxLIGHT_GREY); - m_host_label->SetLabel("..."); - m_host_copy_btn->SetLabel(_("Copy")); - m_host_copy_btn->Disable(); - break; - case TraversalClient::Connected: - m_host_label->SetForegroundColour(*wxBLACK); - m_host_label->SetLabel(wxString(g_TraversalClient->m_HostId.data(), g_TraversalClient->m_HostId.size())); - m_host_copy_btn->SetLabel(_("Copy")); - m_host_copy_btn->Enable(); - m_host_copy_btn_is_retry = false; - break; - case TraversalClient::Failure: - m_host_label->SetForegroundColour(*wxBLACK); - m_host_label->SetLabel(FailureReasonStringForHostLabel(g_TraversalClient->m_FailureReason)); - m_host_copy_btn->SetLabel(_("Retry")); - m_host_copy_btn->Enable(); - m_host_copy_btn_is_retry = true; - break; - } - } - else if (sel != wxNOT_FOUND) // wxNOT_FOUND shouldn't generally happen - { - m_host_label->SetForegroundColour(*wxBLACK); - m_host_label->SetLabel(netplay_server->GetInterfaceHost(DeLabel(m_host_type_choice->GetString(sel)))); - m_host_copy_btn->SetLabel(_("Copy")); - m_host_copy_btn->Enable(); - m_host_copy_btn_is_retry = false; - } + wxString label = _(" (internal IP)"); + auto DeLabel = [=](wxString str) { + if (str == _("Localhost")) + return std::string("!local!"); + return WxStrToStr(str.Left(str.Len() - label.Len())); + }; + auto EnLabel = [=](std::string str) -> wxString { + if (str == "!local!") + return _("Localhost"); + return StrToWxStr(str) + label; + }; + int sel = m_host_type_choice->GetSelection(); + if (sel == 0) + { + // the traversal ID + switch (g_TraversalClient->m_State) + { + case TraversalClient::Connecting: + m_host_label->SetForegroundColour(*wxLIGHT_GREY); + m_host_label->SetLabel("..."); + m_host_copy_btn->SetLabel(_("Copy")); + m_host_copy_btn->Disable(); + break; + case TraversalClient::Connected: + m_host_label->SetForegroundColour(*wxBLACK); + m_host_label->SetLabel( + wxString(g_TraversalClient->m_HostId.data(), g_TraversalClient->m_HostId.size())); + m_host_copy_btn->SetLabel(_("Copy")); + m_host_copy_btn->Enable(); + m_host_copy_btn_is_retry = false; + break; + case TraversalClient::Failure: + m_host_label->SetForegroundColour(*wxBLACK); + m_host_label->SetLabel(FailureReasonStringForHostLabel(g_TraversalClient->m_FailureReason)); + m_host_copy_btn->SetLabel(_("Retry")); + m_host_copy_btn->Enable(); + m_host_copy_btn_is_retry = true; + break; + } + } + else if (sel != wxNOT_FOUND) // wxNOT_FOUND shouldn't generally happen + { + m_host_label->SetForegroundColour(*wxBLACK); + m_host_label->SetLabel( + netplay_server->GetInterfaceHost(DeLabel(m_host_type_choice->GetString(sel)))); + m_host_copy_btn->SetLabel(_("Copy")); + m_host_copy_btn->Enable(); + m_host_copy_btn_is_retry = false; + } - auto set = netplay_server->GetInterfaceSet(); - for (const std::string& iface : set) - { - wxString wxIface = EnLabel(iface); - if (m_host_type_choice->FindString(wxIface) == wxNOT_FOUND) - m_host_type_choice->Append(wxIface); - } - for (unsigned i = 1, count = m_host_type_choice->GetCount(); i != count; i++) - { - if (set.find(DeLabel(m_host_type_choice->GetString(i))) == set.end()) - { - m_host_type_choice->Delete(i); - i--; - count--; - } - } + auto set = netplay_server->GetInterfaceSet(); + for (const std::string& iface : set) + { + wxString wxIface = EnLabel(iface); + if (m_host_type_choice->FindString(wxIface) == wxNOT_FOUND) + m_host_type_choice->Append(wxIface); + } + for (unsigned i = 1, count = m_host_type_choice->GetCount(); i != count; i++) + { + if (set.find(DeLabel(m_host_type_choice->GetString(i))) == set.end()) + { + m_host_type_choice->Delete(i); + i--; + count--; + } + } } diff --git a/Source/Core/DolphinWX/NetPlay/NetWindow.h b/Source/Core/DolphinWX/NetPlay/NetWindow.h index a5c3d390c9..5646e0b23d 100644 --- a/Source/Core/DolphinWX/NetPlay/NetWindow.h +++ b/Source/Core/DolphinWX/NetPlay/NetWindow.h @@ -24,83 +24,83 @@ class wxTextCtrl; enum { - NP_GUI_EVT_CHANGE_GAME = 45, - NP_GUI_EVT_START_GAME, - NP_GUI_EVT_STOP_GAME, + NP_GUI_EVT_CHANGE_GAME = 45, + NP_GUI_EVT_START_GAME, + NP_GUI_EVT_STOP_GAME, }; enum { - INITIAL_PAD_BUFFER_SIZE = 5 + INITIAL_PAD_BUFFER_SIZE = 5 }; class NetPlayDialog : public wxFrame, public NetPlayUI { public: - NetPlayDialog(wxWindow* parent, const CGameListCtrl* const game_list - , const std::string& game, const bool is_hosting = false); - ~NetPlayDialog(); + NetPlayDialog(wxWindow* parent, const CGameListCtrl* const game_list, const std::string& game, + const bool is_hosting = false); + ~NetPlayDialog(); - Common::FifoQueue chat_msgs; + Common::FifoQueue chat_msgs; - void OnStart(wxCommandEvent& event); + void OnStart(wxCommandEvent& event); - // implementation of NetPlayUI methods - void BootGame(const std::string& filename) override; - void StopGame() override; + // implementation of NetPlayUI methods + void BootGame(const std::string& filename) override; + void StopGame() override; - void Update() override; - void AppendChat(const std::string& msg) override; + void Update() override; + void AppendChat(const std::string& msg) override; - void OnMsgChangeGame(const std::string& filename) override; - void OnMsgStartGame() override; - void OnMsgStopGame() override; + void OnMsgChangeGame(const std::string& filename) override; + void OnMsgStartGame() override; + void OnMsgStopGame() override; - static NetPlayDialog*& GetInstance() { return npd; } - static NetPlayClient*& GetNetPlayClient() { return netplay_client; } - static NetPlayServer*& GetNetPlayServer() { return netplay_server; } - static void FillWithGameNames(wxListBox* game_lbox, const CGameListCtrl& game_list); + static NetPlayDialog*& GetInstance() { return npd; } + static NetPlayClient*& GetNetPlayClient() { return netplay_client; } + static NetPlayServer*& GetNetPlayServer() { return netplay_server; } + static void FillWithGameNames(wxListBox* game_lbox, const CGameListCtrl& game_list); - bool IsRecording() override; + bool IsRecording() override; private: - void OnChat(wxCommandEvent& event); - void OnQuit(wxCommandEvent& event); - void OnThread(wxThreadEvent& event); - void OnChangeGame(wxCommandEvent& event); - void OnAdjustBuffer(wxCommandEvent& event); - void OnAssignPads(wxCommandEvent& event); - void OnKick(wxCommandEvent& event); - void OnPlayerSelect(wxCommandEvent& event); - void GetNetSettings(NetSettings& settings); - std::string FindGame(); + void OnChat(wxCommandEvent& event); + void OnQuit(wxCommandEvent& event); + void OnThread(wxThreadEvent& event); + void OnChangeGame(wxCommandEvent& event); + void OnAdjustBuffer(wxCommandEvent& event); + void OnAssignPads(wxCommandEvent& event); + void OnKick(wxCommandEvent& event); + void OnPlayerSelect(wxCommandEvent& event); + void GetNetSettings(NetSettings& settings); + std::string FindGame(); - void OnCopyIP(wxCommandEvent&); - void OnChoice(wxCommandEvent& event); - void UpdateHostLabel(); + void OnCopyIP(wxCommandEvent&); + void OnChoice(wxCommandEvent& event); + void UpdateHostLabel(); - wxListBox* m_player_lbox; - wxTextCtrl* m_chat_text; - wxTextCtrl* m_chat_msg_text; - wxCheckBox* m_memcard_write; - wxCheckBox* m_record_chkbox; + wxListBox* m_player_lbox; + wxTextCtrl* m_chat_text; + wxTextCtrl* m_chat_msg_text; + wxCheckBox* m_memcard_write; + wxCheckBox* m_record_chkbox; - std::string m_selected_game; - wxButton* m_player_config_btn; - wxButton* m_game_btn; - wxButton* m_start_btn; - wxButton* m_kick_btn; - wxStaticText* m_host_label; - wxChoice* m_host_type_choice; - wxButton* m_host_copy_btn; - bool m_host_copy_btn_is_retry; - bool m_is_hosting; + std::string m_selected_game; + wxButton* m_player_config_btn; + wxButton* m_game_btn; + wxButton* m_start_btn; + wxButton* m_kick_btn; + wxStaticText* m_host_label; + wxChoice* m_host_type_choice; + wxButton* m_host_copy_btn; + bool m_host_copy_btn_is_retry; + bool m_is_hosting; - std::vector m_playerids; + std::vector m_playerids; - const CGameListCtrl* const m_game_list; + const CGameListCtrl* const m_game_list; - static NetPlayDialog* npd; - static NetPlayServer* netplay_server; - static NetPlayClient* netplay_client; + static NetPlayDialog* npd; + static NetPlayServer* netplay_server; + static NetPlayClient* netplay_client; }; diff --git a/Source/Core/DolphinWX/NetPlay/PadMapDialog.cpp b/Source/Core/DolphinWX/NetPlay/PadMapDialog.cpp index e4c8927baa..0eeda464cd 100644 --- a/Source/Core/DolphinWX/NetPlay/PadMapDialog.cpp +++ b/Source/Core/DolphinWX/NetPlay/PadMapDialog.cpp @@ -14,67 +14,66 @@ // Removed Wiimote UI elements due to Wiimotes being flat out broken in netplay. PadMapDialog::PadMapDialog(wxWindow* parent, NetPlayServer* server, NetPlayClient* client) - : wxDialog(parent, wxID_ANY, _("Controller Ports")) - , m_pad_mapping(server->GetPadMapping()) - , m_player_list(client->GetPlayers()) + : wxDialog(parent, wxID_ANY, _("Controller Ports")), m_pad_mapping(server->GetPadMapping()), + m_player_list(client->GetPlayers()) { - wxBoxSizer* const h_szr = new wxBoxSizer(wxHORIZONTAL); - h_szr->AddSpacer(10); + wxBoxSizer* const h_szr = new wxBoxSizer(wxHORIZONTAL); + h_szr->AddSpacer(10); - wxArrayString player_names; - player_names.Add(_("None")); - for (auto& player : m_player_list) - player_names.Add(player->name); + wxArrayString player_names; + player_names.Add(_("None")); + for (auto& player : m_player_list) + player_names.Add(player->name); - for (unsigned int i = 0; i < 4; ++i) - { - wxBoxSizer* const v_szr = new wxBoxSizer(wxVERTICAL); - v_szr->Add(new wxStaticText(this, wxID_ANY, (wxString(_("GC Port ")) + (wxChar)('1' + i))), - 1, wxALIGN_CENTER_HORIZONTAL); + for (unsigned int i = 0; i < 4; ++i) + { + wxBoxSizer* const v_szr = new wxBoxSizer(wxVERTICAL); + v_szr->Add(new wxStaticText(this, wxID_ANY, (wxString(_("GC Port ")) + (wxChar)('1' + i))), 1, + wxALIGN_CENTER_HORIZONTAL); - m_map_cbox[i] = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, player_names); - m_map_cbox[i]->Bind(wxEVT_CHOICE, &PadMapDialog::OnAdjust, this); - if (m_pad_mapping[i] == -1) - { - m_map_cbox[i]->Select(0); - } - else - { - for (unsigned int j = 0; j < m_player_list.size(); j++) - { - if (m_pad_mapping[i] == m_player_list[j]->pid) - m_map_cbox[i]->Select(j + 1); - } - } + m_map_cbox[i] = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, player_names); + m_map_cbox[i]->Bind(wxEVT_CHOICE, &PadMapDialog::OnAdjust, this); + if (m_pad_mapping[i] == -1) + { + m_map_cbox[i]->Select(0); + } + else + { + for (unsigned int j = 0; j < m_player_list.size(); j++) + { + if (m_pad_mapping[i] == m_player_list[j]->pid) + m_map_cbox[i]->Select(j + 1); + } + } - v_szr->Add(m_map_cbox[i], 1); + v_szr->Add(m_map_cbox[i], 1); - h_szr->Add(v_szr, 1, wxTOP | wxEXPAND, 20); - h_szr->AddSpacer(10); - } + h_szr->Add(v_szr, 1, wxTOP | wxEXPAND, 20); + h_szr->AddSpacer(10); + } - wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); - main_szr->Add(h_szr); - main_szr->AddSpacer(5); - main_szr->Add(CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT, 20); - main_szr->AddSpacer(5); - SetSizerAndFit(main_szr); - SetFocus(); + wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); + main_szr->Add(h_szr); + main_szr->AddSpacer(5); + main_szr->Add(CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT, 20); + main_szr->AddSpacer(5); + SetSizerAndFit(main_szr); + SetFocus(); } PadMappingArray PadMapDialog::GetModifiedPadMappings() const { - return m_pad_mapping; + return m_pad_mapping; } void PadMapDialog::OnAdjust(wxCommandEvent& WXUNUSED(event)) { - for (unsigned int i = 0; i < 4; i++) - { - int player_idx = m_map_cbox[i]->GetSelection(); - if (player_idx > 0) - m_pad_mapping[i] = m_player_list[player_idx - 1]->pid; - else - m_pad_mapping[i] = -1; - } + for (unsigned int i = 0; i < 4; i++) + { + int player_idx = m_map_cbox[i]->GetSelection(); + if (player_idx > 0) + m_pad_mapping[i] = m_player_list[player_idx - 1]->pid; + else + m_pad_mapping[i] = -1; + } } diff --git a/Source/Core/DolphinWX/NetPlay/PadMapDialog.h b/Source/Core/DolphinWX/NetPlay/PadMapDialog.h index 62837b6307..2f824eb07f 100644 --- a/Source/Core/DolphinWX/NetPlay/PadMapDialog.h +++ b/Source/Core/DolphinWX/NetPlay/PadMapDialog.h @@ -17,14 +17,14 @@ class wxChoice; class PadMapDialog final : public wxDialog { public: - PadMapDialog(wxWindow* parent, NetPlayServer* server, NetPlayClient* client); + PadMapDialog(wxWindow* parent, NetPlayServer* server, NetPlayClient* client); - PadMappingArray GetModifiedPadMappings() const; + PadMappingArray GetModifiedPadMappings() const; private: - void OnAdjust(wxCommandEvent& event); + void OnAdjust(wxCommandEvent& event); - wxChoice* m_map_cbox[4]; - PadMappingArray m_pad_mapping; - std::vector m_player_list; + wxChoice* m_map_cbox[4]; + PadMappingArray m_pad_mapping; + std::vector m_player_list; }; diff --git a/Source/Core/DolphinWX/PatchAddEdit.cpp b/Source/Core/DolphinWX/PatchAddEdit.cpp index ef933b117c..a845c60016 100644 --- a/Source/Core/DolphinWX/PatchAddEdit.cpp +++ b/Source/Core/DolphinWX/PatchAddEdit.cpp @@ -21,14 +21,14 @@ #include "DolphinWX/PatchAddEdit.h" #include "DolphinWX/WxUtils.h" -CPatchAddEdit::CPatchAddEdit(int _selection, std::vector* _onFrame, wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& position, const wxSize& size, long style) - : wxDialog(parent, id, title, position, size, style) - , onFrame(_onFrame) - , selection(_selection) +CPatchAddEdit::CPatchAddEdit(int _selection, std::vector* _onFrame, + wxWindow* parent, wxWindowID id, const wxString& title, + const wxPoint& position, const wxSize& size, long style) + : wxDialog(parent, id, title, position, size, style), onFrame(_onFrame), selection(_selection) { - CreateGUIControls(selection); + CreateGUIControls(selection); - Bind(wxEVT_BUTTON, &CPatchAddEdit::SavePatchData, this, wxID_OK); + Bind(wxEVT_BUTTON, &CPatchAddEdit::SavePatchData, this, wxID_OK); } CPatchAddEdit::~CPatchAddEdit() @@ -37,197 +37,203 @@ CPatchAddEdit::~CPatchAddEdit() void CPatchAddEdit::CreateGUIControls(int _selection) { - wxString currentName = _(""); + wxString currentName = _(""); - if (_selection == -1) - { - tempEntries.clear(); - tempEntries.emplace_back(PatchEngine::PATCH_8BIT, 0x00000000, 0x00000000); - } - else - { - currentName = StrToWxStr(onFrame->at(_selection).name); - tempEntries = onFrame->at(_selection).entries; - } + if (_selection == -1) + { + tempEntries.clear(); + tempEntries.emplace_back(PatchEngine::PATCH_8BIT, 0x00000000, 0x00000000); + } + else + { + currentName = StrToWxStr(onFrame->at(_selection).name); + tempEntries = onFrame->at(_selection).entries; + } - itCurEntry = tempEntries.begin(); + itCurEntry = tempEntries.begin(); - wxBoxSizer* sEditPatch = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sEditPatch = new wxBoxSizer(wxVERTICAL); - wxStaticText* EditPatchNameText = new wxStaticText(this, wxID_ANY, _("Name:")); - EditPatchName = new wxTextCtrl(this, wxID_ANY); - EditPatchName->SetValue(currentName); + wxStaticText* EditPatchNameText = new wxStaticText(this, wxID_ANY, _("Name:")); + EditPatchName = new wxTextCtrl(this, wxID_ANY); + EditPatchName->SetValue(currentName); - wxStaticText* EditPatchOffsetText = new wxStaticText(this, wxID_ANY, _("Offset:")); - EditPatchOffset = new wxTextCtrl(this, wxID_ANY); - EditPatchOffset->SetValue(wxString::Format("%08X", tempEntries.at(0).address)); + wxStaticText* EditPatchOffsetText = new wxStaticText(this, wxID_ANY, _("Offset:")); + EditPatchOffset = new wxTextCtrl(this, wxID_ANY); + EditPatchOffset->SetValue(wxString::Format("%08X", tempEntries.at(0).address)); - EntrySelection = new wxSpinButton(this); - EntrySelection->Bind(wxEVT_SPIN, &CPatchAddEdit::ChangeEntry, this); - EntrySelection->SetRange(0, (int)tempEntries.size() - 1); - EntrySelection->SetValue((int)tempEntries.size() - 1); + EntrySelection = new wxSpinButton(this); + EntrySelection->Bind(wxEVT_SPIN, &CPatchAddEdit::ChangeEntry, this); + EntrySelection->SetRange(0, (int)tempEntries.size() - 1); + EntrySelection->SetValue((int)tempEntries.size() - 1); - wxArrayString wxArrayStringFor_EditPatchType; - for (int i = 0; i < 3; ++i) - wxArrayStringFor_EditPatchType.Add(StrToWxStr(PatchEngine::PatchTypeStrings[i])); - EditPatchType = new wxRadioBox(this, wxID_ANY, _("Type"), wxDefaultPosition, wxDefaultSize, wxArrayStringFor_EditPatchType, 3, wxRA_SPECIFY_COLS); - EditPatchType->SetSelection((int)tempEntries.at(0).type); + wxArrayString wxArrayStringFor_EditPatchType; + for (int i = 0; i < 3; ++i) + wxArrayStringFor_EditPatchType.Add(StrToWxStr(PatchEngine::PatchTypeStrings[i])); + EditPatchType = new wxRadioBox(this, wxID_ANY, _("Type"), wxDefaultPosition, wxDefaultSize, + wxArrayStringFor_EditPatchType, 3, wxRA_SPECIFY_COLS); + EditPatchType->SetSelection((int)tempEntries.at(0).type); - wxStaticText* EditPatchValueText = new wxStaticText(this, wxID_ANY, _("Value:")); - EditPatchValue = new wxTextCtrl(this, wxID_ANY); - EditPatchValue->SetValue(wxString::Format("%0*X", PatchEngine::GetPatchTypeCharLength(tempEntries.at(0).type), tempEntries.at(0).value)); + wxStaticText* EditPatchValueText = new wxStaticText(this, wxID_ANY, _("Value:")); + EditPatchValue = new wxTextCtrl(this, wxID_ANY); + EditPatchValue->SetValue( + wxString::Format("%0*X", PatchEngine::GetPatchTypeCharLength(tempEntries.at(0).type), + tempEntries.at(0).value)); - EntryAdd = new wxButton(this, wxID_ANY, _("Add")); - EntryAdd->Bind(wxEVT_BUTTON, &CPatchAddEdit::AddEntry, this); + EntryAdd = new wxButton(this, wxID_ANY, _("Add")); + EntryAdd->Bind(wxEVT_BUTTON, &CPatchAddEdit::AddEntry, this); - EntryRemove = new wxButton(this, wxID_ANY, _("Remove")); - EntryRemove->Bind(wxEVT_BUTTON, &CPatchAddEdit::RemoveEntry, this); - if ((int)tempEntries.size() <= 1) - EntryRemove->Disable(); + EntryRemove = new wxButton(this, wxID_ANY, _("Remove")); + EntryRemove->Bind(wxEVT_BUTTON, &CPatchAddEdit::RemoveEntry, this); + if ((int)tempEntries.size() <= 1) + EntryRemove->Disable(); - wxBoxSizer* sEditPatchName = new wxBoxSizer(wxHORIZONTAL); - sEditPatchName->Add(EditPatchNameText, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - sEditPatchName->Add(EditPatchName, 1, wxEXPAND | wxALL, 5); - sEditPatch->Add(sEditPatchName, 0, wxEXPAND); - sbEntry = new wxStaticBoxSizer(wxVERTICAL, this, wxString::Format(_("Entry 1/%d"), (int)tempEntries.size())); - currentItem = 1; + wxBoxSizer* sEditPatchName = new wxBoxSizer(wxHORIZONTAL); + sEditPatchName->Add(EditPatchNameText, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); + sEditPatchName->Add(EditPatchName, 1, wxEXPAND | wxALL, 5); + sEditPatch->Add(sEditPatchName, 0, wxEXPAND); + sbEntry = new wxStaticBoxSizer(wxVERTICAL, this, + wxString::Format(_("Entry 1/%d"), (int)tempEntries.size())); + currentItem = 1; - wxGridBagSizer* sgEntry = new wxGridBagSizer(0, 0); - sgEntry->Add(EditPatchType, wxGBPosition(0, 0), wxGBSpan(1, 2), wxEXPAND | wxALL, 5); - sgEntry->Add(EditPatchOffsetText, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL | wxALL, 5); - sgEntry->Add(EditPatchOffset, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5); - sgEntry->Add(EditPatchValueText, wxGBPosition(2, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL | wxALL, 5); - sgEntry->Add(EditPatchValue, wxGBPosition(2, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5); - sgEntry->Add(EntrySelection, wxGBPosition(0, 2), wxGBSpan(3, 1), wxEXPAND | wxALL, 5); - sgEntry->AddGrowableCol(1); + wxGridBagSizer* sgEntry = new wxGridBagSizer(0, 0); + sgEntry->Add(EditPatchType, wxGBPosition(0, 0), wxGBSpan(1, 2), wxEXPAND | wxALL, 5); + sgEntry->Add(EditPatchOffsetText, wxGBPosition(1, 0), wxGBSpan(1, 1), + wxALIGN_CENTER_VERTICAL | wxALL, 5); + sgEntry->Add(EditPatchOffset, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5); + sgEntry->Add(EditPatchValueText, wxGBPosition(2, 0), wxGBSpan(1, 1), + wxALIGN_CENTER_VERTICAL | wxALL, 5); + sgEntry->Add(EditPatchValue, wxGBPosition(2, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5); + sgEntry->Add(EntrySelection, wxGBPosition(0, 2), wxGBSpan(3, 1), wxEXPAND | wxALL, 5); + sgEntry->AddGrowableCol(1); - wxBoxSizer* sEntryAddRemove = new wxBoxSizer(wxHORIZONTAL); - sEntryAddRemove->Add(EntryAdd, 0, wxALL, 5); - sEntryAddRemove->Add(EntryRemove, 0, wxALL, 5); - sbEntry->Add(sgEntry, 0, wxEXPAND); - sbEntry->Add(sEntryAddRemove, 0, wxEXPAND); + wxBoxSizer* sEntryAddRemove = new wxBoxSizer(wxHORIZONTAL); + sEntryAddRemove->Add(EntryAdd, 0, wxALL, 5); + sEntryAddRemove->Add(EntryRemove, 0, wxALL, 5); + sbEntry->Add(sgEntry, 0, wxEXPAND); + sbEntry->Add(sEntryAddRemove, 0, wxEXPAND); - sEditPatch->Add(sbEntry, 0, wxEXPAND | wxALL, 5); - sEditPatch->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - SetSizerAndFit(sEditPatch); - SetFocus(); + sEditPatch->Add(sbEntry, 0, wxEXPAND | wxALL, 5); + sEditPatch->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + SetSizerAndFit(sEditPatch); + SetFocus(); } void CPatchAddEdit::ChangeEntry(wxSpinEvent& event) { - if (!UpdateTempEntryData(itCurEntry)) - return; + if (!UpdateTempEntryData(itCurEntry)) + return; - itCurEntry = tempEntries.end() - event.GetPosition() - 1; - currentItem = (int)tempEntries.size() - event.GetPosition(); - UpdateEntryCtrls(*itCurEntry); + itCurEntry = tempEntries.end() - event.GetPosition() - 1; + currentItem = (int)tempEntries.size() - event.GetPosition(); + UpdateEntryCtrls(*itCurEntry); } void CPatchAddEdit::SavePatchData(wxCommandEvent& event) { - if (!UpdateTempEntryData(itCurEntry)) - return; + if (!UpdateTempEntryData(itCurEntry)) + return; - if (selection == -1) - { - PatchEngine::Patch newPatch; - newPatch.name = WxStrToStr(EditPatchName->GetValue()); - newPatch.entries = tempEntries; - newPatch.active = true; + if (selection == -1) + { + PatchEngine::Patch newPatch; + newPatch.name = WxStrToStr(EditPatchName->GetValue()); + newPatch.entries = tempEntries; + newPatch.active = true; - onFrame->push_back(newPatch); - } - else - { - onFrame->at(selection).name = WxStrToStr(EditPatchName->GetValue()); - onFrame->at(selection).entries = tempEntries; - } + onFrame->push_back(newPatch); + } + else + { + onFrame->at(selection).name = WxStrToStr(EditPatchName->GetValue()); + onFrame->at(selection).entries = tempEntries; + } - AcceptAndClose(); - event.Skip(); + AcceptAndClose(); + event.Skip(); } void CPatchAddEdit::AddEntry(wxCommandEvent& event) { - if (!UpdateTempEntryData(itCurEntry)) - return; + if (!UpdateTempEntryData(itCurEntry)) + return; - PatchEngine::PatchEntry peEmptyEntry(PatchEngine::PATCH_8BIT, 0x00000000, 0x00000000); - ++itCurEntry; - currentItem++; - itCurEntry = tempEntries.insert(itCurEntry, peEmptyEntry); + PatchEngine::PatchEntry peEmptyEntry(PatchEngine::PATCH_8BIT, 0x00000000, 0x00000000); + ++itCurEntry; + currentItem++; + itCurEntry = tempEntries.insert(itCurEntry, peEmptyEntry); - EntrySelection->SetRange(EntrySelection->GetMin(), EntrySelection->GetMax() + 1); - UpdateEntryCtrls(*itCurEntry); + EntrySelection->SetRange(EntrySelection->GetMin(), EntrySelection->GetMax() + 1); + UpdateEntryCtrls(*itCurEntry); - EntryRemove->Enable(); - EntrySelection->Enable(); + EntryRemove->Enable(); + EntrySelection->Enable(); } void CPatchAddEdit::RemoveEntry(wxCommandEvent& event) { - itCurEntry = tempEntries.erase(itCurEntry); + itCurEntry = tempEntries.erase(itCurEntry); - if (itCurEntry != tempEntries.begin()) - { - --itCurEntry; - currentItem--; - } - else - { - EntrySelection->SetValue(EntrySelection->GetValue() - 1); - } + if (itCurEntry != tempEntries.begin()) + { + --itCurEntry; + currentItem--; + } + else + { + EntrySelection->SetValue(EntrySelection->GetValue() - 1); + } - EntrySelection->SetRange(EntrySelection->GetMin(), EntrySelection->GetMax() - 1); - UpdateEntryCtrls(*itCurEntry); + EntrySelection->SetRange(EntrySelection->GetMin(), EntrySelection->GetMax() - 1); + UpdateEntryCtrls(*itCurEntry); - if ((int)tempEntries.size() <= 1) - { - EntryRemove->Disable(); - EntrySelection->Disable(); - } + if ((int)tempEntries.size() <= 1) + { + EntryRemove->Disable(); + EntrySelection->Disable(); + } } void CPatchAddEdit::UpdateEntryCtrls(PatchEngine::PatchEntry pE) { - sbEntry->GetStaticBox()->SetLabel(wxString::Format(_("Entry %d/%d"), currentItem, - (int)tempEntries.size())); - EditPatchOffset->SetValue(wxString::Format("%08X", pE.address)); - EditPatchType->SetSelection(pE.type); - EditPatchValue->SetValue(wxString::Format("%0*X", - PatchEngine::GetPatchTypeCharLength(pE.type), pE.value)); + sbEntry->GetStaticBox()->SetLabel( + wxString::Format(_("Entry %d/%d"), currentItem, (int)tempEntries.size())); + EditPatchOffset->SetValue(wxString::Format("%08X", pE.address)); + EditPatchType->SetSelection(pE.type); + EditPatchValue->SetValue( + wxString::Format("%0*X", PatchEngine::GetPatchTypeCharLength(pE.type), pE.value)); } bool CPatchAddEdit::UpdateTempEntryData(std::vector::iterator iterEntry) { - unsigned long value; - bool parsed_ok = true; + unsigned long value; + bool parsed_ok = true; - if (EditPatchOffset->GetValue().ToULong(&value, 16)) - (*iterEntry).address = value; - else - parsed_ok = false; + if (EditPatchOffset->GetValue().ToULong(&value, 16)) + (*iterEntry).address = value; + else + parsed_ok = false; - PatchEngine::PatchType tempType = - (*iterEntry).type = (PatchEngine::PatchType)EditPatchType->GetSelection(); + PatchEngine::PatchType tempType = (*iterEntry).type = + (PatchEngine::PatchType)EditPatchType->GetSelection(); - if (EditPatchValue->GetValue().ToULong(&value, 16)) - { - (*iterEntry).value = value; - if (tempType == PatchEngine::PATCH_8BIT && value > 0xff) - parsed_ok = false; - else if (tempType == PatchEngine::PATCH_16BIT && value > 0xffff) - parsed_ok = false; - } - else - { - parsed_ok = false; - } + if (EditPatchValue->GetValue().ToULong(&value, 16)) + { + (*iterEntry).value = value; + if (tempType == PatchEngine::PATCH_8BIT && value > 0xff) + parsed_ok = false; + else if (tempType == PatchEngine::PATCH_16BIT && value > 0xffff) + parsed_ok = false; + } + else + { + parsed_ok = false; + } - if (!parsed_ok) - { - wxMessageBox(_("Unable to create patch from given values.\nEntry not modified."), _("Error")); - } + if (!parsed_ok) + { + wxMessageBox(_("Unable to create patch from given values.\nEntry not modified."), _("Error")); + } - return parsed_ok; + return parsed_ok; } diff --git a/Source/Core/DolphinWX/PatchAddEdit.h b/Source/Core/DolphinWX/PatchAddEdit.h index 6d0ebc8db5..22be6d32aa 100644 --- a/Source/Core/DolphinWX/PatchAddEdit.h +++ b/Source/Core/DolphinWX/PatchAddEdit.h @@ -19,35 +19,32 @@ class wxTextCtrl; class CPatchAddEdit : public wxDialog { public: - CPatchAddEdit(int _selection, std::vector* _onFrame, - wxWindow* parent, - wxWindowID id = wxID_ANY, - const wxString& title = _("Edit Patch"), - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxDEFAULT_DIALOG_STYLE); - virtual ~CPatchAddEdit(); + CPatchAddEdit(int _selection, std::vector* _onFrame, wxWindow* parent, + wxWindowID id = wxID_ANY, const wxString& title = _("Edit Patch"), + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_DIALOG_STYLE); + virtual ~CPatchAddEdit(); private: - wxTextCtrl* EditPatchName; - wxTextCtrl* EditPatchOffset; - wxRadioBox* EditPatchType; - wxTextCtrl* EditPatchValue; - wxSpinButton* EntrySelection; - wxButton* EntryAdd; - wxButton* EntryRemove; - wxStaticBoxSizer* sbEntry; - std::vector* onFrame; + wxTextCtrl* EditPatchName; + wxTextCtrl* EditPatchOffset; + wxRadioBox* EditPatchType; + wxTextCtrl* EditPatchValue; + wxSpinButton* EntrySelection; + wxButton* EntryAdd; + wxButton* EntryRemove; + wxStaticBoxSizer* sbEntry; + std::vector* onFrame; - void CreateGUIControls(int selection); - void ChangeEntry(wxSpinEvent& event); - void SavePatchData(wxCommandEvent& event); - void AddEntry(wxCommandEvent& event); - void RemoveEntry(wxCommandEvent& event); - void UpdateEntryCtrls(PatchEngine::PatchEntry pE); - bool UpdateTempEntryData(std::vector::iterator iterEntry); + void CreateGUIControls(int selection); + void ChangeEntry(wxSpinEvent& event); + void SavePatchData(wxCommandEvent& event); + void AddEntry(wxCommandEvent& event); + void RemoveEntry(wxCommandEvent& event); + void UpdateEntryCtrls(PatchEngine::PatchEntry pE); + bool UpdateTempEntryData(std::vector::iterator iterEntry); - int selection, currentItem; - std::vector tempEntries; - std::vector::iterator itCurEntry; + int selection, currentItem; + std::vector tempEntries; + std::vector::iterator itCurEntry; }; diff --git a/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp b/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp index 343fa27f5e..19c4a2b952 100644 --- a/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp +++ b/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp @@ -21,295 +21,305 @@ #include "VideoCommon/RenderBase.h" PostProcessingConfigDiag::PostProcessingConfigDiag(wxWindow* parent, const std::string& shader) - : wxDialog(parent, wxID_ANY, _("Post Processing Shader Configuration")), - m_shader(shader) + : wxDialog(parent, wxID_ANY, _("Post Processing Shader Configuration")), m_shader(shader) { - // Depending on if we are running already, either use the one from the videobackend - // or generate our own. - if (g_renderer && g_renderer->GetPostProcessor()) - { - m_post_processor = g_renderer->GetPostProcessor()->GetConfig(); - } - else - { - m_post_processor = new PostProcessingShaderConfiguration(); - m_post_processor->LoadShader(m_shader); - } + // Depending on if we are running already, either use the one from the videobackend + // or generate our own. + if (g_renderer && g_renderer->GetPostProcessor()) + { + m_post_processor = g_renderer->GetPostProcessor()->GetConfig(); + } + else + { + m_post_processor = new PostProcessingShaderConfiguration(); + m_post_processor->LoadShader(m_shader); + } - // Create our UI classes - const PostProcessingShaderConfiguration::ConfigMap& config_map = m_post_processor->GetOptions(); - for (const auto& it : config_map) - { - if (it.second.m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL) - { - ConfigGrouping* group = new ConfigGrouping(ConfigGrouping::WidgetType::TYPE_TOGGLE, - it.second.m_gui_name, it.first, it.second.m_dependent_option, - &it.second); - m_config_map[it.first] = group; - } - else - { - ConfigGrouping* group = new ConfigGrouping(ConfigGrouping::WidgetType::TYPE_SLIDER, - it.second.m_gui_name, it.first, it.second.m_dependent_option, - &it.second); - m_config_map[it.first] = group; - } - } + // Create our UI classes + const PostProcessingShaderConfiguration::ConfigMap& config_map = m_post_processor->GetOptions(); + for (const auto& it : config_map) + { + if (it.second.m_type == + PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL) + { + ConfigGrouping* group = + new ConfigGrouping(ConfigGrouping::WidgetType::TYPE_TOGGLE, it.second.m_gui_name, + it.first, it.second.m_dependent_option, &it.second); + m_config_map[it.first] = group; + } + else + { + ConfigGrouping* group = + new ConfigGrouping(ConfigGrouping::WidgetType::TYPE_SLIDER, it.second.m_gui_name, + it.first, it.second.m_dependent_option, &it.second); + m_config_map[it.first] = group; + } + } - // Arrange our vectors based on dependency - for (const auto& it : m_config_map) - { - const std::string parent_name = it.second->GetParent(); - if (parent_name.size()) - { - // Since it depends on a different object, push it to a parent's object - m_config_map[parent_name]->AddChild(m_config_map[it.first]); - } - else - { - // It doesn't have a child, just push it to the vector - m_config_groups.push_back(m_config_map[it.first]); - } - } + // Arrange our vectors based on dependency + for (const auto& it : m_config_map) + { + const std::string parent_name = it.second->GetParent(); + if (parent_name.size()) + { + // Since it depends on a different object, push it to a parent's object + m_config_map[parent_name]->AddChild(m_config_map[it.first]); + } + else + { + // It doesn't have a child, just push it to the vector + m_config_groups.push_back(m_config_map[it.first]); + } + } - // Generate our UI - wxNotebook* const notebook = new wxNotebook(this, wxID_ANY); - wxPanel* const page_general = new wxPanel(notebook); - wxFlexGridSizer* const szr_general = new wxFlexGridSizer(2, 5, 5); + // Generate our UI + wxNotebook* const notebook = new wxNotebook(this, wxID_ANY); + wxPanel* const page_general = new wxPanel(notebook); + wxFlexGridSizer* const szr_general = new wxFlexGridSizer(2, 5, 5); - // Now let's actually populate our window with our information - bool add_general_page = false; - for (const auto& it : m_config_groups) - { - if (it->HasChildren()) - { - // Options with children get their own tab - wxPanel* const page_option = new wxPanel(notebook); - wxFlexGridSizer* const szr_option = new wxFlexGridSizer(2, 10, 5); - it->GenerateUI(this, page_option, szr_option); + // Now let's actually populate our window with our information + bool add_general_page = false; + for (const auto& it : m_config_groups) + { + if (it->HasChildren()) + { + // Options with children get their own tab + wxPanel* const page_option = new wxPanel(notebook); + wxFlexGridSizer* const szr_option = new wxFlexGridSizer(2, 10, 5); + it->GenerateUI(this, page_option, szr_option); - // Add all the children - for (const auto& child : it->GetChildren()) - { - child->GenerateUI(this, page_option, szr_option); - } - page_option->SetSizerAndFit(szr_option); - notebook->AddPage(page_option, _(it->GetGUIName())); - } - else - { - // Options with no children go in to the general tab - if (!add_general_page) - { - // Make it so it doesn't show up if there aren't any options without children. - add_general_page = true; - } - it->GenerateUI(this, page_general, szr_general); - } - } + // Add all the children + for (const auto& child : it->GetChildren()) + { + child->GenerateUI(this, page_option, szr_option); + } + page_option->SetSizerAndFit(szr_option); + notebook->AddPage(page_option, _(it->GetGUIName())); + } + else + { + // Options with no children go in to the general tab + if (!add_general_page) + { + // Make it so it doesn't show up if there aren't any options without children. + add_general_page = true; + } + it->GenerateUI(this, page_general, szr_general); + } + } - if (add_general_page) - { - page_general->SetSizerAndFit(szr_general); - notebook->InsertPage(0, page_general, _("General")); - } + if (add_general_page) + { + page_general->SetSizerAndFit(szr_general); + notebook->InsertPage(0, page_general, _("General")); + } - // Close Button - wxButton* const btn_close = new wxButton(this, wxID_OK, _("Close")); - btn_close->Bind(wxEVT_BUTTON, &PostProcessingConfigDiag::Event_ClickClose, this); + // Close Button + wxButton* const btn_close = new wxButton(this, wxID_OK, _("Close")); + btn_close->Bind(wxEVT_BUTTON, &PostProcessingConfigDiag::Event_ClickClose, this); - Bind(wxEVT_CLOSE_WINDOW, &PostProcessingConfigDiag::Event_Close, this); + Bind(wxEVT_CLOSE_WINDOW, &PostProcessingConfigDiag::Event_Close, this); - wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL); - szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5); - szr_main->Add(btn_close, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5); + wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL); + szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5); + szr_main->Add(btn_close, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5); - SetSizerAndFit(szr_main); - Center(); - SetFocus(); + SetSizerAndFit(szr_main); + Center(); + SetFocus(); - UpdateWindowUI(); + UpdateWindowUI(); } PostProcessingConfigDiag::~PostProcessingConfigDiag() { - m_post_processor->SaveOptionsConfiguration(); - if (g_renderer && g_renderer->GetPostProcessor()) - m_post_processor = nullptr; - else - delete m_post_processor; + m_post_processor->SaveOptionsConfiguration(); + if (g_renderer && g_renderer->GetPostProcessor()) + m_post_processor = nullptr; + else + delete m_post_processor; } -void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDiag* dialog, wxWindow* parent, wxFlexGridSizer* sizer) +void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDiag* dialog, + wxWindow* parent, wxFlexGridSizer* sizer) { - if (m_type == WidgetType::TYPE_TOGGLE) - { - m_option_checkbox = new wxCheckBox(parent, wxID_ANY, _(m_gui_name)); - m_option_checkbox->SetValue(m_config_option->m_bool_value); - m_option_checkbox->Bind(wxEVT_CHECKBOX, &PostProcessingConfigDiag::Event_CheckBox, - dialog, wxID_ANY, wxID_ANY, new UserEventData(m_option)); + if (m_type == WidgetType::TYPE_TOGGLE) + { + m_option_checkbox = new wxCheckBox(parent, wxID_ANY, _(m_gui_name)); + m_option_checkbox->SetValue(m_config_option->m_bool_value); + m_option_checkbox->Bind(wxEVT_CHECKBOX, &PostProcessingConfigDiag::Event_CheckBox, dialog, + wxID_ANY, wxID_ANY, new UserEventData(m_option)); - sizer->Add(m_option_checkbox); - sizer->AddStretchSpacer(); - } - else - { - size_t vector_size = 0; - if (m_config_option->m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER) - vector_size = m_config_option->m_integer_values.size(); - else - vector_size = m_config_option->m_float_values.size(); + sizer->Add(m_option_checkbox); + sizer->AddStretchSpacer(); + } + else + { + size_t vector_size = 0; + if (m_config_option->m_type == + PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER) + vector_size = m_config_option->m_integer_values.size(); + else + vector_size = m_config_option->m_float_values.size(); - wxFlexGridSizer* const szr_values = new wxFlexGridSizer(vector_size + 1, 0, 0); - wxStaticText* const option_static_text = new wxStaticText(parent, wxID_ANY, _(m_gui_name)); - sizer->Add(option_static_text); + wxFlexGridSizer* const szr_values = new wxFlexGridSizer(vector_size + 1, 0, 0); + wxStaticText* const option_static_text = new wxStaticText(parent, wxID_ANY, _(m_gui_name)); + sizer->Add(option_static_text); - for (size_t i = 0; i < vector_size; ++i) - { - // wxSlider uses a signed integer for it's minimum and maximum values - // This won't work for floats. - // Let's determine how many steps we can take and use that instead. - int steps = 0; - int current_value = 0; - std::string string_value; - if (m_config_option->m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER) - { - // Find out our range by taking the max subtracting the minimum. - double range = m_config_option->m_integer_max_values[i] - m_config_option->m_integer_min_values[i]; + for (size_t i = 0; i < vector_size; ++i) + { + // wxSlider uses a signed integer for it's minimum and maximum values + // This won't work for floats. + // Let's determine how many steps we can take and use that instead. + int steps = 0; + int current_value = 0; + std::string string_value; + if (m_config_option->m_type == + PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER) + { + // Find out our range by taking the max subtracting the minimum. + double range = + m_config_option->m_integer_max_values[i] - m_config_option->m_integer_min_values[i]; - // How many steps we have is the range divided by the step interval configured. - // This may not be 100% spot on accurate since developers can have odd stepping intervals set. - // Round up so if it is outside our range, then set it to the minimum or maximum - steps = ceil(range / (double)m_config_option->m_integer_step_values[i]); + // How many steps we have is the range divided by the step interval configured. + // This may not be 100% spot on accurate since developers can have odd stepping intervals + // set. + // Round up so if it is outside our range, then set it to the minimum or maximum + steps = ceil(range / (double)m_config_option->m_integer_step_values[i]); - // Default value is just the currently set value here - current_value = m_config_option->m_integer_values[i]; - string_value = std::to_string(m_config_option->m_integer_values[i]); - } - else - { - // Same as above but with floats - float range = m_config_option->m_float_max_values[i] - m_config_option->m_float_min_values[i]; - steps = ceil(range / m_config_option->m_float_step_values[i]); + // Default value is just the currently set value here + current_value = m_config_option->m_integer_values[i]; + string_value = std::to_string(m_config_option->m_integer_values[i]); + } + else + { + // Same as above but with floats + float range = + m_config_option->m_float_max_values[i] - m_config_option->m_float_min_values[i]; + steps = ceil(range / m_config_option->m_float_step_values[i]); - // We need to convert our default float value from a float to the nearest step value range - current_value = (m_config_option->m_float_values[i] / m_config_option->m_float_step_values[i]); - string_value = std::to_string(m_config_option->m_float_values[i]); - } + // We need to convert our default float value from a float to the nearest step value range + current_value = + (m_config_option->m_float_values[i] / m_config_option->m_float_step_values[i]); + string_value = std::to_string(m_config_option->m_float_values[i]); + } - wxSlider* slider = new wxSlider(parent, wxID_ANY, current_value, 0, steps, - wxDefaultPosition, wxSize(200, -1), wxSL_HORIZONTAL | wxSL_BOTTOM); - wxTextCtrl* text_ctrl = new wxTextCtrl(parent, wxID_ANY, string_value); + wxSlider* slider = new wxSlider(parent, wxID_ANY, current_value, 0, steps, wxDefaultPosition, + wxSize(200, -1), wxSL_HORIZONTAL | wxSL_BOTTOM); + wxTextCtrl* text_ctrl = new wxTextCtrl(parent, wxID_ANY, string_value); - // Disable the textctrl, it's only there to show the absolute value from the slider - text_ctrl->Disable(); + // Disable the textctrl, it's only there to show the absolute value from the slider + text_ctrl->Disable(); - // wxWidget takes over the pointer provided to it in the event handler. - // This won't be a memory leak, it'll be destroyed on dialog close. - slider->Bind(wxEVT_SLIDER, &PostProcessingConfigDiag::Event_Slider, - dialog, wxID_ANY, wxID_ANY, new UserEventData(m_option)); + // wxWidget takes over the pointer provided to it in the event handler. + // This won't be a memory leak, it'll be destroyed on dialog close. + slider->Bind(wxEVT_SLIDER, &PostProcessingConfigDiag::Event_Slider, dialog, wxID_ANY, + wxID_ANY, new UserEventData(m_option)); - m_option_sliders.push_back(slider); - m_option_text_ctrls.push_back(text_ctrl); - } + m_option_sliders.push_back(slider); + m_option_text_ctrls.push_back(text_ctrl); + } - if (vector_size == 1) - { - szr_values->Add(m_option_sliders[0], wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL)); - szr_values->Add(m_option_text_ctrls[0]); + if (vector_size == 1) + { + szr_values->Add(m_option_sliders[0], wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL)); + szr_values->Add(m_option_text_ctrls[0]); - sizer->Add(szr_values); - } - else - { - wxFlexGridSizer* const szr_inside = new wxFlexGridSizer(2, 0, 0); - for (size_t i = 0; i < vector_size; ++i) - { - szr_inside->Add(m_option_sliders[i], wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL)); - szr_inside->Add(m_option_text_ctrls[i]); - } + sizer->Add(szr_values); + } + else + { + wxFlexGridSizer* const szr_inside = new wxFlexGridSizer(2, 0, 0); + for (size_t i = 0; i < vector_size; ++i) + { + szr_inside->Add(m_option_sliders[i], wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL)); + szr_inside->Add(m_option_text_ctrls[i]); + } - szr_values->Add(szr_inside); - sizer->Add(szr_values); - } - } + szr_values->Add(szr_inside); + sizer->Add(szr_values); + } + } } void PostProcessingConfigDiag::ConfigGrouping::EnableDependentChildren(bool enable) { - // Enable or disable all the children - for (auto& it : m_children) - { - if (it->m_type == ConfigGrouping::WidgetType::TYPE_TOGGLE) - { - it->m_option_checkbox->Enable(enable); - } - else - { - for (auto& slider : it->m_option_sliders) - slider->Enable(enable); - } - // Set this objects children as well - it->EnableDependentChildren(enable); - } + // Enable or disable all the children + for (auto& it : m_children) + { + if (it->m_type == ConfigGrouping::WidgetType::TYPE_TOGGLE) + { + it->m_option_checkbox->Enable(enable); + } + else + { + for (auto& slider : it->m_option_sliders) + slider->Enable(enable); + } + // Set this objects children as well + it->EnableDependentChildren(enable); + } } -void PostProcessingConfigDiag::Event_CheckBox(wxCommandEvent &ev) +void PostProcessingConfigDiag::Event_CheckBox(wxCommandEvent& ev) { - UserEventData* config_option = (UserEventData*)ev.GetEventUserData(); - ConfigGrouping* config = m_config_map[config_option->GetData()]; + UserEventData* config_option = (UserEventData*)ev.GetEventUserData(); + ConfigGrouping* config = m_config_map[config_option->GetData()]; - m_post_processor->SetOptionb(config->GetOption(), ev.IsChecked()); + m_post_processor->SetOptionb(config->GetOption(), ev.IsChecked()); - config->EnableDependentChildren(ev.IsChecked()); + config->EnableDependentChildren(ev.IsChecked()); - ev.Skip(); + ev.Skip(); } -void PostProcessingConfigDiag::Event_Slider(wxCommandEvent &ev) +void PostProcessingConfigDiag::Event_Slider(wxCommandEvent& ev) { - UserEventData* config_option = (UserEventData*)ev.GetEventUserData(); - ConfigGrouping* config = m_config_map[config_option->GetData()]; + UserEventData* config_option = (UserEventData*)ev.GetEventUserData(); + ConfigGrouping* config = m_config_map[config_option->GetData()]; - const auto& option_data = m_post_processor->GetOption(config->GetOption()); + const auto& option_data = m_post_processor->GetOption(config->GetOption()); - size_t vector_size = 0; - if (option_data.m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER) - vector_size = option_data.m_integer_values.size(); - else - vector_size = option_data.m_float_values.size(); + size_t vector_size = 0; + if (option_data.m_type == + PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER) + vector_size = option_data.m_integer_values.size(); + else + vector_size = option_data.m_float_values.size(); - for (size_t i = 0; i < vector_size; ++i) - { - // Got to do this garbage again. - // Convert current step in to the real range value - int current_step = config->GetSliderValue(i); - std::string string_value; - if (option_data.m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER) - { - s32 value = option_data.m_integer_step_values[i] * current_step + option_data.m_integer_min_values[i]; - m_post_processor->SetOptioni(config->GetOption(), i, value); - string_value = std::to_string(value); - } - else - { - float value = option_data.m_float_step_values[i] * current_step + option_data.m_float_min_values[i]; - m_post_processor->SetOptionf(config->GetOption(), i, value); - string_value = std::to_string(value); - } - // Update the text box to include the new value - config->SetSliderText(i, string_value); - } - ev.Skip(); + for (size_t i = 0; i < vector_size; ++i) + { + // Got to do this garbage again. + // Convert current step in to the real range value + int current_step = config->GetSliderValue(i); + std::string string_value; + if (option_data.m_type == + PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER) + { + s32 value = + option_data.m_integer_step_values[i] * current_step + option_data.m_integer_min_values[i]; + m_post_processor->SetOptioni(config->GetOption(), i, value); + string_value = std::to_string(value); + } + else + { + float value = + option_data.m_float_step_values[i] * current_step + option_data.m_float_min_values[i]; + m_post_processor->SetOptionf(config->GetOption(), i, value); + string_value = std::to_string(value); + } + // Update the text box to include the new value + config->SetSliderText(i, string_value); + } + ev.Skip(); } void PostProcessingConfigDiag::Event_ClickClose(wxCommandEvent&) { - Close(); + Close(); } void PostProcessingConfigDiag::Event_Close(wxCloseEvent& ev) { - EndModal(wxID_OK); + EndModal(wxID_OK); } - diff --git a/Source/Core/DolphinWX/PostProcessingConfigDiag.h b/Source/Core/DolphinWX/PostProcessingConfigDiag.h index 7642fa1e17..fa896c1fb1 100644 --- a/Source/Core/DolphinWX/PostProcessingConfigDiag.h +++ b/Source/Core/DolphinWX/PostProcessingConfigDiag.h @@ -21,86 +21,86 @@ class wxFlexGridSizer; class PostProcessingConfigDiag : public wxDialog { public: - PostProcessingConfigDiag(wxWindow* parent, const std::string& shader); - ~PostProcessingConfigDiag(); + PostProcessingConfigDiag(wxWindow* parent, const std::string& shader); + ~PostProcessingConfigDiag(); private: + // This is literally the stupidest thing ever + // wxWidgets takes ownership of any pointer given to a event handler + // Instead of passing them a pointer to a std::string, we wrap around it here. + class UserEventData : public wxObject + { + public: + UserEventData(const std::string& data) : m_data(data) {} + const std::string& GetData() { return m_data; } + private: + const std::string m_data; + }; - // This is literally the stupidest thing ever - // wxWidgets takes ownership of any pointer given to a event handler - // Instead of passing them a pointer to a std::string, we wrap around it here. - class UserEventData : public wxObject - { - public: - UserEventData(const std::string& data) : m_data(data) {} - const std::string& GetData() { return m_data; } - private: - const std::string m_data; - }; + class ConfigGrouping + { + public: + enum WidgetType + { + TYPE_TOGGLE, + TYPE_SLIDER, + }; - class ConfigGrouping - { - public: - enum WidgetType - { - TYPE_TOGGLE, - TYPE_SLIDER, - }; + ConfigGrouping(WidgetType type, const std::string& gui_name, const std::string& option_name, + const std::string& parent, + const PostProcessingShaderConfiguration::ConfigurationOption* config_option) + : m_type(type), m_gui_name(gui_name), m_option(option_name), m_parent(parent), + m_config_option(config_option) + { + } - ConfigGrouping(WidgetType type, const std::string& gui_name, - const std::string& option_name, const std::string& parent, - const PostProcessingShaderConfiguration::ConfigurationOption* config_option) - : m_type(type), m_gui_name(gui_name), - m_option(option_name), m_parent(parent), - m_config_option(config_option) {} + void AddChild(ConfigGrouping* child) { m_children.push_back(child); } + bool HasChildren() { return m_children.size() != 0; } + std::vector& GetChildren() { return m_children; } + // Gets the string that is shown in the UI for the option + const std::string& GetGUIName() { return m_gui_name; } + // Gets the option name for use in the shader + // Also is a unique identifier for the option's configuration + const std::string& GetOption() { return m_option; } + // Gets the option name of the parent of this option + const std::string& GetParent() { return m_parent; } + void GenerateUI(PostProcessingConfigDiag* dialog, wxWindow* parent, wxFlexGridSizer* sizer); - void AddChild(ConfigGrouping* child) { m_children.push_back(child); } - bool HasChildren() { return m_children.size() != 0; } - std::vector& GetChildren() { return m_children; } + void EnableDependentChildren(bool enable); - // Gets the string that is shown in the UI for the option - const std::string& GetGUIName() { return m_gui_name; } - // Gets the option name for use in the shader - // Also is a unique identifier for the option's configuration - const std::string& GetOption() { return m_option; } - // Gets the option name of the parent of this option - const std::string& GetParent() { return m_parent; } + int GetSliderValue(const int index) { return m_option_sliders[index]->GetValue(); } + void SetSliderText(const int index, const std::string& text) + { + m_option_text_ctrls[index]->SetValue(text); + } - void GenerateUI(PostProcessingConfigDiag* dialog, wxWindow* parent, wxFlexGridSizer* sizer); + private: + const WidgetType m_type; + const std::string m_gui_name; + const std::string m_option; + const std::string m_parent; + const PostProcessingShaderConfiguration::ConfigurationOption* m_config_option; - void EnableDependentChildren(bool enable); + // For TYPE_TOGGLE + wxCheckBox* m_option_checkbox; - int GetSliderValue(const int index) { return m_option_sliders[index]->GetValue(); } - void SetSliderText(const int index, const std::string& text) { m_option_text_ctrls[index]->SetValue(text); } + // For TYPE_SLIDER + // Can have up to 4 + std::vector m_option_sliders; + std::vector m_option_text_ctrls; - private: - const WidgetType m_type; - const std::string m_gui_name; - const std::string m_option; - const std::string m_parent; - const PostProcessingShaderConfiguration::ConfigurationOption* m_config_option; + std::vector m_children; + }; - // For TYPE_TOGGLE - wxCheckBox* m_option_checkbox; + // WX UI things + void Event_Close(wxCloseEvent&); + void Event_ClickClose(wxCommandEvent&); + void Event_Slider(wxCommandEvent& ev); + void Event_CheckBox(wxCommandEvent& ev); - // For TYPE_SLIDER - // Can have up to 4 - std::vector m_option_sliders; - std::vector m_option_text_ctrls; + const std::string& m_shader; + PostProcessingShaderConfiguration* m_post_processor; - std::vector m_children; - }; - - // WX UI things - void Event_Close(wxCloseEvent&); - void Event_ClickClose(wxCommandEvent&); - void Event_Slider(wxCommandEvent &ev); - void Event_CheckBox(wxCommandEvent &ev); - - const std::string& m_shader; - PostProcessingShaderConfiguration* m_post_processor; - - std::map m_config_map; - std::vector m_config_groups; + std::map m_config_map; + std::vector m_config_groups; }; - diff --git a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp index 71c35003e8..f3737512e6 100644 --- a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp +++ b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp @@ -21,123 +21,137 @@ #include "DolphinWX/WxUtils.h" template -IntegerSetting::IntegerSetting(wxWindow* parent, const wxString& label, T& setting, int minVal, int maxVal, long style) : - wxSpinCtrl(parent, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, style), - m_setting(setting) +IntegerSetting::IntegerSetting(wxWindow* parent, const wxString& label, T& setting, int minVal, + int maxVal, long style) + : wxSpinCtrl(parent, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, style), + m_setting(setting) { - SetRange(minVal, maxVal); - SetValue(m_setting); - Bind(wxEVT_SPINCTRL, &IntegerSetting::UpdateValue, this); + SetRange(minVal, maxVal); + SetValue(m_setting); + Bind(wxEVT_SPINCTRL, &IntegerSetting::UpdateValue, this); } - -SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std::string& title, const std::string& ininame) : - wxDialog(parent, wxID_ANY, - wxString(wxString::Format(_("Dolphin %s Graphics Configuration"), title))) +SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std::string& title, + const std::string& ininame) + : wxDialog(parent, wxID_ANY, + wxString(wxString::Format(_("Dolphin %s Graphics Configuration"), title))) { - VideoConfig& vconfig = g_Config; + VideoConfig& vconfig = g_Config; - if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini")) - vconfig.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"); - else - vconfig.Load(File::GetUserPath(D_CONFIG_IDX) + ininame + ".ini"); + if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini")) + vconfig.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"); + else + vconfig.Load(File::GetUserPath(D_CONFIG_IDX) + ininame + ".ini"); - wxNotebook* const notebook = new wxNotebook(this, wxID_ANY); + wxNotebook* const notebook = new wxNotebook(this, wxID_ANY); - // -- GENERAL -- - { - wxPanel* const page_general= new wxPanel(notebook); - notebook->AddPage(page_general, _("General")); - wxBoxSizer* const szr_general = new wxBoxSizer(wxVERTICAL); + // -- GENERAL -- + { + wxPanel* const page_general = new wxPanel(notebook); + notebook->AddPage(page_general, _("General")); + wxBoxSizer* const szr_general = new wxBoxSizer(wxVERTICAL); - // - rendering - { - wxStaticBoxSizer* const group_rendering = new wxStaticBoxSizer(wxVERTICAL, page_general, _("Rendering")); - szr_general->Add(group_rendering, 0, wxEXPAND | wxALL, 5); - wxGridSizer* const szr_rendering = new wxGridSizer(2, 5, 5); - group_rendering->Add(szr_rendering, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + // - rendering + { + wxStaticBoxSizer* const group_rendering = + new wxStaticBoxSizer(wxVERTICAL, page_general, _("Rendering")); + szr_general->Add(group_rendering, 0, wxEXPAND | wxALL, 5); + wxGridSizer* const szr_rendering = new wxGridSizer(2, 5, 5); + group_rendering->Add(szr_rendering, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - // backend - wxStaticText* const label_backend = new wxStaticText(page_general, wxID_ANY, _("Backend:")); - wxChoice* const choice_backend = new wxChoice(page_general, wxID_ANY); + // backend + wxStaticText* const label_backend = new wxStaticText(page_general, wxID_ANY, _("Backend:")); + wxChoice* const choice_backend = new wxChoice(page_general, wxID_ANY); - for (const auto& backend : g_available_video_backends) - { - choice_backend->AppendString(StrToWxStr(backend->GetDisplayName())); - } + for (const auto& backend : g_available_video_backends) + { + choice_backend->AppendString(StrToWxStr(backend->GetDisplayName())); + } - // TODO: How to get the translated plugin name? - choice_backend->SetStringSelection(StrToWxStr(g_video_backend->GetName())); - choice_backend->Bind(wxEVT_CHOICE, &SoftwareVideoConfigDialog::Event_Backend, this); + // TODO: How to get the translated plugin name? + choice_backend->SetStringSelection(StrToWxStr(g_video_backend->GetName())); + choice_backend->Bind(wxEVT_CHOICE, &SoftwareVideoConfigDialog::Event_Backend, this); - szr_rendering->Add(label_backend, 1, wxALIGN_CENTER_VERTICAL, 5); - szr_rendering->Add(choice_backend, 1, 0, 0); + szr_rendering->Add(label_backend, 1, wxALIGN_CENTER_VERTICAL, 5); + szr_rendering->Add(choice_backend, 1, 0, 0); - if (Core::GetState() != Core::CORE_UNINITIALIZED) - { - label_backend->Disable(); - choice_backend->Disable(); - } + if (Core::GetState() != Core::CORE_UNINITIALIZED) + { + label_backend->Disable(); + choice_backend->Disable(); + } - // xfb - szr_rendering->Add(new SettingCheckBox(page_general, _("Bypass XFB"), "", vconfig.bUseXFB, true)); - } + // xfb + szr_rendering->Add( + new SettingCheckBox(page_general, _("Bypass XFB"), "", vconfig.bUseXFB, true)); + } - // - info - { - wxStaticBoxSizer* const group_info = new wxStaticBoxSizer(wxVERTICAL, page_general, _("Overlay Information")); - szr_general->Add(group_info, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - wxGridSizer* const szr_info = new wxGridSizer(2, 5, 5); - group_info->Add(szr_info, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + // - info + { + wxStaticBoxSizer* const group_info = + new wxStaticBoxSizer(wxVERTICAL, page_general, _("Overlay Information")); + szr_general->Add(group_info, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + wxGridSizer* const szr_info = new wxGridSizer(2, 5, 5); + group_info->Add(szr_info, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - szr_info->Add(new SettingCheckBox(page_general, _("Various Statistics"), "", vconfig.bOverlayStats)); - } + szr_info->Add( + new SettingCheckBox(page_general, _("Various Statistics"), "", vconfig.bOverlayStats)); + } - // - utility - { - wxStaticBoxSizer* const group_utility = new wxStaticBoxSizer(wxVERTICAL, page_general, _("Utility")); - szr_general->Add(group_utility, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - wxGridSizer* const szr_utility = new wxGridSizer(2, 5, 5); - group_utility->Add(szr_utility, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + // - utility + { + wxStaticBoxSizer* const group_utility = + new wxStaticBoxSizer(wxVERTICAL, page_general, _("Utility")); + szr_general->Add(group_utility, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + wxGridSizer* const szr_utility = new wxGridSizer(2, 5, 5); + group_utility->Add(szr_utility, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - szr_utility->Add(new SettingCheckBox(page_general, _("Dump Textures"), "", vconfig.bDumpTextures)); - szr_utility->Add(new SettingCheckBox(page_general, _("Dump Objects"), "", vconfig.bDumpObjects)); + szr_utility->Add( + new SettingCheckBox(page_general, _("Dump Textures"), "", vconfig.bDumpTextures)); + szr_utility->Add( + new SettingCheckBox(page_general, _("Dump Objects"), "", vconfig.bDumpObjects)); - // - debug only - wxStaticBoxSizer* const group_debug_only_utility = new wxStaticBoxSizer(wxHORIZONTAL, page_general, _("Debug Only")); - group_utility->Add(group_debug_only_utility, 0, wxEXPAND | wxBOTTOM, 5); - wxGridSizer* const szr_debug_only_utility = new wxGridSizer(2, 5, 5); - group_debug_only_utility->Add(szr_debug_only_utility, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + // - debug only + wxStaticBoxSizer* const group_debug_only_utility = + new wxStaticBoxSizer(wxHORIZONTAL, page_general, _("Debug Only")); + group_utility->Add(group_debug_only_utility, 0, wxEXPAND | wxBOTTOM, 5); + wxGridSizer* const szr_debug_only_utility = new wxGridSizer(2, 5, 5); + group_debug_only_utility->Add(szr_debug_only_utility, 1, + wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - szr_debug_only_utility->Add(new SettingCheckBox(page_general, _("Dump TEV Stages"), "", vconfig.bDumpTevStages)); - szr_debug_only_utility->Add(new SettingCheckBox(page_general, _("Dump Texture Fetches"), "", vconfig.bDumpTevTextureFetches)); - } + szr_debug_only_utility->Add( + new SettingCheckBox(page_general, _("Dump TEV Stages"), "", vconfig.bDumpTevStages)); + szr_debug_only_utility->Add(new SettingCheckBox(page_general, _("Dump Texture Fetches"), "", + vconfig.bDumpTevTextureFetches)); + } - // - misc - { - wxStaticBoxSizer* const group_misc = new wxStaticBoxSizer(wxVERTICAL, page_general, _("Drawn Object Range")); - szr_general->Add(group_misc, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - wxFlexGridSizer* const szr_misc = new wxFlexGridSizer(2, 5, 5); - group_misc->Add(szr_misc, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + // - misc + { + wxStaticBoxSizer* const group_misc = + new wxStaticBoxSizer(wxVERTICAL, page_general, _("Drawn Object Range")); + szr_general->Add(group_misc, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + wxFlexGridSizer* const szr_misc = new wxFlexGridSizer(2, 5, 5); + group_misc->Add(szr_misc, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - szr_misc->Add(new IntegerSetting(page_general, _("Start"), vconfig.drawStart, 0, 100000)); - szr_misc->Add(new IntegerSetting(page_general, _("End"), vconfig.drawEnd, 0, 100000)); - } + szr_misc->Add( + new IntegerSetting(page_general, _("Start"), vconfig.drawStart, 0, 100000)); + szr_misc->Add(new IntegerSetting(page_general, _("End"), vconfig.drawEnd, 0, 100000)); + } - page_general->SetSizerAndFit(szr_general); - } + page_general->SetSizerAndFit(szr_general); + } - wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL); - szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5); - szr_main->Add(new wxButton(this, wxID_OK, _("Close"), wxDefaultPosition), - 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5); + wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL); + szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5); + szr_main->Add(new wxButton(this, wxID_OK, _("Close"), wxDefaultPosition), 0, + wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5); - SetSizerAndFit(szr_main); - Center(); - SetFocus(); + SetSizerAndFit(szr_main); + Center(); + SetFocus(); } SoftwareVideoConfigDialog::~SoftwareVideoConfigDialog() { - g_Config.Save((File::GetUserPath(D_CONFIG_IDX) + "GFX.ini").c_str()); + g_Config.Save((File::GetUserPath(D_CONFIG_IDX) + "GFX.ini").c_str()); } diff --git a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.h b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.h index 10b5b676df..96c4cb4735 100644 --- a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.h +++ b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.h @@ -19,23 +19,23 @@ class SoftwareVideoConfigDialog : public wxDialog { public: - SoftwareVideoConfigDialog(wxWindow* parent, const std::string &title, const std::string& ininame); - ~SoftwareVideoConfigDialog(); + SoftwareVideoConfigDialog(wxWindow* parent, const std::string& title, const std::string& ininame); + ~SoftwareVideoConfigDialog(); - void Event_Backend(wxCommandEvent &ev) - { - auto& new_backend = g_available_video_backends[ev.GetInt()]; + void Event_Backend(wxCommandEvent& ev) + { + auto& new_backend = g_available_video_backends[ev.GetInt()]; - if (g_video_backend != new_backend.get()) - { - Close(); + if (g_video_backend != new_backend.get()) + { + Close(); - g_video_backend = new_backend.get(); - SConfig::GetInstance().m_strVideoBackend = g_video_backend->GetName(); + g_video_backend = new_backend.get(); + SConfig::GetInstance().m_strVideoBackend = g_video_backend->GetName(); - g_video_backend->ShowConfig(GetParent()); - } + g_video_backend->ShowConfig(GetParent()); + } - ev.Skip(); - } + ev.Skip(); + } }; diff --git a/Source/Core/DolphinWX/TASInputDlg.cpp b/Source/Core/DolphinWX/TASInputDlg.cpp index 9c3d8c1f33..84a7ca94e3 100644 --- a/Source/Core/DolphinWX/TASInputDlg.cpp +++ b/Source/Core/DolphinWX/TASInputDlg.cpp @@ -17,12 +17,12 @@ #include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Core/Core.h" -#include "Core/Movie.h" #include "Core/HW/Wiimote.h" -#include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteEmu/Attachment/Classic.h" #include "Core/HW/WiimoteEmu/Attachment/Nunchuk.h" +#include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" +#include "Core/Movie.h" #include "DolphinWX/TASInputDlg.h" #include "InputCommon/GCPadStatus.h" #include "InputCommon/InputConfig.h" @@ -33,1159 +33,1192 @@ wxDEFINE_EVENT(INVALIDATE_EXTENSION_EVENT, wxThreadEvent); struct TASWiimoteReport { - u8* data; - WiimoteEmu::ReportFeatures rptf; - int ext; - const wiimote_key key; + u8* data; + WiimoteEmu::ReportFeatures rptf; + int ext; + const wiimote_key key; }; TASInputDlg::TASInputDlg(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& position, const wxSize& size, long style) -: wxDialog(parent, id, title, position, size, style) + : wxDialog(parent, id, title, position, size, style) { } void TASInputDlg::CreateBaseLayout() { - for (unsigned int i = 0; i < ArraySize(m_controls); ++i) - m_controls[i] = nullptr; - for (unsigned int i = 0; i < ArraySize(m_buttons); ++i) - m_buttons[i] = nullptr; - for (unsigned int i = 0; i < ArraySize(m_cc_controls); ++i) - m_cc_controls[i] = nullptr; + for (unsigned int i = 0; i < ArraySize(m_controls); ++i) + m_controls[i] = nullptr; + for (unsigned int i = 0; i < ArraySize(m_buttons); ++i) + m_buttons[i] = nullptr; + for (unsigned int i = 0; i < ArraySize(m_cc_controls); ++i) + m_cc_controls[i] = nullptr; - m_buttons[0] = &m_dpad_down; - m_buttons[1] = &m_dpad_up; - m_buttons[2] = &m_dpad_left; - m_buttons[3] = &m_dpad_right; - m_buttons[4] = &m_a; - m_buttons[5] = &m_b; - m_controls[0] = &m_main_stick.x_cont; - m_controls[1] = &m_main_stick.y_cont; + m_buttons[0] = &m_dpad_down; + m_buttons[1] = &m_dpad_up; + m_buttons[2] = &m_dpad_left; + m_buttons[3] = &m_dpad_right; + m_buttons[4] = &m_a; + m_buttons[5] = &m_b; + m_controls[0] = &m_main_stick.x_cont; + m_controls[1] = &m_main_stick.y_cont; - m_a = CreateButton("A"); - m_a.checkbox->SetClientData(&m_a); - m_b = CreateButton("B"); - m_b.checkbox->SetClientData(&m_b); - m_dpad_up = CreateButton("Up"); - m_dpad_up.checkbox->SetClientData(&m_dpad_up); - m_dpad_right = CreateButton("Right"); - m_dpad_right.checkbox->SetClientData(&m_dpad_right); - m_dpad_down = CreateButton("Down"); - m_dpad_down.checkbox->SetClientData(&m_dpad_down); - m_dpad_left = CreateButton("Left"); - m_dpad_left.checkbox->SetClientData(&m_dpad_left); + m_a = CreateButton("A"); + m_a.checkbox->SetClientData(&m_a); + m_b = CreateButton("B"); + m_b.checkbox->SetClientData(&m_b); + m_dpad_up = CreateButton("Up"); + m_dpad_up.checkbox->SetClientData(&m_dpad_up); + m_dpad_right = CreateButton("Right"); + m_dpad_right.checkbox->SetClientData(&m_dpad_right); + m_dpad_down = CreateButton("Down"); + m_dpad_down.checkbox->SetClientData(&m_dpad_down); + m_dpad_left = CreateButton("Left"); + m_dpad_left.checkbox->SetClientData(&m_dpad_left); - m_buttons_dpad = new wxGridSizer(3); - m_buttons_dpad->AddSpacer(20); - m_buttons_dpad->Add(m_dpad_up.checkbox); - m_buttons_dpad->AddSpacer(20); - m_buttons_dpad->Add(m_dpad_left.checkbox); - m_buttons_dpad->AddSpacer(20); - m_buttons_dpad->Add(m_dpad_right.checkbox); - m_buttons_dpad->AddSpacer(20); - m_buttons_dpad->Add(m_dpad_down.checkbox); - m_buttons_dpad->AddSpacer(20); + m_buttons_dpad = new wxGridSizer(3); + m_buttons_dpad->AddSpacer(20); + m_buttons_dpad->Add(m_dpad_up.checkbox); + m_buttons_dpad->AddSpacer(20); + m_buttons_dpad->Add(m_dpad_left.checkbox); + m_buttons_dpad->AddSpacer(20); + m_buttons_dpad->Add(m_dpad_right.checkbox); + m_buttons_dpad->AddSpacer(20); + m_buttons_dpad->Add(m_dpad_down.checkbox); + m_buttons_dpad->AddSpacer(20); } const int TASInputDlg::m_gc_pad_buttons_bitmask[12] = { - PAD_BUTTON_DOWN, PAD_BUTTON_UP, PAD_BUTTON_LEFT, PAD_BUTTON_RIGHT, PAD_BUTTON_A, PAD_BUTTON_B, - PAD_BUTTON_X, PAD_BUTTON_Y, PAD_TRIGGER_Z, PAD_TRIGGER_L, PAD_TRIGGER_R, PAD_BUTTON_START -}; + PAD_BUTTON_DOWN, PAD_BUTTON_UP, PAD_BUTTON_LEFT, PAD_BUTTON_RIGHT, + PAD_BUTTON_A, PAD_BUTTON_B, PAD_BUTTON_X, PAD_BUTTON_Y, + PAD_TRIGGER_Z, PAD_TRIGGER_L, PAD_TRIGGER_R, PAD_BUTTON_START}; const int TASInputDlg::m_wii_buttons_bitmask[11] = { - WiimoteEmu::Wiimote::PAD_DOWN, WiimoteEmu::Wiimote::PAD_UP, WiimoteEmu::Wiimote::PAD_LEFT, - WiimoteEmu::Wiimote::PAD_RIGHT, WiimoteEmu::Wiimote::BUTTON_A, WiimoteEmu::Wiimote::BUTTON_B, - WiimoteEmu::Wiimote::BUTTON_ONE, WiimoteEmu::Wiimote::BUTTON_TWO, WiimoteEmu::Wiimote::BUTTON_PLUS, - WiimoteEmu::Wiimote::BUTTON_MINUS, WiimoteEmu::Wiimote::BUTTON_HOME, + WiimoteEmu::Wiimote::PAD_DOWN, WiimoteEmu::Wiimote::PAD_UP, + WiimoteEmu::Wiimote::PAD_LEFT, WiimoteEmu::Wiimote::PAD_RIGHT, + WiimoteEmu::Wiimote::BUTTON_A, WiimoteEmu::Wiimote::BUTTON_B, + WiimoteEmu::Wiimote::BUTTON_ONE, WiimoteEmu::Wiimote::BUTTON_TWO, + WiimoteEmu::Wiimote::BUTTON_PLUS, WiimoteEmu::Wiimote::BUTTON_MINUS, + WiimoteEmu::Wiimote::BUTTON_HOME, }; const int TASInputDlg::m_cc_buttons_bitmask[15] = { - WiimoteEmu::Classic::PAD_DOWN, WiimoteEmu::Classic::PAD_UP, WiimoteEmu::Classic::PAD_LEFT, - WiimoteEmu::Classic::PAD_RIGHT, WiimoteEmu::Classic::BUTTON_A, WiimoteEmu::Classic::BUTTON_B, - WiimoteEmu::Classic::BUTTON_X, WiimoteEmu::Classic::BUTTON_Y, WiimoteEmu::Classic::BUTTON_PLUS, - WiimoteEmu::Classic::BUTTON_MINUS, WiimoteEmu::Classic::TRIGGER_L, WiimoteEmu::Classic::TRIGGER_R, - WiimoteEmu::Classic::BUTTON_ZR, WiimoteEmu::Classic::BUTTON_ZL, WiimoteEmu::Classic::BUTTON_HOME, + WiimoteEmu::Classic::PAD_DOWN, WiimoteEmu::Classic::PAD_UP, + WiimoteEmu::Classic::PAD_LEFT, WiimoteEmu::Classic::PAD_RIGHT, + WiimoteEmu::Classic::BUTTON_A, WiimoteEmu::Classic::BUTTON_B, + WiimoteEmu::Classic::BUTTON_X, WiimoteEmu::Classic::BUTTON_Y, + WiimoteEmu::Classic::BUTTON_PLUS, WiimoteEmu::Classic::BUTTON_MINUS, + WiimoteEmu::Classic::TRIGGER_L, WiimoteEmu::Classic::TRIGGER_R, + WiimoteEmu::Classic::BUTTON_ZR, WiimoteEmu::Classic::BUTTON_ZL, + WiimoteEmu::Classic::BUTTON_HOME, }; const std::string TASInputDlg::m_cc_button_names[] = { - "Down", "Up", "Left", "Right", "A", "B", "X", "Y", "+", "-", "L", "R", "ZR", "ZL", "Home" -}; + "Down", "Up", "Left", "Right", "A", "B", "X", "Y", "+", "-", "L", "R", "ZR", "ZL", "Home"}; void TASInputDlg::CreateWiiLayout(int num) { - if (m_has_layout) - return; + if (m_has_layout) + return; - CreateBaseLayout(); + CreateBaseLayout(); - m_buttons[6] = &m_one; - m_buttons[7] = &m_two; - m_buttons[8] = &m_plus; - m_buttons[9] = &m_minus; - m_buttons[10] = &m_home; + m_buttons[6] = &m_one; + m_buttons[7] = &m_two; + m_buttons[8] = &m_plus; + m_buttons[9] = &m_minus; + m_buttons[10] = &m_home; - m_controls[4] = &m_x_cont; - m_controls[5] = &m_y_cont; - m_controls[6] = &m_z_cont; + m_controls[4] = &m_x_cont; + m_controls[5] = &m_y_cont; + m_controls[6] = &m_z_cont; - m_main_stick = CreateStick(ID_MAIN_STICK, 1024, 768, 512, 384, true, false); - m_main_stick_szr = CreateStickLayout(&m_main_stick, _("IR")); + m_main_stick = CreateStick(ID_MAIN_STICK, 1024, 768, 512, 384, true, false); + m_main_stick_szr = CreateStickLayout(&m_main_stick, _("IR")); - m_x_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 1023, 512); - m_y_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 1023, 512); - m_z_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 1023, 616); - wxStaticBoxSizer* const axisBox = CreateAccelLayout(&m_x_cont, &m_y_cont, &m_z_cont, _("Orientation")); + m_x_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 1023, 512); + m_y_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 1023, 512); + m_z_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 1023, 616); + wxStaticBoxSizer* const axisBox = + CreateAccelLayout(&m_x_cont, &m_y_cont, &m_z_cont, _("Orientation")); - wxStaticBoxSizer* const m_buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons")); - wxGridSizer* const m_buttons_grid = new wxGridSizer(4); + wxStaticBoxSizer* const m_buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons")); + wxGridSizer* const m_buttons_grid = new wxGridSizer(4); - m_plus = CreateButton("+"); - m_plus.checkbox->SetClientData(&m_plus); - m_minus = CreateButton("-"); - m_minus.checkbox->SetClientData(&m_minus); - m_one = CreateButton("1"); - m_one.checkbox->SetClientData(&m_one); - m_two = CreateButton("2"); - m_two.checkbox->SetClientData(&m_two); - m_home = CreateButton("Home"); - m_home.checkbox->SetClientData(&m_home); + m_plus = CreateButton("+"); + m_plus.checkbox->SetClientData(&m_plus); + m_minus = CreateButton("-"); + m_minus.checkbox->SetClientData(&m_minus); + m_one = CreateButton("1"); + m_one.checkbox->SetClientData(&m_one); + m_two = CreateButton("2"); + m_two.checkbox->SetClientData(&m_two); + m_home = CreateButton("Home"); + m_home.checkbox->SetClientData(&m_home); - m_main_szr = new wxBoxSizer(wxVERTICAL); - m_wiimote_szr = new wxBoxSizer(wxHORIZONTAL); - m_ext_szr = new wxBoxSizer(wxHORIZONTAL); - m_cc_szr = CreateCCLayout(); + m_main_szr = new wxBoxSizer(wxVERTICAL); + m_wiimote_szr = new wxBoxSizer(wxHORIZONTAL); + m_ext_szr = new wxBoxSizer(wxHORIZONTAL); + m_cc_szr = CreateCCLayout(); - if (Core::IsRunning()) - { - m_ext = static_cast(Wiimote::GetConfig()->GetController(num))->CurrentExtension(); - } - else - { - IniFile ini; - ini.Load(File::GetUserPath(D_CONFIG_IDX) + "WiimoteNew.ini"); - std::string extension; - ini.GetIfExists("Wiimote" + std::to_string(num + 1), "Extension", &extension); + if (Core::IsRunning()) + { + m_ext = static_cast(Wiimote::GetConfig()->GetController(num)) + ->CurrentExtension(); + } + else + { + IniFile ini; + ini.Load(File::GetUserPath(D_CONFIG_IDX) + "WiimoteNew.ini"); + std::string extension; + ini.GetIfExists("Wiimote" + std::to_string(num + 1), "Extension", &extension); - if (extension == "Nunchuk") - m_ext = 1; - if (extension == "Classic") - m_ext = 2; - } + if (extension == "Nunchuk") + m_ext = 1; + if (extension == "Classic") + m_ext = 2; + } - m_buttons[11] = &m_c; - m_buttons[12] = &m_z; - m_controls[2] = &m_c_stick.x_cont; - m_controls[3] = &m_c_stick.y_cont; - m_controls[7] = &m_nx_cont; - m_controls[8] = &m_ny_cont; - m_controls[9] = &m_nz_cont; + m_buttons[11] = &m_c; + m_buttons[12] = &m_z; + m_controls[2] = &m_c_stick.x_cont; + m_controls[3] = &m_c_stick.y_cont; + m_controls[7] = &m_nx_cont; + m_controls[8] = &m_ny_cont; + m_controls[9] = &m_nz_cont; - m_c_stick = CreateStick(ID_C_STICK, 255, 255, 128, 128, false, true); - m_c_stick_szr = CreateStickLayout(&m_c_stick, _("Nunchuk stick")); + m_c_stick = CreateStick(ID_C_STICK, 255, 255, 128, 128, false, true); + m_c_stick_szr = CreateStickLayout(&m_c_stick, _("Nunchuk stick")); - m_nx_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 1023, 512); - m_ny_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 1023, 512); - m_nz_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 1023, 512); - wxStaticBoxSizer* const nunchukaxisBox = CreateAccelLayout(&m_nx_cont, &m_ny_cont, &m_nz_cont, _("Nunchuk orientation")); + m_nx_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 1023, 512); + m_ny_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 1023, 512); + m_nz_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 1023, 512); + wxStaticBoxSizer* const nunchukaxisBox = + CreateAccelLayout(&m_nx_cont, &m_ny_cont, &m_nz_cont, _("Nunchuk orientation")); - m_c = CreateButton("C"); - m_c.checkbox->SetClientData(&m_c); - m_z = CreateButton("Z"); - m_z.checkbox->SetClientData(&m_z); - m_ext_szr->Add(m_c_stick_szr, 0, wxLEFT | wxBOTTOM | wxRIGHT, 5); - m_ext_szr->Add(nunchukaxisBox); + m_c = CreateButton("C"); + m_c.checkbox->SetClientData(&m_c); + m_z = CreateButton("Z"); + m_z.checkbox->SetClientData(&m_z); + m_ext_szr->Add(m_c_stick_szr, 0, wxLEFT | wxBOTTOM | wxRIGHT, 5); + m_ext_szr->Add(nunchukaxisBox); - for (Control* const control : m_controls) - { - if (control != nullptr) - control->slider->Bind(wxEVT_RIGHT_UP, &TASInputDlg::OnRightClickSlider, this); - } + for (Control* const control : m_controls) + { + if (control != nullptr) + control->slider->Bind(wxEVT_RIGHT_UP, &TASInputDlg::OnRightClickSlider, this); + } - for (unsigned int i = 4; i < ArraySize(m_buttons); ++i) - if (m_buttons[i] != nullptr) - m_buttons_grid->Add(m_buttons[i]->checkbox); - m_buttons_grid->AddSpacer(5); + for (unsigned int i = 4; i < ArraySize(m_buttons); ++i) + if (m_buttons[i] != nullptr) + m_buttons_grid->Add(m_buttons[i]->checkbox); + m_buttons_grid->AddSpacer(5); - m_buttons_box->Add(m_buttons_grid); - m_buttons_box->Add(m_buttons_dpad); + m_buttons_box->Add(m_buttons_grid); + m_buttons_box->Add(m_buttons_dpad); - m_wiimote_szr->Add(m_main_stick_szr, 0, wxALL, 5); - m_wiimote_szr->Add(axisBox, 0, wxTOP | wxRIGHT, 5); - m_wiimote_szr->Add(m_buttons_box, 0, wxTOP | wxRIGHT, 5); - m_main_szr->Add(m_wiimote_szr); - m_main_szr->Add(m_ext_szr); - m_main_szr->Add(m_cc_szr); + m_wiimote_szr->Add(m_main_stick_szr, 0, wxALL, 5); + m_wiimote_szr->Add(axisBox, 0, wxTOP | wxRIGHT, 5); + m_wiimote_szr->Add(m_buttons_box, 0, wxTOP | wxRIGHT, 5); + m_main_szr->Add(m_wiimote_szr); + m_main_szr->Add(m_ext_szr); + m_main_szr->Add(m_cc_szr); - HandleExtensionChange(); - FinishLayout(); + HandleExtensionChange(); + FinishLayout(); } void TASInputDlg::FinishLayout() { - Bind(wxEVT_CLOSE_WINDOW, &TASInputDlg::OnCloseWindow, this); - Bind(INVALIDATE_BUTTON_EVENT, &TASInputDlg::UpdateFromInvalidatedButton, this); - Bind(INVALIDATE_CONTROL_EVENT, &TASInputDlg::UpdateFromInvalidatedControl, this); - Bind(INVALIDATE_EXTENSION_EVENT, &TASInputDlg::UpdateFromInvalidatedExtension, this); - m_has_layout = true; + Bind(wxEVT_CLOSE_WINDOW, &TASInputDlg::OnCloseWindow, this); + Bind(INVALIDATE_BUTTON_EVENT, &TASInputDlg::UpdateFromInvalidatedButton, this); + Bind(INVALIDATE_CONTROL_EVENT, &TASInputDlg::UpdateFromInvalidatedControl, this); + Bind(INVALIDATE_EXTENSION_EVENT, &TASInputDlg::UpdateFromInvalidatedExtension, this); + m_has_layout = true; } wxBoxSizer* TASInputDlg::CreateCCLayout() { - wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL); - for (size_t i = 0; i < ArraySize(m_cc_buttons); ++i) - { - m_cc_buttons[i] = CreateButton(m_cc_button_names[i]); - m_cc_buttons[i].checkbox->SetClientData(&m_cc_buttons[i]); - } + for (size_t i = 0; i < ArraySize(m_cc_buttons); ++i) + { + m_cc_buttons[i] = CreateButton(m_cc_button_names[i]); + m_cc_buttons[i].checkbox->SetClientData(&m_cc_buttons[i]); + } - m_cc_l_stick = CreateStick(ID_CC_L_STICK, 63, 63, WiimoteEmu::Classic::LEFT_STICK_CENTER_X, WiimoteEmu::Classic::LEFT_STICK_CENTER_Y, false, true); - m_cc_r_stick = CreateStick(ID_CC_R_STICK, 31, 31, WiimoteEmu::Classic::RIGHT_STICK_CENTER_X, WiimoteEmu::Classic::RIGHT_STICK_CENTER_Y, false, true); + m_cc_l_stick = CreateStick(ID_CC_L_STICK, 63, 63, WiimoteEmu::Classic::LEFT_STICK_CENTER_X, + WiimoteEmu::Classic::LEFT_STICK_CENTER_Y, false, true); + m_cc_r_stick = CreateStick(ID_CC_R_STICK, 31, 31, WiimoteEmu::Classic::RIGHT_STICK_CENTER_X, + WiimoteEmu::Classic::RIGHT_STICK_CENTER_Y, false, true); - m_cc_controls[CC_L_STICK_X] = &m_cc_l_stick.x_cont; - m_cc_controls[CC_L_STICK_Y] = &m_cc_l_stick.y_cont; - m_cc_controls[CC_R_STICK_X] = &m_cc_r_stick.x_cont; - m_cc_controls[CC_R_STICK_Y] = &m_cc_r_stick.y_cont; - m_cc_controls[CC_L_TRIGGER] = &m_cc_l; - m_cc_controls[CC_R_TRIGGER] = &m_cc_r; + m_cc_controls[CC_L_STICK_X] = &m_cc_l_stick.x_cont; + m_cc_controls[CC_L_STICK_Y] = &m_cc_l_stick.y_cont; + m_cc_controls[CC_R_STICK_X] = &m_cc_r_stick.x_cont; + m_cc_controls[CC_R_STICK_Y] = &m_cc_r_stick.y_cont; + m_cc_controls[CC_L_TRIGGER] = &m_cc_l; + m_cc_controls[CC_R_TRIGGER] = &m_cc_r; - m_cc_l_stick_szr = CreateStickLayout(&m_cc_l_stick, _("Left stick")); - m_cc_r_stick_szr = CreateStickLayout(&m_cc_r_stick, _("Right stick")); + m_cc_l_stick_szr = CreateStickLayout(&m_cc_l_stick, _("Left stick")); + m_cc_r_stick_szr = CreateStickLayout(&m_cc_r_stick, _("Right stick")); - m_cc_l = CreateControl(wxSL_VERTICAL, -1, 100, false, 31, 0);; - m_cc_r = CreateControl(wxSL_VERTICAL, -1, 100, false, 31, 0);; + m_cc_l = CreateControl(wxSL_VERTICAL, -1, 100, false, 31, 0); + ; + m_cc_r = CreateControl(wxSL_VERTICAL, -1, 100, false, 31, 0); + ; - wxStaticBoxSizer* const shoulder_box = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Shoulder Buttons")); - shoulder_box->Add(m_cc_l.slider, 0, wxALIGN_CENTER_VERTICAL); - shoulder_box->Add(m_cc_l.text, 0, wxALIGN_CENTER_VERTICAL); - shoulder_box->Add(m_cc_r.slider, 0, wxALIGN_CENTER_VERTICAL); - shoulder_box->Add(m_cc_r.text, 0, wxALIGN_CENTER_VERTICAL); + wxStaticBoxSizer* const shoulder_box = + new wxStaticBoxSizer(wxHORIZONTAL, this, _("Shoulder Buttons")); + shoulder_box->Add(m_cc_l.slider, 0, wxALIGN_CENTER_VERTICAL); + shoulder_box->Add(m_cc_l.text, 0, wxALIGN_CENTER_VERTICAL); + shoulder_box->Add(m_cc_r.slider, 0, wxALIGN_CENTER_VERTICAL); + shoulder_box->Add(m_cc_r.text, 0, wxALIGN_CENTER_VERTICAL); - wxStaticBoxSizer* const cc_buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons")); - wxGridSizer* const cc_buttons_grid = new wxGridSizer(4); - wxGridSizer* const cc_buttons_dpad = new wxGridSizer(3); + wxStaticBoxSizer* const cc_buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons")); + wxGridSizer* const cc_buttons_grid = new wxGridSizer(4); + wxGridSizer* const cc_buttons_dpad = new wxGridSizer(3); - cc_buttons_dpad->AddSpacer(20); - cc_buttons_dpad->Add(m_cc_buttons[1].checkbox); - cc_buttons_dpad->AddSpacer(20); - cc_buttons_dpad->Add(m_cc_buttons[2].checkbox); - cc_buttons_dpad->AddSpacer(20); - cc_buttons_dpad->Add(m_cc_buttons[3].checkbox); - cc_buttons_dpad->AddSpacer(20); - cc_buttons_dpad->Add(m_cc_buttons[0].checkbox); - cc_buttons_dpad->AddSpacer(20); + cc_buttons_dpad->AddSpacer(20); + cc_buttons_dpad->Add(m_cc_buttons[1].checkbox); + cc_buttons_dpad->AddSpacer(20); + cc_buttons_dpad->Add(m_cc_buttons[2].checkbox); + cc_buttons_dpad->AddSpacer(20); + cc_buttons_dpad->Add(m_cc_buttons[3].checkbox); + cc_buttons_dpad->AddSpacer(20); + cc_buttons_dpad->Add(m_cc_buttons[0].checkbox); + cc_buttons_dpad->AddSpacer(20); + for (auto button : m_cc_buttons) + cc_buttons_grid->Add(button.checkbox); + cc_buttons_grid->AddSpacer(5); - for (auto button : m_cc_buttons) - cc_buttons_grid->Add(button.checkbox); - cc_buttons_grid->AddSpacer(5); + cc_buttons_box->Add(cc_buttons_grid); + cc_buttons_box->Add(cc_buttons_dpad); - cc_buttons_box->Add(cc_buttons_grid); - cc_buttons_box->Add(cc_buttons_dpad); + szr->Add(m_cc_l_stick_szr, 0, wxALL, 5); + szr->Add(m_cc_r_stick_szr, 0, wxALL, 5); + szr->Add(shoulder_box, 0, wxLEFT | wxRIGHT, 5); + szr->Add(cc_buttons_box, 0, wxTOP | wxRIGHT, 5); - szr->Add(m_cc_l_stick_szr, 0, wxALL, 5); - szr->Add(m_cc_r_stick_szr, 0, wxALL, 5); - szr->Add(shoulder_box, 0, wxLEFT | wxRIGHT, 5); - szr->Add(cc_buttons_box, 0, wxTOP | wxRIGHT, 5); - - for (Control* const control : m_cc_controls) - { - if (control != nullptr) - control->slider->Bind(wxEVT_RIGHT_UP, &TASInputDlg::OnRightClickSlider, this); - } - return szr; + for (Control* const control : m_cc_controls) + { + if (control != nullptr) + control->slider->Bind(wxEVT_RIGHT_UP, &TASInputDlg::OnRightClickSlider, this); + } + return szr; } void TASInputDlg::HandleExtensionChange() { - if (m_ext == 1) - { - m_main_szr->Hide(m_cc_szr); - m_main_szr->Show(m_wiimote_szr); - m_main_szr->Show(m_ext_szr); - } - else if (m_ext == 2) - { - m_main_szr->Hide(m_ext_szr); - m_main_szr->Hide(m_wiimote_szr); - m_main_szr->Show(m_cc_szr); - } - else - { - m_main_szr->Hide(m_ext_szr); - m_main_szr->Hide(m_cc_szr); - m_main_szr->Show(m_wiimote_szr); - } - SetSizerAndFit(m_main_szr, true); - ResetValues(); + if (m_ext == 1) + { + m_main_szr->Hide(m_cc_szr); + m_main_szr->Show(m_wiimote_szr); + m_main_szr->Show(m_ext_szr); + } + else if (m_ext == 2) + { + m_main_szr->Hide(m_ext_szr); + m_main_szr->Hide(m_wiimote_szr); + m_main_szr->Show(m_cc_szr); + } + else + { + m_main_szr->Hide(m_ext_szr); + m_main_szr->Hide(m_cc_szr); + m_main_szr->Show(m_wiimote_szr); + } + SetSizerAndFit(m_main_szr, true); + ResetValues(); } void TASInputDlg::CreateGCLayout() { - if (m_has_layout) - return; + if (m_has_layout) + return; - CreateBaseLayout(); + CreateBaseLayout(); - m_buttons[6] = &m_x; - m_buttons[7] = &m_y; - m_buttons[8] = &m_z; - m_buttons[9] = &m_l; - m_buttons[10] = &m_r; - m_buttons[11] = &m_start; + m_buttons[6] = &m_x; + m_buttons[7] = &m_y; + m_buttons[8] = &m_z; + m_buttons[9] = &m_l; + m_buttons[10] = &m_r; + m_buttons[11] = &m_start; - m_controls[2] = &m_c_stick.x_cont; - m_controls[3] = &m_c_stick.y_cont; - m_controls[4] = &m_l_cont; - m_controls[5] = &m_r_cont; + m_controls[2] = &m_c_stick.x_cont; + m_controls[3] = &m_c_stick.y_cont; + m_controls[4] = &m_l_cont; + m_controls[5] = &m_r_cont; - wxBoxSizer* const top_box = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* const bottom_box = new wxBoxSizer(wxHORIZONTAL); - m_main_stick = CreateStick(ID_MAIN_STICK, 255, 255, 128, 128, false, true); - wxStaticBoxSizer* const main_box = CreateStickLayout(&m_main_stick, _("Main Stick")); + wxBoxSizer* const top_box = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* const bottom_box = new wxBoxSizer(wxHORIZONTAL); + m_main_stick = CreateStick(ID_MAIN_STICK, 255, 255, 128, 128, false, true); + wxStaticBoxSizer* const main_box = CreateStickLayout(&m_main_stick, _("Main Stick")); - m_c_stick = CreateStick(ID_C_STICK, 255, 255, 128, 128, false, true); - wxStaticBoxSizer* const c_box = CreateStickLayout(&m_c_stick, _("C Stick")); + m_c_stick = CreateStick(ID_C_STICK, 255, 255, 128, 128, false, true); + wxStaticBoxSizer* const c_box = CreateStickLayout(&m_c_stick, _("C Stick")); - wxStaticBoxSizer* const shoulder_box = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Shoulder Buttons")); - m_l_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 255, 0); - m_r_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 255, 0); - shoulder_box->Add(m_l_cont.slider, 0, wxALIGN_CENTER_VERTICAL); - shoulder_box->Add(m_l_cont.text, 0, wxALIGN_CENTER_VERTICAL); - shoulder_box->Add(m_r_cont.slider, 0, wxALIGN_CENTER_VERTICAL); - shoulder_box->Add(m_r_cont.text, 0, wxALIGN_CENTER_VERTICAL); + wxStaticBoxSizer* const shoulder_box = + new wxStaticBoxSizer(wxHORIZONTAL, this, _("Shoulder Buttons")); + m_l_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 255, 0); + m_r_cont = CreateControl(wxSL_VERTICAL, -1, 100, false, 255, 0); + shoulder_box->Add(m_l_cont.slider, 0, wxALIGN_CENTER_VERTICAL); + shoulder_box->Add(m_l_cont.text, 0, wxALIGN_CENTER_VERTICAL); + shoulder_box->Add(m_r_cont.slider, 0, wxALIGN_CENTER_VERTICAL); + shoulder_box->Add(m_r_cont.text, 0, wxALIGN_CENTER_VERTICAL); - for (Control* const control : m_controls) - { - if (control != nullptr) - control->slider->Bind(wxEVT_RIGHT_UP, &TASInputDlg::OnRightClickSlider, this); - } + for (Control* const control : m_controls) + { + if (control != nullptr) + control->slider->Bind(wxEVT_RIGHT_UP, &TASInputDlg::OnRightClickSlider, this); + } - wxStaticBoxSizer* const m_buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons")); - wxGridSizer* const m_buttons_grid = new wxGridSizer(4); + wxStaticBoxSizer* const m_buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons")); + wxGridSizer* const m_buttons_grid = new wxGridSizer(4); - m_x = CreateButton("X"); - m_x.checkbox->SetClientData(&m_x); - m_y = CreateButton("Y"); - m_y.checkbox->SetClientData(&m_y); - m_l = CreateButton("L"); - m_l.checkbox->SetClientData(&m_l); - m_r = CreateButton("R"); - m_r.checkbox->SetClientData(&m_r); - m_z = CreateButton("Z"); - m_z.checkbox->SetClientData(&m_z); - m_start = CreateButton("Start"); - m_start.checkbox->SetClientData(&m_start); + m_x = CreateButton("X"); + m_x.checkbox->SetClientData(&m_x); + m_y = CreateButton("Y"); + m_y.checkbox->SetClientData(&m_y); + m_l = CreateButton("L"); + m_l.checkbox->SetClientData(&m_l); + m_r = CreateButton("R"); + m_r.checkbox->SetClientData(&m_r); + m_z = CreateButton("Z"); + m_z.checkbox->SetClientData(&m_z); + m_start = CreateButton("Start"); + m_start.checkbox->SetClientData(&m_start); - for (unsigned int i = 4; i < ArraySize(m_buttons); ++i) - if (m_buttons[i] != nullptr) - m_buttons_grid->Add(m_buttons[i]->checkbox, false); - m_buttons_grid->AddSpacer(5); + for (unsigned int i = 4; i < ArraySize(m_buttons); ++i) + if (m_buttons[i] != nullptr) + m_buttons_grid->Add(m_buttons[i]->checkbox, false); + m_buttons_grid->AddSpacer(5); - m_buttons_box->Add(m_buttons_grid); - m_buttons_box->Add(m_buttons_dpad); + m_buttons_box->Add(m_buttons_grid); + m_buttons_box->Add(m_buttons_dpad); - wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); - top_box->Add(main_box, 0, wxALL, 5); - top_box->Add(c_box, 0, wxTOP | wxRIGHT, 5); - bottom_box->Add(shoulder_box, 0, wxLEFT | wxRIGHT, 5); - bottom_box->Add(m_buttons_box, 0, wxBOTTOM, 5); - main_szr->Add(top_box); - main_szr->Add(bottom_box); - SetSizerAndFit(main_szr); + top_box->Add(main_box, 0, wxALL, 5); + top_box->Add(c_box, 0, wxTOP | wxRIGHT, 5); + bottom_box->Add(shoulder_box, 0, wxLEFT | wxRIGHT, 5); + bottom_box->Add(m_buttons_box, 0, wxBOTTOM, 5); + main_szr->Add(top_box); + main_szr->Add(bottom_box); + SetSizerAndFit(main_szr); - ResetValues(); - FinishLayout(); + ResetValues(); + FinishLayout(); } - -TASInputDlg::Control TASInputDlg::CreateControl(long style, int width, int height, bool reverse, u32 range, u32 default_value) +TASInputDlg::Control TASInputDlg::CreateControl(long style, int width, int height, bool reverse, + u32 range, u32 default_value) { - Control tempCont; - tempCont.range = range; - tempCont.default_value = default_value; - tempCont.slider = new wxSlider(this, m_eleID++, default_value, 0, range, wxDefaultPosition, wxDefaultSize, style); - tempCont.slider->SetMinSize(wxSize(width, height)); - tempCont.slider->Bind(wxEVT_SLIDER, &TASInputDlg::UpdateFromSliders, this); - tempCont.text = new wxTextCtrl(this, m_eleID++, std::to_string(default_value), wxDefaultPosition, wxSize(40, 20)); - tempCont.text->SetMaxLength(range > 999 ? 4 : 3); - tempCont.text_id = m_eleID - 1; - tempCont.text->Bind(wxEVT_TEXT, &TASInputDlg::UpdateFromText, this); - tempCont.slider_id = m_eleID - 2; - tempCont.reverse = reverse; - return tempCont; + Control tempCont; + tempCont.range = range; + tempCont.default_value = default_value; + tempCont.slider = new wxSlider(this, m_eleID++, default_value, 0, range, wxDefaultPosition, + wxDefaultSize, style); + tempCont.slider->SetMinSize(wxSize(width, height)); + tempCont.slider->Bind(wxEVT_SLIDER, &TASInputDlg::UpdateFromSliders, this); + tempCont.text = new wxTextCtrl(this, m_eleID++, std::to_string(default_value), wxDefaultPosition, + wxSize(40, 20)); + tempCont.text->SetMaxLength(range > 999 ? 4 : 3); + tempCont.text_id = m_eleID - 1; + tempCont.text->Bind(wxEVT_TEXT, &TASInputDlg::UpdateFromText, this); + tempCont.slider_id = m_eleID - 2; + tempCont.reverse = reverse; + return tempCont; } -TASInputDlg::Stick TASInputDlg::CreateStick(int id_stick, int xRange, int yRange, u32 defaultX, u32 defaultY, bool reverseX, bool reverseY) +TASInputDlg::Stick TASInputDlg::CreateStick(int id_stick, int xRange, int yRange, u32 defaultX, + u32 defaultY, bool reverseX, bool reverseY) { - Stick tempStick; - tempStick.bitmap = new wxStaticBitmap(this, id_stick, CreateStickBitmap(128, 128)); - tempStick.bitmap->Bind(wxEVT_MOTION, &TASInputDlg::OnMouseDownL, this); - tempStick.bitmap->Bind(wxEVT_LEFT_DOWN, &TASInputDlg::OnMouseDownL, this); - tempStick.bitmap->Bind(wxEVT_RIGHT_UP, &TASInputDlg::OnMouseUpR, this); - tempStick.x_cont = CreateControl(wxSL_HORIZONTAL | (reverseX ? wxSL_INVERSE : 0), 120, -1, reverseX, xRange, defaultX); - tempStick.y_cont = CreateControl(wxSL_VERTICAL | (reverseY ? wxSL_INVERSE : 0), -1, 120, reverseY, yRange, defaultY); - return tempStick; + Stick tempStick; + tempStick.bitmap = new wxStaticBitmap(this, id_stick, CreateStickBitmap(128, 128)); + tempStick.bitmap->Bind(wxEVT_MOTION, &TASInputDlg::OnMouseDownL, this); + tempStick.bitmap->Bind(wxEVT_LEFT_DOWN, &TASInputDlg::OnMouseDownL, this); + tempStick.bitmap->Bind(wxEVT_RIGHT_UP, &TASInputDlg::OnMouseUpR, this); + tempStick.x_cont = CreateControl(wxSL_HORIZONTAL | (reverseX ? wxSL_INVERSE : 0), 120, -1, + reverseX, xRange, defaultX); + tempStick.y_cont = CreateControl(wxSL_VERTICAL | (reverseY ? wxSL_INVERSE : 0), -1, 120, reverseY, + yRange, defaultY); + return tempStick; } wxStaticBoxSizer* TASInputDlg::CreateStickLayout(Stick* tempStick, const wxString& title) { - wxStaticBoxSizer* const temp_box = new wxStaticBoxSizer(wxHORIZONTAL, this, title); - wxBoxSizer* const temp_xslider_box = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* const temp_yslider_box = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* const temp_stick_box = new wxBoxSizer(wxVERTICAL); + wxStaticBoxSizer* const temp_box = new wxStaticBoxSizer(wxHORIZONTAL, this, title); + wxBoxSizer* const temp_xslider_box = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* const temp_yslider_box = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* const temp_stick_box = new wxBoxSizer(wxVERTICAL); - temp_xslider_box->Add(tempStick->x_cont.slider, 0, wxALIGN_TOP); - temp_xslider_box->Add(tempStick->x_cont.text, 0, wxALIGN_TOP); - temp_stick_box->Add(temp_xslider_box); - temp_stick_box->Add(tempStick->bitmap, 0, wxALL | wxALIGN_CENTER, 3); - temp_box->Add(temp_stick_box); - temp_yslider_box->Add(tempStick->y_cont.slider, 0, wxALIGN_CENTER_VERTICAL); - temp_yslider_box->Add(tempStick->y_cont.text, 0, wxALIGN_CENTER_VERTICAL); - temp_box->Add(temp_yslider_box); - return temp_box; + temp_xslider_box->Add(tempStick->x_cont.slider, 0, wxALIGN_TOP); + temp_xslider_box->Add(tempStick->x_cont.text, 0, wxALIGN_TOP); + temp_stick_box->Add(temp_xslider_box); + temp_stick_box->Add(tempStick->bitmap, 0, wxALL | wxALIGN_CENTER, 3); + temp_box->Add(temp_stick_box); + temp_yslider_box->Add(tempStick->y_cont.slider, 0, wxALIGN_CENTER_VERTICAL); + temp_yslider_box->Add(tempStick->y_cont.text, 0, wxALIGN_CENTER_VERTICAL); + temp_box->Add(temp_yslider_box); + return temp_box; } -wxStaticBoxSizer* TASInputDlg::CreateAccelLayout(Control* x, Control* y, Control* z, const wxString& title) +wxStaticBoxSizer* TASInputDlg::CreateAccelLayout(Control* x, Control* y, Control* z, + const wxString& title) { - wxStaticBoxSizer* const temp_box = new wxStaticBoxSizer(wxHORIZONTAL, this, title); - wxStaticBoxSizer* const xBox = new wxStaticBoxSizer(wxVERTICAL, this, _("X")); - wxStaticBoxSizer* const yBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Y")); - wxStaticBoxSizer* const zBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Z")); + wxStaticBoxSizer* const temp_box = new wxStaticBoxSizer(wxHORIZONTAL, this, title); + wxStaticBoxSizer* const xBox = new wxStaticBoxSizer(wxVERTICAL, this, _("X")); + wxStaticBoxSizer* const yBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Y")); + wxStaticBoxSizer* const zBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Z")); - xBox->Add(x->slider, 0, wxALIGN_CENTER_VERTICAL); - xBox->Add(x->text, 0, wxALIGN_CENTER_VERTICAL); - yBox->Add(y->slider, 0, wxALIGN_CENTER_VERTICAL); - yBox->Add(y->text, 0, wxALIGN_CENTER_VERTICAL); - zBox->Add(z->slider, 0, wxALIGN_CENTER_VERTICAL); - zBox->Add(z->text, 0, wxALIGN_CENTER_VERTICAL); - temp_box->Add(xBox, 0, wxLEFT | wxBOTTOM | wxRIGHT, 5); - temp_box->Add(yBox, 0, wxRIGHT, 5); - temp_box->Add(zBox, 0, wxRIGHT, 5); - return temp_box; + xBox->Add(x->slider, 0, wxALIGN_CENTER_VERTICAL); + xBox->Add(x->text, 0, wxALIGN_CENTER_VERTICAL); + yBox->Add(y->slider, 0, wxALIGN_CENTER_VERTICAL); + yBox->Add(y->text, 0, wxALIGN_CENTER_VERTICAL); + zBox->Add(z->slider, 0, wxALIGN_CENTER_VERTICAL); + zBox->Add(z->text, 0, wxALIGN_CENTER_VERTICAL); + temp_box->Add(xBox, 0, wxLEFT | wxBOTTOM | wxRIGHT, 5); + temp_box->Add(yBox, 0, wxRIGHT, 5); + temp_box->Add(zBox, 0, wxRIGHT, 5); + return temp_box; } TASInputDlg::Button TASInputDlg::CreateButton(const std::string& name) { - Button temp; - wxCheckBox* checkbox = new wxCheckBox(this, m_eleID++, name); - checkbox->Bind(wxEVT_RIGHT_DOWN, &TASInputDlg::SetTurbo, this); - checkbox->Bind(wxEVT_LEFT_DOWN, &TASInputDlg::SetTurbo, this); - checkbox->Bind(wxEVT_CHECKBOX, &TASInputDlg::OnCheckboxToggle, this); - temp.checkbox = checkbox; - temp.id = m_eleID - 1; - return temp; + Button temp; + wxCheckBox* checkbox = new wxCheckBox(this, m_eleID++, name); + checkbox->Bind(wxEVT_RIGHT_DOWN, &TASInputDlg::SetTurbo, this); + checkbox->Bind(wxEVT_LEFT_DOWN, &TASInputDlg::SetTurbo, this); + checkbox->Bind(wxEVT_CHECKBOX, &TASInputDlg::OnCheckboxToggle, this); + temp.checkbox = checkbox; + temp.id = m_eleID - 1; + return temp; } void TASInputDlg::OnCheckboxToggle(wxCommandEvent& event) { - auto cbox = static_cast(event.GetEventObject()); - static_cast(cbox->GetClientData())->is_checked = event.IsChecked(); + auto cbox = static_cast(event.GetEventObject()); + static_cast(cbox->GetClientData())->is_checked = event.IsChecked(); } void TASInputDlg::ResetValues() { - for (Button* const button : m_buttons) - { - if (button != nullptr) - { - button->value = false; - button->checkbox->SetValue(false); - } - } + for (Button* const button : m_buttons) + { + if (button != nullptr) + { + button->value = false; + button->checkbox->SetValue(false); + } + } - for (Control* const control : m_controls) - { - if (control != nullptr) - { - control->value = control->default_value; - control->slider->SetValue(control->default_value); - control->text->SetValue(std::to_string(control->default_value)); - } - } - if (m_ext == 2) - { - for (Button& button : m_cc_buttons) - { - button.value = false; - button.checkbox->SetValue(false); - } + for (Control* const control : m_controls) + { + if (control != nullptr) + { + control->value = control->default_value; + control->slider->SetValue(control->default_value); + control->text->SetValue(std::to_string(control->default_value)); + } + } + if (m_ext == 2) + { + for (Button& button : m_cc_buttons) + { + button.value = false; + button.checkbox->SetValue(false); + } - for (Control* control : m_cc_controls) - { - control->value = control->default_value; - control->slider->SetValue(control->default_value); - control->text->SetValue(std::to_string(control->default_value)); - } - } + for (Control* control : m_cc_controls) + { + control->value = control->default_value; + control->slider->SetValue(control->default_value); + control->text->SetValue(std::to_string(control->default_value)); + } + } } // NOTE: Host / CPU Thread void TASInputDlg::SetStickValue(Control* control, int CurrentValue, int center) { - if (CurrentValue != center) - { - control->value = CurrentValue; - control->set_by_keyboard = true; - } - else if (control->set_by_keyboard) - { - control->value = center; - control->set_by_keyboard = false; - } - else - { - return; - } + if (CurrentValue != center) + { + control->value = CurrentValue; + control->set_by_keyboard = true; + } + else if (control->set_by_keyboard) + { + control->value = center; + control->set_by_keyboard = false; + } + else + { + return; + } - InvalidateControl(control); + InvalidateControl(control); } // NOTE: Host / CPU Thread void TASInputDlg::SetSliderValue(Control* control, int CurrentValue) { - if (CurrentValue != (int)control->default_value) - { - control->value = CurrentValue; - control->set_by_keyboard = true; - } - else if (control->set_by_keyboard) - { - control->value = control->default_value; - control->set_by_keyboard = false; - } - else - { - return; - } + if (CurrentValue != (int)control->default_value) + { + control->value = CurrentValue; + control->set_by_keyboard = true; + } + else if (control->set_by_keyboard) + { + control->value = control->default_value; + control->set_by_keyboard = false; + } + else + { + return; + } - InvalidateControl(control); + InvalidateControl(control); } // NOTE: Host / CPU Thread void TASInputDlg::SetButtonValue(Button* button, bool CurrentState) { - if (CurrentState) - { - button->set_by_keyboard = true; - } - else if (button->set_by_keyboard) - { - button->set_by_keyboard = false; - } - else - { - return; - } + if (CurrentState) + { + button->set_by_keyboard = true; + } + else if (button->set_by_keyboard) + { + button->set_by_keyboard = false; + } + else + { + return; + } - button->value = CurrentState; - InvalidateButton(button); + button->value = CurrentState; + InvalidateButton(button); } // NOTE: Host / CPU Thread void TASInputDlg::SetWiiButtons(u16* butt) { - for (unsigned int i = 0; i < 11; ++i) - { - if (m_buttons[i] != nullptr) - *butt |= (m_buttons[i]->is_checked) ? m_wii_buttons_bitmask[i] : 0; - } - ButtonTurbo(); + for (unsigned int i = 0; i < 11; ++i) + { + if (m_buttons[i] != nullptr) + *butt |= (m_buttons[i]->is_checked) ? m_wii_buttons_bitmask[i] : 0; + } + ButtonTurbo(); } // NOTE: Host / CPU Thread void TASInputDlg::GetKeyBoardInput(GCPadStatus* PadStatus) { - SetStickValue(&m_main_stick.x_cont, PadStatus->stickX); - SetStickValue(&m_main_stick.y_cont, PadStatus->stickY); + SetStickValue(&m_main_stick.x_cont, PadStatus->stickX); + SetStickValue(&m_main_stick.y_cont, PadStatus->stickY); - SetStickValue(&m_c_stick.x_cont, PadStatus->substickX); - SetStickValue(&m_c_stick.y_cont, PadStatus->substickY); - SetSliderValue(&m_l_cont, PadStatus->triggerLeft); - SetSliderValue(&m_r_cont, PadStatus->triggerRight); + SetStickValue(&m_c_stick.x_cont, PadStatus->substickX); + SetStickValue(&m_c_stick.y_cont, PadStatus->substickY); + SetSliderValue(&m_l_cont, PadStatus->triggerLeft); + SetSliderValue(&m_r_cont, PadStatus->triggerRight); - for (unsigned int i = 0; i < ArraySize(m_buttons); ++i) - { - if (m_buttons[i] != nullptr) - SetButtonValue(m_buttons[i], ((PadStatus->button & m_gc_pad_buttons_bitmask[i]) != 0)); - } - SetButtonValue(&m_l, ((PadStatus->triggerLeft) == 255) || ((PadStatus->button & PAD_TRIGGER_L) != 0)); - SetButtonValue(&m_r, ((PadStatus->triggerRight) == 255) || ((PadStatus->button & PAD_TRIGGER_R) != 0)); + for (unsigned int i = 0; i < ArraySize(m_buttons); ++i) + { + if (m_buttons[i] != nullptr) + SetButtonValue(m_buttons[i], ((PadStatus->button & m_gc_pad_buttons_bitmask[i]) != 0)); + } + SetButtonValue(&m_l, + ((PadStatus->triggerLeft) == 255) || ((PadStatus->button & PAD_TRIGGER_L) != 0)); + SetButtonValue(&m_r, + ((PadStatus->triggerRight) == 255) || ((PadStatus->button & PAD_TRIGGER_R) != 0)); } // NOTE: Host / CPU Thread -void TASInputDlg::GetKeyBoardInput(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, const wiimote_key key) +void TASInputDlg::GetKeyBoardInput(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, + const wiimote_key key) { - u8* const coreData = rptf.core ? (data + rptf.core) : nullptr; - u8* const accelData = rptf.accel ? (data + rptf.accel) : nullptr; - //u8* const irData = rptf.ir ? (data + rptf.ir) : nullptr; - u8* const extData = rptf.ext ? (data + rptf.ext) : nullptr; + u8* const coreData = rptf.core ? (data + rptf.core) : nullptr; + u8* const accelData = rptf.accel ? (data + rptf.accel) : nullptr; + // u8* const irData = rptf.ir ? (data + rptf.ir) : nullptr; + u8* const extData = rptf.ext ? (data + rptf.ext) : nullptr; - if (coreData) - { - for (unsigned int i = 0; i < 11; ++i) - { - if (m_buttons[i] != nullptr) - SetButtonValue(m_buttons[i], (((wm_buttons*)coreData)->hex & m_wii_buttons_bitmask[i]) != 0); - } - } - if (accelData) - { - wm_accel* dt = (wm_accel*)accelData; + if (coreData) + { + for (unsigned int i = 0; i < 11; ++i) + { + if (m_buttons[i] != nullptr) + SetButtonValue(m_buttons[i], + (((wm_buttons*)coreData)->hex & m_wii_buttons_bitmask[i]) != 0); + } + } + if (accelData) + { + wm_accel* dt = (wm_accel*)accelData; - SetSliderValue(&m_x_cont, dt->x << 2 | ((wm_buttons*)coreData)->acc_x_lsb); - SetSliderValue(&m_y_cont, dt->y << 2 | ((wm_buttons*)coreData)->acc_y_lsb << 1); - SetSliderValue(&m_z_cont, dt->z << 2 | ((wm_buttons*)coreData)->acc_z_lsb << 1); - } + SetSliderValue(&m_x_cont, dt->x << 2 | ((wm_buttons*)coreData)->acc_x_lsb); + SetSliderValue(&m_y_cont, dt->y << 2 | ((wm_buttons*)coreData)->acc_y_lsb << 1); + SetSliderValue(&m_z_cont, dt->z << 2 | ((wm_buttons*)coreData)->acc_z_lsb << 1); + } - // I don't think this can be made to work in a sane manner. - //if (irData) - //{ - // u16 x = 1023 - (irData[0] | ((irData[2] >> 4 & 0x3) << 8)); - // u16 y = irData[1] | ((irData[2] >> 6 & 0x3) << 8); + // I don't think this can be made to work in a sane manner. + // if (irData) + //{ + // u16 x = 1023 - (irData[0] | ((irData[2] >> 4 & 0x3) << 8)); + // u16 y = irData[1] | ((irData[2] >> 6 & 0x3) << 8); - // SetStickValue(&m_main_stick.x_cont.set_by_keyboard, &m_main_stick.x_cont.value, m_main_stick.x_cont.text, x, 561); - // SetStickValue(&m_main_stick.y_cont.set_by_keyboard, &m_main_stick.y_cont.value, m_main_stick.y_cont.text, y, 486); - //} + // SetStickValue(&m_main_stick.x_cont.set_by_keyboard, &m_main_stick.x_cont.value, + //m_main_stick.x_cont.text, x, 561); + // SetStickValue(&m_main_stick.y_cont.set_by_keyboard, &m_main_stick.y_cont.value, + //m_main_stick.y_cont.text, y, 486); + //} - if (extData && ext == 1) - { - wm_nc& nunchuk = *(wm_nc*)extData; - WiimoteDecrypt(&key, (u8*)&nunchuk, 0, sizeof(wm_nc)); - nunchuk.bt.hex = nunchuk.bt.hex ^ 0x3; - SetButtonValue(m_buttons[11], nunchuk.bt.c != 0); - SetButtonValue(m_buttons[12], nunchuk.bt.z != 0); - } + if (extData && ext == 1) + { + wm_nc& nunchuk = *(wm_nc*)extData; + WiimoteDecrypt(&key, (u8*)&nunchuk, 0, sizeof(wm_nc)); + nunchuk.bt.hex = nunchuk.bt.hex ^ 0x3; + SetButtonValue(m_buttons[11], nunchuk.bt.c != 0); + SetButtonValue(m_buttons[12], nunchuk.bt.z != 0); + } - if (extData && ext == 2) - { - wm_classic_extension& cc = *(wm_classic_extension*)extData; - WiimoteDecrypt(&key, (u8*)&cc, 0, sizeof(wm_classic_extension)); - cc.bt.hex = cc.bt.hex ^ 0xFFFF; - for (unsigned int i = 0; i < 15; ++i) - { - SetButtonValue(&m_cc_buttons[i], ((cc.bt.hex & m_cc_buttons_bitmask[i]) != 0)); - } + if (extData && ext == 2) + { + wm_classic_extension& cc = *(wm_classic_extension*)extData; + WiimoteDecrypt(&key, (u8*)&cc, 0, sizeof(wm_classic_extension)); + cc.bt.hex = cc.bt.hex ^ 0xFFFF; + for (unsigned int i = 0; i < 15; ++i) + { + SetButtonValue(&m_cc_buttons[i], ((cc.bt.hex & m_cc_buttons_bitmask[i]) != 0)); + } - if (m_cc_l.value == 31) - { - m_cc_buttons[10].value = true; - InvalidateButton(&m_cc_buttons[10]); - } - if (m_cc_r.value == 31) - { - m_cc_buttons[11].value = true; - InvalidateButton(&m_cc_buttons[11]); - } + if (m_cc_l.value == 31) + { + m_cc_buttons[10].value = true; + InvalidateButton(&m_cc_buttons[10]); + } + if (m_cc_r.value == 31) + { + m_cc_buttons[11].value = true; + InvalidateButton(&m_cc_buttons[11]); + } - SetSliderValue(&m_cc_l_stick.x_cont, cc.regular_data.lx); - SetSliderValue(&m_cc_l_stick.y_cont, cc.regular_data.ly); + SetSliderValue(&m_cc_l_stick.x_cont, cc.regular_data.lx); + SetSliderValue(&m_cc_l_stick.y_cont, cc.regular_data.ly); - SetSliderValue(&m_cc_r_stick.x_cont, cc.rx1 | (cc.rx2 << 1) | (cc.rx3 << 3)); - SetSliderValue(&m_cc_r_stick.y_cont, cc.ry); - } + SetSliderValue(&m_cc_r_stick.x_cont, cc.rx1 | (cc.rx2 << 1) | (cc.rx3 << 3)); + SetSliderValue(&m_cc_r_stick.y_cont, cc.ry); + } } // NOTE: Host / CPU Thread // Do not touch the GUI. Requires wxMutexGuiEnter which will deadlock against // the GUI when pausing/stopping. -void TASInputDlg::GetValues(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, const wiimote_key key) +void TASInputDlg::GetValues(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, + const wiimote_key key) { - if (!IsShown() || !m_has_layout) - return; + if (!IsShown() || !m_has_layout) + return; - GetKeyBoardInput(data, rptf, ext, key); + GetKeyBoardInput(data, rptf, ext, key); - u8* const coreData = rptf.core ? (data + rptf.core) : nullptr; - u8* const accelData = rptf.accel ? (data + rptf.accel) : nullptr; - u8* const irData = rptf.ir ? (data + rptf.ir) : nullptr; - u8* const extData = rptf.ext ? (data + rptf.ext) : nullptr; - if (ext != 2) - { - if (coreData) - SetWiiButtons(&((wm_buttons*)coreData)->hex); + u8* const coreData = rptf.core ? (data + rptf.core) : nullptr; + u8* const accelData = rptf.accel ? (data + rptf.accel) : nullptr; + u8* const irData = rptf.ir ? (data + rptf.ir) : nullptr; + u8* const extData = rptf.ext ? (data + rptf.ext) : nullptr; + if (ext != 2) + { + if (coreData) + SetWiiButtons(&((wm_buttons*)coreData)->hex); - if (accelData) - { - wm_accel& dt = *(wm_accel*)accelData; - wm_buttons& but = *(wm_buttons*)coreData; - dt.x = m_x_cont.value >> 2; - dt.y = m_y_cont.value >> 2; - dt.z = m_z_cont.value >> 2; - but.acc_x_lsb = m_x_cont.value & 0x3; - but.acc_y_lsb = m_y_cont.value >> 1 & 0x1; - but.acc_z_lsb = m_z_cont.value >> 1 & 0x1; - } - if (irData) - { - u16 x[4]; - u16 y; + if (accelData) + { + wm_accel& dt = *(wm_accel*)accelData; + wm_buttons& but = *(wm_buttons*)coreData; + dt.x = m_x_cont.value >> 2; + dt.y = m_y_cont.value >> 2; + dt.z = m_z_cont.value >> 2; + but.acc_x_lsb = m_x_cont.value & 0x3; + but.acc_y_lsb = m_y_cont.value >> 1 & 0x1; + but.acc_z_lsb = m_z_cont.value >> 1 & 0x1; + } + if (irData) + { + u16 x[4]; + u16 y; - x[0] = m_main_stick.x_cont.value; - y = m_main_stick.y_cont.value; - x[1] = x[0] + 100; - x[2] = x[0] - 10; - x[3] = x[1] + 10; + x[0] = m_main_stick.x_cont.value; + y = m_main_stick.y_cont.value; + x[1] = x[0] + 100; + x[2] = x[0] - 10; + x[3] = x[1] + 10; - u8 mode; - // Mode 5 not supported in core anyway. - if (rptf.ext) - mode = (rptf.ext - rptf.ir) == 10 ? 1 : 3; - else - mode = (rptf.size - rptf.ir) == 10 ? 1 : 3; + u8 mode; + // Mode 5 not supported in core anyway. + if (rptf.ext) + mode = (rptf.ext - rptf.ir) == 10 ? 1 : 3; + else + mode = (rptf.size - rptf.ir) == 10 ? 1 : 3; - if (mode == 1) - { - memset(irData, 0xFF, sizeof(wm_ir_basic) * 2); - wm_ir_basic* ir_data = (wm_ir_basic*)irData; - for (unsigned int i = 0; i < 2; ++i) - { - if (x[i * 2] < 1024 && y < 768) - { - ir_data[i].x1 = static_cast(x[i*2]); - ir_data[i].x1hi = x[i*2] >> 8; + if (mode == 1) + { + memset(irData, 0xFF, sizeof(wm_ir_basic) * 2); + wm_ir_basic* ir_data = (wm_ir_basic*)irData; + for (unsigned int i = 0; i < 2; ++i) + { + if (x[i * 2] < 1024 && y < 768) + { + ir_data[i].x1 = static_cast(x[i * 2]); + ir_data[i].x1hi = x[i * 2] >> 8; - ir_data[i].y1 = static_cast(y); - ir_data[i].y1hi = y >> 8; - } - if (x[i*2 + 1] < 1024 && y < 768) - { - ir_data[i].x2 = static_cast(x[i*2 + 1]); - ir_data[i].x2hi = x[i*2 + 1] >> 8; + ir_data[i].y1 = static_cast(y); + ir_data[i].y1hi = y >> 8; + } + if (x[i * 2 + 1] < 1024 && y < 768) + { + ir_data[i].x2 = static_cast(x[i * 2 + 1]); + ir_data[i].x2hi = x[i * 2 + 1] >> 8; - ir_data[i].y2 = static_cast(y); - ir_data[i].y2hi = y >> 8; - } - } - } - else - { - memset(data, 0xFF, sizeof(wm_ir_extended) * 4); - wm_ir_extended* const ir_data = (wm_ir_extended*)irData; - for (unsigned int i = 0; i < 4; ++i) - { - if (x[i] < 1024 && y < 768) - { - ir_data[i].x = static_cast(x[i]); - ir_data[i].xhi = x[i] >> 8; + ir_data[i].y2 = static_cast(y); + ir_data[i].y2hi = y >> 8; + } + } + } + else + { + memset(data, 0xFF, sizeof(wm_ir_extended) * 4); + wm_ir_extended* const ir_data = (wm_ir_extended*)irData; + for (unsigned int i = 0; i < 4; ++i) + { + if (x[i] < 1024 && y < 768) + { + ir_data[i].x = static_cast(x[i]); + ir_data[i].xhi = x[i] >> 8; - ir_data[i].y = static_cast(y); - ir_data[i].yhi = y >> 8; + ir_data[i].y = static_cast(y); + ir_data[i].yhi = y >> 8; - ir_data[i].size = 10; - } - } - } - } - } - if (ext != m_ext) - { - m_ext = ext; - InvalidateExtension(); - } - else if (extData && ext == 1) - { - wm_nc& nunchuk = *(wm_nc*)extData; + ir_data[i].size = 10; + } + } + } + } + } + if (ext != m_ext) + { + m_ext = ext; + InvalidateExtension(); + } + else if (extData && ext == 1) + { + wm_nc& nunchuk = *(wm_nc*)extData; - nunchuk.jx = m_c_stick.x_cont.value; - nunchuk.jy = m_c_stick.y_cont.value; + nunchuk.jx = m_c_stick.x_cont.value; + nunchuk.jy = m_c_stick.y_cont.value; - nunchuk.ax = m_nx_cont.value >> 2; - nunchuk.bt.acc_x_lsb = m_nx_cont.value & 0x3; - nunchuk.ay = m_ny_cont.value >> 2; - nunchuk.bt.acc_y_lsb = m_ny_cont.value & 0x3; - nunchuk.az = m_nz_cont.value >> 2; - nunchuk.bt.acc_z_lsb = m_nz_cont.value & 0x3; + nunchuk.ax = m_nx_cont.value >> 2; + nunchuk.bt.acc_x_lsb = m_nx_cont.value & 0x3; + nunchuk.ay = m_ny_cont.value >> 2; + nunchuk.bt.acc_y_lsb = m_ny_cont.value & 0x3; + nunchuk.az = m_nz_cont.value >> 2; + nunchuk.bt.acc_z_lsb = m_nz_cont.value & 0x3; - nunchuk.bt.hex |= (m_buttons[11]->is_checked) ? WiimoteEmu::Nunchuk::BUTTON_C : 0; - nunchuk.bt.hex |= (m_buttons[12]->is_checked) ? WiimoteEmu::Nunchuk::BUTTON_Z : 0; - nunchuk.bt.hex = nunchuk.bt.hex ^ 0x3; - WiimoteEncrypt(&key, (u8*)&nunchuk, 0, sizeof(wm_nc)); - } - else if (extData && ext == 2) - { - wm_classic_extension& cc = *(wm_classic_extension*)extData; - WiimoteDecrypt(&key, (u8*)&cc, 0, sizeof(wm_classic_extension)); - cc.bt.hex = 0; + nunchuk.bt.hex |= (m_buttons[11]->is_checked) ? WiimoteEmu::Nunchuk::BUTTON_C : 0; + nunchuk.bt.hex |= (m_buttons[12]->is_checked) ? WiimoteEmu::Nunchuk::BUTTON_Z : 0; + nunchuk.bt.hex = nunchuk.bt.hex ^ 0x3; + WiimoteEncrypt(&key, (u8*)&nunchuk, 0, sizeof(wm_nc)); + } + else if (extData && ext == 2) + { + wm_classic_extension& cc = *(wm_classic_extension*)extData; + WiimoteDecrypt(&key, (u8*)&cc, 0, sizeof(wm_classic_extension)); + cc.bt.hex = 0; - for (unsigned int i = 0; i < ArraySize(m_cc_buttons); ++i) - { - cc.bt.hex |= (m_cc_buttons[i].is_checked) ? m_cc_buttons_bitmask[i] : 0; - } - cc.bt.hex ^= 0xFFFF; + for (unsigned int i = 0; i < ArraySize(m_cc_buttons); ++i) + { + cc.bt.hex |= (m_cc_buttons[i].is_checked) ? m_cc_buttons_bitmask[i] : 0; + } + cc.bt.hex ^= 0xFFFF; - u16 rx = m_cc_r_stick.x_cont.value; - cc.rx1 = rx & 0x1; - cc.rx2 = (rx >> 1) & 0x3; - cc.rx3 = (rx >> 3) & 0x3; - cc.ry = m_cc_r_stick.y_cont.value; + u16 rx = m_cc_r_stick.x_cont.value; + cc.rx1 = rx & 0x1; + cc.rx2 = (rx >> 1) & 0x3; + cc.rx3 = (rx >> 3) & 0x3; + cc.ry = m_cc_r_stick.y_cont.value; - cc.regular_data.lx = m_cc_l_stick.x_cont.value; - cc.regular_data.ly = m_cc_l_stick.y_cont.value; + cc.regular_data.lx = m_cc_l_stick.x_cont.value; + cc.regular_data.ly = m_cc_l_stick.y_cont.value; - cc.rt = m_cc_r.value; - cc.lt1 = m_cc_l.value & 0x7; - cc.lt2 = (m_cc_l.value >> 3) & 0x3; + cc.rt = m_cc_r.value; + cc.lt1 = m_cc_l.value & 0x7; + cc.lt2 = (m_cc_l.value >> 3) & 0x3; - WiimoteEncrypt(&key, (u8*)&cc, 0, sizeof(wm_classic_extension)); - } + WiimoteEncrypt(&key, (u8*)&cc, 0, sizeof(wm_classic_extension)); + } } // NOTE: Host / CPU Thread void TASInputDlg::GetValues(GCPadStatus* PadStatus) { - if (!IsShown() || !m_has_layout) - return; + if (!IsShown() || !m_has_layout) + return; - //TODO:: Make this instant not when polled. - GetKeyBoardInput(PadStatus); + // TODO:: Make this instant not when polled. + GetKeyBoardInput(PadStatus); - PadStatus->stickX = m_main_stick.x_cont.value; - PadStatus->stickY = m_main_stick.y_cont.value; - PadStatus->substickX = m_c_stick.x_cont.value; - PadStatus->substickY = m_c_stick.y_cont.value; - PadStatus->triggerLeft = m_l.is_checked ? 255 : m_l_cont.value; - PadStatus->triggerRight = m_r.is_checked ? 255 : m_r_cont.value; + PadStatus->stickX = m_main_stick.x_cont.value; + PadStatus->stickY = m_main_stick.y_cont.value; + PadStatus->substickX = m_c_stick.x_cont.value; + PadStatus->substickY = m_c_stick.y_cont.value; + PadStatus->triggerLeft = m_l.is_checked ? 255 : m_l_cont.value; + PadStatus->triggerRight = m_r.is_checked ? 255 : m_r_cont.value; - for (unsigned int i = 0; i < ArraySize(m_buttons); ++i) - { - if (m_buttons[i] != nullptr) - { - if (m_buttons[i]->is_checked) - PadStatus->button |= m_gc_pad_buttons_bitmask[i]; - else - PadStatus->button &= ~m_gc_pad_buttons_bitmask[i]; - } - } + for (unsigned int i = 0; i < ArraySize(m_buttons); ++i) + { + if (m_buttons[i] != nullptr) + { + if (m_buttons[i]->is_checked) + PadStatus->button |= m_gc_pad_buttons_bitmask[i]; + else + PadStatus->button &= ~m_gc_pad_buttons_bitmask[i]; + } + } - if (m_a.is_checked) - PadStatus->analogA = 0xFF; - else - PadStatus->analogA = 0x00; + if (m_a.is_checked) + PadStatus->analogA = 0xFF; + else + PadStatus->analogA = 0x00; - if (m_b.is_checked) - PadStatus->analogB = 0xFF; - else - PadStatus->analogB = 0x00; + if (m_b.is_checked) + PadStatus->analogB = 0xFF; + else + PadStatus->analogB = 0x00; - ButtonTurbo(); + ButtonTurbo(); } void TASInputDlg::UpdateFromSliders(wxCommandEvent& event) { - wxTextCtrl* text = nullptr; + wxTextCtrl* text = nullptr; - for (Control* const control : m_controls) - { - if (control != nullptr && event.GetId() == control->slider_id) - text = control->text; - } + for (Control* const control : m_controls) + { + if (control != nullptr && event.GetId() == control->slider_id) + text = control->text; + } - for (Control* const control : m_cc_controls) - { - if (control != nullptr && event.GetId() == control->slider_id) - text = control->text; - } - int value = ((wxSlider*)event.GetEventObject())->GetValue(); - if (text) - text->SetValue(std::to_string(value)); + for (Control* const control : m_cc_controls) + { + if (control != nullptr && event.GetId() == control->slider_id) + text = control->text; + } + int value = ((wxSlider*)event.GetEventObject())->GetValue(); + if (text) + text->SetValue(std::to_string(value)); } void TASInputDlg::UpdateFromText(wxCommandEvent& event) { - unsigned long value; + unsigned long value; - if (!((wxTextCtrl*)event.GetEventObject())->GetValue().ToULong(&value)) - return; + if (!((wxTextCtrl*)event.GetEventObject())->GetValue().ToULong(&value)) + return; - for (Control* const control : m_controls) - { - if (control != nullptr && event.GetId() == control->text_id) - { - int v = (value > control->range) ? control->range : value; - control->slider->SetValue(v); - control->text->ChangeValue(std::to_string(v)); - control->value = v; - } - } + for (Control* const control : m_controls) + { + if (control != nullptr && event.GetId() == control->text_id) + { + int v = (value > control->range) ? control->range : value; + control->slider->SetValue(v); + control->text->ChangeValue(std::to_string(v)); + control->value = v; + } + } - for (Control* const control : m_cc_controls) - { - if (control != nullptr && event.GetId() == control->text_id) - { - int v = (value > control->range) ? control->range : value; - control->slider->SetValue(v); - control->text->ChangeValue(std::to_string(v)); - control->value = v; - } - } + for (Control* const control : m_cc_controls) + { + if (control != nullptr && event.GetId() == control->text_id) + { + int v = (value > control->range) ? control->range : value; + control->slider->SetValue(v); + control->text->ChangeValue(std::to_string(v)); + control->value = v; + } + } - if (m_controls[0] != nullptr) - UpdateStickBitmap(m_main_stick); - if (m_controls[2] != nullptr) - UpdateStickBitmap(m_c_stick); - if (m_cc_controls[CC_L_STICK_X] != nullptr) - UpdateStickBitmap(m_cc_l_stick); - if (m_cc_controls[CC_R_STICK_X] != nullptr) - UpdateStickBitmap(m_cc_r_stick); + if (m_controls[0] != nullptr) + UpdateStickBitmap(m_main_stick); + if (m_controls[2] != nullptr) + UpdateStickBitmap(m_c_stick); + if (m_cc_controls[CC_L_STICK_X] != nullptr) + UpdateStickBitmap(m_cc_l_stick); + if (m_cc_controls[CC_R_STICK_X] != nullptr) + UpdateStickBitmap(m_cc_r_stick); } void TASInputDlg::UpdateStickBitmap(Stick stick) { - int x = (u8)(std::floor(((double)stick.x_cont.value / (double)(stick.x_cont.range + 1) * 255.0) + .5)); - int y = (u8)(std::floor(((double)stick.y_cont.value / (double)(stick.y_cont.range + 1) * 255.0) + .5)); - if (stick.x_cont.reverse) - x = 256 - (u8)x; - if (stick.y_cont.reverse) - y = 256 - (u8)y; - stick.bitmap->SetBitmap(CreateStickBitmap(x, y)); + int x = (u8)( + std::floor(((double)stick.x_cont.value / (double)(stick.x_cont.range + 1) * 255.0) + .5)); + int y = (u8)( + std::floor(((double)stick.y_cont.value / (double)(stick.y_cont.range + 1) * 255.0) + .5)); + if (stick.x_cont.reverse) + x = 256 - (u8)x; + if (stick.y_cont.reverse) + y = 256 - (u8)y; + stick.bitmap->SetBitmap(CreateStickBitmap(x, y)); } void TASInputDlg::OnCloseWindow(wxCloseEvent& event) { - if (event.CanVeto()) - { - event.Skip(false); - Show(false); - ResetValues(); - } + if (event.CanVeto()) + { + event.Skip(false); + Show(false); + ResetValues(); + } } TASInputDlg::Stick* TASInputDlg::FindStickByID(int id) { - if (id == ID_MAIN_STICK) - return &m_main_stick; - else if (id == ID_C_STICK) - return &m_c_stick; - else if (id == ID_CC_L_STICK) - return &m_cc_l_stick; - else if (id == ID_CC_R_STICK) - return &m_cc_r_stick; - else - return nullptr; + if (id == ID_MAIN_STICK) + return &m_main_stick; + else if (id == ID_C_STICK) + return &m_c_stick; + else if (id == ID_CC_L_STICK) + return &m_cc_l_stick; + else if (id == ID_CC_R_STICK) + return &m_cc_r_stick; + else + return nullptr; } void TASInputDlg::OnMouseUpR(wxMouseEvent& event) { - Stick* stick = FindStickByID(event.GetId()); - if (stick == nullptr) - return; + Stick* stick = FindStickByID(event.GetId()); + if (stick == nullptr) + return; - stick->x_cont.value = stick->x_cont.default_value; - stick->y_cont.value = stick->y_cont.default_value; - stick->bitmap->SetBitmap(CreateStickBitmap(128, 128)); - stick->x_cont.text->SetValue(std::to_string(stick->x_cont.default_value)); - stick->y_cont.text->SetValue(std::to_string(stick->y_cont.default_value)); - stick->x_cont.slider->SetValue(stick->x_cont.default_value); - stick->y_cont.slider->SetValue(stick->y_cont.default_value); + stick->x_cont.value = stick->x_cont.default_value; + stick->y_cont.value = stick->y_cont.default_value; + stick->bitmap->SetBitmap(CreateStickBitmap(128, 128)); + stick->x_cont.text->SetValue(std::to_string(stick->x_cont.default_value)); + stick->y_cont.text->SetValue(std::to_string(stick->y_cont.default_value)); + stick->x_cont.slider->SetValue(stick->x_cont.default_value); + stick->y_cont.slider->SetValue(stick->y_cont.default_value); - event.Skip(); + event.Skip(); } void TASInputDlg::OnRightClickSlider(wxMouseEvent& event) { - for (Control* const control : m_controls) - { - if (control != nullptr && event.GetId() == control->slider_id) - { - control->value = control->default_value; - control->slider->SetValue(control->default_value); - control->text->SetValue(std::to_string(control->default_value)); - return; - } - } - for (Control* const control : m_cc_controls) - { - if (control != nullptr && event.GetId() == control->slider_id) - { - control->value = control->default_value; - control->slider->SetValue(control->default_value); - control->text->SetValue(std::to_string(control->default_value)); - return; - } - } + for (Control* const control : m_controls) + { + if (control != nullptr && event.GetId() == control->slider_id) + { + control->value = control->default_value; + control->slider->SetValue(control->default_value); + control->text->SetValue(std::to_string(control->default_value)); + return; + } + } + for (Control* const control : m_cc_controls) + { + if (control != nullptr && event.GetId() == control->slider_id) + { + control->value = control->default_value; + control->slider->SetValue(control->default_value); + control->text->SetValue(std::to_string(control->default_value)); + return; + } + } } void TASInputDlg::OnMouseDownL(wxMouseEvent& event) { - if (!event.LeftIsDown()) - return; + if (!event.LeftIsDown()) + return; - Stick* stick = FindStickByID(event.GetId()); - if (stick == nullptr) - return; + Stick* stick = FindStickByID(event.GetId()); + if (stick == nullptr) + return; - wxPoint ptM(event.GetPosition()); - stick->x_cont.value = ptM.x * stick->x_cont.range / 127; - stick->y_cont.value = ptM.y * stick->y_cont.range / 127; + wxPoint ptM(event.GetPosition()); + stick->x_cont.value = ptM.x * stick->x_cont.range / 127; + stick->y_cont.value = ptM.y * stick->y_cont.range / 127; - if ((unsigned)stick->y_cont.value > stick->y_cont.range) - stick->y_cont.value = stick->y_cont.range; - if ((unsigned)stick->x_cont.value > stick->x_cont.range) - stick->x_cont.value = stick->x_cont.range; + if ((unsigned)stick->y_cont.value > stick->y_cont.range) + stick->y_cont.value = stick->y_cont.range; + if ((unsigned)stick->x_cont.value > stick->x_cont.range) + stick->x_cont.value = stick->x_cont.range; - if (stick->y_cont.reverse) - stick->y_cont.value = stick->y_cont.range - (u16)stick->y_cont.value; - if (stick->x_cont.reverse) - stick->x_cont.value = stick->x_cont.range - (u16)stick->x_cont.value; + if (stick->y_cont.reverse) + stick->y_cont.value = stick->y_cont.range - (u16)stick->y_cont.value; + if (stick->x_cont.reverse) + stick->x_cont.value = stick->x_cont.range - (u16)stick->x_cont.value; - stick->x_cont.value = (unsigned int)stick->x_cont.value > stick->x_cont.range ? stick->x_cont.range : stick->x_cont.value; - stick->y_cont.value = (unsigned int)stick->y_cont.value > stick->y_cont.range ? stick->y_cont.range : stick->y_cont.value; + stick->x_cont.value = (unsigned int)stick->x_cont.value > stick->x_cont.range ? + stick->x_cont.range : + stick->x_cont.value; + stick->y_cont.value = (unsigned int)stick->y_cont.value > stick->y_cont.range ? + stick->y_cont.range : + stick->y_cont.value; - // This updates sliders and the bitmap too. - stick->x_cont.text->SetValue(std::to_string(stick->x_cont.value)); - stick->y_cont.text->SetValue(std::to_string(stick->y_cont.value)); + // This updates sliders and the bitmap too. + stick->x_cont.text->SetValue(std::to_string(stick->x_cont.value)); + stick->y_cont.text->SetValue(std::to_string(stick->y_cont.value)); - event.Skip(); + event.Skip(); } void TASInputDlg::SetTurbo(wxMouseEvent& event) { - Button* button = nullptr; + Button* button = nullptr; - for (Button* const btn : m_buttons) - { - if (btn != nullptr && event.GetId() == btn->id) - button = btn; - } - if (m_ext == 2) - { - for (size_t i = 0; i < ArraySize(m_cc_buttons); ++i) - { - if (event.GetId() == m_cc_buttons[i].id) - button = &m_cc_buttons[i]; - } - } + for (Button* const btn : m_buttons) + { + if (btn != nullptr && event.GetId() == btn->id) + button = btn; + } + if (m_ext == 2) + { + for (size_t i = 0; i < ArraySize(m_cc_buttons); ++i) + { + if (event.GetId() == m_cc_buttons[i].id) + button = &m_cc_buttons[i]; + } + } - if (event.LeftDown()) - { - if (button) - button->turbo_on = false; + if (event.LeftDown()) + { + if (button) + button->turbo_on = false; - event.Skip(); - return; - } + event.Skip(); + return; + } - if (button) - { - button->checkbox->SetValue(true); - button->turbo_on = !button->turbo_on; - } + if (button) + { + button->checkbox->SetValue(true); + button->turbo_on = !button->turbo_on; + } - event.Skip(); + event.Skip(); } // NOTE: Host / CPU Thread void TASInputDlg::ButtonTurbo() { - static u64 frame = Movie::g_currentFrame; + static u64 frame = Movie::g_currentFrame; - if (frame != Movie::g_currentFrame) - { - frame = Movie::g_currentFrame; - for (Button* const button : m_buttons) - { - if (button != nullptr && button->turbo_on) - { - button->value = !button->is_checked; - InvalidateButton(button); - } - } - if (m_ext == 2) - { - for (Button& button : m_cc_buttons) - { - if (button.turbo_on) - { - button.value = !button.is_checked; - InvalidateButton(&button); - } - } - } - } + if (frame != Movie::g_currentFrame) + { + frame = Movie::g_currentFrame; + for (Button* const button : m_buttons) + { + if (button != nullptr && button->turbo_on) + { + button->value = !button->is_checked; + InvalidateButton(button); + } + } + if (m_ext == 2) + { + for (Button& button : m_cc_buttons) + { + if (button.turbo_on) + { + button.value = !button.is_checked; + InvalidateButton(&button); + } + } + } + } } void TASInputDlg::InvalidateButton(Button* button) { - if (!wxIsMainThread()) - { - wxCommandEvent* evt = new wxCommandEvent(INVALIDATE_BUTTON_EVENT, button->id); - evt->SetClientData(button); - wxQueueEvent(this, evt); - return; - } + if (!wxIsMainThread()) + { + wxCommandEvent* evt = new wxCommandEvent(INVALIDATE_BUTTON_EVENT, button->id); + evt->SetClientData(button); + wxQueueEvent(this, evt); + return; + } - button->checkbox->SetValue(button->value); - button->is_checked = button->value; + button->checkbox->SetValue(button->value); + button->is_checked = button->value; } void TASInputDlg::InvalidateControl(Control* control) { - if (!wxIsMainThread()) - { - wxCommandEvent* evt = new wxCommandEvent(INVALIDATE_CONTROL_EVENT, control->text_id); - evt->SetClientData(control); - wxQueueEvent(this, evt); - return; - } + if (!wxIsMainThread()) + { + wxCommandEvent* evt = new wxCommandEvent(INVALIDATE_CONTROL_EVENT, control->text_id); + evt->SetClientData(control); + wxQueueEvent(this, evt); + return; + } - control->text->SetValue(std::to_string(control->value)); + control->text->SetValue(std::to_string(control->value)); } void TASInputDlg::InvalidateExtension() { - if (!wxIsMainThread()) - { - GetEventHandler()->QueueEvent(new wxThreadEvent(INVALIDATE_EXTENSION_EVENT)); - return; - } + if (!wxIsMainThread()) + { + GetEventHandler()->QueueEvent(new wxThreadEvent(INVALIDATE_EXTENSION_EVENT)); + return; + } - HandleExtensionChange(); + HandleExtensionChange(); } void TASInputDlg::UpdateFromInvalidatedButton(wxCommandEvent& event) { - Button* button = static_cast(event.GetClientData()); - _assert_msg_(PAD, button->id == button->checkbox->GetId(), "Button ids do not match: %i != %i", button->id, button->checkbox->GetId()); - button->checkbox->SetValue(button->value); - button->is_checked = button->value; + Button* button = static_cast(event.GetClientData()); + _assert_msg_(PAD, button->id == button->checkbox->GetId(), "Button ids do not match: %i != %i", + button->id, button->checkbox->GetId()); + button->checkbox->SetValue(button->value); + button->is_checked = button->value; } void TASInputDlg::UpdateFromInvalidatedControl(wxCommandEvent& event) { - Control* control = static_cast(event.GetClientData()); - _assert_msg_(PAD, control->text_id == control->text->GetId(), "Control ids do not match: %i != %i", control->text_id, control->text->GetId()); - control->text->SetValue(std::to_string(control->value)); + Control* control = static_cast(event.GetClientData()); + _assert_msg_(PAD, control->text_id == control->text->GetId(), + "Control ids do not match: %i != %i", control->text_id, control->text->GetId()); + control->text->SetValue(std::to_string(control->value)); } void TASInputDlg::UpdateFromInvalidatedExtension(wxThreadEvent&) { - HandleExtensionChange(); + HandleExtensionChange(); } wxBitmap TASInputDlg::CreateStickBitmap(int x, int y) { - x = x / 2; - y = y / 2; + x = x / 2; + y = y / 2; - wxMemoryDC memDC; - wxBitmap bitmap(129, 129); - memDC.SelectObject(bitmap); - memDC.SetBackground(*wxLIGHT_GREY_BRUSH); - memDC.Clear(); - memDC.SetBrush(*wxWHITE_BRUSH); - memDC.DrawCircle(65, 65, 64); - memDC.SetBrush(*wxRED_BRUSH); - memDC.DrawLine(64, 64, x, y); - memDC.DrawLine(63, 64, x - 1, y); - memDC.DrawLine(65, 64, x + 1, y); - memDC.DrawLine(64, 63, x, y - 1); - memDC.DrawLine(64, 65, x, y + 1); - memDC.SetPen(*wxBLACK_PEN); - memDC.CrossHair(64, 64); - memDC.SetBrush(*wxBLUE_BRUSH); - memDC.DrawCircle(x, y, 5); - memDC.SelectObject(wxNullBitmap); - return bitmap; + wxMemoryDC memDC; + wxBitmap bitmap(129, 129); + memDC.SelectObject(bitmap); + memDC.SetBackground(*wxLIGHT_GREY_BRUSH); + memDC.Clear(); + memDC.SetBrush(*wxWHITE_BRUSH); + memDC.DrawCircle(65, 65, 64); + memDC.SetBrush(*wxRED_BRUSH); + memDC.DrawLine(64, 64, x, y); + memDC.DrawLine(63, 64, x - 1, y); + memDC.DrawLine(65, 64, x + 1, y); + memDC.DrawLine(64, 63, x, y - 1); + memDC.DrawLine(64, 65, x, y + 1); + memDC.SetPen(*wxBLACK_PEN); + memDC.CrossHair(64, 64); + memDC.SetBrush(*wxBLUE_BRUSH); + memDC.DrawCircle(x, y, 5); + memDC.SelectObject(wxNullBitmap); + return bitmap; } diff --git a/Source/Core/DolphinWX/TASInputDlg.h b/Source/Core/DolphinWX/TASInputDlg.h index f7e4996374..0e44f292e1 100644 --- a/Source/Core/DolphinWX/TASInputDlg.h +++ b/Source/Core/DolphinWX/TASInputDlg.h @@ -20,128 +20,128 @@ class wxTextCtrl; class TASInputDlg : public wxDialog { - public: - TASInputDlg(wxWindow* parent, - wxWindowID id = wxID_ANY, - const wxString& title = _("TAS Input"), - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxDEFAULT_DIALOG_STYLE | wxSTAY_ON_TOP); +public: + TASInputDlg(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("TAS Input"), + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_DIALOG_STYLE | wxSTAY_ON_TOP); - void OnCloseWindow(wxCloseEvent& event); - void UpdateFromSliders(wxCommandEvent& event); - void UpdateFromText(wxCommandEvent& event); - void OnMouseDownL(wxMouseEvent& event); - void OnMouseUpR(wxMouseEvent& event); - void OnRightClickSlider(wxMouseEvent& event); - void ResetValues(); - void GetValues(GCPadStatus* PadStatus); - void GetValues(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, const wiimote_key key); - void SetTurbo(wxMouseEvent& event); - void ButtonTurbo(); - void GetKeyBoardInput(GCPadStatus* PadStatus); - void GetKeyBoardInput(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, const wiimote_key key); - void CreateGCLayout(); - void CreateWiiLayout(int num); - wxBitmap CreateStickBitmap(int x, int y); - void SetWiiButtons(u16* butt); - void HandleExtensionChange(); + void OnCloseWindow(wxCloseEvent& event); + void UpdateFromSliders(wxCommandEvent& event); + void UpdateFromText(wxCommandEvent& event); + void OnMouseDownL(wxMouseEvent& event); + void OnMouseUpR(wxMouseEvent& event); + void OnRightClickSlider(wxMouseEvent& event); + void ResetValues(); + void GetValues(GCPadStatus* PadStatus); + void GetValues(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, const wiimote_key key); + void SetTurbo(wxMouseEvent& event); + void ButtonTurbo(); + void GetKeyBoardInput(GCPadStatus* PadStatus); + void GetKeyBoardInput(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, const wiimote_key key); + void CreateGCLayout(); + void CreateWiiLayout(int num); + wxBitmap CreateStickBitmap(int x, int y); + void SetWiiButtons(u16* butt); + void HandleExtensionChange(); - private: - const int ID_C_STICK = 1001; - const int ID_MAIN_STICK = 1002; - const int ID_CC_L_STICK = 1003; - const int ID_CC_R_STICK = 1004; - int m_eleID = 1005; +private: + const int ID_C_STICK = 1001; + const int ID_MAIN_STICK = 1002; + const int ID_CC_L_STICK = 1003; + const int ID_CC_R_STICK = 1004; + int m_eleID = 1005; - struct Control - { - wxTextCtrl* text; - wxSlider* slider; - int value = -1; - int text_id; - int slider_id; - u32 range; - u32 default_value = 128; - bool set_by_keyboard = false; - bool reverse = false; - }; + struct Control + { + wxTextCtrl* text; + wxSlider* slider; + int value = -1; + int text_id; + int slider_id; + u32 range; + u32 default_value = 128; + bool set_by_keyboard = false; + bool reverse = false; + }; - struct Button - { - wxCheckBox* checkbox; - bool is_checked = false; - bool value = false; - bool set_by_keyboard = false; - bool turbo_on = false; - int id; - }; + struct Button + { + wxCheckBox* checkbox; + bool is_checked = false; + bool value = false; + bool set_by_keyboard = false; + bool turbo_on = false; + int id; + }; - struct Stick - { - wxStaticBitmap* bitmap; - Control x_cont; - Control y_cont; - }; + struct Stick + { + wxStaticBitmap* bitmap; + Control x_cont; + Control y_cont; + }; - wxBoxSizer* CreateCCLayout(); - void FinishLayout(); - void SetStickValue(Control* stick, int CurrentValue, int center = 128); - void SetButtonValue(Button* button, bool CurrentState); - void SetSliderValue(Control* control, int CurrentValue); - void CreateBaseLayout(); - void UpdateStickBitmap(Stick stick); - void InvalidateButton(Button* button); - void InvalidateControl(Control* button); - void InvalidateExtension(); - void UpdateFromInvalidatedButton(wxCommandEvent& event); - void UpdateFromInvalidatedControl(wxCommandEvent& event); - void UpdateFromInvalidatedExtension(wxThreadEvent& event); - void OnCheckboxToggle(wxCommandEvent& event); - Stick* FindStickByID(int id); - Stick CreateStick(int id_stick, int xRange, int yRange, u32 defaultX, u32 defaultY, bool reverseX, bool reverseY); - wxStaticBoxSizer* CreateStickLayout(Stick* tempStick, const wxString& title); - wxStaticBoxSizer* CreateAccelLayout(Control* x, Control* y, Control* z, const wxString& title); - Button CreateButton(const std::string& name); - Control CreateControl(long style, int width, int height, bool reverse = false, u32 range = 255, u32 default_value = 128); + wxBoxSizer* CreateCCLayout(); + void FinishLayout(); + void SetStickValue(Control* stick, int CurrentValue, int center = 128); + void SetButtonValue(Button* button, bool CurrentState); + void SetSliderValue(Control* control, int CurrentValue); + void CreateBaseLayout(); + void UpdateStickBitmap(Stick stick); + void InvalidateButton(Button* button); + void InvalidateControl(Control* button); + void InvalidateExtension(); + void UpdateFromInvalidatedButton(wxCommandEvent& event); + void UpdateFromInvalidatedControl(wxCommandEvent& event); + void UpdateFromInvalidatedExtension(wxThreadEvent& event); + void OnCheckboxToggle(wxCommandEvent& event); + Stick* FindStickByID(int id); + Stick CreateStick(int id_stick, int xRange, int yRange, u32 defaultX, u32 defaultY, bool reverseX, + bool reverseY); + wxStaticBoxSizer* CreateStickLayout(Stick* tempStick, const wxString& title); + wxStaticBoxSizer* CreateAccelLayout(Control* x, Control* y, Control* z, const wxString& title); + Button CreateButton(const std::string& name); + Control CreateControl(long style, int width, int height, bool reverse = false, u32 range = 255, + u32 default_value = 128); - enum - { - CC_L_STICK_X, - CC_L_STICK_Y, - CC_R_STICK_X, - CC_R_STICK_Y, - CC_L_TRIGGER, - CC_R_TRIGGER, - }; + enum + { + CC_L_STICK_X, + CC_L_STICK_Y, + CC_R_STICK_X, + CC_R_STICK_Y, + CC_L_TRIGGER, + CC_R_TRIGGER, + }; - Control m_l_cont, m_r_cont, m_x_cont, m_y_cont, m_z_cont, m_nx_cont, m_ny_cont, m_nz_cont, m_cc_l, m_cc_r; - Button m_a, m_b, m_x, m_y, m_z, m_l, m_r, m_c; - Button m_start, m_plus, m_minus, m_one, m_two, m_home; - Button m_dpad_up, m_dpad_down, m_dpad_left, m_dpad_right; - Stick m_main_stick, m_c_stick; + Control m_l_cont, m_r_cont, m_x_cont, m_y_cont, m_z_cont, m_nx_cont, m_ny_cont, m_nz_cont, m_cc_l, + m_cc_r; + Button m_a, m_b, m_x, m_y, m_z, m_l, m_r, m_c; + Button m_start, m_plus, m_minus, m_one, m_two, m_home; + Button m_dpad_up, m_dpad_down, m_dpad_left, m_dpad_right; + Stick m_main_stick, m_c_stick; - Stick m_cc_l_stick, m_cc_r_stick; + Stick m_cc_l_stick, m_cc_r_stick; - Button* m_buttons[13]; - Button m_cc_buttons[15]; - Control* m_controls[10]; - Control* m_cc_controls[6]; - static const int m_gc_pad_buttons_bitmask[12]; - static const int m_wii_buttons_bitmask[11]; - static const int m_cc_buttons_bitmask[15]; - static const std::string m_cc_button_names[15]; - u8 m_ext = 0; - wxBoxSizer* m_main_szr; - wxBoxSizer* m_wiimote_szr; - wxBoxSizer* m_ext_szr; - wxBoxSizer* m_cc_szr; - wxStaticBoxSizer* m_main_stick_szr; - wxStaticBoxSizer* m_c_stick_szr; - wxStaticBoxSizer* m_cc_l_stick_szr; - wxStaticBoxSizer* m_cc_r_stick_szr; + Button* m_buttons[13]; + Button m_cc_buttons[15]; + Control* m_controls[10]; + Control* m_cc_controls[6]; + static const int m_gc_pad_buttons_bitmask[12]; + static const int m_wii_buttons_bitmask[11]; + static const int m_cc_buttons_bitmask[15]; + static const std::string m_cc_button_names[15]; + u8 m_ext = 0; + wxBoxSizer* m_main_szr; + wxBoxSizer* m_wiimote_szr; + wxBoxSizer* m_ext_szr; + wxBoxSizer* m_cc_szr; + wxStaticBoxSizer* m_main_stick_szr; + wxStaticBoxSizer* m_c_stick_szr; + wxStaticBoxSizer* m_cc_l_stick_szr; + wxStaticBoxSizer* m_cc_r_stick_szr; - bool m_has_layout = false; + bool m_has_layout = false; - wxGridSizer* m_buttons_dpad; + wxGridSizer* m_buttons_dpad; }; diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index 322b568171..64e4f7114e 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -40,764 +40,1007 @@ template class BoolSetting; template class BoolSetting; template <> -SettingCheckBox::BoolSetting(wxWindow* parent, const wxString& label, const wxString& tooltip, bool &setting, bool reverse, long style) - : wxCheckBox(parent, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, style) - , m_setting(setting) - , m_reverse(reverse) +SettingCheckBox::BoolSetting(wxWindow* parent, const wxString& label, const wxString& tooltip, + bool& setting, bool reverse, long style) + : wxCheckBox(parent, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, style), + m_setting(setting), m_reverse(reverse) { - SetToolTip(tooltip); - SetValue(m_setting ^ m_reverse); - Bind(wxEVT_CHECKBOX, &SettingCheckBox::UpdateValue, this); + SetToolTip(tooltip); + SetValue(m_setting ^ m_reverse); + Bind(wxEVT_CHECKBOX, &SettingCheckBox::UpdateValue, this); } template <> -SettingRadioButton::BoolSetting(wxWindow* parent, const wxString& label, const wxString& tooltip, bool &setting, bool reverse, long style) - : wxRadioButton(parent, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, style) - , m_setting(setting) - , m_reverse(reverse) +SettingRadioButton::BoolSetting(wxWindow* parent, const wxString& label, const wxString& tooltip, + bool& setting, bool reverse, long style) + : wxRadioButton(parent, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, style), + m_setting(setting), m_reverse(reverse) { - SetToolTip(tooltip); - SetValue(m_setting ^ m_reverse); - Bind(wxEVT_RADIOBUTTON, &SettingRadioButton::UpdateValue, this); + SetToolTip(tooltip); + SetValue(m_setting ^ m_reverse); + Bind(wxEVT_RADIOBUTTON, &SettingRadioButton::UpdateValue, this); } -SettingChoice::SettingChoice(wxWindow* parent, int &setting, const wxString& tooltip, int num, const wxString choices[], long style) - : wxChoice(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, num, choices) - , m_setting(setting) +SettingChoice::SettingChoice(wxWindow* parent, int& setting, const wxString& tooltip, int num, + const wxString choices[], long style) + : wxChoice(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, num, choices), m_setting(setting) { - SetToolTip(tooltip); - Select(m_setting); - Bind(wxEVT_CHOICE, &SettingChoice::UpdateValue, this); + SetToolTip(tooltip); + Select(m_setting); + Bind(wxEVT_CHOICE, &SettingChoice::UpdateValue, this); } void SettingChoice::UpdateValue(wxCommandEvent& ev) { - m_setting = ev.GetInt(); - ev.Skip(); + m_setting = ev.GetInt(); + ev.Skip(); } void VideoConfigDiag::Event_ClickClose(wxCommandEvent&) { - Close(); + Close(); } void VideoConfigDiag::Event_Close(wxCloseEvent& ev) { - g_Config.Save(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"); + g_Config.Save(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"); - EndModal(wxID_OK); + EndModal(wxID_OK); } #if defined(_WIN32) -static wxString backend_desc = wxTRANSLATE("Selects what graphics API to use internally.\nThe software renderer is extremely slow and only useful for debugging, so you'll want to use either Direct3D or OpenGL. Different games and different GPUs will behave differently on each backend, so for the best emulation experience it's recommended to try both and choose the one that's less problematic.\n\nIf unsure, select OpenGL."); +static wxString backend_desc = + wxTRANSLATE("Selects what graphics API to use internally.\nThe software renderer is extremely " + "slow and only useful for debugging, so you'll want to use either Direct3D or " + "OpenGL. Different games and different GPUs will behave differently on each " + "backend, so for the best emulation experience it's recommended to try both and " + "choose the one that's less problematic.\n\nIf unsure, select OpenGL."); #else -static wxString backend_desc = wxTRANSLATE("Selects what graphics API to use internally.\nThe software renderer is extremely slow and only useful for debugging, so unless you have a reason to use it you'll want to select OpenGL here.\n\nIf unsure, select OpenGL."); +static wxString backend_desc = + wxTRANSLATE("Selects what graphics API to use internally.\nThe software renderer is extremely " + "slow and only useful for debugging, so unless you have a reason to use it you'll " + "want to select OpenGL here.\n\nIf unsure, select OpenGL."); #endif -static wxString adapter_desc = wxTRANSLATE("Selects a hardware adapter to use.\n\nIf unsure, use the first one."); -static wxString display_res_desc = wxTRANSLATE("Selects the display resolution used in fullscreen mode.\nThis should always be bigger than or equal to the internal resolution. Performance impact is negligible.\n\nIf unsure, select auto."); -static wxString use_fullscreen_desc = wxTRANSLATE("Enable this if you want the whole screen to be used for rendering.\nIf this is disabled, a render window will be created instead.\n\nIf unsure, leave this unchecked."); -static wxString auto_window_size_desc = wxTRANSLATE("Automatically adjusts the window size to your internal resolution.\n\nIf unsure, leave this unchecked."); -static wxString keep_window_on_top_desc = wxTRANSLATE("Keep the game window on top of all other windows.\n\nIf unsure, leave this unchecked."); -static wxString hide_mouse_cursor_desc = wxTRANSLATE("Hides the mouse cursor if it's on top of the emulation window.\n\nIf unsure, leave this unchecked."); -static wxString render_to_main_win_desc = wxTRANSLATE("Enable this if you want to use the main Dolphin window for rendering rather than a separate render window.\n\nIf unsure, leave this unchecked."); -static wxString prog_scan_desc = wxTRANSLATE("Enables progressive scan if supported by the emulated software.\nMost games don't care about this.\n\nIf unsure, leave this unchecked."); -static wxString ar_desc = wxTRANSLATE("Select what aspect ratio to use when rendering:\nAuto: Use the native aspect ratio\nForce 16:9: Mimic an analog TV with a widescreen aspect ratio.\nForce 4:3: Mimic a standard 4:3 analog TV.\nStretch to Window: Stretch the picture to the window size.\n\nIf unsure, select Auto."); -static wxString ws_hack_desc = wxTRANSLATE("Forces the game to output graphics for any aspect ratio.\nUse with \"Aspect Ratio\" set to \"Force 16:9\" to force 4:3-only games to run at 16:9.\nRarely produces good results and often partially breaks graphics and game UIs.\nUnnecessary (and detrimental) if using any AR/Gecko-code widescreen patches.\n\nIf unsure, leave this unchecked."); -static wxString vsync_desc = wxTRANSLATE("Wait for vertical blanks in order to reduce tearing.\nDecreases performance if emulation speed is below 100%.\n\nIf unsure, leave this unchecked."); -static wxString af_desc = wxTRANSLATE("Enable anisotropic filtering.\nEnhances visual quality of textures that are at oblique viewing angles.\nMight cause issues in a small number of games.\n\nIf unsure, select 1x."); -static wxString aa_desc = wxTRANSLATE("Reduces the amount of aliasing caused by rasterizing 3D graphics. This smooths out jagged edges on objects.\nIncreases GPU load and sometimes causes graphical issues. SSAA is significantly more demanding than MSAA, but provides top quality geometry anti-aliasing and also applies anti-aliasing to lighting, shader effects, and textures.\n\nIf unsure, select None."); -static wxString scaled_efb_copy_desc = wxTRANSLATE("Greatly increases quality of textures generated using render-to-texture effects.\nRaising the internal resolution will improve the effect of this setting.\nSlightly increases GPU load and causes relatively few graphical issues.\n\nIf unsure, leave this checked."); -static wxString pixel_lighting_desc = wxTRANSLATE("Calculates lighting of 3D objects per-pixel rather than per-vertex, smoothing out the appearance of lit polygons and making individual triangles less noticeable.\nRarely causes slowdowns or graphical issues.\n\nIf unsure, leave this unchecked."); -static wxString fast_depth_calc_desc = wxTRANSLATE("Use a less accurate algorithm to calculate depth values.\nCauses issues in a few games, but can give a decent speedup depending on the game and/or your GPU.\n\nIf unsure, leave this checked."); -static wxString disable_bbox_desc = wxTRANSLATE("Disable the bounding box emulation.\nThis may improve the GPU performance a lot, but some games will break.\n\nIf unsure, leave this checked."); -static wxString force_filtering_desc = wxTRANSLATE("Filter all textures, including any that the game explicitly set as unfiltered.\nMay improve quality of certain textures in some games, but will cause issues in others.\n\nIf unsure, leave this unchecked."); -static wxString borderless_fullscreen_desc = wxTRANSLATE("Implement fullscreen mode with a borderless window spanning the whole screen instead of using exclusive mode.\nAllows for faster transitions between fullscreen and windowed mode, but slightly increases input latency, makes movement less smooth and slightly decreases performance.\nExclusive mode is required for Nvidia 3D Vision to work in the Direct3D backend.\n\nIf unsure, leave this unchecked."); -static wxString internal_res_desc = wxTRANSLATE("Specifies the resolution used to render at. A high resolution greatly improves visual quality, but also greatly increases GPU load and can cause issues in certain games.\n\"Multiple of 640x528\" will result in a size slightly larger than \"Window Size\" but yield fewer issues. Generally speaking, the lower the internal resolution is, the better your performance will be. Auto (Window Size), 1.5x, and 2.5x may cause issues in some games.\n\nIf unsure, select Native."); -static wxString efb_access_desc = wxTRANSLATE("Ignore any requests from the CPU to read from or write to the EFB.\nImproves performance in some games, but might disable some gameplay-related features or graphical effects.\n\nIf unsure, leave this unchecked."); -static wxString efb_emulate_format_changes_desc = wxTRANSLATE("Ignore any changes to the EFB format.\nImproves performance in many games without any negative effect. Causes graphical defects in a small number of other games.\n\nIf unsure, leave this checked."); -static wxString skip_efb_copy_to_ram_desc = wxTRANSLATE("Stores EFB Copies exclusively on the GPU, bypassing system memory. Causes graphical defects in a small number of games.\n\nEnabled = EFB Copies to Texture\nDisabled = EFB Copies to RAM (and Texture)\n\nIf unsure, leave this checked."); -static wxString stc_desc = wxTRANSLATE("The \"Safe\" setting eliminates the likelihood of the GPU missing texture updates from RAM.\nLower accuracies cause in-game text to appear garbled in certain games.\n\nIf unsure, use the rightmost value."); -static wxString wireframe_desc = wxTRANSLATE("Render the scene as a wireframe.\n\nIf unsure, leave this unchecked."); -static wxString disable_fog_desc = wxTRANSLATE("Makes distant objects more visible by removing fog, thus increasing the overall detail.\nDisabling fog will break some games which rely on proper fog emulation.\n\nIf unsure, leave this unchecked."); -static wxString show_fps_desc = wxTRANSLATE("Show the number of frames rendered per second as a measure of emulation speed.\n\nIf unsure, leave this unchecked."); -static wxString log_render_time_to_file_desc = wxTRANSLATE("Log the render time of every frame to User/Logs/render_time.txt. Use this feature when you want to measure the performance of Dolphin.\n\nIf unsure, leave this unchecked."); -static wxString show_stats_desc = wxTRANSLATE("Show various rendering statistics.\n\nIf unsure, leave this unchecked."); -static wxString texfmt_desc = wxTRANSLATE("Modify textures to show the format they're encoded in. Needs an emulation reset in most cases.\n\nIf unsure, leave this unchecked."); -static wxString xfb_desc = wxTRANSLATE("Disable any XFB emulation.\nSpeeds up emulation a lot but causes heavy glitches in many games which rely on them (especially homebrew applications).\n\nIf unsure, leave this checked."); -static wxString xfb_virtual_desc = wxTRANSLATE("Emulate XFBs using GPU texture objects.\nFixes many games which don't work without XFB emulation while not being as slow as real XFB emulation. However, it may still fail for a lot of other games (especially homebrew applications).\n\nIf unsure, leave this checked."); -static wxString xfb_real_desc = wxTRANSLATE("Emulate XFBs accurately.\nSlows down emulation a lot and prohibits high-resolution rendering but is necessary to emulate a number of games properly.\n\nIf unsure, check virtual XFB emulation instead."); -static wxString dump_textures_desc = wxTRANSLATE("Dump decoded game textures to User/Dump/Textures//.\n\nIf unsure, leave this unchecked."); -static wxString load_hires_textures_desc = wxTRANSLATE("Load custom textures from User/Load/Textures//.\n\nIf unsure, leave this unchecked."); -static wxString cache_hires_textures_desc = wxTRANSLATE("Cache custom textures to system RAM on startup.\nThis can require exponentially more RAM but fixes possible stuttering.\n\nIf unsure, leave this unchecked."); -static wxString dump_efb_desc = wxTRANSLATE("Dump the contents of EFB copies to User/Dump/Textures/.\n\nIf unsure, leave this unchecked."); -#if defined(HAVE_LIBAV) || defined (_WIN32) -static wxString use_ffv1_desc = wxTRANSLATE("Encode frame dumps using the FFV1 codec.\n\nIf unsure, leave this unchecked."); +static wxString adapter_desc = + wxTRANSLATE("Selects a hardware adapter to use.\n\nIf unsure, use the first one."); +static wxString display_res_desc = + wxTRANSLATE("Selects the display resolution used in fullscreen mode.\nThis should always be " + "bigger than or equal to the internal resolution. Performance impact is " + "negligible.\n\nIf unsure, select auto."); +static wxString use_fullscreen_desc = wxTRANSLATE( + "Enable this if you want the whole screen to be used for rendering.\nIf this is disabled, a " + "render window will be created instead.\n\nIf unsure, leave this unchecked."); +static wxString auto_window_size_desc = + wxTRANSLATE("Automatically adjusts the window size to your internal resolution.\n\nIf unsure, " + "leave this unchecked."); +static wxString keep_window_on_top_desc = wxTRANSLATE( + "Keep the game window on top of all other windows.\n\nIf unsure, leave this unchecked."); +static wxString hide_mouse_cursor_desc = + wxTRANSLATE("Hides the mouse cursor if it's on top of the emulation window.\n\nIf unsure, " + "leave this unchecked."); +static wxString render_to_main_win_desc = + wxTRANSLATE("Enable this if you want to use the main Dolphin window for rendering rather than " + "a separate render window.\n\nIf unsure, leave this unchecked."); +static wxString prog_scan_desc = + wxTRANSLATE("Enables progressive scan if supported by the emulated software.\nMost games don't " + "care about this.\n\nIf unsure, leave this unchecked."); +static wxString ar_desc = + wxTRANSLATE("Select what aspect ratio to use when rendering:\nAuto: Use the native aspect " + "ratio\nForce 16:9: Mimic an analog TV with a widescreen aspect ratio.\nForce 4:3: " + "Mimic a standard 4:3 analog TV.\nStretch to Window: Stretch the picture to the " + "window size.\n\nIf unsure, select Auto."); +static wxString ws_hack_desc = wxTRANSLATE( + "Forces the game to output graphics for any aspect ratio.\nUse with \"Aspect Ratio\" set to " + "\"Force 16:9\" to force 4:3-only games to run at 16:9.\nRarely produces good results and " + "often partially breaks graphics and game UIs.\nUnnecessary (and detrimental) if using any " + "AR/Gecko-code widescreen patches.\n\nIf unsure, leave this unchecked."); +static wxString vsync_desc = + wxTRANSLATE("Wait for vertical blanks in order to reduce tearing.\nDecreases performance if " + "emulation speed is below 100%.\n\nIf unsure, leave this unchecked."); +static wxString af_desc = wxTRANSLATE( + "Enable anisotropic filtering.\nEnhances visual quality of textures that are at oblique " + "viewing angles.\nMight cause issues in a small number of games.\n\nIf unsure, select 1x."); +static wxString aa_desc = + wxTRANSLATE("Reduces the amount of aliasing caused by rasterizing 3D graphics. This smooths " + "out jagged edges on objects.\nIncreases GPU load and sometimes causes graphical " + "issues. SSAA is significantly more demanding than MSAA, but provides top quality " + "geometry anti-aliasing and also applies anti-aliasing to lighting, shader " + "effects, and textures.\n\nIf unsure, select None."); +static wxString scaled_efb_copy_desc = wxTRANSLATE( + "Greatly increases quality of textures generated using render-to-texture effects.\nRaising the " + "internal resolution will improve the effect of this setting.\nSlightly increases GPU load and " + "causes relatively few graphical issues.\n\nIf unsure, leave this checked."); +static wxString pixel_lighting_desc = wxTRANSLATE( + "Calculates lighting of 3D objects per-pixel rather than per-vertex, smoothing out the " + "appearance of lit polygons and making individual triangles less noticeable.\nRarely causes " + "slowdowns or graphical issues.\n\nIf unsure, leave this unchecked."); +static wxString fast_depth_calc_desc = + wxTRANSLATE("Use a less accurate algorithm to calculate depth values.\nCauses issues in a few " + "games, but can give a decent speedup depending on the game and/or your GPU.\n\nIf " + "unsure, leave this checked."); +static wxString disable_bbox_desc = + wxTRANSLATE("Disable the bounding box emulation.\nThis may improve the GPU performance a lot, " + "but some games will break.\n\nIf unsure, leave this checked."); +static wxString force_filtering_desc = + wxTRANSLATE("Filter all textures, including any that the game explicitly set as " + "unfiltered.\nMay improve quality of certain textures in some games, but will " + "cause issues in others.\n\nIf unsure, leave this unchecked."); +static wxString borderless_fullscreen_desc = wxTRANSLATE( + "Implement fullscreen mode with a borderless window spanning the whole screen instead of using " + "exclusive mode.\nAllows for faster transitions between fullscreen and windowed mode, but " + "slightly increases input latency, makes movement less smooth and slightly decreases " + "performance.\nExclusive mode is required for Nvidia 3D Vision to work in the Direct3D " + "backend.\n\nIf unsure, leave this unchecked."); +static wxString internal_res_desc = + wxTRANSLATE("Specifies the resolution used to render at. A high resolution greatly improves " + "visual quality, but also greatly increases GPU load and can cause issues in " + "certain games.\n\"Multiple of 640x528\" will result in a size slightly larger " + "than \"Window Size\" but yield fewer issues. Generally speaking, the lower the " + "internal resolution is, the better your performance will be. Auto (Window Size), " + "1.5x, and 2.5x may cause issues in some games.\n\nIf unsure, select Native."); +static wxString efb_access_desc = + wxTRANSLATE("Ignore any requests from the CPU to read from or write to the EFB.\nImproves " + "performance in some games, but might disable some gameplay-related features or " + "graphical effects.\n\nIf unsure, leave this unchecked."); +static wxString efb_emulate_format_changes_desc = + wxTRANSLATE("Ignore any changes to the EFB format.\nImproves performance in many games without " + "any negative effect. Causes graphical defects in a small number of other " + "games.\n\nIf unsure, leave this checked."); +static wxString skip_efb_copy_to_ram_desc = wxTRANSLATE( + "Stores EFB Copies exclusively on the GPU, bypassing system memory. Causes graphical defects " + "in a small number of games.\n\nEnabled = EFB Copies to Texture\nDisabled = EFB Copies to RAM " + "(and Texture)\n\nIf unsure, leave this checked."); +static wxString stc_desc = + wxTRANSLATE("The \"Safe\" setting eliminates the likelihood of the GPU missing texture updates " + "from RAM.\nLower accuracies cause in-game text to appear garbled in certain " + "games.\n\nIf unsure, use the rightmost value."); +static wxString wireframe_desc = + wxTRANSLATE("Render the scene as a wireframe.\n\nIf unsure, leave this unchecked."); +static wxString disable_fog_desc = + wxTRANSLATE("Makes distant objects more visible by removing fog, thus increasing the overall " + "detail.\nDisabling fog will break some games which rely on proper fog " + "emulation.\n\nIf unsure, leave this unchecked."); +static wxString show_fps_desc = + wxTRANSLATE("Show the number of frames rendered per second as a measure of emulation " + "speed.\n\nIf unsure, leave this unchecked."); +static wxString log_render_time_to_file_desc = wxTRANSLATE( + "Log the render time of every frame to User/Logs/render_time.txt. Use this feature when you " + "want to measure the performance of Dolphin.\n\nIf unsure, leave this unchecked."); +static wxString show_stats_desc = + wxTRANSLATE("Show various rendering statistics.\n\nIf unsure, leave this unchecked."); +static wxString texfmt_desc = + wxTRANSLATE("Modify textures to show the format they're encoded in. Needs an emulation reset " + "in most cases.\n\nIf unsure, leave this unchecked."); +static wxString xfb_desc = wxTRANSLATE( + "Disable any XFB emulation.\nSpeeds up emulation a lot but causes heavy glitches in many games " + "which rely on them (especially homebrew applications).\n\nIf unsure, leave this checked."); +static wxString xfb_virtual_desc = wxTRANSLATE( + "Emulate XFBs using GPU texture objects.\nFixes many games which don't work without XFB " + "emulation while not being as slow as real XFB emulation. However, it may still fail for a lot " + "of other games (especially homebrew applications).\n\nIf unsure, leave this checked."); +static wxString xfb_real_desc = + wxTRANSLATE("Emulate XFBs accurately.\nSlows down emulation a lot and prohibits " + "high-resolution rendering but is necessary to emulate a number of games " + "properly.\n\nIf unsure, check virtual XFB emulation instead."); +static wxString dump_textures_desc = + wxTRANSLATE("Dump decoded game textures to User/Dump/Textures//.\n\nIf unsure, leave " + "this unchecked."); +static wxString load_hires_textures_desc = wxTRANSLATE( + "Load custom textures from User/Load/Textures//.\n\nIf unsure, leave this unchecked."); +static wxString cache_hires_textures_desc = + wxTRANSLATE("Cache custom textures to system RAM on startup.\nThis can require exponentially " + "more RAM but fixes possible stuttering.\n\nIf unsure, leave this unchecked."); +static wxString dump_efb_desc = wxTRANSLATE( + "Dump the contents of EFB copies to User/Dump/Textures/.\n\nIf unsure, leave this unchecked."); +#if defined(HAVE_LIBAV) || defined(_WIN32) +static wxString use_ffv1_desc = + wxTRANSLATE("Encode frame dumps using the FFV1 codec.\n\nIf unsure, leave this unchecked."); #endif -static wxString free_look_desc = wxTRANSLATE("This feature allows you to change the game's camera.\nMove the mouse while holding the right mouse button to pan and while holding the middle button to move.\nHold SHIFT and press one of the WASD keys to move the camera by a certain step distance (SHIFT+2 to move faster and SHIFT+1 to move slower). Press SHIFT+R to reset the camera and SHIFT+F to reset the speed.\n\nIf unsure, leave this unchecked."); -static wxString crop_desc = wxTRANSLATE("Crop the picture from its native aspect ratio to 4:3 or 16:9.\n\nIf unsure, leave this unchecked."); -static wxString ppshader_desc = wxTRANSLATE("Apply a post-processing effect after finishing a frame.\n\nIf unsure, select (off)."); -static wxString cache_efb_copies_desc = wxTRANSLATE("Slightly speeds up EFB to RAM copies by sacrificing emulation accuracy.\nIf you're experiencing any issues, try raising texture cache accuracy or disable this option.\n\nIf unsure, leave this unchecked."); -static wxString stereo_3d_desc = wxTRANSLATE("Selects the stereoscopic 3D mode. Stereoscopy allows you to get a better feeling of depth if you have the necessary hardware.\nSide-by-Side and Top-and-Bottom are used by most 3D TVs.\nAnaglyph is used for Red-Cyan colored glasses.\nHeavily decreases emulation speed and sometimes causes issues.\n\nIf unsure, select Off."); -static wxString stereo_depth_desc = wxTRANSLATE("Controls the separation distance between the virtual cameras.\nA higher value creates a stronger feeling of depth while a lower value is more comfortable."); -static wxString stereo_convergence_desc = wxTRANSLATE("Controls the distance of the convergence plane. This is the distance at which virtual objects will appear to be in front of the screen.\nA higher value creates stronger out-of-screen effects while a lower value is more comfortable."); -static wxString stereo_swap_desc = wxTRANSLATE("Swaps the left and right eye. Mostly useful if you want to view side-by-side cross-eyed.\n\nIf unsure, leave this unchecked."); +static wxString free_look_desc = wxTRANSLATE( + "This feature allows you to change the game's camera.\nMove the mouse while holding the right " + "mouse button to pan and while holding the middle button to move.\nHold SHIFT and press one of " + "the WASD keys to move the camera by a certain step distance (SHIFT+2 to move faster and " + "SHIFT+1 to move slower). Press SHIFT+R to reset the camera and SHIFT+F to reset the " + "speed.\n\nIf unsure, leave this unchecked."); +static wxString crop_desc = wxTRANSLATE("Crop the picture from its native aspect ratio to 4:3 or " + "16:9.\n\nIf unsure, leave this unchecked."); +static wxString ppshader_desc = wxTRANSLATE( + "Apply a post-processing effect after finishing a frame.\n\nIf unsure, select (off)."); +static wxString cache_efb_copies_desc = + wxTRANSLATE("Slightly speeds up EFB to RAM copies by sacrificing emulation accuracy.\nIf " + "you're experiencing any issues, try raising texture cache accuracy or disable " + "this option.\n\nIf unsure, leave this unchecked."); +static wxString stereo_3d_desc = + wxTRANSLATE("Selects the stereoscopic 3D mode. Stereoscopy allows you to get a better feeling " + "of depth if you have the necessary hardware.\nSide-by-Side and Top-and-Bottom are " + "used by most 3D TVs.\nAnaglyph is used for Red-Cyan colored glasses.\nHeavily " + "decreases emulation speed and sometimes causes issues.\n\nIf unsure, select Off."); +static wxString stereo_depth_desc = + wxTRANSLATE("Controls the separation distance between the virtual cameras.\nA higher value " + "creates a stronger feeling of depth while a lower value is more comfortable."); +static wxString stereo_convergence_desc = + wxTRANSLATE("Controls the distance of the convergence plane. This is the distance at which " + "virtual objects will appear to be in front of the screen.\nA higher value creates " + "stronger out-of-screen effects while a lower value is more comfortable."); +static wxString stereo_swap_desc = + wxTRANSLATE("Swaps the left and right eye. Mostly useful if you want to view side-by-side " + "cross-eyed.\n\nIf unsure, leave this unchecked."); #if !defined(__APPLE__) // Search for available resolutions - TODO: Move to Common? static wxArrayString GetListOfResolutions() { - wxArrayString retlist; - retlist.Add(_("Auto")); + wxArrayString retlist; + retlist.Add(_("Auto")); #ifdef _WIN32 - DWORD iModeNum = 0; - DEVMODE dmi; - ZeroMemory(&dmi, sizeof(dmi)); - dmi.dmSize = sizeof(dmi); - std::vector resos; + DWORD iModeNum = 0; + DEVMODE dmi; + ZeroMemory(&dmi, sizeof(dmi)); + dmi.dmSize = sizeof(dmi); + std::vector resos; - while (EnumDisplaySettings(nullptr, iModeNum++, &dmi) != 0) - { - char res[100]; - sprintf(res, "%dx%d", dmi.dmPelsWidth, dmi.dmPelsHeight); - std::string strRes(res); - // Only add unique resolutions - if (std::find(resos.begin(), resos.end(), strRes) == resos.end()) - { - resos.push_back(strRes); - retlist.Add(StrToWxStr(res)); - } - ZeroMemory(&dmi, sizeof(dmi)); - } + while (EnumDisplaySettings(nullptr, iModeNum++, &dmi) != 0) + { + char res[100]; + sprintf(res, "%dx%d", dmi.dmPelsWidth, dmi.dmPelsHeight); + std::string strRes(res); + // Only add unique resolutions + if (std::find(resos.begin(), resos.end(), strRes) == resos.end()) + { + resos.push_back(strRes); + retlist.Add(StrToWxStr(res)); + } + ZeroMemory(&dmi, sizeof(dmi)); + } #elif defined(HAVE_XRANDR) && HAVE_XRANDR - std::vector resos; - main_frame->m_XRRConfig->AddResolutions(resos); - for (auto res : resos) - retlist.Add(StrToWxStr(res)); + std::vector resos; + main_frame->m_XRRConfig->AddResolutions(resos); + for (auto res : resos) + retlist.Add(StrToWxStr(res)); #elif defined(__APPLE__) - CFArrayRef modes = CGDisplayCopyAllDisplayModes(CGMainDisplayID(), nullptr); - for (CFIndex i = 0; i < CFArrayGetCount(modes); i++) - { - std::stringstream res; - CGDisplayModeRef mode; - CFStringRef encoding; - size_t w, h; - bool is32; + CFArrayRef modes = CGDisplayCopyAllDisplayModes(CGMainDisplayID(), nullptr); + for (CFIndex i = 0; i < CFArrayGetCount(modes); i++) + { + std::stringstream res; + CGDisplayModeRef mode; + CFStringRef encoding; + size_t w, h; + bool is32; - mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i); - w = CGDisplayModeGetWidth(mode); - h = CGDisplayModeGetHeight(mode); - encoding = CGDisplayModeCopyPixelEncoding(mode); - is32 = CFEqual(encoding, CFSTR(IO32BitDirectPixels)); - CFRelease(encoding); + mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i); + w = CGDisplayModeGetWidth(mode); + h = CGDisplayModeGetHeight(mode); + encoding = CGDisplayModeCopyPixelEncoding(mode); + is32 = CFEqual(encoding, CFSTR(IO32BitDirectPixels)); + CFRelease(encoding); - if (!is32) - continue; - if (CGDisplayModeGetIOFlags(mode) & kDisplayModeStretchedFlag) - continue; + if (!is32) + continue; + if (CGDisplayModeGetIOFlags(mode) & kDisplayModeStretchedFlag) + continue; - res << w << "x" << h; + res << w << "x" << h; - retlist.Add(res.str()); - } - CFRelease(modes); + retlist.Add(res.str()); + } + CFRelease(modes); #endif - return retlist; + return retlist; } #endif -VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, const std::string& ininame) - : wxDialog(parent, wxID_ANY, - wxString::Format(_("Dolphin %s Graphics Configuration"), wxGetTranslation(StrToWxStr(title)))) - , vconfig(g_Config) +VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title, + const std::string& ininame) + : wxDialog(parent, wxID_ANY, wxString::Format(_("Dolphin %s Graphics Configuration"), + wxGetTranslation(StrToWxStr(title)))), + vconfig(g_Config) { - if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini")) - vconfig.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"); - else - vconfig.Load(File::GetUserPath(D_CONFIG_IDX) + ininame + ".ini"); + if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini")) + vconfig.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"); + else + vconfig.Load(File::GetUserPath(D_CONFIG_IDX) + ininame + ".ini"); - Bind(wxEVT_UPDATE_UI, &VideoConfigDiag::OnUpdateUI, this); + Bind(wxEVT_UPDATE_UI, &VideoConfigDiag::OnUpdateUI, this); - wxNotebook* const notebook = new wxNotebook(this, wxID_ANY); + wxNotebook* const notebook = new wxNotebook(this, wxID_ANY); - // -- GENERAL -- - { - wxPanel* const page_general = new wxPanel(notebook); - notebook->AddPage(page_general, _("General")); - wxBoxSizer* const szr_general = new wxBoxSizer(wxVERTICAL); + // -- GENERAL -- + { + wxPanel* const page_general = new wxPanel(notebook); + notebook->AddPage(page_general, _("General")); + wxBoxSizer* const szr_general = new wxBoxSizer(wxVERTICAL); - // - basic - { - wxFlexGridSizer* const szr_basic = new wxFlexGridSizer(2, 5, 5); + // - basic + { + wxFlexGridSizer* const szr_basic = new wxFlexGridSizer(2, 5, 5); - // backend - { - label_backend = new wxStaticText(page_general, wxID_ANY, _("Backend:")); - choice_backend = new wxChoice(page_general, wxID_ANY); - RegisterControl(choice_backend, wxGetTranslation(backend_desc)); + // backend + { + label_backend = new wxStaticText(page_general, wxID_ANY, _("Backend:")); + choice_backend = new wxChoice(page_general, wxID_ANY); + RegisterControl(choice_backend, wxGetTranslation(backend_desc)); - for (const auto& backend : g_available_video_backends) - { - choice_backend->AppendString(wxGetTranslation(StrToWxStr(backend->GetDisplayName()))); - } + for (const auto& backend : g_available_video_backends) + { + choice_backend->AppendString(wxGetTranslation(StrToWxStr(backend->GetDisplayName()))); + } - choice_backend->SetStringSelection(wxGetTranslation(StrToWxStr(g_video_backend->GetDisplayName()))); - choice_backend->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_Backend, this); + choice_backend->SetStringSelection( + wxGetTranslation(StrToWxStr(g_video_backend->GetDisplayName()))); + choice_backend->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_Backend, this); - szr_basic->Add(label_backend, 1, wxALIGN_CENTER_VERTICAL, 5); - szr_basic->Add(choice_backend, 1, 0, 0); - } + szr_basic->Add(label_backend, 1, wxALIGN_CENTER_VERTICAL, 5); + szr_basic->Add(choice_backend, 1, 0, 0); + } - // adapter (D3D only) - if (vconfig.backend_info.Adapters.size()) - { - choice_adapter = CreateChoice(page_general, vconfig.iAdapter, wxGetTranslation(adapter_desc)); + // adapter (D3D only) + if (vconfig.backend_info.Adapters.size()) + { + choice_adapter = + CreateChoice(page_general, vconfig.iAdapter, wxGetTranslation(adapter_desc)); - for (const std::string& adapter : vconfig.backend_info.Adapters) - { - choice_adapter->AppendString(StrToWxStr(adapter)); - } + for (const std::string& adapter : vconfig.backend_info.Adapters) + { + choice_adapter->AppendString(StrToWxStr(adapter)); + } - choice_adapter->Select(vconfig.iAdapter); + choice_adapter->Select(vconfig.iAdapter); - label_adapter = new wxStaticText(page_general, wxID_ANY, _("Adapter:")); - szr_basic->Add(label_adapter, 1, wxALIGN_CENTER_VERTICAL, 5); - szr_basic->Add(choice_adapter, 1, 0, 0); - } + label_adapter = new wxStaticText(page_general, wxID_ANY, _("Adapter:")); + szr_basic->Add(label_adapter, 1, wxALIGN_CENTER_VERTICAL, 5); + szr_basic->Add(choice_adapter, 1, 0, 0); + } + // - display + wxFlexGridSizer* const szr_display = new wxFlexGridSizer(2, 5, 5); - // - display - wxFlexGridSizer* const szr_display = new wxFlexGridSizer(2, 5, 5); - - { - + { #if !defined(__APPLE__) - // display resolution - { - wxArrayString res_list = GetListOfResolutions(); - if (res_list.empty()) - res_list.Add(_("")); - label_display_resolution = new wxStaticText(page_general, wxID_ANY, _("Fullscreen Resolution:")); - choice_display_resolution = new wxChoice(page_general, wxID_ANY, wxDefaultPosition, wxDefaultSize, res_list); - RegisterControl(choice_display_resolution, wxGetTranslation(display_res_desc)); - choice_display_resolution->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_DisplayResolution, this); + // display resolution + { + wxArrayString res_list = GetListOfResolutions(); + if (res_list.empty()) + res_list.Add(_("")); + label_display_resolution = + new wxStaticText(page_general, wxID_ANY, _("Fullscreen Resolution:")); + choice_display_resolution = + new wxChoice(page_general, wxID_ANY, wxDefaultPosition, wxDefaultSize, res_list); + RegisterControl(choice_display_resolution, wxGetTranslation(display_res_desc)); + choice_display_resolution->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_DisplayResolution, + this); - choice_display_resolution->SetStringSelection(StrToWxStr(SConfig::GetInstance().strFullscreenResolution)); + choice_display_resolution->SetStringSelection( + StrToWxStr(SConfig::GetInstance().strFullscreenResolution)); - szr_display->Add(label_display_resolution, 1, wxALIGN_CENTER_VERTICAL, 0); - szr_display->Add(choice_display_resolution); - } + szr_display->Add(label_display_resolution, 1, wxALIGN_CENTER_VERTICAL, 0); + szr_display->Add(choice_display_resolution); + } #endif - // aspect-ratio - { - const wxString ar_choices[] = { _("Auto"), _("Force 16:9"), _("Force 4:3"), _("Stretch to Window") }; + // aspect-ratio + { + const wxString ar_choices[] = {_("Auto"), _("Force 16:9"), _("Force 4:3"), + _("Stretch to Window")}; - szr_display->Add(new wxStaticText(page_general, wxID_ANY, _("Aspect Ratio:")), 1, wxALIGN_CENTER_VERTICAL, 0); - wxChoice* const choice_aspect = CreateChoice(page_general, vconfig.iAspectRatio, wxGetTranslation(ar_desc), - sizeof(ar_choices)/sizeof(*ar_choices), ar_choices); - szr_display->Add(choice_aspect, 1, 0, 0); - } + szr_display->Add(new wxStaticText(page_general, wxID_ANY, _("Aspect Ratio:")), 1, + wxALIGN_CENTER_VERTICAL, 0); + wxChoice* const choice_aspect = + CreateChoice(page_general, vconfig.iAspectRatio, wxGetTranslation(ar_desc), + sizeof(ar_choices) / sizeof(*ar_choices), ar_choices); + szr_display->Add(choice_aspect, 1, 0, 0); + } - // various other display options - { - szr_display->Add(CreateCheckBox(page_general, _("V-Sync"), wxGetTranslation(vsync_desc), vconfig.bVSync)); - szr_display->Add(CreateCheckBox(page_general, _("Use Fullscreen"), wxGetTranslation(use_fullscreen_desc), SConfig::GetInstance().bFullscreen)); - } - } + // various other display options + { + szr_display->Add(CreateCheckBox(page_general, _("V-Sync"), wxGetTranslation(vsync_desc), + vconfig.bVSync)); + szr_display->Add(CreateCheckBox(page_general, _("Use Fullscreen"), + wxGetTranslation(use_fullscreen_desc), + SConfig::GetInstance().bFullscreen)); + } + } - // - other - wxFlexGridSizer* const szr_other = new wxFlexGridSizer(2, 5, 5); + // - other + wxFlexGridSizer* const szr_other = new wxFlexGridSizer(2, 5, 5); - { - szr_other->Add(CreateCheckBox(page_general, _("Show FPS"), wxGetTranslation(show_fps_desc), vconfig.bShowFPS)); - szr_other->Add(CreateCheckBox(page_general, _("Log Render Time to File"), wxGetTranslation(log_render_time_to_file_desc), vconfig.bLogRenderTimeToFile)); - szr_other->Add(CreateCheckBox(page_general, _("Auto adjust Window Size"), wxGetTranslation(auto_window_size_desc), SConfig::GetInstance().bRenderWindowAutoSize)); - szr_other->Add(CreateCheckBox(page_general, _("Keep Window on Top"), wxGetTranslation(keep_window_on_top_desc), SConfig::GetInstance().bKeepWindowOnTop)); - szr_other->Add(CreateCheckBox(page_general, _("Hide Mouse Cursor"), wxGetTranslation(hide_mouse_cursor_desc), SConfig::GetInstance().bHideCursor)); - szr_other->Add(render_to_main_checkbox = CreateCheckBox(page_general, _("Render to Main Window"), wxGetTranslation(render_to_main_win_desc), SConfig::GetInstance().bRenderToMain)); - } + { + szr_other->Add(CreateCheckBox(page_general, _("Show FPS"), wxGetTranslation(show_fps_desc), + vconfig.bShowFPS)); + szr_other->Add(CreateCheckBox(page_general, _("Log Render Time to File"), + wxGetTranslation(log_render_time_to_file_desc), + vconfig.bLogRenderTimeToFile)); + szr_other->Add(CreateCheckBox(page_general, _("Auto adjust Window Size"), + wxGetTranslation(auto_window_size_desc), + SConfig::GetInstance().bRenderWindowAutoSize)); + szr_other->Add(CreateCheckBox(page_general, _("Keep Window on Top"), + wxGetTranslation(keep_window_on_top_desc), + SConfig::GetInstance().bKeepWindowOnTop)); + szr_other->Add(CreateCheckBox(page_general, _("Hide Mouse Cursor"), + wxGetTranslation(hide_mouse_cursor_desc), + SConfig::GetInstance().bHideCursor)); + szr_other->Add(render_to_main_checkbox = + CreateCheckBox(page_general, _("Render to Main Window"), + wxGetTranslation(render_to_main_win_desc), + SConfig::GetInstance().bRenderToMain)); + } + wxStaticBoxSizer* const group_basic = + new wxStaticBoxSizer(wxVERTICAL, page_general, _("Basic")); + group_basic->Add(szr_basic, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + szr_general->Add(group_basic, 0, wxEXPAND | wxALL, 5); - wxStaticBoxSizer* const group_basic = new wxStaticBoxSizer(wxVERTICAL, page_general, _("Basic")); - group_basic->Add(szr_basic, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - szr_general->Add(group_basic, 0, wxEXPAND | wxALL, 5); + wxStaticBoxSizer* const group_display = + new wxStaticBoxSizer(wxVERTICAL, page_general, _("Display")); + group_display->Add(szr_display, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + szr_general->Add(group_display, 0, wxEXPAND | wxALL, 5); - wxStaticBoxSizer* const group_display = new wxStaticBoxSizer(wxVERTICAL, page_general, _("Display")); - group_display->Add(szr_display, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - szr_general->Add(group_display, 0, wxEXPAND | wxALL, 5); + wxStaticBoxSizer* const group_other = + new wxStaticBoxSizer(wxVERTICAL, page_general, _("Other")); + group_other->Add(szr_other, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + szr_general->Add(group_other, 0, wxEXPAND | wxALL, 5); + } - wxStaticBoxSizer* const group_other = new wxStaticBoxSizer(wxVERTICAL, page_general, _("Other")); - group_other->Add(szr_other, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - szr_general->Add(group_other, 0, wxEXPAND | wxALL, 5); - } + szr_general->AddStretchSpacer(); + CreateDescriptionArea(page_general, szr_general); + page_general->SetSizerAndFit(szr_general); + } - szr_general->AddStretchSpacer(); - CreateDescriptionArea(page_general, szr_general); - page_general->SetSizerAndFit(szr_general); - } + // -- ENHANCEMENTS -- + { + wxPanel* const page_enh = new wxPanel(notebook); + notebook->AddPage(page_enh, _("Enhancements")); + wxBoxSizer* const szr_enh_main = new wxBoxSizer(wxVERTICAL); - // -- ENHANCEMENTS -- - { - wxPanel* const page_enh = new wxPanel(notebook); - notebook->AddPage(page_enh, _("Enhancements")); - wxBoxSizer* const szr_enh_main = new wxBoxSizer(wxVERTICAL); + // - enhancements + wxFlexGridSizer* const szr_enh = new wxFlexGridSizer(2, 5, 5); - // - enhancements - wxFlexGridSizer* const szr_enh = new wxFlexGridSizer(2, 5, 5); + // Internal resolution + { + const wxString efbscale_choices[] = {_("Auto (Window Size)"), + _("Auto (Multiple of 640x528)"), + _("Native (640x528)"), + _("1.5x Native (960x792)"), + _("2x Native (1280x1056) for 720p"), + _("2.5x Native (1600x1320)"), + _("3x Native (1920x1584) for 1080p"), + _("4x Native (2560x2112) for 1440p"), + _("5x Native (3200x2640)"), + _("6x Native (3840x3168) for 4K"), + _("7x Native (4480x3696)"), + _("8x Native (5120x4224) for 5K"), + _("Custom")}; - // Internal resolution - { - const wxString efbscale_choices[] = { _("Auto (Window Size)"), _("Auto (Multiple of 640x528)"), - _("Native (640x528)"), _("1.5x Native (960x792)"), _("2x Native (1280x1056) for 720p"), _("2.5x Native (1600x1320)"), - _("3x Native (1920x1584) for 1080p"), _("4x Native (2560x2112) for 1440p"), _("5x Native (3200x2640)"), - _("6x Native (3840x3168) for 4K"), _("7x Native (4480x3696)"), _("8x Native (5120x4224) for 5K"), _("Custom") }; + wxChoice* const choice_efbscale = CreateChoice( + page_enh, vconfig.iEFBScale, wxGetTranslation(internal_res_desc), + (vconfig.iEFBScale > 11) ? ArraySize(efbscale_choices) : ArraySize(efbscale_choices) - 1, + efbscale_choices); - wxChoice *const choice_efbscale = CreateChoice(page_enh, - vconfig.iEFBScale, wxGetTranslation(internal_res_desc), (vconfig.iEFBScale > 11) ? - ArraySize(efbscale_choices) : ArraySize(efbscale_choices) - 1, efbscale_choices); + if (vconfig.iEFBScale > 11) + choice_efbscale->SetSelection(12); + szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Internal Resolution:")), 1, + wxALIGN_CENTER_VERTICAL, 0); + szr_enh->Add(choice_efbscale); + } - if (vconfig.iEFBScale > 11) - choice_efbscale->SetSelection(12); + // AA + { + text_aamode = new wxStaticText(page_enh, wxID_ANY, _("Anti-Aliasing:")); + choice_aamode = new wxChoice(page_enh, wxID_ANY); + RegisterControl(choice_aamode, wxGetTranslation(aa_desc)); + PopulateAAList(); + choice_aamode->Bind(wxEVT_CHOICE, &VideoConfigDiag::OnAAChanged, this); - szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Internal Resolution:")), 1, wxALIGN_CENTER_VERTICAL, 0); - szr_enh->Add(choice_efbscale); - } + szr_enh->Add(text_aamode, 1, wxALIGN_CENTER_VERTICAL, 0); + szr_enh->Add(choice_aamode); + } - // AA - { + // AF + { + const wxString af_choices[] = {"1x", "2x", "4x", "8x", "16x"}; + szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Anisotropic Filtering:")), 1, + wxALIGN_CENTER_VERTICAL, 0); + szr_enh->Add( + CreateChoice(page_enh, vconfig.iMaxAnisotropy, wxGetTranslation(af_desc), 5, af_choices)); + } - text_aamode = new wxStaticText(page_enh, wxID_ANY, _("Anti-Aliasing:")); - choice_aamode = new wxChoice(page_enh, wxID_ANY); - RegisterControl(choice_aamode, wxGetTranslation(aa_desc)); - PopulateAAList(); - choice_aamode->Bind(wxEVT_CHOICE, &VideoConfigDiag::OnAAChanged, this); + // postproc shader + if (vconfig.backend_info.bSupportsPostProcessing) + { + wxFlexGridSizer* const szr_pp = new wxFlexGridSizer(3, 5, 5); + choice_ppshader = new wxChoice(page_enh, wxID_ANY); + RegisterControl(choice_ppshader, wxGetTranslation(ppshader_desc)); + button_config_pp = new wxButton(page_enh, wxID_ANY, _("Config")); - szr_enh->Add(text_aamode, 1, wxALIGN_CENTER_VERTICAL, 0); - szr_enh->Add(choice_aamode); + PopulatePostProcessingShaders(); - } + choice_ppshader->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_PPShader, this); + button_config_pp->Bind(wxEVT_BUTTON, &VideoConfigDiag::Event_ConfigurePPShader, this); - // AF - { - const wxString af_choices[] = {"1x", "2x", "4x", "8x", "16x"}; - szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Anisotropic Filtering:")), 1, wxALIGN_CENTER_VERTICAL, 0); - szr_enh->Add(CreateChoice(page_enh, vconfig.iMaxAnisotropy, wxGetTranslation(af_desc), 5, af_choices)); - } + szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Post-Processing Effect:")), 1, + wxALIGN_CENTER_VERTICAL, 0); + szr_pp->Add(choice_ppshader); + szr_pp->Add(button_config_pp); + szr_enh->Add(szr_pp); + } + else + { + choice_ppshader = nullptr; + button_config_pp = nullptr; + } - // postproc shader - if (vconfig.backend_info.bSupportsPostProcessing) - { - wxFlexGridSizer* const szr_pp = new wxFlexGridSizer(3, 5, 5); - choice_ppshader = new wxChoice(page_enh, wxID_ANY); - RegisterControl(choice_ppshader, wxGetTranslation(ppshader_desc)); - button_config_pp = new wxButton(page_enh, wxID_ANY, _("Config")); + // Scaled copy, PL, Bilinear filter + szr_enh->Add(CreateCheckBox(page_enh, _("Scaled EFB Copy"), + wxGetTranslation(scaled_efb_copy_desc), vconfig.bCopyEFBScaled)); + szr_enh->Add(CreateCheckBox(page_enh, _("Per-Pixel Lighting"), + wxGetTranslation(pixel_lighting_desc), + vconfig.bEnablePixelLighting)); + szr_enh->Add(CreateCheckBox(page_enh, _("Force Texture Filtering"), + wxGetTranslation(force_filtering_desc), vconfig.bForceFiltering)); + szr_enh->Add(CreateCheckBox(page_enh, _("Widescreen Hack"), wxGetTranslation(ws_hack_desc), + vconfig.bWidescreenHack)); + szr_enh->Add(CreateCheckBox(page_enh, _("Disable Fog"), wxGetTranslation(disable_fog_desc), + vconfig.bDisableFog)); - PopulatePostProcessingShaders(); + wxStaticBoxSizer* const group_enh = + new wxStaticBoxSizer(wxVERTICAL, page_enh, _("Enhancements")); + group_enh->Add(szr_enh, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + szr_enh_main->Add(group_enh, 0, wxEXPAND | wxALL, 5); - choice_ppshader->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_PPShader, this); - button_config_pp->Bind(wxEVT_BUTTON, &VideoConfigDiag::Event_ConfigurePPShader, this); + // - stereoscopy - szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Post-Processing Effect:")), 1, wxALIGN_CENTER_VERTICAL, 0); - szr_pp->Add(choice_ppshader); - szr_pp->Add(button_config_pp); - szr_enh->Add(szr_pp); - } - else - { - choice_ppshader = nullptr; - button_config_pp = nullptr; - } + if (vconfig.backend_info.bSupportsGeometryShaders) + { + wxFlexGridSizer* const szr_stereo = new wxFlexGridSizer(2, 5, 5); - // Scaled copy, PL, Bilinear filter - szr_enh->Add(CreateCheckBox(page_enh, _("Scaled EFB Copy"), wxGetTranslation(scaled_efb_copy_desc), vconfig.bCopyEFBScaled)); - szr_enh->Add(CreateCheckBox(page_enh, _("Per-Pixel Lighting"), wxGetTranslation(pixel_lighting_desc), vconfig.bEnablePixelLighting)); - szr_enh->Add(CreateCheckBox(page_enh, _("Force Texture Filtering"), wxGetTranslation(force_filtering_desc), vconfig.bForceFiltering)); - szr_enh->Add(CreateCheckBox(page_enh, _("Widescreen Hack"), wxGetTranslation(ws_hack_desc), vconfig.bWidescreenHack)); - szr_enh->Add(CreateCheckBox(page_enh, _("Disable Fog"), wxGetTranslation(disable_fog_desc), vconfig.bDisableFog)); + szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Stereoscopic 3D Mode:")), 1, + wxALIGN_CENTER_VERTICAL, 0); - wxStaticBoxSizer* const group_enh = new wxStaticBoxSizer(wxVERTICAL, page_enh, _("Enhancements")); - group_enh->Add(szr_enh, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - szr_enh_main->Add(group_enh, 0, wxEXPAND | wxALL, 5); + const wxString stereo_choices[] = {_("Off"), _("Side-by-Side"), _("Top-and-Bottom"), + _("Anaglyph"), _("Nvidia 3D Vision")}; + wxChoice* stereo_choice = + CreateChoice(page_enh, vconfig.iStereoMode, wxGetTranslation(stereo_3d_desc), + vconfig.backend_info.bSupports3DVision ? ArraySize(stereo_choices) : + ArraySize(stereo_choices) - 1, + stereo_choices); + stereo_choice->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_StereoMode, this); + szr_stereo->Add(stereo_choice); - // - stereoscopy + wxSlider* const sep_slider = new wxSlider(page_enh, wxID_ANY, vconfig.iStereoDepth, 0, 100, + wxDefaultPosition, wxDefaultSize); + sep_slider->Bind(wxEVT_SLIDER, &VideoConfigDiag::Event_StereoDepth, this); + RegisterControl(sep_slider, wxGetTranslation(stereo_depth_desc)); - if (vconfig.backend_info.bSupportsGeometryShaders) - { - wxFlexGridSizer* const szr_stereo = new wxFlexGridSizer(2, 5, 5); + szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Depth:")), 1, wxALIGN_CENTER_VERTICAL, + 0); + szr_stereo->Add(sep_slider, 0, wxEXPAND | wxRIGHT); - szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Stereoscopic 3D Mode:")), 1, wxALIGN_CENTER_VERTICAL, 0); + conv_slider = new wxSlider(page_enh, wxID_ANY, vconfig.iStereoConvergencePercentage, 0, 200, + wxDefaultPosition, wxDefaultSize, wxSL_AUTOTICKS); + conv_slider->ClearTicks(); + conv_slider->SetTick(100); + conv_slider->Bind(wxEVT_SLIDER, &VideoConfigDiag::Event_StereoConvergence, this); + RegisterControl(conv_slider, wxGetTranslation(stereo_convergence_desc)); - const wxString stereo_choices[] = { _("Off"), _("Side-by-Side"), _("Top-and-Bottom"), _("Anaglyph"), _("Nvidia 3D Vision") }; - wxChoice* stereo_choice = CreateChoice(page_enh, vconfig.iStereoMode, wxGetTranslation(stereo_3d_desc), vconfig.backend_info.bSupports3DVision ? ArraySize(stereo_choices) : ArraySize(stereo_choices) - 1, stereo_choices); - stereo_choice->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_StereoMode, this); - szr_stereo->Add(stereo_choice); + szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Convergence:")), 1, + wxALIGN_CENTER_VERTICAL, 0); + szr_stereo->Add(conv_slider, 0, wxEXPAND | wxRIGHT); - wxSlider* const sep_slider = new wxSlider(page_enh, wxID_ANY, vconfig.iStereoDepth, 0, 100, wxDefaultPosition, wxDefaultSize); - sep_slider->Bind(wxEVT_SLIDER, &VideoConfigDiag::Event_StereoDepth, this); - RegisterControl(sep_slider, wxGetTranslation(stereo_depth_desc)); + szr_stereo->Add(CreateCheckBox(page_enh, _("Swap Eyes"), wxGetTranslation(stereo_swap_desc), + vconfig.bStereoSwapEyes)); - szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Depth:")), 1, wxALIGN_CENTER_VERTICAL, 0); - szr_stereo->Add(sep_slider, 0, wxEXPAND | wxRIGHT); + wxStaticBoxSizer* const group_stereo = + new wxStaticBoxSizer(wxVERTICAL, page_enh, _("Stereoscopy")); + group_stereo->Add(szr_stereo, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + szr_enh_main->Add(group_stereo, 0, wxEXPAND | wxALL, 5); + } - conv_slider = new wxSlider(page_enh, wxID_ANY, vconfig.iStereoConvergencePercentage, 0, 200, wxDefaultPosition, wxDefaultSize, wxSL_AUTOTICKS); - conv_slider->ClearTicks(); - conv_slider->SetTick(100); - conv_slider->Bind(wxEVT_SLIDER, &VideoConfigDiag::Event_StereoConvergence, this); - RegisterControl(conv_slider, wxGetTranslation(stereo_convergence_desc)); + szr_enh_main->AddStretchSpacer(); + CreateDescriptionArea(page_enh, szr_enh_main); + page_enh->SetSizerAndFit(szr_enh_main); + } - szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Convergence:")), 1, wxALIGN_CENTER_VERTICAL, 0); - szr_stereo->Add(conv_slider, 0, wxEXPAND | wxRIGHT); + // -- SPEED HACKS -- + { + wxPanel* const page_hacks = new wxPanel(notebook); + notebook->AddPage(page_hacks, _("Hacks")); + wxBoxSizer* const szr_hacks = new wxBoxSizer(wxVERTICAL); - szr_stereo->Add(CreateCheckBox(page_enh, _("Swap Eyes"), wxGetTranslation(stereo_swap_desc), vconfig.bStereoSwapEyes)); + // - EFB hacks + wxStaticBoxSizer* const szr_efb = + new wxStaticBoxSizer(wxVERTICAL, page_hacks, _("Embedded Frame Buffer (EFB)")); - wxStaticBoxSizer* const group_stereo = new wxStaticBoxSizer(wxVERTICAL, page_enh, _("Stereoscopy")); - group_stereo->Add(szr_stereo, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - szr_enh_main->Add(group_stereo, 0, wxEXPAND | wxALL, 5); - } + szr_efb->Add(CreateCheckBox(page_hacks, _("Skip EFB Access from CPU"), + wxGetTranslation(efb_access_desc), vconfig.bEFBAccessEnable, true), + 0, wxBOTTOM | wxLEFT, 5); + szr_efb->Add(CreateCheckBox(page_hacks, _("Ignore Format Changes"), + wxGetTranslation(efb_emulate_format_changes_desc), + vconfig.bEFBEmulateFormatChanges, true), + 0, wxBOTTOM | wxLEFT, 5); + szr_efb->Add(CreateCheckBox(page_hacks, _("Store EFB Copies to Texture Only"), + wxGetTranslation(skip_efb_copy_to_ram_desc), + vconfig.bSkipEFBCopyToRam), + 0, wxBOTTOM | wxLEFT, 5); - szr_enh_main->AddStretchSpacer(); - CreateDescriptionArea(page_enh, szr_enh_main); - page_enh->SetSizerAndFit(szr_enh_main); - } + szr_hacks->Add(szr_efb, 0, wxEXPAND | wxALL, 5); + // Texture cache + { + wxStaticBoxSizer* const szr_safetex = + new wxStaticBoxSizer(wxHORIZONTAL, page_hacks, _("Texture Cache")); - // -- SPEED HACKS -- - { - wxPanel* const page_hacks = new wxPanel(notebook); - notebook->AddPage(page_hacks, _("Hacks")); - wxBoxSizer* const szr_hacks = new wxBoxSizer(wxVERTICAL); + // TODO: Use wxSL_MIN_MAX_LABELS or wxSL_VALUE_LABEL with wx 2.9.1 + wxSlider* const stc_slider = new wxSlider(page_hacks, wxID_ANY, 0, 0, 2, wxDefaultPosition, + wxDefaultSize, wxSL_HORIZONTAL | wxSL_BOTTOM); + stc_slider->Bind(wxEVT_SLIDER, &VideoConfigDiag::Event_Stc, this); + RegisterControl(stc_slider, wxGetTranslation(stc_desc)); - // - EFB hacks - wxStaticBoxSizer* const szr_efb = new wxStaticBoxSizer(wxVERTICAL, page_hacks, _("Embedded Frame Buffer (EFB)")); + if (vconfig.iSafeTextureCache_ColorSamples == 0) + stc_slider->SetValue(0); + else if (vconfig.iSafeTextureCache_ColorSamples == 512) + stc_slider->SetValue(1); + else if (vconfig.iSafeTextureCache_ColorSamples == 128) + stc_slider->SetValue(2); + else + stc_slider->Disable(); // Using custom number of samples; TODO: Inform the user why this is + // disabled.. - szr_efb->Add(CreateCheckBox(page_hacks, _("Skip EFB Access from CPU"), wxGetTranslation(efb_access_desc), vconfig.bEFBAccessEnable, true), 0, wxBOTTOM | wxLEFT, 5); - szr_efb->Add(CreateCheckBox(page_hacks, _("Ignore Format Changes"), wxGetTranslation(efb_emulate_format_changes_desc), vconfig.bEFBEmulateFormatChanges, true), 0, wxBOTTOM | wxLEFT, 5); - szr_efb->Add(CreateCheckBox(page_hacks, _("Store EFB Copies to Texture Only"), wxGetTranslation(skip_efb_copy_to_ram_desc), vconfig.bSkipEFBCopyToRam), 0, wxBOTTOM | wxLEFT, 5); + szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, _("Accuracy:")), 0, wxALL, 5); + szr_safetex->AddStretchSpacer(1); + szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, _("Safe")), 0, + wxLEFT | wxTOP | wxBOTTOM, 5); + szr_safetex->Add(stc_slider, 2, wxRIGHT, 0); + szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, _("Fast")), 0, + wxRIGHT | wxTOP | wxBOTTOM, 5); + szr_hacks->Add(szr_safetex, 0, wxEXPAND | wxALL, 5); + } - szr_hacks->Add(szr_efb, 0, wxEXPAND | wxALL, 5); + // - XFB + { + wxStaticBoxSizer* const group_xfb = + new wxStaticBoxSizer(wxHORIZONTAL, page_hacks, _("External Frame Buffer (XFB)")); - // Texture cache - { - wxStaticBoxSizer* const szr_safetex = new wxStaticBoxSizer(wxHORIZONTAL, page_hacks, _("Texture Cache")); + SettingCheckBox* disable_xfb = CreateCheckBox( + page_hacks, _("Disable"), wxGetTranslation(xfb_desc), vconfig.bUseXFB, true); + virtual_xfb = CreateRadioButton(page_hacks, _("Virtual"), wxGetTranslation(xfb_virtual_desc), + vconfig.bUseRealXFB, true, wxRB_GROUP); + real_xfb = CreateRadioButton(page_hacks, _("Real"), wxGetTranslation(xfb_real_desc), + vconfig.bUseRealXFB); - // TODO: Use wxSL_MIN_MAX_LABELS or wxSL_VALUE_LABEL with wx 2.9.1 - wxSlider* const stc_slider = new wxSlider(page_hacks, wxID_ANY, 0, 0, 2, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL|wxSL_BOTTOM); - stc_slider->Bind(wxEVT_SLIDER, &VideoConfigDiag::Event_Stc, this); - RegisterControl(stc_slider, wxGetTranslation(stc_desc)); + group_xfb->Add(disable_xfb, 0, wxLEFT | wxRIGHT | wxBOTTOM, 5); + group_xfb->AddStretchSpacer(1); + group_xfb->Add(virtual_xfb, 0, wxRIGHT, 5); + group_xfb->Add(real_xfb, 0, wxRIGHT, 5); + szr_hacks->Add(group_xfb, 0, wxEXPAND | wxALL, 5); + } // xfb - if (vconfig.iSafeTextureCache_ColorSamples == 0) stc_slider->SetValue(0); - else if (vconfig.iSafeTextureCache_ColorSamples == 512) stc_slider->SetValue(1); - else if (vconfig.iSafeTextureCache_ColorSamples == 128) stc_slider->SetValue(2); - else stc_slider->Disable(); // Using custom number of samples; TODO: Inform the user why this is disabled.. + // - other hacks + { + wxGridSizer* const szr_other = new wxGridSizer(2, 5, 5); + szr_other->Add(CreateCheckBox(page_hacks, _("Fast Depth Calculation"), + wxGetTranslation(fast_depth_calc_desc), + vconfig.bFastDepthCalc)); + szr_other->Add(CreateCheckBox(page_hacks, _("Disable Bounding Box"), + wxGetTranslation(disable_bbox_desc), vconfig.bBBoxEnable, + true)); - szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, _("Accuracy:")), 0, wxALL, 5); - szr_safetex->AddStretchSpacer(1); - szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, _("Safe")), 0, wxLEFT|wxTOP|wxBOTTOM, 5); - szr_safetex->Add(stc_slider, 2, wxRIGHT, 0); - szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, _("Fast")), 0, wxRIGHT|wxTOP|wxBOTTOM, 5); - szr_hacks->Add(szr_safetex, 0, wxEXPAND | wxALL, 5); - } + wxStaticBoxSizer* const group_other = + new wxStaticBoxSizer(wxVERTICAL, page_hacks, _("Other")); + group_other->Add(szr_other, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + szr_hacks->Add(group_other, 0, wxEXPAND | wxALL, 5); + } - // - XFB - { - wxStaticBoxSizer* const group_xfb = new wxStaticBoxSizer(wxHORIZONTAL, page_hacks, _("External Frame Buffer (XFB)")); + szr_hacks->AddStretchSpacer(); + CreateDescriptionArea(page_hacks, szr_hacks); + page_hacks->SetSizerAndFit(szr_hacks); + } - SettingCheckBox* disable_xfb = CreateCheckBox(page_hacks, _("Disable"), wxGetTranslation(xfb_desc), vconfig.bUseXFB, true); - virtual_xfb = CreateRadioButton(page_hacks, _("Virtual"), wxGetTranslation(xfb_virtual_desc), vconfig.bUseRealXFB, true, wxRB_GROUP); - real_xfb = CreateRadioButton(page_hacks, _("Real"), wxGetTranslation(xfb_real_desc), vconfig.bUseRealXFB); + // -- ADVANCED -- + { + wxPanel* const page_advanced = new wxPanel(notebook); + notebook->AddPage(page_advanced, _("Advanced")); + wxBoxSizer* const szr_advanced = new wxBoxSizer(wxVERTICAL); - group_xfb->Add(disable_xfb, 0, wxLEFT | wxRIGHT | wxBOTTOM, 5); - group_xfb->AddStretchSpacer(1); - group_xfb->Add(virtual_xfb, 0, wxRIGHT, 5); - group_xfb->Add(real_xfb, 0, wxRIGHT, 5); - szr_hacks->Add(group_xfb, 0, wxEXPAND | wxALL, 5); - } // xfb + // - debug + { + wxGridSizer* const szr_debug = new wxGridSizer(2, 5, 5); - // - other hacks - { - wxGridSizer* const szr_other = new wxGridSizer(2, 5, 5); - szr_other->Add(CreateCheckBox(page_hacks, _("Fast Depth Calculation"), wxGetTranslation(fast_depth_calc_desc), vconfig.bFastDepthCalc)); - szr_other->Add(CreateCheckBox(page_hacks, _("Disable Bounding Box"), wxGetTranslation(disable_bbox_desc), vconfig.bBBoxEnable, true)); + szr_debug->Add(CreateCheckBox(page_advanced, _("Enable Wireframe"), + wxGetTranslation(wireframe_desc), vconfig.bWireFrame)); + szr_debug->Add(CreateCheckBox(page_advanced, _("Show Statistics"), + wxGetTranslation(show_stats_desc), vconfig.bOverlayStats)); + szr_debug->Add(CreateCheckBox(page_advanced, _("Texture Format Overlay"), + wxGetTranslation(texfmt_desc), vconfig.bTexFmtOverlayEnable)); - wxStaticBoxSizer* const group_other = new wxStaticBoxSizer(wxVERTICAL, page_hacks, _("Other")); - group_other->Add(szr_other, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - szr_hacks->Add(group_other, 0, wxEXPAND | wxALL, 5); - } + wxStaticBoxSizer* const group_debug = + new wxStaticBoxSizer(wxVERTICAL, page_advanced, _("Debugging")); + szr_advanced->Add(group_debug, 0, wxEXPAND | wxALL, 5); + group_debug->Add(szr_debug, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + } - szr_hacks->AddStretchSpacer(); - CreateDescriptionArea(page_hacks, szr_hacks); - page_hacks->SetSizerAndFit(szr_hacks); - } + // - utility + { + wxGridSizer* const szr_utility = new wxGridSizer(2, 5, 5); - // -- ADVANCED -- - { - wxPanel* const page_advanced = new wxPanel(notebook); - notebook->AddPage(page_advanced, _("Advanced")); - wxBoxSizer* const szr_advanced = new wxBoxSizer(wxVERTICAL); - - // - debug - { - wxGridSizer* const szr_debug = new wxGridSizer(2, 5, 5); - - szr_debug->Add(CreateCheckBox(page_advanced, _("Enable Wireframe"), wxGetTranslation(wireframe_desc), vconfig.bWireFrame)); - szr_debug->Add(CreateCheckBox(page_advanced, _("Show Statistics"), wxGetTranslation(show_stats_desc), vconfig.bOverlayStats)); - szr_debug->Add(CreateCheckBox(page_advanced, _("Texture Format Overlay"), wxGetTranslation(texfmt_desc), vconfig.bTexFmtOverlayEnable)); - - wxStaticBoxSizer* const group_debug = new wxStaticBoxSizer(wxVERTICAL, page_advanced, _("Debugging")); - szr_advanced->Add(group_debug, 0, wxEXPAND | wxALL, 5); - group_debug->Add(szr_debug, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - } - - // - utility - { - wxGridSizer* const szr_utility = new wxGridSizer(2, 5, 5); - - szr_utility->Add(CreateCheckBox(page_advanced, _("Dump Textures"), wxGetTranslation(dump_textures_desc), vconfig.bDumpTextures)); - szr_utility->Add(CreateCheckBox(page_advanced, _("Load Custom Textures"), wxGetTranslation(load_hires_textures_desc), vconfig.bHiresTextures)); - cache_hires_textures = CreateCheckBox(page_advanced, _("Prefetch Custom Textures"), wxGetTranslation(cache_hires_textures_desc), vconfig.bCacheHiresTextures); - szr_utility->Add(cache_hires_textures); - szr_utility->Add(CreateCheckBox(page_advanced, _("Dump EFB Target"), wxGetTranslation(dump_efb_desc), vconfig.bDumpEFBTarget)); - szr_utility->Add(CreateCheckBox(page_advanced, _("Free Look"), wxGetTranslation(free_look_desc), vconfig.bFreeLook)); -#if defined(HAVE_LIBAV) || defined (_WIN32) - szr_utility->Add(CreateCheckBox(page_advanced, _("Frame Dumps use FFV1"), wxGetTranslation(use_ffv1_desc), vconfig.bUseFFV1)); + szr_utility->Add(CreateCheckBox(page_advanced, _("Dump Textures"), + wxGetTranslation(dump_textures_desc), vconfig.bDumpTextures)); + szr_utility->Add(CreateCheckBox(page_advanced, _("Load Custom Textures"), + wxGetTranslation(load_hires_textures_desc), + vconfig.bHiresTextures)); + cache_hires_textures = + CreateCheckBox(page_advanced, _("Prefetch Custom Textures"), + wxGetTranslation(cache_hires_textures_desc), vconfig.bCacheHiresTextures); + szr_utility->Add(cache_hires_textures); + szr_utility->Add(CreateCheckBox(page_advanced, _("Dump EFB Target"), + wxGetTranslation(dump_efb_desc), vconfig.bDumpEFBTarget)); + szr_utility->Add(CreateCheckBox(page_advanced, _("Free Look"), + wxGetTranslation(free_look_desc), vconfig.bFreeLook)); +#if defined(HAVE_LIBAV) || defined(_WIN32) + szr_utility->Add(CreateCheckBox(page_advanced, _("Frame Dumps use FFV1"), + wxGetTranslation(use_ffv1_desc), vconfig.bUseFFV1)); #endif - wxStaticBoxSizer* const group_utility = new wxStaticBoxSizer(wxVERTICAL, page_advanced, _("Utility")); - szr_advanced->Add(group_utility, 0, wxEXPAND | wxALL, 5); - group_utility->Add(szr_utility, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - } + wxStaticBoxSizer* const group_utility = + new wxStaticBoxSizer(wxVERTICAL, page_advanced, _("Utility")); + szr_advanced->Add(group_utility, 0, wxEXPAND | wxALL, 5); + group_utility->Add(szr_utility, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + } - // - misc - { - wxGridSizer* const szr_misc = new wxGridSizer(2, 5, 5); + // - misc + { + wxGridSizer* const szr_misc = new wxGridSizer(2, 5, 5); - szr_misc->Add(CreateCheckBox(page_advanced, _("Crop"), wxGetTranslation(crop_desc), vconfig.bCrop)); + szr_misc->Add( + CreateCheckBox(page_advanced, _("Crop"), wxGetTranslation(crop_desc), vconfig.bCrop)); - // Progressive Scan - { - progressive_scan_checkbox = new wxCheckBox(page_advanced, wxID_ANY, _("Enable Progressive Scan")); - RegisterControl(progressive_scan_checkbox, wxGetTranslation(prog_scan_desc)); - progressive_scan_checkbox->Bind(wxEVT_CHECKBOX, &VideoConfigDiag::Event_ProgressiveScan, this); + // Progressive Scan + { + progressive_scan_checkbox = + new wxCheckBox(page_advanced, wxID_ANY, _("Enable Progressive Scan")); + RegisterControl(progressive_scan_checkbox, wxGetTranslation(prog_scan_desc)); + progressive_scan_checkbox->Bind(wxEVT_CHECKBOX, &VideoConfigDiag::Event_ProgressiveScan, + this); - progressive_scan_checkbox->SetValue(SConfig::GetInstance().bProgressive); - // A bit strange behavior, but this needs to stay in sync with the main progressive boolean; TODO: Is this still necessary? - SConfig::GetInstance().m_SYSCONF->SetData("IPL.PGS", SConfig::GetInstance().bProgressive); + progressive_scan_checkbox->SetValue(SConfig::GetInstance().bProgressive); + // A bit strange behavior, but this needs to stay in sync with the main progressive boolean; + // TODO: Is this still necessary? + SConfig::GetInstance().m_SYSCONF->SetData("IPL.PGS", SConfig::GetInstance().bProgressive); - szr_misc->Add(progressive_scan_checkbox); - } + szr_misc->Add(progressive_scan_checkbox); + } #if defined WIN32 - // Borderless Fullscreen - borderless_fullscreen = CreateCheckBox(page_advanced, _("Borderless Fullscreen"), wxGetTranslation(borderless_fullscreen_desc), vconfig.bBorderlessFullscreen); - szr_misc->Add(borderless_fullscreen); + // Borderless Fullscreen + borderless_fullscreen = CreateCheckBox(page_advanced, _("Borderless Fullscreen"), + wxGetTranslation(borderless_fullscreen_desc), + vconfig.bBorderlessFullscreen); + szr_misc->Add(borderless_fullscreen); #endif - wxStaticBoxSizer* const group_misc = new wxStaticBoxSizer(wxVERTICAL, page_advanced, _("Misc")); - szr_advanced->Add(group_misc, 0, wxEXPAND | wxALL, 5); - group_misc->Add(szr_misc, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - } + wxStaticBoxSizer* const group_misc = + new wxStaticBoxSizer(wxVERTICAL, page_advanced, _("Misc")); + szr_advanced->Add(group_misc, 0, wxEXPAND | wxALL, 5); + group_misc->Add(szr_misc, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + } - szr_advanced->AddStretchSpacer(); - CreateDescriptionArea(page_advanced, szr_advanced); - page_advanced->SetSizerAndFit(szr_advanced); - } + szr_advanced->AddStretchSpacer(); + CreateDescriptionArea(page_advanced, szr_advanced); + page_advanced->SetSizerAndFit(szr_advanced); + } - wxButton* const btn_close = new wxButton(this, wxID_OK, _("Close")); - btn_close->Bind(wxEVT_BUTTON, &VideoConfigDiag::Event_ClickClose, this); + wxButton* const btn_close = new wxButton(this, wxID_OK, _("Close")); + btn_close->Bind(wxEVT_BUTTON, &VideoConfigDiag::Event_ClickClose, this); - Bind(wxEVT_CLOSE_WINDOW, &VideoConfigDiag::Event_Close, this); + Bind(wxEVT_CLOSE_WINDOW, &VideoConfigDiag::Event_Close, this); - wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL); - szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5); - szr_main->Add(btn_close, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5); + wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL); + szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5); + szr_main->Add(btn_close, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5); - SetSizerAndFit(szr_main); - Center(); - SetFocus(); + SetSizerAndFit(szr_main); + Center(); + SetFocus(); - UpdateWindowUI(); + UpdateWindowUI(); } -void VideoConfigDiag::Event_DisplayResolution(wxCommandEvent &ev) +void VideoConfigDiag::Event_DisplayResolution(wxCommandEvent& ev) { - SConfig::GetInstance().strFullscreenResolution = - WxStrToStr(choice_display_resolution->GetStringSelection()); + SConfig::GetInstance().strFullscreenResolution = + WxStrToStr(choice_display_resolution->GetStringSelection()); #if defined(HAVE_XRANDR) && HAVE_XRANDR - main_frame->m_XRRConfig->Update(); + main_frame->m_XRRConfig->Update(); #endif - ev.Skip(); + ev.Skip(); } -SettingCheckBox* VideoConfigDiag::CreateCheckBox(wxWindow* parent, const wxString& label, const wxString& description, bool &setting, bool reverse, long style) +SettingCheckBox* VideoConfigDiag::CreateCheckBox(wxWindow* parent, const wxString& label, + const wxString& description, bool& setting, + bool reverse, long style) { - SettingCheckBox* const cb = new SettingCheckBox(parent, label, wxString(), setting, reverse, style); - RegisterControl(cb, description); - return cb; + SettingCheckBox* const cb = + new SettingCheckBox(parent, label, wxString(), setting, reverse, style); + RegisterControl(cb, description); + return cb; } -SettingChoice* VideoConfigDiag::CreateChoice(wxWindow* parent, int& setting, const wxString& description, int num, const wxString choices[], long style) +SettingChoice* VideoConfigDiag::CreateChoice(wxWindow* parent, int& setting, + const wxString& description, int num, + const wxString choices[], long style) { - SettingChoice* const ch = new SettingChoice(parent, setting, wxString(), num, choices, style); - RegisterControl(ch, description); - return ch; + SettingChoice* const ch = new SettingChoice(parent, setting, wxString(), num, choices, style); + RegisterControl(ch, description); + return ch; } -SettingRadioButton* VideoConfigDiag::CreateRadioButton(wxWindow* parent, const wxString& label, const wxString& description, bool &setting, bool reverse, long style) +SettingRadioButton* VideoConfigDiag::CreateRadioButton(wxWindow* parent, const wxString& label, + const wxString& description, bool& setting, + bool reverse, long style) { - SettingRadioButton* const rb = new SettingRadioButton(parent, label, wxString(), setting, reverse, style); - RegisterControl(rb, description); - return rb; + SettingRadioButton* const rb = + new SettingRadioButton(parent, label, wxString(), setting, reverse, style); + RegisterControl(rb, description); + return rb; } -/* Use this to register descriptions for controls which have NOT been created using the Create* functions from above */ +/* Use this to register descriptions for controls which have NOT been created using the Create* + * functions from above */ wxControl* VideoConfigDiag::RegisterControl(wxControl* const control, const wxString& description) { - ctrl_descs.emplace(control, description); - control->Bind(wxEVT_ENTER_WINDOW, &VideoConfigDiag::Evt_EnterControl, this); - control->Bind(wxEVT_LEAVE_WINDOW, &VideoConfigDiag::Evt_LeaveControl, this); - return control; + ctrl_descs.emplace(control, description); + control->Bind(wxEVT_ENTER_WINDOW, &VideoConfigDiag::Evt_EnterControl, this); + control->Bind(wxEVT_LEAVE_WINDOW, &VideoConfigDiag::Evt_LeaveControl, this); + return control; } void VideoConfigDiag::Evt_EnterControl(wxMouseEvent& ev) { - // TODO: Re-Fit the sizer if necessary! + // TODO: Re-Fit the sizer if necessary! - // Get settings control object from event - wxWindow* ctrl = (wxWindow*)ev.GetEventObject(); - if (!ctrl) return; + // Get settings control object from event + wxWindow* ctrl = (wxWindow*)ev.GetEventObject(); + if (!ctrl) + return; - // look up description text object from the control's parent (which is the wxPanel of the current tab) - wxStaticText* descr_text = desc_texts[ctrl->GetParent()]; - if (!descr_text) return; + // look up description text object from the control's parent (which is the wxPanel of the current + // tab) + wxStaticText* descr_text = desc_texts[ctrl->GetParent()]; + if (!descr_text) + return; - // look up the description of the selected control and assign it to the current description text object's label - descr_text->SetLabel(ctrl_descs[ctrl]); - descr_text->Wrap(descr_text->GetContainingSizer()->GetSize().x - 20); + // look up the description of the selected control and assign it to the current description text + // object's label + descr_text->SetLabel(ctrl_descs[ctrl]); + descr_text->Wrap(descr_text->GetContainingSizer()->GetSize().x - 20); - ev.Skip(); + ev.Skip(); } // TODO: Don't hardcode the size of the description area via line breaks -#define DEFAULT_DESC_TEXT _("Move the mouse pointer over an option to display a detailed description.\n\n\n\n\n\n\n") +#define DEFAULT_DESC_TEXT \ + _("Move the mouse pointer over an option to display a detailed description.\n\n\n\n\n\n\n") void VideoConfigDiag::Evt_LeaveControl(wxMouseEvent& ev) { - // look up description text control and reset its label - wxWindow* ctrl = (wxWindow*)ev.GetEventObject(); - if (!ctrl) return; - wxStaticText* descr_text = desc_texts[ctrl->GetParent()]; - if (!descr_text) return; + // look up description text control and reset its label + wxWindow* ctrl = (wxWindow*)ev.GetEventObject(); + if (!ctrl) + return; + wxStaticText* descr_text = desc_texts[ctrl->GetParent()]; + if (!descr_text) + return; - descr_text->SetLabel(DEFAULT_DESC_TEXT); - descr_text->Wrap(descr_text->GetContainingSizer()->GetSize().x - 20); - ev.Skip(); + descr_text->SetLabel(DEFAULT_DESC_TEXT); + descr_text->Wrap(descr_text->GetContainingSizer()->GetSize().x - 20); + ev.Skip(); } void VideoConfigDiag::CreateDescriptionArea(wxPanel* const page, wxBoxSizer* const sizer) { - // Create description frame - wxStaticBoxSizer* const desc_sizer = new wxStaticBoxSizer(wxVERTICAL, page, _("Description")); - sizer->Add(desc_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + // Create description frame + wxStaticBoxSizer* const desc_sizer = new wxStaticBoxSizer(wxVERTICAL, page, _("Description")); + sizer->Add(desc_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - // Need to call SetSizerAndFit here, since we don't want the description texts to change the dialog width - page->SetSizerAndFit(sizer); + // Need to call SetSizerAndFit here, since we don't want the description texts to change the + // dialog width + page->SetSizerAndFit(sizer); - // Create description text - wxStaticText* const desc_text = new wxStaticText(page, wxID_ANY, DEFAULT_DESC_TEXT); - desc_text->Wrap(desc_sizer->GetSize().x - 20); - desc_sizer->Add(desc_text, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + // Create description text + wxStaticText* const desc_text = new wxStaticText(page, wxID_ANY, DEFAULT_DESC_TEXT); + desc_text->Wrap(desc_sizer->GetSize().x - 20); + desc_sizer->Add(desc_text, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - // Store description text object for later lookup - desc_texts.emplace(page, desc_text); + // Store description text object for later lookup + desc_texts.emplace(page, desc_text); } void VideoConfigDiag::PopulatePostProcessingShaders() { - std::vector &shaders = (vconfig.iStereoMode == STEREO_ANAGLYPH) ? - vconfig.backend_info.AnaglyphShaders : vconfig.backend_info.PPShaders; + std::vector& shaders = (vconfig.iStereoMode == STEREO_ANAGLYPH) ? + vconfig.backend_info.AnaglyphShaders : + vconfig.backend_info.PPShaders; - if (shaders.empty()) - return; + if (shaders.empty()) + return; - choice_ppshader->AppendString(_("(off)")); + choice_ppshader->AppendString(_("(off)")); - for (const std::string& shader : shaders) - { - choice_ppshader->AppendString(StrToWxStr(shader)); - } + for (const std::string& shader : shaders) + { + choice_ppshader->AppendString(StrToWxStr(shader)); + } - if (!choice_ppshader->SetStringSelection(StrToWxStr(vconfig.sPostProcessingShader))) - { - // Invalid shader, reset it to default - choice_ppshader->Select(0); + if (!choice_ppshader->SetStringSelection(StrToWxStr(vconfig.sPostProcessingShader))) + { + // Invalid shader, reset it to default + choice_ppshader->Select(0); - if (vconfig.iStereoMode == STEREO_ANAGLYPH) - { - vconfig.sPostProcessingShader = "dubois"; - choice_ppshader->SetStringSelection(StrToWxStr(vconfig.sPostProcessingShader)); - } - else - vconfig.sPostProcessingShader.clear(); - } + if (vconfig.iStereoMode == STEREO_ANAGLYPH) + { + vconfig.sPostProcessingShader = "dubois"; + choice_ppshader->SetStringSelection(StrToWxStr(vconfig.sPostProcessingShader)); + } + else + vconfig.sPostProcessingShader.clear(); + } - // Should the configuration button be loaded by default? - PostProcessingShaderConfiguration postprocessing_shader; - postprocessing_shader.LoadShader(vconfig.sPostProcessingShader); - button_config_pp->Enable(postprocessing_shader.HasOptions()); + // Should the configuration button be loaded by default? + PostProcessingShaderConfiguration postprocessing_shader; + postprocessing_shader.LoadShader(vconfig.sPostProcessingShader); + button_config_pp->Enable(postprocessing_shader.HasOptions()); } void VideoConfigDiag::PopulateAAList() { - const std::vector& aa_modes = vconfig.backend_info.AAModes; - const bool supports_ssaa = vconfig.backend_info.bSupportsSSAA; - m_msaa_modes = 0; + const std::vector& aa_modes = vconfig.backend_info.AAModes; + const bool supports_ssaa = vconfig.backend_info.bSupportsSSAA; + m_msaa_modes = 0; - for (int mode : aa_modes) - { - if (mode == 1) - { - choice_aamode->AppendString(_("None")); - _assert_msg_(VIDEO, !supports_ssaa || m_msaa_modes == 0, "SSAA setting won't work correctly"); - } - else - { - choice_aamode->AppendString(std::to_string(mode) + "x MSAA"); - ++m_msaa_modes; - } - } + for (int mode : aa_modes) + { + if (mode == 1) + { + choice_aamode->AppendString(_("None")); + _assert_msg_(VIDEO, !supports_ssaa || m_msaa_modes == 0, "SSAA setting won't work correctly"); + } + else + { + choice_aamode->AppendString(std::to_string(mode) + "x MSAA"); + ++m_msaa_modes; + } + } - if (supports_ssaa) - { - for (int mode : aa_modes) - { - if (mode != 1) - choice_aamode->AppendString(std::to_string(mode) + "x SSAA"); - } - } + if (supports_ssaa) + { + for (int mode : aa_modes) + { + if (mode != 1) + choice_aamode->AppendString(std::to_string(mode) + "x SSAA"); + } + } - int selected_mode_index = 0; + int selected_mode_index = 0; - auto index = std::find(aa_modes.begin(), aa_modes.end(), vconfig.iMultisamples); - if (index != aa_modes.end()) - selected_mode_index = index - aa_modes.begin(); + auto index = std::find(aa_modes.begin(), aa_modes.end(), vconfig.iMultisamples); + if (index != aa_modes.end()) + selected_mode_index = index - aa_modes.begin(); - // Select one of the SSAA modes at the end of the list if SSAA is enabled - if (supports_ssaa && vconfig.bSSAA && aa_modes[selected_mode_index] != 1) - selected_mode_index += m_msaa_modes; + // Select one of the SSAA modes at the end of the list if SSAA is enabled + if (supports_ssaa && vconfig.bSSAA && aa_modes[selected_mode_index] != 1) + selected_mode_index += m_msaa_modes; - choice_aamode->SetSelection(selected_mode_index); + choice_aamode->SetSelection(selected_mode_index); } void VideoConfigDiag::OnAAChanged(wxCommandEvent& ev) { - size_t mode = ev.GetInt(); - ev.Skip(); + size_t mode = ev.GetInt(); + ev.Skip(); - vconfig.bSSAA = mode > m_msaa_modes; - mode -= vconfig.bSSAA * m_msaa_modes; + vconfig.bSSAA = mode > m_msaa_modes; + mode -= vconfig.bSSAA * m_msaa_modes; - if (mode >= vconfig.backend_info.AAModes.size()) - return; + if (mode >= vconfig.backend_info.AAModes.size()) + return; - vconfig.iMultisamples = vconfig.backend_info.AAModes[mode]; + vconfig.iMultisamples = vconfig.backend_info.AAModes[mode]; } diff --git a/Source/Core/DolphinWX/VideoConfigDiag.h b/Source/Core/DolphinWX/VideoConfigDiag.h index 601dcb16b0..b6d0f2c515 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.h +++ b/Source/Core/DolphinWX/VideoConfigDiag.h @@ -35,16 +35,18 @@ template class BoolSetting : public W { public: - BoolSetting(wxWindow* parent, const wxString& label, const wxString& tooltip, bool &setting, bool reverse = false, long style = 0); + BoolSetting(wxWindow* parent, const wxString& label, const wxString& tooltip, bool& setting, + bool reverse = false, long style = 0); + + void UpdateValue(wxCommandEvent& ev) + { + m_setting = (ev.GetInt() != 0) ^ m_reverse; + ev.Skip(); + } - void UpdateValue(wxCommandEvent& ev) - { - m_setting = (ev.GetInt() != 0) ^ m_reverse; - ev.Skip(); - } private: - bool &m_setting; - const bool m_reverse; + bool& m_setting; + const bool m_reverse; }; typedef BoolSetting SettingCheckBox; @@ -54,234 +56,248 @@ template class IntegerSetting : public wxSpinCtrl { public: - IntegerSetting(wxWindow* parent, const wxString& label, T& setting, int minVal, int maxVal, long style = 0); + IntegerSetting(wxWindow* parent, const wxString& label, T& setting, int minVal, int maxVal, + long style = 0); + + void UpdateValue(wxCommandEvent& ev) + { + m_setting = ev.GetInt(); + ev.Skip(); + } - void UpdateValue(wxCommandEvent& ev) - { - m_setting = ev.GetInt(); - ev.Skip(); - } private: - T& m_setting; + T& m_setting; }; class SettingChoice : public wxChoice { public: - SettingChoice(wxWindow* parent, int &setting, const wxString& tooltip, int num = 0, const wxString choices[] = nullptr, long style = 0); - void UpdateValue(wxCommandEvent& ev); + SettingChoice(wxWindow* parent, int& setting, const wxString& tooltip, int num = 0, + const wxString choices[] = nullptr, long style = 0); + void UpdateValue(wxCommandEvent& ev); + private: - int &m_setting; + int& m_setting; }; class VideoConfigDiag : public wxDialog { public: - VideoConfigDiag(wxWindow* parent, const std::string &title, const std::string& ininame); + VideoConfigDiag(wxWindow* parent, const std::string& title, const std::string& ininame); protected: - void Event_Backend(wxCommandEvent &ev) - { - auto& new_backend = g_available_video_backends[ev.GetInt()]; + void Event_Backend(wxCommandEvent& ev) + { + auto& new_backend = g_available_video_backends[ev.GetInt()]; - if (g_video_backend != new_backend.get()) - { - bool do_switch = !Core::IsRunning(); - if (new_backend->GetName() == "Software Renderer") - { - do_switch = (wxYES == wxMessageBox(_("Software rendering is an order of magnitude slower than using the other backends.\nIt's only useful for debugging purposes.\nDo you really want to enable software rendering? If unsure, select 'No'."), - _("Warning"), wxYES_NO | wxNO_DEFAULT | wxICON_EXCLAMATION, wxWindow::FindFocus())); - } + if (g_video_backend != new_backend.get()) + { + bool do_switch = !Core::IsRunning(); + if (new_backend->GetName() == "Software Renderer") + { + do_switch = + (wxYES == + wxMessageBox(_("Software rendering is an order of magnitude slower than using the " + "other backends.\nIt's only useful for debugging purposes.\nDo you " + "really want to enable software rendering? If unsure, select 'No'."), + _("Warning"), wxYES_NO | wxNO_DEFAULT | wxICON_EXCLAMATION, + wxWindow::FindFocus())); + } - if (do_switch) - { - // TODO: Only reopen the dialog if the software backend is - // selected (make sure to reinitialize backend info) - // reopen the dialog - Close(); + if (do_switch) + { + // TODO: Only reopen the dialog if the software backend is + // selected (make sure to reinitialize backend info) + // reopen the dialog + Close(); - g_video_backend = new_backend.get(); - SConfig::GetInstance().m_strVideoBackend = g_video_backend->GetName(); + g_video_backend = new_backend.get(); + SConfig::GetInstance().m_strVideoBackend = g_video_backend->GetName(); - g_video_backend->ShowConfig(GetParent()); - } - else - { - // Select current backend again - choice_backend->SetStringSelection(StrToWxStr(g_video_backend->GetName())); - } - } + g_video_backend->ShowConfig(GetParent()); + } + else + { + // Select current backend again + choice_backend->SetStringSelection(StrToWxStr(g_video_backend->GetName())); + } + } - ev.Skip(); - } - void Event_Adapter(wxCommandEvent &ev) { ev.Skip(); } // TODO + ev.Skip(); + } + void Event_Adapter(wxCommandEvent& ev) { ev.Skip(); } // TODO + void Event_DisplayResolution(wxCommandEvent& ev); - void Event_DisplayResolution(wxCommandEvent &ev); + void Event_ProgressiveScan(wxCommandEvent& ev) + { + SConfig::GetInstance().m_SYSCONF->SetData("IPL.PGS", ev.GetInt()); + SConfig::GetInstance().bProgressive = ev.IsChecked(); - void Event_ProgressiveScan(wxCommandEvent &ev) - { - SConfig::GetInstance().m_SYSCONF->SetData("IPL.PGS", ev.GetInt()); - SConfig::GetInstance().bProgressive = ev.IsChecked(); + ev.Skip(); + } - ev.Skip(); - } + void Event_Stc(wxCommandEvent& ev) + { + int samples[] = {0, 512, 128}; + vconfig.iSafeTextureCache_ColorSamples = samples[ev.GetInt()]; - void Event_Stc(wxCommandEvent &ev) - { - int samples[] = { 0, 512, 128 }; - vconfig.iSafeTextureCache_ColorSamples = samples[ev.GetInt()]; + ev.Skip(); + } - ev.Skip(); - } + void Event_PPShader(wxCommandEvent& ev) + { + const int sel = ev.GetInt(); + if (sel) + vconfig.sPostProcessingShader = WxStrToStr(ev.GetString()); + else + vconfig.sPostProcessingShader.clear(); - void Event_PPShader(wxCommandEvent &ev) - { - const int sel = ev.GetInt(); - if (sel) - vconfig.sPostProcessingShader = WxStrToStr(ev.GetString()); - else - vconfig.sPostProcessingShader.clear(); + // Should we enable the configuration button? + PostProcessingShaderConfiguration postprocessing_shader; + postprocessing_shader.LoadShader(vconfig.sPostProcessingShader); + button_config_pp->Enable(postprocessing_shader.HasOptions()); - // Should we enable the configuration button? - PostProcessingShaderConfiguration postprocessing_shader; - postprocessing_shader.LoadShader(vconfig.sPostProcessingShader); - button_config_pp->Enable(postprocessing_shader.HasOptions()); + ev.Skip(); + } - ev.Skip(); - } + void Event_ConfigurePPShader(wxCommandEvent& ev) + { + PostProcessingConfigDiag dialog(this, vconfig.sPostProcessingShader); + dialog.ShowModal(); - void Event_ConfigurePPShader(wxCommandEvent &ev) - { - PostProcessingConfigDiag dialog(this, vconfig.sPostProcessingShader); - dialog.ShowModal(); + ev.Skip(); + } - ev.Skip(); - } + void Event_StereoDepth(wxCommandEvent& ev) + { + vconfig.iStereoDepth = ev.GetInt(); - void Event_StereoDepth(wxCommandEvent &ev) - { - vconfig.iStereoDepth = ev.GetInt(); + ev.Skip(); + } - ev.Skip(); - } + void Event_StereoConvergence(wxCommandEvent& ev) + { + // Snap the slider + int value = ev.GetInt(); + if (90 < value && value < 110) + conv_slider->SetValue(100); - void Event_StereoConvergence(wxCommandEvent &ev) - { - // Snap the slider - int value = ev.GetInt(); - if (90 < value && value < 110) - conv_slider->SetValue(100); + vconfig.iStereoConvergencePercentage = conv_slider->GetValue(); - vconfig.iStereoConvergencePercentage = conv_slider->GetValue(); + ev.Skip(); + } - ev.Skip(); - } + void Event_StereoMode(wxCommandEvent& ev) + { + if (vconfig.backend_info.bSupportsPostProcessing) + { + // Anaglyph overrides post-processing shaders + choice_ppshader->Clear(); + } - void Event_StereoMode(wxCommandEvent &ev) - { - if (vconfig.backend_info.bSupportsPostProcessing) - { - // Anaglyph overrides post-processing shaders - choice_ppshader->Clear(); - } + ev.Skip(); + } - ev.Skip(); - } + void Event_ClickClose(wxCommandEvent&); + void Event_Close(wxCloseEvent&); - void Event_ClickClose(wxCommandEvent&); - void Event_Close(wxCloseEvent&); + // Enables/disables UI elements depending on current config + void OnUpdateUI(wxUpdateUIEvent& ev) + { + // Anti-aliasing + choice_aamode->Enable(vconfig.backend_info.AAModes.size() > 1); + text_aamode->Enable(vconfig.backend_info.AAModes.size() > 1); - // Enables/disables UI elements depending on current config - void OnUpdateUI(wxUpdateUIEvent& ev) - { - // Anti-aliasing - choice_aamode->Enable(vconfig.backend_info.AAModes.size() > 1); - text_aamode->Enable(vconfig.backend_info.AAModes.size() > 1); + // XFB + virtual_xfb->Enable(vconfig.bUseXFB); + real_xfb->Enable(vconfig.bUseXFB); + // custom textures + cache_hires_textures->Enable(vconfig.bHiresTextures); - // XFB - virtual_xfb->Enable(vconfig.bUseXFB); - real_xfb->Enable(vconfig.bUseXFB); + // Repopulating the post-processing shaders can't be done from an event + if (choice_ppshader && choice_ppshader->IsEmpty()) + PopulatePostProcessingShaders(); - // custom textures - cache_hires_textures->Enable(vconfig.bHiresTextures); + // Things which shouldn't be changed during emulation + if (Core::IsRunning()) + { + choice_backend->Disable(); + label_backend->Disable(); - // Repopulating the post-processing shaders can't be done from an event - if (choice_ppshader && choice_ppshader->IsEmpty()) - PopulatePostProcessingShaders(); - - // Things which shouldn't be changed during emulation - if (Core::IsRunning()) - { - choice_backend->Disable(); - label_backend->Disable(); - - // D3D only - if (vconfig.backend_info.Adapters.size()) - { - choice_adapter->Disable(); - label_adapter->Disable(); - } + // D3D only + if (vconfig.backend_info.Adapters.size()) + { + choice_adapter->Disable(); + label_adapter->Disable(); + } #ifndef __APPLE__ - // This isn't supported on OS X. + // This isn't supported on OS X. - choice_display_resolution->Disable(); - label_display_resolution->Disable(); + choice_display_resolution->Disable(); + label_display_resolution->Disable(); #endif - progressive_scan_checkbox->Disable(); - render_to_main_checkbox->Disable(); - } - ev.Skip(); - } + progressive_scan_checkbox->Disable(); + render_to_main_checkbox->Disable(); + } + ev.Skip(); + } - // Creates controls and connects their enter/leave window events to Evt_Enter/LeaveControl - SettingCheckBox* CreateCheckBox(wxWindow* parent, const wxString& label, const wxString& description, bool &setting, bool reverse = false, long style = 0); - SettingChoice* CreateChoice(wxWindow* parent, int& setting, const wxString& description, int num = 0, const wxString choices[] = nullptr, long style = 0); - SettingRadioButton* CreateRadioButton(wxWindow* parent, const wxString& label, const wxString& description, bool &setting, bool reverse = false, long style = 0); + // Creates controls and connects their enter/leave window events to Evt_Enter/LeaveControl + SettingCheckBox* CreateCheckBox(wxWindow* parent, const wxString& label, + const wxString& description, bool& setting, bool reverse = false, + long style = 0); + SettingChoice* CreateChoice(wxWindow* parent, int& setting, const wxString& description, + int num = 0, const wxString choices[] = nullptr, long style = 0); + SettingRadioButton* CreateRadioButton(wxWindow* parent, const wxString& label, + const wxString& description, bool& setting, + bool reverse = false, long style = 0); - // Same as above but only connects enter/leave window events - wxControl* RegisterControl(wxControl* const control, const wxString& description); + // Same as above but only connects enter/leave window events + wxControl* RegisterControl(wxControl* const control, const wxString& description); - void Evt_EnterControl(wxMouseEvent& ev); - void Evt_LeaveControl(wxMouseEvent& ev); - void CreateDescriptionArea(wxPanel* const page, wxBoxSizer* const sizer); - void PopulatePostProcessingShaders(); - void PopulateAAList(); - void OnAAChanged(wxCommandEvent& ev); + void Evt_EnterControl(wxMouseEvent& ev); + void Evt_LeaveControl(wxMouseEvent& ev); + void CreateDescriptionArea(wxPanel* const page, wxBoxSizer* const sizer); + void PopulatePostProcessingShaders(); + void PopulateAAList(); + void OnAAChanged(wxCommandEvent& ev); - wxChoice* choice_backend; - wxChoice* choice_adapter; - wxChoice* choice_display_resolution; + wxChoice* choice_backend; + wxChoice* choice_adapter; + wxChoice* choice_display_resolution; - wxStaticText* label_backend; - wxStaticText* label_adapter; + wxStaticText* label_backend; + wxStaticText* label_adapter; - wxStaticText* text_aamode; - wxChoice* choice_aamode; - wxSlider* conv_slider; + wxStaticText* text_aamode; + wxChoice* choice_aamode; + wxSlider* conv_slider; - wxStaticText* label_display_resolution; + wxStaticText* label_display_resolution; - wxButton* button_config_pp; + wxButton* button_config_pp; - SettingCheckBox* borderless_fullscreen; - SettingCheckBox* render_to_main_checkbox; + SettingCheckBox* borderless_fullscreen; + SettingCheckBox* render_to_main_checkbox; - SettingRadioButton* virtual_xfb; - SettingRadioButton* real_xfb; + SettingRadioButton* virtual_xfb; + SettingRadioButton* real_xfb; - SettingCheckBox* cache_hires_textures; + SettingCheckBox* cache_hires_textures; - wxCheckBox* progressive_scan_checkbox; + wxCheckBox* progressive_scan_checkbox; - wxChoice* choice_ppshader; + wxChoice* choice_ppshader; - std::map ctrl_descs; // maps setting controls to their descriptions - std::map desc_texts; // maps dialog tabs (which are the parents of the setting controls) to their description text objects + std::map ctrl_descs; // maps setting controls to their descriptions + std::map desc_texts; // maps dialog tabs (which are the parents of the + // setting controls) to their description text + // objects - VideoConfig &vconfig; + VideoConfig& vconfig; - size_t m_msaa_modes; + size_t m_msaa_modes; }; diff --git a/Source/Core/DolphinWX/WXInputBase.cpp b/Source/Core/DolphinWX/WXInputBase.cpp index eb87a7169b..20a7549377 100644 --- a/Source/Core/DolphinWX/WXInputBase.cpp +++ b/Source/Core/DolphinWX/WXInputBase.cpp @@ -11,151 +11,254 @@ namespace WxUtils { - const wxString WXKeyToString(int keycode) { - switch (keycode) - { - case WXK_BACK: return _("Back"); - case WXK_TAB: return _("Tab"); - case WXK_RETURN: return _("Return"); - case WXK_ESCAPE: return _("Escape"); - case WXK_SPACE: return _("Space"); - case WXK_DELETE: return _("Delete"); + switch (keycode) + { + case WXK_BACK: + return _("Back"); + case WXK_TAB: + return _("Tab"); + case WXK_RETURN: + return _("Return"); + case WXK_ESCAPE: + return _("Escape"); + case WXK_SPACE: + return _("Space"); + case WXK_DELETE: + return _("Delete"); - // Undocumented wx keycodes - case 167: return _("Paragraph"); - case 177: return _("Plus-Minus"); + // Undocumented wx keycodes + case 167: + return _("Paragraph"); + case 177: + return _("Plus-Minus"); - case WXK_START: return _("Start"); - case WXK_LBUTTON: return _("L Button"); - case WXK_RBUTTON: return _("R Button"); - case WXK_CANCEL: return _("Cancel"); - case WXK_MBUTTON: return _("M Button"); - case WXK_CLEAR: return _("Clear"); - case WXK_SHIFT: return "Shift"; - case WXK_ALT: return "Alt"; - case WXK_RAW_CONTROL: return _("Control"); + case WXK_START: + return _("Start"); + case WXK_LBUTTON: + return _("L Button"); + case WXK_RBUTTON: + return _("R Button"); + case WXK_CANCEL: + return _("Cancel"); + case WXK_MBUTTON: + return _("M Button"); + case WXK_CLEAR: + return _("Clear"); + case WXK_SHIFT: + return "Shift"; + case WXK_ALT: + return "Alt"; + case WXK_RAW_CONTROL: + return _("Control"); #ifdef __WXOSX__ - case WXK_COMMAND: return _("Command"); + case WXK_COMMAND: + return _("Command"); #endif - case WXK_MENU: return _("Menu"); - case WXK_PAUSE: return _("Pause"); - case WXK_CAPITAL: return _("Caps Lock"); - case WXK_END: return _("End"); - case WXK_HOME: return _("Home"); - case WXK_LEFT: return _("Left"); - case WXK_UP: return _("Up"); - case WXK_RIGHT: return _("Right"); - case WXK_DOWN: return _("Down"); - case WXK_SELECT: return _("Select"); - case WXK_PRINT: return _("Print"); - case WXK_EXECUTE: return _("Execute"); - case WXK_SNAPSHOT: return _("Snapshot"); - case WXK_INSERT: return _("Insert"); - case WXK_HELP: return _("Help"); - case WXK_NUMPAD0: return "NP 0"; - case WXK_NUMPAD1: return "NP 1"; - case WXK_NUMPAD2: return "NP 2"; - case WXK_NUMPAD3: return "NP 3"; - case WXK_NUMPAD4: return "NP 4"; - case WXK_NUMPAD5: return "NP 5"; - case WXK_NUMPAD6: return "NP 6"; - case WXK_NUMPAD7: return "NP 7"; - case WXK_NUMPAD8: return "NP 8"; - case WXK_NUMPAD9: return "NP 9"; - case WXK_MULTIPLY: return _("Multiply"); - case WXK_ADD: return _("Add"); - case WXK_SEPARATOR: return _("Separator"); - case WXK_SUBTRACT: return _("Subtract"); - case WXK_DECIMAL: return _("Decimal"); - case WXK_DIVIDE: return _("Divide"); - case WXK_F1: return "F1"; - case WXK_F2: return "F2"; - case WXK_F3: return "F3"; - case WXK_F4: return "F4"; - case WXK_F5: return "F5"; - case WXK_F6: return "F6"; - case WXK_F7: return "F7"; - case WXK_F8: return "F8"; - case WXK_F9: return "F9"; - case WXK_F10: return "F10"; - case WXK_F11: return "F11"; - case WXK_F12: return "F12"; - case WXK_F13: return "F13"; - case WXK_F14: return "F14"; - case WXK_F15: return "F15"; - case WXK_F16: return "F16"; - case WXK_F17: return "F17"; - case WXK_F18: return "F19"; - case WXK_F19: return "F20"; - case WXK_F20: return "F21"; - case WXK_F21: return "F22"; - case WXK_F22: return "F23"; - case WXK_F23: return "F24"; - case WXK_F24: return "F25"; - case WXK_NUMLOCK: return _("Num Lock"); - case WXK_SCROLL: return _("Scroll Lock"); - case WXK_PAGEUP: return _("Page Up"); - case WXK_PAGEDOWN: return _("Page Down"); - case WXK_NUMPAD_SPACE: return _("NP Space"); - case WXK_NUMPAD_TAB: return _("NP Tab"); - case WXK_NUMPAD_ENTER: return _("NP Enter"); - case WXK_NUMPAD_F1: return "NP F1"; - case WXK_NUMPAD_F2: return "NP F2"; - case WXK_NUMPAD_F3: return "NP F3"; - case WXK_NUMPAD_F4: return "NP F4"; - case WXK_NUMPAD_HOME: return _("NP Home"); - case WXK_NUMPAD_LEFT: return _("NP Left"); - case WXK_NUMPAD_UP: return _("NP Up"); - case WXK_NUMPAD_RIGHT: return _("NP Right"); - case WXK_NUMPAD_DOWN: return _("NP Down"); - case WXK_NUMPAD_PAGEUP: return _("NP Page Up"); - case WXK_NUMPAD_PAGEDOWN: return _("NP Page Down"); - case WXK_NUMPAD_END: return _("NP End"); - case WXK_NUMPAD_BEGIN: return _("NP Begin"); - case WXK_NUMPAD_INSERT: return _("NP Insert"); - case WXK_NUMPAD_DELETE: return _("NP Delete"); - case WXK_NUMPAD_EQUAL: return _("NP Equal"); - case WXK_NUMPAD_MULTIPLY: return _("NP Multiply"); - case WXK_NUMPAD_ADD: return _("NP Add"); - case WXK_NUMPAD_SEPARATOR: return _("NP Separator"); - case WXK_NUMPAD_SUBTRACT: return _("NP Subtract"); - case WXK_NUMPAD_DECIMAL: return _("NP Decimal"); - case WXK_NUMPAD_DIVIDE: return _("NP Divide"); - case WXK_WINDOWS_LEFT: return _("Windows Left"); - case WXK_WINDOWS_RIGHT: return _("Windows Right"); - case WXK_WINDOWS_MENU: return _("Windows Menu"); - } + case WXK_MENU: + return _("Menu"); + case WXK_PAUSE: + return _("Pause"); + case WXK_CAPITAL: + return _("Caps Lock"); + case WXK_END: + return _("End"); + case WXK_HOME: + return _("Home"); + case WXK_LEFT: + return _("Left"); + case WXK_UP: + return _("Up"); + case WXK_RIGHT: + return _("Right"); + case WXK_DOWN: + return _("Down"); + case WXK_SELECT: + return _("Select"); + case WXK_PRINT: + return _("Print"); + case WXK_EXECUTE: + return _("Execute"); + case WXK_SNAPSHOT: + return _("Snapshot"); + case WXK_INSERT: + return _("Insert"); + case WXK_HELP: + return _("Help"); + case WXK_NUMPAD0: + return "NP 0"; + case WXK_NUMPAD1: + return "NP 1"; + case WXK_NUMPAD2: + return "NP 2"; + case WXK_NUMPAD3: + return "NP 3"; + case WXK_NUMPAD4: + return "NP 4"; + case WXK_NUMPAD5: + return "NP 5"; + case WXK_NUMPAD6: + return "NP 6"; + case WXK_NUMPAD7: + return "NP 7"; + case WXK_NUMPAD8: + return "NP 8"; + case WXK_NUMPAD9: + return "NP 9"; + case WXK_MULTIPLY: + return _("Multiply"); + case WXK_ADD: + return _("Add"); + case WXK_SEPARATOR: + return _("Separator"); + case WXK_SUBTRACT: + return _("Subtract"); + case WXK_DECIMAL: + return _("Decimal"); + case WXK_DIVIDE: + return _("Divide"); + case WXK_F1: + return "F1"; + case WXK_F2: + return "F2"; + case WXK_F3: + return "F3"; + case WXK_F4: + return "F4"; + case WXK_F5: + return "F5"; + case WXK_F6: + return "F6"; + case WXK_F7: + return "F7"; + case WXK_F8: + return "F8"; + case WXK_F9: + return "F9"; + case WXK_F10: + return "F10"; + case WXK_F11: + return "F11"; + case WXK_F12: + return "F12"; + case WXK_F13: + return "F13"; + case WXK_F14: + return "F14"; + case WXK_F15: + return "F15"; + case WXK_F16: + return "F16"; + case WXK_F17: + return "F17"; + case WXK_F18: + return "F19"; + case WXK_F19: + return "F20"; + case WXK_F20: + return "F21"; + case WXK_F21: + return "F22"; + case WXK_F22: + return "F23"; + case WXK_F23: + return "F24"; + case WXK_F24: + return "F25"; + case WXK_NUMLOCK: + return _("Num Lock"); + case WXK_SCROLL: + return _("Scroll Lock"); + case WXK_PAGEUP: + return _("Page Up"); + case WXK_PAGEDOWN: + return _("Page Down"); + case WXK_NUMPAD_SPACE: + return _("NP Space"); + case WXK_NUMPAD_TAB: + return _("NP Tab"); + case WXK_NUMPAD_ENTER: + return _("NP Enter"); + case WXK_NUMPAD_F1: + return "NP F1"; + case WXK_NUMPAD_F2: + return "NP F2"; + case WXK_NUMPAD_F3: + return "NP F3"; + case WXK_NUMPAD_F4: + return "NP F4"; + case WXK_NUMPAD_HOME: + return _("NP Home"); + case WXK_NUMPAD_LEFT: + return _("NP Left"); + case WXK_NUMPAD_UP: + return _("NP Up"); + case WXK_NUMPAD_RIGHT: + return _("NP Right"); + case WXK_NUMPAD_DOWN: + return _("NP Down"); + case WXK_NUMPAD_PAGEUP: + return _("NP Page Up"); + case WXK_NUMPAD_PAGEDOWN: + return _("NP Page Down"); + case WXK_NUMPAD_END: + return _("NP End"); + case WXK_NUMPAD_BEGIN: + return _("NP Begin"); + case WXK_NUMPAD_INSERT: + return _("NP Insert"); + case WXK_NUMPAD_DELETE: + return _("NP Delete"); + case WXK_NUMPAD_EQUAL: + return _("NP Equal"); + case WXK_NUMPAD_MULTIPLY: + return _("NP Multiply"); + case WXK_NUMPAD_ADD: + return _("NP Add"); + case WXK_NUMPAD_SEPARATOR: + return _("NP Separator"); + case WXK_NUMPAD_SUBTRACT: + return _("NP Subtract"); + case WXK_NUMPAD_DECIMAL: + return _("NP Decimal"); + case WXK_NUMPAD_DIVIDE: + return _("NP Divide"); + case WXK_WINDOWS_LEFT: + return _("Windows Left"); + case WXK_WINDOWS_RIGHT: + return _("Windows Right"); + case WXK_WINDOWS_MENU: + return _("Windows Menu"); + } - if (keycode > WXK_SPACE && keycode < WXK_DELETE) - { - return wxString((wxChar)keycode, 1); - } + if (keycode > WXK_SPACE && keycode < WXK_DELETE) + { + return wxString((wxChar)keycode, 1); + } - return ""; + return ""; } const wxString WXKeymodToString(int modifier) { - wxString mods; + wxString mods; - if (modifier & wxMOD_META) + if (modifier & wxMOD_META) #ifdef __APPLE__ - mods += "Cmd+"; + mods += "Cmd+"; #elif defined _WIN32 - mods += "Win+"; + mods += "Win+"; #else - mods += "Meta+"; + mods += "Meta+"; #endif - if (modifier & wxMOD_CONTROL) - mods += "Ctrl+"; - if (modifier & wxMOD_ALT) - mods += "Alt+"; - if (modifier & wxMOD_SHIFT) - mods += "Shift+"; + if (modifier & wxMOD_CONTROL) + mods += "Ctrl+"; + if (modifier & wxMOD_ALT) + mods += "Alt+"; + if (modifier & wxMOD_SHIFT) + mods += "Shift+"; - return mods; + return mods; } - } diff --git a/Source/Core/DolphinWX/WxUtils.cpp b/Source/Core/DolphinWX/WxUtils.cpp index 14f5977e53..fb33991d6b 100644 --- a/Source/Core/DolphinWX/WxUtils.cpp +++ b/Source/Core/DolphinWX/WxUtils.cpp @@ -23,98 +23,101 @@ namespace WxUtils { - // Launch a file according to its mime type void Launch(const std::string& filename) { - if (! ::wxLaunchDefaultBrowser(StrToWxStr(filename))) - { - // WARN_LOG - } + if (!::wxLaunchDefaultBrowser(StrToWxStr(filename))) + { + // WARN_LOG + } } // Launch an file explorer window on a certain path void Explore(const std::string& path) { - wxString wxPath = StrToWxStr(path); + wxString wxPath = StrToWxStr(path); #ifndef _WIN32 - // Default to file - if (! wxPath.Contains("://")) - { - wxPath = "file://" + wxPath; - } + // Default to file + if (!wxPath.Contains("://")) + { + wxPath = "file://" + wxPath; + } #endif #ifdef __WXGTK__ - wxPath.Replace(" ", "\\ "); + wxPath.Replace(" ", "\\ "); #endif - if (! ::wxLaunchDefaultBrowser(wxPath)) - { - // WARN_LOG - } + if (!::wxLaunchDefaultBrowser(wxPath)) + { + // WARN_LOG + } } void ShowErrorDialog(const wxString& error_msg) { - wxMessageBox(error_msg, _("Error"), wxOK | wxICON_ERROR); + wxMessageBox(error_msg, _("Error"), wxOK | wxICON_ERROR); } wxBitmap LoadResourceBitmap(const std::string& name, const wxSize& padded_size) { - const std::string path_base = File::GetSysDirectory() + RESOURCES_DIR + DIR_SEP + name; - std::string path = path_base + ".png"; - double scale_factor = 1.0; + const std::string path_base = File::GetSysDirectory() + RESOURCES_DIR + DIR_SEP + name; + std::string path = path_base + ".png"; + double scale_factor = 1.0; #ifdef __APPLE__ - if (wxTheApp->GetTopWindow()->GetContentScaleFactor() >= 2) - { - const std::string path_2x = path_base + "@2x.png"; - if (File::Exists(path_2x)) - { - path = path_2x; - scale_factor = 2.0; - } - } + if (wxTheApp->GetTopWindow()->GetContentScaleFactor() >= 2) + { + const std::string path_2x = path_base + "@2x.png"; + if (File::Exists(path_2x)) + { + path = path_2x; + scale_factor = 2.0; + } + } #endif - wxImage image(StrToWxStr(path), wxBITMAP_TYPE_PNG); + wxImage image(StrToWxStr(path), wxBITMAP_TYPE_PNG); - if (padded_size != wxSize()) - { - // Add padding if necessary (or crop, but images aren't supposed to be large enough to require that). - // The image will be left-aligned and vertically centered. - const wxSize scaled_padded_size = padded_size * scale_factor; - image.Resize(scaled_padded_size, wxPoint(0, (scaled_padded_size.GetHeight() - image.GetHeight()) / 2)); - } + if (padded_size != wxSize()) + { + // Add padding if necessary (or crop, but images aren't supposed to be large enough to require + // that). + // The image will be left-aligned and vertically centered. + const wxSize scaled_padded_size = padded_size * scale_factor; + image.Resize(scaled_padded_size, + wxPoint(0, (scaled_padded_size.GetHeight() - image.GetHeight()) / 2)); + } #ifdef __APPLE__ - return wxBitmap(image, -1, scale_factor); + return wxBitmap(image, -1, scale_factor); #else - return wxBitmap(image); + return wxBitmap(image); #endif } wxBitmap CreateDisabledButtonBitmap(const wxBitmap& original) { - wxImage image = original.ConvertToImage(); - return wxBitmap(image.ConvertToDisabled(240)); + wxImage image = original.ConvertToImage(); + return wxBitmap(image.ConvertToDisabled(240)); } -void AddToolbarButton(wxToolBar* toolbar, int toolID, const wxString& label, const wxBitmap& bitmap, const wxString& shortHelp) +void AddToolbarButton(wxToolBar* toolbar, int toolID, const wxString& label, const wxBitmap& bitmap, + const wxString& shortHelp) { - // Must explicitly set the disabled button bitmap because wxWidgets - // incorrectly desaturates it instead of lightening it. - toolbar->AddTool(toolID, label, bitmap, WxUtils::CreateDisabledButtonBitmap(bitmap), wxITEM_NORMAL, shortHelp); + // Must explicitly set the disabled button bitmap because wxWidgets + // incorrectly desaturates it instead of lightening it. + toolbar->AddTool(toolID, label, bitmap, WxUtils::CreateDisabledButtonBitmap(bitmap), + wxITEM_NORMAL, shortHelp); } } // namespace std::string WxStrToStr(const wxString& str) { - return str.ToUTF8().data(); + return str.ToUTF8().data(); } wxString StrToWxStr(const std::string& str) { - //return wxString::FromUTF8Unchecked(str.c_str()); - return wxString::FromUTF8(str.c_str()); + // return wxString::FromUTF8Unchecked(str.c_str()); + return wxString::FromUTF8(str.c_str()); } diff --git a/Source/Core/DolphinWX/WxUtils.h b/Source/Core/DolphinWX/WxUtils.h index 25c3ed2458..1f7937e819 100644 --- a/Source/Core/DolphinWX/WxUtils.h +++ b/Source/Core/DolphinWX/WxUtils.h @@ -13,7 +13,6 @@ class wxToolBar; namespace WxUtils { - // Launch a file according to its mime type void Launch(const std::string& filename); @@ -30,7 +29,8 @@ wxBitmap LoadResourceBitmap(const std::string& name, const wxSize& padded_size = wxBitmap CreateDisabledButtonBitmap(const wxBitmap& original); // Helper function to add a button to a toolbar -void AddToolbarButton(wxToolBar* toolbar, int toolID, const wxString& label, const wxBitmap& bitmap, const wxString& shortHelp); +void AddToolbarButton(wxToolBar* toolbar, int toolID, const wxString& label, const wxBitmap& bitmap, + const wxString& shortHelp); } // namespace diff --git a/Source/Core/DolphinWX/X11Utils.cpp b/Source/Core/DolphinWX/X11Utils.cpp index 581e45bc55..92ead387ef 100644 --- a/Source/Core/DolphinWX/X11Utils.cpp +++ b/Source/Core/DolphinWX/X11Utils.cpp @@ -3,15 +3,15 @@ // Refer to the license.txt file included. #include -#include #include +#include #include "Common/Logging/Log.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "DolphinWX/X11Utils.h" -extern char **environ; +extern char** environ; #if defined(HAVE_WX) && HAVE_WX #include @@ -22,265 +22,255 @@ extern char **environ; namespace X11Utils { - -bool ToggleFullscreen(Display *dpy, Window win) +bool ToggleFullscreen(Display* dpy, Window win) { - // Init X event structure for _NET_WM_STATE_FULLSCREEN client message - XEvent event; - event.xclient.type = ClientMessage; - event.xclient.message_type = XInternAtom(dpy, "_NET_WM_STATE", False); - event.xclient.window = win; - event.xclient.format = 32; - event.xclient.data.l[0] = _NET_WM_STATE_TOGGLE; - event.xclient.data.l[1] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); + // Init X event structure for _NET_WM_STATE_FULLSCREEN client message + XEvent event; + event.xclient.type = ClientMessage; + event.xclient.message_type = XInternAtom(dpy, "_NET_WM_STATE", False); + event.xclient.window = win; + event.xclient.format = 32; + event.xclient.data.l[0] = _NET_WM_STATE_TOGGLE; + event.xclient.data.l[1] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); - // Send the event - if (!XSendEvent(dpy, DefaultRootWindow(dpy), False, - SubstructureRedirectMask | SubstructureNotifyMask, &event)) - { - ERROR_LOG(VIDEO, "Failed to switch fullscreen/windowed mode."); - return false; - } + // Send the event + if (!XSendEvent(dpy, DefaultRootWindow(dpy), False, + SubstructureRedirectMask | SubstructureNotifyMask, &event)) + { + ERROR_LOG(VIDEO, "Failed to switch fullscreen/windowed mode."); + return false; + } - return true; + return true; } -void InhibitScreensaver(Display *dpy, Window win, bool suspend) +void InhibitScreensaver(Display* dpy, Window win, bool suspend) { - char id[11]; - snprintf(id, sizeof(id), "0x%lx", win); + char id[11]; + snprintf(id, sizeof(id), "0x%lx", win); - // Call xdg-screensaver - char *argv[4] = { - (char *)"xdg-screensaver", - (char *)(suspend ? "suspend" : "resume"), - id, - nullptr}; - pid_t pid; - if (!posix_spawnp(&pid, "xdg-screensaver", nullptr, nullptr, argv, environ)) - { - int status; - while (waitpid (pid, &status, 0) == -1); + // Call xdg-screensaver + char* argv[4] = {(char*)"xdg-screensaver", (char*)(suspend ? "suspend" : "resume"), id, nullptr}; + pid_t pid; + if (!posix_spawnp(&pid, "xdg-screensaver", nullptr, nullptr, argv, environ)) + { + int status; + while (waitpid(pid, &status, 0) == -1) + ; - DEBUG_LOG(VIDEO, "Started xdg-screensaver (PID = %d)", (int)pid); - } + DEBUG_LOG(VIDEO, "Started xdg-screensaver (PID = %d)", (int)pid); + } } #if defined(HAVE_XRANDR) && HAVE_XRANDR -XRRConfiguration::XRRConfiguration(Display *_dpy, Window _win) - : dpy(_dpy) - , win(_win) - , screenResources(nullptr), outputInfo(nullptr), crtcInfo(nullptr) - , fullMode(0) - , fs_fb_width(0), fs_fb_height(0), fs_fb_width_mm(0), fs_fb_height_mm(0) - , bValid(true), bIsFullscreen(false) +XRRConfiguration::XRRConfiguration(Display* _dpy, Window _win) + : dpy(_dpy), win(_win), screenResources(nullptr), outputInfo(nullptr), crtcInfo(nullptr), + fullMode(0), fs_fb_width(0), fs_fb_height(0), fs_fb_width_mm(0), fs_fb_height_mm(0), + bValid(true), bIsFullscreen(false) { - int XRRMajorVersion, XRRMinorVersion; + int XRRMajorVersion, XRRMinorVersion; - if (!XRRQueryVersion(dpy, &XRRMajorVersion, &XRRMinorVersion) || - (XRRMajorVersion < 1 || (XRRMajorVersion == 1 && XRRMinorVersion < 3))) - { - WARN_LOG(VIDEO, "XRRExtension not supported."); - bValid = false; - return; - } + if (!XRRQueryVersion(dpy, &XRRMajorVersion, &XRRMinorVersion) || + (XRRMajorVersion < 1 || (XRRMajorVersion == 1 && XRRMinorVersion < 3))) + { + WARN_LOG(VIDEO, "XRRExtension not supported."); + bValid = false; + return; + } - screenResources = XRRGetScreenResourcesCurrent(dpy, win); + screenResources = XRRGetScreenResourcesCurrent(dpy, win); - screen = DefaultScreen(dpy); - fb_width = DisplayWidth(dpy, screen); - fb_height = DisplayHeight(dpy, screen); - fb_width_mm = DisplayWidthMM(dpy, screen); - fb_height_mm = DisplayHeightMM(dpy, screen); + screen = DefaultScreen(dpy); + fb_width = DisplayWidth(dpy, screen); + fb_height = DisplayHeight(dpy, screen); + fb_width_mm = DisplayWidthMM(dpy, screen); + fb_height_mm = DisplayHeightMM(dpy, screen); - INFO_LOG(VIDEO, "XRRExtension-Version %d.%d", XRRMajorVersion, XRRMinorVersion); - Update(); + INFO_LOG(VIDEO, "XRRExtension-Version %d.%d", XRRMajorVersion, XRRMinorVersion); + Update(); } XRRConfiguration::~XRRConfiguration() { - if (bValid && bIsFullscreen) - ToggleDisplayMode(False); - if (screenResources) - XRRFreeScreenResources(screenResources); - if (outputInfo) - XRRFreeOutputInfo(outputInfo); - if (crtcInfo) - XRRFreeCrtcInfo(crtcInfo); + if (bValid && bIsFullscreen) + ToggleDisplayMode(False); + if (screenResources) + XRRFreeScreenResources(screenResources); + if (outputInfo) + XRRFreeOutputInfo(outputInfo); + if (crtcInfo) + XRRFreeCrtcInfo(crtcInfo); } void XRRConfiguration::Update() { - if (SConfig::GetInstance().strFullscreenResolution == "Auto") - return; + if (SConfig::GetInstance().strFullscreenResolution == "Auto") + return; - if (!bValid) - return; + if (!bValid) + return; - if (outputInfo) - { - XRRFreeOutputInfo(outputInfo); - outputInfo = nullptr; - } - if (crtcInfo) - { - XRRFreeCrtcInfo(crtcInfo); - crtcInfo = nullptr; - } - fullMode = 0; + if (outputInfo) + { + XRRFreeOutputInfo(outputInfo); + outputInfo = nullptr; + } + if (crtcInfo) + { + XRRFreeCrtcInfo(crtcInfo); + crtcInfo = nullptr; + } + fullMode = 0; - // Get the resolution setings for fullscreen mode - unsigned int fullWidth, fullHeight; - char *output_name = nullptr; - char auxFlag = '\0'; - if (SConfig::GetInstance().strFullscreenResolution.find(':') == - std::string::npos) - { - fullWidth = fb_width; - fullHeight = fb_height; - } - else - { - sscanf(SConfig::GetInstance().strFullscreenResolution.c_str(), - "%m[^:]: %ux%u%c", &output_name, &fullWidth, &fullHeight, &auxFlag); - } - bool want_interlaced = ('i' == auxFlag); + // Get the resolution setings for fullscreen mode + unsigned int fullWidth, fullHeight; + char* output_name = nullptr; + char auxFlag = '\0'; + if (SConfig::GetInstance().strFullscreenResolution.find(':') == std::string::npos) + { + fullWidth = fb_width; + fullHeight = fb_height; + } + else + { + sscanf(SConfig::GetInstance().strFullscreenResolution.c_str(), "%m[^:]: %ux%u%c", &output_name, + &fullWidth, &fullHeight, &auxFlag); + } + bool want_interlaced = ('i' == auxFlag); - for (int i = 0; i < screenResources->noutput; i++) - { - XRROutputInfo *output_info = XRRGetOutputInfo(dpy, screenResources, screenResources->outputs[i]); - if (output_info && output_info->crtc && output_info->connection == RR_Connected) - { - XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(dpy, screenResources, output_info->crtc); - if (crtc_info) - { - if (!output_name || !strcmp(output_name, output_info->name)) - { - // Use the first output for the default setting. - if (!output_name) - { - output_name = strdup(output_info->name); - SConfig::GetInstance().strFullscreenResolution = - StringFromFormat("%s: %ux%u", output_info->name, fullWidth, fullHeight); - } - outputInfo = output_info; - crtcInfo = crtc_info; - for (int j = 0; j < output_info->nmode && fullMode == 0; j++) - { - for (int k = 0; k < screenResources->nmode && fullMode == 0; k++) - { - if (output_info->modes[j] == screenResources->modes[k].id) - { - if (fullWidth == screenResources->modes[k].width && - fullHeight == screenResources->modes[k].height && - want_interlaced == !!(screenResources->modes[k].modeFlags & RR_Interlace)) - { - fullMode = screenResources->modes[k].id; - if (crtcInfo->x + (int)screenResources->modes[k].width > fs_fb_width) - fs_fb_width = crtcInfo->x + screenResources->modes[k].width; - if (crtcInfo->y + (int)screenResources->modes[k].height > fs_fb_height) - fs_fb_height = crtcInfo->y + screenResources->modes[k].height; - } - } - } - } - } - else - { - if (crtc_info->x + (int)crtc_info->width > fs_fb_width) - fs_fb_width = crtc_info->x + crtc_info->width; - if (crtc_info->y + (int)crtc_info->height > fs_fb_height) - fs_fb_height = crtc_info->y + crtc_info->height; - } - } - if (crtc_info && crtcInfo != crtc_info) - XRRFreeCrtcInfo(crtc_info); - } - if (output_info && outputInfo != output_info) - XRRFreeOutputInfo(output_info); - } - fs_fb_width_mm = fs_fb_width * DisplayHeightMM(dpy, screen) / DisplayHeight(dpy, screen); - fs_fb_height_mm = fs_fb_height * DisplayHeightMM(dpy, screen) / DisplayHeight(dpy, screen); + for (int i = 0; i < screenResources->noutput; i++) + { + XRROutputInfo* output_info = + XRRGetOutputInfo(dpy, screenResources, screenResources->outputs[i]); + if (output_info && output_info->crtc && output_info->connection == RR_Connected) + { + XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(dpy, screenResources, output_info->crtc); + if (crtc_info) + { + if (!output_name || !strcmp(output_name, output_info->name)) + { + // Use the first output for the default setting. + if (!output_name) + { + output_name = strdup(output_info->name); + SConfig::GetInstance().strFullscreenResolution = + StringFromFormat("%s: %ux%u", output_info->name, fullWidth, fullHeight); + } + outputInfo = output_info; + crtcInfo = crtc_info; + for (int j = 0; j < output_info->nmode && fullMode == 0; j++) + { + for (int k = 0; k < screenResources->nmode && fullMode == 0; k++) + { + if (output_info->modes[j] == screenResources->modes[k].id) + { + if (fullWidth == screenResources->modes[k].width && + fullHeight == screenResources->modes[k].height && + want_interlaced == !!(screenResources->modes[k].modeFlags & RR_Interlace)) + { + fullMode = screenResources->modes[k].id; + if (crtcInfo->x + (int)screenResources->modes[k].width > fs_fb_width) + fs_fb_width = crtcInfo->x + screenResources->modes[k].width; + if (crtcInfo->y + (int)screenResources->modes[k].height > fs_fb_height) + fs_fb_height = crtcInfo->y + screenResources->modes[k].height; + } + } + } + } + } + else + { + if (crtc_info->x + (int)crtc_info->width > fs_fb_width) + fs_fb_width = crtc_info->x + crtc_info->width; + if (crtc_info->y + (int)crtc_info->height > fs_fb_height) + fs_fb_height = crtc_info->y + crtc_info->height; + } + } + if (crtc_info && crtcInfo != crtc_info) + XRRFreeCrtcInfo(crtc_info); + } + if (output_info && outputInfo != output_info) + XRRFreeOutputInfo(output_info); + } + fs_fb_width_mm = fs_fb_width * DisplayHeightMM(dpy, screen) / DisplayHeight(dpy, screen); + fs_fb_height_mm = fs_fb_height * DisplayHeightMM(dpy, screen) / DisplayHeight(dpy, screen); - if (output_name) - free(output_name); + if (output_name) + free(output_name); - if (outputInfo && crtcInfo && fullMode) - { - INFO_LOG(VIDEO, "Fullscreen Resolution %dx%d", fullWidth, fullHeight); - } - else - { - ERROR_LOG(VIDEO, "Failed to obtain fullscreen size.\n" - "Using current desktop resolution for fullscreen."); - } + if (outputInfo && crtcInfo && fullMode) + { + INFO_LOG(VIDEO, "Fullscreen Resolution %dx%d", fullWidth, fullHeight); + } + else + { + ERROR_LOG(VIDEO, "Failed to obtain fullscreen size.\n" + "Using current desktop resolution for fullscreen."); + } } void XRRConfiguration::ToggleDisplayMode(bool bFullscreen) { - if (!bValid || !screenResources || !outputInfo || !crtcInfo || !fullMode) - return; - if (bFullscreen == bIsFullscreen) - return; + if (!bValid || !screenResources || !outputInfo || !crtcInfo || !fullMode) + return; + if (bFullscreen == bIsFullscreen) + return; - XGrabServer(dpy); - if (bFullscreen) - { - XRRSetCrtcConfig(dpy, screenResources, outputInfo->crtc, CurrentTime, - crtcInfo->x, crtcInfo->y, fullMode, crtcInfo->rotation, - crtcInfo->outputs, crtcInfo->noutput); - XRRSetScreenSize(dpy, win, fs_fb_width, fs_fb_height, fs_fb_width_mm, fs_fb_height_mm); - bIsFullscreen = true; - } - else - { - XRRSetCrtcConfig(dpy, screenResources, outputInfo->crtc, CurrentTime, - crtcInfo->x, crtcInfo->y, crtcInfo->mode, crtcInfo->rotation, - crtcInfo->outputs, crtcInfo->noutput); - XRRSetScreenSize(dpy, win, fb_width, fb_height, fb_width_mm, fb_height_mm); - bIsFullscreen = false; - } - XUngrabServer(dpy); - XSync(dpy, false); + XGrabServer(dpy); + if (bFullscreen) + { + XRRSetCrtcConfig(dpy, screenResources, outputInfo->crtc, CurrentTime, crtcInfo->x, crtcInfo->y, + fullMode, crtcInfo->rotation, crtcInfo->outputs, crtcInfo->noutput); + XRRSetScreenSize(dpy, win, fs_fb_width, fs_fb_height, fs_fb_width_mm, fs_fb_height_mm); + bIsFullscreen = true; + } + else + { + XRRSetCrtcConfig(dpy, screenResources, outputInfo->crtc, CurrentTime, crtcInfo->x, crtcInfo->y, + crtcInfo->mode, crtcInfo->rotation, crtcInfo->outputs, crtcInfo->noutput); + XRRSetScreenSize(dpy, win, fb_width, fb_height, fb_width_mm, fb_height_mm); + bIsFullscreen = false; + } + XUngrabServer(dpy); + XSync(dpy, false); } void XRRConfiguration::AddResolutions(std::vector& resos) { - if (!bValid || !screenResources) - return; + if (!bValid || !screenResources) + return; - //Get all full screen resolutions for the config dialog - for (int i = 0; i < screenResources->noutput; i++) - { - XRROutputInfo *output_info = - XRRGetOutputInfo(dpy, screenResources, screenResources->outputs[i]); + // Get all full screen resolutions for the config dialog + for (int i = 0; i < screenResources->noutput; i++) + { + XRROutputInfo* output_info = + XRRGetOutputInfo(dpy, screenResources, screenResources->outputs[i]); - if (output_info && output_info->crtc && output_info->connection == RR_Connected) - { - for (int j = 0; j < output_info->nmode; j++) - { - for (int k = 0; k < screenResources->nmode; k++) - { - if (output_info->modes[j] == screenResources->modes[k].id) - { - bool interlaced = !!(screenResources->modes[k].modeFlags & RR_Interlace); - const std::string strRes = - std::string(output_info->name) + ": " + - std::string(screenResources->modes[k].name) + (interlaced? "i" : ""); - // Only add unique resolutions - if (std::find(resos.begin(), resos.end(), strRes) == resos.end()) - { - resos.push_back(strRes); - } - } - } - } - } - if (output_info) - XRRFreeOutputInfo(output_info); - } + if (output_info && output_info->crtc && output_info->connection == RR_Connected) + { + for (int j = 0; j < output_info->nmode; j++) + { + for (int k = 0; k < screenResources->nmode; k++) + { + if (output_info->modes[j] == screenResources->modes[k].id) + { + bool interlaced = !!(screenResources->modes[k].modeFlags & RR_Interlace); + const std::string strRes = std::string(output_info->name) + ": " + + std::string(screenResources->modes[k].name) + + (interlaced ? "i" : ""); + // Only add unique resolutions + if (std::find(resos.begin(), resos.end(), strRes) == resos.end()) + { + resos.push_back(strRes); + } + } + } + } + } + if (output_info) + XRRFreeOutputInfo(output_info); + } } #endif - } diff --git a/Source/Core/DolphinWX/X11Utils.h b/Source/Core/DolphinWX/X11Utils.h index bab37feaf8..c673e1aabd 100644 --- a/Source/Core/DolphinWX/X11Utils.h +++ b/Source/Core/DolphinWX/X11Utils.h @@ -10,11 +10,11 @@ // // We work around that issue by including SFML first before X11 headers. This // is terrible, but such is the life with Xlib. -#include // NOLINT +#include // NOLINT #if defined(HAVE_WX) && HAVE_WX -#include #include +#include #include #endif @@ -24,48 +24,45 @@ #include #include - // EWMH state actions, see // http://freedesktop.org/wiki/Specifications/wm-spec?action=show&redirect=Standards%2Fwm-spec -#define _NET_WM_STATE_REMOVE 0 // remove/unset property -#define _NET_WM_STATE_ADD 1 // add/set property -#define _NET_WM_STATE_TOGGLE 2 // toggle property +#define _NET_WM_STATE_REMOVE 0 // remove/unset property +#define _NET_WM_STATE_ADD 1 // add/set property +#define _NET_WM_STATE_TOGGLE 2 // toggle property namespace X11Utils { - -bool ToggleFullscreen(Display *dpy, Window win); +bool ToggleFullscreen(Display* dpy, Window win); #if defined(HAVE_WX) && HAVE_WX -Window XWindowFromHandle(void *Handle); -Display *XDisplayFromHandle(void *Handle); +Window XWindowFromHandle(void* Handle); +Display* XDisplayFromHandle(void* Handle); #endif -void InhibitScreensaver(Display *dpy, Window win, bool suspend); +void InhibitScreensaver(Display* dpy, Window win, bool suspend); #if defined(HAVE_XRANDR) && HAVE_XRANDR class XRRConfiguration { - public: - XRRConfiguration(Display *_dpy, Window _win); - ~XRRConfiguration(); +public: + XRRConfiguration(Display* _dpy, Window _win); + ~XRRConfiguration(); - void Update(); - void ToggleDisplayMode(bool bFullscreen); - void AddResolutions(std::vector& resos); + void Update(); + void ToggleDisplayMode(bool bFullscreen); + void AddResolutions(std::vector& resos); - private: - Display *dpy; - Window win; - int screen; - XRRScreenResources *screenResources; - XRROutputInfo *outputInfo; - XRRCrtcInfo *crtcInfo; - RRMode fullMode; - int fb_width, fb_height, fb_width_mm, fb_height_mm; - int fs_fb_width, fs_fb_height, fs_fb_width_mm, fs_fb_height_mm; - bool bValid; - bool bIsFullscreen; +private: + Display* dpy; + Window win; + int screen; + XRRScreenResources* screenResources; + XRROutputInfo* outputInfo; + XRRCrtcInfo* crtcInfo; + RRMode fullMode; + int fb_width, fb_height, fb_width_mm, fb_height_mm; + int fs_fb_width, fs_fb_height, fs_fb_width_mm, fs_fb_height_mm; + bool bValid; + bool bIsFullscreen; }; #endif - } diff --git a/Source/Core/DolphinWX/resource.h b/Source/Core/DolphinWX/resource.h index b95c701893..61ca5f2266 100644 --- a/Source/Core/DolphinWX/resource.h +++ b/Source/Core/DolphinWX/resource.h @@ -6,15 +6,15 @@ // Microsoft Visual C++ generated include file. // Used by DolphinWX.rc // -#define IDI_ICON1 101 +#define IDI_ICON1 101 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/Source/Core/InputCommon/ControllerEmu.cpp b/Source/Core/InputCommon/ControllerEmu.cpp index 839cfa9bfa..4d333e1d23 100644 --- a/Source/Core/InputCommon/ControllerEmu.cpp +++ b/Source/Core/InputCommon/ControllerEmu.cpp @@ -2,245 +2,249 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "InputCommon/ControllerEmu.h" #include #include "Common/Common.h" -#include "InputCommon/ControllerEmu.h" void ControllerEmu::UpdateReferences(ControllerInterface& devi) { - for (auto& ctrlGroup : groups) - { - for (auto& control : ctrlGroup->controls) - devi.UpdateReference(control->control_ref.get(), default_device); + for (auto& ctrlGroup : groups) + { + for (auto& control : ctrlGroup->controls) + devi.UpdateReference(control->control_ref.get(), default_device); - // extension - if (ctrlGroup->type == GROUP_TYPE_EXTENSION) - { - for (auto& attachment : ((Extension*)ctrlGroup.get())->attachments) - attachment->UpdateReferences(devi); - } - } + // extension + if (ctrlGroup->type == GROUP_TYPE_EXTENSION) + { + for (auto& attachment : ((Extension*)ctrlGroup.get())->attachments) + attachment->UpdateReferences(devi); + } + } } void ControllerEmu::UpdateDefaultDevice() { - for (auto& ctrlGroup : groups) - { - // extension - if (ctrlGroup->type == GROUP_TYPE_EXTENSION) - { - for (auto& ai : ((Extension*)ctrlGroup.get())->attachments) - { - ai->default_device = default_device; - ai->UpdateDefaultDevice(); - } - } - } + for (auto& ctrlGroup : groups) + { + // extension + if (ctrlGroup->type == GROUP_TYPE_EXTENSION) + { + for (auto& ai : ((Extension*)ctrlGroup.get())->attachments) + { + ai->default_device = default_device; + ai->UpdateDefaultDevice(); + } + } + } } -void ControllerEmu::ControlGroup::LoadConfig(IniFile::Section *sec, const std::string& defdev, const std::string& base) +void ControllerEmu::ControlGroup::LoadConfig(IniFile::Section* sec, const std::string& defdev, + const std::string& base) { - std::string group(base + name + "/"); + std::string group(base + name + "/"); - // settings - for (auto& s : settings) - { - if (s->is_virtual) - continue; - if (s->is_iterate) - continue; - sec->Get(group + s->name, &s->value, s->default_value * 100); - s->value /= 100; - } + // settings + for (auto& s : settings) + { + if (s->is_virtual) + continue; + if (s->is_iterate) + continue; + sec->Get(group + s->name, &s->value, s->default_value * 100); + s->value /= 100; + } - for (auto& c : controls) - { - // control expression - sec->Get(group + c->name, &c->control_ref->expression, ""); + for (auto& c : controls) + { + // control expression + sec->Get(group + c->name, &c->control_ref->expression, ""); - // range - sec->Get(group + c->name + "/Range", &c->control_ref->range, 100.0); - c->control_ref->range /= 100; + // range + sec->Get(group + c->name + "/Range", &c->control_ref->range, 100.0); + c->control_ref->range /= 100; + } - } + // extensions + if (type == GROUP_TYPE_EXTENSION) + { + Extension* const ext = (Extension*)this; - // extensions - if (type == GROUP_TYPE_EXTENSION) - { - Extension* const ext = (Extension*)this; + ext->switch_extension = 0; + unsigned int n = 0; + std::string extname; + sec->Get(base + name, &extname, ""); - ext->switch_extension = 0; - unsigned int n = 0; - std::string extname; - sec->Get(base + name, &extname, ""); + for (auto& ai : ext->attachments) + { + ai->default_device.FromString(defdev); + ai->LoadConfig(sec, base + ai->GetName() + "/"); - for (auto& ai : ext->attachments) - { - ai->default_device.FromString(defdev); - ai->LoadConfig(sec, base + ai->GetName() + "/"); + if (ai->GetName() == extname) + ext->switch_extension = n; - if (ai->GetName() == extname) - ext->switch_extension = n; - - n++; - } - } + n++; + } + } } -void ControllerEmu::LoadConfig(IniFile::Section *sec, const std::string& base) +void ControllerEmu::LoadConfig(IniFile::Section* sec, const std::string& base) { - std::string defdev = default_device.ToString(); - if (base.empty()) - { - sec->Get(base + "Device", &defdev, ""); - default_device.FromString(defdev); - } + std::string defdev = default_device.ToString(); + if (base.empty()) + { + sec->Get(base + "Device", &defdev, ""); + default_device.FromString(defdev); + } - for (auto& cg : groups) - cg->LoadConfig(sec, defdev, base); + for (auto& cg : groups) + cg->LoadConfig(sec, defdev, base); } -void ControllerEmu::ControlGroup::SaveConfig(IniFile::Section *sec, const std::string& defdev, const std::string& base) +void ControllerEmu::ControlGroup::SaveConfig(IniFile::Section* sec, const std::string& defdev, + const std::string& base) { - std::string group(base + name + "/"); + std::string group(base + name + "/"); - for (auto& s : settings) - { - if (s->is_virtual) - continue; - if (s->is_iterate) - continue; + for (auto& s : settings) + { + if (s->is_virtual) + continue; + if (s->is_iterate) + continue; - sec->Set(group + s->name, s->value * 100.0, s->default_value * 100.0); - } + sec->Set(group + s->name, s->value * 100.0, s->default_value * 100.0); + } - for (auto& c : controls) - { - // control expression - sec->Set(group + c->name, c->control_ref->expression, ""); + for (auto& c : controls) + { + // control expression + sec->Set(group + c->name, c->control_ref->expression, ""); - // range - sec->Set(group + c->name + "/Range", c->control_ref->range*100.0, 100.0); - } + // range + sec->Set(group + c->name + "/Range", c->control_ref->range * 100.0, 100.0); + } - // extensions - if (type == GROUP_TYPE_EXTENSION) - { - Extension* const ext = (Extension*)this; - sec->Set(base + name, ext->attachments[ext->switch_extension]->GetName(), "None"); + // extensions + if (type == GROUP_TYPE_EXTENSION) + { + Extension* const ext = (Extension*)this; + sec->Set(base + name, ext->attachments[ext->switch_extension]->GetName(), "None"); - for (auto& ai : ext->attachments) - ai->SaveConfig(sec, base + ai->GetName() + "/"); - } + for (auto& ai : ext->attachments) + ai->SaveConfig(sec, base + ai->GetName() + "/"); + } } -void ControllerEmu::SaveConfig(IniFile::Section *sec, const std::string& base) +void ControllerEmu::SaveConfig(IniFile::Section* sec, const std::string& base) { - const std::string defdev = default_device.ToString(); - if (base.empty()) - sec->Set(/*std::string(" ") +*/ base + "Device", defdev, ""); + const std::string defdev = default_device.ToString(); + if (base.empty()) + sec->Set(/*std::string(" ") +*/ base + "Device", defdev, ""); - for (auto& ctrlGroup : groups) - ctrlGroup->SaveConfig(sec, defdev, base); + for (auto& ctrlGroup : groups) + ctrlGroup->SaveConfig(sec, defdev, base); } void ControllerEmu::ControlGroup::SetControlExpression(int index, const std::string& expression) { - controls.at(index)->control_ref->expression = expression; + controls.at(index)->control_ref->expression = expression; } ControllerEmu::AnalogStick::AnalogStick(const char* const _name, ControlState default_radius) - : AnalogStick(_name, _name, GROUP_TYPE_STICK) -{} - -ControllerEmu::AnalogStick::AnalogStick(const char* const _name, const char* const _ui_name, ControlState default_radius) - : ControlGroup(_name, _ui_name, GROUP_TYPE_STICK) + : AnalogStick(_name, _name, GROUP_TYPE_STICK) { - for (auto& named_direction : named_directions) - controls.emplace_back(std::make_unique(named_direction)); +} - controls.emplace_back(std::make_unique(_trans("Modifier"))); - settings.emplace_back(std::make_unique(_trans("Radius"), default_radius, 0, 100)); - settings.emplace_back(std::make_unique(_trans("Dead Zone"), 0, 0, 50)); +ControllerEmu::AnalogStick::AnalogStick(const char* const _name, const char* const _ui_name, + ControlState default_radius) + : ControlGroup(_name, _ui_name, GROUP_TYPE_STICK) +{ + for (auto& named_direction : named_directions) + controls.emplace_back(std::make_unique(named_direction)); + + controls.emplace_back(std::make_unique(_trans("Modifier"))); + settings.emplace_back(std::make_unique(_trans("Radius"), default_radius, 0, 100)); + settings.emplace_back(std::make_unique(_trans("Dead Zone"), 0, 0, 50)); } ControllerEmu::Buttons::Buttons(const std::string& _name) : ControlGroup(_name, GROUP_TYPE_BUTTONS) { - settings.emplace_back(std::make_unique(_trans("Threshold"), 0.5)); + settings.emplace_back(std::make_unique(_trans("Threshold"), 0.5)); } -ControllerEmu::MixedTriggers::MixedTriggers(const std::string& _name) : ControlGroup(_name, GROUP_TYPE_MIXED_TRIGGERS) +ControllerEmu::MixedTriggers::MixedTriggers(const std::string& _name) + : ControlGroup(_name, GROUP_TYPE_MIXED_TRIGGERS) { - settings.emplace_back(std::make_unique(_trans("Threshold"), 0.9)); + settings.emplace_back(std::make_unique(_trans("Threshold"), 0.9)); } -ControllerEmu::Triggers::Triggers(const std::string& _name) : ControlGroup(_name, GROUP_TYPE_TRIGGERS) +ControllerEmu::Triggers::Triggers(const std::string& _name) + : ControlGroup(_name, GROUP_TYPE_TRIGGERS) { - settings.emplace_back(std::make_unique(_trans("Dead Zone"), 0, 0, 50)); + settings.emplace_back(std::make_unique(_trans("Dead Zone"), 0, 0, 50)); } ControllerEmu::Slider::Slider(const std::string& _name) : ControlGroup(_name, GROUP_TYPE_SLIDER) { - controls.emplace_back(std::make_unique("Left")); - controls.emplace_back(std::make_unique("Right")); + controls.emplace_back(std::make_unique("Left")); + controls.emplace_back(std::make_unique("Right")); - settings.emplace_back(std::make_unique(_trans("Dead Zone"), 0, 0, 50)); + settings.emplace_back(std::make_unique(_trans("Dead Zone"), 0, 0, 50)); } ControllerEmu::Force::Force(const std::string& _name) : ControlGroup(_name, GROUP_TYPE_FORCE) { - memset(m_swing, 0, sizeof(m_swing)); + memset(m_swing, 0, sizeof(m_swing)); - controls.emplace_back(std::make_unique(_trans("Up"))); - controls.emplace_back(std::make_unique(_trans("Down"))); - controls.emplace_back(std::make_unique(_trans("Left"))); - controls.emplace_back(std::make_unique(_trans("Right"))); - controls.emplace_back(std::make_unique(_trans("Forward"))); - controls.emplace_back(std::make_unique(_trans("Backward"))); + controls.emplace_back(std::make_unique(_trans("Up"))); + controls.emplace_back(std::make_unique(_trans("Down"))); + controls.emplace_back(std::make_unique(_trans("Left"))); + controls.emplace_back(std::make_unique(_trans("Right"))); + controls.emplace_back(std::make_unique(_trans("Forward"))); + controls.emplace_back(std::make_unique(_trans("Backward"))); - settings.emplace_back(std::make_unique(_trans("Dead Zone"), 0, 0, 50)); + settings.emplace_back(std::make_unique(_trans("Dead Zone"), 0, 0, 50)); } ControllerEmu::Tilt::Tilt(const std::string& _name) : ControlGroup(_name, GROUP_TYPE_TILT) { - memset(m_tilt, 0, sizeof(m_tilt)); + memset(m_tilt, 0, sizeof(m_tilt)); - controls.emplace_back(std::make_unique("Forward")); - controls.emplace_back(std::make_unique("Backward")); - controls.emplace_back(std::make_unique("Left")); - controls.emplace_back(std::make_unique("Right")); + controls.emplace_back(std::make_unique("Forward")); + controls.emplace_back(std::make_unique("Backward")); + controls.emplace_back(std::make_unique("Left")); + controls.emplace_back(std::make_unique("Right")); - controls.emplace_back(std::make_unique(_trans("Modifier"))); + controls.emplace_back(std::make_unique(_trans("Modifier"))); - settings.emplace_back(std::make_unique(_trans("Dead Zone"), 0, 0, 50)); - settings.emplace_back(std::make_unique(_trans("Circle Stick"), 0)); - settings.emplace_back(std::make_unique(_trans("Angle"), 0.9, 0, 180)); + settings.emplace_back(std::make_unique(_trans("Dead Zone"), 0, 0, 50)); + settings.emplace_back(std::make_unique(_trans("Circle Stick"), 0)); + settings.emplace_back(std::make_unique(_trans("Angle"), 0.9, 0, 180)); } ControllerEmu::Cursor::Cursor(const std::string& _name) - : ControlGroup(_name, GROUP_TYPE_CURSOR) - , m_z(0) + : ControlGroup(_name, GROUP_TYPE_CURSOR), m_z(0) { - for (auto& named_direction : named_directions) - controls.emplace_back(std::make_unique(named_direction)); - controls.emplace_back(std::make_unique("Forward")); - controls.emplace_back(std::make_unique("Backward")); - controls.emplace_back(std::make_unique(_trans("Hide"))); + for (auto& named_direction : named_directions) + controls.emplace_back(std::make_unique(named_direction)); + controls.emplace_back(std::make_unique("Forward")); + controls.emplace_back(std::make_unique("Backward")); + controls.emplace_back(std::make_unique(_trans("Hide"))); - settings.emplace_back(std::make_unique(_trans("Center"), 0.5)); - settings.emplace_back(std::make_unique(_trans("Width"), 0.5)); - settings.emplace_back(std::make_unique(_trans("Height"), 0.5)); + settings.emplace_back(std::make_unique(_trans("Center"), 0.5)); + settings.emplace_back(std::make_unique(_trans("Width"), 0.5)); + settings.emplace_back(std::make_unique(_trans("Height"), 0.5)); } -void ControllerEmu::LoadDefaults(const ControllerInterface &ciface) +void ControllerEmu::LoadDefaults(const ControllerInterface& ciface) { - // load an empty inifile section, clears everything - IniFile::Section sec; - LoadConfig(&sec); + // load an empty inifile section, clears everything + IniFile::Section sec; + LoadConfig(&sec); - if (ciface.Devices().size()) - { - default_device.FromDevice(ciface.Devices()[0]); - UpdateDefaultDevice(); - } + if (ciface.Devices().size()) + { + default_device.FromDevice(ciface.Devices()[0]); + UpdateDefaultDevice(); + } } diff --git a/Source/Core/InputCommon/ControllerEmu.h b/Source/Core/InputCommon/ControllerEmu.h index 6fcc30e9e3..56e469ee8e 100644 --- a/Source/Core/InputCommon/ControllerEmu.h +++ b/Source/Core/InputCommon/ControllerEmu.h @@ -12,446 +12,423 @@ #include "Common/IniFile.h" #include "Core/ConfigManager.h" -#include "InputCommon/GCPadStatus.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" +#include "InputCommon/GCPadStatus.h" -#define sign(x) ((x)?(x)<0?-1:1:0) +#define sign(x) ((x) ? (x) < 0 ? -1 : 1 : 0) enum { - GROUP_TYPE_OTHER, - GROUP_TYPE_STICK, - GROUP_TYPE_MIXED_TRIGGERS, - GROUP_TYPE_BUTTONS, - GROUP_TYPE_FORCE, - GROUP_TYPE_EXTENSION, - GROUP_TYPE_TILT, - GROUP_TYPE_CURSOR, - GROUP_TYPE_TRIGGERS, - GROUP_TYPE_SLIDER + GROUP_TYPE_OTHER, + GROUP_TYPE_STICK, + GROUP_TYPE_MIXED_TRIGGERS, + GROUP_TYPE_BUTTONS, + GROUP_TYPE_FORCE, + GROUP_TYPE_EXTENSION, + GROUP_TYPE_TILT, + GROUP_TYPE_CURSOR, + GROUP_TYPE_TRIGGERS, + GROUP_TYPE_SLIDER }; enum { - SETTING_RADIUS, - SETTING_DEADZONE, + SETTING_RADIUS, + SETTING_DEADZONE, }; -const char* const named_directions[] = -{ - "Up", - "Down", - "Left", - "Right" -}; +const char* const named_directions[] = {"Up", "Down", "Left", "Right"}; class ControllerEmu { public: - - class ControlGroup - { - public: - - class Control - { - protected: - Control(ControllerInterface::ControlReference* const _ref, const std::string& _name) - : control_ref(_ref), name(_name) {} - - public: - virtual ~Control() {} - std::unique_ptr const control_ref; - const std::string name; - - }; - - class Input : public Control - { - public: - - Input(const std::string& _name) - : Control(new ControllerInterface::InputReference, _name) {} - }; - - class Output : public Control - { - public: - - Output(const std::string& _name) - : Control(new ControllerInterface::OutputReference, _name) {} - }; - - class Setting - { - public: - Setting(const std::string& _name, const ControlState def_value - , const unsigned int _low = 0, const unsigned int _high = 100) - : name(_name) - , value(def_value) - , default_value(def_value) - , low(_low) - , high(_high) - , is_virtual(false) - , is_iterate(false) {} - - virtual ~Setting() - { - } - - const std::string name; - ControlState value; - const ControlState default_value; - const unsigned int low, high; - bool is_virtual; - bool is_iterate; - - virtual void SetValue(ControlState new_value) - { - value = new_value; - } - - virtual ControlState GetValue() - { - return value; - } - }; - - class BackgroundInputSetting : public Setting - { - public: - BackgroundInputSetting(const std::string &_name) : Setting(_name, false) - { - is_virtual = true; - } - - void SetValue(ControlState new_value) override - { - SConfig::GetInstance().m_BackgroundInput = !!new_value; - } - - ControlState GetValue() override - { - return SConfig::GetInstance().m_BackgroundInput; - } - }; - - class IterateUI : public Setting - { - public: - IterateUI(const std::string &_name) : Setting(_name, false) - { - is_iterate = true; - } - }; - - ControlGroup(const std::string& _name, const unsigned int _type = GROUP_TYPE_OTHER) - : name(_name), ui_name(_name), type(_type) {} - ControlGroup(const std::string& _name, const std::string& _ui_name, const unsigned int _type = GROUP_TYPE_OTHER) - : name(_name), ui_name(_ui_name), type(_type) {} - virtual ~ControlGroup() {} - - virtual void LoadConfig(IniFile::Section *sec, const std::string& defdev = "", const std::string& base = "" ); - virtual void SaveConfig(IniFile::Section *sec, const std::string& defdev = "", const std::string& base = "" ); - - void SetControlExpression(int index, const std::string& expression); - - const std::string name; - const std::string ui_name; - const unsigned int type; - - std::vector> controls; - std::vector> settings; - - }; - - class AnalogStick : public ControlGroup - { - public: - // The GameCube controller and Wiimote attachments have a different default radius - AnalogStick(const char* const _name, ControlState default_radius); - AnalogStick(const char* const _name, const char* const _ui_name, ControlState default_radius); - - void GetState(ControlState* const x, ControlState* const y) - { - ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State(); - ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State(); - - ControlState radius = settings[SETTING_RADIUS]->value; - ControlState deadzone = settings[SETTING_DEADZONE]->value; - ControlState m = controls[4]->control_ref->State(); - - ControlState ang = atan2(yy, xx); - ControlState ang_sin = sin(ang); - ControlState ang_cos = cos(ang); - - ControlState dist = sqrt(xx*xx + yy*yy); - - // dead zone code - dist = std::max(0.0, dist - deadzone); - dist /= (1 - deadzone); - - // radius - dist *= radius; - - // The modifier halves the distance by 50%, which is useful - // for keyboard controls. - if (m) - dist *= 0.5; - - yy = std::max(-1.0, std::min(1.0, ang_sin * dist)); - xx = std::max(-1.0, std::min(1.0, ang_cos * dist)); - - *y = yy; - *x = xx; - } - }; - - class Buttons : public ControlGroup - { - public: - Buttons(const std::string& _name); - - template - void GetState(C* const buttons, const C* bitmasks) - { - for (auto& control : controls) - { - if (control->control_ref->State() > settings[0]->value) // threshold - *buttons |= *bitmasks; - - bitmasks++; - } - } - - }; - - class MixedTriggers : public ControlGroup - { - public: - MixedTriggers(const std::string& _name); - - void GetState(u16 *const digital, const u16* bitmasks, ControlState* analog) - { - const unsigned int trig_count = ((unsigned int) (controls.size() / 2)); - for (unsigned int i=0; icontrol_ref->State() > settings[0]->value) //threshold - { - *analog = 1.0; - *digital |= *bitmasks; - } - else - { - *analog = controls[i+trig_count]->control_ref->State(); - } - } - } - }; - - class Triggers : public ControlGroup - { - public: - Triggers(const std::string& _name); - - void GetState(ControlState* analog) - { - const unsigned int trig_count = ((unsigned int) (controls.size())); - const ControlState deadzone = settings[0]->value; - for (unsigned int i=0; icontrol_ref->State() - deadzone, 0.0) / (1 - deadzone); - } - }; - - class Slider : public ControlGroup - { - public: - Slider(const std::string& _name); - - void GetState(ControlState* const slider) - { - const ControlState deadzone = settings[0]->value; - const ControlState state = controls[1]->control_ref->State() - controls[0]->control_ref->State(); - - if (fabs(state) > deadzone) - *slider = (state - (deadzone * sign(state))) / (1 - deadzone); - else - *slider = 0; - } - }; - - class Force : public ControlGroup - { - public: - Force(const std::string& _name); - - void GetState(ControlState* axis) - { - const ControlState deadzone = settings[0]->value; - for (unsigned int i = 0; i < 6; i += 2) - { - ControlState tmpf = 0; - const ControlState state = controls[i+1]->control_ref->State() - controls[i]->control_ref->State(); - if (fabs(state) > deadzone) - tmpf = ((state - (deadzone * sign(state))) / (1 - deadzone)); - - ControlState &ax = m_swing[i >> 1]; - *axis++ = (tmpf - ax); - ax = tmpf; - } - } - - private: - ControlState m_swing[3]; - }; - - class Tilt : public ControlGroup - { - public: - Tilt(const std::string& _name); - - void GetState(ControlState* const x, ControlState* const y, const bool step = true) - { - // this is all a mess - - ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State(); - ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State(); - - ControlState deadzone = settings[0]->value; - ControlState circle = settings[1]->value; - auto const angle = settings[2]->value / 1.8; - ControlState m = controls[4]->control_ref->State(); - - // deadzone / circle stick code - // this section might be all wrong, but its working good enough, I think - - ControlState ang = atan2(yy, xx); - ControlState ang_sin = sin(ang); - ControlState ang_cos = cos(ang); - - // the amt a full square stick would have at current angle - ControlState square_full = std::min(ang_sin ? 1/fabs(ang_sin) : 2, ang_cos ? 1/fabs(ang_cos) : 2); - - // the amt a full stick would have that was (user setting circular) at current angle - // I think this is more like a pointed circle rather than a rounded square like it should be - ControlState stick_full = (square_full * (1 - circle)) + (circle); - - ControlState dist = sqrt(xx*xx + yy*yy); - - // dead zone code - dist = std::max(0.0, dist - deadzone * stick_full); - dist /= (1 - deadzone); - - // circle stick code - ControlState amt = dist / stick_full; - dist += (square_full - 1) * amt * circle; - - if (m) - dist *= 0.5; - - yy = std::max(-1.0, std::min(1.0, ang_sin * dist)); - xx = std::max(-1.0, std::min(1.0, ang_cos * dist)); - - // this is kinda silly here - // gui being open will make this happen 2x as fast, o well - - // silly - if (step) - { - if (xx > m_tilt[0]) - m_tilt[0] = std::min(m_tilt[0] + 0.1, xx); - else if (xx < m_tilt[0]) - m_tilt[0] = std::max(m_tilt[0] - 0.1, xx); - - if (yy > m_tilt[1]) - m_tilt[1] = std::min(m_tilt[1] + 0.1, yy); - else if (yy < m_tilt[1]) - m_tilt[1] = std::max(m_tilt[1] - 0.1, yy); - } - - *y = m_tilt[1] * angle; - *x = m_tilt[0] * angle; - } - - private: - ControlState m_tilt[2]; - }; - - class Cursor : public ControlGroup - { - public: - Cursor(const std::string& _name); - - void GetState(ControlState* const x, ControlState* const y, ControlState* const z, const bool adjusted = false) - { - const ControlState zz = controls[4]->control_ref->State() - controls[5]->control_ref->State(); - - // silly being here - if (zz > m_z) - m_z = std::min(m_z + 0.1, zz); - else if (zz < m_z) - m_z = std::max(m_z - 0.1, zz); - - *z = m_z; - - // hide - if (controls[6]->control_ref->State() > 0.5) - { - *x = 10000; *y = 0; - } - else - { - ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State(); - ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State(); - - // adjust cursor according to settings - if (adjusted) - { - xx *= (settings[1]->value * 2); - yy *= (settings[2]->value * 2); - yy += (settings[0]->value - 0.5); - } - - *x = xx; - *y = yy; - } - } - - ControlState m_z; - }; - - class Extension : public ControlGroup - { - public: - Extension(const std::string& _name) - : ControlGroup(_name, GROUP_TYPE_EXTENSION) - , switch_extension(0) - , active_extension(0) {} - - ~Extension() {} - - void GetState(u8* const data); - bool IsButtonPressed() const; - - std::vector> attachments; - - int switch_extension; - int active_extension; - }; - - virtual ~ControllerEmu() {} - - virtual std::string GetName() const = 0; - - virtual void LoadDefaults(const ControllerInterface& ciface); - - virtual void LoadConfig(IniFile::Section *sec, const std::string& base = ""); - virtual void SaveConfig(IniFile::Section *sec, const std::string& base = ""); - void UpdateDefaultDevice(); - - void UpdateReferences(ControllerInterface& devi); - - std::vector> groups; - - ciface::Core::DeviceQualifier default_device; + class ControlGroup + { + public: + class Control + { + protected: + Control(ControllerInterface::ControlReference* const _ref, const std::string& _name) + : control_ref(_ref), name(_name) + { + } + + public: + virtual ~Control() {} + std::unique_ptr const control_ref; + const std::string name; + }; + + class Input : public Control + { + public: + Input(const std::string& _name) : Control(new ControllerInterface::InputReference, _name) {} + }; + + class Output : public Control + { + public: + Output(const std::string& _name) : Control(new ControllerInterface::OutputReference, _name) {} + }; + + class Setting + { + public: + Setting(const std::string& _name, const ControlState def_value, const unsigned int _low = 0, + const unsigned int _high = 100) + : name(_name), value(def_value), default_value(def_value), low(_low), high(_high), + is_virtual(false), is_iterate(false) + { + } + + virtual ~Setting() {} + const std::string name; + ControlState value; + const ControlState default_value; + const unsigned int low, high; + bool is_virtual; + bool is_iterate; + + virtual void SetValue(ControlState new_value) { value = new_value; } + virtual ControlState GetValue() { return value; } + }; + + class BackgroundInputSetting : public Setting + { + public: + BackgroundInputSetting(const std::string& _name) : Setting(_name, false) + { + is_virtual = true; + } + + void SetValue(ControlState new_value) override + { + SConfig::GetInstance().m_BackgroundInput = !!new_value; + } + + ControlState GetValue() override { return SConfig::GetInstance().m_BackgroundInput; } + }; + + class IterateUI : public Setting + { + public: + IterateUI(const std::string& _name) : Setting(_name, false) { is_iterate = true; } + }; + + ControlGroup(const std::string& _name, const unsigned int _type = GROUP_TYPE_OTHER) + : name(_name), ui_name(_name), type(_type) + { + } + ControlGroup(const std::string& _name, const std::string& _ui_name, + const unsigned int _type = GROUP_TYPE_OTHER) + : name(_name), ui_name(_ui_name), type(_type) + { + } + virtual ~ControlGroup() {} + virtual void LoadConfig(IniFile::Section* sec, const std::string& defdev = "", + const std::string& base = ""); + virtual void SaveConfig(IniFile::Section* sec, const std::string& defdev = "", + const std::string& base = ""); + + void SetControlExpression(int index, const std::string& expression); + + const std::string name; + const std::string ui_name; + const unsigned int type; + + std::vector> controls; + std::vector> settings; + }; + + class AnalogStick : public ControlGroup + { + public: + // The GameCube controller and Wiimote attachments have a different default radius + AnalogStick(const char* const _name, ControlState default_radius); + AnalogStick(const char* const _name, const char* const _ui_name, ControlState default_radius); + + void GetState(ControlState* const x, ControlState* const y) + { + ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State(); + ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State(); + + ControlState radius = settings[SETTING_RADIUS]->value; + ControlState deadzone = settings[SETTING_DEADZONE]->value; + ControlState m = controls[4]->control_ref->State(); + + ControlState ang = atan2(yy, xx); + ControlState ang_sin = sin(ang); + ControlState ang_cos = cos(ang); + + ControlState dist = sqrt(xx * xx + yy * yy); + + // dead zone code + dist = std::max(0.0, dist - deadzone); + dist /= (1 - deadzone); + + // radius + dist *= radius; + + // The modifier halves the distance by 50%, which is useful + // for keyboard controls. + if (m) + dist *= 0.5; + + yy = std::max(-1.0, std::min(1.0, ang_sin * dist)); + xx = std::max(-1.0, std::min(1.0, ang_cos * dist)); + + *y = yy; + *x = xx; + } + }; + + class Buttons : public ControlGroup + { + public: + Buttons(const std::string& _name); + + template + void GetState(C* const buttons, const C* bitmasks) + { + for (auto& control : controls) + { + if (control->control_ref->State() > settings[0]->value) // threshold + *buttons |= *bitmasks; + + bitmasks++; + } + } + }; + + class MixedTriggers : public ControlGroup + { + public: + MixedTriggers(const std::string& _name); + + void GetState(u16* const digital, const u16* bitmasks, ControlState* analog) + { + const unsigned int trig_count = ((unsigned int)(controls.size() / 2)); + for (unsigned int i = 0; i < trig_count; ++i, ++bitmasks, ++analog) + { + if (controls[i]->control_ref->State() > settings[0]->value) // threshold + { + *analog = 1.0; + *digital |= *bitmasks; + } + else + { + *analog = controls[i + trig_count]->control_ref->State(); + } + } + } + }; + + class Triggers : public ControlGroup + { + public: + Triggers(const std::string& _name); + + void GetState(ControlState* analog) + { + const unsigned int trig_count = ((unsigned int)(controls.size())); + const ControlState deadzone = settings[0]->value; + for (unsigned int i = 0; i < trig_count; ++i, ++analog) + *analog = std::max(controls[i]->control_ref->State() - deadzone, 0.0) / (1 - deadzone); + } + }; + + class Slider : public ControlGroup + { + public: + Slider(const std::string& _name); + + void GetState(ControlState* const slider) + { + const ControlState deadzone = settings[0]->value; + const ControlState state = + controls[1]->control_ref->State() - controls[0]->control_ref->State(); + + if (fabs(state) > deadzone) + *slider = (state - (deadzone * sign(state))) / (1 - deadzone); + else + *slider = 0; + } + }; + + class Force : public ControlGroup + { + public: + Force(const std::string& _name); + + void GetState(ControlState* axis) + { + const ControlState deadzone = settings[0]->value; + for (unsigned int i = 0; i < 6; i += 2) + { + ControlState tmpf = 0; + const ControlState state = + controls[i + 1]->control_ref->State() - controls[i]->control_ref->State(); + if (fabs(state) > deadzone) + tmpf = ((state - (deadzone * sign(state))) / (1 - deadzone)); + + ControlState& ax = m_swing[i >> 1]; + *axis++ = (tmpf - ax); + ax = tmpf; + } + } + + private: + ControlState m_swing[3]; + }; + + class Tilt : public ControlGroup + { + public: + Tilt(const std::string& _name); + + void GetState(ControlState* const x, ControlState* const y, const bool step = true) + { + // this is all a mess + + ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State(); + ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State(); + + ControlState deadzone = settings[0]->value; + ControlState circle = settings[1]->value; + auto const angle = settings[2]->value / 1.8; + ControlState m = controls[4]->control_ref->State(); + + // deadzone / circle stick code + // this section might be all wrong, but its working good enough, I think + + ControlState ang = atan2(yy, xx); + ControlState ang_sin = sin(ang); + ControlState ang_cos = cos(ang); + + // the amt a full square stick would have at current angle + ControlState square_full = + std::min(ang_sin ? 1 / fabs(ang_sin) : 2, ang_cos ? 1 / fabs(ang_cos) : 2); + + // the amt a full stick would have that was (user setting circular) at current angle + // I think this is more like a pointed circle rather than a rounded square like it should be + ControlState stick_full = (square_full * (1 - circle)) + (circle); + + ControlState dist = sqrt(xx * xx + yy * yy); + + // dead zone code + dist = std::max(0.0, dist - deadzone * stick_full); + dist /= (1 - deadzone); + + // circle stick code + ControlState amt = dist / stick_full; + dist += (square_full - 1) * amt * circle; + + if (m) + dist *= 0.5; + + yy = std::max(-1.0, std::min(1.0, ang_sin * dist)); + xx = std::max(-1.0, std::min(1.0, ang_cos * dist)); + + // this is kinda silly here + // gui being open will make this happen 2x as fast, o well + + // silly + if (step) + { + if (xx > m_tilt[0]) + m_tilt[0] = std::min(m_tilt[0] + 0.1, xx); + else if (xx < m_tilt[0]) + m_tilt[0] = std::max(m_tilt[0] - 0.1, xx); + + if (yy > m_tilt[1]) + m_tilt[1] = std::min(m_tilt[1] + 0.1, yy); + else if (yy < m_tilt[1]) + m_tilt[1] = std::max(m_tilt[1] - 0.1, yy); + } + + *y = m_tilt[1] * angle; + *x = m_tilt[0] * angle; + } + + private: + ControlState m_tilt[2]; + }; + + class Cursor : public ControlGroup + { + public: + Cursor(const std::string& _name); + + void GetState(ControlState* const x, ControlState* const y, ControlState* const z, + const bool adjusted = false) + { + const ControlState zz = controls[4]->control_ref->State() - controls[5]->control_ref->State(); + + // silly being here + if (zz > m_z) + m_z = std::min(m_z + 0.1, zz); + else if (zz < m_z) + m_z = std::max(m_z - 0.1, zz); + + *z = m_z; + + // hide + if (controls[6]->control_ref->State() > 0.5) + { + *x = 10000; + *y = 0; + } + else + { + ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State(); + ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State(); + + // adjust cursor according to settings + if (adjusted) + { + xx *= (settings[1]->value * 2); + yy *= (settings[2]->value * 2); + yy += (settings[0]->value - 0.5); + } + + *x = xx; + *y = yy; + } + } + + ControlState m_z; + }; + + class Extension : public ControlGroup + { + public: + Extension(const std::string& _name) + : ControlGroup(_name, GROUP_TYPE_EXTENSION), switch_extension(0), active_extension(0) + { + } + + ~Extension() {} + void GetState(u8* const data); + bool IsButtonPressed() const; + + std::vector> attachments; + + int switch_extension; + int active_extension; + }; + + virtual ~ControllerEmu() {} + virtual std::string GetName() const = 0; + + virtual void LoadDefaults(const ControllerInterface& ciface); + + virtual void LoadConfig(IniFile::Section* sec, const std::string& base = ""); + virtual void SaveConfig(IniFile::Section* sec, const std::string& base = ""); + void UpdateDefaultDevice(); + + void UpdateReferences(ControllerInterface& devi); + + std::vector> groups; + + ciface::Core::DeviceQualifier default_device; }; diff --git a/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp b/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp index c70f0cc3ed..3d68be633f 100644 --- a/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp @@ -2,193 +2,227 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include #include "InputCommon/ControllerInterface/Android/Android.h" +#include namespace ciface { - namespace Android { - -void Init( std::vector& devices ) +void Init(std::vector& devices) { - devices.push_back(new Touchscreen(0)); - devices.push_back(new Touchscreen(1)); - devices.push_back(new Touchscreen(2)); - devices.push_back(new Touchscreen(3)); - devices.push_back(new Touchscreen(4)); - devices.push_back(new Touchscreen(5)); - devices.push_back(new Touchscreen(6)); - devices.push_back(new Touchscreen(7)); + devices.push_back(new Touchscreen(0)); + devices.push_back(new Touchscreen(1)); + devices.push_back(new Touchscreen(2)); + devices.push_back(new Touchscreen(3)); + devices.push_back(new Touchscreen(4)); + devices.push_back(new Touchscreen(5)); + devices.push_back(new Touchscreen(6)); + devices.push_back(new Touchscreen(7)); } // Touchscreens and stuff std::string Touchscreen::GetName() const { - return "Touchscreen"; + return "Touchscreen"; } std::string Touchscreen::GetSource() const { - return "Android"; + return "Android"; } int Touchscreen::GetId() const { - return _padID; + return _padID; } -Touchscreen::Touchscreen(int padID) - : _padID(padID) +Touchscreen::Touchscreen(int padID) : _padID(padID) { - // GC - AddInput(new Button(_padID, ButtonManager::BUTTON_A)); - AddInput(new Button(_padID, ButtonManager::BUTTON_B)); - AddInput(new Button(_padID, ButtonManager::BUTTON_START)); - AddInput(new Button(_padID, ButtonManager::BUTTON_X)); - AddInput(new Button(_padID, ButtonManager::BUTTON_Y)); - AddInput(new Button(_padID, ButtonManager::BUTTON_Z)); - AddInput(new Button(_padID, ButtonManager::BUTTON_UP)); - AddInput(new Button(_padID, ButtonManager::BUTTON_DOWN)); - AddInput(new Button(_padID, ButtonManager::BUTTON_LEFT)); - AddInput(new Button(_padID, ButtonManager::BUTTON_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::STICK_MAIN_LEFT), new Axis(_padID, ButtonManager::STICK_MAIN_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::STICK_MAIN_UP), new Axis(_padID, ButtonManager::STICK_MAIN_DOWN)); - AddAnalogInputs(new Axis(_padID, ButtonManager::STICK_C_LEFT), new Axis(_padID, ButtonManager::STICK_C_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::STICK_C_UP), new Axis(_padID, ButtonManager::STICK_C_DOWN)); - AddAnalogInputs(new Axis(_padID, ButtonManager::TRIGGER_L), new Axis(_padID, ButtonManager::TRIGGER_L)); - AddAnalogInputs(new Axis(_padID, ButtonManager::TRIGGER_R), new Axis(_padID, ButtonManager::TRIGGER_R)); + // GC + AddInput(new Button(_padID, ButtonManager::BUTTON_A)); + AddInput(new Button(_padID, ButtonManager::BUTTON_B)); + AddInput(new Button(_padID, ButtonManager::BUTTON_START)); + AddInput(new Button(_padID, ButtonManager::BUTTON_X)); + AddInput(new Button(_padID, ButtonManager::BUTTON_Y)); + AddInput(new Button(_padID, ButtonManager::BUTTON_Z)); + AddInput(new Button(_padID, ButtonManager::BUTTON_UP)); + AddInput(new Button(_padID, ButtonManager::BUTTON_DOWN)); + AddInput(new Button(_padID, ButtonManager::BUTTON_LEFT)); + AddInput(new Button(_padID, ButtonManager::BUTTON_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::STICK_MAIN_LEFT), + new Axis(_padID, ButtonManager::STICK_MAIN_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::STICK_MAIN_UP), + new Axis(_padID, ButtonManager::STICK_MAIN_DOWN)); + AddAnalogInputs(new Axis(_padID, ButtonManager::STICK_C_LEFT), + new Axis(_padID, ButtonManager::STICK_C_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::STICK_C_UP), + new Axis(_padID, ButtonManager::STICK_C_DOWN)); + AddAnalogInputs(new Axis(_padID, ButtonManager::TRIGGER_L), + new Axis(_padID, ButtonManager::TRIGGER_L)); + AddAnalogInputs(new Axis(_padID, ButtonManager::TRIGGER_R), + new Axis(_padID, ButtonManager::TRIGGER_R)); - // Wiimote - AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_A)); - AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_B)); - AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_MINUS)); - AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_PLUS)); - AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_HOME)); - AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_1)); - AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_2)); - AddInput(new Button(_padID, ButtonManager::WIIMOTE_UP)); - AddInput(new Button(_padID, ButtonManager::WIIMOTE_DOWN)); - AddInput(new Button(_padID, ButtonManager::WIIMOTE_LEFT)); - AddInput(new Button(_padID, ButtonManager::WIIMOTE_RIGHT)); - AddInput(new Button(_padID, ButtonManager::WIIMOTE_IR_HIDE)); - AddInput(new Button(_padID, ButtonManager::WIIMOTE_TILT_MODIFIER)); - AddInput(new Button(_padID, ButtonManager::WIIMOTE_SHAKE_X)); - AddInput(new Button(_padID, ButtonManager::WIIMOTE_SHAKE_Y)); - AddInput(new Button(_padID, ButtonManager::WIIMOTE_SHAKE_Z)); - AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_IR_UP), new Axis(_padID, ButtonManager::WIIMOTE_IR_DOWN)); - AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_IR_LEFT), new Axis(_padID, ButtonManager::WIIMOTE_IR_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_IR_FORWARD), new Axis(_padID, ButtonManager::WIIMOTE_IR_BACKWARD)); - AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_SWING_UP), new Axis(_padID, ButtonManager::WIIMOTE_SWING_DOWN)); - AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_SWING_LEFT), new Axis(_padID, ButtonManager::WIIMOTE_SWING_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_SWING_FORWARD), new Axis(_padID, ButtonManager::WIIMOTE_SWING_BACKWARD)); - AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_TILT_LEFT), new Axis(_padID, ButtonManager::WIIMOTE_TILT_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_TILT_FORWARD), new Axis(_padID, ButtonManager::WIIMOTE_TILT_BACKWARD)); + // Wiimote + AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_A)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_B)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_MINUS)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_PLUS)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_HOME)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_1)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_BUTTON_2)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_UP)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_DOWN)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_LEFT)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_RIGHT)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_IR_HIDE)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_TILT_MODIFIER)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_SHAKE_X)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_SHAKE_Y)); + AddInput(new Button(_padID, ButtonManager::WIIMOTE_SHAKE_Z)); + AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_IR_UP), + new Axis(_padID, ButtonManager::WIIMOTE_IR_DOWN)); + AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_IR_LEFT), + new Axis(_padID, ButtonManager::WIIMOTE_IR_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_IR_FORWARD), + new Axis(_padID, ButtonManager::WIIMOTE_IR_BACKWARD)); + AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_SWING_UP), + new Axis(_padID, ButtonManager::WIIMOTE_SWING_DOWN)); + AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_SWING_LEFT), + new Axis(_padID, ButtonManager::WIIMOTE_SWING_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_SWING_FORWARD), + new Axis(_padID, ButtonManager::WIIMOTE_SWING_BACKWARD)); + AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_TILT_LEFT), + new Axis(_padID, ButtonManager::WIIMOTE_TILT_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::WIIMOTE_TILT_FORWARD), + new Axis(_padID, ButtonManager::WIIMOTE_TILT_BACKWARD)); - //Wii ext: Nunchuk - AddInput(new Button(_padID, ButtonManager::NUNCHUK_BUTTON_C)); - AddInput(new Button(_padID, ButtonManager::NUNCHUK_BUTTON_Z)); - AddInput(new Button(_padID, ButtonManager::NUNCHUK_TILT_MODIFIER)); - AddInput(new Button(_padID, ButtonManager::NUNCHUK_SHAKE_X)); - AddInput(new Button(_padID, ButtonManager::NUNCHUK_SHAKE_Y)); - AddInput(new Button(_padID, ButtonManager::NUNCHUK_SHAKE_Z)); - AddAnalogInputs(new Axis(_padID, ButtonManager::NUNCHUK_STICK_LEFT), new Axis(_padID, ButtonManager::NUNCHUK_STICK_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::NUNCHUK_STICK_UP), new Axis(_padID, ButtonManager::NUNCHUK_STICK_DOWN)); - AddAnalogInputs(new Axis(_padID, ButtonManager::NUNCHUK_SWING_LEFT), new Axis(_padID, ButtonManager::NUNCHUK_SWING_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::NUNCHUK_SWING_UP), new Axis(_padID, ButtonManager::NUNCHUK_SWING_DOWN)); - AddAnalogInputs(new Axis(_padID, ButtonManager::NUNCHUK_SWING_FORWARD), new Axis(_padID, ButtonManager::NUNCHUK_SWING_BACKWARD)); - AddAnalogInputs(new Axis(_padID, ButtonManager::NUNCHUK_TILT_LEFT), new Axis(_padID, ButtonManager::NUNCHUK_TILT_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::NUNCHUK_TILT_FORWARD), new Axis(_padID, ButtonManager::NUNCHUK_TILT_BACKWARD)); + // Wii ext: Nunchuk + AddInput(new Button(_padID, ButtonManager::NUNCHUK_BUTTON_C)); + AddInput(new Button(_padID, ButtonManager::NUNCHUK_BUTTON_Z)); + AddInput(new Button(_padID, ButtonManager::NUNCHUK_TILT_MODIFIER)); + AddInput(new Button(_padID, ButtonManager::NUNCHUK_SHAKE_X)); + AddInput(new Button(_padID, ButtonManager::NUNCHUK_SHAKE_Y)); + AddInput(new Button(_padID, ButtonManager::NUNCHUK_SHAKE_Z)); + AddAnalogInputs(new Axis(_padID, ButtonManager::NUNCHUK_STICK_LEFT), + new Axis(_padID, ButtonManager::NUNCHUK_STICK_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::NUNCHUK_STICK_UP), + new Axis(_padID, ButtonManager::NUNCHUK_STICK_DOWN)); + AddAnalogInputs(new Axis(_padID, ButtonManager::NUNCHUK_SWING_LEFT), + new Axis(_padID, ButtonManager::NUNCHUK_SWING_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::NUNCHUK_SWING_UP), + new Axis(_padID, ButtonManager::NUNCHUK_SWING_DOWN)); + AddAnalogInputs(new Axis(_padID, ButtonManager::NUNCHUK_SWING_FORWARD), + new Axis(_padID, ButtonManager::NUNCHUK_SWING_BACKWARD)); + AddAnalogInputs(new Axis(_padID, ButtonManager::NUNCHUK_TILT_LEFT), + new Axis(_padID, ButtonManager::NUNCHUK_TILT_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::NUNCHUK_TILT_FORWARD), + new Axis(_padID, ButtonManager::NUNCHUK_TILT_BACKWARD)); - // Wii ext: Classic - AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_A)); - AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_B)); - AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_X)); - AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_Y)); - AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_MINUS)); - AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_PLUS)); - AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_HOME)); - AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_ZL)); - AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_ZR)); - AddInput(new Button(_padID, ButtonManager::CLASSIC_DPAD_UP)); - AddInput(new Button(_padID, ButtonManager::CLASSIC_DPAD_DOWN)); - AddInput(new Button(_padID, ButtonManager::CLASSIC_DPAD_LEFT)); - AddInput(new Button(_padID, ButtonManager::CLASSIC_DPAD_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::CLASSIC_STICK_LEFT_LEFT), new Axis(_padID, ButtonManager::CLASSIC_STICK_LEFT_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::CLASSIC_STICK_LEFT_UP), new Axis(_padID, ButtonManager::CLASSIC_STICK_LEFT_DOWN)); - AddAnalogInputs(new Axis(_padID, ButtonManager::CLASSIC_STICK_RIGHT_LEFT), new Axis(_padID, ButtonManager::CLASSIC_STICK_RIGHT_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::CLASSIC_STICK_RIGHT_UP), new Axis(_padID, ButtonManager::CLASSIC_STICK_RIGHT_DOWN)); - AddAnalogInputs(new Axis(_padID, ButtonManager::CLASSIC_TRIGGER_L), new Axis(_padID, ButtonManager::CLASSIC_TRIGGER_L)); - AddAnalogInputs(new Axis(_padID, ButtonManager::CLASSIC_TRIGGER_R), new Axis(_padID, ButtonManager::CLASSIC_TRIGGER_R)); + // Wii ext: Classic + AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_A)); + AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_B)); + AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_X)); + AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_Y)); + AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_MINUS)); + AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_PLUS)); + AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_HOME)); + AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_ZL)); + AddInput(new Button(_padID, ButtonManager::CLASSIC_BUTTON_ZR)); + AddInput(new Button(_padID, ButtonManager::CLASSIC_DPAD_UP)); + AddInput(new Button(_padID, ButtonManager::CLASSIC_DPAD_DOWN)); + AddInput(new Button(_padID, ButtonManager::CLASSIC_DPAD_LEFT)); + AddInput(new Button(_padID, ButtonManager::CLASSIC_DPAD_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::CLASSIC_STICK_LEFT_LEFT), + new Axis(_padID, ButtonManager::CLASSIC_STICK_LEFT_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::CLASSIC_STICK_LEFT_UP), + new Axis(_padID, ButtonManager::CLASSIC_STICK_LEFT_DOWN)); + AddAnalogInputs(new Axis(_padID, ButtonManager::CLASSIC_STICK_RIGHT_LEFT), + new Axis(_padID, ButtonManager::CLASSIC_STICK_RIGHT_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::CLASSIC_STICK_RIGHT_UP), + new Axis(_padID, ButtonManager::CLASSIC_STICK_RIGHT_DOWN)); + AddAnalogInputs(new Axis(_padID, ButtonManager::CLASSIC_TRIGGER_L), + new Axis(_padID, ButtonManager::CLASSIC_TRIGGER_L)); + AddAnalogInputs(new Axis(_padID, ButtonManager::CLASSIC_TRIGGER_R), + new Axis(_padID, ButtonManager::CLASSIC_TRIGGER_R)); - // Wii-ext: Guitar - AddInput(new Button(_padID, ButtonManager::GUITAR_BUTTON_MINUS)); - AddInput(new Button(_padID, ButtonManager::GUITAR_BUTTON_PLUS)); - AddInput(new Button(_padID, ButtonManager::GUITAR_FRET_GREEN)); - AddInput(new Button(_padID, ButtonManager::GUITAR_FRET_RED)); - AddInput(new Button(_padID, ButtonManager::GUITAR_FRET_YELLOW)); - AddInput(new Button(_padID, ButtonManager::GUITAR_FRET_BLUE)); - AddInput(new Button(_padID, ButtonManager::GUITAR_FRET_ORANGE)); - AddInput(new Button(_padID, ButtonManager::GUITAR_STRUM_UP)); - AddInput(new Button(_padID, ButtonManager::GUITAR_STRUM_DOWN)); - AddAnalogInputs(new Axis(_padID, ButtonManager::GUITAR_STICK_LEFT), new Axis(_padID, ButtonManager::GUITAR_STICK_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::GUITAR_STICK_UP), new Axis(_padID, ButtonManager::GUITAR_STICK_DOWN)); - AddAnalogInputs(new Axis(_padID, ButtonManager::GUITAR_WHAMMY_BAR), new Axis(_padID, ButtonManager::GUITAR_WHAMMY_BAR)); + // Wii-ext: Guitar + AddInput(new Button(_padID, ButtonManager::GUITAR_BUTTON_MINUS)); + AddInput(new Button(_padID, ButtonManager::GUITAR_BUTTON_PLUS)); + AddInput(new Button(_padID, ButtonManager::GUITAR_FRET_GREEN)); + AddInput(new Button(_padID, ButtonManager::GUITAR_FRET_RED)); + AddInput(new Button(_padID, ButtonManager::GUITAR_FRET_YELLOW)); + AddInput(new Button(_padID, ButtonManager::GUITAR_FRET_BLUE)); + AddInput(new Button(_padID, ButtonManager::GUITAR_FRET_ORANGE)); + AddInput(new Button(_padID, ButtonManager::GUITAR_STRUM_UP)); + AddInput(new Button(_padID, ButtonManager::GUITAR_STRUM_DOWN)); + AddAnalogInputs(new Axis(_padID, ButtonManager::GUITAR_STICK_LEFT), + new Axis(_padID, ButtonManager::GUITAR_STICK_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::GUITAR_STICK_UP), + new Axis(_padID, ButtonManager::GUITAR_STICK_DOWN)); + AddAnalogInputs(new Axis(_padID, ButtonManager::GUITAR_WHAMMY_BAR), + new Axis(_padID, ButtonManager::GUITAR_WHAMMY_BAR)); - // Wii-ext: Drums - AddInput(new Button(_padID, ButtonManager::DRUMS_BUTTON_MINUS)); - AddInput(new Button(_padID, ButtonManager::DRUMS_BUTTON_PLUS)); - AddInput(new Button(_padID, ButtonManager::DRUMS_PAD_RED)); - AddInput(new Button(_padID, ButtonManager::DRUMS_PAD_YELLOW)); - AddInput(new Button(_padID, ButtonManager::DRUMS_PAD_BLUE)); - AddInput(new Button(_padID, ButtonManager::DRUMS_PAD_GREEN)); - AddInput(new Button(_padID, ButtonManager::DRUMS_PAD_ORANGE)); - AddInput(new Button(_padID, ButtonManager::DRUMS_PAD_BASS)); - AddAnalogInputs(new Axis(_padID, ButtonManager::DRUMS_STICK_LEFT), new Axis(_padID, ButtonManager::DRUMS_STICK_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::DRUMS_STICK_UP), new Axis(_padID, ButtonManager::DRUMS_STICK_DOWN)); + // Wii-ext: Drums + AddInput(new Button(_padID, ButtonManager::DRUMS_BUTTON_MINUS)); + AddInput(new Button(_padID, ButtonManager::DRUMS_BUTTON_PLUS)); + AddInput(new Button(_padID, ButtonManager::DRUMS_PAD_RED)); + AddInput(new Button(_padID, ButtonManager::DRUMS_PAD_YELLOW)); + AddInput(new Button(_padID, ButtonManager::DRUMS_PAD_BLUE)); + AddInput(new Button(_padID, ButtonManager::DRUMS_PAD_GREEN)); + AddInput(new Button(_padID, ButtonManager::DRUMS_PAD_ORANGE)); + AddInput(new Button(_padID, ButtonManager::DRUMS_PAD_BASS)); + AddAnalogInputs(new Axis(_padID, ButtonManager::DRUMS_STICK_LEFT), + new Axis(_padID, ButtonManager::DRUMS_STICK_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::DRUMS_STICK_UP), + new Axis(_padID, ButtonManager::DRUMS_STICK_DOWN)); - // Wii-ext: Turntable - AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_GREEN_LEFT)); - AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_RED_LEFT)); - AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_BLUE_LEFT)); - AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_GREEN_RIGHT)); - AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_RED_RIGHT)); - AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_BLUE_RIGHT)); - AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_MINUS)); - AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_PLUS)); - AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_HOME)); - AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_EUPHORIA)); - AddAnalogInputs(new Axis(_padID, ButtonManager::TURNTABLE_TABLE_LEFT_LEFT), new Axis(_padID, ButtonManager::TURNTABLE_TABLE_LEFT_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::TURNTABLE_TABLE_RIGHT_LEFT), new Axis(_padID, ButtonManager::TURNTABLE_TABLE_RIGHT_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::TURNTABLE_STICK_LEFT), new Axis(_padID, ButtonManager::TURNTABLE_STICK_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::TURNTABLE_STICK_UP), new Axis(_padID, ButtonManager::TURNTABLE_STICK_DOWN)); - AddAnalogInputs(new Axis(_padID, ButtonManager::TURNTABLE_CROSSFADE_LEFT), new Axis(_padID, ButtonManager::TURNTABLE_CROSSFADE_RIGHT)); - AddAnalogInputs(new Axis(_padID, ButtonManager::TURNTABLE_EFFECT_DIAL), new Axis(_padID, ButtonManager::TURNTABLE_EFFECT_DIAL)); + // Wii-ext: Turntable + AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_GREEN_LEFT)); + AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_RED_LEFT)); + AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_BLUE_LEFT)); + AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_GREEN_RIGHT)); + AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_RED_RIGHT)); + AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_BLUE_RIGHT)); + AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_MINUS)); + AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_PLUS)); + AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_HOME)); + AddInput(new Button(_padID, ButtonManager::TURNTABLE_BUTTON_EUPHORIA)); + AddAnalogInputs(new Axis(_padID, ButtonManager::TURNTABLE_TABLE_LEFT_LEFT), + new Axis(_padID, ButtonManager::TURNTABLE_TABLE_LEFT_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::TURNTABLE_TABLE_RIGHT_LEFT), + new Axis(_padID, ButtonManager::TURNTABLE_TABLE_RIGHT_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::TURNTABLE_STICK_LEFT), + new Axis(_padID, ButtonManager::TURNTABLE_STICK_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::TURNTABLE_STICK_UP), + new Axis(_padID, ButtonManager::TURNTABLE_STICK_DOWN)); + AddAnalogInputs(new Axis(_padID, ButtonManager::TURNTABLE_CROSSFADE_LEFT), + new Axis(_padID, ButtonManager::TURNTABLE_CROSSFADE_RIGHT)); + AddAnalogInputs(new Axis(_padID, ButtonManager::TURNTABLE_EFFECT_DIAL), + new Axis(_padID, ButtonManager::TURNTABLE_EFFECT_DIAL)); } // Buttons and stuff std::string Touchscreen::Button::GetName() const { - std::ostringstream ss; - ss << "Button " << (int)_index; - return ss.str(); + std::ostringstream ss; + ss << "Button " << (int)_index; + return ss.str(); } ControlState Touchscreen::Button::GetState() const { - return ButtonManager::GetButtonPressed(_padID, _index); + return ButtonManager::GetButtonPressed(_padID, _index); } std::string Touchscreen::Axis::GetName() const { - std::ostringstream ss; - ss << "Axis " << (int)_index; - return ss.str(); + std::ostringstream ss; + ss << "Axis " << (int)_index; + return ss.str(); } ControlState Touchscreen::Axis::GetState() const { - return ButtonManager::GetAxisValue(_padID, _index) * _neg; -} - + return ButtonManager::GetAxisValue(_padID, _index) * _neg; +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/Android/Android.h b/Source/Core/InputCommon/ControllerInterface/Android/Android.h index c108a86067..53b578f699 100644 --- a/Source/Core/InputCommon/ControllerInterface/Android/Android.h +++ b/Source/Core/InputCommon/ControllerInterface/Android/Android.h @@ -11,43 +11,46 @@ namespace ciface { namespace Android { - -void Init( std::vector& devices ); +void Init(std::vector& devices); class Touchscreen : public Core::Device { private: - class Button : public Input - { - public: - std::string GetName() const; - Button(int padID, ButtonManager::ButtonType index) : _padID(padID), _index(index) {} - ControlState GetState() const; - private: - const int _padID; - const ButtonManager::ButtonType _index; - }; - class Axis : public Input - { - public: - std::string GetName() const; - Axis(int padID, ButtonManager::ButtonType index, float neg = 1.0f) : _padID(padID), _index(index), _neg(neg) {} - ControlState GetState() const; - private: - const int _padID; - const ButtonManager::ButtonType _index; - const float _neg; - }; + class Button : public Input + { + public: + std::string GetName() const; + Button(int padID, ButtonManager::ButtonType index) : _padID(padID), _index(index) {} + ControlState GetState() const; + + private: + const int _padID; + const ButtonManager::ButtonType _index; + }; + class Axis : public Input + { + public: + std::string GetName() const; + Axis(int padID, ButtonManager::ButtonType index, float neg = 1.0f) + : _padID(padID), _index(index), _neg(neg) + { + } + ControlState GetState() const; + + private: + const int _padID; + const ButtonManager::ButtonType _index; + const float _neg; + }; public: - Touchscreen(int padID); - ~Touchscreen() {} + Touchscreen(int padID); + ~Touchscreen() {} + std::string GetName() const; + int GetId() const; + std::string GetSource() const; - std::string GetName() const; - int GetId() const; - std::string GetSource() const; private: - const int _padID; + const int _padID; }; - } } diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp index 633ce40a5f..55643ece5f 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp @@ -2,35 +2,35 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Common/Thread.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" +#include "Common/Thread.h" #ifdef CIFACE_USE_XINPUT - #include "InputCommon/ControllerInterface/XInput/XInput.h" +#include "InputCommon/ControllerInterface/XInput/XInput.h" #endif #ifdef CIFACE_USE_DINPUT - #include "InputCommon/ControllerInterface/DInput/DInput.h" +#include "InputCommon/ControllerInterface/DInput/DInput.h" #endif #ifdef CIFACE_USE_XLIB - #include "InputCommon/ControllerInterface/Xlib/Xlib.h" - #ifdef CIFACE_USE_X11_XINPUT2 - #include "InputCommon/ControllerInterface/Xlib/XInput2.h" - #endif +#include "InputCommon/ControllerInterface/Xlib/Xlib.h" +#ifdef CIFACE_USE_X11_XINPUT2 +#include "InputCommon/ControllerInterface/Xlib/XInput2.h" +#endif #endif #ifdef CIFACE_USE_OSX - #include "InputCommon/ControllerInterface/OSX/OSX.h" +#include "InputCommon/ControllerInterface/OSX/OSX.h" #endif #ifdef CIFACE_USE_SDL - #include "InputCommon/ControllerInterface/SDL/SDL.h" +#include "InputCommon/ControllerInterface/SDL/SDL.h" #endif #ifdef CIFACE_USE_ANDROID - #include "InputCommon/ControllerInterface/Android/Android.h" +#include "InputCommon/ControllerInterface/Android/Android.h" #endif #ifdef CIFACE_USE_EVDEV - #include "InputCommon/ControllerInterface/evdev/evdev.h" +#include "InputCommon/ControllerInterface/evdev/evdev.h" #endif #ifdef CIFACE_USE_PIPES - #include "InputCommon/ControllerInterface/Pipes/Pipes.h" +#include "InputCommon/ControllerInterface/Pipes/Pipes.h" #endif using namespace ciface::ExpressionParser; @@ -49,49 +49,49 @@ ControllerInterface g_controller_interface; // void ControllerInterface::Initialize(void* const hwnd) { - if (m_is_init) - return; + if (m_is_init) + return; - m_hwnd = hwnd; + m_hwnd = hwnd; #ifdef CIFACE_USE_DINPUT - ciface::DInput::Init(m_devices, (HWND)hwnd); + ciface::DInput::Init(m_devices, (HWND)hwnd); #endif #ifdef CIFACE_USE_XINPUT - ciface::XInput::Init(m_devices); + ciface::XInput::Init(m_devices); #endif #ifdef CIFACE_USE_XLIB - ciface::Xlib::Init(m_devices, hwnd); - #ifdef CIFACE_USE_X11_XINPUT2 - ciface::XInput2::Init(m_devices, hwnd); - #endif + ciface::Xlib::Init(m_devices, hwnd); +#ifdef CIFACE_USE_X11_XINPUT2 + ciface::XInput2::Init(m_devices, hwnd); +#endif #endif #ifdef CIFACE_USE_OSX - ciface::OSX::Init(m_devices, hwnd); + ciface::OSX::Init(m_devices, hwnd); #endif #ifdef CIFACE_USE_SDL - ciface::SDL::Init(m_devices); + ciface::SDL::Init(m_devices); #endif #ifdef CIFACE_USE_ANDROID - ciface::Android::Init(m_devices); + ciface::Android::Init(m_devices); #endif #ifdef CIFACE_USE_EVDEV - ciface::evdev::Init(m_devices); + ciface::evdev::Init(m_devices); #endif #ifdef CIFACE_USE_PIPES - ciface::Pipes::Init(m_devices); + ciface::Pipes::Init(m_devices); #endif - m_is_init = true; + m_is_init = true; } void ControllerInterface::Reinitialize() { - if (!m_is_init) - return; + if (!m_is_init) + return; - Shutdown(); - Initialize(m_hwnd); + Shutdown(); + Initialize(m_hwnd); } // @@ -101,42 +101,42 @@ void ControllerInterface::Reinitialize() // void ControllerInterface::Shutdown() { - if (!m_is_init) - return; + if (!m_is_init) + return; - for (ciface::Core::Device* d : m_devices) - { - // Set outputs to ZERO before destroying device - for (ciface::Core::Device::Output* o : d->Outputs()) - o->SetState(0); + for (ciface::Core::Device* d : m_devices) + { + // Set outputs to ZERO before destroying device + for (ciface::Core::Device::Output* o : d->Outputs()) + o->SetState(0); - // Delete device - delete d; - } + // Delete device + delete d; + } - m_devices.clear(); + m_devices.clear(); #ifdef CIFACE_USE_XINPUT - ciface::XInput::DeInit(); + ciface::XInput::DeInit(); #endif #ifdef CIFACE_USE_DINPUT - // nothing needed +// nothing needed #endif #ifdef CIFACE_USE_XLIB - // nothing needed +// nothing needed #endif #ifdef CIFACE_USE_OSX - ciface::OSX::DeInit(); + ciface::OSX::DeInit(); #endif #ifdef CIFACE_USE_SDL - // TODO: there seems to be some sort of memory leak with SDL, quit isn't freeing everything up - SDL_Quit(); + // TODO: there seems to be some sort of memory leak with SDL, quit isn't freeing everything up + SDL_Quit(); #endif #ifdef CIFACE_USE_ANDROID - // nothing needed +// nothing needed #endif - m_is_init = false; + m_is_init = false; } // @@ -146,8 +146,8 @@ void ControllerInterface::Shutdown() // void ControllerInterface::UpdateInput() { - for (ciface::Core::Device* d : m_devices) - d->UpdateInput(); + for (ciface::Core::Device* d : m_devices) + d->UpdateInput(); } // @@ -156,26 +156,27 @@ void ControllerInterface::UpdateInput() // Gets the state of an input reference // override function for ControlReference::State ... // -ControlState ControllerInterface::InputReference::State( const ControlState ignore ) +ControlState ControllerInterface::InputReference::State(const ControlState ignore) { - if (parsed_expression) - return parsed_expression->GetValue() * range; - else - return 0.0; + if (parsed_expression) + return parsed_expression->GetValue() * range; + else + return 0.0; } // // OutputReference :: State // // Set the state of all binded outputs -// overrides ControlReference::State .. combined them so I could make the GUI simple / inputs == same as outputs one list +// overrides ControlReference::State .. combined them so I could make the GUI simple / inputs == +// same as outputs one list // I was lazy and it works so watever // ControlState ControllerInterface::OutputReference::State(const ControlState state) { - if (parsed_expression) - parsed_expression->SetValue(state); - return 0.0; + if (parsed_expression) + parsed_expression->SetValue(state); + return 0.0; } // @@ -184,14 +185,14 @@ ControlState ControllerInterface::OutputReference::State(const ControlState stat // Updates a controlreference's binded devices/controls // need to call this to re-parse a control reference's expression after changing it // -void ControllerInterface::UpdateReference(ControllerInterface::ControlReference* ref - , const ciface::Core::DeviceQualifier& default_device) const +void ControllerInterface::UpdateReference(ControllerInterface::ControlReference* ref, + const ciface::Core::DeviceQualifier& default_device) const { - delete ref->parsed_expression; - ref->parsed_expression = nullptr; + delete ref->parsed_expression; + ref->parsed_expression = nullptr; - ControlFinder finder(*this, default_device, ref->is_input); - ref->parse_error = ParseExpression(ref->expression, finder, &ref->parsed_expression); + ControlFinder finder(*this, default_device, ref->is_input); + ref->parse_error = ParseExpression(ref->expression, finder, &ref->parsed_expression); } // @@ -204,71 +205,77 @@ void ControllerInterface::UpdateReference(ControllerInterface::ControlReference* // upon input, return pointer to detected Control // else return nullptr // -ciface::Core::Device::Control* ControllerInterface::InputReference::Detect(const unsigned int ms, ciface::Core::Device* const device) +ciface::Core::Device::Control* +ControllerInterface::InputReference::Detect(const unsigned int ms, + ciface::Core::Device* const device) { - unsigned int time = 0; - std::vector states(device->Inputs().size()); + unsigned int time = 0; + std::vector states(device->Inputs().size()); - if (device->Inputs().size() == 0) - return nullptr; + if (device->Inputs().size() == 0) + return nullptr; - // get starting state of all inputs, - // so we can ignore those that were activated at time of Detect start - std::vector::const_iterator - i = device->Inputs().begin(), - e = device->Inputs().end(); - for (std::vector::iterator state = states.begin(); i != e; ++i) - *state++ = ((*i)->GetState() > (1 - INPUT_DETECT_THRESHOLD)); + // get starting state of all inputs, + // so we can ignore those that were activated at time of Detect start + std::vector::const_iterator i = device->Inputs().begin(), + e = device->Inputs().end(); + for (std::vector::iterator state = states.begin(); i != e; ++i) + *state++ = ((*i)->GetState() > (1 - INPUT_DETECT_THRESHOLD)); - while (time < ms) - { - device->UpdateInput(); - i = device->Inputs().begin(); - for (std::vector::iterator state = states.begin(); i != e; ++i,++state) - { - // detected an input - if ((*i)->IsDetectable() && (*i)->GetState() > INPUT_DETECT_THRESHOLD) - { - // input was released at some point during Detect call - // return the detected input - if (false == *state) - return *i; - } - else if ((*i)->GetState() < (1 - INPUT_DETECT_THRESHOLD)) - { - *state = false; - } - } - Common::SleepCurrentThread(10); time += 10; - } + while (time < ms) + { + device->UpdateInput(); + i = device->Inputs().begin(); + for (std::vector::iterator state = states.begin(); i != e; ++i, ++state) + { + // detected an input + if ((*i)->IsDetectable() && (*i)->GetState() > INPUT_DETECT_THRESHOLD) + { + // input was released at some point during Detect call + // return the detected input + if (false == *state) + return *i; + } + else if ((*i)->GetState() < (1 - INPUT_DETECT_THRESHOLD)) + { + *state = false; + } + } + Common::SleepCurrentThread(10); + time += 10; + } - // no input was detected - return nullptr; + // no input was detected + return nullptr; } // // OutputReference :: Detect // -// Totally different from the inputReference detect / I have them combined so it was simpler to make the GUI. -// The GUI doesn't know the difference between an input and an output / it's odd but I was lazy and it was easy +// Totally different from the inputReference detect / I have them combined so it was simpler to make +// the GUI. +// The GUI doesn't know the difference between an input and an output / it's odd but I was lazy and +// it was easy // // set all binded outputs to power for x milliseconds return false // -ciface::Core::Device::Control* ControllerInterface::OutputReference::Detect(const unsigned int ms, ciface::Core::Device* const device) +ciface::Core::Device::Control* +ControllerInterface::OutputReference::Detect(const unsigned int ms, + ciface::Core::Device* const device) { - // ignore device + // ignore device - // don't hang if we don't even have any controls mapped - if (BoundCount() > 0) - { - State(1); - unsigned int slept = 0; + // don't hang if we don't even have any controls mapped + if (BoundCount() > 0) + { + State(1); + unsigned int slept = 0; - // this loop is to make stuff like flashing keyboard LEDs work - while (ms > (slept += 10)) - Common::SleepCurrentThread(10); + // this loop is to make stuff like flashing keyboard LEDs work + while (ms > (slept += 10)) + Common::SleepCurrentThread(10); - State(0); - } - return nullptr; + State(0); + } + return nullptr; } diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h index e324817dd3..25154ede40 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h @@ -17,26 +17,26 @@ // enable disable sources #ifdef _WIN32 - #define CIFACE_USE_XINPUT - #define CIFACE_USE_DINPUT +#define CIFACE_USE_XINPUT +#define CIFACE_USE_DINPUT #endif #if defined(HAVE_X11) && HAVE_X11 - #define CIFACE_USE_XLIB - #if defined(HAVE_X11_XINPUT2) && HAVE_X11_XINPUT2 - #define CIFACE_USE_X11_XINPUT2 - #endif +#define CIFACE_USE_XLIB +#if defined(HAVE_X11_XINPUT2) && HAVE_X11_XINPUT2 +#define CIFACE_USE_X11_XINPUT2 +#endif #endif #if defined(__APPLE__) - #define CIFACE_USE_OSX +#define CIFACE_USE_OSX #endif #if defined(HAVE_SDL) && HAVE_SDL - #define CIFACE_USE_SDL +#define CIFACE_USE_SDL #endif #if defined(HAVE_LIBEVDEV) && defined(HAVE_LIBUDEV) - #define CIFACE_USE_EVDEV +#define CIFACE_USE_EVDEV #endif #if defined(USE_PIPES) - #define CIFACE_USE_PIPES +#define CIFACE_USE_PIPES #endif // @@ -48,86 +48,87 @@ class ControllerInterface : public ciface::Core::DeviceContainer { public: + // + // ControlReference + // + // These are what you create to actually use the inputs, InputReference or OutputReference. + // + // After being bound to devices and controls with ControllerInterface::UpdateReference, + // each one can link to multiple devices and controls + // when you change a ControlReference's expression, + // you must use ControllerInterface::UpdateReference on it to rebind controls + // + class ControlReference + { + friend class ControllerInterface; - // - // ControlReference - // - // These are what you create to actually use the inputs, InputReference or OutputReference. - // - // After being bound to devices and controls with ControllerInterface::UpdateReference, - // each one can link to multiple devices and controls - // when you change a ControlReference's expression, - // you must use ControllerInterface::UpdateReference on it to rebind controls - // - class ControlReference - { - friend class ControllerInterface; - public: - virtual ControlState State(const ControlState state = 0) = 0; - virtual ciface::Core::Device::Control* Detect(const unsigned int ms, ciface::Core::Device* const device) = 0; + public: + virtual ControlState State(const ControlState state = 0) = 0; + virtual ciface::Core::Device::Control* Detect(const unsigned int ms, + ciface::Core::Device* const device) = 0; - ControlState range; - std::string expression; - const bool is_input; - ciface::ExpressionParser::ExpressionParseStatus parse_error; + ControlState range; + std::string expression; + const bool is_input; + ciface::ExpressionParser::ExpressionParseStatus parse_error; - virtual ~ControlReference() - { - delete parsed_expression; - } + virtual ~ControlReference() { delete parsed_expression; } + int BoundCount() + { + if (parsed_expression) + return parsed_expression->num_controls; + else + return 0; + } - int BoundCount() - { - if (parsed_expression) - return parsed_expression->num_controls; - else - return 0; - } + protected: + ControlReference(const bool _is_input) + : range(1), is_input(_is_input), parsed_expression(nullptr) + { + } + ciface::ExpressionParser::Expression* parsed_expression; + }; - protected: - ControlReference(const bool _is_input) : range(1), is_input(_is_input), parsed_expression(nullptr) {} - ciface::ExpressionParser::Expression *parsed_expression; - }; + // + // InputReference + // + // Control reference for inputs + // + class InputReference : public ControlReference + { + public: + InputReference() : ControlReference(true) {} + ControlState State(const ControlState state) override; + ciface::Core::Device::Control* Detect(const unsigned int ms, + ciface::Core::Device* const device) override; + }; - // - // InputReference - // - // Control reference for inputs - // - class InputReference : public ControlReference - { - public: - InputReference() : ControlReference(true) {} - ControlState State(const ControlState state) override; - ciface::Core::Device::Control* Detect(const unsigned int ms, ciface::Core::Device* const device) override; - }; + // + // OutputReference + // + // Control reference for outputs + // + class OutputReference : public ControlReference + { + public: + OutputReference() : ControlReference(false) {} + ControlState State(const ControlState state) override; + ciface::Core::Device::Control* Detect(const unsigned int ms, + ciface::Core::Device* const device) override; + }; - // - // OutputReference - // - // Control reference for outputs - // - class OutputReference : public ControlReference - { - public: - OutputReference() : ControlReference(false) {} - ControlState State(const ControlState state) override; - ciface::Core::Device::Control* Detect(const unsigned int ms, ciface::Core::Device* const device) override; - }; - - ControllerInterface() : m_is_init(false), m_hwnd(nullptr) {} - - void Initialize(void* const hwnd); - void Reinitialize(); - void Shutdown(); - bool IsInit() const { return m_is_init; } - - void UpdateReference(ControlReference* control, const ciface::Core::DeviceQualifier& default_device) const; - void UpdateInput(); + ControllerInterface() : m_is_init(false), m_hwnd(nullptr) {} + void Initialize(void* const hwnd); + void Reinitialize(); + void Shutdown(); + bool IsInit() const { return m_is_init; } + void UpdateReference(ControlReference* control, + const ciface::Core::DeviceQualifier& default_device) const; + void UpdateInput(); private: - bool m_is_init; - void* m_hwnd; + bool m_is_init; + void* m_hwnd; }; extern ControllerInterface g_controller_interface; diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/DInput.cpp b/Source/Core/InputCommon/ControllerInterface/DInput/DInput.cpp index 4a68474618..09227b5932 100644 --- a/Source/Core/InputCommon/ControllerInterface/DInput/DInput.cpp +++ b/Source/Core/InputCommon/ControllerInterface/DInput/DInput.cpp @@ -16,50 +16,47 @@ namespace ciface { namespace DInput { - BOOL CALLBACK DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) { - ((std::list*)pvRef)->push_back(*lpddoi); - return DIENUM_CONTINUE; + ((std::list*)pvRef)->push_back(*lpddoi); + return DIENUM_CONTINUE; } BOOL CALLBACK DIEnumDevicesCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) { - ((std::list*)pvRef)->push_back(*lpddi); - return DIENUM_CONTINUE; + ((std::list*)pvRef)->push_back(*lpddi); + return DIENUM_CONTINUE; } std::string GetDeviceName(const LPDIRECTINPUTDEVICE8 device) { - DIPROPSTRING str = {}; - str.diph.dwSize = sizeof(str); - str.diph.dwHeaderSize = sizeof(str.diph); - str.diph.dwHow = DIPH_DEVICE; + DIPROPSTRING str = {}; + str.diph.dwSize = sizeof(str); + str.diph.dwHeaderSize = sizeof(str.diph); + str.diph.dwHow = DIPH_DEVICE; - std::string result; - if (SUCCEEDED(device->GetProperty(DIPROP_PRODUCTNAME, &str.diph))) - { - result = StripSpaces(UTF16ToUTF8(str.wsz)); - } + std::string result; + if (SUCCEEDED(device->GetProperty(DIPROP_PRODUCTNAME, &str.diph))) + { + result = StripSpaces(UTF16ToUTF8(str.wsz)); + } - return result; + return result; } void Init(std::vector& devices, HWND hwnd) { - IDirectInput8* idi8; - if (FAILED(DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, - IID_IDirectInput8, (LPVOID*)&idi8, nullptr))) - { - return; - } + IDirectInput8* idi8; + if (FAILED(DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, + (LPVOID*)&idi8, nullptr))) + { + return; + } - InitKeyboardMouse(idi8, devices, hwnd); - InitJoystick(idi8, devices, hwnd); - - idi8->Release(); - -} + InitKeyboardMouse(idi8, devices, hwnd); + InitJoystick(idi8, devices, hwnd); + idi8->Release(); +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/DInput.h b/Source/Core/InputCommon/ControllerInterface/DInput/DInput.h index 1823499e98..2f5e2f83a7 100644 --- a/Source/Core/InputCommon/ControllerInterface/DInput/DInput.h +++ b/Source/Core/InputCommon/ControllerInterface/DInput/DInput.h @@ -9,20 +9,18 @@ #include #include -#include "InputCommon/ControllerInterface/Device.h" #include "InputCommon/ControllerInterface/DInput/DInput8.h" +#include "InputCommon/ControllerInterface/Device.h" namespace ciface { namespace DInput { - -//BOOL CALLBACK DIEnumEffectsCallback(LPCDIEFFECTINFO pdei, LPVOID pvRef); +// BOOL CALLBACK DIEnumEffectsCallback(LPCDIEFFECTINFO pdei, LPVOID pvRef); BOOL CALLBACK DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef); BOOL CALLBACK DIEnumDevicesCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef); std::string GetDeviceName(const LPDIRECTINPUTDEVICE8 device); void Init(std::vector& devices, HWND hwnd); - } } diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp b/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp index aa1e972126..bf2c1f3e7e 100644 --- a/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp +++ b/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.cpp @@ -14,268 +14,270 @@ namespace ciface { namespace DInput { - #define DATA_BUFFER_SIZE 32 void InitJoystick(IDirectInput8* const idi8, std::vector& devices, HWND hwnd) { - std::list joysticks; - idi8->EnumDevices(DI8DEVCLASS_GAMECTRL, DIEnumDevicesCallback, (LPVOID)&joysticks, DIEDFL_ATTACHEDONLY); + std::list joysticks; + idi8->EnumDevices(DI8DEVCLASS_GAMECTRL, DIEnumDevicesCallback, (LPVOID)&joysticks, + DIEDFL_ATTACHEDONLY); - // this is used to number the joysticks - // multiple joysticks with the same name shall get unique ids starting at 0 - std::map< std::basic_string, int> name_counts; + // this is used to number the joysticks + // multiple joysticks with the same name shall get unique ids starting at 0 + std::map, int> name_counts; - std::vector xinput_guids; - GetXInputGUIDS(&xinput_guids); + std::vector xinput_guids; + GetXInputGUIDS(&xinput_guids); - for (DIDEVICEINSTANCE& joystick : joysticks) - { - // skip XInput Devices - if (std::find(xinput_guids.begin(), xinput_guids.end(), joystick.guidProduct.Data1) != xinput_guids.end()) - { - continue; - } + for (DIDEVICEINSTANCE& joystick : joysticks) + { + // skip XInput Devices + if (std::find(xinput_guids.begin(), xinput_guids.end(), joystick.guidProduct.Data1) != + xinput_guids.end()) + { + continue; + } - LPDIRECTINPUTDEVICE8 js_device; - if (SUCCEEDED(idi8->CreateDevice(joystick.guidInstance, &js_device, nullptr))) - { - if (SUCCEEDED(js_device->SetDataFormat(&c_dfDIJoystick))) - { - if (FAILED(js_device->SetCooperativeLevel(GetAncestor(hwnd, GA_ROOT), DISCL_BACKGROUND | DISCL_EXCLUSIVE))) - { - //PanicAlert("SetCooperativeLevel(DISCL_EXCLUSIVE) failed!"); - // fall back to non-exclusive mode, with no rumble - if (FAILED(js_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) - { - //PanicAlert("SetCooperativeLevel failed!"); - js_device->Release(); - continue; - } - } + LPDIRECTINPUTDEVICE8 js_device; + if (SUCCEEDED(idi8->CreateDevice(joystick.guidInstance, &js_device, nullptr))) + { + if (SUCCEEDED(js_device->SetDataFormat(&c_dfDIJoystick))) + { + if (FAILED(js_device->SetCooperativeLevel(GetAncestor(hwnd, GA_ROOT), + DISCL_BACKGROUND | DISCL_EXCLUSIVE))) + { + // PanicAlert("SetCooperativeLevel(DISCL_EXCLUSIVE) failed!"); + // fall back to non-exclusive mode, with no rumble + if (FAILED( + js_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) + { + // PanicAlert("SetCooperativeLevel failed!"); + js_device->Release(); + continue; + } + } - Joystick* js = new Joystick(/*&*i, */js_device, name_counts[joystick.tszInstanceName]++); - // only add if it has some inputs/outputs - if (js->Inputs().size() || js->Outputs().size()) - devices.push_back(js); - else - delete js; - } - else - { - //PanicAlert("SetDataFormat failed!"); - js_device->Release(); - } - } - } + Joystick* js = new Joystick(/*&*i, */ js_device, name_counts[joystick.tszInstanceName]++); + // only add if it has some inputs/outputs + if (js->Inputs().size() || js->Outputs().size()) + devices.push_back(js); + else + delete js; + } + else + { + // PanicAlert("SetDataFormat failed!"); + js_device->Release(); + } + } + } } -Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVICE8 device, const unsigned int index ) - : m_device(device) - , m_index(index) - //, m_name(TStringToString(lpddi->tszInstanceName)) +Joystick::Joystick(/*const LPCDIDEVICEINSTANCE lpddi, */ const LPDIRECTINPUTDEVICE8 device, + const unsigned int index) + : m_device(device), m_index(index) +//, m_name(TStringToString(lpddi->tszInstanceName)) { - // seems this needs to be done before GetCapabilities - // polled or buffered data - DIPROPDWORD dipdw; - dipdw.diph.dwSize = sizeof(DIPROPDWORD); - dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dipdw.diph.dwObj = 0; - dipdw.diph.dwHow = DIPH_DEVICE; - dipdw.dwData = DATA_BUFFER_SIZE; - // set the buffer size, - // if we can't set the property, we can't use buffered data - m_buffered = SUCCEEDED(m_device->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)); + // seems this needs to be done before GetCapabilities + // polled or buffered data + DIPROPDWORD dipdw; + dipdw.diph.dwSize = sizeof(DIPROPDWORD); + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = DATA_BUFFER_SIZE; + // set the buffer size, + // if we can't set the property, we can't use buffered data + m_buffered = SUCCEEDED(m_device->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)); - // seems this needs to be done after SetProperty of buffer size - m_device->Acquire(); + // seems this needs to be done after SetProperty of buffer size + m_device->Acquire(); - // get joystick caps - DIDEVCAPS js_caps; - js_caps.dwSize = sizeof(js_caps); - if (FAILED(m_device->GetCapabilities(&js_caps))) - return; + // get joystick caps + DIDEVCAPS js_caps; + js_caps.dwSize = sizeof(js_caps); + if (FAILED(m_device->GetCapabilities(&js_caps))) + return; - // max of 32 buttons and 4 hats / the limit of the data format I am using - js_caps.dwButtons = std::min((DWORD)32, js_caps.dwButtons); - js_caps.dwPOVs = std::min((DWORD)4, js_caps.dwPOVs); + // max of 32 buttons and 4 hats / the limit of the data format I am using + js_caps.dwButtons = std::min((DWORD)32, js_caps.dwButtons); + js_caps.dwPOVs = std::min((DWORD)4, js_caps.dwPOVs); - //m_must_poll = (js_caps.dwFlags & DIDC_POLLEDDATAFORMAT) != 0; + // m_must_poll = (js_caps.dwFlags & DIDC_POLLEDDATAFORMAT) != 0; - // buttons - for (u8 i = 0; i != js_caps.dwButtons; ++i) - AddInput(new Button(i, m_state_in.rgbButtons[i])); + // buttons + for (u8 i = 0; i != js_caps.dwButtons; ++i) + AddInput(new Button(i, m_state_in.rgbButtons[i])); - // hats - for (u8 i = 0; i != js_caps.dwPOVs; ++i) - { - // each hat gets 4 input instances associated with it, (up down left right) - for (u8 d = 0; d != 4; ++d) - AddInput(new Hat(i, m_state_in.rgdwPOV[i], d)); - } + // hats + for (u8 i = 0; i != js_caps.dwPOVs; ++i) + { + // each hat gets 4 input instances associated with it, (up down left right) + for (u8 d = 0; d != 4; ++d) + AddInput(new Hat(i, m_state_in.rgdwPOV[i], d)); + } - // get up to 6 axes and 2 sliders - DIPROPRANGE range; - range.diph.dwSize = sizeof(range); - range.diph.dwHeaderSize = sizeof(range.diph); - range.diph.dwHow = DIPH_BYOFFSET; - // screw EnumObjects, just go through all the axis offsets and try to GetProperty - // this should be more foolproof, less code, and probably faster - for (unsigned int offset = 0; offset < DIJOFS_BUTTON(0) / sizeof(LONG); ++offset) - { - range.diph.dwObj = offset * sizeof(LONG); - // try to set some nice power of 2 values (128) to match the GameCube controls - range.lMin = -(1 << 7); - range.lMax = (1 << 7); - m_device->SetProperty(DIPROP_RANGE, &range.diph); - // but I guess not all devices support setting range - // so I getproperty right afterward incase it didn't set. - // This also checks that the axis is present - if (SUCCEEDED(m_device->GetProperty(DIPROP_RANGE, &range.diph))) - { - const LONG base = (range.lMin + range.lMax) / 2; - const LONG& ax = (&m_state_in.lX)[offset]; + // get up to 6 axes and 2 sliders + DIPROPRANGE range; + range.diph.dwSize = sizeof(range); + range.diph.dwHeaderSize = sizeof(range.diph); + range.diph.dwHow = DIPH_BYOFFSET; + // screw EnumObjects, just go through all the axis offsets and try to GetProperty + // this should be more foolproof, less code, and probably faster + for (unsigned int offset = 0; offset < DIJOFS_BUTTON(0) / sizeof(LONG); ++offset) + { + range.diph.dwObj = offset * sizeof(LONG); + // try to set some nice power of 2 values (128) to match the GameCube controls + range.lMin = -(1 << 7); + range.lMax = (1 << 7); + m_device->SetProperty(DIPROP_RANGE, &range.diph); + // but I guess not all devices support setting range + // so I getproperty right afterward incase it didn't set. + // This also checks that the axis is present + if (SUCCEEDED(m_device->GetProperty(DIPROP_RANGE, &range.diph))) + { + const LONG base = (range.lMin + range.lMax) / 2; + const LONG& ax = (&m_state_in.lX)[offset]; - // each axis gets a negative and a positive input instance associated with it - AddAnalogInputs(new Axis(offset, ax, base, range.lMin-base), - new Axis(offset, ax, base, range.lMax-base)); - } - } + // each axis gets a negative and a positive input instance associated with it + AddAnalogInputs(new Axis(offset, ax, base, range.lMin - base), + new Axis(offset, ax, base, range.lMax - base)); + } + } - // force feedback - std::list objects; - if (SUCCEEDED(m_device->EnumObjects(DIEnumDeviceObjectsCallback, (LPVOID)&objects, DIDFT_AXIS))) - { - InitForceFeedback(m_device, (int)objects.size()); - } + // force feedback + std::list objects; + if (SUCCEEDED(m_device->EnumObjects(DIEnumDeviceObjectsCallback, (LPVOID)&objects, DIDFT_AXIS))) + { + InitForceFeedback(m_device, (int)objects.size()); + } - ZeroMemory(&m_state_in, sizeof(m_state_in)); - // set hats to center - memset(m_state_in.rgdwPOV, 0xFF, sizeof(m_state_in.rgdwPOV)); + ZeroMemory(&m_state_in, sizeof(m_state_in)); + // set hats to center + memset(m_state_in.rgdwPOV, 0xFF, sizeof(m_state_in.rgdwPOV)); } Joystick::~Joystick() { - m_device->Unacquire(); - m_device->Release(); + m_device->Unacquire(); + m_device->Release(); } std::string Joystick::GetName() const { - return GetDeviceName(m_device); + return GetDeviceName(m_device); } int Joystick::GetId() const { - return m_index; + return m_index; } std::string Joystick::GetSource() const { - return DINPUT_SOURCE_NAME; + return DINPUT_SOURCE_NAME; } // update IO void Joystick::UpdateInput() { - HRESULT hr = 0; + HRESULT hr = 0; - // just always poll, - // MSDN says if this isn't needed it doesn't do anything - m_device->Poll(); + // just always poll, + // MSDN says if this isn't needed it doesn't do anything + m_device->Poll(); - if (m_buffered) - { - DIDEVICEOBJECTDATA evtbuf[DATA_BUFFER_SIZE]; - DWORD numevents = DATA_BUFFER_SIZE; - hr = m_device->GetDeviceData(sizeof(*evtbuf), evtbuf, &numevents, 0); + if (m_buffered) + { + DIDEVICEOBJECTDATA evtbuf[DATA_BUFFER_SIZE]; + DWORD numevents = DATA_BUFFER_SIZE; + hr = m_device->GetDeviceData(sizeof(*evtbuf), evtbuf, &numevents, 0); - if (SUCCEEDED(hr)) - { - for (LPDIDEVICEOBJECTDATA evt = evtbuf; evt != (evtbuf + numevents); ++evt) - { - // all the buttons are at the end of the data format - // they are bytes rather than longs - if (evt->dwOfs < DIJOFS_BUTTON(0)) - *(DWORD*)(((BYTE*)&m_state_in) + evt->dwOfs) = evt->dwData; - else - ((BYTE*)&m_state_in)[evt->dwOfs] = (BYTE)evt->dwData; - } + if (SUCCEEDED(hr)) + { + for (LPDIDEVICEOBJECTDATA evt = evtbuf; evt != (evtbuf + numevents); ++evt) + { + // all the buttons are at the end of the data format + // they are bytes rather than longs + if (evt->dwOfs < DIJOFS_BUTTON(0)) + *(DWORD*)(((BYTE*)&m_state_in) + evt->dwOfs) = evt->dwData; + else + ((BYTE*)&m_state_in)[evt->dwOfs] = (BYTE)evt->dwData; + } - // seems like this needs to be done maybe... - if (DI_BUFFEROVERFLOW == hr) - hr = m_device->GetDeviceState(sizeof(m_state_in), &m_state_in); - } - } - else - { - hr = m_device->GetDeviceState(sizeof(m_state_in), &m_state_in); - } + // seems like this needs to be done maybe... + if (DI_BUFFEROVERFLOW == hr) + hr = m_device->GetDeviceState(sizeof(m_state_in), &m_state_in); + } + } + else + { + hr = m_device->GetDeviceState(sizeof(m_state_in), &m_state_in); + } - // try reacquire if input lost - if (DIERR_INPUTLOST == hr || DIERR_NOTACQUIRED == hr) - m_device->Acquire(); + // try reacquire if input lost + if (DIERR_INPUTLOST == hr || DIERR_NOTACQUIRED == hr) + m_device->Acquire(); } // get name std::string Joystick::Button::GetName() const { - std::ostringstream ss; - ss << "Button " << (int)m_index; - return ss.str(); + std::ostringstream ss; + ss << "Button " << (int)m_index; + return ss.str(); } std::string Joystick::Axis::GetName() const { - std::ostringstream ss; - // axis - if (m_index < 6) - { - ss << "Axis " << (char)('X' + (m_index % 3)); - if (m_index > 2) - ss << 'r'; - } - // slider - else - { - ss << "Slider " << (int)(m_index - 6); - } + std::ostringstream ss; + // axis + if (m_index < 6) + { + ss << "Axis " << (char)('X' + (m_index % 3)); + if (m_index > 2) + ss << 'r'; + } + // slider + else + { + ss << "Slider " << (int)(m_index - 6); + } - ss << (m_range < 0 ? '-' : '+'); - return ss.str(); + ss << (m_range < 0 ? '-' : '+'); + return ss.str(); } std::string Joystick::Hat::GetName() const { - static char tmpstr[] = "Hat . ."; - tmpstr[4] = (char)('0' + m_index); - tmpstr[6] = "NESW"[m_direction]; - return tmpstr; + static char tmpstr[] = "Hat . ."; + tmpstr[4] = (char)('0' + m_index); + tmpstr[6] = "NESW"[m_direction]; + return tmpstr; } // get / set state ControlState Joystick::Axis::GetState() const { - return std::max(0.0, ControlState(m_axis - m_base) / m_range); + return std::max(0.0, ControlState(m_axis - m_base) / m_range); } ControlState Joystick::Button::GetState() const { - return ControlState(m_button > 0); + return ControlState(m_button > 0); } ControlState Joystick::Hat::GetState() const { - // can this func be simplified ? - // hat centered code from MSDN - if (0xFFFF == LOWORD(m_hat)) - return 0; - - return (abs((int)(m_hat / 4500 - m_direction * 2 + 8) % 8 - 4) > 2); -} + // can this func be simplified ? + // hat centered code from MSDN + if (0xFFFF == LOWORD(m_hat)) + return 0; + return (abs((int)(m_hat / 4500 - m_direction * 2 + 8) % 8 - 4) > 2); +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.h b/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.h index 3064051101..9a14e910de 100644 --- a/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.h +++ b/Source/Core/InputCommon/ControllerInterface/DInput/DInputJoystick.h @@ -11,64 +11,71 @@ namespace ciface { namespace DInput { - void InitJoystick(IDirectInput8* const idi8, std::vector& devices, HWND hwnd); class Joystick : public ForceFeedback::ForceFeedbackDevice { private: - class Button : public Input - { - public: - Button(u8 index, const BYTE& button) : m_button(button), m_index(index) {} - std::string GetName() const override; - ControlState GetState() const override; - private: - const BYTE& m_button; - const u8 m_index; - }; + class Button : public Input + { + public: + Button(u8 index, const BYTE& button) : m_button(button), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; - class Axis : public Input - { - public: - Axis(u8 index, const LONG& axis, LONG base, LONG range) : m_axis(axis), m_base(base), m_range(range), m_index(index) {} - std::string GetName() const override; - ControlState GetState() const override; - private: - const LONG& m_axis; - const LONG m_base, m_range; - const u8 m_index; - }; + private: + const BYTE& m_button; + const u8 m_index; + }; - class Hat : public Input - { - public: - Hat(u8 index, const DWORD& hat, u8 direction) : m_hat(hat), m_direction(direction), m_index(index) {} - std::string GetName() const override; - ControlState GetState() const override; - private: - const DWORD& m_hat; - const u8 m_index, m_direction; - }; + class Axis : public Input + { + public: + Axis(u8 index, const LONG& axis, LONG base, LONG range) + : m_axis(axis), m_base(base), m_range(range), m_index(index) + { + } + std::string GetName() const override; + ControlState GetState() const override; + + private: + const LONG& m_axis; + const LONG m_base, m_range; + const u8 m_index; + }; + + class Hat : public Input + { + public: + Hat(u8 index, const DWORD& hat, u8 direction) + : m_hat(hat), m_direction(direction), m_index(index) + { + } + std::string GetName() const override; + ControlState GetState() const override; + + private: + const DWORD& m_hat; + const u8 m_index, m_direction; + }; public: - void UpdateInput() override; + void UpdateInput() override; - Joystick(const LPDIRECTINPUTDEVICE8 device, const unsigned int index); - ~Joystick(); + Joystick(const LPDIRECTINPUTDEVICE8 device, const unsigned int index); + ~Joystick(); - std::string GetName() const override; - int GetId() const override; - std::string GetSource() const override; + std::string GetName() const override; + int GetId() const override; + std::string GetSource() const override; private: - const LPDIRECTINPUTDEVICE8 m_device; - const unsigned int m_index; + const LPDIRECTINPUTDEVICE8 m_device; + const unsigned int m_index; - DIJOYSTATE m_state_in; + DIJOYSTATE m_state_in; - bool m_buffered; + bool m_buffered; }; - } } diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.cpp b/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.cpp index 2111f24d62..92c8514825 100644 --- a/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.cpp +++ b/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.cpp @@ -7,27 +7,25 @@ #include "InputCommon/ControllerInterface/DInput/DInput.h" #include "InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h" - // (lower would be more sensitive) user can lower sensitivity by setting range - // seems decent here ( at 8 ), I don't think anyone would need more sensitive than this - // and user can lower it much farther than they would want to with the range -#define MOUSE_AXIS_SENSITIVITY 8 +// (lower would be more sensitive) user can lower sensitivity by setting range +// seems decent here ( at 8 ), I don't think anyone would need more sensitive than this +// and user can lower it much farther than they would want to with the range +#define MOUSE_AXIS_SENSITIVITY 8 - // if input hasn't been received for this many ms, mouse input will be skipped - // otherwise it is just some crazy value -#define DROP_INPUT_TIME 250 +// if input hasn't been received for this many ms, mouse input will be skipped +// otherwise it is just some crazy value +#define DROP_INPUT_TIME 250 namespace ciface { namespace DInput { - static const struct { - const BYTE code; - const char* const name; -} named_keys[] = -{ -#include "InputCommon/ControllerInterface/DInput/NamedKeys.h" // NOLINT + const BYTE code; + const char* const name; +} named_keys[] = { +#include "InputCommon/ControllerInterface/DInput/NamedKeys.h" // NOLINT }; // lil silly @@ -35,223 +33,225 @@ static HWND m_hwnd; void InitKeyboardMouse(IDirectInput8* const idi8, std::vector& devices, HWND _hwnd) { - m_hwnd = _hwnd; + m_hwnd = _hwnd; - // mouse and keyboard are a combined device, to allow shift+click and stuff - // if that's dumb, I will make a VirtualDevice class that just uses ranges of inputs/outputs from other devices - // so there can be a separated Keyboard and mouse, as well as combined KeyboardMouse + // mouse and keyboard are a combined device, to allow shift+click and stuff + // if that's dumb, I will make a VirtualDevice class that just uses ranges of inputs/outputs from + // other devices + // so there can be a separated Keyboard and mouse, as well as combined KeyboardMouse - LPDIRECTINPUTDEVICE8 kb_device = nullptr; - LPDIRECTINPUTDEVICE8 mo_device = nullptr; + LPDIRECTINPUTDEVICE8 kb_device = nullptr; + LPDIRECTINPUTDEVICE8 mo_device = nullptr; - if (SUCCEEDED(idi8->CreateDevice( GUID_SysKeyboard, &kb_device, nullptr))) - { - if (SUCCEEDED(kb_device->SetDataFormat(&c_dfDIKeyboard))) - { - if (SUCCEEDED(kb_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) - { - if (SUCCEEDED(idi8->CreateDevice( GUID_SysMouse, &mo_device, nullptr ))) - { - if (SUCCEEDED(mo_device->SetDataFormat(&c_dfDIMouse2))) - { - if (SUCCEEDED(mo_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) - { - devices.push_back(new KeyboardMouse(kb_device, mo_device)); - return; - } - } - } - } - } - } + if (SUCCEEDED(idi8->CreateDevice(GUID_SysKeyboard, &kb_device, nullptr))) + { + if (SUCCEEDED(kb_device->SetDataFormat(&c_dfDIKeyboard))) + { + if (SUCCEEDED(kb_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) + { + if (SUCCEEDED(idi8->CreateDevice(GUID_SysMouse, &mo_device, nullptr))) + { + if (SUCCEEDED(mo_device->SetDataFormat(&c_dfDIMouse2))) + { + if (SUCCEEDED( + mo_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) + { + devices.push_back(new KeyboardMouse(kb_device, mo_device)); + return; + } + } + } + } + } + } - if (kb_device) - kb_device->Release(); - if (mo_device) - mo_device->Release(); + if (kb_device) + kb_device->Release(); + if (mo_device) + mo_device->Release(); } KeyboardMouse::~KeyboardMouse() { - // kb - m_kb_device->Unacquire(); - m_kb_device->Release(); - // mouse - m_mo_device->Unacquire(); - m_mo_device->Release(); + // kb + m_kb_device->Unacquire(); + m_kb_device->Release(); + // mouse + m_mo_device->Unacquire(); + m_mo_device->Release(); } -KeyboardMouse::KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, const LPDIRECTINPUTDEVICE8 mo_device) - : m_kb_device(kb_device) - , m_mo_device(mo_device) +KeyboardMouse::KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, + const LPDIRECTINPUTDEVICE8 mo_device) + : m_kb_device(kb_device), m_mo_device(mo_device) { - m_kb_device->Acquire(); - m_mo_device->Acquire(); + m_kb_device->Acquire(); + m_mo_device->Acquire(); - m_last_update = GetTickCount(); + m_last_update = GetTickCount(); - ZeroMemory(&m_state_in, sizeof(m_state_in)); + ZeroMemory(&m_state_in, sizeof(m_state_in)); - // KEYBOARD - // add keys - for (u8 i = 0; i < sizeof(named_keys)/sizeof(*named_keys); ++i) - AddInput(new Key(i, m_state_in.keyboard[named_keys[i].code])); + // KEYBOARD + // add keys + for (u8 i = 0; i < sizeof(named_keys) / sizeof(*named_keys); ++i) + AddInput(new Key(i, m_state_in.keyboard[named_keys[i].code])); - // MOUSE - // get caps - DIDEVCAPS mouse_caps; - ZeroMemory( &mouse_caps, sizeof(mouse_caps) ); - mouse_caps.dwSize = sizeof(mouse_caps); - m_mo_device->GetCapabilities(&mouse_caps); - // mouse buttons - for (u8 i = 0; i < mouse_caps.dwButtons; ++i) - AddInput(new Button(i, m_state_in.mouse.rgbButtons[i])); - // mouse axes - for (unsigned int i = 0; i < mouse_caps.dwAxes; ++i) - { - const LONG& ax = (&m_state_in.mouse.lX)[i]; + // MOUSE + // get caps + DIDEVCAPS mouse_caps; + ZeroMemory(&mouse_caps, sizeof(mouse_caps)); + mouse_caps.dwSize = sizeof(mouse_caps); + m_mo_device->GetCapabilities(&mouse_caps); + // mouse buttons + for (u8 i = 0; i < mouse_caps.dwButtons; ++i) + AddInput(new Button(i, m_state_in.mouse.rgbButtons[i])); + // mouse axes + for (unsigned int i = 0; i < mouse_caps.dwAxes; ++i) + { + const LONG& ax = (&m_state_in.mouse.lX)[i]; - // each axis gets a negative and a positive input instance associated with it - AddInput(new Axis(i, ax, (2==i) ? -1 : -MOUSE_AXIS_SENSITIVITY)); - AddInput(new Axis(i, ax, -(2==i) ? 1 : MOUSE_AXIS_SENSITIVITY)); - } - // cursor, with a hax for-loop - for (unsigned int i=0; i<4; ++i) - AddInput(new Cursor(!!(i&2), (&m_state_in.cursor.x)[i/2], !!(i&1))); + // each axis gets a negative and a positive input instance associated with it + AddInput(new Axis(i, ax, (2 == i) ? -1 : -MOUSE_AXIS_SENSITIVITY)); + AddInput(new Axis(i, ax, -(2 == i) ? 1 : MOUSE_AXIS_SENSITIVITY)); + } + // cursor, with a hax for-loop + for (unsigned int i = 0; i < 4; ++i) + AddInput(new Cursor(!!(i & 2), (&m_state_in.cursor.x)[i / 2], !!(i & 1))); } void GetMousePos(ControlState* const x, ControlState* const y) { - POINT point = { 1, 1 }; - GetCursorPos(&point); - // Get the cursor position relative to the upper left corner of the current window (separate or render to main) - HWND hwnd = WindowFromPoint(point); - DWORD processId; - GetWindowThreadProcessId(hwnd, &processId); - if (processId == GetCurrentProcessId()) - { - ScreenToClient(hwnd, &point); + POINT point = {1, 1}; + GetCursorPos(&point); + // Get the cursor position relative to the upper left corner of the current window (separate or + // render to main) + HWND hwnd = WindowFromPoint(point); + DWORD processId; + GetWindowThreadProcessId(hwnd, &processId); + if (processId == GetCurrentProcessId()) + { + ScreenToClient(hwnd, &point); - // Get the size of the current window. (In my case Rect.top and Rect.left was zero.) - RECT rect; - GetClientRect(hwnd, &rect); - // Width and height is the size of the rendering window - unsigned int win_width = rect.right - rect.left; - unsigned int win_height = rect.bottom - rect.top; + // Get the size of the current window. (In my case Rect.top and Rect.left was zero.) + RECT rect; + GetClientRect(hwnd, &rect); + // Width and height is the size of the rendering window + unsigned int win_width = rect.right - rect.left; + unsigned int win_height = rect.bottom - rect.top; - // Return the mouse position as a range from -1 to 1 - *x = (ControlState)point.x / (ControlState)win_width * 2 - 1; - *y = (ControlState)point.y / (ControlState)win_height * 2 - 1; - } - else - { - *x = (ControlState)1; - *y = (ControlState)1; - } + // Return the mouse position as a range from -1 to 1 + *x = (ControlState)point.x / (ControlState)win_width * 2 - 1; + *y = (ControlState)point.y / (ControlState)win_height * 2 - 1; + } + else + { + *x = (ControlState)1; + *y = (ControlState)1; + } } void KeyboardMouse::UpdateInput() { - DIMOUSESTATE2 tmp_mouse; + DIMOUSESTATE2 tmp_mouse; - // if mouse position hasn't been updated in a short while, skip a dev state - DWORD cur_time = GetTickCount(); - if (cur_time - m_last_update > DROP_INPUT_TIME) - { - // set axes to zero - ZeroMemory(&m_state_in.mouse, sizeof(m_state_in.mouse)); - // skip this input state - m_mo_device->GetDeviceState(sizeof(tmp_mouse), &tmp_mouse); - } + // if mouse position hasn't been updated in a short while, skip a dev state + DWORD cur_time = GetTickCount(); + if (cur_time - m_last_update > DROP_INPUT_TIME) + { + // set axes to zero + ZeroMemory(&m_state_in.mouse, sizeof(m_state_in.mouse)); + // skip this input state + m_mo_device->GetDeviceState(sizeof(tmp_mouse), &tmp_mouse); + } - m_last_update = cur_time; + m_last_update = cur_time; - HRESULT kb_hr = m_kb_device->GetDeviceState(sizeof(m_state_in.keyboard), &m_state_in.keyboard); - HRESULT mo_hr = m_mo_device->GetDeviceState(sizeof(tmp_mouse), &tmp_mouse); + HRESULT kb_hr = m_kb_device->GetDeviceState(sizeof(m_state_in.keyboard), &m_state_in.keyboard); + HRESULT mo_hr = m_mo_device->GetDeviceState(sizeof(tmp_mouse), &tmp_mouse); - if (DIERR_INPUTLOST == kb_hr || DIERR_NOTACQUIRED == kb_hr) - m_kb_device->Acquire(); + if (DIERR_INPUTLOST == kb_hr || DIERR_NOTACQUIRED == kb_hr) + m_kb_device->Acquire(); - if (DIERR_INPUTLOST == mo_hr || DIERR_NOTACQUIRED == mo_hr) - m_mo_device->Acquire(); + if (DIERR_INPUTLOST == mo_hr || DIERR_NOTACQUIRED == mo_hr) + m_mo_device->Acquire(); - if (SUCCEEDED(kb_hr) && SUCCEEDED(mo_hr)) - { - // need to smooth out the axes, otherwise it doesn't work for shit - for (unsigned int i = 0; i < 3; ++i) - ((&m_state_in.mouse.lX)[i] += (&tmp_mouse.lX)[i]) /= 2; + if (SUCCEEDED(kb_hr) && SUCCEEDED(mo_hr)) + { + // need to smooth out the axes, otherwise it doesn't work for shit + for (unsigned int i = 0; i < 3; ++i) + ((&m_state_in.mouse.lX)[i] += (&tmp_mouse.lX)[i]) /= 2; - // copy over the buttons - memcpy(m_state_in.mouse.rgbButtons, tmp_mouse.rgbButtons, sizeof(m_state_in.mouse.rgbButtons)); + // copy over the buttons + memcpy(m_state_in.mouse.rgbButtons, tmp_mouse.rgbButtons, sizeof(m_state_in.mouse.rgbButtons)); - // update mouse cursor - GetMousePos(&m_state_in.cursor.x, &m_state_in.cursor.y); - } + // update mouse cursor + GetMousePos(&m_state_in.cursor.x, &m_state_in.cursor.y); + } } std::string KeyboardMouse::GetName() const { - return "Keyboard Mouse"; + return "Keyboard Mouse"; } int KeyboardMouse::GetId() const { - // should this be -1, idk - return 0; + // should this be -1, idk + return 0; } std::string KeyboardMouse::GetSource() const { - return DINPUT_SOURCE_NAME; + return DINPUT_SOURCE_NAME; } // names std::string KeyboardMouse::Key::GetName() const { - return named_keys[m_index].name; + return named_keys[m_index].name; } std::string KeyboardMouse::Button::GetName() const { - return std::string("Click ") + char('0' + m_index); + return std::string("Click ") + char('0' + m_index); } std::string KeyboardMouse::Axis::GetName() const { - static char tmpstr[] = "Axis .."; - tmpstr[5] = (char)('X' + m_index); - tmpstr[6] = (m_range<0 ? '-' : '+'); - return tmpstr; + static char tmpstr[] = "Axis .."; + tmpstr[5] = (char)('X' + m_index); + tmpstr[6] = (m_range < 0 ? '-' : '+'); + return tmpstr; } std::string KeyboardMouse::Cursor::GetName() const { - static char tmpstr[] = "Cursor .."; - tmpstr[7] = (char)('X' + m_index); - tmpstr[8] = (m_positive ? '+' : '-'); - return tmpstr; + static char tmpstr[] = "Cursor .."; + tmpstr[7] = (char)('X' + m_index); + tmpstr[8] = (m_positive ? '+' : '-'); + return tmpstr; } // get/set state ControlState KeyboardMouse::Key::GetState() const { - return (m_key != 0); + return (m_key != 0); } ControlState KeyboardMouse::Button::GetState() const { - return (m_button != 0); + return (m_button != 0); } ControlState KeyboardMouse::Axis::GetState() const { - return std::max(0.0, ControlState(m_axis) / m_range); + return std::max(0.0, ControlState(m_axis) / m_range); } ControlState KeyboardMouse::Cursor::GetState() const { - return std::max(0.0, ControlState(m_axis) / (m_positive ? 1.0 : -1.0)); -} - + return std::max(0.0, ControlState(m_axis) / (m_positive ? 1.0 : -1.0)); +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h b/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h index 14d885ff94..1ba9022f9d 100644 --- a/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h +++ b/Source/Core/InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h @@ -6,93 +6,98 @@ #include -#include "InputCommon/ControllerInterface/Device.h" #include "InputCommon/ControllerInterface/DInput/DInput8.h" +#include "InputCommon/ControllerInterface/Device.h" namespace ciface { namespace DInput { - void InitKeyboardMouse(IDirectInput8* const idi8, std::vector& devices, HWND _hwnd); class KeyboardMouse : public Core::Device { private: - struct State - { - BYTE keyboard[256]; - DIMOUSESTATE2 mouse; - struct - { - ControlState x, y; - } cursor; - }; + struct State + { + BYTE keyboard[256]; + DIMOUSESTATE2 mouse; + struct + { + ControlState x, y; + } cursor; + }; - class Key : public Input - { - public: - Key(u8 index, const BYTE& key) : m_key(key), m_index(index) {} - std::string GetName() const override; - ControlState GetState() const override; - private: - const BYTE& m_key; - const u8 m_index; - }; + class Key : public Input + { + public: + Key(u8 index, const BYTE& key) : m_key(key), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; - class Button : public Input - { - public: - Button(u8 index, const BYTE& button) : m_button(button), m_index(index) {} - std::string GetName() const override; - ControlState GetState() const override; - private: - const BYTE& m_button; - const u8 m_index; - }; + private: + const BYTE& m_key; + const u8 m_index; + }; - class Axis : public Input - { - public: - Axis(u8 index, const LONG& axis, LONG range) : m_axis(axis), m_range(range), m_index(index) {} - std::string GetName() const override; - ControlState GetState() const override; - private: - const LONG& m_axis; - const LONG m_range; - const u8 m_index; - }; + class Button : public Input + { + public: + Button(u8 index, const BYTE& button) : m_button(button), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; - class Cursor : public Input - { - public: - Cursor(u8 index, const ControlState& axis, const bool positive) : m_axis(axis), m_index(index), m_positive(positive) {} - std::string GetName() const override; - bool IsDetectable() override { return false; } - ControlState GetState() const override; - private: - const ControlState& m_axis; - const u8 m_index; - const bool m_positive; - }; + private: + const BYTE& m_button; + const u8 m_index; + }; + + class Axis : public Input + { + public: + Axis(u8 index, const LONG& axis, LONG range) : m_axis(axis), m_range(range), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; + + private: + const LONG& m_axis; + const LONG m_range; + const u8 m_index; + }; + + class Cursor : public Input + { + public: + Cursor(u8 index, const ControlState& axis, const bool positive) + : m_axis(axis), m_index(index), m_positive(positive) + { + } + std::string GetName() const override; + bool IsDetectable() override { return false; } + ControlState GetState() const override; + + private: + const ControlState& m_axis; + const u8 m_index; + const bool m_positive; + }; public: - void UpdateInput() override; + void UpdateInput() override; - KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, const LPDIRECTINPUTDEVICE8 mo_device); - ~KeyboardMouse(); + KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, const LPDIRECTINPUTDEVICE8 mo_device); + ~KeyboardMouse(); - std::string GetName() const override; - int GetId() const override; - std::string GetSource() const override; + std::string GetName() const override; + int GetId() const override; + std::string GetSource() const override; private: - const LPDIRECTINPUTDEVICE8 m_kb_device; - const LPDIRECTINPUTDEVICE8 m_mo_device; + const LPDIRECTINPUTDEVICE8 m_kb_device; + const LPDIRECTINPUTDEVICE8 m_mo_device; - DWORD m_last_update; - State m_state_in; + DWORD m_last_update; + State m_state_in; }; - } } diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/NamedKeys.h b/Source/Core/InputCommon/ControllerInterface/DInput/NamedKeys.h index 6802fd7888..2ac38a86fe 100644 --- a/Source/Core/InputCommon/ControllerInterface/DInput/NamedKeys.h +++ b/Source/Core/InputCommon/ControllerInterface/DInput/NamedKeys.h @@ -2,147 +2,40 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -{ DIK_A, "A" }, -{ DIK_B, "B" }, -{ DIK_C, "C" }, -{ DIK_D, "D" }, -{ DIK_E, "E" }, -{ DIK_F, "F" }, -{ DIK_G, "G" }, -{ DIK_H, "H" }, -{ DIK_I, "I" }, -{ DIK_J, "J" }, -{ DIK_K, "K" }, -{ DIK_L, "L" }, -{ DIK_M, "M" }, -{ DIK_N, "N" }, -{ DIK_O, "O" }, -{ DIK_P, "P" }, -{ DIK_Q, "Q" }, -{ DIK_R, "R" }, -{ DIK_S, "S" }, -{ DIK_T, "T" }, -{ DIK_U, "U" }, -{ DIK_V, "V" }, -{ DIK_W, "W" }, -{ DIK_X, "X" }, -{ DIK_Y, "Y" }, -{ DIK_Z, "Z" }, -{ DIK_0, "0" }, -{ DIK_1, "1" }, -{ DIK_2, "2" }, -{ DIK_3, "3" }, -{ DIK_4, "4" }, -{ DIK_5, "5" }, -{ DIK_6, "6" }, -{ DIK_7, "7" }, -{ DIK_8, "8" }, -{ DIK_9, "9" }, -{ DIK_UP, "UP" }, -{ DIK_DOWN, "DOWN" }, -{ DIK_LEFT, "LEFT" }, -{ DIK_RIGHT, "RIGHT" }, -{ DIK_ABNT_C1, "ABNT_C1" }, -{ DIK_ABNT_C2, "ABNT_C2" }, -{ DIK_ADD, "ADD" }, -{ DIK_APOSTROPHE, "APOSTROPHE" }, -{ DIK_APPS, "APPS" }, -{ DIK_AT, "AT" }, -{ DIK_AX, "AX" }, -{ DIK_BACK, "BACK" }, -{ DIK_BACKSLASH, "BACKSLASH" }, -{ DIK_CALCULATOR, "CALCULATOR" }, -{ DIK_CAPITAL, "CAPITAL" }, -{ DIK_COLON, "COLON" }, -{ DIK_COMMA, "COMMA" }, -{ DIK_CONVERT, "CONVERT" }, -{ DIK_DECIMAL, "DECIMAL" }, -{ DIK_DELETE, "DELETE" }, -{ DIK_DIVIDE, "DIVIDE" }, -{ DIK_EQUALS, "EQUALS" }, -{ DIK_ESCAPE, "ESCAPE" }, -{ DIK_F1, "F1" }, -{ DIK_F2, "F2" }, -{ DIK_F3, "F3" }, -{ DIK_F4, "F4" }, -{ DIK_F5, "F5" }, -{ DIK_F6, "F6" }, -{ DIK_F7, "F7" }, -{ DIK_F8, "F8" }, -{ DIK_F9, "F9" }, -{ DIK_F10, "F10" }, -{ DIK_F11, "F11" }, -{ DIK_F12, "F12" }, -{ DIK_F13, "F13" }, -{ DIK_F14, "F14" }, -{ DIK_F15, "F15" }, -{ DIK_GRAVE, "GRAVE" }, -{ DIK_HOME, "HOME" }, -{ DIK_END, "END" }, -{ DIK_INSERT, "INSERT" }, -{ DIK_KANA, "KANA" }, -{ DIK_KANJI, "KANJI" }, -{ DIK_MAIL, "MAIL" }, -{ DIK_MEDIASELECT, "MEDIASELECT" }, -{ DIK_MEDIASTOP, "MEDIASTOP" }, -{ DIK_MINUS, "MINUS" }, -{ DIK_MULTIPLY, "MULTIPLY" }, -{ DIK_MUTE, "MUTE" }, -{ DIK_MYCOMPUTER, "MYCOMPUTER" }, -{ DIK_NEXTTRACK, "NEXTTRACK" }, -{ DIK_NOCONVERT, "NOCONVERT" }, -{ DIK_NUMLOCK, "NUMLOCK" }, -{ DIK_NUMPAD0, "NUMPAD0" }, -{ DIK_NUMPAD1, "NUMPAD1" }, -{ DIK_NUMPAD2, "NUMPAD2" }, -{ DIK_NUMPAD3, "NUMPAD3" }, -{ DIK_NUMPAD4, "NUMPAD4" }, -{ DIK_NUMPAD5, "NUMPAD5" }, -{ DIK_NUMPAD6, "NUMPAD6" }, -{ DIK_NUMPAD7, "NUMPAD7" }, -{ DIK_NUMPAD8, "NUMPAD8" }, -{ DIK_NUMPAD9, "NUMPAD9" }, -{ DIK_NUMPADCOMMA, "NUMPADCOMMA" }, -{ DIK_NUMPADENTER, "NUMPADENTER" }, -{ DIK_NUMPADEQUALS, "NUMPADEQUALS" }, -{ DIK_OEM_102, "OEM_102" }, -{ DIK_PAUSE, "PAUSE" }, -{ DIK_PERIOD, "PERIOD" }, -{ DIK_PLAYPAUSE, "PLAYPAUSE" }, -{ DIK_POWER, "POWER" }, -{ DIK_PREVTRACK, "PREVTRACK" }, -{ DIK_PRIOR, "PRIOR" }, -{ DIK_NEXT, "NEXT" }, -{ DIK_RETURN, "RETURN" }, -{ DIK_LBRACKET, "LBRACKET" }, -{ DIK_RBRACKET, "RBRACKET" }, -{ DIK_LCONTROL, "LCONTROL" }, -{ DIK_RCONTROL, "RCONTROL" }, -{ DIK_LMENU, "LMENU" }, -{ DIK_RMENU, "RMENU" }, -{ DIK_LSHIFT, "LSHIFT" }, -{ DIK_RSHIFT, "RSHIFT" }, -{ DIK_LWIN, "LWIN" }, -{ DIK_RWIN, "RWIN" }, -{ DIK_SCROLL, "SCROLL" }, -{ DIK_SEMICOLON, "SEMICOLON" }, -{ DIK_SLASH, "SLASH" }, -{ DIK_SLEEP, "SLEEP" }, -{ DIK_SPACE, "SPACE" }, -{ DIK_STOP, "STOP" }, -{ DIK_SUBTRACT, "SUBTRACT" }, -{ DIK_SYSRQ, "SYSRQ" }, -{ DIK_TAB, "TAB" }, -{ DIK_UNDERLINE, "UNDERLINE" }, -{ DIK_UNLABELED, "UNLABELED" }, -{ DIK_VOLUMEDOWN, "VOLUMEDOWN" }, -{ DIK_VOLUMEUP, "VOLUMEUP" }, -{ DIK_WAKE, "WAKE" }, -{ DIK_WEBBACK, "WEBBACK" }, -{ DIK_WEBFAVORITES, "WEBFAVORITES" }, -{ DIK_WEBFORWARD, "WEBFORWARD" }, -{ DIK_WEBHOME, "WEBHOME" }, -{ DIK_WEBREFRESH, "WEBREFRESH" }, -{ DIK_WEBSEARCH, "WEBSEARCH" }, -{ DIK_WEBSTOP, "WEBSTOP" }, -{ DIK_YEN, "YEN" }, +{DIK_A, "A"}, {DIK_B, "B"}, {DIK_C, "C"}, {DIK_D, "D"}, {DIK_E, "E"}, {DIK_F, "F"}, {DIK_G, "G"}, + {DIK_H, "H"}, {DIK_I, "I"}, {DIK_J, "J"}, {DIK_K, "K"}, {DIK_L, "L"}, {DIK_M, "M"}, + {DIK_N, "N"}, {DIK_O, "O"}, {DIK_P, "P"}, {DIK_Q, "Q"}, {DIK_R, "R"}, {DIK_S, "S"}, + {DIK_T, "T"}, {DIK_U, "U"}, {DIK_V, "V"}, {DIK_W, "W"}, {DIK_X, "X"}, {DIK_Y, "Y"}, + {DIK_Z, "Z"}, {DIK_0, "0"}, {DIK_1, "1"}, {DIK_2, "2"}, {DIK_3, "3"}, {DIK_4, "4"}, + {DIK_5, "5"}, {DIK_6, "6"}, {DIK_7, "7"}, {DIK_8, "8"}, {DIK_9, "9"}, {DIK_UP, "UP"}, + {DIK_DOWN, "DOWN"}, {DIK_LEFT, "LEFT"}, {DIK_RIGHT, "RIGHT"}, {DIK_ABNT_C1, "ABNT_C1"}, + {DIK_ABNT_C2, "ABNT_C2"}, {DIK_ADD, "ADD"}, {DIK_APOSTROPHE, "APOSTROPHE"}, {DIK_APPS, "APPS"}, + {DIK_AT, "AT"}, {DIK_AX, "AX"}, {DIK_BACK, "BACK"}, {DIK_BACKSLASH, "BACKSLASH"}, + {DIK_CALCULATOR, "CALCULATOR"}, {DIK_CAPITAL, "CAPITAL"}, {DIK_COLON, "COLON"}, + {DIK_COMMA, "COMMA"}, {DIK_CONVERT, "CONVERT"}, {DIK_DECIMAL, "DECIMAL"}, + {DIK_DELETE, "DELETE"}, {DIK_DIVIDE, "DIVIDE"}, {DIK_EQUALS, "EQUALS"}, {DIK_ESCAPE, "ESCAPE"}, + {DIK_F1, "F1"}, {DIK_F2, "F2"}, {DIK_F3, "F3"}, {DIK_F4, "F4"}, {DIK_F5, "F5"}, {DIK_F6, "F6"}, + {DIK_F7, "F7"}, {DIK_F8, "F8"}, {DIK_F9, "F9"}, {DIK_F10, "F10"}, {DIK_F11, "F11"}, + {DIK_F12, "F12"}, {DIK_F13, "F13"}, {DIK_F14, "F14"}, {DIK_F15, "F15"}, {DIK_GRAVE, "GRAVE"}, + {DIK_HOME, "HOME"}, {DIK_END, "END"}, {DIK_INSERT, "INSERT"}, {DIK_KANA, "KANA"}, + {DIK_KANJI, "KANJI"}, {DIK_MAIL, "MAIL"}, {DIK_MEDIASELECT, "MEDIASELECT"}, + {DIK_MEDIASTOP, "MEDIASTOP"}, {DIK_MINUS, "MINUS"}, {DIK_MULTIPLY, "MULTIPLY"}, + {DIK_MUTE, "MUTE"}, {DIK_MYCOMPUTER, "MYCOMPUTER"}, {DIK_NEXTTRACK, "NEXTTRACK"}, + {DIK_NOCONVERT, "NOCONVERT"}, {DIK_NUMLOCK, "NUMLOCK"}, {DIK_NUMPAD0, "NUMPAD0"}, + {DIK_NUMPAD1, "NUMPAD1"}, {DIK_NUMPAD2, "NUMPAD2"}, {DIK_NUMPAD3, "NUMPAD3"}, + {DIK_NUMPAD4, "NUMPAD4"}, {DIK_NUMPAD5, "NUMPAD5"}, {DIK_NUMPAD6, "NUMPAD6"}, + {DIK_NUMPAD7, "NUMPAD7"}, {DIK_NUMPAD8, "NUMPAD8"}, {DIK_NUMPAD9, "NUMPAD9"}, + {DIK_NUMPADCOMMA, "NUMPADCOMMA"}, {DIK_NUMPADENTER, "NUMPADENTER"}, + {DIK_NUMPADEQUALS, "NUMPADEQUALS"}, {DIK_OEM_102, "OEM_102"}, {DIK_PAUSE, "PAUSE"}, + {DIK_PERIOD, "PERIOD"}, {DIK_PLAYPAUSE, "PLAYPAUSE"}, {DIK_POWER, "POWER"}, + {DIK_PREVTRACK, "PREVTRACK"}, {DIK_PRIOR, "PRIOR"}, {DIK_NEXT, "NEXT"}, {DIK_RETURN, "RETURN"}, + {DIK_LBRACKET, "LBRACKET"}, {DIK_RBRACKET, "RBRACKET"}, {DIK_LCONTROL, "LCONTROL"}, + {DIK_RCONTROL, "RCONTROL"}, {DIK_LMENU, "LMENU"}, {DIK_RMENU, "RMENU"}, {DIK_LSHIFT, "LSHIFT"}, + {DIK_RSHIFT, "RSHIFT"}, {DIK_LWIN, "LWIN"}, {DIK_RWIN, "RWIN"}, {DIK_SCROLL, "SCROLL"}, + {DIK_SEMICOLON, "SEMICOLON"}, {DIK_SLASH, "SLASH"}, {DIK_SLEEP, "SLEEP"}, {DIK_SPACE, "SPACE"}, + {DIK_STOP, "STOP"}, {DIK_SUBTRACT, "SUBTRACT"}, {DIK_SYSRQ, "SYSRQ"}, {DIK_TAB, "TAB"}, + {DIK_UNDERLINE, "UNDERLINE"}, {DIK_UNLABELED, "UNLABELED"}, {DIK_VOLUMEDOWN, "VOLUMEDOWN"}, + {DIK_VOLUMEUP, "VOLUMEUP"}, {DIK_WAKE, "WAKE"}, {DIK_WEBBACK, "WEBBACK"}, + {DIK_WEBFAVORITES, "WEBFAVORITES"}, {DIK_WEBFORWARD, "WEBFORWARD"}, {DIK_WEBHOME, "WEBHOME"}, + {DIK_WEBREFRESH, "WEBREFRESH"}, {DIK_WEBSEARCH, "WEBSEARCH"}, {DIK_WEBSTOP, "WEBSTOP"}, + {DIK_YEN, "YEN"}, diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.cpp b/Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.cpp index aedfc5dc44..d6f1cab257 100644 --- a/Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.cpp +++ b/Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.cpp @@ -5,118 +5,127 @@ // This function is contained in a separate file because WbemIdl.h pulls in files which break on // /Zc:strictStrings, so this compilation unit is compiled without /Zc:strictStrings. -#include #include #include +#include -#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=nullptr; } } +#define SAFE_RELEASE(p) \ + { \ + if (p) \ + { \ + (p)->Release(); \ + (p) = nullptr; \ + } \ + } namespace ciface { namespace DInput { - //----------------------------------------------------------------------------- // Modified some MSDN code to get all the XInput device GUID.Data1 values in a vector, // faster than checking all the devices for each DirectInput device, like MSDN says to do //----------------------------------------------------------------------------- void GetXInputGUIDS(std::vector* guids) { - IWbemLocator* pIWbemLocator = nullptr; - IEnumWbemClassObject* pEnumDevices = nullptr; - IWbemClassObject* pDevices[20] = {0}; - IWbemServices* pIWbemServices = nullptr; - BSTR bstrNamespace = nullptr; - BSTR bstrDeviceID = nullptr; - BSTR bstrClassName = nullptr; - DWORD uReturned = 0; - VARIANT var; - HRESULT hr; + IWbemLocator* pIWbemLocator = nullptr; + IEnumWbemClassObject* pEnumDevices = nullptr; + IWbemClassObject* pDevices[20] = {0}; + IWbemServices* pIWbemServices = nullptr; + BSTR bstrNamespace = nullptr; + BSTR bstrDeviceID = nullptr; + BSTR bstrClassName = nullptr; + DWORD uReturned = 0; + VARIANT var; + HRESULT hr; - // CoInit if needed - hr = CoInitialize(nullptr); - bool bCleanupCOM = SUCCEEDED(hr); + // CoInit if needed + hr = CoInitialize(nullptr); + bool bCleanupCOM = SUCCEEDED(hr); - // Create WMI - hr = CoCreateInstance(__uuidof(WbemLocator), - nullptr, - CLSCTX_INPROC_SERVER, - __uuidof(IWbemLocator), - (LPVOID*) &pIWbemLocator); - if (FAILED(hr) || pIWbemLocator == nullptr) - goto LCleanup; + // Create WMI + hr = CoCreateInstance(__uuidof(WbemLocator), nullptr, CLSCTX_INPROC_SERVER, + __uuidof(IWbemLocator), (LPVOID*)&pIWbemLocator); + if (FAILED(hr) || pIWbemLocator == nullptr) + goto LCleanup; - bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2"); if (bstrNamespace == nullptr) goto LCleanup; - bstrClassName = SysAllocString(L"Win32_PNPEntity"); if (bstrClassName == nullptr) goto LCleanup; - bstrDeviceID = SysAllocString(L"DeviceID"); if (bstrDeviceID == nullptr) goto LCleanup; + bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2"); + if (bstrNamespace == nullptr) + goto LCleanup; + bstrClassName = SysAllocString(L"Win32_PNPEntity"); + if (bstrClassName == nullptr) + goto LCleanup; + bstrDeviceID = SysAllocString(L"DeviceID"); + if (bstrDeviceID == nullptr) + goto LCleanup; - // Connect to WMI - hr = pIWbemLocator->ConnectServer(bstrNamespace, nullptr, nullptr, 0L, 0L, nullptr, nullptr, &pIWbemServices); - if (FAILED(hr) || pIWbemServices == nullptr) - goto LCleanup; + // Connect to WMI + hr = pIWbemLocator->ConnectServer(bstrNamespace, nullptr, nullptr, 0L, 0L, nullptr, nullptr, + &pIWbemServices); + if (FAILED(hr) || pIWbemServices == nullptr) + goto LCleanup; - // Switch security level to IMPERSONATE. - CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, - RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE); + // Switch security level to IMPERSONATE. + CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, + RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE); - hr = pIWbemServices->CreateInstanceEnum(bstrClassName, 0, nullptr, &pEnumDevices); - if (FAILED(hr) || pEnumDevices == nullptr) - goto LCleanup; + hr = pIWbemServices->CreateInstanceEnum(bstrClassName, 0, nullptr, &pEnumDevices); + if (FAILED(hr) || pEnumDevices == nullptr) + goto LCleanup; - // Loop over all devices - while (true) - { - // Get 20 at a time - hr = pEnumDevices->Next(10000, 20, pDevices, &uReturned); - if (FAILED(hr) || uReturned == 0) - break; + // Loop over all devices + while (true) + { + // Get 20 at a time + hr = pEnumDevices->Next(10000, 20, pDevices, &uReturned); + if (FAILED(hr) || uReturned == 0) + break; - for (UINT iDevice = 0; iDevice < uReturned; ++iDevice) - { - // For each device, get its device ID - hr = pDevices[iDevice]->Get(bstrDeviceID, 0L, &var, nullptr, nullptr); - if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != nullptr) - { - // Check if the device ID contains "IG_". If it does, then it's an XInput device - // This information can not be found from DirectInput - if (wcsstr(var.bstrVal, L"IG_")) - { - // If it does, then get the VID/PID from var.bstrVal - DWORD dwPid = 0, dwVid = 0; - WCHAR* strVid = wcsstr(var.bstrVal, L"VID_"); - if (strVid && swscanf(strVid, L"VID_%4X", &dwVid) != 1) - dwVid = 0; - WCHAR* strPid = wcsstr(var.bstrVal, L"PID_"); - if (strPid && swscanf(strPid, L"PID_%4X", &dwPid) != 1) - dwPid = 0; + for (UINT iDevice = 0; iDevice < uReturned; ++iDevice) + { + // For each device, get its device ID + hr = pDevices[iDevice]->Get(bstrDeviceID, 0L, &var, nullptr, nullptr); + if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != nullptr) + { + // Check if the device ID contains "IG_". If it does, then it's an XInput device + // This information can not be found from DirectInput + if (wcsstr(var.bstrVal, L"IG_")) + { + // If it does, then get the VID/PID from var.bstrVal + DWORD dwPid = 0, dwVid = 0; + WCHAR* strVid = wcsstr(var.bstrVal, L"VID_"); + if (strVid && swscanf(strVid, L"VID_%4X", &dwVid) != 1) + dwVid = 0; + WCHAR* strPid = wcsstr(var.bstrVal, L"PID_"); + if (strPid && swscanf(strPid, L"PID_%4X", &dwPid) != 1) + dwPid = 0; - // Compare the VID/PID to the DInput device - DWORD dwVidPid = MAKELONG(dwVid, dwPid); - guids->push_back(dwVidPid); - //bIsXinputDevice = true; - } - } - SAFE_RELEASE(pDevices[iDevice]); - } - } + // Compare the VID/PID to the DInput device + DWORD dwVidPid = MAKELONG(dwVid, dwPid); + guids->push_back(dwVidPid); + // bIsXinputDevice = true; + } + } + SAFE_RELEASE(pDevices[iDevice]); + } + } LCleanup: - if (bstrNamespace) - SysFreeString(bstrNamespace); - if (bstrDeviceID) - SysFreeString(bstrDeviceID); - if (bstrClassName) - SysFreeString(bstrClassName); - for (UINT iDevice = 0; iDevice < 20; iDevice++) - SAFE_RELEASE(pDevices[iDevice]); - SAFE_RELEASE(pEnumDevices); - SAFE_RELEASE(pIWbemLocator); - SAFE_RELEASE(pIWbemServices); + if (bstrNamespace) + SysFreeString(bstrNamespace); + if (bstrDeviceID) + SysFreeString(bstrDeviceID); + if (bstrClassName) + SysFreeString(bstrClassName); + for (UINT iDevice = 0; iDevice < 20; iDevice++) + SAFE_RELEASE(pDevices[iDevice]); + SAFE_RELEASE(pEnumDevices); + SAFE_RELEASE(pIWbemLocator); + SAFE_RELEASE(pIWbemServices); - if (bCleanupCOM) - CoUninitialize(); + if (bCleanupCOM) + CoUninitialize(); } - } } diff --git a/Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.h b/Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.h index 6506dd156e..be075deb9b 100644 --- a/Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.h +++ b/Source/Core/InputCommon/ControllerInterface/DInput/XInputFilter.h @@ -4,15 +4,13 @@ #pragma once -#include #include +#include namespace ciface { namespace DInput { - void GetXInputGUIDS(std::vector* guids); - } } diff --git a/Source/Core/InputCommon/ControllerInterface/Device.cpp b/Source/Core/InputCommon/ControllerInterface/Device.cpp index fae7e98e2f..7a3b8ac845 100644 --- a/Source/Core/InputCommon/ControllerInterface/Device.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Device.cpp @@ -17,7 +17,6 @@ namespace ciface { namespace Core { - // // Device :: ~Device // @@ -25,55 +24,55 @@ namespace Core // Device::~Device() { - // delete inputs - for (Device::Input* input : m_inputs) - delete input; + // delete inputs + for (Device::Input* input : m_inputs) + delete input; - // delete outputs - for (Device::Output* output: m_outputs) - delete output; + // delete outputs + for (Device::Output* output : m_outputs) + delete output; } void Device::AddInput(Device::Input* const i) { - m_inputs.push_back(i); + m_inputs.push_back(i); } void Device::AddOutput(Device::Output* const o) { - m_outputs.push_back(o); + m_outputs.push_back(o); } -Device::Input* Device::FindInput(const std::string &name) const +Device::Input* Device::FindInput(const std::string& name) const { - for (Input* input : m_inputs) - { - if (input->GetName() == name) - return input; - } + for (Input* input : m_inputs) + { + if (input->GetName() == name) + return input; + } - return nullptr; + return nullptr; } -Device::Output* Device::FindOutput(const std::string &name) const +Device::Output* Device::FindOutput(const std::string& name) const { - for (Output* output : m_outputs) - { - if (output->GetName() == name) - return output; - } + for (Output* output : m_outputs) + { + if (output->GetName() == name) + return output; + } - return nullptr; + return nullptr; } bool Device::Control::InputGateOn() { - if (SConfig::GetInstance().m_BackgroundInput) - return true; - else if (Host_RendererHasFocus() || Host_UIHasFocus()) - return true; - else - return false; + if (SConfig::GetInstance().m_BackgroundInput) + return true; + else if (Host_RendererHasFocus() || Host_UIHasFocus()) + return true; + else + return false; } // @@ -83,16 +82,16 @@ bool Device::Control::InputGateOn() // std::string DeviceQualifier::ToString() const { - if (source.empty() && (cid < 0) && name.empty()) - return ""; + if (source.empty() && (cid < 0) && name.empty()) + return ""; - std::ostringstream ss; - ss << source << '/'; - if (cid > -1) - ss << cid; - ss << '/' << name; + std::ostringstream ss; + ss << source << '/'; + if (cid > -1) + ss << cid; + ss << '/' << name; - return ss.str(); + return ss.str(); } // @@ -102,15 +101,15 @@ std::string DeviceQualifier::ToString() const // void DeviceQualifier::FromString(const std::string& str) { - std::istringstream ss(str); + std::istringstream ss(str); - std::getline(ss, source = "", '/'); + std::getline(ss, source = "", '/'); - // silly - std::getline(ss, name, '/'); - std::istringstream(name) >> (cid = -1); + // silly + std::getline(ss, name, '/'); + std::istringstream(name) >> (cid = -1); - std::getline(ss, name = ""); + std::getline(ss, name = ""); } // @@ -120,66 +119,65 @@ void DeviceQualifier::FromString(const std::string& str) // void DeviceQualifier::FromDevice(const Device* const dev) { - name = dev->GetName(); - cid = dev->GetId(); - source= dev->GetSource(); + name = dev->GetName(); + cid = dev->GetId(); + source = dev->GetSource(); } bool DeviceQualifier::operator==(const Device* const dev) const { - if (dev->GetId() == cid) - if (dev->GetName() == name) - if (dev->GetSource() == source) - return true; + if (dev->GetId() == cid) + if (dev->GetName() == name) + if (dev->GetSource() == source) + return true; - return false; + return false; } bool DeviceQualifier::operator==(const DeviceQualifier& devq) const { - if (cid == devq.cid) - if (name == devq.name) - if (source == devq.source) - return true; + if (cid == devq.cid) + if (name == devq.name) + if (source == devq.source) + return true; - return false; + return false; } Device* DeviceContainer::FindDevice(const DeviceQualifier& devq) const { - for (Device* d : m_devices) - { - if (devq == d) - return d; - } + for (Device* d : m_devices) + { + if (devq == d) + return d; + } - return nullptr; + return nullptr; } Device::Input* DeviceContainer::FindInput(const std::string& name, const Device* def_dev) const { - if (def_dev) - { - Device::Input* const inp = def_dev->FindInput(name); - if (inp) - return inp; - } + if (def_dev) + { + Device::Input* const inp = def_dev->FindInput(name); + if (inp) + return inp; + } - for (Device* d : m_devices) - { - Device::Input* const i = d->FindInput(name); + for (Device* d : m_devices) + { + Device::Input* const i = d->FindInput(name); - if (i) - return i; - } + if (i) + return i; + } - return nullptr; + return nullptr; } Device::Output* DeviceContainer::FindOutput(const std::string& name, const Device* def_dev) const { - return def_dev->FindOutput(name); -} - + return def_dev->FindOutput(name); +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/Device.h b/Source/Core/InputCommon/ControllerInterface/Device.h index 7e6172149f..dc60691b56 100644 --- a/Source/Core/InputCommon/ControllerInterface/Device.h +++ b/Source/Core/InputCommon/ControllerInterface/Device.h @@ -16,7 +16,6 @@ namespace ciface { namespace Core { - // Forward declarations class DeviceQualifier; @@ -28,121 +27,109 @@ class DeviceQualifier; class Device { public: - class Input; - class Output; + class Input; + class Output; - // - // Control - // - // Control includes inputs and outputs - // - class Control // input or output - { - public: - virtual std::string GetName() const = 0; - virtual ~Control() {} + // + // Control + // + // Control includes inputs and outputs + // + class Control // input or output + { + public: + virtual std::string GetName() const = 0; + virtual ~Control() {} + bool InputGateOn(); - bool InputGateOn(); + virtual Input* ToInput() { return nullptr; } + virtual Output* ToOutput() { return nullptr; } + }; - virtual Input* ToInput() { return nullptr; } - virtual Output* ToOutput() { return nullptr; } - }; + // + // Input + // + // An input on a device + // + class Input : public Control + { + public: + // things like absolute axes/ absolute mouse position will override this + virtual bool IsDetectable() { return true; } + virtual ControlState GetState() const = 0; - // - // Input - // - // An input on a device - // - class Input : public Control - { - public: - // things like absolute axes/ absolute mouse position will override this - virtual bool IsDetectable() { return true; } + ControlState GetGatedState() + { + if (InputGateOn()) + return GetState(); + else + return 0.0; + } - virtual ControlState GetState() const = 0; + Input* ToInput() override { return this; } + }; - ControlState GetGatedState() - { - if (InputGateOn()) - return GetState(); - else - return 0.0; - } + // + // Output + // + // An output on a device + // + class Output : public Control + { + public: + virtual ~Output() {} + virtual void SetState(ControlState state) = 0; - Input* ToInput() override { return this; } - }; + void SetGatedState(ControlState state) + { + if (InputGateOn()) + SetState(state); + } - // - // Output - // - // An output on a device - // - class Output : public Control - { - public: - virtual ~Output() {} + Output* ToOutput() override { return this; } + }; - virtual void SetState(ControlState state) = 0; + virtual ~Device(); - void SetGatedState(ControlState state) - { - if (InputGateOn()) - SetState(state); - } - - Output* ToOutput() override { return this; } - }; - - virtual ~Device(); - - virtual std::string GetName() const = 0; - virtual int GetId() const = 0; - virtual std::string GetSource() const = 0; - virtual void UpdateInput() {} - - const std::vector& Inputs() const { return m_inputs; } - const std::vector& Outputs() const { return m_outputs; } - - Input* FindInput(const std::string& name) const; - Output* FindOutput(const std::string& name) const; + virtual std::string GetName() const = 0; + virtual int GetId() const = 0; + virtual std::string GetSource() const = 0; + virtual void UpdateInput() {} + const std::vector& Inputs() const { return m_inputs; } + const std::vector& Outputs() const { return m_outputs; } + Input* FindInput(const std::string& name) const; + Output* FindOutput(const std::string& name) const; protected: - void AddInput(Input* const i); - void AddOutput(Output* const o); + void AddInput(Input* const i); + void AddOutput(Output* const o); - class FullAnalogSurface : public Input - { - public: - FullAnalogSurface(Input* low, Input* high) - : m_low(*low), m_high(*high) - {} + class FullAnalogSurface : public Input + { + public: + FullAnalogSurface(Input* low, Input* high) : m_low(*low), m_high(*high) {} + ControlState GetState() const override + { + return (1 + m_high.GetState() - m_low.GetState()) / 2; + } - ControlState GetState() const override - { - return (1 + m_high.GetState() - m_low.GetState()) / 2; - } + std::string GetName() const override { return m_low.GetName() + *m_high.GetName().rbegin(); } + private: + Input& m_low; + Input& m_high; + }; - std::string GetName() const override - { - return m_low.GetName() + *m_high.GetName().rbegin(); - } - - private: - Input& m_low; - Input& m_high; - }; - - void AddAnalogInputs(Input* low, Input* high) - { - AddInput(low); - AddInput(high); - AddInput(new FullAnalogSurface(low, high)); - AddInput(new FullAnalogSurface(high, low)); - } + void AddAnalogInputs(Input* low, Input* high) + { + AddInput(low); + AddInput(high); + AddInput(new FullAnalogSurface(low, high)); + AddInput(new FullAnalogSurface(high, low)); + } private: - std::vector m_inputs; - std::vector m_outputs; + std::vector m_inputs; + std::vector m_outputs; }; // @@ -154,31 +141,33 @@ private: class DeviceQualifier { public: - DeviceQualifier() : cid(-1) {} - DeviceQualifier(const std::string& _source, const int _id, const std::string& _name) - : source(_source), cid(_id), name(_name) {} - void FromDevice(const Device* const dev); - void FromString(const std::string& str); - std::string ToString() const; - bool operator==(const DeviceQualifier& devq) const; - bool operator==(const Device* const dev) const; + DeviceQualifier() : cid(-1) {} + DeviceQualifier(const std::string& _source, const int _id, const std::string& _name) + : source(_source), cid(_id), name(_name) + { + } + void FromDevice(const Device* const dev); + void FromString(const std::string& str); + std::string ToString() const; + bool operator==(const DeviceQualifier& devq) const; + bool operator==(const Device* const dev) const; - std::string source; - int cid; - std::string name; + std::string source; + int cid; + std::string name; }; class DeviceContainer { public: - Device::Input* FindInput(const std::string& name, const Device* def_dev) const; - Device::Output* FindOutput(const std::string& name, const Device* def_dev) const; + Device::Input* FindInput(const std::string& name, const Device* def_dev) const; + Device::Output* FindOutput(const std::string& name, const Device* def_dev) const; + + const std::vector& Devices() const { return m_devices; } + Device* FindDevice(const DeviceQualifier& devq) const; - const std::vector& Devices() const { return m_devices; } - Device* FindDevice(const DeviceQualifier& devq) const; protected: - std::vector m_devices; + std::vector m_devices; }; - } } diff --git a/Source/Core/InputCommon/ControllerInterface/ExpressionParser.cpp b/Source/Core/InputCommon/ControllerInterface/ExpressionParser.cpp index bcb2c95a96..a87bdf8d35 100644 --- a/Source/Core/InputCommon/ControllerInterface/ExpressionParser.cpp +++ b/Source/Core/InputCommon/ControllerInterface/ExpressionParser.cpp @@ -17,601 +17,546 @@ namespace ciface { namespace ExpressionParser { - enum TokenType { - TOK_DISCARD, - TOK_INVALID, - TOK_EOF, - TOK_LPAREN, - TOK_RPAREN, - TOK_AND, - TOK_OR, - TOK_NOT, - TOK_ADD, - TOK_CONTROL, + TOK_DISCARD, + TOK_INVALID, + TOK_EOF, + TOK_LPAREN, + TOK_RPAREN, + TOK_AND, + TOK_OR, + TOK_NOT, + TOK_ADD, + TOK_CONTROL, }; inline std::string OpName(TokenType op) { - switch (op) - { - case TOK_AND: - return "And"; - case TOK_OR: - return "Or"; - case TOK_NOT: - return "Not"; - case TOK_ADD: - return "Add"; - default: - assert(false); - return ""; - } + switch (op) + { + case TOK_AND: + return "And"; + case TOK_OR: + return "Or"; + case TOK_NOT: + return "Not"; + case TOK_ADD: + return "Add"; + default: + assert(false); + return ""; + } } class Token { public: - TokenType type; - ControlQualifier qualifier; + TokenType type; + ControlQualifier qualifier; - Token(TokenType type_) : type(type_) {} - Token(TokenType type_, ControlQualifier qualifier_) : type(type_), qualifier(qualifier_) {} + Token(TokenType type_) : type(type_) {} + Token(TokenType type_, ControlQualifier qualifier_) : type(type_), qualifier(qualifier_) {} + operator std::string() + { + switch (type) + { + case TOK_DISCARD: + return "Discard"; + case TOK_EOF: + return "EOF"; + case TOK_LPAREN: + return "("; + case TOK_RPAREN: + return ")"; + case TOK_AND: + return "&"; + case TOK_OR: + return "|"; + case TOK_NOT: + return "!"; + case TOK_ADD: + return "+"; + case TOK_CONTROL: + return "Device(" + (std::string)qualifier + ")"; + case TOK_INVALID: + break; + } - operator std::string() - { - switch (type) - { - case TOK_DISCARD: - return "Discard"; - case TOK_EOF: - return "EOF"; - case TOK_LPAREN: - return "("; - case TOK_RPAREN: - return ")"; - case TOK_AND: - return "&"; - case TOK_OR: - return "|"; - case TOK_NOT: - return "!"; - case TOK_ADD: - return "+"; - case TOK_CONTROL: - return "Device(" + (std::string)qualifier + ")"; - case TOK_INVALID: - break; - } - - return "Invalid"; - } + return "Invalid"; + } }; -class Lexer { +class Lexer +{ public: - std::string expr; - std::string::iterator it; + std::string expr; + std::string::iterator it; - Lexer(const std::string& expr_) : expr(expr_) - { - it = expr.begin(); - } + Lexer(const std::string& expr_) : expr(expr_) { it = expr.begin(); } + bool FetchBacktickString(std::string& value, char otherDelim = 0) + { + value = ""; + while (it != expr.end()) + { + char c = *it; + ++it; + if (c == '`') + return false; + if (c > 0 && c == otherDelim) + return true; + value += c; + } + return false; + } - bool FetchBacktickString(std::string &value, char otherDelim = 0) - { - value = ""; - while (it != expr.end()) - { - char c = *it; - ++it; - if (c == '`') - return false; - if (c > 0 && c == otherDelim) - return true; - value += c; - } - return false; - } + Token GetFullyQualifiedControl() + { + ControlQualifier qualifier; + std::string value; - Token GetFullyQualifiedControl() - { - ControlQualifier qualifier; - std::string value; + if (FetchBacktickString(value, ':')) + { + // Found colon, this is the device name + qualifier.has_device = true; + qualifier.device_qualifier.FromString(value); + FetchBacktickString(value); + } - if (FetchBacktickString(value, ':')) - { - // Found colon, this is the device name - qualifier.has_device = true; - qualifier.device_qualifier.FromString(value); - FetchBacktickString(value); - } + qualifier.control_name = value; - qualifier.control_name = value; + return Token(TOK_CONTROL, qualifier); + } - return Token(TOK_CONTROL, qualifier); - } + Token GetBarewordsControl(char c) + { + std::string name; + name += c; - Token GetBarewordsControl(char c) - { - std::string name; - name += c; + while (it != expr.end()) + { + c = *it; + if (!isalpha(c)) + break; + name += c; + ++it; + } - while (it != expr.end()) - { - c = *it; - if (!isalpha(c)) - break; - name += c; - ++it; - } + ControlQualifier qualifier; + qualifier.control_name = name; + return Token(TOK_CONTROL, qualifier); + } - ControlQualifier qualifier; - qualifier.control_name = name; - return Token(TOK_CONTROL, qualifier); - } + Token NextToken() + { + if (it == expr.end()) + return Token(TOK_EOF); - Token NextToken() - { - if (it == expr.end()) - return Token(TOK_EOF); + char c = *it++; + switch (c) + { + case ' ': + case '\t': + case '\n': + case '\r': + return Token(TOK_DISCARD); + case '(': + return Token(TOK_LPAREN); + case ')': + return Token(TOK_RPAREN); + case '&': + return Token(TOK_AND); + case '|': + return Token(TOK_OR); + case '!': + return Token(TOK_NOT); + case '+': + return Token(TOK_ADD); + case '`': + return GetFullyQualifiedControl(); + default: + if (isalpha(c)) + return GetBarewordsControl(c); + else + return Token(TOK_INVALID); + } + } - char c = *it++; - switch (c) - { - case ' ': - case '\t': - case '\n': - case '\r': - return Token(TOK_DISCARD); - case '(': - return Token(TOK_LPAREN); - case ')': - return Token(TOK_RPAREN); - case '&': - return Token(TOK_AND); - case '|': - return Token(TOK_OR); - case '!': - return Token(TOK_NOT); - case '+': - return Token(TOK_ADD); - case '`': - return GetFullyQualifiedControl(); - default: - if (isalpha(c)) - return GetBarewordsControl(c); - else - return Token(TOK_INVALID); - } - } + ExpressionParseStatus Tokenize(std::vector& tokens) + { + while (true) + { + Token tok = NextToken(); - ExpressionParseStatus Tokenize(std::vector &tokens) - { - while (true) - { - Token tok = NextToken(); + if (tok.type == TOK_DISCARD) + continue; - if (tok.type == TOK_DISCARD) - continue; + if (tok.type == TOK_INVALID) + { + tokens.clear(); + return EXPRESSION_PARSE_SYNTAX_ERROR; + } - if (tok.type == TOK_INVALID) - { - tokens.clear(); - return EXPRESSION_PARSE_SYNTAX_ERROR; - } + tokens.push_back(tok); - tokens.push_back(tok); - - if (tok.type == TOK_EOF) - break; - } - return EXPRESSION_PARSE_SUCCESS; - } + if (tok.type == TOK_EOF) + break; + } + return EXPRESSION_PARSE_SUCCESS; + } }; class ExpressionNode { public: - virtual ~ExpressionNode() {} - virtual ControlState GetValue() { return 0; } - virtual void SetValue(ControlState state) {} - virtual int CountNumControls() { return 0; } - virtual operator std::string() { return ""; } + virtual ~ExpressionNode() {} + virtual ControlState GetValue() { return 0; } + virtual void SetValue(ControlState state) {} + virtual int CountNumControls() { return 0; } + virtual operator std::string() { return ""; } }; class DummyExpression : public ExpressionNode { public: - std::string name; + std::string name; - DummyExpression(const std::string& name_) : name(name_) {} - - ControlState GetValue() override - { - return 0.0; - } - - void SetValue(ControlState value) override - { - } - - int CountNumControls() override - { - return 0; - } - - operator std::string() override - { - return "`" + name + "`"; - } + DummyExpression(const std::string& name_) : name(name_) {} + ControlState GetValue() override { return 0.0; } + void SetValue(ControlState value) override {} + int CountNumControls() override { return 0; } + operator std::string() override { return "`" + name + "`"; } }; class ControlExpression : public ExpressionNode { public: - ControlQualifier qualifier; - Device::Control *control; + ControlQualifier qualifier; + Device::Control* control; - ControlExpression(ControlQualifier qualifier_, Device::Control *control_) : qualifier(qualifier_), control(control_) {} + ControlExpression(ControlQualifier qualifier_, Device::Control* control_) + : qualifier(qualifier_), control(control_) + { + } - ControlState GetValue() override - { - return control->ToInput()->GetGatedState(); - } - - void SetValue(ControlState value) override - { - control->ToOutput()->SetGatedState(value); - } - - int CountNumControls() override - { - return 1; - } - - operator std::string() override - { - return "`" + (std::string)qualifier + "`"; - } + ControlState GetValue() override { return control->ToInput()->GetGatedState(); } + void SetValue(ControlState value) override { control->ToOutput()->SetGatedState(value); } + int CountNumControls() override { return 1; } + operator std::string() override { return "`" + (std::string)qualifier + "`"; } }; class BinaryExpression : public ExpressionNode { public: - TokenType op; - ExpressionNode *lhs; - ExpressionNode *rhs; + TokenType op; + ExpressionNode* lhs; + ExpressionNode* rhs; - BinaryExpression(TokenType op_, ExpressionNode *lhs_, ExpressionNode *rhs_) : op(op_), lhs(lhs_), rhs(rhs_) {} - virtual ~BinaryExpression() - { - delete lhs; - delete rhs; - } + BinaryExpression(TokenType op_, ExpressionNode* lhs_, ExpressionNode* rhs_) + : op(op_), lhs(lhs_), rhs(rhs_) + { + } + virtual ~BinaryExpression() + { + delete lhs; + delete rhs; + } - ControlState GetValue() override - { - ControlState lhsValue = lhs->GetValue(); - ControlState rhsValue = rhs->GetValue(); - switch (op) - { - case TOK_AND: - return std::min(lhsValue, rhsValue); - case TOK_OR: - return std::max(lhsValue, rhsValue); - case TOK_ADD: - return std::min(lhsValue + rhsValue, 1.0); - default: - assert(false); - return 0; - } - } + ControlState GetValue() override + { + ControlState lhsValue = lhs->GetValue(); + ControlState rhsValue = rhs->GetValue(); + switch (op) + { + case TOK_AND: + return std::min(lhsValue, rhsValue); + case TOK_OR: + return std::max(lhsValue, rhsValue); + case TOK_ADD: + return std::min(lhsValue + rhsValue, 1.0); + default: + assert(false); + return 0; + } + } - void SetValue(ControlState value) override - { - // Don't do anything special with the op we have. - // Treat "A & B" the same as "A | B". - lhs->SetValue(value); - rhs->SetValue(value); - } + void SetValue(ControlState value) override + { + // Don't do anything special with the op we have. + // Treat "A & B" the same as "A | B". + lhs->SetValue(value); + rhs->SetValue(value); + } - int CountNumControls() override - { - return lhs->CountNumControls() + rhs->CountNumControls(); - } - - operator std::string() override - { - return OpName(op) + "(" + (std::string)(*lhs) + ", " + (std::string)(*rhs) + ")"; - } + int CountNumControls() override { return lhs->CountNumControls() + rhs->CountNumControls(); } + operator std::string() override + { + return OpName(op) + "(" + (std::string)(*lhs) + ", " + (std::string)(*rhs) + ")"; + } }; class UnaryExpression : public ExpressionNode { public: - TokenType op; - ExpressionNode *inner; + TokenType op; + ExpressionNode* inner; - UnaryExpression(TokenType op_, ExpressionNode *inner_) : op(op_), inner(inner_) {} - virtual ~UnaryExpression() - { - delete inner; - } + UnaryExpression(TokenType op_, ExpressionNode* inner_) : op(op_), inner(inner_) {} + virtual ~UnaryExpression() { delete inner; } + ControlState GetValue() override + { + ControlState value = inner->GetValue(); + switch (op) + { + case TOK_NOT: + return 1.0 - value; + default: + assert(false); + return 0; + } + } - ControlState GetValue() override - { - ControlState value = inner->GetValue(); - switch (op) - { - case TOK_NOT: - return 1.0 - value; - default: - assert(false); - return 0; - } - } + void SetValue(ControlState value) override + { + switch (op) + { + case TOK_NOT: + inner->SetValue(1.0 - value); + break; - void SetValue(ControlState value) override - { - switch (op) - { - case TOK_NOT: - inner->SetValue(1.0 - value); - break; + default: + assert(false); + } + } - default: - assert(false); - } - } - - int CountNumControls() override - { - return inner->CountNumControls(); - } - - operator std::string() override - { - return OpName(op) + "(" + (std::string)(*inner) + ")"; - } + int CountNumControls() override { return inner->CountNumControls(); } + operator std::string() override { return OpName(op) + "(" + (std::string)(*inner) + ")"; } }; -Device *ControlFinder::FindDevice(ControlQualifier qualifier) +Device* ControlFinder::FindDevice(ControlQualifier qualifier) { - if (qualifier.has_device) - return container.FindDevice(qualifier.device_qualifier); - else - return container.FindDevice(default_device); + if (qualifier.has_device) + return container.FindDevice(qualifier.device_qualifier); + else + return container.FindDevice(default_device); } -Device::Control *ControlFinder::FindControl(ControlQualifier qualifier) +Device::Control* ControlFinder::FindControl(ControlQualifier qualifier) { - Device *device = FindDevice(qualifier); - if (!device) - return nullptr; + Device* device = FindDevice(qualifier); + if (!device) + return nullptr; - if (is_input) - return device->FindInput(qualifier.control_name); - else - return device->FindOutput(qualifier.control_name); + if (is_input) + return device->FindInput(qualifier.control_name); + else + return device->FindOutput(qualifier.control_name); } class Parser { public: + Parser(std::vector tokens_, ControlFinder& finder_) : tokens(tokens_), finder(finder_) + { + m_it = tokens.begin(); + } - Parser(std::vector tokens_, ControlFinder &finder_) : tokens(tokens_), finder(finder_) - { - m_it = tokens.begin(); - } + ExpressionParseStatus Parse(Expression** expr_out) + { + ExpressionNode* node; + ExpressionParseStatus status = Toplevel(&node); + if (status != EXPRESSION_PARSE_SUCCESS) + return status; - ExpressionParseStatus Parse(Expression **expr_out) - { - ExpressionNode *node; - ExpressionParseStatus status = Toplevel(&node); - if (status != EXPRESSION_PARSE_SUCCESS) - return status; - - *expr_out = new Expression(node); - return EXPRESSION_PARSE_SUCCESS; - } + *expr_out = new Expression(node); + return EXPRESSION_PARSE_SUCCESS; + } private: - std::vector tokens; - std::vector::iterator m_it; - ControlFinder &finder; + std::vector tokens; + std::vector::iterator m_it; + ControlFinder& finder; - Token Chew() - { - return *m_it++; - } + Token Chew() { return *m_it++; } + Token Peek() { return *m_it; } + bool Expects(TokenType type) + { + Token tok = Chew(); + return tok.type == type; + } - Token Peek() - { - return *m_it; - } + ExpressionParseStatus Atom(ExpressionNode** expr_out) + { + Token tok = Chew(); + switch (tok.type) + { + case TOK_CONTROL: + { + Device::Control* control = finder.FindControl(tok.qualifier); + if (control == nullptr) + { + *expr_out = new DummyExpression(tok.qualifier); + return EXPRESSION_PARSE_SUCCESS; + } - bool Expects(TokenType type) - { - Token tok = Chew(); - return tok.type == type; - } + *expr_out = new ControlExpression(tok.qualifier, control); + return EXPRESSION_PARSE_SUCCESS; + } + case TOK_LPAREN: + return Paren(expr_out); + default: + return EXPRESSION_PARSE_SYNTAX_ERROR; + } + } - ExpressionParseStatus Atom(ExpressionNode **expr_out) - { - Token tok = Chew(); - switch (tok.type) - { - case TOK_CONTROL: - { - Device::Control *control = finder.FindControl(tok.qualifier); - if (control == nullptr) - { - *expr_out = new DummyExpression(tok.qualifier); - return EXPRESSION_PARSE_SUCCESS; - } + bool IsUnaryExpression(TokenType type) + { + switch (type) + { + case TOK_NOT: + return true; + default: + return false; + } + } - *expr_out = new ControlExpression(tok.qualifier, control); - return EXPRESSION_PARSE_SUCCESS; - } - case TOK_LPAREN: - return Paren(expr_out); - default: - return EXPRESSION_PARSE_SYNTAX_ERROR; - } - } + ExpressionParseStatus Unary(ExpressionNode** expr_out) + { + ExpressionParseStatus status; - bool IsUnaryExpression(TokenType type) - { - switch (type) - { - case TOK_NOT: - return true; - default: - return false; - } - } + if (IsUnaryExpression(Peek().type)) + { + Token tok = Chew(); + ExpressionNode* atom_expr; + if ((status = Atom(&atom_expr)) != EXPRESSION_PARSE_SUCCESS) + return status; + *expr_out = new UnaryExpression(tok.type, atom_expr); + return EXPRESSION_PARSE_SUCCESS; + } - ExpressionParseStatus Unary(ExpressionNode **expr_out) - { - ExpressionParseStatus status; + return Atom(expr_out); + } - if (IsUnaryExpression(Peek().type)) - { - Token tok = Chew(); - ExpressionNode *atom_expr; - if ((status = Atom(&atom_expr)) != EXPRESSION_PARSE_SUCCESS) - return status; - *expr_out = new UnaryExpression(tok.type, atom_expr); - return EXPRESSION_PARSE_SUCCESS; - } + bool IsBinaryToken(TokenType type) + { + switch (type) + { + case TOK_AND: + case TOK_OR: + case TOK_ADD: + return true; + default: + return false; + } + } - return Atom(expr_out); - } + ExpressionParseStatus Binary(ExpressionNode** expr_out) + { + ExpressionParseStatus status; - bool IsBinaryToken(TokenType type) - { - switch (type) - { - case TOK_AND: - case TOK_OR: - case TOK_ADD: - return true; - default: - return false; - } - } + if ((status = Unary(expr_out)) != EXPRESSION_PARSE_SUCCESS) + return status; - ExpressionParseStatus Binary(ExpressionNode **expr_out) - { - ExpressionParseStatus status; + while (IsBinaryToken(Peek().type)) + { + Token tok = Chew(); + ExpressionNode* unary_expr; + if ((status = Unary(&unary_expr)) != EXPRESSION_PARSE_SUCCESS) + { + delete *expr_out; + return status; + } - if ((status = Unary(expr_out)) != EXPRESSION_PARSE_SUCCESS) - return status; + *expr_out = new BinaryExpression(tok.type, *expr_out, unary_expr); + } - while (IsBinaryToken(Peek().type)) - { - Token tok = Chew(); - ExpressionNode *unary_expr; - if ((status = Unary(&unary_expr)) != EXPRESSION_PARSE_SUCCESS) - { - delete *expr_out; - return status; - } + return EXPRESSION_PARSE_SUCCESS; + } - *expr_out = new BinaryExpression(tok.type, *expr_out, unary_expr); - } + ExpressionParseStatus Paren(ExpressionNode** expr_out) + { + ExpressionParseStatus status; - return EXPRESSION_PARSE_SUCCESS; - } + // lparen already chewed + if ((status = Toplevel(expr_out)) != EXPRESSION_PARSE_SUCCESS) + return status; - ExpressionParseStatus Paren(ExpressionNode **expr_out) - { - ExpressionParseStatus status; + if (!Expects(TOK_RPAREN)) + { + delete *expr_out; + return EXPRESSION_PARSE_SYNTAX_ERROR; + } - // lparen already chewed - if ((status = Toplevel(expr_out)) != EXPRESSION_PARSE_SUCCESS) - return status; + return EXPRESSION_PARSE_SUCCESS; + } - if (!Expects(TOK_RPAREN)) - { - delete *expr_out; - return EXPRESSION_PARSE_SYNTAX_ERROR; - } - - return EXPRESSION_PARSE_SUCCESS; - } - - ExpressionParseStatus Toplevel(ExpressionNode **expr_out) - { - return Binary(expr_out); - } + ExpressionParseStatus Toplevel(ExpressionNode** expr_out) { return Binary(expr_out); } }; ControlState Expression::GetValue() { - return node->GetValue(); + return node->GetValue(); } void Expression::SetValue(ControlState value) { - node->SetValue(value); + node->SetValue(value); } -Expression::Expression(ExpressionNode *node_) +Expression::Expression(ExpressionNode* node_) { - node = node_; - num_controls = node->CountNumControls(); + node = node_; + num_controls = node->CountNumControls(); } Expression::~Expression() { - delete node; + delete node; } -static ExpressionParseStatus ParseExpressionInner(const std::string& str, ControlFinder &finder, Expression **expr_out) +static ExpressionParseStatus ParseExpressionInner(const std::string& str, ControlFinder& finder, + Expression** expr_out) { - ExpressionParseStatus status; - Expression *expr; - *expr_out = nullptr; + ExpressionParseStatus status; + Expression* expr; + *expr_out = nullptr; - if (str == "") - return EXPRESSION_PARSE_SUCCESS; + if (str == "") + return EXPRESSION_PARSE_SUCCESS; - Lexer l(str); - std::vector tokens; - status = l.Tokenize(tokens); - if (status != EXPRESSION_PARSE_SUCCESS) - return status; + Lexer l(str); + std::vector tokens; + status = l.Tokenize(tokens); + if (status != EXPRESSION_PARSE_SUCCESS) + return status; - Parser p(tokens, finder); - status = p.Parse(&expr); - if (status != EXPRESSION_PARSE_SUCCESS) - return status; + Parser p(tokens, finder); + status = p.Parse(&expr); + if (status != EXPRESSION_PARSE_SUCCESS) + return status; - *expr_out = expr; - return EXPRESSION_PARSE_SUCCESS; + *expr_out = expr; + return EXPRESSION_PARSE_SUCCESS; } -ExpressionParseStatus ParseExpression(const std::string& str, ControlFinder &finder, Expression **expr_out) +ExpressionParseStatus ParseExpression(const std::string& str, ControlFinder& finder, + Expression** expr_out) { - // Add compatibility with old simple expressions, which are simple - // barewords control names. + // Add compatibility with old simple expressions, which are simple + // barewords control names. - ControlQualifier qualifier; - qualifier.control_name = str; - qualifier.has_device = false; + ControlQualifier qualifier; + qualifier.control_name = str; + qualifier.has_device = false; - Device::Control *control = finder.FindControl(qualifier); - if (control) - { - *expr_out = new Expression(new ControlExpression(qualifier, control)); - return EXPRESSION_PARSE_SUCCESS; - } - - return ParseExpressionInner(str, finder, expr_out); -} + Device::Control* control = finder.FindControl(qualifier); + if (control) + { + *expr_out = new Expression(new ControlExpression(qualifier, control)); + return EXPRESSION_PARSE_SUCCESS; + } + return ParseExpressionInner(str, finder, expr_out); +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/ExpressionParser.h b/Source/Core/InputCommon/ControllerInterface/ExpressionParser.h index 9575ff619d..6894c1924e 100644 --- a/Source/Core/InputCommon/ControllerInterface/ExpressionParser.h +++ b/Source/Core/InputCommon/ControllerInterface/ExpressionParser.h @@ -11,59 +11,61 @@ namespace ciface { namespace ExpressionParser { - class ControlQualifier { public: - bool has_device; - Core::DeviceQualifier device_qualifier; - std::string control_name; + bool has_device; + Core::DeviceQualifier device_qualifier; + std::string control_name; - ControlQualifier() : has_device(false) {} - - operator std::string() - { - if (has_device) - return device_qualifier.ToString() + ":" + control_name; - else - return control_name; - } + ControlQualifier() : has_device(false) {} + operator std::string() + { + if (has_device) + return device_qualifier.ToString() + ":" + control_name; + else + return control_name; + } }; class ControlFinder { public: - ControlFinder(const Core::DeviceContainer &container_, const Core::DeviceQualifier &default_, const bool is_input_) : container(container_), default_device(default_), is_input(is_input_) {} - Core::Device::Control *FindControl(ControlQualifier qualifier); + ControlFinder(const Core::DeviceContainer& container_, const Core::DeviceQualifier& default_, + const bool is_input_) + : container(container_), default_device(default_), is_input(is_input_) + { + } + Core::Device::Control* FindControl(ControlQualifier qualifier); private: - Core::Device *FindDevice(ControlQualifier qualifier); - const Core::DeviceContainer &container; - const Core::DeviceQualifier &default_device; - bool is_input; + Core::Device* FindDevice(ControlQualifier qualifier); + const Core::DeviceContainer& container; + const Core::DeviceQualifier& default_device; + bool is_input; }; class ExpressionNode; class Expression { public: - Expression() : node(nullptr) {} - Expression(ExpressionNode *node); - ~Expression(); - ControlState GetValue(); - void SetValue (ControlState state); - int num_controls; - ExpressionNode *node; + Expression() : node(nullptr) {} + Expression(ExpressionNode* node); + ~Expression(); + ControlState GetValue(); + void SetValue(ControlState state); + int num_controls; + ExpressionNode* node; }; enum ExpressionParseStatus { - EXPRESSION_PARSE_SUCCESS = 0, - EXPRESSION_PARSE_SYNTAX_ERROR, - EXPRESSION_PARSE_NO_DEVICE, + EXPRESSION_PARSE_SUCCESS = 0, + EXPRESSION_PARSE_SYNTAX_ERROR, + EXPRESSION_PARSE_NO_DEVICE, }; -ExpressionParseStatus ParseExpression(const std::string& expr, ControlFinder &finder, Expression **expr_out); - +ExpressionParseStatus ParseExpression(const std::string& expr, ControlFinder& finder, + Expression** expr_out); } } diff --git a/Source/Core/InputCommon/ControllerInterface/ForceFeedback/ForceFeedbackDevice.cpp b/Source/Core/InputCommon/ControllerInterface/ForceFeedback/ForceFeedbackDevice.cpp index f67f63fc8b..34d0ed018b 100644 --- a/Source/Core/InputCommon/ControllerInterface/ForceFeedback/ForceFeedbackDevice.cpp +++ b/Source/Core/InputCommon/ControllerInterface/ForceFeedback/ForceFeedbackDevice.cpp @@ -2,16 +2,15 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "InputCommon/ControllerInterface/ForceFeedback/ForceFeedbackDevice.h" #include #include #include "Common/Thread.h" -#include "InputCommon/ControllerInterface/ForceFeedback/ForceFeedbackDevice.h" namespace ciface { namespace ForceFeedback { - // template instantiation template class ForceFeedbackDevice::Force; template class ForceFeedbackDevice::Force; @@ -19,192 +18,190 @@ template class ForceFeedbackDevice::Force; struct ForceType { - GUID guid; - const std::string name; + GUID guid; + const std::string name; }; -static const ForceType force_type_names[] = -{ - {GUID_ConstantForce, "Constant"}, // DICONSTANTFORCE - {GUID_RampForce, "Ramp"}, // DIRAMPFORCE - {GUID_Square, "Square"}, // DIPERIODIC ... - {GUID_Sine, "Sine"}, - {GUID_Triangle, "Triangle"}, - {GUID_SawtoothUp, "Sawtooth Up"}, - {GUID_SawtoothDown, "Sawtooth Down"}, - //{GUID_Spring, "Spring"}, // DICUSTOMFORCE ... < I think - //{GUID_Damper, "Damper"}, - //{GUID_Inertia, "Inertia"}, - //{GUID_Friction, "Friction"}, +static const ForceType force_type_names[] = { + {GUID_ConstantForce, "Constant"}, // DICONSTANTFORCE + {GUID_RampForce, "Ramp"}, // DIRAMPFORCE + {GUID_Square, "Square"}, // DIPERIODIC ... + {GUID_Sine, "Sine"}, + {GUID_Triangle, "Triangle"}, + {GUID_SawtoothUp, "Sawtooth Up"}, + {GUID_SawtoothDown, "Sawtooth Down"}, + //{GUID_Spring, "Spring"}, // DICUSTOMFORCE ... < I think + //{GUID_Damper, "Damper"}, + //{GUID_Inertia, "Inertia"}, + //{GUID_Friction, "Friction"}, }; bool ForceFeedbackDevice::InitForceFeedback(const LPDIRECTINPUTDEVICE8 device, int cAxes) { - if (cAxes == 0) - return false; + if (cAxes == 0) + return false; - // TODO: check for DIDC_FORCEFEEDBACK in devcaps? + // TODO: check for DIDC_FORCEFEEDBACK in devcaps? - // temporary - DWORD rgdwAxes[2] = {DIJOFS_X, DIJOFS_Y}; - LONG rglDirection[2] = {-200, 0}; + // temporary + DWORD rgdwAxes[2] = {DIJOFS_X, DIJOFS_Y}; + LONG rglDirection[2] = {-200, 0}; - DIEFFECT eff; - memset(&eff, 0, sizeof(eff)); - eff.dwSize = sizeof(DIEFFECT); - eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - eff.dwDuration = INFINITE; // (4 * DI_SECONDS) - eff.dwSamplePeriod = 0; - eff.dwGain = DI_FFNOMINALMAX; - eff.dwTriggerButton = DIEB_NOTRIGGER; - eff.dwTriggerRepeatInterval = 0; - eff.cAxes = std::min(1, cAxes); - eff.rgdwAxes = rgdwAxes; - eff.rglDirection = rglDirection; + DIEFFECT eff; + memset(&eff, 0, sizeof(eff)); + eff.dwSize = sizeof(DIEFFECT); + eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + eff.dwDuration = INFINITE; // (4 * DI_SECONDS) + eff.dwSamplePeriod = 0; + eff.dwGain = DI_FFNOMINALMAX; + eff.dwTriggerButton = DIEB_NOTRIGGER; + eff.dwTriggerRepeatInterval = 0; + eff.cAxes = std::min(1, cAxes); + eff.rgdwAxes = rgdwAxes; + eff.rglDirection = rglDirection; - // initialize parameters - DICONSTANTFORCE diCF = { -10000 }; - diCF.lMagnitude = DI_FFNOMINALMAX; - DIRAMPFORCE diRF = { 0 }; - DIPERIODIC diPE = { 0 }; + // initialize parameters + DICONSTANTFORCE diCF = {-10000}; + diCF.lMagnitude = DI_FFNOMINALMAX; + DIRAMPFORCE diRF = {0}; + DIPERIODIC diPE = {0}; - // doesn't seem needed - //DIENVELOPE env; - //eff.lpEnvelope = &env; - //ZeroMemory(&env, sizeof(env)); - //env.dwSize = sizeof(env); + // doesn't seem needed + // DIENVELOPE env; + // eff.lpEnvelope = &env; + // ZeroMemory(&env, sizeof(env)); + // env.dwSize = sizeof(env); - for (const ForceType& f : force_type_names) - { - if (f.guid == GUID_ConstantForce) - { - eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); - eff.lpvTypeSpecificParams = &diCF; - } - else if (f.guid == GUID_RampForce) - { - eff.cbTypeSpecificParams = sizeof(DIRAMPFORCE); - eff.lpvTypeSpecificParams = &diRF; - } - else - { - // all other forces need periodic parameters - eff.cbTypeSpecificParams = sizeof(DIPERIODIC); - eff.lpvTypeSpecificParams = &diPE; - } + for (const ForceType& f : force_type_names) + { + if (f.guid == GUID_ConstantForce) + { + eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); + eff.lpvTypeSpecificParams = &diCF; + } + else if (f.guid == GUID_RampForce) + { + eff.cbTypeSpecificParams = sizeof(DIRAMPFORCE); + eff.lpvTypeSpecificParams = &diRF; + } + else + { + // all other forces need periodic parameters + eff.cbTypeSpecificParams = sizeof(DIPERIODIC); + eff.lpvTypeSpecificParams = &diPE; + } - LPDIRECTINPUTEFFECT pEffect; - if (SUCCEEDED(device->CreateEffect(f.guid, &eff, &pEffect, nullptr))) - { - if (f.guid == GUID_ConstantForce) - AddOutput(new ForceConstant(f.name, pEffect)); - else if (f.guid == GUID_RampForce) - AddOutput(new ForceRamp(f.name, pEffect)); - else - AddOutput(new ForcePeriodic(f.name, pEffect)); - } - } + LPDIRECTINPUTEFFECT pEffect; + if (SUCCEEDED(device->CreateEffect(f.guid, &eff, &pEffect, nullptr))) + { + if (f.guid == GUID_ConstantForce) + AddOutput(new ForceConstant(f.name, pEffect)); + else if (f.guid == GUID_RampForce) + AddOutput(new ForceRamp(f.name, pEffect)); + else + AddOutput(new ForcePeriodic(f.name, pEffect)); + } + } - // disable autocentering - if (Outputs().size()) - { - DIPROPDWORD dipdw; - dipdw.diph.dwSize = sizeof( DIPROPDWORD ); - dipdw.diph.dwHeaderSize = sizeof( DIPROPHEADER ); - dipdw.diph.dwObj = 0; - dipdw.diph.dwHow = DIPH_DEVICE; - dipdw.dwData = DIPROPAUTOCENTER_OFF; - device->SetProperty( DIPROP_AUTOCENTER, &dipdw.diph ); - } + // disable autocentering + if (Outputs().size()) + { + DIPROPDWORD dipdw; + dipdw.diph.dwSize = sizeof(DIPROPDWORD); + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = DIPROPAUTOCENTER_OFF; + device->SetProperty(DIPROP_AUTOCENTER, &dipdw.diph); + } - return true; + return true; } -template +template ForceFeedbackDevice::Force

::~Force() { - m_iface->Stop(); - m_iface->Unload(); - m_iface->Release(); + m_iface->Stop(); + m_iface->Unload(); + m_iface->Release(); } -template +template void ForceFeedbackDevice::Force

::Update() { - DIEFFECT eff = {}; - eff.dwSize = sizeof(DIEFFECT); - eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + DIEFFECT eff = {}; + eff.dwSize = sizeof(DIEFFECT); + eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - eff.cbTypeSpecificParams = sizeof(P); - eff.lpvTypeSpecificParams = ¶ms; + eff.cbTypeSpecificParams = sizeof(P); + eff.lpvTypeSpecificParams = ¶ms; - // set params and start effect - m_iface->SetParameters(&eff, DIEP_TYPESPECIFICPARAMS | DIEP_START); + // set params and start effect + m_iface->SetParameters(&eff, DIEP_TYPESPECIFICPARAMS | DIEP_START); } -template +template void ForceFeedbackDevice::Force

::Stop() { - m_iface->Stop(); + m_iface->Stop(); } -template<> +template <> void ForceFeedbackDevice::ForceConstant::SetState(const ControlState state) { - const LONG new_val = LONG(10000 * state); + const LONG new_val = LONG(10000 * state); - if (params.lMagnitude == new_val) - return; + if (params.lMagnitude == new_val) + return; - params.lMagnitude = new_val; - if (new_val) - Update(); - else - Stop(); + params.lMagnitude = new_val; + if (new_val) + Update(); + else + Stop(); } -template<> +template <> void ForceFeedbackDevice::ForceRamp::SetState(const ControlState state) { - const LONG new_val = LONG(10000 * state); + const LONG new_val = LONG(10000 * state); - if (params.lStart == new_val) - return; + if (params.lStart == new_val) + return; - params.lStart = params.lEnd = new_val; - if (new_val) - Update(); - else - Stop(); + params.lStart = params.lEnd = new_val; + if (new_val) + Update(); + else + Stop(); } -template<> +template <> void ForceFeedbackDevice::ForcePeriodic::SetState(const ControlState state) { - const DWORD new_val = DWORD(10000 * state); + const DWORD new_val = DWORD(10000 * state); - if (params.dwMagnitude == new_val) - return; + if (params.dwMagnitude == new_val) + return; - params.dwMagnitude = new_val; - if (new_val) - Update(); - else - Stop(); + params.dwMagnitude = new_val; + if (new_val) + Update(); + else + Stop(); } template ForceFeedbackDevice::Force

::Force(const std::string& name, LPDIRECTINPUTEFFECT iface) -: m_name(name), m_iface(iface) + : m_name(name), m_iface(iface) { - memset(¶ms, 0, sizeof(params)); + memset(¶ms, 0, sizeof(params)); } template std::string ForceFeedbackDevice::Force

::GetName() const { - return m_name; -} - + return m_name; +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/ForceFeedback/ForceFeedbackDevice.h b/Source/Core/InputCommon/ControllerInterface/ForceFeedback/ForceFeedbackDevice.h index f49198f037..5994bf2547 100644 --- a/Source/Core/InputCommon/ControllerInterface/ForceFeedback/ForceFeedbackDevice.h +++ b/Source/Core/InputCommon/ControllerInterface/ForceFeedback/ForceFeedbackDevice.h @@ -20,35 +20,32 @@ namespace ciface { namespace ForceFeedback { - - class ForceFeedbackDevice : public Core::Device { private: - template - class Force : public Output - { - public: - Force(const std::string& name, LPDIRECTINPUTEFFECT iface); - ~Force(); + template + class Force : public Output + { + public: + Force(const std::string& name, LPDIRECTINPUTEFFECT iface); + ~Force(); - std::string GetName() const override; - void SetState(ControlState state) override; - void Update(); - void Stop(); - private: - const std::string m_name; - LPDIRECTINPUTEFFECT m_iface; - P params; - }; - typedef Force ForceConstant; - typedef Force ForceRamp; - typedef Force ForcePeriodic; + std::string GetName() const override; + void SetState(ControlState state) override; + void Update(); + void Stop(); + + private: + const std::string m_name; + LPDIRECTINPUTEFFECT m_iface; + P params; + }; + typedef Force ForceConstant; + typedef Force ForceRamp; + typedef Force ForcePeriodic; public: - bool InitForceFeedback(const LPDIRECTINPUTDEVICE8, int cAxes); + bool InitForceFeedback(const LPDIRECTINPUTDEVICE8, int cAxes); }; - - } } diff --git a/Source/Core/InputCommon/ControllerInterface/ForceFeedback/OSX/DirectInputAdapter.h b/Source/Core/InputCommon/ControllerInterface/ForceFeedback/OSX/DirectInputAdapter.h index 133a4e2d09..84bd3bc4a5 100644 --- a/Source/Core/InputCommon/ControllerInterface/ForceFeedback/OSX/DirectInputAdapter.h +++ b/Source/Core/InputCommon/ControllerInterface/ForceFeedback/OSX/DirectInputAdapter.h @@ -14,210 +14,187 @@ #include -typedef LONG* LPLONG; // Missing type for ForceFeedback.h +typedef LONG* LPLONG; // Missing type for ForceFeedback.h #include #include -#include "DirectInputConstants.h" // Not stricty necessary -#include "Common/CommonTypes.h" // for LONG +#include "Common/CommonTypes.h" // for LONG +#include "DirectInputConstants.h" // Not stricty necessary namespace ciface { namespace ForceFeedback { - - // Prototypes class IUnknownImpl; class FFEffectAdapter; class FFDeviceAdapter; // Structs -typedef FFCAPABILITIES DICAPABILITIES; -typedef FFCONDITION DICONDITION; -typedef FFCONSTANTFORCE DICONSTANTFORCE; -typedef FFCUSTOMFORCE DICUSTOMFORCE; -typedef FFEFFECT DIEFFECT; -typedef FFEFFESCAPE DIEFFESCAPE; -typedef FFENVELOPE DIENVELOPE; -typedef FFPERIODIC DIPERIODIC; -typedef FFRAMPFORCE DIRAMPFORCE; +typedef FFCAPABILITIES DICAPABILITIES; +typedef FFCONDITION DICONDITION; +typedef FFCONSTANTFORCE DICONSTANTFORCE; +typedef FFCUSTOMFORCE DICUSTOMFORCE; +typedef FFEFFECT DIEFFECT; +typedef FFEFFESCAPE DIEFFESCAPE; +typedef FFENVELOPE DIENVELOPE; +typedef FFPERIODIC DIPERIODIC; +typedef FFRAMPFORCE DIRAMPFORCE; // Other types -typedef CFUUIDRef GUID; -typedef FFDeviceAdapter* FFDeviceAdapterReference; -typedef FFEffectAdapter* FFEffectAdapterReference; -typedef FFDeviceAdapterReference LPDIRECTINPUTDEVICE8; -typedef FFEffectAdapterReference LPDIRECTINPUTEFFECT; +typedef CFUUIDRef GUID; +typedef FFDeviceAdapter* FFDeviceAdapterReference; +typedef FFEffectAdapter* FFEffectAdapterReference; +typedef FFDeviceAdapterReference LPDIRECTINPUTDEVICE8; +typedef FFEffectAdapterReference LPDIRECTINPUTEFFECT; // Property structures #define DIPH_DEVICE 0 -typedef struct DIPROPHEADER { - DWORD dwSize; - DWORD dwHeaderSize; - DWORD dwObj; - DWORD dwHow; +typedef struct DIPROPHEADER +{ + DWORD dwSize; + DWORD dwHeaderSize; + DWORD dwObj; + DWORD dwHow; } DIPROPHEADER, *LPDIPROPHEADER; -typedef struct DIPROPDWORD { - DIPROPHEADER diph; - DWORD dwData; +typedef struct DIPROPDWORD +{ + DIPROPHEADER diph; + DWORD dwData; } DIPROPDWORD, *LPDIPROPDWORD; class IUnknownImpl : public IUnknown { private: - std::atomic m_cRef; + std::atomic m_cRef; public: - IUnknownImpl() : m_cRef(1) {} - virtual ~IUnknownImpl() {} + IUnknownImpl() : m_cRef(1) {} + virtual ~IUnknownImpl() {} + HRESULT QueryInterface(REFIID iid, LPVOID* ppv) + { + *ppv = nullptr; - HRESULT QueryInterface(REFIID iid, LPVOID *ppv) - { - *ppv = nullptr; + if (CFEqual(&iid, IUnknownUUID)) + *ppv = this; + if (nullptr == *ppv) + return E_NOINTERFACE; - if (CFEqual(&iid, IUnknownUUID)) - *ppv = this; - if (nullptr == *ppv) - return E_NOINTERFACE; + ((IUnknown*)*ppv)->AddRef(); - ((IUnknown*)*ppv)->AddRef(); + return S_OK; + } - return S_OK; - } + ULONG AddRef() { return ++m_cRef; } + ULONG Release() + { + if (--m_cRef == 0) + delete this; - ULONG AddRef() - { - return ++m_cRef; - } - - ULONG Release() - { - if (--m_cRef == 0) - delete this; - - return m_cRef; - } + return m_cRef; + } }; class FFEffectAdapter : public IUnknownImpl { private: - // Only used for destruction - FFDeviceObjectReference m_device; + // Only used for destruction + FFDeviceObjectReference m_device; public: - FFEffectObjectReference m_effect; + FFEffectObjectReference m_effect; - FFEffectAdapter(FFDeviceObjectReference device, FFEffectObjectReference effect) : m_device(device), m_effect(effect) {} - ~FFEffectAdapter() { FFDeviceReleaseEffect(m_device, m_effect); } + FFEffectAdapter(FFDeviceObjectReference device, FFEffectObjectReference effect) + : m_device(device), m_effect(effect) + { + } + ~FFEffectAdapter() { FFDeviceReleaseEffect(m_device, m_effect); } + HRESULT Download() { return FFEffectDownload(m_effect); } + HRESULT Escape(FFEFFESCAPE* pFFEffectEscape) { return FFEffectEscape(m_effect, pFFEffectEscape); } + HRESULT GetEffectStatus(FFEffectStatusFlag* pFlags) + { + return FFEffectGetEffectStatus(m_effect, pFlags); + } - HRESULT Download() - { - return FFEffectDownload(m_effect); - } + HRESULT GetParameters(FFEFFECT* pFFEffect, FFEffectParameterFlag flags) + { + return FFEffectGetParameters(m_effect, pFFEffect, flags); + } - HRESULT Escape(FFEFFESCAPE *pFFEffectEscape) - { - return FFEffectEscape(m_effect, pFFEffectEscape); - } + HRESULT SetParameters(FFEFFECT* pFFEffect, FFEffectParameterFlag flags) + { + return FFEffectSetParameters(m_effect, pFFEffect, flags); + } - HRESULT GetEffectStatus(FFEffectStatusFlag *pFlags) - { - return FFEffectGetEffectStatus(m_effect, pFlags); - } + HRESULT Start(UInt32 iterations, FFEffectStartFlag flags) + { + return FFEffectStart(m_effect, iterations, flags); + } - HRESULT GetParameters(FFEFFECT *pFFEffect, FFEffectParameterFlag flags) - { - return FFEffectGetParameters(m_effect, pFFEffect, flags); - } - - HRESULT SetParameters(FFEFFECT *pFFEffect, FFEffectParameterFlag flags) - { - return FFEffectSetParameters(m_effect, pFFEffect, flags); - } - - HRESULT Start(UInt32 iterations, FFEffectStartFlag flags) - { - return FFEffectStart(m_effect, iterations, flags); - } - - HRESULT Stop() - { - return FFEffectStop(m_effect); - } - - HRESULT Unload() - { - return FFEffectUnload(m_effect); - } + HRESULT Stop() { return FFEffectStop(m_effect); } + HRESULT Unload() { return FFEffectUnload(m_effect); } }; class FFDeviceAdapter : public IUnknownImpl { public: - FFDeviceObjectReference m_device; + FFDeviceObjectReference m_device; - FFDeviceAdapter(FFDeviceObjectReference device) : m_device(device) {} - ~FFDeviceAdapter() { FFReleaseDevice(m_device); } + FFDeviceAdapter(FFDeviceObjectReference device) : m_device(device) {} + ~FFDeviceAdapter() { FFReleaseDevice(m_device); } + static HRESULT Create(io_service_t hidDevice, FFDeviceAdapterReference* pDeviceReference) + { + FFDeviceObjectReference ref; - static HRESULT Create(io_service_t hidDevice, FFDeviceAdapterReference *pDeviceReference) - { - FFDeviceObjectReference ref; + HRESULT hr = FFCreateDevice(hidDevice, &ref); + if (SUCCEEDED(hr)) + *pDeviceReference = new FFDeviceAdapter(ref); - HRESULT hr = FFCreateDevice(hidDevice, &ref); - if (SUCCEEDED(hr)) - *pDeviceReference = new FFDeviceAdapter(ref); + return hr; + } - return hr; - } + HRESULT CreateEffect(CFUUIDRef uuidRef, FFEFFECT* pEffectDefinition, + FFEffectAdapterReference* pEffectReference, IUnknown* punkOuter) + { + FFEffectObjectReference ref; - HRESULT CreateEffect(CFUUIDRef uuidRef, FFEFFECT *pEffectDefinition, FFEffectAdapterReference *pEffectReference, IUnknown *punkOuter) - { - FFEffectObjectReference ref; + HRESULT hr = FFDeviceCreateEffect(m_device, uuidRef, pEffectDefinition, &ref); + if (SUCCEEDED(hr)) + *pEffectReference = new FFEffectAdapter(m_device, ref); - HRESULT hr = FFDeviceCreateEffect(m_device, uuidRef, pEffectDefinition, &ref); - if (SUCCEEDED(hr)) - *pEffectReference = new FFEffectAdapter(m_device, ref); + return hr; + } - return hr; - } + HRESULT Escape(FFEFFESCAPE* pFFEffectEscape) { return FFDeviceEscape(m_device, pFFEffectEscape); } + HRESULT GetForceFeedbackState(FFState* pFFState) + { + return FFDeviceGetForceFeedbackState(m_device, pFFState); + } - HRESULT Escape(FFEFFESCAPE *pFFEffectEscape) - { - return FFDeviceEscape(m_device, pFFEffectEscape); - } + HRESULT SendForceFeedbackCommand(FFCommandFlag flags) + { + return FFDeviceSendForceFeedbackCommand(m_device, flags); + } - HRESULT GetForceFeedbackState(FFState *pFFState) - { - return FFDeviceGetForceFeedbackState(m_device, pFFState); - } + HRESULT SetCooperativeLevel(void* taskIdentifier, FFCooperativeLevelFlag flags) + { + return FFDeviceSetCooperativeLevel(m_device, taskIdentifier, flags); + } - HRESULT SendForceFeedbackCommand(FFCommandFlag flags) - { - return FFDeviceSendForceFeedbackCommand(m_device, flags); - } + HRESULT SetProperty(FFProperty property, const LPDIPROPHEADER pdiph) + { + // There are only two properties supported + if (property != DIPROP_FFGAIN && property != DIPROP_AUTOCENTER) + return DIERR_UNSUPPORTED; - HRESULT SetCooperativeLevel(void *taskIdentifier, FFCooperativeLevelFlag flags) - { - return FFDeviceSetCooperativeLevel(m_device, taskIdentifier, flags); - } + // And they are both device properties + if (pdiph->dwHow != DIPH_DEVICE) + return DIERR_INVALIDPARAM; - HRESULT SetProperty(FFProperty property, const LPDIPROPHEADER pdiph) - { - // There are only two properties supported - if (property != DIPROP_FFGAIN && property != DIPROP_AUTOCENTER) - return DIERR_UNSUPPORTED; - - // And they are both device properties - if (pdiph->dwHow != DIPH_DEVICE) - return DIERR_INVALIDPARAM; - - UInt32 value = ((const LPDIPROPDWORD)pdiph)->dwData; - return FFDeviceSetForceFeedbackProperty(m_device, property, &value); - } + UInt32 value = ((const LPDIPROPDWORD)pdiph)->dwData; + return FFDeviceSetForceFeedbackProperty(m_device, property, &value); + } }; - } } diff --git a/Source/Core/InputCommon/ControllerInterface/ForceFeedback/OSX/DirectInputConstants.h b/Source/Core/InputCommon/ControllerInterface/ForceFeedback/OSX/DirectInputConstants.h index ceac035b6c..7e78eb7199 100644 --- a/Source/Core/InputCommon/ControllerInterface/ForceFeedback/OSX/DirectInputConstants.h +++ b/Source/Core/InputCommon/ControllerInterface/ForceFeedback/OSX/DirectInputConstants.h @@ -12,136 +12,136 @@ */ // UUIDs -#define GUID_ConstantForce kFFEffectType_ConstantForce_ID -#define GUID_CustomForce kFFEffectType_CustomForce_ID -#define GUID_Damper kFFEffectType_Damper_ID -#define GUID_Friction kFFEffectType_Friction_ID -#define GUID_Inertia kFFEffectType_Inertia_ID -#define GUID_RampForce kFFEffectType_RampForce_ID -#define GUID_SawtoothDown kFFEffectType_SawtoothDown_ID -#define GUID_SawtoothUp kFFEffectType_SawtoothUp_ID -#define GUID_Sine kFFEffectType_Sine_ID -#define GUID_Spring kFFEffectType_Spring_ID -#define GUID_Square kFFEffectType_Square_ID -#define GUID_Triangle kFFEffectType_Triangle_ID +#define GUID_ConstantForce kFFEffectType_ConstantForce_ID +#define GUID_CustomForce kFFEffectType_CustomForce_ID +#define GUID_Damper kFFEffectType_Damper_ID +#define GUID_Friction kFFEffectType_Friction_ID +#define GUID_Inertia kFFEffectType_Inertia_ID +#define GUID_RampForce kFFEffectType_RampForce_ID +#define GUID_SawtoothDown kFFEffectType_SawtoothDown_ID +#define GUID_SawtoothUp kFFEffectType_SawtoothUp_ID +#define GUID_Sine kFFEffectType_Sine_ID +#define GUID_Spring kFFEffectType_Spring_ID +#define GUID_Square kFFEffectType_Square_ID +#define GUID_Triangle kFFEffectType_Triangle_ID // Miscellaneous -#define DI_DEGREES FF_DEGREES -#define DI_DOWNLOADSKIPPED FF_DOWNLOADSKIPPED -#define DI_EFFECTRESTARTED FF_EFFECTRESTARTED -#define DI_FALSE FF_FALSE -#define DI_FFNOMINALMAX FF_FFNOMINALMAX -#define DI_INFINITE FF_INFINITE -#define DI_OK FF_OK -#define DI_SECONDS FF_SECONDS -#define DI_TRUNCATED FF_TRUNCATED -#define DI_TRUNCATEDANDRESTARTED FF_TRUNCATEDANDRESTARTED -#define DIEFF_OBJECTOFFSETS FFEFF_OBJECTOFFSETS -#define DIERR_DEVICEFULL FFERR_DEVICEFULL -#define DIERR_DEVICENOTREG FFERR_DEVICENOTREG -#define DIERR_DEVICEPAUSED FFERR_DEVICEPAUSED -#define DIERR_DEVICERELEASED FFERR_DEVICERELEASED -#define DIERR_EFFECTPLAYING FFERR_EFFECTPLAYING -#define DIERR_EFFECTTYPEMISMATCH FFERR_EFFECTTYPEMISMATCH -#define DIERR_EFFECTTYPENOTSUPPORTED FFERR_EFFECTTYPENOTSUPPORTED -#define DIERR_GENERIC FFERR_GENERIC -#define DIERR_HASEFFECTS FFERR_HASEFFECTS -#define DIERR_INCOMPLETEEFFECT FFERR_INCOMPLETEEFFECT -#define DIERR_INTERNAL FFERR_INTERNAL -#define DIERR_INVALIDDOWNLOADID FFERR_INVALIDDOWNLOADID -#define DIERR_INVALIDPARAM FFERR_INVALIDPARAM -#define DIERR_MOREDATA FFERR_MOREDATA -#define DIERR_NOINTERFACE FFERR_NOINTERFACE -#define DIERR_NOTDOWNLOADED FFERR_NOTDOWNLOADED -#define DIERR_NOTINITIALIZED FFERR_NOTINITIALIZED -#define DIERR_OUTOFMEMORY FFERR_OUTOFMEMORY -#define DIERR_UNPLUGGED FFERR_UNPLUGGED -#define DIERR_UNSUPPORTED FFERR_UNSUPPORTED -#define DIERR_UNSUPPORTEDAXIS FFERR_UNSUPPORTEDAXIS -#define DIJOFS_X FFJOFS_X -#define DIJOFS_Y FFJOFS_Y -#define DIJOFS_Z FFJOFS_Z +#define DI_DEGREES FF_DEGREES +#define DI_DOWNLOADSKIPPED FF_DOWNLOADSKIPPED +#define DI_EFFECTRESTARTED FF_EFFECTRESTARTED +#define DI_FALSE FF_FALSE +#define DI_FFNOMINALMAX FF_FFNOMINALMAX +#define DI_INFINITE FF_INFINITE +#define DI_OK FF_OK +#define DI_SECONDS FF_SECONDS +#define DI_TRUNCATED FF_TRUNCATED +#define DI_TRUNCATEDANDRESTARTED FF_TRUNCATEDANDRESTARTED +#define DIEFF_OBJECTOFFSETS FFEFF_OBJECTOFFSETS +#define DIERR_DEVICEFULL FFERR_DEVICEFULL +#define DIERR_DEVICENOTREG FFERR_DEVICENOTREG +#define DIERR_DEVICEPAUSED FFERR_DEVICEPAUSED +#define DIERR_DEVICERELEASED FFERR_DEVICERELEASED +#define DIERR_EFFECTPLAYING FFERR_EFFECTPLAYING +#define DIERR_EFFECTTYPEMISMATCH FFERR_EFFECTTYPEMISMATCH +#define DIERR_EFFECTTYPENOTSUPPORTED FFERR_EFFECTTYPENOTSUPPORTED +#define DIERR_GENERIC FFERR_GENERIC +#define DIERR_HASEFFECTS FFERR_HASEFFECTS +#define DIERR_INCOMPLETEEFFECT FFERR_INCOMPLETEEFFECT +#define DIERR_INTERNAL FFERR_INTERNAL +#define DIERR_INVALIDDOWNLOADID FFERR_INVALIDDOWNLOADID +#define DIERR_INVALIDPARAM FFERR_INVALIDPARAM +#define DIERR_MOREDATA FFERR_MOREDATA +#define DIERR_NOINTERFACE FFERR_NOINTERFACE +#define DIERR_NOTDOWNLOADED FFERR_NOTDOWNLOADED +#define DIERR_NOTINITIALIZED FFERR_NOTINITIALIZED +#define DIERR_OUTOFMEMORY FFERR_OUTOFMEMORY +#define DIERR_UNPLUGGED FFERR_UNPLUGGED +#define DIERR_UNSUPPORTED FFERR_UNSUPPORTED +#define DIERR_UNSUPPORTEDAXIS FFERR_UNSUPPORTEDAXIS +#define DIJOFS_X FFJOFS_X +#define DIJOFS_Y FFJOFS_Y +#define DIJOFS_Z FFJOFS_Z // FFCapabilitiesEffectSubType -#define DICAP_ST_KINESTHETIC FFCAP_ST_KINESTHETIC -#define DICAP_ST_VIBRATION FFCAP_ST_VIBRATION +#define DICAP_ST_KINESTHETIC FFCAP_ST_KINESTHETIC +#define DICAP_ST_VIBRATION FFCAP_ST_VIBRATION // FFCapabilitiesEffectType -#define DICAP_ET_CONSTANTFORCE FFCAP_ET_CONSTANTFORCE -#define DICAP_ET_RAMPFORCE FFCAP_ET_RAMPFORCE -#define DICAP_ET_SQUARE FFCAP_ET_SQUARE -#define DICAP_ET_SINE FFCAP_ET_SINE -#define DICAP_ET_TRIANGLE FFCAP_ET_TRIANGLE -#define DICAP_ET_SAWTOOTHUP FFCAP_ET_SAWTOOTHUP -#define DICAP_ET_SAWTOOTHDOWN FFCAP_ET_SAWTOOTHDOWN -#define DICAP_ET_SPRING FFCAP_ET_SPRING -#define DICAP_ET_DAMPER FFCAP_ET_DAMPER -#define DICAP_ET_INERTIA FFCAP_ET_INERTIA -#define DICAP_ET_FRICTION FFCAP_ET_FRICTION -#define DICAP_ET_CUSTOMFORCE FFCAP_ET_CUSTOMFORCE +#define DICAP_ET_CONSTANTFORCE FFCAP_ET_CONSTANTFORCE +#define DICAP_ET_RAMPFORCE FFCAP_ET_RAMPFORCE +#define DICAP_ET_SQUARE FFCAP_ET_SQUARE +#define DICAP_ET_SINE FFCAP_ET_SINE +#define DICAP_ET_TRIANGLE FFCAP_ET_TRIANGLE +#define DICAP_ET_SAWTOOTHUP FFCAP_ET_SAWTOOTHUP +#define DICAP_ET_SAWTOOTHDOWN FFCAP_ET_SAWTOOTHDOWN +#define DICAP_ET_SPRING FFCAP_ET_SPRING +#define DICAP_ET_DAMPER FFCAP_ET_DAMPER +#define DICAP_ET_INERTIA FFCAP_ET_INERTIA +#define DICAP_ET_FRICTION FFCAP_ET_FRICTION +#define DICAP_ET_CUSTOMFORCE FFCAP_ET_CUSTOMFORCE // FFCommandFlag -#define DISFFC_RESET FFSFFC_RESET -#define DISFFC_STOPALL FFSFFC_STOPALL -#define DISFFC_PAUSE FFSFFC_PAUSE -#define DISFFC_CONTINUE FFSFFC_CONTINUE -#define DISFFC_SETACTUATORSON FFSFFC_SETACTUATORSON -#define DISFFC_SETACTUATORSOFF FFSFFC_SETACTUATORSOFF +#define DISFFC_RESET FFSFFC_RESET +#define DISFFC_STOPALL FFSFFC_STOPALL +#define DISFFC_PAUSE FFSFFC_PAUSE +#define DISFFC_CONTINUE FFSFFC_CONTINUE +#define DISFFC_SETACTUATORSON FFSFFC_SETACTUATORSON +#define DISFFC_SETACTUATORSOFF FFSFFC_SETACTUATORSOFF // FFCooperativeLevelFlag -#define DISCL_EXCLUSIVE FFSCL_EXCLUSIVE -#define DISCL_NONEXCLUSIVE FFSCL_NONEXCLUSIVE -#define DISCL_FOREGROUND FFSCL_FOREGROUND -#define DISCL_BACKGROUND FFSCL_BACKGROUND +#define DISCL_EXCLUSIVE FFSCL_EXCLUSIVE +#define DISCL_NONEXCLUSIVE FFSCL_NONEXCLUSIVE +#define DISCL_FOREGROUND FFSCL_FOREGROUND +#define DISCL_BACKGROUND FFSCL_BACKGROUND // FFCoordinateSystemFlag -#define DIEFF_CARTESIAN FFEFF_CARTESIAN -#define DIEFF_POLAR FFEFF_POLAR -#define DIEFF_SPHERICAL FFEFF_SPHERICAL +#define DIEFF_CARTESIAN FFEFF_CARTESIAN +#define DIEFF_POLAR FFEFF_POLAR +#define DIEFF_SPHERICAL FFEFF_SPHERICAL // FFEffectParameterFlag -#define DIEP_DURATION FFEP_DURATION -#define DIEP_SAMPLEPERIOD FFEP_SAMPLEPERIOD -#define DIEP_GAIN FFEP_GAIN -#define DIEP_TRIGGERBUTTON FFEP_TRIGGERBUTTON -#define DIEP_TRIGGERREPEATINTERVAL FFEP_TRIGGERREPEATINTERVAL -#define DIEP_AXES FFEP_AXES -#define DIEP_DIRECTION FFEP_DIRECTION -#define DIEP_ENVELOPE FFEP_ENVELOPE -#define DIEP_TYPESPECIFICPARAMS FFEP_TYPESPECIFICPARAMS -#define DIEP_STARTDELAY FFEP_STARTDELAY -#define DIEP_ALLPARAMS FFEP_ALLPARAMS -#define DIEP_START FFEP_START -#define DIEP_NORESTART FFEP_NORESTART -#define DIEP_NODOWNLOAD FFEP_NODOWNLOAD -#define DIEB_NOTRIGGER FFEB_NOTRIGGER +#define DIEP_DURATION FFEP_DURATION +#define DIEP_SAMPLEPERIOD FFEP_SAMPLEPERIOD +#define DIEP_GAIN FFEP_GAIN +#define DIEP_TRIGGERBUTTON FFEP_TRIGGERBUTTON +#define DIEP_TRIGGERREPEATINTERVAL FFEP_TRIGGERREPEATINTERVAL +#define DIEP_AXES FFEP_AXES +#define DIEP_DIRECTION FFEP_DIRECTION +#define DIEP_ENVELOPE FFEP_ENVELOPE +#define DIEP_TYPESPECIFICPARAMS FFEP_TYPESPECIFICPARAMS +#define DIEP_STARTDELAY FFEP_STARTDELAY +#define DIEP_ALLPARAMS FFEP_ALLPARAMS +#define DIEP_START FFEP_START +#define DIEP_NORESTART FFEP_NORESTART +#define DIEP_NODOWNLOAD FFEP_NODOWNLOAD +#define DIEB_NOTRIGGER FFEB_NOTRIGGER // FFEffectStartFlag -#define DIES_SOLO FFES_SOLO -#define DIES_NODOWNLOAD FFES_NODOWNLOAD +#define DIES_SOLO FFES_SOLO +#define DIES_NODOWNLOAD FFES_NODOWNLOAD // FFEffectStatusFlag -#define DIEGES_NOTPLAYING FFEGES_NOTPLAYING -#define DIEGES_PLAYING FFEGES_PLAYING -#define DIEGES_EMULATED FFEGES_EMULATED +#define DIEGES_NOTPLAYING FFEGES_NOTPLAYING +#define DIEGES_PLAYING FFEGES_PLAYING +#define DIEGES_EMULATED FFEGES_EMULATED // FFProperty -#define DIPROP_FFGAIN FFPROP_FFGAIN -#define DIPROP_AUTOCENTER FFPROP_AUTOCENTER +#define DIPROP_FFGAIN FFPROP_FFGAIN +#define DIPROP_AUTOCENTER FFPROP_AUTOCENTER // not defined in ForceFeedbackConstants.h -#define DIPROPAUTOCENTER_OFF 0 -#define DIPROPAUTOCENTER_ON 1 +#define DIPROPAUTOCENTER_OFF 0 +#define DIPROPAUTOCENTER_ON 1 // FFState -#define DIGFFS_EMPTY FFGFFS_EMPTY -#define DIGFFS_STOPPED FFGFFS_STOPPED -#define DIGFFS_PAUSED FFGFFS_PAUSED -#define DIGFFS_ACTUATORSON FFGFFS_ACTUATORSON -#define DIGFFS_ACTUATORSOFF FFGFFS_ACTUATORSOFF -#define DIGFFS_POWERON FFGFFS_POWERON -#define DIGFFS_POWEROFF FFGFFS_POWEROFF -#define DIGFFS_SAFETYSWITCHON FFGFFS_SAFETYSWITCHON -#define DIGFFS_SAFETYSWITCHOFF FFGFFS_SAFETYSWITCHOFF -#define DIGFFS_USERFFSWITCHON FFGFFS_USERFFSWITCHON -#define DIGFFS_USERFFSWITCHOFF FFGFFS_USERFFSWITCHOFF -#define DIGFFS_DEVICELOST FFGFFS_DEVICELOST +#define DIGFFS_EMPTY FFGFFS_EMPTY +#define DIGFFS_STOPPED FFGFFS_STOPPED +#define DIGFFS_PAUSED FFGFFS_PAUSED +#define DIGFFS_ACTUATORSON FFGFFS_ACTUATORSON +#define DIGFFS_ACTUATORSOFF FFGFFS_ACTUATORSOFF +#define DIGFFS_POWERON FFGFFS_POWERON +#define DIGFFS_POWEROFF FFGFFS_POWEROFF +#define DIGFFS_SAFETYSWITCHON FFGFFS_SAFETYSWITCHON +#define DIGFFS_SAFETYSWITCHOFF FFGFFS_SAFETYSWITCHOFF +#define DIGFFS_USERFFSWITCHON FFGFFS_USERFFSWITCHON +#define DIGFFS_USERFFSWITCHOFF FFGFFS_USERFFSWITCHOFF +#define DIGFFS_DEVICELOST FFGFFS_DEVICELOST diff --git a/Source/Core/InputCommon/ControllerInterface/OSX/OSX.h b/Source/Core/InputCommon/ControllerInterface/OSX/OSX.h index 5cb4a87fd8..c257d7e8f4 100644 --- a/Source/Core/InputCommon/ControllerInterface/OSX/OSX.h +++ b/Source/Core/InputCommon/ControllerInterface/OSX/OSX.h @@ -10,11 +10,9 @@ namespace ciface { namespace OSX { - -void Init(std::vector& devices, void *window); +void Init(std::vector& devices, void* window); void DeInit(); -void DeviceElementDebugPrint(const void *, void *); - +void DeviceElementDebugPrint(const void*, void*); } } diff --git a/Source/Core/InputCommon/ControllerInterface/OSX/OSX.mm b/Source/Core/InputCommon/ControllerInterface/OSX/OSX.mm index 18542b6c50..1335b01967 100644 --- a/Source/Core/InputCommon/ControllerInterface/OSX/OSX.mm +++ b/Source/Core/InputCommon/ControllerInterface/OSX/OSX.mm @@ -2,13 +2,13 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #include -#include #include "InputCommon/ControllerInterface/OSX/OSX.h" -#include "InputCommon/ControllerInterface/OSX/OSXKeyboard.h" #include "InputCommon/ControllerInterface/OSX/OSXJoystick.h" +#include "InputCommon/ControllerInterface/OSX/OSXKeyboard.h" #include @@ -16,103 +16,94 @@ namespace ciface { namespace OSX { - - static IOHIDManagerRef HIDManager = nullptr; static CFStringRef OurRunLoop = CFSTR("DolphinOSXInput"); static std::map kbd_name_counts, joy_name_counts; -void DeviceElementDebugPrint(const void *value, void *context) +void DeviceElementDebugPrint(const void* value, void* context) { - IOHIDElementRef e = (IOHIDElementRef)value; - bool recurse = false; - if (context) - recurse = *(bool*)context; + IOHIDElementRef e = (IOHIDElementRef)value; + bool recurse = false; + if (context) + recurse = *(bool*)context; - std::string type = ""; - switch (IOHIDElementGetType(e)) - { - case kIOHIDElementTypeInput_Axis: - type = "axis"; - break; - case kIOHIDElementTypeInput_Button: - type = "button"; - break; - case kIOHIDElementTypeInput_Misc: - type = "misc"; - break; - case kIOHIDElementTypeInput_ScanCodes: - type = "scancodes"; - break; - case kIOHIDElementTypeOutput: - type = "output"; - break; - case kIOHIDElementTypeFeature: - type = "feature"; - break; - case kIOHIDElementTypeCollection: - type = "collection"; - break; - } + std::string type = ""; + switch (IOHIDElementGetType(e)) + { + case kIOHIDElementTypeInput_Axis: + type = "axis"; + break; + case kIOHIDElementTypeInput_Button: + type = "button"; + break; + case kIOHIDElementTypeInput_Misc: + type = "misc"; + break; + case kIOHIDElementTypeInput_ScanCodes: + type = "scancodes"; + break; + case kIOHIDElementTypeOutput: + type = "output"; + break; + case kIOHIDElementTypeFeature: + type = "feature"; + break; + case kIOHIDElementTypeCollection: + type = "collection"; + break; + } - std::string c_type = ""; - if (type == "collection") - { - switch (IOHIDElementGetCollectionType(e)) - { - case kIOHIDElementCollectionTypePhysical: - c_type = "physical"; - break; - case kIOHIDElementCollectionTypeApplication: - c_type = "application"; - break; - case kIOHIDElementCollectionTypeLogical: - c_type = "logical"; - break; - case kIOHIDElementCollectionTypeReport: - c_type = "report"; - break; - case kIOHIDElementCollectionTypeNamedArray: - c_type = "namedArray"; - break; - case kIOHIDElementCollectionTypeUsageSwitch: - c_type = "usageSwitch"; - break; - case kIOHIDElementCollectionTypeUsageModifier: - c_type = "usageModifier"; - break; - } - } + std::string c_type = ""; + if (type == "collection") + { + switch (IOHIDElementGetCollectionType(e)) + { + case kIOHIDElementCollectionTypePhysical: + c_type = "physical"; + break; + case kIOHIDElementCollectionTypeApplication: + c_type = "application"; + break; + case kIOHIDElementCollectionTypeLogical: + c_type = "logical"; + break; + case kIOHIDElementCollectionTypeReport: + c_type = "report"; + break; + case kIOHIDElementCollectionTypeNamedArray: + c_type = "namedArray"; + break; + case kIOHIDElementCollectionTypeUsageSwitch: + c_type = "usageSwitch"; + break; + case kIOHIDElementCollectionTypeUsageModifier: + c_type = "usageModifier"; + break; + } + } - c_type.append(" "); - NSLog(@"%s%s%spage: 0x%x usage: 0x%x name: %@ " - "lmin: %ld lmax: %ld pmin: %ld pmax: %ld", - type.c_str(), - type == "collection" ? ":" : "", - type == "collection" ? c_type.c_str() : " ", - IOHIDElementGetUsagePage(e), - IOHIDElementGetUsage(e), - IOHIDElementGetName(e), // usually just nullptr - IOHIDElementGetLogicalMin(e), - IOHIDElementGetLogicalMax(e), - IOHIDElementGetPhysicalMin(e), - IOHIDElementGetPhysicalMax(e)); + c_type.append(" "); + NSLog(@"%s%s%spage: 0x%x usage: 0x%x name: %@ " + "lmin: %ld lmax: %ld pmin: %ld pmax: %ld", + type.c_str(), type == "collection" ? ":" : "", type == "collection" ? c_type.c_str() : " ", + IOHIDElementGetUsagePage(e), IOHIDElementGetUsage(e), + IOHIDElementGetName(e), // usually just nullptr + IOHIDElementGetLogicalMin(e), IOHIDElementGetLogicalMax(e), IOHIDElementGetPhysicalMin(e), + IOHIDElementGetPhysicalMax(e)); - if ((type == "collection") && recurse) - { - CFArrayRef elements = IOHIDElementGetChildren(e); - CFRange range = {0, CFArrayGetCount(elements)}; - // this leaks...but it's just debug code, right? :D - CFArrayApplyFunction(elements, range, - DeviceElementDebugPrint, nullptr); - } + if ((type == "collection") && recurse) + { + CFArrayRef elements = IOHIDElementGetChildren(e); + CFRange range = {0, CFArrayGetCount(elements)}; + // this leaks...but it's just debug code, right? :D + CFArrayApplyFunction(elements, range, DeviceElementDebugPrint, nullptr); + } } static void DeviceDebugPrint(IOHIDDeviceRef device) { #if 0 -#define shortlog(x) NSLog(@"%s: %@", \ - x, IOHIDDeviceGetProperty(device, CFSTR(x))); +#define shortlog(x) NSLog(@"%s: %@", x, IOHIDDeviceGetProperty(device, CFSTR(x))); NSLog(@"-------------------------"); NSLog(@"Got Device: %@", IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey))); @@ -139,81 +130,68 @@ static void DeviceDebugPrint(IOHIDDeviceRef device) #endif } -static void *g_window; +static void* g_window; -static void DeviceMatching_callback(void* inContext, - IOReturn inResult, - void *inSender, - IOHIDDeviceRef inIOHIDDeviceRef) +static void DeviceMatching_callback(void* inContext, IOReturn inResult, void* inSender, + IOHIDDeviceRef inIOHIDDeviceRef) { - NSString *pName = (NSString *) - IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDProductKey)); - std::string name = (pName != nullptr) ? [pName UTF8String] : "Unknown device"; + NSString* pName = (NSString*)IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDProductKey)); + std::string name = (pName != nullptr) ? [pName UTF8String] : "Unknown device"; - DeviceDebugPrint(inIOHIDDeviceRef); + DeviceDebugPrint(inIOHIDDeviceRef); - std::vector *devices = - (std::vector *)inContext; + std::vector* devices = (std::vector*)inContext; - // Add to the devices vector if it's of a type we want - if (IOHIDDeviceConformsTo(inIOHIDDeviceRef, - kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard)) - devices->push_back(new Keyboard(inIOHIDDeviceRef, - name, kbd_name_counts[name]++, g_window)); + // Add to the devices vector if it's of a type we want + if (IOHIDDeviceConformsTo(inIOHIDDeviceRef, kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard)) + devices->push_back(new Keyboard(inIOHIDDeviceRef, name, kbd_name_counts[name]++, g_window)); #if 0 else if (IOHIDDeviceConformsTo(inIOHIDDeviceRef, kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse)) devices->push_back(new Mouse(inIOHIDDeviceRef, name, mouse_name_counts[name]++)); #endif - else - devices->push_back(new Joystick(inIOHIDDeviceRef, - name, joy_name_counts[name]++)); + else + devices->push_back(new Joystick(inIOHIDDeviceRef, name, joy_name_counts[name]++)); } -void Init(std::vector& devices, void *window) +void Init(std::vector& devices, void* window) { - HIDManager = IOHIDManagerCreate(kCFAllocatorDefault, - kIOHIDOptionsTypeNone); - if (!HIDManager) - NSLog(@"Failed to create HID Manager reference"); + HIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + if (!HIDManager) + NSLog(@"Failed to create HID Manager reference"); - g_window = window; + g_window = window; - IOHIDManagerSetDeviceMatching(HIDManager, nullptr); + IOHIDManagerSetDeviceMatching(HIDManager, nullptr); - // Callbacks for acquisition or loss of a matching device - IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, - DeviceMatching_callback, (void *)&devices); + // Callbacks for acquisition or loss of a matching device + IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, DeviceMatching_callback, (void*)&devices); - // Match devices that are plugged in right now - IOHIDManagerScheduleWithRunLoop(HIDManager, - CFRunLoopGetCurrent(), OurRunLoop); - if (IOHIDManagerOpen(HIDManager, kIOHIDOptionsTypeNone) != - kIOReturnSuccess) - NSLog(@"Failed to open HID Manager"); + // Match devices that are plugged in right now + IOHIDManagerScheduleWithRunLoop(HIDManager, CFRunLoopGetCurrent(), OurRunLoop); + if (IOHIDManagerOpen(HIDManager, kIOHIDOptionsTypeNone) != kIOReturnSuccess) + NSLog(@"Failed to open HID Manager"); - kbd_name_counts.clear(); - joy_name_counts.clear(); + kbd_name_counts.clear(); + joy_name_counts.clear(); - // Wait while current devices are initialized - while (CFRunLoopRunInMode(OurRunLoop, 0, TRUE) == - kCFRunLoopRunHandledSource) {}; + // Wait while current devices are initialized + while (CFRunLoopRunInMode(OurRunLoop, 0, TRUE) == kCFRunLoopRunHandledSource) + { + }; - // Things should be configured now - // Disable hotplugging and other scheduling - IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, nullptr, nullptr); - IOHIDManagerUnscheduleFromRunLoop(HIDManager, - CFRunLoopGetCurrent(), OurRunLoop); + // Things should be configured now + // Disable hotplugging and other scheduling + IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, nullptr, nullptr); + IOHIDManagerUnscheduleFromRunLoop(HIDManager, CFRunLoopGetCurrent(), OurRunLoop); } void DeInit() { - // This closes all devices as well - IOHIDManagerClose(HIDManager, kIOHIDOptionsTypeNone); - CFRelease(HIDManager); -} - - + // This closes all devices as well + IOHIDManagerClose(HIDManager, kIOHIDOptionsTypeNone); + CFRelease(HIDManager); +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.h b/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.h index d0ed715130..3e3d62b2c6 100644 --- a/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.h +++ b/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.h @@ -13,81 +13,79 @@ namespace ciface { namespace OSX { - class Joystick : public ForceFeedback::ForceFeedbackDevice { private: - class Button : public Input - { - public: - Button(IOHIDElementRef element, IOHIDDeviceRef device) - : m_element(element), m_device(device) {} - std::string GetName() const override; - ControlState GetState() const override; - private: - const IOHIDElementRef m_element; - const IOHIDDeviceRef m_device; - }; + class Button : public Input + { + public: + Button(IOHIDElementRef element, IOHIDDeviceRef device) : m_element(element), m_device(device) {} + std::string GetName() const override; + ControlState GetState() const override; - class Axis : public Input - { - public: - enum direction - { - positive = 0, - negative - }; + private: + const IOHIDElementRef m_element; + const IOHIDDeviceRef m_device; + }; - Axis(IOHIDElementRef element, IOHIDDeviceRef device, direction dir); - std::string GetName() const override; - ControlState GetState() const override; + class Axis : public Input + { + public: + enum direction + { + positive = 0, + negative + }; - private: - const IOHIDElementRef m_element; - const IOHIDDeviceRef m_device; - std::string m_name; - const direction m_direction; - float m_neutral; - float m_scale; - }; + Axis(IOHIDElementRef element, IOHIDDeviceRef device, direction dir); + std::string GetName() const override; + ControlState GetState() const override; - class Hat : public Input - { - public: - enum direction - { - up = 0, - right, - down, - left - }; + private: + const IOHIDElementRef m_element; + const IOHIDDeviceRef m_device; + std::string m_name; + const direction m_direction; + float m_neutral; + float m_scale; + }; - Hat(IOHIDElementRef element, IOHIDDeviceRef device, direction dir); - std::string GetName() const override; - ControlState GetState() const override; + class Hat : public Input + { + public: + enum direction + { + up = 0, + right, + down, + left + }; - private: - const IOHIDElementRef m_element; - const IOHIDDeviceRef m_device; - const char* m_name; - const direction m_direction; - }; + Hat(IOHIDElementRef element, IOHIDDeviceRef device, direction dir); + std::string GetName() const override; + ControlState GetState() const override; + + private: + const IOHIDElementRef m_element; + const IOHIDDeviceRef m_device; + const char* m_name; + const direction m_direction; + }; public: - Joystick(IOHIDDeviceRef device, std::string name, int index); - ~Joystick(); + Joystick(IOHIDDeviceRef device, std::string name, int index); + ~Joystick(); - std::string GetName() const override; - std::string GetSource() const override; - int GetId() const override; + std::string GetName() const override; + std::string GetSource() const override; + int GetId() const override; private: - const IOHIDDeviceRef m_device; - const std::string m_device_name; - const int m_index; + const IOHIDDeviceRef m_device; + const std::string m_device_name; + const int m_index; - ForceFeedback::FFDeviceAdapterReference m_ff_device; + ForceFeedback::FFDeviceAdapterReference m_ff_device; }; - } } diff --git a/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.mm b/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.mm index bc503ec398..7eb05a52ce 100644 --- a/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.mm +++ b/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.mm @@ -13,281 +13,266 @@ namespace ciface { namespace OSX { - - Joystick::Joystick(IOHIDDeviceRef device, std::string name, int index) - : m_device(device) - , m_device_name(name) - , m_index(index) - , m_ff_device(nullptr) + : m_device(device), m_device_name(name), m_index(index), m_ff_device(nullptr) { - // Buttons - NSDictionary *buttonDict = @{ - @kIOHIDElementTypeKey : @(kIOHIDElementTypeInput_Button), - @kIOHIDElementUsagePageKey : @(kHIDPage_Button) - }; + // Buttons + NSDictionary* buttonDict = @{ + @kIOHIDElementTypeKey : @(kIOHIDElementTypeInput_Button), + @kIOHIDElementUsagePageKey : @(kHIDPage_Button) + }; - CFArrayRef buttons = IOHIDDeviceCopyMatchingElements(m_device, - (CFDictionaryRef)buttonDict, kIOHIDOptionsTypeNone); + CFArrayRef buttons = + IOHIDDeviceCopyMatchingElements(m_device, (CFDictionaryRef)buttonDict, kIOHIDOptionsTypeNone); - if (buttons) - { - for (int i = 0; i < CFArrayGetCount(buttons); i++) - { - IOHIDElementRef e = - (IOHIDElementRef)CFArrayGetValueAtIndex(buttons, i); - //DeviceElementDebugPrint(e, nullptr); + if (buttons) + { + for (int i = 0; i < CFArrayGetCount(buttons); i++) + { + IOHIDElementRef e = (IOHIDElementRef)CFArrayGetValueAtIndex(buttons, i); + // DeviceElementDebugPrint(e, nullptr); - AddInput(new Button(e, m_device)); - } - CFRelease(buttons); - } + AddInput(new Button(e, m_device)); + } + CFRelease(buttons); + } - // Axes - NSDictionary *axisDict = @{ - @kIOHIDElementTypeKey : @(kIOHIDElementTypeInput_Misc) - }; + // Axes + NSDictionary* axisDict = @{ @kIOHIDElementTypeKey : @(kIOHIDElementTypeInput_Misc) }; - CFArrayRef axes = IOHIDDeviceCopyMatchingElements(m_device, - (CFDictionaryRef)axisDict, kIOHIDOptionsTypeNone); + CFArrayRef axes = + IOHIDDeviceCopyMatchingElements(m_device, (CFDictionaryRef)axisDict, kIOHIDOptionsTypeNone); - if (axes) - { - for (int i = 0; i < CFArrayGetCount(axes); i++) - { - IOHIDElementRef e = - (IOHIDElementRef)CFArrayGetValueAtIndex(axes, i); - //DeviceElementDebugPrint(e, nullptr); + if (axes) + { + for (int i = 0; i < CFArrayGetCount(axes); i++) + { + IOHIDElementRef e = (IOHIDElementRef)CFArrayGetValueAtIndex(axes, i); + // DeviceElementDebugPrint(e, nullptr); - if (IOHIDElementGetUsage(e) == kHIDUsage_GD_Hatswitch) - { - AddInput(new Hat(e, m_device, Hat::up)); - AddInput(new Hat(e, m_device, Hat::right)); - AddInput(new Hat(e, m_device, Hat::down)); - AddInput(new Hat(e, m_device, Hat::left)); - } - else - { - AddAnalogInputs(new Axis(e, m_device, Axis::negative), - new Axis(e, m_device, Axis::positive)); - } - } - CFRelease(axes); - } + if (IOHIDElementGetUsage(e) == kHIDUsage_GD_Hatswitch) + { + AddInput(new Hat(e, m_device, Hat::up)); + AddInput(new Hat(e, m_device, Hat::right)); + AddInput(new Hat(e, m_device, Hat::down)); + AddInput(new Hat(e, m_device, Hat::left)); + } + else + { + AddAnalogInputs(new Axis(e, m_device, Axis::negative), + new Axis(e, m_device, Axis::positive)); + } + } + CFRelease(axes); + } - // Force Feedback - FFCAPABILITIES ff_caps; - if (SUCCEEDED(ForceFeedback::FFDeviceAdapter::Create(IOHIDDeviceGetService(m_device), &m_ff_device)) && - SUCCEEDED(FFDeviceGetForceFeedbackCapabilities(m_ff_device->m_device, &ff_caps))) - { - InitForceFeedback(m_ff_device, ff_caps.numFfAxes); - } + // Force Feedback + FFCAPABILITIES ff_caps; + if (SUCCEEDED( + ForceFeedback::FFDeviceAdapter::Create(IOHIDDeviceGetService(m_device), &m_ff_device)) && + SUCCEEDED(FFDeviceGetForceFeedbackCapabilities(m_ff_device->m_device, &ff_caps))) + { + InitForceFeedback(m_ff_device, ff_caps.numFfAxes); + } } Joystick::~Joystick() { - if (m_ff_device) - m_ff_device->Release(); + if (m_ff_device) + m_ff_device->Release(); } std::string Joystick::GetName() const { - return m_device_name; + return m_device_name; } std::string Joystick::GetSource() const { - return "Input"; + return "Input"; } int Joystick::GetId() const { - return m_index; + return m_index; } ControlState Joystick::Button::GetState() const { - IOHIDValueRef value; - if (IOHIDDeviceGetValue(m_device, m_element, &value) == kIOReturnSuccess) - return IOHIDValueGetIntegerValue(value); - else - return 0; + IOHIDValueRef value; + if (IOHIDDeviceGetValue(m_device, m_element, &value) == kIOReturnSuccess) + return IOHIDValueGetIntegerValue(value); + else + return 0; } std::string Joystick::Button::GetName() const { - std::ostringstream s; - s << IOHIDElementGetUsage(m_element); - return std::string("Button ") + s.str(); + std::ostringstream s; + s << IOHIDElementGetUsage(m_element); + return std::string("Button ") + s.str(); } Joystick::Axis::Axis(IOHIDElementRef element, IOHIDDeviceRef device, direction dir) - : m_element(element) - , m_device(device) - , m_direction(dir) + : m_element(element), m_device(device), m_direction(dir) { - // Need to parse the element a bit first - std::string description("unk"); + // Need to parse the element a bit first + std::string description("unk"); - int const usage = IOHIDElementGetUsage(m_element); - switch (usage) - { - case kHIDUsage_GD_X: - description = "X"; - break; - case kHIDUsage_GD_Y: - description = "Y"; - break; - case kHIDUsage_GD_Z: - description = "Z"; - break; - case kHIDUsage_GD_Rx: - description = "Rx"; - break; - case kHIDUsage_GD_Ry: - description = "Ry"; - break; - case kHIDUsage_GD_Rz: - description = "Rz"; - break; - case kHIDUsage_GD_Wheel: - description = "Wheel"; - break; - case kHIDUsage_Csmr_ACPan: - description = "Pan"; - break; - default: - { - std::ostringstream s; - s << usage; - description = s.str(); - break; - } - } + int const usage = IOHIDElementGetUsage(m_element); + switch (usage) + { + case kHIDUsage_GD_X: + description = "X"; + break; + case kHIDUsage_GD_Y: + description = "Y"; + break; + case kHIDUsage_GD_Z: + description = "Z"; + break; + case kHIDUsage_GD_Rx: + description = "Rx"; + break; + case kHIDUsage_GD_Ry: + description = "Ry"; + break; + case kHIDUsage_GD_Rz: + description = "Rz"; + break; + case kHIDUsage_GD_Wheel: + description = "Wheel"; + break; + case kHIDUsage_Csmr_ACPan: + description = "Pan"; + break; + default: + { + std::ostringstream s; + s << usage; + description = s.str(); + break; + } + } - m_name = std::string("Axis ") + description; - m_name.append((m_direction == positive) ? "+" : "-"); + m_name = std::string("Axis ") + description; + m_name.append((m_direction == positive) ? "+" : "-"); - m_neutral = (IOHIDElementGetLogicalMax(m_element) + - IOHIDElementGetLogicalMin(m_element)) / 2.; - m_scale = 1 / fabs(IOHIDElementGetLogicalMax(m_element) - m_neutral); + m_neutral = (IOHIDElementGetLogicalMax(m_element) + IOHIDElementGetLogicalMin(m_element)) / 2.; + m_scale = 1 / fabs(IOHIDElementGetLogicalMax(m_element) - m_neutral); } ControlState Joystick::Axis::GetState() const { - IOHIDValueRef value; + IOHIDValueRef value; - if (IOHIDDeviceGetValue(m_device, m_element, &value) == kIOReturnSuccess) - { - // IOHIDValueGetIntegerValue() crashes when trying - // to convert unusually large element values. - if (IOHIDValueGetLength(value) > 2) - return 0; + if (IOHIDDeviceGetValue(m_device, m_element, &value) == kIOReturnSuccess) + { + // IOHIDValueGetIntegerValue() crashes when trying + // to convert unusually large element values. + if (IOHIDValueGetLength(value) > 2) + return 0; - float position = IOHIDValueGetIntegerValue(value); + float position = IOHIDValueGetIntegerValue(value); - if (m_direction == positive && position > m_neutral) - return (position - m_neutral) * m_scale; - if (m_direction == negative && position < m_neutral) - return (m_neutral - position) * m_scale; - } + if (m_direction == positive && position > m_neutral) + return (position - m_neutral) * m_scale; + if (m_direction == negative && position < m_neutral) + return (m_neutral - position) * m_scale; + } - return 0; + return 0; } std::string Joystick::Axis::GetName() const { - return m_name; + return m_name; } Joystick::Hat::Hat(IOHIDElementRef element, IOHIDDeviceRef device, direction dir) - : m_element(element) - , m_device(device) - , m_direction(dir) + : m_element(element), m_device(device), m_direction(dir) { - switch (dir) - { - case up: - m_name = "Up"; - break; - case right: - m_name = "Right"; - break; - case down: - m_name = "Down"; - break; - case left: - m_name = "Left"; - break; - default: - m_name = "unk"; - } + switch (dir) + { + case up: + m_name = "Up"; + break; + case right: + m_name = "Right"; + break; + case down: + m_name = "Down"; + break; + case left: + m_name = "Left"; + break; + default: + m_name = "unk"; + } } ControlState Joystick::Hat::GetState() const { - IOHIDValueRef value; + IOHIDValueRef value; - if (IOHIDDeviceGetValue(m_device, m_element, &value) == kIOReturnSuccess) - { - int position = IOHIDValueGetIntegerValue(value); - int min = IOHIDElementGetLogicalMin(m_element); - int max = IOHIDElementGetLogicalMax(m_element); + if (IOHIDDeviceGetValue(m_device, m_element, &value) == kIOReturnSuccess) + { + int position = IOHIDValueGetIntegerValue(value); + int min = IOHIDElementGetLogicalMin(m_element); + int max = IOHIDElementGetLogicalMax(m_element); - // if the position is outside the min or max, don't register it as a valid button press - if (position < min || position > max) - { - return 0; - } + // if the position is outside the min or max, don't register it as a valid button press + if (position < min || position > max) + { + return 0; + } - // normalize the position so that its lowest value is 0 - position -= min; + // normalize the position so that its lowest value is 0 + position -= min; - switch (position) - { - case 0: - if (m_direction == up) - return 1; - break; - case 1: - if (m_direction == up || m_direction == right) - return 1; - break; - case 2: - if (m_direction == right) - return 1; - break; - case 3: - if (m_direction == right || m_direction == down) - return 1; - break; - case 4: - if (m_direction == down) - return 1; - break; - case 5: - if (m_direction == down || m_direction == left) - return 1; - break; - case 6: - if (m_direction == left) - return 1; - break; - case 7: - if (m_direction == left || m_direction == up) - return 1; - break; - }; - } + switch (position) + { + case 0: + if (m_direction == up) + return 1; + break; + case 1: + if (m_direction == up || m_direction == right) + return 1; + break; + case 2: + if (m_direction == right) + return 1; + break; + case 3: + if (m_direction == right || m_direction == down) + return 1; + break; + case 4: + if (m_direction == down) + return 1; + break; + case 5: + if (m_direction == down || m_direction == left) + return 1; + break; + case 6: + if (m_direction == left) + return 1; + break; + case 7: + if (m_direction == left || m_direction == up) + return 1; + break; + }; + } - return 0; + return 0; } std::string Joystick::Hat::GetName() const { - return m_name; -} - - + return m_name; +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.h b/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.h index d404f90684..5b3551a5b7 100644 --- a/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.h +++ b/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.h @@ -12,67 +12,71 @@ namespace ciface { namespace OSX { - class Keyboard : public Core::Device { private: - class Key : public Input - { - public: - Key(IOHIDElementRef element, IOHIDDeviceRef device); - std::string GetName() const override; - ControlState GetState() const override; - private: - const IOHIDElementRef m_element; - const IOHIDDeviceRef m_device; - std::string m_name; - }; + class Key : public Input + { + public: + Key(IOHIDElementRef element, IOHIDDeviceRef device); + std::string GetName() const override; + ControlState GetState() const override; - class Cursor : public Input - { - public: - Cursor(u8 index, const float& axis, const bool positive) : m_axis(axis), m_index(index), m_positive(positive) {} - std::string GetName() const override; - bool IsDetectable() override { return false; } - ControlState GetState() const override; - private: - const float& m_axis; - const u8 m_index; - const bool m_positive; - }; + private: + const IOHIDElementRef m_element; + const IOHIDDeviceRef m_device; + std::string m_name; + }; - class Button : public Input - { - public: - Button(u8 index, const unsigned char& button) : m_button(button), m_index(index) {} - std::string GetName() const override; - ControlState GetState() const override; - private: - const unsigned char& m_button; - const u8 m_index; - }; + class Cursor : public Input + { + public: + Cursor(u8 index, const float& axis, const bool positive) + : m_axis(axis), m_index(index), m_positive(positive) + { + } + std::string GetName() const override; + bool IsDetectable() override { return false; } + ControlState GetState() const override; + + private: + const float& m_axis; + const u8 m_index; + const bool m_positive; + }; + + class Button : public Input + { + public: + Button(u8 index, const unsigned char& button) : m_button(button), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; + + private: + const unsigned char& m_button; + const u8 m_index; + }; public: - void UpdateInput() override; + void UpdateInput() override; - Keyboard(IOHIDDeviceRef device, std::string name, int index, void *window); + Keyboard(IOHIDDeviceRef device, std::string name, int index, void* window); - std::string GetName() const override; - std::string GetSource() const override; - int GetId() const override; + std::string GetName() const override; + std::string GetSource() const override; + int GetId() const override; private: - struct - { - float x, y; - } m_cursor; + struct + { + float x, y; + } m_cursor; - const IOHIDDeviceRef m_device; - const std::string m_device_name; - int m_index; - uint32_t m_windowid; - unsigned char m_mousebuttons[3]; + const IOHIDDeviceRef m_device; + const std::string m_device_name; + int m_index; + uint32_t m_windowid; + unsigned char m_mousebuttons[3]; }; - } } diff --git a/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.mm b/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.mm index 759e25b295..f5c1e5ac98 100644 --- a/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.mm +++ b/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.mm @@ -4,9 +4,9 @@ #include +#include #include #include -#include #include "InputCommon/ControllerInterface/OSX/OSXKeyboard.h" @@ -14,261 +14,259 @@ namespace ciface { namespace OSX { - -Keyboard::Keyboard(IOHIDDeviceRef device, std::string name, int index, void *window) - : m_device(device) - , m_device_name(name) - , m_index(index) +Keyboard::Keyboard(IOHIDDeviceRef device, std::string name, int index, void* window) + : m_device(device), m_device_name(name), m_index(index) { - // This class should only recieve Keyboard or Keypad devices - // Now, filter on just the buttons we can handle sanely - NSDictionary *matchingElements = @{ - @kIOHIDElementTypeKey : @(kIOHIDElementTypeInput_Button), - @kIOHIDElementMinKey : @0, - @kIOHIDElementMaxKey : @1 - }; + // This class should only recieve Keyboard or Keypad devices + // Now, filter on just the buttons we can handle sanely + NSDictionary* matchingElements = @{ + @kIOHIDElementTypeKey : @(kIOHIDElementTypeInput_Button), + @kIOHIDElementMinKey : @0, + @kIOHIDElementMaxKey : @1 + }; - CFArrayRef elements = IOHIDDeviceCopyMatchingElements(m_device, - (CFDictionaryRef)matchingElements, kIOHIDOptionsTypeNone); + CFArrayRef elements = IOHIDDeviceCopyMatchingElements(m_device, (CFDictionaryRef)matchingElements, + kIOHIDOptionsTypeNone); - if (elements) - { - for (int i = 0; i < CFArrayGetCount(elements); i++) - { - IOHIDElementRef e = - (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i); - //DeviceElementDebugPrint(e, nullptr); + if (elements) + { + for (int i = 0; i < CFArrayGetCount(elements); i++) + { + IOHIDElementRef e = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i); + // DeviceElementDebugPrint(e, nullptr); - AddInput(new Key(e, m_device)); - } - CFRelease(elements); - } + AddInput(new Key(e, m_device)); + } + CFRelease(elements); + } - m_windowid = [[reinterpret_cast(window) window] windowNumber]; + m_windowid = [[reinterpret_cast(window) window] windowNumber]; - // cursor, with a hax for-loop - for (unsigned int i=0; i<4; ++i) - AddInput(new Cursor(!!(i&2), (&m_cursor.x)[i/2], !!(i&1))); + // cursor, with a hax for-loop + for (unsigned int i = 0; i < 4; ++i) + AddInput(new Cursor(!!(i & 2), (&m_cursor.x)[i / 2], !!(i & 1))); - for (u8 i = 0; i < sizeof(m_mousebuttons) / sizeof(m_mousebuttons[0]); ++i) - AddInput(new Button(i, m_mousebuttons[i])); + for (u8 i = 0; i < sizeof(m_mousebuttons) / sizeof(m_mousebuttons[0]); ++i) + AddInput(new Button(i, m_mousebuttons[i])); } void Keyboard::UpdateInput() { - CGRect bounds = CGRectZero; - uint32_t windowid[1] = { m_windowid }; - CFArrayRef windowArray = CFArrayCreate(nullptr, (const void **) windowid, 1, nullptr); - CFArrayRef windowDescriptions = CGWindowListCreateDescriptionFromArray(windowArray); - CFDictionaryRef windowDescription = (CFDictionaryRef) CFArrayGetValueAtIndex((CFArrayRef) windowDescriptions, 0); + CGRect bounds = CGRectZero; + uint32_t windowid[1] = {m_windowid}; + CFArrayRef windowArray = CFArrayCreate(nullptr, (const void**)windowid, 1, nullptr); + CFArrayRef windowDescriptions = CGWindowListCreateDescriptionFromArray(windowArray); + CFDictionaryRef windowDescription = + (CFDictionaryRef)CFArrayGetValueAtIndex((CFArrayRef)windowDescriptions, 0); - if (CFDictionaryContainsKey(windowDescription, kCGWindowBounds)) - { - CFDictionaryRef boundsDictionary = (CFDictionaryRef) CFDictionaryGetValue(windowDescription, kCGWindowBounds); + if (CFDictionaryContainsKey(windowDescription, kCGWindowBounds)) + { + CFDictionaryRef boundsDictionary = + (CFDictionaryRef)CFDictionaryGetValue(windowDescription, kCGWindowBounds); - if (boundsDictionary != nullptr) - CGRectMakeWithDictionaryRepresentation(boundsDictionary, &bounds); - } + if (boundsDictionary != nullptr) + CGRectMakeWithDictionaryRepresentation(boundsDictionary, &bounds); + } - CFRelease(windowDescriptions); - CFRelease(windowArray); + CFRelease(windowDescriptions); + CFRelease(windowArray); - CGEventRef event = CGEventCreate(nil); - CGPoint loc = CGEventGetLocation(event); - CFRelease(event); + CGEventRef event = CGEventCreate(nil); + CGPoint loc = CGEventGetLocation(event); + CFRelease(event); - loc.x -= bounds.origin.x; - loc.y -= bounds.origin.y; - m_cursor.x = loc.x / bounds.size.width * 2 - 1.0; - m_cursor.y = loc.y / bounds.size.height * 2 - 1.0; + loc.x -= bounds.origin.x; + loc.y -= bounds.origin.y; + m_cursor.x = loc.x / bounds.size.width * 2 - 1.0; + m_cursor.y = loc.y / bounds.size.height * 2 - 1.0; - m_mousebuttons[0] = CGEventSourceButtonState(kCGEventSourceStateHIDSystemState, kCGMouseButtonLeft); - m_mousebuttons[1] = CGEventSourceButtonState(kCGEventSourceStateHIDSystemState, kCGMouseButtonRight); - m_mousebuttons[2] = CGEventSourceButtonState(kCGEventSourceStateHIDSystemState, kCGMouseButtonCenter); + m_mousebuttons[0] = + CGEventSourceButtonState(kCGEventSourceStateHIDSystemState, kCGMouseButtonLeft); + m_mousebuttons[1] = + CGEventSourceButtonState(kCGEventSourceStateHIDSystemState, kCGMouseButtonRight); + m_mousebuttons[2] = + CGEventSourceButtonState(kCGEventSourceStateHIDSystemState, kCGMouseButtonCenter); } std::string Keyboard::GetName() const { - return m_device_name; + return m_device_name; } std::string Keyboard::GetSource() const { - return "Keyboard"; + return "Keyboard"; } int Keyboard::GetId() const { - return m_index; + return m_index; } Keyboard::Key::Key(IOHIDElementRef element, IOHIDDeviceRef device) - : m_element(element) - , m_device(device) + : m_element(element), m_device(device) { - static const struct PrettyKeys - { - const uint32_t code; - const char *const name; - } named_keys[] = { - { kHIDUsage_KeyboardA, "A" }, - { kHIDUsage_KeyboardB, "B" }, - { kHIDUsage_KeyboardC, "C" }, - { kHIDUsage_KeyboardD, "D" }, - { kHIDUsage_KeyboardE, "E" }, - { kHIDUsage_KeyboardF, "F" }, - { kHIDUsage_KeyboardG, "G" }, - { kHIDUsage_KeyboardH, "H" }, - { kHIDUsage_KeyboardI, "I" }, - { kHIDUsage_KeyboardJ, "J" }, - { kHIDUsage_KeyboardK, "K" }, - { kHIDUsage_KeyboardL, "L" }, - { kHIDUsage_KeyboardM, "M" }, - { kHIDUsage_KeyboardN, "N" }, - { kHIDUsage_KeyboardO, "O" }, - { kHIDUsage_KeyboardP, "P" }, - { kHIDUsage_KeyboardQ, "Q" }, - { kHIDUsage_KeyboardR, "R" }, - { kHIDUsage_KeyboardS, "S" }, - { kHIDUsage_KeyboardT, "T" }, - { kHIDUsage_KeyboardU, "U" }, - { kHIDUsage_KeyboardV, "V" }, - { kHIDUsage_KeyboardW, "W" }, - { kHIDUsage_KeyboardX, "X" }, - { kHIDUsage_KeyboardY, "Y" }, - { kHIDUsage_KeyboardZ, "Z" }, - { kHIDUsage_Keyboard1, "1" }, - { kHIDUsage_Keyboard2, "2" }, - { kHIDUsage_Keyboard3, "3" }, - { kHIDUsage_Keyboard4, "4" }, - { kHIDUsage_Keyboard5, "5" }, - { kHIDUsage_Keyboard6, "6" }, - { kHIDUsage_Keyboard7, "7" }, - { kHIDUsage_Keyboard8, "8" }, - { kHIDUsage_Keyboard9, "9" }, - { kHIDUsage_Keyboard0, "0" }, - { kHIDUsage_KeyboardReturnOrEnter, "Return" }, - { kHIDUsage_KeyboardEscape, "Escape" }, - { kHIDUsage_KeyboardDeleteOrBackspace, "Backspace" }, - { kHIDUsage_KeyboardTab, "Tab" }, - { kHIDUsage_KeyboardSpacebar, "Space" }, - { kHIDUsage_KeyboardHyphen, "-" }, - { kHIDUsage_KeyboardEqualSign, "=" }, - { kHIDUsage_KeyboardOpenBracket, "[" }, - { kHIDUsage_KeyboardCloseBracket, "]" }, - { kHIDUsage_KeyboardBackslash, "\\" }, - { kHIDUsage_KeyboardSemicolon, ";" }, - { kHIDUsage_KeyboardQuote, "'" }, - { kHIDUsage_KeyboardGraveAccentAndTilde, "Tilde" }, - { kHIDUsage_KeyboardComma, "," }, - { kHIDUsage_KeyboardPeriod, "." }, - { kHIDUsage_KeyboardSlash, "/" }, - { kHIDUsage_KeyboardCapsLock, "Caps Lock" }, - { kHIDUsage_KeyboardF1, "F1" }, - { kHIDUsage_KeyboardF2, "F2" }, - { kHIDUsage_KeyboardF3, "F3" }, - { kHIDUsage_KeyboardF4, "F4" }, - { kHIDUsage_KeyboardF5, "F5" }, - { kHIDUsage_KeyboardF6, "F6" }, - { kHIDUsage_KeyboardF7, "F7" }, - { kHIDUsage_KeyboardF8, "F8" }, - { kHIDUsage_KeyboardF9, "F9" }, - { kHIDUsage_KeyboardF10, "F10" }, - { kHIDUsage_KeyboardF11, "F11" }, - { kHIDUsage_KeyboardF12, "F12" }, - { kHIDUsage_KeyboardInsert, "Insert" }, - { kHIDUsage_KeyboardHome, "Home" }, - { kHIDUsage_KeyboardPageUp, "Page Up" }, - { kHIDUsage_KeyboardDeleteForward, "Delete" }, - { kHIDUsage_KeyboardEnd, "End" }, - { kHIDUsage_KeyboardPageDown, "Page Down" }, - { kHIDUsage_KeyboardRightArrow, "Right Arrow" }, - { kHIDUsage_KeyboardLeftArrow, "Left Arrow" }, - { kHIDUsage_KeyboardDownArrow, "Down Arrow" }, - { kHIDUsage_KeyboardUpArrow, "Up Arrow" }, - { kHIDUsage_KeypadSlash, "Keypad /" }, - { kHIDUsage_KeypadAsterisk, "Keypad *" }, - { kHIDUsage_KeypadHyphen, "Keypad -" }, - { kHIDUsage_KeypadPlus, "Keypad +" }, - { kHIDUsage_KeypadEnter, "Keypad Enter" }, - { kHIDUsage_Keypad1, "Keypad 1" }, - { kHIDUsage_Keypad2, "Keypad 2" }, - { kHIDUsage_Keypad3, "Keypad 3" }, - { kHIDUsage_Keypad4, "Keypad 4" }, - { kHIDUsage_Keypad5, "Keypad 5" }, - { kHIDUsage_Keypad6, "Keypad 6" }, - { kHIDUsage_Keypad7, "Keypad 7" }, - { kHIDUsage_Keypad8, "Keypad 8" }, - { kHIDUsage_Keypad9, "Keypad 9" }, - { kHIDUsage_Keypad0, "Keypad 0" }, - { kHIDUsage_KeypadPeriod, "Keypad ." }, - { kHIDUsage_KeyboardNonUSBackslash, "Paragraph" }, - { kHIDUsage_KeypadEqualSign, "Keypad =" }, - { kHIDUsage_KeypadComma, "Keypad ," }, - { kHIDUsage_KeyboardLeftControl, "Left Control" }, - { kHIDUsage_KeyboardLeftShift, "Left Shift" }, - { kHIDUsage_KeyboardLeftAlt, "Left Alt" }, - { kHIDUsage_KeyboardLeftGUI, "Left Command" }, - { kHIDUsage_KeyboardRightControl, "Right Control" }, - { kHIDUsage_KeyboardRightShift, "Right Shift" }, - { kHIDUsage_KeyboardRightAlt, "Right Alt" }, - { kHIDUsage_KeyboardRightGUI, "Right Command" }, - { 184, "Eject" }, - }; + static const struct PrettyKeys + { + const uint32_t code; + const char* const name; + } named_keys[] = { + {kHIDUsage_KeyboardA, "A"}, + {kHIDUsage_KeyboardB, "B"}, + {kHIDUsage_KeyboardC, "C"}, + {kHIDUsage_KeyboardD, "D"}, + {kHIDUsage_KeyboardE, "E"}, + {kHIDUsage_KeyboardF, "F"}, + {kHIDUsage_KeyboardG, "G"}, + {kHIDUsage_KeyboardH, "H"}, + {kHIDUsage_KeyboardI, "I"}, + {kHIDUsage_KeyboardJ, "J"}, + {kHIDUsage_KeyboardK, "K"}, + {kHIDUsage_KeyboardL, "L"}, + {kHIDUsage_KeyboardM, "M"}, + {kHIDUsage_KeyboardN, "N"}, + {kHIDUsage_KeyboardO, "O"}, + {kHIDUsage_KeyboardP, "P"}, + {kHIDUsage_KeyboardQ, "Q"}, + {kHIDUsage_KeyboardR, "R"}, + {kHIDUsage_KeyboardS, "S"}, + {kHIDUsage_KeyboardT, "T"}, + {kHIDUsage_KeyboardU, "U"}, + {kHIDUsage_KeyboardV, "V"}, + {kHIDUsage_KeyboardW, "W"}, + {kHIDUsage_KeyboardX, "X"}, + {kHIDUsage_KeyboardY, "Y"}, + {kHIDUsage_KeyboardZ, "Z"}, + {kHIDUsage_Keyboard1, "1"}, + {kHIDUsage_Keyboard2, "2"}, + {kHIDUsage_Keyboard3, "3"}, + {kHIDUsage_Keyboard4, "4"}, + {kHIDUsage_Keyboard5, "5"}, + {kHIDUsage_Keyboard6, "6"}, + {kHIDUsage_Keyboard7, "7"}, + {kHIDUsage_Keyboard8, "8"}, + {kHIDUsage_Keyboard9, "9"}, + {kHIDUsage_Keyboard0, "0"}, + {kHIDUsage_KeyboardReturnOrEnter, "Return"}, + {kHIDUsage_KeyboardEscape, "Escape"}, + {kHIDUsage_KeyboardDeleteOrBackspace, "Backspace"}, + {kHIDUsage_KeyboardTab, "Tab"}, + {kHIDUsage_KeyboardSpacebar, "Space"}, + {kHIDUsage_KeyboardHyphen, "-"}, + {kHIDUsage_KeyboardEqualSign, "="}, + {kHIDUsage_KeyboardOpenBracket, "["}, + {kHIDUsage_KeyboardCloseBracket, "]"}, + {kHIDUsage_KeyboardBackslash, "\\"}, + {kHIDUsage_KeyboardSemicolon, ";"}, + {kHIDUsage_KeyboardQuote, "'"}, + {kHIDUsage_KeyboardGraveAccentAndTilde, "Tilde"}, + {kHIDUsage_KeyboardComma, ","}, + {kHIDUsage_KeyboardPeriod, "."}, + {kHIDUsage_KeyboardSlash, "/"}, + {kHIDUsage_KeyboardCapsLock, "Caps Lock"}, + {kHIDUsage_KeyboardF1, "F1"}, + {kHIDUsage_KeyboardF2, "F2"}, + {kHIDUsage_KeyboardF3, "F3"}, + {kHIDUsage_KeyboardF4, "F4"}, + {kHIDUsage_KeyboardF5, "F5"}, + {kHIDUsage_KeyboardF6, "F6"}, + {kHIDUsage_KeyboardF7, "F7"}, + {kHIDUsage_KeyboardF8, "F8"}, + {kHIDUsage_KeyboardF9, "F9"}, + {kHIDUsage_KeyboardF10, "F10"}, + {kHIDUsage_KeyboardF11, "F11"}, + {kHIDUsage_KeyboardF12, "F12"}, + {kHIDUsage_KeyboardInsert, "Insert"}, + {kHIDUsage_KeyboardHome, "Home"}, + {kHIDUsage_KeyboardPageUp, "Page Up"}, + {kHIDUsage_KeyboardDeleteForward, "Delete"}, + {kHIDUsage_KeyboardEnd, "End"}, + {kHIDUsage_KeyboardPageDown, "Page Down"}, + {kHIDUsage_KeyboardRightArrow, "Right Arrow"}, + {kHIDUsage_KeyboardLeftArrow, "Left Arrow"}, + {kHIDUsage_KeyboardDownArrow, "Down Arrow"}, + {kHIDUsage_KeyboardUpArrow, "Up Arrow"}, + {kHIDUsage_KeypadSlash, "Keypad /"}, + {kHIDUsage_KeypadAsterisk, "Keypad *"}, + {kHIDUsage_KeypadHyphen, "Keypad -"}, + {kHIDUsage_KeypadPlus, "Keypad +"}, + {kHIDUsage_KeypadEnter, "Keypad Enter"}, + {kHIDUsage_Keypad1, "Keypad 1"}, + {kHIDUsage_Keypad2, "Keypad 2"}, + {kHIDUsage_Keypad3, "Keypad 3"}, + {kHIDUsage_Keypad4, "Keypad 4"}, + {kHIDUsage_Keypad5, "Keypad 5"}, + {kHIDUsage_Keypad6, "Keypad 6"}, + {kHIDUsage_Keypad7, "Keypad 7"}, + {kHIDUsage_Keypad8, "Keypad 8"}, + {kHIDUsage_Keypad9, "Keypad 9"}, + {kHIDUsage_Keypad0, "Keypad 0"}, + {kHIDUsage_KeypadPeriod, "Keypad ."}, + {kHIDUsage_KeyboardNonUSBackslash, "Paragraph"}, + {kHIDUsage_KeypadEqualSign, "Keypad ="}, + {kHIDUsage_KeypadComma, "Keypad ,"}, + {kHIDUsage_KeyboardLeftControl, "Left Control"}, + {kHIDUsage_KeyboardLeftShift, "Left Shift"}, + {kHIDUsage_KeyboardLeftAlt, "Left Alt"}, + {kHIDUsage_KeyboardLeftGUI, "Left Command"}, + {kHIDUsage_KeyboardRightControl, "Right Control"}, + {kHIDUsage_KeyboardRightShift, "Right Shift"}, + {kHIDUsage_KeyboardRightAlt, "Right Alt"}, + {kHIDUsage_KeyboardRightGUI, "Right Command"}, + {184, "Eject"}, + }; - const uint32_t keycode = IOHIDElementGetUsage(m_element); - for (auto & named_key : named_keys) - { - if (named_key.code == keycode) - { - m_name = named_key.name; - return; - } - } + const uint32_t keycode = IOHIDElementGetUsage(m_element); + for (auto& named_key : named_keys) + { + if (named_key.code == keycode) + { + m_name = named_key.name; + return; + } + } - std::stringstream ss; - ss << "Key " << keycode; - m_name = ss.str(); + std::stringstream ss; + ss << "Key " << keycode; + m_name = ss.str(); } ControlState Keyboard::Key::GetState() const { - IOHIDValueRef value; + IOHIDValueRef value; - if (IOHIDDeviceGetValue(m_device, m_element, &value) == kIOReturnSuccess) - return IOHIDValueGetIntegerValue(value); - else - return 0; + if (IOHIDDeviceGetValue(m_device, m_element, &value) == kIOReturnSuccess) + return IOHIDValueGetIntegerValue(value); + else + return 0; } ControlState Keyboard::Cursor::GetState() const { - return std::max(0.0, ControlState(m_axis) / (m_positive ? 1.0 : -1.0)); + return std::max(0.0, ControlState(m_axis) / (m_positive ? 1.0 : -1.0)); } ControlState Keyboard::Button::GetState() const { - return (m_button != 0); + return (m_button != 0); } std::string Keyboard::Cursor::GetName() const { - static char tmpstr[] = "Cursor .."; - tmpstr[7] = (char)('X' + m_index); - tmpstr[8] = (m_positive ? '+' : '-'); - return tmpstr; + static char tmpstr[] = "Cursor .."; + tmpstr[7] = (char)('X' + m_index); + tmpstr[8] = (m_positive ? '+' : '-'); + return tmpstr; } std::string Keyboard::Button::GetName() const { - return std::string("Click ") + char('0' + m_index); + return std::string("Click ") + char('0' + m_index); } std::string Keyboard::Key::GetName() const { - return m_name; -} - - + return m_name; +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp b/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp index cff69fabfc..95bdcc4da2 100644 --- a/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp @@ -10,9 +10,9 @@ #include #include #include +#include #include #include -#include #include "Common/FileUtil.h" #include "Common/MathUtil.h" @@ -23,168 +23,144 @@ namespace ciface { namespace Pipes { +static const std::array s_button_tokens{ + {"A", "B", "X", "Y", "Z", "START", "L", "R", "D_UP", "D_DOWN", "D_LEFT", "D_RIGHT"}}; -static const std::array s_button_tokens -{{ - "A", - "B", - "X", - "Y", - "Z", - "START", - "L", - "R", - "D_UP", - "D_DOWN", - "D_LEFT", - "D_RIGHT" -}}; +static const std::array s_shoulder_tokens{{"L", "R"}}; -static const std::array s_shoulder_tokens -{{ - "L", - "R" -}}; - -static const std::array s_axis_tokens -{{ - "MAIN", - "C" -}}; +static const std::array s_axis_tokens{{"MAIN", "C"}}; static double StringToDouble(const std::string& text) { - std::istringstream is(text); - // ignore current locale - is.imbue(std::locale::classic()); - double result; - is >> result; - return result; + std::istringstream is(text); + // ignore current locale + is.imbue(std::locale::classic()); + double result; + is >> result; + return result; } void Init(std::vector& devices) { - // Search the Pipes directory for files that we can open in read-only, - // non-blocking mode. The device name is the virtual name of the file. - File::FSTEntry fst; - int found = 0; - std::string dir_path = File::GetUserPath(D_PIPES_IDX); - if (!File::Exists(dir_path)) - return; - fst = File::ScanDirectoryTree(dir_path, false); - if (!fst.isDirectory) - return; - for (unsigned int i = 0; i < fst.size; ++i) - { - const File::FSTEntry& child = fst.children[i]; - if (child.isDirectory) - continue; - int fd = open(child.physicalName.c_str(), O_RDONLY | O_NONBLOCK); - if (fd < 0) - continue; - devices.push_back(new PipeDevice(fd, child.virtualName, found++)); - } + // Search the Pipes directory for files that we can open in read-only, + // non-blocking mode. The device name is the virtual name of the file. + File::FSTEntry fst; + int found = 0; + std::string dir_path = File::GetUserPath(D_PIPES_IDX); + if (!File::Exists(dir_path)) + return; + fst = File::ScanDirectoryTree(dir_path, false); + if (!fst.isDirectory) + return; + for (unsigned int i = 0; i < fst.size; ++i) + { + const File::FSTEntry& child = fst.children[i]; + if (child.isDirectory) + continue; + int fd = open(child.physicalName.c_str(), O_RDONLY | O_NONBLOCK); + if (fd < 0) + continue; + devices.push_back(new PipeDevice(fd, child.virtualName, found++)); + } } -PipeDevice::PipeDevice(int fd, const std::string& name, int id) - : m_fd(fd), m_name(name), m_id(id) +PipeDevice::PipeDevice(int fd, const std::string& name, int id) : m_fd(fd), m_name(name), m_id(id) { - for (const auto& tok : s_button_tokens) - { - PipeInput* btn = new PipeInput("Button " + tok); - AddInput(btn); - m_buttons[tok] = btn; - } - for (const auto& tok : s_shoulder_tokens) - { - AddAxis(tok, 0.0); - } - for (const auto& tok : s_axis_tokens) - { - AddAxis(tok + " X", 0.5); - AddAxis(tok + " Y", 0.5); - } + for (const auto& tok : s_button_tokens) + { + PipeInput* btn = new PipeInput("Button " + tok); + AddInput(btn); + m_buttons[tok] = btn; + } + for (const auto& tok : s_shoulder_tokens) + { + AddAxis(tok, 0.0); + } + for (const auto& tok : s_axis_tokens) + { + AddAxis(tok + " X", 0.5); + AddAxis(tok + " Y", 0.5); + } } PipeDevice::~PipeDevice() { - close(m_fd); + close(m_fd); } void PipeDevice::UpdateInput() { - // Read any pending characters off the pipe. If we hit a newline, - // then dequeue a command off the front of m_buf and parse it. - char buf[32]; - ssize_t bytes_read = read(m_fd, buf, sizeof buf); - while (bytes_read > 0) - { - m_buf.append(buf, bytes_read); - bytes_read = read(m_fd, buf, sizeof buf); - } - std::size_t newline = m_buf.find("\n"); - while (newline != std::string::npos) - { - std::string command = m_buf.substr(0, newline); - ParseCommand(command); - m_buf.erase(0, newline + 1); - newline = m_buf.find("\n"); - } + // Read any pending characters off the pipe. If we hit a newline, + // then dequeue a command off the front of m_buf and parse it. + char buf[32]; + ssize_t bytes_read = read(m_fd, buf, sizeof buf); + while (bytes_read > 0) + { + m_buf.append(buf, bytes_read); + bytes_read = read(m_fd, buf, sizeof buf); + } + std::size_t newline = m_buf.find("\n"); + while (newline != std::string::npos) + { + std::string command = m_buf.substr(0, newline); + ParseCommand(command); + m_buf.erase(0, newline + 1); + newline = m_buf.find("\n"); + } } void PipeDevice::AddAxis(const std::string& name, double value) { - // Dolphin uses separate axes for left/right, which complicates things. - PipeInput* ax_hi = new PipeInput("Axis " + name + " +"); - ax_hi->SetState(value); - PipeInput* ax_lo = new PipeInput("Axis " + name + " -"); - ax_lo->SetState(value); - m_axes[name + " +"] = ax_hi; - m_axes[name + " -"] = ax_lo; - AddAnalogInputs(ax_lo, ax_hi); + // Dolphin uses separate axes for left/right, which complicates things. + PipeInput* ax_hi = new PipeInput("Axis " + name + " +"); + ax_hi->SetState(value); + PipeInput* ax_lo = new PipeInput("Axis " + name + " -"); + ax_lo->SetState(value); + m_axes[name + " +"] = ax_hi; + m_axes[name + " -"] = ax_lo; + AddAnalogInputs(ax_lo, ax_hi); } void PipeDevice::SetAxis(const std::string& entry, double value) { - value = MathUtil::Clamp(value, 0.0, 1.0); - double hi = std::max(0.0, value - 0.5) * 2.0; - double lo = (0.5 - std::min(0.5, value)) * 2.0; - auto search_hi = m_axes.find(entry + " +"); - if (search_hi != m_axes.end()) - search_hi->second->SetState(hi); - auto search_lo = m_axes.find(entry + " -"); - if (search_lo != m_axes.end()) - search_lo->second->SetState(lo); + value = MathUtil::Clamp(value, 0.0, 1.0); + double hi = std::max(0.0, value - 0.5) * 2.0; + double lo = (0.5 - std::min(0.5, value)) * 2.0; + auto search_hi = m_axes.find(entry + " +"); + if (search_hi != m_axes.end()) + search_hi->second->SetState(hi); + auto search_lo = m_axes.find(entry + " -"); + if (search_lo != m_axes.end()) + search_lo->second->SetState(lo); } void PipeDevice::ParseCommand(const std::string& command) { - std::vector tokens; - SplitString(command, ' ', tokens); - if (tokens.size() < 2 || tokens.size() > 4) - return; - if (tokens[0] == "PRESS" || tokens[0] == "RELEASE") - { - auto search = m_buttons.find(tokens[1]); - if (search != m_buttons.end()) - search->second->SetState(tokens[0] == "PRESS" ? 1.0 : 0.0); - } - else if (tokens[0] == "SET") - { - if (tokens.size() == 3) - { - double value = StringToDouble(tokens[2]); - SetAxis(tokens[1], (value / 2.0) + 0.5); - } - else if (tokens.size() == 4) - { - double x = StringToDouble(tokens[2]); - double y = StringToDouble(tokens[3]); - SetAxis(tokens[1] + " X", x); - SetAxis(tokens[1] + " Y", y); - } - } -} - + std::vector tokens; + SplitString(command, ' ', tokens); + if (tokens.size() < 2 || tokens.size() > 4) + return; + if (tokens[0] == "PRESS" || tokens[0] == "RELEASE") + { + auto search = m_buttons.find(tokens[1]); + if (search != m_buttons.end()) + search->second->SetState(tokens[0] == "PRESS" ? 1.0 : 0.0); + } + else if (tokens[0] == "SET") + { + if (tokens.size() == 3) + { + double value = StringToDouble(tokens[2]); + SetAxis(tokens[1], (value / 2.0) + 0.5); + } + else if (tokens.size() == 4) + { + double x = StringToDouble(tokens[2]); + double y = StringToDouble(tokens[3]); + SetAxis(tokens[1] + " X", x); + SetAxis(tokens[1] + " Y", y); + } + } +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.h b/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.h index c3c2ea0063..855c45953b 100644 --- a/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.h +++ b/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.h @@ -29,37 +29,36 @@ void Init(std::vector& devices); class PipeDevice : public Core::Device { public: - PipeDevice(int fd, const std::string& name, int id); - ~PipeDevice(); - - void UpdateInput() override; - std::string GetName() const override { return m_name; } - int GetId() const override { return m_id; } - std::string GetSource() const override { return "Pipe"; } + PipeDevice(int fd, const std::string& name, int id); + ~PipeDevice(); + void UpdateInput() override; + std::string GetName() const override { return m_name; } + int GetId() const override { return m_id; } + std::string GetSource() const override { return "Pipe"; } private: - class PipeInput : public Input - { - public: - PipeInput(const std::string& name) : m_name(name), m_state(0.0) {} - std::string GetName() const override { return m_name; } - ControlState GetState() const override { return m_state; } - void SetState(ControlState state) { m_state = state; } - private: - const std::string m_name; - ControlState m_state; - }; + class PipeInput : public Input + { + public: + PipeInput(const std::string& name) : m_name(name), m_state(0.0) {} + std::string GetName() const override { return m_name; } + ControlState GetState() const override { return m_state; } + void SetState(ControlState state) { m_state = state; } + private: + const std::string m_name; + ControlState m_state; + }; - void AddAxis(const std::string& name, double value); - void ParseCommand(const std::string& command); - void SetAxis(const std::string& entry, double value); + void AddAxis(const std::string& name, double value); + void ParseCommand(const std::string& command); + void SetAxis(const std::string& entry, double value); - const int m_fd; - const std::string m_name; - const int m_id; - std::string m_buf; - std::map m_buttons; - std::map m_axes; + const int m_fd; + const std::string m_name; + const int m_id; + std::string m_buf; + std::map m_buttons; + std::map m_axes; }; } } diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp index 6cdfa470cd..8b87261480 100644 --- a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp +++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp @@ -17,330 +17,321 @@ namespace ciface { namespace SDL { - // 10ms = 100Hz which homebrew docs very roughly imply is within WiiMote normal // range, used for periodic haptic effects though often ignored by devices static const u16 RUMBLE_PERIOD = 10; -static const u16 RUMBLE_LENGTH_MAX = 500; // ms: enough to span multiple frames at low FPS, but still finite +static const u16 RUMBLE_LENGTH_MAX = + 500; // ms: enough to span multiple frames at low FPS, but still finite static std::string GetJoystickName(int index) { #if SDL_VERSION_ATLEAST(2, 0, 0) - return SDL_JoystickNameForIndex(index); + return SDL_JoystickNameForIndex(index); #else - return SDL_JoystickName(index); + return SDL_JoystickName(index); #endif } -void Init( std::vector& devices ) +void Init(std::vector& devices) { - // this is used to number the joysticks - // multiple joysticks with the same name shall get unique ids starting at 0 - std::map name_counts; + // this is used to number the joysticks + // multiple joysticks with the same name shall get unique ids starting at 0 + std::map name_counts; #ifdef USE_SDL_HAPTIC - if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) >= 0) - { - // Correctly initialized - } - else + if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) >= 0) + { + // Correctly initialized + } + else #endif - if (SDL_Init(SDL_INIT_JOYSTICK) < 0) - { - // Failed to initialize - return; - } + if (SDL_Init(SDL_INIT_JOYSTICK) < 0) + { + // Failed to initialize + return; + } - // joysticks - for (int i = 0; i < SDL_NumJoysticks(); ++i) - { - SDL_Joystick* dev = SDL_JoystickOpen(i); - if (dev) - { - Joystick* js = new Joystick(dev, i, name_counts[GetJoystickName(i)]++); - // only add if it has some inputs/outputs - if (js->Inputs().size() || js->Outputs().size()) - devices.push_back( js ); - else - delete js; - } - } + // joysticks + for (int i = 0; i < SDL_NumJoysticks(); ++i) + { + SDL_Joystick* dev = SDL_JoystickOpen(i); + if (dev) + { + Joystick* js = new Joystick(dev, i, name_counts[GetJoystickName(i)]++); + // only add if it has some inputs/outputs + if (js->Inputs().size() || js->Outputs().size()) + devices.push_back(js); + else + delete js; + } + } } Joystick::Joystick(SDL_Joystick* const joystick, const int sdl_index, const unsigned int index) - : m_joystick(joystick) - , m_sdl_index(sdl_index) - , m_index(index) + : m_joystick(joystick), m_sdl_index(sdl_index), m_index(index) { - // really bad HACKS: - // to not use SDL for an XInput device - // too many people on the forums pick the SDL device and ask: - // "why don't my 360 gamepad triggers/rumble work correctly" +// really bad HACKS: +// to not use SDL for an XInput device +// too many people on the forums pick the SDL device and ask: +// "why don't my 360 gamepad triggers/rumble work correctly" #ifdef _WIN32 - // checking the name is probably good (and hacky) enough - // but I'll double check with the num of buttons/axes - std::string lcasename = GetName(); - std::transform(lcasename.begin(), lcasename.end(), lcasename.begin(), tolower); + // checking the name is probably good (and hacky) enough + // but I'll double check with the num of buttons/axes + std::string lcasename = GetName(); + std::transform(lcasename.begin(), lcasename.end(), lcasename.begin(), tolower); - if ((std::string::npos != lcasename.find("xbox 360")) && - (10 == SDL_JoystickNumButtons(joystick)) && - (5 == SDL_JoystickNumAxes(joystick)) && - (1 == SDL_JoystickNumHats(joystick)) && - (0 == SDL_JoystickNumBalls(joystick))) - { - // this device won't be used - return; - } + if ((std::string::npos != lcasename.find("xbox 360")) && + (10 == SDL_JoystickNumButtons(joystick)) && (5 == SDL_JoystickNumAxes(joystick)) && + (1 == SDL_JoystickNumHats(joystick)) && (0 == SDL_JoystickNumBalls(joystick))) + { + // this device won't be used + return; + } #endif - if (SDL_JoystickNumButtons(joystick) > 255 || - SDL_JoystickNumAxes(joystick) > 255 || - SDL_JoystickNumHats(joystick) > 255 || - SDL_JoystickNumBalls(joystick) > 255) - { - // This device is invalid, don't use it - // Some crazy devices(HP webcam 2100) end up as HID devices - // SDL tries parsing these as joysticks - return; - } + if (SDL_JoystickNumButtons(joystick) > 255 || SDL_JoystickNumAxes(joystick) > 255 || + SDL_JoystickNumHats(joystick) > 255 || SDL_JoystickNumBalls(joystick) > 255) + { + // This device is invalid, don't use it + // Some crazy devices(HP webcam 2100) end up as HID devices + // SDL tries parsing these as joysticks + return; + } - // get buttons - for (u8 i = 0; i != SDL_JoystickNumButtons(m_joystick); ++i) - AddInput(new Button(i, m_joystick)); + // get buttons + for (u8 i = 0; i != SDL_JoystickNumButtons(m_joystick); ++i) + AddInput(new Button(i, m_joystick)); - // get hats - for (u8 i = 0; i != SDL_JoystickNumHats(m_joystick); ++i) - { - // each hat gets 4 input instances associated with it, (up down left right) - for (u8 d = 0; d != 4; ++d) - AddInput(new Hat(i, m_joystick, d)); - } + // get hats + for (u8 i = 0; i != SDL_JoystickNumHats(m_joystick); ++i) + { + // each hat gets 4 input instances associated with it, (up down left right) + for (u8 d = 0; d != 4; ++d) + AddInput(new Hat(i, m_joystick, d)); + } - // get axes - for (u8 i = 0; i != SDL_JoystickNumAxes(m_joystick); ++i) - { - // each axis gets a negative and a positive input instance associated with it - AddAnalogInputs(new Axis(i, m_joystick, -32768), - new Axis(i, m_joystick, 32767)); - } + // get axes + for (u8 i = 0; i != SDL_JoystickNumAxes(m_joystick); ++i) + { + // each axis gets a negative and a positive input instance associated with it + AddAnalogInputs(new Axis(i, m_joystick, -32768), new Axis(i, m_joystick, 32767)); + } #ifdef USE_SDL_HAPTIC - // try to get supported ff effects - m_haptic = SDL_HapticOpenFromJoystick( m_joystick ); - if (m_haptic) - { - //SDL_HapticSetGain( m_haptic, 1000 ); - //SDL_HapticSetAutocenter( m_haptic, 0 ); + // try to get supported ff effects + m_haptic = SDL_HapticOpenFromJoystick(m_joystick); + if (m_haptic) + { + // SDL_HapticSetGain( m_haptic, 1000 ); + // SDL_HapticSetAutocenter( m_haptic, 0 ); - const unsigned int supported_effects = SDL_HapticQuery( m_haptic ); + const unsigned int supported_effects = SDL_HapticQuery(m_haptic); - // constant effect - if (supported_effects & SDL_HAPTIC_CONSTANT) - AddOutput(new ConstantEffect(m_haptic)); + // constant effect + if (supported_effects & SDL_HAPTIC_CONSTANT) + AddOutput(new ConstantEffect(m_haptic)); - // ramp effect - if (supported_effects & SDL_HAPTIC_RAMP) - AddOutput(new RampEffect(m_haptic)); + // ramp effect + if (supported_effects & SDL_HAPTIC_RAMP) + AddOutput(new RampEffect(m_haptic)); - // sine effect - if (supported_effects & SDL_HAPTIC_SINE) - AddOutput(new SineEffect(m_haptic)); + // sine effect + if (supported_effects & SDL_HAPTIC_SINE) + AddOutput(new SineEffect(m_haptic)); - // triangle effect - if (supported_effects & SDL_HAPTIC_TRIANGLE) - AddOutput(new TriangleEffect(m_haptic)); + // triangle effect + if (supported_effects & SDL_HAPTIC_TRIANGLE) + AddOutput(new TriangleEffect(m_haptic)); - // left-right effect - if (supported_effects & SDL_HAPTIC_LEFTRIGHT) - AddOutput(new LeftRightEffect(m_haptic)); - } + // left-right effect + if (supported_effects & SDL_HAPTIC_LEFTRIGHT) + AddOutput(new LeftRightEffect(m_haptic)); + } #endif - } Joystick::~Joystick() { #ifdef USE_SDL_HAPTIC - if (m_haptic) - { - // stop/destroy all effects - SDL_HapticStopAll(m_haptic); - // close haptic first - SDL_HapticClose(m_haptic); - } + if (m_haptic) + { + // stop/destroy all effects + SDL_HapticStopAll(m_haptic); + // close haptic first + SDL_HapticClose(m_haptic); + } #endif - // close joystick - SDL_JoystickClose(m_joystick); + // close joystick + SDL_JoystickClose(m_joystick); } #ifdef USE_SDL_HAPTIC void Joystick::HapticEffect::Update() { - if (m_id == -1 && m_effect.type > 0) - { - m_id = SDL_HapticNewEffect(m_haptic, &m_effect); - if (m_id > -1) - SDL_HapticRunEffect(m_haptic, m_id, 1); - } - else if (m_id > -1 && m_effect.type == 0) - { - SDL_HapticStopEffect(m_haptic, m_id); - SDL_HapticDestroyEffect(m_haptic, m_id); - m_id = -1; - } - else if (m_id > -1) - { - SDL_HapticUpdateEffect(m_haptic, m_id, &m_effect); - } + if (m_id == -1 && m_effect.type > 0) + { + m_id = SDL_HapticNewEffect(m_haptic, &m_effect); + if (m_id > -1) + SDL_HapticRunEffect(m_haptic, m_id, 1); + } + else if (m_id > -1 && m_effect.type == 0) + { + SDL_HapticStopEffect(m_haptic, m_id); + SDL_HapticDestroyEffect(m_haptic, m_id); + m_id = -1; + } + else if (m_id > -1) + { + SDL_HapticUpdateEffect(m_haptic, m_id, &m_effect); + } } std::string Joystick::ConstantEffect::GetName() const { - return "Constant"; + return "Constant"; } std::string Joystick::RampEffect::GetName() const { - return "Ramp"; + return "Ramp"; } std::string Joystick::SineEffect::GetName() const { - return "Sine"; + return "Sine"; } std::string Joystick::TriangleEffect::GetName() const { - return "Triangle"; + return "Triangle"; } std::string Joystick::LeftRightEffect::GetName() const { - return "LeftRight"; + return "LeftRight"; } void Joystick::HapticEffect::SetState(ControlState state) { - memset(&m_effect, 0, sizeof(m_effect)); - if (state) - { - SetSDLHapticEffect(state); - } - else - { - // this module uses type==0 to indicate 'off' - m_effect.type = 0; - } - Update(); + memset(&m_effect, 0, sizeof(m_effect)); + if (state) + { + SetSDLHapticEffect(state); + } + else + { + // this module uses type==0 to indicate 'off' + m_effect.type = 0; + } + Update(); } void Joystick::ConstantEffect::SetSDLHapticEffect(ControlState state) { - m_effect.type = SDL_HAPTIC_CONSTANT; - m_effect.constant.length = RUMBLE_LENGTH_MAX; - m_effect.constant.level = (Sint16)(state * 0x7FFF); + m_effect.type = SDL_HAPTIC_CONSTANT; + m_effect.constant.length = RUMBLE_LENGTH_MAX; + m_effect.constant.level = (Sint16)(state * 0x7FFF); } void Joystick::RampEffect::SetSDLHapticEffect(ControlState state) { - m_effect.type = SDL_HAPTIC_RAMP; - m_effect.ramp.length = RUMBLE_LENGTH_MAX; - m_effect.ramp.start = (Sint16)(state * 0x7FFF); + m_effect.type = SDL_HAPTIC_RAMP; + m_effect.ramp.length = RUMBLE_LENGTH_MAX; + m_effect.ramp.start = (Sint16)(state * 0x7FFF); } void Joystick::SineEffect::SetSDLHapticEffect(ControlState state) { - m_effect.type = SDL_HAPTIC_SINE; - m_effect.periodic.period = RUMBLE_PERIOD; - m_effect.periodic.magnitude = (Sint16)(state * 0x7FFF); - m_effect.periodic.offset = 0; - m_effect.periodic.phase = 18000; - m_effect.periodic.length = RUMBLE_LENGTH_MAX; - m_effect.periodic.delay = 0; - m_effect.periodic.attack_length = 0; + m_effect.type = SDL_HAPTIC_SINE; + m_effect.periodic.period = RUMBLE_PERIOD; + m_effect.periodic.magnitude = (Sint16)(state * 0x7FFF); + m_effect.periodic.offset = 0; + m_effect.periodic.phase = 18000; + m_effect.periodic.length = RUMBLE_LENGTH_MAX; + m_effect.periodic.delay = 0; + m_effect.periodic.attack_length = 0; } void Joystick::TriangleEffect::SetSDLHapticEffect(ControlState state) { - m_effect.type = SDL_HAPTIC_TRIANGLE; - m_effect.periodic.period = RUMBLE_PERIOD; - m_effect.periodic.magnitude = (Sint16)(state * 0x7FFF); - m_effect.periodic.offset = 0; - m_effect.periodic.phase = 18000; - m_effect.periodic.length = RUMBLE_LENGTH_MAX; - m_effect.periodic.delay = 0; - m_effect.periodic.attack_length = 0; + m_effect.type = SDL_HAPTIC_TRIANGLE; + m_effect.periodic.period = RUMBLE_PERIOD; + m_effect.periodic.magnitude = (Sint16)(state * 0x7FFF); + m_effect.periodic.offset = 0; + m_effect.periodic.phase = 18000; + m_effect.periodic.length = RUMBLE_LENGTH_MAX; + m_effect.periodic.delay = 0; + m_effect.periodic.attack_length = 0; } void Joystick::LeftRightEffect::SetSDLHapticEffect(ControlState state) { - m_effect.type = SDL_HAPTIC_LEFTRIGHT; - m_effect.leftright.length = RUMBLE_LENGTH_MAX; - // max ranges tuned to 'feel' similar in magnitude to triangle/sine on xbox360 controller - m_effect.leftright.large_magnitude = (Uint16)(state * 0x4000); - m_effect.leftright.small_magnitude = (Uint16)(state * 0xFFFF); + m_effect.type = SDL_HAPTIC_LEFTRIGHT; + m_effect.leftright.length = RUMBLE_LENGTH_MAX; + // max ranges tuned to 'feel' similar in magnitude to triangle/sine on xbox360 controller + m_effect.leftright.large_magnitude = (Uint16)(state * 0x4000); + m_effect.leftright.small_magnitude = (Uint16)(state * 0xFFFF); } #endif void Joystick::UpdateInput() { - // each joystick is doin this, o well - SDL_JoystickUpdate(); + // each joystick is doin this, o well + SDL_JoystickUpdate(); } std::string Joystick::GetName() const { - return StripSpaces(GetJoystickName(m_sdl_index)); + return StripSpaces(GetJoystickName(m_sdl_index)); } std::string Joystick::GetSource() const { - return "SDL"; + return "SDL"; } int Joystick::GetId() const { - return m_index; + return m_index; } std::string Joystick::Button::GetName() const { - std::ostringstream ss; - ss << "Button " << (int)m_index; - return ss.str(); + std::ostringstream ss; + ss << "Button " << (int)m_index; + return ss.str(); } std::string Joystick::Axis::GetName() const { - std::ostringstream ss; - ss << "Axis " << (int)m_index << (m_range<0 ? '-' : '+'); - return ss.str(); + std::ostringstream ss; + ss << "Axis " << (int)m_index << (m_range < 0 ? '-' : '+'); + return ss.str(); } std::string Joystick::Hat::GetName() const { - static char tmpstr[] = "Hat . ."; - // I don't think more than 10 hats are supported - tmpstr[4] = (char)('0' + m_index); - tmpstr[6] = "NESW"[m_direction]; - return tmpstr; + static char tmpstr[] = "Hat . ."; + // I don't think more than 10 hats are supported + tmpstr[4] = (char)('0' + m_index); + tmpstr[6] = "NESW"[m_direction]; + return tmpstr; } ControlState Joystick::Button::GetState() const { - return SDL_JoystickGetButton(m_js, m_index); + return SDL_JoystickGetButton(m_js, m_index); } ControlState Joystick::Axis::GetState() const { - return std::max(0.0, ControlState(SDL_JoystickGetAxis(m_js, m_index)) / m_range); + return std::max(0.0, ControlState(SDL_JoystickGetAxis(m_js, m_index)) / m_range); } ControlState Joystick::Hat::GetState() const { - return (SDL_JoystickGetHat(m_js, m_index) & (1 << m_direction)) > 0; -} - + return (SDL_JoystickGetHat(m_js, m_index) & (1 << m_direction)) > 0; +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h index 751f40e9f4..10c3fab6ee 100644 --- a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h +++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h @@ -10,144 +10,155 @@ #include "InputCommon/ControllerInterface/Device.h" - #if SDL_VERSION_ATLEAST(1, 3, 0) - #define USE_SDL_HAPTIC +#define USE_SDL_HAPTIC #endif #ifdef USE_SDL_HAPTIC - #include +#include #endif namespace ciface { namespace SDL { - -void Init( std::vector& devices ); +void Init(std::vector& devices); class Joystick : public Core::Device { private: + class Button : public Core::Device::Input + { + public: + std::string GetName() const override; + Button(u8 index, SDL_Joystick* js) : m_js(js), m_index(index) {} + ControlState GetState() const override; - class Button : public Core::Device::Input - { - public: - std::string GetName() const override; - Button(u8 index, SDL_Joystick* js) : m_js(js), m_index(index) {} - ControlState GetState() const override; - private: - SDL_Joystick* const m_js; - const u8 m_index; - }; + private: + SDL_Joystick* const m_js; + const u8 m_index; + }; - class Axis : public Core::Device::Input - { - public: - std::string GetName() const override; - Axis(u8 index, SDL_Joystick* js, Sint16 range) : m_js(js), m_range(range), m_index(index) {} - ControlState GetState() const override; - private: - SDL_Joystick* const m_js; - const Sint16 m_range; - const u8 m_index; - }; + class Axis : public Core::Device::Input + { + public: + std::string GetName() const override; + Axis(u8 index, SDL_Joystick* js, Sint16 range) : m_js(js), m_range(range), m_index(index) {} + ControlState GetState() const override; - class Hat : public Input - { - public: - std::string GetName() const override; - Hat(u8 index, SDL_Joystick* js, u8 direction) : m_js(js), m_direction(direction), m_index(index) {} - ControlState GetState() const override; - private: - SDL_Joystick* const m_js; - const u8 m_direction; - const u8 m_index; - }; + private: + SDL_Joystick* const m_js; + const Sint16 m_range; + const u8 m_index; + }; + + class Hat : public Input + { + public: + std::string GetName() const override; + Hat(u8 index, SDL_Joystick* js, u8 direction) : m_js(js), m_direction(direction), m_index(index) + { + } + ControlState GetState() const override; + + private: + SDL_Joystick* const m_js; + const u8 m_direction; + const u8 m_index; + }; #ifdef USE_SDL_HAPTIC - class HapticEffect : public Output - { - public: - HapticEffect(SDL_Haptic* haptic) : m_haptic(haptic), m_id(-1) {} - ~HapticEffect() { m_effect.type = 0; Update(); } + class HapticEffect : public Output + { + public: + HapticEffect(SDL_Haptic* haptic) : m_haptic(haptic), m_id(-1) {} + ~HapticEffect() + { + m_effect.type = 0; + Update(); + } - protected: - void Update(); - virtual void SetSDLHapticEffect(ControlState state) = 0; + protected: + void Update(); + virtual void SetSDLHapticEffect(ControlState state) = 0; - SDL_HapticEffect m_effect; - SDL_Haptic* m_haptic; - int m_id; - private: - virtual void SetState(ControlState state) override final; - }; + SDL_HapticEffect m_effect; + SDL_Haptic* m_haptic; + int m_id; - class ConstantEffect : public HapticEffect - { - public: - ConstantEffect(SDL_Haptic* haptic) : HapticEffect(haptic) {} - std::string GetName() const override; - private: - void SetSDLHapticEffect(ControlState state) override; - }; + private: + virtual void SetState(ControlState state) override final; + }; - class RampEffect : public HapticEffect - { - public: - RampEffect(SDL_Haptic* haptic) : HapticEffect(haptic) {} - std::string GetName() const override; - private: - void SetSDLHapticEffect(ControlState state) override; - }; + class ConstantEffect : public HapticEffect + { + public: + ConstantEffect(SDL_Haptic* haptic) : HapticEffect(haptic) {} + std::string GetName() const override; - class SineEffect : public HapticEffect - { - public: - SineEffect(SDL_Haptic* haptic) : HapticEffect(haptic) {} - std::string GetName() const override; - private: - void SetSDLHapticEffect(ControlState state) override; - }; + private: + void SetSDLHapticEffect(ControlState state) override; + }; - class TriangleEffect : public HapticEffect - { - public: - TriangleEffect(SDL_Haptic* haptic) : HapticEffect(haptic) {} - std::string GetName() const override; - private: - void SetSDLHapticEffect(ControlState state) override; - }; + class RampEffect : public HapticEffect + { + public: + RampEffect(SDL_Haptic* haptic) : HapticEffect(haptic) {} + std::string GetName() const override; - class LeftRightEffect : public HapticEffect - { - public: - LeftRightEffect(SDL_Haptic* haptic) : HapticEffect(haptic) {} - std::string GetName() const override; - private: - void SetSDLHapticEffect(ControlState state) override; - }; + private: + void SetSDLHapticEffect(ControlState state) override; + }; + + class SineEffect : public HapticEffect + { + public: + SineEffect(SDL_Haptic* haptic) : HapticEffect(haptic) {} + std::string GetName() const override; + + private: + void SetSDLHapticEffect(ControlState state) override; + }; + + class TriangleEffect : public HapticEffect + { + public: + TriangleEffect(SDL_Haptic* haptic) : HapticEffect(haptic) {} + std::string GetName() const override; + + private: + void SetSDLHapticEffect(ControlState state) override; + }; + + class LeftRightEffect : public HapticEffect + { + public: + LeftRightEffect(SDL_Haptic* haptic) : HapticEffect(haptic) {} + std::string GetName() const override; + + private: + void SetSDLHapticEffect(ControlState state) override; + }; #endif public: - void UpdateInput() override; + void UpdateInput() override; - Joystick(SDL_Joystick* const joystick, const int sdl_index, const unsigned int index); - ~Joystick(); + Joystick(SDL_Joystick* const joystick, const int sdl_index, const unsigned int index); + ~Joystick(); - std::string GetName() const override; - int GetId() const override; - std::string GetSource() const override; + std::string GetName() const override; + int GetId() const override; + std::string GetSource() const override; private: - SDL_Joystick* const m_joystick; - const int m_sdl_index; - const unsigned int m_index; + SDL_Joystick* const m_joystick; + const int m_sdl_index; + const unsigned int m_index; #ifdef USE_SDL_HAPTIC - SDL_Haptic* m_haptic; + SDL_Haptic* m_haptic; #endif }; - } } diff --git a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp index c8438b488f..d7ed3343a0 100644 --- a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp +++ b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - #include "InputCommon/ControllerInterface/XInput/XInput.h" #ifndef XINPUT_GAMEPAD_GUIDE @@ -13,49 +12,31 @@ namespace ciface { namespace XInput { - static const struct { - const char* const name; - const WORD bitmask; -} named_buttons[] = -{ - { "Button A", XINPUT_GAMEPAD_A }, - { "Button B", XINPUT_GAMEPAD_B }, - { "Button X", XINPUT_GAMEPAD_X }, - { "Button Y", XINPUT_GAMEPAD_Y }, - { "Pad N", XINPUT_GAMEPAD_DPAD_UP }, - { "Pad S", XINPUT_GAMEPAD_DPAD_DOWN }, - { "Pad W", XINPUT_GAMEPAD_DPAD_LEFT }, - { "Pad E", XINPUT_GAMEPAD_DPAD_RIGHT }, - { "Start", XINPUT_GAMEPAD_START }, - { "Back", XINPUT_GAMEPAD_BACK }, - { "Shoulder L", XINPUT_GAMEPAD_LEFT_SHOULDER }, - { "Shoulder R", XINPUT_GAMEPAD_RIGHT_SHOULDER }, - { "Guide", XINPUT_GAMEPAD_GUIDE }, - { "Thumb L", XINPUT_GAMEPAD_LEFT_THUMB }, - { "Thumb R", XINPUT_GAMEPAD_RIGHT_THUMB } -}; + const char* const name; + const WORD bitmask; +} named_buttons[] = {{"Button A", XINPUT_GAMEPAD_A}, + {"Button B", XINPUT_GAMEPAD_B}, + {"Button X", XINPUT_GAMEPAD_X}, + {"Button Y", XINPUT_GAMEPAD_Y}, + {"Pad N", XINPUT_GAMEPAD_DPAD_UP}, + {"Pad S", XINPUT_GAMEPAD_DPAD_DOWN}, + {"Pad W", XINPUT_GAMEPAD_DPAD_LEFT}, + {"Pad E", XINPUT_GAMEPAD_DPAD_RIGHT}, + {"Start", XINPUT_GAMEPAD_START}, + {"Back", XINPUT_GAMEPAD_BACK}, + {"Shoulder L", XINPUT_GAMEPAD_LEFT_SHOULDER}, + {"Shoulder R", XINPUT_GAMEPAD_RIGHT_SHOULDER}, + {"Guide", XINPUT_GAMEPAD_GUIDE}, + {"Thumb L", XINPUT_GAMEPAD_LEFT_THUMB}, + {"Thumb R", XINPUT_GAMEPAD_RIGHT_THUMB}}; -static const char* const named_triggers[] = -{ - "Trigger L", - "Trigger R" -}; +static const char* const named_triggers[] = {"Trigger L", "Trigger R"}; -static const char* const named_axes[] = -{ - "Left X", - "Left Y", - "Right X", - "Right Y" -}; +static const char* const named_axes[] = {"Left X", "Left Y", "Right X", "Right Y"}; -static const char* const named_motors[] = -{ - "Motor L", - "Motor R" -}; +static const char* const named_motors[] = {"Motor L", "Motor R"}; static HMODULE hXInput = nullptr; @@ -71,199 +52,197 @@ static bool haveGuideButton = false; void Init(std::vector& devices) { - if (!hXInput) - { - // Try for the most recent version we were compiled against (will only work if running on Win8+) - hXInput = ::LoadLibrary(XINPUT_DLL); - if (!hXInput) - { - // Drop back to DXSDK June 2010 version. Requires DX June 2010 redist. - hXInput = ::LoadLibrary(TEXT("xinput1_3.dll")); - if (!hXInput) - { - return; - } - } + if (!hXInput) + { + // Try for the most recent version we were compiled against (will only work if running on Win8+) + hXInput = ::LoadLibrary(XINPUT_DLL); + if (!hXInput) + { + // Drop back to DXSDK June 2010 version. Requires DX June 2010 redist. + hXInput = ::LoadLibrary(TEXT("xinput1_3.dll")); + if (!hXInput) + { + return; + } + } - PXInputGetCapabilities = (XInputGetCapabilities_t)::GetProcAddress(hXInput, "XInputGetCapabilities"); - PXInputSetState = (XInputSetState_t)::GetProcAddress(hXInput, "XInputSetState"); + PXInputGetCapabilities = + (XInputGetCapabilities_t)::GetProcAddress(hXInput, "XInputGetCapabilities"); + PXInputSetState = (XInputSetState_t)::GetProcAddress(hXInput, "XInputSetState"); - // Ordinal 100 is the same as XInputGetState, except it doesn't dummy out the guide - // button info. Try loading it and fall back if needed. - PXInputGetState = (XInputGetState_t)::GetProcAddress(hXInput, (LPCSTR)100); - if (PXInputGetState) - haveGuideButton = true; - else - PXInputGetState = (XInputGetState_t)::GetProcAddress(hXInput, "XInputGetState"); + // Ordinal 100 is the same as XInputGetState, except it doesn't dummy out the guide + // button info. Try loading it and fall back if needed. + PXInputGetState = (XInputGetState_t)::GetProcAddress(hXInput, (LPCSTR)100); + if (PXInputGetState) + haveGuideButton = true; + else + PXInputGetState = (XInputGetState_t)::GetProcAddress(hXInput, "XInputGetState"); - if (!PXInputGetCapabilities || - !PXInputSetState || - !PXInputGetState) - { - ::FreeLibrary(hXInput); - hXInput = nullptr; - return; - } - } + if (!PXInputGetCapabilities || !PXInputSetState || !PXInputGetState) + { + ::FreeLibrary(hXInput); + hXInput = nullptr; + return; + } + } - XINPUT_CAPABILITIES caps; - for (int i = 0; i != 4; ++i) - if (ERROR_SUCCESS == PXInputGetCapabilities(i, 0, &caps)) - devices.push_back(new Device(caps, i)); + XINPUT_CAPABILITIES caps; + for (int i = 0; i != 4; ++i) + if (ERROR_SUCCESS == PXInputGetCapabilities(i, 0, &caps)) + devices.push_back(new Device(caps, i)); } void DeInit() { - if (hXInput) - { - ::FreeLibrary(hXInput); - hXInput = nullptr; - } + if (hXInput) + { + ::FreeLibrary(hXInput); + hXInput = nullptr; + } } -Device::Device(const XINPUT_CAPABILITIES& caps, u8 index) - : m_subtype(caps.SubType), m_index(index) +Device::Device(const XINPUT_CAPABILITIES& caps, u8 index) : m_subtype(caps.SubType), m_index(index) { - // XInputGetCaps seems to always claim all capabilities are supported - // but I will leave all this stuff in, incase m$ fixes xinput up a bit + // XInputGetCaps seems to always claim all capabilities are supported + // but I will leave all this stuff in, incase m$ fixes xinput up a bit - // get supported buttons - for (int i = 0; i != sizeof(named_buttons)/sizeof(*named_buttons); ++i) - { - // Guide button is never reported in caps - if ((named_buttons[i].bitmask & caps.Gamepad.wButtons) || - ((named_buttons[i].bitmask & XINPUT_GAMEPAD_GUIDE) && haveGuideButton)) - AddInput(new Button(i, m_state_in.Gamepad.wButtons)); - } + // get supported buttons + for (int i = 0; i != sizeof(named_buttons) / sizeof(*named_buttons); ++i) + { + // Guide button is never reported in caps + if ((named_buttons[i].bitmask & caps.Gamepad.wButtons) || + ((named_buttons[i].bitmask & XINPUT_GAMEPAD_GUIDE) && haveGuideButton)) + AddInput(new Button(i, m_state_in.Gamepad.wButtons)); + } - // get supported triggers - for (int i = 0; i != sizeof(named_triggers)/sizeof(*named_triggers); ++i) - { - //BYTE val = (&caps.Gamepad.bLeftTrigger)[i]; // should be max value / MSDN lies - if ((&caps.Gamepad.bLeftTrigger)[i]) - AddInput(new Trigger(i, (&m_state_in.Gamepad.bLeftTrigger)[i], 255 )); - } + // get supported triggers + for (int i = 0; i != sizeof(named_triggers) / sizeof(*named_triggers); ++i) + { + // BYTE val = (&caps.Gamepad.bLeftTrigger)[i]; // should be max value / MSDN lies + if ((&caps.Gamepad.bLeftTrigger)[i]) + AddInput(new Trigger(i, (&m_state_in.Gamepad.bLeftTrigger)[i], 255)); + } - // get supported axes - for (int i = 0; i != sizeof(named_axes)/sizeof(*named_axes); ++i) - { - //SHORT val = (&caps.Gamepad.sThumbLX)[i]; // xinput doesn't give the range / MSDN is a liar - if ((&caps.Gamepad.sThumbLX)[i]) - { - const SHORT& ax = (&m_state_in.Gamepad.sThumbLX)[i]; + // get supported axes + for (int i = 0; i != sizeof(named_axes) / sizeof(*named_axes); ++i) + { + // SHORT val = (&caps.Gamepad.sThumbLX)[i]; // xinput doesn't give the range / MSDN is a liar + if ((&caps.Gamepad.sThumbLX)[i]) + { + const SHORT& ax = (&m_state_in.Gamepad.sThumbLX)[i]; - // each axis gets a negative and a positive input instance associated with it - AddInput(new Axis(i, ax, -32768)); - AddInput(new Axis(i, ax, 32767)); - } - } + // each axis gets a negative and a positive input instance associated with it + AddInput(new Axis(i, ax, -32768)); + AddInput(new Axis(i, ax, 32767)); + } + } - // get supported motors - for (int i = 0; i != sizeof(named_motors)/sizeof(*named_motors); ++i) - { - //WORD val = (&caps.Vibration.wLeftMotorSpeed)[i]; // should be max value / nope, more lies - if ((&caps.Vibration.wLeftMotorSpeed)[i]) - AddOutput(new Motor(i, this, (&m_state_out.wLeftMotorSpeed)[i], 65535)); - } + // get supported motors + for (int i = 0; i != sizeof(named_motors) / sizeof(*named_motors); ++i) + { + // WORD val = (&caps.Vibration.wLeftMotorSpeed)[i]; // should be max value / nope, more lies + if ((&caps.Vibration.wLeftMotorSpeed)[i]) + AddOutput(new Motor(i, this, (&m_state_out.wLeftMotorSpeed)[i], 65535)); + } - ZeroMemory(&m_state_in, sizeof(m_state_in)); + ZeroMemory(&m_state_in, sizeof(m_state_in)); } std::string Device::GetName() const { - switch (m_subtype) - { - case XINPUT_DEVSUBTYPE_GAMEPAD: - return "Gamepad"; - case XINPUT_DEVSUBTYPE_WHEEL: - return "Wheel"; - case XINPUT_DEVSUBTYPE_ARCADE_STICK: - return "Arcade Stick"; - case XINPUT_DEVSUBTYPE_FLIGHT_STICK: - return "Flight Stick"; - case XINPUT_DEVSUBTYPE_DANCE_PAD: - return "Dance Pad"; - case XINPUT_DEVSUBTYPE_GUITAR: - return "Guitar"; - case XINPUT_DEVSUBTYPE_DRUM_KIT: - return "Drum Kit"; - default: - return "Device"; - } + switch (m_subtype) + { + case XINPUT_DEVSUBTYPE_GAMEPAD: + return "Gamepad"; + case XINPUT_DEVSUBTYPE_WHEEL: + return "Wheel"; + case XINPUT_DEVSUBTYPE_ARCADE_STICK: + return "Arcade Stick"; + case XINPUT_DEVSUBTYPE_FLIGHT_STICK: + return "Flight Stick"; + case XINPUT_DEVSUBTYPE_DANCE_PAD: + return "Dance Pad"; + case XINPUT_DEVSUBTYPE_GUITAR: + return "Guitar"; + case XINPUT_DEVSUBTYPE_DRUM_KIT: + return "Drum Kit"; + default: + return "Device"; + } } int Device::GetId() const { - return m_index; + return m_index; } std::string Device::GetSource() const { - return "XInput"; + return "XInput"; } // Update I/O void Device::UpdateInput() { - PXInputGetState(m_index, &m_state_in); + PXInputGetState(m_index, &m_state_in); } void Device::UpdateMotors() { - // this if statement is to make rumble work better when multiple ControllerInterfaces are using the device - // only calls XInputSetState if the state changed - if (memcmp(&m_state_out, &m_current_state_out, sizeof(m_state_out))) - { - m_current_state_out = m_state_out; - PXInputSetState(m_index, &m_state_out); - } + // this if statement is to make rumble work better when multiple ControllerInterfaces are using + // the device + // only calls XInputSetState if the state changed + if (memcmp(&m_state_out, &m_current_state_out, sizeof(m_state_out))) + { + m_current_state_out = m_state_out; + PXInputSetState(m_index, &m_state_out); + } } // GET name/source/id std::string Device::Button::GetName() const { - return named_buttons[m_index].name; + return named_buttons[m_index].name; } std::string Device::Axis::GetName() const { - return std::string(named_axes[m_index]) + (m_range<0 ? '-' : '+'); + return std::string(named_axes[m_index]) + (m_range < 0 ? '-' : '+'); } std::string Device::Trigger::GetName() const { - return named_triggers[m_index]; + return named_triggers[m_index]; } std::string Device::Motor::GetName() const { - return named_motors[m_index]; + return named_motors[m_index]; } // GET / SET STATES ControlState Device::Button::GetState() const { - return (m_buttons & named_buttons[m_index].bitmask) > 0; + return (m_buttons & named_buttons[m_index].bitmask) > 0; } ControlState Device::Trigger::GetState() const { - return ControlState(m_trigger) / m_range; + return ControlState(m_trigger) / m_range; } ControlState Device::Axis::GetState() const { - return std::max( 0.0, ControlState(m_axis) / m_range ); + return std::max(0.0, ControlState(m_axis) / m_range); } void Device::Motor::SetState(ControlState state) { - m_motor = (WORD)(state * m_range); - m_parent->UpdateMotors(); -} - + m_motor = (WORD)(state * m_range); + m_parent->UpdateMotors(); +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.h b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.h index 012e99eba2..204b1ecf81 100644 --- a/Source/Core/InputCommon/ControllerInterface/XInput/XInput.h +++ b/Source/Core/InputCommon/ControllerInterface/XInput/XInput.h @@ -9,8 +9,8 @@ #pragma once -#include #include +#include #include "InputCommon/ControllerInterface/Device.h" @@ -22,80 +22,87 @@ namespace ciface { namespace XInput { - void Init(std::vector& devices); void DeInit(); class Device : public Core::Device { private: - class Button : public Core::Device::Input - { - public: - Button(u8 index, const WORD& buttons) : m_buttons(buttons), m_index(index) {} - std::string GetName() const override; - ControlState GetState() const override; - private: - const WORD& m_buttons; - u8 m_index; - }; + class Button : public Core::Device::Input + { + public: + Button(u8 index, const WORD& buttons) : m_buttons(buttons), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; - class Axis : public Core::Device::Input - { - public: - Axis(u8 index, const SHORT& axis, SHORT range) : m_axis(axis), m_range(range), m_index(index) {} - std::string GetName() const override; - ControlState GetState() const override; - private: - const SHORT& m_axis; - const SHORT m_range; - const u8 m_index; - }; + private: + const WORD& m_buttons; + u8 m_index; + }; - class Trigger : public Core::Device::Input - { - public: - Trigger(u8 index, const BYTE& trigger, BYTE range) : m_trigger(trigger), m_range(range), m_index(index) {} - std::string GetName() const override; - ControlState GetState() const override; - private: - const BYTE& m_trigger; - const BYTE m_range; - const u8 m_index; - }; + class Axis : public Core::Device::Input + { + public: + Axis(u8 index, const SHORT& axis, SHORT range) : m_axis(axis), m_range(range), m_index(index) {} + std::string GetName() const override; + ControlState GetState() const override; - class Motor : public Core::Device::Output - { - public: - Motor(u8 index, Device* parent, WORD &motor, WORD range) : m_motor(motor), m_range(range), m_index(index), m_parent(parent) {} - std::string GetName() const override; - void SetState(ControlState state) override; - private: - WORD& m_motor; - const WORD m_range; - const u8 m_index; - Device* m_parent; - }; + private: + const SHORT& m_axis; + const SHORT m_range; + const u8 m_index; + }; + + class Trigger : public Core::Device::Input + { + public: + Trigger(u8 index, const BYTE& trigger, BYTE range) + : m_trigger(trigger), m_range(range), m_index(index) + { + } + std::string GetName() const override; + ControlState GetState() const override; + + private: + const BYTE& m_trigger; + const BYTE m_range; + const u8 m_index; + }; + + class Motor : public Core::Device::Output + { + public: + Motor(u8 index, Device* parent, WORD& motor, WORD range) + : m_motor(motor), m_range(range), m_index(index), m_parent(parent) + { + } + std::string GetName() const override; + void SetState(ControlState state) override; + + private: + WORD& m_motor; + const WORD m_range; + const u8 m_index; + Device* m_parent; + }; public: - void UpdateInput() override; + void UpdateInput() override; - Device(const XINPUT_CAPABILITIES& capabilities, u8 index); + Device(const XINPUT_CAPABILITIES& capabilities, u8 index); - std::string GetName() const override; - int GetId() const override; - std::string GetSource() const override; + std::string GetName() const override; + int GetId() const override; + std::string GetSource() const override; - void UpdateMotors(); + void UpdateMotors(); private: - XINPUT_STATE m_state_in; - XINPUT_VIBRATION m_state_out{}; - XINPUT_VIBRATION m_current_state_out{}; - const BYTE m_subtype; - const u8 m_index; + XINPUT_STATE m_state_in; + XINPUT_VIBRATION m_state_out{}; + XINPUT_VIBRATION m_current_state_out{}; + const BYTE m_subtype; + const u8 m_index; }; - - } } diff --git a/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp b/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp index 3d7a02a3a0..79b86a487d 100644 --- a/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp @@ -2,10 +2,10 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #include #include -#include #include "InputCommon/ControllerInterface/Xlib/XInput2.h" @@ -25,7 +25,6 @@ // * Key controls: these correspond to a limited subset of the keyboard // keys. - // Mouse axis control tuning. Unlike absolute mouse position, relative mouse // motion data needs to be tweaked and smoothed out a bit to be usable. @@ -46,325 +45,324 @@ namespace ciface { namespace XInput2 { - // This function will add zero or more KeyboardMouse objects to devices. void Init(std::vector& devices, void* const hwnd) { - Display* dpy = XOpenDisplay(nullptr); + Display* dpy = XOpenDisplay(nullptr); - // xi_opcode is important; it will be used to identify XInput events by - // the polling loop in UpdateInput. - int xi_opcode, event, error; + // xi_opcode is important; it will be used to identify XInput events by + // the polling loop in UpdateInput. + int xi_opcode, event, error; - // verify that the XInput extension is available - if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &event, &error)) - return; + // verify that the XInput extension is available + if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &event, &error)) + return; - // verify that the XInput extension is at at least version 2.0 - int major = 2, minor = 0; + // verify that the XInput extension is at at least version 2.0 + int major = 2, minor = 0; - if (XIQueryVersion(dpy, &major, &minor) != Success) - return; + if (XIQueryVersion(dpy, &major, &minor) != Success) + return; - // register all master devices with Dolphin + // register all master devices with Dolphin - XIDeviceInfo* all_masters; - XIDeviceInfo* current_master; - int num_masters; + XIDeviceInfo* all_masters; + XIDeviceInfo* current_master; + int num_masters; - all_masters = XIQueryDevice(dpy, XIAllMasterDevices, &num_masters); + all_masters = XIQueryDevice(dpy, XIAllMasterDevices, &num_masters); - for (int i = 0; i < num_masters; i++) - { - current_master = &all_masters[i]; - if (current_master->use == XIMasterPointer) - // Since current_master is a master pointer, its attachment must - // be a master keyboard. - devices.push_back(new KeyboardMouse((Window)hwnd, xi_opcode, current_master->deviceid, current_master->attachment)); - } + for (int i = 0; i < num_masters; i++) + { + current_master = &all_masters[i]; + if (current_master->use == XIMasterPointer) + // Since current_master is a master pointer, its attachment must + // be a master keyboard. + devices.push_back(new KeyboardMouse((Window)hwnd, xi_opcode, current_master->deviceid, + current_master->attachment)); + } - XCloseDisplay(dpy); + XCloseDisplay(dpy); - XIFreeDeviceInfo(all_masters); + XIFreeDeviceInfo(all_masters); } // Apply the event mask to the device and all its slaves. Only used in the // constructor. Remember, each KeyboardMouse has its own copy of the event // stream, which is how multiple event masks can "coexist." -void KeyboardMouse::SelectEventsForDevice(Window window, XIEventMask *mask, int deviceid) +void KeyboardMouse::SelectEventsForDevice(Window window, XIEventMask* mask, int deviceid) { - // Set the event mask for the master device. - mask->deviceid = deviceid; - XISelectEvents(m_display, window, mask, 1); + // Set the event mask for the master device. + mask->deviceid = deviceid; + XISelectEvents(m_display, window, mask, 1); - // Query all the master device's slaves and set the same event mask for - // those too. There are two reasons we want to do this. For mouse devices, - // we want the raw motion events, and only slaves (i.e. physical hardware - // devices) emit those. For keyboard devices, selecting slaves avoids - // dealing with key focus. + // Query all the master device's slaves and set the same event mask for + // those too. There are two reasons we want to do this. For mouse devices, + // we want the raw motion events, and only slaves (i.e. physical hardware + // devices) emit those. For keyboard devices, selecting slaves avoids + // dealing with key focus. - XIDeviceInfo* all_slaves; - XIDeviceInfo* current_slave; - int num_slaves; + XIDeviceInfo* all_slaves; + XIDeviceInfo* current_slave; + int num_slaves; - all_slaves = XIQueryDevice(m_display, XIAllDevices, &num_slaves); + all_slaves = XIQueryDevice(m_display, XIAllDevices, &num_slaves); - for (int i = 0; i < num_slaves; i++) - { - current_slave = &all_slaves[i]; - if ((current_slave->use != XISlavePointer && current_slave->use != XISlaveKeyboard) || current_slave->attachment != deviceid) - continue; - mask->deviceid = current_slave->deviceid; - XISelectEvents(m_display, window, mask, 1); - } + for (int i = 0; i < num_slaves; i++) + { + current_slave = &all_slaves[i]; + if ((current_slave->use != XISlavePointer && current_slave->use != XISlaveKeyboard) || + current_slave->attachment != deviceid) + continue; + mask->deviceid = current_slave->deviceid; + XISelectEvents(m_display, window, mask, 1); + } - XIFreeDeviceInfo(all_slaves); + XIFreeDeviceInfo(all_slaves); } KeyboardMouse::KeyboardMouse(Window window, int opcode, int pointer, int keyboard) - : m_window(window), xi_opcode(opcode), pointer_deviceid(pointer), keyboard_deviceid(keyboard) + : m_window(window), xi_opcode(opcode), pointer_deviceid(pointer), keyboard_deviceid(keyboard) { - memset(&m_state, 0, sizeof(m_state)); + memset(&m_state, 0, sizeof(m_state)); - // The cool thing about each KeyboardMouse object having its own Display - // is that each one gets its own separate copy of the X11 event stream, - // which it can individually filter to get just the events it's interested - // in. So be aware that each KeyboardMouse object actually has its own X11 - // "context." - m_display = XOpenDisplay(nullptr); + // The cool thing about each KeyboardMouse object having its own Display + // is that each one gets its own separate copy of the X11 event stream, + // which it can individually filter to get just the events it's interested + // in. So be aware that each KeyboardMouse object actually has its own X11 + // "context." + m_display = XOpenDisplay(nullptr); - int min_keycode, max_keycode; - XDisplayKeycodes(m_display, &min_keycode, &max_keycode); + int min_keycode, max_keycode; + XDisplayKeycodes(m_display, &min_keycode, &max_keycode); - int unused; // should always be 1 - XIDeviceInfo* pointer_device = XIQueryDevice(m_display, pointer_deviceid, &unused); - name = std::string(pointer_device->name); - XIFreeDeviceInfo(pointer_device); + int unused; // should always be 1 + XIDeviceInfo* pointer_device = XIQueryDevice(m_display, pointer_deviceid, &unused); + name = std::string(pointer_device->name); + XIFreeDeviceInfo(pointer_device); - XIEventMask mask; - unsigned char mask_buf[(XI_LASTEVENT + 7)/8]; + XIEventMask mask; + unsigned char mask_buf[(XI_LASTEVENT + 7) / 8]; - mask.mask_len = sizeof(mask_buf); - mask.mask = mask_buf; - memset(mask_buf, 0, sizeof(mask_buf)); + mask.mask_len = sizeof(mask_buf); + mask.mask = mask_buf; + memset(mask_buf, 0, sizeof(mask_buf)); - XISetMask(mask_buf, XI_ButtonPress); - XISetMask(mask_buf, XI_ButtonRelease); - XISetMask(mask_buf, XI_RawMotion); - XISetMask(mask_buf, XI_KeyPress); - XISetMask(mask_buf, XI_KeyRelease); + XISetMask(mask_buf, XI_ButtonPress); + XISetMask(mask_buf, XI_ButtonRelease); + XISetMask(mask_buf, XI_RawMotion); + XISetMask(mask_buf, XI_KeyPress); + XISetMask(mask_buf, XI_KeyRelease); - SelectEventsForDevice(DefaultRootWindow(m_display), &mask, pointer_deviceid); - SelectEventsForDevice(DefaultRootWindow(m_display), &mask, keyboard_deviceid); + SelectEventsForDevice(DefaultRootWindow(m_display), &mask, pointer_deviceid); + SelectEventsForDevice(DefaultRootWindow(m_display), &mask, keyboard_deviceid); - // Keyboard Keys - for (int i = min_keycode; i <= max_keycode; ++i) - { - Key* temp_key = new Key(m_display, i, m_state.keyboard); - if (temp_key->m_keyname.length()) - AddInput(temp_key); - else - delete temp_key; - } + // Keyboard Keys + for (int i = min_keycode; i <= max_keycode; ++i) + { + Key* temp_key = new Key(m_display, i, m_state.keyboard); + if (temp_key->m_keyname.length()) + AddInput(temp_key); + else + delete temp_key; + } - // Mouse Buttons - for (int i = 0; i < 5; i++) - AddInput(new Button(i, &m_state.buttons)); + // Mouse Buttons + for (int i = 0; i < 5; i++) + AddInput(new Button(i, &m_state.buttons)); - // Mouse Cursor, X-/+ and Y-/+ - for (int i = 0; i != 4; ++i) - AddInput(new Cursor(!!(i & 2), !!(i & 1), (i & 2) ? &m_state.cursor.y : &m_state.cursor.x)); + // Mouse Cursor, X-/+ and Y-/+ + for (int i = 0; i != 4; ++i) + AddInput(new Cursor(!!(i & 2), !!(i & 1), (i & 2) ? &m_state.cursor.y : &m_state.cursor.x)); - // Mouse Axis, X-/+ and Y-/+ - for (int i = 0; i != 4; ++i) - AddInput(new Axis(!!(i & 2), !!(i & 1), (i & 2) ? &m_state.axis.y : &m_state.axis.x)); + // Mouse Axis, X-/+ and Y-/+ + for (int i = 0; i != 4; ++i) + AddInput(new Axis(!!(i & 2), !!(i & 1), (i & 2) ? &m_state.axis.y : &m_state.axis.x)); } KeyboardMouse::~KeyboardMouse() { - XCloseDisplay(m_display); + XCloseDisplay(m_display); } // Update the mouse cursor controls void KeyboardMouse::UpdateCursor() { - double root_x, root_y, win_x, win_y; - Window root, child; + double root_x, root_y, win_x, win_y; + Window root, child; - // unused-- we're not interested in button presses here, as those are - // updated using events - XIButtonState button_state; - XIModifierState mods; - XIGroupState group; + // unused-- we're not interested in button presses here, as those are + // updated using events + XIButtonState button_state; + XIModifierState mods; + XIGroupState group; - XIQueryPointer(m_display, pointer_deviceid, m_window, &root, &child, &root_x, &root_y, &win_x, &win_y, &button_state, &mods, &group); + XIQueryPointer(m_display, pointer_deviceid, m_window, &root, &child, &root_x, &root_y, &win_x, + &win_y, &button_state, &mods, &group); - free (button_state.mask); + free(button_state.mask); - XWindowAttributes win_attribs; - XGetWindowAttributes(m_display, m_window, &win_attribs); + XWindowAttributes win_attribs; + XGetWindowAttributes(m_display, m_window, &win_attribs); - // the mouse position as a range from -1 to 1 - m_state.cursor.x = win_x / (float)win_attribs.width * 2 - 1; - m_state.cursor.y = win_y / (float)win_attribs.height * 2 - 1; + // the mouse position as a range from -1 to 1 + m_state.cursor.x = win_x / (float)win_attribs.width * 2 - 1; + m_state.cursor.y = win_y / (float)win_attribs.height * 2 - 1; } void KeyboardMouse::UpdateInput() { - XFlush(m_display); + XFlush(m_display); - // Get the absolute position of the mouse pointer - UpdateCursor(); + // Get the absolute position of the mouse pointer + UpdateCursor(); - // for the axis controls - float delta_x = 0.0f, delta_y = 0.0f; - double delta_delta; + // for the axis controls + float delta_x = 0.0f, delta_y = 0.0f; + double delta_delta; - // Iterate through the event queue - update the axis controls, mouse - // button controls, and keyboard controls. - XEvent event; - while (XPending(m_display)) - { - XNextEvent(m_display, &event); + // Iterate through the event queue - update the axis controls, mouse + // button controls, and keyboard controls. + XEvent event; + while (XPending(m_display)) + { + XNextEvent(m_display, &event); - if (event.xcookie.type != GenericEvent) - continue; - if (event.xcookie.extension != xi_opcode) - continue; - if (!XGetEventData(m_display, &event.xcookie)) - continue; + if (event.xcookie.type != GenericEvent) + continue; + if (event.xcookie.extension != xi_opcode) + continue; + if (!XGetEventData(m_display, &event.xcookie)) + continue; - // only one of these will get used - XIDeviceEvent* dev_event = (XIDeviceEvent*)event.xcookie.data; - XIRawEvent* raw_event = (XIRawEvent*)event.xcookie.data; + // only one of these will get used + XIDeviceEvent* dev_event = (XIDeviceEvent*)event.xcookie.data; + XIRawEvent* raw_event = (XIRawEvent*)event.xcookie.data; - switch (event.xcookie.evtype) - { - case XI_ButtonPress: - m_state.buttons |= 1<<(dev_event->detail-1); - break; - case XI_ButtonRelease: - m_state.buttons &= ~(1<<(dev_event->detail-1)); - break; - case XI_KeyPress: - m_state.keyboard[dev_event->detail / 8] |= 1<<(dev_event->detail % 8); - break; - case XI_KeyRelease: - m_state.keyboard[dev_event->detail / 8] &= ~(1<<(dev_event->detail % 8)); - break; - case XI_RawMotion: - // always safe because there is always at least one byte in - // raw_event->valuators.mask, and if a bit is set in the mask, - // then the value in raw_values is also available. - if (XIMaskIsSet(raw_event->valuators.mask, 0)) - { - delta_delta = raw_event->raw_values[0]; - // test for inf and nan - if (delta_delta == delta_delta && 1+delta_delta != delta_delta) - delta_x += delta_delta; - } - if (XIMaskIsSet(raw_event->valuators.mask, 1)) - { - delta_delta = raw_event->raw_values[1]; - // test for inf and nan - if (delta_delta == delta_delta && 1+delta_delta != delta_delta) - delta_y += delta_delta; - } - break; - } + switch (event.xcookie.evtype) + { + case XI_ButtonPress: + m_state.buttons |= 1 << (dev_event->detail - 1); + break; + case XI_ButtonRelease: + m_state.buttons &= ~(1 << (dev_event->detail - 1)); + break; + case XI_KeyPress: + m_state.keyboard[dev_event->detail / 8] |= 1 << (dev_event->detail % 8); + break; + case XI_KeyRelease: + m_state.keyboard[dev_event->detail / 8] &= ~(1 << (dev_event->detail % 8)); + break; + case XI_RawMotion: + // always safe because there is always at least one byte in + // raw_event->valuators.mask, and if a bit is set in the mask, + // then the value in raw_values is also available. + if (XIMaskIsSet(raw_event->valuators.mask, 0)) + { + delta_delta = raw_event->raw_values[0]; + // test for inf and nan + if (delta_delta == delta_delta && 1 + delta_delta != delta_delta) + delta_x += delta_delta; + } + if (XIMaskIsSet(raw_event->valuators.mask, 1)) + { + delta_delta = raw_event->raw_values[1]; + // test for inf and nan + if (delta_delta == delta_delta && 1 + delta_delta != delta_delta) + delta_y += delta_delta; + } + break; + } - XFreeEventData(m_display, &event.xcookie); - } + XFreeEventData(m_display, &event.xcookie); + } - // apply axis smoothing - m_state.axis.x *= MOUSE_AXIS_SMOOTHING; - m_state.axis.x += delta_x; - m_state.axis.x /= MOUSE_AXIS_SMOOTHING+1.0f; - m_state.axis.y *= MOUSE_AXIS_SMOOTHING; - m_state.axis.y += delta_y; - m_state.axis.y /= MOUSE_AXIS_SMOOTHING+1.0f; + // apply axis smoothing + m_state.axis.x *= MOUSE_AXIS_SMOOTHING; + m_state.axis.x += delta_x; + m_state.axis.x /= MOUSE_AXIS_SMOOTHING + 1.0f; + m_state.axis.y *= MOUSE_AXIS_SMOOTHING; + m_state.axis.y += delta_y; + m_state.axis.y /= MOUSE_AXIS_SMOOTHING + 1.0f; } std::string KeyboardMouse::GetName() const { - // This is the name string we got from the X server for this master - // pointer/keyboard pair. - return name; + // This is the name string we got from the X server for this master + // pointer/keyboard pair. + return name; } std::string KeyboardMouse::GetSource() const { - return "XInput2"; + return "XInput2"; } int KeyboardMouse::GetId() const { - return -1; + return -1; } KeyboardMouse::Key::Key(Display* const display, KeyCode keycode, const char* keyboard) - : m_display(display), m_keyboard(keyboard), m_keycode(keycode) + : m_display(display), m_keyboard(keyboard), m_keycode(keycode) { - int i = 0; - KeySym keysym = 0; - do - { - keysym = XkbKeycodeToKeysym(m_display, keycode, i, 0); - i++; - } - while (keysym == NoSymbol && i < 8); + int i = 0; + KeySym keysym = 0; + do + { + keysym = XkbKeycodeToKeysym(m_display, keycode, i, 0); + i++; + } while (keysym == NoSymbol && i < 8); - // Convert to upper case for the keyname - if (keysym >= 97 && keysym <= 122) - keysym -= 32; + // Convert to upper case for the keyname + if (keysym >= 97 && keysym <= 122) + keysym -= 32; - // 0x0110ffff is the top of the unicode character range according - // to keysymdef.h although it is probably more than we need. - if (keysym == NoSymbol || keysym > 0x0110ffff || - XKeysymToString(keysym) == nullptr) - m_keyname = std::string(); - else - m_keyname = std::string(XKeysymToString(keysym)); + // 0x0110ffff is the top of the unicode character range according + // to keysymdef.h although it is probably more than we need. + if (keysym == NoSymbol || keysym > 0x0110ffff || XKeysymToString(keysym) == nullptr) + m_keyname = std::string(); + else + m_keyname = std::string(XKeysymToString(keysym)); } ControlState KeyboardMouse::Key::GetState() const { - return (m_keyboard[m_keycode / 8] & (1 << (m_keycode % 8))) != 0; + return (m_keyboard[m_keycode / 8] & (1 << (m_keycode % 8))) != 0; } KeyboardMouse::Button::Button(unsigned int index, unsigned int* buttons) - : m_buttons(buttons), m_index(index) + : m_buttons(buttons), m_index(index) { - // this will be a problem if we remove the hardcoded five-button limit - name = std::string("Click ") + (char)('1' + m_index); + // this will be a problem if we remove the hardcoded five-button limit + name = std::string("Click ") + (char)('1' + m_index); } ControlState KeyboardMouse::Button::GetState() const { - return ((*m_buttons & (1 << m_index)) != 0); + return ((*m_buttons & (1 << m_index)) != 0); } KeyboardMouse::Cursor::Cursor(u8 index, bool positive, const float* cursor) - : m_cursor(cursor), m_index(index), m_positive(positive) + : m_cursor(cursor), m_index(index), m_positive(positive) { - name = std::string("Cursor ") + (char)('X' + m_index) + (m_positive ? '+' : '-'); + name = std::string("Cursor ") + (char)('X' + m_index) + (m_positive ? '+' : '-'); } ControlState KeyboardMouse::Cursor::GetState() const { - return std::max(0.0f, *m_cursor / (m_positive ? 1.0f : -1.0f)); + return std::max(0.0f, *m_cursor / (m_positive ? 1.0f : -1.0f)); } KeyboardMouse::Axis::Axis(u8 index, bool positive, const float* axis) - : m_axis(axis), m_index(index), m_positive(positive) + : m_axis(axis), m_index(index), m_positive(positive) { - name = std::string("Axis ") + (char)('X' + m_index) + (m_positive ? '+' : '-'); + name = std::string("Axis ") + (char)('X' + m_index) + (m_positive ? '+' : '-'); } ControlState KeyboardMouse::Axis::GetState() const { - return std::max(0.0f, *m_axis / (m_positive ? MOUSE_AXIS_SENSITIVITY : -MOUSE_AXIS_SENSITIVITY)); -} - + return std::max(0.0f, *m_axis / (m_positive ? MOUSE_AXIS_SENSITIVITY : -MOUSE_AXIS_SENSITIVITY)); +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.h b/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.h index 09a59706e3..e8f2e2e06b 100644 --- a/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.h +++ b/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.h @@ -7,9 +7,9 @@ #pragma once extern "C" { -#include #include #include +#include } #include "InputCommon/ControllerInterface/Device.h" @@ -18,103 +18,101 @@ namespace ciface { namespace XInput2 { - void Init(std::vector& devices, void* const hwnd); class KeyboardMouse : public Core::Device { +private: + struct State + { + char keyboard[32]; + unsigned int buttons; + struct + { + float x, y; + } cursor, axis; + }; + + class Key : public Input + { + friend class KeyboardMouse; + + public: + std::string GetName() const override { return m_keyname; } + Key(Display* display, KeyCode keycode, const char* keyboard); + ControlState GetState() const override; + + private: + std::string m_keyname; + Display* const m_display; + const char* const m_keyboard; + const KeyCode m_keycode; + }; + + class Button : public Input + { + public: + std::string GetName() const override { return name; } + Button(unsigned int index, unsigned int* buttons); + ControlState GetState() const override; + + private: + const unsigned int* m_buttons; + const unsigned int m_index; + std::string name; + }; + + class Cursor : public Input + { + public: + std::string GetName() const override { return name; } + bool IsDetectable() override { return false; } + Cursor(u8 index, bool positive, const float* cursor); + ControlState GetState() const override; + + private: + const float* m_cursor; + const u8 m_index; + const bool m_positive; + std::string name; + }; + + class Axis : public Input + { + public: + std::string GetName() const override { return name; } + bool IsDetectable() override { return false; } + Axis(u8 index, bool positive, const float* axis); + ControlState GetState() const override; + + private: + const float* m_axis; + const u8 m_index; + const bool m_positive; + std::string name; + }; private: - struct State - { - char keyboard[32]; - unsigned int buttons; - struct - { - float x, y; - } cursor, axis; - }; - - class Key : public Input - { - friend class KeyboardMouse; - public: - std::string GetName() const override { return m_keyname; } - Key(Display* display, KeyCode keycode, const char* keyboard); - ControlState GetState() const override; - - private: - std::string m_keyname; - Display* const m_display; - const char* const m_keyboard; - const KeyCode m_keycode; - }; - - class Button : public Input - { - public: - std::string GetName() const override { return name; } - Button(unsigned int index, unsigned int* buttons); - ControlState GetState() const override; - - private: - const unsigned int* m_buttons; - const unsigned int m_index; - std::string name; - }; - - class Cursor : public Input - { - public: - std::string GetName() const override { return name; } - bool IsDetectable() override { return false; } - Cursor(u8 index, bool positive, const float* cursor); - ControlState GetState() const override; - - private: - const float* m_cursor; - const u8 m_index; - const bool m_positive; - std::string name; - }; - - class Axis : public Input - { - public: - std::string GetName() const override { return name; } - bool IsDetectable() override { return false; } - Axis(u8 index, bool positive, const float* axis); - ControlState GetState() const override; - - private: - const float* m_axis; - const u8 m_index; - const bool m_positive; - std::string name; - }; - -private: - void SelectEventsForDevice(Window window, XIEventMask *mask, int deviceid); - void UpdateCursor(); + void SelectEventsForDevice(Window window, XIEventMask* mask, int deviceid); + void UpdateCursor(); public: - void UpdateInput() override; + void UpdateInput() override; - KeyboardMouse(Window window, int opcode, int pointer_deviceid, int keyboard_deviceid); - ~KeyboardMouse(); + KeyboardMouse(Window window, int opcode, int pointer_deviceid, int keyboard_deviceid); + ~KeyboardMouse(); - std::string GetName() const override; - std::string GetSource() const override; - int GetId() const override; + std::string GetName() const override; + std::string GetSource() const override; + int GetId() const override; private: - Window m_window; - Display* m_display; - State m_state; - int xi_opcode; - const int pointer_deviceid, keyboard_deviceid; - std::string name; + Window m_window; + Display* m_display; + State m_state; + int xi_opcode; + const int pointer_deviceid, keyboard_deviceid; + std::string name; }; - } } diff --git a/Source/Core/InputCommon/ControllerInterface/Xlib/Xlib.cpp b/Source/Core/InputCommon/ControllerInterface/Xlib/Xlib.cpp index e198f1112d..71269c74f7 100644 --- a/Source/Core/InputCommon/ControllerInterface/Xlib/Xlib.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Xlib/Xlib.cpp @@ -2,8 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include #include +#include #include "InputCommon/ControllerInterface/Xlib/Xlib.h" @@ -11,149 +11,156 @@ namespace ciface { namespace Xlib { - void Init(std::vector& devices, void* const hwnd) { - devices.push_back(new KeyboardMouse((Window)hwnd)); + devices.push_back(new KeyboardMouse((Window)hwnd)); } KeyboardMouse::KeyboardMouse(Window window) : m_window(window) { - memset(&m_state, 0, sizeof(m_state)); + memset(&m_state, 0, sizeof(m_state)); - m_display = XOpenDisplay(nullptr); + m_display = XOpenDisplay(nullptr); - int min_keycode, max_keycode; - XDisplayKeycodes(m_display, &min_keycode, &max_keycode); + int min_keycode, max_keycode; + XDisplayKeycodes(m_display, &min_keycode, &max_keycode); - // Keyboard Keys - for (int i = min_keycode; i <= max_keycode; ++i) - { - Key *temp_key = new Key(m_display, i, m_state.keyboard); - if (temp_key->m_keyname.length()) - AddInput(temp_key); - else - delete temp_key; - } + // Keyboard Keys + for (int i = min_keycode; i <= max_keycode; ++i) + { + Key* temp_key = new Key(m_display, i, m_state.keyboard); + if (temp_key->m_keyname.length()) + AddInput(temp_key); + else + delete temp_key; + } - // Mouse Buttons - AddInput(new Button(Button1Mask, m_state.buttons)); - AddInput(new Button(Button2Mask, m_state.buttons)); - AddInput(new Button(Button3Mask, m_state.buttons)); - AddInput(new Button(Button4Mask, m_state.buttons)); - AddInput(new Button(Button5Mask, m_state.buttons)); + // Mouse Buttons + AddInput(new Button(Button1Mask, m_state.buttons)); + AddInput(new Button(Button2Mask, m_state.buttons)); + AddInput(new Button(Button3Mask, m_state.buttons)); + AddInput(new Button(Button4Mask, m_state.buttons)); + AddInput(new Button(Button5Mask, m_state.buttons)); - // Mouse Cursor, X-/+ and Y-/+ - for (int i = 0; i != 4; ++i) - AddInput(new Cursor(!!(i & 2), !!(i & 1), (&m_state.cursor.x)[!!(i & 2)])); + // Mouse Cursor, X-/+ and Y-/+ + for (int i = 0; i != 4; ++i) + AddInput(new Cursor(!!(i & 2), !!(i & 1), (&m_state.cursor.x)[!!(i & 2)])); } KeyboardMouse::~KeyboardMouse() { - XCloseDisplay(m_display); + XCloseDisplay(m_display); } void KeyboardMouse::UpdateInput() { - XQueryKeymap(m_display, m_state.keyboard); + XQueryKeymap(m_display, m_state.keyboard); - int root_x, root_y, win_x, win_y; - Window root, child; - XQueryPointer(m_display, m_window, &root, &child, &root_x, &root_y, &win_x, &win_y, &m_state.buttons); + int root_x, root_y, win_x, win_y; + Window root, child; + XQueryPointer(m_display, m_window, &root, &child, &root_x, &root_y, &win_x, &win_y, + &m_state.buttons); - // update mouse cursor - XWindowAttributes win_attribs; - XGetWindowAttributes(m_display, m_window, &win_attribs); + // update mouse cursor + XWindowAttributes win_attribs; + XGetWindowAttributes(m_display, m_window, &win_attribs); - // the mouse position as a range from -1 to 1 - m_state.cursor.x = (float)win_x / (float)win_attribs.width * 2 - 1; - m_state.cursor.y = (float)win_y / (float)win_attribs.height * 2 - 1; + // the mouse position as a range from -1 to 1 + m_state.cursor.x = (float)win_x / (float)win_attribs.width * 2 - 1; + m_state.cursor.y = (float)win_y / (float)win_attribs.height * 2 - 1; } std::string KeyboardMouse::GetName() const { - return "Keyboard Mouse"; + return "Keyboard Mouse"; } std::string KeyboardMouse::GetSource() const { - return "Xlib"; + return "Xlib"; } int KeyboardMouse::GetId() const { - return 0; + return 0; } KeyboardMouse::Key::Key(Display* const display, KeyCode keycode, const char* keyboard) - : m_display(display), m_keyboard(keyboard), m_keycode(keycode) + : m_display(display), m_keyboard(keyboard), m_keycode(keycode) { - int i = 0; - KeySym keysym = 0; - do - { - keysym = XkbKeycodeToKeysym(m_display, keycode, i, 0); - i++; - } - while (keysym == NoSymbol && i < 8); + int i = 0; + KeySym keysym = 0; + do + { + keysym = XkbKeycodeToKeysym(m_display, keycode, i, 0); + i++; + } while (keysym == NoSymbol && i < 8); - // Convert to upper case for the keyname - if (keysym >= 97 && keysym <= 122) - keysym -= 32; + // Convert to upper case for the keyname + if (keysym >= 97 && keysym <= 122) + keysym -= 32; - // 0x0110ffff is the top of the unicode character range according - // to keysymdef.h although it is probably more than we need. - if (keysym == NoSymbol || keysym > 0x0110ffff || - XKeysymToString(keysym) == nullptr) - m_keyname = std::string(); - else - m_keyname = std::string(XKeysymToString(keysym)); + // 0x0110ffff is the top of the unicode character range according + // to keysymdef.h although it is probably more than we need. + if (keysym == NoSymbol || keysym > 0x0110ffff || XKeysymToString(keysym) == nullptr) + m_keyname = std::string(); + else + m_keyname = std::string(XKeysymToString(keysym)); } ControlState KeyboardMouse::Key::GetState() const { - return (m_keyboard[m_keycode / 8] & (1 << (m_keycode % 8))) != 0; + return (m_keyboard[m_keycode / 8] & (1 << (m_keycode % 8))) != 0; } ControlState KeyboardMouse::Button::GetState() const { - return ((m_buttons & m_index) != 0); + return ((m_buttons & m_index) != 0); } ControlState KeyboardMouse::Cursor::GetState() const { - return std::max(0.0f, m_cursor / (m_positive ? 1.0f : -1.0f)); + return std::max(0.0f, m_cursor / (m_positive ? 1.0f : -1.0f)); } std::string KeyboardMouse::Key::GetName() const { - return m_keyname; + return m_keyname; } std::string KeyboardMouse::Cursor::GetName() const { - static char tmpstr[] = "Cursor .."; - tmpstr[7] = (char)('X' + m_index); - tmpstr[8] = (m_positive ? '+' : '-'); - return tmpstr; + static char tmpstr[] = "Cursor .."; + tmpstr[7] = (char)('X' + m_index); + tmpstr[8] = (m_positive ? '+' : '-'); + return tmpstr; } std::string KeyboardMouse::Button::GetName() const { - char button = '0'; - switch (m_index) - { - case Button1Mask: button = '1'; break; - case Button2Mask: button = '2'; break; - case Button3Mask: button = '3'; break; - case Button4Mask: button = '4'; break; - case Button5Mask: button = '5'; break; - } - - static char tmpstr[] = "Click ."; - tmpstr[6] = button; - return tmpstr; -} + char button = '0'; + switch (m_index) + { + case Button1Mask: + button = '1'; + break; + case Button2Mask: + button = '2'; + break; + case Button3Mask: + button = '3'; + break; + case Button4Mask: + button = '4'; + break; + case Button5Mask: + button = '5'; + break; + } + static char tmpstr[] = "Click ."; + tmpstr[6] = button; + return tmpstr; +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/Xlib/Xlib.h b/Source/Core/InputCommon/ControllerInterface/Xlib/Xlib.h index 6fe72e4da7..94388211c0 100644 --- a/Source/Core/InputCommon/ControllerInterface/Xlib/Xlib.h +++ b/Source/Core/InputCommon/ControllerInterface/Xlib/Xlib.h @@ -4,8 +4,8 @@ #pragma once -#include #include +#include #include "InputCommon/ControllerInterface/Device.h" @@ -13,81 +13,80 @@ namespace ciface { namespace Xlib { - void Init(std::vector& devices, void* const hwnd); class KeyboardMouse : public Core::Device { - private: - struct State - { - char keyboard[32]; - unsigned int buttons; - struct - { - float x, y; - } cursor; - }; + struct State + { + char keyboard[32]; + unsigned int buttons; + struct + { + float x, y; + } cursor; + }; - class Key : public Input - { - friend class KeyboardMouse; - public: - std::string GetName() const override; - Key(Display* display, KeyCode keycode, const char* keyboard); - ControlState GetState() const override; + class Key : public Input + { + friend class KeyboardMouse; - private: - std::string m_keyname; - Display* const m_display; - const char* const m_keyboard; - const KeyCode m_keycode; - }; + public: + std::string GetName() const override; + Key(Display* display, KeyCode keycode, const char* keyboard); + ControlState GetState() const override; - class Button : public Input - { - public: - std::string GetName() const override; - Button(unsigned int index, unsigned int& buttons) - : m_buttons(buttons), m_index(index) {} - ControlState GetState() const override; + private: + std::string m_keyname; + Display* const m_display; + const char* const m_keyboard; + const KeyCode m_keycode; + }; - private: - const unsigned int& m_buttons; - const unsigned int m_index; - }; + class Button : public Input + { + public: + std::string GetName() const override; + Button(unsigned int index, unsigned int& buttons) : m_buttons(buttons), m_index(index) {} + ControlState GetState() const override; - class Cursor : public Input - { - public: - std::string GetName() const override; - bool IsDetectable() override { return false; } - Cursor(u8 index, bool positive, const float& cursor) - : m_cursor(cursor), m_index(index), m_positive(positive) {} - ControlState GetState() const override; + private: + const unsigned int& m_buttons; + const unsigned int m_index; + }; - private: - const float& m_cursor; - const u8 m_index; - const bool m_positive; - }; + class Cursor : public Input + { + public: + std::string GetName() const override; + bool IsDetectable() override { return false; } + Cursor(u8 index, bool positive, const float& cursor) + : m_cursor(cursor), m_index(index), m_positive(positive) + { + } + ControlState GetState() const override; + + private: + const float& m_cursor; + const u8 m_index; + const bool m_positive; + }; public: - void UpdateInput() override; + void UpdateInput() override; - KeyboardMouse(Window window); - ~KeyboardMouse(); + KeyboardMouse(Window window); + ~KeyboardMouse(); - std::string GetName() const override; - std::string GetSource() const override; - int GetId() const override; + std::string GetName() const override; + std::string GetSource() const override; + int GetId() const override; private: - Window m_window; - Display* m_display; - State m_state; + Window m_window; + Display* m_display; + State m_state; }; - } } diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp index d88a44b7ef..7a6ba50713 100644 --- a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp +++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp @@ -11,295 +11,291 @@ #include "Common/Logging/Log.h" #include "InputCommon/ControllerInterface/evdev/evdev.h" - namespace ciface { namespace evdev { - static std::string GetName(const std::string& devnode) { - int fd = open(devnode.c_str(), O_RDWR|O_NONBLOCK); - libevdev* dev = nullptr; - int ret = libevdev_new_from_fd(fd, &dev); - if (ret != 0) - { - close(fd); - return std::string(); - } - std::string res = libevdev_get_name(dev); - libevdev_free(dev); - close(fd); - return res; + int fd = open(devnode.c_str(), O_RDWR | O_NONBLOCK); + libevdev* dev = nullptr; + int ret = libevdev_new_from_fd(fd, &dev); + if (ret != 0) + { + close(fd); + return std::string(); + } + std::string res = libevdev_get_name(dev); + libevdev_free(dev); + close(fd); + return res; } -void Init(std::vector &controllerDevices) +void Init(std::vector& controllerDevices) { - // this is used to number the joysticks - // multiple joysticks with the same name shall get unique ids starting at 0 - std::map name_counts; + // this is used to number the joysticks + // multiple joysticks with the same name shall get unique ids starting at 0 + std::map name_counts; - int num_controllers = 0; + int num_controllers = 0; - // We use Udev to find any devices. In the future this will allow for hotplugging. - // But for now it is essentially iterating over /dev/input/event0 to event31. However if the - // naming scheme is ever updated in the future, this *should* be forwards compatable. + // We use Udev to find any devices. In the future this will allow for hotplugging. + // But for now it is essentially iterating over /dev/input/event0 to event31. However if the + // naming scheme is ever updated in the future, this *should* be forwards compatable. - struct udev* udev = udev_new(); - _assert_msg_(PAD, udev != 0, "Couldn't initilize libudev."); + struct udev* udev = udev_new(); + _assert_msg_(PAD, udev != 0, "Couldn't initilize libudev."); - // List all input devices - udev_enumerate* enumerate = udev_enumerate_new(udev); - udev_enumerate_add_match_subsystem(enumerate, "input"); - udev_enumerate_scan_devices(enumerate); - udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate); + // List all input devices + udev_enumerate* enumerate = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(enumerate, "input"); + udev_enumerate_scan_devices(enumerate); + udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate); - // Iterate over all input devices - udev_list_entry* dev_list_entry; - udev_list_entry_foreach(dev_list_entry, devices) - { - const char* path = udev_list_entry_get_name(dev_list_entry); + // Iterate over all input devices + udev_list_entry* dev_list_entry; + udev_list_entry_foreach(dev_list_entry, devices) + { + const char* path = udev_list_entry_get_name(dev_list_entry); - udev_device* dev = udev_device_new_from_syspath(udev, path); + udev_device* dev = udev_device_new_from_syspath(udev, path); - const char* devnode = udev_device_get_devnode(dev); - // We only care about devices which we have read/write access to. - if (devnode && access(devnode, W_OK) == 0) - { - // Unfortunately udev gives us no way to filter out the non event device interfaces. - // So we open it and see if it works with evdev ioctls or not. - std::string name = GetName(devnode); - evdevDevice* input = new evdevDevice(devnode, name_counts[name]++); + const char* devnode = udev_device_get_devnode(dev); + // We only care about devices which we have read/write access to. + if (devnode && access(devnode, W_OK) == 0) + { + // Unfortunately udev gives us no way to filter out the non event device interfaces. + // So we open it and see if it works with evdev ioctls or not. + std::string name = GetName(devnode); + evdevDevice* input = new evdevDevice(devnode, name_counts[name]++); - if (input->IsInteresting()) - { - controllerDevices.push_back(input); - num_controllers++; - } - else - { - // Either it wasn't a evdev device, or it didn't have at least 8 buttons or two axis. - delete input; - } - } - udev_device_unref(dev); - } - udev_enumerate_unref(enumerate); - udev_unref(udev); + if (input->IsInteresting()) + { + controllerDevices.push_back(input); + num_controllers++; + } + else + { + // Either it wasn't a evdev device, or it didn't have at least 8 buttons or two axis. + delete input; + } + } + udev_device_unref(dev); + } + udev_enumerate_unref(enumerate); + udev_unref(udev); } -evdevDevice::evdevDevice(const std::string &devnode, int id) : m_devfile(devnode), m_id(id) +evdevDevice::evdevDevice(const std::string& devnode, int id) : m_devfile(devnode), m_id(id) { - // The device file will be read on one of the main threads, so we open in non-blocking mode. - m_fd = open(devnode.c_str(), O_RDWR|O_NONBLOCK); - int ret = libevdev_new_from_fd(m_fd, &m_dev); + // The device file will be read on one of the main threads, so we open in non-blocking mode. + m_fd = open(devnode.c_str(), O_RDWR | O_NONBLOCK); + int ret = libevdev_new_from_fd(m_fd, &m_dev); - if (ret != 0) - { - // This useally fails because the device node isn't an evdev device, such as /dev/input/js0 - m_initialized = false; - close(m_fd); - return; - } + if (ret != 0) + { + // This useally fails because the device node isn't an evdev device, such as /dev/input/js0 + m_initialized = false; + close(m_fd); + return; + } - m_name = libevdev_get_name(m_dev); + m_name = libevdev_get_name(m_dev); - // Controller buttons (and keyboard keys) - int num_buttons = 0; - for (int key = 0; key < KEY_MAX; key++) - if (libevdev_has_event_code(m_dev, EV_KEY, key)) - AddInput(new Button(num_buttons++, key, m_dev)); + // Controller buttons (and keyboard keys) + int num_buttons = 0; + for (int key = 0; key < KEY_MAX; key++) + if (libevdev_has_event_code(m_dev, EV_KEY, key)) + AddInput(new Button(num_buttons++, key, m_dev)); - // Absolute axis (thumbsticks) - int num_axis = 0; - for (int axis = 0; axis < 0x100; axis++) - if (libevdev_has_event_code(m_dev, EV_ABS, axis)) - { - AddAnalogInputs(new Axis(num_axis, axis, false, m_dev), - new Axis(num_axis, axis, true, m_dev)); - num_axis++; - } + // Absolute axis (thumbsticks) + int num_axis = 0; + for (int axis = 0; axis < 0x100; axis++) + if (libevdev_has_event_code(m_dev, EV_ABS, axis)) + { + AddAnalogInputs(new Axis(num_axis, axis, false, m_dev), + new Axis(num_axis, axis, true, m_dev)); + num_axis++; + } - // Force feedback - if (libevdev_has_event_code(m_dev, EV_FF, FF_PERIODIC)) - { - for (auto type : {FF_SINE, FF_SQUARE, FF_TRIANGLE, FF_SAW_UP, FF_SAW_DOWN}) - if (libevdev_has_event_code(m_dev, EV_FF, type)) - AddOutput(new ForceFeedback(type, m_dev)); - } - if (libevdev_has_event_code(m_dev, EV_FF, FF_RUMBLE)) - { - AddOutput(new ForceFeedback(FF_RUMBLE, m_dev)); - } + // Force feedback + if (libevdev_has_event_code(m_dev, EV_FF, FF_PERIODIC)) + { + for (auto type : {FF_SINE, FF_SQUARE, FF_TRIANGLE, FF_SAW_UP, FF_SAW_DOWN}) + if (libevdev_has_event_code(m_dev, EV_FF, type)) + AddOutput(new ForceFeedback(type, m_dev)); + } + if (libevdev_has_event_code(m_dev, EV_FF, FF_RUMBLE)) + { + AddOutput(new ForceFeedback(FF_RUMBLE, m_dev)); + } - // TODO: Add leds as output devices + // TODO: Add leds as output devices - m_initialized = true; - m_interesting = num_axis >= 2 || num_buttons >= 8; + m_initialized = true; + m_interesting = num_axis >= 2 || num_buttons >= 8; } evdevDevice::~evdevDevice() { - if (m_initialized) - { - libevdev_free(m_dev); - close(m_fd); - } + if (m_initialized) + { + libevdev_free(m_dev); + close(m_fd); + } } void evdevDevice::UpdateInput() { - // Run through all evdev events - // libevdev will keep track of the actual controller state internally which can be queried - // later with libevdev_fetch_event_value() - input_event ev; - int rc = LIBEVDEV_READ_STATUS_SUCCESS; - do - { - if (rc == LIBEVDEV_READ_STATUS_SYNC) - rc = libevdev_next_event(m_dev, LIBEVDEV_READ_FLAG_SYNC, &ev); - else - rc = libevdev_next_event(m_dev, LIBEVDEV_READ_FLAG_NORMAL, &ev); - } while (rc >= 0); + // Run through all evdev events + // libevdev will keep track of the actual controller state internally which can be queried + // later with libevdev_fetch_event_value() + input_event ev; + int rc = LIBEVDEV_READ_STATUS_SUCCESS; + do + { + if (rc == LIBEVDEV_READ_STATUS_SYNC) + rc = libevdev_next_event(m_dev, LIBEVDEV_READ_FLAG_SYNC, &ev); + else + rc = libevdev_next_event(m_dev, LIBEVDEV_READ_FLAG_NORMAL, &ev); + } while (rc >= 0); } - std::string evdevDevice::Button::GetName() const { - // Buttons below 0x100 are mostly keyboard keys, and the names make sense - if (m_code < 0x100) - { - const char* name = libevdev_event_code_get_name(EV_KEY, m_code); - if (name) - return std::string(name); - } - // But controllers use codes above 0x100, and the standard label often doesn't match. - // We are better off with Button 0 and so on. - return "Button " + std::to_string(m_index); + // Buttons below 0x100 are mostly keyboard keys, and the names make sense + if (m_code < 0x100) + { + const char* name = libevdev_event_code_get_name(EV_KEY, m_code); + if (name) + return std::string(name); + } + // But controllers use codes above 0x100, and the standard label often doesn't match. + // We are better off with Button 0 and so on. + return "Button " + std::to_string(m_index); } ControlState evdevDevice::Button::GetState() const { - int value = 0; - libevdev_fetch_event_value(m_dev, EV_KEY, m_code, &value); - return value; + int value = 0; + libevdev_fetch_event_value(m_dev, EV_KEY, m_code, &value); + return value; } -evdevDevice::Axis::Axis(u8 index, u16 code, bool upper, libevdev* dev) : - m_code(code), m_index(index), m_upper(upper), m_dev(dev) +evdevDevice::Axis::Axis(u8 index, u16 code, bool upper, libevdev* dev) + : m_code(code), m_index(index), m_upper(upper), m_dev(dev) { - m_min = libevdev_get_abs_minimum(m_dev, m_code); - m_range = libevdev_get_abs_maximum(m_dev, m_code) + abs(m_min); + m_min = libevdev_get_abs_minimum(m_dev, m_code); + m_range = libevdev_get_abs_maximum(m_dev, m_code) + abs(m_min); } std::string evdevDevice::Axis::GetName() const { - return "Axis " + std::to_string(m_index) + (m_upper ? "+" : "-"); + return "Axis " + std::to_string(m_index) + (m_upper ? "+" : "-"); } ControlState evdevDevice::Axis::GetState() const { - int value = 0; - libevdev_fetch_event_value(m_dev, EV_ABS, m_code, &value); + int value = 0; + libevdev_fetch_event_value(m_dev, EV_ABS, m_code, &value); - // Value from 0.0 to 1.0 - ControlState fvalue = double(value - m_min) / double(m_range); + // Value from 0.0 to 1.0 + ControlState fvalue = double(value - m_min) / double(m_range); - // Split into two axis, each covering half the range from 0.0 to 1.0 - if (m_upper) - return std::max(0.0, fvalue - 0.5) * 2.0; - else - return (0.5 - std::min(0.5, fvalue)) * 2.0; + // Split into two axis, each covering half the range from 0.0 to 1.0 + if (m_upper) + return std::max(0.0, fvalue - 0.5) * 2.0; + else + return (0.5 - std::min(0.5, fvalue)) * 2.0; } std::string evdevDevice::ForceFeedback::GetName() const { - // We have some default names. - switch (m_type) - { - case FF_SINE: - return "Sine"; - case FF_TRIANGLE: - return "Triangle"; - case FF_SQUARE: - return "Square"; - case FF_RUMBLE: - return "LeftRight"; - default: - { - const char* name = libevdev_event_code_get_name(EV_FF, m_type); - if (name) - return std::string(name); - return "Unknown"; - } - } + // We have some default names. + switch (m_type) + { + case FF_SINE: + return "Sine"; + case FF_TRIANGLE: + return "Triangle"; + case FF_SQUARE: + return "Square"; + case FF_RUMBLE: + return "LeftRight"; + default: + { + const char* name = libevdev_event_code_get_name(EV_FF, m_type); + if (name) + return std::string(name); + return "Unknown"; + } + } } void evdevDevice::ForceFeedback::SetState(ControlState state) { - // libevdev doesn't have nice helpers for forcefeedback - // we will use the file descriptors directly. + // libevdev doesn't have nice helpers for forcefeedback + // we will use the file descriptors directly. - if (m_id != -1) // delete the previous effect (which also stops it) - { - ioctl(m_fd, EVIOCRMFF, m_id); - m_id = -1; - } + if (m_id != -1) // delete the previous effect (which also stops it) + { + ioctl(m_fd, EVIOCRMFF, m_id); + m_id = -1; + } - if (state > 0) // Upload and start an effect. - { - ff_effect effect; + if (state > 0) // Upload and start an effect. + { + ff_effect effect; - effect.id = -1; - effect.direction = 0; // down - effect.replay.length = 500; // 500ms - effect.replay.delay = 0; - effect.trigger.button = 0; // don't trigger on button press - effect.trigger.interval = 0; + effect.id = -1; + effect.direction = 0; // down + effect.replay.length = 500; // 500ms + effect.replay.delay = 0; + effect.trigger.button = 0; // don't trigger on button press + effect.trigger.interval = 0; - // This is the the interface that XInput uses, with 2 motors of differing sizes/frequencies that - // are controlled seperatally - if (m_type == FF_RUMBLE) - { - effect.type = FF_RUMBLE; - // max ranges tuned to 'feel' similar in magnitude to triangle/sine on xbox360 controller - effect.u.rumble.strong_magnitude = u16(state * 0x4000); - effect.u.rumble.weak_magnitude = u16(state * 0xFFFF); - } - else // FF_PERIODIC, a more generic interface. - { - effect.type = FF_PERIODIC; - effect.u.periodic.waveform = m_type; - effect.u.periodic.phase = 0x7fff; // 180 degrees - effect.u.periodic.offset = 0; - effect.u.periodic.period = 10; - effect.u.periodic.magnitude = s16(state * 0x7FFF); - effect.u.periodic.envelope.attack_length = 0; // no attack - effect.u.periodic.envelope.attack_level = 0; - effect.u.periodic.envelope.fade_length = 0; - effect.u.periodic.envelope.fade_level = 0; - } + // This is the the interface that XInput uses, with 2 motors of differing sizes/frequencies that + // are controlled seperatally + if (m_type == FF_RUMBLE) + { + effect.type = FF_RUMBLE; + // max ranges tuned to 'feel' similar in magnitude to triangle/sine on xbox360 controller + effect.u.rumble.strong_magnitude = u16(state * 0x4000); + effect.u.rumble.weak_magnitude = u16(state * 0xFFFF); + } + else // FF_PERIODIC, a more generic interface. + { + effect.type = FF_PERIODIC; + effect.u.periodic.waveform = m_type; + effect.u.periodic.phase = 0x7fff; // 180 degrees + effect.u.periodic.offset = 0; + effect.u.periodic.period = 10; + effect.u.periodic.magnitude = s16(state * 0x7FFF); + effect.u.periodic.envelope.attack_length = 0; // no attack + effect.u.periodic.envelope.attack_level = 0; + effect.u.periodic.envelope.fade_length = 0; + effect.u.periodic.envelope.fade_level = 0; + } - ioctl(m_fd, EVIOCSFF, &effect); - m_id = effect.id; + ioctl(m_fd, EVIOCSFF, &effect); + m_id = effect.id; - input_event play; - play.type = EV_FF; - play.code = m_id; - play.value = 1; + input_event play; + play.type = EV_FF; + play.code = m_id; + play.value = 1; - write(m_fd, (const void*) &play, sizeof(play)); - } + write(m_fd, (const void*)&play, sizeof(play)); + } } evdevDevice::ForceFeedback::~ForceFeedback() { - // delete the uploaded effect, so we don't leak it. - if (m_id != -1) - { - ioctl(m_fd, EVIOCRMFF, m_id); - } -} - + // delete the uploaded effect, so we don't leak it. + if (m_id != -1) + { + ioctl(m_fd, EVIOCRMFF, m_id); + } +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h index 5b3c23a466..ce7831bfdc 100644 --- a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h +++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h @@ -4,9 +4,9 @@ #pragma once +#include #include #include -#include #include "InputCommon/ControllerInterface/Device.h" @@ -14,74 +14,72 @@ namespace ciface { namespace evdev { - void Init(std::vector& devices); class evdevDevice : public Core::Device { private: - class Button : public Core::Device::Input - { - public: - std::string GetName() const override; - Button(u8 index, u16 code, libevdev* dev) : m_index(index), m_code(code), m_dev(dev) {} - ControlState GetState() const override; - private: - const u8 m_index; - const u16 m_code; - libevdev* m_dev; - }; + class Button : public Core::Device::Input + { + public: + std::string GetName() const override; + Button(u8 index, u16 code, libevdev* dev) : m_index(index), m_code(code), m_dev(dev) {} + ControlState GetState() const override; - class Axis : public Core::Device::Input - { - public: - std::string GetName() const override; - Axis(u8 index, u16 code, bool upper, libevdev* dev); - ControlState GetState() const override; - private: - const u16 m_code; - const u8 m_index; - const bool m_upper; - int m_range; - int m_min; - libevdev* m_dev; - }; + private: + const u8 m_index; + const u16 m_code; + libevdev* m_dev; + }; - class ForceFeedback : public Core::Device::Output - { - public: - std::string GetName() const override; - ForceFeedback(u16 type, libevdev* dev) : m_type(type), m_id(-1) { m_fd = libevdev_get_fd(dev); } - ~ForceFeedback(); - void SetState(ControlState state) override; - private: - const u16 m_type; - int m_fd; - int m_id; - }; + class Axis : public Core::Device::Input + { + public: + std::string GetName() const override; + Axis(u8 index, u16 code, bool upper, libevdev* dev); + ControlState GetState() const override; + + private: + const u16 m_code; + const u8 m_index; + const bool m_upper; + int m_range; + int m_min; + libevdev* m_dev; + }; + + class ForceFeedback : public Core::Device::Output + { + public: + std::string GetName() const override; + ForceFeedback(u16 type, libevdev* dev) : m_type(type), m_id(-1) { m_fd = libevdev_get_fd(dev); } + ~ForceFeedback(); + void SetState(ControlState state) override; + + private: + const u16 m_type; + int m_fd; + int m_id; + }; public: - void UpdateInput() override; + void UpdateInput() override; - evdevDevice(const std::string &devnode, int id); - ~evdevDevice(); - - std::string GetName() const override { return m_name; } - int GetId() const override { return m_id; } - std::string GetSource() const override { return "evdev"; } - - bool IsInteresting() const { return m_initialized && m_interesting; } + evdevDevice(const std::string& devnode, int id); + ~evdevDevice(); + std::string GetName() const override { return m_name; } + int GetId() const override { return m_id; } + std::string GetSource() const override { return "evdev"; } + bool IsInteresting() const { return m_initialized && m_interesting; } private: - const std::string m_devfile; - int m_fd; - libevdev* m_dev; - std::string m_name; - const int m_id; - bool m_initialized; - bool m_interesting; + const std::string m_devfile; + int m_fd; + libevdev* m_dev; + std::string m_name; + const int m_id; + bool m_initialized; + bool m_interesting; }; - } - } diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index a5ccb771cc..b86b0aa4c5 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -7,14 +7,14 @@ #include #include "Common/Flag.h" -#include "Common/Thread.h" #include "Common/Logging/Log.h" +#include "Common/Thread.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" -#include "Core/NetPlayProto.h" #include "Core/HW/SI.h" #include "Core/HW/SystemTimers.h" +#include "Core/NetPlayProto.h" #include "InputCommon/GCAdapter.h" #include "InputCommon/GCPadStatus.h" @@ -29,7 +29,9 @@ static void Setup(); static bool s_detected = false; static libusb_device_handle* s_handle = nullptr; -static u8 s_controller_type[MAX_SI_CHANNELS] = { ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE }; +static u8 s_controller_type[MAX_SI_CHANNELS] = { + ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE, + ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE}; static u8 s_controller_rumble[4]; static std::mutex s_mutex; @@ -61,455 +63,480 @@ static u64 s_last_init = 0; static void Read() { - int payload_size = 0; - while (s_adapter_thread_running.IsSet()) - { - libusb_interrupt_transfer(s_handle, s_endpoint_in, s_controller_payload_swap, sizeof(s_controller_payload_swap), &payload_size, 16); + int payload_size = 0; + while (s_adapter_thread_running.IsSet()) + { + libusb_interrupt_transfer(s_handle, s_endpoint_in, s_controller_payload_swap, + sizeof(s_controller_payload_swap), &payload_size, 16); - { - std::lock_guard lk(s_mutex); - std::swap(s_controller_payload_swap, s_controller_payload); - s_controller_payload_size.store(payload_size); - } + { + std::lock_guard lk(s_mutex); + std::swap(s_controller_payload_swap, s_controller_payload); + s_controller_payload_size.store(payload_size); + } - Common::YieldCPU(); - } + Common::YieldCPU(); + } } #if defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102 -static int HotplugCallback(libusb_context* ctx, libusb_device* dev, libusb_hotplug_event event, void* user_data) +static int HotplugCallback(libusb_context* ctx, libusb_device* dev, libusb_hotplug_event event, + void* user_data) { - if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) - { - if (s_handle == nullptr && CheckDeviceAccess(dev)) - { - std::lock_guard lk(s_init_mutex); - AddGCAdapter(dev); - } - } - else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) - { - if (s_handle != nullptr && libusb_get_device(s_handle) == dev) - Reset(); - } - return 0; + if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) + { + if (s_handle == nullptr && CheckDeviceAccess(dev)) + { + std::lock_guard lk(s_init_mutex); + AddGCAdapter(dev); + } + } + else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) + { + if (s_handle != nullptr && libusb_get_device(s_handle) == dev) + Reset(); + } + return 0; } #endif static void ScanThreadFunc() { - Common::SetCurrentThreadName("GC Adapter Scanning Thread"); - NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread started"); + Common::SetCurrentThreadName("GC Adapter Scanning Thread"); + NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread started"); #if defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102 - s_libusb_hotplug_enabled = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) != 0; - if (s_libusb_hotplug_enabled) - { - if (libusb_hotplug_register_callback(s_libusb_context, (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), LIBUSB_HOTPLUG_ENUMERATE, 0x057e, 0x0337, LIBUSB_HOTPLUG_MATCH_ANY, HotplugCallback, nullptr, &s_hotplug_handle) != LIBUSB_SUCCESS) - s_libusb_hotplug_enabled = false; - if (s_libusb_hotplug_enabled) - NOTICE_LOG(SERIALINTERFACE, "Using libUSB hotplug detection"); - } + s_libusb_hotplug_enabled = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) != 0; + if (s_libusb_hotplug_enabled) + { + if (libusb_hotplug_register_callback( + s_libusb_context, (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | + LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), + LIBUSB_HOTPLUG_ENUMERATE, 0x057e, 0x0337, LIBUSB_HOTPLUG_MATCH_ANY, HotplugCallback, + nullptr, &s_hotplug_handle) != LIBUSB_SUCCESS) + s_libusb_hotplug_enabled = false; + if (s_libusb_hotplug_enabled) + NOTICE_LOG(SERIALINTERFACE, "Using libUSB hotplug detection"); + } #endif - while (s_adapter_detect_thread_running.IsSet()) - { - if (s_libusb_hotplug_enabled) - { - static timeval tv = {0, 500000}; - libusb_handle_events_timeout(s_libusb_context, &tv); - } - else - { - if (s_handle == nullptr) - { - std::lock_guard lk(s_init_mutex); - Setup(); - if (s_detected && s_detect_callback != nullptr) - s_detect_callback(); - } - Common::SleepCurrentThread(500); - } - } - NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread stopped"); + while (s_adapter_detect_thread_running.IsSet()) + { + if (s_libusb_hotplug_enabled) + { + static timeval tv = {0, 500000}; + libusb_handle_events_timeout(s_libusb_context, &tv); + } + else + { + if (s_handle == nullptr) + { + std::lock_guard lk(s_init_mutex); + Setup(); + if (s_detected && s_detect_callback != nullptr) + s_detect_callback(); + } + Common::SleepCurrentThread(500); + } + } + NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread stopped"); } void SetAdapterCallback(std::function func) { - s_detect_callback = func; + s_detect_callback = func; } void Init() { - if (s_handle != nullptr) - return; + if (s_handle != nullptr) + return; - if (Core::GetState() != Core::CORE_UNINITIALIZED) - { - if ((CoreTiming::GetTicks() - s_last_init) < SystemTimers::GetTicksPerSecond()) - return; + if (Core::GetState() != Core::CORE_UNINITIALIZED) + { + if ((CoreTiming::GetTicks() - s_last_init) < SystemTimers::GetTicksPerSecond()) + return; - s_last_init = CoreTiming::GetTicks(); - } + s_last_init = CoreTiming::GetTicks(); + } - s_libusb_driver_not_supported = false; + s_libusb_driver_not_supported = false; - int ret = libusb_init(&s_libusb_context); + int ret = libusb_init(&s_libusb_context); - if (ret) - { - ERROR_LOG(SERIALINTERFACE, "libusb_init failed with error: %d", ret); - s_libusb_driver_not_supported = true; - Shutdown(); - } - else - { - if (UseAdapter()) - StartScanThread(); - } + if (ret) + { + ERROR_LOG(SERIALINTERFACE, "libusb_init failed with error: %d", ret); + s_libusb_driver_not_supported = true; + Shutdown(); + } + else + { + if (UseAdapter()) + StartScanThread(); + } } void StartScanThread() { - if (s_adapter_detect_thread_running.IsSet()) - return; + if (s_adapter_detect_thread_running.IsSet()) + return; - s_adapter_detect_thread_running.Set(true); - s_adapter_detect_thread = std::thread(ScanThreadFunc); + s_adapter_detect_thread_running.Set(true); + s_adapter_detect_thread = std::thread(ScanThreadFunc); } void StopScanThread() { - if (s_adapter_detect_thread_running.TestAndClear()) - { - s_adapter_detect_thread.join(); - } + if (s_adapter_detect_thread_running.TestAndClear()) + { + s_adapter_detect_thread.join(); + } } static void Setup() { - libusb_device** list; - ssize_t cnt = libusb_get_device_list(s_libusb_context, &list); + libusb_device** list; + ssize_t cnt = libusb_get_device_list(s_libusb_context, &list); - for (int i = 0; i < MAX_SI_CHANNELS; i++) - { - s_controller_type[i] = ControllerTypes::CONTROLLER_NONE; - s_controller_rumble[i] = 0; - } + for (int i = 0; i < MAX_SI_CHANNELS; i++) + { + s_controller_type[i] = ControllerTypes::CONTROLLER_NONE; + s_controller_rumble[i] = 0; + } - for (int d = 0; d < cnt; d++) - { - libusb_device* device = list[d]; - if (CheckDeviceAccess(device)) - { - // Only connect to a single adapter in case the user has multiple connected - AddGCAdapter(device); - break; - } - } + for (int d = 0; d < cnt; d++) + { + libusb_device* device = list[d]; + if (CheckDeviceAccess(device)) + { + // Only connect to a single adapter in case the user has multiple connected + AddGCAdapter(device); + break; + } + } - libusb_free_device_list(list, 1); + libusb_free_device_list(list, 1); } static bool CheckDeviceAccess(libusb_device* device) { - int ret; - libusb_device_descriptor desc; - int dRet = libusb_get_device_descriptor(device, &desc); - if (dRet) - { - // could not acquire the descriptor, no point in trying to use it. - ERROR_LOG(SERIALINTERFACE, "libusb_get_device_descriptor failed with error: %d", dRet); - return false; - } + int ret; + libusb_device_descriptor desc; + int dRet = libusb_get_device_descriptor(device, &desc); + if (dRet) + { + // could not acquire the descriptor, no point in trying to use it. + ERROR_LOG(SERIALINTERFACE, "libusb_get_device_descriptor failed with error: %d", dRet); + return false; + } - if (desc.idVendor == 0x057e && desc.idProduct == 0x0337) - { - NOTICE_LOG(SERIALINTERFACE, "Found GC Adapter with Vendor: %X Product: %X Devnum: %d", desc.idVendor, desc.idProduct, 1); + if (desc.idVendor == 0x057e && desc.idProduct == 0x0337) + { + NOTICE_LOG(SERIALINTERFACE, "Found GC Adapter with Vendor: %X Product: %X Devnum: %d", + desc.idVendor, desc.idProduct, 1); - u8 bus = libusb_get_bus_number(device); - u8 port = libusb_get_device_address(device); - ret = libusb_open(device, &s_handle); - if (ret) - { - if (ret == LIBUSB_ERROR_ACCESS) - { - if (dRet) - { - ERROR_LOG(SERIALINTERFACE, "Dolphin does not have access to this device: Bus %03d Device %03d: ID ????:???? (couldn't get id).", - bus, - port - ); - } - else - { - ERROR_LOG(SERIALINTERFACE, "Dolphin does not have access to this device: Bus %03d Device %03d: ID %04X:%04X.", - bus, - port, - desc.idVendor, - desc.idProduct - ); - } - } - else - { - ERROR_LOG(SERIALINTERFACE, "libusb_open failed to open device with error = %d", ret); - if (ret == LIBUSB_ERROR_NOT_SUPPORTED) - s_libusb_driver_not_supported = true; - } - return false; - } - else if ((ret = libusb_kernel_driver_active(s_handle, 0)) == 1) - { - if ((ret = libusb_detach_kernel_driver(s_handle, 0)) && ret != LIBUSB_ERROR_NOT_SUPPORTED) - { - ERROR_LOG(SERIALINTERFACE, "libusb_detach_kernel_driver failed with error: %d", ret); - } - } - // this split is needed so that we don't avoid claiming the interface when - // detaching the kernel driver is successful - if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED) - { - return false; - } - else if ((ret = libusb_claim_interface(s_handle, 0))) - { - ERROR_LOG(SERIALINTERFACE, "libusb_claim_interface failed with error: %d", ret); - } - else - { - return true; - } - } - return false; + u8 bus = libusb_get_bus_number(device); + u8 port = libusb_get_device_address(device); + ret = libusb_open(device, &s_handle); + if (ret) + { + if (ret == LIBUSB_ERROR_ACCESS) + { + if (dRet) + { + ERROR_LOG(SERIALINTERFACE, "Dolphin does not have access to this device: Bus %03d Device " + "%03d: ID ????:???? (couldn't get id).", + bus, port); + } + else + { + ERROR_LOG( + SERIALINTERFACE, + "Dolphin does not have access to this device: Bus %03d Device %03d: ID %04X:%04X.", + bus, port, desc.idVendor, desc.idProduct); + } + } + else + { + ERROR_LOG(SERIALINTERFACE, "libusb_open failed to open device with error = %d", ret); + if (ret == LIBUSB_ERROR_NOT_SUPPORTED) + s_libusb_driver_not_supported = true; + } + return false; + } + else if ((ret = libusb_kernel_driver_active(s_handle, 0)) == 1) + { + if ((ret = libusb_detach_kernel_driver(s_handle, 0)) && ret != LIBUSB_ERROR_NOT_SUPPORTED) + { + ERROR_LOG(SERIALINTERFACE, "libusb_detach_kernel_driver failed with error: %d", ret); + } + } + // this split is needed so that we don't avoid claiming the interface when + // detaching the kernel driver is successful + if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED) + { + return false; + } + else if ((ret = libusb_claim_interface(s_handle, 0))) + { + ERROR_LOG(SERIALINTERFACE, "libusb_claim_interface failed with error: %d", ret); + } + else + { + return true; + } + } + return false; } static void AddGCAdapter(libusb_device* device) { - libusb_config_descriptor *config = nullptr; - libusb_get_config_descriptor(device, 0, &config); - for (u8 ic = 0; ic < config->bNumInterfaces; ic++) - { - const libusb_interface *interfaceContainer = &config->interface[ic]; - for (int i = 0; i < interfaceContainer->num_altsetting; i++) - { - const libusb_interface_descriptor *interface = &interfaceContainer->altsetting[i]; - for (u8 e = 0; e < interface->bNumEndpoints; e++) - { - const libusb_endpoint_descriptor *endpoint = &interface->endpoint[e]; - if (endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) - s_endpoint_in = endpoint->bEndpointAddress; - else - s_endpoint_out = endpoint->bEndpointAddress; - } - } - } + libusb_config_descriptor* config = nullptr; + libusb_get_config_descriptor(device, 0, &config); + for (u8 ic = 0; ic < config->bNumInterfaces; ic++) + { + const libusb_interface* interfaceContainer = &config->interface[ic]; + for (int i = 0; i < interfaceContainer->num_altsetting; i++) + { + const libusb_interface_descriptor* interface = &interfaceContainer->altsetting[i]; + for (u8 e = 0; e < interface->bNumEndpoints; e++) + { + const libusb_endpoint_descriptor* endpoint = &interface->endpoint[e]; + if (endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) + s_endpoint_in = endpoint->bEndpointAddress; + else + s_endpoint_out = endpoint->bEndpointAddress; + } + } + } - int tmp = 0; - unsigned char payload = 0x13; - libusb_interrupt_transfer(s_handle, s_endpoint_out, &payload, sizeof(payload), &tmp, 16); + int tmp = 0; + unsigned char payload = 0x13; + libusb_interrupt_transfer(s_handle, s_endpoint_out, &payload, sizeof(payload), &tmp, 16); - s_adapter_thread_running.Set(true); - s_adapter_thread = std::thread(Read); + s_adapter_thread_running.Set(true); + s_adapter_thread = std::thread(Read); - s_detected = true; - if (s_detect_callback != nullptr) - s_detect_callback(); - ResetRumbleLockNeeded(); + s_detected = true; + if (s_detect_callback != nullptr) + s_detect_callback(); + ResetRumbleLockNeeded(); } void Shutdown() { - StopScanThread(); + StopScanThread(); #if defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102 - if (s_libusb_hotplug_enabled) - libusb_hotplug_deregister_callback(s_libusb_context, s_hotplug_handle); + if (s_libusb_hotplug_enabled) + libusb_hotplug_deregister_callback(s_libusb_context, s_hotplug_handle); #endif - Reset(); + Reset(); - if (s_libusb_context) - { - libusb_exit(s_libusb_context); - s_libusb_context = nullptr; - } + if (s_libusb_context) + { + libusb_exit(s_libusb_context); + s_libusb_context = nullptr; + } - s_libusb_driver_not_supported = false; + s_libusb_driver_not_supported = false; } static void Reset() { - std::unique_lock lock(s_init_mutex, std::defer_lock); - if (!lock.try_lock()) - return; - if (!s_detected) - return; + std::unique_lock lock(s_init_mutex, std::defer_lock); + if (!lock.try_lock()) + return; + if (!s_detected) + return; - if (s_adapter_thread_running.TestAndClear()) - { - s_adapter_thread.join(); - } + if (s_adapter_thread_running.TestAndClear()) + { + s_adapter_thread.join(); + } - for (int i = 0; i < MAX_SI_CHANNELS; i++) - s_controller_type[i] = ControllerTypes::CONTROLLER_NONE; + for (int i = 0; i < MAX_SI_CHANNELS; i++) + s_controller_type[i] = ControllerTypes::CONTROLLER_NONE; - s_detected = false; + s_detected = false; - if (s_handle) - { - libusb_release_interface(s_handle, 0); - libusb_close(s_handle); - s_handle = nullptr; - } - if (s_detect_callback != nullptr) - s_detect_callback(); - NOTICE_LOG(SERIALINTERFACE, "GC Adapter detached"); + if (s_handle) + { + libusb_release_interface(s_handle, 0); + libusb_close(s_handle); + s_handle = nullptr; + } + if (s_detect_callback != nullptr) + s_detect_callback(); + NOTICE_LOG(SERIALINTERFACE, "GC Adapter detached"); } void Input(int chan, GCPadStatus* pad) { - if (!UseAdapter()) - return; + if (!UseAdapter()) + return; - if (s_handle == nullptr || !s_detected) - return; + if (s_handle == nullptr || !s_detected) + return; - int payload_size = 0; - u8 controller_payload_copy[37]; + int payload_size = 0; + u8 controller_payload_copy[37]; - { - std::lock_guard lk(s_mutex); - std::copy(std::begin(s_controller_payload), std::end(s_controller_payload), std::begin(controller_payload_copy)); - payload_size = s_controller_payload_size.load(); - } + { + std::lock_guard lk(s_mutex); + std::copy(std::begin(s_controller_payload), std::end(s_controller_payload), + std::begin(controller_payload_copy)); + payload_size = s_controller_payload_size.load(); + } - if (payload_size != sizeof(controller_payload_copy) || controller_payload_copy[0] != LIBUSB_DT_HID) - { - INFO_LOG(SERIALINTERFACE, "error reading payload (size: %d, type: %02x)", payload_size, controller_payload_copy[0]); - Reset(); - } - else - { - bool get_origin = false; - u8 type = controller_payload_copy[1 + (9 * chan)] >> 4; - if (type != ControllerTypes::CONTROLLER_NONE && s_controller_type[chan] == ControllerTypes::CONTROLLER_NONE) - { - NOTICE_LOG(SERIALINTERFACE, "New device connected to Port %d of Type: %02x", chan + 1, controller_payload_copy[1 + (9 * chan)]); - get_origin = true; - } + if (payload_size != sizeof(controller_payload_copy) || + controller_payload_copy[0] != LIBUSB_DT_HID) + { + INFO_LOG(SERIALINTERFACE, "error reading payload (size: %d, type: %02x)", payload_size, + controller_payload_copy[0]); + Reset(); + } + else + { + bool get_origin = false; + u8 type = controller_payload_copy[1 + (9 * chan)] >> 4; + if (type != ControllerTypes::CONTROLLER_NONE && + s_controller_type[chan] == ControllerTypes::CONTROLLER_NONE) + { + NOTICE_LOG(SERIALINTERFACE, "New device connected to Port %d of Type: %02x", chan + 1, + controller_payload_copy[1 + (9 * chan)]); + get_origin = true; + } - s_controller_type[chan] = type; + s_controller_type[chan] = type; - memset(pad, 0, sizeof(*pad)); - if (s_controller_type[chan] != ControllerTypes::CONTROLLER_NONE) - { - u8 b1 = controller_payload_copy[1 + (9 * chan) + 1]; - u8 b2 = controller_payload_copy[1 + (9 * chan) + 2]; + memset(pad, 0, sizeof(*pad)); + if (s_controller_type[chan] != ControllerTypes::CONTROLLER_NONE) + { + u8 b1 = controller_payload_copy[1 + (9 * chan) + 1]; + u8 b2 = controller_payload_copy[1 + (9 * chan) + 2]; - if (b1 & (1 << 0)) pad->button |= PAD_BUTTON_A; - if (b1 & (1 << 1)) pad->button |= PAD_BUTTON_B; - if (b1 & (1 << 2)) pad->button |= PAD_BUTTON_X; - if (b1 & (1 << 3)) pad->button |= PAD_BUTTON_Y; + if (b1 & (1 << 0)) + pad->button |= PAD_BUTTON_A; + if (b1 & (1 << 1)) + pad->button |= PAD_BUTTON_B; + if (b1 & (1 << 2)) + pad->button |= PAD_BUTTON_X; + if (b1 & (1 << 3)) + pad->button |= PAD_BUTTON_Y; - if (b1 & (1 << 4)) pad->button |= PAD_BUTTON_LEFT; - if (b1 & (1 << 5)) pad->button |= PAD_BUTTON_RIGHT; - if (b1 & (1 << 6)) pad->button |= PAD_BUTTON_DOWN; - if (b1 & (1 << 7)) pad->button |= PAD_BUTTON_UP; + if (b1 & (1 << 4)) + pad->button |= PAD_BUTTON_LEFT; + if (b1 & (1 << 5)) + pad->button |= PAD_BUTTON_RIGHT; + if (b1 & (1 << 6)) + pad->button |= PAD_BUTTON_DOWN; + if (b1 & (1 << 7)) + pad->button |= PAD_BUTTON_UP; - if (b2 & (1 << 0)) pad->button |= PAD_BUTTON_START; - if (b2 & (1 << 1)) pad->button |= PAD_TRIGGER_Z; - if (b2 & (1 << 2)) pad->button |= PAD_TRIGGER_R; - if (b2 & (1 << 3)) pad->button |= PAD_TRIGGER_L; + if (b2 & (1 << 0)) + pad->button |= PAD_BUTTON_START; + if (b2 & (1 << 1)) + pad->button |= PAD_TRIGGER_Z; + if (b2 & (1 << 2)) + pad->button |= PAD_TRIGGER_R; + if (b2 & (1 << 3)) + pad->button |= PAD_TRIGGER_L; - if (get_origin) pad->button |= PAD_GET_ORIGIN; + if (get_origin) + pad->button |= PAD_GET_ORIGIN; - pad->stickX = controller_payload_copy[1 + (9 * chan) + 3]; - pad->stickY = controller_payload_copy[1 + (9 * chan) + 4]; - pad->substickX = controller_payload_copy[1 + (9 * chan) + 5]; - pad->substickY = controller_payload_copy[1 + (9 * chan) + 6]; - pad->triggerLeft = controller_payload_copy[1 + (9 * chan) + 7]; - pad->triggerRight = controller_payload_copy[1 + (9 * chan) + 8]; - } - else if (!NetPlay::IsNetPlayRunning()) - { - // This is a hack to prevent a netplay desync due to SI devices - // being different and returning different values. - // The corresponding code in DeviceGCAdapter has the same check - pad->button = PAD_ERR_STATUS; - } - } + pad->stickX = controller_payload_copy[1 + (9 * chan) + 3]; + pad->stickY = controller_payload_copy[1 + (9 * chan) + 4]; + pad->substickX = controller_payload_copy[1 + (9 * chan) + 5]; + pad->substickY = controller_payload_copy[1 + (9 * chan) + 6]; + pad->triggerLeft = controller_payload_copy[1 + (9 * chan) + 7]; + pad->triggerRight = controller_payload_copy[1 + (9 * chan) + 8]; + } + else if (!NetPlay::IsNetPlayRunning()) + { + // This is a hack to prevent a netplay desync due to SI devices + // being different and returning different values. + // The corresponding code in DeviceGCAdapter has the same check + pad->button = PAD_ERR_STATUS; + } + } } bool DeviceConnected(int chan) { - return s_controller_type[chan] != ControllerTypes::CONTROLLER_NONE; + return s_controller_type[chan] != ControllerTypes::CONTROLLER_NONE; } bool UseAdapter() { - return SConfig::GetInstance().m_SIDevice[0] == SIDEVICE_WIIU_ADAPTER || - SConfig::GetInstance().m_SIDevice[1] == SIDEVICE_WIIU_ADAPTER || - SConfig::GetInstance().m_SIDevice[2] == SIDEVICE_WIIU_ADAPTER || - SConfig::GetInstance().m_SIDevice[3] == SIDEVICE_WIIU_ADAPTER; + return SConfig::GetInstance().m_SIDevice[0] == SIDEVICE_WIIU_ADAPTER || + SConfig::GetInstance().m_SIDevice[1] == SIDEVICE_WIIU_ADAPTER || + SConfig::GetInstance().m_SIDevice[2] == SIDEVICE_WIIU_ADAPTER || + SConfig::GetInstance().m_SIDevice[3] == SIDEVICE_WIIU_ADAPTER; } void ResetRumble() { - std::unique_lock lock(s_init_mutex, std::defer_lock); - if (!lock.try_lock()) - return; - ResetRumbleLockNeeded(); + std::unique_lock lock(s_init_mutex, std::defer_lock); + if (!lock.try_lock()) + return; + ResetRumbleLockNeeded(); } // Needs to be called when s_init_mutex is locked in order to avoid // being called while the libusb state is being reset static void ResetRumbleLockNeeded() { - if (!UseAdapter() || (s_handle == nullptr || !s_detected)) - { - return; - } + if (!UseAdapter() || (s_handle == nullptr || !s_detected)) + { + return; + } - std::fill(std::begin(s_controller_rumble), std::end(s_controller_rumble), 0); + std::fill(std::begin(s_controller_rumble), std::end(s_controller_rumble), 0); - unsigned char rumble[5] = {0x11, s_controller_rumble[0], s_controller_rumble[1], s_controller_rumble[2], s_controller_rumble[3]}; + unsigned char rumble[5] = {0x11, s_controller_rumble[0], s_controller_rumble[1], + s_controller_rumble[2], s_controller_rumble[3]}; - int size = 0; - libusb_interrupt_transfer(s_handle, s_endpoint_out, rumble, sizeof(rumble), &size, 16); + int size = 0; + libusb_interrupt_transfer(s_handle, s_endpoint_out, rumble, sizeof(rumble), &size, 16); - DEBUG_LOG(SERIALINTERFACE, "Rumble state reset"); + DEBUG_LOG(SERIALINTERFACE, "Rumble state reset"); } void Output(int chan, u8 rumble_command) { - if (s_handle == nullptr || !UseAdapter() || !SConfig::GetInstance().m_AdapterRumble[chan]) - return; + if (s_handle == nullptr || !UseAdapter() || !SConfig::GetInstance().m_AdapterRumble[chan]) + return; - // Skip over rumble commands if it has not changed or the controller is wireless - if (rumble_command != s_controller_rumble[chan] && s_controller_type[chan] != ControllerTypes::CONTROLLER_WIRELESS) - { - s_controller_rumble[chan] = rumble_command; + // Skip over rumble commands if it has not changed or the controller is wireless + if (rumble_command != s_controller_rumble[chan] && + s_controller_type[chan] != ControllerTypes::CONTROLLER_WIRELESS) + { + s_controller_rumble[chan] = rumble_command; - unsigned char rumble[5] = { 0x11, s_controller_rumble[0], s_controller_rumble[1], s_controller_rumble[2], s_controller_rumble[3] }; - int size = 0; + unsigned char rumble[5] = {0x11, s_controller_rumble[0], s_controller_rumble[1], + s_controller_rumble[2], s_controller_rumble[3]}; + int size = 0; - libusb_interrupt_transfer(s_handle, s_endpoint_out, rumble, sizeof(rumble), &size, 16); - // Netplay sends invalid data which results in size = 0x00. Ignore it. - if (size != 0x05 && size != 0x00) - { - INFO_LOG(SERIALINTERFACE, "error writing rumble (size: %d)", size); - Reset(); - } - } + libusb_interrupt_transfer(s_handle, s_endpoint_out, rumble, sizeof(rumble), &size, 16); + // Netplay sends invalid data which results in size = 0x00. Ignore it. + if (size != 0x05 && size != 0x00) + { + INFO_LOG(SERIALINTERFACE, "error writing rumble (size: %d)", size); + Reset(); + } + } } bool IsDetected() { - return s_detected; + return s_detected; } bool IsDriverDetected() { - return !s_libusb_driver_not_supported; + return !s_libusb_driver_not_supported; } -} // end of namespace GCAdapter +} // end of namespace GCAdapter diff --git a/Source/Core/InputCommon/GCAdapter.h b/Source/Core/InputCommon/GCAdapter.h index 5568b0ae9d..355f24d1f3 100644 --- a/Source/Core/InputCommon/GCAdapter.h +++ b/Source/Core/InputCommon/GCAdapter.h @@ -14,9 +14,9 @@ namespace GCAdapter { enum ControllerTypes { - CONTROLLER_NONE = 0, - CONTROLLER_WIRED = 1, - CONTROLLER_WIRELESS = 2 + CONTROLLER_NONE = 0, + CONTROLLER_WIRED = 1, + CONTROLLER_WIRELESS = 2 }; void Init(); void ResetRumble(); @@ -31,4 +31,4 @@ bool IsDriverDetected(); bool DeviceConnected(int chan); bool UseAdapter(); -} // end of namespace GCAdapter +} // end of namespace GCAdapter diff --git a/Source/Core/InputCommon/GCAdapter_Android.cpp b/Source/Core/InputCommon/GCAdapter_Android.cpp index b05a066478..8d2d6be6fe 100644 --- a/Source/Core/InputCommon/GCAdapter_Android.cpp +++ b/Source/Core/InputCommon/GCAdapter_Android.cpp @@ -8,8 +8,8 @@ #include "Common/Event.h" #include "Common/Flag.h" -#include "Common/Thread.h" #include "Common/Logging/Log.h" +#include "Common/Thread.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" @@ -32,7 +32,9 @@ static jclass s_adapter_class; static bool s_detected = false; static int s_fd = 0; -static u8 s_controller_type[MAX_SI_CHANNELS] = { ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE }; +static u8 s_controller_type[MAX_SI_CHANNELS] = { + ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE, + ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE}; static u8 s_controller_rumble[4]; // Input handling @@ -60,319 +62,346 @@ static u64 s_last_init = 0; static void ScanThreadFunc() { - Common::SetCurrentThreadName("GC Adapter Scanning Thread"); - NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread started"); + Common::SetCurrentThreadName("GC Adapter Scanning Thread"); + NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread started"); - JNIEnv* env; - g_java_vm->AttachCurrentThread(&env, NULL); + JNIEnv* env; + g_java_vm->AttachCurrentThread(&env, NULL); - jmethodID queryadapter_func = env->GetStaticMethodID(s_adapter_class, "QueryAdapter", "()Z"); + jmethodID queryadapter_func = env->GetStaticMethodID(s_adapter_class, "QueryAdapter", "()Z"); - while (s_adapter_detect_thread_running.IsSet()) - { - if (!s_detected && UseAdapter() && - env->CallStaticBooleanMethod(s_adapter_class, queryadapter_func)) - Setup(); - Common::SleepCurrentThread(1000); - } - g_java_vm->DetachCurrentThread(); + while (s_adapter_detect_thread_running.IsSet()) + { + if (!s_detected && UseAdapter() && + env->CallStaticBooleanMethod(s_adapter_class, queryadapter_func)) + Setup(); + Common::SleepCurrentThread(1000); + } + g_java_vm->DetachCurrentThread(); - NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread stopped"); + NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread stopped"); } static void Write() { - Common::SetCurrentThreadName("GC Adapter Write Thread"); - NOTICE_LOG(SERIALINTERFACE, "GC Adapter write thread started"); + Common::SetCurrentThreadName("GC Adapter Write Thread"); + NOTICE_LOG(SERIALINTERFACE, "GC Adapter write thread started"); - JNIEnv* env; - g_java_vm->AttachCurrentThread(&env, NULL); - jmethodID output_func = env->GetStaticMethodID(s_adapter_class, "Output", "([B)I"); + JNIEnv* env; + g_java_vm->AttachCurrentThread(&env, NULL); + jmethodID output_func = env->GetStaticMethodID(s_adapter_class, "Output", "([B)I"); - while (s_write_adapter_thread_running.IsSet()) - { - s_write_happened.Wait(); - int write_size = s_controller_write_payload_size.load(); - if (write_size) - { - jbyteArray jrumble_array = env->NewByteArray(5); - jbyte* jrumble = env->GetByteArrayElements(jrumble_array, NULL); + while (s_write_adapter_thread_running.IsSet()) + { + s_write_happened.Wait(); + int write_size = s_controller_write_payload_size.load(); + if (write_size) + { + jbyteArray jrumble_array = env->NewByteArray(5); + jbyte* jrumble = env->GetByteArrayElements(jrumble_array, NULL); - { - std::lock_guard lk(s_write_mutex); - memcpy(jrumble, s_controller_write_payload, write_size); - } + { + std::lock_guard lk(s_write_mutex); + memcpy(jrumble, s_controller_write_payload, write_size); + } - env->ReleaseByteArrayElements(jrumble_array, jrumble, 0); - int size = env->CallStaticIntMethod(s_adapter_class, output_func, jrumble_array); - // Netplay sends invalid data which results in size = 0x00. Ignore it. - if (size != write_size && size != 0x00) - { - ERROR_LOG(SERIALINTERFACE, "error writing rumble (size: %d)", size); - Reset(); - } - } + env->ReleaseByteArrayElements(jrumble_array, jrumble, 0); + int size = env->CallStaticIntMethod(s_adapter_class, output_func, jrumble_array); + // Netplay sends invalid data which results in size = 0x00. Ignore it. + if (size != write_size && size != 0x00) + { + ERROR_LOG(SERIALINTERFACE, "error writing rumble (size: %d)", size); + Reset(); + } + } - Common::YieldCPU(); - } + Common::YieldCPU(); + } - g_java_vm->DetachCurrentThread(); + g_java_vm->DetachCurrentThread(); - NOTICE_LOG(SERIALINTERFACE, "GC Adapter write thread stopped"); + NOTICE_LOG(SERIALINTERFACE, "GC Adapter write thread stopped"); } static void Read() { - Common::SetCurrentThreadName("GC Adapter Read Thread"); - NOTICE_LOG(SERIALINTERFACE, "GC Adapter read thread started"); + Common::SetCurrentThreadName("GC Adapter Read Thread"); + NOTICE_LOG(SERIALINTERFACE, "GC Adapter read thread started"); - bool first_read = true; - JNIEnv* env; - g_java_vm->AttachCurrentThread(&env, NULL); + bool first_read = true; + JNIEnv* env; + g_java_vm->AttachCurrentThread(&env, NULL); - jfieldID payload_field = env->GetStaticFieldID(s_adapter_class, "controller_payload", "[B"); - jobject payload_object = env->GetStaticObjectField(s_adapter_class, payload_field); - jbyteArray* java_controller_payload = reinterpret_cast(&payload_object); + jfieldID payload_field = env->GetStaticFieldID(s_adapter_class, "controller_payload", "[B"); + jobject payload_object = env->GetStaticObjectField(s_adapter_class, payload_field); + jbyteArray* java_controller_payload = reinterpret_cast(&payload_object); - // Get function pointers - jmethodID getfd_func = env->GetStaticMethodID(s_adapter_class, "GetFD", "()I"); - jmethodID input_func = env->GetStaticMethodID(s_adapter_class, "Input", "()I"); - jmethodID openadapter_func = env->GetStaticMethodID(s_adapter_class, "OpenAdapter", "()Z"); + // Get function pointers + jmethodID getfd_func = env->GetStaticMethodID(s_adapter_class, "GetFD", "()I"); + jmethodID input_func = env->GetStaticMethodID(s_adapter_class, "Input", "()I"); + jmethodID openadapter_func = env->GetStaticMethodID(s_adapter_class, "OpenAdapter", "()Z"); - bool connected = env->CallStaticBooleanMethod(s_adapter_class, openadapter_func); + bool connected = env->CallStaticBooleanMethod(s_adapter_class, openadapter_func); - if (connected) - { - s_write_adapter_thread_running.Set(true); - std::thread write_adapter_thread(Write); + if (connected) + { + s_write_adapter_thread_running.Set(true); + std::thread write_adapter_thread(Write); - // Reset rumble once on initial reading - ResetRumble(); + // Reset rumble once on initial reading + ResetRumble(); - while (s_read_adapter_thread_running.IsSet()) - { - int read_size = env->CallStaticIntMethod(s_adapter_class, input_func); + while (s_read_adapter_thread_running.IsSet()) + { + int read_size = env->CallStaticIntMethod(s_adapter_class, input_func); - jbyte* java_data = env->GetByteArrayElements(*java_controller_payload, nullptr); - { - std::lock_guard lk(s_read_mutex); - memcpy(s_controller_payload, java_data, 0x37); - s_controller_payload_size.store(read_size); - } - env->ReleaseByteArrayElements(*java_controller_payload, java_data, 0); + jbyte* java_data = env->GetByteArrayElements(*java_controller_payload, nullptr); + { + std::lock_guard lk(s_read_mutex); + memcpy(s_controller_payload, java_data, 0x37); + s_controller_payload_size.store(read_size); + } + env->ReleaseByteArrayElements(*java_controller_payload, java_data, 0); - if (first_read) - { - first_read = false; - s_fd = env->CallStaticIntMethod(s_adapter_class, getfd_func); - } + if (first_read) + { + first_read = false; + s_fd = env->CallStaticIntMethod(s_adapter_class, getfd_func); + } - Common::YieldCPU(); - } + Common::YieldCPU(); + } - // Terminate the write thread on leaving - if (s_write_adapter_thread_running.TestAndClear()) - { - s_controller_write_payload_size.store(0); - s_write_happened.Set(); // Kick the waiting event - write_adapter_thread.join(); - } - } + // Terminate the write thread on leaving + if (s_write_adapter_thread_running.TestAndClear()) + { + s_controller_write_payload_size.store(0); + s_write_happened.Set(); // Kick the waiting event + write_adapter_thread.join(); + } + } - s_fd = 0; - s_detected = false; + s_fd = 0; + s_detected = false; - g_java_vm->DetachCurrentThread(); + g_java_vm->DetachCurrentThread(); - NOTICE_LOG(SERIALINTERFACE, "GC Adapter read thread stopped"); + NOTICE_LOG(SERIALINTERFACE, "GC Adapter read thread stopped"); } void Init() { - if (s_fd) - return; + if (s_fd) + return; - if (Core::GetState() != Core::CORE_UNINITIALIZED) - { - if ((CoreTiming::GetTicks() - s_last_init) < SystemTimers::GetTicksPerSecond()) - return; + if (Core::GetState() != Core::CORE_UNINITIALIZED) + { + if ((CoreTiming::GetTicks() - s_last_init) < SystemTimers::GetTicksPerSecond()) + return; - s_last_init = CoreTiming::GetTicks(); - } + s_last_init = CoreTiming::GetTicks(); + } - JNIEnv* env; - g_java_vm->AttachCurrentThread(&env, NULL); + JNIEnv* env; + g_java_vm->AttachCurrentThread(&env, NULL); - jclass adapter_class = env->FindClass("org/dolphinemu/dolphinemu/utils/Java_GCAdapter"); - s_adapter_class = reinterpret_cast(env->NewGlobalRef(adapter_class)); + jclass adapter_class = env->FindClass("org/dolphinemu/dolphinemu/utils/Java_GCAdapter"); + s_adapter_class = reinterpret_cast(env->NewGlobalRef(adapter_class)); - if (UseAdapter()) - StartScanThread(); + if (UseAdapter()) + StartScanThread(); } static void Setup() { - s_fd = 0; - s_detected = true; + s_fd = 0; + s_detected = true; - // Make sure the thread isn't in the middle of shutting down while starting a new one - if (s_read_adapter_thread_running.TestAndClear()) - s_read_adapter_thread.join(); + // Make sure the thread isn't in the middle of shutting down while starting a new one + if (s_read_adapter_thread_running.TestAndClear()) + s_read_adapter_thread.join(); - s_read_adapter_thread_running.Set(true); - s_read_adapter_thread = std::thread(Read); + s_read_adapter_thread_running.Set(true); + s_read_adapter_thread = std::thread(Read); } static void Reset() { - if (!s_detected) - return; + if (!s_detected) + return; - if (s_read_adapter_thread_running.TestAndClear()) - s_read_adapter_thread.join(); + if (s_read_adapter_thread_running.TestAndClear()) + s_read_adapter_thread.join(); - for (int i = 0; i < MAX_SI_CHANNELS; i++) - s_controller_type[i] = ControllerTypes::CONTROLLER_NONE; + for (int i = 0; i < MAX_SI_CHANNELS; i++) + s_controller_type[i] = ControllerTypes::CONTROLLER_NONE; - s_detected = false; - s_fd = 0; - NOTICE_LOG(SERIALINTERFACE, "GC Adapter detached"); + s_detected = false; + s_fd = 0; + NOTICE_LOG(SERIALINTERFACE, "GC Adapter detached"); } void Shutdown() { - StopScanThread(); - Reset(); + StopScanThread(); + Reset(); } void StartScanThread() { - if (s_adapter_detect_thread_running.IsSet()) - return; + if (s_adapter_detect_thread_running.IsSet()) + return; - s_adapter_detect_thread_running.Set(true); - s_adapter_detect_thread = std::thread(ScanThreadFunc); + s_adapter_detect_thread_running.Set(true); + s_adapter_detect_thread = std::thread(ScanThreadFunc); } void StopScanThread() { - if (s_adapter_detect_thread_running.TestAndClear()) - s_adapter_detect_thread.join(); + if (s_adapter_detect_thread_running.TestAndClear()) + s_adapter_detect_thread.join(); } void Input(int chan, GCPadStatus* pad) { - if (!UseAdapter() || !s_detected || !s_fd) - return; + if (!UseAdapter() || !s_detected || !s_fd) + return; - int payload_size = 0; - u8 controller_payload_copy[37]; + int payload_size = 0; + u8 controller_payload_copy[37]; - { - std::lock_guard lk(s_read_mutex); - std::copy(std::begin(s_controller_payload), std::end(s_controller_payload), std::begin(controller_payload_copy)); - payload_size = s_controller_payload_size.load(); - } + { + std::lock_guard lk(s_read_mutex); + std::copy(std::begin(s_controller_payload), std::end(s_controller_payload), + std::begin(controller_payload_copy)); + payload_size = s_controller_payload_size.load(); + } - if (payload_size != sizeof(controller_payload_copy)) - { - ERROR_LOG(SERIALINTERFACE, "error reading payload (size: %d, type: %02x)", payload_size, controller_payload_copy[0]); - Reset(); - } - else - { - bool get_origin = false; - u8 type = controller_payload_copy[1 + (9 * chan)] >> 4; - if (type != ControllerTypes::CONTROLLER_NONE && s_controller_type[chan] == ControllerTypes::CONTROLLER_NONE) - { - ERROR_LOG(SERIALINTERFACE, "New device connected to Port %d of Type: %02x", chan + 1, controller_payload_copy[1 + (9 * chan)]); - get_origin = true; - } + if (payload_size != sizeof(controller_payload_copy)) + { + ERROR_LOG(SERIALINTERFACE, "error reading payload (size: %d, type: %02x)", payload_size, + controller_payload_copy[0]); + Reset(); + } + else + { + bool get_origin = false; + u8 type = controller_payload_copy[1 + (9 * chan)] >> 4; + if (type != ControllerTypes::CONTROLLER_NONE && + s_controller_type[chan] == ControllerTypes::CONTROLLER_NONE) + { + ERROR_LOG(SERIALINTERFACE, "New device connected to Port %d of Type: %02x", chan + 1, + controller_payload_copy[1 + (9 * chan)]); + get_origin = true; + } - s_controller_type[chan] = type; + s_controller_type[chan] = type; - memset(pad, 0, sizeof(*pad)); - if (s_controller_type[chan] != ControllerTypes::CONTROLLER_NONE) - { - u8 b1 = controller_payload_copy[1 + (9 * chan) + 1]; - u8 b2 = controller_payload_copy[1 + (9 * chan) + 2]; + memset(pad, 0, sizeof(*pad)); + if (s_controller_type[chan] != ControllerTypes::CONTROLLER_NONE) + { + u8 b1 = controller_payload_copy[1 + (9 * chan) + 1]; + u8 b2 = controller_payload_copy[1 + (9 * chan) + 2]; - if (b1 & (1 << 0)) pad->button |= PAD_BUTTON_A; - if (b1 & (1 << 1)) pad->button |= PAD_BUTTON_B; - if (b1 & (1 << 2)) pad->button |= PAD_BUTTON_X; - if (b1 & (1 << 3)) pad->button |= PAD_BUTTON_Y; + if (b1 & (1 << 0)) + pad->button |= PAD_BUTTON_A; + if (b1 & (1 << 1)) + pad->button |= PAD_BUTTON_B; + if (b1 & (1 << 2)) + pad->button |= PAD_BUTTON_X; + if (b1 & (1 << 3)) + pad->button |= PAD_BUTTON_Y; - if (b1 & (1 << 4)) pad->button |= PAD_BUTTON_LEFT; - if (b1 & (1 << 5)) pad->button |= PAD_BUTTON_RIGHT; - if (b1 & (1 << 6)) pad->button |= PAD_BUTTON_DOWN; - if (b1 & (1 << 7)) pad->button |= PAD_BUTTON_UP; + if (b1 & (1 << 4)) + pad->button |= PAD_BUTTON_LEFT; + if (b1 & (1 << 5)) + pad->button |= PAD_BUTTON_RIGHT; + if (b1 & (1 << 6)) + pad->button |= PAD_BUTTON_DOWN; + if (b1 & (1 << 7)) + pad->button |= PAD_BUTTON_UP; - if (b2 & (1 << 0)) pad->button |= PAD_BUTTON_START; - if (b2 & (1 << 1)) pad->button |= PAD_TRIGGER_Z; - if (b2 & (1 << 2)) pad->button |= PAD_TRIGGER_R; - if (b2 & (1 << 3)) pad->button |= PAD_TRIGGER_L; + if (b2 & (1 << 0)) + pad->button |= PAD_BUTTON_START; + if (b2 & (1 << 1)) + pad->button |= PAD_TRIGGER_Z; + if (b2 & (1 << 2)) + pad->button |= PAD_TRIGGER_R; + if (b2 & (1 << 3)) + pad->button |= PAD_TRIGGER_L; - if (get_origin) pad->button |= PAD_GET_ORIGIN; + if (get_origin) + pad->button |= PAD_GET_ORIGIN; - pad->stickX = controller_payload_copy[1 + (9 * chan) + 3]; - pad->stickY = controller_payload_copy[1 + (9 * chan) + 4]; - pad->substickX = controller_payload_copy[1 + (9 * chan) + 5]; - pad->substickY = controller_payload_copy[1 + (9 * chan) + 6]; - pad->triggerLeft = controller_payload_copy[1 + (9 * chan) + 7]; - pad->triggerRight = controller_payload_copy[1 + (9 * chan) + 8]; - } - else - { - pad->button = PAD_ERR_STATUS; - } - } + pad->stickX = controller_payload_copy[1 + (9 * chan) + 3]; + pad->stickY = controller_payload_copy[1 + (9 * chan) + 4]; + pad->substickX = controller_payload_copy[1 + (9 * chan) + 5]; + pad->substickY = controller_payload_copy[1 + (9 * chan) + 6]; + pad->triggerLeft = controller_payload_copy[1 + (9 * chan) + 7]; + pad->triggerRight = controller_payload_copy[1 + (9 * chan) + 8]; + } + else + { + pad->button = PAD_ERR_STATUS; + } + } } void Output(int chan, u8 rumble_command) { - if (!UseAdapter() || !s_detected || !s_fd) - return; + if (!UseAdapter() || !s_detected || !s_fd) + return; - // Skip over rumble commands if it has not changed or the controller is wireless - if (rumble_command != s_controller_rumble[chan] && s_controller_type[chan] != ControllerTypes::CONTROLLER_WIRELESS) - { - s_controller_rumble[chan] = rumble_command; - unsigned char rumble[5] = { 0x11, s_controller_rumble[0], s_controller_rumble[1], s_controller_rumble[2], s_controller_rumble[3] }; - { - std::lock_guard lk(s_write_mutex); - memcpy(s_controller_write_payload, rumble, 5); - s_controller_write_payload_size.store(5); - } - s_write_happened.Set(); - } + // Skip over rumble commands if it has not changed or the controller is wireless + if (rumble_command != s_controller_rumble[chan] && + s_controller_type[chan] != ControllerTypes::CONTROLLER_WIRELESS) + { + s_controller_rumble[chan] = rumble_command; + unsigned char rumble[5] = {0x11, s_controller_rumble[0], s_controller_rumble[1], + s_controller_rumble[2], s_controller_rumble[3]}; + { + std::lock_guard lk(s_write_mutex); + memcpy(s_controller_write_payload, rumble, 5); + s_controller_write_payload_size.store(5); + } + s_write_happened.Set(); + } } -bool IsDetected() { return s_detected; } -bool IsDriverDetected() { return true; } +bool IsDetected() +{ + return s_detected; +} +bool IsDriverDetected() +{ + return true; +} bool DeviceConnected(int chan) { - return s_controller_type[chan] != ControllerTypes::CONTROLLER_NONE; + return s_controller_type[chan] != ControllerTypes::CONTROLLER_NONE; } bool UseAdapter() { - return SConfig::GetInstance().m_SIDevice[0] == SIDEVICE_WIIU_ADAPTER || - SConfig::GetInstance().m_SIDevice[1] == SIDEVICE_WIIU_ADAPTER || - SConfig::GetInstance().m_SIDevice[2] == SIDEVICE_WIIU_ADAPTER || - SConfig::GetInstance().m_SIDevice[3] == SIDEVICE_WIIU_ADAPTER; + return SConfig::GetInstance().m_SIDevice[0] == SIDEVICE_WIIU_ADAPTER || + SConfig::GetInstance().m_SIDevice[1] == SIDEVICE_WIIU_ADAPTER || + SConfig::GetInstance().m_SIDevice[2] == SIDEVICE_WIIU_ADAPTER || + SConfig::GetInstance().m_SIDevice[3] == SIDEVICE_WIIU_ADAPTER; } void ResetRumble() { - unsigned char rumble[5] = {0x11, 0, 0, 0, 0}; - { - std::lock_guard lk(s_read_mutex); - memcpy(s_controller_write_payload, rumble, 5); - s_controller_write_payload_size.store(5); - } - s_write_happened.Set(); + unsigned char rumble[5] = {0x11, 0, 0, 0, 0}; + { + std::lock_guard lk(s_read_mutex); + memcpy(s_controller_write_payload, rumble, 5); + s_controller_write_payload_size.store(5); + } + s_write_happened.Set(); } -void SetAdapterCallback(std::function func) { } +void SetAdapterCallback(std::function func) +{ +} -} // end of namespace GCAdapter +} // end of namespace GCAdapter diff --git a/Source/Core/InputCommon/GCAdapter_Null.cpp b/Source/Core/InputCommon/GCAdapter_Null.cpp index d7f13c2917..bb9422807b 100644 --- a/Source/Core/InputCommon/GCAdapter_Null.cpp +++ b/Source/Core/InputCommon/GCAdapter_Null.cpp @@ -2,23 +2,50 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Common/CommonTypes.h" #include "InputCommon/GCAdapter.h" +#include "Common/CommonTypes.h" namespace GCAdapter { +void Init() +{ +} +void ResetRumble() +{ +} +void Shutdown() +{ +} +void SetAdapterCallback(std::function func) +{ +} +void StartScanThread() +{ +} +void StopScanThread() +{ +} +void Input(int chan, GCPadStatus* pad) +{ +} +void Output(int chan, u8 rumble_command) +{ +} +bool IsDetected() +{ + return false; +} +bool IsDriverDetected() +{ + return false; +} +bool DeviceConnected(int chan) +{ + return false; +} +bool UseAdapter() +{ + return false; +} -void Init() {} -void ResetRumble() {} -void Shutdown() {} -void SetAdapterCallback(std::function func) {} -void StartScanThread() {} -void StopScanThread() {} -void Input(int chan, GCPadStatus* pad) {} -void Output(int chan, u8 rumble_command) {} -bool IsDetected() { return false; } -bool IsDriverDetected() { return false; } -bool DeviceConnected(int chan) { return false; } -bool UseAdapter() { return false; } - -} // end of namespace GCAdapter +} // end of namespace GCAdapter diff --git a/Source/Core/InputCommon/GCPadStatus.h b/Source/Core/InputCommon/GCPadStatus.h index deecb30523..d9aa6c5a91 100644 --- a/Source/Core/InputCommon/GCPadStatus.h +++ b/Source/Core/InputCommon/GCPadStatus.h @@ -8,52 +8,52 @@ enum PadError { - PAD_ERR_NONE = 0, - PAD_ERR_NO_CONTROLLER = -1, - PAD_ERR_NOT_READY = -2, - PAD_ERR_TRANSFER = -3, + PAD_ERR_NONE = 0, + PAD_ERR_NO_CONTROLLER = -1, + PAD_ERR_NOT_READY = -2, + PAD_ERR_TRANSFER = -3, }; enum { - PAD_USE_ORIGIN = 0x0080, - PAD_GET_ORIGIN = 0x2000, - PAD_ERR_STATUS = 0x8000, + PAD_USE_ORIGIN = 0x0080, + PAD_GET_ORIGIN = 0x2000, + PAD_ERR_STATUS = 0x8000, }; enum PadButton { - PAD_BUTTON_LEFT = 0x0001, - PAD_BUTTON_RIGHT = 0x0002, - PAD_BUTTON_DOWN = 0x0004, - PAD_BUTTON_UP = 0x0008, - PAD_TRIGGER_Z = 0x0010, - PAD_TRIGGER_R = 0x0020, - PAD_TRIGGER_L = 0x0040, - PAD_BUTTON_A = 0x0100, - PAD_BUTTON_B = 0x0200, - PAD_BUTTON_X = 0x0400, - PAD_BUTTON_Y = 0x0800, - PAD_BUTTON_START = 0x1000, + PAD_BUTTON_LEFT = 0x0001, + PAD_BUTTON_RIGHT = 0x0002, + PAD_BUTTON_DOWN = 0x0004, + PAD_BUTTON_UP = 0x0008, + PAD_TRIGGER_Z = 0x0010, + PAD_TRIGGER_R = 0x0020, + PAD_TRIGGER_L = 0x0040, + PAD_BUTTON_A = 0x0100, + PAD_BUTTON_B = 0x0200, + PAD_BUTTON_X = 0x0400, + PAD_BUTTON_Y = 0x0800, + PAD_BUTTON_START = 0x1000, }; struct GCPadStatus { - u16 button; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits - u8 stickX; // 0 <= stickX <= 255 - u8 stickY; // 0 <= stickY <= 255 - u8 substickX; // 0 <= substickX <= 255 - u8 substickY; // 0 <= substickY <= 255 - u8 triggerLeft; // 0 <= triggerLeft <= 255 - u8 triggerRight; // 0 <= triggerRight <= 255 - u8 analogA; // 0 <= analogA <= 255 - u8 analogB; // 0 <= analogB <= 255 - s8 err; // one of PAD_ERR_* number + u16 button; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits + u8 stickX; // 0 <= stickX <= 255 + u8 stickY; // 0 <= stickY <= 255 + u8 substickX; // 0 <= substickX <= 255 + u8 substickY; // 0 <= substickY <= 255 + u8 triggerLeft; // 0 <= triggerLeft <= 255 + u8 triggerRight; // 0 <= triggerRight <= 255 + u8 analogA; // 0 <= analogA <= 255 + u8 analogB; // 0 <= analogB <= 255 + s8 err; // one of PAD_ERR_* number - static const u8 MAIN_STICK_CENTER_X = 0x80; - static const u8 MAIN_STICK_CENTER_Y = 0x80; - static const u8 MAIN_STICK_RADIUS = 0x7f; - static const u8 C_STICK_CENTER_X = 0x80; - static const u8 C_STICK_CENTER_Y = 0x80; - static const u8 C_STICK_RADIUS = 0x7f; + static const u8 MAIN_STICK_CENTER_X = 0x80; + static const u8 MAIN_STICK_CENTER_Y = 0x80; + static const u8 MAIN_STICK_RADIUS = 0x7f; + static const u8 C_STICK_CENTER_X = 0x80; + static const u8 C_STICK_CENTER_Y = 0x80; + static const u8 C_STICK_RADIUS = 0x7f; }; diff --git a/Source/Core/InputCommon/InputConfig.cpp b/Source/Core/InputCommon/InputConfig.cpp index 58d46b92b6..e1869ca465 100644 --- a/Source/Core/InputCommon/InputConfig.cpp +++ b/Source/Core/InputCommon/InputConfig.cpp @@ -9,125 +9,127 @@ #include "Core/ConfigManager.h" #include "Core/HW/Wiimote.h" #include "InputCommon/ControllerEmu.h" -#include "InputCommon/InputConfig.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" +#include "InputCommon/InputConfig.h" bool InputConfig::LoadConfig(bool isGC) { - IniFile inifile; - bool useProfile[MAX_BBMOTES] = {false, false, false, false, false}; - std::string num[MAX_BBMOTES] = {"1", "2", "3", "4", "BB"}; - std::string profile[MAX_BBMOTES]; - std::string path; + IniFile inifile; + bool useProfile[MAX_BBMOTES] = {false, false, false, false, false}; + std::string num[MAX_BBMOTES] = {"1", "2", "3", "4", "BB"}; + std::string profile[MAX_BBMOTES]; + std::string path; - if (SConfig::GetInstance().GetUniqueID() != "00000000") - { - std::string type; - if (isGC) - { - type = "Pad"; - path = "Profiles/GCPad/"; - } - else - { - type = "Wiimote"; - path = "Profiles/Wiimote/"; - } + if (SConfig::GetInstance().GetUniqueID() != "00000000") + { + std::string type; + if (isGC) + { + type = "Pad"; + path = "Profiles/GCPad/"; + } + else + { + type = "Wiimote"; + path = "Profiles/Wiimote/"; + } - IniFile game_ini = SConfig::GetInstance().LoadGameIni(); - IniFile::Section* control_section = game_ini.GetOrCreateSection("Controls"); + IniFile game_ini = SConfig::GetInstance().LoadGameIni(); + IniFile::Section* control_section = game_ini.GetOrCreateSection("Controls"); - for (int i = 0; i < 4; i++) - { - if (control_section->Exists(type + "Profile" + num[i])) - { - if (control_section->Get(type + "Profile" + num[i], &profile[i])) - { - if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + path + profile[i] + ".ini")) - { - useProfile[i] = true; - } - else - { - // TODO: PanicAlert shouldn't be used for this. - PanicAlertT("Selected controller profile does not exist"); - } - } - } - } - } + for (int i = 0; i < 4; i++) + { + if (control_section->Exists(type + "Profile" + num[i])) + { + if (control_section->Get(type + "Profile" + num[i], &profile[i])) + { + if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + path + profile[i] + ".ini")) + { + useProfile[i] = true; + } + else + { + // TODO: PanicAlert shouldn't be used for this. + PanicAlertT("Selected controller profile does not exist"); + } + } + } + } + } - if (inifile.Load(File::GetUserPath(D_CONFIG_IDX) + m_ini_name + ".ini")) - { - int n = 0; - for (auto& controller : m_controllers) - { - // Load settings from ini - if (useProfile[n]) - { - IniFile profile_ini; - profile_ini.Load(File::GetUserPath(D_CONFIG_IDX) + path + profile[n] + ".ini"); - controller->LoadConfig(profile_ini.GetOrCreateSection("Profile")); - } - else - { - controller->LoadConfig(inifile.GetOrCreateSection(controller->GetName())); - } + if (inifile.Load(File::GetUserPath(D_CONFIG_IDX) + m_ini_name + ".ini")) + { + int n = 0; + for (auto& controller : m_controllers) + { + // Load settings from ini + if (useProfile[n]) + { + IniFile profile_ini; + profile_ini.Load(File::GetUserPath(D_CONFIG_IDX) + path + profile[n] + ".ini"); + controller->LoadConfig(profile_ini.GetOrCreateSection("Profile")); + } + else + { + controller->LoadConfig(inifile.GetOrCreateSection(controller->GetName())); + } - // Update refs - controller->UpdateReferences(g_controller_interface); + // Update refs + controller->UpdateReferences(g_controller_interface); - // Next profile - n++; - } - return true; - } - else - { - m_controllers[0]->LoadDefaults(g_controller_interface); - m_controllers[0]->UpdateReferences(g_controller_interface); - return false; - } + // Next profile + n++; + } + return true; + } + else + { + m_controllers[0]->LoadDefaults(g_controller_interface); + m_controllers[0]->UpdateReferences(g_controller_interface); + return false; + } } void InputConfig::SaveConfig() { - std::string ini_filename = File::GetUserPath(D_CONFIG_IDX) + m_ini_name + ".ini"; + std::string ini_filename = File::GetUserPath(D_CONFIG_IDX) + m_ini_name + ".ini"; - IniFile inifile; - inifile.Load(ini_filename); + IniFile inifile; + inifile.Load(ini_filename); - for (auto& controller : m_controllers) - controller->SaveConfig(inifile.GetOrCreateSection(controller->GetName())); + for (auto& controller : m_controllers) + controller->SaveConfig(inifile.GetOrCreateSection(controller->GetName())); - inifile.Save(ini_filename); + inifile.Save(ini_filename); } ControllerEmu* InputConfig::GetController(int index) { - return m_controllers.at(index).get(); + return m_controllers.at(index).get(); } void InputConfig::ClearControllers() { - m_controllers.clear(); + m_controllers.clear(); } bool InputConfig::ControllersNeedToBeCreated() const { - return m_controllers.empty(); + return m_controllers.empty(); } bool InputConfig::IsControllerControlledByGamepadDevice(int index) const { - if (static_cast(index) >= m_controllers.size()) - return false; + if (static_cast(index) >= m_controllers.size()) + return false; - const auto& controller = m_controllers.at(index).get()->default_device; + const auto& controller = m_controllers.at(index).get()->default_device; - // Filter out anything which obviously not a gamepad - return !((controller.source == "Keyboard") // OSX Keyboard/Mouse - || (controller.source == "XInput2") // Linux and BSD Keyboard/Mouse - || (controller.source == "Android" && controller.name == "Touchscreen") // Android Touchscreen - || (controller.source == "DInput" && controller.name == "Keyboard Mouse")); // Windows Keyboard/Mouse + // Filter out anything which obviously not a gamepad + return !((controller.source == "Keyboard") // OSX Keyboard/Mouse + || (controller.source == "XInput2") // Linux and BSD Keyboard/Mouse + || (controller.source == "Android" && + controller.name == "Touchscreen") // Android Touchscreen + || (controller.source == "DInput" && + controller.name == "Keyboard Mouse")); // Windows Keyboard/Mouse } diff --git a/Source/Core/InputCommon/InputConfig.h b/Source/Core/InputCommon/InputConfig.h index a1f712cc91..27cc70198e 100644 --- a/Source/Core/InputCommon/InputConfig.h +++ b/Source/Core/InputCommon/InputConfig.h @@ -14,31 +14,31 @@ class ControllerEmu; class InputConfig { public: - InputConfig(const std::string& ini_name, const std::string& gui_name, const std::string& profile_name) - : m_ini_name(ini_name), m_gui_name(gui_name), m_profile_name(profile_name) - { - } + InputConfig(const std::string& ini_name, const std::string& gui_name, + const std::string& profile_name) + : m_ini_name(ini_name), m_gui_name(gui_name), m_profile_name(profile_name) + { + } - bool LoadConfig(bool isGC); - void SaveConfig(); + bool LoadConfig(bool isGC); + void SaveConfig(); - template - void CreateController(Args&&... args) - { - m_controllers.emplace_back(std::make_unique(std::forward(args)...)); - } + template + void CreateController(Args&&... args) + { + m_controllers.emplace_back(std::make_unique(std::forward(args)...)); + } - ControllerEmu* GetController(int index); - void ClearControllers(); - bool ControllersNeedToBeCreated() const; - bool IsControllerControlledByGamepadDevice(int index) const; - - std::string GetGUIName() const { return m_gui_name; } - std::string GetProfileName() const { return m_profile_name; } + ControllerEmu* GetController(int index); + void ClearControllers(); + bool ControllersNeedToBeCreated() const; + bool IsControllerControlledByGamepadDevice(int index) const; + std::string GetGUIName() const { return m_gui_name; } + std::string GetProfileName() const { return m_profile_name; } private: - std::vector> m_controllers; - const std::string m_ini_name; - const std::string m_gui_name; - const std::string m_profile_name; + std::vector> m_controllers; + const std::string m_ini_name; + const std::string m_gui_name; + const std::string m_profile_name; }; diff --git a/Source/Core/InputCommon/KeyboardStatus.h b/Source/Core/InputCommon/KeyboardStatus.h index 0ed4e255f9..0a24e24bb4 100644 --- a/Source/Core/InputCommon/KeyboardStatus.h +++ b/Source/Core/InputCommon/KeyboardStatus.h @@ -8,191 +8,191 @@ enum KeyMasks { - KEYMASK_HOME = (1 << 0), - KEYMASK_END = (1 << 1), - KEYMASK_PGUP = (1 << 2), - KEYMASK_PGDN = (1 << 3), - KEYMASK_SCROLLLOCK = (1 << 4), - KEYMASK_A = (1 << 5), - KEYMASK_B = (1 << 6), - KEYMASK_C = (1 << 7), - KEYMASK_D = (1 << 8), - KEYMASK_E = (1 << 9), - KEYMASK_F = (1 << 10), - KEYMASK_G = (1 << 11), - KEYMASK_H = (1 << 12), - KEYMASK_I = (1 << 13), - KEYMASK_J = (1 << 14), - KEYMASK_K = (1 << 15), - KEYMASK_L = (1 << 0), - KEYMASK_M = (1 << 1), - KEYMASK_N = (1 << 2), - KEYMASK_O = (1 << 3), - KEYMASK_P = (1 << 4), - KEYMASK_Q = (1 << 5), - KEYMASK_R = (1 << 6), - KEYMASK_S = (1 << 7), - KEYMASK_T = (1 << 8), - KEYMASK_U = (1 << 9), - KEYMASK_V = (1 << 10), - KEYMASK_W = (1 << 11), - KEYMASK_X = (1 << 12), - KEYMASK_Y = (1 << 13), - KEYMASK_Z = (1 << 14), - KEYMASK_1 = (1 << 15), - KEYMASK_2 = (1 << 0), - KEYMASK_3 = (1 << 1), - KEYMASK_4 = (1 << 2), - KEYMASK_5 = (1 << 3), - KEYMASK_6 = (1 << 4), - KEYMASK_7 = (1 << 5), - KEYMASK_8 = (1 << 6), - KEYMASK_9 = (1 << 7), - KEYMASK_0 = (1 << 8), - KEYMASK_MINUS = (1 << 9), - KEYMASK_PLUS = (1 << 10), - KEYMASK_PRINTSCR = (1 << 11), - KEYMASK_BRACE_OPEN = (1 << 12), - KEYMASK_BRACE_CLOSE = (1 << 13), - KEYMASK_COLON = (1 << 14), - KEYMASK_QUOTE = (1 << 15), - KEYMASK_HASH = (1 << 0), - KEYMASK_COMMA = (1 << 1), - KEYMASK_PERIOD = (1 << 2), - KEYMASK_QUESTIONMARK = (1 << 3), - KEYMASK_INTERNATIONAL1 = (1 << 4), - KEYMASK_F1 = (1 << 5), - KEYMASK_F2 = (1 << 6), - KEYMASK_F3 = (1 << 7), - KEYMASK_F4 = (1 << 8), - KEYMASK_F5 = (1 << 9), - KEYMASK_F6 = (1 << 10), - KEYMASK_F7 = (1 << 11), - KEYMASK_F8 = (1 << 12), - KEYMASK_F9 = (1 << 13), - KEYMASK_F10 = (1 << 14), - KEYMASK_F11 = (1 << 15), - KEYMASK_F12 = (1 << 0), - KEYMASK_ESC = (1 << 1), - KEYMASK_INSERT = (1 << 2), - KEYMASK_DELETE = (1 << 3), - KEYMASK_TILDE = (1 << 4), - KEYMASK_BACKSPACE = (1 << 5), - KEYMASK_TAB = (1 << 6), - KEYMASK_CAPSLOCK = (1 << 7), - KEYMASK_LEFTSHIFT = (1 << 8), - KEYMASK_RIGHTSHIFT = (1 << 9), - KEYMASK_LEFTCONTROL = (1 << 10), - KEYMASK_RIGHTALT = (1 << 11), - KEYMASK_LEFTWINDOWS = (1 << 12), - KEYMASK_SPACE = (1 << 13), - KEYMASK_RIGHTWINDOWS = (1 << 14), - KEYMASK_MENU = (1 << 15), - KEYMASK_LEFTARROW = (1 << 0), - KEYMASK_DOWNARROW = (1 << 1), - KEYMASK_UPARROW = (1 << 2), - KEYMASK_RIGHTARROW = (1 << 3), - KEYMASK_ENTER = (1 << 4), + KEYMASK_HOME = (1 << 0), + KEYMASK_END = (1 << 1), + KEYMASK_PGUP = (1 << 2), + KEYMASK_PGDN = (1 << 3), + KEYMASK_SCROLLLOCK = (1 << 4), + KEYMASK_A = (1 << 5), + KEYMASK_B = (1 << 6), + KEYMASK_C = (1 << 7), + KEYMASK_D = (1 << 8), + KEYMASK_E = (1 << 9), + KEYMASK_F = (1 << 10), + KEYMASK_G = (1 << 11), + KEYMASK_H = (1 << 12), + KEYMASK_I = (1 << 13), + KEYMASK_J = (1 << 14), + KEYMASK_K = (1 << 15), + KEYMASK_L = (1 << 0), + KEYMASK_M = (1 << 1), + KEYMASK_N = (1 << 2), + KEYMASK_O = (1 << 3), + KEYMASK_P = (1 << 4), + KEYMASK_Q = (1 << 5), + KEYMASK_R = (1 << 6), + KEYMASK_S = (1 << 7), + KEYMASK_T = (1 << 8), + KEYMASK_U = (1 << 9), + KEYMASK_V = (1 << 10), + KEYMASK_W = (1 << 11), + KEYMASK_X = (1 << 12), + KEYMASK_Y = (1 << 13), + KEYMASK_Z = (1 << 14), + KEYMASK_1 = (1 << 15), + KEYMASK_2 = (1 << 0), + KEYMASK_3 = (1 << 1), + KEYMASK_4 = (1 << 2), + KEYMASK_5 = (1 << 3), + KEYMASK_6 = (1 << 4), + KEYMASK_7 = (1 << 5), + KEYMASK_8 = (1 << 6), + KEYMASK_9 = (1 << 7), + KEYMASK_0 = (1 << 8), + KEYMASK_MINUS = (1 << 9), + KEYMASK_PLUS = (1 << 10), + KEYMASK_PRINTSCR = (1 << 11), + KEYMASK_BRACE_OPEN = (1 << 12), + KEYMASK_BRACE_CLOSE = (1 << 13), + KEYMASK_COLON = (1 << 14), + KEYMASK_QUOTE = (1 << 15), + KEYMASK_HASH = (1 << 0), + KEYMASK_COMMA = (1 << 1), + KEYMASK_PERIOD = (1 << 2), + KEYMASK_QUESTIONMARK = (1 << 3), + KEYMASK_INTERNATIONAL1 = (1 << 4), + KEYMASK_F1 = (1 << 5), + KEYMASK_F2 = (1 << 6), + KEYMASK_F3 = (1 << 7), + KEYMASK_F4 = (1 << 8), + KEYMASK_F5 = (1 << 9), + KEYMASK_F6 = (1 << 10), + KEYMASK_F7 = (1 << 11), + KEYMASK_F8 = (1 << 12), + KEYMASK_F9 = (1 << 13), + KEYMASK_F10 = (1 << 14), + KEYMASK_F11 = (1 << 15), + KEYMASK_F12 = (1 << 0), + KEYMASK_ESC = (1 << 1), + KEYMASK_INSERT = (1 << 2), + KEYMASK_DELETE = (1 << 3), + KEYMASK_TILDE = (1 << 4), + KEYMASK_BACKSPACE = (1 << 5), + KEYMASK_TAB = (1 << 6), + KEYMASK_CAPSLOCK = (1 << 7), + KEYMASK_LEFTSHIFT = (1 << 8), + KEYMASK_RIGHTSHIFT = (1 << 9), + KEYMASK_LEFTCONTROL = (1 << 10), + KEYMASK_RIGHTALT = (1 << 11), + KEYMASK_LEFTWINDOWS = (1 << 12), + KEYMASK_SPACE = (1 << 13), + KEYMASK_RIGHTWINDOWS = (1 << 14), + KEYMASK_MENU = (1 << 15), + KEYMASK_LEFTARROW = (1 << 0), + KEYMASK_DOWNARROW = (1 << 1), + KEYMASK_UPARROW = (1 << 2), + KEYMASK_RIGHTARROW = (1 << 3), + KEYMASK_ENTER = (1 << 4), }; enum KeyScanCode { - KEY_HOME = 0x06, - KEY_END = 0x07, - KEY_PGUP = 0x08, - KEY_PGDN = 0x09, - KEY_SCROLLLOCK = 0x0A, - KEY_A = 0x10, - KEY_B = 0x11, - KEY_C = 0x12, - KEY_D = 0x13, - KEY_E = 0x14, - KEY_F = 0x15, - KEY_G = 0x16, - KEY_H = 0x17, - KEY_I = 0x18, - KEY_J = 0x19, - KEY_K = 0x1A, - KEY_L = 0x1B, - KEY_M = 0x1C, - KEY_N = 0x1D, - KEY_O = 0x1E, - KEY_P = 0x1F, - KEY_Q = 0x20, - KEY_R = 0x21, - KEY_S = 0x22, - KEY_T = 0x23, - KEY_U = 0x24, - KEY_V = 0x25, - KEY_W = 0x26, - KEY_X = 0x27, - KEY_Y = 0x28, - KEY_Z = 0x29, - KEY_1 = 0x2A, - KEY_2 = 0x2B, - KEY_3 = 0x2C, - KEY_4 = 0x2D, - KEY_5 = 0x2E, - KEY_6 = 0x2F, - KEY_7 = 0x30, - KEY_8 = 0x31, - KEY_9 = 0x32, - KEY_0 = 0x33, - KEY_MINUS = 0x34, - KEY_PLUS = 0x35, - KEY_PRINTSCR = 0x36, - KEY_BRACE_OPEN = 0x37, - KEY_BRACE_CLOSE = 0x38, - KEY_COLON = 0x39, - KEY_QUOTE = 0x3A, - KEY_HASH = 0x3B, - KEY_COMMA = 0x3C, - KEY_PERIOD = 0x3D, - KEY_QUESTIONMARK = 0x3E, - KEY_INTERNATIONAL1 = 0x3F, - KEY_F1 = 0x40, - KEY_F2 = 0x41, - KEY_F3 = 0x42, - KEY_F4 = 0x43, - KEY_F5 = 0x44, - KEY_F6 = 0x45, - KEY_F7 = 0x46, - KEY_F8 = 0x47, - KEY_F9 = 0x48, - KEY_F10 = 0x49, - KEY_F11 = 0x4A, - KEY_F12 = 0x4B, - KEY_ESC = 0x4C, - KEY_INSERT = 0x4D, - KEY_DELETE = 0x4E, - KEY_TILDE = 0x4F, - KEY_BACKSPACE = 0x50, - KEY_TAB = 0x51, - KEY_CAPSLOCK = 0x53, - KEY_LEFTSHIFT = 0x54, - KEY_RIGHTSHIFT = 0x55, - KEY_LEFTCONTROL = 0x56, - KEY_RIGHTALT = 0x57, - KEY_LEFTWINDOWS = 0x58, - KEY_SPACE = 0x59, - KEY_RIGHTWINDOWS = 0x5A, - KEY_MENU = 0x5B, - KEY_LEFTARROW = 0x5C, - KEY_DOWNARROW = 0x5D, - KEY_UPARROW = 0x5E, - KEY_RIGHTARROW = 0x5F, - KEY_ENTER = 0x61 + KEY_HOME = 0x06, + KEY_END = 0x07, + KEY_PGUP = 0x08, + KEY_PGDN = 0x09, + KEY_SCROLLLOCK = 0x0A, + KEY_A = 0x10, + KEY_B = 0x11, + KEY_C = 0x12, + KEY_D = 0x13, + KEY_E = 0x14, + KEY_F = 0x15, + KEY_G = 0x16, + KEY_H = 0x17, + KEY_I = 0x18, + KEY_J = 0x19, + KEY_K = 0x1A, + KEY_L = 0x1B, + KEY_M = 0x1C, + KEY_N = 0x1D, + KEY_O = 0x1E, + KEY_P = 0x1F, + KEY_Q = 0x20, + KEY_R = 0x21, + KEY_S = 0x22, + KEY_T = 0x23, + KEY_U = 0x24, + KEY_V = 0x25, + KEY_W = 0x26, + KEY_X = 0x27, + KEY_Y = 0x28, + KEY_Z = 0x29, + KEY_1 = 0x2A, + KEY_2 = 0x2B, + KEY_3 = 0x2C, + KEY_4 = 0x2D, + KEY_5 = 0x2E, + KEY_6 = 0x2F, + KEY_7 = 0x30, + KEY_8 = 0x31, + KEY_9 = 0x32, + KEY_0 = 0x33, + KEY_MINUS = 0x34, + KEY_PLUS = 0x35, + KEY_PRINTSCR = 0x36, + KEY_BRACE_OPEN = 0x37, + KEY_BRACE_CLOSE = 0x38, + KEY_COLON = 0x39, + KEY_QUOTE = 0x3A, + KEY_HASH = 0x3B, + KEY_COMMA = 0x3C, + KEY_PERIOD = 0x3D, + KEY_QUESTIONMARK = 0x3E, + KEY_INTERNATIONAL1 = 0x3F, + KEY_F1 = 0x40, + KEY_F2 = 0x41, + KEY_F3 = 0x42, + KEY_F4 = 0x43, + KEY_F5 = 0x44, + KEY_F6 = 0x45, + KEY_F7 = 0x46, + KEY_F8 = 0x47, + KEY_F9 = 0x48, + KEY_F10 = 0x49, + KEY_F11 = 0x4A, + KEY_F12 = 0x4B, + KEY_ESC = 0x4C, + KEY_INSERT = 0x4D, + KEY_DELETE = 0x4E, + KEY_TILDE = 0x4F, + KEY_BACKSPACE = 0x50, + KEY_TAB = 0x51, + KEY_CAPSLOCK = 0x53, + KEY_LEFTSHIFT = 0x54, + KEY_RIGHTSHIFT = 0x55, + KEY_LEFTCONTROL = 0x56, + KEY_RIGHTALT = 0x57, + KEY_LEFTWINDOWS = 0x58, + KEY_SPACE = 0x59, + KEY_RIGHTWINDOWS = 0x5A, + KEY_MENU = 0x5B, + KEY_LEFTARROW = 0x5C, + KEY_DOWNARROW = 0x5D, + KEY_UPARROW = 0x5E, + KEY_RIGHTARROW = 0x5F, + KEY_ENTER = 0x61 }; struct KeyboardStatus { - u16 key0x; - u16 key1x; - u16 key2x; - u16 key3x; - u16 key4x; - u16 key5x; - u16 key6x; - s8 err; + u16 key0x; + u16 key1x; + u16 key2x; + u16 key3x; + u16 key4x; + u16 key5x; + u16 key6x; + s8 err; }; diff --git a/Source/Core/UICommon/Disassembler.cpp b/Source/Core/UICommon/Disassembler.cpp index 22865a366e..6d0a4fb014 100644 --- a/Source/Core/UICommon/Disassembler.cpp +++ b/Source/Core/UICommon/Disassembler.cpp @@ -1,4 +1,4 @@ -#include // Bochs +#include // Bochs #if defined(HAS_LLVM) // PowerPC.h defines PC. @@ -10,170 +10,178 @@ #include "Common/StringUtil.h" -#include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/JitCommon/JitBase.h" #include "Core/PowerPC/JitCommon/JitCache.h" +#include "Core/PowerPC/JitInterface.h" #include "UICommon/Disassembler.h" class HostDisassemblerX86 : public HostDisassembler { public: - HostDisassemblerX86(); + HostDisassemblerX86(); private: - disassembler m_disasm; + disassembler m_disasm; - std::string DisassembleHostBlock(const u8* code_start, const u32 code_size, u32* host_instructions_count, u64 starting_pc) override; + std::string DisassembleHostBlock(const u8* code_start, const u32 code_size, + u32* host_instructions_count, u64 starting_pc) override; }; #if defined(HAS_LLVM) class HostDisassemblerLLVM : public HostDisassembler { public: - HostDisassemblerLLVM(const std::string& host_disasm, int inst_size = -1, const std::string& cpu = ""); - ~HostDisassemblerLLVM() - { - if (m_can_disasm) - LLVMDisasmDispose(m_llvm_context); - } + HostDisassemblerLLVM(const std::string& host_disasm, int inst_size = -1, + const std::string& cpu = ""); + ~HostDisassemblerLLVM() + { + if (m_can_disasm) + LLVMDisasmDispose(m_llvm_context); + } private: - bool m_can_disasm; - LLVMDisasmContextRef m_llvm_context; - int m_instruction_size; + bool m_can_disasm; + LLVMDisasmContextRef m_llvm_context; + int m_instruction_size; - std::string DisassembleHostBlock(const u8* code_start, const u32 code_size, u32* host_instructions_count, u64 starting_pc) override; + std::string DisassembleHostBlock(const u8* code_start, const u32 code_size, + u32* host_instructions_count, u64 starting_pc) override; }; -HostDisassemblerLLVM::HostDisassemblerLLVM(const std::string& host_disasm, int inst_size, const std::string& cpu) - : m_can_disasm(false), m_instruction_size(inst_size) +HostDisassemblerLLVM::HostDisassemblerLLVM(const std::string& host_disasm, int inst_size, + const std::string& cpu) + : m_can_disasm(false), m_instruction_size(inst_size) { - LLVMInitializeAllTargetInfos(); - LLVMInitializeAllTargetMCs(); - LLVMInitializeAllDisassemblers(); + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllDisassemblers(); - m_llvm_context = LLVMCreateDisasmCPU(host_disasm.c_str(), cpu.c_str(), nullptr, 0, 0, nullptr); + m_llvm_context = LLVMCreateDisasmCPU(host_disasm.c_str(), cpu.c_str(), nullptr, 0, 0, nullptr); - // Couldn't create llvm context - if (!m_llvm_context) - return; + // Couldn't create llvm context + if (!m_llvm_context) + return; - LLVMSetDisasmOptions(m_llvm_context, - LLVMDisassembler_Option_AsmPrinterVariant | - LLVMDisassembler_Option_PrintLatency); + LLVMSetDisasmOptions(m_llvm_context, LLVMDisassembler_Option_AsmPrinterVariant | + LLVMDisassembler_Option_PrintLatency); - m_can_disasm = true; + m_can_disasm = true; } -std::string HostDisassemblerLLVM::DisassembleHostBlock(const u8* code_start, const u32 code_size, u32 *host_instructions_count, u64 starting_pc) +std::string HostDisassemblerLLVM::DisassembleHostBlock(const u8* code_start, const u32 code_size, + u32* host_instructions_count, + u64 starting_pc) { - if (!m_can_disasm) - return "(No LLVM context)"; + if (!m_can_disasm) + return "(No LLVM context)"; - u8* disasmPtr = (u8*)code_start; - const u8 *end = code_start + code_size; + u8* disasmPtr = (u8*)code_start; + const u8* end = code_start + code_size; - std::ostringstream x86_disasm; - while ((u8*)disasmPtr < end) - { - char inst_disasm[256]; - size_t inst_size = LLVMDisasmInstruction(m_llvm_context, disasmPtr, (u64)(end - disasmPtr), starting_pc, inst_disasm, 256); + std::ostringstream x86_disasm; + while ((u8*)disasmPtr < end) + { + char inst_disasm[256]; + size_t inst_size = LLVMDisasmInstruction(m_llvm_context, disasmPtr, (u64)(end - disasmPtr), + starting_pc, inst_disasm, 256); - x86_disasm << "0x" << std::hex << starting_pc << "\t"; - if (!inst_size) - { - x86_disasm << "Invalid inst:"; + x86_disasm << "0x" << std::hex << starting_pc << "\t"; + if (!inst_size) + { + x86_disasm << "Invalid inst:"; - if (m_instruction_size != -1) - { - // If we are on an architecture that has a fixed instruction size - // We can continue onward past this bad instruction. - std::string inst_str = ""; - for (int i = 0; i < m_instruction_size; ++i) - inst_str += StringFromFormat("%02x", disasmPtr[i]); + if (m_instruction_size != -1) + { + // If we are on an architecture that has a fixed instruction size + // We can continue onward past this bad instruction. + std::string inst_str = ""; + for (int i = 0; i < m_instruction_size; ++i) + inst_str += StringFromFormat("%02x", disasmPtr[i]); - x86_disasm << inst_str << std::endl; - disasmPtr += m_instruction_size; - } - else - { - // We can't continue if we are on an architecture that has flexible instruction sizes - // Dump the rest of the block instead - std::string code_block = ""; - for (int i = 0; (disasmPtr + i) < end; ++i) - code_block += StringFromFormat("%02x", disasmPtr[i]); + x86_disasm << inst_str << std::endl; + disasmPtr += m_instruction_size; + } + else + { + // We can't continue if we are on an architecture that has flexible instruction sizes + // Dump the rest of the block instead + std::string code_block = ""; + for (int i = 0; (disasmPtr + i) < end; ++i) + code_block += StringFromFormat("%02x", disasmPtr[i]); - x86_disasm << code_block << std::endl; - break; - } - } - else - { - x86_disasm << inst_disasm << std::endl; - disasmPtr += inst_size; - starting_pc += inst_size; - } + x86_disasm << code_block << std::endl; + break; + } + } + else + { + x86_disasm << inst_disasm << std::endl; + disasmPtr += inst_size; + starting_pc += inst_size; + } - (*host_instructions_count)++; - } + (*host_instructions_count)++; + } - return x86_disasm.str(); + return x86_disasm.str(); } #endif HostDisassemblerX86::HostDisassemblerX86() { - m_disasm.set_syntax_intel(); + m_disasm.set_syntax_intel(); } -std::string HostDisassemblerX86::DisassembleHostBlock(const u8* code_start, const u32 code_size, u32* host_instructions_count, u64 starting_pc) +std::string HostDisassemblerX86::DisassembleHostBlock(const u8* code_start, const u32 code_size, + u32* host_instructions_count, u64 starting_pc) { - u64 disasmPtr = (u64)code_start; - const u8* end = code_start + code_size; + u64 disasmPtr = (u64)code_start; + const u8* end = code_start + code_size; - std::ostringstream x86_disasm; - while ((u8*)disasmPtr < end) - { - char inst_disasm[256]; - disasmPtr += m_disasm.disasm64(disasmPtr, disasmPtr, (u8*)disasmPtr, inst_disasm); - x86_disasm << inst_disasm << std::endl; - (*host_instructions_count)++; - } + std::ostringstream x86_disasm; + while ((u8*)disasmPtr < end) + { + char inst_disasm[256]; + disasmPtr += m_disasm.disasm64(disasmPtr, disasmPtr, (u8*)disasmPtr, inst_disasm); + x86_disasm << inst_disasm << std::endl; + (*host_instructions_count)++; + } - return x86_disasm.str(); + return x86_disasm.str(); } HostDisassembler* GetNewDisassembler(const std::string& arch) { #if defined(HAS_LLVM) - if (arch == "x86") - return new HostDisassemblerLLVM("x86_64-none-unknown"); - else if (arch == "aarch64") - return new HostDisassemblerLLVM("aarch64-none-unknown", 4, "cortex-a57"); - else if (arch == "armv7") - return new HostDisassemblerLLVM("armv7-none-unknown", 4, "cortex-a15"); + if (arch == "x86") + return new HostDisassemblerLLVM("x86_64-none-unknown"); + else if (arch == "aarch64") + return new HostDisassemblerLLVM("aarch64-none-unknown", 4, "cortex-a57"); + else if (arch == "armv7") + return new HostDisassemblerLLVM("armv7-none-unknown", 4, "cortex-a15"); #elif defined(_M_X86) - if (arch == "x86") - return new HostDisassemblerX86(); + if (arch == "x86") + return new HostDisassemblerX86(); #endif - return new HostDisassembler(); + return new HostDisassembler(); } -std::string DisassembleBlock(HostDisassembler* disasm, u32* address, u32* host_instructions_count, u32* code_size) +std::string DisassembleBlock(HostDisassembler* disasm, u32* address, u32* host_instructions_count, + u32* code_size) { - const u8* code; - int res = JitInterface::GetHostCode(address, &code, code_size); + const u8* code; + int res = JitInterface::GetHostCode(address, &code, code_size); - if (res == 1) - { - *host_instructions_count = 0; - return "(No JIT active)"; - } - else if (res == 2) - { - host_instructions_count = 0; - return "(No translation)"; - } - return disasm->DisassembleHostBlock(code, *code_size, host_instructions_count, (u64)code); + if (res == 1) + { + *host_instructions_count = 0; + return "(No JIT active)"; + } + else if (res == 2) + { + host_instructions_count = 0; + return "(No translation)"; + } + return disasm->DisassembleHostBlock(code, *code_size, host_instructions_count, (u64)code); } diff --git a/Source/Core/UICommon/Disassembler.h b/Source/Core/UICommon/Disassembler.h index 2dcb9757d2..5d1d7eabb4 100644 --- a/Source/Core/UICommon/Disassembler.h +++ b/Source/Core/UICommon/Disassembler.h @@ -9,9 +9,14 @@ class HostDisassembler { public: - virtual ~HostDisassembler() {} - virtual std::string DisassembleHostBlock(const u8* code_start, const u32 code_size, u32* host_instructions_count, u64 starting_pc) { return "(No disassembler)"; } + virtual ~HostDisassembler() {} + virtual std::string DisassembleHostBlock(const u8* code_start, const u32 code_size, + u32* host_instructions_count, u64 starting_pc) + { + return "(No disassembler)"; + } }; HostDisassembler* GetNewDisassembler(const std::string& arch); -std::string DisassembleBlock(HostDisassembler* disasm, u32* address, u32* host_instructions_count, u32* code_size); +std::string DisassembleBlock(HostDisassembler* disasm, u32* address, u32* host_instructions_count, + u32* code_size); diff --git a/Source/Core/UICommon/UICommon.cpp b/Source/Core/UICommon/UICommon.cpp index 9d85ebb8a1..0308fc42bd 100644 --- a/Source/Core/UICommon/UICommon.cpp +++ b/Source/Core/UICommon/UICommon.cpp @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #ifdef _WIN32 -#include // for SHGetFolderPath +#include // for SHGetFolderPath #endif #include "Common/CommonPaths.h" @@ -21,163 +21,167 @@ namespace UICommon { - void Init() { - LogManager::Init(); - SConfig::Init(); - VideoBackendBase::PopulateList(); - WiimoteReal::LoadSettings(); - GCAdapter::Init(); - VideoBackendBase::ActivateBackend(SConfig::GetInstance().m_strVideoBackend); + LogManager::Init(); + SConfig::Init(); + VideoBackendBase::PopulateList(); + WiimoteReal::LoadSettings(); + GCAdapter::Init(); + VideoBackendBase::ActivateBackend(SConfig::GetInstance().m_strVideoBackend); - SetEnableAlert(SConfig::GetInstance().bUsePanicHandlers); + SetEnableAlert(SConfig::GetInstance().bUsePanicHandlers); } void Shutdown() { - GCAdapter::Shutdown(); - WiimoteReal::Shutdown(); - VideoBackendBase::ClearList(); - SConfig::Shutdown(); - LogManager::Shutdown(); + GCAdapter::Shutdown(); + WiimoteReal::Shutdown(); + VideoBackendBase::ClearList(); + SConfig::Shutdown(); + LogManager::Shutdown(); } void CreateDirectories() { - // Copy initial Wii NAND data from Sys to User. - File::CopyDir(File::GetSysDirectory() + WII_USER_DIR, - File::GetUserPath(D_WIIROOT_IDX)); + // Copy initial Wii NAND data from Sys to User. + File::CopyDir(File::GetSysDirectory() + WII_USER_DIR, File::GetUserPath(D_WIIROOT_IDX)); - File::CreateFullPath(File::GetUserPath(D_USER_IDX)); - File::CreateFullPath(File::GetUserPath(D_CACHE_IDX)); - File::CreateFullPath(File::GetUserPath(D_CONFIG_IDX)); - File::CreateFullPath(File::GetUserPath(D_DUMPDSP_IDX)); - File::CreateFullPath(File::GetUserPath(D_DUMPTEXTURES_IDX)); - File::CreateFullPath(File::GetUserPath(D_GAMESETTINGS_IDX)); - File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX)); - File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + USA_DIR DIR_SEP); - File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + EUR_DIR DIR_SEP); - File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + JAP_DIR DIR_SEP); - File::CreateFullPath(File::GetUserPath(D_HIRESTEXTURES_IDX)); - File::CreateFullPath(File::GetUserPath(D_MAILLOGS_IDX)); - File::CreateFullPath(File::GetUserPath(D_MAPS_IDX)); - File::CreateFullPath(File::GetUserPath(D_SCREENSHOTS_IDX)); - File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX)); - File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX) + ANAGLYPH_DIR DIR_SEP); - File::CreateFullPath(File::GetUserPath(D_STATESAVES_IDX)); - File::CreateFullPath(File::GetUserPath(D_THEMES_IDX)); + File::CreateFullPath(File::GetUserPath(D_USER_IDX)); + File::CreateFullPath(File::GetUserPath(D_CACHE_IDX)); + File::CreateFullPath(File::GetUserPath(D_CONFIG_IDX)); + File::CreateFullPath(File::GetUserPath(D_DUMPDSP_IDX)); + File::CreateFullPath(File::GetUserPath(D_DUMPTEXTURES_IDX)); + File::CreateFullPath(File::GetUserPath(D_GAMESETTINGS_IDX)); + File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX)); + File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + USA_DIR DIR_SEP); + File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + EUR_DIR DIR_SEP); + File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + JAP_DIR DIR_SEP); + File::CreateFullPath(File::GetUserPath(D_HIRESTEXTURES_IDX)); + File::CreateFullPath(File::GetUserPath(D_MAILLOGS_IDX)); + File::CreateFullPath(File::GetUserPath(D_MAPS_IDX)); + File::CreateFullPath(File::GetUserPath(D_SCREENSHOTS_IDX)); + File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX)); + File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX) + ANAGLYPH_DIR DIR_SEP); + File::CreateFullPath(File::GetUserPath(D_STATESAVES_IDX)); + File::CreateFullPath(File::GetUserPath(D_THEMES_IDX)); } void SetUserDirectory(const std::string& custom_path) { - if (!custom_path.empty()) - { - File::CreateFullPath(custom_path + DIR_SEP); - File::SetUserPath(D_USER_IDX, custom_path + DIR_SEP); - return; - } + if (!custom_path.empty()) + { + File::CreateFullPath(custom_path + DIR_SEP); + File::SetUserPath(D_USER_IDX, custom_path + DIR_SEP); + return; + } - std::string user_path = ""; + std::string user_path = ""; #ifdef _WIN32 - // Detect where the User directory is. There are five different cases (on top of the - // command line flag, which overrides all this): - // 1. GetExeDirectory()\portable.txt exists - // -> Use GetExeDirectory()\User - // 2. HKCU\Software\Dolphin Emulator\LocalUserConfig exists and is true - // -> Use GetExeDirectory()\User - // 3. HKCU\Software\Dolphin Emulator\UserConfigPath exists - // -> Use this as the user directory path - // 4. My Documents exists - // -> Use My Documents\Dolphin Emulator as the User directory path - // 5. Default - // -> Use GetExeDirectory()\User + // Detect where the User directory is. There are five different cases (on top of the + // command line flag, which overrides all this): + // 1. GetExeDirectory()\portable.txt exists + // -> Use GetExeDirectory()\User + // 2. HKCU\Software\Dolphin Emulator\LocalUserConfig exists and is true + // -> Use GetExeDirectory()\User + // 3. HKCU\Software\Dolphin Emulator\UserConfigPath exists + // -> Use this as the user directory path + // 4. My Documents exists + // -> Use My Documents\Dolphin Emulator as the User directory path + // 5. Default + // -> Use GetExeDirectory()\User - // Check our registry keys - HKEY hkey; - DWORD local = 0; - TCHAR configPath[MAX_PATH] = {0}; - if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Dolphin Emulator"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) - { - DWORD size = 4; - if (RegQueryValueEx(hkey, TEXT("LocalUserConfig"), nullptr, nullptr, reinterpret_cast(&local), &size) != ERROR_SUCCESS) - local = 0; + // Check our registry keys + HKEY hkey; + DWORD local = 0; + TCHAR configPath[MAX_PATH] = {0}; + if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Dolphin Emulator"), 0, KEY_QUERY_VALUE, + &hkey) == ERROR_SUCCESS) + { + DWORD size = 4; + if (RegQueryValueEx(hkey, TEXT("LocalUserConfig"), nullptr, nullptr, + reinterpret_cast(&local), &size) != ERROR_SUCCESS) + local = 0; - size = MAX_PATH; - if (RegQueryValueEx(hkey, TEXT("UserConfigPath"), nullptr, nullptr, (LPBYTE)configPath, &size) != ERROR_SUCCESS) - configPath[0] = 0; - RegCloseKey(hkey); - } + size = MAX_PATH; + if (RegQueryValueEx(hkey, TEXT("UserConfigPath"), nullptr, nullptr, (LPBYTE)configPath, + &size) != ERROR_SUCCESS) + configPath[0] = 0; + RegCloseKey(hkey); + } - local = local || File::Exists(File::GetExeDirectory() + DIR_SEP "portable.txt"); + local = local || File::Exists(File::GetExeDirectory() + DIR_SEP "portable.txt"); - // Get Program Files path in case we need it. - TCHAR my_documents[MAX_PATH]; - bool my_documents_found = SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, my_documents)); + // Get Program Files path in case we need it. + TCHAR my_documents[MAX_PATH]; + bool my_documents_found = SUCCEEDED( + SHGetFolderPath(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, my_documents)); - if (local) // Case 1-2 - user_path = File::GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; - else if (configPath[0]) // Case 3 - user_path = TStrToUTF8(configPath); - else if (my_documents_found) // Case 4 - user_path = TStrToUTF8(my_documents) + DIR_SEP "Dolphin Emulator" DIR_SEP; - else // Case 5 - user_path = File::GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; + if (local) // Case 1-2 + user_path = File::GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; + else if (configPath[0]) // Case 3 + user_path = TStrToUTF8(configPath); + else if (my_documents_found) // Case 4 + user_path = TStrToUTF8(my_documents) + DIR_SEP "Dolphin Emulator" DIR_SEP; + else // Case 5 + user_path = File::GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; - // Prettify the path: it will be displayed in some places, we don't want a mix of \ and /. - user_path = ReplaceAll(user_path, "\\", DIR_SEP); + // Prettify the path: it will be displayed in some places, we don't want a mix of \ and /. + user_path = ReplaceAll(user_path, "\\", DIR_SEP); - // Make sure it ends in DIR_SEP. - if (*user_path.rbegin() != DIR_SEP_CHR) - user_path += DIR_SEP; + // Make sure it ends in DIR_SEP. + if (*user_path.rbegin() != DIR_SEP_CHR) + user_path += DIR_SEP; #else - if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) - { - user_path = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; - } - else - { - const char* home = getenv("HOME"); - if (!home) - home = getenv("PWD"); - if (!home) - home = ""; - std::string home_path = std::string(home) + DIR_SEP; + if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) + { + user_path = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; + } + else + { + const char* home = getenv("HOME"); + if (!home) + home = getenv("PWD"); + if (!home) + home = ""; + std::string home_path = std::string(home) + DIR_SEP; #if defined(__APPLE__) || defined(ANDROID) - user_path = home_path + DOLPHIN_DATA_DIR DIR_SEP; + user_path = home_path + DOLPHIN_DATA_DIR DIR_SEP; #else - // We are on a non-Apple and non-Android POSIX system, let's respect XDG basedir. - // The only case we don't is when there is an existing ~/.dolphin-emu directory. - // See http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + // We are on a non-Apple and non-Android POSIX system, let's respect XDG basedir. + // The only case we don't is when there is an existing ~/.dolphin-emu directory. + // See http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html - user_path = home_path + "." DOLPHIN_DATA_DIR DIR_SEP; - if (!File::Exists(user_path)) - { - const char* data_home = getenv("XDG_DATA_HOME"); - std::string data_path = std::string(data_home && data_home[0] == '/' ? - data_home : - (home_path + ".local" DIR_SEP "share")) + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; + user_path = home_path + "." DOLPHIN_DATA_DIR DIR_SEP; + if (!File::Exists(user_path)) + { + const char* data_home = getenv("XDG_DATA_HOME"); + std::string data_path = + std::string(data_home && data_home[0] == '/' ? data_home : + (home_path + ".local" DIR_SEP "share")) + + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; - const char* config_home = getenv("XDG_CONFIG_HOME"); - std::string config_path = std::string(config_home && config_home[0] == '/' ? - config_home : - (home_path + ".config")) + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; + const char* config_home = getenv("XDG_CONFIG_HOME"); + std::string config_path = + std::string(config_home && config_home[0] == '/' ? config_home : + (home_path + ".config")) + + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; - const char* cache_home = getenv("XDG_CACHE_HOME"); - std::string cache_path = std::string(cache_home && cache_home[0] == '/' ? - cache_home : - (home_path + ".cache")) + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; + const char* cache_home = getenv("XDG_CACHE_HOME"); + std::string cache_path = + std::string(cache_home && cache_home[0] == '/' ? cache_home : (home_path + ".cache")) + + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; - File::SetUserPath(D_USER_IDX, data_path); - File::SetUserPath(D_CONFIG_IDX, config_path); - File::SetUserPath(D_CACHE_IDX, cache_path); - return; - } + File::SetUserPath(D_USER_IDX, data_path); + File::SetUserPath(D_CONFIG_IDX, config_path); + File::SetUserPath(D_CACHE_IDX, cache_path); + return; + } #endif - } + } #endif - File::SetUserPath(D_USER_IDX, user_path); + File::SetUserPath(D_USER_IDX, user_path); } -} // namespace UICommon +} // namespace UICommon diff --git a/Source/Core/UICommon/UICommon.h b/Source/Core/UICommon/UICommon.h index 136d955eda..e9e3be5f99 100644 --- a/Source/Core/UICommon/UICommon.h +++ b/Source/Core/UICommon/UICommon.h @@ -6,11 +6,10 @@ namespace UICommon { - void Init(); void Shutdown(); void CreateDirectories(); void SetUserDirectory(const std::string& custom_path); -} // namespace UICommon +} // namespace UICommon diff --git a/Source/Core/VideoBackends/D3D/BoundingBox.cpp b/Source/Core/VideoBackends/D3D/BoundingBox.cpp index 52e08d8f40..e52ebb9c6d 100644 --- a/Source/Core/VideoBackends/D3D/BoundingBox.cpp +++ b/Source/Core/VideoBackends/D3D/BoundingBox.cpp @@ -2,86 +2,85 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoBackends/D3D/BoundingBox.h" #include "Common/CommonTypes.h" #include "Common/MsgHandler.h" -#include "VideoBackends/D3D/BoundingBox.h" #include "VideoCommon/VideoConfig.h" namespace DX11 { - static ID3D11Buffer* s_bbox_buffer; static ID3D11Buffer* s_bbox_staging_buffer; -static ID3D11UnorderedAccessView* s_bbox_uav; +static ID3D11UnorderedAccessView* s_bbox_uav; -ID3D11UnorderedAccessView* &BBox::GetUAV() +ID3D11UnorderedAccessView*& BBox::GetUAV() { - return s_bbox_uav; + return s_bbox_uav; } void BBox::Init() { - if (g_ActiveConfig.backend_info.bSupportsBBox) - { - // Create 2 buffers here. - // First for unordered access on default pool. - auto desc = CD3D11_BUFFER_DESC(4 * sizeof(s32), D3D11_BIND_UNORDERED_ACCESS, D3D11_USAGE_DEFAULT, 0, 0, 4); - int initial_values[4] = { 0, 0, 0, 0 }; - D3D11_SUBRESOURCE_DATA data; - data.pSysMem = initial_values; - data.SysMemPitch = 4 * sizeof(s32); - data.SysMemSlicePitch = 0; - HRESULT hr; - hr = D3D::device->CreateBuffer(&desc, &data, &s_bbox_buffer); - CHECK(SUCCEEDED(hr), "Create BoundingBox Buffer."); - D3D::SetDebugObjectName(s_bbox_buffer, "BoundingBox Buffer"); + if (g_ActiveConfig.backend_info.bSupportsBBox) + { + // Create 2 buffers here. + // First for unordered access on default pool. + auto desc = CD3D11_BUFFER_DESC(4 * sizeof(s32), D3D11_BIND_UNORDERED_ACCESS, + D3D11_USAGE_DEFAULT, 0, 0, 4); + int initial_values[4] = {0, 0, 0, 0}; + D3D11_SUBRESOURCE_DATA data; + data.pSysMem = initial_values; + data.SysMemPitch = 4 * sizeof(s32); + data.SysMemSlicePitch = 0; + HRESULT hr; + hr = D3D::device->CreateBuffer(&desc, &data, &s_bbox_buffer); + CHECK(SUCCEEDED(hr), "Create BoundingBox Buffer."); + D3D::SetDebugObjectName(s_bbox_buffer, "BoundingBox Buffer"); - // Second to use as a staging buffer. - desc.Usage = D3D11_USAGE_STAGING; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - desc.BindFlags = 0; - hr = D3D::device->CreateBuffer(&desc, nullptr, &s_bbox_staging_buffer); - CHECK(SUCCEEDED(hr), "Create BoundingBox Staging Buffer."); - D3D::SetDebugObjectName(s_bbox_staging_buffer, "BoundingBox Staging Buffer"); + // Second to use as a staging buffer. + desc.Usage = D3D11_USAGE_STAGING; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.BindFlags = 0; + hr = D3D::device->CreateBuffer(&desc, nullptr, &s_bbox_staging_buffer); + CHECK(SUCCEEDED(hr), "Create BoundingBox Staging Buffer."); + D3D::SetDebugObjectName(s_bbox_staging_buffer, "BoundingBox Staging Buffer"); - // UAV is required to allow concurrent access. - D3D11_UNORDERED_ACCESS_VIEW_DESC UAVdesc = {}; - UAVdesc.Format = DXGI_FORMAT_R32_SINT; - UAVdesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; - UAVdesc.Buffer.FirstElement = 0; - UAVdesc.Buffer.Flags = 0; - UAVdesc.Buffer.NumElements = 4; - hr = D3D::device->CreateUnorderedAccessView(s_bbox_buffer, &UAVdesc, &s_bbox_uav); - CHECK(SUCCEEDED(hr), "Create BoundingBox UAV."); - D3D::SetDebugObjectName(s_bbox_uav, "BoundingBox UAV"); - } + // UAV is required to allow concurrent access. + D3D11_UNORDERED_ACCESS_VIEW_DESC UAVdesc = {}; + UAVdesc.Format = DXGI_FORMAT_R32_SINT; + UAVdesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + UAVdesc.Buffer.FirstElement = 0; + UAVdesc.Buffer.Flags = 0; + UAVdesc.Buffer.NumElements = 4; + hr = D3D::device->CreateUnorderedAccessView(s_bbox_buffer, &UAVdesc, &s_bbox_uav); + CHECK(SUCCEEDED(hr), "Create BoundingBox UAV."); + D3D::SetDebugObjectName(s_bbox_uav, "BoundingBox UAV"); + } } void BBox::Shutdown() { - SAFE_RELEASE(s_bbox_buffer); - SAFE_RELEASE(s_bbox_staging_buffer); - SAFE_RELEASE(s_bbox_uav); + SAFE_RELEASE(s_bbox_buffer); + SAFE_RELEASE(s_bbox_staging_buffer); + SAFE_RELEASE(s_bbox_uav); } void BBox::Set(int index, int value) { - D3D11_BOX box{ index * sizeof(s32), 0, 0, (index + 1) * sizeof(s32), 1, 1 }; - D3D::context->UpdateSubresource(s_bbox_buffer, 0, &box, &value, 0, 0); + D3D11_BOX box{index * sizeof(s32), 0, 0, (index + 1) * sizeof(s32), 1, 1}; + D3D::context->UpdateSubresource(s_bbox_buffer, 0, &box, &value, 0, 0); } int BBox::Get(int index) { - int data = 0; - D3D::context->CopyResource(s_bbox_staging_buffer, s_bbox_buffer); - D3D11_MAPPED_SUBRESOURCE map; - HRESULT hr = D3D::context->Map(s_bbox_staging_buffer, 0, D3D11_MAP_READ, 0, &map); - if (SUCCEEDED(hr)) - { - data = ((s32*)map.pData)[index]; - } - D3D::context->Unmap(s_bbox_staging_buffer, 0); - return data; + int data = 0; + D3D::context->CopyResource(s_bbox_staging_buffer, s_bbox_buffer); + D3D11_MAPPED_SUBRESOURCE map; + HRESULT hr = D3D::context->Map(s_bbox_staging_buffer, 0, D3D11_MAP_READ, 0, &map); + if (SUCCEEDED(hr)) + { + data = ((s32*)map.pData)[index]; + } + D3D::context->Unmap(s_bbox_staging_buffer, 0); + return data; } - }; diff --git a/Source/Core/VideoBackends/D3D/BoundingBox.h b/Source/Core/VideoBackends/D3D/BoundingBox.h index 8fd359a356..e46add7f37 100644 --- a/Source/Core/VideoBackends/D3D/BoundingBox.h +++ b/Source/Core/VideoBackends/D3D/BoundingBox.h @@ -7,16 +7,14 @@ namespace DX11 { - class BBox { public: - static ID3D11UnorderedAccessView* &GetUAV(); - static void Init(); - static void Shutdown(); + static ID3D11UnorderedAccessView*& GetUAV(); + static void Init(); + static void Shutdown(); - static void Set(int index, int value); - static int Get(int index); + static void Set(int index, int value); + static int Get(int index); }; - }; diff --git a/Source/Core/VideoBackends/D3D/D3DBase.cpp b/Source/Core/VideoBackends/D3D/D3DBase.cpp index 5a4174ce99..55f3e524bd 100644 --- a/Source/Core/VideoBackends/D3D/D3DBase.cpp +++ b/Source/Core/VideoBackends/D3D/D3DBase.cpp @@ -5,9 +5,9 @@ #include #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DTexture.h" @@ -15,7 +15,6 @@ namespace DX11 { - HINSTANCE hD3DCompilerDll = nullptr; D3DREFLECT PD3DReflect = nullptr; pD3DCompile PD3DCompile = nullptr; @@ -25,7 +24,11 @@ CREATEDXGIFACTORY PCreateDXGIFactory = nullptr; HINSTANCE hDXGIDll = nullptr; int dxgi_dll_ref = 0; -typedef HRESULT (WINAPI* D3D11CREATEDEVICEANDSWAPCHAIN)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL*, UINT, UINT, CONST DXGI_SWAP_CHAIN_DESC*, IDXGISwapChain**, ID3D11Device**, D3D_FEATURE_LEVEL*, ID3D11DeviceContext**); +typedef HRESULT(WINAPI* D3D11CREATEDEVICEANDSWAPCHAIN)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, + UINT, CONST D3D_FEATURE_LEVEL*, UINT, UINT, + CONST DXGI_SWAP_CHAIN_DESC*, + IDXGISwapChain**, ID3D11Device**, + D3D_FEATURE_LEVEL*, ID3D11DeviceContext**); static D3D11CREATEDEVICE PD3D11CreateDevice = nullptr; D3D11CREATEDEVICEANDSWAPCHAIN PD3D11CreateDeviceAndSwapChain = nullptr; HINSTANCE hD3DDll = nullptr; @@ -33,7 +36,6 @@ int d3d_dll_ref = 0; namespace D3D { - ID3D11Device* device = nullptr; ID3D11DeviceContext* context = nullptr; static IDXGISwapChain* swapchain = nullptr; @@ -42,16 +44,13 @@ D3D_FEATURE_LEVEL featlevel; D3DTexture2D* backbuf = nullptr; HWND hWnd; -std::vector aa_modes; // supported AA modes of the current adapter +std::vector aa_modes; // supported AA modes of the current adapter bool bgra_textures_supported; #define NUM_SUPPORTED_FEATURE_LEVELS 3 const D3D_FEATURE_LEVEL supported_feature_levels[NUM_SUPPORTED_FEATURE_LEVELS] = { - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0 -}; + D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0}; unsigned int xres, yres; @@ -59,500 +58,569 @@ bool bFrameInProgress = false; HRESULT LoadDXGI() { - if (dxgi_dll_ref++ > 0) return S_OK; + if (dxgi_dll_ref++ > 0) + return S_OK; - if (hDXGIDll) return S_OK; - hDXGIDll = LoadLibraryA("dxgi.dll"); - if (!hDXGIDll) - { - MessageBoxA(nullptr, "Failed to load dxgi.dll", "Critical error", MB_OK | MB_ICONERROR); - --dxgi_dll_ref; - return E_FAIL; - } - PCreateDXGIFactory = (CREATEDXGIFACTORY)GetProcAddress(hDXGIDll, "CreateDXGIFactory"); - if (PCreateDXGIFactory == nullptr) MessageBoxA(nullptr, "GetProcAddress failed for CreateDXGIFactory!", "Critical error", MB_OK | MB_ICONERROR); + if (hDXGIDll) + return S_OK; + hDXGIDll = LoadLibraryA("dxgi.dll"); + if (!hDXGIDll) + { + MessageBoxA(nullptr, "Failed to load dxgi.dll", "Critical error", MB_OK | MB_ICONERROR); + --dxgi_dll_ref; + return E_FAIL; + } + PCreateDXGIFactory = (CREATEDXGIFACTORY)GetProcAddress(hDXGIDll, "CreateDXGIFactory"); + if (PCreateDXGIFactory == nullptr) + MessageBoxA(nullptr, "GetProcAddress failed for CreateDXGIFactory!", "Critical error", + MB_OK | MB_ICONERROR); - return S_OK; + return S_OK; } HRESULT LoadD3D() { - if (d3d_dll_ref++ > 0) return S_OK; + if (d3d_dll_ref++ > 0) + return S_OK; - if (hD3DDll) return S_OK; - hD3DDll = LoadLibraryA("d3d11.dll"); - if (!hD3DDll) - { - MessageBoxA(nullptr, "Failed to load d3d11.dll", "Critical error", MB_OK | MB_ICONERROR); - --d3d_dll_ref; - return E_FAIL; - } - PD3D11CreateDevice = (D3D11CREATEDEVICE)GetProcAddress(hD3DDll, "D3D11CreateDevice"); - if (PD3D11CreateDevice == nullptr) MessageBoxA(nullptr, "GetProcAddress failed for D3D11CreateDevice!", "Critical error", MB_OK | MB_ICONERROR); + if (hD3DDll) + return S_OK; + hD3DDll = LoadLibraryA("d3d11.dll"); + if (!hD3DDll) + { + MessageBoxA(nullptr, "Failed to load d3d11.dll", "Critical error", MB_OK | MB_ICONERROR); + --d3d_dll_ref; + return E_FAIL; + } + PD3D11CreateDevice = (D3D11CREATEDEVICE)GetProcAddress(hD3DDll, "D3D11CreateDevice"); + if (PD3D11CreateDevice == nullptr) + MessageBoxA(nullptr, "GetProcAddress failed for D3D11CreateDevice!", "Critical error", + MB_OK | MB_ICONERROR); - PD3D11CreateDeviceAndSwapChain = (D3D11CREATEDEVICEANDSWAPCHAIN)GetProcAddress(hD3DDll, "D3D11CreateDeviceAndSwapChain"); - if (PD3D11CreateDeviceAndSwapChain == nullptr) MessageBoxA(nullptr, "GetProcAddress failed for D3D11CreateDeviceAndSwapChain!", "Critical error", MB_OK | MB_ICONERROR); + PD3D11CreateDeviceAndSwapChain = + (D3D11CREATEDEVICEANDSWAPCHAIN)GetProcAddress(hD3DDll, "D3D11CreateDeviceAndSwapChain"); + if (PD3D11CreateDeviceAndSwapChain == nullptr) + MessageBoxA(nullptr, "GetProcAddress failed for D3D11CreateDeviceAndSwapChain!", + "Critical error", MB_OK | MB_ICONERROR); - return S_OK; + return S_OK; } HRESULT LoadD3DCompiler() { - if (d3dcompiler_dll_ref++ > 0) return S_OK; - if (hD3DCompilerDll) return S_OK; + if (d3dcompiler_dll_ref++ > 0) + return S_OK; + if (hD3DCompilerDll) + return S_OK; - // try to load D3DCompiler first to check whether we have proper runtime support - // try to use the dll the backend was compiled against first - don't bother about debug runtimes - hD3DCompilerDll = LoadLibraryA(D3DCOMPILER_DLL_A); - if (!hD3DCompilerDll) - { - // if that fails, use the dll which should be available in every SDK which officially supports DX11. - hD3DCompilerDll = LoadLibraryA("D3DCompiler_42.dll"); - if (!hD3DCompilerDll) - { - MessageBoxA(nullptr, "Failed to load D3DCompiler_42.dll, update your DX11 runtime, please", "Critical error", MB_OK | MB_ICONERROR); - return E_FAIL; - } - else - { - NOTICE_LOG(VIDEO, "Successfully loaded D3DCompiler_42.dll. If you're having trouble, try updating your DX runtime first."); - } - } + // try to load D3DCompiler first to check whether we have proper runtime support + // try to use the dll the backend was compiled against first - don't bother about debug runtimes + hD3DCompilerDll = LoadLibraryA(D3DCOMPILER_DLL_A); + if (!hD3DCompilerDll) + { + // if that fails, use the dll which should be available in every SDK which officially supports + // DX11. + hD3DCompilerDll = LoadLibraryA("D3DCompiler_42.dll"); + if (!hD3DCompilerDll) + { + MessageBoxA(nullptr, "Failed to load D3DCompiler_42.dll, update your DX11 runtime, please", + "Critical error", MB_OK | MB_ICONERROR); + return E_FAIL; + } + else + { + NOTICE_LOG(VIDEO, "Successfully loaded D3DCompiler_42.dll. If you're having trouble, try " + "updating your DX runtime first."); + } + } - PD3DReflect = (D3DREFLECT)GetProcAddress(hD3DCompilerDll, "D3DReflect"); - if (PD3DReflect == nullptr) MessageBoxA(nullptr, "GetProcAddress failed for D3DReflect!", "Critical error", MB_OK | MB_ICONERROR); - PD3DCompile = (pD3DCompile)GetProcAddress(hD3DCompilerDll, "D3DCompile"); - if (PD3DCompile == nullptr) MessageBoxA(nullptr, "GetProcAddress failed for D3DCompile!", "Critical error", MB_OK | MB_ICONERROR); + PD3DReflect = (D3DREFLECT)GetProcAddress(hD3DCompilerDll, "D3DReflect"); + if (PD3DReflect == nullptr) + MessageBoxA(nullptr, "GetProcAddress failed for D3DReflect!", "Critical error", + MB_OK | MB_ICONERROR); + PD3DCompile = (pD3DCompile)GetProcAddress(hD3DCompilerDll, "D3DCompile"); + if (PD3DCompile == nullptr) + MessageBoxA(nullptr, "GetProcAddress failed for D3DCompile!", "Critical error", + MB_OK | MB_ICONERROR); - return S_OK; + return S_OK; } void UnloadDXGI() { - if (!dxgi_dll_ref) return; - if (--dxgi_dll_ref != 0) return; + if (!dxgi_dll_ref) + return; + if (--dxgi_dll_ref != 0) + return; - if (hDXGIDll) FreeLibrary(hDXGIDll); - hDXGIDll = nullptr; - PCreateDXGIFactory = nullptr; + if (hDXGIDll) + FreeLibrary(hDXGIDll); + hDXGIDll = nullptr; + PCreateDXGIFactory = nullptr; } void UnloadD3D() { - if (!d3d_dll_ref) return; - if (--d3d_dll_ref != 0) return; + if (!d3d_dll_ref) + return; + if (--d3d_dll_ref != 0) + return; - if (hD3DDll) FreeLibrary(hD3DDll); - hD3DDll = nullptr; - PD3D11CreateDevice = nullptr; - PD3D11CreateDeviceAndSwapChain = nullptr; + if (hD3DDll) + FreeLibrary(hD3DDll); + hD3DDll = nullptr; + PD3D11CreateDevice = nullptr; + PD3D11CreateDeviceAndSwapChain = nullptr; } void UnloadD3DCompiler() { - if (!d3dcompiler_dll_ref) return; - if (--d3dcompiler_dll_ref != 0) return; + if (!d3dcompiler_dll_ref) + return; + if (--d3dcompiler_dll_ref != 0) + return; - if (hD3DCompilerDll) FreeLibrary(hD3DCompilerDll); - hD3DCompilerDll = nullptr; - PD3DReflect = nullptr; + if (hD3DCompilerDll) + FreeLibrary(hD3DCompilerDll); + hD3DCompilerDll = nullptr; + PD3DReflect = nullptr; } std::vector EnumAAModes(IDXGIAdapter* adapter) { - std::vector _aa_modes; + std::vector _aa_modes; - // NOTE: D3D 10.0 doesn't support multisampled resources which are bound as depth buffers AND shader resources. - // Thus, we can't have MSAA with 10.0 level hardware. - ID3D11Device* _device; - ID3D11DeviceContext* _context; - D3D_FEATURE_LEVEL feat_level; - HRESULT hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_SINGLETHREADED, supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &_device, &feat_level, &_context); - if (FAILED(hr) || feat_level == D3D_FEATURE_LEVEL_10_0) - { - DXGI_SAMPLE_DESC desc; - desc.Count = 1; - desc.Quality = 0; - _aa_modes.push_back(desc); - SAFE_RELEASE(_context); - SAFE_RELEASE(_device); - } - else - { - for (int samples = 0; samples < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; ++samples) - { - UINT quality_levels = 0; - _device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, samples, &quality_levels); + // NOTE: D3D 10.0 doesn't support multisampled resources which are bound as depth buffers AND + // shader resources. + // Thus, we can't have MSAA with 10.0 level hardware. + ID3D11Device* _device; + ID3D11DeviceContext* _context; + D3D_FEATURE_LEVEL feat_level; + HRESULT hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, + D3D11_CREATE_DEVICE_SINGLETHREADED, supported_feature_levels, + NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &_device, + &feat_level, &_context); + if (FAILED(hr) || feat_level == D3D_FEATURE_LEVEL_10_0) + { + DXGI_SAMPLE_DESC desc; + desc.Count = 1; + desc.Quality = 0; + _aa_modes.push_back(desc); + SAFE_RELEASE(_context); + SAFE_RELEASE(_device); + } + else + { + for (int samples = 0; samples < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; ++samples) + { + UINT quality_levels = 0; + _device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, samples, &quality_levels); - DXGI_SAMPLE_DESC desc; - desc.Count = samples; - desc.Quality = 0; + DXGI_SAMPLE_DESC desc; + desc.Count = samples; + desc.Quality = 0; - if (quality_levels > 0) - _aa_modes.push_back(desc); - } - _context->Release(); - _device->Release(); - } - return _aa_modes; + if (quality_levels > 0) + _aa_modes.push_back(desc); + } + _context->Release(); + _device->Release(); + } + return _aa_modes; } D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter) { - D3D_FEATURE_LEVEL feat_level = D3D_FEATURE_LEVEL_9_1; - PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_SINGLETHREADED, supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, nullptr, &feat_level, nullptr); - return feat_level; + D3D_FEATURE_LEVEL feat_level = D3D_FEATURE_LEVEL_9_1; + PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_SINGLETHREADED, + supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, + nullptr, &feat_level, nullptr); + return feat_level; } HRESULT Create(HWND wnd) { - hWnd = wnd; - HRESULT hr; + hWnd = wnd; + HRESULT hr; - RECT client; - GetClientRect(hWnd, &client); - xres = client.right - client.left; - yres = client.bottom - client.top; + RECT client; + GetClientRect(hWnd, &client); + xres = client.right - client.left; + yres = client.bottom - client.top; - hr = LoadDXGI(); - if (SUCCEEDED(hr)) hr = LoadD3D(); - if (SUCCEEDED(hr)) hr = LoadD3DCompiler(); - if (FAILED(hr)) - { - UnloadDXGI(); - UnloadD3D(); - UnloadD3DCompiler(); - return hr; - } + hr = LoadDXGI(); + if (SUCCEEDED(hr)) + hr = LoadD3D(); + if (SUCCEEDED(hr)) + hr = LoadD3DCompiler(); + if (FAILED(hr)) + { + UnloadDXGI(); + UnloadD3D(); + UnloadD3DCompiler(); + return hr; + } - IDXGIFactory* factory; - IDXGIAdapter* adapter; - IDXGIOutput* output; - hr = PCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory); - if (FAILED(hr)) MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR); + IDXGIFactory* factory; + IDXGIAdapter* adapter; + IDXGIOutput* output; + hr = PCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory); + if (FAILED(hr)) + MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 11 backend"), + MB_OK | MB_ICONERROR); - hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter); - if (FAILED(hr)) - { - // try using the first one - hr = factory->EnumAdapters(0, &adapter); - if (FAILED(hr)) MessageBox(wnd, _T("Failed to enumerate adapters"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR); - } + hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter); + if (FAILED(hr)) + { + // try using the first one + hr = factory->EnumAdapters(0, &adapter); + if (FAILED(hr)) + MessageBox(wnd, _T("Failed to enumerate adapters"), _T("Dolphin Direct3D 11 backend"), + MB_OK | MB_ICONERROR); + } - // TODO: Make this configurable - hr = adapter->EnumOutputs(0, &output); - if (FAILED(hr)) - { - // try using the first one - IDXGIAdapter* firstadapter; - hr = factory->EnumAdapters(0, &firstadapter); - if (!FAILED(hr)) - hr = firstadapter->EnumOutputs(0, &output); - if (FAILED(hr)) MessageBox(wnd, - _T("Failed to enumerate outputs!\n") - _T("This usually happens when you've set your video adapter to the Nvidia GPU in an Optimus-equipped system.\n") - _T("Set Dolphin to use the high-performance graphics in Nvidia's drivers instead and leave Dolphin's video adapter set to the Intel GPU."), - _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR); - SAFE_RELEASE(firstadapter); - } + // TODO: Make this configurable + hr = adapter->EnumOutputs(0, &output); + if (FAILED(hr)) + { + // try using the first one + IDXGIAdapter* firstadapter; + hr = factory->EnumAdapters(0, &firstadapter); + if (!FAILED(hr)) + hr = firstadapter->EnumOutputs(0, &output); + if (FAILED(hr)) + MessageBox(wnd, _T("Failed to enumerate outputs!\n") + _T("This usually happens when you've set your video adapter to the Nvidia ") + _T("GPU in an Optimus-equipped system.\n") + _T("Set Dolphin to use the high-performance graphics in Nvidia's drivers ") + _T("instead and leave Dolphin's video adapter set to the Intel GPU."), + _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR); + SAFE_RELEASE(firstadapter); + } - // get supported AA modes - aa_modes = EnumAAModes(adapter); + // get supported AA modes + aa_modes = EnumAAModes(adapter); - if (std::find_if( - aa_modes.begin(), - aa_modes.end(), - [](const DXGI_SAMPLE_DESC& desc) {return desc.Count == g_Config.iMultisamples;} - ) == aa_modes.end()) - { - g_Config.iMultisamples = 1; - UpdateActiveConfig(); - } + if (std::find_if(aa_modes.begin(), aa_modes.end(), [](const DXGI_SAMPLE_DESC& desc) { + return desc.Count == g_Config.iMultisamples; + }) == aa_modes.end()) + { + g_Config.iMultisamples = 1; + UpdateActiveConfig(); + } - DXGI_SWAP_CHAIN_DESC swap_chain_desc = {}; - swap_chain_desc.BufferCount = 1; - swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swap_chain_desc.OutputWindow = wnd; - swap_chain_desc.SampleDesc.Count = 1; - swap_chain_desc.SampleDesc.Quality = 0; - swap_chain_desc.Windowed = !g_Config.bFullscreen; + DXGI_SWAP_CHAIN_DESC swap_chain_desc = {}; + swap_chain_desc.BufferCount = 1; + swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swap_chain_desc.OutputWindow = wnd; + swap_chain_desc.SampleDesc.Count = 1; + swap_chain_desc.SampleDesc.Quality = 0; + swap_chain_desc.Windowed = !g_Config.bFullscreen; - DXGI_OUTPUT_DESC out_desc = {}; - output->GetDesc(&out_desc); + DXGI_OUTPUT_DESC out_desc = {}; + output->GetDesc(&out_desc); - DXGI_MODE_DESC mode_desc = {}; - mode_desc.Width = out_desc.DesktopCoordinates.right - out_desc.DesktopCoordinates.left; - mode_desc.Height = out_desc.DesktopCoordinates.bottom - out_desc.DesktopCoordinates.top; - mode_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - mode_desc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - hr = output->FindClosestMatchingMode(&mode_desc, &swap_chain_desc.BufferDesc, nullptr); - if (FAILED(hr)) MessageBox(wnd, _T("Failed to find a supported video mode"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR); + DXGI_MODE_DESC mode_desc = {}; + mode_desc.Width = out_desc.DesktopCoordinates.right - out_desc.DesktopCoordinates.left; + mode_desc.Height = out_desc.DesktopCoordinates.bottom - out_desc.DesktopCoordinates.top; + mode_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + mode_desc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + hr = output->FindClosestMatchingMode(&mode_desc, &swap_chain_desc.BufferDesc, nullptr); + if (FAILED(hr)) + MessageBox(wnd, _T("Failed to find a supported video mode"), _T("Dolphin Direct3D 11 backend"), + MB_OK | MB_ICONERROR); - if (swap_chain_desc.Windowed) - { - // forcing buffer resolution to xres and yres.. - // this is not a problem as long as we're in windowed mode - swap_chain_desc.BufferDesc.Width = xres; - swap_chain_desc.BufferDesc.Height = yres; - } + if (swap_chain_desc.Windowed) + { + // forcing buffer resolution to xres and yres.. + // this is not a problem as long as we're in windowed mode + swap_chain_desc.BufferDesc.Width = xres; + swap_chain_desc.BufferDesc.Height = yres; + } #if defined(_DEBUG) || defined(DEBUGFAST) - // Creating debug devices can sometimes fail if the user doesn't have the correct - // version of the DirectX SDK. If it does, simply fallback to a non-debug device. - { - hr = PD3D11CreateDeviceAndSwapChain(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, - D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_DEBUG, - supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, - D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device, - &featlevel, &context); - // Debugbreak on D3D error - if (SUCCEEDED(hr) && SUCCEEDED(device->QueryInterface(__uuidof(ID3D11Debug), (void**)&debug))) - { - ID3D11InfoQueue* infoQueue = nullptr; - if (SUCCEEDED(debug->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&infoQueue))) - { - infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); - infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); + // Creating debug devices can sometimes fail if the user doesn't have the correct + // version of the DirectX SDK. If it does, simply fallback to a non-debug device. + { + hr = PD3D11CreateDeviceAndSwapChain( + adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, + D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_DEBUG, supported_feature_levels, + NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device, + &featlevel, &context); + // Debugbreak on D3D error + if (SUCCEEDED(hr) && SUCCEEDED(device->QueryInterface(__uuidof(ID3D11Debug), (void**)&debug))) + { + ID3D11InfoQueue* infoQueue = nullptr; + if (SUCCEEDED(debug->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&infoQueue))) + { + infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); + infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); - D3D11_MESSAGE_ID hide[] = - { - D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS - }; + D3D11_MESSAGE_ID hide[] = {D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS}; - D3D11_INFO_QUEUE_FILTER filter = {}; - filter.DenyList.NumIDs = sizeof(hide) / sizeof(D3D11_MESSAGE_ID); - filter.DenyList.pIDList = hide; - infoQueue->AddStorageFilterEntries(&filter); - infoQueue->Release(); - } - } - } + D3D11_INFO_QUEUE_FILTER filter = {}; + filter.DenyList.NumIDs = sizeof(hide) / sizeof(D3D11_MESSAGE_ID); + filter.DenyList.pIDList = hide; + infoQueue->AddStorageFilterEntries(&filter); + infoQueue->Release(); + } + } + } - if (FAILED(hr)) + if (FAILED(hr)) #endif - { - hr = PD3D11CreateDeviceAndSwapChain(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, - D3D11_CREATE_DEVICE_SINGLETHREADED, - supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, - D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device, - &featlevel, &context); - } + { + hr = PD3D11CreateDeviceAndSwapChain( + adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_SINGLETHREADED, + supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &swap_chain_desc, + &swapchain, &device, &featlevel, &context); + } - if (FAILED(hr)) - { - MessageBox(wnd, _T("Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR); - SAFE_RELEASE(device); - SAFE_RELEASE(context); - SAFE_RELEASE(swapchain); - return E_FAIL; - } + if (FAILED(hr)) + { + MessageBox( + wnd, + _T("Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0"), + _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR); + SAFE_RELEASE(device); + SAFE_RELEASE(context); + SAFE_RELEASE(swapchain); + return E_FAIL; + } - // prevent DXGI from responding to Alt+Enter, unfortunately DXGI_MWA_NO_ALT_ENTER - // does not work so we disable all monitoring of window messages. However this - // may make it more difficult for DXGI to handle display mode changes. - hr = factory->MakeWindowAssociation(wnd, DXGI_MWA_NO_WINDOW_CHANGES); - if (FAILED(hr)) MessageBox(wnd, _T("Failed to associate the window"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR); + // prevent DXGI from responding to Alt+Enter, unfortunately DXGI_MWA_NO_ALT_ENTER + // does not work so we disable all monitoring of window messages. However this + // may make it more difficult for DXGI to handle display mode changes. + hr = factory->MakeWindowAssociation(wnd, DXGI_MWA_NO_WINDOW_CHANGES); + if (FAILED(hr)) + MessageBox(wnd, _T("Failed to associate the window"), _T("Dolphin Direct3D 11 backend"), + MB_OK | MB_ICONERROR); - SetDebugObjectName((ID3D11DeviceChild*)context, "device context"); - SAFE_RELEASE(factory); - SAFE_RELEASE(output); - SAFE_RELEASE(adapter); + SetDebugObjectName((ID3D11DeviceChild*)context, "device context"); + SAFE_RELEASE(factory); + SAFE_RELEASE(output); + SAFE_RELEASE(adapter); - ID3D11Texture2D* buf; - hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf); - if (FAILED(hr)) - { - MessageBox(wnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR); - SAFE_RELEASE(device); - SAFE_RELEASE(context); - SAFE_RELEASE(swapchain); - return E_FAIL; - } - backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET); - SAFE_RELEASE(buf); - CHECK(backbuf!=nullptr, "Create back buffer texture"); - SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture"); - SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view"); + ID3D11Texture2D* buf; + hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf); + if (FAILED(hr)) + { + MessageBox(wnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 backend"), + MB_OK | MB_ICONERROR); + SAFE_RELEASE(device); + SAFE_RELEASE(context); + SAFE_RELEASE(swapchain); + return E_FAIL; + } + backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET); + SAFE_RELEASE(buf); + CHECK(backbuf != nullptr, "Create back buffer texture"); + SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture"); + SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view"); - context->OMSetRenderTargets(1, &backbuf->GetRTV(), nullptr); + context->OMSetRenderTargets(1, &backbuf->GetRTV(), nullptr); - // BGRA textures are easier to deal with in TextureCache, but might not be supported by the hardware - UINT format_support; - device->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM, &format_support); - bgra_textures_supported = (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0; + // BGRA textures are easier to deal with in TextureCache, but might not be supported by the + // hardware + UINT format_support; + device->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM, &format_support); + bgra_textures_supported = (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0; - stateman = new StateManager; - return S_OK; + stateman = new StateManager; + return S_OK; } void Close() { - // we can't release the swapchain while in fullscreen. - swapchain->SetFullscreenState(false, nullptr); + // we can't release the swapchain while in fullscreen. + swapchain->SetFullscreenState(false, nullptr); - // release all bound resources - context->ClearState(); - SAFE_RELEASE(backbuf); - SAFE_RELEASE(swapchain); - SAFE_DELETE(stateman); - context->Flush(); // immediately destroy device objects + // release all bound resources + context->ClearState(); + SAFE_RELEASE(backbuf); + SAFE_RELEASE(swapchain); + SAFE_DELETE(stateman); + context->Flush(); // immediately destroy device objects - SAFE_RELEASE(context); - ULONG references = device->Release(); + SAFE_RELEASE(context); + ULONG references = device->Release(); #if defined(_DEBUG) || defined(DEBUGFAST) - if (debug) - { - --references; // the debug interface increases the refcount of the device, subtract that. - if (references) - { - // print out alive objects, but only if we actually have pending references - // note this will also print out internal live objects to the debug console - debug->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL); - } - SAFE_RELEASE(debug) - } + if (debug) + { + --references; // the debug interface increases the refcount of the device, subtract that. + if (references) + { + // print out alive objects, but only if we actually have pending references + // note this will also print out internal live objects to the debug console + debug->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL); + } + SAFE_RELEASE(debug) + } #endif - if (references) - { - ERROR_LOG(VIDEO, "Unreleased references: %i.", references); - } - else - { - NOTICE_LOG(VIDEO, "Successfully released all device references!"); - } - device = nullptr; + if (references) + { + ERROR_LOG(VIDEO, "Unreleased references: %i.", references); + } + else + { + NOTICE_LOG(VIDEO, "Successfully released all device references!"); + } + device = nullptr; - // unload DLLs - UnloadD3D(); - UnloadDXGI(); + // unload DLLs + UnloadD3D(); + UnloadDXGI(); } const char* VertexShaderVersionString() { - if (featlevel == D3D_FEATURE_LEVEL_11_0) return "vs_5_0"; - else if (featlevel == D3D_FEATURE_LEVEL_10_1) return "vs_4_1"; - else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ return "vs_4_0"; + if (featlevel == D3D_FEATURE_LEVEL_11_0) + return "vs_5_0"; + else if (featlevel == D3D_FEATURE_LEVEL_10_1) + return "vs_4_1"; + else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ + return "vs_4_0"; } const char* GeometryShaderVersionString() { - if (featlevel == D3D_FEATURE_LEVEL_11_0) return "gs_5_0"; - else if (featlevel == D3D_FEATURE_LEVEL_10_1) return "gs_4_1"; - else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ return "gs_4_0"; + if (featlevel == D3D_FEATURE_LEVEL_11_0) + return "gs_5_0"; + else if (featlevel == D3D_FEATURE_LEVEL_10_1) + return "gs_4_1"; + else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ + return "gs_4_0"; } const char* PixelShaderVersionString() { - if (featlevel == D3D_FEATURE_LEVEL_11_0) return "ps_5_0"; - else if (featlevel == D3D_FEATURE_LEVEL_10_1) return "ps_4_1"; - else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ return "ps_4_0"; + if (featlevel == D3D_FEATURE_LEVEL_11_0) + return "ps_5_0"; + else if (featlevel == D3D_FEATURE_LEVEL_10_1) + return "ps_4_1"; + else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ + return "ps_4_0"; } -D3DTexture2D* &GetBackBuffer() { return backbuf; } -unsigned int GetBackBufferWidth() { return xres; } -unsigned int GetBackBufferHeight() { return yres; } +D3DTexture2D*& GetBackBuffer() +{ + return backbuf; +} +unsigned int GetBackBufferWidth() +{ + return xres; +} +unsigned int GetBackBufferHeight() +{ + return yres; +} -bool BGRATexturesSupported() { return bgra_textures_supported; } +bool BGRATexturesSupported() +{ + return bgra_textures_supported; +} -// Returns the maximum width/height of a texture. This value only depends upon the feature level in DX11 +// Returns the maximum width/height of a texture. This value only depends upon the feature level in +// DX11 unsigned int GetMaxTextureSize() { - switch (featlevel) - { - case D3D_FEATURE_LEVEL_11_0: - return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + switch (featlevel) + { + case D3D_FEATURE_LEVEL_11_0: + return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: - return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; - case D3D_FEATURE_LEVEL_9_3: - return 4096; + case D3D_FEATURE_LEVEL_9_3: + return 4096; - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: - return 2048; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 2048; - default: - return 0; - } + default: + return 0; + } } void Reset() { - // release all back buffer references - SAFE_RELEASE(backbuf); + // release all back buffer references + SAFE_RELEASE(backbuf); - // resize swapchain buffers - RECT client; - GetClientRect(hWnd, &client); - xres = client.right - client.left; - yres = client.bottom - client.top; - D3D::swapchain->ResizeBuffers(1, xres, yres, DXGI_FORMAT_R8G8B8A8_UNORM, 0); + // resize swapchain buffers + RECT client; + GetClientRect(hWnd, &client); + xres = client.right - client.left; + yres = client.bottom - client.top; + D3D::swapchain->ResizeBuffers(1, xres, yres, DXGI_FORMAT_R8G8B8A8_UNORM, 0); - // recreate back buffer texture - ID3D11Texture2D* buf; - HRESULT hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf); - if (FAILED(hr)) - { - MessageBox(hWnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR); - SAFE_RELEASE(device); - SAFE_RELEASE(context); - SAFE_RELEASE(swapchain); - return; - } - backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET); - SAFE_RELEASE(buf); - CHECK(backbuf!=nullptr, "Create back buffer texture"); - SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture"); - SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view"); + // recreate back buffer texture + ID3D11Texture2D* buf; + HRESULT hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf); + if (FAILED(hr)) + { + MessageBox(hWnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 backend"), + MB_OK | MB_ICONERROR); + SAFE_RELEASE(device); + SAFE_RELEASE(context); + SAFE_RELEASE(swapchain); + return; + } + backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET); + SAFE_RELEASE(buf); + CHECK(backbuf != nullptr, "Create back buffer texture"); + SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture"); + SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view"); } bool BeginFrame() { - if (bFrameInProgress) - { - PanicAlert("BeginFrame called although a frame is already in progress"); - return false; - } - bFrameInProgress = true; - return (device != nullptr); + if (bFrameInProgress) + { + PanicAlert("BeginFrame called although a frame is already in progress"); + return false; + } + bFrameInProgress = true; + return (device != nullptr); } void EndFrame() { - if (!bFrameInProgress) - { - PanicAlert("EndFrame called although no frame is in progress"); - return; - } - bFrameInProgress = false; + if (!bFrameInProgress) + { + PanicAlert("EndFrame called although no frame is in progress"); + return; + } + bFrameInProgress = false; } void Present() { - // TODO: Is 1 the correct value for vsyncing? - swapchain->Present((UINT)g_ActiveConfig.IsVSync(), 0); + // TODO: Is 1 the correct value for vsyncing? + swapchain->Present((UINT)g_ActiveConfig.IsVSync(), 0); } HRESULT SetFullscreenState(bool enable_fullscreen) { - return swapchain->SetFullscreenState(enable_fullscreen, nullptr); + return swapchain->SetFullscreenState(enable_fullscreen, nullptr); } HRESULT GetFullscreenState(bool* fullscreen_state) { - if (fullscreen_state == nullptr) - { - return E_POINTER; - } + if (fullscreen_state == nullptr) + { + return E_POINTER; + } - BOOL state; - HRESULT hr = swapchain->GetFullscreenState(&state, nullptr); - *fullscreen_state = !!state; - return hr; + BOOL state; + HRESULT hr = swapchain->GetFullscreenState(&state, nullptr); + *fullscreen_state = !!state; + return hr; } } // namespace D3D diff --git a/Source/Core/VideoBackends/D3D/D3DBase.h b/Source/Core/VideoBackends/D3D/D3DBase.h index 4647f1e3a0..52d7b446d0 100644 --- a/Source/Core/VideoBackends/D3D/D3DBase.h +++ b/Source/Core/VideoBackends/D3D/D3DBase.h @@ -13,17 +13,33 @@ namespace DX11 { - -#define SAFE_RELEASE(x) { if (x) (x)->Release(); (x) = nullptr; } -#define SAFE_DELETE(x) { delete (x); (x) = nullptr; } -#define SAFE_DELETE_ARRAY(x) { delete[] (x); (x) = nullptr; } -#define CHECK(cond, Message, ...) if (!(cond)) { PanicAlert(__FUNCTION__ " failed in %s at line %d: " Message, __FILE__, __LINE__, __VA_ARGS__); } +#define SAFE_RELEASE(x) \ + { \ + if (x) \ + (x)->Release(); \ + (x) = nullptr; \ + } +#define SAFE_DELETE(x) \ + { \ + delete (x); \ + (x) = nullptr; \ + } +#define SAFE_DELETE_ARRAY(x) \ + { \ + delete[](x); \ + (x) = nullptr; \ + } +#define CHECK(cond, Message, ...) \ + if (!(cond)) \ + { \ + PanicAlert(__FUNCTION__ " failed in %s at line %d: " Message, __FILE__, __LINE__, \ + __VA_ARGS__); \ + } class D3DTexture2D; namespace D3D { - HRESULT LoadDXGI(); HRESULT LoadD3D(); HRESULT LoadD3DCompiler(); @@ -49,7 +65,7 @@ void Present(); unsigned int GetBackBufferWidth(); unsigned int GetBackBufferHeight(); -D3DTexture2D* &GetBackBuffer(); +D3DTexture2D*& GetBackBuffer(); const char* PixelShaderVersionString(); const char* GeometryShaderVersionString(); const char* VertexShaderVersionString(); @@ -66,39 +82,41 @@ HRESULT GetFullscreenState(bool* fullscreen_state); template void SetDebugObjectName(T resource, const char* name) { - static_assert(std::is_convertible::value, - "resource must be convertible to ID3D11DeviceChild*"); + static_assert(std::is_convertible::value, + "resource must be convertible to ID3D11DeviceChild*"); #if defined(_DEBUG) || defined(DEBUGFAST) - if (resource) - resource->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)(name ? strlen(name) : 0), name); + if (resource) + resource->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)(name ? strlen(name) : 0), name); #endif } template std::string GetDebugObjectName(T resource) { - static_assert(std::is_convertible::value, - "resource must be convertible to ID3D11DeviceChild*"); - std::string name; + static_assert(std::is_convertible::value, + "resource must be convertible to ID3D11DeviceChild*"); + std::string name; #if defined(_DEBUG) || defined(DEBUGFAST) - if (resource) - { - UINT size = 0; - resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, nullptr); //get required size - name.resize(size); - resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, const_cast(name.data())); - } + if (resource) + { + UINT size = 0; + resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, nullptr); // get required size + name.resize(size); + resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, const_cast(name.data())); + } #endif - return name; + return name; } } // namespace D3D -typedef HRESULT (WINAPI* CREATEDXGIFACTORY)(REFIID, void**); +typedef HRESULT(WINAPI* CREATEDXGIFACTORY)(REFIID, void**); extern CREATEDXGIFACTORY PCreateDXGIFactory; -typedef HRESULT (WINAPI* D3D11CREATEDEVICE)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL*, UINT, UINT, ID3D11Device**, D3D_FEATURE_LEVEL*, ID3D11DeviceContext**); +typedef HRESULT(WINAPI* D3D11CREATEDEVICE)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, + CONST D3D_FEATURE_LEVEL*, UINT, UINT, ID3D11Device**, + D3D_FEATURE_LEVEL*, ID3D11DeviceContext**); -typedef HRESULT (WINAPI* D3DREFLECT)(LPCVOID, SIZE_T, REFIID, void**); +typedef HRESULT(WINAPI* D3DREFLECT)(LPCVOID, SIZE_T, REFIID, void**); extern D3DREFLECT PD3DReflect; extern pD3DCompile PD3DCompile; diff --git a/Source/Core/VideoBackends/D3D/D3DBlob.cpp b/Source/Core/VideoBackends/D3D/D3DBlob.cpp index db5210e539..c0991825b6 100644 --- a/Source/Core/VideoBackends/D3D/D3DBlob.cpp +++ b/Source/Core/VideoBackends/D3D/D3DBlob.cpp @@ -8,50 +8,53 @@ namespace DX11 { - -D3DBlob::D3DBlob(unsigned int blob_size, const u8* init_data) : ref(1), size(blob_size), blob(nullptr) +D3DBlob::D3DBlob(unsigned int blob_size, const u8* init_data) + : ref(1), size(blob_size), blob(nullptr) { - data = new u8[blob_size]; - if (init_data) memcpy(data, init_data, size); + data = new u8[blob_size]; + if (init_data) + memcpy(data, init_data, size); } D3DBlob::D3DBlob(ID3D10Blob* d3dblob) : ref(1) { - blob = d3dblob; - data = (u8*)blob->GetBufferPointer(); - size = (unsigned int)blob->GetBufferSize(); - d3dblob->AddRef(); + blob = d3dblob; + data = (u8*)blob->GetBufferPointer(); + size = (unsigned int)blob->GetBufferSize(); + d3dblob->AddRef(); } D3DBlob::~D3DBlob() { - if (blob) blob->Release(); - else delete[] data; + if (blob) + blob->Release(); + else + delete[] data; } void D3DBlob::AddRef() { - ++ref; + ++ref; } unsigned int D3DBlob::Release() { - if (--ref == 0) - { - delete this; - return 0; - } - return ref; + if (--ref == 0) + { + delete this; + return 0; + } + return ref; } unsigned int D3DBlob::Size() const { - return size; + return size; } u8* D3DBlob::Data() { - return data; + return data; } } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/D3DBlob.h b/Source/Core/VideoBackends/D3D/D3DBlob.h index cbdc7f5792..c332b0c517 100644 --- a/Source/Core/VideoBackends/D3D/D3DBlob.h +++ b/Source/Core/VideoBackends/D3D/D3DBlob.h @@ -10,31 +10,30 @@ struct ID3D10Blob; namespace DX11 { - // use this class instead ID3D10Blob or ID3D11Blob whenever possible class D3DBlob { public: - // memory will be copied into an own buffer - D3DBlob(unsigned int blob_size, const u8* init_data = nullptr); + // memory will be copied into an own buffer + D3DBlob(unsigned int blob_size, const u8* init_data = nullptr); - // d3dblob will be AddRef'd - D3DBlob(ID3D10Blob* d3dblob); + // d3dblob will be AddRef'd + D3DBlob(ID3D10Blob* d3dblob); - void AddRef(); - unsigned int Release(); + void AddRef(); + unsigned int Release(); - unsigned int Size() const; - u8* Data(); + unsigned int Size() const; + u8* Data(); private: - ~D3DBlob(); + ~D3DBlob(); - unsigned int ref; - unsigned int size; + unsigned int ref; + unsigned int size; - u8* data; - ID3D10Blob* blob; + u8* data; + ID3D10Blob* blob; }; } // namespace diff --git a/Source/Core/VideoBackends/D3D/D3DShader.cpp b/Source/Core/VideoBackends/D3D/D3DShader.cpp index 106f54d4c4..cf329c13ad 100644 --- a/Source/Core/VideoBackends/D3D/D3DShader.cpp +++ b/Source/Core/VideoBackends/D3D/D3DShader.cpp @@ -6,218 +6,224 @@ #include #include "Common/FileUtil.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DShader.h" #include "VideoCommon/VideoConfig.h" namespace DX11 { - namespace D3D { - // bytecode->shader ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, unsigned int len) { - ID3D11VertexShader* v_shader; - HRESULT hr = D3D::device->CreateVertexShader(bytecode, len, nullptr, &v_shader); - if (FAILED(hr)) - return nullptr; + ID3D11VertexShader* v_shader; + HRESULT hr = D3D::device->CreateVertexShader(bytecode, len, nullptr, &v_shader); + if (FAILED(hr)) + return nullptr; - return v_shader; + return v_shader; } // code->bytecode bool CompileVertexShader(const std::string& code, D3DBlob** blob) { - ID3D10Blob* shaderBuffer = nullptr; - ID3D10Blob* errorBuffer = nullptr; + ID3D10Blob* shaderBuffer = nullptr; + ID3D10Blob* errorBuffer = nullptr; #if defined(_DEBUG) || defined(DEBUGFAST) - UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_DEBUG; + UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3D10_SHADER_DEBUG; #else - UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_OPTIMIZATION_LEVEL3|D3D10_SHADER_SKIP_VALIDATION; + UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3D10_SHADER_OPTIMIZATION_LEVEL3 | + D3D10_SHADER_SKIP_VALIDATION; #endif - HRESULT hr = PD3DCompile(code.c_str(), code.length(), nullptr, nullptr, nullptr, "main", D3D::VertexShaderVersionString(), - flags, 0, &shaderBuffer, &errorBuffer); - if (errorBuffer) - { - INFO_LOG(VIDEO, "Vertex shader compiler messages:\n%s\n", - (const char*)errorBuffer->GetBufferPointer()); - } + HRESULT hr = PD3DCompile(code.c_str(), code.length(), nullptr, nullptr, nullptr, "main", + D3D::VertexShaderVersionString(), flags, 0, &shaderBuffer, &errorBuffer); + if (errorBuffer) + { + INFO_LOG(VIDEO, "Vertex shader compiler messages:\n%s\n", + (const char*)errorBuffer->GetBufferPointer()); + } - if (FAILED(hr)) - { - static int num_failures = 0; - std::string filename = StringFromFormat("%sbad_vs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); - std::ofstream file; - OpenFStream(file, filename, std::ios_base::out); - file << code; - file.close(); + if (FAILED(hr)) + { + static int num_failures = 0; + std::string filename = StringFromFormat("%sbad_vs_%04i.txt", + File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); + std::ofstream file; + OpenFStream(file, filename, std::ios_base::out); + file << code; + file.close(); - PanicAlert("Failed to compile vertex shader: %s\nDebug info (%s):\n%s", - filename.c_str(), D3D::VertexShaderVersionString(), (const char*)errorBuffer->GetBufferPointer()); + PanicAlert("Failed to compile vertex shader: %s\nDebug info (%s):\n%s", filename.c_str(), + D3D::VertexShaderVersionString(), (const char*)errorBuffer->GetBufferPointer()); - *blob = nullptr; - errorBuffer->Release(); - } - else - { - *blob = new D3DBlob(shaderBuffer); - shaderBuffer->Release(); - } - return SUCCEEDED(hr); + *blob = nullptr; + errorBuffer->Release(); + } + else + { + *blob = new D3DBlob(shaderBuffer); + shaderBuffer->Release(); + } + return SUCCEEDED(hr); } // bytecode->shader ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, unsigned int len) { - ID3D11GeometryShader* g_shader; - HRESULT hr = D3D::device->CreateGeometryShader(bytecode, len, nullptr, &g_shader); - if (FAILED(hr)) - return nullptr; + ID3D11GeometryShader* g_shader; + HRESULT hr = D3D::device->CreateGeometryShader(bytecode, len, nullptr, &g_shader); + if (FAILED(hr)) + return nullptr; - return g_shader; + return g_shader; } // code->bytecode -bool CompileGeometryShader(const std::string& code, D3DBlob** blob, const D3D_SHADER_MACRO* pDefines) +bool CompileGeometryShader(const std::string& code, D3DBlob** blob, + const D3D_SHADER_MACRO* pDefines) { - ID3D10Blob* shaderBuffer = nullptr; - ID3D10Blob* errorBuffer = nullptr; + ID3D10Blob* shaderBuffer = nullptr; + ID3D10Blob* errorBuffer = nullptr; #if defined(_DEBUG) || defined(DEBUGFAST) - UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_DEBUG; + UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3D10_SHADER_DEBUG; #else - UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_OPTIMIZATION_LEVEL3|D3D10_SHADER_SKIP_VALIDATION; + UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3D10_SHADER_OPTIMIZATION_LEVEL3 | + D3D10_SHADER_SKIP_VALIDATION; #endif - HRESULT hr = PD3DCompile(code.c_str(), code.length(), nullptr, pDefines, nullptr, "main", D3D::GeometryShaderVersionString(), - flags, 0, &shaderBuffer, &errorBuffer); + HRESULT hr = + PD3DCompile(code.c_str(), code.length(), nullptr, pDefines, nullptr, "main", + D3D::GeometryShaderVersionString(), flags, 0, &shaderBuffer, &errorBuffer); - if (errorBuffer) - { - INFO_LOG(VIDEO, "Geometry shader compiler messages:\n%s\n", - (const char*)errorBuffer->GetBufferPointer()); - } + if (errorBuffer) + { + INFO_LOG(VIDEO, "Geometry shader compiler messages:\n%s\n", + (const char*)errorBuffer->GetBufferPointer()); + } - if (FAILED(hr)) - { - static int num_failures = 0; - std::string filename = StringFromFormat("%sbad_gs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); - std::ofstream file; - OpenFStream(file, filename, std::ios_base::out); - file << code; - file.close(); + if (FAILED(hr)) + { + static int num_failures = 0; + std::string filename = StringFromFormat("%sbad_gs_%04i.txt", + File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); + std::ofstream file; + OpenFStream(file, filename, std::ios_base::out); + file << code; + file.close(); - PanicAlert("Failed to compile geometry shader: %s\nDebug info (%s):\n%s", - filename.c_str(), D3D::GeometryShaderVersionString(), (const char*)errorBuffer->GetBufferPointer()); + PanicAlert("Failed to compile geometry shader: %s\nDebug info (%s):\n%s", filename.c_str(), + D3D::GeometryShaderVersionString(), (const char*)errorBuffer->GetBufferPointer()); - *blob = nullptr; - errorBuffer->Release(); - } - else - { - *blob = new D3DBlob(shaderBuffer); - shaderBuffer->Release(); - } - return SUCCEEDED(hr); + *blob = nullptr; + errorBuffer->Release(); + } + else + { + *blob = new D3DBlob(shaderBuffer); + shaderBuffer->Release(); + } + return SUCCEEDED(hr); } // bytecode->shader ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int len) { - ID3D11PixelShader* p_shader; - HRESULT hr = D3D::device->CreatePixelShader(bytecode, len, nullptr, &p_shader); - if (FAILED(hr)) - { - PanicAlert("CreatePixelShaderFromByteCode failed at %s %d\n", __FILE__, __LINE__); - p_shader = nullptr; - } - return p_shader; + ID3D11PixelShader* p_shader; + HRESULT hr = D3D::device->CreatePixelShader(bytecode, len, nullptr, &p_shader); + if (FAILED(hr)) + { + PanicAlert("CreatePixelShaderFromByteCode failed at %s %d\n", __FILE__, __LINE__); + p_shader = nullptr; + } + return p_shader; } // code->bytecode bool CompilePixelShader(const std::string& code, D3DBlob** blob, const D3D_SHADER_MACRO* pDefines) { - ID3D10Blob* shaderBuffer = nullptr; - ID3D10Blob* errorBuffer = nullptr; + ID3D10Blob* shaderBuffer = nullptr; + ID3D10Blob* errorBuffer = nullptr; #if defined(_DEBUG) || defined(DEBUGFAST) - UINT flags = D3D10_SHADER_DEBUG; + UINT flags = D3D10_SHADER_DEBUG; #else - UINT flags = D3D10_SHADER_OPTIMIZATION_LEVEL3; + UINT flags = D3D10_SHADER_OPTIMIZATION_LEVEL3; #endif - HRESULT hr = PD3DCompile(code.c_str(), code.length(), nullptr, pDefines, nullptr, "main", D3D::PixelShaderVersionString(), - flags, 0, &shaderBuffer, &errorBuffer); + HRESULT hr = PD3DCompile(code.c_str(), code.length(), nullptr, pDefines, nullptr, "main", + D3D::PixelShaderVersionString(), flags, 0, &shaderBuffer, &errorBuffer); - if (errorBuffer) - { - INFO_LOG(VIDEO, "Pixel shader compiler messages:\n%s", - (const char*)errorBuffer->GetBufferPointer()); - } + if (errorBuffer) + { + INFO_LOG(VIDEO, "Pixel shader compiler messages:\n%s", + (const char*)errorBuffer->GetBufferPointer()); + } - if (FAILED(hr)) - { - static int num_failures = 0; - std::string filename = StringFromFormat("%sbad_ps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); - std::ofstream file; - OpenFStream(file, filename, std::ios_base::out); - file << code; - file.close(); + if (FAILED(hr)) + { + static int num_failures = 0; + std::string filename = StringFromFormat("%sbad_ps_%04i.txt", + File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); + std::ofstream file; + OpenFStream(file, filename, std::ios_base::out); + file << code; + file.close(); - PanicAlert("Failed to compile pixel shader: %s\nDebug info (%s):\n%s", - filename.c_str(), D3D::PixelShaderVersionString(), (const char*)errorBuffer->GetBufferPointer()); + PanicAlert("Failed to compile pixel shader: %s\nDebug info (%s):\n%s", filename.c_str(), + D3D::PixelShaderVersionString(), (const char*)errorBuffer->GetBufferPointer()); - *blob = nullptr; - errorBuffer->Release(); - } - else - { - *blob = new D3DBlob(shaderBuffer); - shaderBuffer->Release(); - } + *blob = nullptr; + errorBuffer->Release(); + } + else + { + *blob = new D3DBlob(shaderBuffer); + shaderBuffer->Release(); + } - return SUCCEEDED(hr); + return SUCCEEDED(hr); } ID3D11VertexShader* CompileAndCreateVertexShader(const std::string& code) { - D3DBlob* blob = nullptr; - if (CompileVertexShader(code, &blob)) - { - ID3D11VertexShader* v_shader = CreateVertexShaderFromByteCode(blob); - blob->Release(); - return v_shader; - } - return nullptr; + D3DBlob* blob = nullptr; + if (CompileVertexShader(code, &blob)) + { + ID3D11VertexShader* v_shader = CreateVertexShaderFromByteCode(blob); + blob->Release(); + return v_shader; + } + return nullptr; } -ID3D11GeometryShader* CompileAndCreateGeometryShader(const std::string& code, const D3D_SHADER_MACRO* pDefines) +ID3D11GeometryShader* CompileAndCreateGeometryShader(const std::string& code, + const D3D_SHADER_MACRO* pDefines) { - D3DBlob* blob = nullptr; - if (CompileGeometryShader(code, &blob, pDefines)) - { - ID3D11GeometryShader* g_shader = CreateGeometryShaderFromByteCode(blob); - blob->Release(); - return g_shader; - } - return nullptr; + D3DBlob* blob = nullptr; + if (CompileGeometryShader(code, &blob, pDefines)) + { + ID3D11GeometryShader* g_shader = CreateGeometryShaderFromByteCode(blob); + blob->Release(); + return g_shader; + } + return nullptr; } ID3D11PixelShader* CompileAndCreatePixelShader(const std::string& code) { - D3DBlob* blob = nullptr; - CompilePixelShader(code, &blob); - if (blob) - { - ID3D11PixelShader* p_shader = CreatePixelShaderFromByteCode(blob); - blob->Release(); - return p_shader; - } - return nullptr; + D3DBlob* blob = nullptr; + CompilePixelShader(code, &blob); + if (blob) + { + ID3D11PixelShader* p_shader = CreatePixelShaderFromByteCode(blob); + blob->Release(); + return p_shader; + } + return nullptr; } } // namespace diff --git a/Source/Core/VideoBackends/D3D/D3DShader.h b/Source/Core/VideoBackends/D3D/D3DShader.h index 033987e9aa..0b417d9885 100644 --- a/Source/Core/VideoBackends/D3D/D3DShader.h +++ b/Source/Core/VideoBackends/D3D/D3DShader.h @@ -14,44 +14,53 @@ struct ID3D11VertexShader; namespace DX11 { - namespace D3D { - ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, unsigned int len); - ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, unsigned int len); - ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int len); +ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, unsigned int len); +ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, unsigned int len); +ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int len); - // The returned bytecode buffers should be Release()d. - bool CompileVertexShader(const std::string& code, D3DBlob** blob); - bool CompileGeometryShader(const std::string& code, D3DBlob** blob, const D3D_SHADER_MACRO* pDefines = nullptr); - bool CompilePixelShader(const std::string& code, D3DBlob** blob, const D3D_SHADER_MACRO* pDefines = nullptr); +// The returned bytecode buffers should be Release()d. +bool CompileVertexShader(const std::string& code, D3DBlob** blob); +bool CompileGeometryShader(const std::string& code, D3DBlob** blob, + const D3D_SHADER_MACRO* pDefines = nullptr); +bool CompilePixelShader(const std::string& code, D3DBlob** blob, + const D3D_SHADER_MACRO* pDefines = nullptr); - // Utility functions - ID3D11VertexShader* CompileAndCreateVertexShader(const std::string& code); - ID3D11GeometryShader* CompileAndCreateGeometryShader(const std::string& code, const D3D_SHADER_MACRO* pDefines = nullptr); - ID3D11PixelShader* CompileAndCreatePixelShader(const std::string& code); +// Utility functions +ID3D11VertexShader* CompileAndCreateVertexShader(const std::string& code); +ID3D11GeometryShader* CompileAndCreateGeometryShader(const std::string& code, + const D3D_SHADER_MACRO* pDefines = nullptr); +ID3D11PixelShader* CompileAndCreatePixelShader(const std::string& code); - inline ID3D11VertexShader* CreateVertexShaderFromByteCode(D3DBlob* bytecode) - { return CreateVertexShaderFromByteCode(bytecode->Data(), bytecode->Size()); } - inline ID3D11GeometryShader* CreateGeometryShaderFromByteCode(D3DBlob* bytecode) - { return CreateGeometryShaderFromByteCode(bytecode->Data(), bytecode->Size()); } - inline ID3D11PixelShader* CreatePixelShaderFromByteCode(D3DBlob* bytecode) - { return CreatePixelShaderFromByteCode(bytecode->Data(), bytecode->Size()); } +inline ID3D11VertexShader* CreateVertexShaderFromByteCode(D3DBlob* bytecode) +{ + return CreateVertexShaderFromByteCode(bytecode->Data(), bytecode->Size()); +} +inline ID3D11GeometryShader* CreateGeometryShaderFromByteCode(D3DBlob* bytecode) +{ + return CreateGeometryShaderFromByteCode(bytecode->Data(), bytecode->Size()); +} +inline ID3D11PixelShader* CreatePixelShaderFromByteCode(D3DBlob* bytecode) +{ + return CreatePixelShaderFromByteCode(bytecode->Data(), bytecode->Size()); +} - inline ID3D11VertexShader* CompileAndCreateVertexShader(D3DBlob* code) - { - return CompileAndCreateVertexShader((const char*)code->Data()); - } +inline ID3D11VertexShader* CompileAndCreateVertexShader(D3DBlob* code) +{ + return CompileAndCreateVertexShader((const char*)code->Data()); +} - inline ID3D11GeometryShader* CompileAndCreateGeometryShader(D3DBlob* code, const D3D_SHADER_MACRO* pDefines = nullptr) - { - return CompileAndCreateGeometryShader((const char*)code->Data(), pDefines); - } +inline ID3D11GeometryShader* +CompileAndCreateGeometryShader(D3DBlob* code, const D3D_SHADER_MACRO* pDefines = nullptr) +{ + return CompileAndCreateGeometryShader((const char*)code->Data(), pDefines); +} - inline ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code) - { - return CompileAndCreatePixelShader((const char*)code->Data()); - } +inline ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code) +{ + return CompileAndCreatePixelShader((const char*)code->Data()); +} } } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index 64c6b48740..e277c74805 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -6,8 +6,8 @@ #include "Common/BitSet.h" #include "Common/CommonTypes.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DState.h" @@ -15,503 +15,520 @@ namespace DX11 { - namespace D3D { - StateManager* stateman; - -template AutoState::AutoState(const T* object) : state(object) +template +AutoState::AutoState(const T* object) : state(object) { - ((IUnknown*)state)->AddRef(); + ((IUnknown*)state)->AddRef(); } -template AutoState::AutoState(const AutoState &source) +template +AutoState::AutoState(const AutoState& source) { - state = source.GetPtr(); - ((T*)state)->AddRef(); + state = source.GetPtr(); + ((T*)state)->AddRef(); } -template AutoState::~AutoState() +template +AutoState::~AutoState() { - if (state) ((T*)state)->Release(); - state = nullptr; + if (state) + ((T*)state)->Release(); + state = nullptr; } StateManager::StateManager() - : m_currentBlendState(nullptr) - , m_currentDepthState(nullptr) - , m_currentRasterizerState(nullptr) - , m_dirtyFlags(~0u) - , m_pending() - , m_current() + : m_currentBlendState(nullptr), m_currentDepthState(nullptr), m_currentRasterizerState(nullptr), + m_dirtyFlags(~0u), m_pending(), m_current() { } -void StateManager::PushBlendState(const ID3D11BlendState* state) { m_blendStates.push(AutoBlendState(state)); } -void StateManager::PushDepthState(const ID3D11DepthStencilState* state) { m_depthStates.push(AutoDepthStencilState(state)); } -void StateManager::PushRasterizerState(const ID3D11RasterizerState* state) { m_rasterizerStates.push(AutoRasterizerState(state)); } -void StateManager::PopBlendState() { m_blendStates.pop(); } -void StateManager::PopDepthState() { m_depthStates.pop(); } -void StateManager::PopRasterizerState() { m_rasterizerStates.pop(); } +void StateManager::PushBlendState(const ID3D11BlendState* state) +{ + m_blendStates.push(AutoBlendState(state)); +} +void StateManager::PushDepthState(const ID3D11DepthStencilState* state) +{ + m_depthStates.push(AutoDepthStencilState(state)); +} +void StateManager::PushRasterizerState(const ID3D11RasterizerState* state) +{ + m_rasterizerStates.push(AutoRasterizerState(state)); +} +void StateManager::PopBlendState() +{ + m_blendStates.pop(); +} +void StateManager::PopDepthState() +{ + m_depthStates.pop(); +} +void StateManager::PopRasterizerState() +{ + m_rasterizerStates.pop(); +} void StateManager::Apply() { - if (!m_blendStates.empty()) - { - if (m_currentBlendState != m_blendStates.top().GetPtr()) - { - m_currentBlendState = (ID3D11BlendState*)m_blendStates.top().GetPtr(); - D3D::context->OMSetBlendState(m_currentBlendState, nullptr, 0xFFFFFFFF); - } - } - else ERROR_LOG(VIDEO, "Tried to apply without blend state!"); + if (!m_blendStates.empty()) + { + if (m_currentBlendState != m_blendStates.top().GetPtr()) + { + m_currentBlendState = (ID3D11BlendState*)m_blendStates.top().GetPtr(); + D3D::context->OMSetBlendState(m_currentBlendState, nullptr, 0xFFFFFFFF); + } + } + else + ERROR_LOG(VIDEO, "Tried to apply without blend state!"); - if (!m_depthStates.empty()) - { - if (m_currentDepthState != m_depthStates.top().GetPtr()) - { - m_currentDepthState = (ID3D11DepthStencilState*)m_depthStates.top().GetPtr(); - D3D::context->OMSetDepthStencilState(m_currentDepthState, 0); - } - } - else ERROR_LOG(VIDEO, "Tried to apply without depth state!"); + if (!m_depthStates.empty()) + { + if (m_currentDepthState != m_depthStates.top().GetPtr()) + { + m_currentDepthState = (ID3D11DepthStencilState*)m_depthStates.top().GetPtr(); + D3D::context->OMSetDepthStencilState(m_currentDepthState, 0); + } + } + else + ERROR_LOG(VIDEO, "Tried to apply without depth state!"); - if (!m_rasterizerStates.empty()) - { - if (m_currentRasterizerState != m_rasterizerStates.top().GetPtr()) - { - m_currentRasterizerState = (ID3D11RasterizerState*)m_rasterizerStates.top().GetPtr(); - D3D::context->RSSetState(m_currentRasterizerState); - } - } - else ERROR_LOG(VIDEO, "Tried to apply without rasterizer state!"); + if (!m_rasterizerStates.empty()) + { + if (m_currentRasterizerState != m_rasterizerStates.top().GetPtr()) + { + m_currentRasterizerState = (ID3D11RasterizerState*)m_rasterizerStates.top().GetPtr(); + D3D::context->RSSetState(m_currentRasterizerState); + } + } + else + ERROR_LOG(VIDEO, "Tried to apply without rasterizer state!"); - if (!m_dirtyFlags) - { - return; - } + if (!m_dirtyFlags) + { + return; + } - int textureMaskShift = LeastSignificantSetBit((u32)DirtyFlag_Texture0); - int samplerMaskShift = LeastSignificantSetBit((u32)DirtyFlag_Sampler0); + int textureMaskShift = LeastSignificantSetBit((u32)DirtyFlag_Texture0); + int samplerMaskShift = LeastSignificantSetBit((u32)DirtyFlag_Sampler0); - u32 dirtyTextures = (m_dirtyFlags & (DirtyFlag_Texture0 | DirtyFlag_Texture1 | DirtyFlag_Texture2 | DirtyFlag_Texture3 - | DirtyFlag_Texture4 | DirtyFlag_Texture5 | DirtyFlag_Texture6 | DirtyFlag_Texture7)) >> textureMaskShift; - u32 dirtySamplers = (m_dirtyFlags & (DirtyFlag_Sampler0 | DirtyFlag_Sampler1 | DirtyFlag_Sampler2 | DirtyFlag_Sampler3 - | DirtyFlag_Sampler4 | DirtyFlag_Sampler5 | DirtyFlag_Sampler6 | DirtyFlag_Sampler7)) >> samplerMaskShift; - u32 dirtyConstants = m_dirtyFlags & (DirtyFlag_PixelConstants | DirtyFlag_VertexConstants | DirtyFlag_GeometryConstants); - u32 dirtyShaders = m_dirtyFlags & (DirtyFlag_PixelShader | DirtyFlag_VertexShader | DirtyFlag_GeometryShader); - u32 dirtyBuffers = m_dirtyFlags & (DirtyFlag_VertexBuffer | DirtyFlag_IndexBuffer); + u32 dirtyTextures = + (m_dirtyFlags & + (DirtyFlag_Texture0 | DirtyFlag_Texture1 | DirtyFlag_Texture2 | DirtyFlag_Texture3 | + DirtyFlag_Texture4 | DirtyFlag_Texture5 | DirtyFlag_Texture6 | DirtyFlag_Texture7)) >> + textureMaskShift; + u32 dirtySamplers = + (m_dirtyFlags & + (DirtyFlag_Sampler0 | DirtyFlag_Sampler1 | DirtyFlag_Sampler2 | DirtyFlag_Sampler3 | + DirtyFlag_Sampler4 | DirtyFlag_Sampler5 | DirtyFlag_Sampler6 | DirtyFlag_Sampler7)) >> + samplerMaskShift; + u32 dirtyConstants = m_dirtyFlags & (DirtyFlag_PixelConstants | DirtyFlag_VertexConstants | + DirtyFlag_GeometryConstants); + u32 dirtyShaders = + m_dirtyFlags & (DirtyFlag_PixelShader | DirtyFlag_VertexShader | DirtyFlag_GeometryShader); + u32 dirtyBuffers = m_dirtyFlags & (DirtyFlag_VertexBuffer | DirtyFlag_IndexBuffer); - if (dirtyConstants) - { - if (m_current.pixelConstants[0] != m_pending.pixelConstants[0] || - m_current.pixelConstants[1] != m_pending.pixelConstants[1]) - { - D3D::context->PSSetConstantBuffers(0, m_pending.pixelConstants[1] ? 2 : 1, m_pending.pixelConstants); - m_current.pixelConstants[0] = m_pending.pixelConstants[0]; - m_current.pixelConstants[1] = m_pending.pixelConstants[1]; - } + if (dirtyConstants) + { + if (m_current.pixelConstants[0] != m_pending.pixelConstants[0] || + m_current.pixelConstants[1] != m_pending.pixelConstants[1]) + { + D3D::context->PSSetConstantBuffers(0, m_pending.pixelConstants[1] ? 2 : 1, + m_pending.pixelConstants); + m_current.pixelConstants[0] = m_pending.pixelConstants[0]; + m_current.pixelConstants[1] = m_pending.pixelConstants[1]; + } - if (m_current.vertexConstants != m_pending.vertexConstants) - { - D3D::context->VSSetConstantBuffers(0, 1, &m_pending.vertexConstants); - m_current.vertexConstants = m_pending.vertexConstants; - } + if (m_current.vertexConstants != m_pending.vertexConstants) + { + D3D::context->VSSetConstantBuffers(0, 1, &m_pending.vertexConstants); + m_current.vertexConstants = m_pending.vertexConstants; + } - if (m_current.geometryConstants != m_pending.geometryConstants) - { - D3D::context->GSSetConstantBuffers(0, 1, &m_pending.geometryConstants); - m_current.geometryConstants = m_pending.geometryConstants; - } - } + if (m_current.geometryConstants != m_pending.geometryConstants) + { + D3D::context->GSSetConstantBuffers(0, 1, &m_pending.geometryConstants); + m_current.geometryConstants = m_pending.geometryConstants; + } + } - if (dirtyBuffers || (m_dirtyFlags & DirtyFlag_InputAssembler)) - { - if (m_current.vertexBuffer != m_pending.vertexBuffer || - m_current.vertexBufferStride != m_pending.vertexBufferStride || - m_current.vertexBufferOffset != m_pending.vertexBufferOffset) - { - D3D::context->IASetVertexBuffers(0, 1, &m_pending.vertexBuffer, &m_pending.vertexBufferStride, &m_pending.vertexBufferOffset); - m_current.vertexBuffer = m_pending.vertexBuffer; - m_current.vertexBufferStride = m_pending.vertexBufferStride; - m_current.vertexBufferOffset = m_pending.vertexBufferOffset; - } + if (dirtyBuffers || (m_dirtyFlags & DirtyFlag_InputAssembler)) + { + if (m_current.vertexBuffer != m_pending.vertexBuffer || + m_current.vertexBufferStride != m_pending.vertexBufferStride || + m_current.vertexBufferOffset != m_pending.vertexBufferOffset) + { + D3D::context->IASetVertexBuffers(0, 1, &m_pending.vertexBuffer, &m_pending.vertexBufferStride, + &m_pending.vertexBufferOffset); + m_current.vertexBuffer = m_pending.vertexBuffer; + m_current.vertexBufferStride = m_pending.vertexBufferStride; + m_current.vertexBufferOffset = m_pending.vertexBufferOffset; + } - if (m_current.indexBuffer != m_pending.indexBuffer) - { - D3D::context->IASetIndexBuffer(m_pending.indexBuffer, DXGI_FORMAT_R16_UINT, 0); - m_current.indexBuffer = m_pending.indexBuffer; - } + if (m_current.indexBuffer != m_pending.indexBuffer) + { + D3D::context->IASetIndexBuffer(m_pending.indexBuffer, DXGI_FORMAT_R16_UINT, 0); + m_current.indexBuffer = m_pending.indexBuffer; + } - if (m_current.topology != m_pending.topology) - { - D3D::context->IASetPrimitiveTopology(m_pending.topology); - m_current.topology = m_pending.topology; - } + if (m_current.topology != m_pending.topology) + { + D3D::context->IASetPrimitiveTopology(m_pending.topology); + m_current.topology = m_pending.topology; + } - if (m_current.inputLayout != m_pending.inputLayout) - { - D3D::context->IASetInputLayout(m_pending.inputLayout); - m_current.inputLayout = m_pending.inputLayout; - } - } + if (m_current.inputLayout != m_pending.inputLayout) + { + D3D::context->IASetInputLayout(m_pending.inputLayout); + m_current.inputLayout = m_pending.inputLayout; + } + } - while (dirtyTextures) - { - int index = LeastSignificantSetBit(dirtyTextures); - if (m_current.textures[index] != m_pending.textures[index]) - { - D3D::context->PSSetShaderResources(index, 1, &m_pending.textures[index]); - m_current.textures[index] = m_pending.textures[index]; - } + while (dirtyTextures) + { + int index = LeastSignificantSetBit(dirtyTextures); + if (m_current.textures[index] != m_pending.textures[index]) + { + D3D::context->PSSetShaderResources(index, 1, &m_pending.textures[index]); + m_current.textures[index] = m_pending.textures[index]; + } - dirtyTextures &= ~(1 << index); - } + dirtyTextures &= ~(1 << index); + } - while (dirtySamplers) - { - int index = LeastSignificantSetBit(dirtySamplers); - if (m_current.samplers[index] != m_pending.samplers[index]) - { - D3D::context->PSSetSamplers(index, 1, &m_pending.samplers[index]); - m_current.samplers[index] = m_pending.samplers[index]; - } + while (dirtySamplers) + { + int index = LeastSignificantSetBit(dirtySamplers); + if (m_current.samplers[index] != m_pending.samplers[index]) + { + D3D::context->PSSetSamplers(index, 1, &m_pending.samplers[index]); + m_current.samplers[index] = m_pending.samplers[index]; + } - dirtySamplers &= ~(1 << index); - } + dirtySamplers &= ~(1 << index); + } - if (dirtyShaders) - { - if (m_current.pixelShader != m_pending.pixelShader) - { - D3D::context->PSSetShader(m_pending.pixelShader, nullptr, 0); - m_current.pixelShader = m_pending.pixelShader; - } + if (dirtyShaders) + { + if (m_current.pixelShader != m_pending.pixelShader) + { + D3D::context->PSSetShader(m_pending.pixelShader, nullptr, 0); + m_current.pixelShader = m_pending.pixelShader; + } - if (m_current.vertexShader != m_pending.vertexShader) - { - D3D::context->VSSetShader(m_pending.vertexShader, nullptr, 0); - m_current.vertexShader = m_pending.vertexShader; - } + if (m_current.vertexShader != m_pending.vertexShader) + { + D3D::context->VSSetShader(m_pending.vertexShader, nullptr, 0); + m_current.vertexShader = m_pending.vertexShader; + } - if (m_current.geometryShader != m_pending.geometryShader) - { - D3D::context->GSSetShader(m_pending.geometryShader, nullptr, 0); - m_current.geometryShader = m_pending.geometryShader; - } - } + if (m_current.geometryShader != m_pending.geometryShader) + { + D3D::context->GSSetShader(m_pending.geometryShader, nullptr, 0); + m_current.geometryShader = m_pending.geometryShader; + } + } - m_dirtyFlags = 0; + m_dirtyFlags = 0; } u32 StateManager::UnsetTexture(ID3D11ShaderResourceView* srv) { - u32 mask = 0; + u32 mask = 0; - for (u32 index = 0; index < 8; ++index) - { - if (m_current.textures[index] == srv) - { - SetTexture(index, nullptr); - mask |= 1 << index; - } - } + for (u32 index = 0; index < 8; ++index) + { + if (m_current.textures[index] == srv) + { + SetTexture(index, nullptr); + mask |= 1 << index; + } + } - return mask; + return mask; } void StateManager::SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceView* srv) { - while (textureSlotMask) - { - int index = LeastSignificantSetBit(textureSlotMask); - SetTexture(index, srv); - textureSlotMask &= ~(1 << index); - } + while (textureSlotMask) + { + int index = LeastSignificantSetBit(textureSlotMask); + SetTexture(index, srv); + textureSlotMask &= ~(1 << index); + } } } // namespace D3D ID3D11SamplerState* StateCache::Get(SamplerState state) { - auto it = m_sampler.find(state.packed); + auto it = m_sampler.find(state.packed); - if (it != m_sampler.end()) - { - return it->second; - } + if (it != m_sampler.end()) + { + return it->second; + } - const unsigned int d3dMipFilters[4] = - { - TexMode0::TEXF_NONE, - TexMode0::TEXF_POINT, - TexMode0::TEXF_LINEAR, - TexMode0::TEXF_NONE, //reserved - }; - const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] = - { - D3D11_TEXTURE_ADDRESS_CLAMP, - D3D11_TEXTURE_ADDRESS_WRAP, - D3D11_TEXTURE_ADDRESS_MIRROR, - D3D11_TEXTURE_ADDRESS_WRAP //reserved - }; + const unsigned int d3dMipFilters[4] = { + TexMode0::TEXF_NONE, TexMode0::TEXF_POINT, TexMode0::TEXF_LINEAR, + TexMode0::TEXF_NONE, // reserved + }; + const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] = { + D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_WRAP, D3D11_TEXTURE_ADDRESS_MIRROR, + D3D11_TEXTURE_ADDRESS_WRAP // reserved + }; - D3D11_SAMPLER_DESC sampdc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT()); + D3D11_SAMPLER_DESC sampdc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT()); - unsigned int mip = d3dMipFilters[state.min_filter & 3]; + unsigned int mip = d3dMipFilters[state.min_filter & 3]; - if (state.max_anisotropy > 1 && !SamplerCommon::IsBpTexMode0PointFiltering(state)) - { - sampdc.Filter = D3D11_FILTER_ANISOTROPIC; - sampdc.MaxAnisotropy = (u32)state.max_anisotropy; - } - else if (state.min_filter & 4) // linear min filter - { - if (state.mag_filter) // linear mag filter - { - if (mip == TexMode0::TEXF_NONE) - sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; - else if (mip == TexMode0::TEXF_POINT) - sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; - else if (mip == TexMode0::TEXF_LINEAR) - sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - } - else // point mag filter - { - if (mip == TexMode0::TEXF_NONE) - sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; - else if (mip == TexMode0::TEXF_POINT) - sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; - else if (mip == TexMode0::TEXF_LINEAR) - sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; - } - } - else // point min filter - { - if (state.mag_filter) // linear mag filter - { - if (mip == TexMode0::TEXF_NONE) - sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; - else if (mip == TexMode0::TEXF_POINT) - sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; - else if (mip == TexMode0::TEXF_LINEAR) - sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR; - } - else // point mag filter - { - if (mip == TexMode0::TEXF_NONE) - sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; - else if (mip == TexMode0::TEXF_POINT) - sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; - else if (mip == TexMode0::TEXF_LINEAR) - sampdc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; - } - } + if (state.max_anisotropy > 1 && !SamplerCommon::IsBpTexMode0PointFiltering(state)) + { + sampdc.Filter = D3D11_FILTER_ANISOTROPIC; + sampdc.MaxAnisotropy = (u32)state.max_anisotropy; + } + else if (state.min_filter & 4) // linear min filter + { + if (state.mag_filter) // linear mag filter + { + if (mip == TexMode0::TEXF_NONE) + sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; + else if (mip == TexMode0::TEXF_POINT) + sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; + else if (mip == TexMode0::TEXF_LINEAR) + sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + } + else // point mag filter + { + if (mip == TexMode0::TEXF_NONE) + sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; + else if (mip == TexMode0::TEXF_POINT) + sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; + else if (mip == TexMode0::TEXF_LINEAR) + sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; + } + } + else // point min filter + { + if (state.mag_filter) // linear mag filter + { + if (mip == TexMode0::TEXF_NONE) + sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; + else if (mip == TexMode0::TEXF_POINT) + sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; + else if (mip == TexMode0::TEXF_LINEAR) + sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR; + } + else // point mag filter + { + if (mip == TexMode0::TEXF_NONE) + sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + else if (mip == TexMode0::TEXF_POINT) + sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + else if (mip == TexMode0::TEXF_LINEAR) + sampdc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; + } + } - sampdc.AddressU = d3dClamps[state.wrap_s]; - sampdc.AddressV = d3dClamps[state.wrap_t]; + sampdc.AddressU = d3dClamps[state.wrap_s]; + sampdc.AddressV = d3dClamps[state.wrap_t]; - sampdc.MaxLOD = SamplerCommon::AreBpTexMode0MipmapsEnabled(state) ? state.max_lod / 16.f : 0.f; - sampdc.MinLOD = std::min(state.min_lod / 16.f, sampdc.MaxLOD); - sampdc.MipLODBias = (s32)state.lod_bias / 32.0f; + sampdc.MaxLOD = SamplerCommon::AreBpTexMode0MipmapsEnabled(state) ? state.max_lod / 16.f : 0.f; + sampdc.MinLOD = std::min(state.min_lod / 16.f, sampdc.MaxLOD); + sampdc.MipLODBias = (s32)state.lod_bias / 32.0f; - ID3D11SamplerState* res = nullptr; + ID3D11SamplerState* res = nullptr; - HRESULT hr = D3D::device->CreateSamplerState(&sampdc, &res); - if (FAILED(hr)) - PanicAlert("Fail %s %d\n", __FILE__, __LINE__); + HRESULT hr = D3D::device->CreateSamplerState(&sampdc, &res); + if (FAILED(hr)) + PanicAlert("Fail %s %d\n", __FILE__, __LINE__); - D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "sampler state used to emulate the GX pipeline"); - m_sampler.emplace(state.packed, res); + D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "sampler state used to emulate the GX pipeline"); + m_sampler.emplace(state.packed, res); - return res; + return res; } ID3D11BlendState* StateCache::Get(BlendState state) { - if (!state.blend_enable) - { - state.src_blend = D3D11_BLEND_ONE; - state.dst_blend = D3D11_BLEND_ZERO; - state.blend_op = D3D11_BLEND_OP_ADD; - state.use_dst_alpha = false; - } + if (!state.blend_enable) + { + state.src_blend = D3D11_BLEND_ONE; + state.dst_blend = D3D11_BLEND_ZERO; + state.blend_op = D3D11_BLEND_OP_ADD; + state.use_dst_alpha = false; + } - auto it = m_blend.find(state.packed); + auto it = m_blend.find(state.packed); - if (it != m_blend.end()) - return it->second; + if (it != m_blend.end()) + return it->second; - D3D11_BLEND_DESC blenddc = CD3D11_BLEND_DESC(CD3D11_DEFAULT()); + D3D11_BLEND_DESC blenddc = CD3D11_BLEND_DESC(CD3D11_DEFAULT()); - blenddc.AlphaToCoverageEnable = FALSE; - blenddc.IndependentBlendEnable = FALSE; - blenddc.RenderTarget[0].BlendEnable = state.blend_enable; - blenddc.RenderTarget[0].RenderTargetWriteMask = (u32)state.write_mask; - blenddc.RenderTarget[0].SrcBlend = state.src_blend; - blenddc.RenderTarget[0].DestBlend = state.dst_blend; - blenddc.RenderTarget[0].BlendOp = state.blend_op; - blenddc.RenderTarget[0].SrcBlendAlpha = state.src_blend; - blenddc.RenderTarget[0].DestBlendAlpha = state.dst_blend; - blenddc.RenderTarget[0].BlendOpAlpha = state.blend_op; + blenddc.AlphaToCoverageEnable = FALSE; + blenddc.IndependentBlendEnable = FALSE; + blenddc.RenderTarget[0].BlendEnable = state.blend_enable; + blenddc.RenderTarget[0].RenderTargetWriteMask = (u32)state.write_mask; + blenddc.RenderTarget[0].SrcBlend = state.src_blend; + blenddc.RenderTarget[0].DestBlend = state.dst_blend; + blenddc.RenderTarget[0].BlendOp = state.blend_op; + blenddc.RenderTarget[0].SrcBlendAlpha = state.src_blend; + blenddc.RenderTarget[0].DestBlendAlpha = state.dst_blend; + blenddc.RenderTarget[0].BlendOpAlpha = state.blend_op; - if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_COLOR) - blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; - else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_SRC_COLOR) - blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; - else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_DEST_COLOR) - blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA; - else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_DEST_COLOR) - blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; - else - blenddc.RenderTarget[0].SrcBlendAlpha = blenddc.RenderTarget[0].SrcBlend; + if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_COLOR) + blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; + else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_SRC_COLOR) + blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_DEST_COLOR) + blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA; + else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_DEST_COLOR) + blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; + else + blenddc.RenderTarget[0].SrcBlendAlpha = blenddc.RenderTarget[0].SrcBlend; - if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_SRC_COLOR) - blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA; - else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_SRC_COLOR) - blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; - else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_DEST_COLOR) - blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA; - else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_DEST_COLOR) - blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; - else - blenddc.RenderTarget[0].DestBlendAlpha = blenddc.RenderTarget[0].DestBlend; + if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_SRC_COLOR) + blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA; + else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_SRC_COLOR) + blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_DEST_COLOR) + blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA; + else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_DEST_COLOR) + blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; + else + blenddc.RenderTarget[0].DestBlendAlpha = blenddc.RenderTarget[0].DestBlend; - if (state.use_dst_alpha) - { - // Colors should blend against SRC1_ALPHA - if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_ALPHA) - blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC1_ALPHA; - else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_SRC_ALPHA) - blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_SRC1_ALPHA; + if (state.use_dst_alpha) + { + // Colors should blend against SRC1_ALPHA + if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_ALPHA) + blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC1_ALPHA; + else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_SRC_ALPHA) + blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_SRC1_ALPHA; - // Colors should blend against SRC1_ALPHA - if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_SRC_ALPHA) - blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_SRC1_ALPHA; - else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_SRC_ALPHA) - blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC1_ALPHA; + // Colors should blend against SRC1_ALPHA + if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_SRC_ALPHA) + blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_SRC1_ALPHA; + else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_SRC_ALPHA) + blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC1_ALPHA; - blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; - blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; - blenddc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - } + blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + blenddc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + } - ID3D11BlendState* res = nullptr; + ID3D11BlendState* res = nullptr; - HRESULT hr = D3D::device->CreateBlendState(&blenddc, &res); - if (FAILED(hr)) - PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__); + HRESULT hr = D3D::device->CreateBlendState(&blenddc, &res); + if (FAILED(hr)) + PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__); - D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "blend state used to emulate the GX pipeline"); - m_blend.emplace(state.packed, res); + D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "blend state used to emulate the GX pipeline"); + m_blend.emplace(state.packed, res); - return res; + return res; } ID3D11RasterizerState* StateCache::Get(RasterizerState state) { - auto it = m_raster.find(state.packed); + auto it = m_raster.find(state.packed); - if (it != m_raster.end()) - return it->second; + if (it != m_raster.end()) + return it->second; - D3D11_RASTERIZER_DESC rastdc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, - state.cull_mode, - false, 0, 0.f, 0, true, true, false, false); + D3D11_RASTERIZER_DESC rastdc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, state.cull_mode, false, 0, + 0.f, 0, true, true, false, false); - ID3D11RasterizerState* res = nullptr; + ID3D11RasterizerState* res = nullptr; - HRESULT hr = D3D::device->CreateRasterizerState(&rastdc, &res); - if (FAILED(hr)) - PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__); + HRESULT hr = D3D::device->CreateRasterizerState(&rastdc, &res); + if (FAILED(hr)) + PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__); - D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "rasterizer state used to emulate the GX pipeline"); - m_raster.emplace(state.packed, res); + D3D::SetDebugObjectName((ID3D11DeviceChild*)res, + "rasterizer state used to emulate the GX pipeline"); + m_raster.emplace(state.packed, res); - return res; + return res; } ID3D11DepthStencilState* StateCache::Get(ZMode state) { - auto it = m_depth.find(state.hex); + auto it = m_depth.find(state.hex); - if (it != m_depth.end()) - return it->second; + if (it != m_depth.end()) + return it->second; - D3D11_DEPTH_STENCIL_DESC depthdc = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT()); + D3D11_DEPTH_STENCIL_DESC depthdc = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT()); - depthdc.DepthEnable = TRUE; - depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; - depthdc.DepthFunc = D3D11_COMPARISON_GREATER; - depthdc.StencilEnable = FALSE; - depthdc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - depthdc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + depthdc.DepthEnable = TRUE; + depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthdc.DepthFunc = D3D11_COMPARISON_GREATER; + depthdc.StencilEnable = FALSE; + depthdc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + depthdc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] = - { - D3D11_COMPARISON_NEVER, - D3D11_COMPARISON_GREATER, - D3D11_COMPARISON_EQUAL, - D3D11_COMPARISON_GREATER_EQUAL, - D3D11_COMPARISON_LESS, - D3D11_COMPARISON_NOT_EQUAL, - D3D11_COMPARISON_LESS_EQUAL, - D3D11_COMPARISON_ALWAYS - }; + const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] = { + D3D11_COMPARISON_NEVER, D3D11_COMPARISON_GREATER, D3D11_COMPARISON_EQUAL, + D3D11_COMPARISON_GREATER_EQUAL, D3D11_COMPARISON_LESS, D3D11_COMPARISON_NOT_EQUAL, + D3D11_COMPARISON_LESS_EQUAL, D3D11_COMPARISON_ALWAYS}; - if (state.testenable) - { - depthdc.DepthEnable = TRUE; - depthdc.DepthWriteMask = state.updateenable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; - depthdc.DepthFunc = d3dCmpFuncs[state.func]; - } - else - { - // if the test is disabled write is disabled too - depthdc.DepthEnable = FALSE; - depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - } + if (state.testenable) + { + depthdc.DepthEnable = TRUE; + depthdc.DepthWriteMask = + state.updateenable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + depthdc.DepthFunc = d3dCmpFuncs[state.func]; + } + else + { + // if the test is disabled write is disabled too + depthdc.DepthEnable = FALSE; + depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + } - ID3D11DepthStencilState* res = nullptr; + ID3D11DepthStencilState* res = nullptr; - HRESULT hr = D3D::device->CreateDepthStencilState(&depthdc, &res); - if (SUCCEEDED(hr)) - D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "depth-stencil state used to emulate the GX pipeline"); - else - PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__); + HRESULT hr = D3D::device->CreateDepthStencilState(&depthdc, &res); + if (SUCCEEDED(hr)) + D3D::SetDebugObjectName((ID3D11DeviceChild*)res, + "depth-stencil state used to emulate the GX pipeline"); + else + PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__); - m_depth.emplace(state.hex, res); + m_depth.emplace(state.hex, res); - return res; + return res; } void StateCache::Clear() { - for (auto it : m_depth) - { - SAFE_RELEASE(it.second); - } - m_depth.clear(); + for (auto it : m_depth) + { + SAFE_RELEASE(it.second); + } + m_depth.clear(); - for (auto it : m_raster) - { - SAFE_RELEASE(it.second); - } - m_raster.clear(); + for (auto it : m_raster) + { + SAFE_RELEASE(it.second); + } + m_raster.clear(); - for (auto it : m_blend) - { - SAFE_RELEASE(it.second); - } - m_blend.clear(); + for (auto it : m_blend) + { + SAFE_RELEASE(it.second); + } + m_blend.clear(); - for (auto it : m_sampler) - { - SAFE_RELEASE(it.second); - } - m_sampler.clear(); + for (auto it : m_sampler) + { + SAFE_RELEASE(it.second); + } + m_sampler.clear(); } } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/D3DState.h b/Source/Core/VideoBackends/D3D/D3DState.h index 9ddc60d8ed..a3c439f49d 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.h +++ b/Source/Core/VideoBackends/D3D/D3DState.h @@ -18,76 +18,69 @@ struct ID3D11RasterizerState; namespace DX11 { +union RasterizerState { + BitField<0, 2, D3D11_CULL_MODE> cull_mode; -union RasterizerState -{ - BitField<0, 2, D3D11_CULL_MODE> cull_mode; - - u32 packed; + u32 packed; }; -union BlendState -{ - BitField<0, 1, u32> blend_enable; - BitField<1, 3, D3D11_BLEND_OP> blend_op; - BitField<4, 4, u32> write_mask; - BitField<8, 5, D3D11_BLEND> src_blend; - BitField<13, 5, D3D11_BLEND> dst_blend; - BitField<18, 1, u32> use_dst_alpha; +union BlendState { + BitField<0, 1, u32> blend_enable; + BitField<1, 3, D3D11_BLEND_OP> blend_op; + BitField<4, 4, u32> write_mask; + BitField<8, 5, D3D11_BLEND> src_blend; + BitField<13, 5, D3D11_BLEND> dst_blend; + BitField<18, 1, u32> use_dst_alpha; - u32 packed; + u32 packed; }; -union SamplerState -{ - BitField<0, 3, u64> min_filter; - BitField<3, 1, u64> mag_filter; - BitField<4, 8, u64> min_lod; - BitField<12, 8, u64> max_lod; - BitField<20, 8, s64> lod_bias; - BitField<28, 2, u64> wrap_s; - BitField<30, 2, u64> wrap_t; - BitField<32, 5, u64> max_anisotropy; +union SamplerState { + BitField<0, 3, u64> min_filter; + BitField<3, 1, u64> mag_filter; + BitField<4, 8, u64> min_lod; + BitField<12, 8, u64> max_lod; + BitField<20, 8, s64> lod_bias; + BitField<28, 2, u64> wrap_s; + BitField<30, 2, u64> wrap_t; + BitField<32, 5, u64> max_anisotropy; - u64 packed; + u64 packed; }; class StateCache { public: + // Get existing or create new render state. + // Returned objects is owned by the cache and does not need to be released. + ID3D11SamplerState* Get(SamplerState state); + ID3D11BlendState* Get(BlendState state); + ID3D11RasterizerState* Get(RasterizerState state); + ID3D11DepthStencilState* Get(ZMode state); - // Get existing or create new render state. - // Returned objects is owned by the cache and does not need to be released. - ID3D11SamplerState* Get(SamplerState state); - ID3D11BlendState* Get(BlendState state); - ID3D11RasterizerState* Get(RasterizerState state); - ID3D11DepthStencilState* Get(ZMode state); - - // Release all cached states and clear hash tables. - void Clear(); + // Release all cached states and clear hash tables. + void Clear(); private: - - std::unordered_map m_depth; - std::unordered_map m_raster; - std::unordered_map m_blend; - std::unordered_map m_sampler; + std::unordered_map m_depth; + std::unordered_map m_raster; + std::unordered_map m_blend; + std::unordered_map m_sampler; }; namespace D3D { - -template class AutoState +template +class AutoState { public: - AutoState(const T* object); - AutoState(const AutoState &source); - ~AutoState(); - - const inline T* GetPtr() const { return state; } + AutoState(const T* object); + AutoState(const AutoState& source); + ~AutoState(); + const inline T* GetPtr() const { return state; } private: - const T* state; + const T* state; }; typedef AutoState AutoBlendState; @@ -97,199 +90,199 @@ typedef AutoState AutoRasterizerState; class StateManager { public: - StateManager(); + StateManager(); - // call any of these to change the affected states - void PushBlendState(const ID3D11BlendState* state); - void PushDepthState(const ID3D11DepthStencilState* state); - void PushRasterizerState(const ID3D11RasterizerState* state); + // call any of these to change the affected states + void PushBlendState(const ID3D11BlendState* state); + void PushDepthState(const ID3D11DepthStencilState* state); + void PushRasterizerState(const ID3D11RasterizerState* state); - // call these after drawing - void PopBlendState(); - void PopDepthState(); - void PopRasterizerState(); + // call these after drawing + void PopBlendState(); + void PopDepthState(); + void PopRasterizerState(); - void SetTexture(u32 index, ID3D11ShaderResourceView* texture) - { - if (m_current.textures[index] != texture) - m_dirtyFlags |= DirtyFlag_Texture0 << index; + void SetTexture(u32 index, ID3D11ShaderResourceView* texture) + { + if (m_current.textures[index] != texture) + m_dirtyFlags |= DirtyFlag_Texture0 << index; - m_pending.textures[index] = texture; - } + m_pending.textures[index] = texture; + } - void SetSampler(u32 index, ID3D11SamplerState* sampler) - { - if (m_current.samplers[index] != sampler) - m_dirtyFlags |= DirtyFlag_Sampler0 << index; + void SetSampler(u32 index, ID3D11SamplerState* sampler) + { + if (m_current.samplers[index] != sampler) + m_dirtyFlags |= DirtyFlag_Sampler0 << index; - m_pending.samplers[index] = sampler; - } + m_pending.samplers[index] = sampler; + } - void SetPixelConstants(ID3D11Buffer* buffer0, ID3D11Buffer* buffer1 = nullptr) - { - if (m_current.pixelConstants[0] != buffer0 || m_current.pixelConstants[1] != buffer1) - m_dirtyFlags |= DirtyFlag_PixelConstants; + void SetPixelConstants(ID3D11Buffer* buffer0, ID3D11Buffer* buffer1 = nullptr) + { + if (m_current.pixelConstants[0] != buffer0 || m_current.pixelConstants[1] != buffer1) + m_dirtyFlags |= DirtyFlag_PixelConstants; - m_pending.pixelConstants[0] = buffer0; - m_pending.pixelConstants[1] = buffer1; - } + m_pending.pixelConstants[0] = buffer0; + m_pending.pixelConstants[1] = buffer1; + } - void SetVertexConstants(ID3D11Buffer* buffer) - { - if (m_current.vertexConstants != buffer) - m_dirtyFlags |= DirtyFlag_VertexConstants; + void SetVertexConstants(ID3D11Buffer* buffer) + { + if (m_current.vertexConstants != buffer) + m_dirtyFlags |= DirtyFlag_VertexConstants; - m_pending.vertexConstants = buffer; - } + m_pending.vertexConstants = buffer; + } - void SetGeometryConstants(ID3D11Buffer* buffer) - { - if (m_current.geometryConstants != buffer) - m_dirtyFlags |= DirtyFlag_GeometryConstants; + void SetGeometryConstants(ID3D11Buffer* buffer) + { + if (m_current.geometryConstants != buffer) + m_dirtyFlags |= DirtyFlag_GeometryConstants; - m_pending.geometryConstants = buffer; - } + m_pending.geometryConstants = buffer; + } - void SetVertexBuffer(ID3D11Buffer* buffer, u32 stride, u32 offset) - { - if (m_current.vertexBuffer != buffer || - m_current.vertexBufferStride != stride || - m_current.vertexBufferOffset != offset) - m_dirtyFlags |= DirtyFlag_VertexBuffer; + void SetVertexBuffer(ID3D11Buffer* buffer, u32 stride, u32 offset) + { + if (m_current.vertexBuffer != buffer || m_current.vertexBufferStride != stride || + m_current.vertexBufferOffset != offset) + m_dirtyFlags |= DirtyFlag_VertexBuffer; - m_pending.vertexBuffer = buffer; - m_pending.vertexBufferStride = stride; - m_pending.vertexBufferOffset = offset; - } + m_pending.vertexBuffer = buffer; + m_pending.vertexBufferStride = stride; + m_pending.vertexBufferOffset = offset; + } - void SetIndexBuffer(ID3D11Buffer* buffer) - { - if (m_current.indexBuffer != buffer) - m_dirtyFlags |= DirtyFlag_IndexBuffer; + void SetIndexBuffer(ID3D11Buffer* buffer) + { + if (m_current.indexBuffer != buffer) + m_dirtyFlags |= DirtyFlag_IndexBuffer; - m_pending.indexBuffer = buffer; - } + m_pending.indexBuffer = buffer; + } - void SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY topology) - { - if (m_current.topology != topology) - m_dirtyFlags |= DirtyFlag_InputAssembler; + void SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY topology) + { + if (m_current.topology != topology) + m_dirtyFlags |= DirtyFlag_InputAssembler; - m_pending.topology = topology; - } + m_pending.topology = topology; + } - void SetInputLayout(ID3D11InputLayout* layout) - { - if (m_current.inputLayout != layout) - m_dirtyFlags |= DirtyFlag_InputAssembler; + void SetInputLayout(ID3D11InputLayout* layout) + { + if (m_current.inputLayout != layout) + m_dirtyFlags |= DirtyFlag_InputAssembler; - m_pending.inputLayout = layout; - } + m_pending.inputLayout = layout; + } - void SetPixelShader(ID3D11PixelShader* shader) - { - if (m_current.pixelShader != shader) - m_dirtyFlags |= DirtyFlag_PixelShader; + void SetPixelShader(ID3D11PixelShader* shader) + { + if (m_current.pixelShader != shader) + m_dirtyFlags |= DirtyFlag_PixelShader; - m_pending.pixelShader = shader; - } + m_pending.pixelShader = shader; + } - void SetPixelShaderDynamic(ID3D11PixelShader* shader, ID3D11ClassInstance * const * classInstances, u32 classInstancesCount) - { - D3D::context->PSSetShader(shader, classInstances, classInstancesCount); - m_current.pixelShader = shader; - m_pending.pixelShader = shader; - } + void SetPixelShaderDynamic(ID3D11PixelShader* shader, ID3D11ClassInstance* const* classInstances, + u32 classInstancesCount) + { + D3D::context->PSSetShader(shader, classInstances, classInstancesCount); + m_current.pixelShader = shader; + m_pending.pixelShader = shader; + } - void SetVertexShader(ID3D11VertexShader* shader) - { - if (m_current.vertexShader != shader) - m_dirtyFlags |= DirtyFlag_VertexShader; + void SetVertexShader(ID3D11VertexShader* shader) + { + if (m_current.vertexShader != shader) + m_dirtyFlags |= DirtyFlag_VertexShader; - m_pending.vertexShader = shader; - } + m_pending.vertexShader = shader; + } - void SetGeometryShader(ID3D11GeometryShader* shader) - { - if (m_current.geometryShader != shader) - m_dirtyFlags |= DirtyFlag_GeometryShader; + void SetGeometryShader(ID3D11GeometryShader* shader) + { + if (m_current.geometryShader != shader) + m_dirtyFlags |= DirtyFlag_GeometryShader; - m_pending.geometryShader = shader; - } + m_pending.geometryShader = shader; + } - // removes currently set texture from all slots, returns mask of previously bound slots - u32 UnsetTexture(ID3D11ShaderResourceView* srv); - void SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceView* srv); + // removes currently set texture from all slots, returns mask of previously bound slots + u32 UnsetTexture(ID3D11ShaderResourceView* srv); + void SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceView* srv); - // call this immediately before any drawing operation or to explicitly apply pending resource state changes - void Apply(); + // call this immediately before any drawing operation or to explicitly apply pending resource + // state changes + void Apply(); private: + std::stack m_blendStates; + std::stack m_depthStates; + std::stack m_rasterizerStates; - std::stack m_blendStates; - std::stack m_depthStates; - std::stack m_rasterizerStates; + ID3D11BlendState* m_currentBlendState; + ID3D11DepthStencilState* m_currentDepthState; + ID3D11RasterizerState* m_currentRasterizerState; - ID3D11BlendState* m_currentBlendState; - ID3D11DepthStencilState* m_currentDepthState; - ID3D11RasterizerState* m_currentRasterizerState; + enum DirtyFlags + { + DirtyFlag_Texture0 = 1 << 0, + DirtyFlag_Texture1 = 1 << 1, + DirtyFlag_Texture2 = 1 << 2, + DirtyFlag_Texture3 = 1 << 3, + DirtyFlag_Texture4 = 1 << 4, + DirtyFlag_Texture5 = 1 << 5, + DirtyFlag_Texture6 = 1 << 6, + DirtyFlag_Texture7 = 1 << 7, - enum DirtyFlags - { - DirtyFlag_Texture0 = 1 << 0, - DirtyFlag_Texture1 = 1 << 1, - DirtyFlag_Texture2 = 1 << 2, - DirtyFlag_Texture3 = 1 << 3, - DirtyFlag_Texture4 = 1 << 4, - DirtyFlag_Texture5 = 1 << 5, - DirtyFlag_Texture6 = 1 << 6, - DirtyFlag_Texture7 = 1 << 7, + DirtyFlag_Sampler0 = 1 << 8, + DirtyFlag_Sampler1 = 1 << 9, + DirtyFlag_Sampler2 = 1 << 10, + DirtyFlag_Sampler3 = 1 << 11, + DirtyFlag_Sampler4 = 1 << 12, + DirtyFlag_Sampler5 = 1 << 13, + DirtyFlag_Sampler6 = 1 << 14, + DirtyFlag_Sampler7 = 1 << 15, - DirtyFlag_Sampler0 = 1 << 8, - DirtyFlag_Sampler1 = 1 << 9, - DirtyFlag_Sampler2 = 1 << 10, - DirtyFlag_Sampler3 = 1 << 11, - DirtyFlag_Sampler4 = 1 << 12, - DirtyFlag_Sampler5 = 1 << 13, - DirtyFlag_Sampler6 = 1 << 14, - DirtyFlag_Sampler7 = 1 << 15, + DirtyFlag_PixelConstants = 1 << 16, + DirtyFlag_VertexConstants = 1 << 17, + DirtyFlag_GeometryConstants = 1 << 18, - DirtyFlag_PixelConstants = 1 << 16, - DirtyFlag_VertexConstants = 1 << 17, - DirtyFlag_GeometryConstants = 1 << 18, + DirtyFlag_VertexBuffer = 1 << 19, + DirtyFlag_IndexBuffer = 1 << 20, - DirtyFlag_VertexBuffer = 1 << 19, - DirtyFlag_IndexBuffer = 1 << 20, + DirtyFlag_PixelShader = 1 << 21, + DirtyFlag_VertexShader = 1 << 22, + DirtyFlag_GeometryShader = 1 << 23, - DirtyFlag_PixelShader = 1 << 21, - DirtyFlag_VertexShader = 1 << 22, - DirtyFlag_GeometryShader = 1 << 23, + DirtyFlag_InputAssembler = 1 << 24, + }; - DirtyFlag_InputAssembler = 1 << 24, - }; + u32 m_dirtyFlags; - u32 m_dirtyFlags; + struct Resources + { + ID3D11ShaderResourceView* textures[8]; + ID3D11SamplerState* samplers[8]; + ID3D11Buffer* pixelConstants[2]; + ID3D11Buffer* vertexConstants; + ID3D11Buffer* geometryConstants; + ID3D11Buffer* vertexBuffer; + ID3D11Buffer* indexBuffer; + u32 vertexBufferStride; + u32 vertexBufferOffset; + D3D11_PRIMITIVE_TOPOLOGY topology; + ID3D11InputLayout* inputLayout; + ID3D11PixelShader* pixelShader; + ID3D11VertexShader* vertexShader; + ID3D11GeometryShader* geometryShader; + }; - struct Resources - { - ID3D11ShaderResourceView* textures[8]; - ID3D11SamplerState* samplers[8]; - ID3D11Buffer* pixelConstants[2]; - ID3D11Buffer* vertexConstants; - ID3D11Buffer* geometryConstants; - ID3D11Buffer* vertexBuffer; - ID3D11Buffer* indexBuffer; - u32 vertexBufferStride; - u32 vertexBufferOffset; - D3D11_PRIMITIVE_TOPOLOGY topology; - ID3D11InputLayout* inputLayout; - ID3D11PixelShader* pixelShader; - ID3D11VertexShader* vertexShader; - ID3D11GeometryShader* geometryShader; - }; - - Resources m_pending; - Resources m_current; + Resources m_pending; + Resources m_current; }; extern StateManager* stateman; diff --git a/Source/Core/VideoBackends/D3D/D3DTexture.cpp b/Source/Core/VideoBackends/D3D/D3DTexture.cpp index b5a65c9a39..fb5e710711 100644 --- a/Source/Core/VideoBackends/D3D/D3DTexture.cpp +++ b/Source/Core/VideoBackends/D3D/D3DTexture.cpp @@ -11,110 +11,129 @@ namespace DX11 { - namespace D3D { - -void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int src_pitch, unsigned int level, D3D11_USAGE usage) +void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, + unsigned int height, unsigned int src_pitch, unsigned int level, + D3D11_USAGE usage) { - if (usage == D3D11_USAGE_DYNAMIC || usage == D3D11_USAGE_STAGING) - { - D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(pTexture, level, D3D11_MAP_WRITE_DISCARD, 0, &map); - if (src_pitch == map.RowPitch) - { - memcpy(map.pData, buffer, map.RowPitch * height); - } - else - { - // Source row size is aligned to texture block size. This can result in a different - // pitch to what the driver returns, so copy whichever is smaller. - unsigned int copy_size = std::min(src_pitch, map.RowPitch); - for (unsigned int y = 0; y < height; ++y) - memcpy((u8*)map.pData + y * map.RowPitch, buffer + y * src_pitch, copy_size); - } - D3D::context->Unmap(pTexture, level); - } - else - { - D3D11_BOX dest_region = CD3D11_BOX(0, 0, 0, width, height, 1); - D3D::context->UpdateSubresource(pTexture, level, &dest_region, buffer, src_pitch, src_pitch * height); - } + if (usage == D3D11_USAGE_DYNAMIC || usage == D3D11_USAGE_STAGING) + { + D3D11_MAPPED_SUBRESOURCE map; + D3D::context->Map(pTexture, level, D3D11_MAP_WRITE_DISCARD, 0, &map); + if (src_pitch == map.RowPitch) + { + memcpy(map.pData, buffer, map.RowPitch * height); + } + else + { + // Source row size is aligned to texture block size. This can result in a different + // pitch to what the driver returns, so copy whichever is smaller. + unsigned int copy_size = std::min(src_pitch, map.RowPitch); + for (unsigned int y = 0; y < height; ++y) + memcpy((u8*)map.pData + y * map.RowPitch, buffer + y * src_pitch, copy_size); + } + D3D::context->Unmap(pTexture, level); + } + else + { + D3D11_BOX dest_region = CD3D11_BOX(0, 0, 0, width, height, 1); + D3D::context->UpdateSubresource(pTexture, level, &dest_region, buffer, src_pitch, + src_pitch * height); + } } } // namespace -D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT fmt, unsigned int levels, unsigned int slices, D3D11_SUBRESOURCE_DATA* data) +D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, + D3D11_USAGE usage, DXGI_FORMAT fmt, unsigned int levels, + unsigned int slices, D3D11_SUBRESOURCE_DATA* data) { - ID3D11Texture2D* pTexture = nullptr; - HRESULT hr; + ID3D11Texture2D* pTexture = nullptr; + HRESULT hr; - D3D11_CPU_ACCESS_FLAG cpuflags; - if (usage == D3D11_USAGE_STAGING) - cpuflags = (D3D11_CPU_ACCESS_FLAG)((int)D3D11_CPU_ACCESS_WRITE|(int)D3D11_CPU_ACCESS_READ); - else if (usage == D3D11_USAGE_DYNAMIC) - cpuflags = D3D11_CPU_ACCESS_WRITE; - else - cpuflags = (D3D11_CPU_ACCESS_FLAG)0; - D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(fmt, width, height, slices, levels, bind, usage, cpuflags); - hr = D3D::device->CreateTexture2D(&texdesc, data, &pTexture); - if (FAILED(hr)) - { - PanicAlert("Failed to create texture at %s, line %d: hr=%#x\n", __FILE__, __LINE__, hr); - return nullptr; - } + D3D11_CPU_ACCESS_FLAG cpuflags; + if (usage == D3D11_USAGE_STAGING) + cpuflags = (D3D11_CPU_ACCESS_FLAG)((int)D3D11_CPU_ACCESS_WRITE | (int)D3D11_CPU_ACCESS_READ); + else if (usage == D3D11_USAGE_DYNAMIC) + cpuflags = D3D11_CPU_ACCESS_WRITE; + else + cpuflags = (D3D11_CPU_ACCESS_FLAG)0; + D3D11_TEXTURE2D_DESC texdesc = + CD3D11_TEXTURE2D_DESC(fmt, width, height, slices, levels, bind, usage, cpuflags); + hr = D3D::device->CreateTexture2D(&texdesc, data, &pTexture); + if (FAILED(hr)) + { + PanicAlert("Failed to create texture at %s, line %d: hr=%#x\n", __FILE__, __LINE__, hr); + return nullptr; + } - D3DTexture2D* ret = new D3DTexture2D(pTexture, bind); - SAFE_RELEASE(pTexture); - return ret; + D3DTexture2D* ret = new D3DTexture2D(pTexture, bind); + SAFE_RELEASE(pTexture); + return ret; } void D3DTexture2D::AddRef() { - ++ref; + ++ref; } UINT D3DTexture2D::Release() { - --ref; - if (ref == 0) - { - delete this; - return 0; - } - return ref; + --ref; + if (ref == 0) + { + delete this; + return 0; + } + return ref; } -ID3D11Texture2D* &D3DTexture2D::GetTex() { return tex; } -ID3D11ShaderResourceView* &D3DTexture2D::GetSRV() { return srv; } -ID3D11RenderTargetView* &D3DTexture2D::GetRTV() { return rtv; } -ID3D11DepthStencilView* &D3DTexture2D::GetDSV() { return dsv; } - -D3DTexture2D::D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind, - DXGI_FORMAT srv_format, DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format, bool multisampled) - : ref(1), tex(texptr), srv(nullptr), rtv(nullptr), dsv(nullptr) +ID3D11Texture2D*& D3DTexture2D::GetTex() { - D3D11_SRV_DIMENSION srv_dim = multisampled ? D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY : D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - D3D11_DSV_DIMENSION dsv_dim = multisampled ? D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D11_DSV_DIMENSION_TEXTURE2DARRAY; - D3D11_RTV_DIMENSION rtv_dim = multisampled ? D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = CD3D11_SHADER_RESOURCE_VIEW_DESC(srv_dim, srv_format); - D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = CD3D11_DEPTH_STENCIL_VIEW_DESC(dsv_dim, dsv_format); - D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = CD3D11_RENDER_TARGET_VIEW_DESC(rtv_dim, rtv_format); - if (bind & D3D11_BIND_SHADER_RESOURCE) - D3D::device->CreateShaderResourceView(tex, &srv_desc, &srv); - if (bind & D3D11_BIND_RENDER_TARGET) - D3D::device->CreateRenderTargetView(tex, &rtv_desc, &rtv); - if (bind & D3D11_BIND_DEPTH_STENCIL) - D3D::device->CreateDepthStencilView(tex, &dsv_desc, &dsv); - tex->AddRef(); + return tex; +} +ID3D11ShaderResourceView*& D3DTexture2D::GetSRV() +{ + return srv; +} +ID3D11RenderTargetView*& D3DTexture2D::GetRTV() +{ + return rtv; +} +ID3D11DepthStencilView*& D3DTexture2D::GetDSV() +{ + return dsv; +} + +D3DTexture2D::D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind, DXGI_FORMAT srv_format, + DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format, bool multisampled) + : ref(1), tex(texptr), srv(nullptr), rtv(nullptr), dsv(nullptr) +{ + D3D11_SRV_DIMENSION srv_dim = + multisampled ? D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY : D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + D3D11_DSV_DIMENSION dsv_dim = + multisampled ? D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + D3D11_RTV_DIMENSION rtv_dim = + multisampled ? D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = CD3D11_SHADER_RESOURCE_VIEW_DESC(srv_dim, srv_format); + D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = CD3D11_DEPTH_STENCIL_VIEW_DESC(dsv_dim, dsv_format); + D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = CD3D11_RENDER_TARGET_VIEW_DESC(rtv_dim, rtv_format); + if (bind & D3D11_BIND_SHADER_RESOURCE) + D3D::device->CreateShaderResourceView(tex, &srv_desc, &srv); + if (bind & D3D11_BIND_RENDER_TARGET) + D3D::device->CreateRenderTargetView(tex, &rtv_desc, &rtv); + if (bind & D3D11_BIND_DEPTH_STENCIL) + D3D::device->CreateDepthStencilView(tex, &dsv_desc, &dsv); + tex->AddRef(); } D3DTexture2D::~D3DTexture2D() { - SAFE_RELEASE(srv); - SAFE_RELEASE(rtv); - SAFE_RELEASE(dsv); - SAFE_RELEASE(tex); + SAFE_RELEASE(srv); + SAFE_RELEASE(rtv); + SAFE_RELEASE(dsv); + SAFE_RELEASE(tex); } } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/D3DTexture.h b/Source/Core/VideoBackends/D3D/D3DTexture.h index 86d7c188a4..4afb73b260 100644 --- a/Source/Core/VideoBackends/D3D/D3DTexture.h +++ b/Source/Core/VideoBackends/D3D/D3DTexture.h @@ -8,40 +8,48 @@ namespace DX11 { - namespace D3D { - void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int src_pitch, unsigned int level, D3D11_USAGE usage); +void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, + unsigned int height, unsigned int src_pitch, unsigned int level, + D3D11_USAGE usage); } class D3DTexture2D { public: - // there are two ways to create a D3DTexture2D object: - // either create an ID3D11Texture2D object, pass it to the constructor and specify what views to create - // or let the texture automatically be created by D3DTexture2D::Create + // there are two ways to create a D3DTexture2D object: + // either create an ID3D11Texture2D object, pass it to the constructor and specify what views + // to create + // or let the texture automatically be created by D3DTexture2D::Create - D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind, DXGI_FORMAT srv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN, bool multisampled = false); - static D3DTexture2D* Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT, unsigned int levels = 1, unsigned int slices = 1, D3D11_SUBRESOURCE_DATA* data = nullptr); + D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind, + DXGI_FORMAT srv_format = DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN, bool multisampled = false); + static D3DTexture2D* Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, + D3D11_USAGE usage, DXGI_FORMAT, unsigned int levels = 1, + unsigned int slices = 1, D3D11_SUBRESOURCE_DATA* data = nullptr); - // reference counting, use AddRef() when creating a new reference and Release() it when you don't need it anymore - void AddRef(); - UINT Release(); + // reference counting, use AddRef() when creating a new reference and Release() it when you don't + // need it anymore + void AddRef(); + UINT Release(); - ID3D11Texture2D* &GetTex(); - ID3D11ShaderResourceView* &GetSRV(); - ID3D11RenderTargetView* &GetRTV(); - ID3D11DepthStencilView* &GetDSV(); + ID3D11Texture2D*& GetTex(); + ID3D11ShaderResourceView*& GetSRV(); + ID3D11RenderTargetView*& GetRTV(); + ID3D11DepthStencilView*& GetDSV(); private: - ~D3DTexture2D(); + ~D3DTexture2D(); - ID3D11Texture2D* tex; - ID3D11ShaderResourceView* srv; - ID3D11RenderTargetView* rtv; - ID3D11DepthStencilView* dsv; - D3D11_BIND_FLAG bindflags; - UINT ref; + ID3D11Texture2D* tex; + ID3D11ShaderResourceView* srv; + ID3D11RenderTargetView* rtv; + ID3D11DepthStencilView* dsv; + D3D11_BIND_FLAG bindflags; + UINT ref; }; } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/D3DUtil.cpp b/Source/Core/VideoBackends/D3D/D3DUtil.cpp index 1b56fad9f7..639b1988c0 100644 --- a/Source/Core/VideoBackends/D3D/D3DUtil.cpp +++ b/Source/Core/VideoBackends/D3D/D3DUtil.cpp @@ -16,473 +16,488 @@ namespace DX11 { - namespace D3D { - // Ring buffer class, shared between the draw* functions class UtilVertexBuffer { public: - UtilVertexBuffer(int size) : buf(nullptr), offset(0), max_size(size) - { - D3D11_BUFFER_DESC desc = CD3D11_BUFFER_DESC(max_size, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - device->CreateBuffer(&desc, nullptr, &buf); - } - ~UtilVertexBuffer() - { - buf->Release(); - } + UtilVertexBuffer(int size) : buf(nullptr), offset(0), max_size(size) + { + D3D11_BUFFER_DESC desc = CD3D11_BUFFER_DESC(max_size, D3D11_BIND_VERTEX_BUFFER, + D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + device->CreateBuffer(&desc, nullptr, &buf); + } + ~UtilVertexBuffer() { buf->Release(); } + int GetSize() const { return max_size; } + // returns vertex offset to the new data + int AppendData(void* data, int size, int vertex_size) + { + D3D11_MAPPED_SUBRESOURCE map; + if (offset + size >= max_size) + { + // wrap buffer around and notify observers + offset = 0; + context->Map(buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - int GetSize() const { return max_size; } + for (bool* observer : observers) + *observer = true; + } + else + { + context->Map(buf, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map); + } + offset = ((offset + vertex_size - 1) / vertex_size) * + vertex_size; // align offset to vertex_size bytes + memcpy((u8*)map.pData + offset, data, size); + context->Unmap(buf, 0); - // returns vertex offset to the new data - int AppendData(void* data, int size, int vertex_size) - { - D3D11_MAPPED_SUBRESOURCE map; - if (offset + size >= max_size) - { - // wrap buffer around and notify observers - offset = 0; - context->Map(buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + offset += size; + return (offset - size) / vertex_size; + } - for (bool* observer : observers) - *observer = true; - } - else - { - context->Map(buf, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map); - } - offset = ((offset+vertex_size-1)/vertex_size)*vertex_size; // align offset to vertex_size bytes - memcpy((u8*)map.pData + offset, data, size); - context->Unmap(buf, 0); + int BeginAppendData(void** write_ptr, int size, int vertex_size) + { + _dbg_assert_(VIDEO, size < max_size); - offset += size; - return (offset - size) / vertex_size; - } + D3D11_MAPPED_SUBRESOURCE map; + int aligned_offset = ((offset + vertex_size - 1) / vertex_size) * + vertex_size; // align offset to vertex_size bytes + if (aligned_offset + size > max_size) + { + // wrap buffer around and notify observers + offset = 0; + aligned_offset = 0; + context->Map(buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - int BeginAppendData(void** write_ptr, int size, int vertex_size) - { - _dbg_assert_(VIDEO, size < max_size); + for (bool* observer : observers) + *observer = true; + } + else + { + context->Map(buf, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map); + } - D3D11_MAPPED_SUBRESOURCE map; - int aligned_offset = ((offset + vertex_size - 1) / vertex_size) * vertex_size; // align offset to vertex_size bytes - if (aligned_offset + size > max_size) - { - // wrap buffer around and notify observers - offset = 0; - aligned_offset = 0; - context->Map(buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - - for (bool* observer : observers) - *observer = true; - } - else - { - context->Map(buf, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map); - } - - *write_ptr = reinterpret_cast(map.pData) + aligned_offset; - offset = aligned_offset + size; - return aligned_offset / vertex_size; - } - - void EndAppendData() - { - context->Unmap(buf, 0); - } - - void AddWrapObserver(bool* observer) - { - observers.push_back(observer); - } - - inline ID3D11Buffer* &GetBuffer() { return buf; } + *write_ptr = reinterpret_cast(map.pData) + aligned_offset; + offset = aligned_offset + size; + return aligned_offset / vertex_size; + } + void EndAppendData() { context->Unmap(buf, 0); } + void AddWrapObserver(bool* observer) { observers.push_back(observer); } + inline ID3D11Buffer*& GetBuffer() { return buf; } private: - ID3D11Buffer* buf; - int offset; - int max_size; + ID3D11Buffer* buf; + int offset; + int max_size; - std::list observers; + std::list observers; }; CD3DFont font; UtilVertexBuffer* util_vbuf = nullptr; -#define MAX_NUM_VERTICES 50*6 -struct FONT2DVERTEX { - float x,y,z; - float col[4]; - float tu, tv; +#define MAX_NUM_VERTICES 50 * 6 +struct FONT2DVERTEX +{ + float x, y, z; + float col[4]; + float tu, tv; }; inline FONT2DVERTEX InitFont2DVertex(float x, float y, u32 color, float tu, float tv) { - FONT2DVERTEX v; v.x=x; v.y=y; v.z=0; v.tu = tu; v.tv = tv; - v.col[0] = ((float)((color >> 16) & 0xFF)) / 255.f; - v.col[1] = ((float)((color >> 8) & 0xFF)) / 255.f; - v.col[2] = ((float)((color >> 0) & 0xFF)) / 255.f; - v.col[3] = ((float)((color >> 24) & 0xFF)) / 255.f; - return v; + FONT2DVERTEX v; + v.x = x; + v.y = y; + v.z = 0; + v.tu = tu; + v.tv = tv; + v.col[0] = ((float)((color >> 16) & 0xFF)) / 255.f; + v.col[1] = ((float)((color >> 8) & 0xFF)) / 255.f; + v.col[2] = ((float)((color >> 0) & 0xFF)) / 255.f; + v.col[3] = ((float)((color >> 24) & 0xFF)) / 255.f; + return v; } CD3DFont::CD3DFont() : m_dwTexWidth(512), m_dwTexHeight(512) { - m_pTexture = nullptr; - m_pVB = nullptr; - m_InputLayout = nullptr; - m_pshader = nullptr; - m_vshader = nullptr; + m_pTexture = nullptr; + m_pVB = nullptr; + m_InputLayout = nullptr; + m_pshader = nullptr; + m_vshader = nullptr; } -const char fontpixshader[] = { - "Texture2D tex2D;\n" - "SamplerState linearSampler\n" - "{\n" - " Filter = MIN_MAG_MIP_LINEAR;\n" - " AddressU = D3D11_TEXTURE_ADDRESS_BORDER;\n" - " AddressV = D3D11_TEXTURE_ADDRESS_BORDER;\n" - " BorderColor = float4(0.f, 0.f, 0.f, 0.f);\n" - "};\n" - "struct PS_INPUT\n" - "{\n" - " float4 pos : SV_POSITION;\n" - " float4 col : COLOR;\n" - " float2 tex : TEXCOORD;\n" - "};\n" - "float4 main( PS_INPUT input ) : SV_Target\n" - "{\n" - " return tex2D.Sample( linearSampler, input.tex ) * input.col;\n" - "};\n" -}; +const char fontpixshader[] = {"Texture2D tex2D;\n" + "SamplerState linearSampler\n" + "{\n" + " Filter = MIN_MAG_MIP_LINEAR;\n" + " AddressU = D3D11_TEXTURE_ADDRESS_BORDER;\n" + " AddressV = D3D11_TEXTURE_ADDRESS_BORDER;\n" + " BorderColor = float4(0.f, 0.f, 0.f, 0.f);\n" + "};\n" + "struct PS_INPUT\n" + "{\n" + " float4 pos : SV_POSITION;\n" + " float4 col : COLOR;\n" + " float2 tex : TEXCOORD;\n" + "};\n" + "float4 main( PS_INPUT input ) : SV_Target\n" + "{\n" + " return tex2D.Sample( linearSampler, input.tex ) * input.col;\n" + "};\n"}; -const char fontvertshader[] = { - "struct VS_INPUT\n" - "{\n" - " float4 pos : POSITION;\n" - " float4 col : COLOR;\n" - " float2 tex : TEXCOORD;\n" - "};\n" - "struct PS_INPUT\n" - "{\n" - " float4 pos : SV_POSITION;\n" - " float4 col : COLOR;\n" - " float2 tex : TEXCOORD;\n" - "};\n" - "PS_INPUT main( VS_INPUT input )\n" - "{\n" - " PS_INPUT output;\n" - " output.pos = input.pos;\n" - " output.col = input.col;\n" - " output.tex = input.tex;\n" - " return output;\n" - "};\n" -}; +const char fontvertshader[] = {"struct VS_INPUT\n" + "{\n" + " float4 pos : POSITION;\n" + " float4 col : COLOR;\n" + " float2 tex : TEXCOORD;\n" + "};\n" + "struct PS_INPUT\n" + "{\n" + " float4 pos : SV_POSITION;\n" + " float4 col : COLOR;\n" + " float2 tex : TEXCOORD;\n" + "};\n" + "PS_INPUT main( VS_INPUT input )\n" + "{\n" + " PS_INPUT output;\n" + " output.pos = input.pos;\n" + " output.col = input.col;\n" + " output.tex = input.tex;\n" + " return output;\n" + "};\n"}; int CD3DFont::Init() { - // Create vertex buffer for the letters - HRESULT hr; + // Create vertex buffer for the letters + HRESULT hr; - // Prepare to create a bitmap - unsigned int* pBitmapBits; - BITMAPINFO bmi; - ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = (int)m_dwTexWidth; - bmi.bmiHeader.biHeight = -(int)m_dwTexHeight; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biBitCount = 32; + // Prepare to create a bitmap + unsigned int* pBitmapBits; + BITMAPINFO bmi; + ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = (int)m_dwTexWidth; + bmi.bmiHeader.biHeight = -(int)m_dwTexHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biBitCount = 32; - // Create a DC and a bitmap for the font - HDC hDC = CreateCompatibleDC(nullptr); - HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&pBitmapBits, nullptr, 0); - SetMapMode(hDC, MM_TEXT); + // Create a DC and a bitmap for the font + HDC hDC = CreateCompatibleDC(nullptr); + HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&pBitmapBits, nullptr, 0); + SetMapMode(hDC, MM_TEXT); - // create a GDI font - HFONT hFont = CreateFont(24, 0, 0, 0, FW_NORMAL, FALSE, - FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, PROOF_QUALITY, - VARIABLE_PITCH, _T("Tahoma")); - if (nullptr == hFont) return E_FAIL; + // create a GDI font + HFONT hFont = + CreateFont(24, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH, _T("Tahoma")); + if (nullptr == hFont) + return E_FAIL; - HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap); - HGDIOBJ hOldFont = SelectObject(hDC, hFont); + HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap); + HGDIOBJ hOldFont = SelectObject(hDC, hFont); - // Set text properties - SetTextColor(hDC, 0xFFFFFF); - SetBkColor (hDC, 0); - SetTextAlign(hDC, TA_TOP); + // Set text properties + SetTextColor(hDC, 0xFFFFFF); + SetBkColor(hDC, 0); + SetTextAlign(hDC, TA_TOP); - TEXTMETRICW tm; - GetTextMetricsW(hDC, &tm); - m_LineHeight = tm.tmHeight; + TEXTMETRICW tm; + GetTextMetricsW(hDC, &tm); + m_LineHeight = tm.tmHeight; - // Loop through all printable characters and output them to the bitmap - // Meanwhile, keep track of the corresponding tex coords for each character. - int x = 0, y = 0; - char str[2] = "\0"; - for (int c = 0; c < 127 - 32; c++) - { - str[0] = c + 32; - SIZE size; - GetTextExtentPoint32A(hDC, str, 1, &size); - if ((int)(x+size.cx+1) > m_dwTexWidth) - { - x = 0; - y += m_LineHeight; - } + // Loop through all printable characters and output them to the bitmap + // Meanwhile, keep track of the corresponding tex coords for each character. + int x = 0, y = 0; + char str[2] = "\0"; + for (int c = 0; c < 127 - 32; c++) + { + str[0] = c + 32; + SIZE size; + GetTextExtentPoint32A(hDC, str, 1, &size); + if ((int)(x + size.cx + 1) > m_dwTexWidth) + { + x = 0; + y += m_LineHeight; + } - ExtTextOutA(hDC, x+1, y+0, ETO_OPAQUE | ETO_CLIPPED, nullptr, str, 1, nullptr); - m_fTexCoords[c][0] = ((float)(x+0))/m_dwTexWidth; - m_fTexCoords[c][1] = ((float)(y+0))/m_dwTexHeight; - m_fTexCoords[c][2] = ((float)(x+0+size.cx))/m_dwTexWidth; - m_fTexCoords[c][3] = ((float)(y+0+size.cy))/m_dwTexHeight; + ExtTextOutA(hDC, x + 1, y + 0, ETO_OPAQUE | ETO_CLIPPED, nullptr, str, 1, nullptr); + m_fTexCoords[c][0] = ((float)(x + 0)) / m_dwTexWidth; + m_fTexCoords[c][1] = ((float)(y + 0)) / m_dwTexHeight; + m_fTexCoords[c][2] = ((float)(x + 0 + size.cx)) / m_dwTexWidth; + m_fTexCoords[c][3] = ((float)(y + 0 + size.cy)) / m_dwTexHeight; - x += size.cx + 3; // 3 to work around annoying ij conflict (part of the j ends up with the i) - } + x += size.cx + 3; // 3 to work around annoying ij conflict (part of the j ends up with the i) + } - // Create a new texture for the font - // possible optimization: store the converted data in a buffer and fill the texture on creation. - // That way, we can use a static texture - ID3D11Texture2D* buftex; - D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_dwTexWidth, m_dwTexHeight, - 1, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DYNAMIC, - D3D11_CPU_ACCESS_WRITE); - hr = device->CreateTexture2D(&texdesc, nullptr, &buftex); - if (FAILED(hr)) - { - PanicAlert("Failed to create font texture"); - return hr; - } - D3D::SetDebugObjectName((ID3D11DeviceChild*)buftex, "texture of a CD3DFont object"); + // Create a new texture for the font + // possible optimization: store the converted data in a buffer and fill the texture on creation. + // That way, we can use a static texture + ID3D11Texture2D* buftex; + D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC( + DXGI_FORMAT_R8G8B8A8_UNORM, m_dwTexWidth, m_dwTexHeight, 1, 1, D3D11_BIND_SHADER_RESOURCE, + D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + hr = device->CreateTexture2D(&texdesc, nullptr, &buftex); + if (FAILED(hr)) + { + PanicAlert("Failed to create font texture"); + return hr; + } + D3D::SetDebugObjectName((ID3D11DeviceChild*)buftex, "texture of a CD3DFont object"); - // Lock the surface and write the alpha values for the set pixels - D3D11_MAPPED_SUBRESOURCE texmap; - hr = context->Map(buftex, 0, D3D11_MAP_WRITE_DISCARD, 0, &texmap); - if (FAILED(hr)) PanicAlert("Failed to map a texture at %s %d\n", __FILE__, __LINE__); + // Lock the surface and write the alpha values for the set pixels + D3D11_MAPPED_SUBRESOURCE texmap; + hr = context->Map(buftex, 0, D3D11_MAP_WRITE_DISCARD, 0, &texmap); + if (FAILED(hr)) + PanicAlert("Failed to map a texture at %s %d\n", __FILE__, __LINE__); - for (y = 0; y < m_dwTexHeight; y++) - { - u32* pDst32 = (u32*)((u8*)texmap.pData + y * texmap.RowPitch); - for (x = 0; x < m_dwTexWidth; x++) - { - const u8 bAlpha = (pBitmapBits[m_dwTexWidth * y + x] & 0xff); - *pDst32++ = (((bAlpha << 4) | bAlpha) << 24) | 0xFFFFFF; - } - } + for (y = 0; y < m_dwTexHeight; y++) + { + u32* pDst32 = (u32*)((u8*)texmap.pData + y * texmap.RowPitch); + for (x = 0; x < m_dwTexWidth; x++) + { + const u8 bAlpha = (pBitmapBits[m_dwTexWidth * y + x] & 0xff); + *pDst32++ = (((bAlpha << 4) | bAlpha) << 24) | 0xFFFFFF; + } + } - // Done updating texture, so clean up used objects - context->Unmap(buftex, 0); - hr = D3D::device->CreateShaderResourceView(buftex, nullptr, &m_pTexture); - if (FAILED(hr)) PanicAlert("Failed to create shader resource view at %s %d\n", __FILE__, __LINE__); - SAFE_RELEASE(buftex); + // Done updating texture, so clean up used objects + context->Unmap(buftex, 0); + hr = D3D::device->CreateShaderResourceView(buftex, nullptr, &m_pTexture); + if (FAILED(hr)) + PanicAlert("Failed to create shader resource view at %s %d\n", __FILE__, __LINE__); + SAFE_RELEASE(buftex); - SelectObject(hDC, hOldbmBitmap); - DeleteObject(hbmBitmap); + SelectObject(hDC, hOldbmBitmap); + DeleteObject(hbmBitmap); - SelectObject(hDC, hOldFont); - DeleteObject(hFont); + SelectObject(hDC, hOldFont); + DeleteObject(hFont); - // setup device objects for drawing - m_pshader = D3D::CompileAndCreatePixelShader(fontpixshader); - if (m_pshader == nullptr) PanicAlert("Failed to create pixel shader, %s %d\n", __FILE__, __LINE__); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_pshader, "pixel shader of a CD3DFont object"); + // setup device objects for drawing + m_pshader = D3D::CompileAndCreatePixelShader(fontpixshader); + if (m_pshader == nullptr) + PanicAlert("Failed to create pixel shader, %s %d\n", __FILE__, __LINE__); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_pshader, "pixel shader of a CD3DFont object"); - D3DBlob* vsbytecode; - D3D::CompileVertexShader(fontvertshader, &vsbytecode); - if (vsbytecode == nullptr) PanicAlert("Failed to compile vertex shader, %s %d\n", __FILE__, __LINE__); - m_vshader = D3D::CreateVertexShaderFromByteCode(vsbytecode); - if (m_vshader == nullptr) PanicAlert("Failed to create vertex shader, %s %d\n", __FILE__, __LINE__); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_vshader, "vertex shader of a CD3DFont object"); + D3DBlob* vsbytecode; + D3D::CompileVertexShader(fontvertshader, &vsbytecode); + if (vsbytecode == nullptr) + PanicAlert("Failed to compile vertex shader, %s %d\n", __FILE__, __LINE__); + m_vshader = D3D::CreateVertexShaderFromByteCode(vsbytecode); + if (m_vshader == nullptr) + PanicAlert("Failed to create vertex shader, %s %d\n", __FILE__, __LINE__); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_vshader, "vertex shader of a CD3DFont object"); - const D3D11_INPUT_ELEMENT_DESC desc[] = - { - { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - }; - hr = D3D::device->CreateInputLayout(desc, 3, vsbytecode->Data(), vsbytecode->Size(), &m_InputLayout); - if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__); - SAFE_RELEASE(vsbytecode); + const D3D11_INPUT_ELEMENT_DESC desc[] = { + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }; + hr = D3D::device->CreateInputLayout(desc, 3, vsbytecode->Data(), vsbytecode->Size(), + &m_InputLayout); + if (FAILED(hr)) + PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__); + SAFE_RELEASE(vsbytecode); - D3D11_BLEND_DESC blenddesc; - blenddesc.AlphaToCoverageEnable = FALSE; - blenddesc.IndependentBlendEnable = FALSE; - blenddesc.RenderTarget[0].BlendEnable = TRUE; - blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; - blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; - blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; - blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; - blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - hr = D3D::device->CreateBlendState(&blenddesc, &m_blendstate); - CHECK(hr==S_OK, "Create font blend state"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_blendstate, "blend state of a CD3DFont object"); + D3D11_BLEND_DESC blenddesc; + blenddesc.AlphaToCoverageEnable = FALSE; + blenddesc.IndependentBlendEnable = FALSE; + blenddesc.RenderTarget[0].BlendEnable = TRUE; + blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; + blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + hr = D3D::device->CreateBlendState(&blenddesc, &m_blendstate); + CHECK(hr == S_OK, "Create font blend state"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_blendstate, "blend state of a CD3DFont object"); - D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0.f, false, false, false, false); - hr = D3D::device->CreateRasterizerState(&rastdesc, &m_raststate); - CHECK(hr==S_OK, "Create font rasterizer state"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_raststate, "rasterizer state of a CD3DFont object"); + D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, + 0, 0.f, 0.f, false, false, false, false); + hr = D3D::device->CreateRasterizerState(&rastdesc, &m_raststate); + CHECK(hr == S_OK, "Create font rasterizer state"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_raststate, "rasterizer state of a CD3DFont object"); - D3D11_BUFFER_DESC vbdesc = CD3D11_BUFFER_DESC(MAX_NUM_VERTICES*sizeof(FONT2DVERTEX), D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - if (FAILED(hr = device->CreateBuffer(&vbdesc, nullptr, &m_pVB))) - { - PanicAlert("Failed to create font vertex buffer at %s, line %d\n", __FILE__, __LINE__); - return hr; - } - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_pVB, "vertex buffer of a CD3DFont object"); - return S_OK; + D3D11_BUFFER_DESC vbdesc = + CD3D11_BUFFER_DESC(MAX_NUM_VERTICES * sizeof(FONT2DVERTEX), D3D11_BIND_VERTEX_BUFFER, + D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + if (FAILED(hr = device->CreateBuffer(&vbdesc, nullptr, &m_pVB))) + { + PanicAlert("Failed to create font vertex buffer at %s, line %d\n", __FILE__, __LINE__); + return hr; + } + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_pVB, "vertex buffer of a CD3DFont object"); + return S_OK; } int CD3DFont::Shutdown() { - SAFE_RELEASE(m_pVB); - SAFE_RELEASE(m_pTexture); - SAFE_RELEASE(m_InputLayout); - SAFE_RELEASE(m_pshader); - SAFE_RELEASE(m_vshader); + SAFE_RELEASE(m_pVB); + SAFE_RELEASE(m_pTexture); + SAFE_RELEASE(m_InputLayout); + SAFE_RELEASE(m_pshader); + SAFE_RELEASE(m_vshader); - SAFE_RELEASE(m_blendstate); - SAFE_RELEASE(m_raststate); + SAFE_RELEASE(m_blendstate); + SAFE_RELEASE(m_raststate); - return S_OK; + return S_OK; } -int CD3DFont::DrawTextScaled(float x, float y, float size, float spacing, u32 dwColor, const std::string& text) +int CD3DFont::DrawTextScaled(float x, float y, float size, float spacing, u32 dwColor, + const std::string& text) { - if (!m_pVB) - return 0; + if (!m_pVB) + return 0; - UINT stride = sizeof(FONT2DVERTEX); - UINT bufoffset = 0; + UINT stride = sizeof(FONT2DVERTEX); + UINT bufoffset = 0; - float scalex = 1 / (float)D3D::GetBackBufferWidth() * 2.f; - float scaley = 1 / (float)D3D::GetBackBufferHeight() * 2.f; - float sizeratio = size / (float)m_LineHeight; + float scalex = 1 / (float)D3D::GetBackBufferWidth() * 2.f; + float scaley = 1 / (float)D3D::GetBackBufferHeight() * 2.f; + float sizeratio = size / (float)m_LineHeight; - // translate starting positions - float sx = x * scalex - 1.f; - float sy = 1.f - y * scaley; + // translate starting positions + float sx = x * scalex - 1.f; + float sy = 1.f - y * scaley; - // Fill vertex buffer - FONT2DVERTEX* pVertices; - int dwNumTriangles = 0L; + // Fill vertex buffer + FONT2DVERTEX* pVertices; + int dwNumTriangles = 0L; - D3D11_MAPPED_SUBRESOURCE vbmap; - HRESULT hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vbmap); - if (FAILED(hr)) PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__); - pVertices = (D3D::FONT2DVERTEX*)vbmap.pData; + D3D11_MAPPED_SUBRESOURCE vbmap; + HRESULT hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vbmap); + if (FAILED(hr)) + PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__); + pVertices = (D3D::FONT2DVERTEX*)vbmap.pData; - // set general pipeline state - D3D::stateman->PushBlendState(m_blendstate); - D3D::stateman->PushRasterizerState(m_raststate); + // set general pipeline state + D3D::stateman->PushBlendState(m_blendstate); + D3D::stateman->PushRasterizerState(m_raststate); - D3D::stateman->SetPixelShader(m_pshader); - D3D::stateman->SetVertexShader(m_vshader); - D3D::stateman->SetGeometryShader(nullptr); + D3D::stateman->SetPixelShader(m_pshader); + D3D::stateman->SetVertexShader(m_vshader); + D3D::stateman->SetGeometryShader(nullptr); - D3D::stateman->SetInputLayout(m_InputLayout); - D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - D3D::stateman->SetTexture(0, m_pTexture); + D3D::stateman->SetInputLayout(m_InputLayout); + D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + D3D::stateman->SetTexture(0, m_pTexture); - float fStartX = sx; - for (char c : text) - { - if (c == '\n') - { - sx = fStartX; - sy -= scaley * size; - } - if (!std::isprint(c)) - continue; + float fStartX = sx; + for (char c : text) + { + if (c == '\n') + { + sx = fStartX; + sy -= scaley * size; + } + if (!std::isprint(c)) + continue; - c -= 32; - float tx1 = m_fTexCoords[c][0]; - float ty1 = m_fTexCoords[c][1]; - float tx2 = m_fTexCoords[c][2]; - float ty2 = m_fTexCoords[c][3]; + c -= 32; + float tx1 = m_fTexCoords[c][0]; + float ty1 = m_fTexCoords[c][1]; + float tx2 = m_fTexCoords[c][2]; + float ty2 = m_fTexCoords[c][3]; - float w = (float)(tx2-tx1) * m_dwTexWidth * scalex * sizeratio; - float h = (float)(ty1-ty2) * m_dwTexHeight * scaley * sizeratio; + float w = (float)(tx2 - tx1) * m_dwTexWidth * scalex * sizeratio; + float h = (float)(ty1 - ty2) * m_dwTexHeight * scaley * sizeratio; - FONT2DVERTEX v[6]; - v[0] = InitFont2DVertex(sx, sy+h, dwColor, tx1, ty2); - v[1] = InitFont2DVertex(sx, sy, dwColor, tx1, ty1); - v[2] = InitFont2DVertex(sx+w, sy+h, dwColor, tx2, ty2); - v[3] = InitFont2DVertex(sx+w, sy, dwColor, tx2, ty1); - v[4] = v[2]; - v[5] = v[1]; + FONT2DVERTEX v[6]; + v[0] = InitFont2DVertex(sx, sy + h, dwColor, tx1, ty2); + v[1] = InitFont2DVertex(sx, sy, dwColor, tx1, ty1); + v[2] = InitFont2DVertex(sx + w, sy + h, dwColor, tx2, ty2); + v[3] = InitFont2DVertex(sx + w, sy, dwColor, tx2, ty1); + v[4] = v[2]; + v[5] = v[1]; - memcpy(pVertices, v, 6*sizeof(FONT2DVERTEX)); + memcpy(pVertices, v, 6 * sizeof(FONT2DVERTEX)); - pVertices+=6; - dwNumTriangles += 2; + pVertices += 6; + dwNumTriangles += 2; - if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) - { - context->Unmap(m_pVB, 0); + if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) + { + context->Unmap(m_pVB, 0); - D3D::stateman->SetVertexBuffer(m_pVB, stride, bufoffset); + D3D::stateman->SetVertexBuffer(m_pVB, stride, bufoffset); - D3D::stateman->Apply(); - D3D::context->Draw(3 * dwNumTriangles, 0); + D3D::stateman->Apply(); + D3D::context->Draw(3 * dwNumTriangles, 0); - dwNumTriangles = 0; - D3D11_MAPPED_SUBRESOURCE _vbmap; - hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &_vbmap); - if (FAILED(hr)) PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__); - pVertices = (D3D::FONT2DVERTEX*)_vbmap.pData; - } - sx += w + spacing * scalex * size; - } + dwNumTriangles = 0; + D3D11_MAPPED_SUBRESOURCE _vbmap; + hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &_vbmap); + if (FAILED(hr)) + PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__); + pVertices = (D3D::FONT2DVERTEX*)_vbmap.pData; + } + sx += w + spacing * scalex * size; + } - // Unlock and render the vertex buffer - context->Unmap(m_pVB, 0); - if (dwNumTriangles > 0) - { - D3D::stateman->SetVertexBuffer(m_pVB, stride, bufoffset); + // Unlock and render the vertex buffer + context->Unmap(m_pVB, 0); + if (dwNumTriangles > 0) + { + D3D::stateman->SetVertexBuffer(m_pVB, stride, bufoffset); - D3D::stateman->Apply(); - D3D::context->Draw(3 * dwNumTriangles, 0); - } - D3D::stateman->PopBlendState(); - D3D::stateman->PopRasterizerState(); - return S_OK; + D3D::stateman->Apply(); + D3D::context->Draw(3 * dwNumTriangles, 0); + } + D3D::stateman->PopBlendState(); + D3D::stateman->PopRasterizerState(); + return S_OK; } ID3D11SamplerState* linear_copy_sampler = nullptr; ID3D11SamplerState* point_copy_sampler = nullptr; -struct STQVertex { float x, y, z, u, v, w, g; }; -struct STSQVertex { float x, y, z, u, v, w, g; }; -struct ClearVertex { float x, y, z; u32 col; }; -struct ColVertex { float x, y, z; u32 col; }; +struct STQVertex +{ + float x, y, z, u, v, w, g; +}; +struct STSQVertex +{ + float x, y, z, u, v, w, g; +}; +struct ClearVertex +{ + float x, y, z; + u32 col; +}; +struct ColVertex +{ + float x, y, z; + u32 col; +}; struct { - float u1, v1, u2, v2, S, G; + float u1, v1, u2, v2, S, G; } tex_quad_data; struct { - MathUtil::Rectangle rdest; - float u1, v1, u2, v2, S, G; + MathUtil::Rectangle rdest; + float u1, v1, u2, v2, S, G; } tex_sub_quad_data; struct { - float x1, y1, x2, y2, z; - u32 col; + float x1, y1, x2, y2, z; + u32 col; } draw_quad_data; struct { - u32 col; - float z; + u32 col; + float z; } clear_quad_data; // ring buffer offsets @@ -493,256 +508,255 @@ bool stq_observer, stsq_observer, cq_observer, clearq_observer; void InitUtils() { - util_vbuf = new UtilVertexBuffer(65536); // 64KiB + util_vbuf = new UtilVertexBuffer(65536); // 64KiB - float border[4] = { 0.f, 0.f, 0.f, 0.f }; - D3D11_SAMPLER_DESC samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f); - HRESULT hr = D3D::device->CreateSamplerState(&samDesc, &point_copy_sampler); - if (FAILED(hr)) PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__); - else SetDebugObjectName((ID3D11DeviceChild*)point_copy_sampler, "point copy sampler state"); + float border[4] = {0.f, 0.f, 0.f, 0.f}; + D3D11_SAMPLER_DESC samDesc = CD3D11_SAMPLER_DESC( + D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, + D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f); + HRESULT hr = D3D::device->CreateSamplerState(&samDesc, &point_copy_sampler); + if (FAILED(hr)) + PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__); + else + SetDebugObjectName((ID3D11DeviceChild*)point_copy_sampler, "point copy sampler state"); - samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f); - hr = D3D::device->CreateSamplerState(&samDesc, &linear_copy_sampler); - if (FAILED(hr)) PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__); - else SetDebugObjectName((ID3D11DeviceChild*)linear_copy_sampler, "linear copy sampler state"); + samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_BORDER, + D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, + D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f); + hr = D3D::device->CreateSamplerState(&samDesc, &linear_copy_sampler); + if (FAILED(hr)) + PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__); + else + SetDebugObjectName((ID3D11DeviceChild*)linear_copy_sampler, "linear copy sampler state"); - // cached data used to avoid unnecessarily reloading the vertex buffers - memset(&tex_quad_data, 0, sizeof(tex_quad_data)); - memset(&tex_sub_quad_data, 0, sizeof(tex_sub_quad_data)); - memset(&draw_quad_data, 0, sizeof(draw_quad_data)); - memset(&clear_quad_data, 0, sizeof(clear_quad_data)); + // cached data used to avoid unnecessarily reloading the vertex buffers + memset(&tex_quad_data, 0, sizeof(tex_quad_data)); + memset(&tex_sub_quad_data, 0, sizeof(tex_sub_quad_data)); + memset(&draw_quad_data, 0, sizeof(draw_quad_data)); + memset(&clear_quad_data, 0, sizeof(clear_quad_data)); - // make sure to properly load the vertex data whenever the corresponding functions get called the first time - stq_observer = stsq_observer = cq_observer = clearq_observer = true; - util_vbuf->AddWrapObserver(&stq_observer); - util_vbuf->AddWrapObserver(&stsq_observer); - util_vbuf->AddWrapObserver(&cq_observer); - util_vbuf->AddWrapObserver(&clearq_observer); + // make sure to properly load the vertex data whenever the corresponding functions get called the + // first time + stq_observer = stsq_observer = cq_observer = clearq_observer = true; + util_vbuf->AddWrapObserver(&stq_observer); + util_vbuf->AddWrapObserver(&stsq_observer); + util_vbuf->AddWrapObserver(&cq_observer); + util_vbuf->AddWrapObserver(&clearq_observer); - font.Init(); + font.Init(); } void ShutdownUtils() { - font.Shutdown(); - SAFE_RELEASE(point_copy_sampler); - SAFE_RELEASE(linear_copy_sampler); - SAFE_DELETE(util_vbuf); + font.Shutdown(); + SAFE_RELEASE(point_copy_sampler); + SAFE_RELEASE(linear_copy_sampler); + SAFE_DELETE(util_vbuf); } void SetPointCopySampler() { - D3D::stateman->SetSampler(0, point_copy_sampler); + D3D::stateman->SetSampler(0, point_copy_sampler); } void SetLinearCopySampler() { - D3D::stateman->SetSampler(0, linear_copy_sampler); + D3D::stateman->SetSampler(0, linear_copy_sampler); } -void drawShadedTexQuad(ID3D11ShaderResourceView* texture, - const D3D11_RECT* rSource, - int SourceWidth, - int SourceHeight, - ID3D11PixelShader* PShader, - ID3D11VertexShader* VShader, - ID3D11InputLayout* layout, - ID3D11GeometryShader* GShader, - float Gamma, - u32 slice) +void drawShadedTexQuad(ID3D11ShaderResourceView* texture, const D3D11_RECT* rSource, + int SourceWidth, int SourceHeight, ID3D11PixelShader* PShader, + ID3D11VertexShader* VShader, ID3D11InputLayout* layout, + ID3D11GeometryShader* GShader, float Gamma, u32 slice) { - float sw = 1.0f /(float) SourceWidth; - float sh = 1.0f /(float) SourceHeight; - float u1 = ((float)rSource->left) * sw; - float u2 = ((float)rSource->right) * sw; - float v1 = ((float)rSource->top) * sh; - float v2 = ((float)rSource->bottom) * sh; - float S = (float)slice; - float G = 1.0f / Gamma; + float sw = 1.0f / (float)SourceWidth; + float sh = 1.0f / (float)SourceHeight; + float u1 = ((float)rSource->left) * sw; + float u2 = ((float)rSource->right) * sw; + float v1 = ((float)rSource->top) * sh; + float v2 = ((float)rSource->bottom) * sh; + float S = (float)slice; + float G = 1.0f / Gamma; - STQVertex coords[4] = { - {-1.0f, 1.0f, 0.0f, u1, v1, S, G}, - { 1.0f, 1.0f, 0.0f, u2, v1, S, G}, - {-1.0f,-1.0f, 0.0f, u1, v2, S, G}, - { 1.0f,-1.0f, 0.0f, u2, v2, S, G}, - }; + STQVertex coords[4] = { + {-1.0f, 1.0f, 0.0f, u1, v1, S, G}, + {1.0f, 1.0f, 0.0f, u2, v1, S, G}, + {-1.0f, -1.0f, 0.0f, u1, v2, S, G}, + {1.0f, -1.0f, 0.0f, u2, v2, S, G}, + }; - // only upload the data to VRAM if it changed - if (stq_observer || - tex_quad_data.u1 != u1 || tex_quad_data.v1 != v1 || - tex_quad_data.u2 != u2 || tex_quad_data.v2 != v2 || - tex_quad_data.S != S || tex_quad_data.G != G) - { - stq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(STQVertex)); - stq_observer = false; + // only upload the data to VRAM if it changed + if (stq_observer || tex_quad_data.u1 != u1 || tex_quad_data.v1 != v1 || tex_quad_data.u2 != u2 || + tex_quad_data.v2 != v2 || tex_quad_data.S != S || tex_quad_data.G != G) + { + stq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(STQVertex)); + stq_observer = false; - tex_quad_data.u1 = u1; - tex_quad_data.v1 = v1; - tex_quad_data.u2 = u2; - tex_quad_data.v2 = v2; - tex_quad_data.S = S; - tex_quad_data.G = G; - } - UINT stride = sizeof(STQVertex); - UINT offset = 0; + tex_quad_data.u1 = u1; + tex_quad_data.v1 = v1; + tex_quad_data.u2 = u2; + tex_quad_data.v2 = v2; + tex_quad_data.S = S; + tex_quad_data.G = G; + } + UINT stride = sizeof(STQVertex); + UINT offset = 0; - D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - D3D::stateman->SetInputLayout(layout); - D3D::stateman->SetVertexBuffer(util_vbuf->GetBuffer(), stride, offset); - D3D::stateman->SetPixelShader(PShader); - D3D::stateman->SetTexture(0, texture); - D3D::stateman->SetVertexShader(VShader); - D3D::stateman->SetGeometryShader(GShader); + D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + D3D::stateman->SetInputLayout(layout); + D3D::stateman->SetVertexBuffer(util_vbuf->GetBuffer(), stride, offset); + D3D::stateman->SetPixelShader(PShader); + D3D::stateman->SetTexture(0, texture); + D3D::stateman->SetVertexShader(VShader); + D3D::stateman->SetGeometryShader(GShader); - D3D::stateman->Apply(); - D3D::context->Draw(4, stq_offset); + D3D::stateman->Apply(); + D3D::context->Draw(4, stq_offset); - D3D::stateman->SetTexture(0, nullptr); // immediately unbind the texture - D3D::stateman->Apply(); + D3D::stateman->SetTexture(0, nullptr); // immediately unbind the texture + D3D::stateman->Apply(); - D3D::stateman->SetGeometryShader(nullptr); + D3D::stateman->SetGeometryShader(nullptr); } // Fills a certain area of the current render target with the specified color // destination coordinates normalized to (-1;1) void drawColorQuad(u32 Color, float z, float x1, float y1, float x2, float y2) { - ColVertex coords[4] = { - { x1, y1, z, Color }, - { x2, y1, z, Color }, - { x1, y2, z, Color }, - { x2, y2, z, Color }, - }; + ColVertex coords[4] = { + {x1, y1, z, Color}, {x2, y1, z, Color}, {x1, y2, z, Color}, {x2, y2, z, Color}, + }; - if (cq_observer || - draw_quad_data.x1 != x1 || draw_quad_data.y1 != y1 || - draw_quad_data.x2 != x2 || draw_quad_data.y2 != y2 || - draw_quad_data.col != Color || draw_quad_data.z != z) - { - cq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(ColVertex)); - cq_observer = false; + if (cq_observer || draw_quad_data.x1 != x1 || draw_quad_data.y1 != y1 || + draw_quad_data.x2 != x2 || draw_quad_data.y2 != y2 || draw_quad_data.col != Color || + draw_quad_data.z != z) + { + cq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(ColVertex)); + cq_observer = false; - draw_quad_data.x1 = x1; - draw_quad_data.y1 = y1; - draw_quad_data.x2 = x2; - draw_quad_data.y2 = y2; - draw_quad_data.col = Color; - draw_quad_data.z = z; - } + draw_quad_data.x1 = x1; + draw_quad_data.y1 = y1; + draw_quad_data.x2 = x2; + draw_quad_data.y2 = y2; + draw_quad_data.col = Color; + draw_quad_data.z = z; + } - stateman->SetVertexShader(VertexShaderCache::GetClearVertexShader()); - stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader()); - stateman->SetPixelShader(PixelShaderCache::GetClearProgram()); - stateman->SetInputLayout(VertexShaderCache::GetClearInputLayout()); + stateman->SetVertexShader(VertexShaderCache::GetClearVertexShader()); + stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader()); + stateman->SetPixelShader(PixelShaderCache::GetClearProgram()); + stateman->SetInputLayout(VertexShaderCache::GetClearInputLayout()); - UINT stride = sizeof(ColVertex); - UINT offset = 0; - stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - stateman->SetVertexBuffer(util_vbuf->GetBuffer(), stride, offset); + UINT stride = sizeof(ColVertex); + UINT offset = 0; + stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + stateman->SetVertexBuffer(util_vbuf->GetBuffer(), stride, offset); - stateman->Apply(); - context->Draw(4, cq_offset); + stateman->Apply(); + context->Draw(4, cq_offset); - stateman->SetGeometryShader(nullptr); + stateman->SetGeometryShader(nullptr); } void drawClearQuad(u32 Color, float z) { - ClearVertex coords[4] = { - {-1.0f, 1.0f, z, Color}, - { 1.0f, 1.0f, z, Color}, - {-1.0f, -1.0f, z, Color}, - { 1.0f, -1.0f, z, Color}, - }; + ClearVertex coords[4] = { + {-1.0f, 1.0f, z, Color}, + {1.0f, 1.0f, z, Color}, + {-1.0f, -1.0f, z, Color}, + {1.0f, -1.0f, z, Color}, + }; - if (clearq_observer || clear_quad_data.col != Color || clear_quad_data.z != z) - { - clearq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(ClearVertex)); - clearq_observer = false; + if (clearq_observer || clear_quad_data.col != Color || clear_quad_data.z != z) + { + clearq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(ClearVertex)); + clearq_observer = false; - clear_quad_data.col = Color; - clear_quad_data.z = z; - } + clear_quad_data.col = Color; + clear_quad_data.z = z; + } - stateman->SetVertexShader(VertexShaderCache::GetClearVertexShader()); - stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader()); - stateman->SetPixelShader(PixelShaderCache::GetClearProgram()); - stateman->SetInputLayout(VertexShaderCache::GetClearInputLayout()); + stateman->SetVertexShader(VertexShaderCache::GetClearVertexShader()); + stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader()); + stateman->SetPixelShader(PixelShaderCache::GetClearProgram()); + stateman->SetInputLayout(VertexShaderCache::GetClearInputLayout()); - UINT stride = sizeof(ClearVertex); - UINT offset = 0; - stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - stateman->SetVertexBuffer(util_vbuf->GetBuffer(), stride, offset); + UINT stride = sizeof(ClearVertex); + UINT offset = 0; + stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + stateman->SetVertexBuffer(util_vbuf->GetBuffer(), stride, offset); - stateman->Apply(); - context->Draw(4, clearq_offset); + stateman->Apply(); + context->Draw(4, clearq_offset); - stateman->SetGeometryShader(nullptr); + stateman->SetGeometryShader(nullptr); } static void InitColVertex(ColVertex* vert, float x, float y, float z, u32 col) { - vert->x = x; - vert->y = y; - vert->z = z; - vert->col = col; + vert->x = x; + vert->y = y; + vert->z = z; + vert->col = col; } void DrawEFBPokeQuads(EFBAccessType type, const EfbPokeData* points, size_t num_points) { - const size_t COL_QUAD_SIZE = sizeof(ColVertex) * 6; + const size_t COL_QUAD_SIZE = sizeof(ColVertex) * 6; - // Set common state - stateman->SetVertexShader(VertexShaderCache::GetClearVertexShader()); - stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader()); - stateman->SetPixelShader(PixelShaderCache::GetClearProgram()); - stateman->SetInputLayout(VertexShaderCache::GetClearInputLayout()); - stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - stateman->SetVertexBuffer(util_vbuf->GetBuffer(), sizeof(ColVertex), 0); - stateman->Apply(); + // Set common state + stateman->SetVertexShader(VertexShaderCache::GetClearVertexShader()); + stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader()); + stateman->SetPixelShader(PixelShaderCache::GetClearProgram()); + stateman->SetInputLayout(VertexShaderCache::GetClearInputLayout()); + stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + stateman->SetVertexBuffer(util_vbuf->GetBuffer(), sizeof(ColVertex), 0); + stateman->Apply(); - // if drawing a large number of points at once, this will have to be split into multiple passes. - size_t points_per_draw = util_vbuf->GetSize() / COL_QUAD_SIZE; - size_t current_point_index = 0; - while (current_point_index < num_points) - { - size_t points_to_draw = std::min(num_points - current_point_index, points_per_draw); - size_t required_bytes = COL_QUAD_SIZE * points_to_draw; + // if drawing a large number of points at once, this will have to be split into multiple passes. + size_t points_per_draw = util_vbuf->GetSize() / COL_QUAD_SIZE; + size_t current_point_index = 0; + while (current_point_index < num_points) + { + size_t points_to_draw = std::min(num_points - current_point_index, points_per_draw); + size_t required_bytes = COL_QUAD_SIZE * points_to_draw; - // map and reserve enough buffer space for this draw - void* buffer_ptr; - int base_vertex_index = util_vbuf->BeginAppendData(&buffer_ptr, (int)required_bytes, sizeof(ColVertex)); + // map and reserve enough buffer space for this draw + void* buffer_ptr; + int base_vertex_index = + util_vbuf->BeginAppendData(&buffer_ptr, (int)required_bytes, sizeof(ColVertex)); - // generate quads for each efb point - ColVertex* base_vertex_ptr = reinterpret_cast(buffer_ptr); - for (size_t i = 0; i < points_to_draw; i++) - { - // generate quad from the single point (clip-space coordinates) - const EfbPokeData* point = &points[current_point_index]; - float x1 = float(point->x) * 2.0f / EFB_WIDTH - 1.0f; - float y1 = -float(point->y) * 2.0f / EFB_HEIGHT + 1.0f; - float x2 = float(point->x + 1) * 2.0f / EFB_WIDTH - 1.0f; - float y2 = -float(point->y + 1) * 2.0f / EFB_HEIGHT + 1.0f; - float z = (type == POKE_Z) ? (1.0f - float(point->data & 0xFFFFFF) / 16777216.0f) : 0.0f; - u32 col = (type == POKE_Z) ? 0 : ((point->data & 0xFF00FF00) | ((point->data >> 16) & 0xFF) | ((point->data << 16) & 0xFF0000)); - current_point_index++; + // generate quads for each efb point + ColVertex* base_vertex_ptr = reinterpret_cast(buffer_ptr); + for (size_t i = 0; i < points_to_draw; i++) + { + // generate quad from the single point (clip-space coordinates) + const EfbPokeData* point = &points[current_point_index]; + float x1 = float(point->x) * 2.0f / EFB_WIDTH - 1.0f; + float y1 = -float(point->y) * 2.0f / EFB_HEIGHT + 1.0f; + float x2 = float(point->x + 1) * 2.0f / EFB_WIDTH - 1.0f; + float y2 = -float(point->y + 1) * 2.0f / EFB_HEIGHT + 1.0f; + float z = (type == POKE_Z) ? (1.0f - float(point->data & 0xFFFFFF) / 16777216.0f) : 0.0f; + u32 col = (type == POKE_Z) ? 0 : ((point->data & 0xFF00FF00) | ((point->data >> 16) & 0xFF) | + ((point->data << 16) & 0xFF0000)); + current_point_index++; - // quad -> triangles - ColVertex* vertex = &base_vertex_ptr[i * 6]; - InitColVertex(&vertex[0], x1, y1, z, col); - InitColVertex(&vertex[1], x2, y1, z, col); - InitColVertex(&vertex[2], x1, y2, z, col); - InitColVertex(&vertex[3], x1, y2, z, col); - InitColVertex(&vertex[4], x2, y1, z, col); - InitColVertex(&vertex[5], x2, y2, z, col); - } + // quad -> triangles + ColVertex* vertex = &base_vertex_ptr[i * 6]; + InitColVertex(&vertex[0], x1, y1, z, col); + InitColVertex(&vertex[1], x2, y1, z, col); + InitColVertex(&vertex[2], x1, y2, z, col); + InitColVertex(&vertex[3], x1, y2, z, col); + InitColVertex(&vertex[4], x2, y1, z, col); + InitColVertex(&vertex[5], x2, y2, z, col); + } - // unmap the util buffer, and issue the draw - util_vbuf->EndAppendData(); - context->Draw(6 * (UINT)points_to_draw, base_vertex_index); - } + // unmap the util buffer, and issue the draw + util_vbuf->EndAppendData(); + context->Draw(6 * (UINT)points_to_draw, base_vertex_index); + } - stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader()); + stateman->SetGeometryShader(GeometryShaderCache::GetClearGeometryShader()); } } // namespace D3D diff --git a/Source/Core/VideoBackends/D3D/D3DUtil.h b/Source/Core/VideoBackends/D3D/D3DUtil.h index a21c901c2e..43bbd0ecdd 100644 --- a/Source/Core/VideoBackends/D3D/D3DUtil.h +++ b/Source/Core/VideoBackends/D3D/D3DUtil.h @@ -12,64 +12,54 @@ namespace DX11 { - namespace D3D { - // Font creation flags - #define D3DFONT_BOLD 0x0001 - #define D3DFONT_ITALIC 0x0002 +// Font creation flags +#define D3DFONT_BOLD 0x0001 +#define D3DFONT_ITALIC 0x0002 - // Font rendering flags - #define D3DFONT_CENTERED 0x0001 +// Font rendering flags +#define D3DFONT_CENTERED 0x0001 - class CD3DFont - { - ID3D11ShaderResourceView* m_pTexture; - ID3D11Buffer* m_pVB; - ID3D11InputLayout* m_InputLayout; - ID3D11PixelShader* m_pshader; - ID3D11VertexShader* m_vshader; - ID3D11BlendState* m_blendstate; - ID3D11RasterizerState* m_raststate; - const int m_dwTexWidth; - const int m_dwTexHeight; - unsigned int m_LineHeight; - float m_fTexCoords[128-32][4]; +class CD3DFont +{ + ID3D11ShaderResourceView* m_pTexture; + ID3D11Buffer* m_pVB; + ID3D11InputLayout* m_InputLayout; + ID3D11PixelShader* m_pshader; + ID3D11VertexShader* m_vshader; + ID3D11BlendState* m_blendstate; + ID3D11RasterizerState* m_raststate; + const int m_dwTexWidth; + const int m_dwTexHeight; + unsigned int m_LineHeight; + float m_fTexCoords[128 - 32][4]; - public: - CD3DFont(); - // 2D text drawing function - // Initializing and destroying device-dependent objects - int Init(); - int Shutdown(); - int DrawTextScaled(float x, float y, - float size, - float spacing, u32 dwColor, - const std::string& text); - }; +public: + CD3DFont(); + // 2D text drawing function + // Initializing and destroying device-dependent objects + int Init(); + int Shutdown(); + int DrawTextScaled(float x, float y, float size, float spacing, u32 dwColor, + const std::string& text); +}; - extern CD3DFont font; +extern CD3DFont font; - void InitUtils(); - void ShutdownUtils(); +void InitUtils(); +void ShutdownUtils(); - void SetPointCopySampler(); - void SetLinearCopySampler(); +void SetPointCopySampler(); +void SetLinearCopySampler(); - void drawShadedTexQuad(ID3D11ShaderResourceView* texture, - const D3D11_RECT* rSource, - int SourceWidth, - int SourceHeight, - ID3D11PixelShader* PShader, - ID3D11VertexShader* VShader, - ID3D11InputLayout* layout, - ID3D11GeometryShader* GShader = nullptr, - float Gamma = 1.0f, - u32 slice = 0); - void drawClearQuad(u32 Color, float z); - void drawColorQuad(u32 Color, float z, float x1, float y1, float x2, float y2); +void drawShadedTexQuad(ID3D11ShaderResourceView* texture, const D3D11_RECT* rSource, + int SourceWidth, int SourceHeight, ID3D11PixelShader* PShader, + ID3D11VertexShader* VShader, ID3D11InputLayout* layout, + ID3D11GeometryShader* GShader = nullptr, float Gamma = 1.0f, u32 slice = 0); +void drawClearQuad(u32 Color, float z); +void drawColorQuad(u32 Color, float z, float x1, float y1, float x2, float y2); - void DrawEFBPokeQuads(EFBAccessType type, const EfbPokeData* points, size_t num_points); +void DrawEFBPokeQuads(EFBAccessType type, const EfbPokeData* points, size_t num_points); } - } diff --git a/Source/Core/VideoBackends/D3D/FramebufferManager.cpp b/Source/Core/VideoBackends/D3D/FramebufferManager.cpp index 8ed0e88765..bb761b8a5b 100644 --- a/Source/Core/VideoBackends/D3D/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/D3D/FramebufferManager.cpp @@ -18,235 +18,312 @@ namespace DX11 { - static XFBEncoder s_xfbEncoder; FramebufferManager::Efb FramebufferManager::m_efb; unsigned int FramebufferManager::m_target_width; unsigned int FramebufferManager::m_target_height; -D3DTexture2D* &FramebufferManager::GetEFBColorTexture() { return m_efb.color_tex; } -D3DTexture2D* &FramebufferManager::GetEFBColorReadTexture() { return m_efb.color_read_texture; } -ID3D11Texture2D* &FramebufferManager::GetEFBColorStagingBuffer() { return m_efb.color_staging_buf; } - -D3DTexture2D* &FramebufferManager::GetEFBDepthTexture() { return m_efb.depth_tex; } -D3DTexture2D* &FramebufferManager::GetEFBDepthReadTexture() { return m_efb.depth_read_texture; } -ID3D11Texture2D* &FramebufferManager::GetEFBDepthStagingBuffer() { return m_efb.depth_staging_buf; } - -D3DTexture2D* &FramebufferManager::GetResolvedEFBColorTexture() +D3DTexture2D*& FramebufferManager::GetEFBColorTexture() { - if (g_ActiveConfig.iMultisamples > 1) - { - for (int i = 0; i < m_efb.slices; i++) - D3D::context->ResolveSubresource(m_efb.resolved_color_tex->GetTex(), D3D11CalcSubresource(0, i, 1), m_efb.color_tex->GetTex(), D3D11CalcSubresource(0, i, 1), DXGI_FORMAT_R8G8B8A8_UNORM); - return m_efb.resolved_color_tex; - } - else - { - return m_efb.color_tex; - } + return m_efb.color_tex; +} +D3DTexture2D*& FramebufferManager::GetEFBColorReadTexture() +{ + return m_efb.color_read_texture; +} +ID3D11Texture2D*& FramebufferManager::GetEFBColorStagingBuffer() +{ + return m_efb.color_staging_buf; } -D3DTexture2D* &FramebufferManager::GetResolvedEFBDepthTexture() +D3DTexture2D*& FramebufferManager::GetEFBDepthTexture() { - if (g_ActiveConfig.iMultisamples > 1) - { - // ResolveSubresource does not work with depth textures. - // Instead, we use a shader that selects the minimum depth from all samples. - g_renderer->ResetAPIState(); + return m_efb.depth_tex; +} +D3DTexture2D*& FramebufferManager::GetEFBDepthReadTexture() +{ + return m_efb.depth_read_texture; +} +ID3D11Texture2D*& FramebufferManager::GetEFBDepthStagingBuffer() +{ + return m_efb.depth_staging_buf; +} - CD3D11_VIEWPORT viewport(0.f, 0.f, (float)m_target_width, (float)m_target_height); - D3D::context->RSSetViewports(1, &viewport); - D3D::context->OMSetRenderTargets(1, &m_efb.resolved_depth_tex->GetRTV(), nullptr); +D3DTexture2D*& FramebufferManager::GetResolvedEFBColorTexture() +{ + if (g_ActiveConfig.iMultisamples > 1) + { + for (int i = 0; i < m_efb.slices; i++) + D3D::context->ResolveSubresource(m_efb.resolved_color_tex->GetTex(), + D3D11CalcSubresource(0, i, 1), m_efb.color_tex->GetTex(), + D3D11CalcSubresource(0, i, 1), DXGI_FORMAT_R8G8B8A8_UNORM); + return m_efb.resolved_color_tex; + } + else + { + return m_efb.color_tex; + } +} - const D3D11_RECT source_rect = CD3D11_RECT(0, 0, m_target_width, m_target_height); - D3D::drawShadedTexQuad(m_efb.depth_tex->GetSRV(), &source_rect, m_target_width, m_target_height, - PixelShaderCache::GetDepthResolveProgram(), VertexShaderCache::GetSimpleVertexShader(), - VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader()); +D3DTexture2D*& FramebufferManager::GetResolvedEFBDepthTexture() +{ + if (g_ActiveConfig.iMultisamples > 1) + { + // ResolveSubresource does not work with depth textures. + // Instead, we use a shader that selects the minimum depth from all samples. + g_renderer->ResetAPIState(); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); - g_renderer->RestoreAPIState(); + CD3D11_VIEWPORT viewport(0.f, 0.f, (float)m_target_width, (float)m_target_height); + D3D::context->RSSetViewports(1, &viewport); + D3D::context->OMSetRenderTargets(1, &m_efb.resolved_depth_tex->GetRTV(), nullptr); - return m_efb.resolved_depth_tex; - } - else - { - return m_efb.depth_tex; - } + const D3D11_RECT source_rect = CD3D11_RECT(0, 0, m_target_width, m_target_height); + D3D::drawShadedTexQuad( + m_efb.depth_tex->GetSRV(), &source_rect, m_target_width, m_target_height, + PixelShaderCache::GetDepthResolveProgram(), VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader()); + + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); + g_renderer->RestoreAPIState(); + + return m_efb.resolved_depth_tex; + } + else + { + return m_efb.depth_tex; + } } FramebufferManager::FramebufferManager() { - m_target_width = Renderer::GetTargetWidth(); - m_target_height = Renderer::GetTargetHeight(); - if (m_target_height < 1) - { - m_target_height = 1; - } - if (m_target_width < 1) - { - m_target_width = 1; - } - DXGI_SAMPLE_DESC sample_desc; - sample_desc.Count = g_ActiveConfig.iMultisamples; - sample_desc.Quality = 0; + m_target_width = Renderer::GetTargetWidth(); + m_target_height = Renderer::GetTargetHeight(); + if (m_target_height < 1) + { + m_target_height = 1; + } + if (m_target_width < 1) + { + m_target_width = 1; + } + DXGI_SAMPLE_DESC sample_desc; + sample_desc.Count = g_ActiveConfig.iMultisamples; + sample_desc.Quality = 0; - ID3D11Texture2D* buf; - D3D11_TEXTURE2D_DESC texdesc; - HRESULT hr; + ID3D11Texture2D* buf; + D3D11_TEXTURE2D_DESC texdesc; + HRESULT hr; - m_EFBLayers = m_efb.slices = (g_ActiveConfig.iStereoMode > 0) ? 2 : 1; + m_EFBLayers = m_efb.slices = (g_ActiveConfig.iStereoMode > 0) ? 2 : 1; - // EFB color texture - primary render target - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality); - hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); - CHECK(hr==S_OK, "create EFB color texture (size: %dx%d; hr=%#x)", m_target_width, m_target_height, hr); - m_efb.color_tex = new D3DTexture2D(buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET), DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, (sample_desc.Count > 1)); - SAFE_RELEASE(buf); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetTex(), "EFB color texture"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetSRV(), "EFB color texture shader resource view"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetRTV(), "EFB color texture render target view"); + // EFB color texture - primary render target + texdesc = + CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, + m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, + D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality); + hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); + CHECK(hr == S_OK, "create EFB color texture (size: %dx%d; hr=%#x)", m_target_width, + m_target_height, hr); + m_efb.color_tex = new D3DTexture2D( + buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET), + DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, + (sample_desc.Count > 1)); + SAFE_RELEASE(buf); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetTex(), "EFB color texture"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetSRV(), + "EFB color texture shader resource view"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetRTV(), + "EFB color texture render target view"); - // Temporary EFB color texture - used in ReinterpretPixelData - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality); - hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); - CHECK(hr==S_OK, "create EFB color temp texture (size: %dx%d; hr=%#x)", m_target_width, m_target_height, hr); - m_efb.color_temp_tex = new D3DTexture2D(buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET), DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, (sample_desc.Count > 1)); - SAFE_RELEASE(buf); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetTex(), "EFB color temp texture"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetSRV(), "EFB color temp texture shader resource view"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetRTV(), "EFB color temp texture render target view"); + // Temporary EFB color texture - used in ReinterpretPixelData + texdesc = + CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, + m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, + D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality); + hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); + CHECK(hr == S_OK, "create EFB color temp texture (size: %dx%d; hr=%#x)", m_target_width, + m_target_height, hr); + m_efb.color_temp_tex = new D3DTexture2D( + buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET), + DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, + (sample_desc.Count > 1)); + SAFE_RELEASE(buf); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetTex(), + "EFB color temp texture"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetSRV(), + "EFB color temp texture shader resource view"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetRTV(), + "EFB color temp texture render target view"); - // Render buffer for AccessEFB (color data) - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, D3D11_BIND_RENDER_TARGET); - hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); - CHECK(hr==S_OK, "create EFB color read texture (hr=%#x)", hr); - m_efb.color_read_texture = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET); - SAFE_RELEASE(buf); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetTex(), "EFB color read texture (used in Renderer::AccessEFB)"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetRTV(), "EFB color read texture render target view (used in Renderer::AccessEFB)"); + // Render buffer for AccessEFB (color data) + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, D3D11_BIND_RENDER_TARGET); + hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); + CHECK(hr == S_OK, "create EFB color read texture (hr=%#x)", hr); + m_efb.color_read_texture = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET); + SAFE_RELEASE(buf); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetTex(), + "EFB color read texture (used in Renderer::AccessEFB)"); + D3D::SetDebugObjectName( + (ID3D11DeviceChild*)m_efb.depth_read_texture->GetRTV(), + "EFB color read texture render target view (used in Renderer::AccessEFB)"); - // AccessEFB - Sysmem buffer used to retrieve the pixel data from depth_read_texture - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ); - hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &m_efb.color_staging_buf); - CHECK(hr==S_OK, "create EFB color staging buffer (hr=%#x)", hr); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_staging_buf, "EFB color staging texture (used for Renderer::AccessEFB)"); + // AccessEFB - Sysmem buffer used to retrieve the pixel data from depth_read_texture + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, 0, D3D11_USAGE_STAGING, + D3D11_CPU_ACCESS_READ); + hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &m_efb.color_staging_buf); + CHECK(hr == S_OK, "create EFB color staging buffer (hr=%#x)", hr); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_staging_buf, + "EFB color staging texture (used for Renderer::AccessEFB)"); - // EFB depth buffer - primary depth buffer - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_TYPELESS, m_target_width, m_target_height, m_efb.slices, 1, D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality); - hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); - CHECK(hr==S_OK, "create EFB depth texture (size: %dx%d; hr=%#x)", m_target_width, m_target_height, hr); - m_efb.depth_tex = new D3DTexture2D(buf, (D3D11_BIND_FLAG)(D3D11_BIND_DEPTH_STENCIL|D3D11_BIND_SHADER_RESOURCE), DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_D32_FLOAT, DXGI_FORMAT_UNKNOWN, (sample_desc.Count > 1)); - SAFE_RELEASE(buf); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetTex(), "EFB depth texture"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetDSV(), "EFB depth texture depth stencil view"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetSRV(), "EFB depth texture shader resource view"); + // EFB depth buffer - primary depth buffer + texdesc = + CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_TYPELESS, m_target_width, m_target_height, m_efb.slices, + 1, D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE, + D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality); + hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); + CHECK(hr == S_OK, "create EFB depth texture (size: %dx%d; hr=%#x)", m_target_width, + m_target_height, hr); + m_efb.depth_tex = new D3DTexture2D( + buf, (D3D11_BIND_FLAG)(D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE), + DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_D32_FLOAT, DXGI_FORMAT_UNKNOWN, (sample_desc.Count > 1)); + SAFE_RELEASE(buf); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetTex(), "EFB depth texture"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetDSV(), + "EFB depth texture depth stencil view"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetSRV(), + "EFB depth texture shader resource view"); - // Render buffer for AccessEFB (depth data) - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 1, 1, 1, 1, D3D11_BIND_RENDER_TARGET); - hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); - CHECK(hr==S_OK, "create EFB depth read texture (hr=%#x)", hr); - m_efb.depth_read_texture = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET); - SAFE_RELEASE(buf); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetTex(), "EFB depth read texture (used in Renderer::AccessEFB)"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetRTV(), "EFB depth read texture render target view (used in Renderer::AccessEFB)"); + // Render buffer for AccessEFB (depth data) + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 1, 1, 1, 1, D3D11_BIND_RENDER_TARGET); + hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); + CHECK(hr == S_OK, "create EFB depth read texture (hr=%#x)", hr); + m_efb.depth_read_texture = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET); + SAFE_RELEASE(buf); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetTex(), + "EFB depth read texture (used in Renderer::AccessEFB)"); + D3D::SetDebugObjectName( + (ID3D11DeviceChild*)m_efb.depth_read_texture->GetRTV(), + "EFB depth read texture render target view (used in Renderer::AccessEFB)"); - // AccessEFB - Sysmem buffer used to retrieve the pixel data from depth_read_texture - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 1, 1, 1, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ); - hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &m_efb.depth_staging_buf); - CHECK(hr==S_OK, "create EFB depth staging buffer (hr=%#x)", hr); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_staging_buf, "EFB depth staging texture (used for Renderer::AccessEFB)"); + // AccessEFB - Sysmem buffer used to retrieve the pixel data from depth_read_texture + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 1, 1, 1, 1, 0, D3D11_USAGE_STAGING, + D3D11_CPU_ACCESS_READ); + hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &m_efb.depth_staging_buf); + CHECK(hr == S_OK, "create EFB depth staging buffer (hr=%#x)", hr); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_staging_buf, + "EFB depth staging texture (used for Renderer::AccessEFB)"); - if (g_ActiveConfig.iMultisamples > 1) - { - // Framebuffer resolve textures (color+depth) - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DEFAULT, 0, 1); - hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); - CHECK(hr==S_OK, "create EFB color resolve texture (size: %dx%d; hr=%#x)", m_target_width, m_target_height, hr); - m_efb.resolved_color_tex = new D3DTexture2D(buf, D3D11_BIND_SHADER_RESOURCE, DXGI_FORMAT_R8G8B8A8_UNORM); - SAFE_RELEASE(buf); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_color_tex->GetTex(), "EFB color resolve texture"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_color_tex->GetSRV(), "EFB color resolve texture shader resource view"); + if (g_ActiveConfig.iMultisamples > 1) + { + // Framebuffer resolve textures (color+depth) + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, + m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE, + D3D11_USAGE_DEFAULT, 0, 1); + hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); + CHECK(hr == S_OK, "create EFB color resolve texture (size: %dx%d; hr=%#x)", m_target_width, + m_target_height, hr); + m_efb.resolved_color_tex = + new D3DTexture2D(buf, D3D11_BIND_SHADER_RESOURCE, DXGI_FORMAT_R8G8B8A8_UNORM); + SAFE_RELEASE(buf); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_color_tex->GetTex(), + "EFB color resolve texture"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_color_tex->GetSRV(), + "EFB color resolve texture shader resource view"); - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, m_target_width, m_target_height, m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); - hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); - CHECK(hr==S_OK, "create EFB depth resolve texture (size: %dx%d; hr=%#x)", m_target_width, m_target_height, hr); - m_efb.resolved_depth_tex = new D3DTexture2D(buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET), DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32_FLOAT); - SAFE_RELEASE(buf); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_depth_tex->GetTex(), "EFB depth resolve texture"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_depth_tex->GetSRV(), "EFB depth resolve texture shader resource view"); - } - else - { - m_efb.resolved_color_tex = nullptr; - m_efb.resolved_depth_tex = nullptr; - } + texdesc = + CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, m_target_width, m_target_height, m_efb.slices, + 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); + hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); + CHECK(hr == S_OK, "create EFB depth resolve texture (size: %dx%d; hr=%#x)", m_target_width, + m_target_height, hr); + m_efb.resolved_depth_tex = new D3DTexture2D( + buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET), + DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32_FLOAT); + SAFE_RELEASE(buf); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_depth_tex->GetTex(), + "EFB depth resolve texture"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_depth_tex->GetSRV(), + "EFB depth resolve texture shader resource view"); + } + else + { + m_efb.resolved_color_tex = nullptr; + m_efb.resolved_depth_tex = nullptr; + } - s_xfbEncoder.Init(); + s_xfbEncoder.Init(); } FramebufferManager::~FramebufferManager() { - s_xfbEncoder.Shutdown(); + s_xfbEncoder.Shutdown(); - SAFE_RELEASE(m_efb.color_tex); - SAFE_RELEASE(m_efb.color_temp_tex); - SAFE_RELEASE(m_efb.color_staging_buf); - SAFE_RELEASE(m_efb.color_read_texture); - SAFE_RELEASE(m_efb.resolved_color_tex); - SAFE_RELEASE(m_efb.depth_tex); - SAFE_RELEASE(m_efb.depth_staging_buf); - SAFE_RELEASE(m_efb.depth_read_texture); - SAFE_RELEASE(m_efb.resolved_depth_tex); + SAFE_RELEASE(m_efb.color_tex); + SAFE_RELEASE(m_efb.color_temp_tex); + SAFE_RELEASE(m_efb.color_staging_buf); + SAFE_RELEASE(m_efb.color_read_texture); + SAFE_RELEASE(m_efb.resolved_color_tex); + SAFE_RELEASE(m_efb.depth_tex); + SAFE_RELEASE(m_efb.depth_staging_buf); + SAFE_RELEASE(m_efb.depth_read_texture); + SAFE_RELEASE(m_efb.resolved_depth_tex); } -void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma) +void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, + const EFBRectangle& sourceRc, float Gamma) { - u8* dst = Memory::GetPointer(xfbAddr); - // below div2 due to dx using pixel width - s_xfbEncoder.Encode(dst, fbStride/2, fbHeight, sourceRc, Gamma); + u8* dst = Memory::GetPointer(xfbAddr); + // below div2 due to dx using pixel width + s_xfbEncoder.Encode(dst, fbStride / 2, fbHeight, sourceRc, Gamma); } -std::unique_ptr FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) +std::unique_ptr FramebufferManager::CreateXFBSource(unsigned int target_width, + unsigned int target_height, + unsigned int layers) { - return std::make_unique(D3DTexture2D::Create(target_width, target_height, - (D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE), - D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, layers), layers); + return std::make_unique( + D3DTexture2D::Create(target_width, target_height, + (D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE), + D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, layers), + layers); } -void FramebufferManager::GetTargetSize(unsigned int *width, unsigned int *height) +void FramebufferManager::GetTargetSize(unsigned int* width, unsigned int* height) { - *width = m_target_width; - *height = m_target_height; + *width = m_target_width; + *height = m_target_height; } void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) { - // DX11's XFB decoder does not use this function. - // YUYV data is decoded in Render::Swap. + // DX11's XFB decoder does not use this function. + // YUYV data is decoded in Render::Swap. } void XFBSource::CopyEFB(float Gamma) { - g_renderer->ResetAPIState(); // reset any game specific settings + g_renderer->ResetAPIState(); // reset any game specific settings - // Copy EFB data to XFB and restore render target again - const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)texWidth, (float)texHeight); - const D3D11_RECT rect = CD3D11_RECT(0, 0, texWidth, texHeight); + // Copy EFB data to XFB and restore render target again + const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)texWidth, (float)texHeight); + const D3D11_RECT rect = CD3D11_RECT(0, 0, texWidth, texHeight); - D3D::context->RSSetViewports(1, &vp); - D3D::context->OMSetRenderTargets(1, &tex->GetRTV(), nullptr); - D3D::SetPointCopySampler(); + D3D::context->RSSetViewports(1, &vp); + D3D::context->OMSetRenderTargets(1, &tex->GetRTV(), nullptr); + D3D::SetPointCopySampler(); - D3D::drawShadedTexQuad(FramebufferManager::GetEFBColorTexture()->GetSRV(), &rect, - Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), PixelShaderCache::GetColorCopyProgram(true), - VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), - GeometryShaderCache::GetCopyGeometryShader(), Gamma); + D3D::drawShadedTexQuad( + FramebufferManager::GetEFBColorTexture()->GetSRV(), &rect, Renderer::GetTargetWidth(), + Renderer::GetTargetHeight(), PixelShaderCache::GetColorCopyProgram(true), + VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), + GeometryShaderCache::GetCopyGeometryShader(), Gamma); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); - g_renderer->RestoreAPIState(); + g_renderer->RestoreAPIState(); } } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/FramebufferManager.h b/Source/Core/VideoBackends/D3D/FramebufferManager.h index 0a8c226ad8..9411debdca 100644 --- a/Source/Core/VideoBackends/D3D/FramebufferManager.h +++ b/Source/Core/VideoBackends/D3D/FramebufferManager.h @@ -46,67 +46,69 @@ namespace DX11 struct XFBSource : public XFBSourceBase { - XFBSource(D3DTexture2D *_tex, int slices) : tex(_tex), m_slices(slices) {} - ~XFBSource() { tex->Release(); } + XFBSource(D3DTexture2D* _tex, int slices) : tex(_tex), m_slices(slices) {} + ~XFBSource() { tex->Release(); } + void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override; + void CopyEFB(float Gamma) override; - void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override; - void CopyEFB(float Gamma) override; - - D3DTexture2D* const tex; - const int m_slices; + D3DTexture2D* const tex; + const int m_slices; }; class FramebufferManager : public FramebufferManagerBase { public: - FramebufferManager(); - ~FramebufferManager(); + FramebufferManager(); + ~FramebufferManager(); - static D3DTexture2D* &GetEFBColorTexture(); - static D3DTexture2D* &GetEFBColorReadTexture(); - static ID3D11Texture2D* &GetEFBColorStagingBuffer(); + static D3DTexture2D*& GetEFBColorTexture(); + static D3DTexture2D*& GetEFBColorReadTexture(); + static ID3D11Texture2D*& GetEFBColorStagingBuffer(); - static D3DTexture2D* &GetEFBDepthTexture(); - static D3DTexture2D* &GetEFBDepthReadTexture(); - static ID3D11Texture2D* &GetEFBDepthStagingBuffer(); + static D3DTexture2D*& GetEFBDepthTexture(); + static D3DTexture2D*& GetEFBDepthReadTexture(); + static ID3D11Texture2D*& GetEFBDepthStagingBuffer(); - static D3DTexture2D* &GetResolvedEFBColorTexture(); - static D3DTexture2D* &GetResolvedEFBDepthTexture(); + static D3DTexture2D*& GetResolvedEFBColorTexture(); + static D3DTexture2D*& GetResolvedEFBDepthTexture(); - static D3DTexture2D* &GetEFBColorTempTexture() { return m_efb.color_temp_tex; } - static void SwapReinterpretTexture() - { - D3DTexture2D* swaptex = GetEFBColorTempTexture(); - m_efb.color_temp_tex = GetEFBColorTexture(); - m_efb.color_tex = swaptex; - } + static D3DTexture2D*& GetEFBColorTempTexture() { return m_efb.color_temp_tex; } + static void SwapReinterpretTexture() + { + D3DTexture2D* swaptex = GetEFBColorTempTexture(); + m_efb.color_temp_tex = GetEFBColorTexture(); + m_efb.color_tex = swaptex; + } private: - std::unique_ptr CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) override; - void GetTargetSize(unsigned int *width, unsigned int *height) override; + std::unique_ptr CreateXFBSource(unsigned int target_width, + unsigned int target_height, + unsigned int layers) override; + void GetTargetSize(unsigned int* width, unsigned int* height) override; - void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma) override; + void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, + float Gamma) override; - static struct Efb - { - D3DTexture2D* color_tex; - ID3D11Texture2D* color_staging_buf; - D3DTexture2D* color_read_texture; + static struct Efb + { + D3DTexture2D* color_tex; + ID3D11Texture2D* color_staging_buf; + D3DTexture2D* color_read_texture; - D3DTexture2D* depth_tex; - ID3D11Texture2D* depth_staging_buf; - D3DTexture2D* depth_read_texture; + D3DTexture2D* depth_tex; + ID3D11Texture2D* depth_staging_buf; + D3DTexture2D* depth_read_texture; - D3DTexture2D* color_temp_tex; + D3DTexture2D* color_temp_tex; - D3DTexture2D* resolved_color_tex; - D3DTexture2D* resolved_depth_tex; + D3DTexture2D* resolved_color_tex; + D3DTexture2D* resolved_depth_tex; - int slices; - } m_efb; + int slices; + } m_efb; - static unsigned int m_target_width; - static unsigned int m_target_height; + static unsigned int m_target_width; + static unsigned int m_target_height; }; } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp index 65b8053810..f899f7f078 100644 --- a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp @@ -23,11 +23,10 @@ namespace DX11 { - GeometryShaderCache::GSCache GeometryShaderCache::GeometryShaders; const GeometryShaderCache::GSCacheEntry* GeometryShaderCache::last_entry; GeometryShaderUid GeometryShaderCache::last_uid; -UidChecker GeometryShaderCache::geometry_uid_checker; +UidChecker GeometryShaderCache::geometry_uid_checker; const GeometryShaderCache::GSCacheEntry GeometryShaderCache::pass_entry; ID3D11GeometryShader* ClearGeometryShader = nullptr; @@ -35,241 +34,250 @@ ID3D11GeometryShader* CopyGeometryShader = nullptr; LinearDiskCache g_gs_disk_cache; -ID3D11GeometryShader* GeometryShaderCache::GetClearGeometryShader() { return (g_ActiveConfig.iStereoMode > 0) ? ClearGeometryShader: nullptr; } -ID3D11GeometryShader* GeometryShaderCache::GetCopyGeometryShader() { return (g_ActiveConfig.iStereoMode > 0) ? CopyGeometryShader : nullptr; } +ID3D11GeometryShader* GeometryShaderCache::GetClearGeometryShader() +{ + return (g_ActiveConfig.iStereoMode > 0) ? ClearGeometryShader : nullptr; +} +ID3D11GeometryShader* GeometryShaderCache::GetCopyGeometryShader() +{ + return (g_ActiveConfig.iStereoMode > 0) ? CopyGeometryShader : nullptr; +} ID3D11Buffer* gscbuf = nullptr; -ID3D11Buffer* &GeometryShaderCache::GetConstantBuffer() +ID3D11Buffer*& GeometryShaderCache::GetConstantBuffer() { - // TODO: divide the global variables of the generated shaders into about 5 constant buffers to speed this up - if (GeometryShaderManager::dirty) - { - D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(gscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, &GeometryShaderManager::constants, sizeof(GeometryShaderConstants)); - D3D::context->Unmap(gscbuf, 0); - GeometryShaderManager::dirty = false; + // TODO: divide the global variables of the generated shaders into about 5 constant buffers to + // speed this up + if (GeometryShaderManager::dirty) + { + D3D11_MAPPED_SUBRESOURCE map; + D3D::context->Map(gscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, &GeometryShaderManager::constants, sizeof(GeometryShaderConstants)); + D3D::context->Unmap(gscbuf, 0); + GeometryShaderManager::dirty = false; - ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(GeometryShaderConstants)); - } - return gscbuf; + ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(GeometryShaderConstants)); + } + return gscbuf; } // this class will load the precompiled shaders into our cache class GeometryShaderCacheInserter : public LinearDiskCacheReader { public: - void Read(const GeometryShaderUid &key, const u8* value, u32 value_size) - { - GeometryShaderCache::InsertByteCode(key, value, value_size); - } + void Read(const GeometryShaderUid& key, const u8* value, u32 value_size) + { + GeometryShaderCache::InsertByteCode(key, value, value_size); + } }; const char clear_shader_code[] = { - "struct VSOUTPUT\n" - "{\n" - " float4 vPosition : POSITION;\n" - " float4 vColor0 : COLOR0;\n" - "};\n" - "struct GSOUTPUT\n" - "{\n" - " float4 vPosition : POSITION;\n" - " float4 vColor0 : COLOR0;\n" - " uint slice : SV_RenderTargetArrayIndex;\n" - "};\n" - "[maxvertexcount(6)]\n" - "void main(triangle VSOUTPUT o[3], inout TriangleStream Output)\n" - "{\n" - "for(int slice = 0; slice < 2; slice++)\n" - "{\n" - " for(int i = 0; i < 3; i++)\n" - " {\n" - " GSOUTPUT OUT;\n" - " OUT.vPosition = o[i].vPosition;\n" - " OUT.vColor0 = o[i].vColor0;\n" - " OUT.slice = slice;\n" - " Output.Append(OUT);\n" - " }\n" - " Output.RestartStrip();\n" - "}\n" - "}\n" -}; + "struct VSOUTPUT\n" + "{\n" + " float4 vPosition : POSITION;\n" + " float4 vColor0 : COLOR0;\n" + "};\n" + "struct GSOUTPUT\n" + "{\n" + " float4 vPosition : POSITION;\n" + " float4 vColor0 : COLOR0;\n" + " uint slice : SV_RenderTargetArrayIndex;\n" + "};\n" + "[maxvertexcount(6)]\n" + "void main(triangle VSOUTPUT o[3], inout TriangleStream Output)\n" + "{\n" + "for(int slice = 0; slice < 2; slice++)\n" + "{\n" + " for(int i = 0; i < 3; i++)\n" + " {\n" + " GSOUTPUT OUT;\n" + " OUT.vPosition = o[i].vPosition;\n" + " OUT.vColor0 = o[i].vColor0;\n" + " OUT.slice = slice;\n" + " Output.Append(OUT);\n" + " }\n" + " Output.RestartStrip();\n" + "}\n" + "}\n"}; const char copy_shader_code[] = { - "struct VSOUTPUT\n" - "{\n" - " float4 vPosition : POSITION;\n" - " float3 vTexCoord : TEXCOORD0;\n" - " float vTexCoord1 : TEXCOORD1;\n" - "};\n" - "struct GSOUTPUT\n" - "{\n" - " float4 vPosition : POSITION;\n" - " float3 vTexCoord : TEXCOORD0;\n" - " float vTexCoord1 : TEXCOORD1;\n" - " uint slice : SV_RenderTargetArrayIndex;\n" - "};\n" - "[maxvertexcount(6)]\n" - "void main(triangle VSOUTPUT o[3], inout TriangleStream Output)\n" - "{\n" - "for(int slice = 0; slice < 2; slice++)\n" - "{\n" - " for(int i = 0; i < 3; i++)\n" - " {\n" - " GSOUTPUT OUT;\n" - " OUT.vPosition = o[i].vPosition;\n" - " OUT.vTexCoord = o[i].vTexCoord;\n" - " OUT.vTexCoord.z = slice;\n" - " OUT.vTexCoord1 = o[i].vTexCoord1;\n" - " OUT.slice = slice;\n" - " Output.Append(OUT);\n" - " }\n" - " Output.RestartStrip();\n" - "}\n" - "}\n" -}; + "struct VSOUTPUT\n" + "{\n" + " float4 vPosition : POSITION;\n" + " float3 vTexCoord : TEXCOORD0;\n" + " float vTexCoord1 : TEXCOORD1;\n" + "};\n" + "struct GSOUTPUT\n" + "{\n" + " float4 vPosition : POSITION;\n" + " float3 vTexCoord : TEXCOORD0;\n" + " float vTexCoord1 : TEXCOORD1;\n" + " uint slice : SV_RenderTargetArrayIndex;\n" + "};\n" + "[maxvertexcount(6)]\n" + "void main(triangle VSOUTPUT o[3], inout TriangleStream Output)\n" + "{\n" + "for(int slice = 0; slice < 2; slice++)\n" + "{\n" + " for(int i = 0; i < 3; i++)\n" + " {\n" + " GSOUTPUT OUT;\n" + " OUT.vPosition = o[i].vPosition;\n" + " OUT.vTexCoord = o[i].vTexCoord;\n" + " OUT.vTexCoord.z = slice;\n" + " OUT.vTexCoord1 = o[i].vTexCoord1;\n" + " OUT.slice = slice;\n" + " Output.Append(OUT);\n" + " }\n" + " Output.RestartStrip();\n" + "}\n" + "}\n"}; void GeometryShaderCache::Init() { - unsigned int gbsize = ROUND_UP(sizeof(GeometryShaderConstants), 16); // must be a multiple of 16 - D3D11_BUFFER_DESC gbdesc = CD3D11_BUFFER_DESC(gbsize, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - HRESULT hr = D3D::device->CreateBuffer(&gbdesc, nullptr, &gscbuf); - CHECK(hr == S_OK, "Create geometry shader constant buffer (size=%u)", gbsize); - D3D::SetDebugObjectName((ID3D11DeviceChild*)gscbuf, "geometry shader constant buffer used to emulate the GX pipeline"); + unsigned int gbsize = ROUND_UP(sizeof(GeometryShaderConstants), 16); // must be a multiple of 16 + D3D11_BUFFER_DESC gbdesc = CD3D11_BUFFER_DESC(gbsize, D3D11_BIND_CONSTANT_BUFFER, + D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + HRESULT hr = D3D::device->CreateBuffer(&gbdesc, nullptr, &gscbuf); + CHECK(hr == S_OK, "Create geometry shader constant buffer (size=%u)", gbsize); + D3D::SetDebugObjectName((ID3D11DeviceChild*)gscbuf, + "geometry shader constant buffer used to emulate the GX pipeline"); - // used when drawing clear quads - ClearGeometryShader = D3D::CompileAndCreateGeometryShader(clear_shader_code); - CHECK(ClearGeometryShader != nullptr, "Create clear geometry shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearGeometryShader, "clear geometry shader"); + // used when drawing clear quads + ClearGeometryShader = D3D::CompileAndCreateGeometryShader(clear_shader_code); + CHECK(ClearGeometryShader != nullptr, "Create clear geometry shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearGeometryShader, "clear geometry shader"); - // used for buffer copy - CopyGeometryShader = D3D::CompileAndCreateGeometryShader(copy_shader_code); - CHECK(CopyGeometryShader != nullptr, "Create copy geometry shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)CopyGeometryShader, "copy geometry shader"); + // used for buffer copy + CopyGeometryShader = D3D::CompileAndCreateGeometryShader(copy_shader_code); + CHECK(CopyGeometryShader != nullptr, "Create copy geometry shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)CopyGeometryShader, "copy geometry shader"); - Clear(); + Clear(); - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - std::string cache_filename = StringFromFormat("%sdx11-%s-gs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), - SConfig::GetInstance().m_strUniqueID.c_str()); - GeometryShaderCacheInserter inserter; - g_gs_disk_cache.OpenAndRead(cache_filename, inserter); + std::string cache_filename = + StringFromFormat("%sdx11-%s-gs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), + SConfig::GetInstance().m_strUniqueID.c_str()); + GeometryShaderCacheInserter inserter; + g_gs_disk_cache.OpenAndRead(cache_filename, inserter); - if (g_Config.bEnableShaderDebugging) - Clear(); + if (g_Config.bEnableShaderDebugging) + Clear(); - last_entry = nullptr; + last_entry = nullptr; } // ONLY to be used during shutdown. void GeometryShaderCache::Clear() { - for (auto& iter : GeometryShaders) - iter.second.Destroy(); - GeometryShaders.clear(); - geometry_uid_checker.Invalidate(); + for (auto& iter : GeometryShaders) + iter.second.Destroy(); + GeometryShaders.clear(); + geometry_uid_checker.Invalidate(); - last_entry = nullptr; + last_entry = nullptr; } void GeometryShaderCache::Shutdown() { - SAFE_RELEASE(gscbuf); + SAFE_RELEASE(gscbuf); - SAFE_RELEASE(ClearGeometryShader); - SAFE_RELEASE(CopyGeometryShader); + SAFE_RELEASE(ClearGeometryShader); + SAFE_RELEASE(CopyGeometryShader); - Clear(); - g_gs_disk_cache.Sync(); - g_gs_disk_cache.Close(); + Clear(); + g_gs_disk_cache.Sync(); + g_gs_disk_cache.Close(); } bool GeometryShaderCache::SetShader(u32 primitive_type) { - GeometryShaderUid uid = GetGeometryShaderUid(primitive_type, API_D3D); - if (g_ActiveConfig.bEnableShaderDebugging) - { - ShaderCode code = GenerateGeometryShaderCode(primitive_type, API_D3D); - geometry_uid_checker.AddToIndexAndCheck(code, uid, "Geometry", "g"); - } + GeometryShaderUid uid = GetGeometryShaderUid(primitive_type, API_D3D); + if (g_ActiveConfig.bEnableShaderDebugging) + { + ShaderCode code = GenerateGeometryShaderCode(primitive_type, API_D3D); + geometry_uid_checker.AddToIndexAndCheck(code, uid, "Geometry", "g"); + } - // Check if the shader is already set - if (last_entry) - { - if (uid == last_uid) - { - GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); - return true; - } - } + // Check if the shader is already set + if (last_entry) + { + if (uid == last_uid) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + return true; + } + } - last_uid = uid; + last_uid = uid; - // Check if the shader is a pass-through shader - if (uid.GetUidData()->IsPassthrough()) - { - // Return the default pass-through shader - last_entry = &pass_entry; - return true; - } + // Check if the shader is a pass-through shader + if (uid.GetUidData()->IsPassthrough()) + { + // Return the default pass-through shader + last_entry = &pass_entry; + return true; + } - // Check if the shader is already in the cache - GSCache::iterator iter; - iter = GeometryShaders.find(uid); - if (iter != GeometryShaders.end()) - { - const GSCacheEntry &entry = iter->second; - last_entry = &entry; + // Check if the shader is already in the cache + GSCache::iterator iter; + iter = GeometryShaders.find(uid); + if (iter != GeometryShaders.end()) + { + const GSCacheEntry& entry = iter->second; + last_entry = &entry; - return (entry.shader != nullptr); - } + return (entry.shader != nullptr); + } - // Need to compile a new shader - ShaderCode code = GenerateGeometryShaderCode(primitive_type, API_D3D); + // Need to compile a new shader + ShaderCode code = GenerateGeometryShaderCode(primitive_type, API_D3D); - D3DBlob* pbytecode; - if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode)) - { - GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); - return false; - } + D3DBlob* pbytecode; + if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode)) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); + return false; + } - // Insert the bytecode into the caches - g_gs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); + // Insert the bytecode into the caches + g_gs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); - bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); - pbytecode->Release(); + bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); + pbytecode->Release(); - if (g_ActiveConfig.bEnableShaderDebugging && success) - { - GeometryShaders[uid].code = code.GetBuffer(); - } + if (g_ActiveConfig.bEnableShaderDebugging && success) + { + GeometryShaders[uid].code = code.GetBuffer(); + } - return success; + return success; } -bool GeometryShaderCache::InsertByteCode(const GeometryShaderUid &uid, const void* bytecode, unsigned int bytecodelen) +bool GeometryShaderCache::InsertByteCode(const GeometryShaderUid& uid, const void* bytecode, + unsigned int bytecodelen) { - ID3D11GeometryShader* shader = D3D::CreateGeometryShaderFromByteCode(bytecode, bytecodelen); - if (shader == nullptr) - return false; + ID3D11GeometryShader* shader = D3D::CreateGeometryShaderFromByteCode(bytecode, bytecodelen); + if (shader == nullptr) + return false; - // TODO: Somehow make the debug name a bit more specific - D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of GeometryShaderCache"); + // TODO: Somehow make the debug name a bit more specific + D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of GeometryShaderCache"); - // Make an entry in the table - GSCacheEntry newentry; - newentry.shader = shader; - GeometryShaders[uid] = newentry; - last_entry = &GeometryShaders[uid]; + // Make an entry in the table + GSCacheEntry newentry; + newentry.shader = shader; + GeometryShaders[uid] = newentry; + last_entry = &GeometryShaders[uid]; - if (!shader) - return false; + if (!shader) + return false; - return true; + return true; } } // DX11 diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.h b/Source/Core/VideoBackends/D3D/GeometryShaderCache.h index 93e5dfa8b1..b3c17cd37f 100644 --- a/Source/Core/VideoBackends/D3D/GeometryShaderCache.h +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.h @@ -11,41 +11,41 @@ namespace DX11 { - class GeometryShaderCache { public: - static void Init(); - static void Clear(); - static void Shutdown(); - static bool SetShader(u32 primitive_type); // TODO: Should be renamed to LoadShader - static bool InsertByteCode(const GeometryShaderUid &uid, const void* bytecode, unsigned int bytecodelen); + static void Init(); + static void Clear(); + static void Shutdown(); + static bool SetShader(u32 primitive_type); // TODO: Should be renamed to LoadShader + static bool InsertByteCode(const GeometryShaderUid& uid, const void* bytecode, + unsigned int bytecodelen); - static ID3D11GeometryShader* GeometryShaderCache::GetClearGeometryShader(); - static ID3D11GeometryShader* GeometryShaderCache::GetCopyGeometryShader(); + static ID3D11GeometryShader* GeometryShaderCache::GetClearGeometryShader(); + static ID3D11GeometryShader* GeometryShaderCache::GetCopyGeometryShader(); - static ID3D11GeometryShader* GetActiveShader() { return last_entry->shader; } - static ID3D11Buffer* &GetConstantBuffer(); + static ID3D11GeometryShader* GetActiveShader() { return last_entry->shader; } + static ID3D11Buffer*& GetConstantBuffer(); private: - struct GSCacheEntry - { - ID3D11GeometryShader* shader; + struct GSCacheEntry + { + ID3D11GeometryShader* shader; - std::string code; + std::string code; - GSCacheEntry() : shader(nullptr) {} - void Destroy() { SAFE_RELEASE(shader); } - }; + GSCacheEntry() : shader(nullptr) {} + void Destroy() { SAFE_RELEASE(shader); } + }; - typedef std::map GSCache; + typedef std::map GSCache; - static GSCache GeometryShaders; - static const GSCacheEntry* last_entry; - static GeometryShaderUid last_uid; - static const GSCacheEntry pass_entry; + static GSCache GeometryShaders; + static const GSCacheEntry* last_entry; + static GeometryShaderUid last_uid; + static const GSCacheEntry pass_entry; - static UidChecker geometry_uid_checker; + static UidChecker geometry_uid_checker; }; } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/NativeVertexFormat.cpp b/Source/Core/VideoBackends/D3D/NativeVertexFormat.cpp index 0e0b27c031..4aa52bd4bf 100644 --- a/Source/Core/VideoBackends/D3D/NativeVertexFormat.cpp +++ b/Source/Core/VideoBackends/D3D/NativeVertexFormat.cpp @@ -13,134 +13,139 @@ namespace DX11 { - class D3DVertexFormat : public NativeVertexFormat { public: - D3DVertexFormat(const PortableVertexDeclaration& vtx_decl); - ~D3DVertexFormat() { SAFE_RELEASE(m_layout); } - - void SetupVertexPointers() override; + D3DVertexFormat(const PortableVertexDeclaration& vtx_decl); + ~D3DVertexFormat() { SAFE_RELEASE(m_layout); } + void SetupVertexPointers() override; private: - std::array m_elems{}; - UINT m_num_elems = 0; + std::array m_elems{}; + UINT m_num_elems = 0; - ID3D11InputLayout* m_layout = nullptr; + ID3D11InputLayout* m_layout = nullptr; }; -NativeVertexFormat* VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) +NativeVertexFormat* +VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) { - return new D3DVertexFormat(vtx_decl); + return new D3DVertexFormat(vtx_decl); } -static const DXGI_FORMAT d3d_format_lookup[5*4*2] = -{ - // float formats - DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R32_FLOAT, - DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R32G32_FLOAT, - DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32_FLOAT, - DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R32G32B32A32_FLOAT, +static const DXGI_FORMAT d3d_format_lookup[5 * 4 * 2] = { + // float formats + DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_SNORM, + DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R16G16_UNORM, + DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32_FLOAT, + DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R32G32B32A32_FLOAT, - // integer formats - DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_UNKNOWN, + // integer formats + DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_SINT, + DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R16G16_UINT, + DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_UNKNOWN, }; DXGI_FORMAT VarToD3D(VarType t, int size, bool integer) { - DXGI_FORMAT retval = d3d_format_lookup[(int)t + 5*(size-1) + 5*4*(int)integer]; - if (retval == DXGI_FORMAT_UNKNOWN) - { - PanicAlert("VarToD3D: Invalid type/size combo %i , %i, %i", (int)t, size, (int)integer); - } - return retval; + DXGI_FORMAT retval = d3d_format_lookup[(int)t + 5 * (size - 1) + 5 * 4 * (int)integer]; + if (retval == DXGI_FORMAT_UNKNOWN) + { + PanicAlert("VarToD3D: Invalid type/size combo %i , %i, %i", (int)t, size, (int)integer); + } + return retval; } D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& _vtx_decl) { - this->vtx_decl = _vtx_decl; + this->vtx_decl = _vtx_decl; - const AttributeFormat* format = &_vtx_decl.position; + const AttributeFormat* format = &_vtx_decl.position; - if (format->enable) - { - m_elems[m_num_elems].SemanticName = "POSITION"; - m_elems[m_num_elems].AlignedByteOffset = format->offset; - m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer); - m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - ++m_num_elems; - } + if (format->enable) + { + m_elems[m_num_elems].SemanticName = "POSITION"; + m_elems[m_num_elems].AlignedByteOffset = format->offset; + m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer); + m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + ++m_num_elems; + } - for (int i = 0; i < 3; i++) - { - format = &_vtx_decl.normals[i]; - if (format->enable) - { - m_elems[m_num_elems].SemanticName = "NORMAL"; - m_elems[m_num_elems].SemanticIndex = i; - m_elems[m_num_elems].AlignedByteOffset = format->offset; - m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer); - m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - ++m_num_elems; - } - } + for (int i = 0; i < 3; i++) + { + format = &_vtx_decl.normals[i]; + if (format->enable) + { + m_elems[m_num_elems].SemanticName = "NORMAL"; + m_elems[m_num_elems].SemanticIndex = i; + m_elems[m_num_elems].AlignedByteOffset = format->offset; + m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer); + m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + ++m_num_elems; + } + } - for (int i = 0; i < 2; i++) - { - format = &_vtx_decl.colors[i]; - if (format->enable) - { - m_elems[m_num_elems].SemanticName = "COLOR"; - m_elems[m_num_elems].SemanticIndex = i; - m_elems[m_num_elems].AlignedByteOffset = format->offset; - m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer); - m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - ++m_num_elems; - } - } + for (int i = 0; i < 2; i++) + { + format = &_vtx_decl.colors[i]; + if (format->enable) + { + m_elems[m_num_elems].SemanticName = "COLOR"; + m_elems[m_num_elems].SemanticIndex = i; + m_elems[m_num_elems].AlignedByteOffset = format->offset; + m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer); + m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + ++m_num_elems; + } + } - for (int i = 0; i < 8; i++) - { - format = &_vtx_decl.texcoords[i]; - if (format->enable) - { - m_elems[m_num_elems].SemanticName = "TEXCOORD"; - m_elems[m_num_elems].SemanticIndex = i; - m_elems[m_num_elems].AlignedByteOffset = format->offset; - m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer); - m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - ++m_num_elems; - } - } + for (int i = 0; i < 8; i++) + { + format = &_vtx_decl.texcoords[i]; + if (format->enable) + { + m_elems[m_num_elems].SemanticName = "TEXCOORD"; + m_elems[m_num_elems].SemanticIndex = i; + m_elems[m_num_elems].AlignedByteOffset = format->offset; + m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer); + m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + ++m_num_elems; + } + } - format = &_vtx_decl.posmtx; - if (format->enable) - { - m_elems[m_num_elems].SemanticName = "BLENDINDICES"; - m_elems[m_num_elems].AlignedByteOffset = format->offset; - m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer); - m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - ++m_num_elems; - } + format = &_vtx_decl.posmtx; + if (format->enable) + { + m_elems[m_num_elems].SemanticName = "BLENDINDICES"; + m_elems[m_num_elems].AlignedByteOffset = format->offset; + m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer); + m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + ++m_num_elems; + } } void D3DVertexFormat::SetupVertexPointers() { - if (!m_layout) - { - // CreateInputLayout requires a shader input, but it only looks at the - // signature of the shader, so we don't need to recompute it if the shader - // changes. - D3DBlob* vs_bytecode = DX11::VertexShaderCache::GetActiveShaderBytecode(); + if (!m_layout) + { + // CreateInputLayout requires a shader input, but it only looks at the + // signature of the shader, so we don't need to recompute it if the shader + // changes. + D3DBlob* vs_bytecode = DX11::VertexShaderCache::GetActiveShaderBytecode(); - HRESULT hr = DX11::D3D::device->CreateInputLayout(m_elems.data(), m_num_elems, vs_bytecode->Data(), vs_bytecode->Size(), &m_layout); - if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__); - DX11::D3D::SetDebugObjectName((ID3D11DeviceChild*)m_layout, "input layout used to emulate the GX pipeline"); - } - DX11::D3D::stateman->SetInputLayout(m_layout); + HRESULT hr = DX11::D3D::device->CreateInputLayout( + m_elems.data(), m_num_elems, vs_bytecode->Data(), vs_bytecode->Size(), &m_layout); + if (FAILED(hr)) + PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__); + DX11::D3D::SetDebugObjectName((ID3D11DeviceChild*)m_layout, + "input layout used to emulate the GX pipeline"); + } + DX11::D3D::stateman->SetInputLayout(m_layout); } -} // namespace DX11 +} // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp index 5698077817..ad7d7146f0 100644 --- a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp +++ b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp @@ -2,13 +2,13 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoBackends/D3D/PSTextureEncoder.h" #include "Core/HW/Memmap.h" #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DShader.h" #include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DUtil.h" #include "VideoBackends/D3D/FramebufferManager.h" -#include "VideoBackends/D3D/PSTextureEncoder.h" #include "VideoBackends/D3D/Render.h" #include "VideoBackends/D3D/TextureCache.h" #include "VideoBackends/D3D/VertexShaderCache.h" @@ -17,214 +17,211 @@ namespace DX11 { - struct EFBEncodeParams { - DWORD SrcLeft; - DWORD SrcTop; - DWORD DestWidth; - DWORD ScaleFactor; + DWORD SrcLeft; + DWORD SrcTop; + DWORD DestWidth; + DWORD ScaleFactor; }; PSTextureEncoder::PSTextureEncoder() - : m_ready(false), m_out(nullptr), m_outRTV(nullptr), m_outStage(nullptr), - m_encodeParams(nullptr) + : m_ready(false), m_out(nullptr), m_outRTV(nullptr), m_outStage(nullptr), + m_encodeParams(nullptr) { } void PSTextureEncoder::Init() { - m_ready = false; + m_ready = false; - HRESULT hr; + HRESULT hr; - // Create output texture RGBA format - D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC( - DXGI_FORMAT_B8G8R8A8_UNORM, - EFB_WIDTH * 4, EFB_HEIGHT / 4, 1, 1, D3D11_BIND_RENDER_TARGET); - hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_out); - CHECK(SUCCEEDED(hr), "create efb encode output texture"); - D3D::SetDebugObjectName(m_out, "efb encoder output texture"); + // Create output texture RGBA format + D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_B8G8R8A8_UNORM, EFB_WIDTH * 4, + EFB_HEIGHT / 4, 1, 1, D3D11_BIND_RENDER_TARGET); + hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_out); + CHECK(SUCCEEDED(hr), "create efb encode output texture"); + D3D::SetDebugObjectName(m_out, "efb encoder output texture"); - // Create output render target view - D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC(m_out, - D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_B8G8R8A8_UNORM); - hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV); - CHECK(SUCCEEDED(hr), "create efb encode output render target view"); - D3D::SetDebugObjectName(m_outRTV, "efb encoder output rtv"); + // Create output render target view + D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC( + m_out, D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_B8G8R8A8_UNORM); + hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV); + CHECK(SUCCEEDED(hr), "create efb encode output render target view"); + D3D::SetDebugObjectName(m_outRTV, "efb encoder output rtv"); - // Create output staging buffer - t2dd.Usage = D3D11_USAGE_STAGING; - t2dd.BindFlags = 0; - t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_outStage); - CHECK(SUCCEEDED(hr), "create efb encode output staging buffer"); - D3D::SetDebugObjectName(m_outStage, "efb encoder output staging buffer"); + // Create output staging buffer + t2dd.Usage = D3D11_USAGE_STAGING; + t2dd.BindFlags = 0; + t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_outStage); + CHECK(SUCCEEDED(hr), "create efb encode output staging buffer"); + D3D::SetDebugObjectName(m_outStage, "efb encoder output staging buffer"); - // Create constant buffer for uploading data to shaders - D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(EFBEncodeParams), - D3D11_BIND_CONSTANT_BUFFER); - hr = D3D::device->CreateBuffer(&bd, nullptr, &m_encodeParams); - CHECK(SUCCEEDED(hr), "create efb encode params buffer"); - D3D::SetDebugObjectName(m_encodeParams, "efb encoder params buffer"); + // Create constant buffer for uploading data to shaders + D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(EFBEncodeParams), D3D11_BIND_CONSTANT_BUFFER); + hr = D3D::device->CreateBuffer(&bd, nullptr, &m_encodeParams); + CHECK(SUCCEEDED(hr), "create efb encode params buffer"); + D3D::SetDebugObjectName(m_encodeParams, "efb encoder params buffer"); - m_ready = true; + m_ready = true; } void PSTextureEncoder::Shutdown() { - m_ready = false; + m_ready = false; - for (auto& it : m_staticShaders) - { - SAFE_RELEASE(it.second); - } - m_staticShaders.clear(); + for (auto& it : m_staticShaders) + { + SAFE_RELEASE(it.second); + } + m_staticShaders.clear(); - SAFE_RELEASE(m_encodeParams); - SAFE_RELEASE(m_outStage); - SAFE_RELEASE(m_outRTV); - SAFE_RELEASE(m_out); + SAFE_RELEASE(m_encodeParams); + SAFE_RELEASE(m_outStage); + SAFE_RELEASE(m_outRTV); + SAFE_RELEASE(m_out); } -void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool isIntensity, bool scaleByHalf) +void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, PEControl::PixelFormat srcFormat, + const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) { - if (!m_ready) // Make sure we initialized OK - return; + if (!m_ready) // Make sure we initialized OK + return; - HRESULT hr; + HRESULT hr; - // Resolve MSAA targets before copying. - ID3D11ShaderResourceView* pEFB = (srcFormat == PEControl::Z24) ? - FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() : - // FIXME: Instead of resolving EFB, it would be better to pick out a - // single sample from each pixel. The game may break if it isn't - // expecting the blurred edges around multisampled shapes. - FramebufferManager::GetResolvedEFBColorTexture()->GetSRV(); + // Resolve MSAA targets before copying. + ID3D11ShaderResourceView* pEFB = + (srcFormat == PEControl::Z24) ? + FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() : + // FIXME: Instead of resolving EFB, it would be better to pick out a + // single sample from each pixel. The game may break if it isn't + // expecting the blurred edges around multisampled shapes. + FramebufferManager::GetResolvedEFBColorTexture()->GetSRV(); - // Reset API - g_renderer->ResetAPIState(); + // Reset API + g_renderer->ResetAPIState(); - // Set up all the state for EFB encoding - { - const u32 words_per_row = bytes_per_row / sizeof(u32); + // Set up all the state for EFB encoding + { + const u32 words_per_row = bytes_per_row / sizeof(u32); - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(words_per_row), FLOAT(num_blocks_y)); - D3D::context->RSSetViewports(1, &vp); + D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(words_per_row), FLOAT(num_blocks_y)); + D3D::context->RSSetViewports(1, &vp); - constexpr EFBRectangle fullSrcRect(0, 0, EFB_WIDTH, EFB_HEIGHT); - TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(fullSrcRect); + constexpr EFBRectangle fullSrcRect(0, 0, EFB_WIDTH, EFB_HEIGHT); + TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(fullSrcRect); - D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr); + D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr); - EFBEncodeParams params; - params.SrcLeft = srcRect.left; - params.SrcTop = srcRect.top; - params.DestWidth = native_width; - params.ScaleFactor = scaleByHalf ? 2 : 1; - D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, ¶ms, 0, 0); - D3D::stateman->SetPixelConstants(m_encodeParams); + EFBEncodeParams params; + params.SrcLeft = srcRect.left; + params.SrcTop = srcRect.top; + params.DestWidth = native_width; + params.ScaleFactor = scaleByHalf ? 2 : 1; + D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, ¶ms, 0, 0); + D3D::stateman->SetPixelConstants(m_encodeParams); - // Use linear filtering if (bScaleByHalf), use point filtering otherwise - if (scaleByHalf) - D3D::SetLinearCopySampler(); - else - D3D::SetPointCopySampler(); + // Use linear filtering if (bScaleByHalf), use point filtering otherwise + if (scaleByHalf) + D3D::SetLinearCopySampler(); + else + D3D::SetPointCopySampler(); - D3D::drawShadedTexQuad(pEFB, - targetRect.AsRECT(), - Renderer::GetTargetWidth(), - Renderer::GetTargetHeight(), - SetStaticShader(format, srcFormat, isIntensity, scaleByHalf), - VertexShaderCache::GetSimpleVertexShader(), - VertexShaderCache::GetSimpleInputLayout()); + D3D::drawShadedTexQuad( + pEFB, targetRect.AsRECT(), Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), + SetStaticShader(format, srcFormat, isIntensity, scaleByHalf), + VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout()); - // Copy to staging buffer - D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, words_per_row, num_blocks_y, 1); - D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox); + // Copy to staging buffer + D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, words_per_row, num_blocks_y, 1); + D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox); - // Transfer staging buffer to GameCube/Wii RAM - D3D11_MAPPED_SUBRESOURCE map = { 0 }; - hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map); - CHECK(SUCCEEDED(hr), "map staging buffer (0x%x)", hr); + // Transfer staging buffer to GameCube/Wii RAM + D3D11_MAPPED_SUBRESOURCE map = {0}; + hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map); + CHECK(SUCCEEDED(hr), "map staging buffer (0x%x)", hr); - u8* src = (u8*)map.pData; - u32 readStride = std::min(bytes_per_row, map.RowPitch); - for (unsigned int y = 0; y < num_blocks_y; ++y) - { - memcpy(dst, src, readStride); - dst += memory_stride; - src += map.RowPitch; - } + u8* src = (u8*)map.pData; + u32 readStride = std::min(bytes_per_row, map.RowPitch); + for (unsigned int y = 0; y < num_blocks_y; ++y) + { + memcpy(dst, src, readStride); + dst += memory_stride; + src += map.RowPitch; + } - D3D::context->Unmap(m_outStage, 0); - } + D3D::context->Unmap(m_outStage, 0); + } - // Restore API - g_renderer->RestoreAPIState(); - D3D::context->OMSetRenderTargets(1, - &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); + // Restore API + g_renderer->RestoreAPIState(); + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); } -ID3D11PixelShader* PSTextureEncoder::SetStaticShader(unsigned int dstFormat, PEControl::PixelFormat srcFormat, - bool isIntensity, bool scaleByHalf) +ID3D11PixelShader* PSTextureEncoder::SetStaticShader(unsigned int dstFormat, + PEControl::PixelFormat srcFormat, + bool isIntensity, bool scaleByHalf) { - size_t fetchNum = static_cast(srcFormat); - size_t scaledFetchNum = scaleByHalf ? 1 : 0; - size_t intensityNum = isIntensity ? 1 : 0; - size_t generatorNum = dstFormat; + size_t fetchNum = static_cast(srcFormat); + size_t scaledFetchNum = scaleByHalf ? 1 : 0; + size_t intensityNum = isIntensity ? 1 : 0; + size_t generatorNum = dstFormat; - ComboKey key = MakeComboKey(dstFormat, srcFormat, isIntensity, scaleByHalf); + ComboKey key = MakeComboKey(dstFormat, srcFormat, isIntensity, scaleByHalf); - ComboMap::iterator it = m_staticShaders.find(key); - if (it == m_staticShaders.end()) - { - INFO_LOG(VIDEO, "Compiling efb encoding shader for dstFormat 0x%X, srcFormat %d, isIntensity %d, scaleByHalf %d", - dstFormat, static_cast(srcFormat), isIntensity ? 1 : 0, scaleByHalf ? 1 : 0); + ComboMap::iterator it = m_staticShaders.find(key); + if (it == m_staticShaders.end()) + { + INFO_LOG(VIDEO, "Compiling efb encoding shader for dstFormat 0x%X, srcFormat %d, isIntensity " + "%d, scaleByHalf %d", + dstFormat, static_cast(srcFormat), isIntensity ? 1 : 0, scaleByHalf ? 1 : 0); - u32 format = dstFormat; + u32 format = dstFormat; - if (srcFormat == PEControl::Z24) - { - format |= _GX_TF_ZTF; - if (dstFormat == 11) - format = GX_TF_Z16; - else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) - format |= _GX_TF_CTF; - } - else - { - if (dstFormat > GX_TF_RGBA8 || (dstFormat < GX_TF_RGB565 && !isIntensity)) - format |= _GX_TF_CTF; - } + if (srcFormat == PEControl::Z24) + { + format |= _GX_TF_ZTF; + if (dstFormat == 11) + format = GX_TF_Z16; + else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) + format |= _GX_TF_CTF; + } + else + { + if (dstFormat > GX_TF_RGBA8 || (dstFormat < GX_TF_RGB565 && !isIntensity)) + format |= _GX_TF_CTF; + } - D3DBlob* bytecode = nullptr; - const char* shader = TextureConversionShader::GenerateEncodingShader(format, API_D3D); - if (!D3D::CompilePixelShader(shader, &bytecode)) - { - WARN_LOG(VIDEO, "EFB encoder shader for dstFormat 0x%X, srcFormat %d, isIntensity %d, scaleByHalf %d failed to compile", - dstFormat, static_cast(srcFormat), isIntensity ? 1 : 0, scaleByHalf ? 1 : 0); - m_staticShaders[key] = nullptr; - return nullptr; - } + D3DBlob* bytecode = nullptr; + const char* shader = TextureConversionShader::GenerateEncodingShader(format, API_D3D); + if (!D3D::CompilePixelShader(shader, &bytecode)) + { + WARN_LOG(VIDEO, "EFB encoder shader for dstFormat 0x%X, srcFormat %d, isIntensity %d, " + "scaleByHalf %d failed to compile", + dstFormat, static_cast(srcFormat), isIntensity ? 1 : 0, scaleByHalf ? 1 : 0); + m_staticShaders[key] = nullptr; + return nullptr; + } - ID3D11PixelShader* newShader; - HRESULT hr = D3D::device->CreatePixelShader(bytecode->Data(), bytecode->Size(), nullptr, &newShader); - CHECK(SUCCEEDED(hr), "create efb encoder pixel shader"); + ID3D11PixelShader* newShader; + HRESULT hr = + D3D::device->CreatePixelShader(bytecode->Data(), bytecode->Size(), nullptr, &newShader); + CHECK(SUCCEEDED(hr), "create efb encoder pixel shader"); - char debugName[255] = {}; - sprintf_s(debugName, "efb encoder pixel shader (dst:%d, src:%d, intensity:%d, scale:%d)", - dstFormat, srcFormat, isIntensity, scaleByHalf); - D3D::SetDebugObjectName(newShader, debugName); + char debugName[255] = {}; + sprintf_s(debugName, "efb encoder pixel shader (dst:%d, src:%d, intensity:%d, scale:%d)", + dstFormat, srcFormat, isIntensity, scaleByHalf); + D3D::SetDebugObjectName(newShader, debugName); - it = m_staticShaders.emplace(key, newShader).first; - bytecode->Release(); - } + it = m_staticShaders.emplace(key, newShader).first; + bytecode->Release(); + } - return it->second; + return it->second; } - } diff --git a/Source/Core/VideoBackends/D3D/PSTextureEncoder.h b/Source/Core/VideoBackends/D3D/PSTextureEncoder.h index b12030ec66..6300ba085a 100644 --- a/Source/Core/VideoBackends/D3D/PSTextureEncoder.h +++ b/Source/Core/VideoBackends/D3D/PSTextureEncoder.h @@ -23,41 +23,39 @@ struct ID3D11SamplerState; namespace DX11 { - class PSTextureEncoder : public TextureEncoder { public: - PSTextureEncoder(); + PSTextureEncoder(); - void Init(); - void Shutdown(); - void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool isIntensity, bool scaleByHalf); + void Init(); + void Shutdown(); + void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, + u32 memory_stride, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, + bool isIntensity, bool scaleByHalf); private: - bool m_ready; + bool m_ready; - ID3D11Texture2D* m_out; - ID3D11RenderTargetView* m_outRTV; - ID3D11Texture2D* m_outStage; - ID3D11Buffer* m_encodeParams; + ID3D11Texture2D* m_out; + ID3D11RenderTargetView* m_outRTV; + ID3D11Texture2D* m_outStage; + ID3D11Buffer* m_encodeParams; - ID3D11PixelShader* SetStaticShader(unsigned int dstFormat, - PEControl::PixelFormat srcFormat, bool isIntensity, bool scaleByHalf); + ID3D11PixelShader* SetStaticShader(unsigned int dstFormat, PEControl::PixelFormat srcFormat, + bool isIntensity, bool scaleByHalf); - typedef unsigned int ComboKey; // Key for a shader combination + typedef unsigned int ComboKey; // Key for a shader combination - ComboKey MakeComboKey(unsigned int dstFormat, - PEControl::PixelFormat srcFormat, bool isIntensity, bool scaleByHalf) - { - return (dstFormat << 4) | (static_cast(srcFormat) << 2) | (isIntensity ? (1<<1) : 0) - | (scaleByHalf ? (1<<0) : 0); - } + ComboKey MakeComboKey(unsigned int dstFormat, PEControl::PixelFormat srcFormat, bool isIntensity, + bool scaleByHalf) + { + return (dstFormat << 4) | (static_cast(srcFormat) << 2) | (isIntensity ? (1 << 1) : 0) | + (scaleByHalf ? (1 << 0) : 0); + } - typedef std::map ComboMap; + typedef std::map ComboMap; - ComboMap m_staticShaders; + ComboMap m_staticShaders; }; - } diff --git a/Source/Core/VideoBackends/D3D/PerfQuery.cpp b/Source/Core/VideoBackends/D3D/PerfQuery.cpp index 825e1696b0..2eb3c6d89d 100644 --- a/Source/Core/VideoBackends/D3D/PerfQuery.cpp +++ b/Source/Core/VideoBackends/D3D/PerfQuery.cpp @@ -2,147 +2,149 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoBackends/D3D/PerfQuery.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "VideoBackends/D3D/D3DBase.h" -#include "VideoBackends/D3D/PerfQuery.h" #include "VideoCommon/RenderBase.h" -namespace DX11 { - -PerfQuery::PerfQuery() - : m_query_read_pos() +namespace DX11 { - for (ActiveQuery& entry : m_query_buffer) - { - D3D11_QUERY_DESC qdesc = CD3D11_QUERY_DESC(D3D11_QUERY_OCCLUSION, 0); - D3D::device->CreateQuery(&qdesc, &entry.query); - } +PerfQuery::PerfQuery() : m_query_read_pos() +{ + for (ActiveQuery& entry : m_query_buffer) + { + D3D11_QUERY_DESC qdesc = CD3D11_QUERY_DESC(D3D11_QUERY_OCCLUSION, 0); + D3D::device->CreateQuery(&qdesc, &entry.query); + } - ResetQuery(); + ResetQuery(); } PerfQuery::~PerfQuery() { - for (ActiveQuery& entry : m_query_buffer) - { - // TODO: EndQuery? - entry.query->Release(); - } + for (ActiveQuery& entry : m_query_buffer) + { + // TODO: EndQuery? + entry.query->Release(); + } } void PerfQuery::EnableQuery(PerfQueryGroup type) { - // Is this sane? - if (m_query_count > m_query_buffer.size() / 2) - WeakFlush(); + // Is this sane? + if (m_query_count > m_query_buffer.size() / 2) + WeakFlush(); - if (m_query_buffer.size() == m_query_count) - { - // TODO - FlushOne(); - ERROR_LOG(VIDEO, "Flushed query buffer early!"); - } + if (m_query_buffer.size() == m_query_count) + { + // TODO + FlushOne(); + ERROR_LOG(VIDEO, "Flushed query buffer early!"); + } - // start query - if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) - { - auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % m_query_buffer.size()]; + // start query + if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) + { + auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % m_query_buffer.size()]; - D3D::context->Begin(entry.query); - entry.query_type = type; + D3D::context->Begin(entry.query); + entry.query_type = type; - ++m_query_count; - } + ++m_query_count; + } } void PerfQuery::DisableQuery(PerfQueryGroup type) { - // stop query - if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) - { - auto& entry = m_query_buffer[(m_query_read_pos + m_query_count + m_query_buffer.size()-1) % m_query_buffer.size()]; - D3D::context->End(entry.query); - } + // stop query + if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) + { + auto& entry = m_query_buffer[(m_query_read_pos + m_query_count + m_query_buffer.size() - 1) % + m_query_buffer.size()]; + D3D::context->End(entry.query); + } } void PerfQuery::ResetQuery() { - m_query_count = 0; - std::fill_n(m_results, ArraySize(m_results), 0); + m_query_count = 0; + std::fill_n(m_results, ArraySize(m_results), 0); } u32 PerfQuery::GetQueryResult(PerfQueryType type) { - u32 result = 0; + u32 result = 0; - if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC) - result = m_results[PQG_ZCOMP_ZCOMPLOC]; - else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT) - result = m_results[PQG_ZCOMP]; - else if (type == PQ_BLEND_INPUT) - result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC]; - else if (type == PQ_EFB_COPY_CLOCKS) - result = m_results[PQG_EFB_COPY_CLOCKS]; + if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC) + result = m_results[PQG_ZCOMP_ZCOMPLOC]; + else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT) + result = m_results[PQG_ZCOMP]; + else if (type == PQ_BLEND_INPUT) + result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC]; + else if (type == PQ_EFB_COPY_CLOCKS) + result = m_results[PQG_EFB_COPY_CLOCKS]; - return result / 4; + return result / 4; } void PerfQuery::FlushOne() { - auto& entry = m_query_buffer[m_query_read_pos]; + auto& entry = m_query_buffer[m_query_read_pos]; - UINT64 result = 0; - HRESULT hr = S_FALSE; - while (hr != S_OK) - { - // TODO: Might cause us to be stuck in an infinite loop! - hr = D3D::context->GetData(entry.query, &result, sizeof(result), 0); - } + UINT64 result = 0; + HRESULT hr = S_FALSE; + while (hr != S_OK) + { + // TODO: Might cause us to be stuck in an infinite loop! + hr = D3D::context->GetData(entry.query, &result, sizeof(result), 0); + } - // NOTE: Reported pixel metrics should be referenced to native resolution - m_results[entry.query_type] += (u32)(result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight()); + // NOTE: Reported pixel metrics should be referenced to native resolution + m_results[entry.query_type] += (u32)(result * EFB_WIDTH / g_renderer->GetTargetWidth() * + EFB_HEIGHT / g_renderer->GetTargetHeight()); - m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size(); - --m_query_count; + m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size(); + --m_query_count; } // TODO: could selectively flush things, but I don't think that will do much void PerfQuery::FlushResults() { - while (!IsFlushed()) - FlushOne(); + while (!IsFlushed()) + FlushOne(); } void PerfQuery::WeakFlush() { - while (!IsFlushed()) - { - auto& entry = m_query_buffer[m_query_read_pos]; + while (!IsFlushed()) + { + auto& entry = m_query_buffer[m_query_read_pos]; - UINT64 result = 0; - HRESULT hr = D3D::context->GetData(entry.query, &result, sizeof(result), D3D11_ASYNC_GETDATA_DONOTFLUSH); + UINT64 result = 0; + HRESULT hr = + D3D::context->GetData(entry.query, &result, sizeof(result), D3D11_ASYNC_GETDATA_DONOTFLUSH); - if (hr == S_OK) - { - // NOTE: Reported pixel metrics should be referenced to native resolution - m_results[entry.query_type] += (u32)(result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight()); + if (hr == S_OK) + { + // NOTE: Reported pixel metrics should be referenced to native resolution + m_results[entry.query_type] += (u32)(result * EFB_WIDTH / g_renderer->GetTargetWidth() * + EFB_HEIGHT / g_renderer->GetTargetHeight()); - m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size(); - --m_query_count; - } - else - { - break; - } - } + m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size(); + --m_query_count; + } + else + { + break; + } + } } bool PerfQuery::IsFlushed() const { - return 0 == m_query_count; + return 0 == m_query_count; } - -} // namespace +} // namespace diff --git a/Source/Core/VideoBackends/D3D/PerfQuery.h b/Source/Core/VideoBackends/D3D/PerfQuery.h index e133e13d01..2e7aa6a6ff 100644 --- a/Source/Core/VideoBackends/D3D/PerfQuery.h +++ b/Source/Core/VideoBackends/D3D/PerfQuery.h @@ -8,38 +8,38 @@ #include "VideoCommon/PerfQueryBase.h" -namespace DX11 { - +namespace DX11 +{ class PerfQuery : public PerfQueryBase { public: - PerfQuery(); - ~PerfQuery(); + PerfQuery(); + ~PerfQuery(); - void EnableQuery(PerfQueryGroup type) override; - void DisableQuery(PerfQueryGroup type) override; - void ResetQuery() override; - u32 GetQueryResult(PerfQueryType type) override; - void FlushResults() override; - bool IsFlushed() const override; + void EnableQuery(PerfQueryGroup type) override; + void DisableQuery(PerfQueryGroup type) override; + void ResetQuery() override; + u32 GetQueryResult(PerfQueryType type) override; + void FlushResults() override; + bool IsFlushed() const override; private: - struct ActiveQuery - { - ID3D11Query* query; - PerfQueryGroup query_type; - }; + struct ActiveQuery + { + ID3D11Query* query; + PerfQueryGroup query_type; + }; - void WeakFlush(); + void WeakFlush(); - // Only use when non-empty - void FlushOne(); + // Only use when non-empty + void FlushOne(); - // when testing in SMS: 64 was too small, 128 was ok - static const int PERF_QUERY_BUFFER_SIZE = 512; + // when testing in SMS: 64 was too small, 128 was ok + static const int PERF_QUERY_BUFFER_SIZE = 512; - std::array m_query_buffer; - int m_query_read_pos; + std::array m_query_buffer; + int m_query_read_pos; }; -} // namespace +} // namespace diff --git a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp index 901a29b71d..3d48784647 100644 --- a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp @@ -23,7 +23,6 @@ namespace DX11 { - PixelShaderCache::PSCache PixelShaderCache::PixelShaders; const PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry; PixelShaderUid PixelShaderCache::last_uid; @@ -41,604 +40,603 @@ ID3D11PixelShader* s_rgba6_to_rgb8[2] = {nullptr}; ID3D11PixelShader* s_rgb8_to_rgba6[2] = {nullptr}; ID3D11Buffer* pscbuf = nullptr; -const char clear_program_code[] = { - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - "in float4 pos : SV_Position,\n" - "in float4 incol0 : COLOR0){\n" - "ocol0 = incol0;\n" - "}\n" -}; +const char clear_program_code[] = {"void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + "in float4 incol0 : COLOR0){\n" + "ocol0 = incol0;\n" + "}\n"}; // TODO: Find some way to avoid having separate shaders for non-MSAA and MSAA... -const char color_copy_program_code[] = { - "sampler samp0 : register(s0);\n" - "Texture2DArray Tex0 : register(t0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - "in float4 pos : SV_Position,\n" - "in float3 uv0 : TEXCOORD0){\n" - "ocol0 = Tex0.Sample(samp0,uv0);\n" - "}\n" -}; +const char color_copy_program_code[] = {"sampler samp0 : register(s0);\n" + "Texture2DArray Tex0 : register(t0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + "in float3 uv0 : TEXCOORD0){\n" + "ocol0 = Tex0.Sample(samp0,uv0);\n" + "}\n"}; // Anaglyph Red-Cyan shader based on Dubois algorithm // Constants taken from the paper: // "Conversion of a Stereo Pair to Anaglyph with // the Least-Squares Projection Method" // Eric Dubois, March 2009 -const char anaglyph_program_code[] = { - "sampler samp0 : register(s0);\n" - "Texture2DArray Tex0 : register(t0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - "in float4 pos : SV_Position,\n" - "in float3 uv0 : TEXCOORD0){\n" - "float4 c0 = Tex0.Sample(samp0, float3(uv0.xy, 0.0));\n" - "float4 c1 = Tex0.Sample(samp0, float3(uv0.xy, 1.0));\n" - "float3x3 l = float3x3( 0.437, 0.449, 0.164,\n" - " -0.062,-0.062,-0.024,\n" - " -0.048,-0.050,-0.017);\n" - "float3x3 r = float3x3(-0.011,-0.032,-0.007,\n" - " 0.377, 0.761, 0.009,\n" - " -0.026,-0.093, 1.234);\n" - "ocol0 = float4(mul(l, c0.rgb) + mul(r, c1.rgb), c0.a);\n" - "}\n" -}; +const char anaglyph_program_code[] = {"sampler samp0 : register(s0);\n" + "Texture2DArray Tex0 : register(t0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + "in float3 uv0 : TEXCOORD0){\n" + "float4 c0 = Tex0.Sample(samp0, float3(uv0.xy, 0.0));\n" + "float4 c1 = Tex0.Sample(samp0, float3(uv0.xy, 1.0));\n" + "float3x3 l = float3x3( 0.437, 0.449, 0.164,\n" + " -0.062,-0.062,-0.024,\n" + " -0.048,-0.050,-0.017);\n" + "float3x3 r = float3x3(-0.011,-0.032,-0.007,\n" + " 0.377, 0.761, 0.009,\n" + " -0.026,-0.093, 1.234);\n" + "ocol0 = float4(mul(l, c0.rgb) + mul(r, c1.rgb), c0.a);\n" + "}\n"}; // TODO: Improve sampling algorithm! const char color_copy_program_code_msaa[] = { - "#define SAMPLES %d\n" - "sampler samp0 : register(s0);\n" - "Texture2DMSArray Tex0 : register(t0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - "in float4 pos : SV_Position,\n" - "in float3 uv0 : TEXCOORD0){\n" - "int width, height, slices, samples;\n" - "Tex0.GetDimensions(width, height, slices, samples);\n" - "ocol0 = 0;\n" - "for(int i = 0; i < SAMPLES; ++i)\n" - " ocol0 += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" - "ocol0 /= SAMPLES;\n" - "}\n" -}; + "#define SAMPLES %d\n" + "sampler samp0 : register(s0);\n" + "Texture2DMSArray Tex0 : register(t0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + "in float3 uv0 : TEXCOORD0){\n" + "int width, height, slices, samples;\n" + "Tex0.GetDimensions(width, height, slices, samples);\n" + "ocol0 = 0;\n" + "for(int i = 0; i < SAMPLES; ++i)\n" + " ocol0 += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" + "ocol0 /= SAMPLES;\n" + "}\n"}; -const char color_matrix_program_code[] = { - "sampler samp0 : register(s0);\n" - "Texture2DArray Tex0 : register(t0);\n" - "uniform float4 cColMatrix[7] : register(c0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - "in float4 pos : SV_Position,\n" - "in float3 uv0 : TEXCOORD0){\n" - "float4 texcol = Tex0.Sample(samp0,uv0);\n" - "texcol = round(texcol * cColMatrix[5])*cColMatrix[6];\n" - "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n" -}; +const char color_matrix_program_code[] = {"sampler samp0 : register(s0);\n" + "Texture2DArray Tex0 : register(t0);\n" + "uniform float4 cColMatrix[7] : register(c0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + "in float3 uv0 : TEXCOORD0){\n" + "float4 texcol = Tex0.Sample(samp0,uv0);\n" + "texcol = round(texcol * cColMatrix[5])*cColMatrix[6];\n" + "ocol0 = " + "float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[" + "1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3]))" + " + cColMatrix[4];\n" + "}\n"}; const char color_matrix_program_code_msaa[] = { - "#define SAMPLES %d\n" - "sampler samp0 : register(s0);\n" - "Texture2DMSArray Tex0 : register(t0);\n" - "uniform float4 cColMatrix[7] : register(c0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - "in float4 pos : SV_Position,\n" - "in float3 uv0 : TEXCOORD0){\n" - "int width, height, slices, samples;\n" - "Tex0.GetDimensions(width, height, slices, samples);\n" - "float4 texcol = 0;\n" - "for(int i = 0; i < SAMPLES; ++i)\n" - " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" - "texcol /= SAMPLES;\n" - "texcol = round(texcol * cColMatrix[5])*cColMatrix[6];\n" - "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n" -}; + "#define SAMPLES %d\n" + "sampler samp0 : register(s0);\n" + "Texture2DMSArray Tex0 : register(t0);\n" + "uniform float4 cColMatrix[7] : register(c0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + "in float3 uv0 : TEXCOORD0){\n" + "int width, height, slices, samples;\n" + "Tex0.GetDimensions(width, height, slices, samples);\n" + "float4 texcol = 0;\n" + "for(int i = 0; i < SAMPLES; ++i)\n" + " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" + "texcol /= SAMPLES;\n" + "texcol = round(texcol * cColMatrix[5])*cColMatrix[6];\n" + "ocol0 = " + "float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(" + "texcol,cColMatrix[3])) + cColMatrix[4];\n" + "}\n"}; -const char depth_matrix_program[] = { - "sampler samp0 : register(s0);\n" - "Texture2DArray Tex0 : register(t0);\n" - "uniform float4 cColMatrix[7] : register(c0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - " in float4 pos : SV_Position,\n" - " in float3 uv0 : TEXCOORD0){\n" - " float4 texcol = Tex0.Sample(samp0,uv0);\n" - " int depth = int((1.0 - texcol.x) * 16777216.0);\n" +const char depth_matrix_program[] = {"sampler samp0 : register(s0);\n" + "Texture2DArray Tex0 : register(t0);\n" + "uniform float4 cColMatrix[7] : register(c0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + " in float4 pos : SV_Position,\n" + " in float3 uv0 : TEXCOORD0){\n" + " float4 texcol = Tex0.Sample(samp0,uv0);\n" + " int depth = int((1.0 - texcol.x) * 16777216.0);\n" - // Convert to Z24 format - " int4 workspace;\n" - " workspace.r = (depth >> 16) & 255;\n" - " workspace.g = (depth >> 8) & 255;\n" - " workspace.b = depth & 255;\n" + // Convert to Z24 format + " int4 workspace;\n" + " workspace.r = (depth >> 16) & 255;\n" + " workspace.g = (depth >> 8) & 255;\n" + " workspace.b = depth & 255;\n" - // Convert to Z4 format - " workspace.a = (depth >> 16) & 0xF0;\n" + // Convert to Z4 format + " workspace.a = (depth >> 16) & 0xF0;\n" - // Normalize components to [0.0..1.0] - " texcol = float4(workspace) / 255.0;\n" + // Normalize components to [0.0..1.0] + " texcol = float4(workspace) / 255.0;\n" - // Apply color matrix - " ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n" -}; + // Apply color matrix + " ocol0 = " + "float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1])," + "dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + " + "cColMatrix[4];\n" + "}\n"}; const char depth_matrix_program_msaa[] = { - "#define SAMPLES %d\n" - "sampler samp0 : register(s0);\n" - "Texture2DMSArray Tex0 : register(t0);\n" - "uniform float4 cColMatrix[7] : register(c0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - " in float4 pos : SV_Position,\n" - " in float3 uv0 : TEXCOORD0){\n" - " int width, height, slices, samples;\n" - " Tex0.GetDimensions(width, height, slices, samples);\n" - " float4 texcol = 0;\n" - " for(int i = 0; i < SAMPLES; ++i)\n" - " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" - " texcol /= SAMPLES;\n" - " int depth = int((1.0 - texcol.x) * 16777216.0);\n" + "#define SAMPLES %d\n" + "sampler samp0 : register(s0);\n" + "Texture2DMSArray Tex0 : register(t0);\n" + "uniform float4 cColMatrix[7] : register(c0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + " in float4 pos : SV_Position,\n" + " in float3 uv0 : TEXCOORD0){\n" + " int width, height, slices, samples;\n" + " Tex0.GetDimensions(width, height, slices, samples);\n" + " float4 texcol = 0;\n" + " for(int i = 0; i < SAMPLES; ++i)\n" + " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" + " texcol /= SAMPLES;\n" + " int depth = int((1.0 - texcol.x) * 16777216.0);\n" - // Convert to Z24 format - " int4 workspace;\n" - " workspace.r = (depth >> 16) & 255;\n" - " workspace.g = (depth >> 8) & 255;\n" - " workspace.b = depth & 255;\n" + // Convert to Z24 format + " int4 workspace;\n" + " workspace.r = (depth >> 16) & 255;\n" + " workspace.g = (depth >> 8) & 255;\n" + " workspace.b = depth & 255;\n" - // Convert to Z4 format - " workspace.a = (depth >> 16) & 0xF0;\n" + // Convert to Z4 format + " workspace.a = (depth >> 16) & 0xF0;\n" - // Normalize components to [0.0..1.0] - " texcol = float4(workspace) / 255.0;\n" + // Normalize components to [0.0..1.0] + " texcol = float4(workspace) / 255.0;\n" - // Apply color matrix - " ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n" -}; + // Apply color matrix + " ocol0 = " + "float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(" + "texcol,cColMatrix[3])) + cColMatrix[4];\n" + "}\n"}; const char depth_resolve_program[] = { - "#define SAMPLES %d\n" - "Texture2DMSArray Tex0 : register(t0);\n" - "void main(\n" - " out float ocol0 : SV_Target,\n" - " in float4 pos : SV_Position,\n" - " in float3 uv0 : TEXCOORD0)\n" - "{\n" - " int width, height, slices, samples;\n" - " Tex0.GetDimensions(width, height, slices, samples);\n" - " ocol0 = Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), 0).x;\n" - " for(int i = 1; i < SAMPLES; ++i)\n" - " ocol0 = min(ocol0, Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i).x);\n" - "}\n" -}; + "#define SAMPLES %d\n" + "Texture2DMSArray Tex0 : register(t0);\n" + "void main(\n" + " out float ocol0 : SV_Target,\n" + " in float4 pos : SV_Position,\n" + " in float3 uv0 : TEXCOORD0)\n" + "{\n" + " int width, height, slices, samples;\n" + " Tex0.GetDimensions(width, height, slices, samples);\n" + " ocol0 = Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), 0).x;\n" + " for(int i = 1; i < SAMPLES; ++i)\n" + " ocol0 = min(ocol0, Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i).x);\n" + "}\n"}; -const char reint_rgba6_to_rgb8[] = { - "sampler samp0 : register(s0);\n" - "Texture2DArray Tex0 : register(t0);\n" - "void main(\n" - " out float4 ocol0 : SV_Target,\n" - " in float4 pos : SV_Position,\n" - " in float3 uv0 : TEXCOORD0)\n" - "{\n" - " int4 src6 = round(Tex0.Sample(samp0,uv0) * 63.f);\n" - " int4 dst8;\n" - " dst8.r = (src6.r << 2) | (src6.g >> 4);\n" - " dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n" - " dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n" - " dst8.a = 255;\n" - " ocol0 = (float4)dst8 / 255.f;\n" - "}" -}; +const char reint_rgba6_to_rgb8[] = {"sampler samp0 : register(s0);\n" + "Texture2DArray Tex0 : register(t0);\n" + "void main(\n" + " out float4 ocol0 : SV_Target,\n" + " in float4 pos : SV_Position,\n" + " in float3 uv0 : TEXCOORD0)\n" + "{\n" + " int4 src6 = round(Tex0.Sample(samp0,uv0) * 63.f);\n" + " int4 dst8;\n" + " dst8.r = (src6.r << 2) | (src6.g >> 4);\n" + " dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n" + " dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n" + " dst8.a = 255;\n" + " ocol0 = (float4)dst8 / 255.f;\n" + "}"}; const char reint_rgba6_to_rgb8_msaa[] = { - "#define SAMPLES %d\n" - "sampler samp0 : register(s0);\n" - "Texture2DMSArray Tex0 : register(t0);\n" - "void main(\n" - " out float4 ocol0 : SV_Target,\n" - " in float4 pos : SV_Position,\n" - " in float3 uv0 : TEXCOORD0)\n" - "{\n" - " int width, height, slices, samples;\n" - " Tex0.GetDimensions(width, height, slices, samples);\n" - " float4 texcol = 0;\n" - " for (int i = 0; i < SAMPLES; ++i)\n" - " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" - " texcol /= SAMPLES;\n" - " int4 src6 = round(texcol * 63.f);\n" - " int4 dst8;\n" - " dst8.r = (src6.r << 2) | (src6.g >> 4);\n" - " dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n" - " dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n" - " dst8.a = 255;\n" - " ocol0 = (float4)dst8 / 255.f;\n" - "}" -}; + "#define SAMPLES %d\n" + "sampler samp0 : register(s0);\n" + "Texture2DMSArray Tex0 : register(t0);\n" + "void main(\n" + " out float4 ocol0 : SV_Target,\n" + " in float4 pos : SV_Position,\n" + " in float3 uv0 : TEXCOORD0)\n" + "{\n" + " int width, height, slices, samples;\n" + " Tex0.GetDimensions(width, height, slices, samples);\n" + " float4 texcol = 0;\n" + " for (int i = 0; i < SAMPLES; ++i)\n" + " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" + " texcol /= SAMPLES;\n" + " int4 src6 = round(texcol * 63.f);\n" + " int4 dst8;\n" + " dst8.r = (src6.r << 2) | (src6.g >> 4);\n" + " dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n" + " dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n" + " dst8.a = 255;\n" + " ocol0 = (float4)dst8 / 255.f;\n" + "}"}; -const char reint_rgb8_to_rgba6[] = { - "sampler samp0 : register(s0);\n" - "Texture2DArray Tex0 : register(t0);\n" - "void main(\n" - " out float4 ocol0 : SV_Target,\n" - " in float4 pos : SV_Position,\n" - " in float3 uv0 : TEXCOORD0)\n" - "{\n" - " int4 src8 = round(Tex0.Sample(samp0,uv0) * 255.f);\n" - " int4 dst6;\n" - " dst6.r = src8.r >> 2;\n" - " dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n" - " dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n" - " dst6.a = src8.b & 0x3F;\n" - " ocol0 = (float4)dst6 / 63.f;\n" - "}\n" -}; +const char reint_rgb8_to_rgba6[] = {"sampler samp0 : register(s0);\n" + "Texture2DArray Tex0 : register(t0);\n" + "void main(\n" + " out float4 ocol0 : SV_Target,\n" + " in float4 pos : SV_Position,\n" + " in float3 uv0 : TEXCOORD0)\n" + "{\n" + " int4 src8 = round(Tex0.Sample(samp0,uv0) * 255.f);\n" + " int4 dst6;\n" + " dst6.r = src8.r >> 2;\n" + " dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n" + " dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n" + " dst6.a = src8.b & 0x3F;\n" + " ocol0 = (float4)dst6 / 63.f;\n" + "}\n"}; const char reint_rgb8_to_rgba6_msaa[] = { - "#define SAMPLES %d\n" - "sampler samp0 : register(s0);\n" - "Texture2DMSArray Tex0 : register(t0);\n" - "void main(\n" - " out float4 ocol0 : SV_Target,\n" - " in float4 pos : SV_Position,\n" - " in float3 uv0 : TEXCOORD0)\n" - "{\n" - " int width, height, slices, samples;\n" - " Tex0.GetDimensions(width, height, slices, samples);\n" - " float4 texcol = 0;\n" - " for (int i = 0; i < SAMPLES; ++i)\n" - " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" - " texcol /= SAMPLES;\n" - " int4 src8 = round(texcol * 255.f);\n" - " int4 dst6;\n" - " dst6.r = src8.r >> 2;\n" - " dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n" - " dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n" - " dst6.a = src8.b & 0x3F;\n" - " ocol0 = (float4)dst6 / 63.f;\n" - "}\n" -}; + "#define SAMPLES %d\n" + "sampler samp0 : register(s0);\n" + "Texture2DMSArray Tex0 : register(t0);\n" + "void main(\n" + " out float4 ocol0 : SV_Target,\n" + " in float4 pos : SV_Position,\n" + " in float3 uv0 : TEXCOORD0)\n" + "{\n" + " int width, height, slices, samples;\n" + " Tex0.GetDimensions(width, height, slices, samples);\n" + " float4 texcol = 0;\n" + " for (int i = 0; i < SAMPLES; ++i)\n" + " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" + " texcol /= SAMPLES;\n" + " int4 src8 = round(texcol * 255.f);\n" + " int4 dst6;\n" + " dst6.r = src8.r >> 2;\n" + " dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n" + " dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n" + " dst6.a = src8.b & 0x3F;\n" + " ocol0 = (float4)dst6 / 63.f;\n" + "}\n"}; ID3D11PixelShader* PixelShaderCache::ReinterpRGBA6ToRGB8(bool multisampled) { - if (!multisampled || g_ActiveConfig.iMultisamples <= 1) - { - if (!s_rgba6_to_rgb8[0]) - { - s_rgba6_to_rgb8[0] = D3D::CompileAndCreatePixelShader(reint_rgba6_to_rgb8); - CHECK(s_rgba6_to_rgb8[0], "Create RGBA6 to RGB8 pixel shader"); - D3D::SetDebugObjectName(s_rgba6_to_rgb8[0], "RGBA6 to RGB8 pixel shader"); - } - return s_rgba6_to_rgb8[0]; - } - else if (!s_rgba6_to_rgb8[1]) - { - // create MSAA shader for current AA mode - std::string buf = StringFromFormat(reint_rgba6_to_rgb8_msaa, g_ActiveConfig.iMultisamples); - s_rgba6_to_rgb8[1] = D3D::CompileAndCreatePixelShader(buf); + if (!multisampled || g_ActiveConfig.iMultisamples <= 1) + { + if (!s_rgba6_to_rgb8[0]) + { + s_rgba6_to_rgb8[0] = D3D::CompileAndCreatePixelShader(reint_rgba6_to_rgb8); + CHECK(s_rgba6_to_rgb8[0], "Create RGBA6 to RGB8 pixel shader"); + D3D::SetDebugObjectName(s_rgba6_to_rgb8[0], "RGBA6 to RGB8 pixel shader"); + } + return s_rgba6_to_rgb8[0]; + } + else if (!s_rgba6_to_rgb8[1]) + { + // create MSAA shader for current AA mode + std::string buf = StringFromFormat(reint_rgba6_to_rgb8_msaa, g_ActiveConfig.iMultisamples); + s_rgba6_to_rgb8[1] = D3D::CompileAndCreatePixelShader(buf); - CHECK(s_rgba6_to_rgb8[1], "Create RGBA6 to RGB8 MSAA pixel shader"); - D3D::SetDebugObjectName(s_rgba6_to_rgb8[1], "RGBA6 to RGB8 MSAA pixel shader"); - } - return s_rgba6_to_rgb8[1]; + CHECK(s_rgba6_to_rgb8[1], "Create RGBA6 to RGB8 MSAA pixel shader"); + D3D::SetDebugObjectName(s_rgba6_to_rgb8[1], "RGBA6 to RGB8 MSAA pixel shader"); + } + return s_rgba6_to_rgb8[1]; } ID3D11PixelShader* PixelShaderCache::ReinterpRGB8ToRGBA6(bool multisampled) { - if (!multisampled || g_ActiveConfig.iMultisamples <= 1) - { - if (!s_rgb8_to_rgba6[0]) - { - s_rgb8_to_rgba6[0] = D3D::CompileAndCreatePixelShader(reint_rgb8_to_rgba6); - CHECK(s_rgb8_to_rgba6[0], "Create RGB8 to RGBA6 pixel shader"); - D3D::SetDebugObjectName(s_rgb8_to_rgba6[0], "RGB8 to RGBA6 pixel shader"); - } - return s_rgb8_to_rgba6[0]; - } - else if (!s_rgb8_to_rgba6[1]) - { - // create MSAA shader for current AA mode - std::string buf = StringFromFormat(reint_rgb8_to_rgba6_msaa, g_ActiveConfig.iMultisamples); - s_rgb8_to_rgba6[1] = D3D::CompileAndCreatePixelShader(buf); + if (!multisampled || g_ActiveConfig.iMultisamples <= 1) + { + if (!s_rgb8_to_rgba6[0]) + { + s_rgb8_to_rgba6[0] = D3D::CompileAndCreatePixelShader(reint_rgb8_to_rgba6); + CHECK(s_rgb8_to_rgba6[0], "Create RGB8 to RGBA6 pixel shader"); + D3D::SetDebugObjectName(s_rgb8_to_rgba6[0], "RGB8 to RGBA6 pixel shader"); + } + return s_rgb8_to_rgba6[0]; + } + else if (!s_rgb8_to_rgba6[1]) + { + // create MSAA shader for current AA mode + std::string buf = StringFromFormat(reint_rgb8_to_rgba6_msaa, g_ActiveConfig.iMultisamples); + s_rgb8_to_rgba6[1] = D3D::CompileAndCreatePixelShader(buf); - CHECK(s_rgb8_to_rgba6[1], "Create RGB8 to RGBA6 MSAA pixel shader"); - D3D::SetDebugObjectName(s_rgb8_to_rgba6[1], "RGB8 to RGBA6 MSAA pixel shader"); - } - return s_rgb8_to_rgba6[1]; + CHECK(s_rgb8_to_rgba6[1], "Create RGB8 to RGBA6 MSAA pixel shader"); + D3D::SetDebugObjectName(s_rgb8_to_rgba6[1], "RGB8 to RGBA6 MSAA pixel shader"); + } + return s_rgb8_to_rgba6[1]; } ID3D11PixelShader* PixelShaderCache::GetColorCopyProgram(bool multisampled) { - if (!multisampled || g_ActiveConfig.iMultisamples <= 1) - { - return s_ColorCopyProgram[0]; - } - else if (s_ColorCopyProgram[1]) - { - return s_ColorCopyProgram[1]; - } - else - { - // create MSAA shader for current AA mode - std::string buf = StringFromFormat(color_copy_program_code_msaa, g_ActiveConfig.iMultisamples); - s_ColorCopyProgram[1] = D3D::CompileAndCreatePixelShader(buf); - CHECK(s_ColorCopyProgram[1]!=nullptr, "Create color copy MSAA pixel shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorCopyProgram[1], "color copy MSAA pixel shader"); - return s_ColorCopyProgram[1]; - } + if (!multisampled || g_ActiveConfig.iMultisamples <= 1) + { + return s_ColorCopyProgram[0]; + } + else if (s_ColorCopyProgram[1]) + { + return s_ColorCopyProgram[1]; + } + else + { + // create MSAA shader for current AA mode + std::string buf = StringFromFormat(color_copy_program_code_msaa, g_ActiveConfig.iMultisamples); + s_ColorCopyProgram[1] = D3D::CompileAndCreatePixelShader(buf); + CHECK(s_ColorCopyProgram[1] != nullptr, "Create color copy MSAA pixel shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorCopyProgram[1], + "color copy MSAA pixel shader"); + return s_ColorCopyProgram[1]; + } } ID3D11PixelShader* PixelShaderCache::GetColorMatrixProgram(bool multisampled) { - if (!multisampled || g_ActiveConfig.iMultisamples <= 1) - { - return s_ColorMatrixProgram[0]; - } - else if (s_ColorMatrixProgram[1]) - { - return s_ColorMatrixProgram[1]; - } - else - { - // create MSAA shader for current AA mode - std::string buf = StringFromFormat(color_matrix_program_code_msaa, g_ActiveConfig.iMultisamples); - s_ColorMatrixProgram[1] = D3D::CompileAndCreatePixelShader(buf); - CHECK(s_ColorMatrixProgram[1]!=nullptr, "Create color matrix MSAA pixel shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorMatrixProgram[1], "color matrix MSAA pixel shader"); - return s_ColorMatrixProgram[1]; - } + if (!multisampled || g_ActiveConfig.iMultisamples <= 1) + { + return s_ColorMatrixProgram[0]; + } + else if (s_ColorMatrixProgram[1]) + { + return s_ColorMatrixProgram[1]; + } + else + { + // create MSAA shader for current AA mode + std::string buf = + StringFromFormat(color_matrix_program_code_msaa, g_ActiveConfig.iMultisamples); + s_ColorMatrixProgram[1] = D3D::CompileAndCreatePixelShader(buf); + CHECK(s_ColorMatrixProgram[1] != nullptr, "Create color matrix MSAA pixel shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorMatrixProgram[1], + "color matrix MSAA pixel shader"); + return s_ColorMatrixProgram[1]; + } } ID3D11PixelShader* PixelShaderCache::GetDepthMatrixProgram(bool multisampled) { - if (!multisampled || g_ActiveConfig.iMultisamples <= 1) - { - return s_DepthMatrixProgram[0]; - } - else if (s_DepthMatrixProgram[1]) - { - return s_DepthMatrixProgram[1]; - } - else - { - // create MSAA shader for current AA mode - std::string buf = StringFromFormat(depth_matrix_program_msaa, g_ActiveConfig.iMultisamples); - s_DepthMatrixProgram[1] = D3D::CompileAndCreatePixelShader(buf); - CHECK(s_DepthMatrixProgram[1]!=nullptr, "Create depth matrix MSAA pixel shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)s_DepthMatrixProgram[1], "depth matrix MSAA pixel shader"); - return s_DepthMatrixProgram[1]; - } + if (!multisampled || g_ActiveConfig.iMultisamples <= 1) + { + return s_DepthMatrixProgram[0]; + } + else if (s_DepthMatrixProgram[1]) + { + return s_DepthMatrixProgram[1]; + } + else + { + // create MSAA shader for current AA mode + std::string buf = StringFromFormat(depth_matrix_program_msaa, g_ActiveConfig.iMultisamples); + s_DepthMatrixProgram[1] = D3D::CompileAndCreatePixelShader(buf); + CHECK(s_DepthMatrixProgram[1] != nullptr, "Create depth matrix MSAA pixel shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_DepthMatrixProgram[1], + "depth matrix MSAA pixel shader"); + return s_DepthMatrixProgram[1]; + } } ID3D11PixelShader* PixelShaderCache::GetClearProgram() { - return s_ClearProgram; + return s_ClearProgram; } ID3D11PixelShader* PixelShaderCache::GetAnaglyphProgram() { - return s_AnaglyphProgram; + return s_AnaglyphProgram; } ID3D11PixelShader* PixelShaderCache::GetDepthResolveProgram() { - if (s_DepthResolveProgram != nullptr) - return s_DepthResolveProgram; + if (s_DepthResolveProgram != nullptr) + return s_DepthResolveProgram; - // create MSAA shader for current AA mode - std::string buf = StringFromFormat(depth_resolve_program, g_ActiveConfig.iMultisamples); - s_DepthResolveProgram = D3D::CompileAndCreatePixelShader(buf); - CHECK(s_DepthResolveProgram != nullptr, "Create depth matrix MSAA pixel shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)s_DepthResolveProgram, "depth resolve pixel shader"); - return s_DepthResolveProgram; + // create MSAA shader for current AA mode + std::string buf = StringFromFormat(depth_resolve_program, g_ActiveConfig.iMultisamples); + s_DepthResolveProgram = D3D::CompileAndCreatePixelShader(buf); + CHECK(s_DepthResolveProgram != nullptr, "Create depth matrix MSAA pixel shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_DepthResolveProgram, "depth resolve pixel shader"); + return s_DepthResolveProgram; } -ID3D11Buffer* &PixelShaderCache::GetConstantBuffer() +ID3D11Buffer*& PixelShaderCache::GetConstantBuffer() { - // TODO: divide the global variables of the generated shaders into about 5 constant buffers to speed this up - if (PixelShaderManager::dirty) - { - D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(pscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, &PixelShaderManager::constants, sizeof(PixelShaderConstants)); - D3D::context->Unmap(pscbuf, 0); - PixelShaderManager::dirty = false; + // TODO: divide the global variables of the generated shaders into about 5 constant buffers to + // speed this up + if (PixelShaderManager::dirty) + { + D3D11_MAPPED_SUBRESOURCE map; + D3D::context->Map(pscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, &PixelShaderManager::constants, sizeof(PixelShaderConstants)); + D3D::context->Unmap(pscbuf, 0); + PixelShaderManager::dirty = false; - ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(PixelShaderConstants)); - } - return pscbuf; + ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(PixelShaderConstants)); + } + return pscbuf; } // this class will load the precompiled shaders into our cache class PixelShaderCacheInserter : public LinearDiskCacheReader { public: - void Read(const PixelShaderUid &key, const u8* value, u32 value_size) - { - PixelShaderCache::InsertByteCode(key, value, value_size); - } + void Read(const PixelShaderUid& key, const u8* value, u32 value_size) + { + PixelShaderCache::InsertByteCode(key, value, value_size); + } }; void PixelShaderCache::Init() { - unsigned int cbsize = ROUND_UP(sizeof(PixelShaderConstants), 16); // must be a multiple of 16 - D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(cbsize, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - D3D::device->CreateBuffer(&cbdesc, nullptr, &pscbuf); - CHECK(pscbuf!=nullptr, "Create pixel shader constant buffer"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)pscbuf, "pixel shader constant buffer used to emulate the GX pipeline"); + unsigned int cbsize = ROUND_UP(sizeof(PixelShaderConstants), 16); // must be a multiple of 16 + D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(cbsize, D3D11_BIND_CONSTANT_BUFFER, + D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + D3D::device->CreateBuffer(&cbdesc, nullptr, &pscbuf); + CHECK(pscbuf != nullptr, "Create pixel shader constant buffer"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)pscbuf, + "pixel shader constant buffer used to emulate the GX pipeline"); - // used when drawing clear quads - s_ClearProgram = D3D::CompileAndCreatePixelShader(clear_program_code); - CHECK(s_ClearProgram!=nullptr, "Create clear pixel shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "clear pixel shader"); + // used when drawing clear quads + s_ClearProgram = D3D::CompileAndCreatePixelShader(clear_program_code); + CHECK(s_ClearProgram != nullptr, "Create clear pixel shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "clear pixel shader"); - // used for anaglyph stereoscopy - s_AnaglyphProgram = D3D::CompileAndCreatePixelShader(anaglyph_program_code); - CHECK(s_AnaglyphProgram != nullptr, "Create anaglyph pixel shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)s_AnaglyphProgram, "anaglyph pixel shader"); + // used for anaglyph stereoscopy + s_AnaglyphProgram = D3D::CompileAndCreatePixelShader(anaglyph_program_code); + CHECK(s_AnaglyphProgram != nullptr, "Create anaglyph pixel shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_AnaglyphProgram, "anaglyph pixel shader"); - // used when copying/resolving the color buffer - s_ColorCopyProgram[0] = D3D::CompileAndCreatePixelShader(color_copy_program_code); - CHECK(s_ColorCopyProgram[0]!=nullptr, "Create color copy pixel shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorCopyProgram[0], "color copy pixel shader"); + // used when copying/resolving the color buffer + s_ColorCopyProgram[0] = D3D::CompileAndCreatePixelShader(color_copy_program_code); + CHECK(s_ColorCopyProgram[0] != nullptr, "Create color copy pixel shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorCopyProgram[0], "color copy pixel shader"); - // used for color conversion - s_ColorMatrixProgram[0] = D3D::CompileAndCreatePixelShader(color_matrix_program_code); - CHECK(s_ColorMatrixProgram[0]!=nullptr, "Create color matrix pixel shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorMatrixProgram[0], "color matrix pixel shader"); + // used for color conversion + s_ColorMatrixProgram[0] = D3D::CompileAndCreatePixelShader(color_matrix_program_code); + CHECK(s_ColorMatrixProgram[0] != nullptr, "Create color matrix pixel shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorMatrixProgram[0], "color matrix pixel shader"); - // used for depth copy - s_DepthMatrixProgram[0] = D3D::CompileAndCreatePixelShader(depth_matrix_program); - CHECK(s_DepthMatrixProgram[0]!=nullptr, "Create depth matrix pixel shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)s_DepthMatrixProgram[0], "depth matrix pixel shader"); + // used for depth copy + s_DepthMatrixProgram[0] = D3D::CompileAndCreatePixelShader(depth_matrix_program); + CHECK(s_DepthMatrixProgram[0] != nullptr, "Create depth matrix pixel shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_DepthMatrixProgram[0], "depth matrix pixel shader"); - Clear(); + Clear(); - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - SETSTAT(stats.numPixelShadersCreated, 0); - SETSTAT(stats.numPixelShadersAlive, 0); + SETSTAT(stats.numPixelShadersCreated, 0); + SETSTAT(stats.numPixelShadersAlive, 0); - std::string cache_filename = StringFromFormat("%sdx11-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), - SConfig::GetInstance().m_strUniqueID.c_str()); - PixelShaderCacheInserter inserter; - g_ps_disk_cache.OpenAndRead(cache_filename, inserter); + std::string cache_filename = + StringFromFormat("%sdx11-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), + SConfig::GetInstance().m_strUniqueID.c_str()); + PixelShaderCacheInserter inserter; + g_ps_disk_cache.OpenAndRead(cache_filename, inserter); - if (g_Config.bEnableShaderDebugging) - Clear(); + if (g_Config.bEnableShaderDebugging) + Clear(); - last_entry = nullptr; + last_entry = nullptr; } // ONLY to be used during shutdown. void PixelShaderCache::Clear() { - for (auto& iter : PixelShaders) - iter.second.Destroy(); - PixelShaders.clear(); - pixel_uid_checker.Invalidate(); + for (auto& iter : PixelShaders) + iter.second.Destroy(); + PixelShaders.clear(); + pixel_uid_checker.Invalidate(); - last_entry = nullptr; + last_entry = nullptr; } // Used in Swap() when AA mode has changed void PixelShaderCache::InvalidateMSAAShaders() { - SAFE_RELEASE(s_ColorCopyProgram[1]); - SAFE_RELEASE(s_ColorMatrixProgram[1]); - SAFE_RELEASE(s_DepthMatrixProgram[1]); - SAFE_RELEASE(s_rgb8_to_rgba6[1]); - SAFE_RELEASE(s_rgba6_to_rgb8[1]); - SAFE_RELEASE(s_DepthResolveProgram); + SAFE_RELEASE(s_ColorCopyProgram[1]); + SAFE_RELEASE(s_ColorMatrixProgram[1]); + SAFE_RELEASE(s_DepthMatrixProgram[1]); + SAFE_RELEASE(s_rgb8_to_rgba6[1]); + SAFE_RELEASE(s_rgba6_to_rgb8[1]); + SAFE_RELEASE(s_DepthResolveProgram); } void PixelShaderCache::Shutdown() { - SAFE_RELEASE(pscbuf); + SAFE_RELEASE(pscbuf); - SAFE_RELEASE(s_ClearProgram); - SAFE_RELEASE(s_AnaglyphProgram); - SAFE_RELEASE(s_DepthResolveProgram); - for (int i = 0; i < 2; ++i) - { - SAFE_RELEASE(s_ColorCopyProgram[i]); - SAFE_RELEASE(s_ColorMatrixProgram[i]); - SAFE_RELEASE(s_DepthMatrixProgram[i]); - SAFE_RELEASE(s_rgba6_to_rgb8[i]); - SAFE_RELEASE(s_rgb8_to_rgba6[i]); - } + SAFE_RELEASE(s_ClearProgram); + SAFE_RELEASE(s_AnaglyphProgram); + SAFE_RELEASE(s_DepthResolveProgram); + for (int i = 0; i < 2; ++i) + { + SAFE_RELEASE(s_ColorCopyProgram[i]); + SAFE_RELEASE(s_ColorMatrixProgram[i]); + SAFE_RELEASE(s_DepthMatrixProgram[i]); + SAFE_RELEASE(s_rgba6_to_rgb8[i]); + SAFE_RELEASE(s_rgb8_to_rgba6[i]); + } - Clear(); - g_ps_disk_cache.Sync(); - g_ps_disk_cache.Close(); + Clear(); + g_ps_disk_cache.Sync(); + g_ps_disk_cache.Close(); } bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode) { - PixelShaderUid uid = GetPixelShaderUid(dstAlphaMode, API_D3D); - if (g_ActiveConfig.bEnableShaderDebugging) - { - ShaderCode code = GeneratePixelShaderCode(dstAlphaMode, API_D3D); - pixel_uid_checker.AddToIndexAndCheck(code, uid, "Pixel", "p"); - } + PixelShaderUid uid = GetPixelShaderUid(dstAlphaMode, API_D3D); + if (g_ActiveConfig.bEnableShaderDebugging) + { + ShaderCode code = GeneratePixelShaderCode(dstAlphaMode, API_D3D); + pixel_uid_checker.AddToIndexAndCheck(code, uid, "Pixel", "p"); + } - // Check if the shader is already set - if (last_entry) - { - if (uid == last_uid) - { - GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); - return (last_entry->shader != nullptr); - } - } + // Check if the shader is already set + if (last_entry) + { + if (uid == last_uid) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + return (last_entry->shader != nullptr); + } + } - last_uid = uid; + last_uid = uid; - // Check if the shader is already in the cache - PSCache::iterator iter; - iter = PixelShaders.find(uid); - if (iter != PixelShaders.end()) - { - const PSCacheEntry &entry = iter->second; - last_entry = &entry; + // Check if the shader is already in the cache + PSCache::iterator iter; + iter = PixelShaders.find(uid); + if (iter != PixelShaders.end()) + { + const PSCacheEntry& entry = iter->second; + last_entry = &entry; - GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); - return (entry.shader != nullptr); - } + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + return (entry.shader != nullptr); + } - // Need to compile a new shader - ShaderCode code = GeneratePixelShaderCode(dstAlphaMode, API_D3D); + // Need to compile a new shader + ShaderCode code = GeneratePixelShaderCode(dstAlphaMode, API_D3D); - D3DBlob* pbytecode; - if (!D3D::CompilePixelShader(code.GetBuffer(), &pbytecode)) - { - GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); - return false; - } + D3DBlob* pbytecode; + if (!D3D::CompilePixelShader(code.GetBuffer(), &pbytecode)) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); + return false; + } - // Insert the bytecode into the caches - g_ps_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); + // Insert the bytecode into the caches + g_ps_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); - bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); - pbytecode->Release(); + bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); + pbytecode->Release(); - if (g_ActiveConfig.bEnableShaderDebugging && success) - { - PixelShaders[uid].code = code.GetBuffer(); - } + if (g_ActiveConfig.bEnableShaderDebugging && success) + { + PixelShaders[uid].code = code.GetBuffer(); + } - GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - return success; + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + return success; } -bool PixelShaderCache::InsertByteCode(const PixelShaderUid &uid, const void* bytecode, unsigned int bytecodelen) +bool PixelShaderCache::InsertByteCode(const PixelShaderUid& uid, const void* bytecode, + unsigned int bytecodelen) { - ID3D11PixelShader* shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen); - if (shader == nullptr) - return false; + ID3D11PixelShader* shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen); + if (shader == nullptr) + return false; - // TODO: Somehow make the debug name a bit more specific - D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of PixelShaderCache"); + // TODO: Somehow make the debug name a bit more specific + D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of PixelShaderCache"); - // Make an entry in the table - PSCacheEntry newentry; - newentry.shader = shader; - PixelShaders[uid] = newentry; - last_entry = &PixelShaders[uid]; + // Make an entry in the table + PSCacheEntry newentry; + newentry.shader = shader; + PixelShaders[uid] = newentry; + last_entry = &PixelShaders[uid]; - if (!shader) - { - // INCSTAT(stats.numPixelShadersFailed); - return false; - } + if (!shader) + { + // INCSTAT(stats.numPixelShadersFailed); + return false; + } - INCSTAT(stats.numPixelShadersCreated); - SETSTAT(stats.numPixelShadersAlive, PixelShaders.size()); - return true; + INCSTAT(stats.numPixelShadersCreated); + SETSTAT(stats.numPixelShadersAlive, PixelShaders.size()); + return true; } } // DX11 diff --git a/Source/Core/VideoBackends/D3D/PixelShaderCache.h b/Source/Core/VideoBackends/D3D/PixelShaderCache.h index 0e8c071caa..e985374f97 100644 --- a/Source/Core/VideoBackends/D3D/PixelShaderCache.h +++ b/Source/Core/VideoBackends/D3D/PixelShaderCache.h @@ -13,48 +13,48 @@ enum DSTALPHA_MODE; namespace DX11 { - class PixelShaderCache { public: - static void Init(); - static void Clear(); - static void Shutdown(); - static bool SetShader(DSTALPHA_MODE dstAlphaMode); // TODO: Should be renamed to LoadShader - static bool InsertByteCode(const PixelShaderUid &uid, const void* bytecode, unsigned int bytecodelen); + static void Init(); + static void Clear(); + static void Shutdown(); + static bool SetShader(DSTALPHA_MODE dstAlphaMode); // TODO: Should be renamed to LoadShader + static bool InsertByteCode(const PixelShaderUid& uid, const void* bytecode, + unsigned int bytecodelen); - static ID3D11PixelShader* GetActiveShader() { return last_entry->shader; } - static ID3D11Buffer* &GetConstantBuffer(); + static ID3D11PixelShader* GetActiveShader() { return last_entry->shader; } + static ID3D11Buffer*& GetConstantBuffer(); - static ID3D11PixelShader* GetColorMatrixProgram(bool multisampled); - static ID3D11PixelShader* GetColorCopyProgram(bool multisampled); - static ID3D11PixelShader* GetDepthMatrixProgram(bool multisampled); - static ID3D11PixelShader* GetClearProgram(); - static ID3D11PixelShader* GetAnaglyphProgram(); - static ID3D11PixelShader* GetDepthResolveProgram(); - static ID3D11PixelShader* ReinterpRGBA6ToRGB8(bool multisampled); - static ID3D11PixelShader* ReinterpRGB8ToRGBA6(bool multisampled); + static ID3D11PixelShader* GetColorMatrixProgram(bool multisampled); + static ID3D11PixelShader* GetColorCopyProgram(bool multisampled); + static ID3D11PixelShader* GetDepthMatrixProgram(bool multisampled); + static ID3D11PixelShader* GetClearProgram(); + static ID3D11PixelShader* GetAnaglyphProgram(); + static ID3D11PixelShader* GetDepthResolveProgram(); + static ID3D11PixelShader* ReinterpRGBA6ToRGB8(bool multisampled); + static ID3D11PixelShader* ReinterpRGB8ToRGBA6(bool multisampled); - static void InvalidateMSAAShaders(); + static void InvalidateMSAAShaders(); private: - struct PSCacheEntry - { - ID3D11PixelShader* shader; + struct PSCacheEntry + { + ID3D11PixelShader* shader; - std::string code; + std::string code; - PSCacheEntry() : shader(nullptr) {} - void Destroy() { SAFE_RELEASE(shader); } - }; + PSCacheEntry() : shader(nullptr) {} + void Destroy() { SAFE_RELEASE(shader); } + }; - typedef std::map PSCache; + typedef std::map PSCache; - static PSCache PixelShaders; - static const PSCacheEntry* last_entry; - static PixelShaderUid last_uid; + static PSCache PixelShaders; + static const PSCacheEntry* last_entry; + static PixelShaderUid last_uid; - static UidChecker pixel_uid_checker; + static UidChecker pixel_uid_checker; }; } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index c5f591bd30..a18538e234 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -41,7 +41,6 @@ namespace DX11 { - static u32 s_last_multisamples = 1; static bool s_last_stereo_mode = false; static bool s_last_xfb_mode = false; @@ -60,11 +59,11 @@ static D3DTexture2D* s_3d_vision_texture = nullptr; // Nvidia stereo blitting struct defined in "nvstereo.h" from the Nvidia SDK typedef struct _Nv_Stereo_Image_Header { - unsigned int dwSignature; - unsigned int dwWidth; - unsigned int dwHeight; - unsigned int dwBPP; - unsigned int dwFlags; + unsigned int dwSignature; + unsigned int dwWidth; + unsigned int dwHeight; + unsigned int dwBPP; + unsigned int dwFlags; } NVSTEREOIMAGEHEADER, *LPNVSTEREOIMAGEHEADER; #define NVSTEREO_IMAGE_SIGNATURE 0x4433564e @@ -72,10 +71,10 @@ typedef struct _Nv_Stereo_Image_Header // GX pipeline state struct { - SamplerState sampler[8]; - BlendState blend; - ZMode zmode; - RasterizerState raster; + SamplerState sampler[8]; + BlendState blend; + ZMode zmode; + RasterizerState raster; } gx_state; @@ -83,260 +82,277 @@ StateCache gx_state_cache; static void SetupDeviceObjects() { - s_television.Init(); + s_television.Init(); - g_framebuffer_manager = std::make_unique(); + g_framebuffer_manager = std::make_unique(); - HRESULT hr; + HRESULT hr; - D3D11_DEPTH_STENCIL_DESC ddesc; - ddesc.DepthEnable = FALSE; - ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - ddesc.DepthFunc = D3D11_COMPARISON_ALWAYS; - ddesc.StencilEnable = FALSE; - ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[0]); - CHECK(hr==S_OK, "Create depth state for Renderer::ClearScreen"); - ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; - ddesc.DepthEnable = TRUE; - hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[1]); - CHECK(hr==S_OK, "Create depth state for Renderer::ClearScreen"); - ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[2]); - CHECK(hr==S_OK, "Create depth state for Renderer::ClearScreen"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)cleardepthstates[0], "depth state for Renderer::ClearScreen (depth buffer disabled)"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)cleardepthstates[1], "depth state for Renderer::ClearScreen (depth buffer enabled, writing enabled)"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)cleardepthstates[2], "depth state for Renderer::ClearScreen (depth buffer enabled, writing disabled)"); + D3D11_DEPTH_STENCIL_DESC ddesc; + ddesc.DepthEnable = FALSE; + ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + ddesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + ddesc.StencilEnable = FALSE; + ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[0]); + CHECK(hr == S_OK, "Create depth state for Renderer::ClearScreen"); + ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + ddesc.DepthEnable = TRUE; + hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[1]); + CHECK(hr == S_OK, "Create depth state for Renderer::ClearScreen"); + ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[2]); + CHECK(hr == S_OK, "Create depth state for Renderer::ClearScreen"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)cleardepthstates[0], + "depth state for Renderer::ClearScreen (depth buffer disabled)"); + D3D::SetDebugObjectName( + (ID3D11DeviceChild*)cleardepthstates[1], + "depth state for Renderer::ClearScreen (depth buffer enabled, writing enabled)"); + D3D::SetDebugObjectName( + (ID3D11DeviceChild*)cleardepthstates[2], + "depth state for Renderer::ClearScreen (depth buffer enabled, writing disabled)"); - D3D11_BLEND_DESC blenddesc; - blenddesc.AlphaToCoverageEnable = FALSE; - blenddesc.IndependentBlendEnable = FALSE; - blenddesc.RenderTarget[0].BlendEnable = FALSE; - blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; - blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; - blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; - blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; - blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - hr = D3D::device->CreateBlendState(&blenddesc, &resetblendstate); - CHECK(hr==S_OK, "Create blend state for Renderer::ResetAPIState"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)resetblendstate, "blend state for Renderer::ResetAPIState"); + D3D11_BLEND_DESC blenddesc; + blenddesc.AlphaToCoverageEnable = FALSE; + blenddesc.IndependentBlendEnable = FALSE; + blenddesc.RenderTarget[0].BlendEnable = FALSE; + blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; + blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; + blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + hr = D3D::device->CreateBlendState(&blenddesc, &resetblendstate); + CHECK(hr == S_OK, "Create blend state for Renderer::ResetAPIState"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)resetblendstate, + "blend state for Renderer::ResetAPIState"); - clearblendstates[0] = resetblendstate; - resetblendstate->AddRef(); + clearblendstates[0] = resetblendstate; + resetblendstate->AddRef(); - blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_RED|D3D11_COLOR_WRITE_ENABLE_GREEN|D3D11_COLOR_WRITE_ENABLE_BLUE; - hr = D3D::device->CreateBlendState(&blenddesc, &clearblendstates[1]); - CHECK(hr==S_OK, "Create blend state for Renderer::ClearScreen"); + blenddesc.RenderTarget[0].RenderTargetWriteMask = + D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE; + hr = D3D::device->CreateBlendState(&blenddesc, &clearblendstates[1]); + CHECK(hr == S_OK, "Create blend state for Renderer::ClearScreen"); - blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALPHA; - hr = D3D::device->CreateBlendState(&blenddesc, &clearblendstates[2]); - CHECK(hr==S_OK, "Create blend state for Renderer::ClearScreen"); + blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALPHA; + hr = D3D::device->CreateBlendState(&blenddesc, &clearblendstates[2]); + CHECK(hr == S_OK, "Create blend state for Renderer::ClearScreen"); - blenddesc.RenderTarget[0].RenderTargetWriteMask = 0; - hr = D3D::device->CreateBlendState(&blenddesc, &clearblendstates[3]); - CHECK(hr==S_OK, "Create blend state for Renderer::ClearScreen"); + blenddesc.RenderTarget[0].RenderTargetWriteMask = 0; + hr = D3D::device->CreateBlendState(&blenddesc, &clearblendstates[3]); + CHECK(hr == S_OK, "Create blend state for Renderer::ClearScreen"); - ddesc.DepthEnable = FALSE; - ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - ddesc.DepthFunc = D3D11_COMPARISON_LESS; - ddesc.StencilEnable = FALSE; - ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - hr = D3D::device->CreateDepthStencilState(&ddesc, &resetdepthstate); - CHECK(hr==S_OK, "Create depth state for Renderer::ResetAPIState"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)resetdepthstate, "depth stencil state for Renderer::ResetAPIState"); + ddesc.DepthEnable = FALSE; + ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + ddesc.DepthFunc = D3D11_COMPARISON_LESS; + ddesc.StencilEnable = FALSE; + ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + hr = D3D::device->CreateDepthStencilState(&ddesc, &resetdepthstate); + CHECK(hr == S_OK, "Create depth state for Renderer::ResetAPIState"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)resetdepthstate, + "depth stencil state for Renderer::ResetAPIState"); - D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0.f, false, false, false, false); - hr = D3D::device->CreateRasterizerState(&rastdesc, &resetraststate); - CHECK(hr==S_OK, "Create rasterizer state for Renderer::ResetAPIState"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)resetraststate, "rasterizer state for Renderer::ResetAPIState"); + D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, + 0, 0.f, 0.f, false, false, false, false); + hr = D3D::device->CreateRasterizerState(&rastdesc, &resetraststate); + CHECK(hr == S_OK, "Create rasterizer state for Renderer::ResetAPIState"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)resetraststate, + "rasterizer state for Renderer::ResetAPIState"); - s_screenshot_texture = nullptr; + s_screenshot_texture = nullptr; } // Kill off all device objects static void TeardownDeviceObjects() { - g_framebuffer_manager.reset(); + g_framebuffer_manager.reset(); - SAFE_RELEASE(clearblendstates[0]); - SAFE_RELEASE(clearblendstates[1]); - SAFE_RELEASE(clearblendstates[2]); - SAFE_RELEASE(clearblendstates[3]); - SAFE_RELEASE(cleardepthstates[0]); - SAFE_RELEASE(cleardepthstates[1]); - SAFE_RELEASE(cleardepthstates[2]); - SAFE_RELEASE(resetblendstate); - SAFE_RELEASE(resetdepthstate); - SAFE_RELEASE(resetraststate); - SAFE_RELEASE(s_screenshot_texture); - SAFE_RELEASE(s_3d_vision_texture); + SAFE_RELEASE(clearblendstates[0]); + SAFE_RELEASE(clearblendstates[1]); + SAFE_RELEASE(clearblendstates[2]); + SAFE_RELEASE(clearblendstates[3]); + SAFE_RELEASE(cleardepthstates[0]); + SAFE_RELEASE(cleardepthstates[1]); + SAFE_RELEASE(cleardepthstates[2]); + SAFE_RELEASE(resetblendstate); + SAFE_RELEASE(resetdepthstate); + SAFE_RELEASE(resetraststate); + SAFE_RELEASE(s_screenshot_texture); + SAFE_RELEASE(s_3d_vision_texture); - s_television.Shutdown(); + s_television.Shutdown(); - gx_state_cache.Clear(); + gx_state_cache.Clear(); } static void CreateScreenshotTexture() { - // We can't render anything outside of the backbuffer anyway, so use the backbuffer size as the screenshot buffer size. - // This texture is released to be recreated when the window is resized in Renderer::SwapImpl. - D3D11_TEXTURE2D_DESC scrtex_desc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, D3D::GetBackBufferWidth(), D3D::GetBackBufferHeight(), 1, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ|D3D11_CPU_ACCESS_WRITE); - HRESULT hr = D3D::device->CreateTexture2D(&scrtex_desc, nullptr, &s_screenshot_texture); - CHECK(hr==S_OK, "Create screenshot staging texture"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)s_screenshot_texture, "staging screenshot texture"); + // We can't render anything outside of the backbuffer anyway, so use the backbuffer size as the + // screenshot buffer size. + // This texture is released to be recreated when the window is resized in Renderer::SwapImpl. + D3D11_TEXTURE2D_DESC scrtex_desc = CD3D11_TEXTURE2D_DESC( + DXGI_FORMAT_R8G8B8A8_UNORM, D3D::GetBackBufferWidth(), D3D::GetBackBufferHeight(), 1, 1, 0, + D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE); + HRESULT hr = D3D::device->CreateTexture2D(&scrtex_desc, nullptr, &s_screenshot_texture); + CHECK(hr == S_OK, "Create screenshot staging texture"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_screenshot_texture, "staging screenshot texture"); } static D3D11_BOX GetScreenshotSourceBox(const TargetRectangle& targetRc) { - // Since the screenshot buffer is copied back to the CPU via Map(), we can't access pixels that - // fall outside the backbuffer bounds. Therefore, when crop is enabled and the target rect is - // off-screen to the top/left, we clamp the origin at zero, as well as the bottom/right - // coordinates at the backbuffer dimensions. This will result in a rectangle that can be - // smaller than the backbuffer, but never larger. - return CD3D11_BOX( - std::max(targetRc.left, 0), - std::max(targetRc.top, 0), - 0, - std::min(D3D::GetBackBufferWidth(), (unsigned int)targetRc.right), - std::min(D3D::GetBackBufferHeight(), (unsigned int)targetRc.bottom), - 1); + // Since the screenshot buffer is copied back to the CPU via Map(), we can't access pixels that + // fall outside the backbuffer bounds. Therefore, when crop is enabled and the target rect is + // off-screen to the top/left, we clamp the origin at zero, as well as the bottom/right + // coordinates at the backbuffer dimensions. This will result in a rectangle that can be + // smaller than the backbuffer, but never larger. + return CD3D11_BOX(std::max(targetRc.left, 0), std::max(targetRc.top, 0), 0, + std::min(D3D::GetBackBufferWidth(), (unsigned int)targetRc.right), + std::min(D3D::GetBackBufferHeight(), (unsigned int)targetRc.bottom), 1); } static void Create3DVisionTexture(int width, int height) { - // Create a staging texture for 3D vision with signature information in the last row. - // Nvidia 3D Vision supports full SBS, so there is no loss in resolution during this process. - D3D11_SUBRESOURCE_DATA sysData; - sysData.SysMemPitch = 4 * width * 2; - sysData.pSysMem = new u8[(height + 1) * sysData.SysMemPitch]; - LPNVSTEREOIMAGEHEADER header = (LPNVSTEREOIMAGEHEADER)((u8*)sysData.pSysMem + height * sysData.SysMemPitch); - header->dwSignature = NVSTEREO_IMAGE_SIGNATURE; - header->dwWidth = width * 2; - header->dwHeight = height + 1; - header->dwBPP = 32; - header->dwFlags = 0; + // Create a staging texture for 3D vision with signature information in the last row. + // Nvidia 3D Vision supports full SBS, so there is no loss in resolution during this process. + D3D11_SUBRESOURCE_DATA sysData; + sysData.SysMemPitch = 4 * width * 2; + sysData.pSysMem = new u8[(height + 1) * sysData.SysMemPitch]; + LPNVSTEREOIMAGEHEADER header = + (LPNVSTEREOIMAGEHEADER)((u8*)sysData.pSysMem + height * sysData.SysMemPitch); + header->dwSignature = NVSTEREO_IMAGE_SIGNATURE; + header->dwWidth = width * 2; + header->dwHeight = height + 1; + header->dwBPP = 32; + header->dwFlags = 0; - s_3d_vision_texture = D3DTexture2D::Create(width * 2, height + 1, D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, &sysData); - delete[] sysData.pSysMem; + s_3d_vision_texture = + D3DTexture2D::Create(width * 2, height + 1, D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, + DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, &sysData); + delete[] sysData.pSysMem; } -Renderer::Renderer(void *&window_handle) +Renderer::Renderer(void*& window_handle) { - D3D::Create((HWND)window_handle); + D3D::Create((HWND)window_handle); - s_backbuffer_width = D3D::GetBackBufferWidth(); - s_backbuffer_height = D3D::GetBackBufferHeight(); + s_backbuffer_width = D3D::GetBackBufferWidth(); + s_backbuffer_height = D3D::GetBackBufferHeight(); - FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH); - FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT); + FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH); + FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT); - UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); + UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); - s_last_multisamples = g_ActiveConfig.iMultisamples; - s_last_efb_scale = g_ActiveConfig.iEFBScale; - s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; - s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; - CalculateTargetSize(s_backbuffer_width, s_backbuffer_height); - PixelShaderManager::SetEfbScaleChanged(); + s_last_multisamples = g_ActiveConfig.iMultisamples; + s_last_efb_scale = g_ActiveConfig.iEFBScale; + s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; + s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; + CalculateTargetSize(s_backbuffer_width, s_backbuffer_height); + PixelShaderManager::SetEfbScaleChanged(); - SetupDeviceObjects(); + SetupDeviceObjects(); - // Setup GX pipeline state - gx_state.blend.blend_enable = false; - gx_state.blend.write_mask = D3D11_COLOR_WRITE_ENABLE_ALL; - gx_state.blend.src_blend = D3D11_BLEND_ONE; - gx_state.blend.dst_blend = D3D11_BLEND_ZERO; - gx_state.blend.blend_op = D3D11_BLEND_OP_ADD; - gx_state.blend.use_dst_alpha = false; + // Setup GX pipeline state + gx_state.blend.blend_enable = false; + gx_state.blend.write_mask = D3D11_COLOR_WRITE_ENABLE_ALL; + gx_state.blend.src_blend = D3D11_BLEND_ONE; + gx_state.blend.dst_blend = D3D11_BLEND_ZERO; + gx_state.blend.blend_op = D3D11_BLEND_OP_ADD; + gx_state.blend.use_dst_alpha = false; - for (unsigned int k = 0;k < 8;k++) - { - gx_state.sampler[k].packed = 0; - } + for (unsigned int k = 0; k < 8; k++) + { + gx_state.sampler[k].packed = 0; + } - gx_state.zmode.testenable = false; - gx_state.zmode.updateenable = false; - gx_state.zmode.func = ZMode::NEVER; + gx_state.zmode.testenable = false; + gx_state.zmode.updateenable = false; + gx_state.zmode.func = ZMode::NEVER; - gx_state.raster.cull_mode = D3D11_CULL_NONE; + gx_state.raster.cull_mode = D3D11_CULL_NONE; - // Clear EFB textures - float ClearColor[4] = { 0.f, 0.f, 0.f, 1.f }; - D3D::context->ClearRenderTargetView(FramebufferManager::GetEFBColorTexture()->GetRTV(), ClearColor); - D3D::context->ClearDepthStencilView(FramebufferManager::GetEFBDepthTexture()->GetDSV(), D3D11_CLEAR_DEPTH, 0.f, 0); + // Clear EFB textures + float ClearColor[4] = {0.f, 0.f, 0.f, 1.f}; + D3D::context->ClearRenderTargetView(FramebufferManager::GetEFBColorTexture()->GetRTV(), + ClearColor); + D3D::context->ClearDepthStencilView(FramebufferManager::GetEFBDepthTexture()->GetDSV(), + D3D11_CLEAR_DEPTH, 0.f, 0); - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)s_target_width, (float)s_target_height); - D3D::context->RSSetViewports(1, &vp); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); - D3D::BeginFrame(); + D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)s_target_width, (float)s_target_height); + D3D::context->RSSetViewports(1, &vp); + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); + D3D::BeginFrame(); } Renderer::~Renderer() { - TeardownDeviceObjects(); - D3D::EndFrame(); - D3D::Present(); - D3D::Close(); + TeardownDeviceObjects(); + D3D::EndFrame(); + D3D::Present(); + D3D::Close(); } void Renderer::RenderText(const std::string& text, int left, int top, u32 color) { - D3D::font.DrawTextScaled((float)(left+1), (float)(top+1), 20.f, 0.0f, color & 0xFF000000, text); - D3D::font.DrawTextScaled((float)left, (float)top, 20.f, 0.0f, color, text); + D3D::font.DrawTextScaled((float)(left + 1), (float)(top + 1), 20.f, 0.0f, color & 0xFF000000, + text); + D3D::font.DrawTextScaled((float)left, (float)top, 20.f, 0.0f, color, text); } TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc) { - TargetRectangle result; - result.left = EFBToScaledX(rc.left); - result.top = EFBToScaledY(rc.top); - result.right = EFBToScaledX(rc.right); - result.bottom = EFBToScaledY(rc.bottom); - return result; + TargetRectangle result; + result.left = EFBToScaledX(rc.left); + result.top = EFBToScaledY(rc.top); + result.right = EFBToScaledX(rc.right); + result.bottom = EFBToScaledY(rc.bottom); + return result; } // With D3D, we have to resize the backbuffer if the window changed // size. bool Renderer::CheckForResize() { - RECT rcWindow; - GetClientRect(D3D::hWnd, &rcWindow); - int client_width = rcWindow.right - rcWindow.left; - int client_height = rcWindow.bottom - rcWindow.top; + RECT rcWindow; + GetClientRect(D3D::hWnd, &rcWindow); + int client_width = rcWindow.right - rcWindow.left; + int client_height = rcWindow.bottom - rcWindow.top; - // Sanity check - if ((client_width != Renderer::GetBackbufferWidth() || - client_height != Renderer::GetBackbufferHeight()) && - client_width >= 4 && client_height >= 4) - { - return true; - } + // Sanity check + if ((client_width != Renderer::GetBackbufferWidth() || + client_height != Renderer::GetBackbufferHeight()) && + client_width >= 4 && client_height >= 4) + { + return true; + } - return false; + return false; } void Renderer::SetScissorRect(const EFBRectangle& rc) { - TargetRectangle trc = ConvertEFBRectangle(rc); - D3D::context->RSSetScissorRects(1, trc.AsRECT()); + TargetRectangle trc = ConvertEFBRectangle(rc); + D3D::context->RSSetScissorRects(1, trc.AsRECT()); } void Renderer::SetColorMask() { - // Only enable alpha channel if it's supported by the current EFB format - UINT8 color_mask = 0; - if (bpmem.alpha_test.TestResult() != AlphaTest::FAIL) - { - if (bpmem.blendmode.alphaupdate && (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24)) - color_mask = D3D11_COLOR_WRITE_ENABLE_ALPHA; - if (bpmem.blendmode.colorupdate) - color_mask |= D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE; - } - gx_state.blend.write_mask = color_mask; + // Only enable alpha channel if it's supported by the current EFB format + UINT8 color_mask = 0; + if (bpmem.alpha_test.TestResult() != AlphaTest::FAIL) + { + if (bpmem.blendmode.alphaupdate && (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24)) + color_mask = D3D11_COLOR_WRITE_ENABLE_ALPHA; + if (bpmem.blendmode.colorupdate) + color_mask |= D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | + D3D11_COLOR_WRITE_ENABLE_BLUE; + } + gx_state.blend.write_mask = color_mask; } // This function allows the CPU to directly access the EFB. @@ -355,976 +371,1037 @@ void Renderer::SetColorMask() // - GX_PokeZMode (TODO) u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) { - // Convert EFB dimensions to the ones of our render target - EFBRectangle efbPixelRc; - efbPixelRc.left = x; - efbPixelRc.top = y; - efbPixelRc.right = x + 1; - efbPixelRc.bottom = y + 1; - TargetRectangle targetPixelRc = Renderer::ConvertEFBRectangle(efbPixelRc); + // Convert EFB dimensions to the ones of our render target + EFBRectangle efbPixelRc; + efbPixelRc.left = x; + efbPixelRc.top = y; + efbPixelRc.right = x + 1; + efbPixelRc.bottom = y + 1; + TargetRectangle targetPixelRc = Renderer::ConvertEFBRectangle(efbPixelRc); - // Take the mean of the resulting dimensions; TODO: Don't use the center pixel, compute the average color instead - D3D11_RECT RectToLock; - if (type == PEEK_COLOR || type == PEEK_Z) - { - RectToLock.left = (targetPixelRc.left + targetPixelRc.right) / 2; - RectToLock.top = (targetPixelRc.top + targetPixelRc.bottom) / 2; - RectToLock.right = RectToLock.left + 1; - RectToLock.bottom = RectToLock.top + 1; - } - else - { - RectToLock.left = targetPixelRc.left; - RectToLock.right = targetPixelRc.right; - RectToLock.top = targetPixelRc.top; - RectToLock.bottom = targetPixelRc.bottom; - } + // Take the mean of the resulting dimensions; TODO: Don't use the center pixel, compute the + // average color instead + D3D11_RECT RectToLock; + if (type == PEEK_COLOR || type == PEEK_Z) + { + RectToLock.left = (targetPixelRc.left + targetPixelRc.right) / 2; + RectToLock.top = (targetPixelRc.top + targetPixelRc.bottom) / 2; + RectToLock.right = RectToLock.left + 1; + RectToLock.bottom = RectToLock.top + 1; + } + else + { + RectToLock.left = targetPixelRc.left; + RectToLock.right = targetPixelRc.right; + RectToLock.top = targetPixelRc.top; + RectToLock.bottom = targetPixelRc.bottom; + } - // Reset any game specific settings. - ResetAPIState(); - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, 1.f, 1.f); - D3D::context->RSSetViewports(1, &vp); - D3D::SetPointCopySampler(); + // Reset any game specific settings. + ResetAPIState(); + D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, 1.f, 1.f); + D3D::context->RSSetViewports(1, &vp); + D3D::SetPointCopySampler(); - // Select copy and read textures depending on if we are doing a color or depth read (since they are different formats). - D3DTexture2D* source_tex; - D3DTexture2D* read_tex; - ID3D11Texture2D* staging_tex; - if (type == PEEK_COLOR) - { - source_tex = FramebufferManager::GetEFBColorTexture(); - read_tex = FramebufferManager::GetEFBColorReadTexture(); - staging_tex = FramebufferManager::GetEFBColorStagingBuffer(); - } - else - { - source_tex = FramebufferManager::GetEFBDepthTexture(); - read_tex = FramebufferManager::GetEFBDepthReadTexture(); - staging_tex = FramebufferManager::GetEFBDepthStagingBuffer(); - } + // Select copy and read textures depending on if we are doing a color or depth read (since they + // are different formats). + D3DTexture2D* source_tex; + D3DTexture2D* read_tex; + ID3D11Texture2D* staging_tex; + if (type == PEEK_COLOR) + { + source_tex = FramebufferManager::GetEFBColorTexture(); + read_tex = FramebufferManager::GetEFBColorReadTexture(); + staging_tex = FramebufferManager::GetEFBColorStagingBuffer(); + } + else + { + source_tex = FramebufferManager::GetEFBDepthTexture(); + read_tex = FramebufferManager::GetEFBDepthReadTexture(); + staging_tex = FramebufferManager::GetEFBDepthStagingBuffer(); + } - // Select pixel shader (we don't want to average depth samples, instead select the minimum). - ID3D11PixelShader* copy_pixel_shader; - if (type == PEEK_Z && g_ActiveConfig.iMultisamples > 1) - copy_pixel_shader = PixelShaderCache::GetDepthResolveProgram(); - else - copy_pixel_shader = PixelShaderCache::GetColorCopyProgram(true); + // Select pixel shader (we don't want to average depth samples, instead select the minimum). + ID3D11PixelShader* copy_pixel_shader; + if (type == PEEK_Z && g_ActiveConfig.iMultisamples > 1) + copy_pixel_shader = PixelShaderCache::GetDepthResolveProgram(); + else + copy_pixel_shader = PixelShaderCache::GetColorCopyProgram(true); - // Draw a quad to grab the texel we want to read. - D3D::context->OMSetRenderTargets(1, &read_tex->GetRTV(), nullptr); - D3D::drawShadedTexQuad(source_tex->GetSRV(), - &RectToLock, - Renderer::GetTargetWidth(), - Renderer::GetTargetHeight(), - copy_pixel_shader, - VertexShaderCache::GetSimpleVertexShader(), - VertexShaderCache::GetSimpleInputLayout()); + // Draw a quad to grab the texel we want to read. + D3D::context->OMSetRenderTargets(1, &read_tex->GetRTV(), nullptr); + D3D::drawShadedTexQuad(source_tex->GetSRV(), &RectToLock, Renderer::GetTargetWidth(), + Renderer::GetTargetHeight(), copy_pixel_shader, + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout()); - // Restore expected game state. - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); - RestoreAPIState(); + // Restore expected game state. + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); + RestoreAPIState(); - // Copy the pixel from the renderable to cpu-readable buffer. - D3D11_BOX box = CD3D11_BOX(0, 0, 0, 1, 1, 1); - D3D::context->CopySubresourceRegion(staging_tex, 0, 0, 0, 0, read_tex->GetTex(), 0, &box); - D3D11_MAPPED_SUBRESOURCE map; - CHECK(D3D::context->Map(staging_tex, 0, D3D11_MAP_READ, 0, &map) == S_OK, "Map staging buffer failed"); + // Copy the pixel from the renderable to cpu-readable buffer. + D3D11_BOX box = CD3D11_BOX(0, 0, 0, 1, 1, 1); + D3D::context->CopySubresourceRegion(staging_tex, 0, 0, 0, 0, read_tex->GetTex(), 0, &box); + D3D11_MAPPED_SUBRESOURCE map; + CHECK(D3D::context->Map(staging_tex, 0, D3D11_MAP_READ, 0, &map) == S_OK, + "Map staging buffer failed"); - // Convert the framebuffer data to the format the game is expecting to receive. - u32 ret; - if (type == PEEK_COLOR) - { - u32 val; - memcpy(&val, map.pData, sizeof(val)); + // Convert the framebuffer data to the format the game is expecting to receive. + u32 ret; + if (type == PEEK_COLOR) + { + u32 val; + memcpy(&val, map.pData, sizeof(val)); - // our buffers are RGBA, yet a BGRA value is expected - val = ((val & 0xFF00FF00) | ((val >> 16) & 0xFF) | ((val << 16) & 0xFF0000)); + // our buffers are RGBA, yet a BGRA value is expected + val = ((val & 0xFF00FF00) | ((val >> 16) & 0xFF) | ((val << 16) & 0xFF0000)); - // check what to do with the alpha channel (GX_PokeAlphaRead) - PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode(); + // check what to do with the alpha channel (GX_PokeAlphaRead) + PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode(); - if (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24) - { - val = RGBA8ToRGBA6ToRGBA8(val); - } - else if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) - { - val = RGBA8ToRGB565ToRGBA8(val); - } - if (bpmem.zcontrol.pixel_format != PEControl::RGBA6_Z24) - { - val |= 0xFF000000; - } + if (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24) + { + val = RGBA8ToRGBA6ToRGBA8(val); + } + else if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) + { + val = RGBA8ToRGB565ToRGBA8(val); + } + if (bpmem.zcontrol.pixel_format != PEControl::RGBA6_Z24) + { + val |= 0xFF000000; + } - if (alpha_read_mode.ReadMode == 2) ret = val; // GX_READ_NONE - else if (alpha_read_mode.ReadMode == 1) ret = (val | 0xFF000000); // GX_READ_FF - else /*if(alpha_read_mode.ReadMode == 0)*/ ret = (val & 0x00FFFFFF); // GX_READ_00 - } - else // type == PEEK_Z - { - float val; - memcpy(&val, map.pData, sizeof(val)); + if (alpha_read_mode.ReadMode == 2) + ret = val; // GX_READ_NONE + else if (alpha_read_mode.ReadMode == 1) + ret = (val | 0xFF000000); // GX_READ_FF + else /*if(alpha_read_mode.ReadMode == 0)*/ + ret = (val & 0x00FFFFFF); // GX_READ_00 + } + else // type == PEEK_Z + { + float val; + memcpy(&val, map.pData, sizeof(val)); - // depth buffer is inverted in the d3d backend - val = 1.0f - val; + // depth buffer is inverted in the d3d backend + val = 1.0f - val; - if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) - { - // if Z is in 16 bit format you must return a 16 bit integer - ret = MathUtil::Clamp(static_cast(val * 65536.0f), 0, 0xFFFF); - } - else - { - ret = MathUtil::Clamp(static_cast(val * 16777216.0f), 0, 0xFFFFFF); - } - } + if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) + { + // if Z is in 16 bit format you must return a 16 bit integer + ret = MathUtil::Clamp(static_cast(val * 65536.0f), 0, 0xFFFF); + } + else + { + ret = MathUtil::Clamp(static_cast(val * 16777216.0f), 0, 0xFFFFFF); + } + } - D3D::context->Unmap(staging_tex, 0); - return ret; + D3D::context->Unmap(staging_tex, 0); + return ret; } void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) { - ResetAPIState(); + ResetAPIState(); - if (type == POKE_COLOR) - { - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight()); - D3D::context->RSSetViewports(1, &vp); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), nullptr); - } - else // if (type == POKE_Z) - { - D3D::stateman->PushBlendState(clearblendstates[3]); - D3D::stateman->PushDepthState(cleardepthstates[1]); + if (type == POKE_COLOR) + { + D3D11_VIEWPORT vp = + CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight()); + D3D::context->RSSetViewports(1, &vp); + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + nullptr); + } + else // if (type == POKE_Z) + { + D3D::stateman->PushBlendState(clearblendstates[3]); + D3D::stateman->PushDepthState(cleardepthstates[1]); - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight()); + D3D11_VIEWPORT vp = + CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight()); - D3D::context->RSSetViewports(1, &vp); + D3D::context->RSSetViewports(1, &vp); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); - } + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); + } - D3D::DrawEFBPokeQuads(type, points, num_points); + D3D::DrawEFBPokeQuads(type, points, num_points); - if (type == POKE_Z) - { - D3D::stateman->PopDepthState(); - D3D::stateman->PopBlendState(); - } + if (type == POKE_Z) + { + D3D::stateman->PopDepthState(); + D3D::stateman->PopBlendState(); + } - RestoreAPIState(); + RestoreAPIState(); } void Renderer::SetViewport() { - // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) - // [0] = width/2 - // [1] = height/2 - // [2] = 16777215 * (farz - nearz) - // [3] = xorig + width/2 + 342 - // [4] = yorig + height/2 + 342 - // [5] = 16777215 * farz + // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) + // [0] = width/2 + // [1] = height/2 + // [2] = 16777215 * (farz - nearz) + // [3] = xorig + width/2 + 342 + // [4] = yorig + height/2 + 342 + // [5] = 16777215 * farz - // D3D crashes for zero viewports - if (xfmem.viewport.wd == 0 || xfmem.viewport.ht == 0) - return; + // D3D crashes for zero viewports + if (xfmem.viewport.wd == 0 || xfmem.viewport.ht == 0) + return; - int scissorXOff = bpmem.scissorOffset.x * 2; - int scissorYOff = bpmem.scissorOffset.y * 2; + int scissorXOff = bpmem.scissorOffset.x * 2; + int scissorYOff = bpmem.scissorOffset.y * 2; - float X = Renderer::EFBToScaledXf(xfmem.viewport.xOrig - xfmem.viewport.wd - scissorXOff); - float Y = Renderer::EFBToScaledYf(xfmem.viewport.yOrig + xfmem.viewport.ht - scissorYOff); - float Wd = Renderer::EFBToScaledXf(2.0f * xfmem.viewport.wd); - float Ht = Renderer::EFBToScaledYf(-2.0f * xfmem.viewport.ht); - if (Wd < 0.0f) - { - X += Wd; - Wd = -Wd; - } - if (Ht < 0.0f) - { - Y += Ht; - Ht = -Ht; - } + float X = Renderer::EFBToScaledXf(xfmem.viewport.xOrig - xfmem.viewport.wd - scissorXOff); + float Y = Renderer::EFBToScaledYf(xfmem.viewport.yOrig + xfmem.viewport.ht - scissorYOff); + float Wd = Renderer::EFBToScaledXf(2.0f * xfmem.viewport.wd); + float Ht = Renderer::EFBToScaledYf(-2.0f * xfmem.viewport.ht); + if (Wd < 0.0f) + { + X += Wd; + Wd = -Wd; + } + if (Ht < 0.0f) + { + Y += Ht; + Ht = -Ht; + } - // In D3D, the viewport rectangle must fit within the render target. - X = (X >= 0.f) ? X : 0.f; - Y = (Y >= 0.f) ? Y : 0.f; - Wd = (X + Wd <= GetTargetWidth()) ? Wd : (GetTargetWidth() - X); - Ht = (Y + Ht <= GetTargetHeight()) ? Ht : (GetTargetHeight() - Y); + // In D3D, the viewport rectangle must fit within the render target. + X = (X >= 0.f) ? X : 0.f; + Y = (Y >= 0.f) ? Y : 0.f; + Wd = (X + Wd <= GetTargetWidth()) ? Wd : (GetTargetWidth() - X); + Ht = (Y + Ht <= GetTargetHeight()) ? Ht : (GetTargetHeight() - Y); - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(X, Y, Wd, Ht, - 1.0f - MathUtil::Clamp(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f, - 1.0f - MathUtil::Clamp(xfmem.viewport.farZ - MathUtil::Clamp(xfmem.viewport.zRange, 0.0f, 16777216.0f), 0.0f, 16777215.0f) / 16777216.0f); - D3D::context->RSSetViewports(1, &vp); + D3D11_VIEWPORT vp = CD3D11_VIEWPORT( + X, Y, Wd, Ht, + 1.0f - MathUtil::Clamp(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f, + 1.0f - + MathUtil::Clamp(xfmem.viewport.farZ - MathUtil::Clamp(xfmem.viewport.zRange, + 0.0f, 16777216.0f), + 0.0f, 16777215.0f) / + 16777216.0f); + D3D::context->RSSetViewports(1, &vp); } -void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) +void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, + u32 color, u32 z) { - ResetAPIState(); + ResetAPIState(); - if (colorEnable && alphaEnable) D3D::stateman->PushBlendState(clearblendstates[0]); - else if (colorEnable) D3D::stateman->PushBlendState(clearblendstates[1]); - else if (alphaEnable) D3D::stateman->PushBlendState(clearblendstates[2]); - else D3D::stateman->PushBlendState(clearblendstates[3]); + if (colorEnable && alphaEnable) + D3D::stateman->PushBlendState(clearblendstates[0]); + else if (colorEnable) + D3D::stateman->PushBlendState(clearblendstates[1]); + else if (alphaEnable) + D3D::stateman->PushBlendState(clearblendstates[2]); + else + D3D::stateman->PushBlendState(clearblendstates[3]); - // TODO: Should we enable Z testing here? - /*if (!bpmem.zmode.testenable) D3D::stateman->PushDepthState(cleardepthstates[0]); - else */if (zEnable) D3D::stateman->PushDepthState(cleardepthstates[1]); - else /*if (!zEnable)*/ D3D::stateman->PushDepthState(cleardepthstates[2]); + // TODO: Should we enable Z testing here? + /*if (!bpmem.zmode.testenable) D3D::stateman->PushDepthState(cleardepthstates[0]); + else */ if (zEnable) + D3D::stateman->PushDepthState(cleardepthstates[1]); + else /*if (!zEnable)*/ + D3D::stateman->PushDepthState(cleardepthstates[2]); - // Update the view port for clearing the picture - TargetRectangle targetRc = Renderer::ConvertEFBRectangle(rc); - D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top, (float)targetRc.GetWidth(), (float)targetRc.GetHeight(), 0.f, 1.f); - D3D::context->RSSetViewports(1, &vp); + // Update the view port for clearing the picture + TargetRectangle targetRc = Renderer::ConvertEFBRectangle(rc); + D3D11_VIEWPORT vp = + CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top, (float)targetRc.GetWidth(), + (float)targetRc.GetHeight(), 0.f, 1.f); + D3D::context->RSSetViewports(1, &vp); - // Color is passed in bgra mode so we need to convert it to rgba - u32 rgbaColor = (color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000); - D3D::drawClearQuad(rgbaColor, 1.0f - (z & 0xFFFFFF) / 16777216.0f); + // Color is passed in bgra mode so we need to convert it to rgba + u32 rgbaColor = (color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000); + D3D::drawClearQuad(rgbaColor, 1.0f - (z & 0xFFFFFF) / 16777216.0f); - D3D::stateman->PopDepthState(); - D3D::stateman->PopBlendState(); + D3D::stateman->PopDepthState(); + D3D::stateman->PopBlendState(); - RestoreAPIState(); + RestoreAPIState(); } void Renderer::ReinterpretPixelData(unsigned int convtype) { - // TODO: MSAA support.. - D3D11_RECT source = CD3D11_RECT(0, 0, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight()); + // TODO: MSAA support.. + D3D11_RECT source = + CD3D11_RECT(0, 0, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight()); - ID3D11PixelShader* pixel_shader; - if (convtype == 0) pixel_shader = PixelShaderCache::ReinterpRGB8ToRGBA6(true); - else if (convtype == 2) pixel_shader = PixelShaderCache::ReinterpRGBA6ToRGB8(true); - else - { - ERROR_LOG(VIDEO, "Trying to reinterpret pixel data with unsupported conversion type %d", convtype); - return; - } + ID3D11PixelShader* pixel_shader; + if (convtype == 0) + pixel_shader = PixelShaderCache::ReinterpRGB8ToRGBA6(true); + else if (convtype == 2) + pixel_shader = PixelShaderCache::ReinterpRGBA6ToRGB8(true); + else + { + ERROR_LOG(VIDEO, "Trying to reinterpret pixel data with unsupported conversion type %d", + convtype); + return; + } - // convert data and set the target texture as our new EFB - g_renderer->ResetAPIState(); + // convert data and set the target texture as our new EFB + g_renderer->ResetAPIState(); - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)g_renderer->GetTargetWidth(), (float)g_renderer->GetTargetHeight()); - D3D::context->RSSetViewports(1, &vp); + D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)g_renderer->GetTargetWidth(), + (float)g_renderer->GetTargetHeight()); + D3D::context->RSSetViewports(1, &vp); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTempTexture()->GetRTV(), nullptr); - D3D::SetPointCopySampler(); - D3D::drawShadedTexQuad(FramebufferManager::GetEFBColorTexture()->GetSRV(), &source, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(), - pixel_shader, VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader()); + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTempTexture()->GetRTV(), + nullptr); + D3D::SetPointCopySampler(); + D3D::drawShadedTexQuad( + FramebufferManager::GetEFBColorTexture()->GetSRV(), &source, g_renderer->GetTargetWidth(), + g_renderer->GetTargetHeight(), pixel_shader, VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader()); - g_renderer->RestoreAPIState(); + g_renderer->RestoreAPIState(); - FramebufferManager::SwapReinterpretTexture(); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); + FramebufferManager::SwapReinterpretTexture(); + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); } void Renderer::SetBlendMode(bool forceUpdate) { - // Our render target always uses an alpha channel, so we need to override the blend functions to assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel - // Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel is assumed to always be 1. - bool target_has_alpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; - const D3D11_BLEND d3dSrcFactors[8] = - { - D3D11_BLEND_ZERO, - D3D11_BLEND_ONE, - D3D11_BLEND_DEST_COLOR, - D3D11_BLEND_INV_DEST_COLOR, - D3D11_BLEND_SRC_ALPHA, - D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled! - (target_has_alpha) ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_ONE, - (target_has_alpha) ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_ZERO - }; - const D3D11_BLEND d3dDestFactors[8] = - { - D3D11_BLEND_ZERO, - D3D11_BLEND_ONE, - D3D11_BLEND_SRC_COLOR, - D3D11_BLEND_INV_SRC_COLOR, - D3D11_BLEND_SRC_ALPHA, - D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled! - (target_has_alpha) ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_ONE, - (target_has_alpha) ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_ZERO - }; + // Our render target always uses an alpha channel, so we need to override the blend functions to + // assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel + // Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel + // is assumed to always be 1. + bool target_has_alpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; + const D3D11_BLEND d3dSrcFactors[8] = { + D3D11_BLEND_ZERO, + D3D11_BLEND_ONE, + D3D11_BLEND_DEST_COLOR, + D3D11_BLEND_INV_DEST_COLOR, + D3D11_BLEND_SRC_ALPHA, + D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled! + (target_has_alpha) ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_ONE, + (target_has_alpha) ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_ZERO}; + const D3D11_BLEND d3dDestFactors[8] = { + D3D11_BLEND_ZERO, + D3D11_BLEND_ONE, + D3D11_BLEND_SRC_COLOR, + D3D11_BLEND_INV_SRC_COLOR, + D3D11_BLEND_SRC_ALPHA, + D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled! + (target_has_alpha) ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_ONE, + (target_has_alpha) ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_ZERO}; - if (bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable && !forceUpdate) - return; + if (bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable && !forceUpdate) + return; - if (bpmem.blendmode.subtract) - { - gx_state.blend.blend_enable = true; - gx_state.blend.blend_op = D3D11_BLEND_OP_REV_SUBTRACT; - gx_state.blend.src_blend = D3D11_BLEND_ONE; - gx_state.blend.dst_blend = D3D11_BLEND_ONE; - } - else - { - gx_state.blend.blend_enable = (u32)bpmem.blendmode.blendenable; - if (bpmem.blendmode.blendenable) - { - gx_state.blend.blend_op = D3D11_BLEND_OP_ADD; - gx_state.blend.src_blend = d3dSrcFactors[bpmem.blendmode.srcfactor]; - gx_state.blend.dst_blend = d3dDestFactors[bpmem.blendmode.dstfactor]; - } - } + if (bpmem.blendmode.subtract) + { + gx_state.blend.blend_enable = true; + gx_state.blend.blend_op = D3D11_BLEND_OP_REV_SUBTRACT; + gx_state.blend.src_blend = D3D11_BLEND_ONE; + gx_state.blend.dst_blend = D3D11_BLEND_ONE; + } + else + { + gx_state.blend.blend_enable = (u32)bpmem.blendmode.blendenable; + if (bpmem.blendmode.blendenable) + { + gx_state.blend.blend_op = D3D11_BLEND_OP_ADD; + gx_state.blend.src_blend = d3dSrcFactors[bpmem.blendmode.srcfactor]; + gx_state.blend.dst_blend = d3dDestFactors[bpmem.blendmode.dstfactor]; + } + } } -bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle& rc) +bool Renderer::SaveScreenshot(const std::string& filename, const TargetRectangle& rc) { - if (!s_screenshot_texture) - CreateScreenshotTexture(); + if (!s_screenshot_texture) + CreateScreenshotTexture(); - // copy back buffer to system memory - D3D11_BOX source_box = GetScreenshotSourceBox(rc); - D3D::context->CopySubresourceRegion(s_screenshot_texture, 0, 0, 0, 0, (ID3D11Resource*)D3D::GetBackBuffer()->GetTex(), 0, &source_box); + // copy back buffer to system memory + D3D11_BOX source_box = GetScreenshotSourceBox(rc); + D3D::context->CopySubresourceRegion(s_screenshot_texture, 0, 0, 0, 0, + (ID3D11Resource*)D3D::GetBackBuffer()->GetTex(), 0, + &source_box); - D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ_WRITE, 0, &map); + D3D11_MAPPED_SUBRESOURCE map; + D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ_WRITE, 0, &map); - bool saved_png = TextureToPng((u8*)map.pData, map.RowPitch, filename, source_box.right - source_box.left, source_box.bottom - source_box.top, false); + bool saved_png = + TextureToPng((u8*)map.pData, map.RowPitch, filename, source_box.right - source_box.left, + source_box.bottom - source_box.top, false); - D3D::context->Unmap(s_screenshot_texture, 0); + D3D::context->Unmap(s_screenshot_texture, 0); + if (saved_png) + { + OSD::AddMessage( + StringFromFormat("Saved %i x %i %s", rc.GetWidth(), rc.GetHeight(), filename.c_str())); + } + else + { + OSD::AddMessage(StringFromFormat("Error saving %s", filename.c_str())); + } - if (saved_png) - { - OSD::AddMessage(StringFromFormat("Saved %i x %i %s", rc.GetWidth(), - rc.GetHeight(), filename.c_str())); - } - else - { - OSD::AddMessage(StringFromFormat("Error saving %s", filename.c_str())); - } - - return saved_png; + return saved_png; } void formatBufferDump(const u8* in, u8* out, int w, int h, int p) { - for (int y = 0; y < h; ++y) - { - auto line = (in + (h - y - 1) * p); - for (int x = 0; x < w; ++x) - { - out[0] = line[2]; - out[1] = line[1]; - out[2] = line[0]; - out += 3; - line += 4; - } - } + for (int y = 0; y < h; ++y) + { + auto line = (in + (h - y - 1) * p); + for (int x = 0; x < w; ++x) + { + out[0] = line[2]; + out[1] = line[1]; + out[2] = line[0]; + out += 3; + line += 4; + } + } } // This function has the final picture. We adjust the aspect ratio here. -void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma) +void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, + const EFBRectangle& rc, float Gamma) { - if (Fifo::WillSkipCurrentFrame() || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight) - { - if (SConfig::GetInstance().m_DumpFrames && !frame_data.empty()) - AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight); + if (Fifo::WillSkipCurrentFrame() || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || + !fbWidth || !fbHeight) + { + if (SConfig::GetInstance().m_DumpFrames && !frame_data.empty()) + AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight); - Core::Callback_VideoCopiedToXFB(false); - return; - } + Core::Callback_VideoCopiedToXFB(false); + return; + } - u32 xfbCount = 0; - const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbStride, fbHeight, &xfbCount); - if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) - { - if (SConfig::GetInstance().m_DumpFrames && !frame_data.empty()) - AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight); + u32 xfbCount = 0; + const XFBSourceBase* const* xfbSourceList = + FramebufferManager::GetXFBSource(xfbAddr, fbStride, fbHeight, &xfbCount); + if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) + { + if (SConfig::GetInstance().m_DumpFrames && !frame_data.empty()) + AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight); - Core::Callback_VideoCopiedToXFB(false); - return; - } + Core::Callback_VideoCopiedToXFB(false); + return; + } - ResetAPIState(); + ResetAPIState(); - // Prepare to copy the XFBs to our backbuffer - UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); - TargetRectangle targetRc = GetTargetRectangle(); + // Prepare to copy the XFBs to our backbuffer + UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); + TargetRectangle targetRc = GetTargetRectangle(); - D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr); + D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr); - float ClearColor[4] = { 0.f, 0.f, 0.f, 1.f }; - D3D::context->ClearRenderTargetView(D3D::GetBackBuffer()->GetRTV(), ClearColor); + float ClearColor[4] = {0.f, 0.f, 0.f, 1.f}; + D3D::context->ClearRenderTargetView(D3D::GetBackBuffer()->GetRTV(), ClearColor); - // activate linear filtering for the buffer copies - D3D::SetLinearCopySampler(); + // activate linear filtering for the buffer copies + D3D::SetLinearCopySampler(); - if (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB) - { - // TODO: Television should be used to render Virtual XFB mode as well. - D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top, (float)targetRc.GetWidth(), (float)targetRc.GetHeight()); - D3D::context->RSSetViewports(1, &vp); + if (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB) + { + // TODO: Television should be used to render Virtual XFB mode as well. + D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top, + (float)targetRc.GetWidth(), (float)targetRc.GetHeight()); + D3D::context->RSSetViewports(1, &vp); - s_television.Submit(xfbAddr, fbStride, fbWidth, fbHeight); - s_television.Render(); - } - else if (g_ActiveConfig.bUseXFB) - { - const XFBSource* xfbSource; + s_television.Submit(xfbAddr, fbStride, fbWidth, fbHeight); + s_television.Render(); + } + else if (g_ActiveConfig.bUseXFB) + { + const XFBSource* xfbSource; - // draw each xfb source - for (u32 i = 0; i < xfbCount; ++i) - { - xfbSource = (const XFBSource*)xfbSourceList[i]; + // draw each xfb source + for (u32 i = 0; i < xfbCount; ++i) + { + xfbSource = (const XFBSource*)xfbSourceList[i]; - TargetRectangle drawRc; + TargetRectangle drawRc; - // use virtual xfb with offset - int xfbHeight = xfbSource->srcHeight; - int xfbWidth = xfbSource->srcWidth; - int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbStride * 2); + // use virtual xfb with offset + int xfbHeight = xfbSource->srcHeight; + int xfbWidth = xfbSource->srcWidth; + int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbStride * 2); - drawRc.top = targetRc.top + hOffset * targetRc.GetHeight() / (s32)fbHeight; - drawRc.bottom = targetRc.top + (hOffset + xfbHeight) * targetRc.GetHeight() / (s32)fbHeight; - drawRc.left = targetRc.left + (targetRc.GetWidth() - xfbWidth * targetRc.GetWidth() / (s32)fbStride) / 2; - drawRc.right = targetRc.left + (targetRc.GetWidth() + xfbWidth * targetRc.GetWidth() / (s32)fbStride) / 2; + drawRc.top = targetRc.top + hOffset * targetRc.GetHeight() / (s32)fbHeight; + drawRc.bottom = targetRc.top + (hOffset + xfbHeight) * targetRc.GetHeight() / (s32)fbHeight; + drawRc.left = targetRc.left + + (targetRc.GetWidth() - xfbWidth * targetRc.GetWidth() / (s32)fbStride) / 2; + drawRc.right = targetRc.left + + (targetRc.GetWidth() + xfbWidth * targetRc.GetWidth() / (s32)fbStride) / 2; - // The following code disables auto stretch. Kept for reference. - // scale draw area for a 1 to 1 pixel mapping with the draw target - //float vScale = (float)fbHeight / (float)s_backbuffer_height; - //float hScale = (float)fbWidth / (float)s_backbuffer_width; - //drawRc.top *= vScale; - //drawRc.bottom *= vScale; - //drawRc.left *= hScale; - //drawRc.right *= hScale; + // The following code disables auto stretch. Kept for reference. + // scale draw area for a 1 to 1 pixel mapping with the draw target + // float vScale = (float)fbHeight / (float)s_backbuffer_height; + // float hScale = (float)fbWidth / (float)s_backbuffer_width; + // drawRc.top *= vScale; + // drawRc.bottom *= vScale; + // drawRc.left *= hScale; + // drawRc.right *= hScale; - TargetRectangle sourceRc; - sourceRc.left = xfbSource->sourceRc.left; - sourceRc.top = xfbSource->sourceRc.top; - sourceRc.right = xfbSource->sourceRc.right; - sourceRc.bottom = xfbSource->sourceRc.bottom; + TargetRectangle sourceRc; + sourceRc.left = xfbSource->sourceRc.left; + sourceRc.top = xfbSource->sourceRc.top; + sourceRc.right = xfbSource->sourceRc.right; + sourceRc.bottom = xfbSource->sourceRc.bottom; - sourceRc.right -= Renderer::EFBToScaledX(fbStride - fbWidth); + sourceRc.right -= Renderer::EFBToScaledX(fbStride - fbWidth); - BlitScreen(sourceRc, drawRc, xfbSource->tex, xfbSource->texWidth, xfbSource->texHeight, Gamma); - } - } - else - { - TargetRectangle sourceRc = Renderer::ConvertEFBRectangle(rc); + BlitScreen(sourceRc, drawRc, xfbSource->tex, xfbSource->texWidth, xfbSource->texHeight, + Gamma); + } + } + else + { + TargetRectangle sourceRc = Renderer::ConvertEFBRectangle(rc); - // TODO: Improve sampling algorithm for the pixel shader so that we can use the multisampled EFB texture as source - D3DTexture2D* read_texture = FramebufferManager::GetResolvedEFBColorTexture(); - BlitScreen(sourceRc, targetRc, read_texture, GetTargetWidth(), GetTargetHeight(), Gamma); - } + // TODO: Improve sampling algorithm for the pixel shader so that we can use the multisampled EFB + // texture as source + D3DTexture2D* read_texture = FramebufferManager::GetResolvedEFBColorTexture(); + BlitScreen(sourceRc, targetRc, read_texture, GetTargetWidth(), GetTargetHeight(), Gamma); + } - // done with drawing the game stuff, good moment to save a screenshot - if (s_bScreenshot) - { - std::lock_guard guard(s_criticalScreenshot); + // done with drawing the game stuff, good moment to save a screenshot + if (s_bScreenshot) + { + std::lock_guard guard(s_criticalScreenshot); - SaveScreenshot(s_sScreenshotName, GetTargetRectangle()); - s_sScreenshotName.clear(); - s_bScreenshot = false; - s_screenshotCompleted.Set(); - } + SaveScreenshot(s_sScreenshotName, GetTargetRectangle()); + s_sScreenshotName.clear(); + s_bScreenshot = false; + s_screenshotCompleted.Set(); + } - // Dump frames - static int w = 0, h = 0; - if (SConfig::GetInstance().m_DumpFrames) - { - static int s_recordWidth; - static int s_recordHeight; + // Dump frames + static int w = 0, h = 0; + if (SConfig::GetInstance().m_DumpFrames) + { + static int s_recordWidth; + static int s_recordHeight; - if (!s_screenshot_texture) - CreateScreenshotTexture(); + if (!s_screenshot_texture) + CreateScreenshotTexture(); - D3D11_BOX source_box = GetScreenshotSourceBox(targetRc); - unsigned int source_width = source_box.right - source_box.left; - unsigned int source_height = source_box.bottom - source_box.top; - D3D::context->CopySubresourceRegion(s_screenshot_texture, 0, 0, 0, 0, (ID3D11Resource*)D3D::GetBackBuffer()->GetTex(), 0, &source_box); - if (!bLastFrameDumped) - { - s_recordWidth = source_width; - s_recordHeight = source_height; - bAVIDumping = AVIDump::Start(s_recordWidth, s_recordHeight, AVIDump::DumpFormat::FORMAT_BGR); - if (!bAVIDumping) - { - PanicAlert("Error dumping frames to AVI."); - } - else - { - std::string msg = StringFromFormat("Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)", - File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), s_recordWidth, s_recordHeight); + D3D11_BOX source_box = GetScreenshotSourceBox(targetRc); + unsigned int source_width = source_box.right - source_box.left; + unsigned int source_height = source_box.bottom - source_box.top; + D3D::context->CopySubresourceRegion(s_screenshot_texture, 0, 0, 0, 0, + (ID3D11Resource*)D3D::GetBackBuffer()->GetTex(), 0, + &source_box); + if (!bLastFrameDumped) + { + s_recordWidth = source_width; + s_recordHeight = source_height; + bAVIDumping = AVIDump::Start(s_recordWidth, s_recordHeight, AVIDump::DumpFormat::FORMAT_BGR); + if (!bAVIDumping) + { + PanicAlert("Error dumping frames to AVI."); + } + else + { + std::string msg = StringFromFormat("Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)", + File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), + s_recordWidth, s_recordHeight); - OSD::AddMessage(msg, 2000); - } - } - if (bAVIDumping) - { - D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ, 0, &map); + OSD::AddMessage(msg, 2000); + } + } + if (bAVIDumping) + { + D3D11_MAPPED_SUBRESOURCE map; + D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ, 0, &map); - if (frame_data.empty() || w != s_recordWidth || h != s_recordHeight) - { - frame_data.resize(3 * s_recordWidth * s_recordHeight); - w = s_recordWidth; - h = s_recordHeight; - } - formatBufferDump((u8*)map.pData, &frame_data[0], source_width, source_height, map.RowPitch); - FlipImageData(&frame_data[0], w, h); - AVIDump::AddFrame(&frame_data[0], source_width, source_height); - D3D::context->Unmap(s_screenshot_texture, 0); - } - bLastFrameDumped = true; - } - else - { - if (bLastFrameDumped && bAVIDumping) - { - std::vector().swap(frame_data); - w = h = 0; + if (frame_data.empty() || w != s_recordWidth || h != s_recordHeight) + { + frame_data.resize(3 * s_recordWidth * s_recordHeight); + w = s_recordWidth; + h = s_recordHeight; + } + formatBufferDump((u8*)map.pData, &frame_data[0], source_width, source_height, map.RowPitch); + FlipImageData(&frame_data[0], w, h); + AVIDump::AddFrame(&frame_data[0], source_width, source_height); + D3D::context->Unmap(s_screenshot_texture, 0); + } + bLastFrameDumped = true; + } + else + { + if (bLastFrameDumped && bAVIDumping) + { + std::vector().swap(frame_data); + w = h = 0; - AVIDump::Stop(); - bAVIDumping = false; - OSD::AddMessage("Stop dumping frames to AVI", 2000); - } - bLastFrameDumped = false; - } + AVIDump::Stop(); + bAVIDumping = false; + OSD::AddMessage("Stop dumping frames to AVI", 2000); + } + bLastFrameDumped = false; + } - // Reset viewport for drawing text - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetBackbufferWidth(), (float)GetBackbufferHeight()); - D3D::context->RSSetViewports(1, &vp); + // Reset viewport for drawing text + D3D11_VIEWPORT vp = + CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetBackbufferWidth(), (float)GetBackbufferHeight()); + D3D::context->RSSetViewports(1, &vp); - Renderer::DrawDebugText(); + Renderer::DrawDebugText(); - OSD::DrawMessages(); - D3D::EndFrame(); + OSD::DrawMessages(); + D3D::EndFrame(); - TextureCacheBase::Cleanup(frameCount); + TextureCacheBase::Cleanup(frameCount); - // Enable configuration changes - UpdateActiveConfig(); - TextureCacheBase::OnConfigChanged(g_ActiveConfig); + // Enable configuration changes + UpdateActiveConfig(); + TextureCacheBase::OnConfigChanged(g_ActiveConfig); - SetWindowSize(fbStride, fbHeight); + SetWindowSize(fbStride, fbHeight); - const bool windowResized = CheckForResize(); - const bool fullscreen = g_ActiveConfig.bFullscreen && !g_ActiveConfig.bBorderlessFullscreen && - !SConfig::GetInstance().bRenderToMain; + const bool windowResized = CheckForResize(); + const bool fullscreen = g_ActiveConfig.bFullscreen && !g_ActiveConfig.bBorderlessFullscreen && + !SConfig::GetInstance().bRenderToMain; - bool xfbchanged = s_last_xfb_mode != g_ActiveConfig.bUseRealXFB; + bool xfbchanged = s_last_xfb_mode != g_ActiveConfig.bUseRealXFB; - if (FramebufferManagerBase::LastXfbWidth() != fbStride || FramebufferManagerBase::LastXfbHeight() != fbHeight) - { - xfbchanged = true; - unsigned int xfb_w = (fbStride < 1 || fbStride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fbStride; - unsigned int xfb_h = (fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fbHeight; - FramebufferManagerBase::SetLastXfbWidth(xfb_w); - FramebufferManagerBase::SetLastXfbHeight(xfb_h); - } + if (FramebufferManagerBase::LastXfbWidth() != fbStride || + FramebufferManagerBase::LastXfbHeight() != fbHeight) + { + xfbchanged = true; + unsigned int xfb_w = (fbStride < 1 || fbStride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fbStride; + unsigned int xfb_h = (fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fbHeight; + FramebufferManagerBase::SetLastXfbWidth(xfb_w); + FramebufferManagerBase::SetLastXfbHeight(xfb_h); + } - // Flip/present backbuffer to frontbuffer here - D3D::Present(); + // Flip/present backbuffer to frontbuffer here + D3D::Present(); - // Check exclusive fullscreen state - bool exclusive_mode, fullscreen_changed = false; - if (SUCCEEDED(D3D::GetFullscreenState(&exclusive_mode))) - { - if (fullscreen && !exclusive_mode) - { - if (g_Config.bExclusiveMode) - OSD::AddMessage("Lost exclusive fullscreen."); + // Check exclusive fullscreen state + bool exclusive_mode, fullscreen_changed = false; + if (SUCCEEDED(D3D::GetFullscreenState(&exclusive_mode))) + { + if (fullscreen && !exclusive_mode) + { + if (g_Config.bExclusiveMode) + OSD::AddMessage("Lost exclusive fullscreen."); - // Exclusive fullscreen is enabled in the configuration, but we're - // not in exclusive mode. Either exclusive fullscreen was turned on - // or the render frame lost focus. When the render frame is in focus - // we can apply exclusive mode. - fullscreen_changed = Host_RendererHasFocus(); + // Exclusive fullscreen is enabled in the configuration, but we're + // not in exclusive mode. Either exclusive fullscreen was turned on + // or the render frame lost focus. When the render frame is in focus + // we can apply exclusive mode. + fullscreen_changed = Host_RendererHasFocus(); - g_Config.bExclusiveMode = false; - } - else if (!fullscreen && exclusive_mode) - { - // Exclusive fullscreen is disabled, but we're still in exclusive mode. - fullscreen_changed = true; - } - } + g_Config.bExclusiveMode = false; + } + else if (!fullscreen && exclusive_mode) + { + // Exclusive fullscreen is disabled, but we're still in exclusive mode. + fullscreen_changed = true; + } + } - // Resize the back buffers NOW to avoid flickering - if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height) || - xfbchanged || - windowResized || - fullscreen_changed || - s_last_efb_scale != g_ActiveConfig.iEFBScale || - s_last_multisamples != g_ActiveConfig.iMultisamples || - s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0)) - { - s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; - s_last_multisamples = g_ActiveConfig.iMultisamples; - PixelShaderCache::InvalidateMSAAShaders(); + // Resize the back buffers NOW to avoid flickering + if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height) || xfbchanged || windowResized || + fullscreen_changed || s_last_efb_scale != g_ActiveConfig.iEFBScale || + s_last_multisamples != g_ActiveConfig.iMultisamples || + s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0)) + { + s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; + s_last_multisamples = g_ActiveConfig.iMultisamples; + PixelShaderCache::InvalidateMSAAShaders(); - if (windowResized || fullscreen_changed) - { - // Apply fullscreen state - if (fullscreen_changed) - { - g_Config.bExclusiveMode = fullscreen; + if (windowResized || fullscreen_changed) + { + // Apply fullscreen state + if (fullscreen_changed) + { + g_Config.bExclusiveMode = fullscreen; - if (fullscreen) - OSD::AddMessage("Entered exclusive fullscreen."); + if (fullscreen) + OSD::AddMessage("Entered exclusive fullscreen."); - D3D::SetFullscreenState(fullscreen); + D3D::SetFullscreenState(fullscreen); - // If fullscreen is disabled we can safely notify the UI to exit fullscreen. - if (!g_ActiveConfig.bFullscreen) - Host_RequestFullscreen(false); - } + // If fullscreen is disabled we can safely notify the UI to exit fullscreen. + if (!g_ActiveConfig.bFullscreen) + Host_RequestFullscreen(false); + } - // TODO: Aren't we still holding a reference to the back buffer right now? - D3D::Reset(); - SAFE_RELEASE(s_screenshot_texture); - SAFE_RELEASE(s_3d_vision_texture); - s_backbuffer_width = D3D::GetBackBufferWidth(); - s_backbuffer_height = D3D::GetBackBufferHeight(); - } + // TODO: Aren't we still holding a reference to the back buffer right now? + D3D::Reset(); + SAFE_RELEASE(s_screenshot_texture); + SAFE_RELEASE(s_3d_vision_texture); + s_backbuffer_width = D3D::GetBackBufferWidth(); + s_backbuffer_height = D3D::GetBackBufferHeight(); + } - UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); + UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); - s_last_efb_scale = g_ActiveConfig.iEFBScale; - s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; + s_last_efb_scale = g_ActiveConfig.iEFBScale; + s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; - PixelShaderManager::SetEfbScaleChanged(); + PixelShaderManager::SetEfbScaleChanged(); - D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr); + D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr); - g_framebuffer_manager.reset(); - g_framebuffer_manager = std::make_unique(); - float clear_col[4] = { 0.f, 0.f, 0.f, 1.f }; - D3D::context->ClearRenderTargetView(FramebufferManager::GetEFBColorTexture()->GetRTV(), clear_col); - D3D::context->ClearDepthStencilView(FramebufferManager::GetEFBDepthTexture()->GetDSV(), D3D11_CLEAR_DEPTH, 0.f, 0); - } + g_framebuffer_manager.reset(); + g_framebuffer_manager = std::make_unique(); + float clear_col[4] = {0.f, 0.f, 0.f, 1.f}; + D3D::context->ClearRenderTargetView(FramebufferManager::GetEFBColorTexture()->GetRTV(), + clear_col); + D3D::context->ClearDepthStencilView(FramebufferManager::GetEFBDepthTexture()->GetDSV(), + D3D11_CLEAR_DEPTH, 0.f, 0); + } - // begin next frame - RestoreAPIState(); - D3D::BeginFrame(); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); - SetViewport(); + // begin next frame + RestoreAPIState(); + D3D::BeginFrame(); + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); + SetViewport(); } // ALWAYS call RestoreAPIState for each ResetAPIState call you're doing void Renderer::ResetAPIState() { - D3D::stateman->PushBlendState(resetblendstate); - D3D::stateman->PushDepthState(resetdepthstate); - D3D::stateman->PushRasterizerState(resetraststate); + D3D::stateman->PushBlendState(resetblendstate); + D3D::stateman->PushDepthState(resetdepthstate); + D3D::stateman->PushRasterizerState(resetraststate); } void Renderer::RestoreAPIState() { - // Gets us back into a more game-like state. - D3D::stateman->PopBlendState(); - D3D::stateman->PopDepthState(); - D3D::stateman->PopRasterizerState(); - SetViewport(); - BPFunctions::SetScissor(); + // Gets us back into a more game-like state. + D3D::stateman->PopBlendState(); + D3D::stateman->PopDepthState(); + D3D::stateman->PopRasterizerState(); + SetViewport(); + BPFunctions::SetScissor(); } void Renderer::ApplyState(bool bUseDstAlpha) { - gx_state.blend.use_dst_alpha = bUseDstAlpha; - D3D::stateman->PushBlendState(gx_state_cache.Get(gx_state.blend)); - D3D::stateman->PushDepthState(gx_state_cache.Get(gx_state.zmode)); - D3D::stateman->PushRasterizerState(gx_state_cache.Get(gx_state.raster)); + gx_state.blend.use_dst_alpha = bUseDstAlpha; + D3D::stateman->PushBlendState(gx_state_cache.Get(gx_state.blend)); + D3D::stateman->PushDepthState(gx_state_cache.Get(gx_state.zmode)); + D3D::stateman->PushRasterizerState(gx_state_cache.Get(gx_state.raster)); - for (unsigned int stage = 0; stage < 8; stage++) - { - // TODO: cache SamplerState directly, not d3d object - gx_state.sampler[stage].max_anisotropy = UINT64_C(1) << g_ActiveConfig.iMaxAnisotropy; - D3D::stateman->SetSampler(stage, gx_state_cache.Get(gx_state.sampler[stage])); - } + for (unsigned int stage = 0; stage < 8; stage++) + { + // TODO: cache SamplerState directly, not d3d object + gx_state.sampler[stage].max_anisotropy = UINT64_C(1) << g_ActiveConfig.iMaxAnisotropy; + D3D::stateman->SetSampler(stage, gx_state_cache.Get(gx_state.sampler[stage])); + } - if (bUseDstAlpha) - { - // restore actual state - SetBlendMode(false); - SetLogicOpMode(); - } + if (bUseDstAlpha) + { + // restore actual state + SetBlendMode(false); + SetLogicOpMode(); + } - ID3D11Buffer* vertexConstants = VertexShaderCache::GetConstantBuffer(); + ID3D11Buffer* vertexConstants = VertexShaderCache::GetConstantBuffer(); - D3D::stateman->SetPixelConstants(PixelShaderCache::GetConstantBuffer(), g_ActiveConfig.bEnablePixelLighting ? vertexConstants : nullptr); - D3D::stateman->SetVertexConstants(vertexConstants); - D3D::stateman->SetGeometryConstants(GeometryShaderCache::GetConstantBuffer()); + D3D::stateman->SetPixelConstants(PixelShaderCache::GetConstantBuffer(), + g_ActiveConfig.bEnablePixelLighting ? vertexConstants : nullptr); + D3D::stateman->SetVertexConstants(vertexConstants); + D3D::stateman->SetGeometryConstants(GeometryShaderCache::GetConstantBuffer()); - D3D::stateman->SetPixelShader(PixelShaderCache::GetActiveShader()); - D3D::stateman->SetVertexShader(VertexShaderCache::GetActiveShader()); - D3D::stateman->SetGeometryShader(GeometryShaderCache::GetActiveShader()); + D3D::stateman->SetPixelShader(PixelShaderCache::GetActiveShader()); + D3D::stateman->SetVertexShader(VertexShaderCache::GetActiveShader()); + D3D::stateman->SetGeometryShader(GeometryShaderCache::GetActiveShader()); } void Renderer::RestoreState() { - D3D::stateman->PopBlendState(); - D3D::stateman->PopDepthState(); - D3D::stateman->PopRasterizerState(); + D3D::stateman->PopBlendState(); + D3D::stateman->PopDepthState(); + D3D::stateman->PopRasterizerState(); } void Renderer::ApplyCullDisable() { - RasterizerState rast = gx_state.raster; - rast.cull_mode = D3D11_CULL_NONE; + RasterizerState rast = gx_state.raster; + rast.cull_mode = D3D11_CULL_NONE; - ID3D11RasterizerState* raststate = gx_state_cache.Get(rast); - D3D::stateman->PushRasterizerState(raststate); + ID3D11RasterizerState* raststate = gx_state_cache.Get(rast); + D3D::stateman->PushRasterizerState(raststate); } void Renderer::RestoreCull() { - D3D::stateman->PopRasterizerState(); + D3D::stateman->PopRasterizerState(); } void Renderer::SetGenerationMode() { - const D3D11_CULL_MODE d3dCullModes[4] = - { - D3D11_CULL_NONE, - D3D11_CULL_BACK, - D3D11_CULL_FRONT, - D3D11_CULL_BACK - }; + const D3D11_CULL_MODE d3dCullModes[4] = {D3D11_CULL_NONE, D3D11_CULL_BACK, D3D11_CULL_FRONT, + D3D11_CULL_BACK}; - // rastdc.FrontCounterClockwise must be false for this to work - // TODO: GX_CULL_ALL not supported, yet! - gx_state.raster.cull_mode = d3dCullModes[bpmem.genMode.cullmode]; + // rastdc.FrontCounterClockwise must be false for this to work + // TODO: GX_CULL_ALL not supported, yet! + gx_state.raster.cull_mode = d3dCullModes[bpmem.genMode.cullmode]; } void Renderer::SetDepthMode() { - gx_state.zmode.hex = bpmem.zmode.hex; + gx_state.zmode.hex = bpmem.zmode.hex; } void Renderer::SetLogicOpMode() { - // D3D11 doesn't support logic blending, so this is a huge hack - // TODO: Make use of D3D11.1's logic blending support + // D3D11 doesn't support logic blending, so this is a huge hack + // TODO: Make use of D3D11.1's logic blending support - // 0 0x00 - // 1 Source & destination - // 2 Source & ~destination - // 3 Source - // 4 ~Source & destination - // 5 Destination - // 6 Source ^ destination = Source & ~destination | ~Source & destination - // 7 Source | destination - // 8 ~(Source | destination) - // 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination - // 10 ~Destination - // 11 Source | ~destination - // 12 ~Source - // 13 ~Source | destination - // 14 ~(Source & destination) - // 15 0xff - const D3D11_BLEND_OP d3dLogicOps[16] = - { - D3D11_BLEND_OP_ADD,//0 - D3D11_BLEND_OP_ADD,//1 - D3D11_BLEND_OP_SUBTRACT,//2 - D3D11_BLEND_OP_ADD,//3 - D3D11_BLEND_OP_REV_SUBTRACT,//4 - D3D11_BLEND_OP_ADD,//5 - D3D11_BLEND_OP_MAX,//6 - D3D11_BLEND_OP_ADD,//7 - D3D11_BLEND_OP_MAX,//8 - D3D11_BLEND_OP_MAX,//9 - D3D11_BLEND_OP_ADD,//10 - D3D11_BLEND_OP_ADD,//11 - D3D11_BLEND_OP_ADD,//12 - D3D11_BLEND_OP_ADD,//13 - D3D11_BLEND_OP_ADD,//14 - D3D11_BLEND_OP_ADD//15 - }; - const D3D11_BLEND d3dLogicOpSrcFactors[16] = - { - D3D11_BLEND_ZERO,//0 - D3D11_BLEND_DEST_COLOR,//1 - D3D11_BLEND_ONE,//2 - D3D11_BLEND_ONE,//3 - D3D11_BLEND_DEST_COLOR,//4 - D3D11_BLEND_ZERO,//5 - D3D11_BLEND_INV_DEST_COLOR,//6 - D3D11_BLEND_INV_DEST_COLOR,//7 - D3D11_BLEND_INV_SRC_COLOR,//8 - D3D11_BLEND_INV_SRC_COLOR,//9 - D3D11_BLEND_INV_DEST_COLOR,//10 - D3D11_BLEND_ONE,//11 - D3D11_BLEND_INV_SRC_COLOR,//12 - D3D11_BLEND_INV_SRC_COLOR,//13 - D3D11_BLEND_INV_DEST_COLOR,//14 - D3D11_BLEND_ONE//15 - }; - const D3D11_BLEND d3dLogicOpDestFactors[16] = - { - D3D11_BLEND_ZERO,//0 - D3D11_BLEND_ZERO,//1 - D3D11_BLEND_INV_SRC_COLOR,//2 - D3D11_BLEND_ZERO,//3 - D3D11_BLEND_ONE,//4 - D3D11_BLEND_ONE,//5 - D3D11_BLEND_INV_SRC_COLOR,//6 - D3D11_BLEND_ONE,//7 - D3D11_BLEND_INV_DEST_COLOR,//8 - D3D11_BLEND_SRC_COLOR,//9 - D3D11_BLEND_INV_DEST_COLOR,//10 - D3D11_BLEND_INV_DEST_COLOR,//11 - D3D11_BLEND_INV_SRC_COLOR,//12 - D3D11_BLEND_ONE,//13 - D3D11_BLEND_INV_SRC_COLOR,//14 - D3D11_BLEND_ONE//15 - }; + // 0 0x00 + // 1 Source & destination + // 2 Source & ~destination + // 3 Source + // 4 ~Source & destination + // 5 Destination + // 6 Source ^ destination = Source & ~destination | ~Source & destination + // 7 Source | destination + // 8 ~(Source | destination) + // 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination + // 10 ~Destination + // 11 Source | ~destination + // 12 ~Source + // 13 ~Source | destination + // 14 ~(Source & destination) + // 15 0xff + const D3D11_BLEND_OP d3dLogicOps[16] = { + D3D11_BLEND_OP_ADD, // 0 + D3D11_BLEND_OP_ADD, // 1 + D3D11_BLEND_OP_SUBTRACT, // 2 + D3D11_BLEND_OP_ADD, // 3 + D3D11_BLEND_OP_REV_SUBTRACT, // 4 + D3D11_BLEND_OP_ADD, // 5 + D3D11_BLEND_OP_MAX, // 6 + D3D11_BLEND_OP_ADD, // 7 + D3D11_BLEND_OP_MAX, // 8 + D3D11_BLEND_OP_MAX, // 9 + D3D11_BLEND_OP_ADD, // 10 + D3D11_BLEND_OP_ADD, // 11 + D3D11_BLEND_OP_ADD, // 12 + D3D11_BLEND_OP_ADD, // 13 + D3D11_BLEND_OP_ADD, // 14 + D3D11_BLEND_OP_ADD // 15 + }; + const D3D11_BLEND d3dLogicOpSrcFactors[16] = { + D3D11_BLEND_ZERO, // 0 + D3D11_BLEND_DEST_COLOR, // 1 + D3D11_BLEND_ONE, // 2 + D3D11_BLEND_ONE, // 3 + D3D11_BLEND_DEST_COLOR, // 4 + D3D11_BLEND_ZERO, // 5 + D3D11_BLEND_INV_DEST_COLOR, // 6 + D3D11_BLEND_INV_DEST_COLOR, // 7 + D3D11_BLEND_INV_SRC_COLOR, // 8 + D3D11_BLEND_INV_SRC_COLOR, // 9 + D3D11_BLEND_INV_DEST_COLOR, // 10 + D3D11_BLEND_ONE, // 11 + D3D11_BLEND_INV_SRC_COLOR, // 12 + D3D11_BLEND_INV_SRC_COLOR, // 13 + D3D11_BLEND_INV_DEST_COLOR, // 14 + D3D11_BLEND_ONE // 15 + }; + const D3D11_BLEND d3dLogicOpDestFactors[16] = { + D3D11_BLEND_ZERO, // 0 + D3D11_BLEND_ZERO, // 1 + D3D11_BLEND_INV_SRC_COLOR, // 2 + D3D11_BLEND_ZERO, // 3 + D3D11_BLEND_ONE, // 4 + D3D11_BLEND_ONE, // 5 + D3D11_BLEND_INV_SRC_COLOR, // 6 + D3D11_BLEND_ONE, // 7 + D3D11_BLEND_INV_DEST_COLOR, // 8 + D3D11_BLEND_SRC_COLOR, // 9 + D3D11_BLEND_INV_DEST_COLOR, // 10 + D3D11_BLEND_INV_DEST_COLOR, // 11 + D3D11_BLEND_INV_SRC_COLOR, // 12 + D3D11_BLEND_ONE, // 13 + D3D11_BLEND_INV_SRC_COLOR, // 14 + D3D11_BLEND_ONE // 15 + }; - if (bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable) - { - gx_state.blend.blend_enable = true; - gx_state.blend.blend_op = d3dLogicOps[bpmem.blendmode.logicmode]; - gx_state.blend.src_blend = d3dLogicOpSrcFactors[bpmem.blendmode.logicmode]; - gx_state.blend.dst_blend = d3dLogicOpDestFactors[bpmem.blendmode.logicmode]; - } - else - { - SetBlendMode(true); - } + if (bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable) + { + gx_state.blend.blend_enable = true; + gx_state.blend.blend_op = d3dLogicOps[bpmem.blendmode.logicmode]; + gx_state.blend.src_blend = d3dLogicOpSrcFactors[bpmem.blendmode.logicmode]; + gx_state.blend.dst_blend = d3dLogicOpDestFactors[bpmem.blendmode.logicmode]; + } + else + { + SetBlendMode(true); + } } void Renderer::SetDitherMode() { - // TODO: Set dither mode to bpmem.blendmode.dither + // TODO: Set dither mode to bpmem.blendmode.dither } void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex) { - const FourTexUnits &tex = bpmem.tex[texindex]; - const TexMode0 &tm0 = tex.texMode0[stage]; - const TexMode1 &tm1 = tex.texMode1[stage]; + const FourTexUnits& tex = bpmem.tex[texindex]; + const TexMode0& tm0 = tex.texMode0[stage]; + const TexMode1& tm1 = tex.texMode1[stage]; - if (texindex) - stage += 4; + if (texindex) + stage += 4; - if (g_ActiveConfig.bForceFiltering) - { - // Only use mipmaps if the game says they are available. - gx_state.sampler[stage].min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4; - gx_state.sampler[stage].mag_filter = 1; // linear mag - } - else - { - gx_state.sampler[stage].min_filter = (u32)tm0.min_filter; - gx_state.sampler[stage].mag_filter = (u32)tm0.mag_filter; - } + if (g_ActiveConfig.bForceFiltering) + { + // Only use mipmaps if the game says they are available. + gx_state.sampler[stage].min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4; + gx_state.sampler[stage].mag_filter = 1; // linear mag + } + else + { + gx_state.sampler[stage].min_filter = (u32)tm0.min_filter; + gx_state.sampler[stage].mag_filter = (u32)tm0.mag_filter; + } - gx_state.sampler[stage].wrap_s = (u32)tm0.wrap_s; - gx_state.sampler[stage].wrap_t = (u32)tm0.wrap_t; - gx_state.sampler[stage].max_lod = (u32)tm1.max_lod; - gx_state.sampler[stage].min_lod = (u32)tm1.min_lod; - gx_state.sampler[stage].lod_bias = (s32)tm0.lod_bias; + gx_state.sampler[stage].wrap_s = (u32)tm0.wrap_s; + gx_state.sampler[stage].wrap_t = (u32)tm0.wrap_t; + gx_state.sampler[stage].max_lod = (u32)tm1.max_lod; + gx_state.sampler[stage].min_lod = (u32)tm1.min_lod; + gx_state.sampler[stage].lod_bias = (s32)tm0.lod_bias; - // custom textures may have higher resolution, so disable the max_lod - if (custom_tex) - { - gx_state.sampler[stage].max_lod = 255; - } + // custom textures may have higher resolution, so disable the max_lod + if (custom_tex) + { + gx_state.sampler[stage].max_lod = 255; + } } void Renderer::SetInterlacingMode() { - // TODO + // TODO } int Renderer::GetMaxTextureSize() { - return DX11::D3D::GetMaxTextureSize(); + return DX11::D3D::GetMaxTextureSize(); } u16 Renderer::BBoxRead(int index) { - // Here we get the min/max value of the truncated position of the upscaled framebuffer. - // So we have to correct them to the unscaled EFB sizes. - int value = BBox::Get(index); + // Here we get the min/max value of the truncated position of the upscaled framebuffer. + // So we have to correct them to the unscaled EFB sizes. + int value = BBox::Get(index); - if (index < 2) - { - // left/right - value = value * EFB_WIDTH / s_target_width; - } - else - { - // up/down - value = value * EFB_HEIGHT / s_target_height; - } - if (index & 1) - value++; // fix max values to describe the outer border + if (index < 2) + { + // left/right + value = value * EFB_WIDTH / s_target_width; + } + else + { + // up/down + value = value * EFB_HEIGHT / s_target_height; + } + if (index & 1) + value++; // fix max values to describe the outer border - return value; + return value; } void Renderer::BBoxWrite(int index, u16 _value) { - int value = _value; // u16 isn't enough to multiply by the efb width - if (index & 1) - value--; - if (index < 2) - { - value = value * s_target_width / EFB_WIDTH; - } - else - { - value = value * s_target_height / EFB_HEIGHT; - } + int value = _value; // u16 isn't enough to multiply by the efb width + if (index & 1) + value--; + if (index < 2) + { + value = value * s_target_width / EFB_WIDTH; + } + else + { + value = value * s_target_height / EFB_HEIGHT; + } - BBox::Set(index, value); + BBox::Set(index, value); } -void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, u32 src_width, u32 src_height, float Gamma) +void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, + u32 src_width, u32 src_height, float Gamma) { - if (g_ActiveConfig.iStereoMode == STEREO_SBS || g_ActiveConfig.iStereoMode == STEREO_TAB) - { - TargetRectangle leftRc, rightRc; - ConvertStereoRectangle(dst, leftRc, rightRc); + if (g_ActiveConfig.iStereoMode == STEREO_SBS || g_ActiveConfig.iStereoMode == STEREO_TAB) + { + TargetRectangle leftRc, rightRc; + ConvertStereoRectangle(dst, leftRc, rightRc); - D3D11_VIEWPORT leftVp = CD3D11_VIEWPORT((float)leftRc.left, (float)leftRc.top, (float)leftRc.GetWidth(), (float)leftRc.GetHeight()); - D3D11_VIEWPORT rightVp = CD3D11_VIEWPORT((float)rightRc.left, (float)rightRc.top, (float)rightRc.GetWidth(), (float)rightRc.GetHeight()); + D3D11_VIEWPORT leftVp = CD3D11_VIEWPORT((float)leftRc.left, (float)leftRc.top, + (float)leftRc.GetWidth(), (float)leftRc.GetHeight()); + D3D11_VIEWPORT rightVp = CD3D11_VIEWPORT((float)rightRc.left, (float)rightRc.top, + (float)rightRc.GetWidth(), (float)rightRc.GetHeight()); - D3D::context->RSSetViewports(1, &leftVp); - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 0); + D3D::context->RSSetViewports(1, &leftVp); + D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, + PixelShaderCache::GetColorCopyProgram(false), + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 0); - D3D::context->RSSetViewports(1, &rightVp); - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 1); - } - else if (g_ActiveConfig.iStereoMode == STEREO_3DVISION) - { - if (!s_3d_vision_texture) - Create3DVisionTexture(s_backbuffer_width, s_backbuffer_height); + D3D::context->RSSetViewports(1, &rightVp); + D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, + PixelShaderCache::GetColorCopyProgram(false), + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 1); + } + else if (g_ActiveConfig.iStereoMode == STEREO_3DVISION) + { + if (!s_3d_vision_texture) + Create3DVisionTexture(s_backbuffer_width, s_backbuffer_height); - D3D11_VIEWPORT leftVp = CD3D11_VIEWPORT((float)dst.left, (float)dst.top, (float)dst.GetWidth(), (float)dst.GetHeight()); - D3D11_VIEWPORT rightVp = CD3D11_VIEWPORT((float)(dst.left + s_backbuffer_width), (float)dst.top, (float)dst.GetWidth(), (float)dst.GetHeight()); + D3D11_VIEWPORT leftVp = CD3D11_VIEWPORT((float)dst.left, (float)dst.top, (float)dst.GetWidth(), + (float)dst.GetHeight()); + D3D11_VIEWPORT rightVp = CD3D11_VIEWPORT((float)(dst.left + s_backbuffer_width), (float)dst.top, + (float)dst.GetWidth(), (float)dst.GetHeight()); - // Render to staging texture which is double the width of the backbuffer - D3D::context->OMSetRenderTargets(1, &s_3d_vision_texture->GetRTV(), nullptr); + // Render to staging texture which is double the width of the backbuffer + D3D::context->OMSetRenderTargets(1, &s_3d_vision_texture->GetRTV(), nullptr); - D3D::context->RSSetViewports(1, &leftVp); - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 0); + D3D::context->RSSetViewports(1, &leftVp); + D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, + PixelShaderCache::GetColorCopyProgram(false), + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 0); - D3D::context->RSSetViewports(1, &rightVp); - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 1); + D3D::context->RSSetViewports(1, &rightVp); + D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, + PixelShaderCache::GetColorCopyProgram(false), + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 1); - // Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should - // recognize the signature and automatically include the right eye frame. - D3D11_BOX box = CD3D11_BOX(0, 0, 0, s_backbuffer_width, s_backbuffer_height, 1); - D3D::context->CopySubresourceRegion(D3D::GetBackBuffer()->GetTex(), 0, 0, 0, 0, s_3d_vision_texture->GetTex(), 0, &box); + // Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should + // recognize the signature and automatically include the right eye frame. + D3D11_BOX box = CD3D11_BOX(0, 0, 0, s_backbuffer_width, s_backbuffer_height, 1); + D3D::context->CopySubresourceRegion(D3D::GetBackBuffer()->GetTex(), 0, 0, 0, 0, + s_3d_vision_texture->GetTex(), 0, &box); - // Restore render target to backbuffer - D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr); - } - else - { - D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)dst.left, (float)dst.top, (float)dst.GetWidth(), (float)dst.GetHeight()); - D3D::context->RSSetViewports(1, &vp); - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, (g_Config.iStereoMode == STEREO_ANAGLYPH) ? PixelShaderCache::GetAnaglyphProgram() : PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma); - } + // Restore render target to backbuffer + D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr); + } + else + { + D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)dst.left, (float)dst.top, (float)dst.GetWidth(), + (float)dst.GetHeight()); + D3D::context->RSSetViewports(1, &vp); + D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, + (g_Config.iStereoMode == STEREO_ANAGLYPH) ? + PixelShaderCache::GetAnaglyphProgram() : + PixelShaderCache::GetColorCopyProgram(false), + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma); + } } } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/Render.h b/Source/Core/VideoBackends/D3D/Render.h index 8e25419a5a..4bde0f05fb 100644 --- a/Source/Core/VideoBackends/D3D/Render.h +++ b/Source/Core/VideoBackends/D3D/Render.h @@ -9,58 +9,59 @@ namespace DX11 { - class Renderer : public ::Renderer { public: - Renderer(void *&window_handle); - ~Renderer(); + Renderer(void*& window_handle); + ~Renderer(); - void SetColorMask() override; - void SetBlendMode(bool forceUpdate) override; - void SetScissorRect(const EFBRectangle& rc) override; - void SetGenerationMode() override; - void SetDepthMode() override; - void SetLogicOpMode() override; - void SetDitherMode() override; - void SetSamplerState(int stage, int texindex, bool custom_tex) override; - void SetInterlacingMode() override; - void SetViewport() override; + void SetColorMask() override; + void SetBlendMode(bool forceUpdate) override; + void SetScissorRect(const EFBRectangle& rc) override; + void SetGenerationMode() override; + void SetDepthMode() override; + void SetLogicOpMode() override; + void SetDitherMode() override; + void SetSamplerState(int stage, int texindex, bool custom_tex) override; + void SetInterlacingMode() override; + void SetViewport() override; - // TODO: Fix confusing names (see ResetAPIState and RestoreAPIState) - void ApplyState(bool bUseDstAlpha) override; - void RestoreState() override; + // TODO: Fix confusing names (see ResetAPIState and RestoreAPIState) + void ApplyState(bool bUseDstAlpha) override; + void RestoreState() override; - void ApplyCullDisable(); - void RestoreCull(); + void ApplyCullDisable(); + void RestoreCull(); - void RenderText(const std::string& text, int left, int top, u32 color) override; + void RenderText(const std::string& text, int left, int top, u32 color) override; - u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; - void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override; + u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; + void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override; - u16 BBoxRead(int index) override; - void BBoxWrite(int index, u16 value) override; + u16 BBoxRead(int index) override; + void BBoxWrite(int index, u16 value) override; - void ResetAPIState() override; - void RestoreAPIState() override; + void ResetAPIState() override; + void RestoreAPIState() override; - TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; + TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; - void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma) override; + void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, + float Gamma) override; - void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override; + void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, + u32 color, u32 z) override; - void ReinterpretPixelData(unsigned int convtype) override; + void ReinterpretPixelData(unsigned int convtype) override; - bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc) override; + bool SaveScreenshot(const std::string& filename, const TargetRectangle& rc) override; - static bool CheckForResize(); + static bool CheckForResize(); - int GetMaxTextureSize() override; + int GetMaxTextureSize() override; private: - void BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, u32 src_width, u32 src_height, float Gamma); + void BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, + u32 src_width, u32 src_height, float Gamma); }; - } diff --git a/Source/Core/VideoBackends/D3D/Television.cpp b/Source/Core/VideoBackends/D3D/Television.cpp index 334d1b7420..148aa2a696 100644 --- a/Source/Core/VideoBackends/D3D/Television.cpp +++ b/Source/Core/VideoBackends/D3D/Television.cpp @@ -15,157 +15,150 @@ namespace DX11 { - static const char YUYV_DECODER_PS[] = -"// dolphin-emu YUYV decoder pixel shader\n" + "// dolphin-emu YUYV decoder pixel shader\n" -"Texture2D Tex0 : register(t0);\n" -"sampler Samp0 : register(s0);\n" + "Texture2D Tex0 : register(t0);\n" + "sampler Samp0 : register(s0);\n" -"static const float3x3 YCBCR_TO_RGB = float3x3(\n" - "1.164, 0.000, 1.596,\n" - "1.164, -0.392, -0.813,\n" - "1.164, 2.017, 0.000\n" - ");\n" + "static const float3x3 YCBCR_TO_RGB = float3x3(\n" + "1.164, 0.000, 1.596,\n" + "1.164, -0.392, -0.813,\n" + "1.164, 2.017, 0.000\n" + ");\n" -"void main(out float4 ocol0 : SV_Target, in float4 pos : SV_Position, in float2 uv0 : TEXCOORD0)\n" -"{\n" - "float3 sample = Tex0.Sample(Samp0, uv0).rgb;\n" + "void main(out float4 ocol0 : SV_Target, in float4 pos : SV_Position, in float2 uv0 : " + "TEXCOORD0)\n" + "{\n" + "float3 sample = Tex0.Sample(Samp0, uv0).rgb;\n" - // GameCube/Wii XFB data is in YUYV format with ITU-R Rec. BT.601 color - // primaries, compressed to the range Y in 16..235, U and V in 16..240. - // We want to convert it to RGB format with sRGB color primaries, with - // range 0..255. + // GameCube/Wii XFB data is in YUYV format with ITU-R Rec. BT.601 color + // primaries, compressed to the range Y in 16..235, U and V in 16..240. + // We want to convert it to RGB format with sRGB color primaries, with + // range 0..255. - // Recover RGB components - "float3 yuv_601_sub = sample.grb - float3(16.0/255.0, 128.0/255.0, 128.0/255.0);\n" - "float3 rgb_601 = mul(YCBCR_TO_RGB, yuv_601_sub);\n" + // Recover RGB components + "float3 yuv_601_sub = sample.grb - float3(16.0/255.0, 128.0/255.0, 128.0/255.0);\n" + "float3 rgb_601 = mul(YCBCR_TO_RGB, yuv_601_sub);\n" - // If we were really obsessed with accuracy, we would correct for the - // differing color primaries between BT.601 and sRGB. However, this may not - // be worth the trouble because: - // - BT.601 defines two sets of primaries: one for NTSC and one for PAL. - // - sRGB's color primaries are actually an intermediate between BT.601's - // NTSC and PAL primaries. - // - If users even noticed any difference at all, they would be confused by - // the slightly-different colors in the NTSC and PAL versions of the same - // game. - // - Even the game designers probably don't pay close attention to this - // stuff. - // Still, instructions on how to do it can be found at - // + // If we were really obsessed with accuracy, we would correct for the + // differing color primaries between BT.601 and sRGB. However, this may not + // be worth the trouble because: + // - BT.601 defines two sets of primaries: one for NTSC and one for PAL. + // - sRGB's color primaries are actually an intermediate between BT.601's + // NTSC and PAL primaries. + // - If users even noticed any difference at all, they would be confused by + // the slightly-different colors in the NTSC and PAL versions of the same + // game. + // - Even the game designers probably don't pay close attention to this + // stuff. + // Still, instructions on how to do it can be found at + // - "ocol0 = float4(rgb_601, 1);\n" -"}\n" -; + "ocol0 = float4(rgb_601, 1);\n" + "}\n"; -Television::Television() - : m_yuyvTexture(nullptr), m_yuyvTextureSRV(nullptr), m_pShader(nullptr) -{ } +Television::Television() : m_yuyvTexture(nullptr), m_yuyvTextureSRV(nullptr), m_pShader(nullptr) +{ +} void Television::Init() { - HRESULT hr; + HRESULT hr; - // Create YUYV texture for real XFB mode + // Create YUYV texture for real XFB mode + // Initialize the texture with YCbCr black + // + // Some games use narrower XFB widths (Nintendo titles are fond of 608), + // so the sampler's BorderColor won't cover the right side + // (see sampler state below) + const unsigned int MAX_XFB_SIZE = 2 * (MAX_XFB_WIDTH)*MAX_XFB_HEIGHT; + std::vector fill(MAX_XFB_SIZE); + for (size_t i = 0; i < MAX_XFB_SIZE / sizeof(u32); ++i) + reinterpret_cast(fill.data())[i] = 0x80108010; + D3D11_SUBRESOURCE_DATA srd = {fill.data(), 2 * (MAX_XFB_WIDTH), 0}; - // Initialize the texture with YCbCr black - // - // Some games use narrower XFB widths (Nintendo titles are fond of 608), - // so the sampler's BorderColor won't cover the right side - // (see sampler state below) - const unsigned int MAX_XFB_SIZE = 2*(MAX_XFB_WIDTH) * MAX_XFB_HEIGHT; - std::vector fill(MAX_XFB_SIZE); - for (size_t i = 0; i < MAX_XFB_SIZE / sizeof(u32); ++i) - reinterpret_cast(fill.data())[i] = 0x80108010; - D3D11_SUBRESOURCE_DATA srd = { fill.data(), 2*(MAX_XFB_WIDTH), 0 }; + // This texture format is designed for YUYV data. + D3D11_TEXTURE2D_DESC t2dd = + CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_G8R8_G8B8_UNORM, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 1, 1); + hr = D3D::device->CreateTexture2D(&t2dd, &srd, &m_yuyvTexture); + CHECK(SUCCEEDED(hr), "create tv yuyv texture"); + D3D::SetDebugObjectName(m_yuyvTexture, "tv yuyv texture"); - // This texture format is designed for YUYV data. - D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC( - DXGI_FORMAT_G8R8_G8B8_UNORM, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 1, 1); - hr = D3D::device->CreateTexture2D(&t2dd, &srd, &m_yuyvTexture); - CHECK(SUCCEEDED(hr), "create tv yuyv texture"); - D3D::SetDebugObjectName(m_yuyvTexture, "tv yuyv texture"); + // Create shader resource view for YUYV texture - // Create shader resource view for YUYV texture + D3D11_SHADER_RESOURCE_VIEW_DESC srvd = CD3D11_SHADER_RESOURCE_VIEW_DESC( + m_yuyvTexture, D3D11_SRV_DIMENSION_TEXTURE2D, DXGI_FORMAT_G8R8_G8B8_UNORM); + hr = D3D::device->CreateShaderResourceView(m_yuyvTexture, &srvd, &m_yuyvTextureSRV); + CHECK(SUCCEEDED(hr), "create tv yuyv texture srv"); + D3D::SetDebugObjectName(m_yuyvTextureSRV, "tv yuyv texture srv"); - D3D11_SHADER_RESOURCE_VIEW_DESC srvd = CD3D11_SHADER_RESOURCE_VIEW_DESC( - m_yuyvTexture, D3D11_SRV_DIMENSION_TEXTURE2D, - DXGI_FORMAT_G8R8_G8B8_UNORM); - hr = D3D::device->CreateShaderResourceView(m_yuyvTexture, &srvd, &m_yuyvTextureSRV); - CHECK(SUCCEEDED(hr), "create tv yuyv texture srv"); - D3D::SetDebugObjectName(m_yuyvTextureSRV, "tv yuyv texture srv"); + // Create YUYV-decoding pixel shader - // Create YUYV-decoding pixel shader + m_pShader = D3D::CompileAndCreatePixelShader(YUYV_DECODER_PS); + CHECK(m_pShader != nullptr, "compile and create yuyv decoder pixel shader"); + D3D::SetDebugObjectName(m_pShader, "yuyv decoder pixel shader"); - m_pShader = D3D::CompileAndCreatePixelShader(YUYV_DECODER_PS); - CHECK(m_pShader != nullptr, "compile and create yuyv decoder pixel shader"); - D3D::SetDebugObjectName(m_pShader, "yuyv decoder pixel shader"); - - // Create sampler state and set border color - // - // The default sampler border color of { 0.f, 0.f, 0.f, 0.f } - // creates a green border around the image - see issue 6483 - // (remember, the XFB is being interpreted as YUYV, and 0,0,0,0 - // is actually two green pixels in YUYV - black should be 16,128,16,128, - // but we reverse the order to match DXGI_FORMAT_G8R8_G8B8_UNORM's ordering) - float border[4] = { 128.0f/255.0f, 16.0f/255.0f, 128.0f/255.0f, 16.0f/255.0f }; - D3D11_SAMPLER_DESC samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR, - D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, - 0.f, 1, D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f); - hr = D3D::device->CreateSamplerState(&samDesc, &m_samplerState); - CHECK(SUCCEEDED(hr), "create yuyv decoder sampler state"); - D3D::SetDebugObjectName(m_samplerState, "yuyv decoder sampler state"); + // Create sampler state and set border color + // + // The default sampler border color of { 0.f, 0.f, 0.f, 0.f } + // creates a green border around the image - see issue 6483 + // (remember, the XFB is being interpreted as YUYV, and 0,0,0,0 + // is actually two green pixels in YUYV - black should be 16,128,16,128, + // but we reverse the order to match DXGI_FORMAT_G8R8_G8B8_UNORM's ordering) + float border[4] = {128.0f / 255.0f, 16.0f / 255.0f, 128.0f / 255.0f, 16.0f / 255.0f}; + D3D11_SAMPLER_DESC samDesc = CD3D11_SAMPLER_DESC( + D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, + D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f); + hr = D3D::device->CreateSamplerState(&samDesc, &m_samplerState); + CHECK(SUCCEEDED(hr), "create yuyv decoder sampler state"); + D3D::SetDebugObjectName(m_samplerState, "yuyv decoder sampler state"); } void Television::Shutdown() { - SAFE_RELEASE(m_pShader); - SAFE_RELEASE(m_yuyvTextureSRV); - SAFE_RELEASE(m_yuyvTexture); - SAFE_RELEASE(m_samplerState); + SAFE_RELEASE(m_pShader); + SAFE_RELEASE(m_yuyvTextureSRV); + SAFE_RELEASE(m_yuyvTexture); + SAFE_RELEASE(m_samplerState); } void Television::Submit(u32 xfbAddr, u32 stride, u32 width, u32 height) { - m_curAddr = xfbAddr; - m_curWidth = width; - m_curHeight = height; + m_curAddr = xfbAddr; + m_curWidth = width; + m_curHeight = height; - // Load data from GameCube RAM to YUYV texture - u8* yuyvSrc = Memory::GetPointer(xfbAddr); - D3D11_BOX box = CD3D11_BOX(0, 0, 0, stride, height, 1); - D3D::context->UpdateSubresource(m_yuyvTexture, 0, &box, yuyvSrc, 2 * stride, 2 * stride * height); + // Load data from GameCube RAM to YUYV texture + u8* yuyvSrc = Memory::GetPointer(xfbAddr); + D3D11_BOX box = CD3D11_BOX(0, 0, 0, stride, height, 1); + D3D::context->UpdateSubresource(m_yuyvTexture, 0, &box, yuyvSrc, 2 * stride, 2 * stride * height); } void Television::Render() { - if (g_ActiveConfig.bUseRealXFB && g_ActiveConfig.bUseXFB) - { - // Use real XFB mode - // TODO: If this is the lower field, render at a vertical offset of 1 - // line down. We could even consider implementing a deinterlacing - // algorithm. + if (g_ActiveConfig.bUseRealXFB && g_ActiveConfig.bUseXFB) + { + // Use real XFB mode + // TODO: If this is the lower field, render at a vertical offset of 1 + // line down. We could even consider implementing a deinterlacing + // algorithm. - D3D11_RECT sourceRc = CD3D11_RECT(0, 0, int(m_curWidth), int(m_curHeight)); + D3D11_RECT sourceRc = CD3D11_RECT(0, 0, int(m_curWidth), int(m_curHeight)); - D3D::stateman->SetSampler(0, m_samplerState); + D3D::stateman->SetSampler(0, m_samplerState); - D3D::drawShadedTexQuad( - m_yuyvTextureSRV, &sourceRc, - MAX_XFB_WIDTH, MAX_XFB_HEIGHT, - m_pShader, - VertexShaderCache::GetSimpleVertexShader(), - VertexShaderCache::GetSimpleInputLayout()); - } - else if (g_ActiveConfig.bUseXFB) - { - // Use virtual XFB mode + D3D::drawShadedTexQuad(m_yuyvTextureSRV, &sourceRc, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, m_pShader, + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout()); + } + else if (g_ActiveConfig.bUseXFB) + { + // Use virtual XFB mode - // TODO: Eventually, Television should render the Virtual XFB mode - // display as well. - } + // TODO: Eventually, Television should render the Virtual XFB mode + // display as well. + } } - } diff --git a/Source/Core/VideoBackends/D3D/Television.h b/Source/Core/VideoBackends/D3D/Television.h index 688fbbeab0..5bb5ecb85a 100644 --- a/Source/Core/VideoBackends/D3D/Television.h +++ b/Source/Core/VideoBackends/D3D/Television.h @@ -13,39 +13,33 @@ struct ID3D11SamplerState; namespace DX11 { - class Television { - public: + Television(); - Television(); + void Init(); + void Shutdown(); - void Init(); - void Shutdown(); + // Submit video data to be drawn. This will change the current state of the + // TV. xfbAddr points to YUYV data stored in GameCube/Wii RAM, but the XFB + // may be virtualized when rendering so the RAM may not actually be read. + void Submit(u32 xfbAddr, u32 stride, u32 width, u32 height); - // Submit video data to be drawn. This will change the current state of the - // TV. xfbAddr points to YUYV data stored in GameCube/Wii RAM, but the XFB - // may be virtualized when rendering so the RAM may not actually be read. - void Submit(u32 xfbAddr, u32 stride, u32 width, u32 height); - - // Render the current state of the TV. - void Render(); + // Render the current state of the TV. + void Render(); private: + // Properties of last Submit call + u32 m_curAddr; + u32 m_curWidth; + u32 m_curHeight; - // Properties of last Submit call - u32 m_curAddr; - u32 m_curWidth; - u32 m_curHeight; - - // Used for real XFB mode - - ID3D11Texture2D* m_yuyvTexture; - ID3D11ShaderResourceView* m_yuyvTextureSRV; - ID3D11PixelShader* m_pShader; - ID3D11SamplerState* m_samplerState; + // Used for real XFB mode + ID3D11Texture2D* m_yuyvTexture; + ID3D11ShaderResourceView* m_yuyvTextureSRV; + ID3D11PixelShader* m_pShader; + ID3D11SamplerState* m_samplerState; }; - } diff --git a/Source/Core/VideoBackends/D3D/TextureCache.cpp b/Source/Core/VideoBackends/D3D/TextureCache.cpp index f30d0309ef..62fdbd23d7 100644 --- a/Source/Core/VideoBackends/D3D/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D/TextureCache.cpp @@ -10,8 +10,8 @@ #include "VideoBackends/D3D/D3DUtil.h" #include "VideoBackends/D3D/FramebufferManager.h" #include "VideoBackends/D3D/GeometryShaderCache.h" -#include "VideoBackends/D3D/PixelShaderCache.h" #include "VideoBackends/D3D/PSTextureEncoder.h" +#include "VideoBackends/D3D/PixelShaderCache.h" #include "VideoBackends/D3D/TextureCache.h" #include "VideoBackends/D3D/TextureEncoder.h" #include "VideoBackends/D3D/VertexShaderCache.h" @@ -22,249 +22,246 @@ namespace DX11 { - static std::unique_ptr g_encoder; const size_t MAX_COPY_BUFFERS = 32; -ID3D11Buffer* efbcopycbuf[MAX_COPY_BUFFERS] = { 0 }; +ID3D11Buffer* efbcopycbuf[MAX_COPY_BUFFERS] = {0}; TextureCache::TCacheEntry::~TCacheEntry() { - texture->Release(); + texture->Release(); } void TextureCache::TCacheEntry::Bind(unsigned int stage) { - D3D::stateman->SetTexture(stage, texture->GetSRV()); + D3D::stateman->SetTexture(stage, texture->GetSRV()); } bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int level) { - // TODO: Somehow implement this (D3DX11 doesn't support dumping individual LODs) - static bool warn_once = true; - if (level && warn_once) - { - WARN_LOG(VIDEO, "Dumping individual LOD not supported by D3D11 backend!"); - warn_once = false; - return false; - } + // TODO: Somehow implement this (D3DX11 doesn't support dumping individual LODs) + static bool warn_once = true; + if (level && warn_once) + { + WARN_LOG(VIDEO, "Dumping individual LOD not supported by D3D11 backend!"); + warn_once = false; + return false; + } - ID3D11Texture2D* pNewTexture = nullptr; - ID3D11Texture2D* pSurface = texture->GetTex(); - D3D11_TEXTURE2D_DESC desc; - pSurface->GetDesc(&desc); + ID3D11Texture2D* pNewTexture = nullptr; + ID3D11Texture2D* pSurface = texture->GetTex(); + D3D11_TEXTURE2D_DESC desc; + pSurface->GetDesc(&desc); - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; - desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + desc.Usage = D3D11_USAGE_STAGING; - HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, &pNewTexture); + HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, &pNewTexture); - bool saved_png = false; + bool saved_png = false; - if (SUCCEEDED(hr) && pNewTexture) - { - D3D::context->CopyResource(pNewTexture, pSurface); + if (SUCCEEDED(hr) && pNewTexture) + { + D3D::context->CopyResource(pNewTexture, pSurface); - D3D11_MAPPED_SUBRESOURCE map; - hr = D3D::context->Map(pNewTexture, 0, D3D11_MAP_READ_WRITE, 0, &map); - if (SUCCEEDED(hr)) - { - saved_png = TextureToPng((u8*)map.pData, map.RowPitch, filename, desc.Width, desc.Height); - D3D::context->Unmap(pNewTexture, 0); - } - SAFE_RELEASE(pNewTexture); - } + D3D11_MAPPED_SUBRESOURCE map; + hr = D3D::context->Map(pNewTexture, 0, D3D11_MAP_READ_WRITE, 0, &map); + if (SUCCEEDED(hr)) + { + saved_png = TextureToPng((u8*)map.pData, map.RowPitch, filename, desc.Width, desc.Height); + D3D::context->Unmap(pNewTexture, 0); + } + SAFE_RELEASE(pNewTexture); + } - return saved_png; + return saved_png; } -void TextureCache::TCacheEntry::CopyRectangleFromTexture( - const TCacheEntryBase* source, - const MathUtil::Rectangle &srcrect, - const MathUtil::Rectangle &dstrect) +void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase* source, + const MathUtil::Rectangle& srcrect, + const MathUtil::Rectangle& dstrect) { - TCacheEntry* srcentry = (TCacheEntry*)source; - if (srcrect.GetWidth() == dstrect.GetWidth() - && srcrect.GetHeight() == dstrect.GetHeight()) - { - D3D11_BOX srcbox; - srcbox.left = srcrect.left; - srcbox.top = srcrect.top; - srcbox.right = srcrect.right; - srcbox.bottom = srcrect.bottom; - srcbox.front = 0; - srcbox.back = srcentry->config.layers; + TCacheEntry* srcentry = (TCacheEntry*)source; + if (srcrect.GetWidth() == dstrect.GetWidth() && srcrect.GetHeight() == dstrect.GetHeight()) + { + D3D11_BOX srcbox; + srcbox.left = srcrect.left; + srcbox.top = srcrect.top; + srcbox.right = srcrect.right; + srcbox.bottom = srcrect.bottom; + srcbox.front = 0; + srcbox.back = srcentry->config.layers; - D3D::context->CopySubresourceRegion( - texture->GetTex(), - 0, - dstrect.left, - dstrect.top, - 0, - srcentry->texture->GetTex(), - 0, - &srcbox); - return; - } - else if (!config.rendertarget) - { - return; - } - g_renderer->ResetAPIState(); // reset any game specific settings + D3D::context->CopySubresourceRegion(texture->GetTex(), 0, dstrect.left, dstrect.top, 0, + srcentry->texture->GetTex(), 0, &srcbox); + return; + } + else if (!config.rendertarget) + { + return; + } + g_renderer->ResetAPIState(); // reset any game specific settings - const D3D11_VIEWPORT vp = CD3D11_VIEWPORT( - float(dstrect.left), - float(dstrect.top), - float(dstrect.GetWidth()), - float(dstrect.GetHeight())); + const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(float(dstrect.left), float(dstrect.top), + float(dstrect.GetWidth()), float(dstrect.GetHeight())); - D3D::stateman->UnsetTexture(texture->GetSRV()); - D3D::stateman->Apply(); + D3D::stateman->UnsetTexture(texture->GetSRV()); + D3D::stateman->Apply(); - D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), nullptr); - D3D::context->RSSetViewports(1, &vp); - D3D::SetLinearCopySampler(); - D3D11_RECT srcRC; - srcRC.left = srcrect.left; - srcRC.right = srcrect.right; - srcRC.top = srcrect.top; - srcRC.bottom = srcrect.bottom; - D3D::drawShadedTexQuad(srcentry->texture->GetSRV(), &srcRC, - srcentry->config.width, srcentry->config.height, - PixelShaderCache::GetColorCopyProgram(false), - VertexShaderCache::GetSimpleVertexShader(), - VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader(), 1.0, 0); + D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), nullptr); + D3D::context->RSSetViewports(1, &vp); + D3D::SetLinearCopySampler(); + D3D11_RECT srcRC; + srcRC.left = srcrect.left; + srcRC.right = srcrect.right; + srcRC.top = srcrect.top; + srcRC.bottom = srcrect.bottom; + D3D::drawShadedTexQuad(srcentry->texture->GetSRV(), &srcRC, srcentry->config.width, + srcentry->config.height, PixelShaderCache::GetColorCopyProgram(false), + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), + GeometryShaderCache::GetCopyGeometryShader(), 1.0, 0); - D3D::context->OMSetRenderTargets(1, - &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); - g_renderer->RestoreAPIState(); + g_renderer->RestoreAPIState(); } void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int level) + unsigned int expanded_width, unsigned int level) { - unsigned int src_pitch = 4 * expanded_width; - D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, src_pitch, level, usage); + unsigned int src_pitch = 4 * expanded_width; + D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, src_pitch, level, + usage); } TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntryConfig& config) { - if (config.rendertarget) - { - return new TCacheEntry(config, D3DTexture2D::Create(config.width, config.height, - (D3D11_BIND_FLAG)((int)D3D11_BIND_RENDER_TARGET | (int)D3D11_BIND_SHADER_RESOURCE), - D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, config.layers)); - } - else - { - D3D11_USAGE usage = D3D11_USAGE_DEFAULT; - D3D11_CPU_ACCESS_FLAG cpu_access = (D3D11_CPU_ACCESS_FLAG)0; + if (config.rendertarget) + { + return new TCacheEntry( + config, D3DTexture2D::Create( + config.width, config.height, (D3D11_BIND_FLAG)((int)D3D11_BIND_RENDER_TARGET | + (int)D3D11_BIND_SHADER_RESOURCE), + D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, config.layers)); + } + else + { + D3D11_USAGE usage = D3D11_USAGE_DEFAULT; + D3D11_CPU_ACCESS_FLAG cpu_access = (D3D11_CPU_ACCESS_FLAG)0; - if (config.levels == 1) - { - usage = D3D11_USAGE_DYNAMIC; - cpu_access = D3D11_CPU_ACCESS_WRITE; - } + if (config.levels == 1) + { + usage = D3D11_USAGE_DYNAMIC; + cpu_access = D3D11_CPU_ACCESS_WRITE; + } - const D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, - config.width, config.height, 1, config.levels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access); + const D3D11_TEXTURE2D_DESC texdesc = + CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, config.width, config.height, 1, + config.levels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access); - ID3D11Texture2D *pTexture; - const HRESULT hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture); - CHECK(SUCCEEDED(hr), "Create texture of the TextureCache"); + ID3D11Texture2D* pTexture; + const HRESULT hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture); + CHECK(SUCCEEDED(hr), "Create texture of the TextureCache"); - TCacheEntry* const entry = new TCacheEntry(config, new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE)); - entry->usage = usage; + TCacheEntry* const entry = + new TCacheEntry(config, new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE)); + entry->usage = usage; - // TODO: better debug names - D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetTex(), "a texture of the TextureCache"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetSRV(), "shader resource view of a texture of the TextureCache"); + // TODO: better debug names + D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetTex(), + "a texture of the TextureCache"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetSRV(), + "shader resource view of a texture of the TextureCache"); - SAFE_RELEASE(pTexture); + SAFE_RELEASE(pTexture); - return entry; - } + return entry; + } } -void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool scaleByHalf, unsigned int cbufid, const float *colmat) +void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat, + const EFBRectangle& srcRect, bool scaleByHalf, + unsigned int cbufid, const float* colmat) { - // When copying at half size, in multisampled mode, resolve the color/depth buffer first. - // This is because multisampled texture reads go through Load, not Sample, and the linear - // filter is ignored. - bool multisampled = (g_ActiveConfig.iMultisamples > 1); - ID3D11ShaderResourceView* efbTexSRV = (srcFormat == PEControl::Z24) ? - FramebufferManager::GetEFBDepthTexture()->GetSRV() : - FramebufferManager::GetEFBColorTexture()->GetSRV(); - if (multisampled && scaleByHalf) - { - multisampled = false; - efbTexSRV = (srcFormat == PEControl::Z24) ? - FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() : - FramebufferManager::GetResolvedEFBColorTexture()->GetSRV(); - } + // When copying at half size, in multisampled mode, resolve the color/depth buffer first. + // This is because multisampled texture reads go through Load, not Sample, and the linear + // filter is ignored. + bool multisampled = (g_ActiveConfig.iMultisamples > 1); + ID3D11ShaderResourceView* efbTexSRV = (srcFormat == PEControl::Z24) ? + FramebufferManager::GetEFBDepthTexture()->GetSRV() : + FramebufferManager::GetEFBColorTexture()->GetSRV(); + if (multisampled && scaleByHalf) + { + multisampled = false; + efbTexSRV = (srcFormat == PEControl::Z24) ? + FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() : + FramebufferManager::GetResolvedEFBColorTexture()->GetSRV(); + } - g_renderer->ResetAPIState(); + g_renderer->ResetAPIState(); - // stretch picture with increased internal resolution - const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)config.width, (float)config.height); - D3D::context->RSSetViewports(1, &vp); + // stretch picture with increased internal resolution + const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)config.width, (float)config.height); + D3D::context->RSSetViewports(1, &vp); - // set transformation - if (nullptr == efbcopycbuf[cbufid]) - { - const D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(28 * sizeof(float), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT); - D3D11_SUBRESOURCE_DATA data; - data.pSysMem = colmat; - HRESULT hr = D3D::device->CreateBuffer(&cbdesc, &data, &efbcopycbuf[cbufid]); - CHECK(SUCCEEDED(hr), "Create efb copy constant buffer %d", cbufid); - D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopycbuf[cbufid], "a constant buffer used in TextureCache::CopyRenderTargetToTexture"); - } - D3D::stateman->SetPixelConstants(efbcopycbuf[cbufid]); + // set transformation + if (nullptr == efbcopycbuf[cbufid]) + { + const D3D11_BUFFER_DESC cbdesc = + CD3D11_BUFFER_DESC(28 * sizeof(float), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT); + D3D11_SUBRESOURCE_DATA data; + data.pSysMem = colmat; + HRESULT hr = D3D::device->CreateBuffer(&cbdesc, &data, &efbcopycbuf[cbufid]); + CHECK(SUCCEEDED(hr), "Create efb copy constant buffer %d", cbufid); + D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopycbuf[cbufid], + "a constant buffer used in TextureCache::CopyRenderTargetToTexture"); + } + D3D::stateman->SetPixelConstants(efbcopycbuf[cbufid]); - const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(srcRect); - // TODO: try targetSource.asRECT(); - const D3D11_RECT sourcerect = CD3D11_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom); + const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(srcRect); + // TODO: try targetSource.asRECT(); + const D3D11_RECT sourcerect = + CD3D11_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom); - // Use linear filtering if (bScaleByHalf), use point filtering otherwise - if (scaleByHalf) - D3D::SetLinearCopySampler(); - else - D3D::SetPointCopySampler(); + // Use linear filtering if (bScaleByHalf), use point filtering otherwise + if (scaleByHalf) + D3D::SetLinearCopySampler(); + else + D3D::SetPointCopySampler(); - // Make sure we don't draw with the texture set as both a source and target. - // (This can happen because we don't unbind textures when we free them.) - D3D::stateman->UnsetTexture(texture->GetSRV()); - D3D::stateman->Apply(); + // Make sure we don't draw with the texture set as both a source and target. + // (This can happen because we don't unbind textures when we free them.) + D3D::stateman->UnsetTexture(texture->GetSRV()); + D3D::stateman->Apply(); - D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), nullptr); + D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), nullptr); - // Create texture copy - D3D::drawShadedTexQuad( - efbTexSRV, - &sourcerect, Renderer::GetTargetWidth(), - Renderer::GetTargetHeight(), - srcFormat == PEControl::Z24 ? PixelShaderCache::GetDepthMatrixProgram(multisampled) : PixelShaderCache::GetColorMatrixProgram(multisampled), - VertexShaderCache::GetSimpleVertexShader(), - VertexShaderCache::GetSimpleInputLayout(), - GeometryShaderCache::GetCopyGeometryShader()); + // Create texture copy + D3D::drawShadedTexQuad( + efbTexSRV, &sourcerect, Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), + srcFormat == PEControl::Z24 ? PixelShaderCache::GetDepthMatrixProgram(multisampled) : + PixelShaderCache::GetColorMatrixProgram(multisampled), + VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), + GeometryShaderCache::GetCopyGeometryShader()); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); - g_renderer->RestoreAPIState(); + g_renderer->RestoreAPIState(); } -void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool isIntensity, bool scaleByHalf) +void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, PEControl::PixelFormat srcFormat, + const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) { - g_encoder->Encode(dst, format, native_width, bytes_per_row, num_blocks_y, memory_stride, srcFormat, srcRect, isIntensity, scaleByHalf); + g_encoder->Encode(dst, format, native_width, bytes_per_row, num_blocks_y, memory_stride, + srcFormat, srcRect, isIntensity, scaleByHalf); } const char palette_shader[] = -R"HLSL( + R"HLSL( sampler samp0 : register(s0); Texture2DArray Tex0 : register(t0); Buffer Tex1 : register(t1); @@ -343,97 +340,103 @@ void main( } )HLSL"; -void TextureCache::ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format) +void TextureCache::ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, + void* palette, TlutFormat format) { - g_renderer->ResetAPIState(); + g_renderer->ResetAPIState(); - // stretch picture with increased internal resolution - const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)unconverted->config.width, (float)unconverted->config.height); - D3D::context->RSSetViewports(1, &vp); + // stretch picture with increased internal resolution + const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)unconverted->config.width, + (float)unconverted->config.height); + D3D::context->RSSetViewports(1, &vp); - D3D11_BOX box{ 0, 0, 0, 512, 1, 1 }; - D3D::context->UpdateSubresource(palette_buf, 0, &box, palette, 0, 0); + D3D11_BOX box{0, 0, 0, 512, 1, 1}; + D3D::context->UpdateSubresource(palette_buf, 0, &box, palette, 0, 0); - D3D::stateman->SetTexture(1, palette_buf_srv); + D3D::stateman->SetTexture(1, palette_buf_srv); - // TODO: Add support for C14X2 format. (Different multiplier, more palette entries.) - float params[4] = { (unconverted->format & 0xf) == GX_TF_I4 ? 15.f : 255.f }; - D3D::context->UpdateSubresource(palette_uniform, 0, nullptr, ¶ms, 0, 0); - D3D::stateman->SetPixelConstants(palette_uniform); + // TODO: Add support for C14X2 format. (Different multiplier, more palette entries.) + float params[4] = {(unconverted->format & 0xf) == GX_TF_I4 ? 15.f : 255.f}; + D3D::context->UpdateSubresource(palette_uniform, 0, nullptr, ¶ms, 0, 0); + D3D::stateman->SetPixelConstants(palette_uniform); - const D3D11_RECT sourcerect = CD3D11_RECT(0, 0, unconverted->config.width, unconverted->config.height); + const D3D11_RECT sourcerect = + CD3D11_RECT(0, 0, unconverted->config.width, unconverted->config.height); - D3D::SetPointCopySampler(); + D3D::SetPointCopySampler(); - // Make sure we don't draw with the texture set as both a source and target. - // (This can happen because we don't unbind textures when we free them.) - D3D::stateman->UnsetTexture(static_cast(entry)->texture->GetSRV()); - D3D::stateman->Apply(); + // Make sure we don't draw with the texture set as both a source and target. + // (This can happen because we don't unbind textures when we free them.) + D3D::stateman->UnsetTexture(static_cast(entry)->texture->GetSRV()); + D3D::stateman->Apply(); - D3D::context->OMSetRenderTargets(1, &static_cast(entry)->texture->GetRTV(), nullptr); + D3D::context->OMSetRenderTargets(1, &static_cast(entry)->texture->GetRTV(), + nullptr); - // Create texture copy - D3D::drawShadedTexQuad( - static_cast(unconverted)->texture->GetSRV(), - &sourcerect, unconverted->config.width, unconverted->config.height, - palette_pixel_shader[format], - VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), - GeometryShaderCache::GetCopyGeometryShader()); + // Create texture copy + D3D::drawShadedTexQuad(static_cast(unconverted)->texture->GetSRV(), &sourcerect, + unconverted->config.width, unconverted->config.height, + palette_pixel_shader[format], VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), + GeometryShaderCache::GetCopyGeometryShader()); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); - g_renderer->RestoreAPIState(); + g_renderer->RestoreAPIState(); } -ID3D11PixelShader *GetConvertShader(const char* Type) +ID3D11PixelShader* GetConvertShader(const char* Type) { - std::string shader = "#define DECODE DecodePixel_"; - shader.append(Type); - shader.append("\n"); - shader.append(palette_shader); - return D3D::CompileAndCreatePixelShader(shader); + std::string shader = "#define DECODE DecodePixel_"; + shader.append(Type); + shader.append("\n"); + shader.append(palette_shader); + return D3D::CompileAndCreatePixelShader(shader); } TextureCache::TextureCache() { - // FIXME: Is it safe here? - g_encoder = std::make_unique(); - g_encoder->Init(); + // FIXME: Is it safe here? + g_encoder = std::make_unique(); + g_encoder->Init(); - palette_buf = nullptr; - palette_buf_srv = nullptr; - palette_uniform = nullptr; - palette_pixel_shader[GX_TL_IA8] = GetConvertShader("IA8"); - palette_pixel_shader[GX_TL_RGB565] = GetConvertShader("RGB565"); - palette_pixel_shader[GX_TL_RGB5A3] = GetConvertShader("RGB5A3"); - auto lutBd = CD3D11_BUFFER_DESC(sizeof(u16) * 256, D3D11_BIND_SHADER_RESOURCE); - HRESULT hr = D3D::device->CreateBuffer(&lutBd, nullptr, &palette_buf); - CHECK(SUCCEEDED(hr), "create palette decoder lut buffer"); - D3D::SetDebugObjectName(palette_buf, "texture decoder lut buffer"); - // TODO: C14X2 format. - auto outlutUavDesc = CD3D11_SHADER_RESOURCE_VIEW_DESC(palette_buf, DXGI_FORMAT_R16_UINT, 0, 256, 0); - hr = D3D::device->CreateShaderResourceView(palette_buf, &outlutUavDesc, &palette_buf_srv); - CHECK(SUCCEEDED(hr), "create palette decoder lut srv"); - D3D::SetDebugObjectName(palette_buf_srv, "texture decoder lut srv"); - const D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(16, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT); - hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &palette_uniform); - CHECK(SUCCEEDED(hr), "Create palette decoder constant buffer"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)palette_uniform, "a constant buffer used in TextureCache::CopyRenderTargetToTexture"); + palette_buf = nullptr; + palette_buf_srv = nullptr; + palette_uniform = nullptr; + palette_pixel_shader[GX_TL_IA8] = GetConvertShader("IA8"); + palette_pixel_shader[GX_TL_RGB565] = GetConvertShader("RGB565"); + palette_pixel_shader[GX_TL_RGB5A3] = GetConvertShader("RGB5A3"); + auto lutBd = CD3D11_BUFFER_DESC(sizeof(u16) * 256, D3D11_BIND_SHADER_RESOURCE); + HRESULT hr = D3D::device->CreateBuffer(&lutBd, nullptr, &palette_buf); + CHECK(SUCCEEDED(hr), "create palette decoder lut buffer"); + D3D::SetDebugObjectName(palette_buf, "texture decoder lut buffer"); + // TODO: C14X2 format. + auto outlutUavDesc = + CD3D11_SHADER_RESOURCE_VIEW_DESC(palette_buf, DXGI_FORMAT_R16_UINT, 0, 256, 0); + hr = D3D::device->CreateShaderResourceView(palette_buf, &outlutUavDesc, &palette_buf_srv); + CHECK(SUCCEEDED(hr), "create palette decoder lut srv"); + D3D::SetDebugObjectName(palette_buf_srv, "texture decoder lut srv"); + const D3D11_BUFFER_DESC cbdesc = + CD3D11_BUFFER_DESC(16, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT); + hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &palette_uniform); + CHECK(SUCCEEDED(hr), "Create palette decoder constant buffer"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)palette_uniform, + "a constant buffer used in TextureCache::CopyRenderTargetToTexture"); } TextureCache::~TextureCache() { - for (unsigned int k = 0; k < MAX_COPY_BUFFERS; ++k) - SAFE_RELEASE(efbcopycbuf[k]); + for (unsigned int k = 0; k < MAX_COPY_BUFFERS; ++k) + SAFE_RELEASE(efbcopycbuf[k]); - g_encoder->Shutdown(); - g_encoder.reset(); + g_encoder->Shutdown(); + g_encoder.reset(); - SAFE_RELEASE(palette_buf); - SAFE_RELEASE(palette_buf_srv); - SAFE_RELEASE(palette_uniform); - for (ID3D11PixelShader*& shader : palette_pixel_shader) - SAFE_RELEASE(shader); + SAFE_RELEASE(palette_buf); + SAFE_RELEASE(palette_buf_srv); + SAFE_RELEASE(palette_uniform); + for (ID3D11PixelShader*& shader : palette_pixel_shader) + SAFE_RELEASE(shader); } - } diff --git a/Source/Core/VideoBackends/D3D/TextureCache.h b/Source/Core/VideoBackends/D3D/TextureCache.h index 37f0dcc6c7..85cc641812 100644 --- a/Source/Core/VideoBackends/D3D/TextureCache.h +++ b/Source/Core/VideoBackends/D3D/TextureCache.h @@ -9,55 +9,60 @@ namespace DX11 { - class TextureCache : public TextureCacheBase { public: - TextureCache(); - ~TextureCache(); + TextureCache(); + ~TextureCache(); private: - struct TCacheEntry : TCacheEntryBase - { - D3DTexture2D *const texture; + struct TCacheEntry : TCacheEntryBase + { + D3DTexture2D* const texture; - D3D11_USAGE usage; + D3D11_USAGE usage; - TCacheEntry(const TCacheEntryConfig& config, D3DTexture2D *_tex) : TCacheEntryBase(config), texture(_tex) {} - ~TCacheEntry(); + TCacheEntry(const TCacheEntryConfig& config, D3DTexture2D* _tex) + : TCacheEntryBase(config), texture(_tex) + { + } + ~TCacheEntry(); - void CopyRectangleFromTexture( - const TCacheEntryBase* source, - const MathUtil::Rectangle &srcrect, - const MathUtil::Rectangle &dstrect) override; + void CopyRectangleFromTexture(const TCacheEntryBase* source, + const MathUtil::Rectangle& srcrect, + const MathUtil::Rectangle& dstrect) override; - void Load(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int levels) override; + void Load(unsigned int width, unsigned int height, unsigned int expanded_width, + unsigned int levels) override; - void FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool scaleByHalf, unsigned int cbufid, const float *colmat) override; + void FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, + bool scaleByHalf, unsigned int cbufid, const float* colmat) override; - void Bind(unsigned int stage) override; - bool Save(const std::string& filename, unsigned int level) override; - }; + void Bind(unsigned int stage) override; + bool Save(const std::string& filename, unsigned int level) override; + }; - TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) override; + TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) override; - u64 EncodeToRamFromTexture(u32 address, void* source_texture, u32 SourceW, u32 SourceH, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) {return 0;}; + u64 EncodeToRamFromTexture(u32 address, void* source_texture, u32 SourceW, u32 SourceH, + bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, + const EFBRectangle& source) + { + return 0; + }; - void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format) override; + void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, + TlutFormat format) override; - void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool isIntensity, bool scaleByHalf) override; + void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, + u32 memory_stride, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, + bool isIntensity, bool scaleByHalf) override; - void CompileShaders() override { } - void DeleteShaders() override { } - - ID3D11Buffer* palette_buf; - ID3D11ShaderResourceView* palette_buf_srv; - ID3D11Buffer* palette_uniform; - ID3D11PixelShader* palette_pixel_shader[3]; + void CompileShaders() override {} + void DeleteShaders() override {} + ID3D11Buffer* palette_buf; + ID3D11ShaderResourceView* palette_buf_srv; + ID3D11Buffer* palette_uniform; + ID3D11PixelShader* palette_pixel_shader[3]; }; - } diff --git a/Source/Core/VideoBackends/D3D/TextureEncoder.h b/Source/Core/VideoBackends/D3D/TextureEncoder.h index 52ac6ba25e..998c6c2241 100644 --- a/Source/Core/VideoBackends/D3D/TextureEncoder.h +++ b/Source/Core/VideoBackends/D3D/TextureEncoder.h @@ -12,24 +12,19 @@ namespace DX11 { // Maximum number of bytes that can occur in a texture block-row generated by // the encoder -static const UINT MAX_BYTES_PER_BLOCK_ROW = (EFB_WIDTH/4)*64; +static const UINT MAX_BYTES_PER_BLOCK_ROW = (EFB_WIDTH / 4) * 64; // The maximum amount of data that the texture encoder can generate in one call -static const UINT MAX_BYTES_PER_ENCODE = MAX_BYTES_PER_BLOCK_ROW*(EFB_HEIGHT/4); +static const UINT MAX_BYTES_PER_ENCODE = MAX_BYTES_PER_BLOCK_ROW * (EFB_HEIGHT / 4); class TextureEncoder { - public: - - virtual ~TextureEncoder() { } - - virtual void Init() = 0; - virtual void Shutdown() = 0; - // Returns size in bytes of encoded block of memory - virtual void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool isIntensity, bool scaleByHalf) = 0; - + virtual ~TextureEncoder() {} + virtual void Init() = 0; + virtual void Shutdown() = 0; + // Returns size in bytes of encoded block of memory + virtual void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, + u32 memory_stride, PEControl::PixelFormat srcFormat, + const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) = 0; }; - } diff --git a/Source/Core/VideoBackends/D3D/VertexManager.cpp b/Source/Core/VideoBackends/D3D/VertexManager.cpp index 6a739c9737..ddffc6653d 100644 --- a/Source/Core/VideoBackends/D3D/VertexManager.cpp +++ b/Source/Core/VideoBackends/D3D/VertexManager.cpp @@ -23,7 +23,6 @@ namespace DX11 { - // TODO: Find sensible values for these two const u32 MAX_IBUFFER_SIZE = VertexManager::MAXIBUFFERSIZE * sizeof(u16) * 8; const u32 MAX_VBUFFER_SIZE = VertexManager::MAXVBUFFERSIZE; @@ -31,164 +30,166 @@ const u32 MAX_BUFFER_SIZE = MAX_IBUFFER_SIZE + MAX_VBUFFER_SIZE; void VertexManager::CreateDeviceObjects() { - D3D11_BUFFER_DESC bufdesc = CD3D11_BUFFER_DESC(MAX_BUFFER_SIZE, - D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + D3D11_BUFFER_DESC bufdesc = + CD3D11_BUFFER_DESC(MAX_BUFFER_SIZE, D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER, + D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - m_vertexDrawOffset = 0; - m_indexDrawOffset = 0; + m_vertexDrawOffset = 0; + m_indexDrawOffset = 0; - for (int i = 0; i < MAX_BUFFER_COUNT; i++) - { - m_buffers[i] = nullptr; - CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, nullptr, &m_buffers[i])), "Failed to create buffer."); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_buffers[i], "Buffer of VertexManager"); - } + for (int i = 0; i < MAX_BUFFER_COUNT; i++) + { + m_buffers[i] = nullptr; + CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, nullptr, &m_buffers[i])), + "Failed to create buffer."); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_buffers[i], "Buffer of VertexManager"); + } - m_currentBuffer = 0; - m_bufferCursor = MAX_BUFFER_SIZE; + m_currentBuffer = 0; + m_bufferCursor = MAX_BUFFER_SIZE; } void VertexManager::DestroyDeviceObjects() { - for (int i = 0; i < MAX_BUFFER_COUNT; i++) - { - SAFE_RELEASE(m_buffers[i]); - } - + for (int i = 0; i < MAX_BUFFER_COUNT; i++) + { + SAFE_RELEASE(m_buffers[i]); + } } VertexManager::VertexManager() { - LocalVBuffer.resize(MAXVBUFFERSIZE); + LocalVBuffer.resize(MAXVBUFFERSIZE); - s_pCurBufferPointer = s_pBaseBufferPointer = &LocalVBuffer[0]; - s_pEndBufferPointer = s_pBaseBufferPointer + LocalVBuffer.size(); + s_pCurBufferPointer = s_pBaseBufferPointer = &LocalVBuffer[0]; + s_pEndBufferPointer = s_pBaseBufferPointer + LocalVBuffer.size(); - LocalIBuffer.resize(MAXIBUFFERSIZE); + LocalIBuffer.resize(MAXIBUFFERSIZE); - CreateDeviceObjects(); + CreateDeviceObjects(); } VertexManager::~VertexManager() { - DestroyDeviceObjects(); + DestroyDeviceObjects(); } void VertexManager::PrepareDrawBuffers(u32 stride) { - D3D11_MAPPED_SUBRESOURCE map; + D3D11_MAPPED_SUBRESOURCE map; - u32 vertexBufferSize = u32(s_pCurBufferPointer - s_pBaseBufferPointer); - u32 indexBufferSize = IndexGenerator::GetIndexLen() * sizeof(u16); - u32 totalBufferSize = vertexBufferSize + indexBufferSize; + u32 vertexBufferSize = u32(s_pCurBufferPointer - s_pBaseBufferPointer); + u32 indexBufferSize = IndexGenerator::GetIndexLen() * sizeof(u16); + u32 totalBufferSize = vertexBufferSize + indexBufferSize; - u32 cursor = m_bufferCursor; - u32 padding = m_bufferCursor % stride; - if (padding) - { - cursor += stride - padding; - } + u32 cursor = m_bufferCursor; + u32 padding = m_bufferCursor % stride; + if (padding) + { + cursor += stride - padding; + } - D3D11_MAP MapType = D3D11_MAP_WRITE_NO_OVERWRITE; - if (cursor + totalBufferSize >= MAX_BUFFER_SIZE) - { - // Wrap around - m_currentBuffer = (m_currentBuffer + 1) % MAX_BUFFER_COUNT; - cursor = 0; - MapType = D3D11_MAP_WRITE_DISCARD; - } + D3D11_MAP MapType = D3D11_MAP_WRITE_NO_OVERWRITE; + if (cursor + totalBufferSize >= MAX_BUFFER_SIZE) + { + // Wrap around + m_currentBuffer = (m_currentBuffer + 1) % MAX_BUFFER_COUNT; + cursor = 0; + MapType = D3D11_MAP_WRITE_DISCARD; + } - m_vertexDrawOffset = cursor; - m_indexDrawOffset = cursor + vertexBufferSize; + m_vertexDrawOffset = cursor; + m_indexDrawOffset = cursor + vertexBufferSize; - D3D::context->Map(m_buffers[m_currentBuffer], 0, MapType, 0, &map); - u8* mappedData = reinterpret_cast(map.pData); - memcpy(mappedData + m_vertexDrawOffset, s_pBaseBufferPointer, vertexBufferSize); - memcpy(mappedData + m_indexDrawOffset, GetIndexBuffer(), indexBufferSize); - D3D::context->Unmap(m_buffers[m_currentBuffer], 0); + D3D::context->Map(m_buffers[m_currentBuffer], 0, MapType, 0, &map); + u8* mappedData = reinterpret_cast(map.pData); + memcpy(mappedData + m_vertexDrawOffset, s_pBaseBufferPointer, vertexBufferSize); + memcpy(mappedData + m_indexDrawOffset, GetIndexBuffer(), indexBufferSize); + D3D::context->Unmap(m_buffers[m_currentBuffer], 0); - m_bufferCursor = cursor + totalBufferSize; + m_bufferCursor = cursor + totalBufferSize; - ADDSTAT(stats.thisFrame.bytesVertexStreamed, vertexBufferSize); - ADDSTAT(stats.thisFrame.bytesIndexStreamed, indexBufferSize); + ADDSTAT(stats.thisFrame.bytesVertexStreamed, vertexBufferSize); + ADDSTAT(stats.thisFrame.bytesIndexStreamed, indexBufferSize); } void VertexManager::Draw(u32 stride) { - u32 indices = IndexGenerator::GetIndexLen(); + u32 indices = IndexGenerator::GetIndexLen(); - D3D::stateman->SetVertexBuffer(m_buffers[m_currentBuffer], stride, 0); - D3D::stateman->SetIndexBuffer(m_buffers[m_currentBuffer]); + D3D::stateman->SetVertexBuffer(m_buffers[m_currentBuffer], stride, 0); + D3D::stateman->SetIndexBuffer(m_buffers[m_currentBuffer]); - u32 baseVertex = m_vertexDrawOffset / stride; - u32 startIndex = m_indexDrawOffset / sizeof(u16); + u32 baseVertex = m_vertexDrawOffset / stride; + u32 startIndex = m_indexDrawOffset / sizeof(u16); - switch (current_primitive_type) - { - case PRIMITIVE_POINTS: - D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); - static_cast(g_renderer.get())->ApplyCullDisable(); - break; - case PRIMITIVE_LINES: - D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); - static_cast(g_renderer.get())->ApplyCullDisable(); - break; - case PRIMITIVE_TRIANGLES: - D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - break; - } + switch (current_primitive_type) + { + case PRIMITIVE_POINTS: + D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); + static_cast(g_renderer.get())->ApplyCullDisable(); + break; + case PRIMITIVE_LINES: + D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); + static_cast(g_renderer.get())->ApplyCullDisable(); + break; + case PRIMITIVE_TRIANGLES: + D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + break; + } - D3D::stateman->Apply(); - D3D::context->DrawIndexed(indices, startIndex, baseVertex); + D3D::stateman->Apply(); + D3D::context->DrawIndexed(indices, startIndex, baseVertex); - INCSTAT(stats.thisFrame.numDrawCalls); + INCSTAT(stats.thisFrame.numDrawCalls); - if (current_primitive_type != PRIMITIVE_TRIANGLES) - static_cast(g_renderer.get())->RestoreCull(); + if (current_primitive_type != PRIMITIVE_TRIANGLES) + static_cast(g_renderer.get())->RestoreCull(); } void VertexManager::vFlush(bool useDstAlpha) { - if (!PixelShaderCache::SetShader( - useDstAlpha ? DSTALPHA_DUAL_SOURCE_BLEND : DSTALPHA_NONE)) - { - GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");}); - return; - } + if (!PixelShaderCache::SetShader(useDstAlpha ? DSTALPHA_DUAL_SOURCE_BLEND : DSTALPHA_NONE)) + { + GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR, true, { printf("Fail to set pixel shader\n"); }); + return; + } - if (!VertexShaderCache::SetShader()) - { - GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");}); - return; - } + if (!VertexShaderCache::SetShader()) + { + GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR, true, { printf("Fail to set pixel shader\n"); }); + return; + } - if (!GeometryShaderCache::SetShader(current_primitive_type)) - { - GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR, true, { printf("Fail to set pixel shader\n"); }); - return; - } + if (!GeometryShaderCache::SetShader(current_primitive_type)) + { + GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR, true, { printf("Fail to set pixel shader\n"); }); + return; + } - if (g_ActiveConfig.backend_info.bSupportsBBox && BoundingBox::active) - { - D3D::context->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, 2, 1, &BBox::GetUAV(), nullptr); - } + if (g_ActiveConfig.backend_info.bSupportsBBox && BoundingBox::active) + { + D3D::context->OMSetRenderTargetsAndUnorderedAccessViews( + D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, 2, 1, &BBox::GetUAV(), + nullptr); + } - u32 stride = VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride(); + u32 stride = VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride(); - PrepareDrawBuffers(stride); + PrepareDrawBuffers(stride); - VertexLoaderManager::GetCurrentVertexFormat()->SetupVertexPointers(); - g_renderer->ApplyState(useDstAlpha); + VertexLoaderManager::GetCurrentVertexFormat()->SetupVertexPointers(); + g_renderer->ApplyState(useDstAlpha); - Draw(stride); + Draw(stride); - g_renderer->RestoreState(); + g_renderer->RestoreState(); } void VertexManager::ResetBuffer(u32 stride) { - s_pCurBufferPointer = s_pBaseBufferPointer; - IndexGenerator::Start(GetIndexBuffer()); + s_pCurBufferPointer = s_pBaseBufferPointer; + IndexGenerator::Start(GetIndexBuffer()); } } // namespace diff --git a/Source/Core/VideoBackends/D3D/VertexManager.h b/Source/Core/VideoBackends/D3D/VertexManager.h index 2cc6b555d7..e05a505eb5 100644 --- a/Source/Core/VideoBackends/D3D/VertexManager.h +++ b/Source/Core/VideoBackends/D3D/VertexManager.h @@ -8,38 +8,38 @@ namespace DX11 { - class VertexManager : public VertexManagerBase { public: - VertexManager(); - ~VertexManager(); + VertexManager(); + ~VertexManager(); - NativeVertexFormat* CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override; - void CreateDeviceObjects() override; - void DestroyDeviceObjects() override; + NativeVertexFormat* CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override; + void CreateDeviceObjects() override; + void DestroyDeviceObjects() override; protected: - void ResetBuffer(u32 stride) override; - u16* GetIndexBuffer() { return &LocalIBuffer[0]; } - + void ResetBuffer(u32 stride) override; + u16* GetIndexBuffer() { return &LocalIBuffer[0]; } private: + void PrepareDrawBuffers(u32 stride); + void Draw(u32 stride); + // temp + void vFlush(bool useDstAlpha) override; - void PrepareDrawBuffers(u32 stride); - void Draw(u32 stride); - // temp - void vFlush(bool useDstAlpha) override; + u32 m_vertexDrawOffset; + u32 m_indexDrawOffset; + u32 m_currentBuffer; + u32 m_bufferCursor; - u32 m_vertexDrawOffset; - u32 m_indexDrawOffset; - u32 m_currentBuffer; - u32 m_bufferCursor; + enum + { + MAX_BUFFER_COUNT = 2 + }; + ID3D11Buffer* m_buffers[MAX_BUFFER_COUNT]; - enum { MAX_BUFFER_COUNT = 2 }; - ID3D11Buffer* m_buffers[MAX_BUFFER_COUNT]; - - std::vector LocalVBuffer; - std::vector LocalIBuffer; + std::vector LocalVBuffer; + std::vector LocalIBuffer; }; } // namespace diff --git a/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp b/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp index 6c7f074e97..7b3f71da26 100644 --- a/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp @@ -19,10 +19,10 @@ #include "VideoCommon/VertexShaderGen.h" #include "VideoCommon/VertexShaderManager.h" -namespace DX11 { - +namespace DX11 +{ VertexShaderCache::VSCache VertexShaderCache::vshaders; -const VertexShaderCache::VSCacheEntry *VertexShaderCache::last_entry; +const VertexShaderCache::VSCacheEntry* VertexShaderCache::last_entry; VertexShaderUid VertexShaderCache::last_uid; UidChecker VertexShaderCache::vertex_uid_checker; @@ -33,232 +33,245 @@ static ID3D11InputLayout* ClearLayout = nullptr; LinearDiskCache g_vs_disk_cache; -ID3D11VertexShader* VertexShaderCache::GetSimpleVertexShader() { return SimpleVertexShader; } -ID3D11VertexShader* VertexShaderCache::GetClearVertexShader() { return ClearVertexShader; } -ID3D11InputLayout* VertexShaderCache::GetSimpleInputLayout() { return SimpleLayout; } -ID3D11InputLayout* VertexShaderCache::GetClearInputLayout() { return ClearLayout; } +ID3D11VertexShader* VertexShaderCache::GetSimpleVertexShader() +{ + return SimpleVertexShader; +} +ID3D11VertexShader* VertexShaderCache::GetClearVertexShader() +{ + return ClearVertexShader; +} +ID3D11InputLayout* VertexShaderCache::GetSimpleInputLayout() +{ + return SimpleLayout; +} +ID3D11InputLayout* VertexShaderCache::GetClearInputLayout() +{ + return ClearLayout; +} ID3D11Buffer* vscbuf = nullptr; -ID3D11Buffer* &VertexShaderCache::GetConstantBuffer() +ID3D11Buffer*& VertexShaderCache::GetConstantBuffer() { - // TODO: divide the global variables of the generated shaders into about 5 constant buffers to speed this up - if (VertexShaderManager::dirty) - { - D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(vscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, &VertexShaderManager::constants, sizeof(VertexShaderConstants)); - D3D::context->Unmap(vscbuf, 0); - VertexShaderManager::dirty = false; + // TODO: divide the global variables of the generated shaders into about 5 constant buffers to + // speed this up + if (VertexShaderManager::dirty) + { + D3D11_MAPPED_SUBRESOURCE map; + D3D::context->Map(vscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, &VertexShaderManager::constants, sizeof(VertexShaderConstants)); + D3D::context->Unmap(vscbuf, 0); + VertexShaderManager::dirty = false; - ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(VertexShaderConstants)); - } - return vscbuf; + ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(VertexShaderConstants)); + } + return vscbuf; } // this class will load the precompiled shaders into our cache class VertexShaderCacheInserter : public LinearDiskCacheReader { public: - void Read(const VertexShaderUid &key, const u8* value, u32 value_size) - { - D3DBlob* blob = new D3DBlob(value_size, value); - VertexShaderCache::InsertByteCode(key, blob); - blob->Release(); - - } + void Read(const VertexShaderUid& key, const u8* value, u32 value_size) + { + D3DBlob* blob = new D3DBlob(value_size, value); + VertexShaderCache::InsertByteCode(key, blob); + blob->Release(); + } }; const char simple_shader_code[] = { - "struct VSOUTPUT\n" - "{\n" - "float4 vPosition : POSITION;\n" - "float3 vTexCoord : TEXCOORD0;\n" - "float vTexCoord1 : TEXCOORD1;\n" - "};\n" - "VSOUTPUT main(float4 inPosition : POSITION,float4 inTEX0 : TEXCOORD0)\n" - "{\n" - "VSOUTPUT OUT;\n" - "OUT.vPosition = inPosition;\n" - "OUT.vTexCoord = inTEX0.xyz;\n" - "OUT.vTexCoord1 = inTEX0.w;\n" - "return OUT;\n" - "}\n" -}; + "struct VSOUTPUT\n" + "{\n" + "float4 vPosition : POSITION;\n" + "float3 vTexCoord : TEXCOORD0;\n" + "float vTexCoord1 : TEXCOORD1;\n" + "};\n" + "VSOUTPUT main(float4 inPosition : POSITION,float4 inTEX0 : TEXCOORD0)\n" + "{\n" + "VSOUTPUT OUT;\n" + "OUT.vPosition = inPosition;\n" + "OUT.vTexCoord = inTEX0.xyz;\n" + "OUT.vTexCoord1 = inTEX0.w;\n" + "return OUT;\n" + "}\n"}; const char clear_shader_code[] = { - "struct VSOUTPUT\n" - "{\n" - "float4 vPosition : POSITION;\n" - "float4 vColor0 : COLOR0;\n" - "};\n" - "VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0)\n" - "{\n" - "VSOUTPUT OUT;\n" - "OUT.vPosition = inPosition;\n" - "OUT.vColor0 = inColor0;\n" - "return OUT;\n" - "}\n" -}; + "struct VSOUTPUT\n" + "{\n" + "float4 vPosition : POSITION;\n" + "float4 vColor0 : COLOR0;\n" + "};\n" + "VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0)\n" + "{\n" + "VSOUTPUT OUT;\n" + "OUT.vPosition = inPosition;\n" + "OUT.vColor0 = inColor0;\n" + "return OUT;\n" + "}\n"}; void VertexShaderCache::Init() { - const D3D11_INPUT_ELEMENT_DESC simpleelems[2] = - { - { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + const D3D11_INPUT_ELEMENT_DESC simpleelems[2] = { + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, - }; - const D3D11_INPUT_ELEMENT_DESC clearelems[2] = - { - { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - }; + }; + const D3D11_INPUT_ELEMENT_DESC clearelems[2] = { + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }; - unsigned int cbsize = ROUND_UP(sizeof(VertexShaderConstants), 16); // must be a multiple of 16 - D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(cbsize, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - HRESULT hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &vscbuf); - CHECK(hr==S_OK, "Create vertex shader constant buffer (size=%u)", cbsize); - D3D::SetDebugObjectName((ID3D11DeviceChild*)vscbuf, "vertex shader constant buffer used to emulate the GX pipeline"); + unsigned int cbsize = ROUND_UP(sizeof(VertexShaderConstants), 16); // must be a multiple of 16 + D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(cbsize, D3D11_BIND_CONSTANT_BUFFER, + D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + HRESULT hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &vscbuf); + CHECK(hr == S_OK, "Create vertex shader constant buffer (size=%u)", cbsize); + D3D::SetDebugObjectName((ID3D11DeviceChild*)vscbuf, + "vertex shader constant buffer used to emulate the GX pipeline"); - D3DBlob* blob; - D3D::CompileVertexShader(simple_shader_code, &blob); - D3D::device->CreateInputLayout(simpleelems, 2, blob->Data(), blob->Size(), &SimpleLayout); - SimpleVertexShader = D3D::CreateVertexShaderFromByteCode(blob); - if (SimpleLayout == nullptr || SimpleVertexShader == nullptr) - PanicAlert("Failed to create simple vertex shader or input layout at %s %d\n", __FILE__, __LINE__); - blob->Release(); - D3D::SetDebugObjectName((ID3D11DeviceChild*)SimpleVertexShader, "simple vertex shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)SimpleLayout, "simple input layout"); + D3DBlob* blob; + D3D::CompileVertexShader(simple_shader_code, &blob); + D3D::device->CreateInputLayout(simpleelems, 2, blob->Data(), blob->Size(), &SimpleLayout); + SimpleVertexShader = D3D::CreateVertexShaderFromByteCode(blob); + if (SimpleLayout == nullptr || SimpleVertexShader == nullptr) + PanicAlert("Failed to create simple vertex shader or input layout at %s %d\n", __FILE__, + __LINE__); + blob->Release(); + D3D::SetDebugObjectName((ID3D11DeviceChild*)SimpleVertexShader, "simple vertex shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)SimpleLayout, "simple input layout"); - D3D::CompileVertexShader(clear_shader_code, &blob); - D3D::device->CreateInputLayout(clearelems, 2, blob->Data(), blob->Size(), &ClearLayout); - ClearVertexShader = D3D::CreateVertexShaderFromByteCode(blob); - if (ClearLayout == nullptr || ClearVertexShader == nullptr) - PanicAlert("Failed to create clear vertex shader or input layout at %s %d\n", __FILE__, __LINE__); - blob->Release(); - D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearVertexShader, "clear vertex shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearLayout, "clear input layout"); + D3D::CompileVertexShader(clear_shader_code, &blob); + D3D::device->CreateInputLayout(clearelems, 2, blob->Data(), blob->Size(), &ClearLayout); + ClearVertexShader = D3D::CreateVertexShaderFromByteCode(blob); + if (ClearLayout == nullptr || ClearVertexShader == nullptr) + PanicAlert("Failed to create clear vertex shader or input layout at %s %d\n", __FILE__, + __LINE__); + blob->Release(); + D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearVertexShader, "clear vertex shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearLayout, "clear input layout"); - Clear(); + Clear(); - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - SETSTAT(stats.numVertexShadersCreated, 0); - SETSTAT(stats.numVertexShadersAlive, 0); + SETSTAT(stats.numVertexShadersCreated, 0); + SETSTAT(stats.numVertexShadersAlive, 0); - std::string cache_filename = StringFromFormat("%sdx11-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), - SConfig::GetInstance().m_strUniqueID.c_str()); - VertexShaderCacheInserter inserter; - g_vs_disk_cache.OpenAndRead(cache_filename, inserter); + std::string cache_filename = + StringFromFormat("%sdx11-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), + SConfig::GetInstance().m_strUniqueID.c_str()); + VertexShaderCacheInserter inserter; + g_vs_disk_cache.OpenAndRead(cache_filename, inserter); - if (g_Config.bEnableShaderDebugging) - Clear(); + if (g_Config.bEnableShaderDebugging) + Clear(); - last_entry = nullptr; + last_entry = nullptr; } void VertexShaderCache::Clear() { - for (auto& iter : vshaders) - iter.second.Destroy(); - vshaders.clear(); - vertex_uid_checker.Invalidate(); + for (auto& iter : vshaders) + iter.second.Destroy(); + vshaders.clear(); + vertex_uid_checker.Invalidate(); - last_entry = nullptr; + last_entry = nullptr; } void VertexShaderCache::Shutdown() { - SAFE_RELEASE(vscbuf); + SAFE_RELEASE(vscbuf); - SAFE_RELEASE(SimpleVertexShader); - SAFE_RELEASE(ClearVertexShader); + SAFE_RELEASE(SimpleVertexShader); + SAFE_RELEASE(ClearVertexShader); - SAFE_RELEASE(SimpleLayout); - SAFE_RELEASE(ClearLayout); + SAFE_RELEASE(SimpleLayout); + SAFE_RELEASE(ClearLayout); - Clear(); - g_vs_disk_cache.Sync(); - g_vs_disk_cache.Close(); + Clear(); + g_vs_disk_cache.Sync(); + g_vs_disk_cache.Close(); } bool VertexShaderCache::SetShader() { - VertexShaderUid uid = GetVertexShaderUid(API_D3D); - if (g_ActiveConfig.bEnableShaderDebugging) - { - ShaderCode code = GenerateVertexShaderCode(API_D3D); - vertex_uid_checker.AddToIndexAndCheck(code, uid, "Vertex", "v"); - } + VertexShaderUid uid = GetVertexShaderUid(API_D3D); + if (g_ActiveConfig.bEnableShaderDebugging) + { + ShaderCode code = GenerateVertexShaderCode(API_D3D); + vertex_uid_checker.AddToIndexAndCheck(code, uid, "Vertex", "v"); + } - if (last_entry) - { - if (uid == last_uid) - { - GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); - return (last_entry->shader != nullptr); - } - } + if (last_entry) + { + if (uid == last_uid) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); + return (last_entry->shader != nullptr); + } + } - last_uid = uid; + last_uid = uid; - VSCache::iterator iter = vshaders.find(uid); - if (iter != vshaders.end()) - { - const VSCacheEntry &entry = iter->second; - last_entry = &entry; + VSCache::iterator iter = vshaders.find(uid); + if (iter != vshaders.end()) + { + const VSCacheEntry& entry = iter->second; + last_entry = &entry; - GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); - return (entry.shader != nullptr); - } + GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); + return (entry.shader != nullptr); + } - ShaderCode code = GenerateVertexShaderCode(API_D3D); + ShaderCode code = GenerateVertexShaderCode(API_D3D); - D3DBlob* pbytecode = nullptr; - D3D::CompileVertexShader(code.GetBuffer(), &pbytecode); + D3DBlob* pbytecode = nullptr; + D3D::CompileVertexShader(code.GetBuffer(), &pbytecode); - if (pbytecode == nullptr) - { - GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); - return false; - } - g_vs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); + if (pbytecode == nullptr) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); + return false; + } + g_vs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); - bool success = InsertByteCode(uid, pbytecode); - pbytecode->Release(); + bool success = InsertByteCode(uid, pbytecode); + pbytecode->Release(); - if (g_ActiveConfig.bEnableShaderDebugging && success) - { - vshaders[uid].code = code.GetBuffer(); - } + if (g_ActiveConfig.bEnableShaderDebugging && success) + { + vshaders[uid].code = code.GetBuffer(); + } - GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); - return success; + GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); + return success; } -bool VertexShaderCache::InsertByteCode(const VertexShaderUid &uid, D3DBlob* bcodeblob) +bool VertexShaderCache::InsertByteCode(const VertexShaderUid& uid, D3DBlob* bcodeblob) { - ID3D11VertexShader* shader = D3D::CreateVertexShaderFromByteCode(bcodeblob); - if (shader == nullptr) - return false; + ID3D11VertexShader* shader = D3D::CreateVertexShaderFromByteCode(bcodeblob); + if (shader == nullptr) + return false; - // TODO: Somehow make the debug name a bit more specific - D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a vertex shader of VertexShaderCache"); + // TODO: Somehow make the debug name a bit more specific + D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a vertex shader of VertexShaderCache"); - // Make an entry in the table - VSCacheEntry entry; - entry.shader = shader; - entry.SetByteCode(bcodeblob); + // Make an entry in the table + VSCacheEntry entry; + entry.shader = shader; + entry.SetByteCode(bcodeblob); - vshaders[uid] = entry; - last_entry = &vshaders[uid]; + vshaders[uid] = entry; + last_entry = &vshaders[uid]; - INCSTAT(stats.numVertexShadersCreated); - SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size()); + INCSTAT(stats.numVertexShadersCreated); + SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size()); - return true; + return true; } } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/VertexShaderCache.h b/Source/Core/VideoBackends/D3D/VertexShaderCache.h index 2d7afa2d20..d680fca6de 100644 --- a/Source/Core/VideoBackends/D3D/VertexShaderCache.h +++ b/Source/Core/VideoBackends/D3D/VertexShaderCache.h @@ -11,55 +11,55 @@ #include "VideoCommon/VertexShaderGen.h" -namespace DX11 { - +namespace DX11 +{ class VertexShaderCache { public: - static void Init(); - static void Clear(); - static void Shutdown(); - static bool SetShader(); // TODO: Should be renamed to LoadShader + static void Init(); + static void Clear(); + static void Shutdown(); + static bool SetShader(); // TODO: Should be renamed to LoadShader - static ID3D11VertexShader* GetActiveShader() { return last_entry->shader; } - static D3DBlob* GetActiveShaderBytecode() { return last_entry->bytecode; } - static ID3D11Buffer* &GetConstantBuffer(); + static ID3D11VertexShader* GetActiveShader() { return last_entry->shader; } + static D3DBlob* GetActiveShaderBytecode() { return last_entry->bytecode; } + static ID3D11Buffer*& GetConstantBuffer(); - static ID3D11VertexShader* GetSimpleVertexShader(); - static ID3D11VertexShader* GetClearVertexShader(); - static ID3D11InputLayout* GetSimpleInputLayout(); - static ID3D11InputLayout* GetClearInputLayout(); + static ID3D11VertexShader* GetSimpleVertexShader(); + static ID3D11VertexShader* GetClearVertexShader(); + static ID3D11InputLayout* GetSimpleInputLayout(); + static ID3D11InputLayout* GetClearInputLayout(); - static bool VertexShaderCache::InsertByteCode(const VertexShaderUid &uid, D3DBlob* bcodeblob); + static bool VertexShaderCache::InsertByteCode(const VertexShaderUid& uid, D3DBlob* bcodeblob); private: - struct VSCacheEntry - { - ID3D11VertexShader* shader; - D3DBlob* bytecode; // needed to initialize the input layout + struct VSCacheEntry + { + ID3D11VertexShader* shader; + D3DBlob* bytecode; // needed to initialize the input layout - std::string code; + std::string code; - VSCacheEntry() : shader(nullptr), bytecode(nullptr) {} - void SetByteCode(D3DBlob* blob) - { - SAFE_RELEASE(bytecode); - bytecode = blob; - blob->AddRef(); - } - void Destroy() - { - SAFE_RELEASE(shader); - SAFE_RELEASE(bytecode); - } - }; - typedef std::map VSCache; + VSCacheEntry() : shader(nullptr), bytecode(nullptr) {} + void SetByteCode(D3DBlob* blob) + { + SAFE_RELEASE(bytecode); + bytecode = blob; + blob->AddRef(); + } + void Destroy() + { + SAFE_RELEASE(shader); + SAFE_RELEASE(bytecode); + } + }; + typedef std::map VSCache; - static VSCache vshaders; - static const VSCacheEntry* last_entry; - static VertexShaderUid last_uid; + static VSCache vshaders; + static const VSCacheEntry* last_entry; + static VertexShaderUid last_uid; - static UidChecker vertex_uid_checker; + static UidChecker vertex_uid_checker; }; } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/VideoBackend.h b/Source/Core/VideoBackends/D3D/VideoBackend.h index 7f9b54821e..59491f735d 100644 --- a/Source/Core/VideoBackends/D3D/VideoBackend.h +++ b/Source/Core/VideoBackends/D3D/VideoBackend.h @@ -9,24 +9,21 @@ namespace DX11 { - class VideoBackend : public VideoBackendBase { - bool Initialize(void*) override; - void Shutdown() override; + bool Initialize(void*) override; + void Shutdown() override; - std::string GetName() const override; - std::string GetDisplayName() const override; + std::string GetName() const override; + std::string GetDisplayName() const override; - void Video_Prepare() override; - void Video_Cleanup() override; + void Video_Prepare() override; + void Video_Cleanup() override; - void ShowConfig(void* parent) override; + void ShowConfig(void* parent) override; - unsigned int PeekMessages() override; + unsigned int PeekMessages() override; - void* m_window_handle; + void* m_window_handle; }; - } - diff --git a/Source/Core/VideoBackends/D3D/XFBEncoder.cpp b/Source/Core/VideoBackends/D3D/XFBEncoder.cpp index e1e93a6966..ef106dffa8 100644 --- a/Source/Core/VideoBackends/D3D/XFBEncoder.cpp +++ b/Source/Core/VideoBackends/D3D/XFBEncoder.cpp @@ -2,372 +2,366 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoBackends/D3D/XFBEncoder.h" #include "Common/CommonTypes.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DBlob.h" #include "VideoBackends/D3D/D3DShader.h" #include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/FramebufferManager.h" #include "VideoBackends/D3D/Render.h" -#include "VideoBackends/D3D/XFBEncoder.h" namespace DX11 { - -union XFBEncodeParams -{ - struct - { - FLOAT Width; // Width and height of encoded XFB in luma pixels - FLOAT Height; - FLOAT TexLeft; // Normalized tex coordinates of XFB source area in EFB texture - FLOAT TexTop; - FLOAT TexRight; - FLOAT TexBottom; - FLOAT Gamma; - }; - // Constant buffers must be a multiple of 16 bytes in size - u8 pad[32]; // Pad to the next multiple of 16 +union XFBEncodeParams { + struct + { + FLOAT Width; // Width and height of encoded XFB in luma pixels + FLOAT Height; + FLOAT TexLeft; // Normalized tex coordinates of XFB source area in EFB texture + FLOAT TexTop; + FLOAT TexRight; + FLOAT TexBottom; + FLOAT Gamma; + }; + // Constant buffers must be a multiple of 16 bytes in size + u8 pad[32]; // Pad to the next multiple of 16 }; static const char XFB_ENCODE_VS[] = -"// dolphin-emu XFB encoder vertex shader\n" + "// dolphin-emu XFB encoder vertex shader\n" -"cbuffer cbParams : register(b0)\n" -"{\n" - "struct\n" // Should match XFBEncodeParams above - "{\n" - "float Width;\n" - "float Height;\n" - "float TexLeft;\n" - "float TexTop;\n" - "float TexRight;\n" - "float TexBottom;\n" - "float Gamma;\n" - "} Params;\n" -"}\n" + "cbuffer cbParams : register(b0)\n" + "{\n" + "struct\n" // Should match XFBEncodeParams above + "{\n" + "float Width;\n" + "float Height;\n" + "float TexLeft;\n" + "float TexTop;\n" + "float TexRight;\n" + "float TexBottom;\n" + "float Gamma;\n" + "} Params;\n" + "}\n" -"struct Output\n" -"{\n" - "float4 Pos : SV_Position;\n" - "float2 Coord : ENCODECOORD;\n" -"};\n" + "struct Output\n" + "{\n" + "float4 Pos : SV_Position;\n" + "float2 Coord : ENCODECOORD;\n" + "};\n" -"Output main(in float2 Pos : POSITION)\n" -"{\n" - "Output result;\n" - "result.Pos = float4(2*Pos.x-1, -2*Pos.y+1, 0, 1);\n" - "result.Coord = Pos * float2(floor(Params.Width/2), Params.Height);\n" - "return result;\n" -"}\n" -; + "Output main(in float2 Pos : POSITION)\n" + "{\n" + "Output result;\n" + "result.Pos = float4(2*Pos.x-1, -2*Pos.y+1, 0, 1);\n" + "result.Coord = Pos * float2(floor(Params.Width/2), Params.Height);\n" + "return result;\n" + "}\n"; static const char XFB_ENCODE_PS[] = -"// dolphin-emu XFB encoder pixel shader\n" + "// dolphin-emu XFB encoder pixel shader\n" -"cbuffer cbParams : register(b0)\n" -"{\n" - "struct\n" // Should match XFBEncodeParams above - "{\n" - "float Width;\n" - "float Height;\n" - "float TexLeft;\n" - "float TexTop;\n" - "float TexRight;\n" - "float TexBottom;\n" - "float Gamma;\n" - "} Params;\n" -"}\n" + "cbuffer cbParams : register(b0)\n" + "{\n" + "struct\n" // Should match XFBEncodeParams above + "{\n" + "float Width;\n" + "float Height;\n" + "float TexLeft;\n" + "float TexTop;\n" + "float TexRight;\n" + "float TexBottom;\n" + "float Gamma;\n" + "} Params;\n" + "}\n" -"Texture2DArray EFBTexture : register(t0);\n" -"sampler EFBSampler : register(s0);\n" + "Texture2DArray EFBTexture : register(t0);\n" + "sampler EFBSampler : register(s0);\n" -// GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see -// -"static const float3x4 RGB_TO_YCBCR = float3x4(\n" - "0.257, 0.504, 0.098, 16.0/255.0,\n" - "-0.148, -0.291, 0.439, 128.0/255.0,\n" - "0.439, -0.368, -0.071, 128.0/255.0\n" - ");\n" + // GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see + // + "static const float3x4 RGB_TO_YCBCR = float3x4(\n" + "0.257, 0.504, 0.098, 16.0/255.0,\n" + "-0.148, -0.291, 0.439, 128.0/255.0,\n" + "0.439, -0.368, -0.071, 128.0/255.0\n" + ");\n" -"float3 SampleEFB(float2 coord)\n" -"{\n" - "float2 texCoord = lerp(float2(Params.TexLeft,Params.TexTop), float2(Params.TexRight,Params.TexBottom), coord / float2(Params.Width,Params.Height));\n" - "return EFBTexture.Sample(EFBSampler, float3(texCoord, 0.0)).rgb;\n" -"}\n" + "float3 SampleEFB(float2 coord)\n" + "{\n" + "float2 texCoord = lerp(float2(Params.TexLeft,Params.TexTop), " + "float2(Params.TexRight,Params.TexBottom), coord / float2(Params.Width,Params.Height));\n" + "return EFBTexture.Sample(EFBSampler, float3(texCoord, 0.0)).rgb;\n" + "}\n" -"void main(out float4 ocol0 : SV_Target, in float4 Pos : SV_Position, in float2 Coord : ENCODECOORD)\n" -"{\n" - // Multiplying X by 2, moves pixel centers from (x+0.5) to (2x+1) instead of (2x+0.5), so subtract 0.5 to compensate - "float2 baseCoord = Coord * float2(2,1) - float2(0.5,0);\n" - // FIXME: Shall we apply gamma here, or apply it below to the Y components? - // Be careful if you apply it to Y! The Y components are in the range (16..235) / 255. - "float3 sampleL = pow(abs(SampleEFB(baseCoord+float2(-1,0))), Params.Gamma);\n" // Left - "float3 sampleM = pow(abs(SampleEFB(baseCoord)), Params.Gamma);\n" // Middle - "float3 sampleR = pow(abs(SampleEFB(baseCoord+float2(1,0))), Params.Gamma);\n" // Right + "void main(out float4 ocol0 : SV_Target, in float4 Pos : SV_Position, in float2 Coord : " + "ENCODECOORD)\n" + "{\n" + // Multiplying X by 2, moves pixel centers from (x+0.5) to (2x+1) instead of (2x+0.5), so + // subtract 0.5 to compensate + "float2 baseCoord = Coord * float2(2,1) - float2(0.5,0);\n" + // FIXME: Shall we apply gamma here, or apply it below to the Y components? + // Be careful if you apply it to Y! The Y components are in the range (16..235) / 255. + "float3 sampleL = pow(abs(SampleEFB(baseCoord+float2(-1,0))), Params.Gamma);\n" // Left + "float3 sampleM = pow(abs(SampleEFB(baseCoord)), Params.Gamma);\n" // Middle + "float3 sampleR = pow(abs(SampleEFB(baseCoord+float2(1,0))), Params.Gamma);\n" // Right - "float3 yuvL = mul(RGB_TO_YCBCR, float4(sampleL,1));\n" - "float3 yuvM = mul(RGB_TO_YCBCR, float4(sampleM,1));\n" - "float3 yuvR = mul(RGB_TO_YCBCR, float4(sampleR,1));\n" + "float3 yuvL = mul(RGB_TO_YCBCR, float4(sampleL,1));\n" + "float3 yuvM = mul(RGB_TO_YCBCR, float4(sampleM,1));\n" + "float3 yuvR = mul(RGB_TO_YCBCR, float4(sampleR,1));\n" - // The Y components correspond to two EFB pixels, while the U and V are - // made from a blend of three EFB pixels. - "float y0 = yuvM.r;\n" - "float y1 = yuvR.r;\n" - "float u0 = 0.25*yuvL.g + 0.5*yuvM.g + 0.25*yuvR.g;\n" - "float v0 = 0.25*yuvL.b + 0.5*yuvM.b + 0.25*yuvR.b;\n" + // The Y components correspond to two EFB pixels, while the U and V are + // made from a blend of three EFB pixels. + "float y0 = yuvM.r;\n" + "float y1 = yuvR.r;\n" + "float u0 = 0.25*yuvL.g + 0.5*yuvM.g + 0.25*yuvR.g;\n" + "float v0 = 0.25*yuvL.b + 0.5*yuvM.b + 0.25*yuvR.b;\n" - "ocol0 = float4(y0, u0, y1, v0);\n" -"}\n" -; + "ocol0 = float4(y0, u0, y1, v0);\n" + "}\n"; static const D3D11_INPUT_ELEMENT_DESC QUAD_LAYOUT_DESC[] = { - { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 } -}; + {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}}; static const struct QuadVertex { - float posX; - float posY; -} QUAD_VERTS[4] = { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }; + float posX; + float posY; +} QUAD_VERTS[4] = {{0, 0}, {1, 0}, {0, 1}, {1, 1}}; XFBEncoder::XFBEncoder() - : m_out(nullptr), m_outRTV(nullptr), m_outStage(nullptr), m_encodeParams(nullptr), - m_quad(nullptr), m_vShader(nullptr), m_quadLayout(nullptr), m_pShader(nullptr), - m_xfbEncodeBlendState(nullptr), m_xfbEncodeDepthState(nullptr), - m_xfbEncodeRastState(nullptr), m_efbSampler(nullptr) -{ } + : m_out(nullptr), m_outRTV(nullptr), m_outStage(nullptr), m_encodeParams(nullptr), + m_quad(nullptr), m_vShader(nullptr), m_quadLayout(nullptr), m_pShader(nullptr), + m_xfbEncodeBlendState(nullptr), m_xfbEncodeDepthState(nullptr), m_xfbEncodeRastState(nullptr), + m_efbSampler(nullptr) +{ +} void XFBEncoder::Init() { - HRESULT hr; + HRESULT hr; - // Create output texture + // Create output texture - // The pixel shader can generate one YUYV entry per pixel. One YUYV entry - // is created for every two EFB pixels. - D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC( - DXGI_FORMAT_R8G8B8A8_UNORM, MAX_XFB_WIDTH/2, MAX_XFB_HEIGHT, 1, 1, - D3D11_BIND_RENDER_TARGET); - hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_out); - CHECK(SUCCEEDED(hr), "create xfb encoder output texture"); - D3D::SetDebugObjectName(m_out, "xfb encoder output texture"); + // The pixel shader can generate one YUYV entry per pixel. One YUYV entry + // is created for every two EFB pixels. + D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, MAX_XFB_WIDTH / 2, + MAX_XFB_HEIGHT, 1, 1, D3D11_BIND_RENDER_TARGET); + hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_out); + CHECK(SUCCEEDED(hr), "create xfb encoder output texture"); + D3D::SetDebugObjectName(m_out, "xfb encoder output texture"); - // Create output render target view + // Create output render target view - D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC(m_out, - D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM); - hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV); - CHECK(SUCCEEDED(hr), "create xfb encoder output texture rtv"); - D3D::SetDebugObjectName(m_outRTV, "xfb encoder output rtv"); + D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC( + m_out, D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM); + hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV); + CHECK(SUCCEEDED(hr), "create xfb encoder output texture rtv"); + D3D::SetDebugObjectName(m_outRTV, "xfb encoder output rtv"); - // Create output staging buffer + // Create output staging buffer - t2dd.Usage = D3D11_USAGE_STAGING; - t2dd.BindFlags = 0; - t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_outStage); - CHECK(SUCCEEDED(hr), "create xfb encoder output staging buffer"); - D3D::SetDebugObjectName(m_outStage, "xfb encoder output staging buffer"); + t2dd.Usage = D3D11_USAGE_STAGING; + t2dd.BindFlags = 0; + t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_outStage); + CHECK(SUCCEEDED(hr), "create xfb encoder output staging buffer"); + D3D::SetDebugObjectName(m_outStage, "xfb encoder output staging buffer"); - // Create constant buffer for uploading params to shaders + // Create constant buffer for uploading params to shaders - D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(XFBEncodeParams), - D3D11_BIND_CONSTANT_BUFFER); - hr = D3D::device->CreateBuffer(&bd, nullptr, &m_encodeParams); - CHECK(SUCCEEDED(hr), "create xfb encode params buffer"); - D3D::SetDebugObjectName(m_encodeParams, "xfb encoder params buffer"); + D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(XFBEncodeParams), D3D11_BIND_CONSTANT_BUFFER); + hr = D3D::device->CreateBuffer(&bd, nullptr, &m_encodeParams); + CHECK(SUCCEEDED(hr), "create xfb encode params buffer"); + D3D::SetDebugObjectName(m_encodeParams, "xfb encoder params buffer"); - // Create vertex quad + // Create vertex quad - bd = CD3D11_BUFFER_DESC(sizeof(QUAD_VERTS), D3D11_BIND_VERTEX_BUFFER, - D3D11_USAGE_IMMUTABLE); - D3D11_SUBRESOURCE_DATA srd = { QUAD_VERTS, 0, 0 }; + bd = CD3D11_BUFFER_DESC(sizeof(QUAD_VERTS), D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_IMMUTABLE); + D3D11_SUBRESOURCE_DATA srd = {QUAD_VERTS, 0, 0}; - hr = D3D::device->CreateBuffer(&bd, &srd, &m_quad); - CHECK(SUCCEEDED(hr), "create xfb encode quad vertex buffer"); - D3D::SetDebugObjectName(m_quad, "xfb encoder quad vertex buffer"); + hr = D3D::device->CreateBuffer(&bd, &srd, &m_quad); + CHECK(SUCCEEDED(hr), "create xfb encode quad vertex buffer"); + D3D::SetDebugObjectName(m_quad, "xfb encoder quad vertex buffer"); - // Create vertex shader + // Create vertex shader - D3DBlob* bytecode = nullptr; - if (!D3D::CompileVertexShader(XFB_ENCODE_VS, &bytecode)) - { - ERROR_LOG(VIDEO, "XFB encode vertex shader failed to compile"); - return; - } + D3DBlob* bytecode = nullptr; + if (!D3D::CompileVertexShader(XFB_ENCODE_VS, &bytecode)) + { + ERROR_LOG(VIDEO, "XFB encode vertex shader failed to compile"); + return; + } - hr = D3D::device->CreateVertexShader(bytecode->Data(), bytecode->Size(), nullptr, &m_vShader); - CHECK(SUCCEEDED(hr), "create xfb encode vertex shader"); - D3D::SetDebugObjectName(m_vShader, "xfb encoder vertex shader"); + hr = D3D::device->CreateVertexShader(bytecode->Data(), bytecode->Size(), nullptr, &m_vShader); + CHECK(SUCCEEDED(hr), "create xfb encode vertex shader"); + D3D::SetDebugObjectName(m_vShader, "xfb encoder vertex shader"); - // Create input layout for vertex quad using bytecode from vertex shader + // Create input layout for vertex quad using bytecode from vertex shader - hr = D3D::device->CreateInputLayout(QUAD_LAYOUT_DESC, - sizeof(QUAD_LAYOUT_DESC)/sizeof(D3D11_INPUT_ELEMENT_DESC), - bytecode->Data(), bytecode->Size(), &m_quadLayout); - CHECK(SUCCEEDED(hr), "create xfb encode quad vertex layout"); - D3D::SetDebugObjectName(m_quadLayout, "xfb encoder quad layout"); + hr = D3D::device->CreateInputLayout(QUAD_LAYOUT_DESC, + sizeof(QUAD_LAYOUT_DESC) / sizeof(D3D11_INPUT_ELEMENT_DESC), + bytecode->Data(), bytecode->Size(), &m_quadLayout); + CHECK(SUCCEEDED(hr), "create xfb encode quad vertex layout"); + D3D::SetDebugObjectName(m_quadLayout, "xfb encoder quad layout"); - bytecode->Release(); + bytecode->Release(); - // Create pixel shader + // Create pixel shader - m_pShader = D3D::CompileAndCreatePixelShader(XFB_ENCODE_PS); - if (!m_pShader) - { - ERROR_LOG(VIDEO, "XFB encode pixel shader failed to compile"); - return; - } - D3D::SetDebugObjectName(m_pShader, "xfb encoder pixel shader"); + m_pShader = D3D::CompileAndCreatePixelShader(XFB_ENCODE_PS); + if (!m_pShader) + { + ERROR_LOG(VIDEO, "XFB encode pixel shader failed to compile"); + return; + } + D3D::SetDebugObjectName(m_pShader, "xfb encoder pixel shader"); - // Create blend state + // Create blend state - D3D11_BLEND_DESC bld = CD3D11_BLEND_DESC(CD3D11_DEFAULT()); - hr = D3D::device->CreateBlendState(&bld, &m_xfbEncodeBlendState); - CHECK(SUCCEEDED(hr), "create xfb encode blend state"); - D3D::SetDebugObjectName(m_xfbEncodeBlendState, "xfb encoder blend state"); + D3D11_BLEND_DESC bld = CD3D11_BLEND_DESC(CD3D11_DEFAULT()); + hr = D3D::device->CreateBlendState(&bld, &m_xfbEncodeBlendState); + CHECK(SUCCEEDED(hr), "create xfb encode blend state"); + D3D::SetDebugObjectName(m_xfbEncodeBlendState, "xfb encoder blend state"); - // Create depth state + // Create depth state - D3D11_DEPTH_STENCIL_DESC dsd = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT()); - dsd.DepthEnable = FALSE; - hr = D3D::device->CreateDepthStencilState(&dsd, &m_xfbEncodeDepthState); - CHECK(SUCCEEDED(hr), "create xfb encode depth state"); - D3D::SetDebugObjectName(m_xfbEncodeDepthState, "xfb encoder depth state"); + D3D11_DEPTH_STENCIL_DESC dsd = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT()); + dsd.DepthEnable = FALSE; + hr = D3D::device->CreateDepthStencilState(&dsd, &m_xfbEncodeDepthState); + CHECK(SUCCEEDED(hr), "create xfb encode depth state"); + D3D::SetDebugObjectName(m_xfbEncodeDepthState, "xfb encoder depth state"); - // Create rasterizer state + // Create rasterizer state - D3D11_RASTERIZER_DESC rd = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT()); - rd.CullMode = D3D11_CULL_NONE; - rd.DepthClipEnable = FALSE; - hr = D3D::device->CreateRasterizerState(&rd, &m_xfbEncodeRastState); - CHECK(SUCCEEDED(hr), "create xfb encode rasterizer state"); - D3D::SetDebugObjectName(m_xfbEncodeRastState, "xfb encoder rast state"); + D3D11_RASTERIZER_DESC rd = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT()); + rd.CullMode = D3D11_CULL_NONE; + rd.DepthClipEnable = FALSE; + hr = D3D::device->CreateRasterizerState(&rd, &m_xfbEncodeRastState); + CHECK(SUCCEEDED(hr), "create xfb encode rasterizer state"); + D3D::SetDebugObjectName(m_xfbEncodeRastState, "xfb encoder rast state"); - // Create EFB texture sampler + // Create EFB texture sampler - D3D11_SAMPLER_DESC sd = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT()); - sd.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; - hr = D3D::device->CreateSamplerState(&sd, &m_efbSampler); - CHECK(SUCCEEDED(hr), "create xfb encode texture sampler"); - D3D::SetDebugObjectName(m_efbSampler, "xfb encoder texture sampler"); + D3D11_SAMPLER_DESC sd = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT()); + sd.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; + hr = D3D::device->CreateSamplerState(&sd, &m_efbSampler); + CHECK(SUCCEEDED(hr), "create xfb encode texture sampler"); + D3D::SetDebugObjectName(m_efbSampler, "xfb encoder texture sampler"); } void XFBEncoder::Shutdown() { - SAFE_RELEASE(m_efbSampler); - SAFE_RELEASE(m_xfbEncodeRastState); - SAFE_RELEASE(m_xfbEncodeDepthState); - SAFE_RELEASE(m_xfbEncodeBlendState); - SAFE_RELEASE(m_pShader); - SAFE_RELEASE(m_quadLayout); - SAFE_RELEASE(m_vShader); - SAFE_RELEASE(m_quad); - SAFE_RELEASE(m_encodeParams); - SAFE_RELEASE(m_outStage); - SAFE_RELEASE(m_outRTV); - SAFE_RELEASE(m_out); + SAFE_RELEASE(m_efbSampler); + SAFE_RELEASE(m_xfbEncodeRastState); + SAFE_RELEASE(m_xfbEncodeDepthState); + SAFE_RELEASE(m_xfbEncodeBlendState); + SAFE_RELEASE(m_pShader); + SAFE_RELEASE(m_quadLayout); + SAFE_RELEASE(m_vShader); + SAFE_RELEASE(m_quad); + SAFE_RELEASE(m_encodeParams); + SAFE_RELEASE(m_outStage); + SAFE_RELEASE(m_outRTV); + SAFE_RELEASE(m_out); } void XFBEncoder::Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma) { - HRESULT hr; + HRESULT hr; - // Reset API + // Reset API - g_renderer->ResetAPIState(); + g_renderer->ResetAPIState(); - // Set up all the state for XFB encoding + // Set up all the state for XFB encoding - D3D::stateman->SetPixelShader(m_pShader); - D3D::stateman->SetVertexShader(m_vShader); - D3D::stateman->SetGeometryShader(nullptr); + D3D::stateman->SetPixelShader(m_pShader); + D3D::stateman->SetVertexShader(m_vShader); + D3D::stateman->SetGeometryShader(nullptr); - D3D::stateman->PushBlendState(m_xfbEncodeBlendState); - D3D::stateman->PushDepthState(m_xfbEncodeDepthState); - D3D::stateman->PushRasterizerState(m_xfbEncodeRastState); + D3D::stateman->PushBlendState(m_xfbEncodeBlendState); + D3D::stateman->PushDepthState(m_xfbEncodeDepthState); + D3D::stateman->PushRasterizerState(m_xfbEncodeRastState); - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(width/2), FLOAT(height)); - D3D::context->RSSetViewports(1, &vp); + D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(width / 2), FLOAT(height)); + D3D::context->RSSetViewports(1, &vp); - D3D::stateman->SetInputLayout(m_quadLayout); - D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - UINT stride = sizeof(QuadVertex); - UINT offset = 0; - D3D::stateman->SetVertexBuffer(m_quad, stride, offset); + D3D::stateman->SetInputLayout(m_quadLayout); + D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + UINT stride = sizeof(QuadVertex); + UINT offset = 0; + D3D::stateman->SetVertexBuffer(m_quad, stride, offset); - TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(srcRect); + TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(srcRect); - XFBEncodeParams params = { 0 }; - params.Width = FLOAT(width); - params.Height = FLOAT(height); - params.TexLeft = FLOAT(targetRect.left) / g_renderer->GetTargetWidth(); - params.TexTop = FLOAT(targetRect.top) / g_renderer->GetTargetHeight(); - params.TexRight = FLOAT(targetRect.right) / g_renderer->GetTargetWidth(); - params.TexBottom = FLOAT(targetRect.bottom) / g_renderer->GetTargetHeight(); - params.Gamma = gamma; - D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, ¶ms, 0, 0); + XFBEncodeParams params = {0}; + params.Width = FLOAT(width); + params.Height = FLOAT(height); + params.TexLeft = FLOAT(targetRect.left) / g_renderer->GetTargetWidth(); + params.TexTop = FLOAT(targetRect.top) / g_renderer->GetTargetHeight(); + params.TexRight = FLOAT(targetRect.right) / g_renderer->GetTargetWidth(); + params.TexBottom = FLOAT(targetRect.bottom) / g_renderer->GetTargetHeight(); + params.Gamma = gamma; + D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, ¶ms, 0, 0); - D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr); + D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr); - ID3D11ShaderResourceView* pEFB = FramebufferManager::GetResolvedEFBColorTexture()->GetSRV(); + ID3D11ShaderResourceView* pEFB = FramebufferManager::GetResolvedEFBColorTexture()->GetSRV(); - D3D::stateman->SetVertexConstants(m_encodeParams); - D3D::stateman->SetPixelConstants(m_encodeParams); - D3D::stateman->SetTexture(0, pEFB); - D3D::stateman->SetSampler(0, m_efbSampler); + D3D::stateman->SetVertexConstants(m_encodeParams); + D3D::stateman->SetPixelConstants(m_encodeParams); + D3D::stateman->SetTexture(0, pEFB); + D3D::stateman->SetSampler(0, m_efbSampler); - // Encode! + // Encode! - D3D::stateman->Apply(); - D3D::context->Draw(4, 0); + D3D::stateman->Apply(); + D3D::context->Draw(4, 0); - // Copy to staging buffer + // Copy to staging buffer - D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, width/2, height, 1); - D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox); + D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, width / 2, height, 1); + D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox); - // Clean up state + // Clean up state - D3D::context->OMSetRenderTargets(0, nullptr, nullptr); + D3D::context->OMSetRenderTargets(0, nullptr, nullptr); - D3D::stateman->SetSampler(0, nullptr); - D3D::stateman->SetTexture(0, nullptr); - D3D::stateman->SetPixelConstants(nullptr); - D3D::stateman->SetVertexConstants(nullptr); + D3D::stateman->SetSampler(0, nullptr); + D3D::stateman->SetTexture(0, nullptr); + D3D::stateman->SetPixelConstants(nullptr); + D3D::stateman->SetVertexConstants(nullptr); - D3D::stateman->SetPixelShader(nullptr); - D3D::stateman->SetVertexShader(nullptr); + D3D::stateman->SetPixelShader(nullptr); + D3D::stateman->SetVertexShader(nullptr); - D3D::stateman->PopRasterizerState(); - D3D::stateman->PopDepthState(); - D3D::stateman->PopBlendState(); + D3D::stateman->PopRasterizerState(); + D3D::stateman->PopDepthState(); + D3D::stateman->PopBlendState(); - // Transfer staging buffer to GameCube/Wii RAM + // Transfer staging buffer to GameCube/Wii RAM - D3D11_MAPPED_SUBRESOURCE map = { 0 }; - hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map); - CHECK(SUCCEEDED(hr), "map staging buffer"); + D3D11_MAPPED_SUBRESOURCE map = {0}; + hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map); + CHECK(SUCCEEDED(hr), "map staging buffer"); - u8* src = (u8*)map.pData; - for (unsigned int y = 0; y < height; ++y) - { - memcpy(dst, src, 2*width); - dst += bpmem.copyMipMapStrideChannels*32; - src += map.RowPitch; - } + u8* src = (u8*)map.pData; + for (unsigned int y = 0; y < height; ++y) + { + memcpy(dst, src, 2 * width); + dst += bpmem.copyMipMapStrideChannels * 32; + src += map.RowPitch; + } - D3D::context->Unmap(m_outStage, 0); + D3D::context->Unmap(m_outStage, 0); - // Restore API - g_renderer->RestoreAPIState(); - D3D::stateman->Apply(); // force unbind efb texture as shader resource - D3D::context->OMSetRenderTargets(1, - &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); + // Restore API + g_renderer->RestoreAPIState(); + D3D::stateman->Apply(); // force unbind efb texture as shader resource + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); } - } diff --git a/Source/Core/VideoBackends/D3D/XFBEncoder.h b/Source/Core/VideoBackends/D3D/XFBEncoder.h index b1ab0969b8..91da877b8b 100644 --- a/Source/Core/VideoBackends/D3D/XFBEncoder.h +++ b/Source/Core/VideoBackends/D3D/XFBEncoder.h @@ -19,34 +19,28 @@ struct ID3D11SamplerState; namespace DX11 { - class XFBEncoder { - public: + XFBEncoder(); - XFBEncoder(); + void Init(); + void Shutdown(); - void Init(); - void Shutdown(); - - void Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma); + void Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma); private: - - ID3D11Texture2D* m_out; - ID3D11RenderTargetView* m_outRTV; - ID3D11Texture2D* m_outStage; - ID3D11Buffer* m_encodeParams; - ID3D11Buffer* m_quad; - ID3D11VertexShader* m_vShader; - ID3D11InputLayout* m_quadLayout; - ID3D11PixelShader* m_pShader; - ID3D11BlendState* m_xfbEncodeBlendState; - ID3D11DepthStencilState* m_xfbEncodeDepthState; - ID3D11RasterizerState* m_xfbEncodeRastState; - ID3D11SamplerState* m_efbSampler; - + ID3D11Texture2D* m_out; + ID3D11RenderTargetView* m_outRTV; + ID3D11Texture2D* m_outStage; + ID3D11Buffer* m_encodeParams; + ID3D11Buffer* m_quad; + ID3D11VertexShader* m_vShader; + ID3D11InputLayout* m_quadLayout; + ID3D11PixelShader* m_pShader; + ID3D11BlendState* m_xfbEncodeBlendState; + ID3D11DepthStencilState* m_xfbEncodeDepthState; + ID3D11RasterizerState* m_xfbEncodeRastState; + ID3D11SamplerState* m_efbSampler; }; - } diff --git a/Source/Core/VideoBackends/D3D/main.cpp b/Source/Core/VideoBackends/D3D/main.cpp index e5766540ee..8fd9989a92 100644 --- a/Source/Core/VideoBackends/D3D/main.cpp +++ b/Source/Core/VideoBackends/D3D/main.cpp @@ -38,198 +38,198 @@ namespace DX11 { - unsigned int VideoBackend::PeekMessages() { - MSG msg; - while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - return FALSE; - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return TRUE; + MSG msg; + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + return FALSE; + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return TRUE; } std::string VideoBackend::GetName() const { - return "D3D"; + return "D3D"; } std::string VideoBackend::GetDisplayName() const { - return "Direct3D 11"; + return "Direct3D 11"; } void InitBackendInfo() { - HRESULT hr = DX11::D3D::LoadDXGI(); - if (SUCCEEDED(hr)) hr = DX11::D3D::LoadD3D(); - if (FAILED(hr)) - { - DX11::D3D::UnloadDXGI(); - return; - } + HRESULT hr = DX11::D3D::LoadDXGI(); + if (SUCCEEDED(hr)) + hr = DX11::D3D::LoadD3D(); + if (FAILED(hr)) + { + DX11::D3D::UnloadDXGI(); + return; + } - g_Config.backend_info.APIType = API_D3D; - g_Config.backend_info.bSupportsExclusiveFullscreen = true; - g_Config.backend_info.bSupportsDualSourceBlend = true; - g_Config.backend_info.bSupportsPrimitiveRestart = true; - g_Config.backend_info.bSupportsOversizedViewports = false; - g_Config.backend_info.bSupportsGeometryShaders = true; - g_Config.backend_info.bSupports3DVision = true; - g_Config.backend_info.bSupportsPostProcessing = false; - g_Config.backend_info.bSupportsPaletteConversion = true; - g_Config.backend_info.bSupportsClipControl = true; + g_Config.backend_info.APIType = API_D3D; + g_Config.backend_info.bSupportsExclusiveFullscreen = true; + g_Config.backend_info.bSupportsDualSourceBlend = true; + g_Config.backend_info.bSupportsPrimitiveRestart = true; + g_Config.backend_info.bSupportsOversizedViewports = false; + g_Config.backend_info.bSupportsGeometryShaders = true; + g_Config.backend_info.bSupports3DVision = true; + g_Config.backend_info.bSupportsPostProcessing = false; + g_Config.backend_info.bSupportsPaletteConversion = true; + g_Config.backend_info.bSupportsClipControl = true; - IDXGIFactory* factory; - IDXGIAdapter* ad; - hr = DX11::PCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory); - if (FAILED(hr)) - PanicAlert("Failed to create IDXGIFactory object"); + IDXGIFactory* factory; + IDXGIAdapter* ad; + hr = DX11::PCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory); + if (FAILED(hr)) + PanicAlert("Failed to create IDXGIFactory object"); - // adapters - g_Config.backend_info.Adapters.clear(); - g_Config.backend_info.AAModes.clear(); - while (factory->EnumAdapters((UINT)g_Config.backend_info.Adapters.size(), &ad) != DXGI_ERROR_NOT_FOUND) - { - const size_t adapter_index = g_Config.backend_info.Adapters.size(); + // adapters + g_Config.backend_info.Adapters.clear(); + g_Config.backend_info.AAModes.clear(); + while (factory->EnumAdapters((UINT)g_Config.backend_info.Adapters.size(), &ad) != + DXGI_ERROR_NOT_FOUND) + { + const size_t adapter_index = g_Config.backend_info.Adapters.size(); - DXGI_ADAPTER_DESC desc; - ad->GetDesc(&desc); + DXGI_ADAPTER_DESC desc; + ad->GetDesc(&desc); - // TODO: These don't get updated on adapter change, yet - if (adapter_index == g_Config.iAdapter) - { - std::string samples; - std::vector modes = DX11::D3D::EnumAAModes(ad); - // First iteration will be 1. This equals no AA. - for (unsigned int i = 0; i < modes.size(); ++i) - { - g_Config.backend_info.AAModes.push_back(modes[i].Count); - } + // TODO: These don't get updated on adapter change, yet + if (adapter_index == g_Config.iAdapter) + { + std::string samples; + std::vector modes = DX11::D3D::EnumAAModes(ad); + // First iteration will be 1. This equals no AA. + for (unsigned int i = 0; i < modes.size(); ++i) + { + g_Config.backend_info.AAModes.push_back(modes[i].Count); + } - bool shader_model_5_supported = (DX11::D3D::GetFeatureLevel(ad) >= D3D_FEATURE_LEVEL_11_0); + bool shader_model_5_supported = (DX11::D3D::GetFeatureLevel(ad) >= D3D_FEATURE_LEVEL_11_0); - // Requires the earlydepthstencil attribute (only available in shader model 5) - g_Config.backend_info.bSupportsEarlyZ = shader_model_5_supported; + // Requires the earlydepthstencil attribute (only available in shader model 5) + g_Config.backend_info.bSupportsEarlyZ = shader_model_5_supported; - // Requires full UAV functionality (only available in shader model 5) - g_Config.backend_info.bSupportsBBox = shader_model_5_supported; + // Requires full UAV functionality (only available in shader model 5) + g_Config.backend_info.bSupportsBBox = shader_model_5_supported; - // Requires the instance attribute (only available in shader model 5) - g_Config.backend_info.bSupportsGSInstancing = shader_model_5_supported; + // Requires the instance attribute (only available in shader model 5) + g_Config.backend_info.bSupportsGSInstancing = shader_model_5_supported; - // Sample shading requires shader model 5 - g_Config.backend_info.bSupportsSSAA = shader_model_5_supported; - } - g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description)); - ad->Release(); - } - factory->Release(); + // Sample shading requires shader model 5 + g_Config.backend_info.bSupportsSSAA = shader_model_5_supported; + } + g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description)); + ad->Release(); + } + factory->Release(); - // Clear ppshaders string vector - g_Config.backend_info.PPShaders.clear(); - g_Config.backend_info.AnaglyphShaders.clear(); + // Clear ppshaders string vector + g_Config.backend_info.PPShaders.clear(); + g_Config.backend_info.AnaglyphShaders.clear(); - DX11::D3D::UnloadDXGI(); - DX11::D3D::UnloadD3D(); + DX11::D3D::UnloadDXGI(); + DX11::D3D::UnloadD3D(); } -void VideoBackend::ShowConfig(void *hParent) +void VideoBackend::ShowConfig(void* hParent) { - InitBackendInfo(); - Host_ShowVideoConfig(hParent, GetDisplayName(), "gfx_dx11"); + InitBackendInfo(); + Host_ShowVideoConfig(hParent, GetDisplayName(), "gfx_dx11"); } -bool VideoBackend::Initialize(void *window_handle) +bool VideoBackend::Initialize(void* window_handle) { - if (window_handle == nullptr) - return false; + if (window_handle == nullptr) + return false; - InitializeShared(); - InitBackendInfo(); + InitializeShared(); + InitBackendInfo(); - frameCount = 0; + frameCount = 0; - if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini")) - g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"); - else - g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "gfx_dx11.ini"); + if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini")) + g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"); + else + g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "gfx_dx11.ini"); - g_Config.GameIniLoad(); - g_Config.UpdateProjectionHack(); - g_Config.VerifyValidity(); - UpdateActiveConfig(); + g_Config.GameIniLoad(); + g_Config.UpdateProjectionHack(); + g_Config.VerifyValidity(); + UpdateActiveConfig(); - m_window_handle = window_handle; - m_initialized = true; + m_window_handle = window_handle; + m_initialized = true; - return true; + return true; } void VideoBackend::Video_Prepare() { - // internal interfaces - g_renderer = std::make_unique(m_window_handle); - g_texture_cache = std::make_unique(); - g_vertex_manager = std::make_unique(); - g_perf_query = std::make_unique(); - VertexShaderCache::Init(); - PixelShaderCache::Init(); - GeometryShaderCache::Init(); - D3D::InitUtils(); + // internal interfaces + g_renderer = std::make_unique(m_window_handle); + g_texture_cache = std::make_unique(); + g_vertex_manager = std::make_unique(); + g_perf_query = std::make_unique(); + VertexShaderCache::Init(); + PixelShaderCache::Init(); + GeometryShaderCache::Init(); + D3D::InitUtils(); - // VideoCommon - BPInit(); - Fifo::Init(); - IndexGenerator::Init(); - VertexLoaderManager::Init(); - OpcodeDecoder::Init(); - VertexShaderManager::Init(); - PixelShaderManager::Init(); - GeometryShaderManager::Init(); - CommandProcessor::Init(); - PixelEngine::Init(); - BBox::Init(); + // VideoCommon + BPInit(); + Fifo::Init(); + IndexGenerator::Init(); + VertexLoaderManager::Init(); + OpcodeDecoder::Init(); + VertexShaderManager::Init(); + PixelShaderManager::Init(); + GeometryShaderManager::Init(); + CommandProcessor::Init(); + PixelEngine::Init(); + BBox::Init(); - // Tell the host that the window is ready - Host_Message(WM_USER_CREATE); + // Tell the host that the window is ready + Host_Message(WM_USER_CREATE); } void VideoBackend::Shutdown() { - m_initialized = false; + m_initialized = false; - // TODO: should be in Video_Cleanup - if (g_renderer) - { - // VideoCommon - Fifo::Shutdown(); - CommandProcessor::Shutdown(); - GeometryShaderManager::Shutdown(); - PixelShaderManager::Shutdown(); - VertexShaderManager::Shutdown(); - OpcodeDecoder::Shutdown(); - VertexLoaderManager::Shutdown(); + // TODO: should be in Video_Cleanup + if (g_renderer) + { + // VideoCommon + Fifo::Shutdown(); + CommandProcessor::Shutdown(); + GeometryShaderManager::Shutdown(); + PixelShaderManager::Shutdown(); + VertexShaderManager::Shutdown(); + OpcodeDecoder::Shutdown(); + VertexLoaderManager::Shutdown(); - // internal interfaces - D3D::ShutdownUtils(); - PixelShaderCache::Shutdown(); - VertexShaderCache::Shutdown(); - GeometryShaderCache::Shutdown(); - BBox::Shutdown(); + // internal interfaces + D3D::ShutdownUtils(); + PixelShaderCache::Shutdown(); + VertexShaderCache::Shutdown(); + GeometryShaderCache::Shutdown(); + BBox::Shutdown(); - g_perf_query.reset(); - g_vertex_manager.reset(); - g_texture_cache.reset(); - g_renderer.reset(); - } + g_perf_query.reset(); + g_vertex_manager.reset(); + g_texture_cache.reset(); + g_renderer.reset(); + } } void VideoBackend::Video_Cleanup() { } - } diff --git a/Source/Core/VideoBackends/D3D12/BoundingBox.cpp b/Source/Core/VideoBackends/D3D12/BoundingBox.cpp index b9ee9b4929..5ff7d7a3f1 100644 --- a/Source/Core/VideoBackends/D3D12/BoundingBox.cpp +++ b/Source/Core/VideoBackends/D3D12/BoundingBox.cpp @@ -18,7 +18,6 @@ namespace DX12 { - constexpr size_t BBOX_BUFFER_SIZE = sizeof(int) * 4; constexpr size_t BBOX_STREAM_BUFFER_SIZE = BBOX_BUFFER_SIZE * 128; @@ -30,123 +29,133 @@ static D3D12_GPU_DESCRIPTOR_HANDLE s_bbox_descriptor_handle; void BBox::Init() { - CD3DX12_RESOURCE_DESC buffer_desc(CD3DX12_RESOURCE_DESC::Buffer(BBOX_BUFFER_SIZE, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, 0)); - CD3DX12_RESOURCE_DESC staging_buffer_desc(CD3DX12_RESOURCE_DESC::Buffer(BBOX_BUFFER_SIZE, D3D12_RESOURCE_FLAG_NONE, 0)); + CD3DX12_RESOURCE_DESC buffer_desc(CD3DX12_RESOURCE_DESC::Buffer( + BBOX_BUFFER_SIZE, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, 0)); + CD3DX12_RESOURCE_DESC staging_buffer_desc( + CD3DX12_RESOURCE_DESC::Buffer(BBOX_BUFFER_SIZE, D3D12_RESOURCE_FLAG_NONE, 0)); - CheckHR(D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), - D3D12_HEAP_FLAG_NONE, - &buffer_desc, - D3D12_RESOURCE_STATE_UNORDERED_ACCESS, - nullptr, - IID_PPV_ARGS(&s_bbox_buffer))); + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &buffer_desc, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, IID_PPV_ARGS(&s_bbox_buffer))); - CheckHR(D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), - D3D12_HEAP_FLAG_NONE, - &staging_buffer_desc, - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(&s_bbox_staging_buffer))); + CheckHR(D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), + D3D12_HEAP_FLAG_NONE, &staging_buffer_desc, + D3D12_RESOURCE_STATE_COPY_DEST, nullptr, + IID_PPV_ARGS(&s_bbox_staging_buffer))); - s_bbox_stream_buffer = std::make_unique(BBOX_STREAM_BUFFER_SIZE, BBOX_STREAM_BUFFER_SIZE, nullptr); + s_bbox_stream_buffer = + std::make_unique(BBOX_STREAM_BUFFER_SIZE, BBOX_STREAM_BUFFER_SIZE, nullptr); - // D3D12 root signature UAV must be raw or structured buffers, not typed. Since we used a typed buffer, - // we have to use a descriptor table. Luckily, we only have to allocate this once, and it never changes. - D3D12_CPU_DESCRIPTOR_HANDLE cpu_descriptor_handle; - if (!D3D::gpu_descriptor_heap_mgr->Allocate(&cpu_descriptor_handle, &s_bbox_descriptor_handle, nullptr, false)) - PanicAlert("Failed to create bounding box UAV descriptor"); + // D3D12 root signature UAV must be raw or structured buffers, not typed. Since we used a typed + // buffer, + // we have to use a descriptor table. Luckily, we only have to allocate this once, and it never + // changes. + D3D12_CPU_DESCRIPTOR_HANDLE cpu_descriptor_handle; + if (!D3D::gpu_descriptor_heap_mgr->Allocate(&cpu_descriptor_handle, &s_bbox_descriptor_handle, + nullptr, false)) + PanicAlert("Failed to create bounding box UAV descriptor"); - D3D12_UNORDERED_ACCESS_VIEW_DESC view_desc = { DXGI_FORMAT_R32_SINT, D3D12_UAV_DIMENSION_BUFFER }; - view_desc.Buffer.FirstElement = 0; - view_desc.Buffer.NumElements = 4; - view_desc.Buffer.StructureByteStride = 0; - view_desc.Buffer.CounterOffsetInBytes = 0; - view_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; - D3D::device12->CreateUnorderedAccessView(s_bbox_buffer, nullptr, &view_desc, cpu_descriptor_handle); + D3D12_UNORDERED_ACCESS_VIEW_DESC view_desc = {DXGI_FORMAT_R32_SINT, D3D12_UAV_DIMENSION_BUFFER}; + view_desc.Buffer.FirstElement = 0; + view_desc.Buffer.NumElements = 4; + view_desc.Buffer.StructureByteStride = 0; + view_desc.Buffer.CounterOffsetInBytes = 0; + view_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; + D3D::device12->CreateUnorderedAccessView(s_bbox_buffer, nullptr, &view_desc, + cpu_descriptor_handle); - Bind(); + Bind(); } void BBox::Bind() { - D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_UAV, s_bbox_descriptor_handle); + D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_UAV, + s_bbox_descriptor_handle); } void BBox::Invalidate() { - if (!s_bbox_staging_buffer_map) - return; + if (!s_bbox_staging_buffer_map) + return; - D3D12_RANGE write_range = {}; - s_bbox_staging_buffer->Unmap(0, &write_range); - s_bbox_staging_buffer_map = nullptr; + D3D12_RANGE write_range = {}; + s_bbox_staging_buffer->Unmap(0, &write_range); + s_bbox_staging_buffer_map = nullptr; } void BBox::Shutdown() { - Invalidate(); + Invalidate(); - if (s_bbox_buffer) - { - D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(s_bbox_buffer); - s_bbox_buffer = nullptr; - } + if (s_bbox_buffer) + { + D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(s_bbox_buffer); + s_bbox_buffer = nullptr; + } - if (s_bbox_staging_buffer) - { - D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(s_bbox_staging_buffer); - s_bbox_staging_buffer = nullptr; - } + if (s_bbox_staging_buffer) + { + D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(s_bbox_staging_buffer); + s_bbox_staging_buffer = nullptr; + } - s_bbox_stream_buffer.reset(); + s_bbox_stream_buffer.reset(); } void BBox::Set(int index, int value) { - // If the buffer is currently mapped, compare the value, and update the staging buffer. - if (s_bbox_staging_buffer_map) - { - int current_value; - memcpy(¤t_value, reinterpret_cast(s_bbox_staging_buffer_map) + (index * sizeof(int)), sizeof(int)); - if (current_value == value) - { - // Value hasn't changed. So skip updating completely. - return; - } + // If the buffer is currently mapped, compare the value, and update the staging buffer. + if (s_bbox_staging_buffer_map) + { + int current_value; + memcpy(¤t_value, reinterpret_cast(s_bbox_staging_buffer_map) + (index * sizeof(int)), + sizeof(int)); + if (current_value == value) + { + // Value hasn't changed. So skip updating completely. + return; + } - memcpy(reinterpret_cast(s_bbox_staging_buffer_map) + (index * sizeof(int)), &value, sizeof(int)); - } + memcpy(reinterpret_cast(s_bbox_staging_buffer_map) + (index * sizeof(int)), &value, + sizeof(int)); + } - s_bbox_stream_buffer->AllocateSpaceInBuffer(sizeof(int), sizeof(int)); + s_bbox_stream_buffer->AllocateSpaceInBuffer(sizeof(int), sizeof(int)); - // Allocate temporary bytes in upload buffer, then copy to real buffer. - memcpy(s_bbox_stream_buffer->GetCPUAddressOfCurrentAllocation(), &value, sizeof(int)); - D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST, 0); - D3D::current_command_list->CopyBufferRegion(s_bbox_buffer, index * sizeof(int), s_bbox_stream_buffer->GetBuffer(), s_bbox_stream_buffer->GetOffsetOfCurrentAllocation(), sizeof(int)); - D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0); + // Allocate temporary bytes in upload buffer, then copy to real buffer. + memcpy(s_bbox_stream_buffer->GetCPUAddressOfCurrentAllocation(), &value, sizeof(int)); + D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST, 0); + D3D::current_command_list->CopyBufferRegion( + s_bbox_buffer, index * sizeof(int), s_bbox_stream_buffer->GetBuffer(), + s_bbox_stream_buffer->GetOffsetOfCurrentAllocation(), sizeof(int)); + D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_COPY_DEST, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0); } int BBox::Get(int index) { - if (!s_bbox_staging_buffer_map) - { - D3D::command_list_mgr->CPUAccessNotify(); + if (!s_bbox_staging_buffer_map) + { + D3D::command_list_mgr->CPUAccessNotify(); - // Copy from real buffer to staging buffer, then block until we have the results. - D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE, 0); - D3D::current_command_list->CopyBufferRegion(s_bbox_staging_buffer, 0, s_bbox_buffer, 0, BBOX_BUFFER_SIZE); - D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0); + // Copy from real buffer to staging buffer, then block until we have the results. + D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE, + 0); + D3D::current_command_list->CopyBufferRegion(s_bbox_staging_buffer, 0, s_bbox_buffer, 0, + BBOX_BUFFER_SIZE); + D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0); - D3D::command_list_mgr->ExecuteQueuedWork(true); + D3D::command_list_mgr->ExecuteQueuedWork(true); - D3D12_RANGE read_range = { 0, BBOX_BUFFER_SIZE }; - CheckHR(s_bbox_staging_buffer->Map(0, &read_range, &s_bbox_staging_buffer_map)); - } + D3D12_RANGE read_range = {0, BBOX_BUFFER_SIZE}; + CheckHR(s_bbox_staging_buffer->Map(0, &read_range, &s_bbox_staging_buffer_map)); + } - int value; - memcpy(&value, &reinterpret_cast(s_bbox_staging_buffer_map)[index], sizeof(int)); - return value; + int value; + memcpy(&value, &reinterpret_cast(s_bbox_staging_buffer_map)[index], sizeof(int)); + return value; } - }; diff --git a/Source/Core/VideoBackends/D3D12/BoundingBox.h b/Source/Core/VideoBackends/D3D12/BoundingBox.h index 5a762e7b59..e326d781f5 100644 --- a/Source/Core/VideoBackends/D3D12/BoundingBox.h +++ b/Source/Core/VideoBackends/D3D12/BoundingBox.h @@ -7,17 +7,15 @@ namespace DX12 { - class BBox { public: - static void Init(); - static void Bind(); - static void Invalidate(); - static void Shutdown(); + static void Init(); + static void Bind(); + static void Invalidate(); + static void Shutdown(); - static void Set(int index, int value); - static int Get(int index); + static void Set(int index, int value); + static int Get(int index); }; - }; diff --git a/Source/Core/VideoBackends/D3D12/D3DBase.cpp b/Source/Core/VideoBackends/D3D12/D3DBase.cpp index dc32f782e9..5405ec1f2e 100644 --- a/Source/Core/VideoBackends/D3D12/D3DBase.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DBase.cpp @@ -6,9 +6,9 @@ #include #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "VideoBackends/D3D12/D3DBase.h" #include "VideoBackends/D3D12/D3DCommandListManager.h" #include "VideoBackends/D3D12/D3DDescriptorHeapManager.h" @@ -21,7 +21,6 @@ static const unsigned int SWAP_CHAIN_BUFFER_COUNT = 4; namespace DX12 { - // d3dcompiler_*.dll exports static HINSTANCE s_d3d_compiler_dll = nullptr; static int s_d3d_compiler_dll_ref = 0; @@ -43,7 +42,6 @@ D3D12GETDEBUGINTERFACE d3d12_get_debug_interface = nullptr; namespace D3D { - // Begin extern'd variables. ID3D12Device* device12 = nullptr; @@ -81,769 +79,804 @@ static bool s_frame_in_progress = false; HRESULT LoadDXGI() { - if (s_dxgi_dll_ref++ > 0) - return S_OK; + if (s_dxgi_dll_ref++ > 0) + return S_OK; - if (s_dxgi_dll) - return S_OK; + if (s_dxgi_dll) + return S_OK; - s_dxgi_dll = LoadLibraryA("dxgi.dll"); - if (!s_dxgi_dll) - { - MessageBoxA(nullptr, "Failed to load dxgi.dll", "Critical error", MB_OK | MB_ICONERROR); - --s_dxgi_dll_ref; - return E_FAIL; - } - create_dxgi_factory = (CREATEDXGIFACTORY)GetProcAddress(s_dxgi_dll, "CreateDXGIFactory"); + s_dxgi_dll = LoadLibraryA("dxgi.dll"); + if (!s_dxgi_dll) + { + MessageBoxA(nullptr, "Failed to load dxgi.dll", "Critical error", MB_OK | MB_ICONERROR); + --s_dxgi_dll_ref; + return E_FAIL; + } + create_dxgi_factory = (CREATEDXGIFACTORY)GetProcAddress(s_dxgi_dll, "CreateDXGIFactory"); - if (create_dxgi_factory == nullptr) - MessageBoxA(nullptr, "GetProcAddress failed for CreateDXGIFactory!", "Critical error", MB_OK | MB_ICONERROR); + if (create_dxgi_factory == nullptr) + MessageBoxA(nullptr, "GetProcAddress failed for CreateDXGIFactory!", "Critical error", + MB_OK | MB_ICONERROR); - return S_OK; + return S_OK; } HRESULT LoadD3D() { - if (s_d3d12_dll_ref++ > 0) - return S_OK; + if (s_d3d12_dll_ref++ > 0) + return S_OK; - s_d3d12_dll = LoadLibraryA("d3d12.dll"); - if (!s_d3d12_dll) - { - MessageBoxA(nullptr, "Failed to load d3d12.dll", "Critical error", MB_OK | MB_ICONERROR); - --s_d3d12_dll_ref; - return E_FAIL; - } + s_d3d12_dll = LoadLibraryA("d3d12.dll"); + if (!s_d3d12_dll) + { + MessageBoxA(nullptr, "Failed to load d3d12.dll", "Critical error", MB_OK | MB_ICONERROR); + --s_d3d12_dll_ref; + return E_FAIL; + } - d3d12_create_device = (D3D12CREATEDEVICE)GetProcAddress(s_d3d12_dll, "D3D12CreateDevice"); - if (d3d12_create_device == nullptr) - { - MessageBoxA(nullptr, "GetProcAddress failed for D3D12CreateDevice!", "Critical error", MB_OK | MB_ICONERROR); - return E_FAIL; - } + d3d12_create_device = (D3D12CREATEDEVICE)GetProcAddress(s_d3d12_dll, "D3D12CreateDevice"); + if (d3d12_create_device == nullptr) + { + MessageBoxA(nullptr, "GetProcAddress failed for D3D12CreateDevice!", "Critical error", + MB_OK | MB_ICONERROR); + return E_FAIL; + } - d3d12_serialize_root_signature = (D3D12SERIALIZEROOTSIGNATURE)GetProcAddress(s_d3d12_dll, "D3D12SerializeRootSignature"); - if (d3d12_serialize_root_signature == nullptr) - { - MessageBoxA(nullptr, "GetProcAddress failed for D3D12SerializeRootSignature!", "Critical error", MB_OK | MB_ICONERROR); - return E_FAIL; - } + d3d12_serialize_root_signature = + (D3D12SERIALIZEROOTSIGNATURE)GetProcAddress(s_d3d12_dll, "D3D12SerializeRootSignature"); + if (d3d12_serialize_root_signature == nullptr) + { + MessageBoxA(nullptr, "GetProcAddress failed for D3D12SerializeRootSignature!", "Critical error", + MB_OK | MB_ICONERROR); + return E_FAIL; + } - d3d12_get_debug_interface = (D3D12GETDEBUGINTERFACE)GetProcAddress(s_d3d12_dll, "D3D12GetDebugInterface"); - if (d3d12_get_debug_interface == nullptr) - { - MessageBoxA(nullptr, "GetProcAddress failed for D3D12GetDebugInterface!", "Critical error", MB_OK | MB_ICONERROR); - return E_FAIL; - } + d3d12_get_debug_interface = + (D3D12GETDEBUGINTERFACE)GetProcAddress(s_d3d12_dll, "D3D12GetDebugInterface"); + if (d3d12_get_debug_interface == nullptr) + { + MessageBoxA(nullptr, "GetProcAddress failed for D3D12GetDebugInterface!", "Critical error", + MB_OK | MB_ICONERROR); + return E_FAIL; + } - return S_OK; + return S_OK; } HRESULT LoadD3DCompiler() { - if (s_d3d_compiler_dll_ref++ > 0) - return S_OK; + if (s_d3d_compiler_dll_ref++ > 0) + return S_OK; - if (s_d3d_compiler_dll) - return S_OK; + if (s_d3d_compiler_dll) + return S_OK; - // try to load D3DCompiler first to check whether we have proper runtime support - // try to use the dll the backend was compiled against first - don't bother about debug runtimes - s_d3d_compiler_dll = LoadLibraryA(D3DCOMPILER_DLL_A); - if (!s_d3d_compiler_dll) - { - // if that fails, use the dll which should be available in every SDK which officially supports DX12. - s_d3d_compiler_dll = LoadLibraryA("D3DCompiler_42.dll"); - if (!s_d3d_compiler_dll) - { - MessageBoxA(nullptr, "Failed to load D3DCompiler_42.dll, update your DX12 runtime, please", "Critical error", MB_OK | MB_ICONERROR); - return E_FAIL; - } - else - { - NOTICE_LOG(VIDEO, "Successfully loaded D3DCompiler_42.dll. If you're having trouble, try updating your DX runtime first."); - } - } + // try to load D3DCompiler first to check whether we have proper runtime support + // try to use the dll the backend was compiled against first - don't bother about debug runtimes + s_d3d_compiler_dll = LoadLibraryA(D3DCOMPILER_DLL_A); + if (!s_d3d_compiler_dll) + { + // if that fails, use the dll which should be available in every SDK which officially supports + // DX12. + s_d3d_compiler_dll = LoadLibraryA("D3DCompiler_42.dll"); + if (!s_d3d_compiler_dll) + { + MessageBoxA(nullptr, "Failed to load D3DCompiler_42.dll, update your DX12 runtime, please", + "Critical error", MB_OK | MB_ICONERROR); + return E_FAIL; + } + else + { + NOTICE_LOG(VIDEO, "Successfully loaded D3DCompiler_42.dll. If you're having trouble, try " + "updating your DX runtime first."); + } + } - d3d_reflect = (D3DREFLECT) GetProcAddress(s_d3d_compiler_dll, "D3DReflect"); - if (d3d_reflect == nullptr) - MessageBoxA(nullptr, "GetProcAddress failed for D3DReflect!", "Critical error", MB_OK | MB_ICONERROR); + d3d_reflect = (D3DREFLECT)GetProcAddress(s_d3d_compiler_dll, "D3DReflect"); + if (d3d_reflect == nullptr) + MessageBoxA(nullptr, "GetProcAddress failed for D3DReflect!", "Critical error", + MB_OK | MB_ICONERROR); - d3d_create_blob = (D3DCREATEBLOB)GetProcAddress(s_d3d_compiler_dll, "D3DCreateBlob"); - if (d3d_create_blob == nullptr) - MessageBoxA(nullptr, "GetProcAddress failed for D3DCreateBlob!", "Critical error", MB_OK | MB_ICONERROR); + d3d_create_blob = (D3DCREATEBLOB)GetProcAddress(s_d3d_compiler_dll, "D3DCreateBlob"); + if (d3d_create_blob == nullptr) + MessageBoxA(nullptr, "GetProcAddress failed for D3DCreateBlob!", "Critical error", + MB_OK | MB_ICONERROR); - d3d_compile = (pD3DCompile) GetProcAddress(s_d3d_compiler_dll, "D3DCompile"); - if (d3d_compile == nullptr) - MessageBoxA(nullptr, "GetProcAddress failed for D3DCompile!", "Critical error", MB_OK | MB_ICONERROR); + d3d_compile = (pD3DCompile)GetProcAddress(s_d3d_compiler_dll, "D3DCompile"); + if (d3d_compile == nullptr) + MessageBoxA(nullptr, "GetProcAddress failed for D3DCompile!", "Critical error", + MB_OK | MB_ICONERROR); - return S_OK; + return S_OK; } void UnloadDXGI() { - if (!s_dxgi_dll_ref) - return; + if (!s_dxgi_dll_ref) + return; - if (--s_dxgi_dll_ref != 0) - return; + if (--s_dxgi_dll_ref != 0) + return; - if (s_dxgi_dll) - FreeLibrary(s_dxgi_dll); + if (s_dxgi_dll) + FreeLibrary(s_dxgi_dll); - s_dxgi_dll = nullptr; - create_dxgi_factory = nullptr; + s_dxgi_dll = nullptr; + create_dxgi_factory = nullptr; } void UnloadD3D() { - if (!s_d3d12_dll_ref) - return; + if (!s_d3d12_dll_ref) + return; - if (--s_d3d12_dll_ref != 0) - return; + if (--s_d3d12_dll_ref != 0) + return; - if (s_d3d12_dll) - FreeLibrary(s_d3d12_dll); + if (s_d3d12_dll) + FreeLibrary(s_d3d12_dll); - s_d3d12_dll = nullptr; - d3d12_create_device = nullptr; - d3d12_serialize_root_signature = nullptr; + s_d3d12_dll = nullptr; + d3d12_create_device = nullptr; + d3d12_serialize_root_signature = nullptr; } void UnloadD3DCompiler() { - if (!s_d3d_compiler_dll_ref) - return; + if (!s_d3d_compiler_dll_ref) + return; - if (--s_d3d_compiler_dll_ref != 0) - return; + if (--s_d3d_compiler_dll_ref != 0) + return; - if (s_d3d_compiler_dll) - FreeLibrary(s_d3d_compiler_dll); + if (s_d3d_compiler_dll) + FreeLibrary(s_d3d_compiler_dll); - s_d3d_compiler_dll = nullptr; - d3d_compile = nullptr; - d3d_create_blob = nullptr; - d3d_reflect = nullptr; + s_d3d_compiler_dll = nullptr; + d3d_compile = nullptr; + d3d_create_blob = nullptr; + d3d_reflect = nullptr; } std::vector EnumAAModes(ID3D12Device* device) { - std::vector aa_modes; + std::vector aa_modes; - for (int samples = 0; samples < D3D12_MAX_MULTISAMPLE_SAMPLE_COUNT; ++samples) - { - D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS multisample_quality_levels = {}; - multisample_quality_levels.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - multisample_quality_levels.SampleCount = samples; + for (int samples = 0; samples < D3D12_MAX_MULTISAMPLE_SAMPLE_COUNT; ++samples) + { + D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS multisample_quality_levels = {}; + multisample_quality_levels.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + multisample_quality_levels.SampleCount = samples; - device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &multisample_quality_levels, sizeof(multisample_quality_levels)); + device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, + &multisample_quality_levels, sizeof(multisample_quality_levels)); - DXGI_SAMPLE_DESC desc; - desc.Count = samples; - desc.Quality = 0; + DXGI_SAMPLE_DESC desc; + desc.Count = samples; + desc.Quality = 0; - if (multisample_quality_levels.NumQualityLevels > 0) - aa_modes.push_back(desc); - } + if (multisample_quality_levels.NumQualityLevels > 0) + aa_modes.push_back(desc); + } - return aa_modes; + return aa_modes; } HRESULT Create(HWND wnd) { - hWnd = wnd; - HRESULT hr; + hWnd = wnd; + HRESULT hr; - RECT client; - GetClientRect(hWnd, &client); - s_xres = client.right - client.left; - s_yres = client.bottom - client.top; + RECT client; + GetClientRect(hWnd, &client); + s_xres = client.right - client.left; + s_yres = client.bottom - client.top; - hr = LoadDXGI(); - if (FAILED(hr)) - return hr; + hr = LoadDXGI(); + if (FAILED(hr)) + return hr; - hr = LoadD3D(); - if (FAILED(hr)) - { - UnloadDXGI(); - return hr; - } + hr = LoadD3D(); + if (FAILED(hr)) + { + UnloadDXGI(); + return hr; + } - hr = LoadD3DCompiler(); - if (FAILED(hr)) - { - UnloadD3D(); - UnloadDXGI(); - return hr; - } + hr = LoadD3DCompiler(); + if (FAILED(hr)) + { + UnloadD3D(); + UnloadDXGI(); + return hr; + } - IDXGIFactory* factory; - IDXGIAdapter* adapter; - hr = create_dxgi_factory(__uuidof(IDXGIFactory), (void**)&factory); - if (FAILED(hr)) - { - MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 12 backend"), MB_OK | MB_ICONERROR); - UnloadD3DCompiler(); - UnloadD3D(); - UnloadDXGI(); - return hr; - } + IDXGIFactory* factory; + IDXGIAdapter* adapter; + hr = create_dxgi_factory(__uuidof(IDXGIFactory), (void**)&factory); + if (FAILED(hr)) + { + MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 12 backend"), + MB_OK | MB_ICONERROR); + UnloadD3DCompiler(); + UnloadD3D(); + UnloadDXGI(); + return hr; + } - hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter); - if (FAILED(hr)) - { - // try using the first one - hr = factory->EnumAdapters(0, &adapter); - if (FAILED(hr)) - { - MessageBox(wnd, _T("Failed to enumerate adapters"), _T("Dolphin Direct3D 12 backend"), MB_OK | MB_ICONERROR); - UnloadD3DCompiler(); - UnloadD3D(); - UnloadDXGI(); - return hr; - } - } + hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter); + if (FAILED(hr)) + { + // try using the first one + hr = factory->EnumAdapters(0, &adapter); + if (FAILED(hr)) + { + MessageBox(wnd, _T("Failed to enumerate adapters"), _T("Dolphin Direct3D 12 backend"), + MB_OK | MB_ICONERROR); + UnloadD3DCompiler(); + UnloadD3D(); + UnloadDXGI(); + return hr; + } + } - DXGI_SWAP_CHAIN_DESC swap_chain_desc = {}; - swap_chain_desc.BufferCount = SWAP_CHAIN_BUFFER_COUNT; - swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swap_chain_desc.OutputWindow = wnd; - swap_chain_desc.SampleDesc.Count = 1; - swap_chain_desc.SampleDesc.Quality = 0; - swap_chain_desc.Windowed = true; - swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; - swap_chain_desc.Flags = 0; + DXGI_SWAP_CHAIN_DESC swap_chain_desc = {}; + swap_chain_desc.BufferCount = SWAP_CHAIN_BUFFER_COUNT; + swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swap_chain_desc.OutputWindow = wnd; + swap_chain_desc.SampleDesc.Count = 1; + swap_chain_desc.SampleDesc.Quality = 0; + swap_chain_desc.Windowed = true; + swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + swap_chain_desc.Flags = 0; - swap_chain_desc.BufferDesc.Width = s_xres; - swap_chain_desc.BufferDesc.Height = s_yres; - swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - swap_chain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + swap_chain_desc.BufferDesc.Width = s_xres; + swap_chain_desc.BufferDesc.Height = s_yres; + swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swap_chain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; #if defined(_DEBUG) || defined(DEBUGFAST) || defined(USE_D3D12_DEBUG_LAYER) - // Enabling the debug layer will fail if the Graphics Tools feature is not installed. - ID3D12Debug* debug_controller; - hr = d3d12_get_debug_interface(IID_PPV_ARGS(&debug_controller)); - if (SUCCEEDED(hr)) - { - debug_controller->EnableDebugLayer(); - debug_controller->Release(); - } - else - { - MessageBox(wnd, _T("WARNING: Failed to enable D3D12 debug layer, please ensure the Graphics Tools feature is installed."), _T("Dolphin Direct3D 12 backend"), MB_OK | MB_ICONERROR); - } + // Enabling the debug layer will fail if the Graphics Tools feature is not installed. + ID3D12Debug* debug_controller; + hr = d3d12_get_debug_interface(IID_PPV_ARGS(&debug_controller)); + if (SUCCEEDED(hr)) + { + debug_controller->EnableDebugLayer(); + debug_controller->Release(); + } + else + { + MessageBox(wnd, _T("WARNING: Failed to enable D3D12 debug layer, please ensure the Graphics ") + _T("Tools feature is installed."), + _T("Dolphin Direct3D 12 backend"), MB_OK | MB_ICONERROR); + } #endif - hr = d3d12_create_device(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device12)); - if (FAILED(hr)) - { - MessageBox(wnd, _T("Failed to initialize Direct3D.\nMake sure your video card supports Direct3D 12 and your drivers are up-to-date."), _T("Dolphin Direct3D 12 backend"), MB_OK | MB_ICONERROR); - adapter->Release(); - UnloadD3DCompiler(); - UnloadD3D(); - UnloadDXGI(); - return hr; - } + hr = d3d12_create_device(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device12)); + if (FAILED(hr)) + { + MessageBox(wnd, _T("Failed to initialize Direct3D.\nMake sure your video card supports ") + _T("Direct3D 12 and your drivers are up-to-date."), + _T("Dolphin Direct3D 12 backend"), MB_OK | MB_ICONERROR); + adapter->Release(); + UnloadD3DCompiler(); + UnloadD3D(); + UnloadDXGI(); + return hr; + } - // Ensure that the chosen AA mode is supported by the device. - std::vector aa_modes = EnumAAModes(device12); - if (std::find_if( - aa_modes.begin(), - aa_modes.end(), - [](const DXGI_SAMPLE_DESC& desc) {return desc.Count == g_Config.iMultisamples; } - ) == aa_modes.end()) - { - g_Config.iMultisamples = 1; - UpdateActiveConfig(); - } + // Ensure that the chosen AA mode is supported by the device. + std::vector aa_modes = EnumAAModes(device12); + if (std::find_if(aa_modes.begin(), aa_modes.end(), [](const DXGI_SAMPLE_DESC& desc) { + return desc.Count == g_Config.iMultisamples; + }) == aa_modes.end()) + { + g_Config.iMultisamples = 1; + UpdateActiveConfig(); + } - D3D12_COMMAND_QUEUE_DESC command_queue_desc = { - D3D12_COMMAND_LIST_TYPE_DIRECT, // D3D12_COMMAND_LIST_TYPE Type; - 0, // INT Priority; - D3D12_COMMAND_QUEUE_FLAG_NONE, // D3D12_COMMAND_QUEUE_FLAG Flags; - 0 // UINT NodeMask; - }; + D3D12_COMMAND_QUEUE_DESC command_queue_desc = { + D3D12_COMMAND_LIST_TYPE_DIRECT, // D3D12_COMMAND_LIST_TYPE Type; + 0, // INT Priority; + D3D12_COMMAND_QUEUE_FLAG_NONE, // D3D12_COMMAND_QUEUE_FLAG Flags; + 0 // UINT NodeMask; + }; - CheckHR(device12->CreateCommandQueue(&command_queue_desc, IID_PPV_ARGS(&command_queue))); + CheckHR(device12->CreateCommandQueue(&command_queue_desc, IID_PPV_ARGS(&command_queue))); - CheckHR(factory->CreateSwapChain(command_queue, &swap_chain_desc, &s_swap_chain)); + CheckHR(factory->CreateSwapChain(command_queue, &swap_chain_desc, &s_swap_chain)); - s_current_back_buf = 0; + s_current_back_buf = 0; - // Query the monitor refresh rate, to ensure proper Present throttling behavior. - DEVMODE dev_mode; - memset(&dev_mode, 0, sizeof(DEVMODE)); - dev_mode.dmSize = sizeof(DEVMODE); - dev_mode.dmDriverExtra = 0; + // Query the monitor refresh rate, to ensure proper Present throttling behavior. + DEVMODE dev_mode; + memset(&dev_mode, 0, sizeof(DEVMODE)); + dev_mode.dmSize = sizeof(DEVMODE); + dev_mode.dmDriverExtra = 0; - if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode) == 0) - { - // If EnumDisplaySettings fails, assume monitor refresh rate of 60 Hz. - s_monitor_refresh_rate = 60; - } - else - { - s_monitor_refresh_rate = dev_mode.dmDisplayFrequency; - } + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode) == 0) + { + // If EnumDisplaySettings fails, assume monitor refresh rate of 60 Hz. + s_monitor_refresh_rate = 60; + } + else + { + s_monitor_refresh_rate = dev_mode.dmDisplayFrequency; + } - ID3D12InfoQueue* info_queue = nullptr; - if (SUCCEEDED(device12->QueryInterface(&info_queue))) - { - CheckHR(info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE)); - CheckHR(info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, TRUE)); + ID3D12InfoQueue* info_queue = nullptr; + if (SUCCEEDED(device12->QueryInterface(&info_queue))) + { + CheckHR(info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE)); + CheckHR(info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, TRUE)); - D3D12_INFO_QUEUE_FILTER filter = {}; - D3D12_MESSAGE_ID id_list[] = { - D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_DEPTHSTENCILVIEW_NOT_SET, // Benign. - D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_RENDERTARGETVIEW_NOT_SET, // Benign. - D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_TYPE_MISMATCH // Benign. - }; - filter.DenyList.NumIDs = ARRAYSIZE(id_list); - filter.DenyList.pIDList = id_list; - info_queue->PushStorageFilter(&filter); + D3D12_INFO_QUEUE_FILTER filter = {}; + D3D12_MESSAGE_ID id_list[] = { + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_DEPTHSTENCILVIEW_NOT_SET, // Benign. + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_RENDERTARGETVIEW_NOT_SET, // Benign. + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_TYPE_MISMATCH // Benign. + }; + filter.DenyList.NumIDs = ARRAYSIZE(id_list); + filter.DenyList.pIDList = id_list; + info_queue->PushStorageFilter(&filter); - info_queue->Release(); + info_queue->Release(); - // Used at Close time to report live objects. - CheckHR(device12->QueryInterface(&s_debug_device12)); - } + // Used at Close time to report live objects. + CheckHR(device12->QueryInterface(&s_debug_device12)); + } - // prevent DXGI from responding to Alt+Enter, unfortunately DXGI_MWA_NO_ALT_ENTER - // does not work so we disable all monitoring of window messages. However this - // may make it more difficult for DXGI to handle display mode changes. - hr = factory->MakeWindowAssociation(wnd, DXGI_MWA_NO_WINDOW_CHANGES); - if (FAILED(hr)) - MessageBox(wnd, _T("Failed to associate the window"), _T("Dolphin Direct3D 12 backend"), MB_OK | MB_ICONERROR); + // prevent DXGI from responding to Alt+Enter, unfortunately DXGI_MWA_NO_ALT_ENTER + // does not work so we disable all monitoring of window messages. However this + // may make it more difficult for DXGI to handle display mode changes. + hr = factory->MakeWindowAssociation(wnd, DXGI_MWA_NO_WINDOW_CHANGES); + if (FAILED(hr)) + MessageBox(wnd, _T("Failed to associate the window"), _T("Dolphin Direct3D 12 backend"), + MB_OK | MB_ICONERROR); - CreateDescriptorHeaps(); - CreateRootSignatures(); + CreateDescriptorHeaps(); + CreateRootSignatures(); - command_list_mgr = std::make_unique( - D3D12_COMMAND_LIST_TYPE_DIRECT, - device12, - command_queue - ); + command_list_mgr = std::make_unique(D3D12_COMMAND_LIST_TYPE_DIRECT, + device12, command_queue); - command_list_mgr->GetCommandList(¤t_command_list); - command_list_mgr->SetInitialCommandListState(); + command_list_mgr->GetCommandList(¤t_command_list); + command_list_mgr->SetInitialCommandListState(); - for (UINT i = 0; i < SWAP_CHAIN_BUFFER_COUNT; i++) - { - ID3D12Resource* buf12 = nullptr; - hr = s_swap_chain->GetBuffer(i, IID_PPV_ARGS(&buf12)); + for (UINT i = 0; i < SWAP_CHAIN_BUFFER_COUNT; i++) + { + ID3D12Resource* buf12 = nullptr; + hr = s_swap_chain->GetBuffer(i, IID_PPV_ARGS(&buf12)); - CHECK(SUCCEEDED(hr), "Retrieve back buffer texture"); + CHECK(SUCCEEDED(hr), "Retrieve back buffer texture"); - s_backbuf[i] = new D3DTexture2D(buf12, - TEXTURE_BIND_FLAG_RENDER_TARGET, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - false, - D3D12_RESOURCE_STATE_PRESENT // Swap Chain back buffers start out in D3D12_RESOURCE_STATE_PRESENT. - ); + s_backbuf[i] = + new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_RENDER_TARGET, DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, false, + D3D12_RESOURCE_STATE_PRESENT // Swap Chain back buffers start out in + // D3D12_RESOURCE_STATE_PRESENT. + ); - SAFE_RELEASE(buf12); - SetDebugObjectName12(s_backbuf[i]->GetTex12(), "backbuffer texture"); - } + SAFE_RELEASE(buf12); + SetDebugObjectName12(s_backbuf[i]->GetTex12(), "backbuffer texture"); + } - s_backbuf[s_current_back_buf]->TransitionToResourceState(current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - current_command_list->OMSetRenderTargets(1, &s_backbuf[s_current_back_buf]->GetRTV12(), FALSE, nullptr); + s_backbuf[s_current_back_buf]->TransitionToResourceState(current_command_list, + D3D12_RESOURCE_STATE_RENDER_TARGET); + current_command_list->OMSetRenderTargets(1, &s_backbuf[s_current_back_buf]->GetRTV12(), FALSE, + nullptr); - QueryPerformanceFrequency(&s_qpc_frequency); + QueryPerformanceFrequency(&s_qpc_frequency); - // Render the device name. - DXGI_ADAPTER_DESC adapter_desc; - CheckHR(adapter->GetDesc(&adapter_desc)); - OSD::AddMessage(StringFromFormat("Using D3D Adapter: %s.", UTF16ToUTF8(adapter_desc.Description).c_str())); + // Render the device name. + DXGI_ADAPTER_DESC adapter_desc; + CheckHR(adapter->GetDesc(&adapter_desc)); + OSD::AddMessage( + StringFromFormat("Using D3D Adapter: %s.", UTF16ToUTF8(adapter_desc.Description).c_str())); - SAFE_RELEASE(factory); - SAFE_RELEASE(adapter); + SAFE_RELEASE(factory); + SAFE_RELEASE(adapter); - return S_OK; + return S_OK; } void CreateDescriptorHeaps() { - // Create D3D12 GPU and CPU descriptor heaps. + // Create D3D12 GPU and CPU descriptor heaps. - { - D3D12_DESCRIPTOR_HEAP_DESC gpu_descriptor_heap_desc = {}; - gpu_descriptor_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - gpu_descriptor_heap_desc.NumDescriptors = 500000; - gpu_descriptor_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + { + D3D12_DESCRIPTOR_HEAP_DESC gpu_descriptor_heap_desc = {}; + gpu_descriptor_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + gpu_descriptor_heap_desc.NumDescriptors = 500000; + gpu_descriptor_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - gpu_descriptor_heap_mgr = std::make_unique(&gpu_descriptor_heap_desc, device12, 50000); + gpu_descriptor_heap_mgr = + std::make_unique(&gpu_descriptor_heap_desc, device12, 50000); - gpu_descriptor_heaps[0] = gpu_descriptor_heap_mgr->GetDescriptorHeap(); + gpu_descriptor_heaps[0] = gpu_descriptor_heap_mgr->GetDescriptorHeap(); - D3D12_CPU_DESCRIPTOR_HANDLE descriptor_heap_cpu_base = gpu_descriptor_heap_mgr->GetDescriptorHeap()->GetCPUDescriptorHandleForHeapStart(); + D3D12_CPU_DESCRIPTOR_HANDLE descriptor_heap_cpu_base = + gpu_descriptor_heap_mgr->GetDescriptorHeap()->GetCPUDescriptorHandleForHeapStart(); - resource_descriptor_size = device12->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - sampler_descriptor_size = device12->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + resource_descriptor_size = + device12->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + sampler_descriptor_size = + device12->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - D3D12_GPU_DESCRIPTOR_HANDLE null_srv_gpu = {}; - gpu_descriptor_heap_mgr->Allocate(&null_srv_cpu, &null_srv_gpu, &null_srv_cpu_shadow); + D3D12_GPU_DESCRIPTOR_HANDLE null_srv_gpu = {}; + gpu_descriptor_heap_mgr->Allocate(&null_srv_cpu, &null_srv_gpu, &null_srv_cpu_shadow); - D3D12_SHADER_RESOURCE_VIEW_DESC null_srv_desc = {}; - null_srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - null_srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; - null_srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + D3D12_SHADER_RESOURCE_VIEW_DESC null_srv_desc = {}; + null_srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + null_srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + null_srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - device12->CreateShaderResourceView(NULL, &null_srv_desc, null_srv_cpu); + device12->CreateShaderResourceView(NULL, &null_srv_desc, null_srv_cpu); - for (UINT i = 0; i < 500000; i++) - { - // D3D12TODO: Make paving of descriptor heap optional. + for (UINT i = 0; i < 500000; i++) + { + // D3D12TODO: Make paving of descriptor heap optional. - D3D12_CPU_DESCRIPTOR_HANDLE destination_descriptor = {}; - destination_descriptor.ptr = descriptor_heap_cpu_base.ptr + i * resource_descriptor_size; + D3D12_CPU_DESCRIPTOR_HANDLE destination_descriptor = {}; + destination_descriptor.ptr = descriptor_heap_cpu_base.ptr + i * resource_descriptor_size; - device12->CreateShaderResourceView(NULL, &null_srv_desc, destination_descriptor); - } - } + device12->CreateShaderResourceView(NULL, &null_srv_desc, destination_descriptor); + } + } - { - D3D12_DESCRIPTOR_HEAP_DESC sampler_descriptor_heap_desc = {}; - sampler_descriptor_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - sampler_descriptor_heap_desc.NumDescriptors = 2000; - sampler_descriptor_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; + { + D3D12_DESCRIPTOR_HEAP_DESC sampler_descriptor_heap_desc = {}; + sampler_descriptor_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + sampler_descriptor_heap_desc.NumDescriptors = 2000; + sampler_descriptor_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; - sampler_descriptor_heap_mgr = std::make_unique(&sampler_descriptor_heap_desc, device12); + sampler_descriptor_heap_mgr = + std::make_unique(&sampler_descriptor_heap_desc, device12); - gpu_descriptor_heaps[1] = sampler_descriptor_heap_mgr->GetDescriptorHeap(); - } + gpu_descriptor_heaps[1] = sampler_descriptor_heap_mgr->GetDescriptorHeap(); + } - { - D3D12_DESCRIPTOR_HEAP_DESC dsv_descriptor_heap_desc = {}; - dsv_descriptor_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; - dsv_descriptor_heap_desc.NumDescriptors = 2000; - dsv_descriptor_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; + { + D3D12_DESCRIPTOR_HEAP_DESC dsv_descriptor_heap_desc = {}; + dsv_descriptor_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + dsv_descriptor_heap_desc.NumDescriptors = 2000; + dsv_descriptor_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; - dsv_descriptor_heap_mgr = std::make_unique(&dsv_descriptor_heap_desc, device12); - } + dsv_descriptor_heap_mgr = + std::make_unique(&dsv_descriptor_heap_desc, device12); + } - { - // D3D12TODO: Temporary workaround.. really need to properly suballocate out of render target heap. - D3D12_DESCRIPTOR_HEAP_DESC rtv_descriptor_heap_desc = {}; - rtv_descriptor_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; - rtv_descriptor_heap_desc.NumDescriptors = 1000000; - rtv_descriptor_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + { + // D3D12TODO: Temporary workaround.. really need to properly suballocate out of render target + // heap. + D3D12_DESCRIPTOR_HEAP_DESC rtv_descriptor_heap_desc = {}; + rtv_descriptor_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + rtv_descriptor_heap_desc.NumDescriptors = 1000000; + rtv_descriptor_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; - rtv_descriptor_heap_mgr = std::make_unique(&rtv_descriptor_heap_desc, device12); - } + rtv_descriptor_heap_mgr = + std::make_unique(&rtv_descriptor_heap_desc, device12); + } } void CreateRootSignatures() { - D3D12_DESCRIPTOR_RANGE desc_range_srv = { - D3D12_DESCRIPTOR_RANGE_TYPE_SRV, // D3D12_DESCRIPTOR_RANGE_TYPE RangeType; - 8, // UINT NumDescriptors; - 0, // UINT BaseShaderRegister; - 0, // UINT RegisterSpace; - D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND // UINT OffsetInDescriptorsFromTableStart; - }; + D3D12_DESCRIPTOR_RANGE desc_range_srv = { + D3D12_DESCRIPTOR_RANGE_TYPE_SRV, // D3D12_DESCRIPTOR_RANGE_TYPE RangeType; + 8, // UINT NumDescriptors; + 0, // UINT BaseShaderRegister; + 0, // UINT RegisterSpace; + D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND // UINT OffsetInDescriptorsFromTableStart; + }; - D3D12_DESCRIPTOR_RANGE desc_range_sampler = { - D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, // D3D12_DESCRIPTOR_RANGE_TYPE RangeType; - 8, // UINT NumDescriptors; - 0, // UINT BaseShaderRegister; - 0, // UINT RegisterSpace; - D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND // UINT OffsetInDescriptorsFromTableStart; - }; + D3D12_DESCRIPTOR_RANGE desc_range_sampler = { + D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, // D3D12_DESCRIPTOR_RANGE_TYPE RangeType; + 8, // UINT NumDescriptors; + 0, // UINT BaseShaderRegister; + 0, // UINT RegisterSpace; + D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND // UINT OffsetInDescriptorsFromTableStart; + }; - D3D12_DESCRIPTOR_RANGE desc_range_uav = { - D3D12_DESCRIPTOR_RANGE_TYPE_UAV, // D3D12_DESCRIPTOR_RANGE_TYPE RangeType; - 1, // UINT NumDescriptors; - 2, // UINT BaseShaderRegister; - 0, // UINT RegisterSpace; - D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND // UINT OffsetInDescriptorsFromTableStart; - }; + D3D12_DESCRIPTOR_RANGE desc_range_uav = { + D3D12_DESCRIPTOR_RANGE_TYPE_UAV, // D3D12_DESCRIPTOR_RANGE_TYPE RangeType; + 1, // UINT NumDescriptors; + 2, // UINT BaseShaderRegister; + 0, // UINT RegisterSpace; + D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND // UINT OffsetInDescriptorsFromTableStart; + }; - D3D12_ROOT_PARAMETER root_parameters[NUM_GRAPHICS_ROOT_PARAMETERS]; + D3D12_ROOT_PARAMETER root_parameters[NUM_GRAPHICS_ROOT_PARAMETERS]; - root_parameters[DESCRIPTOR_TABLE_PS_SRV].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - root_parameters[DESCRIPTOR_TABLE_PS_SRV].DescriptorTable.NumDescriptorRanges = 1; - root_parameters[DESCRIPTOR_TABLE_PS_SRV].DescriptorTable.pDescriptorRanges = &desc_range_srv; - root_parameters[DESCRIPTOR_TABLE_PS_SRV].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + root_parameters[DESCRIPTOR_TABLE_PS_SRV].ParameterType = + D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + root_parameters[DESCRIPTOR_TABLE_PS_SRV].DescriptorTable.NumDescriptorRanges = 1; + root_parameters[DESCRIPTOR_TABLE_PS_SRV].DescriptorTable.pDescriptorRanges = &desc_range_srv; + root_parameters[DESCRIPTOR_TABLE_PS_SRV].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; - root_parameters[DESCRIPTOR_TABLE_PS_SAMPLER].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - root_parameters[DESCRIPTOR_TABLE_PS_SAMPLER].DescriptorTable.NumDescriptorRanges = 1; - root_parameters[DESCRIPTOR_TABLE_PS_SAMPLER].DescriptorTable.pDescriptorRanges = &desc_range_sampler; - root_parameters[DESCRIPTOR_TABLE_PS_SAMPLER].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + root_parameters[DESCRIPTOR_TABLE_PS_SAMPLER].ParameterType = + D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + root_parameters[DESCRIPTOR_TABLE_PS_SAMPLER].DescriptorTable.NumDescriptorRanges = 1; + root_parameters[DESCRIPTOR_TABLE_PS_SAMPLER].DescriptorTable.pDescriptorRanges = + &desc_range_sampler; + root_parameters[DESCRIPTOR_TABLE_PS_SAMPLER].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; - root_parameters[DESCRIPTOR_TABLE_GS_CBV].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; - root_parameters[DESCRIPTOR_TABLE_GS_CBV].Descriptor.RegisterSpace = 0; - root_parameters[DESCRIPTOR_TABLE_GS_CBV].Descriptor.ShaderRegister = 0; - root_parameters[DESCRIPTOR_TABLE_GS_CBV].ShaderVisibility = D3D12_SHADER_VISIBILITY_GEOMETRY; + root_parameters[DESCRIPTOR_TABLE_GS_CBV].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + root_parameters[DESCRIPTOR_TABLE_GS_CBV].Descriptor.RegisterSpace = 0; + root_parameters[DESCRIPTOR_TABLE_GS_CBV].Descriptor.ShaderRegister = 0; + root_parameters[DESCRIPTOR_TABLE_GS_CBV].ShaderVisibility = D3D12_SHADER_VISIBILITY_GEOMETRY; - root_parameters[DESCRIPTOR_TABLE_VS_CBV].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; - root_parameters[DESCRIPTOR_TABLE_VS_CBV].Descriptor.RegisterSpace = 0; - root_parameters[DESCRIPTOR_TABLE_VS_CBV].Descriptor.ShaderRegister = 0; - root_parameters[DESCRIPTOR_TABLE_VS_CBV].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; + root_parameters[DESCRIPTOR_TABLE_VS_CBV].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + root_parameters[DESCRIPTOR_TABLE_VS_CBV].Descriptor.RegisterSpace = 0; + root_parameters[DESCRIPTOR_TABLE_VS_CBV].Descriptor.ShaderRegister = 0; + root_parameters[DESCRIPTOR_TABLE_VS_CBV].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; - root_parameters[DESCRIPTOR_TABLE_PS_CBVONE].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; - root_parameters[DESCRIPTOR_TABLE_PS_CBVONE].Descriptor.RegisterSpace = 0; - root_parameters[DESCRIPTOR_TABLE_PS_CBVONE].Descriptor.ShaderRegister = 0; - root_parameters[DESCRIPTOR_TABLE_PS_CBVONE].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + root_parameters[DESCRIPTOR_TABLE_PS_CBVONE].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + root_parameters[DESCRIPTOR_TABLE_PS_CBVONE].Descriptor.RegisterSpace = 0; + root_parameters[DESCRIPTOR_TABLE_PS_CBVONE].Descriptor.ShaderRegister = 0; + root_parameters[DESCRIPTOR_TABLE_PS_CBVONE].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; - root_parameters[DESCRIPTOR_TABLE_PS_CBVTWO].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; - root_parameters[DESCRIPTOR_TABLE_PS_CBVTWO].Descriptor.RegisterSpace = 0; - root_parameters[DESCRIPTOR_TABLE_PS_CBVTWO].Descriptor.ShaderRegister = 1; - root_parameters[DESCRIPTOR_TABLE_PS_CBVTWO].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + root_parameters[DESCRIPTOR_TABLE_PS_CBVTWO].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + root_parameters[DESCRIPTOR_TABLE_PS_CBVTWO].Descriptor.RegisterSpace = 0; + root_parameters[DESCRIPTOR_TABLE_PS_CBVTWO].Descriptor.ShaderRegister = 1; + root_parameters[DESCRIPTOR_TABLE_PS_CBVTWO].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; - root_parameters[DESCRIPTOR_TABLE_PS_UAV].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - root_parameters[DESCRIPTOR_TABLE_PS_UAV].DescriptorTable.NumDescriptorRanges = 1; - root_parameters[DESCRIPTOR_TABLE_PS_UAV].DescriptorTable.pDescriptorRanges = &desc_range_uav; - root_parameters[DESCRIPTOR_TABLE_PS_UAV].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + root_parameters[DESCRIPTOR_TABLE_PS_UAV].ParameterType = + D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + root_parameters[DESCRIPTOR_TABLE_PS_UAV].DescriptorTable.NumDescriptorRanges = 1; + root_parameters[DESCRIPTOR_TABLE_PS_UAV].DescriptorTable.pDescriptorRanges = &desc_range_uav; + root_parameters[DESCRIPTOR_TABLE_PS_UAV].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; - D3D12_ROOT_SIGNATURE_DESC root_signature_desc = {}; - root_signature_desc.pParameters = root_parameters; - root_signature_desc.Flags = - D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | - D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | - D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS; + D3D12_ROOT_SIGNATURE_DESC root_signature_desc = {}; + root_signature_desc.pParameters = root_parameters; + root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | + D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | + D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS; - root_signature_desc.NumParameters = ARRAYSIZE(root_parameters); + root_signature_desc.NumParameters = ARRAYSIZE(root_parameters); - ID3DBlob* text_root_signature_blob; - ID3DBlob* text_root_signature_error_blob; + ID3DBlob* text_root_signature_blob; + ID3DBlob* text_root_signature_error_blob; - CheckHR(d3d12_serialize_root_signature(&root_signature_desc, D3D_ROOT_SIGNATURE_VERSION_1, &text_root_signature_blob, &text_root_signature_error_blob)); + CheckHR(d3d12_serialize_root_signature(&root_signature_desc, D3D_ROOT_SIGNATURE_VERSION_1, + &text_root_signature_blob, + &text_root_signature_error_blob)); - CheckHR(D3D::device12->CreateRootSignature(0, text_root_signature_blob->GetBufferPointer(), text_root_signature_blob->GetBufferSize(), IID_PPV_ARGS(&default_root_signature))); + CheckHR(D3D::device12->CreateRootSignature(0, text_root_signature_blob->GetBufferPointer(), + text_root_signature_blob->GetBufferSize(), + IID_PPV_ARGS(&default_root_signature))); } void WaitForOutstandingRenderingToComplete() { - command_list_mgr->ExecuteQueuedWork(true); + command_list_mgr->ExecuteQueuedWork(true); } void Close() { - // we can't release the swapchain while in fullscreen. - s_swap_chain->SetFullscreenState(false, nullptr); + // we can't release the swapchain while in fullscreen. + s_swap_chain->SetFullscreenState(false, nullptr); - // Release all back buffer references - for (UINT i = 0; i < ARRAYSIZE(s_backbuf); i++) - { - SAFE_RELEASE(s_backbuf[i]); - } + // Release all back buffer references + for (UINT i = 0; i < ARRAYSIZE(s_backbuf); i++) + { + SAFE_RELEASE(s_backbuf[i]); + } - D3D::CleanupPersistentD3DTextureResources(); + D3D::CleanupPersistentD3DTextureResources(); - SAFE_RELEASE(s_swap_chain); + SAFE_RELEASE(s_swap_chain); - command_list_mgr.reset(); - command_queue->Release(); + command_list_mgr.reset(); + command_queue->Release(); - default_root_signature->Release(); + default_root_signature->Release(); - gpu_descriptor_heap_mgr.reset(); - sampler_descriptor_heap_mgr.reset(); - rtv_descriptor_heap_mgr.reset(); - dsv_descriptor_heap_mgr.reset(); + gpu_descriptor_heap_mgr.reset(); + sampler_descriptor_heap_mgr.reset(); + rtv_descriptor_heap_mgr.reset(); + dsv_descriptor_heap_mgr.reset(); - ULONG remaining_references = device12->Release(); - if ((!s_debug_device12 && remaining_references) || (s_debug_device12 && remaining_references > 1)) - { - ERROR_LOG(VIDEO, "Unreleased D3D12 references: %i.", remaining_references); - } - else - { - NOTICE_LOG(VIDEO, "Successfully released all D3D12 device references!"); - } + ULONG remaining_references = device12->Release(); + if ((!s_debug_device12 && remaining_references) || (s_debug_device12 && remaining_references > 1)) + { + ERROR_LOG(VIDEO, "Unreleased D3D12 references: %i.", remaining_references); + } + else + { + NOTICE_LOG(VIDEO, "Successfully released all D3D12 device references!"); + } #if defined(_DEBUG) || defined(DEBUGFAST) - if (s_debug_device12) - { - --remaining_references; // the debug interface increases the refcount of the device, subtract that. - if (remaining_references) - { - // print out alive objects, but only if we actually have pending references - // note this will also print out internal live objects to the debug console - s_debug_device12->ReportLiveDeviceObjects(D3D12_RLDO_DETAIL); - } - SAFE_RELEASE(s_debug_device12); - } + if (s_debug_device12) + { + --remaining_references; // the debug interface increases the refcount of the device, subtract + // that. + if (remaining_references) + { + // print out alive objects, but only if we actually have pending references + // note this will also print out internal live objects to the debug console + s_debug_device12->ReportLiveDeviceObjects(D3D12_RLDO_DETAIL); + } + SAFE_RELEASE(s_debug_device12); + } #endif - device12 = nullptr; - current_command_list = nullptr; + device12 = nullptr; + current_command_list = nullptr; - // unload DLLs - UnloadD3DCompiler(); - UnloadD3D(); - UnloadDXGI(); + // unload DLLs + UnloadD3DCompiler(); + UnloadD3D(); + UnloadDXGI(); } const std::string VertexShaderVersionString() { - return "vs_5_0"; + return "vs_5_0"; } const std::string GeometryShaderVersionString() { - return "gs_5_0"; + return "gs_5_0"; } const std::string PixelShaderVersionString() { - return "ps_5_0"; + return "ps_5_0"; } -D3DTexture2D* &GetBackBuffer() +D3DTexture2D*& GetBackBuffer() { - return s_backbuf[s_current_back_buf]; + return s_backbuf[s_current_back_buf]; } unsigned int GetBackBufferWidth() { - return s_xres; + return s_xres; } unsigned int GetBackBufferHeight() { - return s_yres; + return s_yres; } // Returns the maximum width/height of a texture. unsigned int GetMaxTextureSize() { - return D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + return D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; } void Reset() { - // release all back buffer references - for (UINT i = 0; i < ARRAYSIZE(s_backbuf); i++) - { - SAFE_RELEASE(s_backbuf[i]); - } + // release all back buffer references + for (UINT i = 0; i < ARRAYSIZE(s_backbuf); i++) + { + SAFE_RELEASE(s_backbuf[i]); + } - // Block until all commands have finished. - // This will also final-release all pending resources (including the backbuffer above) - command_list_mgr->ExecuteQueuedWork(true); + // Block until all commands have finished. + // This will also final-release all pending resources (including the backbuffer above) + command_list_mgr->ExecuteQueuedWork(true); - // resize swapchain buffers - RECT client; - GetClientRect(hWnd, &client); - s_xres = client.right - client.left; - s_yres = client.bottom - client.top; + // resize swapchain buffers + RECT client; + GetClientRect(hWnd, &client); + s_xres = client.right - client.left; + s_yres = client.bottom - client.top; - CheckHR(s_swap_chain->ResizeBuffers(SWAP_CHAIN_BUFFER_COUNT, s_xres, s_yres, DXGI_FORMAT_R8G8B8A8_UNORM, 0)); + CheckHR(s_swap_chain->ResizeBuffers(SWAP_CHAIN_BUFFER_COUNT, s_xres, s_yres, + DXGI_FORMAT_R8G8B8A8_UNORM, 0)); - // recreate back buffer textures + // recreate back buffer textures - HRESULT hr = S_OK; + HRESULT hr = S_OK; - for (UINT i = 0; i < SWAP_CHAIN_BUFFER_COUNT; i++) - { - ID3D12Resource* buf12 = nullptr; - hr = s_swap_chain->GetBuffer(i, IID_PPV_ARGS(&buf12)); + for (UINT i = 0; i < SWAP_CHAIN_BUFFER_COUNT; i++) + { + ID3D12Resource* buf12 = nullptr; + hr = s_swap_chain->GetBuffer(i, IID_PPV_ARGS(&buf12)); - CHECK(SUCCEEDED(hr), "Retrieve back buffer texture"); + CHECK(SUCCEEDED(hr), "Retrieve back buffer texture"); - s_backbuf[i] = new D3DTexture2D(buf12, - TEXTURE_BIND_FLAG_RENDER_TARGET, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - false, - D3D12_RESOURCE_STATE_PRESENT - ); + s_backbuf[i] = new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_RENDER_TARGET, DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, false, + D3D12_RESOURCE_STATE_PRESENT); - SAFE_RELEASE(buf12); - SetDebugObjectName12(s_backbuf[i]->GetTex12(), "backbuffer texture"); - } + SAFE_RELEASE(buf12); + SetDebugObjectName12(s_backbuf[i]->GetTex12(), "backbuffer texture"); + } - // The 'about-to-be-presented' back buffer index is always set back to '0' upon ResizeBuffers, just like - // creating a new swap chain. - s_current_back_buf = 0; + // The 'about-to-be-presented' back buffer index is always set back to '0' upon ResizeBuffers, + // just like + // creating a new swap chain. + s_current_back_buf = 0; - s_backbuf[s_current_back_buf]->TransitionToResourceState(current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + s_backbuf[s_current_back_buf]->TransitionToResourceState(current_command_list, + D3D12_RESOURCE_STATE_RENDER_TARGET); } bool BeginFrame() { - if (s_frame_in_progress) - { - PanicAlert("BeginFrame called although a frame is already in progress"); - return false; - } - s_frame_in_progress = true; - return (device12 != nullptr); + if (s_frame_in_progress) + { + PanicAlert("BeginFrame called although a frame is already in progress"); + return false; + } + s_frame_in_progress = true; + return (device12 != nullptr); } void EndFrame() { - if (!s_frame_in_progress) - { - PanicAlert("EndFrame called although no frame is in progress"); - return; - } - s_frame_in_progress = false; + if (!s_frame_in_progress) + { + PanicAlert("EndFrame called although no frame is in progress"); + return; + } + s_frame_in_progress = false; } void Present() { - // The Present function contains logic to ensure we never Present faster than Windows can - // send to the monitor. If we Present too fast, the Present call will start to block, and we'll be - // throttled - obviously not desired if vsync is disabled and the emulated CPU speed is > 100%. + // The Present function contains logic to ensure we never Present faster than Windows can + // send to the monitor. If we Present too fast, the Present call will start to block, and we'll be + // throttled - obviously not desired if vsync is disabled and the emulated CPU speed is > 100%. - // The throttling logic ensures that we don't Present more than twice in a given monitor vsync. - // This is accomplished through timing data - there is a programmatic way to determine if a - // Present call will block, however after investigation that is not feasible here (without invasive - // workarounds), due to the fact this method does not actually call Present - we just queue a Present - // command for the background thread to dispatch. + // The throttling logic ensures that we don't Present more than twice in a given monitor vsync. + // This is accomplished through timing data - there is a programmatic way to determine if a + // Present call will block, however after investigation that is not feasible here (without + // invasive + // workarounds), due to the fact this method does not actually call Present - we just queue a + // Present + // command for the background thread to dispatch. - // The monitor refresh rate is determined in Create(). + // The monitor refresh rate is determined in Create(). - static LARGE_INTEGER s_last_present_qpc; + static LARGE_INTEGER s_last_present_qpc; - LARGE_INTEGER current_qpc; - QueryPerformanceCounter(¤t_qpc); + LARGE_INTEGER current_qpc; + QueryPerformanceCounter(¤t_qpc); - const double time_elapsed_since_last_present = static_cast(current_qpc.QuadPart - s_last_present_qpc.QuadPart) / s_qpc_frequency.QuadPart; + const double time_elapsed_since_last_present = + static_cast(current_qpc.QuadPart - s_last_present_qpc.QuadPart) / + s_qpc_frequency.QuadPart; - unsigned int present_flags = 0; + unsigned int present_flags = 0; - if (g_ActiveConfig.IsVSync() == false && - time_elapsed_since_last_present < (1.0 / static_cast(s_monitor_refresh_rate)) / 2.0 - ) - { - present_flags = DXGI_PRESENT_TEST; // Causes Present to be a no-op. - } - else - { - s_last_present_qpc = current_qpc; + if (g_ActiveConfig.IsVSync() == false && + time_elapsed_since_last_present < (1.0 / static_cast(s_monitor_refresh_rate)) / 2.0) + { + present_flags = DXGI_PRESENT_TEST; // Causes Present to be a no-op. + } + else + { + s_last_present_qpc = current_qpc; - s_backbuf[s_current_back_buf]->TransitionToResourceState(current_command_list, D3D12_RESOURCE_STATE_PRESENT); - s_current_back_buf = (s_current_back_buf + 1) % SWAP_CHAIN_BUFFER_COUNT; - } + s_backbuf[s_current_back_buf]->TransitionToResourceState(current_command_list, + D3D12_RESOURCE_STATE_PRESENT); + s_current_back_buf = (s_current_back_buf + 1) % SWAP_CHAIN_BUFFER_COUNT; + } - command_list_mgr->ExecuteQueuedWorkAndPresent(s_swap_chain, g_ActiveConfig.IsVSync() ? 1 : 0, present_flags); + command_list_mgr->ExecuteQueuedWorkAndPresent(s_swap_chain, g_ActiveConfig.IsVSync() ? 1 : 0, + present_flags); - command_list_mgr->m_cpu_access_last_frame = command_list_mgr->m_cpu_access_this_frame; - command_list_mgr->m_cpu_access_this_frame = false; - command_list_mgr->m_draws_since_last_execution = 0; + command_list_mgr->m_cpu_access_last_frame = command_list_mgr->m_cpu_access_this_frame; + command_list_mgr->m_cpu_access_this_frame = false; + command_list_mgr->m_draws_since_last_execution = 0; } HRESULT SetFullscreenState(bool enable_fullscreen) { - return S_OK; + return S_OK; } HRESULT GetFullscreenState(bool* fullscreen_state) { - // Fullscreen exclusive intentionally not supported in DX12 backend. No performance - // difference between it and windowed full-screen due to usage of a FLIP swap chain. - *fullscreen_state = false; - return S_OK; + // Fullscreen exclusive intentionally not supported in DX12 backend. No performance + // difference between it and windowed full-screen due to usage of a FLIP swap chain. + *fullscreen_state = false; + return S_OK; } } // namespace D3D diff --git a/Source/Core/VideoBackends/D3D12/D3DBase.h b/Source/Core/VideoBackends/D3D12/D3DBase.h index 4016a039b1..a23bad1feb 100644 --- a/Source/Core/VideoBackends/D3D12/D3DBase.h +++ b/Source/Core/VideoBackends/D3D12/D3DBase.h @@ -23,20 +23,35 @@ namespace DX12 { - -#define SAFE_RELEASE(x) { if (x) (x)->Release(); (x) = nullptr; } -#define CHECK(cond, Message, ...) if (!(cond)) { __debugbreak(); PanicAlert(__FUNCTION__ " failed in %s at line %d: " Message, __FILE__, __LINE__, __VA_ARGS__); } +#define SAFE_RELEASE(x) \ + { \ + if (x) \ + (x)->Release(); \ + (x) = nullptr; \ + } +#define CHECK(cond, Message, ...) \ + if (!(cond)) \ + { \ + __debugbreak(); \ + PanicAlert(__FUNCTION__ " failed in %s at line %d: " Message, __FILE__, __LINE__, \ + __VA_ARGS__); \ + } // DEBUGCHECK is for high-frequency functions that we only want to check on debug builds. #if defined(_DEBUG) || defined(DEBUGFAST) -#define DEBUGCHECK(cond, Message, ...) if (!(cond)) { PanicAlert(__FUNCTION__ " failed in %s at line %d: " Message, __FILE__, __LINE__, __VA_ARGS__); } +#define DEBUGCHECK(cond, Message, ...) \ + if (!(cond)) \ + { \ + PanicAlert(__FUNCTION__ " failed in %s at line %d: " Message, __FILE__, __LINE__, \ + __VA_ARGS__); \ + } #else #define DEBUGCHECK(cond, Message, ...) #endif inline void CheckHR(HRESULT hr) { - CHECK(SUCCEEDED(hr), "Failed HRESULT."); + CHECK(SUCCEEDED(hr), "Failed HRESULT."); } class D3DCommandListManager; @@ -45,19 +60,18 @@ class D3DTexture2D; enum GRAPHICS_ROOT_PARAMETER : u32 { - DESCRIPTOR_TABLE_PS_SRV, - DESCRIPTOR_TABLE_PS_SAMPLER, - DESCRIPTOR_TABLE_GS_CBV, - DESCRIPTOR_TABLE_VS_CBV, - DESCRIPTOR_TABLE_PS_CBVONE, - DESCRIPTOR_TABLE_PS_CBVTWO, - DESCRIPTOR_TABLE_PS_UAV, - NUM_GRAPHICS_ROOT_PARAMETERS + DESCRIPTOR_TABLE_PS_SRV, + DESCRIPTOR_TABLE_PS_SAMPLER, + DESCRIPTOR_TABLE_GS_CBV, + DESCRIPTOR_TABLE_VS_CBV, + DESCRIPTOR_TABLE_PS_CBVONE, + DESCRIPTOR_TABLE_PS_CBVTWO, + DESCRIPTOR_TABLE_PS_UAV, + NUM_GRAPHICS_ROOT_PARAMETERS }; namespace D3D { - HRESULT LoadDXGI(); HRESULT LoadD3D(); HRESULT LoadD3DCompiler(); @@ -85,7 +99,6 @@ extern std::unique_ptr dsv_descriptor_heap_mgr; extern std::unique_ptr rtv_descriptor_heap_mgr; extern std::array gpu_descriptor_heaps; - extern D3D12_CPU_DESCRIPTOR_HANDLE null_srv_cpu; extern D3D12_CPU_DESCRIPTOR_HANDLE null_srv_cpu_shadow; @@ -118,26 +131,27 @@ HRESULT GetFullscreenState(bool* fullscreen_state); // e.g. when listing up all resources who have unreleased references. static void SetDebugObjectName12(ID3D12Resource* resource, LPCSTR name) { - HRESULT hr = resource->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)(name ? strlen(name) : 0), name); - if (FAILED(hr)) - { - throw std::exception("Failure setting name for D3D12 object"); - } + HRESULT hr = + resource->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)(name ? strlen(name) : 0), name); + if (FAILED(hr)) + { + throw std::exception("Failure setting name for D3D12 object"); + } } static std::string GetDebugObjectName12(ID3D12Resource* resource) { - std::string name; + std::string name; - if (resource) - { - UINT size = 0; - resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, nullptr); //get required size - name.resize(size); - resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, const_cast(name.data())); - } + if (resource) + { + UINT size = 0; + resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, nullptr); // get required size + name.resize(size); + resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, const_cast(name.data())); + } - return name; + return name; } } // namespace D3D @@ -148,7 +162,9 @@ extern CREATEDXGIFACTORY create_dxgi_factory; using D3D12CREATEDEVICE = HRESULT(WINAPI*)(IUnknown*, D3D_FEATURE_LEVEL, REFIID, void**); extern D3D12CREATEDEVICE d3d12_create_device; -using D3D12SERIALIZEROOTSIGNATURE = HRESULT(WINAPI*)(const D3D12_ROOT_SIGNATURE_DESC* pRootSignature, D3D_ROOT_SIGNATURE_VERSION Version, ID3DBlob** ppBlob, ID3DBlob** ppErrorBlob); +using D3D12SERIALIZEROOTSIGNATURE = + HRESULT(WINAPI*)(const D3D12_ROOT_SIGNATURE_DESC* pRootSignature, + D3D_ROOT_SIGNATURE_VERSION Version, ID3DBlob** ppBlob, ID3DBlob** ppErrorBlob); using D3D12GETDEBUGINTERFACE = HRESULT(WINAPI*)(REFIID riid, void** ppvDebug); using D3DREFLECT = HRESULT(WINAPI*)(LPCVOID, SIZE_T, REFIID, void**); diff --git a/Source/Core/VideoBackends/D3D12/D3DCommandListManager.cpp b/Source/Core/VideoBackends/D3D12/D3DCommandListManager.cpp index 07c9b65eab..5a8f0bc106 100644 --- a/Source/Core/VideoBackends/D3D12/D3DCommandListManager.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DCommandListManager.cpp @@ -23,345 +23,367 @@ namespace DX12 { extern StateCache gx_state_cache; -D3DCommandListManager::D3DCommandListManager( - D3D12_COMMAND_LIST_TYPE command_list_type, - ID3D12Device* device, - ID3D12CommandQueue* command_queue - ) : - m_device(device), - m_command_queue(command_queue) +D3DCommandListManager::D3DCommandListManager(D3D12_COMMAND_LIST_TYPE command_list_type, + ID3D12Device* device, + ID3D12CommandQueue* command_queue) + : m_device(device), m_command_queue(command_queue) { - // Create two lists, with two command allocators each. This corresponds to up to two frames in flight at once. - m_current_command_allocator = 0; - m_current_command_allocator_list = 0; - for (UINT i = 0; i < COMMAND_ALLOCATORS_PER_LIST; i++) - { - for (UINT j = 0; j < m_command_allocator_lists.size(); j++) - { - ID3D12CommandAllocator* command_allocator = nullptr; + // Create two lists, with two command allocators each. This corresponds to up to two frames in + // flight at once. + m_current_command_allocator = 0; + m_current_command_allocator_list = 0; + for (UINT i = 0; i < COMMAND_ALLOCATORS_PER_LIST; i++) + { + for (UINT j = 0; j < m_command_allocator_lists.size(); j++) + { + ID3D12CommandAllocator* command_allocator = nullptr; - CheckHR(m_device->CreateCommandAllocator(command_list_type, IID_PPV_ARGS(&command_allocator))); - m_command_allocator_lists[j].push_back(command_allocator); - } - } + CheckHR( + m_device->CreateCommandAllocator(command_list_type, IID_PPV_ARGS(&command_allocator))); + m_command_allocator_lists[j].push_back(command_allocator); + } + } - // Create backing command list. - CheckHR(m_device->CreateCommandList(0, command_list_type, m_command_allocator_lists[m_current_command_allocator_list][0], nullptr, IID_PPV_ARGS(&m_backing_command_list))); + // Create backing command list. + CheckHR(m_device->CreateCommandList( + 0, command_list_type, m_command_allocator_lists[m_current_command_allocator_list][0], nullptr, + IID_PPV_ARGS(&m_backing_command_list))); #ifdef USE_D3D12_QUEUED_COMMAND_LISTS - m_queued_command_list = new ID3D12QueuedCommandList(m_backing_command_list, m_command_queue); + m_queued_command_list = new ID3D12QueuedCommandList(m_backing_command_list, m_command_queue); #endif - // Create fence that will be used to measure GPU progress of app rendering requests (e.g. CPU readback of GPU data). - m_queue_fence_value = 0; - CheckHR(m_device->CreateFence(m_queue_fence_value, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_queue_fence))); + // Create fence that will be used to measure GPU progress of app rendering requests (e.g. CPU + // readback of GPU data). + m_queue_fence_value = 0; + CheckHR(m_device->CreateFence(m_queue_fence_value, D3D12_FENCE_FLAG_NONE, + IID_PPV_ARGS(&m_queue_fence))); - // Create fence that will be used internally by D3DCommandListManager for frame-level resource tracking. - m_queue_frame_fence_value = 0; - CheckHR(m_device->CreateFence(m_queue_frame_fence_value, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_queue_frame_fence))); + // Create fence that will be used internally by D3DCommandListManager for frame-level resource + // tracking. + m_queue_frame_fence_value = 0; + CheckHR(m_device->CreateFence(m_queue_frame_fence_value, D3D12_FENCE_FLAG_NONE, + IID_PPV_ARGS(&m_queue_frame_fence))); - // Create event that will be used for waiting on CPU until a fence is signaled by GPU. - m_wait_on_cpu_fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr); + // Create event that will be used for waiting on CPU until a fence is signaled by GPU. + m_wait_on_cpu_fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr); - // Pre-size the deferred destruction lists. - for (UINT i = 0; i < m_deferred_destruction_lists.size(); i++) - { - m_deferred_destruction_lists[i].reserve(200); - } + // Pre-size the deferred destruction lists. + for (UINT i = 0; i < m_deferred_destruction_lists.size(); i++) + { + m_deferred_destruction_lists[i].reserve(200); + } - m_current_deferred_destruction_list = 0; + m_current_deferred_destruction_list = 0; - std::fill(m_command_allocator_list_fences.begin(), m_command_allocator_list_fences.end(), 0); - std::fill(m_deferred_destruction_list_fences.begin(), m_deferred_destruction_list_fences.end(), 0); + std::fill(m_command_allocator_list_fences.begin(), m_command_allocator_list_fences.end(), 0); + std::fill(m_deferred_destruction_list_fences.begin(), m_deferred_destruction_list_fences.end(), + 0); } void D3DCommandListManager::SetInitialCommandListState() { - ID3D12GraphicsCommandList* command_list = nullptr; - GetCommandList(&command_list); + ID3D12GraphicsCommandList* command_list = nullptr; + GetCommandList(&command_list); - command_list->SetDescriptorHeaps(static_cast(D3D::gpu_descriptor_heaps.size()), D3D::gpu_descriptor_heaps.data()); - command_list->SetGraphicsRootSignature(D3D::default_root_signature); + command_list->SetDescriptorHeaps(static_cast(D3D::gpu_descriptor_heaps.size()), + D3D::gpu_descriptor_heaps.data()); + command_list->SetGraphicsRootSignature(D3D::default_root_signature); - if (g_renderer) - { - // It is possible that we change command lists in the middle of the frame. In that case, restore - // the viewport/scissor to the current console GPU state. - g_renderer->RestoreAPIState(); - } + if (g_renderer) + { + // It is possible that we change command lists in the middle of the frame. In that case, restore + // the viewport/scissor to the current console GPU state. + g_renderer->RestoreAPIState(); + } - m_command_list_dirty_state = UINT_MAX; + m_command_list_dirty_state = UINT_MAX; - command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - m_command_list_current_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; + command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + m_command_list_current_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; - if (g_vertex_manager) - reinterpret_cast(g_vertex_manager.get())->SetIndexBuffer(); + if (g_vertex_manager) + reinterpret_cast(g_vertex_manager.get())->SetIndexBuffer(); } void D3DCommandListManager::GetCommandList(ID3D12GraphicsCommandList** command_list) const { #ifdef USE_D3D12_QUEUED_COMMAND_LISTS - *command_list = this->m_queued_command_list; + *command_list = this->m_queued_command_list; #else - *command_list = this->m_backing_command_list; + *command_list = this->m_backing_command_list; #endif } void D3DCommandListManager::ExecuteQueuedWork(bool wait_for_gpu_completion) { - m_queue_fence_value++; + m_queue_fence_value++; #ifdef USE_D3D12_QUEUED_COMMAND_LISTS - m_queued_command_list->Close(); - m_queued_command_list->QueueExecute(); - m_queued_command_list->QueueFenceGpuSignal(m_queue_fence, m_queue_fence_value); - m_queued_command_list->ProcessQueuedItems(wait_for_gpu_completion, wait_for_gpu_completion); + m_queued_command_list->Close(); + m_queued_command_list->QueueExecute(); + m_queued_command_list->QueueFenceGpuSignal(m_queue_fence, m_queue_fence_value); + m_queued_command_list->ProcessQueuedItems(wait_for_gpu_completion, wait_for_gpu_completion); #else - CheckHR(m_backing_command_list->Close()); + CheckHR(m_backing_command_list->Close()); - ID3D12CommandList* const execute_list[1] = { m_backing_command_list }; - m_command_queue->ExecuteCommandLists(1, execute_list); + ID3D12CommandList* const execute_list[1] = {m_backing_command_list}; + m_command_queue->ExecuteCommandLists(1, execute_list); - CheckHR(m_command_queue->Signal(m_queue_fence, m_queue_fence_value)); + CheckHR(m_command_queue->Signal(m_queue_fence, m_queue_fence_value)); #endif - // Notify observers of the fence value for the current work to finish. - for (auto it : m_queue_fence_callbacks) - it.second(it.first, m_queue_fence_value); + // Notify observers of the fence value for the current work to finish. + for (auto it : m_queue_fence_callbacks) + it.second(it.first, m_queue_fence_value); - if (wait_for_gpu_completion) - WaitForGPUCompletion(); + if (wait_for_gpu_completion) + WaitForGPUCompletion(); - // Re-open the command list, using the current allocator. - ResetCommandList(); - SetInitialCommandListState(); + // Re-open the command list, using the current allocator. + ResetCommandList(); + SetInitialCommandListState(); } -void D3DCommandListManager::ExecuteQueuedWorkAndPresent(IDXGISwapChain* swap_chain, UINT sync_interval, UINT flags) +void D3DCommandListManager::ExecuteQueuedWorkAndPresent(IDXGISwapChain* swap_chain, + UINT sync_interval, UINT flags) { - m_queue_fence_value++; + m_queue_fence_value++; #ifdef USE_D3D12_QUEUED_COMMAND_LISTS - m_queued_command_list->Close(); - m_queued_command_list->QueueExecute(); - m_queued_command_list->QueuePresent(swap_chain, sync_interval, flags); - m_queued_command_list->QueueFenceGpuSignal(m_queue_fence, m_queue_fence_value); - m_queued_command_list->ProcessQueuedItems(true); + m_queued_command_list->Close(); + m_queued_command_list->QueueExecute(); + m_queued_command_list->QueuePresent(swap_chain, sync_interval, flags); + m_queued_command_list->QueueFenceGpuSignal(m_queue_fence, m_queue_fence_value); + m_queued_command_list->ProcessQueuedItems(true); #else - CheckHR(m_backing_command_list->Close()); + CheckHR(m_backing_command_list->Close()); - ID3D12CommandList* const execute_list[1] = { m_backing_command_list }; - m_command_queue->ExecuteCommandLists(1, execute_list); + ID3D12CommandList* const execute_list[1] = {m_backing_command_list}; + m_command_queue->ExecuteCommandLists(1, execute_list); - CheckHR(swap_chain->Present(sync_interval, flags)); - CheckHR(m_command_queue->Signal(m_queue_fence, m_queue_fence_value)); + CheckHR(swap_chain->Present(sync_interval, flags)); + CheckHR(m_command_queue->Signal(m_queue_fence, m_queue_fence_value)); #endif - // Notify observers of the fence value for the current work to finish. - for (auto it : m_queue_fence_callbacks) - it.second(it.first, m_queue_fence_value); + // Notify observers of the fence value for the current work to finish. + for (auto it : m_queue_fence_callbacks) + it.second(it.first, m_queue_fence_value); - // Move to the next command allocator, this may mean switching allocator lists. - MoveToNextCommandAllocator(); - ResetCommandList(); - SetInitialCommandListState(); + // Move to the next command allocator, this may mean switching allocator lists. + MoveToNextCommandAllocator(); + ResetCommandList(); + SetInitialCommandListState(); } void D3DCommandListManager::DestroyAllPendingResources() { - for (auto& destruction_list : m_deferred_destruction_lists) - { - for (auto& resource : destruction_list) - resource->Release(); + for (auto& destruction_list : m_deferred_destruction_lists) + { + for (auto& resource : destruction_list) + resource->Release(); - destruction_list.clear(); - } + destruction_list.clear(); + } } void D3DCommandListManager::ResetAllCommandAllocators() { - for (auto& allocator_list : m_command_allocator_lists) - { - for (auto& allocator : allocator_list) - allocator->Reset(); - } + for (auto& allocator_list : m_command_allocator_lists) + { + for (auto& allocator : allocator_list) + allocator->Reset(); + } - // Move back to the start, using the first allocator of first list. - m_current_command_allocator = 0; - m_current_command_allocator_list = 0; - m_current_deferred_destruction_list = 0; + // Move back to the start, using the first allocator of first list. + m_current_command_allocator = 0; + m_current_command_allocator_list = 0; + m_current_deferred_destruction_list = 0; } void D3DCommandListManager::WaitForGPUCompletion() { - // Wait for GPU to finish all outstanding work. - // This method assumes that no command lists are open. - m_queue_frame_fence_value++; + // Wait for GPU to finish all outstanding work. + // This method assumes that no command lists are open. + m_queue_frame_fence_value++; #ifdef USE_D3D12_QUEUED_COMMAND_LISTS - m_queued_command_list->QueueFenceGpuSignal(m_queue_frame_fence, m_queue_frame_fence_value); - m_queued_command_list->ProcessQueuedItems(true); + m_queued_command_list->QueueFenceGpuSignal(m_queue_frame_fence, m_queue_frame_fence_value); + m_queued_command_list->ProcessQueuedItems(true); #else - CheckHR(m_command_queue->Signal(m_queue_frame_fence, m_queue_frame_fence_value)); + CheckHR(m_command_queue->Signal(m_queue_frame_fence, m_queue_frame_fence_value)); #endif - WaitOnCPUForFence(m_queue_frame_fence, m_queue_frame_fence_value); + WaitOnCPUForFence(m_queue_frame_fence, m_queue_frame_fence_value); - // GPU is up to date with us. Therefore, it has finished with any pending resources. - DestroyAllPendingResources(); + // GPU is up to date with us. Therefore, it has finished with any pending resources. + DestroyAllPendingResources(); - // Command allocators are also up-to-date, so reset these. - ResetAllCommandAllocators(); + // Command allocators are also up-to-date, so reset these. + ResetAllCommandAllocators(); } void D3DCommandListManager::PerformGPURolloverChecks() { - m_queue_frame_fence_value++; + m_queue_frame_fence_value++; #ifdef USE_D3D12_QUEUED_COMMAND_LISTS - m_queued_command_list->QueueFenceGpuSignal(m_queue_frame_fence, m_queue_frame_fence_value); + m_queued_command_list->QueueFenceGpuSignal(m_queue_frame_fence, m_queue_frame_fence_value); #else - CheckHR(m_command_queue->Signal(m_queue_frame_fence, m_queue_frame_fence_value)); + CheckHR(m_command_queue->Signal(m_queue_frame_fence, m_queue_frame_fence_value)); #endif - // We now know that the previous 'set' of command lists has completed on GPU, and it is safe to - // release resources / start back at beginning of command allocator list. + // We now know that the previous 'set' of command lists has completed on GPU, and it is safe to + // release resources / start back at beginning of command allocator list. - // Begin Deferred Resource Destruction - UINT safe_to_delete_deferred_destruction_list = (m_current_deferred_destruction_list - 1) % m_deferred_destruction_lists.size(); - WaitOnCPUForFence(m_queue_frame_fence, m_deferred_destruction_list_fences[safe_to_delete_deferred_destruction_list]); + // Begin Deferred Resource Destruction + UINT safe_to_delete_deferred_destruction_list = + (m_current_deferred_destruction_list - 1) % m_deferred_destruction_lists.size(); + WaitOnCPUForFence(m_queue_frame_fence, + m_deferred_destruction_list_fences[safe_to_delete_deferred_destruction_list]); - for (UINT i = 0; i < m_deferred_destruction_lists[safe_to_delete_deferred_destruction_list].size(); i++) - { - CHECK(m_deferred_destruction_lists[safe_to_delete_deferred_destruction_list][i]->Release() == 0, "Resource leak."); - } + for (UINT i = 0; + i < m_deferred_destruction_lists[safe_to_delete_deferred_destruction_list].size(); i++) + { + CHECK(m_deferred_destruction_lists[safe_to_delete_deferred_destruction_list][i]->Release() == 0, + "Resource leak."); + } - m_deferred_destruction_lists[safe_to_delete_deferred_destruction_list].clear(); + m_deferred_destruction_lists[safe_to_delete_deferred_destruction_list].clear(); - m_deferred_destruction_list_fences[m_current_deferred_destruction_list] = m_queue_frame_fence_value; - m_current_deferred_destruction_list = (m_current_deferred_destruction_list + 1) % m_deferred_destruction_lists.size(); - // End Deferred Resource Destruction + m_deferred_destruction_list_fences[m_current_deferred_destruction_list] = + m_queue_frame_fence_value; + m_current_deferred_destruction_list = + (m_current_deferred_destruction_list + 1) % m_deferred_destruction_lists.size(); + // End Deferred Resource Destruction + // Begin Command Allocator Resets + UINT safe_to_reset_command_allocator_list = + (m_current_command_allocator_list - 1) % m_command_allocator_lists.size(); + WaitOnCPUForFence(m_queue_frame_fence, + m_command_allocator_list_fences[safe_to_reset_command_allocator_list]); - // Begin Command Allocator Resets - UINT safe_to_reset_command_allocator_list = (m_current_command_allocator_list - 1) % m_command_allocator_lists.size(); - WaitOnCPUForFence(m_queue_frame_fence, m_command_allocator_list_fences[safe_to_reset_command_allocator_list]); + for (UINT i = 0; i < m_command_allocator_lists[safe_to_reset_command_allocator_list].size(); i++) + { + CheckHR(m_command_allocator_lists[safe_to_reset_command_allocator_list][i]->Reset()); + } - for (UINT i = 0; i < m_command_allocator_lists[safe_to_reset_command_allocator_list].size(); i++) - { - CheckHR(m_command_allocator_lists[safe_to_reset_command_allocator_list][i]->Reset()); - } - - m_command_allocator_list_fences[m_current_command_allocator_list] = m_queue_frame_fence_value; - m_current_command_allocator_list = (m_current_command_allocator_list + 1) % m_command_allocator_lists.size(); - m_current_command_allocator = 0; - // End Command Allocator Resets + m_command_allocator_list_fences[m_current_command_allocator_list] = m_queue_frame_fence_value; + m_current_command_allocator_list = + (m_current_command_allocator_list + 1) % m_command_allocator_lists.size(); + m_current_command_allocator = 0; + // End Command Allocator Resets } void D3DCommandListManager::MoveToNextCommandAllocator() { - // Move to the next allocator in the current allocator list. - m_current_command_allocator = (m_current_command_allocator + 1) % m_command_allocator_lists[m_current_command_allocator_list].size(); + // Move to the next allocator in the current allocator list. + m_current_command_allocator = (m_current_command_allocator + 1) % + m_command_allocator_lists[m_current_command_allocator_list].size(); - // Did we wrap around? Move to the next set of allocators. - if (m_current_command_allocator == 0) - PerformGPURolloverChecks(); + // Did we wrap around? Move to the next set of allocators. + if (m_current_command_allocator == 0) + PerformGPURolloverChecks(); } void D3DCommandListManager::ResetCommandList() { #ifdef USE_D3D12_QUEUED_COMMAND_LISTS - ID3D12QueuedCommandList* command_list = m_queued_command_list; + ID3D12QueuedCommandList* command_list = m_queued_command_list; #else - ID3D12GraphicsCommandList* command_list = m_backing_command_list; + ID3D12GraphicsCommandList* command_list = m_backing_command_list; #endif - CheckHR(command_list->Reset(m_command_allocator_lists[m_current_command_allocator_list][m_current_command_allocator], nullptr)); + CheckHR(command_list->Reset(m_command_allocator_lists[m_current_command_allocator_list] + [m_current_command_allocator], + nullptr)); } void D3DCommandListManager::DestroyResourceAfterCurrentCommandListExecuted(ID3D12Resource* resource) { - CHECK(resource, "Null resource being inserted!"); + CHECK(resource, "Null resource being inserted!"); - m_deferred_destruction_lists[m_current_deferred_destruction_list].push_back(resource); + m_deferred_destruction_lists[m_current_deferred_destruction_list].push_back(resource); } D3DCommandListManager::~D3DCommandListManager() { #ifdef USE_D3D12_QUEUED_COMMAND_LISTS - // Wait for background thread to exit. - m_queued_command_list->Release(); + // Wait for background thread to exit. + m_queued_command_list->Release(); #endif - // The command list will still be open, close it before destroying. - m_backing_command_list->Close(); + // The command list will still be open, close it before destroying. + m_backing_command_list->Close(); - DestroyAllPendingResources(); + DestroyAllPendingResources(); - m_backing_command_list->Release(); + m_backing_command_list->Release(); - for (auto& allocator_list : m_command_allocator_lists) - { - for (auto& resource : allocator_list) - resource->Release(); - } + for (auto& allocator_list : m_command_allocator_lists) + { + for (auto& resource : allocator_list) + resource->Release(); + } - m_queue_fence->Release(); - m_queue_frame_fence->Release(); + m_queue_fence->Release(); + m_queue_frame_fence->Release(); - CloseHandle(m_wait_on_cpu_fence_event); + CloseHandle(m_wait_on_cpu_fence_event); } void D3DCommandListManager::WaitOnCPUForFence(ID3D12Fence* fence, UINT64 fence_value) { - if (fence->GetCompletedValue() >= fence_value) - return; + if (fence->GetCompletedValue() >= fence_value) + return; - CheckHR(fence->SetEventOnCompletion(fence_value, m_wait_on_cpu_fence_event)); - WaitForSingleObject(m_wait_on_cpu_fence_event, INFINITE); + CheckHR(fence->SetEventOnCompletion(fence_value, m_wait_on_cpu_fence_event)); + WaitForSingleObject(m_wait_on_cpu_fence_event, INFINITE); } void D3DCommandListManager::SetCommandListDirtyState(unsigned int command_list_state, bool dirty) { - if (dirty) - m_command_list_dirty_state |= command_list_state; - else - m_command_list_dirty_state &= ~command_list_state; + if (dirty) + m_command_list_dirty_state |= command_list_state; + else + m_command_list_dirty_state &= ~command_list_state; } bool D3DCommandListManager::GetCommandListDirtyState(COMMAND_LIST_STATE command_list_state) const { - return ((m_command_list_dirty_state & command_list_state) != 0); + return ((m_command_list_dirty_state & command_list_state) != 0); } -void D3DCommandListManager::SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY primitive_topology) +void D3DCommandListManager::SetCommandListPrimitiveTopology( + D3D_PRIMITIVE_TOPOLOGY primitive_topology) { - m_command_list_current_topology = primitive_topology; + m_command_list_current_topology = primitive_topology; } D3D_PRIMITIVE_TOPOLOGY D3DCommandListManager::GetCommandListPrimitiveTopology() const { - return m_command_list_current_topology; + return m_command_list_current_topology; } void D3DCommandListManager::CPUAccessNotify() { - m_cpu_access_last_frame = true; - m_cpu_access_this_frame = true; - m_draws_since_last_execution = 0; + m_cpu_access_last_frame = true; + m_cpu_access_this_frame = true; + m_draws_since_last_execution = 0; }; -ID3D12Fence* D3DCommandListManager::RegisterQueueFenceCallback(void* owning_object, PFN_QUEUE_FENCE_CALLBACK* callback_function) +ID3D12Fence* +D3DCommandListManager::RegisterQueueFenceCallback(void* owning_object, + PFN_QUEUE_FENCE_CALLBACK* callback_function) { - m_queue_fence_callbacks[owning_object] = callback_function; + m_queue_fence_callbacks[owning_object] = callback_function; - return m_queue_fence; + return m_queue_fence; } void D3DCommandListManager::RemoveQueueFenceCallback(void* owning_object) { - m_queue_fence_callbacks.erase(owning_object); + m_queue_fence_callbacks.erase(owning_object); } } // namespace DX12 \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D12/D3DCommandListManager.h b/Source/Core/VideoBackends/D3D12/D3DCommandListManager.h index 2629cd2333..0c8fd1a474 100644 --- a/Source/Core/VideoBackends/D3D12/D3DCommandListManager.h +++ b/Source/Core/VideoBackends/D3D12/D3DCommandListManager.h @@ -12,87 +12,87 @@ namespace DX12 { - enum COMMAND_LIST_STATE { - COMMAND_LIST_STATE_GS_CBV = 1, - COMMAND_LIST_STATE_PS_CBV = 2, - COMMAND_LIST_STATE_VS_CBV = 4, - COMMAND_LIST_STATE_PSO = 8, - COMMAND_LIST_STATE_SAMPLERS = 16, - COMMAND_LIST_STATE_VERTEX_BUFFER = 32 + COMMAND_LIST_STATE_GS_CBV = 1, + COMMAND_LIST_STATE_PS_CBV = 2, + COMMAND_LIST_STATE_VS_CBV = 4, + COMMAND_LIST_STATE_PSO = 8, + COMMAND_LIST_STATE_SAMPLERS = 16, + COMMAND_LIST_STATE_VERTEX_BUFFER = 32 }; // This class provides an abstraction for D3D12 descriptor heaps. class D3DCommandListManager { public: + D3DCommandListManager(D3D12_COMMAND_LIST_TYPE command_list_type, ID3D12Device* device, + ID3D12CommandQueue* command_queue); + ~D3DCommandListManager(); - D3DCommandListManager(D3D12_COMMAND_LIST_TYPE command_list_type, ID3D12Device* device, ID3D12CommandQueue* command_queue); - ~D3DCommandListManager(); + void SetInitialCommandListState(); - void SetInitialCommandListState(); + void GetCommandList(ID3D12GraphicsCommandList** command_list) const; - void GetCommandList(ID3D12GraphicsCommandList** command_list) const; + void ExecuteQueuedWork(bool wait_for_gpu_completion = false); + void ExecuteQueuedWorkAndPresent(IDXGISwapChain* swap_chain, UINT sync_interval, UINT flags); - void ExecuteQueuedWork(bool wait_for_gpu_completion = false); - void ExecuteQueuedWorkAndPresent(IDXGISwapChain* swap_chain, UINT sync_interval, UINT flags); + void DestroyResourceAfterCurrentCommandListExecuted(ID3D12Resource* resource); - void DestroyResourceAfterCurrentCommandListExecuted(ID3D12Resource* resource); + void SetCommandListDirtyState(unsigned int command_list_state, bool dirty); + bool GetCommandListDirtyState(COMMAND_LIST_STATE command_list_state) const; - void SetCommandListDirtyState(unsigned int command_list_state, bool dirty); - bool GetCommandListDirtyState(COMMAND_LIST_STATE command_list_state) const; + void SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY primitive_topology); + D3D_PRIMITIVE_TOPOLOGY GetCommandListPrimitiveTopology() const; - void SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY primitive_topology); - D3D_PRIMITIVE_TOPOLOGY GetCommandListPrimitiveTopology() const; + unsigned int m_draws_since_last_execution = 0; + bool m_cpu_access_last_frame = false; + bool m_cpu_access_this_frame = false; - unsigned int m_draws_since_last_execution = 0; - bool m_cpu_access_last_frame = false; - bool m_cpu_access_this_frame = false; + void CPUAccessNotify(); - void CPUAccessNotify(); + // Allow other components to register for a callback each time a fence is queued. + using PFN_QUEUE_FENCE_CALLBACK = void(void* owning_object, UINT64 fence_value); + ID3D12Fence* RegisterQueueFenceCallback(void* owning_object, + PFN_QUEUE_FENCE_CALLBACK* callback_function); + void RemoveQueueFenceCallback(void* owning_object); - // Allow other components to register for a callback each time a fence is queued. - using PFN_QUEUE_FENCE_CALLBACK = void(void* owning_object, UINT64 fence_value); - ID3D12Fence* RegisterQueueFenceCallback(void* owning_object, PFN_QUEUE_FENCE_CALLBACK* callback_function); - void RemoveQueueFenceCallback(void* owning_object); - - void WaitOnCPUForFence(ID3D12Fence* fence, UINT64 fence_value); + void WaitOnCPUForFence(ID3D12Fence* fence, UINT64 fence_value); private: - void DestroyAllPendingResources(); - void ResetAllCommandAllocators(); - void WaitForGPUCompletion(); + void DestroyAllPendingResources(); + void ResetAllCommandAllocators(); + void WaitForGPUCompletion(); - void PerformGPURolloverChecks(); - void MoveToNextCommandAllocator(); - void ResetCommandList(); + void PerformGPURolloverChecks(); + void MoveToNextCommandAllocator(); + void ResetCommandList(); - unsigned int m_command_list_dirty_state = UINT_MAX; - D3D_PRIMITIVE_TOPOLOGY m_command_list_current_topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; + unsigned int m_command_list_dirty_state = UINT_MAX; + D3D_PRIMITIVE_TOPOLOGY m_command_list_current_topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; - HANDLE m_wait_on_cpu_fence_event; + HANDLE m_wait_on_cpu_fence_event; - ID3D12Device* m_device; - ID3D12CommandQueue* m_command_queue; - UINT64 m_queue_fence_value; - ID3D12Fence* m_queue_fence; - UINT64 m_queue_frame_fence_value; - ID3D12Fence* m_queue_frame_fence; + ID3D12Device* m_device; + ID3D12CommandQueue* m_command_queue; + UINT64 m_queue_fence_value; + ID3D12Fence* m_queue_fence; + UINT64 m_queue_frame_fence_value; + ID3D12Fence* m_queue_frame_fence; - std::map m_queue_fence_callbacks; + std::map m_queue_fence_callbacks; - UINT m_current_command_allocator; - UINT m_current_command_allocator_list; - std::array, 2> m_command_allocator_lists; - std::array m_command_allocator_list_fences; + UINT m_current_command_allocator; + UINT m_current_command_allocator_list; + std::array, 2> m_command_allocator_lists; + std::array m_command_allocator_list_fences; - ID3D12GraphicsCommandList* m_backing_command_list; - ID3D12QueuedCommandList* m_queued_command_list; + ID3D12GraphicsCommandList* m_backing_command_list; + ID3D12QueuedCommandList* m_queued_command_list; - UINT m_current_deferred_destruction_list; - std::array, 2> m_deferred_destruction_lists; - std::array m_deferred_destruction_list_fences; + UINT m_current_deferred_destruction_list; + std::array, 2> m_deferred_destruction_lists; + std::array m_deferred_destruction_list_fences; }; } // namespace \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D12/D3DDescriptorHeapManager.cpp b/Source/Core/VideoBackends/D3D12/D3DDescriptorHeapManager.cpp index 25c1e7c79c..e302dcf044 100644 --- a/Source/Core/VideoBackends/D3D12/D3DDescriptorHeapManager.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DDescriptorHeapManager.cpp @@ -2,168 +2,186 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "VideoBackends/D3D12/D3DBase.h" #include "VideoBackends/D3D12/D3DDescriptorHeapManager.h" +#include "VideoBackends/D3D12/D3DBase.h" #include "VideoBackends/D3D12/D3DState.h" namespace DX12 { - -bool operator==(const D3DDescriptorHeapManager::SamplerStateSet& lhs, const D3DDescriptorHeapManager::SamplerStateSet& rhs) +bool operator==(const D3DDescriptorHeapManager::SamplerStateSet& lhs, + const D3DDescriptorHeapManager::SamplerStateSet& rhs) { - // D3D12TODO: Do something more efficient than this. - return (!memcmp(&lhs, &rhs, sizeof(D3DDescriptorHeapManager::SamplerStateSet))); + // D3D12TODO: Do something more efficient than this. + return (!memcmp(&lhs, &rhs, sizeof(D3DDescriptorHeapManager::SamplerStateSet))); } -D3DDescriptorHeapManager::D3DDescriptorHeapManager(D3D12_DESCRIPTOR_HEAP_DESC* desc, ID3D12Device* device, unsigned int temporarySlots) : - m_device(device) +D3DDescriptorHeapManager::D3DDescriptorHeapManager(D3D12_DESCRIPTOR_HEAP_DESC* desc, + ID3D12Device* device, + unsigned int temporarySlots) + : m_device(device) { - CheckHR(device->CreateDescriptorHeap(desc, IID_PPV_ARGS(&m_descriptor_heap))); + CheckHR(device->CreateDescriptorHeap(desc, IID_PPV_ARGS(&m_descriptor_heap))); - m_descriptor_heap_size = desc->NumDescriptors; - m_descriptor_increment_size = device->GetDescriptorHandleIncrementSize(desc->Type); - m_gpu_visible = (desc->Flags == D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE); + m_descriptor_heap_size = desc->NumDescriptors; + m_descriptor_increment_size = device->GetDescriptorHandleIncrementSize(desc->Type); + m_gpu_visible = (desc->Flags == D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE); - if (m_gpu_visible) - { - D3D12_DESCRIPTOR_HEAP_DESC cpu_shadow_heap_desc = *desc; - cpu_shadow_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + if (m_gpu_visible) + { + D3D12_DESCRIPTOR_HEAP_DESC cpu_shadow_heap_desc = *desc; + cpu_shadow_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; - CheckHR(device->CreateDescriptorHeap(&cpu_shadow_heap_desc, IID_PPV_ARGS(&m_descriptor_heap_cpu_shadow))); + CheckHR(device->CreateDescriptorHeap(&cpu_shadow_heap_desc, + IID_PPV_ARGS(&m_descriptor_heap_cpu_shadow))); - m_heap_base_gpu = m_descriptor_heap->GetGPUDescriptorHandleForHeapStart(); - m_heap_base_gpu_cpu_shadow = m_descriptor_heap_cpu_shadow->GetCPUDescriptorHandleForHeapStart(); - } + m_heap_base_gpu = m_descriptor_heap->GetGPUDescriptorHandleForHeapStart(); + m_heap_base_gpu_cpu_shadow = m_descriptor_heap_cpu_shadow->GetCPUDescriptorHandleForHeapStart(); + } - m_heap_base_cpu = m_descriptor_heap->GetCPUDescriptorHandleForHeapStart(); + m_heap_base_cpu = m_descriptor_heap->GetCPUDescriptorHandleForHeapStart(); - m_first_temporary_slot_in_heap = m_descriptor_heap_size - temporarySlots; - m_current_temporary_offset_in_heap = m_first_temporary_slot_in_heap; + m_first_temporary_slot_in_heap = m_descriptor_heap_size - temporarySlots; + m_current_temporary_offset_in_heap = m_first_temporary_slot_in_heap; } -bool D3DDescriptorHeapManager::Allocate(D3D12_CPU_DESCRIPTOR_HANDLE* cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* gpu_handle, D3D12_CPU_DESCRIPTOR_HANDLE* gpu_handle_cpu_shadow, bool temporary) +bool D3DDescriptorHeapManager::Allocate(D3D12_CPU_DESCRIPTOR_HANDLE* cpu_handle, + D3D12_GPU_DESCRIPTOR_HANDLE* gpu_handle, + D3D12_CPU_DESCRIPTOR_HANDLE* gpu_handle_cpu_shadow, + bool temporary) { - bool allocated_from_current_heap = true; + bool allocated_from_current_heap = true; - if (m_current_permanent_offset_in_heap + 1 >= m_first_temporary_slot_in_heap) - { - // If out of room in the heap, start back at beginning. - allocated_from_current_heap = false; - m_current_permanent_offset_in_heap = 0; - } + if (m_current_permanent_offset_in_heap + 1 >= m_first_temporary_slot_in_heap) + { + // If out of room in the heap, start back at beginning. + allocated_from_current_heap = false; + m_current_permanent_offset_in_heap = 0; + } - CHECK(!gpu_handle || (gpu_handle && m_gpu_visible), "D3D12_GPU_DESCRIPTOR_HANDLE used on non-GPU-visible heap."); + CHECK(!gpu_handle || (gpu_handle && m_gpu_visible), + "D3D12_GPU_DESCRIPTOR_HANDLE used on non-GPU-visible heap."); - if (temporary && m_current_temporary_offset_in_heap + 1 >= m_descriptor_heap_size) - { - m_current_temporary_offset_in_heap = m_first_temporary_slot_in_heap; - } + if (temporary && m_current_temporary_offset_in_heap + 1 >= m_descriptor_heap_size) + { + m_current_temporary_offset_in_heap = m_first_temporary_slot_in_heap; + } - unsigned int heapOffsetToUse = temporary ? m_current_temporary_offset_in_heap : m_current_permanent_offset_in_heap; + unsigned int heapOffsetToUse = + temporary ? m_current_temporary_offset_in_heap : m_current_permanent_offset_in_heap; - if (m_gpu_visible) - { - gpu_handle->ptr = m_heap_base_gpu.ptr + heapOffsetToUse * m_descriptor_increment_size; + if (m_gpu_visible) + { + gpu_handle->ptr = m_heap_base_gpu.ptr + heapOffsetToUse * m_descriptor_increment_size; - if (gpu_handle_cpu_shadow) - gpu_handle_cpu_shadow->ptr = m_heap_base_gpu_cpu_shadow.ptr + heapOffsetToUse * m_descriptor_increment_size; - } + if (gpu_handle_cpu_shadow) + gpu_handle_cpu_shadow->ptr = + m_heap_base_gpu_cpu_shadow.ptr + heapOffsetToUse * m_descriptor_increment_size; + } - cpu_handle->ptr = m_heap_base_cpu.ptr + heapOffsetToUse * m_descriptor_increment_size; + cpu_handle->ptr = m_heap_base_cpu.ptr + heapOffsetToUse * m_descriptor_increment_size; - if (!temporary) - { - m_current_permanent_offset_in_heap++; - } + if (!temporary) + { + m_current_permanent_offset_in_heap++; + } - return allocated_from_current_heap; + return allocated_from_current_heap; } -bool D3DDescriptorHeapManager::AllocateGroup(D3D12_CPU_DESCRIPTOR_HANDLE* base_cpu_handle, unsigned int num_handles, D3D12_GPU_DESCRIPTOR_HANDLE* base_gpu_handle, D3D12_CPU_DESCRIPTOR_HANDLE* base_gpu_handle_cpu_shadow, bool temporary) +bool D3DDescriptorHeapManager::AllocateGroup( + D3D12_CPU_DESCRIPTOR_HANDLE* base_cpu_handle, unsigned int num_handles, + D3D12_GPU_DESCRIPTOR_HANDLE* base_gpu_handle, + D3D12_CPU_DESCRIPTOR_HANDLE* base_gpu_handle_cpu_shadow, bool temporary) { - bool allocated_from_current_heap = true; + bool allocated_from_current_heap = true; - if (m_current_permanent_offset_in_heap + num_handles >= m_first_temporary_slot_in_heap) - { - // If out of room in the heap, start back at beginning. - allocated_from_current_heap = false; - m_current_permanent_offset_in_heap = 0; - } + if (m_current_permanent_offset_in_heap + num_handles >= m_first_temporary_slot_in_heap) + { + // If out of room in the heap, start back at beginning. + allocated_from_current_heap = false; + m_current_permanent_offset_in_heap = 0; + } - CHECK(!base_gpu_handle || (base_gpu_handle && m_gpu_visible), "D3D12_GPU_DESCRIPTOR_HANDLE used on non-GPU-visible heap."); + CHECK(!base_gpu_handle || (base_gpu_handle && m_gpu_visible), + "D3D12_GPU_DESCRIPTOR_HANDLE used on non-GPU-visible heap."); - if (temporary && m_current_temporary_offset_in_heap + num_handles >= m_descriptor_heap_size) - { - m_current_temporary_offset_in_heap = m_first_temporary_slot_in_heap; - } + if (temporary && m_current_temporary_offset_in_heap + num_handles >= m_descriptor_heap_size) + { + m_current_temporary_offset_in_heap = m_first_temporary_slot_in_heap; + } - unsigned int heapOffsetToUse = temporary ? m_current_temporary_offset_in_heap : m_current_permanent_offset_in_heap; + unsigned int heapOffsetToUse = + temporary ? m_current_temporary_offset_in_heap : m_current_permanent_offset_in_heap; - if (m_gpu_visible) - { - base_gpu_handle->ptr = m_heap_base_gpu.ptr + heapOffsetToUse * m_descriptor_increment_size; + if (m_gpu_visible) + { + base_gpu_handle->ptr = m_heap_base_gpu.ptr + heapOffsetToUse * m_descriptor_increment_size; - if (base_gpu_handle_cpu_shadow) - base_gpu_handle_cpu_shadow->ptr = m_heap_base_gpu_cpu_shadow.ptr + heapOffsetToUse * m_descriptor_increment_size; - } + if (base_gpu_handle_cpu_shadow) + base_gpu_handle_cpu_shadow->ptr = + m_heap_base_gpu_cpu_shadow.ptr + heapOffsetToUse * m_descriptor_increment_size; + } - base_cpu_handle->ptr = m_heap_base_cpu.ptr + heapOffsetToUse * m_descriptor_increment_size; + base_cpu_handle->ptr = m_heap_base_cpu.ptr + heapOffsetToUse * m_descriptor_increment_size; - if (temporary) - { - m_current_temporary_offset_in_heap += num_handles; - } - else - { - m_current_permanent_offset_in_heap += num_handles; - } + if (temporary) + { + m_current_temporary_offset_in_heap += num_handles; + } + else + { + m_current_permanent_offset_in_heap += num_handles; + } - return allocated_from_current_heap; + return allocated_from_current_heap; } -D3D12_GPU_DESCRIPTOR_HANDLE D3DDescriptorHeapManager::GetHandleForSamplerGroup(SamplerState* sampler_state, unsigned int num_sampler_samples) +D3D12_GPU_DESCRIPTOR_HANDLE +D3DDescriptorHeapManager::GetHandleForSamplerGroup(SamplerState* sampler_state, + unsigned int num_sampler_samples) { - auto it = m_sampler_map.find(*reinterpret_cast(sampler_state)); + auto it = m_sampler_map.find(*reinterpret_cast(sampler_state)); - if (it == m_sampler_map.end()) - { - D3D12_CPU_DESCRIPTOR_HANDLE base_sampler_cpu_handle; - D3D12_GPU_DESCRIPTOR_HANDLE base_sampler_gpu_handle; + if (it == m_sampler_map.end()) + { + D3D12_CPU_DESCRIPTOR_HANDLE base_sampler_cpu_handle; + D3D12_GPU_DESCRIPTOR_HANDLE base_sampler_gpu_handle; - bool allocatedFromExistingHeap = AllocateGroup(&base_sampler_cpu_handle, num_sampler_samples, &base_sampler_gpu_handle); + bool allocatedFromExistingHeap = + AllocateGroup(&base_sampler_cpu_handle, num_sampler_samples, &base_sampler_gpu_handle); - if (!allocatedFromExistingHeap) - { - m_sampler_map.clear(); - } + if (!allocatedFromExistingHeap) + { + m_sampler_map.clear(); + } - for (unsigned int i = 0; i < num_sampler_samples; i++) - { - D3D12_CPU_DESCRIPTOR_HANDLE destinationDescriptor; - destinationDescriptor.ptr = base_sampler_cpu_handle.ptr + i * D3D::sampler_descriptor_size; + for (unsigned int i = 0; i < num_sampler_samples; i++) + { + D3D12_CPU_DESCRIPTOR_HANDLE destinationDescriptor; + destinationDescriptor.ptr = base_sampler_cpu_handle.ptr + i * D3D::sampler_descriptor_size; - D3D::device12->CreateSampler(&StateCache::GetDesc12(sampler_state[i]), destinationDescriptor); - } + D3D::device12->CreateSampler(&StateCache::GetDesc12(sampler_state[i]), destinationDescriptor); + } - m_sampler_map[*reinterpret_cast(sampler_state)] = base_sampler_gpu_handle; + m_sampler_map[*reinterpret_cast(sampler_state)] = base_sampler_gpu_handle; - return base_sampler_gpu_handle; - } - else - { - return it->second; - } + return base_sampler_gpu_handle; + } + else + { + return it->second; + } } ID3D12DescriptorHeap* D3DDescriptorHeapManager::GetDescriptorHeap() const { - return m_descriptor_heap; + return m_descriptor_heap; } D3DDescriptorHeapManager::~D3DDescriptorHeapManager() { - SAFE_RELEASE(m_descriptor_heap); - SAFE_RELEASE(m_descriptor_heap_cpu_shadow); + SAFE_RELEASE(m_descriptor_heap); + SAFE_RELEASE(m_descriptor_heap_cpu_shadow); } } // namespace DX12 \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D12/D3DDescriptorHeapManager.h b/Source/Core/VideoBackends/D3D12/D3DDescriptorHeapManager.h index 4ff1fa789f..c64ae73125 100644 --- a/Source/Core/VideoBackends/D3D12/D3DDescriptorHeapManager.h +++ b/Source/Core/VideoBackends/D3D12/D3DDescriptorHeapManager.h @@ -11,62 +11,67 @@ namespace DX12 { - // This class provides an abstraction for D3D12 descriptor heaps. class D3DDescriptorHeapManager { public: + D3DDescriptorHeapManager(D3D12_DESCRIPTOR_HEAP_DESC* desc, ID3D12Device* device, + unsigned int temporarySlots = 0); + ~D3DDescriptorHeapManager(); - D3DDescriptorHeapManager(D3D12_DESCRIPTOR_HEAP_DESC* desc, ID3D12Device* device, unsigned int temporarySlots = 0); - ~D3DDescriptorHeapManager(); + bool Allocate(D3D12_CPU_DESCRIPTOR_HANDLE* cpu_handle, + D3D12_GPU_DESCRIPTOR_HANDLE* gpu_handle = nullptr, + D3D12_CPU_DESCRIPTOR_HANDLE* gpu_handle_cpu_shadow = nullptr, + bool temporary = false); + bool AllocateGroup(D3D12_CPU_DESCRIPTOR_HANDLE* cpu_handles, unsigned int num_handles, + D3D12_GPU_DESCRIPTOR_HANDLE* gpu_handles = nullptr, + D3D12_CPU_DESCRIPTOR_HANDLE* gpu_handle_cpu_shadows = nullptr, + bool temporary = false); - bool Allocate(D3D12_CPU_DESCRIPTOR_HANDLE* cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* gpu_handle = nullptr, D3D12_CPU_DESCRIPTOR_HANDLE* gpu_handle_cpu_shadow = nullptr, bool temporary = false); - bool AllocateGroup(D3D12_CPU_DESCRIPTOR_HANDLE* cpu_handles, unsigned int num_handles, D3D12_GPU_DESCRIPTOR_HANDLE* gpu_handles = nullptr, D3D12_CPU_DESCRIPTOR_HANDLE* gpu_handle_cpu_shadows = nullptr, bool temporary = false); + D3D12_GPU_DESCRIPTOR_HANDLE GetHandleForSamplerGroup(SamplerState* sampler_state, + unsigned int num_sampler_samples); - D3D12_GPU_DESCRIPTOR_HANDLE GetHandleForSamplerGroup(SamplerState* sampler_state, unsigned int num_sampler_samples); + ID3D12DescriptorHeap* GetDescriptorHeap() const; - ID3D12DescriptorHeap* GetDescriptorHeap() const; - - struct SamplerStateSet - { - SamplerState desc0; - SamplerState desc1; - SamplerState desc2; - SamplerState desc3; - SamplerState desc4; - SamplerState desc5; - SamplerState desc6; - SamplerState desc7; - }; + struct SamplerStateSet + { + SamplerState desc0; + SamplerState desc1; + SamplerState desc2; + SamplerState desc3; + SamplerState desc4; + SamplerState desc5; + SamplerState desc6; + SamplerState desc7; + }; private: + ID3D12Device* m_device = nullptr; + ID3D12DescriptorHeap* m_descriptor_heap = nullptr; + ID3D12DescriptorHeap* m_descriptor_heap_cpu_shadow = nullptr; - ID3D12Device* m_device = nullptr; - ID3D12DescriptorHeap* m_descriptor_heap = nullptr; - ID3D12DescriptorHeap* m_descriptor_heap_cpu_shadow = nullptr; + D3D12_CPU_DESCRIPTOR_HANDLE m_heap_base_cpu; + D3D12_GPU_DESCRIPTOR_HANDLE m_heap_base_gpu; + D3D12_CPU_DESCRIPTOR_HANDLE m_heap_base_gpu_cpu_shadow; - D3D12_CPU_DESCRIPTOR_HANDLE m_heap_base_cpu; - D3D12_GPU_DESCRIPTOR_HANDLE m_heap_base_gpu; - D3D12_CPU_DESCRIPTOR_HANDLE m_heap_base_gpu_cpu_shadow; + struct hash_sampler_desc + { + size_t operator()(const SamplerStateSet sampler_state_set) const + { + return sampler_state_set.desc0.hex; + } + }; - struct hash_sampler_desc - { - size_t operator()(const SamplerStateSet sampler_state_set) const - { - return sampler_state_set.desc0.hex; - } - }; + std::unordered_map m_sampler_map; - std::unordered_map m_sampler_map; + unsigned int m_current_temporary_offset_in_heap = 0; + unsigned int m_current_permanent_offset_in_heap = 0; - unsigned int m_current_temporary_offset_in_heap = 0; - unsigned int m_current_permanent_offset_in_heap = 0; + unsigned int m_descriptor_increment_size; + unsigned int m_descriptor_heap_size; + bool m_gpu_visible; - unsigned int m_descriptor_increment_size; - unsigned int m_descriptor_heap_size; - bool m_gpu_visible; - - unsigned int m_first_temporary_slot_in_heap; + unsigned int m_first_temporary_slot_in_heap; }; } // namespace \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D12/D3DQueuedCommandList.cpp b/Source/Core/VideoBackends/D3D12/D3DQueuedCommandList.cpp index 8a84a0c42b..6db743464b 100644 --- a/Source/Core/VideoBackends/D3D12/D3DQueuedCommandList.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DQueuedCommandList.cpp @@ -2,1371 +2,1270 @@ // Dual-Licensed under MIT and GPLv2+ // Refer to the license.txt file included. -#include "VideoBackends/D3D12/D3DBase.h" #include "VideoBackends/D3D12/D3DQueuedCommandList.h" +#include "VideoBackends/D3D12/D3DBase.h" namespace DX12 { - template constexpr size_t BufferOffsetForQueueItemType() { - return sizeof(T) + sizeof(D3DQueueItemType) * 2; + return sizeof(T) + sizeof(D3DQueueItemType) * 2; } -void ID3D12QueuedCommandList::BackgroundThreadFunction(ID3D12QueuedCommandList* parent_queued_command_list) +void ID3D12QueuedCommandList::BackgroundThreadFunction( + ID3D12QueuedCommandList* parent_queued_command_list) { - ID3D12GraphicsCommandList* command_list = parent_queued_command_list->m_command_list; - - byte* queue_array = parent_queued_command_list->m_queue_array; - - unsigned int queue_array_front = 0; - - while (true) - { - WaitForSingleObject(parent_queued_command_list->m_begin_execution_event, INFINITE); - - byte* item = &queue_array[queue_array_front]; - - while (true) - { - switch (reinterpret_cast(item)->Type) - { - case D3DQueueItemType::ClearDepthStencilView: - { - command_list->ClearDepthStencilView(reinterpret_cast(item)->ClearDepthStencilView.DepthStencilView, D3D12_CLEAR_FLAG_DEPTH, 0.f, 0, 0, nullptr); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::ClearRenderTargetView: - { - float clearColor[4] = { 0.f, 0.f, 0.f, 1.f }; - command_list->ClearRenderTargetView(reinterpret_cast(item)->ClearRenderTargetView.RenderTargetView, clearColor, 0, nullptr); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::CopyBufferRegion: - { - command_list->CopyBufferRegion( - reinterpret_cast(item)->CopyBufferRegion.pDstBuffer, - reinterpret_cast(item)->CopyBufferRegion.DstOffset, - reinterpret_cast(item)->CopyBufferRegion.pSrcBuffer, - reinterpret_cast(item)->CopyBufferRegion.SrcOffset, - reinterpret_cast(item)->CopyBufferRegion.NumBytes - ); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::CopyTextureRegion: - { - // If box is completely empty, assume that the original API call has a NULL box (which means - // copy from the entire resource. - - D3D12_BOX* src_box = &reinterpret_cast(item)->CopyTextureRegion.srcBox; - - // Front/Back never used, so don't need to check. - bool empty_box = - src_box->bottom == 0 && - src_box->left == 0 && - src_box->right == 0 && - src_box->top == 0; - - command_list->CopyTextureRegion( - &reinterpret_cast(item)->CopyTextureRegion.dst, - reinterpret_cast(item)->CopyTextureRegion.DstX, - reinterpret_cast(item)->CopyTextureRegion.DstY, - reinterpret_cast(item)->CopyTextureRegion.DstZ, - &reinterpret_cast(item)->CopyTextureRegion.src, - empty_box ? - nullptr : src_box - ); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::DrawIndexedInstanced: - { - command_list->DrawIndexedInstanced( - reinterpret_cast(item)->DrawIndexedInstanced.IndexCount, - 1, - reinterpret_cast(item)->DrawIndexedInstanced.StartIndexLocation, - reinterpret_cast(item)->DrawIndexedInstanced.BaseVertexLocation, - 0 - ); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::DrawInstanced: - { - command_list->DrawInstanced( - reinterpret_cast(item)->DrawInstanced.VertexCount, - 1, - reinterpret_cast(item)->DrawInstanced.StartVertexLocation, - 0 - ); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::IASetPrimitiveTopology: - { - command_list->IASetPrimitiveTopology(reinterpret_cast(item)->IASetPrimitiveTopology.PrimitiveTopology); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::ResourceBarrier: - { - command_list->ResourceBarrier(1, &reinterpret_cast(item)->ResourceBarrier.barrier); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::RSSetScissorRects: - { - D3D12_RECT rect = { - reinterpret_cast(item)->RSSetScissorRects.left, - reinterpret_cast(item)->RSSetScissorRects.top, - reinterpret_cast(item)->RSSetScissorRects.right, - reinterpret_cast(item)->RSSetScissorRects.bottom - }; - - command_list->RSSetScissorRects(1, &rect); - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::RSSetViewports: - { - D3D12_VIEWPORT viewport = { - reinterpret_cast(item)->RSSetViewports.TopLeftX, - reinterpret_cast(item)->RSSetViewports.TopLeftY, - reinterpret_cast(item)->RSSetViewports.Width, - reinterpret_cast(item)->RSSetViewports.Height, - reinterpret_cast(item)->RSSetViewports.MinDepth, - reinterpret_cast(item)->RSSetViewports.MaxDepth - }; - - command_list->RSSetViewports(1, &viewport); - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::SetDescriptorHeaps: - { - command_list->SetDescriptorHeaps( - reinterpret_cast(item)->SetDescriptorHeaps.NumDescriptorHeaps, - reinterpret_cast(item)->SetDescriptorHeaps.ppDescriptorHeap - ); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::SetGraphicsRootConstantBufferView: - { - command_list->SetGraphicsRootConstantBufferView( - reinterpret_cast(item)->SetGraphicsRootConstantBufferView.RootParameterIndex, - reinterpret_cast(item)->SetGraphicsRootConstantBufferView.BufferLocation - ); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::SetGraphicsRootDescriptorTable: - { - command_list->SetGraphicsRootDescriptorTable( - reinterpret_cast(item)->SetGraphicsRootDescriptorTable.RootParameterIndex, - reinterpret_cast(item)->SetGraphicsRootDescriptorTable.BaseDescriptor - ); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::SetGraphicsRootSignature: - { - command_list->SetGraphicsRootSignature( - reinterpret_cast(item)->SetGraphicsRootSignature.pRootSignature - ); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::SetIndexBuffer: - { - command_list->IASetIndexBuffer( - &reinterpret_cast(item)->SetIndexBuffer.desc - ); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::SetVertexBuffers: - { - command_list->IASetVertexBuffers( - 0, - 1, - &reinterpret_cast(item)->SetVertexBuffers.desc - ); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::SetPipelineState: - { - command_list->SetPipelineState(reinterpret_cast(item)->SetPipelineState.pPipelineStateObject); - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::SetRenderTargets: - { - unsigned int render_target_count = 0; - - if (reinterpret_cast(item)->SetRenderTargets.RenderTargetDescriptor.ptr) - { - render_target_count = 1; - } - - command_list->OMSetRenderTargets( - render_target_count, - reinterpret_cast(item)->SetRenderTargets.RenderTargetDescriptor.ptr == NULL ? - nullptr : - &reinterpret_cast(item)->SetRenderTargets.RenderTargetDescriptor, - FALSE, - reinterpret_cast(item)->SetRenderTargets.DepthStencilDescriptor.ptr == NULL ? - nullptr : - &reinterpret_cast(item)->SetRenderTargets.DepthStencilDescriptor - ); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::ResolveSubresource: - { - command_list->ResolveSubresource( - reinterpret_cast(item)->ResolveSubresource.pDstResource, - reinterpret_cast(item)->ResolveSubresource.DstSubresource, - reinterpret_cast(item)->ResolveSubresource.pSrcResource, - reinterpret_cast(item)->ResolveSubresource.SrcSubresource, - reinterpret_cast(item)->ResolveSubresource.Format - ); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::BeginQuery: - { - command_list->BeginQuery( - reinterpret_cast(item)->BeginQuery.pQueryHeap, - reinterpret_cast(item)->BeginQuery.Type, - reinterpret_cast(item)->BeginQuery.Index - ); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::EndQuery: - { - command_list->EndQuery( - reinterpret_cast(item)->EndQuery.pQueryHeap, - reinterpret_cast(item)->EndQuery.Type, - reinterpret_cast(item)->EndQuery.Index - ); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::ResolveQueryData: - { - command_list->ResolveQueryData( - reinterpret_cast(item)->ResolveQueryData.pQueryHeap, - reinterpret_cast(item)->ResolveQueryData.Type, - reinterpret_cast(item)->ResolveQueryData.StartElement, - reinterpret_cast(item)->ResolveQueryData.ElementCount, - reinterpret_cast(item)->ResolveQueryData.pDestinationBuffer, - reinterpret_cast(item)->ResolveQueryData.AlignedDestinationBufferOffset - ); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::CloseCommandList: - { - CheckHR(command_list->Close()); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::ExecuteCommandList: - { - parent_queued_command_list->m_command_queue->ExecuteCommandLists(1, reinterpret_cast(&command_list)); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::Present: - { - CheckHR(reinterpret_cast(item)->Present.swapChain->Present(reinterpret_cast(item)->Present.syncInterval, reinterpret_cast(item)->Present.flags)); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::ResetCommandList: - { - CheckHR(command_list->Reset(reinterpret_cast(item)->ResetCommandList.allocator, nullptr)); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::ResetCommandAllocator: - { - CheckHR(reinterpret_cast(item)->ResetCommandAllocator.allocator->Reset()); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::FenceGpuSignal: - { - CheckHR(parent_queued_command_list->m_command_queue->Signal(reinterpret_cast(item)->FenceGpuSignal.fence, reinterpret_cast(item)->FenceGpuSignal.fence_value)); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::FenceCpuSignal: - { - CheckHR(reinterpret_cast(item)->FenceCpuSignal.fence->Signal(reinterpret_cast(item)->FenceCpuSignal.fence_value)); - - item += BufferOffsetForQueueItemType(); - break; - } - - case D3DQueueItemType::Stop: - - // Use a goto to break out of the loop, since we can't exit the loop from - // within a switch statement. We could use a separate 'if' after the switch, - // but that was the highest source of overhead in the function after profiling. - // http://stackoverflow.com/questions/1420029/how-to-break-out-of-a-loop-from-inside-a-switch - - bool eligible_to_move_to_front_of_queue = reinterpret_cast(item)->Stop.eligible_to_move_to_front_of_queue; - bool signal_stop_event = reinterpret_cast(item)->Stop.signal_stop_event; - bool terminate_worker_thread = reinterpret_cast(item)->Stop.terminate_worker_thread; - - item += BufferOffsetForQueueItemType(); - - if (eligible_to_move_to_front_of_queue && item - queue_array > QUEUE_ARRAY_SIZE * 2 / 3) - { - item = queue_array; - } - - if (signal_stop_event) - { - SetEvent(parent_queued_command_list->m_stop_execution_event); - } - - if (terminate_worker_thread) - return; - - goto exitLoop; - } - } - - exitLoop: - - queue_array_front = static_cast(item - queue_array); - } + ID3D12GraphicsCommandList* command_list = parent_queued_command_list->m_command_list; + + byte* queue_array = parent_queued_command_list->m_queue_array; + + unsigned int queue_array_front = 0; + + while (true) + { + WaitForSingleObject(parent_queued_command_list->m_begin_execution_event, INFINITE); + + byte* item = &queue_array[queue_array_front]; + + while (true) + { + switch (reinterpret_cast(item)->Type) + { + case D3DQueueItemType::ClearDepthStencilView: + { + command_list->ClearDepthStencilView( + reinterpret_cast(item)->ClearDepthStencilView.DepthStencilView, + D3D12_CLEAR_FLAG_DEPTH, 0.f, 0, 0, nullptr); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::ClearRenderTargetView: + { + float clearColor[4] = {0.f, 0.f, 0.f, 1.f}; + command_list->ClearRenderTargetView( + reinterpret_cast(item)->ClearRenderTargetView.RenderTargetView, + clearColor, 0, nullptr); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::CopyBufferRegion: + { + command_list->CopyBufferRegion( + reinterpret_cast(item)->CopyBufferRegion.pDstBuffer, + reinterpret_cast(item)->CopyBufferRegion.DstOffset, + reinterpret_cast(item)->CopyBufferRegion.pSrcBuffer, + reinterpret_cast(item)->CopyBufferRegion.SrcOffset, + reinterpret_cast(item)->CopyBufferRegion.NumBytes); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::CopyTextureRegion: + { + // If box is completely empty, assume that the original API call has a NULL box (which means + // copy from the entire resource. + + D3D12_BOX* src_box = &reinterpret_cast(item)->CopyTextureRegion.srcBox; + + // Front/Back never used, so don't need to check. + bool empty_box = + src_box->bottom == 0 && src_box->left == 0 && src_box->right == 0 && src_box->top == 0; + + command_list->CopyTextureRegion( + &reinterpret_cast(item)->CopyTextureRegion.dst, + reinterpret_cast(item)->CopyTextureRegion.DstX, + reinterpret_cast(item)->CopyTextureRegion.DstY, + reinterpret_cast(item)->CopyTextureRegion.DstZ, + &reinterpret_cast(item)->CopyTextureRegion.src, + empty_box ? nullptr : src_box); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::DrawIndexedInstanced: + { + command_list->DrawIndexedInstanced( + reinterpret_cast(item)->DrawIndexedInstanced.IndexCount, 1, + reinterpret_cast(item)->DrawIndexedInstanced.StartIndexLocation, + reinterpret_cast(item)->DrawIndexedInstanced.BaseVertexLocation, 0); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::DrawInstanced: + { + command_list->DrawInstanced( + reinterpret_cast(item)->DrawInstanced.VertexCount, 1, + reinterpret_cast(item)->DrawInstanced.StartVertexLocation, 0); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::IASetPrimitiveTopology: + { + command_list->IASetPrimitiveTopology( + reinterpret_cast(item)->IASetPrimitiveTopology.PrimitiveTopology); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::ResourceBarrier: + { + command_list->ResourceBarrier( + 1, &reinterpret_cast(item)->ResourceBarrier.barrier); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::RSSetScissorRects: + { + D3D12_RECT rect = {reinterpret_cast(item)->RSSetScissorRects.left, + reinterpret_cast(item)->RSSetScissorRects.top, + reinterpret_cast(item)->RSSetScissorRects.right, + reinterpret_cast(item)->RSSetScissorRects.bottom}; + + command_list->RSSetScissorRects(1, &rect); + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::RSSetViewports: + { + D3D12_VIEWPORT viewport = {reinterpret_cast(item)->RSSetViewports.TopLeftX, + reinterpret_cast(item)->RSSetViewports.TopLeftY, + reinterpret_cast(item)->RSSetViewports.Width, + reinterpret_cast(item)->RSSetViewports.Height, + reinterpret_cast(item)->RSSetViewports.MinDepth, + reinterpret_cast(item)->RSSetViewports.MaxDepth}; + + command_list->RSSetViewports(1, &viewport); + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::SetDescriptorHeaps: + { + command_list->SetDescriptorHeaps( + reinterpret_cast(item)->SetDescriptorHeaps.NumDescriptorHeaps, + reinterpret_cast(item)->SetDescriptorHeaps.ppDescriptorHeap); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::SetGraphicsRootConstantBufferView: + { + command_list->SetGraphicsRootConstantBufferView( + reinterpret_cast(item) + ->SetGraphicsRootConstantBufferView.RootParameterIndex, + reinterpret_cast(item) + ->SetGraphicsRootConstantBufferView.BufferLocation); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::SetGraphicsRootDescriptorTable: + { + command_list->SetGraphicsRootDescriptorTable( + reinterpret_cast(item) + ->SetGraphicsRootDescriptorTable.RootParameterIndex, + reinterpret_cast(item)->SetGraphicsRootDescriptorTable.BaseDescriptor); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::SetGraphicsRootSignature: + { + command_list->SetGraphicsRootSignature( + reinterpret_cast(item)->SetGraphicsRootSignature.pRootSignature); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::SetIndexBuffer: + { + command_list->IASetIndexBuffer(&reinterpret_cast(item)->SetIndexBuffer.desc); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::SetVertexBuffers: + { + command_list->IASetVertexBuffers( + 0, 1, &reinterpret_cast(item)->SetVertexBuffers.desc); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::SetPipelineState: + { + command_list->SetPipelineState( + reinterpret_cast(item)->SetPipelineState.pPipelineStateObject); + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::SetRenderTargets: + { + unsigned int render_target_count = 0; + + if (reinterpret_cast(item)->SetRenderTargets.RenderTargetDescriptor.ptr) + { + render_target_count = 1; + } + + command_list->OMSetRenderTargets( + render_target_count, + reinterpret_cast(item)->SetRenderTargets.RenderTargetDescriptor.ptr == + NULL ? + nullptr : + &reinterpret_cast(item)->SetRenderTargets.RenderTargetDescriptor, + FALSE, + reinterpret_cast(item)->SetRenderTargets.DepthStencilDescriptor.ptr == + NULL ? + nullptr : + &reinterpret_cast(item)->SetRenderTargets.DepthStencilDescriptor); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::ResolveSubresource: + { + command_list->ResolveSubresource( + reinterpret_cast(item)->ResolveSubresource.pDstResource, + reinterpret_cast(item)->ResolveSubresource.DstSubresource, + reinterpret_cast(item)->ResolveSubresource.pSrcResource, + reinterpret_cast(item)->ResolveSubresource.SrcSubresource, + reinterpret_cast(item)->ResolveSubresource.Format); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::BeginQuery: + { + command_list->BeginQuery(reinterpret_cast(item)->BeginQuery.pQueryHeap, + reinterpret_cast(item)->BeginQuery.Type, + reinterpret_cast(item)->BeginQuery.Index); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::EndQuery: + { + command_list->EndQuery(reinterpret_cast(item)->EndQuery.pQueryHeap, + reinterpret_cast(item)->EndQuery.Type, + reinterpret_cast(item)->EndQuery.Index); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::ResolveQueryData: + { + command_list->ResolveQueryData( + reinterpret_cast(item)->ResolveQueryData.pQueryHeap, + reinterpret_cast(item)->ResolveQueryData.Type, + reinterpret_cast(item)->ResolveQueryData.StartElement, + reinterpret_cast(item)->ResolveQueryData.ElementCount, + reinterpret_cast(item)->ResolveQueryData.pDestinationBuffer, + reinterpret_cast(item)->ResolveQueryData.AlignedDestinationBufferOffset); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::CloseCommandList: + { + CheckHR(command_list->Close()); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::ExecuteCommandList: + { + parent_queued_command_list->m_command_queue->ExecuteCommandLists( + 1, reinterpret_cast(&command_list)); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::Present: + { + CheckHR(reinterpret_cast(item)->Present.swapChain->Present( + reinterpret_cast(item)->Present.syncInterval, + reinterpret_cast(item)->Present.flags)); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::ResetCommandList: + { + CheckHR(command_list->Reset( + reinterpret_cast(item)->ResetCommandList.allocator, nullptr)); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::ResetCommandAllocator: + { + CheckHR(reinterpret_cast(item)->ResetCommandAllocator.allocator->Reset()); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::FenceGpuSignal: + { + CheckHR(parent_queued_command_list->m_command_queue->Signal( + reinterpret_cast(item)->FenceGpuSignal.fence, + reinterpret_cast(item)->FenceGpuSignal.fence_value)); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::FenceCpuSignal: + { + CheckHR(reinterpret_cast(item)->FenceCpuSignal.fence->Signal( + reinterpret_cast(item)->FenceCpuSignal.fence_value)); + + item += BufferOffsetForQueueItemType(); + break; + } + + case D3DQueueItemType::Stop: + + // Use a goto to break out of the loop, since we can't exit the loop from + // within a switch statement. We could use a separate 'if' after the switch, + // but that was the highest source of overhead in the function after profiling. + // http://stackoverflow.com/questions/1420029/how-to-break-out-of-a-loop-from-inside-a-switch + + bool eligible_to_move_to_front_of_queue = + reinterpret_cast(item)->Stop.eligible_to_move_to_front_of_queue; + bool signal_stop_event = reinterpret_cast(item)->Stop.signal_stop_event; + bool terminate_worker_thread = + reinterpret_cast(item)->Stop.terminate_worker_thread; + + item += BufferOffsetForQueueItemType(); + + if (eligible_to_move_to_front_of_queue && item - queue_array > QUEUE_ARRAY_SIZE * 2 / 3) + { + item = queue_array; + } + + if (signal_stop_event) + { + SetEvent(parent_queued_command_list->m_stop_execution_event); + } + + if (terminate_worker_thread) + return; + + goto exitLoop; + } + } + + exitLoop: + + queue_array_front = static_cast(item - queue_array); + } } -ID3D12QueuedCommandList::ID3D12QueuedCommandList(ID3D12GraphicsCommandList* backing_command_list, ID3D12CommandQueue* backing_command_queue) : - m_command_list(backing_command_list), - m_command_queue(backing_command_queue) +ID3D12QueuedCommandList::ID3D12QueuedCommandList(ID3D12GraphicsCommandList* backing_command_list, + ID3D12CommandQueue* backing_command_queue) + : m_command_list(backing_command_list), m_command_queue(backing_command_queue) { - memset(m_queue_array, 0, sizeof(m_queue_array)); + memset(m_queue_array, 0, sizeof(m_queue_array)); - m_queue_array_back = m_queue_array; + m_queue_array_back = m_queue_array; - m_begin_execution_event = CreateSemaphore(nullptr, 0, 256, nullptr); - m_stop_execution_event = CreateEvent(nullptr, FALSE, FALSE, nullptr); + m_begin_execution_event = CreateSemaphore(nullptr, 0, 256, nullptr); + m_stop_execution_event = CreateEvent(nullptr, FALSE, FALSE, nullptr); - m_background_thread = std::thread(BackgroundThreadFunction, this); + m_background_thread = std::thread(BackgroundThreadFunction, this); } ID3D12QueuedCommandList::~ID3D12QueuedCommandList() { - // Kick worker thread, and tell it to exit. - ProcessQueuedItems(true, true, true); - m_background_thread.join(); + // Kick worker thread, and tell it to exit. + ProcessQueuedItems(true, true, true); + m_background_thread.join(); - CloseHandle(m_begin_execution_event); - CloseHandle(m_stop_execution_event); + CloseHandle(m_begin_execution_event); + CloseHandle(m_stop_execution_event); } void ID3D12QueuedCommandList::CheckForOverflow() { - constexpr const unsigned int queue_space_allowed_per_frame = QUEUE_ARRAY_SIZE / 3; + constexpr const unsigned int queue_space_allowed_per_frame = QUEUE_ARRAY_SIZE / 3; - if (m_queue_array_back - m_queue_array_back_at_start_of_frame > queue_space_allowed_per_frame) - { - // Game is (possibly) using too much space, kick off queue processing and - // wait on this thread till it chews through queue. + if (m_queue_array_back - m_queue_array_back_at_start_of_frame > queue_space_allowed_per_frame) + { + // Game is (possibly) using too much space, kick off queue processing and + // wait on this thread till it chews through queue. - // This means the game is submitting more than 28,000 draws a frame. + // This means the game is submitting more than 28,000 draws a frame. - ProcessQueuedItems(true, true); - } + ProcessQueuedItems(true, true); + } } void ID3D12QueuedCommandList::ResetQueueOverflowTracking() { - m_queue_array_back_at_start_of_frame = m_queue_array_back; + m_queue_array_back_at_start_of_frame = m_queue_array_back; } void ID3D12QueuedCommandList::QueueExecute() { - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::ExecuteCommandList; + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::ExecuteCommandList; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void ID3D12QueuedCommandList::QueueFenceGpuSignal(ID3D12Fence* fence_to_signal, UINT64 fence_value) { - D3DQueueItem item = {}; + D3DQueueItem item = {}; - item.Type = D3DQueueItemType::FenceGpuSignal; - item.FenceGpuSignal.fence = fence_to_signal; - item.FenceGpuSignal.fence_value = fence_value; + item.Type = D3DQueueItemType::FenceGpuSignal; + item.FenceGpuSignal.fence = fence_to_signal; + item.FenceGpuSignal.fence_value = fence_value; - *reinterpret_cast(m_queue_array_back) = item; + *reinterpret_cast(m_queue_array_back) = item; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void ID3D12QueuedCommandList::QueueFenceCpuSignal(ID3D12Fence* fence_to_signal, UINT64 fence_value) { - D3DQueueItem item = {}; + D3DQueueItem item = {}; - item.Type = D3DQueueItemType::FenceCpuSignal; - item.FenceCpuSignal.fence = fence_to_signal; - item.FenceCpuSignal.fence_value = fence_value; + item.Type = D3DQueueItemType::FenceCpuSignal; + item.FenceCpuSignal.fence = fence_to_signal; + item.FenceCpuSignal.fence_value = fence_value; - *reinterpret_cast(m_queue_array_back) = item; + *reinterpret_cast(m_queue_array_back) = item; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } -void ID3D12QueuedCommandList::QueuePresent(IDXGISwapChain* swap_chain, UINT sync_interval, UINT flags) +void ID3D12QueuedCommandList::QueuePresent(IDXGISwapChain* swap_chain, UINT sync_interval, + UINT flags) { - D3DQueueItem item = {}; + D3DQueueItem item = {}; - item.Type = D3DQueueItemType::Present; - item.Present.swapChain = swap_chain; - item.Present.flags = flags; - item.Present.syncInterval = sync_interval; + item.Type = D3DQueueItemType::Present; + item.Present.swapChain = swap_chain; + item.Present.flags = flags; + item.Present.syncInterval = sync_interval; - *reinterpret_cast(m_queue_array_back) = item; + *reinterpret_cast(m_queue_array_back) = item; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } -void ID3D12QueuedCommandList::ProcessQueuedItems(bool eligible_to_move_to_front_of_queue, bool wait_for_stop, bool terminate_worker_thread) +void ID3D12QueuedCommandList::ProcessQueuedItems(bool eligible_to_move_to_front_of_queue, + bool wait_for_stop, bool terminate_worker_thread) { - D3DQueueItem item = {}; + D3DQueueItem item = {}; - item.Type = D3DQueueItemType::Stop; - item.Stop.eligible_to_move_to_front_of_queue = eligible_to_move_to_front_of_queue; - item.Stop.signal_stop_event = wait_for_stop; - item.Stop.terminate_worker_thread = terminate_worker_thread; + item.Type = D3DQueueItemType::Stop; + item.Stop.eligible_to_move_to_front_of_queue = eligible_to_move_to_front_of_queue; + item.Stop.signal_stop_event = wait_for_stop; + item.Stop.terminate_worker_thread = terminate_worker_thread; - *reinterpret_cast(m_queue_array_back) = item; + *reinterpret_cast(m_queue_array_back) = item; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - // Only (possibly) move to front of queue when finishing a frame, or when draining GPU queue. - // Logic in ID3D12QueuedCommandList::CheckForOverflow - // ensures that not more than one third of queue is used per frame. - if (eligible_to_move_to_front_of_queue && (m_queue_array_back - m_queue_array > QUEUE_ARRAY_SIZE * 2 / 3)) - { - m_queue_array_back = m_queue_array; - } + // Only (possibly) move to front of queue when finishing a frame, or when draining GPU queue. + // Logic in ID3D12QueuedCommandList::CheckForOverflow + // ensures that not more than one third of queue is used per frame. + if (eligible_to_move_to_front_of_queue && + (m_queue_array_back - m_queue_array > QUEUE_ARRAY_SIZE * 2 / 3)) + { + m_queue_array_back = m_queue_array; + } - if (eligible_to_move_to_front_of_queue) - { - ResetQueueOverflowTracking(); - } + if (eligible_to_move_to_front_of_queue) + { + ResetQueueOverflowTracking(); + } - ReleaseSemaphore(m_begin_execution_event, 1, nullptr); + ReleaseSemaphore(m_begin_execution_event, 1, nullptr); - if (wait_for_stop) - { - WaitForSingleObject(m_stop_execution_event, INFINITE); - ResetEvent(m_stop_execution_event); - } + if (wait_for_stop) + { + WaitForSingleObject(m_stop_execution_event, INFINITE); + ResetEvent(m_stop_execution_event); + } } ULONG ID3D12QueuedCommandList::AddRef() { - m_ref.fetch_add(1); - return m_ref.load(); + m_ref.fetch_add(1); + return m_ref.load(); } ULONG ID3D12QueuedCommandList::Release() { - // fetch_sub returns the value held before the subtraction. - ULONG ref = m_ref.fetch_sub(1); - if (ref == 1) - { - delete this; - } + // fetch_sub returns the value held before the subtraction. + ULONG ref = m_ref.fetch_sub(1); + if (ref == 1) + { + delete this; + } - return ref; + return ref; } -HRESULT STDMETHODCALLTYPE ID3D12QueuedCommandList::QueryInterface( - _In_ REFIID riid, - _COM_Outptr_ void** ppvObject - ) +HRESULT STDMETHODCALLTYPE ID3D12QueuedCommandList::QueryInterface(_In_ REFIID riid, + _COM_Outptr_ void** ppvObject) { - *ppvObject = nullptr; - HRESULT hr = S_OK; + *ppvObject = nullptr; + HRESULT hr = S_OK; - if (riid == __uuidof(ID3D12GraphicsCommandList)) - { - *ppvObject = reinterpret_cast(this); - } - else if (riid == __uuidof(ID3D12CommandList)) - { - *ppvObject = reinterpret_cast(this); - } - else if (riid == __uuidof(ID3D12DeviceChild)) - { - *ppvObject = reinterpret_cast(this); - } - else if (riid == __uuidof(ID3D12Object)) - { - *ppvObject = reinterpret_cast(this); - } - else - { - hr = E_NOINTERFACE; - } + if (riid == __uuidof(ID3D12GraphicsCommandList)) + { + *ppvObject = reinterpret_cast(this); + } + else if (riid == __uuidof(ID3D12CommandList)) + { + *ppvObject = reinterpret_cast(this); + } + else if (riid == __uuidof(ID3D12DeviceChild)) + { + *ppvObject = reinterpret_cast(this); + } + else if (riid == __uuidof(ID3D12Object)) + { + *ppvObject = reinterpret_cast(this); + } + else + { + hr = E_NOINTERFACE; + } - if (*ppvObject != nullptr) - { - AddRef(); - } + if (*ppvObject != nullptr) + { + AddRef(); + } - return hr; + return hr; } // ID3D12Object HRESULT STDMETHODCALLTYPE ID3D12QueuedCommandList::GetPrivateData( - _In_ REFGUID guid, - _Inout_ UINT* pDataSize, - _Out_writes_bytes_opt_(*pDataSize) void* pData - ) + _In_ REFGUID guid, _Inout_ UINT* pDataSize, _Out_writes_bytes_opt_(*pDataSize) void* pData) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); - return E_FAIL; + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); + return E_FAIL; } -HRESULT STDMETHODCALLTYPE ID3D12QueuedCommandList::SetPrivateData( - _In_ REFGUID guid, - _In_ UINT DataSize, - _In_reads_bytes_opt_(DataSize) const void* pData - ) +HRESULT STDMETHODCALLTYPE ID3D12QueuedCommandList::SetPrivateData(_In_ REFGUID guid, + _In_ UINT DataSize, + _In_reads_bytes_opt_(DataSize) + const void* pData) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); - return E_FAIL; + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); + return E_FAIL; } -HRESULT STDMETHODCALLTYPE ID3D12QueuedCommandList::SetPrivateDataInterface( - _In_ REFGUID guid, - _In_opt_ const IUnknown* pData - ) +HRESULT STDMETHODCALLTYPE +ID3D12QueuedCommandList::SetPrivateDataInterface(_In_ REFGUID guid, _In_opt_ const IUnknown* pData) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); - return E_FAIL; + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); + return E_FAIL; } -HRESULT STDMETHODCALLTYPE ID3D12QueuedCommandList::SetName( - _In_z_ LPCWSTR pName - ) +HRESULT STDMETHODCALLTYPE ID3D12QueuedCommandList::SetName(_In_z_ LPCWSTR pName) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); - return E_FAIL; + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); + return E_FAIL; } // ID3D12DeviceChild D3D12_COMMAND_LIST_TYPE STDMETHODCALLTYPE ID3D12QueuedCommandList::GetType() { - return D3D12_COMMAND_LIST_TYPE_DIRECT; + return D3D12_COMMAND_LIST_TYPE_DIRECT; } // ID3D12CommandList -HRESULT STDMETHODCALLTYPE ID3D12QueuedCommandList::GetDevice( - REFIID riid, - _Out_ void** ppDevice - ) +HRESULT STDMETHODCALLTYPE ID3D12QueuedCommandList::GetDevice(REFIID riid, _Out_ void** ppDevice) { - return m_command_list->GetDevice(riid, ppDevice); + return m_command_list->GetDevice(riid, ppDevice); } -HRESULT STDMETHODCALLTYPE ID3D12QueuedCommandList::Close() { +HRESULT STDMETHODCALLTYPE ID3D12QueuedCommandList::Close() +{ + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::CloseCommandList; - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::CloseCommandList; + m_queue_array_back += BufferOffsetForQueueItemType(); - m_queue_array_back += BufferOffsetForQueueItemType(); + CheckForOverflow(); - CheckForOverflow(); - - return S_OK; + return S_OK; } HRESULT STDMETHODCALLTYPE ID3D12QueuedCommandList::Reset( - _In_ ID3D12CommandAllocator* pAllocator, - _In_opt_ ID3D12PipelineState* pInitialState - ) + _In_ ID3D12CommandAllocator* pAllocator, _In_opt_ ID3D12PipelineState* pInitialState) { - DEBUGCHECK(pInitialState == nullptr, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(pInitialState == nullptr, "Error: Invalid assumption in ID3D12QueuedCommandList."); - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::ResetCommandList; - reinterpret_cast(m_queue_array_back)->ResetCommandList.allocator = pAllocator; + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::ResetCommandList; + reinterpret_cast(m_queue_array_back)->ResetCommandList.allocator = pAllocator; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); - return S_OK; + return S_OK; } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::ClearState( - _In_ ID3D12PipelineState* pPipelineState - ) +void STDMETHODCALLTYPE ID3D12QueuedCommandList::ClearState(_In_ ID3D12PipelineState* pPipelineState) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::DrawInstanced( - _In_ UINT VertexCountPerInstance, - _In_ UINT InstanceCount, - _In_ UINT StartVertexLocation, - _In_ UINT StartInstanceLocation - ) +void STDMETHODCALLTYPE ID3D12QueuedCommandList::DrawInstanced(_In_ UINT VertexCountPerInstance, + _In_ UINT InstanceCount, + _In_ UINT StartVertexLocation, + _In_ UINT StartInstanceLocation) { - DEBUGCHECK(InstanceCount == 1, "Error: Invalid assumption in ID3D12QueuedCommandList."); - DEBUGCHECK(StartInstanceLocation == 0, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(InstanceCount == 1, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(StartInstanceLocation == 0, "Error: Invalid assumption in ID3D12QueuedCommandList."); - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::DrawInstanced; - reinterpret_cast(m_queue_array_back)->DrawInstanced.StartVertexLocation = StartVertexLocation; - reinterpret_cast(m_queue_array_back)->DrawInstanced.VertexCount = VertexCountPerInstance; + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::DrawInstanced; + reinterpret_cast(m_queue_array_back)->DrawInstanced.StartVertexLocation = + StartVertexLocation; + reinterpret_cast(m_queue_array_back)->DrawInstanced.VertexCount = + VertexCountPerInstance; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::DrawIndexedInstanced( - _In_ UINT IndexCountPerInstance, - _In_ UINT InstanceCount, - _In_ UINT StartIndexLocation, - _In_ INT BaseVertexLocation, - _In_ UINT StartInstanceLocation - ) + _In_ UINT IndexCountPerInstance, _In_ UINT InstanceCount, _In_ UINT StartIndexLocation, + _In_ INT BaseVertexLocation, _In_ UINT StartInstanceLocation) { - DEBUGCHECK(InstanceCount == 1, "Error: Invalid assumption in ID3D12QueuedCommandList."); - DEBUGCHECK(StartInstanceLocation == 0, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(InstanceCount == 1, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(StartInstanceLocation == 0, "Error: Invalid assumption in ID3D12QueuedCommandList."); - D3DQueueItem* item = reinterpret_cast(m_queue_array_back); + D3DQueueItem* item = reinterpret_cast(m_queue_array_back); - item->Type = D3DQueueItemType::DrawIndexedInstanced; - item->DrawIndexedInstanced.BaseVertexLocation = BaseVertexLocation; - item->DrawIndexedInstanced.IndexCount = IndexCountPerInstance; - item->DrawIndexedInstanced.StartIndexLocation = StartIndexLocation; + item->Type = D3DQueueItemType::DrawIndexedInstanced; + item->DrawIndexedInstanced.BaseVertexLocation = BaseVertexLocation; + item->DrawIndexedInstanced.IndexCount = IndexCountPerInstance; + item->DrawIndexedInstanced.StartIndexLocation = StartIndexLocation; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::Dispatch( - _In_ UINT ThreadGroupCountX, - _In_ UINT ThreadGroupCountY, - _In_ UINT ThreadGroupCountZ - ) +void STDMETHODCALLTYPE ID3D12QueuedCommandList::Dispatch(_In_ UINT ThreadGroupCountX, + _In_ UINT ThreadGroupCountY, + _In_ UINT ThreadGroupCountZ) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::DispatchIndirect( - _In_ ID3D12Resource* pBufferForArgs, - _In_ UINT AlignedByteOffsetForArgs - ) + _In_ ID3D12Resource* pBufferForArgs, _In_ UINT AlignedByteOffsetForArgs) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::CopyBufferRegion( - _In_ ID3D12Resource* pDstBuffer, - UINT64 DstOffset, - _In_ ID3D12Resource* pSrcBuffer, - UINT64 SrcOffset, - UINT64 NumBytes - ) +void STDMETHODCALLTYPE ID3D12QueuedCommandList::CopyBufferRegion(_In_ ID3D12Resource* pDstBuffer, + UINT64 DstOffset, + _In_ ID3D12Resource* pSrcBuffer, + UINT64 SrcOffset, UINT64 NumBytes) { - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::CopyBufferRegion; - reinterpret_cast(m_queue_array_back)->CopyBufferRegion.pDstBuffer = pDstBuffer; - reinterpret_cast(m_queue_array_back)->CopyBufferRegion.DstOffset = static_cast(DstOffset); - reinterpret_cast(m_queue_array_back)->CopyBufferRegion.pSrcBuffer = pSrcBuffer; - reinterpret_cast(m_queue_array_back)->CopyBufferRegion.SrcOffset = static_cast(SrcOffset); - reinterpret_cast(m_queue_array_back)->CopyBufferRegion.NumBytes = static_cast(NumBytes); + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::CopyBufferRegion; + reinterpret_cast(m_queue_array_back)->CopyBufferRegion.pDstBuffer = pDstBuffer; + reinterpret_cast(m_queue_array_back)->CopyBufferRegion.DstOffset = + static_cast(DstOffset); + reinterpret_cast(m_queue_array_back)->CopyBufferRegion.pSrcBuffer = pSrcBuffer; + reinterpret_cast(m_queue_array_back)->CopyBufferRegion.SrcOffset = + static_cast(SrcOffset); + reinterpret_cast(m_queue_array_back)->CopyBufferRegion.NumBytes = + static_cast(NumBytes); - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::CopyTextureRegion( - _In_ const D3D12_TEXTURE_COPY_LOCATION* pDst, - UINT DstX, - UINT DstY, - UINT DstZ, - _In_ const D3D12_TEXTURE_COPY_LOCATION* pSrc, - _In_opt_ const D3D12_BOX* pSrcBox - ) + _In_ const D3D12_TEXTURE_COPY_LOCATION* pDst, UINT DstX, UINT DstY, UINT DstZ, + _In_ const D3D12_TEXTURE_COPY_LOCATION* pSrc, _In_opt_ const D3D12_BOX* pSrcBox) { - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::CopyTextureRegion; - reinterpret_cast(m_queue_array_back)->CopyTextureRegion.dst =* pDst; - reinterpret_cast(m_queue_array_back)->CopyTextureRegion.src =* pSrc; + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::CopyTextureRegion; + reinterpret_cast(m_queue_array_back)->CopyTextureRegion.dst = *pDst; + reinterpret_cast(m_queue_array_back)->CopyTextureRegion.src = *pSrc; - reinterpret_cast(m_queue_array_back)->CopyTextureRegion.DstX = DstX; - reinterpret_cast(m_queue_array_back)->CopyTextureRegion.DstY = DstY; - reinterpret_cast(m_queue_array_back)->CopyTextureRegion.DstZ = DstZ; + reinterpret_cast(m_queue_array_back)->CopyTextureRegion.DstX = DstX; + reinterpret_cast(m_queue_array_back)->CopyTextureRegion.DstY = DstY; + reinterpret_cast(m_queue_array_back)->CopyTextureRegion.DstZ = DstZ; - if (pSrcBox) - reinterpret_cast(m_queue_array_back)->CopyTextureRegion.srcBox = *pSrcBox; - else - reinterpret_cast(m_queue_array_back)->CopyTextureRegion.srcBox = {}; + if (pSrcBox) + reinterpret_cast(m_queue_array_back)->CopyTextureRegion.srcBox = *pSrcBox; + else + reinterpret_cast(m_queue_array_back)->CopyTextureRegion.srcBox = {}; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::CopyResource( - _In_ ID3D12Resource* pDstResource, - _In_ ID3D12Resource* pSrcResource - ) +void STDMETHODCALLTYPE ID3D12QueuedCommandList::CopyResource(_In_ ID3D12Resource* pDstResource, + _In_ ID3D12Resource* pSrcResource) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::CopyTiles( - _In_ ID3D12Resource* pTiledResource, - _In_ const D3D12_TILED_RESOURCE_COORDINATE* pTileRegionStartCoordinate, - _In_ const D3D12_TILE_REGION_SIZE* pTileRegionSize, - _In_ ID3D12Resource* pBuffer, - UINT64 BufferStartOffsetInBytes, - D3D12_TILE_COPY_FLAGS Flags - ) + _In_ ID3D12Resource* pTiledResource, + _In_ const D3D12_TILED_RESOURCE_COORDINATE* pTileRegionStartCoordinate, + _In_ const D3D12_TILE_REGION_SIZE* pTileRegionSize, _In_ ID3D12Resource* pBuffer, + UINT64 BufferStartOffsetInBytes, D3D12_TILE_COPY_FLAGS Flags) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::ResolveSubresource( - _In_ ID3D12Resource* pDstResource, - _In_ UINT DstSubresource, - _In_ ID3D12Resource* pSrcResource, - _In_ UINT SrcSubresource, - _In_ DXGI_FORMAT Format - ) + _In_ ID3D12Resource* pDstResource, _In_ UINT DstSubresource, _In_ ID3D12Resource* pSrcResource, + _In_ UINT SrcSubresource, _In_ DXGI_FORMAT Format) { - // No ignored parameters, no assumptions to DEBUGCHECK. + // No ignored parameters, no assumptions to DEBUGCHECK. - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::ResolveSubresource; - reinterpret_cast(m_queue_array_back)->ResolveSubresource.pDstResource = pDstResource; - reinterpret_cast(m_queue_array_back)->ResolveSubresource.DstSubresource = DstSubresource; - reinterpret_cast(m_queue_array_back)->ResolveSubresource.pSrcResource = pSrcResource; - reinterpret_cast(m_queue_array_back)->ResolveSubresource.SrcSubresource = SrcSubresource; - reinterpret_cast(m_queue_array_back)->ResolveSubresource.Format = Format; + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::ResolveSubresource; + reinterpret_cast(m_queue_array_back)->ResolveSubresource.pDstResource = + pDstResource; + reinterpret_cast(m_queue_array_back)->ResolveSubresource.DstSubresource = + DstSubresource; + reinterpret_cast(m_queue_array_back)->ResolveSubresource.pSrcResource = + pSrcResource; + reinterpret_cast(m_queue_array_back)->ResolveSubresource.SrcSubresource = + SrcSubresource; + reinterpret_cast(m_queue_array_back)->ResolveSubresource.Format = Format; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::IASetPrimitiveTopology( - _In_ D3D12_PRIMITIVE_TOPOLOGY PrimitiveTopology - ) +void STDMETHODCALLTYPE +ID3D12QueuedCommandList::IASetPrimitiveTopology(_In_ D3D12_PRIMITIVE_TOPOLOGY PrimitiveTopology) { - // No ignored parameters, no assumptions to DEBUGCHECK. + // No ignored parameters, no assumptions to DEBUGCHECK. - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::IASetPrimitiveTopology; - reinterpret_cast(m_queue_array_back)->IASetPrimitiveTopology.PrimitiveTopology = PrimitiveTopology; + reinterpret_cast(m_queue_array_back)->Type = + D3DQueueItemType::IASetPrimitiveTopology; + reinterpret_cast(m_queue_array_back)->IASetPrimitiveTopology.PrimitiveTopology = + PrimitiveTopology; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::RSSetViewports( - _In_range_(0, D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT Count, - _In_reads_(Count) const D3D12_VIEWPORT* pViewports - ) + _In_range_(0, D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT Count, + _In_reads_(Count) const D3D12_VIEWPORT* pViewports) { - DEBUGCHECK(Count == 1, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(Count == 1, "Error: Invalid assumption in ID3D12QueuedCommandList."); - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::RSSetViewports; - reinterpret_cast(m_queue_array_back)->RSSetViewports.Height = pViewports->Height; - reinterpret_cast(m_queue_array_back)->RSSetViewports.Width = pViewports->Width; - reinterpret_cast(m_queue_array_back)->RSSetViewports.TopLeftX = pViewports->TopLeftX; - reinterpret_cast(m_queue_array_back)->RSSetViewports.TopLeftY = pViewports->TopLeftY; - reinterpret_cast(m_queue_array_back)->RSSetViewports.MinDepth = pViewports->MinDepth; - reinterpret_cast(m_queue_array_back)->RSSetViewports.MaxDepth = pViewports->MaxDepth; + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::RSSetViewports; + reinterpret_cast(m_queue_array_back)->RSSetViewports.Height = pViewports->Height; + reinterpret_cast(m_queue_array_back)->RSSetViewports.Width = pViewports->Width; + reinterpret_cast(m_queue_array_back)->RSSetViewports.TopLeftX = + pViewports->TopLeftX; + reinterpret_cast(m_queue_array_back)->RSSetViewports.TopLeftY = + pViewports->TopLeftY; + reinterpret_cast(m_queue_array_back)->RSSetViewports.MinDepth = + pViewports->MinDepth; + reinterpret_cast(m_queue_array_back)->RSSetViewports.MaxDepth = + pViewports->MaxDepth; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::RSSetScissorRects( - _In_range_(0, D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT Count, - _In_reads_(Count) const D3D12_RECT* pRects - ) + _In_range_(0, D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT Count, + _In_reads_(Count) const D3D12_RECT* pRects) { - DEBUGCHECK(Count == 1, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(Count == 1, "Error: Invalid assumption in ID3D12QueuedCommandList."); - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::RSSetScissorRects; - reinterpret_cast(m_queue_array_back)->RSSetScissorRects.bottom = pRects->bottom; - reinterpret_cast(m_queue_array_back)->RSSetScissorRects.left = pRects->left; - reinterpret_cast(m_queue_array_back)->RSSetScissorRects.right = pRects->right; - reinterpret_cast(m_queue_array_back)->RSSetScissorRects.top = pRects->top; + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::RSSetScissorRects; + reinterpret_cast(m_queue_array_back)->RSSetScissorRects.bottom = pRects->bottom; + reinterpret_cast(m_queue_array_back)->RSSetScissorRects.left = pRects->left; + reinterpret_cast(m_queue_array_back)->RSSetScissorRects.right = pRects->right; + reinterpret_cast(m_queue_array_back)->RSSetScissorRects.top = pRects->top; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::OMSetBlendFactor( - _In_opt_ const FLOAT BlendFactor[4] - ) +void STDMETHODCALLTYPE +ID3D12QueuedCommandList::OMSetBlendFactor(_In_opt_ const FLOAT BlendFactor[4]) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::OMSetStencilRef( - _In_ UINT StencilRef - ) +void STDMETHODCALLTYPE ID3D12QueuedCommandList::OMSetStencilRef(_In_ UINT StencilRef) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetPipelineState( - _In_ ID3D12PipelineState* pPipelineState - ) +void STDMETHODCALLTYPE +ID3D12QueuedCommandList::SetPipelineState(_In_ ID3D12PipelineState* pPipelineState) { - // No ignored parameters, no assumptions to DEBUGCHECK. + // No ignored parameters, no assumptions to DEBUGCHECK. - D3DQueueItem* item = reinterpret_cast(m_queue_array_back); + D3DQueueItem* item = reinterpret_cast(m_queue_array_back); - item->Type = D3DQueueItemType::SetPipelineState; - item->SetPipelineState.pPipelineStateObject = pPipelineState; + item->Type = D3DQueueItemType::SetPipelineState; + item->SetPipelineState.pPipelineStateObject = pPipelineState; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::ResourceBarrier( - _In_ UINT NumBarriers, - _In_reads_(NumBarriers) const D3D12_RESOURCE_BARRIER* pBarriers - ) + _In_ UINT NumBarriers, _In_reads_(NumBarriers) const D3D12_RESOURCE_BARRIER* pBarriers) { - DEBUGCHECK(NumBarriers == 1, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(NumBarriers == 1, "Error: Invalid assumption in ID3D12QueuedCommandList."); - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::ResourceBarrier; - reinterpret_cast(m_queue_array_back)->ResourceBarrier.barrier = *pBarriers; + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::ResourceBarrier; + reinterpret_cast(m_queue_array_back)->ResourceBarrier.barrier = *pBarriers; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::ExecuteBundle( - _In_ ID3D12GraphicsCommandList *pCommandList - ) +void STDMETHODCALLTYPE +ID3D12QueuedCommandList::ExecuteBundle(_In_ ID3D12GraphicsCommandList* pCommandList) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::BeginQuery( - _In_ ID3D12QueryHeap* pQueryHeap, - _In_ D3D12_QUERY_TYPE Type, - _In_ UINT Index - ) +void STDMETHODCALLTYPE ID3D12QueuedCommandList::BeginQuery(_In_ ID3D12QueryHeap* pQueryHeap, + _In_ D3D12_QUERY_TYPE Type, + _In_ UINT Index) { - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::BeginQuery; - reinterpret_cast(m_queue_array_back)->BeginQuery.pQueryHeap = pQueryHeap; - reinterpret_cast(m_queue_array_back)->BeginQuery.Type = Type; - reinterpret_cast(m_queue_array_back)->BeginQuery.Index = Index; + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::BeginQuery; + reinterpret_cast(m_queue_array_back)->BeginQuery.pQueryHeap = pQueryHeap; + reinterpret_cast(m_queue_array_back)->BeginQuery.Type = Type; + reinterpret_cast(m_queue_array_back)->BeginQuery.Index = Index; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::EndQuery( - _In_ ID3D12QueryHeap* pQueryHeap, - _In_ D3D12_QUERY_TYPE Type, - _In_ UINT Index - ) +void STDMETHODCALLTYPE ID3D12QueuedCommandList::EndQuery(_In_ ID3D12QueryHeap* pQueryHeap, + _In_ D3D12_QUERY_TYPE Type, + _In_ UINT Index) { - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::EndQuery; - reinterpret_cast(m_queue_array_back)->EndQuery.pQueryHeap = pQueryHeap; - reinterpret_cast(m_queue_array_back)->EndQuery.Type = Type; - reinterpret_cast(m_queue_array_back)->EndQuery.Index = Index; + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::EndQuery; + reinterpret_cast(m_queue_array_back)->EndQuery.pQueryHeap = pQueryHeap; + reinterpret_cast(m_queue_array_back)->EndQuery.Type = Type; + reinterpret_cast(m_queue_array_back)->EndQuery.Index = Index; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::ResolveQueryData( - _In_ ID3D12QueryHeap* pQueryHeap, - _In_ D3D12_QUERY_TYPE Type, - _In_ UINT StartElement, - _In_ UINT ElementCount, - _In_ ID3D12Resource* pDestinationBuffer, - _In_ UINT64 AlignedDestinationBufferOffset - ) + _In_ ID3D12QueryHeap* pQueryHeap, _In_ D3D12_QUERY_TYPE Type, _In_ UINT StartElement, + _In_ UINT ElementCount, _In_ ID3D12Resource* pDestinationBuffer, + _In_ UINT64 AlignedDestinationBufferOffset) { - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::ResolveQueryData; - reinterpret_cast(m_queue_array_back)->ResolveQueryData.pQueryHeap = pQueryHeap; - reinterpret_cast(m_queue_array_back)->ResolveQueryData.Type = Type; - reinterpret_cast(m_queue_array_back)->ResolveQueryData.StartElement = StartElement; - reinterpret_cast(m_queue_array_back)->ResolveQueryData.ElementCount = ElementCount; - reinterpret_cast(m_queue_array_back)->ResolveQueryData.pDestinationBuffer = pDestinationBuffer; - reinterpret_cast(m_queue_array_back)->ResolveQueryData.AlignedDestinationBufferOffset = AlignedDestinationBufferOffset; + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::ResolveQueryData; + reinterpret_cast(m_queue_array_back)->ResolveQueryData.pQueryHeap = pQueryHeap; + reinterpret_cast(m_queue_array_back)->ResolveQueryData.Type = Type; + reinterpret_cast(m_queue_array_back)->ResolveQueryData.StartElement = StartElement; + reinterpret_cast(m_queue_array_back)->ResolveQueryData.ElementCount = ElementCount; + reinterpret_cast(m_queue_array_back)->ResolveQueryData.pDestinationBuffer = + pDestinationBuffer; + reinterpret_cast(m_queue_array_back) + ->ResolveQueryData.AlignedDestinationBufferOffset = AlignedDestinationBufferOffset; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetPredication( - _In_opt_ ID3D12Resource* pBuffer, - _In_ UINT64 AlignedBufferOffset, - _In_ D3D12_PREDICATION_OP Operation - ) +void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetPredication(_In_opt_ ID3D12Resource* pBuffer, + _In_ UINT64 AlignedBufferOffset, + _In_ D3D12_PREDICATION_OP Operation) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetDescriptorHeaps( - _In_ UINT NumDescriptorHeaps, - _In_reads_(NumDescriptorHeaps) ID3D12DescriptorHeap *const * pDescriptorHeaps - ) + _In_ UINT NumDescriptorHeaps, + _In_reads_(NumDescriptorHeaps) ID3D12DescriptorHeap* const* pDescriptorHeaps) { - // No ignored parameters, no assumptions to DEBUGCHECK. + // No ignored parameters, no assumptions to DEBUGCHECK. - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::SetDescriptorHeaps; - reinterpret_cast(m_queue_array_back)->SetDescriptorHeaps.ppDescriptorHeap = pDescriptorHeaps; - reinterpret_cast(m_queue_array_back)->SetDescriptorHeaps.NumDescriptorHeaps = NumDescriptorHeaps; + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::SetDescriptorHeaps; + reinterpret_cast(m_queue_array_back)->SetDescriptorHeaps.ppDescriptorHeap = + pDescriptorHeaps; + reinterpret_cast(m_queue_array_back)->SetDescriptorHeaps.NumDescriptorHeaps = + NumDescriptorHeaps; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetComputeRootSignature( - _In_ ID3D12RootSignature* pRootSignature - ) +void STDMETHODCALLTYPE +ID3D12QueuedCommandList::SetComputeRootSignature(_In_ ID3D12RootSignature* pRootSignature) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetGraphicsRootSignature( - _In_ ID3D12RootSignature* pRootSignature - ) +void STDMETHODCALLTYPE +ID3D12QueuedCommandList::SetGraphicsRootSignature(_In_ ID3D12RootSignature* pRootSignature) { - // No ignored parameters, no assumptions to DEBUGCHECK. + // No ignored parameters, no assumptions to DEBUGCHECK. - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::SetGraphicsRootSignature; - reinterpret_cast(m_queue_array_back)->SetGraphicsRootSignature.pRootSignature = pRootSignature; + reinterpret_cast(m_queue_array_back)->Type = + D3DQueueItemType::SetGraphicsRootSignature; + reinterpret_cast(m_queue_array_back)->SetGraphicsRootSignature.pRootSignature = + pRootSignature; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetComputeRootDescriptorTable( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor - ) + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetGraphicsRootDescriptorTable( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor - ) + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor) { - // No ignored parameters, no assumptions to DEBUGCHECK. + // No ignored parameters, no assumptions to DEBUGCHECK. - D3DQueueItem* item = reinterpret_cast(m_queue_array_back); + D3DQueueItem* item = reinterpret_cast(m_queue_array_back); - item->Type = D3DQueueItemType::SetGraphicsRootDescriptorTable; - item->SetGraphicsRootDescriptorTable.RootParameterIndex = RootParameterIndex; - item->SetGraphicsRootDescriptorTable.BaseDescriptor = BaseDescriptor; + item->Type = D3DQueueItemType::SetGraphicsRootDescriptorTable; + item->SetGraphicsRootDescriptorTable.RootParameterIndex = RootParameterIndex; + item->SetGraphicsRootDescriptorTable.BaseDescriptor = BaseDescriptor; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetComputeRoot32BitConstant( - _In_ UINT RootParameterIndex, - _In_ UINT SrcData, - _In_ UINT DestOffsetIn32BitValues - ) + _In_ UINT RootParameterIndex, _In_ UINT SrcData, _In_ UINT DestOffsetIn32BitValues) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetGraphicsRoot32BitConstant( - _In_ UINT RootParameterIndex, - _In_ UINT SrcData, - _In_ UINT DestOffsetIn32BitValues - ) + _In_ UINT RootParameterIndex, _In_ UINT SrcData, _In_ UINT DestOffsetIn32BitValues) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetComputeRoot32BitConstants( - _In_ UINT RootParameterIndex, - _In_ UINT Num32BitValuesToSet, - _In_reads_(Num32BitValuesToSet*sizeof(UINT)) const void* pSrcData, - _In_ UINT DestOffsetIn32BitValues - ) + _In_ UINT RootParameterIndex, _In_ UINT Num32BitValuesToSet, + _In_reads_(Num32BitValuesToSet * sizeof(UINT)) const void* pSrcData, + _In_ UINT DestOffsetIn32BitValues) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetGraphicsRoot32BitConstants( - _In_ UINT RootParameterIndex, - _In_ UINT Num32BitValuesToSet, - _In_reads_(Num32BitValuesToSet*sizeof(UINT)) const void* pSrcData, - _In_ UINT DestOffsetIn32BitValues - ) + _In_ UINT RootParameterIndex, _In_ UINT Num32BitValuesToSet, + _In_reads_(Num32BitValuesToSet * sizeof(UINT)) const void* pSrcData, + _In_ UINT DestOffsetIn32BitValues) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetGraphicsRootConstantBufferView( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_VIRTUAL_ADDRESS BufferLocation - ) + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_VIRTUAL_ADDRESS BufferLocation) { - // No ignored parameters, no assumptions to DEBUGCHECK. + // No ignored parameters, no assumptions to DEBUGCHECK. - D3DQueueItem* item = reinterpret_cast(m_queue_array_back); + D3DQueueItem* item = reinterpret_cast(m_queue_array_back); - item->Type = D3DQueueItemType::SetGraphicsRootConstantBufferView; - item->SetGraphicsRootConstantBufferView.RootParameterIndex = RootParameterIndex; - item->SetGraphicsRootConstantBufferView.BufferLocation = BufferLocation; + item->Type = D3DQueueItemType::SetGraphicsRootConstantBufferView; + item->SetGraphicsRootConstantBufferView.RootParameterIndex = RootParameterIndex; + item->SetGraphicsRootConstantBufferView.BufferLocation = BufferLocation; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetComputeRootConstantBufferView( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_VIRTUAL_ADDRESS BufferLocation - ) + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_VIRTUAL_ADDRESS BufferLocation) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetComputeRootShaderResourceView( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle - ) + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetGraphicsRootShaderResourceView( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle - ) + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetComputeRootUnorderedAccessView( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle - ) + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetGraphicsRootUnorderedAccessView( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle - ) + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::IASetIndexBuffer( - _In_opt_ const D3D12_INDEX_BUFFER_VIEW* pDesc - ) +void STDMETHODCALLTYPE +ID3D12QueuedCommandList::IASetIndexBuffer(_In_opt_ const D3D12_INDEX_BUFFER_VIEW* pDesc) { - // No ignored parameters, no assumptions to DEBUGCHECK. + // No ignored parameters, no assumptions to DEBUGCHECK. - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::SetIndexBuffer; - reinterpret_cast(m_queue_array_back)->SetIndexBuffer.desc = *pDesc; + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::SetIndexBuffer; + reinterpret_cast(m_queue_array_back)->SetIndexBuffer.desc = *pDesc; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::IASetVertexBuffers( - _In_ UINT StartSlot, - _In_ UINT NumBuffers, - _In_ const D3D12_VERTEX_BUFFER_VIEW* pDesc - ) + _In_ UINT StartSlot, _In_ UINT NumBuffers, _In_ const D3D12_VERTEX_BUFFER_VIEW* pDesc) { - DEBUGCHECK(StartSlot == 0, "Error: Invalid assumption in ID3D12QueuedCommandList."); - DEBUGCHECK(NumBuffers == 1, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(StartSlot == 0, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(NumBuffers == 1, "Error: Invalid assumption in ID3D12QueuedCommandList."); - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::SetVertexBuffers; - reinterpret_cast(m_queue_array_back)->SetVertexBuffers.desc = *pDesc; + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::SetVertexBuffers; + reinterpret_cast(m_queue_array_back)->SetVertexBuffers.desc = *pDesc; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::SOSetTargets( - _In_ UINT StartSlot, - _In_ UINT NumViews, - _In_ const D3D12_STREAM_OUTPUT_BUFFER_VIEW* pViews - ) + _In_ UINT StartSlot, _In_ UINT NumViews, _In_ const D3D12_STREAM_OUTPUT_BUFFER_VIEW* pViews) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::OMSetRenderTargets( - _In_ UINT NumRenderTargetDescriptors, - _In_ const D3D12_CPU_DESCRIPTOR_HANDLE* pRenderTargetDescriptors, - _In_ BOOL RTsSingleHandleToDescriptorRange, - _In_opt_ const D3D12_CPU_DESCRIPTOR_HANDLE *pDepthStencilDescriptor - ) + _In_ UINT NumRenderTargetDescriptors, + _In_ const D3D12_CPU_DESCRIPTOR_HANDLE* pRenderTargetDescriptors, + _In_ BOOL RTsSingleHandleToDescriptorRange, + _In_opt_ const D3D12_CPU_DESCRIPTOR_HANDLE* pDepthStencilDescriptor) { - DEBUGCHECK(RTsSingleHandleToDescriptorRange == FALSE, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(RTsSingleHandleToDescriptorRange == FALSE, + "Error: Invalid assumption in ID3D12QueuedCommandList."); - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::SetRenderTargets; + reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::SetRenderTargets; - if (pRenderTargetDescriptors) - reinterpret_cast(m_queue_array_back)->SetRenderTargets.RenderTargetDescriptor = *pRenderTargetDescriptors; - else - reinterpret_cast(m_queue_array_back)->SetRenderTargets.RenderTargetDescriptor = {}; + if (pRenderTargetDescriptors) + reinterpret_cast(m_queue_array_back)->SetRenderTargets.RenderTargetDescriptor = + *pRenderTargetDescriptors; + else + reinterpret_cast(m_queue_array_back)->SetRenderTargets.RenderTargetDescriptor = + {}; - if (pDepthStencilDescriptor) - reinterpret_cast(m_queue_array_back)->SetRenderTargets.DepthStencilDescriptor = *pDepthStencilDescriptor; - else - reinterpret_cast(m_queue_array_back)->SetRenderTargets.DepthStencilDescriptor = {}; + if (pDepthStencilDescriptor) + reinterpret_cast(m_queue_array_back)->SetRenderTargets.DepthStencilDescriptor = + *pDepthStencilDescriptor; + else + reinterpret_cast(m_queue_array_back)->SetRenderTargets.DepthStencilDescriptor = + {}; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::ClearDepthStencilView( - _In_ D3D12_CPU_DESCRIPTOR_HANDLE DepthStencilView, - _In_ D3D12_CLEAR_FLAGS ClearFlags, - _In_ FLOAT Depth, - _In_ UINT8 Stencil, - _In_ UINT NumRects, - _In_reads_opt_(NumRects) const D3D12_RECT* pRect - ) + _In_ D3D12_CPU_DESCRIPTOR_HANDLE DepthStencilView, _In_ D3D12_CLEAR_FLAGS ClearFlags, + _In_ FLOAT Depth, _In_ UINT8 Stencil, _In_ UINT NumRects, + _In_reads_opt_(NumRects) const D3D12_RECT* pRect) { - DEBUGCHECK(ClearFlags == D3D12_CLEAR_FLAG_DEPTH, "Error: Invalid assumption in ID3D12QueuedCommandList."); - DEBUGCHECK(Depth == 0.0f, "Error: Invalid assumption in ID3D12QueuedCommandList."); - DEBUGCHECK(Stencil == 0, "Error: Invalid assumption in ID3D12QueuedCommandList."); - DEBUGCHECK(pRect == nullptr, "Error: Invalid assumption in ID3D12QueuedCommandList."); - DEBUGCHECK(NumRects == 0, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(ClearFlags == D3D12_CLEAR_FLAG_DEPTH, + "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(Depth == 0.0f, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(Stencil == 0, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(pRect == nullptr, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(NumRects == 0, "Error: Invalid assumption in ID3D12QueuedCommandList."); - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::ClearDepthStencilView; - reinterpret_cast(m_queue_array_back)->ClearDepthStencilView.DepthStencilView = DepthStencilView; + reinterpret_cast(m_queue_array_back)->Type = + D3DQueueItemType::ClearDepthStencilView; + reinterpret_cast(m_queue_array_back)->ClearDepthStencilView.DepthStencilView = + DepthStencilView; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::ClearRenderTargetView( - _In_ D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetView, - _In_ const FLOAT ColorRGBA[4], - _In_ UINT NumRects, - _In_reads_opt_(NumRects) const D3D12_RECT* pRects - ) + _In_ D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetView, _In_ const FLOAT ColorRGBA[4], + _In_ UINT NumRects, _In_reads_opt_(NumRects) const D3D12_RECT* pRects) { - DEBUGCHECK(ColorRGBA[0] == 0.0f, "Error: Invalid assumption in ID3D12QueuedCommandList."); - DEBUGCHECK(ColorRGBA[1] == 0.0f, "Error: Invalid assumption in ID3D12QueuedCommandList."); - DEBUGCHECK(ColorRGBA[2] == 0.0f, "Error: Invalid assumption in ID3D12QueuedCommandList."); - DEBUGCHECK(ColorRGBA[3] == 1.0f, "Error: Invalid assumption in ID3D12QueuedCommandList."); - DEBUGCHECK(pRects == nullptr, "Error: Invalid assumption in ID3D12QueuedCommandList."); - DEBUGCHECK(NumRects == 0, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(ColorRGBA[0] == 0.0f, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(ColorRGBA[1] == 0.0f, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(ColorRGBA[2] == 0.0f, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(ColorRGBA[3] == 1.0f, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(pRects == nullptr, "Error: Invalid assumption in ID3D12QueuedCommandList."); + DEBUGCHECK(NumRects == 0, "Error: Invalid assumption in ID3D12QueuedCommandList."); - reinterpret_cast(m_queue_array_back)->Type = D3DQueueItemType::ClearRenderTargetView; - reinterpret_cast(m_queue_array_back)->ClearRenderTargetView.RenderTargetView = RenderTargetView; + reinterpret_cast(m_queue_array_back)->Type = + D3DQueueItemType::ClearRenderTargetView; + reinterpret_cast(m_queue_array_back)->ClearRenderTargetView.RenderTargetView = + RenderTargetView; - m_queue_array_back += BufferOffsetForQueueItemType(); + m_queue_array_back += BufferOffsetForQueueItemType(); - CheckForOverflow(); + CheckForOverflow(); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::ClearUnorderedAccessViewUint( - _In_ D3D12_GPU_DESCRIPTOR_HANDLE ViewGPUHandleInCurrentHeap, - _In_ D3D12_CPU_DESCRIPTOR_HANDLE ViewCPUHandle, - _In_ ID3D12Resource* pResource, - _In_ const UINT Values[4], - _In_ UINT NumRects, - _In_reads_opt_(NumRects) const D3D12_RECT* pRects - ) + _In_ D3D12_GPU_DESCRIPTOR_HANDLE ViewGPUHandleInCurrentHeap, + _In_ D3D12_CPU_DESCRIPTOR_HANDLE ViewCPUHandle, _In_ ID3D12Resource* pResource, + _In_ const UINT Values[4], _In_ UINT NumRects, + _In_reads_opt_(NumRects) const D3D12_RECT* pRects) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::ClearUnorderedAccessViewFloat( - _In_ D3D12_GPU_DESCRIPTOR_HANDLE ViewGPUHandleInCurrentHeap, - _In_ D3D12_CPU_DESCRIPTOR_HANDLE ViewCPUHandle, - _In_ ID3D12Resource* pResource, - _In_ const FLOAT Values[4], - _In_ UINT NumRects, - _In_reads_opt_(NumRects) const D3D12_RECT* pRects - ) + _In_ D3D12_GPU_DESCRIPTOR_HANDLE ViewGPUHandleInCurrentHeap, + _In_ D3D12_CPU_DESCRIPTOR_HANDLE ViewCPUHandle, _In_ ID3D12Resource* pResource, + _In_ const FLOAT Values[4], _In_ UINT NumRects, + _In_reads_opt_(NumRects) const D3D12_RECT* pRects) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::DiscardResource( - _In_ ID3D12Resource* pResource, - _In_opt_ const D3D12_DISCARD_REGION* pDesc - ) + _In_ ID3D12Resource* pResource, _In_opt_ const D3D12_DISCARD_REGION* pDesc) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetMarker( - UINT Metadata, - _In_reads_bytes_opt_(Size) const void* pData, - UINT Size - ) +void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetMarker(UINT Metadata, _In_reads_bytes_opt_(Size) + const void* pData, + UINT Size) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } -void STDMETHODCALLTYPE ID3D12QueuedCommandList::BeginEvent( - UINT Metadata, - _In_reads_bytes_opt_(Size) const void* pData, - UINT Size - ) +void STDMETHODCALLTYPE ID3D12QueuedCommandList::BeginEvent(UINT Metadata, _In_reads_bytes_opt_(Size) + const void* pData, + UINT Size) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::EndEvent() { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } void STDMETHODCALLTYPE ID3D12QueuedCommandList::ExecuteIndirect( - _In_ ID3D12CommandSignature* pCommandSignature, - _In_ UINT MaxCommandCount, - _In_ ID3D12Resource* pArgumentBuffer, - _In_ UINT64 ArgumentBufferOffset, - _In_opt_ ID3D12Resource* pCountBuffer, - _In_ UINT64 CountBufferOffset - ) + _In_ ID3D12CommandSignature* pCommandSignature, _In_ UINT MaxCommandCount, + _In_ ID3D12Resource* pArgumentBuffer, _In_ UINT64 ArgumentBufferOffset, + _In_opt_ ID3D12Resource* pCountBuffer, _In_ UINT64 CountBufferOffset) { - // Function not implemented yet. - DEBUGCHECK(0, "Function not implemented yet."); + // Function not implemented yet. + DEBUGCHECK(0, "Function not implemented yet."); } } // namespace DX12 \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D12/D3DQueuedCommandList.h b/Source/Core/VideoBackends/D3D12/D3DQueuedCommandList.h index 2c9d80febe..d192ac608d 100644 --- a/Source/Core/VideoBackends/D3D12/D3DQueuedCommandList.h +++ b/Source/Core/VideoBackends/D3D12/D3DQueuedCommandList.h @@ -10,191 +10,190 @@ namespace DX12 { - static const unsigned int QUEUE_ARRAY_SIZE = 24 * 1024 * 1024; enum D3DQueueItemType { - AbortProcessing = 0, - SetPipelineState, - SetRenderTargets, - SetVertexBuffers, - SetIndexBuffer, - RSSetViewports, - RSSetScissorRects, - SetGraphicsRootDescriptorTable, - SetGraphicsRootConstantBufferView, - SetGraphicsRootSignature, - ClearRenderTargetView, - ClearDepthStencilView, - DrawInstanced, - DrawIndexedInstanced, - IASetPrimitiveTopology, - CopyBufferRegion, - CopyTextureRegion, - SetDescriptorHeaps, - ResourceBarrier, - ResolveSubresource, - BeginQuery, - EndQuery, - ResolveQueryData, - ExecuteCommandList, - CloseCommandList, - Present, - ResetCommandList, - ResetCommandAllocator, - FenceGpuSignal, - FenceCpuSignal, - Stop + AbortProcessing = 0, + SetPipelineState, + SetRenderTargets, + SetVertexBuffers, + SetIndexBuffer, + RSSetViewports, + RSSetScissorRects, + SetGraphicsRootDescriptorTable, + SetGraphicsRootConstantBufferView, + SetGraphicsRootSignature, + ClearRenderTargetView, + ClearDepthStencilView, + DrawInstanced, + DrawIndexedInstanced, + IASetPrimitiveTopology, + CopyBufferRegion, + CopyTextureRegion, + SetDescriptorHeaps, + ResourceBarrier, + ResolveSubresource, + BeginQuery, + EndQuery, + ResolveQueryData, + ExecuteCommandList, + CloseCommandList, + Present, + ResetCommandList, + ResetCommandAllocator, + FenceGpuSignal, + FenceCpuSignal, + Stop }; struct SetPipelineStateArguments { - ID3D12PipelineState* pPipelineStateObject; + ID3D12PipelineState* pPipelineStateObject; }; struct SetRenderTargetsArguments { - D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetDescriptor; - D3D12_CPU_DESCRIPTOR_HANDLE DepthStencilDescriptor; + D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetDescriptor; + D3D12_CPU_DESCRIPTOR_HANDLE DepthStencilDescriptor; }; struct SetVertexBuffersArguments { - // UINT startSlot; - Dolphin only uses the 0th slot. - D3D12_VERTEX_BUFFER_VIEW desc; - // UINT numBuffers; - Only supporting single vertex buffer set since that's all Dolphin uses. + // UINT startSlot; - Dolphin only uses the 0th slot. + D3D12_VERTEX_BUFFER_VIEW desc; + // UINT numBuffers; - Only supporting single vertex buffer set since that's all Dolphin uses. }; struct SetIndexBufferArguments { - D3D12_INDEX_BUFFER_VIEW desc; + D3D12_INDEX_BUFFER_VIEW desc; }; struct RSSetViewportsArguments { - FLOAT TopLeftX; - FLOAT TopLeftY; - FLOAT Width; - FLOAT Height; - FLOAT MinDepth; - FLOAT MaxDepth; + FLOAT TopLeftX; + FLOAT TopLeftY; + FLOAT Width; + FLOAT Height; + FLOAT MinDepth; + FLOAT MaxDepth; }; struct RSSetScissorRectsArguments { - LONG left; - LONG top; - LONG right; - LONG bottom; + LONG left; + LONG top; + LONG right; + LONG bottom; }; struct SetGraphicsRootDescriptorTableArguments { - UINT RootParameterIndex; - D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor; + UINT RootParameterIndex; + D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor; }; struct SetGraphicsRootConstantBufferViewArguments { - UINT RootParameterIndex; - D3D12_GPU_VIRTUAL_ADDRESS BufferLocation; + UINT RootParameterIndex; + D3D12_GPU_VIRTUAL_ADDRESS BufferLocation; }; struct SetGraphicsRootSignatureArguments { - ID3D12RootSignature* pRootSignature; + ID3D12RootSignature* pRootSignature; }; struct ClearRenderTargetViewArguments { - D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetView; + D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetView; }; struct ClearDepthStencilViewArguments { - D3D12_CPU_DESCRIPTOR_HANDLE DepthStencilView; + D3D12_CPU_DESCRIPTOR_HANDLE DepthStencilView; }; struct DrawInstancedArguments { - UINT VertexCount; - UINT StartVertexLocation; + UINT VertexCount; + UINT StartVertexLocation; }; struct DrawIndexedInstancedArguments { - UINT IndexCount; - UINT StartIndexLocation; - INT BaseVertexLocation; + UINT IndexCount; + UINT StartIndexLocation; + INT BaseVertexLocation; }; struct IASetPrimitiveTopologyArguments { - D3D12_PRIMITIVE_TOPOLOGY PrimitiveTopology; + D3D12_PRIMITIVE_TOPOLOGY PrimitiveTopology; }; struct CopyBufferRegionArguments { - ID3D12Resource* pDstBuffer; - UINT DstOffset; - ID3D12Resource* pSrcBuffer; - UINT SrcOffset; - UINT NumBytes; + ID3D12Resource* pDstBuffer; + UINT DstOffset; + ID3D12Resource* pSrcBuffer; + UINT SrcOffset; + UINT NumBytes; }; struct CopyTextureRegionArguments { - D3D12_TEXTURE_COPY_LOCATION dst; - UINT DstX; - UINT DstY; - UINT DstZ; - D3D12_TEXTURE_COPY_LOCATION src; - D3D12_BOX srcBox; + D3D12_TEXTURE_COPY_LOCATION dst; + UINT DstX; + UINT DstY; + UINT DstZ; + D3D12_TEXTURE_COPY_LOCATION src; + D3D12_BOX srcBox; }; struct SetDescriptorHeapsArguments { - ID3D12DescriptorHeap* const* ppDescriptorHeap; - UINT NumDescriptorHeaps; + ID3D12DescriptorHeap* const* ppDescriptorHeap; + UINT NumDescriptorHeaps; }; struct ResourceBarrierArguments { - D3D12_RESOURCE_BARRIER barrier; + D3D12_RESOURCE_BARRIER barrier; }; struct ResolveSubresourceArguments { - ID3D12Resource* pDstResource; - UINT DstSubresource; - ID3D12Resource* pSrcResource; - UINT SrcSubresource; - DXGI_FORMAT Format; + ID3D12Resource* pDstResource; + UINT DstSubresource; + ID3D12Resource* pSrcResource; + UINT SrcSubresource; + DXGI_FORMAT Format; }; struct BeginQueryArguments { - ID3D12QueryHeap* pQueryHeap; - D3D12_QUERY_TYPE Type; - UINT Index; + ID3D12QueryHeap* pQueryHeap; + D3D12_QUERY_TYPE Type; + UINT Index; }; struct EndQueryArguments { - ID3D12QueryHeap* pQueryHeap; - D3D12_QUERY_TYPE Type; - UINT Index; + ID3D12QueryHeap* pQueryHeap; + D3D12_QUERY_TYPE Type; + UINT Index; }; struct ResolveQueryDataArguments { - ID3D12QueryHeap* pQueryHeap; - D3D12_QUERY_TYPE Type; - UINT StartElement; - UINT ElementCount; - ID3D12Resource* pDestinationBuffer; - UINT64 AlignedDestinationBufferOffset; + ID3D12QueryHeap* pQueryHeap; + D3D12_QUERY_TYPE Type; + UINT StartElement; + UINT ElementCount; + ID3D12Resource* pDestinationBuffer; + UINT64 AlignedDestinationBufferOffset; }; struct CloseCommandListArguments @@ -207,458 +206,329 @@ struct ExecuteCommandListArguments struct PresentArguments { - IDXGISwapChain* swapChain; - UINT syncInterval; - UINT flags; + IDXGISwapChain* swapChain; + UINT syncInterval; + UINT flags; }; struct ResetCommandListArguments { - ID3D12CommandAllocator* allocator; + ID3D12CommandAllocator* allocator; }; struct ResetCommandAllocatorArguments { - ID3D12CommandAllocator* allocator; + ID3D12CommandAllocator* allocator; }; struct FenceGpuSignalArguments { - ID3D12Fence* fence; - UINT64 fence_value; + ID3D12Fence* fence; + UINT64 fence_value; }; struct FenceCpuSignalArguments { - ID3D12Fence* fence; - UINT64 fence_value; + ID3D12Fence* fence; + UINT64 fence_value; }; struct StopArguments { - bool eligible_to_move_to_front_of_queue; - bool signal_stop_event; - bool terminate_worker_thread; + bool eligible_to_move_to_front_of_queue; + bool signal_stop_event; + bool terminate_worker_thread; }; struct D3DQueueItem { - D3DQueueItemType Type; + D3DQueueItemType Type; - union - { - SetPipelineStateArguments SetPipelineState; - SetRenderTargetsArguments SetRenderTargets; - SetVertexBuffersArguments SetVertexBuffers; - SetIndexBufferArguments SetIndexBuffer; - RSSetViewportsArguments RSSetViewports; - RSSetScissorRectsArguments RSSetScissorRects; - SetGraphicsRootDescriptorTableArguments SetGraphicsRootDescriptorTable; - SetGraphicsRootConstantBufferViewArguments SetGraphicsRootConstantBufferView; - SetGraphicsRootSignatureArguments SetGraphicsRootSignature; - ClearRenderTargetViewArguments ClearRenderTargetView; - ClearDepthStencilViewArguments ClearDepthStencilView; - DrawInstancedArguments DrawInstanced; - DrawIndexedInstancedArguments DrawIndexedInstanced; - IASetPrimitiveTopologyArguments IASetPrimitiveTopology; - CopyBufferRegionArguments CopyBufferRegion; - CopyTextureRegionArguments CopyTextureRegion; - SetDescriptorHeapsArguments SetDescriptorHeaps; - ResourceBarrierArguments ResourceBarrier; - ResolveSubresourceArguments ResolveSubresource; - BeginQueryArguments BeginQuery; - EndQueryArguments EndQuery; - ResolveQueryDataArguments ResolveQueryData; - CloseCommandListArguments CloseCommandList; - ExecuteCommandListArguments ExecuteCommandList; - PresentArguments Present; - ResetCommandListArguments ResetCommandList; - ResetCommandAllocatorArguments ResetCommandAllocator; - FenceGpuSignalArguments FenceGpuSignal; - FenceCpuSignalArguments FenceCpuSignal; - StopArguments Stop; - }; + union { + SetPipelineStateArguments SetPipelineState; + SetRenderTargetsArguments SetRenderTargets; + SetVertexBuffersArguments SetVertexBuffers; + SetIndexBufferArguments SetIndexBuffer; + RSSetViewportsArguments RSSetViewports; + RSSetScissorRectsArguments RSSetScissorRects; + SetGraphicsRootDescriptorTableArguments SetGraphicsRootDescriptorTable; + SetGraphicsRootConstantBufferViewArguments SetGraphicsRootConstantBufferView; + SetGraphicsRootSignatureArguments SetGraphicsRootSignature; + ClearRenderTargetViewArguments ClearRenderTargetView; + ClearDepthStencilViewArguments ClearDepthStencilView; + DrawInstancedArguments DrawInstanced; + DrawIndexedInstancedArguments DrawIndexedInstanced; + IASetPrimitiveTopologyArguments IASetPrimitiveTopology; + CopyBufferRegionArguments CopyBufferRegion; + CopyTextureRegionArguments CopyTextureRegion; + SetDescriptorHeapsArguments SetDescriptorHeaps; + ResourceBarrierArguments ResourceBarrier; + ResolveSubresourceArguments ResolveSubresource; + BeginQueryArguments BeginQuery; + EndQueryArguments EndQuery; + ResolveQueryDataArguments ResolveQueryData; + CloseCommandListArguments CloseCommandList; + ExecuteCommandListArguments ExecuteCommandList; + PresentArguments Present; + ResetCommandListArguments ResetCommandList; + ResetCommandAllocatorArguments ResetCommandAllocator; + FenceGpuSignalArguments FenceGpuSignal; + FenceCpuSignalArguments FenceCpuSignal; + StopArguments Stop; + }; }; class ID3D12QueuedCommandList : public ID3D12GraphicsCommandList { public: + ID3D12QueuedCommandList(ID3D12GraphicsCommandList* backing_command_list, + ID3D12CommandQueue* backing_command_queue); - ID3D12QueuedCommandList(ID3D12GraphicsCommandList* backing_command_list, ID3D12CommandQueue* backing_command_queue); - - void ProcessQueuedItems(bool eligible_to_move_to_front_of_queue = false, bool wait_for_stop = false, bool terminate_worker_thread = false); - - void QueueExecute(); - void QueueFenceGpuSignal(ID3D12Fence* fence_to_signal, UINT64 fence_value); - void QueueFenceCpuSignal(ID3D12Fence* fence_to_signal, UINT64 fence_value); - void QueuePresent(IDXGISwapChain* swap_chain, UINT sync_interval, UINT flags); - - // IUnknown methods - - ULONG STDMETHODCALLTYPE AddRef(); - ULONG STDMETHODCALLTYPE Release(); - HRESULT STDMETHODCALLTYPE QueryInterface( - _In_ REFIID riid, - _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject - ); - - // ID3D12Object methods - - HRESULT STDMETHODCALLTYPE GetPrivateData( - _In_ REFGUID guid, - _Inout_ UINT* pDataSize, - _Out_writes_bytes_opt_(*pDataSize) void* pData - ); - - HRESULT STDMETHODCALLTYPE SetPrivateData( - _In_ REFGUID guid, - _In_ UINT DataSize, - _In_reads_bytes_opt_(DataSize) const void* pData - ); - - HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( - _In_ REFGUID guid, - _In_opt_ const IUnknown* pData - ); - - HRESULT STDMETHODCALLTYPE SetName( - _In_z_ LPCWSTR pName - ); - - // ID3D12DeviceChild methods - - D3D12_COMMAND_LIST_TYPE STDMETHODCALLTYPE GetType( - ); - - // ID3D12CommandList methods - - HRESULT STDMETHODCALLTYPE GetDevice( - REFIID riid, - void** ppvDevice - ); - - HRESULT STDMETHODCALLTYPE Close(void); - - HRESULT STDMETHODCALLTYPE Reset( - _In_ ID3D12CommandAllocator* pAllocator, - _In_opt_ ID3D12PipelineState* pInitialState - ); - - void STDMETHODCALLTYPE ClearState( - _In_ ID3D12PipelineState* pPipelineState - ); - - void STDMETHODCALLTYPE DrawInstanced( - _In_ UINT VertexCountPerInstance, - _In_ UINT InstanceCount, - _In_ UINT StartVertexLocation, - _In_ UINT StartInstanceLocation - ); - - void STDMETHODCALLTYPE DrawIndexedInstanced( - _In_ UINT IndexCountPerInstance, - _In_ UINT InstanceCount, - _In_ UINT StartIndexLocation, - _In_ INT BaseVertexLocation, - _In_ UINT StartInstanceLocation - ); - - void STDMETHODCALLTYPE Dispatch( - _In_ UINT ThreadGroupCountX, - _In_ UINT ThreadGroupCountY, - _In_ UINT ThreadGroupCountZ - ); - - void STDMETHODCALLTYPE DispatchIndirect( - _In_ ID3D12Resource* pBufferForArgs, - _In_ UINT AlignedByteOffsetForArgs - ); - - void STDMETHODCALLTYPE CopyBufferRegion( - _In_ ID3D12Resource* pDstBuffer, - UINT64 DstOffset, - _In_ ID3D12Resource* pSrcBuffer, - UINT64 SrcOffset, - UINT64 NumBytes - ); - - void STDMETHODCALLTYPE CopyTextureRegion( - _In_ const D3D12_TEXTURE_COPY_LOCATION* pDst, - UINT DstX, - UINT DstY, - UINT DstZ, - _In_ const D3D12_TEXTURE_COPY_LOCATION* pSrc, - _In_opt_ const D3D12_BOX* pSrcBox - ); - - void STDMETHODCALLTYPE CopyResource( - _In_ ID3D12Resource* pDstResource, - _In_ ID3D12Resource* pSrcResource - ); - - void STDMETHODCALLTYPE CopyTiles( - _In_ ID3D12Resource* pTiledResource, - _In_ const D3D12_TILED_RESOURCE_COORDINATE* pTileRegionStartCoordinate, - _In_ const D3D12_TILE_REGION_SIZE* pTileRegionSize, - _In_ ID3D12Resource* pBuffer, - UINT64 BufferStartOffsetInBytes, - D3D12_TILE_COPY_FLAGS Flags - ); - - void STDMETHODCALLTYPE ResolveSubresource( - _In_ ID3D12Resource* pDstResource, - _In_ UINT DstSubresource, - _In_ ID3D12Resource* pSrcResource, - _In_ UINT SrcSubresource, - _In_ DXGI_FORMAT Format - ); - - void STDMETHODCALLTYPE IASetPrimitiveTopology( - _In_ D3D12_PRIMITIVE_TOPOLOGY PrimitiveTopology - ); - - void STDMETHODCALLTYPE RSSetViewports( - _In_range_(0, D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT Count, - _In_reads_(Count) const D3D12_VIEWPORT* pViewports - ); - - void STDMETHODCALLTYPE RSSetScissorRects( - _In_range_(0, D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT Count, - _In_reads_(Count) const D3D12_RECT* pRects - ); - - void STDMETHODCALLTYPE OMSetBlendFactor( - _In_opt_ const FLOAT BlendFactor[4] - ); - - void STDMETHODCALLTYPE OMSetStencilRef( - _In_ UINT StencilRef - ); - - void STDMETHODCALLTYPE SetPipelineState( - _In_ ID3D12PipelineState* pPipelineState - ); - - void STDMETHODCALLTYPE ResourceBarrier( - _In_ UINT NumBarriers, - _In_reads_(NumBarriers) const D3D12_RESOURCE_BARRIER* pBarriers - ); - - void STDMETHODCALLTYPE ExecuteBundle( - _In_ ID3D12GraphicsCommandList* command_list - ); - - void STDMETHODCALLTYPE BeginQuery( - _In_ ID3D12QueryHeap* pQueryHeap, - _In_ D3D12_QUERY_TYPE Type, - _In_ UINT Index - ); - - void STDMETHODCALLTYPE EndQuery( - _In_ ID3D12QueryHeap* pQueryHeap, - _In_ D3D12_QUERY_TYPE Type, - _In_ UINT Index - ); - - void STDMETHODCALLTYPE ResolveQueryData( - _In_ ID3D12QueryHeap* pQueryHeap, - _In_ D3D12_QUERY_TYPE Type, - _In_ UINT StartElement, - _In_ UINT ElementCount, - _In_ ID3D12Resource* pDestinationBuffer, - _In_ UINT64 AlignedDestinationBufferOffset - ); - - void STDMETHODCALLTYPE SetPredication( - _In_opt_ ID3D12Resource* pBuffer, - _In_ UINT64 AlignedBufferOffset, - _In_ D3D12_PREDICATION_OP Operation - ); - - void STDMETHODCALLTYPE SetDescriptorHeaps( - _In_ UINT NumDescriptorHeaps, - _In_reads_(NumDescriptorHeaps) ID3D12DescriptorHeap *const * pDescriptorHeaps - ); - - void STDMETHODCALLTYPE SetComputeRootSignature( - _In_ ID3D12RootSignature* pRootSignature - ); - - void STDMETHODCALLTYPE SetGraphicsRootSignature( - _In_ ID3D12RootSignature* pRootSignature - ); - - void STDMETHODCALLTYPE SetComputeRootDescriptorTable( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor - ); - - void STDMETHODCALLTYPE SetGraphicsRootDescriptorTable( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor - ); - - void STDMETHODCALLTYPE SetComputeRoot32BitConstant( - _In_ UINT RootParameterIndex, - _In_ UINT SrcData, - _In_ UINT DestOffsetIn32BitValues - ); - - void STDMETHODCALLTYPE SetGraphicsRoot32BitConstant( - _In_ UINT RootParameterIndex, - _In_ UINT SrcData, - _In_ UINT DestOffsetIn32BitValues - ); - - void STDMETHODCALLTYPE SetComputeRoot32BitConstants( - _In_ UINT RootParameterIndex, - _In_ UINT Num32BitValuesToSet, - _In_reads_(Num32BitValuesToSet*sizeof(UINT)) const void* pSrcData, - _In_ UINT DestOffsetIn32BitValues - ); - - void STDMETHODCALLTYPE SetGraphicsRoot32BitConstants( - _In_ UINT RootParameterIndex, - _In_ UINT Num32BitValuesToSet, - _In_reads_(Num32BitValuesToSet*sizeof(UINT)) const void* pSrcData, - _In_ UINT DestOffsetIn32BitValues - ); - - void STDMETHODCALLTYPE SetGraphicsRootConstantBufferView( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_VIRTUAL_ADDRESS BufferLocation - ); - - void STDMETHODCALLTYPE SetComputeRootConstantBufferView( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_VIRTUAL_ADDRESS BufferLocation - ); - - void STDMETHODCALLTYPE SetComputeRootShaderResourceView( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle - ); - - void STDMETHODCALLTYPE SetGraphicsRootShaderResourceView( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle - ); - - void STDMETHODCALLTYPE SetComputeRootUnorderedAccessView( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle - ); - - void STDMETHODCALLTYPE SetGraphicsRootUnorderedAccessView( - _In_ UINT RootParameterIndex, - _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle - ); - - void STDMETHODCALLTYPE IASetIndexBuffer( - _In_opt_ const D3D12_INDEX_BUFFER_VIEW* pDesc - ); - - void STDMETHODCALLTYPE IASetVertexBuffers( - _In_ UINT StartSlot, - _In_ UINT NumBuffers, - _In_ const D3D12_VERTEX_BUFFER_VIEW* pDesc - ); - - void STDMETHODCALLTYPE SOSetTargets( - _In_ UINT StartSlot, - _In_ UINT NumViews, - _In_ const D3D12_STREAM_OUTPUT_BUFFER_VIEW* pViews - ); - - void STDMETHODCALLTYPE OMSetRenderTargets( - _In_ UINT NumRenderTargetDescriptors, - _In_ const D3D12_CPU_DESCRIPTOR_HANDLE* pRenderTargetDescriptors, - _In_ BOOL RTsSingleHandleToDescriptorRange, - _In_opt_ const D3D12_CPU_DESCRIPTOR_HANDLE* pDepthStencilDescriptor - ); - - void STDMETHODCALLTYPE ClearDepthStencilView( - _In_ D3D12_CPU_DESCRIPTOR_HANDLE DepthStencilView, - _In_ D3D12_CLEAR_FLAGS ClearFlags, - _In_ FLOAT Depth, - _In_ UINT8 Stencil, - _In_ UINT NumRects, - _In_reads_opt_(NumRects) const D3D12_RECT* pRect - ); - - void STDMETHODCALLTYPE ClearRenderTargetView( - _In_ D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetView, - _In_ const FLOAT ColorRGBA[4], - _In_ UINT NumRects, - _In_reads_opt_(NumRects) const D3D12_RECT* pRects - ); - - void STDMETHODCALLTYPE ClearUnorderedAccessViewUint( - _In_ D3D12_GPU_DESCRIPTOR_HANDLE ViewGPUHandleInCurrentHeap, - _In_ D3D12_CPU_DESCRIPTOR_HANDLE ViewCPUHandle, - _In_ ID3D12Resource* pResource, - _In_ const UINT Values[4], - _In_ UINT NumRects, - _In_reads_opt_(NumRects) const D3D12_RECT* pRects - ); - - void STDMETHODCALLTYPE ClearUnorderedAccessViewFloat( - _In_ D3D12_GPU_DESCRIPTOR_HANDLE ViewGPUHandleInCurrentHeap, - _In_ D3D12_CPU_DESCRIPTOR_HANDLE ViewCPUHandle, - _In_ ID3D12Resource* pResource, - _In_ const FLOAT Values[4], - _In_ UINT NumRects, - _In_reads_opt_(NumRects) const D3D12_RECT* pRects - ); - - void STDMETHODCALLTYPE DiscardResource( - _In_ ID3D12Resource* pResource, - _In_opt_ const D3D12_DISCARD_REGION* pRegion - ); - - void STDMETHODCALLTYPE SetMarker( - UINT Metadata, - _In_reads_bytes_opt_(Size) const void* pData, - UINT Size); - - void STDMETHODCALLTYPE BeginEvent( - UINT Metadata, - _In_reads_bytes_opt_(Size) const void* pData, - UINT Size); - - void STDMETHODCALLTYPE EndEvent(void); - - void STDMETHODCALLTYPE ExecuteIndirect( - _In_ ID3D12CommandSignature* pCommandSignature, - _In_ UINT MaxCommandCount, - _In_ ID3D12Resource* pArgumentBuffer, - _In_ UINT64 ArgumentBufferOffset, - _In_opt_ ID3D12Resource* pCountBuffer, - _In_ UINT64 CountBufferOffset - ); + void ProcessQueuedItems(bool eligible_to_move_to_front_of_queue = false, + bool wait_for_stop = false, bool terminate_worker_thread = false); + + void QueueExecute(); + void QueueFenceGpuSignal(ID3D12Fence* fence_to_signal, UINT64 fence_value); + void QueueFenceCpuSignal(ID3D12Fence* fence_to_signal, UINT64 fence_value); + void QueuePresent(IDXGISwapChain* swap_chain, UINT sync_interval, UINT flags); + + // IUnknown methods + + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + HRESULT STDMETHODCALLTYPE QueryInterface(_In_ REFIID riid, + _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject); + + // ID3D12Object methods + + HRESULT STDMETHODCALLTYPE GetPrivateData(_In_ REFGUID guid, _Inout_ UINT* pDataSize, + _Out_writes_bytes_opt_(*pDataSize) void* pData); + + HRESULT STDMETHODCALLTYPE SetPrivateData(_In_ REFGUID guid, _In_ UINT DataSize, + _In_reads_bytes_opt_(DataSize) const void* pData); + + HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(_In_ REFGUID guid, + _In_opt_ const IUnknown* pData); + + HRESULT STDMETHODCALLTYPE SetName(_In_z_ LPCWSTR pName); + + // ID3D12DeviceChild methods + + D3D12_COMMAND_LIST_TYPE STDMETHODCALLTYPE GetType(); + + // ID3D12CommandList methods + + HRESULT STDMETHODCALLTYPE GetDevice(REFIID riid, void** ppvDevice); + + HRESULT STDMETHODCALLTYPE Close(void); + + HRESULT STDMETHODCALLTYPE Reset(_In_ ID3D12CommandAllocator* pAllocator, + _In_opt_ ID3D12PipelineState* pInitialState); + + void STDMETHODCALLTYPE ClearState(_In_ ID3D12PipelineState* pPipelineState); + + void STDMETHODCALLTYPE DrawInstanced(_In_ UINT VertexCountPerInstance, _In_ UINT InstanceCount, + _In_ UINT StartVertexLocation, + _In_ UINT StartInstanceLocation); + + void STDMETHODCALLTYPE DrawIndexedInstanced(_In_ UINT IndexCountPerInstance, + _In_ UINT InstanceCount, _In_ UINT StartIndexLocation, + _In_ INT BaseVertexLocation, + _In_ UINT StartInstanceLocation); + + void STDMETHODCALLTYPE Dispatch(_In_ UINT ThreadGroupCountX, _In_ UINT ThreadGroupCountY, + _In_ UINT ThreadGroupCountZ); + + void STDMETHODCALLTYPE DispatchIndirect(_In_ ID3D12Resource* pBufferForArgs, + _In_ UINT AlignedByteOffsetForArgs); + + void STDMETHODCALLTYPE CopyBufferRegion(_In_ ID3D12Resource* pDstBuffer, UINT64 DstOffset, + _In_ ID3D12Resource* pSrcBuffer, UINT64 SrcOffset, + UINT64 NumBytes); + + void STDMETHODCALLTYPE CopyTextureRegion(_In_ const D3D12_TEXTURE_COPY_LOCATION* pDst, UINT DstX, + UINT DstY, UINT DstZ, + _In_ const D3D12_TEXTURE_COPY_LOCATION* pSrc, + _In_opt_ const D3D12_BOX* pSrcBox); + + void STDMETHODCALLTYPE CopyResource(_In_ ID3D12Resource* pDstResource, + _In_ ID3D12Resource* pSrcResource); + + void STDMETHODCALLTYPE + CopyTiles(_In_ ID3D12Resource* pTiledResource, + _In_ const D3D12_TILED_RESOURCE_COORDINATE* pTileRegionStartCoordinate, + _In_ const D3D12_TILE_REGION_SIZE* pTileRegionSize, _In_ ID3D12Resource* pBuffer, + UINT64 BufferStartOffsetInBytes, D3D12_TILE_COPY_FLAGS Flags); + + void STDMETHODCALLTYPE ResolveSubresource(_In_ ID3D12Resource* pDstResource, + _In_ UINT DstSubresource, + _In_ ID3D12Resource* pSrcResource, + _In_ UINT SrcSubresource, _In_ DXGI_FORMAT Format); + + void STDMETHODCALLTYPE IASetPrimitiveTopology(_In_ D3D12_PRIMITIVE_TOPOLOGY PrimitiveTopology); + + void STDMETHODCALLTYPE RSSetViewports( + _In_range_(0, D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT Count, + _In_reads_(Count) const D3D12_VIEWPORT* pViewports); + + void STDMETHODCALLTYPE RSSetScissorRects( + _In_range_(0, D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT Count, + _In_reads_(Count) const D3D12_RECT* pRects); + + void STDMETHODCALLTYPE OMSetBlendFactor(_In_opt_ const FLOAT BlendFactor[4]); + + void STDMETHODCALLTYPE OMSetStencilRef(_In_ UINT StencilRef); + + void STDMETHODCALLTYPE SetPipelineState(_In_ ID3D12PipelineState* pPipelineState); + + void STDMETHODCALLTYPE ResourceBarrier(_In_ UINT NumBarriers, + _In_reads_(NumBarriers) + const D3D12_RESOURCE_BARRIER* pBarriers); + + void STDMETHODCALLTYPE ExecuteBundle(_In_ ID3D12GraphicsCommandList* command_list); + + void STDMETHODCALLTYPE BeginQuery(_In_ ID3D12QueryHeap* pQueryHeap, _In_ D3D12_QUERY_TYPE Type, + _In_ UINT Index); + + void STDMETHODCALLTYPE EndQuery(_In_ ID3D12QueryHeap* pQueryHeap, _In_ D3D12_QUERY_TYPE Type, + _In_ UINT Index); + + void STDMETHODCALLTYPE ResolveQueryData(_In_ ID3D12QueryHeap* pQueryHeap, + _In_ D3D12_QUERY_TYPE Type, _In_ UINT StartElement, + _In_ UINT ElementCount, + _In_ ID3D12Resource* pDestinationBuffer, + _In_ UINT64 AlignedDestinationBufferOffset); + + void STDMETHODCALLTYPE SetPredication(_In_opt_ ID3D12Resource* pBuffer, + _In_ UINT64 AlignedBufferOffset, + _In_ D3D12_PREDICATION_OP Operation); + + void STDMETHODCALLTYPE SetDescriptorHeaps(_In_ UINT NumDescriptorHeaps, + _In_reads_(NumDescriptorHeaps) + ID3D12DescriptorHeap* const* pDescriptorHeaps); + + void STDMETHODCALLTYPE SetComputeRootSignature(_In_ ID3D12RootSignature* pRootSignature); + + void STDMETHODCALLTYPE SetGraphicsRootSignature(_In_ ID3D12RootSignature* pRootSignature); + + void STDMETHODCALLTYPE SetComputeRootDescriptorTable( + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor); + + void STDMETHODCALLTYPE SetGraphicsRootDescriptorTable( + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor); + + void STDMETHODCALLTYPE SetComputeRoot32BitConstant(_In_ UINT RootParameterIndex, + _In_ UINT SrcData, + _In_ UINT DestOffsetIn32BitValues); + + void STDMETHODCALLTYPE SetGraphicsRoot32BitConstant(_In_ UINT RootParameterIndex, + _In_ UINT SrcData, + _In_ UINT DestOffsetIn32BitValues); + + void STDMETHODCALLTYPE SetComputeRoot32BitConstants(_In_ UINT RootParameterIndex, + _In_ UINT Num32BitValuesToSet, + _In_reads_(Num32BitValuesToSet * sizeof(UINT)) + const void* pSrcData, + _In_ UINT DestOffsetIn32BitValues); + + void STDMETHODCALLTYPE + SetGraphicsRoot32BitConstants(_In_ UINT RootParameterIndex, _In_ UINT Num32BitValuesToSet, + _In_reads_(Num32BitValuesToSet * sizeof(UINT)) const void* pSrcData, + _In_ UINT DestOffsetIn32BitValues); + + void STDMETHODCALLTYPE SetGraphicsRootConstantBufferView( + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_VIRTUAL_ADDRESS BufferLocation); + + void STDMETHODCALLTYPE SetComputeRootConstantBufferView( + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_VIRTUAL_ADDRESS BufferLocation); + + void STDMETHODCALLTYPE SetComputeRootShaderResourceView( + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle); + + void STDMETHODCALLTYPE SetGraphicsRootShaderResourceView( + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle); + + void STDMETHODCALLTYPE SetComputeRootUnorderedAccessView( + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle); + + void STDMETHODCALLTYPE SetGraphicsRootUnorderedAccessView( + _In_ UINT RootParameterIndex, _In_ D3D12_GPU_VIRTUAL_ADDRESS DescriptorHandle); + + void STDMETHODCALLTYPE IASetIndexBuffer(_In_opt_ const D3D12_INDEX_BUFFER_VIEW* pDesc); + + void STDMETHODCALLTYPE IASetVertexBuffers(_In_ UINT StartSlot, _In_ UINT NumBuffers, + _In_ const D3D12_VERTEX_BUFFER_VIEW* pDesc); + + void STDMETHODCALLTYPE SOSetTargets(_In_ UINT StartSlot, _In_ UINT NumViews, + _In_ const D3D12_STREAM_OUTPUT_BUFFER_VIEW* pViews); + + void STDMETHODCALLTYPE + OMSetRenderTargets(_In_ UINT NumRenderTargetDescriptors, + _In_ const D3D12_CPU_DESCRIPTOR_HANDLE* pRenderTargetDescriptors, + _In_ BOOL RTsSingleHandleToDescriptorRange, + _In_opt_ const D3D12_CPU_DESCRIPTOR_HANDLE* pDepthStencilDescriptor); + + void STDMETHODCALLTYPE ClearDepthStencilView(_In_ D3D12_CPU_DESCRIPTOR_HANDLE DepthStencilView, + _In_ D3D12_CLEAR_FLAGS ClearFlags, _In_ FLOAT Depth, + _In_ UINT8 Stencil, _In_ UINT NumRects, + _In_reads_opt_(NumRects) const D3D12_RECT* pRect); + + void STDMETHODCALLTYPE ClearRenderTargetView(_In_ D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetView, + _In_ const FLOAT ColorRGBA[4], _In_ UINT NumRects, + _In_reads_opt_(NumRects) const D3D12_RECT* pRects); + + void STDMETHODCALLTYPE ClearUnorderedAccessViewUint( + _In_ D3D12_GPU_DESCRIPTOR_HANDLE ViewGPUHandleInCurrentHeap, + _In_ D3D12_CPU_DESCRIPTOR_HANDLE ViewCPUHandle, _In_ ID3D12Resource* pResource, + _In_ const UINT Values[4], _In_ UINT NumRects, + _In_reads_opt_(NumRects) const D3D12_RECT* pRects); + + void STDMETHODCALLTYPE ClearUnorderedAccessViewFloat( + _In_ D3D12_GPU_DESCRIPTOR_HANDLE ViewGPUHandleInCurrentHeap, + _In_ D3D12_CPU_DESCRIPTOR_HANDLE ViewCPUHandle, _In_ ID3D12Resource* pResource, + _In_ const FLOAT Values[4], _In_ UINT NumRects, + _In_reads_opt_(NumRects) const D3D12_RECT* pRects); + + void STDMETHODCALLTYPE DiscardResource(_In_ ID3D12Resource* pResource, + _In_opt_ const D3D12_DISCARD_REGION* pRegion); + + void STDMETHODCALLTYPE SetMarker(UINT Metadata, _In_reads_bytes_opt_(Size) const void* pData, + UINT Size); + + void STDMETHODCALLTYPE BeginEvent(UINT Metadata, _In_reads_bytes_opt_(Size) const void* pData, + UINT Size); + + void STDMETHODCALLTYPE EndEvent(void); + + void STDMETHODCALLTYPE ExecuteIndirect(_In_ ID3D12CommandSignature* pCommandSignature, + _In_ UINT MaxCommandCount, + _In_ ID3D12Resource* pArgumentBuffer, + _In_ UINT64 ArgumentBufferOffset, + _In_opt_ ID3D12Resource* pCountBuffer, + _In_ UINT64 CountBufferOffset); private: - ~ID3D12QueuedCommandList(); + ~ID3D12QueuedCommandList(); - void ResetQueueOverflowTracking(); - void CheckForOverflow(); + void ResetQueueOverflowTracking(); + void CheckForOverflow(); - static void BackgroundThreadFunction(ID3D12QueuedCommandList* parent_queued_command_list); + static void BackgroundThreadFunction(ID3D12QueuedCommandList* parent_queued_command_list); - byte m_queue_array[QUEUE_ARRAY_SIZE]; - byte* m_queue_array_back = m_queue_array; + byte m_queue_array[QUEUE_ARRAY_SIZE]; + byte* m_queue_array_back = m_queue_array; - byte* m_queue_array_back_at_start_of_frame = m_queue_array_back; + byte* m_queue_array_back_at_start_of_frame = m_queue_array_back; - std::thread m_background_thread; + std::thread m_background_thread; - HANDLE m_begin_execution_event; - HANDLE m_stop_execution_event; + HANDLE m_begin_execution_event; + HANDLE m_stop_execution_event; - ID3D12GraphicsCommandList* m_command_list; - ID3D12CommandQueue* m_command_queue; + ID3D12GraphicsCommandList* m_command_list; + ID3D12CommandQueue* m_command_queue; - std::atomic m_ref = 1; + std::atomic m_ref = 1; }; } // namespace \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D12/D3DShader.cpp b/Source/Core/VideoBackends/D3D12/D3DShader.cpp index d99a02c5ac..bb1f0de5cf 100644 --- a/Source/Core/VideoBackends/D3D12/D3DShader.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DShader.cpp @@ -6,82 +6,84 @@ #include #include "Common/FileUtil.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "VideoBackends/D3D12/D3DBase.h" #include "VideoBackends/D3D12/D3DShader.h" #include "VideoCommon/VideoConfig.h" namespace DX12 { - namespace D3D { - -bool CompileShader(const std::string& code, ID3DBlob** blob, const D3D_SHADER_MACRO* defines, const std::string& shader_version_string) +bool CompileShader(const std::string& code, ID3DBlob** blob, const D3D_SHADER_MACRO* defines, + const std::string& shader_version_string) { - ID3D10Blob* shader_buffer = nullptr; - ID3D10Blob* error_buffer = nullptr; + ID3D10Blob* shader_buffer = nullptr; + ID3D10Blob* error_buffer = nullptr; #if defined(_DEBUG) || defined(DEBUGFAST) - UINT flags = D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_DEBUG; + UINT flags = D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_DEBUG; #else - UINT flags = D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_SKIP_VALIDATION; + UINT flags = D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_OPTIMIZATION_LEVEL3 | + D3DCOMPILE_SKIP_VALIDATION; #endif - HRESULT hr = d3d_compile(code.c_str(), code.length(), nullptr, defines, nullptr, "main", shader_version_string.data(), - flags, 0, &shader_buffer, &error_buffer); + HRESULT hr = d3d_compile(code.c_str(), code.length(), nullptr, defines, nullptr, "main", + shader_version_string.data(), flags, 0, &shader_buffer, &error_buffer); - if (error_buffer) - { - WARN_LOG(VIDEO, "Warning generated when compiling %s shader:\n%s\n", - shader_version_string.c_str(), - static_cast(error_buffer->GetBufferPointer())); - } + if (error_buffer) + { + WARN_LOG(VIDEO, "Warning generated when compiling %s shader:\n%s\n", + shader_version_string.c_str(), + static_cast(error_buffer->GetBufferPointer())); + } - if (FAILED(hr)) - { - static int num_failures = 0; - std::string filename = StringFromFormat("%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), shader_version_string.c_str(), num_failures++); - std::ofstream file; - OpenFStream(file, filename, std::ios_base::out); - file << code; - file << std::endl << "Errors:" << std::endl; - file << static_cast(error_buffer->GetBufferPointer()); - file.close(); + if (FAILED(hr)) + { + static int num_failures = 0; + std::string filename = + StringFromFormat("%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), + shader_version_string.c_str(), num_failures++); + std::ofstream file; + OpenFStream(file, filename, std::ios_base::out); + file << code; + file << std::endl << "Errors:" << std::endl; + file << static_cast(error_buffer->GetBufferPointer()); + file.close(); - PanicAlert("Failed to compile shader: %s\nDebug info (%s):\n%s", - filename.c_str(), - shader_version_string.c_str(), - static_cast(error_buffer->GetBufferPointer())); + PanicAlert("Failed to compile shader: %s\nDebug info (%s):\n%s", filename.c_str(), + shader_version_string.c_str(), + static_cast(error_buffer->GetBufferPointer())); - *blob = nullptr; - error_buffer->Release(); - } - else - { - *blob = shader_buffer; - } + *blob = nullptr; + error_buffer->Release(); + } + else + { + *blob = shader_buffer; + } - return SUCCEEDED(hr); + return SUCCEEDED(hr); } // code->bytecode bool CompileVertexShader(const std::string& code, ID3DBlob** blob) { - return CompileShader(code, blob, nullptr, D3D::VertexShaderVersionString()); + return CompileShader(code, blob, nullptr, D3D::VertexShaderVersionString()); } // code->bytecode -bool CompileGeometryShader(const std::string& code, ID3DBlob** blob, const D3D_SHADER_MACRO* defines) +bool CompileGeometryShader(const std::string& code, ID3DBlob** blob, + const D3D_SHADER_MACRO* defines) { - return CompileShader(code, blob, defines, D3D::GeometryShaderVersionString()); + return CompileShader(code, blob, defines, D3D::GeometryShaderVersionString()); } // code->bytecode bool CompilePixelShader(const std::string& code, ID3DBlob** blob, const D3D_SHADER_MACRO* defines) { - return CompileShader(code, blob, defines, D3D::PixelShaderVersionString()); + return CompileShader(code, blob, defines, D3D::PixelShaderVersionString()); } } // namespace diff --git a/Source/Core/VideoBackends/D3D12/D3DShader.h b/Source/Core/VideoBackends/D3D12/D3DShader.h index e43522302d..b867a15716 100644 --- a/Source/Core/VideoBackends/D3D12/D3DShader.h +++ b/Source/Core/VideoBackends/D3D12/D3DShader.h @@ -12,15 +12,14 @@ class D3DBlob; namespace DX12 { - namespace D3D { - // The returned bytecode buffers should be Release()d. bool CompileVertexShader(const std::string& code, ID3DBlob** blob); -bool CompileGeometryShader(const std::string& code, ID3DBlob** blob, const D3D_SHADER_MACRO* defines = nullptr); -bool CompilePixelShader(const std::string& code, ID3DBlob** blob, const D3D_SHADER_MACRO* defines = nullptr); - +bool CompileGeometryShader(const std::string& code, ID3DBlob** blob, + const D3D_SHADER_MACRO* defines = nullptr); +bool CompilePixelShader(const std::string& code, ID3DBlob** blob, + const D3D_SHADER_MACRO* defines = nullptr); } } // namespace DX12 diff --git a/Source/Core/VideoBackends/D3D12/D3DState.cpp b/Source/Core/VideoBackends/D3D12/D3DState.cpp index ffe1e573e5..2902f3272f 100644 --- a/Source/Core/VideoBackends/D3D12/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DState.cpp @@ -8,9 +8,9 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/LinearDiskCache.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "Core/ConfigManager.h" @@ -28,470 +28,470 @@ namespace DX12 { - static bool s_cache_is_corrupted = false; static LinearDiskCache s_pso_disk_cache; class PipelineStateCacheInserter : public LinearDiskCacheReader { public: - void Read(const SmallPsoDiskDesc& key, const u8* value, u32 value_size) - { - if (s_cache_is_corrupted) - return; + void Read(const SmallPsoDiskDesc& key, const u8* value, u32 value_size) + { + if (s_cache_is_corrupted) + return; - D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = {}; - desc.pRootSignature = D3D::default_root_signature; - desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; // This state changes in PSTextureEncoder::Encode. - desc.DSVFormat = DXGI_FORMAT_D32_FLOAT; // This state changes in PSTextureEncoder::Encode. - desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF; - desc.NumRenderTargets = 1; - desc.SampleMask = UINT_MAX; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; + D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = {}; + desc.pRootSignature = D3D::default_root_signature; + desc.RTVFormats[0] = + DXGI_FORMAT_R8G8B8A8_UNORM; // This state changes in PSTextureEncoder::Encode. + desc.DSVFormat = DXGI_FORMAT_D32_FLOAT; // This state changes in PSTextureEncoder::Encode. + desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF; + desc.NumRenderTargets = 1; + desc.SampleMask = UINT_MAX; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; - desc.GS = ShaderCache::GetGeometryShaderFromUid(&key.gs_uid); - desc.PS = ShaderCache::GetPixelShaderFromUid(&key.ps_uid); - desc.VS = ShaderCache::GetVertexShaderFromUid(&key.vs_uid); + desc.GS = ShaderCache::GetGeometryShaderFromUid(&key.gs_uid); + desc.PS = ShaderCache::GetPixelShaderFromUid(&key.ps_uid); + desc.VS = ShaderCache::GetVertexShaderFromUid(&key.vs_uid); - if (!desc.PS.pShaderBytecode || !desc.VS.pShaderBytecode) - { - s_cache_is_corrupted = true; - return; - } + if (!desc.PS.pShaderBytecode || !desc.VS.pShaderBytecode) + { + s_cache_is_corrupted = true; + return; + } - BlendState blend_state = {}; - blend_state.hex = key.blend_state_hex; - desc.BlendState = StateCache::GetDesc12(blend_state); + BlendState blend_state = {}; + blend_state.hex = key.blend_state_hex; + desc.BlendState = StateCache::GetDesc12(blend_state); - ZMode depth_stencil_state = {}; - depth_stencil_state.hex = key.depth_stencil_state_hex; - desc.DepthStencilState = StateCache::GetDesc12(depth_stencil_state); + ZMode depth_stencil_state = {}; + depth_stencil_state.hex = key.depth_stencil_state_hex; + desc.DepthStencilState = StateCache::GetDesc12(depth_stencil_state); - RasterizerState rasterizer_state = {}; - rasterizer_state.hex = key.rasterizer_state_hex; - desc.RasterizerState = StateCache::GetDesc12(rasterizer_state); + RasterizerState rasterizer_state = {}; + rasterizer_state.hex = key.rasterizer_state_hex; + desc.RasterizerState = StateCache::GetDesc12(rasterizer_state); - desc.PrimitiveTopologyType = key.topology; + desc.PrimitiveTopologyType = key.topology; - // search for a cached native vertex format - const PortableVertexDeclaration& native_vtx_decl = key.vertex_declaration; - std::unique_ptr& native = (*VertexLoaderManager::GetNativeVertexFormatMap())[native_vtx_decl]; + // search for a cached native vertex format + const PortableVertexDeclaration& native_vtx_decl = key.vertex_declaration; + std::unique_ptr& native = + (*VertexLoaderManager::GetNativeVertexFormatMap())[native_vtx_decl]; - if (!native) - { - native.reset(g_vertex_manager->CreateNativeVertexFormat(native_vtx_decl)); - } + if (!native) + { + native.reset(g_vertex_manager->CreateNativeVertexFormat(native_vtx_decl)); + } - desc.InputLayout = reinterpret_cast(native.get())->GetActiveInputLayout12(); + desc.InputLayout = reinterpret_cast(native.get())->GetActiveInputLayout12(); - desc.CachedPSO.CachedBlobSizeInBytes = value_size; - desc.CachedPSO.pCachedBlob = value; + desc.CachedPSO.CachedBlobSizeInBytes = value_size; + desc.CachedPSO.pCachedBlob = value; - ID3D12PipelineState* pso = nullptr; - HRESULT hr = D3D::device12->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&pso)); + ID3D12PipelineState* pso = nullptr; + HRESULT hr = D3D::device12->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&pso)); - if (FAILED(hr)) - { - // Failure can occur if disk cache is corrupted, or a driver upgrade invalidates the existing blobs. - // In this case, we need to clear the disk cache. + if (FAILED(hr)) + { + // Failure can occur if disk cache is corrupted, or a driver upgrade invalidates the existing + // blobs. + // In this case, we need to clear the disk cache. - s_cache_is_corrupted = true; - return; - } + s_cache_is_corrupted = true; + return; + } - SmallPsoDesc small_desc = {}; - small_desc.blend_state.hex = key.blend_state_hex; - small_desc.depth_stencil_state.hex = key.depth_stencil_state_hex; - small_desc.rasterizer_state.hex = key.rasterizer_state_hex; - small_desc.gs_bytecode = desc.GS; - small_desc.ps_bytecode = desc.PS; - small_desc.vs_bytecode = desc.VS; - small_desc.input_layout = reinterpret_cast(native.get()); + SmallPsoDesc small_desc = {}; + small_desc.blend_state.hex = key.blend_state_hex; + small_desc.depth_stencil_state.hex = key.depth_stencil_state_hex; + small_desc.rasterizer_state.hex = key.rasterizer_state_hex; + small_desc.gs_bytecode = desc.GS; + small_desc.ps_bytecode = desc.PS; + small_desc.vs_bytecode = desc.VS; + small_desc.input_layout = reinterpret_cast(native.get()); - gx_state_cache.m_small_pso_map[small_desc] = pso; - } + gx_state_cache.m_small_pso_map[small_desc] = pso; + } }; StateCache::StateCache() { - m_current_pso_desc = {}; + m_current_pso_desc = {}; - m_current_pso_desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; // This state changes in PSTextureEncoder::Encode. - m_current_pso_desc.DSVFormat = DXGI_FORMAT_D32_FLOAT; // This state changes in PSTextureEncoder::Encode. - m_current_pso_desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF; - m_current_pso_desc.NumRenderTargets = 1; - m_current_pso_desc.SampleMask = UINT_MAX; + m_current_pso_desc.RTVFormats[0] = + DXGI_FORMAT_R8G8B8A8_UNORM; // This state changes in PSTextureEncoder::Encode. + m_current_pso_desc.DSVFormat = + DXGI_FORMAT_D32_FLOAT; // This state changes in PSTextureEncoder::Encode. + m_current_pso_desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF; + m_current_pso_desc.NumRenderTargets = 1; + m_current_pso_desc.SampleMask = UINT_MAX; } void StateCache::Init() { - // Root signature isn't available at time of StateCache construction, so fill it in now. - gx_state_cache.m_current_pso_desc.pRootSignature = D3D::default_root_signature; + // Root signature isn't available at time of StateCache construction, so fill it in now. + gx_state_cache.m_current_pso_desc.pRootSignature = D3D::default_root_signature; - // Multi-sample configuration isn't available at time of StateCache construction, so fille it in now. - gx_state_cache.m_current_pso_desc.SampleDesc.Count = g_ActiveConfig.iMultisamples; - gx_state_cache.m_current_pso_desc.SampleDesc.Quality = 0; + // Multi-sample configuration isn't available at time of StateCache construction, so fille it in + // now. + gx_state_cache.m_current_pso_desc.SampleDesc.Count = g_ActiveConfig.iMultisamples; + gx_state_cache.m_current_pso_desc.SampleDesc.Quality = 0; - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - std::string cache_filename = StringFromFormat("%sdx12-%s-pso.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), - SConfig::GetInstance().m_strUniqueID.c_str()); + std::string cache_filename = + StringFromFormat("%sdx12-%s-pso.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), + SConfig::GetInstance().m_strUniqueID.c_str()); - PipelineStateCacheInserter inserter; - s_pso_disk_cache.OpenAndRead(cache_filename, inserter); + PipelineStateCacheInserter inserter; + s_pso_disk_cache.OpenAndRead(cache_filename, inserter); - if (s_cache_is_corrupted) - { - // If a PSO fails to create, that means either: - // - The file itself is corrupt. - // - A driver/HW change has occurred, causing the existing cache blobs to be invalid. - // - // In either case, we want to re-create the disk cache. This should not be a frequent occurence. + if (s_cache_is_corrupted) + { + // If a PSO fails to create, that means either: + // - The file itself is corrupt. + // - A driver/HW change has occurred, causing the existing cache blobs to be invalid. + // + // In either case, we want to re-create the disk cache. This should not be a frequent occurence. - s_pso_disk_cache.Close(); + s_pso_disk_cache.Close(); - for (auto it : gx_state_cache.m_small_pso_map) - { - SAFE_RELEASE(it.second); - } - gx_state_cache.m_small_pso_map.clear(); + for (auto it : gx_state_cache.m_small_pso_map) + { + SAFE_RELEASE(it.second); + } + gx_state_cache.m_small_pso_map.clear(); - File::Delete(cache_filename); + File::Delete(cache_filename); - s_pso_disk_cache.OpenAndRead(cache_filename, inserter); + s_pso_disk_cache.OpenAndRead(cache_filename, inserter); - s_cache_is_corrupted = false; - } + s_cache_is_corrupted = false; + } } D3D12_SAMPLER_DESC StateCache::GetDesc12(SamplerState state) { - const unsigned int d3d_mip_filters[4] = - { - TexMode0::TEXF_NONE, - TexMode0::TEXF_POINT, - TexMode0::TEXF_LINEAR, - TexMode0::TEXF_NONE, //reserved - }; - const D3D12_TEXTURE_ADDRESS_MODE d3d_clamps[4] = - { - D3D12_TEXTURE_ADDRESS_MODE_CLAMP, - D3D12_TEXTURE_ADDRESS_MODE_WRAP, - D3D12_TEXTURE_ADDRESS_MODE_MIRROR, - D3D12_TEXTURE_ADDRESS_MODE_WRAP //reserved - }; + const unsigned int d3d_mip_filters[4] = { + TexMode0::TEXF_NONE, TexMode0::TEXF_POINT, TexMode0::TEXF_LINEAR, + TexMode0::TEXF_NONE, // reserved + }; + const D3D12_TEXTURE_ADDRESS_MODE d3d_clamps[4] = { + D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_WRAP, + D3D12_TEXTURE_ADDRESS_MODE_MIRROR, + D3D12_TEXTURE_ADDRESS_MODE_WRAP // reserved + }; - D3D12_SAMPLER_DESC sampdc; + D3D12_SAMPLER_DESC sampdc; - unsigned int mip = d3d_mip_filters[state.min_filter & 3]; + unsigned int mip = d3d_mip_filters[state.min_filter & 3]; - sampdc.MaxAnisotropy = 1; - if (g_ActiveConfig.iMaxAnisotropy > 0 && !SamplerCommon::IsBpTexMode0PointFiltering(state)) - { - sampdc.Filter = D3D12_FILTER_ANISOTROPIC; - sampdc.MaxAnisotropy = 1 << g_ActiveConfig.iMaxAnisotropy; - } - else if (state.min_filter & 4) // linear min filter - { - if (state.mag_filter) // linear mag filter - { - if (mip == TexMode0::TEXF_NONE) - sampdc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT; - else if (mip == TexMode0::TEXF_POINT) - sampdc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT; - else if (mip == TexMode0::TEXF_LINEAR) - sampdc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; - } - else // point mag filter - { - if (mip == TexMode0::TEXF_NONE) - sampdc.Filter = D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT; - else if (mip == TexMode0::TEXF_POINT) - sampdc.Filter = D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT; - else if (mip == TexMode0::TEXF_LINEAR) - sampdc.Filter = D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; - } - } - else // point min filter - { - if (state.mag_filter) // linear mag filter - { - if (mip == TexMode0::TEXF_NONE) - sampdc.Filter = D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; - else if (mip == TexMode0::TEXF_POINT) - sampdc.Filter = D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; - else if (mip == TexMode0::TEXF_LINEAR) - sampdc.Filter = D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR; - } - else // point mag filter - { - if (mip == TexMode0::TEXF_NONE) - sampdc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; - else if (mip == TexMode0::TEXF_POINT) - sampdc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; - else if (mip == TexMode0::TEXF_LINEAR) - sampdc.Filter = D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR; - } - } + sampdc.MaxAnisotropy = 1; + if (g_ActiveConfig.iMaxAnisotropy > 0 && !SamplerCommon::IsBpTexMode0PointFiltering(state)) + { + sampdc.Filter = D3D12_FILTER_ANISOTROPIC; + sampdc.MaxAnisotropy = 1 << g_ActiveConfig.iMaxAnisotropy; + } + else if (state.min_filter & 4) // linear min filter + { + if (state.mag_filter) // linear mag filter + { + if (mip == TexMode0::TEXF_NONE) + sampdc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT; + else if (mip == TexMode0::TEXF_POINT) + sampdc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT; + else if (mip == TexMode0::TEXF_LINEAR) + sampdc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; + } + else // point mag filter + { + if (mip == TexMode0::TEXF_NONE) + sampdc.Filter = D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT; + else if (mip == TexMode0::TEXF_POINT) + sampdc.Filter = D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT; + else if (mip == TexMode0::TEXF_LINEAR) + sampdc.Filter = D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; + } + } + else // point min filter + { + if (state.mag_filter) // linear mag filter + { + if (mip == TexMode0::TEXF_NONE) + sampdc.Filter = D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; + else if (mip == TexMode0::TEXF_POINT) + sampdc.Filter = D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; + else if (mip == TexMode0::TEXF_LINEAR) + sampdc.Filter = D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR; + } + else // point mag filter + { + if (mip == TexMode0::TEXF_NONE) + sampdc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; + else if (mip == TexMode0::TEXF_POINT) + sampdc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; + else if (mip == TexMode0::TEXF_LINEAR) + sampdc.Filter = D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR; + } + } - sampdc.AddressU = d3d_clamps[state.wrap_s]; - sampdc.AddressV = d3d_clamps[state.wrap_t]; - sampdc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + sampdc.AddressU = d3d_clamps[state.wrap_s]; + sampdc.AddressV = d3d_clamps[state.wrap_t]; + sampdc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; - sampdc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; + sampdc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; - sampdc.BorderColor[0] = sampdc.BorderColor[1] = sampdc.BorderColor[2] = sampdc.BorderColor[3] = 1.0f; + sampdc.BorderColor[0] = sampdc.BorderColor[1] = sampdc.BorderColor[2] = sampdc.BorderColor[3] = + 1.0f; - sampdc.MaxLOD = SamplerCommon::AreBpTexMode0MipmapsEnabled(state) ? state.max_lod / 16.f : 0.f; - sampdc.MinLOD = std::min(state.min_lod / 16.f, sampdc.MaxLOD); - sampdc.MipLODBias = static_cast(state.lod_bias) / 32.0f; + sampdc.MaxLOD = SamplerCommon::AreBpTexMode0MipmapsEnabled(state) ? state.max_lod / 16.f : 0.f; + sampdc.MinLOD = std::min(state.min_lod / 16.f, sampdc.MaxLOD); + sampdc.MipLODBias = static_cast(state.lod_bias) / 32.0f; - return sampdc; + return sampdc; } D3D12_BLEND GetBlendingAlpha(D3D12_BLEND blend) { - switch (blend) - { - case D3D12_BLEND_SRC_COLOR: - return D3D12_BLEND_SRC_ALPHA; - case D3D12_BLEND_INV_SRC_COLOR: - return D3D12_BLEND_INV_SRC_ALPHA; - case D3D12_BLEND_DEST_COLOR: - return D3D12_BLEND_DEST_ALPHA; - case D3D12_BLEND_INV_DEST_COLOR: - return D3D12_BLEND_INV_DEST_ALPHA; + switch (blend) + { + case D3D12_BLEND_SRC_COLOR: + return D3D12_BLEND_SRC_ALPHA; + case D3D12_BLEND_INV_SRC_COLOR: + return D3D12_BLEND_INV_SRC_ALPHA; + case D3D12_BLEND_DEST_COLOR: + return D3D12_BLEND_DEST_ALPHA; + case D3D12_BLEND_INV_DEST_COLOR: + return D3D12_BLEND_INV_DEST_ALPHA; - default: - return blend; - } + default: + return blend; + } } D3D12_BLEND_DESC StateCache::GetDesc12(BlendState state) { - if (!state.blend_enable) - { - state.src_blend = D3D12_BLEND_ONE; - state.dst_blend = D3D12_BLEND_ZERO; - state.blend_op = D3D12_BLEND_OP_ADD; - state.use_dst_alpha = false; - } + if (!state.blend_enable) + { + state.src_blend = D3D12_BLEND_ONE; + state.dst_blend = D3D12_BLEND_ZERO; + state.blend_op = D3D12_BLEND_OP_ADD; + state.use_dst_alpha = false; + } - D3D12_BLEND_DESC blenddc = { - FALSE, // BOOL AlphaToCoverageEnable; - FALSE, // BOOL IndependentBlendEnable; - { - state.blend_enable, // BOOL BlendEnable; - FALSE, // BOOL LogicOpEnable; - state.src_blend, // D3D12_BLEND SrcBlend; - state.dst_blend, // D3D12_BLEND DestBlend; - state.blend_op, // D3D12_BLEND_OP BlendOp; - state.src_blend, // D3D12_BLEND SrcBlendAlpha; - state.dst_blend, // D3D12_BLEND DestBlendAlpha; - state.blend_op, // D3D12_BLEND_OP BlendOpAlpha; - D3D12_LOGIC_OP_NOOP, // D3D12_LOGIC_OP LogicOp - state.write_mask // UINT8 RenderTargetWriteMask; - } - }; + D3D12_BLEND_DESC blenddc = {FALSE, // BOOL AlphaToCoverageEnable; + FALSE, // BOOL IndependentBlendEnable; + { + state.blend_enable, // BOOL BlendEnable; + FALSE, // BOOL LogicOpEnable; + state.src_blend, // D3D12_BLEND SrcBlend; + state.dst_blend, // D3D12_BLEND DestBlend; + state.blend_op, // D3D12_BLEND_OP BlendOp; + state.src_blend, // D3D12_BLEND SrcBlendAlpha; + state.dst_blend, // D3D12_BLEND DestBlendAlpha; + state.blend_op, // D3D12_BLEND_OP BlendOpAlpha; + D3D12_LOGIC_OP_NOOP, // D3D12_LOGIC_OP LogicOp + state.write_mask // UINT8 RenderTargetWriteMask; + }}; - blenddc.RenderTarget[0].SrcBlendAlpha = GetBlendingAlpha(blenddc.RenderTarget[0].SrcBlend); - blenddc.RenderTarget[0].DestBlendAlpha = GetBlendingAlpha(blenddc.RenderTarget[0].DestBlend); + blenddc.RenderTarget[0].SrcBlendAlpha = GetBlendingAlpha(blenddc.RenderTarget[0].SrcBlend); + blenddc.RenderTarget[0].DestBlendAlpha = GetBlendingAlpha(blenddc.RenderTarget[0].DestBlend); - if (state.use_dst_alpha) - { - // Colors should blend against SRC1_ALPHA - if (blenddc.RenderTarget[0].SrcBlend == D3D12_BLEND_SRC_ALPHA) - blenddc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC1_ALPHA; - else if (blenddc.RenderTarget[0].SrcBlend == D3D12_BLEND_INV_SRC_ALPHA) - blenddc.RenderTarget[0].SrcBlend = D3D12_BLEND_INV_SRC1_ALPHA; + if (state.use_dst_alpha) + { + // Colors should blend against SRC1_ALPHA + if (blenddc.RenderTarget[0].SrcBlend == D3D12_BLEND_SRC_ALPHA) + blenddc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC1_ALPHA; + else if (blenddc.RenderTarget[0].SrcBlend == D3D12_BLEND_INV_SRC_ALPHA) + blenddc.RenderTarget[0].SrcBlend = D3D12_BLEND_INV_SRC1_ALPHA; - // Colors should blend against SRC1_ALPHA - if (blenddc.RenderTarget[0].DestBlend == D3D12_BLEND_SRC_ALPHA) - blenddc.RenderTarget[0].DestBlend = D3D12_BLEND_SRC1_ALPHA; - else if (blenddc.RenderTarget[0].DestBlend == D3D12_BLEND_INV_SRC_ALPHA) - blenddc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC1_ALPHA; + // Colors should blend against SRC1_ALPHA + if (blenddc.RenderTarget[0].DestBlend == D3D12_BLEND_SRC_ALPHA) + blenddc.RenderTarget[0].DestBlend = D3D12_BLEND_SRC1_ALPHA; + else if (blenddc.RenderTarget[0].DestBlend == D3D12_BLEND_INV_SRC_ALPHA) + blenddc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC1_ALPHA; - blenddc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; - blenddc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO; - blenddc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; - } + blenddc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; + blenddc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO; + blenddc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; + } - return blenddc; + return blenddc; } D3D12_RASTERIZER_DESC StateCache::GetDesc12(RasterizerState state) { - return { - D3D12_FILL_MODE_SOLID, - state.cull_mode, - false, - 0, - 0.f, - 0, - true, - true, - false, - 0, - D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF - }; + return {D3D12_FILL_MODE_SOLID, + state.cull_mode, + false, + 0, + 0.f, + 0, + true, + true, + false, + 0, + D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF}; } inline D3D12_DEPTH_STENCIL_DESC StateCache::GetDesc12(ZMode state) { - D3D12_DEPTH_STENCIL_DESC depthdc; + D3D12_DEPTH_STENCIL_DESC depthdc; - depthdc.StencilEnable = FALSE; - depthdc.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK; - depthdc.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK; + depthdc.StencilEnable = FALSE; + depthdc.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK; + depthdc.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK; - D3D12_DEPTH_STENCILOP_DESC defaultStencilOp = { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS }; - depthdc.FrontFace = defaultStencilOp; - depthdc.BackFace = defaultStencilOp; + D3D12_DEPTH_STENCILOP_DESC defaultStencilOp = {D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, + D3D12_STENCIL_OP_KEEP, + D3D12_COMPARISON_FUNC_ALWAYS}; + depthdc.FrontFace = defaultStencilOp; + depthdc.BackFace = defaultStencilOp; - const D3D12_COMPARISON_FUNC d3dCmpFuncs[8] = - { - D3D12_COMPARISON_FUNC_NEVER, - D3D12_COMPARISON_FUNC_GREATER, - D3D12_COMPARISON_FUNC_EQUAL, - D3D12_COMPARISON_FUNC_GREATER_EQUAL, - D3D12_COMPARISON_FUNC_LESS, - D3D12_COMPARISON_FUNC_NOT_EQUAL, - D3D12_COMPARISON_FUNC_LESS_EQUAL, - D3D12_COMPARISON_FUNC_ALWAYS - }; + const D3D12_COMPARISON_FUNC d3dCmpFuncs[8] = { + D3D12_COMPARISON_FUNC_NEVER, D3D12_COMPARISON_FUNC_GREATER, + D3D12_COMPARISON_FUNC_EQUAL, D3D12_COMPARISON_FUNC_GREATER_EQUAL, + D3D12_COMPARISON_FUNC_LESS, D3D12_COMPARISON_FUNC_NOT_EQUAL, + D3D12_COMPARISON_FUNC_LESS_EQUAL, D3D12_COMPARISON_FUNC_ALWAYS}; - if (state.testenable) - { - depthdc.DepthEnable = TRUE; - depthdc.DepthWriteMask = state.updateenable ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; - depthdc.DepthFunc = d3dCmpFuncs[state.func]; - } - else - { - // if the test is disabled write is disabled too - depthdc.DepthEnable = FALSE; - depthdc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; - } + if (state.testenable) + { + depthdc.DepthEnable = TRUE; + depthdc.DepthWriteMask = + state.updateenable ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; + depthdc.DepthFunc = d3dCmpFuncs[state.func]; + } + else + { + // if the test is disabled write is disabled too + depthdc.DepthEnable = FALSE; + depthdc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; + } - return depthdc; + return depthdc; } -HRESULT StateCache::GetPipelineStateObjectFromCache(D3D12_GRAPHICS_PIPELINE_STATE_DESC* pso_desc, ID3D12PipelineState** pso) +HRESULT StateCache::GetPipelineStateObjectFromCache(D3D12_GRAPHICS_PIPELINE_STATE_DESC* pso_desc, + ID3D12PipelineState** pso) { - auto it = m_pso_map.find(*pso_desc); + auto it = m_pso_map.find(*pso_desc); - if (it == m_pso_map.end()) - { - // Not found, create new PSO. + if (it == m_pso_map.end()) + { + // Not found, create new PSO. - ID3D12PipelineState* new_pso = nullptr; - HRESULT hr = D3D::device12->CreateGraphicsPipelineState(pso_desc, IID_PPV_ARGS(&new_pso)); + ID3D12PipelineState* new_pso = nullptr; + HRESULT hr = D3D::device12->CreateGraphicsPipelineState(pso_desc, IID_PPV_ARGS(&new_pso)); - if (FAILED(hr)) - { - return hr; - } + if (FAILED(hr)) + { + return hr; + } - m_pso_map[*pso_desc] = new_pso; - *pso = new_pso; - } - else - { - *pso = it->second; - } + m_pso_map[*pso_desc] = new_pso; + *pso = new_pso; + } + else + { + *pso = it->second; + } - return S_OK; + return S_OK; } -HRESULT StateCache::GetPipelineStateObjectFromCache(SmallPsoDesc* pso_desc, ID3D12PipelineState** pso, D3D12_PRIMITIVE_TOPOLOGY_TYPE topology, const GeometryShaderUid* gs_uid, const PixelShaderUid* ps_uid, const VertexShaderUid* vs_uid) +HRESULT StateCache::GetPipelineStateObjectFromCache( + SmallPsoDesc* pso_desc, ID3D12PipelineState** pso, D3D12_PRIMITIVE_TOPOLOGY_TYPE topology, + const GeometryShaderUid* gs_uid, const PixelShaderUid* ps_uid, const VertexShaderUid* vs_uid) { - auto it = m_small_pso_map.find(*pso_desc); + auto it = m_small_pso_map.find(*pso_desc); - if (it == m_small_pso_map.end()) - { - // Not found, create new PSO. + if (it == m_small_pso_map.end()) + { + // Not found, create new PSO. - // RootSignature, SampleMask, SampleDesc, NumRenderTargets, RTVFormats, DSVFormat - // never change so they are set in constructor and forgotten. - m_current_pso_desc.GS = pso_desc->gs_bytecode; - m_current_pso_desc.PS = pso_desc->ps_bytecode; - m_current_pso_desc.VS = pso_desc->vs_bytecode; - m_current_pso_desc.BlendState = GetDesc12(pso_desc->blend_state); - m_current_pso_desc.DepthStencilState = GetDesc12(pso_desc->depth_stencil_state); - m_current_pso_desc.RasterizerState = GetDesc12(pso_desc->rasterizer_state); - m_current_pso_desc.PrimitiveTopologyType = topology; - m_current_pso_desc.InputLayout = pso_desc->input_layout->GetActiveInputLayout12(); + // RootSignature, SampleMask, SampleDesc, NumRenderTargets, RTVFormats, DSVFormat + // never change so they are set in constructor and forgotten. + m_current_pso_desc.GS = pso_desc->gs_bytecode; + m_current_pso_desc.PS = pso_desc->ps_bytecode; + m_current_pso_desc.VS = pso_desc->vs_bytecode; + m_current_pso_desc.BlendState = GetDesc12(pso_desc->blend_state); + m_current_pso_desc.DepthStencilState = GetDesc12(pso_desc->depth_stencil_state); + m_current_pso_desc.RasterizerState = GetDesc12(pso_desc->rasterizer_state); + m_current_pso_desc.PrimitiveTopologyType = topology; + m_current_pso_desc.InputLayout = pso_desc->input_layout->GetActiveInputLayout12(); - ID3D12PipelineState* new_pso = nullptr; - HRESULT hr = D3D::device12->CreateGraphicsPipelineState(&m_current_pso_desc, IID_PPV_ARGS(&new_pso)); + ID3D12PipelineState* new_pso = nullptr; + HRESULT hr = + D3D::device12->CreateGraphicsPipelineState(&m_current_pso_desc, IID_PPV_ARGS(&new_pso)); - if (FAILED(hr)) - { - return hr; - } + if (FAILED(hr)) + { + return hr; + } - m_small_pso_map[*pso_desc] = new_pso; - *pso = new_pso; + m_small_pso_map[*pso_desc] = new_pso; + *pso = new_pso; - // This contains all of the information needed to reconstruct a PSO at startup. - SmallPsoDiskDesc disk_desc = {}; - disk_desc.blend_state_hex = pso_desc->blend_state.hex; - disk_desc.depth_stencil_state_hex = pso_desc->depth_stencil_state.hex; - disk_desc.rasterizer_state_hex = pso_desc->rasterizer_state.hex; - disk_desc.ps_uid = *ps_uid; - disk_desc.vs_uid = *vs_uid; - disk_desc.gs_uid = *gs_uid; - disk_desc.vertex_declaration = pso_desc->input_layout->GetVertexDeclaration(); - disk_desc.topology = topology; + // This contains all of the information needed to reconstruct a PSO at startup. + SmallPsoDiskDesc disk_desc = {}; + disk_desc.blend_state_hex = pso_desc->blend_state.hex; + disk_desc.depth_stencil_state_hex = pso_desc->depth_stencil_state.hex; + disk_desc.rasterizer_state_hex = pso_desc->rasterizer_state.hex; + disk_desc.ps_uid = *ps_uid; + disk_desc.vs_uid = *vs_uid; + disk_desc.gs_uid = *gs_uid; + disk_desc.vertex_declaration = pso_desc->input_layout->GetVertexDeclaration(); + disk_desc.topology = topology; - // This shouldn't fail.. but if it does, don't cache to disk. - ID3DBlob* psoBlob = nullptr; - hr = new_pso->GetCachedBlob(&psoBlob); + // This shouldn't fail.. but if it does, don't cache to disk. + ID3DBlob* psoBlob = nullptr; + hr = new_pso->GetCachedBlob(&psoBlob); - if (SUCCEEDED(hr)) - { - s_pso_disk_cache.Append(disk_desc, reinterpret_cast(psoBlob->GetBufferPointer()), static_cast(psoBlob->GetBufferSize())); - psoBlob->Release(); - } - } - else - { - *pso = it->second; - } + if (SUCCEEDED(hr)) + { + s_pso_disk_cache.Append(disk_desc, reinterpret_cast(psoBlob->GetBufferPointer()), + static_cast(psoBlob->GetBufferSize())); + psoBlob->Release(); + } + } + else + { + *pso = it->second; + } - return S_OK; + return S_OK; } void StateCache::OnMSAASettingsChanged() { - for (auto& it : m_small_pso_map) - { - SAFE_RELEASE(it.second); - } - m_small_pso_map.clear(); + for (auto& it : m_small_pso_map) + { + SAFE_RELEASE(it.second); + } + m_small_pso_map.clear(); - // Update sample count for new PSOs being created - gx_state_cache.m_current_pso_desc.SampleDesc.Count = g_ActiveConfig.iMultisamples; + // Update sample count for new PSOs being created + gx_state_cache.m_current_pso_desc.SampleDesc.Count = g_ActiveConfig.iMultisamples; } void StateCache::Clear() { - for (auto& it : m_pso_map) - { - SAFE_RELEASE(it.second); - } - m_pso_map.clear(); + for (auto& it : m_pso_map) + { + SAFE_RELEASE(it.second); + } + m_pso_map.clear(); - for (auto& it : m_small_pso_map) - { - SAFE_RELEASE(it.second); - } - m_small_pso_map.clear(); + for (auto& it : m_small_pso_map) + { + SAFE_RELEASE(it.second); + } + m_small_pso_map.clear(); - s_pso_disk_cache.Sync(); - s_pso_disk_cache.Close(); + s_pso_disk_cache.Sync(); + s_pso_disk_cache.Close(); } } // namespace DX12 diff --git a/Source/Core/VideoBackends/D3D12/D3DState.h b/Source/Core/VideoBackends/D3D12/D3DState.h index 49d4fab157..22744ac15d 100644 --- a/Source/Core/VideoBackends/D3D12/D3DState.h +++ b/Source/Core/VideoBackends/D3D12/D3DState.h @@ -17,50 +17,46 @@ namespace DX12 { - class PipelineStateCacheInserter; -union RasterizerState -{ - BitField<0, 2, D3D12_CULL_MODE> cull_mode; +union RasterizerState { + BitField<0, 2, D3D12_CULL_MODE> cull_mode; - u32 hex; + u32 hex; }; -union BlendState -{ - BitField<0, 1, u32> blend_enable; - BitField<1, 3, D3D12_BLEND_OP> blend_op; - BitField<4, 4, u8> write_mask; - BitField<8, 5, D3D12_BLEND> src_blend; - BitField<13, 5, D3D12_BLEND> dst_blend; - BitField<18, 1, u32> use_dst_alpha; +union BlendState { + BitField<0, 1, u32> blend_enable; + BitField<1, 3, D3D12_BLEND_OP> blend_op; + BitField<4, 4, u8> write_mask; + BitField<8, 5, D3D12_BLEND> src_blend; + BitField<13, 5, D3D12_BLEND> dst_blend; + BitField<18, 1, u32> use_dst_alpha; - u32 hex; + u32 hex; }; -union SamplerState -{ - BitField<0, 3, u32> min_filter; - BitField<3, 1, u32> mag_filter; - BitField<4, 8, u32> min_lod; - BitField<12, 8, u32> max_lod; - BitField<20, 8, s32> lod_bias; - BitField<28, 2, u32> wrap_s; - BitField<30, 2, u32> wrap_t; +union SamplerState { + BitField<0, 3, u32> min_filter; + BitField<3, 1, u32> mag_filter; + BitField<4, 8, u32> min_lod; + BitField<12, 8, u32> max_lod; + BitField<20, 8, s32> lod_bias; + BitField<28, 2, u32> wrap_s; + BitField<30, 2, u32> wrap_t; - u32 hex; + u32 hex; }; struct SmallPsoDesc { - D3D12_SHADER_BYTECODE gs_bytecode; - D3D12_SHADER_BYTECODE ps_bytecode; - D3D12_SHADER_BYTECODE vs_bytecode; - D3DVertexFormat* input_layout; - BlendState blend_state; - RasterizerState rasterizer_state; - ZMode depth_stencil_state; + D3D12_SHADER_BYTECODE gs_bytecode; + D3D12_SHADER_BYTECODE ps_bytecode; + D3D12_SHADER_BYTECODE vs_bytecode; + D3DVertexFormat* input_layout; + BlendState blend_state; + RasterizerState rasterizer_state; + ZMode depth_stencil_state; }; // The Bitfield members in BlendState, RasterizerState, and ZMode cause the.. @@ -69,124 +65,128 @@ struct SmallPsoDesc struct SmallPsoDiskDesc { - u32 blend_state_hex; - u32 rasterizer_state_hex; - u32 depth_stencil_state_hex; - PixelShaderUid ps_uid; - VertexShaderUid vs_uid; - GeometryShaderUid gs_uid; - D3D12_PRIMITIVE_TOPOLOGY_TYPE topology; - PortableVertexDeclaration vertex_declaration; // Used to construct the input layout. + u32 blend_state_hex; + u32 rasterizer_state_hex; + u32 depth_stencil_state_hex; + PixelShaderUid ps_uid; + VertexShaderUid vs_uid; + GeometryShaderUid gs_uid; + D3D12_PRIMITIVE_TOPOLOGY_TYPE topology; + PortableVertexDeclaration vertex_declaration; // Used to construct the input layout. }; class StateCache { public: - StateCache(); + StateCache(); - static void Init(); + static void Init(); - // Get D3D12 descs for the internal state bitfields. - static D3D12_SAMPLER_DESC GetDesc12(SamplerState state); - static D3D12_BLEND_DESC GetDesc12(BlendState state); - static D3D12_RASTERIZER_DESC GetDesc12(RasterizerState state); - static D3D12_DEPTH_STENCIL_DESC GetDesc12(ZMode state); + // Get D3D12 descs for the internal state bitfields. + static D3D12_SAMPLER_DESC GetDesc12(SamplerState state); + static D3D12_BLEND_DESC GetDesc12(BlendState state); + static D3D12_RASTERIZER_DESC GetDesc12(RasterizerState state); + static D3D12_DEPTH_STENCIL_DESC GetDesc12(ZMode state); - HRESULT GetPipelineStateObjectFromCache(D3D12_GRAPHICS_PIPELINE_STATE_DESC* pso_desc, ID3D12PipelineState** pso); - HRESULT GetPipelineStateObjectFromCache(SmallPsoDesc* pso_desc, ID3D12PipelineState** pso, D3D12_PRIMITIVE_TOPOLOGY_TYPE topology, const GeometryShaderUid* gs_uid, const PixelShaderUid* ps_uid, const VertexShaderUid* vs_uid); + HRESULT GetPipelineStateObjectFromCache(D3D12_GRAPHICS_PIPELINE_STATE_DESC* pso_desc, + ID3D12PipelineState** pso); + HRESULT GetPipelineStateObjectFromCache(SmallPsoDesc* pso_desc, ID3D12PipelineState** pso, + D3D12_PRIMITIVE_TOPOLOGY_TYPE topology, + const GeometryShaderUid* gs_uid, + const PixelShaderUid* ps_uid, + const VertexShaderUid* vs_uid); - // Called when the MSAA count/quality changes. Invalidates all small PSOs. - void OnMSAASettingsChanged(); + // Called when the MSAA count/quality changes. Invalidates all small PSOs. + void OnMSAASettingsChanged(); - // Release all cached states and clear hash tables. - void Clear(); + // Release all cached states and clear hash tables. + void Clear(); private: + friend DX12::PipelineStateCacheInserter; - friend DX12::PipelineStateCacheInserter; + D3D12_GRAPHICS_PIPELINE_STATE_DESC m_current_pso_desc; - D3D12_GRAPHICS_PIPELINE_STATE_DESC m_current_pso_desc; + struct hash_pso_desc + { + size_t operator()(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& pso_desc) const + { + return ((uintptr_t)pso_desc.PS.pShaderBytecode * 1000000) ^ + ((uintptr_t)pso_desc.VS.pShaderBytecode * 1000) ^ + ((uintptr_t)pso_desc.InputLayout.pInputElementDescs); + } + }; - struct hash_pso_desc - { - size_t operator()(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& pso_desc) const - { - return ((uintptr_t)pso_desc.PS.pShaderBytecode * 1000000) ^ ((uintptr_t)pso_desc.VS.pShaderBytecode * 1000) ^ ((uintptr_t)pso_desc.InputLayout.pInputElementDescs); - } - }; + struct equality_pipeline_state_desc + { + bool operator()(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& lhs, + const D3D12_GRAPHICS_PIPELINE_STATE_DESC& rhs) const + { + return std::tie( + lhs.PS.pShaderBytecode, lhs.VS.pShaderBytecode, lhs.GS.pShaderBytecode, + lhs.RasterizerState.CullMode, lhs.DepthStencilState.DepthEnable, + lhs.DepthStencilState.DepthFunc, lhs.DepthStencilState.DepthWriteMask, + lhs.BlendState.RenderTarget[0].BlendEnable, lhs.BlendState.RenderTarget[0].BlendOp, + lhs.BlendState.RenderTarget[0].DestBlend, lhs.BlendState.RenderTarget[0].SrcBlend, + lhs.BlendState.RenderTarget[0].RenderTargetWriteMask, lhs.RTVFormats[0], + lhs.SampleDesc.Count) == + std::tie( + rhs.PS.pShaderBytecode, rhs.VS.pShaderBytecode, rhs.GS.pShaderBytecode, + rhs.RasterizerState.CullMode, rhs.DepthStencilState.DepthEnable, + rhs.DepthStencilState.DepthFunc, rhs.DepthStencilState.DepthWriteMask, + rhs.BlendState.RenderTarget[0].BlendEnable, rhs.BlendState.RenderTarget[0].BlendOp, + rhs.BlendState.RenderTarget[0].DestBlend, rhs.BlendState.RenderTarget[0].SrcBlend, + rhs.BlendState.RenderTarget[0].RenderTargetWriteMask, rhs.RTVFormats[0], + rhs.SampleDesc.Count); + } + }; - struct equality_pipeline_state_desc - { - bool operator()(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& lhs, const D3D12_GRAPHICS_PIPELINE_STATE_DESC& rhs) const - { - return std::tie(lhs.PS.pShaderBytecode, lhs.VS.pShaderBytecode, lhs.GS.pShaderBytecode, - lhs.RasterizerState.CullMode, - lhs.DepthStencilState.DepthEnable, - lhs.DepthStencilState.DepthFunc, - lhs.DepthStencilState.DepthWriteMask, - lhs.BlendState.RenderTarget[0].BlendEnable, - lhs.BlendState.RenderTarget[0].BlendOp, - lhs.BlendState.RenderTarget[0].DestBlend, - lhs.BlendState.RenderTarget[0].SrcBlend, - lhs.BlendState.RenderTarget[0].RenderTargetWriteMask, - lhs.RTVFormats[0], - lhs.SampleDesc.Count) == - std::tie(rhs.PS.pShaderBytecode, rhs.VS.pShaderBytecode, rhs.GS.pShaderBytecode, - rhs.RasterizerState.CullMode, - rhs.DepthStencilState.DepthEnable, - rhs.DepthStencilState.DepthFunc, - rhs.DepthStencilState.DepthWriteMask, - rhs.BlendState.RenderTarget[0].BlendEnable, - rhs.BlendState.RenderTarget[0].BlendOp, - rhs.BlendState.RenderTarget[0].DestBlend, - rhs.BlendState.RenderTarget[0].SrcBlend, - rhs.BlendState.RenderTarget[0].RenderTargetWriteMask, - rhs.RTVFormats[0], - rhs.SampleDesc.Count); - } - }; + std::unordered_map + m_pso_map; - std::unordered_map m_pso_map; + struct hash_small_pso_desc + { + size_t operator()(const SmallPsoDesc& pso_desc) const + { + return ((uintptr_t)pso_desc.vs_bytecode.pShaderBytecode << 10) ^ + ((uintptr_t)pso_desc.ps_bytecode.pShaderBytecode) + pso_desc.blend_state.hex + + pso_desc.depth_stencil_state.hex; + } + }; - struct hash_small_pso_desc - { - size_t operator()(const SmallPsoDesc& pso_desc) const - { - return ((uintptr_t)pso_desc.vs_bytecode.pShaderBytecode << 10) ^ - ((uintptr_t)pso_desc.ps_bytecode.pShaderBytecode) + - pso_desc.blend_state.hex + - pso_desc.depth_stencil_state.hex; - } - }; + struct equality_small_pipeline_state_desc + { + bool operator()(const SmallPsoDesc& lhs, const SmallPsoDesc& rhs) const + { + return std::tie(lhs.ps_bytecode.pShaderBytecode, lhs.vs_bytecode.pShaderBytecode, + lhs.gs_bytecode.pShaderBytecode, lhs.input_layout, lhs.blend_state.hex, + lhs.depth_stencil_state.hex, lhs.rasterizer_state.hex) == + std::tie(rhs.ps_bytecode.pShaderBytecode, rhs.vs_bytecode.pShaderBytecode, + rhs.gs_bytecode.pShaderBytecode, rhs.input_layout, rhs.blend_state.hex, + rhs.depth_stencil_state.hex, rhs.rasterizer_state.hex); + } + }; - struct equality_small_pipeline_state_desc - { - bool operator()(const SmallPsoDesc& lhs, const SmallPsoDesc& rhs) const - { - return std::tie(lhs.ps_bytecode.pShaderBytecode, lhs.vs_bytecode.pShaderBytecode, lhs.gs_bytecode.pShaderBytecode, - lhs.input_layout, lhs.blend_state.hex, lhs.depth_stencil_state.hex, lhs.rasterizer_state.hex) == - std::tie(rhs.ps_bytecode.pShaderBytecode, rhs.vs_bytecode.pShaderBytecode, rhs.gs_bytecode.pShaderBytecode, - rhs.input_layout, rhs.blend_state.hex, rhs.depth_stencil_state.hex, rhs.rasterizer_state.hex); - } - }; + struct hash_shader_bytecode + { + size_t operator()(const D3D12_SHADER_BYTECODE& shader) const + { + return (uintptr_t)shader.pShaderBytecode; + } + }; - struct hash_shader_bytecode - { - size_t operator()(const D3D12_SHADER_BYTECODE& shader) const - { - return (uintptr_t)shader.pShaderBytecode; - } - }; + struct equality_shader_bytecode + { + bool operator()(const D3D12_SHADER_BYTECODE& lhs, const D3D12_SHADER_BYTECODE& rhs) const + { + return lhs.pShaderBytecode == rhs.pShaderBytecode; + } + }; - struct equality_shader_bytecode - { - bool operator()(const D3D12_SHADER_BYTECODE& lhs, const D3D12_SHADER_BYTECODE& rhs) const - { - return lhs.pShaderBytecode == rhs.pShaderBytecode; - } - }; - - std::unordered_map m_small_pso_map; + std::unordered_map + m_small_pso_map; }; } // namespace DX12 diff --git a/Source/Core/VideoBackends/D3D12/D3DStreamBuffer.cpp b/Source/Core/VideoBackends/D3D12/D3DStreamBuffer.cpp index cfb67209c8..55133b400e 100644 --- a/Source/Core/VideoBackends/D3D12/D3DStreamBuffer.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DStreamBuffer.cpp @@ -11,27 +11,28 @@ namespace DX12 { - -D3DStreamBuffer::D3DStreamBuffer(size_t initial_size, size_t max_size, bool* buffer_reallocation_notification) : - m_buffer_size(initial_size), - m_buffer_max_size(max_size), - m_buffer_reallocation_notification(buffer_reallocation_notification) +D3DStreamBuffer::D3DStreamBuffer(size_t initial_size, size_t max_size, + bool* buffer_reallocation_notification) + : m_buffer_size(initial_size), m_buffer_max_size(max_size), + m_buffer_reallocation_notification(buffer_reallocation_notification) { - CHECK(initial_size <= max_size, "Error: Initial size for D3DStreamBuffer is greater than max_size."); + CHECK(initial_size <= max_size, + "Error: Initial size for D3DStreamBuffer is greater than max_size."); - AllocateBuffer(initial_size); + AllocateBuffer(initial_size); - // Register for callback from D3DCommandListManager each time a fence is queued to be signaled. - m_buffer_tracking_fence = D3D::command_list_mgr->RegisterQueueFenceCallback(this, &D3DStreamBuffer::QueueFenceCallback); + // Register for callback from D3DCommandListManager each time a fence is queued to be signaled. + m_buffer_tracking_fence = + D3D::command_list_mgr->RegisterQueueFenceCallback(this, &D3DStreamBuffer::QueueFenceCallback); } D3DStreamBuffer::~D3DStreamBuffer() { - D3D::command_list_mgr->RemoveQueueFenceCallback(this); + D3D::command_list_mgr->RemoveQueueFenceCallback(this); - D3D12_RANGE write_range = { 0, m_buffer_size }; - m_buffer->Unmap(0, &write_range); - D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_buffer); + D3D12_RANGE write_range = {0, m_buffer_size}; + m_buffer->Unmap(0, &write_range); + D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_buffer); } // Function returns true if (worst case), needed to flush existing command list in order to @@ -40,45 +41,49 @@ D3DStreamBuffer::~D3DStreamBuffer() // Obviously this is non-performant, so the buffer max_size should be large enough to // ensure this never happens. -bool D3DStreamBuffer::AllocateSpaceInBuffer(size_t allocation_size, size_t alignment, bool allow_execute) +bool D3DStreamBuffer::AllocateSpaceInBuffer(size_t allocation_size, size_t alignment, + bool allow_execute) { - CHECK(allocation_size <= m_buffer_max_size, "Error: Requested allocation size in D3DStreamBuffer is greater than max allowed size of backing buffer."); + CHECK(allocation_size <= m_buffer_max_size, "Error: Requested allocation size in D3DStreamBuffer " + "is greater than max allowed size of backing " + "buffer."); - if (alignment && m_buffer_offset > 0) - { - size_t padding = m_buffer_offset % alignment; + if (alignment && m_buffer_offset > 0) + { + size_t padding = m_buffer_offset % alignment; - // Check for case when adding alignment causes CPU offset to equal GPU offset, - // which would imply entire buffer is available (if not corrected). - if (m_buffer_offset < m_buffer_gpu_completion_offset && - m_buffer_offset + alignment - padding >= m_buffer_gpu_completion_offset) - { - m_buffer_gpu_completion_offset++; - } + // Check for case when adding alignment causes CPU offset to equal GPU offset, + // which would imply entire buffer is available (if not corrected). + if (m_buffer_offset < m_buffer_gpu_completion_offset && + m_buffer_offset + alignment - padding >= m_buffer_gpu_completion_offset) + { + m_buffer_gpu_completion_offset++; + } - m_buffer_offset += alignment - padding; + m_buffer_offset += alignment - padding; - if (m_buffer_offset > m_buffer_size) - { - m_buffer_offset = 0; + if (m_buffer_offset > m_buffer_size) + { + m_buffer_offset = 0; - // Correct for case where CPU was about to run into GPU. - if (m_buffer_gpu_completion_offset == 0) - m_buffer_gpu_completion_offset = 1; - } - } + // Correct for case where CPU was about to run into GPU. + if (m_buffer_gpu_completion_offset == 0) + m_buffer_gpu_completion_offset = 1; + } + } - // First, check if there is available (not-in-use-by-GPU) space in existing buffer. - if (AttemptToAllocateOutOfExistingUnusedSpaceInBuffer(allocation_size)) - { - return false; - } + // First, check if there is available (not-in-use-by-GPU) space in existing buffer. + if (AttemptToAllocateOutOfExistingUnusedSpaceInBuffer(allocation_size)) + { + return false; + } - // Slow path. No room at front, or back, due to the GPU still (possibly) accessing parts of the buffer. - // Resize if possible, else stall. - bool command_list_executed = AttemptBufferResizeOrElseStall(allocation_size, allow_execute); + // Slow path. No room at front, or back, due to the GPU still (possibly) accessing parts of the + // buffer. + // Resize if possible, else stall. + bool command_list_executed = AttemptBufferResizeOrElseStall(allocation_size, allow_execute); - return command_list_executed; + return command_list_executed; } // In VertexManager, we don't know the 'real' size of the allocation at the time @@ -87,48 +92,42 @@ bool D3DStreamBuffer::AllocateSpaceInBuffer(size_t allocation_size, size_t align // size to avoid wasting space. void D3DStreamBuffer::OverrideSizeOfPreviousAllocation(size_t override_allocation_size) { - m_buffer_offset = m_buffer_current_allocation_offset + override_allocation_size; + m_buffer_offset = m_buffer_current_allocation_offset + override_allocation_size; } void D3DStreamBuffer::AllocateBuffer(size_t size) { - // First, put existing buffer (if it exists) in deferred destruction list. - if (m_buffer) - { - D3D12_RANGE write_range = { 0, m_buffer_size }; - m_buffer->Unmap(0, &write_range); - D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_buffer); - m_buffer = nullptr; - } + // First, put existing buffer (if it exists) in deferred destruction list. + if (m_buffer) + { + D3D12_RANGE write_range = {0, m_buffer_size}; + m_buffer->Unmap(0, &write_range); + D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_buffer); + m_buffer = nullptr; + } - CheckHR( - D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Buffer(size), - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, - IID_PPV_ARGS(&m_buffer) - ) - ); + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer(size), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, + IID_PPV_ARGS(&m_buffer))); - D3D12_RANGE read_range = {}; - CheckHR(m_buffer->Map(0, &read_range, &m_buffer_cpu_address)); + D3D12_RANGE read_range = {}; + CheckHR(m_buffer->Map(0, &read_range, &m_buffer_cpu_address)); - m_buffer_gpu_address = m_buffer->GetGPUVirtualAddress(); - m_buffer_size = size; + m_buffer_gpu_address = m_buffer->GetGPUVirtualAddress(); + m_buffer_size = size; - // Start at the beginning of the new buffer. - m_buffer_gpu_completion_offset = 0; - m_buffer_current_allocation_offset = 0; - m_buffer_offset = 0; + // Start at the beginning of the new buffer. + m_buffer_gpu_completion_offset = 0; + m_buffer_current_allocation_offset = 0; + m_buffer_offset = 0; - // Notify observers. - if (m_buffer_reallocation_notification != nullptr) - *m_buffer_reallocation_notification = true; + // Notify observers. + if (m_buffer_reallocation_notification != nullptr) + *m_buffer_reallocation_notification = true; - // If we had any fences queued, they are no longer relevant. - ClearFences(); + // If we had any fences queued, they are no longer relevant. + ClearFences(); } // Function returns true if current command list executed as a result of current command list @@ -136,255 +135,260 @@ void D3DStreamBuffer::AllocateBuffer(size_t size) // flush. See comments above AllocateSpaceInBuffer for more details. bool D3DStreamBuffer::AttemptBufferResizeOrElseStall(size_t allocation_size, bool allow_execute) { - // This function will attempt to increase the size of the buffer, in response - // to running out of room. If the buffer is already at its maximum size specified - // at creation time, then stall waiting for the GPU to finish with the currently - // requested memory. + // This function will attempt to increase the size of the buffer, in response + // to running out of room. If the buffer is already at its maximum size specified + // at creation time, then stall waiting for the GPU to finish with the currently + // requested memory. - // Four possibilities, in order of desirability. - // 1) Best - Update GPU tracking progress - maybe the GPU has made enough - // progress such that there is now room. - // 2) Enlarge GPU buffer, up to our max allowed size. - // 3) Stall until GPU finishes existing queued work/advances offset - // in buffer enough to free room. - // 4) Worst - flush current GPU commands and wait, which will free all room - // in buffer. + // Four possibilities, in order of desirability. + // 1) Best - Update GPU tracking progress - maybe the GPU has made enough + // progress such that there is now room. + // 2) Enlarge GPU buffer, up to our max allowed size. + // 3) Stall until GPU finishes existing queued work/advances offset + // in buffer enough to free room. + // 4) Worst - flush current GPU commands and wait, which will free all room + // in buffer. - // 1) First, let's check if GPU has already continued farther along buffer. If it has freed up - // enough of the buffer, we won't have to stall/allocate new memory. + // 1) First, let's check if GPU has already continued farther along buffer. If it has freed up + // enough of the buffer, we won't have to stall/allocate new memory. - UpdateGPUProgress(); + UpdateGPUProgress(); - // Now that GPU progress is updated, do we have room in the queue? - if (AttemptToAllocateOutOfExistingUnusedSpaceInBuffer(allocation_size)) - { - return false; - } + // Now that GPU progress is updated, do we have room in the queue? + if (AttemptToAllocateOutOfExistingUnusedSpaceInBuffer(allocation_size)) + { + return false; + } - // 2) Next, prefer increasing buffer size instead of stalling. - size_t new_size = std::min(static_cast(m_buffer_size * 1.5f), m_buffer_max_size); - new_size = std::max(new_size, allocation_size); + // 2) Next, prefer increasing buffer size instead of stalling. + size_t new_size = std::min(static_cast(m_buffer_size * 1.5f), m_buffer_max_size); + new_size = std::max(new_size, allocation_size); - // Can we grow buffer further? - if (new_size > m_buffer_size) - { - AllocateBuffer(new_size); - m_buffer_offset = allocation_size; - return false; - } + // Can we grow buffer further? + if (new_size > m_buffer_size) + { + AllocateBuffer(new_size); + m_buffer_offset = allocation_size; + return false; + } - // 3) Bad case - we need to stall. - // This might be ok if we have > 2 frames queued up or something, but - // we don't want to be stalling as we generate the front-of-queue frame. + // 3) Bad case - we need to stall. + // This might be ok if we have > 2 frames queued up or something, but + // we don't want to be stalling as we generate the front-of-queue frame. - const bool found_fence_to_wait_on = AttemptToFindExistingFenceToStallOn(allocation_size); + const bool found_fence_to_wait_on = AttemptToFindExistingFenceToStallOn(allocation_size); - if (found_fence_to_wait_on) - { - return false; - } + if (found_fence_to_wait_on) + { + return false; + } - // If allow_execute is false, the caller cannot handle command list execution (and the associated reset), so re-allocate the same-sized buffer. - if (!allow_execute) - { - AllocateBuffer(new_size); - m_buffer_offset = allocation_size; - return false; - } + // If allow_execute is false, the caller cannot handle command list execution (and the associated + // reset), so re-allocate the same-sized buffer. + if (!allow_execute) + { + AllocateBuffer(new_size); + m_buffer_offset = allocation_size; + return false; + } - // 4) If we get to this point, that means there is no outstanding queued GPU work, and we're still out of room. - // This is bad - and performance will suffer due to the CPU/GPU serialization, but the show must go on. + // 4) If we get to this point, that means there is no outstanding queued GPU work, and we're still + // out of room. + // This is bad - and performance will suffer due to the CPU/GPU serialization, but the show must + // go on. - // This is guaranteed to succeed, since we've already CHECK'd that the allocation_size <= max_buffer_size, and flushing now and waiting will - // free all space in buffer. + // This is guaranteed to succeed, since we've already CHECK'd that the allocation_size <= + // max_buffer_size, and flushing now and waiting will + // free all space in buffer. - D3D::command_list_mgr->ExecuteQueuedWork(true); + D3D::command_list_mgr->ExecuteQueuedWork(true); - m_buffer_offset = allocation_size; - m_buffer_current_allocation_offset = 0; - m_buffer_gpu_completion_offset = 0; - ClearFences(); + m_buffer_offset = allocation_size; + m_buffer_current_allocation_offset = 0; + m_buffer_gpu_completion_offset = 0; + ClearFences(); - return true; + return true; } // Return true if space is found. bool D3DStreamBuffer::AttemptToAllocateOutOfExistingUnusedSpaceInBuffer(size_t allocation_size) { - // First, check if there is room at end of buffer. Fast path. - if (m_buffer_offset >= m_buffer_gpu_completion_offset) - { - if (m_buffer_offset + allocation_size <= m_buffer_size) - { - m_buffer_current_allocation_offset = m_buffer_offset; - m_buffer_offset += allocation_size; - return true; - } + // First, check if there is room at end of buffer. Fast path. + if (m_buffer_offset >= m_buffer_gpu_completion_offset) + { + if (m_buffer_offset + allocation_size <= m_buffer_size) + { + m_buffer_current_allocation_offset = m_buffer_offset; + m_buffer_offset += allocation_size; + return true; + } - if (0 + allocation_size < m_buffer_gpu_completion_offset) - { - m_buffer_current_allocation_offset = 0; - m_buffer_offset = allocation_size; - return true; - } - } + if (0 + allocation_size < m_buffer_gpu_completion_offset) + { + m_buffer_current_allocation_offset = 0; + m_buffer_offset = allocation_size; + return true; + } + } - // Next, check if there is room at front of buffer. Fast path. - if (m_buffer_offset < m_buffer_gpu_completion_offset && m_buffer_offset + allocation_size < m_buffer_gpu_completion_offset) - { - m_buffer_current_allocation_offset = m_buffer_offset; - m_buffer_offset += allocation_size; - return true; - } + // Next, check if there is room at front of buffer. Fast path. + if (m_buffer_offset < m_buffer_gpu_completion_offset && + m_buffer_offset + allocation_size < m_buffer_gpu_completion_offset) + { + m_buffer_current_allocation_offset = m_buffer_offset; + m_buffer_offset += allocation_size; + return true; + } - return false; + return false; } // Returns true if fence was found and waited on. bool D3DStreamBuffer::AttemptToFindExistingFenceToStallOn(size_t allocation_size) { - // Let's find the first fence that will free up enough space in our buffer. + // Let's find the first fence that will free up enough space in our buffer. - UINT64 fence_value_required = 0; + UINT64 fence_value_required = 0; - while (m_queued_fences.size() > 0) - { - FenceTrackingInformation tracking_information = m_queued_fences.front(); - m_queued_fences.pop(); + while (m_queued_fences.size() > 0) + { + FenceTrackingInformation tracking_information = m_queued_fences.front(); + m_queued_fences.pop(); - if (m_buffer_offset >= m_buffer_gpu_completion_offset) - { - // At this point, we need to wrap around, so req'd gpu offset is allocation_size. - if (tracking_information.buffer_offset >= allocation_size) - { - fence_value_required = tracking_information.fence_value; - m_buffer_current_allocation_offset = 0; - m_buffer_offset = allocation_size; - break; - } - } - else - { - if (m_buffer_offset + allocation_size <= m_buffer_size) - { - if (tracking_information.buffer_offset >= m_buffer_offset + allocation_size) - { - fence_value_required = tracking_information.fence_value; - m_buffer_current_allocation_offset = m_buffer_offset; - m_buffer_offset = m_buffer_offset + allocation_size; - break; - } - } - else - { - if (tracking_information.buffer_offset >= allocation_size) - { - fence_value_required = tracking_information.fence_value; - m_buffer_current_allocation_offset = 0; - m_buffer_offset = allocation_size; - break; - } - } - } - } + if (m_buffer_offset >= m_buffer_gpu_completion_offset) + { + // At this point, we need to wrap around, so req'd gpu offset is allocation_size. + if (tracking_information.buffer_offset >= allocation_size) + { + fence_value_required = tracking_information.fence_value; + m_buffer_current_allocation_offset = 0; + m_buffer_offset = allocation_size; + break; + } + } + else + { + if (m_buffer_offset + allocation_size <= m_buffer_size) + { + if (tracking_information.buffer_offset >= m_buffer_offset + allocation_size) + { + fence_value_required = tracking_information.fence_value; + m_buffer_current_allocation_offset = m_buffer_offset; + m_buffer_offset = m_buffer_offset + allocation_size; + break; + } + } + else + { + if (tracking_information.buffer_offset >= allocation_size) + { + fence_value_required = tracking_information.fence_value; + m_buffer_current_allocation_offset = 0; + m_buffer_offset = allocation_size; + break; + } + } + } + } - // Check if we found a fence we can wait on, for GPU to make sufficient progress. - // If so, wait on it. - if (fence_value_required > 0) - { - D3D::command_list_mgr->WaitOnCPUForFence(m_buffer_tracking_fence, fence_value_required); - return true; - } + // Check if we found a fence we can wait on, for GPU to make sufficient progress. + // If so, wait on it. + if (fence_value_required > 0) + { + D3D::command_list_mgr->WaitOnCPUForFence(m_buffer_tracking_fence, fence_value_required); + return true; + } - return false; + return false; } void D3DStreamBuffer::UpdateGPUProgress() { - const UINT64 fence_value = m_buffer_tracking_fence->GetCompletedValue(); + const UINT64 fence_value = m_buffer_tracking_fence->GetCompletedValue(); - while (m_queued_fences.size() > 0) - { - FenceTrackingInformation tracking_information = m_queued_fences.front(); - m_queued_fences.pop(); + while (m_queued_fences.size() > 0) + { + FenceTrackingInformation tracking_information = m_queued_fences.front(); + m_queued_fences.pop(); - // Has fence gone past this point? - if (fence_value >= tracking_information.fence_value) - { - m_buffer_gpu_completion_offset = tracking_information.buffer_offset; - } - else - { - // Fences are stored in ascending order, so once we hit a fence we haven't yet crossed on GPU, abort search. - break; - } - } + // Has fence gone past this point? + if (fence_value >= tracking_information.fence_value) + { + m_buffer_gpu_completion_offset = tracking_information.buffer_offset; + } + else + { + // Fences are stored in ascending order, so once we hit a fence we haven't yet crossed on GPU, + // abort search. + break; + } + } } void D3DStreamBuffer::QueueFenceCallback(void* owning_object, UINT64 fence_value) { - D3DStreamBuffer* owning_stream_buffer = reinterpret_cast(owning_object); - if (owning_stream_buffer->HasBufferOffsetChangedSinceLastFence()) - owning_stream_buffer->QueueFence(fence_value); + D3DStreamBuffer* owning_stream_buffer = reinterpret_cast(owning_object); + if (owning_stream_buffer->HasBufferOffsetChangedSinceLastFence()) + owning_stream_buffer->QueueFence(fence_value); } void D3DStreamBuffer::ClearFences() { - while (!m_queued_fences.empty()) - m_queued_fences.pop(); + while (!m_queued_fences.empty()) + m_queued_fences.pop(); } bool D3DStreamBuffer::HasBufferOffsetChangedSinceLastFence() const { - if (m_queued_fences.empty()) - return true; + if (m_queued_fences.empty()) + return true; - // Don't add a new fence tracking entry when our offset hasn't changed. - return (m_queued_fences.back().buffer_offset != m_buffer_offset); + // Don't add a new fence tracking entry when our offset hasn't changed. + return (m_queued_fences.back().buffer_offset != m_buffer_offset); } void D3DStreamBuffer::QueueFence(UINT64 fence_value) { - FenceTrackingInformation tracking_information = {}; - tracking_information.fence_value = fence_value; - tracking_information.buffer_offset = m_buffer_offset; + FenceTrackingInformation tracking_information = {}; + tracking_information.fence_value = fence_value; + tracking_information.buffer_offset = m_buffer_offset; - m_queued_fences.push(tracking_information); + m_queued_fences.push(tracking_information); } ID3D12Resource* D3DStreamBuffer::GetBuffer() const { - return m_buffer; + return m_buffer; } D3D12_GPU_VIRTUAL_ADDRESS D3DStreamBuffer::GetGPUAddressOfCurrentAllocation() const { - return m_buffer_gpu_address + m_buffer_current_allocation_offset; + return m_buffer_gpu_address + m_buffer_current_allocation_offset; } void* D3DStreamBuffer::GetCPUAddressOfCurrentAllocation() const { - return static_cast(m_buffer_cpu_address) + m_buffer_current_allocation_offset; + return static_cast(m_buffer_cpu_address) + m_buffer_current_allocation_offset; } size_t D3DStreamBuffer::GetOffsetOfCurrentAllocation() const { - return m_buffer_current_allocation_offset; + return m_buffer_current_allocation_offset; } size_t D3DStreamBuffer::GetSize() const { - return m_buffer_size; + return m_buffer_size; } void* D3DStreamBuffer::GetBaseCPUAddress() const { - return m_buffer_cpu_address; + return m_buffer_cpu_address; } D3D12_GPU_VIRTUAL_ADDRESS D3DStreamBuffer::GetBaseGPUAddress() const { - return m_buffer_gpu_address; + return m_buffer_gpu_address; } - } \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D12/D3DStreamBuffer.h b/Source/Core/VideoBackends/D3D12/D3DStreamBuffer.h index 9aeb18468c..d07de47cfa 100644 --- a/Source/Core/VideoBackends/D3D12/D3DStreamBuffer.h +++ b/Source/Core/VideoBackends/D3D12/D3DStreamBuffer.h @@ -10,64 +10,62 @@ struct ID3D12Resource; namespace DX12 { - class D3DStreamBuffer { public: - D3DStreamBuffer(size_t initial_size, size_t max_size, bool* buffer_reallocation_notification); - ~D3DStreamBuffer(); + D3DStreamBuffer(size_t initial_size, size_t max_size, bool* buffer_reallocation_notification); + ~D3DStreamBuffer(); - bool AllocateSpaceInBuffer(size_t allocation_size, size_t alignment, bool allow_execute = true); - void OverrideSizeOfPreviousAllocation(size_t override_allocation_size); + bool AllocateSpaceInBuffer(size_t allocation_size, size_t alignment, bool allow_execute = true); + void OverrideSizeOfPreviousAllocation(size_t override_allocation_size); - void* GetBaseCPUAddress() const; - D3D12_GPU_VIRTUAL_ADDRESS GetBaseGPUAddress() const; - ID3D12Resource* GetBuffer() const; - void* GetCPUAddressOfCurrentAllocation() const; - D3D12_GPU_VIRTUAL_ADDRESS GetGPUAddressOfCurrentAllocation() const; - size_t GetOffsetOfCurrentAllocation() const; - size_t GetSize() const; + void* GetBaseCPUAddress() const; + D3D12_GPU_VIRTUAL_ADDRESS GetBaseGPUAddress() const; + ID3D12Resource* GetBuffer() const; + void* GetCPUAddressOfCurrentAllocation() const; + D3D12_GPU_VIRTUAL_ADDRESS GetGPUAddressOfCurrentAllocation() const; + size_t GetOffsetOfCurrentAllocation() const; + size_t GetSize() const; - static void QueueFenceCallback(void* owning_object, UINT64 fence_value); + static void QueueFenceCallback(void* owning_object, UINT64 fence_value); private: - void AllocateBuffer(size_t size); - bool AttemptBufferResizeOrElseStall(size_t allocation_size, bool allow_execute); + void AllocateBuffer(size_t size); + bool AttemptBufferResizeOrElseStall(size_t allocation_size, bool allow_execute); - bool AttemptToAllocateOutOfExistingUnusedSpaceInBuffer(size_t allocation_size); + bool AttemptToAllocateOutOfExistingUnusedSpaceInBuffer(size_t allocation_size); - bool AttemptToFindExistingFenceToStallOn(size_t allocation_size); + bool AttemptToFindExistingFenceToStallOn(size_t allocation_size); - void UpdateGPUProgress(); + void UpdateGPUProgress(); - void ClearFences(); - bool HasBufferOffsetChangedSinceLastFence() const; - void QueueFence(UINT64 fence_value); + void ClearFences(); + bool HasBufferOffsetChangedSinceLastFence() const; + void QueueFence(UINT64 fence_value); - struct FenceTrackingInformation - { - UINT64 fence_value; - size_t buffer_offset; - }; + struct FenceTrackingInformation + { + UINT64 fence_value; + size_t buffer_offset; + }; - std::queue m_queued_fences; + std::queue m_queued_fences; - ID3D12Fence* m_buffer_tracking_fence = nullptr; + ID3D12Fence* m_buffer_tracking_fence = nullptr; - ID3D12Resource* m_buffer = nullptr; + ID3D12Resource* m_buffer = nullptr; - void* m_buffer_cpu_address = nullptr; - D3D12_GPU_VIRTUAL_ADDRESS m_buffer_gpu_address = {}; + void* m_buffer_cpu_address = nullptr; + D3D12_GPU_VIRTUAL_ADDRESS m_buffer_gpu_address = {}; - size_t m_buffer_current_allocation_offset = 0; - size_t m_buffer_offset = 0; - size_t m_buffer_size = 0; + size_t m_buffer_current_allocation_offset = 0; + size_t m_buffer_offset = 0; + size_t m_buffer_size = 0; - const size_t m_buffer_max_size = 0; + const size_t m_buffer_max_size = 0; - size_t m_buffer_gpu_completion_offset = 0; + size_t m_buffer_gpu_completion_offset = 0; - bool* m_buffer_reallocation_notification = nullptr; + bool* m_buffer_reallocation_notification = nullptr; }; - } \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D12/D3DTexture.cpp b/Source/Core/VideoBackends/D3D12/D3DTexture.cpp index 9749a36a76..1d8146f1e6 100644 --- a/Source/Core/VideoBackends/D3D12/D3DTexture.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DTexture.cpp @@ -17,10 +17,8 @@ namespace DX12 { - namespace D3D { - constexpr size_t INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE = 4 * 1024 * 1024; constexpr size_t MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE = 64 * 1024 * 1024; @@ -28,272 +26,283 @@ static std::unique_ptr s_texture_upload_stream_buffer; void CleanupPersistentD3DTextureResources() { - s_texture_upload_stream_buffer.reset(); + s_texture_upload_stream_buffer.reset(); } -void ReplaceRGBATexture2D(ID3D12Resource* texture12, const u8* buffer, unsigned int width, unsigned int height, unsigned int src_pitch, unsigned int level, D3D12_RESOURCE_STATES current_resource_state) +void ReplaceRGBATexture2D(ID3D12Resource* texture12, const u8* buffer, unsigned int width, + unsigned int height, unsigned int src_pitch, unsigned int level, + D3D12_RESOURCE_STATES current_resource_state) { - const unsigned int upload_size = AlignValue(src_pitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * height; + const unsigned int upload_size = + AlignValue(src_pitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * height; - ID3D12Resource* upload_buffer = nullptr; - size_t upload_buffer_offset = 0; - u8* dest_data = nullptr; + ID3D12Resource* upload_buffer = nullptr; + size_t upload_buffer_offset = 0; + u8* dest_data = nullptr; - if (upload_size > MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE) - { - // If the texture is too large to fit in the upload buffer, create a temporary buffer instead. - // This will only be the case for large (e.g. 8192x8192) textures from custom texture packs. - CheckHR(D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Buffer(upload_size), - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, - IID_PPV_ARGS(&upload_buffer))); + if (upload_size > MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE) + { + // If the texture is too large to fit in the upload buffer, create a temporary buffer instead. + // This will only be the case for large (e.g. 8192x8192) textures from custom texture packs. + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer(upload_size), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, + IID_PPV_ARGS(&upload_buffer))); - D3D12_RANGE read_range = {}; - CheckHR(upload_buffer->Map(0, &read_range, reinterpret_cast(&dest_data))); - } - else - { - if (!s_texture_upload_stream_buffer) - s_texture_upload_stream_buffer = std::make_unique(INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE, MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE, nullptr); + D3D12_RANGE read_range = {}; + CheckHR(upload_buffer->Map(0, &read_range, reinterpret_cast(&dest_data))); + } + else + { + if (!s_texture_upload_stream_buffer) + s_texture_upload_stream_buffer = std::make_unique( + INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE, MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE, nullptr); - s_texture_upload_stream_buffer->AllocateSpaceInBuffer(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); + s_texture_upload_stream_buffer->AllocateSpaceInBuffer(upload_size, + D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); - upload_buffer = s_texture_upload_stream_buffer->GetBuffer(); - upload_buffer_offset = s_texture_upload_stream_buffer->GetOffsetOfCurrentAllocation(); - dest_data = reinterpret_cast(s_texture_upload_stream_buffer->GetCPUAddressOfCurrentAllocation()); - } + upload_buffer = s_texture_upload_stream_buffer->GetBuffer(); + upload_buffer_offset = s_texture_upload_stream_buffer->GetOffsetOfCurrentAllocation(); + dest_data = + reinterpret_cast(s_texture_upload_stream_buffer->GetCPUAddressOfCurrentAllocation()); + } - ResourceBarrier(current_command_list, texture12, current_resource_state, D3D12_RESOURCE_STATE_COPY_DEST, level); + ResourceBarrier(current_command_list, texture12, current_resource_state, + D3D12_RESOURCE_STATE_COPY_DEST, level); - D3D12_PLACED_SUBRESOURCE_FOOTPRINT upload_footprint = {}; - u32 upload_rows = 0; - u64 upload_row_size_in_bytes = 0; - u64 upload_total_bytes = 0; + D3D12_PLACED_SUBRESOURCE_FOOTPRINT upload_footprint = {}; + u32 upload_rows = 0; + u64 upload_row_size_in_bytes = 0; + u64 upload_total_bytes = 0; - D3D::device12->GetCopyableFootprints(&texture12->GetDesc(), level, 1, upload_buffer_offset, &upload_footprint, &upload_rows, &upload_row_size_in_bytes, &upload_total_bytes); + D3D::device12->GetCopyableFootprints(&texture12->GetDesc(), level, 1, upload_buffer_offset, + &upload_footprint, &upload_rows, &upload_row_size_in_bytes, + &upload_total_bytes); - const u8* src_data = reinterpret_cast(buffer); - for (u32 y = 0; y < upload_rows; ++y) - { - memcpy( - dest_data + upload_footprint.Footprint.RowPitch * y, - src_data + src_pitch * y, - upload_row_size_in_bytes - ); - } + const u8* src_data = reinterpret_cast(buffer); + for (u32 y = 0; y < upload_rows; ++y) + { + memcpy(dest_data + upload_footprint.Footprint.RowPitch * y, src_data + src_pitch * y, + upload_row_size_in_bytes); + } - D3D::current_command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(texture12, level), 0, 0, 0, &CD3DX12_TEXTURE_COPY_LOCATION(upload_buffer, upload_footprint), nullptr); + D3D::current_command_list->CopyTextureRegion( + &CD3DX12_TEXTURE_COPY_LOCATION(texture12, level), 0, 0, 0, + &CD3DX12_TEXTURE_COPY_LOCATION(upload_buffer, upload_footprint), nullptr); - ResourceBarrier(D3D::current_command_list, texture12, D3D12_RESOURCE_STATE_COPY_DEST, current_resource_state, level); + ResourceBarrier(D3D::current_command_list, texture12, D3D12_RESOURCE_STATE_COPY_DEST, + current_resource_state, level); - // Release temporary buffer after commands complete. - // We block here because otherwise if there was a large number of texture uploads, we may run out of memory. - if (!s_texture_upload_stream_buffer || upload_buffer != s_texture_upload_stream_buffer->GetBuffer()) - { - D3D12_RANGE write_range = { 0, upload_size }; - upload_buffer->Unmap(0, &write_range); + // Release temporary buffer after commands complete. + // We block here because otherwise if there was a large number of texture uploads, we may run out + // of memory. + if (!s_texture_upload_stream_buffer || + upload_buffer != s_texture_upload_stream_buffer->GetBuffer()) + { + D3D12_RANGE write_range = {0, upload_size}; + upload_buffer->Unmap(0, &write_range); - D3D::command_list_mgr->ExecuteQueuedWork(true); + D3D::command_list_mgr->ExecuteQueuedWork(true); - upload_buffer->Release(); - } + upload_buffer->Release(); + } } } // namespace -D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, u32 bind, DXGI_FORMAT fmt, unsigned int levels, unsigned int slices, D3D12_SUBRESOURCE_DATA* data) +D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, u32 bind, + DXGI_FORMAT fmt, unsigned int levels, unsigned int slices, + D3D12_SUBRESOURCE_DATA* data) { - ID3D12Resource* texture12 = nullptr; + ID3D12Resource* texture12 = nullptr; - D3D12_RESOURCE_DESC texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D( - fmt, - width, - height, - slices, - levels - ); + D3D12_RESOURCE_DESC texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(fmt, width, height, slices, levels); - D3D12_CLEAR_VALUE optimized_clear_value = {}; - optimized_clear_value.Format = fmt; + D3D12_CLEAR_VALUE optimized_clear_value = {}; + optimized_clear_value.Format = fmt; - if (bind & TEXTURE_BIND_FLAG_RENDER_TARGET) - { - texdesc12.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; - optimized_clear_value.Color[0] = 0.0f; - optimized_clear_value.Color[1] = 0.0f; - optimized_clear_value.Color[2] = 0.0f; - optimized_clear_value.Color[3] = 1.0f; - } + if (bind & TEXTURE_BIND_FLAG_RENDER_TARGET) + { + texdesc12.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + optimized_clear_value.Color[0] = 0.0f; + optimized_clear_value.Color[1] = 0.0f; + optimized_clear_value.Color[2] = 0.0f; + optimized_clear_value.Color[3] = 1.0f; + } - if (bind & TEXTURE_BIND_FLAG_DEPTH_STENCIL) - { - texdesc12.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; - optimized_clear_value.DepthStencil.Depth = 0.0f; - optimized_clear_value.DepthStencil.Stencil = 0; - } + if (bind & TEXTURE_BIND_FLAG_DEPTH_STENCIL) + { + texdesc12.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + optimized_clear_value.DepthStencil.Depth = 0.0f; + optimized_clear_value.DepthStencil.Stencil = 0; + } - CheckHR( - D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC(texdesc12), - D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, - &optimized_clear_value, - IID_PPV_ARGS(&texture12) - ) - ); + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC(texdesc12), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + &optimized_clear_value, IID_PPV_ARGS(&texture12))); - D3D::SetDebugObjectName12(texture12, "Texture created via D3DTexture2D::Create"); - D3DTexture2D* ret = new D3DTexture2D(texture12, bind, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, false, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + D3D::SetDebugObjectName12(texture12, "Texture created via D3DTexture2D::Create"); + D3DTexture2D* ret = + new D3DTexture2D(texture12, bind, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, false, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - if (data) - { - DX12::D3D::ReplaceRGBATexture2D(texture12, reinterpret_cast(data->pData), width, height, static_cast(data->RowPitch), 0, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - } + if (data) + { + DX12::D3D::ReplaceRGBATexture2D(texture12, reinterpret_cast(data->pData), width, + height, static_cast(data->RowPitch), 0, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + } - SAFE_RELEASE(texture12); - return ret; + SAFE_RELEASE(texture12); + return ret; } void D3DTexture2D::AddRef() { - m_ref.fetch_add(1); + m_ref.fetch_add(1); } UINT D3DTexture2D::Release() { - // fetch_sub returns the value held before the subtraction. - if (m_ref.fetch_sub(1) == 1) - { - delete this; - return 0; - } - return m_ref.load(); + // fetch_sub returns the value held before the subtraction. + if (m_ref.fetch_sub(1) == 1) + { + delete this; + return 0; + } + return m_ref.load(); } D3D12_RESOURCE_STATES D3DTexture2D::GetResourceUsageState() const { - return m_resource_state; + return m_resource_state; } bool D3DTexture2D::GetMultisampled() const { - return m_multisampled; + return m_multisampled; } ID3D12Resource* D3DTexture2D::GetTex12() const { - return m_tex12; + return m_tex12; } D3D12_CPU_DESCRIPTOR_HANDLE D3DTexture2D::GetSRV12CPU() const { - return m_srv12_cpu; + return m_srv12_cpu; } D3D12_GPU_DESCRIPTOR_HANDLE D3DTexture2D::GetSRV12GPU() const { - return m_srv12_gpu; + return m_srv12_gpu; } D3D12_CPU_DESCRIPTOR_HANDLE D3DTexture2D::GetSRV12GPUCPUShadow() const { - return m_srv12_gpu_cpu_shadow; + return m_srv12_gpu_cpu_shadow; } D3D12_CPU_DESCRIPTOR_HANDLE D3DTexture2D::GetDSV12() const { - return m_dsv12; + return m_dsv12; } D3D12_CPU_DESCRIPTOR_HANDLE D3DTexture2D::GetRTV12() const { - return m_rtv12; + return m_rtv12; } -D3DTexture2D::D3DTexture2D(ID3D12Resource* texptr, u32 bind, - DXGI_FORMAT srv_format, DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format, bool multisampled, D3D12_RESOURCE_STATES resource_state) - : m_tex12(texptr), m_resource_state(resource_state), m_multisampled(multisampled) +D3DTexture2D::D3DTexture2D(ID3D12Resource* texptr, u32 bind, DXGI_FORMAT srv_format, + DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format, bool multisampled, + D3D12_RESOURCE_STATES resource_state) + : m_tex12(texptr), m_resource_state(resource_state), m_multisampled(multisampled) { - D3D12_SRV_DIMENSION srv_dim12 = multisampled ? D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY : D3D12_SRV_DIMENSION_TEXTURE2DARRAY; - D3D12_DSV_DIMENSION dsv_dim12 = multisampled ? D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D12_DSV_DIMENSION_TEXTURE2DARRAY; - D3D12_RTV_DIMENSION rtv_dim12 = multisampled ? D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D12_RTV_DIMENSION_TEXTURE2DARRAY; + D3D12_SRV_DIMENSION srv_dim12 = + multisampled ? D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY : D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + D3D12_DSV_DIMENSION dsv_dim12 = + multisampled ? D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D12_DSV_DIMENSION_TEXTURE2DARRAY; + D3D12_RTV_DIMENSION rtv_dim12 = + multisampled ? D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D12_RTV_DIMENSION_TEXTURE2DARRAY; - if (bind & TEXTURE_BIND_FLAG_SHADER_RESOURCE) - { - D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = { - srv_format, // DXGI_FORMAT Format - srv_dim12 // D3D12_SRV_DIMENSION ViewDimension - }; + if (bind & TEXTURE_BIND_FLAG_SHADER_RESOURCE) + { + D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = { + srv_format, // DXGI_FORMAT Format + srv_dim12 // D3D12_SRV_DIMENSION ViewDimension + }; - if (srv_dim12 == D3D12_SRV_DIMENSION_TEXTURE2DARRAY) - { - srv_desc.Texture2DArray.MipLevels = -1; - srv_desc.Texture2DArray.MostDetailedMip = 0; - srv_desc.Texture2DArray.ResourceMinLODClamp = 0; - srv_desc.Texture2DArray.ArraySize = -1; - } - else - { - srv_desc.Texture2DMSArray.ArraySize = -1; - } + if (srv_dim12 == D3D12_SRV_DIMENSION_TEXTURE2DARRAY) + { + srv_desc.Texture2DArray.MipLevels = -1; + srv_desc.Texture2DArray.MostDetailedMip = 0; + srv_desc.Texture2DArray.ResourceMinLODClamp = 0; + srv_desc.Texture2DArray.ArraySize = -1; + } + else + { + srv_desc.Texture2DMSArray.ArraySize = -1; + } - srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - CHECK(D3D::gpu_descriptor_heap_mgr->Allocate(&m_srv12_cpu, &m_srv12_gpu, &m_srv12_gpu_cpu_shadow), "Error: Ran out of permenant slots in GPU descriptor heap, but don't support rolling over heap."); + CHECK( + D3D::gpu_descriptor_heap_mgr->Allocate(&m_srv12_cpu, &m_srv12_gpu, &m_srv12_gpu_cpu_shadow), + "Error: Ran out of permenant slots in GPU descriptor heap, but don't support rolling over " + "heap."); - D3D::device12->CreateShaderResourceView(m_tex12, &srv_desc, m_srv12_cpu); - D3D::device12->CreateShaderResourceView(m_tex12, &srv_desc, m_srv12_gpu_cpu_shadow); - } + D3D::device12->CreateShaderResourceView(m_tex12, &srv_desc, m_srv12_cpu); + D3D::device12->CreateShaderResourceView(m_tex12, &srv_desc, m_srv12_gpu_cpu_shadow); + } - if (bind & TEXTURE_BIND_FLAG_DEPTH_STENCIL) - { - D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = { - dsv_format, // DXGI_FORMAT Format - dsv_dim12, // D3D12_DSV_DIMENSION - D3D12_DSV_FLAG_NONE // D3D12_DSV_FLAG Flags - }; + if (bind & TEXTURE_BIND_FLAG_DEPTH_STENCIL) + { + D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = { + dsv_format, // DXGI_FORMAT Format + dsv_dim12, // D3D12_DSV_DIMENSION + D3D12_DSV_FLAG_NONE // D3D12_DSV_FLAG Flags + }; - if (dsv_dim12 == D3D12_DSV_DIMENSION_TEXTURE2DARRAY) - dsv_desc.Texture2DArray.ArraySize = -1; - else - dsv_desc.Texture2DMSArray.ArraySize = -1; + if (dsv_dim12 == D3D12_DSV_DIMENSION_TEXTURE2DARRAY) + dsv_desc.Texture2DArray.ArraySize = -1; + else + dsv_desc.Texture2DMSArray.ArraySize = -1; - D3D::dsv_descriptor_heap_mgr->Allocate(&m_dsv12); - D3D::device12->CreateDepthStencilView(m_tex12, &dsv_desc, m_dsv12); - } + D3D::dsv_descriptor_heap_mgr->Allocate(&m_dsv12); + D3D::device12->CreateDepthStencilView(m_tex12, &dsv_desc, m_dsv12); + } - if (bind & TEXTURE_BIND_FLAG_RENDER_TARGET) - { - D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = { - rtv_format, // DXGI_FORMAT Format - rtv_dim12 // D3D12_RTV_DIMENSION ViewDimension - }; + if (bind & TEXTURE_BIND_FLAG_RENDER_TARGET) + { + D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = { + rtv_format, // DXGI_FORMAT Format + rtv_dim12 // D3D12_RTV_DIMENSION ViewDimension + }; - if (rtv_dim12 == D3D12_RTV_DIMENSION_TEXTURE2DARRAY) - rtv_desc.Texture2DArray.ArraySize = -1; - else - rtv_desc.Texture2DMSArray.ArraySize = -1; + if (rtv_dim12 == D3D12_RTV_DIMENSION_TEXTURE2DARRAY) + rtv_desc.Texture2DArray.ArraySize = -1; + else + rtv_desc.Texture2DMSArray.ArraySize = -1; - D3D::rtv_descriptor_heap_mgr->Allocate(&m_rtv12); - D3D::device12->CreateRenderTargetView(m_tex12, &rtv_desc, m_rtv12); - } + D3D::rtv_descriptor_heap_mgr->Allocate(&m_rtv12); + D3D::device12->CreateRenderTargetView(m_tex12, &rtv_desc, m_rtv12); + } - m_tex12->AddRef(); + m_tex12->AddRef(); } -void D3DTexture2D::TransitionToResourceState(ID3D12GraphicsCommandList* command_list, D3D12_RESOURCE_STATES state_after) +void D3DTexture2D::TransitionToResourceState(ID3D12GraphicsCommandList* command_list, + D3D12_RESOURCE_STATES state_after) { - DX12::D3D::ResourceBarrier(command_list, m_tex12, m_resource_state, state_after, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES); - m_resource_state = state_after; + DX12::D3D::ResourceBarrier(command_list, m_tex12, m_resource_state, state_after, + D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES); + m_resource_state = state_after; } D3DTexture2D::~D3DTexture2D() { - DX12::D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_tex12); + DX12::D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_tex12); } } // namespace DX12 diff --git a/Source/Core/VideoBackends/D3D12/D3DTexture.h b/Source/Core/VideoBackends/D3D12/D3DTexture.h index 8f58d84692..7b369f07e5 100644 --- a/Source/Core/VideoBackends/D3D12/D3DTexture.h +++ b/Source/Core/VideoBackends/D3D12/D3DTexture.h @@ -8,65 +8,74 @@ namespace DX12 { - enum TEXTURE_BIND_FLAG : u32 { - TEXTURE_BIND_FLAG_SHADER_RESOURCE = (1 << 0), - TEXTURE_BIND_FLAG_RENDER_TARGET = (1 << 1), - TEXTURE_BIND_FLAG_DEPTH_STENCIL = (1 << 2) + TEXTURE_BIND_FLAG_SHADER_RESOURCE = (1 << 0), + TEXTURE_BIND_FLAG_RENDER_TARGET = (1 << 1), + TEXTURE_BIND_FLAG_DEPTH_STENCIL = (1 << 2) }; namespace D3D { - void ReplaceRGBATexture2D(ID3D12Resource* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int src_pitch, unsigned int level, D3D12_RESOURCE_STATES current_resource_state = D3D12_RESOURCE_STATE_COMMON); - void CleanupPersistentD3DTextureResources(); +void ReplaceRGBATexture2D( + ID3D12Resource* pTexture, const u8* buffer, unsigned int width, unsigned int height, + unsigned int src_pitch, unsigned int level, + D3D12_RESOURCE_STATES current_resource_state = D3D12_RESOURCE_STATE_COMMON); +void CleanupPersistentD3DTextureResources(); } class D3DTexture2D { - public: - // there are two ways to create a D3DTexture2D object: - // either create an ID3D12Resource object, pass it to the constructor and specify what views to create - // or let the texture automatically be created by D3DTexture2D::Create + // there are two ways to create a D3DTexture2D object: + // either create an ID3D12Resource object, pass it to the constructor and specify what views + // to create + // or let the texture automatically be created by D3DTexture2D::Create - D3DTexture2D(ID3D12Resource* texptr, u32 bind, DXGI_FORMAT srv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN, bool multisampled = false, D3D12_RESOURCE_STATES resource_state = D3D12_RESOURCE_STATE_COMMON); - static D3DTexture2D* Create(unsigned int width, unsigned int height, u32 bind, DXGI_FORMAT fmt, unsigned int levels = 1, unsigned int slices = 1, D3D12_SUBRESOURCE_DATA* data = nullptr); - void TransitionToResourceState(ID3D12GraphicsCommandList* command_list, D3D12_RESOURCE_STATES state_after); + D3DTexture2D(ID3D12Resource* texptr, u32 bind, DXGI_FORMAT srv_format = DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN, bool multisampled = false, + D3D12_RESOURCE_STATES resource_state = D3D12_RESOURCE_STATE_COMMON); + static D3DTexture2D* Create(unsigned int width, unsigned int height, u32 bind, DXGI_FORMAT fmt, + unsigned int levels = 1, unsigned int slices = 1, + D3D12_SUBRESOURCE_DATA* data = nullptr); + void TransitionToResourceState(ID3D12GraphicsCommandList* command_list, + D3D12_RESOURCE_STATES state_after); - // reference counting, use AddRef() when creating a new reference and Release() it when you don't need it anymore - void AddRef(); - UINT Release(); + // reference counting, use AddRef() when creating a new reference and Release() it when you don't + // need it anymore + void AddRef(); + UINT Release(); - ID3D12Resource* GetTex12() const; + ID3D12Resource* GetTex12() const; - D3D12_CPU_DESCRIPTOR_HANDLE GetSRV12CPU() const; - D3D12_GPU_DESCRIPTOR_HANDLE GetSRV12GPU() const; - D3D12_CPU_DESCRIPTOR_HANDLE GetSRV12GPUCPUShadow() const; - D3D12_CPU_DESCRIPTOR_HANDLE GetDSV12() const; - D3D12_CPU_DESCRIPTOR_HANDLE GetRTV12() const; + D3D12_CPU_DESCRIPTOR_HANDLE GetSRV12CPU() const; + D3D12_GPU_DESCRIPTOR_HANDLE GetSRV12GPU() const; + D3D12_CPU_DESCRIPTOR_HANDLE GetSRV12GPUCPUShadow() const; + D3D12_CPU_DESCRIPTOR_HANDLE GetDSV12() const; + D3D12_CPU_DESCRIPTOR_HANDLE GetRTV12() const; - D3D12_RESOURCE_STATES GetResourceUsageState() const; + D3D12_RESOURCE_STATES GetResourceUsageState() const; - bool GetMultisampled() const; + bool GetMultisampled() const; private: - ~D3DTexture2D(); + ~D3DTexture2D(); - ID3D12Resource* m_tex12 = nullptr; + ID3D12Resource* m_tex12 = nullptr; - D3D12_CPU_DESCRIPTOR_HANDLE m_srv12_cpu = {}; - D3D12_GPU_DESCRIPTOR_HANDLE m_srv12_gpu = {}; - D3D12_CPU_DESCRIPTOR_HANDLE m_srv12_gpu_cpu_shadow = {}; + D3D12_CPU_DESCRIPTOR_HANDLE m_srv12_cpu = {}; + D3D12_GPU_DESCRIPTOR_HANDLE m_srv12_gpu = {}; + D3D12_CPU_DESCRIPTOR_HANDLE m_srv12_gpu_cpu_shadow = {}; - D3D12_CPU_DESCRIPTOR_HANDLE m_dsv12 = {}; - D3D12_CPU_DESCRIPTOR_HANDLE m_rtv12 = {}; + D3D12_CPU_DESCRIPTOR_HANDLE m_dsv12 = {}; + D3D12_CPU_DESCRIPTOR_HANDLE m_rtv12 = {}; - D3D12_RESOURCE_STATES m_resource_state = D3D12_RESOURCE_STATE_COMMON; + D3D12_RESOURCE_STATES m_resource_state = D3D12_RESOURCE_STATE_COMMON; - bool m_multisampled = false; + bool m_multisampled = false; - std::atomic m_ref = 1; + std::atomic m_ref = 1; }; } // namespace DX12 diff --git a/Source/Core/VideoBackends/D3D12/D3DUtil.cpp b/Source/Core/VideoBackends/D3D12/D3DUtil.cpp index bf58b084b3..61e39d376a 100644 --- a/Source/Core/VideoBackends/D3D12/D3DUtil.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DUtil.cpp @@ -22,79 +22,70 @@ namespace DX12 { - namespace D3D { - -void ResourceBarrier(ID3D12GraphicsCommandList* command_list, ID3D12Resource* resource, D3D12_RESOURCE_STATES state_before, D3D12_RESOURCE_STATES state_after, UINT subresource) +void ResourceBarrier(ID3D12GraphicsCommandList* command_list, ID3D12Resource* resource, + D3D12_RESOURCE_STATES state_before, D3D12_RESOURCE_STATES state_after, + UINT subresource) { - if (state_before == state_after) - return; + if (state_before == state_after) + return; - CHECK(resource, "NULL resource passed to ResourceBarrier."); + CHECK(resource, "NULL resource passed to ResourceBarrier."); - D3D12_RESOURCE_BARRIER resourceBarrierDesc = { - D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, // D3D12_RESOURCE_TRANSITION_BARRIER_DESC Transition - D3D12_RESOURCE_BARRIER_FLAG_NONE, // D3D12_RESOURCE_BARRIER_FLAGS Flags + D3D12_RESOURCE_BARRIER resourceBarrierDesc = { + D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, // D3D12_RESOURCE_TRANSITION_BARRIER_DESC Transition + D3D12_RESOURCE_BARRIER_FLAG_NONE, // D3D12_RESOURCE_BARRIER_FLAGS Flags - // D3D12_RESOURCE_TRANSITION_BARRIER_DESC Transition - { - resource, // ID3D12Resource *pResource; - subresource, // UINT Subresource; - state_before, // UINT StateBefore; - state_after // UINT StateAfter; - } - }; + // D3D12_RESOURCE_TRANSITION_BARRIER_DESC Transition + { + resource, // ID3D12Resource *pResource; + subresource, // UINT Subresource; + state_before, // UINT StateBefore; + state_after // UINT StateAfter; + }}; - command_list->ResourceBarrier(1, &resourceBarrierDesc); + command_list->ResourceBarrier(1, &resourceBarrierDesc); } // Ring buffer class, shared between the draw* functions class UtilVertexBuffer { public: - explicit UtilVertexBuffer(size_t size) - { - m_stream_buffer = std::make_unique(size, size * 4, nullptr); - } + explicit UtilVertexBuffer(size_t size) + { + m_stream_buffer = std::make_unique(size, size * 4, nullptr); + } - ~UtilVertexBuffer() - { - } + ~UtilVertexBuffer() {} + size_t GetSize() const { return m_stream_buffer->GetSize(); } + // returns vertex offset to the new data + size_t AppendData(const void* data, size_t size, size_t vertex_size) + { + m_stream_buffer->AllocateSpaceInBuffer(size, vertex_size, false); - size_t GetSize() const { return m_stream_buffer->GetSize(); } + memcpy(static_cast(m_stream_buffer->GetCPUAddressOfCurrentAllocation()), data, size); - // returns vertex offset to the new data - size_t AppendData(const void* data, size_t size, size_t vertex_size) - { - m_stream_buffer->AllocateSpaceInBuffer(size, vertex_size, false); + return m_stream_buffer->GetOffsetOfCurrentAllocation() / vertex_size; + } - memcpy(static_cast(m_stream_buffer->GetCPUAddressOfCurrentAllocation()), data, size); + size_t BeginAppendData(void** write_ptr, size_t size, size_t vertex_size) + { + m_stream_buffer->AllocateSpaceInBuffer(size, vertex_size, false); - return m_stream_buffer->GetOffsetOfCurrentAllocation() / vertex_size; - } + *write_ptr = m_stream_buffer->GetCPUAddressOfCurrentAllocation(); - size_t BeginAppendData(void** write_ptr, size_t size, size_t vertex_size) - { - m_stream_buffer->AllocateSpaceInBuffer(size, vertex_size, false); + return m_stream_buffer->GetOffsetOfCurrentAllocation() / vertex_size; + } - *write_ptr = m_stream_buffer->GetCPUAddressOfCurrentAllocation(); - - return m_stream_buffer->GetOffsetOfCurrentAllocation() / vertex_size; - } - - void EndAppendData() - { - // No-op on DX12. - } - - ID3D12Resource* GetBuffer12() - { - return m_stream_buffer->GetBuffer(); - } + void EndAppendData() + { + // No-op on DX12. + } + ID3D12Resource* GetBuffer12() { return m_stream_buffer->GetBuffer(); } private: - std::unique_ptr m_stream_buffer; + std::unique_ptr m_stream_buffer; }; CD3DFont font; @@ -106,19 +97,24 @@ static const unsigned int s_max_num_vertices = 8000 * 6; struct FONT2DVERTEX { - float x, y, z; - float col[4]; - float tu, tv; + float x, y, z; + float col[4]; + float tu, tv; }; FONT2DVERTEX InitFont2DVertex(float x, float y, u32 color, float tu, float tv) { - FONT2DVERTEX v; v.x=x; v.y=y; v.z=0; v.tu = tu; v.tv = tv; - v.col[0] = (static_cast((color >> 16) & 0xFF)) / 255.f; - v.col[1] = (static_cast((color >> 8) & 0xFF)) / 255.f; - v.col[2] = (static_cast((color >> 0) & 0xFF)) / 255.f; - v.col[3] = (static_cast((color >> 24) & 0xFF)) / 255.f; - return v; + FONT2DVERTEX v; + v.x = x; + v.y = y; + v.z = 0; + v.tu = tu; + v.tv = tv; + v.col[0] = (static_cast((color >> 16) & 0xFF)) / 255.f; + v.col[1] = (static_cast((color >> 8) & 0xFF)) / 255.f; + v.col[2] = (static_cast((color >> 0) & 0xFF)) / 255.f; + v.col[3] = (static_cast((color >> 24) & 0xFF)) / 255.f; + return v; } CD3DFont::CD3DFont() @@ -126,348 +122,351 @@ CD3DFont::CD3DFont() } constexpr const char fontpixshader[] = { - "Texture2D tex2D;\n" - "SamplerState linearSampler\n" - "{\n" - " Filter = MIN_MAG_MIP_LINEAR;\n" - " AddressU = D3D11_TEXTURE_ADDRESS_BORDER;\n" - " AddressV = D3D11_TEXTURE_ADDRESS_BORDER;\n" - " BorderColor = float4(0.f, 0.f, 0.f, 0.f);\n" - "};\n" - "struct PS_INPUT\n" - "{\n" - " float4 pos : SV_POSITION;\n" - " float4 col : COLOR;\n" - " float2 tex : TEXCOORD;\n" - "};\n" - "float4 main( PS_INPUT input ) : SV_Target\n" - "{\n" - " return tex2D.Sample( linearSampler, input.tex ) * input.col;\n" - "};\n" -}; + "Texture2D tex2D;\n" + "SamplerState linearSampler\n" + "{\n" + " Filter = MIN_MAG_MIP_LINEAR;\n" + " AddressU = D3D11_TEXTURE_ADDRESS_BORDER;\n" + " AddressV = D3D11_TEXTURE_ADDRESS_BORDER;\n" + " BorderColor = float4(0.f, 0.f, 0.f, 0.f);\n" + "};\n" + "struct PS_INPUT\n" + "{\n" + " float4 pos : SV_POSITION;\n" + " float4 col : COLOR;\n" + " float2 tex : TEXCOORD;\n" + "};\n" + "float4 main( PS_INPUT input ) : SV_Target\n" + "{\n" + " return tex2D.Sample( linearSampler, input.tex ) * input.col;\n" + "};\n"}; -constexpr const char fontvertshader[] = { - "struct VS_INPUT\n" - "{\n" - " float4 pos : POSITION;\n" - " float4 col : COLOR;\n" - " float2 tex : TEXCOORD;\n" - "};\n" - "struct PS_INPUT\n" - "{\n" - " float4 pos : SV_POSITION;\n" - " float4 col : COLOR;\n" - " float2 tex : TEXCOORD;\n" - "};\n" - "PS_INPUT main( VS_INPUT input )\n" - "{\n" - " PS_INPUT output;\n" - " output.pos = input.pos;\n" - " output.col = input.col;\n" - " output.tex = input.tex;\n" - " return output;\n" - "};\n" -}; +constexpr const char fontvertshader[] = {"struct VS_INPUT\n" + "{\n" + " float4 pos : POSITION;\n" + " float4 col : COLOR;\n" + " float2 tex : TEXCOORD;\n" + "};\n" + "struct PS_INPUT\n" + "{\n" + " float4 pos : SV_POSITION;\n" + " float4 col : COLOR;\n" + " float2 tex : TEXCOORD;\n" + "};\n" + "PS_INPUT main( VS_INPUT input )\n" + "{\n" + " PS_INPUT output;\n" + " output.pos = input.pos;\n" + " output.col = input.col;\n" + " output.tex = input.tex;\n" + " return output;\n" + "};\n"}; int CD3DFont::Init() { - // Create vertex buffer for the letters + // Create vertex buffer for the letters - // Prepare to create a bitmap - unsigned int* bitmap_bits; - BITMAPINFO bmi; - ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = static_cast(m_tex_width); - bmi.bmiHeader.biHeight = -static_cast(m_tex_height); - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biBitCount = 32; + // Prepare to create a bitmap + unsigned int* bitmap_bits; + BITMAPINFO bmi; + ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = static_cast(m_tex_width); + bmi.bmiHeader.biHeight = -static_cast(m_tex_height); + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biBitCount = 32; - // Create a DC and a bitmap for the font - HDC hDC = CreateCompatibleDC(nullptr); - HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, reinterpret_cast(&bitmap_bits), nullptr, 0); - SetMapMode(hDC, MM_TEXT); + // Create a DC and a bitmap for the font + HDC hDC = CreateCompatibleDC(nullptr); + HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, + reinterpret_cast(&bitmap_bits), nullptr, 0); + SetMapMode(hDC, MM_TEXT); - // create a GDI font - HFONT hFont = CreateFont(24, 0, 0, 0, FW_NORMAL, FALSE, - FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, PROOF_QUALITY, - VARIABLE_PITCH, _T("Tahoma")); + // create a GDI font + HFONT hFont = + CreateFont(24, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH, _T("Tahoma")); - if (nullptr == hFont) - return E_FAIL; + if (nullptr == hFont) + return E_FAIL; - HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap); - HGDIOBJ hOldFont = SelectObject(hDC, hFont); + HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap); + HGDIOBJ hOldFont = SelectObject(hDC, hFont); - // Set text properties - SetTextColor(hDC, 0xFFFFFF); - SetBkColor (hDC, 0); - SetTextAlign(hDC, TA_TOP); + // Set text properties + SetTextColor(hDC, 0xFFFFFF); + SetBkColor(hDC, 0); + SetTextAlign(hDC, TA_TOP); - TEXTMETRICW tm; - GetTextMetricsW(hDC, &tm); - m_line_height = tm.tmHeight; + TEXTMETRICW tm; + GetTextMetricsW(hDC, &tm); + m_line_height = tm.tmHeight; - // Loop through all printable characters and output them to the bitmap - // Meanwhile, keep track of the corresponding tex coords for each character. - int x = 0, y = 0; - char str[2] = "\0"; - for (int c = 0; c < 127 - 32; c++) - { - str[0] = c + 32; - SIZE size; - GetTextExtentPoint32A(hDC, str, 1, &size); - if (static_cast(x + size.cx + 1) > m_tex_width) - { - x = 0; - y += m_line_height; - } + // Loop through all printable characters and output them to the bitmap + // Meanwhile, keep track of the corresponding tex coords for each character. + int x = 0, y = 0; + char str[2] = "\0"; + for (int c = 0; c < 127 - 32; c++) + { + str[0] = c + 32; + SIZE size; + GetTextExtentPoint32A(hDC, str, 1, &size); + if (static_cast(x + size.cx + 1) > m_tex_width) + { + x = 0; + y += m_line_height; + } - ExtTextOutA(hDC, x+1, y+0, ETO_OPAQUE | ETO_CLIPPED, nullptr, str, 1, nullptr); - m_tex_coords[c][0] = (static_cast(x + 0))/m_tex_width; - m_tex_coords[c][1] = (static_cast(y + 0))/m_tex_height; - m_tex_coords[c][2] = (static_cast(x + 0 + size.cx))/m_tex_width; - m_tex_coords[c][3] = (static_cast(y + 0 + size.cy))/m_tex_height; + ExtTextOutA(hDC, x + 1, y + 0, ETO_OPAQUE | ETO_CLIPPED, nullptr, str, 1, nullptr); + m_tex_coords[c][0] = (static_cast(x + 0)) / m_tex_width; + m_tex_coords[c][1] = (static_cast(y + 0)) / m_tex_height; + m_tex_coords[c][2] = (static_cast(x + 0 + size.cx)) / m_tex_width; + m_tex_coords[c][3] = (static_cast(y + 0 + size.cy)) / m_tex_height; - x += size.cx + 3; // 3 to work around annoying ij conflict (part of the j ends up with the i) - } + x += size.cx + 3; // 3 to work around annoying ij conflict (part of the j ends up with the i) + } - // Create a new texture for the font - // possible optimization: store the converted data in a buffer and fill the texture on creation. - // That way, we can use a static texture - std::unique_ptr tex_initial_data(new byte[m_tex_width * m_tex_height * 4]); + // Create a new texture for the font + // possible optimization: store the converted data in a buffer and fill the texture on creation. + // That way, we can use a static texture + std::unique_ptr tex_initial_data(new byte[m_tex_width * m_tex_height * 4]); - for (y = 0; y < m_tex_height; y++) - { - u32* pDst32 = reinterpret_cast(static_cast(tex_initial_data.get()) + y * m_tex_width * 4); - for (x = 0; x < m_tex_width; x++) - { - const u8 bAlpha = (bitmap_bits[m_tex_width * y + x] & 0xff); + for (y = 0; y < m_tex_height; y++) + { + u32* pDst32 = + reinterpret_cast(static_cast(tex_initial_data.get()) + y * m_tex_width * 4); + for (x = 0; x < m_tex_width; x++) + { + const u8 bAlpha = (bitmap_bits[m_tex_width * y + x] & 0xff); - *pDst32++ = (((bAlpha << 4) | bAlpha) << 24) | 0xFFFFFF; - } - } + *pDst32++ = (((bAlpha << 4) | bAlpha) << 24) | 0xFFFFFF; + } + } - CheckHR( - D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, m_tex_width, m_tex_height, 1, 1), - D3D12_RESOURCE_STATE_COMMON, - nullptr, - IID_PPV_ARGS(&m_texture12) - ) - ); + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, m_tex_width, m_tex_height, 1, 1), + D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&m_texture12))); - D3D::SetDebugObjectName12(m_texture12, "texture of a CD3DFont object"); + D3D::SetDebugObjectName12(m_texture12, "texture of a CD3DFont object"); - ID3D12Resource* temporaryFontTextureUploadBuffer; - CheckHR( - D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Buffer(AlignValue(m_tex_width * 4, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * m_tex_height), - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, - IID_PPV_ARGS(&temporaryFontTextureUploadBuffer) - ) - ); + ID3D12Resource* temporaryFontTextureUploadBuffer; + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer( + AlignValue(m_tex_width * 4, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * m_tex_height), + D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&temporaryFontTextureUploadBuffer))); - D3D12_SUBRESOURCE_DATA subresource_data_dest = { - tex_initial_data.get(), // const void *pData; - m_tex_width * 4, // LONG_PTR RowPitch; - 0 // LONG_PTR SlicePitch; - }; + D3D12_SUBRESOURCE_DATA subresource_data_dest = { + tex_initial_data.get(), // const void *pData; + m_tex_width * 4, // LONG_PTR RowPitch; + 0 // LONG_PTR SlicePitch; + }; - D3D::ResourceBarrier(D3D::current_command_list, m_texture12, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES); + D3D::ResourceBarrier(D3D::current_command_list, m_texture12, D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES); - CHECK(0 != UpdateSubresources(D3D::current_command_list, m_texture12, temporaryFontTextureUploadBuffer, 0, 0, 1, &subresource_data_dest), "UpdateSubresources call failed."); + CHECK(0 != UpdateSubresources(D3D::current_command_list, m_texture12, + temporaryFontTextureUploadBuffer, 0, 0, 1, &subresource_data_dest), + "UpdateSubresources call failed."); - command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(temporaryFontTextureUploadBuffer); + command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted( + temporaryFontTextureUploadBuffer); - tex_initial_data.release(); + tex_initial_data.release(); - D3D::gpu_descriptor_heap_mgr->Allocate(&m_texture12_cpu, &m_texture12_gpu); + D3D::gpu_descriptor_heap_mgr->Allocate(&m_texture12_cpu, &m_texture12_gpu); - D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {}; - srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; - srv_desc.Texture2D.MipLevels = -1; + D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {}; + srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srv_desc.Texture2D.MipLevels = -1; - D3D::device12->CreateShaderResourceView(m_texture12, &srv_desc, m_texture12_cpu); + D3D::device12->CreateShaderResourceView(m_texture12, &srv_desc, m_texture12_cpu); - D3D::ResourceBarrier(D3D::current_command_list, m_texture12, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES); + D3D::ResourceBarrier(D3D::current_command_list, m_texture12, D3D12_RESOURCE_STATE_COPY_DEST, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES); - SelectObject(hDC, hOldbmBitmap); - DeleteObject(hbmBitmap); + SelectObject(hDC, hOldbmBitmap); + DeleteObject(hbmBitmap); - SelectObject(hDC, hOldFont); - DeleteObject(hFont); + SelectObject(hDC, hOldFont); + DeleteObject(hFont); - // setup device objects for drawing - ID3DBlob* psbytecode = nullptr; - D3D::CompilePixelShader(fontpixshader, &psbytecode); - if (psbytecode == nullptr) - PanicAlert("Failed to compile pixel shader, %s %d\n", __FILE__, __LINE__); + // setup device objects for drawing + ID3DBlob* psbytecode = nullptr; + D3D::CompilePixelShader(fontpixshader, &psbytecode); + if (psbytecode == nullptr) + PanicAlert("Failed to compile pixel shader, %s %d\n", __FILE__, __LINE__); - m_pshader12.pShaderBytecode = psbytecode->GetBufferPointer(); - m_pshader12.BytecodeLength = psbytecode->GetBufferSize(); + m_pshader12.pShaderBytecode = psbytecode->GetBufferPointer(); + m_pshader12.BytecodeLength = psbytecode->GetBufferSize(); - ID3DBlob* vsbytecode = nullptr; - D3D::CompileVertexShader(fontvertshader, &vsbytecode); - if (vsbytecode == nullptr) - PanicAlert("Failed to compile vertex shader, %s %d\n", __FILE__, __LINE__); + ID3DBlob* vsbytecode = nullptr; + D3D::CompileVertexShader(fontvertshader, &vsbytecode); + if (vsbytecode == nullptr) + PanicAlert("Failed to compile vertex shader, %s %d\n", __FILE__, __LINE__); - m_vshader12.pShaderBytecode = vsbytecode->GetBufferPointer(); - m_vshader12.BytecodeLength = vsbytecode->GetBufferSize(); + m_vshader12.pShaderBytecode = vsbytecode->GetBufferPointer(); + m_vshader12.BytecodeLength = vsbytecode->GetBufferSize(); - const D3D12_INPUT_ELEMENT_DESC desc[] = - { - { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, - { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, - }; + const D3D12_INPUT_ELEMENT_DESC desc[] = { + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, + 0}, + {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, + D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, + 0}, + }; - m_input_layout12.NumElements = ARRAYSIZE(desc); - m_input_layout12.pInputElementDescs = desc; + m_input_layout12.NumElements = ARRAYSIZE(desc); + m_input_layout12.pInputElementDescs = desc; - D3D12_BLEND_DESC blenddesc = {}; - blenddesc.AlphaToCoverageEnable = FALSE; - blenddesc.IndependentBlendEnable = FALSE; - blenddesc.RenderTarget[0].BlendEnable = TRUE; - blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; - blenddesc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; - blenddesc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; - blenddesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; - blenddesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA; - blenddesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; - blenddesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; - blenddesc.RenderTarget[0].LogicOp = D3D12_LOGIC_OP_NOOP; - blenddesc.RenderTarget[0].LogicOpEnable = FALSE; - m_blendstate12 = blenddesc; + D3D12_BLEND_DESC blenddesc = {}; + blenddesc.AlphaToCoverageEnable = FALSE; + blenddesc.IndependentBlendEnable = FALSE; + blenddesc.RenderTarget[0].BlendEnable = TRUE; + blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + blenddesc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; + blenddesc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; + blenddesc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; + blenddesc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA; + blenddesc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; + blenddesc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; + blenddesc.RenderTarget[0].LogicOp = D3D12_LOGIC_OP_NOOP; + blenddesc.RenderTarget[0].LogicOpEnable = FALSE; + m_blendstate12 = blenddesc; - D3D12_RASTERIZER_DESC rastdesc = { D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_NONE, false, 0, 0.f, 0.f, false, false, false, false }; - m_raststate12 = rastdesc; + D3D12_RASTERIZER_DESC rastdesc = { + D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_NONE, false, 0, 0.f, 0.f, false, false, false, false}; + m_raststate12 = rastdesc; - const unsigned int text_vb_size = s_max_num_vertices * sizeof(FONT2DVERTEX); + const unsigned int text_vb_size = s_max_num_vertices * sizeof(FONT2DVERTEX); - m_vertex_buffer = std::make_unique(text_vb_size * 2, text_vb_size * 16, nullptr); + m_vertex_buffer = std::make_unique(text_vb_size * 2, text_vb_size * 16, nullptr); - D3D12_GRAPHICS_PIPELINE_STATE_DESC text_pso_desc = { - default_root_signature, // ID3D12RootSignature *pRootSignature; - { vsbytecode->GetBufferPointer(), vsbytecode->GetBufferSize() }, // D3D12_SHADER_BYTECODE VS; - { psbytecode->GetBufferPointer(), psbytecode->GetBufferSize() }, // D3D12_SHADER_BYTECODE PS; - {}, // D3D12_SHADER_BYTECODE DS; - {}, // D3D12_SHADER_BYTECODE HS; - {}, // D3D12_SHADER_BYTECODE GS; - {}, // D3D12_STREAM_OUTPUT_DESC StreamOutput - blenddesc, // D3D12_BLEND_DESC BlendState; - UINT_MAX, // UINT SampleMask; - rastdesc, // D3D12_RASTERIZER_DESC RasterizerState - CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT), // D3D12_DEPTH_STENCIL_DESC DepthStencilState - m_input_layout12, // D3D12_INPUT_LAYOUT_DESC InputLayout - D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF, // D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IndexBufferProperties - D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, // D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType - 1, // UINT NumRenderTargets - { DXGI_FORMAT_R8G8B8A8_UNORM }, // DXGI_FORMAT RTVFormats[8] - DXGI_FORMAT_UNKNOWN, // DXGI_FORMAT DSVFormat - { 1 /* UINT Count */, 0 /* UINT Quality */ } // DXGI_SAMPLE_DESC SampleDesc - }; + D3D12_GRAPHICS_PIPELINE_STATE_DESC text_pso_desc = { + default_root_signature, // ID3D12RootSignature *pRootSignature; + {vsbytecode->GetBufferPointer(), vsbytecode->GetBufferSize()}, // D3D12_SHADER_BYTECODE VS; + {psbytecode->GetBufferPointer(), psbytecode->GetBufferSize()}, // D3D12_SHADER_BYTECODE PS; + {}, // D3D12_SHADER_BYTECODE DS; + {}, // D3D12_SHADER_BYTECODE HS; + {}, // D3D12_SHADER_BYTECODE GS; + {}, // D3D12_STREAM_OUTPUT_DESC StreamOutput + blenddesc, // D3D12_BLEND_DESC BlendState; + UINT_MAX, // UINT SampleMask; + rastdesc, // D3D12_RASTERIZER_DESC RasterizerState + CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT), // D3D12_DEPTH_STENCIL_DESC DepthStencilState + m_input_layout12, // D3D12_INPUT_LAYOUT_DESC InputLayout + D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF, // D3D12_INDEX_BUFFER_STRIP_CUT_VALUE + // IndexBufferProperties + D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, // D3D12_PRIMITIVE_TOPOLOGY_TYPE + // PrimitiveTopologyType + 1, // UINT NumRenderTargets + {DXGI_FORMAT_R8G8B8A8_UNORM}, // DXGI_FORMAT RTVFormats[8] + DXGI_FORMAT_UNKNOWN, // DXGI_FORMAT DSVFormat + {1 /* UINT Count */, 0 /* UINT Quality */} // DXGI_SAMPLE_DESC SampleDesc + }; - CheckHR(DX12::gx_state_cache.GetPipelineStateObjectFromCache(&text_pso_desc, &m_pso)); + CheckHR(DX12::gx_state_cache.GetPipelineStateObjectFromCache(&text_pso_desc, &m_pso)); - SAFE_RELEASE(psbytecode); - SAFE_RELEASE(vsbytecode); + SAFE_RELEASE(psbytecode); + SAFE_RELEASE(vsbytecode); - return S_OK; + return S_OK; } int CD3DFont::Shutdown() { - m_vertex_buffer.reset(); - D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_texture12); + m_vertex_buffer.reset(); + D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_texture12); - return S_OK; + return S_OK; } -int CD3DFont::DrawTextScaled(float x, float y, float size, float spacing, u32 dwColor, const std::string& text) +int CD3DFont::DrawTextScaled(float x, float y, float size, float spacing, u32 dwColor, + const std::string& text) { - if (!m_vertex_buffer) - return 0; + if (!m_vertex_buffer) + return 0; - float scale_x = 1 / static_cast(D3D::GetBackBufferWidth()) * 2.f; - float scale_y = 1 / static_cast(D3D::GetBackBufferHeight()) * 2.f; - float sizeratio = size / static_cast(m_line_height); + float scale_x = 1 / static_cast(D3D::GetBackBufferWidth()) * 2.f; + float scale_y = 1 / static_cast(D3D::GetBackBufferHeight()) * 2.f; + float sizeratio = size / static_cast(m_line_height); - // translate starting positions - float sx = x * scale_x - 1.f; - float sy = 1.f - y * scale_y; + // translate starting positions + float sx = x * scale_x - 1.f; + float sy = 1.f - y * scale_y; - // set general pipeline state - D3D::current_command_list->SetPipelineState(m_pso); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); + // set general pipeline state + D3D::current_command_list->SetPipelineState(m_pso); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); - D3D::current_command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - D3D::command_list_mgr->SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + D3D::current_command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + D3D::command_list_mgr->SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SRV, m_texture12_gpu); + D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SRV, + m_texture12_gpu); - // upper bound is nchars * 6, assuming no spaces - m_vertex_buffer->AllocateSpaceInBuffer(static_cast(text.length()) * 6 * sizeof(FONT2DVERTEX), sizeof(FONT2DVERTEX), false); + // upper bound is nchars * 6, assuming no spaces + m_vertex_buffer->AllocateSpaceInBuffer(static_cast(text.length()) * 6 * sizeof(FONT2DVERTEX), + sizeof(FONT2DVERTEX), false); - FONT2DVERTEX* vertices12 = reinterpret_cast(m_vertex_buffer->GetCPUAddressOfCurrentAllocation()); - int num_triangles = 0; - float start_x = sx; - for (char c : text) - { - if (c == '\n') - { - sx = start_x; - sy -= scale_y * size; - } - if (!std::isprint(c)) - continue; + FONT2DVERTEX* vertices12 = + reinterpret_cast(m_vertex_buffer->GetCPUAddressOfCurrentAllocation()); + int num_triangles = 0; + float start_x = sx; + for (char c : text) + { + if (c == '\n') + { + sx = start_x; + sy -= scale_y * size; + } + if (!std::isprint(c)) + continue; - c -= 32; - float tx1 = m_tex_coords[c][0]; - float ty1 = m_tex_coords[c][1]; - float tx2 = m_tex_coords[c][2]; - float ty2 = m_tex_coords[c][3]; + c -= 32; + float tx1 = m_tex_coords[c][0]; + float ty1 = m_tex_coords[c][1]; + float tx2 = m_tex_coords[c][2]; + float ty2 = m_tex_coords[c][3]; - float w = static_cast(tx2 - tx1) * m_tex_width * scale_x * sizeratio; - float h = static_cast(ty1 - ty2) * m_tex_height * scale_y * sizeratio; + float w = static_cast(tx2 - tx1) * m_tex_width * scale_x * sizeratio; + float h = static_cast(ty1 - ty2) * m_tex_height * scale_y * sizeratio; - FONT2DVERTEX v[6]; - v[0] = InitFont2DVertex(sx, sy + h, dwColor, tx1, ty2); - v[1] = InitFont2DVertex(sx, sy, dwColor, tx1, ty1); - v[2] = InitFont2DVertex(sx + w, sy + h, dwColor, tx2, ty2); - v[3] = InitFont2DVertex(sx + w, sy, dwColor, tx2, ty1); - v[4] = v[2]; - v[5] = v[1]; + FONT2DVERTEX v[6]; + v[0] = InitFont2DVertex(sx, sy + h, dwColor, tx1, ty2); + v[1] = InitFont2DVertex(sx, sy, dwColor, tx1, ty1); + v[2] = InitFont2DVertex(sx + w, sy + h, dwColor, tx2, ty2); + v[3] = InitFont2DVertex(sx + w, sy, dwColor, tx2, ty1); + v[4] = v[2]; + v[5] = v[1]; - memcpy(vertices12, v, 6 * sizeof(FONT2DVERTEX)); - vertices12 += 6; + memcpy(vertices12, v, 6 * sizeof(FONT2DVERTEX)); + vertices12 += 6; - num_triangles += 2; + num_triangles += 2; - sx += w + spacing * scale_x * size; - } + sx += w + spacing * scale_x * size; + } - // Render the vertex buffer - if (num_triangles > 0) - { - u32 written_size = num_triangles * 3 * sizeof(FONT2DVERTEX); - m_vertex_buffer->OverrideSizeOfPreviousAllocation(written_size); + // Render the vertex buffer + if (num_triangles > 0) + { + u32 written_size = num_triangles * 3 * sizeof(FONT2DVERTEX); + m_vertex_buffer->OverrideSizeOfPreviousAllocation(written_size); - D3D12_VERTEX_BUFFER_VIEW vb_view = { m_vertex_buffer->GetGPUAddressOfCurrentAllocation(), written_size, sizeof(FONT2DVERTEX) }; - D3D::current_command_list->IASetVertexBuffers(0, 1, &vb_view); - D3D::current_command_list->DrawInstanced(3 * num_triangles, 1, 0, 0); - } + D3D12_VERTEX_BUFFER_VIEW vb_view = {m_vertex_buffer->GetGPUAddressOfCurrentAllocation(), + written_size, sizeof(FONT2DVERTEX)}; + D3D::current_command_list->IASetVertexBuffers(0, 1, &vb_view); + D3D::current_command_list->DrawInstanced(3 * num_triangles, 1, 0, 0); + } - return S_OK; + return S_OK; } D3D12_CPU_DESCRIPTOR_HANDLE linear_copy_sampler12CPU; @@ -477,29 +476,29 @@ D3D12_GPU_DESCRIPTOR_HANDLE point_copy_sampler12GPU; struct STQVertex { - float x, y, z, u, v, w, g; + float x, y, z, u, v, w, g; }; struct ClearVertex { - float x, y, z; - u32 col; + float x, y, z; + u32 col; }; struct ColVertex { - float x, y, z; - u32 col; + float x, y, z; + u32 col; }; struct { - float u1, v1, u2, v2, S, G; + float u1, v1, u2, v2, S, G; } tex_quad_data; struct { - u32 col; - float z; + u32 col; + float z; } clear_quad_data; // ring buffer offsets @@ -508,377 +507,380 @@ static size_t clearq_offset; void InitUtils() { - util_vbuf_stq = std::make_unique(0x10000); - util_vbuf_clearq = std::make_unique(0x10000); - util_vbuf_efbpokequads = std::make_unique(0x100000); + util_vbuf_stq = std::make_unique(0x10000); + util_vbuf_clearq = std::make_unique(0x10000); + util_vbuf_efbpokequads = std::make_unique(0x100000); - D3D12_SAMPLER_DESC point_sampler_desc = { - D3D12_FILTER_MIN_MAG_MIP_POINT, - D3D12_TEXTURE_ADDRESS_MODE_BORDER, - D3D12_TEXTURE_ADDRESS_MODE_BORDER, - D3D12_TEXTURE_ADDRESS_MODE_BORDER, - 0.f, - 1, - D3D12_COMPARISON_FUNC_ALWAYS, - { 0.f, 0.f, 0.f, 0.f }, - 0.f, - 0.f - }; + D3D12_SAMPLER_DESC point_sampler_desc = {D3D12_FILTER_MIN_MAG_MIP_POINT, + D3D12_TEXTURE_ADDRESS_MODE_BORDER, + D3D12_TEXTURE_ADDRESS_MODE_BORDER, + D3D12_TEXTURE_ADDRESS_MODE_BORDER, + 0.f, + 1, + D3D12_COMPARISON_FUNC_ALWAYS, + {0.f, 0.f, 0.f, 0.f}, + 0.f, + 0.f}; - D3D::sampler_descriptor_heap_mgr->Allocate(&point_copy_sampler12CPU, &point_copy_sampler12GPU); - D3D::device12->CreateSampler(&point_sampler_desc, point_copy_sampler12CPU); + D3D::sampler_descriptor_heap_mgr->Allocate(&point_copy_sampler12CPU, &point_copy_sampler12GPU); + D3D::device12->CreateSampler(&point_sampler_desc, point_copy_sampler12CPU); - D3D12_SAMPLER_DESC linear_sampler_desc = { - D3D12_FILTER_MIN_MAG_MIP_LINEAR, - D3D12_TEXTURE_ADDRESS_MODE_BORDER, - D3D12_TEXTURE_ADDRESS_MODE_BORDER, - D3D12_TEXTURE_ADDRESS_MODE_BORDER, - 0.f, - 1, - D3D12_COMPARISON_FUNC_ALWAYS, - { 0.f, 0.f, 0.f, 0.f }, - 0.f, - 0.f - }; + D3D12_SAMPLER_DESC linear_sampler_desc = {D3D12_FILTER_MIN_MAG_MIP_LINEAR, + D3D12_TEXTURE_ADDRESS_MODE_BORDER, + D3D12_TEXTURE_ADDRESS_MODE_BORDER, + D3D12_TEXTURE_ADDRESS_MODE_BORDER, + 0.f, + 1, + D3D12_COMPARISON_FUNC_ALWAYS, + {0.f, 0.f, 0.f, 0.f}, + 0.f, + 0.f}; - D3D::sampler_descriptor_heap_mgr->Allocate(&linear_copy_sampler12CPU, &linear_copy_sampler12GPU); - D3D::device12->CreateSampler(&linear_sampler_desc, linear_copy_sampler12CPU); + D3D::sampler_descriptor_heap_mgr->Allocate(&linear_copy_sampler12CPU, &linear_copy_sampler12GPU); + D3D::device12->CreateSampler(&linear_sampler_desc, linear_copy_sampler12CPU); - // cached data used to avoid unnecessarily reloading the vertex buffers - memset(&tex_quad_data, 0, sizeof(tex_quad_data)); - memset(&clear_quad_data, 0, sizeof(clear_quad_data)); + // cached data used to avoid unnecessarily reloading the vertex buffers + memset(&tex_quad_data, 0, sizeof(tex_quad_data)); + memset(&clear_quad_data, 0, sizeof(clear_quad_data)); - font.Init(); + font.Init(); } void ShutdownUtils() { - font.Shutdown(); + font.Shutdown(); - util_vbuf_stq.reset(); - util_vbuf_clearq.reset(); - util_vbuf_efbpokequads.reset(); + util_vbuf_stq.reset(); + util_vbuf_clearq.reset(); + util_vbuf_efbpokequads.reset(); } void SetPointCopySampler() { - D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SAMPLER, point_copy_sampler12GPU); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_SAMPLERS, true); + D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SAMPLER, + point_copy_sampler12GPU); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_SAMPLERS, true); } void SetLinearCopySampler() { - D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SAMPLER, linear_copy_sampler12GPU); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_SAMPLERS, true); + D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SAMPLER, + linear_copy_sampler12GPU); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_SAMPLERS, true); } -void SetViewportAndScissor(int top_left_x, int top_left_y, int width, int height, float min_depth, float max_depth) +void SetViewportAndScissor(int top_left_x, int top_left_y, int width, int height, float min_depth, + float max_depth) { - D3D12_VIEWPORT viewport = { - static_cast(top_left_x), - static_cast(top_left_y), - static_cast(width), - static_cast(height), - min_depth, - max_depth - }; + D3D12_VIEWPORT viewport = {static_cast(top_left_x), + static_cast(top_left_y), + static_cast(width), + static_cast(height), + min_depth, + max_depth}; - D3D12_RECT scissor = { - static_cast(top_left_x), - static_cast(top_left_y), - static_cast(top_left_x + width), - static_cast(top_left_y + height) - }; + D3D12_RECT scissor = {static_cast(top_left_x), static_cast(top_left_y), + static_cast(top_left_x + width), + static_cast(top_left_y + height)}; - D3D::current_command_list->RSSetViewports(1, &viewport); - D3D::current_command_list->RSSetScissorRects(1, &scissor); + D3D::current_command_list->RSSetViewports(1, &viewport); + D3D::current_command_list->RSSetScissorRects(1, &scissor); }; -void DrawShadedTexQuad(D3DTexture2D* texture, - const D3D12_RECT* rSource, - int source_width, - int source_height, - D3D12_SHADER_BYTECODE pshader12, - D3D12_SHADER_BYTECODE vshader12, - D3D12_INPUT_LAYOUT_DESC layout12, - D3D12_SHADER_BYTECODE gshader12, - float gamma, - u32 slice, - DXGI_FORMAT rt_format, - bool inherit_srv_binding, - bool rt_multisampled - ) +void DrawShadedTexQuad(D3DTexture2D* texture, const D3D12_RECT* rSource, int source_width, + int source_height, D3D12_SHADER_BYTECODE pshader12, + D3D12_SHADER_BYTECODE vshader12, D3D12_INPUT_LAYOUT_DESC layout12, + D3D12_SHADER_BYTECODE gshader12, float gamma, u32 slice, + DXGI_FORMAT rt_format, bool inherit_srv_binding, bool rt_multisampled) { - float sw = 1.0f / static_cast(source_width); - float sh = 1.0f / static_cast(source_height); - float u1 = static_cast(rSource->left) * sw; - float u2 = static_cast(rSource->right) * sw; - float v1 = static_cast(rSource->top) * sh; - float v2 = static_cast(rSource->bottom) * sh; - float S = static_cast(slice); - float G = 1.0f / gamma; + float sw = 1.0f / static_cast(source_width); + float sh = 1.0f / static_cast(source_height); + float u1 = static_cast(rSource->left) * sw; + float u2 = static_cast(rSource->right) * sw; + float v1 = static_cast(rSource->top) * sh; + float v2 = static_cast(rSource->bottom) * sh; + float S = static_cast(slice); + float G = 1.0f / gamma; - STQVertex coords[4] = { - { -1.0f, 1.0f, 0.0f, u1, v1, S, G }, - { 1.0f, 1.0f, 0.0f, u2, v1, S, G }, - { -1.0f, -1.0f, 0.0f, u1, v2, S, G }, - { 1.0f, -1.0f, 0.0f, u2, v2, S, G }, - }; + STQVertex coords[4] = { + {-1.0f, 1.0f, 0.0f, u1, v1, S, G}, + {1.0f, 1.0f, 0.0f, u2, v1, S, G}, + {-1.0f, -1.0f, 0.0f, u1, v2, S, G}, + {1.0f, -1.0f, 0.0f, u2, v2, S, G}, + }; - // only upload the data to VRAM if it changed - if (tex_quad_data.u1 != u1 || tex_quad_data.v1 != v1 || - tex_quad_data.u2 != u2 || tex_quad_data.v2 != v2 || - tex_quad_data.S != S || tex_quad_data.G != G) - { - stq_offset = util_vbuf_stq->AppendData(coords, sizeof(coords), sizeof(STQVertex)); + // only upload the data to VRAM if it changed + if (tex_quad_data.u1 != u1 || tex_quad_data.v1 != v1 || tex_quad_data.u2 != u2 || + tex_quad_data.v2 != v2 || tex_quad_data.S != S || tex_quad_data.G != G) + { + stq_offset = util_vbuf_stq->AppendData(coords, sizeof(coords), sizeof(STQVertex)); - tex_quad_data.u1 = u1; - tex_quad_data.v1 = v1; - tex_quad_data.u2 = u2; - tex_quad_data.v2 = v2; - tex_quad_data.S = S; - tex_quad_data.G = G; - } + tex_quad_data.u1 = u1; + tex_quad_data.v1 = v1; + tex_quad_data.u2 = u2; + tex_quad_data.v2 = v2; + tex_quad_data.S = S; + tex_quad_data.G = G; + } - D3D::current_command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - D3D::command_list_mgr->SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + D3D::current_command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + D3D::command_list_mgr->SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - D3D12_VERTEX_BUFFER_VIEW vb_view = { - util_vbuf_stq->GetBuffer12()->GetGPUVirtualAddress(), // D3D12_GPU_VIRTUAL_ADDRESS BufferLocation; - static_cast(util_vbuf_stq->GetSize()), // UINT SizeInBytes; This is the size of the entire buffer, not just the size of the vertex data for one draw call, since the offsetting is done in the draw call itself. - sizeof(STQVertex) // UINT StrideInBytes; - }; + D3D12_VERTEX_BUFFER_VIEW vb_view = { + util_vbuf_stq->GetBuffer12() + ->GetGPUVirtualAddress(), // D3D12_GPU_VIRTUAL_ADDRESS BufferLocation; + static_cast(util_vbuf_stq->GetSize()), // UINT SizeInBytes; This is the size of the + // entire buffer, not just the size of the + // vertex data for one draw call, since the + // offsetting is done in the draw call itself. + sizeof(STQVertex) // UINT StrideInBytes; + }; - D3D::current_command_list->IASetVertexBuffers(0, 1, &vb_view); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_VERTEX_BUFFER, true); + D3D::current_command_list->IASetVertexBuffers(0, 1, &vb_view); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_VERTEX_BUFFER, true); - if (!inherit_srv_binding) - { - texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SRV, texture->GetSRV12GPU()); - } + if (!inherit_srv_binding) + { + texture->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SRV, + texture->GetSRV12GPU()); + } - D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = { - default_root_signature, // ID3D12RootSignature *pRootSignature; - vshader12, // D3D12_SHADER_BYTECODE VS; - pshader12, // D3D12_SHADER_BYTECODE PS; - {}, // D3D12_SHADER_BYTECODE DS; - {}, // D3D12_SHADER_BYTECODE HS; - gshader12, // D3D12_SHADER_BYTECODE GS; - {}, // D3D12_STREAM_OUTPUT_DESC StreamOutput - Renderer::GetResetBlendDesc(), // D3D12_BLEND_DESC BlendState; - UINT_MAX, // UINT SampleMask; - Renderer::GetResetRasterizerDesc(), // D3D12_RASTERIZER_DESC RasterizerState - Renderer::GetResetDepthStencilDesc(), // D3D12_DEPTH_STENCIL_DESC DepthStencilState - layout12, // D3D12_INPUT_LAYOUT_DESC InputLayout - D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF, // D3D12_INDEX_BUFFER_PROPERTIES IndexBufferProperties - D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, // D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType - 1, // UINT NumRenderTargets - { rt_format }, // DXGI_FORMAT RTVFormats[8] - DXGI_FORMAT_D32_FLOAT, // DXGI_FORMAT DSVFormat - { 1 /* UINT Count */, 0 /* UINT Quality */ } // DXGI_SAMPLE_DESC SampleDesc - }; + D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = { + default_root_signature, // ID3D12RootSignature *pRootSignature; + vshader12, // D3D12_SHADER_BYTECODE VS; + pshader12, // D3D12_SHADER_BYTECODE PS; + {}, // D3D12_SHADER_BYTECODE DS; + {}, // D3D12_SHADER_BYTECODE HS; + gshader12, // D3D12_SHADER_BYTECODE GS; + {}, // D3D12_STREAM_OUTPUT_DESC StreamOutput + Renderer::GetResetBlendDesc(), // D3D12_BLEND_DESC BlendState; + UINT_MAX, // UINT SampleMask; + Renderer::GetResetRasterizerDesc(), // D3D12_RASTERIZER_DESC RasterizerState + Renderer::GetResetDepthStencilDesc(), // D3D12_DEPTH_STENCIL_DESC DepthStencilState + layout12, // D3D12_INPUT_LAYOUT_DESC InputLayout + D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF, // D3D12_INDEX_BUFFER_PROPERTIES + // IndexBufferProperties + D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, // D3D12_PRIMITIVE_TOPOLOGY_TYPE + // PrimitiveTopologyType + 1, // UINT NumRenderTargets + {rt_format}, // DXGI_FORMAT RTVFormats[8] + DXGI_FORMAT_D32_FLOAT, // DXGI_FORMAT DSVFormat + {1 /* UINT Count */, 0 /* UINT Quality */} // DXGI_SAMPLE_DESC SampleDesc + }; - if (rt_multisampled) - { - pso_desc.SampleDesc.Count = g_ActiveConfig.iMultisamples; - } + if (rt_multisampled) + { + pso_desc.SampleDesc.Count = g_ActiveConfig.iMultisamples; + } - ID3D12PipelineState* pso = nullptr; - CheckHR(DX12::gx_state_cache.GetPipelineStateObjectFromCache(&pso_desc, &pso)); + ID3D12PipelineState* pso = nullptr; + CheckHR(DX12::gx_state_cache.GetPipelineStateObjectFromCache(&pso_desc, &pso)); - D3D::current_command_list->SetPipelineState(pso); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); + D3D::current_command_list->SetPipelineState(pso); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); - D3D::current_command_list->DrawInstanced(4, 1, static_cast(stq_offset), 0); + D3D::current_command_list->DrawInstanced(4, 1, static_cast(stq_offset), 0); } -void DrawClearQuad(u32 Color, float z, D3D12_BLEND_DESC* blend_desc, D3D12_DEPTH_STENCIL_DESC* depth_stencil_desc, bool rt_multisampled) +void DrawClearQuad(u32 Color, float z, D3D12_BLEND_DESC* blend_desc, + D3D12_DEPTH_STENCIL_DESC* depth_stencil_desc, bool rt_multisampled) { - ClearVertex coords[4] = { - {-1.0f, 1.0f, z, Color}, - { 1.0f, 1.0f, z, Color}, - {-1.0f, -1.0f, z, Color}, - { 1.0f, -1.0f, z, Color}, - }; + ClearVertex coords[4] = { + {-1.0f, 1.0f, z, Color}, + {1.0f, 1.0f, z, Color}, + {-1.0f, -1.0f, z, Color}, + {1.0f, -1.0f, z, Color}, + }; - if (clear_quad_data.col != Color || clear_quad_data.z != z) - { - clearq_offset = util_vbuf_clearq->AppendData(coords, sizeof(coords), sizeof(ClearVertex)); + if (clear_quad_data.col != Color || clear_quad_data.z != z) + { + clearq_offset = util_vbuf_clearq->AppendData(coords, sizeof(coords), sizeof(ClearVertex)); - clear_quad_data.col = Color; - clear_quad_data.z = z; - } + clear_quad_data.col = Color; + clear_quad_data.z = z; + } - D3D::current_command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - D3D::command_list_mgr->SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + D3D::current_command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + D3D::command_list_mgr->SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - D3D12_VERTEX_BUFFER_VIEW vb_view = { - util_vbuf_clearq->GetBuffer12()->GetGPUVirtualAddress(), // D3D12_GPU_VIRTUAL_ADDRESS BufferLocation; - static_cast(util_vbuf_clearq->GetSize()), // UINT SizeInBytes; This is the size of the entire buffer, not just the size of the vertex data for one draw call, since the offsetting is done in the draw call itself. - sizeof(ClearVertex) // UINT StrideInBytes; - }; + D3D12_VERTEX_BUFFER_VIEW vb_view = { + util_vbuf_clearq->GetBuffer12() + ->GetGPUVirtualAddress(), // D3D12_GPU_VIRTUAL_ADDRESS BufferLocation; + static_cast(util_vbuf_clearq->GetSize()), // UINT SizeInBytes; This is the size of the + // entire buffer, not just the size of the + // vertex data for one draw call, since the + // offsetting is done in the draw call + // itself. + sizeof(ClearVertex) // UINT StrideInBytes; + }; - D3D::current_command_list->IASetVertexBuffers(0, 1, &vb_view); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_VERTEX_BUFFER, true); + D3D::current_command_list->IASetVertexBuffers(0, 1, &vb_view); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_VERTEX_BUFFER, true); - D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = { - default_root_signature, // ID3D12RootSignature *pRootSignature; - StaticShaderCache::GetClearVertexShader(), // D3D12_SHADER_BYTECODE VS; - StaticShaderCache::GetClearPixelShader(), // D3D12_SHADER_BYTECODE PS; - {}, // D3D12_SHADER_BYTECODE DS; - {}, // D3D12_SHADER_BYTECODE HS; - g_ActiveConfig.iStereoMode > 0 ? - StaticShaderCache::GetClearGeometryShader() : - D3D12_SHADER_BYTECODE(), // D3D12_SHADER_BYTECODE GS; - {}, // D3D12_STREAM_OUTPUT_DESC StreamOutput - *blend_desc, // D3D12_BLEND_DESC BlendState; - UINT_MAX, // UINT SampleMask; - Renderer::GetResetRasterizerDesc(), // D3D12_RASTERIZER_DESC RasterizerState - *depth_stencil_desc, // D3D12_DEPTH_STENCIL_DESC DepthStencilState - StaticShaderCache::GetClearVertexShaderInputLayout(), // D3D12_INPUT_LAYOUT_DESC InputLayout - D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF, // D3D12_INDEX_BUFFER_PROPERTIES IndexBufferProperties - D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, // D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType - 1, // UINT NumRenderTargets - { DXGI_FORMAT_R8G8B8A8_UNORM }, // DXGI_FORMAT RTVFormats[8] - DXGI_FORMAT_D32_FLOAT, // DXGI_FORMAT DSVFormat - { 1 /* UINT Count */, 0 /* UINT Quality */ } // DXGI_SAMPLE_DESC SampleDesc - }; + D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = { + default_root_signature, // ID3D12RootSignature *pRootSignature; + StaticShaderCache::GetClearVertexShader(), // D3D12_SHADER_BYTECODE VS; + StaticShaderCache::GetClearPixelShader(), // D3D12_SHADER_BYTECODE PS; + {}, // D3D12_SHADER_BYTECODE DS; + {}, // D3D12_SHADER_BYTECODE HS; + g_ActiveConfig.iStereoMode > 0 ? StaticShaderCache::GetClearGeometryShader() : + D3D12_SHADER_BYTECODE(), // D3D12_SHADER_BYTECODE GS; + {}, // D3D12_STREAM_OUTPUT_DESC StreamOutput + *blend_desc, // D3D12_BLEND_DESC BlendState; + UINT_MAX, // UINT SampleMask; + Renderer::GetResetRasterizerDesc(), // D3D12_RASTERIZER_DESC RasterizerState + *depth_stencil_desc, // D3D12_DEPTH_STENCIL_DESC DepthStencilState + StaticShaderCache::GetClearVertexShaderInputLayout(), // D3D12_INPUT_LAYOUT_DESC InputLayout + D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF, // D3D12_INDEX_BUFFER_PROPERTIES + // IndexBufferProperties + D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, // D3D12_PRIMITIVE_TOPOLOGY_TYPE + // PrimitiveTopologyType + 1, // UINT NumRenderTargets + {DXGI_FORMAT_R8G8B8A8_UNORM}, // DXGI_FORMAT RTVFormats[8] + DXGI_FORMAT_D32_FLOAT, // DXGI_FORMAT DSVFormat + {1 /* UINT Count */, 0 /* UINT Quality */} // DXGI_SAMPLE_DESC SampleDesc + }; - if (rt_multisampled) - { - pso_desc.SampleDesc.Count = g_ActiveConfig.iMultisamples; - } + if (rt_multisampled) + { + pso_desc.SampleDesc.Count = g_ActiveConfig.iMultisamples; + } - ID3D12PipelineState* pso = nullptr; - CheckHR(DX12::gx_state_cache.GetPipelineStateObjectFromCache(&pso_desc, &pso)); + ID3D12PipelineState* pso = nullptr; + CheckHR(DX12::gx_state_cache.GetPipelineStateObjectFromCache(&pso_desc, &pso)); - D3D::current_command_list->SetPipelineState(pso); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); + D3D::current_command_list->SetPipelineState(pso); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); - D3D::current_command_list->DrawInstanced(4, 1, static_cast(clearq_offset), 0); + D3D::current_command_list->DrawInstanced(4, 1, static_cast(clearq_offset), 0); } static void InitColVertex(ColVertex* vert, float x, float y, float z, u32 col) { - vert->x = x; - vert->y = y; - vert->z = z; - vert->col = col; + vert->x = x; + vert->y = y; + vert->z = z; + vert->col = col; } -void DrawEFBPokeQuads(EFBAccessType type, - const EfbPokeData* points, - size_t num_points, - D3D12_BLEND_DESC* blend_desc, - D3D12_DEPTH_STENCIL_DESC* depth_stencil_desc, - D3D12_CPU_DESCRIPTOR_HANDLE* render_target, - D3D12_CPU_DESCRIPTOR_HANDLE* depth_buffer, - bool rt_multisampled - ) +void DrawEFBPokeQuads(EFBAccessType type, const EfbPokeData* points, size_t num_points, + D3D12_BLEND_DESC* blend_desc, D3D12_DEPTH_STENCIL_DESC* depth_stencil_desc, + D3D12_CPU_DESCRIPTOR_HANDLE* render_target, + D3D12_CPU_DESCRIPTOR_HANDLE* depth_buffer, bool rt_multisampled) { - // The viewport and RT/DB are passed in so we can reconstruct the state if we need to execute in the middle of building the vertex buffer. + // The viewport and RT/DB are passed in so we can reconstruct the state if we need to execute in + // the middle of building the vertex buffer. - D3D::command_list_mgr->SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + D3D::command_list_mgr->SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = { - default_root_signature, // ID3D12RootSignature *pRootSignature; - StaticShaderCache::GetClearVertexShader(), // D3D12_SHADER_BYTECODE VS; - StaticShaderCache::GetClearPixelShader(), // D3D12_SHADER_BYTECODE PS; - {}, // D3D12_SHADER_BYTECODE DS; - {}, // D3D12_SHADER_BYTECODE HS; - g_ActiveConfig.iStereoMode > 0 ? - StaticShaderCache::GetClearGeometryShader() : - D3D12_SHADER_BYTECODE(), // D3D12_SHADER_BYTECODE GS; - {}, // D3D12_STREAM_OUTPUT_DESC StreamOutput - *blend_desc, // D3D12_BLEND_DESC BlendState; - UINT_MAX, // UINT SampleMask; - Renderer::GetResetRasterizerDesc(), // D3D12_RASTERIZER_DESC RasterizerState - *depth_stencil_desc, // D3D12_DEPTH_STENCIL_DESC DepthStencilState - StaticShaderCache::GetClearVertexShaderInputLayout(), // D3D12_INPUT_LAYOUT_DESC InputLayout - D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF, // D3D12_INDEX_BUFFER_PROPERTIES IndexBufferProperties - D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, // D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType - 1, // UINT NumRenderTargets - { DXGI_FORMAT_R8G8B8A8_UNORM }, // DXGI_FORMAT RTVFormats[8] - DXGI_FORMAT_D32_FLOAT, // DXGI_FORMAT DSVFormat - { 1 /* UINT Count */, 0 /* UINT Quality */ } // DXGI_SAMPLE_DESC SampleDesc - }; + D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = { + default_root_signature, // ID3D12RootSignature *pRootSignature; + StaticShaderCache::GetClearVertexShader(), // D3D12_SHADER_BYTECODE VS; + StaticShaderCache::GetClearPixelShader(), // D3D12_SHADER_BYTECODE PS; + {}, // D3D12_SHADER_BYTECODE DS; + {}, // D3D12_SHADER_BYTECODE HS; + g_ActiveConfig.iStereoMode > 0 ? StaticShaderCache::GetClearGeometryShader() : + D3D12_SHADER_BYTECODE(), // D3D12_SHADER_BYTECODE GS; + {}, // D3D12_STREAM_OUTPUT_DESC StreamOutput + *blend_desc, // D3D12_BLEND_DESC BlendState; + UINT_MAX, // UINT SampleMask; + Renderer::GetResetRasterizerDesc(), // D3D12_RASTERIZER_DESC RasterizerState + *depth_stencil_desc, // D3D12_DEPTH_STENCIL_DESC DepthStencilState + StaticShaderCache::GetClearVertexShaderInputLayout(), // D3D12_INPUT_LAYOUT_DESC InputLayout + D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF, // D3D12_INDEX_BUFFER_PROPERTIES + // IndexBufferProperties + D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, // D3D12_PRIMITIVE_TOPOLOGY_TYPE + // PrimitiveTopologyType + 1, // UINT NumRenderTargets + {DXGI_FORMAT_R8G8B8A8_UNORM}, // DXGI_FORMAT RTVFormats[8] + DXGI_FORMAT_D32_FLOAT, // DXGI_FORMAT DSVFormat + {1 /* UINT Count */, 0 /* UINT Quality */} // DXGI_SAMPLE_DESC SampleDesc + }; - if (rt_multisampled) - { - pso_desc.SampleDesc.Count = g_ActiveConfig.iMultisamples; - } + if (rt_multisampled) + { + pso_desc.SampleDesc.Count = g_ActiveConfig.iMultisamples; + } - ID3D12PipelineState* pso = nullptr; - CheckHR(DX12::gx_state_cache.GetPipelineStateObjectFromCache(&pso_desc, &pso)); + ID3D12PipelineState* pso = nullptr; + CheckHR(DX12::gx_state_cache.GetPipelineStateObjectFromCache(&pso_desc, &pso)); - // If drawing a large number of points at once, this will have to be split into multiple passes. - const size_t COL_QUAD_SIZE = sizeof(ColVertex) * 6; - size_t points_per_draw = util_vbuf_efbpokequads->GetSize() / COL_QUAD_SIZE; + // If drawing a large number of points at once, this will have to be split into multiple passes. + const size_t COL_QUAD_SIZE = sizeof(ColVertex) * 6; + size_t points_per_draw = util_vbuf_efbpokequads->GetSize() / COL_QUAD_SIZE; - size_t current_point_index = 0; + size_t current_point_index = 0; - while (current_point_index < num_points) - { - // Map and reserve enough buffer space for this draw - size_t points_to_draw = std::min(num_points - current_point_index, points_per_draw); - size_t required_bytes = COL_QUAD_SIZE * points_to_draw; + while (current_point_index < num_points) + { + // Map and reserve enough buffer space for this draw + size_t points_to_draw = std::min(num_points - current_point_index, points_per_draw); + size_t required_bytes = COL_QUAD_SIZE * points_to_draw; - void* buffer_ptr = nullptr; - size_t base_vertex_index = util_vbuf_efbpokequads->BeginAppendData(&buffer_ptr, required_bytes, sizeof(ColVertex)); + void* buffer_ptr = nullptr; + size_t base_vertex_index = + util_vbuf_efbpokequads->BeginAppendData(&buffer_ptr, required_bytes, sizeof(ColVertex)); - CHECK(base_vertex_index * 16 + required_bytes <= util_vbuf_efbpokequads->GetSize(), "Uh oh"); + CHECK(base_vertex_index * 16 + required_bytes <= util_vbuf_efbpokequads->GetSize(), "Uh oh"); - // Corresponding dirty flags set outside loop. - D3D::current_command_list->OMSetRenderTargets(1, render_target, FALSE, depth_buffer); - D3D::current_command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - D3D::command_list_mgr->SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + // Corresponding dirty flags set outside loop. + D3D::current_command_list->OMSetRenderTargets(1, render_target, FALSE, depth_buffer); + D3D::current_command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + D3D::command_list_mgr->SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - D3D12_VERTEX_BUFFER_VIEW vb_view = { - util_vbuf_efbpokequads->GetBuffer12()->GetGPUVirtualAddress(), // D3D12_GPU_VIRTUAL_ADDRESS BufferLocation; - static_cast(util_vbuf_efbpokequads->GetSize()), // UINT SizeInBytes; This is the size of the entire buffer, not just the size of the vertex data for one draw call, since the offsetting is done in the draw call itself. - sizeof(ColVertex) // UINT StrideInBytes; - }; + D3D12_VERTEX_BUFFER_VIEW vb_view = { + util_vbuf_efbpokequads->GetBuffer12() + ->GetGPUVirtualAddress(), // D3D12_GPU_VIRTUAL_ADDRESS BufferLocation; + static_cast(util_vbuf_efbpokequads->GetSize()), // UINT SizeInBytes; This is the size + // of the entire buffer, not just the + // size of the vertex data for one + // draw call, since the offsetting is + // done in the draw call itself. + sizeof(ColVertex) // UINT StrideInBytes; + }; - D3D::current_command_list->IASetVertexBuffers(0, 1, &vb_view); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_VERTEX_BUFFER, true); + D3D::current_command_list->IASetVertexBuffers(0, 1, &vb_view); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_VERTEX_BUFFER, true); - D3D::current_command_list->SetPipelineState(pso); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); + D3D::current_command_list->SetPipelineState(pso); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); - // generate quads for each efb point - ColVertex* base_vertex_ptr = reinterpret_cast(buffer_ptr); - for (size_t i = 0; i < points_to_draw; i++) - { - // generate quad from the single point (clip-space coordinates) - const EfbPokeData* point = &points[current_point_index]; - float x1 = float(point->x) * 2.0f / EFB_WIDTH - 1.0f; - float y1 = -float(point->y) * 2.0f / EFB_HEIGHT + 1.0f; - float x2 = float(point->x + 1) * 2.0f / EFB_WIDTH - 1.0f; - float y2 = -float(point->y + 1) * 2.0f / EFB_HEIGHT + 1.0f; - float z = (type == POKE_Z) ? (1.0f - float(point->data & 0xFFFFFF) / 16777216.0f) : 0.0f; - u32 col = (type == POKE_Z) ? 0 : ((point->data & 0xFF00FF00) | ((point->data >> 16) & 0xFF) | ((point->data << 16) & 0xFF0000)); - current_point_index++; + // generate quads for each efb point + ColVertex* base_vertex_ptr = reinterpret_cast(buffer_ptr); + for (size_t i = 0; i < points_to_draw; i++) + { + // generate quad from the single point (clip-space coordinates) + const EfbPokeData* point = &points[current_point_index]; + float x1 = float(point->x) * 2.0f / EFB_WIDTH - 1.0f; + float y1 = -float(point->y) * 2.0f / EFB_HEIGHT + 1.0f; + float x2 = float(point->x + 1) * 2.0f / EFB_WIDTH - 1.0f; + float y2 = -float(point->y + 1) * 2.0f / EFB_HEIGHT + 1.0f; + float z = (type == POKE_Z) ? (1.0f - float(point->data & 0xFFFFFF) / 16777216.0f) : 0.0f; + u32 col = (type == POKE_Z) ? 0 : ((point->data & 0xFF00FF00) | ((point->data >> 16) & 0xFF) | + ((point->data << 16) & 0xFF0000)); + current_point_index++; - // quad -> triangles - ColVertex* vertex = &base_vertex_ptr[i * 6]; - InitColVertex(&vertex[0], x1, y1, z, col); - InitColVertex(&vertex[1], x2, y1, z, col); - InitColVertex(&vertex[2], x1, y2, z, col); - InitColVertex(&vertex[3], x1, y2, z, col); - InitColVertex(&vertex[4], x2, y1, z, col); - InitColVertex(&vertex[5], x2, y2, z, col); + // quad -> triangles + ColVertex* vertex = &base_vertex_ptr[i * 6]; + InitColVertex(&vertex[0], x1, y1, z, col); + InitColVertex(&vertex[1], x2, y1, z, col); + InitColVertex(&vertex[2], x1, y2, z, col); + InitColVertex(&vertex[3], x1, y2, z, col); + InitColVertex(&vertex[4], x2, y1, z, col); + InitColVertex(&vertex[5], x2, y2, z, col); - if (type == POKE_COLOR) - FramebufferManager::UpdateEFBColorAccessCopy(point->x, point->y, col); - else if (type == POKE_Z) - FramebufferManager::UpdateEFBDepthAccessCopy(point->x, point->y, z); - } - - // Issue the draw - D3D::current_command_list->DrawInstanced(6 * static_cast(points_to_draw), 1, static_cast(base_vertex_index), 0); - } + if (type == POKE_COLOR) + FramebufferManager::UpdateEFBColorAccessCopy(point->x, point->y, col); + else if (type == POKE_Z) + FramebufferManager::UpdateEFBDepthAccessCopy(point->x, point->y, z); + } + // Issue the draw + D3D::current_command_list->DrawInstanced(6 * static_cast(points_to_draw), 1, + static_cast(base_vertex_index), 0); + } } } // namespace D3D diff --git a/Source/Core/VideoBackends/D3D12/D3DUtil.h b/Source/Core/VideoBackends/D3D12/D3DUtil.h index 6f4500c71e..942f9bcdec 100644 --- a/Source/Core/VideoBackends/D3D12/D3DUtil.h +++ b/Source/Core/VideoBackends/D3D12/D3DUtil.h @@ -15,18 +15,18 @@ namespace DX12 { - extern StateCache gx_state_cache; namespace D3D { - constexpr unsigned int AlignValue(unsigned int value, unsigned int alignment) { - return (value + (alignment - 1)) & ~(alignment - 1); + return (value + (alignment - 1)) & ~(alignment - 1); } -void ResourceBarrier(ID3D12GraphicsCommandList* command_list, ID3D12Resource* resource, D3D12_RESOURCE_STATES state_before, D3D12_RESOURCE_STATES state_after, UINT subresource); +void ResourceBarrier(ID3D12GraphicsCommandList* command_list, ID3D12Resource* resource, + D3D12_RESOURCE_STATES state_before, D3D12_RESOURCE_STATES state_after, + UINT subresource); // Font creation flags static const unsigned int D3DFONT_BOLD = 0x0001; @@ -38,35 +38,33 @@ static const unsigned int D3DFONT_CENTERED = 0x0001; class CD3DFont { public: - CD3DFont(); - // 2D text drawing function - // Initializing and destroying device-dependent objects - int Init(); - int Shutdown(); - int DrawTextScaled(float x, float y, - float size, - float spacing, u32 dwColor, - const std::string& text); + CD3DFont(); + // 2D text drawing function + // Initializing and destroying device-dependent objects + int Init(); + int Shutdown(); + int DrawTextScaled(float x, float y, float size, float spacing, u32 dwColor, + const std::string& text); private: - ID3D12Resource* m_texture12 = nullptr; - D3D12_CPU_DESCRIPTOR_HANDLE m_texture12_cpu = {}; - D3D12_GPU_DESCRIPTOR_HANDLE m_texture12_gpu = {}; + ID3D12Resource* m_texture12 = nullptr; + D3D12_CPU_DESCRIPTOR_HANDLE m_texture12_cpu = {}; + D3D12_GPU_DESCRIPTOR_HANDLE m_texture12_gpu = {}; - std::unique_ptr m_vertex_buffer; + std::unique_ptr m_vertex_buffer; - D3D12_INPUT_LAYOUT_DESC m_input_layout12 = {}; - D3D12_SHADER_BYTECODE m_pshader12 = {}; - D3D12_SHADER_BYTECODE m_vshader12 = {}; - D3D12_BLEND_DESC m_blendstate12 = {}; - D3D12_RASTERIZER_DESC m_raststate12 = {}; - ID3D12PipelineState* m_pso = nullptr; + D3D12_INPUT_LAYOUT_DESC m_input_layout12 = {}; + D3D12_SHADER_BYTECODE m_pshader12 = {}; + D3D12_SHADER_BYTECODE m_vshader12 = {}; + D3D12_BLEND_DESC m_blendstate12 = {}; + D3D12_RASTERIZER_DESC m_raststate12 = {}; + ID3D12PipelineState* m_pso = nullptr; - unsigned int m_line_height = 0; - float m_tex_coords[128 - 32][4] = {}; + unsigned int m_line_height = 0; + float m_tex_coords[128 - 32][4] = {}; - const int m_tex_width = 512; - const int m_tex_height = 512; + const int m_tex_width = 512; + const int m_tex_height = 512; }; extern CD3DFont font; @@ -77,33 +75,22 @@ void ShutdownUtils(); void SetPointCopySampler(); void SetLinearCopySampler(); -void SetViewportAndScissor(int top_left_x, int top_left_y, int width, int height, float min_depth = D3D12_MIN_DEPTH, float max_depth = D3D12_MAX_DEPTH); +void SetViewportAndScissor(int top_left_x, int top_left_y, int width, int height, + float min_depth = D3D12_MIN_DEPTH, float max_depth = D3D12_MAX_DEPTH); -void DrawShadedTexQuad(D3DTexture2D* texture, - const D3D12_RECT* source, - int source_width, - int source_height, - D3D12_SHADER_BYTECODE pshader12 = {}, - D3D12_SHADER_BYTECODE vshader12 = {}, - D3D12_INPUT_LAYOUT_DESC layout12 = {}, - D3D12_SHADER_BYTECODE gshader12 = {}, - float gamma = 1.0f, - u32 slice = 0, - DXGI_FORMAT rt_format = DXGI_FORMAT_R8G8B8A8_UNORM, - bool inherit_srv_binding = false, - bool rt_multisampled = false - ); +void DrawShadedTexQuad(D3DTexture2D* texture, const D3D12_RECT* source, int source_width, + int source_height, D3D12_SHADER_BYTECODE pshader12 = {}, + D3D12_SHADER_BYTECODE vshader12 = {}, D3D12_INPUT_LAYOUT_DESC layout12 = {}, + D3D12_SHADER_BYTECODE gshader12 = {}, float gamma = 1.0f, u32 slice = 0, + DXGI_FORMAT rt_format = DXGI_FORMAT_R8G8B8A8_UNORM, + bool inherit_srv_binding = false, bool rt_multisampled = false); -void DrawClearQuad(u32 Color, float z, D3D12_BLEND_DESC* blend_desc, D3D12_DEPTH_STENCIL_DESC* depth_stencil_desc, bool rt_multisampled); +void DrawClearQuad(u32 Color, float z, D3D12_BLEND_DESC* blend_desc, + D3D12_DEPTH_STENCIL_DESC* depth_stencil_desc, bool rt_multisampled); -void DrawEFBPokeQuads(EFBAccessType type, - const EfbPokeData* points, - size_t num_points, - D3D12_BLEND_DESC* blend_desc, - D3D12_DEPTH_STENCIL_DESC* depth_stencil_desc, - D3D12_CPU_DESCRIPTOR_HANDLE* render_target, - D3D12_CPU_DESCRIPTOR_HANDLE* depth_buffer, - bool rt_multisampled); +void DrawEFBPokeQuads(EFBAccessType type, const EfbPokeData* points, size_t num_points, + D3D12_BLEND_DESC* blend_desc, D3D12_DEPTH_STENCIL_DESC* depth_stencil_desc, + D3D12_CPU_DESCRIPTOR_HANDLE* render_target, + D3D12_CPU_DESCRIPTOR_HANDLE* depth_buffer, bool rt_multisampled); } - } diff --git a/Source/Core/VideoBackends/D3D12/FramebufferManager.cpp b/Source/Core/VideoBackends/D3D12/FramebufferManager.cpp index f7cfb2b9a7..f567852568 100644 --- a/Source/Core/VideoBackends/D3D12/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/D3D12/FramebufferManager.cpp @@ -2,11 +2,11 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoBackends/D3D12/FramebufferManager.h" #include "Core/HW/Memmap.h" #include "VideoBackends/D3D12/D3DBase.h" #include "VideoBackends/D3D12/D3DCommandListManager.h" #include "VideoBackends/D3D12/D3DUtil.h" -#include "VideoBackends/D3D12/FramebufferManager.h" #include "VideoBackends/D3D12/Render.h" #include "VideoBackends/D3D12/StaticShaderCache.h" #include "VideoBackends/D3D12/XFBEncoder.h" @@ -14,446 +14,529 @@ namespace DX12 { - FramebufferManager::Efb FramebufferManager::m_efb; unsigned int FramebufferManager::m_target_width; unsigned int FramebufferManager::m_target_height; -D3DTexture2D*& FramebufferManager::GetEFBColorTexture() { return m_efb.color_tex; } -D3DTexture2D*& FramebufferManager::GetEFBDepthTexture() { return m_efb.depth_tex; } +D3DTexture2D*& FramebufferManager::GetEFBColorTexture() +{ + return m_efb.color_tex; +} +D3DTexture2D*& FramebufferManager::GetEFBDepthTexture() +{ + return m_efb.depth_tex; +} -D3DTexture2D*& FramebufferManager::GetEFBColorTempTexture() { return m_efb.color_temp_tex; } +D3DTexture2D*& FramebufferManager::GetEFBColorTempTexture() +{ + return m_efb.color_temp_tex; +} void FramebufferManager::SwapReinterpretTexture() { - D3DTexture2D* swaptex = GetEFBColorTempTexture(); - m_efb.color_temp_tex = GetEFBColorTexture(); - m_efb.color_tex = swaptex; + D3DTexture2D* swaptex = GetEFBColorTempTexture(); + m_efb.color_temp_tex = GetEFBColorTexture(); + m_efb.color_tex = swaptex; } D3DTexture2D*& FramebufferManager::GetResolvedEFBColorTexture() { - if (g_ActiveConfig.iMultisamples > 1) - { - m_efb.resolved_color_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RESOLVE_DEST); - m_efb.color_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RESOLVE_SOURCE); + if (g_ActiveConfig.iMultisamples > 1) + { + m_efb.resolved_color_tex->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_RESOLVE_DEST); + m_efb.color_tex->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_RESOLVE_SOURCE); - for (int i = 0; i < m_efb.slices; i++) - { - D3D::current_command_list->ResolveSubresource( - m_efb.resolved_color_tex->GetTex12(), - D3D12CalcSubresource(0, i, 0, 1, m_efb.slices), - m_efb.color_tex->GetTex12(), - D3D12CalcSubresource(0, i, 0, 1, m_efb.slices), - DXGI_FORMAT_R8G8B8A8_UNORM); - } + for (int i = 0; i < m_efb.slices; i++) + { + D3D::current_command_list->ResolveSubresource( + m_efb.resolved_color_tex->GetTex12(), D3D12CalcSubresource(0, i, 0, 1, m_efb.slices), + m_efb.color_tex->GetTex12(), D3D12CalcSubresource(0, i, 0, 1, m_efb.slices), + DXGI_FORMAT_R8G8B8A8_UNORM); + } - m_efb.color_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + m_efb.color_tex->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_RENDER_TARGET); - return m_efb.resolved_color_tex; - } - else - { - return m_efb.color_tex; - } + return m_efb.resolved_color_tex; + } + else + { + return m_efb.color_tex; + } } D3DTexture2D*& FramebufferManager::GetResolvedEFBDepthTexture() { - if (g_ActiveConfig.iMultisamples > 1) - { - ResolveDepthTexture(); + if (g_ActiveConfig.iMultisamples > 1) + { + ResolveDepthTexture(); - return m_efb.resolved_depth_tex; - } - else - { - return m_efb.depth_tex; - } + return m_efb.resolved_depth_tex; + } + else + { + return m_efb.depth_tex; + } } FramebufferManager::FramebufferManager() { - m_target_width = std::max(Renderer::GetTargetWidth(), 1); - m_target_height = std::max(Renderer::GetTargetHeight(), 1); + m_target_width = std::max(Renderer::GetTargetWidth(), 1); + m_target_height = std::max(Renderer::GetTargetHeight(), 1); - DXGI_SAMPLE_DESC sample_desc; - sample_desc.Count = g_ActiveConfig.iMultisamples; - sample_desc.Quality = 0; + DXGI_SAMPLE_DESC sample_desc; + sample_desc.Count = g_ActiveConfig.iMultisamples; + sample_desc.Quality = 0; - ID3D12Resource* buf12; - D3D12_RESOURCE_DESC texdesc12; - D3D12_CLEAR_VALUE optimized_clear_valueRTV = { DXGI_FORMAT_R8G8B8A8_UNORM, { 0.0f, 0.0f, 0.0f, 1.0f } }; - D3D12_CLEAR_VALUE optimized_clear_valueDSV = CD3DX12_CLEAR_VALUE(DXGI_FORMAT_D32_FLOAT, 0.0f, 0); + ID3D12Resource* buf12; + D3D12_RESOURCE_DESC texdesc12; + D3D12_CLEAR_VALUE optimized_clear_valueRTV = {DXGI_FORMAT_R8G8B8A8_UNORM, + {0.0f, 0.0f, 0.0f, 1.0f}}; + D3D12_CLEAR_VALUE optimized_clear_valueDSV = CD3DX12_CLEAR_VALUE(DXGI_FORMAT_D32_FLOAT, 0.0f, 0); - HRESULT hr; + HRESULT hr; - m_EFBLayers = m_efb.slices = (g_ActiveConfig.iStereoMode > 0) ? 2 : 1; + m_EFBLayers = m_efb.slices = (g_ActiveConfig.iStereoMode > 0) ? 2 : 1; - // EFB color texture - primary render target - texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, m_efb.slices, 1, sample_desc.Count, sample_desc.Quality, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); - hr = D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COMMON, &optimized_clear_valueRTV, IID_PPV_ARGS(&buf12)); + // EFB color texture - primary render target + texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D( + DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, m_efb.slices, 1, + sample_desc.Count, sample_desc.Quality, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); + hr = D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, + D3D12_RESOURCE_STATE_COMMON, &optimized_clear_valueRTV, IID_PPV_ARGS(&buf12)); - m_efb.color_tex = new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, (sample_desc.Count > 1), D3D12_RESOURCE_STATE_COMMON); - SAFE_RELEASE(buf12); + m_efb.color_tex = + new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, + DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, + (sample_desc.Count > 1), D3D12_RESOURCE_STATE_COMMON); + SAFE_RELEASE(buf12); - // Temporary EFB color texture - used in ReinterpretPixelData - texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, m_efb.slices, 1, sample_desc.Count, sample_desc.Quality, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); - CheckHR(D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COMMON, &optimized_clear_valueRTV, IID_PPV_ARGS(&buf12))); - m_efb.color_temp_tex = new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, (sample_desc.Count > 1), D3D12_RESOURCE_STATE_COMMON); - SAFE_RELEASE(buf12); - D3D::SetDebugObjectName12(m_efb.color_temp_tex->GetTex12(), "EFB color temp texture"); + // Temporary EFB color texture - used in ReinterpretPixelData + texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D( + DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, m_efb.slices, 1, + sample_desc.Count, sample_desc.Quality, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, + D3D12_RESOURCE_STATE_COMMON, &optimized_clear_valueRTV, IID_PPV_ARGS(&buf12))); + m_efb.color_temp_tex = + new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, + DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, + (sample_desc.Count > 1), D3D12_RESOURCE_STATE_COMMON); + SAFE_RELEASE(buf12); + D3D::SetDebugObjectName12(m_efb.color_temp_tex->GetTex12(), "EFB color temp texture"); - // EFB depth buffer - primary depth buffer - texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R32_TYPELESS, m_target_width, m_target_height, m_efb.slices, 1, sample_desc.Count, sample_desc.Quality, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL); - CheckHR(D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COMMON, &optimized_clear_valueDSV, IID_PPV_ARGS(&buf12))); + // EFB depth buffer - primary depth buffer + texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D( + DXGI_FORMAT_R32_TYPELESS, m_target_width, m_target_height, m_efb.slices, 1, sample_desc.Count, + sample_desc.Quality, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL); + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, + D3D12_RESOURCE_STATE_COMMON, &optimized_clear_valueDSV, IID_PPV_ARGS(&buf12))); - m_efb.depth_tex = new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_DEPTH_STENCIL, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_D32_FLOAT, DXGI_FORMAT_UNKNOWN, (sample_desc.Count > 1), D3D12_RESOURCE_STATE_COMMON); - SAFE_RELEASE(buf12); - D3D::SetDebugObjectName12(m_efb.depth_tex->GetTex12(), "EFB depth texture"); + m_efb.depth_tex = + new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_DEPTH_STENCIL, + DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_D32_FLOAT, DXGI_FORMAT_UNKNOWN, + (sample_desc.Count > 1), D3D12_RESOURCE_STATE_COMMON); + SAFE_RELEASE(buf12); + D3D::SetDebugObjectName12(m_efb.depth_tex->GetTex12(), "EFB depth texture"); - if (g_ActiveConfig.iMultisamples > 1) - { - // Framebuffer resolve textures (color+depth) - texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, m_efb.slices, 1); - hr = D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&buf12)); - CHECK(hr == S_OK, "create EFB color resolve texture (size: %dx%d)", m_target_width, m_target_height); - m_efb.resolved_color_tex = new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_SHADER_RESOURCE, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, false, D3D12_RESOURCE_STATE_COMMON); - SAFE_RELEASE(buf12); - D3D::SetDebugObjectName12(m_efb.resolved_color_tex->GetTex12(), "EFB color resolve texture shader resource view"); + if (g_ActiveConfig.iMultisamples > 1) + { + // Framebuffer resolve textures (color+depth) + texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, + m_target_height, m_efb.slices, 1); + hr = D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, + D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&buf12)); + CHECK(hr == S_OK, "create EFB color resolve texture (size: %dx%d)", m_target_width, + m_target_height); + m_efb.resolved_color_tex = new D3DTexture2D( + buf12, TEXTURE_BIND_FLAG_SHADER_RESOURCE, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, false, D3D12_RESOURCE_STATE_COMMON); + SAFE_RELEASE(buf12); + D3D::SetDebugObjectName12(m_efb.resolved_color_tex->GetTex12(), + "EFB color resolve texture shader resource view"); - texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R32_FLOAT, m_target_width, m_target_height, m_efb.slices, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); - hr = D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&buf12)); - CHECK(hr == S_OK, "create EFB depth resolve texture (size: %dx%d; hr=%#x)", m_target_width, m_target_height, hr); - m_efb.resolved_depth_tex = new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, false, D3D12_RESOURCE_STATE_COMMON); - SAFE_RELEASE(buf12); - D3D::SetDebugObjectName12(m_efb.resolved_depth_tex->GetTex12(), "EFB depth resolve texture shader resource view"); - } - else - { - m_efb.resolved_color_tex = nullptr; - m_efb.resolved_depth_tex = nullptr; - } + texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R32_FLOAT, m_target_width, m_target_height, + m_efb.slices, 1, 1, 0, + D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); + hr = D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, + D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&buf12)); + CHECK(hr == S_OK, "create EFB depth resolve texture (size: %dx%d; hr=%#x)", m_target_width, + m_target_height, hr); + m_efb.resolved_depth_tex = + new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, + DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, false, + D3D12_RESOURCE_STATE_COMMON); + SAFE_RELEASE(buf12); + D3D::SetDebugObjectName12(m_efb.resolved_depth_tex->GetTex12(), + "EFB depth resolve texture shader resource view"); + } + else + { + m_efb.resolved_color_tex = nullptr; + m_efb.resolved_depth_tex = nullptr; + } - InitializeEFBAccessCopies(); + InitializeEFBAccessCopies(); } FramebufferManager::~FramebufferManager() { - DestroyEFBAccessCopies(); + DestroyEFBAccessCopies(); - SAFE_RELEASE(m_efb.color_tex); - SAFE_RELEASE(m_efb.depth_tex); - SAFE_RELEASE(m_efb.color_temp_tex); - SAFE_RELEASE(m_efb.resolved_color_tex); - SAFE_RELEASE(m_efb.resolved_depth_tex); + SAFE_RELEASE(m_efb.color_tex); + SAFE_RELEASE(m_efb.depth_tex); + SAFE_RELEASE(m_efb.color_temp_tex); + SAFE_RELEASE(m_efb.resolved_color_tex); + SAFE_RELEASE(m_efb.resolved_depth_tex); } -void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, float gamma) +void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, + const EFBRectangle& sourceRc, float gamma) { - u8* dst = Memory::GetPointer(xfbAddr); - D3DTexture2D* src_texture = GetResolvedEFBColorTexture(); - TargetRectangle scaled_rect = g_renderer->ConvertEFBRectangle(sourceRc); - g_xfb_encoder->EncodeTextureToRam(dst, fbStride, fbHeight, src_texture, scaled_rect, m_target_width, m_target_height, gamma); + u8* dst = Memory::GetPointer(xfbAddr); + D3DTexture2D* src_texture = GetResolvedEFBColorTexture(); + TargetRectangle scaled_rect = g_renderer->ConvertEFBRectangle(sourceRc); + g_xfb_encoder->EncodeTextureToRam(dst, fbStride, fbHeight, src_texture, scaled_rect, + m_target_width, m_target_height, gamma); } -std::unique_ptr FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) +std::unique_ptr FramebufferManager::CreateXFBSource(unsigned int target_width, + unsigned int target_height, + unsigned int layers) { - return std::make_unique(D3DTexture2D::Create(target_width, target_height, - TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, - DXGI_FORMAT_R8G8B8A8_UNORM, 1, layers), layers); + return std::make_unique( + D3DTexture2D::Create(target_width, target_height, + TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, + DXGI_FORMAT_R8G8B8A8_UNORM, 1, layers), + layers); } void FramebufferManager::GetTargetSize(unsigned int* width, unsigned int* height) { - *width = m_target_width; - *height = m_target_height; + *width = m_target_width; + *height = m_target_height; } void FramebufferManager::ResolveDepthTexture() { - // ResolveSubresource does not work with depth textures. - // Instead, we use a shader that selects the minimum depth from all samples. - D3D::SetViewportAndScissor(0, 0, m_target_width, m_target_height); + // ResolveSubresource does not work with depth textures. + // Instead, we use a shader that selects the minimum depth from all samples. + D3D::SetViewportAndScissor(0, 0, m_target_width, m_target_height); - m_efb.resolved_depth_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - D3D::current_command_list->OMSetRenderTargets(0, nullptr, FALSE, &m_efb.resolved_depth_tex->GetDSV12()); + m_efb.resolved_depth_tex->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_RENDER_TARGET); + D3D::current_command_list->OMSetRenderTargets(0, nullptr, FALSE, + &m_efb.resolved_depth_tex->GetDSV12()); - FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - const D3D12_RECT source_rect = CD3DX12_RECT(0, 0, m_target_width, m_target_height); - D3D::DrawShadedTexQuad( - FramebufferManager::GetEFBDepthTexture(), - &source_rect, - m_target_width, - m_target_height, - StaticShaderCache::GetDepthResolveToColorPixelShader(), - StaticShaderCache::GetSimpleVertexShader(), - StaticShaderCache::GetSimpleVertexShaderInputLayout(), - StaticShaderCache::GetCopyGeometryShader(), - 1.0, - 0, - DXGI_FORMAT_D32_FLOAT - ); + const D3D12_RECT source_rect = CD3DX12_RECT(0, 0, m_target_width, m_target_height); + D3D::DrawShadedTexQuad(FramebufferManager::GetEFBDepthTexture(), &source_rect, m_target_width, + m_target_height, StaticShaderCache::GetDepthResolveToColorPixelShader(), + StaticShaderCache::GetSimpleVertexShader(), + StaticShaderCache::GetSimpleVertexShaderInputLayout(), + StaticShaderCache::GetCopyGeometryShader(), 1.0, 0, DXGI_FORMAT_D32_FLOAT); - FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); + FramebufferManager::GetEFBColorTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); - // Restores proper viewport/scissor settings. - g_renderer->RestoreAPIState(); + // Restores proper viewport/scissor settings. + g_renderer->RestoreAPIState(); } void FramebufferManager::RestoreEFBRenderTargets() { - D3D::current_command_list->OMSetRenderTargets(1, - &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, - &FramebufferManager::GetEFBDepthTexture()->GetDSV12()); + D3D::current_command_list->OMSetRenderTargets( + 1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, + &FramebufferManager::GetEFBDepthTexture()->GetDSV12()); } u32 FramebufferManager::ReadEFBColorAccessCopy(u32 x, u32 y) { - if (!m_efb.color_access_readback_map) - MapEFBColorAccessCopy(); + if (!m_efb.color_access_readback_map) + MapEFBColorAccessCopy(); - u32 color; - size_t buffer_offset = y * m_efb.color_access_readback_pitch + x * sizeof(u32); - memcpy(&color, &m_efb.color_access_readback_map[buffer_offset], sizeof(color)); - return color; + u32 color; + size_t buffer_offset = y * m_efb.color_access_readback_pitch + x * sizeof(u32); + memcpy(&color, &m_efb.color_access_readback_map[buffer_offset], sizeof(color)); + return color; } float FramebufferManager::ReadEFBDepthAccessCopy(u32 x, u32 y) { - if (!m_efb.depth_access_readback_map) - MapEFBDepthAccessCopy(); + if (!m_efb.depth_access_readback_map) + MapEFBDepthAccessCopy(); - float depth; - size_t buffer_offset = y * m_efb.depth_access_readback_pitch + x * sizeof(float); - memcpy(&depth, &m_efb.depth_access_readback_map[buffer_offset], sizeof(depth)); - return depth; + float depth; + size_t buffer_offset = y * m_efb.depth_access_readback_pitch + x * sizeof(float); + memcpy(&depth, &m_efb.depth_access_readback_map[buffer_offset], sizeof(depth)); + return depth; } void FramebufferManager::UpdateEFBColorAccessCopy(u32 x, u32 y, u32 color) { - if (!m_efb.color_access_readback_map) - return; + if (!m_efb.color_access_readback_map) + return; - size_t buffer_offset = y * m_efb.color_access_readback_pitch + x * sizeof(u32); - memcpy(&m_efb.color_access_readback_map[buffer_offset], &color, sizeof(color)); + size_t buffer_offset = y * m_efb.color_access_readback_pitch + x * sizeof(u32); + memcpy(&m_efb.color_access_readback_map[buffer_offset], &color, sizeof(color)); } void FramebufferManager::UpdateEFBDepthAccessCopy(u32 x, u32 y, float depth) { - if (!m_efb.depth_access_readback_map) - return; + if (!m_efb.depth_access_readback_map) + return; - size_t buffer_offset = y * m_efb.depth_access_readback_pitch + x * sizeof(float); - memcpy(&m_efb.depth_access_readback_map[buffer_offset], &depth, sizeof(depth)); + size_t buffer_offset = y * m_efb.depth_access_readback_pitch + x * sizeof(float); + memcpy(&m_efb.depth_access_readback_map[buffer_offset], &depth, sizeof(depth)); } void FramebufferManager::InitializeEFBAccessCopies() { - D3D12_CLEAR_VALUE optimized_color_clear_value = { DXGI_FORMAT_R8G8B8A8_UNORM, { 0.0f, 0.0f, 0.0f, 1.0f } }; - D3D12_CLEAR_VALUE optimized_depth_clear_value = { DXGI_FORMAT_R32_FLOAT, { 1.0f } }; - CD3DX12_RESOURCE_DESC texdesc12; - ID3D12Resource* buf12; - HRESULT hr; + D3D12_CLEAR_VALUE optimized_color_clear_value = {DXGI_FORMAT_R8G8B8A8_UNORM, + {0.0f, 0.0f, 0.0f, 1.0f}}; + D3D12_CLEAR_VALUE optimized_depth_clear_value = {DXGI_FORMAT_R32_FLOAT, {1.0f}}; + CD3DX12_RESOURCE_DESC texdesc12; + ID3D12Resource* buf12; + HRESULT hr; - // EFB access - color resize buffer - texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, EFB_WIDTH, EFB_HEIGHT, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_TEXTURE_LAYOUT_UNKNOWN, 0); - hr = D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COMMON, &optimized_color_clear_value, IID_PPV_ARGS(&buf12)); - CHECK(hr == S_OK, "create EFB access color resize buffer (hr=%#x)", hr); - m_efb.color_access_resize_tex = new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_RENDER_TARGET, DXGI_FORMAT_R8G8B8A8_UNORM); - D3D::SetDebugObjectName12(m_efb.color_access_resize_tex->GetTex12(), "EFB access color resize buffer"); - buf12->Release(); + // EFB access - color resize buffer + texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, EFB_WIDTH, EFB_HEIGHT, 1, 1, + 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, + D3D12_TEXTURE_LAYOUT_UNKNOWN, 0); + hr = D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, + D3D12_RESOURCE_STATE_COMMON, &optimized_color_clear_value, IID_PPV_ARGS(&buf12)); + CHECK(hr == S_OK, "create EFB access color resize buffer (hr=%#x)", hr); + m_efb.color_access_resize_tex = + new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_RENDER_TARGET, DXGI_FORMAT_R8G8B8A8_UNORM); + D3D::SetDebugObjectName12(m_efb.color_access_resize_tex->GetTex12(), + "EFB access color resize buffer"); + buf12->Release(); - // EFB access - color staging/readback buffer - m_efb.color_access_readback_pitch = D3D::AlignValue(EFB_WIDTH * sizeof(u32), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); - texdesc12 = CD3DX12_RESOURCE_DESC::Buffer(m_efb.color_access_readback_pitch * EFB_HEIGHT); - hr = D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_efb.color_access_readback_buffer)); - D3D::SetDebugObjectName12(m_efb.color_access_readback_buffer, "EFB access color readback buffer"); + // EFB access - color staging/readback buffer + m_efb.color_access_readback_pitch = + D3D::AlignValue(EFB_WIDTH * sizeof(u32), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + texdesc12 = CD3DX12_RESOURCE_DESC::Buffer(m_efb.color_access_readback_pitch * EFB_HEIGHT); + hr = D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), D3D12_HEAP_FLAG_NONE, &texdesc12, + D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_efb.color_access_readback_buffer)); + D3D::SetDebugObjectName12(m_efb.color_access_readback_buffer, "EFB access color readback buffer"); - // EFB access - depth resize buffer - texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R32_FLOAT, EFB_WIDTH, EFB_HEIGHT, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_TEXTURE_LAYOUT_UNKNOWN, 0); - hr = D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COMMON, &optimized_depth_clear_value, IID_PPV_ARGS(&buf12)); - CHECK(hr == S_OK, "create EFB access depth resize buffer (hr=%#x)", hr); - m_efb.depth_access_resize_tex = new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_RENDER_TARGET, DXGI_FORMAT_R32_FLOAT); - D3D::SetDebugObjectName12(m_efb.color_access_resize_tex->GetTex12(), "EFB access depth resize buffer"); - buf12->Release(); + // EFB access - depth resize buffer + texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R32_FLOAT, EFB_WIDTH, EFB_HEIGHT, 1, 1, 1, 0, + D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, + D3D12_TEXTURE_LAYOUT_UNKNOWN, 0); + hr = D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, + D3D12_RESOURCE_STATE_COMMON, &optimized_depth_clear_value, IID_PPV_ARGS(&buf12)); + CHECK(hr == S_OK, "create EFB access depth resize buffer (hr=%#x)", hr); + m_efb.depth_access_resize_tex = + new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_RENDER_TARGET, DXGI_FORMAT_R32_FLOAT); + D3D::SetDebugObjectName12(m_efb.color_access_resize_tex->GetTex12(), + "EFB access depth resize buffer"); + buf12->Release(); - // EFB access - depth staging/readback buffer - m_efb.depth_access_readback_pitch = D3D::AlignValue(EFB_WIDTH * sizeof(float), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); - texdesc12 = CD3DX12_RESOURCE_DESC::Buffer(m_efb.depth_access_readback_pitch * EFB_HEIGHT); - hr = D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_efb.depth_access_readback_buffer)); - D3D::SetDebugObjectName12(m_efb.color_access_readback_buffer, "EFB access depth readback buffer"); + // EFB access - depth staging/readback buffer + m_efb.depth_access_readback_pitch = + D3D::AlignValue(EFB_WIDTH * sizeof(float), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + texdesc12 = CD3DX12_RESOURCE_DESC::Buffer(m_efb.depth_access_readback_pitch * EFB_HEIGHT); + hr = D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), D3D12_HEAP_FLAG_NONE, &texdesc12, + D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_efb.depth_access_readback_buffer)); + D3D::SetDebugObjectName12(m_efb.color_access_readback_buffer, "EFB access depth readback buffer"); } void FramebufferManager::MapEFBColorAccessCopy() { - D3D::command_list_mgr->CPUAccessNotify(); + D3D::command_list_mgr->CPUAccessNotify(); - ID3D12Resource* src_resource; - if (m_target_width != EFB_WIDTH || m_target_height != EFB_HEIGHT || g_ActiveConfig.iMultisamples > 1) - { - // for non-1xIR or multisampled cases, we need to copy to an intermediate texture first - m_efb.color_access_resize_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + ID3D12Resource* src_resource; + if (m_target_width != EFB_WIDTH || m_target_height != EFB_HEIGHT || + g_ActiveConfig.iMultisamples > 1) + { + // for non-1xIR or multisampled cases, we need to copy to an intermediate texture first + m_efb.color_access_resize_tex->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_RENDER_TARGET); - D3D::SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT); - D3D::SetPointCopySampler(); - D3D::current_command_list->OMSetRenderTargets(1, &m_efb.color_access_resize_tex->GetRTV12(), FALSE, nullptr); + D3D::SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT); + D3D::SetPointCopySampler(); + D3D::current_command_list->OMSetRenderTargets(1, &m_efb.color_access_resize_tex->GetRTV12(), + FALSE, nullptr); - CD3DX12_RECT src_rect(0, 0, m_target_width, m_target_height); - D3D::DrawShadedTexQuad(m_efb.color_tex, &src_rect, m_target_width, m_target_height, - StaticShaderCache::GetColorCopyPixelShader(true), - StaticShaderCache::GetSimpleVertexShader(), - StaticShaderCache::GetSimpleVertexShaderInputLayout(), - {}, 1.0f, 0, DXGI_FORMAT_R8G8B8A8_UNORM, false, false); + CD3DX12_RECT src_rect(0, 0, m_target_width, m_target_height); + D3D::DrawShadedTexQuad(m_efb.color_tex, &src_rect, m_target_width, m_target_height, + StaticShaderCache::GetColorCopyPixelShader(true), + StaticShaderCache::GetSimpleVertexShader(), + StaticShaderCache::GetSimpleVertexShaderInputLayout(), {}, 1.0f, 0, + DXGI_FORMAT_R8G8B8A8_UNORM, false, false); - m_efb.color_access_resize_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); - src_resource = m_efb.color_access_resize_tex->GetTex12(); - } - else - { - // Can source the EFB buffer - m_efb.color_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); - src_resource = m_efb.color_tex->GetTex12(); - } + m_efb.color_access_resize_tex->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_COPY_SOURCE); + src_resource = m_efb.color_access_resize_tex->GetTex12(); + } + else + { + // Can source the EFB buffer + m_efb.color_tex->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_COPY_SOURCE); + src_resource = m_efb.color_tex->GetTex12(); + } - // Copy to staging resource - D3D12_PLACED_SUBRESOURCE_FOOTPRINT dst_footprint = { 0, { DXGI_FORMAT_R8G8B8A8_UNORM, EFB_WIDTH, EFB_HEIGHT, 1, m_efb.color_access_readback_pitch } }; - CD3DX12_TEXTURE_COPY_LOCATION dst_location(m_efb.color_access_readback_buffer, dst_footprint); - CD3DX12_TEXTURE_COPY_LOCATION src_location(src_resource, 0); - D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, nullptr); + // Copy to staging resource + D3D12_PLACED_SUBRESOURCE_FOOTPRINT dst_footprint = { + 0, {DXGI_FORMAT_R8G8B8A8_UNORM, EFB_WIDTH, EFB_HEIGHT, 1, m_efb.color_access_readback_pitch}}; + CD3DX12_TEXTURE_COPY_LOCATION dst_location(m_efb.color_access_readback_buffer, dst_footprint); + CD3DX12_TEXTURE_COPY_LOCATION src_location(src_resource, 0); + D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, nullptr); - // Restore EFB resource state if it was sourced from here - if (src_resource == m_efb.color_tex->GetTex12()) - m_efb.color_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + // Restore EFB resource state if it was sourced from here + if (src_resource == m_efb.color_tex->GetTex12()) + m_efb.color_tex->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_RENDER_TARGET); - // Block until completion - state is automatically restored - D3D::command_list_mgr->ExecuteQueuedWork(true); + // Block until completion - state is automatically restored + D3D::command_list_mgr->ExecuteQueuedWork(true); - // Resource copy has finished, so safe to map now - D3D12_RANGE read_range = { 0, m_efb.color_access_readback_pitch * EFB_HEIGHT }; - m_efb.color_access_readback_buffer->Map(0, &read_range, reinterpret_cast(&m_efb.color_access_readback_map)); + // Resource copy has finished, so safe to map now + D3D12_RANGE read_range = {0, m_efb.color_access_readback_pitch * EFB_HEIGHT}; + m_efb.color_access_readback_buffer->Map( + 0, &read_range, reinterpret_cast(&m_efb.color_access_readback_map)); } void FramebufferManager::MapEFBDepthAccessCopy() { - D3D::command_list_mgr->CPUAccessNotify(); + D3D::command_list_mgr->CPUAccessNotify(); - ID3D12Resource* src_resource; - if (m_target_width != EFB_WIDTH || m_target_height != EFB_HEIGHT || g_ActiveConfig.iMultisamples > 1) - { - // for non-1xIR or multisampled cases, we need to copy to an intermediate texture first - m_efb.depth_access_resize_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + ID3D12Resource* src_resource; + if (m_target_width != EFB_WIDTH || m_target_height != EFB_HEIGHT || + g_ActiveConfig.iMultisamples > 1) + { + // for non-1xIR or multisampled cases, we need to copy to an intermediate texture first + m_efb.depth_access_resize_tex->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_RENDER_TARGET); - D3D::SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT); - D3D::SetPointCopySampler(); - D3D::current_command_list->OMSetRenderTargets(1, &m_efb.depth_access_resize_tex->GetRTV12(), FALSE, nullptr); + D3D::SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT); + D3D::SetPointCopySampler(); + D3D::current_command_list->OMSetRenderTargets(1, &m_efb.depth_access_resize_tex->GetRTV12(), + FALSE, nullptr); - CD3DX12_RECT src_rect(0, 0, m_target_width, m_target_height); - D3D::DrawShadedTexQuad(m_efb.depth_tex, &src_rect, m_target_width, m_target_height, - (g_ActiveConfig.iMultisamples > 1) ? StaticShaderCache::GetDepthResolveToColorPixelShader() : StaticShaderCache::GetColorCopyPixelShader(false), - StaticShaderCache::GetSimpleVertexShader(), - StaticShaderCache::GetSimpleVertexShaderInputLayout(), - {}, 1.0f, 0, DXGI_FORMAT_R32_FLOAT, false, false); + CD3DX12_RECT src_rect(0, 0, m_target_width, m_target_height); + D3D::DrawShadedTexQuad(m_efb.depth_tex, &src_rect, m_target_width, m_target_height, + (g_ActiveConfig.iMultisamples > 1) ? + StaticShaderCache::GetDepthResolveToColorPixelShader() : + StaticShaderCache::GetColorCopyPixelShader(false), + StaticShaderCache::GetSimpleVertexShader(), + StaticShaderCache::GetSimpleVertexShaderInputLayout(), {}, 1.0f, 0, + DXGI_FORMAT_R32_FLOAT, false, false); - m_efb.depth_access_resize_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); - src_resource = m_efb.depth_access_resize_tex->GetTex12(); - } - else - { - // Can source the EFB buffer - m_efb.depth_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); - src_resource = m_efb.depth_tex->GetTex12(); - } + m_efb.depth_access_resize_tex->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_COPY_SOURCE); + src_resource = m_efb.depth_access_resize_tex->GetTex12(); + } + else + { + // Can source the EFB buffer + m_efb.depth_tex->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_COPY_SOURCE); + src_resource = m_efb.depth_tex->GetTex12(); + } - // Copy to staging resource - D3D12_PLACED_SUBRESOURCE_FOOTPRINT dst_footprint = { 0,{ DXGI_FORMAT_R32_FLOAT, EFB_WIDTH, EFB_HEIGHT, 1, m_efb.depth_access_readback_pitch } }; - CD3DX12_TEXTURE_COPY_LOCATION dst_location(m_efb.depth_access_readback_buffer, dst_footprint); - CD3DX12_TEXTURE_COPY_LOCATION src_location(src_resource, 0); - D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, nullptr); + // Copy to staging resource + D3D12_PLACED_SUBRESOURCE_FOOTPRINT dst_footprint = { + 0, {DXGI_FORMAT_R32_FLOAT, EFB_WIDTH, EFB_HEIGHT, 1, m_efb.depth_access_readback_pitch}}; + CD3DX12_TEXTURE_COPY_LOCATION dst_location(m_efb.depth_access_readback_buffer, dst_footprint); + CD3DX12_TEXTURE_COPY_LOCATION src_location(src_resource, 0); + D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, nullptr); - // Restore EFB resource state if it was sourced from here - if (src_resource == m_efb.depth_tex->GetTex12()) - m_efb.depth_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); + // Restore EFB resource state if it was sourced from here + if (src_resource == m_efb.depth_tex->GetTex12()) + m_efb.depth_tex->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_DEPTH_WRITE); - // Block until completion - state is automatically restored - D3D::command_list_mgr->ExecuteQueuedWork(true); + // Block until completion - state is automatically restored + D3D::command_list_mgr->ExecuteQueuedWork(true); - // Resource copy has finished, so safe to map now - D3D12_RANGE read_range = { 0, m_efb.depth_access_readback_pitch * EFB_HEIGHT }; - m_efb.depth_access_readback_buffer->Map(0, &read_range, reinterpret_cast(&m_efb.depth_access_readback_map)); + // Resource copy has finished, so safe to map now + D3D12_RANGE read_range = {0, m_efb.depth_access_readback_pitch * EFB_HEIGHT}; + m_efb.depth_access_readback_buffer->Map( + 0, &read_range, reinterpret_cast(&m_efb.depth_access_readback_map)); } void FramebufferManager::InvalidateEFBAccessCopies() { - D3D12_RANGE write_range = {}; + D3D12_RANGE write_range = {}; - if (m_efb.color_access_readback_map) - { - m_efb.color_access_readback_buffer->Unmap(0, &write_range); - m_efb.color_access_readback_map = nullptr; - } + if (m_efb.color_access_readback_map) + { + m_efb.color_access_readback_buffer->Unmap(0, &write_range); + m_efb.color_access_readback_map = nullptr; + } - if (m_efb.depth_access_readback_map) - { - m_efb.depth_access_readback_buffer->Unmap(0, &write_range); - m_efb.depth_access_readback_map = nullptr; - } + if (m_efb.depth_access_readback_map) + { + m_efb.depth_access_readback_buffer->Unmap(0, &write_range); + m_efb.depth_access_readback_map = nullptr; + } } void FramebufferManager::DestroyEFBAccessCopies() { - InvalidateEFBAccessCopies(); + InvalidateEFBAccessCopies(); - SAFE_RELEASE(m_efb.color_access_resize_tex); - D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_efb.color_access_readback_buffer); - m_efb.color_access_readback_buffer = nullptr; + SAFE_RELEASE(m_efb.color_access_resize_tex); + D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted( + m_efb.color_access_readback_buffer); + m_efb.color_access_readback_buffer = nullptr; - SAFE_RELEASE(m_efb.depth_access_resize_tex); - D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_efb.depth_access_readback_buffer); - m_efb.depth_access_readback_buffer = nullptr; + SAFE_RELEASE(m_efb.depth_access_resize_tex); + D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted( + m_efb.depth_access_readback_buffer); + m_efb.depth_access_readback_buffer = nullptr; } void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) { - u8* src = Memory::GetPointer(xfbAddr); - g_xfb_encoder->DecodeToTexture(m_tex, src, fbWidth, fbHeight); + u8* src = Memory::GetPointer(xfbAddr); + g_xfb_encoder->DecodeToTexture(m_tex, src, fbWidth, fbHeight); } void XFBSource::CopyEFB(float gamma) { - // Copy EFB data to XFB and restore render target again - D3D::SetViewportAndScissor(0, 0, texWidth, texHeight); + // Copy EFB data to XFB and restore render target again + D3D::SetViewportAndScissor(0, 0, texWidth, texHeight); - const D3D12_RECT rect = CD3DX12_RECT(0, 0, texWidth, texHeight); + const D3D12_RECT rect = CD3DX12_RECT(0, 0, texWidth, texHeight); - m_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - D3D::current_command_list->OMSetRenderTargets(1, &m_tex->GetRTV12(), FALSE, nullptr); + m_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + D3D::current_command_list->OMSetRenderTargets(1, &m_tex->GetRTV12(), FALSE, nullptr); - D3D::SetPointCopySampler(); + D3D::SetPointCopySampler(); - D3D::DrawShadedTexQuad( - FramebufferManager::GetEFBColorTexture(), - &rect, - Renderer::GetTargetWidth(), - Renderer::GetTargetHeight(), - StaticShaderCache::GetColorCopyPixelShader(true), - StaticShaderCache::GetSimpleVertexShader(), - StaticShaderCache::GetSimpleVertexShaderInputLayout(), - StaticShaderCache::GetCopyGeometryShader(), - gamma, - 0, - DXGI_FORMAT_R8G8B8A8_UNORM, - false, - m_tex->GetMultisampled() - ); + D3D::DrawShadedTexQuad(FramebufferManager::GetEFBColorTexture(), &rect, + Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), + StaticShaderCache::GetColorCopyPixelShader(true), + StaticShaderCache::GetSimpleVertexShader(), + StaticShaderCache::GetSimpleVertexShaderInputLayout(), + StaticShaderCache::GetCopyGeometryShader(), gamma, 0, + DXGI_FORMAT_R8G8B8A8_UNORM, false, m_tex->GetMultisampled()); - FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE ); + FramebufferManager::GetEFBColorTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); - // Restores proper viewport/scissor settings. - g_renderer->RestoreAPIState(); + // Restores proper viewport/scissor settings. + g_renderer->RestoreAPIState(); } } // namespace DX12 diff --git a/Source/Core/VideoBackends/D3D12/FramebufferManager.h b/Source/Core/VideoBackends/D3D12/FramebufferManager.h index 09721f143d..d5b6c32555 100644 --- a/Source/Core/VideoBackends/D3D12/FramebufferManager.h +++ b/Source/Core/VideoBackends/D3D12/FramebufferManager.h @@ -9,7 +9,6 @@ namespace DX12 { - // On the GameCube, the game sends a request for the graphics processor to // transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM // called the XFB (External Framebuffer). The size and location of the XFB is @@ -44,77 +43,79 @@ namespace DX12 struct XFBSource final : public XFBSourceBase { - XFBSource(D3DTexture2D* tex, int slices) : m_tex(tex), m_slices(slices) {} - ~XFBSource() { m_tex->Release(); } + XFBSource(D3DTexture2D* tex, int slices) : m_tex(tex), m_slices(slices) {} + ~XFBSource() { m_tex->Release(); } + void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override; + void CopyEFB(float gamma) override; - void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override; - void CopyEFB(float gamma) override; - - D3DTexture2D* m_tex; - const int m_slices; + D3DTexture2D* m_tex; + const int m_slices; }; class FramebufferManager final : public FramebufferManagerBase { public: - FramebufferManager(); - ~FramebufferManager(); + FramebufferManager(); + ~FramebufferManager(); - static D3DTexture2D*& GetEFBColorTexture(); - static D3DTexture2D*& GetEFBDepthTexture(); - static D3DTexture2D*& GetResolvedEFBColorTexture(); - static D3DTexture2D*& GetResolvedEFBDepthTexture(); + static D3DTexture2D*& GetEFBColorTexture(); + static D3DTexture2D*& GetEFBDepthTexture(); + static D3DTexture2D*& GetResolvedEFBColorTexture(); + static D3DTexture2D*& GetResolvedEFBDepthTexture(); - static D3DTexture2D*& GetEFBColorTempTexture(); - static void SwapReinterpretTexture(); + static D3DTexture2D*& GetEFBColorTempTexture(); + static void SwapReinterpretTexture(); - static void ResolveDepthTexture(); + static void ResolveDepthTexture(); - static void RestoreEFBRenderTargets(); + static void RestoreEFBRenderTargets(); - // Access EFB from CPU - static u32 ReadEFBColorAccessCopy(u32 x, u32 y); - static float ReadEFBDepthAccessCopy(u32 x, u32 y); - static void UpdateEFBColorAccessCopy(u32 x, u32 y, u32 color); - static void UpdateEFBDepthAccessCopy(u32 x, u32 y, float depth); - static void InitializeEFBAccessCopies(); - static void MapEFBColorAccessCopy(); - static void MapEFBDepthAccessCopy(); - static void InvalidateEFBAccessCopies(); - static void DestroyEFBAccessCopies(); + // Access EFB from CPU + static u32 ReadEFBColorAccessCopy(u32 x, u32 y); + static float ReadEFBDepthAccessCopy(u32 x, u32 y); + static void UpdateEFBColorAccessCopy(u32 x, u32 y, u32 color); + static void UpdateEFBDepthAccessCopy(u32 x, u32 y, float depth); + static void InitializeEFBAccessCopies(); + static void MapEFBColorAccessCopy(); + static void MapEFBDepthAccessCopy(); + static void InvalidateEFBAccessCopies(); + static void DestroyEFBAccessCopies(); private: - std::unique_ptr CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) override; - void GetTargetSize(unsigned int* width, unsigned int* height) override; + std::unique_ptr CreateXFBSource(unsigned int target_width, + unsigned int target_height, + unsigned int layers) override; + void GetTargetSize(unsigned int* width, unsigned int* height) override; - void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, float gamma) override; + void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, + float gamma) override; - static struct Efb - { - D3DTexture2D* color_tex; + static struct Efb + { + D3DTexture2D* color_tex; - D3DTexture2D* depth_tex; + D3DTexture2D* depth_tex; - D3DTexture2D* color_temp_tex; + D3DTexture2D* color_temp_tex; - D3DTexture2D* resolved_color_tex; - D3DTexture2D* resolved_depth_tex; + D3DTexture2D* resolved_color_tex; + D3DTexture2D* resolved_depth_tex; - D3DTexture2D* color_access_resize_tex; - ID3D12Resource* color_access_readback_buffer; - u8* color_access_readback_map; - u32 color_access_readback_pitch; + D3DTexture2D* color_access_resize_tex; + ID3D12Resource* color_access_readback_buffer; + u8* color_access_readback_map; + u32 color_access_readback_pitch; - D3DTexture2D* depth_access_resize_tex; - ID3D12Resource* depth_access_readback_buffer; - u8* depth_access_readback_map; - u32 depth_access_readback_pitch; + D3DTexture2D* depth_access_resize_tex; + ID3D12Resource* depth_access_readback_buffer; + u8* depth_access_readback_map; + u32 depth_access_readback_pitch; - int slices; - } m_efb; + int slices; + } m_efb; - static unsigned int m_target_width; - static unsigned int m_target_height; + static unsigned int m_target_width; + static unsigned int m_target_height; }; } // namespace DX12 diff --git a/Source/Core/VideoBackends/D3D12/NativeVertexFormat.cpp b/Source/Core/VideoBackends/D3D12/NativeVertexFormat.cpp index d5a4cdd5a5..30b071833a 100644 --- a/Source/Core/VideoBackends/D3D12/NativeVertexFormat.cpp +++ b/Source/Core/VideoBackends/D3D12/NativeVertexFormat.cpp @@ -13,97 +13,103 @@ namespace DX12 { - -NativeVertexFormat* VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) +NativeVertexFormat* +VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) { - return new D3DVertexFormat(vtx_decl); + return new D3DVertexFormat(vtx_decl); } -static const constexpr DXGI_FORMAT d3d_format_lookup[5*4*2] = -{ - // float formats - DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R32_FLOAT, - DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R32G32_FLOAT, - DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32_FLOAT, - DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R32G32B32A32_FLOAT, +static const constexpr DXGI_FORMAT d3d_format_lookup[5 * 4 * 2] = { + // float formats + DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_SNORM, + DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R16G16_UNORM, + DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32_FLOAT, + DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R32G32B32A32_FLOAT, - // integer formats - DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_UNKNOWN, + // integer formats + DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_SINT, + DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R16G16_UINT, + DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UINT, + DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_UNKNOWN, }; DXGI_FORMAT VarToD3D(VarType t, int size, bool integer) { - DXGI_FORMAT retval = d3d_format_lookup[static_cast(t) + 5 * (size-1) + 5 * 4 * static_cast(integer)]; - if (retval == DXGI_FORMAT_UNKNOWN) - { - PanicAlert("VarToD3D: Invalid type/size combo %i , %i, %i", static_cast(t), size, static_cast(integer)); - } - return retval; + DXGI_FORMAT retval = + d3d_format_lookup[static_cast(t) + 5 * (size - 1) + 5 * 4 * static_cast(integer)]; + if (retval == DXGI_FORMAT_UNKNOWN) + { + PanicAlert("VarToD3D: Invalid type/size combo %i , %i, %i", static_cast(t), size, + static_cast(integer)); + } + return retval; } D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& vtx_decl) { - this->vtx_decl = vtx_decl; + this->vtx_decl = vtx_decl; - AddInputElementDescFromAttributeFormatIfValid(&vtx_decl.position, "POSITION", 0); + AddInputElementDescFromAttributeFormatIfValid(&vtx_decl.position, "POSITION", 0); - for (int i = 0; i < 3; i++) - { - AddInputElementDescFromAttributeFormatIfValid(&vtx_decl.normals[i], "NORMAL", i); - } + for (int i = 0; i < 3; i++) + { + AddInputElementDescFromAttributeFormatIfValid(&vtx_decl.normals[i], "NORMAL", i); + } - for (int i = 0; i < 2; i++) - { - AddInputElementDescFromAttributeFormatIfValid(&vtx_decl.colors[i], "COLOR", i); - } + for (int i = 0; i < 2; i++) + { + AddInputElementDescFromAttributeFormatIfValid(&vtx_decl.colors[i], "COLOR", i); + } - for (int i = 0; i < 8; i++) - { - AddInputElementDescFromAttributeFormatIfValid(&vtx_decl.texcoords[i], "TEXCOORD", i); - } + for (int i = 0; i < 8; i++) + { + AddInputElementDescFromAttributeFormatIfValid(&vtx_decl.texcoords[i], "TEXCOORD", i); + } - AddInputElementDescFromAttributeFormatIfValid(&vtx_decl.posmtx, "BLENDINDICES", 0); + AddInputElementDescFromAttributeFormatIfValid(&vtx_decl.posmtx, "BLENDINDICES", 0); - m_layout12.NumElements = m_num_elems; - m_layout12.pInputElementDescs = m_elems.data(); + m_layout12.NumElements = m_num_elems; + m_layout12.pInputElementDescs = m_elems.data(); } D3DVertexFormat::~D3DVertexFormat() { } -void D3DVertexFormat::AddInputElementDescFromAttributeFormatIfValid(const AttributeFormat* format, const char* semantic_name, unsigned int semantic_index) +void D3DVertexFormat::AddInputElementDescFromAttributeFormatIfValid(const AttributeFormat* format, + const char* semantic_name, + unsigned int semantic_index) { - if (!format->enable) - { - return; - } + if (!format->enable) + { + return; + } - D3D12_INPUT_ELEMENT_DESC desc = {}; + D3D12_INPUT_ELEMENT_DESC desc = {}; - desc.AlignedByteOffset = format->offset; - desc.Format = VarToD3D(format->type, format->components, format->integer); - desc.InputSlot = 0; - desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; - desc.SemanticName = semantic_name; - desc.SemanticIndex = semantic_index; + desc.AlignedByteOffset = format->offset; + desc.Format = VarToD3D(format->type, format->components, format->integer); + desc.InputSlot = 0; + desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; + desc.SemanticName = semantic_name; + desc.SemanticIndex = semantic_index; - m_elems[m_num_elems] = desc; - ++m_num_elems; + m_elems[m_num_elems] = desc; + ++m_num_elems; } void D3DVertexFormat::SetupVertexPointers() { - // No-op on DX12. + // No-op on DX12. } D3D12_INPUT_LAYOUT_DESC D3DVertexFormat::GetActiveInputLayout12() const { - return m_layout12; + return m_layout12; } - -} // namespace DX12 +} // namespace DX12 diff --git a/Source/Core/VideoBackends/D3D12/NativeVertexFormat.h b/Source/Core/VideoBackends/D3D12/NativeVertexFormat.h index 7b7daf19e8..b0eb1eff27 100644 --- a/Source/Core/VideoBackends/D3D12/NativeVertexFormat.h +++ b/Source/Core/VideoBackends/D3D12/NativeVertexFormat.h @@ -9,23 +9,24 @@ namespace DX12 { - class D3DVertexFormat final : public NativeVertexFormat { public: - D3DVertexFormat(const PortableVertexDeclaration& vtx_decl); - ~D3DVertexFormat(); + D3DVertexFormat(const PortableVertexDeclaration& vtx_decl); + ~D3DVertexFormat(); - void SetupVertexPointers() override; + void SetupVertexPointers() override; - D3D12_INPUT_LAYOUT_DESC GetActiveInputLayout12() const; + D3D12_INPUT_LAYOUT_DESC GetActiveInputLayout12() const; private: - void AddInputElementDescFromAttributeFormatIfValid(const AttributeFormat* format, const char* semantic_name, unsigned int semantic_index); + void AddInputElementDescFromAttributeFormatIfValid(const AttributeFormat* format, + const char* semantic_name, + unsigned int semantic_index); - std::array m_elems{}; - UINT m_num_elems = 0; + std::array m_elems{}; + UINT m_num_elems = 0; - D3D12_INPUT_LAYOUT_DESC m_layout12{}; + D3D12_INPUT_LAYOUT_DESC m_layout12{}; }; } diff --git a/Source/Core/VideoBackends/D3D12/PSTextureEncoder.cpp b/Source/Core/VideoBackends/D3D12/PSTextureEncoder.cpp index fda14dd7e1..76e19777ab 100644 --- a/Source/Core/VideoBackends/D3D12/PSTextureEncoder.cpp +++ b/Source/Core/VideoBackends/D3D12/PSTextureEncoder.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoBackends/D3D12/PSTextureEncoder.h" #include "Core/HW/Memmap.h" #include "VideoBackends/D3D12/D3DBase.h" #include "VideoBackends/D3D12/D3DCommandListManager.h" @@ -10,7 +11,6 @@ #include "VideoBackends/D3D12/D3DState.h" #include "VideoBackends/D3D12/D3DUtil.h" #include "VideoBackends/D3D12/FramebufferManager.h" -#include "VideoBackends/D3D12/PSTextureEncoder.h" #include "VideoBackends/D3D12/Render.h" #include "VideoBackends/D3D12/StaticShaderCache.h" #include "VideoBackends/D3D12/TextureCache.h" @@ -19,13 +19,12 @@ namespace DX12 { - struct EFBEncodeParams { - DWORD SrcLeft; - DWORD SrcTop; - DWORD DestWidth; - DWORD ScaleFactor; + DWORD SrcLeft; + DWORD SrcTop; + DWORD DestWidth; + DWORD ScaleFactor; }; PSTextureEncoder::PSTextureEncoder() @@ -34,268 +33,241 @@ PSTextureEncoder::PSTextureEncoder() void PSTextureEncoder::Init() { - // Create output texture RGBA format - D3D12_RESOURCE_DESC out_tex_desc = CD3DX12_RESOURCE_DESC::Tex2D( - DXGI_FORMAT_B8G8R8A8_UNORM, - EFB_WIDTH * 4, - EFB_HEIGHT / 4, - 1, - 0, - 1, - 0, - D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET - ); + // Create output texture RGBA format + D3D12_RESOURCE_DESC out_tex_desc = + CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_B8G8R8A8_UNORM, EFB_WIDTH * 4, EFB_HEIGHT / 4, 1, 0, + 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); - D3D12_CLEAR_VALUE optimized_clear_value = { DXGI_FORMAT_B8G8R8A8_UNORM, { 0.0f, 0.0f, 0.0f, 1.0f } }; + D3D12_CLEAR_VALUE optimized_clear_value = {DXGI_FORMAT_B8G8R8A8_UNORM, {0.0f, 0.0f, 0.0f, 1.0f}}; - CheckHR( - D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), - D3D12_HEAP_FLAG_NONE, - &out_tex_desc, - D3D12_RESOURCE_STATE_COPY_SOURCE, - &optimized_clear_value, - IID_PPV_ARGS(&m_out) - ) - ); + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &out_tex_desc, + D3D12_RESOURCE_STATE_COPY_SOURCE, &optimized_clear_value, IID_PPV_ARGS(&m_out))); - D3D::SetDebugObjectName12(m_out, "efb encoder output texture"); + D3D::SetDebugObjectName12(m_out, "efb encoder output texture"); - // Create output render target view - D3D12_RENDER_TARGET_VIEW_DESC tex_rtv_desc = { - DXGI_FORMAT_B8G8R8A8_UNORM, // DXGI_FORMAT Format; - D3D12_RTV_DIMENSION_TEXTURE2D // D3D12_RTV_DIMENSION ViewDimension; - }; + // Create output render target view + D3D12_RENDER_TARGET_VIEW_DESC tex_rtv_desc = { + DXGI_FORMAT_B8G8R8A8_UNORM, // DXGI_FORMAT Format; + D3D12_RTV_DIMENSION_TEXTURE2D // D3D12_RTV_DIMENSION ViewDimension; + }; - tex_rtv_desc.Texture2D.MipSlice = 0; + tex_rtv_desc.Texture2D.MipSlice = 0; - D3D::rtv_descriptor_heap_mgr->Allocate(&m_out_rtv_cpu); - D3D::device12->CreateRenderTargetView(m_out, &tex_rtv_desc, m_out_rtv_cpu); + D3D::rtv_descriptor_heap_mgr->Allocate(&m_out_rtv_cpu); + D3D::device12->CreateRenderTargetView(m_out, &tex_rtv_desc, m_out_rtv_cpu); - // Create output staging buffer - CheckHR( - D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Buffer( - D3D::AlignValue(static_cast(out_tex_desc.Width) * 4, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * - out_tex_desc.Height - ), - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(&m_out_readback_buffer) - ) - ); + // Create output staging buffer + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer( + D3D::AlignValue(static_cast(out_tex_desc.Width) * 4, + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * + out_tex_desc.Height), + D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_out_readback_buffer))); - D3D::SetDebugObjectName12(m_out_readback_buffer, "efb encoder output staging buffer"); + D3D::SetDebugObjectName12(m_out_readback_buffer, "efb encoder output staging buffer"); - // Create constant buffer for uploading data to shaders. Need to align to 256 bytes. - unsigned int encode_params_buffer_size = (sizeof(EFBEncodeParams) + 0xff) & ~0xff; + // Create constant buffer for uploading data to shaders. Need to align to 256 bytes. + unsigned int encode_params_buffer_size = (sizeof(EFBEncodeParams) + 0xff) & ~0xff; - CheckHR( - D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Buffer(encode_params_buffer_size), - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, - IID_PPV_ARGS(&m_encode_params_buffer) - ) - ); + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer(encode_params_buffer_size), D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, IID_PPV_ARGS(&m_encode_params_buffer))); - D3D::SetDebugObjectName12(m_encode_params_buffer, "efb encoder params buffer"); + D3D::SetDebugObjectName12(m_encode_params_buffer, "efb encoder params buffer"); - // NOTE: This upload buffer is okay to overwrite each time, since we block until completion when it's used anyway. - D3D12_RANGE read_range = {}; - CheckHR(m_encode_params_buffer->Map(0, &read_range, &m_encode_params_buffer_data)); + // NOTE: This upload buffer is okay to overwrite each time, since we block until completion when + // it's used anyway. + D3D12_RANGE read_range = {}; + CheckHR(m_encode_params_buffer->Map(0, &read_range, &m_encode_params_buffer_data)); - m_ready = true; + m_ready = true; } void PSTextureEncoder::Shutdown() { - m_ready = false; + m_ready = false; - D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_out); - D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_out_readback_buffer); - D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_encode_params_buffer); + D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_out); + D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_out_readback_buffer); + D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_encode_params_buffer); - for (auto& it : m_static_shaders_blobs) - { - SAFE_RELEASE(it); - } + for (auto& it : m_static_shaders_blobs) + { + SAFE_RELEASE(it); + } - m_static_shaders_blobs.clear(); - m_static_shaders_map.clear(); + m_static_shaders_blobs.clear(); + m_static_shaders_map.clear(); } -void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat src_format, const EFBRectangle& src_rect, - bool is_intensity, bool scale_by_half) +void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, + PEControl::PixelFormat src_format, const EFBRectangle& src_rect, + bool is_intensity, bool scale_by_half) { - if (!m_ready) // Make sure we initialized OK - return; + if (!m_ready) // Make sure we initialized OK + return; - D3D::command_list_mgr->CPUAccessNotify(); + D3D::command_list_mgr->CPUAccessNotify(); - // Resolve MSAA targets before copying. - D3DTexture2D* efb_source = (src_format == PEControl::Z24) ? - FramebufferManager::GetResolvedEFBDepthTexture() : - // EXISTINGD3D11TODO: Instead of resolving EFB, it would be better to pick out a - // single sample from each pixel. The game may break if it isn't - // expecting the blurred edges around multisampled shapes. - FramebufferManager::GetResolvedEFBColorTexture(); + // Resolve MSAA targets before copying. + D3DTexture2D* efb_source = + (src_format == PEControl::Z24) ? + FramebufferManager::GetResolvedEFBDepthTexture() : + // EXISTINGD3D11TODO: Instead of resolving EFB, it would be better to pick out a + // single sample from each pixel. The game may break if it isn't + // expecting the blurred edges around multisampled shapes. + FramebufferManager::GetResolvedEFBColorTexture(); - // GetResolvedEFBDepthTexture will set the render targets, when MSAA is enabled - // (since it needs to do a manual depth resolve). So make sure to set the RTs - // afterwards. + // GetResolvedEFBDepthTexture will set the render targets, when MSAA is enabled + // (since it needs to do a manual depth resolve). So make sure to set the RTs + // afterwards. - const u32 words_per_row = bytes_per_row / sizeof(u32); + const u32 words_per_row = bytes_per_row / sizeof(u32); - D3D::SetViewportAndScissor(0, 0, words_per_row, num_blocks_y); + D3D::SetViewportAndScissor(0, 0, words_per_row, num_blocks_y); - constexpr EFBRectangle full_src_rect(0, 0, EFB_WIDTH, EFB_HEIGHT); + constexpr EFBRectangle full_src_rect(0, 0, EFB_WIDTH, EFB_HEIGHT); - TargetRectangle target_rect = g_renderer->ConvertEFBRectangle(full_src_rect); + TargetRectangle target_rect = g_renderer->ConvertEFBRectangle(full_src_rect); - D3D::ResourceBarrier(D3D::current_command_list, m_out, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET, 0); - D3D::current_command_list->OMSetRenderTargets(1, &m_out_rtv_cpu, FALSE, nullptr); + D3D::ResourceBarrier(D3D::current_command_list, m_out, D3D12_RESOURCE_STATE_COPY_SOURCE, + D3D12_RESOURCE_STATE_RENDER_TARGET, 0); + D3D::current_command_list->OMSetRenderTargets(1, &m_out_rtv_cpu, FALSE, nullptr); - EFBEncodeParams params; - params.SrcLeft = src_rect.left; - params.SrcTop = src_rect.top; - params.DestWidth = native_width; - params.ScaleFactor = scale_by_half ? 2 : 1; + EFBEncodeParams params; + params.SrcLeft = src_rect.left; + params.SrcTop = src_rect.top; + params.DestWidth = native_width; + params.ScaleFactor = scale_by_half ? 2 : 1; - memcpy(m_encode_params_buffer_data, ¶ms, sizeof(params)); - D3D::current_command_list->SetGraphicsRootConstantBufferView( - DESCRIPTOR_TABLE_PS_CBVONE, - m_encode_params_buffer->GetGPUVirtualAddress() - ); + memcpy(m_encode_params_buffer_data, ¶ms, sizeof(params)); + D3D::current_command_list->SetGraphicsRootConstantBufferView( + DESCRIPTOR_TABLE_PS_CBVONE, m_encode_params_buffer->GetGPUVirtualAddress()); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, true); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, true); - // Use linear filtering if (bScaleByHalf), use point filtering otherwise - if (scale_by_half) - D3D::SetLinearCopySampler(); - else - D3D::SetPointCopySampler(); + // Use linear filtering if (bScaleByHalf), use point filtering otherwise + if (scale_by_half) + D3D::SetLinearCopySampler(); + else + D3D::SetPointCopySampler(); - D3D::DrawShadedTexQuad(efb_source, - target_rect.AsRECT(), - Renderer::GetTargetWidth(), - Renderer::GetTargetHeight(), - SetStaticShader(format, src_format, is_intensity, scale_by_half), - StaticShaderCache::GetSimpleVertexShader(), - StaticShaderCache::GetSimpleVertexShaderInputLayout(), - D3D12_SHADER_BYTECODE(), - 1.0f, - 0, - DXGI_FORMAT_B8G8R8A8_UNORM, - false, - false /* Render target is not multisampled */ - ); + D3D::DrawShadedTexQuad( + efb_source, target_rect.AsRECT(), Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), + SetStaticShader(format, src_format, is_intensity, scale_by_half), + StaticShaderCache::GetSimpleVertexShader(), + StaticShaderCache::GetSimpleVertexShaderInputLayout(), D3D12_SHADER_BYTECODE(), 1.0f, 0, + DXGI_FORMAT_B8G8R8A8_UNORM, false, false /* Render target is not multisampled */ + ); - // Copy to staging buffer - D3D12_BOX src_box = CD3DX12_BOX(0, 0, 0, words_per_row, num_blocks_y, 1); + // Copy to staging buffer + D3D12_BOX src_box = CD3DX12_BOX(0, 0, 0, words_per_row, num_blocks_y, 1); - D3D12_TEXTURE_COPY_LOCATION dst_location = {}; - dst_location.pResource = m_out_readback_buffer; - dst_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - dst_location.PlacedFootprint.Offset = 0; - dst_location.PlacedFootprint.Footprint.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - dst_location.PlacedFootprint.Footprint.Width = EFB_WIDTH * 4; - dst_location.PlacedFootprint.Footprint.Height = EFB_HEIGHT / 4; - dst_location.PlacedFootprint.Footprint.Depth = 1; - dst_location.PlacedFootprint.Footprint.RowPitch = D3D::AlignValue(dst_location.PlacedFootprint.Footprint.Width * 4, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + D3D12_TEXTURE_COPY_LOCATION dst_location = {}; + dst_location.pResource = m_out_readback_buffer; + dst_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + dst_location.PlacedFootprint.Offset = 0; + dst_location.PlacedFootprint.Footprint.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + dst_location.PlacedFootprint.Footprint.Width = EFB_WIDTH * 4; + dst_location.PlacedFootprint.Footprint.Height = EFB_HEIGHT / 4; + dst_location.PlacedFootprint.Footprint.Depth = 1; + dst_location.PlacedFootprint.Footprint.RowPitch = D3D::AlignValue( + dst_location.PlacedFootprint.Footprint.Width * 4, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); - D3D12_TEXTURE_COPY_LOCATION src_location = {}; - src_location.pResource = m_out; - src_location.SubresourceIndex = 0; - src_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + D3D12_TEXTURE_COPY_LOCATION src_location = {}; + src_location.pResource = m_out; + src_location.SubresourceIndex = 0; + src_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - D3D::ResourceBarrier(D3D::current_command_list, m_out, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE, 0); - D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, &src_box); + D3D::ResourceBarrier(D3D::current_command_list, m_out, D3D12_RESOURCE_STATE_RENDER_TARGET, + D3D12_RESOURCE_STATE_COPY_SOURCE, 0); + D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, &src_box); - FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); + FramebufferManager::GetEFBColorTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); - // State is automatically restored after executing command list. - D3D::command_list_mgr->ExecuteQueuedWork(true); + // State is automatically restored after executing command list. + D3D::command_list_mgr->ExecuteQueuedWork(true); - // Transfer staging buffer to GameCube/Wii RAM - void* readback_data_map; - D3D12_RANGE read_range = { 0, dst_location.PlacedFootprint.Footprint.RowPitch * num_blocks_y }; - CheckHR(m_out_readback_buffer->Map(0, &read_range, &readback_data_map)); + // Transfer staging buffer to GameCube/Wii RAM + void* readback_data_map; + D3D12_RANGE read_range = {0, dst_location.PlacedFootprint.Footprint.RowPitch * num_blocks_y}; + CheckHR(m_out_readback_buffer->Map(0, &read_range, &readback_data_map)); - u8* src = static_cast(readback_data_map); - u32 read_stride = std::min(bytes_per_row, dst_location.PlacedFootprint.Footprint.RowPitch); - for (unsigned int y = 0; y < num_blocks_y; ++y) - { - memcpy(dst, src, read_stride); + u8* src = static_cast(readback_data_map); + u32 read_stride = std::min(bytes_per_row, dst_location.PlacedFootprint.Footprint.RowPitch); + for (unsigned int y = 0; y < num_blocks_y; ++y) + { + memcpy(dst, src, read_stride); - dst += memory_stride; - src += dst_location.PlacedFootprint.Footprint.RowPitch; - } + dst += memory_stride; + src += dst_location.PlacedFootprint.Footprint.RowPitch; + } - D3D12_RANGE write_range = {}; - m_out_readback_buffer->Unmap(0, &write_range); + D3D12_RANGE write_range = {}; + m_out_readback_buffer->Unmap(0, &write_range); } -D3D12_SHADER_BYTECODE PSTextureEncoder::SetStaticShader(unsigned int dst_format, PEControl::PixelFormat src_format, - bool is_intensity, bool scale_by_half) +D3D12_SHADER_BYTECODE PSTextureEncoder::SetStaticShader(unsigned int dst_format, + PEControl::PixelFormat src_format, + bool is_intensity, bool scale_by_half) { - size_t fetch_num = static_cast(src_format); - size_t scaled_fetch_num = scale_by_half ? 1 : 0; - size_t intensity_num = is_intensity ? 1 : 0; - size_t generator_num = dst_format; + size_t fetch_num = static_cast(src_format); + size_t scaled_fetch_num = scale_by_half ? 1 : 0; + size_t intensity_num = is_intensity ? 1 : 0; + size_t generator_num = dst_format; - ComboKey key = MakeComboKey(dst_format, src_format, is_intensity, scale_by_half); + ComboKey key = MakeComboKey(dst_format, src_format, is_intensity, scale_by_half); - ComboMap::iterator it = m_static_shaders_map.find(key); - if (it == m_static_shaders_map.end()) - { - INFO_LOG(VIDEO, "Compiling efb encoding shader for dst_format 0x%X, src_format %d, is_intensity %d, scale_by_half %d", - dst_format, static_cast(src_format), is_intensity ? 1 : 0, scale_by_half ? 1 : 0); + ComboMap::iterator it = m_static_shaders_map.find(key); + if (it == m_static_shaders_map.end()) + { + INFO_LOG(VIDEO, "Compiling efb encoding shader for dst_format 0x%X, src_format %d, " + "is_intensity %d, scale_by_half %d", + dst_format, static_cast(src_format), is_intensity ? 1 : 0, scale_by_half ? 1 : 0); - u32 format = dst_format; + u32 format = dst_format; - if (src_format == PEControl::Z24) - { - format |= _GX_TF_ZTF; - if (dst_format == 11) - format = GX_TF_Z16; - else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) - format |= _GX_TF_CTF; - } - else - { - if (dst_format > GX_TF_RGBA8 || (dst_format < GX_TF_RGB565 && !is_intensity)) - format |= _GX_TF_CTF; - } + if (src_format == PEControl::Z24) + { + format |= _GX_TF_ZTF; + if (dst_format == 11) + format = GX_TF_Z16; + else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) + format |= _GX_TF_CTF; + } + else + { + if (dst_format > GX_TF_RGBA8 || (dst_format < GX_TF_RGB565 && !is_intensity)) + format |= _GX_TF_CTF; + } - ID3DBlob* bytecode = nullptr; - const char* shader = TextureConversionShader::GenerateEncodingShader(format, API_D3D); - if (!D3D::CompilePixelShader(shader, &bytecode)) - { - WARN_LOG(VIDEO, "EFB encoder shader for dst_format 0x%X, src_format %d, is_intensity %d, scale_by_half %d failed to compile", - dst_format, static_cast(src_format), is_intensity ? 1 : 0, scale_by_half ? 1 : 0); - m_static_shaders_blobs[key] = {}; - return {}; - } + ID3DBlob* bytecode = nullptr; + const char* shader = TextureConversionShader::GenerateEncodingShader(format, API_D3D); + if (!D3D::CompilePixelShader(shader, &bytecode)) + { + WARN_LOG(VIDEO, "EFB encoder shader for dst_format 0x%X, src_format %d, is_intensity %d, " + "scale_by_half %d failed to compile", + dst_format, static_cast(src_format), is_intensity ? 1 : 0, + scale_by_half ? 1 : 0); + m_static_shaders_blobs[key] = {}; + return {}; + } - D3D12_SHADER_BYTECODE new_shader = { - bytecode->GetBufferPointer(), - bytecode->GetBufferSize() - }; + D3D12_SHADER_BYTECODE new_shader = {bytecode->GetBufferPointer(), bytecode->GetBufferSize()}; - it = m_static_shaders_map.emplace(key, new_shader).first; + it = m_static_shaders_map.emplace(key, new_shader).first; - // Keep track of the ID3DBlobs, so we can free them upon shutdown. - m_static_shaders_blobs.push_back(bytecode); - } + // Keep track of the ID3DBlobs, so we can free them upon shutdown. + m_static_shaders_blobs.push_back(bytecode); + } - return it->second; + return it->second; } - } diff --git a/Source/Core/VideoBackends/D3D12/PSTextureEncoder.h b/Source/Core/VideoBackends/D3D12/PSTextureEncoder.h index 1e42a87f6a..67f6927d97 100644 --- a/Source/Core/VideoBackends/D3D12/PSTextureEncoder.h +++ b/Source/Core/VideoBackends/D3D12/PSTextureEncoder.h @@ -10,43 +10,41 @@ namespace DX12 { - class PSTextureEncoder final : public TextureEncoder { public: - PSTextureEncoder(); + PSTextureEncoder(); - void Init(); - void Shutdown(); - void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat src_format, const EFBRectangle& src_rect, - bool is_intensity, bool scale_by_half); + void Init(); + void Shutdown(); + void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, + u32 memory_stride, PEControl::PixelFormat src_format, const EFBRectangle& src_rect, + bool is_intensity, bool scale_by_half); private: - bool m_ready = false; + bool m_ready = false; - ID3D12Resource* m_out = nullptr; - D3D12_CPU_DESCRIPTOR_HANDLE m_out_rtv_cpu = {}; + ID3D12Resource* m_out = nullptr; + D3D12_CPU_DESCRIPTOR_HANDLE m_out_rtv_cpu = {}; - ID3D12Resource* m_out_readback_buffer = nullptr; + ID3D12Resource* m_out_readback_buffer = nullptr; - ID3D12Resource* m_encode_params_buffer = nullptr; - void* m_encode_params_buffer_data = nullptr; + ID3D12Resource* m_encode_params_buffer = nullptr; + void* m_encode_params_buffer_data = nullptr; - D3D12_SHADER_BYTECODE SetStaticShader(unsigned int dst_format, - PEControl::PixelFormat src_format, bool is_intensity, bool scale_by_half); + D3D12_SHADER_BYTECODE SetStaticShader(unsigned int dst_format, PEControl::PixelFormat src_format, + bool is_intensity, bool scale_by_half); - using ComboKey = unsigned int; // Key for a shader combination - static ComboKey MakeComboKey(unsigned int dst_format, - PEControl::PixelFormat src_format, bool is_intensity, bool scale_by_half) - { - return (dst_format << 4) | (static_cast(src_format) << 2) | (is_intensity ? (1 << 1) : 0) - | (scale_by_half ? (1 << 0) : 0); - } + using ComboKey = unsigned int; // Key for a shader combination + static ComboKey MakeComboKey(unsigned int dst_format, PEControl::PixelFormat src_format, + bool is_intensity, bool scale_by_half) + { + return (dst_format << 4) | (static_cast(src_format) << 2) | (is_intensity ? (1 << 1) : 0) | + (scale_by_half ? (1 << 0) : 0); + } - using ComboMap = std::map; - ComboMap m_static_shaders_map; - std::vector m_static_shaders_blobs; + using ComboMap = std::map; + ComboMap m_static_shaders_map; + std::vector m_static_shaders_blobs; }; - } diff --git a/Source/Core/VideoBackends/D3D12/PerfQuery.cpp b/Source/Core/VideoBackends/D3D12/PerfQuery.cpp index 5f4b5508e5..4794b134c1 100644 --- a/Source/Core/VideoBackends/D3D12/PerfQuery.cpp +++ b/Source/Core/VideoBackends/D3D12/PerfQuery.cpp @@ -14,203 +14,210 @@ namespace DX12 { - PerfQuery::PerfQuery() { - D3D12_QUERY_HEAP_DESC desc = { D3D12_QUERY_HEAP_TYPE_OCCLUSION, PERF_QUERY_BUFFER_SIZE, 0 }; - CheckHR(D3D::device12->CreateQueryHeap(&desc, IID_PPV_ARGS(&m_query_heap))); + D3D12_QUERY_HEAP_DESC desc = {D3D12_QUERY_HEAP_TYPE_OCCLUSION, PERF_QUERY_BUFFER_SIZE, 0}; + CheckHR(D3D::device12->CreateQueryHeap(&desc, IID_PPV_ARGS(&m_query_heap))); - CheckHR(D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Buffer(QUERY_READBACK_BUFFER_SIZE), - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(&m_query_readback_buffer))); + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer(QUERY_READBACK_BUFFER_SIZE), D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, IID_PPV_ARGS(&m_query_readback_buffer))); - m_tracking_fence = D3D::command_list_mgr->RegisterQueueFenceCallback(this, &PerfQuery::QueueFenceCallback); + m_tracking_fence = + D3D::command_list_mgr->RegisterQueueFenceCallback(this, &PerfQuery::QueueFenceCallback); } PerfQuery::~PerfQuery() { - D3D::command_list_mgr->RemoveQueueFenceCallback(this); + D3D::command_list_mgr->RemoveQueueFenceCallback(this); - SAFE_RELEASE(m_query_heap); - SAFE_RELEASE(m_query_readback_buffer); + SAFE_RELEASE(m_query_heap); + SAFE_RELEASE(m_query_readback_buffer); } void PerfQuery::EnableQuery(PerfQueryGroup type) { - if (m_query_count > m_query_buffer.size() / 2) - WeakFlush(); + if (m_query_count > m_query_buffer.size() / 2) + WeakFlush(); - // all queries already used? - if (m_query_buffer.size() == m_query_count) - { - FlushOne(); - //WARN_LOG(VIDEO, "Flushed query buffer early!"); - } + // all queries already used? + if (m_query_buffer.size() == m_query_count) + { + FlushOne(); + // WARN_LOG(VIDEO, "Flushed query buffer early!"); + } - if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) - { - size_t index = (m_query_read_pos + m_query_count) % m_query_buffer.size(); - auto& entry = m_query_buffer[index]; + if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) + { + size_t index = (m_query_read_pos + m_query_count) % m_query_buffer.size(); + auto& entry = m_query_buffer[index]; - D3D::current_command_list->BeginQuery(m_query_heap, D3D12_QUERY_TYPE_OCCLUSION, static_cast(index)); - entry.query_type = type; - entry.fence_value = -1; + D3D::current_command_list->BeginQuery(m_query_heap, D3D12_QUERY_TYPE_OCCLUSION, + static_cast(index)); + entry.query_type = type; + entry.fence_value = -1; - ++m_query_count; - } + ++m_query_count; + } } void PerfQuery::DisableQuery(PerfQueryGroup type) { - if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) - { - size_t index = (m_query_read_pos + m_query_count + m_query_buffer.size() - 1) % m_query_buffer.size(); - auto& entry = m_query_buffer[index]; + if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) + { + size_t index = + (m_query_read_pos + m_query_count + m_query_buffer.size() - 1) % m_query_buffer.size(); + auto& entry = m_query_buffer[index]; - D3D::current_command_list->EndQuery(m_query_heap, D3D12_QUERY_TYPE_OCCLUSION, static_cast(index)); - D3D::current_command_list->ResolveQueryData(m_query_heap, D3D12_QUERY_TYPE_OCCLUSION, static_cast(index), 1, m_query_readback_buffer, index * sizeof(UINT64)); - entry.fence_value = m_next_fence_value; - } + D3D::current_command_list->EndQuery(m_query_heap, D3D12_QUERY_TYPE_OCCLUSION, + static_cast(index)); + D3D::current_command_list->ResolveQueryData(m_query_heap, D3D12_QUERY_TYPE_OCCLUSION, + static_cast(index), 1, + m_query_readback_buffer, index * sizeof(UINT64)); + entry.fence_value = m_next_fence_value; + } } void PerfQuery::ResetQuery() { - m_query_count = 0; - std::fill_n(m_results, ArraySize(m_results), 0); + m_query_count = 0; + std::fill_n(m_results, ArraySize(m_results), 0); } u32 PerfQuery::GetQueryResult(PerfQueryType type) { - u32 result = 0; + u32 result = 0; - if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC) - result = m_results[PQG_ZCOMP_ZCOMPLOC]; - else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT) - result = m_results[PQG_ZCOMP]; - else if (type == PQ_BLEND_INPUT) - result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC]; - else if (type == PQ_EFB_COPY_CLOCKS) - result = m_results[PQG_EFB_COPY_CLOCKS]; + if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC) + result = m_results[PQG_ZCOMP_ZCOMPLOC]; + else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT) + result = m_results[PQG_ZCOMP]; + else if (type == PQ_BLEND_INPUT) + result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC]; + else if (type == PQ_EFB_COPY_CLOCKS) + result = m_results[PQG_EFB_COPY_CLOCKS]; - return result / 4; + return result / 4; } void PerfQuery::FlushOne() { - size_t index = m_query_read_pos; - ActiveQuery& entry = m_query_buffer[index]; + size_t index = m_query_read_pos; + ActiveQuery& entry = m_query_buffer[index]; - // Has the command list been executed yet? - if (entry.fence_value == m_next_fence_value) - D3D::command_list_mgr->ExecuteQueuedWork(false); + // Has the command list been executed yet? + if (entry.fence_value == m_next_fence_value) + D3D::command_list_mgr->ExecuteQueuedWork(false); - // Block until the fence is reached - D3D::command_list_mgr->WaitOnCPUForFence(m_tracking_fence, entry.fence_value); + // Block until the fence is reached + D3D::command_list_mgr->WaitOnCPUForFence(m_tracking_fence, entry.fence_value); - // Copy from readback buffer to local - void* readback_buffer_map; - D3D12_RANGE read_range = { sizeof(UINT64) * index, sizeof(UINT64) * (index + 1) }; - CheckHR(m_query_readback_buffer->Map(0, &read_range, &readback_buffer_map)); + // Copy from readback buffer to local + void* readback_buffer_map; + D3D12_RANGE read_range = {sizeof(UINT64) * index, sizeof(UINT64) * (index + 1)}; + CheckHR(m_query_readback_buffer->Map(0, &read_range, &readback_buffer_map)); - UINT64 result; - memcpy(&result, reinterpret_cast(readback_buffer_map) + sizeof(UINT64) * index, sizeof(UINT64)); + UINT64 result; + memcpy(&result, reinterpret_cast(readback_buffer_map) + sizeof(UINT64) * index, + sizeof(UINT64)); - D3D12_RANGE write_range = {}; - m_query_readback_buffer->Unmap(0, &write_range); + D3D12_RANGE write_range = {}; + m_query_readback_buffer->Unmap(0, &write_range); - // NOTE: Reported pixel metrics should be referenced to native resolution - m_results[entry.query_type] += (u32)(result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight()); + // NOTE: Reported pixel metrics should be referenced to native resolution + m_results[entry.query_type] += (u32)(result * EFB_WIDTH / g_renderer->GetTargetWidth() * + EFB_HEIGHT / g_renderer->GetTargetHeight()); - m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size(); - m_query_count--; + m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size(); + m_query_count--; } UINT64 PerfQuery::FindLastPendingFenceValue() const { - UINT64 last_fence_value = 0; - u32 query_count = m_query_count; - u32 query_read_pos = m_query_read_pos; - while (query_count > 0) - { - const ActiveQuery& entry = m_query_buffer[query_read_pos]; + UINT64 last_fence_value = 0; + u32 query_count = m_query_count; + u32 query_read_pos = m_query_read_pos; + while (query_count > 0) + { + const ActiveQuery& entry = m_query_buffer[query_read_pos]; - last_fence_value = std::max(entry.fence_value, last_fence_value); - query_read_pos = (query_read_pos + 1) % m_query_buffer.size(); - query_count--; - } + last_fence_value = std::max(entry.fence_value, last_fence_value); + query_read_pos = (query_read_pos + 1) % m_query_buffer.size(); + query_count--; + } - return last_fence_value; + return last_fence_value; } void PerfQuery::FlushResults() { - if (IsFlushed()) - return; + if (IsFlushed()) + return; - // Find the fence value we have to wait for. - UINT64 last_fence_value = FindLastPendingFenceValue(); - if (last_fence_value == m_next_fence_value) - D3D::command_list_mgr->ExecuteQueuedWork(false); + // Find the fence value we have to wait for. + UINT64 last_fence_value = FindLastPendingFenceValue(); + if (last_fence_value == m_next_fence_value) + D3D::command_list_mgr->ExecuteQueuedWork(false); - // Wait for all queries to be resolved. - D3D::command_list_mgr->WaitOnCPUForFence(m_tracking_fence, last_fence_value); + // Wait for all queries to be resolved. + D3D::command_list_mgr->WaitOnCPUForFence(m_tracking_fence, last_fence_value); - // Map the whole readback buffer. Shouldn't have much overhead, and saves taking the wrapped-around cases into consideration. - void* readback_buffer_map; - D3D12_RANGE read_range = { 0, QUERY_READBACK_BUFFER_SIZE }; - CheckHR(m_query_readback_buffer->Map(0, &read_range, &readback_buffer_map)); + // Map the whole readback buffer. Shouldn't have much overhead, and saves taking the + // wrapped-around cases into consideration. + void* readback_buffer_map; + D3D12_RANGE read_range = {0, QUERY_READBACK_BUFFER_SIZE}; + CheckHR(m_query_readback_buffer->Map(0, &read_range, &readback_buffer_map)); - // Read all pending queries. - while (m_query_count > 0) - { - ActiveQuery& entry = m_query_buffer[m_query_read_pos]; + // Read all pending queries. + while (m_query_count > 0) + { + ActiveQuery& entry = m_query_buffer[m_query_read_pos]; - UINT64 result; - memcpy(&result, reinterpret_cast(readback_buffer_map) + sizeof(UINT64) * m_query_read_pos, sizeof(UINT64)); + UINT64 result; + memcpy(&result, reinterpret_cast(readback_buffer_map) + sizeof(UINT64) * m_query_read_pos, + sizeof(UINT64)); - // NOTE: Reported pixel metrics should be referenced to native resolution - m_results[entry.query_type] += (u32)(result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight()); + // NOTE: Reported pixel metrics should be referenced to native resolution + m_results[entry.query_type] += (u32)(result * EFB_WIDTH / g_renderer->GetTargetWidth() * + EFB_HEIGHT / g_renderer->GetTargetHeight()); - m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size(); - m_query_count--; - } + m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size(); + m_query_count--; + } - D3D12_RANGE write_range = {}; - m_query_readback_buffer->Unmap(0, &write_range); + D3D12_RANGE write_range = {}; + m_query_readback_buffer->Unmap(0, &write_range); } void PerfQuery::WeakFlush() { - UINT64 completed_fence = m_tracking_fence->GetCompletedValue(); + UINT64 completed_fence = m_tracking_fence->GetCompletedValue(); - while (!IsFlushed()) - { - ActiveQuery& entry = m_query_buffer[m_query_read_pos]; - if (entry.fence_value > completed_fence) - break; + while (!IsFlushed()) + { + ActiveQuery& entry = m_query_buffer[m_query_read_pos]; + if (entry.fence_value > completed_fence) + break; - FlushOne(); - } + FlushOne(); + } } bool PerfQuery::IsFlushed() const { - return m_query_count == 0; + return m_query_count == 0; } void PerfQuery::QueueFenceCallback(void* owning_object, UINT64 fence_value) { - PerfQuery* owning_perf_query = static_cast(owning_object); - owning_perf_query->QueueFence(fence_value); + PerfQuery* owning_perf_query = static_cast(owning_object); + owning_perf_query->QueueFence(fence_value); } void PerfQuery::QueueFence(UINT64 fence_value) { - m_next_fence_value = fence_value + 1; + m_next_fence_value = fence_value + 1; } -} // namespace +} // namespace diff --git a/Source/Core/VideoBackends/D3D12/PerfQuery.h b/Source/Core/VideoBackends/D3D12/PerfQuery.h index 98760910f3..2b766900f4 100644 --- a/Source/Core/VideoBackends/D3D12/PerfQuery.h +++ b/Source/Core/VideoBackends/D3D12/PerfQuery.h @@ -11,50 +11,49 @@ namespace DX12 { - class PerfQuery final : public PerfQueryBase { public: - PerfQuery(); - ~PerfQuery(); + PerfQuery(); + ~PerfQuery(); - void EnableQuery(PerfQueryGroup type) override; - void DisableQuery(PerfQueryGroup type) override; - void ResetQuery() override; - u32 GetQueryResult(PerfQueryType type) override; - void FlushResults() override; - bool IsFlushed() const override; + void EnableQuery(PerfQueryGroup type) override; + void DisableQuery(PerfQueryGroup type) override; + void ResetQuery() override; + u32 GetQueryResult(PerfQueryType type) override; + void FlushResults() override; + bool IsFlushed() const override; private: - struct ActiveQuery - { - PerfQueryGroup query_type; - UINT64 fence_value; - }; + struct ActiveQuery + { + PerfQueryGroup query_type; + UINT64 fence_value; + }; - void WeakFlush(); + void WeakFlush(); - // Find the last fence value of all pending queries. - UINT64 FindLastPendingFenceValue() const; + // Find the last fence value of all pending queries. + UINT64 FindLastPendingFenceValue() const; - // Only use when non-empty - void FlushOne(); + // Only use when non-empty + void FlushOne(); - static void QueueFenceCallback(void* owning_object, UINT64 fence_value); - void QueueFence(UINT64 fence_value); + static void QueueFenceCallback(void* owning_object, UINT64 fence_value); + void QueueFence(UINT64 fence_value); - // when testing in SMS: 64 was too small, 128 was ok - static constexpr size_t PERF_QUERY_BUFFER_SIZE = 512; - static constexpr size_t QUERY_READBACK_BUFFER_SIZE = PERF_QUERY_BUFFER_SIZE * sizeof(UINT64); + // when testing in SMS: 64 was too small, 128 was ok + static constexpr size_t PERF_QUERY_BUFFER_SIZE = 512; + static constexpr size_t QUERY_READBACK_BUFFER_SIZE = PERF_QUERY_BUFFER_SIZE * sizeof(UINT64); - std::array m_query_buffer; - int m_query_read_pos = 0; + std::array m_query_buffer; + int m_query_read_pos = 0; - ID3D12QueryHeap* m_query_heap = nullptr; - ID3D12Resource* m_query_readback_buffer = nullptr; + ID3D12QueryHeap* m_query_heap = nullptr; + ID3D12Resource* m_query_readback_buffer = nullptr; - ID3D12Fence* m_tracking_fence = nullptr; - UINT64 m_next_fence_value = 0; + ID3D12Fence* m_tracking_fence = nullptr; + UINT64 m_next_fence_value = 0; }; -} // namespace +} // namespace diff --git a/Source/Core/VideoBackends/D3D12/Render.cpp b/Source/Core/VideoBackends/D3D12/Render.cpp index 17653bd193..f868b36f39 100644 --- a/Source/Core/VideoBackends/D3D12/Render.cpp +++ b/Source/Core/VideoBackends/D3D12/Render.cpp @@ -44,26 +44,25 @@ namespace DX12 { - static u32 s_last_multisamples = 1; static bool s_last_stereo_mode = false; static bool s_last_xfb_mode = false; enum CLEAR_BLEND_DESC { - CLEAR_BLEND_DESC_ALL_CHANNELS_ENABLED = 0, - CLEAR_BLEND_DESC_RGB_CHANNELS_ENABLED = 1, - CLEAR_BLEND_DESC_ALPHA_CHANNEL_ENABLED = 2, - CLEAR_BLEND_DESC_ALL_CHANNELS_DISABLED = 3 + CLEAR_BLEND_DESC_ALL_CHANNELS_ENABLED = 0, + CLEAR_BLEND_DESC_RGB_CHANNELS_ENABLED = 1, + CLEAR_BLEND_DESC_ALPHA_CHANNEL_ENABLED = 2, + CLEAR_BLEND_DESC_ALL_CHANNELS_DISABLED = 3 }; static D3D12_BLEND_DESC s_clear_blend_descs[4] = {}; enum CLEAR_DEPTH_DESC { - CLEAR_DEPTH_DESC_DEPTH_DISABLED = 0, - CLEAR_DEPTH_DESC_DEPTH_ENABLED_WRITES_ENABLED = 1, - CLEAR_DEPTH_DESC_DEPTH_ENABLED_WRITES_DISABLED = 2, + CLEAR_DEPTH_DESC_DEPTH_DISABLED = 0, + CLEAR_DEPTH_DESC_DEPTH_ENABLED_WRITES_ENABLED = 1, + CLEAR_DEPTH_DESC_DEPTH_ENABLED_WRITES_DISABLED = 2, }; static D3D12_DEPTH_STENCIL_DESC s_clear_depth_descs[3] = {}; @@ -78,11 +77,11 @@ static ID3D12Resource* s_screenshot_texture = nullptr; // Nvidia stereo blitting struct defined in "nvstereo.h" from the Nvidia SDK typedef struct _Nv_Stereo_Image_Header { - unsigned int dwSignature; - unsigned int dwWidth; - unsigned int dwHeight; - unsigned int dwBPP; - unsigned int dwFlags; + unsigned int dwSignature; + unsigned int dwWidth; + unsigned int dwHeight; + unsigned int dwBPP; + unsigned int dwFlags; } NVSTEREOIMAGEHEADER, *LPNVSTEREOIMAGEHEADER; #define NVSTEREO_IMAGE_SIGNATURE 0x4433564e @@ -90,10 +89,10 @@ typedef struct _Nv_Stereo_Image_Header // GX pipeline state static struct { - SamplerState sampler[8]; - BlendState blend; - ZMode zmode; - RasterizerState raster; + SamplerState sampler[8]; + BlendState blend; + ZMode zmode; + RasterizerState raster; } gx_state; @@ -101,244 +100,252 @@ StateCache gx_state_cache; static void SetupDeviceObjects() { - g_framebuffer_manager = std::make_unique(); + g_framebuffer_manager = std::make_unique(); - D3D12_DEPTH_STENCIL_DESC depth_desc; - depth_desc.DepthEnable = FALSE; - depth_desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; - depth_desc.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS; - depth_desc.StencilEnable = FALSE; - depth_desc.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK; - depth_desc.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK; - s_clear_depth_descs[CLEAR_DEPTH_DESC_DEPTH_DISABLED] = depth_desc; + D3D12_DEPTH_STENCIL_DESC depth_desc; + depth_desc.DepthEnable = FALSE; + depth_desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; + depth_desc.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS; + depth_desc.StencilEnable = FALSE; + depth_desc.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK; + depth_desc.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK; + s_clear_depth_descs[CLEAR_DEPTH_DESC_DEPTH_DISABLED] = depth_desc; - depth_desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; - depth_desc.DepthEnable = TRUE; - s_clear_depth_descs[CLEAR_DEPTH_DESC_DEPTH_ENABLED_WRITES_ENABLED] = depth_desc; + depth_desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; + depth_desc.DepthEnable = TRUE; + s_clear_depth_descs[CLEAR_DEPTH_DESC_DEPTH_ENABLED_WRITES_ENABLED] = depth_desc; - depth_desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; - s_clear_depth_descs[CLEAR_DEPTH_DESC_DEPTH_ENABLED_WRITES_DISABLED] = depth_desc; + depth_desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; + s_clear_depth_descs[CLEAR_DEPTH_DESC_DEPTH_ENABLED_WRITES_DISABLED] = depth_desc; - D3D12_BLEND_DESC blend_desc; - blend_desc.AlphaToCoverageEnable = FALSE; - blend_desc.IndependentBlendEnable = FALSE; - blend_desc.RenderTarget[0].LogicOpEnable = FALSE; - blend_desc.RenderTarget[0].LogicOp = D3D12_LOGIC_OP_NOOP; - blend_desc.RenderTarget[0].BlendEnable = FALSE; - blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; - blend_desc.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE; - blend_desc.RenderTarget[0].DestBlend = D3D12_BLEND_ZERO; - blend_desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; - blend_desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; - blend_desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO; - blend_desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; - g_reset_blend_desc = blend_desc; - s_clear_blend_descs[CLEAR_BLEND_DESC_ALL_CHANNELS_ENABLED] = g_reset_blend_desc; + D3D12_BLEND_DESC blend_desc; + blend_desc.AlphaToCoverageEnable = FALSE; + blend_desc.IndependentBlendEnable = FALSE; + blend_desc.RenderTarget[0].LogicOpEnable = FALSE; + blend_desc.RenderTarget[0].LogicOp = D3D12_LOGIC_OP_NOOP; + blend_desc.RenderTarget[0].BlendEnable = FALSE; + blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + blend_desc.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE; + blend_desc.RenderTarget[0].DestBlend = D3D12_BLEND_ZERO; + blend_desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; + blend_desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; + blend_desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO; + blend_desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; + g_reset_blend_desc = blend_desc; + s_clear_blend_descs[CLEAR_BLEND_DESC_ALL_CHANNELS_ENABLED] = g_reset_blend_desc; - blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_RED|D3D12_COLOR_WRITE_ENABLE_GREEN|D3D12_COLOR_WRITE_ENABLE_BLUE; - s_clear_blend_descs[CLEAR_BLEND_DESC_RGB_CHANNELS_ENABLED] = blend_desc; + blend_desc.RenderTarget[0].RenderTargetWriteMask = + D3D12_COLOR_WRITE_ENABLE_RED | D3D12_COLOR_WRITE_ENABLE_GREEN | D3D12_COLOR_WRITE_ENABLE_BLUE; + s_clear_blend_descs[CLEAR_BLEND_DESC_RGB_CHANNELS_ENABLED] = blend_desc; - blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALPHA; - s_clear_blend_descs[CLEAR_BLEND_DESC_ALPHA_CHANNEL_ENABLED] = blend_desc; + blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALPHA; + s_clear_blend_descs[CLEAR_BLEND_DESC_ALPHA_CHANNEL_ENABLED] = blend_desc; - blend_desc.RenderTarget[0].RenderTargetWriteMask = 0; - s_clear_blend_descs[CLEAR_BLEND_DESC_ALL_CHANNELS_DISABLED] = blend_desc; + blend_desc.RenderTarget[0].RenderTargetWriteMask = 0; + s_clear_blend_descs[CLEAR_BLEND_DESC_ALL_CHANNELS_DISABLED] = blend_desc; - depth_desc.DepthEnable = FALSE; - depth_desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; - depth_desc.DepthFunc = D3D12_COMPARISON_FUNC_LESS; - depth_desc.StencilEnable = FALSE; - depth_desc.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK; - depth_desc.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK; + depth_desc.DepthEnable = FALSE; + depth_desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; + depth_desc.DepthFunc = D3D12_COMPARISON_FUNC_LESS; + depth_desc.StencilEnable = FALSE; + depth_desc.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK; + depth_desc.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK; - g_reset_depth_desc = depth_desc; + g_reset_depth_desc = depth_desc; - D3D12_RASTERIZER_DESC rast_desc = CD3DX12_RASTERIZER_DESC(D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_NONE, false, 0, 0.f, 0.f, false, false, false, 0, D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF); - g_reset_rast_desc = rast_desc; + D3D12_RASTERIZER_DESC rast_desc = + CD3DX12_RASTERIZER_DESC(D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_NONE, false, 0, 0.f, 0.f, + false, false, false, 0, D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF); + g_reset_rast_desc = rast_desc; - s_screenshot_texture = nullptr; + s_screenshot_texture = nullptr; } // Kill off all device objects static void TeardownDeviceObjects() { - g_framebuffer_manager.reset(); + g_framebuffer_manager.reset(); - if (s_screenshot_texture) - { - D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(s_screenshot_texture); - s_screenshot_texture = nullptr; - } + if (s_screenshot_texture) + { + D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(s_screenshot_texture); + s_screenshot_texture = nullptr; + } - gx_state_cache.Clear(); + gx_state_cache.Clear(); } void CreateScreenshotTexture() { - // We can't render anything outside of the backbuffer anyway, so use the backbuffer size as the screenshot buffer size. - // This texture is released to be recreated when the window is resized in Renderer::SwapImpl. + // We can't render anything outside of the backbuffer anyway, so use the backbuffer size as the + // screenshot buffer size. + // This texture is released to be recreated when the window is resized in Renderer::SwapImpl. - const unsigned int screenshot_buffer_size = - D3D::AlignValue(D3D::GetBackBufferWidth() * 4, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * - D3D::GetBackBufferHeight(); + const unsigned int screenshot_buffer_size = + D3D::AlignValue(D3D::GetBackBufferWidth() * 4, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * + D3D::GetBackBufferHeight(); - CheckHR( - D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Buffer(screenshot_buffer_size), - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(&s_screenshot_texture) - ) - ); + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer(screenshot_buffer_size), D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, IID_PPV_ARGS(&s_screenshot_texture))); } static D3D12_BOX GetScreenshotSourceBox(const TargetRectangle& target_rc) { - // Since the screenshot buffer is copied back to the CPU, we can't access pixels that - // fall outside the backbuffer bounds. Therefore, when crop is enabled and the target rect is - // off-screen to the top/left, we clamp the origin at zero, as well as the bottom/right - // coordinates at the backbuffer dimensions. This will result in a rectangle that can be - // smaller than the backbuffer, but never larger. + // Since the screenshot buffer is copied back to the CPU, we can't access pixels that + // fall outside the backbuffer bounds. Therefore, when crop is enabled and the target rect is + // off-screen to the top/left, we clamp the origin at zero, as well as the bottom/right + // coordinates at the backbuffer dimensions. This will result in a rectangle that can be + // smaller than the backbuffer, but never larger. - return CD3DX12_BOX( - std::max(target_rc.left, 0), - std::max(target_rc.top, 0), - 0, - std::min(D3D::GetBackBufferWidth(), static_cast(target_rc.right)), - std::min(D3D::GetBackBufferHeight(), static_cast(target_rc.bottom)), - 1); + return CD3DX12_BOX( + std::max(target_rc.left, 0), std::max(target_rc.top, 0), 0, + std::min(D3D::GetBackBufferWidth(), static_cast(target_rc.right)), + std::min(D3D::GetBackBufferHeight(), static_cast(target_rc.bottom)), 1); } static void Create3DVisionTexture(int width, int height) { - // D3D12TODO: 3D Vision not implemented on D3D12 backend. + // D3D12TODO: 3D Vision not implemented on D3D12 backend. } Renderer::Renderer(void*& window_handle) { - if (g_ActiveConfig.iStereoMode == STEREO_3DVISION) - { - PanicAlert("3DVision not implemented on D3D12 backend."); - return; - } + if (g_ActiveConfig.iStereoMode == STEREO_3DVISION) + { + PanicAlert("3DVision not implemented on D3D12 backend."); + return; + } - s_backbuffer_width = D3D::GetBackBufferWidth(); - s_backbuffer_height = D3D::GetBackBufferHeight(); + s_backbuffer_width = D3D::GetBackBufferWidth(); + s_backbuffer_height = D3D::GetBackBufferHeight(); - FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH); - FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT); + FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH); + FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT); - UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); + UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); - s_last_multisamples = g_ActiveConfig.iMultisamples; - s_last_efb_scale = g_ActiveConfig.iEFBScale; - s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; - s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; - CalculateTargetSize(s_backbuffer_width, s_backbuffer_height); - PixelShaderManager::SetEfbScaleChanged(); + s_last_multisamples = g_ActiveConfig.iMultisamples; + s_last_efb_scale = g_ActiveConfig.iEFBScale; + s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; + s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; + CalculateTargetSize(s_backbuffer_width, s_backbuffer_height); + PixelShaderManager::SetEfbScaleChanged(); - SetupDeviceObjects(); + SetupDeviceObjects(); - // Setup GX pipeline state - gx_state.blend.blend_enable = false; - gx_state.blend.write_mask = D3D12_COLOR_WRITE_ENABLE_ALL; - gx_state.blend.src_blend = D3D12_BLEND_ONE; - gx_state.blend.dst_blend = D3D12_BLEND_ZERO; - gx_state.blend.blend_op = D3D12_BLEND_OP_ADD; - gx_state.blend.use_dst_alpha = false; + // Setup GX pipeline state + gx_state.blend.blend_enable = false; + gx_state.blend.write_mask = D3D12_COLOR_WRITE_ENABLE_ALL; + gx_state.blend.src_blend = D3D12_BLEND_ONE; + gx_state.blend.dst_blend = D3D12_BLEND_ZERO; + gx_state.blend.blend_op = D3D12_BLEND_OP_ADD; + gx_state.blend.use_dst_alpha = false; - for (unsigned int k = 0; k < 8; k++) - { - gx_state.sampler[k].hex = 0; - } + for (unsigned int k = 0; k < 8; k++) + { + gx_state.sampler[k].hex = 0; + } - gx_state.zmode.testenable = false; - gx_state.zmode.updateenable = false; - gx_state.zmode.func = ZMode::NEVER; + gx_state.zmode.testenable = false; + gx_state.zmode.updateenable = false; + gx_state.zmode.func = ZMode::NEVER; - gx_state.raster.cull_mode = D3D12_CULL_MODE_NONE; + gx_state.raster.cull_mode = D3D12_CULL_MODE_NONE; - // Clear EFB textures - float clear_color[4] = { 0.f, 0.f, 0.f, 1.f }; - FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE ); - D3D::current_command_list->ClearRenderTargetView(FramebufferManager::GetEFBColorTexture()->GetRTV12(), clear_color, 0, nullptr); - D3D::current_command_list->ClearDepthStencilView(FramebufferManager::GetEFBDepthTexture()->GetDSV12(), D3D12_CLEAR_FLAG_DEPTH, 0.f, 0, 0, nullptr); + // Clear EFB textures + float clear_color[4] = {0.f, 0.f, 0.f, 1.f}; + FramebufferManager::GetEFBColorTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); + D3D::current_command_list->ClearRenderTargetView( + FramebufferManager::GetEFBColorTexture()->GetRTV12(), clear_color, 0, nullptr); + D3D::current_command_list->ClearDepthStencilView( + FramebufferManager::GetEFBDepthTexture()->GetDSV12(), D3D12_CLEAR_FLAG_DEPTH, 0.f, 0, 0, + nullptr); - D3D12_VIEWPORT vp = { 0.f, 0.f, static_cast(s_target_width), static_cast(s_target_height), D3D12_MIN_DEPTH, D3D12_MAX_DEPTH }; - D3D::current_command_list->RSSetViewports(1, &vp); + D3D12_VIEWPORT vp = {0.f, + 0.f, + static_cast(s_target_width), + static_cast(s_target_height), + D3D12_MIN_DEPTH, + D3D12_MAX_DEPTH}; + D3D::current_command_list->RSSetViewports(1, &vp); - // Already transitioned to appropriate states a few lines up for the clears. - FramebufferManager::RestoreEFBRenderTargets(); + // Already transitioned to appropriate states a few lines up for the clears. + FramebufferManager::RestoreEFBRenderTargets(); - D3D::BeginFrame(); + D3D::BeginFrame(); } Renderer::~Renderer() { - D3D::EndFrame(); - D3D::WaitForOutstandingRenderingToComplete(); - TeardownDeviceObjects(); + D3D::EndFrame(); + D3D::WaitForOutstandingRenderingToComplete(); + TeardownDeviceObjects(); } void Renderer::RenderText(const std::string& text, int left, int top, u32 color) { - D3D::font.DrawTextScaled(static_cast(left + 1), static_cast(top + 1), 20.f, 0.0f, color & 0xFF000000, text); - D3D::font.DrawTextScaled(static_cast(left), static_cast(top), 20.f, 0.0f, color, text); + D3D::font.DrawTextScaled(static_cast(left + 1), static_cast(top + 1), 20.f, 0.0f, + color & 0xFF000000, text); + D3D::font.DrawTextScaled(static_cast(left), static_cast(top), 20.f, 0.0f, color, + text); } TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc) { - TargetRectangle result; - result.left = EFBToScaledX(rc.left); - result.top = EFBToScaledY(rc.top); - result.right = EFBToScaledX(rc.right); - result.bottom = EFBToScaledY(rc.bottom); - return result; + TargetRectangle result; + result.left = EFBToScaledX(rc.left); + result.top = EFBToScaledY(rc.top); + result.right = EFBToScaledX(rc.right); + result.bottom = EFBToScaledY(rc.bottom); + return result; } // With D3D, we have to resize the backbuffer if the window changed // size. __declspec(noinline) bool Renderer::CheckForResize() { - RECT rc_window; - GetClientRect(D3D::hWnd, &rc_window); - int client_width = rc_window.right - rc_window.left; - int client_height = rc_window.bottom - rc_window.top; + RECT rc_window; + GetClientRect(D3D::hWnd, &rc_window); + int client_width = rc_window.right - rc_window.left; + int client_height = rc_window.bottom - rc_window.top; - // Sanity check - if ((client_width != Renderer::GetBackbufferWidth() || - client_height != Renderer::GetBackbufferHeight()) && - client_width >= 4 && client_height >= 4) - { - return true; - } + // Sanity check + if ((client_width != Renderer::GetBackbufferWidth() || + client_height != Renderer::GetBackbufferHeight()) && + client_width >= 4 && client_height >= 4) + { + return true; + } - return false; + return false; } void Renderer::SetScissorRect(const EFBRectangle& rc) { - TargetRectangle trc = ConvertEFBRectangle(rc); - D3D::current_command_list->RSSetScissorRects(1, trc.AsRECT()); + TargetRectangle trc = ConvertEFBRectangle(rc); + D3D::current_command_list->RSSetScissorRects(1, trc.AsRECT()); } void Renderer::SetColorMask() { - // Only enable alpha channel if it's supported by the current EFB format - UINT8 color_mask = 0; - if (bpmem.alpha_test.TestResult() != AlphaTest::FAIL) - { - if (bpmem.blendmode.alphaupdate && (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24)) - color_mask = D3D12_COLOR_WRITE_ENABLE_ALPHA; - if (bpmem.blendmode.colorupdate) - color_mask |= D3D12_COLOR_WRITE_ENABLE_RED | D3D12_COLOR_WRITE_ENABLE_GREEN | D3D12_COLOR_WRITE_ENABLE_BLUE; - } - gx_state.blend.write_mask = color_mask; + // Only enable alpha channel if it's supported by the current EFB format + UINT8 color_mask = 0; + if (bpmem.alpha_test.TestResult() != AlphaTest::FAIL) + { + if (bpmem.blendmode.alphaupdate && (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24)) + color_mask = D3D12_COLOR_WRITE_ENABLE_ALPHA; + if (bpmem.blendmode.colorupdate) + color_mask |= D3D12_COLOR_WRITE_ENABLE_RED | D3D12_COLOR_WRITE_ENABLE_GREEN | + D3D12_COLOR_WRITE_ENABLE_BLUE; + } + gx_state.blend.write_mask = color_mask; - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); } // This function allows the CPU to directly access the EFB. @@ -357,661 +364,692 @@ void Renderer::SetColorMask() // - GX_PokeZMode (TODO) u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) { - if (type == PEEK_COLOR) - { - u32 color = FramebufferManager::ReadEFBColorAccessCopy(x, y); + if (type == PEEK_COLOR) + { + u32 color = FramebufferManager::ReadEFBColorAccessCopy(x, y); - // a little-endian value is expected to be returned - color = ((color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000)); + // a little-endian value is expected to be returned + color = ((color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000)); - // check what to do with the alpha channel (GX_PokeAlphaRead) - PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode(); + // check what to do with the alpha channel (GX_PokeAlphaRead) + PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode(); - if (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24) - { - color = RGBA8ToRGBA6ToRGBA8(color); - } - else if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) - { - color = RGBA8ToRGB565ToRGBA8(color); - } - if (bpmem.zcontrol.pixel_format != PEControl::RGBA6_Z24) - { - color |= 0xFF000000; - } + if (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24) + { + color = RGBA8ToRGBA6ToRGBA8(color); + } + else if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) + { + color = RGBA8ToRGB565ToRGBA8(color); + } + if (bpmem.zcontrol.pixel_format != PEControl::RGBA6_Z24) + { + color |= 0xFF000000; + } - if (alpha_read_mode.ReadMode == 2) - { - return color; // GX_READ_NONE - } - else if (alpha_read_mode.ReadMode == 1) - { - return (color | 0xFF000000); // GX_READ_FF - } - else /*if(alpha_read_mode.ReadMode == 0)*/ - { - return (color & 0x00FFFFFF); // GX_READ_00 - } - } - else // if (type == PEEK_Z) - { - // depth buffer is inverted in the d3d backend - float depth = 1.0f - FramebufferManager::ReadEFBDepthAccessCopy(x, y); - u32 ret = 0; + if (alpha_read_mode.ReadMode == 2) + { + return color; // GX_READ_NONE + } + else if (alpha_read_mode.ReadMode == 1) + { + return (color | 0xFF000000); // GX_READ_FF + } + else /*if(alpha_read_mode.ReadMode == 0)*/ + { + return (color & 0x00FFFFFF); // GX_READ_00 + } + } + else // if (type == PEEK_Z) + { + // depth buffer is inverted in the d3d backend + float depth = 1.0f - FramebufferManager::ReadEFBDepthAccessCopy(x, y); + u32 ret = 0; - if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) - { - // if Z is in 16 bit format you must return a 16 bit integer - ret = MathUtil::Clamp(static_cast(depth * 65536.0f), 0, 0xFFFF); - } - else - { - ret = MathUtil::Clamp(static_cast(depth * 16777216.0f), 0, 0xFFFFFF); - } + if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) + { + // if Z is in 16 bit format you must return a 16 bit integer + ret = MathUtil::Clamp(static_cast(depth * 65536.0f), 0, 0xFFFF); + } + else + { + ret = MathUtil::Clamp(static_cast(depth * 16777216.0f), 0, 0xFFFFFF); + } - return ret; - } + return ret; + } } void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) { - D3D::SetViewportAndScissor(0, 0, GetTargetWidth(), GetTargetHeight()); + D3D::SetViewportAndScissor(0, 0, GetTargetWidth(), GetTargetHeight()); - if (type == POKE_COLOR) - { - // In the D3D12 backend, the rt/db/viewport is passed into DrawEFBPokeQuads, and set there. - D3D::DrawEFBPokeQuads( - type, - points, - num_points, - &g_reset_blend_desc, - &g_reset_depth_desc, - &FramebufferManager::GetEFBColorTexture()->GetRTV12(), - nullptr, - FramebufferManager::GetEFBColorTexture()->GetMultisampled() - ); - } - else // if (type == POKE_Z) - { - D3D::DrawEFBPokeQuads( - type, - points, - num_points, - &s_clear_blend_descs[CLEAR_BLEND_DESC_ALL_CHANNELS_DISABLED], - &s_clear_depth_descs[CLEAR_DEPTH_DESC_DEPTH_ENABLED_WRITES_ENABLED], - &FramebufferManager::GetEFBColorTexture()->GetRTV12(), - &FramebufferManager::GetEFBDepthTexture()->GetDSV12(), - FramebufferManager::GetEFBColorTexture()->GetMultisampled() - ); - } + if (type == POKE_COLOR) + { + // In the D3D12 backend, the rt/db/viewport is passed into DrawEFBPokeQuads, and set there. + D3D::DrawEFBPokeQuads(type, points, num_points, &g_reset_blend_desc, &g_reset_depth_desc, + &FramebufferManager::GetEFBColorTexture()->GetRTV12(), nullptr, + FramebufferManager::GetEFBColorTexture()->GetMultisampled()); + } + else // if (type == POKE_Z) + { + D3D::DrawEFBPokeQuads(type, points, num_points, + &s_clear_blend_descs[CLEAR_BLEND_DESC_ALL_CHANNELS_DISABLED], + &s_clear_depth_descs[CLEAR_DEPTH_DESC_DEPTH_ENABLED_WRITES_ENABLED], + &FramebufferManager::GetEFBColorTexture()->GetRTV12(), + &FramebufferManager::GetEFBDepthTexture()->GetDSV12(), + FramebufferManager::GetEFBColorTexture()->GetMultisampled()); + } - RestoreAPIState(); + RestoreAPIState(); } void Renderer::SetViewport() { - // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) - // [0] = width/2 - // [1] = height/2 - // [2] = 16777215 * (farz - nearz) - // [3] = xorig + width/2 + 342 - // [4] = yorig + height/2 + 342 - // [5] = 16777215 * farz + // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) + // [0] = width/2 + // [1] = height/2 + // [2] = 16777215 * (farz - nearz) + // [3] = xorig + width/2 + 342 + // [4] = yorig + height/2 + 342 + // [5] = 16777215 * farz - // D3D crashes for zero viewports - if (xfmem.viewport.wd == 0 || xfmem.viewport.ht == 0) - return; + // D3D crashes for zero viewports + if (xfmem.viewport.wd == 0 || xfmem.viewport.ht == 0) + return; - int scissor_x_offset = bpmem.scissorOffset.x * 2; - int scissor_y_offset = bpmem.scissorOffset.y * 2; + int scissor_x_offset = bpmem.scissorOffset.x * 2; + int scissor_y_offset = bpmem.scissorOffset.y * 2; - float x = Renderer::EFBToScaledXf(xfmem.viewport.xOrig - xfmem.viewport.wd - scissor_x_offset); - float y = Renderer::EFBToScaledYf(xfmem.viewport.yOrig + xfmem.viewport.ht - scissor_y_offset); - float width = Renderer::EFBToScaledXf(2.0f * xfmem.viewport.wd); - float height = Renderer::EFBToScaledYf(-2.0f * xfmem.viewport.ht); - if (width < 0.0f) - { - x += width; - width = -width; - } - if (height < 0.0f) - { - y += height; - height = -height; - } + float x = Renderer::EFBToScaledXf(xfmem.viewport.xOrig - xfmem.viewport.wd - scissor_x_offset); + float y = Renderer::EFBToScaledYf(xfmem.viewport.yOrig + xfmem.viewport.ht - scissor_y_offset); + float width = Renderer::EFBToScaledXf(2.0f * xfmem.viewport.wd); + float height = Renderer::EFBToScaledYf(-2.0f * xfmem.viewport.ht); + if (width < 0.0f) + { + x += width; + width = -width; + } + if (height < 0.0f) + { + y += height; + height = -height; + } - // In D3D, the viewport rectangle must fit within the render target. - x = (x >= 0.f) ? x : 0.f; - y = (y >= 0.f) ? y : 0.f; - width = (x + width <= GetTargetWidth()) ? width : (GetTargetWidth() - x); - height = (y + height <= GetTargetHeight()) ? height : (GetTargetHeight() - y); + // In D3D, the viewport rectangle must fit within the render target. + x = (x >= 0.f) ? x : 0.f; + y = (y >= 0.f) ? y : 0.f; + width = (x + width <= GetTargetWidth()) ? width : (GetTargetWidth() - x); + height = (y + height <= GetTargetHeight()) ? height : (GetTargetHeight() - y); - D3D12_VIEWPORT vp = { x, y, width, height, - 1.0f - MathUtil::Clamp(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f, - 1.0f - MathUtil::Clamp(xfmem.viewport.farZ - MathUtil::Clamp(xfmem.viewport.zRange, 0.0f, 16777216.0f), 0.0f, 16777215.0f) / 16777216.0f }; + D3D12_VIEWPORT vp = { + x, y, width, height, + 1.0f - MathUtil::Clamp(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f, + 1.0f - + MathUtil::Clamp(xfmem.viewport.farZ - MathUtil::Clamp(xfmem.viewport.zRange, + 0.0f, 16777216.0f), + 0.0f, 16777215.0f) / + 16777216.0f}; - D3D::current_command_list->RSSetViewports(1, &vp); + D3D::current_command_list->RSSetViewports(1, &vp); } -void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha_enable, bool z_enable, u32 color, u32 z) +void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha_enable, + bool z_enable, u32 color, u32 z) { - D3D12_BLEND_DESC* blend_desc = nullptr; + D3D12_BLEND_DESC* blend_desc = nullptr; - if (color_enable && alpha_enable) - blend_desc = &s_clear_blend_descs[CLEAR_BLEND_DESC_ALL_CHANNELS_ENABLED]; - else if (color_enable) - blend_desc = &s_clear_blend_descs[CLEAR_BLEND_DESC_RGB_CHANNELS_ENABLED]; - else if (alpha_enable) - blend_desc = &s_clear_blend_descs[CLEAR_BLEND_DESC_ALPHA_CHANNEL_ENABLED]; - else - blend_desc = &s_clear_blend_descs[CLEAR_BLEND_DESC_ALL_CHANNELS_DISABLED]; + if (color_enable && alpha_enable) + blend_desc = &s_clear_blend_descs[CLEAR_BLEND_DESC_ALL_CHANNELS_ENABLED]; + else if (color_enable) + blend_desc = &s_clear_blend_descs[CLEAR_BLEND_DESC_RGB_CHANNELS_ENABLED]; + else if (alpha_enable) + blend_desc = &s_clear_blend_descs[CLEAR_BLEND_DESC_ALPHA_CHANNEL_ENABLED]; + else + blend_desc = &s_clear_blend_descs[CLEAR_BLEND_DESC_ALL_CHANNELS_DISABLED]; - D3D12_DEPTH_STENCIL_DESC* depth_stencil_desc = nullptr; + D3D12_DEPTH_STENCIL_DESC* depth_stencil_desc = nullptr; - // EXISTINGD3D11TODO: Should we enable Z testing here? - /*if (!bpmem.zmode.testenable) depth_stencil_desc = &s_clear_depth_descs[CLEAR_DEPTH_DESC_DEPTH_DISABLED]; - else */if (z_enable) - depth_stencil_desc = &s_clear_depth_descs[CLEAR_DEPTH_DESC_DEPTH_ENABLED_WRITES_ENABLED]; - else /*if (!z_enable)*/ - depth_stencil_desc = &s_clear_depth_descs[CLEAR_DEPTH_DESC_DEPTH_ENABLED_WRITES_DISABLED]; + // EXISTINGD3D11TODO: Should we enable Z testing here? + /*if (!bpmem.zmode.testenable) depth_stencil_desc = &s_clear_depth_descs[CLEAR_DEPTH_DESC_DEPTH_DISABLED]; + else */ if ( + z_enable) + depth_stencil_desc = &s_clear_depth_descs[CLEAR_DEPTH_DESC_DEPTH_ENABLED_WRITES_ENABLED]; + else /*if (!z_enable)*/ + depth_stencil_desc = &s_clear_depth_descs[CLEAR_DEPTH_DESC_DEPTH_ENABLED_WRITES_DISABLED]; - // Update the view port for clearing the picture - TargetRectangle target_rc = Renderer::ConvertEFBRectangle(rc); + // Update the view port for clearing the picture + TargetRectangle target_rc = Renderer::ConvertEFBRectangle(rc); - // Color is passed in bgra mode so we need to convert it to rgba - u32 rgba_color = (color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000); - D3D::SetViewportAndScissor(target_rc.left, target_rc.top, target_rc.GetWidth(), target_rc.GetHeight()); - D3D::DrawClearQuad(rgba_color, 1.0f - (z & 0xFFFFFF) / 16777216.0f, blend_desc, depth_stencil_desc, FramebufferManager::GetEFBColorTexture()->GetMultisampled()); + // Color is passed in bgra mode so we need to convert it to rgba + u32 rgba_color = (color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000); + D3D::SetViewportAndScissor(target_rc.left, target_rc.top, target_rc.GetWidth(), + target_rc.GetHeight()); + D3D::DrawClearQuad(rgba_color, 1.0f - (z & 0xFFFFFF) / 16777216.0f, blend_desc, + depth_stencil_desc, + FramebufferManager::GetEFBColorTexture()->GetMultisampled()); - // Restores proper viewport/scissor settings. - g_renderer->SetViewport(); - BPFunctions::SetScissor(); + // Restores proper viewport/scissor settings. + g_renderer->SetViewport(); + BPFunctions::SetScissor(); - FramebufferManager::InvalidateEFBAccessCopies(); + FramebufferManager::InvalidateEFBAccessCopies(); } void Renderer::ReinterpretPixelData(unsigned int convtype) { - // EXISTINGD3D11TODO: MSAA support.. - D3D12_RECT source = CD3DX12_RECT(0, 0, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight()); + // EXISTINGD3D11TODO: MSAA support.. + D3D12_RECT source = + CD3DX12_RECT(0, 0, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight()); - D3D12_SHADER_BYTECODE pixel_shader = {}; + D3D12_SHADER_BYTECODE pixel_shader = {}; - if (convtype == 0) - { - pixel_shader = StaticShaderCache::GetReinterpRGB8ToRGBA6PixelShader(true); - } - else if (convtype == 2) - { - pixel_shader = StaticShaderCache::GetReinterpRGBA6ToRGB8PixelShader(true); - } - else - { - ERROR_LOG(VIDEO, "Trying to reinterpret pixel data with unsupported conversion type %d", convtype); - return; - } + if (convtype == 0) + { + pixel_shader = StaticShaderCache::GetReinterpRGB8ToRGBA6PixelShader(true); + } + else if (convtype == 2) + { + pixel_shader = StaticShaderCache::GetReinterpRGBA6ToRGB8PixelShader(true); + } + else + { + ERROR_LOG(VIDEO, "Trying to reinterpret pixel data with unsupported conversion type %d", + convtype); + return; + } - D3D::SetViewportAndScissor(0, 0, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight()); + D3D::SetViewportAndScissor(0, 0, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight()); - FramebufferManager::GetEFBColorTempTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTempTexture()->GetRTV12(), FALSE, nullptr); + FramebufferManager::GetEFBColorTempTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + D3D::current_command_list->OMSetRenderTargets( + 1, &FramebufferManager::GetEFBColorTempTexture()->GetRTV12(), FALSE, nullptr); - D3D::SetPointCopySampler(); - D3D::DrawShadedTexQuad( - FramebufferManager::GetEFBColorTexture(), - &source, - g_renderer->GetTargetWidth(), - g_renderer->GetTargetHeight(), - pixel_shader, - StaticShaderCache::GetSimpleVertexShader(), - StaticShaderCache::GetSimpleVertexShaderInputLayout(), - StaticShaderCache::GetCopyGeometryShader(), - 1.0f, - 0, - DXGI_FORMAT_R8G8B8A8_UNORM, - false, - FramebufferManager::GetEFBColorTempTexture()->GetMultisampled() - ); + D3D::SetPointCopySampler(); + D3D::DrawShadedTexQuad( + FramebufferManager::GetEFBColorTexture(), &source, g_renderer->GetTargetWidth(), + g_renderer->GetTargetHeight(), pixel_shader, StaticShaderCache::GetSimpleVertexShader(), + StaticShaderCache::GetSimpleVertexShaderInputLayout(), + StaticShaderCache::GetCopyGeometryShader(), 1.0f, 0, DXGI_FORMAT_R8G8B8A8_UNORM, false, + FramebufferManager::GetEFBColorTempTexture()->GetMultisampled()); - FramebufferManager::SwapReinterpretTexture(); + FramebufferManager::SwapReinterpretTexture(); - FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); + FramebufferManager::GetEFBColorTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); - // Restores proper viewport/scissor settings. - RestoreAPIState(); + // Restores proper viewport/scissor settings. + RestoreAPIState(); } void Renderer::SetBlendMode(bool force_update) { - // Our render target always uses an alpha channel, so we need to override the blend functions to assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel - // Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel is assumed to always be 1. - bool target_has_alpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; - const D3D12_BLEND d3d_src_factors[8] = - { - D3D12_BLEND_ZERO, - D3D12_BLEND_ONE, - D3D12_BLEND_DEST_COLOR, - D3D12_BLEND_INV_DEST_COLOR, - D3D12_BLEND_SRC_ALPHA, - D3D12_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled! - (target_has_alpha) ? D3D12_BLEND_DEST_ALPHA : D3D12_BLEND_ONE, - (target_has_alpha) ? D3D12_BLEND_INV_DEST_ALPHA : D3D12_BLEND_ZERO - }; - const D3D12_BLEND d3d_dst_factors[8] = - { - D3D12_BLEND_ZERO, - D3D12_BLEND_ONE, - D3D12_BLEND_SRC_COLOR, - D3D12_BLEND_INV_SRC_COLOR, - D3D12_BLEND_SRC_ALPHA, - D3D12_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled! - (target_has_alpha) ? D3D12_BLEND_DEST_ALPHA : D3D12_BLEND_ONE, - (target_has_alpha) ? D3D12_BLEND_INV_DEST_ALPHA : D3D12_BLEND_ZERO - }; + // Our render target always uses an alpha channel, so we need to override the blend functions to + // assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel + // Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel + // is assumed to always be 1. + bool target_has_alpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; + const D3D12_BLEND d3d_src_factors[8] = { + D3D12_BLEND_ZERO, + D3D12_BLEND_ONE, + D3D12_BLEND_DEST_COLOR, + D3D12_BLEND_INV_DEST_COLOR, + D3D12_BLEND_SRC_ALPHA, + D3D12_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled! + (target_has_alpha) ? D3D12_BLEND_DEST_ALPHA : D3D12_BLEND_ONE, + (target_has_alpha) ? D3D12_BLEND_INV_DEST_ALPHA : D3D12_BLEND_ZERO}; + const D3D12_BLEND d3d_dst_factors[8] = { + D3D12_BLEND_ZERO, + D3D12_BLEND_ONE, + D3D12_BLEND_SRC_COLOR, + D3D12_BLEND_INV_SRC_COLOR, + D3D12_BLEND_SRC_ALPHA, + D3D12_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled! + (target_has_alpha) ? D3D12_BLEND_DEST_ALPHA : D3D12_BLEND_ONE, + (target_has_alpha) ? D3D12_BLEND_INV_DEST_ALPHA : D3D12_BLEND_ZERO}; - if (bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable && !force_update) - return; + if (bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable && !force_update) + return; - if (bpmem.blendmode.subtract) - { - gx_state.blend.blend_enable = true; - gx_state.blend.blend_op = D3D12_BLEND_OP_REV_SUBTRACT; - gx_state.blend.src_blend = D3D12_BLEND_ONE; - gx_state.blend.dst_blend = D3D12_BLEND_ONE; - } - else - { - gx_state.blend.blend_enable = static_cast(bpmem.blendmode.blendenable); - if (bpmem.blendmode.blendenable) - { - gx_state.blend.blend_op = D3D12_BLEND_OP_ADD; - gx_state.blend.src_blend = d3d_src_factors[bpmem.blendmode.srcfactor]; - gx_state.blend.dst_blend = d3d_dst_factors[bpmem.blendmode.dstfactor]; - } - } + if (bpmem.blendmode.subtract) + { + gx_state.blend.blend_enable = true; + gx_state.blend.blend_op = D3D12_BLEND_OP_REV_SUBTRACT; + gx_state.blend.src_blend = D3D12_BLEND_ONE; + gx_state.blend.dst_blend = D3D12_BLEND_ONE; + } + else + { + gx_state.blend.blend_enable = static_cast(bpmem.blendmode.blendenable); + if (bpmem.blendmode.blendenable) + { + gx_state.blend.blend_op = D3D12_BLEND_OP_ADD; + gx_state.blend.src_blend = d3d_src_factors[bpmem.blendmode.srcfactor]; + gx_state.blend.dst_blend = d3d_dst_factors[bpmem.blendmode.dstfactor]; + } + } - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); } bool Renderer::SaveScreenshot(const std::string& filename, const TargetRectangle& rc) { - if (!s_screenshot_texture) - CreateScreenshotTexture(); + if (!s_screenshot_texture) + CreateScreenshotTexture(); - // copy back buffer to system memory - bool saved_png = false; + // copy back buffer to system memory + bool saved_png = false; - D3D12_BOX source_box = GetScreenshotSourceBox(rc); + D3D12_BOX source_box = GetScreenshotSourceBox(rc); - D3D12_TEXTURE_COPY_LOCATION dst_location = {}; - dst_location.pResource = s_screenshot_texture; - dst_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - dst_location.PlacedFootprint.Offset = 0; - dst_location.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - dst_location.PlacedFootprint.Footprint.Width = D3D::GetBackBufferWidth(); - dst_location.PlacedFootprint.Footprint.Height = D3D::GetBackBufferHeight(); - dst_location.PlacedFootprint.Footprint.Depth = 1; - dst_location.PlacedFootprint.Footprint.RowPitch = D3D::AlignValue(dst_location.PlacedFootprint.Footprint.Width * 4, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + D3D12_TEXTURE_COPY_LOCATION dst_location = {}; + dst_location.pResource = s_screenshot_texture; + dst_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + dst_location.PlacedFootprint.Offset = 0; + dst_location.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + dst_location.PlacedFootprint.Footprint.Width = D3D::GetBackBufferWidth(); + dst_location.PlacedFootprint.Footprint.Height = D3D::GetBackBufferHeight(); + dst_location.PlacedFootprint.Footprint.Depth = 1; + dst_location.PlacedFootprint.Footprint.RowPitch = D3D::AlignValue( + dst_location.PlacedFootprint.Footprint.Width * 4, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); - D3D12_TEXTURE_COPY_LOCATION src_location = {}; - src_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - src_location.SubresourceIndex = 0; - src_location.pResource = D3D::GetBackBuffer()->GetTex12(); + D3D12_TEXTURE_COPY_LOCATION src_location = {}; + src_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + src_location.SubresourceIndex = 0; + src_location.pResource = D3D::GetBackBuffer()->GetTex12(); - D3D::GetBackBuffer()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); - D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, &source_box); + D3D::GetBackBuffer()->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_COPY_SOURCE); + D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, &source_box); - D3D::command_list_mgr->ExecuteQueuedWork(true); + D3D::command_list_mgr->ExecuteQueuedWork(true); - void* screenshot_texture_map; - D3D12_RANGE read_range = { 0, dst_location.PlacedFootprint.Footprint.RowPitch * (source_box.bottom - source_box.top) }; - CheckHR(s_screenshot_texture->Map(0, &read_range, &screenshot_texture_map)); + void* screenshot_texture_map; + D3D12_RANGE read_range = {0, dst_location.PlacedFootprint.Footprint.RowPitch * + (source_box.bottom - source_box.top)}; + CheckHR(s_screenshot_texture->Map(0, &read_range, &screenshot_texture_map)); - saved_png = TextureToPng(static_cast(screenshot_texture_map), dst_location.PlacedFootprint.Footprint.RowPitch, filename, source_box.right - source_box.left, source_box.bottom - source_box.top, false); + saved_png = TextureToPng( + static_cast(screenshot_texture_map), dst_location.PlacedFootprint.Footprint.RowPitch, + filename, source_box.right - source_box.left, source_box.bottom - source_box.top, false); - D3D12_RANGE write_range = {}; - s_screenshot_texture->Unmap(0, &write_range); + D3D12_RANGE write_range = {}; + s_screenshot_texture->Unmap(0, &write_range); - if (saved_png) - { - OSD::AddMessage(StringFromFormat("Saved %i x %i %s", rc.GetWidth(), - rc.GetHeight(), filename.c_str())); - } - else - { - OSD::AddMessage(StringFromFormat("Error saving %s", filename.c_str())); - } + if (saved_png) + { + OSD::AddMessage( + StringFromFormat("Saved %i x %i %s", rc.GetWidth(), rc.GetHeight(), filename.c_str())); + } + else + { + OSD::AddMessage(StringFromFormat("Error saving %s", filename.c_str())); + } - return saved_png; + return saved_png; } void formatBufferDump(const u8* in, u8* out, int w, int h, int p) { - for (int y = 0; y < h; ++y) - { - auto line = (in + (h - y - 1) * p); - for (int x = 0; x < w; ++x) - { - out[0] = line[2]; - out[1] = line[1]; - out[2] = line[0]; - out += 3; - line += 4; - } - } + for (int y = 0; y < h; ++y) + { + auto line = (in + (h - y - 1) * p); + for (int x = 0; x < w; ++x) + { + out[0] = line[2]; + out[1] = line[1]; + out[2] = line[0]; + out += 3; + line += 4; + } + } } // This function has the final picture. We adjust the aspect ratio here. -void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, const EFBRectangle& rc, float gamma) +void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, + const EFBRectangle& rc, float gamma) { - if (Fifo::WillSkipCurrentFrame() || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fb_width || !fb_height) - { - if (SConfig::GetInstance().m_DumpFrames && !frame_data.empty()) - AVIDump::AddFrame(&frame_data[0], fb_width, fb_height); + if (Fifo::WillSkipCurrentFrame() || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || + !fb_width || !fb_height) + { + if (SConfig::GetInstance().m_DumpFrames && !frame_data.empty()) + AVIDump::AddFrame(&frame_data[0], fb_width, fb_height); - Core::Callback_VideoCopiedToXFB(false); - return; - } + Core::Callback_VideoCopiedToXFB(false); + return; + } - u32 xfb_count = 0; - const XFBSourceBase* const* xfb_source_list = FramebufferManager::GetXFBSource(xfb_addr, fb_stride, fb_height, &xfb_count); - if ((!xfb_source_list || xfb_count == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) - { - if (SConfig::GetInstance().m_DumpFrames && !frame_data.empty()) - AVIDump::AddFrame(&frame_data[0], fb_width, fb_height); + u32 xfb_count = 0; + const XFBSourceBase* const* xfb_source_list = + FramebufferManager::GetXFBSource(xfb_addr, fb_stride, fb_height, &xfb_count); + if ((!xfb_source_list || xfb_count == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) + { + if (SConfig::GetInstance().m_DumpFrames && !frame_data.empty()) + AVIDump::AddFrame(&frame_data[0], fb_width, fb_height); - Core::Callback_VideoCopiedToXFB(false); - return; - } + Core::Callback_VideoCopiedToXFB(false); + return; + } - // Invalidate EFB access copies. Not strictly necessary, but this avoids having the buffers mapped when calling Present(). - FramebufferManager::InvalidateEFBAccessCopies(); - BBox::Invalidate(); + // Invalidate EFB access copies. Not strictly necessary, but this avoids having the buffers mapped + // when calling Present(). + FramebufferManager::InvalidateEFBAccessCopies(); + BBox::Invalidate(); - // Prepare to copy the XFBs to our backbuffer - UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); - TargetRectangle target_rc = GetTargetRectangle(); + // Prepare to copy the XFBs to our backbuffer + UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); + TargetRectangle target_rc = GetTargetRectangle(); - D3D::GetBackBuffer()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - D3D::current_command_list->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV12(), FALSE, nullptr); + D3D::GetBackBuffer()->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_RENDER_TARGET); + D3D::current_command_list->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV12(), FALSE, + nullptr); - float clear_color[4] = { 0.f, 0.f, 0.f, 1.f }; - D3D::current_command_list->ClearRenderTargetView(D3D::GetBackBuffer()->GetRTV12(), clear_color, 0, nullptr); + float clear_color[4] = {0.f, 0.f, 0.f, 1.f}; + D3D::current_command_list->ClearRenderTargetView(D3D::GetBackBuffer()->GetRTV12(), clear_color, 0, + nullptr); - // activate linear filtering for the buffer copies - D3D::SetLinearCopySampler(); + // activate linear filtering for the buffer copies + D3D::SetLinearCopySampler(); - if (g_ActiveConfig.bUseXFB) - { - const XFBSource* xfb_source; + if (g_ActiveConfig.bUseXFB) + { + const XFBSource* xfb_source; - // draw each xfb source - for (u32 i = 0; i < xfb_count; ++i) - { - xfb_source = static_cast(xfb_source_list[i]); + // draw each xfb source + for (u32 i = 0; i < xfb_count; ++i) + { + xfb_source = static_cast(xfb_source_list[i]); - TargetRectangle drawRc; - TargetRectangle source_rc; - source_rc.left = xfb_source->sourceRc.left; - source_rc.top = xfb_source->sourceRc.top; - source_rc.right = xfb_source->sourceRc.right; - source_rc.bottom = xfb_source->sourceRc.bottom; + TargetRectangle drawRc; + TargetRectangle source_rc; + source_rc.left = xfb_source->sourceRc.left; + source_rc.top = xfb_source->sourceRc.top; + source_rc.right = xfb_source->sourceRc.right; + source_rc.bottom = xfb_source->sourceRc.bottom; - // use virtual xfb with offset - int xfb_height = xfb_source->srcHeight; - int xfb_width = xfb_source->srcWidth; - int hOffset = (static_cast(xfb_source->srcAddr) - static_cast(xfb_addr)) / (static_cast(fb_stride) * 2); + // use virtual xfb with offset + int xfb_height = xfb_source->srcHeight; + int xfb_width = xfb_source->srcWidth; + int hOffset = (static_cast(xfb_source->srcAddr) - static_cast(xfb_addr)) / + (static_cast(fb_stride) * 2); - if (g_ActiveConfig.bUseRealXFB) - { - drawRc = target_rc; - source_rc.right -= fb_stride - fb_width; - } - else - { - drawRc.top = target_rc.top + hOffset * target_rc.GetHeight() / static_cast(fb_height); - drawRc.bottom = target_rc.top + (hOffset + xfb_height) * target_rc.GetHeight() / static_cast(fb_height); - drawRc.left = target_rc.left + (target_rc.GetWidth() - xfb_width * target_rc.GetWidth() / static_cast(fb_stride)) / 2; - drawRc.right = target_rc.left + (target_rc.GetWidth() + xfb_width * target_rc.GetWidth() / static_cast(fb_stride)) / 2; + if (g_ActiveConfig.bUseRealXFB) + { + drawRc = target_rc; + source_rc.right -= fb_stride - fb_width; + } + else + { + drawRc.top = target_rc.top + hOffset * target_rc.GetHeight() / static_cast(fb_height); + drawRc.bottom = + target_rc.top + + (hOffset + xfb_height) * target_rc.GetHeight() / static_cast(fb_height); + drawRc.left = target_rc.left + + (target_rc.GetWidth() - + xfb_width * target_rc.GetWidth() / static_cast(fb_stride)) / + 2; + drawRc.right = target_rc.left + + (target_rc.GetWidth() + + xfb_width * target_rc.GetWidth() / static_cast(fb_stride)) / + 2; - // The following code disables auto stretch. Kept for reference. - // scale draw area for a 1 to 1 pixel mapping with the draw target - //float vScale = static_cast(fbHeight) / static_cast(s_backbuffer_height); - //float hScale = static_cast(fbWidth) / static_cast(s_backbuffer_width); - //drawRc.top *= vScale; - //drawRc.bottom *= vScale; - //drawRc.left *= hScale; - //drawRc.right *= hScale; + // The following code disables auto stretch. Kept for reference. + // scale draw area for a 1 to 1 pixel mapping with the draw target + // float vScale = static_cast(fbHeight) / static_cast(s_backbuffer_height); + // float hScale = static_cast(fbWidth) / static_cast(s_backbuffer_width); + // drawRc.top *= vScale; + // drawRc.bottom *= vScale; + // drawRc.left *= hScale; + // drawRc.right *= hScale; - source_rc.right -= Renderer::EFBToScaledX(fb_stride - fb_width); - } + source_rc.right -= Renderer::EFBToScaledX(fb_stride - fb_width); + } - BlitScreen(source_rc, drawRc, xfb_source->m_tex, xfb_source->texWidth, xfb_source->texHeight, gamma); - } - } - else - { - TargetRectangle source_rc = Renderer::ConvertEFBRectangle(rc); + BlitScreen(source_rc, drawRc, xfb_source->m_tex, xfb_source->texWidth, xfb_source->texHeight, + gamma); + } + } + else + { + TargetRectangle source_rc = Renderer::ConvertEFBRectangle(rc); - // EXISTINGD3D11TODO: Improve sampling algorithm for the pixel shader so that we can use the multisampled EFB texture as source - D3DTexture2D* read_texture = FramebufferManager::GetResolvedEFBColorTexture(); + // EXISTINGD3D11TODO: Improve sampling algorithm for the pixel shader so that we can use the + // multisampled EFB texture as source + D3DTexture2D* read_texture = FramebufferManager::GetResolvedEFBColorTexture(); - BlitScreen(source_rc, target_rc, read_texture, GetTargetWidth(), GetTargetHeight(), gamma); - } + BlitScreen(source_rc, target_rc, read_texture, GetTargetWidth(), GetTargetHeight(), gamma); + } - // done with drawing the game stuff, good moment to save a screenshot - if (s_bScreenshot) - { - std::lock_guard guard(s_criticalScreenshot); + // done with drawing the game stuff, good moment to save a screenshot + if (s_bScreenshot) + { + std::lock_guard guard(s_criticalScreenshot); - SaveScreenshot(s_sScreenshotName, GetTargetRectangle()); - s_sScreenshotName.clear(); - s_bScreenshot = false; - s_screenshotCompleted.Set(); - } + SaveScreenshot(s_sScreenshotName, GetTargetRectangle()); + s_sScreenshotName.clear(); + s_bScreenshot = false; + s_screenshotCompleted.Set(); + } - // Dump frames - static int w = 0, h = 0; - if (SConfig::GetInstance().m_DumpFrames) - { - static unsigned int s_record_width; - static unsigned int s_record_height; + // Dump frames + static int w = 0, h = 0; + if (SConfig::GetInstance().m_DumpFrames) + { + static unsigned int s_record_width; + static unsigned int s_record_height; - if (!s_screenshot_texture) - CreateScreenshotTexture(); + if (!s_screenshot_texture) + CreateScreenshotTexture(); - D3D12_BOX source_box = GetScreenshotSourceBox(target_rc); + D3D12_BOX source_box = GetScreenshotSourceBox(target_rc); - unsigned int source_width = source_box.right - source_box.left; - unsigned int source_height = source_box.bottom - source_box.top; + unsigned int source_width = source_box.right - source_box.left; + unsigned int source_height = source_box.bottom - source_box.top; - D3D12_TEXTURE_COPY_LOCATION dst_location = {}; - dst_location.pResource = s_screenshot_texture; - dst_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - dst_location.PlacedFootprint.Offset = 0; - dst_location.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - dst_location.PlacedFootprint.Footprint.Width = GetTargetRectangle().GetWidth(); - dst_location.PlacedFootprint.Footprint.Height = GetTargetRectangle().GetHeight(); - dst_location.PlacedFootprint.Footprint.Depth = 1; - dst_location.PlacedFootprint.Footprint.RowPitch = D3D::AlignValue(dst_location.PlacedFootprint.Footprint.Width * 4, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + D3D12_TEXTURE_COPY_LOCATION dst_location = {}; + dst_location.pResource = s_screenshot_texture; + dst_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + dst_location.PlacedFootprint.Offset = 0; + dst_location.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + dst_location.PlacedFootprint.Footprint.Width = GetTargetRectangle().GetWidth(); + dst_location.PlacedFootprint.Footprint.Height = GetTargetRectangle().GetHeight(); + dst_location.PlacedFootprint.Footprint.Depth = 1; + dst_location.PlacedFootprint.Footprint.RowPitch = D3D::AlignValue( + dst_location.PlacedFootprint.Footprint.Width * 4, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); - D3D12_TEXTURE_COPY_LOCATION src_location = {}; - src_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - src_location.SubresourceIndex = 0; - src_location.pResource = D3D::GetBackBuffer()->GetTex12(); + D3D12_TEXTURE_COPY_LOCATION src_location = {}; + src_location.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + src_location.SubresourceIndex = 0; + src_location.pResource = D3D::GetBackBuffer()->GetTex12(); - D3D::GetBackBuffer()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); - D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, &source_box); + D3D::GetBackBuffer()->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_COPY_SOURCE); + D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, + &source_box); - D3D::command_list_mgr->ExecuteQueuedWork(true); + D3D::command_list_mgr->ExecuteQueuedWork(true); - if (!bLastFrameDumped) - { - s_record_width = source_width; - s_record_height = source_height; - bAVIDumping = AVIDump::Start(s_record_width, s_record_height, AVIDump::DumpFormat::FORMAT_BGR); - if (!bAVIDumping) - { - PanicAlert("Error dumping frames to AVI."); - } - else - { - std::string msg = StringFromFormat("Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)", - File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), s_record_width, s_record_height); + if (!bLastFrameDumped) + { + s_record_width = source_width; + s_record_height = source_height; + bAVIDumping = + AVIDump::Start(s_record_width, s_record_height, AVIDump::DumpFormat::FORMAT_BGR); + if (!bAVIDumping) + { + PanicAlert("Error dumping frames to AVI."); + } + else + { + std::string msg = StringFromFormat("Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)", + File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), + s_record_width, s_record_height); - OSD::AddMessage(msg, 2000); - } - } - if (bAVIDumping) - { - if (frame_data.empty() || w != s_record_width || h != s_record_height) - { - frame_data.resize(3 * s_record_width * s_record_height); - w = s_record_width; - h = s_record_height; - } + OSD::AddMessage(msg, 2000); + } + } + if (bAVIDumping) + { + if (frame_data.empty() || w != s_record_width || h != s_record_height) + { + frame_data.resize(3 * s_record_width * s_record_height); + w = s_record_width; + h = s_record_height; + } - void* screenshot_texture_map; - D3D12_RANGE read_range = { 0, dst_location.PlacedFootprint.Footprint.RowPitch * source_height }; - CheckHR(s_screenshot_texture->Map(0, &read_range, &screenshot_texture_map)); - formatBufferDump(static_cast(screenshot_texture_map), &frame_data[0], source_width, source_height, dst_location.PlacedFootprint.Footprint.RowPitch); + void* screenshot_texture_map; + D3D12_RANGE read_range = {0, dst_location.PlacedFootprint.Footprint.RowPitch * source_height}; + CheckHR(s_screenshot_texture->Map(0, &read_range, &screenshot_texture_map)); + formatBufferDump(static_cast(screenshot_texture_map), &frame_data[0], source_width, + source_height, dst_location.PlacedFootprint.Footprint.RowPitch); - D3D12_RANGE write_range = {}; - s_screenshot_texture->Unmap(0, &write_range); + D3D12_RANGE write_range = {}; + s_screenshot_texture->Unmap(0, &write_range); - FlipImageData(&frame_data[0], w, h); - AVIDump::AddFrame(&frame_data[0], source_width, source_height); - } - bLastFrameDumped = true; - } - else - { - if (bLastFrameDumped && bAVIDumping) - { - std::vector().swap(frame_data); - w = h = 0; + FlipImageData(&frame_data[0], w, h); + AVIDump::AddFrame(&frame_data[0], source_width, source_height); + } + bLastFrameDumped = true; + } + else + { + if (bLastFrameDumped && bAVIDumping) + { + std::vector().swap(frame_data); + w = h = 0; - AVIDump::Stop(); - bAVIDumping = false; - OSD::AddMessage("Stop dumping frames to AVI", 2000); - } - bLastFrameDumped = false; - } + AVIDump::Stop(); + bAVIDumping = false; + OSD::AddMessage("Stop dumping frames to AVI", 2000); + } + bLastFrameDumped = false; + } - // Reset viewport for drawing text - D3D::SetViewportAndScissor(0, 0, GetBackbufferWidth(), GetBackbufferHeight()); + // Reset viewport for drawing text + D3D::SetViewportAndScissor(0, 0, GetBackbufferWidth(), GetBackbufferHeight()); - Renderer::DrawDebugText(); + Renderer::DrawDebugText(); - OSD::DrawMessages(); - D3D::EndFrame(); + OSD::DrawMessages(); + D3D::EndFrame(); - TextureCacheBase::Cleanup(frameCount); + TextureCacheBase::Cleanup(frameCount); - // Enable configuration changes - UpdateActiveConfig(); - TextureCacheBase::OnConfigChanged(g_ActiveConfig); + // Enable configuration changes + UpdateActiveConfig(); + TextureCacheBase::OnConfigChanged(g_ActiveConfig); - SetWindowSize(fb_stride, fb_height); + SetWindowSize(fb_stride, fb_height); - const bool window_resized = CheckForResize(); - const bool fullscreen = g_ActiveConfig.bFullscreen && !g_ActiveConfig.bBorderlessFullscreen && - !SConfig::GetInstance().bRenderToMain; + const bool window_resized = CheckForResize(); + const bool fullscreen = g_ActiveConfig.bFullscreen && !g_ActiveConfig.bBorderlessFullscreen && + !SConfig::GetInstance().bRenderToMain; - bool xfb_changed = s_last_xfb_mode != g_ActiveConfig.bUseRealXFB; + bool xfb_changed = s_last_xfb_mode != g_ActiveConfig.bUseRealXFB; - if (FramebufferManagerBase::LastXfbWidth() != fb_stride || FramebufferManagerBase::LastXfbHeight() != fb_height) - { - xfb_changed = true; - unsigned int xfb_w = (fb_stride < 1 || fb_stride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fb_stride; - unsigned int xfb_h = (fb_height < 1 || fb_height > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fb_height; - FramebufferManagerBase::SetLastXfbWidth(xfb_w); - FramebufferManagerBase::SetLastXfbHeight(xfb_h); - } + if (FramebufferManagerBase::LastXfbWidth() != fb_stride || + FramebufferManagerBase::LastXfbHeight() != fb_height) + { + xfb_changed = true; + unsigned int xfb_w = (fb_stride < 1 || fb_stride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fb_stride; + unsigned int xfb_h = (fb_height < 1 || fb_height > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fb_height; + FramebufferManagerBase::SetLastXfbWidth(xfb_w); + FramebufferManagerBase::SetLastXfbHeight(xfb_h); + } - // Flip/present backbuffer to frontbuffer here - D3D::Present(); + // Flip/present backbuffer to frontbuffer here + D3D::Present(); - // Resize the back buffers NOW to avoid flickering - if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height) || - xfb_changed || - window_resized || - s_last_efb_scale != g_ActiveConfig.iEFBScale || - s_last_multisamples != g_ActiveConfig.iMultisamples || - s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0)) - { - s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; + // Resize the back buffers NOW to avoid flickering + if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height) || xfb_changed || + window_resized || s_last_efb_scale != g_ActiveConfig.iEFBScale || + s_last_multisamples != g_ActiveConfig.iMultisamples || + s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0)) + { + s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; - // Block on any changes until the GPU catches up, so we can free resources safely. - D3D::command_list_mgr->ExecuteQueuedWork(true); + // Block on any changes until the GPU catches up, so we can free resources safely. + D3D::command_list_mgr->ExecuteQueuedWork(true); - if (s_last_multisamples != g_ActiveConfig.iMultisamples) - { - s_last_multisamples = g_ActiveConfig.iMultisamples; - StaticShaderCache::InvalidateMSAAShaders(); - gx_state_cache.OnMSAASettingsChanged(); - } + if (s_last_multisamples != g_ActiveConfig.iMultisamples) + { + s_last_multisamples = g_ActiveConfig.iMultisamples; + StaticShaderCache::InvalidateMSAAShaders(); + gx_state_cache.OnMSAASettingsChanged(); + } - if (window_resized) - { - // TODO: Aren't we still holding a reference to the back buffer right now? - D3D::Reset(); + if (window_resized) + { + // TODO: Aren't we still holding a reference to the back buffer right now? + D3D::Reset(); - if (s_screenshot_texture) - { - D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(s_screenshot_texture); - s_screenshot_texture = nullptr; - } + if (s_screenshot_texture) + { + D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(s_screenshot_texture); + s_screenshot_texture = nullptr; + } - s_backbuffer_width = D3D::GetBackBufferWidth(); - s_backbuffer_height = D3D::GetBackBufferHeight(); - } + s_backbuffer_width = D3D::GetBackBufferWidth(); + s_backbuffer_height = D3D::GetBackBufferHeight(); + } - UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); + UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); - s_last_efb_scale = g_ActiveConfig.iEFBScale; - s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; + s_last_efb_scale = g_ActiveConfig.iEFBScale; + s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; - PixelShaderManager::SetEfbScaleChanged(); + PixelShaderManager::SetEfbScaleChanged(); - D3D::GetBackBuffer()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - D3D::current_command_list->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV12(), FALSE, nullptr); + D3D::GetBackBuffer()->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_RENDER_TARGET); + D3D::current_command_list->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV12(), FALSE, + nullptr); - g_framebuffer_manager.reset(); - g_framebuffer_manager = std::make_unique(); - const float clear_color[4] = { 0.f, 0.f, 0.f, 1.f }; + g_framebuffer_manager.reset(); + g_framebuffer_manager = std::make_unique(); + const float clear_color[4] = {0.f, 0.f, 0.f, 1.f}; - FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - D3D::current_command_list->ClearRenderTargetView(FramebufferManager::GetEFBColorTexture()->GetRTV12(), clear_color, 0, nullptr); + FramebufferManager::GetEFBColorTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + D3D::current_command_list->ClearRenderTargetView( + FramebufferManager::GetEFBColorTexture()->GetRTV12(), clear_color, 0, nullptr); - FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE ); - D3D::current_command_list->ClearDepthStencilView(FramebufferManager::GetEFBDepthTexture()->GetDSV12(), D3D12_CLEAR_FLAG_DEPTH, 0.f, 0, 0, nullptr); - } + FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); + D3D::current_command_list->ClearDepthStencilView( + FramebufferManager::GetEFBDepthTexture()->GetDSV12(), D3D12_CLEAR_FLAG_DEPTH, 0.f, 0, 0, + nullptr); + } - // begin next frame - D3D::BeginFrame(); + // begin next frame + D3D::BeginFrame(); - FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE ); + FramebufferManager::GetEFBColorTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); - RestoreAPIState(); + RestoreAPIState(); } void Renderer::ResetAPIState() { - CHECK(0, "This should never be called.. just required for inheritance."); + CHECK(0, "This should never be called.. just required for inheritance."); } void Renderer::RestoreAPIState() { - // Restores viewport/scissor rects, which might have been - // overwritten elsewhere (particularly the viewport). - SetViewport(); - BPFunctions::SetScissor(); + // Restores viewport/scissor rects, which might have been + // overwritten elsewhere (particularly the viewport). + SetViewport(); + BPFunctions::SetScissor(); - FramebufferManager::RestoreEFBRenderTargets(); - BBox::Bind(); + FramebufferManager::RestoreEFBRenderTargets(); + BBox::Bind(); } static bool s_previous_use_dst_alpha = false; @@ -1019,77 +1057,75 @@ static D3DVertexFormat* s_previous_vertex_format = nullptr; void Renderer::ApplyState(bool use_dst_alpha) { - if (use_dst_alpha != s_previous_use_dst_alpha) - { - s_previous_use_dst_alpha = use_dst_alpha; - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); - } + if (use_dst_alpha != s_previous_use_dst_alpha) + { + s_previous_use_dst_alpha = use_dst_alpha; + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); + } - gx_state.blend.use_dst_alpha = use_dst_alpha; + gx_state.blend.use_dst_alpha = use_dst_alpha; - if (D3D::command_list_mgr->GetCommandListDirtyState(COMMAND_LIST_STATE_SAMPLERS)) - { - D3D12_GPU_DESCRIPTOR_HANDLE sample_group_gpu_handle; - sample_group_gpu_handle = D3D::sampler_descriptor_heap_mgr->GetHandleForSamplerGroup(gx_state.sampler, 8); + if (D3D::command_list_mgr->GetCommandListDirtyState(COMMAND_LIST_STATE_SAMPLERS)) + { + D3D12_GPU_DESCRIPTOR_HANDLE sample_group_gpu_handle; + sample_group_gpu_handle = + D3D::sampler_descriptor_heap_mgr->GetHandleForSamplerGroup(gx_state.sampler, 8); - D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SAMPLER, sample_group_gpu_handle); + D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SAMPLER, + sample_group_gpu_handle); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_SAMPLERS, false); - } + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_SAMPLERS, false); + } - // Uploads and binds required constant buffer data for all stages. - ShaderConstantsManager::LoadAndSetGeometryShaderConstants(); - ShaderConstantsManager::LoadAndSetPixelShaderConstants(); - ShaderConstantsManager::LoadAndSetVertexShaderConstants(); + // Uploads and binds required constant buffer data for all stages. + ShaderConstantsManager::LoadAndSetGeometryShaderConstants(); + ShaderConstantsManager::LoadAndSetPixelShaderConstants(); + ShaderConstantsManager::LoadAndSetVertexShaderConstants(); - if (D3D::command_list_mgr->GetCommandListDirtyState(COMMAND_LIST_STATE_PSO) || s_previous_vertex_format != reinterpret_cast(VertexLoaderManager::GetCurrentVertexFormat())) - { - s_previous_vertex_format = reinterpret_cast(VertexLoaderManager::GetCurrentVertexFormat()); + if (D3D::command_list_mgr->GetCommandListDirtyState(COMMAND_LIST_STATE_PSO) || + s_previous_vertex_format != + reinterpret_cast(VertexLoaderManager::GetCurrentVertexFormat())) + { + s_previous_vertex_format = + reinterpret_cast(VertexLoaderManager::GetCurrentVertexFormat()); - D3D12_PRIMITIVE_TOPOLOGY_TYPE topologyType = ShaderCache::GetCurrentPrimitiveTopology(); - RasterizerState modifiableRastState = gx_state.raster; + D3D12_PRIMITIVE_TOPOLOGY_TYPE topologyType = ShaderCache::GetCurrentPrimitiveTopology(); + RasterizerState modifiableRastState = gx_state.raster; - if (topologyType != D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE) - { - modifiableRastState.cull_mode = D3D12_CULL_MODE_NONE; - } + if (topologyType != D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE) + { + modifiableRastState.cull_mode = D3D12_CULL_MODE_NONE; + } - SmallPsoDesc pso_desc = { - ShaderCache::GetActiveGeometryShaderBytecode(), // D3D12_SHADER_BYTECODE GS; - ShaderCache::GetActivePixelShaderBytecode(), // D3D12_SHADER_BYTECODE PS; - ShaderCache::GetActiveVertexShaderBytecode(), // D3D12_SHADER_BYTECODE VS; - s_previous_vertex_format, // D3DVertexFormat* InputLayout; - gx_state.blend, // BlendState BlendState; - modifiableRastState, // RasterizerState RasterizerState; - gx_state.zmode, // ZMode DepthStencilState; - }; + SmallPsoDesc pso_desc = { + ShaderCache::GetActiveGeometryShaderBytecode(), // D3D12_SHADER_BYTECODE GS; + ShaderCache::GetActivePixelShaderBytecode(), // D3D12_SHADER_BYTECODE PS; + ShaderCache::GetActiveVertexShaderBytecode(), // D3D12_SHADER_BYTECODE VS; + s_previous_vertex_format, // D3DVertexFormat* InputLayout; + gx_state.blend, // BlendState BlendState; + modifiableRastState, // RasterizerState RasterizerState; + gx_state.zmode, // ZMode DepthStencilState; + }; - if (use_dst_alpha) - { - // restore actual state - SetBlendMode(false); - SetLogicOpMode(); - } + if (use_dst_alpha) + { + // restore actual state + SetBlendMode(false); + SetLogicOpMode(); + } - ID3D12PipelineState* pso = nullptr; - CheckHR( - gx_state_cache.GetPipelineStateObjectFromCache( - &pso_desc, - &pso, - topologyType, - ShaderCache::GetActiveGeometryShaderUid(), - ShaderCache::GetActivePixelShaderUid(), - ShaderCache::GetActiveVertexShaderUid() - ) - ); + ID3D12PipelineState* pso = nullptr; + CheckHR(gx_state_cache.GetPipelineStateObjectFromCache( + &pso_desc, &pso, topologyType, ShaderCache::GetActiveGeometryShaderUid(), + ShaderCache::GetActivePixelShaderUid(), ShaderCache::GetActiveVertexShaderUid())); - D3D::current_command_list->SetPipelineState(pso); + D3D::current_command_list->SetPipelineState(pso); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, false); - } + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, false); + } - // Always called prior to drawing, so we can invalidate the CPU EFB copies here. - FramebufferManager::InvalidateEFBAccessCopies(); + // Always called prior to drawing, so we can invalidate the CPU EFB copies here. + FramebufferManager::InvalidateEFBAccessCopies(); } void Renderer::RestoreState() @@ -1098,315 +1134,333 @@ void Renderer::RestoreState() void Renderer::ApplyCullDisable() { - // This functionality is handled directly in ApplyState. + // This functionality is handled directly in ApplyState. } void Renderer::RestoreCull() { - // This functionality is handled directly in ApplyState. + // This functionality is handled directly in ApplyState. } void Renderer::SetGenerationMode() { - const D3D12_CULL_MODE d3d_cull_modes[4] = - { - D3D12_CULL_MODE_NONE, - D3D12_CULL_MODE_BACK, - D3D12_CULL_MODE_FRONT, - D3D12_CULL_MODE_BACK - }; + const D3D12_CULL_MODE d3d_cull_modes[4] = {D3D12_CULL_MODE_NONE, D3D12_CULL_MODE_BACK, + D3D12_CULL_MODE_FRONT, D3D12_CULL_MODE_BACK}; - // rastdc.FrontCounterClockwise must be false for this to work - // EXISTINGD3D11TODO: GX_CULL_ALL not supported, yet! - gx_state.raster.cull_mode = d3d_cull_modes[bpmem.genMode.cullmode]; + // rastdc.FrontCounterClockwise must be false for this to work + // EXISTINGD3D11TODO: GX_CULL_ALL not supported, yet! + gx_state.raster.cull_mode = d3d_cull_modes[bpmem.genMode.cullmode]; - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); } void Renderer::SetDepthMode() { - gx_state.zmode.hex = bpmem.zmode.hex; + gx_state.zmode.hex = bpmem.zmode.hex; - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); } void Renderer::SetLogicOpMode() { - // D3D11 doesn't support logic blending, so this is a huge hack - // EXISTINGD3D11TODO: Make use of D3D11.1's logic blending support - // D3D12TODO: Obviously these are always available in D3D12.. + // D3D11 doesn't support logic blending, so this is a huge hack + // EXISTINGD3D11TODO: Make use of D3D11.1's logic blending support + // D3D12TODO: Obviously these are always available in D3D12.. - // 0 0x00 - // 1 Source & destination - // 2 Source & ~destination - // 3 Source - // 4 ~Source & destination - // 5 Destination - // 6 Source ^ destination = Source & ~destination | ~Source & destination - // 7 Source | destination - // 8 ~(Source | destination) - // 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination - // 10 ~Destination - // 11 Source | ~destination - // 12 ~Source - // 13 ~Source | destination - // 14 ~(Source & destination) - // 15 0xff - const D3D12_BLEND_OP d3d_logic_ops[16] = - { - D3D12_BLEND_OP_ADD,//0 - D3D12_BLEND_OP_ADD,//1 - D3D12_BLEND_OP_SUBTRACT,//2 - D3D12_BLEND_OP_ADD,//3 - D3D12_BLEND_OP_REV_SUBTRACT,//4 - D3D12_BLEND_OP_ADD,//5 - D3D12_BLEND_OP_MAX,//6 - D3D12_BLEND_OP_ADD,//7 - D3D12_BLEND_OP_MAX,//8 - D3D12_BLEND_OP_MAX,//9 - D3D12_BLEND_OP_ADD,//10 - D3D12_BLEND_OP_ADD,//11 - D3D12_BLEND_OP_ADD,//12 - D3D12_BLEND_OP_ADD,//13 - D3D12_BLEND_OP_ADD,//14 - D3D12_BLEND_OP_ADD//15 - }; - const D3D12_BLEND d3d_logic_op_src_factors[16] = - { - D3D12_BLEND_ZERO,//0 - D3D12_BLEND_DEST_COLOR,//1 - D3D12_BLEND_ONE,//2 - D3D12_BLEND_ONE,//3 - D3D12_BLEND_DEST_COLOR,//4 - D3D12_BLEND_ZERO,//5 - D3D12_BLEND_INV_DEST_COLOR,//6 - D3D12_BLEND_INV_DEST_COLOR,//7 - D3D12_BLEND_INV_SRC_COLOR,//8 - D3D12_BLEND_INV_SRC_COLOR,//9 - D3D12_BLEND_INV_DEST_COLOR,//10 - D3D12_BLEND_ONE,//11 - D3D12_BLEND_INV_SRC_COLOR,//12 - D3D12_BLEND_INV_SRC_COLOR,//13 - D3D12_BLEND_INV_DEST_COLOR,//14 - D3D12_BLEND_ONE//15 - }; - const D3D12_BLEND d3d_logic_op_dest_factors[16] = - { - D3D12_BLEND_ZERO,//0 - D3D12_BLEND_ZERO,//1 - D3D12_BLEND_INV_SRC_COLOR,//2 - D3D12_BLEND_ZERO,//3 - D3D12_BLEND_ONE,//4 - D3D12_BLEND_ONE,//5 - D3D12_BLEND_INV_SRC_COLOR,//6 - D3D12_BLEND_ONE,//7 - D3D12_BLEND_INV_DEST_COLOR,//8 - D3D12_BLEND_SRC_COLOR,//9 - D3D12_BLEND_INV_DEST_COLOR,//10 - D3D12_BLEND_INV_DEST_COLOR,//11 - D3D12_BLEND_INV_SRC_COLOR,//12 - D3D12_BLEND_ONE,//13 - D3D12_BLEND_INV_SRC_COLOR,//14 - D3D12_BLEND_ONE//15 - }; + // 0 0x00 + // 1 Source & destination + // 2 Source & ~destination + // 3 Source + // 4 ~Source & destination + // 5 Destination + // 6 Source ^ destination = Source & ~destination | ~Source & destination + // 7 Source | destination + // 8 ~(Source | destination) + // 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination + // 10 ~Destination + // 11 Source | ~destination + // 12 ~Source + // 13 ~Source | destination + // 14 ~(Source & destination) + // 15 0xff + const D3D12_BLEND_OP d3d_logic_ops[16] = { + D3D12_BLEND_OP_ADD, // 0 + D3D12_BLEND_OP_ADD, // 1 + D3D12_BLEND_OP_SUBTRACT, // 2 + D3D12_BLEND_OP_ADD, // 3 + D3D12_BLEND_OP_REV_SUBTRACT, // 4 + D3D12_BLEND_OP_ADD, // 5 + D3D12_BLEND_OP_MAX, // 6 + D3D12_BLEND_OP_ADD, // 7 + D3D12_BLEND_OP_MAX, // 8 + D3D12_BLEND_OP_MAX, // 9 + D3D12_BLEND_OP_ADD, // 10 + D3D12_BLEND_OP_ADD, // 11 + D3D12_BLEND_OP_ADD, // 12 + D3D12_BLEND_OP_ADD, // 13 + D3D12_BLEND_OP_ADD, // 14 + D3D12_BLEND_OP_ADD // 15 + }; + const D3D12_BLEND d3d_logic_op_src_factors[16] = { + D3D12_BLEND_ZERO, // 0 + D3D12_BLEND_DEST_COLOR, // 1 + D3D12_BLEND_ONE, // 2 + D3D12_BLEND_ONE, // 3 + D3D12_BLEND_DEST_COLOR, // 4 + D3D12_BLEND_ZERO, // 5 + D3D12_BLEND_INV_DEST_COLOR, // 6 + D3D12_BLEND_INV_DEST_COLOR, // 7 + D3D12_BLEND_INV_SRC_COLOR, // 8 + D3D12_BLEND_INV_SRC_COLOR, // 9 + D3D12_BLEND_INV_DEST_COLOR, // 10 + D3D12_BLEND_ONE, // 11 + D3D12_BLEND_INV_SRC_COLOR, // 12 + D3D12_BLEND_INV_SRC_COLOR, // 13 + D3D12_BLEND_INV_DEST_COLOR, // 14 + D3D12_BLEND_ONE // 15 + }; + const D3D12_BLEND d3d_logic_op_dest_factors[16] = { + D3D12_BLEND_ZERO, // 0 + D3D12_BLEND_ZERO, // 1 + D3D12_BLEND_INV_SRC_COLOR, // 2 + D3D12_BLEND_ZERO, // 3 + D3D12_BLEND_ONE, // 4 + D3D12_BLEND_ONE, // 5 + D3D12_BLEND_INV_SRC_COLOR, // 6 + D3D12_BLEND_ONE, // 7 + D3D12_BLEND_INV_DEST_COLOR, // 8 + D3D12_BLEND_SRC_COLOR, // 9 + D3D12_BLEND_INV_DEST_COLOR, // 10 + D3D12_BLEND_INV_DEST_COLOR, // 11 + D3D12_BLEND_INV_SRC_COLOR, // 12 + D3D12_BLEND_ONE, // 13 + D3D12_BLEND_INV_SRC_COLOR, // 14 + D3D12_BLEND_ONE // 15 + }; - if (bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable) - { - gx_state.blend.blend_enable = true; - gx_state.blend.blend_op = d3d_logic_ops[bpmem.blendmode.logicmode]; - gx_state.blend.src_blend = d3d_logic_op_src_factors[bpmem.blendmode.logicmode]; - gx_state.blend.dst_blend = d3d_logic_op_dest_factors[bpmem.blendmode.logicmode]; - } - else - { - SetBlendMode(true); - } + if (bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable) + { + gx_state.blend.blend_enable = true; + gx_state.blend.blend_op = d3d_logic_ops[bpmem.blendmode.logicmode]; + gx_state.blend.src_blend = d3d_logic_op_src_factors[bpmem.blendmode.logicmode]; + gx_state.blend.dst_blend = d3d_logic_op_dest_factors[bpmem.blendmode.logicmode]; + } + else + { + SetBlendMode(true); + } - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); } void Renderer::SetDitherMode() { - // EXISTINGD3D11TODO: Set dither mode to bpmem.blendmode.dither + // EXISTINGD3D11TODO: Set dither mode to bpmem.blendmode.dither } void Renderer::SetSamplerState(int stage, int tex_index, bool custom_tex) { - const FourTexUnits& tex = bpmem.tex[tex_index]; - const TexMode0& tm0 = tex.texMode0[stage]; - const TexMode1& tm1 = tex.texMode1[stage]; - SamplerState new_state = {}; + const FourTexUnits& tex = bpmem.tex[tex_index]; + const TexMode0& tm0 = tex.texMode0[stage]; + const TexMode1& tm1 = tex.texMode1[stage]; + SamplerState new_state = {}; - if (tex_index) - stage += 4; + if (tex_index) + stage += 4; - if (g_ActiveConfig.bForceFiltering) - { - // Only use mipmaps if the game says they are available. - new_state.min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4; - new_state.mag_filter = 1; // linear mag - } - else - { - new_state.min_filter = tm0.min_filter; - new_state.mag_filter = tm0.mag_filter; - } + if (g_ActiveConfig.bForceFiltering) + { + // Only use mipmaps if the game says they are available. + new_state.min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4; + new_state.mag_filter = 1; // linear mag + } + else + { + new_state.min_filter = tm0.min_filter; + new_state.mag_filter = tm0.mag_filter; + } - new_state.wrap_s = tm0.wrap_s; - new_state.wrap_t = tm0.wrap_t; - new_state.max_lod = tm1.max_lod; - new_state.min_lod = tm1.min_lod; - new_state.lod_bias = tm0.lod_bias; + new_state.wrap_s = tm0.wrap_s; + new_state.wrap_t = tm0.wrap_t; + new_state.max_lod = tm1.max_lod; + new_state.min_lod = tm1.min_lod; + new_state.lod_bias = tm0.lod_bias; - // custom textures may have higher resolution, so disable the max_lod - if (custom_tex) - { - new_state.max_lod = 255; - } + // custom textures may have higher resolution, so disable the max_lod + if (custom_tex) + { + new_state.max_lod = 255; + } - if (new_state.hex != gx_state.sampler[stage].hex) - { - gx_state.sampler[stage].hex = new_state.hex; - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_SAMPLERS, true); - } + if (new_state.hex != gx_state.sampler[stage].hex) + { + gx_state.sampler[stage].hex = new_state.hex; + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_SAMPLERS, true); + } } void Renderer::SetInterlacingMode() { - // EXISTINGD3D11TODO + // EXISTINGD3D11TODO } int Renderer::GetMaxTextureSize() { - return DX12::D3D::GetMaxTextureSize(); + return DX12::D3D::GetMaxTextureSize(); } u16 Renderer::BBoxRead(int index) { - // Here we get the min/max value of the truncated position of the upscaled framebuffer. - // So we have to correct them to the unscaled EFB sizes. - int value = BBox::Get(index); + // Here we get the min/max value of the truncated position of the upscaled framebuffer. + // So we have to correct them to the unscaled EFB sizes. + int value = BBox::Get(index); - if (index < 2) - { - // left/right - value = value * EFB_WIDTH / s_target_width; - } - else - { - // up/down - value = value * EFB_HEIGHT / s_target_height; - } - if (index & 1) - value++; // fix max values to describe the outer border + if (index < 2) + { + // left/right + value = value * EFB_WIDTH / s_target_width; + } + else + { + // up/down + value = value * EFB_HEIGHT / s_target_height; + } + if (index & 1) + value++; // fix max values to describe the outer border - return value; + return value; } void Renderer::BBoxWrite(int index, u16 value) { - int local_value = value; // u16 isn't enough to multiply by the efb width - if (index & 1) - local_value--; - if (index < 2) - { - local_value = local_value * s_target_width / EFB_WIDTH; - } - else - { - local_value = local_value * s_target_height / EFB_HEIGHT; - } + int local_value = value; // u16 isn't enough to multiply by the efb width + if (index & 1) + local_value--; + if (index < 2) + { + local_value = local_value * s_target_width / EFB_WIDTH; + } + else + { + local_value = local_value * s_target_height / EFB_HEIGHT; + } - BBox::Set(index, local_value); + BBox::Set(index, local_value); } -void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, u32 src_width, u32 src_height, float gamma) +void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, + u32 src_width, u32 src_height, float gamma) { - if (g_ActiveConfig.iStereoMode == STEREO_SBS || g_ActiveConfig.iStereoMode == STEREO_TAB) - { - TargetRectangle left_rc, right_rc; - ConvertStereoRectangle(dst, left_rc, right_rc); + if (g_ActiveConfig.iStereoMode == STEREO_SBS || g_ActiveConfig.iStereoMode == STEREO_TAB) + { + TargetRectangle left_rc, right_rc; + ConvertStereoRectangle(dst, left_rc, right_rc); - // Swap chain backbuffer is never multisampled.. + // Swap chain backbuffer is never multisampled.. - D3D::SetViewportAndScissor(left_rc.left, left_rc.top, left_rc.GetWidth(), left_rc.GetHeight()); - D3D::DrawShadedTexQuad(src_texture, src.AsRECT(), src_width, src_height, StaticShaderCache::GetColorCopyPixelShader(false), StaticShaderCache::GetSimpleVertexShader(), StaticShaderCache::GetSimpleVertexShaderInputLayout(), D3D12_SHADER_BYTECODE(), gamma, 0, DXGI_FORMAT_R8G8B8A8_UNORM, false, false); + D3D::SetViewportAndScissor(left_rc.left, left_rc.top, left_rc.GetWidth(), left_rc.GetHeight()); + D3D::DrawShadedTexQuad(src_texture, src.AsRECT(), src_width, src_height, + StaticShaderCache::GetColorCopyPixelShader(false), + StaticShaderCache::GetSimpleVertexShader(), + StaticShaderCache::GetSimpleVertexShaderInputLayout(), + D3D12_SHADER_BYTECODE(), gamma, 0, DXGI_FORMAT_R8G8B8A8_UNORM, false, + false); - D3D::SetViewportAndScissor(right_rc.left, right_rc.top, right_rc.GetWidth(), right_rc.GetHeight()); - D3D::DrawShadedTexQuad(src_texture, src.AsRECT(), src_width, src_height, StaticShaderCache::GetColorCopyPixelShader(false), StaticShaderCache::GetSimpleVertexShader(), StaticShaderCache::GetSimpleVertexShaderInputLayout(), D3D12_SHADER_BYTECODE(), gamma, 1, DXGI_FORMAT_R8G8B8A8_UNORM, false, false); - } - else if (g_ActiveConfig.iStereoMode == STEREO_3DVISION) - { - // D3D12TODO - // Not currently supported on D3D12 backend. Implemented (but untested) code kept for reference. + D3D::SetViewportAndScissor(right_rc.left, right_rc.top, right_rc.GetWidth(), + right_rc.GetHeight()); + D3D::DrawShadedTexQuad(src_texture, src.AsRECT(), src_width, src_height, + StaticShaderCache::GetColorCopyPixelShader(false), + StaticShaderCache::GetSimpleVertexShader(), + StaticShaderCache::GetSimpleVertexShaderInputLayout(), + D3D12_SHADER_BYTECODE(), gamma, 1, DXGI_FORMAT_R8G8B8A8_UNORM, false, + false); + } + else if (g_ActiveConfig.iStereoMode == STEREO_3DVISION) + { + // D3D12TODO + // Not currently supported on D3D12 backend. Implemented (but untested) code kept for reference. - //if (!s_3d_vision_texture) - // Create3DVisionTexture(s_backbuffer_width, s_backbuffer_height); + // if (!s_3d_vision_texture) + // Create3DVisionTexture(s_backbuffer_width, s_backbuffer_height); - //D3D12_VIEWPORT leftVp12 = { static_cast(dst.left), static_cast(dst.top), static_cast(dst.GetWidth()), static_cast(dst.GetHeight()), D3D12_MIN_DEPTH, D3D12_MAX_DEPTH }; - //D3D12_VIEWPORT rightVp12 = { static_cast(dst.left + s_backbuffer_width), static_cast(dst.top), static_cast(dst.GetWidth()), static_cast(dst.GetHeight()), D3D12_MIN_DEPTH, D3D12_MAX_DEPTH }; + // D3D12_VIEWPORT leftVp12 = { static_cast(dst.left), static_cast(dst.top), + // static_cast(dst.GetWidth()), static_cast(dst.GetHeight()), D3D12_MIN_DEPTH, + // D3D12_MAX_DEPTH }; + // D3D12_VIEWPORT rightVp12 = { static_cast(dst.left + s_backbuffer_width), + // static_cast(dst.top), static_cast(dst.GetWidth()), + // static_cast(dst.GetHeight()), D3D12_MIN_DEPTH, D3D12_MAX_DEPTH }; - //// Render to staging texture which is double the width of the backbuffer - //s_3d_vision_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - //D3D::current_command_list->OMSetRenderTargets(1, &s_3d_vision_texture->GetRTV12(), FALSE, nullptr); + //// Render to staging texture which is double the width of the backbuffer + // s_3d_vision_texture->TransitionToResourceState(D3D::current_command_list, + // D3D12_RESOURCE_STATE_RENDER_TARGET); + // D3D::current_command_list->OMSetRenderTargets(1, &s_3d_vision_texture->GetRTV12(), FALSE, + // nullptr); - //D3D::current_command_list->RSSetViewports(1, &leftVp12); - //D3D::DrawShadedTexQuad(src_texture, src.AsRECT(), src_width, src_height, StaticShaderCache::GetColorCopyPixelShader(false), StaticShaderCache::GetSimpleVertexShader(), StaticShaderCache::GetSimpleVertexShaderInputLayout(), D3D12_SHADER_BYTECODE(), gamma, 0, DXGI_FORMAT_R8G8B8A8_UNORM, false, s_3d_vision_texture->GetMultisampled()); + // D3D::current_command_list->RSSetViewports(1, &leftVp12); + // D3D::DrawShadedTexQuad(src_texture, src.AsRECT(), src_width, src_height, + // StaticShaderCache::GetColorCopyPixelShader(false), + // StaticShaderCache::GetSimpleVertexShader(), + // StaticShaderCache::GetSimpleVertexShaderInputLayout(), D3D12_SHADER_BYTECODE(), gamma, 0, + // DXGI_FORMAT_R8G8B8A8_UNORM, false, s_3d_vision_texture->GetMultisampled()); - //D3D::current_command_list->RSSetViewports(1, &rightVp12); - //D3D::DrawShadedTexQuad(src_texture, src.AsRECT(), src_width, src_height, StaticShaderCache::GetColorCopyPixelShader(false), StaticShaderCache::GetSimpleVertexShader(), StaticShaderCache::GetSimpleVertexShaderInputLayout(), D3D12_SHADER_BYTECODE(), gamma, 1, DXGI_FORMAT_R8G8B8A8_UNORM, false, s_3d_vision_texture->GetMultisampled()); + // D3D::current_command_list->RSSetViewports(1, &rightVp12); + // D3D::DrawShadedTexQuad(src_texture, src.AsRECT(), src_width, src_height, + // StaticShaderCache::GetColorCopyPixelShader(false), + // StaticShaderCache::GetSimpleVertexShader(), + // StaticShaderCache::GetSimpleVertexShaderInputLayout(), D3D12_SHADER_BYTECODE(), gamma, 1, + // DXGI_FORMAT_R8G8B8A8_UNORM, false, s_3d_vision_texture->GetMultisampled()); - //// Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should - //// recognize the signature and automatically include the right eye frame. - //// D3D12TODO: Does this work on D3D12? + //// Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should + //// recognize the signature and automatically include the right eye frame. + //// D3D12TODO: Does this work on D3D12? - //D3D12_BOX box = CD3DX12_BOX(0, 0, 0, s_backbuffer_width, s_backbuffer_height, 1); - //D3D12_TEXTURE_COPY_LOCATION dst = CD3DX12_TEXTURE_COPY_LOCATION(D3D::GetBackBuffer()->GetTex12(), 0); - //D3D12_TEXTURE_COPY_LOCATION src = CD3DX12_TEXTURE_COPY_LOCATION(s_3d_vision_texture->GetTex12(), 0); + // D3D12_BOX box = CD3DX12_BOX(0, 0, 0, s_backbuffer_width, s_backbuffer_height, 1); + // D3D12_TEXTURE_COPY_LOCATION dst = + // CD3DX12_TEXTURE_COPY_LOCATION(D3D::GetBackBuffer()->GetTex12(), 0); + // D3D12_TEXTURE_COPY_LOCATION src = + // CD3DX12_TEXTURE_COPY_LOCATION(s_3d_vision_texture->GetTex12(), 0); - //D3D::GetBackBuffer()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_DEST); - //s_3d_vision_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); - //D3D::current_command_list->CopyTextureRegion(&dst, 0, 0, 0, &src, &box); + // D3D::GetBackBuffer()->TransitionToResourceState(D3D::current_command_list, + // D3D12_RESOURCE_STATE_COPY_DEST); + // s_3d_vision_texture->TransitionToResourceState(D3D::current_command_list, + // D3D12_RESOURCE_STATE_COPY_SOURCE); + // D3D::current_command_list->CopyTextureRegion(&dst, 0, 0, 0, &src, &box); - //// Restore render target to backbuffer - //D3D::GetBackBuffer()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - //D3D::current_command_list->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV12(), FALSE, nullptr); - } - else - { - D3D::SetViewportAndScissor(dst.left, dst.top, dst.GetWidth(), dst.GetHeight()); + //// Restore render target to backbuffer + // D3D::GetBackBuffer()->TransitionToResourceState(D3D::current_command_list, + // D3D12_RESOURCE_STATE_RENDER_TARGET); + // D3D::current_command_list->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV12(), FALSE, + // nullptr); + } + else + { + D3D::SetViewportAndScissor(dst.left, dst.top, dst.GetWidth(), dst.GetHeight()); - D3D::DrawShadedTexQuad( - src_texture, - src.AsRECT(), - src_width, - src_height, - (g_Config.iStereoMode == STEREO_ANAGLYPH) ? StaticShaderCache::GetAnaglyphPixelShader() : StaticShaderCache::GetColorCopyPixelShader(false), - StaticShaderCache::GetSimpleVertexShader(), - StaticShaderCache::GetSimpleVertexShaderInputLayout(), - D3D12_SHADER_BYTECODE(), - gamma, - 0, - DXGI_FORMAT_R8G8B8A8_UNORM, - false, - false // Backbuffer never multisampled. - ); - } + D3D::DrawShadedTexQuad(src_texture, src.AsRECT(), src_width, src_height, + (g_Config.iStereoMode == STEREO_ANAGLYPH) ? + StaticShaderCache::GetAnaglyphPixelShader() : + StaticShaderCache::GetColorCopyPixelShader(false), + StaticShaderCache::GetSimpleVertexShader(), + StaticShaderCache::GetSimpleVertexShaderInputLayout(), + D3D12_SHADER_BYTECODE(), gamma, 0, DXGI_FORMAT_R8G8B8A8_UNORM, false, + false // Backbuffer never multisampled. + ); + } } D3D12_BLEND_DESC Renderer::GetResetBlendDesc() { - return g_reset_blend_desc; + return g_reset_blend_desc; } D3D12_DEPTH_STENCIL_DESC Renderer::GetResetDepthStencilDesc() { - return g_reset_depth_desc; + return g_reset_depth_desc; } D3D12_RASTERIZER_DESC Renderer::GetResetRasterizerDesc() { - return g_reset_rast_desc; + return g_reset_rast_desc; } } // namespace DX12 diff --git a/Source/Core/VideoBackends/D3D12/Render.h b/Source/Core/VideoBackends/D3D12/Render.h index bf0c73dad9..21bb00cc76 100644 --- a/Source/Core/VideoBackends/D3D12/Render.h +++ b/Source/Core/VideoBackends/D3D12/Render.h @@ -9,62 +9,63 @@ namespace DX12 { - class Renderer final : public ::Renderer { public: - Renderer(void*& window_handle); - ~Renderer(); + Renderer(void*& window_handle); + ~Renderer(); - void SetColorMask() override; - void SetBlendMode(bool force_update) override; - void SetScissorRect(const EFBRectangle& rc) override; - void SetGenerationMode() override; - void SetDepthMode() override; - void SetLogicOpMode() override; - void SetDitherMode() override; - void SetSamplerState(int stage, int tex_index, bool custom_tex) override; - void SetInterlacingMode() override; - void SetViewport() override; + void SetColorMask() override; + void SetBlendMode(bool force_update) override; + void SetScissorRect(const EFBRectangle& rc) override; + void SetGenerationMode() override; + void SetDepthMode() override; + void SetLogicOpMode() override; + void SetDitherMode() override; + void SetSamplerState(int stage, int tex_index, bool custom_tex) override; + void SetInterlacingMode() override; + void SetViewport() override; - // TODO: Fix confusing names (see ResetAPIState and RestoreAPIState) - void ApplyState(bool use_dst_alpha) override; - void RestoreState() override; + // TODO: Fix confusing names (see ResetAPIState and RestoreAPIState) + void ApplyState(bool use_dst_alpha) override; + void RestoreState() override; - void ApplyCullDisable(); - void RestoreCull(); + void ApplyCullDisable(); + void RestoreCull(); - void RenderText(const std::string& text, int left, int top, u32 color) override; + void RenderText(const std::string& text, int left, int top, u32 color) override; - u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; - void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override; + u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; + void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override; - u16 BBoxRead(int index) override; - void BBoxWrite(int index, u16 value) override; + u16 BBoxRead(int index) override; + void BBoxWrite(int index, u16 value) override; - void ResetAPIState() override; - void RestoreAPIState() override; + void ResetAPIState() override; + void RestoreAPIState() override; - TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; + TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; - void SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, const EFBRectangle& rc, float gamma) override; + void SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, const EFBRectangle& rc, + float gamma) override; - void ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha_enable, bool z_enable, u32 color, u32 z) override; + void ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha_enable, bool z_enable, + u32 color, u32 z) override; - void ReinterpretPixelData(unsigned int conv_type) override; + void ReinterpretPixelData(unsigned int conv_type) override; - bool SaveScreenshot(const std::string& filename, const TargetRectangle& rc) override; + bool SaveScreenshot(const std::string& filename, const TargetRectangle& rc) override; - static bool CheckForResize(); + static bool CheckForResize(); - int GetMaxTextureSize() override; + int GetMaxTextureSize() override; - static D3D12_BLEND_DESC GetResetBlendDesc(); - static D3D12_DEPTH_STENCIL_DESC GetResetDepthStencilDesc(); - static D3D12_RASTERIZER_DESC GetResetRasterizerDesc(); + static D3D12_BLEND_DESC GetResetBlendDesc(); + static D3D12_DEPTH_STENCIL_DESC GetResetDepthStencilDesc(); + static D3D12_RASTERIZER_DESC GetResetRasterizerDesc(); private: - void BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, u32 src_width, u32 src_height, float gamma); + void BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, + u32 src_width, u32 src_height, float gamma); }; - } diff --git a/Source/Core/VideoBackends/D3D12/ShaderCache.cpp b/Source/Core/VideoBackends/D3D12/ShaderCache.cpp index 1152ea19b6..2f93956003 100644 --- a/Source/Core/VideoBackends/D3D12/ShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D12/ShaderCache.cpp @@ -15,10 +15,10 @@ namespace DX12 { - // Primitive topology type is always triangle, unless the GS stage is used. This is consumed // by the PSO created in Renderer::ApplyState. -static D3D12_PRIMITIVE_TOPOLOGY_TYPE s_current_primitive_topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; +static D3D12_PRIMITIVE_TOPOLOGY_TYPE s_current_primitive_topology = + D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; using GsBytecodeCache = std::map; using PsBytecodeCache = std::map; @@ -53,336 +53,364 @@ static GeometryShaderUid s_last_geometry_shader_uid; static PixelShaderUid s_last_pixel_shader_uid; static VertexShaderUid s_last_vertex_shader_uid; -template +template class ShaderCacheInserter final : public LinearDiskCacheReader { public: - void Read(const UidType &key, const u8* value, u32 value_size) - { - ID3DBlob* blob = nullptr; - CheckHR(d3d_create_blob(value_size, &blob)); - memcpy(blob->GetBufferPointer(), value, value_size); + void Read(const UidType& key, const u8* value, u32 value_size) + { + ID3DBlob* blob = nullptr; + CheckHR(d3d_create_blob(value_size, &blob)); + memcpy(blob->GetBufferPointer(), value, value_size); - ShaderCache::InsertByteCode(key, cache, blob); - } + ShaderCache::InsertByteCode(key, cache, blob); + } }; void ShaderCache::Init() { - // This class intentionally shares its shader cache files with DX11, as the shaders are (right now) identical. - // Reduces unnecessary compilation when switching between APIs. + // This class intentionally shares its shader cache files with DX11, as the shaders are (right + // now) identical. + // Reduces unnecessary compilation when switching between APIs. - s_last_geometry_shader_bytecode = {}; - s_last_pixel_shader_bytecode = {}; - s_last_vertex_shader_bytecode = {}; - s_last_geometry_shader_uid = {}; - s_last_pixel_shader_uid = {}; - s_last_vertex_shader_uid = {}; + s_last_geometry_shader_bytecode = {}; + s_last_pixel_shader_bytecode = {}; + s_last_vertex_shader_bytecode = {}; + s_last_geometry_shader_uid = {}; + s_last_pixel_shader_uid = {}; + s_last_vertex_shader_uid = {}; - // Ensure shader cache directory exists.. - std::string shader_cache_path = File::GetUserPath(D_SHADERCACHE_IDX); + // Ensure shader cache directory exists.. + std::string shader_cache_path = File::GetUserPath(D_SHADERCACHE_IDX); - if (!File::Exists(shader_cache_path)) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + if (!File::Exists(shader_cache_path)) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - std::string title_unique_id = SConfig::GetInstance().m_strUniqueID.c_str(); + std::string title_unique_id = SConfig::GetInstance().m_strUniqueID.c_str(); - std::string gs_cache_filename = StringFromFormat("%sdx11-%s-gs.cache", shader_cache_path.c_str(), title_unique_id.c_str()); - std::string ps_cache_filename = StringFromFormat("%sdx11-%s-ps.cache", shader_cache_path.c_str(), title_unique_id.c_str()); - std::string vs_cache_filename = StringFromFormat("%sdx11-%s-vs.cache", shader_cache_path.c_str(), title_unique_id.c_str()); + std::string gs_cache_filename = + StringFromFormat("%sdx11-%s-gs.cache", shader_cache_path.c_str(), title_unique_id.c_str()); + std::string ps_cache_filename = + StringFromFormat("%sdx11-%s-ps.cache", shader_cache_path.c_str(), title_unique_id.c_str()); + std::string vs_cache_filename = + StringFromFormat("%sdx11-%s-vs.cache", shader_cache_path.c_str(), title_unique_id.c_str()); - ShaderCacheInserter gs_inserter; - s_gs_disk_cache.OpenAndRead(gs_cache_filename, gs_inserter); + ShaderCacheInserter gs_inserter; + s_gs_disk_cache.OpenAndRead(gs_cache_filename, gs_inserter); - ShaderCacheInserter ps_inserter; - s_ps_disk_cache.OpenAndRead(ps_cache_filename, ps_inserter); + ShaderCacheInserter ps_inserter; + s_ps_disk_cache.OpenAndRead(ps_cache_filename, ps_inserter); - ShaderCacheInserter vs_inserter; - s_vs_disk_cache.OpenAndRead(vs_cache_filename, vs_inserter); + ShaderCacheInserter vs_inserter; + s_vs_disk_cache.OpenAndRead(vs_cache_filename, vs_inserter); - // Clear out cache when debugging shaders to ensure stale ones don't stick around.. - if (g_Config.bEnableShaderDebugging) - Clear(); + // Clear out cache when debugging shaders to ensure stale ones don't stick around.. + if (g_Config.bEnableShaderDebugging) + Clear(); - SETSTAT(stats.numPixelShadersAlive, static_cast(s_ps_bytecode_cache.size())); - SETSTAT(stats.numPixelShadersCreated, static_cast(s_ps_bytecode_cache.size())); - SETSTAT(stats.numVertexShadersAlive, static_cast(s_vs_bytecode_cache.size())); - SETSTAT(stats.numVertexShadersCreated, static_cast(s_vs_bytecode_cache.size())); + SETSTAT(stats.numPixelShadersAlive, static_cast(s_ps_bytecode_cache.size())); + SETSTAT(stats.numPixelShadersCreated, static_cast(s_ps_bytecode_cache.size())); + SETSTAT(stats.numVertexShadersAlive, static_cast(s_vs_bytecode_cache.size())); + SETSTAT(stats.numVertexShadersCreated, static_cast(s_vs_bytecode_cache.size())); } void ShaderCache::Clear() { - for (auto& iter : s_shader_blob_list) - SAFE_RELEASE(iter); + for (auto& iter : s_shader_blob_list) + SAFE_RELEASE(iter); - s_shader_blob_list.clear(); + s_shader_blob_list.clear(); - s_gs_bytecode_cache.clear(); - s_ps_bytecode_cache.clear(); - s_vs_bytecode_cache.clear(); + s_gs_bytecode_cache.clear(); + s_ps_bytecode_cache.clear(); + s_vs_bytecode_cache.clear(); - s_last_geometry_shader_bytecode = {}; - s_last_geometry_shader_uid = {}; + s_last_geometry_shader_bytecode = {}; + s_last_geometry_shader_uid = {}; - s_last_pixel_shader_bytecode = {}; - s_last_pixel_shader_uid = {}; + s_last_pixel_shader_bytecode = {}; + s_last_pixel_shader_uid = {}; - s_last_vertex_shader_bytecode = {}; - s_last_vertex_shader_uid = {}; + s_last_vertex_shader_bytecode = {}; + s_last_vertex_shader_uid = {}; } void ShaderCache::Shutdown() { - Clear(); + Clear(); - s_gs_disk_cache.Sync(); - s_gs_disk_cache.Close(); - s_ps_disk_cache.Sync(); - s_ps_disk_cache.Close(); - s_vs_disk_cache.Sync(); - s_vs_disk_cache.Close(); + s_gs_disk_cache.Sync(); + s_gs_disk_cache.Close(); + s_ps_disk_cache.Sync(); + s_ps_disk_cache.Close(); + s_vs_disk_cache.Sync(); + s_vs_disk_cache.Close(); - if (g_Config.bEnableShaderDebugging) - { - s_gs_hlsl_cache.clear(); - s_ps_hlsl_cache.clear(); - s_vs_hlsl_cache.clear(); - } + if (g_Config.bEnableShaderDebugging) + { + s_gs_hlsl_cache.clear(); + s_ps_hlsl_cache.clear(); + s_vs_hlsl_cache.clear(); + } - s_geometry_uid_checker.Invalidate(); - s_pixel_uid_checker.Invalidate(); - s_vertex_uid_checker.Invalidate(); + s_geometry_uid_checker.Invalidate(); + s_pixel_uid_checker.Invalidate(); + s_vertex_uid_checker.Invalidate(); } void ShaderCache::LoadAndSetActiveShaders(DSTALPHA_MODE ps_dst_alpha_mode, u32 gs_primitive_type) { - SetCurrentPrimitiveTopology(gs_primitive_type); + SetCurrentPrimitiveTopology(gs_primitive_type); - GeometryShaderUid gs_uid = GetGeometryShaderUid(gs_primitive_type, API_D3D); - PixelShaderUid ps_uid = GetPixelShaderUid(ps_dst_alpha_mode, API_D3D); - VertexShaderUid vs_uid = GetVertexShaderUid(API_D3D); + GeometryShaderUid gs_uid = GetGeometryShaderUid(gs_primitive_type, API_D3D); + PixelShaderUid ps_uid = GetPixelShaderUid(ps_dst_alpha_mode, API_D3D); + VertexShaderUid vs_uid = GetVertexShaderUid(API_D3D); - bool gs_changed = gs_uid != s_last_geometry_shader_uid; - bool ps_changed = ps_uid != s_last_pixel_shader_uid; - bool vs_changed = vs_uid != s_last_vertex_shader_uid; + bool gs_changed = gs_uid != s_last_geometry_shader_uid; + bool ps_changed = ps_uid != s_last_pixel_shader_uid; + bool vs_changed = vs_uid != s_last_vertex_shader_uid; - if (!gs_changed && !ps_changed && !vs_changed) - { - return; - } + if (!gs_changed && !ps_changed && !vs_changed) + { + return; + } - if (gs_changed) - { - HandleGSUIDChange(gs_uid, gs_primitive_type); - } + if (gs_changed) + { + HandleGSUIDChange(gs_uid, gs_primitive_type); + } - if (ps_changed) - { - HandlePSUIDChange(ps_uid, ps_dst_alpha_mode); - } + if (ps_changed) + { + HandlePSUIDChange(ps_uid, ps_dst_alpha_mode); + } - if (vs_changed) - { - HandleVSUIDChange(vs_uid); - } + if (vs_changed) + { + HandleVSUIDChange(vs_uid); + } - // A Uid has changed, so the PSO will need to be reset at next ApplyState. - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); + // A Uid has changed, so the PSO will need to be reset at next ApplyState. + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); } void ShaderCache::SetCurrentPrimitiveTopology(u32 gs_primitive_type) { - switch (gs_primitive_type) - { - case PRIMITIVE_TRIANGLES: - s_current_primitive_topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - break; - case PRIMITIVE_LINES: - s_current_primitive_topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; - break; - case PRIMITIVE_POINTS: - s_current_primitive_topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; - break; - default: - CHECK(0, "Invalid primitive type."); - break; - } + switch (gs_primitive_type) + { + case PRIMITIVE_TRIANGLES: + s_current_primitive_topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + break; + case PRIMITIVE_LINES: + s_current_primitive_topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; + break; + case PRIMITIVE_POINTS: + s_current_primitive_topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; + break; + default: + CHECK(0, "Invalid primitive type."); + break; + } } void ShaderCache::HandleGSUIDChange(GeometryShaderUid gs_uid, u32 gs_primitive_type) { - s_last_geometry_shader_uid = gs_uid; + s_last_geometry_shader_uid = gs_uid; - if (g_ActiveConfig.bEnableShaderDebugging) - { - ShaderCode code = GenerateGeometryShaderCode(gs_primitive_type, API_D3D); - s_geometry_uid_checker.AddToIndexAndCheck(code, gs_uid, "Geometry", "g"); - } + if (g_ActiveConfig.bEnableShaderDebugging) + { + ShaderCode code = GenerateGeometryShaderCode(gs_primitive_type, API_D3D); + s_geometry_uid_checker.AddToIndexAndCheck(code, gs_uid, "Geometry", "g"); + } - if (gs_uid.GetUidData()->IsPassthrough()) - { - s_last_geometry_shader_bytecode = {}; - return; - } + if (gs_uid.GetUidData()->IsPassthrough()) + { + s_last_geometry_shader_bytecode = {}; + return; + } - auto gs_iterator = s_gs_bytecode_cache.find(gs_uid); - if (gs_iterator != s_gs_bytecode_cache.end()) - { - s_last_geometry_shader_bytecode = gs_iterator->second; - } - else - { - ShaderCode gs_code = GenerateGeometryShaderCode(gs_primitive_type, API_D3D); - ID3DBlob* gs_bytecode = nullptr; + auto gs_iterator = s_gs_bytecode_cache.find(gs_uid); + if (gs_iterator != s_gs_bytecode_cache.end()) + { + s_last_geometry_shader_bytecode = gs_iterator->second; + } + else + { + ShaderCode gs_code = GenerateGeometryShaderCode(gs_primitive_type, API_D3D); + ID3DBlob* gs_bytecode = nullptr; - if (!D3D::CompileGeometryShader(gs_code.GetBuffer(), &gs_bytecode)) - { - GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); - return; - } + if (!D3D::CompileGeometryShader(gs_code.GetBuffer(), &gs_bytecode)) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); + return; + } - s_last_geometry_shader_bytecode = InsertByteCode(gs_uid, &s_gs_bytecode_cache, gs_bytecode); - s_gs_disk_cache.Append(gs_uid, reinterpret_cast(gs_bytecode->GetBufferPointer()), static_cast(gs_bytecode->GetBufferSize())); + s_last_geometry_shader_bytecode = InsertByteCode(gs_uid, &s_gs_bytecode_cache, gs_bytecode); + s_gs_disk_cache.Append(gs_uid, reinterpret_cast(gs_bytecode->GetBufferPointer()), + static_cast(gs_bytecode->GetBufferSize())); - if (g_ActiveConfig.bEnableShaderDebugging) - { - s_gs_hlsl_cache[gs_uid] = gs_code.GetBuffer(); - } - } + if (g_ActiveConfig.bEnableShaderDebugging) + { + s_gs_hlsl_cache[gs_uid] = gs_code.GetBuffer(); + } + } } void ShaderCache::HandlePSUIDChange(PixelShaderUid ps_uid, DSTALPHA_MODE ps_dst_alpha_mode) { - s_last_pixel_shader_uid = ps_uid; + s_last_pixel_shader_uid = ps_uid; - if (g_ActiveConfig.bEnableShaderDebugging) - { - ShaderCode code = GeneratePixelShaderCode(ps_dst_alpha_mode, API_D3D); - s_pixel_uid_checker.AddToIndexAndCheck(code, ps_uid, "Pixel", "p"); - } + if (g_ActiveConfig.bEnableShaderDebugging) + { + ShaderCode code = GeneratePixelShaderCode(ps_dst_alpha_mode, API_D3D); + s_pixel_uid_checker.AddToIndexAndCheck(code, ps_uid, "Pixel", "p"); + } - auto ps_iterator = s_ps_bytecode_cache.find(ps_uid); - if (ps_iterator != s_ps_bytecode_cache.end()) - { - s_last_pixel_shader_bytecode = ps_iterator->second; - GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - } - else - { - ShaderCode ps_code = GeneratePixelShaderCode(ps_dst_alpha_mode, API_D3D); - ID3DBlob* ps_bytecode = nullptr; + auto ps_iterator = s_ps_bytecode_cache.find(ps_uid); + if (ps_iterator != s_ps_bytecode_cache.end()) + { + s_last_pixel_shader_bytecode = ps_iterator->second; + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + } + else + { + ShaderCode ps_code = GeneratePixelShaderCode(ps_dst_alpha_mode, API_D3D); + ID3DBlob* ps_bytecode = nullptr; - if (!D3D::CompilePixelShader(ps_code.GetBuffer(), &ps_bytecode)) - { - GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); - return; - } + if (!D3D::CompilePixelShader(ps_code.GetBuffer(), &ps_bytecode)) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); + return; + } - s_last_pixel_shader_bytecode = InsertByteCode(ps_uid, &s_ps_bytecode_cache, ps_bytecode); - s_ps_disk_cache.Append(ps_uid, reinterpret_cast(ps_bytecode->GetBufferPointer()), static_cast(ps_bytecode->GetBufferSize())); + s_last_pixel_shader_bytecode = InsertByteCode(ps_uid, &s_ps_bytecode_cache, ps_bytecode); + s_ps_disk_cache.Append(ps_uid, reinterpret_cast(ps_bytecode->GetBufferPointer()), + static_cast(ps_bytecode->GetBufferSize())); - SETSTAT(stats.numPixelShadersAlive, static_cast(s_ps_bytecode_cache.size())); - INCSTAT(stats.numPixelShadersCreated); + SETSTAT(stats.numPixelShadersAlive, static_cast(s_ps_bytecode_cache.size())); + INCSTAT(stats.numPixelShadersCreated); - if (g_ActiveConfig.bEnableShaderDebugging) - { - s_ps_hlsl_cache[ps_uid] = ps_code.GetBuffer(); - } - } + if (g_ActiveConfig.bEnableShaderDebugging) + { + s_ps_hlsl_cache[ps_uid] = ps_code.GetBuffer(); + } + } } void ShaderCache::HandleVSUIDChange(VertexShaderUid vs_uid) { - s_last_vertex_shader_uid = vs_uid; + s_last_vertex_shader_uid = vs_uid; - if (g_ActiveConfig.bEnableShaderDebugging) - { - ShaderCode code = GenerateVertexShaderCode(API_D3D); - s_vertex_uid_checker.AddToIndexAndCheck(code, vs_uid, "Vertex", "v"); - } + if (g_ActiveConfig.bEnableShaderDebugging) + { + ShaderCode code = GenerateVertexShaderCode(API_D3D); + s_vertex_uid_checker.AddToIndexAndCheck(code, vs_uid, "Vertex", "v"); + } - auto vs_iterator = s_vs_bytecode_cache.find(vs_uid); - if (vs_iterator != s_vs_bytecode_cache.end()) - { - s_last_vertex_shader_bytecode = vs_iterator->second; - GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); - } - else - { - ShaderCode vs_code = GenerateVertexShaderCode(API_D3D); - ID3DBlob* vs_bytecode = nullptr; + auto vs_iterator = s_vs_bytecode_cache.find(vs_uid); + if (vs_iterator != s_vs_bytecode_cache.end()) + { + s_last_vertex_shader_bytecode = vs_iterator->second; + GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); + } + else + { + ShaderCode vs_code = GenerateVertexShaderCode(API_D3D); + ID3DBlob* vs_bytecode = nullptr; - if (!D3D::CompileVertexShader(vs_code.GetBuffer(), &vs_bytecode)) - { - GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); - return; - } + if (!D3D::CompileVertexShader(vs_code.GetBuffer(), &vs_bytecode)) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); + return; + } - s_last_vertex_shader_bytecode = InsertByteCode(vs_uid, &s_vs_bytecode_cache, vs_bytecode); - s_vs_disk_cache.Append(vs_uid, reinterpret_cast(vs_bytecode->GetBufferPointer()), static_cast(vs_bytecode->GetBufferSize())); + s_last_vertex_shader_bytecode = InsertByteCode(vs_uid, &s_vs_bytecode_cache, vs_bytecode); + s_vs_disk_cache.Append(vs_uid, reinterpret_cast(vs_bytecode->GetBufferPointer()), + static_cast(vs_bytecode->GetBufferSize())); - SETSTAT(stats.numVertexShadersAlive, static_cast(s_vs_bytecode_cache.size())); - INCSTAT(stats.numVertexShadersCreated); + SETSTAT(stats.numVertexShadersAlive, static_cast(s_vs_bytecode_cache.size())); + INCSTAT(stats.numVertexShadersCreated); - if (g_ActiveConfig.bEnableShaderDebugging) - { - s_vs_hlsl_cache[vs_uid] = vs_code.GetBuffer(); - } - } + if (g_ActiveConfig.bEnableShaderDebugging) + { + s_vs_hlsl_cache[vs_uid] = vs_code.GetBuffer(); + } + } } -template -D3D12_SHADER_BYTECODE ShaderCache::InsertByteCode(const UidType& uid, ShaderCacheType* shader_cache, ID3DBlob* bytecode_blob) +template +D3D12_SHADER_BYTECODE ShaderCache::InsertByteCode(const UidType& uid, ShaderCacheType* shader_cache, + ID3DBlob* bytecode_blob) { - // Note: Don't release the incoming bytecode, we need it to stick around, since in D3D12 - // the raw bytecode itself is bound. It is released at Shutdown() time. + // Note: Don't release the incoming bytecode, we need it to stick around, since in D3D12 + // the raw bytecode itself is bound. It is released at Shutdown() time. - s_shader_blob_list.push_back(bytecode_blob); + s_shader_blob_list.push_back(bytecode_blob); - D3D12_SHADER_BYTECODE shader_bytecode; - shader_bytecode.pShaderBytecode = bytecode_blob->GetBufferPointer(); - shader_bytecode.BytecodeLength = bytecode_blob->GetBufferSize(); + D3D12_SHADER_BYTECODE shader_bytecode; + shader_bytecode.pShaderBytecode = bytecode_blob->GetBufferPointer(); + shader_bytecode.BytecodeLength = bytecode_blob->GetBufferSize(); - (*shader_cache)[uid] = shader_bytecode; + (*shader_cache)[uid] = shader_bytecode; - return shader_bytecode; + return shader_bytecode; } -D3D12_PRIMITIVE_TOPOLOGY_TYPE ShaderCache::GetCurrentPrimitiveTopology() { return s_current_primitive_topology; } +D3D12_PRIMITIVE_TOPOLOGY_TYPE ShaderCache::GetCurrentPrimitiveTopology() +{ + return s_current_primitive_topology; +} -D3D12_SHADER_BYTECODE ShaderCache::GetActiveGeometryShaderBytecode() { return s_last_geometry_shader_bytecode; } -D3D12_SHADER_BYTECODE ShaderCache::GetActivePixelShaderBytecode() { return s_last_pixel_shader_bytecode; } -D3D12_SHADER_BYTECODE ShaderCache::GetActiveVertexShaderBytecode() { return s_last_vertex_shader_bytecode; } +D3D12_SHADER_BYTECODE ShaderCache::GetActiveGeometryShaderBytecode() +{ + return s_last_geometry_shader_bytecode; +} +D3D12_SHADER_BYTECODE ShaderCache::GetActivePixelShaderBytecode() +{ + return s_last_pixel_shader_bytecode; +} +D3D12_SHADER_BYTECODE ShaderCache::GetActiveVertexShaderBytecode() +{ + return s_last_vertex_shader_bytecode; +} -const GeometryShaderUid* ShaderCache::GetActiveGeometryShaderUid() { return &s_last_geometry_shader_uid; } -const PixelShaderUid* ShaderCache::GetActivePixelShaderUid() { return &s_last_pixel_shader_uid; } -const VertexShaderUid* ShaderCache::GetActiveVertexShaderUid() { return &s_last_vertex_shader_uid; } +const GeometryShaderUid* ShaderCache::GetActiveGeometryShaderUid() +{ + return &s_last_geometry_shader_uid; +} +const PixelShaderUid* ShaderCache::GetActivePixelShaderUid() +{ + return &s_last_pixel_shader_uid; +} +const VertexShaderUid* ShaderCache::GetActiveVertexShaderUid() +{ + return &s_last_vertex_shader_uid; +} D3D12_SHADER_BYTECODE ShaderCache::GetGeometryShaderFromUid(const GeometryShaderUid* uid) { - auto bytecode = s_gs_bytecode_cache.find(*uid); - if (bytecode != s_gs_bytecode_cache.end()) - return bytecode->second; + auto bytecode = s_gs_bytecode_cache.find(*uid); + if (bytecode != s_gs_bytecode_cache.end()) + return bytecode->second; - return D3D12_SHADER_BYTECODE(); + return D3D12_SHADER_BYTECODE(); } D3D12_SHADER_BYTECODE ShaderCache::GetPixelShaderFromUid(const PixelShaderUid* uid) { - auto bytecode = s_ps_bytecode_cache.find(*uid); - if (bytecode != s_ps_bytecode_cache.end()) - return bytecode->second; + auto bytecode = s_ps_bytecode_cache.find(*uid); + if (bytecode != s_ps_bytecode_cache.end()) + return bytecode->second; - return D3D12_SHADER_BYTECODE(); + return D3D12_SHADER_BYTECODE(); } D3D12_SHADER_BYTECODE ShaderCache::GetVertexShaderFromUid(const VertexShaderUid* uid) { - auto bytecode = s_vs_bytecode_cache.find(*uid); - if (bytecode != s_vs_bytecode_cache.end()) - return bytecode->second; + auto bytecode = s_vs_bytecode_cache.find(*uid); + if (bytecode != s_vs_bytecode_cache.end()) + return bytecode->second; - return D3D12_SHADER_BYTECODE(); + return D3D12_SHADER_BYTECODE(); } - } \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D12/ShaderCache.h b/Source/Core/VideoBackends/D3D12/ShaderCache.h index e9b6a081e7..b6308b922b 100644 --- a/Source/Core/VideoBackends/D3D12/ShaderCache.h +++ b/Source/Core/VideoBackends/D3D12/ShaderCache.h @@ -10,41 +10,40 @@ namespace DX12 { - class D3DBlob; class ShaderCache final { public: - static void Init(); - static void Clear(); - static void Shutdown(); + static void Init(); + static void Clear(); + static void Shutdown(); - static void LoadAndSetActiveShaders(DSTALPHA_MODE ps_dst_alpha_mode, u32 gs_primitive_type); + static void LoadAndSetActiveShaders(DSTALPHA_MODE ps_dst_alpha_mode, u32 gs_primitive_type); - template - static D3D12_SHADER_BYTECODE InsertByteCode(const UidType& uid, ShaderCacheType* shader_cache, ID3DBlob* bytecode_blob); + template + static D3D12_SHADER_BYTECODE InsertByteCode(const UidType& uid, ShaderCacheType* shader_cache, + ID3DBlob* bytecode_blob); - static D3D12_SHADER_BYTECODE GetActiveGeometryShaderBytecode(); - static D3D12_SHADER_BYTECODE GetActivePixelShaderBytecode(); - static D3D12_SHADER_BYTECODE GetActiveVertexShaderBytecode(); + static D3D12_SHADER_BYTECODE GetActiveGeometryShaderBytecode(); + static D3D12_SHADER_BYTECODE GetActivePixelShaderBytecode(); + static D3D12_SHADER_BYTECODE GetActiveVertexShaderBytecode(); - static const GeometryShaderUid* GetActiveGeometryShaderUid(); - static const PixelShaderUid* GetActivePixelShaderUid(); - static const VertexShaderUid* GetActiveVertexShaderUid(); + static const GeometryShaderUid* GetActiveGeometryShaderUid(); + static const PixelShaderUid* GetActivePixelShaderUid(); + static const VertexShaderUid* GetActiveVertexShaderUid(); - static D3D12_SHADER_BYTECODE GetGeometryShaderFromUid(const GeometryShaderUid* uid); - static D3D12_SHADER_BYTECODE GetPixelShaderFromUid(const PixelShaderUid* uid); - static D3D12_SHADER_BYTECODE GetVertexShaderFromUid(const VertexShaderUid* uid); + static D3D12_SHADER_BYTECODE GetGeometryShaderFromUid(const GeometryShaderUid* uid); + static D3D12_SHADER_BYTECODE GetPixelShaderFromUid(const PixelShaderUid* uid); + static D3D12_SHADER_BYTECODE GetVertexShaderFromUid(const VertexShaderUid* uid); - static D3D12_PRIMITIVE_TOPOLOGY_TYPE GetCurrentPrimitiveTopology(); + static D3D12_PRIMITIVE_TOPOLOGY_TYPE GetCurrentPrimitiveTopology(); private: - static void SetCurrentPrimitiveTopology(u32 gs_primitive_type); + static void SetCurrentPrimitiveTopology(u32 gs_primitive_type); - static void HandleGSUIDChange(GeometryShaderUid gs_uid, u32 gs_primitive_type); - static void HandlePSUIDChange(PixelShaderUid ps_uid, DSTALPHA_MODE ps_dst_alpha_mode); - static void HandleVSUIDChange(VertexShaderUid vs_uid); + static void HandleGSUIDChange(GeometryShaderUid gs_uid, u32 gs_primitive_type); + static void HandlePSUIDChange(PixelShaderUid ps_uid, DSTALPHA_MODE ps_dst_alpha_mode); + static void HandleVSUIDChange(VertexShaderUid vs_uid); }; - } diff --git a/Source/Core/VideoBackends/D3D12/ShaderConstantsManager.cpp b/Source/Core/VideoBackends/D3D12/ShaderConstantsManager.cpp index b531c0a11b..e6a04a52a8 100644 --- a/Source/Core/VideoBackends/D3D12/ShaderConstantsManager.cpp +++ b/Source/Core/VideoBackends/D3D12/ShaderConstantsManager.cpp @@ -17,152 +17,149 @@ namespace DX12 { - enum SHADER_STAGE { - SHADER_STAGE_GEOMETRY_SHADER = 0, - SHADER_STAGE_PIXEL_SHADER = 1, - SHADER_STAGE_VERTEX_SHADER = 2, - SHADER_STAGE_COUNT = 3 + SHADER_STAGE_GEOMETRY_SHADER = 0, + SHADER_STAGE_PIXEL_SHADER = 1, + SHADER_STAGE_VERTEX_SHADER = 2, + SHADER_STAGE_COUNT = 3 }; -static std::array, SHADER_STAGE_COUNT> s_shader_constant_stream_buffers; +static std::array, SHADER_STAGE_COUNT> + s_shader_constant_stream_buffers; static const unsigned int s_shader_constant_buffer_padded_sizes[SHADER_STAGE_COUNT] = { - (sizeof(GeometryShaderConstants) + 0xff) & ~0xff, - (sizeof(PixelShaderConstants) + 0xff) & ~0xff, - (sizeof(VertexShaderConstants) + 0xff) & ~0xff -}; + (sizeof(GeometryShaderConstants) + 0xff) & ~0xff, (sizeof(PixelShaderConstants) + 0xff) & ~0xff, + (sizeof(VertexShaderConstants) + 0xff) & ~0xff}; void ShaderConstantsManager::Init() { - // Allow a large maximum size, as we want to minimize stalls here - std::generate(std::begin(s_shader_constant_stream_buffers), std::end(s_shader_constant_stream_buffers), []() { - return std::make_unique(2 * 1024 * 1024, 64 * 1024 * 1024, nullptr); - }); + // Allow a large maximum size, as we want to minimize stalls here + std::generate(std::begin(s_shader_constant_stream_buffers), + std::end(s_shader_constant_stream_buffers), []() { + return std::make_unique(2 * 1024 * 1024, 64 * 1024 * 1024, + nullptr); + }); } void ShaderConstantsManager::Shutdown() { - for (auto& buffer : s_shader_constant_stream_buffers) - buffer.reset(); + for (auto& buffer : s_shader_constant_stream_buffers) + buffer.reset(); } bool ShaderConstantsManager::LoadAndSetGeometryShaderConstants() { - bool command_list_executed = false; + bool command_list_executed = false; - if (GeometryShaderManager::dirty) - { - command_list_executed = s_shader_constant_stream_buffers[SHADER_STAGE_GEOMETRY_SHADER]->AllocateSpaceInBuffer( - s_shader_constant_buffer_padded_sizes[SHADER_STAGE_GEOMETRY_SHADER], - 0 // The padded sizes are already aligned to 256 bytes, so don't need to worry about manually aligning offset. - ); + if (GeometryShaderManager::dirty) + { + command_list_executed = + s_shader_constant_stream_buffers[SHADER_STAGE_GEOMETRY_SHADER]->AllocateSpaceInBuffer( + s_shader_constant_buffer_padded_sizes[SHADER_STAGE_GEOMETRY_SHADER], + 0 // The padded sizes are already aligned to 256 bytes, so don't need to worry about + // manually aligning offset. + ); - memcpy( - s_shader_constant_stream_buffers[SHADER_STAGE_GEOMETRY_SHADER]->GetCPUAddressOfCurrentAllocation(), - &GeometryShaderManager::constants, - sizeof(GeometryShaderConstants)); + memcpy(s_shader_constant_stream_buffers[SHADER_STAGE_GEOMETRY_SHADER] + ->GetCPUAddressOfCurrentAllocation(), + &GeometryShaderManager::constants, sizeof(GeometryShaderConstants)); - GeometryShaderManager::dirty = false; + GeometryShaderManager::dirty = false; - ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(GeometryShaderConstants)); + ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(GeometryShaderConstants)); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_GS_CBV, true); - } + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_GS_CBV, true); + } - if (D3D::command_list_mgr->GetCommandListDirtyState(COMMAND_LIST_STATE_GS_CBV)) - { - D3D::current_command_list->SetGraphicsRootConstantBufferView( - DESCRIPTOR_TABLE_GS_CBV, - s_shader_constant_stream_buffers[SHADER_STAGE_GEOMETRY_SHADER]->GetGPUAddressOfCurrentAllocation() - ); + if (D3D::command_list_mgr->GetCommandListDirtyState(COMMAND_LIST_STATE_GS_CBV)) + { + D3D::current_command_list->SetGraphicsRootConstantBufferView( + DESCRIPTOR_TABLE_GS_CBV, s_shader_constant_stream_buffers[SHADER_STAGE_GEOMETRY_SHADER] + ->GetGPUAddressOfCurrentAllocation()); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_GS_CBV, false); - } + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_GS_CBV, false); + } - return command_list_executed; + return command_list_executed; } bool ShaderConstantsManager::LoadAndSetPixelShaderConstants() { - bool command_list_executed = false; + bool command_list_executed = false; - if (PixelShaderManager::dirty) - { - command_list_executed = s_shader_constant_stream_buffers[SHADER_STAGE_PIXEL_SHADER]->AllocateSpaceInBuffer( - s_shader_constant_buffer_padded_sizes[SHADER_STAGE_PIXEL_SHADER], - 0 // The padded sizes are already aligned to 256 bytes, so don't need to worry about manually aligning offset. - ); + if (PixelShaderManager::dirty) + { + command_list_executed = + s_shader_constant_stream_buffers[SHADER_STAGE_PIXEL_SHADER]->AllocateSpaceInBuffer( + s_shader_constant_buffer_padded_sizes[SHADER_STAGE_PIXEL_SHADER], + 0 // The padded sizes are already aligned to 256 bytes, so don't need to worry about + // manually aligning offset. + ); - memcpy( - s_shader_constant_stream_buffers[SHADER_STAGE_PIXEL_SHADER]->GetCPUAddressOfCurrentAllocation(), - &PixelShaderManager::constants, - sizeof(PixelShaderConstants)); + memcpy(s_shader_constant_stream_buffers[SHADER_STAGE_PIXEL_SHADER] + ->GetCPUAddressOfCurrentAllocation(), + &PixelShaderManager::constants, sizeof(PixelShaderConstants)); - PixelShaderManager::dirty = false; + PixelShaderManager::dirty = false; - ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(PixelShaderConstants)); + ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(PixelShaderConstants)); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, true); - } + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, true); + } - if (D3D::command_list_mgr->GetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV)) - { - D3D::current_command_list->SetGraphicsRootConstantBufferView( - DESCRIPTOR_TABLE_PS_CBVONE, - s_shader_constant_stream_buffers[SHADER_STAGE_PIXEL_SHADER]->GetGPUAddressOfCurrentAllocation() - ); + if (D3D::command_list_mgr->GetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV)) + { + D3D::current_command_list->SetGraphicsRootConstantBufferView( + DESCRIPTOR_TABLE_PS_CBVONE, s_shader_constant_stream_buffers[SHADER_STAGE_PIXEL_SHADER] + ->GetGPUAddressOfCurrentAllocation()); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, false); - } + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, false); + } - return command_list_executed; + return command_list_executed; } bool ShaderConstantsManager::LoadAndSetVertexShaderConstants() { - bool command_list_executed = false; + bool command_list_executed = false; - if (VertexShaderManager::dirty) - { - command_list_executed = s_shader_constant_stream_buffers[SHADER_STAGE_VERTEX_SHADER]->AllocateSpaceInBuffer( - s_shader_constant_buffer_padded_sizes[SHADER_STAGE_VERTEX_SHADER], - 0 // The padded sizes are already aligned to 256 bytes, so don't need to worry about manually aligning offset. - ); + if (VertexShaderManager::dirty) + { + command_list_executed = + s_shader_constant_stream_buffers[SHADER_STAGE_VERTEX_SHADER]->AllocateSpaceInBuffer( + s_shader_constant_buffer_padded_sizes[SHADER_STAGE_VERTEX_SHADER], + 0 // The padded sizes are already aligned to 256 bytes, so don't need to worry about + // manually aligning offset. + ); - memcpy( - s_shader_constant_stream_buffers[SHADER_STAGE_VERTEX_SHADER]->GetCPUAddressOfCurrentAllocation(), - &VertexShaderManager::constants, - sizeof(VertexShaderConstants)); + memcpy(s_shader_constant_stream_buffers[SHADER_STAGE_VERTEX_SHADER] + ->GetCPUAddressOfCurrentAllocation(), + &VertexShaderManager::constants, sizeof(VertexShaderConstants)); - VertexShaderManager::dirty = false; + VertexShaderManager::dirty = false; - ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(VertexShaderConstants)); + ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(VertexShaderConstants)); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_VS_CBV, true); - } + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_VS_CBV, true); + } - if (D3D::command_list_mgr->GetCommandListDirtyState(COMMAND_LIST_STATE_VS_CBV)) - { - const D3D12_GPU_VIRTUAL_ADDRESS calculated_gpu_va = - s_shader_constant_stream_buffers[SHADER_STAGE_VERTEX_SHADER]->GetGPUAddressOfCurrentAllocation(); + if (D3D::command_list_mgr->GetCommandListDirtyState(COMMAND_LIST_STATE_VS_CBV)) + { + const D3D12_GPU_VIRTUAL_ADDRESS calculated_gpu_va = + s_shader_constant_stream_buffers[SHADER_STAGE_VERTEX_SHADER] + ->GetGPUAddressOfCurrentAllocation(); - D3D::current_command_list->SetGraphicsRootConstantBufferView( - DESCRIPTOR_TABLE_VS_CBV, - calculated_gpu_va - ); + D3D::current_command_list->SetGraphicsRootConstantBufferView(DESCRIPTOR_TABLE_VS_CBV, + calculated_gpu_va); - if (g_ActiveConfig.bEnablePixelLighting) - D3D::current_command_list->SetGraphicsRootConstantBufferView( - DESCRIPTOR_TABLE_PS_CBVTWO, - calculated_gpu_va - ); + if (g_ActiveConfig.bEnablePixelLighting) + D3D::current_command_list->SetGraphicsRootConstantBufferView(DESCRIPTOR_TABLE_PS_CBVTWO, + calculated_gpu_va); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_VS_CBV, false); - } + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_VS_CBV, false); + } - return command_list_executed; + return command_list_executed; } - } \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D12/ShaderConstantsManager.h b/Source/Core/VideoBackends/D3D12/ShaderConstantsManager.h index 1d235a030d..786a1ff028 100644 --- a/Source/Core/VideoBackends/D3D12/ShaderConstantsManager.h +++ b/Source/Core/VideoBackends/D3D12/ShaderConstantsManager.h @@ -8,16 +8,14 @@ namespace DX12 { - class ShaderConstantsManager final { public: - static void Init(); - static void Shutdown(); + static void Init(); + static void Shutdown(); - static bool LoadAndSetGeometryShaderConstants(); - static bool LoadAndSetPixelShaderConstants(); - static bool LoadAndSetVertexShaderConstants(); + static bool LoadAndSetGeometryShaderConstants(); + static bool LoadAndSetPixelShaderConstants(); + static bool LoadAndSetVertexShaderConstants(); }; - } \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D12/StaticShaderCache.cpp b/Source/Core/VideoBackends/D3D12/StaticShaderCache.cpp index 38de296e87..652b1515ba 100644 --- a/Source/Core/VideoBackends/D3D12/StaticShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D12/StaticShaderCache.cpp @@ -2,15 +2,14 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoBackends/D3D12/StaticShaderCache.h" #include "Common/StringUtil.h" #include "VideoBackends/D3D12/D3DBase.h" #include "VideoBackends/D3D12/D3DShader.h" -#include "VideoBackends/D3D12/StaticShaderCache.h" #include "VideoCommon/VideoConfig.h" namespace DX12 { - // Pixel Shader blobs static ID3DBlob* s_color_matrix_program_blob[2] = {}; static ID3DBlob* s_color_copy_program_blob[2] = {}; @@ -28,52 +27,45 @@ static ID3DBlob* s_simple_vertex_shader_blob = {}; static ID3DBlob* s_simple_clear_vertex_shader_blob = {}; static const D3D12_INPUT_ELEMENT_DESC s_simple_vertex_shader_input_elements[] = { - { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, + 0}, + {"TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, + 0}, }; static const D3D12_INPUT_LAYOUT_DESC s_simple_vertex_shader_input_layout = { - s_simple_vertex_shader_input_elements, - ARRAYSIZE(s_simple_vertex_shader_input_elements) + s_simple_vertex_shader_input_elements, ARRAYSIZE(s_simple_vertex_shader_input_elements)}; + +static const D3D12_INPUT_ELEMENT_DESC s_clear_vertex_shader_input_elements[] = { + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, + 0}, + {"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}, }; -static const D3D12_INPUT_ELEMENT_DESC s_clear_vertex_shader_input_elements[] = -{ - { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, - { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, -}; - -static const D3D12_INPUT_LAYOUT_DESC s_clear_vertex_shader_input_layout = -{ - s_clear_vertex_shader_input_elements, - ARRAYSIZE(s_clear_vertex_shader_input_elements) -}; +static const D3D12_INPUT_LAYOUT_DESC s_clear_vertex_shader_input_layout = { + s_clear_vertex_shader_input_elements, ARRAYSIZE(s_clear_vertex_shader_input_elements)}; // Geometry Shader blobs static ID3DBlob* s_clear_geometry_shader_blob = nullptr; static ID3DBlob* s_copy_geometry_shader_blob = nullptr; // Pixel Shader HLSL -static constexpr const char s_clear_program_hlsl[] = { - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - "in float4 pos : SV_Position,\n" - "in float4 incol0 : COLOR0){\n" - "ocol0 = incol0;\n" - "}\n" -}; +static constexpr const char s_clear_program_hlsl[] = {"void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + "in float4 incol0 : COLOR0){\n" + "ocol0 = incol0;\n" + "}\n"}; // EXISTINGD3D11TODO: Find some way to avoid having separate shaders for non-MSAA and MSAA... -static constexpr const char s_color_copy_program_hlsl[] = { - "sampler samp0 : register(s0);\n" - "Texture2DArray Tex0 : register(t0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - "in float4 pos : SV_Position,\n" - "in float3 uv0 : TEXCOORD0){\n" - "ocol0 = Tex0.Sample(samp0,uv0);\n" - "}\n" -}; +static constexpr const char s_color_copy_program_hlsl[] = {"sampler samp0 : register(s0);\n" + "Texture2DArray Tex0 : register(t0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + "in float3 uv0 : TEXCOORD0){\n" + "ocol0 = Tex0.Sample(samp0,uv0);\n" + "}\n"}; // Anaglyph Red-Cyan shader based on Dubois algorithm // Constants taken from the paper: @@ -81,337 +73,330 @@ static constexpr const char s_color_copy_program_hlsl[] = { // the Least-Squares Projection Method" // Eric Dubois, March 2009 static constexpr const char s_anaglyph_program_hlsl[] = { - "sampler samp0 : register(s0);\n" - "Texture2DArray Tex0 : register(t0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - "in float4 pos : SV_Position,\n" - "in float3 uv0 : TEXCOORD0){\n" - "float4 c0 = Tex0.Sample(samp0, float3(uv0.xy, 0.0));\n" - "float4 c1 = Tex0.Sample(samp0, float3(uv0.xy, 1.0));\n" - "float3x3 l = float3x3( 0.437, 0.449, 0.164,\n" - " -0.062,-0.062,-0.024,\n" - " -0.048,-0.050,-0.017);\n" - "float3x3 r = float3x3(-0.011,-0.032,-0.007,\n" - " 0.377, 0.761, 0.009,\n" - " -0.026,-0.093, 1.234);\n" - "ocol0 = float4(mul(l, c0.rgb) + mul(r, c1.rgb), c0.a);\n" - "}\n" -}; + "sampler samp0 : register(s0);\n" + "Texture2DArray Tex0 : register(t0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + "in float3 uv0 : TEXCOORD0){\n" + "float4 c0 = Tex0.Sample(samp0, float3(uv0.xy, 0.0));\n" + "float4 c1 = Tex0.Sample(samp0, float3(uv0.xy, 1.0));\n" + "float3x3 l = float3x3( 0.437, 0.449, 0.164,\n" + " -0.062,-0.062,-0.024,\n" + " -0.048,-0.050,-0.017);\n" + "float3x3 r = float3x3(-0.011,-0.032,-0.007,\n" + " 0.377, 0.761, 0.009,\n" + " -0.026,-0.093, 1.234);\n" + "ocol0 = float4(mul(l, c0.rgb) + mul(r, c1.rgb), c0.a);\n" + "}\n"}; // TODO: Improve sampling algorithm! static constexpr const char s_color_copy_program_msaa_hlsl[] = { - "#define SAMPLES %d\n" - "sampler samp0 : register(s0);\n" - "Texture2DMSArray Tex0 : register(t0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - "in float4 pos : SV_Position,\n" - "in float3 uv0 : TEXCOORD0){\n" - "int width, height, slices, samples;\n" - "Tex0.GetDimensions(width, height, slices, samples);\n" - "ocol0 = 0;\n" - "for(int i = 0; i < SAMPLES; ++i)\n" - " ocol0 += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" - "ocol0 /= SAMPLES;\n" - "}\n" -}; + "#define SAMPLES %d\n" + "sampler samp0 : register(s0);\n" + "Texture2DMSArray Tex0 : register(t0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + "in float3 uv0 : TEXCOORD0){\n" + "int width, height, slices, samples;\n" + "Tex0.GetDimensions(width, height, slices, samples);\n" + "ocol0 = 0;\n" + "for(int i = 0; i < SAMPLES; ++i)\n" + " ocol0 += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" + "ocol0 /= SAMPLES;\n" + "}\n"}; static constexpr const char s_depth_resolve_to_color_program_hlsl[] = { - "#define SAMPLES %d\n" - "Texture2DMSArray Tex0 : register(t0);\n" - "void main(\n" - " out float ocol0 : SV_Target,\n" - " in float4 pos : SV_Position,\n" - " in float3 uv0 : TEXCOORD0)\n" - "{\n" - " int width, height, slices, samples;\n" - " Tex0.GetDimensions(width, height, slices, samples);\n" - " ocol0 = Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), 0).x;\n" - " for(int i = 1; i < SAMPLES; ++i)\n" - " ocol0 = min(ocol0, Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i).x);\n" - "}\n" -}; + "#define SAMPLES %d\n" + "Texture2DMSArray Tex0 : register(t0);\n" + "void main(\n" + " out float ocol0 : SV_Target,\n" + " in float4 pos : SV_Position,\n" + " in float3 uv0 : TEXCOORD0)\n" + "{\n" + " int width, height, slices, samples;\n" + " Tex0.GetDimensions(width, height, slices, samples);\n" + " ocol0 = Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), 0).x;\n" + " for(int i = 1; i < SAMPLES; ++i)\n" + " ocol0 = min(ocol0, Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i).x);\n" + "}\n"}; static constexpr const char s_color_matrix_program_hlsl[] = { - "sampler samp0 : register(s0);\n" - "Texture2DArray Tex0 : register(t0);\n" - "uniform float4 cColMatrix[7] : register(c0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - "in float4 pos : SV_Position,\n" - "in float3 uv0 : TEXCOORD0){\n" - "float4 texcol = Tex0.Sample(samp0,uv0);\n" - "texcol = round(texcol * cColMatrix[5])*cColMatrix[6];\n" - "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n" -}; + "sampler samp0 : register(s0);\n" + "Texture2DArray Tex0 : register(t0);\n" + "uniform float4 cColMatrix[7] : register(c0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + "in float3 uv0 : TEXCOORD0){\n" + "float4 texcol = Tex0.Sample(samp0,uv0);\n" + "texcol = round(texcol * cColMatrix[5])*cColMatrix[6];\n" + "ocol0 = " + "float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(" + "texcol,cColMatrix[3])) + cColMatrix[4];\n" + "}\n"}; static constexpr const char s_color_matrix_program_msaa_hlsl[] = { - "#define SAMPLES %d\n" - "sampler samp0 : register(s0);\n" - "Texture2DMSArray Tex0 : register(t0);\n" - "uniform float4 cColMatrix[7] : register(c0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - "in float4 pos : SV_Position,\n" - "in float3 uv0 : TEXCOORD0){\n" - "int width, height, slices, samples;\n" - "Tex0.GetDimensions(width, height, slices, samples);\n" - "float4 texcol = 0;\n" - "for(int i = 0; i < SAMPLES; ++i)\n" - " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" - "texcol /= SAMPLES;\n" - "texcol = round(texcol * cColMatrix[5])*cColMatrix[6];\n" - "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n" -}; + "#define SAMPLES %d\n" + "sampler samp0 : register(s0);\n" + "Texture2DMSArray Tex0 : register(t0);\n" + "uniform float4 cColMatrix[7] : register(c0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + "in float3 uv0 : TEXCOORD0){\n" + "int width, height, slices, samples;\n" + "Tex0.GetDimensions(width, height, slices, samples);\n" + "float4 texcol = 0;\n" + "for(int i = 0; i < SAMPLES; ++i)\n" + " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" + "texcol /= SAMPLES;\n" + "texcol = round(texcol * cColMatrix[5])*cColMatrix[6];\n" + "ocol0 = " + "float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(" + "texcol,cColMatrix[3])) + cColMatrix[4];\n" + "}\n"}; static constexpr const char s_depth_matrix_program_hlsl[] = { - "sampler samp0 : register(s0);\n" - "Texture2DArray Tex0 : register(t0);\n" - "uniform float4 cColMatrix[7] : register(c0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - " in float4 pos : SV_Position,\n" - " in float3 uv0 : TEXCOORD0){\n" - " float4 texcol = Tex0.Sample(samp0,uv0);\n" - " int depth = int((1.0 - texcol.x) * 16777216.0);\n" + "sampler samp0 : register(s0);\n" + "Texture2DArray Tex0 : register(t0);\n" + "uniform float4 cColMatrix[7] : register(c0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + " in float4 pos : SV_Position,\n" + " in float3 uv0 : TEXCOORD0){\n" + " float4 texcol = Tex0.Sample(samp0,uv0);\n" + " int depth = int((1.0 - texcol.x) * 16777216.0);\n" - // Convert to Z24 format - " int4 workspace;\n" - " workspace.r = (depth >> 16) & 255;\n" - " workspace.g = (depth >> 8) & 255;\n" - " workspace.b = depth & 255;\n" + // Convert to Z24 format + " int4 workspace;\n" + " workspace.r = (depth >> 16) & 255;\n" + " workspace.g = (depth >> 8) & 255;\n" + " workspace.b = depth & 255;\n" - // Convert to Z4 format - " workspace.a = (depth >> 16) & 0xF0;\n" + // Convert to Z4 format + " workspace.a = (depth >> 16) & 0xF0;\n" - // Normalize components to [0.0..1.0] - " texcol = float4(workspace) / 255.0;\n" + // Normalize components to [0.0..1.0] + " texcol = float4(workspace) / 255.0;\n" - // Apply color matrix - " ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n" -}; + // Apply color matrix + " ocol0 = " + "float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(" + "texcol,cColMatrix[3])) + cColMatrix[4];\n" + "}\n"}; static constexpr const char s_depth_matrix_program_msaa_hlsl[] = { - "#define SAMPLES %d\n" - "sampler samp0 : register(s0);\n" - "Texture2DMSArray Tex0 : register(t0);\n" - "uniform float4 cColMatrix[7] : register(c0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - " in float4 pos : SV_Position,\n" - " in float3 uv0 : TEXCOORD0){\n" - " int width, height, slices, samples;\n" - " Tex0.GetDimensions(width, height, slices, samples);\n" - " float4 texcol = 0;\n" - " for(int i = 0; i < SAMPLES; ++i)\n" - " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" - " texcol /= SAMPLES;\n" - " int depth = int((1.0 - texcol.x) * 16777216.0);\n" + "#define SAMPLES %d\n" + "sampler samp0 : register(s0);\n" + "Texture2DMSArray Tex0 : register(t0);\n" + "uniform float4 cColMatrix[7] : register(c0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + " in float4 pos : SV_Position,\n" + " in float3 uv0 : TEXCOORD0){\n" + " int width, height, slices, samples;\n" + " Tex0.GetDimensions(width, height, slices, samples);\n" + " float4 texcol = 0;\n" + " for(int i = 0; i < SAMPLES; ++i)\n" + " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" + " texcol /= SAMPLES;\n" + " int depth = int((1.0 - texcol.x) * 16777216.0);\n" - // Convert to Z24 format - " int4 workspace;\n" - " workspace.r = (depth >> 16) & 255;\n" - " workspace.g = (depth >> 8) & 255;\n" - " workspace.b = depth & 255;\n" + // Convert to Z24 format + " int4 workspace;\n" + " workspace.r = (depth >> 16) & 255;\n" + " workspace.g = (depth >> 8) & 255;\n" + " workspace.b = depth & 255;\n" - // Convert to Z4 format - " workspace.a = (depth >> 16) & 0xF0;\n" + // Convert to Z4 format + " workspace.a = (depth >> 16) & 0xF0;\n" - // Normalize components to [0.0..1.0] - " texcol = float4(workspace) / 255.0;\n" + // Normalize components to [0.0..1.0] + " texcol = float4(workspace) / 255.0;\n" - // Apply color matrix - " ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n" -}; + // Apply color matrix + " ocol0 = " + "float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(" + "texcol,cColMatrix[3])) + cColMatrix[4];\n" + "}\n"}; static constexpr const char s_reint_rgba6_to_rgb8_program_hlsl[] = { - "sampler samp0 : register(s0);\n" - "Texture2DArray Tex0 : register(t0);\n" - "void main(\n" - " out float4 ocol0 : SV_Target,\n" - " in float4 pos : SV_Position,\n" - " in float3 uv0 : TEXCOORD0)\n" - "{\n" - " int4 src6 = round(Tex0.Sample(samp0,uv0) * 63.f);\n" - " int4 dst8;\n" - " dst8.r = (src6.r << 2) | (src6.g >> 4);\n" - " dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n" - " dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n" - " dst8.a = 255;\n" - " ocol0 = (float4)dst8 / 255.f;\n" - "}" -}; + "sampler samp0 : register(s0);\n" + "Texture2DArray Tex0 : register(t0);\n" + "void main(\n" + " out float4 ocol0 : SV_Target,\n" + " in float4 pos : SV_Position,\n" + " in float3 uv0 : TEXCOORD0)\n" + "{\n" + " int4 src6 = round(Tex0.Sample(samp0,uv0) * 63.f);\n" + " int4 dst8;\n" + " dst8.r = (src6.r << 2) | (src6.g >> 4);\n" + " dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n" + " dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n" + " dst8.a = 255;\n" + " ocol0 = (float4)dst8 / 255.f;\n" + "}"}; static constexpr const char s_reint_rgba6_to_rgb8_program_msaa_hlsl[] = { - "#define SAMPLES %d\n" - "sampler samp0 : register(s0);\n" - "Texture2DMSArray Tex0 : register(t0);\n" - "void main(\n" - " out float4 ocol0 : SV_Target,\n" - " in float4 pos : SV_Position,\n" - " in float3 uv0 : TEXCOORD0)\n" - "{\n" - " int width, height, slices, samples;\n" - " Tex0.GetDimensions(width, height, slices, samples);\n" - " float4 texcol = 0;\n" - " for (int i = 0; i < SAMPLES; ++i)\n" - " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" - " texcol /= SAMPLES;\n" - " int4 src6 = round(texcol * 63.f);\n" - " int4 dst8;\n" - " dst8.r = (src6.r << 2) | (src6.g >> 4);\n" - " dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n" - " dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n" - " dst8.a = 255;\n" - " ocol0 = (float4)dst8 / 255.f;\n" - "}" -}; + "#define SAMPLES %d\n" + "sampler samp0 : register(s0);\n" + "Texture2DMSArray Tex0 : register(t0);\n" + "void main(\n" + " out float4 ocol0 : SV_Target,\n" + " in float4 pos : SV_Position,\n" + " in float3 uv0 : TEXCOORD0)\n" + "{\n" + " int width, height, slices, samples;\n" + " Tex0.GetDimensions(width, height, slices, samples);\n" + " float4 texcol = 0;\n" + " for (int i = 0; i < SAMPLES; ++i)\n" + " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" + " texcol /= SAMPLES;\n" + " int4 src6 = round(texcol * 63.f);\n" + " int4 dst8;\n" + " dst8.r = (src6.r << 2) | (src6.g >> 4);\n" + " dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n" + " dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n" + " dst8.a = 255;\n" + " ocol0 = (float4)dst8 / 255.f;\n" + "}"}; static constexpr const char s_reint_rgb8_to_rgba6_program_hlsl[] = { - "sampler samp0 : register(s0);\n" - "Texture2DArray Tex0 : register(t0);\n" - "void main(\n" - " out float4 ocol0 : SV_Target,\n" - " in float4 pos : SV_Position,\n" - " in float3 uv0 : TEXCOORD0)\n" - "{\n" - " int4 src8 = round(Tex0.Sample(samp0,uv0) * 255.f);\n" - " int4 dst6;\n" - " dst6.r = src8.r >> 2;\n" - " dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n" - " dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n" - " dst6.a = src8.b & 0x3F;\n" - " ocol0 = (float4)dst6 / 63.f;\n" - "}\n" -}; + "sampler samp0 : register(s0);\n" + "Texture2DArray Tex0 : register(t0);\n" + "void main(\n" + " out float4 ocol0 : SV_Target,\n" + " in float4 pos : SV_Position,\n" + " in float3 uv0 : TEXCOORD0)\n" + "{\n" + " int4 src8 = round(Tex0.Sample(samp0,uv0) * 255.f);\n" + " int4 dst6;\n" + " dst6.r = src8.r >> 2;\n" + " dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n" + " dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n" + " dst6.a = src8.b & 0x3F;\n" + " ocol0 = (float4)dst6 / 63.f;\n" + "}\n"}; static constexpr const char s_reint_rgb8_to_rgba6_program_msaa_hlsl[] = { - "#define SAMPLES %d\n" - "sampler samp0 : register(s0);\n" - "Texture2DMSArray Tex0 : register(t0);\n" - "void main(\n" - " out float4 ocol0 : SV_Target,\n" - " in float4 pos : SV_Position,\n" - " in float3 uv0 : TEXCOORD0)\n" - "{\n" - " int width, height, slices, samples;\n" - " Tex0.GetDimensions(width, height, slices, samples);\n" - " float4 texcol = 0;\n" - " for (int i = 0; i < SAMPLES; ++i)\n" - " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" - " texcol /= SAMPLES;\n" - " int4 src8 = round(texcol * 255.f);\n" - " int4 dst6;\n" - " dst6.r = src8.r >> 2;\n" - " dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n" - " dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n" - " dst6.a = src8.b & 0x3F;\n" - " ocol0 = (float4)dst6 / 63.f;\n" - "}\n" -}; + "#define SAMPLES %d\n" + "sampler samp0 : register(s0);\n" + "Texture2DMSArray Tex0 : register(t0);\n" + "void main(\n" + " out float4 ocol0 : SV_Target,\n" + " in float4 pos : SV_Position,\n" + " in float3 uv0 : TEXCOORD0)\n" + "{\n" + " int width, height, slices, samples;\n" + " Tex0.GetDimensions(width, height, slices, samples);\n" + " float4 texcol = 0;\n" + " for (int i = 0; i < SAMPLES; ++i)\n" + " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" + " texcol /= SAMPLES;\n" + " int4 src8 = round(texcol * 255.f);\n" + " int4 dst6;\n" + " dst6.r = src8.r >> 2;\n" + " dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n" + " dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n" + " dst6.a = src8.b & 0x3F;\n" + " ocol0 = (float4)dst6 / 63.f;\n" + "}\n"}; // Vertex Shader HLSL static constexpr const char s_simple_vertex_shader_hlsl[] = { - "struct VSOUTPUT\n" - "{\n" - "float4 vPosition : POSITION;\n" - "float3 vTexCoord : TEXCOORD0;\n" - "float vTexCoord1 : TEXCOORD1;\n" - "};\n" - "VSOUTPUT main(float4 inPosition : POSITION,float4 inTEX0 : TEXCOORD0)\n" - "{\n" - "VSOUTPUT OUT;\n" - "OUT.vPosition = inPosition;\n" - "OUT.vTexCoord = inTEX0.xyz;\n" - "OUT.vTexCoord1 = inTEX0.w;\n" - "return OUT;\n" - "}\n" -}; + "struct VSOUTPUT\n" + "{\n" + "float4 vPosition : POSITION;\n" + "float3 vTexCoord : TEXCOORD0;\n" + "float vTexCoord1 : TEXCOORD1;\n" + "};\n" + "VSOUTPUT main(float4 inPosition : POSITION,float4 inTEX0 : TEXCOORD0)\n" + "{\n" + "VSOUTPUT OUT;\n" + "OUT.vPosition = inPosition;\n" + "OUT.vTexCoord = inTEX0.xyz;\n" + "OUT.vTexCoord1 = inTEX0.w;\n" + "return OUT;\n" + "}\n"}; static constexpr const char s_clear_vertex_shader_hlsl[] = { - "struct VSOUTPUT\n" - "{\n" - "float4 vPosition : POSITION;\n" - "float4 vColor0 : COLOR0;\n" - "};\n" - "VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0)\n" - "{\n" - "VSOUTPUT OUT;\n" - "OUT.vPosition = inPosition;\n" - "OUT.vColor0 = inColor0;\n" - "return OUT;\n" - "}\n" -}; + "struct VSOUTPUT\n" + "{\n" + "float4 vPosition : POSITION;\n" + "float4 vColor0 : COLOR0;\n" + "};\n" + "VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0)\n" + "{\n" + "VSOUTPUT OUT;\n" + "OUT.vPosition = inPosition;\n" + "OUT.vColor0 = inColor0;\n" + "return OUT;\n" + "}\n"}; // Geometry Shader HLSL static constexpr const char s_clear_geometry_shader_hlsl[] = { - "struct VSOUTPUT\n" - "{\n" - " float4 vPosition : POSITION;\n" - " float4 vColor0 : COLOR0;\n" - "};\n" - "struct GSOUTPUT\n" - "{\n" - " float4 vPosition : POSITION;\n" - " float4 vColor0 : COLOR0;\n" - " uint slice : SV_RenderTargetArrayIndex;\n" - "};\n" - "[maxvertexcount(6)]\n" - "void main(triangle VSOUTPUT o[3], inout TriangleStream Output)\n" - "{\n" - "for(int slice = 0; slice < 2; slice++)\n" - "{\n" - " for(int i = 0; i < 3; i++)\n" - " {\n" - " GSOUTPUT OUT;\n" - " OUT.vPosition = o[i].vPosition;\n" - " OUT.vColor0 = o[i].vColor0;\n" - " OUT.slice = slice;\n" - " Output.Append(OUT);\n" - " }\n" - " Output.RestartStrip();\n" - "}\n" - "}\n" -}; + "struct VSOUTPUT\n" + "{\n" + " float4 vPosition : POSITION;\n" + " float4 vColor0 : COLOR0;\n" + "};\n" + "struct GSOUTPUT\n" + "{\n" + " float4 vPosition : POSITION;\n" + " float4 vColor0 : COLOR0;\n" + " uint slice : SV_RenderTargetArrayIndex;\n" + "};\n" + "[maxvertexcount(6)]\n" + "void main(triangle VSOUTPUT o[3], inout TriangleStream Output)\n" + "{\n" + "for(int slice = 0; slice < 2; slice++)\n" + "{\n" + " for(int i = 0; i < 3; i++)\n" + " {\n" + " GSOUTPUT OUT;\n" + " OUT.vPosition = o[i].vPosition;\n" + " OUT.vColor0 = o[i].vColor0;\n" + " OUT.slice = slice;\n" + " Output.Append(OUT);\n" + " }\n" + " Output.RestartStrip();\n" + "}\n" + "}\n"}; static constexpr const char s_copy_geometry_shader_hlsl[] = { - "struct VSOUTPUT\n" - "{\n" - " float4 vPosition : POSITION;\n" - " float3 vTexCoord : TEXCOORD0;\n" - " float vTexCoord1 : TEXCOORD1;\n" - "};\n" - "struct GSOUTPUT\n" - "{\n" - " float4 vPosition : POSITION;\n" - " float3 vTexCoord : TEXCOORD0;\n" - " float vTexCoord1 : TEXCOORD1;\n" - " uint slice : SV_RenderTargetArrayIndex;\n" - "};\n" - "[maxvertexcount(6)]\n" - "void main(triangle VSOUTPUT o[3], inout TriangleStream Output)\n" - "{\n" - "for(int slice = 0; slice < 2; slice++)\n" - "{\n" - " for(int i = 0; i < 3; i++)\n" - " {\n" - " GSOUTPUT OUT;\n" - " OUT.vPosition = o[i].vPosition;\n" - " OUT.vTexCoord = o[i].vTexCoord;\n" - " OUT.vTexCoord.z = slice;\n" - " OUT.vTexCoord1 = o[i].vTexCoord1;\n" - " OUT.slice = slice;\n" - " Output.Append(OUT);\n" - " }\n" - " Output.RestartStrip();\n" - "}\n" - "}\n" -}; + "struct VSOUTPUT\n" + "{\n" + " float4 vPosition : POSITION;\n" + " float3 vTexCoord : TEXCOORD0;\n" + " float vTexCoord1 : TEXCOORD1;\n" + "};\n" + "struct GSOUTPUT\n" + "{\n" + " float4 vPosition : POSITION;\n" + " float3 vTexCoord : TEXCOORD0;\n" + " float vTexCoord1 : TEXCOORD1;\n" + " uint slice : SV_RenderTargetArrayIndex;\n" + "};\n" + "[maxvertexcount(6)]\n" + "void main(triangle VSOUTPUT o[3], inout TriangleStream Output)\n" + "{\n" + "for(int slice = 0; slice < 2; slice++)\n" + "{\n" + " for(int i = 0; i < 3; i++)\n" + " {\n" + " GSOUTPUT OUT;\n" + " OUT.vPosition = o[i].vPosition;\n" + " OUT.vTexCoord = o[i].vTexCoord;\n" + " OUT.vTexCoord.z = slice;\n" + " OUT.vTexCoord1 = o[i].vTexCoord1;\n" + " OUT.slice = slice;\n" + " Output.Append(OUT);\n" + " }\n" + " Output.RestartStrip();\n" + "}\n" + "}\n"}; static const char s_xfb_encode_shader_hlsl[] = R"( @@ -502,298 +487,312 @@ void main( D3D12_SHADER_BYTECODE StaticShaderCache::GetReinterpRGBA6ToRGB8PixelShader(bool multisampled) { - D3D12_SHADER_BYTECODE bytecode = {}; + D3D12_SHADER_BYTECODE bytecode = {}; - if (!multisampled || g_ActiveConfig.iMultisamples == 1) - { - if (!s_rgba6_to_rgb8_program_blob[0]) - { - D3D::CompilePixelShader(s_reint_rgba6_to_rgb8_program_hlsl, &s_rgba6_to_rgb8_program_blob[0]); - } + if (!multisampled || g_ActiveConfig.iMultisamples == 1) + { + if (!s_rgba6_to_rgb8_program_blob[0]) + { + D3D::CompilePixelShader(s_reint_rgba6_to_rgb8_program_hlsl, &s_rgba6_to_rgb8_program_blob[0]); + } - bytecode = { s_rgba6_to_rgb8_program_blob[0]->GetBufferPointer(), s_rgba6_to_rgb8_program_blob[0]->GetBufferSize() }; - return bytecode; - } - else if (!s_rgba6_to_rgb8_program_blob[1]) - { - // create MSAA shader for current AA mode - std::string buf = StringFromFormat(s_reint_rgba6_to_rgb8_program_msaa_hlsl, g_ActiveConfig.iMultisamples); + bytecode = {s_rgba6_to_rgb8_program_blob[0]->GetBufferPointer(), + s_rgba6_to_rgb8_program_blob[0]->GetBufferSize()}; + return bytecode; + } + else if (!s_rgba6_to_rgb8_program_blob[1]) + { + // create MSAA shader for current AA mode + std::string buf = + StringFromFormat(s_reint_rgba6_to_rgb8_program_msaa_hlsl, g_ActiveConfig.iMultisamples); - D3D::CompilePixelShader(buf, &s_rgba6_to_rgb8_program_blob[1]); - bytecode = { s_rgba6_to_rgb8_program_blob[1]->GetBufferPointer(), s_rgba6_to_rgb8_program_blob[1]->GetBufferSize() }; - } - return bytecode; + D3D::CompilePixelShader(buf, &s_rgba6_to_rgb8_program_blob[1]); + bytecode = {s_rgba6_to_rgb8_program_blob[1]->GetBufferPointer(), + s_rgba6_to_rgb8_program_blob[1]->GetBufferSize()}; + } + return bytecode; } D3D12_SHADER_BYTECODE StaticShaderCache::GetReinterpRGB8ToRGBA6PixelShader(bool multisampled) { - D3D12_SHADER_BYTECODE bytecode = {}; + D3D12_SHADER_BYTECODE bytecode = {}; - if (!multisampled || g_ActiveConfig.iMultisamples == 1) - { - if (!s_rgb8_to_rgba6_program_blob[0]) - { - D3D::CompilePixelShader(s_reint_rgb8_to_rgba6_program_hlsl, &s_rgb8_to_rgba6_program_blob[0]); - } + if (!multisampled || g_ActiveConfig.iMultisamples == 1) + { + if (!s_rgb8_to_rgba6_program_blob[0]) + { + D3D::CompilePixelShader(s_reint_rgb8_to_rgba6_program_hlsl, &s_rgb8_to_rgba6_program_blob[0]); + } - bytecode = { s_rgb8_to_rgba6_program_blob[0]->GetBufferPointer(), s_rgb8_to_rgba6_program_blob[0]->GetBufferSize() }; - return bytecode; - } - else if (!s_rgb8_to_rgba6_program_blob[1]) - { - // create MSAA shader for current AA mode - std::string buf = StringFromFormat(s_reint_rgb8_to_rgba6_program_msaa_hlsl, g_ActiveConfig.iMultisamples); + bytecode = {s_rgb8_to_rgba6_program_blob[0]->GetBufferPointer(), + s_rgb8_to_rgba6_program_blob[0]->GetBufferSize()}; + return bytecode; + } + else if (!s_rgb8_to_rgba6_program_blob[1]) + { + // create MSAA shader for current AA mode + std::string buf = + StringFromFormat(s_reint_rgb8_to_rgba6_program_msaa_hlsl, g_ActiveConfig.iMultisamples); - D3D::CompilePixelShader(buf, &s_rgb8_to_rgba6_program_blob[1]); - bytecode = { s_rgb8_to_rgba6_program_blob[1]->GetBufferPointer(), s_rgb8_to_rgba6_program_blob[1]->GetBufferSize() }; - } + D3D::CompilePixelShader(buf, &s_rgb8_to_rgba6_program_blob[1]); + bytecode = {s_rgb8_to_rgba6_program_blob[1]->GetBufferPointer(), + s_rgb8_to_rgba6_program_blob[1]->GetBufferSize()}; + } - return bytecode; + return bytecode; } D3D12_SHADER_BYTECODE StaticShaderCache::GetColorCopyPixelShader(bool multisampled) { - D3D12_SHADER_BYTECODE bytecode = {}; + D3D12_SHADER_BYTECODE bytecode = {}; - if (!multisampled || g_ActiveConfig.iMultisamples == 1) - { - bytecode = { s_color_copy_program_blob[0]->GetBufferPointer(), s_color_copy_program_blob[0]->GetBufferSize() }; - } - else if (s_color_copy_program_blob[1]) - { - bytecode = { s_color_copy_program_blob[1]->GetBufferPointer(), s_color_copy_program_blob[1]->GetBufferSize() }; - } - else - { - // create MSAA shader for current AA mode - std::string buf = StringFromFormat(s_color_copy_program_msaa_hlsl, g_ActiveConfig.iMultisamples); + if (!multisampled || g_ActiveConfig.iMultisamples == 1) + { + bytecode = {s_color_copy_program_blob[0]->GetBufferPointer(), + s_color_copy_program_blob[0]->GetBufferSize()}; + } + else if (s_color_copy_program_blob[1]) + { + bytecode = {s_color_copy_program_blob[1]->GetBufferPointer(), + s_color_copy_program_blob[1]->GetBufferSize()}; + } + else + { + // create MSAA shader for current AA mode + std::string buf = + StringFromFormat(s_color_copy_program_msaa_hlsl, g_ActiveConfig.iMultisamples); - D3D::CompilePixelShader(buf, &s_color_copy_program_blob[1]); - bytecode = { s_color_copy_program_blob[1]->GetBufferPointer(), s_color_copy_program_blob[1]->GetBufferSize() }; - } + D3D::CompilePixelShader(buf, &s_color_copy_program_blob[1]); + bytecode = {s_color_copy_program_blob[1]->GetBufferPointer(), + s_color_copy_program_blob[1]->GetBufferSize()}; + } - return bytecode; + return bytecode; } D3D12_SHADER_BYTECODE StaticShaderCache::GetDepthResolveToColorPixelShader() { - D3D12_SHADER_BYTECODE bytecode = {}; + D3D12_SHADER_BYTECODE bytecode = {}; - if (s_depth_resolve_to_color_program_blob) - { - bytecode = { s_depth_resolve_to_color_program_blob->GetBufferPointer(), s_depth_resolve_to_color_program_blob->GetBufferSize() }; - } - else - { - // create MSAA shader for current AA mode - std::string buf = StringFromFormat(s_depth_resolve_to_color_program_hlsl, g_ActiveConfig.iMultisamples); + if (s_depth_resolve_to_color_program_blob) + { + bytecode = {s_depth_resolve_to_color_program_blob->GetBufferPointer(), + s_depth_resolve_to_color_program_blob->GetBufferSize()}; + } + else + { + // create MSAA shader for current AA mode + std::string buf = + StringFromFormat(s_depth_resolve_to_color_program_hlsl, g_ActiveConfig.iMultisamples); - D3D::CompilePixelShader(buf, &s_depth_resolve_to_color_program_blob); - bytecode = { s_depth_resolve_to_color_program_blob->GetBufferPointer(), s_depth_resolve_to_color_program_blob->GetBufferSize() }; - } + D3D::CompilePixelShader(buf, &s_depth_resolve_to_color_program_blob); + bytecode = {s_depth_resolve_to_color_program_blob->GetBufferPointer(), + s_depth_resolve_to_color_program_blob->GetBufferSize()}; + } - return bytecode; + return bytecode; } D3D12_SHADER_BYTECODE StaticShaderCache::GetColorMatrixPixelShader(bool multisampled) { - D3D12_SHADER_BYTECODE bytecode = {}; + D3D12_SHADER_BYTECODE bytecode = {}; - if (!multisampled || g_ActiveConfig.iMultisamples == 1) - { - bytecode = { s_color_matrix_program_blob[0]->GetBufferPointer(), s_color_matrix_program_blob[0]->GetBufferSize() }; - } - else if (s_color_matrix_program_blob[1]) - { - bytecode = { s_color_matrix_program_blob[1]->GetBufferPointer(), s_color_matrix_program_blob[1]->GetBufferSize() }; - } - else - { - // create MSAA shader for current AA mode - std::string buf = StringFromFormat(s_color_matrix_program_msaa_hlsl, g_ActiveConfig.iMultisamples); + if (!multisampled || g_ActiveConfig.iMultisamples == 1) + { + bytecode = {s_color_matrix_program_blob[0]->GetBufferPointer(), + s_color_matrix_program_blob[0]->GetBufferSize()}; + } + else if (s_color_matrix_program_blob[1]) + { + bytecode = {s_color_matrix_program_blob[1]->GetBufferPointer(), + s_color_matrix_program_blob[1]->GetBufferSize()}; + } + else + { + // create MSAA shader for current AA mode + std::string buf = + StringFromFormat(s_color_matrix_program_msaa_hlsl, g_ActiveConfig.iMultisamples); - D3D::CompilePixelShader(buf, &s_color_matrix_program_blob[1]); - bytecode = { s_color_matrix_program_blob[1]->GetBufferPointer(), s_color_matrix_program_blob[1]->GetBufferSize() }; - } + D3D::CompilePixelShader(buf, &s_color_matrix_program_blob[1]); + bytecode = {s_color_matrix_program_blob[1]->GetBufferPointer(), + s_color_matrix_program_blob[1]->GetBufferSize()}; + } - return bytecode; + return bytecode; } D3D12_SHADER_BYTECODE StaticShaderCache::GetDepthMatrixPixelShader(bool multisampled) { - D3D12_SHADER_BYTECODE bytecode = {}; + D3D12_SHADER_BYTECODE bytecode = {}; - if (!multisampled || g_ActiveConfig.iMultisamples == 1) - { - bytecode = { s_depth_matrix_program_blob[0]->GetBufferPointer(), s_depth_matrix_program_blob[0]->GetBufferSize() }; - } - else if (s_depth_matrix_program_blob[1]) - { - bytecode = { s_depth_matrix_program_blob[1]->GetBufferPointer(), s_depth_matrix_program_blob[1]->GetBufferSize() }; - } - else - { - // create MSAA shader for current AA mode - std::string buf = StringFromFormat(s_depth_matrix_program_msaa_hlsl, g_ActiveConfig.iMultisamples); + if (!multisampled || g_ActiveConfig.iMultisamples == 1) + { + bytecode = {s_depth_matrix_program_blob[0]->GetBufferPointer(), + s_depth_matrix_program_blob[0]->GetBufferSize()}; + } + else if (s_depth_matrix_program_blob[1]) + { + bytecode = {s_depth_matrix_program_blob[1]->GetBufferPointer(), + s_depth_matrix_program_blob[1]->GetBufferSize()}; + } + else + { + // create MSAA shader for current AA mode + std::string buf = + StringFromFormat(s_depth_matrix_program_msaa_hlsl, g_ActiveConfig.iMultisamples); - D3D::CompilePixelShader(buf, &s_depth_matrix_program_blob[1]); + D3D::CompilePixelShader(buf, &s_depth_matrix_program_blob[1]); - bytecode = { s_depth_matrix_program_blob[1]->GetBufferPointer(), s_depth_matrix_program_blob[1]->GetBufferSize() }; - } + bytecode = {s_depth_matrix_program_blob[1]->GetBufferPointer(), + s_depth_matrix_program_blob[1]->GetBufferSize()}; + } - return bytecode; + return bytecode; } D3D12_SHADER_BYTECODE StaticShaderCache::GetClearPixelShader() { - D3D12_SHADER_BYTECODE shader = {}; - shader.BytecodeLength = s_clear_program_blob->GetBufferSize(); - shader.pShaderBytecode = s_clear_program_blob->GetBufferPointer(); + D3D12_SHADER_BYTECODE shader = {}; + shader.BytecodeLength = s_clear_program_blob->GetBufferSize(); + shader.pShaderBytecode = s_clear_program_blob->GetBufferPointer(); - return shader; + return shader; } D3D12_SHADER_BYTECODE StaticShaderCache::GetAnaglyphPixelShader() { - D3D12_SHADER_BYTECODE shader = {}; - shader.BytecodeLength = s_anaglyph_program_blob->GetBufferSize(); - shader.pShaderBytecode = s_anaglyph_program_blob->GetBufferPointer(); + D3D12_SHADER_BYTECODE shader = {}; + shader.BytecodeLength = s_anaglyph_program_blob->GetBufferSize(); + shader.pShaderBytecode = s_anaglyph_program_blob->GetBufferPointer(); - return shader; + return shader; } D3D12_SHADER_BYTECODE StaticShaderCache::GetSimpleVertexShader() { - D3D12_SHADER_BYTECODE shader = {}; - shader.BytecodeLength = s_simple_vertex_shader_blob->GetBufferSize(); - shader.pShaderBytecode = s_simple_vertex_shader_blob->GetBufferPointer(); + D3D12_SHADER_BYTECODE shader = {}; + shader.BytecodeLength = s_simple_vertex_shader_blob->GetBufferSize(); + shader.pShaderBytecode = s_simple_vertex_shader_blob->GetBufferPointer(); - return shader; + return shader; } D3D12_SHADER_BYTECODE StaticShaderCache::GetClearVertexShader() { - D3D12_SHADER_BYTECODE shader = {}; - shader.BytecodeLength = s_simple_clear_vertex_shader_blob->GetBufferSize(); - shader.pShaderBytecode = s_simple_clear_vertex_shader_blob->GetBufferPointer(); + D3D12_SHADER_BYTECODE shader = {}; + shader.BytecodeLength = s_simple_clear_vertex_shader_blob->GetBufferSize(); + shader.pShaderBytecode = s_simple_clear_vertex_shader_blob->GetBufferPointer(); - return shader; + return shader; } D3D12_INPUT_LAYOUT_DESC StaticShaderCache::GetSimpleVertexShaderInputLayout() { - return s_simple_vertex_shader_input_layout; + return s_simple_vertex_shader_input_layout; } D3D12_INPUT_LAYOUT_DESC StaticShaderCache::GetClearVertexShaderInputLayout() { - return s_clear_vertex_shader_input_layout; + return s_clear_vertex_shader_input_layout; } D3D12_SHADER_BYTECODE StaticShaderCache::GetClearGeometryShader() { - D3D12_SHADER_BYTECODE bytecode = {}; - if (g_ActiveConfig.iStereoMode > 0) - { - bytecode.BytecodeLength = s_clear_geometry_shader_blob->GetBufferSize(); - bytecode.pShaderBytecode = s_clear_geometry_shader_blob->GetBufferPointer(); - } + D3D12_SHADER_BYTECODE bytecode = {}; + if (g_ActiveConfig.iStereoMode > 0) + { + bytecode.BytecodeLength = s_clear_geometry_shader_blob->GetBufferSize(); + bytecode.pShaderBytecode = s_clear_geometry_shader_blob->GetBufferPointer(); + } - return bytecode; + return bytecode; } D3D12_SHADER_BYTECODE StaticShaderCache::GetCopyGeometryShader() { - D3D12_SHADER_BYTECODE bytecode = {}; - if (g_ActiveConfig.iStereoMode > 0) - { - bytecode.BytecodeLength = s_copy_geometry_shader_blob->GetBufferSize(); - bytecode.pShaderBytecode = s_copy_geometry_shader_blob->GetBufferPointer(); - } + D3D12_SHADER_BYTECODE bytecode = {}; + if (g_ActiveConfig.iStereoMode > 0) + { + bytecode.BytecodeLength = s_copy_geometry_shader_blob->GetBufferSize(); + bytecode.pShaderBytecode = s_copy_geometry_shader_blob->GetBufferPointer(); + } - return bytecode; + return bytecode; } D3D12_SHADER_BYTECODE StaticShaderCache::GetXFBEncodePixelShader() { - D3D12_SHADER_BYTECODE bytecode = - { - s_xfb_encode_shader_blob->GetBufferPointer(), - s_xfb_encode_shader_blob->GetBufferSize() - }; + D3D12_SHADER_BYTECODE bytecode = {s_xfb_encode_shader_blob->GetBufferPointer(), + s_xfb_encode_shader_blob->GetBufferSize()}; - return bytecode; + return bytecode; } D3D12_SHADER_BYTECODE StaticShaderCache::GetXFBDecodePixelShader() { - D3D12_SHADER_BYTECODE bytecode = - { - s_xfb_decode_shader_blob->GetBufferPointer(), - s_xfb_decode_shader_blob->GetBufferSize() - }; + D3D12_SHADER_BYTECODE bytecode = {s_xfb_decode_shader_blob->GetBufferPointer(), + s_xfb_decode_shader_blob->GetBufferSize()}; - return bytecode; + return bytecode; } void StaticShaderCache::Init() { - // Compile static pixel shaders - D3D::CompilePixelShader(s_clear_program_hlsl, &s_clear_program_blob); - D3D::CompilePixelShader(s_anaglyph_program_hlsl, &s_anaglyph_program_blob); - D3D::CompilePixelShader(s_color_copy_program_hlsl, &s_color_copy_program_blob[0]); - D3D::CompilePixelShader(s_color_matrix_program_hlsl, &s_color_matrix_program_blob[0]); - D3D::CompilePixelShader(s_depth_matrix_program_hlsl, &s_depth_matrix_program_blob[0]); - D3D::CompilePixelShader(s_xfb_encode_shader_hlsl, &s_xfb_encode_shader_blob); - D3D::CompilePixelShader(s_xfb_decode_shader_hlsl, &s_xfb_decode_shader_blob); + // Compile static pixel shaders + D3D::CompilePixelShader(s_clear_program_hlsl, &s_clear_program_blob); + D3D::CompilePixelShader(s_anaglyph_program_hlsl, &s_anaglyph_program_blob); + D3D::CompilePixelShader(s_color_copy_program_hlsl, &s_color_copy_program_blob[0]); + D3D::CompilePixelShader(s_color_matrix_program_hlsl, &s_color_matrix_program_blob[0]); + D3D::CompilePixelShader(s_depth_matrix_program_hlsl, &s_depth_matrix_program_blob[0]); + D3D::CompilePixelShader(s_xfb_encode_shader_hlsl, &s_xfb_encode_shader_blob); + D3D::CompilePixelShader(s_xfb_decode_shader_hlsl, &s_xfb_decode_shader_blob); - // Compile static vertex shaders - D3D::CompileVertexShader(s_simple_vertex_shader_hlsl, &s_simple_vertex_shader_blob); - D3D::CompileVertexShader(s_clear_vertex_shader_hlsl, &s_simple_clear_vertex_shader_blob); + // Compile static vertex shaders + D3D::CompileVertexShader(s_simple_vertex_shader_hlsl, &s_simple_vertex_shader_blob); + D3D::CompileVertexShader(s_clear_vertex_shader_hlsl, &s_simple_clear_vertex_shader_blob); - // Compile static geometry shaders - D3D::CompileGeometryShader(s_clear_geometry_shader_hlsl, &s_clear_geometry_shader_blob); - D3D::CompileGeometryShader(s_copy_geometry_shader_hlsl, &s_copy_geometry_shader_blob); + // Compile static geometry shaders + D3D::CompileGeometryShader(s_clear_geometry_shader_hlsl, &s_clear_geometry_shader_blob); + D3D::CompileGeometryShader(s_copy_geometry_shader_hlsl, &s_copy_geometry_shader_blob); } // Call this when multisampling mode changes, and shaders need to be regenerated. void StaticShaderCache::InvalidateMSAAShaders() { - SAFE_RELEASE(s_color_copy_program_blob[1]); - SAFE_RELEASE(s_color_matrix_program_blob[1]); - SAFE_RELEASE(s_depth_matrix_program_blob[1]); - SAFE_RELEASE(s_rgb8_to_rgba6_program_blob[1]); - SAFE_RELEASE(s_rgba6_to_rgb8_program_blob[1]); - SAFE_RELEASE(s_depth_resolve_to_color_program_blob); + SAFE_RELEASE(s_color_copy_program_blob[1]); + SAFE_RELEASE(s_color_matrix_program_blob[1]); + SAFE_RELEASE(s_depth_matrix_program_blob[1]); + SAFE_RELEASE(s_rgb8_to_rgba6_program_blob[1]); + SAFE_RELEASE(s_rgba6_to_rgb8_program_blob[1]); + SAFE_RELEASE(s_depth_resolve_to_color_program_blob); } void StaticShaderCache::Shutdown() { - // Free pixel shader blobs - SAFE_RELEASE(s_xfb_decode_shader_blob); - SAFE_RELEASE(s_xfb_encode_shader_blob); - SAFE_RELEASE(s_clear_program_blob); - SAFE_RELEASE(s_anaglyph_program_blob); - SAFE_RELEASE(s_depth_resolve_to_color_program_blob); + // Free pixel shader blobs + SAFE_RELEASE(s_xfb_decode_shader_blob); + SAFE_RELEASE(s_xfb_encode_shader_blob); + SAFE_RELEASE(s_clear_program_blob); + SAFE_RELEASE(s_anaglyph_program_blob); + SAFE_RELEASE(s_depth_resolve_to_color_program_blob); - for (unsigned int i = 0; i < 2; ++i) - { - SAFE_RELEASE(s_color_copy_program_blob[i]); - SAFE_RELEASE(s_color_matrix_program_blob[i]); - SAFE_RELEASE(s_depth_matrix_program_blob[i]); - SAFE_RELEASE(s_rgba6_to_rgb8_program_blob[i]); - SAFE_RELEASE(s_rgb8_to_rgba6_program_blob[i]); - } + for (unsigned int i = 0; i < 2; ++i) + { + SAFE_RELEASE(s_color_copy_program_blob[i]); + SAFE_RELEASE(s_color_matrix_program_blob[i]); + SAFE_RELEASE(s_depth_matrix_program_blob[i]); + SAFE_RELEASE(s_rgba6_to_rgb8_program_blob[i]); + SAFE_RELEASE(s_rgb8_to_rgba6_program_blob[i]); + } - // Free vertex shader blobs + // Free vertex shader blobs - SAFE_RELEASE(s_simple_vertex_shader_blob); - SAFE_RELEASE(s_simple_clear_vertex_shader_blob); + SAFE_RELEASE(s_simple_vertex_shader_blob); + SAFE_RELEASE(s_simple_clear_vertex_shader_blob); - // Free geometry shader blobs + // Free geometry shader blobs - SAFE_RELEASE(s_clear_geometry_shader_blob); - SAFE_RELEASE(s_copy_geometry_shader_blob); + SAFE_RELEASE(s_clear_geometry_shader_blob); + SAFE_RELEASE(s_copy_geometry_shader_blob); } - } \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D12/StaticShaderCache.h b/Source/Core/VideoBackends/D3D12/StaticShaderCache.h index 492363f0a8..89e2d9c0f8 100644 --- a/Source/Core/VideoBackends/D3D12/StaticShaderCache.h +++ b/Source/Core/VideoBackends/D3D12/StaticShaderCache.h @@ -6,35 +6,33 @@ namespace DX12 { - class StaticShaderCache final { public: - static void Init(); - static void InvalidateMSAAShaders(); - static void Shutdown(); + static void Init(); + static void InvalidateMSAAShaders(); + static void Shutdown(); - // Pixel shaders - static D3D12_SHADER_BYTECODE GetColorMatrixPixelShader(bool multisampled); - static D3D12_SHADER_BYTECODE GetColorCopyPixelShader(bool multisampled); - static D3D12_SHADER_BYTECODE GetDepthMatrixPixelShader(bool multisampled); - static D3D12_SHADER_BYTECODE GetDepthResolveToColorPixelShader(); - static D3D12_SHADER_BYTECODE GetClearPixelShader(); - static D3D12_SHADER_BYTECODE GetAnaglyphPixelShader(); - static D3D12_SHADER_BYTECODE GetReinterpRGBA6ToRGB8PixelShader(bool multisampled); - static D3D12_SHADER_BYTECODE GetReinterpRGB8ToRGBA6PixelShader(bool multisampled); - static D3D12_SHADER_BYTECODE GetXFBEncodePixelShader(); - static D3D12_SHADER_BYTECODE GetXFBDecodePixelShader(); + // Pixel shaders + static D3D12_SHADER_BYTECODE GetColorMatrixPixelShader(bool multisampled); + static D3D12_SHADER_BYTECODE GetColorCopyPixelShader(bool multisampled); + static D3D12_SHADER_BYTECODE GetDepthMatrixPixelShader(bool multisampled); + static D3D12_SHADER_BYTECODE GetDepthResolveToColorPixelShader(); + static D3D12_SHADER_BYTECODE GetClearPixelShader(); + static D3D12_SHADER_BYTECODE GetAnaglyphPixelShader(); + static D3D12_SHADER_BYTECODE GetReinterpRGBA6ToRGB8PixelShader(bool multisampled); + static D3D12_SHADER_BYTECODE GetReinterpRGB8ToRGBA6PixelShader(bool multisampled); + static D3D12_SHADER_BYTECODE GetXFBEncodePixelShader(); + static D3D12_SHADER_BYTECODE GetXFBDecodePixelShader(); - // Vertex shaders - static D3D12_SHADER_BYTECODE GetSimpleVertexShader(); - static D3D12_SHADER_BYTECODE GetClearVertexShader(); - static D3D12_INPUT_LAYOUT_DESC GetSimpleVertexShaderInputLayout(); - static D3D12_INPUT_LAYOUT_DESC GetClearVertexShaderInputLayout(); + // Vertex shaders + static D3D12_SHADER_BYTECODE GetSimpleVertexShader(); + static D3D12_SHADER_BYTECODE GetClearVertexShader(); + static D3D12_INPUT_LAYOUT_DESC GetSimpleVertexShaderInputLayout(); + static D3D12_INPUT_LAYOUT_DESC GetClearVertexShaderInputLayout(); - // Geometry shaders - static D3D12_SHADER_BYTECODE GetClearGeometryShader(); - static D3D12_SHADER_BYTECODE GetCopyGeometryShader(); + // Geometry shaders + static D3D12_SHADER_BYTECODE GetClearGeometryShader(); + static D3D12_SHADER_BYTECODE GetCopyGeometryShader(); }; - } \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D12/TextureCache.cpp b/Source/Core/VideoBackends/D3D12/TextureCache.cpp index 4b235d1037..ffedeeeadc 100644 --- a/Source/Core/VideoBackends/D3D12/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D12/TextureCache.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoBackends/D3D12/TextureCache.h" #include "VideoBackends/D3D12/D3DBase.h" #include "VideoBackends/D3D12/D3DCommandListManager.h" #include "VideoBackends/D3D12/D3DDescriptorHeapManager.h" @@ -12,7 +13,6 @@ #include "VideoBackends/D3D12/FramebufferManager.h" #include "VideoBackends/D3D12/PSTextureEncoder.h" #include "VideoBackends/D3D12/StaticShaderCache.h" -#include "VideoBackends/D3D12/TextureCache.h" #include "VideoBackends/D3D12/TextureEncoder.h" #include "VideoCommon/ImageWrite.h" #include "VideoCommon/LookUpTables.h" @@ -21,7 +21,6 @@ namespace DX12 { - static std::unique_ptr s_encoder = nullptr; static std::unique_ptr s_efb_copy_stream_buffer = nullptr; @@ -32,287 +31,288 @@ static size_t s_texture_cache_entry_readback_buffer_size = 0; TextureCache::TCacheEntry::~TCacheEntry() { - m_texture->Release(); + m_texture->Release(); } void TextureCache::TCacheEntry::Bind(unsigned int stage) { - // Textures bound as group in TextureCache::BindTextures method. + // Textures bound as group in TextureCache::BindTextures method. } bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int level) { - u32 level_width = std::max(config.width >> level, 1u); - u32 level_height = std::max(config.height >> level, 1u); - size_t level_pitch = D3D::AlignValue(level_width * sizeof(u32), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); - size_t required_readback_buffer_size = level_pitch * level_height; + u32 level_width = std::max(config.width >> level, 1u); + u32 level_height = std::max(config.height >> level, 1u); + size_t level_pitch = + D3D::AlignValue(level_width * sizeof(u32), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + size_t required_readback_buffer_size = level_pitch * level_height; - // Check if the current readback buffer is large enough - if (required_readback_buffer_size > s_texture_cache_entry_readback_buffer_size) - { - // Reallocate the buffer with the new size. Safe to immediately release because we're the only user and we block until completion. - if (s_texture_cache_entry_readback_buffer) - s_texture_cache_entry_readback_buffer->Release(); + // Check if the current readback buffer is large enough + if (required_readback_buffer_size > s_texture_cache_entry_readback_buffer_size) + { + // Reallocate the buffer with the new size. Safe to immediately release because we're the only + // user and we block until completion. + if (s_texture_cache_entry_readback_buffer) + s_texture_cache_entry_readback_buffer->Release(); - s_texture_cache_entry_readback_buffer_size = required_readback_buffer_size; - CheckHR(D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Buffer(s_texture_cache_entry_readback_buffer_size), - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(&s_texture_cache_entry_readback_buffer))); - } + s_texture_cache_entry_readback_buffer_size = required_readback_buffer_size; + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer(s_texture_cache_entry_readback_buffer_size), + D3D12_RESOURCE_STATE_COPY_DEST, nullptr, + IID_PPV_ARGS(&s_texture_cache_entry_readback_buffer))); + } - m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); + m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); - D3D12_TEXTURE_COPY_LOCATION dst_location = {}; - dst_location.pResource = s_texture_cache_entry_readback_buffer; - dst_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - dst_location.PlacedFootprint.Offset = 0; - dst_location.PlacedFootprint.Footprint.Depth = 1; - dst_location.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - dst_location.PlacedFootprint.Footprint.Width = level_width; - dst_location.PlacedFootprint.Footprint.Height = level_height; - dst_location.PlacedFootprint.Footprint.RowPitch = static_cast(level_pitch); + D3D12_TEXTURE_COPY_LOCATION dst_location = {}; + dst_location.pResource = s_texture_cache_entry_readback_buffer; + dst_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + dst_location.PlacedFootprint.Offset = 0; + dst_location.PlacedFootprint.Footprint.Depth = 1; + dst_location.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + dst_location.PlacedFootprint.Footprint.Width = level_width; + dst_location.PlacedFootprint.Footprint.Height = level_height; + dst_location.PlacedFootprint.Footprint.RowPitch = static_cast(level_pitch); - D3D12_TEXTURE_COPY_LOCATION src_location = CD3DX12_TEXTURE_COPY_LOCATION(m_texture->GetTex12(), level); + D3D12_TEXTURE_COPY_LOCATION src_location = + CD3DX12_TEXTURE_COPY_LOCATION(m_texture->GetTex12(), level); - D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, nullptr); + D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, nullptr); - D3D::command_list_mgr->ExecuteQueuedWork(true); + D3D::command_list_mgr->ExecuteQueuedWork(true); - // Map readback buffer and save to file. - void* readback_texture_map; - D3D12_RANGE read_range = { 0, required_readback_buffer_size }; - CheckHR(s_texture_cache_entry_readback_buffer->Map(0, &read_range, &readback_texture_map)); + // Map readback buffer and save to file. + void* readback_texture_map; + D3D12_RANGE read_range = {0, required_readback_buffer_size}; + CheckHR(s_texture_cache_entry_readback_buffer->Map(0, &read_range, &readback_texture_map)); - bool saved = TextureToPng( - static_cast(readback_texture_map), - dst_location.PlacedFootprint.Footprint.RowPitch, - filename, - dst_location.PlacedFootprint.Footprint.Width, - dst_location.PlacedFootprint.Footprint.Height - ); + bool saved = TextureToPng(static_cast(readback_texture_map), + dst_location.PlacedFootprint.Footprint.RowPitch, filename, + dst_location.PlacedFootprint.Footprint.Width, + dst_location.PlacedFootprint.Footprint.Height); - D3D12_RANGE write_range = {}; - s_texture_cache_entry_readback_buffer->Unmap(0, &write_range); - return saved; + D3D12_RANGE write_range = {}; + s_texture_cache_entry_readback_buffer->Unmap(0, &write_range); + return saved; } -void TextureCache::TCacheEntry::CopyRectangleFromTexture( - const TCacheEntryBase* source, - const MathUtil::Rectangle& src_rect, - const MathUtil::Rectangle& dst_rect) +void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase* source, + const MathUtil::Rectangle& src_rect, + const MathUtil::Rectangle& dst_rect) { - const TCacheEntry* srcentry = reinterpret_cast(source); - if (src_rect.GetWidth() == dst_rect.GetWidth() - && src_rect.GetHeight() == dst_rect.GetHeight()) - { - // These assertions should hold true unless the base code is passing us sizes too large, in which case it should be fixed instead. - _assert_msg_(VIDEO, - static_cast(src_rect.GetWidth()) <= source->config.width && - static_cast(src_rect.GetHeight()) <= source->config.height, - "Source rect is too large for CopyRectangleFromTexture"); + const TCacheEntry* srcentry = reinterpret_cast(source); + if (src_rect.GetWidth() == dst_rect.GetWidth() && src_rect.GetHeight() == dst_rect.GetHeight()) + { + // These assertions should hold true unless the base code is passing us sizes too large, in + // which case it should be fixed instead. + _assert_msg_(VIDEO, static_cast(src_rect.GetWidth()) <= source->config.width && + static_cast(src_rect.GetHeight()) <= source->config.height, + "Source rect is too large for CopyRectangleFromTexture"); - _assert_msg_(VIDEO, - static_cast(dst_rect.GetWidth()) <= config.width && - static_cast(dst_rect.GetHeight()) <= config.height, - "Dest rect is too large for CopyRectangleFromTexture"); + _assert_msg_(VIDEO, static_cast(dst_rect.GetWidth()) <= config.width && + static_cast(dst_rect.GetHeight()) <= config.height, + "Dest rect is too large for CopyRectangleFromTexture"); - CD3DX12_BOX src_box(src_rect.left, src_rect.top, 0, src_rect.right, src_rect.bottom, srcentry->config.layers); - D3D12_TEXTURE_COPY_LOCATION dst_location = CD3DX12_TEXTURE_COPY_LOCATION(m_texture->GetTex12(), 0); - D3D12_TEXTURE_COPY_LOCATION src_location = CD3DX12_TEXTURE_COPY_LOCATION(srcentry->m_texture->GetTex12(), 0); + CD3DX12_BOX src_box(src_rect.left, src_rect.top, 0, src_rect.right, src_rect.bottom, + srcentry->config.layers); + D3D12_TEXTURE_COPY_LOCATION dst_location = + CD3DX12_TEXTURE_COPY_LOCATION(m_texture->GetTex12(), 0); + D3D12_TEXTURE_COPY_LOCATION src_location = + CD3DX12_TEXTURE_COPY_LOCATION(srcentry->m_texture->GetTex12(), 0); - m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_DEST); - srcentry->m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); - D3D::current_command_list->CopyTextureRegion(&dst_location, dst_rect.left, dst_rect.top, 0, &src_location, &src_box); + m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_DEST); + srcentry->m_texture->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_COPY_SOURCE); + D3D::current_command_list->CopyTextureRegion(&dst_location, dst_rect.left, dst_rect.top, 0, + &src_location, &src_box); - m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - srcentry->m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + m_texture->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + srcentry->m_texture->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - return; - } - else if (!config.rendertarget) - { - return; - } + return; + } + else if (!config.rendertarget) + { + return; + } - D3D::SetViewportAndScissor(dst_rect.left, dst_rect.top, dst_rect.GetWidth(), dst_rect.GetHeight()); + D3D::SetViewportAndScissor(dst_rect.left, dst_rect.top, dst_rect.GetWidth(), + dst_rect.GetHeight()); - m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - D3D::current_command_list->OMSetRenderTargets(1, &m_texture->GetRTV12(), FALSE, nullptr); + m_texture->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_RENDER_TARGET); + D3D::current_command_list->OMSetRenderTargets(1, &m_texture->GetRTV12(), FALSE, nullptr); - D3D::SetLinearCopySampler(); + D3D::SetLinearCopySampler(); - D3D12_RECT src_rc; - src_rc.left = src_rect.left; - src_rc.right = src_rect.right; - src_rc.top = src_rect.top; - src_rc.bottom = src_rect.bottom; + D3D12_RECT src_rc; + src_rc.left = src_rect.left; + src_rc.right = src_rect.right; + src_rc.top = src_rect.top; + src_rc.bottom = src_rect.bottom; - D3D::DrawShadedTexQuad(srcentry->m_texture, &src_rc, - srcentry->config.width, srcentry->config.height, - StaticShaderCache::GetColorCopyPixelShader(false), - StaticShaderCache::GetSimpleVertexShader(), - StaticShaderCache::GetSimpleVertexShaderInputLayout(), D3D12_SHADER_BYTECODE(), 1.0, 0, - DXGI_FORMAT_R8G8B8A8_UNORM, false, m_texture->GetMultisampled()); + D3D::DrawShadedTexQuad( + srcentry->m_texture, &src_rc, srcentry->config.width, srcentry->config.height, + StaticShaderCache::GetColorCopyPixelShader(false), StaticShaderCache::GetSimpleVertexShader(), + StaticShaderCache::GetSimpleVertexShaderInputLayout(), D3D12_SHADER_BYTECODE(), 1.0, 0, + DXGI_FORMAT_R8G8B8A8_UNORM, false, m_texture->GetMultisampled()); - m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + m_texture->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); + FramebufferManager::GetEFBColorTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); - g_renderer->RestoreAPIState(); + g_renderer->RestoreAPIState(); } void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int level) + unsigned int expanded_width, unsigned int level) { - unsigned int src_pitch = 4 * expanded_width; - D3D::ReplaceRGBATexture2D(m_texture->GetTex12(), TextureCache::temp, width, height, src_pitch, level, m_texture->GetResourceUsageState()); + unsigned int src_pitch = 4 * expanded_width; + D3D::ReplaceRGBATexture2D(m_texture->GetTex12(), TextureCache::temp, width, height, src_pitch, + level, m_texture->GetResourceUsageState()); } TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntryConfig& config) { - if (config.rendertarget) - { - D3DTexture2D* texture = D3DTexture2D::Create(config.width, config.height, - TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, - DXGI_FORMAT_R8G8B8A8_UNORM, 1, config.layers); + if (config.rendertarget) + { + D3DTexture2D* texture = + D3DTexture2D::Create(config.width, config.height, + TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, + DXGI_FORMAT_R8G8B8A8_UNORM, 1, config.layers); - TCacheEntry* entry = new TCacheEntry(config, texture); + TCacheEntry* entry = new TCacheEntry(config, texture); - entry->m_texture_srv_cpu_handle = texture->GetSRV12CPU(); - entry->m_texture_srv_gpu_handle = texture->GetSRV12GPU(); - entry->m_texture_srv_gpu_handle_cpu_shadow = texture->GetSRV12GPUCPUShadow(); + entry->m_texture_srv_cpu_handle = texture->GetSRV12CPU(); + entry->m_texture_srv_gpu_handle = texture->GetSRV12GPU(); + entry->m_texture_srv_gpu_handle_cpu_shadow = texture->GetSRV12GPUCPUShadow(); - return entry; - } - else - { - ID3D12Resource* texture_resource = nullptr; + return entry; + } + else + { + ID3D12Resource* texture_resource = nullptr; - D3D12_RESOURCE_DESC texture_resource_desc = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, - config.width, config.height, 1, config.levels); + D3D12_RESOURCE_DESC texture_resource_desc = CD3DX12_RESOURCE_DESC::Tex2D( + DXGI_FORMAT_R8G8B8A8_UNORM, config.width, config.height, 1, config.levels); - CheckHR( - D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC(texture_resource_desc), - D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, - nullptr, - IID_PPV_ARGS(&texture_resource) - ) - ); + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC(texture_resource_desc), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + nullptr, IID_PPV_ARGS(&texture_resource))); - D3DTexture2D* texture = new D3DTexture2D( - texture_resource, - TEXTURE_BIND_FLAG_SHADER_RESOURCE, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, - false, - D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE - ); + D3DTexture2D* texture = + new D3DTexture2D(texture_resource, TEXTURE_BIND_FLAG_SHADER_RESOURCE, DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, false, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - TCacheEntry* const entry = new TCacheEntry( - config, texture - ); + TCacheEntry* const entry = new TCacheEntry(config, texture); - entry->m_texture_srv_cpu_handle = texture->GetSRV12CPU(); - entry->m_texture_srv_gpu_handle = texture->GetSRV12GPU(); - entry->m_texture_srv_gpu_handle_cpu_shadow = texture->GetSRV12GPUCPUShadow(); + entry->m_texture_srv_cpu_handle = texture->GetSRV12CPU(); + entry->m_texture_srv_gpu_handle = texture->GetSRV12GPU(); + entry->m_texture_srv_gpu_handle_cpu_shadow = texture->GetSRV12GPUCPUShadow(); - // EXISTINGD3D11TODO: better debug names - D3D::SetDebugObjectName12(entry->m_texture->GetTex12(), "a texture of the TextureCache"); + // EXISTINGD3D11TODO: better debug names + D3D::SetDebugObjectName12(entry->m_texture->GetTex12(), "a texture of the TextureCache"); - SAFE_RELEASE(texture_resource); + SAFE_RELEASE(texture_resource); - return entry; - } + return entry; + } } -void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat src_format, const EFBRectangle& srcRect, - bool scale_by_half, unsigned int cbuf_id, const float* colmat) +void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat src_format, + const EFBRectangle& srcRect, bool scale_by_half, + unsigned int cbuf_id, const float* colmat) { - // When copying at half size, in multisampled mode, resolve the color/depth buffer first. - // This is because multisampled texture reads go through Load, not Sample, and the linear - // filter is ignored. - bool multisampled = (g_ActiveConfig.iMultisamples > 1); - D3DTexture2D* efb_tex = (src_format == PEControl::Z24) ? - FramebufferManager::GetEFBDepthTexture() : - FramebufferManager::GetEFBColorTexture(); - if (multisampled && scale_by_half) - { - multisampled = false; - efb_tex = (src_format == PEControl::Z24) ? - FramebufferManager::GetResolvedEFBDepthTexture() : - FramebufferManager::GetResolvedEFBColorTexture(); - } + // When copying at half size, in multisampled mode, resolve the color/depth buffer first. + // This is because multisampled texture reads go through Load, not Sample, and the linear + // filter is ignored. + bool multisampled = (g_ActiveConfig.iMultisamples > 1); + D3DTexture2D* efb_tex = (src_format == PEControl::Z24) ? + FramebufferManager::GetEFBDepthTexture() : + FramebufferManager::GetEFBColorTexture(); + if (multisampled && scale_by_half) + { + multisampled = false; + efb_tex = (src_format == PEControl::Z24) ? FramebufferManager::GetResolvedEFBDepthTexture() : + FramebufferManager::GetResolvedEFBColorTexture(); + } - // set transformation - if (s_efb_copy_last_cbuf_id != cbuf_id) - { - s_efb_copy_stream_buffer->AllocateSpaceInBuffer(28 * sizeof(float), 256); + // set transformation + if (s_efb_copy_last_cbuf_id != cbuf_id) + { + s_efb_copy_stream_buffer->AllocateSpaceInBuffer(28 * sizeof(float), 256); - memcpy(s_efb_copy_stream_buffer->GetCPUAddressOfCurrentAllocation(), colmat, 28 * sizeof(float)); + memcpy(s_efb_copy_stream_buffer->GetCPUAddressOfCurrentAllocation(), colmat, + 28 * sizeof(float)); - s_efb_copy_last_cbuf_id = cbuf_id; - } + s_efb_copy_last_cbuf_id = cbuf_id; + } - // stretch picture with increased internal resolution - D3D::SetViewportAndScissor(0, 0, config.width, config.height); + // stretch picture with increased internal resolution + D3D::SetViewportAndScissor(0, 0, config.width, config.height); - D3D::current_command_list->SetGraphicsRootConstantBufferView(DESCRIPTOR_TABLE_PS_CBVONE, s_efb_copy_stream_buffer->GetGPUAddressOfCurrentAllocation()); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, true); + D3D::current_command_list->SetGraphicsRootConstantBufferView( + DESCRIPTOR_TABLE_PS_CBVONE, s_efb_copy_stream_buffer->GetGPUAddressOfCurrentAllocation()); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, true); - const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(srcRect); - // EXISTINGD3D11TODO: try targetSource.asRECT(); - const D3D12_RECT sourcerect = CD3DX12_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom); + const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(srcRect); + // EXISTINGD3D11TODO: try targetSource.asRECT(); + const D3D12_RECT sourcerect = + CD3DX12_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom); - // Use linear filtering if (bScaleByHalf), use point filtering otherwise - if (scale_by_half) - D3D::SetLinearCopySampler(); - else - D3D::SetPointCopySampler(); + // Use linear filtering if (bScaleByHalf), use point filtering otherwise + if (scale_by_half) + D3D::SetLinearCopySampler(); + else + D3D::SetPointCopySampler(); - // Make sure we don't draw with the texture set as both a source and target. - // (This can happen because we don't unbind textures when we free them.) + // Make sure we don't draw with the texture set as both a source and target. + // (This can happen because we don't unbind textures when we free them.) - m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - D3D::current_command_list->OMSetRenderTargets(1, &m_texture->GetRTV12(), FALSE, nullptr); + m_texture->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_RENDER_TARGET); + D3D::current_command_list->OMSetRenderTargets(1, &m_texture->GetRTV12(), FALSE, nullptr); - // Create texture copy - D3D::DrawShadedTexQuad( - efb_tex, - &sourcerect, - Renderer::GetTargetWidth(), - Renderer::GetTargetHeight(), - (src_format == PEControl::Z24) ? StaticShaderCache::GetDepthMatrixPixelShader(multisampled) : StaticShaderCache::GetColorMatrixPixelShader(multisampled), - StaticShaderCache::GetSimpleVertexShader(), - StaticShaderCache::GetSimpleVertexShaderInputLayout(), - StaticShaderCache::GetCopyGeometryShader(), - 1.0f, 0, DXGI_FORMAT_R8G8B8A8_UNORM, false, m_texture->GetMultisampled() - ); + // Create texture copy + D3D::DrawShadedTexQuad( + efb_tex, &sourcerect, Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), + (src_format == PEControl::Z24) ? StaticShaderCache::GetDepthMatrixPixelShader(multisampled) : + StaticShaderCache::GetColorMatrixPixelShader(multisampled), + StaticShaderCache::GetSimpleVertexShader(), + StaticShaderCache::GetSimpleVertexShaderInputLayout(), + StaticShaderCache::GetCopyGeometryShader(), 1.0f, 0, DXGI_FORMAT_R8G8B8A8_UNORM, false, + m_texture->GetMultisampled()); - m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + m_texture->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); + FramebufferManager::GetEFBColorTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); - g_renderer->RestoreAPIState(); + g_renderer->RestoreAPIState(); } -void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool isIntensity, bool scaleByHalf) +void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, PEControl::PixelFormat srcFormat, + const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) { - s_encoder->Encode(dst, format, native_width, bytes_per_row, num_blocks_y, memory_stride, srcFormat, srcRect, isIntensity, scaleByHalf); + s_encoder->Encode(dst, format, native_width, bytes_per_row, num_blocks_y, memory_stride, + srcFormat, srcRect, isIntensity, scaleByHalf); } static const constexpr char s_palette_shader_hlsl[] = -R"HLSL( + R"HLSL( sampler samp0 : register(s0); Texture2DArray Tex0 : register(t0); Buffer Tex1 : register(t1); @@ -391,232 +391,248 @@ void main( } )HLSL"; -void TextureCache::ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format) +void TextureCache::ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, + void* palette, TlutFormat format) { - const unsigned int palette_buffer_allocation_size = 512; - m_palette_stream_buffer->AllocateSpaceInBuffer(palette_buffer_allocation_size, 256); - memcpy(m_palette_stream_buffer->GetCPUAddressOfCurrentAllocation(), palette, palette_buffer_allocation_size); + const unsigned int palette_buffer_allocation_size = 512; + m_palette_stream_buffer->AllocateSpaceInBuffer(palette_buffer_allocation_size, 256); + memcpy(m_palette_stream_buffer->GetCPUAddressOfCurrentAllocation(), palette, + palette_buffer_allocation_size); - // stretch picture with increased internal resolution - D3D::SetViewportAndScissor(0, 0, unconverted->config.width, unconverted->config.height); + // stretch picture with increased internal resolution + D3D::SetViewportAndScissor(0, 0, unconverted->config.width, unconverted->config.height); - // D3D12: Because the second SRV slot is occupied by this buffer, and an arbitrary texture occupies the first SRV slot, - // we need to allocate temporary space out of our descriptor heap, place the palette SRV in the second slot, then copy the - // existing texture's descriptor into the first slot. + // D3D12: Because the second SRV slot is occupied by this buffer, and an arbitrary texture + // occupies the first SRV slot, + // we need to allocate temporary space out of our descriptor heap, place the palette SRV in the + // second slot, then copy the + // existing texture's descriptor into the first slot. - // First, allocate the (temporary) space in the descriptor heap. - D3D12_CPU_DESCRIPTOR_HANDLE srv_group_cpu_handle[2] = {}; - D3D12_GPU_DESCRIPTOR_HANDLE srv_group_gpu_handle[2] = {}; - D3D::gpu_descriptor_heap_mgr->AllocateGroup(srv_group_cpu_handle, 2, srv_group_gpu_handle, nullptr, true); + // First, allocate the (temporary) space in the descriptor heap. + D3D12_CPU_DESCRIPTOR_HANDLE srv_group_cpu_handle[2] = {}; + D3D12_GPU_DESCRIPTOR_HANDLE srv_group_gpu_handle[2] = {}; + D3D::gpu_descriptor_heap_mgr->AllocateGroup(srv_group_cpu_handle, 2, srv_group_gpu_handle, + nullptr, true); - srv_group_cpu_handle[1].ptr = srv_group_cpu_handle[0].ptr + D3D::resource_descriptor_size; + srv_group_cpu_handle[1].ptr = srv_group_cpu_handle[0].ptr + D3D::resource_descriptor_size; - // Now, create the palette SRV at the appropriate offset. - D3D12_SHADER_RESOURCE_VIEW_DESC palette_buffer_srv_desc = { - DXGI_FORMAT_R16_UINT, // DXGI_FORMAT Format; - D3D12_SRV_DIMENSION_BUFFER, // D3D12_SRV_DIMENSION ViewDimension; - D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING // UINT Shader4ComponentMapping; - }; + // Now, create the palette SRV at the appropriate offset. + D3D12_SHADER_RESOURCE_VIEW_DESC palette_buffer_srv_desc = { + DXGI_FORMAT_R16_UINT, // DXGI_FORMAT Format; + D3D12_SRV_DIMENSION_BUFFER, // D3D12_SRV_DIMENSION ViewDimension; + D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING // UINT Shader4ComponentMapping; + }; - // Each 'element' is two bytes since format is R16. - palette_buffer_srv_desc.Buffer.FirstElement = m_palette_stream_buffer->GetOffsetOfCurrentAllocation() / sizeof(u16); - palette_buffer_srv_desc.Buffer.NumElements = 256; + // Each 'element' is two bytes since format is R16. + palette_buffer_srv_desc.Buffer.FirstElement = + m_palette_stream_buffer->GetOffsetOfCurrentAllocation() / sizeof(u16); + palette_buffer_srv_desc.Buffer.NumElements = 256; - D3D::device12->CreateShaderResourceView(m_palette_stream_buffer->GetBuffer(), &palette_buffer_srv_desc, srv_group_cpu_handle[1]); + D3D::device12->CreateShaderResourceView(m_palette_stream_buffer->GetBuffer(), + &palette_buffer_srv_desc, srv_group_cpu_handle[1]); - // Now, copy the existing texture's descriptor into the new temporary location. - static_cast(unconverted)->m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - D3D::device12->CopyDescriptorsSimple( - 1, - srv_group_cpu_handle[0], - static_cast(unconverted)->m_texture->GetSRV12GPUCPUShadow(), - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV - ); + // Now, copy the existing texture's descriptor into the new temporary location. + static_cast(unconverted) + ->m_texture->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + D3D::device12->CopyDescriptorsSimple( + 1, srv_group_cpu_handle[0], + static_cast(unconverted)->m_texture->GetSRV12GPUCPUShadow(), + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - // Finally, bind our temporary location. - D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SRV, srv_group_gpu_handle[0]); + // Finally, bind our temporary location. + D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SRV, + srv_group_gpu_handle[0]); - // D3D11EXISTINGTODO: Add support for C14X2 format. (Different multiplier, more palette entries.) + // D3D11EXISTINGTODO: Add support for C14X2 format. (Different multiplier, more palette entries.) - // D3D12: See TextureCache::TextureCache() - because there are only two possible buffer contents here, - // just pre-populate the data in two parts of the same upload heap. - if ((unconverted->format & 0xf) == GX_TF_I4) - { - D3D::current_command_list->SetGraphicsRootConstantBufferView(DESCRIPTOR_TABLE_PS_CBVONE, m_palette_uniform_buffer->GetGPUVirtualAddress()); - } - else - { - D3D::current_command_list->SetGraphicsRootConstantBufferView(DESCRIPTOR_TABLE_PS_CBVONE, m_palette_uniform_buffer->GetGPUVirtualAddress() + 256); - } + // D3D12: See TextureCache::TextureCache() - because there are only two possible buffer contents + // here, + // just pre-populate the data in two parts of the same upload heap. + if ((unconverted->format & 0xf) == GX_TF_I4) + { + D3D::current_command_list->SetGraphicsRootConstantBufferView( + DESCRIPTOR_TABLE_PS_CBVONE, m_palette_uniform_buffer->GetGPUVirtualAddress()); + } + else + { + D3D::current_command_list->SetGraphicsRootConstantBufferView( + DESCRIPTOR_TABLE_PS_CBVONE, m_palette_uniform_buffer->GetGPUVirtualAddress() + 256); + } - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, true); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, true); - const D3D12_RECT source_rect = CD3DX12_RECT(0, 0, unconverted->config.width, unconverted->config.height); + const D3D12_RECT source_rect = + CD3DX12_RECT(0, 0, unconverted->config.width, unconverted->config.height); - D3D::SetPointCopySampler(); + D3D::SetPointCopySampler(); - // Make sure we don't draw with the texture set as both a source and target. - // (This can happen because we don't unbind textures when we free them.) + // Make sure we don't draw with the texture set as both a source and target. + // (This can happen because we don't unbind textures when we free them.) - static_cast(entry)->m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - D3D::current_command_list->OMSetRenderTargets(1, &static_cast(entry)->m_texture->GetRTV12(), FALSE, nullptr); + static_cast(entry)->m_texture->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + D3D::current_command_list->OMSetRenderTargets( + 1, &static_cast(entry)->m_texture->GetRTV12(), FALSE, nullptr); - // Create texture copy - D3D::DrawShadedTexQuad( - static_cast(unconverted)->m_texture, - &source_rect, unconverted->config.width, - unconverted->config.height, - m_palette_pixel_shaders[format], - StaticShaderCache::GetSimpleVertexShader(), - StaticShaderCache::GetSimpleVertexShaderInputLayout(), - StaticShaderCache::GetCopyGeometryShader(), - 1.0f, - 0, - DXGI_FORMAT_R8G8B8A8_UNORM, - true, - static_cast(entry)->m_texture->GetMultisampled() - ); + // Create texture copy + D3D::DrawShadedTexQuad( + static_cast(unconverted)->m_texture, &source_rect, unconverted->config.width, + unconverted->config.height, m_palette_pixel_shaders[format], + StaticShaderCache::GetSimpleVertexShader(), + StaticShaderCache::GetSimpleVertexShaderInputLayout(), + StaticShaderCache::GetCopyGeometryShader(), 1.0f, 0, DXGI_FORMAT_R8G8B8A8_UNORM, true, + static_cast(entry)->m_texture->GetMultisampled()); - static_cast(entry)->m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + static_cast(entry)->m_texture->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE ); + FramebufferManager::GetEFBColorTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); + FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState( + D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); - g_renderer->RestoreAPIState(); + g_renderer->RestoreAPIState(); } D3D12_SHADER_BYTECODE GetConvertShader12(std::string& Type) { - std::string shader = "#define DECODE DecodePixel_"; - shader.append(Type); - shader.append("\n"); - shader.append(s_palette_shader_hlsl); + std::string shader = "#define DECODE DecodePixel_"; + shader.append(Type); + shader.append("\n"); + shader.append(s_palette_shader_hlsl); - ID3DBlob* blob = nullptr; - D3D::CompilePixelShader(shader, &blob); + ID3DBlob* blob = nullptr; + D3D::CompilePixelShader(shader, &blob); - return { blob->GetBufferPointer(), blob->GetBufferSize() }; + return {blob->GetBufferPointer(), blob->GetBufferSize()}; } TextureCache::TextureCache() { - s_encoder = std::make_unique(); - s_encoder->Init(); + s_encoder = std::make_unique(); + s_encoder->Init(); - s_efb_copy_stream_buffer = std::make_unique(1024 * 1024, 1024 * 1024, nullptr); - s_efb_copy_last_cbuf_id = UINT_MAX; + s_efb_copy_stream_buffer = std::make_unique(1024 * 1024, 1024 * 1024, nullptr); + s_efb_copy_last_cbuf_id = UINT_MAX; - s_texture_cache_entry_readback_buffer = nullptr; - s_texture_cache_entry_readback_buffer_size = 0; + s_texture_cache_entry_readback_buffer = nullptr; + s_texture_cache_entry_readback_buffer_size = 0; - m_palette_pixel_shaders[GX_TL_IA8] = GetConvertShader12(std::string("IA8")); - m_palette_pixel_shaders[GX_TL_RGB565] = GetConvertShader12(std::string("RGB565")); - m_palette_pixel_shaders[GX_TL_RGB5A3] = GetConvertShader12(std::string("RGB5A3")); + m_palette_pixel_shaders[GX_TL_IA8] = GetConvertShader12(std::string("IA8")); + m_palette_pixel_shaders[GX_TL_RGB565] = GetConvertShader12(std::string("RGB565")); + m_palette_pixel_shaders[GX_TL_RGB5A3] = GetConvertShader12(std::string("RGB5A3")); - m_palette_stream_buffer = std::make_unique(sizeof(u16) * 256 * 1024, sizeof(u16) * 256 * 1024 * 16, nullptr); + m_palette_stream_buffer = std::make_unique( + sizeof(u16) * 256 * 1024, sizeof(u16) * 256 * 1024 * 16, nullptr); - // Right now, there are only two variants of palette_uniform data. So, we'll just create an upload heap to permanently store both of these. - CheckHR( - D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Buffer(((16 + 255) & ~255) * 2), // Constant Buffers have to be 256b aligned. "* 2" to create for two sets of data. - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(&m_palette_uniform_buffer) - ) - ); + // Right now, there are only two variants of palette_uniform data. So, we'll just create an upload + // heap to permanently store both of these. + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer( + ((16 + 255) & ~255) * + 2), // Constant Buffers have to be 256b aligned. "* 2" to create for two sets of data. + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, IID_PPV_ARGS(&m_palette_uniform_buffer))); - D3D::SetDebugObjectName12(m_palette_uniform_buffer, "a constant buffer used in TextureCache::ConvertTexture"); + D3D::SetDebugObjectName12(m_palette_uniform_buffer, + "a constant buffer used in TextureCache::ConvertTexture"); - // Temporarily repurpose m_palette_stream_buffer as a copy source to populate initial data here. - m_palette_stream_buffer->AllocateSpaceInBuffer(256 * 2, 256); + // Temporarily repurpose m_palette_stream_buffer as a copy source to populate initial data here. + m_palette_stream_buffer->AllocateSpaceInBuffer(256 * 2, 256); - u8* upload_heap_data_location = reinterpret_cast(m_palette_stream_buffer->GetCPUAddressOfCurrentAllocation()); + u8* upload_heap_data_location = + reinterpret_cast(m_palette_stream_buffer->GetCPUAddressOfCurrentAllocation()); - memset(upload_heap_data_location, 0, 256 * 2); + memset(upload_heap_data_location, 0, 256 * 2); - float paramsFormatZero[4] = { 15.f }; - float paramsFormatNonzero[4] = { 255.f }; + float paramsFormatZero[4] = {15.f}; + float paramsFormatNonzero[4] = {255.f}; - memcpy(upload_heap_data_location, paramsFormatZero, sizeof(paramsFormatZero)); - memcpy(upload_heap_data_location + 256, paramsFormatNonzero, sizeof(paramsFormatNonzero)); + memcpy(upload_heap_data_location, paramsFormatZero, sizeof(paramsFormatZero)); + memcpy(upload_heap_data_location + 256, paramsFormatNonzero, sizeof(paramsFormatNonzero)); - D3D::current_command_list->CopyBufferRegion(m_palette_uniform_buffer, 0, m_palette_stream_buffer->GetBuffer(), m_palette_stream_buffer->GetOffsetOfCurrentAllocation(), 256 * 2); + D3D::current_command_list->CopyBufferRegion( + m_palette_uniform_buffer, 0, m_palette_stream_buffer->GetBuffer(), + m_palette_stream_buffer->GetOffsetOfCurrentAllocation(), 256 * 2); - DX12::D3D::ResourceBarrier(D3D::current_command_list, m_palette_uniform_buffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, 0); + DX12::D3D::ResourceBarrier(D3D::current_command_list, m_palette_uniform_buffer, + D3D12_RESOURCE_STATE_COPY_DEST, + D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, 0); } TextureCache::~TextureCache() { - s_encoder->Shutdown(); - s_encoder.reset(); + s_encoder->Shutdown(); + s_encoder.reset(); - s_efb_copy_stream_buffer.reset(); + s_efb_copy_stream_buffer.reset(); - if (s_texture_cache_entry_readback_buffer) - { - // Safe to destroy the readback buffer immediately, as the only time it's used is blocked until completion. - s_texture_cache_entry_readback_buffer->Release(); - s_texture_cache_entry_readback_buffer = nullptr; - s_texture_cache_entry_readback_buffer_size = 0; - } + if (s_texture_cache_entry_readback_buffer) + { + // Safe to destroy the readback buffer immediately, as the only time it's used is blocked until + // completion. + s_texture_cache_entry_readback_buffer->Release(); + s_texture_cache_entry_readback_buffer = nullptr; + s_texture_cache_entry_readback_buffer_size = 0; + } - D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_palette_uniform_buffer); + D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_palette_uniform_buffer); } void TextureCache::BindTextures() { - unsigned int last_texture = 0; - for (unsigned int i = 0; i < 8; ++i) - { - if (bound_textures[i] != nullptr) - { - last_texture = i; - } - } + unsigned int last_texture = 0; + for (unsigned int i = 0; i < 8; ++i) + { + if (bound_textures[i] != nullptr) + { + last_texture = i; + } + } - if (last_texture == 0 && bound_textures[0] != nullptr) - { - DX12::D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SRV, reinterpret_cast(bound_textures[0])->m_texture_srv_gpu_handle); - return; - } + if (last_texture == 0 && bound_textures[0] != nullptr) + { + DX12::D3D::current_command_list->SetGraphicsRootDescriptorTable( + DESCRIPTOR_TABLE_PS_SRV, + reinterpret_cast(bound_textures[0])->m_texture_srv_gpu_handle); + return; + } - // If more than one texture, allocate space for group. - D3D12_CPU_DESCRIPTOR_HANDLE s_group_base_texture_cpu_handle; - D3D12_GPU_DESCRIPTOR_HANDLE s_group_base_texture_gpu_handle; - DX12::D3D::gpu_descriptor_heap_mgr->AllocateGroup(&s_group_base_texture_cpu_handle, 8, &s_group_base_texture_gpu_handle, nullptr, true); + // If more than one texture, allocate space for group. + D3D12_CPU_DESCRIPTOR_HANDLE s_group_base_texture_cpu_handle; + D3D12_GPU_DESCRIPTOR_HANDLE s_group_base_texture_gpu_handle; + DX12::D3D::gpu_descriptor_heap_mgr->AllocateGroup( + &s_group_base_texture_cpu_handle, 8, &s_group_base_texture_gpu_handle, nullptr, true); - for (unsigned int stage = 0; stage < 8; stage++) - { - if (bound_textures[stage] != nullptr) - { - D3D12_CPU_DESCRIPTOR_HANDLE textureDestDescriptor; - textureDestDescriptor.ptr = s_group_base_texture_cpu_handle.ptr + stage * D3D::resource_descriptor_size; + for (unsigned int stage = 0; stage < 8; stage++) + { + if (bound_textures[stage] != nullptr) + { + D3D12_CPU_DESCRIPTOR_HANDLE textureDestDescriptor; + textureDestDescriptor.ptr = + s_group_base_texture_cpu_handle.ptr + stage * D3D::resource_descriptor_size; - DX12::D3D::device12->CopyDescriptorsSimple( - 1, - textureDestDescriptor, - reinterpret_cast(bound_textures[stage])->m_texture_srv_gpu_handle_cpu_shadow, - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV - ); - } - else - { - D3D12_CPU_DESCRIPTOR_HANDLE nullDestDescriptor; - nullDestDescriptor.ptr = s_group_base_texture_cpu_handle.ptr + stage * D3D::resource_descriptor_size; + DX12::D3D::device12->CopyDescriptorsSimple( + 1, textureDestDescriptor, reinterpret_cast(bound_textures[stage]) + ->m_texture_srv_gpu_handle_cpu_shadow, + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + } + else + { + D3D12_CPU_DESCRIPTOR_HANDLE nullDestDescriptor; + nullDestDescriptor.ptr = + s_group_base_texture_cpu_handle.ptr + stage * D3D::resource_descriptor_size; - DX12::D3D::device12->CopyDescriptorsSimple( - 1, - nullDestDescriptor, - DX12::D3D::null_srv_cpu_shadow, - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV - ); - } - } + DX12::D3D::device12->CopyDescriptorsSimple(1, nullDestDescriptor, + DX12::D3D::null_srv_cpu_shadow, + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + } + } - // Actually bind the textures. - DX12::D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SRV, s_group_base_texture_gpu_handle); + // Actually bind the textures. + DX12::D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SRV, + s_group_base_texture_gpu_handle); } - } diff --git a/Source/Core/VideoBackends/D3D12/TextureCache.h b/Source/Core/VideoBackends/D3D12/TextureCache.h index 3747cd9e0c..4cce8a75b0 100644 --- a/Source/Core/VideoBackends/D3D12/TextureCache.h +++ b/Source/Core/VideoBackends/D3D12/TextureCache.h @@ -11,60 +11,65 @@ namespace DX12 { - class D3DStreamBuffer; class TextureCache final : public TextureCacheBase { public: - TextureCache(); - ~TextureCache(); + TextureCache(); + ~TextureCache(); - virtual void BindTextures(); + virtual void BindTextures(); private: - struct TCacheEntry : TCacheEntryBase - { - D3DTexture2D* const m_texture = nullptr; - D3D12_CPU_DESCRIPTOR_HANDLE m_texture_srv_cpu_handle = {}; - D3D12_GPU_DESCRIPTOR_HANDLE m_texture_srv_gpu_handle = {}; - D3D12_CPU_DESCRIPTOR_HANDLE m_texture_srv_gpu_handle_cpu_shadow = {}; + struct TCacheEntry : TCacheEntryBase + { + D3DTexture2D* const m_texture = nullptr; + D3D12_CPU_DESCRIPTOR_HANDLE m_texture_srv_cpu_handle = {}; + D3D12_GPU_DESCRIPTOR_HANDLE m_texture_srv_gpu_handle = {}; + D3D12_CPU_DESCRIPTOR_HANDLE m_texture_srv_gpu_handle_cpu_shadow = {}; - TCacheEntry(const TCacheEntryConfig& config, D3DTexture2D* tex) : TCacheEntryBase(config), m_texture(tex) {} - ~TCacheEntry(); + TCacheEntry(const TCacheEntryConfig& config, D3DTexture2D* tex) + : TCacheEntryBase(config), m_texture(tex) + { + } + ~TCacheEntry(); - void CopyRectangleFromTexture( - const TCacheEntryBase* source, - const MathUtil::Rectangle &src_rect, - const MathUtil::Rectangle &dst_rect) override; + void CopyRectangleFromTexture(const TCacheEntryBase* source, + const MathUtil::Rectangle& src_rect, + const MathUtil::Rectangle& dst_rect) override; - void Load(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int levels) override; + void Load(unsigned int width, unsigned int height, unsigned int expanded_width, + unsigned int levels) override; - void FromRenderTarget(u8* dst, PEControl::PixelFormat src_format, const EFBRectangle& src_rect, - bool scale_by_half, unsigned int cbuf_id, const float* colmat) override; + void FromRenderTarget(u8* dst, PEControl::PixelFormat src_format, const EFBRectangle& src_rect, + bool scale_by_half, unsigned int cbuf_id, const float* colmat) override; - void Bind(unsigned int stage) override; - bool Save(const std::string& filename, unsigned int level) override; - }; + void Bind(unsigned int stage) override; + bool Save(const std::string& filename, unsigned int level) override; + }; - TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) override; + TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) override; - u64 EncodeToRamFromTexture(u32 address, void* source_texture, u32 source_width, u32 source_height, bool is_from_z_buffer, bool is_intensity_format, u32 copy_format, int scale_by_half, const EFBRectangle& source) {return 0;}; + u64 EncodeToRamFromTexture(u32 address, void* source_texture, u32 source_width, u32 source_height, + bool is_from_z_buffer, bool is_intensity_format, u32 copy_format, + int scale_by_half, const EFBRectangle& source) + { + return 0; + }; - void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format) override; + void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, + TlutFormat format) override; - void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat src_format, const EFBRectangle& src_rect, - bool is_intensity, bool scale_by_half) override; + void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, + u32 memory_stride, PEControl::PixelFormat src_format, const EFBRectangle& src_rect, + bool is_intensity, bool scale_by_half) override; - void CompileShaders() override { } - void DeleteShaders() override { } + void CompileShaders() override {} + void DeleteShaders() override {} + std::unique_ptr m_palette_stream_buffer; - std::unique_ptr m_palette_stream_buffer; - - ID3D12Resource* m_palette_uniform_buffer = nullptr; - D3D12_SHADER_BYTECODE m_palette_pixel_shaders[3] = {}; + ID3D12Resource* m_palette_uniform_buffer = nullptr; + D3D12_SHADER_BYTECODE m_palette_pixel_shaders[3] = {}; }; - } diff --git a/Source/Core/VideoBackends/D3D12/TextureEncoder.h b/Source/Core/VideoBackends/D3D12/TextureEncoder.h index 346f87d79f..968815513a 100644 --- a/Source/Core/VideoBackends/D3D12/TextureEncoder.h +++ b/Source/Core/VideoBackends/D3D12/TextureEncoder.h @@ -19,14 +19,12 @@ static constexpr unsigned int MAX_BYTES_PER_ENCODE = MAX_BYTES_PER_BLOCK_ROW * ( class TextureEncoder { public: - virtual ~TextureEncoder() { } - - virtual void Init() = 0; - virtual void Shutdown() = 0; - // Returns size in bytes of encoded block of memory - virtual void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat src_format, const EFBRectangle& src_rect, - bool is_intensity, bool scale_by_half) = 0; + virtual ~TextureEncoder() {} + virtual void Init() = 0; + virtual void Shutdown() = 0; + // Returns size in bytes of encoded block of memory + virtual void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, + u32 memory_stride, PEControl::PixelFormat src_format, + const EFBRectangle& src_rect, bool is_intensity, bool scale_by_half) = 0; }; - } diff --git a/Source/Core/VideoBackends/D3D12/VertexManager.cpp b/Source/Core/VideoBackends/D3D12/VertexManager.cpp index 9f22cc56eb..d6265ae725 100644 --- a/Source/Core/VideoBackends/D3D12/VertexManager.cpp +++ b/Source/Core/VideoBackends/D3D12/VertexManager.cpp @@ -24,187 +24,197 @@ namespace DX12 { - static constexpr unsigned int MAX_IBUFFER_SIZE = VertexManager::MAXIBUFFERSIZE * sizeof(u16) * 16; static constexpr unsigned int MAX_VBUFFER_SIZE = VertexManager::MAXVBUFFERSIZE * 4; void VertexManager::SetIndexBuffer() { - D3D12_INDEX_BUFFER_VIEW ib_view = { - m_index_stream_buffer->GetBaseGPUAddress(), // D3D12_GPU_VIRTUAL_ADDRESS BufferLocation; - static_cast(m_index_stream_buffer->GetSize()), // UINT SizeInBytes; - DXGI_FORMAT_R16_UINT // DXGI_FORMAT Format; - }; + D3D12_INDEX_BUFFER_VIEW ib_view = { + m_index_stream_buffer->GetBaseGPUAddress(), // D3D12_GPU_VIRTUAL_ADDRESS BufferLocation; + static_cast(m_index_stream_buffer->GetSize()), // UINT SizeInBytes; + DXGI_FORMAT_R16_UINT // DXGI_FORMAT Format; + }; - D3D::current_command_list->IASetIndexBuffer(&ib_view); + D3D::current_command_list->IASetIndexBuffer(&ib_view); } void VertexManager::CreateDeviceObjects() { - m_vertex_draw_offset = 0; - m_index_draw_offset = 0; + m_vertex_draw_offset = 0; + m_index_draw_offset = 0; - m_vertex_stream_buffer = std::make_unique(MAXVBUFFERSIZE * 2, MAX_VBUFFER_SIZE, &m_vertex_stream_buffer_reallocated); - m_index_stream_buffer = std::make_unique(MAXIBUFFERSIZE * sizeof(u16) * 2, MAXIBUFFERSIZE * sizeof(u16) * 16, &m_index_stream_buffer_reallocated); + m_vertex_stream_buffer = std::make_unique(MAXVBUFFERSIZE * 2, MAX_VBUFFER_SIZE, + &m_vertex_stream_buffer_reallocated); + m_index_stream_buffer = std::make_unique(MAXIBUFFERSIZE * sizeof(u16) * 2, + MAXIBUFFERSIZE * sizeof(u16) * 16, + &m_index_stream_buffer_reallocated); - SetIndexBuffer(); + SetIndexBuffer(); - // Use CPU-only memory if the GPU won't be reading from the buffers, - // since reading upload heaps on the CPU is slow.. - m_vertex_cpu_buffer.resize(MAXVBUFFERSIZE); - m_index_cpu_buffer.resize(MAXIBUFFERSIZE); + // Use CPU-only memory if the GPU won't be reading from the buffers, + // since reading upload heaps on the CPU is slow.. + m_vertex_cpu_buffer.resize(MAXVBUFFERSIZE); + m_index_cpu_buffer.resize(MAXIBUFFERSIZE); } void VertexManager::DestroyDeviceObjects() { - m_vertex_stream_buffer.reset(); - m_index_stream_buffer.reset(); + m_vertex_stream_buffer.reset(); + m_index_stream_buffer.reset(); - m_vertex_cpu_buffer.clear(); - m_index_cpu_buffer.clear(); + m_vertex_cpu_buffer.clear(); + m_index_cpu_buffer.clear(); } VertexManager::VertexManager() { - CreateDeviceObjects(); + CreateDeviceObjects(); } VertexManager::~VertexManager() { - DestroyDeviceObjects(); + DestroyDeviceObjects(); } void VertexManager::PrepareDrawBuffers(u32 stride) { - u32 vertex_data_size = IndexGenerator::GetNumVerts() * stride; - u32 index_data_size = IndexGenerator::GetIndexLen() * sizeof(u16); + u32 vertex_data_size = IndexGenerator::GetNumVerts() * stride; + u32 index_data_size = IndexGenerator::GetIndexLen() * sizeof(u16); - m_vertex_stream_buffer->OverrideSizeOfPreviousAllocation(vertex_data_size); - m_index_stream_buffer->OverrideSizeOfPreviousAllocation(index_data_size); + m_vertex_stream_buffer->OverrideSizeOfPreviousAllocation(vertex_data_size); + m_index_stream_buffer->OverrideSizeOfPreviousAllocation(index_data_size); - ADDSTAT(stats.thisFrame.bytesVertexStreamed, vertex_data_size); - ADDSTAT(stats.thisFrame.bytesIndexStreamed, index_data_size); + ADDSTAT(stats.thisFrame.bytesVertexStreamed, vertex_data_size); + ADDSTAT(stats.thisFrame.bytesIndexStreamed, index_data_size); } void VertexManager::Draw(u32 stride) { - static u32 s_previous_stride = UINT_MAX; + static u32 s_previous_stride = UINT_MAX; - u32 indices = IndexGenerator::GetIndexLen(); + u32 indices = IndexGenerator::GetIndexLen(); - if (D3D::command_list_mgr->GetCommandListDirtyState(COMMAND_LIST_STATE_VERTEX_BUFFER) || s_previous_stride != stride) - { - D3D12_VERTEX_BUFFER_VIEW vb_view = { - m_vertex_stream_buffer->GetBaseGPUAddress(), // D3D12_GPU_VIRTUAL_ADDRESS BufferLocation; - static_cast(m_vertex_stream_buffer->GetSize()), // UINT SizeInBytes; - stride // UINT StrideInBytes; - }; + if (D3D::command_list_mgr->GetCommandListDirtyState(COMMAND_LIST_STATE_VERTEX_BUFFER) || + s_previous_stride != stride) + { + D3D12_VERTEX_BUFFER_VIEW vb_view = { + m_vertex_stream_buffer->GetBaseGPUAddress(), // D3D12_GPU_VIRTUAL_ADDRESS BufferLocation; + static_cast(m_vertex_stream_buffer->GetSize()), // UINT SizeInBytes; + stride // UINT StrideInBytes; + }; - D3D::current_command_list->IASetVertexBuffers(0, 1, &vb_view); + D3D::current_command_list->IASetVertexBuffers(0, 1, &vb_view); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_VERTEX_BUFFER, false); - s_previous_stride = stride; - } + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_VERTEX_BUFFER, false); + s_previous_stride = stride; + } - D3D_PRIMITIVE_TOPOLOGY d3d_primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; + D3D_PRIMITIVE_TOPOLOGY d3d_primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; - switch (current_primitive_type) - { - case PRIMITIVE_POINTS: - d3d_primitive_topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST; - break; - case PRIMITIVE_LINES: - d3d_primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; - break; - } + switch (current_primitive_type) + { + case PRIMITIVE_POINTS: + d3d_primitive_topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST; + break; + case PRIMITIVE_LINES: + d3d_primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; + break; + } - if (D3D::command_list_mgr->GetCommandListPrimitiveTopology() != d3d_primitive_topology) - { - D3D::current_command_list->IASetPrimitiveTopology(d3d_primitive_topology); - D3D::command_list_mgr->SetCommandListPrimitiveTopology(d3d_primitive_topology); - } + if (D3D::command_list_mgr->GetCommandListPrimitiveTopology() != d3d_primitive_topology) + { + D3D::current_command_list->IASetPrimitiveTopology(d3d_primitive_topology); + D3D::command_list_mgr->SetCommandListPrimitiveTopology(d3d_primitive_topology); + } - u32 base_vertex = m_vertex_draw_offset / stride; - u32 start_index = m_index_draw_offset / sizeof(u16); + u32 base_vertex = m_vertex_draw_offset / stride; + u32 start_index = m_index_draw_offset / sizeof(u16); - D3D::current_command_list->DrawIndexedInstanced(indices, 1, start_index, base_vertex, 0); + D3D::current_command_list->DrawIndexedInstanced(indices, 1, start_index, base_vertex, 0); - INCSTAT(stats.thisFrame.numDrawCalls); + INCSTAT(stats.thisFrame.numDrawCalls); } void VertexManager::vFlush(bool use_dst_alpha) { - ShaderCache::LoadAndSetActiveShaders(use_dst_alpha ? DSTALPHA_DUAL_SOURCE_BLEND : DSTALPHA_NONE, current_primitive_type); + ShaderCache::LoadAndSetActiveShaders(use_dst_alpha ? DSTALPHA_DUAL_SOURCE_BLEND : DSTALPHA_NONE, + current_primitive_type); - if (g_ActiveConfig.backend_info.bSupportsBBox && BoundingBox::active) - BBox::Invalidate(); + if (g_ActiveConfig.backend_info.bSupportsBBox && BoundingBox::active) + BBox::Invalidate(); - u32 stride = VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride(); + u32 stride = VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride(); - PrepareDrawBuffers(stride); + PrepareDrawBuffers(stride); - g_renderer->ApplyState(use_dst_alpha); + g_renderer->ApplyState(use_dst_alpha); - Draw(stride); + Draw(stride); - D3D::command_list_mgr->m_draws_since_last_execution++; + D3D::command_list_mgr->m_draws_since_last_execution++; - // Many Gamecube/Wii titles read from the EFB each frame to determine what new rendering work to submit, e.g. where sun rays are - // occluded and where they aren't. When the CPU wants to read this data (done in Renderer::AccessEFB), it requires that the GPU - // finish all oustanding work. As an optimization, when we detect that the CPU is likely to read back data this frame, we break - // up the rendering work and submit it more frequently to the GPU (via ExecuteCommandList). Thus, when the CPU finally needs the - // the GPU to finish all of its work, there is (hopefully) less work outstanding to wait on at that moment. + // Many Gamecube/Wii titles read from the EFB each frame to determine what new rendering work to + // submit, e.g. where sun rays are + // occluded and where they aren't. When the CPU wants to read this data (done in + // Renderer::AccessEFB), it requires that the GPU + // finish all oustanding work. As an optimization, when we detect that the CPU is likely to read + // back data this frame, we break + // up the rendering work and submit it more frequently to the GPU (via ExecuteCommandList). Thus, + // when the CPU finally needs the + // the GPU to finish all of its work, there is (hopefully) less work outstanding to wait on at + // that moment. - // D3D12TODO: Decide right threshold for drawCountSinceAsyncFlush at runtime depending on - // amount of stall measured in AccessEFB. + // D3D12TODO: Decide right threshold for drawCountSinceAsyncFlush at runtime depending on + // amount of stall measured in AccessEFB. - // We can't do this with perf queries enabled since it can leave queries open. + // We can't do this with perf queries enabled since it can leave queries open. - if (D3D::command_list_mgr->m_cpu_access_last_frame && - D3D::command_list_mgr->m_draws_since_last_execution > 100 && - !PerfQueryBase::ShouldEmulate()) - { - D3D::command_list_mgr->m_draws_since_last_execution = 0; + if (D3D::command_list_mgr->m_cpu_access_last_frame && + D3D::command_list_mgr->m_draws_since_last_execution > 100 && !PerfQueryBase::ShouldEmulate()) + { + D3D::command_list_mgr->m_draws_since_last_execution = 0; - D3D::command_list_mgr->ExecuteQueuedWork(); - } + D3D::command_list_mgr->ExecuteQueuedWork(); + } } void VertexManager::ResetBuffer(u32 stride) { - if (s_cull_all) - { - s_pCurBufferPointer = m_vertex_cpu_buffer.data(); - s_pBaseBufferPointer = m_vertex_cpu_buffer.data(); - s_pEndBufferPointer = m_vertex_cpu_buffer.data() + MAXVBUFFERSIZE; + if (s_cull_all) + { + s_pCurBufferPointer = m_vertex_cpu_buffer.data(); + s_pBaseBufferPointer = m_vertex_cpu_buffer.data(); + s_pEndBufferPointer = m_vertex_cpu_buffer.data() + MAXVBUFFERSIZE; - IndexGenerator::Start(reinterpret_cast(m_index_cpu_buffer.data())); - return; - } + IndexGenerator::Start(reinterpret_cast(m_index_cpu_buffer.data())); + return; + } - m_vertex_stream_buffer->AllocateSpaceInBuffer(MAXVBUFFERSIZE, stride); + m_vertex_stream_buffer->AllocateSpaceInBuffer(MAXVBUFFERSIZE, stride); - if (m_vertex_stream_buffer_reallocated) - { - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_VERTEX_BUFFER, true); - m_vertex_stream_buffer_reallocated = false; - } + if (m_vertex_stream_buffer_reallocated) + { + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_VERTEX_BUFFER, true); + m_vertex_stream_buffer_reallocated = false; + } - s_pBaseBufferPointer = static_cast(m_vertex_stream_buffer->GetBaseCPUAddress()); - s_pEndBufferPointer = s_pBaseBufferPointer + m_vertex_stream_buffer->GetSize(); - s_pCurBufferPointer = static_cast(m_vertex_stream_buffer->GetCPUAddressOfCurrentAllocation()); - m_vertex_draw_offset = static_cast(m_vertex_stream_buffer->GetOffsetOfCurrentAllocation()); + s_pBaseBufferPointer = static_cast(m_vertex_stream_buffer->GetBaseCPUAddress()); + s_pEndBufferPointer = s_pBaseBufferPointer + m_vertex_stream_buffer->GetSize(); + s_pCurBufferPointer = + static_cast(m_vertex_stream_buffer->GetCPUAddressOfCurrentAllocation()); + m_vertex_draw_offset = static_cast(m_vertex_stream_buffer->GetOffsetOfCurrentAllocation()); - m_index_stream_buffer->AllocateSpaceInBuffer(MAXIBUFFERSIZE * sizeof(u16), sizeof(u16)); + m_index_stream_buffer->AllocateSpaceInBuffer(MAXIBUFFERSIZE * sizeof(u16), sizeof(u16)); - if (m_index_stream_buffer_reallocated) - { - SetIndexBuffer(); - m_index_stream_buffer_reallocated = false; - } + if (m_index_stream_buffer_reallocated) + { + SetIndexBuffer(); + m_index_stream_buffer_reallocated = false; + } - m_index_draw_offset = static_cast(m_index_stream_buffer->GetOffsetOfCurrentAllocation()); - IndexGenerator::Start(static_cast(m_index_stream_buffer->GetCPUAddressOfCurrentAllocation())); + m_index_draw_offset = static_cast(m_index_stream_buffer->GetOffsetOfCurrentAllocation()); + IndexGenerator::Start( + static_cast(m_index_stream_buffer->GetCPUAddressOfCurrentAllocation())); } } // namespace diff --git a/Source/Core/VideoBackends/D3D12/VertexManager.h b/Source/Core/VideoBackends/D3D12/VertexManager.h index 4deac9f897..8fbcf4102e 100644 --- a/Source/Core/VideoBackends/D3D12/VertexManager.h +++ b/Source/Core/VideoBackends/D3D12/VertexManager.h @@ -9,40 +9,39 @@ namespace DX12 { - class D3DStreamBuffer; class VertexManager final : public VertexManagerBase { public: - VertexManager(); - ~VertexManager(); + VertexManager(); + ~VertexManager(); - NativeVertexFormat* CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override; - void CreateDeviceObjects() override; - void DestroyDeviceObjects() override; + NativeVertexFormat* CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override; + void CreateDeviceObjects() override; + void DestroyDeviceObjects() override; - void SetIndexBuffer(); + void SetIndexBuffer(); protected: - void ResetBuffer(u32 stride) override; + void ResetBuffer(u32 stride) override; private: - void PrepareDrawBuffers(u32 stride); - void Draw(u32 stride); - void vFlush(bool use_dst_alpha) override; + void PrepareDrawBuffers(u32 stride); + void Draw(u32 stride); + void vFlush(bool use_dst_alpha) override; - u32 m_vertex_draw_offset; - u32 m_index_draw_offset; + u32 m_vertex_draw_offset; + u32 m_index_draw_offset; - std::unique_ptr m_vertex_stream_buffer; - std::unique_ptr m_index_stream_buffer; + std::unique_ptr m_vertex_stream_buffer; + std::unique_ptr m_index_stream_buffer; - bool m_vertex_stream_buffer_reallocated = false; - bool m_index_stream_buffer_reallocated = false; + bool m_vertex_stream_buffer_reallocated = false; + bool m_index_stream_buffer_reallocated = false; - std::vector m_index_cpu_buffer; - std::vector m_vertex_cpu_buffer; + std::vector m_index_cpu_buffer; + std::vector m_vertex_cpu_buffer; }; } // namespace diff --git a/Source/Core/VideoBackends/D3D12/VideoBackend.h b/Source/Core/VideoBackends/D3D12/VideoBackend.h index 168ac93351..9fbf639238 100644 --- a/Source/Core/VideoBackends/D3D12/VideoBackend.h +++ b/Source/Core/VideoBackends/D3D12/VideoBackend.h @@ -9,25 +9,22 @@ namespace DX12 { - class VideoBackend : public VideoBackendBase { - bool Initialize(void*) override; - void Shutdown() override; + bool Initialize(void*) override; + void Shutdown() override; - std::string GetName() const override; - std::string GetDisplayName() const override; + std::string GetName() const override; + std::string GetDisplayName() const override; - void Video_Prepare() override; - void Video_Cleanup() override; + void Video_Prepare() override; + void Video_Cleanup() override; - void ShowConfig(void* parent) override; + void ShowConfig(void* parent) override; - unsigned int PeekMessages() override; + unsigned int PeekMessages() override; private: - void* m_window_handle; + void* m_window_handle; }; - } - diff --git a/Source/Core/VideoBackends/D3D12/XFBEncoder.cpp b/Source/Core/VideoBackends/D3D12/XFBEncoder.cpp index 670cda05e2..a2b2bc1998 100644 --- a/Source/Core/VideoBackends/D3D12/XFBEncoder.cpp +++ b/Source/Core/VideoBackends/D3D12/XFBEncoder.cpp @@ -2,9 +2,10 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoBackends/D3D12/XFBEncoder.h" #include "Common/CommonTypes.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "VideoBackends/D3D12/D3DBase.h" #include "VideoBackends/D3D12/D3DCommandListManager.h" #include "VideoBackends/D3D12/D3DShader.h" @@ -13,173 +14,183 @@ #include "VideoBackends/D3D12/FramebufferManager.h" #include "VideoBackends/D3D12/Render.h" #include "VideoBackends/D3D12/StaticShaderCache.h" -#include "VideoBackends/D3D12/XFBEncoder.h" namespace DX12 { - // YUYV data is packed into half-width RGBA, with Y values in (R,B) and UV in (G,A) constexpr size_t XFB_TEXTURE_WIDTH = MAX_XFB_WIDTH / 2; constexpr size_t XFB_TEXTURE_HEIGHT = MAX_XFB_HEIGHT; // Buffer enough space for 2 XFB buffers (our frame latency) -constexpr size_t XFB_UPLOAD_BUFFER_SIZE = D3D::AlignValue(XFB_TEXTURE_WIDTH * sizeof(u32), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * XFB_TEXTURE_HEIGHT * 2; +constexpr size_t XFB_UPLOAD_BUFFER_SIZE = + D3D::AlignValue(XFB_TEXTURE_WIDTH * sizeof(u32), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * + XFB_TEXTURE_HEIGHT * 2; constexpr size_t XFB_ENCODER_PARAMS_BUFFER_SIZE = 64 * 1024; std::unique_ptr g_xfb_encoder; XFBEncoder::XFBEncoder() { - ID3D12Resource* texture; + ID3D12Resource* texture; - CheckHR(D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, XFB_TEXTURE_WIDTH, XFB_TEXTURE_HEIGHT, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET), - D3D12_RESOURCE_STATE_RENDER_TARGET, - nullptr, - IID_PPV_ARGS(&texture))); + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, XFB_TEXTURE_WIDTH, + XFB_TEXTURE_HEIGHT, 1, 1, 1, 0, + D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET), + D3D12_RESOURCE_STATE_RENDER_TARGET, nullptr, IID_PPV_ARGS(&texture))); - m_yuyv_texture = new D3DTexture2D(texture, - TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, - DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM); - SAFE_RELEASE(texture); + m_yuyv_texture = + new D3DTexture2D(texture, TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, + DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM); + SAFE_RELEASE(texture); - CheckHR(D3D::device12->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Buffer(D3D::AlignValue(XFB_TEXTURE_WIDTH * sizeof(u32), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * MAX_XFB_HEIGHT), - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(&m_readback_buffer))); + CheckHR(D3D::device12->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer( + D3D::AlignValue(XFB_TEXTURE_WIDTH * sizeof(u32), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * + MAX_XFB_HEIGHT), + D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_readback_buffer))); - m_upload_buffer = std::make_unique(XFB_UPLOAD_BUFFER_SIZE, XFB_UPLOAD_BUFFER_SIZE, nullptr); - m_encode_params_buffer = std::make_unique(XFB_ENCODER_PARAMS_BUFFER_SIZE, XFB_ENCODER_PARAMS_BUFFER_SIZE, nullptr); + m_upload_buffer = + std::make_unique(XFB_UPLOAD_BUFFER_SIZE, XFB_UPLOAD_BUFFER_SIZE, nullptr); + m_encode_params_buffer = std::make_unique( + XFB_ENCODER_PARAMS_BUFFER_SIZE, XFB_ENCODER_PARAMS_BUFFER_SIZE, nullptr); } XFBEncoder::~XFBEncoder() { - SAFE_RELEASE(m_yuyv_texture); - SAFE_RELEASE(m_readback_buffer); + SAFE_RELEASE(m_yuyv_texture); + SAFE_RELEASE(m_readback_buffer); } void XFBEncoder::EncodeTextureToRam(u8* dst, u32 dst_pitch, u32 dst_height, - D3DTexture2D* src_texture, const TargetRectangle& src_rect, - u32 src_width, u32 src_height, float gamma) + D3DTexture2D* src_texture, const TargetRectangle& src_rect, + u32 src_width, u32 src_height, float gamma) { - // src_rect is in native coordinates - // dst_pitch is in words - u32 dst_width = dst_pitch / 2; - u32 dst_texture_width = dst_width / 2; - _assert_msg_(VIDEO, dst_width <= MAX_XFB_WIDTH && dst_height <= MAX_XFB_HEIGHT, "XFB destination does not exceed maximum size"); + // src_rect is in native coordinates + // dst_pitch is in words + u32 dst_width = dst_pitch / 2; + u32 dst_texture_width = dst_width / 2; + _assert_msg_(VIDEO, dst_width <= MAX_XFB_WIDTH && dst_height <= MAX_XFB_HEIGHT, + "XFB destination does not exceed maximum size"); - // Encode parameters constant buffer used by shader - struct EncodeParameters - { - float srcRect[4]; - float texelSize[2]; - float pad[2]; - }; - EncodeParameters parameters = - { - { - static_cast(src_rect.left) / static_cast(src_width), - static_cast(src_rect.top) / static_cast(src_height), - static_cast(src_rect.right) / static_cast(src_width), - static_cast(src_rect.bottom) / static_cast(src_height) - }, - { - 1.0f / EFB_WIDTH, - 1.0f / EFB_HEIGHT - }, - { - 0.0f, - 0.0f - } - }; - m_encode_params_buffer->AllocateSpaceInBuffer(sizeof(parameters), D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); - memcpy(m_encode_params_buffer->GetCPUAddressOfCurrentAllocation(), ¶meters, sizeof(parameters)); + // Encode parameters constant buffer used by shader + struct EncodeParameters + { + float srcRect[4]; + float texelSize[2]; + float pad[2]; + }; + EncodeParameters parameters = { + {static_cast(src_rect.left) / static_cast(src_width), + static_cast(src_rect.top) / static_cast(src_height), + static_cast(src_rect.right) / static_cast(src_width), + static_cast(src_rect.bottom) / static_cast(src_height)}, + {1.0f / EFB_WIDTH, 1.0f / EFB_HEIGHT}, + {0.0f, 0.0f}}; + m_encode_params_buffer->AllocateSpaceInBuffer(sizeof(parameters), + D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); + memcpy(m_encode_params_buffer->GetCPUAddressOfCurrentAllocation(), ¶meters, + sizeof(parameters)); - // Convert RGBA texture to YUYV intermediate texture. - // Performs downscaling through a linear filter. Probably not ideal, but it's not going to look perfect anyway. - CD3DX12_RECT src_texture_rect(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom); - D3D12_RESOURCE_STATES src_texture_state = src_texture->GetResourceUsageState(); - m_yuyv_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - D3D::current_command_list->OMSetRenderTargets(1, &m_yuyv_texture->GetRTV12(), FALSE, nullptr); - D3D::current_command_list->SetGraphicsRootConstantBufferView(DESCRIPTOR_TABLE_PS_CBVONE, m_encode_params_buffer->GetGPUAddressOfCurrentAllocation()); - D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, true); - D3D::SetViewportAndScissor(0, 0, dst_texture_width, dst_height); - D3D::SetLinearCopySampler(); - D3D::DrawShadedTexQuad( - src_texture, &src_texture_rect, src_rect.GetWidth(), src_rect.GetHeight(), - StaticShaderCache::GetXFBEncodePixelShader(), StaticShaderCache::GetSimpleVertexShader(), StaticShaderCache::GetSimpleVertexShaderInputLayout(), - {}, gamma, 0, DXGI_FORMAT_R8G8B8A8_UNORM, false, false); + // Convert RGBA texture to YUYV intermediate texture. + // Performs downscaling through a linear filter. Probably not ideal, but it's not going to look + // perfect anyway. + CD3DX12_RECT src_texture_rect(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom); + D3D12_RESOURCE_STATES src_texture_state = src_texture->GetResourceUsageState(); + m_yuyv_texture->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_RENDER_TARGET); + D3D::current_command_list->OMSetRenderTargets(1, &m_yuyv_texture->GetRTV12(), FALSE, nullptr); + D3D::current_command_list->SetGraphicsRootConstantBufferView( + DESCRIPTOR_TABLE_PS_CBVONE, m_encode_params_buffer->GetGPUAddressOfCurrentAllocation()); + D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, true); + D3D::SetViewportAndScissor(0, 0, dst_texture_width, dst_height); + D3D::SetLinearCopySampler(); + D3D::DrawShadedTexQuad(src_texture, &src_texture_rect, src_rect.GetWidth(), src_rect.GetHeight(), + StaticShaderCache::GetXFBEncodePixelShader(), + StaticShaderCache::GetSimpleVertexShader(), + StaticShaderCache::GetSimpleVertexShaderInputLayout(), {}, gamma, 0, + DXGI_FORMAT_R8G8B8A8_UNORM, false, false); - src_texture->TransitionToResourceState(D3D::current_command_list, src_texture_state); + src_texture->TransitionToResourceState(D3D::current_command_list, src_texture_state); - // Copy from YUYV intermediate texture to readback buffer. It's likely the pitch here is going to be different to dst_pitch. - u32 readback_pitch = D3D::AlignValue(dst_width * sizeof(u16), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); - D3D12_PLACED_SUBRESOURCE_FOOTPRINT dst_footprint = { 0, { DXGI_FORMAT_R8G8B8A8_UNORM, dst_texture_width, dst_height, 1, readback_pitch } }; - CD3DX12_TEXTURE_COPY_LOCATION dst_location(m_readback_buffer, dst_footprint); - CD3DX12_TEXTURE_COPY_LOCATION src_location(m_yuyv_texture->GetTex12(), 0); - CD3DX12_BOX src_box(0, 0, dst_texture_width, dst_height); - m_yuyv_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); - D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, &src_box); + // Copy from YUYV intermediate texture to readback buffer. It's likely the pitch here is going to + // be different to dst_pitch. + u32 readback_pitch = D3D::AlignValue(dst_width * sizeof(u16), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + D3D12_PLACED_SUBRESOURCE_FOOTPRINT dst_footprint = { + 0, {DXGI_FORMAT_R8G8B8A8_UNORM, dst_texture_width, dst_height, 1, readback_pitch}}; + CD3DX12_TEXTURE_COPY_LOCATION dst_location(m_readback_buffer, dst_footprint); + CD3DX12_TEXTURE_COPY_LOCATION src_location(m_yuyv_texture->GetTex12(), 0); + CD3DX12_BOX src_box(0, 0, dst_texture_width, dst_height); + m_yuyv_texture->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_COPY_SOURCE); + D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, &src_box); - // Wait until the GPU completes the copy. Resets back to known state automatically. - D3D::command_list_mgr->ExecuteQueuedWork(true); + // Wait until the GPU completes the copy. Resets back to known state automatically. + D3D::command_list_mgr->ExecuteQueuedWork(true); - // Copy from the readback buffer to dst. - // Can't be done as one memcpy due to pitch difference. - void* readback_texture_map; - D3D12_RANGE read_range = { 0, readback_pitch * dst_height }; - CheckHR(m_readback_buffer->Map(0, &read_range, &readback_texture_map)); + // Copy from the readback buffer to dst. + // Can't be done as one memcpy due to pitch difference. + void* readback_texture_map; + D3D12_RANGE read_range = {0, readback_pitch * dst_height}; + CheckHR(m_readback_buffer->Map(0, &read_range, &readback_texture_map)); - for (u32 row = 0; row < dst_height; row++) - { - const u8* row_src = reinterpret_cast(readback_texture_map) + readback_pitch * row; - u8* row_dst = dst + dst_pitch * row; - memcpy(row_dst, row_src, std::min(dst_pitch, readback_pitch)); - } + for (u32 row = 0; row < dst_height; row++) + { + const u8* row_src = reinterpret_cast(readback_texture_map) + readback_pitch * row; + u8* row_dst = dst + dst_pitch * row; + memcpy(row_dst, row_src, std::min(dst_pitch, readback_pitch)); + } - D3D12_RANGE write_range = {}; - m_readback_buffer->Unmap(0, &write_range); + D3D12_RANGE write_range = {}; + m_readback_buffer->Unmap(0, &write_range); } -void XFBEncoder::DecodeToTexture(D3DTexture2D* dst_texture, const u8* src, u32 src_width, u32 src_height) +void XFBEncoder::DecodeToTexture(D3DTexture2D* dst_texture, const u8* src, u32 src_width, + u32 src_height) { - _assert_msg_(VIDEO, src_width <= MAX_XFB_WIDTH && src_height <= MAX_XFB_HEIGHT, "XFB source does not exceed maximum size"); + _assert_msg_(VIDEO, src_width <= MAX_XFB_WIDTH && src_height <= MAX_XFB_HEIGHT, + "XFB source does not exceed maximum size"); - // Copy to XFB upload buffer. Each row has to be done separately due to pitch differences. - u32 buffer_pitch = D3D::AlignValue(src_width / 2 * sizeof(u32), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); - m_upload_buffer->AllocateSpaceInBuffer(buffer_pitch * src_height, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); - for (u32 row = 0; row < src_height; row++) - { - const u8* row_src = src + (src_width * 2) * row; - u8* row_dst = reinterpret_cast(m_upload_buffer->GetCPUAddressOfCurrentAllocation()) + buffer_pitch * row; - memcpy(row_dst, row_src, src_width * 2); - } + // Copy to XFB upload buffer. Each row has to be done separately due to pitch differences. + u32 buffer_pitch = + D3D::AlignValue(src_width / 2 * sizeof(u32), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + m_upload_buffer->AllocateSpaceInBuffer(buffer_pitch * src_height, + D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); + for (u32 row = 0; row < src_height; row++) + { + const u8* row_src = src + (src_width * 2) * row; + u8* row_dst = reinterpret_cast(m_upload_buffer->GetCPUAddressOfCurrentAllocation()) + + buffer_pitch * row; + memcpy(row_dst, row_src, src_width * 2); + } - // Copy from upload buffer to intermediate YUYV texture. - D3D12_PLACED_SUBRESOURCE_FOOTPRINT src_footprint = { m_upload_buffer->GetOffsetOfCurrentAllocation(), { DXGI_FORMAT_R8G8B8A8_UNORM, src_width / 2, src_height, 1, buffer_pitch } }; - CD3DX12_TEXTURE_COPY_LOCATION src_location(m_upload_buffer->GetBuffer(), src_footprint); - CD3DX12_TEXTURE_COPY_LOCATION dst_location(m_yuyv_texture->GetTex12(), 0); - CD3DX12_BOX src_box(0, 0, src_width / 2, src_height); - m_yuyv_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_DEST); - D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, &src_box); + // Copy from upload buffer to intermediate YUYV texture. + D3D12_PLACED_SUBRESOURCE_FOOTPRINT src_footprint = { + m_upload_buffer->GetOffsetOfCurrentAllocation(), + {DXGI_FORMAT_R8G8B8A8_UNORM, src_width / 2, src_height, 1, buffer_pitch}}; + CD3DX12_TEXTURE_COPY_LOCATION src_location(m_upload_buffer->GetBuffer(), src_footprint); + CD3DX12_TEXTURE_COPY_LOCATION dst_location(m_yuyv_texture->GetTex12(), 0); + CD3DX12_BOX src_box(0, 0, src_width / 2, src_height); + m_yuyv_texture->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_COPY_DEST); + D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, &src_box); - // Convert YUYV texture to RGBA texture with pixel shader. - CD3DX12_RECT src_texture_rect(0, 0, src_width / 2, src_height); - dst_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); - D3D::current_command_list->OMSetRenderTargets(1, &dst_texture->GetRTV12(), FALSE, nullptr); - D3D::SetViewportAndScissor(0, 0, src_width, src_height); - D3D::DrawShadedTexQuad( - m_yuyv_texture, &src_texture_rect, XFB_TEXTURE_WIDTH, XFB_TEXTURE_HEIGHT, - StaticShaderCache::GetXFBDecodePixelShader(), StaticShaderCache::GetSimpleVertexShader(), StaticShaderCache::GetSimpleVertexShaderInputLayout(), - {}, 1.0f, 0, DXGI_FORMAT_R8G8B8A8_UNORM, false, false); + // Convert YUYV texture to RGBA texture with pixel shader. + CD3DX12_RECT src_texture_rect(0, 0, src_width / 2, src_height); + dst_texture->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_RENDER_TARGET); + D3D::current_command_list->OMSetRenderTargets(1, &dst_texture->GetRTV12(), FALSE, nullptr); + D3D::SetViewportAndScissor(0, 0, src_width, src_height); + D3D::DrawShadedTexQuad(m_yuyv_texture, &src_texture_rect, XFB_TEXTURE_WIDTH, XFB_TEXTURE_HEIGHT, + StaticShaderCache::GetXFBDecodePixelShader(), + StaticShaderCache::GetSimpleVertexShader(), + StaticShaderCache::GetSimpleVertexShaderInputLayout(), {}, 1.0f, 0, + DXGI_FORMAT_R8G8B8A8_UNORM, false, false); - // XFB source textures are expected to be in shader resource state. - dst_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + // XFB source textures are expected to be in shader resource state. + dst_texture->TransitionToResourceState(D3D::current_command_list, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); } - } diff --git a/Source/Core/VideoBackends/D3D12/XFBEncoder.h b/Source/Core/VideoBackends/D3D12/XFBEncoder.h index cb4f712cd6..1621bcdbca 100644 --- a/Source/Core/VideoBackends/D3D12/XFBEncoder.h +++ b/Source/Core/VideoBackends/D3D12/XFBEncoder.h @@ -13,30 +13,28 @@ namespace DX12 { - class D3DTexture2D; class XFBEncoder { public: - XFBEncoder(); - ~XFBEncoder(); + XFBEncoder(); + ~XFBEncoder(); - void EncodeTextureToRam(u8* dst, u32 dst_pitch, u32 dst_height, - D3DTexture2D* src_texture, const TargetRectangle& src_rect, - u32 src_width, u32 src_height, float gamma); + void EncodeTextureToRam(u8* dst, u32 dst_pitch, u32 dst_height, D3DTexture2D* src_texture, + const TargetRectangle& src_rect, u32 src_width, u32 src_height, + float gamma); - void DecodeToTexture(D3DTexture2D* dst_texture, const u8* src, u32 src_width, u32 src_height); + void DecodeToTexture(D3DTexture2D* dst_texture, const u8* src, u32 src_width, u32 src_height); private: - D3DTexture2D* m_yuyv_texture; + D3DTexture2D* m_yuyv_texture; - ID3D12Resource* m_readback_buffer; + ID3D12Resource* m_readback_buffer; - std::unique_ptr m_upload_buffer; - std::unique_ptr m_encode_params_buffer; + std::unique_ptr m_upload_buffer; + std::unique_ptr m_encode_params_buffer; }; extern std::unique_ptr g_xfb_encoder; - } diff --git a/Source/Core/VideoBackends/D3D12/main.cpp b/Source/Core/VideoBackends/D3D12/main.cpp index e67ea2777a..c0be65c7c4 100644 --- a/Source/Core/VideoBackends/D3D12/main.cpp +++ b/Source/Core/VideoBackends/D3D12/main.cpp @@ -39,223 +39,223 @@ namespace DX12 { - unsigned int VideoBackend::PeekMessages() { - MSG msg; - while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - return FALSE; - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return TRUE; + MSG msg; + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + return FALSE; + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return TRUE; } std::string VideoBackend::GetName() const { - return "D3D12"; + return "D3D12"; } std::string VideoBackend::GetDisplayName() const { - return "Direct3D 12 (experimental)"; + return "Direct3D 12 (experimental)"; } void InitBackendInfo() { - HRESULT hr = D3D::LoadDXGI(); - if (FAILED(hr)) - return; + HRESULT hr = D3D::LoadDXGI(); + if (FAILED(hr)) + return; - hr = D3D::LoadD3D(); - if (FAILED(hr)) - { - D3D::UnloadDXGI(); - return; - } + hr = D3D::LoadD3D(); + if (FAILED(hr)) + { + D3D::UnloadDXGI(); + return; + } - g_Config.backend_info.APIType = API_D3D; - g_Config.backend_info.bSupportsExclusiveFullscreen = false; - g_Config.backend_info.bSupportsDualSourceBlend = true; - g_Config.backend_info.bSupportsPrimitiveRestart = true; - g_Config.backend_info.bSupportsOversizedViewports = false; - g_Config.backend_info.bSupportsGeometryShaders = true; - g_Config.backend_info.bSupports3DVision = true; - g_Config.backend_info.bSupportsPostProcessing = false; - g_Config.backend_info.bSupportsPaletteConversion = true; - g_Config.backend_info.bSupportsClipControl = true; + g_Config.backend_info.APIType = API_D3D; + g_Config.backend_info.bSupportsExclusiveFullscreen = false; + g_Config.backend_info.bSupportsDualSourceBlend = true; + g_Config.backend_info.bSupportsPrimitiveRestart = true; + g_Config.backend_info.bSupportsOversizedViewports = false; + g_Config.backend_info.bSupportsGeometryShaders = true; + g_Config.backend_info.bSupports3DVision = true; + g_Config.backend_info.bSupportsPostProcessing = false; + g_Config.backend_info.bSupportsPaletteConversion = true; + g_Config.backend_info.bSupportsClipControl = true; - IDXGIFactory* factory; - IDXGIAdapter* ad; - hr = create_dxgi_factory(__uuidof(IDXGIFactory), (void**)&factory); - if (FAILED(hr)) - { - PanicAlert("Failed to create IDXGIFactory object"); - D3D::UnloadD3D(); - D3D::UnloadDXGI(); - return; - } + IDXGIFactory* factory; + IDXGIAdapter* ad; + hr = create_dxgi_factory(__uuidof(IDXGIFactory), (void**)&factory); + if (FAILED(hr)) + { + PanicAlert("Failed to create IDXGIFactory object"); + D3D::UnloadD3D(); + D3D::UnloadDXGI(); + return; + } - // adapters - g_Config.backend_info.Adapters.clear(); - g_Config.backend_info.AAModes.clear(); - while (factory->EnumAdapters((UINT)g_Config.backend_info.Adapters.size(), &ad) != DXGI_ERROR_NOT_FOUND) - { - const size_t adapter_index = g_Config.backend_info.Adapters.size(); + // adapters + g_Config.backend_info.Adapters.clear(); + g_Config.backend_info.AAModes.clear(); + while (factory->EnumAdapters((UINT)g_Config.backend_info.Adapters.size(), &ad) != + DXGI_ERROR_NOT_FOUND) + { + const size_t adapter_index = g_Config.backend_info.Adapters.size(); - DXGI_ADAPTER_DESC desc; - ad->GetDesc(&desc); + DXGI_ADAPTER_DESC desc; + ad->GetDesc(&desc); - // TODO: These don't get updated on adapter change, yet - if (adapter_index == g_Config.iAdapter) - { - ID3D12Device* temp_device; - hr = d3d12_create_device(ad, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&temp_device)); - if (SUCCEEDED(hr)) - { - std::string samples; - std::vector modes = D3D::EnumAAModes(temp_device); - // First iteration will be 1. This equals no AA. - for (unsigned int i = 0; i < modes.size(); ++i) - { - g_Config.backend_info.AAModes.push_back(modes[i].Count); - } + // TODO: These don't get updated on adapter change, yet + if (adapter_index == g_Config.iAdapter) + { + ID3D12Device* temp_device; + hr = d3d12_create_device(ad, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&temp_device)); + if (SUCCEEDED(hr)) + { + std::string samples; + std::vector modes = D3D::EnumAAModes(temp_device); + // First iteration will be 1. This equals no AA. + for (unsigned int i = 0; i < modes.size(); ++i) + { + g_Config.backend_info.AAModes.push_back(modes[i].Count); + } - // Requires the earlydepthstencil attribute (only available in shader model 5) - g_Config.backend_info.bSupportsEarlyZ = true; + // Requires the earlydepthstencil attribute (only available in shader model 5) + g_Config.backend_info.bSupportsEarlyZ = true; - // Requires full UAV functionality (only available in shader model 5) - g_Config.backend_info.bSupportsBBox = true; + // Requires full UAV functionality (only available in shader model 5) + g_Config.backend_info.bSupportsBBox = true; - // Requires the instance attribute (only available in shader model 5) - g_Config.backend_info.bSupportsGSInstancing = true; + // Requires the instance attribute (only available in shader model 5) + g_Config.backend_info.bSupportsGSInstancing = true; - // Sample shading requires shader model 5 - g_Config.backend_info.bSupportsSSAA = true; + // Sample shading requires shader model 5 + g_Config.backend_info.bSupportsSSAA = true; - temp_device->Release(); - } - } + temp_device->Release(); + } + } - g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description)); - ad->Release(); - } - factory->Release(); + g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description)); + ad->Release(); + } + factory->Release(); - // Clear ppshaders string vector - g_Config.backend_info.PPShaders.clear(); - g_Config.backend_info.AnaglyphShaders.clear(); + // Clear ppshaders string vector + g_Config.backend_info.PPShaders.clear(); + g_Config.backend_info.AnaglyphShaders.clear(); - D3D::UnloadD3D(); - D3D::UnloadDXGI(); + D3D::UnloadD3D(); + D3D::UnloadDXGI(); } -void VideoBackend::ShowConfig(void *hParent) +void VideoBackend::ShowConfig(void* hParent) { - InitBackendInfo(); - Host_ShowVideoConfig(hParent, GetDisplayName(), "gfx_dx12"); + InitBackendInfo(); + Host_ShowVideoConfig(hParent, GetDisplayName(), "gfx_dx12"); } -bool VideoBackend::Initialize(void *window_handle) +bool VideoBackend::Initialize(void* window_handle) { - if (window_handle == nullptr) - return false; + if (window_handle == nullptr) + return false; - InitializeShared(); - InitBackendInfo(); + InitializeShared(); + InitBackendInfo(); - frameCount = 0; + frameCount = 0; - if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini")) - g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"); - else - g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "gfx_dx12.ini"); + if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini")) + g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"); + else + g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "gfx_dx12.ini"); - g_Config.GameIniLoad(); - g_Config.UpdateProjectionHack(); - g_Config.VerifyValidity(); - UpdateActiveConfig(); + g_Config.GameIniLoad(); + g_Config.UpdateProjectionHack(); + g_Config.VerifyValidity(); + UpdateActiveConfig(); - if (FAILED(D3D::Create((HWND)window_handle))) - return false; + if (FAILED(D3D::Create((HWND)window_handle))) + return false; - m_window_handle = window_handle; - m_initialized = true; + m_window_handle = window_handle; + m_initialized = true; - return true; + return true; } void VideoBackend::Video_Prepare() { - // internal interfaces - g_renderer = std::make_unique(m_window_handle); - g_texture_cache = std::make_unique(); - g_vertex_manager = std::make_unique(); - g_perf_query = std::make_unique(); - g_xfb_encoder = std::make_unique(); - ShaderCache::Init(); - ShaderConstantsManager::Init(); - StaticShaderCache::Init(); - StateCache::Init(); // PSO cache is populated here, after constituent shaders are loaded. - D3D::InitUtils(); + // internal interfaces + g_renderer = std::make_unique(m_window_handle); + g_texture_cache = std::make_unique(); + g_vertex_manager = std::make_unique(); + g_perf_query = std::make_unique(); + g_xfb_encoder = std::make_unique(); + ShaderCache::Init(); + ShaderConstantsManager::Init(); + StaticShaderCache::Init(); + StateCache::Init(); // PSO cache is populated here, after constituent shaders are loaded. + D3D::InitUtils(); - // VideoCommon - BPInit(); - Fifo::Init(); - IndexGenerator::Init(); - VertexLoaderManager::Init(); - OpcodeDecoder::Init(); - VertexShaderManager::Init(); - PixelShaderManager::Init(); - GeometryShaderManager::Init(); - CommandProcessor::Init(); - PixelEngine::Init(); - BBox::Init(); + // VideoCommon + BPInit(); + Fifo::Init(); + IndexGenerator::Init(); + VertexLoaderManager::Init(); + OpcodeDecoder::Init(); + VertexShaderManager::Init(); + PixelShaderManager::Init(); + GeometryShaderManager::Init(); + CommandProcessor::Init(); + PixelEngine::Init(); + BBox::Init(); - // Tell the host that the window is ready - Host_Message(WM_USER_CREATE); + // Tell the host that the window is ready + Host_Message(WM_USER_CREATE); } void VideoBackend::Shutdown() { - m_initialized = true; + m_initialized = true; - // TODO: should be in Video_Cleanup - if (g_renderer) - { - // Immediately stop app from submitting work to GPU, and wait for all submitted work to complete. D3D12TODO: Check this. - D3D::command_list_mgr->ExecuteQueuedWork(true); + // TODO: should be in Video_Cleanup + if (g_renderer) + { + // Immediately stop app from submitting work to GPU, and wait for all submitted work to + // complete. D3D12TODO: Check this. + D3D::command_list_mgr->ExecuteQueuedWork(true); - // VideoCommon - Fifo::Shutdown(); - CommandProcessor::Shutdown(); - GeometryShaderManager::Shutdown(); - PixelShaderManager::Shutdown(); - VertexShaderManager::Shutdown(); - OpcodeDecoder::Shutdown(); - VertexLoaderManager::Shutdown(); + // VideoCommon + Fifo::Shutdown(); + CommandProcessor::Shutdown(); + GeometryShaderManager::Shutdown(); + PixelShaderManager::Shutdown(); + VertexShaderManager::Shutdown(); + OpcodeDecoder::Shutdown(); + VertexLoaderManager::Shutdown(); - // internal interfaces - D3D::ShutdownUtils(); - ShaderCache::Shutdown(); - ShaderConstantsManager::Shutdown(); - StaticShaderCache::Shutdown(); - BBox::Shutdown(); + // internal interfaces + D3D::ShutdownUtils(); + ShaderCache::Shutdown(); + ShaderConstantsManager::Shutdown(); + StaticShaderCache::Shutdown(); + BBox::Shutdown(); - g_xfb_encoder.reset(); - g_perf_query.reset(); - g_vertex_manager.reset(); - g_texture_cache.reset(); - g_renderer.reset(); + g_xfb_encoder.reset(); + g_perf_query.reset(); + g_vertex_manager.reset(); + g_texture_cache.reset(); + g_renderer.reset(); - D3D::Close(); - } + D3D::Close(); + } } void VideoBackend::Video_Cleanup() { } - } diff --git a/Source/Core/VideoBackends/OGL/BoundingBox.cpp b/Source/Core/VideoBackends/OGL/BoundingBox.cpp index 2923b9c2c4..7ec094f9f2 100644 --- a/Source/Core/VideoBackends/OGL/BoundingBox.cpp +++ b/Source/Core/VideoBackends/OGL/BoundingBox.cpp @@ -15,57 +15,56 @@ static GLuint s_bbox_buffer_id; namespace OGL { - void BoundingBox::Init() { - if (g_ActiveConfig.backend_info.bSupportsBBox) - { - int initial_values[4] = {0,0,0,0}; - glGenBuffers(1, &s_bbox_buffer_id); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id); - glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * sizeof(s32), initial_values, GL_DYNAMIC_DRAW); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, s_bbox_buffer_id); - } + if (g_ActiveConfig.backend_info.bSupportsBBox) + { + int initial_values[4] = {0, 0, 0, 0}; + glGenBuffers(1, &s_bbox_buffer_id); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id); + glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * sizeof(s32), initial_values, GL_DYNAMIC_DRAW); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, s_bbox_buffer_id); + } } void BoundingBox::Shutdown() { - if (g_ActiveConfig.backend_info.bSupportsBBox) - glDeleteBuffers(1, &s_bbox_buffer_id); + if (g_ActiveConfig.backend_info.bSupportsBBox) + glDeleteBuffers(1, &s_bbox_buffer_id); } void BoundingBox::Set(int index, int value) { - glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id); - glBufferSubData(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), &value); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id); + glBufferSubData(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), &value); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); } int BoundingBox::Get(int index) { - int data = 0; - glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id); + int data = 0; + glBindBuffer(GL_SHADER_STORAGE_BUFFER, s_bbox_buffer_id); - if (!DriverDetails::HasBug(DriverDetails::BUG_SLOWGETBUFFERSUBDATA)) - { - // Using glMapBufferRange to read back the contents of the SSBO is extremely slow - // on nVidia drivers. This is more noticeable at higher internal resolutions. - // Using glGetBufferSubData instead does not seem to exhibit this slowdown. - glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), &data); - } - else - { - // Using glMapBufferRange is faster on AMD cards by a measurable margin. - void* ptr = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), GL_MAP_READ_BIT); - if (ptr) - { - memcpy(&data, ptr, sizeof(int)); - glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); - } - } + if (!DriverDetails::HasBug(DriverDetails::BUG_SLOWGETBUFFERSUBDATA)) + { + // Using glMapBufferRange to read back the contents of the SSBO is extremely slow + // on nVidia drivers. This is more noticeable at higher internal resolutions. + // Using glGetBufferSubData instead does not seem to exhibit this slowdown. + glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), &data); + } + else + { + // Using glMapBufferRange is faster on AMD cards by a measurable margin. + void* ptr = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, index * sizeof(int), sizeof(int), + GL_MAP_READ_BIT); + if (ptr) + { + memcpy(&data, ptr, sizeof(int)); + glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); + } + } - glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); - return data; + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + return data; } - }; diff --git a/Source/Core/VideoBackends/OGL/BoundingBox.h b/Source/Core/VideoBackends/OGL/BoundingBox.h index 76b86d0c4c..0aedff54df 100644 --- a/Source/Core/VideoBackends/OGL/BoundingBox.h +++ b/Source/Core/VideoBackends/OGL/BoundingBox.h @@ -6,15 +6,13 @@ namespace OGL { - class BoundingBox { public: - static void Init(); - static void Shutdown(); + static void Init(); + static void Shutdown(); - static void Set(int index, int value); - static int Get(int index); + static void Set(int index, int value); + static int Get(int index); }; - }; diff --git a/Source/Core/VideoBackends/OGL/FramebufferManager.cpp b/Source/Core/VideoBackends/OGL/FramebufferManager.cpp index 0ccef81358..a487cf1ac1 100644 --- a/Source/Core/VideoBackends/OGL/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/OGL/FramebufferManager.cpp @@ -21,7 +21,6 @@ namespace OGL { - int FramebufferManager::m_targetWidth; int FramebufferManager::m_targetHeight; int FramebufferManager::m_msaaSamples; @@ -31,7 +30,7 @@ std::vector FramebufferManager::m_efbFramebuffer; GLuint FramebufferManager::m_xfbFramebuffer; GLuint FramebufferManager::m_efbColor; GLuint FramebufferManager::m_efbDepth; -GLuint FramebufferManager::m_efbColorSwap; // for hot swap when reinterpreting EFB pixel formats +GLuint FramebufferManager::m_efbColorSwap; // for hot swap when reinterpreting EFB pixel formats // Only used in MSAA mode. std::vector FramebufferManager::m_resolvedFramebuffer; @@ -48,627 +47,652 @@ SHADER FramebufferManager::m_EfbPokes; FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples) { - m_xfbFramebuffer = 0; - m_efbColor = 0; - m_efbDepth = 0; - m_efbColorSwap = 0; - m_resolvedColorTexture = 0; - m_resolvedDepthTexture = 0; + m_xfbFramebuffer = 0; + m_efbColor = 0; + m_efbDepth = 0; + m_efbColorSwap = 0; + m_resolvedColorTexture = 0; + m_resolvedDepthTexture = 0; - m_targetWidth = targetWidth; - m_targetHeight = targetHeight; + m_targetWidth = targetWidth; + m_targetHeight = targetHeight; - m_msaaSamples = msaaSamples; + m_msaaSamples = msaaSamples; - // The EFB can be set to different pixel formats by the game through the - // BPMEM_ZCOMPARE register (which should probably have a different name). - // They are: - // - 24-bit RGB (8-bit components) with 24-bit Z - // - 24-bit RGBA (6-bit components) with 24-bit Z - // - Multisampled 16-bit RGB (5-6-5 format) with 16-bit Z - // We only use one EFB format here: 32-bit ARGB with 24-bit Z. - // Multisampling depends on user settings. - // The distinction becomes important for certain operations, i.e. the - // alpha channel should be ignored if the EFB does not have one. + // The EFB can be set to different pixel formats by the game through the + // BPMEM_ZCOMPARE register (which should probably have a different name). + // They are: + // - 24-bit RGB (8-bit components) with 24-bit Z + // - 24-bit RGBA (6-bit components) with 24-bit Z + // - Multisampled 16-bit RGB (5-6-5 format) with 16-bit Z + // We only use one EFB format here: 32-bit ARGB with 24-bit Z. + // Multisampling depends on user settings. + // The distinction becomes important for certain operations, i.e. the + // alpha channel should be ignored if the EFB does not have one. - glActiveTexture(GL_TEXTURE9); + glActiveTexture(GL_TEXTURE9); - GLuint glObj[3]; - glGenTextures(3, glObj); - m_efbColor = glObj[0]; - m_efbDepth = glObj[1]; - m_efbColorSwap = glObj[2]; + GLuint glObj[3]; + glGenTextures(3, glObj); + m_efbColor = glObj[0]; + m_efbDepth = glObj[1]; + m_efbColorSwap = glObj[2]; - m_EFBLayers = (g_ActiveConfig.iStereoMode > 0) ? 2 : 1; - m_efbFramebuffer.resize(m_EFBLayers); - m_resolvedFramebuffer.resize(m_EFBLayers); + m_EFBLayers = (g_ActiveConfig.iStereoMode > 0) ? 2 : 1; + m_efbFramebuffer.resize(m_EFBLayers); + m_resolvedFramebuffer.resize(m_EFBLayers); - // OpenGL MSAA textures are a different kind of texture type and must be allocated - // with a different function, so we create them separately. - if (m_msaaSamples <= 1) - { - m_textureType = GL_TEXTURE_2D_ARRAY; + // OpenGL MSAA textures are a different kind of texture type and must be allocated + // with a different function, so we create them separately. + if (m_msaaSamples <= 1) + { + m_textureType = GL_TEXTURE_2D_ARRAY; - glBindTexture(m_textureType, m_efbColor); - glTexParameteri(m_textureType, GL_TEXTURE_MAX_LEVEL, 0); - glTexImage3D(m_textureType, 0, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glBindTexture(m_textureType, m_efbColor); + glTexParameteri(m_textureType, GL_TEXTURE_MAX_LEVEL, 0); + glTexImage3D(m_textureType, 0, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr); - glBindTexture(m_textureType, m_efbDepth); - glTexParameteri(m_textureType, GL_TEXTURE_MAX_LEVEL, 0); - glTexImage3D(m_textureType, 0, GL_DEPTH_COMPONENT32F, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); + glBindTexture(m_textureType, m_efbDepth); + glTexParameteri(m_textureType, GL_TEXTURE_MAX_LEVEL, 0); + glTexImage3D(m_textureType, 0, GL_DEPTH_COMPONENT32F, m_targetWidth, m_targetHeight, + m_EFBLayers, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); - glBindTexture(m_textureType, m_efbColorSwap); - glTexParameteri(m_textureType, GL_TEXTURE_MAX_LEVEL, 0); - glTexImage3D(m_textureType, 0, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - } - else - { - GLenum resolvedType = GL_TEXTURE_2D_ARRAY; + glBindTexture(m_textureType, m_efbColorSwap); + glTexParameteri(m_textureType, GL_TEXTURE_MAX_LEVEL, 0); + glTexImage3D(m_textureType, 0, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr); + } + else + { + GLenum resolvedType = GL_TEXTURE_2D_ARRAY; - // Only use a layered multisample texture if needed. Some drivers - // slow down significantly with single-layered multisample textures. - if (m_EFBLayers > 1) - { - m_textureType = GL_TEXTURE_2D_MULTISAMPLE_ARRAY; + // Only use a layered multisample texture if needed. Some drivers + // slow down significantly with single-layered multisample textures. + if (m_EFBLayers > 1) + { + m_textureType = GL_TEXTURE_2D_MULTISAMPLE_ARRAY; - if (g_ogl_config.bSupports3DTextureStorage) - { - glBindTexture(m_textureType, m_efbColor); - glTexStorage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight, m_EFBLayers, false); + if (g_ogl_config.bSupports3DTextureStorage) + { + glBindTexture(m_textureType, m_efbColor); + glTexStorage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA8, m_targetWidth, + m_targetHeight, m_EFBLayers, false); - glBindTexture(m_textureType, m_efbDepth); - glTexStorage3DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT32F, m_targetWidth, m_targetHeight, m_EFBLayers, false); + glBindTexture(m_textureType, m_efbDepth); + glTexStorage3DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT32F, + m_targetWidth, m_targetHeight, m_EFBLayers, false); - glBindTexture(m_textureType, m_efbColorSwap); - glTexStorage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight, m_EFBLayers, false); - glBindTexture(m_textureType, 0); + glBindTexture(m_textureType, m_efbColorSwap); + glTexStorage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA8, m_targetWidth, + m_targetHeight, m_EFBLayers, false); + glBindTexture(m_textureType, 0); + } + else + { + glBindTexture(m_textureType, m_efbColor); + glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, + m_targetHeight, m_EFBLayers, false); - } - else - { - glBindTexture(m_textureType, m_efbColor); - glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, false); + glBindTexture(m_textureType, m_efbDepth); + glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT32F, m_targetWidth, + m_targetHeight, m_EFBLayers, false); - glBindTexture(m_textureType, m_efbDepth); - glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT32F, m_targetWidth, m_targetHeight, m_EFBLayers, false); + glBindTexture(m_textureType, m_efbColorSwap); + glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, + m_targetHeight, m_EFBLayers, false); + glBindTexture(m_textureType, 0); + } + } + else + { + m_textureType = GL_TEXTURE_2D_MULTISAMPLE; - glBindTexture(m_textureType, m_efbColorSwap); - glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, false); - glBindTexture(m_textureType, 0); - } - } - else - { - m_textureType = GL_TEXTURE_2D_MULTISAMPLE; + if (g_ogl_config.bSupports2DTextureStorage) + { + glBindTexture(m_textureType, m_efbColor); + glTexStorage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA8, m_targetWidth, + m_targetHeight, false); - if (g_ogl_config.bSupports2DTextureStorage) - { - glBindTexture(m_textureType, m_efbColor); - glTexStorage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight, false); + glBindTexture(m_textureType, m_efbDepth); + glTexStorage2DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT32F, + m_targetWidth, m_targetHeight, false); - glBindTexture(m_textureType, m_efbDepth); - glTexStorage2DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT32F, m_targetWidth, m_targetHeight, false); + glBindTexture(m_textureType, m_efbColorSwap); + glTexStorage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA8, m_targetWidth, + m_targetHeight, false); + glBindTexture(m_textureType, 0); + } + else + { + glBindTexture(m_textureType, m_efbColor); + glTexImage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, + m_targetHeight, false); - glBindTexture(m_textureType, m_efbColorSwap); - glTexStorage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight, false); - glBindTexture(m_textureType, 0); - } - else - { - glBindTexture(m_textureType, m_efbColor); - glTexImage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, false); + glBindTexture(m_textureType, m_efbDepth); + glTexImage2DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT32F, m_targetWidth, + m_targetHeight, false); - glBindTexture(m_textureType, m_efbDepth); - glTexImage2DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT32F, m_targetWidth, m_targetHeight, false); + glBindTexture(m_textureType, m_efbColorSwap); + glTexImage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, + m_targetHeight, false); + glBindTexture(m_textureType, 0); + } + } - glBindTexture(m_textureType, m_efbColorSwap); - glTexImage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, false); - glBindTexture(m_textureType, 0); - } - } + // Although we are able to access the multisampled texture directly, we don't do it everywhere. + // The old way is to "resolve" this multisampled texture by copying it into a non-sampled + // texture. + // This would lead to an unneeded copy of the EFB, so we are going to avoid it. + // But as this job isn't done right now, we do need that texture for resolving: + glGenTextures(2, glObj); + m_resolvedColorTexture = glObj[0]; + m_resolvedDepthTexture = glObj[1]; - // Although we are able to access the multisampled texture directly, we don't do it everywhere. - // The old way is to "resolve" this multisampled texture by copying it into a non-sampled texture. - // This would lead to an unneeded copy of the EFB, so we are going to avoid it. - // But as this job isn't done right now, we do need that texture for resolving: - glGenTextures(2, glObj); - m_resolvedColorTexture = glObj[0]; - m_resolvedDepthTexture = glObj[1]; + glBindTexture(resolvedType, m_resolvedColorTexture); + glTexParameteri(resolvedType, GL_TEXTURE_MAX_LEVEL, 0); + glTexImage3D(resolvedType, 0, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr); - glBindTexture(resolvedType, m_resolvedColorTexture); - glTexParameteri(resolvedType, GL_TEXTURE_MAX_LEVEL, 0); - glTexImage3D(resolvedType, 0, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glBindTexture(resolvedType, m_resolvedDepthTexture); + glTexParameteri(resolvedType, GL_TEXTURE_MAX_LEVEL, 0); + glTexImage3D(resolvedType, 0, GL_DEPTH_COMPONENT32F, m_targetWidth, m_targetHeight, m_EFBLayers, + 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); - glBindTexture(resolvedType, m_resolvedDepthTexture); - glTexParameteri(resolvedType, GL_TEXTURE_MAX_LEVEL, 0); - glTexImage3D(resolvedType, 0, GL_DEPTH_COMPONENT32F, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); + // Bind resolved textures to resolved framebuffer. + glGenFramebuffers(m_EFBLayers, m_resolvedFramebuffer.data()); + glBindFramebuffer(GL_FRAMEBUFFER, m_resolvedFramebuffer[0]); + FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, resolvedType, m_resolvedColorTexture, + 0); + FramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, resolvedType, m_resolvedDepthTexture, + 0); - // Bind resolved textures to resolved framebuffer. - glGenFramebuffers(m_EFBLayers, m_resolvedFramebuffer.data()); - glBindFramebuffer(GL_FRAMEBUFFER, m_resolvedFramebuffer[0]); - FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, resolvedType, m_resolvedColorTexture, 0); - FramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, resolvedType, m_resolvedDepthTexture, 0); + // Bind all the other layers as separate FBOs for blitting. + for (unsigned int i = 1; i < m_EFBLayers; i++) + { + glBindFramebuffer(GL_FRAMEBUFFER, m_resolvedFramebuffer[i]); + glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_resolvedColorTexture, 0, i); + glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_resolvedDepthTexture, 0, i); + } + } - // Bind all the other layers as separate FBOs for blitting. - for (unsigned int i = 1; i < m_EFBLayers; i++) - { - glBindFramebuffer(GL_FRAMEBUFFER, m_resolvedFramebuffer[i]); - glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_resolvedColorTexture, 0, i); - glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_resolvedDepthTexture, 0, i); - } - } + // Create XFB framebuffer; targets will be created elsewhere. + glGenFramebuffers(1, &m_xfbFramebuffer); - // Create XFB framebuffer; targets will be created elsewhere. - glGenFramebuffers(1, &m_xfbFramebuffer); + // Bind target textures to EFB framebuffer. + glGenFramebuffers(m_EFBLayers, m_efbFramebuffer.data()); + glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]); + FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textureType, m_efbColor, 0); + FramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_textureType, m_efbDepth, 0); - // Bind target textures to EFB framebuffer. - glGenFramebuffers(m_EFBLayers, m_efbFramebuffer.data()); - glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]); - FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textureType, m_efbColor, 0); - FramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_textureType, m_efbDepth, 0); + // Bind all the other layers as separate FBOs for blitting. + for (unsigned int i = 1; i < m_EFBLayers; i++) + { + glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[i]); + glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_efbColor, 0, i); + glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_efbDepth, 0, i); + } - // Bind all the other layers as separate FBOs for blitting. - for (unsigned int i = 1; i < m_EFBLayers; i++) - { - glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[i]); - glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_efbColor, 0, i); - glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_efbDepth, 0, i); - } + // EFB framebuffer is currently bound, make sure to clear its alpha value to 1.f + glViewport(0, 0, m_targetWidth, m_targetHeight); + glScissor(0, 0, m_targetWidth, m_targetHeight); + glClearColor(0.f, 0.f, 0.f, 1.f); + glClearDepthf(1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // EFB framebuffer is currently bound, make sure to clear its alpha value to 1.f - glViewport(0, 0, m_targetWidth, m_targetHeight); - glScissor(0, 0, m_targetWidth, m_targetHeight); - glClearColor(0.f, 0.f, 0.f, 1.f); - glClearDepthf(1.0f); - glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + // reinterpret pixel format + const char* vs = m_EFBLayers > 1 ? "void main(void) {\n" + " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" + " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" + "}\n" : + "flat out int layer;\n" + "void main(void) {\n" + " layer = 0;\n" + " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" + " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" + "}\n"; - // reinterpret pixel format - const char* vs = m_EFBLayers > 1 ? - "void main(void) {\n" - " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" - " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" - "}\n" : - "flat out int layer;\n" - "void main(void) {\n" - " layer = 0;\n" - " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" - " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" - "}\n"; + // The way to sample the EFB is based on the on the current configuration. + // As we use the same sampling way for both interpreting shaders, the sampling + // shader are generated first: + std::string sampler; + if (m_msaaSamples <= 1) + { + // non-msaa, so just fetch the pixel + sampler = "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" + "vec4 sampleEFB(ivec3 pos) {\n" + " return texelFetch(samp9, pos, 0);\n" + "}\n"; + } + else if (g_ActiveConfig.backend_info.bSupportsSSAA) + { + // msaa + sample shading available, so just fetch the sample + // This will lead to sample shading, but it's the only way to not loose + // the values of each sample. + if (m_EFBLayers > 1) + { + sampler = "SAMPLER_BINDING(9) uniform sampler2DMSArray samp9;\n" + "vec4 sampleEFB(ivec3 pos) {\n" + " return texelFetch(samp9, pos, gl_SampleID);\n" + "}\n"; + } + else + { + sampler = "SAMPLER_BINDING(9) uniform sampler2DMS samp9;\n" + "vec4 sampleEFB(ivec3 pos) {\n" + " return texelFetch(samp9, pos.xy, gl_SampleID);\n" + "}\n"; + } + } + else + { + // msaa without sample shading: calculate the mean value of the pixel + std::stringstream samples; + samples << m_msaaSamples; + if (m_EFBLayers > 1) + { + sampler = "SAMPLER_BINDING(9) uniform sampler2DMSArray samp9;\n" + "vec4 sampleEFB(ivec3 pos) {\n" + " vec4 color = vec4(0.0, 0.0, 0.0, 0.0);\n" + " for(int i=0; i<" + + samples.str() + "; i++)\n" + " color += texelFetch(samp9, pos, i);\n" + " return color / " + + samples.str() + ";\n" + "}\n"; + } + else + { + sampler = "SAMPLER_BINDING(9) uniform sampler2DMS samp9;\n" + "vec4 sampleEFB(ivec3 pos) {\n" + " vec4 color = vec4(0.0, 0.0, 0.0, 0.0);\n" + " for(int i=0; i<" + + samples.str() + "; i++)\n" + " color += texelFetch(samp9, pos.xy, i);\n" + " return color / " + + samples.str() + ";\n" + "}\n"; + } + } - // The way to sample the EFB is based on the on the current configuration. - // As we use the same sampling way for both interpreting shaders, the sampling - // shader are generated first: - std::string sampler; - if (m_msaaSamples <= 1) - { - // non-msaa, so just fetch the pixel - sampler = - "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" - "vec4 sampleEFB(ivec3 pos) {\n" - " return texelFetch(samp9, pos, 0);\n" - "}\n"; - } - else if (g_ActiveConfig.backend_info.bSupportsSSAA) - { - // msaa + sample shading available, so just fetch the sample - // This will lead to sample shading, but it's the only way to not loose - // the values of each sample. - if (m_EFBLayers > 1) - { - sampler = - "SAMPLER_BINDING(9) uniform sampler2DMSArray samp9;\n" - "vec4 sampleEFB(ivec3 pos) {\n" - " return texelFetch(samp9, pos, gl_SampleID);\n" - "}\n"; - } - else - { - sampler = - "SAMPLER_BINDING(9) uniform sampler2DMS samp9;\n" - "vec4 sampleEFB(ivec3 pos) {\n" - " return texelFetch(samp9, pos.xy, gl_SampleID);\n" - "}\n"; - } - } - else - { - // msaa without sample shading: calculate the mean value of the pixel - std::stringstream samples; - samples << m_msaaSamples; - if (m_EFBLayers > 1) - { - sampler = - "SAMPLER_BINDING(9) uniform sampler2DMSArray samp9;\n" - "vec4 sampleEFB(ivec3 pos) {\n" - " vec4 color = vec4(0.0, 0.0, 0.0, 0.0);\n" - " for(int i=0; i<" + samples.str() + "; i++)\n" - " color += texelFetch(samp9, pos, i);\n" - " return color / " + samples.str() + ";\n" - "}\n"; - } - else - { - sampler = - "SAMPLER_BINDING(9) uniform sampler2DMS samp9;\n" - "vec4 sampleEFB(ivec3 pos) {\n" - " vec4 color = vec4(0.0, 0.0, 0.0, 0.0);\n" - " for(int i=0; i<" + samples.str() + "; i++)\n" - " color += texelFetch(samp9, pos.xy, i);\n" - " return color / " + samples.str() + ";\n" - "}\n"; - } - } + std::string ps_rgba6_to_rgb8 = + sampler + "flat in int layer;\n" + "out vec4 ocol0;\n" + "void main()\n" + "{\n" + " ivec4 src6 = ivec4(round(sampleEFB(ivec3(gl_FragCoord.xy, layer)) * 63.f));\n" + " ivec4 dst8;\n" + " dst8.r = (src6.r << 2) | (src6.g >> 4);\n" + " dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n" + " dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n" + " dst8.a = 255;\n" + " ocol0 = float4(dst8) / 255.f;\n" + "}"; - std::string ps_rgba6_to_rgb8 = sampler + - "flat in int layer;\n" - "out vec4 ocol0;\n" - "void main()\n" - "{\n" - " ivec4 src6 = ivec4(round(sampleEFB(ivec3(gl_FragCoord.xy, layer)) * 63.f));\n" - " ivec4 dst8;\n" - " dst8.r = (src6.r << 2) | (src6.g >> 4);\n" - " dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n" - " dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n" - " dst8.a = 255;\n" - " ocol0 = float4(dst8) / 255.f;\n" - "}"; + std::string ps_rgb8_to_rgba6 = + sampler + "flat in int layer;\n" + "out vec4 ocol0;\n" + "void main()\n" + "{\n" + " ivec4 src8 = ivec4(round(sampleEFB(ivec3(gl_FragCoord.xy, layer)) * 255.f));\n" + " ivec4 dst6;\n" + " dst6.r = src8.r >> 2;\n" + " dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n" + " dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n" + " dst6.a = src8.b & 0x3F;\n" + " ocol0 = float4(dst6) / 63.f;\n" + "}"; - std::string ps_rgb8_to_rgba6 = sampler + - "flat in int layer;\n" - "out vec4 ocol0;\n" - "void main()\n" - "{\n" - " ivec4 src8 = ivec4(round(sampleEFB(ivec3(gl_FragCoord.xy, layer)) * 255.f));\n" - " ivec4 dst6;\n" - " dst6.r = src8.r >> 2;\n" - " dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n" - " dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n" - " dst6.a = src8.b & 0x3F;\n" - " ocol0 = float4(dst6) / 63.f;\n" - "}"; + std::stringstream vertices, layers; + vertices << m_EFBLayers * 3; + layers << m_EFBLayers; + std::string gs = "layout(triangles) in;\n" + "layout(triangle_strip, max_vertices = " + + vertices.str() + ") out;\n" + "flat out int layer;\n" + "void main()\n" + "{\n" + " for (int j = 0; j < " + + layers.str() + "; ++j) {\n" + " for (int i = 0; i < 3; ++i) {\n" + " layer = j;\n" + " gl_Layer = j;\n" + " gl_Position = gl_in[i].gl_Position;\n" + " EmitVertex();\n" + " }\n" + " EndPrimitive();\n" + " }\n" + "}\n"; - std::stringstream vertices, layers; - vertices << m_EFBLayers * 3; - layers << m_EFBLayers; - std::string gs = - "layout(triangles) in;\n" - "layout(triangle_strip, max_vertices = " + vertices.str() + ") out;\n" - "flat out int layer;\n" - "void main()\n" - "{\n" - " for (int j = 0; j < " + layers.str() + "; ++j) {\n" - " for (int i = 0; i < 3; ++i) {\n" - " layer = j;\n" - " gl_Layer = j;\n" - " gl_Position = gl_in[i].gl_Position;\n" - " EmitVertex();\n" - " }\n" - " EndPrimitive();\n" - " }\n" - "}\n"; + ProgramShaderCache::CompileShader(m_pixel_format_shaders[0], vs, ps_rgb8_to_rgba6.c_str(), + (m_EFBLayers > 1) ? gs : ""); + ProgramShaderCache::CompileShader(m_pixel_format_shaders[1], vs, ps_rgba6_to_rgb8.c_str(), + (m_EFBLayers > 1) ? gs : ""); - ProgramShaderCache::CompileShader(m_pixel_format_shaders[0], vs, ps_rgb8_to_rgba6.c_str(), (m_EFBLayers > 1) ? gs : ""); - ProgramShaderCache::CompileShader(m_pixel_format_shaders[1], vs, ps_rgba6_to_rgb8.c_str(), (m_EFBLayers > 1) ? gs : ""); + ProgramShaderCache::CompileShader( + m_EfbPokes, + StringFromFormat("in vec2 rawpos;\n" + "in vec4 color0;\n" // color + "in int color1;\n" // depth + "out vec4 v_c;\n" + "out float v_z;\n" + "void main(void) {\n" + " gl_Position = vec4(((rawpos + 0.5) / vec2(640.0, 528.0) * 2.0 - 1.0) * " + "vec2(1.0, -1.0), 0.0, 1.0);\n" + " gl_PointSize = %d.0 / 640.0;\n" + " v_c = color0.bgra;\n" + " v_z = float(color1 & 0xFFFFFF) / 16777216.0;\n" + "}\n", + m_targetWidth), - ProgramShaderCache::CompileShader(m_EfbPokes, - StringFromFormat( - "in vec2 rawpos;\n" - "in vec4 color0;\n" // color - "in int color1;\n" // depth - "out vec4 v_c;\n" - "out float v_z;\n" - "void main(void) {\n" - " gl_Position = vec4(((rawpos + 0.5) / vec2(640.0, 528.0) * 2.0 - 1.0) * vec2(1.0, -1.0), 0.0, 1.0);\n" - " gl_PointSize = %d.0 / 640.0;\n" - " v_c = color0.bgra;\n" - " v_z = float(color1 & 0xFFFFFF) / 16777216.0;\n" - "}\n", m_targetWidth), + StringFromFormat("in vec4 %s_c;\n" + "in float %s_z;\n" + "out vec4 ocol0;\n" + "void main(void) {\n" + " ocol0 = %s_c;\n" + " gl_FragDepth = %s_z;\n" + "}\n", + m_EFBLayers > 1 ? "g" : "v", m_EFBLayers > 1 ? "g" : "v", + m_EFBLayers > 1 ? "g" : "v", m_EFBLayers > 1 ? "g" : "v"), - StringFromFormat( - "in vec4 %s_c;\n" - "in float %s_z;\n" - "out vec4 ocol0;\n" - "void main(void) {\n" - " ocol0 = %s_c;\n" - " gl_FragDepth = %s_z;\n" - "}\n", m_EFBLayers > 1 ? "g" : "v", m_EFBLayers > 1 ? "g" : "v", m_EFBLayers > 1 ? "g" : "v", m_EFBLayers > 1 ? "g" : "v"), + m_EFBLayers > 1 ? StringFromFormat("layout(points) in;\n" + "layout(points, max_vertices = %d) out;\n" + "in vec4 v_c[1];\n" + "in float v_z[1];\n" + "out vec4 g_c;\n" + "out float g_z;\n" + "void main()\n" + "{\n" + " for (int j = 0; j < %d; ++j) {\n" + " gl_Layer = j;\n" + " gl_Position = gl_in[0].gl_Position;\n" + " gl_PointSize = %d.0 / 640.0;\n" + " g_c = v_c[0];\n" + " g_z = v_z[0];\n" + " EmitVertex();\n" + " EndPrimitive();\n" + " }\n" + "}\n", + m_EFBLayers, m_EFBLayers, m_targetWidth) : + ""); + glGenBuffers(1, &m_EfbPokes_VBO); + glGenVertexArrays(1, &m_EfbPokes_VAO); + glBindBuffer(GL_ARRAY_BUFFER, m_EfbPokes_VBO); + glBindVertexArray(m_EfbPokes_VAO); + glEnableVertexAttribArray(SHADER_POSITION_ATTRIB); + glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_UNSIGNED_SHORT, 0, sizeof(EfbPokeData), + (void*)offsetof(EfbPokeData, x)); + glEnableVertexAttribArray(SHADER_COLOR0_ATTRIB); + glVertexAttribPointer(SHADER_COLOR0_ATTRIB, 4, GL_UNSIGNED_BYTE, 1, sizeof(EfbPokeData), + (void*)offsetof(EfbPokeData, data)); + glEnableVertexAttribArray(SHADER_COLOR1_ATTRIB); + glVertexAttribIPointer(SHADER_COLOR1_ATTRIB, 1, GL_INT, sizeof(EfbPokeData), + (void*)offsetof(EfbPokeData, data)); - m_EFBLayers > 1 ? StringFromFormat( - "layout(points) in;\n" - "layout(points, max_vertices = %d) out;\n" - "in vec4 v_c[1];\n" - "in float v_z[1];\n" - "out vec4 g_c;\n" - "out float g_z;\n" - "void main()\n" - "{\n" - " for (int j = 0; j < %d; ++j) {\n" - " gl_Layer = j;\n" - " gl_Position = gl_in[0].gl_Position;\n" - " gl_PointSize = %d.0 / 640.0;\n" - " g_c = v_c[0];\n" - " g_z = v_z[0];\n" - " EmitVertex();\n" - " EndPrimitive();\n" - " }\n" - "}\n", m_EFBLayers, m_EFBLayers, m_targetWidth) : ""); - glGenBuffers(1, &m_EfbPokes_VBO); - glGenVertexArrays(1, &m_EfbPokes_VAO); - glBindBuffer(GL_ARRAY_BUFFER, m_EfbPokes_VBO); - glBindVertexArray(m_EfbPokes_VAO ); - glEnableVertexAttribArray(SHADER_POSITION_ATTRIB); - glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_UNSIGNED_SHORT, 0, sizeof(EfbPokeData), (void*)offsetof(EfbPokeData, x)); - glEnableVertexAttribArray(SHADER_COLOR0_ATTRIB); - glVertexAttribPointer(SHADER_COLOR0_ATTRIB, 4, GL_UNSIGNED_BYTE, 1, sizeof(EfbPokeData), (void*)offsetof(EfbPokeData, data)); - glEnableVertexAttribArray(SHADER_COLOR1_ATTRIB); - glVertexAttribIPointer(SHADER_COLOR1_ATTRIB, 1, GL_INT, sizeof(EfbPokeData), (void*)offsetof(EfbPokeData, data)); - - if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) - glEnable(GL_PROGRAM_POINT_SIZE); + if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) + glEnable(GL_PROGRAM_POINT_SIZE); } FramebufferManager::~FramebufferManager() { - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); - GLuint glObj[3]; + GLuint glObj[3]; - // Note: OpenGL deletion functions silently ignore parameters of "0". + // Note: OpenGL deletion functions silently ignore parameters of "0". - glDeleteFramebuffers(m_EFBLayers, m_efbFramebuffer.data()); - glDeleteFramebuffers(m_EFBLayers, m_resolvedFramebuffer.data()); + glDeleteFramebuffers(m_EFBLayers, m_efbFramebuffer.data()); + glDeleteFramebuffers(m_EFBLayers, m_resolvedFramebuffer.data()); - // Required, as these are static class members - m_efbFramebuffer.clear(); - m_resolvedFramebuffer.clear(); + // Required, as these are static class members + m_efbFramebuffer.clear(); + m_resolvedFramebuffer.clear(); - glDeleteFramebuffers(1, &m_xfbFramebuffer); - m_xfbFramebuffer = 0; + glDeleteFramebuffers(1, &m_xfbFramebuffer); + m_xfbFramebuffer = 0; - glObj[0] = m_resolvedColorTexture; - glObj[1] = m_resolvedDepthTexture; - glDeleteTextures(2, glObj); - m_resolvedColorTexture = 0; - m_resolvedDepthTexture = 0; + glObj[0] = m_resolvedColorTexture; + glObj[1] = m_resolvedDepthTexture; + glDeleteTextures(2, glObj); + m_resolvedColorTexture = 0; + m_resolvedDepthTexture = 0; - glObj[0] = m_efbColor; - glObj[1] = m_efbDepth; - glObj[2] = m_efbColorSwap; - glDeleteTextures(3, glObj); - m_efbColor = 0; - m_efbDepth = 0; - m_efbColorSwap = 0; + glObj[0] = m_efbColor; + glObj[1] = m_efbDepth; + glObj[2] = m_efbColorSwap; + glDeleteTextures(3, glObj); + m_efbColor = 0; + m_efbDepth = 0; + m_efbColorSwap = 0; - // reinterpret pixel format - m_pixel_format_shaders[0].Destroy(); - m_pixel_format_shaders[1].Destroy(); + // reinterpret pixel format + m_pixel_format_shaders[0].Destroy(); + m_pixel_format_shaders[1].Destroy(); - // EFB pokes - glDeleteBuffers(1, &m_EfbPokes_VBO); - glDeleteVertexArrays(1, &m_EfbPokes_VAO); - m_EfbPokes_VBO = 0; - m_EfbPokes_VAO = 0; - m_EfbPokes.Destroy(); + // EFB pokes + glDeleteBuffers(1, &m_EfbPokes_VBO); + glDeleteVertexArrays(1, &m_EfbPokes_VAO); + m_EfbPokes_VBO = 0; + m_EfbPokes_VAO = 0; + m_EfbPokes.Destroy(); } GLuint FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc) { - if (m_msaaSamples <= 1) - { - return m_efbColor; - } - else - { - // Transfer the EFB to a resolved texture. EXT_framebuffer_blit is - // required. + if (m_msaaSamples <= 1) + { + return m_efbColor; + } + else + { + // Transfer the EFB to a resolved texture. EXT_framebuffer_blit is + // required. - TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc); - targetRc.ClampUL(0, 0, m_targetWidth, m_targetHeight); + TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc); + targetRc.ClampUL(0, 0, m_targetWidth, m_targetHeight); - // Resolve. - for (unsigned int i = 0; i < m_EFBLayers; i++) - { - glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer[i]); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer[i]); - glBlitFramebuffer( - targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, - targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, - GL_COLOR_BUFFER_BIT, GL_NEAREST - ); - } + // Resolve. + for (unsigned int i = 0; i < m_EFBLayers; i++) + { + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer[i]); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer[i]); + glBlitFramebuffer(targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, targetRc.left, + targetRc.top, targetRc.right, targetRc.bottom, GL_COLOR_BUFFER_BIT, + GL_NEAREST); + } - // Return to EFB. - glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]); + // Return to EFB. + glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]); - return m_resolvedColorTexture; - } + return m_resolvedColorTexture; + } } GLuint FramebufferManager::GetEFBDepthTexture(const EFBRectangle& sourceRc) { - if (m_msaaSamples <= 1) - { - return m_efbDepth; - } - else - { - // Transfer the EFB to a resolved texture. + if (m_msaaSamples <= 1) + { + return m_efbDepth; + } + else + { + // Transfer the EFB to a resolved texture. - TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc); - targetRc.ClampUL(0, 0, m_targetWidth, m_targetHeight); + TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc); + targetRc.ClampUL(0, 0, m_targetWidth, m_targetHeight); - // Resolve. - for (unsigned int i = 0; i < m_EFBLayers; i++) - { - glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer[i]); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer[i]); - glBlitFramebuffer( - targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, - targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, - GL_DEPTH_BUFFER_BIT, GL_NEAREST - ); - } + // Resolve. + for (unsigned int i = 0; i < m_EFBLayers; i++) + { + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer[i]); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer[i]); + glBlitFramebuffer(targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, targetRc.left, + targetRc.top, targetRc.right, targetRc.bottom, GL_DEPTH_BUFFER_BIT, + GL_NEAREST); + } - // Return to EFB. - glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]); + // Return to EFB. + glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]); - return m_resolvedDepthTexture; - } + return m_resolvedDepthTexture; + } } -void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma) +void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, + const EFBRectangle& sourceRc, float Gamma) { - u8* xfb_in_ram = Memory::GetPointer(xfbAddr); - if (!xfb_in_ram) - { - WARN_LOG(VIDEO, "Tried to copy to invalid XFB address"); - return; - } + u8* xfb_in_ram = Memory::GetPointer(xfbAddr); + if (!xfb_in_ram) + { + WARN_LOG(VIDEO, "Tried to copy to invalid XFB address"); + return; + } - TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc); - TextureConverter::EncodeToRamYUYV(ResolveAndGetRenderTarget(sourceRc), targetRc, xfb_in_ram, sourceRc.GetWidth(), fbStride, fbHeight); + TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc); + TextureConverter::EncodeToRamYUYV(ResolveAndGetRenderTarget(sourceRc), targetRc, xfb_in_ram, + sourceRc.GetWidth(), fbStride, fbHeight); } void FramebufferManager::SetFramebuffer(GLuint fb) { - glBindFramebuffer(GL_FRAMEBUFFER, fb != 0 ? fb : GetEFBFramebuffer()); + glBindFramebuffer(GL_FRAMEBUFFER, fb != 0 ? fb : GetEFBFramebuffer()); } -void FramebufferManager::FramebufferTexture(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +void FramebufferManager::FramebufferTexture(GLenum target, GLenum attachment, GLenum textarget, + GLuint texture, GLint level) { - if (textarget == GL_TEXTURE_2D_ARRAY || textarget == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) - { - if (m_EFBLayers > 1) - glFramebufferTexture(target, attachment, texture, level); - else - glFramebufferTextureLayer(target, attachment, texture, level, 0); - } - else - { - glFramebufferTexture2D(target, attachment, textarget, texture, level); - } + if (textarget == GL_TEXTURE_2D_ARRAY || textarget == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) + { + if (m_EFBLayers > 1) + glFramebufferTexture(target, attachment, texture, level); + else + glFramebufferTextureLayer(target, attachment, texture, level, 0); + } + else + { + glFramebufferTexture2D(target, attachment, textarget, texture, level); + } } // Apply AA if enabled -GLuint FramebufferManager::ResolveAndGetRenderTarget(const EFBRectangle &source_rect) +GLuint FramebufferManager::ResolveAndGetRenderTarget(const EFBRectangle& source_rect) { - return GetEFBColorTexture(source_rect); + return GetEFBColorTexture(source_rect); } -GLuint FramebufferManager::ResolveAndGetDepthTarget(const EFBRectangle &source_rect) +GLuint FramebufferManager::ResolveAndGetDepthTarget(const EFBRectangle& source_rect) { - return GetEFBDepthTexture(source_rect); + return GetEFBDepthTexture(source_rect); } void FramebufferManager::ReinterpretPixelData(unsigned int convtype) { - g_renderer->ResetAPIState(); + g_renderer->ResetAPIState(); - OpenGL_BindAttributelessVAO(); + OpenGL_BindAttributelessVAO(); - GLuint src_texture = 0; + GLuint src_texture = 0; - // We aren't allowed to render and sample the same texture in one draw call, - // so we have to create a new texture and overwrite it completely. - // To not allocate one big texture every time, we've allocated two on - // initialization and just swap them here: - src_texture = m_efbColor; - m_efbColor = m_efbColorSwap; - m_efbColorSwap = src_texture; - FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textureType, m_efbColor, 0); + // We aren't allowed to render and sample the same texture in one draw call, + // so we have to create a new texture and overwrite it completely. + // To not allocate one big texture every time, we've allocated two on + // initialization and just swap them here: + src_texture = m_efbColor; + m_efbColor = m_efbColorSwap; + m_efbColorSwap = src_texture; + FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textureType, m_efbColor, 0); - glViewport(0,0, m_targetWidth, m_targetHeight); - glActiveTexture(GL_TEXTURE9); - glBindTexture(m_textureType, src_texture); - g_sampler_cache->BindNearestSampler(9); + glViewport(0, 0, m_targetWidth, m_targetHeight); + glActiveTexture(GL_TEXTURE9); + glBindTexture(m_textureType, src_texture); + g_sampler_cache->BindNearestSampler(9); - m_pixel_format_shaders[convtype ? 1 : 0].Bind(); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glBindTexture(m_textureType, 0); + m_pixel_format_shaders[convtype ? 1 : 0].Bind(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindTexture(m_textureType, 0); - g_renderer->RestoreAPIState(); + g_renderer->RestoreAPIState(); } XFBSource::~XFBSource() { - glDeleteTextures(1, &texture); + glDeleteTextures(1, &texture); } void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) { - TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, texture); + TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, texture); } void XFBSource::CopyEFB(float Gamma) { - g_renderer->ResetAPIState(); + g_renderer->ResetAPIState(); - // Copy EFB data to XFB and restore render target again - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferManager::GetXFBFramebuffer()); + // Copy EFB data to XFB and restore render target again + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferManager::GetXFBFramebuffer()); - for (int i = 0; i < m_layers; i++) - { - // Bind EFB and texture layer - glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetEFBFramebuffer(i)); - glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, i); + for (int i = 0; i < m_layers; i++) + { + // Bind EFB and texture layer + glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetEFBFramebuffer(i)); + glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, i); - glBlitFramebuffer( - 0, 0, texWidth, texHeight, - 0, 0, texWidth, texHeight, - GL_COLOR_BUFFER_BIT, GL_NEAREST - ); - } + glBlitFramebuffer(0, 0, texWidth, texHeight, 0, 0, texWidth, texHeight, GL_COLOR_BUFFER_BIT, + GL_NEAREST); + } - // Return to EFB. - FramebufferManager::SetFramebuffer(0); - - g_renderer->RestoreAPIState(); + // Return to EFB. + FramebufferManager::SetFramebuffer(0); + g_renderer->RestoreAPIState(); } -std::unique_ptr FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) +std::unique_ptr FramebufferManager::CreateXFBSource(unsigned int target_width, + unsigned int target_height, + unsigned int layers) { - GLuint texture; + GLuint texture; - glGenTextures(1, &texture); + glGenTextures(1, &texture); - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D_ARRAY, texture); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, target_width, target_height, layers, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glActiveTexture(GL_TEXTURE9); + glBindTexture(GL_TEXTURE_2D_ARRAY, texture); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, target_width, target_height, layers, 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr); - return std::make_unique(texture, layers); + return std::make_unique(texture, layers); } -void FramebufferManager::GetTargetSize(unsigned int *width, unsigned int *height) +void FramebufferManager::GetTargetSize(unsigned int* width, unsigned int* height) { - *width = m_targetWidth; - *height = m_targetHeight; + *width = m_targetWidth; + *height = m_targetHeight; } void FramebufferManager::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) { - g_renderer->ResetAPIState(); + g_renderer->ResetAPIState(); - if (type == POKE_Z) - { - glDepthMask(GL_TRUE); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - } + if (type == POKE_Z) + { + glDepthMask(GL_TRUE); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + } - glBindVertexArray(m_EfbPokes_VAO); - glBindBuffer(GL_ARRAY_BUFFER, m_EfbPokes_VBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(EfbPokeData) * num_points, points, GL_STREAM_DRAW); - m_EfbPokes.Bind(); - glViewport(0, 0, m_targetWidth, m_targetHeight); - glDrawArrays(GL_POINTS, 0, (GLsizei)num_points); + glBindVertexArray(m_EfbPokes_VAO); + glBindBuffer(GL_ARRAY_BUFFER, m_EfbPokes_VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(EfbPokeData) * num_points, points, GL_STREAM_DRAW); + m_EfbPokes.Bind(); + glViewport(0, 0, m_targetWidth, m_targetHeight); + glDrawArrays(GL_POINTS, 0, (GLsizei)num_points); - g_renderer->RestoreAPIState(); + g_renderer->RestoreAPIState(); - // TODO: Could just update the EFB cache with the new value - ClearEFBCache(); + // TODO: Could just update the EFB cache with the new value + ClearEFBCache(); } } // namespace OGL diff --git a/Source/Core/VideoBackends/OGL/FramebufferManager.h b/Source/Core/VideoBackends/OGL/FramebufferManager.h index e9e53ec9db..5079cfe618 100644 --- a/Source/Core/VideoBackends/OGL/FramebufferManager.h +++ b/Source/Core/VideoBackends/OGL/FramebufferManager.h @@ -46,84 +46,92 @@ namespace OGL { - struct XFBSource : public XFBSourceBase { - XFBSource(GLuint tex, int layers) : texture(tex), m_layers(layers) {} - ~XFBSource(); + XFBSource(GLuint tex, int layers) : texture(tex), m_layers(layers) {} + ~XFBSource(); - void CopyEFB(float Gamma) override; - void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override; + void CopyEFB(float Gamma) override; + void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override; - const GLuint texture; - const int m_layers; + const GLuint texture; + const int m_layers; }; class FramebufferManager : public FramebufferManagerBase { public: - FramebufferManager(int targetWidth, int targetHeight, int msaaSamples); - ~FramebufferManager(); + FramebufferManager(int targetWidth, int targetHeight, int msaaSamples); + ~FramebufferManager(); - // To get the EFB in texture form, these functions may have to transfer - // the EFB to a resolved texture first. - static GLuint GetEFBColorTexture(const EFBRectangle& sourceRc); - static GLuint GetEFBDepthTexture(const EFBRectangle& sourceRc); + // To get the EFB in texture form, these functions may have to transfer + // the EFB to a resolved texture first. + static GLuint GetEFBColorTexture(const EFBRectangle& sourceRc); + static GLuint GetEFBDepthTexture(const EFBRectangle& sourceRc); - static GLuint GetEFBFramebuffer(unsigned int layer = 0) { return (layer < m_EFBLayers) ? m_efbFramebuffer[layer] : m_efbFramebuffer.back(); } - static GLuint GetXFBFramebuffer() { return m_xfbFramebuffer; } + static GLuint GetEFBFramebuffer(unsigned int layer = 0) + { + return (layer < m_EFBLayers) ? m_efbFramebuffer[layer] : m_efbFramebuffer.back(); + } + static GLuint GetXFBFramebuffer() { return m_xfbFramebuffer; } + // Resolved framebuffer is only used in MSAA mode. + static GLuint GetResolvedFramebuffer() { return m_resolvedFramebuffer[0]; } + static void SetFramebuffer(GLuint fb); + static void FramebufferTexture(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, + GLint level); - // Resolved framebuffer is only used in MSAA mode. - static GLuint GetResolvedFramebuffer() { return m_resolvedFramebuffer[0]; } + // If in MSAA mode, this will perform a resolve of the specified rectangle, and return the resolve + // target as a texture ID. + // Thus, this call may be expensive. Don't repeat it unnecessarily. + // If not in MSAA mode, will just return the render target texture ID. + // After calling this, before you render anything else, you MUST bind the framebuffer you want to + // draw to. + static GLuint ResolveAndGetRenderTarget(const EFBRectangle& rect); - static void SetFramebuffer(GLuint fb); - static void FramebufferTexture(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); + // Same as above but for the depth Target. + // After calling this, before you render anything else, you MUST bind the framebuffer you want to + // draw to. + static GLuint ResolveAndGetDepthTarget(const EFBRectangle& rect); - // If in MSAA mode, this will perform a resolve of the specified rectangle, and return the resolve target as a texture ID. - // Thus, this call may be expensive. Don't repeat it unnecessarily. - // If not in MSAA mode, will just return the render target texture ID. - // After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to. - static GLuint ResolveAndGetRenderTarget(const EFBRectangle &rect); + // Convert EFB content on pixel format change. + // convtype=0 -> rgb8->rgba6, convtype=2 -> rgba6->rgb8 + static void ReinterpretPixelData(unsigned int convtype); - // Same as above but for the depth Target. - // After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to. - static GLuint ResolveAndGetDepthTarget(const EFBRectangle &rect); - - // Convert EFB content on pixel format change. - // convtype=0 -> rgb8->rgba6, convtype=2 -> rgba6->rgb8 - static void ReinterpretPixelData(unsigned int convtype); - - static void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points); + static void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points); private: - std::unique_ptr CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) override; - void GetTargetSize(unsigned int *width, unsigned int *height) override; + std::unique_ptr CreateXFBSource(unsigned int target_width, + unsigned int target_height, + unsigned int layers) override; + void GetTargetSize(unsigned int* width, unsigned int* height) override; - void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma) override; + void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, + float Gamma) override; - static int m_targetWidth; - static int m_targetHeight; - static int m_msaaSamples; + static int m_targetWidth; + static int m_targetHeight; + static int m_msaaSamples; - static GLenum m_textureType; - static std::vector m_efbFramebuffer; - static GLuint m_xfbFramebuffer; - static GLuint m_efbColor; - static GLuint m_efbDepth; - static GLuint m_efbColorSwap;// will be hot swapped with m_efbColor when reinterpreting EFB pixel formats + static GLenum m_textureType; + static std::vector m_efbFramebuffer; + static GLuint m_xfbFramebuffer; + static GLuint m_efbColor; + static GLuint m_efbDepth; + static GLuint + m_efbColorSwap; // will be hot swapped with m_efbColor when reinterpreting EFB pixel formats - // Only used in MSAA mode, TODO: try to avoid them - static std::vector m_resolvedFramebuffer; - static GLuint m_resolvedColorTexture; - static GLuint m_resolvedDepthTexture; + // Only used in MSAA mode, TODO: try to avoid them + static std::vector m_resolvedFramebuffer; + static GLuint m_resolvedColorTexture; + static GLuint m_resolvedDepthTexture; - // For pixel format draw - static SHADER m_pixel_format_shaders[2]; + // For pixel format draw + static SHADER m_pixel_format_shaders[2]; - // For EFB pokes - static GLuint m_EfbPokes_VBO; - static GLuint m_EfbPokes_VAO; - static SHADER m_EfbPokes; + // For EFB pokes + static GLuint m_EfbPokes_VBO; + static GLuint m_EfbPokes_VAO; + static SHADER m_EfbPokes; }; } // namespace OGL diff --git a/Source/Core/VideoBackends/OGL/NativeVertexFormat.cpp b/Source/Core/VideoBackends/OGL/NativeVertexFormat.cpp index 68b8e1b2d6..93a8c18d40 100644 --- a/Source/Core/VideoBackends/OGL/NativeVertexFormat.cpp +++ b/Source/Core/VideoBackends/OGL/NativeVertexFormat.cpp @@ -3,10 +3,10 @@ // Refer to the license.txt file included. #include "Common/Common.h" +#include "Common/GL/GLUtil.h" #include "Common/MemoryUtil.h" #include "Common/x64ABI.h" #include "Common/x64Emitter.h" -#include "Common/GL/GLUtil.h" #include "VideoBackends/OGL/ProgramShaderCache.h" #include "VideoBackends/OGL/VertexManager.h" @@ -20,73 +20,73 @@ namespace OGL { - -NativeVertexFormat* VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) +NativeVertexFormat* +VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) { - return new GLVertexFormat(vtx_decl); + return new GLVertexFormat(vtx_decl); } static inline GLuint VarToGL(VarType t) { - static const GLuint lookup[5] = { - GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, GL_FLOAT - }; - return lookup[t]; + static const GLuint lookup[5] = {GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, + GL_FLOAT}; + return lookup[t]; } -static void SetPointer(u32 attrib, u32 stride, const AttributeFormat &format) +static void SetPointer(u32 attrib, u32 stride, const AttributeFormat& format) { - if (!format.enable) - return; + if (!format.enable) + return; - glEnableVertexAttribArray(attrib); - if (format.integer) - glVertexAttribIPointer(attrib, format.components, VarToGL(format.type), stride, (u8*)nullptr + format.offset); - else - glVertexAttribPointer(attrib, format.components, VarToGL(format.type), true, stride, (u8*)nullptr + format.offset); + glEnableVertexAttribArray(attrib); + if (format.integer) + glVertexAttribIPointer(attrib, format.components, VarToGL(format.type), stride, + (u8*)nullptr + format.offset); + else + glVertexAttribPointer(attrib, format.components, VarToGL(format.type), true, stride, + (u8*)nullptr + format.offset); } GLVertexFormat::GLVertexFormat(const PortableVertexDeclaration& _vtx_decl) { - this->vtx_decl = _vtx_decl; - u32 vertex_stride = _vtx_decl.stride; + this->vtx_decl = _vtx_decl; + u32 vertex_stride = _vtx_decl.stride; - // We will not allow vertex components causing uneven strides. - if (vertex_stride & 3) - PanicAlert("Uneven vertex stride: %i", vertex_stride); + // We will not allow vertex components causing uneven strides. + if (vertex_stride & 3) + PanicAlert("Uneven vertex stride: %i", vertex_stride); - VertexManager* const vm = static_cast(g_vertex_manager.get()); + VertexManager* const vm = static_cast(g_vertex_manager.get()); - glGenVertexArrays(1, &VAO); - glBindVertexArray(VAO); + glGenVertexArrays(1, &VAO); + glBindVertexArray(VAO); - // the element buffer is bound directly to the vao, so we must it set for every vao - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vm->m_index_buffers); - glBindBuffer(GL_ARRAY_BUFFER, vm->m_vertex_buffers); + // the element buffer is bound directly to the vao, so we must it set for every vao + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vm->m_index_buffers); + glBindBuffer(GL_ARRAY_BUFFER, vm->m_vertex_buffers); - SetPointer(SHADER_POSITION_ATTRIB, vertex_stride, _vtx_decl.position); + SetPointer(SHADER_POSITION_ATTRIB, vertex_stride, _vtx_decl.position); - for (int i = 0; i < 3; i++) - SetPointer(SHADER_NORM0_ATTRIB+i, vertex_stride, _vtx_decl.normals[i]); + for (int i = 0; i < 3; i++) + SetPointer(SHADER_NORM0_ATTRIB + i, vertex_stride, _vtx_decl.normals[i]); - for (int i = 0; i < 2; i++) - SetPointer(SHADER_COLOR0_ATTRIB+i, vertex_stride, _vtx_decl.colors[i]); + for (int i = 0; i < 2; i++) + SetPointer(SHADER_COLOR0_ATTRIB + i, vertex_stride, _vtx_decl.colors[i]); - for (int i = 0; i < 8; i++) - SetPointer(SHADER_TEXTURE0_ATTRIB+i, vertex_stride, _vtx_decl.texcoords[i]); + for (int i = 0; i < 8; i++) + SetPointer(SHADER_TEXTURE0_ATTRIB + i, vertex_stride, _vtx_decl.texcoords[i]); - SetPointer(SHADER_POSMTX_ATTRIB, vertex_stride, _vtx_decl.posmtx); + SetPointer(SHADER_POSMTX_ATTRIB, vertex_stride, _vtx_decl.posmtx); - vm->m_last_vao = VAO; + vm->m_last_vao = VAO; } GLVertexFormat::~GLVertexFormat() { - glDeleteVertexArrays(1, &VAO); + glDeleteVertexArrays(1, &VAO); } void GLVertexFormat::SetupVertexPointers() { } - } diff --git a/Source/Core/VideoBackends/OGL/PerfQuery.cpp b/Source/Core/VideoBackends/OGL/PerfQuery.cpp index 9fac58aa5f..cbe4ff7056 100644 --- a/Source/Core/VideoBackends/OGL/PerfQuery.cpp +++ b/Source/Core/VideoBackends/OGL/PerfQuery.cpp @@ -16,243 +16,243 @@ namespace OGL { std::unique_ptr GetPerfQuery() { - if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3 && - GLExtensions::Supports("GL_NV_occlusion_query_samples")) - return std::make_unique(); + if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3 && + GLExtensions::Supports("GL_NV_occlusion_query_samples")) + return std::make_unique(); - if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3) - return std::make_unique(GL_ANY_SAMPLES_PASSED); + if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3) + return std::make_unique(GL_ANY_SAMPLES_PASSED); - return std::make_unique(GL_SAMPLES_PASSED); + return std::make_unique(GL_SAMPLES_PASSED); } -PerfQuery::PerfQuery() - : m_query_read_pos() +PerfQuery::PerfQuery() : m_query_read_pos() { - ResetQuery(); + ResetQuery(); } void PerfQuery::EnableQuery(PerfQueryGroup type) { - m_query->EnableQuery(type); + m_query->EnableQuery(type); } void PerfQuery::DisableQuery(PerfQueryGroup type) { - m_query->DisableQuery(type); + m_query->DisableQuery(type); } bool PerfQuery::IsFlushed() const { - return 0 == m_query_count; + return 0 == m_query_count; } // TODO: could selectively flush things, but I don't think that will do much void PerfQuery::FlushResults() { - m_query->FlushResults(); + m_query->FlushResults(); } void PerfQuery::ResetQuery() { - m_query_count = 0; - std::fill_n(m_results, ArraySize(m_results), 0); + m_query_count = 0; + std::fill_n(m_results, ArraySize(m_results), 0); } u32 PerfQuery::GetQueryResult(PerfQueryType type) { - u32 result = 0; + u32 result = 0; - if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC) - { - result = m_results[PQG_ZCOMP_ZCOMPLOC]; - } - else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT) - { - result = m_results[PQG_ZCOMP]; - } - else if (type == PQ_BLEND_INPUT) - { - result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC]; - } - else if (type == PQ_EFB_COPY_CLOCKS) - { - result = m_results[PQG_EFB_COPY_CLOCKS]; - } + if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC) + { + result = m_results[PQG_ZCOMP_ZCOMPLOC]; + } + else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT) + { + result = m_results[PQG_ZCOMP]; + } + else if (type == PQ_BLEND_INPUT) + { + result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC]; + } + else if (type == PQ_EFB_COPY_CLOCKS) + { + result = m_results[PQG_EFB_COPY_CLOCKS]; + } - return result / 4; + return result / 4; } // Implementations -PerfQueryGL::PerfQueryGL(GLenum query_type) - : m_query_type(query_type) +PerfQueryGL::PerfQueryGL(GLenum query_type) : m_query_type(query_type) { - for (ActiveQuery& query : m_query_buffer) - glGenQueries(1, &query.query_id); + for (ActiveQuery& query : m_query_buffer) + glGenQueries(1, &query.query_id); } PerfQueryGL::~PerfQueryGL() { - for (ActiveQuery& query : m_query_buffer) - glDeleteQueries(1, &query.query_id); + for (ActiveQuery& query : m_query_buffer) + glDeleteQueries(1, &query.query_id); } void PerfQueryGL::EnableQuery(PerfQueryGroup type) { - // Is this sane? - if (m_query_count > m_query_buffer.size() / 2) - WeakFlush(); + // Is this sane? + if (m_query_count > m_query_buffer.size() / 2) + WeakFlush(); - if (m_query_buffer.size() == m_query_count) - { - FlushOne(); - //ERROR_LOG(VIDEO, "Flushed query buffer early!"); - } + if (m_query_buffer.size() == m_query_count) + { + FlushOne(); + // ERROR_LOG(VIDEO, "Flushed query buffer early!"); + } - // start query - if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) - { - auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % m_query_buffer.size()]; + // start query + if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) + { + auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % m_query_buffer.size()]; - glBeginQuery(m_query_type, entry.query_id); - entry.query_type = type; + glBeginQuery(m_query_type, entry.query_id); + entry.query_type = type; - ++m_query_count; - } + ++m_query_count; + } } void PerfQueryGL::DisableQuery(PerfQueryGroup type) { - // stop query - if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) - { - glEndQuery(m_query_type); - } + // stop query + if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) + { + glEndQuery(m_query_type); + } } void PerfQueryGL::WeakFlush() { - while (!IsFlushed()) - { - auto& entry = m_query_buffer[m_query_read_pos]; + while (!IsFlushed()) + { + auto& entry = m_query_buffer[m_query_read_pos]; - GLuint result = GL_FALSE; - glGetQueryObjectuiv(entry.query_id, GL_QUERY_RESULT_AVAILABLE, &result); + GLuint result = GL_FALSE; + glGetQueryObjectuiv(entry.query_id, GL_QUERY_RESULT_AVAILABLE, &result); - if (GL_TRUE == result) - { - FlushOne(); - } - else - { - break; - } - } + if (GL_TRUE == result) + { + FlushOne(); + } + else + { + break; + } + } } void PerfQueryGL::FlushOne() { - auto& entry = m_query_buffer[m_query_read_pos]; + auto& entry = m_query_buffer[m_query_read_pos]; - GLuint result = 0; - glGetQueryObjectuiv(entry.query_id, GL_QUERY_RESULT, &result); + GLuint result = 0; + glGetQueryObjectuiv(entry.query_id, GL_QUERY_RESULT, &result); - // NOTE: Reported pixel metrics should be referenced to native resolution - m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight(); + // NOTE: Reported pixel metrics should be referenced to native resolution + m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * + EFB_HEIGHT / g_renderer->GetTargetHeight(); - m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size(); - --m_query_count; + m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size(); + --m_query_count; } // TODO: could selectively flush things, but I don't think that will do much void PerfQueryGL::FlushResults() { - while (!IsFlushed()) - FlushOne(); + while (!IsFlushed()) + FlushOne(); } PerfQueryGLESNV::PerfQueryGLESNV() { - for (ActiveQuery& query : m_query_buffer) - glGenOcclusionQueriesNV(1, &query.query_id); + for (ActiveQuery& query : m_query_buffer) + glGenOcclusionQueriesNV(1, &query.query_id); } PerfQueryGLESNV::~PerfQueryGLESNV() { - for (ActiveQuery& query : m_query_buffer) - glDeleteOcclusionQueriesNV(1, &query.query_id); + for (ActiveQuery& query : m_query_buffer) + glDeleteOcclusionQueriesNV(1, &query.query_id); } void PerfQueryGLESNV::EnableQuery(PerfQueryGroup type) { - // Is this sane? - if (m_query_count > m_query_buffer.size() / 2) - WeakFlush(); + // Is this sane? + if (m_query_count > m_query_buffer.size() / 2) + WeakFlush(); - if (m_query_buffer.size() == m_query_count) - { - FlushOne(); - //ERROR_LOG(VIDEO, "Flushed query buffer early!"); - } + if (m_query_buffer.size() == m_query_count) + { + FlushOne(); + // ERROR_LOG(VIDEO, "Flushed query buffer early!"); + } - // start query - if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) - { - auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % m_query_buffer.size()]; + // start query + if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) + { + auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % m_query_buffer.size()]; - glBeginOcclusionQueryNV(entry.query_id); - entry.query_type = type; + glBeginOcclusionQueryNV(entry.query_id); + entry.query_type = type; - ++m_query_count; - } + ++m_query_count; + } } void PerfQueryGLESNV::DisableQuery(PerfQueryGroup type) { - // stop query - if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) - { - glEndOcclusionQueryNV(); - } + // stop query + if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP) + { + glEndOcclusionQueryNV(); + } } void PerfQueryGLESNV::WeakFlush() { - while (!IsFlushed()) - { - auto& entry = m_query_buffer[m_query_read_pos]; + while (!IsFlushed()) + { + auto& entry = m_query_buffer[m_query_read_pos]; - GLuint result = GL_FALSE; - glGetOcclusionQueryuivNV(entry.query_id, GL_PIXEL_COUNT_AVAILABLE_NV, &result); + GLuint result = GL_FALSE; + glGetOcclusionQueryuivNV(entry.query_id, GL_PIXEL_COUNT_AVAILABLE_NV, &result); - if (GL_TRUE == result) - { - FlushOne(); - } - else - { - break; - } - } + if (GL_TRUE == result) + { + FlushOne(); + } + else + { + break; + } + } } void PerfQueryGLESNV::FlushOne() { - auto& entry = m_query_buffer[m_query_read_pos]; + auto& entry = m_query_buffer[m_query_read_pos]; - GLuint result = 0; - glGetOcclusionQueryuivNV(entry.query_id, GL_OCCLUSION_TEST_RESULT_HP, &result); + GLuint result = 0; + glGetOcclusionQueryuivNV(entry.query_id, GL_OCCLUSION_TEST_RESULT_HP, &result); - // NOTE: Reported pixel metrics should be referenced to native resolution - m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight(); + // NOTE: Reported pixel metrics should be referenced to native resolution + m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * + EFB_HEIGHT / g_renderer->GetTargetHeight(); - m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size(); - --m_query_count; + m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size(); + --m_query_count; } // TODO: could selectively flush things, but I don't think that will do much void PerfQueryGLESNV::FlushResults() { - while (!IsFlushed()) - FlushOne(); + while (!IsFlushed()) + FlushOne(); } -} // namespace +} // namespace diff --git a/Source/Core/VideoBackends/OGL/PerfQuery.h b/Source/Core/VideoBackends/OGL/PerfQuery.h index de9fc9ad19..8becce755d 100644 --- a/Source/Core/VideoBackends/OGL/PerfQuery.h +++ b/Source/Core/VideoBackends/OGL/PerfQuery.h @@ -18,71 +18,67 @@ std::unique_ptr GetPerfQuery(); class PerfQuery : public PerfQueryBase { public: - PerfQuery(); - ~PerfQuery() {} - - void EnableQuery(PerfQueryGroup type) override; - void DisableQuery(PerfQueryGroup type) override; - void ResetQuery() override; - u32 GetQueryResult(PerfQueryType type) override; - void FlushResults() override; - bool IsFlushed() const override; + PerfQuery(); + ~PerfQuery() {} + void EnableQuery(PerfQueryGroup type) override; + void DisableQuery(PerfQueryGroup type) override; + void ResetQuery() override; + u32 GetQueryResult(PerfQueryType type) override; + void FlushResults() override; + bool IsFlushed() const override; protected: - struct ActiveQuery - { - GLuint query_id; - PerfQueryGroup query_type; - }; + struct ActiveQuery + { + GLuint query_id; + PerfQueryGroup query_type; + }; - // when testing in SMS: 64 was too small, 128 was ok - static const u32 PERF_QUERY_BUFFER_SIZE = 512; + // when testing in SMS: 64 was too small, 128 was ok + static const u32 PERF_QUERY_BUFFER_SIZE = 512; - // This contains gl query objects with unretrieved results. - std::array m_query_buffer; - u32 m_query_read_pos; + // This contains gl query objects with unretrieved results. + std::array m_query_buffer; + u32 m_query_read_pos; private: - // Implementation - std::unique_ptr m_query; + // Implementation + std::unique_ptr m_query; }; // Implementations class PerfQueryGL : public PerfQuery { public: - PerfQueryGL(GLenum query_type); - ~PerfQueryGL(); + PerfQueryGL(GLenum query_type); + ~PerfQueryGL(); - void EnableQuery(PerfQueryGroup type) override; - void DisableQuery(PerfQueryGroup type) override; - void FlushResults() override; + void EnableQuery(PerfQueryGroup type) override; + void DisableQuery(PerfQueryGroup type) override; + void FlushResults() override; private: + void WeakFlush(); + // Only use when non-empty + void FlushOne(); - void WeakFlush(); - // Only use when non-empty - void FlushOne(); - - GLenum m_query_type; + GLenum m_query_type; }; class PerfQueryGLESNV : public PerfQuery { public: - PerfQueryGLESNV(); - ~PerfQueryGLESNV(); + PerfQueryGLESNV(); + ~PerfQueryGLESNV(); - void EnableQuery(PerfQueryGroup type) override; - void DisableQuery(PerfQueryGroup type) override; - void FlushResults() override; + void EnableQuery(PerfQueryGroup type) override; + void DisableQuery(PerfQueryGroup type) override; + void FlushResults() override; private: - - void WeakFlush(); - // Only use when non-empty - void FlushOne(); + void WeakFlush(); + // Only use when non-empty + void FlushOne(); }; - -} // namespace +} // namespace diff --git a/Source/Core/VideoBackends/OGL/PostProcessing.cpp b/Source/Core/VideoBackends/OGL/PostProcessing.cpp index 636c338281..ed7b7250b8 100644 --- a/Source/Core/VideoBackends/OGL/PostProcessing.cpp +++ b/Source/Core/VideoBackends/OGL/PostProcessing.cpp @@ -20,262 +20,254 @@ namespace OGL { +static const char s_vertex_shader[] = "out vec2 uv0;\n" + "uniform vec4 src_rect;\n" + "void main(void) {\n" + " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" + " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" + " uv0 = rawpos * src_rect.zw + src_rect.xy;\n" + "}\n"; -static const char s_vertex_shader[] = - "out vec2 uv0;\n" - "uniform vec4 src_rect;\n" - "void main(void) {\n" - " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" - " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" - " uv0 = rawpos * src_rect.zw + src_rect.xy;\n" - "}\n"; - -OpenGLPostProcessing::OpenGLPostProcessing() - : m_initialized(false) +OpenGLPostProcessing::OpenGLPostProcessing() : m_initialized(false) { - CreateHeader(); + CreateHeader(); } OpenGLPostProcessing::~OpenGLPostProcessing() { - m_shader.Destroy(); + m_shader.Destroy(); } void OpenGLPostProcessing::BlitFromTexture(TargetRectangle src, TargetRectangle dst, - int src_texture, int src_width, int src_height, int layer) + int src_texture, int src_width, int src_height, + int layer) { - ApplyShader(); + ApplyShader(); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - glViewport(dst.left, dst.bottom, dst.GetWidth(), dst.GetHeight()); + glViewport(dst.left, dst.bottom, dst.GetWidth(), dst.GetHeight()); - OpenGL_BindAttributelessVAO(); + OpenGL_BindAttributelessVAO(); - m_shader.Bind(); + m_shader.Bind(); - glUniform4f(m_uniform_resolution, (float)src_width, (float)src_height, 1.0f / (float)src_width, 1.0f / (float)src_height); - glUniform4f(m_uniform_src_rect, src.left / (float) src_width, src.bottom / (float) src_height, - src.GetWidth() / (float) src_width, src.GetHeight() / (float) src_height); - glUniform1ui(m_uniform_time, (GLuint)m_timer.GetTimeElapsed()); - glUniform1i(m_uniform_layer, layer); + glUniform4f(m_uniform_resolution, (float)src_width, (float)src_height, 1.0f / (float)src_width, + 1.0f / (float)src_height); + glUniform4f(m_uniform_src_rect, src.left / (float)src_width, src.bottom / (float)src_height, + src.GetWidth() / (float)src_width, src.GetHeight() / (float)src_height); + glUniform1ui(m_uniform_time, (GLuint)m_timer.GetTimeElapsed()); + glUniform1i(m_uniform_layer, layer); - if (m_config.IsDirty()) - { - for (auto& it : m_config.GetOptions()) - { - if (it.second.m_dirty) - { - switch (it.second.m_type) - { - case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL: - glUniform1i(m_uniform_bindings[it.first], it.second.m_bool_value); - break; - case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER: - switch (it.second.m_integer_values.size()) - { - case 1: - glUniform1i(m_uniform_bindings[it.first], it.second.m_integer_values[0]); - break; - case 2: - glUniform2i(m_uniform_bindings[it.first], - it.second.m_integer_values[0], - it.second.m_integer_values[1]); - break; - case 3: - glUniform3i(m_uniform_bindings[it.first], - it.second.m_integer_values[0], - it.second.m_integer_values[1], - it.second.m_integer_values[2]); - break; - case 4: - glUniform4i(m_uniform_bindings[it.first], - it.second.m_integer_values[0], - it.second.m_integer_values[1], - it.second.m_integer_values[2], - it.second.m_integer_values[3]); - break; - } - break; - case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_FLOAT: - switch (it.second.m_float_values.size()) - { - case 1: - glUniform1f(m_uniform_bindings[it.first], it.second.m_float_values[0]); - break; - case 2: - glUniform2f(m_uniform_bindings[it.first], - it.second.m_float_values[0], - it.second.m_float_values[1]); - break; - case 3: - glUniform3f(m_uniform_bindings[it.first], - it.second.m_float_values[0], - it.second.m_float_values[1], - it.second.m_float_values[2]); - break; - case 4: - glUniform4f(m_uniform_bindings[it.first], - it.second.m_float_values[0], - it.second.m_float_values[1], - it.second.m_float_values[2], - it.second.m_float_values[3]); - break; - } - break; - } - it.second.m_dirty = false; - } - } - m_config.SetDirty(false); - } + if (m_config.IsDirty()) + { + for (auto& it : m_config.GetOptions()) + { + if (it.second.m_dirty) + { + switch (it.second.m_type) + { + case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL: + glUniform1i(m_uniform_bindings[it.first], it.second.m_bool_value); + break; + case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER: + switch (it.second.m_integer_values.size()) + { + case 1: + glUniform1i(m_uniform_bindings[it.first], it.second.m_integer_values[0]); + break; + case 2: + glUniform2i(m_uniform_bindings[it.first], it.second.m_integer_values[0], + it.second.m_integer_values[1]); + break; + case 3: + glUniform3i(m_uniform_bindings[it.first], it.second.m_integer_values[0], + it.second.m_integer_values[1], it.second.m_integer_values[2]); + break; + case 4: + glUniform4i(m_uniform_bindings[it.first], it.second.m_integer_values[0], + it.second.m_integer_values[1], it.second.m_integer_values[2], + it.second.m_integer_values[3]); + break; + } + break; + case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_FLOAT: + switch (it.second.m_float_values.size()) + { + case 1: + glUniform1f(m_uniform_bindings[it.first], it.second.m_float_values[0]); + break; + case 2: + glUniform2f(m_uniform_bindings[it.first], it.second.m_float_values[0], + it.second.m_float_values[1]); + break; + case 3: + glUniform3f(m_uniform_bindings[it.first], it.second.m_float_values[0], + it.second.m_float_values[1], it.second.m_float_values[2]); + break; + case 4: + glUniform4f(m_uniform_bindings[it.first], it.second.m_float_values[0], + it.second.m_float_values[1], it.second.m_float_values[2], + it.second.m_float_values[3]); + break; + } + break; + } + it.second.m_dirty = false; + } + } + m_config.SetDirty(false); + } - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D_ARRAY, src_texture); - g_sampler_cache->BindLinearSampler(9); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glActiveTexture(GL_TEXTURE9); + glBindTexture(GL_TEXTURE_2D_ARRAY, src_texture); + g_sampler_cache->BindLinearSampler(9); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } void OpenGLPostProcessing::ApplyShader() { - // shader didn't changed - if (m_initialized && m_config.GetShader() == g_ActiveConfig.sPostProcessingShader) - return; + // shader didn't changed + if (m_initialized && m_config.GetShader() == g_ActiveConfig.sPostProcessingShader) + return; - m_shader.Destroy(); - m_uniform_bindings.clear(); + m_shader.Destroy(); + m_uniform_bindings.clear(); - // load shader code - std::string code = m_config.LoadShader(); - code = LoadShaderOptions(code); + // load shader code + std::string code = m_config.LoadShader(); + code = LoadShaderOptions(code); - // and compile it - if (!ProgramShaderCache::CompileShader(m_shader, s_vertex_shader, code)) - { - ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", m_config.GetShader().c_str()); - g_ActiveConfig.sPostProcessingShader.clear(); - code = m_config.LoadShader(); - ProgramShaderCache::CompileShader(m_shader, s_vertex_shader, code); - } + // and compile it + if (!ProgramShaderCache::CompileShader(m_shader, s_vertex_shader, code)) + { + ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", m_config.GetShader().c_str()); + g_ActiveConfig.sPostProcessingShader.clear(); + code = m_config.LoadShader(); + ProgramShaderCache::CompileShader(m_shader, s_vertex_shader, code); + } - // read uniform locations - m_uniform_resolution = glGetUniformLocation(m_shader.glprogid, "resolution"); - m_uniform_time = glGetUniformLocation(m_shader.glprogid, "time"); - m_uniform_src_rect = glGetUniformLocation(m_shader.glprogid, "src_rect"); - m_uniform_layer = glGetUniformLocation(m_shader.glprogid, "layer"); + // read uniform locations + m_uniform_resolution = glGetUniformLocation(m_shader.glprogid, "resolution"); + m_uniform_time = glGetUniformLocation(m_shader.glprogid, "time"); + m_uniform_src_rect = glGetUniformLocation(m_shader.glprogid, "src_rect"); + m_uniform_layer = glGetUniformLocation(m_shader.glprogid, "layer"); - for (const auto& it : m_config.GetOptions()) - { - std::string glsl_name = "option_" + it.first; - m_uniform_bindings[it.first] = glGetUniformLocation(m_shader.glprogid, glsl_name.c_str()); - } - m_initialized = true; + for (const auto& it : m_config.GetOptions()) + { + std::string glsl_name = "option_" + it.first; + m_uniform_bindings[it.first] = glGetUniformLocation(m_shader.glprogid, glsl_name.c_str()); + } + m_initialized = true; } void OpenGLPostProcessing::CreateHeader() { - m_glsl_header = - // Required variables - // Shouldn't be accessed directly by the PP shader - // Texture sampler - "SAMPLER_BINDING(8) uniform sampler2D samp8;\n" - "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" + m_glsl_header = + // Required variables + // Shouldn't be accessed directly by the PP shader + // Texture sampler + "SAMPLER_BINDING(8) uniform sampler2D samp8;\n" + "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" - // Output variable - "out float4 ocol0;\n" - // Input coordinates - "in float2 uv0;\n" - // Resolution - "uniform float4 resolution;\n" - // Time - "uniform uint time;\n" - // Layer - "uniform int layer;\n" + // Output variable + "out float4 ocol0;\n" + // Input coordinates + "in float2 uv0;\n" + // Resolution + "uniform float4 resolution;\n" + // Time + "uniform uint time;\n" + // Layer + "uniform int layer;\n" - // Interfacing functions - "float4 Sample()\n" - "{\n" - "\treturn texture(samp9, float3(uv0, layer));\n" - "}\n" + // Interfacing functions + "float4 Sample()\n" + "{\n" + "\treturn texture(samp9, float3(uv0, layer));\n" + "}\n" - "float4 SampleLocation(float2 location)\n" - "{\n" - "\treturn texture(samp9, float3(location, layer));\n" - "}\n" + "float4 SampleLocation(float2 location)\n" + "{\n" + "\treturn texture(samp9, float3(location, layer));\n" + "}\n" - "float4 SampleLayer(int layer)\n" - "{\n" - "\treturn texture(samp9, float3(uv0, layer));\n" - "}\n" + "float4 SampleLayer(int layer)\n" + "{\n" + "\treturn texture(samp9, float3(uv0, layer));\n" + "}\n" - "#define SampleOffset(offset) textureOffset(samp9, float3(uv0, layer), offset)\n" + "#define SampleOffset(offset) textureOffset(samp9, float3(uv0, layer), offset)\n" - "float4 SampleFontLocation(float2 location)\n" - "{\n" - "\treturn texture(samp8, location);\n" - "}\n" + "float4 SampleFontLocation(float2 location)\n" + "{\n" + "\treturn texture(samp8, location);\n" + "}\n" - "float2 GetResolution()\n" - "{\n" - "\treturn resolution.xy;\n" - "}\n" + "float2 GetResolution()\n" + "{\n" + "\treturn resolution.xy;\n" + "}\n" - "float2 GetInvResolution()\n" - "{\n" - "\treturn resolution.zw;\n" - "}\n" + "float2 GetInvResolution()\n" + "{\n" + "\treturn resolution.zw;\n" + "}\n" - "float2 GetCoordinates()\n" - "{\n" - "\treturn uv0;\n" - "}\n" + "float2 GetCoordinates()\n" + "{\n" + "\treturn uv0;\n" + "}\n" - "uint GetTime()\n" - "{\n" - "\treturn time;\n" - "}\n" + "uint GetTime()\n" + "{\n" + "\treturn time;\n" + "}\n" - "void SetOutput(float4 color)\n" - "{\n" - "\tocol0 = color;\n" - "}\n" + "void SetOutput(float4 color)\n" + "{\n" + "\tocol0 = color;\n" + "}\n" - "#define GetOption(x) (option_##x)\n" - "#define OptionEnabled(x) (option_##x != 0)\n"; + "#define GetOption(x) (option_##x)\n" + "#define OptionEnabled(x) (option_##x != 0)\n"; } std::string OpenGLPostProcessing::LoadShaderOptions(const std::string& code) { - std::string glsl_options = ""; - m_uniform_bindings.clear(); + std::string glsl_options = ""; + m_uniform_bindings.clear(); - for (const auto& it : m_config.GetOptions()) - { - if (it.second.m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL) - { - glsl_options += StringFromFormat("uniform int option_%s;\n", it.first.c_str()); - } - else if (it.second.m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER) - { - u32 count = static_cast(it.second.m_integer_values.size()); - if (count == 1) - glsl_options += StringFromFormat("uniform int option_%s;\n", it.first.c_str()); - else - glsl_options += StringFromFormat("uniform int%d option_%s;\n", count, it.first.c_str()); - } - else if (it.second.m_type == PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_FLOAT) - { - u32 count = static_cast(it.second.m_float_values.size()); - if (count == 1) - glsl_options += StringFromFormat("uniform float option_%s;\n", it.first.c_str()); - else - glsl_options += StringFromFormat("uniform float%d option_%s;\n", count, it.first.c_str()); - } + for (const auto& it : m_config.GetOptions()) + { + if (it.second.m_type == + PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL) + { + glsl_options += StringFromFormat("uniform int option_%s;\n", it.first.c_str()); + } + else if (it.second.m_type == + PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER) + { + u32 count = static_cast(it.second.m_integer_values.size()); + if (count == 1) + glsl_options += StringFromFormat("uniform int option_%s;\n", it.first.c_str()); + else + glsl_options += StringFromFormat("uniform int%d option_%s;\n", count, it.first.c_str()); + } + else if (it.second.m_type == + PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_FLOAT) + { + u32 count = static_cast(it.second.m_float_values.size()); + if (count == 1) + glsl_options += StringFromFormat("uniform float option_%s;\n", it.first.c_str()); + else + glsl_options += StringFromFormat("uniform float%d option_%s;\n", count, it.first.c_str()); + } - m_uniform_bindings[it.first] = 0; - } + m_uniform_bindings[it.first] = 0; + } - return m_glsl_header + glsl_options + code; + return m_glsl_header + glsl_options + code; } } // namespace OGL diff --git a/Source/Core/VideoBackends/OGL/PostProcessing.h b/Source/Core/VideoBackends/OGL/PostProcessing.h index 804232fbfd..ea01defd83 100644 --- a/Source/Core/VideoBackends/OGL/PostProcessing.h +++ b/Source/Core/VideoBackends/OGL/PostProcessing.h @@ -16,30 +16,29 @@ namespace OGL { - class OpenGLPostProcessing : public PostProcessingShaderImplementation { public: - OpenGLPostProcessing(); - ~OpenGLPostProcessing(); + OpenGLPostProcessing(); + ~OpenGLPostProcessing(); - void BlitFromTexture(TargetRectangle src, TargetRectangle dst, - int src_texture, int src_width, int src_height, int layer) override; - void ApplyShader() override; + void BlitFromTexture(TargetRectangle src, TargetRectangle dst, int src_texture, int src_width, + int src_height, int layer) override; + void ApplyShader() override; private: - bool m_initialized; - SHADER m_shader; - GLuint m_uniform_resolution; - GLuint m_uniform_src_rect; - GLuint m_uniform_time; - GLuint m_uniform_layer; - std::string m_glsl_header; + bool m_initialized; + SHADER m_shader; + GLuint m_uniform_resolution; + GLuint m_uniform_src_rect; + GLuint m_uniform_time; + GLuint m_uniform_layer; + std::string m_glsl_header; - std::unordered_map m_uniform_bindings; + std::unordered_map m_uniform_bindings; - void CreateHeader(); - std::string LoadShaderOptions(const std::string& code); + void CreateHeader(); + std::string LoadShaderOptions(const std::string& code); }; } // namespace diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp index fe43a1db38..9ec9684224 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp @@ -23,8 +23,7 @@ namespace OGL { - -static const u32 UBO_LENGTH = 32*1024*1024; +static const u32 UBO_LENGTH = 32 * 1024 * 1024; u32 ProgramShaderCache::s_ubo_buffer_size; s32 ProgramShaderCache::s_ubo_align; @@ -45,600 +44,636 @@ static std::string s_glsl_header = ""; static std::string GetGLSLVersionString() { - GLSL_VERSION v = g_ogl_config.eSupportedGLSLVersion; - switch(v) - { - case GLSLES_300: - return "#version 300 es"; - case GLSLES_310: - return "#version 310 es"; - case GLSLES_320: - return "#version 320 es"; - case GLSL_130: - return "#version 130"; - case GLSL_140: - return "#version 140"; - case GLSL_150: - return "#version 150"; - case GLSL_330: - return "#version 330"; - case GLSL_400: - return "#version 400"; - default: - // Shouldn't ever hit this - return "#version ERROR"; - } + GLSL_VERSION v = g_ogl_config.eSupportedGLSLVersion; + switch (v) + { + case GLSLES_300: + return "#version 300 es"; + case GLSLES_310: + return "#version 310 es"; + case GLSLES_320: + return "#version 320 es"; + case GLSL_130: + return "#version 130"; + case GLSL_140: + return "#version 140"; + case GLSL_150: + return "#version 150"; + case GLSL_330: + return "#version 330"; + case GLSL_400: + return "#version 400"; + default: + // Shouldn't ever hit this + return "#version ERROR"; + } } void SHADER::SetProgramVariables() { - // Bind UBO and texture samplers - if (!g_ActiveConfig.backend_info.bSupportsBindingLayout) - { - // glsl shader must be bind to set samplers if we don't support binding layout - Bind(); + // Bind UBO and texture samplers + if (!g_ActiveConfig.backend_info.bSupportsBindingLayout) + { + // glsl shader must be bind to set samplers if we don't support binding layout + Bind(); - GLint PSBlock_id = glGetUniformBlockIndex(glprogid, "PSBlock"); - GLint VSBlock_id = glGetUniformBlockIndex(glprogid, "VSBlock"); - GLint GSBlock_id = glGetUniformBlockIndex(glprogid, "GSBlock"); + GLint PSBlock_id = glGetUniformBlockIndex(glprogid, "PSBlock"); + GLint VSBlock_id = glGetUniformBlockIndex(glprogid, "VSBlock"); + GLint GSBlock_id = glGetUniformBlockIndex(glprogid, "GSBlock"); - if (PSBlock_id != -1) - glUniformBlockBinding(glprogid, PSBlock_id, 1); - if (VSBlock_id != -1) - glUniformBlockBinding(glprogid, VSBlock_id, 2); - if (GSBlock_id != -1) - glUniformBlockBinding(glprogid, GSBlock_id, 3); + if (PSBlock_id != -1) + glUniformBlockBinding(glprogid, PSBlock_id, 1); + if (VSBlock_id != -1) + glUniformBlockBinding(glprogid, VSBlock_id, 2); + if (GSBlock_id != -1) + glUniformBlockBinding(glprogid, GSBlock_id, 3); - // Bind Texture Samplers - for (int a = 0; a <= 9; ++a) - { - std::string name = StringFromFormat(a < 8 ? "samp[%d]" : "samp%d", a); + // Bind Texture Samplers + for (int a = 0; a <= 9; ++a) + { + std::string name = StringFromFormat(a < 8 ? "samp[%d]" : "samp%d", a); - // Still need to get sampler locations since we aren't binding them statically in the shaders - int loc = glGetUniformLocation(glprogid, name.c_str()); - if (loc != -1) - glUniform1i(loc, a); - } - } + // Still need to get sampler locations since we aren't binding them statically in the shaders + int loc = glGetUniformLocation(glprogid, name.c_str()); + if (loc != -1) + glUniform1i(loc, a); + } + } } void SHADER::SetProgramBindings() { - if (g_ActiveConfig.backend_info.bSupportsDualSourceBlend) - { - // So we do support extended blending - // So we need to set a few more things here. - // Bind our out locations - glBindFragDataLocationIndexed(glprogid, 0, 0, "ocol0"); - glBindFragDataLocationIndexed(glprogid, 0, 1, "ocol1"); - } - // Need to set some attribute locations - glBindAttribLocation(glprogid, SHADER_POSITION_ATTRIB, "rawpos"); + if (g_ActiveConfig.backend_info.bSupportsDualSourceBlend) + { + // So we do support extended blending + // So we need to set a few more things here. + // Bind our out locations + glBindFragDataLocationIndexed(glprogid, 0, 0, "ocol0"); + glBindFragDataLocationIndexed(glprogid, 0, 1, "ocol1"); + } + // Need to set some attribute locations + glBindAttribLocation(glprogid, SHADER_POSITION_ATTRIB, "rawpos"); - glBindAttribLocation(glprogid, SHADER_POSMTX_ATTRIB, "posmtx"); + glBindAttribLocation(glprogid, SHADER_POSMTX_ATTRIB, "posmtx"); - glBindAttribLocation(glprogid, SHADER_COLOR0_ATTRIB, "color0"); - glBindAttribLocation(glprogid, SHADER_COLOR1_ATTRIB, "color1"); + glBindAttribLocation(glprogid, SHADER_COLOR0_ATTRIB, "color0"); + glBindAttribLocation(glprogid, SHADER_COLOR1_ATTRIB, "color1"); - glBindAttribLocation(glprogid, SHADER_NORM0_ATTRIB, "rawnorm0"); - glBindAttribLocation(glprogid, SHADER_NORM1_ATTRIB, "rawnorm1"); - glBindAttribLocation(glprogid, SHADER_NORM2_ATTRIB, "rawnorm2"); + glBindAttribLocation(glprogid, SHADER_NORM0_ATTRIB, "rawnorm0"); + glBindAttribLocation(glprogid, SHADER_NORM1_ATTRIB, "rawnorm1"); + glBindAttribLocation(glprogid, SHADER_NORM2_ATTRIB, "rawnorm2"); - for (int i = 0; i < 8; i++) - { - std::string attrib_name = StringFromFormat("tex%d", i); - glBindAttribLocation(glprogid, SHADER_TEXTURE0_ATTRIB+i, attrib_name.c_str()); - } + for (int i = 0; i < 8; i++) + { + std::string attrib_name = StringFromFormat("tex%d", i); + glBindAttribLocation(glprogid, SHADER_TEXTURE0_ATTRIB + i, attrib_name.c_str()); + } } void SHADER::Bind() { - if (CurrentProgram != glprogid) - { - INCSTAT(stats.thisFrame.numShaderChanges); - glUseProgram(glprogid); - CurrentProgram = glprogid; - } + if (CurrentProgram != glprogid) + { + INCSTAT(stats.thisFrame.numShaderChanges); + glUseProgram(glprogid); + CurrentProgram = glprogid; + } } void ProgramShaderCache::UploadConstants() { - if (PixelShaderManager::dirty || VertexShaderManager::dirty || GeometryShaderManager::dirty) - { - auto buffer = s_buffer->Map(s_ubo_buffer_size, s_ubo_align); + if (PixelShaderManager::dirty || VertexShaderManager::dirty || GeometryShaderManager::dirty) + { + auto buffer = s_buffer->Map(s_ubo_buffer_size, s_ubo_align); - memcpy(buffer.first, - &PixelShaderManager::constants, sizeof(PixelShaderConstants)); + memcpy(buffer.first, &PixelShaderManager::constants, sizeof(PixelShaderConstants)); - memcpy(buffer.first + ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align), - &VertexShaderManager::constants, sizeof(VertexShaderConstants)); + memcpy(buffer.first + ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align), + &VertexShaderManager::constants, sizeof(VertexShaderConstants)); - memcpy(buffer.first + ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align) + ROUND_UP(sizeof(VertexShaderConstants), s_ubo_align), - &GeometryShaderManager::constants, sizeof(GeometryShaderConstants)); + memcpy(buffer.first + ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align) + + ROUND_UP(sizeof(VertexShaderConstants), s_ubo_align), + &GeometryShaderManager::constants, sizeof(GeometryShaderConstants)); - s_buffer->Unmap(s_ubo_buffer_size); - glBindBufferRange(GL_UNIFORM_BUFFER, 1, s_buffer->m_buffer, buffer.second, - sizeof(PixelShaderConstants)); - glBindBufferRange(GL_UNIFORM_BUFFER, 2, s_buffer->m_buffer, buffer.second + ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align), - sizeof(VertexShaderConstants)); - glBindBufferRange(GL_UNIFORM_BUFFER, 3, s_buffer->m_buffer, buffer.second + ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align) + ROUND_UP(sizeof(VertexShaderConstants), s_ubo_align), - sizeof(GeometryShaderConstants)); + s_buffer->Unmap(s_ubo_buffer_size); + glBindBufferRange(GL_UNIFORM_BUFFER, 1, s_buffer->m_buffer, buffer.second, + sizeof(PixelShaderConstants)); + glBindBufferRange(GL_UNIFORM_BUFFER, 2, s_buffer->m_buffer, + buffer.second + ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align), + sizeof(VertexShaderConstants)); + glBindBufferRange(GL_UNIFORM_BUFFER, 3, s_buffer->m_buffer, + buffer.second + ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align) + + ROUND_UP(sizeof(VertexShaderConstants), s_ubo_align), + sizeof(GeometryShaderConstants)); - PixelShaderManager::dirty = false; - VertexShaderManager::dirty = false; - GeometryShaderManager::dirty = false; + PixelShaderManager::dirty = false; + VertexShaderManager::dirty = false; + GeometryShaderManager::dirty = false; - ADDSTAT(stats.thisFrame.bytesUniformStreamed, s_ubo_buffer_size); - } + ADDSTAT(stats.thisFrame.bytesUniformStreamed, s_ubo_buffer_size); + } } SHADER* ProgramShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 primitive_type) { - SHADERUID uid; - GetShaderId(&uid, dstAlphaMode, primitive_type); + SHADERUID uid; + GetShaderId(&uid, dstAlphaMode, primitive_type); - // Check if the shader is already set - if (last_entry) - { - if (uid == last_uid) - { - GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - last_entry->shader.Bind(); - return &last_entry->shader; - } - } + // Check if the shader is already set + if (last_entry) + { + if (uid == last_uid) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + last_entry->shader.Bind(); + return &last_entry->shader; + } + } - last_uid = uid; + last_uid = uid; - // Check if shader is already in cache - PCache::iterator iter = pshaders.find(uid); - if (iter != pshaders.end()) - { - PCacheEntry *entry = &iter->second; - last_entry = entry; + // Check if shader is already in cache + PCache::iterator iter = pshaders.find(uid); + if (iter != pshaders.end()) + { + PCacheEntry* entry = &iter->second; + last_entry = entry; - GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - last_entry->shader.Bind(); - return &last_entry->shader; - } + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + last_entry->shader.Bind(); + return &last_entry->shader; + } - // Make an entry in the table - PCacheEntry& newentry = pshaders[uid]; - last_entry = &newentry; - newentry.in_cache = 0; + // Make an entry in the table + PCacheEntry& newentry = pshaders[uid]; + last_entry = &newentry; + newentry.in_cache = 0; - ShaderCode vcode = GenerateVertexShaderCode(API_OPENGL); - ShaderCode pcode = GeneratePixelShaderCode(dstAlphaMode, API_OPENGL); - ShaderCode gcode; - if (g_ActiveConfig.backend_info.bSupportsGeometryShaders && !uid.guid.GetUidData()->IsPassthrough()) - gcode = GenerateGeometryShaderCode(primitive_type, API_OPENGL); + ShaderCode vcode = GenerateVertexShaderCode(API_OPENGL); + ShaderCode pcode = GeneratePixelShaderCode(dstAlphaMode, API_OPENGL); + ShaderCode gcode; + if (g_ActiveConfig.backend_info.bSupportsGeometryShaders && + !uid.guid.GetUidData()->IsPassthrough()) + gcode = GenerateGeometryShaderCode(primitive_type, API_OPENGL); - if (g_ActiveConfig.bEnableShaderDebugging) - { - newentry.shader.strvprog = vcode.GetBuffer(); - newentry.shader.strpprog = pcode.GetBuffer(); - newentry.shader.strgprog = gcode.GetBuffer(); - } + if (g_ActiveConfig.bEnableShaderDebugging) + { + newentry.shader.strvprog = vcode.GetBuffer(); + newentry.shader.strpprog = pcode.GetBuffer(); + newentry.shader.strgprog = gcode.GetBuffer(); + } #if defined(_DEBUG) || defined(DEBUGFAST) - if (g_ActiveConfig.iLog & CONF_SAVESHADERS) - { - static int counter = 0; - std::string filename = StringFromFormat("%svs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); - SaveData(filename, vcode.GetBuffer()); + if (g_ActiveConfig.iLog & CONF_SAVESHADERS) + { + static int counter = 0; + std::string filename = + StringFromFormat("%svs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); + SaveData(filename, vcode.GetBuffer()); - filename = StringFromFormat("%sps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); - SaveData(filename, pcode.GetBuffer()); + filename = StringFromFormat("%sps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); + SaveData(filename, pcode.GetBuffer()); - if (!gcode.GetBuffer().empty()) - { - filename = StringFromFormat("%sgs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); - SaveData(filename, gcode.GetBuffer()); - } - } + if (!gcode.GetBuffer().empty()) + { + filename = + StringFromFormat("%sgs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); + SaveData(filename, gcode.GetBuffer()); + } + } #endif - if (!CompileShader(newentry.shader, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer())) - { - GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); - return nullptr; - } + if (!CompileShader(newentry.shader, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer())) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); + return nullptr; + } - INCSTAT(stats.numPixelShadersCreated); - SETSTAT(stats.numPixelShadersAlive, pshaders.size()); - GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + INCSTAT(stats.numPixelShadersCreated); + SETSTAT(stats.numPixelShadersAlive, pshaders.size()); + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); - last_entry->shader.Bind(); - return &last_entry->shader; + last_entry->shader.Bind(); + return &last_entry->shader; } -bool ProgramShaderCache::CompileShader(SHADER& shader, const std::string& vcode, const std::string& pcode, const std::string& gcode) +bool ProgramShaderCache::CompileShader(SHADER& shader, const std::string& vcode, + const std::string& pcode, const std::string& gcode) { - GLuint vsid = CompileSingleShader(GL_VERTEX_SHADER, vcode); - GLuint psid = CompileSingleShader(GL_FRAGMENT_SHADER, pcode); + GLuint vsid = CompileSingleShader(GL_VERTEX_SHADER, vcode); + GLuint psid = CompileSingleShader(GL_FRAGMENT_SHADER, pcode); - // Optional geometry shader - GLuint gsid = 0; - if (!gcode.empty()) - gsid = CompileSingleShader(GL_GEOMETRY_SHADER, gcode); + // Optional geometry shader + GLuint gsid = 0; + if (!gcode.empty()) + gsid = CompileSingleShader(GL_GEOMETRY_SHADER, gcode); - if (!vsid || !psid || (!gcode.empty() && !gsid)) - { - glDeleteShader(vsid); - glDeleteShader(psid); - glDeleteShader(gsid); - return false; - } + if (!vsid || !psid || (!gcode.empty() && !gsid)) + { + glDeleteShader(vsid); + glDeleteShader(psid); + glDeleteShader(gsid); + return false; + } - GLuint pid = shader.glprogid = glCreateProgram(); + GLuint pid = shader.glprogid = glCreateProgram(); - glAttachShader(pid, vsid); - glAttachShader(pid, psid); - if (gsid) - glAttachShader(pid, gsid); + glAttachShader(pid, vsid); + glAttachShader(pid, psid); + if (gsid) + glAttachShader(pid, gsid); - if (g_ogl_config.bSupportsGLSLCache) - glProgramParameteri(pid, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); + if (g_ogl_config.bSupportsGLSLCache) + glProgramParameteri(pid, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); - shader.SetProgramBindings(); + shader.SetProgramBindings(); - glLinkProgram(pid); + glLinkProgram(pid); - // original shaders aren't needed any more - glDeleteShader(vsid); - glDeleteShader(psid); - glDeleteShader(gsid); + // original shaders aren't needed any more + glDeleteShader(vsid); + glDeleteShader(psid); + glDeleteShader(gsid); - GLint linkStatus; - glGetProgramiv(pid, GL_LINK_STATUS, &linkStatus); - GLsizei length = 0; - glGetProgramiv(pid, GL_INFO_LOG_LENGTH, &length); - if (linkStatus != GL_TRUE || (length > 1 && DEBUG_GLSL)) - { - GLsizei charsWritten; - GLchar* infoLog = new GLchar[length]; - glGetProgramInfoLog(pid, length, &charsWritten, infoLog); - ERROR_LOG(VIDEO, "Program info log:\n%s", infoLog); + GLint linkStatus; + glGetProgramiv(pid, GL_LINK_STATUS, &linkStatus); + GLsizei length = 0; + glGetProgramiv(pid, GL_INFO_LOG_LENGTH, &length); + if (linkStatus != GL_TRUE || (length > 1 && DEBUG_GLSL)) + { + GLsizei charsWritten; + GLchar* infoLog = new GLchar[length]; + glGetProgramInfoLog(pid, length, &charsWritten, infoLog); + ERROR_LOG(VIDEO, "Program info log:\n%s", infoLog); - std::string filename = StringFromFormat("%sbad_p_%d.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); - std::ofstream file; - OpenFStream(file, filename, std::ios_base::out); - file << s_glsl_header << vcode << s_glsl_header << pcode; - if (!gcode.empty()) - file << s_glsl_header << gcode; - file << infoLog; - file.close(); + std::string filename = + StringFromFormat("%sbad_p_%d.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); + std::ofstream file; + OpenFStream(file, filename, std::ios_base::out); + file << s_glsl_header << vcode << s_glsl_header << pcode; + if (!gcode.empty()) + file << s_glsl_header << gcode; + file << infoLog; + file.close(); - if (linkStatus != GL_TRUE) - { - PanicAlert("Failed to link shaders: %s\n" - "Debug info (%s, %s, %s):\n%s", - filename.c_str(), - g_ogl_config.gl_vendor, g_ogl_config.gl_renderer, g_ogl_config.gl_version, infoLog); - } + if (linkStatus != GL_TRUE) + { + PanicAlert("Failed to link shaders: %s\n" + "Debug info (%s, %s, %s):\n%s", + filename.c_str(), g_ogl_config.gl_vendor, g_ogl_config.gl_renderer, + g_ogl_config.gl_version, infoLog); + } - delete [] infoLog; - } - if (linkStatus != GL_TRUE) - { - // Compile failed - ERROR_LOG(VIDEO, "Program linking failed; see info log"); + delete[] infoLog; + } + if (linkStatus != GL_TRUE) + { + // Compile failed + ERROR_LOG(VIDEO, "Program linking failed; see info log"); - // Don't try to use this shader - glDeleteProgram(pid); - return false; - } + // Don't try to use this shader + glDeleteProgram(pid); + return false; + } - shader.SetProgramVariables(); + shader.SetProgramVariables(); - return true; + return true; } GLuint ProgramShaderCache::CompileSingleShader(GLuint type, const std::string& code) { - GLuint result = glCreateShader(type); + GLuint result = glCreateShader(type); - const char *src[] = {s_glsl_header.c_str(), code.c_str()}; + const char* src[] = {s_glsl_header.c_str(), code.c_str()}; - glShaderSource(result, 2, src, nullptr); - glCompileShader(result); - GLint compileStatus; - glGetShaderiv(result, GL_COMPILE_STATUS, &compileStatus); - GLsizei length = 0; - glGetShaderiv(result, GL_INFO_LOG_LENGTH, &length); + glShaderSource(result, 2, src, nullptr); + glCompileShader(result); + GLint compileStatus; + glGetShaderiv(result, GL_COMPILE_STATUS, &compileStatus); + GLsizei length = 0; + glGetShaderiv(result, GL_INFO_LOG_LENGTH, &length); - if (compileStatus != GL_TRUE || (length > 1 && DEBUG_GLSL)) - { - GLsizei charsWritten; - GLchar* infoLog = new GLchar[length]; - glGetShaderInfoLog(result, length, &charsWritten, infoLog); - ERROR_LOG(VIDEO, "%s Shader info log:\n%s", type==GL_VERTEX_SHADER ? "VS" : type==GL_FRAGMENT_SHADER ? "PS" : "GS", infoLog); + if (compileStatus != GL_TRUE || (length > 1 && DEBUG_GLSL)) + { + GLsizei charsWritten; + GLchar* infoLog = new GLchar[length]; + glGetShaderInfoLog(result, length, &charsWritten, infoLog); + ERROR_LOG(VIDEO, "%s Shader info log:\n%s", + type == GL_VERTEX_SHADER ? "VS" : type == GL_FRAGMENT_SHADER ? "PS" : "GS", infoLog); - std::string filename = StringFromFormat("%sbad_%s_%04i.txt", - File::GetUserPath(D_DUMP_IDX).c_str(), - type==GL_VERTEX_SHADER ? "vs" : type==GL_FRAGMENT_SHADER ? "ps" : "gs", - num_failures++); - std::ofstream file; - OpenFStream(file, filename, std::ios_base::out); - file << s_glsl_header << code << infoLog; - file.close(); + std::string filename = StringFromFormat( + "%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), + type == GL_VERTEX_SHADER ? "vs" : type == GL_FRAGMENT_SHADER ? "ps" : "gs", num_failures++); + std::ofstream file; + OpenFStream(file, filename, std::ios_base::out); + file << s_glsl_header << code << infoLog; + file.close(); - if (compileStatus != GL_TRUE) - { - PanicAlert("Failed to compile %s shader: %s\n" - "Debug info (%s, %s, %s):\n%s", - type == GL_VERTEX_SHADER ? "vertex" : type==GL_FRAGMENT_SHADER ? "pixel" : "geometry", - filename.c_str(), - g_ogl_config.gl_vendor, g_ogl_config.gl_renderer, g_ogl_config.gl_version, infoLog); - } + if (compileStatus != GL_TRUE) + { + PanicAlert("Failed to compile %s shader: %s\n" + "Debug info (%s, %s, %s):\n%s", + type == GL_VERTEX_SHADER ? "vertex" : type == GL_FRAGMENT_SHADER ? "pixel" : + "geometry", + filename.c_str(), g_ogl_config.gl_vendor, g_ogl_config.gl_renderer, + g_ogl_config.gl_version, infoLog); + } - delete[] infoLog; - } - if (compileStatus != GL_TRUE) - { - // Compile failed - ERROR_LOG(VIDEO, "Shader compilation failed; see info log"); + delete[] infoLog; + } + if (compileStatus != GL_TRUE) + { + // Compile failed + ERROR_LOG(VIDEO, "Shader compilation failed; see info log"); - // Don't try to use this shader - glDeleteShader(result); - return 0; - } + // Don't try to use this shader + glDeleteShader(result); + return 0; + } - return result; + return result; } void ProgramShaderCache::GetShaderId(SHADERUID* uid, DSTALPHA_MODE dstAlphaMode, u32 primitive_type) { - uid->puid = GetPixelShaderUid(dstAlphaMode, API_OPENGL); - uid->vuid = GetVertexShaderUid(API_OPENGL); - uid->guid = GetGeometryShaderUid(primitive_type, API_OPENGL); + uid->puid = GetPixelShaderUid(dstAlphaMode, API_OPENGL); + uid->vuid = GetVertexShaderUid(API_OPENGL); + uid->guid = GetGeometryShaderUid(primitive_type, API_OPENGL); - if (g_ActiveConfig.bEnableShaderDebugging) - { - ShaderCode pcode = GeneratePixelShaderCode(dstAlphaMode, API_OPENGL); - pixel_uid_checker.AddToIndexAndCheck(pcode, uid->puid, "Pixel", "p"); + if (g_ActiveConfig.bEnableShaderDebugging) + { + ShaderCode pcode = GeneratePixelShaderCode(dstAlphaMode, API_OPENGL); + pixel_uid_checker.AddToIndexAndCheck(pcode, uid->puid, "Pixel", "p"); - ShaderCode vcode = GenerateVertexShaderCode(API_OPENGL); - vertex_uid_checker.AddToIndexAndCheck(vcode, uid->vuid, "Vertex", "v"); + ShaderCode vcode = GenerateVertexShaderCode(API_OPENGL); + vertex_uid_checker.AddToIndexAndCheck(vcode, uid->vuid, "Vertex", "v"); - ShaderCode gcode = GenerateGeometryShaderCode(primitive_type, API_OPENGL); - geometry_uid_checker.AddToIndexAndCheck(gcode, uid->guid, "Geometry", "g"); - } + ShaderCode gcode = GenerateGeometryShaderCode(primitive_type, API_OPENGL); + geometry_uid_checker.AddToIndexAndCheck(gcode, uid->guid, "Geometry", "g"); + } } ProgramShaderCache::PCacheEntry ProgramShaderCache::GetShaderProgram() { - return *last_entry; + return *last_entry; } void ProgramShaderCache::Init() { - // We have to get the UBO alignment here because - // if we generate a buffer that isn't aligned - // then the UBO will fail. - glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &s_ubo_align); + // We have to get the UBO alignment here because + // if we generate a buffer that isn't aligned + // then the UBO will fail. + glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &s_ubo_align); - s_ubo_buffer_size = ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align) + ROUND_UP(sizeof(VertexShaderConstants), s_ubo_align) + ROUND_UP(sizeof(GeometryShaderConstants), s_ubo_align); + s_ubo_buffer_size = ROUND_UP(sizeof(PixelShaderConstants), s_ubo_align) + + ROUND_UP(sizeof(VertexShaderConstants), s_ubo_align) + + ROUND_UP(sizeof(GeometryShaderConstants), s_ubo_align); - // We multiply by *4*4 because we need to get down to basic machine units. - // So multiply by four to get how many floats we have from vec4s - // Then once more to get bytes - s_buffer = StreamBuffer::Create(GL_UNIFORM_BUFFER, UBO_LENGTH); + // We multiply by *4*4 because we need to get down to basic machine units. + // So multiply by four to get how many floats we have from vec4s + // Then once more to get bytes + s_buffer = StreamBuffer::Create(GL_UNIFORM_BUFFER, UBO_LENGTH); - // Read our shader cache, only if supported - if (g_ogl_config.bSupportsGLSLCache && !g_Config.bEnableShaderDebugging) - { - GLint Supported; - glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &Supported); - if (!Supported) - { - ERROR_LOG(VIDEO, "GL_ARB_get_program_binary is supported, but no binary format is known. So disable shader cache."); - g_ogl_config.bSupportsGLSLCache = false; - } - else - { - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + // Read our shader cache, only if supported + if (g_ogl_config.bSupportsGLSLCache && !g_Config.bEnableShaderDebugging) + { + GLint Supported; + glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &Supported); + if (!Supported) + { + ERROR_LOG(VIDEO, "GL_ARB_get_program_binary is supported, but no binary format is known. So " + "disable shader cache."); + g_ogl_config.bSupportsGLSLCache = false; + } + else + { + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - std::string cache_filename = StringFromFormat("%sogl-%s-shaders.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), - SConfig::GetInstance().m_strUniqueID.c_str()); + std::string cache_filename = + StringFromFormat("%sogl-%s-shaders.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), + SConfig::GetInstance().m_strUniqueID.c_str()); - ProgramShaderCacheInserter inserter; - g_program_disk_cache.OpenAndRead(cache_filename, inserter); - } - SETSTAT(stats.numPixelShadersAlive, pshaders.size()); - } + ProgramShaderCacheInserter inserter; + g_program_disk_cache.OpenAndRead(cache_filename, inserter); + } + SETSTAT(stats.numPixelShadersAlive, pshaders.size()); + } - CreateHeader(); + CreateHeader(); - CurrentProgram = 0; - last_entry = nullptr; + CurrentProgram = 0; + last_entry = nullptr; } void ProgramShaderCache::Shutdown() { - // store all shaders in cache on disk - if (g_ogl_config.bSupportsGLSLCache && !g_Config.bEnableShaderDebugging) - { - for (auto& entry : pshaders) - { - // Clear any prior error code - glGetError(); + // store all shaders in cache on disk + if (g_ogl_config.bSupportsGLSLCache && !g_Config.bEnableShaderDebugging) + { + for (auto& entry : pshaders) + { + // Clear any prior error code + glGetError(); - if (entry.second.in_cache) - { - continue; - } + if (entry.second.in_cache) + { + continue; + } - GLint link_status = GL_FALSE, delete_status = GL_TRUE, binary_size = 0; - glGetProgramiv(entry.second.shader.glprogid, GL_LINK_STATUS, &link_status); - glGetProgramiv(entry.second.shader.glprogid, GL_DELETE_STATUS, &delete_status); - glGetProgramiv(entry.second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size); - if (glGetError() != GL_NO_ERROR || link_status == GL_FALSE || delete_status == GL_TRUE || !binary_size) - { - continue; - } + GLint link_status = GL_FALSE, delete_status = GL_TRUE, binary_size = 0; + glGetProgramiv(entry.second.shader.glprogid, GL_LINK_STATUS, &link_status); + glGetProgramiv(entry.second.shader.glprogid, GL_DELETE_STATUS, &delete_status); + glGetProgramiv(entry.second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size); + if (glGetError() != GL_NO_ERROR || link_status == GL_FALSE || delete_status == GL_TRUE || + !binary_size) + { + continue; + } - std::vector data(binary_size + sizeof(GLenum)); - u8* binary = &data[sizeof(GLenum)]; - GLenum* prog_format = (GLenum*)&data[0]; - glGetProgramBinary(entry.second.shader.glprogid, binary_size, nullptr, prog_format, binary); - if (glGetError() != GL_NO_ERROR) - { - continue; - } + std::vector data(binary_size + sizeof(GLenum)); + u8* binary = &data[sizeof(GLenum)]; + GLenum* prog_format = (GLenum*)&data[0]; + glGetProgramBinary(entry.second.shader.glprogid, binary_size, nullptr, prog_format, binary); + if (glGetError() != GL_NO_ERROR) + { + continue; + } - g_program_disk_cache.Append(entry.first, &data[0], binary_size + sizeof(GLenum)); - } + g_program_disk_cache.Append(entry.first, &data[0], binary_size + sizeof(GLenum)); + } - g_program_disk_cache.Sync(); - g_program_disk_cache.Close(); - } + g_program_disk_cache.Sync(); + g_program_disk_cache.Close(); + } - glUseProgram(0); + glUseProgram(0); - for (auto& entry : pshaders) - { - entry.second.Destroy(); - } - pshaders.clear(); + for (auto& entry : pshaders) + { + entry.second.Destroy(); + } + pshaders.clear(); - pixel_uid_checker.Invalidate(); - vertex_uid_checker.Invalidate(); + pixel_uid_checker.Invalidate(); + vertex_uid_checker.Invalidate(); - s_buffer.reset(); + s_buffer.reset(); } void ProgramShaderCache::CreateHeader() { - GLSL_VERSION v = g_ogl_config.eSupportedGLSLVersion; - bool is_glsles = v >= GLSLES_300; - std::string SupportedESPointSize; - std::string SupportedESTextureBuffer; - switch (g_ogl_config.SupportedESPointSize) - { - case 1: SupportedESPointSize = "#extension GL_OES_geometry_point_size : enable"; break; - case 2: SupportedESPointSize = "#extension GL_EXT_geometry_point_size : enable"; break; - default: SupportedESPointSize = ""; break; - } + GLSL_VERSION v = g_ogl_config.eSupportedGLSLVersion; + bool is_glsles = v >= GLSLES_300; + std::string SupportedESPointSize; + std::string SupportedESTextureBuffer; + switch (g_ogl_config.SupportedESPointSize) + { + case 1: + SupportedESPointSize = "#extension GL_OES_geometry_point_size : enable"; + break; + case 2: + SupportedESPointSize = "#extension GL_EXT_geometry_point_size : enable"; + break; + default: + SupportedESPointSize = ""; + break; + } - switch (g_ogl_config.SupportedESTextureBuffer) - { - case ES_TEXBUF_TYPE::TEXBUF_EXT: - SupportedESTextureBuffer = "#extension GL_EXT_texture_buffer : enable"; - break; - case ES_TEXBUF_TYPE::TEXBUF_OES: - SupportedESTextureBuffer = "#extension GL_OES_texture_buffer : enable"; - break; - case ES_TEXBUF_TYPE::TEXBUF_CORE: - case ES_TEXBUF_TYPE::TEXBUF_NONE: - SupportedESTextureBuffer = ""; - break; - } + switch (g_ogl_config.SupportedESTextureBuffer) + { + case ES_TEXBUF_TYPE::TEXBUF_EXT: + SupportedESTextureBuffer = "#extension GL_EXT_texture_buffer : enable"; + break; + case ES_TEXBUF_TYPE::TEXBUF_OES: + SupportedESTextureBuffer = "#extension GL_OES_texture_buffer : enable"; + break; + case ES_TEXBUF_TYPE::TEXBUF_CORE: + case ES_TEXBUF_TYPE::TEXBUF_NONE: + SupportedESTextureBuffer = ""; + break; + } - std::string earlyz_string = ""; - if (g_ActiveConfig.backend_info.bSupportsEarlyZ) - { - if (g_ogl_config.bSupportsEarlyFragmentTests) - { - earlyz_string = "#define FORCE_EARLY_Z layout(early_fragment_tests) in\n"; - if (!is_glsles) // GLES supports this by default - earlyz_string += "#extension GL_ARB_shader_image_load_store : enable\n"; - } - else if(g_ogl_config.bSupportsConservativeDepth) - { - // See PixelShaderGen for details about this fallback. - earlyz_string = "#define FORCE_EARLY_Z layout(depth_unchanged) out float gl_FragDepth\n"; - earlyz_string += "#extension GL_ARB_conservative_depth : enable\n"; - } - } + std::string earlyz_string = ""; + if (g_ActiveConfig.backend_info.bSupportsEarlyZ) + { + if (g_ogl_config.bSupportsEarlyFragmentTests) + { + earlyz_string = "#define FORCE_EARLY_Z layout(early_fragment_tests) in\n"; + if (!is_glsles) // GLES supports this by default + earlyz_string += "#extension GL_ARB_shader_image_load_store : enable\n"; + } + else if (g_ogl_config.bSupportsConservativeDepth) + { + // See PixelShaderGen for details about this fallback. + earlyz_string = "#define FORCE_EARLY_Z layout(depth_unchanged) out float gl_FragDepth\n"; + earlyz_string += "#extension GL_ARB_conservative_depth : enable\n"; + } + } - s_glsl_header = StringFromFormat( - "%s\n" - "%s\n" // ubo - "%s\n" // early-z - "%s\n" // 420pack - "%s\n" // msaa - "%s\n" // Sampler binding - "%s\n" // storage buffer - "%s\n" // shader5 - "%s\n" // SSAA - "%s\n" // Geometry point size - "%s\n" // AEP - "%s\n" // texture buffer - "%s\n" // ES texture buffer - "%s\n" // ES dual source blend + s_glsl_header = StringFromFormat( + "%s\n" + "%s\n" // ubo + "%s\n" // early-z + "%s\n" // 420pack + "%s\n" // msaa + "%s\n" // Sampler binding + "%s\n" // storage buffer + "%s\n" // shader5 + "%s\n" // SSAA + "%s\n" // Geometry point size + "%s\n" // AEP + "%s\n" // texture buffer + "%s\n" // ES texture buffer + "%s\n" // ES dual source blend - // Precision defines for GLSL ES - "%s\n" - "%s\n" - "%s\n" - "%s\n" - "%s\n" + // Precision defines for GLSL ES + "%s\n" + "%s\n" + "%s\n" + "%s\n" + "%s\n" - // Silly differences - "#define float2 vec2\n" - "#define float3 vec3\n" - "#define float4 vec4\n" - "#define uint2 uvec2\n" - "#define uint3 uvec3\n" - "#define uint4 uvec4\n" - "#define int2 ivec2\n" - "#define int3 ivec3\n" - "#define int4 ivec4\n" + // Silly differences + "#define float2 vec2\n" + "#define float3 vec3\n" + "#define float4 vec4\n" + "#define uint2 uvec2\n" + "#define uint3 uvec3\n" + "#define uint4 uvec4\n" + "#define int2 ivec2\n" + "#define int3 ivec3\n" + "#define int4 ivec4\n" - // hlsl to glsl function translation - "#define frac fract\n" - "#define lerp mix\n" + // hlsl to glsl function translation + "#define frac fract\n" + "#define lerp mix\n" - , GetGLSLVersionString().c_str() - , v < GLSL_140 ? "#extension GL_ARB_uniform_buffer_object : enable" : "" - , earlyz_string.c_str() - , (g_ActiveConfig.backend_info.bSupportsBindingLayout && v < GLSLES_310) ? "#extension GL_ARB_shading_language_420pack : enable" : "" - , (g_ogl_config.bSupportsMSAA && v < GLSL_150) ? "#extension GL_ARB_texture_multisample : enable" : "" - , g_ActiveConfig.backend_info.bSupportsBindingLayout ? "#define SAMPLER_BINDING(x) layout(binding = x)" : "#define SAMPLER_BINDING(x)" - , !is_glsles && g_ActiveConfig.backend_info.bSupportsBBox ? "#extension GL_ARB_shader_storage_buffer_object : enable" : "" - , v < GLSL_400 && g_ActiveConfig.backend_info.bSupportsGSInstancing ? "#extension GL_ARB_gpu_shader5 : enable" : "" - , v < GLSL_400 && g_ActiveConfig.backend_info.bSupportsSSAA ? "#extension GL_ARB_sample_shading : enable" : "" - , SupportedESPointSize.c_str() - , g_ogl_config.bSupportsAEP ? "#extension GL_ANDROID_extension_pack_es31a : enable" : "" - , v < GLSL_140 && g_ActiveConfig.backend_info.bSupportsPaletteConversion ? "#extension GL_ARB_texture_buffer_object : enable" : "" - , SupportedESTextureBuffer.c_str() - , is_glsles && g_ActiveConfig.backend_info.bSupportsDualSourceBlend ? "#extension GL_EXT_blend_func_extended : enable" : "" + , + GetGLSLVersionString().c_str(), + v < GLSL_140 ? "#extension GL_ARB_uniform_buffer_object : enable" : "", earlyz_string.c_str(), + (g_ActiveConfig.backend_info.bSupportsBindingLayout && v < GLSLES_310) ? + "#extension GL_ARB_shading_language_420pack : enable" : + "", + (g_ogl_config.bSupportsMSAA && v < GLSL_150) ? + "#extension GL_ARB_texture_multisample : enable" : + "", + g_ActiveConfig.backend_info.bSupportsBindingLayout ? + "#define SAMPLER_BINDING(x) layout(binding = x)" : + "#define SAMPLER_BINDING(x)", + !is_glsles && g_ActiveConfig.backend_info.bSupportsBBox ? + "#extension GL_ARB_shader_storage_buffer_object : enable" : + "", + v < GLSL_400 && g_ActiveConfig.backend_info.bSupportsGSInstancing ? + "#extension GL_ARB_gpu_shader5 : enable" : + "", + v < GLSL_400 && g_ActiveConfig.backend_info.bSupportsSSAA ? + "#extension GL_ARB_sample_shading : enable" : + "", + SupportedESPointSize.c_str(), + g_ogl_config.bSupportsAEP ? "#extension GL_ANDROID_extension_pack_es31a : enable" : "", + v < GLSL_140 && g_ActiveConfig.backend_info.bSupportsPaletteConversion ? + "#extension GL_ARB_texture_buffer_object : enable" : + "", + SupportedESTextureBuffer.c_str(), + is_glsles && g_ActiveConfig.backend_info.bSupportsDualSourceBlend ? + "#extension GL_EXT_blend_func_extended : enable" : + "" - , is_glsles ? "precision highp float;" : "" - , is_glsles ? "precision highp int;" : "" - , is_glsles ? "precision highp sampler2DArray;" : "" - , (is_glsles && g_ActiveConfig.backend_info.bSupportsPaletteConversion) ? "precision highp usamplerBuffer;" : "" - , v > GLSLES_300 ? "precision highp sampler2DMS;" : "" - ); + , + is_glsles ? "precision highp float;" : "", is_glsles ? "precision highp int;" : "", + is_glsles ? "precision highp sampler2DArray;" : "", + (is_glsles && g_ActiveConfig.backend_info.bSupportsPaletteConversion) ? + "precision highp usamplerBuffer;" : + "", + v > GLSLES_300 ? "precision highp sampler2DMS;" : ""); } - -void ProgramShaderCache::ProgramShaderCacheInserter::Read(const SHADERUID& key, const u8* value, u32 value_size) +void ProgramShaderCache::ProgramShaderCacheInserter::Read(const SHADERUID& key, const u8* value, + u32 value_size) { - const u8 *binary = value+sizeof(GLenum); - GLenum *prog_format = (GLenum*)value; - GLint binary_size = value_size-sizeof(GLenum); + const u8* binary = value + sizeof(GLenum); + GLenum* prog_format = (GLenum*)value; + GLint binary_size = value_size - sizeof(GLenum); - PCacheEntry entry; - entry.in_cache = 1; - entry.shader.glprogid = glCreateProgram(); - glProgramBinary(entry.shader.glprogid, *prog_format, binary, binary_size); + PCacheEntry entry; + entry.in_cache = 1; + entry.shader.glprogid = glCreateProgram(); + glProgramBinary(entry.shader.glprogid, *prog_format, binary, binary_size); - GLint success; - glGetProgramiv(entry.shader.glprogid, GL_LINK_STATUS, &success); + GLint success; + glGetProgramiv(entry.shader.glprogid, GL_LINK_STATUS, &success); - if (success) - { - pshaders[key] = entry; - entry.shader.SetProgramVariables(); - } - else - { - glDeleteProgram(entry.shader.glprogid); - } + if (success) + { + pshaders[key] = entry; + entry.shader.SetProgramVariables(); + } + else + { + glDeleteProgram(entry.shader.glprogid); + } } - -} // namespace OGL +} // namespace OGL diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h index 234ac678c9..4852d71b86 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h @@ -6,8 +6,8 @@ #include -#include "Common/LinearDiskCache.h" #include "Common/GL/GLUtil.h" +#include "Common/LinearDiskCache.h" #include "Core/ConfigManager.h" @@ -17,91 +17,83 @@ namespace OGL { - class SHADERUID { public: - VertexShaderUid vuid; - PixelShaderUid puid; - GeometryShaderUid guid; + VertexShaderUid vuid; + PixelShaderUid puid; + GeometryShaderUid guid; - bool operator <(const SHADERUID& r) const - { - return std::tie(puid, vuid, guid) < - std::tie(r.puid, r.vuid, r.guid); - } + bool operator<(const SHADERUID& r) const + { + return std::tie(puid, vuid, guid) < std::tie(r.puid, r.vuid, r.guid); + } - bool operator ==(const SHADERUID& r) const - { - return std::tie(puid, vuid, guid) == - std::tie(r.puid, r.vuid, r.guid); - } + bool operator==(const SHADERUID& r) const + { + return std::tie(puid, vuid, guid) == std::tie(r.puid, r.vuid, r.guid); + } }; - struct SHADER { - SHADER() : glprogid(0) { } - void Destroy() - { - glDeleteProgram(glprogid); - glprogid = 0; - } - GLuint glprogid; // OpenGL program id + SHADER() : glprogid(0) {} + void Destroy() + { + glDeleteProgram(glprogid); + glprogid = 0; + } + GLuint glprogid; // OpenGL program id - std::string strvprog, strpprog, strgprog; + std::string strvprog, strpprog, strgprog; - void SetProgramVariables(); - void SetProgramBindings(); - void Bind(); + void SetProgramVariables(); + void SetProgramBindings(); + void Bind(); }; class ProgramShaderCache { public: + struct PCacheEntry + { + SHADER shader; + bool in_cache; - struct PCacheEntry - { - SHADER shader; - bool in_cache; + void Destroy() { shader.Destroy(); } + }; - void Destroy() - { - shader.Destroy(); - } - }; + static PCacheEntry GetShaderProgram(); + static SHADER* SetShader(DSTALPHA_MODE dstAlphaMode, u32 primitive_type); + static void GetShaderId(SHADERUID* uid, DSTALPHA_MODE dstAlphaMode, u32 primitive_type); + static bool CompileShader(SHADER& shader, const std::string& vcode, const std::string& pcode, + const std::string& gcode = ""); + static GLuint CompileSingleShader(GLuint type, const std::string& code); + static void UploadConstants(); - static PCacheEntry GetShaderProgram(); - static SHADER* SetShader(DSTALPHA_MODE dstAlphaMode, u32 primitive_type); - static void GetShaderId(SHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 primitive_type); - - static bool CompileShader(SHADER &shader, const std::string& vcode, const std::string& pcode, const std::string& gcode = ""); - static GLuint CompileSingleShader(GLuint type, const std::string& code); - static void UploadConstants(); - - static void Init(); - static void Shutdown(); - static void CreateHeader(); + static void Init(); + static void Shutdown(); + static void CreateHeader(); private: - class ProgramShaderCacheInserter : public LinearDiskCacheReader - { - public: - void Read(const SHADERUID &key, const u8 *value, u32 value_size) override; - }; + class ProgramShaderCacheInserter : public LinearDiskCacheReader + { + public: + void Read(const SHADERUID& key, const u8* value, u32 value_size) override; + }; - typedef std::map PCache; - static PCache pshaders; - static PCacheEntry* last_entry; - static SHADERUID last_uid; + typedef std::map PCache; + static PCache pshaders; + static PCacheEntry* last_entry; + static SHADERUID last_uid; - static UidChecker pixel_uid_checker; - static UidChecker vertex_uid_checker; - static UidChecker geometry_uid_checker; + static UidChecker pixel_uid_checker; + static UidChecker vertex_uid_checker; + static UidChecker geometry_uid_checker; - static u32 s_ubo_buffer_size; - static s32 s_ubo_align; + static u32 s_ubo_buffer_size; + static s32 s_ubo_align; }; } // namespace OGL diff --git a/Source/Core/VideoBackends/OGL/RasterFont.cpp b/Source/Core/VideoBackends/OGL/RasterFont.cpp index 8bc1b3db84..6f0fd7ea92 100644 --- a/Source/Core/VideoBackends/OGL/RasterFont.cpp +++ b/Source/Core/VideoBackends/OGL/RasterFont.cpp @@ -14,267 +14,268 @@ namespace OGL { - static const int CHAR_WIDTH = 8; static const int CHAR_HEIGHT = 13; static const int CHAR_OFFSET = 32; static const int CHAR_COUNT = 95; static const u8 rasters[CHAR_COUNT][CHAR_HEIGHT] = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36}, - {0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00}, - {0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18}, - {0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70}, - {0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e}, - {0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c}, - {0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30}, - {0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00}, - {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03}, - {0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c}, - {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e}, - {0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, - {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06}, - {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60}, - {0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e}, - {0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18}, - {0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, - {0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e}, - {0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06}, - {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3}, - {0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, - {0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c}, - {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, - {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff}, - {0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c}, - {0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60}, - {0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18}, - {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70}, - {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03}, - {0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e}, - {0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00}, - {0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00}, - {0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78}, - {0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00}, - {0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00}, - {0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00}, - {0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f}, - {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, - {0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00} -}; + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36}, + {0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18}, + {0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70}, + {0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e}, + {0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c}, + {0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30}, + {0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03}, + {0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e}, + {0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06}, + {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60}, + {0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e}, + {0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18}, + {0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e}, + {0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06}, + {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3}, + {0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c}, + {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff}, + {0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c}, + {0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60}, + {0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18}, + {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70}, + {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03}, + {0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e}, + {0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00}, + {0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00}, + {0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78}, + {0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00}, + {0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00}, + {0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f}, + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, + {0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00}}; -static const char *s_vertexShaderSrc = - "uniform vec2 charSize;\n" - "uniform vec2 offset;" - "in vec2 rawpos;\n" - "in vec2 tex0;\n" - "out vec2 uv0;\n" - "void main(void) {\n" - " gl_Position = vec4(rawpos + offset,0,1);\n" - " uv0 = tex0 * charSize;\n" - "}\n"; +static const char* s_vertexShaderSrc = "uniform vec2 charSize;\n" + "uniform vec2 offset;" + "in vec2 rawpos;\n" + "in vec2 tex0;\n" + "out vec2 uv0;\n" + "void main(void) {\n" + " gl_Position = vec4(rawpos + offset,0,1);\n" + " uv0 = tex0 * charSize;\n" + "}\n"; -static const char *s_fragmentShaderSrc = - "SAMPLER_BINDING(8) uniform sampler2D samp8;\n" - "uniform vec4 color;\n" - "in vec2 uv0;\n" - "out vec4 ocol0;\n" - "void main(void) {\n" - " ocol0 = texture(samp8,uv0) * color;\n" - "}\n"; +static const char* s_fragmentShaderSrc = "SAMPLER_BINDING(8) uniform sampler2D samp8;\n" + "uniform vec4 color;\n" + "in vec2 uv0;\n" + "out vec4 ocol0;\n" + "void main(void) {\n" + " ocol0 = texture(samp8,uv0) * color;\n" + "}\n"; static SHADER s_shader; RasterFont::RasterFont() { - // generate the texture - glGenTextures(1, &texture); - glActiveTexture(GL_TEXTURE8); - glBindTexture(GL_TEXTURE_2D, texture); - std::vector texture_data(CHAR_WIDTH * CHAR_COUNT * CHAR_HEIGHT); - for (int y = 0; y < CHAR_HEIGHT; y++) - { - for (int c = 0; c < CHAR_COUNT; c++) - { - for (int x = 0; x < CHAR_WIDTH; x++) - { - bool pixel = (0 != (rasters[c][y] & (1 << (CHAR_WIDTH - x - 1)))); - texture_data[CHAR_WIDTH * CHAR_COUNT * y + CHAR_WIDTH * c + x] = pixel ? -1 : 0; - } - } - } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, CHAR_WIDTH * CHAR_COUNT, CHAR_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data.data()); + // generate the texture + glGenTextures(1, &texture); + glActiveTexture(GL_TEXTURE8); + glBindTexture(GL_TEXTURE_2D, texture); + std::vector texture_data(CHAR_WIDTH * CHAR_COUNT * CHAR_HEIGHT); + for (int y = 0; y < CHAR_HEIGHT; y++) + { + for (int c = 0; c < CHAR_COUNT; c++) + { + for (int x = 0; x < CHAR_WIDTH; x++) + { + bool pixel = (0 != (rasters[c][y] & (1 << (CHAR_WIDTH - x - 1)))); + texture_data[CHAR_WIDTH * CHAR_COUNT * y + CHAR_WIDTH * c + x] = pixel ? -1 : 0; + } + } + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, CHAR_WIDTH * CHAR_COUNT, CHAR_HEIGHT, 0, GL_RGBA, + GL_UNSIGNED_BYTE, texture_data.data()); - // generate shader - ProgramShaderCache::CompileShader(s_shader, s_vertexShaderSrc, s_fragmentShaderSrc); - s_shader.Bind(); + // generate shader + ProgramShaderCache::CompileShader(s_shader, s_vertexShaderSrc, s_fragmentShaderSrc); + s_shader.Bind(); - // bound uniforms - glUniform2f(glGetUniformLocation(s_shader.glprogid,"charSize"), 1.0f / GLfloat(CHAR_COUNT), 1.0f); - uniform_color_id = glGetUniformLocation(s_shader.glprogid,"color"); - glUniform4f(uniform_color_id, 1.0f, 1.0f, 1.0f, 1.0f); - uniform_offset_id = glGetUniformLocation(s_shader.glprogid, "offset"); - glUniform2f(uniform_offset_id, 0.0f, 0.0f); + // bound uniforms + glUniform2f(glGetUniformLocation(s_shader.glprogid, "charSize"), 1.0f / GLfloat(CHAR_COUNT), + 1.0f); + uniform_color_id = glGetUniformLocation(s_shader.glprogid, "color"); + glUniform4f(uniform_color_id, 1.0f, 1.0f, 1.0f, 1.0f); + uniform_offset_id = glGetUniformLocation(s_shader.glprogid, "offset"); + glUniform2f(uniform_offset_id, 0.0f, 0.0f); - // generate VBO & VAO - glGenBuffers(1, &VBO); - glGenVertexArrays(1, &VAO); - glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBindVertexArray(VAO); - glEnableVertexAttribArray(SHADER_POSITION_ATTRIB); - glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, nullptr); - glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB); - glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)nullptr+2); + // generate VBO & VAO + glGenBuffers(1, &VBO); + glGenVertexArrays(1, &VAO); + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBindVertexArray(VAO); + glEnableVertexAttribArray(SHADER_POSITION_ATTRIB); + glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat) * 4, nullptr); + glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB); + glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat) * 4, + (GLfloat*)nullptr + 2); } RasterFont::~RasterFont() { - glDeleteTextures(1, &texture); - glDeleteBuffers(1, &VBO); - glDeleteVertexArrays(1, &VAO); - s_shader.Destroy(); + glDeleteTextures(1, &texture); + glDeleteBuffers(1, &VBO); + glDeleteVertexArrays(1, &VAO); + s_shader.Destroy(); } -void RasterFont::printMultilineText(const std::string& text, double start_x, double start_y, double z, int bbWidth, int bbHeight, u32 color) +void RasterFont::printMultilineText(const std::string& text, double start_x, double start_y, + double z, int bbWidth, int bbHeight, u32 color) { - std::vector vertices(text.length() * 6 * 4); + std::vector vertices(text.length() * 6 * 4); - int usage = 0; - GLfloat delta_x = GLfloat(2 * CHAR_WIDTH) / GLfloat(bbWidth); - GLfloat delta_y = GLfloat(2 * CHAR_HEIGHT) / GLfloat(bbHeight); - GLfloat border_x = 2.0f / GLfloat(bbWidth); - GLfloat border_y = 4.0f / GLfloat(bbHeight); + int usage = 0; + GLfloat delta_x = GLfloat(2 * CHAR_WIDTH) / GLfloat(bbWidth); + GLfloat delta_y = GLfloat(2 * CHAR_HEIGHT) / GLfloat(bbHeight); + GLfloat border_x = 2.0f / GLfloat(bbWidth); + GLfloat border_y = 4.0f / GLfloat(bbHeight); - GLfloat x = GLfloat(start_x); - GLfloat y = GLfloat(start_y); + GLfloat x = GLfloat(start_x); + GLfloat y = GLfloat(start_y); - for (const char& c : text) - { - if (c == '\n') - { - x = GLfloat(start_x); - y -= delta_y + border_y; - continue; - } + for (const char& c : text) + { + if (c == '\n') + { + x = GLfloat(start_x); + y -= delta_y + border_y; + continue; + } - // do not print spaces, they can be skipped easily - if (c == ' ') - { - x += delta_x + border_x; - continue; - } + // do not print spaces, they can be skipped easily + if (c == ' ') + { + x += delta_x + border_x; + continue; + } - if (c < CHAR_OFFSET || c >= CHAR_COUNT + CHAR_OFFSET) - continue; + if (c < CHAR_OFFSET || c >= CHAR_COUNT + CHAR_OFFSET) + continue; - vertices[usage++] = x; - vertices[usage++] = y; - vertices[usage++] = GLfloat(c - CHAR_OFFSET); - vertices[usage++] = 0.0f; + vertices[usage++] = x; + vertices[usage++] = y; + vertices[usage++] = GLfloat(c - CHAR_OFFSET); + vertices[usage++] = 0.0f; - vertices[usage++] = x + delta_x; - vertices[usage++] = y; - vertices[usage++] = GLfloat(c - CHAR_OFFSET + 1); - vertices[usage++] = 0.0f; + vertices[usage++] = x + delta_x; + vertices[usage++] = y; + vertices[usage++] = GLfloat(c - CHAR_OFFSET + 1); + vertices[usage++] = 0.0f; - vertices[usage++] = x + delta_x; - vertices[usage++] = y + delta_y; - vertices[usage++] = GLfloat(c - CHAR_OFFSET + 1); - vertices[usage++] = 1.0f; + vertices[usage++] = x + delta_x; + vertices[usage++] = y + delta_y; + vertices[usage++] = GLfloat(c - CHAR_OFFSET + 1); + vertices[usage++] = 1.0f; - vertices[usage++] = x; - vertices[usage++] = y; - vertices[usage++] = GLfloat(c - CHAR_OFFSET); - vertices[usage++] = 0.0f; + vertices[usage++] = x; + vertices[usage++] = y; + vertices[usage++] = GLfloat(c - CHAR_OFFSET); + vertices[usage++] = 0.0f; - vertices[usage++] = x + delta_x; - vertices[usage++] = y + delta_y; - vertices[usage++] = GLfloat(c - CHAR_OFFSET + 1); - vertices[usage++] = 1.0f; + vertices[usage++] = x + delta_x; + vertices[usage++] = y + delta_y; + vertices[usage++] = GLfloat(c - CHAR_OFFSET + 1); + vertices[usage++] = 1.0f; - vertices[usage++] = x; - vertices[usage++] = y + delta_y; - vertices[usage++] = GLfloat(c - CHAR_OFFSET); - vertices[usage++] = 1.0f; + vertices[usage++] = x; + vertices[usage++] = y + delta_y; + vertices[usage++] = GLfloat(c - CHAR_OFFSET); + vertices[usage++] = 1.0f; - x += delta_x + border_x; - } + x += delta_x + border_x; + } - if (!usage) - { - return; - } + if (!usage) + { + return; + } - glBindVertexArray(VAO); - glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferData(GL_ARRAY_BUFFER, usage*sizeof(GLfloat), vertices.data(), GL_STREAM_DRAW); + glBindVertexArray(VAO); + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, usage * sizeof(GLfloat), vertices.data(), GL_STREAM_DRAW); - s_shader.Bind(); + s_shader.Bind(); - // shadows - glUniform2f(uniform_offset_id, 2.0f / GLfloat(bbWidth), -2.0f / GLfloat(bbHeight)); - glUniform4f(uniform_color_id, 0.0f, 0.0f, 0.0f, GLfloat((color>>24)&0xff)/255.f); - glDrawArrays(GL_TRIANGLES, 0, usage/4); + // shadows + glUniform2f(uniform_offset_id, 2.0f / GLfloat(bbWidth), -2.0f / GLfloat(bbHeight)); + glUniform4f(uniform_color_id, 0.0f, 0.0f, 0.0f, GLfloat((color >> 24) & 0xff) / 255.f); + glDrawArrays(GL_TRIANGLES, 0, usage / 4); - glUniform2f(uniform_offset_id, 0.0f, 0.0f); - glUniform4f(uniform_color_id, GLfloat((color>>16)&0xff)/255.f,GLfloat((color>>8)&0xff)/255.f,GLfloat((color>>0)&0xff)/255.f,GLfloat((color>>24)&0xff)/255.f); - glDrawArrays(GL_TRIANGLES, 0, usage/4); + glUniform2f(uniform_offset_id, 0.0f, 0.0f); + glUniform4f(uniform_color_id, GLfloat((color >> 16) & 0xff) / 255.f, + GLfloat((color >> 8) & 0xff) / 255.f, GLfloat((color >> 0) & 0xff) / 255.f, + GLfloat((color >> 24) & 0xff) / 255.f); + glDrawArrays(GL_TRIANGLES, 0, usage / 4); } - } diff --git a/Source/Core/VideoBackends/OGL/RasterFont.h b/Source/Core/VideoBackends/OGL/RasterFont.h index ca0e1d6099..359e4f8551 100644 --- a/Source/Core/VideoBackends/OGL/RasterFont.h +++ b/Source/Core/VideoBackends/OGL/RasterFont.h @@ -10,22 +10,21 @@ namespace OGL { - class RasterFont { public: - RasterFont(); - ~RasterFont(); - static int debug; + RasterFont(); + ~RasterFont(); + static int debug; + + void printMultilineText(const std::string& text, double x, double y, double z, int bbWidth, + int bbHeight, u32 color); - void printMultilineText(const std::string& text, double x, double y, double z, int bbWidth, int bbHeight, u32 color); private: - - u32 VBO; - u32 VAO; - u32 texture; - u32 uniform_color_id; - u32 uniform_offset_id; + u32 VBO; + u32 VAO; + u32 texture; + u32 uniform_color_id; + u32 uniform_offset_id; }; - } diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 73fc32d7ea..8805a4bea8 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -13,11 +13,11 @@ #include "Common/Atomic.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/MathUtil.h" -#include "Common/StringUtil.h" #include "Common/GL/GLInterfaceBase.h" #include "Common/GL/GLUtil.h" #include "Common/Logging/LogManager.h" +#include "Common/MathUtil.h" +#include "Common/StringUtil.h" #include "Core/ConfigManager.h" #include "Core/Core.h" @@ -32,7 +32,7 @@ #include "VideoBackends/OGL/TextureCache.h" #include "VideoBackends/OGL/VertexManager.h" -#if defined(HAVE_LIBAV) || defined (_WIN32) +#if defined(HAVE_LIBAV) || defined(_WIN32) #include "VideoCommon/AVIDump.h" #endif #include "VideoCommon/BPFunctions.h" @@ -45,10 +45,9 @@ #include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/VideoConfig.h" - void VideoConfig::UpdateProjectionHack() { - ::UpdateProjectionHack(g_Config.iPhackvalue, g_Config.sPhackvalue); + ::UpdateProjectionHack(g_Config.iPhackvalue, g_Config.sPhackvalue); } static int OSDInternalW, OSDInternalH; @@ -56,7 +55,6 @@ static int s_max_texture_size = 0; namespace OGL { - VideoConfig g_ogl_config; // Declarations and definitions @@ -74,617 +72,689 @@ static u32 s_blendMode; static bool s_vsync; // EFB cache related -static const u32 EFB_CACHE_RECT_SIZE = 64; // Cache 64x64 blocks. -static const u32 EFB_CACHE_WIDTH = (EFB_WIDTH + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE; // round up +static const u32 EFB_CACHE_RECT_SIZE = 64; // Cache 64x64 blocks. +static const u32 EFB_CACHE_WIDTH = + (EFB_WIDTH + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE; // round up static const u32 EFB_CACHE_HEIGHT = (EFB_HEIGHT + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE; static bool s_efbCacheValid[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT]; static bool s_efbCacheIsCleared = false; -static std::vector s_efbCache[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT]; // 2 for PEEK_Z and PEEK_COLOR +static std::vector + s_efbCache[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT]; // 2 for PEEK_Z and PEEK_COLOR -static void APIENTRY ErrorCallback( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, const void* userParam) +static void APIENTRY ErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity, + GLsizei length, const char* message, const void* userParam) { - const char *s_source; - const char *s_type; + const char* s_source; + const char* s_type; - switch (source) - { - case GL_DEBUG_SOURCE_API_ARB: s_source = "API"; break; - case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: s_source = "Window System"; break; - case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: s_source = "Shader Compiler"; break; - case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: s_source = "Third Party"; break; - case GL_DEBUG_SOURCE_APPLICATION_ARB: s_source = "Application"; break; - case GL_DEBUG_SOURCE_OTHER_ARB: s_source = "Other"; break; - default: s_source = "Unknown"; break; - } - switch (type) - { - case GL_DEBUG_TYPE_ERROR_ARB: s_type = "Error"; break; - case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: s_type = "Deprecated"; break; - case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: s_type = "Undefined"; break; - case GL_DEBUG_TYPE_PORTABILITY_ARB: s_type = "Portability"; break; - case GL_DEBUG_TYPE_PERFORMANCE_ARB: s_type = "Performance"; break; - case GL_DEBUG_TYPE_OTHER_ARB: s_type = "Other"; break; - default: s_type = "Unknown"; break; - } - switch (severity) - { - case GL_DEBUG_SEVERITY_HIGH_ARB: ERROR_LOG(HOST_GPU, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message); break; - case GL_DEBUG_SEVERITY_MEDIUM_ARB: WARN_LOG(HOST_GPU, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message); break; - case GL_DEBUG_SEVERITY_LOW_ARB: WARN_LOG(HOST_GPU, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message); break; - case GL_DEBUG_SEVERITY_NOTIFICATION: DEBUG_LOG(HOST_GPU, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message); break; - default: ERROR_LOG(HOST_GPU, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message); break; - } + switch (source) + { + case GL_DEBUG_SOURCE_API_ARB: + s_source = "API"; + break; + case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: + s_source = "Window System"; + break; + case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: + s_source = "Shader Compiler"; + break; + case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: + s_source = "Third Party"; + break; + case GL_DEBUG_SOURCE_APPLICATION_ARB: + s_source = "Application"; + break; + case GL_DEBUG_SOURCE_OTHER_ARB: + s_source = "Other"; + break; + default: + s_source = "Unknown"; + break; + } + switch (type) + { + case GL_DEBUG_TYPE_ERROR_ARB: + s_type = "Error"; + break; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: + s_type = "Deprecated"; + break; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: + s_type = "Undefined"; + break; + case GL_DEBUG_TYPE_PORTABILITY_ARB: + s_type = "Portability"; + break; + case GL_DEBUG_TYPE_PERFORMANCE_ARB: + s_type = "Performance"; + break; + case GL_DEBUG_TYPE_OTHER_ARB: + s_type = "Other"; + break; + default: + s_type = "Unknown"; + break; + } + switch (severity) + { + case GL_DEBUG_SEVERITY_HIGH_ARB: + ERROR_LOG(HOST_GPU, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message); + break; + case GL_DEBUG_SEVERITY_MEDIUM_ARB: + WARN_LOG(HOST_GPU, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message); + break; + case GL_DEBUG_SEVERITY_LOW_ARB: + WARN_LOG(HOST_GPU, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message); + break; + case GL_DEBUG_SEVERITY_NOTIFICATION: + DEBUG_LOG(HOST_GPU, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message); + break; + default: + ERROR_LOG(HOST_GPU, "id: %x, source: %s, type: %s - %s", id, s_source, s_type, message); + break; + } } // Two small Fallbacks to avoid GL_ARB_ES2_compatibility static void APIENTRY DepthRangef(GLfloat neardepth, GLfloat fardepth) { - glDepthRange(neardepth, fardepth); + glDepthRange(neardepth, fardepth); } static void APIENTRY ClearDepthf(GLfloat depthval) { - glClearDepth(depthval); + glClearDepth(depthval); } static void InitDriverInfo() { - std::string svendor = std::string(g_ogl_config.gl_vendor); - std::string srenderer = std::string(g_ogl_config.gl_renderer); - std::string sversion = std::string(g_ogl_config.gl_version); - DriverDetails::Vendor vendor = DriverDetails::VENDOR_UNKNOWN; - DriverDetails::Driver driver = DriverDetails::DRIVER_UNKNOWN; - DriverDetails::Family family = DriverDetails::Family::UNKNOWN; - double version = 0.0; + std::string svendor = std::string(g_ogl_config.gl_vendor); + std::string srenderer = std::string(g_ogl_config.gl_renderer); + std::string sversion = std::string(g_ogl_config.gl_version); + DriverDetails::Vendor vendor = DriverDetails::VENDOR_UNKNOWN; + DriverDetails::Driver driver = DriverDetails::DRIVER_UNKNOWN; + DriverDetails::Family family = DriverDetails::Family::UNKNOWN; + double version = 0.0; - // Get the vendor first - if (svendor == "NVIDIA Corporation" && srenderer != "NVIDIA Tegra") - { - vendor = DriverDetails::VENDOR_NVIDIA; - } - else if (svendor == "ATI Technologies Inc." || svendor == "Advanced Micro Devices, Inc.") - { - vendor = DriverDetails::VENDOR_ATI; - } - else if (std::string::npos != sversion.find("Mesa")) - { - vendor = DriverDetails::VENDOR_MESA; - } - else if (std::string::npos != svendor.find("Intel")) - { - vendor = DriverDetails::VENDOR_INTEL; - } - else if (svendor == "ARM") - { - vendor = DriverDetails::VENDOR_ARM; - } - else if (svendor == "http://limadriver.org/") - { - vendor = DriverDetails::VENDOR_ARM; - driver = DriverDetails::DRIVER_LIMA; - } - else if (svendor == "Qualcomm") - { - vendor = DriverDetails::VENDOR_QUALCOMM; - } - else if (svendor == "Imagination Technologies") - { - vendor = DriverDetails::VENDOR_IMGTEC; - } - else if (svendor == "NVIDIA Corporation" && srenderer == "NVIDIA Tegra") - { - vendor = DriverDetails::VENDOR_TEGRA; - } - else if (svendor == "Vivante Corporation") - { - vendor = DriverDetails::VENDOR_VIVANTE; - } + // Get the vendor first + if (svendor == "NVIDIA Corporation" && srenderer != "NVIDIA Tegra") + { + vendor = DriverDetails::VENDOR_NVIDIA; + } + else if (svendor == "ATI Technologies Inc." || svendor == "Advanced Micro Devices, Inc.") + { + vendor = DriverDetails::VENDOR_ATI; + } + else if (std::string::npos != sversion.find("Mesa")) + { + vendor = DriverDetails::VENDOR_MESA; + } + else if (std::string::npos != svendor.find("Intel")) + { + vendor = DriverDetails::VENDOR_INTEL; + } + else if (svendor == "ARM") + { + vendor = DriverDetails::VENDOR_ARM; + } + else if (svendor == "http://limadriver.org/") + { + vendor = DriverDetails::VENDOR_ARM; + driver = DriverDetails::DRIVER_LIMA; + } + else if (svendor == "Qualcomm") + { + vendor = DriverDetails::VENDOR_QUALCOMM; + } + else if (svendor == "Imagination Technologies") + { + vendor = DriverDetails::VENDOR_IMGTEC; + } + else if (svendor == "NVIDIA Corporation" && srenderer == "NVIDIA Tegra") + { + vendor = DriverDetails::VENDOR_TEGRA; + } + else if (svendor == "Vivante Corporation") + { + vendor = DriverDetails::VENDOR_VIVANTE; + } - // Get device family and driver version...if we care about it - switch (vendor) - { - case DriverDetails::VENDOR_QUALCOMM: - { - driver = DriverDetails::DRIVER_QUALCOMM; - double glVersion; - sscanf(g_ogl_config.gl_version, "OpenGL ES %lg V@%lg", &glVersion, &version); - } - break; - case DriverDetails::VENDOR_ARM: - // Currently the Mali-T line has two families in it. - // Mali-T6xx and Mali-T7xx - // These two families are similar enough that they share bugs in their drivers. - // - // Mali drivers provide no way to explicitly find out what video driver is running. - // This is similar to how we can't find the Nvidia driver version in Windows. - // Good thing is that ARM introduces a new video driver about once every two years so we can - // find the driver version by the features it exposes. - // r2p0 - No OpenGL ES 3.0 support (We don't support this) - // r3p0 - OpenGL ES 3.0 support - // r4p0 - Supports 'GL_EXT_shader_pixel_local_storage' extension. + // Get device family and driver version...if we care about it + switch (vendor) + { + case DriverDetails::VENDOR_QUALCOMM: + { + driver = DriverDetails::DRIVER_QUALCOMM; + double glVersion; + sscanf(g_ogl_config.gl_version, "OpenGL ES %lg V@%lg", &glVersion, &version); + } + break; + case DriverDetails::VENDOR_ARM: + // Currently the Mali-T line has two families in it. + // Mali-T6xx and Mali-T7xx + // These two families are similar enough that they share bugs in their drivers. + // + // Mali drivers provide no way to explicitly find out what video driver is running. + // This is similar to how we can't find the Nvidia driver version in Windows. + // Good thing is that ARM introduces a new video driver about once every two years so we can + // find the driver version by the features it exposes. + // r2p0 - No OpenGL ES 3.0 support (We don't support this) + // r3p0 - OpenGL ES 3.0 support + // r4p0 - Supports 'GL_EXT_shader_pixel_local_storage' extension. - driver = DriverDetails::DRIVER_ARM; - if (GLExtensions::Supports("GL_EXT_shader_pixel_local_storage")) - version = 400; - else - version = 300; - break; - case DriverDetails::VENDOR_MESA: - { - if (svendor == "nouveau") - { - driver = DriverDetails::DRIVER_NOUVEAU; - } - else if (svendor == "Intel Open Source Technology Center") - { - driver = DriverDetails::DRIVER_I965; - if (srenderer.find("Sandybridge") != std::string::npos) - family = DriverDetails::Family::INTEL_SANDY; - else if (srenderer.find("Ivybridge") != std::string::npos) - family = DriverDetails::Family::INTEL_IVY; - } - else if (std::string::npos != srenderer.find("AMD") || std::string::npos != srenderer.find("ATI")) - { - driver = DriverDetails::DRIVER_R600; - } + driver = DriverDetails::DRIVER_ARM; + if (GLExtensions::Supports("GL_EXT_shader_pixel_local_storage")) + version = 400; + else + version = 300; + break; + case DriverDetails::VENDOR_MESA: + { + if (svendor == "nouveau") + { + driver = DriverDetails::DRIVER_NOUVEAU; + } + else if (svendor == "Intel Open Source Technology Center") + { + driver = DriverDetails::DRIVER_I965; + if (srenderer.find("Sandybridge") != std::string::npos) + family = DriverDetails::Family::INTEL_SANDY; + else if (srenderer.find("Ivybridge") != std::string::npos) + family = DriverDetails::Family::INTEL_IVY; + } + else if (std::string::npos != srenderer.find("AMD") || + std::string::npos != srenderer.find("ATI")) + { + driver = DriverDetails::DRIVER_R600; + } - int major = 0; - int minor = 0; - int release = 0; - sscanf(g_ogl_config.gl_version, "%*s (Core Profile) Mesa %d.%d.%d", &major, &minor, &release); - version = 100*major + 10*minor + release; - } - break; - case DriverDetails::VENDOR_INTEL: // Happens in OS X/Windows - { - u32 market_name; - sscanf(g_ogl_config.gl_renderer, "Intel HD Graphics %d", &market_name); - switch (market_name) - { - case 2000: - case 3000: - family = DriverDetails::Family::INTEL_SANDY; - break; - case 2500: - case 4000: - family = DriverDetails::Family::INTEL_IVY; - break; - default: - family = DriverDetails::Family::UNKNOWN; - break; - }; + int major = 0; + int minor = 0; + int release = 0; + sscanf(g_ogl_config.gl_version, "%*s (Core Profile) Mesa %d.%d.%d", &major, &minor, &release); + version = 100 * major + 10 * minor + release; + } + break; + case DriverDetails::VENDOR_INTEL: // Happens in OS X/Windows + { + u32 market_name; + sscanf(g_ogl_config.gl_renderer, "Intel HD Graphics %d", &market_name); + switch (market_name) + { + case 2000: + case 3000: + family = DriverDetails::Family::INTEL_SANDY; + break; + case 2500: + case 4000: + family = DriverDetails::Family::INTEL_IVY; + break; + default: + family = DriverDetails::Family::UNKNOWN; + break; + }; #ifdef _WIN32 - int glmajor = 0; - int glminor = 0; - int major = 0; - int minor = 0; - int release = 0; - int revision = 0; - // Example version string: '4.3.0 - Build 10.18.10.3907' - sscanf(g_ogl_config.gl_version, "%d.%d.0 - Build %d.%d.%d.%d", &glmajor, &glminor, &major, &minor, &release, &revision); - version = 100000000 * major + 1000000 * minor + 10000 * release + revision; - version /= 10000; + int glmajor = 0; + int glminor = 0; + int major = 0; + int minor = 0; + int release = 0; + int revision = 0; + // Example version string: '4.3.0 - Build 10.18.10.3907' + sscanf(g_ogl_config.gl_version, "%d.%d.0 - Build %d.%d.%d.%d", &glmajor, &glminor, &major, + &minor, &release, &revision); + version = 100000000 * major + 1000000 * minor + 10000 * release + revision; + version /= 10000; #endif - } - break; - case DriverDetails::VENDOR_NVIDIA: - { - int glmajor = 0; - int glminor = 0; - int glrelease = 0; - int major = 0; - int minor = 0; - // TODO: this is known to be broken on Windows - // Nvidia seems to have removed their driver version from this string, so we can't get it. - // hopefully we'll never have to workaround Nvidia bugs - sscanf(g_ogl_config.gl_version, "%d.%d.%d NVIDIA %d.%d", &glmajor, &glminor, &glrelease, &major, &minor); - version = 100*major + minor; - } - break; - // We don't care about these - default: - break; - } - DriverDetails::Init(vendor, driver, version, family); + } + break; + case DriverDetails::VENDOR_NVIDIA: + { + int glmajor = 0; + int glminor = 0; + int glrelease = 0; + int major = 0; + int minor = 0; + // TODO: this is known to be broken on Windows + // Nvidia seems to have removed their driver version from this string, so we can't get it. + // hopefully we'll never have to workaround Nvidia bugs + sscanf(g_ogl_config.gl_version, "%d.%d.%d NVIDIA %d.%d", &glmajor, &glminor, &glrelease, &major, + &minor); + version = 100 * major + minor; + } + break; + // We don't care about these + default: + break; + } + DriverDetails::Init(vendor, driver, version, family); } // Init functions Renderer::Renderer() { - OSDInternalW = 0; - OSDInternalH = 0; + OSDInternalW = 0; + OSDInternalH = 0; - s_blendMode = 0; + s_blendMode = 0; - bool bSuccess = true; + bool bSuccess = true; - // Init extension support. - if (!GLExtensions::Init()) - { - // OpenGL 2.0 is required for all shader based drawings. There is no way to get this by extensions - PanicAlert("GPU: OGL ERROR: Does your video card support OpenGL 2.0?"); - bSuccess = false; - } + // Init extension support. + if (!GLExtensions::Init()) + { + // OpenGL 2.0 is required for all shader based drawings. There is no way to get this by + // extensions + PanicAlert("GPU: OGL ERROR: Does your video card support OpenGL 2.0?"); + bSuccess = false; + } - g_ogl_config.gl_vendor = (const char*)glGetString(GL_VENDOR); - g_ogl_config.gl_renderer = (const char*)glGetString(GL_RENDERER); - g_ogl_config.gl_version = (const char*)glGetString(GL_VERSION); - g_ogl_config.glsl_version = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION); + g_ogl_config.gl_vendor = (const char*)glGetString(GL_VENDOR); + g_ogl_config.gl_renderer = (const char*)glGetString(GL_RENDERER); + g_ogl_config.gl_version = (const char*)glGetString(GL_VERSION); + g_ogl_config.glsl_version = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION); - InitDriverInfo(); + InitDriverInfo(); - if (GLExtensions::Version() < 300) - { - // integer vertex attributes require a gl3 only function - PanicAlert("GPU: OGL ERROR: Need OpenGL version 3.\n" - "GPU: Does your video card support OpenGL 3?"); - bSuccess = false; - } + if (GLExtensions::Version() < 300) + { + // integer vertex attributes require a gl3 only function + PanicAlert("GPU: OGL ERROR: Need OpenGL version 3.\n" + "GPU: Does your video card support OpenGL 3?"); + bSuccess = false; + } - // check for the max vertex attributes - GLint numvertexattribs = 0; - glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &numvertexattribs); - if (numvertexattribs < 16) - { - PanicAlert("GPU: OGL ERROR: Number of attributes %d not enough.\n" - "GPU: Does your video card support OpenGL 2.x?", - numvertexattribs); - bSuccess = false; - } + // check for the max vertex attributes + GLint numvertexattribs = 0; + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &numvertexattribs); + if (numvertexattribs < 16) + { + PanicAlert("GPU: OGL ERROR: Number of attributes %d not enough.\n" + "GPU: Does your video card support OpenGL 2.x?", + numvertexattribs); + bSuccess = false; + } - // check the max texture width and height - GLint max_texture_size; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&max_texture_size); - if (max_texture_size < 1024) - { - PanicAlert("GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024.", - max_texture_size); - bSuccess = false; - } + // check the max texture width and height + GLint max_texture_size; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*)&max_texture_size); + if (max_texture_size < 1024) + { + PanicAlert("GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024.", max_texture_size); + bSuccess = false; + } - if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) - { - if (!GLExtensions::Supports("GL_ARB_framebuffer_object")) - { - // We want the ogl3 framebuffer instead of the ogl2 one for better blitting support. - // It's also compatible with the gles3 one. - PanicAlert("GPU: ERROR: Need GL_ARB_framebuffer_object for multiple render targets.\n" - "GPU: Does your video card support OpenGL 3.0?"); - bSuccess = false; - } + if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) + { + if (!GLExtensions::Supports("GL_ARB_framebuffer_object")) + { + // We want the ogl3 framebuffer instead of the ogl2 one for better blitting support. + // It's also compatible with the gles3 one. + PanicAlert("GPU: ERROR: Need GL_ARB_framebuffer_object for multiple render targets.\n" + "GPU: Does your video card support OpenGL 3.0?"); + bSuccess = false; + } - if (!GLExtensions::Supports("GL_ARB_vertex_array_object")) - { - // This extension is used to replace lots of pointer setting function. - // Also gles3 requires to use it. - PanicAlert("GPU: OGL ERROR: Need GL_ARB_vertex_array_object.\n" - "GPU: Does your video card support OpenGL 3.0?"); - bSuccess = false; - } + if (!GLExtensions::Supports("GL_ARB_vertex_array_object")) + { + // This extension is used to replace lots of pointer setting function. + // Also gles3 requires to use it. + PanicAlert("GPU: OGL ERROR: Need GL_ARB_vertex_array_object.\n" + "GPU: Does your video card support OpenGL 3.0?"); + bSuccess = false; + } - if (!GLExtensions::Supports("GL_ARB_map_buffer_range")) - { - // ogl3 buffer mapping for better streaming support. - // The ogl2 one also isn't in gles3. - PanicAlert("GPU: OGL ERROR: Need GL_ARB_map_buffer_range.\n" - "GPU: Does your video card support OpenGL 3.0?"); - bSuccess = false; - } + if (!GLExtensions::Supports("GL_ARB_map_buffer_range")) + { + // ogl3 buffer mapping for better streaming support. + // The ogl2 one also isn't in gles3. + PanicAlert("GPU: OGL ERROR: Need GL_ARB_map_buffer_range.\n" + "GPU: Does your video card support OpenGL 3.0?"); + bSuccess = false; + } - if (!GLExtensions::Supports("GL_ARB_uniform_buffer_object")) - { - // ubo allow us to keep the current constants on shader switches - // we also can stream them much nicer and pack into it whatever we want to - PanicAlert("GPU: OGL ERROR: Need GL_ARB_uniform_buffer_object.\n" - "GPU: Does your video card support OpenGL 3.1?"); - bSuccess = false; - } - else if (DriverDetails::HasBug(DriverDetails::BUG_BROKENUBO)) - { - PanicAlert("Buggy GPU driver detected.\n" - "Please either install the closed-source GPU driver or update your Mesa 3D version."); - bSuccess = false; - } + if (!GLExtensions::Supports("GL_ARB_uniform_buffer_object")) + { + // ubo allow us to keep the current constants on shader switches + // we also can stream them much nicer and pack into it whatever we want to + PanicAlert("GPU: OGL ERROR: Need GL_ARB_uniform_buffer_object.\n" + "GPU: Does your video card support OpenGL 3.1?"); + bSuccess = false; + } + else if (DriverDetails::HasBug(DriverDetails::BUG_BROKENUBO)) + { + PanicAlert( + "Buggy GPU driver detected.\n" + "Please either install the closed-source GPU driver or update your Mesa 3D version."); + bSuccess = false; + } - if (!GLExtensions::Supports("GL_ARB_sampler_objects")) - { - // Our sampler cache uses this extension. It could easyly be workaround and it's by far the - // highest requirement, but it seems that no driver lacks support for it. - PanicAlert("GPU: OGL ERROR: Need GL_ARB_sampler_objects.\n" - "GPU: Does your video card support OpenGL 3.3?"); - bSuccess = false; - } + if (!GLExtensions::Supports("GL_ARB_sampler_objects")) + { + // Our sampler cache uses this extension. It could easyly be workaround and it's by far the + // highest requirement, but it seems that no driver lacks support for it. + PanicAlert("GPU: OGL ERROR: Need GL_ARB_sampler_objects.\n" + "GPU: Does your video card support OpenGL 3.3?"); + bSuccess = false; + } - // OpenGL 3 doesn't provide GLES like float functions for depth. - // They are in core in OpenGL 4.1, so almost every driver should support them. - // But for the oldest ones, we provide fallbacks to the old double functions. - if (!GLExtensions::Supports("GL_ARB_ES2_compatibility")) - { - glDepthRangef = DepthRangef; - glClearDepthf = ClearDepthf; - } - } + // OpenGL 3 doesn't provide GLES like float functions for depth. + // They are in core in OpenGL 4.1, so almost every driver should support them. + // But for the oldest ones, we provide fallbacks to the old double functions. + if (!GLExtensions::Supports("GL_ARB_ES2_compatibility")) + { + glDepthRangef = DepthRangef; + glClearDepthf = ClearDepthf; + } + } - // Copy the GPU name to g_Config, so Analytics can see it. - g_Config.backend_info.AdapterName = g_ogl_config.gl_renderer; + // Copy the GPU name to g_Config, so Analytics can see it. + g_Config.backend_info.AdapterName = g_ogl_config.gl_renderer; - g_Config.backend_info.bSupportsDualSourceBlend = GLExtensions::Supports("GL_ARB_blend_func_extended") || - GLExtensions::Supports("GL_EXT_blend_func_extended"); - g_Config.backend_info.bSupportsPrimitiveRestart = !DriverDetails::HasBug(DriverDetails::BUG_PRIMITIVERESTART) && - ((GLExtensions::Version() >= 310) || GLExtensions::Supports("GL_NV_primitive_restart")); - g_Config.backend_info.bSupportsBBox = GLExtensions::Supports("GL_ARB_shader_storage_buffer_object"); - g_Config.backend_info.bSupportsGSInstancing = GLExtensions::Supports("GL_ARB_gpu_shader5"); - g_Config.backend_info.bSupportsSSAA = GLExtensions::Supports("GL_ARB_gpu_shader5") && GLExtensions::Supports("GL_ARB_sample_shading"); - g_Config.backend_info.bSupportsGeometryShaders = GLExtensions::Version() >= 320 && !DriverDetails::HasBug(DriverDetails::BUG_BROKENGEOMETRYSHADERS); - g_Config.backend_info.bSupportsPaletteConversion = GLExtensions::Supports("GL_ARB_texture_buffer_object") || - GLExtensions::Supports("GL_OES_texture_buffer") || - GLExtensions::Supports("GL_EXT_texture_buffer"); - g_Config.backend_info.bSupportsClipControl = GLExtensions::Supports("GL_ARB_clip_control"); - g_ogl_config.bSupportsCopySubImage = (GLExtensions::Supports("GL_ARB_copy_image") || - GLExtensions::Supports("GL_NV_copy_image") || - GLExtensions::Supports("GL_EXT_copy_image") || - GLExtensions::Supports("GL_OES_copy_image")) && - !DriverDetails::HasBug(DriverDetails::BUG_BROKENCOPYIMAGE); + g_Config.backend_info.bSupportsDualSourceBlend = + GLExtensions::Supports("GL_ARB_blend_func_extended") || + GLExtensions::Supports("GL_EXT_blend_func_extended"); + g_Config.backend_info.bSupportsPrimitiveRestart = + !DriverDetails::HasBug(DriverDetails::BUG_PRIMITIVERESTART) && + ((GLExtensions::Version() >= 310) || GLExtensions::Supports("GL_NV_primitive_restart")); + g_Config.backend_info.bSupportsBBox = + GLExtensions::Supports("GL_ARB_shader_storage_buffer_object"); + g_Config.backend_info.bSupportsGSInstancing = GLExtensions::Supports("GL_ARB_gpu_shader5"); + g_Config.backend_info.bSupportsSSAA = GLExtensions::Supports("GL_ARB_gpu_shader5") && + GLExtensions::Supports("GL_ARB_sample_shading"); + g_Config.backend_info.bSupportsGeometryShaders = + GLExtensions::Version() >= 320 && + !DriverDetails::HasBug(DriverDetails::BUG_BROKENGEOMETRYSHADERS); + g_Config.backend_info.bSupportsPaletteConversion = + GLExtensions::Supports("GL_ARB_texture_buffer_object") || + GLExtensions::Supports("GL_OES_texture_buffer") || + GLExtensions::Supports("GL_EXT_texture_buffer"); + g_Config.backend_info.bSupportsClipControl = GLExtensions::Supports("GL_ARB_clip_control"); + g_ogl_config.bSupportsCopySubImage = + (GLExtensions::Supports("GL_ARB_copy_image") || GLExtensions::Supports("GL_NV_copy_image") || + GLExtensions::Supports("GL_EXT_copy_image") || + GLExtensions::Supports("GL_OES_copy_image")) && + !DriverDetails::HasBug(DriverDetails::BUG_BROKENCOPYIMAGE); - // Desktop OpenGL supports the binding layout if it supports 420pack - // OpenGL ES 3.1 supports it implicitly without an extension - g_Config.backend_info.bSupportsBindingLayout = GLExtensions::Supports("GL_ARB_shading_language_420pack"); + // Desktop OpenGL supports the binding layout if it supports 420pack + // OpenGL ES 3.1 supports it implicitly without an extension + g_Config.backend_info.bSupportsBindingLayout = + GLExtensions::Supports("GL_ARB_shading_language_420pack"); - g_ogl_config.bSupportsGLSLCache = GLExtensions::Supports("GL_ARB_get_program_binary"); - g_ogl_config.bSupportsGLPinnedMemory = GLExtensions::Supports("GL_AMD_pinned_memory"); - g_ogl_config.bSupportsGLSync = GLExtensions::Supports("GL_ARB_sync"); - g_ogl_config.bSupportsGLBaseVertex = GLExtensions::Supports("GL_ARB_draw_elements_base_vertex") || - GLExtensions::Supports("GL_EXT_draw_elements_base_vertex") || - GLExtensions::Supports("GL_OES_draw_elements_base_vertex"); - g_ogl_config.bSupportsGLBufferStorage = GLExtensions::Supports("GL_ARB_buffer_storage") || - GLExtensions::Supports("GL_EXT_buffer_storage"); - g_ogl_config.bSupportsMSAA = GLExtensions::Supports("GL_ARB_texture_multisample"); - g_ogl_config.bSupportViewportFloat = GLExtensions::Supports("GL_ARB_viewport_array"); - g_ogl_config.bSupportsDebug = GLExtensions::Supports("GL_KHR_debug") || - GLExtensions::Supports("GL_ARB_debug_output"); - g_ogl_config.bSupports3DTextureStorage = GLExtensions::Supports("GL_ARB_texture_storage_multisample") || - GLExtensions::Supports("GL_OES_texture_storage_multisample_2d_array"); - g_ogl_config.bSupports2DTextureStorage = GLExtensions::Supports("GL_ARB_texture_storage_multisample"); - g_ogl_config.bSupportsEarlyFragmentTests = GLExtensions::Supports("GL_ARB_shader_image_load_store"); - g_ogl_config.bSupportsConservativeDepth = GLExtensions::Supports("GL_ARB_conservative_depth"); - g_ogl_config.bSupportsAniso = GLExtensions::Supports("GL_EXT_texture_filter_anisotropic"); + g_ogl_config.bSupportsGLSLCache = GLExtensions::Supports("GL_ARB_get_program_binary"); + g_ogl_config.bSupportsGLPinnedMemory = GLExtensions::Supports("GL_AMD_pinned_memory"); + g_ogl_config.bSupportsGLSync = GLExtensions::Supports("GL_ARB_sync"); + g_ogl_config.bSupportsGLBaseVertex = GLExtensions::Supports("GL_ARB_draw_elements_base_vertex") || + GLExtensions::Supports("GL_EXT_draw_elements_base_vertex") || + GLExtensions::Supports("GL_OES_draw_elements_base_vertex"); + g_ogl_config.bSupportsGLBufferStorage = GLExtensions::Supports("GL_ARB_buffer_storage") || + GLExtensions::Supports("GL_EXT_buffer_storage"); + g_ogl_config.bSupportsMSAA = GLExtensions::Supports("GL_ARB_texture_multisample"); + g_ogl_config.bSupportViewportFloat = GLExtensions::Supports("GL_ARB_viewport_array"); + g_ogl_config.bSupportsDebug = + GLExtensions::Supports("GL_KHR_debug") || GLExtensions::Supports("GL_ARB_debug_output"); + g_ogl_config.bSupports3DTextureStorage = + GLExtensions::Supports("GL_ARB_texture_storage_multisample") || + GLExtensions::Supports("GL_OES_texture_storage_multisample_2d_array"); + g_ogl_config.bSupports2DTextureStorage = + GLExtensions::Supports("GL_ARB_texture_storage_multisample"); + g_ogl_config.bSupportsEarlyFragmentTests = + GLExtensions::Supports("GL_ARB_shader_image_load_store"); + g_ogl_config.bSupportsConservativeDepth = GLExtensions::Supports("GL_ARB_conservative_depth"); + g_ogl_config.bSupportsAniso = GLExtensions::Supports("GL_EXT_texture_filter_anisotropic"); - if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3) - { - g_ogl_config.SupportedESPointSize = GLExtensions::Supports("GL_OES_geometry_point_size") ? 1 : GLExtensions::Supports("GL_EXT_geometry_point_size") ? 2 : 0; - g_ogl_config.SupportedESTextureBuffer = GLExtensions::Supports("VERSION_GLES_3_2") ? ES_TEXBUF_TYPE::TEXBUF_CORE : - GLExtensions::Supports("GL_OES_texture_buffer") ? ES_TEXBUF_TYPE::TEXBUF_OES : - GLExtensions::Supports("GL_EXT_texture_buffer") ? ES_TEXBUF_TYPE::TEXBUF_EXT : ES_TEXBUF_TYPE::TEXBUF_NONE; + if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3) + { + g_ogl_config.SupportedESPointSize = + GLExtensions::Supports("GL_OES_geometry_point_size") ? + 1 : + GLExtensions::Supports("GL_EXT_geometry_point_size") ? 2 : 0; + g_ogl_config.SupportedESTextureBuffer = GLExtensions::Supports("VERSION_GLES_3_2") ? + ES_TEXBUF_TYPE::TEXBUF_CORE : + GLExtensions::Supports("GL_OES_texture_buffer") ? + ES_TEXBUF_TYPE::TEXBUF_OES : + GLExtensions::Supports("GL_EXT_texture_buffer") ? + ES_TEXBUF_TYPE::TEXBUF_EXT : + ES_TEXBUF_TYPE::TEXBUF_NONE; - g_ogl_config.bSupportsGLSLCache = true; - g_ogl_config.bSupportsGLSync = true; + g_ogl_config.bSupportsGLSLCache = true; + g_ogl_config.bSupportsGLSync = true; - if (strstr(g_ogl_config.glsl_version, "3.0")) - { - g_ogl_config.eSupportedGLSLVersion = GLSLES_300; - g_ogl_config.bSupportsAEP = false; - g_Config.backend_info.bSupportsGeometryShaders = false; - } - else if (strstr(g_ogl_config.glsl_version, "3.1")) - { - g_ogl_config.eSupportedGLSLVersion = GLSLES_310; - g_ogl_config.bSupportsAEP = GLExtensions::Supports("GL_ANDROID_extension_pack_es31a"); - g_Config.backend_info.bSupportsBindingLayout = true; - g_ogl_config.bSupportsEarlyFragmentTests = true; - g_Config.backend_info.bSupportsGeometryShaders = g_ogl_config.bSupportsAEP; - g_Config.backend_info.bSupportsGSInstancing = g_Config.backend_info.bSupportsGeometryShaders && g_ogl_config.SupportedESPointSize > 0; - g_Config.backend_info.bSupportsSSAA = g_ogl_config.bSupportsAEP; - g_Config.backend_info.bSupportsBBox = true; - g_ogl_config.bSupportsMSAA = true; - g_ogl_config.bSupports2DTextureStorage = true; - if (g_ActiveConfig.iStereoMode > 0 && g_ActiveConfig.iMultisamples > 1 && !g_ogl_config.bSupports3DTextureStorage) - { - // GLES 3.1 can't support stereo rendering and MSAA - OSD::AddMessage("MSAA Stereo rendering isn't supported by your GPU.", 10000); - g_ActiveConfig.iMultisamples = 1; - } - } - else - { - g_ogl_config.eSupportedGLSLVersion = GLSLES_320; - g_ogl_config.bSupportsAEP = GLExtensions::Supports("GL_ANDROID_extension_pack_es31a"); - g_Config.backend_info.bSupportsBindingLayout = true; - g_ogl_config.bSupportsEarlyFragmentTests = true; - g_Config.backend_info.bSupportsGeometryShaders = true; - g_Config.backend_info.bSupportsGSInstancing = g_ogl_config.SupportedESPointSize > 0; - g_Config.backend_info.bSupportsPaletteConversion = true; - g_Config.backend_info.bSupportsSSAA = true; - g_Config.backend_info.bSupportsBBox = true; - g_ogl_config.bSupportsCopySubImage = true; - g_ogl_config.bSupportsGLBaseVertex = true; - g_ogl_config.bSupportsDebug = true; - g_ogl_config.bSupportsMSAA = true; - g_ogl_config.bSupports2DTextureStorage = true; - g_ogl_config.bSupports3DTextureStorage = true; - } - } - else - { - if (strstr(g_ogl_config.glsl_version, "1.00") || strstr(g_ogl_config.glsl_version, "1.10") || strstr(g_ogl_config.glsl_version, "1.20")) - { - PanicAlert("GPU: OGL ERROR: Need at least GLSL 1.30\n" - "GPU: Does your video card support OpenGL 3.0?\n" - "GPU: Your driver supports GLSL %s", g_ogl_config.glsl_version); - bSuccess = false; - } - else if (strstr(g_ogl_config.glsl_version, "1.30")) - { - g_ogl_config.eSupportedGLSLVersion = GLSL_130; - g_ogl_config.bSupportsEarlyFragmentTests = false; // layout keyword is only supported on glsl150+ - g_ogl_config.bSupportsConservativeDepth = false; // layout keyword is only supported on glsl150+ - g_Config.backend_info.bSupportsGeometryShaders = false; // geometry shaders are only supported on glsl150+ - } - else if (strstr(g_ogl_config.glsl_version, "1.40")) - { - g_ogl_config.eSupportedGLSLVersion = GLSL_140; - g_ogl_config.bSupportsEarlyFragmentTests = false; // layout keyword is only supported on glsl150+ - g_ogl_config.bSupportsConservativeDepth = false; // layout keyword is only supported on glsl150+ - g_Config.backend_info.bSupportsGeometryShaders = false; // geometry shaders are only supported on glsl150+ - } - else if (strstr(g_ogl_config.glsl_version, "1.50")) - { - g_ogl_config.eSupportedGLSLVersion = GLSL_150; - } - else if (strstr(g_ogl_config.glsl_version, "3.30")) - { - g_ogl_config.eSupportedGLSLVersion = GLSL_330; - } - else - { - g_ogl_config.eSupportedGLSLVersion = GLSL_400; - g_Config.backend_info.bSupportsSSAA = true; - } + if (strstr(g_ogl_config.glsl_version, "3.0")) + { + g_ogl_config.eSupportedGLSLVersion = GLSLES_300; + g_ogl_config.bSupportsAEP = false; + g_Config.backend_info.bSupportsGeometryShaders = false; + } + else if (strstr(g_ogl_config.glsl_version, "3.1")) + { + g_ogl_config.eSupportedGLSLVersion = GLSLES_310; + g_ogl_config.bSupportsAEP = GLExtensions::Supports("GL_ANDROID_extension_pack_es31a"); + g_Config.backend_info.bSupportsBindingLayout = true; + g_ogl_config.bSupportsEarlyFragmentTests = true; + g_Config.backend_info.bSupportsGeometryShaders = g_ogl_config.bSupportsAEP; + g_Config.backend_info.bSupportsGSInstancing = + g_Config.backend_info.bSupportsGeometryShaders && g_ogl_config.SupportedESPointSize > 0; + g_Config.backend_info.bSupportsSSAA = g_ogl_config.bSupportsAEP; + g_Config.backend_info.bSupportsBBox = true; + g_ogl_config.bSupportsMSAA = true; + g_ogl_config.bSupports2DTextureStorage = true; + if (g_ActiveConfig.iStereoMode > 0 && g_ActiveConfig.iMultisamples > 1 && + !g_ogl_config.bSupports3DTextureStorage) + { + // GLES 3.1 can't support stereo rendering and MSAA + OSD::AddMessage("MSAA Stereo rendering isn't supported by your GPU.", 10000); + g_ActiveConfig.iMultisamples = 1; + } + } + else + { + g_ogl_config.eSupportedGLSLVersion = GLSLES_320; + g_ogl_config.bSupportsAEP = GLExtensions::Supports("GL_ANDROID_extension_pack_es31a"); + g_Config.backend_info.bSupportsBindingLayout = true; + g_ogl_config.bSupportsEarlyFragmentTests = true; + g_Config.backend_info.bSupportsGeometryShaders = true; + g_Config.backend_info.bSupportsGSInstancing = g_ogl_config.SupportedESPointSize > 0; + g_Config.backend_info.bSupportsPaletteConversion = true; + g_Config.backend_info.bSupportsSSAA = true; + g_Config.backend_info.bSupportsBBox = true; + g_ogl_config.bSupportsCopySubImage = true; + g_ogl_config.bSupportsGLBaseVertex = true; + g_ogl_config.bSupportsDebug = true; + g_ogl_config.bSupportsMSAA = true; + g_ogl_config.bSupports2DTextureStorage = true; + g_ogl_config.bSupports3DTextureStorage = true; + } + } + else + { + if (strstr(g_ogl_config.glsl_version, "1.00") || strstr(g_ogl_config.glsl_version, "1.10") || + strstr(g_ogl_config.glsl_version, "1.20")) + { + PanicAlert("GPU: OGL ERROR: Need at least GLSL 1.30\n" + "GPU: Does your video card support OpenGL 3.0?\n" + "GPU: Your driver supports GLSL %s", + g_ogl_config.glsl_version); + bSuccess = false; + } + else if (strstr(g_ogl_config.glsl_version, "1.30")) + { + g_ogl_config.eSupportedGLSLVersion = GLSL_130; + g_ogl_config.bSupportsEarlyFragmentTests = + false; // layout keyword is only supported on glsl150+ + g_ogl_config.bSupportsConservativeDepth = + false; // layout keyword is only supported on glsl150+ + g_Config.backend_info.bSupportsGeometryShaders = + false; // geometry shaders are only supported on glsl150+ + } + else if (strstr(g_ogl_config.glsl_version, "1.40")) + { + g_ogl_config.eSupportedGLSLVersion = GLSL_140; + g_ogl_config.bSupportsEarlyFragmentTests = + false; // layout keyword is only supported on glsl150+ + g_ogl_config.bSupportsConservativeDepth = + false; // layout keyword is only supported on glsl150+ + g_Config.backend_info.bSupportsGeometryShaders = + false; // geometry shaders are only supported on glsl150+ + } + else if (strstr(g_ogl_config.glsl_version, "1.50")) + { + g_ogl_config.eSupportedGLSLVersion = GLSL_150; + } + else if (strstr(g_ogl_config.glsl_version, "3.30")) + { + g_ogl_config.eSupportedGLSLVersion = GLSL_330; + } + else + { + g_ogl_config.eSupportedGLSLVersion = GLSL_400; + g_Config.backend_info.bSupportsSSAA = true; + } - // Desktop OpenGL can't have the Android Extension Pack - g_ogl_config.bSupportsAEP = false; - } + // Desktop OpenGL can't have the Android Extension Pack + g_ogl_config.bSupportsAEP = false; + } - // Either method can do early-z tests. See PixelShaderGen for details. - g_Config.backend_info.bSupportsEarlyZ = g_ogl_config.bSupportsEarlyFragmentTests || g_ogl_config.bSupportsConservativeDepth; + // Either method can do early-z tests. See PixelShaderGen for details. + g_Config.backend_info.bSupportsEarlyZ = + g_ogl_config.bSupportsEarlyFragmentTests || g_ogl_config.bSupportsConservativeDepth; - if (g_ogl_config.bSupportsDebug) - { - if (GLExtensions::Supports("GL_KHR_debug")) - { - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, true); - glDebugMessageCallback(ErrorCallback, nullptr); - } - else - { - glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, true); - glDebugMessageCallbackARB(ErrorCallback, nullptr); - } - if (LogManager::GetInstance()->IsEnabled(LogTypes::HOST_GPU, LogTypes::LERROR)) - glEnable(GL_DEBUG_OUTPUT); - else - glDisable(GL_DEBUG_OUTPUT); - } + if (g_ogl_config.bSupportsDebug) + { + if (GLExtensions::Supports("GL_KHR_debug")) + { + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, true); + glDebugMessageCallback(ErrorCallback, nullptr); + } + else + { + glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, true); + glDebugMessageCallbackARB(ErrorCallback, nullptr); + } + if (LogManager::GetInstance()->IsEnabled(LogTypes::HOST_GPU, LogTypes::LERROR)) + glEnable(GL_DEBUG_OUTPUT); + else + glDisable(GL_DEBUG_OUTPUT); + } - int samples; - glGetIntegerv(GL_SAMPLES, &samples); - if (samples > 1) - { - // MSAA on default framebuffer isn't working because of glBlitFramebuffer. - // It also isn't useful as we don't render anything to the default framebuffer. - // We also try to get a non-msaa fb, so this only happens when forced by the driver. - PanicAlert("MSAA on default framebuffer isn't supported.\n" - "Please avoid forcing Dolphin to use MSAA by the driver.\n" - "%d samples on default framebuffer found.", samples); - bSuccess = false; - } + int samples; + glGetIntegerv(GL_SAMPLES, &samples); + if (samples > 1) + { + // MSAA on default framebuffer isn't working because of glBlitFramebuffer. + // It also isn't useful as we don't render anything to the default framebuffer. + // We also try to get a non-msaa fb, so this only happens when forced by the driver. + PanicAlert("MSAA on default framebuffer isn't supported.\n" + "Please avoid forcing Dolphin to use MSAA by the driver.\n" + "%d samples on default framebuffer found.", + samples); + bSuccess = false; + } - if (!bSuccess) - { - // Not all needed extensions are supported, so we have to stop here. - // Else some of the next calls might crash. - return; - } + if (!bSuccess) + { + // Not all needed extensions are supported, so we have to stop here. + // Else some of the next calls might crash. + return; + } - glGetIntegerv(GL_MAX_SAMPLES, &g_ogl_config.max_samples); - if (g_ogl_config.max_samples < 1 || !g_ogl_config.bSupportsMSAA) - g_ogl_config.max_samples = 1; + glGetIntegerv(GL_MAX_SAMPLES, &g_ogl_config.max_samples); + if (g_ogl_config.max_samples < 1 || !g_ogl_config.bSupportsMSAA) + g_ogl_config.max_samples = 1; - g_Config.VerifyValidity(); - UpdateActiveConfig(); + g_Config.VerifyValidity(); + UpdateActiveConfig(); - OSD::AddMessage(StringFromFormat("Video Info: %s, %s, %s", - g_ogl_config.gl_vendor, - g_ogl_config.gl_renderer, - g_ogl_config.gl_version), 5000); + OSD::AddMessage(StringFromFormat("Video Info: %s, %s, %s", g_ogl_config.gl_vendor, + g_ogl_config.gl_renderer, g_ogl_config.gl_version), + 5000); - WARN_LOG(VIDEO,"Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s%s%s%s", - g_ActiveConfig.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend ", - g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" : "PrimitiveRestart ", - g_ActiveConfig.backend_info.bSupportsEarlyZ ? "" : "EarlyZ ", - g_ogl_config.bSupportsGLPinnedMemory ? "" : "PinnedMemory ", - g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache ", - g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", - g_ogl_config.bSupportsGLBufferStorage ? "" : "BufferStorage ", - g_ogl_config.bSupportsGLSync ? "" : "Sync ", - g_ogl_config.bSupportsMSAA ? "" : "MSAA ", - g_ActiveConfig.backend_info.bSupportsSSAA ? "" : "SSAA ", - g_ActiveConfig.backend_info.bSupportsGSInstancing ? "" : "GSInstancing ", - g_ActiveConfig.backend_info.bSupportsClipControl ? "" : "ClipControl ", - g_ogl_config.bSupportsCopySubImage ? "" : "CopyImageSubData " - ); + WARN_LOG(VIDEO, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s%s%s%s", + g_ActiveConfig.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend ", + g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" : "PrimitiveRestart ", + g_ActiveConfig.backend_info.bSupportsEarlyZ ? "" : "EarlyZ ", + g_ogl_config.bSupportsGLPinnedMemory ? "" : "PinnedMemory ", + g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache ", + g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ", + g_ogl_config.bSupportsGLBufferStorage ? "" : "BufferStorage ", + g_ogl_config.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportsMSAA ? "" : "MSAA ", + g_ActiveConfig.backend_info.bSupportsSSAA ? "" : "SSAA ", + g_ActiveConfig.backend_info.bSupportsGSInstancing ? "" : "GSInstancing ", + g_ActiveConfig.backend_info.bSupportsClipControl ? "" : "ClipControl ", + g_ogl_config.bSupportsCopySubImage ? "" : "CopyImageSubData "); - s_last_multisamples = g_ActiveConfig.iMultisamples; - s_MSAASamples = s_last_multisamples; + s_last_multisamples = g_ActiveConfig.iMultisamples; + s_MSAASamples = s_last_multisamples; - s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; - s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; + s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; + s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; - // Decide framebuffer size - s_backbuffer_width = (int)GLInterface->GetBackBufferWidth(); - s_backbuffer_height = (int)GLInterface->GetBackBufferHeight(); + // Decide framebuffer size + s_backbuffer_width = (int)GLInterface->GetBackBufferWidth(); + s_backbuffer_height = (int)GLInterface->GetBackBufferHeight(); - // Handle VSync on/off - s_vsync = g_ActiveConfig.IsVSync(); - if (!DriverDetails::HasBug(DriverDetails::BUG_BROKENVSYNC)) - GLInterface->SwapInterval(s_vsync); + // Handle VSync on/off + s_vsync = g_ActiveConfig.IsVSync(); + if (!DriverDetails::HasBug(DriverDetails::BUG_BROKENVSYNC)) + GLInterface->SwapInterval(s_vsync); - // TODO: Move these somewhere else? - FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH); - FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT); + // TODO: Move these somewhere else? + FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH); + FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT); - UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); + UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); - s_last_efb_scale = g_ActiveConfig.iEFBScale; - CalculateTargetSize(s_backbuffer_width, s_backbuffer_height); + s_last_efb_scale = g_ActiveConfig.iEFBScale; + CalculateTargetSize(s_backbuffer_width, s_backbuffer_height); - PixelShaderManager::SetEfbScaleChanged(); + PixelShaderManager::SetEfbScaleChanged(); - // Because of the fixed framebuffer size we need to disable the resolution - // options while running - g_Config.bRunning = true; + // Because of the fixed framebuffer size we need to disable the resolution + // options while running + g_Config.bRunning = true; - glStencilFunc(GL_ALWAYS, 0, 0); - glBlendFunc(GL_ONE, GL_ONE); + glStencilFunc(GL_ALWAYS, 0, 0); + glBlendFunc(GL_ONE, GL_ONE); - glViewport(0, 0, GetTargetWidth(), GetTargetHeight()); // Reset The Current Viewport - if (g_ActiveConfig.backend_info.bSupportsClipControl) - glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); + glViewport(0, 0, GetTargetWidth(), GetTargetHeight()); // Reset The Current Viewport + if (g_ActiveConfig.backend_info.bSupportsClipControl) + glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClearDepthf(1.0f); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClearDepthf(1.0f); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment - glDisable(GL_STENCIL_TEST); - glEnable(GL_SCISSOR_TEST); + glDisable(GL_STENCIL_TEST); + glEnable(GL_SCISSOR_TEST); - glScissor(0, 0, GetTargetWidth(), GetTargetHeight()); - glBlendColor(0, 0, 0, 0.5f); - glClearDepthf(1.0f); + glScissor(0, 0, GetTargetWidth(), GetTargetHeight()); + glBlendColor(0, 0, 0, 0.5f); + glClearDepthf(1.0f); - if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart) - { - if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3) - { - glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); - } - else - { - if (GLExtensions::Version() >= 310) - { - glEnable(GL_PRIMITIVE_RESTART); - glPrimitiveRestartIndex(65535); - } - else - { - glEnableClientState(GL_PRIMITIVE_RESTART_NV); - glPrimitiveRestartIndexNV(65535); - } - } - } - UpdateActiveConfig(); - ClearEFBCache(); + if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart) + { + if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3) + { + glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); + } + else + { + if (GLExtensions::Version() >= 310) + { + glEnable(GL_PRIMITIVE_RESTART); + glPrimitiveRestartIndex(65535); + } + else + { + glEnableClientState(GL_PRIMITIVE_RESTART_NV); + glPrimitiveRestartIndexNV(65535); + } + } + } + UpdateActiveConfig(); + ClearEFBCache(); } Renderer::~Renderer() @@ -693,48 +763,47 @@ Renderer::~Renderer() void Renderer::Shutdown() { - g_framebuffer_manager.reset(); + g_framebuffer_manager.reset(); - g_Config.bRunning = false; - UpdateActiveConfig(); + g_Config.bRunning = false; + UpdateActiveConfig(); - s_raster_font.reset(); - m_post_processor.reset(); + s_raster_font.reset(); + m_post_processor.reset(); - OpenGL_DeleteAttributelessVAO(); + OpenGL_DeleteAttributelessVAO(); } void Renderer::Init() { - // Initialize the FramebufferManager - g_framebuffer_manager = std::make_unique(s_target_width, s_target_height, - s_MSAASamples); + // Initialize the FramebufferManager + g_framebuffer_manager = + std::make_unique(s_target_width, s_target_height, s_MSAASamples); - m_post_processor = std::make_unique(); - s_raster_font = std::make_unique(); + m_post_processor = std::make_unique(); + s_raster_font = std::make_unique(); - OpenGL_CreateAttributelessVAO(); + OpenGL_CreateAttributelessVAO(); } void Renderer::RenderText(const std::string& text, int left, int top, u32 color) { - const int nBackbufferWidth = (int)GLInterface->GetBackBufferWidth(); - const int nBackbufferHeight = (int)GLInterface->GetBackBufferHeight(); + const int nBackbufferWidth = (int)GLInterface->GetBackBufferWidth(); + const int nBackbufferHeight = (int)GLInterface->GetBackBufferHeight(); - s_raster_font->printMultilineText(text, - left * 2.0f / (float)nBackbufferWidth - 1, - 1 - top * 2.0f / (float)nBackbufferHeight, - 0, nBackbufferWidth, nBackbufferHeight, color); + s_raster_font->printMultilineText(text, left * 2.0f / (float)nBackbufferWidth - 1, + 1 - top * 2.0f / (float)nBackbufferHeight, 0, nBackbufferWidth, + nBackbufferHeight, color); } TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc) { - TargetRectangle result; - result.left = EFBToScaledX(rc.left); - result.top = EFBToScaledY(EFB_HEIGHT - rc.top); - result.right = EFBToScaledX(rc.right); - result.bottom = EFBToScaledY(EFB_HEIGHT - rc.bottom); - return result; + TargetRectangle result; + result.left = EFBToScaledX(rc.left); + result.top = EFBToScaledY(EFB_HEIGHT - rc.top); + result.right = EFBToScaledX(rc.right); + result.bottom = EFBToScaledY(EFB_HEIGHT - rc.bottom); + return result; } // Function: This function handles the OpenGL glScissor() function @@ -749,72 +818,74 @@ TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc) // therefore the width and height are (scissorBR + 1) - scissorTL void Renderer::SetScissorRect(const EFBRectangle& rc) { - TargetRectangle trc = g_renderer->ConvertEFBRectangle(rc); - glScissor(trc.left, trc.bottom, trc.GetWidth(), trc.GetHeight()); + TargetRectangle trc = g_renderer->ConvertEFBRectangle(rc); + glScissor(trc.left, trc.bottom, trc.GetWidth(), trc.GetHeight()); } void Renderer::SetColorMask() { - // Only enable alpha channel if it's supported by the current EFB format - GLenum ColorMask = GL_FALSE, AlphaMask = GL_FALSE; - if (bpmem.alpha_test.TestResult() != AlphaTest::FAIL) - { - if (bpmem.blendmode.colorupdate) - ColorMask = GL_TRUE; - if (bpmem.blendmode.alphaupdate && (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24)) - AlphaMask = GL_TRUE; - } - glColorMask(ColorMask, ColorMask, ColorMask, AlphaMask); + // Only enable alpha channel if it's supported by the current EFB format + GLenum ColorMask = GL_FALSE, AlphaMask = GL_FALSE; + if (bpmem.alpha_test.TestResult() != AlphaTest::FAIL) + { + if (bpmem.blendmode.colorupdate) + ColorMask = GL_TRUE; + if (bpmem.blendmode.alphaupdate && (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24)) + AlphaMask = GL_TRUE; + } + glColorMask(ColorMask, ColorMask, ColorMask, AlphaMask); } void ClearEFBCache() { - if (!s_efbCacheIsCleared) - { - s_efbCacheIsCleared = true; - memset(s_efbCacheValid, 0, sizeof(s_efbCacheValid)); - } + if (!s_efbCacheIsCleared) + { + s_efbCacheIsCleared = true; + memset(s_efbCacheValid, 0, sizeof(s_efbCacheValid)); + } } -void Renderer::UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc, const TargetRectangle& targetPixelRc, const void* data) +void Renderer::UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc, + const TargetRectangle& targetPixelRc, const void* data) { - u32 cacheType = (type == PEEK_Z ? 0 : 1); + u32 cacheType = (type == PEEK_Z ? 0 : 1); - if (!s_efbCache[cacheType][cacheRectIdx].size()) - s_efbCache[cacheType][cacheRectIdx].resize(EFB_CACHE_RECT_SIZE * EFB_CACHE_RECT_SIZE); + if (!s_efbCache[cacheType][cacheRectIdx].size()) + s_efbCache[cacheType][cacheRectIdx].resize(EFB_CACHE_RECT_SIZE * EFB_CACHE_RECT_SIZE); - u32 targetPixelRcWidth = targetPixelRc.right - targetPixelRc.left; - u32 efbPixelRcHeight = efbPixelRc.bottom - efbPixelRc.top; - u32 efbPixelRcWidth = efbPixelRc.right - efbPixelRc.left; + u32 targetPixelRcWidth = targetPixelRc.right - targetPixelRc.left; + u32 efbPixelRcHeight = efbPixelRc.bottom - efbPixelRc.top; + u32 efbPixelRcWidth = efbPixelRc.right - efbPixelRc.left; - for (u32 yCache = 0; yCache < efbPixelRcHeight; ++yCache) - { - u32 yEFB = efbPixelRc.top + yCache; - u32 yPixel = (EFBToScaledY(EFB_HEIGHT - yEFB) + EFBToScaledY(EFB_HEIGHT - yEFB - 1)) / 2; - u32 yData = yPixel - targetPixelRc.bottom; + for (u32 yCache = 0; yCache < efbPixelRcHeight; ++yCache) + { + u32 yEFB = efbPixelRc.top + yCache; + u32 yPixel = (EFBToScaledY(EFB_HEIGHT - yEFB) + EFBToScaledY(EFB_HEIGHT - yEFB - 1)) / 2; + u32 yData = yPixel - targetPixelRc.bottom; - for (u32 xCache = 0; xCache < efbPixelRcWidth; ++xCache) - { - u32 xEFB = efbPixelRc.left + xCache; - u32 xPixel = (EFBToScaledX(xEFB) + EFBToScaledX(xEFB + 1)) / 2; - u32 xData = xPixel - targetPixelRc.left; - u32 value; - if (type == PEEK_Z) - { - float* ptr = (float*)data; - value = MathUtil::Clamp((u32)(ptr[yData * targetPixelRcWidth + xData] * 16777216.0f), 0, 0xFFFFFF); - } - else - { - u32* ptr = (u32*)data; - value = ptr[yData * targetPixelRcWidth + xData]; - } - s_efbCache[cacheType][cacheRectIdx][yCache * EFB_CACHE_RECT_SIZE + xCache] = value; - } - } + for (u32 xCache = 0; xCache < efbPixelRcWidth; ++xCache) + { + u32 xEFB = efbPixelRc.left + xCache; + u32 xPixel = (EFBToScaledX(xEFB) + EFBToScaledX(xEFB + 1)) / 2; + u32 xData = xPixel - targetPixelRc.left; + u32 value; + if (type == PEEK_Z) + { + float* ptr = (float*)data; + value = MathUtil::Clamp((u32)(ptr[yData * targetPixelRcWidth + xData] * 16777216.0f), + 0, 0xFFFFFF); + } + else + { + u32* ptr = (u32*)data; + value = ptr[yData * targetPixelRcWidth + xData]; + } + s_efbCache[cacheType][cacheRectIdx][yCache * EFB_CACHE_RECT_SIZE + xCache] = value; + } + } - s_efbCacheValid[cacheType][cacheRectIdx] = true; - s_efbCacheIsCleared = false; + s_efbCacheValid[cacheType][cacheRectIdx] = true; + s_efbCacheIsCleared = false; } // This function allows the CPU to directly access the EFB. @@ -833,880 +904,874 @@ void Renderer::UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRec // - GX_PokeZMode (TODO) u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) { - u32 cacheRectIdx = (y / EFB_CACHE_RECT_SIZE) * EFB_CACHE_WIDTH - + (x / EFB_CACHE_RECT_SIZE); + u32 cacheRectIdx = (y / EFB_CACHE_RECT_SIZE) * EFB_CACHE_WIDTH + (x / EFB_CACHE_RECT_SIZE); - EFBRectangle efbPixelRc; + EFBRectangle efbPixelRc; - if (type == PEEK_COLOR || type == PEEK_Z) - { - // Get the rectangular target region containing the EFB pixel - efbPixelRc.left = (x / EFB_CACHE_RECT_SIZE) * EFB_CACHE_RECT_SIZE; - efbPixelRc.top = (y / EFB_CACHE_RECT_SIZE) * EFB_CACHE_RECT_SIZE; - efbPixelRc.right = std::min(efbPixelRc.left + EFB_CACHE_RECT_SIZE, (u32)EFB_WIDTH); - efbPixelRc.bottom = std::min(efbPixelRc.top + EFB_CACHE_RECT_SIZE, (u32)EFB_HEIGHT); - } - else - { - efbPixelRc.left = x; - efbPixelRc.top = y; - efbPixelRc.right = x+1; - efbPixelRc.bottom = y+1; - } + if (type == PEEK_COLOR || type == PEEK_Z) + { + // Get the rectangular target region containing the EFB pixel + efbPixelRc.left = (x / EFB_CACHE_RECT_SIZE) * EFB_CACHE_RECT_SIZE; + efbPixelRc.top = (y / EFB_CACHE_RECT_SIZE) * EFB_CACHE_RECT_SIZE; + efbPixelRc.right = std::min(efbPixelRc.left + EFB_CACHE_RECT_SIZE, (u32)EFB_WIDTH); + efbPixelRc.bottom = std::min(efbPixelRc.top + EFB_CACHE_RECT_SIZE, (u32)EFB_HEIGHT); + } + else + { + efbPixelRc.left = x; + efbPixelRc.top = y; + efbPixelRc.right = x + 1; + efbPixelRc.bottom = y + 1; + } - TargetRectangle targetPixelRc = ConvertEFBRectangle(efbPixelRc); - u32 targetPixelRcWidth = targetPixelRc.right - targetPixelRc.left; - u32 targetPixelRcHeight = targetPixelRc.top - targetPixelRc.bottom; + TargetRectangle targetPixelRc = ConvertEFBRectangle(efbPixelRc); + u32 targetPixelRcWidth = targetPixelRc.right - targetPixelRc.left; + u32 targetPixelRcHeight = targetPixelRc.top - targetPixelRc.bottom; - // TODO (FIX) : currently, AA path is broken/offset and doesn't return the correct pixel - switch (type) - { - case PEEK_Z: - { - if (!s_efbCacheValid[0][cacheRectIdx]) - { - if (s_MSAASamples > 1) - { - g_renderer->ResetAPIState(); + // TODO (FIX) : currently, AA path is broken/offset and doesn't return the correct pixel + switch (type) + { + case PEEK_Z: + { + if (!s_efbCacheValid[0][cacheRectIdx]) + { + if (s_MSAASamples > 1) + { + g_renderer->ResetAPIState(); - // Resolve our rectangle. - FramebufferManager::GetEFBDepthTexture(efbPixelRc); - glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetResolvedFramebuffer()); + // Resolve our rectangle. + FramebufferManager::GetEFBDepthTexture(efbPixelRc); + glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetResolvedFramebuffer()); - g_renderer->RestoreAPIState(); - } + g_renderer->RestoreAPIState(); + } - std::unique_ptr depthMap(new float[targetPixelRcWidth * targetPixelRcHeight]); + std::unique_ptr depthMap(new float[targetPixelRcWidth * targetPixelRcHeight]); - glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, targetPixelRcHeight, - GL_DEPTH_COMPONENT, GL_FLOAT, depthMap.get()); + glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, + targetPixelRcHeight, GL_DEPTH_COMPONENT, GL_FLOAT, depthMap.get()); - UpdateEFBCache(type, cacheRectIdx, efbPixelRc, targetPixelRc, depthMap.get()); - } + UpdateEFBCache(type, cacheRectIdx, efbPixelRc, targetPixelRc, depthMap.get()); + } - u32 xRect = x % EFB_CACHE_RECT_SIZE; - u32 yRect = y % EFB_CACHE_RECT_SIZE; - u32 z = s_efbCache[0][cacheRectIdx][yRect * EFB_CACHE_RECT_SIZE + xRect]; + u32 xRect = x % EFB_CACHE_RECT_SIZE; + u32 yRect = y % EFB_CACHE_RECT_SIZE; + u32 z = s_efbCache[0][cacheRectIdx][yRect * EFB_CACHE_RECT_SIZE + xRect]; - // if Z is in 16 bit format you must return a 16 bit integer - if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) - z = z >> 8; + // if Z is in 16 bit format you must return a 16 bit integer + if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) + z = z >> 8; - return z; - } + return z; + } - case PEEK_COLOR: // GXPeekARGB - { - // Although it may sound strange, this really is A8R8G8B8 and not RGBA or 24-bit... + case PEEK_COLOR: // GXPeekARGB + { + // Although it may sound strange, this really is A8R8G8B8 and not RGBA or 24-bit... - // Tested in Killer 7, the first 8bits represent the alpha value which is used to - // determine if we're aiming at an enemy (0x80 / 0x88) or not (0x70) - // Wind Waker is also using it for the pictograph to determine the color of each pixel - if (!s_efbCacheValid[1][cacheRectIdx]) - { - if (s_MSAASamples > 1) - { - g_renderer->ResetAPIState(); + // Tested in Killer 7, the first 8bits represent the alpha value which is used to + // determine if we're aiming at an enemy (0x80 / 0x88) or not (0x70) + // Wind Waker is also using it for the pictograph to determine the color of each pixel + if (!s_efbCacheValid[1][cacheRectIdx]) + { + if (s_MSAASamples > 1) + { + g_renderer->ResetAPIState(); - // Resolve our rectangle. - FramebufferManager::GetEFBColorTexture(efbPixelRc); - glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetResolvedFramebuffer()); + // Resolve our rectangle. + FramebufferManager::GetEFBColorTexture(efbPixelRc); + glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetResolvedFramebuffer()); - g_renderer->RestoreAPIState(); - } + g_renderer->RestoreAPIState(); + } - std::unique_ptr colorMap(new u32[targetPixelRcWidth * targetPixelRcHeight]); + std::unique_ptr colorMap(new u32[targetPixelRcWidth * targetPixelRcHeight]); - if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3) - // XXX: Swap colours - glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, targetPixelRcHeight, - GL_RGBA, GL_UNSIGNED_BYTE, colorMap.get()); - else - glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, targetPixelRcHeight, - GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, colorMap.get()); + if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3) + // XXX: Swap colours + glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, + targetPixelRcHeight, GL_RGBA, GL_UNSIGNED_BYTE, colorMap.get()); + else + glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth, + targetPixelRcHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, colorMap.get()); - UpdateEFBCache(type, cacheRectIdx, efbPixelRc, targetPixelRc, colorMap.get()); - } + UpdateEFBCache(type, cacheRectIdx, efbPixelRc, targetPixelRc, colorMap.get()); + } - u32 xRect = x % EFB_CACHE_RECT_SIZE; - u32 yRect = y % EFB_CACHE_RECT_SIZE; - u32 color = s_efbCache[1][cacheRectIdx][yRect * EFB_CACHE_RECT_SIZE + xRect]; + u32 xRect = x % EFB_CACHE_RECT_SIZE; + u32 yRect = y % EFB_CACHE_RECT_SIZE; + u32 color = s_efbCache[1][cacheRectIdx][yRect * EFB_CACHE_RECT_SIZE + xRect]; - // check what to do with the alpha channel (GX_PokeAlphaRead) - PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode(); + // check what to do with the alpha channel (GX_PokeAlphaRead) + PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode(); - if (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24) - { - color = RGBA8ToRGBA6ToRGBA8(color); - } - else if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) - { - color = RGBA8ToRGB565ToRGBA8(color); - } - if (bpmem.zcontrol.pixel_format != PEControl::RGBA6_Z24) - { - color |= 0xFF000000; - } - if (alpha_read_mode.ReadMode == 2) - { - // GX_READ_NONE - return color; - } - else if (alpha_read_mode.ReadMode == 1) - { - // GX_READ_FF - return (color | 0xFF000000); - } - else /*if(alpha_read_mode.ReadMode == 0)*/ - { - // GX_READ_00 - return (color & 0x00FFFFFF); - } - } + if (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24) + { + color = RGBA8ToRGBA6ToRGBA8(color); + } + else if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) + { + color = RGBA8ToRGB565ToRGBA8(color); + } + if (bpmem.zcontrol.pixel_format != PEControl::RGBA6_Z24) + { + color |= 0xFF000000; + } + if (alpha_read_mode.ReadMode == 2) + { + // GX_READ_NONE + return color; + } + else if (alpha_read_mode.ReadMode == 1) + { + // GX_READ_FF + return (color | 0xFF000000); + } + else /*if(alpha_read_mode.ReadMode == 0)*/ + { + // GX_READ_00 + return (color & 0x00FFFFFF); + } + } - default: - break; - } + default: + break; + } - return 0; + return 0; } void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) { - FramebufferManager::PokeEFB(type, points, num_points); + FramebufferManager::PokeEFB(type, points, num_points); } u16 Renderer::BBoxRead(int index) { - int swapped_index = index; - if (index >= 2) - swapped_index ^= 1; // swap 2 and 3 for top/bottom + int swapped_index = index; + if (index >= 2) + swapped_index ^= 1; // swap 2 and 3 for top/bottom - // Here we get the min/max value of the truncated position of the upscaled and swapped framebuffer. - // So we have to correct them to the unscaled EFB sizes. - int value = BoundingBox::Get(swapped_index); + // Here we get the min/max value of the truncated position of the upscaled and swapped + // framebuffer. + // So we have to correct them to the unscaled EFB sizes. + int value = BoundingBox::Get(swapped_index); - if (index < 2) - { - // left/right - value = value * EFB_WIDTH / s_target_width; - } - else - { - // up/down -- we have to swap up and down - value = value * EFB_HEIGHT / s_target_height; - value = EFB_HEIGHT - value - 1; - } - if (index & 1) - value++; // fix max values to describe the outer border + if (index < 2) + { + // left/right + value = value * EFB_WIDTH / s_target_width; + } + else + { + // up/down -- we have to swap up and down + value = value * EFB_HEIGHT / s_target_height; + value = EFB_HEIGHT - value - 1; + } + if (index & 1) + value++; // fix max values to describe the outer border - return value; + return value; } void Renderer::BBoxWrite(int index, u16 _value) { - int value = _value; // u16 isn't enough to multiply by the efb width - if (index & 1) - value--; - if (index < 2) - { - value = value * s_target_width / EFB_WIDTH; - } - else - { - index ^= 1; // swap 2 and 3 for top/bottom - value = EFB_HEIGHT - value - 1; - value = value * s_target_height / EFB_HEIGHT; - } + int value = _value; // u16 isn't enough to multiply by the efb width + if (index & 1) + value--; + if (index < 2) + { + value = value * s_target_width / EFB_WIDTH; + } + else + { + index ^= 1; // swap 2 and 3 for top/bottom + value = EFB_HEIGHT - value - 1; + value = value * s_target_height / EFB_HEIGHT; + } - BoundingBox::Set(index, value); + BoundingBox::Set(index, value); } void Renderer::SetViewport() { - // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) - // [0] = width/2 - // [1] = height/2 - // [2] = 16777215 * (farz - nearz) - // [3] = xorig + width/2 + 342 - // [4] = yorig + height/2 + 342 - // [5] = 16777215 * farz + // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) + // [0] = width/2 + // [1] = height/2 + // [2] = 16777215 * (farz - nearz) + // [3] = xorig + width/2 + 342 + // [4] = yorig + height/2 + 342 + // [5] = 16777215 * farz - int scissorXOff = bpmem.scissorOffset.x * 2; - int scissorYOff = bpmem.scissorOffset.y * 2; + int scissorXOff = bpmem.scissorOffset.x * 2; + int scissorYOff = bpmem.scissorOffset.y * 2; - // TODO: ceil, floor or just cast to int? - float X = EFBToScaledXf(xfmem.viewport.xOrig - xfmem.viewport.wd - (float)scissorXOff); - float Y = EFBToScaledYf((float)EFB_HEIGHT - xfmem.viewport.yOrig + xfmem.viewport.ht + (float)scissorYOff); - float Width = EFBToScaledXf(2.0f * xfmem.viewport.wd); - float Height = EFBToScaledYf(-2.0f * xfmem.viewport.ht); - float GLNear = MathUtil::Clamp(xfmem.viewport.farZ - MathUtil::Clamp(xfmem.viewport.zRange, -16777216.0f, 16777216.0f), 0.0f, 16777215.0f) / 16777216.0f; - float GLFar = MathUtil::Clamp(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f; - if (Width < 0) - { - X += Width; - Width *= -1; - } - if (Height < 0) - { - Y += Height; - Height *= -1; - } + // TODO: ceil, floor or just cast to int? + float X = EFBToScaledXf(xfmem.viewport.xOrig - xfmem.viewport.wd - (float)scissorXOff); + float Y = EFBToScaledYf((float)EFB_HEIGHT - xfmem.viewport.yOrig + xfmem.viewport.ht + + (float)scissorYOff); + float Width = EFBToScaledXf(2.0f * xfmem.viewport.wd); + float Height = EFBToScaledYf(-2.0f * xfmem.viewport.ht); + float GLNear = MathUtil::Clamp( + xfmem.viewport.farZ - + MathUtil::Clamp(xfmem.viewport.zRange, -16777216.0f, 16777216.0f), + 0.0f, 16777215.0f) / + 16777216.0f; + float GLFar = MathUtil::Clamp(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f; + if (Width < 0) + { + X += Width; + Width *= -1; + } + if (Height < 0) + { + Y += Height; + Height *= -1; + } - // Update the view port - if (g_ogl_config.bSupportViewportFloat) - { - glViewportIndexedf(0, X, Y, Width, Height); - } - else - { - auto iceilf = [](float f) - { - return static_cast(ceilf(f)); - }; - glViewport(iceilf(X), iceilf(Y), iceilf(Width), iceilf(Height)); - } - glDepthRangef(GLFar, GLNear); + // Update the view port + if (g_ogl_config.bSupportViewportFloat) + { + glViewportIndexedf(0, X, Y, Width, Height); + } + else + { + auto iceilf = [](float f) { return static_cast(ceilf(f)); }; + glViewport(iceilf(X), iceilf(Y), iceilf(Width), iceilf(Height)); + } + glDepthRangef(GLFar, GLNear); } -void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) +void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, + u32 color, u32 z) { - ResetAPIState(); + ResetAPIState(); - // color - GLboolean const - color_mask = colorEnable ? GL_TRUE : GL_FALSE, - alpha_mask = alphaEnable ? GL_TRUE : GL_FALSE; - glColorMask(color_mask, color_mask, color_mask, alpha_mask); + // color + GLboolean const color_mask = colorEnable ? GL_TRUE : GL_FALSE, + alpha_mask = alphaEnable ? GL_TRUE : GL_FALSE; + glColorMask(color_mask, color_mask, color_mask, alpha_mask); - glClearColor( - float((color >> 16) & 0xFF) / 255.0f, - float((color >> 8) & 0xFF) / 255.0f, - float((color >> 0) & 0xFF) / 255.0f, - float((color >> 24) & 0xFF) / 255.0f); + glClearColor(float((color >> 16) & 0xFF) / 255.0f, float((color >> 8) & 0xFF) / 255.0f, + float((color >> 0) & 0xFF) / 255.0f, float((color >> 24) & 0xFF) / 255.0f); - // depth - glDepthMask(zEnable ? GL_TRUE : GL_FALSE); + // depth + glDepthMask(zEnable ? GL_TRUE : GL_FALSE); - glClearDepthf(float(z & 0xFFFFFF) / 16777216.0f); + glClearDepthf(float(z & 0xFFFFFF) / 16777216.0f); - // Update rect for clearing the picture - glEnable(GL_SCISSOR_TEST); + // Update rect for clearing the picture + glEnable(GL_SCISSOR_TEST); - TargetRectangle const targetRc = ConvertEFBRectangle(rc); - glScissor(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight()); + TargetRectangle const targetRc = ConvertEFBRectangle(rc); + glScissor(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight()); - // glColorMask/glDepthMask/glScissor affect glClear (glViewport does not) - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // glColorMask/glDepthMask/glScissor affect glClear (glViewport does not) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - RestoreAPIState(); + RestoreAPIState(); - ClearEFBCache(); + ClearEFBCache(); } -void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, GLuint src_texture, int src_width, int src_height) +void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, GLuint src_texture, + int src_width, int src_height) { - if (g_ActiveConfig.iStereoMode == STEREO_SBS || g_ActiveConfig.iStereoMode == STEREO_TAB) - { - TargetRectangle leftRc, rightRc; + if (g_ActiveConfig.iStereoMode == STEREO_SBS || g_ActiveConfig.iStereoMode == STEREO_TAB) + { + TargetRectangle leftRc, rightRc; - // Top-and-Bottom mode needs to compensate for inverted vertical screen coordinates. - if (g_ActiveConfig.iStereoMode == STEREO_TAB) - ConvertStereoRectangle(dst, rightRc, leftRc); - else - ConvertStereoRectangle(dst, leftRc, rightRc); + // Top-and-Bottom mode needs to compensate for inverted vertical screen coordinates. + if (g_ActiveConfig.iStereoMode == STEREO_TAB) + ConvertStereoRectangle(dst, rightRc, leftRc); + else + ConvertStereoRectangle(dst, leftRc, rightRc); - m_post_processor->BlitFromTexture(src, leftRc, src_texture, src_width, src_height, 0); - m_post_processor->BlitFromTexture(src, rightRc, src_texture, src_width, src_height, 1); - } - else - { - m_post_processor->BlitFromTexture(src, dst, src_texture, src_width, src_height); - } + m_post_processor->BlitFromTexture(src, leftRc, src_texture, src_width, src_height, 0); + m_post_processor->BlitFromTexture(src, rightRc, src_texture, src_width, src_height, 1); + } + else + { + m_post_processor->BlitFromTexture(src, dst, src_texture, src_width, src_height); + } } void Renderer::ReinterpretPixelData(unsigned int convtype) { - if (convtype == 0 || convtype == 2) - { - FramebufferManager::ReinterpretPixelData(convtype); - } - else - { - ERROR_LOG(VIDEO, "Trying to reinterpret pixel data with unsupported conversion type %d", convtype); - } + if (convtype == 0 || convtype == 2) + { + FramebufferManager::ReinterpretPixelData(convtype); + } + else + { + ERROR_LOG(VIDEO, "Trying to reinterpret pixel data with unsupported conversion type %d", + convtype); + } } void Renderer::SetBlendMode(bool forceUpdate) { - // Our render target always uses an alpha channel, so we need to override the blend functions to assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel - // Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel is assumed to always be 1. - bool target_has_alpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; + // Our render target always uses an alpha channel, so we need to override the blend functions to + // assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel + // Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel + // is assumed to always be 1. + bool target_has_alpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; - bool useDstAlpha = bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate && target_has_alpha; - bool useDualSource = useDstAlpha && g_ActiveConfig.backend_info.bSupportsDualSourceBlend; + bool useDstAlpha = bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate && target_has_alpha; + bool useDualSource = useDstAlpha && g_ActiveConfig.backend_info.bSupportsDualSourceBlend; - const GLenum glSrcFactors[8] = - { - GL_ZERO, - GL_ONE, - GL_DST_COLOR, - GL_ONE_MINUS_DST_COLOR, - (useDualSource) ? GL_SRC1_ALPHA : (GLenum)GL_SRC_ALPHA, - (useDualSource) ? GL_ONE_MINUS_SRC1_ALPHA : (GLenum)GL_ONE_MINUS_SRC_ALPHA, - (target_has_alpha) ? GL_DST_ALPHA : (GLenum)GL_ONE, - (target_has_alpha) ? GL_ONE_MINUS_DST_ALPHA : (GLenum)GL_ZERO - }; - const GLenum glDestFactors[8] = - { - GL_ZERO, - GL_ONE, - GL_SRC_COLOR, - GL_ONE_MINUS_SRC_COLOR, - (useDualSource) ? GL_SRC1_ALPHA : (GLenum)GL_SRC_ALPHA, - (useDualSource) ? GL_ONE_MINUS_SRC1_ALPHA : (GLenum)GL_ONE_MINUS_SRC_ALPHA, - (target_has_alpha) ? GL_DST_ALPHA : (GLenum)GL_ONE, - (target_has_alpha) ? GL_ONE_MINUS_DST_ALPHA : (GLenum)GL_ZERO - }; + const GLenum glSrcFactors[8] = { + GL_ZERO, + GL_ONE, + GL_DST_COLOR, + GL_ONE_MINUS_DST_COLOR, + (useDualSource) ? GL_SRC1_ALPHA : (GLenum)GL_SRC_ALPHA, + (useDualSource) ? GL_ONE_MINUS_SRC1_ALPHA : (GLenum)GL_ONE_MINUS_SRC_ALPHA, + (target_has_alpha) ? GL_DST_ALPHA : (GLenum)GL_ONE, + (target_has_alpha) ? GL_ONE_MINUS_DST_ALPHA : (GLenum)GL_ZERO}; + const GLenum glDestFactors[8] = { + GL_ZERO, + GL_ONE, + GL_SRC_COLOR, + GL_ONE_MINUS_SRC_COLOR, + (useDualSource) ? GL_SRC1_ALPHA : (GLenum)GL_SRC_ALPHA, + (useDualSource) ? GL_ONE_MINUS_SRC1_ALPHA : (GLenum)GL_ONE_MINUS_SRC_ALPHA, + (target_has_alpha) ? GL_DST_ALPHA : (GLenum)GL_ONE, + (target_has_alpha) ? GL_ONE_MINUS_DST_ALPHA : (GLenum)GL_ZERO}; - // blend mode bit mask - // 0 - blend enable - // 1 - dst alpha enabled - // 2 - reverse subtract enable (else add) - // 3-5 - srcRGB function - // 6-8 - dstRGB function + // blend mode bit mask + // 0 - blend enable + // 1 - dst alpha enabled + // 2 - reverse subtract enable (else add) + // 3-5 - srcRGB function + // 6-8 - dstRGB function - u32 newval = useDualSource << 1; - newval |= bpmem.blendmode.subtract << 2; + u32 newval = useDualSource << 1; + newval |= bpmem.blendmode.subtract << 2; - if (bpmem.blendmode.subtract) - { - newval |= 0x0049; // enable blending src 1 dst 1 - } - else if (bpmem.blendmode.blendenable) - { - newval |= 1; // enable blending - newval |= bpmem.blendmode.srcfactor << 3; - newval |= bpmem.blendmode.dstfactor << 6; - } + if (bpmem.blendmode.subtract) + { + newval |= 0x0049; // enable blending src 1 dst 1 + } + else if (bpmem.blendmode.blendenable) + { + newval |= 1; // enable blending + newval |= bpmem.blendmode.srcfactor << 3; + newval |= bpmem.blendmode.dstfactor << 6; + } - u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode; + u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode; - if (changes & 1) - { - // blend enable change - (newval & 1) ? glEnable(GL_BLEND) : glDisable(GL_BLEND); - } + if (changes & 1) + { + // blend enable change + (newval & 1) ? glEnable(GL_BLEND) : glDisable(GL_BLEND); + } - if (changes & 4) - { - // subtract enable change - GLenum equation = newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD; - GLenum equationAlpha = useDualSource ? GL_FUNC_ADD : equation; + if (changes & 4) + { + // subtract enable change + GLenum equation = newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD; + GLenum equationAlpha = useDualSource ? GL_FUNC_ADD : equation; - glBlendEquationSeparate(equation, equationAlpha); - } + glBlendEquationSeparate(equation, equationAlpha); + } - if (changes & 0x1FA) - { - u32 srcidx = (newval >> 3) & 7; - u32 dstidx = (newval >> 6) & 7; - GLenum srcFactor = glSrcFactors[srcidx]; - GLenum dstFactor = glDestFactors[dstidx]; + if (changes & 0x1FA) + { + u32 srcidx = (newval >> 3) & 7; + u32 dstidx = (newval >> 6) & 7; + GLenum srcFactor = glSrcFactors[srcidx]; + GLenum dstFactor = glDestFactors[dstidx]; - // adjust alpha factors - if (useDualSource) - { - srcidx = BlendMode::ONE; - dstidx = BlendMode::ZERO; - } - else - { - // we can't use GL_DST_COLOR or GL_ONE_MINUS_DST_COLOR for source in alpha channel so use their alpha equivalent instead - if (srcidx == BlendMode::DSTCLR) - srcidx = BlendMode::DSTALPHA; - else if (srcidx == BlendMode::INVDSTCLR) - srcidx = BlendMode::INVDSTALPHA; + // adjust alpha factors + if (useDualSource) + { + srcidx = BlendMode::ONE; + dstidx = BlendMode::ZERO; + } + else + { + // we can't use GL_DST_COLOR or GL_ONE_MINUS_DST_COLOR for source in alpha channel so use + // their alpha equivalent instead + if (srcidx == BlendMode::DSTCLR) + srcidx = BlendMode::DSTALPHA; + else if (srcidx == BlendMode::INVDSTCLR) + srcidx = BlendMode::INVDSTALPHA; - // we can't use GL_SRC_COLOR or GL_ONE_MINUS_SRC_COLOR for destination in alpha channel so use their alpha equivalent instead - if (dstidx == BlendMode::SRCCLR) - dstidx = BlendMode::SRCALPHA; - else if (dstidx == BlendMode::INVSRCCLR) - dstidx = BlendMode::INVSRCALPHA; - } - GLenum srcFactorAlpha = glSrcFactors[srcidx]; - GLenum dstFactorAlpha = glDestFactors[dstidx]; - // blend RGB change - glBlendFuncSeparate(srcFactor, dstFactor, srcFactorAlpha, dstFactorAlpha); - } - s_blendMode = newval; + // we can't use GL_SRC_COLOR or GL_ONE_MINUS_SRC_COLOR for destination in alpha channel so use + // their alpha equivalent instead + if (dstidx == BlendMode::SRCCLR) + dstidx = BlendMode::SRCALPHA; + else if (dstidx == BlendMode::INVSRCCLR) + dstidx = BlendMode::INVSRCALPHA; + } + GLenum srcFactorAlpha = glSrcFactors[srcidx]; + GLenum dstFactorAlpha = glDestFactors[dstidx]; + // blend RGB change + glBlendFuncSeparate(srcFactor, dstFactor, srcFactorAlpha, dstFactorAlpha); + } + s_blendMode = newval; } static void DumpFrame(const std::vector& data, int w, int h) { -#if defined(HAVE_LIBAV) || defined (_WIN32) - if (SConfig::GetInstance().m_DumpFrames && !data.empty()) - { - AVIDump::AddFrame(&data[0], w, h); - } +#if defined(HAVE_LIBAV) || defined(_WIN32) + if (SConfig::GetInstance().m_DumpFrames && !data.empty()) + { + AVIDump::AddFrame(&data[0], w, h); + } #endif } // This function has the final picture. We adjust the aspect ratio here. -void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma) +void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, + const EFBRectangle& rc, float Gamma) { - if (g_ogl_config.bSupportsDebug) - { - if (LogManager::GetInstance()->IsEnabled(LogTypes::HOST_GPU, LogTypes::LERROR)) - glEnable(GL_DEBUG_OUTPUT); - else - glDisable(GL_DEBUG_OUTPUT); - } + if (g_ogl_config.bSupportsDebug) + { + if (LogManager::GetInstance()->IsEnabled(LogTypes::HOST_GPU, LogTypes::LERROR)) + glEnable(GL_DEBUG_OUTPUT); + else + glDisable(GL_DEBUG_OUTPUT); + } - static int w = 0, h = 0; - if (Fifo::WillSkipCurrentFrame() || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight) - { - DumpFrame(frame_data, w, h); - Core::Callback_VideoCopiedToXFB(false); - return; - } + static int w = 0, h = 0; + if (Fifo::WillSkipCurrentFrame() || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || + !fbWidth || !fbHeight) + { + DumpFrame(frame_data, w, h); + Core::Callback_VideoCopiedToXFB(false); + return; + } - u32 xfbCount = 0; - const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbStride, fbHeight, &xfbCount); - if (g_ActiveConfig.VirtualXFBEnabled() && (!xfbSourceList || xfbCount == 0)) - { - DumpFrame(frame_data, w, h); - Core::Callback_VideoCopiedToXFB(false); - return; - } + u32 xfbCount = 0; + const XFBSourceBase* const* xfbSourceList = + FramebufferManager::GetXFBSource(xfbAddr, fbStride, fbHeight, &xfbCount); + if (g_ActiveConfig.VirtualXFBEnabled() && (!xfbSourceList || xfbCount == 0)) + { + DumpFrame(frame_data, w, h); + Core::Callback_VideoCopiedToXFB(false); + return; + } - ResetAPIState(); + ResetAPIState(); - UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); - TargetRectangle flipped_trc = GetTargetRectangle(); + UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); + TargetRectangle flipped_trc = GetTargetRectangle(); - // Flip top and bottom for some reason; TODO: Fix the code to suck less? - std::swap(flipped_trc.top, flipped_trc.bottom); + // Flip top and bottom for some reason; TODO: Fix the code to suck less? + std::swap(flipped_trc.top, flipped_trc.bottom); - // Copy the framebuffer to screen. - const XFBSource* xfbSource = nullptr; + // Copy the framebuffer to screen. + const XFBSource* xfbSource = nullptr; - if (g_ActiveConfig.bUseXFB) - { - // draw each xfb source - for (u32 i = 0; i < xfbCount; ++i) - { - xfbSource = (const XFBSource*) xfbSourceList[i]; + if (g_ActiveConfig.bUseXFB) + { + // draw each xfb source + for (u32 i = 0; i < xfbCount; ++i) + { + xfbSource = (const XFBSource*)xfbSourceList[i]; - TargetRectangle drawRc; - TargetRectangle sourceRc; - sourceRc.left = xfbSource->sourceRc.left; - sourceRc.right = xfbSource->sourceRc.right; - sourceRc.top = xfbSource->sourceRc.top; - sourceRc.bottom = xfbSource->sourceRc.bottom; + TargetRectangle drawRc; + TargetRectangle sourceRc; + sourceRc.left = xfbSource->sourceRc.left; + sourceRc.right = xfbSource->sourceRc.right; + sourceRc.top = xfbSource->sourceRc.top; + sourceRc.bottom = xfbSource->sourceRc.bottom; - if (g_ActiveConfig.bUseRealXFB) - { - drawRc = flipped_trc; - sourceRc.right -= fbStride - fbWidth; + if (g_ActiveConfig.bUseRealXFB) + { + drawRc = flipped_trc; + sourceRc.right -= fbStride - fbWidth; - // RealXFB doesn't call ConvertEFBRectangle for sourceRc, therefore it is still assuming a top-left origin. - // The top offset is always zero (see FramebufferManagerBase::GetRealXFBSource). - sourceRc.top = sourceRc.bottom; - sourceRc.bottom = 0; - } - else - { - // use virtual xfb with offset - int xfbHeight = xfbSource->srcHeight; - int xfbWidth = xfbSource->srcWidth; - int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbStride * 2); + // RealXFB doesn't call ConvertEFBRectangle for sourceRc, therefore it is still assuming a + // top-left origin. + // The top offset is always zero (see FramebufferManagerBase::GetRealXFBSource). + sourceRc.top = sourceRc.bottom; + sourceRc.bottom = 0; + } + else + { + // use virtual xfb with offset + int xfbHeight = xfbSource->srcHeight; + int xfbWidth = xfbSource->srcWidth; + int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbStride * 2); - drawRc.top = flipped_trc.top - hOffset * flipped_trc.GetHeight() / (s32)fbHeight; - drawRc.bottom = flipped_trc.top - (hOffset + xfbHeight) * flipped_trc.GetHeight() / (s32)fbHeight; - drawRc.left = flipped_trc.left + (flipped_trc.GetWidth() - xfbWidth * flipped_trc.GetWidth() / (s32)fbStride) / 2; - drawRc.right = flipped_trc.left + (flipped_trc.GetWidth() + xfbWidth * flipped_trc.GetWidth() / (s32)fbStride) / 2; + drawRc.top = flipped_trc.top - hOffset * flipped_trc.GetHeight() / (s32)fbHeight; + drawRc.bottom = + flipped_trc.top - (hOffset + xfbHeight) * flipped_trc.GetHeight() / (s32)fbHeight; + drawRc.left = + flipped_trc.left + + (flipped_trc.GetWidth() - xfbWidth * flipped_trc.GetWidth() / (s32)fbStride) / 2; + drawRc.right = + flipped_trc.left + + (flipped_trc.GetWidth() + xfbWidth * flipped_trc.GetWidth() / (s32)fbStride) / 2; - // The following code disables auto stretch. Kept for reference. - // scale draw area for a 1 to 1 pixel mapping with the draw target - //float vScale = (float)fbHeight / (float)flipped_trc.GetHeight(); - //float hScale = (float)fbWidth / (float)flipped_trc.GetWidth(); - //drawRc.top *= vScale; - //drawRc.bottom *= vScale; - //drawRc.left *= hScale; - //drawRc.right *= hScale; + // The following code disables auto stretch. Kept for reference. + // scale draw area for a 1 to 1 pixel mapping with the draw target + // float vScale = (float)fbHeight / (float)flipped_trc.GetHeight(); + // float hScale = (float)fbWidth / (float)flipped_trc.GetWidth(); + // drawRc.top *= vScale; + // drawRc.bottom *= vScale; + // drawRc.left *= hScale; + // drawRc.right *= hScale; - sourceRc.right -= Renderer::EFBToScaledX(fbStride - fbWidth); - } - // Tell the OSD Menu about the current internal resolution - OSDInternalW = xfbSource->sourceRc.GetWidth(); OSDInternalH = xfbSource->sourceRc.GetHeight(); + sourceRc.right -= Renderer::EFBToScaledX(fbStride - fbWidth); + } + // Tell the OSD Menu about the current internal resolution + OSDInternalW = xfbSource->sourceRc.GetWidth(); + OSDInternalH = xfbSource->sourceRc.GetHeight(); - BlitScreen(sourceRc, drawRc, xfbSource->texture, xfbSource->texWidth, xfbSource->texHeight); - } - } - else - { - TargetRectangle targetRc = ConvertEFBRectangle(rc); + BlitScreen(sourceRc, drawRc, xfbSource->texture, xfbSource->texWidth, xfbSource->texHeight); + } + } + else + { + TargetRectangle targetRc = ConvertEFBRectangle(rc); - // for msaa mode, we must resolve the efb content to non-msaa - GLuint tex = FramebufferManager::ResolveAndGetRenderTarget(rc); - BlitScreen(targetRc, flipped_trc, tex, s_target_width, s_target_height); - } + // for msaa mode, we must resolve the efb content to non-msaa + GLuint tex = FramebufferManager::ResolveAndGetRenderTarget(rc); + BlitScreen(targetRc, flipped_trc, tex, s_target_width, s_target_height); + } - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - // Save screenshot - if (s_bScreenshot) - { - std::lock_guard lk(s_criticalScreenshot); + // Save screenshot + if (s_bScreenshot) + { + std::lock_guard lk(s_criticalScreenshot); - if (SaveScreenshot(s_sScreenshotName, flipped_trc)) - OSD::AddMessage("Screenshot saved to " + s_sScreenshotName); + if (SaveScreenshot(s_sScreenshotName, flipped_trc)) + OSD::AddMessage("Screenshot saved to " + s_sScreenshotName); - // Reset settings - s_sScreenshotName.clear(); - s_bScreenshot = false; - s_screenshotCompleted.Set(); - } + // Reset settings + s_sScreenshotName.clear(); + s_bScreenshot = false; + s_screenshotCompleted.Set(); + } - // Frame dumps are handled a little differently in Windows -#if defined(HAVE_LIBAV) || defined (_WIN32) - if (SConfig::GetInstance().m_DumpFrames) - { - std::lock_guard lk(s_criticalScreenshot); +// Frame dumps are handled a little differently in Windows +#if defined(HAVE_LIBAV) || defined(_WIN32) + if (SConfig::GetInstance().m_DumpFrames) + { + std::lock_guard lk(s_criticalScreenshot); - if (frame_data.empty() || - w != flipped_trc.GetWidth() || h != flipped_trc.GetHeight()) - { - w = flipped_trc.GetWidth(); - h = flipped_trc.GetHeight(); - frame_data.resize(4 * w * h); - } + if (frame_data.empty() || w != flipped_trc.GetWidth() || h != flipped_trc.GetHeight()) + { + w = flipped_trc.GetWidth(); + h = flipped_trc.GetHeight(); + frame_data.resize(4 * w * h); + } - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(flipped_trc.left, flipped_trc.bottom, w, h, GL_RGBA, GL_UNSIGNED_BYTE, &frame_data[0]); - if (w > 0 && h > 0) - { - if (!bLastFrameDumped) - { - bAVIDumping = AVIDump::Start(w, h, AVIDump::DumpFormat::FORMAT_RGBA); - if (!bAVIDumping) - { - OSD::AddMessage("AVIDump Start failed", 2000); - } - else - { - OSD::AddMessage(StringFromFormat( - "Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)", - File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), w, h), 2000); - } - } - if (bAVIDumping) - { - FlipImageData(&frame_data[0], w, h, 4); - AVIDump::AddFrame(&frame_data[0], w, h); - } + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(flipped_trc.left, flipped_trc.bottom, w, h, GL_RGBA, GL_UNSIGNED_BYTE, + &frame_data[0]); + if (w > 0 && h > 0) + { + if (!bLastFrameDumped) + { + bAVIDumping = AVIDump::Start(w, h, AVIDump::DumpFormat::FORMAT_RGBA); + if (!bAVIDumping) + { + OSD::AddMessage("AVIDump Start failed", 2000); + } + else + { + OSD::AddMessage(StringFromFormat("Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)", + File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), w, h), + 2000); + } + } + if (bAVIDumping) + { + FlipImageData(&frame_data[0], w, h, 4); + AVIDump::AddFrame(&frame_data[0], w, h); + } - bLastFrameDumped = true; - } - else - { - NOTICE_LOG(VIDEO, "Error reading framebuffer"); - } - } - else - { - if (bLastFrameDumped && bAVIDumping) - { - std::vector().swap(frame_data); - w = h = 0; - AVIDump::Stop(); - bAVIDumping = false; - OSD::AddMessage("Stop dumping frames", 2000); - } - bLastFrameDumped = false; - } + bLastFrameDumped = true; + } + else + { + NOTICE_LOG(VIDEO, "Error reading framebuffer"); + } + } + else + { + if (bLastFrameDumped && bAVIDumping) + { + std::vector().swap(frame_data); + w = h = 0; + AVIDump::Stop(); + bAVIDumping = false; + OSD::AddMessage("Stop dumping frames", 2000); + } + bLastFrameDumped = false; + } #endif - // Finish up the current frame, print some stats + // Finish up the current frame, print some stats - SetWindowSize(fbStride, fbHeight); + SetWindowSize(fbStride, fbHeight); - GLInterface->Update(); // just updates the render window position and the backbuffer size + GLInterface->Update(); // just updates the render window position and the backbuffer size - bool xfbchanged = s_last_xfb_mode != g_ActiveConfig.bUseRealXFB; + bool xfbchanged = s_last_xfb_mode != g_ActiveConfig.bUseRealXFB; - if (FramebufferManagerBase::LastXfbWidth() != fbStride || FramebufferManagerBase::LastXfbHeight() != fbHeight) - { - xfbchanged = true; - unsigned int const last_w = (fbStride < 1 || fbStride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fbStride; - unsigned int const last_h = (fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fbHeight; - FramebufferManagerBase::SetLastXfbWidth(last_w); - FramebufferManagerBase::SetLastXfbHeight(last_h); - } + if (FramebufferManagerBase::LastXfbWidth() != fbStride || + FramebufferManagerBase::LastXfbHeight() != fbHeight) + { + xfbchanged = true; + unsigned int const last_w = + (fbStride < 1 || fbStride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fbStride; + unsigned int const last_h = + (fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fbHeight; + FramebufferManagerBase::SetLastXfbWidth(last_w); + FramebufferManagerBase::SetLastXfbHeight(last_h); + } - bool WindowResized = false; - int W = (int)GLInterface->GetBackBufferWidth(); - int H = (int)GLInterface->GetBackBufferHeight(); - if (W != s_backbuffer_width || H != s_backbuffer_height || s_last_efb_scale != g_ActiveConfig.iEFBScale) - { - WindowResized = true; - s_backbuffer_width = W; - s_backbuffer_height = H; - s_last_efb_scale = g_ActiveConfig.iEFBScale; - } - bool TargetSizeChanged = false; - if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height)) - { - TargetSizeChanged = true; - } - if (TargetSizeChanged || xfbchanged || WindowResized || - (s_last_multisamples != g_ActiveConfig.iMultisamples) || (s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0))) - { - s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; + bool WindowResized = false; + int W = (int)GLInterface->GetBackBufferWidth(); + int H = (int)GLInterface->GetBackBufferHeight(); + if (W != s_backbuffer_width || H != s_backbuffer_height || + s_last_efb_scale != g_ActiveConfig.iEFBScale) + { + WindowResized = true; + s_backbuffer_width = W; + s_backbuffer_height = H; + s_last_efb_scale = g_ActiveConfig.iEFBScale; + } + bool TargetSizeChanged = false; + if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height)) + { + TargetSizeChanged = true; + } + if (TargetSizeChanged || xfbchanged || WindowResized || + (s_last_multisamples != g_ActiveConfig.iMultisamples) || + (s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0))) + { + s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; - UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); + UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); - if (TargetSizeChanged || - s_last_multisamples != g_ActiveConfig.iMultisamples || s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0)) - { - s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; - s_last_multisamples = g_ActiveConfig.iMultisamples; - s_MSAASamples = s_last_multisamples; + if (TargetSizeChanged || s_last_multisamples != g_ActiveConfig.iMultisamples || + s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0)) + { + s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; + s_last_multisamples = g_ActiveConfig.iMultisamples; + s_MSAASamples = s_last_multisamples; - if (s_MSAASamples > 1 && s_MSAASamples > g_ogl_config.max_samples) - { - s_MSAASamples = g_ogl_config.max_samples; - OSD::AddMessage(StringFromFormat("%d Anti Aliasing samples selected, but only %d supported by your GPU.", s_last_multisamples, g_ogl_config.max_samples), 10000); - } + if (s_MSAASamples > 1 && s_MSAASamples > g_ogl_config.max_samples) + { + s_MSAASamples = g_ogl_config.max_samples; + OSD::AddMessage(StringFromFormat( + "%d Anti Aliasing samples selected, but only %d supported by your GPU.", + s_last_multisamples, g_ogl_config.max_samples), + 10000); + } - g_framebuffer_manager.reset(); - g_framebuffer_manager = std::make_unique(s_target_width, s_target_height, s_MSAASamples); + g_framebuffer_manager.reset(); + g_framebuffer_manager = + std::make_unique(s_target_width, s_target_height, s_MSAASamples); - PixelShaderManager::SetEfbScaleChanged(); - } - } + PixelShaderManager::SetEfbScaleChanged(); + } + } - // --------------------------------------------------------------------- - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + // --------------------------------------------------------------------- + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - // Reset viewport for drawing text - glViewport(0, 0, GLInterface->GetBackBufferWidth(), GLInterface->GetBackBufferHeight()); + // Reset viewport for drawing text + glViewport(0, 0, GLInterface->GetBackBufferWidth(), GLInterface->GetBackBufferHeight()); - DrawDebugText(); + DrawDebugText(); - // Do our OSD callbacks - OSD::DoCallbacks(OSD::CallbackType::OnFrame); - OSD::DrawMessages(); + // Do our OSD callbacks + OSD::DoCallbacks(OSD::CallbackType::OnFrame); + OSD::DrawMessages(); - if (s_SurfaceNeedsChanged.IsSet()) - { - GLInterface->UpdateSurface(); - s_SurfaceNeedsChanged.Clear(); - s_ChangedSurface.Set(); - } + if (s_SurfaceNeedsChanged.IsSet()) + { + GLInterface->UpdateSurface(); + s_SurfaceNeedsChanged.Clear(); + s_ChangedSurface.Set(); + } - // Copy the rendered frame to the real window - GLInterface->Swap(); + // Copy the rendered frame to the real window + GLInterface->Swap(); - // Clear framebuffer - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // Clear framebuffer + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - if (s_vsync != g_ActiveConfig.IsVSync()) - { - s_vsync = g_ActiveConfig.IsVSync(); - if (!DriverDetails::HasBug(DriverDetails::BUG_BROKENVSYNC)) - GLInterface->SwapInterval(s_vsync); - } + if (s_vsync != g_ActiveConfig.IsVSync()) + { + s_vsync = g_ActiveConfig.IsVSync(); + if (!DriverDetails::HasBug(DriverDetails::BUG_BROKENVSYNC)) + GLInterface->SwapInterval(s_vsync); + } - // Clean out old stuff from caches. It's not worth it to clean out the shader caches. - TextureCache::Cleanup(frameCount); + // Clean out old stuff from caches. It's not worth it to clean out the shader caches. + TextureCache::Cleanup(frameCount); - // Render to the framebuffer. - FramebufferManager::SetFramebuffer(0); + // Render to the framebuffer. + FramebufferManager::SetFramebuffer(0); - RestoreAPIState(); + RestoreAPIState(); - g_Config.iSaveTargetId = 0; + g_Config.iSaveTargetId = 0; - UpdateActiveConfig(); - TextureCache::OnConfigChanged(g_ActiveConfig); + UpdateActiveConfig(); + TextureCache::OnConfigChanged(g_ActiveConfig); - // For testing zbuffer targets. - // Renderer::SetZBufferRender(); - // SaveTexture("tex.png", GL_TEXTURE_2D, s_FakeZTarget, - // GetTargetWidth(), GetTargetHeight()); + // For testing zbuffer targets. + // Renderer::SetZBufferRender(); + // SaveTexture("tex.png", GL_TEXTURE_2D, s_FakeZTarget, + // GetTargetWidth(), GetTargetHeight()); - // Invalidate EFB cache - ClearEFBCache(); + // Invalidate EFB cache + ClearEFBCache(); } // ALWAYS call RestoreAPIState for each ResetAPIState call you're doing void Renderer::ResetAPIState() { - // Gets us to a reasonably sane state where it's possible to do things like - // image copies with textured quads, etc. - glDisable(GL_SCISSOR_TEST); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) - glDisable(GL_COLOR_LOGIC_OP); - glDepthMask(GL_FALSE); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + // Gets us to a reasonably sane state where it's possible to do things like + // image copies with textured quads, etc. + glDisable(GL_SCISSOR_TEST); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) + glDisable(GL_COLOR_LOGIC_OP); + glDepthMask(GL_FALSE); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } void Renderer::RestoreAPIState() { - // Gets us back into a more game-like state. - glEnable(GL_SCISSOR_TEST); - SetGenerationMode(); - BPFunctions::SetScissor(); - SetColorMask(); - SetDepthMode(); - SetBlendMode(true); - SetLogicOpMode(); - SetViewport(); + // Gets us back into a more game-like state. + glEnable(GL_SCISSOR_TEST); + SetGenerationMode(); + BPFunctions::SetScissor(); + SetColorMask(); + SetDepthMode(); + SetBlendMode(true); + SetLogicOpMode(); + SetViewport(); - const VertexManager* const vm = static_cast(g_vertex_manager.get()); - glBindBuffer(GL_ARRAY_BUFFER, vm->m_vertex_buffers); - if (vm->m_last_vao) - glBindVertexArray(vm->m_last_vao); + const VertexManager* const vm = static_cast(g_vertex_manager.get()); + glBindBuffer(GL_ARRAY_BUFFER, vm->m_vertex_buffers); + if (vm->m_last_vao) + glBindVertexArray(vm->m_last_vao); - TextureCache::SetStage(); + TextureCache::SetStage(); } void Renderer::SetGenerationMode() { - // none, ccw, cw, ccw - if (bpmem.genMode.cullmode > 0) - { - // TODO: GX_CULL_ALL not supported, yet! - glEnable(GL_CULL_FACE); - glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW : GL_CW); - } - else - { - glDisable(GL_CULL_FACE); - } + // none, ccw, cw, ccw + if (bpmem.genMode.cullmode > 0) + { + // TODO: GX_CULL_ALL not supported, yet! + glEnable(GL_CULL_FACE); + glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW : GL_CW); + } + else + { + glDisable(GL_CULL_FACE); + } } void Renderer::SetDepthMode() { - const GLenum glCmpFuncs[8] = - { - GL_NEVER, - GL_LESS, - GL_EQUAL, - GL_LEQUAL, - GL_GREATER, - GL_NOTEQUAL, - GL_GEQUAL, - GL_ALWAYS - }; + const GLenum glCmpFuncs[8] = {GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, + GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS}; - if (bpmem.zmode.testenable) - { - glEnable(GL_DEPTH_TEST); - glDepthMask(bpmem.zmode.updateenable ? GL_TRUE : GL_FALSE); - glDepthFunc(glCmpFuncs[bpmem.zmode.func]); - } - else - { - // if the test is disabled write is disabled too - // TODO: When PE performance metrics are being emulated via occlusion queries, we should (probably?) enable depth test with depth function ALWAYS here - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - } + if (bpmem.zmode.testenable) + { + glEnable(GL_DEPTH_TEST); + glDepthMask(bpmem.zmode.updateenable ? GL_TRUE : GL_FALSE); + glDepthFunc(glCmpFuncs[bpmem.zmode.func]); + } + else + { + // if the test is disabled write is disabled too + // TODO: When PE performance metrics are being emulated via occlusion queries, we should + // (probably?) enable depth test with depth function ALWAYS here + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + } } void Renderer::SetLogicOpMode() { - if (GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL) - return; - // Logic ops aren't available in GLES3/GLES2 - const GLenum glLogicOpCodes[16] = - { - GL_CLEAR, - GL_AND, - GL_AND_REVERSE, - GL_COPY, - GL_AND_INVERTED, - GL_NOOP, - GL_XOR, - GL_OR, - GL_NOR, - GL_EQUIV, - GL_INVERT, - GL_OR_REVERSE, - GL_COPY_INVERTED, - GL_OR_INVERTED, - GL_NAND, - GL_SET - }; + if (GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL) + return; + // Logic ops aren't available in GLES3/GLES2 + const GLenum glLogicOpCodes[16] = { + GL_CLEAR, GL_AND, GL_AND_REVERSE, GL_COPY, GL_AND_INVERTED, GL_NOOP, + GL_XOR, GL_OR, GL_NOR, GL_EQUIV, GL_INVERT, GL_OR_REVERSE, + GL_COPY_INVERTED, GL_OR_INVERTED, GL_NAND, GL_SET}; - if (bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable) - { - glEnable(GL_COLOR_LOGIC_OP); - glLogicOp(glLogicOpCodes[bpmem.blendmode.logicmode]); - } - else - { - glDisable(GL_COLOR_LOGIC_OP); - } + if (bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable) + { + glEnable(GL_COLOR_LOGIC_OP); + glLogicOp(glLogicOpCodes[bpmem.blendmode.logicmode]); + } + else + { + glDisable(GL_COLOR_LOGIC_OP); + } } void Renderer::SetDitherMode() { - if (bpmem.blendmode.dither) - glEnable(GL_DITHER); - else - glDisable(GL_DITHER); + if (bpmem.blendmode.dither) + glEnable(GL_DITHER); + else + glDisable(GL_DITHER); } void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex) { - auto const& tex = bpmem.tex[texindex]; - auto const& tm0 = tex.texMode0[stage]; - auto const& tm1 = tex.texMode1[stage]; + auto const& tex = bpmem.tex[texindex]; + auto const& tm0 = tex.texMode0[stage]; + auto const& tm1 = tex.texMode1[stage]; - g_sampler_cache->SetSamplerState((texindex * 4) + stage, tm0, tm1, custom_tex); + g_sampler_cache->SetSamplerState((texindex * 4) + stage, tm0, tm1, custom_tex); } void Renderer::SetInterlacingMode() { - // TODO + // TODO } - } namespace OGL { - -bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle &back_rc) +bool Renderer::SaveScreenshot(const std::string& filename, const TargetRectangle& back_rc) { - u32 W = back_rc.GetWidth(); - u32 H = back_rc.GetHeight(); - std::unique_ptr data(new u8[W * 4 * H]); - glPixelStorei(GL_PACK_ALIGNMENT, 1); + u32 W = back_rc.GetWidth(); + u32 H = back_rc.GetHeight(); + std::unique_ptr data(new u8[W * 4 * H]); + glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(back_rc.left, back_rc.bottom, W, H, GL_RGBA, GL_UNSIGNED_BYTE, data.get()); + glReadPixels(back_rc.left, back_rc.bottom, W, H, GL_RGBA, GL_UNSIGNED_BYTE, data.get()); - // Turn image upside down - FlipImageData(data.get(), W, H, 4); - - return TextureToPng(data.get(), W * 4, filename, W, H, false); + // Turn image upside down + FlipImageData(data.get(), W, H, 4); + return TextureToPng(data.get(), W * 4, filename, W, H, false); } int Renderer::GetMaxTextureSize() { - // Right now nvidia seems to do something very weird if we try to cache GL_MAX_TEXTURE_SIZE in init. This is a workaround that lets - // us keep the perf improvement that caching it gives us. - if (s_max_texture_size == 0) - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &s_max_texture_size); - return s_max_texture_size; + // Right now nvidia seems to do something very weird if we try to cache GL_MAX_TEXTURE_SIZE in + // init. This is a workaround that lets + // us keep the perf improvement that caching it gives us. + if (s_max_texture_size == 0) + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &s_max_texture_size); + return s_max_texture_size; } - } diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index babf9d6aca..efcc4e81b9 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -9,106 +9,108 @@ namespace OGL { - void ClearEFBCache(); enum GLSL_VERSION { - GLSL_130, - GLSL_140, - GLSL_150, - GLSL_330, - GLSL_400, // and above - GLSLES_300, // GLES 3.0 - GLSLES_310, // GLES 3.1 - GLSLES_320, // GLES 3.2 + GLSL_130, + GLSL_140, + GLSL_150, + GLSL_330, + GLSL_400, // and above + GLSLES_300, // GLES 3.0 + GLSLES_310, // GLES 3.1 + GLSLES_320, // GLES 3.2 }; enum class ES_TEXBUF_TYPE { - TEXBUF_NONE, - TEXBUF_CORE, - TEXBUF_OES, - TEXBUF_EXT + TEXBUF_NONE, + TEXBUF_CORE, + TEXBUF_OES, + TEXBUF_EXT }; // ogl-only config, so not in VideoConfig.h struct VideoConfig { - bool bSupportsGLSLCache; - bool bSupportsGLPinnedMemory; - bool bSupportsGLSync; - bool bSupportsGLBaseVertex; - bool bSupportsGLBufferStorage; - bool bSupportsMSAA; - GLSL_VERSION eSupportedGLSLVersion; - bool bSupportViewportFloat; - bool bSupportsAEP; - bool bSupportsDebug; - bool bSupportsCopySubImage; - u8 SupportedESPointSize; - ES_TEXBUF_TYPE SupportedESTextureBuffer; - bool bSupports2DTextureStorage; - bool bSupports3DTextureStorage; - bool bSupportsEarlyFragmentTests; - bool bSupportsConservativeDepth; - bool bSupportsAniso; + bool bSupportsGLSLCache; + bool bSupportsGLPinnedMemory; + bool bSupportsGLSync; + bool bSupportsGLBaseVertex; + bool bSupportsGLBufferStorage; + bool bSupportsMSAA; + GLSL_VERSION eSupportedGLSLVersion; + bool bSupportViewportFloat; + bool bSupportsAEP; + bool bSupportsDebug; + bool bSupportsCopySubImage; + u8 SupportedESPointSize; + ES_TEXBUF_TYPE SupportedESTextureBuffer; + bool bSupports2DTextureStorage; + bool bSupports3DTextureStorage; + bool bSupportsEarlyFragmentTests; + bool bSupportsConservativeDepth; + bool bSupportsAniso; - const char* gl_vendor; - const char* gl_renderer; - const char* gl_version; - const char* glsl_version; + const char* gl_vendor; + const char* gl_renderer; + const char* gl_version; + const char* glsl_version; - s32 max_samples; + s32 max_samples; }; extern VideoConfig g_ogl_config; class Renderer : public ::Renderer { public: - Renderer(); - ~Renderer(); + Renderer(); + ~Renderer(); - static void Init(); - static void Shutdown(); + static void Init(); + static void Shutdown(); - void SetColorMask() override; - void SetBlendMode(bool forceUpdate) override; - void SetScissorRect(const EFBRectangle& rc) override; - void SetGenerationMode() override; - void SetDepthMode() override; - void SetLogicOpMode() override; - void SetDitherMode() override; - void SetSamplerState(int stage, int texindex, bool custom_tex) override; - void SetInterlacingMode() override; - void SetViewport() override; + void SetColorMask() override; + void SetBlendMode(bool forceUpdate) override; + void SetScissorRect(const EFBRectangle& rc) override; + void SetGenerationMode() override; + void SetDepthMode() override; + void SetLogicOpMode() override; + void SetDitherMode() override; + void SetSamplerState(int stage, int texindex, bool custom_tex) override; + void SetInterlacingMode() override; + void SetViewport() override; - void RenderText(const std::string& text, int left, int top, u32 color) override; + void RenderText(const std::string& text, int left, int top, u32 color) override; - u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; - void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override; + u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; + void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override; - u16 BBoxRead(int index) override; - void BBoxWrite(int index, u16 value) override; + u16 BBoxRead(int index) override; + void BBoxWrite(int index, u16 value) override; - void ResetAPIState() override; - void RestoreAPIState() override; + void ResetAPIState() override; + void RestoreAPIState() override; - TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; + TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; - void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma) override; + void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, + float Gamma) override; - void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override; + void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, + u32 color, u32 z) override; - void ReinterpretPixelData(unsigned int convtype) override; + void ReinterpretPixelData(unsigned int convtype) override; - bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc) override; + bool SaveScreenshot(const std::string& filename, const TargetRectangle& rc) override; - int GetMaxTextureSize() override; + int GetMaxTextureSize() override; private: - void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc, const TargetRectangle& targetPixelRc, const void* data); + void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc, + const TargetRectangle& targetPixelRc, const void* data); - void BlitScreen(TargetRectangle src, TargetRectangle dst, GLuint src_texture, int src_width, int src_height); + void BlitScreen(TargetRectangle src, TargetRectangle dst, GLuint src_texture, int src_width, + int src_height); }; - } diff --git a/Source/Core/VideoBackends/OGL/SamplerCache.cpp b/Source/Core/VideoBackends/OGL/SamplerCache.cpp index d9a2008a50..82cc74daa8 100644 --- a/Source/Core/VideoBackends/OGL/SamplerCache.cpp +++ b/Source/Core/VideoBackends/OGL/SamplerCache.cpp @@ -13,154 +13,143 @@ namespace OGL { - std::unique_ptr g_sampler_cache; -SamplerCache::SamplerCache() - : m_last_max_anisotropy() +SamplerCache::SamplerCache() : m_last_max_anisotropy() { - glGenSamplers(2, m_sampler_id); - glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glGenSamplers(2, m_sampler_id); + glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } SamplerCache::~SamplerCache() { - Clear(); - glDeleteSamplers(2, m_sampler_id); + Clear(); + glDeleteSamplers(2, m_sampler_id); } void SamplerCache::BindNearestSampler(int stage) { - glBindSampler(stage, m_sampler_id[0]); + glBindSampler(stage, m_sampler_id[0]); } void SamplerCache::BindLinearSampler(int stage) { - glBindSampler(stage, m_sampler_id[1]); + glBindSampler(stage, m_sampler_id[1]); } -void SamplerCache::SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1, bool custom_tex) +void SamplerCache::SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1, + bool custom_tex) { - // TODO: can this go somewhere else? - if (m_last_max_anisotropy != g_ActiveConfig.iMaxAnisotropy) - { - m_last_max_anisotropy = g_ActiveConfig.iMaxAnisotropy; - Clear(); - } + // TODO: can this go somewhere else? + if (m_last_max_anisotropy != g_ActiveConfig.iMaxAnisotropy) + { + m_last_max_anisotropy = g_ActiveConfig.iMaxAnisotropy; + Clear(); + } - Params params(tm0, tm1); + Params params(tm0, tm1); - // take equivalent forced linear when bForceFiltering - if (g_ActiveConfig.bForceFiltering) - { - params.tm0.min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4; - params.tm0.mag_filter = 1; - } + // take equivalent forced linear when bForceFiltering + if (g_ActiveConfig.bForceFiltering) + { + params.tm0.min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4; + params.tm0.mag_filter = 1; + } - // custom textures may have higher resolution, so disable the max_lod - if (custom_tex) - { - params.tm1.max_lod = 255; - } + // custom textures may have higher resolution, so disable the max_lod + if (custom_tex) + { + params.tm1.max_lod = 255; + } - // TODO: Should keep a circular buffer for each stage of recently used samplers. + // TODO: Should keep a circular buffer for each stage of recently used samplers. - auto& active_sampler = m_active_samplers[stage]; - if (active_sampler.first != params || !active_sampler.second.sampler_id) - { - // Active sampler does not match parameters (or is invalid), bind the proper one. - active_sampler.first = params; - active_sampler.second = GetEntry(params); - glBindSampler(stage, active_sampler.second.sampler_id); - } + auto& active_sampler = m_active_samplers[stage]; + if (active_sampler.first != params || !active_sampler.second.sampler_id) + { + // Active sampler does not match parameters (or is invalid), bind the proper one. + active_sampler.first = params; + active_sampler.second = GetEntry(params); + glBindSampler(stage, active_sampler.second.sampler_id); + } } SamplerCache::Value& SamplerCache::GetEntry(const Params& params) { - auto& val = m_cache[params]; - if (!val.sampler_id) - { - // Sampler not found in cache, create it. - glGenSamplers(1, &val.sampler_id); - SetParameters(val.sampler_id, params); + auto& val = m_cache[params]; + if (!val.sampler_id) + { + // Sampler not found in cache, create it. + glGenSamplers(1, &val.sampler_id); + SetParameters(val.sampler_id, params); - // TODO: Maybe kill old samplers if the cache gets huge. It doesn't seem to get huge though. - //ERROR_LOG(VIDEO, "Sampler cache size is now %ld.", m_cache.size()); - } + // TODO: Maybe kill old samplers if the cache gets huge. It doesn't seem to get huge though. + // ERROR_LOG(VIDEO, "Sampler cache size is now %ld.", m_cache.size()); + } - return val; + return val; } void SamplerCache::SetParameters(GLuint sampler_id, const Params& params) { - static const GLint min_filters[8] = - { - GL_NEAREST, - GL_NEAREST_MIPMAP_NEAREST, - GL_NEAREST_MIPMAP_LINEAR, - GL_NEAREST, - GL_LINEAR, - GL_LINEAR_MIPMAP_NEAREST, - GL_LINEAR_MIPMAP_LINEAR, - GL_LINEAR, - }; + static const GLint min_filters[8] = { + GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, + GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, + }; - static const GLint wrap_settings[4] = - { - GL_CLAMP_TO_EDGE, - GL_REPEAT, - GL_MIRRORED_REPEAT, - GL_REPEAT, - }; + static const GLint wrap_settings[4] = { + GL_CLAMP_TO_EDGE, GL_REPEAT, GL_MIRRORED_REPEAT, GL_REPEAT, + }; - auto& tm0 = params.tm0; - auto& tm1 = params.tm1; + auto& tm0 = params.tm0; + auto& tm1 = params.tm1; - glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_S, wrap_settings[tm0.wrap_s]); - glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T, wrap_settings[tm0.wrap_t]); + glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_S, wrap_settings[tm0.wrap_s]); + glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T, wrap_settings[tm0.wrap_t]); - glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, tm1.min_lod / 16.f); - glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, tm1.max_lod / 16.f); + glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, tm1.min_lod / 16.f); + glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, tm1.max_lod / 16.f); - if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) - glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, (s32)tm0.lod_bias / 32.f); + if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) + glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, (s32)tm0.lod_bias / 32.f); - GLint min_filter = min_filters[tm0.min_filter]; - GLint mag_filter = tm0.mag_filter ? GL_LINEAR : GL_NEAREST; + GLint min_filter = min_filters[tm0.min_filter]; + GLint mag_filter = tm0.mag_filter ? GL_LINEAR : GL_NEAREST; - if (g_ActiveConfig.iMaxAnisotropy > 0 && g_ogl_config.bSupportsAniso && - !SamplerCommon::IsBpTexMode0PointFiltering(tm0)) - { - // https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt - // For predictable results on all hardware/drivers, only use one of: - // GL_LINEAR + GL_LINEAR (No Mipmaps [Bilinear]) - // GL_LINEAR + GL_LINEAR_MIPMAP_LINEAR (w/ Mipmaps [Trilinear]) - // Letting the game set other combinations will have varying arbitrary results; - // possibly being interpreted as equal to bilinear/trilinear, implicitly - // disabling anisotropy, or changing the anisotropic algorithm employed. - min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR; - mag_filter = GL_LINEAR; - glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)(1 << g_ActiveConfig.iMaxAnisotropy)); - } + if (g_ActiveConfig.iMaxAnisotropy > 0 && g_ogl_config.bSupportsAniso && + !SamplerCommon::IsBpTexMode0PointFiltering(tm0)) + { + // https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt + // For predictable results on all hardware/drivers, only use one of: + // GL_LINEAR + GL_LINEAR (No Mipmaps [Bilinear]) + // GL_LINEAR + GL_LINEAR_MIPMAP_LINEAR (w/ Mipmaps [Trilinear]) + // Letting the game set other combinations will have varying arbitrary results; + // possibly being interpreted as equal to bilinear/trilinear, implicitly + // disabling anisotropy, or changing the anisotropic algorithm employed. + min_filter = + SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR; + mag_filter = GL_LINEAR; + glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, + (float)(1 << g_ActiveConfig.iMaxAnisotropy)); + } - glSamplerParameteri(sampler_id, GL_TEXTURE_MIN_FILTER, min_filter); - glSamplerParameteri(sampler_id, GL_TEXTURE_MAG_FILTER, mag_filter); + glSamplerParameteri(sampler_id, GL_TEXTURE_MIN_FILTER, min_filter); + glSamplerParameteri(sampler_id, GL_TEXTURE_MAG_FILTER, mag_filter); } void SamplerCache::Clear() { - for (auto& p : m_cache) - { - glDeleteSamplers(1, &p.second.sampler_id); - } - m_cache.clear(); + for (auto& p : m_cache) + { + glDeleteSamplers(1, &p.second.sampler_id); + } + m_cache.clear(); } - } diff --git a/Source/Core/VideoBackends/OGL/SamplerCache.h b/Source/Core/VideoBackends/OGL/SamplerCache.h index 920835ef03..a579591387 100644 --- a/Source/Core/VideoBackends/OGL/SamplerCache.h +++ b/Source/Core/VideoBackends/OGL/SamplerCache.h @@ -8,79 +8,61 @@ #include #include "Common/CommonTypes.h" -#include "Common/NonCopyable.h" #include "Common/GL/GLUtil.h" +#include "Common/NonCopyable.h" #include "VideoBackends/OGL/Render.h" namespace OGL { - class SamplerCache : NonCopyable { public: - SamplerCache(); - ~SamplerCache(); + SamplerCache(); + ~SamplerCache(); - void SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1, bool custom_tex); - void Clear(); - void BindNearestSampler(int stage); - void BindLinearSampler(int stage); + void SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1, bool custom_tex); + void Clear(); + void BindNearestSampler(int stage); + void BindLinearSampler(int stage); private: - struct Params - { - union - { - struct - { - TexMode0 tm0; - TexMode1 tm1; - }; + struct Params + { + union { + struct + { + TexMode0 tm0; + TexMode1 tm1; + }; - u64 hex; - }; + u64 hex; + }; - Params() - : hex() - {} + Params() : hex() {} + Params(const TexMode0& _tm0, const TexMode1& _tm1) : tm0(_tm0), tm1(_tm1) + { + static_assert(sizeof(Params) == 8, "Assuming I can treat this as a 64bit int."); + } - Params(const TexMode0& _tm0, const TexMode1& _tm1) - : tm0(_tm0) - , tm1(_tm1) - { - static_assert(sizeof(Params) == 8, "Assuming I can treat this as a 64bit int."); - } + bool operator<(const Params& other) const { return hex < other.hex; } + bool operator!=(const Params& other) const { return hex != other.hex; } + }; - bool operator<(const Params& other) const - { - return hex < other.hex; - } + struct Value + { + Value() : sampler_id() {} + GLuint sampler_id; + }; - bool operator!=(const Params& other) const - { - return hex != other.hex; - } - }; + void SetParameters(GLuint sampler_id, const Params& params); + Value& GetEntry(const Params& params); - struct Value - { - Value() - : sampler_id() - {} + std::map m_cache; + std::pair m_active_samplers[8]; - GLuint sampler_id; - }; - - void SetParameters(GLuint sampler_id, const Params& params); - Value& GetEntry(const Params& params); - - std::map m_cache; - std::pair m_active_samplers[8]; - - int m_last_max_anisotropy; - u32 m_sampler_id[2]; + int m_last_max_anisotropy; + u32 m_sampler_id[2]; }; extern std::unique_ptr g_sampler_cache; - } diff --git a/Source/Core/VideoBackends/OGL/StreamBuffer.cpp b/Source/Core/VideoBackends/OGL/StreamBuffer.cpp index b616720ae2..1ed598b043 100644 --- a/Source/Core/VideoBackends/OGL/StreamBuffer.cpp +++ b/Source/Core/VideoBackends/OGL/StreamBuffer.cpp @@ -2,8 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Common/MemoryUtil.h" #include "Common/GL/GLUtil.h" +#include "Common/MemoryUtil.h" #include "VideoBackends/OGL/Render.h" #include "VideoBackends/OGL/StreamBuffer.h" @@ -13,27 +13,26 @@ namespace OGL { - // moved out of constructor, so m_buffer is allowed to be const static u32 GenBuffer() { - u32 id; - glGenBuffers(1, &id); - return id; + u32 id; + glGenBuffers(1, &id); + return id; } StreamBuffer::StreamBuffer(u32 type, u32 size) - : m_buffer(GenBuffer()), m_buffertype(type), m_size(ROUND_UP_POW2(size)), m_bit_per_slot(IntLog2(ROUND_UP_POW2(size) / SYNC_POINTS)) + : m_buffer(GenBuffer()), m_buffertype(type), m_size(ROUND_UP_POW2(size)), + m_bit_per_slot(IntLog2(ROUND_UP_POW2(size) / SYNC_POINTS)) { - m_iterator = 0; - m_used_iterator = 0; - m_free_iterator = 0; + m_iterator = 0; + m_used_iterator = 0; + m_free_iterator = 0; } - StreamBuffer::~StreamBuffer() { - glDeleteBuffers(1, &m_buffer); + glDeleteBuffers(1, &m_buffer); } /* Shared synchronization code for ring buffers @@ -44,76 +43,79 @@ StreamBuffer::~StreamBuffer() * To reduce overhead, the complete buffer is splitted up into SYNC_POINTS chunks. * For each of this chunks, there is a fence which checks if this chunk is still in use. * - * As our API allows to alloc more memory then it has to use, we have to catch how much is already written. + * As our API allows to alloc more memory then it has to use, we have to catch how much is already + * written. * * m_iterator - writing position * m_free_iterator - last position checked if free * m_used_iterator - last position known to be written * - * So on alloc, we have to wait for all slots between m_free_iterator and m_iterator (and set m_free_iterator to m_iterator afterwards). + * So on alloc, we have to wait for all slots between m_free_iterator and m_iterator (and set + * m_free_iterator to m_iterator afterwards). * * We also assume that this buffer is accessed by the GPU between the Unmap and Map function, * so we may create the fences on the start of mapping. - * Some here, new fences for the chunks between m_used_iterator and m_iterator (also update m_used_iterator). + * Some here, new fences for the chunks between m_used_iterator and m_iterator (also update + * m_used_iterator). * * As ring buffers have an ugly behavior on rollover, have fun to read this code ;) */ void StreamBuffer::CreateFences() { - for (int i = 0; i < SYNC_POINTS; i++) - { - m_fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - } + for (int i = 0; i < SYNC_POINTS; i++) + { + m_fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + } } void StreamBuffer::DeleteFences() { - for (int i = Slot(m_free_iterator) + 1; i < SYNC_POINTS; i++) - { - glDeleteSync(m_fences[i]); - } - for (int i = 0; i < Slot(m_iterator); i++) - { - glDeleteSync(m_fences[i]); - } + for (int i = Slot(m_free_iterator) + 1; i < SYNC_POINTS; i++) + { + glDeleteSync(m_fences[i]); + } + for (int i = 0; i < Slot(m_iterator); i++) + { + glDeleteSync(m_fences[i]); + } } void StreamBuffer::AllocMemory(u32 size) { - // insert waiting slots for used memory - for (int i = Slot(m_used_iterator); i < Slot(m_iterator); i++) - { - m_fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - } - m_used_iterator = m_iterator; + // insert waiting slots for used memory + for (int i = Slot(m_used_iterator); i < Slot(m_iterator); i++) + { + m_fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + } + m_used_iterator = m_iterator; - // wait for new slots to end of buffer - for (int i = Slot(m_free_iterator) + 1; i <= Slot(m_iterator + size) && i < SYNC_POINTS; i++) - { - glClientWaitSync(m_fences[i], GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED); - glDeleteSync(m_fences[i]); - } - m_free_iterator = m_iterator + size; + // wait for new slots to end of buffer + for (int i = Slot(m_free_iterator) + 1; i <= Slot(m_iterator + size) && i < SYNC_POINTS; i++) + { + glClientWaitSync(m_fences[i], GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED); + glDeleteSync(m_fences[i]); + } + m_free_iterator = m_iterator + size; - // if buffer is full - if (m_iterator + size >= m_size) - { - // insert waiting slots in unused space at the end of the buffer - for (int i = Slot(m_used_iterator); i < SYNC_POINTS; i++) - { - m_fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - } + // if buffer is full + if (m_iterator + size >= m_size) + { + // insert waiting slots in unused space at the end of the buffer + for (int i = Slot(m_used_iterator); i < SYNC_POINTS; i++) + { + m_fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + } - // move to the start - m_used_iterator = m_iterator = 0; // offset 0 is always aligned + // move to the start + m_used_iterator = m_iterator = 0; // offset 0 is always aligned - // wait for space at the start - for (int i = 0; i <= Slot(m_iterator + size); i++) - { - glClientWaitSync(m_fences[i], GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED); - glDeleteSync(m_fences[i]); - } - m_free_iterator = m_iterator + size; - } + // wait for space at the start + for (int i = 0; i <= Slot(m_iterator + size); i++) + { + glClientWaitSync(m_fences[i], GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED); + glDeleteSync(m_fences[i]); + } + m_free_iterator = m_iterator + size; + } } /* The usual way to stream data to the GPU. @@ -126,34 +128,32 @@ void StreamBuffer::AllocMemory(u32 size) class MapAndOrphan : public StreamBuffer { public: - MapAndOrphan(u32 type, u32 size) : StreamBuffer(type, size) - { - glBindBuffer(m_buffertype, m_buffer); - glBufferData(m_buffertype, m_size, nullptr, GL_STREAM_DRAW); - } + MapAndOrphan(u32 type, u32 size) : StreamBuffer(type, size) + { + glBindBuffer(m_buffertype, m_buffer); + glBufferData(m_buffertype, m_size, nullptr, GL_STREAM_DRAW); + } - ~MapAndOrphan() - { - } + ~MapAndOrphan() {} + std::pair Map(u32 size) override + { + if (m_iterator + size >= m_size) + { + glBufferData(m_buffertype, m_size, nullptr, GL_STREAM_DRAW); + m_iterator = 0; + } + u8* pointer = (u8*)glMapBufferRange(m_buffertype, m_iterator, size, + GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | + GL_MAP_UNSYNCHRONIZED_BIT); + return std::make_pair(pointer, m_iterator); + } - std::pair Map(u32 size) override - { - if (m_iterator + size >= m_size) - { - glBufferData(m_buffertype, m_size, nullptr, GL_STREAM_DRAW); - m_iterator = 0; - } - u8* pointer = (u8*)glMapBufferRange(m_buffertype, m_iterator, size, - GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT); - return std::make_pair(pointer, m_iterator); - } - - void Unmap(u32 used_size) override - { - glFlushMappedBufferRange(m_buffertype, 0, used_size); - glUnmapBuffer(m_buffertype); - m_iterator += used_size; - } + void Unmap(u32 used_size) override + { + glFlushMappedBufferRange(m_buffertype, 0, used_size); + glUnmapBuffer(m_buffertype); + m_iterator += used_size; + } }; /* A modified streaming way without reallocation @@ -166,32 +166,29 @@ public: class MapAndSync : public StreamBuffer { public: - MapAndSync(u32 type, u32 size) : StreamBuffer(type, size) - { - CreateFences(); - glBindBuffer(m_buffertype, m_buffer); - glBufferData(m_buffertype, m_size, nullptr, GL_STREAM_DRAW); - } + MapAndSync(u32 type, u32 size) : StreamBuffer(type, size) + { + CreateFences(); + glBindBuffer(m_buffertype, m_buffer); + glBufferData(m_buffertype, m_size, nullptr, GL_STREAM_DRAW); + } - ~MapAndSync() - { - DeleteFences(); - } + ~MapAndSync() { DeleteFences(); } + std::pair Map(u32 size) override + { + AllocMemory(size); + u8* pointer = (u8*)glMapBufferRange(m_buffertype, m_iterator, size, + GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | + GL_MAP_UNSYNCHRONIZED_BIT); + return std::make_pair(pointer, m_iterator); + } - std::pair Map(u32 size) override - { - AllocMemory(size); - u8* pointer = (u8*)glMapBufferRange(m_buffertype, m_iterator, size, - GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT); - return std::make_pair(pointer, m_iterator); - } - - void Unmap(u32 used_size) override - { - glFlushMappedBufferRange(m_buffertype, 0, used_size); - glUnmapBuffer(m_buffertype); - m_iterator += used_size; - } + void Unmap(u32 used_size) override + { + glFlushMappedBufferRange(m_buffertype, 0, used_size); + glUnmapBuffer(m_buffertype); + m_iterator += used_size; + } }; /* Streaming fifo without mapping overhead. @@ -210,42 +207,45 @@ public: class BufferStorage : public StreamBuffer { public: - BufferStorage(u32 type, u32 size, bool _coherent = false) : StreamBuffer(type, size), coherent(_coherent) - { - CreateFences(); - glBindBuffer(m_buffertype, m_buffer); + BufferStorage(u32 type, u32 size, bool _coherent = false) + : StreamBuffer(type, size), coherent(_coherent) + { + CreateFences(); + glBindBuffer(m_buffertype, m_buffer); - // PERSISTANT_BIT to make sure that the buffer can be used while mapped - // COHERENT_BIT is set so we don't have to use a MemoryBarrier on write - // CLIENT_STORAGE_BIT is set since we access the buffer more frequently on the client side then server side - glBufferStorage(m_buffertype, m_size, nullptr, - GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (coherent ? GL_MAP_COHERENT_BIT : 0)); - m_pointer = (u8*)glMapBufferRange(m_buffertype, 0, m_size, - GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT)); - } + // PERSISTANT_BIT to make sure that the buffer can be used while mapped + // COHERENT_BIT is set so we don't have to use a MemoryBarrier on write + // CLIENT_STORAGE_BIT is set since we access the buffer more frequently on the client side then + // server side + glBufferStorage(m_buffertype, m_size, nullptr, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | + (coherent ? GL_MAP_COHERENT_BIT : 0)); + m_pointer = (u8*)glMapBufferRange( + m_buffertype, 0, m_size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | + (coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT)); + } - ~BufferStorage() - { - DeleteFences(); - glUnmapBuffer(m_buffertype); - glBindBuffer(m_buffertype, 0); - } + ~BufferStorage() + { + DeleteFences(); + glUnmapBuffer(m_buffertype); + glBindBuffer(m_buffertype, 0); + } - std::pair Map(u32 size) override - { - AllocMemory(size); - return std::make_pair(m_pointer + m_iterator, m_iterator); - } + std::pair Map(u32 size) override + { + AllocMemory(size); + return std::make_pair(m_pointer + m_iterator, m_iterator); + } - void Unmap(u32 used_size) override - { - if (!coherent) - glFlushMappedBufferRange(m_buffertype, m_iterator, used_size); - m_iterator += used_size; - } + void Unmap(u32 used_size) override + { + if (!coherent) + glFlushMappedBufferRange(m_buffertype, m_iterator, used_size); + m_iterator += used_size; + } - u8* m_pointer; - const bool coherent; + u8* m_pointer; + const bool coherent; }; /* --- AMD only --- @@ -258,38 +258,36 @@ public: class PinnedMemory : public StreamBuffer { public: - PinnedMemory(u32 type, u32 size) : StreamBuffer(type, size) - { - CreateFences(); - m_pointer = (u8*)AllocateAlignedMemory(ROUND_UP(m_size,ALIGN_PINNED_MEMORY), ALIGN_PINNED_MEMORY ); - glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_buffer); - glBufferData(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, ROUND_UP(m_size,ALIGN_PINNED_MEMORY), m_pointer, GL_STREAM_COPY); - glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0); - glBindBuffer(m_buffertype, m_buffer); - } + PinnedMemory(u32 type, u32 size) : StreamBuffer(type, size) + { + CreateFences(); + m_pointer = + (u8*)AllocateAlignedMemory(ROUND_UP(m_size, ALIGN_PINNED_MEMORY), ALIGN_PINNED_MEMORY); + glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_buffer); + glBufferData(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, ROUND_UP(m_size, ALIGN_PINNED_MEMORY), + m_pointer, GL_STREAM_COPY); + glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0); + glBindBuffer(m_buffertype, m_buffer); + } - ~PinnedMemory() - { - DeleteFences(); - glBindBuffer(m_buffertype, 0); - glFinish(); // ogl pipeline must be flushed, else this buffer can be in use - FreeAlignedMemory(m_pointer); - m_pointer = nullptr; - } + ~PinnedMemory() + { + DeleteFences(); + glBindBuffer(m_buffertype, 0); + glFinish(); // ogl pipeline must be flushed, else this buffer can be in use + FreeAlignedMemory(m_pointer); + m_pointer = nullptr; + } - std::pair Map(u32 size) override - { - AllocMemory(size); - return std::make_pair(m_pointer + m_iterator, m_iterator); - } + std::pair Map(u32 size) override + { + AllocMemory(size); + return std::make_pair(m_pointer + m_iterator, m_iterator); + } - void Unmap(u32 used_size) override - { - m_iterator += used_size; - } - - u8* m_pointer; - static const u32 ALIGN_PINNED_MEMORY = 4096; + void Unmap(u32 used_size) override { m_iterator += used_size; } + u8* m_pointer; + static const u32 ALIGN_PINNED_MEMORY = 4096; }; /* Fifo based on the glBufferSubData call. @@ -300,29 +298,17 @@ public: class BufferSubData : public StreamBuffer { public: - BufferSubData(u32 type, u32 size) : StreamBuffer(type, size) - { - glBindBuffer(m_buffertype, m_buffer); - glBufferData(m_buffertype, size, nullptr, GL_STATIC_DRAW); - m_pointer = new u8[m_size]; - } + BufferSubData(u32 type, u32 size) : StreamBuffer(type, size) + { + glBindBuffer(m_buffertype, m_buffer); + glBufferData(m_buffertype, size, nullptr, GL_STATIC_DRAW); + m_pointer = new u8[m_size]; + } - ~BufferSubData() - { - delete [] m_pointer; - } - - std::pair Map(u32 size) override - { - return std::make_pair(m_pointer, 0); - } - - void Unmap(u32 used_size) override - { - glBufferSubData(m_buffertype, 0, used_size, m_pointer); - } - - u8* m_pointer; + ~BufferSubData() { delete[] m_pointer; } + std::pair Map(u32 size) override { return std::make_pair(m_pointer, 0); } + void Unmap(u32 used_size) override { glBufferSubData(m_buffertype, 0, used_size, m_pointer); } + u8* m_pointer; }; /* Fifo based on the glBufferData call. @@ -333,69 +319,63 @@ public: class BufferData : public StreamBuffer { public: - BufferData(u32 type, u32 size) : StreamBuffer(type, size) - { - glBindBuffer(m_buffertype, m_buffer); - m_pointer = new u8[m_size]; - } + BufferData(u32 type, u32 size) : StreamBuffer(type, size) + { + glBindBuffer(m_buffertype, m_buffer); + m_pointer = new u8[m_size]; + } - ~BufferData() - { - delete [] m_pointer; - } + ~BufferData() { delete[] m_pointer; } + std::pair Map(u32 size) override { return std::make_pair(m_pointer, 0); } + void Unmap(u32 used_size) override + { + glBufferData(m_buffertype, used_size, m_pointer, GL_STREAM_DRAW); + } - std::pair Map(u32 size) override - { - return std::make_pair(m_pointer, 0); - } - - void Unmap(u32 used_size) override - { - glBufferData(m_buffertype, used_size, m_pointer, GL_STREAM_DRAW); - } - - u8* m_pointer; + u8* m_pointer; }; // Chooses the best streaming method based on the supported extensions and known issues std::unique_ptr StreamBuffer::Create(u32 type, u32 size) { - // without basevertex support, only streaming methods whith uploads everything to zero works fine: - if (!g_ogl_config.bSupportsGLBaseVertex) - { - if (!DriverDetails::HasBug(DriverDetails::BUG_BROKENBUFFERSTREAM)) - return std::make_unique(type, size); + // without basevertex support, only streaming methods whith uploads everything to zero works fine: + if (!g_ogl_config.bSupportsGLBaseVertex) + { + if (!DriverDetails::HasBug(DriverDetails::BUG_BROKENBUFFERSTREAM)) + return std::make_unique(type, size); - // BufferData is by far the worst way, only use it if needed - return std::make_unique(type, size); - } + // BufferData is by far the worst way, only use it if needed + return std::make_unique(type, size); + } - // Prefer the syncing buffers over the orphaning one - if (g_ogl_config.bSupportsGLSync) - { - // pinned memory is much faster than buffer storage on AMD cards - if (g_ogl_config.bSupportsGLPinnedMemory && - !(DriverDetails::HasBug(DriverDetails::BUG_BROKENPINNEDMEMORY) && type == GL_ELEMENT_ARRAY_BUFFER)) - return std::make_unique(type, size); + // Prefer the syncing buffers over the orphaning one + if (g_ogl_config.bSupportsGLSync) + { + // pinned memory is much faster than buffer storage on AMD cards + if (g_ogl_config.bSupportsGLPinnedMemory && + !(DriverDetails::HasBug(DriverDetails::BUG_BROKENPINNEDMEMORY) && + type == GL_ELEMENT_ARRAY_BUFFER)) + return std::make_unique(type, size); - // buffer storage works well in most situations - bool coherent = DriverDetails::HasBug(DriverDetails::BUG_BROKENEXPLICITFLUSH); - if (g_ogl_config.bSupportsGLBufferStorage && - !(DriverDetails::HasBug(DriverDetails::BUG_BROKENBUFFERSTORAGE) && type == GL_ARRAY_BUFFER) && - !(DriverDetails::HasBug(DriverDetails::BUG_INTELBROKENBUFFERSTORAGE) && type == GL_ELEMENT_ARRAY_BUFFER)) - return std::make_unique(type, size, coherent); + // buffer storage works well in most situations + bool coherent = DriverDetails::HasBug(DriverDetails::BUG_BROKENEXPLICITFLUSH); + if (g_ogl_config.bSupportsGLBufferStorage && + !(DriverDetails::HasBug(DriverDetails::BUG_BROKENBUFFERSTORAGE) && + type == GL_ARRAY_BUFFER) && + !(DriverDetails::HasBug(DriverDetails::BUG_INTELBROKENBUFFERSTORAGE) && + type == GL_ELEMENT_ARRAY_BUFFER)) + return std::make_unique(type, size, coherent); - // don't fall back to MapAnd* for Nvidia drivers - if (DriverDetails::HasBug(DriverDetails::BUG_BROKENUNSYNCMAPPING)) - return std::make_unique(type, size); + // don't fall back to MapAnd* for Nvidia drivers + if (DriverDetails::HasBug(DriverDetails::BUG_BROKENUNSYNCMAPPING)) + return std::make_unique(type, size); - // mapping fallback - if (g_ogl_config.bSupportsGLSync) - return std::make_unique(type, size); - } + // mapping fallback + if (g_ogl_config.bSupportsGLSync) + return std::make_unique(type, size); + } - // default fallback, should work everywhere, but isn't the best way to do this job - return std::make_unique(type, size); + // default fallback, should work everywhere, but isn't the best way to do this job + return std::make_unique(type, size); } - } diff --git a/Source/Core/VideoBackends/OGL/StreamBuffer.h b/Source/Core/VideoBackends/OGL/StreamBuffer.h index 4cb1c93703..864da268c9 100644 --- a/Source/Core/VideoBackends/OGL/StreamBuffer.h +++ b/Source/Core/VideoBackends/OGL/StreamBuffer.h @@ -16,56 +16,53 @@ namespace OGL { - class StreamBuffer { - public: - static std::unique_ptr Create(u32 type, u32 size); - virtual ~StreamBuffer(); + static std::unique_ptr Create(u32 type, u32 size); + virtual ~StreamBuffer(); - /* This mapping function will return a pair of: - * - the pointer to the mapped buffer - * - the offset into the real GPU buffer (always multiple of stride) - * On mapping, the maximum of size for allocation has to be set. - * The size really pushed into this fifo only has to be known on Unmapping. - * Mapping invalidates the current buffer content, - * so it isn't allowed to access the old content any more. - */ - virtual std::pair Map(u32 size) = 0; - virtual void Unmap(u32 used_size) = 0; + /* This mapping function will return a pair of: + * - the pointer to the mapped buffer + * - the offset into the real GPU buffer (always multiple of stride) + * On mapping, the maximum of size for allocation has to be set. + * The size really pushed into this fifo only has to be known on Unmapping. + * Mapping invalidates the current buffer content, + * so it isn't allowed to access the old content any more. + */ + virtual std::pair Map(u32 size) = 0; + virtual void Unmap(u32 used_size) = 0; - std::pair Map(u32 size, u32 stride) - { - u32 padding = m_iterator % stride; - if (padding) - { - m_iterator += stride - padding; - } - return Map(size); - } + std::pair Map(u32 size, u32 stride) + { + u32 padding = m_iterator % stride; + if (padding) + { + m_iterator += stride - padding; + } + return Map(size); + } - const u32 m_buffer; + const u32 m_buffer; protected: - StreamBuffer(u32 type, u32 size); - void CreateFences(); - void DeleteFences(); - void AllocMemory(u32 size); + StreamBuffer(u32 type, u32 size); + void CreateFences(); + void DeleteFences(); + void AllocMemory(u32 size); - const u32 m_buffertype; - const u32 m_size; + const u32 m_buffertype; + const u32 m_size; - u32 m_iterator; - u32 m_used_iterator; - u32 m_free_iterator; + u32 m_iterator; + u32 m_used_iterator; + u32 m_free_iterator; private: - static constexpr int SYNC_POINTS = 16; - int Slot(u32 x) const { return x >> m_bit_per_slot; } - const int m_bit_per_slot; + static constexpr int SYNC_POINTS = 16; + int Slot(u32 x) const { return x >> m_bit_per_slot; } + const int m_bit_per_slot; - std::array m_fences{}; + std::array m_fences{}; }; - } diff --git a/Source/Core/VideoBackends/OGL/TextureCache.cpp b/Source/Core/VideoBackends/OGL/TextureCache.cpp index 6cd9c50359..82d036a631 100644 --- a/Source/Core/VideoBackends/OGL/TextureCache.cpp +++ b/Source/Core/VideoBackends/OGL/TextureCache.cpp @@ -36,7 +36,6 @@ namespace OGL { - static SHADER s_ColorCopyProgram; static SHADER s_ColorMatrixProgram; static SHADER s_DepthMatrixProgram; @@ -58,270 +57,250 @@ static GLuint s_palette_buffer_offset_uniform[3]; static GLuint s_palette_multiplier_uniform[3]; static GLuint s_palette_copy_position_uniform[3]; -bool SaveTexture(const std::string& filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level) +bool SaveTexture(const std::string& filename, u32 textarget, u32 tex, int virtual_width, + int virtual_height, unsigned int level) { - if (GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL) - return false; - int width = std::max(virtual_width >> level, 1); - int height = std::max(virtual_height >> level, 1); - std::vector data(width * height * 4); - glActiveTexture(GL_TEXTURE9); - glBindTexture(textarget, tex); - glGetTexImage(textarget, level, GL_RGBA, GL_UNSIGNED_BYTE, data.data()); - TextureCache::SetStage(); + if (GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL) + return false; + int width = std::max(virtual_width >> level, 1); + int height = std::max(virtual_height >> level, 1); + std::vector data(width * height * 4); + glActiveTexture(GL_TEXTURE9); + glBindTexture(textarget, tex); + glGetTexImage(textarget, level, GL_RGBA, GL_UNSIGNED_BYTE, data.data()); + TextureCache::SetStage(); - return TextureToPng(data.data(), width * 4, filename, width, height, true); + return TextureToPng(data.data(), width * 4, filename, width, height, true); } TextureCache::TCacheEntry::~TCacheEntry() { - if (texture) - { - for (auto& gtex : s_Textures) - if (gtex == texture) - gtex = 0; - glDeleteTextures(1, &texture); - texture = 0; - } + if (texture) + { + for (auto& gtex : s_Textures) + if (gtex == texture) + gtex = 0; + glDeleteTextures(1, &texture); + texture = 0; + } - if (framebuffer) - { - glDeleteFramebuffers(1, &framebuffer); - framebuffer = 0; - } + if (framebuffer) + { + glDeleteFramebuffers(1, &framebuffer); + framebuffer = 0; + } } -TextureCache::TCacheEntry::TCacheEntry(const TCacheEntryConfig& _config) -: TCacheEntryBase(_config) +TextureCache::TCacheEntry::TCacheEntry(const TCacheEntryConfig& _config) : TCacheEntryBase(_config) { - glGenTextures(1, &texture); + glGenTextures(1, &texture); - framebuffer = 0; + framebuffer = 0; } void TextureCache::TCacheEntry::Bind(unsigned int stage) { - if (s_Textures[stage] != texture) - { - if (s_ActiveTexture != stage) - { - glActiveTexture(GL_TEXTURE0 + stage); - s_ActiveTexture = stage; - } + if (s_Textures[stage] != texture) + { + if (s_ActiveTexture != stage) + { + glActiveTexture(GL_TEXTURE0 + stage); + s_ActiveTexture = stage; + } - glBindTexture(GL_TEXTURE_2D_ARRAY, texture); - s_Textures[stage] = texture; - } + glBindTexture(GL_TEXTURE_2D_ARRAY, texture); + s_Textures[stage] = texture; + } } bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int level) { - return SaveTexture(filename, GL_TEXTURE_2D_ARRAY, texture, config.width, config.height, level); + return SaveTexture(filename, GL_TEXTURE_2D_ARRAY, texture, config.width, config.height, level); } TextureCache::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntryConfig& config) { - TCacheEntry* entry = new TCacheEntry(config); + TCacheEntry* entry = new TCacheEntry(config); - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D_ARRAY, entry->texture); + glActiveTexture(GL_TEXTURE9); + glBindTexture(GL_TEXTURE_2D_ARRAY, entry->texture); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, config.levels - 1); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, config.levels - 1); - if (config.rendertarget) - { - for (u32 level = 0; level <= config.levels; level++) - { - glTexImage3D(GL_TEXTURE_2D_ARRAY, level, GL_RGBA, config.width, config.height, config.layers, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - } - glGenFramebuffers(1, &entry->framebuffer); - FramebufferManager::SetFramebuffer(entry->framebuffer); - FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_ARRAY, entry->texture, 0); - } + if (config.rendertarget) + { + for (u32 level = 0; level <= config.levels; level++) + { + glTexImage3D(GL_TEXTURE_2D_ARRAY, level, GL_RGBA, config.width, config.height, config.layers, + 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + } + glGenFramebuffers(1, &entry->framebuffer); + FramebufferManager::SetFramebuffer(entry->framebuffer); + FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D_ARRAY, entry->texture, 0); + } - TextureCache::SetStage(); - return entry; + TextureCache::SetStage(); + return entry; } -void TextureCache::TCacheEntry::CopyRectangleFromTexture( - const TCacheEntryBase* source, - const MathUtil::Rectangle &srcrect, - const MathUtil::Rectangle &dstrect) +void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase* source, + const MathUtil::Rectangle& srcrect, + const MathUtil::Rectangle& dstrect) { - TCacheEntry* srcentry = (TCacheEntry*)source; - if (srcrect.GetWidth() == dstrect.GetWidth() - && srcrect.GetHeight() == dstrect.GetHeight() - && g_ogl_config.bSupportsCopySubImage) - { - glCopyImageSubData( - srcentry->texture, - GL_TEXTURE_2D_ARRAY, - 0, - srcrect.left, - srcrect.top, - 0, - texture, - GL_TEXTURE_2D_ARRAY, - 0, - dstrect.left, - dstrect.top, - 0, - dstrect.GetWidth(), - dstrect.GetHeight(), - srcentry->config.layers); - return; - } - else if (!framebuffer) - { - glGenFramebuffers(1, &framebuffer); - FramebufferManager::SetFramebuffer(framebuffer); - FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_ARRAY, texture, 0); - } - g_renderer->ResetAPIState(); - FramebufferManager::SetFramebuffer(framebuffer); - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D_ARRAY, srcentry->texture); - g_sampler_cache->BindLinearSampler(9); - glViewport(dstrect.left, dstrect.top, dstrect.GetWidth(), dstrect.GetHeight()); - s_ColorCopyProgram.Bind(); - glUniform4f(s_ColorCopyPositionUniform, - float(srcrect.left), - float(srcrect.top), - float(srcrect.GetWidth()), - float(srcrect.GetHeight())); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - FramebufferManager::SetFramebuffer(0); - g_renderer->RestoreAPIState(); + TCacheEntry* srcentry = (TCacheEntry*)source; + if (srcrect.GetWidth() == dstrect.GetWidth() && srcrect.GetHeight() == dstrect.GetHeight() && + g_ogl_config.bSupportsCopySubImage) + { + glCopyImageSubData(srcentry->texture, GL_TEXTURE_2D_ARRAY, 0, srcrect.left, srcrect.top, 0, + texture, GL_TEXTURE_2D_ARRAY, 0, dstrect.left, dstrect.top, 0, + dstrect.GetWidth(), dstrect.GetHeight(), srcentry->config.layers); + return; + } + else if (!framebuffer) + { + glGenFramebuffers(1, &framebuffer); + FramebufferManager::SetFramebuffer(framebuffer); + FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D_ARRAY, texture, 0); + } + g_renderer->ResetAPIState(); + FramebufferManager::SetFramebuffer(framebuffer); + glActiveTexture(GL_TEXTURE9); + glBindTexture(GL_TEXTURE_2D_ARRAY, srcentry->texture); + g_sampler_cache->BindLinearSampler(9); + glViewport(dstrect.left, dstrect.top, dstrect.GetWidth(), dstrect.GetHeight()); + s_ColorCopyProgram.Bind(); + glUniform4f(s_ColorCopyPositionUniform, float(srcrect.left), float(srcrect.top), + float(srcrect.GetWidth()), float(srcrect.GetHeight())); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + FramebufferManager::SetFramebuffer(0); + g_renderer->RestoreAPIState(); } void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int level) + unsigned int expanded_width, unsigned int level) { - if (level >= config.levels) - PanicAlert("Texture only has %d levels, can't update level %d", config.levels, level); - if (width != std::max(1u, config.width >> level) || height != std::max(1u, config.height >> level)) - PanicAlert("size of level %d must be %dx%d, but %dx%d requested", - level, std::max(1u, config.width >> level), std::max(1u, config.height >> level), width, height); + if (level >= config.levels) + PanicAlert("Texture only has %d levels, can't update level %d", config.levels, level); + if (width != std::max(1u, config.width >> level) || + height != std::max(1u, config.height >> level)) + PanicAlert("size of level %d must be %dx%d, but %dx%d requested", level, + std::max(1u, config.width >> level), std::max(1u, config.height >> level), width, + height); - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D_ARRAY, texture); + glActiveTexture(GL_TEXTURE9); + glBindTexture(GL_TEXTURE_2D_ARRAY, texture); - if (expanded_width != width) - glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width); + if (expanded_width != width) + glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width); - glTexImage3D(GL_TEXTURE_2D_ARRAY, level, GL_RGBA, width, height, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp); + glTexImage3D(GL_TEXTURE_2D_ARRAY, level, GL_RGBA, width, height, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, + temp); - if (expanded_width != width) - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + if (expanded_width != width) + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - TextureCache::SetStage(); + TextureCache::SetStage(); } -void TextureCache::TCacheEntry::FromRenderTarget(u8* dstPointer, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool scaleByHalf, unsigned int cbufid, const float *colmat) +void TextureCache::TCacheEntry::FromRenderTarget(u8* dstPointer, PEControl::PixelFormat srcFormat, + const EFBRectangle& srcRect, bool scaleByHalf, + unsigned int cbufid, const float* colmat) { - g_renderer->ResetAPIState(); // reset any game specific settings + g_renderer->ResetAPIState(); // reset any game specific settings - // Make sure to resolve anything we need to read from. - const GLuint read_texture = (srcFormat == PEControl::Z24) ? - FramebufferManager::ResolveAndGetDepthTarget(srcRect) : - FramebufferManager::ResolveAndGetRenderTarget(srcRect); + // Make sure to resolve anything we need to read from. + const GLuint read_texture = (srcFormat == PEControl::Z24) ? + FramebufferManager::ResolveAndGetDepthTarget(srcRect) : + FramebufferManager::ResolveAndGetRenderTarget(srcRect); - FramebufferManager::SetFramebuffer(framebuffer); + FramebufferManager::SetFramebuffer(framebuffer); - OpenGL_BindAttributelessVAO(); + OpenGL_BindAttributelessVAO(); - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D_ARRAY, read_texture); - if (scaleByHalf) - g_sampler_cache->BindLinearSampler(9); - else - g_sampler_cache->BindNearestSampler(9); + glActiveTexture(GL_TEXTURE9); + glBindTexture(GL_TEXTURE_2D_ARRAY, read_texture); + if (scaleByHalf) + g_sampler_cache->BindLinearSampler(9); + else + g_sampler_cache->BindNearestSampler(9); - glViewport(0, 0, config.width, config.height); + glViewport(0, 0, config.width, config.height); - GLuint uniform_location; - if (srcFormat == PEControl::Z24) - { - s_DepthMatrixProgram.Bind(); - if (s_DepthCbufid != cbufid) - glUniform4fv(s_DepthMatrixUniform, 5, colmat); - s_DepthCbufid = cbufid; - uniform_location = s_DepthCopyPositionUniform; - } - else - { - s_ColorMatrixProgram.Bind(); - if (s_ColorCbufid != cbufid) - glUniform4fv(s_ColorMatrixUniform, 7, colmat); - s_ColorCbufid = cbufid; - uniform_location = s_ColorMatrixPositionUniform; - } + GLuint uniform_location; + if (srcFormat == PEControl::Z24) + { + s_DepthMatrixProgram.Bind(); + if (s_DepthCbufid != cbufid) + glUniform4fv(s_DepthMatrixUniform, 5, colmat); + s_DepthCbufid = cbufid; + uniform_location = s_DepthCopyPositionUniform; + } + else + { + s_ColorMatrixProgram.Bind(); + if (s_ColorCbufid != cbufid) + glUniform4fv(s_ColorMatrixUniform, 7, colmat); + s_ColorCbufid = cbufid; + uniform_location = s_ColorMatrixPositionUniform; + } - TargetRectangle R = g_renderer->ConvertEFBRectangle(srcRect); - glUniform4f(uniform_location, static_cast(R.left), static_cast(R.top), - static_cast(R.right), static_cast(R.bottom)); + TargetRectangle R = g_renderer->ConvertEFBRectangle(srcRect); + glUniform4f(uniform_location, static_cast(R.left), static_cast(R.top), + static_cast(R.right), static_cast(R.bottom)); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - FramebufferManager::SetFramebuffer(0); - g_renderer->RestoreAPIState(); + FramebufferManager::SetFramebuffer(0); + g_renderer->RestoreAPIState(); } -void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool isIntensity, bool scaleByHalf) +void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, PEControl::PixelFormat srcFormat, + const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) { - TextureConverter::EncodeToRamFromTexture( - dst, - format, - native_width, - bytes_per_row, - num_blocks_y, - memory_stride, - srcFormat, - isIntensity, - scaleByHalf, - srcRect); + TextureConverter::EncodeToRamFromTexture(dst, format, native_width, bytes_per_row, num_blocks_y, + memory_stride, srcFormat, isIntensity, scaleByHalf, + srcRect); } TextureCache::TextureCache() { - CompileShaders(); + CompileShaders(); - s_ActiveTexture = -1; - for (auto& gtex : s_Textures) - gtex = -1; + s_ActiveTexture = -1; + for (auto& gtex : s_Textures) + gtex = -1; - if (g_ActiveConfig.backend_info.bSupportsPaletteConversion) - { - s32 buffer_size = 1024 * 1024; - s32 max_buffer_size = 0; + if (g_ActiveConfig.backend_info.bSupportsPaletteConversion) + { + s32 buffer_size = 1024 * 1024; + s32 max_buffer_size = 0; - // The minimum MAX_TEXTURE_BUFFER_SIZE that the spec mandates - // is 65KB, we are asking for a 1MB buffer here. - // Make sure to check the maximum size and if it is below 1MB - // then use the maximum the hardware supports instead. - glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &max_buffer_size); - buffer_size = std::min(buffer_size, max_buffer_size); + // The minimum MAX_TEXTURE_BUFFER_SIZE that the spec mandates + // is 65KB, we are asking for a 1MB buffer here. + // Make sure to check the maximum size and if it is below 1MB + // then use the maximum the hardware supports instead. + glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &max_buffer_size); + buffer_size = std::min(buffer_size, max_buffer_size); - s_palette_stream_buffer = StreamBuffer::Create(GL_TEXTURE_BUFFER, buffer_size); - glGenTextures(1, &s_palette_resolv_texture); - glBindTexture(GL_TEXTURE_BUFFER, s_palette_resolv_texture); - glTexBuffer(GL_TEXTURE_BUFFER, GL_R16UI, s_palette_stream_buffer->m_buffer); - } + s_palette_stream_buffer = StreamBuffer::Create(GL_TEXTURE_BUFFER, buffer_size); + glGenTextures(1, &s_palette_resolv_texture); + glBindTexture(GL_TEXTURE_BUFFER, s_palette_resolv_texture); + glTexBuffer(GL_TEXTURE_BUFFER, GL_R16UI, s_palette_stream_buffer->m_buffer); + } } - TextureCache::~TextureCache() { - DeleteShaders(); + DeleteShaders(); - if (g_ActiveConfig.backend_info.bSupportsPaletteConversion) - { - s_palette_stream_buffer.reset(); - glDeleteTextures(1, &s_palette_resolv_texture); - } + if (g_ActiveConfig.backend_info.bSupportsPaletteConversion) + { + s_palette_stream_buffer.reset(); + glDeleteTextures(1, &s_palette_resolv_texture); + } } void TextureCache::DisableStage(unsigned int stage) @@ -330,109 +309,117 @@ void TextureCache::DisableStage(unsigned int stage) void TextureCache::SetStage() { - // -1 is the initial value as we don't know which texture should be bound - if (s_ActiveTexture != (u32)-1) - glActiveTexture(GL_TEXTURE0 + s_ActiveTexture); + // -1 is the initial value as we don't know which texture should be bound + if (s_ActiveTexture != (u32)-1) + glActiveTexture(GL_TEXTURE0 + s_ActiveTexture); } void TextureCache::CompileShaders() { - constexpr const char* color_copy_program = - "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" - "in vec3 f_uv0;\n" - "out vec4 ocol0;\n" - "\n" - "void main(){\n" - " vec4 texcol = texture(samp9, f_uv0);\n" - " ocol0 = texcol;\n" - "}\n"; + constexpr const char* color_copy_program = "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" + "in vec3 f_uv0;\n" + "out vec4 ocol0;\n" + "\n" + "void main(){\n" + " vec4 texcol = texture(samp9, f_uv0);\n" + " ocol0 = texcol;\n" + "}\n"; - constexpr const char* color_matrix_program = - "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" - "uniform vec4 colmat[7];\n" - "in vec3 f_uv0;\n" - "out vec4 ocol0;\n" - "\n" - "void main(){\n" - " vec4 texcol = texture(samp9, f_uv0);\n" - " texcol = round(texcol * colmat[5]) * colmat[6];\n" - " ocol0 = texcol * mat4(colmat[0], colmat[1], colmat[2], colmat[3]) + colmat[4];\n" - "}\n"; + constexpr const char* color_matrix_program = + "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" + "uniform vec4 colmat[7];\n" + "in vec3 f_uv0;\n" + "out vec4 ocol0;\n" + "\n" + "void main(){\n" + " vec4 texcol = texture(samp9, f_uv0);\n" + " texcol = round(texcol * colmat[5]) * colmat[6];\n" + " ocol0 = texcol * mat4(colmat[0], colmat[1], colmat[2], colmat[3]) + colmat[4];\n" + "}\n"; - constexpr const char* depth_matrix_program = - "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" - "uniform vec4 colmat[5];\n" - "in vec3 f_uv0;\n" - "out vec4 ocol0;\n" - "\n" - "void main(){\n" - " vec4 texcol = texture(samp9, vec3(f_uv0.xy, %s));\n" - " int depth = int(texcol.x * 16777216.0);\n" + constexpr const char* depth_matrix_program = + "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" + "uniform vec4 colmat[5];\n" + "in vec3 f_uv0;\n" + "out vec4 ocol0;\n" + "\n" + "void main(){\n" + " vec4 texcol = texture(samp9, vec3(f_uv0.xy, %s));\n" + " int depth = int(texcol.x * 16777216.0);\n" - // Convert to Z24 format - " ivec4 workspace;\n" - " workspace.r = (depth >> 16) & 255;\n" - " workspace.g = (depth >> 8) & 255;\n" - " workspace.b = depth & 255;\n" + // Convert to Z24 format + " ivec4 workspace;\n" + " workspace.r = (depth >> 16) & 255;\n" + " workspace.g = (depth >> 8) & 255;\n" + " workspace.b = depth & 255;\n" - // Convert to Z4 format - " workspace.a = (depth >> 16) & 0xF0;\n" + // Convert to Z4 format + " workspace.a = (depth >> 16) & 0xF0;\n" - // Normalize components to [0.0..1.0] - " texcol = vec4(workspace) / 255.0;\n" + // Normalize components to [0.0..1.0] + " texcol = vec4(workspace) / 255.0;\n" - " ocol0 = texcol * mat4(colmat[0], colmat[1], colmat[2], colmat[3]) + colmat[4];\n" - "}\n"; + " ocol0 = texcol * mat4(colmat[0], colmat[1], colmat[2], colmat[3]) + colmat[4];\n" + "}\n"; - constexpr const char* vertex_program = - "out vec3 %s_uv0;\n" - "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" - "uniform vec4 copy_position;\n" // left, top, right, bottom - "void main()\n" - "{\n" - " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" - " %s_uv0 = vec3(mix(copy_position.xy, copy_position.zw, rawpos) / vec2(textureSize(samp9, 0).xy), 0.0);\n" - " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" - "}\n"; + constexpr const char* vertex_program = + "out vec3 %s_uv0;\n" + "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" + "uniform vec4 copy_position;\n" // left, top, right, bottom + "void main()\n" + "{\n" + " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" + " %s_uv0 = vec3(mix(copy_position.xy, copy_position.zw, rawpos) / vec2(textureSize(samp9, " + "0).xy), 0.0);\n" + " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" + "}\n"; - const std::string geo_program = g_ActiveConfig.iStereoMode > 0 ? - "layout(triangles) in;\n" - "layout(triangle_strip, max_vertices = 6) out;\n" - "in vec3 v_uv0[3];\n" - "out vec3 f_uv0;\n" - "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" - "void main()\n" - "{\n" - " int layers = textureSize(samp9, 0).z;\n" - " for (int layer = 0; layer < layers; ++layer) {\n" - " for (int i = 0; i < 3; ++i) {\n" - " f_uv0 = vec3(v_uv0[i].xy, layer);\n" - " gl_Position = gl_in[i].gl_Position;\n" - " gl_Layer = layer;\n" - " EmitVertex();\n" - " }\n" - " EndPrimitive();\n" - " }\n" - "}\n" : ""; + const std::string geo_program = g_ActiveConfig.iStereoMode > 0 ? + "layout(triangles) in;\n" + "layout(triangle_strip, max_vertices = 6) out;\n" + "in vec3 v_uv0[3];\n" + "out vec3 f_uv0;\n" + "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" + "void main()\n" + "{\n" + " int layers = textureSize(samp9, 0).z;\n" + " for (int layer = 0; layer < layers; ++layer) {\n" + " for (int i = 0; i < 3; ++i) {\n" + " f_uv0 = vec3(v_uv0[i].xy, layer);\n" + " gl_Position = gl_in[i].gl_Position;\n" + " gl_Layer = layer;\n" + " EmitVertex();\n" + " }\n" + " EndPrimitive();\n" + " }\n" + "}\n" : + ""; - const char* prefix = geo_program.empty() ? "f" : "v"; - const char* depth_layer = g_ActiveConfig.bStereoEFBMonoDepth ? "0.0" : "f_uv0.z"; + const char* prefix = geo_program.empty() ? "f" : "v"; + const char* depth_layer = g_ActiveConfig.bStereoEFBMonoDepth ? "0.0" : "f_uv0.z"; - ProgramShaderCache::CompileShader(s_ColorCopyProgram, StringFromFormat(vertex_program, prefix, prefix).c_str(), color_copy_program, geo_program); - ProgramShaderCache::CompileShader(s_ColorMatrixProgram, StringFromFormat(vertex_program, prefix, prefix).c_str(), color_matrix_program, geo_program); - ProgramShaderCache::CompileShader(s_DepthMatrixProgram, StringFromFormat(vertex_program, prefix, prefix).c_str(), StringFromFormat(depth_matrix_program, depth_layer).c_str(), geo_program); + ProgramShaderCache::CompileShader(s_ColorCopyProgram, + StringFromFormat(vertex_program, prefix, prefix).c_str(), + color_copy_program, geo_program); + ProgramShaderCache::CompileShader(s_ColorMatrixProgram, + StringFromFormat(vertex_program, prefix, prefix).c_str(), + color_matrix_program, geo_program); + ProgramShaderCache::CompileShader( + s_DepthMatrixProgram, StringFromFormat(vertex_program, prefix, prefix).c_str(), + StringFromFormat(depth_matrix_program, depth_layer).c_str(), geo_program); - s_ColorMatrixUniform = glGetUniformLocation(s_ColorMatrixProgram.glprogid, "colmat"); - s_DepthMatrixUniform = glGetUniformLocation(s_DepthMatrixProgram.glprogid, "colmat"); - s_ColorCbufid = -1; - s_DepthCbufid = -1; + s_ColorMatrixUniform = glGetUniformLocation(s_ColorMatrixProgram.glprogid, "colmat"); + s_DepthMatrixUniform = glGetUniformLocation(s_DepthMatrixProgram.glprogid, "colmat"); + s_ColorCbufid = -1; + s_DepthCbufid = -1; - s_ColorCopyPositionUniform = glGetUniformLocation(s_ColorCopyProgram.glprogid, "copy_position"); - s_ColorMatrixPositionUniform = glGetUniformLocation(s_ColorMatrixProgram.glprogid, "copy_position"); - s_DepthCopyPositionUniform = glGetUniformLocation(s_DepthMatrixProgram.glprogid, "copy_position"); + s_ColorCopyPositionUniform = glGetUniformLocation(s_ColorCopyProgram.glprogid, "copy_position"); + s_ColorMatrixPositionUniform = + glGetUniformLocation(s_ColorMatrixProgram.glprogid, "copy_position"); + s_DepthCopyPositionUniform = glGetUniformLocation(s_DepthMatrixProgram.glprogid, "copy_position"); - std::string palette_shader = - R"GLSL( + std::string palette_shader = + R"GLSL( uniform int texture_buffer_offset; uniform float multiplier; SAMPLER_BINDING(9) uniform sampler2DArray samp9; @@ -511,83 +498,88 @@ void TextureCache::CompileShaders() } )GLSL"; - if (g_ActiveConfig.backend_info.bSupportsPaletteConversion) - { - ProgramShaderCache::CompileShader( - s_palette_pixel_shader[GX_TL_IA8], - StringFromFormat(vertex_program, prefix, prefix), - "#define DECODE DecodePixel_IA8" + palette_shader, - geo_program); - s_palette_buffer_offset_uniform[GX_TL_IA8] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_IA8].glprogid, "texture_buffer_offset"); - s_palette_multiplier_uniform[GX_TL_IA8] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_IA8].glprogid, "multiplier"); - s_palette_copy_position_uniform[GX_TL_IA8] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_IA8].glprogid, "copy_position"); + if (g_ActiveConfig.backend_info.bSupportsPaletteConversion) + { + ProgramShaderCache::CompileShader( + s_palette_pixel_shader[GX_TL_IA8], StringFromFormat(vertex_program, prefix, prefix), + "#define DECODE DecodePixel_IA8" + palette_shader, geo_program); + s_palette_buffer_offset_uniform[GX_TL_IA8] = + glGetUniformLocation(s_palette_pixel_shader[GX_TL_IA8].glprogid, "texture_buffer_offset"); + s_palette_multiplier_uniform[GX_TL_IA8] = + glGetUniformLocation(s_palette_pixel_shader[GX_TL_IA8].glprogid, "multiplier"); + s_palette_copy_position_uniform[GX_TL_IA8] = + glGetUniformLocation(s_palette_pixel_shader[GX_TL_IA8].glprogid, "copy_position"); - ProgramShaderCache::CompileShader( - s_palette_pixel_shader[GX_TL_RGB565], - StringFromFormat(vertex_program, prefix, prefix), - "#define DECODE DecodePixel_RGB565" + palette_shader, - geo_program); - s_palette_buffer_offset_uniform[GX_TL_RGB565] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB565].glprogid, "texture_buffer_offset"); - s_palette_multiplier_uniform[GX_TL_RGB565] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB565].glprogid, "multiplier"); - s_palette_copy_position_uniform[GX_TL_RGB565] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB565].glprogid, "copy_position"); + ProgramShaderCache::CompileShader( + s_palette_pixel_shader[GX_TL_RGB565], StringFromFormat(vertex_program, prefix, prefix), + "#define DECODE DecodePixel_RGB565" + palette_shader, geo_program); + s_palette_buffer_offset_uniform[GX_TL_RGB565] = glGetUniformLocation( + s_palette_pixel_shader[GX_TL_RGB565].glprogid, "texture_buffer_offset"); + s_palette_multiplier_uniform[GX_TL_RGB565] = + glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB565].glprogid, "multiplier"); + s_palette_copy_position_uniform[GX_TL_RGB565] = + glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB565].glprogid, "copy_position"); - ProgramShaderCache::CompileShader( - s_palette_pixel_shader[GX_TL_RGB5A3], - StringFromFormat(vertex_program, prefix, prefix), - "#define DECODE DecodePixel_RGB5A3" + palette_shader, - geo_program); - s_palette_buffer_offset_uniform[GX_TL_RGB5A3] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB5A3].glprogid, "texture_buffer_offset"); - s_palette_multiplier_uniform[GX_TL_RGB5A3] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB5A3].glprogid, "multiplier"); - s_palette_copy_position_uniform[GX_TL_RGB5A3] = glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB5A3].glprogid, "copy_position"); - } + ProgramShaderCache::CompileShader( + s_palette_pixel_shader[GX_TL_RGB5A3], StringFromFormat(vertex_program, prefix, prefix), + "#define DECODE DecodePixel_RGB5A3" + palette_shader, geo_program); + s_palette_buffer_offset_uniform[GX_TL_RGB5A3] = glGetUniformLocation( + s_palette_pixel_shader[GX_TL_RGB5A3].glprogid, "texture_buffer_offset"); + s_palette_multiplier_uniform[GX_TL_RGB5A3] = + glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB5A3].glprogid, "multiplier"); + s_palette_copy_position_uniform[GX_TL_RGB5A3] = + glGetUniformLocation(s_palette_pixel_shader[GX_TL_RGB5A3].glprogid, "copy_position"); + } } void TextureCache::DeleteShaders() { - s_ColorMatrixProgram.Destroy(); - s_DepthMatrixProgram.Destroy(); + s_ColorMatrixProgram.Destroy(); + s_DepthMatrixProgram.Destroy(); - if (g_ActiveConfig.backend_info.bSupportsPaletteConversion) - for (auto& shader : s_palette_pixel_shader) - shader.Destroy(); + if (g_ActiveConfig.backend_info.bSupportsPaletteConversion) + for (auto& shader : s_palette_pixel_shader) + shader.Destroy(); } -void TextureCache::ConvertTexture(TCacheEntryBase* _entry, TCacheEntryBase* _unconverted, void* palette, TlutFormat format) +void TextureCache::ConvertTexture(TCacheEntryBase* _entry, TCacheEntryBase* _unconverted, + void* palette, TlutFormat format) { - if (!g_ActiveConfig.backend_info.bSupportsPaletteConversion) - return; + if (!g_ActiveConfig.backend_info.bSupportsPaletteConversion) + return; - g_renderer->ResetAPIState(); + g_renderer->ResetAPIState(); - TCacheEntry* entry = (TCacheEntry*) _entry; - TCacheEntry* unconverted = (TCacheEntry*) _unconverted; + TCacheEntry* entry = (TCacheEntry*)_entry; + TCacheEntry* unconverted = (TCacheEntry*)_unconverted; - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D_ARRAY, unconverted->texture); - g_sampler_cache->BindNearestSampler(9); + glActiveTexture(GL_TEXTURE9); + glBindTexture(GL_TEXTURE_2D_ARRAY, unconverted->texture); + g_sampler_cache->BindNearestSampler(9); - FramebufferManager::SetFramebuffer(entry->framebuffer); - glViewport(0, 0, entry->config.width, entry->config.height); - s_palette_pixel_shader[format].Bind(); + FramebufferManager::SetFramebuffer(entry->framebuffer); + glViewport(0, 0, entry->config.width, entry->config.height); + s_palette_pixel_shader[format].Bind(); - // C14 textures are currently unsupported - int size = (unconverted->format & 0xf) == GX_TF_I4 ? 32 : 512; - auto buffer = s_palette_stream_buffer->Map(size); - memcpy(buffer.first, palette, size); - s_palette_stream_buffer->Unmap(size); - glUniform1i(s_palette_buffer_offset_uniform[format], buffer.second / 2); - glUniform1f(s_palette_multiplier_uniform[format], (unconverted->format & 0xf) == 0 ? 15.0f : 255.0f); - glUniform4f(s_palette_copy_position_uniform[format], 0.0f, 0.0f, (float)unconverted->config.width, (float)unconverted->config.height); + // C14 textures are currently unsupported + int size = (unconverted->format & 0xf) == GX_TF_I4 ? 32 : 512; + auto buffer = s_palette_stream_buffer->Map(size); + memcpy(buffer.first, palette, size); + s_palette_stream_buffer->Unmap(size); + glUniform1i(s_palette_buffer_offset_uniform[format], buffer.second / 2); + glUniform1f(s_palette_multiplier_uniform[format], + (unconverted->format & 0xf) == 0 ? 15.0f : 255.0f); + glUniform4f(s_palette_copy_position_uniform[format], 0.0f, 0.0f, (float)unconverted->config.width, + (float)unconverted->config.height); - glActiveTexture(GL_TEXTURE10); - glBindTexture(GL_TEXTURE_BUFFER, s_palette_resolv_texture); - g_sampler_cache->BindNearestSampler(10); + glActiveTexture(GL_TEXTURE10); + glBindTexture(GL_TEXTURE_BUFFER, s_palette_resolv_texture); + g_sampler_cache->BindNearestSampler(10); - OpenGL_BindAttributelessVAO(); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + OpenGL_BindAttributelessVAO(); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - FramebufferManager::SetFramebuffer(0); - g_renderer->RestoreAPIState(); + FramebufferManager::SetFramebuffer(0); + g_renderer->RestoreAPIState(); } - } diff --git a/Source/Core/VideoBackends/OGL/TextureCache.h b/Source/Core/VideoBackends/OGL/TextureCache.h index 7c857da127..ecd9056127 100644 --- a/Source/Core/VideoBackends/OGL/TextureCache.h +++ b/Source/Core/VideoBackends/OGL/TextureCache.h @@ -14,54 +14,53 @@ namespace OGL { - class TextureCache : public TextureCacheBase { public: - TextureCache(); - ~TextureCache(); + TextureCache(); + ~TextureCache(); - static void DisableStage(unsigned int stage); - static void SetStage(); + static void DisableStage(unsigned int stage); + static void SetStage(); private: - struct TCacheEntry : TCacheEntryBase - { - GLuint texture; - GLuint framebuffer; + struct TCacheEntry : TCacheEntryBase + { + GLuint texture; + GLuint framebuffer; - //TexMode0 mode; // current filter and clamp modes that texture is set to - //TexMode1 mode1; // current filter and clamp modes that texture is set to + // TexMode0 mode; // current filter and clamp modes that texture is set to + // TexMode1 mode1; // current filter and clamp modes that texture is set to - TCacheEntry(const TCacheEntryConfig& config); - ~TCacheEntry(); + TCacheEntry(const TCacheEntryConfig& config); + ~TCacheEntry(); - void CopyRectangleFromTexture( - const TCacheEntryBase* source, - const MathUtil::Rectangle &srcrect, - const MathUtil::Rectangle &dstrect) override; + void CopyRectangleFromTexture(const TCacheEntryBase* source, + const MathUtil::Rectangle& srcrect, + const MathUtil::Rectangle& dstrect) override; - void Load(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int level) override; + void Load(unsigned int width, unsigned int height, unsigned int expanded_width, + unsigned int level) override; - void FromRenderTarget(u8 *dst, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool scaleByHalf, unsigned int cbufid, const float *colmat) override; + void FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, + bool scaleByHalf, unsigned int cbufid, const float* colmat) override; - void Bind(unsigned int stage) override; - bool Save(const std::string& filename, unsigned int level) override; - }; + void Bind(unsigned int stage) override; + bool Save(const std::string& filename, unsigned int level) override; + }; - TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) override; - void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format) override; + TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) override; + void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, + TlutFormat format) override; - void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool isIntensity, bool scaleByHalf) override; + void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, + u32 memory_stride, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, + bool isIntensity, bool scaleByHalf) override; - void CompileShaders() override; - void DeleteShaders() override; + void CompileShaders() override; + void DeleteShaders() override; }; -bool SaveTexture(const std::string& filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level); - +bool SaveTexture(const std::string& filename, u32 textarget, u32 tex, int virtual_width, + int virtual_height, unsigned int level); } diff --git a/Source/Core/VideoBackends/OGL/TextureConverter.cpp b/Source/Core/VideoBackends/OGL/TextureConverter.cpp index b56b08ab4f..456992d3cf 100644 --- a/Source/Core/VideoBackends/OGL/TextureConverter.cpp +++ b/Source/Core/VideoBackends/OGL/TextureConverter.cpp @@ -24,18 +24,15 @@ #include "VideoCommon/TextureConversionShader.h" #include "VideoCommon/VideoConfig.h" - namespace OGL { - namespace TextureConverter { - using OGL::TextureCache; -static GLuint s_texConvFrameBuffer[2] = {0,0}; -static GLuint s_srcTexture = 0; // for decoding from RAM -static GLuint s_dstTexture = 0; // for encoding to RAM +static GLuint s_texConvFrameBuffer[2] = {0, 0}; +static GLuint s_srcTexture = 0; // for decoding from RAM +static GLuint s_dstTexture = 0; // for encoding to RAM const int renderBufferWidth = EFB_WIDTH * 4; const int renderBufferHeight = 1024; @@ -50,301 +47,305 @@ const u32 NUM_ENCODING_PROGRAMS = 64; static SHADER s_encodingPrograms[NUM_ENCODING_PROGRAMS]; static int s_encodingUniforms[NUM_ENCODING_PROGRAMS]; -static GLuint s_PBO = 0; // for readback with different strides +static GLuint s_PBO = 0; // for readback with different strides static void CreatePrograms() { - /* TODO: Accuracy Improvements - * - * This shader doesn't really match what the GameCube does internally in the - * copy pipeline. - * 1. It uses OpenGL's built in filtering when yscaling, someone could work - * out how the copypipeline does it's filtering and implement it correctly - * in this shader. - * 2. Deflickering isn't implemented, a futher filtering over 3 lines. - * Isn't really needed on non-interlaced monitors (and would lower quality; - * But hey, accuracy!) - * 3. Flipper's YUYV conversion implements a 3 pixel horizontal blur on the - * UV channels, centering the U channel on the Left pixel and the V channel - * on the Right pixel. - * The current implementation Centers both UV channels at the same place - * inbetween the two Pixels, and only blurs over these two pixels. - */ - // Output is BGRA because that is slightly faster than RGBA. - const char *VProgramRgbToYuyv = - "out vec2 uv0;\n" - "uniform vec4 copy_position;\n" // left, top, right, bottom - "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" - "void main()\n" - "{\n" - " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" - " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" - " uv0 = mix(copy_position.xy, copy_position.zw, rawpos) / vec2(textureSize(samp9, 0).xy);\n" - "}\n"; - const char *FProgramRgbToYuyv = - "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" - "in vec2 uv0;\n" - "out vec4 ocol0;\n" - "void main()\n" - "{\n" - " vec3 c0 = texture(samp9, vec3(uv0 - dFdx(uv0) * 0.25, 0.0)).rgb;\n" - " vec3 c1 = texture(samp9, vec3(uv0 + dFdx(uv0) * 0.25, 0.0)).rgb;\n" - " vec3 c01 = (c0 + c1) * 0.5;\n" - " vec3 y_const = vec3(0.257,0.504,0.098);\n" - " vec3 u_const = vec3(-0.148,-0.291,0.439);\n" - " vec3 v_const = vec3(0.439,-0.368,-0.071);\n" - " vec4 const3 = vec4(0.0625,0.5,0.0625,0.5);\n" - " ocol0 = vec4(dot(c1,y_const),dot(c01,u_const),dot(c0,y_const),dot(c01, v_const)) + const3;\n" - "}\n"; - ProgramShaderCache::CompileShader(s_rgbToYuyvProgram, VProgramRgbToYuyv, FProgramRgbToYuyv); - s_rgbToYuyvUniform_loc = glGetUniformLocation(s_rgbToYuyvProgram.glprogid, "copy_position"); + /* TODO: Accuracy Improvements + * + * This shader doesn't really match what the GameCube does internally in the + * copy pipeline. + * 1. It uses OpenGL's built in filtering when yscaling, someone could work + * out how the copypipeline does it's filtering and implement it correctly + * in this shader. + * 2. Deflickering isn't implemented, a futher filtering over 3 lines. + * Isn't really needed on non-interlaced monitors (and would lower quality; + * But hey, accuracy!) + * 3. Flipper's YUYV conversion implements a 3 pixel horizontal blur on the + * UV channels, centering the U channel on the Left pixel and the V channel + * on the Right pixel. + * The current implementation Centers both UV channels at the same place + * inbetween the two Pixels, and only blurs over these two pixels. + */ + // Output is BGRA because that is slightly faster than RGBA. + const char* VProgramRgbToYuyv = + "out vec2 uv0;\n" + "uniform vec4 copy_position;\n" // left, top, right, bottom + "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" + "void main()\n" + "{\n" + " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" + " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" + " uv0 = mix(copy_position.xy, copy_position.zw, rawpos) / vec2(textureSize(samp9, 0).xy);\n" + "}\n"; + const char* FProgramRgbToYuyv = + "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" + "in vec2 uv0;\n" + "out vec4 ocol0;\n" + "void main()\n" + "{\n" + " vec3 c0 = texture(samp9, vec3(uv0 - dFdx(uv0) * 0.25, 0.0)).rgb;\n" + " vec3 c1 = texture(samp9, vec3(uv0 + dFdx(uv0) * 0.25, 0.0)).rgb;\n" + " vec3 c01 = (c0 + c1) * 0.5;\n" + " vec3 y_const = vec3(0.257,0.504,0.098);\n" + " vec3 u_const = vec3(-0.148,-0.291,0.439);\n" + " vec3 v_const = vec3(0.439,-0.368,-0.071);\n" + " vec4 const3 = vec4(0.0625,0.5,0.0625,0.5);\n" + " ocol0 = vec4(dot(c1,y_const),dot(c01,u_const),dot(c0,y_const),dot(c01, v_const)) + " + "const3;\n" + "}\n"; + ProgramShaderCache::CompileShader(s_rgbToYuyvProgram, VProgramRgbToYuyv, FProgramRgbToYuyv); + s_rgbToYuyvUniform_loc = glGetUniformLocation(s_rgbToYuyvProgram.glprogid, "copy_position"); - /* TODO: Accuracy Improvements - * - * The YVYU to RGB conversion here matches the RGB to YUYV done above, but - * if a game modifies or adds images to the XFB then it should be using the - * same algorithm as the flipper, and could result in slight color inaccuracies - * when run back through this shader. - */ - const char *VProgramYuyvToRgb = - "void main()\n" - "{\n" - " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" - " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" - "}\n"; - const char *FProgramYuyvToRgb = - "SAMPLER_BINDING(9) uniform sampler2D samp9;\n" - "in vec2 uv0;\n" - "out vec4 ocol0;\n" - "void main()\n" - "{\n" - " ivec2 uv = ivec2(gl_FragCoord.xy);\n" - // We switch top/bottom here. TODO: move this to screen blit. - " ivec2 ts = textureSize(samp9, 0);\n" - " vec4 c0 = texelFetch(samp9, ivec2(uv.x>>1, ts.y-uv.y-1), 0);\n" - " float y = mix(c0.r, c0.b, (uv.x & 1) == 1);\n" - " float yComp = 1.164 * (y - 0.0625);\n" - " float uComp = c0.g - 0.5;\n" - " float vComp = c0.a - 0.5;\n" - " ocol0 = vec4(yComp + (1.596 * vComp),\n" - " yComp - (0.813 * vComp) - (0.391 * uComp),\n" - " yComp + (2.018 * uComp),\n" - " 1.0);\n" - "}\n"; - ProgramShaderCache::CompileShader(s_yuyvToRgbProgram, VProgramYuyvToRgb, FProgramYuyvToRgb); + /* TODO: Accuracy Improvements + * + * The YVYU to RGB conversion here matches the RGB to YUYV done above, but + * if a game modifies or adds images to the XFB then it should be using the + * same algorithm as the flipper, and could result in slight color inaccuracies + * when run back through this shader. + */ + const char* VProgramYuyvToRgb = "void main()\n" + "{\n" + " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" + " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" + "}\n"; + const char* FProgramYuyvToRgb = "SAMPLER_BINDING(9) uniform sampler2D samp9;\n" + "in vec2 uv0;\n" + "out vec4 ocol0;\n" + "void main()\n" + "{\n" + " ivec2 uv = ivec2(gl_FragCoord.xy);\n" + // We switch top/bottom here. TODO: move this to screen blit. + " ivec2 ts = textureSize(samp9, 0);\n" + " vec4 c0 = texelFetch(samp9, ivec2(uv.x>>1, ts.y-uv.y-1), 0);\n" + " float y = mix(c0.r, c0.b, (uv.x & 1) == 1);\n" + " float yComp = 1.164 * (y - 0.0625);\n" + " float uComp = c0.g - 0.5;\n" + " float vComp = c0.a - 0.5;\n" + " ocol0 = vec4(yComp + (1.596 * vComp),\n" + " yComp - (0.813 * vComp) - (0.391 * uComp),\n" + " yComp + (2.018 * uComp),\n" + " 1.0);\n" + "}\n"; + ProgramShaderCache::CompileShader(s_yuyvToRgbProgram, VProgramYuyvToRgb, FProgramYuyvToRgb); } -static SHADER &GetOrCreateEncodingShader(u32 format) +static SHADER& GetOrCreateEncodingShader(u32 format) { - if (format >= NUM_ENCODING_PROGRAMS) - { - PanicAlert("Unknown texture copy format: 0x%x\n", format); - return s_encodingPrograms[0]; - } + if (format >= NUM_ENCODING_PROGRAMS) + { + PanicAlert("Unknown texture copy format: 0x%x\n", format); + return s_encodingPrograms[0]; + } - if (s_encodingPrograms[format].glprogid == 0) - { - const char* shader = TextureConversionShader::GenerateEncodingShader(format, API_OPENGL); + if (s_encodingPrograms[format].glprogid == 0) + { + const char* shader = TextureConversionShader::GenerateEncodingShader(format, API_OPENGL); #if defined(_DEBUG) || defined(DEBUGFAST) - if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader) - { - static int counter = 0; - std::string filename = StringFromFormat("%senc_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); + if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader) + { + static int counter = 0; + std::string filename = + StringFromFormat("%senc_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); - SaveData(filename, shader); - } + SaveData(filename, shader); + } #endif - const char *VProgram = - "void main()\n" - "{\n" - " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" - " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" - "}\n"; + const char* VProgram = "void main()\n" + "{\n" + " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" + " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" + "}\n"; - ProgramShaderCache::CompileShader(s_encodingPrograms[format], VProgram, shader); + ProgramShaderCache::CompileShader(s_encodingPrograms[format], VProgram, shader); - s_encodingUniforms[format] = glGetUniformLocation(s_encodingPrograms[format].glprogid, "position"); - } - return s_encodingPrograms[format]; + s_encodingUniforms[format] = + glGetUniformLocation(s_encodingPrograms[format].glprogid, "position"); + } + return s_encodingPrograms[format]; } void Init() { - glGenFramebuffers(2, s_texConvFrameBuffer); + glGenFramebuffers(2, s_texConvFrameBuffer); - glActiveTexture(GL_TEXTURE9); - glGenTextures(1, &s_srcTexture); - glBindTexture(GL_TEXTURE_2D, s_srcTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glActiveTexture(GL_TEXTURE9); + glGenTextures(1, &s_srcTexture); + glBindTexture(GL_TEXTURE_2D, s_srcTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glGenTextures(1, &s_dstTexture); - glBindTexture(GL_TEXTURE_2D, s_dstTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, renderBufferWidth, renderBufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glGenTextures(1, &s_dstTexture); + glBindTexture(GL_TEXTURE_2D, s_dstTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, renderBufferWidth, renderBufferHeight, 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr); + FramebufferManager::SetFramebuffer(s_texConvFrameBuffer[0]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s_dstTexture, 0); + FramebufferManager::SetFramebuffer(0); - FramebufferManager::SetFramebuffer(s_texConvFrameBuffer[0]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s_dstTexture, 0); - FramebufferManager::SetFramebuffer(0); + glGenBuffers(1, &s_PBO); - glGenBuffers(1, &s_PBO); - - CreatePrograms(); + CreatePrograms(); } void Shutdown() { - glDeleteTextures(1, &s_srcTexture); - glDeleteTextures(1, &s_dstTexture); - glDeleteBuffers(1, &s_PBO); - glDeleteFramebuffers(2, s_texConvFrameBuffer); + glDeleteTextures(1, &s_srcTexture); + glDeleteTextures(1, &s_dstTexture); + glDeleteBuffers(1, &s_PBO); + glDeleteFramebuffers(2, s_texConvFrameBuffer); - s_rgbToYuyvProgram.Destroy(); - s_yuyvToRgbProgram.Destroy(); + s_rgbToYuyvProgram.Destroy(); + s_yuyvToRgbProgram.Destroy(); - for (auto& program : s_encodingPrograms) - program.Destroy(); + for (auto& program : s_encodingPrograms) + program.Destroy(); - s_srcTexture = 0; - s_dstTexture = 0; - s_PBO = 0; - s_texConvFrameBuffer[0] = 0; - s_texConvFrameBuffer[1] = 0; + s_srcTexture = 0; + s_dstTexture = 0; + s_PBO = 0; + s_texConvFrameBuffer[0] = 0; + s_texConvFrameBuffer[1] = 0; } // dst_line_size, writeStride in bytes -static void EncodeToRamUsingShader(GLuint srcTexture, - u8* destAddr, u32 dst_line_size, u32 dstHeight, - u32 writeStride, bool linearFilter) +static void EncodeToRamUsingShader(GLuint srcTexture, u8* destAddr, u32 dst_line_size, + u32 dstHeight, u32 writeStride, bool linearFilter) { - // switch to texture converter frame buffer - // attach render buffer as color destination - FramebufferManager::SetFramebuffer(s_texConvFrameBuffer[0]); + // switch to texture converter frame buffer + // attach render buffer as color destination + FramebufferManager::SetFramebuffer(s_texConvFrameBuffer[0]); - OpenGL_BindAttributelessVAO(); + OpenGL_BindAttributelessVAO(); - // set source texture - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D_ARRAY, srcTexture); + // set source texture + glActiveTexture(GL_TEXTURE9); + glBindTexture(GL_TEXTURE_2D_ARRAY, srcTexture); - if (linearFilter) - g_sampler_cache->BindLinearSampler(9); - else - g_sampler_cache->BindNearestSampler(9); + if (linearFilter) + g_sampler_cache->BindLinearSampler(9); + else + g_sampler_cache->BindNearestSampler(9); - glViewport(0, 0, (GLsizei)(dst_line_size / 4), (GLsizei)dstHeight); + glViewport(0, 0, (GLsizei)(dst_line_size / 4), (GLsizei)dstHeight); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - int dstSize = dst_line_size * dstHeight; + int dstSize = dst_line_size * dstHeight; - if ((writeStride != dst_line_size) && (dstHeight > 1)) - { - // writing to a texture of a different size - // also copy more then one block line, so the different strides matters - // copy into one pbo first, map this buffer, and then memcpy into GC memory - // in this way, we only have one vram->ram transfer, but maybe a bigger - // CPU overhead because of the pbo - glBindBuffer(GL_PIXEL_PACK_BUFFER, s_PBO); - glBufferData(GL_PIXEL_PACK_BUFFER, dstSize, nullptr, GL_STREAM_READ); - glReadPixels(0, 0, (GLsizei)(dst_line_size / 4), (GLsizei)dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, nullptr); - u8* pbo = (u8*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, dstSize, GL_MAP_READ_BIT); + if ((writeStride != dst_line_size) && (dstHeight > 1)) + { + // writing to a texture of a different size + // also copy more then one block line, so the different strides matters + // copy into one pbo first, map this buffer, and then memcpy into GC memory + // in this way, we only have one vram->ram transfer, but maybe a bigger + // CPU overhead because of the pbo + glBindBuffer(GL_PIXEL_PACK_BUFFER, s_PBO); + glBufferData(GL_PIXEL_PACK_BUFFER, dstSize, nullptr, GL_STREAM_READ); + glReadPixels(0, 0, (GLsizei)(dst_line_size / 4), (GLsizei)dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, + nullptr); + u8* pbo = (u8*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, dstSize, GL_MAP_READ_BIT); - for (size_t i = 0; i < dstHeight; ++i) - { - memcpy(destAddr, pbo, dst_line_size); - pbo += dst_line_size; - destAddr += writeStride; - } + for (size_t i = 0; i < dstHeight; ++i) + { + memcpy(destAddr, pbo, dst_line_size); + pbo += dst_line_size; + destAddr += writeStride; + } - glUnmapBuffer(GL_PIXEL_PACK_BUFFER); - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - } - else - { - glReadPixels(0, 0, (GLsizei)(dst_line_size / 4), (GLsizei)dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, destAddr); - } + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + } + else + { + glReadPixels(0, 0, (GLsizei)(dst_line_size / 4), (GLsizei)dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, + destAddr); + } } -void EncodeToRamFromTexture(u8* dest_ptr, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat srcFormat, bool bIsIntensityFmt, int bScaleByHalf, const EFBRectangle& source) +void EncodeToRamFromTexture(u8* dest_ptr, u32 format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, PEControl::PixelFormat srcFormat, + bool bIsIntensityFmt, int bScaleByHalf, const EFBRectangle& source) { - g_renderer->ResetAPIState(); + g_renderer->ResetAPIState(); - SHADER& texconv_shader = GetOrCreateEncodingShader(format); + SHADER& texconv_shader = GetOrCreateEncodingShader(format); - texconv_shader.Bind(); - glUniform4i(s_encodingUniforms[format], - source.left, source.top, native_width, bScaleByHalf ? 2 : 1); + texconv_shader.Bind(); + glUniform4i(s_encodingUniforms[format], source.left, source.top, native_width, + bScaleByHalf ? 2 : 1); - const GLuint read_texture = (srcFormat == PEControl::Z24) ? - FramebufferManager::ResolveAndGetDepthTarget(source) : - FramebufferManager::ResolveAndGetRenderTarget(source); + const GLuint read_texture = (srcFormat == PEControl::Z24) ? + FramebufferManager::ResolveAndGetDepthTarget(source) : + FramebufferManager::ResolveAndGetRenderTarget(source); - EncodeToRamUsingShader(read_texture, - dest_ptr, bytes_per_row, num_blocks_y, - memory_stride, bScaleByHalf > 0 && srcFormat != PEControl::Z24); + EncodeToRamUsingShader(read_texture, dest_ptr, bytes_per_row, num_blocks_y, memory_stride, + bScaleByHalf > 0 && srcFormat != PEControl::Z24); - FramebufferManager::SetFramebuffer(0); - g_renderer->RestoreAPIState(); + FramebufferManager::SetFramebuffer(0); + g_renderer->RestoreAPIState(); } -void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* destAddr, u32 dstWidth, u32 dstStride, u32 dstHeight) +void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* destAddr, u32 dstWidth, + u32 dstStride, u32 dstHeight) { - g_renderer->ResetAPIState(); + g_renderer->ResetAPIState(); - s_rgbToYuyvProgram.Bind(); + s_rgbToYuyvProgram.Bind(); - glUniform4f(s_rgbToYuyvUniform_loc, static_cast(sourceRc.left), static_cast(sourceRc.top), - static_cast(sourceRc.right), static_cast(sourceRc.bottom)); + glUniform4f(s_rgbToYuyvUniform_loc, static_cast(sourceRc.left), + static_cast(sourceRc.top), static_cast(sourceRc.right), + static_cast(sourceRc.bottom)); - // We enable linear filtering, because the GameCube does filtering in the vertical direction when - // yscale is enabled. - // Otherwise we get jaggies when a game uses yscaling (most PAL games) - EncodeToRamUsingShader(srcTexture, destAddr, dstWidth * 2, dstHeight, dstStride, true); - FramebufferManager::SetFramebuffer(0); - TextureCache::DisableStage(0); - g_renderer->RestoreAPIState(); + // We enable linear filtering, because the GameCube does filtering in the vertical direction when + // yscale is enabled. + // Otherwise we get jaggies when a game uses yscaling (most PAL games) + EncodeToRamUsingShader(srcTexture, destAddr, dstWidth * 2, dstHeight, dstStride, true); + FramebufferManager::SetFramebuffer(0); + TextureCache::DisableStage(0); + g_renderer->RestoreAPIState(); } - // Should be scale free. void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture) { - u8* srcAddr = Memory::GetPointer(xfbAddr); - if (!srcAddr) - { - WARN_LOG(VIDEO, "Tried to decode from invalid memory address"); - return; - } + u8* srcAddr = Memory::GetPointer(xfbAddr); + if (!srcAddr) + { + WARN_LOG(VIDEO, "Tried to decode from invalid memory address"); + return; + } - g_renderer->ResetAPIState(); // reset any game specific settings + g_renderer->ResetAPIState(); // reset any game specific settings - OpenGL_BindAttributelessVAO(); + OpenGL_BindAttributelessVAO(); - // switch to texture converter frame buffer - // attach destTexture as color destination - FramebufferManager::SetFramebuffer(s_texConvFrameBuffer[1]); - FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_ARRAY, destTexture, 0); + // switch to texture converter frame buffer + // attach destTexture as color destination + FramebufferManager::SetFramebuffer(s_texConvFrameBuffer[1]); + FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_ARRAY, + destTexture, 0); - // activate source texture - // set srcAddr as data for source texture - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D, s_srcTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, srcWidth / 2, srcHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, srcAddr); - g_sampler_cache->BindNearestSampler(9); + // activate source texture + // set srcAddr as data for source texture + glActiveTexture(GL_TEXTURE9); + glBindTexture(GL_TEXTURE_2D, s_srcTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, srcWidth / 2, srcHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, + srcAddr); + g_sampler_cache->BindNearestSampler(9); - glViewport(0, 0, srcWidth, srcHeight); - s_yuyvToRgbProgram.Bind(); + glViewport(0, 0, srcWidth, srcHeight); + s_yuyvToRgbProgram.Bind(); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - FramebufferManager::SetFramebuffer(0); + FramebufferManager::SetFramebuffer(0); - g_renderer->RestoreAPIState(); + g_renderer->RestoreAPIState(); } } // namespace diff --git a/Source/Core/VideoBackends/OGL/TextureConverter.h b/Source/Core/VideoBackends/OGL/TextureConverter.h index 5fdb46e92f..734fb247ab 100644 --- a/Source/Core/VideoBackends/OGL/TextureConverter.h +++ b/Source/Core/VideoBackends/OGL/TextureConverter.h @@ -11,24 +11,22 @@ namespace OGL { - // Converts textures between formats using shaders // TODO: support multiple texture formats namespace TextureConverter { - void Init(); void Shutdown(); -void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, - u8* destAddr, u32 dstWidth, u32 dstStride, u32 dstHeight); +void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* destAddr, u32 dstWidth, + u32 dstStride, u32 dstHeight); void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture); // returns size of the encoded data (in bytes) -void EncodeToRamFromTexture(u8* dest_ptr, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat srcFormat, bool bIsIntensityFmt, int bScaleByHalf, const EFBRectangle& source); - +void EncodeToRamFromTexture(u8* dest_ptr, u32 format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, PEControl::PixelFormat srcFormat, + bool bIsIntensityFmt, int bScaleByHalf, const EFBRectangle& source); } } // namespace OGL diff --git a/Source/Core/VideoBackends/OGL/VertexManager.cpp b/Source/Core/VideoBackends/OGL/VertexManager.cpp index d15de83df3..04b83dc893 100644 --- a/Source/Core/VideoBackends/OGL/VertexManager.cpp +++ b/Source/Core/VideoBackends/OGL/VertexManager.cpp @@ -9,8 +9,8 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/StringUtil.h" #include "Common/GL/GLExtensions/GLExtensions.h" +#include "Common/StringUtil.h" #include "VideoBackends/OGL/ProgramShaderCache.h" #include "VideoBackends/OGL/Render.h" @@ -25,199 +25,204 @@ namespace OGL { -//This are the initially requested size for the buffers expressed in bytes -const u32 MAX_IBUFFER_SIZE = 2*1024*1024; -const u32 MAX_VBUFFER_SIZE = 32*1024*1024; +// This are the initially requested size for the buffers expressed in bytes +const u32 MAX_IBUFFER_SIZE = 2 * 1024 * 1024; +const u32 MAX_VBUFFER_SIZE = 32 * 1024 * 1024; static std::unique_ptr s_vertexBuffer; static std::unique_ptr s_indexBuffer; static size_t s_baseVertex; static size_t s_index_offset; -VertexManager::VertexManager() - : m_cpu_v_buffer(MAX_VBUFFER_SIZE), m_cpu_i_buffer(MAX_IBUFFER_SIZE) +VertexManager::VertexManager() : m_cpu_v_buffer(MAX_VBUFFER_SIZE), m_cpu_i_buffer(MAX_IBUFFER_SIZE) { - CreateDeviceObjects(); + CreateDeviceObjects(); } VertexManager::~VertexManager() { - DestroyDeviceObjects(); + DestroyDeviceObjects(); } void VertexManager::CreateDeviceObjects() { - s_vertexBuffer = StreamBuffer::Create(GL_ARRAY_BUFFER, MAX_VBUFFER_SIZE); - m_vertex_buffers = s_vertexBuffer->m_buffer; + s_vertexBuffer = StreamBuffer::Create(GL_ARRAY_BUFFER, MAX_VBUFFER_SIZE); + m_vertex_buffers = s_vertexBuffer->m_buffer; - s_indexBuffer = StreamBuffer::Create(GL_ELEMENT_ARRAY_BUFFER, MAX_IBUFFER_SIZE); - m_index_buffers = s_indexBuffer->m_buffer; + s_indexBuffer = StreamBuffer::Create(GL_ELEMENT_ARRAY_BUFFER, MAX_IBUFFER_SIZE); + m_index_buffers = s_indexBuffer->m_buffer; - m_last_vao = 0; + m_last_vao = 0; } void VertexManager::DestroyDeviceObjects() { - s_vertexBuffer.reset(); - s_indexBuffer.reset(); + s_vertexBuffer.reset(); + s_indexBuffer.reset(); } void VertexManager::PrepareDrawBuffers(u32 stride) { - u32 vertex_data_size = IndexGenerator::GetNumVerts() * stride; - u32 index_data_size = IndexGenerator::GetIndexLen() * sizeof(u16); + u32 vertex_data_size = IndexGenerator::GetNumVerts() * stride; + u32 index_data_size = IndexGenerator::GetIndexLen() * sizeof(u16); - s_vertexBuffer->Unmap(vertex_data_size); - s_indexBuffer->Unmap(index_data_size); + s_vertexBuffer->Unmap(vertex_data_size); + s_indexBuffer->Unmap(index_data_size); - ADDSTAT(stats.thisFrame.bytesVertexStreamed, vertex_data_size); - ADDSTAT(stats.thisFrame.bytesIndexStreamed, index_data_size); + ADDSTAT(stats.thisFrame.bytesVertexStreamed, vertex_data_size); + ADDSTAT(stats.thisFrame.bytesIndexStreamed, index_data_size); } void VertexManager::ResetBuffer(u32 stride) { - if (s_cull_all) - { - // This buffer isn't getting sent to the GPU. Just allocate it on the cpu. - s_pCurBufferPointer = s_pBaseBufferPointer = m_cpu_v_buffer.data(); - s_pEndBufferPointer = s_pBaseBufferPointer + m_cpu_v_buffer.size(); + if (s_cull_all) + { + // This buffer isn't getting sent to the GPU. Just allocate it on the cpu. + s_pCurBufferPointer = s_pBaseBufferPointer = m_cpu_v_buffer.data(); + s_pEndBufferPointer = s_pBaseBufferPointer + m_cpu_v_buffer.size(); - IndexGenerator::Start((u16*)m_cpu_i_buffer.data()); - } - else - { - auto buffer = s_vertexBuffer->Map(MAXVBUFFERSIZE, stride); - s_pCurBufferPointer = s_pBaseBufferPointer = buffer.first; - s_pEndBufferPointer = buffer.first + MAXVBUFFERSIZE; - s_baseVertex = buffer.second / stride; + IndexGenerator::Start((u16*)m_cpu_i_buffer.data()); + } + else + { + auto buffer = s_vertexBuffer->Map(MAXVBUFFERSIZE, stride); + s_pCurBufferPointer = s_pBaseBufferPointer = buffer.first; + s_pEndBufferPointer = buffer.first + MAXVBUFFERSIZE; + s_baseVertex = buffer.second / stride; - buffer = s_indexBuffer->Map(MAXIBUFFERSIZE * sizeof(u16)); - IndexGenerator::Start((u16*)buffer.first); - s_index_offset = buffer.second; - } + buffer = s_indexBuffer->Map(MAXIBUFFERSIZE * sizeof(u16)); + IndexGenerator::Start((u16*)buffer.first); + s_index_offset = buffer.second; + } } void VertexManager::Draw(u32 stride) { - u32 index_size = IndexGenerator::GetIndexLen(); - u32 max_index = IndexGenerator::GetNumVerts(); - GLenum primitive_mode = 0; + u32 index_size = IndexGenerator::GetIndexLen(); + u32 max_index = IndexGenerator::GetNumVerts(); + GLenum primitive_mode = 0; - switch (current_primitive_type) - { - case PRIMITIVE_POINTS: - primitive_mode = GL_POINTS; - glDisable(GL_CULL_FACE); - break; - case PRIMITIVE_LINES: - primitive_mode = GL_LINES; - glDisable(GL_CULL_FACE); - break; - case PRIMITIVE_TRIANGLES: - primitive_mode = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? GL_TRIANGLE_STRIP : GL_TRIANGLES; - break; - } + switch (current_primitive_type) + { + case PRIMITIVE_POINTS: + primitive_mode = GL_POINTS; + glDisable(GL_CULL_FACE); + break; + case PRIMITIVE_LINES: + primitive_mode = GL_LINES; + glDisable(GL_CULL_FACE); + break; + case PRIMITIVE_TRIANGLES: + primitive_mode = + g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? GL_TRIANGLE_STRIP : GL_TRIANGLES; + break; + } - if (g_ogl_config.bSupportsGLBaseVertex) - { - glDrawRangeElementsBaseVertex(primitive_mode, 0, max_index, index_size, GL_UNSIGNED_SHORT, (u8*)nullptr+s_index_offset, (GLint)s_baseVertex); - } - else - { - glDrawRangeElements(primitive_mode, 0, max_index, index_size, GL_UNSIGNED_SHORT, (u8*)nullptr+s_index_offset); - } + if (g_ogl_config.bSupportsGLBaseVertex) + { + glDrawRangeElementsBaseVertex(primitive_mode, 0, max_index, index_size, GL_UNSIGNED_SHORT, + (u8*)nullptr + s_index_offset, (GLint)s_baseVertex); + } + else + { + glDrawRangeElements(primitive_mode, 0, max_index, index_size, GL_UNSIGNED_SHORT, + (u8*)nullptr + s_index_offset); + } - INCSTAT(stats.thisFrame.numDrawCalls); + INCSTAT(stats.thisFrame.numDrawCalls); - if (current_primitive_type != PRIMITIVE_TRIANGLES) - static_cast(g_renderer.get())->SetGenerationMode(); + if (current_primitive_type != PRIMITIVE_TRIANGLES) + static_cast(g_renderer.get())->SetGenerationMode(); } void VertexManager::vFlush(bool useDstAlpha) { - GLVertexFormat *nativeVertexFmt = (GLVertexFormat*)VertexLoaderManager::GetCurrentVertexFormat(); - u32 stride = nativeVertexFmt->GetVertexStride(); + GLVertexFormat* nativeVertexFmt = (GLVertexFormat*)VertexLoaderManager::GetCurrentVertexFormat(); + u32 stride = nativeVertexFmt->GetVertexStride(); - if (m_last_vao != nativeVertexFmt->VAO) - { - glBindVertexArray(nativeVertexFmt->VAO); - m_last_vao = nativeVertexFmt->VAO; - } + if (m_last_vao != nativeVertexFmt->VAO) + { + glBindVertexArray(nativeVertexFmt->VAO); + m_last_vao = nativeVertexFmt->VAO; + } - PrepareDrawBuffers(stride); + PrepareDrawBuffers(stride); - // Makes sure we can actually do Dual source blending - bool dualSourcePossible = g_ActiveConfig.backend_info.bSupportsDualSourceBlend; + // Makes sure we can actually do Dual source blending + bool dualSourcePossible = g_ActiveConfig.backend_info.bSupportsDualSourceBlend; - // If host supports GL_ARB_blend_func_extended, we can do dst alpha in - // the same pass as regular rendering. - if (useDstAlpha && dualSourcePossible) - { - ProgramShaderCache::SetShader(DSTALPHA_DUAL_SOURCE_BLEND, current_primitive_type); - } - else - { - ProgramShaderCache::SetShader(DSTALPHA_NONE, current_primitive_type); - } + // If host supports GL_ARB_blend_func_extended, we can do dst alpha in + // the same pass as regular rendering. + if (useDstAlpha && dualSourcePossible) + { + ProgramShaderCache::SetShader(DSTALPHA_DUAL_SOURCE_BLEND, current_primitive_type); + } + else + { + ProgramShaderCache::SetShader(DSTALPHA_NONE, current_primitive_type); + } - // upload global constants - ProgramShaderCache::UploadConstants(); + // upload global constants + ProgramShaderCache::UploadConstants(); - // setup the pointers - nativeVertexFmt->SetupVertexPointers(); + // setup the pointers + nativeVertexFmt->SetupVertexPointers(); - Draw(stride); + Draw(stride); - // run through vertex groups again to set alpha - if (useDstAlpha && !dualSourcePossible) - { - ProgramShaderCache::SetShader(DSTALPHA_ALPHA_PASS, current_primitive_type); + // run through vertex groups again to set alpha + if (useDstAlpha && !dualSourcePossible) + { + ProgramShaderCache::SetShader(DSTALPHA_ALPHA_PASS, current_primitive_type); - // only update alpha - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); + // only update alpha + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); - glDisable(GL_BLEND); + glDisable(GL_BLEND); - Draw(stride); + Draw(stride); - // restore color mask - g_renderer->SetColorMask(); + // restore color mask + g_renderer->SetColorMask(); - if (bpmem.blendmode.blendenable || bpmem.blendmode.subtract) - glEnable(GL_BLEND); - } + if (bpmem.blendmode.blendenable || bpmem.blendmode.subtract) + glEnable(GL_BLEND); + } #if defined(_DEBUG) || defined(DEBUGFAST) - if (g_ActiveConfig.iLog & CONF_SAVESHADERS) - { - // save the shaders - ProgramShaderCache::PCacheEntry prog = ProgramShaderCache::GetShaderProgram(); - std::string filename = StringFromFormat("%sps%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_ActiveConfig.iSaveTargetId); - std::ofstream fps; - OpenFStream(fps, filename, std::ios_base::out); - fps << prog.shader.strpprog.c_str(); + if (g_ActiveConfig.iLog & CONF_SAVESHADERS) + { + // save the shaders + ProgramShaderCache::PCacheEntry prog = ProgramShaderCache::GetShaderProgram(); + std::string filename = StringFromFormat( + "%sps%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_ActiveConfig.iSaveTargetId); + std::ofstream fps; + OpenFStream(fps, filename, std::ios_base::out); + fps << prog.shader.strpprog.c_str(); - filename = StringFromFormat("%svs%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_ActiveConfig.iSaveTargetId); - std::ofstream fvs; - OpenFStream(fvs, filename, std::ios_base::out); - fvs << prog.shader.strvprog.c_str(); - } + filename = StringFromFormat("%svs%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), + g_ActiveConfig.iSaveTargetId); + std::ofstream fvs; + OpenFStream(fvs, filename, std::ios_base::out); + fvs << prog.shader.strvprog.c_str(); + } - if (g_ActiveConfig.iLog & CONF_SAVETARGETS) - { - std::string filename = StringFromFormat("%starg%.3d.png", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_ActiveConfig.iSaveTargetId); - TargetRectangle tr; - tr.left = 0; - tr.right = Renderer::GetTargetWidth(); - tr.top = 0; - tr.bottom = Renderer::GetTargetHeight(); - g_renderer->SaveScreenshot(filename, tr); - } + if (g_ActiveConfig.iLog & CONF_SAVETARGETS) + { + std::string filename = + StringFromFormat("%starg%.3d.png", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), + g_ActiveConfig.iSaveTargetId); + TargetRectangle tr; + tr.left = 0; + tr.right = Renderer::GetTargetWidth(); + tr.top = 0; + tr.bottom = Renderer::GetTargetHeight(); + g_renderer->SaveScreenshot(filename, tr); + } #endif - g_Config.iSaveTargetId++; + g_Config.iSaveTargetId++; - ClearEFBCache(); + ClearEFBCache(); } - } // namespace diff --git a/Source/Core/VideoBackends/OGL/VertexManager.h b/Source/Core/VideoBackends/OGL/VertexManager.h index a980f2205c..2eecb7d582 100644 --- a/Source/Core/VideoBackends/OGL/VertexManager.h +++ b/Source/Core/VideoBackends/OGL/VertexManager.h @@ -9,43 +9,43 @@ namespace OGL { - class GLVertexFormat : public NativeVertexFormat - { - public: - GLVertexFormat(const PortableVertexDeclaration& vtx_decl); - ~GLVertexFormat(); +class GLVertexFormat : public NativeVertexFormat +{ +public: + GLVertexFormat(const PortableVertexDeclaration& vtx_decl); + ~GLVertexFormat(); - void SetupVertexPointers() override; + void SetupVertexPointers() override; - GLuint VAO; - }; + GLuint VAO; +}; // Handles the OpenGL details of drawing lots of vertices quickly. // Other functionality is moving out. class VertexManager : public VertexManagerBase { public: - VertexManager(); - ~VertexManager(); - NativeVertexFormat* CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override; - void CreateDeviceObjects() override; - void DestroyDeviceObjects() override; + VertexManager(); + ~VertexManager(); + NativeVertexFormat* CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override; + void CreateDeviceObjects() override; + void DestroyDeviceObjects() override; + + // NativeVertexFormat use this + GLuint m_vertex_buffers; + GLuint m_index_buffers; + GLuint m_last_vao; - // NativeVertexFormat use this - GLuint m_vertex_buffers; - GLuint m_index_buffers; - GLuint m_last_vao; protected: - void ResetBuffer(u32 stride) override; + void ResetBuffer(u32 stride) override; private: - void Draw(u32 stride); - void vFlush(bool useDstAlpha) override; - void PrepareDrawBuffers(u32 stride); + void Draw(u32 stride); + void vFlush(bool useDstAlpha) override; + void PrepareDrawBuffers(u32 stride); - // Alternative buffers in CPU memory for primatives we are going to discard. - std::vector m_cpu_v_buffer; - std::vector m_cpu_i_buffer; + // Alternative buffers in CPU memory for primatives we are going to discard. + std::vector m_cpu_v_buffer; + std::vector m_cpu_i_buffer; }; - } diff --git a/Source/Core/VideoBackends/OGL/VideoBackend.h b/Source/Core/VideoBackends/OGL/VideoBackend.h index ccac9767fe..755ed9fa6f 100644 --- a/Source/Core/VideoBackends/OGL/VideoBackend.h +++ b/Source/Core/VideoBackends/OGL/VideoBackend.h @@ -9,21 +9,19 @@ namespace OGL { - class VideoBackend : public VideoBackendBase { - bool Initialize(void *) override; - void Shutdown() override; + bool Initialize(void*) override; + void Shutdown() override; - std::string GetName() const override; - std::string GetDisplayName() const override; + std::string GetName() const override; + std::string GetDisplayName() const override; - void Video_Prepare() override; - void Video_Cleanup() override; + void Video_Prepare() override; + void Video_Cleanup() override; - void ShowConfig(void* parent) override; + void ShowConfig(void* parent) override; - unsigned int PeekMessages() override; + unsigned int PeekMessages() override; }; - } diff --git a/Source/Core/VideoBackends/OGL/main.cpp b/Source/Core/VideoBackends/OGL/main.cpp index c4698d28d6..48b580ad2d 100644 --- a/Source/Core/VideoBackends/OGL/main.cpp +++ b/Source/Core/VideoBackends/OGL/main.cpp @@ -2,8 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - - // OpenGL Backend Documentation /* @@ -74,168 +72,165 @@ Make AA apply instantly during gameplay if possible namespace OGL { - // Draw messages on top of the screen unsigned int VideoBackend::PeekMessages() { - return GLInterface->PeekMessages(); + return GLInterface->PeekMessages(); } std::string VideoBackend::GetName() const { - return "OGL"; + return "OGL"; } std::string VideoBackend::GetDisplayName() const { - if (GLInterface != nullptr && GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3) - return "OpenGLES"; - else - return "OpenGL"; + if (GLInterface != nullptr && GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3) + return "OpenGLES"; + else + return "OpenGL"; } -static std::vector GetShaders(const std::string &sub_dir = "") +static std::vector GetShaders(const std::string& sub_dir = "") { - std::vector paths = DoFileSearch({".glsl"}, { - File::GetUserPath(D_SHADERS_IDX) + sub_dir, - File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir - }); - std::vector result; - for (std::string path : paths) - { - std::string name; - SplitPath(path, nullptr, &name, nullptr); - result.push_back(name); - } - return result; + std::vector paths = + DoFileSearch({".glsl"}, {File::GetUserPath(D_SHADERS_IDX) + sub_dir, + File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir}); + std::vector result; + for (std::string path : paths) + { + std::string name; + SplitPath(path, nullptr, &name, nullptr); + result.push_back(name); + } + return result; } static void InitBackendInfo() { - g_Config.backend_info.APIType = API_OPENGL; - g_Config.backend_info.bSupportsExclusiveFullscreen = false; - g_Config.backend_info.bSupportsOversizedViewports = true; - g_Config.backend_info.bSupportsGeometryShaders = true; - g_Config.backend_info.bSupports3DVision = false; - g_Config.backend_info.bSupportsPostProcessing = true; - g_Config.backend_info.bSupportsSSAA = true; + g_Config.backend_info.APIType = API_OPENGL; + g_Config.backend_info.bSupportsExclusiveFullscreen = false; + g_Config.backend_info.bSupportsOversizedViewports = true; + g_Config.backend_info.bSupportsGeometryShaders = true; + g_Config.backend_info.bSupports3DVision = false; + g_Config.backend_info.bSupportsPostProcessing = true; + g_Config.backend_info.bSupportsSSAA = true; - g_Config.backend_info.Adapters.clear(); + g_Config.backend_info.Adapters.clear(); - // aamodes - 1 is to stay consistent with D3D (means no AA) - g_Config.backend_info.AAModes = { 1, 2, 4, 8 }; + // aamodes - 1 is to stay consistent with D3D (means no AA) + g_Config.backend_info.AAModes = {1, 2, 4, 8}; - // pp shaders - g_Config.backend_info.PPShaders = GetShaders(""); - g_Config.backend_info.AnaglyphShaders = GetShaders(ANAGLYPH_DIR DIR_SEP); + // pp shaders + g_Config.backend_info.PPShaders = GetShaders(""); + g_Config.backend_info.AnaglyphShaders = GetShaders(ANAGLYPH_DIR DIR_SEP); } void VideoBackend::ShowConfig(void* parent_handle) { - if (!m_initialized) - InitBackendInfo(); + if (!m_initialized) + InitBackendInfo(); - Host_ShowVideoConfig(parent_handle, GetDisplayName(), "gfx_opengl"); + Host_ShowVideoConfig(parent_handle, GetDisplayName(), "gfx_opengl"); } bool VideoBackend::Initialize(void* window_handle) { - InitializeShared(); - InitBackendInfo(); + InitializeShared(); + InitBackendInfo(); - frameCount = 0; + frameCount = 0; - if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini")) - g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"); - else - g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "gfx_opengl.ini"); - g_Config.GameIniLoad(); - g_Config.UpdateProjectionHack(); - g_Config.VerifyValidity(); - UpdateActiveConfig(); + if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini")) + g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"); + else + g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "gfx_opengl.ini"); + g_Config.GameIniLoad(); + g_Config.UpdateProjectionHack(); + g_Config.VerifyValidity(); + UpdateActiveConfig(); - InitInterface(); - GLInterface->SetMode(GLInterfaceMode::MODE_DETECT); - if (!GLInterface->Create(window_handle)) - return false; + InitInterface(); + GLInterface->SetMode(GLInterfaceMode::MODE_DETECT); + if (!GLInterface->Create(window_handle)) + return false; - // Do our OSD callbacks - OSD::DoCallbacks(OSD::CallbackType::Initialization); + // Do our OSD callbacks + OSD::DoCallbacks(OSD::CallbackType::Initialization); - m_initialized = true; + m_initialized = true; - return true; + return true; } // This is called after Initialize() from the Core // Run from the graphics thread void VideoBackend::Video_Prepare() { - GLInterface->MakeCurrent(); + GLInterface->MakeCurrent(); - g_renderer = std::make_unique(); + g_renderer = std::make_unique(); - CommandProcessor::Init(); - PixelEngine::Init(); + CommandProcessor::Init(); + PixelEngine::Init(); - BPInit(); - g_vertex_manager = std::make_unique(); - g_perf_query = GetPerfQuery(); - Fifo::Init(); // must be done before OpcodeDecoder::Init() - OpcodeDecoder::Init(); - IndexGenerator::Init(); - VertexShaderManager::Init(); - PixelShaderManager::Init(); - GeometryShaderManager::Init(); - ProgramShaderCache::Init(); - g_texture_cache = std::make_unique(); - g_sampler_cache = std::make_unique(); - Renderer::Init(); - VertexLoaderManager::Init(); - TextureConverter::Init(); - BoundingBox::Init(); + BPInit(); + g_vertex_manager = std::make_unique(); + g_perf_query = GetPerfQuery(); + Fifo::Init(); // must be done before OpcodeDecoder::Init() + OpcodeDecoder::Init(); + IndexGenerator::Init(); + VertexShaderManager::Init(); + PixelShaderManager::Init(); + GeometryShaderManager::Init(); + ProgramShaderCache::Init(); + g_texture_cache = std::make_unique(); + g_sampler_cache = std::make_unique(); + Renderer::Init(); + VertexLoaderManager::Init(); + TextureConverter::Init(); + BoundingBox::Init(); - // Notify the core that the video backend is ready - Host_Message(WM_USER_CREATE); + // Notify the core that the video backend is ready + Host_Message(WM_USER_CREATE); } void VideoBackend::Shutdown() { - m_initialized = false; + m_initialized = false; - // Do our OSD callbacks - OSD::DoCallbacks(OSD::CallbackType::Shutdown); + // Do our OSD callbacks + OSD::DoCallbacks(OSD::CallbackType::Shutdown); - GLInterface->Shutdown(); - GLInterface.reset(); + GLInterface->Shutdown(); + GLInterface.reset(); } void VideoBackend::Video_Cleanup() { - if (!g_renderer) - return; + if (!g_renderer) + return; - Fifo::Shutdown(); + Fifo::Shutdown(); - // The following calls are NOT Thread Safe - // And need to be called from the video thread - Renderer::Shutdown(); - BoundingBox::Shutdown(); - TextureConverter::Shutdown(); - VertexLoaderManager::Shutdown(); - g_sampler_cache.reset(); - g_texture_cache.reset(); - ProgramShaderCache::Shutdown(); - VertexShaderManager::Shutdown(); - PixelShaderManager::Shutdown(); - GeometryShaderManager::Shutdown(); + // The following calls are NOT Thread Safe + // And need to be called from the video thread + Renderer::Shutdown(); + BoundingBox::Shutdown(); + TextureConverter::Shutdown(); + VertexLoaderManager::Shutdown(); + g_sampler_cache.reset(); + g_texture_cache.reset(); + ProgramShaderCache::Shutdown(); + VertexShaderManager::Shutdown(); + PixelShaderManager::Shutdown(); + GeometryShaderManager::Shutdown(); - g_perf_query.reset(); - g_vertex_manager.reset(); + g_perf_query.reset(); + g_vertex_manager.reset(); - OpcodeDecoder::Shutdown(); - g_renderer.reset(); - GLInterface->ClearCurrent(); + OpcodeDecoder::Shutdown(); + g_renderer.reset(); + GLInterface->ClearCurrent(); } - } diff --git a/Source/Core/VideoBackends/Software/Clipper.cpp b/Source/Core/VideoBackends/Software/Clipper.cpp index 0d1b6ce059..c0c8021808 100644 --- a/Source/Core/VideoBackends/Software/Clipper.cpp +++ b/Source/Core/VideoBackends/Software/Clipper.cpp @@ -35,8 +35,8 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "Common/ChunkFile.h" #include "VideoBackends/Software/Clipper.h" +#include "Common/ChunkFile.h" #include "VideoBackends/Software/NativeVertexFormat.h" #include "VideoBackends/Software/Rasterizer.h" @@ -46,399 +46,412 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Clipper { - enum - { - NUM_CLIPPED_VERTICES = 33, - NUM_INDICES = NUM_CLIPPED_VERTICES + 3 - }; - - static OutputVertexData ClippedVertices[NUM_CLIPPED_VERTICES]; - static OutputVertexData *Vertices[NUM_INDICES]; - - void Init() - { - for (int i = 0; i < NUM_CLIPPED_VERTICES; ++i) - Vertices[i+3] = &ClippedVertices[i]; - } - - - enum - { - SKIP_FLAG = -1, - CLIP_POS_X_BIT = 0x01, - CLIP_NEG_X_BIT = 0x02, - CLIP_POS_Y_BIT = 0x04, - CLIP_NEG_Y_BIT = 0x08, - CLIP_POS_Z_BIT = 0x10, - CLIP_NEG_Z_BIT = 0x20 - }; - - static inline int CalcClipMask(OutputVertexData *v) - { - int cmask = 0; - Vec4 pos = v->projectedPosition; - - if (pos.w - pos.x < 0) - cmask |= CLIP_POS_X_BIT; - - if (pos.x + pos.w < 0) - cmask |= CLIP_NEG_X_BIT; - - if (pos.w - pos.y < 0) - cmask |= CLIP_POS_Y_BIT; - - if (pos.y + pos.w < 0) - cmask |= CLIP_NEG_Y_BIT; - - if (pos.w * pos.z > 0) - cmask |= CLIP_POS_Z_BIT; - - if (pos.z + pos.w < 0) - cmask |= CLIP_NEG_Z_BIT; - - return cmask; - } - - static inline void AddInterpolatedVertex(float t, int out, int in, int* numVertices) - { - Vertices[(*numVertices)++]->Lerp(t, Vertices[out], Vertices[in]); - } - - #define DIFFERENT_SIGNS(x,y) ((x <= 0 && y > 0) || (x > 0 && y <= 0)) - - #define CLIP_DOTPROD(I, A, B, C, D) \ - (Vertices[I]->projectedPosition.x * A + Vertices[I]->projectedPosition.y * B + Vertices[I]->projectedPosition.z * C + Vertices[I]->projectedPosition.w * D) - - #define POLY_CLIP( PLANE_BIT, A, B, C, D ) \ - { \ - if (mask & PLANE_BIT) { \ - int idxPrev = inlist[0]; \ - float dpPrev = CLIP_DOTPROD(idxPrev, A, B, C, D ); \ - int outcount = 0; \ - \ - inlist[n] = inlist[0]; \ - for (int j = 1; j <= n; j++) { \ - int idx = inlist[j]; \ - float dp = CLIP_DOTPROD(idx, A, B, C, D ); \ - if (dpPrev >= 0) { \ - outlist[outcount++] = idxPrev; \ - } \ - \ - if (DIFFERENT_SIGNS(dp, dpPrev)) { \ - if (dp < 0) { \ - float t = dp / (dp - dpPrev); \ - AddInterpolatedVertex(t, idx, idxPrev, &numVertices); \ - } else { \ - float t = dpPrev / (dpPrev - dp); \ - AddInterpolatedVertex(t, idxPrev, idx, &numVertices); \ - } \ - outlist[outcount++] = numVertices - 1; \ - } \ - \ - idxPrev = idx; \ - dpPrev = dp; \ - } \ - \ - if (outcount < 3) \ - continue; \ - \ - { \ - int *tmp = inlist; \ - inlist = outlist; \ - outlist = tmp; \ - n = outcount; \ - } \ - } \ - } - - #define LINE_CLIP(PLANE_BIT, A, B, C, D ) \ - { \ - if (mask & PLANE_BIT) { \ - const float dp0 = CLIP_DOTPROD( 0, A, B, C, D ); \ - const float dp1 = CLIP_DOTPROD( 1, A, B, C, D ); \ - const bool neg_dp0 = dp0 < 0; \ - const bool neg_dp1 = dp1 < 0; \ - \ - if (neg_dp0 && neg_dp1) \ - return; \ - \ - if (neg_dp1) { \ - float t = dp1 / (dp1 - dp0); \ - if (t > t1) t1 = t; \ - } else if (neg_dp0) { \ - float t = dp0 / (dp0 - dp1); \ - if (t > t0) t0 = t; \ - } \ - } \ - } - - static void ClipTriangle(int *indices, int* numIndices) - { - int mask = 0; - - mask |= CalcClipMask(Vertices[0]); - mask |= CalcClipMask(Vertices[1]); - mask |= CalcClipMask(Vertices[2]); - - if (mask != 0) - { - for (int i = 0; i < 3; i += 3) - { - int vlist[2][2*6+1]; - int *inlist = vlist[0], *outlist = vlist[1]; - int n = 3; - int numVertices = 3; - - inlist[0] = 0; - inlist[1] = 1; - inlist[2] = 2; - - // mark this triangle as unused in case it should be completely - // clipped - indices[0] = SKIP_FLAG; - indices[1] = SKIP_FLAG; - indices[2] = SKIP_FLAG; - - POLY_CLIP(CLIP_POS_X_BIT, -1, 0, 0, 1); - POLY_CLIP(CLIP_NEG_X_BIT, 1, 0, 0, 1); - POLY_CLIP(CLIP_POS_Y_BIT, 0, -1, 0, 1); - POLY_CLIP(CLIP_NEG_Y_BIT, 0, 1, 0, 1); - POLY_CLIP(CLIP_POS_Z_BIT, 0, 0, 0, 1); - POLY_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1); - - INCSTAT(stats.thisFrame.numTrianglesClipped); - - // transform the poly in inlist into triangles - indices[0] = inlist[0]; - indices[1] = inlist[1]; - indices[2] = inlist[2]; - for (int j = 3; j < n; ++j) - { - indices[(*numIndices)++] = inlist[0]; - indices[(*numIndices)++] = inlist[j - 1]; - indices[(*numIndices)++] = inlist[j]; - } - } - } - } - - static void ClipLine(int *indices) - { - int mask = 0; - int clip_mask[2] = { 0, 0 }; - - for (int i = 0; i < 2; ++i) - { - clip_mask[i] = CalcClipMask(Vertices[i]); - mask |= clip_mask[i]; - } - - if (mask == 0) - return; - - float t0 = 0; - float t1 = 0; - - // Mark unused in case of early termination - // of the macros below. (When fully clipped) - indices[0] = SKIP_FLAG; - indices[1] = SKIP_FLAG; - - LINE_CLIP(CLIP_POS_X_BIT, -1, 0, 0, 1); - LINE_CLIP(CLIP_NEG_X_BIT, 1, 0, 0, 1); - LINE_CLIP(CLIP_POS_Y_BIT, 0, -1, 0, 1); - LINE_CLIP(CLIP_NEG_Y_BIT, 0, 1, 0, 1); - LINE_CLIP(CLIP_POS_Z_BIT, 0, 0, -1, 1); - LINE_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1); - - // Restore the old values as this line - // was not fully clipped. - indices[0] = 0; - indices[1] = 1; - - int numVertices = 2; - - if (clip_mask[0]) - { - indices[0] = numVertices; - AddInterpolatedVertex(t0, 0, 1, &numVertices); - } - - if (clip_mask[1]) - { - indices[1] = numVertices; - AddInterpolatedVertex(t1, 1, 0, &numVertices); - } - } - - void ProcessTriangle(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2) - { - INCSTAT(stats.thisFrame.numTrianglesIn) - - bool backface; - - if (!CullTest(v0, v1, v2, backface)) - return; - - int indices[NUM_INDICES] = { - 0, 1, 2, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, - SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, - SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG - }; - int numIndices = 3; - - if (backface) - { - Vertices[0] = v0; - Vertices[1] = v2; - Vertices[2] = v1; - } - else - { - Vertices[0] = v0; - Vertices[1] = v1; - Vertices[2] = v2; - } - - ClipTriangle(indices, &numIndices); - - for (int i = 0; i+3 <= numIndices; i+=3) - { - _assert_(i < NUM_INDICES); - if (indices[i] != SKIP_FLAG) - { - PerspectiveDivide(Vertices[indices[i]]); - PerspectiveDivide(Vertices[indices[i+1]]); - PerspectiveDivide(Vertices[indices[i+2]]); - - Rasterizer::DrawTriangleFrontFace(Vertices[indices[i]], Vertices[indices[i+1]], Vertices[indices[i+2]]); - } - } - } - - static void CopyVertex(OutputVertexData *dst, OutputVertexData *src, float dx, float dy, unsigned int sOffset) - { - dst->screenPosition.x = src->screenPosition.x + dx; - dst->screenPosition.y = src->screenPosition.y + dy; - dst->screenPosition.z = src->screenPosition.z; - - for (int i = 0; i < 3; ++i) - dst->normal[i] = src->normal[i]; - - for (int i = 0; i < 4; ++i) - dst->color[0][i] = src->color[0][i]; - - // todo - s offset - for (int i = 0; i < 8; ++i) - dst->texCoords[i] = src->texCoords[i]; - } - - void ProcessLine(OutputVertexData *lineV0, OutputVertexData *lineV1) - { - int indices[4] = { 0, 1, SKIP_FLAG, SKIP_FLAG }; - - Vertices[0] = lineV0; - Vertices[1] = lineV1; - - // point to a valid vertex to store to when clipping - Vertices[2] = &ClippedVertices[17]; - - ClipLine(indices); - - if (indices[0] != SKIP_FLAG) - { - OutputVertexData *v0 = Vertices[indices[0]]; - OutputVertexData *v1 = Vertices[indices[1]]; - - PerspectiveDivide(v0); - PerspectiveDivide(v1); - - float dx = v1->screenPosition.x - v0->screenPosition.x; - float dy = v1->screenPosition.y - v0->screenPosition.y; - - float screenDx = 0; - float screenDy = 0; - - if (fabsf(dx) > fabsf(dy)) - { - if (dx > 0) - screenDy = bpmem.lineptwidth.linesize / -12.0f; - else - screenDy = bpmem.lineptwidth.linesize / 12.0f; - } - else - { - if (dy > 0) - screenDx = bpmem.lineptwidth.linesize / 12.0f; - else - screenDx = bpmem.lineptwidth.linesize / -12.0f; - } - - OutputVertexData triangle[3]; - - CopyVertex(&triangle[0], v0, screenDx, screenDy, 0); - CopyVertex(&triangle[1], v1, screenDx, screenDy, 0); - CopyVertex(&triangle[2], v1, -screenDx, -screenDy, bpmem.lineptwidth.lineoff); - - // ccw winding - Rasterizer::DrawTriangleFrontFace(&triangle[2], &triangle[1], &triangle[0]); - - CopyVertex(&triangle[1], v0, -screenDx, -screenDy, bpmem.lineptwidth.lineoff); - - Rasterizer::DrawTriangleFrontFace(&triangle[0], &triangle[1], &triangle[2]); - } - } - - bool CullTest(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2, bool &backface) - { - int mask = CalcClipMask(v0); - mask &= CalcClipMask(v1); - mask &= CalcClipMask(v2); - - if (mask) - { - INCSTAT(stats.thisFrame.numTrianglesRejected) - return false; - } - - float x0 = v0->projectedPosition.x; - float x1 = v1->projectedPosition.x; - float x2 = v2->projectedPosition.x; - float y1 = v1->projectedPosition.y; - float y0 = v0->projectedPosition.y; - float y2 = v2->projectedPosition.y; - float w0 = v0->projectedPosition.w; - float w1 = v1->projectedPosition.w; - float w2 = v2->projectedPosition.w; - - float normalZDir = (x0*w2 - x2*w0)*y1 + (x2*y0 - x0*y2)*w1 + (y2*w0 - y0*w2)*x1; - - backface = normalZDir <= 0.0f; - - if ((bpmem.genMode.cullmode & 1) && !backface) // cull frontfacing - { - INCSTAT(stats.thisFrame.numTrianglesCulled) - return false; - } - - if ((bpmem.genMode.cullmode & 2) && backface) // cull backfacing - { - INCSTAT(stats.thisFrame.numTrianglesCulled) - return false; - } - - return true; - } - - void PerspectiveDivide(OutputVertexData *vertex) - { - Vec4 &projected = vertex->projectedPosition; - Vec3 &screen = vertex->screenPosition; - - float wInverse = 1.0f/projected.w; - screen.x = projected.x * wInverse * xfmem.viewport.wd + xfmem.viewport.xOrig - 342; - screen.y = projected.y * wInverse * xfmem.viewport.ht + xfmem.viewport.yOrig - 342; - screen.z = projected.z * wInverse * xfmem.viewport.zRange + xfmem.viewport.farZ; - } - +enum +{ + NUM_CLIPPED_VERTICES = 33, + NUM_INDICES = NUM_CLIPPED_VERTICES + 3 +}; + +static OutputVertexData ClippedVertices[NUM_CLIPPED_VERTICES]; +static OutputVertexData* Vertices[NUM_INDICES]; + +void Init() +{ + for (int i = 0; i < NUM_CLIPPED_VERTICES; ++i) + Vertices[i + 3] = &ClippedVertices[i]; +} + +enum +{ + SKIP_FLAG = -1, + CLIP_POS_X_BIT = 0x01, + CLIP_NEG_X_BIT = 0x02, + CLIP_POS_Y_BIT = 0x04, + CLIP_NEG_Y_BIT = 0x08, + CLIP_POS_Z_BIT = 0x10, + CLIP_NEG_Z_BIT = 0x20 +}; + +static inline int CalcClipMask(OutputVertexData* v) +{ + int cmask = 0; + Vec4 pos = v->projectedPosition; + + if (pos.w - pos.x < 0) + cmask |= CLIP_POS_X_BIT; + + if (pos.x + pos.w < 0) + cmask |= CLIP_NEG_X_BIT; + + if (pos.w - pos.y < 0) + cmask |= CLIP_POS_Y_BIT; + + if (pos.y + pos.w < 0) + cmask |= CLIP_NEG_Y_BIT; + + if (pos.w * pos.z > 0) + cmask |= CLIP_POS_Z_BIT; + + if (pos.z + pos.w < 0) + cmask |= CLIP_NEG_Z_BIT; + + return cmask; +} + +static inline void AddInterpolatedVertex(float t, int out, int in, int* numVertices) +{ + Vertices[(*numVertices)++]->Lerp(t, Vertices[out], Vertices[in]); +} + +#define DIFFERENT_SIGNS(x, y) ((x <= 0 && y > 0) || (x > 0 && y <= 0)) + +#define CLIP_DOTPROD(I, A, B, C, D) \ + (Vertices[I]->projectedPosition.x * A + Vertices[I]->projectedPosition.y * B + \ + Vertices[I]->projectedPosition.z * C + Vertices[I]->projectedPosition.w * D) + +#define POLY_CLIP(PLANE_BIT, A, B, C, D) \ + { \ + if (mask & PLANE_BIT) \ + { \ + int idxPrev = inlist[0]; \ + float dpPrev = CLIP_DOTPROD(idxPrev, A, B, C, D); \ + int outcount = 0; \ + \ + inlist[n] = inlist[0]; \ + for (int j = 1; j <= n; j++) \ + { \ + int idx = inlist[j]; \ + float dp = CLIP_DOTPROD(idx, A, B, C, D); \ + if (dpPrev >= 0) \ + { \ + outlist[outcount++] = idxPrev; \ + } \ + \ + if (DIFFERENT_SIGNS(dp, dpPrev)) \ + { \ + if (dp < 0) \ + { \ + float t = dp / (dp - dpPrev); \ + AddInterpolatedVertex(t, idx, idxPrev, &numVertices); \ + } \ + else \ + { \ + float t = dpPrev / (dpPrev - dp); \ + AddInterpolatedVertex(t, idxPrev, idx, &numVertices); \ + } \ + outlist[outcount++] = numVertices - 1; \ + } \ + \ + idxPrev = idx; \ + dpPrev = dp; \ + } \ + \ + if (outcount < 3) \ + continue; \ + \ + { \ + int* tmp = inlist; \ + inlist = outlist; \ + outlist = tmp; \ + n = outcount; \ + } \ + } \ + } + +#define LINE_CLIP(PLANE_BIT, A, B, C, D) \ + { \ + if (mask & PLANE_BIT) \ + { \ + const float dp0 = CLIP_DOTPROD(0, A, B, C, D); \ + const float dp1 = CLIP_DOTPROD(1, A, B, C, D); \ + const bool neg_dp0 = dp0 < 0; \ + const bool neg_dp1 = dp1 < 0; \ + \ + if (neg_dp0 && neg_dp1) \ + return; \ + \ + if (neg_dp1) \ + { \ + float t = dp1 / (dp1 - dp0); \ + if (t > t1) \ + t1 = t; \ + } \ + else if (neg_dp0) \ + { \ + float t = dp0 / (dp0 - dp1); \ + if (t > t0) \ + t0 = t; \ + } \ + } \ + } + +static void ClipTriangle(int* indices, int* numIndices) +{ + int mask = 0; + + mask |= CalcClipMask(Vertices[0]); + mask |= CalcClipMask(Vertices[1]); + mask |= CalcClipMask(Vertices[2]); + + if (mask != 0) + { + for (int i = 0; i < 3; i += 3) + { + int vlist[2][2 * 6 + 1]; + int *inlist = vlist[0], *outlist = vlist[1]; + int n = 3; + int numVertices = 3; + + inlist[0] = 0; + inlist[1] = 1; + inlist[2] = 2; + + // mark this triangle as unused in case it should be completely + // clipped + indices[0] = SKIP_FLAG; + indices[1] = SKIP_FLAG; + indices[2] = SKIP_FLAG; + + POLY_CLIP(CLIP_POS_X_BIT, -1, 0, 0, 1); + POLY_CLIP(CLIP_NEG_X_BIT, 1, 0, 0, 1); + POLY_CLIP(CLIP_POS_Y_BIT, 0, -1, 0, 1); + POLY_CLIP(CLIP_NEG_Y_BIT, 0, 1, 0, 1); + POLY_CLIP(CLIP_POS_Z_BIT, 0, 0, 0, 1); + POLY_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1); + + INCSTAT(stats.thisFrame.numTrianglesClipped); + + // transform the poly in inlist into triangles + indices[0] = inlist[0]; + indices[1] = inlist[1]; + indices[2] = inlist[2]; + for (int j = 3; j < n; ++j) + { + indices[(*numIndices)++] = inlist[0]; + indices[(*numIndices)++] = inlist[j - 1]; + indices[(*numIndices)++] = inlist[j]; + } + } + } +} + +static void ClipLine(int* indices) +{ + int mask = 0; + int clip_mask[2] = {0, 0}; + + for (int i = 0; i < 2; ++i) + { + clip_mask[i] = CalcClipMask(Vertices[i]); + mask |= clip_mask[i]; + } + + if (mask == 0) + return; + + float t0 = 0; + float t1 = 0; + + // Mark unused in case of early termination + // of the macros below. (When fully clipped) + indices[0] = SKIP_FLAG; + indices[1] = SKIP_FLAG; + + LINE_CLIP(CLIP_POS_X_BIT, -1, 0, 0, 1); + LINE_CLIP(CLIP_NEG_X_BIT, 1, 0, 0, 1); + LINE_CLIP(CLIP_POS_Y_BIT, 0, -1, 0, 1); + LINE_CLIP(CLIP_NEG_Y_BIT, 0, 1, 0, 1); + LINE_CLIP(CLIP_POS_Z_BIT, 0, 0, -1, 1); + LINE_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1); + + // Restore the old values as this line + // was not fully clipped. + indices[0] = 0; + indices[1] = 1; + + int numVertices = 2; + + if (clip_mask[0]) + { + indices[0] = numVertices; + AddInterpolatedVertex(t0, 0, 1, &numVertices); + } + + if (clip_mask[1]) + { + indices[1] = numVertices; + AddInterpolatedVertex(t1, 1, 0, &numVertices); + } +} + +void ProcessTriangle(OutputVertexData* v0, OutputVertexData* v1, OutputVertexData* v2) +{ + INCSTAT(stats.thisFrame.numTrianglesIn) + + bool backface; + + if (!CullTest(v0, v1, v2, backface)) + return; + + int indices[NUM_INDICES] = {0, 1, 2, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, + SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, + SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, + SKIP_FLAG, SKIP_FLAG, SKIP_FLAG}; + int numIndices = 3; + + if (backface) + { + Vertices[0] = v0; + Vertices[1] = v2; + Vertices[2] = v1; + } + else + { + Vertices[0] = v0; + Vertices[1] = v1; + Vertices[2] = v2; + } + + ClipTriangle(indices, &numIndices); + + for (int i = 0; i + 3 <= numIndices; i += 3) + { + _assert_(i < NUM_INDICES); + if (indices[i] != SKIP_FLAG) + { + PerspectiveDivide(Vertices[indices[i]]); + PerspectiveDivide(Vertices[indices[i + 1]]); + PerspectiveDivide(Vertices[indices[i + 2]]); + + Rasterizer::DrawTriangleFrontFace(Vertices[indices[i]], Vertices[indices[i + 1]], + Vertices[indices[i + 2]]); + } + } +} + +static void CopyVertex(OutputVertexData* dst, OutputVertexData* src, float dx, float dy, + unsigned int sOffset) +{ + dst->screenPosition.x = src->screenPosition.x + dx; + dst->screenPosition.y = src->screenPosition.y + dy; + dst->screenPosition.z = src->screenPosition.z; + + for (int i = 0; i < 3; ++i) + dst->normal[i] = src->normal[i]; + + for (int i = 0; i < 4; ++i) + dst->color[0][i] = src->color[0][i]; + + // todo - s offset + for (int i = 0; i < 8; ++i) + dst->texCoords[i] = src->texCoords[i]; +} + +void ProcessLine(OutputVertexData* lineV0, OutputVertexData* lineV1) +{ + int indices[4] = {0, 1, SKIP_FLAG, SKIP_FLAG}; + + Vertices[0] = lineV0; + Vertices[1] = lineV1; + + // point to a valid vertex to store to when clipping + Vertices[2] = &ClippedVertices[17]; + + ClipLine(indices); + + if (indices[0] != SKIP_FLAG) + { + OutputVertexData* v0 = Vertices[indices[0]]; + OutputVertexData* v1 = Vertices[indices[1]]; + + PerspectiveDivide(v0); + PerspectiveDivide(v1); + + float dx = v1->screenPosition.x - v0->screenPosition.x; + float dy = v1->screenPosition.y - v0->screenPosition.y; + + float screenDx = 0; + float screenDy = 0; + + if (fabsf(dx) > fabsf(dy)) + { + if (dx > 0) + screenDy = bpmem.lineptwidth.linesize / -12.0f; + else + screenDy = bpmem.lineptwidth.linesize / 12.0f; + } + else + { + if (dy > 0) + screenDx = bpmem.lineptwidth.linesize / 12.0f; + else + screenDx = bpmem.lineptwidth.linesize / -12.0f; + } + + OutputVertexData triangle[3]; + + CopyVertex(&triangle[0], v0, screenDx, screenDy, 0); + CopyVertex(&triangle[1], v1, screenDx, screenDy, 0); + CopyVertex(&triangle[2], v1, -screenDx, -screenDy, bpmem.lineptwidth.lineoff); + + // ccw winding + Rasterizer::DrawTriangleFrontFace(&triangle[2], &triangle[1], &triangle[0]); + + CopyVertex(&triangle[1], v0, -screenDx, -screenDy, bpmem.lineptwidth.lineoff); + + Rasterizer::DrawTriangleFrontFace(&triangle[0], &triangle[1], &triangle[2]); + } +} + +bool CullTest(OutputVertexData* v0, OutputVertexData* v1, OutputVertexData* v2, bool& backface) +{ + int mask = CalcClipMask(v0); + mask &= CalcClipMask(v1); + mask &= CalcClipMask(v2); + + if (mask) + { + INCSTAT(stats.thisFrame.numTrianglesRejected) + return false; + } + + float x0 = v0->projectedPosition.x; + float x1 = v1->projectedPosition.x; + float x2 = v2->projectedPosition.x; + float y1 = v1->projectedPosition.y; + float y0 = v0->projectedPosition.y; + float y2 = v2->projectedPosition.y; + float w0 = v0->projectedPosition.w; + float w1 = v1->projectedPosition.w; + float w2 = v2->projectedPosition.w; + + float normalZDir = (x0 * w2 - x2 * w0) * y1 + (x2 * y0 - x0 * y2) * w1 + (y2 * w0 - y0 * w2) * x1; + + backface = normalZDir <= 0.0f; + + if ((bpmem.genMode.cullmode & 1) && !backface) // cull frontfacing + { + INCSTAT(stats.thisFrame.numTrianglesCulled) + return false; + } + + if ((bpmem.genMode.cullmode & 2) && backface) // cull backfacing + { + INCSTAT(stats.thisFrame.numTrianglesCulled) + return false; + } + + return true; +} + +void PerspectiveDivide(OutputVertexData* vertex) +{ + Vec4& projected = vertex->projectedPosition; + Vec3& screen = vertex->screenPosition; + + float wInverse = 1.0f / projected.w; + screen.x = projected.x * wInverse * xfmem.viewport.wd + xfmem.viewport.xOrig - 342; + screen.y = projected.y * wInverse * xfmem.viewport.ht + xfmem.viewport.yOrig - 342; + screen.z = projected.z * wInverse * xfmem.viewport.zRange + xfmem.viewport.farZ; +} } diff --git a/Source/Core/VideoBackends/Software/Clipper.h b/Source/Core/VideoBackends/Software/Clipper.h index 0e8fead073..0b2d3440c9 100644 --- a/Source/Core/VideoBackends/Software/Clipper.h +++ b/Source/Core/VideoBackends/Software/Clipper.h @@ -8,13 +8,13 @@ struct OutputVertexData; namespace Clipper { - void Init(); +void Init(); - void ProcessTriangle(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2); +void ProcessTriangle(OutputVertexData* v0, OutputVertexData* v1, OutputVertexData* v2); - void ProcessLine(OutputVertexData *v0, OutputVertexData *v1); +void ProcessLine(OutputVertexData* v0, OutputVertexData* v1); - bool CullTest(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2, bool &backface); +bool CullTest(OutputVertexData* v0, OutputVertexData* v1, OutputVertexData* v2, bool& backface); - void PerspectiveDivide(OutputVertexData *vertex); +void PerspectiveDivide(OutputVertexData* vertex); } diff --git a/Source/Core/VideoBackends/Software/DebugUtil.cpp b/Source/Core/VideoBackends/Software/DebugUtil.cpp index 0e2b4e1934..4d0d73137e 100644 --- a/Source/Core/VideoBackends/Software/DebugUtil.cpp +++ b/Source/Core/VideoBackends/Software/DebugUtil.cpp @@ -21,10 +21,9 @@ namespace DebugUtil { - static const int NUM_OBJECT_BUFFERS = 40; -static u32 *ObjectBuffer[NUM_OBJECT_BUFFERS]; +static u32* ObjectBuffer[NUM_OBJECT_BUFFERS]; static u32 TempBuffer[NUM_OBJECT_BUFFERS]; static bool DrawnToBuffer[NUM_OBJECT_BUFFERS]; @@ -33,197 +32,199 @@ static int BufferBase[NUM_OBJECT_BUFFERS]; void Init() { - for (int i = 0; i < NUM_OBJECT_BUFFERS; i++) - { - ObjectBuffer[i] = new u32[EFB_WIDTH*EFB_HEIGHT](); - DrawnToBuffer[i] = false; - ObjectBufferName[i] = nullptr; - BufferBase[i] = 0; - } + for (int i = 0; i < NUM_OBJECT_BUFFERS; i++) + { + ObjectBuffer[i] = new u32[EFB_WIDTH * EFB_HEIGHT](); + DrawnToBuffer[i] = false; + ObjectBufferName[i] = nullptr; + BufferBase[i] = 0; + } } void Shutdown() { - for (int i = 0; i < NUM_OBJECT_BUFFERS; i++) - { - delete[] ObjectBuffer[i]; - } + for (int i = 0; i < NUM_OBJECT_BUFFERS; i++) + { + delete[] ObjectBuffer[i]; + } } static void SaveTexture(const std::string& filename, u32 texmap, s32 mip) { - FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1]; - u8 subTexmap = texmap & 3; + FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1]; + u8 subTexmap = texmap & 3; - TexImage0& ti0 = texUnit.texImage0[subTexmap]; + TexImage0& ti0 = texUnit.texImage0[subTexmap]; - u32 width = ti0.width + 1; - u32 height = ti0.height + 1; + u32 width = ti0.width + 1; + u32 height = ti0.height + 1; - u8 *data = new u8[width * height * 4]; + u8* data = new u8[width * height * 4]; - GetTextureRGBA(data, texmap, mip, width, height); - - TextureToPng(data, width*4, filename, width, height, true); - delete[] data; + GetTextureRGBA(data, texmap, mip, width, height); + TextureToPng(data, width * 4, filename, width, height, true); + delete[] data; } -void GetTextureRGBA(u8 *dst, u32 texmap, s32 mip, u32 width, u32 height) +void GetTextureRGBA(u8* dst, u32 texmap, s32 mip, u32 width, u32 height) { - for (u32 y = 0; y < height; y++) - { - for (u32 x = 0; x < width; x++) - { - TextureSampler::SampleMip(x << 7, y << 7, mip, false, texmap, dst); - dst += 4; - } - } + for (u32 y = 0; y < height; y++) + { + for (u32 x = 0; x < width; x++) + { + TextureSampler::SampleMip(x << 7, y << 7, mip, false, texmap, dst); + dst += 4; + } + } } static s32 GetMaxTextureLod(u32 texmap) { - FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1]; - u8 subTexmap = texmap & 3; + FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1]; + u8 subTexmap = texmap & 3; - u8 maxLod = texUnit.texMode1[subTexmap].max_lod; - u8 mip = maxLod >> 4; - u8 fract = maxLod & 0xf; + u8 maxLod = texUnit.texMode1[subTexmap].max_lod; + u8 mip = maxLod >> 4; + u8 fract = maxLod & 0xf; - if (fract) - ++mip; + if (fract) + ++mip; - return (s32)mip; + return (s32)mip; } void DumpActiveTextures() { - for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++) - { - u32 texmap = bpmem.tevindref.getTexMap(stageNum); + for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++) + { + u32 texmap = bpmem.tevindref.getTexMap(stageNum); - s32 maxLod = GetMaxTextureLod(texmap); - for (s32 mip = 0; mip <= maxLod; ++mip) - { - SaveTexture(StringFromFormat("%star%i_ind%i_map%i_mip%i.png", - File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(), - stats.thisFrame.numDrawnObjects, stageNum, texmap, mip), texmap, mip); - } - } + s32 maxLod = GetMaxTextureLod(texmap); + for (s32 mip = 0; mip <= maxLod; ++mip) + { + SaveTexture(StringFromFormat("%star%i_ind%i_map%i_mip%i.png", + File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(), + stats.thisFrame.numDrawnObjects, stageNum, texmap, mip), + texmap, mip); + } + } - for (unsigned int stageNum = 0; stageNum <= bpmem.genMode.numtevstages; stageNum++) - { - int stageNum2 = stageNum >> 1; - int stageOdd = stageNum&1; - TwoTevStageOrders &order = bpmem.tevorders[stageNum2]; + for (unsigned int stageNum = 0; stageNum <= bpmem.genMode.numtevstages; stageNum++) + { + int stageNum2 = stageNum >> 1; + int stageOdd = stageNum & 1; + TwoTevStageOrders& order = bpmem.tevorders[stageNum2]; - int texmap = order.getTexMap(stageOdd); + int texmap = order.getTexMap(stageOdd); - s32 maxLod = GetMaxTextureLod(texmap); - for (s32 mip = 0; mip <= maxLod; ++mip) - { - SaveTexture(StringFromFormat("%star%i_stage%i_map%i_mip%i.png", - File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(), - stats.thisFrame.numDrawnObjects, stageNum, texmap, mip), texmap, mip); - } - } + s32 maxLod = GetMaxTextureLod(texmap); + for (s32 mip = 0; mip <= maxLod; ++mip) + { + SaveTexture(StringFromFormat("%star%i_stage%i_map%i_mip%i.png", + File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(), + stats.thisFrame.numDrawnObjects, stageNum, texmap, mip), + texmap, mip); + } + } } static void DumpEfb(const std::string& filename) { - u8 *data = new u8[EFB_WIDTH * EFB_HEIGHT * 4]; - u8 *writePtr = data; - u8 sample[4]; + u8* data = new u8[EFB_WIDTH * EFB_HEIGHT * 4]; + u8* writePtr = data; + u8 sample[4]; - for (int y = 0; y < EFB_HEIGHT; y++) - { - for (int x = 0; x < EFB_WIDTH; x++) - { - EfbInterface::GetColor(x, y, sample); - // ABGR to RGBA - *(writePtr++) = sample[3]; - *(writePtr++) = sample[2]; - *(writePtr++) = sample[1]; - *(writePtr++) = sample[0]; - } - } + for (int y = 0; y < EFB_HEIGHT; y++) + { + for (int x = 0; x < EFB_WIDTH; x++) + { + EfbInterface::GetColor(x, y, sample); + // ABGR to RGBA + *(writePtr++) = sample[3]; + *(writePtr++) = sample[2]; + *(writePtr++) = sample[1]; + *(writePtr++) = sample[0]; + } + } - TextureToPng(data, EFB_WIDTH * 4, filename, EFB_WIDTH, EFB_HEIGHT, true); - delete[] data; + TextureToPng(data, EFB_WIDTH * 4, filename, EFB_WIDTH, EFB_HEIGHT, true); + delete[] data; } -void DrawObjectBuffer(s16 x, s16 y, u8 *color, int bufferBase, int subBuffer, const char *name) +void DrawObjectBuffer(s16 x, s16 y, u8* color, int bufferBase, int subBuffer, const char* name) { - int buffer = bufferBase + subBuffer; + int buffer = bufferBase + subBuffer; - u32 offset = (x + y * EFB_WIDTH) * 4; - u8 *dst = (u8*)&ObjectBuffer[buffer][offset]; - *(dst++) = color[2]; - *(dst++) = color[1]; - *(dst++) = color[0]; - *(dst++) = color[3]; + u32 offset = (x + y * EFB_WIDTH) * 4; + u8* dst = (u8*)&ObjectBuffer[buffer][offset]; + *(dst++) = color[2]; + *(dst++) = color[1]; + *(dst++) = color[0]; + *(dst++) = color[3]; - DrawnToBuffer[buffer] = true; - ObjectBufferName[buffer] = name; - BufferBase[buffer] = bufferBase; + DrawnToBuffer[buffer] = true; + ObjectBufferName[buffer] = name; + BufferBase[buffer] = bufferBase; } -void DrawTempBuffer(u8 *color, int buffer) +void DrawTempBuffer(u8* color, int buffer) { - u8 *dst = (u8*)&TempBuffer[buffer]; - *(dst++) = color[2]; - *(dst++) = color[1]; - *(dst++) = color[0]; - *(dst++) = color[3]; + u8* dst = (u8*)&TempBuffer[buffer]; + *(dst++) = color[2]; + *(dst++) = color[1]; + *(dst++) = color[0]; + *(dst++) = color[3]; } -void CopyTempBuffer(s16 x, s16 y, int bufferBase, int subBuffer, const char *name) +void CopyTempBuffer(s16 x, s16 y, int bufferBase, int subBuffer, const char* name) { - int buffer = bufferBase + subBuffer; + int buffer = bufferBase + subBuffer; - u32 offset = (x + y * EFB_WIDTH); - ObjectBuffer[buffer][offset] = TempBuffer[buffer]; + u32 offset = (x + y * EFB_WIDTH); + ObjectBuffer[buffer][offset] = TempBuffer[buffer]; - DrawnToBuffer[buffer] = true; - ObjectBufferName[buffer] = name; - BufferBase[buffer] = bufferBase; + DrawnToBuffer[buffer] = true; + ObjectBufferName[buffer] = name; + BufferBase[buffer] = bufferBase; } void OnObjectBegin() { - if (!Fifo::WillSkipCurrentFrame()) - { - if (g_ActiveConfig.bDumpTextures && stats.thisFrame.numDrawnObjects >= g_ActiveConfig.drawStart && stats.thisFrame.numDrawnObjects < g_ActiveConfig.drawEnd) - DumpActiveTextures(); - } + if (!Fifo::WillSkipCurrentFrame()) + { + if (g_ActiveConfig.bDumpTextures && + stats.thisFrame.numDrawnObjects >= g_ActiveConfig.drawStart && + stats.thisFrame.numDrawnObjects < g_ActiveConfig.drawEnd) + DumpActiveTextures(); + } } void OnObjectEnd() { - if (!Fifo::WillSkipCurrentFrame()) - { - if (g_ActiveConfig.bDumpObjects && stats.thisFrame.numDrawnObjects >= g_ActiveConfig.drawStart && stats.thisFrame.numDrawnObjects < g_ActiveConfig.drawEnd) - DumpEfb(StringFromFormat("%sobject%i.png", - File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), - stats.thisFrame.numDrawnObjects)); + if (!Fifo::WillSkipCurrentFrame()) + { + if (g_ActiveConfig.bDumpObjects && + stats.thisFrame.numDrawnObjects >= g_ActiveConfig.drawStart && + stats.thisFrame.numDrawnObjects < g_ActiveConfig.drawEnd) + DumpEfb(StringFromFormat("%sobject%i.png", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), + stats.thisFrame.numDrawnObjects)); - for (int i = 0; i < NUM_OBJECT_BUFFERS; i++) - { - if (DrawnToBuffer[i]) - { - DrawnToBuffer[i] = false; - std::string filename = StringFromFormat("%sobject%i_%s(%i).png", - File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), - stats.thisFrame.numDrawnObjects, ObjectBufferName[i], i - BufferBase[i]); + for (int i = 0; i < NUM_OBJECT_BUFFERS; i++) + { + if (DrawnToBuffer[i]) + { + DrawnToBuffer[i] = false; + std::string filename = StringFromFormat( + "%sobject%i_%s(%i).png", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), + stats.thisFrame.numDrawnObjects, ObjectBufferName[i], i - BufferBase[i]); - TextureToPng((u8*)ObjectBuffer[i], EFB_WIDTH * 4, filename, EFB_WIDTH, EFB_HEIGHT, true); - memset(ObjectBuffer[i], 0, EFB_WIDTH * EFB_HEIGHT * sizeof(u32)); + TextureToPng((u8*)ObjectBuffer[i], EFB_WIDTH * 4, filename, EFB_WIDTH, EFB_HEIGHT, true); + memset(ObjectBuffer[i], 0, EFB_WIDTH * EFB_HEIGHT * sizeof(u32)); + } + } - } - } - - stats.thisFrame.numDrawnObjects++; - } + stats.thisFrame.numDrawnObjects++; + } } - } diff --git a/Source/Core/VideoBackends/Software/DebugUtil.h b/Source/Core/VideoBackends/Software/DebugUtil.h index 1d5b072500..c90e790496 100644 --- a/Source/Core/VideoBackends/Software/DebugUtil.h +++ b/Source/Core/VideoBackends/Software/DebugUtil.h @@ -8,18 +8,18 @@ namespace DebugUtil { - void Init(); - void Shutdown(); +void Init(); +void Shutdown(); - void GetTextureRGBA(u8 *dst, u32 texmap, s32 mip, u32 width, u32 height); +void GetTextureRGBA(u8* dst, u32 texmap, s32 mip, u32 width, u32 height); - void DumpActiveTextures(); +void DumpActiveTextures(); - void OnObjectBegin(); - void OnObjectEnd(); +void OnObjectBegin(); +void OnObjectEnd(); - void DrawObjectBuffer(s16 x, s16 y, u8 *color, int bufferBase, int subBuffer, const char *name); +void DrawObjectBuffer(s16 x, s16 y, u8* color, int bufferBase, int subBuffer, const char* name); - void DrawTempBuffer(u8 *color, int buffer); - void CopyTempBuffer(s16 x, s16 y, int bufferBase, int subBuffer, const char *name); +void DrawTempBuffer(u8* color, int buffer); +void CopyTempBuffer(s16 x, s16 y, int bufferBase, int subBuffer, const char* name); } diff --git a/Source/Core/VideoBackends/Software/EfbCopy.cpp b/Source/Core/VideoBackends/Software/EfbCopy.cpp index b076cb3d35..d0092e6729 100644 --- a/Source/Core/VideoBackends/Software/EfbCopy.cpp +++ b/Source/Core/VideoBackends/Software/EfbCopy.cpp @@ -2,104 +2,99 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoBackends/Software/EfbCopy.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Core/HW/Memmap.h" -#include "VideoBackends/Software/EfbCopy.h" #include "VideoBackends/Software/EfbInterface.h" #include "VideoBackends/Software/TextureEncoder.h" #include "VideoCommon/BPMemory.h" #include "VideoCommon/Fifo.h" -static const float s_gammaLUT[] = -{ - 1.0f, - 1.7f, - 2.2f, - 1.0f -}; +static const float s_gammaLUT[] = {1.0f, 1.7f, 2.2f, 1.0f}; namespace EfbCopy { - static void CopyToXfb(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma) - { - INFO_LOG(VIDEO, "xfbaddr: %x, fbwidth: %i, fbheight: %i, source: (%i, %i, %i, %i), Gamma %f", - xfbAddr, fbWidth, fbHeight, sourceRc.top, sourceRc.left, sourceRc.bottom, sourceRc.right, Gamma); +static void CopyToXfb(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, + float Gamma) +{ + INFO_LOG(VIDEO, "xfbaddr: %x, fbwidth: %i, fbheight: %i, source: (%i, %i, %i, %i), Gamma %f", + xfbAddr, fbWidth, fbHeight, sourceRc.top, sourceRc.left, sourceRc.bottom, sourceRc.right, + Gamma); - EfbInterface::yuv422_packed* xfb_in_ram = (EfbInterface::yuv422_packed*) Memory::GetPointer(xfbAddr); + EfbInterface::yuv422_packed* xfb_in_ram = + (EfbInterface::yuv422_packed*)Memory::GetPointer(xfbAddr); - EfbInterface::CopyToXFB(xfb_in_ram, fbWidth, fbHeight, sourceRc, Gamma); - } - - static void CopyToRam() - { - u8 *dest_ptr = Memory::GetPointer(bpmem.copyTexDest << 5); - - TextureEncoder::Encode(dest_ptr); - } - - void ClearEfb() - { - u32 clearColor = (bpmem.clearcolorAR & 0xff) << 24 | bpmem.clearcolorGB << 8 | (bpmem.clearcolorAR & 0xff00) >> 8; - - int left = bpmem.copyTexSrcXY.x; - int top = bpmem.copyTexSrcXY.y; - int right = left + bpmem.copyTexSrcWH.x; - int bottom = top + bpmem.copyTexSrcWH.y; - - for (u16 y = top; y <= bottom; y++) - { - for (u16 x = left; x <= right; x++) - { - EfbInterface::SetColor(x, y, (u8*)(&clearColor)); - EfbInterface::SetDepth(x, y, bpmem.clearZValue); - } - } - } - - void CopyEfb() - { - EFBRectangle rc; - rc.left = (int)bpmem.copyTexSrcXY.x; - rc.top = (int)bpmem.copyTexSrcXY.y; - - // flipper represents the widths internally as last pixel minus starting pixel, so - // these are zero indexed. - rc.right = rc.left + (int)bpmem.copyTexSrcWH.x + 1; - rc.bottom = rc.top + (int)bpmem.copyTexSrcWH.y + 1; - - if (!Fifo::WillSkipCurrentFrame()) - { - if (bpmem.triggerEFBCopy.copy_to_xfb) - { - float yScale; - if (bpmem.triggerEFBCopy.scale_invert) - yScale = 256.0f / (float)bpmem.dispcopyyscale; - else - yScale = (float)bpmem.dispcopyyscale / 256.0f; - - float xfbLines = ((bpmem.copyTexSrcWH.y + 1.0f) * yScale); - - if (yScale != 1.0) - WARN_LOG(VIDEO, "yScale of %f is currently unsupported", yScale); - - if ((u32)xfbLines > MAX_XFB_HEIGHT) - { - INFO_LOG(VIDEO, "Tried to scale EFB to too many XFB lines (%f)", xfbLines); - xfbLines = MAX_XFB_HEIGHT; - } - - CopyToXfb(bpmem.copyTexDest << 5, - bpmem.copyMipMapStrideChannels << 4, - (u32)xfbLines, - rc, - s_gammaLUT[bpmem.triggerEFBCopy.gamma]); - } - else - { - CopyToRam(); // FIXME: should use the rectangle we have already created above - } - } - } + EfbInterface::CopyToXFB(xfb_in_ram, fbWidth, fbHeight, sourceRc, Gamma); +} + +static void CopyToRam() +{ + u8* dest_ptr = Memory::GetPointer(bpmem.copyTexDest << 5); + + TextureEncoder::Encode(dest_ptr); +} + +void ClearEfb() +{ + u32 clearColor = (bpmem.clearcolorAR & 0xff) << 24 | bpmem.clearcolorGB << 8 | + (bpmem.clearcolorAR & 0xff00) >> 8; + + int left = bpmem.copyTexSrcXY.x; + int top = bpmem.copyTexSrcXY.y; + int right = left + bpmem.copyTexSrcWH.x; + int bottom = top + bpmem.copyTexSrcWH.y; + + for (u16 y = top; y <= bottom; y++) + { + for (u16 x = left; x <= right; x++) + { + EfbInterface::SetColor(x, y, (u8*)(&clearColor)); + EfbInterface::SetDepth(x, y, bpmem.clearZValue); + } + } +} + +void CopyEfb() +{ + EFBRectangle rc; + rc.left = (int)bpmem.copyTexSrcXY.x; + rc.top = (int)bpmem.copyTexSrcXY.y; + + // flipper represents the widths internally as last pixel minus starting pixel, so + // these are zero indexed. + rc.right = rc.left + (int)bpmem.copyTexSrcWH.x + 1; + rc.bottom = rc.top + (int)bpmem.copyTexSrcWH.y + 1; + + if (!Fifo::WillSkipCurrentFrame()) + { + if (bpmem.triggerEFBCopy.copy_to_xfb) + { + float yScale; + if (bpmem.triggerEFBCopy.scale_invert) + yScale = 256.0f / (float)bpmem.dispcopyyscale; + else + yScale = (float)bpmem.dispcopyyscale / 256.0f; + + float xfbLines = ((bpmem.copyTexSrcWH.y + 1.0f) * yScale); + + if (yScale != 1.0) + WARN_LOG(VIDEO, "yScale of %f is currently unsupported", yScale); + + if ((u32)xfbLines > MAX_XFB_HEIGHT) + { + INFO_LOG(VIDEO, "Tried to scale EFB to too many XFB lines (%f)", xfbLines); + xfbLines = MAX_XFB_HEIGHT; + } + + CopyToXfb(bpmem.copyTexDest << 5, bpmem.copyMipMapStrideChannels << 4, (u32)xfbLines, rc, + s_gammaLUT[bpmem.triggerEFBCopy.gamma]); + } + else + { + CopyToRam(); // FIXME: should use the rectangle we have already created above + } + } +} } diff --git a/Source/Core/VideoBackends/Software/EfbCopy.h b/Source/Core/VideoBackends/Software/EfbCopy.h index 97698d3c5f..b7101c55b8 100644 --- a/Source/Core/VideoBackends/Software/EfbCopy.h +++ b/Source/Core/VideoBackends/Software/EfbCopy.h @@ -8,8 +8,8 @@ namespace EfbCopy { - // Copy the EFB to RAM as a texture format or XFB - void CopyEfb(); +// Copy the EFB to RAM as a texture format or XFB +void CopyEfb(); - void ClearEfb(); +void ClearEfb(); } diff --git a/Source/Core/VideoBackends/Software/EfbInterface.cpp b/Source/Core/VideoBackends/Software/EfbInterface.cpp index 9d8af4f88b..abfb9edc79 100644 --- a/Source/Core/VideoBackends/Software/EfbInterface.cpp +++ b/Source/Core/VideoBackends/Software/EfbInterface.cpp @@ -12,625 +12,628 @@ #include "VideoCommon/LookUpTables.h" #include "VideoCommon/PerfQueryBase.h" - -static u8 efb[EFB_WIDTH*EFB_HEIGHT*6]; +static u8 efb[EFB_WIDTH * EFB_HEIGHT * 6]; namespace EfbInterface { - u32 perf_values[PQ_NUM_MEMBERS]; +u32 perf_values[PQ_NUM_MEMBERS]; - static inline u32 GetColorOffset(u16 x, u16 y) - { - return (x + y * EFB_WIDTH) * 3; - } - - static inline u32 GetDepthOffset(u16 x, u16 y) - { - return (x + y * EFB_WIDTH) * 3 + DEPTH_BUFFER_START; - } - - static void SetPixelAlphaOnly(u32 offset, u8 a) - { - switch (bpmem.zcontrol.pixel_format) - { - case PEControl::RGB8_Z24: - case PEControl::Z24: - case PEControl::RGB565_Z16: - // do nothing - break; - case PEControl::RGBA6_Z24: - { - u32 a32 = a; - u32 *dst = (u32*)&efb[offset]; - u32 val = *dst & 0xffffffc0; - val |= (a32 >> 2) & 0x0000003f; - *dst = val; - } - break; - default: - ERROR_LOG(VIDEO, "Unsupported pixel format: %i", static_cast(bpmem.zcontrol.pixel_format)); - } - } - - static void SetPixelColorOnly(u32 offset, u8 *rgb) - { - switch (bpmem.zcontrol.pixel_format) - { - case PEControl::RGB8_Z24: - case PEControl::Z24: - { - u32 src = *(u32*)rgb; - u32 *dst = (u32*)&efb[offset]; - u32 val = *dst & 0xff000000; - val |= src >> 8; - *dst = val; - } - break; - case PEControl::RGBA6_Z24: - { - u32 src = *(u32*)rgb; - u32 *dst = (u32*)&efb[offset]; - u32 val = *dst & 0xff00003f; - val |= (src >> 4) & 0x00000fc0; // blue - val |= (src >> 6) & 0x0003f000; // green - val |= (src >> 8) & 0x00fc0000; // red - *dst = val; - } - break; - case PEControl::RGB565_Z16: - { - INFO_LOG(VIDEO, "RGB565_Z16 is not supported correctly yet"); - u32 src = *(u32*)rgb; - u32 *dst = (u32*)&efb[offset]; - u32 val = *dst & 0xff000000; - val |= src >> 8; - *dst = val; - } - break; - default: - ERROR_LOG(VIDEO, "Unsupported pixel format: %i", static_cast(bpmem.zcontrol.pixel_format)); - } - } - - static void SetPixelAlphaColor(u32 offset, u8 *color) - { - switch (bpmem.zcontrol.pixel_format) - { - case PEControl::RGB8_Z24: - case PEControl::Z24: - { - u32 src = *(u32*)color; - u32 *dst = (u32*)&efb[offset]; - u32 val = *dst & 0xff000000; - val |= src >> 8; - *dst = val; - } - break; - case PEControl::RGBA6_Z24: - { - u32 src = *(u32*)color; - u32 *dst = (u32*)&efb[offset]; - u32 val = *dst & 0xff000000; - val |= (src >> 2) & 0x0000003f; // alpha - val |= (src >> 4) & 0x00000fc0; // blue - val |= (src >> 6) & 0x0003f000; // green - val |= (src >> 8) & 0x00fc0000; // red - *dst = val; - } - break; - case PEControl::RGB565_Z16: - { - INFO_LOG(VIDEO, "RGB565_Z16 is not supported correctly yet"); - u32 src = *(u32*)color; - u32 *dst = (u32*)&efb[offset]; - u32 val = *dst & 0xff000000; - val |= src >> 8; - *dst = val; - } - break; - default: - ERROR_LOG(VIDEO, "Unsupported pixel format: %i", static_cast(bpmem.zcontrol.pixel_format)); - } - } - - static void GetPixelColor(u32 offset, u8 *color) - { - switch (bpmem.zcontrol.pixel_format) - { - case PEControl::RGB8_Z24: - case PEControl::Z24: - { - u32 src = *(u32*)&efb[offset]; - u32 *dst = (u32*)color; - u32 val = 0xff | ((src & 0x00ffffff) << 8); - *dst = val; - } - break; - case PEControl::RGBA6_Z24: - { - u32 src = *(u32*)&efb[offset]; - color[ALP_C] = Convert6To8(src & 0x3f); - color[BLU_C] = Convert6To8((src >> 6) & 0x3f); - color[GRN_C] = Convert6To8((src >> 12) & 0x3f); - color[RED_C] = Convert6To8((src >> 18) & 0x3f); - } - break; - case PEControl::RGB565_Z16: - { - INFO_LOG(VIDEO, "RGB565_Z16 is not supported correctly yet"); - u32 src = *(u32*)&efb[offset]; - u32 *dst = (u32*)color; - u32 val = 0xff | ((src & 0x00ffffff) << 8); - *dst = val; - } - break; - default: - ERROR_LOG(VIDEO, "Unsupported pixel format: %i", static_cast(bpmem.zcontrol.pixel_format)); - } - } - - static void SetPixelDepth(u32 offset, u32 depth) - { - switch (bpmem.zcontrol.pixel_format) - { - case PEControl::RGB8_Z24: - case PEControl::RGBA6_Z24: - case PEControl::Z24: - { - u32 *dst = (u32*)&efb[offset]; - u32 val = *dst & 0xff000000; - val |= depth & 0x00ffffff; - *dst = val; - } - break; - case PEControl::RGB565_Z16: - { - INFO_LOG(VIDEO, "RGB565_Z16 is not supported correctly yet"); - u32 *dst = (u32*)&efb[offset]; - u32 val = *dst & 0xff000000; - val |= depth & 0x00ffffff; - *dst = val; - } - break; - default: - ERROR_LOG(VIDEO, "Unsupported pixel format: %i", static_cast(bpmem.zcontrol.pixel_format)); - } - } - - static u32 GetPixelDepth(u32 offset) - { - u32 depth = 0; - - switch (bpmem.zcontrol.pixel_format) - { - case PEControl::RGB8_Z24: - case PEControl::RGBA6_Z24: - case PEControl::Z24: - { - depth = (*(u32*)&efb[offset]) & 0x00ffffff; - } - break; - case PEControl::RGB565_Z16: - { - INFO_LOG(VIDEO, "RGB565_Z16 is not supported correctly yet"); - depth = (*(u32*)&efb[offset]) & 0x00ffffff; - } - break; - default: - ERROR_LOG(VIDEO, "Unsupported pixel format: %i", static_cast(bpmem.zcontrol.pixel_format)); - } - - return depth; - } - - static u32 GetSourceFactor(u8 *srcClr, u8 *dstClr, BlendMode::BlendFactor mode) - { - switch (mode) - { - case BlendMode::ZERO: - return 0; - case BlendMode::ONE: - return 0xffffffff; - case BlendMode::DSTCLR: - return *(u32*)dstClr; - case BlendMode::INVDSTCLR: - return 0xffffffff - *(u32*)dstClr; - case BlendMode::SRCALPHA: - { - u8 alpha = srcClr[ALP_C]; - u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; - return factor; - } - case BlendMode::INVSRCALPHA: - { - u8 alpha = 0xff - srcClr[ALP_C]; - u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; - return factor; - } - case BlendMode::DSTALPHA: - { - u8 alpha = dstClr[ALP_C]; - u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; - return factor; - } - case BlendMode::INVDSTALPHA: - { - u8 alpha = 0xff - dstClr[ALP_C]; - u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; - return factor; - } - } - - return 0; - } - - static u32 GetDestinationFactor(u8 *srcClr, u8 *dstClr, BlendMode::BlendFactor mode) - { - switch (mode) - { - case BlendMode::ZERO: - return 0; - case BlendMode::ONE: - return 0xffffffff; - case BlendMode::SRCCLR: - return *(u32*)srcClr; - case BlendMode::INVSRCCLR: - return 0xffffffff - *(u32*)srcClr; - case BlendMode::SRCALPHA: - { - u8 alpha = srcClr[ALP_C]; - u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; - return factor; - } - case BlendMode::INVSRCALPHA: - { - u8 alpha = 0xff - srcClr[ALP_C]; - u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; - return factor; - } - case BlendMode::DSTALPHA: - { - u8 alpha = dstClr[ALP_C] & 0xff; - u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; - return factor; - } - case BlendMode::INVDSTALPHA: - { - u8 alpha = 0xff - dstClr[ALP_C]; - u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; - return factor; - } - } - - return 0; - } - - static void BlendColor(u8 *srcClr, u8 *dstClr) - { - u32 srcFactor = GetSourceFactor(srcClr, dstClr, bpmem.blendmode.srcfactor); - u32 dstFactor = GetDestinationFactor(srcClr, dstClr, bpmem.blendmode.dstfactor); - - for (int i = 0; i < 4; i++) - { - // add MSB of factors to make their range 0 -> 256 - u32 sf = (srcFactor & 0xff); - sf += sf >> 7; - - u32 df = (dstFactor & 0xff); - df += df >> 7; - - u32 color = (srcClr[i] * sf + dstClr[i] * df) >> 8; - dstClr[i] = (color>255)?255:color; - - dstFactor >>= 8; - srcFactor >>= 8; - } - } - - static void LogicBlend(u32 srcClr, u32* dstClr, BlendMode::LogicOp op) - { - switch (op) - { - case BlendMode::CLEAR: - *dstClr = 0; - break; - case BlendMode::AND: - *dstClr = srcClr & *dstClr; - break; - case BlendMode::AND_REVERSE: - *dstClr = srcClr & (~*dstClr); - break; - case BlendMode::COPY: - *dstClr = srcClr; - break; - case BlendMode::AND_INVERTED: - *dstClr = (~srcClr) & *dstClr; - break; - case BlendMode::NOOP: - // Do nothing - break; - case BlendMode::XOR: - *dstClr = srcClr ^ *dstClr; - break; - case BlendMode::OR: - *dstClr = srcClr | *dstClr; - break; - case BlendMode::NOR: - *dstClr = ~(srcClr | *dstClr); - break; - case BlendMode::EQUIV: - *dstClr = ~(srcClr ^ *dstClr); - break; - case BlendMode::INVERT: - *dstClr = ~*dstClr; - break; - case BlendMode::OR_REVERSE: - *dstClr = srcClr | (~*dstClr); - break; - case BlendMode::COPY_INVERTED: - *dstClr = ~srcClr; - break; - case BlendMode::OR_INVERTED: - *dstClr = (~srcClr) | *dstClr; - break; - case BlendMode::NAND: - *dstClr = ~(srcClr & *dstClr); - break; - case BlendMode::SET: - *dstClr = 0xffffffff; - break; - } - } - - static void SubtractBlend(u8 *srcClr, u8 *dstClr) - { - for (int i = 0; i < 4; i++) - { - int c = (int)dstClr[i] - (int)srcClr[i]; - dstClr[i] = (c < 0)?0:c; - } - } - - static void Dither(u16 x, u16 y, u8 *color) - { - // No blending for RGB8 mode - if (!bpmem.blendmode.dither || bpmem.zcontrol.pixel_format != PEControl::PixelFormat::RGBA6_Z24) - return; - - // Flipper uses a standard 2x2 Bayer Matrix for 6 bit dithering - static const u8 dither[2][2] = {{0, 2}, {3, 1}}; - - // Only the color channels are dithered? - for (int i = BLU_C; i <= RED_C; i++) - color[i] = ((color[i] - (color[i] >> 6)) + dither[y & 1][x & 1]) & 0xfc; - } - - void BlendTev(u16 x, u16 y, u8 *color) - { - u32 dstClr; - u32 offset = GetColorOffset(x, y); - - u8 *dstClrPtr = (u8*)&dstClr; - - GetPixelColor(offset, dstClrPtr); - - if (bpmem.blendmode.blendenable) - { - if (bpmem.blendmode.subtract) - SubtractBlend(color, dstClrPtr); - else - BlendColor(color, dstClrPtr); - } - else if (bpmem.blendmode.logicopenable) - { - LogicBlend(*((u32*)color), &dstClr, bpmem.blendmode.logicmode); - } - else - { - dstClrPtr = color; - } - - if (bpmem.dstalpha.enable) - dstClrPtr[ALP_C] = bpmem.dstalpha.alpha; - - if (bpmem.blendmode.colorupdate) - { - Dither(x, y, dstClrPtr); - if (bpmem.blendmode.alphaupdate) - SetPixelAlphaColor(offset, dstClrPtr); - else - SetPixelColorOnly(offset, dstClrPtr); - } - else if (bpmem.blendmode.alphaupdate) - { - SetPixelAlphaOnly(offset, dstClrPtr[ALP_C]); - } - } - - void SetColor(u16 x, u16 y, u8 *color) - { - u32 offset = GetColorOffset(x, y); - if (bpmem.blendmode.colorupdate) - { - if (bpmem.blendmode.alphaupdate) - SetPixelAlphaColor(offset, color); - else - SetPixelColorOnly(offset, color); - } - else if (bpmem.blendmode.alphaupdate) - { - SetPixelAlphaOnly(offset, color[ALP_C]); - } - } - - void SetDepth(u16 x, u16 y, u32 depth) - { - if (bpmem.zmode.updateenable) - SetPixelDepth(GetDepthOffset(x, y), depth); - } - - void GetColor(u16 x, u16 y, u8 *color) - { - u32 offset = GetColorOffset(x, y); - GetPixelColor(offset, color); - } - - // For internal used only, return a non-normalized value, which saves work later. - void GetColorYUV(u16 x, u16 y, yuv444 *out) - { - u8 color[4]; - GetColor(x, y, color); - - // GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see - // http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion - out->Y = (u8)( 0.257f * color[RED_C] + 0.504f * color[GRN_C] + 0.098f * color[BLU_C]); - out->U = (u8)(-0.148f * color[RED_C] + -0.291f * color[GRN_C] + 0.439f * color[BLU_C]); - out->V = (u8)( 0.439f * color[RED_C] + -0.368f * color[GRN_C] + -0.071f * color[BLU_C]); - } - - u32 GetDepth(u16 x, u16 y) - { - u32 offset = GetDepthOffset(x, y); - return GetPixelDepth(offset); - } - - u8 *GetPixelPointer(u16 x, u16 y, bool depth) - { - if (depth) - return &efb[GetDepthOffset(x, y)]; - return &efb[GetColorOffset(x, y)]; - } - - void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma) - { - // FIXME: We should do Gamma correction - - if (!xfb_in_ram) - { - WARN_LOG(VIDEO, "Tried to copy to invalid XFB address"); - return; - } - - int left = sourceRc.left; - int right = sourceRc.right; - - // this assumes copies will always start on an even (YU) pixel and the - // copy always has an even width, which might not be true. - if (left & 1 || right & 1) - { - WARN_LOG(VIDEO, "Trying to copy XFB to from unaligned EFB source"); - // this will show up as wrongly encoded - } - - // Scanline buffer, leave room for borders - yuv444 scanline[EFB_WIDTH+2]; - - // our internal yuv444 type is not normalized, so black is {0, 0, 0} instead of {16, 128, 128} - yuv444 black; - black.Y = 0; - black.U = 0; - black.V = 0; - - scanline[0] = black; // black border at start - scanline[right+1] = black; // black border at end - - for (u16 y = sourceRc.top; y < sourceRc.bottom; y++) - { - // Get a scanline of YUV pixels in 4:4:4 format - - for (int i = 1, x = left; x < right; i++, x++) - { - GetColorYUV(x, y, &scanline[i]); - } - - // And Downsample them to 4:2:2 - for (int i = 1, x = left; x < right; i+=2, x+=2) - { - // YU pixel - xfb_in_ram[x].Y = scanline[i].Y + 16; - // we mix our color differences in 10 bit space so it will round more accurately - // U[i] = 1/4 * U[i-1] + 1/2 * U[i] + 1/4 * U[i+1] - xfb_in_ram[x].UV = 128 + ((scanline[i-1].U + (scanline[i].U << 1) + scanline[i+1].U) >> 2); - - // YV pixel - xfb_in_ram[x+1].Y = scanline[i+1].Y + 16; - // V[i] = 1/4 * V[i-1] + 1/2 * V[i] + 1/4 * V[i+1] - xfb_in_ram[x+1].UV = 128 + ((scanline[i].V + (scanline[i+1].V << 1) + scanline[i+2].V) >> 2); - } - xfb_in_ram += fbWidth; - } - } - - // Like CopyToXFB, but we copy directly into the OpenGL color texture without going via GameCube main memory or doing a yuyv conversion - void BypassXFB(u8* texture, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma) - { - if (fbWidth*fbHeight > MAX_XFB_WIDTH*MAX_XFB_HEIGHT) - { - ERROR_LOG(VIDEO, "Framebuffer is too large: %ix%i", fbWidth, fbHeight); - return; - } - - u32 color; - u8* colorPtr = (u8*)&color; - u32* texturePtr = (u32*)texture; - u32 textureAddress = 0; - - int left = sourceRc.left; - int right = sourceRc.right; - - for (u16 y = sourceRc.top; y < sourceRc.bottom; y++) - { - for (u16 x = left; x < right; x++) - { - GetColor(x, y, colorPtr); - texturePtr[textureAddress++] = Common::swap32(color | 0xFF); - } - } - } - - bool ZCompare(u16 x, u16 y, u32 z) - { - u32 offset = GetDepthOffset(x, y); - u32 depth = GetPixelDepth(offset); - - bool pass; - - switch (bpmem.zmode.func) - { - case ZMode::NEVER: - pass = false; - break; - case ZMode::LESS: - pass = z < depth; - break; - case ZMode::EQUAL: - pass = z == depth; - break; - case ZMode::LEQUAL: - pass = z <= depth; - break; - case ZMode::GREATER: - pass = z > depth; - break; - case ZMode::NEQUAL: - pass = z != depth; - break; - case ZMode::GEQUAL: - pass = z >= depth; - break; - case ZMode::ALWAYS: - pass = true; - break; - default: - pass = false; - ERROR_LOG(VIDEO, "Bad Z compare mode %i", (int)bpmem.zmode.func); - } - - if (pass && bpmem.zmode.updateenable) - { - SetPixelDepth(offset, z); - } - - return pass; - } +static inline u32 GetColorOffset(u16 x, u16 y) +{ + return (x + y * EFB_WIDTH) * 3; +} + +static inline u32 GetDepthOffset(u16 x, u16 y) +{ + return (x + y * EFB_WIDTH) * 3 + DEPTH_BUFFER_START; +} + +static void SetPixelAlphaOnly(u32 offset, u8 a) +{ + switch (bpmem.zcontrol.pixel_format) + { + case PEControl::RGB8_Z24: + case PEControl::Z24: + case PEControl::RGB565_Z16: + // do nothing + break; + case PEControl::RGBA6_Z24: + { + u32 a32 = a; + u32* dst = (u32*)&efb[offset]; + u32 val = *dst & 0xffffffc0; + val |= (a32 >> 2) & 0x0000003f; + *dst = val; + } + break; + default: + ERROR_LOG(VIDEO, "Unsupported pixel format: %i", static_cast(bpmem.zcontrol.pixel_format)); + } +} + +static void SetPixelColorOnly(u32 offset, u8* rgb) +{ + switch (bpmem.zcontrol.pixel_format) + { + case PEControl::RGB8_Z24: + case PEControl::Z24: + { + u32 src = *(u32*)rgb; + u32* dst = (u32*)&efb[offset]; + u32 val = *dst & 0xff000000; + val |= src >> 8; + *dst = val; + } + break; + case PEControl::RGBA6_Z24: + { + u32 src = *(u32*)rgb; + u32* dst = (u32*)&efb[offset]; + u32 val = *dst & 0xff00003f; + val |= (src >> 4) & 0x00000fc0; // blue + val |= (src >> 6) & 0x0003f000; // green + val |= (src >> 8) & 0x00fc0000; // red + *dst = val; + } + break; + case PEControl::RGB565_Z16: + { + INFO_LOG(VIDEO, "RGB565_Z16 is not supported correctly yet"); + u32 src = *(u32*)rgb; + u32* dst = (u32*)&efb[offset]; + u32 val = *dst & 0xff000000; + val |= src >> 8; + *dst = val; + } + break; + default: + ERROR_LOG(VIDEO, "Unsupported pixel format: %i", static_cast(bpmem.zcontrol.pixel_format)); + } +} + +static void SetPixelAlphaColor(u32 offset, u8* color) +{ + switch (bpmem.zcontrol.pixel_format) + { + case PEControl::RGB8_Z24: + case PEControl::Z24: + { + u32 src = *(u32*)color; + u32* dst = (u32*)&efb[offset]; + u32 val = *dst & 0xff000000; + val |= src >> 8; + *dst = val; + } + break; + case PEControl::RGBA6_Z24: + { + u32 src = *(u32*)color; + u32* dst = (u32*)&efb[offset]; + u32 val = *dst & 0xff000000; + val |= (src >> 2) & 0x0000003f; // alpha + val |= (src >> 4) & 0x00000fc0; // blue + val |= (src >> 6) & 0x0003f000; // green + val |= (src >> 8) & 0x00fc0000; // red + *dst = val; + } + break; + case PEControl::RGB565_Z16: + { + INFO_LOG(VIDEO, "RGB565_Z16 is not supported correctly yet"); + u32 src = *(u32*)color; + u32* dst = (u32*)&efb[offset]; + u32 val = *dst & 0xff000000; + val |= src >> 8; + *dst = val; + } + break; + default: + ERROR_LOG(VIDEO, "Unsupported pixel format: %i", static_cast(bpmem.zcontrol.pixel_format)); + } +} + +static void GetPixelColor(u32 offset, u8* color) +{ + switch (bpmem.zcontrol.pixel_format) + { + case PEControl::RGB8_Z24: + case PEControl::Z24: + { + u32 src = *(u32*)&efb[offset]; + u32* dst = (u32*)color; + u32 val = 0xff | ((src & 0x00ffffff) << 8); + *dst = val; + } + break; + case PEControl::RGBA6_Z24: + { + u32 src = *(u32*)&efb[offset]; + color[ALP_C] = Convert6To8(src & 0x3f); + color[BLU_C] = Convert6To8((src >> 6) & 0x3f); + color[GRN_C] = Convert6To8((src >> 12) & 0x3f); + color[RED_C] = Convert6To8((src >> 18) & 0x3f); + } + break; + case PEControl::RGB565_Z16: + { + INFO_LOG(VIDEO, "RGB565_Z16 is not supported correctly yet"); + u32 src = *(u32*)&efb[offset]; + u32* dst = (u32*)color; + u32 val = 0xff | ((src & 0x00ffffff) << 8); + *dst = val; + } + break; + default: + ERROR_LOG(VIDEO, "Unsupported pixel format: %i", static_cast(bpmem.zcontrol.pixel_format)); + } +} + +static void SetPixelDepth(u32 offset, u32 depth) +{ + switch (bpmem.zcontrol.pixel_format) + { + case PEControl::RGB8_Z24: + case PEControl::RGBA6_Z24: + case PEControl::Z24: + { + u32* dst = (u32*)&efb[offset]; + u32 val = *dst & 0xff000000; + val |= depth & 0x00ffffff; + *dst = val; + } + break; + case PEControl::RGB565_Z16: + { + INFO_LOG(VIDEO, "RGB565_Z16 is not supported correctly yet"); + u32* dst = (u32*)&efb[offset]; + u32 val = *dst & 0xff000000; + val |= depth & 0x00ffffff; + *dst = val; + } + break; + default: + ERROR_LOG(VIDEO, "Unsupported pixel format: %i", static_cast(bpmem.zcontrol.pixel_format)); + } +} + +static u32 GetPixelDepth(u32 offset) +{ + u32 depth = 0; + + switch (bpmem.zcontrol.pixel_format) + { + case PEControl::RGB8_Z24: + case PEControl::RGBA6_Z24: + case PEControl::Z24: + { + depth = (*(u32*)&efb[offset]) & 0x00ffffff; + } + break; + case PEControl::RGB565_Z16: + { + INFO_LOG(VIDEO, "RGB565_Z16 is not supported correctly yet"); + depth = (*(u32*)&efb[offset]) & 0x00ffffff; + } + break; + default: + ERROR_LOG(VIDEO, "Unsupported pixel format: %i", static_cast(bpmem.zcontrol.pixel_format)); + } + + return depth; +} + +static u32 GetSourceFactor(u8* srcClr, u8* dstClr, BlendMode::BlendFactor mode) +{ + switch (mode) + { + case BlendMode::ZERO: + return 0; + case BlendMode::ONE: + return 0xffffffff; + case BlendMode::DSTCLR: + return *(u32*)dstClr; + case BlendMode::INVDSTCLR: + return 0xffffffff - *(u32*)dstClr; + case BlendMode::SRCALPHA: + { + u8 alpha = srcClr[ALP_C]; + u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; + return factor; + } + case BlendMode::INVSRCALPHA: + { + u8 alpha = 0xff - srcClr[ALP_C]; + u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; + return factor; + } + case BlendMode::DSTALPHA: + { + u8 alpha = dstClr[ALP_C]; + u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; + return factor; + } + case BlendMode::INVDSTALPHA: + { + u8 alpha = 0xff - dstClr[ALP_C]; + u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; + return factor; + } + } + + return 0; +} + +static u32 GetDestinationFactor(u8* srcClr, u8* dstClr, BlendMode::BlendFactor mode) +{ + switch (mode) + { + case BlendMode::ZERO: + return 0; + case BlendMode::ONE: + return 0xffffffff; + case BlendMode::SRCCLR: + return *(u32*)srcClr; + case BlendMode::INVSRCCLR: + return 0xffffffff - *(u32*)srcClr; + case BlendMode::SRCALPHA: + { + u8 alpha = srcClr[ALP_C]; + u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; + return factor; + } + case BlendMode::INVSRCALPHA: + { + u8 alpha = 0xff - srcClr[ALP_C]; + u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; + return factor; + } + case BlendMode::DSTALPHA: + { + u8 alpha = dstClr[ALP_C] & 0xff; + u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; + return factor; + } + case BlendMode::INVDSTALPHA: + { + u8 alpha = 0xff - dstClr[ALP_C]; + u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha; + return factor; + } + } + + return 0; +} + +static void BlendColor(u8* srcClr, u8* dstClr) +{ + u32 srcFactor = GetSourceFactor(srcClr, dstClr, bpmem.blendmode.srcfactor); + u32 dstFactor = GetDestinationFactor(srcClr, dstClr, bpmem.blendmode.dstfactor); + + for (int i = 0; i < 4; i++) + { + // add MSB of factors to make their range 0 -> 256 + u32 sf = (srcFactor & 0xff); + sf += sf >> 7; + + u32 df = (dstFactor & 0xff); + df += df >> 7; + + u32 color = (srcClr[i] * sf + dstClr[i] * df) >> 8; + dstClr[i] = (color > 255) ? 255 : color; + + dstFactor >>= 8; + srcFactor >>= 8; + } +} + +static void LogicBlend(u32 srcClr, u32* dstClr, BlendMode::LogicOp op) +{ + switch (op) + { + case BlendMode::CLEAR: + *dstClr = 0; + break; + case BlendMode::AND: + *dstClr = srcClr & *dstClr; + break; + case BlendMode::AND_REVERSE: + *dstClr = srcClr & (~*dstClr); + break; + case BlendMode::COPY: + *dstClr = srcClr; + break; + case BlendMode::AND_INVERTED: + *dstClr = (~srcClr) & *dstClr; + break; + case BlendMode::NOOP: + // Do nothing + break; + case BlendMode::XOR: + *dstClr = srcClr ^ *dstClr; + break; + case BlendMode::OR: + *dstClr = srcClr | *dstClr; + break; + case BlendMode::NOR: + *dstClr = ~(srcClr | *dstClr); + break; + case BlendMode::EQUIV: + *dstClr = ~(srcClr ^ *dstClr); + break; + case BlendMode::INVERT: + *dstClr = ~*dstClr; + break; + case BlendMode::OR_REVERSE: + *dstClr = srcClr | (~*dstClr); + break; + case BlendMode::COPY_INVERTED: + *dstClr = ~srcClr; + break; + case BlendMode::OR_INVERTED: + *dstClr = (~srcClr) | *dstClr; + break; + case BlendMode::NAND: + *dstClr = ~(srcClr & *dstClr); + break; + case BlendMode::SET: + *dstClr = 0xffffffff; + break; + } +} + +static void SubtractBlend(u8* srcClr, u8* dstClr) +{ + for (int i = 0; i < 4; i++) + { + int c = (int)dstClr[i] - (int)srcClr[i]; + dstClr[i] = (c < 0) ? 0 : c; + } +} + +static void Dither(u16 x, u16 y, u8* color) +{ + // No blending for RGB8 mode + if (!bpmem.blendmode.dither || bpmem.zcontrol.pixel_format != PEControl::PixelFormat::RGBA6_Z24) + return; + + // Flipper uses a standard 2x2 Bayer Matrix for 6 bit dithering + static const u8 dither[2][2] = {{0, 2}, {3, 1}}; + + // Only the color channels are dithered? + for (int i = BLU_C; i <= RED_C; i++) + color[i] = ((color[i] - (color[i] >> 6)) + dither[y & 1][x & 1]) & 0xfc; +} + +void BlendTev(u16 x, u16 y, u8* color) +{ + u32 dstClr; + u32 offset = GetColorOffset(x, y); + + u8* dstClrPtr = (u8*)&dstClr; + + GetPixelColor(offset, dstClrPtr); + + if (bpmem.blendmode.blendenable) + { + if (bpmem.blendmode.subtract) + SubtractBlend(color, dstClrPtr); + else + BlendColor(color, dstClrPtr); + } + else if (bpmem.blendmode.logicopenable) + { + LogicBlend(*((u32*)color), &dstClr, bpmem.blendmode.logicmode); + } + else + { + dstClrPtr = color; + } + + if (bpmem.dstalpha.enable) + dstClrPtr[ALP_C] = bpmem.dstalpha.alpha; + + if (bpmem.blendmode.colorupdate) + { + Dither(x, y, dstClrPtr); + if (bpmem.blendmode.alphaupdate) + SetPixelAlphaColor(offset, dstClrPtr); + else + SetPixelColorOnly(offset, dstClrPtr); + } + else if (bpmem.blendmode.alphaupdate) + { + SetPixelAlphaOnly(offset, dstClrPtr[ALP_C]); + } +} + +void SetColor(u16 x, u16 y, u8* color) +{ + u32 offset = GetColorOffset(x, y); + if (bpmem.blendmode.colorupdate) + { + if (bpmem.blendmode.alphaupdate) + SetPixelAlphaColor(offset, color); + else + SetPixelColorOnly(offset, color); + } + else if (bpmem.blendmode.alphaupdate) + { + SetPixelAlphaOnly(offset, color[ALP_C]); + } +} + +void SetDepth(u16 x, u16 y, u32 depth) +{ + if (bpmem.zmode.updateenable) + SetPixelDepth(GetDepthOffset(x, y), depth); +} + +void GetColor(u16 x, u16 y, u8* color) +{ + u32 offset = GetColorOffset(x, y); + GetPixelColor(offset, color); +} + +// For internal used only, return a non-normalized value, which saves work later. +void GetColorYUV(u16 x, u16 y, yuv444* out) +{ + u8 color[4]; + GetColor(x, y, color); + + // GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see + // http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion + out->Y = (u8)(0.257f * color[RED_C] + 0.504f * color[GRN_C] + 0.098f * color[BLU_C]); + out->U = (u8)(-0.148f * color[RED_C] + -0.291f * color[GRN_C] + 0.439f * color[BLU_C]); + out->V = (u8)(0.439f * color[RED_C] + -0.368f * color[GRN_C] + -0.071f * color[BLU_C]); +} + +u32 GetDepth(u16 x, u16 y) +{ + u32 offset = GetDepthOffset(x, y); + return GetPixelDepth(offset); +} + +u8* GetPixelPointer(u16 x, u16 y, bool depth) +{ + if (depth) + return &efb[GetDepthOffset(x, y)]; + return &efb[GetColorOffset(x, y)]; +} + +void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, + float Gamma) +{ + // FIXME: We should do Gamma correction + + if (!xfb_in_ram) + { + WARN_LOG(VIDEO, "Tried to copy to invalid XFB address"); + return; + } + + int left = sourceRc.left; + int right = sourceRc.right; + + // this assumes copies will always start on an even (YU) pixel and the + // copy always has an even width, which might not be true. + if (left & 1 || right & 1) + { + WARN_LOG(VIDEO, "Trying to copy XFB to from unaligned EFB source"); + // this will show up as wrongly encoded + } + + // Scanline buffer, leave room for borders + yuv444 scanline[EFB_WIDTH + 2]; + + // our internal yuv444 type is not normalized, so black is {0, 0, 0} instead of {16, 128, 128} + yuv444 black; + black.Y = 0; + black.U = 0; + black.V = 0; + + scanline[0] = black; // black border at start + scanline[right + 1] = black; // black border at end + + for (u16 y = sourceRc.top; y < sourceRc.bottom; y++) + { + // Get a scanline of YUV pixels in 4:4:4 format + + for (int i = 1, x = left; x < right; i++, x++) + { + GetColorYUV(x, y, &scanline[i]); + } + + // And Downsample them to 4:2:2 + for (int i = 1, x = left; x < right; i += 2, x += 2) + { + // YU pixel + xfb_in_ram[x].Y = scanline[i].Y + 16; + // we mix our color differences in 10 bit space so it will round more accurately + // U[i] = 1/4 * U[i-1] + 1/2 * U[i] + 1/4 * U[i+1] + xfb_in_ram[x].UV = + 128 + ((scanline[i - 1].U + (scanline[i].U << 1) + scanline[i + 1].U) >> 2); + + // YV pixel + xfb_in_ram[x + 1].Y = scanline[i + 1].Y + 16; + // V[i] = 1/4 * V[i-1] + 1/2 * V[i] + 1/4 * V[i+1] + xfb_in_ram[x + 1].UV = + 128 + ((scanline[i].V + (scanline[i + 1].V << 1) + scanline[i + 2].V) >> 2); + } + xfb_in_ram += fbWidth; + } +} + +// Like CopyToXFB, but we copy directly into the OpenGL color texture without going via GameCube +// main memory or doing a yuyv conversion +void BypassXFB(u8* texture, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma) +{ + if (fbWidth * fbHeight > MAX_XFB_WIDTH * MAX_XFB_HEIGHT) + { + ERROR_LOG(VIDEO, "Framebuffer is too large: %ix%i", fbWidth, fbHeight); + return; + } + + u32 color; + u8* colorPtr = (u8*)&color; + u32* texturePtr = (u32*)texture; + u32 textureAddress = 0; + + int left = sourceRc.left; + int right = sourceRc.right; + + for (u16 y = sourceRc.top; y < sourceRc.bottom; y++) + { + for (u16 x = left; x < right; x++) + { + GetColor(x, y, colorPtr); + texturePtr[textureAddress++] = Common::swap32(color | 0xFF); + } + } +} + +bool ZCompare(u16 x, u16 y, u32 z) +{ + u32 offset = GetDepthOffset(x, y); + u32 depth = GetPixelDepth(offset); + + bool pass; + + switch (bpmem.zmode.func) + { + case ZMode::NEVER: + pass = false; + break; + case ZMode::LESS: + pass = z < depth; + break; + case ZMode::EQUAL: + pass = z == depth; + break; + case ZMode::LEQUAL: + pass = z <= depth; + break; + case ZMode::GREATER: + pass = z > depth; + break; + case ZMode::NEQUAL: + pass = z != depth; + break; + case ZMode::GEQUAL: + pass = z >= depth; + break; + case ZMode::ALWAYS: + pass = true; + break; + default: + pass = false; + ERROR_LOG(VIDEO, "Bad Z compare mode %i", (int)bpmem.zmode.func); + } + + if (pass && bpmem.zmode.updateenable) + { + SetPixelDepth(offset, z); + } + + return pass; +} } diff --git a/Source/Core/VideoBackends/Software/EfbInterface.h b/Source/Core/VideoBackends/Software/EfbInterface.h index 9355d4678b..a116d700de 100644 --- a/Source/Core/VideoBackends/Software/EfbInterface.h +++ b/Source/Core/VideoBackends/Software/EfbInterface.h @@ -10,67 +10,68 @@ namespace EfbInterface { - const int DEPTH_BUFFER_START = EFB_WIDTH * EFB_HEIGHT * 3; +const int DEPTH_BUFFER_START = EFB_WIDTH * EFB_HEIGHT * 3; - // xfb color format - packed so the compiler doesn't mess with alignment -#pragma pack(push,1) - struct yuv422_packed - { - u8 Y; - u8 UV; - }; +// xfb color format - packed so the compiler doesn't mess with alignment +#pragma pack(push, 1) +struct yuv422_packed +{ + u8 Y; + u8 UV; +}; #pragma pack(pop) - // But this struct is only used internally, so we could optimise alignment - struct yuv444 - { - u8 Y; - s8 U; - s8 V; - }; +// But this struct is only used internally, so we could optimise alignment +struct yuv444 +{ + u8 Y; + s8 U; + s8 V; +}; - enum - { - ALP_C, - BLU_C, - GRN_C, - RED_C - }; +enum +{ + ALP_C, + BLU_C, + GRN_C, + RED_C +}; - // color order is ABGR in order to emulate RGBA on little-endian hardware +// color order is ABGR in order to emulate RGBA on little-endian hardware - // does full blending of an incoming pixel - void BlendTev(u16 x, u16 y, u8 *color); +// does full blending of an incoming pixel +void BlendTev(u16 x, u16 y, u8* color); - // compare z at location x,y - // writes it if it passes - // returns result of compare. - bool ZCompare(u16 x, u16 y, u32 z); +// compare z at location x,y +// writes it if it passes +// returns result of compare. +bool ZCompare(u16 x, u16 y, u32 z); - // sets the color and alpha - void SetColor(u16 x, u16 y, u8 *color); - void SetDepth(u16 x, u16 y, u32 depth); +// sets the color and alpha +void SetColor(u16 x, u16 y, u8* color); +void SetDepth(u16 x, u16 y, u32 depth); - void GetColor(u16 x, u16 y, u8 *color); - void GetColorYUV(u16 x, u16 y, yuv444 *color); - u32 GetDepth(u16 x, u16 y); +void GetColor(u16 x, u16 y, u8* color); +void GetColorYUV(u16 x, u16 y, yuv444* color); +u32 GetDepth(u16 x, u16 y); - u8* GetPixelPointer(u16 x, u16 y, bool depth); +u8* GetPixelPointer(u16 x, u16 y, bool depth); - void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma); - void BypassXFB(u8* texture, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma); +void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, + float Gamma); +void BypassXFB(u8* texture, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma); - extern u32 perf_values[PQ_NUM_MEMBERS]; - inline void IncPerfCounterQuadCount(PerfQueryType type) - { - // NOTE: hardware doesn't process individual pixels but quads instead. - // Current software renderer architecture works on pixels though, so - // we have this "quad" hack here to only increment the registers on - // every fourth rendered pixel - static u32 quad[PQ_NUM_MEMBERS]; - if (++quad[type] != 3) - return; - quad[type] = 0; - ++perf_values[type]; - } +extern u32 perf_values[PQ_NUM_MEMBERS]; +inline void IncPerfCounterQuadCount(PerfQueryType type) +{ + // NOTE: hardware doesn't process individual pixels but quads instead. + // Current software renderer architecture works on pixels though, so + // we have this "quad" hack here to only increment the registers on + // every fourth rendered pixel + static u32 quad[PQ_NUM_MEMBERS]; + if (++quad[type] != 3) + return; + quad[type] = 0; + ++perf_values[type]; +} } diff --git a/Source/Core/VideoBackends/Software/NativeVertexFormat.h b/Source/Core/VideoBackends/Software/NativeVertexFormat.h index 6fb0f7c1ae..a80ebc80bb 100644 --- a/Source/Core/VideoBackends/Software/NativeVertexFormat.h +++ b/Source/Core/VideoBackends/Software/NativeVertexFormat.h @@ -9,72 +9,72 @@ struct Vec4 { - float x; - float y; - float z; - float w; + float x; + float y; + float z; + float w; }; struct InputVertexData { - u8 posMtx; - u8 texMtx[8]; + u8 posMtx; + u8 texMtx[8]; - Vec3 position; - Vec3 normal[3]; - u8 color[2][4]; - float texCoords[8][2]; + Vec3 position; + Vec3 normal[3]; + u8 color[2][4]; + float texCoords[8][2]; }; struct OutputVertexData { - // components in color channels - enum - { - RED_C, - GRN_C, - BLU_C, - ALP_C - }; + // components in color channels + enum + { + RED_C, + GRN_C, + BLU_C, + ALP_C + }; - Vec3 mvPosition = {}; - Vec4 projectedPosition = {}; - Vec3 screenPosition = {}; - Vec3 normal[3] = {}; - u8 color[2][4] = {}; - Vec3 texCoords[8] = {}; + Vec3 mvPosition = {}; + Vec4 projectedPosition = {}; + Vec3 screenPosition = {}; + Vec3 normal[3] = {}; + u8 color[2][4] = {}; + Vec3 texCoords[8] = {}; - void Lerp(float t, OutputVertexData *a, OutputVertexData *b) - { - #define LINTERP(T, OUT, IN) (OUT) + ((IN - OUT) * T) + void Lerp(float t, OutputVertexData* a, OutputVertexData* b) + { +#define LINTERP(T, OUT, IN) (OUT) + ((IN - OUT) * T) - #define LINTERP_INT(T, OUT, IN) (OUT) + (((IN - OUT) * T) >> 8) +#define LINTERP_INT(T, OUT, IN) (OUT) + (((IN - OUT) * T) >> 8) - mvPosition = LINTERP(t, a->mvPosition, b->mvPosition); + mvPosition = LINTERP(t, a->mvPosition, b->mvPosition); - projectedPosition.x = LINTERP(t, a->projectedPosition.x, b->projectedPosition.x); - projectedPosition.y = LINTERP(t, a->projectedPosition.y, b->projectedPosition.y); - projectedPosition.z = LINTERP(t, a->projectedPosition.z, b->projectedPosition.z); - projectedPosition.w = LINTERP(t, a->projectedPosition.w, b->projectedPosition.w); + projectedPosition.x = LINTERP(t, a->projectedPosition.x, b->projectedPosition.x); + projectedPosition.y = LINTERP(t, a->projectedPosition.y, b->projectedPosition.y); + projectedPosition.z = LINTERP(t, a->projectedPosition.z, b->projectedPosition.z); + projectedPosition.w = LINTERP(t, a->projectedPosition.w, b->projectedPosition.w); - for (int i = 0; i < 3; ++i) - { - normal[i] = LINTERP(t, a->normal[i], b->normal[i]); - } + for (int i = 0; i < 3; ++i) + { + normal[i] = LINTERP(t, a->normal[i], b->normal[i]); + } - u16 t_int = (u16)(t * 256); - for (int i = 0; i < 4; ++i) - { - color[0][i] = LINTERP_INT(t_int, a->color[0][i], b->color[0][i]); - color[1][i] = LINTERP_INT(t_int, a->color[1][i], b->color[1][i]); - } + u16 t_int = (u16)(t * 256); + for (int i = 0; i < 4; ++i) + { + color[0][i] = LINTERP_INT(t_int, a->color[0][i], b->color[0][i]); + color[1][i] = LINTERP_INT(t_int, a->color[1][i], b->color[1][i]); + } - for (int i = 0; i < 8; ++i) - { - texCoords[i] = LINTERP(t, a->texCoords[i], b->texCoords[i]); - } + for (int i = 0; i < 8; ++i) + { + texCoords[i] = LINTERP(t, a->texCoords[i], b->texCoords[i]); + } - #undef LINTERP - #undef LINTERP_INT - } +#undef LINTERP +#undef LINTERP_INT + } }; diff --git a/Source/Core/VideoBackends/Software/Rasterizer.cpp b/Source/Core/VideoBackends/Software/Rasterizer.cpp index 5e835ba91a..e4ebdd1234 100644 --- a/Source/Core/VideoBackends/Software/Rasterizer.cpp +++ b/Source/Core/VideoBackends/Software/Rasterizer.cpp @@ -34,427 +34,436 @@ static RasterBlock rasterBlock; void Init() { - tev.Init(); + tev.Init(); - // Set initial z reference plane in the unlikely case that zfreeze is enabled when drawing the first primitive. - // TODO: This is just a guess! - ZSlope.dfdx = ZSlope.dfdy = 0.f; - ZSlope.f0 = 1.f; + // Set initial z reference plane in the unlikely case that zfreeze is enabled when drawing the + // first primitive. + // TODO: This is just a guess! + ZSlope.dfdx = ZSlope.dfdy = 0.f; + ZSlope.f0 = 1.f; } // Returns approximation of log2(f) in s28.4 // results are close enough to use for LOD static s32 FixedLog2(float f) { - u32 x; - std::memcpy(&x, &f, sizeof(u32)); + u32 x; + std::memcpy(&x, &f, sizeof(u32)); - s32 logInt = ((x & 0x7F800000) >> 19) - 2032; // integer part - s32 logFract = (x & 0x007fffff) >> 19; // approximate fractional part + s32 logInt = ((x & 0x7F800000) >> 19) - 2032; // integer part + s32 logFract = (x & 0x007fffff) >> 19; // approximate fractional part - return logInt + logFract; + return logInt + logFract; } static inline int iround(float x) { - int t = (int)x; - if ((x - t) >= 0.5) - return t + 1; + int t = (int)x; + if ((x - t) >= 0.5) + return t + 1; - return t; + return t; } void SetTevReg(int reg, int comp, s16 color) { - tev.SetRegColor(reg, comp, color); + tev.SetRegColor(reg, comp, color); } static void Draw(s32 x, s32 y, s32 xi, s32 yi) { - INCSTAT(stats.thisFrame.rasterizedPixels); + INCSTAT(stats.thisFrame.rasterizedPixels); - float dx = vertexOffsetX + (float)(x - vertex0X); - float dy = vertexOffsetY + (float)(y - vertex0Y); + float dx = vertexOffsetX + (float)(x - vertex0X); + float dy = vertexOffsetY + (float)(y - vertex0Y); - s32 z = (s32)MathUtil::Clamp(ZSlope.GetValue(dx, dy), 0.0f, 16777215.0f); + s32 z = (s32)MathUtil::Clamp(ZSlope.GetValue(dx, dy), 0.0f, 16777215.0f); - if (bpmem.UseEarlyDepthTest() && g_ActiveConfig.bZComploc) - { - // TODO: Test if perf regs are incremented even if test is disabled - EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT_ZCOMPLOC); - if (bpmem.zmode.testenable) - { - // early z - if (!EfbInterface::ZCompare(x, y, z)) - return; - } - EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_OUTPUT_ZCOMPLOC); - } + if (bpmem.UseEarlyDepthTest() && g_ActiveConfig.bZComploc) + { + // TODO: Test if perf regs are incremented even if test is disabled + EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT_ZCOMPLOC); + if (bpmem.zmode.testenable) + { + // early z + if (!EfbInterface::ZCompare(x, y, z)) + return; + } + EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_OUTPUT_ZCOMPLOC); + } - RasterBlockPixel& pixel = rasterBlock.Pixel[xi][yi]; + RasterBlockPixel& pixel = rasterBlock.Pixel[xi][yi]; - tev.Position[0] = x; - tev.Position[1] = y; - tev.Position[2] = z; + tev.Position[0] = x; + tev.Position[1] = y; + tev.Position[2] = z; - // colors - for (unsigned int i = 0; i < bpmem.genMode.numcolchans; i++) - { - for (int comp = 0; comp < 4; comp++) - { - u16 color = (u16)ColorSlopes[i][comp].GetValue(dx, dy); + // colors + for (unsigned int i = 0; i < bpmem.genMode.numcolchans; i++) + { + for (int comp = 0; comp < 4; comp++) + { + u16 color = (u16)ColorSlopes[i][comp].GetValue(dx, dy); - // clamp color value to 0 - u16 mask = ~(color >> 8); + // clamp color value to 0 + u16 mask = ~(color >> 8); - tev.Color[i][comp] = color & mask; - } - } + tev.Color[i][comp] = color & mask; + } + } - // tex coords - for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++) - { - // multiply by 128 because TEV stores UVs as s17.7 - tev.Uv[i].s = (s32)(pixel.Uv[i][0] * 128); - tev.Uv[i].t = (s32)(pixel.Uv[i][1] * 128); - } + // tex coords + for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++) + { + // multiply by 128 because TEV stores UVs as s17.7 + tev.Uv[i].s = (s32)(pixel.Uv[i][0] * 128); + tev.Uv[i].t = (s32)(pixel.Uv[i][1] * 128); + } - for (unsigned int i = 0; i < bpmem.genMode.numindstages; i++) - { - tev.IndirectLod[i] = rasterBlock.IndirectLod[i]; - tev.IndirectLinear[i] = rasterBlock.IndirectLinear[i]; - } + for (unsigned int i = 0; i < bpmem.genMode.numindstages; i++) + { + tev.IndirectLod[i] = rasterBlock.IndirectLod[i]; + tev.IndirectLinear[i] = rasterBlock.IndirectLinear[i]; + } - for (unsigned int i = 0; i <= bpmem.genMode.numtevstages; i++) - { - tev.TextureLod[i] = rasterBlock.TextureLod[i]; - tev.TextureLinear[i] = rasterBlock.TextureLinear[i]; - } + for (unsigned int i = 0; i <= bpmem.genMode.numtevstages; i++) + { + tev.TextureLod[i] = rasterBlock.TextureLod[i]; + tev.TextureLinear[i] = rasterBlock.TextureLinear[i]; + } - tev.Draw(); + tev.Draw(); } static void InitTriangle(float X1, float Y1, s32 xi, s32 yi) { - vertex0X = xi; - vertex0Y = yi; + vertex0X = xi; + vertex0Y = yi; - // adjust a little less than 0.5 - const float adjust = 0.495f; + // adjust a little less than 0.5 + const float adjust = 0.495f; - vertexOffsetX = ((float)xi - X1) + adjust; - vertexOffsetY = ((float)yi - Y1) + adjust; + vertexOffsetX = ((float)xi - X1) + adjust; + vertexOffsetY = ((float)yi - Y1) + adjust; } -static void InitSlope(Slope *slope, float f1, float f2, float f3, float DX31, float DX12, float DY12, float DY31) +static void InitSlope(Slope* slope, float f1, float f2, float f3, float DX31, float DX12, + float DY12, float DY31) { - float DF31 = f3 - f1; - float DF21 = f2 - f1; - float a = DF31 * -DY12 - DF21 * DY31; - float b = DX31 * DF21 + DX12 * DF31; - float c = -DX12 * DY31 - DX31 * -DY12; - slope->dfdx = -a / c; - slope->dfdy = -b / c; - slope->f0 = f1; + float DF31 = f3 - f1; + float DF21 = f2 - f1; + float a = DF31 * -DY12 - DF21 * DY31; + float b = DX31 * DF21 + DX12 * DF31; + float c = -DX12 * DY31 - DX31 * -DY12; + slope->dfdx = -a / c; + slope->dfdy = -b / c; + slope->f0 = f1; } static inline void CalculateLOD(s32* lodp, bool* linear, u32 texmap, u32 texcoord) { - const FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1]; - const u8 subTexmap = texmap & 3; + const FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1]; + const u8 subTexmap = texmap & 3; - // LOD calculation requires data from the texture mode for bias, etc. - // it does not seem to use the actual texture size - const TexMode0& tm0 = texUnit.texMode0[subTexmap]; - const TexMode1& tm1 = texUnit.texMode1[subTexmap]; + // LOD calculation requires data from the texture mode for bias, etc. + // it does not seem to use the actual texture size + const TexMode0& tm0 = texUnit.texMode0[subTexmap]; + const TexMode1& tm1 = texUnit.texMode1[subTexmap]; - float sDelta, tDelta; - if (tm0.diag_lod) - { - float *uv0 = rasterBlock.Pixel[0][0].Uv[texcoord]; - float *uv1 = rasterBlock.Pixel[1][1].Uv[texcoord]; + float sDelta, tDelta; + if (tm0.diag_lod) + { + float* uv0 = rasterBlock.Pixel[0][0].Uv[texcoord]; + float* uv1 = rasterBlock.Pixel[1][1].Uv[texcoord]; - sDelta = fabsf(uv0[0] - uv1[0]); - tDelta = fabsf(uv0[1] - uv1[1]); - } - else - { - float *uv0 = rasterBlock.Pixel[0][0].Uv[texcoord]; - float *uv1 = rasterBlock.Pixel[1][0].Uv[texcoord]; - float *uv2 = rasterBlock.Pixel[0][1].Uv[texcoord]; + sDelta = fabsf(uv0[0] - uv1[0]); + tDelta = fabsf(uv0[1] - uv1[1]); + } + else + { + float* uv0 = rasterBlock.Pixel[0][0].Uv[texcoord]; + float* uv1 = rasterBlock.Pixel[1][0].Uv[texcoord]; + float* uv2 = rasterBlock.Pixel[0][1].Uv[texcoord]; - sDelta = std::max(fabsf(uv0[0] - uv1[0]), fabsf(uv0[0] - uv2[0])); - tDelta = std::max(fabsf(uv0[1] - uv1[1]), fabsf(uv0[1] - uv2[1])); - } + sDelta = std::max(fabsf(uv0[0] - uv1[0]), fabsf(uv0[0] - uv2[0])); + tDelta = std::max(fabsf(uv0[1] - uv1[1]), fabsf(uv0[1] - uv2[1])); + } - // get LOD in s28.4 - s32 lod = FixedLog2(std::max(sDelta, tDelta)); + // get LOD in s28.4 + s32 lod = FixedLog2(std::max(sDelta, tDelta)); - // bias is s2.5 - int bias = tm0.lod_bias; - bias >>= 1; - lod += bias; + // bias is s2.5 + int bias = tm0.lod_bias; + bias >>= 1; + lod += bias; - *linear = ((lod > 0 && (tm0.min_filter & 4)) || (lod <= 0 && tm0.mag_filter)); + *linear = ((lod > 0 && (tm0.min_filter & 4)) || (lod <= 0 && tm0.mag_filter)); - // NOTE: The order of comparisons for this clamp check matters. - if (lod > static_cast(tm1.max_lod)) - lod = static_cast(tm1.max_lod); - else if (lod < static_cast(tm1.min_lod)) - lod = static_cast(tm1.min_lod); + // NOTE: The order of comparisons for this clamp check matters. + if (lod > static_cast(tm1.max_lod)) + lod = static_cast(tm1.max_lod); + else if (lod < static_cast(tm1.min_lod)) + lod = static_cast(tm1.min_lod); - *lodp = lod; + *lodp = lod; } static void BuildBlock(s32 blockX, s32 blockY) { - for (s32 yi = 0; yi < BLOCK_SIZE; yi++) - { - for (s32 xi = 0; xi < BLOCK_SIZE; xi++) - { - RasterBlockPixel& pixel = rasterBlock.Pixel[xi][yi]; + for (s32 yi = 0; yi < BLOCK_SIZE; yi++) + { + for (s32 xi = 0; xi < BLOCK_SIZE; xi++) + { + RasterBlockPixel& pixel = rasterBlock.Pixel[xi][yi]; - float dx = vertexOffsetX + (float)(xi + blockX - vertex0X); - float dy = vertexOffsetY + (float)(yi + blockY - vertex0Y); + float dx = vertexOffsetX + (float)(xi + blockX - vertex0X); + float dy = vertexOffsetY + (float)(yi + blockY - vertex0Y); - float invW = 1.0f / WSlope.GetValue(dx, dy); - pixel.InvW = invW; + float invW = 1.0f / WSlope.GetValue(dx, dy); + pixel.InvW = invW; - // tex coords - for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++) - { - float projection = invW; - if (xfmem.texMtxInfo[i].projection) - { - float q = TexSlopes[i][2].GetValue(dx, dy) * invW; - if (q != 0.0f) - projection = invW / q; - } + // tex coords + for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++) + { + float projection = invW; + if (xfmem.texMtxInfo[i].projection) + { + float q = TexSlopes[i][2].GetValue(dx, dy) * invW; + if (q != 0.0f) + projection = invW / q; + } - pixel.Uv[i][0] = TexSlopes[i][0].GetValue(dx, dy) * projection; - pixel.Uv[i][1] = TexSlopes[i][1].GetValue(dx, dy) * projection; - } - } - } + pixel.Uv[i][0] = TexSlopes[i][0].GetValue(dx, dy) * projection; + pixel.Uv[i][1] = TexSlopes[i][1].GetValue(dx, dy) * projection; + } + } + } - u32 indref = bpmem.tevindref.hex; - for (unsigned int i = 0; i < bpmem.genMode.numindstages; i++) - { - u32 texmap = indref & 3; - indref >>= 3; - u32 texcoord = indref & 3; - indref >>= 3; + u32 indref = bpmem.tevindref.hex; + for (unsigned int i = 0; i < bpmem.genMode.numindstages; i++) + { + u32 texmap = indref & 3; + indref >>= 3; + u32 texcoord = indref & 3; + indref >>= 3; - CalculateLOD(&rasterBlock.IndirectLod[i], &rasterBlock.IndirectLinear[i], texmap, texcoord); - } + CalculateLOD(&rasterBlock.IndirectLod[i], &rasterBlock.IndirectLinear[i], texmap, texcoord); + } - for (unsigned int i = 0; i <= bpmem.genMode.numtevstages; i++) - { - int stageOdd = i&1; - const TwoTevStageOrders& order = bpmem.tevorders[i >> 1]; - if (order.getEnable(stageOdd)) - { - u32 texmap = order.getTexMap(stageOdd); - u32 texcoord = order.getTexCoord(stageOdd); + for (unsigned int i = 0; i <= bpmem.genMode.numtevstages; i++) + { + int stageOdd = i & 1; + const TwoTevStageOrders& order = bpmem.tevorders[i >> 1]; + if (order.getEnable(stageOdd)) + { + u32 texmap = order.getTexMap(stageOdd); + u32 texcoord = order.getTexCoord(stageOdd); - CalculateLOD(&rasterBlock.TextureLod[i], &rasterBlock.TextureLinear[i], texmap, texcoord); - } - } + CalculateLOD(&rasterBlock.TextureLod[i], &rasterBlock.TextureLinear[i], texmap, texcoord); + } + } } -void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2) +void DrawTriangleFrontFace(OutputVertexData* v0, OutputVertexData* v1, OutputVertexData* v2) { - INCSTAT(stats.thisFrame.numTrianglesDrawn); + INCSTAT(stats.thisFrame.numTrianglesDrawn); - // adapted from http://devmaster.net/posts/6145/advanced-rasterization + // adapted from http://devmaster.net/posts/6145/advanced-rasterization - // 28.4 fixed-pou32 coordinates. rounded to nearest and adjusted to match hardware output - // could also take floor and adjust -8 - const s32 Y1 = iround(16.0f * v0->screenPosition[1]) - 9; - const s32 Y2 = iround(16.0f * v1->screenPosition[1]) - 9; - const s32 Y3 = iround(16.0f * v2->screenPosition[1]) - 9; + // 28.4 fixed-pou32 coordinates. rounded to nearest and adjusted to match hardware output + // could also take floor and adjust -8 + const s32 Y1 = iround(16.0f * v0->screenPosition[1]) - 9; + const s32 Y2 = iround(16.0f * v1->screenPosition[1]) - 9; + const s32 Y3 = iround(16.0f * v2->screenPosition[1]) - 9; - const s32 X1 = iround(16.0f * v0->screenPosition[0]) - 9; - const s32 X2 = iround(16.0f * v1->screenPosition[0]) - 9; - const s32 X3 = iround(16.0f * v2->screenPosition[0]) - 9; + const s32 X1 = iround(16.0f * v0->screenPosition[0]) - 9; + const s32 X2 = iround(16.0f * v1->screenPosition[0]) - 9; + const s32 X3 = iround(16.0f * v2->screenPosition[0]) - 9; - // Deltas - const s32 DX12 = X1 - X2; - const s32 DX23 = X2 - X3; - const s32 DX31 = X3 - X1; + // Deltas + const s32 DX12 = X1 - X2; + const s32 DX23 = X2 - X3; + const s32 DX31 = X3 - X1; - const s32 DY12 = Y1 - Y2; - const s32 DY23 = Y2 - Y3; - const s32 DY31 = Y3 - Y1; + const s32 DY12 = Y1 - Y2; + const s32 DY23 = Y2 - Y3; + const s32 DY31 = Y3 - Y1; - // Fixed-pos32 deltas - const s32 FDX12 = DX12 * 16; - const s32 FDX23 = DX23 * 16; - const s32 FDX31 = DX31 * 16; + // Fixed-pos32 deltas + const s32 FDX12 = DX12 * 16; + const s32 FDX23 = DX23 * 16; + const s32 FDX31 = DX31 * 16; - const s32 FDY12 = DY12 * 16; - const s32 FDY23 = DY23 * 16; - const s32 FDY31 = DY31 * 16; + const s32 FDY12 = DY12 * 16; + const s32 FDY23 = DY23 * 16; + const s32 FDY31 = DY31 * 16; - // Bounding rectangle - s32 minx = (std::min(std::min(X1, X2), X3) + 0xF) >> 4; - s32 maxx = (std::max(std::max(X1, X2), X3) + 0xF) >> 4; - s32 miny = (std::min(std::min(Y1, Y2), Y3) + 0xF) >> 4; - s32 maxy = (std::max(std::max(Y1, Y2), Y3) + 0xF) >> 4; + // Bounding rectangle + s32 minx = (std::min(std::min(X1, X2), X3) + 0xF) >> 4; + s32 maxx = (std::max(std::max(X1, X2), X3) + 0xF) >> 4; + s32 miny = (std::min(std::min(Y1, Y2), Y3) + 0xF) >> 4; + s32 maxy = (std::max(std::max(Y1, Y2), Y3) + 0xF) >> 4; - // scissor - int xoff = bpmem.scissorOffset.x * 2 - 342; - int yoff = bpmem.scissorOffset.y * 2 - 342; + // scissor + int xoff = bpmem.scissorOffset.x * 2 - 342; + int yoff = bpmem.scissorOffset.y * 2 - 342; - s32 scissorLeft = bpmem.scissorTL.x - xoff - 342; - if (scissorLeft < 0) - scissorLeft = 0; + s32 scissorLeft = bpmem.scissorTL.x - xoff - 342; + if (scissorLeft < 0) + scissorLeft = 0; - s32 scissorTop = bpmem.scissorTL.y - yoff - 342; - if (scissorTop < 0) - scissorTop = 0; + s32 scissorTop = bpmem.scissorTL.y - yoff - 342; + if (scissorTop < 0) + scissorTop = 0; - s32 scissorRight = bpmem.scissorBR.x - xoff - 341; - if (scissorRight > EFB_WIDTH) - scissorRight = EFB_WIDTH; + s32 scissorRight = bpmem.scissorBR.x - xoff - 341; + if (scissorRight > EFB_WIDTH) + scissorRight = EFB_WIDTH; - s32 scissorBottom = bpmem.scissorBR.y - yoff - 341; - if (scissorBottom > EFB_HEIGHT) - scissorBottom = EFB_HEIGHT; + s32 scissorBottom = bpmem.scissorBR.y - yoff - 341; + if (scissorBottom > EFB_HEIGHT) + scissorBottom = EFB_HEIGHT; - minx = std::max(minx, scissorLeft); - maxx = std::min(maxx, scissorRight); - miny = std::max(miny, scissorTop); - maxy = std::min(maxy, scissorBottom); + minx = std::max(minx, scissorLeft); + maxx = std::min(maxx, scissorRight); + miny = std::max(miny, scissorTop); + maxy = std::min(maxy, scissorBottom); - if (minx >= maxx || miny >= maxy) - return; + if (minx >= maxx || miny >= maxy) + return; - // Setup slopes - float fltx1 = v0->screenPosition.x; - float flty1 = v0->screenPosition.y; - float fltdx31 = v2->screenPosition.x - fltx1; - float fltdx12 = fltx1 - v1->screenPosition.x; - float fltdy12 = flty1 - v1->screenPosition.y; - float fltdy31 = v2->screenPosition.y - flty1; + // Setup slopes + float fltx1 = v0->screenPosition.x; + float flty1 = v0->screenPosition.y; + float fltdx31 = v2->screenPosition.x - fltx1; + float fltdx12 = fltx1 - v1->screenPosition.x; + float fltdy12 = flty1 - v1->screenPosition.y; + float fltdy31 = v2->screenPosition.y - flty1; - InitTriangle(fltx1, flty1, (X1 + 0xF) >> 4, (Y1 + 0xF) >> 4); + InitTriangle(fltx1, flty1, (X1 + 0xF) >> 4, (Y1 + 0xF) >> 4); - float w[3] = { 1.0f / v0->projectedPosition.w, 1.0f / v1->projectedPosition.w, 1.0f / v2->projectedPosition.w }; - InitSlope(&WSlope, w[0], w[1], w[2], fltdx31, fltdx12, fltdy12, fltdy31); + float w[3] = {1.0f / v0->projectedPosition.w, 1.0f / v1->projectedPosition.w, + 1.0f / v2->projectedPosition.w}; + InitSlope(&WSlope, w[0], w[1], w[2], fltdx31, fltdx12, fltdy12, fltdy31); - // TODO: The zfreeze emulation is not quite correct, yet! - // Many things might prevent us from reaching this line (culling, clipping, scissoring). - // However, the zslope is always guaranteed to be calculated unless all vertices are trivially rejected during clipping! - // We're currently sloppy at this since we abort early if any of the culling/clipping/scissoring tests fail. - if (!bpmem.genMode.zfreeze || !g_ActiveConfig.bZFreeze) - InitSlope(&ZSlope, v0->screenPosition[2], v1->screenPosition[2], v2->screenPosition[2], fltdx31, fltdx12, fltdy12, fltdy31); + // TODO: The zfreeze emulation is not quite correct, yet! + // Many things might prevent us from reaching this line (culling, clipping, scissoring). + // However, the zslope is always guaranteed to be calculated unless all vertices are trivially + // rejected during clipping! + // We're currently sloppy at this since we abort early if any of the culling/clipping/scissoring + // tests fail. + if (!bpmem.genMode.zfreeze || !g_ActiveConfig.bZFreeze) + InitSlope(&ZSlope, v0->screenPosition[2], v1->screenPosition[2], v2->screenPosition[2], fltdx31, + fltdx12, fltdy12, fltdy31); - for (unsigned int i = 0; i < bpmem.genMode.numcolchans; i++) - { - for (int comp = 0; comp < 4; comp++) - InitSlope(&ColorSlopes[i][comp], v0->color[i][comp], v1->color[i][comp], v2->color[i][comp], fltdx31, fltdx12, fltdy12, fltdy31); - } + for (unsigned int i = 0; i < bpmem.genMode.numcolchans; i++) + { + for (int comp = 0; comp < 4; comp++) + InitSlope(&ColorSlopes[i][comp], v0->color[i][comp], v1->color[i][comp], v2->color[i][comp], + fltdx31, fltdx12, fltdy12, fltdy31); + } - for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++) - { - for (int comp = 0; comp < 3; comp++) - InitSlope(&TexSlopes[i][comp], v0->texCoords[i][comp] * w[0], v1->texCoords[i][comp] * w[1], v2->texCoords[i][comp] * w[2], fltdx31, fltdx12, fltdy12, fltdy31); - } + for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++) + { + for (int comp = 0; comp < 3; comp++) + InitSlope(&TexSlopes[i][comp], v0->texCoords[i][comp] * w[0], v1->texCoords[i][comp] * w[1], + v2->texCoords[i][comp] * w[2], fltdx31, fltdx12, fltdy12, fltdy31); + } - // Half-edge constants - s32 C1 = DY12 * X1 - DX12 * Y1; - s32 C2 = DY23 * X2 - DX23 * Y2; - s32 C3 = DY31 * X3 - DX31 * Y3; + // Half-edge constants + s32 C1 = DY12 * X1 - DX12 * Y1; + s32 C2 = DY23 * X2 - DX23 * Y2; + s32 C3 = DY31 * X3 - DX31 * Y3; - // Correct for fill convention - if (DY12 < 0 || (DY12 == 0 && DX12 > 0)) C1++; - if (DY23 < 0 || (DY23 == 0 && DX23 > 0)) C2++; - if (DY31 < 0 || (DY31 == 0 && DX31 > 0)) C3++; + // Correct for fill convention + if (DY12 < 0 || (DY12 == 0 && DX12 > 0)) + C1++; + if (DY23 < 0 || (DY23 == 0 && DX23 > 0)) + C2++; + if (DY31 < 0 || (DY31 == 0 && DX31 > 0)) + C3++; - // Start in corner of 8x8 block - minx &= ~(BLOCK_SIZE - 1); - miny &= ~(BLOCK_SIZE - 1); + // Start in corner of 8x8 block + minx &= ~(BLOCK_SIZE - 1); + miny &= ~(BLOCK_SIZE - 1); - // Loop through blocks - for (s32 y = miny; y < maxy; y += BLOCK_SIZE) - { - for (s32 x = minx; x < maxx; x += BLOCK_SIZE) - { - // Corners of block - s32 x0 = x << 4; - s32 x1 = (x + BLOCK_SIZE - 1) << 4; - s32 y0 = y << 4; - s32 y1 = (y + BLOCK_SIZE - 1) << 4; + // Loop through blocks + for (s32 y = miny; y < maxy; y += BLOCK_SIZE) + { + for (s32 x = minx; x < maxx; x += BLOCK_SIZE) + { + // Corners of block + s32 x0 = x << 4; + s32 x1 = (x + BLOCK_SIZE - 1) << 4; + s32 y0 = y << 4; + s32 y1 = (y + BLOCK_SIZE - 1) << 4; - // Evaluate half-space functions - bool a00 = C1 + DX12 * y0 - DY12 * x0 > 0; - bool a10 = C1 + DX12 * y0 - DY12 * x1 > 0; - bool a01 = C1 + DX12 * y1 - DY12 * x0 > 0; - bool a11 = C1 + DX12 * y1 - DY12 * x1 > 0; - int a = (a00 << 0) | (a10 << 1) | (a01 << 2) | (a11 << 3); + // Evaluate half-space functions + bool a00 = C1 + DX12 * y0 - DY12 * x0 > 0; + bool a10 = C1 + DX12 * y0 - DY12 * x1 > 0; + bool a01 = C1 + DX12 * y1 - DY12 * x0 > 0; + bool a11 = C1 + DX12 * y1 - DY12 * x1 > 0; + int a = (a00 << 0) | (a10 << 1) | (a01 << 2) | (a11 << 3); - bool b00 = C2 + DX23 * y0 - DY23 * x0 > 0; - bool b10 = C2 + DX23 * y0 - DY23 * x1 > 0; - bool b01 = C2 + DX23 * y1 - DY23 * x0 > 0; - bool b11 = C2 + DX23 * y1 - DY23 * x1 > 0; - int b = (b00 << 0) | (b10 << 1) | (b01 << 2) | (b11 << 3); + bool b00 = C2 + DX23 * y0 - DY23 * x0 > 0; + bool b10 = C2 + DX23 * y0 - DY23 * x1 > 0; + bool b01 = C2 + DX23 * y1 - DY23 * x0 > 0; + bool b11 = C2 + DX23 * y1 - DY23 * x1 > 0; + int b = (b00 << 0) | (b10 << 1) | (b01 << 2) | (b11 << 3); - bool c00 = C3 + DX31 * y0 - DY31 * x0 > 0; - bool c10 = C3 + DX31 * y0 - DY31 * x1 > 0; - bool c01 = C3 + DX31 * y1 - DY31 * x0 > 0; - bool c11 = C3 + DX31 * y1 - DY31 * x1 > 0; - int c = (c00 << 0) | (c10 << 1) | (c01 << 2) | (c11 << 3); + bool c00 = C3 + DX31 * y0 - DY31 * x0 > 0; + bool c10 = C3 + DX31 * y0 - DY31 * x1 > 0; + bool c01 = C3 + DX31 * y1 - DY31 * x0 > 0; + bool c11 = C3 + DX31 * y1 - DY31 * x1 > 0; + int c = (c00 << 0) | (c10 << 1) | (c01 << 2) | (c11 << 3); - // Skip block when outside an edge - if (a == 0x0 || b == 0x0 || c == 0x0) - continue; + // Skip block when outside an edge + if (a == 0x0 || b == 0x0 || c == 0x0) + continue; - BuildBlock(x, y); + BuildBlock(x, y); - // Accept whole block when totally covered - if (a == 0xF && b == 0xF && c == 0xF) - { - for (s32 iy = 0; iy < BLOCK_SIZE; iy++) - { - for (s32 ix = 0; ix < BLOCK_SIZE; ix++) - { - Draw(x + ix, y + iy, ix, iy); - } - } - } - else // Partially covered block - { - s32 CY1 = C1 + DX12 * y0 - DY12 * x0; - s32 CY2 = C2 + DX23 * y0 - DY23 * x0; - s32 CY3 = C3 + DX31 * y0 - DY31 * x0; + // Accept whole block when totally covered + if (a == 0xF && b == 0xF && c == 0xF) + { + for (s32 iy = 0; iy < BLOCK_SIZE; iy++) + { + for (s32 ix = 0; ix < BLOCK_SIZE; ix++) + { + Draw(x + ix, y + iy, ix, iy); + } + } + } + else // Partially covered block + { + s32 CY1 = C1 + DX12 * y0 - DY12 * x0; + s32 CY2 = C2 + DX23 * y0 - DY23 * x0; + s32 CY3 = C3 + DX31 * y0 - DY31 * x0; - for (s32 iy = 0; iy < BLOCK_SIZE; iy++) - { - s32 CX1 = CY1; - s32 CX2 = CY2; - s32 CX3 = CY3; + for (s32 iy = 0; iy < BLOCK_SIZE; iy++) + { + s32 CX1 = CY1; + s32 CX2 = CY2; + s32 CX3 = CY3; - for (s32 ix = 0; ix < BLOCK_SIZE; ix++) - { - if (CX1 > 0 && CX2 > 0 && CX3 > 0) - { - Draw(x + ix, y + iy, ix, iy); - } + for (s32 ix = 0; ix < BLOCK_SIZE; ix++) + { + if (CX1 > 0 && CX2 > 0 && CX3 > 0) + { + Draw(x + ix, y + iy, ix, iy); + } - CX1 -= FDY12; - CX2 -= FDY23; - CX3 -= FDY31; - } + CX1 -= FDY12; + CX2 -= FDY23; + CX3 -= FDY31; + } - CY1 += FDX12; - CY2 += FDX23; - CY3 += FDX31; - } - } - } - } + CY1 += FDX12; + CY2 += FDX23; + CY3 += FDX31; + } + } + } + } } - - } diff --git a/Source/Core/VideoBackends/Software/Rasterizer.h b/Source/Core/VideoBackends/Software/Rasterizer.h index 747d72b58b..50308b7449 100644 --- a/Source/Core/VideoBackends/Software/Rasterizer.h +++ b/Source/Core/VideoBackends/Software/Rasterizer.h @@ -10,33 +10,33 @@ struct OutputVertexData; namespace Rasterizer { - void Init(); +void Init(); - void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2); +void DrawTriangleFrontFace(OutputVertexData* v0, OutputVertexData* v1, OutputVertexData* v2); - void SetTevReg(int reg, int comp, s16 color); +void SetTevReg(int reg, int comp, s16 color); - struct Slope - { - float dfdx; - float dfdy; - float f0; +struct Slope +{ + float dfdx; + float dfdy; + float f0; - float GetValue(float dx, float dy) { return f0 + (dfdx * dx) + (dfdy * dy); } - }; + float GetValue(float dx, float dy) { return f0 + (dfdx * dx) + (dfdy * dy); } +}; - struct RasterBlockPixel - { - float InvW; - float Uv[8][2]; - }; +struct RasterBlockPixel +{ + float InvW; + float Uv[8][2]; +}; - struct RasterBlock - { - RasterBlockPixel Pixel[2][2]; - s32 IndirectLod[4]; - bool IndirectLinear[4]; - s32 TextureLod[16]; - bool TextureLinear[16]; - }; +struct RasterBlock +{ + RasterBlockPixel Pixel[2][2]; + s32 IndirectLod[4]; + bool IndirectLinear[4]; + s32 TextureLod[16]; + bool TextureLinear[16]; +}; } diff --git a/Source/Core/VideoBackends/Software/SWOGLWindow.cpp b/Source/Core/VideoBackends/Software/SWOGLWindow.cpp index cd411610ed..f64b9656db 100644 --- a/Source/Core/VideoBackends/Software/SWOGLWindow.cpp +++ b/Source/Core/VideoBackends/Software/SWOGLWindow.cpp @@ -12,120 +12,118 @@ std::unique_ptr SWOGLWindow::s_instance; -void SWOGLWindow::Init(void *window_handle) +void SWOGLWindow::Init(void* window_handle) { - InitInterface(); - GLInterface->SetMode(GLInterfaceMode::MODE_DETECT); - if (!GLInterface->Create(window_handle)) - { - INFO_LOG(VIDEO, "GLInterface::Create failed."); - } + InitInterface(); + GLInterface->SetMode(GLInterfaceMode::MODE_DETECT); + if (!GLInterface->Create(window_handle)) + { + INFO_LOG(VIDEO, "GLInterface::Create failed."); + } - s_instance.reset(new SWOGLWindow()); + s_instance.reset(new SWOGLWindow()); } void SWOGLWindow::Shutdown() { - GLInterface->Shutdown(); - GLInterface.reset(); + GLInterface->Shutdown(); + GLInterface.reset(); - s_instance.reset(); + s_instance.reset(); } void SWOGLWindow::Prepare() { - if (m_init) return; - m_init = true; + if (m_init) + return; + m_init = true; - // Init extension support. - if (!GLExtensions::Init()) - { - ERROR_LOG(VIDEO, "GLExtensions::Init failed!Does your video card support OpenGL 2.0?"); - return; - } - else if (GLExtensions::Version() < 310) - { - ERROR_LOG(VIDEO, "OpenGL Version %d detected, but at least 3.1 is required.", GLExtensions::Version()); - return; - } + // Init extension support. + if (!GLExtensions::Init()) + { + ERROR_LOG(VIDEO, "GLExtensions::Init failed!Does your video card support OpenGL 2.0?"); + return; + } + else if (GLExtensions::Version() < 310) + { + ERROR_LOG(VIDEO, "OpenGL Version %d detected, but at least 3.1 is required.", + GLExtensions::Version()); + return; + } - std::string frag_shader = - "in vec2 TexCoord;\n" - "out vec4 ColorOut;\n" - "uniform sampler2D Texture;\n" - "void main() {\n" - " ColorOut = texture2D(Texture, TexCoord);\n" - "}\n"; + std::string frag_shader = "in vec2 TexCoord;\n" + "out vec4 ColorOut;\n" + "uniform sampler2D Texture;\n" + "void main() {\n" + " ColorOut = texture2D(Texture, TexCoord);\n" + "}\n"; - std::string vertex_shader = - "out vec2 TexCoord;\n" - "void main() {\n" - " vec2 rawpos = vec2(gl_VertexID & 1, (gl_VertexID & 2) >> 1);\n" - " gl_Position = vec4(rawpos * 2.0 - 1.0, 0.0, 1.0);\n" - " TexCoord = vec2(rawpos.x, -rawpos.y);\n" - "}\n"; + std::string vertex_shader = "out vec2 TexCoord;\n" + "void main() {\n" + " vec2 rawpos = vec2(gl_VertexID & 1, (gl_VertexID & 2) >> 1);\n" + " gl_Position = vec4(rawpos * 2.0 - 1.0, 0.0, 1.0);\n" + " TexCoord = vec2(rawpos.x, -rawpos.y);\n" + "}\n"; - std::string header = - GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL ? - "#version 140\n" - : - "#version 300 es\n" - "precision highp float;\n"; + std::string header = GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL ? + "#version 140\n" : + "#version 300 es\n" + "precision highp float;\n"; - m_image_program = OpenGL_CompileProgram(header + vertex_shader, header + frag_shader); + m_image_program = OpenGL_CompileProgram(header + vertex_shader, header + frag_shader); - glUseProgram(m_image_program); + glUseProgram(m_image_program); - glUniform1i(glGetUniformLocation(m_image_program, "Texture"), 0); + glUniform1i(glGetUniformLocation(m_image_program, "Texture"), 0); - glGenTextures(1, &m_image_texture); - glBindTexture(GL_TEXTURE_2D, m_image_texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glGenTextures(1, &m_image_texture); + glBindTexture(GL_TEXTURE_2D, m_image_texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glGenVertexArrays(1, &m_image_vao); + glGenVertexArrays(1, &m_image_vao); } void SWOGLWindow::PrintText(const std::string& text, int x, int y, u32 color) { - TextData data{text, x, y, color}; - m_text.emplace_back(data); + TextData data{text, x, y, color}; + m_text.emplace_back(data); } void SWOGLWindow::ShowImage(u8* data, int stride, int width, int height, float aspect) { - GLInterface->MakeCurrent(); - GLInterface->Update(); - Prepare(); + GLInterface->MakeCurrent(); + GLInterface->Update(); + Prepare(); - GLsizei glWidth = (GLsizei)GLInterface->GetBackBufferWidth(); - GLsizei glHeight = (GLsizei)GLInterface->GetBackBufferHeight(); + GLsizei glWidth = (GLsizei)GLInterface->GetBackBufferWidth(); + GLsizei glHeight = (GLsizei)GLInterface->GetBackBufferHeight(); - glViewport(0, 0, glWidth, glHeight); + glViewport(0, 0, glWidth, glHeight); - glBindTexture(GL_TEXTURE_2D, m_image_texture); + glBindTexture(GL_TEXTURE_2D, m_image_texture); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment - glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / 4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment + glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / 4); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, + GL_UNSIGNED_BYTE, data); - glUseProgram(m_image_program); + glUseProgram(m_image_program); - glBindVertexArray(m_image_vao); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(m_image_vao); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); -// TODO: implement OSD -// for (TextData& text : m_text) -// { -// } - m_text.clear(); + // TODO: implement OSD + // for (TextData& text : m_text) + // { + // } + m_text.clear(); - GLInterface->Swap(); - GLInterface->ClearCurrent(); + GLInterface->Swap(); + GLInterface->ClearCurrent(); } int SWOGLWindow::PeekMessages() { - return GLInterface->PeekMessages(); + return GLInterface->PeekMessages(); } - diff --git a/Source/Core/VideoBackends/Software/SWOGLWindow.h b/Source/Core/VideoBackends/Software/SWOGLWindow.h index 8be58c2e66..3c85255cb2 100644 --- a/Source/Core/VideoBackends/Software/SWOGLWindow.h +++ b/Source/Core/VideoBackends/Software/SWOGLWindow.h @@ -13,33 +13,32 @@ class SWOGLWindow { public: - static void Init(void* window_handle); - static void Shutdown(); + static void Init(void* window_handle); + static void Shutdown(); - // Will be printed on the *next* image - void PrintText(const std::string& text, int x, int y, u32 color); + // Will be printed on the *next* image + void PrintText(const std::string& text, int x, int y, u32 color); - // Image to show, will be swapped immediately - void ShowImage(u8* data, int stride, int width, int height, float aspect); + // Image to show, will be swapped immediately + void ShowImage(u8* data, int stride, int width, int height, float aspect); - int PeekMessages(); + int PeekMessages(); - static std::unique_ptr s_instance; + static std::unique_ptr s_instance; private: - SWOGLWindow() {} + SWOGLWindow() {} + void Prepare(); - void Prepare(); + struct TextData + { + std::string text; + int x, y; + u32 color; + }; + std::vector m_text; - struct TextData - { - std::string text; - int x, y; - u32 color; - }; - std::vector m_text; + bool m_init{false}; - bool m_init {false}; - - u32 m_image_program, m_image_texture, m_image_vao; + u32 m_image_program, m_image_texture, m_image_vao; }; diff --git a/Source/Core/VideoBackends/Software/SWRenderer.cpp b/Source/Core/VideoBackends/Software/SWRenderer.cpp index 04f82415a0..5a0bd246a9 100644 --- a/Source/Core/VideoBackends/Software/SWRenderer.cpp +++ b/Source/Core/VideoBackends/Software/SWRenderer.cpp @@ -9,8 +9,8 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/StringUtil.h" #include "Common/Logging/Log.h" +#include "Common/StringUtil.h" #include "Core/ConfigManager.h" #include "Core/HW/Memmap.h" @@ -25,187 +25,193 @@ #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/VideoConfig.h" -static u8 *s_xfbColorTexture[2]; +static u8* s_xfbColorTexture[2]; static int s_currentColorTexture = 0; SWRenderer::~SWRenderer() { - delete[] s_xfbColorTexture[0]; - delete[] s_xfbColorTexture[1]; + delete[] s_xfbColorTexture[0]; + delete[] s_xfbColorTexture[1]; } void SWRenderer::Init() { - s_xfbColorTexture[0] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4]; - s_xfbColorTexture[1] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4]; + s_xfbColorTexture[0] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4]; + s_xfbColorTexture[1] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4]; - s_currentColorTexture = 0; + s_currentColorTexture = 0; } void SWRenderer::Shutdown() { - g_Config.bRunning = false; - UpdateActiveConfig(); + g_Config.bRunning = false; + UpdateActiveConfig(); } void SWRenderer::RenderText(const std::string& pstr, int left, int top, u32 color) { - SWOGLWindow::s_instance->PrintText(pstr, left, top, color); + SWOGLWindow::s_instance->PrintText(pstr, left, top, color); } u8* SWRenderer::GetNextColorTexture() { - return s_xfbColorTexture[!s_currentColorTexture]; + return s_xfbColorTexture[!s_currentColorTexture]; } u8* SWRenderer::GetCurrentColorTexture() { - return s_xfbColorTexture[s_currentColorTexture]; + return s_xfbColorTexture[s_currentColorTexture]; } void SWRenderer::SwapColorTexture() { - s_currentColorTexture = !s_currentColorTexture; + s_currentColorTexture = !s_currentColorTexture; } -void SWRenderer::UpdateColorTexture(EfbInterface::yuv422_packed *xfb, u32 fbWidth, u32 fbHeight) +void SWRenderer::UpdateColorTexture(EfbInterface::yuv422_packed* xfb, u32 fbWidth, u32 fbHeight) { - if (fbWidth * fbHeight > MAX_XFB_WIDTH * MAX_XFB_HEIGHT) - { - ERROR_LOG(VIDEO, "Framebuffer is too large: %ix%i", fbWidth, fbHeight); - return; - } + if (fbWidth * fbHeight > MAX_XFB_WIDTH * MAX_XFB_HEIGHT) + { + ERROR_LOG(VIDEO, "Framebuffer is too large: %ix%i", fbWidth, fbHeight); + return; + } - u32 offset = 0; - u8 *TexturePointer = GetNextColorTexture(); + u32 offset = 0; + u8* TexturePointer = GetNextColorTexture(); - for (u16 y = 0; y < fbHeight; y++) - { - for (u16 x = 0; x < fbWidth; x+=2) - { - // We do this one color sample (aka 2 RGB pixles) at a time - int Y1 = xfb[x].Y - 16; - int Y2 = xfb[x + 1].Y - 16; - int U = int(xfb[x].UV) - 128; - int V = int(xfb[x + 1].UV) - 128; + for (u16 y = 0; y < fbHeight; y++) + { + for (u16 x = 0; x < fbWidth; x += 2) + { + // We do this one color sample (aka 2 RGB pixles) at a time + int Y1 = xfb[x].Y - 16; + int Y2 = xfb[x + 1].Y - 16; + int U = int(xfb[x].UV) - 128; + int V = int(xfb[x + 1].UV) - 128; - // We do the inverse BT.601 conversion for YCbCr to RGB - // http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion - TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 + 1.596f * V), 0, 255); - TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 - 0.392f * U - 0.813f * V), 0, 255); - TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 + 2.017f * U ), 0, 255); - TexturePointer[offset++] = 255; + // We do the inverse BT.601 conversion for YCbCr to RGB + // http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion + TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 + 1.596f * V), 0, 255); + TexturePointer[offset++] = + MathUtil::Clamp(int(1.164f * Y1 - 0.392f * U - 0.813f * V), 0, 255); + TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 + 2.017f * U), 0, 255); + TexturePointer[offset++] = 255; - TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 + 1.596f * V), 0, 255); - TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 - 0.392f * U - 0.813f * V), 0, 255); - TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 + 2.017f * U ), 0, 255); - TexturePointer[offset++] = 255; - } - xfb += fbWidth; - } - SwapColorTexture(); + TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 + 1.596f * V), 0, 255); + TexturePointer[offset++] = + MathUtil::Clamp(int(1.164f * Y2 - 0.392f * U - 0.813f * V), 0, 255); + TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 + 2.017f * U), 0, 255); + TexturePointer[offset++] = 255; + } + xfb += fbWidth; + } + SwapColorTexture(); } // Called on the GPU thread -void SWRenderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma) +void SWRenderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, + const EFBRectangle& rc, float Gamma) { - if (!Fifo::WillSkipCurrentFrame()) - { + if (!Fifo::WillSkipCurrentFrame()) + { + if (g_ActiveConfig.bUseXFB) + { + EfbInterface::yuv422_packed* xfb = (EfbInterface::yuv422_packed*)Memory::GetPointer(xfbAddr); + UpdateColorTexture(xfb, fbWidth, fbHeight); + } + else + { + EfbInterface::BypassXFB(GetCurrentColorTexture(), fbWidth, fbHeight, rc, Gamma); + } - if (g_ActiveConfig.bUseXFB) - { - EfbInterface::yuv422_packed* xfb = (EfbInterface::yuv422_packed*) Memory::GetPointer(xfbAddr); - UpdateColorTexture(xfb, fbWidth, fbHeight); - } - else - { - EfbInterface::BypassXFB(GetCurrentColorTexture(), fbWidth, fbHeight, rc, Gamma); - } + // Save screenshot + if (s_bScreenshot) + { + std::lock_guard lk(s_criticalScreenshot); - // Save screenshot - if (s_bScreenshot) - { - std::lock_guard lk(s_criticalScreenshot); + if (TextureToPng(GetCurrentColorTexture(), fbWidth * 4, s_sScreenshotName, fbWidth, fbHeight, + false)) + OSD::AddMessage("Screenshot saved to " + s_sScreenshotName); - if (TextureToPng(GetCurrentColorTexture(), fbWidth * 4, s_sScreenshotName, fbWidth, fbHeight, false)) - OSD::AddMessage("Screenshot saved to " + s_sScreenshotName); + // Reset settings + s_sScreenshotName.clear(); + s_bScreenshot = false; + s_screenshotCompleted.Set(); + } - // Reset settings - s_sScreenshotName.clear(); - s_bScreenshot = false; - s_screenshotCompleted.Set(); - } + if (SConfig::GetInstance().m_DumpFrames) + { + static int frame_index = 0; + TextureToPng(GetCurrentColorTexture(), fbWidth * 4, + StringFromFormat("%sframe%i_color.png", + File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), frame_index), + fbWidth, fbHeight, true); + frame_index++; + } + } - if (SConfig::GetInstance().m_DumpFrames) - { - static int frame_index = 0; - TextureToPng(GetCurrentColorTexture(), fbWidth * 4, StringFromFormat("%sframe%i_color.png", - File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), frame_index), fbWidth, fbHeight, true); - frame_index++; - } - } + OSD::DoCallbacks(OSD::CallbackType::OnFrame); - OSD::DoCallbacks(OSD::CallbackType::OnFrame); + DrawDebugText(); - DrawDebugText(); + SWOGLWindow::s_instance->ShowImage(GetCurrentColorTexture(), fbWidth * 4, fbWidth, fbHeight, 1.0); - SWOGLWindow::s_instance->ShowImage(GetCurrentColorTexture(), fbWidth * 4, fbWidth, fbHeight, 1.0); + UpdateActiveConfig(); - UpdateActiveConfig(); - - // virtual XFB is not supported - if (g_ActiveConfig.bUseXFB) - g_ActiveConfig.bUseRealXFB = true; + // virtual XFB is not supported + if (g_ActiveConfig.bUseXFB) + g_ActiveConfig.bUseRealXFB = true; } u32 SWRenderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData) { - u32 value = 0; + u32 value = 0; - switch (type) - { - case PEEK_Z: - { - value = EfbInterface::GetDepth(x, y); - break; - } - case PEEK_COLOR: - { - u32 color = 0; - EfbInterface::GetColor(x, y, (u8*)&color); + switch (type) + { + case PEEK_Z: + { + value = EfbInterface::GetDepth(x, y); + break; + } + case PEEK_COLOR: + { + u32 color = 0; + EfbInterface::GetColor(x, y, (u8*)&color); - // rgba to argb - value = (color >> 8) | (color & 0xff) << 24; - break; - } - default: - break; - } + // rgba to argb + value = (color >> 8) | (color & 0xff) << 24; + break; + } + default: + break; + } - return value; + return value; } u16 SWRenderer::BBoxRead(int index) { - return BoundingBox::coords[index]; + return BoundingBox::coords[index]; } void SWRenderer::BBoxWrite(int index, u16 value) { - BoundingBox::coords[index] = value; + BoundingBox::coords[index] = value; } TargetRectangle SWRenderer::ConvertEFBRectangle(const EFBRectangle& rc) { - TargetRectangle result; - result.left = rc.left; - result.top = rc.top; - result.right = rc.right; - result.bottom = rc.bottom; - return result; + TargetRectangle result; + result.left = rc.left; + result.top = rc.top; + result.right = rc.right; + result.bottom = rc.bottom; + return result; } -void SWRenderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) +void SWRenderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, + bool zEnable, u32 color, u32 z) { - EfbCopy::ClearEfb(); + EfbCopy::ClearEfb(); } diff --git a/Source/Core/VideoBackends/Software/SWRenderer.h b/Source/Core/VideoBackends/Software/SWRenderer.h index 3ce1cc4593..919d06c6ab 100644 --- a/Source/Core/VideoBackends/Software/SWRenderer.h +++ b/Source/Core/VideoBackends/Software/SWRenderer.h @@ -14,32 +14,35 @@ class SWRenderer : public Renderer { public: - ~SWRenderer() override; + ~SWRenderer() override; - static void Init(); - static void Shutdown(); + static void Init(); + static void Shutdown(); - static u8* GetNextColorTexture(); - static u8* GetCurrentColorTexture(); - void SwapColorTexture(); - void UpdateColorTexture(EfbInterface::yuv422_packed *xfb, u32 fbWidth, u32 fbHeight); + static u8* GetNextColorTexture(); + static u8* GetCurrentColorTexture(); + void SwapColorTexture(); + void UpdateColorTexture(EfbInterface::yuv422_packed* xfb, u32 fbWidth, u32 fbHeight); - void RenderText(const std::string& pstr, int left, int top, u32 color) override; - u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; - void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {}; + void RenderText(const std::string& pstr, int left, int top, u32 color) override; + u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; + void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override{}; - u16 BBoxRead(int index) override; - void BBoxWrite(int index, u16 value) override; + u16 BBoxRead(int index) override; + void BBoxWrite(int index, u16 value) override; - int GetMaxTextureSize() override { return 16 * 1024; }; + int GetMaxTextureSize() override { return 16 * 1024; }; + TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; - TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override; + void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, + float Gamma) override; - void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma) override; + void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, + u32 color, u32 z) override; - void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override; - - void ReinterpretPixelData(unsigned int convtype) override {} - - bool SaveScreenshot(const std::string& filename, const TargetRectangle& rc) override { return true; }; + void ReinterpretPixelData(unsigned int convtype) override {} + bool SaveScreenshot(const std::string& filename, const TargetRectangle& rc) override + { + return true; + }; }; diff --git a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp index a72eacd31c..ebbf628c1a 100644 --- a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp +++ b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp @@ -11,8 +11,8 @@ #include "VideoBackends/Software/DebugUtil.h" #include "VideoBackends/Software/NativeVertexFormat.h" #include "VideoBackends/Software/Rasterizer.h" -#include "VideoBackends/Software/SetupUnit.h" #include "VideoBackends/Software/SWVertexLoader.h" +#include "VideoBackends/Software/SetupUnit.h" #include "VideoBackends/Software/Tev.h" #include "VideoBackends/Software/TransformUnit.h" @@ -29,217 +29,220 @@ class NullNativeVertexFormat : public NativeVertexFormat { public: - NullNativeVertexFormat(const PortableVertexDeclaration& _vtx_decl) { vtx_decl = _vtx_decl; } - void SetupVertexPointers() override {} + NullNativeVertexFormat(const PortableVertexDeclaration& _vtx_decl) { vtx_decl = _vtx_decl; } + void SetupVertexPointers() override {} }; -NativeVertexFormat* SWVertexLoader::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) +NativeVertexFormat* +SWVertexLoader::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) { - return new NullNativeVertexFormat(vtx_decl); + return new NullNativeVertexFormat(vtx_decl); } SWVertexLoader::SWVertexLoader() { - LocalVBuffer.resize(MAXVBUFFERSIZE); - LocalIBuffer.resize(MAXIBUFFERSIZE); - m_SetupUnit = new SetupUnit; + LocalVBuffer.resize(MAXVBUFFERSIZE); + LocalIBuffer.resize(MAXIBUFFERSIZE); + m_SetupUnit = new SetupUnit; } SWVertexLoader::~SWVertexLoader() { - delete m_SetupUnit; - m_SetupUnit = nullptr; + delete m_SetupUnit; + m_SetupUnit = nullptr; } void SWVertexLoader::ResetBuffer(u32 stride) { - s_pCurBufferPointer = s_pBaseBufferPointer = LocalVBuffer.data(); - s_pEndBufferPointer = s_pCurBufferPointer + LocalVBuffer.size(); - IndexGenerator::Start(GetIndexBuffer()); + s_pCurBufferPointer = s_pBaseBufferPointer = LocalVBuffer.data(); + s_pEndBufferPointer = s_pCurBufferPointer + LocalVBuffer.size(); + IndexGenerator::Start(GetIndexBuffer()); } void SWVertexLoader::vFlush(bool useDstAlpha) { - DebugUtil::OnObjectBegin(); + DebugUtil::OnObjectBegin(); - u8 primitiveType = 0; - switch (current_primitive_type) - { - case PRIMITIVE_POINTS: - primitiveType = GX_DRAW_POINTS; - break; - case PRIMITIVE_LINES: - primitiveType = GX_DRAW_LINES; - break; - case PRIMITIVE_TRIANGLES: - primitiveType = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? GX_DRAW_TRIANGLE_STRIP : GX_DRAW_TRIANGLES; - break; - } + u8 primitiveType = 0; + switch (current_primitive_type) + { + case PRIMITIVE_POINTS: + primitiveType = GX_DRAW_POINTS; + break; + case PRIMITIVE_LINES: + primitiveType = GX_DRAW_LINES; + break; + case PRIMITIVE_TRIANGLES: + primitiveType = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? GX_DRAW_TRIANGLE_STRIP : + GX_DRAW_TRIANGLES; + break; + } - m_SetupUnit->Init(primitiveType); + m_SetupUnit->Init(primitiveType); - // set all states with are stored within video sw - for (int i = 0; i < 4; i++) - { - Rasterizer::SetTevReg(i, Tev::RED_C, PixelShaderManager::constants.kcolors[i][0]); - Rasterizer::SetTevReg(i, Tev::GRN_C, PixelShaderManager::constants.kcolors[i][1]); - Rasterizer::SetTevReg(i, Tev::BLU_C, PixelShaderManager::constants.kcolors[i][2]); - Rasterizer::SetTevReg(i, Tev::ALP_C, PixelShaderManager::constants.kcolors[i][3]); - } + // set all states with are stored within video sw + for (int i = 0; i < 4; i++) + { + Rasterizer::SetTevReg(i, Tev::RED_C, PixelShaderManager::constants.kcolors[i][0]); + Rasterizer::SetTevReg(i, Tev::GRN_C, PixelShaderManager::constants.kcolors[i][1]); + Rasterizer::SetTevReg(i, Tev::BLU_C, PixelShaderManager::constants.kcolors[i][2]); + Rasterizer::SetTevReg(i, Tev::ALP_C, PixelShaderManager::constants.kcolors[i][3]); + } - for (u32 i = 0; i < IndexGenerator::GetIndexLen(); i++) - { - u16 index = LocalIBuffer[i]; + for (u32 i = 0; i < IndexGenerator::GetIndexLen(); i++) + { + u16 index = LocalIBuffer[i]; - if (index == 0xffff) - { - // primitive restart - m_SetupUnit->Init(primitiveType); - continue; - } - memset(&m_Vertex, 0, sizeof(m_Vertex)); + if (index == 0xffff) + { + // primitive restart + m_SetupUnit->Init(primitiveType); + continue; + } + memset(&m_Vertex, 0, sizeof(m_Vertex)); - // Super Mario Sunshine requires those to be zero for those debug boxes. - memset(&m_Vertex.color, 0, sizeof(m_Vertex.color)); + // Super Mario Sunshine requires those to be zero for those debug boxes. + memset(&m_Vertex.color, 0, sizeof(m_Vertex.color)); - // parse the videocommon format to our own struct format (m_Vertex) - SetFormat(g_main_cp_state.last_id, primitiveType); - ParseVertex(VertexLoaderManager::GetCurrentVertexFormat()->GetVertexDeclaration(), index); + // parse the videocommon format to our own struct format (m_Vertex) + SetFormat(g_main_cp_state.last_id, primitiveType); + ParseVertex(VertexLoaderManager::GetCurrentVertexFormat()->GetVertexDeclaration(), index); - // transform this vertex so that it can be used for rasterization (outVertex) - OutputVertexData* outVertex = m_SetupUnit->GetVertex(); - TransformUnit::TransformPosition(&m_Vertex, outVertex); - memset(&outVertex->normal, 0, sizeof(outVertex->normal)); - if (VertexLoaderManager::g_current_components & VB_HAS_NRM0) - { - TransformUnit::TransformNormal(&m_Vertex, (VertexLoaderManager::g_current_components & VB_HAS_NRM2) != 0, outVertex); - } - TransformUnit::TransformColor(&m_Vertex, outVertex); - TransformUnit::TransformTexCoord(&m_Vertex, outVertex, m_TexGenSpecialCase); + // transform this vertex so that it can be used for rasterization (outVertex) + OutputVertexData* outVertex = m_SetupUnit->GetVertex(); + TransformUnit::TransformPosition(&m_Vertex, outVertex); + memset(&outVertex->normal, 0, sizeof(outVertex->normal)); + if (VertexLoaderManager::g_current_components & VB_HAS_NRM0) + { + TransformUnit::TransformNormal( + &m_Vertex, (VertexLoaderManager::g_current_components & VB_HAS_NRM2) != 0, outVertex); + } + TransformUnit::TransformColor(&m_Vertex, outVertex); + TransformUnit::TransformTexCoord(&m_Vertex, outVertex, m_TexGenSpecialCase); - // assemble and rasterize the primitive - m_SetupUnit->SetupVertex(); + // assemble and rasterize the primitive + m_SetupUnit->SetupVertex(); - INCSTAT(stats.thisFrame.numVerticesLoaded) - } + INCSTAT(stats.thisFrame.numVerticesLoaded) + } - DebugUtil::OnObjectEnd(); + DebugUtil::OnObjectEnd(); } void SWVertexLoader::SetFormat(u8 attributeIndex, u8 primitiveType) { - // matrix index from xf regs or cp memory? - if (xfmem.MatrixIndexA.PosNormalMtxIdx != g_main_cp_state.matrix_index_a.PosNormalMtxIdx || - xfmem.MatrixIndexA.Tex0MtxIdx != g_main_cp_state.matrix_index_a.Tex0MtxIdx || - xfmem.MatrixIndexA.Tex1MtxIdx != g_main_cp_state.matrix_index_a.Tex1MtxIdx || - xfmem.MatrixIndexA.Tex2MtxIdx != g_main_cp_state.matrix_index_a.Tex2MtxIdx || - xfmem.MatrixIndexA.Tex3MtxIdx != g_main_cp_state.matrix_index_a.Tex3MtxIdx || - xfmem.MatrixIndexB.Tex4MtxIdx != g_main_cp_state.matrix_index_b.Tex4MtxIdx || - xfmem.MatrixIndexB.Tex5MtxIdx != g_main_cp_state.matrix_index_b.Tex5MtxIdx || - xfmem.MatrixIndexB.Tex6MtxIdx != g_main_cp_state.matrix_index_b.Tex6MtxIdx || - xfmem.MatrixIndexB.Tex7MtxIdx != g_main_cp_state.matrix_index_b.Tex7MtxIdx) - { - ERROR_LOG(VIDEO, "Matrix indices don't match"); - } + // matrix index from xf regs or cp memory? + if (xfmem.MatrixIndexA.PosNormalMtxIdx != g_main_cp_state.matrix_index_a.PosNormalMtxIdx || + xfmem.MatrixIndexA.Tex0MtxIdx != g_main_cp_state.matrix_index_a.Tex0MtxIdx || + xfmem.MatrixIndexA.Tex1MtxIdx != g_main_cp_state.matrix_index_a.Tex1MtxIdx || + xfmem.MatrixIndexA.Tex2MtxIdx != g_main_cp_state.matrix_index_a.Tex2MtxIdx || + xfmem.MatrixIndexA.Tex3MtxIdx != g_main_cp_state.matrix_index_a.Tex3MtxIdx || + xfmem.MatrixIndexB.Tex4MtxIdx != g_main_cp_state.matrix_index_b.Tex4MtxIdx || + xfmem.MatrixIndexB.Tex5MtxIdx != g_main_cp_state.matrix_index_b.Tex5MtxIdx || + xfmem.MatrixIndexB.Tex6MtxIdx != g_main_cp_state.matrix_index_b.Tex6MtxIdx || + xfmem.MatrixIndexB.Tex7MtxIdx != g_main_cp_state.matrix_index_b.Tex7MtxIdx) + { + ERROR_LOG(VIDEO, "Matrix indices don't match"); + } - m_Vertex.posMtx = xfmem.MatrixIndexA.PosNormalMtxIdx; - m_Vertex.texMtx[0] = xfmem.MatrixIndexA.Tex0MtxIdx; - m_Vertex.texMtx[1] = xfmem.MatrixIndexA.Tex1MtxIdx; - m_Vertex.texMtx[2] = xfmem.MatrixIndexA.Tex2MtxIdx; - m_Vertex.texMtx[3] = xfmem.MatrixIndexA.Tex3MtxIdx; - m_Vertex.texMtx[4] = xfmem.MatrixIndexB.Tex4MtxIdx; - m_Vertex.texMtx[5] = xfmem.MatrixIndexB.Tex5MtxIdx; - m_Vertex.texMtx[6] = xfmem.MatrixIndexB.Tex6MtxIdx; - m_Vertex.texMtx[7] = xfmem.MatrixIndexB.Tex7MtxIdx; + m_Vertex.posMtx = xfmem.MatrixIndexA.PosNormalMtxIdx; + m_Vertex.texMtx[0] = xfmem.MatrixIndexA.Tex0MtxIdx; + m_Vertex.texMtx[1] = xfmem.MatrixIndexA.Tex1MtxIdx; + m_Vertex.texMtx[2] = xfmem.MatrixIndexA.Tex2MtxIdx; + m_Vertex.texMtx[3] = xfmem.MatrixIndexA.Tex3MtxIdx; + m_Vertex.texMtx[4] = xfmem.MatrixIndexB.Tex4MtxIdx; + m_Vertex.texMtx[5] = xfmem.MatrixIndexB.Tex5MtxIdx; + m_Vertex.texMtx[6] = xfmem.MatrixIndexB.Tex6MtxIdx; + m_Vertex.texMtx[7] = xfmem.MatrixIndexB.Tex7MtxIdx; - - // special case if only pos and tex coord 0 and tex coord input is AB11 - // http://libogc.devkitpro.org/gx_8h.html#a55a426a3ff796db584302bddd829f002 - m_TexGenSpecialCase = - VertexLoaderManager::g_current_components == VB_HAS_UV0 && - xfmem.texMtxInfo[0].projection == XF_TEXPROJ_ST; + // special case if only pos and tex coord 0 and tex coord input is AB11 + // http://libogc.devkitpro.org/gx_8h.html#a55a426a3ff796db584302bddd829f002 + m_TexGenSpecialCase = VertexLoaderManager::g_current_components == VB_HAS_UV0 && + xfmem.texMtxInfo[0].projection == XF_TEXPROJ_ST; } template static T ReadNormalized(I value) { - T casted = (T) value; - if (!std::numeric_limits::is_integer && std::numeric_limits::is_integer) - { - // normalize if non-float is converted to a float - casted *= (T) (1.0 / std::numeric_limits::max()); - } - return casted; + T casted = (T)value; + if (!std::numeric_limits::is_integer && std::numeric_limits::is_integer) + { + // normalize if non-float is converted to a float + casted *= (T)(1.0 / std::numeric_limits::max()); + } + return casted; } template -static void ReadVertexAttribute(T* dst, DataReader src, const AttributeFormat& format, int base_component, int components, bool reverse) +static void ReadVertexAttribute(T* dst, DataReader src, const AttributeFormat& format, + int base_component, int components, bool reverse) { - if (format.enable) - { - src.Skip(format.offset); - src.Skip(base_component * (1<<(format.type>>1))); + if (format.enable) + { + src.Skip(format.offset); + src.Skip(base_component * (1 << (format.type >> 1))); - int i; - for (i = 0; i < std::min(format.components - base_component, components); i++) - { - int i_dst = reverse ? components - i - 1 : i; - switch (format.type) - { - case VAR_UNSIGNED_BYTE: - dst[i_dst] = ReadNormalized(src.Read()); - break; - case VAR_BYTE: - dst[i_dst] = ReadNormalized(src.Read()); - break; - case VAR_UNSIGNED_SHORT: - dst[i_dst] = ReadNormalized(src.Read()); - break; - case VAR_SHORT: - dst[i_dst] = ReadNormalized(src.Read()); - break; - case VAR_FLOAT: - dst[i_dst] = ReadNormalized(src.Read()); - break; - } + int i; + for (i = 0; i < std::min(format.components - base_component, components); i++) + { + int i_dst = reverse ? components - i - 1 : i; + switch (format.type) + { + case VAR_UNSIGNED_BYTE: + dst[i_dst] = ReadNormalized(src.Read()); + break; + case VAR_BYTE: + dst[i_dst] = ReadNormalized(src.Read()); + break; + case VAR_UNSIGNED_SHORT: + dst[i_dst] = ReadNormalized(src.Read()); + break; + case VAR_SHORT: + dst[i_dst] = ReadNormalized(src.Read()); + break; + case VAR_FLOAT: + dst[i_dst] = ReadNormalized(src.Read()); + break; + } - _assert_msg_(VIDEO, !format.integer || format.type != VAR_FLOAT, "only non-float values are allowed to be streamed as integer"); - } - for (; i < components; i++) - { - int i_dst = reverse ? components - i - 1 : i; - dst[i_dst] = i == 3; - } - } + _assert_msg_(VIDEO, !format.integer || format.type != VAR_FLOAT, + "only non-float values are allowed to be streamed as integer"); + } + for (; i < components; i++) + { + int i_dst = reverse ? components - i - 1 : i; + dst[i_dst] = i == 3; + } + } } void SWVertexLoader::ParseVertex(const PortableVertexDeclaration& vdec, int index) { - DataReader src(LocalVBuffer.data(), LocalVBuffer.data() + LocalVBuffer.size()); - src.Skip(index * vdec.stride); + DataReader src(LocalVBuffer.data(), LocalVBuffer.data() + LocalVBuffer.size()); + src.Skip(index * vdec.stride); - ReadVertexAttribute(&m_Vertex.position[0], src, vdec.position, 0, 3, false); + ReadVertexAttribute(&m_Vertex.position[0], src, vdec.position, 0, 3, false); - for (int i = 0; i < 3; i++) - { - ReadVertexAttribute(&m_Vertex.normal[i][0], src, vdec.normals[i], 0, 3, false); - } + for (int i = 0; i < 3; i++) + { + ReadVertexAttribute(&m_Vertex.normal[i][0], src, vdec.normals[i], 0, 3, false); + } - for (int i = 0; i < 2; i++) - { - ReadVertexAttribute(m_Vertex.color[i], src, vdec.colors[i], 0, 4, true); - } + for (int i = 0; i < 2; i++) + { + ReadVertexAttribute(m_Vertex.color[i], src, vdec.colors[i], 0, 4, true); + } - for (int i = 0; i < 8; i++) - { - ReadVertexAttribute(m_Vertex.texCoords[i], src, vdec.texcoords[i], 0, 2, false); + for (int i = 0; i < 8; i++) + { + ReadVertexAttribute(m_Vertex.texCoords[i], src, vdec.texcoords[i], 0, 2, false); - // the texmtr is stored as third component of the texCoord - if (vdec.texcoords[i].components >= 3) - { - ReadVertexAttribute(&m_Vertex.texMtx[i], src, vdec.texcoords[i], 2, 1, false); - } - } + // the texmtr is stored as third component of the texCoord + if (vdec.texcoords[i].components >= 3) + { + ReadVertexAttribute(&m_Vertex.texMtx[i], src, vdec.texcoords[i], 2, 1, false); + } + } - ReadVertexAttribute(&m_Vertex.posMtx, src, vdec.posmtx, 0, 1, false); + ReadVertexAttribute(&m_Vertex.posMtx, src, vdec.posmtx, 0, 1, false); } diff --git a/Source/Core/VideoBackends/Software/SWVertexLoader.h b/Source/Core/VideoBackends/Software/SWVertexLoader.h index 1880ae8c07..e924886d8d 100644 --- a/Source/Core/VideoBackends/Software/SWVertexLoader.h +++ b/Source/Core/VideoBackends/Software/SWVertexLoader.h @@ -20,28 +20,27 @@ class SetupUnit; class SWVertexLoader : public VertexManagerBase { public: - SWVertexLoader(); - ~SWVertexLoader(); + SWVertexLoader(); + ~SWVertexLoader(); - NativeVertexFormat* CreateNativeVertexFormat(const PortableVertexDeclaration& vdec) override; + NativeVertexFormat* CreateNativeVertexFormat(const PortableVertexDeclaration& vdec) override; protected: - void ResetBuffer(u32 stride) override; - u16* GetIndexBuffer() { return &LocalIBuffer[0]; } + void ResetBuffer(u32 stride) override; + u16* GetIndexBuffer() { return &LocalIBuffer[0]; } private: - void vFlush(bool useDstAlpha) override; - std::vector LocalVBuffer; - std::vector LocalIBuffer; + void vFlush(bool useDstAlpha) override; + std::vector LocalVBuffer; + std::vector LocalIBuffer; - InputVertexData m_Vertex; + InputVertexData m_Vertex; - void ParseVertex(const PortableVertexDeclaration& vdec, int index); + void ParseVertex(const PortableVertexDeclaration& vdec, int index); - SetupUnit *m_SetupUnit; + SetupUnit* m_SetupUnit; - bool m_TexGenSpecialCase; + bool m_TexGenSpecialCase; public: - - void SetFormat(u8 attributeIndex, u8 primitiveType); + void SetFormat(u8 attributeIndex, u8 primitiveType); }; diff --git a/Source/Core/VideoBackends/Software/SWmain.cpp b/Source/Core/VideoBackends/Software/SWmain.cpp index e229a713e4..083e9766e7 100644 --- a/Source/Core/VideoBackends/Software/SWmain.cpp +++ b/Source/Core/VideoBackends/Software/SWmain.cpp @@ -40,206 +40,208 @@ namespace SW { - class PerfQuery : public PerfQueryBase { public: - PerfQuery() {} - ~PerfQuery() {} - - void EnableQuery(PerfQueryGroup type) override {} - void DisableQuery(PerfQueryGroup type) override {} - void ResetQuery() override - { - memset(EfbInterface::perf_values, 0, sizeof(EfbInterface::perf_values)); - } - u32 GetQueryResult(PerfQueryType type) override - { - return EfbInterface::perf_values[type]; - }; - void FlushResults() override {} - bool IsFlushed() const override { return true; }; + PerfQuery() {} + ~PerfQuery() {} + void EnableQuery(PerfQueryGroup type) override {} + void DisableQuery(PerfQueryGroup type) override {} + void ResetQuery() override + { + memset(EfbInterface::perf_values, 0, sizeof(EfbInterface::perf_values)); + } + u32 GetQueryResult(PerfQueryType type) override { return EfbInterface::perf_values[type]; }; + void FlushResults() override {} + bool IsFlushed() const override { return true; }; }; class TextureCache : public TextureCacheBase { public: - void CompileShaders() override {}; - void DeleteShaders() override {}; - void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format) override {}; - void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool isIntensity, bool scaleByHalf) override - { - EfbCopy::CopyEfb(); - } + void CompileShaders() override{}; + void DeleteShaders() override{}; + void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, + TlutFormat format) override{}; + void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, + u32 memory_stride, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, + bool isIntensity, bool scaleByHalf) override + { + EfbCopy::CopyEfb(); + } private: - struct TCacheEntry : TCacheEntryBase - { - TCacheEntry(const TCacheEntryConfig& _config) : TCacheEntryBase(_config) {} - ~TCacheEntry() {} + struct TCacheEntry : TCacheEntryBase + { + TCacheEntry(const TCacheEntryConfig& _config) : TCacheEntryBase(_config) {} + ~TCacheEntry() {} + void Load(unsigned int width, unsigned int height, unsigned int expanded_width, + unsigned int level) override + { + } - void Load(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int level) override {} + void FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, + bool scaleByHalf, unsigned int cbufid, const float* colmat) override + { + EfbCopy::CopyEfb(); + } - void FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool scaleByHalf, unsigned int cbufid, const float *colmat) override - { - EfbCopy::CopyEfb(); - } + void CopyRectangleFromTexture(const TCacheEntryBase* source, + const MathUtil::Rectangle& srcrect, + const MathUtil::Rectangle& dstrect) override + { + } - void CopyRectangleFromTexture( - const TCacheEntryBase* source, - const MathUtil::Rectangle& srcrect, - const MathUtil::Rectangle& dstrect) override {} + void Bind(unsigned int stage) override {} + bool Save(const std::string& filename, unsigned int level) override { return false; } + }; - void Bind(unsigned int stage) override {} - - bool Save(const std::string& filename, unsigned int level) override { return false; } - }; - - TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) override - { - return new TCacheEntry(config); - } + TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) override + { + return new TCacheEntry(config); + } }; class XFBSource : public XFBSourceBase { - void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override {} - void CopyEFB(float Gamma) override {} + void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override {} + void CopyEFB(float Gamma) override {} }; class FramebufferManager : public FramebufferManagerBase { - std::unique_ptr CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) override { return std::make_unique(); } - void GetTargetSize(unsigned int* width, unsigned int* height) override {}; - void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma = 1.0f) override - { - EfbCopy::CopyEfb(); - } + std::unique_ptr CreateXFBSource(unsigned int target_width, + unsigned int target_height, + unsigned int layers) override + { + return std::make_unique(); + } + void GetTargetSize(unsigned int* width, unsigned int* height) override{}; + void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, + float Gamma = 1.0f) override + { + EfbCopy::CopyEfb(); + } }; std::string VideoSoftware::GetName() const { - return "Software Renderer"; + return "Software Renderer"; } std::string VideoSoftware::GetDisplayName() const { - return "Software Renderer"; + return "Software Renderer"; } static void InitBackendInfo() { - g_Config.backend_info.APIType = API_NONE; - g_Config.backend_info.bSupports3DVision = false; - g_Config.backend_info.bSupportsDualSourceBlend = true; - g_Config.backend_info.bSupportsEarlyZ = true; - g_Config.backend_info.bSupportsOversizedViewports = true; - g_Config.backend_info.bSupportsPrimitiveRestart = false; + g_Config.backend_info.APIType = API_NONE; + g_Config.backend_info.bSupports3DVision = false; + g_Config.backend_info.bSupportsDualSourceBlend = true; + g_Config.backend_info.bSupportsEarlyZ = true; + g_Config.backend_info.bSupportsOversizedViewports = true; + g_Config.backend_info.bSupportsPrimitiveRestart = false; - // aamodes - g_Config.backend_info.AAModes = {1}; + // aamodes + g_Config.backend_info.AAModes = {1}; } -void VideoSoftware::ShowConfig(void *hParent) +void VideoSoftware::ShowConfig(void* hParent) { - if (!m_initialized) - InitBackendInfo(); - Host_ShowVideoConfig(hParent, GetDisplayName(), "gfx_software"); + if (!m_initialized) + InitBackendInfo(); + Host_ShowVideoConfig(hParent, GetDisplayName(), "gfx_software"); } -bool VideoSoftware::Initialize(void *window_handle) +bool VideoSoftware::Initialize(void* window_handle) { - InitializeShared(); - InitBackendInfo(); + InitializeShared(); + InitBackendInfo(); - g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_software.ini").c_str()); - g_Config.GameIniLoad(); - g_Config.UpdateProjectionHack(); - g_Config.VerifyValidity(); - UpdateActiveConfig(); + g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_software.ini").c_str()); + g_Config.GameIniLoad(); + g_Config.UpdateProjectionHack(); + g_Config.VerifyValidity(); + UpdateActiveConfig(); - SWOGLWindow::Init(window_handle); + SWOGLWindow::Init(window_handle); - PixelEngine::Init(); - Clipper::Init(); - Rasterizer::Init(); - SWRenderer::Init(); - DebugUtil::Init(); + PixelEngine::Init(); + Clipper::Init(); + Rasterizer::Init(); + SWRenderer::Init(); + DebugUtil::Init(); - // Do our OSD callbacks - OSD::DoCallbacks(OSD::CallbackType::Initialization); + // Do our OSD callbacks + OSD::DoCallbacks(OSD::CallbackType::Initialization); - m_initialized = true; + m_initialized = true; - return true; + return true; } void VideoSoftware::Shutdown() { - m_initialized = false; + m_initialized = false; - // Do our OSD callbacks - OSD::DoCallbacks(OSD::CallbackType::Shutdown); + // Do our OSD callbacks + OSD::DoCallbacks(OSD::CallbackType::Shutdown); - SWOGLWindow::Shutdown(); + SWOGLWindow::Shutdown(); } void VideoSoftware::Video_Cleanup() { - if (g_renderer) - { - Fifo::Shutdown(); - SWRenderer::Shutdown(); - DebugUtil::Shutdown(); - // The following calls are NOT Thread Safe - // And need to be called from the video thread - SWRenderer::Shutdown(); - VertexLoaderManager::Shutdown(); - g_framebuffer_manager.reset(); - g_texture_cache.reset(); - VertexShaderManager::Shutdown(); - PixelShaderManager::Shutdown(); - g_perf_query.reset(); - g_vertex_manager.reset(); - OpcodeDecoder::Shutdown(); - g_renderer.reset(); - } + if (g_renderer) + { + Fifo::Shutdown(); + SWRenderer::Shutdown(); + DebugUtil::Shutdown(); + // The following calls are NOT Thread Safe + // And need to be called from the video thread + SWRenderer::Shutdown(); + VertexLoaderManager::Shutdown(); + g_framebuffer_manager.reset(); + g_texture_cache.reset(); + VertexShaderManager::Shutdown(); + PixelShaderManager::Shutdown(); + g_perf_query.reset(); + g_vertex_manager.reset(); + OpcodeDecoder::Shutdown(); + g_renderer.reset(); + } } // This is called after Video_Initialize() from the Core void VideoSoftware::Video_Prepare() { - g_renderer = std::make_unique(); + g_renderer = std::make_unique(); - CommandProcessor::Init(); - PixelEngine::Init(); + CommandProcessor::Init(); + PixelEngine::Init(); - BPInit(); - g_vertex_manager = std::make_unique(); - g_perf_query = std::make_unique(); - Fifo::Init(); // must be done before OpcodeDecoder::Init() - OpcodeDecoder::Init(); - IndexGenerator::Init(); - VertexShaderManager::Init(); - PixelShaderManager::Init(); - g_texture_cache = std::make_unique(); - SWRenderer::Init(); - VertexLoaderManager::Init(); - g_framebuffer_manager = std::make_unique(); + BPInit(); + g_vertex_manager = std::make_unique(); + g_perf_query = std::make_unique(); + Fifo::Init(); // must be done before OpcodeDecoder::Init() + OpcodeDecoder::Init(); + IndexGenerator::Init(); + VertexShaderManager::Init(); + PixelShaderManager::Init(); + g_texture_cache = std::make_unique(); + SWRenderer::Init(); + VertexLoaderManager::Init(); + g_framebuffer_manager = std::make_unique(); - // Notify the core that the video backend is ready - Host_Message(WM_USER_CREATE); + // Notify the core that the video backend is ready + Host_Message(WM_USER_CREATE); - INFO_LOG(VIDEO, "Video backend initialized."); + INFO_LOG(VIDEO, "Video backend initialized."); } unsigned int VideoSoftware::PeekMessages() { - return SWOGLWindow::s_instance->PeekMessages(); + return SWOGLWindow::s_instance->PeekMessages(); } - } diff --git a/Source/Core/VideoBackends/Software/SetupUnit.cpp b/Source/Core/VideoBackends/Software/SetupUnit.cpp index a9ef985963..78e331e15a 100644 --- a/Source/Core/VideoBackends/Software/SetupUnit.cpp +++ b/Source/Core/VideoBackends/Software/SetupUnit.cpp @@ -2,166 +2,165 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoBackends/Software/SetupUnit.h" #include "Common/ChunkFile.h" #include "VideoBackends/Software/Clipper.h" -#include "VideoBackends/Software/SetupUnit.h" #include "VideoCommon/OpcodeDecoding.h" void SetupUnit::Init(u8 primitiveType) { - m_PrimType = primitiveType; + m_PrimType = primitiveType; - m_VertexCounter = 0; - m_VertPointer[0] = &m_Vertices[0]; - m_VertPointer[1] = &m_Vertices[1]; - m_VertPointer[2] = &m_Vertices[2]; - m_VertWritePointer = m_VertPointer[0]; + m_VertexCounter = 0; + m_VertPointer[0] = &m_Vertices[0]; + m_VertPointer[1] = &m_Vertices[1]; + m_VertPointer[2] = &m_Vertices[2]; + m_VertWritePointer = m_VertPointer[0]; } OutputVertexData* SetupUnit::GetVertex() { - memset(m_VertWritePointer, 0, sizeof(*m_VertWritePointer)); - return m_VertWritePointer; + memset(m_VertWritePointer, 0, sizeof(*m_VertWritePointer)); + return m_VertWritePointer; } void SetupUnit::SetupVertex() { - switch (m_PrimType) - { - case GX_DRAW_QUADS: - SetupQuad(); - break; - case GX_DRAW_QUADS_2: - WARN_LOG(VIDEO, "Non-standard primitive drawing command GL_DRAW_QUADS_2"); - SetupQuad(); - break; - case GX_DRAW_TRIANGLES: - SetupTriangle(); - break; - case GX_DRAW_TRIANGLE_STRIP: - SetupTriStrip(); - break; - case GX_DRAW_TRIANGLE_FAN: - SetupTriFan(); - break; - case GX_DRAW_LINES: - SetupLine(); - break; - case GX_DRAW_LINE_STRIP: - SetupLineStrip(); - break; - case GX_DRAW_POINTS: - SetupPoint(); - break; - } + switch (m_PrimType) + { + case GX_DRAW_QUADS: + SetupQuad(); + break; + case GX_DRAW_QUADS_2: + WARN_LOG(VIDEO, "Non-standard primitive drawing command GL_DRAW_QUADS_2"); + SetupQuad(); + break; + case GX_DRAW_TRIANGLES: + SetupTriangle(); + break; + case GX_DRAW_TRIANGLE_STRIP: + SetupTriStrip(); + break; + case GX_DRAW_TRIANGLE_FAN: + SetupTriFan(); + break; + case GX_DRAW_LINES: + SetupLine(); + break; + case GX_DRAW_LINE_STRIP: + SetupLineStrip(); + break; + case GX_DRAW_POINTS: + SetupPoint(); + break; + } } - void SetupUnit::SetupQuad() { - if (m_VertexCounter < 2) - { - m_VertexCounter++; - m_VertWritePointer = m_VertPointer[m_VertexCounter]; - return; - } + if (m_VertexCounter < 2) + { + m_VertexCounter++; + m_VertWritePointer = m_VertPointer[m_VertexCounter]; + return; + } - Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]); + Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]); - m_VertexCounter++; - m_VertexCounter &= 3; - m_VertWritePointer = &m_Vertices[m_VertexCounter & 1]; - OutputVertexData* temp = m_VertPointer[1]; - m_VertPointer[1] = m_VertPointer[2]; - m_VertPointer[2] = temp; + m_VertexCounter++; + m_VertexCounter &= 3; + m_VertWritePointer = &m_Vertices[m_VertexCounter & 1]; + OutputVertexData* temp = m_VertPointer[1]; + m_VertPointer[1] = m_VertPointer[2]; + m_VertPointer[2] = temp; } void SetupUnit::SetupTriangle() { - if (m_VertexCounter < 2) - { - m_VertexCounter++; - m_VertWritePointer = m_VertPointer[m_VertexCounter]; - return; - } + if (m_VertexCounter < 2) + { + m_VertexCounter++; + m_VertWritePointer = m_VertPointer[m_VertexCounter]; + return; + } - Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]); + Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]); - m_VertexCounter = 0; - m_VertWritePointer = m_VertPointer[0]; + m_VertexCounter = 0; + m_VertWritePointer = m_VertPointer[0]; } void SetupUnit::SetupTriStrip() { - if (m_VertexCounter < 2) - { - m_VertexCounter++; - m_VertWritePointer = m_VertPointer[m_VertexCounter]; - return; - } + if (m_VertexCounter < 2) + { + m_VertexCounter++; + m_VertWritePointer = m_VertPointer[m_VertexCounter]; + return; + } - Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]); + Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]); - m_VertexCounter++; - m_VertPointer[2 - (m_VertexCounter & 1)] = m_VertPointer[0]; - m_VertWritePointer = m_VertPointer[0]; + m_VertexCounter++; + m_VertPointer[2 - (m_VertexCounter & 1)] = m_VertPointer[0]; + m_VertWritePointer = m_VertPointer[0]; - m_VertPointer[0] = &m_Vertices[(m_VertexCounter + 1) % 3]; + m_VertPointer[0] = &m_Vertices[(m_VertexCounter + 1) % 3]; } void SetupUnit::SetupTriFan() { - if (m_VertexCounter < 2) - { - m_VertexCounter++; - m_VertWritePointer = m_VertPointer[m_VertexCounter]; - return; - } + if (m_VertexCounter < 2) + { + m_VertexCounter++; + m_VertWritePointer = m_VertPointer[m_VertexCounter]; + return; + } - Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]); + Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]); - m_VertexCounter++; - m_VertPointer[1] = m_VertPointer[2]; - m_VertPointer[2] = &m_Vertices[2 - (m_VertexCounter & 1)]; + m_VertexCounter++; + m_VertPointer[1] = m_VertPointer[2]; + m_VertPointer[2] = &m_Vertices[2 - (m_VertexCounter & 1)]; - m_VertWritePointer = m_VertPointer[2]; + m_VertWritePointer = m_VertPointer[2]; } void SetupUnit::SetupLine() { - if (m_VertexCounter < 1) - { - m_VertexCounter++; - m_VertWritePointer = m_VertPointer[m_VertexCounter]; - return; - } + if (m_VertexCounter < 1) + { + m_VertexCounter++; + m_VertWritePointer = m_VertPointer[m_VertexCounter]; + return; + } - Clipper::ProcessLine(m_VertPointer[0], m_VertPointer[1]); + Clipper::ProcessLine(m_VertPointer[0], m_VertPointer[1]); - m_VertexCounter = 0; - m_VertWritePointer = m_VertPointer[0]; + m_VertexCounter = 0; + m_VertWritePointer = m_VertPointer[0]; } void SetupUnit::SetupLineStrip() { - if (m_VertexCounter < 1) - { - m_VertexCounter++; - m_VertWritePointer = m_VertPointer[m_VertexCounter]; - return; - } + if (m_VertexCounter < 1) + { + m_VertexCounter++; + m_VertWritePointer = m_VertPointer[m_VertexCounter]; + return; + } - m_VertexCounter++; + m_VertexCounter++; - Clipper::ProcessLine(m_VertPointer[0], m_VertPointer[1]); + Clipper::ProcessLine(m_VertPointer[0], m_VertPointer[1]); - m_VertWritePointer = m_VertPointer[0]; + m_VertWritePointer = m_VertPointer[0]; - m_VertPointer[0] = m_VertPointer[1]; - m_VertPointer[1] = &m_Vertices[m_VertexCounter & 1]; + m_VertPointer[0] = m_VertPointer[1]; + m_VertPointer[1] = &m_Vertices[m_VertexCounter & 1]; } void SetupUnit::SetupPoint() -{} - +{ +} diff --git a/Source/Core/VideoBackends/Software/SetupUnit.h b/Source/Core/VideoBackends/Software/SetupUnit.h index a00fc29634..642376c710 100644 --- a/Source/Core/VideoBackends/Software/SetupUnit.h +++ b/Source/Core/VideoBackends/Software/SetupUnit.h @@ -9,25 +9,25 @@ class SetupUnit { - u8 m_PrimType; - int m_VertexCounter; + u8 m_PrimType; + int m_VertexCounter; - OutputVertexData m_Vertices[3]; - OutputVertexData *m_VertPointer[3]; - OutputVertexData *m_VertWritePointer; + OutputVertexData m_Vertices[3]; + OutputVertexData* m_VertPointer[3]; + OutputVertexData* m_VertWritePointer; - void SetupQuad(); - void SetupTriangle(); - void SetupTriStrip(); - void SetupTriFan(); - void SetupLine(); - void SetupLineStrip(); - void SetupPoint(); + void SetupQuad(); + void SetupTriangle(); + void SetupTriStrip(); + void SetupTriFan(); + void SetupLine(); + void SetupLineStrip(); + void SetupPoint(); public: - void Init(u8 primitiveType); + void Init(u8 primitiveType); - OutputVertexData* GetVertex(); + OutputVertexData* GetVertex(); - void SetupVertex(); + void SetupVertex(); }; diff --git a/Source/Core/VideoBackends/Software/Tev.cpp b/Source/Core/VideoBackends/Software/Tev.cpp index b8c02187d4..54dd305206 100644 --- a/Source/Core/VideoBackends/Software/Tev.cpp +++ b/Source/Core/VideoBackends/Software/Tev.cpp @@ -26,792 +26,855 @@ void Tev::Init() { - FixedConstants[0] = 0; - FixedConstants[1] = 32; - FixedConstants[2] = 64; - FixedConstants[3] = 96; - FixedConstants[4] = 128; - FixedConstants[5] = 159; - FixedConstants[6] = 191; - FixedConstants[7] = 223; - FixedConstants[8] = 255; + FixedConstants[0] = 0; + FixedConstants[1] = 32; + FixedConstants[2] = 64; + FixedConstants[3] = 96; + FixedConstants[4] = 128; + FixedConstants[5] = 159; + FixedConstants[6] = 191; + FixedConstants[7] = 223; + FixedConstants[8] = 255; - for (s16& comp : Zero16) - { - comp = 0; - } + for (s16& comp : Zero16) + { + comp = 0; + } - m_ColorInputLUT[0][RED_INP] = &Reg[0][RED_C]; m_ColorInputLUT[0][GRN_INP] = &Reg[0][GRN_C]; m_ColorInputLUT[0][BLU_INP] = &Reg[0][BLU_C]; // prev.rgb - m_ColorInputLUT[1][RED_INP] = &Reg[0][ALP_C]; m_ColorInputLUT[1][GRN_INP] = &Reg[0][ALP_C]; m_ColorInputLUT[1][BLU_INP] = &Reg[0][ALP_C]; // prev.aaa - m_ColorInputLUT[2][RED_INP] = &Reg[1][RED_C]; m_ColorInputLUT[2][GRN_INP] = &Reg[1][GRN_C]; m_ColorInputLUT[2][BLU_INP] = &Reg[1][BLU_C]; // c0.rgb - m_ColorInputLUT[3][RED_INP] = &Reg[1][ALP_C]; m_ColorInputLUT[3][GRN_INP] = &Reg[1][ALP_C]; m_ColorInputLUT[3][BLU_INP] = &Reg[1][ALP_C]; // c0.aaa - m_ColorInputLUT[4][RED_INP] = &Reg[2][RED_C]; m_ColorInputLUT[4][GRN_INP] = &Reg[2][GRN_C]; m_ColorInputLUT[4][BLU_INP] = &Reg[2][BLU_C]; // c1.rgb - m_ColorInputLUT[5][RED_INP] = &Reg[2][ALP_C]; m_ColorInputLUT[5][GRN_INP] = &Reg[2][ALP_C]; m_ColorInputLUT[5][BLU_INP] = &Reg[2][ALP_C]; // c1.aaa - m_ColorInputLUT[6][RED_INP] = &Reg[3][RED_C]; m_ColorInputLUT[6][GRN_INP] = &Reg[3][GRN_C]; m_ColorInputLUT[6][BLU_INP] = &Reg[3][BLU_C]; // c2.rgb - m_ColorInputLUT[7][RED_INP] = &Reg[3][ALP_C]; m_ColorInputLUT[7][GRN_INP] = &Reg[3][ALP_C]; m_ColorInputLUT[7][BLU_INP] = &Reg[3][ALP_C]; // c2.aaa - m_ColorInputLUT[8][RED_INP] = &TexColor[RED_C]; m_ColorInputLUT[8][GRN_INP] = &TexColor[GRN_C]; m_ColorInputLUT[8][BLU_INP] = &TexColor[BLU_C]; // tex.rgb - m_ColorInputLUT[9][RED_INP] = &TexColor[ALP_C]; m_ColorInputLUT[9][GRN_INP] = &TexColor[ALP_C]; m_ColorInputLUT[9][BLU_INP] = &TexColor[ALP_C]; // tex.aaa - m_ColorInputLUT[10][RED_INP] = &RasColor[RED_C]; m_ColorInputLUT[10][GRN_INP] = &RasColor[GRN_C]; m_ColorInputLUT[10][BLU_INP] = &RasColor[BLU_C]; // ras.rgb - m_ColorInputLUT[11][RED_INP] = &RasColor[ALP_C]; m_ColorInputLUT[11][GRN_INP] = &RasColor[ALP_C]; m_ColorInputLUT[11][BLU_INP] = &RasColor[ALP_C]; // ras.rgb - m_ColorInputLUT[12][RED_INP] = &FixedConstants[8]; m_ColorInputLUT[12][GRN_INP] = &FixedConstants[8]; m_ColorInputLUT[12][BLU_INP] = &FixedConstants[8]; // one - m_ColorInputLUT[13][RED_INP] = &FixedConstants[4]; m_ColorInputLUT[13][GRN_INP] = &FixedConstants[4]; m_ColorInputLUT[13][BLU_INP] = &FixedConstants[4]; // half - m_ColorInputLUT[14][RED_INP] = &StageKonst[RED_C]; m_ColorInputLUT[14][GRN_INP] = &StageKonst[GRN_C]; m_ColorInputLUT[14][BLU_INP] = &StageKonst[BLU_C]; // konst - m_ColorInputLUT[15][RED_INP] = &FixedConstants[0]; m_ColorInputLUT[15][GRN_INP] = &FixedConstants[0]; m_ColorInputLUT[15][BLU_INP] = &FixedConstants[0]; // zero + m_ColorInputLUT[0][RED_INP] = &Reg[0][RED_C]; + m_ColorInputLUT[0][GRN_INP] = &Reg[0][GRN_C]; + m_ColorInputLUT[0][BLU_INP] = &Reg[0][BLU_C]; // prev.rgb + m_ColorInputLUT[1][RED_INP] = &Reg[0][ALP_C]; + m_ColorInputLUT[1][GRN_INP] = &Reg[0][ALP_C]; + m_ColorInputLUT[1][BLU_INP] = &Reg[0][ALP_C]; // prev.aaa + m_ColorInputLUT[2][RED_INP] = &Reg[1][RED_C]; + m_ColorInputLUT[2][GRN_INP] = &Reg[1][GRN_C]; + m_ColorInputLUT[2][BLU_INP] = &Reg[1][BLU_C]; // c0.rgb + m_ColorInputLUT[3][RED_INP] = &Reg[1][ALP_C]; + m_ColorInputLUT[3][GRN_INP] = &Reg[1][ALP_C]; + m_ColorInputLUT[3][BLU_INP] = &Reg[1][ALP_C]; // c0.aaa + m_ColorInputLUT[4][RED_INP] = &Reg[2][RED_C]; + m_ColorInputLUT[4][GRN_INP] = &Reg[2][GRN_C]; + m_ColorInputLUT[4][BLU_INP] = &Reg[2][BLU_C]; // c1.rgb + m_ColorInputLUT[5][RED_INP] = &Reg[2][ALP_C]; + m_ColorInputLUT[5][GRN_INP] = &Reg[2][ALP_C]; + m_ColorInputLUT[5][BLU_INP] = &Reg[2][ALP_C]; // c1.aaa + m_ColorInputLUT[6][RED_INP] = &Reg[3][RED_C]; + m_ColorInputLUT[6][GRN_INP] = &Reg[3][GRN_C]; + m_ColorInputLUT[6][BLU_INP] = &Reg[3][BLU_C]; // c2.rgb + m_ColorInputLUT[7][RED_INP] = &Reg[3][ALP_C]; + m_ColorInputLUT[7][GRN_INP] = &Reg[3][ALP_C]; + m_ColorInputLUT[7][BLU_INP] = &Reg[3][ALP_C]; // c2.aaa + m_ColorInputLUT[8][RED_INP] = &TexColor[RED_C]; + m_ColorInputLUT[8][GRN_INP] = &TexColor[GRN_C]; + m_ColorInputLUT[8][BLU_INP] = &TexColor[BLU_C]; // tex.rgb + m_ColorInputLUT[9][RED_INP] = &TexColor[ALP_C]; + m_ColorInputLUT[9][GRN_INP] = &TexColor[ALP_C]; + m_ColorInputLUT[9][BLU_INP] = &TexColor[ALP_C]; // tex.aaa + m_ColorInputLUT[10][RED_INP] = &RasColor[RED_C]; + m_ColorInputLUT[10][GRN_INP] = &RasColor[GRN_C]; + m_ColorInputLUT[10][BLU_INP] = &RasColor[BLU_C]; // ras.rgb + m_ColorInputLUT[11][RED_INP] = &RasColor[ALP_C]; + m_ColorInputLUT[11][GRN_INP] = &RasColor[ALP_C]; + m_ColorInputLUT[11][BLU_INP] = &RasColor[ALP_C]; // ras.rgb + m_ColorInputLUT[12][RED_INP] = &FixedConstants[8]; + m_ColorInputLUT[12][GRN_INP] = &FixedConstants[8]; + m_ColorInputLUT[12][BLU_INP] = &FixedConstants[8]; // one + m_ColorInputLUT[13][RED_INP] = &FixedConstants[4]; + m_ColorInputLUT[13][GRN_INP] = &FixedConstants[4]; + m_ColorInputLUT[13][BLU_INP] = &FixedConstants[4]; // half + m_ColorInputLUT[14][RED_INP] = &StageKonst[RED_C]; + m_ColorInputLUT[14][GRN_INP] = &StageKonst[GRN_C]; + m_ColorInputLUT[14][BLU_INP] = &StageKonst[BLU_C]; // konst + m_ColorInputLUT[15][RED_INP] = &FixedConstants[0]; + m_ColorInputLUT[15][GRN_INP] = &FixedConstants[0]; + m_ColorInputLUT[15][BLU_INP] = &FixedConstants[0]; // zero - m_AlphaInputLUT[0] = &Reg[0][ALP_C]; // prev - m_AlphaInputLUT[1] = &Reg[1][ALP_C]; // c0 - m_AlphaInputLUT[2] = &Reg[2][ALP_C]; // c1 - m_AlphaInputLUT[3] = &Reg[3][ALP_C]; // c2 - m_AlphaInputLUT[4] = &TexColor[ALP_C]; // tex - m_AlphaInputLUT[5] = &RasColor[ALP_C]; // ras - m_AlphaInputLUT[6] = &StageKonst[ALP_C]; // konst - m_AlphaInputLUT[7] = &Zero16[ALP_C]; // zero + m_AlphaInputLUT[0] = &Reg[0][ALP_C]; // prev + m_AlphaInputLUT[1] = &Reg[1][ALP_C]; // c0 + m_AlphaInputLUT[2] = &Reg[2][ALP_C]; // c1 + m_AlphaInputLUT[3] = &Reg[3][ALP_C]; // c2 + m_AlphaInputLUT[4] = &TexColor[ALP_C]; // tex + m_AlphaInputLUT[5] = &RasColor[ALP_C]; // ras + m_AlphaInputLUT[6] = &StageKonst[ALP_C]; // konst + m_AlphaInputLUT[7] = &Zero16[ALP_C]; // zero - for (int comp = 0; comp < 4; comp++) - { - m_KonstLUT[0][comp] = &FixedConstants[8]; - m_KonstLUT[1][comp] = &FixedConstants[7]; - m_KonstLUT[2][comp] = &FixedConstants[6]; - m_KonstLUT[3][comp] = &FixedConstants[5]; - m_KonstLUT[4][comp] = &FixedConstants[4]; - m_KonstLUT[5][comp] = &FixedConstants[3]; - m_KonstLUT[6][comp] = &FixedConstants[2]; - m_KonstLUT[7][comp] = &FixedConstants[1]; + for (int comp = 0; comp < 4; comp++) + { + m_KonstLUT[0][comp] = &FixedConstants[8]; + m_KonstLUT[1][comp] = &FixedConstants[7]; + m_KonstLUT[2][comp] = &FixedConstants[6]; + m_KonstLUT[3][comp] = &FixedConstants[5]; + m_KonstLUT[4][comp] = &FixedConstants[4]; + m_KonstLUT[5][comp] = &FixedConstants[3]; + m_KonstLUT[6][comp] = &FixedConstants[2]; + m_KonstLUT[7][comp] = &FixedConstants[1]; - // These are "invalid" values, not meant to be used. On hardware, - // they all output zero. - for (int i = 8; i < 16; ++i) - { - m_KonstLUT[i][comp] = &FixedConstants[0]; - } + // These are "invalid" values, not meant to be used. On hardware, + // they all output zero. + for (int i = 8; i < 16; ++i) + { + m_KonstLUT[i][comp] = &FixedConstants[0]; + } - if (comp != ALP_C) - { - m_KonstLUT[12][comp] = &KonstantColors[0][comp]; - m_KonstLUT[13][comp] = &KonstantColors[1][comp]; - m_KonstLUT[14][comp] = &KonstantColors[2][comp]; - m_KonstLUT[15][comp] = &KonstantColors[3][comp]; - } + if (comp != ALP_C) + { + m_KonstLUT[12][comp] = &KonstantColors[0][comp]; + m_KonstLUT[13][comp] = &KonstantColors[1][comp]; + m_KonstLUT[14][comp] = &KonstantColors[2][comp]; + m_KonstLUT[15][comp] = &KonstantColors[3][comp]; + } - m_KonstLUT[16][comp] = &KonstantColors[0][RED_C]; - m_KonstLUT[17][comp] = &KonstantColors[1][RED_C]; - m_KonstLUT[18][comp] = &KonstantColors[2][RED_C]; - m_KonstLUT[19][comp] = &KonstantColors[3][RED_C]; - m_KonstLUT[20][comp] = &KonstantColors[0][GRN_C]; - m_KonstLUT[21][comp] = &KonstantColors[1][GRN_C]; - m_KonstLUT[22][comp] = &KonstantColors[2][GRN_C]; - m_KonstLUT[23][comp] = &KonstantColors[3][GRN_C]; - m_KonstLUT[24][comp] = &KonstantColors[0][BLU_C]; - m_KonstLUT[25][comp] = &KonstantColors[1][BLU_C]; - m_KonstLUT[26][comp] = &KonstantColors[2][BLU_C]; - m_KonstLUT[27][comp] = &KonstantColors[3][BLU_C]; - m_KonstLUT[28][comp] = &KonstantColors[0][ALP_C]; - m_KonstLUT[29][comp] = &KonstantColors[1][ALP_C]; - m_KonstLUT[30][comp] = &KonstantColors[2][ALP_C]; - m_KonstLUT[31][comp] = &KonstantColors[3][ALP_C]; - } + m_KonstLUT[16][comp] = &KonstantColors[0][RED_C]; + m_KonstLUT[17][comp] = &KonstantColors[1][RED_C]; + m_KonstLUT[18][comp] = &KonstantColors[2][RED_C]; + m_KonstLUT[19][comp] = &KonstantColors[3][RED_C]; + m_KonstLUT[20][comp] = &KonstantColors[0][GRN_C]; + m_KonstLUT[21][comp] = &KonstantColors[1][GRN_C]; + m_KonstLUT[22][comp] = &KonstantColors[2][GRN_C]; + m_KonstLUT[23][comp] = &KonstantColors[3][GRN_C]; + m_KonstLUT[24][comp] = &KonstantColors[0][BLU_C]; + m_KonstLUT[25][comp] = &KonstantColors[1][BLU_C]; + m_KonstLUT[26][comp] = &KonstantColors[2][BLU_C]; + m_KonstLUT[27][comp] = &KonstantColors[3][BLU_C]; + m_KonstLUT[28][comp] = &KonstantColors[0][ALP_C]; + m_KonstLUT[29][comp] = &KonstantColors[1][ALP_C]; + m_KonstLUT[30][comp] = &KonstantColors[2][ALP_C]; + m_KonstLUT[31][comp] = &KonstantColors[3][ALP_C]; + } - m_BiasLUT[0] = 0; - m_BiasLUT[1] = 128; - m_BiasLUT[2] = -128; - m_BiasLUT[3] = 0; + m_BiasLUT[0] = 0; + m_BiasLUT[1] = 128; + m_BiasLUT[2] = -128; + m_BiasLUT[3] = 0; - m_ScaleLShiftLUT[0] = 0; - m_ScaleLShiftLUT[1] = 1; - m_ScaleLShiftLUT[2] = 2; - m_ScaleLShiftLUT[3] = 0; + m_ScaleLShiftLUT[0] = 0; + m_ScaleLShiftLUT[1] = 1; + m_ScaleLShiftLUT[2] = 2; + m_ScaleLShiftLUT[3] = 0; - m_ScaleRShiftLUT[0] = 0; - m_ScaleRShiftLUT[1] = 0; - m_ScaleRShiftLUT[2] = 0; - m_ScaleRShiftLUT[3] = 1; + m_ScaleRShiftLUT[0] = 0; + m_ScaleRShiftLUT[1] = 0; + m_ScaleRShiftLUT[2] = 0; + m_ScaleRShiftLUT[3] = 1; } static inline s16 Clamp255(s16 in) { - return in>255?255:(in<0?0:in); + return in > 255 ? 255 : (in < 0 ? 0 : in); } static inline s16 Clamp1024(s16 in) { - return in>1023?1023:(in<-1024?-1024:in); + return in > 1023 ? 1023 : (in < -1024 ? -1024 : in); } void Tev::SetRasColor(int colorChan, int swaptable) { - switch (colorChan) - { - case 0: // Color0 - { - u8 *color = Color[0]; - RasColor[RED_C] = color[bpmem.tevksel[swaptable].swap1]; - RasColor[GRN_C] = color[bpmem.tevksel[swaptable].swap2]; - swaptable++; - RasColor[BLU_C] = color[bpmem.tevksel[swaptable].swap1]; - RasColor[ALP_C] = color[bpmem.tevksel[swaptable].swap2]; - } - break; - case 1: // Color1 - { - u8 *color = Color[1]; - RasColor[RED_C] = color[bpmem.tevksel[swaptable].swap1]; - RasColor[GRN_C] = color[bpmem.tevksel[swaptable].swap2]; - swaptable++; - RasColor[BLU_C] = color[bpmem.tevksel[swaptable].swap1]; - RasColor[ALP_C] = color[bpmem.tevksel[swaptable].swap2]; - } - break; - case 5: // alpha bump - { - for (s16& comp : RasColor) - { - comp = AlphaBump; - } - } - break; - case 6: // alpha bump normalized - { - u8 normalized = AlphaBump | AlphaBump >> 5; - for (s16& comp : RasColor) - { - comp = normalized; - } - } - break; - default: // zero - { - for (s16& comp : RasColor) - { - comp = 0; - } - } - break; - } + switch (colorChan) + { + case 0: // Color0 + { + u8* color = Color[0]; + RasColor[RED_C] = color[bpmem.tevksel[swaptable].swap1]; + RasColor[GRN_C] = color[bpmem.tevksel[swaptable].swap2]; + swaptable++; + RasColor[BLU_C] = color[bpmem.tevksel[swaptable].swap1]; + RasColor[ALP_C] = color[bpmem.tevksel[swaptable].swap2]; + } + break; + case 1: // Color1 + { + u8* color = Color[1]; + RasColor[RED_C] = color[bpmem.tevksel[swaptable].swap1]; + RasColor[GRN_C] = color[bpmem.tevksel[swaptable].swap2]; + swaptable++; + RasColor[BLU_C] = color[bpmem.tevksel[swaptable].swap1]; + RasColor[ALP_C] = color[bpmem.tevksel[swaptable].swap2]; + } + break; + case 5: // alpha bump + { + for (s16& comp : RasColor) + { + comp = AlphaBump; + } + } + break; + case 6: // alpha bump normalized + { + u8 normalized = AlphaBump | AlphaBump >> 5; + for (s16& comp : RasColor) + { + comp = normalized; + } + } + break; + default: // zero + { + for (s16& comp : RasColor) + { + comp = 0; + } + } + break; + } } -void Tev::DrawColorRegular(TevStageCombiner::ColorCombiner &cc, const InputRegType inputs[4]) +void Tev::DrawColorRegular(TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]) { - for (int i = 0; i < 3; i++) - { - const InputRegType& InputReg = inputs[BLU_C + i]; + for (int i = 0; i < 3; i++) + { + const InputRegType& InputReg = inputs[BLU_C + i]; - u16 c = InputReg.c + (InputReg.c >> 7); + u16 c = InputReg.c + (InputReg.c >> 7); - s32 temp = InputReg.a * (256 - c) + (InputReg.b * c); - temp <<= m_ScaleLShiftLUT[cc.shift]; - temp += (cc.shift == 3) ? 0 : (cc.op == 1) ? 127 : 128; - temp >>= 8; - temp = cc.op ? -temp : temp; + s32 temp = InputReg.a * (256 - c) + (InputReg.b * c); + temp <<= m_ScaleLShiftLUT[cc.shift]; + temp += (cc.shift == 3) ? 0 : (cc.op == 1) ? 127 : 128; + temp >>= 8; + temp = cc.op ? -temp : temp; - s32 result = ((InputReg.d + m_BiasLUT[cc.bias]) << m_ScaleLShiftLUT[cc.shift]) + temp; - result = result >> m_ScaleRShiftLUT[cc.shift]; + s32 result = ((InputReg.d + m_BiasLUT[cc.bias]) << m_ScaleLShiftLUT[cc.shift]) + temp; + result = result >> m_ScaleRShiftLUT[cc.shift]; - Reg[cc.dest][BLU_C + i] = result; - } + Reg[cc.dest][BLU_C + i] = result; + } } -void Tev::DrawColorCompare(TevStageCombiner::ColorCombiner &cc, const InputRegType inputs[4]) +void Tev::DrawColorCompare(TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]) { - for (int i = BLU_C; i <= RED_C; i++) - { - switch ((cc.shift<<1)|cc.op|8) // encoded compare mode - { - case TEVCMP_R8_GT: - Reg[cc.dest][i] = inputs[i].d + ((inputs[RED_C].a > inputs[RED_C].b) ? inputs[i].c : 0); - break; + for (int i = BLU_C; i <= RED_C; i++) + { + switch ((cc.shift << 1) | cc.op | 8) // encoded compare mode + { + case TEVCMP_R8_GT: + Reg[cc.dest][i] = inputs[i].d + ((inputs[RED_C].a > inputs[RED_C].b) ? inputs[i].c : 0); + break; - case TEVCMP_R8_EQ: - Reg[cc.dest][i] = inputs[i].d + ((inputs[RED_C].a == inputs[RED_C].b) ? inputs[i].c : 0); - break; + case TEVCMP_R8_EQ: + Reg[cc.dest][i] = inputs[i].d + ((inputs[RED_C].a == inputs[RED_C].b) ? inputs[i].c : 0); + break; - case TEVCMP_GR16_GT: - { - u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; - u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[cc.dest][i] = inputs[i].d + ((a > b) ? inputs[i].c : 0); - } - break; + case TEVCMP_GR16_GT: + { + u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; + u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; + Reg[cc.dest][i] = inputs[i].d + ((a > b) ? inputs[i].c : 0); + } + break; - case TEVCMP_GR16_EQ: - { - u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; - u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[cc.dest][i] = inputs[i].d + ((a == b) ? inputs[i].c : 0); - } - break; + case TEVCMP_GR16_EQ: + { + u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; + u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; + Reg[cc.dest][i] = inputs[i].d + ((a == b) ? inputs[i].c : 0); + } + break; - case TEVCMP_BGR24_GT: - { - u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a; - u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[cc.dest][i] = inputs[i].d + ((a > b) ? inputs[i].c : 0); - } - break; + case TEVCMP_BGR24_GT: + { + u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a; + u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b; + Reg[cc.dest][i] = inputs[i].d + ((a > b) ? inputs[i].c : 0); + } + break; - case TEVCMP_BGR24_EQ: - { - u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a; - u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[cc.dest][i] = inputs[i].d + ((a == b) ? inputs[i].c : 0); - } - break; + case TEVCMP_BGR24_EQ: + { + u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a; + u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b; + Reg[cc.dest][i] = inputs[i].d + ((a == b) ? inputs[i].c : 0); + } + break; - case TEVCMP_RGB8_GT: - Reg[cc.dest][i] = inputs[i].d + ((inputs[i].a > inputs[i].b) ? inputs[i].c : 0); - break; + case TEVCMP_RGB8_GT: + Reg[cc.dest][i] = inputs[i].d + ((inputs[i].a > inputs[i].b) ? inputs[i].c : 0); + break; - case TEVCMP_RGB8_EQ: - Reg[cc.dest][i] = inputs[i].d + ((inputs[i].a == inputs[i].b) ? inputs[i].c : 0); - break; - } - } + case TEVCMP_RGB8_EQ: + Reg[cc.dest][i] = inputs[i].d + ((inputs[i].a == inputs[i].b) ? inputs[i].c : 0); + break; + } + } } -void Tev::DrawAlphaRegular(TevStageCombiner::AlphaCombiner &ac, const InputRegType inputs[4]) +void Tev::DrawAlphaRegular(TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4]) { - const InputRegType& InputReg = inputs[ALP_C]; + const InputRegType& InputReg = inputs[ALP_C]; - u16 c = InputReg.c + (InputReg.c >> 7); + u16 c = InputReg.c + (InputReg.c >> 7); - s32 temp = InputReg.a * (256 - c) + (InputReg.b * c); - temp <<= m_ScaleLShiftLUT[ac.shift]; - temp += (ac.shift != 3) ? 0 : (ac.op == 1) ? 127 : 128; - temp = ac.op ? (-temp >> 8) : (temp >> 8); + s32 temp = InputReg.a * (256 - c) + (InputReg.b * c); + temp <<= m_ScaleLShiftLUT[ac.shift]; + temp += (ac.shift != 3) ? 0 : (ac.op == 1) ? 127 : 128; + temp = ac.op ? (-temp >> 8) : (temp >> 8); - s32 result = ((InputReg.d + m_BiasLUT[ac.bias]) << m_ScaleLShiftLUT[ac.shift]) + temp; - result = result >> m_ScaleRShiftLUT[ac.shift]; + s32 result = ((InputReg.d + m_BiasLUT[ac.bias]) << m_ScaleLShiftLUT[ac.shift]) + temp; + result = result >> m_ScaleRShiftLUT[ac.shift]; - Reg[ac.dest][ALP_C] = result; + Reg[ac.dest][ALP_C] = result; } void Tev::DrawAlphaCompare(TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4]) { - switch ((ac.shift<<1)|ac.op|8) // encoded compare mode - { - case TEVCMP_R8_GT: - Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((inputs[RED_C].a > inputs[RED_C].b) ? inputs[ALP_C].c : 0); - break; + switch ((ac.shift << 1) | ac.op | 8) // encoded compare mode + { + case TEVCMP_R8_GT: + Reg[ac.dest][ALP_C] = + inputs[ALP_C].d + ((inputs[RED_C].a > inputs[RED_C].b) ? inputs[ALP_C].c : 0); + break; - case TEVCMP_R8_EQ: - Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((inputs[RED_C].a == inputs[RED_C].b) ? inputs[ALP_C].c : 0); - break; + case TEVCMP_R8_EQ: + Reg[ac.dest][ALP_C] = + inputs[ALP_C].d + ((inputs[RED_C].a == inputs[RED_C].b) ? inputs[ALP_C].c : 0); + break; - case TEVCMP_GR16_GT: - { - u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; - u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a > b) ? inputs[ALP_C].c : 0); - } - break; + case TEVCMP_GR16_GT: + { + u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; + u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; + Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a > b) ? inputs[ALP_C].c : 0); + } + break; - case TEVCMP_GR16_EQ: - { - u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; - u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a == b) ? inputs[ALP_C].c : 0); - } - break; + case TEVCMP_GR16_EQ: + { + u32 a = (inputs[GRN_C].a << 8) | inputs[RED_C].a; + u32 b = (inputs[GRN_C].b << 8) | inputs[RED_C].b; + Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a == b) ? inputs[ALP_C].c : 0); + } + break; - case TEVCMP_BGR24_GT: - { - u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a; - u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a > b) ? inputs[ALP_C].c : 0); - } - break; + case TEVCMP_BGR24_GT: + { + u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a; + u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b; + Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a > b) ? inputs[ALP_C].c : 0); + } + break; - case TEVCMP_BGR24_EQ: - { - u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a; - u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b; - Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a == b) ? inputs[ALP_C].c : 0); - } - break; + case TEVCMP_BGR24_EQ: + { + u32 a = (inputs[BLU_C].a << 16) | (inputs[GRN_C].a << 8) | inputs[RED_C].a; + u32 b = (inputs[BLU_C].b << 16) | (inputs[GRN_C].b << 8) | inputs[RED_C].b; + Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((a == b) ? inputs[ALP_C].c : 0); + } + break; - case TEVCMP_A8_GT: - Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((inputs[ALP_C].a > inputs[ALP_C].b) ? inputs[ALP_C].c : 0); - break; + case TEVCMP_A8_GT: + Reg[ac.dest][ALP_C] = + inputs[ALP_C].d + ((inputs[ALP_C].a > inputs[ALP_C].b) ? inputs[ALP_C].c : 0); + break; - case TEVCMP_A8_EQ: - Reg[ac.dest][ALP_C] = inputs[ALP_C].d + ((inputs[ALP_C].a == inputs[ALP_C].b) ? inputs[ALP_C].c : 0); - break; - } + case TEVCMP_A8_EQ: + Reg[ac.dest][ALP_C] = + inputs[ALP_C].d + ((inputs[ALP_C].a == inputs[ALP_C].b) ? inputs[ALP_C].c : 0); + break; + } } static bool AlphaCompare(int alpha, int ref, AlphaTest::CompareMode comp) { - switch (comp) - { - case AlphaTest::ALWAYS: return true; - case AlphaTest::NEVER: return false; - case AlphaTest::LEQUAL: return alpha <= ref; - case AlphaTest::LESS: return alpha < ref; - case AlphaTest::GEQUAL: return alpha >= ref; - case AlphaTest::GREATER: return alpha > ref; - case AlphaTest::EQUAL: return alpha == ref; - case AlphaTest::NEQUAL: return alpha != ref; - default: return true; - } + switch (comp) + { + case AlphaTest::ALWAYS: + return true; + case AlphaTest::NEVER: + return false; + case AlphaTest::LEQUAL: + return alpha <= ref; + case AlphaTest::LESS: + return alpha < ref; + case AlphaTest::GEQUAL: + return alpha >= ref; + case AlphaTest::GREATER: + return alpha > ref; + case AlphaTest::EQUAL: + return alpha == ref; + case AlphaTest::NEQUAL: + return alpha != ref; + default: + return true; + } } static bool TevAlphaTest(int alpha) { - bool comp0 = AlphaCompare(alpha, bpmem.alpha_test.ref0, bpmem.alpha_test.comp0); - bool comp1 = AlphaCompare(alpha, bpmem.alpha_test.ref1, bpmem.alpha_test.comp1); + bool comp0 = AlphaCompare(alpha, bpmem.alpha_test.ref0, bpmem.alpha_test.comp0); + bool comp1 = AlphaCompare(alpha, bpmem.alpha_test.ref1, bpmem.alpha_test.comp1); - switch (bpmem.alpha_test.logic) - { - case 0: return comp0 && comp1; // and - case 1: return comp0 || comp1; // or - case 2: return comp0 ^ comp1; // xor - case 3: return !(comp0 ^ comp1); // xnor - default: return true; - } + switch (bpmem.alpha_test.logic) + { + case 0: + return comp0 && comp1; // and + case 1: + return comp0 || comp1; // or + case 2: + return comp0 ^ comp1; // xor + case 3: + return !(comp0 ^ comp1); // xnor + default: + return true; + } } static inline s32 WrapIndirectCoord(s32 coord, int wrapMode) { - switch (wrapMode) - { - case ITW_OFF: - return coord; - case ITW_256: - return (coord & ((256 << 7) - 1)); - case ITW_128: - return (coord & ((128 << 7) - 1)); - case ITW_64: - return (coord & ((64 << 7) - 1)); - case ITW_32: - return (coord & ((32 << 7) - 1)); - case ITW_16: - return (coord & ((16 << 7) - 1)); - case ITW_0: - return 0; - default: - return 0; - } + switch (wrapMode) + { + case ITW_OFF: + return coord; + case ITW_256: + return (coord & ((256 << 7) - 1)); + case ITW_128: + return (coord & ((128 << 7) - 1)); + case ITW_64: + return (coord & ((64 << 7) - 1)); + case ITW_32: + return (coord & ((32 << 7) - 1)); + case ITW_16: + return (coord & ((16 << 7) - 1)); + case ITW_0: + return 0; + default: + return 0; + } } void Tev::Indirect(unsigned int stageNum, s32 s, s32 t) { - TevStageIndirect &indirect = bpmem.tevind[stageNum]; - u8 *indmap = IndirectTex[indirect.bt]; + TevStageIndirect& indirect = bpmem.tevind[stageNum]; + u8* indmap = IndirectTex[indirect.bt]; - s32 indcoord[3]; + s32 indcoord[3]; - // alpha bump select - switch (indirect.bs) - { - case ITBA_OFF: - AlphaBump = 0; - break; - case ITBA_S: - AlphaBump = indmap[TextureSampler::ALP_SMP]; - break; - case ITBA_T: - AlphaBump = indmap[TextureSampler::BLU_SMP]; - break; - case ITBA_U: - AlphaBump = indmap[TextureSampler::GRN_SMP]; - break; - } + // alpha bump select + switch (indirect.bs) + { + case ITBA_OFF: + AlphaBump = 0; + break; + case ITBA_S: + AlphaBump = indmap[TextureSampler::ALP_SMP]; + break; + case ITBA_T: + AlphaBump = indmap[TextureSampler::BLU_SMP]; + break; + case ITBA_U: + AlphaBump = indmap[TextureSampler::GRN_SMP]; + break; + } - // bias select - s16 biasValue = indirect.fmt==ITF_8?-128:1; - s16 bias[3]; - bias[0] = indirect.bias&1?biasValue:0; - bias[1] = indirect.bias&2?biasValue:0; - bias[2] = indirect.bias&4?biasValue:0; + // bias select + s16 biasValue = indirect.fmt == ITF_8 ? -128 : 1; + s16 bias[3]; + bias[0] = indirect.bias & 1 ? biasValue : 0; + bias[1] = indirect.bias & 2 ? biasValue : 0; + bias[2] = indirect.bias & 4 ? biasValue : 0; - // format - switch (indirect.fmt) - { - case ITF_8: - indcoord[0] = indmap[TextureSampler::ALP_SMP] + bias[0]; - indcoord[1] = indmap[TextureSampler::BLU_SMP] + bias[1]; - indcoord[2] = indmap[TextureSampler::GRN_SMP] + bias[2]; - AlphaBump = AlphaBump & 0xf8; - break; - case ITF_5: - indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x1f) + bias[0]; - indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x1f) + bias[1]; - indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x1f) + bias[2]; - AlphaBump = AlphaBump & 0xe0; - break; - case ITF_4: - indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x0f) + bias[0]; - indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x0f) + bias[1]; - indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x0f) + bias[2]; - AlphaBump = AlphaBump & 0xf0; - break; - case ITF_3: - indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x07) + bias[0]; - indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x07) + bias[1]; - indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x07) + bias[2]; - AlphaBump = AlphaBump & 0xf8; - break; - default: - PanicAlert("Tev::Indirect"); - return; - } + // format + switch (indirect.fmt) + { + case ITF_8: + indcoord[0] = indmap[TextureSampler::ALP_SMP] + bias[0]; + indcoord[1] = indmap[TextureSampler::BLU_SMP] + bias[1]; + indcoord[2] = indmap[TextureSampler::GRN_SMP] + bias[2]; + AlphaBump = AlphaBump & 0xf8; + break; + case ITF_5: + indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x1f) + bias[0]; + indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x1f) + bias[1]; + indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x1f) + bias[2]; + AlphaBump = AlphaBump & 0xe0; + break; + case ITF_4: + indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x0f) + bias[0]; + indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x0f) + bias[1]; + indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x0f) + bias[2]; + AlphaBump = AlphaBump & 0xf0; + break; + case ITF_3: + indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x07) + bias[0]; + indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x07) + bias[1]; + indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x07) + bias[2]; + AlphaBump = AlphaBump & 0xf8; + break; + default: + PanicAlert("Tev::Indirect"); + return; + } - s32 indtevtrans[2] = { 0,0 }; + s32 indtevtrans[2] = {0, 0}; - // matrix multiply - results might overflow, but we don't care since we only use the lower 24 bits of the result. - int indmtxid = indirect.mid & 3; - if (indmtxid) - { - IND_MTX &indmtx = bpmem.indmtx[indmtxid - 1]; - int scale = ((u32)indmtx.col0.s0 << 0) | - ((u32)indmtx.col1.s1 << 2) | - ((u32)indmtx.col2.s2 << 4); + // matrix multiply - results might overflow, but we don't care since we only use the lower 24 bits + // of the result. + int indmtxid = indirect.mid & 3; + if (indmtxid) + { + IND_MTX& indmtx = bpmem.indmtx[indmtxid - 1]; + int scale = + ((u32)indmtx.col0.s0 << 0) | ((u32)indmtx.col1.s1 << 2) | ((u32)indmtx.col2.s2 << 4); - int shift; + int shift; - switch (indirect.mid & 12) - { - case 0: - // matrix values are S0.10, output format is S17.7, so divide by 8 - shift = (17 - scale); - indtevtrans[0] = (indmtx.col0.ma * indcoord[0] + indmtx.col1.mc * indcoord[1] + indmtx.col2.me * indcoord[2]) >> 3; - indtevtrans[1] = (indmtx.col0.mb * indcoord[0] + indmtx.col1.md * indcoord[1] + indmtx.col2.mf * indcoord[2]) >> 3; - break; - case 4: // s matrix - // s is S17.7, matrix elements are divided by 256, output is S17.7, so divide by 256. - TODO: Maybe, since s is actually stored as S24, we should divide by 256*64? - shift = (17 - scale); - indtevtrans[0] = s * indcoord[0] / 256; - indtevtrans[1] = t * indcoord[0] / 256; - break; - case 8: // t matrix - shift = (17 - scale); - indtevtrans[0] = s * indcoord[1] / 256; - indtevtrans[1] = t * indcoord[1] / 256; - break; - default: - return; - } + switch (indirect.mid & 12) + { + case 0: + // matrix values are S0.10, output format is S17.7, so divide by 8 + shift = (17 - scale); + indtevtrans[0] = (indmtx.col0.ma * indcoord[0] + indmtx.col1.mc * indcoord[1] + + indmtx.col2.me * indcoord[2]) >> + 3; + indtevtrans[1] = (indmtx.col0.mb * indcoord[0] + indmtx.col1.md * indcoord[1] + + indmtx.col2.mf * indcoord[2]) >> + 3; + break; + case 4: // s matrix + // s is S17.7, matrix elements are divided by 256, output is S17.7, so divide by 256. - TODO: + // Maybe, since s is actually stored as S24, we should divide by 256*64? + shift = (17 - scale); + indtevtrans[0] = s * indcoord[0] / 256; + indtevtrans[1] = t * indcoord[0] / 256; + break; + case 8: // t matrix + shift = (17 - scale); + indtevtrans[0] = s * indcoord[1] / 256; + indtevtrans[1] = t * indcoord[1] / 256; + break; + default: + return; + } - indtevtrans[0] = shift >= 0 ? indtevtrans[0] >> shift : indtevtrans[0] << -shift; - indtevtrans[1] = shift >= 0 ? indtevtrans[1] >> shift : indtevtrans[1] << -shift; - } + indtevtrans[0] = shift >= 0 ? indtevtrans[0] >> shift : indtevtrans[0] << -shift; + indtevtrans[1] = shift >= 0 ? indtevtrans[1] >> shift : indtevtrans[1] << -shift; + } - if (indirect.fb_addprev) - { - TexCoord.s += (int)(WrapIndirectCoord(s, indirect.sw) + indtevtrans[0]); - TexCoord.t += (int)(WrapIndirectCoord(t, indirect.tw) + indtevtrans[1]); - } - else - { - TexCoord.s = (int)(WrapIndirectCoord(s, indirect.sw) + indtevtrans[0]); - TexCoord.t = (int)(WrapIndirectCoord(t, indirect.tw) + indtevtrans[1]); - } + if (indirect.fb_addprev) + { + TexCoord.s += (int)(WrapIndirectCoord(s, indirect.sw) + indtevtrans[0]); + TexCoord.t += (int)(WrapIndirectCoord(t, indirect.tw) + indtevtrans[1]); + } + else + { + TexCoord.s = (int)(WrapIndirectCoord(s, indirect.sw) + indtevtrans[0]); + TexCoord.t = (int)(WrapIndirectCoord(t, indirect.tw) + indtevtrans[1]); + } } void Tev::Draw() { - _assert_(Position[0] >= 0 && Position[0] < EFB_WIDTH); - _assert_(Position[1] >= 0 && Position[1] < EFB_HEIGHT); + _assert_(Position[0] >= 0 && Position[0] < EFB_WIDTH); + _assert_(Position[1] >= 0 && Position[1] < EFB_HEIGHT); - INCSTAT(stats.thisFrame.tevPixelsIn); + INCSTAT(stats.thisFrame.tevPixelsIn); - // initial color values - for (int i = 0; i < 4; i++) - { - Reg[i][RED_C] = PixelShaderManager::constants.colors[i][0]; - Reg[i][GRN_C] = PixelShaderManager::constants.colors[i][1]; - Reg[i][BLU_C] = PixelShaderManager::constants.colors[i][2]; - Reg[i][ALP_C] = PixelShaderManager::constants.colors[i][3]; - } + // initial color values + for (int i = 0; i < 4; i++) + { + Reg[i][RED_C] = PixelShaderManager::constants.colors[i][0]; + Reg[i][GRN_C] = PixelShaderManager::constants.colors[i][1]; + Reg[i][BLU_C] = PixelShaderManager::constants.colors[i][2]; + Reg[i][ALP_C] = PixelShaderManager::constants.colors[i][3]; + } - for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++) - { - int stageNum2 = stageNum >> 1; - int stageOdd = stageNum&1; + for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++) + { + int stageNum2 = stageNum >> 1; + int stageOdd = stageNum & 1; - u32 texcoordSel = bpmem.tevindref.getTexCoord(stageNum); - u32 texmap = bpmem.tevindref.getTexMap(stageNum); + u32 texcoordSel = bpmem.tevindref.getTexCoord(stageNum); + u32 texmap = bpmem.tevindref.getTexMap(stageNum); - const TEXSCALE& texscale = bpmem.texscale[stageNum2]; - s32 scaleS = stageOdd ? texscale.ss1:texscale.ss0; - s32 scaleT = stageOdd ? texscale.ts1:texscale.ts0; + const TEXSCALE& texscale = bpmem.texscale[stageNum2]; + s32 scaleS = stageOdd ? texscale.ss1 : texscale.ss0; + s32 scaleT = stageOdd ? texscale.ts1 : texscale.ts0; - TextureSampler::Sample(Uv[texcoordSel].s >> scaleS, Uv[texcoordSel].t >> scaleT, - IndirectLod[stageNum], IndirectLinear[stageNum], texmap, IndirectTex[stageNum]); + TextureSampler::Sample(Uv[texcoordSel].s >> scaleS, Uv[texcoordSel].t >> scaleT, + IndirectLod[stageNum], IndirectLinear[stageNum], texmap, + IndirectTex[stageNum]); #if ALLOW_TEV_DUMPS - if (g_ActiveConfig.bDumpTevStages) - { - u8 stage[4] = { - IndirectTex[stageNum][TextureSampler::ALP_SMP], - IndirectTex[stageNum][TextureSampler::BLU_SMP], - IndirectTex[stageNum][TextureSampler::GRN_SMP], - 255 - }; - DebugUtil::DrawTempBuffer(stage, INDIRECT + stageNum); - } + if (g_ActiveConfig.bDumpTevStages) + { + u8 stage[4] = {IndirectTex[stageNum][TextureSampler::ALP_SMP], + IndirectTex[stageNum][TextureSampler::BLU_SMP], + IndirectTex[stageNum][TextureSampler::GRN_SMP], 255}; + DebugUtil::DrawTempBuffer(stage, INDIRECT + stageNum); + } #endif - } + } - for (unsigned int stageNum = 0; stageNum <= bpmem.genMode.numtevstages; stageNum++) - { - int stageNum2 = stageNum >> 1; - int stageOdd = stageNum&1; - TwoTevStageOrders &order = bpmem.tevorders[stageNum2]; - TevKSel &kSel = bpmem.tevksel[stageNum2]; + for (unsigned int stageNum = 0; stageNum <= bpmem.genMode.numtevstages; stageNum++) + { + int stageNum2 = stageNum >> 1; + int stageOdd = stageNum & 1; + TwoTevStageOrders& order = bpmem.tevorders[stageNum2]; + TevKSel& kSel = bpmem.tevksel[stageNum2]; - // stage combiners - TevStageCombiner::ColorCombiner &cc = bpmem.combiners[stageNum].colorC; - TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[stageNum].alphaC; + // stage combiners + TevStageCombiner::ColorCombiner& cc = bpmem.combiners[stageNum].colorC; + TevStageCombiner::AlphaCombiner& ac = bpmem.combiners[stageNum].alphaC; - int texcoordSel = order.getTexCoord(stageOdd); - int texmap = order.getTexMap(stageOdd); + int texcoordSel = order.getTexCoord(stageOdd); + int texmap = order.getTexMap(stageOdd); - Indirect(stageNum, Uv[texcoordSel].s, Uv[texcoordSel].t); + Indirect(stageNum, Uv[texcoordSel].s, Uv[texcoordSel].t); - // sample texture - if (order.getEnable(stageOdd)) - { - // RGBA - u8 texel[4]; + // sample texture + if (order.getEnable(stageOdd)) + { + // RGBA + u8 texel[4]; - TextureSampler::Sample(TexCoord.s, TexCoord.t, TextureLod[stageNum], TextureLinear[stageNum], texmap, texel); + TextureSampler::Sample(TexCoord.s, TexCoord.t, TextureLod[stageNum], TextureLinear[stageNum], + texmap, texel); #if ALLOW_TEV_DUMPS - if (g_ActiveConfig.bDumpTevTextureFetches) - DebugUtil::DrawTempBuffer(texel, DIRECT_TFETCH + stageNum); + if (g_ActiveConfig.bDumpTevTextureFetches) + DebugUtil::DrawTempBuffer(texel, DIRECT_TFETCH + stageNum); #endif - int swaptable = ac.tswap * 2; + int swaptable = ac.tswap * 2; - TexColor[RED_C] = texel[bpmem.tevksel[swaptable].swap1]; - TexColor[GRN_C] = texel[bpmem.tevksel[swaptable].swap2]; - swaptable++; - TexColor[BLU_C] = texel[bpmem.tevksel[swaptable].swap1]; - TexColor[ALP_C] = texel[bpmem.tevksel[swaptable].swap2]; - } + TexColor[RED_C] = texel[bpmem.tevksel[swaptable].swap1]; + TexColor[GRN_C] = texel[bpmem.tevksel[swaptable].swap2]; + swaptable++; + TexColor[BLU_C] = texel[bpmem.tevksel[swaptable].swap1]; + TexColor[ALP_C] = texel[bpmem.tevksel[swaptable].swap2]; + } - // set konst for this stage - int kc = kSel.getKC(stageOdd); - int ka = kSel.getKA(stageOdd); - StageKonst[RED_C] = *(m_KonstLUT[kc][RED_C]); - StageKonst[GRN_C] = *(m_KonstLUT[kc][GRN_C]); - StageKonst[BLU_C] = *(m_KonstLUT[kc][BLU_C]); - StageKonst[ALP_C] = *(m_KonstLUT[ka][ALP_C]); + // set konst for this stage + int kc = kSel.getKC(stageOdd); + int ka = kSel.getKA(stageOdd); + StageKonst[RED_C] = *(m_KonstLUT[kc][RED_C]); + StageKonst[GRN_C] = *(m_KonstLUT[kc][GRN_C]); + StageKonst[BLU_C] = *(m_KonstLUT[kc][BLU_C]); + StageKonst[ALP_C] = *(m_KonstLUT[ka][ALP_C]); - // set color - SetRasColor(order.getColorChan(stageOdd), ac.rswap * 2); + // set color + SetRasColor(order.getColorChan(stageOdd), ac.rswap * 2); - // combine inputs - InputRegType inputs[4]; - for (int i = 0; i < 3; i++) - { - inputs[BLU_C + i].a = *m_ColorInputLUT[cc.a][i]; - inputs[BLU_C + i].b = *m_ColorInputLUT[cc.b][i]; - inputs[BLU_C + i].c = *m_ColorInputLUT[cc.c][i]; - inputs[BLU_C + i].d = *m_ColorInputLUT[cc.d][i]; - } - inputs[ALP_C].a = *m_AlphaInputLUT[ac.a]; - inputs[ALP_C].b = *m_AlphaInputLUT[ac.b]; - inputs[ALP_C].c = *m_AlphaInputLUT[ac.c]; - inputs[ALP_C].d = *m_AlphaInputLUT[ac.d]; + // combine inputs + InputRegType inputs[4]; + for (int i = 0; i < 3; i++) + { + inputs[BLU_C + i].a = *m_ColorInputLUT[cc.a][i]; + inputs[BLU_C + i].b = *m_ColorInputLUT[cc.b][i]; + inputs[BLU_C + i].c = *m_ColorInputLUT[cc.c][i]; + inputs[BLU_C + i].d = *m_ColorInputLUT[cc.d][i]; + } + inputs[ALP_C].a = *m_AlphaInputLUT[ac.a]; + inputs[ALP_C].b = *m_AlphaInputLUT[ac.b]; + inputs[ALP_C].c = *m_AlphaInputLUT[ac.c]; + inputs[ALP_C].d = *m_AlphaInputLUT[ac.d]; - if (cc.bias != 3) - DrawColorRegular(cc, inputs); - else - DrawColorCompare(cc, inputs); + if (cc.bias != 3) + DrawColorRegular(cc, inputs); + else + DrawColorCompare(cc, inputs); - if (cc.clamp) - { - Reg[cc.dest][RED_C] = Clamp255(Reg[cc.dest][RED_C]); - Reg[cc.dest][GRN_C] = Clamp255(Reg[cc.dest][GRN_C]); - Reg[cc.dest][BLU_C] = Clamp255(Reg[cc.dest][BLU_C]); - } - else - { - Reg[cc.dest][RED_C] = Clamp1024(Reg[cc.dest][RED_C]); - Reg[cc.dest][GRN_C] = Clamp1024(Reg[cc.dest][GRN_C]); - Reg[cc.dest][BLU_C] = Clamp1024(Reg[cc.dest][BLU_C]); - } + if (cc.clamp) + { + Reg[cc.dest][RED_C] = Clamp255(Reg[cc.dest][RED_C]); + Reg[cc.dest][GRN_C] = Clamp255(Reg[cc.dest][GRN_C]); + Reg[cc.dest][BLU_C] = Clamp255(Reg[cc.dest][BLU_C]); + } + else + { + Reg[cc.dest][RED_C] = Clamp1024(Reg[cc.dest][RED_C]); + Reg[cc.dest][GRN_C] = Clamp1024(Reg[cc.dest][GRN_C]); + Reg[cc.dest][BLU_C] = Clamp1024(Reg[cc.dest][BLU_C]); + } - if (ac.bias != 3) - DrawAlphaRegular(ac, inputs); - else - DrawAlphaCompare(ac, inputs); + if (ac.bias != 3) + DrawAlphaRegular(ac, inputs); + else + DrawAlphaCompare(ac, inputs); - if (ac.clamp) - Reg[ac.dest][ALP_C] = Clamp255(Reg[ac.dest][ALP_C]); - else - Reg[ac.dest][ALP_C] = Clamp1024(Reg[ac.dest][ALP_C]); + if (ac.clamp) + Reg[ac.dest][ALP_C] = Clamp255(Reg[ac.dest][ALP_C]); + else + Reg[ac.dest][ALP_C] = Clamp1024(Reg[ac.dest][ALP_C]); #if ALLOW_TEV_DUMPS - if (g_ActiveConfig.bDumpTevStages) - { - u8 stage[4] = {(u8)Reg[0][RED_C], (u8)Reg[0][GRN_C], (u8)Reg[0][BLU_C], (u8)Reg[0][ALP_C]}; - DebugUtil::DrawTempBuffer(stage, DIRECT + stageNum); - } + if (g_ActiveConfig.bDumpTevStages) + { + u8 stage[4] = {(u8)Reg[0][RED_C], (u8)Reg[0][GRN_C], (u8)Reg[0][BLU_C], (u8)Reg[0][ALP_C]}; + DebugUtil::DrawTempBuffer(stage, DIRECT + stageNum); + } #endif - } + } - // convert to 8 bits per component - // the results of the last tev stage are put onto the screen, - // regardless of the used destination register - TODO: Verify! - u32 color_index = bpmem.combiners[bpmem.genMode.numtevstages].colorC.dest; - u32 alpha_index = bpmem.combiners[bpmem.genMode.numtevstages].alphaC.dest; - u8 output[4] = {(u8)Reg[alpha_index][ALP_C], (u8)Reg[color_index][BLU_C], (u8)Reg[color_index][GRN_C], (u8)Reg[color_index][RED_C]}; + // convert to 8 bits per component + // the results of the last tev stage are put onto the screen, + // regardless of the used destination register - TODO: Verify! + u32 color_index = bpmem.combiners[bpmem.genMode.numtevstages].colorC.dest; + u32 alpha_index = bpmem.combiners[bpmem.genMode.numtevstages].alphaC.dest; + u8 output[4] = {(u8)Reg[alpha_index][ALP_C], (u8)Reg[color_index][BLU_C], + (u8)Reg[color_index][GRN_C], (u8)Reg[color_index][RED_C]}; - if (!TevAlphaTest(output[ALP_C])) - return; + if (!TevAlphaTest(output[ALP_C])) + return; - // z texture - if (bpmem.ztex2.op) - { - u32 ztex = bpmem.ztex1.bias; - switch (bpmem.ztex2.type) - { - case 0: // 8 bit - ztex += TexColor[ALP_C]; - break; - case 1: // 16 bit - ztex += TexColor[ALP_C] << 8 | TexColor[RED_C]; - break; - case 2: // 24 bit - ztex += TexColor[RED_C] << 16 | TexColor[GRN_C] << 8 | TexColor[BLU_C]; - break; - } + // z texture + if (bpmem.ztex2.op) + { + u32 ztex = bpmem.ztex1.bias; + switch (bpmem.ztex2.type) + { + case 0: // 8 bit + ztex += TexColor[ALP_C]; + break; + case 1: // 16 bit + ztex += TexColor[ALP_C] << 8 | TexColor[RED_C]; + break; + case 2: // 24 bit + ztex += TexColor[RED_C] << 16 | TexColor[GRN_C] << 8 | TexColor[BLU_C]; + break; + } - if (bpmem.ztex2.op == ZTEXTURE_ADD) - ztex += Position[2]; + if (bpmem.ztex2.op == ZTEXTURE_ADD) + ztex += Position[2]; - Position[2] = ztex & 0x00ffffff; - } + Position[2] = ztex & 0x00ffffff; + } - // fog - if (bpmem.fog.c_proj_fsel.fsel) - { - float ze; + // fog + if (bpmem.fog.c_proj_fsel.fsel) + { + float ze; - if (bpmem.fog.c_proj_fsel.proj == 0) - { - // perspective - // ze = A/(B - (Zs >> B_SHF)) - s32 denom = bpmem.fog.b_magnitude - (Position[2] >> bpmem.fog.b_shift); - //in addition downscale magnitude and zs to 0.24 bits - ze = (bpmem.fog.a.GetA() * 16777215.0f) / (float)denom; - } - else - { - // orthographic - // ze = a*Zs - //in addition downscale zs to 0.24 bits - ze = bpmem.fog.a.GetA() * ((float)Position[2] / 16777215.0f); + if (bpmem.fog.c_proj_fsel.proj == 0) + { + // perspective + // ze = A/(B - (Zs >> B_SHF)) + s32 denom = bpmem.fog.b_magnitude - (Position[2] >> bpmem.fog.b_shift); + // in addition downscale magnitude and zs to 0.24 bits + ze = (bpmem.fog.a.GetA() * 16777215.0f) / (float)denom; + } + else + { + // orthographic + // ze = a*Zs + // in addition downscale zs to 0.24 bits + ze = bpmem.fog.a.GetA() * ((float)Position[2] / 16777215.0f); + } - } + if (bpmem.fogRange.Base.Enabled) + { + // TODO: This is untested and should definitely be checked against real hw. + // - No idea if offset is really normalized against the viewport width or against the + // projection matrix or yet something else + // - scaling of the "k" coefficient isn't clear either. - if (bpmem.fogRange.Base.Enabled) - { - // TODO: This is untested and should definitely be checked against real hw. - // - No idea if offset is really normalized against the viewport width or against the projection matrix or yet something else - // - scaling of the "k" coefficient isn't clear either. + // First, calculate the offset from the viewport center (normalized to 0..1) + float offset = (Position[0] - (bpmem.fogRange.Base.Center - 342)) / (float)xfmem.viewport.wd; - // First, calculate the offset from the viewport center (normalized to 0..1) - float offset = (Position[0] - (bpmem.fogRange.Base.Center - 342)) / (float)xfmem.viewport.wd; + // Based on that, choose the index such that points which are far away from the z-axis use the + // 10th "k" value and such that central points use the first value. + float floatindex = 9.f - std::abs(offset) * 9.f; + floatindex = (floatindex < 0.f) ? 0.f : (floatindex > 9.f) ? + 9.f : + floatindex; // TODO: This shouldn't be necessary! - // Based on that, choose the index such that points which are far away from the z-axis use the 10th "k" value and such that central points use the first value. - float floatindex = 9.f - std::abs(offset) * 9.f; - floatindex = (floatindex < 0.f) ? 0.f : (floatindex > 9.f) ? 9.f : floatindex; // TODO: This shouldn't be necessary! + // Get the two closest integer indices, look up the corresponding samples + int indexlower = (int)floor(floatindex); + int indexupper = indexlower + 1; + // Look up coefficient... Seems like multiplying by 4 makes Fortune Street work properly (fog + // is too strong without the factor) + float klower = bpmem.fogRange.K[indexlower / 2].GetValue(indexlower % 2) * 4.f; + float kupper = bpmem.fogRange.K[indexupper / 2].GetValue(indexupper % 2) * 4.f; - // Get the two closest integer indices, look up the corresponding samples - int indexlower = (int)floor(floatindex); - int indexupper = indexlower + 1; - // Look up coefficient... Seems like multiplying by 4 makes Fortune Street work properly (fog is too strong without the factor) - float klower = bpmem.fogRange.K[indexlower/2].GetValue(indexlower%2) * 4.f; - float kupper = bpmem.fogRange.K[indexupper/2].GetValue(indexupper%2) * 4.f; + // linearly interpolate the samples and multiple ze by the resulting adjustment factor + float factor = indexupper - floatindex; + float k = klower * factor + kupper * (1.f - factor); + float x_adjust = sqrt(offset * offset + k * k) / k; + ze *= x_adjust; // NOTE: This is basically dividing by a cosine (hidden behind + // GXInitFogAdjTable): 1/cos = c/b = sqrt(a^2+b^2)/b + } - // linearly interpolate the samples and multiple ze by the resulting adjustment factor - float factor = indexupper - floatindex; - float k = klower * factor + kupper * (1.f - factor); - float x_adjust = sqrt(offset*offset + k*k)/k; - ze *= x_adjust; // NOTE: This is basically dividing by a cosine (hidden behind GXInitFogAdjTable): 1/cos = c/b = sqrt(a^2+b^2)/b - } + ze -= bpmem.fog.c_proj_fsel.GetC(); - ze -= bpmem.fog.c_proj_fsel.GetC(); + // clamp 0 to 1 + float fog = (ze < 0.0f) ? 0.0f : ((ze > 1.0f) ? 1.0f : ze); - // clamp 0 to 1 - float fog = (ze<0.0f) ? 0.0f : ((ze>1.0f) ? 1.0f : ze); + switch (bpmem.fog.c_proj_fsel.fsel) + { + case 4: // exp + fog = 1.0f - pow(2.0f, -8.0f * fog); + break; + case 5: // exp2 + fog = 1.0f - pow(2.0f, -8.0f * fog * fog); + break; + case 6: // backward exp + fog = 1.0f - fog; + fog = pow(2.0f, -8.0f * fog); + break; + case 7: // backward exp2 + fog = 1.0f - fog; + fog = pow(2.0f, -8.0f * fog * fog); + break; + } - switch (bpmem.fog.c_proj_fsel.fsel) - { - case 4: // exp - fog = 1.0f - pow(2.0f, -8.0f * fog); - break; - case 5: // exp2 - fog = 1.0f - pow(2.0f, -8.0f * fog * fog); - break; - case 6: // backward exp - fog = 1.0f - fog; - fog = pow(2.0f, -8.0f * fog); - break; - case 7: // backward exp2 - fog = 1.0f - fog; - fog = pow(2.0f, -8.0f * fog * fog); - break; - } + // lerp from output to fog color + u32 fogInt = (u32)(fog * 256); + u32 invFog = 256 - fogInt; - // lerp from output to fog color - u32 fogInt = (u32)(fog * 256); - u32 invFog = 256 - fogInt; + output[RED_C] = (output[RED_C] * invFog + fogInt * bpmem.fog.color.r) >> 8; + output[GRN_C] = (output[GRN_C] * invFog + fogInt * bpmem.fog.color.g) >> 8; + output[BLU_C] = (output[BLU_C] * invFog + fogInt * bpmem.fog.color.b) >> 8; + } - output[RED_C] = (output[RED_C] * invFog + fogInt * bpmem.fog.color.r) >> 8; - output[GRN_C] = (output[GRN_C] * invFog + fogInt * bpmem.fog.color.g) >> 8; - output[BLU_C] = (output[BLU_C] * invFog + fogInt * bpmem.fog.color.b) >> 8; - } + bool late_ztest = !bpmem.zcontrol.early_ztest || !g_ActiveConfig.bZComploc; + if (late_ztest && bpmem.zmode.testenable) + { + // TODO: Check against hw if these values get incremented even if depth testing is disabled + EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT); - bool late_ztest = !bpmem.zcontrol.early_ztest || !g_ActiveConfig.bZComploc; - if (late_ztest && bpmem.zmode.testenable) - { - // TODO: Check against hw if these values get incremented even if depth testing is disabled - EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT); + if (!EfbInterface::ZCompare(Position[0], Position[1], Position[2])) + return; - if (!EfbInterface::ZCompare(Position[0], Position[1], Position[2])) - return; + EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_OUTPUT); + } - EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_OUTPUT); - } - - // branchless bounding box update - BoundingBox::coords[BoundingBox::LEFT] = std::min((u16)Position[0], BoundingBox::coords[BoundingBox::LEFT]); - BoundingBox::coords[BoundingBox::RIGHT] = std::max((u16)Position[0], BoundingBox::coords[BoundingBox::RIGHT]); - BoundingBox::coords[BoundingBox::TOP] = std::min((u16)Position[1], BoundingBox::coords[BoundingBox::TOP]); - BoundingBox::coords[BoundingBox::BOTTOM] = std::max((u16)Position[1], BoundingBox::coords[BoundingBox::BOTTOM]); + // branchless bounding box update + BoundingBox::coords[BoundingBox::LEFT] = + std::min((u16)Position[0], BoundingBox::coords[BoundingBox::LEFT]); + BoundingBox::coords[BoundingBox::RIGHT] = + std::max((u16)Position[0], BoundingBox::coords[BoundingBox::RIGHT]); + BoundingBox::coords[BoundingBox::TOP] = + std::min((u16)Position[1], BoundingBox::coords[BoundingBox::TOP]); + BoundingBox::coords[BoundingBox::BOTTOM] = + std::max((u16)Position[1], BoundingBox::coords[BoundingBox::BOTTOM]); #if ALLOW_TEV_DUMPS - if (g_ActiveConfig.bDumpTevStages) - { - for (u32 i = 0; i < bpmem.genMode.numindstages; ++i) - DebugUtil::CopyTempBuffer(Position[0], Position[1], INDIRECT, i, "Indirect"); - for (u32 i = 0; i <= bpmem.genMode.numtevstages; ++i) - DebugUtil::CopyTempBuffer(Position[0], Position[1], DIRECT, i, "Stage"); - } + if (g_ActiveConfig.bDumpTevStages) + { + for (u32 i = 0; i < bpmem.genMode.numindstages; ++i) + DebugUtil::CopyTempBuffer(Position[0], Position[1], INDIRECT, i, "Indirect"); + for (u32 i = 0; i <= bpmem.genMode.numtevstages; ++i) + DebugUtil::CopyTempBuffer(Position[0], Position[1], DIRECT, i, "Stage"); + } - if (g_ActiveConfig.bDumpTevTextureFetches) - { - for (u32 i = 0; i <= bpmem.genMode.numtevstages; ++i) - { - TwoTevStageOrders &order = bpmem.tevorders[i >> 1]; - if (order.getEnable(i & 1)) - DebugUtil::CopyTempBuffer(Position[0], Position[1], DIRECT_TFETCH, i, "TFetch"); - } - } + if (g_ActiveConfig.bDumpTevTextureFetches) + { + for (u32 i = 0; i <= bpmem.genMode.numtevstages; ++i) + { + TwoTevStageOrders& order = bpmem.tevorders[i >> 1]; + if (order.getEnable(i & 1)) + DebugUtil::CopyTempBuffer(Position[0], Position[1], DIRECT_TFETCH, i, "TFetch"); + } + } #endif - INCSTAT(stats.thisFrame.tevPixelsOut); - EfbInterface::IncPerfCounterQuadCount(PQ_BLEND_INPUT); + INCSTAT(stats.thisFrame.tevPixelsOut); + EfbInterface::IncPerfCounterQuadCount(PQ_BLEND_INPUT); - EfbInterface::BlendTev(Position[0], Position[1], output); + EfbInterface::BlendTev(Position[0], Position[1], output); } void Tev::SetRegColor(int reg, int comp, s16 color) { - KonstantColors[reg][comp] = color; + KonstantColors[reg][comp] = color; } - diff --git a/Source/Core/VideoBackends/Software/Tev.h b/Source/Core/VideoBackends/Software/Tev.h index 84b94886a7..3c2bdb176a 100644 --- a/Source/Core/VideoBackends/Software/Tev.h +++ b/Source/Core/VideoBackends/Software/Tev.h @@ -8,84 +8,84 @@ class Tev { - struct InputRegType - { - unsigned a : 8; - unsigned b : 8; - unsigned c : 8; - signed d : 11; - }; + struct InputRegType + { + unsigned a : 8; + unsigned b : 8; + unsigned c : 8; + signed d : 11; + }; - struct TextureCoordinateType - { - signed s : 24; - signed t : 24; - }; + struct TextureCoordinateType + { + signed s : 24; + signed t : 24; + }; - // color order: ABGR - s16 Reg[4][4]; - s16 KonstantColors[4][4]; - s16 TexColor[4]; - s16 RasColor[4]; - s16 StageKonst[4]; - s16 Zero16[4]; + // color order: ABGR + s16 Reg[4][4]; + s16 KonstantColors[4][4]; + s16 TexColor[4]; + s16 RasColor[4]; + s16 StageKonst[4]; + s16 Zero16[4]; - s16 FixedConstants[9]; - u8 AlphaBump; - u8 IndirectTex[4][4]; - TextureCoordinateType TexCoord; + s16 FixedConstants[9]; + u8 AlphaBump; + u8 IndirectTex[4][4]; + TextureCoordinateType TexCoord; - s16 *m_ColorInputLUT[16][3]; - s16 *m_AlphaInputLUT[8]; // values must point to ABGR color - s16 *m_KonstLUT[32][4]; - s16 m_BiasLUT[4]; - u8 m_ScaleLShiftLUT[4]; - u8 m_ScaleRShiftLUT[4]; + s16* m_ColorInputLUT[16][3]; + s16* m_AlphaInputLUT[8]; // values must point to ABGR color + s16* m_KonstLUT[32][4]; + s16 m_BiasLUT[4]; + u8 m_ScaleLShiftLUT[4]; + u8 m_ScaleRShiftLUT[4]; - // enumeration for color input LUT - enum - { - BLU_INP, - GRN_INP, - RED_INP - }; + // enumeration for color input LUT + enum + { + BLU_INP, + GRN_INP, + RED_INP + }; - enum BufferBase - { - DIRECT = 0, - DIRECT_TFETCH = 16, - INDIRECT = 32 - }; + enum BufferBase + { + DIRECT = 0, + DIRECT_TFETCH = 16, + INDIRECT = 32 + }; - void SetRasColor(int colorChan, int swaptable); + void SetRasColor(int colorChan, int swaptable); - void DrawColorRegular(TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]); - void DrawColorCompare(TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]); - void DrawAlphaRegular(TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4]); - void DrawAlphaCompare(TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4]); + void DrawColorRegular(TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]); + void DrawColorCompare(TevStageCombiner::ColorCombiner& cc, const InputRegType inputs[4]); + void DrawAlphaRegular(TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4]); + void DrawAlphaCompare(TevStageCombiner::AlphaCombiner& ac, const InputRegType inputs[4]); - void Indirect(unsigned int stageNum, s32 s, s32 t); + void Indirect(unsigned int stageNum, s32 s, s32 t); public: - s32 Position[3]; - u8 Color[2][4]; // must be RGBA for correct swap table ordering - TextureCoordinateType Uv[8]; - s32 IndirectLod[4]; - bool IndirectLinear[4]; - s32 TextureLod[16]; - bool TextureLinear[16]; + s32 Position[3]; + u8 Color[2][4]; // must be RGBA for correct swap table ordering + TextureCoordinateType Uv[8]; + s32 IndirectLod[4]; + bool IndirectLinear[4]; + s32 TextureLod[16]; + bool TextureLinear[16]; - enum - { - ALP_C, - BLU_C, - GRN_C, - RED_C - }; + enum + { + ALP_C, + BLU_C, + GRN_C, + RED_C + }; - void Init(); + void Init(); - void Draw(); + void Draw(); - void SetRegColor(int reg, int comp, s16 color); + void SetRegColor(int reg, int comp, s16 color); }; diff --git a/Source/Core/VideoBackends/Software/TextureEncoder.cpp b/Source/Core/VideoBackends/Software/TextureEncoder.cpp index 5ac514ca11..c046d9e5a5 100644 --- a/Source/Core/VideoBackends/Software/TextureEncoder.cpp +++ b/Source/Core/VideoBackends/Software/TextureEncoder.cpp @@ -13,32 +13,30 @@ #include "VideoCommon/LookUpTables.h" #include "VideoCommon/TextureDecoder.h" - namespace TextureEncoder { - -static inline void RGBA_to_RGBA8(const u8 *src, u8* r, u8* g, u8* b, u8* a) +static inline void RGBA_to_RGBA8(const u8* src, u8* r, u8* g, u8* b, u8* a) { - u32 srcColor = *(u32*)src; - *a = Convert6To8(srcColor & 0x3f); - *b = Convert6To8((srcColor >> 6) & 0x3f); - *g = Convert6To8((srcColor >> 12)& 0x3f); - *r = Convert6To8((srcColor >> 18)& 0x3f); + u32 srcColor = *(u32*)src; + *a = Convert6To8(srcColor & 0x3f); + *b = Convert6To8((srcColor >> 6) & 0x3f); + *g = Convert6To8((srcColor >> 12) & 0x3f); + *r = Convert6To8((srcColor >> 18) & 0x3f); } -static inline void RGBA_to_RGB8(const u8 *src, u8* r, u8* g, u8* b) +static inline void RGBA_to_RGB8(const u8* src, u8* r, u8* g, u8* b) { - u32 srcColor = *(u32*)src; - *b = Convert6To8((srcColor >> 6) & 0x3f); - *g = Convert6To8((srcColor >> 12)& 0x3f); - *r = Convert6To8((srcColor >> 18)& 0x3f); + u32 srcColor = *(u32*)src; + *b = Convert6To8((srcColor >> 6) & 0x3f); + *g = Convert6To8((srcColor >> 12) & 0x3f); + *r = Convert6To8((srcColor >> 18) & 0x3f); } static inline u8 RGB8_to_I(u8 r, u8 g, u8 b) { - // values multiplied by 256 to keep math integer - u16 val = 4096 + 66 * r + 129 * g + 25 * b; - return val >> 8; + // values multiplied by 256 to keep math integer + u16 val = 4096 + 66 * r + 129 * g + 25 * b; + return val >> 8; } // box filter sampling averages 4 samples with the source texel being the top left of the box @@ -46,1394 +44,1394 @@ static inline u8 RGB8_to_I(u8 r, u8 g, u8 b) static inline void BoxfilterRGBA_to_RGBA8(const u8* src, u8* r, u8* g, u8* b, u8* a) { - u16 r16 = 0, g16 = 0, b16 = 0, a16 = 0; + u16 r16 = 0, g16 = 0, b16 = 0, a16 = 0; - for (int y = 0; y < 2; y++) - { - for (int x = 0; x < 2; x++) - { - u32 srcColor = *(u32*)src; + for (int y = 0; y < 2; y++) + { + for (int x = 0; x < 2; x++) + { + u32 srcColor = *(u32*)src; - a16 += srcColor & 0x3f; - b16 += (srcColor >> 6) & 0x3f; - g16 += (srcColor >> 12) & 0x3f; - r16 += (srcColor >> 18) & 0x3f; + a16 += srcColor & 0x3f; + b16 += (srcColor >> 6) & 0x3f; + g16 += (srcColor >> 12) & 0x3f; + r16 += (srcColor >> 18) & 0x3f; - src += 3; // move to next pixel - } - src += (640 - 2) * 3; // move to next line - } + src += 3; // move to next pixel + } + src += (640 - 2) * 3; // move to next line + } - *r = r16 + (r16 >> 6); - *g = g16 + (g16 >> 6); - *b = b16 + (b16 >> 6); - *a = a16 + (a16 >> 6); + *r = r16 + (r16 >> 6); + *g = g16 + (g16 >> 6); + *b = b16 + (b16 >> 6); + *a = a16 + (a16 >> 6); } static inline void BoxfilterRGBA_to_RGB8(const u8* src, u8* r, u8* g, u8* b) { - u16 r16 = 0, g16 = 0, b16 = 0; + u16 r16 = 0, g16 = 0, b16 = 0; - for (int y = 0; y < 2; y++) - { - for (int x = 0; x < 2; x++) - { - u32 srcColor = *(u32*)src; + for (int y = 0; y < 2; y++) + { + for (int x = 0; x < 2; x++) + { + u32 srcColor = *(u32*)src; - b16 += (srcColor >> 6) & 0x3f; - g16 += (srcColor >> 12) & 0x3f; - r16 += (srcColor >> 18) & 0x3f; + b16 += (srcColor >> 6) & 0x3f; + g16 += (srcColor >> 12) & 0x3f; + r16 += (srcColor >> 18) & 0x3f; - src += 3; // move to next pixel - } - src += (640 - 2) * 3; // move to next line - } + src += 3; // move to next pixel + } + src += (640 - 2) * 3; // move to next line + } - *r = r16 + (r16 >> 6); - *g = g16 + (g16 >> 6); - *b = b16 + (b16 >> 6); + *r = r16 + (r16 >> 6); + *g = g16 + (g16 >> 6); + *b = b16 + (b16 >> 6); } static inline void BoxfilterRGBA_to_x8(const u8* src, u8* x8, int shift) { - u16 x16 = 0; + u16 x16 = 0; - for (int y = 0; y < 2; y++) - { - for (int x = 0; x < 2; x++) - { - u32 srcColor = *(u32*)src; + for (int y = 0; y < 2; y++) + { + for (int x = 0; x < 2; x++) + { + u32 srcColor = *(u32*)src; - x16 += (srcColor >> shift) & 0x3f; + x16 += (srcColor >> shift) & 0x3f; - src += 3; // move to next pixel - } - src += (640 - 2) * 3; // move to next line - } + src += 3; // move to next pixel + } + src += (640 - 2) * 3; // move to next line + } - *x8 = x16 + (x16 >> 6); + *x8 = x16 + (x16 >> 6); } static inline void BoxfilterRGBA_to_xx8(const u8* src, u8* x1, u8* x2, int shift1, int shift2) { - u16 x16_1 = 0; - u16 x16_2 = 0; + u16 x16_1 = 0; + u16 x16_2 = 0; - for (int y = 0; y < 2; y++) - { - for (int x = 0; x < 2; x++) - { - u32 srcColor = *(u32*)src; + for (int y = 0; y < 2; y++) + { + for (int x = 0; x < 2; x++) + { + u32 srcColor = *(u32*)src; - x16_1 += (srcColor >> shift1) & 0x3f; - x16_2 += (srcColor >> shift2) & 0x3f; + x16_1 += (srcColor >> shift1) & 0x3f; + x16_2 += (srcColor >> shift2) & 0x3f; - src += 3; // move to next pixel - } - src += (640 - 2) * 3; // move to next line - } + src += 3; // move to next pixel + } + src += (640 - 2) * 3; // move to next line + } - *x1 = x16_1 + (x16_1 >> 6); - *x2 = x16_2 + (x16_2 >> 6); + *x1 = x16_1 + (x16_1 >> 6); + *x2 = x16_2 + (x16_2 >> 6); } static inline void BoxfilterRGB_to_RGB8(const u8* src, u8* r, u8* g, u8* b) { - u16 r16 = 0, g16 = 0, b16 = 0; + u16 r16 = 0, g16 = 0, b16 = 0; - for (int y = 0; y < 2; y++) - { - for (int x = 0; x < 2; x++) - { - b16 += src[0]; - g16 += src[1]; - r16 += src[2]; + for (int y = 0; y < 2; y++) + { + for (int x = 0; x < 2; x++) + { + b16 += src[0]; + g16 += src[1]; + r16 += src[2]; - src += 3; // move to next pixel - } - src += (640 - 2) * 3; // move to next line - } + src += 3; // move to next pixel + } + src += (640 - 2) * 3; // move to next line + } - *r = r16 >> 2; - *g = g16 >> 2; - *b = b16 >> 2; + *r = r16 >> 2; + *g = g16 >> 2; + *b = b16 >> 2; } -static inline void BoxfilterRGB_to_x8(u8 *src, u8* x8, int comp) +static inline void BoxfilterRGB_to_x8(u8* src, u8* x8, int comp) { - u16 x16 = 0; + u16 x16 = 0; - for (int y = 0; y < 2; y++) - { - for (int x = 0; x < 2; x++) - { + for (int y = 0; y < 2; y++) + { + for (int x = 0; x < 2; x++) + { + x16 += src[comp]; - x16 += src[comp]; + src += 3; // move to next pixel + } + src += (640 - 2) * 3; // move to next line + } - src += 3; // move to next pixel - } - src += (640 - 2) * 3; // move to next line - } - - *x8 = x16 >> 2; + *x8 = x16 >> 2; } static inline void BoxfilterRGB_to_xx8(const u8* src, u8* x1, u8* x2, int comp1, int comp2) { - u16 x16_1 = 0; - u16 x16_2 = 0; + u16 x16_1 = 0; + u16 x16_2 = 0; - for (int y = 0; y < 2; y++) - { - for (int x = 0; x < 2; x++) - { + for (int y = 0; y < 2; y++) + { + for (int x = 0; x < 2; x++) + { + x16_1 += src[comp1]; + x16_2 += src[comp2]; - x16_1 += src[comp1]; - x16_2 += src[comp2]; + src += 3; // move to next pixel + } + src += (640 - 2) * 3; // move to next line + } - src += 3; // move to next pixel - } - src += (640 - 2) * 3; // move to next line - } - - *x1 = x16_1 >> 2; - *x2 = x16_2 >> 2; + *x1 = x16_1 >> 2; + *x2 = x16_2 >> 2; } -static void SetBlockDimensions(int blkWidthLog2, int blkHeightLog2, u16* sBlkCount, u16* tBlkCount, u16* sBlkSize, u16* tBlkSize) +static void SetBlockDimensions(int blkWidthLog2, int blkHeightLog2, u16* sBlkCount, u16* tBlkCount, + u16* sBlkSize, u16* tBlkSize) { - // if half_scale is 1 then the size is cut in half - u32 width = bpmem.copyTexSrcWH.x >> bpmem.triggerEFBCopy.half_scale; - u32 height = bpmem.copyTexSrcWH.y >> bpmem.triggerEFBCopy.half_scale; + // if half_scale is 1 then the size is cut in half + u32 width = bpmem.copyTexSrcWH.x >> bpmem.triggerEFBCopy.half_scale; + u32 height = bpmem.copyTexSrcWH.y >> bpmem.triggerEFBCopy.half_scale; - *sBlkCount = (width >> blkWidthLog2) + 1; - *tBlkCount = (height >> blkHeightLog2) + 1; + *sBlkCount = (width >> blkWidthLog2) + 1; + *tBlkCount = (height >> blkHeightLog2) + 1; - *sBlkSize = 1 << blkWidthLog2; - *tBlkSize = 1 << blkHeightLog2; + *sBlkSize = 1 << blkWidthLog2; + *tBlkSize = 1 << blkHeightLog2; } -static void SetSpans(int sBlkSize, int tBlkSize, s32* tSpan, s32* sBlkSpan, s32* tBlkSpan, s32* writeStride) +static void SetSpans(int sBlkSize, int tBlkSize, s32* tSpan, s32* sBlkSpan, s32* tBlkSpan, + s32* writeStride) { - // width is 1 less than the number of pixels of width - u32 width = bpmem.copyTexSrcWH.x >> bpmem.triggerEFBCopy.half_scale; - u32 alignedWidth = (width + sBlkSize) & (~(sBlkSize-1)); + // width is 1 less than the number of pixels of width + u32 width = bpmem.copyTexSrcWH.x >> bpmem.triggerEFBCopy.half_scale; + u32 alignedWidth = (width + sBlkSize) & (~(sBlkSize - 1)); - u32 readStride = 3 << bpmem.triggerEFBCopy.half_scale; + u32 readStride = 3 << bpmem.triggerEFBCopy.half_scale; - *tSpan = (640 - sBlkSize) * readStride; // bytes to advance src pointer after each row of texels in a block - *sBlkSpan = ((-640 * tBlkSize) + sBlkSize) * readStride; // bytes to advance src pointer after each block - *tBlkSpan = ((640 * tBlkSize) - alignedWidth) * readStride; // bytes to advance src pointer after each row of blocks + *tSpan = (640 - sBlkSize) * + readStride; // bytes to advance src pointer after each row of texels in a block + *sBlkSpan = + ((-640 * tBlkSize) + sBlkSize) * readStride; // bytes to advance src pointer after each block + *tBlkSpan = ((640 * tBlkSize) - alignedWidth) * + readStride; // bytes to advance src pointer after each row of blocks - *writeStride = bpmem.copyMipMapStrideChannels * 32; + *writeStride = bpmem.copyMipMapStrideChannels * 32; } -#define ENCODE_LOOP_BLOCKS \ - for (int tBlk = 0; tBlk < tBlkCount; tBlk++) { \ - dst = dstBlockStart; \ - for (int sBlk = 0; sBlk < sBlkCount; sBlk++) { \ - for (int t = 0; t < tBlkSize; t++) { \ - for (int s = 0; s < sBlkSize; s++) { \ +#define ENCODE_LOOP_BLOCKS \ + for (int tBlk = 0; tBlk < tBlkCount; tBlk++) \ + { \ + dst = dstBlockStart; \ + for (int sBlk = 0; sBlk < sBlkCount; sBlk++) \ + { \ + for (int t = 0; t < tBlkSize; t++) \ + { \ + for (int s = 0; s < sBlkSize; s++) \ + { +#define ENCODE_LOOP_SPANS \ + } \ + src += tSpan; \ + } \ + src += sBlkSpan; \ + } \ + src += tBlkSpan; \ + dstBlockStart += writeStride; \ + } +#define ENCODE_LOOP_SPANS2 \ + } \ + src += tSpan; \ + } \ + src += sBlkSpan; \ + dst += 32; \ + } \ + src += tBlkSpan; \ + dstBlockStart += writeStride; \ + } -#define ENCODE_LOOP_SPANS \ - } \ - src += tSpan; \ - } \ - src += sBlkSpan; \ - } \ - src += tBlkSpan; \ - dstBlockStart += writeStride; \ - } \ - -#define ENCODE_LOOP_SPANS2 \ - } \ - src += tSpan; \ - } \ - src += sBlkSpan; \ - dst += 32; \ - } \ - src += tBlkSpan; \ - dstBlockStart += writeStride; \ - } \ - -static void EncodeRGBA6(u8 *dst, u8 *src, u32 format) +static void EncodeRGBA6(u8* dst, u8* src, u32 format) { - u16 sBlkCount, tBlkCount, sBlkSize, tBlkSize; - s32 tSpan, sBlkSpan, tBlkSpan, writeStride; - u8 r, g, b, a; - u32 readStride = 3; - u8 *dstBlockStart = dst; + u16 sBlkCount, tBlkCount, sBlkSize, tBlkSize; + s32 tSpan, sBlkSpan, tBlkSpan, writeStride; + u8 r, g, b, a; + u32 readStride = 3; + u8* dstBlockStart = dst; - switch (format) - { - case GX_TF_I4: - SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - sBlkSize /= 2; - ENCODE_LOOP_BLOCKS - { - RGBA_to_RGB8(src, &r, &g, &b); - src += readStride; - *dst = RGB8_to_I(r, g, b) & 0xf0; + switch (format) + { + case GX_TF_I4: + SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + sBlkSize /= 2; + ENCODE_LOOP_BLOCKS + { + RGBA_to_RGB8(src, &r, &g, &b); + src += readStride; + *dst = RGB8_to_I(r, g, b) & 0xf0; - RGBA_to_RGB8(src, &r, &g, &b); - src += readStride; - *dst |= RGB8_to_I(r, g, b) >> 4; - dst++; - } - ENCODE_LOOP_SPANS - break; + RGBA_to_RGB8(src, &r, &g, &b); + src += readStride; + *dst |= RGB8_to_I(r, g, b) >> 4; + dst++; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_I8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - RGBA_to_RGB8(src, &r, &g, &b); - src += readStride; - *dst++ = RGB8_to_I(r, g, b); - } - ENCODE_LOOP_SPANS - break; + case GX_TF_I8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + RGBA_to_RGB8(src, &r, &g, &b); + src += readStride; + *dst++ = RGB8_to_I(r, g, b); + } + ENCODE_LOOP_SPANS + break; - case GX_TF_IA4: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - RGBA_to_RGBA8(src, &r, &g, &b, &a); - src += readStride; - *dst++ = (a & 0xf0) | (RGB8_to_I(r, g, b) >> 4); - } - ENCODE_LOOP_SPANS - break; + case GX_TF_IA4: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + RGBA_to_RGBA8(src, &r, &g, &b, &a); + src += readStride; + *dst++ = (a & 0xf0) | (RGB8_to_I(r, g, b) >> 4); + } + ENCODE_LOOP_SPANS + break; - case GX_TF_IA8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - RGBA_to_RGBA8(src, &r, &g, &b, &a); - src += readStride; - *dst++ = a; - *dst++ = RGB8_to_I(r, g, b); - } - ENCODE_LOOP_SPANS - break; + case GX_TF_IA8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + RGBA_to_RGBA8(src, &r, &g, &b, &a); + src += readStride; + *dst++ = a; + *dst++ = RGB8_to_I(r, g, b); + } + ENCODE_LOOP_SPANS + break; - case GX_TF_RGB565: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - u32 srcColor = *(u32*)src; - src += readStride; + case GX_TF_RGB565: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + u32 srcColor = *(u32*)src; + src += readStride; - u16 val = ((srcColor >> 8) & 0xf800) | ((srcColor >> 7) & 0x07e0) | ((srcColor >> 7) & 0x001e); - *(u16*)dst = Common::swap16(val); - dst+=2; - } - ENCODE_LOOP_SPANS - break; + u16 val = + ((srcColor >> 8) & 0xf800) | ((srcColor >> 7) & 0x07e0) | ((srcColor >> 7) & 0x001e); + *(u16*)dst = Common::swap16(val); + dst += 2; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_RGB5A3: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - u32 srcColor = *(u32*)src; - src += readStride; + case GX_TF_RGB5A3: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + u32 srcColor = *(u32*)src; + src += readStride; - u16 alpha = (srcColor << 9) & 0x7000; - u16 val; - if (alpha == 0x7000) // 555 - val = 0x8000 | ((srcColor >> 9) & 0x7c00) | ((srcColor >> 8) & 0x03e0) | ((srcColor >> 7) & 0x001e); - else // 4443 - val = alpha | ((srcColor >> 12) & 0x0f00) | ((srcColor >> 10) & 0x00f0) | ((srcColor >> 8) & 0x000f); + u16 alpha = (srcColor << 9) & 0x7000; + u16 val; + if (alpha == 0x7000) // 555 + val = 0x8000 | ((srcColor >> 9) & 0x7c00) | ((srcColor >> 8) & 0x03e0) | + ((srcColor >> 7) & 0x001e); + else // 4443 + val = alpha | ((srcColor >> 12) & 0x0f00) | ((srcColor >> 10) & 0x00f0) | + ((srcColor >> 8) & 0x000f); - *(u16*)dst = Common::swap16(val); - dst+=2; - } - ENCODE_LOOP_SPANS - break; + *(u16*)dst = Common::swap16(val); + dst += 2; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_RGBA8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - RGBA_to_RGBA8(src, &dst[1], &dst[32], &dst[33], &dst[0]); - src += readStride; - dst += 2; - } - ENCODE_LOOP_SPANS2 - break; + case GX_TF_RGBA8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + RGBA_to_RGBA8(src, &dst[1], &dst[32], &dst[33], &dst[0]); + src += readStride; + dst += 2; + } + ENCODE_LOOP_SPANS2 + break; - case GX_CTF_R4: - SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - sBlkSize /= 2; - ENCODE_LOOP_BLOCKS - { - u32 srcColor = *(u32*)src; - src += readStride; - *dst = (srcColor >> 16) & 0xf0; + case GX_CTF_R4: + SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + sBlkSize /= 2; + ENCODE_LOOP_BLOCKS + { + u32 srcColor = *(u32*)src; + src += readStride; + *dst = (srcColor >> 16) & 0xf0; - srcColor = *(u32*)src; - src += readStride; - *dst |= (srcColor >> 20) & 0x0f; - dst++; - } - ENCODE_LOOP_SPANS - break; + srcColor = *(u32*)src; + src += readStride; + *dst |= (srcColor >> 20) & 0x0f; + dst++; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_RA4: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - u32 srcColor = *(u32*)src; - src += readStride; - *dst++ = ((srcColor << 2) & 0xf0) | ((srcColor >> 20) & 0x0f); - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_RA4: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + u32 srcColor = *(u32*)src; + src += readStride; + *dst++ = ((srcColor << 2) & 0xf0) | ((srcColor >> 20) & 0x0f); + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_RA8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - u32 srcColor = *(u32*)src; - src += readStride; - *dst++ = Convert6To8(srcColor & 0x3f); - *dst++ = Convert6To8((srcColor >> 18) & 0x3f); - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_RA8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + u32 srcColor = *(u32*)src; + src += readStride; + *dst++ = Convert6To8(srcColor & 0x3f); + *dst++ = Convert6To8((srcColor >> 18) & 0x3f); + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_A8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - u32 srcColor = *(u32*)src; - *dst++ = Convert6To8(srcColor & 0x3f); - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_A8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + u32 srcColor = *(u32*)src; + *dst++ = Convert6To8(srcColor & 0x3f); + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_R8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - u32 srcColor = *(u32*)src; - *dst++ = Convert6To8((srcColor >> 18) & 0x3f); - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_R8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + u32 srcColor = *(u32*)src; + *dst++ = Convert6To8((srcColor >> 18) & 0x3f); + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_G8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - u32 srcColor = *(u32*)src; - *dst++ = Convert6To8((srcColor >> 12) & 0x3f); - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_G8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + u32 srcColor = *(u32*)src; + *dst++ = Convert6To8((srcColor >> 12) & 0x3f); + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_B8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - u32 srcColor = *(u32*)src; - *dst++ = Convert6To8((srcColor >> 6) & 0x3f); - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_B8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + u32 srcColor = *(u32*)src; + *dst++ = Convert6To8((srcColor >> 6) & 0x3f); + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_RG8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - u32 srcColor = *(u32*)src; - src += readStride; - *dst++ = Convert6To8((srcColor >> 12) & 0x3f); - *dst++ = Convert6To8((srcColor >> 18) & 0x3f); - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_RG8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + u32 srcColor = *(u32*)src; + src += readStride; + *dst++ = Convert6To8((srcColor >> 12) & 0x3f); + *dst++ = Convert6To8((srcColor >> 18) & 0x3f); + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_GB8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - u32 srcColor = *(u32*)src; - src += readStride; - *dst++ = Convert6To8((srcColor >> 6) & 0x3f); - *dst++ = Convert6To8((srcColor >> 12) & 0x3f); - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_GB8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + u32 srcColor = *(u32*)src; + src += readStride; + *dst++ = Convert6To8((srcColor >> 6) & 0x3f); + *dst++ = Convert6To8((srcColor >> 12) & 0x3f); + } + ENCODE_LOOP_SPANS + break; - default: - PanicAlert("Unknown texture copy format: 0x%x\n", format); - break; - } + default: + PanicAlert("Unknown texture copy format: 0x%x\n", format); + break; + } } - -static void EncodeRGBA6halfscale(u8 *dst, u8 *src, u32 format) +static void EncodeRGBA6halfscale(u8* dst, u8* src, u32 format) { - u16 sBlkCount, tBlkCount, sBlkSize, tBlkSize; - s32 tSpan, sBlkSpan, tBlkSpan, writeStride; - u8 r, g, b, a; - u32 readStride = 6; - u8 *dstBlockStart = dst; + u16 sBlkCount, tBlkCount, sBlkSize, tBlkSize; + s32 tSpan, sBlkSpan, tBlkSpan, writeStride; + u8 r, g, b, a; + u32 readStride = 6; + u8* dstBlockStart = dst; - switch (format) - { - case GX_TF_I4: - SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - sBlkSize /= 2; - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_RGB8(src, &r, &g, &b); - src += readStride; - *dst = RGB8_to_I(r, g, b) & 0xf0; + switch (format) + { + case GX_TF_I4: + SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + sBlkSize /= 2; + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_RGB8(src, &r, &g, &b); + src += readStride; + *dst = RGB8_to_I(r, g, b) & 0xf0; - BoxfilterRGBA_to_RGB8(src, &r, &g, &b); - src += readStride; - *dst |= RGB8_to_I(r, g, b) >> 4; - dst++; - } - ENCODE_LOOP_SPANS - break; + BoxfilterRGBA_to_RGB8(src, &r, &g, &b); + src += readStride; + *dst |= RGB8_to_I(r, g, b) >> 4; + dst++; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_I8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_RGB8(src, &r, &g, &b); - src += readStride; - *dst++ = RGB8_to_I(r, g, b); - } - ENCODE_LOOP_SPANS - break; + case GX_TF_I8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_RGB8(src, &r, &g, &b); + src += readStride; + *dst++ = RGB8_to_I(r, g, b); + } + ENCODE_LOOP_SPANS + break; - case GX_TF_IA4: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_RGBA8(src, &r, &g, &b, &a); - src += readStride; - *dst++ = (a & 0xf0) | (RGB8_to_I(r, g, b) >> 4); - } - ENCODE_LOOP_SPANS - break; + case GX_TF_IA4: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_RGBA8(src, &r, &g, &b, &a); + src += readStride; + *dst++ = (a & 0xf0) | (RGB8_to_I(r, g, b) >> 4); + } + ENCODE_LOOP_SPANS + break; - case GX_TF_IA8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_RGBA8(src, &r, &g, &b, &a); - src += readStride; - *dst++ = a; - *dst++ = RGB8_to_I(r, g, b); - } - ENCODE_LOOP_SPANS - break; + case GX_TF_IA8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_RGBA8(src, &r, &g, &b, &a); + src += readStride; + *dst++ = a; + *dst++ = RGB8_to_I(r, g, b); + } + ENCODE_LOOP_SPANS + break; - case GX_TF_RGB565: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_RGB8(src, &r, &g, &b); - src += readStride; + case GX_TF_RGB565: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_RGB8(src, &r, &g, &b); + src += readStride; - u16 val = ((r << 8) & 0xf800) | ((g << 3) & 0x07e0) | ((b >> 3) & 0x001e); - *(u16*)dst = Common::swap16(val); - dst+=2; - } - ENCODE_LOOP_SPANS - break; + u16 val = ((r << 8) & 0xf800) | ((g << 3) & 0x07e0) | ((b >> 3) & 0x001e); + *(u16*)dst = Common::swap16(val); + dst += 2; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_RGB5A3: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_RGBA8(src, &r, &g, &b, &a); - src += readStride; + case GX_TF_RGB5A3: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_RGBA8(src, &r, &g, &b, &a); + src += readStride; - u16 val; - if (a >= 224) // 5551 - val = 0x8000 | ((r << 7) & 0x7c00) | ((g << 2) & 0x03e0) | ((b >> 3) & 0x001e); - else // 4443 - val = ((a << 7) & 0x7000) | ((r << 4) & 0x0f00) | (g & 0x00f0) | ((b >> 4) & 0x000f); + u16 val; + if (a >= 224) // 5551 + val = 0x8000 | ((r << 7) & 0x7c00) | ((g << 2) & 0x03e0) | ((b >> 3) & 0x001e); + else // 4443 + val = ((a << 7) & 0x7000) | ((r << 4) & 0x0f00) | (g & 0x00f0) | ((b >> 4) & 0x000f); - *(u16*)dst = Common::swap16(val); - dst+=2; - } - ENCODE_LOOP_SPANS - break; + *(u16*)dst = Common::swap16(val); + dst += 2; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_RGBA8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_RGBA8(src, &dst[1], &dst[32], &dst[33], &dst[0]); - src += readStride; - dst += 2; - } - ENCODE_LOOP_SPANS2 - break; + case GX_TF_RGBA8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_RGBA8(src, &dst[1], &dst[32], &dst[33], &dst[0]); + src += readStride; + dst += 2; + } + ENCODE_LOOP_SPANS2 + break; - case GX_CTF_R4: - SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - sBlkSize /= 2; - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_x8(src, &r, 18); - src += readStride; - *dst = r & 0xf0; + case GX_CTF_R4: + SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + sBlkSize /= 2; + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_x8(src, &r, 18); + src += readStride; + *dst = r & 0xf0; - BoxfilterRGBA_to_x8(src, &r, 18); - src += readStride; - *dst |= r >> 4; - dst++; - } - ENCODE_LOOP_SPANS - break; + BoxfilterRGBA_to_x8(src, &r, 18); + src += readStride; + *dst |= r >> 4; + dst++; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_RA4: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_xx8(src, &r, &a, 18, 0); - src += readStride; - *dst++ = (a & 0xf0) | (r >> 4); - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_RA4: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_xx8(src, &r, &a, 18, 0); + src += readStride; + *dst++ = (a & 0xf0) | (r >> 4); + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_RA8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_xx8(src, &r, &a, 18, 0); - src += readStride; - *dst++ = a; - *dst++ = r; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_RA8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_xx8(src, &r, &a, 18, 0); + src += readStride; + *dst++ = a; + *dst++ = r; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_A8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_x8(src, &a, 0); - *dst++ = a; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_A8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_x8(src, &a, 0); + *dst++ = a; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_R8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_x8(src, &r, 18); - *dst++ = r; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_R8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_x8(src, &r, 18); + *dst++ = r; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_G8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_x8(src, &g, 12); - *dst++ = g; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_G8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_x8(src, &g, 12); + *dst++ = g; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_B8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_x8(src, &b, 6); - *dst++ = b; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_B8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_x8(src, &b, 6); + *dst++ = b; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_RG8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_xx8(src, &r, &g, 18, 12); - src += readStride; - *dst++ = g; - *dst++ = r; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_RG8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_xx8(src, &r, &g, 18, 12); + src += readStride; + *dst++ = g; + *dst++ = r; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_GB8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGBA_to_xx8(src, &g, &b, 12, 6); - src += readStride; - *dst++ = b; - *dst++ = g; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_GB8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGBA_to_xx8(src, &g, &b, 12, 6); + src += readStride; + *dst++ = b; + *dst++ = g; + } + ENCODE_LOOP_SPANS + break; - default: - PanicAlert("Unknown texture copy format: 0x%x\n", format); - break; - } + default: + PanicAlert("Unknown texture copy format: 0x%x\n", format); + break; + } } -static void EncodeRGB8(u8 *dst, u8 *src, u32 format) +static void EncodeRGB8(u8* dst, u8* src, u32 format) { - u16 sBlkCount, tBlkCount, sBlkSize, tBlkSize; - s32 tSpan, sBlkSpan, tBlkSpan, writeStride; - u32 readStride = 3; - u8 *dstBlockStart = dst; + u16 sBlkCount, tBlkCount, sBlkSize, tBlkSize; + s32 tSpan, sBlkSpan, tBlkSpan, writeStride; + u32 readStride = 3; + u8* dstBlockStart = dst; - switch (format) - { - case GX_TF_I4: - SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - sBlkSize /= 2; - ENCODE_LOOP_BLOCKS - { - *dst = RGB8_to_I(src[2], src[1], src[0]) & 0xf0; - src += readStride; + switch (format) + { + case GX_TF_I4: + SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + sBlkSize /= 2; + ENCODE_LOOP_BLOCKS + { + *dst = RGB8_to_I(src[2], src[1], src[0]) & 0xf0; + src += readStride; - *dst |= RGB8_to_I(src[2], src[1], src[0]) >> 4; - src += readStride; - dst++; - } - ENCODE_LOOP_SPANS - break; + *dst |= RGB8_to_I(src[2], src[1], src[0]) >> 4; + src += readStride; + dst++; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_I8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = RGB8_to_I(src[2], src[1], src[0]); - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_TF_I8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + *dst++ = RGB8_to_I(src[2], src[1], src[0]); + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_IA4: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = 0xf0 | (RGB8_to_I(src[2], src[1], src[0]) >> 4); - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_TF_IA4: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + *dst++ = 0xf0 | (RGB8_to_I(src[2], src[1], src[0]) >> 4); + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_IA8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = 0xff; - *dst++ = RGB8_to_I(src[2], src[1], src[0]); + case GX_TF_IA8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + *dst++ = 0xff; + *dst++ = RGB8_to_I(src[2], src[1], src[0]); - src += readStride; - } - ENCODE_LOOP_SPANS - break; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_RGB565: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - u16 val = ((src[2] << 8) & 0xf800) | ((src[1] << 3) & 0x07e0) | ((src[0] >> 3) & 0x001e); - *(u16*)dst = Common::swap16(val); - src += readStride; - dst+=2; - } - ENCODE_LOOP_SPANS - break; + case GX_TF_RGB565: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + u16 val = ((src[2] << 8) & 0xf800) | ((src[1] << 3) & 0x07e0) | ((src[0] >> 3) & 0x001e); + *(u16*)dst = Common::swap16(val); + src += readStride; + dst += 2; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_RGB5A3: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - u16 val = 0x8000 | ((src[2] << 7) & 0x7c00) | ((src[1] << 2) & 0x03e0) | ((src[0] >> 3) & 0x001e); - *(u16*)dst = Common::swap16(val); - src += readStride; - dst+=2; - } - ENCODE_LOOP_SPANS - break; + case GX_TF_RGB5A3: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + u16 val = + 0x8000 | ((src[2] << 7) & 0x7c00) | ((src[1] << 2) & 0x03e0) | ((src[0] >> 3) & 0x001e); + *(u16*)dst = Common::swap16(val); + src += readStride; + dst += 2; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_RGBA8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - dst[0] = 0xff; - dst[1] = src[2]; - dst[32] = src[1]; - dst[33] = src[0]; - src += readStride; - dst += 2; - } - ENCODE_LOOP_SPANS2 - break; + case GX_TF_RGBA8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + dst[0] = 0xff; + dst[1] = src[2]; + dst[32] = src[1]; + dst[33] = src[0]; + src += readStride; + dst += 2; + } + ENCODE_LOOP_SPANS2 + break; - case GX_CTF_R4: - SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - sBlkSize /= 2; - ENCODE_LOOP_BLOCKS - { - *dst = src[2] & 0xf0; - src += readStride; + case GX_CTF_R4: + SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + sBlkSize /= 2; + ENCODE_LOOP_BLOCKS + { + *dst = src[2] & 0xf0; + src += readStride; - *dst |= src[2] >> 4; - src += readStride; + *dst |= src[2] >> 4; + src += readStride; - dst++; - } - ENCODE_LOOP_SPANS - break; + dst++; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_RA4: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = 0xf0 | (src[2] >> 4); - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_RA4: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + *dst++ = 0xf0 | (src[2] >> 4); + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_RA8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = 0xff; - *dst++ = src[2]; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_RA8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + *dst++ = 0xff; + *dst++ = src[2]; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_A8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = 0xff; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_A8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS { *dst++ = 0xff; } + ENCODE_LOOP_SPANS + break; - case GX_CTF_R8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = src[2]; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_R8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + *dst++ = src[2]; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_G8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = src[1]; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_G8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + *dst++ = src[1]; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_B8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = src[0]; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_B8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + *dst++ = src[0]; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_RG8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = src[1]; - *dst++ = src[2]; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_RG8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + *dst++ = src[1]; + *dst++ = src[2]; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_GB8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = src[0]; - *dst++ = src[1]; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_GB8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + *dst++ = src[0]; + *dst++ = src[1]; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - default: - PanicAlert("Unknown texture copy format: 0x%x\n", format); - break; - } + default: + PanicAlert("Unknown texture copy format: 0x%x\n", format); + break; + } } -static void EncodeRGB8halfscale(u8 *dst, u8 *src, u32 format) +static void EncodeRGB8halfscale(u8* dst, u8* src, u32 format) { - u16 sBlkCount, tBlkCount, sBlkSize, tBlkSize; - s32 tSpan, sBlkSpan, tBlkSpan, writeStride; - u8 r, g, b; - u32 readStride = 6; - u8 *dstBlockStart = dst; + u16 sBlkCount, tBlkCount, sBlkSize, tBlkSize; + s32 tSpan, sBlkSpan, tBlkSpan, writeStride; + u8 r, g, b; + u32 readStride = 6; + u8* dstBlockStart = dst; - switch (format) - { - case GX_TF_I4: - SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - sBlkSize /= 2; - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_RGB8(src, &r, &g, &b); - *dst = RGB8_to_I(r, g, b) & 0xf0; - src += readStride; + switch (format) + { + case GX_TF_I4: + SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + sBlkSize /= 2; + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_RGB8(src, &r, &g, &b); + *dst = RGB8_to_I(r, g, b) & 0xf0; + src += readStride; - BoxfilterRGB_to_RGB8(src, &r, &g, &b); - *dst |= RGB8_to_I(r, g, b) >> 4; - src += readStride; - dst++; - } - ENCODE_LOOP_SPANS - break; + BoxfilterRGB_to_RGB8(src, &r, &g, &b); + *dst |= RGB8_to_I(r, g, b) >> 4; + src += readStride; + dst++; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_I8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_RGB8(src, &r, &g, &b); - *dst++ = RGB8_to_I(r, g, b); - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_TF_I8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_RGB8(src, &r, &g, &b); + *dst++ = RGB8_to_I(r, g, b); + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_IA4: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_RGB8(src, &r, &g, &b); - *dst++ = 0xf0 | (RGB8_to_I(r, g, b) >> 4); - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_TF_IA4: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_RGB8(src, &r, &g, &b); + *dst++ = 0xf0 | (RGB8_to_I(r, g, b) >> 4); + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_IA8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_RGB8(src, &r, &g, &b); - *dst++ = 0xff; - *dst++ = RGB8_to_I(r, g, b); - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_TF_IA8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_RGB8(src, &r, &g, &b); + *dst++ = 0xff; + *dst++ = RGB8_to_I(r, g, b); + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_RGB565: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_RGB8(src, &r, &g, &b); - u16 val = ((r << 8) & 0xf800) | ((g << 3) & 0x07e0) | ((b >> 3) & 0x001e); - *(u16*)dst = Common::swap16(val); - src += readStride; - dst+=2; - } - ENCODE_LOOP_SPANS - break; + case GX_TF_RGB565: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_RGB8(src, &r, &g, &b); + u16 val = ((r << 8) & 0xf800) | ((g << 3) & 0x07e0) | ((b >> 3) & 0x001e); + *(u16*)dst = Common::swap16(val); + src += readStride; + dst += 2; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_RGB5A3: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_RGB8(src, &r, &g, &b); - u16 val = 0x8000 | ((r << 7) & 0x7c00) | ((g << 2) & 0x03e0) | ((b >> 3) & 0x001e); - *(u16*)dst = Common::swap16(val); - src += readStride; - dst+=2; - } - ENCODE_LOOP_SPANS - break; + case GX_TF_RGB5A3: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_RGB8(src, &r, &g, &b); + u16 val = 0x8000 | ((r << 7) & 0x7c00) | ((g << 2) & 0x03e0) | ((b >> 3) & 0x001e); + *(u16*)dst = Common::swap16(val); + src += readStride; + dst += 2; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_RGBA8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_RGB8(src, &r, &g, &b); - dst[0] = 0xff; - dst[1] = r; - dst[32] = g; - dst[33] = b; - src += readStride; - dst += 2; - } - ENCODE_LOOP_SPANS2 - break; + case GX_TF_RGBA8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_RGB8(src, &r, &g, &b); + dst[0] = 0xff; + dst[1] = r; + dst[32] = g; + dst[33] = b; + src += readStride; + dst += 2; + } + ENCODE_LOOP_SPANS2 + break; - case GX_CTF_R4: - SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - sBlkSize /= 2; - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_x8(src, &r, 2); - *dst = r & 0xf0; - src += readStride; + case GX_CTF_R4: + SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + sBlkSize /= 2; + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_x8(src, &r, 2); + *dst = r & 0xf0; + src += readStride; - BoxfilterRGB_to_x8(src, &r, 2); - *dst |= r >> 4; - src += readStride; + BoxfilterRGB_to_x8(src, &r, 2); + *dst |= r >> 4; + src += readStride; - dst++; - } - ENCODE_LOOP_SPANS - break; + dst++; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_RA4: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_x8(src, &r, 2); - *dst++ = 0xf0 | (r >> 4); - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_RA4: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_x8(src, &r, 2); + *dst++ = 0xf0 | (r >> 4); + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_RA8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_x8(src, &r, 2); - *dst++ = 0xff; - *dst++ = r; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_RA8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_x8(src, &r, 2); + *dst++ = 0xff; + *dst++ = r; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_A8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = 0xff; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_A8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS { *dst++ = 0xff; } + ENCODE_LOOP_SPANS + break; - case GX_CTF_R8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_x8(src, &r, 2); - *dst++ = r; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_R8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_x8(src, &r, 2); + *dst++ = r; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_G8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_x8(src, &g, 1); - *dst++ = g; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_G8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_x8(src, &g, 1); + *dst++ = g; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_B8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_x8(src, &b, 0); - *dst++ = b; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_B8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_x8(src, &b, 0); + *dst++ = b; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_RG8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_xx8(src, &r, &g, 2, 1); - *dst++ = g; - *dst++ = r; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_RG8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_xx8(src, &r, &g, 2, 1); + *dst++ = g; + *dst++ = r; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_GB8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_xx8(src, &g, &b, 1, 0); - *dst++ = b; - *dst++ = g; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_GB8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_xx8(src, &g, &b, 1, 0); + *dst++ = b; + *dst++ = g; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - default: - PanicAlert("Unknown texture copy format: 0x%x\n", format); - break; - } + default: + PanicAlert("Unknown texture copy format: 0x%x\n", format); + break; + } } -static void EncodeZ24(u8 *dst, u8 *src, u32 format) +static void EncodeZ24(u8* dst, u8* src, u32 format) { - u16 sBlkCount, tBlkCount, sBlkSize, tBlkSize; - s32 tSpan, sBlkSpan, tBlkSpan, writeStride; - u32 readStride = 3; - u8 *dstBlockStart = dst; + u16 sBlkCount, tBlkCount, sBlkSize, tBlkSize; + s32 tSpan, sBlkSpan, tBlkSpan, writeStride; + u32 readStride = 3; + u8* dstBlockStart = dst; - switch (format) - { - case GX_TF_Z8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = src[2]; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + switch (format) + { + case GX_TF_Z8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + *dst++ = src[2]; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_Z16: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = src[1]; - *dst++ = src[2]; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_TF_Z16: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + *dst++ = src[1]; + *dst++ = src[2]; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_Z24X8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - dst[0] = 0xff; - dst[1] = src[2]; - dst[32] = src[1]; - dst[33] = src[0]; - src += readStride; - dst += 2; - } - ENCODE_LOOP_SPANS2 - break; + case GX_TF_Z24X8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + dst[0] = 0xff; + dst[1] = src[2]; + dst[32] = src[1]; + dst[33] = src[0]; + src += readStride; + dst += 2; + } + ENCODE_LOOP_SPANS2 + break; - case GX_CTF_Z4: - SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - sBlkSize /= 2; - ENCODE_LOOP_BLOCKS - { - *dst = src[2] & 0xf0; - src += readStride; + case GX_CTF_Z4: + SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + sBlkSize /= 2; + ENCODE_LOOP_BLOCKS + { + *dst = src[2] & 0xf0; + src += readStride; - *dst |= src[2] >> 4; - src += readStride; + *dst |= src[2] >> 4; + src += readStride; - dst++; - } - ENCODE_LOOP_SPANS - break; + dst++; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_Z8M: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = src[1]; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_Z8M: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + *dst++ = src[1]; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_Z8L: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = src[0]; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_Z8L: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + *dst++ = src[0]; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_Z16L: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - *dst++ = src[0]; - *dst++ = src[1]; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_Z16L: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + *dst++ = src[0]; + *dst++ = src[1]; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - default: - PanicAlert("Unknown texture copy format: 0x%x\n", format); - break; - } + default: + PanicAlert("Unknown texture copy format: 0x%x\n", format); + break; + } } -static void EncodeZ24halfscale(u8 *dst, u8 *src, u32 format) +static void EncodeZ24halfscale(u8* dst, u8* src, u32 format) { - u16 sBlkCount, tBlkCount, sBlkSize, tBlkSize; - s32 tSpan, sBlkSpan, tBlkSpan, writeStride; - u32 readStride = 6; - u8 r, g, b; - u8 *dstBlockStart = dst; + u16 sBlkCount, tBlkCount, sBlkSize, tBlkSize; + s32 tSpan, sBlkSpan, tBlkSpan, writeStride; + u32 readStride = 6; + u8 r, g, b; + u8* dstBlockStart = dst; - switch (format) - { - case GX_TF_Z8: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_x8(src, &b, 2); - *dst++ = b; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + switch (format) + { + case GX_TF_Z8: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_x8(src, &b, 2); + *dst++ = b; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_Z16: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_xx8(src, &g, &b, 1, 2); - *dst++ = b; - *dst++ = g; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_TF_Z16: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_xx8(src, &g, &b, 1, 2); + *dst++ = b; + *dst++ = g; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_TF_Z24X8: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_RGB8(src, &dst[33], &dst[32], &dst[1]); - dst[0] = 255; - src += readStride; - dst += 2; - } - ENCODE_LOOP_SPANS2 - break; + case GX_TF_Z24X8: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_RGB8(src, &dst[33], &dst[32], &dst[1]); + dst[0] = 255; + src += readStride; + dst += 2; + } + ENCODE_LOOP_SPANS2 + break; - case GX_CTF_Z4: - SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - sBlkSize /= 2; - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_x8(src, &b, 2); - *dst = b & 0xf0; - src += readStride; + case GX_CTF_Z4: + SetBlockDimensions(3, 3, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + sBlkSize /= 2; + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_x8(src, &b, 2); + *dst = b & 0xf0; + src += readStride; - BoxfilterRGB_to_x8(src, &b, 2); - *dst |= b >> 4; - src += readStride; + BoxfilterRGB_to_x8(src, &b, 2); + *dst |= b >> 4; + src += readStride; - dst++; - } - ENCODE_LOOP_SPANS - break; + dst++; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_Z8M: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_x8(src, &g, 1); - *dst++ = g; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_Z8M: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_x8(src, &g, 1); + *dst++ = g; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_Z8L: - SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_x8(src, &r, 0); - *dst++ = r; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_Z8L: + SetBlockDimensions(3, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_x8(src, &r, 0); + *dst++ = r; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - case GX_CTF_Z16L: - SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); - SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); - ENCODE_LOOP_BLOCKS - { - BoxfilterRGB_to_xx8(src, &r, &g, 0, 1); - *dst++ = g; - *dst++ = r; - src += readStride; - } - ENCODE_LOOP_SPANS - break; + case GX_CTF_Z16L: + SetBlockDimensions(2, 2, &sBlkCount, &tBlkCount, &sBlkSize, &tBlkSize); + SetSpans(sBlkSize, tBlkSize, &tSpan, &sBlkSpan, &tBlkSpan, &writeStride); + ENCODE_LOOP_BLOCKS + { + BoxfilterRGB_to_xx8(src, &r, &g, 0, 1); + *dst++ = g; + *dst++ = r; + src += readStride; + } + ENCODE_LOOP_SPANS + break; - default: - PanicAlert("Unknown texture copy format: 0x%x\n", format); - break; - } + default: + PanicAlert("Unknown texture copy format: 0x%x\n", format); + break; + } } -void Encode(u8 *dest_ptr) +void Encode(u8* dest_ptr) { - auto pixelformat = bpmem.zcontrol.pixel_format; - bool bFromZBuffer = pixelformat == PEControl::Z24; - bool bIsIntensityFmt = bpmem.triggerEFBCopy.intensity_fmt > 0; - u32 copyfmt = ((bpmem.triggerEFBCopy.target_pixel_format / 2) + ((bpmem.triggerEFBCopy.target_pixel_format & 1) * 8)); + auto pixelformat = bpmem.zcontrol.pixel_format; + bool bFromZBuffer = pixelformat == PEControl::Z24; + bool bIsIntensityFmt = bpmem.triggerEFBCopy.intensity_fmt > 0; + u32 copyfmt = ((bpmem.triggerEFBCopy.target_pixel_format / 2) + + ((bpmem.triggerEFBCopy.target_pixel_format & 1) * 8)); - // pack copy format information into a single variable - u32 format = copyfmt; - if (bFromZBuffer) - { - format |= _GX_TF_ZTF; - if (copyfmt == 11) - format = GX_TF_Z16; - else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) - format |= _GX_TF_CTF; - } - else - if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt)) - format |= _GX_TF_CTF; + // pack copy format information into a single variable + u32 format = copyfmt; + if (bFromZBuffer) + { + format |= _GX_TF_ZTF; + if (copyfmt == 11) + format = GX_TF_Z16; + else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) + format |= _GX_TF_CTF; + } + else if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt)) + format |= _GX_TF_CTF; - u8 *src = EfbInterface::GetPixelPointer(bpmem.copyTexSrcXY.x, bpmem.copyTexSrcXY.y, bFromZBuffer); + u8* src = EfbInterface::GetPixelPointer(bpmem.copyTexSrcXY.x, bpmem.copyTexSrcXY.y, bFromZBuffer); - if (bpmem.triggerEFBCopy.half_scale) - { - if (pixelformat == PEControl::RGBA6_Z24) - EncodeRGBA6halfscale(dest_ptr, src, format); - else if (pixelformat == PEControl::RGB8_Z24) - EncodeRGB8halfscale(dest_ptr, src, format); - else if (pixelformat == PEControl::RGB565_Z16) // not supported - EncodeRGB8halfscale(dest_ptr, src, format); - else if (pixelformat == PEControl::Z24) - EncodeZ24halfscale(dest_ptr, src, format); - } - else - { - if (pixelformat == PEControl::RGBA6_Z24) - EncodeRGBA6(dest_ptr, src, format); - else if (pixelformat == PEControl::RGB8_Z24) - EncodeRGB8(dest_ptr, src, format); - else if (pixelformat == PEControl::RGB565_Z16) // not supported - EncodeRGB8(dest_ptr, src, format); - else if (pixelformat == PEControl::Z24) - EncodeZ24(dest_ptr, src, format); - } + if (bpmem.triggerEFBCopy.half_scale) + { + if (pixelformat == PEControl::RGBA6_Z24) + EncodeRGBA6halfscale(dest_ptr, src, format); + else if (pixelformat == PEControl::RGB8_Z24) + EncodeRGB8halfscale(dest_ptr, src, format); + else if (pixelformat == PEControl::RGB565_Z16) // not supported + EncodeRGB8halfscale(dest_ptr, src, format); + else if (pixelformat == PEControl::Z24) + EncodeZ24halfscale(dest_ptr, src, format); + } + else + { + if (pixelformat == PEControl::RGBA6_Z24) + EncodeRGBA6(dest_ptr, src, format); + else if (pixelformat == PEControl::RGB8_Z24) + EncodeRGB8(dest_ptr, src, format); + else if (pixelformat == PEControl::RGB565_Z16) // not supported + EncodeRGB8(dest_ptr, src, format); + else if (pixelformat == PEControl::Z24) + EncodeZ24(dest_ptr, src, format); + } } - - } diff --git a/Source/Core/VideoBackends/Software/TextureEncoder.h b/Source/Core/VideoBackends/Software/TextureEncoder.h index 5fb8731c4b..32bc9d10cd 100644 --- a/Source/Core/VideoBackends/Software/TextureEncoder.h +++ b/Source/Core/VideoBackends/Software/TextureEncoder.h @@ -8,5 +8,5 @@ namespace TextureEncoder { - void Encode(u8 *dest_ptr); +void Encode(u8* dest_ptr); } diff --git a/Source/Core/VideoBackends/Software/TextureSampler.cpp b/Source/Core/VideoBackends/Software/TextureSampler.cpp index b5049cb6a3..648dd7446b 100644 --- a/Source/Core/VideoBackends/Software/TextureSampler.cpp +++ b/Source/Core/VideoBackends/Software/TextureSampler.cpp @@ -17,224 +17,232 @@ namespace TextureSampler { - static inline void WrapCoord(int* coordp, int wrapMode, int imageSize) { - int coord = *coordp; - switch (wrapMode) - { - case 0: // clamp - coord = (coord>imageSize)?imageSize:(coord<0)?0:coord; - break; - case 1: // wrap - coord = coord % (imageSize + 1); - coord = (coord<0)?imageSize+coord:coord; - break; - case 2: // mirror - { - int sizePlus1 = imageSize + 1; - int div = coord / sizePlus1; - coord = coord - (div * sizePlus1); - coord = (coord<0)?-coord:coord; - coord = (div&1)?imageSize - coord:coord; - } - break; - } - *coordp = coord; + int coord = *coordp; + switch (wrapMode) + { + case 0: // clamp + coord = (coord > imageSize) ? imageSize : (coord < 0) ? 0 : coord; + break; + case 1: // wrap + coord = coord % (imageSize + 1); + coord = (coord < 0) ? imageSize + coord : coord; + break; + case 2: // mirror + { + int sizePlus1 = imageSize + 1; + int div = coord / sizePlus1; + coord = coord - (div * sizePlus1); + coord = (coord < 0) ? -coord : coord; + coord = (div & 1) ? imageSize - coord : coord; + } + break; + } + *coordp = coord; } -static inline void SetTexel(u8 *inTexel, u32 *outTexel, u32 fract) +static inline void SetTexel(u8* inTexel, u32* outTexel, u32 fract) { - outTexel[0] = inTexel[0] * fract; - outTexel[1] = inTexel[1] * fract; - outTexel[2] = inTexel[2] * fract; - outTexel[3] = inTexel[3] * fract; + outTexel[0] = inTexel[0] * fract; + outTexel[1] = inTexel[1] * fract; + outTexel[2] = inTexel[2] * fract; + outTexel[3] = inTexel[3] * fract; } -static inline void AddTexel(u8 *inTexel, u32 *outTexel, u32 fract) +static inline void AddTexel(u8* inTexel, u32* outTexel, u32 fract) { - outTexel[0] += inTexel[0] * fract; - outTexel[1] += inTexel[1] * fract; - outTexel[2] += inTexel[2] * fract; - outTexel[3] += inTexel[3] * fract; + outTexel[0] += inTexel[0] * fract; + outTexel[1] += inTexel[1] * fract; + outTexel[2] += inTexel[2] * fract; + outTexel[3] += inTexel[3] * fract; } -void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8 *sample) +void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8* sample) { - int baseMip = 0; - bool mipLinear = false; + int baseMip = 0; + bool mipLinear = false; #if (ALLOW_MIPMAP) - FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1]; - TexMode0& tm0 = texUnit.texMode0[texmap & 3]; + FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1]; + TexMode0& tm0 = texUnit.texMode0[texmap & 3]; - s32 lodFract = lod & 0xf; + s32 lodFract = lod & 0xf; - if (lod > 0 && SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0)) - { - // use mipmap - baseMip = lod >> 4; - mipLinear = (lodFract && tm0.min_filter & TexMode0::TEXF_LINEAR); + if (lod > 0 && SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0)) + { + // use mipmap + baseMip = lod >> 4; + mipLinear = (lodFract && tm0.min_filter & TexMode0::TEXF_LINEAR); - // if using nearest mip filter and lodFract >= 0.5 round up to next mip - baseMip += (lodFract >> 3) & (tm0.min_filter & TexMode0::TEXF_POINT); - } + // if using nearest mip filter and lodFract >= 0.5 round up to next mip + baseMip += (lodFract >> 3) & (tm0.min_filter & TexMode0::TEXF_POINT); + } - if (mipLinear) - { - u8 sampledTex[4]; - u32 texel[4]; + if (mipLinear) + { + u8 sampledTex[4]; + u32 texel[4]; - SampleMip(s, t, baseMip, linear, texmap, sampledTex); - SetTexel(sampledTex, texel, (16 - lodFract)); + SampleMip(s, t, baseMip, linear, texmap, sampledTex); + SetTexel(sampledTex, texel, (16 - lodFract)); - SampleMip(s, t, baseMip + 1, linear, texmap, sampledTex); - AddTexel(sampledTex, texel, lodFract); + SampleMip(s, t, baseMip + 1, linear, texmap, sampledTex); + AddTexel(sampledTex, texel, lodFract); - sample[0] = (u8)(texel[0] >> 4); - sample[1] = (u8)(texel[1] >> 4); - sample[2] = (u8)(texel[2] >> 4); - sample[3] = (u8)(texel[3] >> 4); - } - else + sample[0] = (u8)(texel[0] >> 4); + sample[1] = (u8)(texel[1] >> 4); + sample[2] = (u8)(texel[2] >> 4); + sample[3] = (u8)(texel[3] >> 4); + } + else #endif - { - SampleMip(s, t, baseMip, linear, texmap, sample); - } + { + SampleMip(s, t, baseMip, linear, texmap, sample); + } } -void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8 *sample) +void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8* sample) { - FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1]; - u8 subTexmap = texmap & 3; + FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1]; + u8 subTexmap = texmap & 3; - TexMode0& tm0 = texUnit.texMode0[subTexmap]; - TexImage0& ti0 = texUnit.texImage0[subTexmap]; - TexTLUT& texTlut = texUnit.texTlut[subTexmap]; - TlutFormat tlutfmt = (TlutFormat) texTlut.tlut_format; + TexMode0& tm0 = texUnit.texMode0[subTexmap]; + TexImage0& ti0 = texUnit.texImage0[subTexmap]; + TexTLUT& texTlut = texUnit.texTlut[subTexmap]; + TlutFormat tlutfmt = (TlutFormat)texTlut.tlut_format; - u8 *imageSrc, *imageSrcOdd = nullptr; - if (texUnit.texImage1[subTexmap].image_type) - { - imageSrc = &texMem[texUnit.texImage1[subTexmap].tmem_even * TMEM_LINE_SIZE]; - if (ti0.format == GX_TF_RGBA8) - imageSrcOdd = &texMem[texUnit.texImage2[subTexmap].tmem_odd * TMEM_LINE_SIZE]; - } - else - { - u32 imageBase = texUnit.texImage3[subTexmap].image_base << 5; - imageSrc = Memory::GetPointer(imageBase); - } + u8 *imageSrc, *imageSrcOdd = nullptr; + if (texUnit.texImage1[subTexmap].image_type) + { + imageSrc = &texMem[texUnit.texImage1[subTexmap].tmem_even * TMEM_LINE_SIZE]; + if (ti0.format == GX_TF_RGBA8) + imageSrcOdd = &texMem[texUnit.texImage2[subTexmap].tmem_odd * TMEM_LINE_SIZE]; + } + else + { + u32 imageBase = texUnit.texImage3[subTexmap].image_base << 5; + imageSrc = Memory::GetPointer(imageBase); + } - int imageWidth = ti0.width; - int imageHeight = ti0.height; + int imageWidth = ti0.width; + int imageHeight = ti0.height; - int tlutAddress = texTlut.tmem_offset << 9; - const u8* tlut = &texMem[tlutAddress]; + int tlutAddress = texTlut.tmem_offset << 9; + const u8* tlut = &texMem[tlutAddress]; - // reduce sample location and texture size to mip level - // move texture pointer to mip location - if (mip) - { - int mipWidth = imageWidth + 1; - int mipHeight = imageHeight + 1; + // reduce sample location and texture size to mip level + // move texture pointer to mip location + if (mip) + { + int mipWidth = imageWidth + 1; + int mipHeight = imageHeight + 1; - int fmtWidth = TexDecoder_GetBlockWidthInTexels(ti0.format); - int fmtHeight = TexDecoder_GetBlockHeightInTexels(ti0.format); - int fmtDepth = TexDecoder_GetTexelSizeInNibbles(ti0.format); + int fmtWidth = TexDecoder_GetBlockWidthInTexels(ti0.format); + int fmtHeight = TexDecoder_GetBlockHeightInTexels(ti0.format); + int fmtDepth = TexDecoder_GetTexelSizeInNibbles(ti0.format); - imageWidth >>= mip; - imageHeight >>= mip; - s >>= mip; - t >>= mip; + imageWidth >>= mip; + imageHeight >>= mip; + s >>= mip; + t >>= mip; - while (mip) - { - mipWidth = std::max(mipWidth, fmtWidth); - mipHeight = std::max(mipHeight, fmtHeight); - u32 size = (mipWidth * mipHeight * fmtDepth) >> 1; + while (mip) + { + mipWidth = std::max(mipWidth, fmtWidth); + mipHeight = std::max(mipHeight, fmtHeight); + u32 size = (mipWidth * mipHeight * fmtDepth) >> 1; - imageSrc += size; - mipWidth >>= 1; - mipHeight >>= 1; - mip--; - } - } + imageSrc += size; + mipWidth >>= 1; + mipHeight >>= 1; + mip--; + } + } - if (linear) - { - // offset linear sampling - s -= 64; - t -= 64; + if (linear) + { + // offset linear sampling + s -= 64; + t -= 64; - // integer part of sample location - int imageS = s >> 7; - int imageT = t >> 7; + // integer part of sample location + int imageS = s >> 7; + int imageT = t >> 7; - // linear sampling - int imageSPlus1 = imageS + 1; - int fractS = s & 0x7f; + // linear sampling + int imageSPlus1 = imageS + 1; + int fractS = s & 0x7f; - int imageTPlus1 = imageT + 1; - int fractT = t & 0x7f; + int imageTPlus1 = imageT + 1; + int fractT = t & 0x7f; - u8 sampledTex[4]; - u32 texel[4]; + u8 sampledTex[4]; + u32 texel[4]; - WrapCoord(&imageS, tm0.wrap_s, imageWidth); - WrapCoord(&imageT, tm0.wrap_t, imageHeight); - WrapCoord(&imageSPlus1, tm0.wrap_s, imageWidth); - WrapCoord(&imageTPlus1, tm0.wrap_t, imageHeight); + WrapCoord(&imageS, tm0.wrap_s, imageWidth); + WrapCoord(&imageT, tm0.wrap_t, imageHeight); + WrapCoord(&imageSPlus1, tm0.wrap_s, imageWidth); + WrapCoord(&imageTPlus1, tm0.wrap_t, imageHeight); - if (!(ti0.format == GX_TF_RGBA8 && texUnit.texImage1[subTexmap].image_type)) - { - TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageT, imageWidth, ti0.format, tlut, tlutfmt); - SetTexel(sampledTex, texel, (128 - fractS) * (128 - fractT)); + if (!(ti0.format == GX_TF_RGBA8 && texUnit.texImage1[subTexmap].image_type)) + { + TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageT, imageWidth, ti0.format, tlut, + tlutfmt); + SetTexel(sampledTex, texel, (128 - fractS) * (128 - fractT)); - TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageT, imageWidth, ti0.format, tlut, tlutfmt); - AddTexel(sampledTex, texel, (fractS) * (128 - fractT)); + TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageT, imageWidth, ti0.format, + tlut, tlutfmt); + AddTexel(sampledTex, texel, (fractS) * (128 - fractT)); - TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageTPlus1, imageWidth, ti0.format, tlut, tlutfmt); - AddTexel(sampledTex, texel, (128 - fractS) * (fractT)); + TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageTPlus1, imageWidth, ti0.format, + tlut, tlutfmt); + AddTexel(sampledTex, texel, (128 - fractS) * (fractT)); - TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageTPlus1, imageWidth, ti0.format, tlut, tlutfmt); - AddTexel(sampledTex, texel, (fractS) * (fractT)); - } - else - { - TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageS, imageT, imageWidth); - SetTexel(sampledTex, texel, (128 - fractS) * (128 - fractT)); + TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageTPlus1, imageWidth, ti0.format, + tlut, tlutfmt); + AddTexel(sampledTex, texel, (fractS) * (fractT)); + } + else + { + TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageS, imageT, + imageWidth); + SetTexel(sampledTex, texel, (128 - fractS) * (128 - fractT)); - TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageSPlus1, imageT, imageWidth); - AddTexel(sampledTex, texel, (fractS) * (128 - fractT)); + TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageSPlus1, imageT, + imageWidth); + AddTexel(sampledTex, texel, (fractS) * (128 - fractT)); - TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageS, imageTPlus1, imageWidth); - AddTexel(sampledTex, texel, (128 - fractS) * (fractT)); + TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageS, imageTPlus1, + imageWidth); + AddTexel(sampledTex, texel, (128 - fractS) * (fractT)); - TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageSPlus1, imageTPlus1, imageWidth); - AddTexel(sampledTex, texel, (fractS) * (fractT)); - } + TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageSPlus1, + imageTPlus1, imageWidth); + AddTexel(sampledTex, texel, (fractS) * (fractT)); + } - sample[0] = (u8)(texel[0] >> 14); - sample[1] = (u8)(texel[1] >> 14); - sample[2] = (u8)(texel[2] >> 14); - sample[3] = (u8)(texel[3] >> 14); - } - else - { - // integer part of sample location - int imageS = s >> 7; - int imageT = t >> 7; + sample[0] = (u8)(texel[0] >> 14); + sample[1] = (u8)(texel[1] >> 14); + sample[2] = (u8)(texel[2] >> 14); + sample[3] = (u8)(texel[3] >> 14); + } + else + { + // integer part of sample location + int imageS = s >> 7; + int imageT = t >> 7; - // nearest neighbor sampling - WrapCoord(&imageS, tm0.wrap_s, imageWidth); - WrapCoord(&imageT, tm0.wrap_t, imageHeight); + // nearest neighbor sampling + WrapCoord(&imageS, tm0.wrap_s, imageWidth); + WrapCoord(&imageT, tm0.wrap_t, imageHeight); - if (!(ti0.format == GX_TF_RGBA8 && texUnit.texImage1[subTexmap].image_type)) - TexDecoder_DecodeTexel(sample, imageSrc, imageS, imageT, imageWidth, ti0.format, tlut, tlutfmt); - else - TexDecoder_DecodeTexelRGBA8FromTmem(sample, imageSrc, imageSrcOdd, imageS, imageT, imageWidth); - } + if (!(ti0.format == GX_TF_RGBA8 && texUnit.texImage1[subTexmap].image_type)) + TexDecoder_DecodeTexel(sample, imageSrc, imageS, imageT, imageWidth, ti0.format, tlut, + tlutfmt); + else + TexDecoder_DecodeTexelRGBA8FromTmem(sample, imageSrc, imageSrcOdd, imageS, imageT, + imageWidth); + } } - } diff --git a/Source/Core/VideoBackends/Software/TextureSampler.h b/Source/Core/VideoBackends/Software/TextureSampler.h index bd6a69766b..a7e8a136f5 100644 --- a/Source/Core/VideoBackends/Software/TextureSampler.h +++ b/Source/Core/VideoBackends/Software/TextureSampler.h @@ -8,15 +8,15 @@ namespace TextureSampler { - void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8 *sample); +void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8* sample); - void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8 *sample); +void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8* sample); - enum - { - RED_SMP, - GRN_SMP, - BLU_SMP, - ALP_SMP - }; +enum +{ + RED_SMP, + GRN_SMP, + BLU_SMP, + ALP_SMP +}; } diff --git a/Source/Core/VideoBackends/Software/TransformUnit.cpp b/Source/Core/VideoBackends/Software/TransformUnit.cpp index ab75964c24..57492cc326 100644 --- a/Source/Core/VideoBackends/Software/TransformUnit.cpp +++ b/Source/Core/VideoBackends/Software/TransformUnit.cpp @@ -17,419 +17,424 @@ namespace TransformUnit { - -static void MultiplyVec2Mat24(const Vec3 &vec, const float *mat, Vec3 &result) +static void MultiplyVec2Mat24(const Vec3& vec, const float* mat, Vec3& result) { - result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] + mat[3]; - result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] + mat[7]; - result.z = 1.0f; + result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] + mat[3]; + result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] + mat[7]; + result.z = 1.0f; } -static void MultiplyVec2Mat34(const Vec3 &vec, const float *mat, Vec3 &result) +static void MultiplyVec2Mat34(const Vec3& vec, const float* mat, Vec3& result) { - result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] + mat[3]; - result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] + mat[7]; - result.z = mat[8] * vec.x + mat[9] * vec.y + mat[10] + mat[11]; + result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] + mat[3]; + result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] + mat[7]; + result.z = mat[8] * vec.x + mat[9] * vec.y + mat[10] + mat[11]; } -static void MultiplyVec3Mat33(const Vec3 &vec, const float *mat, Vec3 &result) +static void MultiplyVec3Mat33(const Vec3& vec, const float* mat, Vec3& result) { - result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z; - result.y = mat[3] * vec.x + mat[4] * vec.y + mat[5] * vec.z; - result.z = mat[6] * vec.x + mat[7] * vec.y + mat[8] * vec.z; + result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z; + result.y = mat[3] * vec.x + mat[4] * vec.y + mat[5] * vec.z; + result.z = mat[6] * vec.x + mat[7] * vec.y + mat[8] * vec.z; } -static void MultiplyVec3Mat24(const Vec3 &vec, const float *mat, Vec3 &result) +static void MultiplyVec3Mat24(const Vec3& vec, const float* mat, Vec3& result) { - result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z + mat[3]; - result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] * vec.z + mat[7]; - result.z = 1.0f; + result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z + mat[3]; + result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] * vec.z + mat[7]; + result.z = 1.0f; } -static void MultiplyVec3Mat34(const Vec3 &vec, const float *mat, Vec3 &result) +static void MultiplyVec3Mat34(const Vec3& vec, const float* mat, Vec3& result) { - result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z + mat[3]; - result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] * vec.z + mat[7]; - result.z = mat[8] * vec.x + mat[9] * vec.y + mat[10] * vec.z + mat[11]; + result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z + mat[3]; + result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] * vec.z + mat[7]; + result.z = mat[8] * vec.x + mat[9] * vec.y + mat[10] * vec.z + mat[11]; } -static void MultipleVec3Perspective(const Vec3 &vec, const float *proj, Vec4 &result) +static void MultipleVec3Perspective(const Vec3& vec, const float* proj, Vec4& result) { - result.x = proj[0] * vec.x + proj[1] * vec.z; - result.y = proj[2] * vec.y + proj[3] * vec.z; - //result.z = (proj[4] * vec.z + proj[5]); - result.z = (proj[4] * vec.z + proj[5]) * (1.0f - (float)1e-7); - result.w = -vec.z; + result.x = proj[0] * vec.x + proj[1] * vec.z; + result.y = proj[2] * vec.y + proj[3] * vec.z; + // result.z = (proj[4] * vec.z + proj[5]); + result.z = (proj[4] * vec.z + proj[5]) * (1.0f - (float)1e-7); + result.w = -vec.z; } -static void MultipleVec3Ortho(const Vec3 &vec, const float *proj, Vec4 &result) +static void MultipleVec3Ortho(const Vec3& vec, const float* proj, Vec4& result) { - result.x = proj[0] * vec.x + proj[1]; - result.y = proj[2] * vec.y + proj[3]; - result.z = proj[4] * vec.z + proj[5]; - result.w = 1; + result.x = proj[0] * vec.x + proj[1]; + result.y = proj[2] * vec.y + proj[3]; + result.z = proj[4] * vec.z + proj[5]; + result.w = 1; } -void TransformPosition(const InputVertexData *src, OutputVertexData *dst) +void TransformPosition(const InputVertexData* src, OutputVertexData* dst) { - const float* mat = &xfmem.posMatrices[src->posMtx * 4]; - MultiplyVec3Mat34(src->position, mat, dst->mvPosition); + const float* mat = &xfmem.posMatrices[src->posMtx * 4]; + MultiplyVec3Mat34(src->position, mat, dst->mvPosition); - if (xfmem.projection.type == GX_PERSPECTIVE) - { - MultipleVec3Perspective(dst->mvPosition, xfmem.projection.rawProjection, dst->projectedPosition); - } - else - { - MultipleVec3Ortho(dst->mvPosition, xfmem.projection.rawProjection, dst->projectedPosition); - } + if (xfmem.projection.type == GX_PERSPECTIVE) + { + MultipleVec3Perspective(dst->mvPosition, xfmem.projection.rawProjection, + dst->projectedPosition); + } + else + { + MultipleVec3Ortho(dst->mvPosition, xfmem.projection.rawProjection, dst->projectedPosition); + } } -void TransformNormal(const InputVertexData *src, bool nbt, OutputVertexData *dst) +void TransformNormal(const InputVertexData* src, bool nbt, OutputVertexData* dst) { - const float* mat = &xfmem.normalMatrices[(src->posMtx & 31) * 3]; + const float* mat = &xfmem.normalMatrices[(src->posMtx & 31) * 3]; - if (nbt) - { - MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]); - MultiplyVec3Mat33(src->normal[1], mat, dst->normal[1]); - MultiplyVec3Mat33(src->normal[2], mat, dst->normal[2]); - dst->normal[0].Normalize(); - } - else - { - MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]); - dst->normal[0].Normalize(); - } + if (nbt) + { + MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]); + MultiplyVec3Mat33(src->normal[1], mat, dst->normal[1]); + MultiplyVec3Mat33(src->normal[2], mat, dst->normal[2]); + dst->normal[0].Normalize(); + } + else + { + MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]); + dst->normal[0].Normalize(); + } } -static void TransformTexCoordRegular(const TexMtxInfo &texinfo, int coordNum, bool specialCase, const InputVertexData *srcVertex, OutputVertexData *dstVertex) +static void TransformTexCoordRegular(const TexMtxInfo& texinfo, int coordNum, bool specialCase, + const InputVertexData* srcVertex, OutputVertexData* dstVertex) { - const Vec3 *src; - switch (texinfo.sourcerow) - { - case XF_SRCGEOM_INROW: - src = &srcVertex->position; - break; - case XF_SRCNORMAL_INROW: - src = &srcVertex->normal[0]; - break; - case XF_SRCBINORMAL_T_INROW: - src = &srcVertex->normal[1]; - break; - case XF_SRCBINORMAL_B_INROW: - src = &srcVertex->normal[2]; - break; - default: - _assert_(texinfo.sourcerow >= XF_SRCTEX0_INROW && texinfo.sourcerow <= XF_SRCTEX7_INROW); - src = (Vec3*)srcVertex->texCoords[texinfo.sourcerow - XF_SRCTEX0_INROW]; - break; - } + const Vec3* src; + switch (texinfo.sourcerow) + { + case XF_SRCGEOM_INROW: + src = &srcVertex->position; + break; + case XF_SRCNORMAL_INROW: + src = &srcVertex->normal[0]; + break; + case XF_SRCBINORMAL_T_INROW: + src = &srcVertex->normal[1]; + break; + case XF_SRCBINORMAL_B_INROW: + src = &srcVertex->normal[2]; + break; + default: + _assert_(texinfo.sourcerow >= XF_SRCTEX0_INROW && texinfo.sourcerow <= XF_SRCTEX7_INROW); + src = (Vec3*)srcVertex->texCoords[texinfo.sourcerow - XF_SRCTEX0_INROW]; + break; + } - const float* mat = &xfmem.posMatrices[srcVertex->texMtx[coordNum] * 4]; - Vec3* dst = &dstVertex->texCoords[coordNum]; + const float* mat = &xfmem.posMatrices[srcVertex->texMtx[coordNum] * 4]; + Vec3* dst = &dstVertex->texCoords[coordNum]; - if (texinfo.projection == XF_TEXPROJ_ST) - { - if (texinfo.inputform == XF_TEXINPUT_AB11 || specialCase) - MultiplyVec2Mat24(*src, mat, *dst); - else - MultiplyVec3Mat24(*src, mat, *dst); - } - else // texinfo.projection == XF_TEXPROJ_STQ - { - _assert_(!specialCase); + if (texinfo.projection == XF_TEXPROJ_ST) + { + if (texinfo.inputform == XF_TEXINPUT_AB11 || specialCase) + MultiplyVec2Mat24(*src, mat, *dst); + else + MultiplyVec3Mat24(*src, mat, *dst); + } + else // texinfo.projection == XF_TEXPROJ_STQ + { + _assert_(!specialCase); - if (texinfo.inputform == XF_TEXINPUT_AB11) - MultiplyVec2Mat34(*src, mat, *dst); - else - MultiplyVec3Mat34(*src, mat, *dst); - } + if (texinfo.inputform == XF_TEXINPUT_AB11) + MultiplyVec2Mat34(*src, mat, *dst); + else + MultiplyVec3Mat34(*src, mat, *dst); + } - if (xfmem.dualTexTrans.enabled) - { - Vec3 tempCoord; + if (xfmem.dualTexTrans.enabled) + { + Vec3 tempCoord; - // normalize - const PostMtxInfo &postInfo = xfmem.postMtxInfo[coordNum]; - const float* postMat = &xfmem.postMatrices[postInfo.index * 4]; + // normalize + const PostMtxInfo& postInfo = xfmem.postMtxInfo[coordNum]; + const float* postMat = &xfmem.postMatrices[postInfo.index * 4]; - if (specialCase) - { - // no normalization - // q of input is 1 - // q of output is unknown - tempCoord.x = dst->x; - tempCoord.y = dst->y; + if (specialCase) + { + // no normalization + // q of input is 1 + // q of output is unknown + tempCoord.x = dst->x; + tempCoord.y = dst->y; - dst->x = postMat[0] * tempCoord.x + postMat[1] * tempCoord.y + postMat[2] + postMat[3]; - dst->y = postMat[4] * tempCoord.x + postMat[5] * tempCoord.y + postMat[6] + postMat[7]; - dst->z = 1.0f; - } - else - { - if (postInfo.normalize) - tempCoord = dst->Normalized(); - else - tempCoord = *dst; + dst->x = postMat[0] * tempCoord.x + postMat[1] * tempCoord.y + postMat[2] + postMat[3]; + dst->y = postMat[4] * tempCoord.x + postMat[5] * tempCoord.y + postMat[6] + postMat[7]; + dst->z = 1.0f; + } + else + { + if (postInfo.normalize) + tempCoord = dst->Normalized(); + else + tempCoord = *dst; - MultiplyVec3Mat34(tempCoord, postMat, *dst); - } - } + MultiplyVec3Mat34(tempCoord, postMat, *dst); + } + } } struct LightPointer { - u32 reserved[3]; - u8 color[4]; - Vec3 cosatt; - Vec3 distatt; - Vec3 pos; - Vec3 dir; + u32 reserved[3]; + u8 color[4]; + Vec3 cosatt; + Vec3 distatt; + Vec3 pos; + Vec3 dir; }; -static inline void AddScaledIntegerColor(const u8 *src, float scale, Vec3 &dst) +static inline void AddScaledIntegerColor(const u8* src, float scale, Vec3& dst) { - dst.x += src[1] * scale; - dst.y += src[2] * scale; - dst.z += src[3] * scale; + dst.x += src[1] * scale; + dst.y += src[2] * scale; + dst.z += src[3] * scale; } static inline float SafeDivide(float n, float d) { - return (d==0) ? (n>0?1:0) : n/d; + return (d == 0) ? (n > 0 ? 1 : 0) : n / d; } -static float CalculateLightAttn(const LightPointer *light, Vec3* _ldir, const Vec3 &normal, const LitChannel &chan) +static float CalculateLightAttn(const LightPointer* light, Vec3* _ldir, const Vec3& normal, + const LitChannel& chan) { - float attn = 1.0f; - Vec3& ldir = *_ldir; + float attn = 1.0f; + Vec3& ldir = *_ldir; - switch (chan.attnfunc) - { - case LIGHTATTN_NONE: - case LIGHTATTN_DIR: - { - ldir = ldir.Normalized(); - if (ldir == Vec3(0.0f, 0.0f, 0.0f)) - ldir = normal; - break; - } - case LIGHTATTN_SPEC: - { - ldir = ldir.Normalized(); - attn = (ldir * normal) >= 0.0 ? std::max(0.0f, light->dir * normal) : 0; - Vec3 attLen = Vec3(1.0, attn, attn*attn); - Vec3 cosAttn = light->cosatt; - Vec3 distAttn = light->distatt; - if (chan.diffusefunc != LIGHTDIF_NONE) - distAttn = distAttn.Normalized(); + switch (chan.attnfunc) + { + case LIGHTATTN_NONE: + case LIGHTATTN_DIR: + { + ldir = ldir.Normalized(); + if (ldir == Vec3(0.0f, 0.0f, 0.0f)) + ldir = normal; + break; + } + case LIGHTATTN_SPEC: + { + ldir = ldir.Normalized(); + attn = (ldir * normal) >= 0.0 ? std::max(0.0f, light->dir * normal) : 0; + Vec3 attLen = Vec3(1.0, attn, attn * attn); + Vec3 cosAttn = light->cosatt; + Vec3 distAttn = light->distatt; + if (chan.diffusefunc != LIGHTDIF_NONE) + distAttn = distAttn.Normalized(); - attn = SafeDivide(std::max(0.0f, attLen * cosAttn), attLen * distAttn); - break; - } - case LIGHTATTN_SPOT: - { - float dist2 = ldir.Length2(); - float dist = sqrtf(dist2); - ldir = ldir / dist; - attn = std::max(0.0f, ldir * light->dir); + attn = SafeDivide(std::max(0.0f, attLen * cosAttn), attLen * distAttn); + break; + } + case LIGHTATTN_SPOT: + { + float dist2 = ldir.Length2(); + float dist = sqrtf(dist2); + ldir = ldir / dist; + attn = std::max(0.0f, ldir * light->dir); - float cosAtt = light->cosatt.x + (light->cosatt.y * attn) + (light->cosatt.z * attn * attn); - float distAtt = light->distatt.x + (light->distatt.y * dist) + (light->distatt.z * dist2); - attn = SafeDivide(std::max(0.0f, cosAtt), distAtt); - break; - } - default: - PanicAlert("LightColor"); - } + float cosAtt = light->cosatt.x + (light->cosatt.y * attn) + (light->cosatt.z * attn * attn); + float distAtt = light->distatt.x + (light->distatt.y * dist) + (light->distatt.z * dist2); + attn = SafeDivide(std::max(0.0f, cosAtt), distAtt); + break; + } + default: + PanicAlert("LightColor"); + } - return attn; + return attn; } -static void LightColor(const Vec3 &pos, const Vec3 &normal, u8 lightNum, LitChannel &chan, Vec3 &lightCol) +static void LightColor(const Vec3& pos, const Vec3& normal, u8 lightNum, LitChannel& chan, + Vec3& lightCol) { - const LightPointer *light = (const LightPointer*)&xfmem.lights[lightNum]; + const LightPointer* light = (const LightPointer*)&xfmem.lights[lightNum]; - Vec3 ldir = light->pos - pos; - float attn = CalculateLightAttn(light, &ldir, normal, chan); + Vec3 ldir = light->pos - pos; + float attn = CalculateLightAttn(light, &ldir, normal, chan); - float difAttn = ldir * normal; - switch (chan.diffusefunc) - { - case LIGHTDIF_NONE: - AddScaledIntegerColor(light->color, attn, lightCol); - break; - case LIGHTDIF_SIGN: - AddScaledIntegerColor(light->color, attn * difAttn, lightCol); - break; - case LIGHTDIF_CLAMP: - difAttn = std::max(0.0f, difAttn); - AddScaledIntegerColor(light->color, attn * difAttn, lightCol); - break; - default: _assert_(0); - } + float difAttn = ldir * normal; + switch (chan.diffusefunc) + { + case LIGHTDIF_NONE: + AddScaledIntegerColor(light->color, attn, lightCol); + break; + case LIGHTDIF_SIGN: + AddScaledIntegerColor(light->color, attn * difAttn, lightCol); + break; + case LIGHTDIF_CLAMP: + difAttn = std::max(0.0f, difAttn); + AddScaledIntegerColor(light->color, attn * difAttn, lightCol); + break; + default: + _assert_(0); + } } -static void LightAlpha(const Vec3 &pos, const Vec3 &normal, u8 lightNum, const LitChannel &chan, float &lightCol) +static void LightAlpha(const Vec3& pos, const Vec3& normal, u8 lightNum, const LitChannel& chan, + float& lightCol) { - const LightPointer *light = (const LightPointer*)&xfmem.lights[lightNum]; + const LightPointer* light = (const LightPointer*)&xfmem.lights[lightNum]; - Vec3 ldir = light->pos - pos; - float attn = CalculateLightAttn(light, &ldir, normal, chan); + Vec3 ldir = light->pos - pos; + float attn = CalculateLightAttn(light, &ldir, normal, chan); - float difAttn = ldir * normal; - switch (chan.diffusefunc) - { - case LIGHTDIF_NONE: - lightCol += light->color[0] * attn; - break; - case LIGHTDIF_SIGN: - lightCol += light->color[0] * attn * difAttn; - break; - case LIGHTDIF_CLAMP: - difAttn = std::max(0.0f, difAttn); - lightCol += light->color[0] * attn * difAttn; - break; - default: _assert_(0); - } + float difAttn = ldir * normal; + switch (chan.diffusefunc) + { + case LIGHTDIF_NONE: + lightCol += light->color[0] * attn; + break; + case LIGHTDIF_SIGN: + lightCol += light->color[0] * attn * difAttn; + break; + case LIGHTDIF_CLAMP: + difAttn = std::max(0.0f, difAttn); + lightCol += light->color[0] * attn * difAttn; + break; + default: + _assert_(0); + } } -void TransformColor(const InputVertexData *src, OutputVertexData *dst) +void TransformColor(const InputVertexData* src, OutputVertexData* dst) { - for (u32 chan = 0; chan < xfmem.numChan.numColorChans; chan++) - { - // abgr - u8 matcolor[4]; - u8 chancolor[4]; + for (u32 chan = 0; chan < xfmem.numChan.numColorChans; chan++) + { + // abgr + u8 matcolor[4]; + u8 chancolor[4]; - // color - LitChannel &colorchan = xfmem.color[chan]; - if (colorchan.matsource) - *(u32*)matcolor = *(u32*)src->color[chan]; // vertex - else - *(u32*)matcolor = xfmem.matColor[chan]; + // color + LitChannel& colorchan = xfmem.color[chan]; + if (colorchan.matsource) + *(u32*)matcolor = *(u32*)src->color[chan]; // vertex + else + *(u32*)matcolor = xfmem.matColor[chan]; - if (colorchan.enablelighting) - { - Vec3 lightCol; - if (colorchan.ambsource) - { - // vertex - lightCol.x = src->color[chan][1]; - lightCol.y = src->color[chan][2]; - lightCol.z = src->color[chan][3]; - } - else - { - u8 *ambColor = (u8*)&xfmem.ambColor[chan]; - lightCol.x = ambColor[1]; - lightCol.y = ambColor[2]; - lightCol.z = ambColor[3]; - } + if (colorchan.enablelighting) + { + Vec3 lightCol; + if (colorchan.ambsource) + { + // vertex + lightCol.x = src->color[chan][1]; + lightCol.y = src->color[chan][2]; + lightCol.z = src->color[chan][3]; + } + else + { + u8* ambColor = (u8*)&xfmem.ambColor[chan]; + lightCol.x = ambColor[1]; + lightCol.y = ambColor[2]; + lightCol.z = ambColor[3]; + } - u8 mask = colorchan.GetFullLightMask(); - for (int i = 0; i < 8; ++i) - { - if (mask&(1<mvPosition, dst->normal[0], i, colorchan, lightCol); - } + u8 mask = colorchan.GetFullLightMask(); + for (int i = 0; i < 8; ++i) + { + if (mask & (1 << i)) + LightColor(dst->mvPosition, dst->normal[0], i, colorchan, lightCol); + } - int light_x = MathUtil::Clamp(static_cast(lightCol.x), 0, 255); - int light_y = MathUtil::Clamp(static_cast(lightCol.y), 0, 255); - int light_z = MathUtil::Clamp(static_cast(lightCol.z), 0, 255); - chancolor[1] = (matcolor[1] * (light_x + (light_x >> 7))) >> 8; - chancolor[2] = (matcolor[2] * (light_y + (light_y >> 7))) >> 8; - chancolor[3] = (matcolor[3] * (light_z + (light_z >> 7))) >> 8; - } - else - { - *(u32*)chancolor = *(u32*)matcolor; - } + int light_x = MathUtil::Clamp(static_cast(lightCol.x), 0, 255); + int light_y = MathUtil::Clamp(static_cast(lightCol.y), 0, 255); + int light_z = MathUtil::Clamp(static_cast(lightCol.z), 0, 255); + chancolor[1] = (matcolor[1] * (light_x + (light_x >> 7))) >> 8; + chancolor[2] = (matcolor[2] * (light_y + (light_y >> 7))) >> 8; + chancolor[3] = (matcolor[3] * (light_z + (light_z >> 7))) >> 8; + } + else + { + *(u32*)chancolor = *(u32*)matcolor; + } - // alpha - LitChannel &alphachan = xfmem.alpha[chan]; - if (alphachan.matsource) - matcolor[0] = src->color[chan][0]; // vertex - else - matcolor[0] = xfmem.matColor[chan] & 0xff; + // alpha + LitChannel& alphachan = xfmem.alpha[chan]; + if (alphachan.matsource) + matcolor[0] = src->color[chan][0]; // vertex + else + matcolor[0] = xfmem.matColor[chan] & 0xff; - if (xfmem.alpha[chan].enablelighting) - { - float lightCol; - if (alphachan.ambsource) - lightCol = src->color[chan][0]; // vertex - else - lightCol = (float)(xfmem.ambColor[chan] & 0xff); + if (xfmem.alpha[chan].enablelighting) + { + float lightCol; + if (alphachan.ambsource) + lightCol = src->color[chan][0]; // vertex + else + lightCol = (float)(xfmem.ambColor[chan] & 0xff); - u8 mask = alphachan.GetFullLightMask(); - for (int i = 0; i < 8; ++i) - { - if (mask&(1<mvPosition, dst->normal[0], i, alphachan, lightCol); - } + u8 mask = alphachan.GetFullLightMask(); + for (int i = 0; i < 8; ++i) + { + if (mask & (1 << i)) + LightAlpha(dst->mvPosition, dst->normal[0], i, alphachan, lightCol); + } - int light_a = MathUtil::Clamp(static_cast(lightCol), 0, 255); - chancolor[0] = (matcolor[0] * (light_a + (light_a >> 7))) >> 8; - } - else - { - chancolor[0] = matcolor[0]; - } + int light_a = MathUtil::Clamp(static_cast(lightCol), 0, 255); + chancolor[0] = (matcolor[0] * (light_a + (light_a >> 7))) >> 8; + } + else + { + chancolor[0] = matcolor[0]; + } - // abgr -> rgba - *(u32*)dst->color[chan] = Common::swap32(*(u32*)chancolor); - } + // abgr -> rgba + *(u32*)dst->color[chan] = Common::swap32(*(u32*)chancolor); + } } -void TransformTexCoord(const InputVertexData *src, OutputVertexData *dst, bool specialCase) +void TransformTexCoord(const InputVertexData* src, OutputVertexData* dst, bool specialCase) { - for (u32 coordNum = 0; coordNum < xfmem.numTexGen.numTexGens; coordNum++) - { - const TexMtxInfo &texinfo = xfmem.texMtxInfo[coordNum]; + for (u32 coordNum = 0; coordNum < xfmem.numTexGen.numTexGens; coordNum++) + { + const TexMtxInfo& texinfo = xfmem.texMtxInfo[coordNum]; - switch (texinfo.texgentype) - { - case XF_TEXGEN_REGULAR: - TransformTexCoordRegular(texinfo, coordNum, specialCase, src, dst); - break; - case XF_TEXGEN_EMBOSS_MAP: - { - const LightPointer *light = (const LightPointer*)&xfmem.lights[texinfo.embosslightshift]; + switch (texinfo.texgentype) + { + case XF_TEXGEN_REGULAR: + TransformTexCoordRegular(texinfo, coordNum, specialCase, src, dst); + break; + case XF_TEXGEN_EMBOSS_MAP: + { + const LightPointer* light = (const LightPointer*)&xfmem.lights[texinfo.embosslightshift]; - Vec3 ldir = (light->pos - dst->mvPosition).Normalized(); - float d1 = ldir * dst->normal[1]; - float d2 = ldir * dst->normal[2]; + Vec3 ldir = (light->pos - dst->mvPosition).Normalized(); + float d1 = ldir * dst->normal[1]; + float d2 = ldir * dst->normal[2]; - dst->texCoords[coordNum].x = dst->texCoords[texinfo.embosssourceshift].x + d1; - dst->texCoords[coordNum].y = dst->texCoords[texinfo.embosssourceshift].y + d2; - dst->texCoords[coordNum].z = dst->texCoords[texinfo.embosssourceshift].z; - } - break; - case XF_TEXGEN_COLOR_STRGBC0: - _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW); - _assert_(texinfo.inputform == XF_TEXINPUT_AB11); - dst->texCoords[coordNum].x = (float)dst->color[0][0] / 255.0f; - dst->texCoords[coordNum].y = (float)dst->color[0][1] / 255.0f; - dst->texCoords[coordNum].z = 1.0f; - break; - case XF_TEXGEN_COLOR_STRGBC1: - _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW); - _assert_(texinfo.inputform == XF_TEXINPUT_AB11); - dst->texCoords[coordNum].x = (float)dst->color[1][0] / 255.0f; - dst->texCoords[coordNum].y = (float)dst->color[1][1] / 255.0f; - dst->texCoords[coordNum].z = 1.0f; - break; - default: - ERROR_LOG(VIDEO, "Bad tex gen type %i", texinfo.texgentype); - } - } + dst->texCoords[coordNum].x = dst->texCoords[texinfo.embosssourceshift].x + d1; + dst->texCoords[coordNum].y = dst->texCoords[texinfo.embosssourceshift].y + d2; + dst->texCoords[coordNum].z = dst->texCoords[texinfo.embosssourceshift].z; + } + break; + case XF_TEXGEN_COLOR_STRGBC0: + _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW); + _assert_(texinfo.inputform == XF_TEXINPUT_AB11); + dst->texCoords[coordNum].x = (float)dst->color[0][0] / 255.0f; + dst->texCoords[coordNum].y = (float)dst->color[0][1] / 255.0f; + dst->texCoords[coordNum].z = 1.0f; + break; + case XF_TEXGEN_COLOR_STRGBC1: + _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW); + _assert_(texinfo.inputform == XF_TEXINPUT_AB11); + dst->texCoords[coordNum].x = (float)dst->color[1][0] / 255.0f; + dst->texCoords[coordNum].y = (float)dst->color[1][1] / 255.0f; + dst->texCoords[coordNum].z = 1.0f; + break; + default: + ERROR_LOG(VIDEO, "Bad tex gen type %i", texinfo.texgentype); + } + } - for (u32 coordNum = 0; coordNum < xfmem.numTexGen.numTexGens; coordNum++) - { - dst->texCoords[coordNum][0] *= (bpmem.texcoords[coordNum].s.scale_minus_1 + 1); - dst->texCoords[coordNum][1] *= (bpmem.texcoords[coordNum].t.scale_minus_1 + 1); - } + for (u32 coordNum = 0; coordNum < xfmem.numTexGen.numTexGens; coordNum++) + { + dst->texCoords[coordNum][0] *= (bpmem.texcoords[coordNum].s.scale_minus_1 + 1); + dst->texCoords[coordNum][1] *= (bpmem.texcoords[coordNum].t.scale_minus_1 + 1); + } } - } diff --git a/Source/Core/VideoBackends/Software/TransformUnit.h b/Source/Core/VideoBackends/Software/TransformUnit.h index fa62b0586f..fea42c8104 100644 --- a/Source/Core/VideoBackends/Software/TransformUnit.h +++ b/Source/Core/VideoBackends/Software/TransformUnit.h @@ -9,8 +9,8 @@ struct OutputVertexData; namespace TransformUnit { - void TransformPosition(const InputVertexData *src, OutputVertexData *dst); - void TransformNormal(const InputVertexData *src, bool nbt, OutputVertexData *dst); - void TransformColor(const InputVertexData *src, OutputVertexData *dst); - void TransformTexCoord(const InputVertexData *src, OutputVertexData *dst, bool specialCase); +void TransformPosition(const InputVertexData* src, OutputVertexData* dst); +void TransformNormal(const InputVertexData* src, bool nbt, OutputVertexData* dst); +void TransformColor(const InputVertexData* src, OutputVertexData* dst); +void TransformTexCoord(const InputVertexData* src, OutputVertexData* dst, bool specialCase); } diff --git a/Source/Core/VideoBackends/Software/Vec3.h b/Source/Core/VideoBackends/Software/Vec3.h index f6c806847e..51fc435f4d 100644 --- a/Source/Core/VideoBackends/Software/Vec3.h +++ b/Source/Core/VideoBackends/Software/Vec3.h @@ -12,151 +12,76 @@ class Vec3 { public: - float x, y, z; + float x, y, z; - Vec3() - { - } + Vec3() {} + explicit Vec3(float f) { x = y = z = f; } + explicit Vec3(const float* f) + { + x = f[0]; + y = f[1]; + z = f[2]; + } - explicit Vec3(float f) - { - x = y = z = f; - } + Vec3(const float _x, const float _y, const float _z) + { + x = _x; + y = _y; + z = _z; + } - explicit Vec3(const float *f) - { - x = f[0]; - y = f[1]; - z = f[2]; - } + void set(const float _x, const float _y, const float _z) + { + x = _x; + y = _y; + z = _z; + } - Vec3(const float _x, const float _y, const float _z) - { - x = _x; - y = _y; - z = _z; - } + Vec3 operator+(const Vec3& other) const { return Vec3(x + other.x, y + other.y, z + other.z); } + void operator+=(const Vec3& other) + { + x += other.x; + y += other.y; + z += other.z; + } - void set(const float _x, const float _y, const float _z) - { - x = _x; - y = _y; - z = _z; - } + Vec3 operator-(const Vec3& v) const { return Vec3(x - v.x, y - v.y, z - v.z); } + void operator-=(const Vec3& other) + { + x -= other.x; + y -= other.y; + z -= other.z; + } - Vec3 operator+(const Vec3 &other) const - { - return Vec3(x + other.x, y + other.y, z + other.z); - } + Vec3 operator-() const { return Vec3(-x, -y, -z); } + Vec3 operator*(const float f) const { return Vec3(x * f, y * f, z * f); } + Vec3 operator/(const float f) const + { + float invf = (1.0f / f); + return Vec3(x * invf, y * invf, z * invf); + } - void operator+=(const Vec3 &other) - { - x += other.x; - y += other.y; - z += other.z; - } + void operator/=(const float f) { *this = *this / f; } + float operator*(const Vec3& other) const { return (x * other.x) + (y * other.y) + (z * other.z); } + void operator*=(const float f) { *this = *this * f; } + Vec3 ScaledBy(const Vec3& other) const { return Vec3(x * other.x, y * other.y, z * other.z); } + Vec3 operator%(const Vec3& v) const + { + return Vec3((y * v.z) - (z * v.y), (z * v.x) - (x * v.z), (x * v.y) - (y * v.x)); + } - Vec3 operator-(const Vec3 &v) const - { - return Vec3(x - v.x, y - v.y, z - v.z); - } - - void operator-=(const Vec3 &other) - { - x -= other.x; - y -= other.y; - z -= other.z; - } - - Vec3 operator-() const - { - return Vec3(-x, -y, -z); - } - - Vec3 operator*(const float f) const - { - return Vec3(x * f, y * f, z * f); - } - - Vec3 operator/(const float f) const - { - float invf = (1.0f / f); - return Vec3(x * invf, y * invf, z * invf); - } - - void operator/=(const float f) - { - *this = *this / f; - } - - float operator*(const Vec3 &other) const - { - return (x * other.x) + - (y * other.y) + - (z * other.z); - } - - void operator*=(const float f) - { - *this = *this * f; - } - - Vec3 ScaledBy(const Vec3 &other) const - { - return Vec3(x * other.x, y * other.y, z * other.z); - } - - Vec3 operator%(const Vec3 &v) const - { - return Vec3((y * v.z) - (z * v.y), - (z * v.x) - (x * v.z), - (x * v.y) - (y * v.x)); - } - - float Length2() const - { - return (x * x) + (y * y) + (z * z); - } - - float Length() const - { - return sqrtf(Length2()); - } - - float Distance2To(Vec3 &other) - { - return (other - (*this)).Length2(); - } - - Vec3 Normalized() const - { - return (*this) / Length(); - } - - void Normalize() - { - (*this) /= Length(); - } - - float &operator[](int i) - { - return *((&x) + i); - } - - float operator[](const int i) const - { - return *((&x) + i); - } - - bool operator==(const Vec3 &other) const - { - return x == other.x && y == other.y && z == other.z; - } - - void SetZero() - { - x = 0.0f; - y = 0.0f; - z = 0.0f; - } + float Length2() const { return (x * x) + (y * y) + (z * z); } + float Length() const { return sqrtf(Length2()); } + float Distance2To(Vec3& other) { return (other - (*this)).Length2(); } + Vec3 Normalized() const { return (*this) / Length(); } + void Normalize() { (*this) /= Length(); } + float& operator[](int i) { return *((&x) + i); } + float operator[](const int i) const { return *((&x) + i); } + bool operator==(const Vec3& other) const { return x == other.x && y == other.y && z == other.z; } + void SetZero() + { + x = 0.0f; + y = 0.0f; + z = 0.0f; + } }; diff --git a/Source/Core/VideoBackends/Software/VideoBackend.h b/Source/Core/VideoBackends/Software/VideoBackend.h index c7f5d5c535..efb057d968 100644 --- a/Source/Core/VideoBackends/Software/VideoBackend.h +++ b/Source/Core/VideoBackends/Software/VideoBackend.h @@ -7,25 +7,26 @@ #include #include "VideoCommon/VideoBackendBase.h" -namespace MMIO { class Mapping; } +namespace MMIO +{ +class Mapping; +} namespace SW { - class VideoSoftware : public VideoBackendBase { - bool Initialize(void *window_handle) override; - void Shutdown() override; + bool Initialize(void* window_handle) override; + void Shutdown() override; - std::string GetName() const override; - std::string GetDisplayName() const override; + std::string GetName() const override; + std::string GetDisplayName() const override; - void Video_Prepare() override; - void Video_Cleanup() override; + void Video_Prepare() override; + void Video_Cleanup() override; - void ShowConfig(void* parent) override; + void ShowConfig(void* parent) override; - unsigned int PeekMessages() override; + unsigned int PeekMessages() override; }; - } diff --git a/Source/Core/VideoCommon/AVIDump.cpp b/Source/Core/VideoCommon/AVIDump.cpp index aa6cb9ecbb..eba3da3e32 100644 --- a/Source/Core/VideoCommon/AVIDump.cpp +++ b/Source/Core/VideoCommon/AVIDump.cpp @@ -16,14 +16,14 @@ extern "C" { } #include "Common/FileUtil.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "Core/ConfigManager.h" #include "Core/CoreTiming.h" -#include "Core/Movie.h" #include "Core/HW/SystemTimers.h" -#include "Core/HW/VideoInterface.h" //for TargetRefreshRate +#include "Core/HW/VideoInterface.h" //for TargetRefreshRate +#include "Core/Movie.h" #include "VideoCommon/AVIDump.h" #include "VideoCommon/VideoConfig.h" @@ -48,227 +48,228 @@ static u64 s_last_pts; static void InitAVCodec() { - static bool first_run = true; - if (first_run) - { - av_register_all(); - first_run = false; - } + static bool first_run = true; + if (first_run) + { + av_register_all(); + first_run = false; + } } bool AVIDump::Start(int w, int h, DumpFormat format) { - if (format == DumpFormat::FORMAT_BGR) - s_pix_fmt = AV_PIX_FMT_BGR24; - else - s_pix_fmt = AV_PIX_FMT_RGBA; + if (format == DumpFormat::FORMAT_BGR) + s_pix_fmt = AV_PIX_FMT_BGR24; + else + s_pix_fmt = AV_PIX_FMT_RGBA; - s_width = w; - s_height = h; + s_width = w; + s_height = h; - s_last_frame = CoreTiming::GetTicks(); - s_last_pts = 0; + s_last_frame = CoreTiming::GetTicks(); + s_last_pts = 0; - InitAVCodec(); - bool success = CreateFile(); - if (!success) - CloseFile(); - return success; + InitAVCodec(); + bool success = CreateFile(); + if (!success) + CloseFile(); + return success; } bool AVIDump::CreateFile() { - AVCodec* codec = nullptr; + AVCodec* codec = nullptr; - s_format_context = avformat_alloc_context(); - snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s", - (File::GetUserPath(D_DUMPFRAMES_IDX) + "framedump0.avi").c_str()); - File::CreateFullPath(s_format_context->filename); + s_format_context = avformat_alloc_context(); + snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s", + (File::GetUserPath(D_DUMPFRAMES_IDX) + "framedump0.avi").c_str()); + File::CreateFullPath(s_format_context->filename); - // Ask to delete file - if (File::Exists(s_format_context->filename)) - { - if (SConfig::GetInstance().m_DumpFramesSilent || - AskYesNoT("Delete the existing file '%s'?", s_format_context->filename)) - { - File::Delete(s_format_context->filename); - } - else - { - // Stop and cancel dumping the video - return false; - } - } + // Ask to delete file + if (File::Exists(s_format_context->filename)) + { + if (SConfig::GetInstance().m_DumpFramesSilent || + AskYesNoT("Delete the existing file '%s'?", s_format_context->filename)) + { + File::Delete(s_format_context->filename); + } + else + { + // Stop and cancel dumping the video + return false; + } + } - if (!(s_format_context->oformat = av_guess_format("avi", nullptr, nullptr)) || - !(s_stream = avformat_new_stream(s_format_context, codec))) - { - return false; - } + if (!(s_format_context->oformat = av_guess_format("avi", nullptr, nullptr)) || + !(s_stream = avformat_new_stream(s_format_context, codec))) + { + return false; + } - s_stream->codec->codec_id = g_Config.bUseFFV1 ? AV_CODEC_ID_FFV1 - : s_format_context->oformat->video_codec; - if (!g_Config.bUseFFV1) - s_stream->codec->codec_tag = MKTAG('X', 'V', 'I', 'D'); // Force XVID FourCC for better compatibility - s_stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; - s_stream->codec->bit_rate = 400000; - s_stream->codec->width = s_width; - s_stream->codec->height = s_height; - s_stream->codec->time_base.num = 1; - s_stream->codec->time_base.den = VideoInterface::GetTargetRefreshRate(); - s_stream->codec->gop_size = 12; - s_stream->codec->pix_fmt = g_Config.bUseFFV1 ? AV_PIX_FMT_BGRA : AV_PIX_FMT_YUV420P; + s_stream->codec->codec_id = + g_Config.bUseFFV1 ? AV_CODEC_ID_FFV1 : s_format_context->oformat->video_codec; + if (!g_Config.bUseFFV1) + s_stream->codec->codec_tag = + MKTAG('X', 'V', 'I', 'D'); // Force XVID FourCC for better compatibility + s_stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; + s_stream->codec->bit_rate = 400000; + s_stream->codec->width = s_width; + s_stream->codec->height = s_height; + s_stream->codec->time_base.num = 1; + s_stream->codec->time_base.den = VideoInterface::GetTargetRefreshRate(); + s_stream->codec->gop_size = 12; + s_stream->codec->pix_fmt = g_Config.bUseFFV1 ? AV_PIX_FMT_BGRA : AV_PIX_FMT_YUV420P; - if (!(codec = avcodec_find_encoder(s_stream->codec->codec_id)) || - (avcodec_open2(s_stream->codec, codec, nullptr) < 0)) - { - return false; - } + if (!(codec = avcodec_find_encoder(s_stream->codec->codec_id)) || + (avcodec_open2(s_stream->codec, codec, nullptr) < 0)) + { + return false; + } - s_src_frame = av_frame_alloc(); - s_scaled_frame = av_frame_alloc(); + s_src_frame = av_frame_alloc(); + s_scaled_frame = av_frame_alloc(); - s_size = avpicture_get_size(s_stream->codec->pix_fmt, s_width, s_height); + s_size = avpicture_get_size(s_stream->codec->pix_fmt, s_width, s_height); - s_yuv_buffer = new uint8_t[s_size]; - avpicture_fill((AVPicture*)s_scaled_frame, s_yuv_buffer, s_stream->codec->pix_fmt, s_width, s_height); + s_yuv_buffer = new uint8_t[s_size]; + avpicture_fill((AVPicture*)s_scaled_frame, s_yuv_buffer, s_stream->codec->pix_fmt, s_width, + s_height); - NOTICE_LOG(VIDEO, "Opening file %s for dumping", s_format_context->filename); - if (avio_open(&s_format_context->pb, s_format_context->filename, AVIO_FLAG_WRITE) < 0) - { - WARN_LOG(VIDEO, "Could not open %s", s_format_context->filename); - return false; - } + NOTICE_LOG(VIDEO, "Opening file %s for dumping", s_format_context->filename); + if (avio_open(&s_format_context->pb, s_format_context->filename, AVIO_FLAG_WRITE) < 0) + { + WARN_LOG(VIDEO, "Could not open %s", s_format_context->filename); + return false; + } - avformat_write_header(s_format_context, nullptr); + avformat_write_header(s_format_context, nullptr); - return true; + return true; } static void PreparePacket(AVPacket* pkt) { - av_init_packet(pkt); - pkt->data = nullptr; - pkt->size = 0; + av_init_packet(pkt); + pkt->data = nullptr; + pkt->size = 0; } void AVIDump::AddFrame(const u8* data, int width, int height) { - avpicture_fill((AVPicture*)s_src_frame, const_cast(data), s_pix_fmt, width, height); + avpicture_fill((AVPicture*)s_src_frame, const_cast(data), s_pix_fmt, width, height); - // Convert image from {BGR24, RGBA} to desired pixel format, and scale to initial - // width and height - if ((s_sws_context = sws_getCachedContext(s_sws_context, - width, height, s_pix_fmt, - s_width, s_height, s_stream->codec->pix_fmt, - SWS_BICUBIC, nullptr, nullptr, nullptr))) - { - sws_scale(s_sws_context, s_src_frame->data, s_src_frame->linesize, 0, - height, s_scaled_frame->data, s_scaled_frame->linesize); - } + // Convert image from {BGR24, RGBA} to desired pixel format, and scale to initial + // width and height + if ((s_sws_context = + sws_getCachedContext(s_sws_context, width, height, s_pix_fmt, s_width, s_height, + s_stream->codec->pix_fmt, SWS_BICUBIC, nullptr, nullptr, nullptr))) + { + sws_scale(s_sws_context, s_src_frame->data, s_src_frame->linesize, 0, height, + s_scaled_frame->data, s_scaled_frame->linesize); + } - s_scaled_frame->format = s_stream->codec->pix_fmt; - s_scaled_frame->width = s_width; - s_scaled_frame->height = s_height; + s_scaled_frame->format = s_stream->codec->pix_fmt; + s_scaled_frame->width = s_width; + s_scaled_frame->height = s_height; - // Encode and write the image. - AVPacket pkt; - PreparePacket(&pkt); - int got_packet = 0; - int error = 0; - u64 delta; - s64 last_pts; - // Check to see if the first frame being dumped is the first frame of output from the emulator. - // This prevents an issue with starting dumping later in emulation from placing the frames incorrectly. - if (!s_start_dumping && Movie::g_currentFrame < 1) - { - delta = CoreTiming::GetTicks(); - last_pts = AV_NOPTS_VALUE; - s_start_dumping = true; - } - else - { - delta = CoreTiming::GetTicks() - s_last_frame; - last_pts = (s_last_pts * s_stream->codec->time_base.den) / SystemTimers::GetTicksPerSecond(); - } - u64 pts_in_ticks = s_last_pts + delta; - s_scaled_frame->pts = (pts_in_ticks * s_stream->codec->time_base.den) / SystemTimers::GetTicksPerSecond(); - if (s_scaled_frame->pts != last_pts) - { - s_last_frame = CoreTiming::GetTicks(); - s_last_pts = pts_in_ticks; - error = avcodec_encode_video2(s_stream->codec, &pkt, s_scaled_frame, &got_packet); - } - while (!error && got_packet) - { - // Write the compressed frame in the media file. - if (pkt.pts != (s64)AV_NOPTS_VALUE) - { - pkt.pts = av_rescale_q(pkt.pts, - s_stream->codec->time_base, s_stream->time_base); - } - if (pkt.dts != (s64)AV_NOPTS_VALUE) - { - pkt.dts = av_rescale_q(pkt.dts, - s_stream->codec->time_base, s_stream->time_base); - } + // Encode and write the image. + AVPacket pkt; + PreparePacket(&pkt); + int got_packet = 0; + int error = 0; + u64 delta; + s64 last_pts; + // Check to see if the first frame being dumped is the first frame of output from the emulator. + // This prevents an issue with starting dumping later in emulation from placing the frames + // incorrectly. + if (!s_start_dumping && Movie::g_currentFrame < 1) + { + delta = CoreTiming::GetTicks(); + last_pts = AV_NOPTS_VALUE; + s_start_dumping = true; + } + else + { + delta = CoreTiming::GetTicks() - s_last_frame; + last_pts = (s_last_pts * s_stream->codec->time_base.den) / SystemTimers::GetTicksPerSecond(); + } + u64 pts_in_ticks = s_last_pts + delta; + s_scaled_frame->pts = + (pts_in_ticks * s_stream->codec->time_base.den) / SystemTimers::GetTicksPerSecond(); + if (s_scaled_frame->pts != last_pts) + { + s_last_frame = CoreTiming::GetTicks(); + s_last_pts = pts_in_ticks; + error = avcodec_encode_video2(s_stream->codec, &pkt, s_scaled_frame, &got_packet); + } + while (!error && got_packet) + { + // Write the compressed frame in the media file. + if (pkt.pts != (s64)AV_NOPTS_VALUE) + { + pkt.pts = av_rescale_q(pkt.pts, s_stream->codec->time_base, s_stream->time_base); + } + if (pkt.dts != (s64)AV_NOPTS_VALUE) + { + pkt.dts = av_rescale_q(pkt.dts, s_stream->codec->time_base, s_stream->time_base); + } #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(56, 60, 100) - if (s_stream->codec->coded_frame->key_frame) - pkt.flags |= AV_PKT_FLAG_KEY; + if (s_stream->codec->coded_frame->key_frame) + pkt.flags |= AV_PKT_FLAG_KEY; #endif - pkt.stream_index = s_stream->index; - av_interleaved_write_frame(s_format_context, &pkt); + pkt.stream_index = s_stream->index; + av_interleaved_write_frame(s_format_context, &pkt); - // Handle delayed frames. - PreparePacket(&pkt); - error = avcodec_encode_video2(s_stream->codec, &pkt, nullptr, &got_packet); - } - if (error) - ERROR_LOG(VIDEO, "Error while encoding video: %d", error); + // Handle delayed frames. + PreparePacket(&pkt); + error = avcodec_encode_video2(s_stream->codec, &pkt, nullptr, &got_packet); + } + if (error) + ERROR_LOG(VIDEO, "Error while encoding video: %d", error); } void AVIDump::Stop() { - av_write_trailer(s_format_context); - CloseFile(); - NOTICE_LOG(VIDEO, "Stopping frame dump"); + av_write_trailer(s_format_context); + CloseFile(); + NOTICE_LOG(VIDEO, "Stopping frame dump"); } void AVIDump::CloseFile() { - if (s_stream) - { - if (s_stream->codec) - avcodec_close(s_stream->codec); - av_free(s_stream); - s_stream = nullptr; - } + if (s_stream) + { + if (s_stream->codec) + avcodec_close(s_stream->codec); + av_free(s_stream); + s_stream = nullptr; + } - if (s_yuv_buffer) - { - delete[] s_yuv_buffer; - s_yuv_buffer = nullptr; - } + if (s_yuv_buffer) + { + delete[] s_yuv_buffer; + s_yuv_buffer = nullptr; + } - av_frame_free(&s_src_frame); - av_frame_free(&s_scaled_frame); + av_frame_free(&s_src_frame); + av_frame_free(&s_scaled_frame); - if (s_format_context) - { - if (s_format_context->pb) - avio_close(s_format_context->pb); - av_free(s_format_context); - s_format_context = nullptr; - } + if (s_format_context) + { + if (s_format_context->pb) + avio_close(s_format_context->pb); + av_free(s_format_context); + s_format_context = nullptr; + } - if (s_sws_context) - { - sws_freeContext(s_sws_context); - s_sws_context = nullptr; - } + if (s_sws_context) + { + sws_freeContext(s_sws_context); + s_sws_context = nullptr; + } } void AVIDump::DoState() { - s_last_frame = CoreTiming::GetTicks(); + s_last_frame = CoreTiming::GetTicks(); } diff --git a/Source/Core/VideoCommon/AVIDump.h b/Source/Core/VideoCommon/AVIDump.h index 63fce15112..caac19da43 100644 --- a/Source/Core/VideoCommon/AVIDump.h +++ b/Source/Core/VideoCommon/AVIDump.h @@ -9,18 +9,18 @@ class AVIDump { private: - static bool CreateFile(); - static void CloseFile(); + static bool CreateFile(); + static void CloseFile(); public: - enum class DumpFormat - { - FORMAT_BGR, - FORMAT_RGBA - }; + enum class DumpFormat + { + FORMAT_BGR, + FORMAT_RGBA + }; - static bool Start(int w, int h, DumpFormat format); - static void AddFrame(const u8* data, int width, int height); - static void Stop(); - static void DoState(); + static bool Start(int w, int h, DumpFormat format); + static void AddFrame(const u8* data, int width, int height); + static void Stop(); + static void DoState(); }; diff --git a/Source/Core/VideoCommon/AsyncRequests.cpp b/Source/Core/VideoCommon/AsyncRequests.cpp index 13cbf70937..32f407373b 100644 --- a/Source/Core/VideoCommon/AsyncRequests.cpp +++ b/Source/Core/VideoCommon/AsyncRequests.cpp @@ -12,146 +12,144 @@ AsyncRequests AsyncRequests::s_singleton; -AsyncRequests::AsyncRequests() -: m_enable(false), m_passthrough(true) +AsyncRequests::AsyncRequests() : m_enable(false), m_passthrough(true) { } void AsyncRequests::PullEventsInternal() { - std::unique_lock lock(m_mutex); - m_empty.store(true); + std::unique_lock lock(m_mutex); + m_empty.store(true); - while (!m_queue.empty()) - { - Event e = m_queue.front(); + while (!m_queue.empty()) + { + Event e = m_queue.front(); - // try to merge as many efb pokes as possible - // it's a bit hacky, but some games render a complete frame in this way - if ((e.type == Event::EFB_POKE_COLOR || e.type == Event::EFB_POKE_Z)) - { - m_merged_efb_pokes.clear(); - Event first_event = m_queue.front(); - EFBAccessType t = first_event.type == Event::EFB_POKE_COLOR ? POKE_COLOR : POKE_Z; + // try to merge as many efb pokes as possible + // it's a bit hacky, but some games render a complete frame in this way + if ((e.type == Event::EFB_POKE_COLOR || e.type == Event::EFB_POKE_Z)) + { + m_merged_efb_pokes.clear(); + Event first_event = m_queue.front(); + EFBAccessType t = first_event.type == Event::EFB_POKE_COLOR ? POKE_COLOR : POKE_Z; - do - { - e = m_queue.front(); + do + { + e = m_queue.front(); - EfbPokeData d; - d.data = e.efb_poke.data; - d.x = e.efb_poke.x; - d.y = e.efb_poke.y; - m_merged_efb_pokes.push_back(d); + EfbPokeData d; + d.data = e.efb_poke.data; + d.x = e.efb_poke.x; + d.y = e.efb_poke.y; + m_merged_efb_pokes.push_back(d); - m_queue.pop(); - } while(!m_queue.empty() && m_queue.front().type == first_event.type); + m_queue.pop(); + } while (!m_queue.empty() && m_queue.front().type == first_event.type); - lock.unlock(); - g_renderer->PokeEFB(t, m_merged_efb_pokes.data(), m_merged_efb_pokes.size()); - lock.lock(); - continue; - } + lock.unlock(); + g_renderer->PokeEFB(t, m_merged_efb_pokes.data(), m_merged_efb_pokes.size()); + lock.lock(); + continue; + } - lock.unlock(); - HandleEvent(e); - lock.lock(); + lock.unlock(); + HandleEvent(e); + lock.lock(); - m_queue.pop(); - } + m_queue.pop(); + } - if (m_wake_me_up_again) - { - m_wake_me_up_again = false; - m_cond.notify_all(); - } + if (m_wake_me_up_again) + { + m_wake_me_up_again = false; + m_cond.notify_all(); + } } void AsyncRequests::PushEvent(const AsyncRequests::Event& event, bool blocking) { - std::unique_lock lock(m_mutex); + std::unique_lock lock(m_mutex); - if (m_passthrough) - { - HandleEvent(event); - return; - } + if (m_passthrough) + { + HandleEvent(event); + return; + } - m_empty.store(false); - m_wake_me_up_again |= blocking; + m_empty.store(false); + m_wake_me_up_again |= blocking; - if (!m_enable) - return; + if (!m_enable) + return; - m_queue.push(event); + m_queue.push(event); - Fifo::RunGpu(); - if (blocking) - { - m_cond.wait(lock, [this]{return m_queue.empty();}); - } + Fifo::RunGpu(); + if (blocking) + { + m_cond.wait(lock, [this] { return m_queue.empty(); }); + } } void AsyncRequests::SetEnable(bool enable) { - std::unique_lock lock(m_mutex); - m_enable = enable; + std::unique_lock lock(m_mutex); + m_enable = enable; - if (!enable) - { - // flush the queue on disabling - while (!m_queue.empty()) - m_queue.pop(); - if (m_wake_me_up_again) - m_cond.notify_all(); - } + if (!enable) + { + // flush the queue on disabling + while (!m_queue.empty()) + m_queue.pop(); + if (m_wake_me_up_again) + m_cond.notify_all(); + } } void AsyncRequests::HandleEvent(const AsyncRequests::Event& e) { - EFBRectangle rc; - switch (e.type) - { - case Event::EFB_POKE_COLOR: - { - EfbPokeData poke = { e.efb_poke.x, e.efb_poke.y, e.efb_poke.data }; - g_renderer->PokeEFB(POKE_COLOR, &poke, 1); - } - break; + EFBRectangle rc; + switch (e.type) + { + case Event::EFB_POKE_COLOR: + { + EfbPokeData poke = {e.efb_poke.x, e.efb_poke.y, e.efb_poke.data}; + g_renderer->PokeEFB(POKE_COLOR, &poke, 1); + } + break; - case Event::EFB_POKE_Z: - { - EfbPokeData poke = { e.efb_poke.x, e.efb_poke.y, e.efb_poke.data }; - g_renderer->PokeEFB(POKE_Z, &poke, 1); - } - break; + case Event::EFB_POKE_Z: + { + EfbPokeData poke = {e.efb_poke.x, e.efb_poke.y, e.efb_poke.data}; + g_renderer->PokeEFB(POKE_Z, &poke, 1); + } + break; - case Event::EFB_PEEK_COLOR: - *e.efb_peek.data = g_renderer->AccessEFB(PEEK_COLOR, e.efb_peek.x, e.efb_peek.y, 0); - break; + case Event::EFB_PEEK_COLOR: + *e.efb_peek.data = g_renderer->AccessEFB(PEEK_COLOR, e.efb_peek.x, e.efb_peek.y, 0); + break; - case Event::EFB_PEEK_Z: - *e.efb_peek.data = g_renderer->AccessEFB(PEEK_Z, e.efb_peek.x, e.efb_peek.y, 0); - break; + case Event::EFB_PEEK_Z: + *e.efb_peek.data = g_renderer->AccessEFB(PEEK_Z, e.efb_peek.x, e.efb_peek.y, 0); + break; - case Event::SWAP_EVENT: - Renderer::Swap(e.swap_event.xfbAddr, e.swap_event.fbWidth, e.swap_event.fbStride, e.swap_event.fbHeight, rc); - break; + case Event::SWAP_EVENT: + Renderer::Swap(e.swap_event.xfbAddr, e.swap_event.fbWidth, e.swap_event.fbStride, + e.swap_event.fbHeight, rc); + break; - case Event::BBOX_READ: - *e.bbox.data = g_renderer->BBoxRead(e.bbox.index); - break; + case Event::BBOX_READ: + *e.bbox.data = g_renderer->BBoxRead(e.bbox.index); + break; - case Event::PERF_QUERY: - g_perf_query->FlushResults(); - break; - - } + case Event::PERF_QUERY: + g_perf_query->FlushResults(); + break; + } } void AsyncRequests::SetPassthrough(bool enable) { - std::unique_lock lock(m_mutex); - m_passthrough = enable; + std::unique_lock lock(m_mutex); + m_passthrough = enable; } - diff --git a/Source/Core/VideoCommon/AsyncRequests.h b/Source/Core/VideoCommon/AsyncRequests.h index 6625618dd1..bcf9c1ce7e 100644 --- a/Source/Core/VideoCommon/AsyncRequests.h +++ b/Source/Core/VideoCommon/AsyncRequests.h @@ -17,83 +17,81 @@ struct EfbPokeData; class AsyncRequests { public: - struct Event - { - enum Type - { - EFB_POKE_COLOR, - EFB_POKE_Z, - EFB_PEEK_COLOR, - EFB_PEEK_Z, - SWAP_EVENT, - BBOX_READ, - PERF_QUERY, - } type; - u64 time; + struct Event + { + enum Type + { + EFB_POKE_COLOR, + EFB_POKE_Z, + EFB_PEEK_COLOR, + EFB_PEEK_Z, + SWAP_EVENT, + BBOX_READ, + PERF_QUERY, + } type; + u64 time; - union - { - struct - { - u16 x; - u16 y; - u32 data; - } efb_poke; + union { + struct + { + u16 x; + u16 y; + u32 data; + } efb_poke; - struct - { - u16 x; - u16 y; - u32* data; - } efb_peek; + struct + { + u16 x; + u16 y; + u32* data; + } efb_peek; - struct - { - u32 xfbAddr; - u32 fbWidth; - u32 fbStride; - u32 fbHeight; - } swap_event; + struct + { + u32 xfbAddr; + u32 fbWidth; + u32 fbStride; + u32 fbHeight; + } swap_event; - struct - { - int index; - u16* data; - } bbox; + struct + { + int index; + u16* data; + } bbox; - struct - { - } perf_query; - }; - }; + struct + { + } perf_query; + }; + }; - AsyncRequests(); + AsyncRequests(); - void PullEvents() - { - if (!m_empty.load()) - PullEventsInternal(); - } - void PushEvent(const Event& event, bool blocking = false); - void SetEnable(bool enable); - void SetPassthrough(bool enable); - - static AsyncRequests* GetInstance() { return &s_singleton; } + void PullEvents() + { + if (!m_empty.load()) + PullEventsInternal(); + } + void PushEvent(const Event& event, bool blocking = false); + void SetEnable(bool enable); + void SetPassthrough(bool enable); + static AsyncRequests* GetInstance() { return &s_singleton; } private: - void PullEventsInternal(); - void HandleEvent(const Event& e); + void PullEventsInternal(); + void HandleEvent(const Event& e); - static AsyncRequests s_singleton; + static AsyncRequests s_singleton; - std::atomic m_empty; - std::queue m_queue; - std::mutex m_mutex; - std::condition_variable m_cond; + std::atomic m_empty; + std::queue m_queue; + std::mutex m_mutex; + std::condition_variable m_cond; - bool m_wake_me_up_again; - bool m_enable; - bool m_passthrough; + bool m_wake_me_up_again; + bool m_enable; + bool m_passthrough; - std::vector m_merged_efb_pokes; + std::vector m_merged_efb_pokes; }; diff --git a/Source/Core/VideoCommon/BPFunctions.cpp b/Source/Core/VideoCommon/BPFunctions.cpp index 63b99495e2..d471de9e6f 100644 --- a/Source/Core/VideoCommon/BPFunctions.cpp +++ b/Source/Core/VideoCommon/BPFunctions.cpp @@ -21,219 +21,224 @@ namespace BPFunctions // Reference: Yet Another GameCube Documentation // ---------------------------------------------- - void FlushPipeline() { - VertexManagerBase::Flush(); + VertexManagerBase::Flush(); } void SetGenerationMode() { - g_renderer->SetGenerationMode(); + g_renderer->SetGenerationMode(); } void SetScissor() { - /* NOTE: the minimum value here for the scissor rect and offset is -342. - * GX internally adds on an offset of 342 to both the offset and scissor - * coords to ensure that the register was always unsigned. - * - * The code that was here before tried to "undo" this offset, but - * since we always take the difference, the +342 added to both - * sides cancels out. */ + /* NOTE: the minimum value here for the scissor rect and offset is -342. + * GX internally adds on an offset of 342 to both the offset and scissor + * coords to ensure that the register was always unsigned. + * + * The code that was here before tried to "undo" this offset, but + * since we always take the difference, the +342 added to both + * sides cancels out. */ - /* The scissor offset is always even, so to save space, the scissor offset - * register is scaled down by 2. So, if somebody calls - * GX_SetScissorBoxOffset(20, 20); the registers will be set to 10, 10. */ - const int xoff = bpmem.scissorOffset.x * 2; - const int yoff = bpmem.scissorOffset.y * 2; + /* The scissor offset is always even, so to save space, the scissor offset + * register is scaled down by 2. So, if somebody calls + * GX_SetScissorBoxOffset(20, 20); the registers will be set to 10, 10. */ + const int xoff = bpmem.scissorOffset.x * 2; + const int yoff = bpmem.scissorOffset.y * 2; - EFBRectangle rc (bpmem.scissorTL.x - xoff, bpmem.scissorTL.y - yoff, - bpmem.scissorBR.x - xoff + 1, bpmem.scissorBR.y - yoff + 1); + EFBRectangle rc(bpmem.scissorTL.x - xoff, bpmem.scissorTL.y - yoff, bpmem.scissorBR.x - xoff + 1, + bpmem.scissorBR.y - yoff + 1); - if (rc.left < 0) rc.left = 0; - if (rc.top < 0) rc.top = 0; - if (rc.right > EFB_WIDTH) rc.right = EFB_WIDTH; - if (rc.bottom > EFB_HEIGHT) rc.bottom = EFB_HEIGHT; + if (rc.left < 0) + rc.left = 0; + if (rc.top < 0) + rc.top = 0; + if (rc.right > EFB_WIDTH) + rc.right = EFB_WIDTH; + if (rc.bottom > EFB_HEIGHT) + rc.bottom = EFB_HEIGHT; - if (rc.left > rc.right) rc.right = rc.left; - if (rc.top > rc.bottom) rc.bottom = rc.top; + if (rc.left > rc.right) + rc.right = rc.left; + if (rc.top > rc.bottom) + rc.bottom = rc.top; - g_renderer->SetScissorRect(rc); + g_renderer->SetScissorRect(rc); } void SetDepthMode() { - g_renderer->SetDepthMode(); + g_renderer->SetDepthMode(); } void SetBlendMode() { - g_renderer->SetBlendMode(false); + g_renderer->SetBlendMode(false); } void SetDitherMode() { - g_renderer->SetDitherMode(); + g_renderer->SetDitherMode(); } void SetLogicOpMode() { - g_renderer->SetLogicOpMode(); + g_renderer->SetLogicOpMode(); } void SetColorMask() { - g_renderer->SetColorMask(); + g_renderer->SetColorMask(); } /* Explanation of the magic behind ClearScreen: - There's numerous possible formats for the pixel data in the EFB. - However, in the HW accelerated backends we're always using RGBA8 - for the EFB format, which causes some problems: - - We're using an alpha channel although the game doesn't - - If the actual EFB format is RGBA6_Z24 or R5G6B5_Z16, we are using more bits per channel than the native HW + There's numerous possible formats for the pixel data in the EFB. + However, in the HW accelerated backends we're always using RGBA8 + for the EFB format, which causes some problems: + - We're using an alpha channel although the game doesn't + - If the actual EFB format is RGBA6_Z24 or R5G6B5_Z16, we are using more bits per channel than the + native HW - To properly emulate the above points, we're doing the following: - (1) - - disable alpha channel writing of any kind of rendering if the actual EFB format doesn't use an alpha channel - - NOTE: Always make sure that the EFB has been cleared to an alpha value of 0xFF in this case! - - Same for color channels, these need to be cleared to 0x00 though. - (2) - - convert the RGBA8 color to RGBA6/RGB8/RGB565 and convert it to RGBA8 again - - convert the Z24 depth value to Z16 and back to Z24 + To properly emulate the above points, we're doing the following: + (1) + - disable alpha channel writing of any kind of rendering if the actual EFB format doesn't use an + alpha channel + - NOTE: Always make sure that the EFB has been cleared to an alpha value of 0xFF in this case! + - Same for color channels, these need to be cleared to 0x00 though. + (2) + - convert the RGBA8 color to RGBA6/RGB8/RGB565 and convert it to RGBA8 again + - convert the Z24 depth value to Z16 and back to Z24 */ -void ClearScreen(const EFBRectangle &rc) +void ClearScreen(const EFBRectangle& rc) { - bool colorEnable = (bpmem.blendmode.colorupdate != 0); - bool alphaEnable = (bpmem.blendmode.alphaupdate != 0); - bool zEnable = (bpmem.zmode.updateenable != 0); - auto pixel_format = bpmem.zcontrol.pixel_format; + bool colorEnable = (bpmem.blendmode.colorupdate != 0); + bool alphaEnable = (bpmem.blendmode.alphaupdate != 0); + bool zEnable = (bpmem.zmode.updateenable != 0); + auto pixel_format = bpmem.zcontrol.pixel_format; - // (1): Disable unused color channels - if (pixel_format == PEControl::RGB8_Z24 || - pixel_format == PEControl::RGB565_Z16 || - pixel_format == PEControl::Z24) - { - alphaEnable = false; - } + // (1): Disable unused color channels + if (pixel_format == PEControl::RGB8_Z24 || pixel_format == PEControl::RGB565_Z16 || + pixel_format == PEControl::Z24) + { + alphaEnable = false; + } - if (colorEnable || alphaEnable || zEnable) - { - u32 color = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB; - u32 z = bpmem.clearZValue; + if (colorEnable || alphaEnable || zEnable) + { + u32 color = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB; + u32 z = bpmem.clearZValue; - // (2) drop additional accuracy - if (pixel_format == PEControl::RGBA6_Z24) - { - color = RGBA8ToRGBA6ToRGBA8(color); - } - else if (pixel_format == PEControl::RGB565_Z16) - { - color = RGBA8ToRGB565ToRGBA8(color); - z = Z24ToZ16ToZ24(z); - } - g_renderer->ClearScreen(rc, colorEnable, alphaEnable, zEnable, color, z); - } + // (2) drop additional accuracy + if (pixel_format == PEControl::RGBA6_Z24) + { + color = RGBA8ToRGBA6ToRGBA8(color); + } + else if (pixel_format == PEControl::RGB565_Z16) + { + color = RGBA8ToRGB565ToRGBA8(color); + z = Z24ToZ16ToZ24(z); + } + g_renderer->ClearScreen(rc, colorEnable, alphaEnable, zEnable, color, z); + } } void OnPixelFormatChange() { - int convtype = -1; + int convtype = -1; - // TODO : Check for Z compression format change - // When using 16bit Z, the game may enable a special compression format which we need to handle - // If we don't, Z values will be completely screwed up, currently only Star Wars:RS2 uses that. + // TODO : Check for Z compression format change + // When using 16bit Z, the game may enable a special compression format which we need to handle + // If we don't, Z values will be completely screwed up, currently only Star Wars:RS2 uses that. - /* - * When changing the EFB format, the pixel data won't get converted to the new format but stays the same. - * Since we are always using an RGBA8 buffer though, this causes issues in some games. - * Thus, we reinterpret the old EFB data with the new format here. - */ - if (!g_ActiveConfig.bEFBEmulateFormatChanges) - return; + /* + * When changing the EFB format, the pixel data won't get converted to the new format but stays + * the same. + * Since we are always using an RGBA8 buffer though, this causes issues in some games. + * Thus, we reinterpret the old EFB data with the new format here. + */ + if (!g_ActiveConfig.bEFBEmulateFormatChanges) + return; - auto old_format = Renderer::GetPrevPixelFormat(); - auto new_format = bpmem.zcontrol.pixel_format; + auto old_format = Renderer::GetPrevPixelFormat(); + auto new_format = bpmem.zcontrol.pixel_format; - // no need to reinterpret pixel data in these cases - if (new_format == old_format || old_format == PEControl::INVALID_FMT) - goto skip; + // no need to reinterpret pixel data in these cases + if (new_format == old_format || old_format == PEControl::INVALID_FMT) + goto skip; - // Check for pixel format changes - switch (old_format) - { - case PEControl::RGB8_Z24: - case PEControl::Z24: - // Z24 and RGB8_Z24 are treated equal, so just return in this case - if (new_format == PEControl::RGB8_Z24 || new_format == PEControl::Z24) - goto skip; + // Check for pixel format changes + switch (old_format) + { + case PEControl::RGB8_Z24: + case PEControl::Z24: + // Z24 and RGB8_Z24 are treated equal, so just return in this case + if (new_format == PEControl::RGB8_Z24 || new_format == PEControl::Z24) + goto skip; - if (new_format == PEControl::RGBA6_Z24) - convtype = 0; - else if (new_format == PEControl::RGB565_Z16) - convtype = 1; - break; + if (new_format == PEControl::RGBA6_Z24) + convtype = 0; + else if (new_format == PEControl::RGB565_Z16) + convtype = 1; + break; - case PEControl::RGBA6_Z24: - if (new_format == PEControl::RGB8_Z24 || - new_format == PEControl::Z24) - convtype = 2; - else if (new_format == PEControl::RGB565_Z16) - convtype = 3; - break; + case PEControl::RGBA6_Z24: + if (new_format == PEControl::RGB8_Z24 || new_format == PEControl::Z24) + convtype = 2; + else if (new_format == PEControl::RGB565_Z16) + convtype = 3; + break; - case PEControl::RGB565_Z16: - if (new_format == PEControl::RGB8_Z24 || - new_format == PEControl::Z24) - convtype = 4; - else if (new_format == PEControl::RGBA6_Z24) - convtype = 5; - break; + case PEControl::RGB565_Z16: + if (new_format == PEControl::RGB8_Z24 || new_format == PEControl::Z24) + convtype = 4; + else if (new_format == PEControl::RGBA6_Z24) + convtype = 5; + break; - default: - break; - } + default: + break; + } - if (convtype == -1) - { - ERROR_LOG(VIDEO, "Unhandled EFB format change: %d to %d\n", static_cast(old_format), static_cast(new_format)); - goto skip; - } + if (convtype == -1) + { + ERROR_LOG(VIDEO, "Unhandled EFB format change: %d to %d\n", static_cast(old_format), + static_cast(new_format)); + goto skip; + } - g_renderer->ReinterpretPixelData(convtype); + g_renderer->ReinterpretPixelData(convtype); skip: - DEBUG_LOG(VIDEO, "pixelfmt: pixel=%d, zc=%d", static_cast(new_format), static_cast(bpmem.zcontrol.zformat)); + DEBUG_LOG(VIDEO, "pixelfmt: pixel=%d, zc=%d", static_cast(new_format), + static_cast(bpmem.zcontrol.zformat)); - Renderer::StorePixelFormat(new_format); + Renderer::StorePixelFormat(new_format); } -void SetInterlacingMode(const BPCmd &bp) +void SetInterlacingMode(const BPCmd& bp) { - // TODO - switch (bp.address) - { - case BPMEM_FIELDMODE: - { - // SDK always sets bpmem.lineptwidth.lineaspect via BPMEM_LINEPTWIDTH - // just before this cmd - const char *action[] = { "don't adjust", "adjust" }; - DEBUG_LOG(VIDEO, "BPMEM_FIELDMODE texLOD:%s lineaspect:%s", - action[bpmem.fieldmode.texLOD], - action[bpmem.lineptwidth.lineaspect]); - } - break; - case BPMEM_FIELDMASK: - { - // Determines if fields will be written to EFB (always computed) - const char *action[] = { "skip", "write" }; - DEBUG_LOG(VIDEO, "BPMEM_FIELDMASK even:%s odd:%s", - action[bpmem.fieldmask.even], action[bpmem.fieldmask.odd]); - } - break; - default: - ERROR_LOG(VIDEO, "SetInterlacingMode default"); - break; - } + // TODO + switch (bp.address) + { + case BPMEM_FIELDMODE: + { + // SDK always sets bpmem.lineptwidth.lineaspect via BPMEM_LINEPTWIDTH + // just before this cmd + const char* action[] = {"don't adjust", "adjust"}; + DEBUG_LOG(VIDEO, "BPMEM_FIELDMODE texLOD:%s lineaspect:%s", action[bpmem.fieldmode.texLOD], + action[bpmem.lineptwidth.lineaspect]); + } + break; + case BPMEM_FIELDMASK: + { + // Determines if fields will be written to EFB (always computed) + const char* action[] = {"skip", "write"}; + DEBUG_LOG(VIDEO, "BPMEM_FIELDMASK even:%s odd:%s", action[bpmem.fieldmask.even], + action[bpmem.fieldmask.odd]); + } + break; + default: + ERROR_LOG(VIDEO, "SetInterlacingMode default"); + break; + } } - }; diff --git a/Source/Core/VideoCommon/BPFunctions.h b/Source/Core/VideoCommon/BPFunctions.h index 4d78e9bc87..3208939cc7 100644 --- a/Source/Core/VideoCommon/BPFunctions.h +++ b/Source/Core/VideoCommon/BPFunctions.h @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // ------------------------------------------ // Video backend must define these functions // ------------------------------------------ @@ -15,7 +14,6 @@ struct BPCmd; namespace BPFunctions { - void FlushPipeline(); void SetGenerationMode(); void SetScissor(); @@ -24,7 +22,7 @@ void SetBlendMode(); void SetDitherMode(); void SetLogicOpMode(); void SetColorMask(); -void ClearScreen(const EFBRectangle &rc); +void ClearScreen(const EFBRectangle& rc); void OnPixelFormatChange(); -void SetInterlacingMode(const BPCmd &bp); +void SetInterlacingMode(const BPCmd& bp); } diff --git a/Source/Core/VideoCommon/BPMemory.h b/Source/Core/VideoCommon/BPMemory.h index 0dc2b44212..b823e8163b 100644 --- a/Source/Core/VideoCommon/BPMemory.h +++ b/Source/Core/VideoCommon/BPMemory.h @@ -13,335 +13,327 @@ enum { - BPMEM_GENMODE = 0x00, - BPMEM_DISPLAYCOPYFILTER = 0x01, // 0x01 + 4 - BPMEM_IND_MTXA = 0x06, // 0x06 + (3 * 3) - BPMEM_IND_MTXB = 0x07, // 0x07 + (3 * 3) - BPMEM_IND_MTXC = 0x08, // 0x08 + (3 * 3) - BPMEM_IND_IMASK = 0x0F, - BPMEM_IND_CMD = 0x10, // 0x10 + 16 - BPMEM_SCISSORTL = 0x20, - BPMEM_SCISSORBR = 0x21, - BPMEM_LINEPTWIDTH = 0x22, - BPMEM_PERF0_TRI = 0x23, - BPMEM_PERF0_QUAD = 0x24, - BPMEM_RAS1_SS0 = 0x25, - BPMEM_RAS1_SS1 = 0x26, - BPMEM_IREF = 0x27, - BPMEM_TREF = 0x28, // 0x28 + 8 - BPMEM_SU_SSIZE = 0x30, // 0x30 + (2 * 8) - BPMEM_SU_TSIZE = 0x31, // 0x31 + (2 * 8) - BPMEM_ZMODE = 0x40, - BPMEM_BLENDMODE = 0x41, - BPMEM_CONSTANTALPHA = 0x42, - BPMEM_ZCOMPARE = 0x43, - BPMEM_FIELDMASK = 0x44, - BPMEM_SETDRAWDONE = 0x45, - BPMEM_BUSCLOCK0 = 0x46, - BPMEM_PE_TOKEN_ID = 0x47, - BPMEM_PE_TOKEN_INT_ID = 0x48, - BPMEM_EFB_TL = 0x49, - BPMEM_EFB_BR = 0x4A, - BPMEM_EFB_ADDR = 0x4B, - BPMEM_MIPMAP_STRIDE = 0x4D, - BPMEM_COPYYSCALE = 0x4E, - BPMEM_CLEAR_AR = 0x4F, - BPMEM_CLEAR_GB = 0x50, - BPMEM_CLEAR_Z = 0x51, - BPMEM_TRIGGER_EFB_COPY = 0x52, - BPMEM_COPYFILTER0 = 0x53, - BPMEM_COPYFILTER1 = 0x54, - BPMEM_CLEARBBOX1 = 0x55, - BPMEM_CLEARBBOX2 = 0x56, - BPMEM_CLEAR_PIXEL_PERF = 0x57, - BPMEM_REVBITS = 0x58, - BPMEM_SCISSOROFFSET = 0x59, - BPMEM_PRELOAD_ADDR = 0x60, - BPMEM_PRELOAD_TMEMEVEN = 0x61, - BPMEM_PRELOAD_TMEMODD = 0x62, - BPMEM_PRELOAD_MODE = 0x63, - BPMEM_LOADTLUT0 = 0x64, - BPMEM_LOADTLUT1 = 0x65, - BPMEM_TEXINVALIDATE = 0x66, - BPMEM_PERF1 = 0x67, - BPMEM_FIELDMODE = 0x68, - BPMEM_BUSCLOCK1 = 0x69, - BPMEM_TX_SETMODE0 = 0x80, // 0x80 + 4 - BPMEM_TX_SETMODE1 = 0x84, // 0x84 + 4 - BPMEM_TX_SETIMAGE0 = 0x88, // 0x88 + 4 - BPMEM_TX_SETIMAGE1 = 0x8C, // 0x8C + 4 - BPMEM_TX_SETIMAGE2 = 0x90, // 0x90 + 4 - BPMEM_TX_SETIMAGE3 = 0x94, // 0x94 + 4 - BPMEM_TX_SETTLUT = 0x98, // 0x98 + 4 - BPMEM_TX_SETMODE0_4 = 0xA0, // 0xA0 + 4 - BPMEM_TX_SETMODE1_4 = 0xA4, // 0xA4 + 4 - BPMEM_TX_SETIMAGE0_4 = 0xA8, // 0xA8 + 4 - BPMEM_TX_SETIMAGE1_4 = 0xAC, // 0xA4 + 4 - BPMEM_TX_SETIMAGE2_4 = 0xB0, // 0xB0 + 4 - BPMEM_TX_SETIMAGE3_4 = 0xB4, // 0xB4 + 4 - BPMEM_TX_SETTLUT_4 = 0xB8, // 0xB8 + 4 - BPMEM_TEV_COLOR_ENV = 0xC0, // 0xC0 + (2 * 16) - BPMEM_TEV_ALPHA_ENV = 0xC1, // 0xC1 + (2 * 16) - BPMEM_TEV_COLOR_RA = 0xE0, // 0xE0 + (2 * 4) - BPMEM_TEV_COLOR_BG = 0xE1, // 0xE1 + (2 * 4) - BPMEM_FOGRANGE = 0xE8, // 0xE8 + 6 - BPMEM_FOGPARAM0 = 0xEE, - BPMEM_FOGBMAGNITUDE = 0xEF, - BPMEM_FOGBEXPONENT = 0xF0, - BPMEM_FOGPARAM3 = 0xF1, - BPMEM_FOGCOLOR = 0xF2, - BPMEM_ALPHACOMPARE = 0xF3, - BPMEM_BIAS = 0xF4, - BPMEM_ZTEX2 = 0xF5, - BPMEM_TEV_KSEL = 0xF6, // 0xF6 + 8 - BPMEM_BP_MASK = 0xFE, + BPMEM_GENMODE = 0x00, + BPMEM_DISPLAYCOPYFILTER = 0x01, // 0x01 + 4 + BPMEM_IND_MTXA = 0x06, // 0x06 + (3 * 3) + BPMEM_IND_MTXB = 0x07, // 0x07 + (3 * 3) + BPMEM_IND_MTXC = 0x08, // 0x08 + (3 * 3) + BPMEM_IND_IMASK = 0x0F, + BPMEM_IND_CMD = 0x10, // 0x10 + 16 + BPMEM_SCISSORTL = 0x20, + BPMEM_SCISSORBR = 0x21, + BPMEM_LINEPTWIDTH = 0x22, + BPMEM_PERF0_TRI = 0x23, + BPMEM_PERF0_QUAD = 0x24, + BPMEM_RAS1_SS0 = 0x25, + BPMEM_RAS1_SS1 = 0x26, + BPMEM_IREF = 0x27, + BPMEM_TREF = 0x28, // 0x28 + 8 + BPMEM_SU_SSIZE = 0x30, // 0x30 + (2 * 8) + BPMEM_SU_TSIZE = 0x31, // 0x31 + (2 * 8) + BPMEM_ZMODE = 0x40, + BPMEM_BLENDMODE = 0x41, + BPMEM_CONSTANTALPHA = 0x42, + BPMEM_ZCOMPARE = 0x43, + BPMEM_FIELDMASK = 0x44, + BPMEM_SETDRAWDONE = 0x45, + BPMEM_BUSCLOCK0 = 0x46, + BPMEM_PE_TOKEN_ID = 0x47, + BPMEM_PE_TOKEN_INT_ID = 0x48, + BPMEM_EFB_TL = 0x49, + BPMEM_EFB_BR = 0x4A, + BPMEM_EFB_ADDR = 0x4B, + BPMEM_MIPMAP_STRIDE = 0x4D, + BPMEM_COPYYSCALE = 0x4E, + BPMEM_CLEAR_AR = 0x4F, + BPMEM_CLEAR_GB = 0x50, + BPMEM_CLEAR_Z = 0x51, + BPMEM_TRIGGER_EFB_COPY = 0x52, + BPMEM_COPYFILTER0 = 0x53, + BPMEM_COPYFILTER1 = 0x54, + BPMEM_CLEARBBOX1 = 0x55, + BPMEM_CLEARBBOX2 = 0x56, + BPMEM_CLEAR_PIXEL_PERF = 0x57, + BPMEM_REVBITS = 0x58, + BPMEM_SCISSOROFFSET = 0x59, + BPMEM_PRELOAD_ADDR = 0x60, + BPMEM_PRELOAD_TMEMEVEN = 0x61, + BPMEM_PRELOAD_TMEMODD = 0x62, + BPMEM_PRELOAD_MODE = 0x63, + BPMEM_LOADTLUT0 = 0x64, + BPMEM_LOADTLUT1 = 0x65, + BPMEM_TEXINVALIDATE = 0x66, + BPMEM_PERF1 = 0x67, + BPMEM_FIELDMODE = 0x68, + BPMEM_BUSCLOCK1 = 0x69, + BPMEM_TX_SETMODE0 = 0x80, // 0x80 + 4 + BPMEM_TX_SETMODE1 = 0x84, // 0x84 + 4 + BPMEM_TX_SETIMAGE0 = 0x88, // 0x88 + 4 + BPMEM_TX_SETIMAGE1 = 0x8C, // 0x8C + 4 + BPMEM_TX_SETIMAGE2 = 0x90, // 0x90 + 4 + BPMEM_TX_SETIMAGE3 = 0x94, // 0x94 + 4 + BPMEM_TX_SETTLUT = 0x98, // 0x98 + 4 + BPMEM_TX_SETMODE0_4 = 0xA0, // 0xA0 + 4 + BPMEM_TX_SETMODE1_4 = 0xA4, // 0xA4 + 4 + BPMEM_TX_SETIMAGE0_4 = 0xA8, // 0xA8 + 4 + BPMEM_TX_SETIMAGE1_4 = 0xAC, // 0xA4 + 4 + BPMEM_TX_SETIMAGE2_4 = 0xB0, // 0xB0 + 4 + BPMEM_TX_SETIMAGE3_4 = 0xB4, // 0xB4 + 4 + BPMEM_TX_SETTLUT_4 = 0xB8, // 0xB8 + 4 + BPMEM_TEV_COLOR_ENV = 0xC0, // 0xC0 + (2 * 16) + BPMEM_TEV_ALPHA_ENV = 0xC1, // 0xC1 + (2 * 16) + BPMEM_TEV_COLOR_RA = 0xE0, // 0xE0 + (2 * 4) + BPMEM_TEV_COLOR_BG = 0xE1, // 0xE1 + (2 * 4) + BPMEM_FOGRANGE = 0xE8, // 0xE8 + 6 + BPMEM_FOGPARAM0 = 0xEE, + BPMEM_FOGBMAGNITUDE = 0xEF, + BPMEM_FOGBEXPONENT = 0xF0, + BPMEM_FOGPARAM3 = 0xF1, + BPMEM_FOGCOLOR = 0xF2, + BPMEM_ALPHACOMPARE = 0xF3, + BPMEM_BIAS = 0xF4, + BPMEM_ZTEX2 = 0xF5, + BPMEM_TEV_KSEL = 0xF6, // 0xF6 + 8 + BPMEM_BP_MASK = 0xFE, }; - // Tev/combiner things // TEV scaling type enum : u32 { - TEVSCALE_1 = 0, - TEVSCALE_2 = 1, - TEVSCALE_4 = 2, - TEVDIVIDE_2 = 3 + TEVSCALE_1 = 0, + TEVSCALE_2 = 1, + TEVSCALE_4 = 2, + TEVDIVIDE_2 = 3 }; enum : u32 { - TEVCMP_R8 = 0, - TEVCMP_GR16 = 1, - TEVCMP_BGR24 = 2, - TEVCMP_RGB8 = 3 + TEVCMP_R8 = 0, + TEVCMP_GR16 = 1, + TEVCMP_BGR24 = 2, + TEVCMP_RGB8 = 3 }; // TEV combiner operator enum : u32 { - TEVOP_ADD = 0, - TEVOP_SUB = 1, - TEVCMP_R8_GT = 8, - TEVCMP_R8_EQ = 9, - TEVCMP_GR16_GT = 10, - TEVCMP_GR16_EQ = 11, - TEVCMP_BGR24_GT = 12, - TEVCMP_BGR24_EQ = 13, - TEVCMP_RGB8_GT = 14, - TEVCMP_RGB8_EQ = 15, - TEVCMP_A8_GT = TEVCMP_RGB8_GT, - TEVCMP_A8_EQ = TEVCMP_RGB8_EQ + TEVOP_ADD = 0, + TEVOP_SUB = 1, + TEVCMP_R8_GT = 8, + TEVCMP_R8_EQ = 9, + TEVCMP_GR16_GT = 10, + TEVCMP_GR16_EQ = 11, + TEVCMP_BGR24_GT = 12, + TEVCMP_BGR24_EQ = 13, + TEVCMP_RGB8_GT = 14, + TEVCMP_RGB8_EQ = 15, + TEVCMP_A8_GT = TEVCMP_RGB8_GT, + TEVCMP_A8_EQ = TEVCMP_RGB8_EQ }; // TEV color combiner input enum : u32 { - TEVCOLORARG_CPREV = 0, - TEVCOLORARG_APREV = 1, - TEVCOLORARG_C0 = 2, - TEVCOLORARG_A0 = 3, - TEVCOLORARG_C1 = 4, - TEVCOLORARG_A1 = 5, - TEVCOLORARG_C2 = 6, - TEVCOLORARG_A2 = 7, - TEVCOLORARG_TEXC = 8, - TEVCOLORARG_TEXA = 9, - TEVCOLORARG_RASC = 10, - TEVCOLORARG_RASA = 11, - TEVCOLORARG_ONE = 12, - TEVCOLORARG_HALF = 13, - TEVCOLORARG_KONST = 14, - TEVCOLORARG_ZERO = 15 + TEVCOLORARG_CPREV = 0, + TEVCOLORARG_APREV = 1, + TEVCOLORARG_C0 = 2, + TEVCOLORARG_A0 = 3, + TEVCOLORARG_C1 = 4, + TEVCOLORARG_A1 = 5, + TEVCOLORARG_C2 = 6, + TEVCOLORARG_A2 = 7, + TEVCOLORARG_TEXC = 8, + TEVCOLORARG_TEXA = 9, + TEVCOLORARG_RASC = 10, + TEVCOLORARG_RASA = 11, + TEVCOLORARG_ONE = 12, + TEVCOLORARG_HALF = 13, + TEVCOLORARG_KONST = 14, + TEVCOLORARG_ZERO = 15 }; // TEV alpha combiner input enum : u32 { - TEVALPHAARG_APREV = 0, - TEVALPHAARG_A0 = 1, - TEVALPHAARG_A1 = 2, - TEVALPHAARG_A2 = 3, - TEVALPHAARG_TEXA = 4, - TEVALPHAARG_RASA = 5, - TEVALPHAARG_KONST = 6, - TEVALPHAARG_ZERO = 7 + TEVALPHAARG_APREV = 0, + TEVALPHAARG_A0 = 1, + TEVALPHAARG_A1 = 2, + TEVALPHAARG_A2 = 3, + TEVALPHAARG_TEXA = 4, + TEVALPHAARG_RASA = 5, + TEVALPHAARG_KONST = 6, + TEVALPHAARG_ZERO = 7 }; // TEV output registers enum : u32 { - GX_TEVPREV = 0, - GX_TEVREG0 = 1, - GX_TEVREG1 = 2, - GX_TEVREG2 = 3 + GX_TEVPREV = 0, + GX_TEVREG0 = 1, + GX_TEVREG1 = 2, + GX_TEVREG2 = 3 }; // Z-texture formats enum : u32 { - TEV_ZTEX_TYPE_U8 = 0, - TEV_ZTEX_TYPE_U16 = 1, - TEV_ZTEX_TYPE_U24 = 2 + TEV_ZTEX_TYPE_U8 = 0, + TEV_ZTEX_TYPE_U16 = 1, + TEV_ZTEX_TYPE_U24 = 2 }; // Z texture operator enum : u32 { - ZTEXTURE_DISABLE = 0, - ZTEXTURE_ADD = 1, - ZTEXTURE_REPLACE = 2 + ZTEXTURE_DISABLE = 0, + ZTEXTURE_ADD = 1, + ZTEXTURE_REPLACE = 2 }; // TEV bias value enum : u32 { - TEVBIAS_ZERO = 0, - TEVBIAS_ADDHALF = 1, - TEVBIAS_SUBHALF = 2, - TEVBIAS_COMPARE = 3 + TEVBIAS_ZERO = 0, + TEVBIAS_ADDHALF = 1, + TEVBIAS_SUBHALF = 2, + TEVBIAS_COMPARE = 3 }; // Indirect texture format enum : u32 { - ITF_8 = 0, - ITF_5 = 1, - ITF_4 = 2, - ITF_3 = 3 + ITF_8 = 0, + ITF_5 = 1, + ITF_4 = 2, + ITF_3 = 3 }; // Indirect texture bias enum : u32 { - ITB_NONE = 0, - ITB_S = 1, - ITB_T = 2, - ITB_ST = 3, - ITB_U = 4, - ITB_SU = 5, - ITB_TU = 6, - ITB_STU = 7 + ITB_NONE = 0, + ITB_S = 1, + ITB_T = 2, + ITB_ST = 3, + ITB_U = 4, + ITB_SU = 5, + ITB_TU = 6, + ITB_STU = 7 }; // Indirect texture bump alpha enum : u32 { - ITBA_OFF = 0, - ITBA_S = 1, - ITBA_T = 2, - ITBA_U = 3 + ITBA_OFF = 0, + ITBA_S = 1, + ITBA_T = 2, + ITBA_U = 3 }; // Indirect texture wrap value enum : u32 { - ITW_OFF = 0, - ITW_256 = 1, - ITW_128 = 2, - ITW_64 = 3, - ITW_32 = 4, - ITW_16 = 5, - ITW_0 = 6 + ITW_OFF = 0, + ITW_256 = 1, + ITW_128 = 2, + ITW_64 = 3, + ITW_32 = 4, + ITW_16 = 5, + ITW_0 = 6 }; -union IND_MTXA -{ - struct - { - s32 ma : 11; - s32 mb : 11; - u32 s0 : 2; // bits 0-1 of scale factor - u32 rid : 8; - }; - u32 hex; +union IND_MTXA { + struct + { + s32 ma : 11; + s32 mb : 11; + u32 s0 : 2; // bits 0-1 of scale factor + u32 rid : 8; + }; + u32 hex; }; -union IND_MTXB -{ - struct - { - s32 mc : 11; - s32 md : 11; - u32 s1 : 2; // bits 2-3 of scale factor - u32 rid : 8; - }; - u32 hex; +union IND_MTXB { + struct + { + s32 mc : 11; + s32 md : 11; + u32 s1 : 2; // bits 2-3 of scale factor + u32 rid : 8; + }; + u32 hex; }; -union IND_MTXC -{ - struct - { - s32 me : 11; - s32 mf : 11; - u32 s2 : 2; // bits 4-5 of scale factor - u32 rid : 8; - }; - u32 hex; +union IND_MTXC { + struct + { + s32 me : 11; + s32 mf : 11; + u32 s2 : 2; // bits 4-5 of scale factor + u32 rid : 8; + }; + u32 hex; }; struct IND_MTX { - IND_MTXA col0; - IND_MTXB col1; - IND_MTXC col2; + IND_MTXA col0; + IND_MTXB col1; + IND_MTXC col2; }; -union IND_IMASK -{ - struct - { - u32 mask : 24; - u32 rid : 8; - }; - u32 hex; +union IND_IMASK { + struct + { + u32 mask : 24; + u32 rid : 8; + }; + u32 hex; }; struct TevStageCombiner { - union ColorCombiner - { - struct //abc=8bit,d=10bit - { - u32 d : 4; // TEVSELCC_X - u32 c : 4; // TEVSELCC_X - u32 b : 4; // TEVSELCC_X - u32 a : 4; // TEVSELCC_X + union ColorCombiner { + struct // abc=8bit,d=10bit + { + u32 d : 4; // TEVSELCC_X + u32 c : 4; // TEVSELCC_X + u32 b : 4; // TEVSELCC_X + u32 a : 4; // TEVSELCC_X - u32 bias : 2; - u32 op : 1; - u32 clamp : 1; + u32 bias : 2; + u32 op : 1; + u32 clamp : 1; - u32 shift : 2; - u32 dest : 2; //1,2,3 + u32 shift : 2; + u32 dest : 2; // 1,2,3 + }; + u32 hex; + }; + union AlphaCombiner { + struct + { + u32 rswap : 2; + u32 tswap : 2; + u32 d : 3; // TEVSELCA_ + u32 c : 3; // TEVSELCA_ + u32 b : 3; // TEVSELCA_ + u32 a : 3; // TEVSELCA_ - }; - u32 hex; - }; - union AlphaCombiner - { - struct - { - u32 rswap : 2; - u32 tswap : 2; - u32 d : 3; // TEVSELCA_ - u32 c : 3; // TEVSELCA_ - u32 b : 3; // TEVSELCA_ - u32 a : 3; // TEVSELCA_ + u32 bias : 2; // GXTevBias + u32 op : 1; + u32 clamp : 1; - u32 bias : 2; //GXTevBias - u32 op : 1; - u32 clamp : 1; + u32 shift : 2; + u32 dest : 2; // 1,2,3 + }; + u32 hex; + }; - u32 shift : 2; - u32 dest : 2; //1,2,3 - }; - u32 hex; - }; - - ColorCombiner colorC; - AlphaCombiner alphaC; + ColorCombiner colorC; + AlphaCombiner alphaC; }; // several discoveries: @@ -353,763 +345,734 @@ struct TevStageCombiner // GXSetTevIndirect(tevstage+1, indstage, 0, 3, realmat+4, 6, 6, 1, 0, 0) // GXSetTevIndirect(tevstage+2, indstage, 0, 0, 0, 0, 0, 1, 0, 0) - union TevStageIndirect - { - struct - { - u32 bt : 2; // Indirect tex stage ID - u32 fmt : 2; // Format: ITF_X - u32 bias : 3; // ITB_X - u32 bs : 2; // ITBA_X, indicates which coordinate will become the 'bump alpha' - u32 mid : 4; // Matrix ID to multiply offsets with - u32 sw : 3; // ITW_X, wrapping factor for S of regular coord - u32 tw : 3; // ITW_X, wrapping factor for T of regular coord - u32 lb_utclod : 1; // Use modified or unmodified texture coordinates for LOD computation - u32 fb_addprev : 1; // 1 if the texture coordinate results from the previous TEV stage should be added - u32 pad0 : 3; - u32 rid : 8; - }; - struct - { - u32 hex : 21; - u32 unused : 11; - }; +union TevStageIndirect { + struct + { + u32 bt : 2; // Indirect tex stage ID + u32 fmt : 2; // Format: ITF_X + u32 bias : 3; // ITB_X + u32 bs : 2; // ITBA_X, indicates which coordinate will become the 'bump alpha' + u32 mid : 4; // Matrix ID to multiply offsets with + u32 sw : 3; // ITW_X, wrapping factor for S of regular coord + u32 tw : 3; // ITW_X, wrapping factor for T of regular coord + u32 lb_utclod : 1; // Use modified or unmodified texture coordinates for LOD computation + u32 fb_addprev : 1; // 1 if the texture coordinate results from the previous TEV stage should + // be added + u32 pad0 : 3; + u32 rid : 8; + }; + struct + { + u32 hex : 21; + u32 unused : 11; + }; - // If bs and mid are zero, the result of the stage is independent of - // the texture sample data, so we can skip sampling the texture. - bool IsActive() { return bs != ITBA_OFF || mid != 0; } - }; - - union TwoTevStageOrders - { - struct - { - u32 texmap0 : 3; // Indirect tex stage texmap - u32 texcoord0 : 3; - u32 enable0 : 1; // 1 if should read from texture - u32 colorchan0 : 3; // RAS1_CC_X - - u32 pad0 : 2; - - u32 texmap1 : 3; - u32 texcoord1 : 3; - u32 enable1 : 1; // 1 if should read from texture - u32 colorchan1 : 3; // RAS1_CC_X - - u32 pad1 : 2; - u32 rid : 8; - }; - u32 hex; - int getTexMap(int i) const { return i ? texmap1 : texmap0;} - int getTexCoord(int i) const { return i ? texcoord1 : texcoord0;} - int getEnable(int i) const { return i ? enable1 : enable0; } - int getColorChan(int i) const { return i ? colorchan1 : colorchan0; } - }; - -union TEXSCALE -{ - struct - { - u32 ss0 : 4; // Indirect tex stage 0, 2^(-ss0) - u32 ts0 : 4; // Indirect tex stage 0 - u32 ss1 : 4; // Indirect tex stage 1 - u32 ts1 : 4; // Indirect tex stage 1 - u32 pad : 8; - u32 rid : 8; - }; - u32 hex; + // If bs and mid are zero, the result of the stage is independent of + // the texture sample data, so we can skip sampling the texture. + bool IsActive() { return bs != ITBA_OFF || mid != 0; } }; -union RAS1_IREF -{ - struct - { - u32 bi0 : 3; // Indirect tex stage 0 ntexmap - u32 bc0 : 3; // Indirect tex stage 0 ntexcoord - u32 bi1 : 3; - u32 bc1 : 3; - u32 bi2 : 3; - u32 bc3 : 3; - u32 bi4 : 3; - u32 bc4 : 3; - u32 rid : 8; - }; - u32 hex; +union TwoTevStageOrders { + struct + { + u32 texmap0 : 3; // Indirect tex stage texmap + u32 texcoord0 : 3; + u32 enable0 : 1; // 1 if should read from texture + u32 colorchan0 : 3; // RAS1_CC_X - u32 getTexCoord(int i) { return (hex>>(6*i+3))&7; } - u32 getTexMap(int i) { return (hex>>(6*i))&7; } + u32 pad0 : 2; + + u32 texmap1 : 3; + u32 texcoord1 : 3; + u32 enable1 : 1; // 1 if should read from texture + u32 colorchan1 : 3; // RAS1_CC_X + + u32 pad1 : 2; + u32 rid : 8; + }; + u32 hex; + int getTexMap(int i) const { return i ? texmap1 : texmap0; } + int getTexCoord(int i) const { return i ? texcoord1 : texcoord0; } + int getEnable(int i) const { return i ? enable1 : enable0; } + int getColorChan(int i) const { return i ? colorchan1 : colorchan0; } }; +union TEXSCALE { + struct + { + u32 ss0 : 4; // Indirect tex stage 0, 2^(-ss0) + u32 ts0 : 4; // Indirect tex stage 0 + u32 ss1 : 4; // Indirect tex stage 1 + u32 ts1 : 4; // Indirect tex stage 1 + u32 pad : 8; + u32 rid : 8; + }; + u32 hex; +}; + +union RAS1_IREF { + struct + { + u32 bi0 : 3; // Indirect tex stage 0 ntexmap + u32 bc0 : 3; // Indirect tex stage 0 ntexcoord + u32 bi1 : 3; + u32 bc1 : 3; + u32 bi2 : 3; + u32 bc3 : 3; + u32 bi4 : 3; + u32 bc4 : 3; + u32 rid : 8; + }; + u32 hex; + + u32 getTexCoord(int i) { return (hex >> (6 * i + 3)) & 7; } + u32 getTexMap(int i) { return (hex >> (6 * i)) & 7; } +}; // Texture structs -union TexMode0 -{ - enum TextureFilter : u32 - { - TEXF_NONE = 0, - TEXF_POINT = 1, - TEXF_LINEAR = 2 - }; +union TexMode0 { + enum TextureFilter : u32 + { + TEXF_NONE = 0, + TEXF_POINT = 1, + TEXF_LINEAR = 2 + }; - struct - { - u32 wrap_s : 2; - u32 wrap_t : 2; - u32 mag_filter : 1; - u32 min_filter : 3; - u32 diag_lod : 1; - s32 lod_bias : 8; - u32 pad0 : 2; - u32 max_aniso : 2; - u32 lod_clamp : 1; - }; - u32 hex; + struct + { + u32 wrap_s : 2; + u32 wrap_t : 2; + u32 mag_filter : 1; + u32 min_filter : 3; + u32 diag_lod : 1; + s32 lod_bias : 8; + u32 pad0 : 2; + u32 max_aniso : 2; + u32 lod_clamp : 1; + }; + u32 hex; }; -union TexMode1 -{ - struct - { - u32 min_lod : 8; - u32 max_lod : 8; - }; - u32 hex; +union TexMode1 { + struct + { + u32 min_lod : 8; + u32 max_lod : 8; + }; + u32 hex; }; -union TexImage0 -{ - struct - { - u32 width : 10; // Actually w-1 - u32 height : 10; // Actually h-1 - u32 format : 4; - }; - u32 hex; +union TexImage0 { + struct + { + u32 width : 10; // Actually w-1 + u32 height : 10; // Actually h-1 + u32 format : 4; + }; + u32 hex; }; -union TexImage1 -{ - struct - { - u32 tmem_even : 15; // TMEM line index for even LODs - u32 cache_width : 3; - u32 cache_height : 3; - u32 image_type : 1; // 1 if this texture is managed manually (0 means we'll autofetch the texture data whenever it changes) - }; - u32 hex; +union TexImage1 { + struct + { + u32 tmem_even : 15; // TMEM line index for even LODs + u32 cache_width : 3; + u32 cache_height : 3; + u32 image_type : 1; // 1 if this texture is managed manually (0 means we'll autofetch the + // texture data whenever it changes) + }; + u32 hex; }; -union TexImage2 -{ - struct - { - u32 tmem_odd : 15; // tmem line index for odd LODs - u32 cache_width : 3; - u32 cache_height : 3; - }; - u32 hex; +union TexImage2 { + struct + { + u32 tmem_odd : 15; // tmem line index for odd LODs + u32 cache_width : 3; + u32 cache_height : 3; + }; + u32 hex; }; -union TexImage3 -{ - struct - { - u32 image_base: 24; //address in memory >> 5 (was 20 for GC) - }; - u32 hex; +union TexImage3 { + struct + { + u32 image_base : 24; // address in memory >> 5 (was 20 for GC) + }; + u32 hex; }; -union TexTLUT -{ - struct - { - u32 tmem_offset : 10; - u32 tlut_format : 2; - }; - u32 hex; +union TexTLUT { + struct + { + u32 tmem_offset : 10; + u32 tlut_format : 2; + }; + u32 hex; }; -union ZTex1 -{ - struct - { - u32 bias : 24; - }; - u32 hex; +union ZTex1 { + struct + { + u32 bias : 24; + }; + u32 hex; }; -union ZTex2 -{ - struct - { - u32 type : 2; // TEV_Z_TYPE_X - u32 op : 2; // GXZTexOp - }; - u32 hex; +union ZTex2 { + struct + { + u32 type : 2; // TEV_Z_TYPE_X + u32 op : 2; // GXZTexOp + }; + u32 hex; }; struct FourTexUnits { - TexMode0 texMode0[4]; - TexMode1 texMode1[4]; - TexImage0 texImage0[4]; - TexImage1 texImage1[4]; - TexImage2 texImage2[4]; - TexImage3 texImage3[4]; - TexTLUT texTlut[4]; - u32 unknown[4]; + TexMode0 texMode0[4]; + TexMode1 texMode1[4]; + TexImage0 texImage0[4]; + TexImage1 texImage1[4]; + TexImage2 texImage2[4]; + TexImage3 texImage3[4]; + TexTLUT texTlut[4]; + u32 unknown[4]; }; - - // Geometry/other structs -union GenMode -{ - enum CullMode : u32 - { - CULL_NONE = 0, - CULL_BACK = 1, // cull back-facing primitives - CULL_FRONT = 2, // cull front-facing primitives - CULL_ALL = 3, // cull all primitives - }; +union GenMode { + enum CullMode : u32 + { + CULL_NONE = 0, + CULL_BACK = 1, // cull back-facing primitives + CULL_FRONT = 2, // cull front-facing primitives + CULL_ALL = 3, // cull all primitives + }; - BitField< 0,4,u32> numtexgens; - BitField< 4,3,u32> numcolchans; - // 1 bit unused? - BitField< 8,1,u32> flat_shading; // unconfirmed - BitField< 9,1,u32> multisampling; - BitField<10,4,u32> numtevstages; - BitField<14,2,CullMode> cullmode; - BitField<16,3,u32> numindstages; - BitField<19,1,u32> zfreeze; + BitField<0, 4, u32> numtexgens; + BitField<4, 3, u32> numcolchans; + // 1 bit unused? + BitField<8, 1, u32> flat_shading; // unconfirmed + BitField<9, 1, u32> multisampling; + BitField<10, 4, u32> numtevstages; + BitField<14, 2, CullMode> cullmode; + BitField<16, 3, u32> numindstages; + BitField<19, 1, u32> zfreeze; - u32 hex; + u32 hex; }; -union LPSize -{ - struct - { - u32 linesize : 8; // in 1/6th pixels - u32 pointsize : 8; // in 1/6th pixels - u32 lineoff : 3; - u32 pointoff : 3; - u32 lineaspect : 1; // interlacing: adjust for pixels having AR of 1/2 - u32 padding : 1; - }; - u32 hex; +union LPSize { + struct + { + u32 linesize : 8; // in 1/6th pixels + u32 pointsize : 8; // in 1/6th pixels + u32 lineoff : 3; + u32 pointoff : 3; + u32 lineaspect : 1; // interlacing: adjust for pixels having AR of 1/2 + u32 padding : 1; + }; + u32 hex; }; - -union X12Y12 -{ - struct - { - u32 y : 12; - u32 x : 12; - }; - u32 hex; +union X12Y12 { + struct + { + u32 y : 12; + u32 x : 12; + }; + u32 hex; }; -union X10Y10 -{ - struct - { - u32 x : 10; - u32 y : 10; - }; - u32 hex; +union X10Y10 { + struct + { + u32 x : 10; + u32 y : 10; + }; + u32 hex; }; - // Framebuffer/pixel stuff (incl fog) -union BlendMode -{ - enum BlendFactor : u32 - { - ZERO = 0, - ONE = 1, - SRCCLR = 2, // for dst factor - INVSRCCLR = 3, // for dst factor - DSTCLR = SRCCLR, // for src factor - INVDSTCLR = INVSRCCLR, // for src factor - SRCALPHA = 4, - INVSRCALPHA = 5, - DSTALPHA = 6, - INVDSTALPHA = 7 - }; +union BlendMode { + enum BlendFactor : u32 + { + ZERO = 0, + ONE = 1, + SRCCLR = 2, // for dst factor + INVSRCCLR = 3, // for dst factor + DSTCLR = SRCCLR, // for src factor + INVDSTCLR = INVSRCCLR, // for src factor + SRCALPHA = 4, + INVSRCALPHA = 5, + DSTALPHA = 6, + INVDSTALPHA = 7 + }; - enum LogicOp : u32 - { - CLEAR = 0, - AND = 1, - AND_REVERSE = 2, - COPY = 3, - AND_INVERTED = 4, - NOOP = 5, - XOR = 6, - OR = 7, - NOR = 8, - EQUIV = 9, - INVERT = 10, - OR_REVERSE = 11, - COPY_INVERTED = 12, - OR_INVERTED = 13, - NAND = 14, - SET = 15 - }; + enum LogicOp : u32 + { + CLEAR = 0, + AND = 1, + AND_REVERSE = 2, + COPY = 3, + AND_INVERTED = 4, + NOOP = 5, + XOR = 6, + OR = 7, + NOR = 8, + EQUIV = 9, + INVERT = 10, + OR_REVERSE = 11, + COPY_INVERTED = 12, + OR_INVERTED = 13, + NAND = 14, + SET = 15 + }; - BitField< 0,1,u32> blendenable; - BitField< 1,1,u32> logicopenable; - BitField< 2,1,u32> dither; - BitField< 3,1,u32> colorupdate; - BitField< 4,1,u32> alphaupdate; - BitField< 5,3,BlendFactor> dstfactor; - BitField< 8,3,BlendFactor> srcfactor; - BitField<11,1,u32> subtract; - BitField<12,4,LogicOp> logicmode; + BitField<0, 1, u32> blendenable; + BitField<1, 1, u32> logicopenable; + BitField<2, 1, u32> dither; + BitField<3, 1, u32> colorupdate; + BitField<4, 1, u32> alphaupdate; + BitField<5, 3, BlendFactor> dstfactor; + BitField<8, 3, BlendFactor> srcfactor; + BitField<11, 1, u32> subtract; + BitField<12, 4, LogicOp> logicmode; - u32 hex; + u32 hex; }; +union FogParam0 { + struct + { + u32 mantissa : 11; + u32 exponent : 8; + u32 sign : 1; + }; -union FogParam0 -{ - struct - { - u32 mantissa : 11; - u32 exponent : 8; - u32 sign : 1; - }; + float GetA() + { + union { + u32 i; + float f; + } dummy; + dummy.i = ((u32)sign << 31) | ((u32)exponent << 23) | + ((u32)mantissa << 12); // scale mantissa from 11 to 23 bits + return dummy.f; + } - float GetA() - { - union { u32 i; float f; } dummy; - dummy.i = ((u32)sign << 31) | ((u32)exponent << 23) | ((u32)mantissa << 12); // scale mantissa from 11 to 23 bits - return dummy.f; - } - - u32 hex; + u32 hex; }; -union FogParam3 -{ - struct - { - u32 c_mant : 11; - u32 c_exp : 8; - u32 c_sign : 1; - u32 proj : 1; // 0 - perspective, 1 - orthographic - u32 fsel : 3; // 0 - off, 2 - linear, 4 - exp, 5 - exp2, 6 - backward exp, 7 - backward exp2 - }; +union FogParam3 { + struct + { + u32 c_mant : 11; + u32 c_exp : 8; + u32 c_sign : 1; + u32 proj : 1; // 0 - perspective, 1 - orthographic + u32 fsel : 3; // 0 - off, 2 - linear, 4 - exp, 5 - exp2, 6 - backward exp, 7 - backward exp2 + }; - // amount to subtract from eyespacez after range adjustment - float GetC() - { - union { u32 i; float f; } dummy; - dummy.i = ((u32)c_sign << 31) | ((u32)c_exp << 23) | ((u32)c_mant << 12); // scale mantissa from 11 to 23 bits - return dummy.f; - } + // amount to subtract from eyespacez after range adjustment + float GetC() + { + union { + u32 i; + float f; + } dummy; + dummy.i = ((u32)c_sign << 31) | ((u32)c_exp << 23) | + ((u32)c_mant << 12); // scale mantissa from 11 to 23 bits + return dummy.f; + } - u32 hex; + u32 hex; }; -union FogRangeKElement -{ - struct - { - u32 HI : 12; - u32 LO : 12; - u32 regid : 8; - }; +union FogRangeKElement { + struct + { + u32 HI : 12; + u32 LO : 12; + u32 regid : 8; + }; - // TODO: Which scaling coefficient should we use here? This is just a guess! - float GetValue(int i) { return (i ? HI : LO) / 256.f; } - u32 HEX; + // TODO: Which scaling coefficient should we use here? This is just a guess! + float GetValue(int i) { return (i ? HI : LO) / 256.f; } + u32 HEX; }; struct FogRangeParams { - union RangeBase - { - struct - { - u32 Center : 10; // viewport center + 342 - u32 Enabled : 1; - u32 unused : 13; - u32 regid : 8; - }; - u32 hex; - }; - RangeBase Base; - FogRangeKElement K[5]; + union RangeBase { + struct + { + u32 Center : 10; // viewport center + 342 + u32 Enabled : 1; + u32 unused : 13; + u32 regid : 8; + }; + u32 hex; + }; + RangeBase Base; + FogRangeKElement K[5]; }; // final eq: ze = A/(B_MAG - (Zs>>B_SHF)); struct FogParams { - FogParam0 a; - u32 b_magnitude; - u32 b_shift; // b's exp + 1? - FogParam3 c_proj_fsel; + FogParam0 a; + u32 b_magnitude; + u32 b_shift; // b's exp + 1? + FogParam3 c_proj_fsel; - union FogColor - { - struct - { - u32 b : 8; - u32 g : 8; - u32 r : 8; - }; - u32 hex; - }; + union FogColor { + struct + { + u32 b : 8; + u32 g : 8; + u32 r : 8; + }; + u32 hex; + }; - FogColor color; //0:b 8:g 16:r - nice! + FogColor color; // 0:b 8:g 16:r - nice! }; -union ZMode -{ - enum CompareMode : u32 - { - NEVER = 0, - LESS = 1, - EQUAL = 2, - LEQUAL = 3, - GREATER = 4, - NEQUAL = 5, - GEQUAL = 6, - ALWAYS = 7 - }; +union ZMode { + enum CompareMode : u32 + { + NEVER = 0, + LESS = 1, + EQUAL = 2, + LEQUAL = 3, + GREATER = 4, + NEQUAL = 5, + GEQUAL = 6, + ALWAYS = 7 + }; - BitField<0,1,u32> testenable; - BitField<1,3,CompareMode> func; - BitField<4,1,u32> updateenable; + BitField<0, 1, u32> testenable; + BitField<1, 3, CompareMode> func; + BitField<4, 1, u32> updateenable; - u32 hex; + u32 hex; }; -union ConstantAlpha -{ - struct - { - u32 alpha : 8; - u32 enable : 1; - }; - u32 hex; +union ConstantAlpha { + struct + { + u32 alpha : 8; + u32 enable : 1; + }; + u32 hex; }; -union FieldMode -{ - struct - { - u32 texLOD : 1; // adjust vert tex LOD computation to account for interlacing - }; - u32 hex; +union FieldMode { + struct + { + u32 texLOD : 1; // adjust vert tex LOD computation to account for interlacing + }; + u32 hex; }; -union FieldMask -{ - struct - { - // If bit is not set, do not write field to EFB - u32 odd : 1; - u32 even : 1; - }; - u32 hex; +union FieldMask { + struct + { + // If bit is not set, do not write field to EFB + u32 odd : 1; + u32 even : 1; + }; + u32 hex; }; -union PEControl -{ - enum PixelFormat : u32 - { - RGB8_Z24 = 0, - RGBA6_Z24 = 1, - RGB565_Z16 = 2, - Z24 = 3, - Y8 = 4, - U8 = 5, - V8 = 6, - YUV420 = 7, - INVALID_FMT = 0xffffffff, // Used by Dolphin to represent a missing value. - }; +union PEControl { + enum PixelFormat : u32 + { + RGB8_Z24 = 0, + RGBA6_Z24 = 1, + RGB565_Z16 = 2, + Z24 = 3, + Y8 = 4, + U8 = 5, + V8 = 6, + YUV420 = 7, + INVALID_FMT = 0xffffffff, // Used by Dolphin to represent a missing value. + }; - enum DepthFormat : u32 - { - ZLINEAR = 0, - ZNEAR = 1, - ZMID = 2, - ZFAR = 3, + enum DepthFormat : u32 + { + ZLINEAR = 0, + ZNEAR = 1, + ZMID = 2, + ZFAR = 3, - // It seems these Z formats aren't supported/were removed ? - ZINV_LINEAR = 4, - ZINV_NEAR = 5, - ZINV_MID = 6, - ZINV_FAR = 7 - }; + // It seems these Z formats aren't supported/were removed ? + ZINV_LINEAR = 4, + ZINV_NEAR = 5, + ZINV_MID = 6, + ZINV_FAR = 7 + }; - BitField< 0,3,PixelFormat> pixel_format; - BitField< 3,3,DepthFormat> zformat; - BitField< 6,1,u32> early_ztest; + BitField<0, 3, PixelFormat> pixel_format; + BitField<3, 3, DepthFormat> zformat; + BitField<6, 1, u32> early_ztest; - u32 hex; + u32 hex; }; - // Texture coordinate stuff -union TCInfo -{ - struct - { - u32 scale_minus_1 : 16; - u32 range_bias : 1; - u32 cylindric_wrap : 1; - // These bits only have effect in the s field of TCoordInfo - u32 line_offset : 1; - u32 point_offset : 1; - }; - u32 hex; +union TCInfo { + struct + { + u32 scale_minus_1 : 16; + u32 range_bias : 1; + u32 cylindric_wrap : 1; + // These bits only have effect in the s field of TCoordInfo + u32 line_offset : 1; + u32 point_offset : 1; + }; + u32 hex; }; struct TCoordInfo { - TCInfo s; - TCInfo t; + TCInfo s; + TCInfo t; }; +union TevReg { + u64 hex; -union TevReg -{ - u64 hex; + // Access to individual registers + BitField<0, 32, u64> low; + BitField<32, 32, u64> high; - // Access to individual registers - BitField< 0, 32,u64> low; - BitField<32, 32,u64> high; + // TODO: Check if Konst uses all 11 bits or just 8 - // TODO: Check if Konst uses all 11 bits or just 8 + // Low register + BitField<0, 11, s64> red; - // Low register - BitField< 0,11,s64> red; + BitField<12, 11, s64> alpha; + BitField<23, 1, u64> type_ra; - BitField<12,11,s64> alpha; - BitField<23, 1,u64> type_ra; + // High register + BitField<32, 11, s64> blue; - // High register - BitField<32,11,s64> blue; - - BitField<44,11,s64> green; - BitField<55, 1,u64> type_bg; + BitField<44, 11, s64> green; + BitField<55, 1, u64> type_bg; }; -union TevKSel -{ - struct { - u32 swap1 : 2; - u32 swap2 : 2; - u32 kcsel0 : 5; - u32 kasel0 : 5; - u32 kcsel1 : 5; - u32 kasel1 : 5; - }; - u32 hex; +union TevKSel { + struct + { + u32 swap1 : 2; + u32 swap2 : 2; + u32 kcsel0 : 5; + u32 kasel0 : 5; + u32 kcsel1 : 5; + u32 kasel1 : 5; + }; + u32 hex; - int getKC(int i) {return i?kcsel1:kcsel0;} - int getKA(int i) {return i?kasel1:kasel0;} + int getKC(int i) { return i ? kcsel1 : kcsel0; } + int getKA(int i) { return i ? kasel1 : kasel0; } }; -union AlphaTest -{ - enum CompareMode : u32 - { - NEVER = 0, - LESS = 1, - EQUAL = 2, - LEQUAL = 3, - GREATER = 4, - NEQUAL = 5, - GEQUAL = 6, - ALWAYS = 7 - }; +union AlphaTest { + enum CompareMode : u32 + { + NEVER = 0, + LESS = 1, + EQUAL = 2, + LEQUAL = 3, + GREATER = 4, + NEQUAL = 5, + GEQUAL = 6, + ALWAYS = 7 + }; - enum Op : u32 - { - AND = 0, - OR = 1, - XOR = 2, - XNOR = 3 - }; + enum Op : u32 + { + AND = 0, + OR = 1, + XOR = 2, + XNOR = 3 + }; - BitField< 0,8, u32> ref0; - BitField< 8,8, u32> ref1; - BitField<16,3, CompareMode> comp0; - BitField<19,3, CompareMode> comp1; - BitField<22,2, Op> logic; + BitField<0, 8, u32> ref0; + BitField<8, 8, u32> ref1; + BitField<16, 3, CompareMode> comp0; + BitField<19, 3, CompareMode> comp1; + BitField<22, 2, Op> logic; - u32 hex; + u32 hex; - enum TEST_RESULT - { - UNDETERMINED = 0, - FAIL = 1, - PASS = 2, - }; + enum TEST_RESULT + { + UNDETERMINED = 0, + FAIL = 1, + PASS = 2, + }; - __forceinline TEST_RESULT TestResult() const - { - switch (logic) - { - case AND: - if (comp0 == ALWAYS && comp1 == ALWAYS) - return PASS; - if (comp0 == NEVER || comp1 == NEVER) - return FAIL; - break; + __forceinline TEST_RESULT TestResult() const + { + switch (logic) + { + case AND: + if (comp0 == ALWAYS && comp1 == ALWAYS) + return PASS; + if (comp0 == NEVER || comp1 == NEVER) + return FAIL; + break; - case OR: - if (comp0 == ALWAYS || comp1 == ALWAYS) - return PASS; - if (comp0 == NEVER && comp1 == NEVER) - return FAIL; - break; + case OR: + if (comp0 == ALWAYS || comp1 == ALWAYS) + return PASS; + if (comp0 == NEVER && comp1 == NEVER) + return FAIL; + break; - case XOR: - if ((comp0 == ALWAYS && comp1 == NEVER) || (comp0 == NEVER && comp1 == ALWAYS)) - return PASS; - if ((comp0 == ALWAYS && comp1 == ALWAYS) || (comp0 == NEVER && comp1 == NEVER)) - return FAIL; - break; + case XOR: + if ((comp0 == ALWAYS && comp1 == NEVER) || (comp0 == NEVER && comp1 == ALWAYS)) + return PASS; + if ((comp0 == ALWAYS && comp1 == ALWAYS) || (comp0 == NEVER && comp1 == NEVER)) + return FAIL; + break; - case XNOR: - if ((comp0 == ALWAYS && comp1 == NEVER) || (comp0 == NEVER && comp1 == ALWAYS)) - return FAIL; - if ((comp0 == ALWAYS && comp1 == ALWAYS) || (comp0 == NEVER && comp1 == NEVER)) - return PASS; - break; + case XNOR: + if ((comp0 == ALWAYS && comp1 == NEVER) || (comp0 == NEVER && comp1 == ALWAYS)) + return FAIL; + if ((comp0 == ALWAYS && comp1 == ALWAYS) || (comp0 == NEVER && comp1 == NEVER)) + return PASS; + break; - default: - return UNDETERMINED; - } - return UNDETERMINED; - } + default: + return UNDETERMINED; + } + return UNDETERMINED; + } }; -union UPE_Copy -{ - u32 Hex; +union UPE_Copy { + u32 Hex; - BitField< 0,1,u32> clamp0; // if set clamp top - BitField< 1,1,u32> clamp1; // if set clamp bottom - BitField< 2,1,u32> yuv; // if set, color conversion from RGB to YUV - BitField< 3,4,u32> target_pixel_format; // realformat is (fmt/2)+((fmt&1)*8).... for some reason the msb is the lsb (pattern: cycling right shift) - BitField< 7,2,u32> gamma; // gamma correction.. 0 = 1.0 ; 1 = 1.7 ; 2 = 2.2 ; 3 is reserved - BitField< 9,1,u32> half_scale; // "mipmap" filter... 0 = no filter (scale 1:1) ; 1 = box filter (scale 2:1) - BitField<10,1,u32> scale_invert; // if set vertical scaling is on - BitField<11,1,u32> clear; - BitField<12,2,u32> frame_to_field; // 0 progressive ; 1 is reserved ; 2 = interlaced (even lines) ; 3 = interlaced 1 (odd lines) - BitField<14,1,u32> copy_to_xfb; - BitField<15,1,u32> intensity_fmt; // if set, is an intensity format (I4,I8,IA4,IA8) - BitField<16,1,u32> auto_conv; // if 0 automatic color conversion by texture format and pixel type + BitField<0, 1, u32> clamp0; // if set clamp top + BitField<1, 1, u32> clamp1; // if set clamp bottom + BitField<2, 1, u32> yuv; // if set, color conversion from RGB to YUV + BitField<3, 4, u32> target_pixel_format; // realformat is (fmt/2)+((fmt&1)*8).... for some reason + // the msb is the lsb (pattern: cycling right shift) + BitField<7, 2, u32> gamma; // gamma correction.. 0 = 1.0 ; 1 = 1.7 ; 2 = 2.2 ; 3 is reserved + BitField<9, 1, u32> + half_scale; // "mipmap" filter... 0 = no filter (scale 1:1) ; 1 = box filter (scale 2:1) + BitField<10, 1, u32> scale_invert; // if set vertical scaling is on + BitField<11, 1, u32> clear; + BitField<12, 2, u32> frame_to_field; // 0 progressive ; 1 is reserved ; 2 = interlaced (even + // lines) ; 3 = interlaced 1 (odd lines) + BitField<14, 1, u32> copy_to_xfb; + BitField<15, 1, u32> intensity_fmt; // if set, is an intensity format (I4,I8,IA4,IA8) + BitField<16, 1, u32> + auto_conv; // if 0 automatic color conversion by texture format and pixel type - u32 tp_realFormat() - { - return target_pixel_format / 2 + (target_pixel_format & 1) * 8; - } + u32 tp_realFormat() { return target_pixel_format / 2 + (target_pixel_format & 1) * 8; } }; -union BPU_PreloadTileInfo -{ - u32 hex; - struct - { - u32 count : 15; - u32 type : 2; - }; +union BPU_PreloadTileInfo { + u32 hex; + struct + { + u32 count : 15; + u32 type : 2; + }; }; struct BPS_TmemConfig { - u32 preload_addr; - u32 preload_tmem_even; - u32 preload_tmem_odd; - BPU_PreloadTileInfo preload_tile_info; - u32 tlut_src; - u32 tlut_dest; - u32 texinvalidate; + u32 preload_addr; + u32 preload_tmem_even; + u32 preload_tmem_odd; + BPU_PreloadTileInfo preload_tile_info; + u32 tlut_src; + u32 tlut_dest; + u32 texinvalidate; }; // All of BP memory - struct BPCmd { - int address; - int changes; - int newvalue; + int address; + int changes; + int newvalue; }; struct BPMemory { - GenMode genMode; - u32 display_copy_filter[4]; // 01-04 - u32 unknown; // 05 - // indirect matrices (set by GXSetIndTexMtx, selected by TevStageIndirect::mid) - // abc form a 2x3 offset matrix, there's 3 such matrices - // the 3 offset matrices can either be indirect type, S-type, or T-type - // 6bit scale factor s is distributed across IND_MTXA/B/C. - // before using matrices scale by 2^-(s-17) - IND_MTX indmtx[3];//06-0e GXSetIndTexMtx, 2x3 matrices - IND_IMASK imask;//0f - TevStageIndirect tevind[16];//10 GXSetTevIndirect - X12Y12 scissorTL; //20 - X12Y12 scissorBR; //21 - LPSize lineptwidth; //22 line and point width - u32 sucounter; //23 - u32 rascounter; //24 - TEXSCALE texscale[2]; //25-26 GXSetIndTexCoordScale - RAS1_IREF tevindref; //27 GXSetIndTexOrder - TwoTevStageOrders tevorders[8]; //28-2F - TCoordInfo texcoords[8]; //0x30 s,t,s,t,s,t,s,t... - ZMode zmode; //40 - BlendMode blendmode; //41 - ConstantAlpha dstalpha; //42 - PEControl zcontrol; //43 GXSetZCompLoc, GXPixModeSync - FieldMask fieldmask; //44 - u32 drawdone; //45, bit1=1 if end of list - u32 unknown5; //46 clock? - u32 petoken; //47 - u32 petokenint; // 48 - X10Y10 copyTexSrcXY; // 49 - X10Y10 copyTexSrcWH; // 4a - u32 copyTexDest; //4b// 4b == CopyAddress (GXDispCopy and GXTexCopy use it) - u32 unknown6; //4c - u32 copyMipMapStrideChannels; // 4d usually set to 4 when dest is single channel, 8 when dest is 2 channel, 16 when dest is RGBA - // also, doubles whenever mipmap box filter option is set (excent on RGBA). Probably to do with number of bytes to look at when smoothing - u32 dispcopyyscale; //4e - u32 clearcolorAR; //4f - u32 clearcolorGB; //50 - u32 clearZValue; //51 - UPE_Copy triggerEFBCopy; //52 - u32 copyfilter[2]; //53,54 - u32 boundbox0;//55 - u32 boundbox1;//56 - u32 unknown7[2];//57,58 - X10Y10 scissorOffset; //59 - u32 unknown8[6]; //5a,5b,5c,5d, 5e,5f - BPS_TmemConfig tmem_config; // 60-66 - u32 metric; //67 - FieldMode fieldmode;//68 - u32 unknown10[7];//69-6F - u32 unknown11[16];//70-7F - FourTexUnits tex[2]; //80-bf - TevStageCombiner combiners[16]; //0xC0-0xDF - TevReg tevregs[4]; //0xE0 - FogRangeParams fogRange; // 0xE8 - FogParams fog; //0xEE,0xEF,0xF0,0xF1,0xF2 - AlphaTest alpha_test; //0xF3 - ZTex1 ztex1; //0xf4,0xf5 - ZTex2 ztex2; - TevKSel tevksel[8];//0xf6,0xf7,f8,f9,fa,fb,fc,fd - u32 bpMask; //0xFE - u32 unknown18; //ff + GenMode genMode; + u32 display_copy_filter[4]; // 01-04 + u32 unknown; // 05 + // indirect matrices (set by GXSetIndTexMtx, selected by TevStageIndirect::mid) + // abc form a 2x3 offset matrix, there's 3 such matrices + // the 3 offset matrices can either be indirect type, S-type, or T-type + // 6bit scale factor s is distributed across IND_MTXA/B/C. + // before using matrices scale by 2^-(s-17) + IND_MTX indmtx[3]; // 06-0e GXSetIndTexMtx, 2x3 matrices + IND_IMASK imask; // 0f + TevStageIndirect tevind[16]; // 10 GXSetTevIndirect + X12Y12 scissorTL; // 20 + X12Y12 scissorBR; // 21 + LPSize lineptwidth; // 22 line and point width + u32 sucounter; // 23 + u32 rascounter; // 24 + TEXSCALE texscale[2]; // 25-26 GXSetIndTexCoordScale + RAS1_IREF tevindref; // 27 GXSetIndTexOrder + TwoTevStageOrders tevorders[8]; // 28-2F + TCoordInfo texcoords[8]; // 0x30 s,t,s,t,s,t,s,t... + ZMode zmode; // 40 + BlendMode blendmode; // 41 + ConstantAlpha dstalpha; // 42 + PEControl zcontrol; // 43 GXSetZCompLoc, GXPixModeSync + FieldMask fieldmask; // 44 + u32 drawdone; // 45, bit1=1 if end of list + u32 unknown5; // 46 clock? + u32 petoken; // 47 + u32 petokenint; // 48 + X10Y10 copyTexSrcXY; // 49 + X10Y10 copyTexSrcWH; // 4a + u32 copyTexDest; // 4b// 4b == CopyAddress (GXDispCopy and GXTexCopy use it) + u32 unknown6; // 4c + u32 copyMipMapStrideChannels; // 4d usually set to 4 when dest is single channel, 8 when dest is + // 2 channel, 16 when dest is RGBA + // also, doubles whenever mipmap box filter option is set (excent on RGBA). Probably to do with + // number of bytes to look at when smoothing + u32 dispcopyyscale; // 4e + u32 clearcolorAR; // 4f + u32 clearcolorGB; // 50 + u32 clearZValue; // 51 + UPE_Copy triggerEFBCopy; // 52 + u32 copyfilter[2]; // 53,54 + u32 boundbox0; // 55 + u32 boundbox1; // 56 + u32 unknown7[2]; // 57,58 + X10Y10 scissorOffset; // 59 + u32 unknown8[6]; // 5a,5b,5c,5d, 5e,5f + BPS_TmemConfig tmem_config; // 60-66 + u32 metric; // 67 + FieldMode fieldmode; // 68 + u32 unknown10[7]; // 69-6F + u32 unknown11[16]; // 70-7F + FourTexUnits tex[2]; // 80-bf + TevStageCombiner combiners[16]; // 0xC0-0xDF + TevReg tevregs[4]; // 0xE0 + FogRangeParams fogRange; // 0xE8 + FogParams fog; // 0xEE,0xEF,0xF0,0xF1,0xF2 + AlphaTest alpha_test; // 0xF3 + ZTex1 ztex1; // 0xf4,0xf5 + ZTex2 ztex2; + TevKSel tevksel[8]; // 0xf6,0xf7,f8,f9,fa,fb,fc,fd + u32 bpMask; // 0xFE + u32 unknown18; // ff - bool UseEarlyDepthTest() const { return zcontrol.early_ztest && zmode.testenable; } - bool UseLateDepthTest() const { return !zcontrol.early_ztest && zmode.testenable; } + bool UseEarlyDepthTest() const { return zcontrol.early_ztest && zmode.testenable; } + bool UseLateDepthTest() const { return !zcontrol.early_ztest && zmode.testenable; } }; #pragma pack() diff --git a/Source/Core/VideoCommon/BPStructs.cpp b/Source/Core/VideoCommon/BPStructs.cpp index aaa73d991d..dba1b33180 100644 --- a/Source/Core/VideoCommon/BPStructs.cpp +++ b/Source/Core/VideoCommon/BPStructs.cpp @@ -6,17 +6,17 @@ #include #include +#include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "Common/Thread.h" -#include "Common/Logging/Log.h" #include "Core/ConfigManager.h" #include "Core/FifoPlayer/FifoRecorder.h" #include "Core/HW/Memmap.h" -#include "VideoCommon/BoundingBox.h" #include "VideoCommon/BPFunctions.h" #include "VideoCommon/BPMemory.h" #include "VideoCommon/BPStructs.h" +#include "VideoCommon/BoundingBox.h" #include "VideoCommon/Fifo.h" #include "VideoCommon/GeometryShaderManager.h" #include "VideoCommon/PerfQueryBase.h" @@ -31,1379 +31,1412 @@ using namespace BPFunctions; -static const float s_gammaLUT[] = -{ - 1.0f, - 1.7f, - 2.2f, - 1.0f -}; +static const float s_gammaLUT[] = {1.0f, 1.7f, 2.2f, 1.0f}; void BPInit() { - memset(&bpmem, 0, sizeof(bpmem)); - bpmem.bpMask = 0xFFFFFF; + memset(&bpmem, 0, sizeof(bpmem)); + bpmem.bpMask = 0xFFFFFF; } static void BPWritten(const BPCmd& bp) { - /* - ---------------------------------------------------------------------------------------------------------------- - Purpose: Writes to the BP registers - Called: At the end of every: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg - How It Works: First the pipeline is flushed then update the bpmem with the new value. - Some of the BP cases have to call certain functions while others just update the bpmem. - some bp cases check the changes variable, because they might not have to be updated all the time - NOTE: it seems not all bp cases like checking changes, so calling if (bp.changes == 0 ? false : true) - had to be ditched and the games seem to work fine with out it. - NOTE2: Yet Another GameCube Documentation calls them Bypass Raster State Registers but possibly completely wrong - NOTE3: This controls the register groups: RAS1/2, SU, TF, TEV, C/Z, PEC - TODO: Turn into function table. The (future) DisplayList (DL) jit can then call the functions directly, - getting rid of dynamic dispatch. Unfortunately, few games use DLs properly - most\ - just stuff geometry in them and don't put state changes there - ---------------------------------------------------------------------------------------------------------------- - */ + /* + ---------------------------------------------------------------------------------------------------------------- + Purpose: Writes to the BP registers + Called: At the end of every: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg + How It Works: First the pipeline is flushed then update the bpmem with the new value. + Some of the BP cases have to call certain functions while others just update the bpmem. + some bp cases check the changes variable, because they might not have to be updated all + the time + NOTE: it seems not all bp cases like checking changes, so calling if (bp.changes == 0 ? false : + true) + had to be ditched and the games seem to work fine with out it. + NOTE2: Yet Another GameCube Documentation calls them Bypass Raster State Registers but possibly + completely wrong + NOTE3: This controls the register groups: RAS1/2, SU, TF, TEV, C/Z, PEC + TODO: Turn into function table. The (future) DisplayList (DL) jit can then call the functions + directly, + getting rid of dynamic dispatch. Unfortunately, few games use DLs properly - most\ + just stuff geometry in them and don't put state changes there + ---------------------------------------------------------------------------------------------------------------- + */ - // check for invalid state, else unneeded configuration are built - g_video_backend->CheckInvalidState(); + // check for invalid state, else unneeded configuration are built + g_video_backend->CheckInvalidState(); - if (((s32*)&bpmem)[bp.address] == bp.newvalue) - { - if (!(bp.address == BPMEM_TRIGGER_EFB_COPY || - bp.address == BPMEM_CLEARBBOX1 || - bp.address == BPMEM_CLEARBBOX2 || - bp.address == BPMEM_SETDRAWDONE || - bp.address == BPMEM_PE_TOKEN_ID || - bp.address == BPMEM_PE_TOKEN_INT_ID || - bp.address == BPMEM_LOADTLUT0 || - bp.address == BPMEM_LOADTLUT1 || - bp.address == BPMEM_TEXINVALIDATE || - bp.address == BPMEM_PRELOAD_MODE || - bp.address == BPMEM_CLEAR_PIXEL_PERF)) - { - return; - } - } + if (((s32*)&bpmem)[bp.address] == bp.newvalue) + { + if (!(bp.address == BPMEM_TRIGGER_EFB_COPY || bp.address == BPMEM_CLEARBBOX1 || + bp.address == BPMEM_CLEARBBOX2 || bp.address == BPMEM_SETDRAWDONE || + bp.address == BPMEM_PE_TOKEN_ID || bp.address == BPMEM_PE_TOKEN_INT_ID || + bp.address == BPMEM_LOADTLUT0 || bp.address == BPMEM_LOADTLUT1 || + bp.address == BPMEM_TEXINVALIDATE || bp.address == BPMEM_PRELOAD_MODE || + bp.address == BPMEM_CLEAR_PIXEL_PERF)) + { + return; + } + } - FlushPipeline(); + FlushPipeline(); - ((u32*)&bpmem)[bp.address] = bp.newvalue; + ((u32*)&bpmem)[bp.address] = bp.newvalue; - switch (bp.address) - { - case BPMEM_GENMODE: // Set the Generation Mode - PRIM_LOG("genmode: texgen=%d, col=%d, multisampling=%d, tev=%d, cullmode=%d, ind=%d, zfeeze=%d", - (u32)bpmem.genMode.numtexgens, (u32)bpmem.genMode.numcolchans, - (u32)bpmem.genMode.multisampling, (u32)bpmem.genMode.numtevstages+1, (u32)bpmem.genMode.cullmode, - (u32)bpmem.genMode.numindstages, (u32)bpmem.genMode.zfreeze); + switch (bp.address) + { + case BPMEM_GENMODE: // Set the Generation Mode + PRIM_LOG("genmode: texgen=%d, col=%d, multisampling=%d, tev=%d, cullmode=%d, ind=%d, zfeeze=%d", + (u32)bpmem.genMode.numtexgens, (u32)bpmem.genMode.numcolchans, + (u32)bpmem.genMode.multisampling, (u32)bpmem.genMode.numtevstages + 1, + (u32)bpmem.genMode.cullmode, (u32)bpmem.genMode.numindstages, + (u32)bpmem.genMode.zfreeze); - // Only call SetGenerationMode when cull mode changes. - if (bp.changes & 0xC000) - SetGenerationMode(); - return; - case BPMEM_IND_MTXA: // Index Matrix Changed - case BPMEM_IND_MTXB: - case BPMEM_IND_MTXC: - case BPMEM_IND_MTXA+3: - case BPMEM_IND_MTXB+3: - case BPMEM_IND_MTXC+3: - case BPMEM_IND_MTXA+6: - case BPMEM_IND_MTXB+6: - case BPMEM_IND_MTXC+6: - if (bp.changes) - PixelShaderManager::SetIndMatrixChanged((bp.address - BPMEM_IND_MTXA) / 3); - return; - case BPMEM_RAS1_SS0: // Index Texture Coordinate Scale 0 - if (bp.changes) - PixelShaderManager::SetIndTexScaleChanged(false); - return; - case BPMEM_RAS1_SS1: // Index Texture Coordinate Scale 1 - if (bp.changes) - PixelShaderManager::SetIndTexScaleChanged(true); - return; - // ---------------- - // Scissor Control - // ---------------- - case BPMEM_SCISSORTL: // Scissor Rectable Top, Left - case BPMEM_SCISSORBR: // Scissor Rectable Bottom, Right - case BPMEM_SCISSOROFFSET: // Scissor Offset - SetScissor(); - VertexShaderManager::SetViewportChanged(); - GeometryShaderManager::SetViewportChanged(); - return; - case BPMEM_LINEPTWIDTH: // Line Width - GeometryShaderManager::SetLinePtWidthChanged(); - return; - case BPMEM_ZMODE: // Depth Control - PRIM_LOG("zmode: test=%d, func=%d, upd=%d", (int)bpmem.zmode.testenable, - (int)bpmem.zmode.func, (int)bpmem.zmode.updateenable); - SetDepthMode(); - return; - case BPMEM_BLENDMODE: // Blending Control - if (bp.changes & 0xFFFF) - { - PRIM_LOG("blendmode: en=%d, open=%d, colupd=%d, alphaupd=%d, dst=%d, src=%d, sub=%d, mode=%d", - (int)bpmem.blendmode.blendenable, (int)bpmem.blendmode.logicopenable, (int)bpmem.blendmode.colorupdate, - (int)bpmem.blendmode.alphaupdate, (int)bpmem.blendmode.dstfactor, (int)bpmem.blendmode.srcfactor, - (int)bpmem.blendmode.subtract, (int)bpmem.blendmode.logicmode); + // Only call SetGenerationMode when cull mode changes. + if (bp.changes & 0xC000) + SetGenerationMode(); + return; + case BPMEM_IND_MTXA: // Index Matrix Changed + case BPMEM_IND_MTXB: + case BPMEM_IND_MTXC: + case BPMEM_IND_MTXA + 3: + case BPMEM_IND_MTXB + 3: + case BPMEM_IND_MTXC + 3: + case BPMEM_IND_MTXA + 6: + case BPMEM_IND_MTXB + 6: + case BPMEM_IND_MTXC + 6: + if (bp.changes) + PixelShaderManager::SetIndMatrixChanged((bp.address - BPMEM_IND_MTXA) / 3); + return; + case BPMEM_RAS1_SS0: // Index Texture Coordinate Scale 0 + if (bp.changes) + PixelShaderManager::SetIndTexScaleChanged(false); + return; + case BPMEM_RAS1_SS1: // Index Texture Coordinate Scale 1 + if (bp.changes) + PixelShaderManager::SetIndTexScaleChanged(true); + return; + // ---------------- + // Scissor Control + // ---------------- + case BPMEM_SCISSORTL: // Scissor Rectable Top, Left + case BPMEM_SCISSORBR: // Scissor Rectable Bottom, Right + case BPMEM_SCISSOROFFSET: // Scissor Offset + SetScissor(); + VertexShaderManager::SetViewportChanged(); + GeometryShaderManager::SetViewportChanged(); + return; + case BPMEM_LINEPTWIDTH: // Line Width + GeometryShaderManager::SetLinePtWidthChanged(); + return; + case BPMEM_ZMODE: // Depth Control + PRIM_LOG("zmode: test=%d, func=%d, upd=%d", (int)bpmem.zmode.testenable, (int)bpmem.zmode.func, + (int)bpmem.zmode.updateenable); + SetDepthMode(); + return; + case BPMEM_BLENDMODE: // Blending Control + if (bp.changes & 0xFFFF) + { + PRIM_LOG("blendmode: en=%d, open=%d, colupd=%d, alphaupd=%d, dst=%d, src=%d, sub=%d, mode=%d", + (int)bpmem.blendmode.blendenable, (int)bpmem.blendmode.logicopenable, + (int)bpmem.blendmode.colorupdate, (int)bpmem.blendmode.alphaupdate, + (int)bpmem.blendmode.dstfactor, (int)bpmem.blendmode.srcfactor, + (int)bpmem.blendmode.subtract, (int)bpmem.blendmode.logicmode); - // Set LogicOp Blending Mode - if (bp.changes & 0xF002) // logicopenable | logicmode - SetLogicOpMode(); + // Set LogicOp Blending Mode + if (bp.changes & 0xF002) // logicopenable | logicmode + SetLogicOpMode(); - // Set Dithering Mode - if (bp.changes & 4) // dither - SetDitherMode(); + // Set Dithering Mode + if (bp.changes & 4) // dither + SetDitherMode(); - // Set Blending Mode - if (bp.changes & 0xFF1) // blendenable | alphaupdate | dstfactor | srcfactor | subtract - SetBlendMode(); + // Set Blending Mode + if (bp.changes & 0xFF1) // blendenable | alphaupdate | dstfactor | srcfactor | subtract + SetBlendMode(); - // Set Color Mask - if (bp.changes & 0x18) // colorupdate | alphaupdate - SetColorMask(); - } - return; - case BPMEM_CONSTANTALPHA: // Set Destination Alpha - PRIM_LOG("constalpha: alp=%d, en=%d", bpmem.dstalpha.alpha, bpmem.dstalpha.enable); - if (bp.changes & 0xFF) - PixelShaderManager::SetDestAlpha(); - if (bp.changes & 0x100) - SetBlendMode(); - return; + // Set Color Mask + if (bp.changes & 0x18) // colorupdate | alphaupdate + SetColorMask(); + } + return; + case BPMEM_CONSTANTALPHA: // Set Destination Alpha + PRIM_LOG("constalpha: alp=%d, en=%d", bpmem.dstalpha.alpha, bpmem.dstalpha.enable); + if (bp.changes & 0xFF) + PixelShaderManager::SetDestAlpha(); + if (bp.changes & 0x100) + SetBlendMode(); + return; - // This is called when the game is done drawing the new frame (eg: like in DX: Begin(); Draw(); End();) - // Triggers an interrupt on the PPC side so that the game knows when the GPU has finished drawing. - // Tokens are similar. - case BPMEM_SETDRAWDONE: - switch (bp.newvalue & 0xFF) - { - case 0x02: - if (!Fifo::UseDeterministicGPUThread()) - PixelEngine::SetFinish(); // may generate interrupt - DEBUG_LOG(VIDEO, "GXSetDrawDone SetPEFinish (value: 0x%02X)", (bp.newvalue & 0xFFFF)); - return; + // This is called when the game is done drawing the new frame (eg: like in DX: Begin(); Draw(); + // End();) + // Triggers an interrupt on the PPC side so that the game knows when the GPU has finished drawing. + // Tokens are similar. + case BPMEM_SETDRAWDONE: + switch (bp.newvalue & 0xFF) + { + case 0x02: + if (!Fifo::UseDeterministicGPUThread()) + PixelEngine::SetFinish(); // may generate interrupt + DEBUG_LOG(VIDEO, "GXSetDrawDone SetPEFinish (value: 0x%02X)", (bp.newvalue & 0xFFFF)); + return; - default: - WARN_LOG(VIDEO, "GXSetDrawDone ??? (value 0x%02X)", (bp.newvalue & 0xFFFF)); - return; - } - return; - case BPMEM_PE_TOKEN_ID: // Pixel Engine Token ID - if (!Fifo::UseDeterministicGPUThread()) - PixelEngine::SetToken(static_cast(bp.newvalue & 0xFFFF), false); - DEBUG_LOG(VIDEO, "SetPEToken 0x%04x", (bp.newvalue & 0xFFFF)); - return; - case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID - if (!Fifo::UseDeterministicGPUThread()) - PixelEngine::SetToken(static_cast(bp.newvalue & 0xFFFF), true); - DEBUG_LOG(VIDEO, "SetPEToken + INT 0x%04x", (bp.newvalue & 0xFFFF)); - return; + default: + WARN_LOG(VIDEO, "GXSetDrawDone ??? (value 0x%02X)", (bp.newvalue & 0xFFFF)); + return; + } + return; + case BPMEM_PE_TOKEN_ID: // Pixel Engine Token ID + if (!Fifo::UseDeterministicGPUThread()) + PixelEngine::SetToken(static_cast(bp.newvalue & 0xFFFF), false); + DEBUG_LOG(VIDEO, "SetPEToken 0x%04x", (bp.newvalue & 0xFFFF)); + return; + case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID + if (!Fifo::UseDeterministicGPUThread()) + PixelEngine::SetToken(static_cast(bp.newvalue & 0xFFFF), true); + DEBUG_LOG(VIDEO, "SetPEToken + INT 0x%04x", (bp.newvalue & 0xFFFF)); + return; - // ------------------------ - // EFB copy command. This copies a rectangle from the EFB to either RAM in a texture format or to XFB as YUYV. - // It can also optionally clear the EFB while copying from it. To emulate this, we of course copy first and clear afterwards. - case BPMEM_TRIGGER_EFB_COPY: // Copy EFB Region or Render to the XFB or Clear the screen. - { - // The bottom right is within the rectangle - // The values in bpmem.copyTexSrcXY and bpmem.copyTexSrcWH are updated in case 0x49 and 0x4a in this function + // ------------------------ + // EFB copy command. This copies a rectangle from the EFB to either RAM in a texture format or to + // XFB as YUYV. + // It can also optionally clear the EFB while copying from it. To emulate this, we of course copy + // first and clear afterwards. + case BPMEM_TRIGGER_EFB_COPY: // Copy EFB Region or Render to the XFB or Clear the screen. + { + // The bottom right is within the rectangle + // The values in bpmem.copyTexSrcXY and bpmem.copyTexSrcWH are updated in case 0x49 and 0x4a in + // this function - u32 destAddr = bpmem.copyTexDest << 5; - u32 destStride = bpmem.copyMipMapStrideChannels << 5; + u32 destAddr = bpmem.copyTexDest << 5; + u32 destStride = bpmem.copyMipMapStrideChannels << 5; - EFBRectangle srcRect; - srcRect.left = (int)bpmem.copyTexSrcXY.x; - srcRect.top = (int)bpmem.copyTexSrcXY.y; + EFBRectangle srcRect; + srcRect.left = (int)bpmem.copyTexSrcXY.x; + srcRect.top = (int)bpmem.copyTexSrcXY.y; - // Here Width+1 like Height, otherwise some textures are corrupted already since the native resolution. - // TODO: What's the behavior of out of bound access? - srcRect.right = (int)(bpmem.copyTexSrcXY.x + bpmem.copyTexSrcWH.x + 1); - srcRect.bottom = (int)(bpmem.copyTexSrcXY.y + bpmem.copyTexSrcWH.y + 1); + // Here Width+1 like Height, otherwise some textures are corrupted already since the native + // resolution. + // TODO: What's the behavior of out of bound access? + srcRect.right = (int)(bpmem.copyTexSrcXY.x + bpmem.copyTexSrcWH.x + 1); + srcRect.bottom = (int)(bpmem.copyTexSrcXY.y + bpmem.copyTexSrcWH.y + 1); - UPE_Copy PE_copy = bpmem.triggerEFBCopy; + UPE_Copy PE_copy = bpmem.triggerEFBCopy; - // Check if we are to copy from the EFB or draw to the XFB - if (PE_copy.copy_to_xfb == 0) - { - // bpmem.zcontrol.pixel_format to PEControl::Z24 is when the game wants to copy from ZBuffer (Zbuffer uses 24-bit Format) - TextureCacheBase::CopyRenderTargetToTexture(destAddr, PE_copy.tp_realFormat(), destStride, - bpmem.zcontrol.pixel_format, srcRect, - !!PE_copy.intensity_fmt, !!PE_copy.half_scale); - } - else - { - // We should be able to get away with deactivating the current bbox tracking - // here. Not sure if there's a better spot to put this. - // the number of lines copied is determined by the y scale * source efb height + // Check if we are to copy from the EFB or draw to the XFB + if (PE_copy.copy_to_xfb == 0) + { + // bpmem.zcontrol.pixel_format to PEControl::Z24 is when the game wants to copy from ZBuffer + // (Zbuffer uses 24-bit Format) + TextureCacheBase::CopyRenderTargetToTexture(destAddr, PE_copy.tp_realFormat(), destStride, + bpmem.zcontrol.pixel_format, srcRect, + !!PE_copy.intensity_fmt, !!PE_copy.half_scale); + } + else + { + // We should be able to get away with deactivating the current bbox tracking + // here. Not sure if there's a better spot to put this. + // the number of lines copied is determined by the y scale * source efb height - BoundingBox::active = false; + BoundingBox::active = false; - float yScale; - if (PE_copy.scale_invert) - yScale = 256.0f / (float)bpmem.dispcopyyscale; - else - yScale = (float)bpmem.dispcopyyscale / 256.0f; + float yScale; + if (PE_copy.scale_invert) + yScale = 256.0f / (float)bpmem.dispcopyyscale; + else + yScale = (float)bpmem.dispcopyyscale / 256.0f; - float num_xfb_lines = 1.0f + bpmem.copyTexSrcWH.y * yScale; + float num_xfb_lines = 1.0f + bpmem.copyTexSrcWH.y * yScale; - u32 height = static_cast(num_xfb_lines); - if (height > MAX_XFB_HEIGHT) - { - INFO_LOG(VIDEO, "Tried to scale EFB to too many XFB lines: %d (%f)", - height, num_xfb_lines); - height = MAX_XFB_HEIGHT; - } + u32 height = static_cast(num_xfb_lines); + if (height > MAX_XFB_HEIGHT) + { + INFO_LOG(VIDEO, "Tried to scale EFB to too many XFB lines: %d (%f)", height, num_xfb_lines); + height = MAX_XFB_HEIGHT; + } - DEBUG_LOG(VIDEO, "RenderToXFB: destAddr: %08x | srcRect {%d %d %d %d} | fbWidth: %u | fbStride: %u | fbHeight: %u", - destAddr, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom, bpmem.copyTexSrcWH.x + 1, destStride, height); - Renderer::RenderToXFB(destAddr, srcRect, destStride, height, s_gammaLUT[PE_copy.gamma]); - } + DEBUG_LOG(VIDEO, "RenderToXFB: destAddr: %08x | srcRect {%d %d %d %d} | fbWidth: %u | " + "fbStride: %u | fbHeight: %u", + destAddr, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom, + bpmem.copyTexSrcWH.x + 1, destStride, height); + Renderer::RenderToXFB(destAddr, srcRect, destStride, height, s_gammaLUT[PE_copy.gamma]); + } - // Clear the rectangular region after copying it. - if (PE_copy.clear) - { - ClearScreen(srcRect); - } + // Clear the rectangular region after copying it. + if (PE_copy.clear) + { + ClearScreen(srcRect); + } - return; - } - case BPMEM_LOADTLUT0: // This one updates bpmem.tlutXferSrc, no need to do anything here. - return; - case BPMEM_LOADTLUT1: // Load a Texture Look Up Table - { - u32 tlutTMemAddr = (bp.newvalue & 0x3FF) << 9; - u32 tlutXferCount = (bp.newvalue & 0x1FFC00) >> 5; - u32 addr = bpmem.tmem_config.tlut_src << 5; + return; + } + case BPMEM_LOADTLUT0: // This one updates bpmem.tlutXferSrc, no need to do anything here. + return; + case BPMEM_LOADTLUT1: // Load a Texture Look Up Table + { + u32 tlutTMemAddr = (bp.newvalue & 0x3FF) << 9; + u32 tlutXferCount = (bp.newvalue & 0x1FFC00) >> 5; + u32 addr = bpmem.tmem_config.tlut_src << 5; - // The GameCube ignores the upper bits of this address. Some games (WW, MKDD) set them. - if (!SConfig::GetInstance().bWii) - addr = addr & 0x01FFFFFF; + // The GameCube ignores the upper bits of this address. Some games (WW, MKDD) set them. + if (!SConfig::GetInstance().bWii) + addr = addr & 0x01FFFFFF; - Memory::CopyFromEmu(texMem + tlutTMemAddr, addr, tlutXferCount); + Memory::CopyFromEmu(texMem + tlutTMemAddr, addr, tlutXferCount); - if (g_bRecordFifoData) - FifoRecorder::GetInstance().UseMemory(addr, tlutXferCount, MemoryUpdate::TMEM); + if (g_bRecordFifoData) + FifoRecorder::GetInstance().UseMemory(addr, tlutXferCount, MemoryUpdate::TMEM); - return; - } - case BPMEM_FOGRANGE: // Fog Settings Control - case BPMEM_FOGRANGE+1: - case BPMEM_FOGRANGE+2: - case BPMEM_FOGRANGE+3: - case BPMEM_FOGRANGE+4: - case BPMEM_FOGRANGE+5: - if (bp.changes) - PixelShaderManager::SetFogRangeAdjustChanged(); - return; - case BPMEM_FOGPARAM0: - case BPMEM_FOGBMAGNITUDE: - case BPMEM_FOGBEXPONENT: - case BPMEM_FOGPARAM3: - if (bp.changes) - PixelShaderManager::SetFogParamChanged(); - return; - case BPMEM_FOGCOLOR: // Fog Color - if (bp.changes) - PixelShaderManager::SetFogColorChanged(); - return; - case BPMEM_ALPHACOMPARE: // Compare Alpha Values - PRIM_LOG("alphacmp: ref0=%d, ref1=%d, comp0=%d, comp1=%d, logic=%d", - (int)bpmem.alpha_test.ref0, (int)bpmem.alpha_test.ref1, - (int)bpmem.alpha_test.comp0, (int)bpmem.alpha_test.comp1, - (int)bpmem.alpha_test.logic); - if (bp.changes & 0xFFFF) - PixelShaderManager::SetAlpha(); - if (bp.changes) - g_renderer->SetColorMask(); - return; - case BPMEM_BIAS: // BIAS - PRIM_LOG("ztex bias=0x%x", bpmem.ztex1.bias); - if (bp.changes) - PixelShaderManager::SetZTextureBias(); - return; - case BPMEM_ZTEX2: // Z Texture type - { - if (bp.changes & 3) - PixelShaderManager::SetZTextureTypeChanged(); - #if defined(_DEBUG) || defined(DEBUGFAST) - const char* pzop[] = {"DISABLE", "ADD", "REPLACE", "?"}; - const char* pztype[] = {"Z8", "Z16", "Z24", "?"}; - PRIM_LOG("ztex op=%s, type=%s", pzop[bpmem.ztex2.op], pztype[bpmem.ztex2.type]); - #endif - } - return; - // ---------------------------------- - // Display Copy Filtering Control - GX_SetCopyFilter(u8 aa,u8 sample_pattern[12][2],u8 vf,u8 vfilter[7]) - // Fields: Destination, Frame2Field, Gamma, Source - // ---------------------------------- - case BPMEM_DISPLAYCOPYFILTER: // if (aa) { use sample_pattern } else { use 666666 } - case BPMEM_DISPLAYCOPYFILTER+1: // if (aa) { use sample_pattern } else { use 666666 } - case BPMEM_DISPLAYCOPYFILTER+2: // if (aa) { use sample_pattern } else { use 666666 } - case BPMEM_DISPLAYCOPYFILTER+3: // if (aa) { use sample_pattern } else { use 666666 } - case BPMEM_COPYFILTER0: // if (vf) { use vfilter } else { use 595000 } - case BPMEM_COPYFILTER1: // if (vf) { use vfilter } else { use 000015 } - return; - // ----------------------------------- - // Interlacing Control - // ----------------------------------- - case BPMEM_FIELDMASK: // GX_SetFieldMask(u8 even_mask,u8 odd_mask) - case BPMEM_FIELDMODE: // GX_SetFieldMode(u8 field_mode,u8 half_aspect_ratio) - // TODO - return; - // ---------------------------------------- - // Unimportant regs (Clock, Perf, ...) - // ---------------------------------------- - case BPMEM_BUSCLOCK0: // TB Bus Clock ? - case BPMEM_BUSCLOCK1: // TB Bus Clock ? - case BPMEM_PERF0_TRI: // Perf: Triangles - case BPMEM_PERF0_QUAD: // Perf: Quads - case BPMEM_PERF1: // Perf: Some Clock, Texels, TX, TC - break; - // ---------------- - // EFB Copy config - // ---------------- - case BPMEM_EFB_TL: // EFB Source Rect. Top, Left - case BPMEM_EFB_BR: // EFB Source Rect. Bottom, Right (w, h - 1) - case BPMEM_EFB_ADDR: // EFB Target Address - return; - // -------------- - // Clear Config - // -------------- - case BPMEM_CLEAR_AR: // Alpha and Red Components - case BPMEM_CLEAR_GB: // Green and Blue Components - case BPMEM_CLEAR_Z: // Z Components (24-bit Zbuffer) - return; - // ------------------------- - // Bounding Box Control - // ------------------------- - case BPMEM_CLEARBBOX1: - case BPMEM_CLEARBBOX2: - // Don't compute bounding box if this frame is being skipped! - // Wrong but valid values are better than bogus values... - if (!Fifo::WillSkipCurrentFrame()) - { - u8 offset = bp.address & 2; - BoundingBox::active = true; + return; + } + case BPMEM_FOGRANGE: // Fog Settings Control + case BPMEM_FOGRANGE + 1: + case BPMEM_FOGRANGE + 2: + case BPMEM_FOGRANGE + 3: + case BPMEM_FOGRANGE + 4: + case BPMEM_FOGRANGE + 5: + if (bp.changes) + PixelShaderManager::SetFogRangeAdjustChanged(); + return; + case BPMEM_FOGPARAM0: + case BPMEM_FOGBMAGNITUDE: + case BPMEM_FOGBEXPONENT: + case BPMEM_FOGPARAM3: + if (bp.changes) + PixelShaderManager::SetFogParamChanged(); + return; + case BPMEM_FOGCOLOR: // Fog Color + if (bp.changes) + PixelShaderManager::SetFogColorChanged(); + return; + case BPMEM_ALPHACOMPARE: // Compare Alpha Values + PRIM_LOG("alphacmp: ref0=%d, ref1=%d, comp0=%d, comp1=%d, logic=%d", (int)bpmem.alpha_test.ref0, + (int)bpmem.alpha_test.ref1, (int)bpmem.alpha_test.comp0, (int)bpmem.alpha_test.comp1, + (int)bpmem.alpha_test.logic); + if (bp.changes & 0xFFFF) + PixelShaderManager::SetAlpha(); + if (bp.changes) + g_renderer->SetColorMask(); + return; + case BPMEM_BIAS: // BIAS + PRIM_LOG("ztex bias=0x%x", bpmem.ztex1.bias); + if (bp.changes) + PixelShaderManager::SetZTextureBias(); + return; + case BPMEM_ZTEX2: // Z Texture type + { + if (bp.changes & 3) + PixelShaderManager::SetZTextureTypeChanged(); +#if defined(_DEBUG) || defined(DEBUGFAST) + const char* pzop[] = {"DISABLE", "ADD", "REPLACE", "?"}; + const char* pztype[] = {"Z8", "Z16", "Z24", "?"}; + PRIM_LOG("ztex op=%s, type=%s", pzop[bpmem.ztex2.op], pztype[bpmem.ztex2.type]); +#endif + } + return; + // ---------------------------------- + // Display Copy Filtering Control - GX_SetCopyFilter(u8 aa,u8 sample_pattern[12][2],u8 vf,u8 + // vfilter[7]) + // Fields: Destination, Frame2Field, Gamma, Source + // ---------------------------------- + case BPMEM_DISPLAYCOPYFILTER: // if (aa) { use sample_pattern } else { use 666666 } + case BPMEM_DISPLAYCOPYFILTER + 1: // if (aa) { use sample_pattern } else { use 666666 } + case BPMEM_DISPLAYCOPYFILTER + 2: // if (aa) { use sample_pattern } else { use 666666 } + case BPMEM_DISPLAYCOPYFILTER + 3: // if (aa) { use sample_pattern } else { use 666666 } + case BPMEM_COPYFILTER0: // if (vf) { use vfilter } else { use 595000 } + case BPMEM_COPYFILTER1: // if (vf) { use vfilter } else { use 000015 } + return; + // ----------------------------------- + // Interlacing Control + // ----------------------------------- + case BPMEM_FIELDMASK: // GX_SetFieldMask(u8 even_mask,u8 odd_mask) + case BPMEM_FIELDMODE: // GX_SetFieldMode(u8 field_mode,u8 half_aspect_ratio) + // TODO + return; + // ---------------------------------------- + // Unimportant regs (Clock, Perf, ...) + // ---------------------------------------- + case BPMEM_BUSCLOCK0: // TB Bus Clock ? + case BPMEM_BUSCLOCK1: // TB Bus Clock ? + case BPMEM_PERF0_TRI: // Perf: Triangles + case BPMEM_PERF0_QUAD: // Perf: Quads + case BPMEM_PERF1: // Perf: Some Clock, Texels, TX, TC + break; + // ---------------- + // EFB Copy config + // ---------------- + case BPMEM_EFB_TL: // EFB Source Rect. Top, Left + case BPMEM_EFB_BR: // EFB Source Rect. Bottom, Right (w, h - 1) + case BPMEM_EFB_ADDR: // EFB Target Address + return; + // -------------- + // Clear Config + // -------------- + case BPMEM_CLEAR_AR: // Alpha and Red Components + case BPMEM_CLEAR_GB: // Green and Blue Components + case BPMEM_CLEAR_Z: // Z Components (24-bit Zbuffer) + return; + // ------------------------- + // Bounding Box Control + // ------------------------- + case BPMEM_CLEARBBOX1: + case BPMEM_CLEARBBOX2: + // Don't compute bounding box if this frame is being skipped! + // Wrong but valid values are better than bogus values... + if (!Fifo::WillSkipCurrentFrame()) + { + u8 offset = bp.address & 2; + BoundingBox::active = true; - if (g_ActiveConfig.backend_info.bSupportsBBox && g_ActiveConfig.bBBoxEnable) - { - g_renderer->BBoxWrite(offset, bp.newvalue & 0x3ff); - g_renderer->BBoxWrite(offset + 1, bp.newvalue >> 10); - } - } - return; - case BPMEM_TEXINVALIDATE: - // TODO: Needs some restructuring in TextureCacheBase. - return; + if (g_ActiveConfig.backend_info.bSupportsBBox && g_ActiveConfig.bBBoxEnable) + { + g_renderer->BBoxWrite(offset, bp.newvalue & 0x3ff); + g_renderer->BBoxWrite(offset + 1, bp.newvalue >> 10); + } + } + return; + case BPMEM_TEXINVALIDATE: + // TODO: Needs some restructuring in TextureCacheBase. + return; - case BPMEM_ZCOMPARE: // Set the Z-Compare and EFB pixel format - OnPixelFormatChange(); - if (bp.changes & 7) - { - SetBlendMode(); // dual source could be activated by changing to PIXELFMT_RGBA6_Z24 - g_renderer->SetColorMask(); // alpha writing needs to be disabled if the new pixel format doesn't have an alpha channel - } - return; + case BPMEM_ZCOMPARE: // Set the Z-Compare and EFB pixel format + OnPixelFormatChange(); + if (bp.changes & 7) + { + SetBlendMode(); // dual source could be activated by changing to PIXELFMT_RGBA6_Z24 + g_renderer->SetColorMask(); // alpha writing needs to be disabled if the new pixel format + // doesn't have an alpha channel + } + return; - case BPMEM_MIPMAP_STRIDE: // MipMap Stride Channel - case BPMEM_COPYYSCALE: // Display Copy Y Scale + case BPMEM_MIPMAP_STRIDE: // MipMap Stride Channel + case BPMEM_COPYYSCALE: // Display Copy Y Scale - /* 24 RID - * 21 BC3 - Ind. Tex Stage 3 NTexCoord - * 18 BI3 - Ind. Tex Stage 3 NTexMap - * 15 BC2 - Ind. Tex Stage 2 NTexCoord - * 12 BI2 - Ind. Tex Stage 2 NTexMap - * 9 BC1 - Ind. Tex Stage 1 NTexCoord - * 6 BI1 - Ind. Tex Stage 1 NTexMap - * 3 BC0 - Ind. Tex Stage 0 NTexCoord - * 0 BI0 - Ind. Tex Stage 0 NTexMap */ - case BPMEM_IREF: + /* 24 RID + * 21 BC3 - Ind. Tex Stage 3 NTexCoord + * 18 BI3 - Ind. Tex Stage 3 NTexMap + * 15 BC2 - Ind. Tex Stage 2 NTexCoord + * 12 BI2 - Ind. Tex Stage 2 NTexMap + * 9 BC1 - Ind. Tex Stage 1 NTexCoord + * 6 BI1 - Ind. Tex Stage 1 NTexMap + * 3 BC0 - Ind. Tex Stage 0 NTexCoord + * 0 BI0 - Ind. Tex Stage 0 NTexMap */ + case BPMEM_IREF: - case BPMEM_TEV_KSEL: // Texture Environment Swap Mode Table 0 - case BPMEM_TEV_KSEL+1: // Texture Environment Swap Mode Table 1 - case BPMEM_TEV_KSEL+2: // Texture Environment Swap Mode Table 2 - case BPMEM_TEV_KSEL+3: // Texture Environment Swap Mode Table 3 - case BPMEM_TEV_KSEL+4: // Texture Environment Swap Mode Table 4 - case BPMEM_TEV_KSEL+5: // Texture Environment Swap Mode Table 5 - case BPMEM_TEV_KSEL+6: // Texture Environment Swap Mode Table 6 - case BPMEM_TEV_KSEL+7: // Texture Environment Swap Mode Table 7 + case BPMEM_TEV_KSEL: // Texture Environment Swap Mode Table 0 + case BPMEM_TEV_KSEL + 1: // Texture Environment Swap Mode Table 1 + case BPMEM_TEV_KSEL + 2: // Texture Environment Swap Mode Table 2 + case BPMEM_TEV_KSEL + 3: // Texture Environment Swap Mode Table 3 + case BPMEM_TEV_KSEL + 4: // Texture Environment Swap Mode Table 4 + case BPMEM_TEV_KSEL + 5: // Texture Environment Swap Mode Table 5 + case BPMEM_TEV_KSEL + 6: // Texture Environment Swap Mode Table 6 + case BPMEM_TEV_KSEL + 7: // Texture Environment Swap Mode Table 7 - /* This Register can be used to limit to which bits of BP registers is - * actually written to. The mask is only valid for the next BP write, - * and will reset itself afterwards. It's handled as a special case in - * LoadBPReg. */ - case BPMEM_BP_MASK: + /* This Register can be used to limit to which bits of BP registers is + * actually written to. The mask is only valid for the next BP write, + * and will reset itself afterwards. It's handled as a special case in + * LoadBPReg. */ + case BPMEM_BP_MASK: - case BPMEM_IND_IMASK: // Index Mask ? - case BPMEM_REVBITS: // Always set to 0x0F when GX_InitRevBits() is called. - return; + case BPMEM_IND_IMASK: // Index Mask ? + case BPMEM_REVBITS: // Always set to 0x0F when GX_InitRevBits() is called. + return; - case BPMEM_CLEAR_PIXEL_PERF: - // GXClearPixMetric writes 0xAAA here, Sunshine alternates this register between values 0x000 and 0xAAA - if (PerfQueryBase::ShouldEmulate()) - g_perf_query->ResetQuery(); - return; + case BPMEM_CLEAR_PIXEL_PERF: + // GXClearPixMetric writes 0xAAA here, Sunshine alternates this register between values 0x000 + // and 0xAAA + if (PerfQueryBase::ShouldEmulate()) + g_perf_query->ResetQuery(); + return; - case BPMEM_PRELOAD_ADDR: - case BPMEM_PRELOAD_TMEMEVEN: - case BPMEM_PRELOAD_TMEMODD: // Used when PRELOAD_MODE is set - return; + case BPMEM_PRELOAD_ADDR: + case BPMEM_PRELOAD_TMEMEVEN: + case BPMEM_PRELOAD_TMEMODD: // Used when PRELOAD_MODE is set + return; - case BPMEM_PRELOAD_MODE: // Set to 0 when GX_TexModeSync() is called. - // if this is different from 0, manual TMEM management is used (GX_PreloadEntireTexture). - if (bp.newvalue != 0) - { - // TODO: Not quite sure if this is completely correct (likely not) - // NOTE: libogc's implementation of GX_PreloadEntireTexture seems flawed, so it's not necessarily a good reference for RE'ing this feature. + case BPMEM_PRELOAD_MODE: // Set to 0 when GX_TexModeSync() is called. + // if this is different from 0, manual TMEM management is used (GX_PreloadEntireTexture). + if (bp.newvalue != 0) + { + // TODO: Not quite sure if this is completely correct (likely not) + // NOTE: libogc's implementation of GX_PreloadEntireTexture seems flawed, so it's not + // necessarily a good reference for RE'ing this feature. - BPS_TmemConfig& tmem_cfg = bpmem.tmem_config; - u32 src_addr = tmem_cfg.preload_addr << 5; // TODO: Should we add mask here on GC? - u32 bytes_read = 0; - u32 tmem_addr_even = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE; + BPS_TmemConfig& tmem_cfg = bpmem.tmem_config; + u32 src_addr = tmem_cfg.preload_addr << 5; // TODO: Should we add mask here on GC? + u32 bytes_read = 0; + u32 tmem_addr_even = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE; - if (tmem_cfg.preload_tile_info.type != 3) - { - bytes_read = tmem_cfg.preload_tile_info.count * TMEM_LINE_SIZE; - if (tmem_addr_even + bytes_read > TMEM_SIZE) - bytes_read = TMEM_SIZE - tmem_addr_even; + if (tmem_cfg.preload_tile_info.type != 3) + { + bytes_read = tmem_cfg.preload_tile_info.count * TMEM_LINE_SIZE; + if (tmem_addr_even + bytes_read > TMEM_SIZE) + bytes_read = TMEM_SIZE - tmem_addr_even; - Memory::CopyFromEmu(texMem + tmem_addr_even, src_addr, bytes_read); - } - else // RGBA8 tiles (and CI14, but that might just be stupid libogc!) - { - u8* src_ptr = Memory::GetPointer(src_addr); + Memory::CopyFromEmu(texMem + tmem_addr_even, src_addr, bytes_read); + } + else // RGBA8 tiles (and CI14, but that might just be stupid libogc!) + { + u8* src_ptr = Memory::GetPointer(src_addr); - // AR and GB tiles are stored in separate TMEM banks => can't use a single memcpy for everything - u32 tmem_addr_odd = tmem_cfg.preload_tmem_odd * TMEM_LINE_SIZE; + // AR and GB tiles are stored in separate TMEM banks => can't use a single memcpy for + // everything + u32 tmem_addr_odd = tmem_cfg.preload_tmem_odd * TMEM_LINE_SIZE; - for (u32 i = 0; i < tmem_cfg.preload_tile_info.count; ++i) - { - if (tmem_addr_even + TMEM_LINE_SIZE > TMEM_SIZE || tmem_addr_odd + TMEM_LINE_SIZE > TMEM_SIZE) - break; + for (u32 i = 0; i < tmem_cfg.preload_tile_info.count; ++i) + { + if (tmem_addr_even + TMEM_LINE_SIZE > TMEM_SIZE || + tmem_addr_odd + TMEM_LINE_SIZE > TMEM_SIZE) + break; - memcpy(texMem + tmem_addr_even, src_ptr + bytes_read, TMEM_LINE_SIZE); - memcpy(texMem + tmem_addr_odd, src_ptr + bytes_read + TMEM_LINE_SIZE, TMEM_LINE_SIZE); - tmem_addr_even += TMEM_LINE_SIZE; - tmem_addr_odd += TMEM_LINE_SIZE; - bytes_read += TMEM_LINE_SIZE * 2; - } - } + memcpy(texMem + tmem_addr_even, src_ptr + bytes_read, TMEM_LINE_SIZE); + memcpy(texMem + tmem_addr_odd, src_ptr + bytes_read + TMEM_LINE_SIZE, TMEM_LINE_SIZE); + tmem_addr_even += TMEM_LINE_SIZE; + tmem_addr_odd += TMEM_LINE_SIZE; + bytes_read += TMEM_LINE_SIZE * 2; + } + } - if (g_bRecordFifoData) - FifoRecorder::GetInstance().UseMemory(src_addr, bytes_read, MemoryUpdate::TMEM); - } - return; + if (g_bRecordFifoData) + FifoRecorder::GetInstance().UseMemory(src_addr, bytes_read, MemoryUpdate::TMEM); + } + return; - // --------------------------------------------------- - // Set the TEV Color - // --------------------------------------------------- - // - // NOTE: Each of these registers actually maps to two variables internally. - // There's a bit that specifies which one is currently written to. - // - // NOTE: Some games write only to the RA register (or only to the BG register). - // We may not assume that the unwritten register holds a valid value, hence - // both component pairs need to be loaded individually. - case BPMEM_TEV_COLOR_RA: - case BPMEM_TEV_COLOR_RA + 2: - case BPMEM_TEV_COLOR_RA + 4: - case BPMEM_TEV_COLOR_RA + 6: - { - int num = (bp.address >> 1) & 0x3; - if (bpmem.tevregs[num].type_ra) - { - PixelShaderManager::SetTevKonstColor(num, 0, (s32)bpmem.tevregs[num].red); - PixelShaderManager::SetTevKonstColor(num, 3, (s32)bpmem.tevregs[num].alpha); - } - else - { - PixelShaderManager::SetTevColor(num, 0, (s32)bpmem.tevregs[num].red); - PixelShaderManager::SetTevColor(num, 3, (s32)bpmem.tevregs[num].alpha); - } - return; - } + // --------------------------------------------------- + // Set the TEV Color + // --------------------------------------------------- + // + // NOTE: Each of these registers actually maps to two variables internally. + // There's a bit that specifies which one is currently written to. + // + // NOTE: Some games write only to the RA register (or only to the BG register). + // We may not assume that the unwritten register holds a valid value, hence + // both component pairs need to be loaded individually. + case BPMEM_TEV_COLOR_RA: + case BPMEM_TEV_COLOR_RA + 2: + case BPMEM_TEV_COLOR_RA + 4: + case BPMEM_TEV_COLOR_RA + 6: + { + int num = (bp.address >> 1) & 0x3; + if (bpmem.tevregs[num].type_ra) + { + PixelShaderManager::SetTevKonstColor(num, 0, (s32)bpmem.tevregs[num].red); + PixelShaderManager::SetTevKonstColor(num, 3, (s32)bpmem.tevregs[num].alpha); + } + else + { + PixelShaderManager::SetTevColor(num, 0, (s32)bpmem.tevregs[num].red); + PixelShaderManager::SetTevColor(num, 3, (s32)bpmem.tevregs[num].alpha); + } + return; + } - case BPMEM_TEV_COLOR_BG: - case BPMEM_TEV_COLOR_BG + 2: - case BPMEM_TEV_COLOR_BG + 4: - case BPMEM_TEV_COLOR_BG + 6: - { - int num = (bp.address >> 1) & 0x3; - if (bpmem.tevregs[num].type_bg) - { - PixelShaderManager::SetTevKonstColor(num, 1, (s32)bpmem.tevregs[num].green); - PixelShaderManager::SetTevKonstColor(num, 2, (s32)bpmem.tevregs[num].blue); - } - else - { - PixelShaderManager::SetTevColor(num, 1, (s32)bpmem.tevregs[num].green); - PixelShaderManager::SetTevColor(num, 2, (s32)bpmem.tevregs[num].blue); - } - return; - } + case BPMEM_TEV_COLOR_BG: + case BPMEM_TEV_COLOR_BG + 2: + case BPMEM_TEV_COLOR_BG + 4: + case BPMEM_TEV_COLOR_BG + 6: + { + int num = (bp.address >> 1) & 0x3; + if (bpmem.tevregs[num].type_bg) + { + PixelShaderManager::SetTevKonstColor(num, 1, (s32)bpmem.tevregs[num].green); + PixelShaderManager::SetTevKonstColor(num, 2, (s32)bpmem.tevregs[num].blue); + } + else + { + PixelShaderManager::SetTevColor(num, 1, (s32)bpmem.tevregs[num].green); + PixelShaderManager::SetTevColor(num, 2, (s32)bpmem.tevregs[num].blue); + } + return; + } - default: - break; - } + default: + break; + } - switch (bp.address & 0xFC) // Texture sampler filter - { - // ------------------------- - // Texture Environment Order - // ------------------------- - case BPMEM_TREF: - case BPMEM_TREF+4: - return; - // ---------------------- - // Set wrap size - // ---------------------- - case BPMEM_SU_SSIZE: - case BPMEM_SU_TSIZE: - case BPMEM_SU_SSIZE+2: - case BPMEM_SU_TSIZE+2: - case BPMEM_SU_SSIZE+4: - case BPMEM_SU_TSIZE+4: - case BPMEM_SU_SSIZE+6: - case BPMEM_SU_TSIZE+6: - case BPMEM_SU_SSIZE+8: - case BPMEM_SU_TSIZE+8: - case BPMEM_SU_SSIZE+10: - case BPMEM_SU_TSIZE+10: - case BPMEM_SU_SSIZE+12: - case BPMEM_SU_TSIZE+12: - case BPMEM_SU_SSIZE+14: - case BPMEM_SU_TSIZE+14: - if (bp.changes) - { - PixelShaderManager::SetTexCoordChanged((bp.address - BPMEM_SU_SSIZE) >> 1); - GeometryShaderManager::SetTexCoordChanged((bp.address - BPMEM_SU_SSIZE) >> 1); - } - return; - // ------------------------ - // BPMEM_TX_SETMODE0 - (Texture lookup and filtering mode) LOD/BIAS Clamp, MaxAnsio, LODBIAS, DiagLoad, Min Filter, Mag Filter, Wrap T, S - // BPMEM_TX_SETMODE1 - (LOD Stuff) - Max LOD, Min LOD - // ------------------------ - case BPMEM_TX_SETMODE0: // (0x90 for linear) - case BPMEM_TX_SETMODE0_4: - return; + switch (bp.address & 0xFC) // Texture sampler filter + { + // ------------------------- + // Texture Environment Order + // ------------------------- + case BPMEM_TREF: + case BPMEM_TREF + 4: + return; + // ---------------------- + // Set wrap size + // ---------------------- + case BPMEM_SU_SSIZE: + case BPMEM_SU_TSIZE: + case BPMEM_SU_SSIZE + 2: + case BPMEM_SU_TSIZE + 2: + case BPMEM_SU_SSIZE + 4: + case BPMEM_SU_TSIZE + 4: + case BPMEM_SU_SSIZE + 6: + case BPMEM_SU_TSIZE + 6: + case BPMEM_SU_SSIZE + 8: + case BPMEM_SU_TSIZE + 8: + case BPMEM_SU_SSIZE + 10: + case BPMEM_SU_TSIZE + 10: + case BPMEM_SU_SSIZE + 12: + case BPMEM_SU_TSIZE + 12: + case BPMEM_SU_SSIZE + 14: + case BPMEM_SU_TSIZE + 14: + if (bp.changes) + { + PixelShaderManager::SetTexCoordChanged((bp.address - BPMEM_SU_SSIZE) >> 1); + GeometryShaderManager::SetTexCoordChanged((bp.address - BPMEM_SU_SSIZE) >> 1); + } + return; + // ------------------------ + // BPMEM_TX_SETMODE0 - (Texture lookup and filtering mode) LOD/BIAS Clamp, MaxAnsio, LODBIAS, + // DiagLoad, Min Filter, Mag Filter, Wrap T, S + // BPMEM_TX_SETMODE1 - (LOD Stuff) - Max LOD, Min LOD + // ------------------------ + case BPMEM_TX_SETMODE0: // (0x90 for linear) + case BPMEM_TX_SETMODE0_4: + return; - case BPMEM_TX_SETMODE1: - case BPMEM_TX_SETMODE1_4: - return; - // -------------------------------------------- - // BPMEM_TX_SETIMAGE0 - Texture width, height, format - // BPMEM_TX_SETIMAGE1 - even LOD address in TMEM - Image Type, Cache Height, Cache Width, TMEM Offset - // BPMEM_TX_SETIMAGE2 - odd LOD address in TMEM - Cache Height, Cache Width, TMEM Offset - // BPMEM_TX_SETIMAGE3 - Address of Texture in main memory - // -------------------------------------------- - case BPMEM_TX_SETIMAGE0: - case BPMEM_TX_SETIMAGE0_4: - case BPMEM_TX_SETIMAGE1: - case BPMEM_TX_SETIMAGE1_4: - case BPMEM_TX_SETIMAGE2: - case BPMEM_TX_SETIMAGE2_4: - case BPMEM_TX_SETIMAGE3: - case BPMEM_TX_SETIMAGE3_4: - return; - // ------------------------------- - // Set a TLUT - // BPMEM_TX_SETTLUT - Format, TMEM Offset (offset of TLUT from start of TMEM high bank > > 5) - // ------------------------------- - case BPMEM_TX_SETTLUT: - case BPMEM_TX_SETTLUT_4: - return; + case BPMEM_TX_SETMODE1: + case BPMEM_TX_SETMODE1_4: + return; + // -------------------------------------------- + // BPMEM_TX_SETIMAGE0 - Texture width, height, format + // BPMEM_TX_SETIMAGE1 - even LOD address in TMEM - Image Type, Cache Height, Cache Width, TMEM + // Offset + // BPMEM_TX_SETIMAGE2 - odd LOD address in TMEM - Cache Height, Cache Width, TMEM Offset + // BPMEM_TX_SETIMAGE3 - Address of Texture in main memory + // -------------------------------------------- + case BPMEM_TX_SETIMAGE0: + case BPMEM_TX_SETIMAGE0_4: + case BPMEM_TX_SETIMAGE1: + case BPMEM_TX_SETIMAGE1_4: + case BPMEM_TX_SETIMAGE2: + case BPMEM_TX_SETIMAGE2_4: + case BPMEM_TX_SETIMAGE3: + case BPMEM_TX_SETIMAGE3_4: + return; + // ------------------------------- + // Set a TLUT + // BPMEM_TX_SETTLUT - Format, TMEM Offset (offset of TLUT from start of TMEM high bank > > 5) + // ------------------------------- + case BPMEM_TX_SETTLUT: + case BPMEM_TX_SETTLUT_4: + return; - default: - break; - } + default: + break; + } - switch (bp.address & 0xF0) - { - // -------------- - // Indirect Tev - // -------------- - case BPMEM_IND_CMD: - case BPMEM_IND_CMD+1: - case BPMEM_IND_CMD+2: - case BPMEM_IND_CMD+3: - case BPMEM_IND_CMD+4: - case BPMEM_IND_CMD+5: - case BPMEM_IND_CMD+6: - case BPMEM_IND_CMD+7: - case BPMEM_IND_CMD+8: - case BPMEM_IND_CMD+9: - case BPMEM_IND_CMD+10: - case BPMEM_IND_CMD+11: - case BPMEM_IND_CMD+12: - case BPMEM_IND_CMD+13: - case BPMEM_IND_CMD+14: - case BPMEM_IND_CMD+15: - return; - // -------------------------------------------------- - // Set Color/Alpha of a Tev - // BPMEM_TEV_COLOR_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D - // BPMEM_TEV_ALPHA_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D, T Swap, R Swap - // -------------------------------------------------- - case BPMEM_TEV_COLOR_ENV: // Texture Environment 1 - case BPMEM_TEV_ALPHA_ENV: - case BPMEM_TEV_COLOR_ENV+2: // Texture Environment 2 - case BPMEM_TEV_ALPHA_ENV+2: - case BPMEM_TEV_COLOR_ENV+4: // Texture Environment 3 - case BPMEM_TEV_ALPHA_ENV+4: - case BPMEM_TEV_COLOR_ENV+6: // Texture Environment 4 - case BPMEM_TEV_ALPHA_ENV+6: - case BPMEM_TEV_COLOR_ENV+8: // Texture Environment 5 - case BPMEM_TEV_ALPHA_ENV+8: - case BPMEM_TEV_COLOR_ENV+10: // Texture Environment 6 - case BPMEM_TEV_ALPHA_ENV+10: - case BPMEM_TEV_COLOR_ENV+12: // Texture Environment 7 - case BPMEM_TEV_ALPHA_ENV+12: - case BPMEM_TEV_COLOR_ENV+14: // Texture Environment 8 - case BPMEM_TEV_ALPHA_ENV+14: - case BPMEM_TEV_COLOR_ENV+16: // Texture Environment 9 - case BPMEM_TEV_ALPHA_ENV+16: - case BPMEM_TEV_COLOR_ENV+18: // Texture Environment 10 - case BPMEM_TEV_ALPHA_ENV+18: - case BPMEM_TEV_COLOR_ENV+20: // Texture Environment 11 - case BPMEM_TEV_ALPHA_ENV+20: - case BPMEM_TEV_COLOR_ENV+22: // Texture Environment 12 - case BPMEM_TEV_ALPHA_ENV+22: - case BPMEM_TEV_COLOR_ENV+24: // Texture Environment 13 - case BPMEM_TEV_ALPHA_ENV+24: - case BPMEM_TEV_COLOR_ENV+26: // Texture Environment 14 - case BPMEM_TEV_ALPHA_ENV+26: - case BPMEM_TEV_COLOR_ENV+28: // Texture Environment 15 - case BPMEM_TEV_ALPHA_ENV+28: - case BPMEM_TEV_COLOR_ENV+30: // Texture Environment 16 - case BPMEM_TEV_ALPHA_ENV+30: - return; - default: - break; - } + switch (bp.address & 0xF0) + { + // -------------- + // Indirect Tev + // -------------- + case BPMEM_IND_CMD: + case BPMEM_IND_CMD + 1: + case BPMEM_IND_CMD + 2: + case BPMEM_IND_CMD + 3: + case BPMEM_IND_CMD + 4: + case BPMEM_IND_CMD + 5: + case BPMEM_IND_CMD + 6: + case BPMEM_IND_CMD + 7: + case BPMEM_IND_CMD + 8: + case BPMEM_IND_CMD + 9: + case BPMEM_IND_CMD + 10: + case BPMEM_IND_CMD + 11: + case BPMEM_IND_CMD + 12: + case BPMEM_IND_CMD + 13: + case BPMEM_IND_CMD + 14: + case BPMEM_IND_CMD + 15: + return; + // -------------------------------------------------- + // Set Color/Alpha of a Tev + // BPMEM_TEV_COLOR_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D + // BPMEM_TEV_ALPHA_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D, T Swap, R Swap + // -------------------------------------------------- + case BPMEM_TEV_COLOR_ENV: // Texture Environment 1 + case BPMEM_TEV_ALPHA_ENV: + case BPMEM_TEV_COLOR_ENV + 2: // Texture Environment 2 + case BPMEM_TEV_ALPHA_ENV + 2: + case BPMEM_TEV_COLOR_ENV + 4: // Texture Environment 3 + case BPMEM_TEV_ALPHA_ENV + 4: + case BPMEM_TEV_COLOR_ENV + 6: // Texture Environment 4 + case BPMEM_TEV_ALPHA_ENV + 6: + case BPMEM_TEV_COLOR_ENV + 8: // Texture Environment 5 + case BPMEM_TEV_ALPHA_ENV + 8: + case BPMEM_TEV_COLOR_ENV + 10: // Texture Environment 6 + case BPMEM_TEV_ALPHA_ENV + 10: + case BPMEM_TEV_COLOR_ENV + 12: // Texture Environment 7 + case BPMEM_TEV_ALPHA_ENV + 12: + case BPMEM_TEV_COLOR_ENV + 14: // Texture Environment 8 + case BPMEM_TEV_ALPHA_ENV + 14: + case BPMEM_TEV_COLOR_ENV + 16: // Texture Environment 9 + case BPMEM_TEV_ALPHA_ENV + 16: + case BPMEM_TEV_COLOR_ENV + 18: // Texture Environment 10 + case BPMEM_TEV_ALPHA_ENV + 18: + case BPMEM_TEV_COLOR_ENV + 20: // Texture Environment 11 + case BPMEM_TEV_ALPHA_ENV + 20: + case BPMEM_TEV_COLOR_ENV + 22: // Texture Environment 12 + case BPMEM_TEV_ALPHA_ENV + 22: + case BPMEM_TEV_COLOR_ENV + 24: // Texture Environment 13 + case BPMEM_TEV_ALPHA_ENV + 24: + case BPMEM_TEV_COLOR_ENV + 26: // Texture Environment 14 + case BPMEM_TEV_ALPHA_ENV + 26: + case BPMEM_TEV_COLOR_ENV + 28: // Texture Environment 15 + case BPMEM_TEV_ALPHA_ENV + 28: + case BPMEM_TEV_COLOR_ENV + 30: // Texture Environment 16 + case BPMEM_TEV_ALPHA_ENV + 30: + return; + default: + break; + } - WARN_LOG(VIDEO, "Unknown BP opcode: address = 0x%08x value = 0x%08x", bp.address, bp.newvalue); + WARN_LOG(VIDEO, "Unknown BP opcode: address = 0x%08x value = 0x%08x", bp.address, bp.newvalue); } // Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg() void LoadBPReg(u32 value0) { - int regNum = value0 >> 24; - int oldval = ((u32*)&bpmem)[regNum]; - int newval = (oldval & ~bpmem.bpMask) | (value0 & bpmem.bpMask); - int changes = (oldval ^ newval) & 0xFFFFFF; + int regNum = value0 >> 24; + int oldval = ((u32*)&bpmem)[regNum]; + int newval = (oldval & ~bpmem.bpMask) | (value0 & bpmem.bpMask); + int changes = (oldval ^ newval) & 0xFFFFFF; - BPCmd bp = {regNum, changes, newval}; + BPCmd bp = {regNum, changes, newval}; - // Reset the mask register if we're not trying to set it ourselves. - if (regNum != BPMEM_BP_MASK) - bpmem.bpMask = 0xFFFFFF; + // Reset the mask register if we're not trying to set it ourselves. + if (regNum != BPMEM_BP_MASK) + bpmem.bpMask = 0xFFFFFF; - BPWritten(bp); + BPWritten(bp); } void LoadBPRegPreprocess(u32 value0) { - int regNum = value0 >> 24; - // masking could hypothetically be a problem - u32 newval = value0 & 0xffffff; - switch (regNum) - { - case BPMEM_SETDRAWDONE: - if ((newval & 0xff) == 0x02) - PixelEngine::SetFinish(); - break; - case BPMEM_PE_TOKEN_ID: - PixelEngine::SetToken(newval & 0xffff, false); - break; - case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID - PixelEngine::SetToken(newval & 0xffff, true); - break; - } + int regNum = value0 >> 24; + // masking could hypothetically be a problem + u32 newval = value0 & 0xffffff; + switch (regNum) + { + case BPMEM_SETDRAWDONE: + if ((newval & 0xff) == 0x02) + PixelEngine::SetFinish(); + break; + case BPMEM_PE_TOKEN_ID: + PixelEngine::SetToken(newval & 0xffff, false); + break; + case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID + PixelEngine::SetToken(newval & 0xffff, true); + break; + } } void GetBPRegInfo(const u8* data, std::string* name, std::string* desc) { - const char* no_yes[2] = { "No", "Yes" }; - - u8 cmd = data[0]; - u32 cmddata = Common::swap32(*(u32*)data) & 0xFFFFFF; - switch (cmd) - { - // Macro to set the register name and make sure it was written correctly via compile time assertion - #define SetRegName(reg) \ - *name = #reg; \ - (void)(reg); - - case BPMEM_GENMODE: // 0x00 - SetRegName(BPMEM_GENMODE); - // TODO: Description - break; - - case BPMEM_DISPLAYCOPYFILTER: // 0x01 - // TODO: This is actually the sample pattern used for copies from an antialiased EFB - SetRegName(BPMEM_DISPLAYCOPYFILTER); - // TODO: Description - break; - - case 0x02: // 0x02 - case 0x03: // 0x03 - case 0x04: // 0x04 - // TODO: same as BPMEM_DISPLAYCOPYFILTER - break; - - case BPMEM_IND_MTXA: // 0x06 - case BPMEM_IND_MTXA+3: - case BPMEM_IND_MTXA+6: - SetRegName(BPMEM_IND_MTXA); - // TODO: Description - break; - - case BPMEM_IND_MTXB: // 0x07 - case BPMEM_IND_MTXB+3: - case BPMEM_IND_MTXB+6: - SetRegName(BPMEM_IND_MTXB); - // TODO: Descriptio - break; - - case BPMEM_IND_MTXC: // 0x08 - case BPMEM_IND_MTXC+3: - case BPMEM_IND_MTXC+6: - SetRegName(BPMEM_IND_MTXC); - // TODO: Description - break; - - case BPMEM_IND_IMASK: // 0x0F - SetRegName(BPMEM_IND_IMASK); - // TODO: Description - break; - - case BPMEM_IND_CMD: // 0x10 - case BPMEM_IND_CMD+1: - case BPMEM_IND_CMD+2: - case BPMEM_IND_CMD+3: - case BPMEM_IND_CMD+4: - case BPMEM_IND_CMD+5: - case BPMEM_IND_CMD+6: - case BPMEM_IND_CMD+7: - case BPMEM_IND_CMD+8: - case BPMEM_IND_CMD+9: - case BPMEM_IND_CMD+10: - case BPMEM_IND_CMD+11: - case BPMEM_IND_CMD+12: - case BPMEM_IND_CMD+13: - case BPMEM_IND_CMD+14: - case BPMEM_IND_CMD+15: - SetRegName(BPMEM_IND_CMD); - // TODO: Description - break; - - case BPMEM_SCISSORTL: // 0x20 - SetRegName(BPMEM_SCISSORTL); - // TODO: Description - break; - - case BPMEM_SCISSORBR: // 0x21 - SetRegName(BPMEM_SCISSORBR); - // TODO: Description - break; - - case BPMEM_LINEPTWIDTH: // 0x22 - SetRegName(BPMEM_LINEPTWIDTH); - // TODO: Description - break; - - case BPMEM_PERF0_TRI: // 0x23 - SetRegName(BPMEM_PERF0_TRI); - // TODO: Description - break; - - case BPMEM_PERF0_QUAD: // 0x24 - SetRegName(BPMEM_PERF0_QUAD); - // TODO: Description - break; - - case BPMEM_RAS1_SS0: // 0x25 - SetRegName(BPMEM_RAS1_SS0); - // TODO: Description - break; - - case BPMEM_RAS1_SS1: // 0x26 - SetRegName(BPMEM_RAS1_SS1); - // TODO: Description - break; - - case BPMEM_IREF: // 0x27 - SetRegName(BPMEM_IREF); - // TODO: Description - break; - - case BPMEM_TREF: // 0x28 - case BPMEM_TREF+1: - case BPMEM_TREF+2: - case BPMEM_TREF+3: - case BPMEM_TREF+4: - case BPMEM_TREF+5: - case BPMEM_TREF+6: - case BPMEM_TREF+7: - SetRegName(BPMEM_TREF); - // TODO: Description - break; - - case BPMEM_SU_SSIZE: // 0x30 - case BPMEM_SU_SSIZE+2: - case BPMEM_SU_SSIZE+4: - case BPMEM_SU_SSIZE+6: - case BPMEM_SU_SSIZE+8: - case BPMEM_SU_SSIZE+10: - case BPMEM_SU_SSIZE+12: - case BPMEM_SU_SSIZE+14: - SetRegName(BPMEM_SU_SSIZE); - // TODO: Description - break; - - case BPMEM_SU_TSIZE: // 0x31 - case BPMEM_SU_TSIZE+2: - case BPMEM_SU_TSIZE+4: - case BPMEM_SU_TSIZE+6: - case BPMEM_SU_TSIZE+8: - case BPMEM_SU_TSIZE+10: - case BPMEM_SU_TSIZE+12: - case BPMEM_SU_TSIZE+14: - SetRegName(BPMEM_SU_TSIZE); - // TODO: Description - break; - - case BPMEM_ZMODE: // 0x40 - SetRegName(BPMEM_ZMODE); - // TODO: Description - break; - - case BPMEM_BLENDMODE: // 0x41 - { - SetRegName(BPMEM_BLENDMODE); - BlendMode mode; mode.hex = cmddata; - const char* dstfactors[] = { "0", "1", "src_color", "1-src_color", "src_alpha", "1-src_alpha", "dst_alpha", "1-dst_alpha" }; - const char* srcfactors[] = { "0", "1", "dst_color", "1-dst_color", "src_alpha", "1-src_alpha", "dst_alpha", "1-dst_alpha" }; - const char* logicmodes[] = { "0", "s & d", "s & ~d", "s", "~s & d", "d", "s ^ d", "s | d", "~(s | d)", "~(s ^ d)", "~d", "s | ~d", "~s", "~s | d", "~(s & d)", "1" }; - *desc = StringFromFormat("Enable: %s\n" - "Logic ops: %s\n" - "Dither: %s\n" - "Color write: %s\n" - "Alpha write: %s\n" - "Dest factor: %s\n" - "Source factor: %s\n" - "Subtract: %s\n" - "Logic mode: %s\n", - no_yes[mode.blendenable], no_yes[mode.logicopenable], no_yes[mode.dither], - no_yes[mode.colorupdate], no_yes[mode.alphaupdate], dstfactors[mode.dstfactor], - srcfactors[mode.srcfactor], no_yes[mode.subtract], logicmodes[mode.logicmode]); - } - break; - - case BPMEM_CONSTANTALPHA: // 0x42 - SetRegName(BPMEM_CONSTANTALPHA); - // TODO: Description - break; - - case BPMEM_ZCOMPARE: // 0x43 - { - SetRegName(BPMEM_ZCOMPARE); - PEControl config; config.hex = cmddata; - const char* pixel_formats[] = { "RGB8_Z24", "RGBA6_Z24", "RGB565_Z16", "Z24", "Y8", "U8", "V8", "YUV420" }; - const char* zformats[] = { "linear", "compressed (near)", "compressed (mid)", "compressed (far)", "inv linear", "compressed (inv near)", "compressed (inv mid)", "compressed (inv far)" }; - *desc = StringFromFormat("EFB pixel format: %s\n" - "Depth format: %s\n" - "Early depth test: %s\n", - pixel_formats[config.pixel_format], zformats[config.zformat], no_yes[config.early_ztest]); - } - break; - - case BPMEM_FIELDMASK: // 0x44 - SetRegName(BPMEM_FIELDMASK); - // TODO: Description - break; - - case BPMEM_SETDRAWDONE: // 0x45 - SetRegName(BPMEM_SETDRAWDONE); - // TODO: Description - break; - - case BPMEM_BUSCLOCK0: // 0x46 - SetRegName(BPMEM_BUSCLOCK0); - // TODO: Description - break; - - case BPMEM_PE_TOKEN_ID: // 0x47 - SetRegName(BPMEM_PE_TOKEN_ID); - // TODO: Description - break; - - case BPMEM_PE_TOKEN_INT_ID: // 0x48 - SetRegName(BPMEM_PE_TOKEN_INT_ID); - // TODO: Description - break; - - case BPMEM_EFB_TL: // 0x49 - { - SetRegName(BPMEM_EFB_TL); - X10Y10 left_top; left_top.hex = cmddata; - *desc = StringFromFormat("Left: %d\nTop: %d", left_top.x, left_top.y); - } - break; - - case BPMEM_EFB_BR: // 0x4A - { - // TODO: Misleading name, should be BPMEM_EFB_WH instead - SetRegName(BPMEM_EFB_BR); - X10Y10 width_height; width_height.hex = cmddata; - *desc = StringFromFormat("Width: %d\nHeight: %d", width_height.x+1, width_height.y+1); - } - break; - - case BPMEM_EFB_ADDR: // 0x4B - SetRegName(BPMEM_EFB_ADDR); - *desc = StringFromFormat("Target address (32 byte aligned): 0x%06X", cmddata << 5); - break; - - case BPMEM_MIPMAP_STRIDE: // 0x4D - SetRegName(BPMEM_MIPMAP_STRIDE); - // TODO: Description - break; - - case BPMEM_COPYYSCALE: // 0x4E - SetRegName(BPMEM_COPYYSCALE); - *desc = StringFromFormat("Scaling factor (XFB copy only): 0x%X (%f or inverted %f)", cmddata, (float)cmddata/256.f, 256.f/(float)cmddata); - break; - - case BPMEM_CLEAR_AR: // 0x4F - SetRegName(BPMEM_CLEAR_AR); - *desc = StringFromFormat("Alpha: 0x%02X\nRed: 0x%02X", (cmddata&0xFF00)>>8, cmddata&0xFF); - break; - - case BPMEM_CLEAR_GB: // 0x50 - SetRegName(BPMEM_CLEAR_GB); - *desc = StringFromFormat("Green: 0x%02X\nBlue: 0x%02X", (cmddata&0xFF00)>>8, cmddata&0xFF); - break; - - case BPMEM_CLEAR_Z: // 0x51 - SetRegName(BPMEM_CLEAR_Z); - *desc = StringFromFormat("Z value: 0x%06X", cmddata); - break; - - case BPMEM_TRIGGER_EFB_COPY: // 0x52 - { - SetRegName(BPMEM_TRIGGER_EFB_COPY); - UPE_Copy copy; copy.Hex = cmddata; - *desc = StringFromFormat("Clamping: %s\n" - "Converting from RGB to YUV: %s\n" - "Target pixel format: 0x%X\n" - "Gamma correction: %s\n" - "Mipmap filter: %s\n" - "Vertical scaling: %s\n" - "Clear: %s\n" - "Frame to field: 0x%01X\n" - "Copy to XFB: %s\n" - "Intensity format: %s\n" - "Automatic color conversion: %s", - (copy.clamp0 && copy.clamp1) ? "Top and Bottom" : (copy.clamp0) ? "Top only" : (copy.clamp1) ? "Bottom only" : "None", - no_yes[copy.yuv], - copy.tp_realFormat(), - (copy.gamma==0)?"1.0":(copy.gamma==1)?"1.7":(copy.gamma==2)?"2.2":"Invalid value 0x3?", - no_yes[copy.half_scale], - no_yes[copy.scale_invert], - no_yes[copy.clear], - (u32)copy.frame_to_field, - no_yes[copy.copy_to_xfb], - no_yes[copy.intensity_fmt], - no_yes[copy.auto_conv]); - } - break; - - case BPMEM_COPYFILTER0: // 0x53 - SetRegName(BPMEM_COPYFILTER0); - // TODO: Description - break; - - case BPMEM_COPYFILTER1: // 0x54 - SetRegName(BPMEM_COPYFILTER1); - // TODO: Description - break; - - case BPMEM_CLEARBBOX1: // 0x55 - SetRegName(BPMEM_CLEARBBOX1); - // TODO: Description - break; - - case BPMEM_CLEARBBOX2: // 0x56 - SetRegName(BPMEM_CLEARBBOX2); - // TODO: Description - break; - - case BPMEM_CLEAR_PIXEL_PERF: // 0x57 - SetRegName(BPMEM_CLEAR_PIXEL_PERF); - // TODO: Description - break; - - case BPMEM_REVBITS: // 0x58 - SetRegName(BPMEM_REVBITS); - // TODO: Description - break; - - case BPMEM_SCISSOROFFSET: // 0x59 - SetRegName(BPMEM_SCISSOROFFSET); - // TODO: Description - break; - - case BPMEM_PRELOAD_ADDR: // 0x60 - SetRegName(BPMEM_PRELOAD_ADDR); - // TODO: Description - break; - - case BPMEM_PRELOAD_TMEMEVEN: // 0x61 - SetRegName(BPMEM_PRELOAD_TMEMEVEN); - // TODO: Description - break; - - case BPMEM_PRELOAD_TMEMODD: // 0x62 - SetRegName(BPMEM_PRELOAD_TMEMODD); - // TODO: Description - break; - - case BPMEM_PRELOAD_MODE: // 0x63 - SetRegName(BPMEM_PRELOAD_MODE); - // TODO: Description - break; - - case BPMEM_LOADTLUT0: // 0x64 - SetRegName(BPMEM_LOADTLUT0); - // TODO: Description - break; - - case BPMEM_LOADTLUT1: // 0x65 - SetRegName(BPMEM_LOADTLUT1); - // TODO: Description - break; - - case BPMEM_TEXINVALIDATE: // 0x66 - SetRegName(BPMEM_TEXINVALIDATE); - // TODO: Description - break; - - case BPMEM_PERF1: // 0x67 - SetRegName(BPMEM_PERF1); - // TODO: Description - break; - - case BPMEM_FIELDMODE: // 0x68 - SetRegName(BPMEM_FIELDMODE); - // TODO: Description - break; - - case BPMEM_BUSCLOCK1: // 0x69 - SetRegName(BPMEM_BUSCLOCK1); - // TODO: Description - break; - - case BPMEM_TX_SETMODE0: // 0x80 - case BPMEM_TX_SETMODE0+1: - case BPMEM_TX_SETMODE0+2: - case BPMEM_TX_SETMODE0+3: - SetRegName(BPMEM_TX_SETMODE0); - // TODO: Description - break; - - case BPMEM_TX_SETMODE1: // 0x84 - case BPMEM_TX_SETMODE1+1: - case BPMEM_TX_SETMODE1+2: - case BPMEM_TX_SETMODE1+3: - SetRegName(BPMEM_TX_SETMODE1); - // TODO: Description - break; - - case BPMEM_TX_SETIMAGE0: // 0x88 - case BPMEM_TX_SETIMAGE0+1: - case BPMEM_TX_SETIMAGE0+2: - case BPMEM_TX_SETIMAGE0+3: - case BPMEM_TX_SETIMAGE0_4: // 0xA8 - case BPMEM_TX_SETIMAGE0_4+1: - case BPMEM_TX_SETIMAGE0_4+2: - case BPMEM_TX_SETIMAGE0_4+3: - { - SetRegName(BPMEM_TX_SETIMAGE0); - int texnum = (cmd < BPMEM_TX_SETIMAGE0_4) ? cmd - BPMEM_TX_SETIMAGE0 : cmd - BPMEM_TX_SETIMAGE0_4 + 4; - TexImage0 teximg; teximg.hex = cmddata; - *desc = StringFromFormat("Texture Unit: %i\n" - "Width: %i\n" - "Height: %i\n" - "Format: %x\n", - texnum, teximg.width+1, teximg.height+1, teximg.format); - } - break; - - case BPMEM_TX_SETIMAGE1: // 0x8C - case BPMEM_TX_SETIMAGE1+1: - case BPMEM_TX_SETIMAGE1+2: - case BPMEM_TX_SETIMAGE1+3: - case BPMEM_TX_SETIMAGE1_4: // 0xAC - case BPMEM_TX_SETIMAGE1_4+1: - case BPMEM_TX_SETIMAGE1_4+2: - case BPMEM_TX_SETIMAGE1_4+3: - { - SetRegName(BPMEM_TX_SETIMAGE1); - int texnum = (cmd < BPMEM_TX_SETIMAGE1_4) ? cmd - BPMEM_TX_SETIMAGE1 : cmd - BPMEM_TX_SETIMAGE1_4 + 4; - TexImage1 teximg; teximg.hex = cmddata; - *desc = StringFromFormat("Texture Unit: %i\n" - "Even TMEM Offset: %x\n" - "Even TMEM Width: %i\n" - "Even TMEM Height: %i\n" - "Cache is manually managed: %s\n", - texnum, teximg.tmem_even, teximg.cache_width, teximg.cache_height, no_yes[teximg.image_type]); - } - break; - - case BPMEM_TX_SETIMAGE2: // 0x90 - case BPMEM_TX_SETIMAGE2+1: - case BPMEM_TX_SETIMAGE2+2: - case BPMEM_TX_SETIMAGE2+3: - case BPMEM_TX_SETIMAGE2_4: // 0xB0 - case BPMEM_TX_SETIMAGE2_4+1: - case BPMEM_TX_SETIMAGE2_4+2: - case BPMEM_TX_SETIMAGE2_4+3: - { - SetRegName(BPMEM_TX_SETIMAGE2); - int texnum = (cmd < BPMEM_TX_SETIMAGE2_4) ? cmd - BPMEM_TX_SETIMAGE2 : cmd - BPMEM_TX_SETIMAGE2_4 + 4; - TexImage2 teximg; teximg.hex = cmddata; - *desc = StringFromFormat("Texture Unit: %i\n" - "Odd TMEM Offset: %x\n" - "Odd TMEM Width: %i\n" - "Odd TMEM Height: %i\n", - texnum, teximg.tmem_odd, teximg.cache_width, teximg.cache_height); - } - break; - - case BPMEM_TX_SETIMAGE3: // 0x94 - case BPMEM_TX_SETIMAGE3+1: - case BPMEM_TX_SETIMAGE3+2: - case BPMEM_TX_SETIMAGE3+3: - case BPMEM_TX_SETIMAGE3_4: // 0xB4 - case BPMEM_TX_SETIMAGE3_4+1: - case BPMEM_TX_SETIMAGE3_4+2: - case BPMEM_TX_SETIMAGE3_4+3: - { - SetRegName(BPMEM_TX_SETIMAGE3); - int texnum = (cmd < BPMEM_TX_SETIMAGE3_4) ? cmd - BPMEM_TX_SETIMAGE3 : cmd - BPMEM_TX_SETIMAGE3_4 + 4; - TexImage3 teximg; teximg.hex = cmddata; - *desc = StringFromFormat("Texture %i source address (32 byte aligned): 0x%06X", texnum, teximg.image_base << 5); - } - break; - - case BPMEM_TX_SETTLUT: // 0x98 - case BPMEM_TX_SETTLUT+1: - case BPMEM_TX_SETTLUT+2: - case BPMEM_TX_SETTLUT+3: - case BPMEM_TX_SETTLUT_4: // 0xB8 - case BPMEM_TX_SETTLUT_4+1: - case BPMEM_TX_SETTLUT_4+2: - case BPMEM_TX_SETTLUT_4+3: - SetRegName(BPMEM_TX_SETTLUT); - // TODO: Description - break; - - case BPMEM_TEV_COLOR_ENV: // 0xC0 - case BPMEM_TEV_COLOR_ENV+2: - case BPMEM_TEV_COLOR_ENV+4: - case BPMEM_TEV_COLOR_ENV+8: - case BPMEM_TEV_COLOR_ENV+10: - case BPMEM_TEV_COLOR_ENV+12: - case BPMEM_TEV_COLOR_ENV+14: - case BPMEM_TEV_COLOR_ENV+16: - case BPMEM_TEV_COLOR_ENV+18: - case BPMEM_TEV_COLOR_ENV+20: - case BPMEM_TEV_COLOR_ENV+22: - case BPMEM_TEV_COLOR_ENV+24: - case BPMEM_TEV_COLOR_ENV+26: - case BPMEM_TEV_COLOR_ENV+28: - case BPMEM_TEV_COLOR_ENV+30: - { - SetRegName(BPMEM_TEV_COLOR_ENV); - TevStageCombiner::ColorCombiner cc; cc.hex = cmddata; - const char* tevin[] = - { - "prev.rgb", "prev.aaa", - "c0.rgb", "c0.aaa", - "c1.rgb", "c1.aaa", - "c2.rgb", "c2.aaa", - "tex.rgb", "tex.aaa", - "ras.rgb", "ras.aaa", - "ONE", "HALF", "konst.rgb", "ZERO", - }; - const char* tevbias[] = { "0", "+0.5", "-0.5", "compare" }; - const char* tevop[] = { "add", "sub" }; - const char* tevscale[] = { "1", "2", "4", "0.5" }; - const char* tevout[] = { "prev.rgb", "c0.rgb", "c1.rgb", "c2.rgb" }; - *desc = StringFromFormat("Tev stage: %d\n" - "a: %s\n" - "b: %s\n" - "c: %s\n" - "d: %s\n" - "Bias: %s\n" - "Op: %s\n" - "Clamp: %s\n" - "Scale factor: %s\n" - "Dest: %s\n", - (data[0] - BPMEM_TEV_COLOR_ENV)/2, tevin[cc.a], tevin[cc.b], tevin[cc.c], tevin[cc.d], - tevbias[cc.bias], tevop[cc.op], no_yes[cc.clamp], tevscale[cc.shift], tevout[cc.dest]); - break; - } - - case BPMEM_TEV_ALPHA_ENV: // 0xC1 - case BPMEM_TEV_ALPHA_ENV+2: - case BPMEM_TEV_ALPHA_ENV+4: - case BPMEM_TEV_ALPHA_ENV+6: - case BPMEM_TEV_ALPHA_ENV+8: - case BPMEM_TEV_ALPHA_ENV+10: - case BPMEM_TEV_ALPHA_ENV+12: - case BPMEM_TEV_ALPHA_ENV+14: - case BPMEM_TEV_ALPHA_ENV+16: - case BPMEM_TEV_ALPHA_ENV+18: - case BPMEM_TEV_ALPHA_ENV+20: - case BPMEM_TEV_ALPHA_ENV+22: - case BPMEM_TEV_ALPHA_ENV+24: - case BPMEM_TEV_ALPHA_ENV+26: - case BPMEM_TEV_ALPHA_ENV+28: - case BPMEM_TEV_ALPHA_ENV+30: - { - SetRegName(BPMEM_TEV_ALPHA_ENV); - TevStageCombiner::AlphaCombiner ac; ac.hex = cmddata; - const char* tevin[] = - { - "prev", "c0", "c1", "c2", - "tex", "ras", "konst", "ZERO", - }; - const char* tevbias[] = { "0", "+0.5", "-0.5", "compare" }; - const char* tevop[] = { "add", "sub" }; - const char* tevscale[] = { "1", "2", "4", "0.5" }; - const char* tevout[] = { "prev", "c0", "c1", "c2" }; - *desc = StringFromFormat("Tev stage: %d\n" - "a: %s\n" - "b: %s\n" - "c: %s\n" - "d: %s\n" - "Bias: %s\n" - "Op: %s\n" - "Clamp: %s\n" - "Scale factor: %s\n" - "Dest: %s\n" - "Ras sel: %d\n" - "Tex sel: %d\n", - (data[0] - BPMEM_TEV_ALPHA_ENV)/2, tevin[ac.a], tevin[ac.b], tevin[ac.c], tevin[ac.d], - tevbias[ac.bias], tevop[ac.op], no_yes[ac.clamp], tevscale[ac.shift], tevout[ac.dest], - ac.rswap, ac.tswap); - break; - } - - case BPMEM_TEV_COLOR_RA: // 0xE0 - case BPMEM_TEV_COLOR_RA + 2: // 0xE2 - case BPMEM_TEV_COLOR_RA + 4: // 0xE4 - case BPMEM_TEV_COLOR_RA + 6: // 0xE6 - SetRegName(BPMEM_TEV_COLOR_RA); - // TODO: Description - break; - - case BPMEM_TEV_COLOR_BG: // 0xE1 - case BPMEM_TEV_COLOR_BG + 2: // 0xE3 - case BPMEM_TEV_COLOR_BG + 4: // 0xE5 - case BPMEM_TEV_COLOR_BG + 6: // 0xE7 - SetRegName(BPMEM_TEV_COLOR_BG); - // TODO: Description - break; - - case BPMEM_FOGRANGE: // 0xE8 - case BPMEM_FOGRANGE+1: - case BPMEM_FOGRANGE+2: - case BPMEM_FOGRANGE+3: - case BPMEM_FOGRANGE+4: - case BPMEM_FOGRANGE+5: - SetRegName(BPMEM_FOGRANGE); - // TODO: Description - break; - - case BPMEM_FOGPARAM0: // 0xEE - SetRegName(BPMEM_FOGPARAM0); - // TODO: Description - break; - - case BPMEM_FOGBMAGNITUDE: // 0xEF - SetRegName(BPMEM_FOGBMAGNITUDE); - // TODO: Description - break; - - case BPMEM_FOGBEXPONENT: // 0xF0 - SetRegName(BPMEM_FOGBEXPONENT); - // TODO: Description - break; - - case BPMEM_FOGPARAM3: // 0xF1 - SetRegName(BPMEM_FOGPARAM3); - // TODO: Description - break; - - case BPMEM_FOGCOLOR: // 0xF2 - SetRegName(BPMEM_FOGCOLOR); - // TODO: Description - break; - - case BPMEM_ALPHACOMPARE: // 0xF3 - { - SetRegName(BPMEM_ALPHACOMPARE); - AlphaTest test; test.hex = cmddata; - const char* functions[] = { "NEVER", "LESS", "EQUAL", "LEQUAL", "GREATER", "NEQUAL", "GEQUAL", "ALWAYS" }; - const char* logic[] = { "AND", "OR", "XOR", "XNOR" }; - *desc = StringFromFormat("Test 1: %s (ref: %#02x)\n" - "Test 2: %s (ref: %#02x)\n" - "Logic: %s\n", - functions[test.comp0], (int)test.ref0, functions[test.comp1], (int)test.ref1, logic[test.logic]); - break; - } - - case BPMEM_BIAS: // 0xF4 - SetRegName(BPMEM_BIAS); - // TODO: Description - break; - - case BPMEM_ZTEX2: // 0xF5 - SetRegName(BPMEM_ZTEX2); - // TODO: Description - break; - - case BPMEM_TEV_KSEL: // 0xF6 - case BPMEM_TEV_KSEL+1: - case BPMEM_TEV_KSEL+2: - case BPMEM_TEV_KSEL+3: - case BPMEM_TEV_KSEL+4: - case BPMEM_TEV_KSEL+5: - case BPMEM_TEV_KSEL+6: - case BPMEM_TEV_KSEL+7: - SetRegName(BPMEM_TEV_KSEL); - // TODO: Description - break; + const char* no_yes[2] = {"No", "Yes"}; + + u8 cmd = data[0]; + u32 cmddata = Common::swap32(*(u32*)data) & 0xFFFFFF; + switch (cmd) + { +// Macro to set the register name and make sure it was written correctly via compile time assertion +#define SetRegName(reg) \ + *name = #reg; \ + (void)(reg); + + case BPMEM_GENMODE: // 0x00 + SetRegName(BPMEM_GENMODE); + // TODO: Description + break; + + case BPMEM_DISPLAYCOPYFILTER: // 0x01 + // TODO: This is actually the sample pattern used for copies from an antialiased EFB + SetRegName(BPMEM_DISPLAYCOPYFILTER); + // TODO: Description + break; + + case 0x02: // 0x02 + case 0x03: // 0x03 + case 0x04: // 0x04 + // TODO: same as BPMEM_DISPLAYCOPYFILTER + break; + + case BPMEM_IND_MTXA: // 0x06 + case BPMEM_IND_MTXA + 3: + case BPMEM_IND_MTXA + 6: + SetRegName(BPMEM_IND_MTXA); + // TODO: Description + break; + + case BPMEM_IND_MTXB: // 0x07 + case BPMEM_IND_MTXB + 3: + case BPMEM_IND_MTXB + 6: + SetRegName(BPMEM_IND_MTXB); + // TODO: Descriptio + break; + + case BPMEM_IND_MTXC: // 0x08 + case BPMEM_IND_MTXC + 3: + case BPMEM_IND_MTXC + 6: + SetRegName(BPMEM_IND_MTXC); + // TODO: Description + break; + + case BPMEM_IND_IMASK: // 0x0F + SetRegName(BPMEM_IND_IMASK); + // TODO: Description + break; + + case BPMEM_IND_CMD: // 0x10 + case BPMEM_IND_CMD + 1: + case BPMEM_IND_CMD + 2: + case BPMEM_IND_CMD + 3: + case BPMEM_IND_CMD + 4: + case BPMEM_IND_CMD + 5: + case BPMEM_IND_CMD + 6: + case BPMEM_IND_CMD + 7: + case BPMEM_IND_CMD + 8: + case BPMEM_IND_CMD + 9: + case BPMEM_IND_CMD + 10: + case BPMEM_IND_CMD + 11: + case BPMEM_IND_CMD + 12: + case BPMEM_IND_CMD + 13: + case BPMEM_IND_CMD + 14: + case BPMEM_IND_CMD + 15: + SetRegName(BPMEM_IND_CMD); + // TODO: Description + break; + + case BPMEM_SCISSORTL: // 0x20 + SetRegName(BPMEM_SCISSORTL); + // TODO: Description + break; + + case BPMEM_SCISSORBR: // 0x21 + SetRegName(BPMEM_SCISSORBR); + // TODO: Description + break; + + case BPMEM_LINEPTWIDTH: // 0x22 + SetRegName(BPMEM_LINEPTWIDTH); + // TODO: Description + break; + + case BPMEM_PERF0_TRI: // 0x23 + SetRegName(BPMEM_PERF0_TRI); + // TODO: Description + break; + + case BPMEM_PERF0_QUAD: // 0x24 + SetRegName(BPMEM_PERF0_QUAD); + // TODO: Description + break; + + case BPMEM_RAS1_SS0: // 0x25 + SetRegName(BPMEM_RAS1_SS0); + // TODO: Description + break; + + case BPMEM_RAS1_SS1: // 0x26 + SetRegName(BPMEM_RAS1_SS1); + // TODO: Description + break; + + case BPMEM_IREF: // 0x27 + SetRegName(BPMEM_IREF); + // TODO: Description + break; + + case BPMEM_TREF: // 0x28 + case BPMEM_TREF + 1: + case BPMEM_TREF + 2: + case BPMEM_TREF + 3: + case BPMEM_TREF + 4: + case BPMEM_TREF + 5: + case BPMEM_TREF + 6: + case BPMEM_TREF + 7: + SetRegName(BPMEM_TREF); + // TODO: Description + break; + + case BPMEM_SU_SSIZE: // 0x30 + case BPMEM_SU_SSIZE + 2: + case BPMEM_SU_SSIZE + 4: + case BPMEM_SU_SSIZE + 6: + case BPMEM_SU_SSIZE + 8: + case BPMEM_SU_SSIZE + 10: + case BPMEM_SU_SSIZE + 12: + case BPMEM_SU_SSIZE + 14: + SetRegName(BPMEM_SU_SSIZE); + // TODO: Description + break; + + case BPMEM_SU_TSIZE: // 0x31 + case BPMEM_SU_TSIZE + 2: + case BPMEM_SU_TSIZE + 4: + case BPMEM_SU_TSIZE + 6: + case BPMEM_SU_TSIZE + 8: + case BPMEM_SU_TSIZE + 10: + case BPMEM_SU_TSIZE + 12: + case BPMEM_SU_TSIZE + 14: + SetRegName(BPMEM_SU_TSIZE); + // TODO: Description + break; + + case BPMEM_ZMODE: // 0x40 + SetRegName(BPMEM_ZMODE); + // TODO: Description + break; + + case BPMEM_BLENDMODE: // 0x41 + { + SetRegName(BPMEM_BLENDMODE); + BlendMode mode; + mode.hex = cmddata; + const char* dstfactors[] = {"0", "1", "src_color", "1-src_color", + "src_alpha", "1-src_alpha", "dst_alpha", "1-dst_alpha"}; + const char* srcfactors[] = {"0", "1", "dst_color", "1-dst_color", + "src_alpha", "1-src_alpha", "dst_alpha", "1-dst_alpha"}; + const char* logicmodes[] = {"0", "s & d", "s & ~d", "s", "~s & d", "d", + "s ^ d", "s | d", "~(s | d)", "~(s ^ d)", "~d", "s | ~d", + "~s", "~s | d", "~(s & d)", "1"}; + *desc = StringFromFormat( + "Enable: %s\n" + "Logic ops: %s\n" + "Dither: %s\n" + "Color write: %s\n" + "Alpha write: %s\n" + "Dest factor: %s\n" + "Source factor: %s\n" + "Subtract: %s\n" + "Logic mode: %s\n", + no_yes[mode.blendenable], no_yes[mode.logicopenable], no_yes[mode.dither], + no_yes[mode.colorupdate], no_yes[mode.alphaupdate], dstfactors[mode.dstfactor], + srcfactors[mode.srcfactor], no_yes[mode.subtract], logicmodes[mode.logicmode]); + } + break; + + case BPMEM_CONSTANTALPHA: // 0x42 + SetRegName(BPMEM_CONSTANTALPHA); + // TODO: Description + break; + + case BPMEM_ZCOMPARE: // 0x43 + { + SetRegName(BPMEM_ZCOMPARE); + PEControl config; + config.hex = cmddata; + const char* pixel_formats[] = {"RGB8_Z24", "RGBA6_Z24", "RGB565_Z16", "Z24", + "Y8", "U8", "V8", "YUV420"}; + const char* zformats[] = { + "linear", "compressed (near)", "compressed (mid)", "compressed (far)", + "inv linear", "compressed (inv near)", "compressed (inv mid)", "compressed (inv far)"}; + *desc = StringFromFormat("EFB pixel format: %s\n" + "Depth format: %s\n" + "Early depth test: %s\n", + pixel_formats[config.pixel_format], zformats[config.zformat], + no_yes[config.early_ztest]); + } + break; + + case BPMEM_FIELDMASK: // 0x44 + SetRegName(BPMEM_FIELDMASK); + // TODO: Description + break; + + case BPMEM_SETDRAWDONE: // 0x45 + SetRegName(BPMEM_SETDRAWDONE); + // TODO: Description + break; + + case BPMEM_BUSCLOCK0: // 0x46 + SetRegName(BPMEM_BUSCLOCK0); + // TODO: Description + break; + + case BPMEM_PE_TOKEN_ID: // 0x47 + SetRegName(BPMEM_PE_TOKEN_ID); + // TODO: Description + break; + + case BPMEM_PE_TOKEN_INT_ID: // 0x48 + SetRegName(BPMEM_PE_TOKEN_INT_ID); + // TODO: Description + break; + + case BPMEM_EFB_TL: // 0x49 + { + SetRegName(BPMEM_EFB_TL); + X10Y10 left_top; + left_top.hex = cmddata; + *desc = StringFromFormat("Left: %d\nTop: %d", left_top.x, left_top.y); + } + break; + + case BPMEM_EFB_BR: // 0x4A + { + // TODO: Misleading name, should be BPMEM_EFB_WH instead + SetRegName(BPMEM_EFB_BR); + X10Y10 width_height; + width_height.hex = cmddata; + *desc = StringFromFormat("Width: %d\nHeight: %d", width_height.x + 1, width_height.y + 1); + } + break; + + case BPMEM_EFB_ADDR: // 0x4B + SetRegName(BPMEM_EFB_ADDR); + *desc = StringFromFormat("Target address (32 byte aligned): 0x%06X", cmddata << 5); + break; + + case BPMEM_MIPMAP_STRIDE: // 0x4D + SetRegName(BPMEM_MIPMAP_STRIDE); + // TODO: Description + break; + + case BPMEM_COPYYSCALE: // 0x4E + SetRegName(BPMEM_COPYYSCALE); + *desc = StringFromFormat("Scaling factor (XFB copy only): 0x%X (%f or inverted %f)", cmddata, + (float)cmddata / 256.f, 256.f / (float)cmddata); + break; + + case BPMEM_CLEAR_AR: // 0x4F + SetRegName(BPMEM_CLEAR_AR); + *desc = StringFromFormat("Alpha: 0x%02X\nRed: 0x%02X", (cmddata & 0xFF00) >> 8, cmddata & 0xFF); + break; + + case BPMEM_CLEAR_GB: // 0x50 + SetRegName(BPMEM_CLEAR_GB); + *desc = + StringFromFormat("Green: 0x%02X\nBlue: 0x%02X", (cmddata & 0xFF00) >> 8, cmddata & 0xFF); + break; + + case BPMEM_CLEAR_Z: // 0x51 + SetRegName(BPMEM_CLEAR_Z); + *desc = StringFromFormat("Z value: 0x%06X", cmddata); + break; + + case BPMEM_TRIGGER_EFB_COPY: // 0x52 + { + SetRegName(BPMEM_TRIGGER_EFB_COPY); + UPE_Copy copy; + copy.Hex = cmddata; + *desc = StringFromFormat("Clamping: %s\n" + "Converting from RGB to YUV: %s\n" + "Target pixel format: 0x%X\n" + "Gamma correction: %s\n" + "Mipmap filter: %s\n" + "Vertical scaling: %s\n" + "Clear: %s\n" + "Frame to field: 0x%01X\n" + "Copy to XFB: %s\n" + "Intensity format: %s\n" + "Automatic color conversion: %s", + (copy.clamp0 && copy.clamp1) ? "Top and Bottom" : (copy.clamp0) ? + "Top only" : + (copy.clamp1) ? "Bottom only" : "None", + no_yes[copy.yuv], copy.tp_realFormat(), + (copy.gamma == 0) ? "1.0" : (copy.gamma == 1) ? + "1.7" : + (copy.gamma == 2) ? "2.2" : "Invalid value 0x3?", + no_yes[copy.half_scale], no_yes[copy.scale_invert], no_yes[copy.clear], + (u32)copy.frame_to_field, no_yes[copy.copy_to_xfb], + no_yes[copy.intensity_fmt], no_yes[copy.auto_conv]); + } + break; + + case BPMEM_COPYFILTER0: // 0x53 + SetRegName(BPMEM_COPYFILTER0); + // TODO: Description + break; + + case BPMEM_COPYFILTER1: // 0x54 + SetRegName(BPMEM_COPYFILTER1); + // TODO: Description + break; + + case BPMEM_CLEARBBOX1: // 0x55 + SetRegName(BPMEM_CLEARBBOX1); + // TODO: Description + break; + + case BPMEM_CLEARBBOX2: // 0x56 + SetRegName(BPMEM_CLEARBBOX2); + // TODO: Description + break; + + case BPMEM_CLEAR_PIXEL_PERF: // 0x57 + SetRegName(BPMEM_CLEAR_PIXEL_PERF); + // TODO: Description + break; + + case BPMEM_REVBITS: // 0x58 + SetRegName(BPMEM_REVBITS); + // TODO: Description + break; + + case BPMEM_SCISSOROFFSET: // 0x59 + SetRegName(BPMEM_SCISSOROFFSET); + // TODO: Description + break; + + case BPMEM_PRELOAD_ADDR: // 0x60 + SetRegName(BPMEM_PRELOAD_ADDR); + // TODO: Description + break; + + case BPMEM_PRELOAD_TMEMEVEN: // 0x61 + SetRegName(BPMEM_PRELOAD_TMEMEVEN); + // TODO: Description + break; + + case BPMEM_PRELOAD_TMEMODD: // 0x62 + SetRegName(BPMEM_PRELOAD_TMEMODD); + // TODO: Description + break; + + case BPMEM_PRELOAD_MODE: // 0x63 + SetRegName(BPMEM_PRELOAD_MODE); + // TODO: Description + break; + + case BPMEM_LOADTLUT0: // 0x64 + SetRegName(BPMEM_LOADTLUT0); + // TODO: Description + break; + + case BPMEM_LOADTLUT1: // 0x65 + SetRegName(BPMEM_LOADTLUT1); + // TODO: Description + break; + + case BPMEM_TEXINVALIDATE: // 0x66 + SetRegName(BPMEM_TEXINVALIDATE); + // TODO: Description + break; + + case BPMEM_PERF1: // 0x67 + SetRegName(BPMEM_PERF1); + // TODO: Description + break; + + case BPMEM_FIELDMODE: // 0x68 + SetRegName(BPMEM_FIELDMODE); + // TODO: Description + break; + + case BPMEM_BUSCLOCK1: // 0x69 + SetRegName(BPMEM_BUSCLOCK1); + // TODO: Description + break; + + case BPMEM_TX_SETMODE0: // 0x80 + case BPMEM_TX_SETMODE0 + 1: + case BPMEM_TX_SETMODE0 + 2: + case BPMEM_TX_SETMODE0 + 3: + SetRegName(BPMEM_TX_SETMODE0); + // TODO: Description + break; + + case BPMEM_TX_SETMODE1: // 0x84 + case BPMEM_TX_SETMODE1 + 1: + case BPMEM_TX_SETMODE1 + 2: + case BPMEM_TX_SETMODE1 + 3: + SetRegName(BPMEM_TX_SETMODE1); + // TODO: Description + break; + + case BPMEM_TX_SETIMAGE0: // 0x88 + case BPMEM_TX_SETIMAGE0 + 1: + case BPMEM_TX_SETIMAGE0 + 2: + case BPMEM_TX_SETIMAGE0 + 3: + case BPMEM_TX_SETIMAGE0_4: // 0xA8 + case BPMEM_TX_SETIMAGE0_4 + 1: + case BPMEM_TX_SETIMAGE0_4 + 2: + case BPMEM_TX_SETIMAGE0_4 + 3: + { + SetRegName(BPMEM_TX_SETIMAGE0); + int texnum = + (cmd < BPMEM_TX_SETIMAGE0_4) ? cmd - BPMEM_TX_SETIMAGE0 : cmd - BPMEM_TX_SETIMAGE0_4 + 4; + TexImage0 teximg; + teximg.hex = cmddata; + *desc = StringFromFormat("Texture Unit: %i\n" + "Width: %i\n" + "Height: %i\n" + "Format: %x\n", + texnum, teximg.width + 1, teximg.height + 1, teximg.format); + } + break; + + case BPMEM_TX_SETIMAGE1: // 0x8C + case BPMEM_TX_SETIMAGE1 + 1: + case BPMEM_TX_SETIMAGE1 + 2: + case BPMEM_TX_SETIMAGE1 + 3: + case BPMEM_TX_SETIMAGE1_4: // 0xAC + case BPMEM_TX_SETIMAGE1_4 + 1: + case BPMEM_TX_SETIMAGE1_4 + 2: + case BPMEM_TX_SETIMAGE1_4 + 3: + { + SetRegName(BPMEM_TX_SETIMAGE1); + int texnum = + (cmd < BPMEM_TX_SETIMAGE1_4) ? cmd - BPMEM_TX_SETIMAGE1 : cmd - BPMEM_TX_SETIMAGE1_4 + 4; + TexImage1 teximg; + teximg.hex = cmddata; + *desc = StringFromFormat("Texture Unit: %i\n" + "Even TMEM Offset: %x\n" + "Even TMEM Width: %i\n" + "Even TMEM Height: %i\n" + "Cache is manually managed: %s\n", + texnum, teximg.tmem_even, teximg.cache_width, teximg.cache_height, + no_yes[teximg.image_type]); + } + break; + + case BPMEM_TX_SETIMAGE2: // 0x90 + case BPMEM_TX_SETIMAGE2 + 1: + case BPMEM_TX_SETIMAGE2 + 2: + case BPMEM_TX_SETIMAGE2 + 3: + case BPMEM_TX_SETIMAGE2_4: // 0xB0 + case BPMEM_TX_SETIMAGE2_4 + 1: + case BPMEM_TX_SETIMAGE2_4 + 2: + case BPMEM_TX_SETIMAGE2_4 + 3: + { + SetRegName(BPMEM_TX_SETIMAGE2); + int texnum = + (cmd < BPMEM_TX_SETIMAGE2_4) ? cmd - BPMEM_TX_SETIMAGE2 : cmd - BPMEM_TX_SETIMAGE2_4 + 4; + TexImage2 teximg; + teximg.hex = cmddata; + *desc = StringFromFormat("Texture Unit: %i\n" + "Odd TMEM Offset: %x\n" + "Odd TMEM Width: %i\n" + "Odd TMEM Height: %i\n", + texnum, teximg.tmem_odd, teximg.cache_width, teximg.cache_height); + } + break; + + case BPMEM_TX_SETIMAGE3: // 0x94 + case BPMEM_TX_SETIMAGE3 + 1: + case BPMEM_TX_SETIMAGE3 + 2: + case BPMEM_TX_SETIMAGE3 + 3: + case BPMEM_TX_SETIMAGE3_4: // 0xB4 + case BPMEM_TX_SETIMAGE3_4 + 1: + case BPMEM_TX_SETIMAGE3_4 + 2: + case BPMEM_TX_SETIMAGE3_4 + 3: + { + SetRegName(BPMEM_TX_SETIMAGE3); + int texnum = + (cmd < BPMEM_TX_SETIMAGE3_4) ? cmd - BPMEM_TX_SETIMAGE3 : cmd - BPMEM_TX_SETIMAGE3_4 + 4; + TexImage3 teximg; + teximg.hex = cmddata; + *desc = StringFromFormat("Texture %i source address (32 byte aligned): 0x%06X", texnum, + teximg.image_base << 5); + } + break; + + case BPMEM_TX_SETTLUT: // 0x98 + case BPMEM_TX_SETTLUT + 1: + case BPMEM_TX_SETTLUT + 2: + case BPMEM_TX_SETTLUT + 3: + case BPMEM_TX_SETTLUT_4: // 0xB8 + case BPMEM_TX_SETTLUT_4 + 1: + case BPMEM_TX_SETTLUT_4 + 2: + case BPMEM_TX_SETTLUT_4 + 3: + SetRegName(BPMEM_TX_SETTLUT); + // TODO: Description + break; + + case BPMEM_TEV_COLOR_ENV: // 0xC0 + case BPMEM_TEV_COLOR_ENV + 2: + case BPMEM_TEV_COLOR_ENV + 4: + case BPMEM_TEV_COLOR_ENV + 8: + case BPMEM_TEV_COLOR_ENV + 10: + case BPMEM_TEV_COLOR_ENV + 12: + case BPMEM_TEV_COLOR_ENV + 14: + case BPMEM_TEV_COLOR_ENV + 16: + case BPMEM_TEV_COLOR_ENV + 18: + case BPMEM_TEV_COLOR_ENV + 20: + case BPMEM_TEV_COLOR_ENV + 22: + case BPMEM_TEV_COLOR_ENV + 24: + case BPMEM_TEV_COLOR_ENV + 26: + case BPMEM_TEV_COLOR_ENV + 28: + case BPMEM_TEV_COLOR_ENV + 30: + { + SetRegName(BPMEM_TEV_COLOR_ENV); + TevStageCombiner::ColorCombiner cc; + cc.hex = cmddata; + const char* tevin[] = { + "prev.rgb", "prev.aaa", "c0.rgb", "c0.aaa", "c1.rgb", "c1.aaa", "c2.rgb", "c2.aaa", + "tex.rgb", "tex.aaa", "ras.rgb", "ras.aaa", "ONE", "HALF", "konst.rgb", "ZERO", + }; + const char* tevbias[] = {"0", "+0.5", "-0.5", "compare"}; + const char* tevop[] = {"add", "sub"}; + const char* tevscale[] = {"1", "2", "4", "0.5"}; + const char* tevout[] = {"prev.rgb", "c0.rgb", "c1.rgb", "c2.rgb"}; + *desc = StringFromFormat("Tev stage: %d\n" + "a: %s\n" + "b: %s\n" + "c: %s\n" + "d: %s\n" + "Bias: %s\n" + "Op: %s\n" + "Clamp: %s\n" + "Scale factor: %s\n" + "Dest: %s\n", + (data[0] - BPMEM_TEV_COLOR_ENV) / 2, tevin[cc.a], tevin[cc.b], + tevin[cc.c], tevin[cc.d], tevbias[cc.bias], tevop[cc.op], + no_yes[cc.clamp], tevscale[cc.shift], tevout[cc.dest]); + break; + } + + case BPMEM_TEV_ALPHA_ENV: // 0xC1 + case BPMEM_TEV_ALPHA_ENV + 2: + case BPMEM_TEV_ALPHA_ENV + 4: + case BPMEM_TEV_ALPHA_ENV + 6: + case BPMEM_TEV_ALPHA_ENV + 8: + case BPMEM_TEV_ALPHA_ENV + 10: + case BPMEM_TEV_ALPHA_ENV + 12: + case BPMEM_TEV_ALPHA_ENV + 14: + case BPMEM_TEV_ALPHA_ENV + 16: + case BPMEM_TEV_ALPHA_ENV + 18: + case BPMEM_TEV_ALPHA_ENV + 20: + case BPMEM_TEV_ALPHA_ENV + 22: + case BPMEM_TEV_ALPHA_ENV + 24: + case BPMEM_TEV_ALPHA_ENV + 26: + case BPMEM_TEV_ALPHA_ENV + 28: + case BPMEM_TEV_ALPHA_ENV + 30: + { + SetRegName(BPMEM_TEV_ALPHA_ENV); + TevStageCombiner::AlphaCombiner ac; + ac.hex = cmddata; + const char* tevin[] = { + "prev", "c0", "c1", "c2", "tex", "ras", "konst", "ZERO", + }; + const char* tevbias[] = {"0", "+0.5", "-0.5", "compare"}; + const char* tevop[] = {"add", "sub"}; + const char* tevscale[] = {"1", "2", "4", "0.5"}; + const char* tevout[] = {"prev", "c0", "c1", "c2"}; + *desc = + StringFromFormat("Tev stage: %d\n" + "a: %s\n" + "b: %s\n" + "c: %s\n" + "d: %s\n" + "Bias: %s\n" + "Op: %s\n" + "Clamp: %s\n" + "Scale factor: %s\n" + "Dest: %s\n" + "Ras sel: %d\n" + "Tex sel: %d\n", + (data[0] - BPMEM_TEV_ALPHA_ENV) / 2, tevin[ac.a], tevin[ac.b], tevin[ac.c], + tevin[ac.d], tevbias[ac.bias], tevop[ac.op], no_yes[ac.clamp], + tevscale[ac.shift], tevout[ac.dest], ac.rswap, ac.tswap); + break; + } + + case BPMEM_TEV_COLOR_RA: // 0xE0 + case BPMEM_TEV_COLOR_RA + 2: // 0xE2 + case BPMEM_TEV_COLOR_RA + 4: // 0xE4 + case BPMEM_TEV_COLOR_RA + 6: // 0xE6 + SetRegName(BPMEM_TEV_COLOR_RA); + // TODO: Description + break; + + case BPMEM_TEV_COLOR_BG: // 0xE1 + case BPMEM_TEV_COLOR_BG + 2: // 0xE3 + case BPMEM_TEV_COLOR_BG + 4: // 0xE5 + case BPMEM_TEV_COLOR_BG + 6: // 0xE7 + SetRegName(BPMEM_TEV_COLOR_BG); + // TODO: Description + break; + + case BPMEM_FOGRANGE: // 0xE8 + case BPMEM_FOGRANGE + 1: + case BPMEM_FOGRANGE + 2: + case BPMEM_FOGRANGE + 3: + case BPMEM_FOGRANGE + 4: + case BPMEM_FOGRANGE + 5: + SetRegName(BPMEM_FOGRANGE); + // TODO: Description + break; + + case BPMEM_FOGPARAM0: // 0xEE + SetRegName(BPMEM_FOGPARAM0); + // TODO: Description + break; + + case BPMEM_FOGBMAGNITUDE: // 0xEF + SetRegName(BPMEM_FOGBMAGNITUDE); + // TODO: Description + break; + + case BPMEM_FOGBEXPONENT: // 0xF0 + SetRegName(BPMEM_FOGBEXPONENT); + // TODO: Description + break; + + case BPMEM_FOGPARAM3: // 0xF1 + SetRegName(BPMEM_FOGPARAM3); + // TODO: Description + break; + + case BPMEM_FOGCOLOR: // 0xF2 + SetRegName(BPMEM_FOGCOLOR); + // TODO: Description + break; + + case BPMEM_ALPHACOMPARE: // 0xF3 + { + SetRegName(BPMEM_ALPHACOMPARE); + AlphaTest test; + test.hex = cmddata; + const char* functions[] = {"NEVER", "LESS", "EQUAL", "LEQUAL", + "GREATER", "NEQUAL", "GEQUAL", "ALWAYS"}; + const char* logic[] = {"AND", "OR", "XOR", "XNOR"}; + *desc = StringFromFormat("Test 1: %s (ref: %#02x)\n" + "Test 2: %s (ref: %#02x)\n" + "Logic: %s\n", + functions[test.comp0], (int)test.ref0, functions[test.comp1], + (int)test.ref1, logic[test.logic]); + break; + } + + case BPMEM_BIAS: // 0xF4 + SetRegName(BPMEM_BIAS); + // TODO: Description + break; + + case BPMEM_ZTEX2: // 0xF5 + SetRegName(BPMEM_ZTEX2); + // TODO: Description + break; + + case BPMEM_TEV_KSEL: // 0xF6 + case BPMEM_TEV_KSEL + 1: + case BPMEM_TEV_KSEL + 2: + case BPMEM_TEV_KSEL + 3: + case BPMEM_TEV_KSEL + 4: + case BPMEM_TEV_KSEL + 5: + case BPMEM_TEV_KSEL + 6: + case BPMEM_TEV_KSEL + 7: + SetRegName(BPMEM_TEV_KSEL); + // TODO: Description + break; #undef SetRegName - } + } } // Called when loading a saved state. void BPReload() { - // restore anything that goes straight to the renderer. - // let's not risk actually replaying any writes. - // note that PixelShaderManager is already covered since it has its own DoState. - SetGenerationMode(); - SetScissor(); - SetDepthMode(); - SetLogicOpMode(); - SetDitherMode(); - SetBlendMode(); - SetColorMask(); - OnPixelFormatChange(); + // restore anything that goes straight to the renderer. + // let's not risk actually replaying any writes. + // note that PixelShaderManager is already covered since it has its own DoState. + SetGenerationMode(); + SetScissor(); + SetDepthMode(); + SetLogicOpMode(); + SetDitherMode(); + SetBlendMode(); + SetColorMask(); + OnPixelFormatChange(); } diff --git a/Source/Core/VideoCommon/BoundingBox.cpp b/Source/Core/VideoCommon/BoundingBox.cpp index 016d80edc7..4c9b6c4c3b 100644 --- a/Source/Core/VideoCommon/BoundingBox.cpp +++ b/Source/Core/VideoCommon/BoundingBox.cpp @@ -2,22 +2,21 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoCommon/BoundingBox.h" #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" -#include "VideoCommon/BoundingBox.h" namespace BoundingBox { - // External vars bool active = false; -u16 coords[4] = { 0x80, 0xA0, 0x80, 0xA0 }; +u16 coords[4] = {0x80, 0xA0, 0x80, 0xA0}; // Save state void DoState(PointerWrap& p) { - p.Do(active); - p.Do(coords); + p.Do(active); + p.Do(coords); } -} // namespace BoundingBox +} // namespace BoundingBox diff --git a/Source/Core/VideoCommon/BoundingBox.h b/Source/Core/VideoCommon/BoundingBox.h index 6a4e5e14b6..e10b97cc06 100644 --- a/Source/Core/VideoCommon/BoundingBox.h +++ b/Source/Core/VideoCommon/BoundingBox.h @@ -11,7 +11,6 @@ class PointerWrap; // Bounding Box manager namespace BoundingBox { - // Determines if bounding box is active extern bool active; @@ -20,13 +19,13 @@ extern u16 coords[4]; enum { - LEFT = 0, - RIGHT = 1, - TOP = 2, - BOTTOM = 3 + LEFT = 0, + RIGHT = 1, + TOP = 2, + BOTTOM = 3 }; // Save state void DoState(PointerWrap& p); -}; // end of namespace BoundingBox +}; // end of namespace BoundingBox diff --git a/Source/Core/VideoCommon/CPMemory.cpp b/Source/Core/VideoCommon/CPMemory.cpp index f737e360b9..52384cddaf 100644 --- a/Source/Core/VideoCommon/CPMemory.cpp +++ b/Source/Core/VideoCommon/CPMemory.cpp @@ -2,8 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "Common/ChunkFile.h" #include "VideoCommon/CPMemory.h" +#include "Common/ChunkFile.h" // CP state CPState g_main_cp_state; @@ -11,23 +11,23 @@ CPState g_preprocess_cp_state; void DoCPState(PointerWrap& p) { - // We don't save g_preprocess_cp_state separately because the GPU should be - // synced around state save/load. - p.DoArray(g_main_cp_state.array_bases); - p.DoArray(g_main_cp_state.array_strides); - p.Do(g_main_cp_state.matrix_index_a); - p.Do(g_main_cp_state.matrix_index_b); - p.Do(g_main_cp_state.vtx_desc.Hex); - p.DoArray(g_main_cp_state.vtx_attr); - p.DoMarker("CP Memory"); - if (p.mode == PointerWrap::MODE_READ) - { - CopyPreprocessCPStateFromMain(); - g_main_cp_state.bases_dirty = true; - } + // We don't save g_preprocess_cp_state separately because the GPU should be + // synced around state save/load. + p.DoArray(g_main_cp_state.array_bases); + p.DoArray(g_main_cp_state.array_strides); + p.Do(g_main_cp_state.matrix_index_a); + p.Do(g_main_cp_state.matrix_index_b); + p.Do(g_main_cp_state.vtx_desc.Hex); + p.DoArray(g_main_cp_state.vtx_attr); + p.DoMarker("CP Memory"); + if (p.mode == PointerWrap::MODE_READ) + { + CopyPreprocessCPStateFromMain(); + g_main_cp_state.bases_dirty = true; + } } void CopyPreprocessCPStateFromMain() { - memcpy(&g_preprocess_cp_state, &g_main_cp_state, sizeof(CPState)); + memcpy(&g_preprocess_cp_state, &g_main_cp_state, sizeof(CPState)); } diff --git a/Source/Core/VideoCommon/CPMemory.h b/Source/Core/VideoCommon/CPMemory.h index c2280b06b7..c28a8cf328 100644 --- a/Source/Core/VideoCommon/CPMemory.h +++ b/Source/Core/VideoCommon/CPMemory.h @@ -10,234 +10,225 @@ // Vertex array numbers enum { - ARRAY_POSITION = 0, - ARRAY_NORMAL = 1, - ARRAY_COLOR = 2, - ARRAY_COLOR2 = 3, - ARRAY_TEXCOORD0 = 4, + ARRAY_POSITION = 0, + ARRAY_NORMAL = 1, + ARRAY_COLOR = 2, + ARRAY_COLOR2 = 3, + ARRAY_TEXCOORD0 = 4, }; // Vertex components enum { - NOT_PRESENT = 0, - DIRECT = 1, - INDEX8 = 2, - INDEX16 = 3, + NOT_PRESENT = 0, + DIRECT = 1, + INDEX8 = 2, + INDEX16 = 3, - MASK_INDEXED = 2, + MASK_INDEXED = 2, }; enum { - FORMAT_UBYTE = 0, // 2 Cmp - FORMAT_BYTE = 1, // 3 Cmp - FORMAT_USHORT = 2, - FORMAT_SHORT = 3, - FORMAT_FLOAT = 4, + FORMAT_UBYTE = 0, // 2 Cmp + FORMAT_BYTE = 1, // 3 Cmp + FORMAT_USHORT = 2, + FORMAT_SHORT = 3, + FORMAT_FLOAT = 4, }; enum { - FORMAT_16B_565 = 0, // NA - FORMAT_24B_888 = 1, - FORMAT_32B_888x = 2, - FORMAT_16B_4444 = 3, - FORMAT_24B_6666 = 4, - FORMAT_32B_8888 = 5, + FORMAT_16B_565 = 0, // NA + FORMAT_24B_888 = 1, + FORMAT_32B_888x = 2, + FORMAT_16B_4444 = 3, + FORMAT_24B_6666 = 4, + FORMAT_32B_8888 = 5, }; #pragma pack(4) -union TVtxDesc -{ - u64 Hex; - struct - { - // 0: not present - // 1: present - u64 PosMatIdx : 1; - u64 Tex0MatIdx : 1; - u64 Tex1MatIdx : 1; - u64 Tex2MatIdx : 1; - u64 Tex3MatIdx : 1; - u64 Tex4MatIdx : 1; - u64 Tex5MatIdx : 1; - u64 Tex6MatIdx : 1; - u64 Tex7MatIdx : 1; +union TVtxDesc { + u64 Hex; + struct + { + // 0: not present + // 1: present + u64 PosMatIdx : 1; + u64 Tex0MatIdx : 1; + u64 Tex1MatIdx : 1; + u64 Tex2MatIdx : 1; + u64 Tex3MatIdx : 1; + u64 Tex4MatIdx : 1; + u64 Tex5MatIdx : 1; + u64 Tex6MatIdx : 1; + u64 Tex7MatIdx : 1; - // 00: not present - // 01: direct - // 10: 8 bit index - // 11: 16 bit index - u64 Position : 2; - u64 Normal : 2; - u64 Color0 : 2; - u64 Color1 : 2; - u64 Tex0Coord : 2; - u64 Tex1Coord : 2; - u64 Tex2Coord : 2; - u64 Tex3Coord : 2; - u64 Tex4Coord : 2; - u64 Tex5Coord : 2; - u64 Tex6Coord : 2; - u64 Tex7Coord : 2; - u64 :31; - }; + // 00: not present + // 01: direct + // 10: 8 bit index + // 11: 16 bit index + u64 Position : 2; + u64 Normal : 2; + u64 Color0 : 2; + u64 Color1 : 2; + u64 Tex0Coord : 2; + u64 Tex1Coord : 2; + u64 Tex2Coord : 2; + u64 Tex3Coord : 2; + u64 Tex4Coord : 2; + u64 Tex5Coord : 2; + u64 Tex6Coord : 2; + u64 Tex7Coord : 2; + u64 : 31; + }; - struct - { - u32 Hex0, Hex1; - }; + struct + { + u32 Hex0, Hex1; + }; - // Easily index into the Position..Tex7Coord fields. - u32 GetVertexArrayStatus(int idx) - { - return (Hex >> (9 + idx * 2)) & 0x3; - } + // Easily index into the Position..Tex7Coord fields. + u32 GetVertexArrayStatus(int idx) { return (Hex >> (9 + idx * 2)) & 0x3; } }; -union UVAT_group0 -{ - u32 Hex; - struct - { - // 0:8 - u32 PosElements : 1; - u32 PosFormat : 3; - u32 PosFrac : 5; - // 9:12 - u32 NormalElements : 1; - u32 NormalFormat : 3; - // 13:16 - u32 Color0Elements : 1; - u32 Color0Comp : 3; - // 17:20 - u32 Color1Elements : 1; - u32 Color1Comp : 3; - // 21:29 - u32 Tex0CoordElements : 1; - u32 Tex0CoordFormat : 3; - u32 Tex0Frac : 5; - // 30:31 - u32 ByteDequant : 1; - u32 NormalIndex3 : 1; - }; +union UVAT_group0 { + u32 Hex; + struct + { + // 0:8 + u32 PosElements : 1; + u32 PosFormat : 3; + u32 PosFrac : 5; + // 9:12 + u32 NormalElements : 1; + u32 NormalFormat : 3; + // 13:16 + u32 Color0Elements : 1; + u32 Color0Comp : 3; + // 17:20 + u32 Color1Elements : 1; + u32 Color1Comp : 3; + // 21:29 + u32 Tex0CoordElements : 1; + u32 Tex0CoordFormat : 3; + u32 Tex0Frac : 5; + // 30:31 + u32 ByteDequant : 1; + u32 NormalIndex3 : 1; + }; }; -union UVAT_group1 -{ - u32 Hex; - struct - { - // 0:8 - u32 Tex1CoordElements : 1; - u32 Tex1CoordFormat : 3; - u32 Tex1Frac : 5; - // 9:17 - u32 Tex2CoordElements : 1; - u32 Tex2CoordFormat : 3; - u32 Tex2Frac : 5; - // 18:26 - u32 Tex3CoordElements : 1; - u32 Tex3CoordFormat : 3; - u32 Tex3Frac : 5; - // 27:30 - u32 Tex4CoordElements : 1; - u32 Tex4CoordFormat : 3; - // - u32 : 1; - }; +union UVAT_group1 { + u32 Hex; + struct + { + // 0:8 + u32 Tex1CoordElements : 1; + u32 Tex1CoordFormat : 3; + u32 Tex1Frac : 5; + // 9:17 + u32 Tex2CoordElements : 1; + u32 Tex2CoordFormat : 3; + u32 Tex2Frac : 5; + // 18:26 + u32 Tex3CoordElements : 1; + u32 Tex3CoordFormat : 3; + u32 Tex3Frac : 5; + // 27:30 + u32 Tex4CoordElements : 1; + u32 Tex4CoordFormat : 3; + // + u32 : 1; + }; }; -union UVAT_group2 -{ - u32 Hex; - struct - { - // 0:4 - u32 Tex4Frac : 5; - // 5:13 - u32 Tex5CoordElements : 1; - u32 Tex5CoordFormat : 3; - u32 Tex5Frac : 5; - // 14:22 - u32 Tex6CoordElements : 1; - u32 Tex6CoordFormat : 3; - u32 Tex6Frac : 5; - // 23:31 - u32 Tex7CoordElements : 1; - u32 Tex7CoordFormat : 3; - u32 Tex7Frac : 5; - }; +union UVAT_group2 { + u32 Hex; + struct + { + // 0:4 + u32 Tex4Frac : 5; + // 5:13 + u32 Tex5CoordElements : 1; + u32 Tex5CoordFormat : 3; + u32 Tex5Frac : 5; + // 14:22 + u32 Tex6CoordElements : 1; + u32 Tex6CoordFormat : 3; + u32 Tex6Frac : 5; + // 23:31 + u32 Tex7CoordElements : 1; + u32 Tex7CoordFormat : 3; + u32 Tex7Frac : 5; + }; }; struct ColorAttr { - u8 Elements; - u8 Comp; + u8 Elements; + u8 Comp; }; struct TexAttr { - u8 Elements; - u8 Format; - u8 Frac; + u8 Elements; + u8 Format; + u8 Frac; }; struct TVtxAttr { - u8 PosElements; - u8 PosFormat; - u8 PosFrac; - u8 NormalElements; - u8 NormalFormat; - ColorAttr color[2]; - TexAttr texCoord[8]; - bool ByteDequant; - u8 NormalIndex3; + u8 PosElements; + u8 PosFormat; + u8 PosFrac; + u8 NormalElements; + u8 NormalFormat; + ColorAttr color[2]; + TexAttr texCoord[8]; + bool ByteDequant; + u8 NormalIndex3; }; // Matrix indices -union TMatrixIndexA -{ - struct - { - u32 PosNormalMtxIdx : 6; - u32 Tex0MtxIdx : 6; - u32 Tex1MtxIdx : 6; - u32 Tex2MtxIdx : 6; - u32 Tex3MtxIdx : 6; - }; - struct - { - u32 Hex : 30; - u32 unused : 2; - }; +union TMatrixIndexA { + struct + { + u32 PosNormalMtxIdx : 6; + u32 Tex0MtxIdx : 6; + u32 Tex1MtxIdx : 6; + u32 Tex2MtxIdx : 6; + u32 Tex3MtxIdx : 6; + }; + struct + { + u32 Hex : 30; + u32 unused : 2; + }; }; -union TMatrixIndexB -{ - struct - { - u32 Tex4MtxIdx : 6; - u32 Tex5MtxIdx : 6; - u32 Tex6MtxIdx : 6; - u32 Tex7MtxIdx : 6; - }; - struct - { - u32 Hex : 24; - u32 unused : 8; - }; +union TMatrixIndexB { + struct + { + u32 Tex4MtxIdx : 6; + u32 Tex5MtxIdx : 6; + u32 Tex6MtxIdx : 6; + u32 Tex7MtxIdx : 6; + }; + struct + { + u32 Hex : 24; + u32 unused : 8; + }; }; #pragma pack() struct VAT { - UVAT_group0 g0; - UVAT_group1 g1; - UVAT_group2 g2; + UVAT_group0 g0; + UVAT_group1 g1; + UVAT_group2 g2; }; class VertexLoaderBase; @@ -245,19 +236,19 @@ class VertexLoaderBase; // STATE_TO_SAVE struct CPState final { - u32 array_bases[16]; - u32 array_strides[16]; - TMatrixIndexA matrix_index_a; - TMatrixIndexB matrix_index_b; - TVtxDesc vtx_desc; - // Most games only use the first VtxAttr and simply reconfigure it all the time as needed. - VAT vtx_attr[8]; + u32 array_bases[16]; + u32 array_strides[16]; + TMatrixIndexA matrix_index_a; + TMatrixIndexB matrix_index_b; + TVtxDesc vtx_desc; + // Most games only use the first VtxAttr and simply reconfigure it all the time as needed. + VAT vtx_attr[8]; - // Attributes that actually belong to VertexLoaderManager: - BitSet32 attr_dirty; - bool bases_dirty; - VertexLoaderBase* vertex_loaders[8]; - int last_id; + // Attributes that actually belong to VertexLoaderManager: + BitSet32 attr_dirty; + bool bases_dirty; + VertexLoaderBase* vertex_loaders[8]; + int last_id; }; class PointerWrap; @@ -269,7 +260,7 @@ extern CPState g_preprocess_cp_state; void LoadCPReg(u32 SubCmd, u32 Value, bool is_preprocess = false); // Fills memory with data from CP regs -void FillCPMemoryArray(u32 *memory); +void FillCPMemoryArray(u32* memory); void DoCPState(PointerWrap& p); diff --git a/Source/Core/VideoCommon/CommandProcessor.cpp b/Source/Core/VideoCommon/CommandProcessor.cpp index a480cc90dc..878c3370c5 100644 --- a/Source/Core/VideoCommon/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/CommandProcessor.cpp @@ -20,7 +20,6 @@ namespace CommandProcessor { - static int et_UpdateInterrupts; // TODO(ector): Warn on bbox read/write @@ -28,7 +27,7 @@ static int et_UpdateInterrupts; // STATE_TO_SAVE SCPFifoStruct fifo; static UCPStatusReg m_CPStatusReg; -static UCPCtrlReg m_CPCtrlReg; +static UCPCtrlReg m_CPCtrlReg; static UCPClearReg m_CPClearReg; static u16 m_bboxleft; @@ -44,493 +43,469 @@ static std::atomic s_interrupt_finish_waiting; static bool IsOnThread() { - return SConfig::GetInstance().bCPUThread; + return SConfig::GetInstance().bCPUThread; } static void UpdateInterrupts_Wrapper(u64 userdata, s64 cyclesLate) { - UpdateInterrupts(userdata); + UpdateInterrupts(userdata); } -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - p.DoPOD(m_CPStatusReg); - p.DoPOD(m_CPCtrlReg); - p.DoPOD(m_CPClearReg); - p.Do(m_bboxleft); - p.Do(m_bboxtop); - p.Do(m_bboxright); - p.Do(m_bboxbottom); - p.Do(m_tokenReg); - p.Do(fifo); + p.DoPOD(m_CPStatusReg); + p.DoPOD(m_CPCtrlReg); + p.DoPOD(m_CPClearReg); + p.Do(m_bboxleft); + p.Do(m_bboxtop); + p.Do(m_bboxright); + p.Do(m_bboxbottom); + p.Do(m_tokenReg); + p.Do(fifo); - p.Do(s_interrupt_set); - p.Do(s_interrupt_waiting); - p.Do(s_interrupt_token_waiting); - p.Do(s_interrupt_finish_waiting); + p.Do(s_interrupt_set); + p.Do(s_interrupt_waiting); + p.Do(s_interrupt_token_waiting); + p.Do(s_interrupt_finish_waiting); } static inline void WriteLow(volatile u32& _reg, u16 lowbits) { - Common::AtomicStore(_reg, (_reg & 0xFFFF0000) | lowbits); + Common::AtomicStore(_reg, (_reg & 0xFFFF0000) | lowbits); } static inline void WriteHigh(volatile u32& _reg, u16 highbits) { - Common::AtomicStore(_reg, (_reg & 0x0000FFFF) | ((u32)highbits << 16)); + Common::AtomicStore(_reg, (_reg & 0x0000FFFF) | ((u32)highbits << 16)); } static inline u16 ReadLow(u32 _reg) { - return (u16)(_reg & 0xFFFF); + return (u16)(_reg & 0xFFFF); } static inline u16 ReadHigh(u32 _reg) { - return (u16)(_reg >> 16); + return (u16)(_reg >> 16); } void Init() { - m_CPStatusReg.Hex = 0; - m_CPStatusReg.CommandIdle = 1; - m_CPStatusReg.ReadIdle = 1; + m_CPStatusReg.Hex = 0; + m_CPStatusReg.CommandIdle = 1; + m_CPStatusReg.ReadIdle = 1; - m_CPCtrlReg.Hex = 0; + m_CPCtrlReg.Hex = 0; - m_CPClearReg.Hex = 0; + m_CPClearReg.Hex = 0; - m_bboxleft = 0; - m_bboxtop = 0; - m_bboxright = 640; - m_bboxbottom = 480; + m_bboxleft = 0; + m_bboxtop = 0; + m_bboxright = 640; + m_bboxbottom = 480; - m_tokenReg = 0; + m_tokenReg = 0; - memset(&fifo,0,sizeof(fifo)); - fifo.bFF_Breakpoint = 0; - fifo.bFF_HiWatermark = 0; - fifo.bFF_HiWatermarkInt = 0; - fifo.bFF_LoWatermark = 0; - fifo.bFF_LoWatermarkInt = 0; + memset(&fifo, 0, sizeof(fifo)); + fifo.bFF_Breakpoint = 0; + fifo.bFF_HiWatermark = 0; + fifo.bFF_HiWatermarkInt = 0; + fifo.bFF_LoWatermark = 0; + fifo.bFF_LoWatermarkInt = 0; - s_interrupt_set.store(false); - s_interrupt_waiting.store(false); - s_interrupt_finish_waiting.store(false); - s_interrupt_token_waiting.store(false); + s_interrupt_set.store(false); + s_interrupt_waiting.store(false); + s_interrupt_finish_waiting.store(false); + s_interrupt_token_waiting.store(false); - et_UpdateInterrupts = CoreTiming::RegisterEvent("CPInterrupt", UpdateInterrupts_Wrapper); + et_UpdateInterrupts = CoreTiming::RegisterEvent("CPInterrupt", UpdateInterrupts_Wrapper); } void RegisterMMIO(MMIO::Mapping* mmio, u32 base) { - struct { - u32 addr; - u16* ptr; - bool readonly; - bool writes_align_to_32_bytes; - } directly_mapped_vars[] = { - { FIFO_TOKEN_REGISTER, &m_tokenReg }, + struct + { + u32 addr; + u16* ptr; + bool readonly; + bool writes_align_to_32_bytes; + } directly_mapped_vars[] = { + {FIFO_TOKEN_REGISTER, &m_tokenReg}, - // Bounding box registers are read only. - { FIFO_BOUNDING_BOX_LEFT, &m_bboxleft, true }, - { FIFO_BOUNDING_BOX_RIGHT, &m_bboxright, true }, - { FIFO_BOUNDING_BOX_TOP, &m_bboxtop, true }, - { FIFO_BOUNDING_BOX_BOTTOM, &m_bboxbottom, true }, + // Bounding box registers are read only. + {FIFO_BOUNDING_BOX_LEFT, &m_bboxleft, true}, + {FIFO_BOUNDING_BOX_RIGHT, &m_bboxright, true}, + {FIFO_BOUNDING_BOX_TOP, &m_bboxtop, true}, + {FIFO_BOUNDING_BOX_BOTTOM, &m_bboxbottom, true}, - // Some FIFO addresses need to be aligned on 32 bytes on write - only - // the high part can be written directly without a mask. - { FIFO_BASE_LO, MMIO::Utils::LowPart(&fifo.CPBase), false, true }, - { FIFO_BASE_HI, MMIO::Utils::HighPart(&fifo.CPBase) }, - { FIFO_END_LO, MMIO::Utils::LowPart(&fifo.CPEnd), false, true }, - { FIFO_END_HI, MMIO::Utils::HighPart(&fifo.CPEnd) }, - { FIFO_HI_WATERMARK_LO, MMIO::Utils::LowPart(&fifo.CPHiWatermark) }, - { FIFO_HI_WATERMARK_HI, MMIO::Utils::HighPart(&fifo.CPHiWatermark) }, - { FIFO_LO_WATERMARK_LO, MMIO::Utils::LowPart(&fifo.CPLoWatermark) }, - { FIFO_LO_WATERMARK_HI, MMIO::Utils::HighPart(&fifo.CPLoWatermark) }, - // FIFO_RW_DISTANCE has some complex read code different for - // single/dual core. - { FIFO_WRITE_POINTER_LO, MMIO::Utils::LowPart(&fifo.CPWritePointer), false, true }, - { FIFO_WRITE_POINTER_HI, MMIO::Utils::HighPart(&fifo.CPWritePointer) }, - // FIFO_READ_POINTER has different code for single/dual core. - }; + // Some FIFO addresses need to be aligned on 32 bytes on write - only + // the high part can be written directly without a mask. + {FIFO_BASE_LO, MMIO::Utils::LowPart(&fifo.CPBase), false, true}, + {FIFO_BASE_HI, MMIO::Utils::HighPart(&fifo.CPBase)}, + {FIFO_END_LO, MMIO::Utils::LowPart(&fifo.CPEnd), false, true}, + {FIFO_END_HI, MMIO::Utils::HighPart(&fifo.CPEnd)}, + {FIFO_HI_WATERMARK_LO, MMIO::Utils::LowPart(&fifo.CPHiWatermark)}, + {FIFO_HI_WATERMARK_HI, MMIO::Utils::HighPart(&fifo.CPHiWatermark)}, + {FIFO_LO_WATERMARK_LO, MMIO::Utils::LowPart(&fifo.CPLoWatermark)}, + {FIFO_LO_WATERMARK_HI, MMIO::Utils::HighPart(&fifo.CPLoWatermark)}, + // FIFO_RW_DISTANCE has some complex read code different for + // single/dual core. + {FIFO_WRITE_POINTER_LO, MMIO::Utils::LowPart(&fifo.CPWritePointer), false, true}, + {FIFO_WRITE_POINTER_HI, MMIO::Utils::HighPart(&fifo.CPWritePointer)}, + // FIFO_READ_POINTER has different code for single/dual core. + }; - for (auto& mapped_var : directly_mapped_vars) - { - u16 wmask = mapped_var.writes_align_to_32_bytes ? 0xFFE0 : 0xFFFF; - mmio->Register(base | mapped_var.addr, - MMIO::DirectRead(mapped_var.ptr), - mapped_var.readonly - ? MMIO::InvalidWrite() - : MMIO::DirectWrite(mapped_var.ptr, wmask) - ); - } + for (auto& mapped_var : directly_mapped_vars) + { + u16 wmask = mapped_var.writes_align_to_32_bytes ? 0xFFE0 : 0xFFFF; + mmio->Register(base | mapped_var.addr, MMIO::DirectRead(mapped_var.ptr), + mapped_var.readonly ? MMIO::InvalidWrite() : + MMIO::DirectWrite(mapped_var.ptr, wmask)); + } - mmio->Register(base | FIFO_BP_LO, - MMIO::DirectRead(MMIO::Utils::LowPart(&fifo.CPBreakpoint)), - MMIO::ComplexWrite([](u32, u16 val) { - WriteLow(fifo.CPBreakpoint, val & 0xffe0); - }) - ); - mmio->Register(base | FIFO_BP_HI, - MMIO::DirectRead(MMIO::Utils::HighPart(&fifo.CPBreakpoint)), - MMIO::ComplexWrite([](u32, u16 val) { - WriteHigh(fifo.CPBreakpoint, val); - }) - ); + mmio->Register( + base | FIFO_BP_LO, MMIO::DirectRead(MMIO::Utils::LowPart(&fifo.CPBreakpoint)), + MMIO::ComplexWrite([](u32, u16 val) { WriteLow(fifo.CPBreakpoint, val & 0xffe0); })); + mmio->Register(base | FIFO_BP_HI, + MMIO::DirectRead(MMIO::Utils::HighPart(&fifo.CPBreakpoint)), + MMIO::ComplexWrite([](u32, u16 val) { WriteHigh(fifo.CPBreakpoint, val); })); - // Timing and metrics MMIOs are stubbed with fixed values. - struct { - u32 addr; - u16 value; - } metrics_mmios[] = { - { XF_RASBUSY_L, 0 }, - { XF_RASBUSY_H, 0 }, - { XF_CLKS_L, 0 }, - { XF_CLKS_H, 0 }, - { XF_WAIT_IN_L, 0 }, - { XF_WAIT_IN_H, 0 }, - { XF_WAIT_OUT_L, 0 }, - { XF_WAIT_OUT_H, 0 }, - { VCACHE_METRIC_CHECK_L, 0 }, - { VCACHE_METRIC_CHECK_H, 0 }, - { VCACHE_METRIC_MISS_L, 0 }, - { VCACHE_METRIC_MISS_H, 0 }, - { VCACHE_METRIC_STALL_L, 0 }, - { VCACHE_METRIC_STALL_H, 0 }, - { CLKS_PER_VTX_OUT, 4 }, - }; - for (auto& metrics_mmio : metrics_mmios) - { - mmio->Register(base | metrics_mmio.addr, - MMIO::Constant(metrics_mmio.value), - MMIO::InvalidWrite() - ); - } + // Timing and metrics MMIOs are stubbed with fixed values. + struct + { + u32 addr; + u16 value; + } metrics_mmios[] = { + {XF_RASBUSY_L, 0}, + {XF_RASBUSY_H, 0}, + {XF_CLKS_L, 0}, + {XF_CLKS_H, 0}, + {XF_WAIT_IN_L, 0}, + {XF_WAIT_IN_H, 0}, + {XF_WAIT_OUT_L, 0}, + {XF_WAIT_OUT_H, 0}, + {VCACHE_METRIC_CHECK_L, 0}, + {VCACHE_METRIC_CHECK_H, 0}, + {VCACHE_METRIC_MISS_L, 0}, + {VCACHE_METRIC_MISS_H, 0}, + {VCACHE_METRIC_STALL_L, 0}, + {VCACHE_METRIC_STALL_H, 0}, + {CLKS_PER_VTX_OUT, 4}, + }; + for (auto& metrics_mmio : metrics_mmios) + { + mmio->Register(base | metrics_mmio.addr, MMIO::Constant(metrics_mmio.value), + MMIO::InvalidWrite()); + } - mmio->Register(base | STATUS_REGISTER, - MMIO::ComplexRead([](u32) { - SetCpStatusRegister(); - return m_CPStatusReg.Hex; - }), - MMIO::InvalidWrite() - ); + mmio->Register(base | STATUS_REGISTER, MMIO::ComplexRead([](u32) { + SetCpStatusRegister(); + return m_CPStatusReg.Hex; + }), + MMIO::InvalidWrite()); - mmio->Register(base | CTRL_REGISTER, - MMIO::DirectRead(&m_CPCtrlReg.Hex), - MMIO::ComplexWrite([](u32, u16 val) { - UCPCtrlReg tmp(val); - m_CPCtrlReg.Hex = tmp.Hex; - SetCpControlRegister(); - Fifo::RunGpu(); - }) - ); + mmio->Register(base | CTRL_REGISTER, MMIO::DirectRead(&m_CPCtrlReg.Hex), + MMIO::ComplexWrite([](u32, u16 val) { + UCPCtrlReg tmp(val); + m_CPCtrlReg.Hex = tmp.Hex; + SetCpControlRegister(); + Fifo::RunGpu(); + })); - mmio->Register(base | CLEAR_REGISTER, - MMIO::DirectRead(&m_CPClearReg.Hex), - MMIO::ComplexWrite([](u32, u16 val) { - UCPClearReg tmp(val); - m_CPClearReg.Hex = tmp.Hex; - SetCpClearRegister(); - Fifo::RunGpu(); - }) - ); + mmio->Register(base | CLEAR_REGISTER, MMIO::DirectRead(&m_CPClearReg.Hex), + MMIO::ComplexWrite([](u32, u16 val) { + UCPClearReg tmp(val); + m_CPClearReg.Hex = tmp.Hex; + SetCpClearRegister(); + Fifo::RunGpu(); + })); - mmio->Register(base | PERF_SELECT, - MMIO::InvalidRead(), - MMIO::Nop() - ); + mmio->Register(base | PERF_SELECT, MMIO::InvalidRead(), MMIO::Nop()); - // Some MMIOs have different handlers for single core vs. dual core mode. - mmio->Register(base | FIFO_RW_DISTANCE_LO, - IsOnThread() - ? MMIO::ComplexRead([](u32) { - if (fifo.CPWritePointer >= fifo.SafeCPReadPointer) - return ReadLow(fifo.CPWritePointer - fifo.SafeCPReadPointer); - else - return ReadLow(fifo.CPEnd - fifo.SafeCPReadPointer + fifo.CPWritePointer - fifo.CPBase + 32); - }) - : MMIO::DirectRead(MMIO::Utils::LowPart(&fifo.CPReadWriteDistance)), - MMIO::DirectWrite(MMIO::Utils::LowPart(&fifo.CPReadWriteDistance), 0xFFE0) - ); - mmio->Register(base | FIFO_RW_DISTANCE_HI, - IsOnThread() - ? MMIO::ComplexRead([](u32) { - if (fifo.CPWritePointer >= fifo.SafeCPReadPointer) - return ReadHigh(fifo.CPWritePointer - fifo.SafeCPReadPointer); - else - return ReadHigh(fifo.CPEnd - fifo.SafeCPReadPointer + fifo.CPWritePointer - fifo.CPBase + 32); - }) - : MMIO::DirectRead(MMIO::Utils::HighPart(&fifo.CPReadWriteDistance)), - MMIO::ComplexWrite([](u32, u16 val) { - WriteHigh(fifo.CPReadWriteDistance, val); - Fifo::SyncGPU(Fifo::SYNC_GPU_OTHER); - if (fifo.CPReadWriteDistance == 0) - { - GPFifo::ResetGatherPipe(); - Fifo::ResetVideoBuffer(); - } - else - { - Fifo::ResetVideoBuffer(); - } - Fifo::RunGpu(); - }) - ); - mmio->Register(base | FIFO_READ_POINTER_LO, - IsOnThread() - ? MMIO::DirectRead(MMIO::Utils::LowPart(&fifo.SafeCPReadPointer)) - : MMIO::DirectRead(MMIO::Utils::LowPart(&fifo.CPReadPointer)), - MMIO::DirectWrite(MMIO::Utils::LowPart(&fifo.CPReadPointer), 0xFFE0) - ); - mmio->Register(base | FIFO_READ_POINTER_HI, - IsOnThread() - ? MMIO::DirectRead(MMIO::Utils::HighPart(&fifo.SafeCPReadPointer)) - : MMIO::DirectRead(MMIO::Utils::HighPart(&fifo.CPReadPointer)), - IsOnThread() - ? MMIO::ComplexWrite([](u32, u16 val) { - WriteHigh(fifo.CPReadPointer, val); - fifo.SafeCPReadPointer = fifo.CPReadPointer; - }) - : MMIO::DirectWrite(MMIO::Utils::HighPart(&fifo.CPReadPointer)) - ); + // Some MMIOs have different handlers for single core vs. dual core mode. + mmio->Register(base | FIFO_RW_DISTANCE_LO, + IsOnThread() ? + MMIO::ComplexRead([](u32) { + if (fifo.CPWritePointer >= fifo.SafeCPReadPointer) + return ReadLow(fifo.CPWritePointer - fifo.SafeCPReadPointer); + else + return ReadLow(fifo.CPEnd - fifo.SafeCPReadPointer + fifo.CPWritePointer - + fifo.CPBase + 32); + }) : + MMIO::DirectRead(MMIO::Utils::LowPart(&fifo.CPReadWriteDistance)), + MMIO::DirectWrite(MMIO::Utils::LowPart(&fifo.CPReadWriteDistance), 0xFFE0)); + mmio->Register(base | FIFO_RW_DISTANCE_HI, + IsOnThread() ? + MMIO::ComplexRead([](u32) { + if (fifo.CPWritePointer >= fifo.SafeCPReadPointer) + return ReadHigh(fifo.CPWritePointer - fifo.SafeCPReadPointer); + else + return ReadHigh(fifo.CPEnd - fifo.SafeCPReadPointer + fifo.CPWritePointer - + fifo.CPBase + 32); + }) : + MMIO::DirectRead(MMIO::Utils::HighPart(&fifo.CPReadWriteDistance)), + MMIO::ComplexWrite([](u32, u16 val) { + WriteHigh(fifo.CPReadWriteDistance, val); + Fifo::SyncGPU(Fifo::SYNC_GPU_OTHER); + if (fifo.CPReadWriteDistance == 0) + { + GPFifo::ResetGatherPipe(); + Fifo::ResetVideoBuffer(); + } + else + { + Fifo::ResetVideoBuffer(); + } + Fifo::RunGpu(); + })); + mmio->Register(base | FIFO_READ_POINTER_LO, + IsOnThread() ? + MMIO::DirectRead(MMIO::Utils::LowPart(&fifo.SafeCPReadPointer)) : + MMIO::DirectRead(MMIO::Utils::LowPart(&fifo.CPReadPointer)), + MMIO::DirectWrite(MMIO::Utils::LowPart(&fifo.CPReadPointer), 0xFFE0)); + mmio->Register(base | FIFO_READ_POINTER_HI, + IsOnThread() ? + MMIO::DirectRead(MMIO::Utils::HighPart(&fifo.SafeCPReadPointer)) : + MMIO::DirectRead(MMIO::Utils::HighPart(&fifo.CPReadPointer)), + IsOnThread() ? MMIO::ComplexWrite([](u32, u16 val) { + WriteHigh(fifo.CPReadPointer, val); + fifo.SafeCPReadPointer = fifo.CPReadPointer; + }) : + MMIO::DirectWrite(MMIO::Utils::HighPart(&fifo.CPReadPointer))); } void GatherPipeBursted() { - if (IsOnThread()) - SetCPStatusFromCPU(); + if (IsOnThread()) + SetCPStatusFromCPU(); - ProcessFifoEvents(); - // if we aren't linked, we don't care about gather pipe data - if (!m_CPCtrlReg.GPLinkEnable) - { - if (IsOnThread() && !Fifo::UseDeterministicGPUThread()) - { - // In multibuffer mode is not allowed write in the same FIFO attached to the GPU. - // Fix Pokemon XD in DC mode. - if ((ProcessorInterface::Fifo_CPUEnd == fifo.CPEnd) && - (ProcessorInterface::Fifo_CPUBase == fifo.CPBase) && - fifo.CPReadWriteDistance > 0) - { - Fifo::FlushGpu(); - } - } - Fifo::RunGpu(); - return; - } + ProcessFifoEvents(); + // if we aren't linked, we don't care about gather pipe data + if (!m_CPCtrlReg.GPLinkEnable) + { + if (IsOnThread() && !Fifo::UseDeterministicGPUThread()) + { + // In multibuffer mode is not allowed write in the same FIFO attached to the GPU. + // Fix Pokemon XD in DC mode. + if ((ProcessorInterface::Fifo_CPUEnd == fifo.CPEnd) && + (ProcessorInterface::Fifo_CPUBase == fifo.CPBase) && fifo.CPReadWriteDistance > 0) + { + Fifo::FlushGpu(); + } + } + Fifo::RunGpu(); + return; + } - // update the fifo pointer - if (fifo.CPWritePointer == fifo.CPEnd) - fifo.CPWritePointer = fifo.CPBase; - else - fifo.CPWritePointer += GATHER_PIPE_SIZE; + // update the fifo pointer + if (fifo.CPWritePointer == fifo.CPEnd) + fifo.CPWritePointer = fifo.CPBase; + else + fifo.CPWritePointer += GATHER_PIPE_SIZE; - if (m_CPCtrlReg.GPReadEnable && m_CPCtrlReg.GPLinkEnable) - { - ProcessorInterface::Fifo_CPUWritePointer = fifo.CPWritePointer; - ProcessorInterface::Fifo_CPUBase = fifo.CPBase; - ProcessorInterface::Fifo_CPUEnd = fifo.CPEnd; - } + if (m_CPCtrlReg.GPReadEnable && m_CPCtrlReg.GPLinkEnable) + { + ProcessorInterface::Fifo_CPUWritePointer = fifo.CPWritePointer; + ProcessorInterface::Fifo_CPUBase = fifo.CPBase; + ProcessorInterface::Fifo_CPUEnd = fifo.CPEnd; + } - // If the game is running close to overflowing, make the exception checking more frequent. - if (fifo.bFF_HiWatermark) - CoreTiming::ForceExceptionCheck(0); + // If the game is running close to overflowing, make the exception checking more frequent. + if (fifo.bFF_HiWatermark) + CoreTiming::ForceExceptionCheck(0); - Common::AtomicAdd(fifo.CPReadWriteDistance, GATHER_PIPE_SIZE); + Common::AtomicAdd(fifo.CPReadWriteDistance, GATHER_PIPE_SIZE); - Fifo::RunGpu(); + Fifo::RunGpu(); - _assert_msg_(COMMANDPROCESSOR, fifo.CPReadWriteDistance <= fifo.CPEnd - fifo.CPBase, - "FIFO is overflowed by GatherPipe !\nCPU thread is too fast!"); + _assert_msg_(COMMANDPROCESSOR, fifo.CPReadWriteDistance <= fifo.CPEnd - fifo.CPBase, + "FIFO is overflowed by GatherPipe !\nCPU thread is too fast!"); - // check if we are in sync - _assert_msg_(COMMANDPROCESSOR, fifo.CPWritePointer == ProcessorInterface::Fifo_CPUWritePointer, "FIFOs linked but out of sync"); - _assert_msg_(COMMANDPROCESSOR, fifo.CPBase == ProcessorInterface::Fifo_CPUBase, "FIFOs linked but out of sync"); - _assert_msg_(COMMANDPROCESSOR, fifo.CPEnd == ProcessorInterface::Fifo_CPUEnd, "FIFOs linked but out of sync"); + // check if we are in sync + _assert_msg_(COMMANDPROCESSOR, fifo.CPWritePointer == ProcessorInterface::Fifo_CPUWritePointer, + "FIFOs linked but out of sync"); + _assert_msg_(COMMANDPROCESSOR, fifo.CPBase == ProcessorInterface::Fifo_CPUBase, + "FIFOs linked but out of sync"); + _assert_msg_(COMMANDPROCESSOR, fifo.CPEnd == ProcessorInterface::Fifo_CPUEnd, + "FIFOs linked but out of sync"); } void UpdateInterrupts(u64 userdata) { - if (userdata) - { - s_interrupt_set.store(true); - INFO_LOG(COMMANDPROCESSOR,"Interrupt set"); - ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true); - } - else - { - s_interrupt_set.store(false); - INFO_LOG(COMMANDPROCESSOR,"Interrupt cleared"); - ProcessorInterface::SetInterrupt(INT_CAUSE_CP, false); - } - CoreTiming::ForceExceptionCheck(0); - s_interrupt_waiting.store(false); - Fifo::RunGpu(); + if (userdata) + { + s_interrupt_set.store(true); + INFO_LOG(COMMANDPROCESSOR, "Interrupt set"); + ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true); + } + else + { + s_interrupt_set.store(false); + INFO_LOG(COMMANDPROCESSOR, "Interrupt cleared"); + ProcessorInterface::SetInterrupt(INT_CAUSE_CP, false); + } + CoreTiming::ForceExceptionCheck(0); + s_interrupt_waiting.store(false); + Fifo::RunGpu(); } void UpdateInterruptsFromVideoBackend(u64 userdata) { - if (!Fifo::UseDeterministicGPUThread()) - CoreTiming::ScheduleEvent_Threadsafe(0, et_UpdateInterrupts, userdata); + if (!Fifo::UseDeterministicGPUThread()) + CoreTiming::ScheduleEvent_Threadsafe(0, et_UpdateInterrupts, userdata); } bool IsInterruptWaiting() { - return s_interrupt_waiting.load(); + return s_interrupt_waiting.load(); } void SetInterruptTokenWaiting(bool waiting) { - s_interrupt_token_waiting.store(waiting); + s_interrupt_token_waiting.store(waiting); } void SetInterruptFinishWaiting(bool waiting) { - s_interrupt_finish_waiting.store(waiting); + s_interrupt_finish_waiting.store(waiting); } void SetCPStatusFromGPU() { - // breakpoint - if (fifo.bFF_BPEnable) - { - if (fifo.CPBreakpoint == fifo.CPReadPointer) - { - if (!fifo.bFF_Breakpoint) - { - INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %i", fifo.CPReadPointer); - fifo.bFF_Breakpoint = true; - } - } - else - { - if (fifo.bFF_Breakpoint) - INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer); - fifo.bFF_Breakpoint = false; - } - } - else - { - if (fifo.bFF_Breakpoint) - INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer); - fifo.bFF_Breakpoint = false; - } + // breakpoint + if (fifo.bFF_BPEnable) + { + if (fifo.CPBreakpoint == fifo.CPReadPointer) + { + if (!fifo.bFF_Breakpoint) + { + INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %i", fifo.CPReadPointer); + fifo.bFF_Breakpoint = true; + } + } + else + { + if (fifo.bFF_Breakpoint) + INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer); + fifo.bFF_Breakpoint = false; + } + } + else + { + if (fifo.bFF_Breakpoint) + INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer); + fifo.bFF_Breakpoint = false; + } - // overflow & underflow check - fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark); - fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark); + // overflow & underflow check + fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark); + fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark); - bool bpInt = fifo.bFF_Breakpoint && fifo.bFF_BPInt; - bool ovfInt = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt; - bool undfInt = fifo.bFF_LoWatermark && fifo.bFF_LoWatermarkInt; + bool bpInt = fifo.bFF_Breakpoint && fifo.bFF_BPInt; + bool ovfInt = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt; + bool undfInt = fifo.bFF_LoWatermark && fifo.bFF_LoWatermarkInt; - bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable; + bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable; - if (interrupt != s_interrupt_set.load() && !s_interrupt_waiting.load()) - { - u64 userdata = interrupt ? 1 : 0; - if (IsOnThread()) - { - if (!interrupt || bpInt || undfInt || ovfInt) - { - // Schedule the interrupt asynchronously - s_interrupt_waiting.store(true); - CommandProcessor::UpdateInterruptsFromVideoBackend(userdata); - } - } - else - { - CommandProcessor::UpdateInterrupts(userdata); - } - } + if (interrupt != s_interrupt_set.load() && !s_interrupt_waiting.load()) + { + u64 userdata = interrupt ? 1 : 0; + if (IsOnThread()) + { + if (!interrupt || bpInt || undfInt || ovfInt) + { + // Schedule the interrupt asynchronously + s_interrupt_waiting.store(true); + CommandProcessor::UpdateInterruptsFromVideoBackend(userdata); + } + } + else + { + CommandProcessor::UpdateInterrupts(userdata); + } + } } void SetCPStatusFromCPU() { - // overflow & underflow check - fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark); - fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark); + // overflow & underflow check + fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark); + fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark); - bool bpInt = fifo.bFF_Breakpoint && fifo.bFF_BPInt; - bool ovfInt = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt; - bool undfInt = fifo.bFF_LoWatermark && fifo.bFF_LoWatermarkInt; + bool bpInt = fifo.bFF_Breakpoint && fifo.bFF_BPInt; + bool ovfInt = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt; + bool undfInt = fifo.bFF_LoWatermark && fifo.bFF_LoWatermarkInt; - bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable; + bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable; - if (interrupt != s_interrupt_set.load() && !s_interrupt_waiting.load()) - { - u64 userdata = interrupt ? 1 : 0; - if (IsOnThread()) - { - if (!interrupt || bpInt || undfInt || ovfInt) - { - s_interrupt_set.store(interrupt); - INFO_LOG(COMMANDPROCESSOR,"Interrupt set"); - ProcessorInterface::SetInterrupt(INT_CAUSE_CP, interrupt); - } - } - else - { - CommandProcessor::UpdateInterrupts(userdata); - } - } + if (interrupt != s_interrupt_set.load() && !s_interrupt_waiting.load()) + { + u64 userdata = interrupt ? 1 : 0; + if (IsOnThread()) + { + if (!interrupt || bpInt || undfInt || ovfInt) + { + s_interrupt_set.store(interrupt); + INFO_LOG(COMMANDPROCESSOR, "Interrupt set"); + ProcessorInterface::SetInterrupt(INT_CAUSE_CP, interrupt); + } + } + else + { + CommandProcessor::UpdateInterrupts(userdata); + } + } } void ProcessFifoEvents() { - if (IsOnThread() && (s_interrupt_waiting.load() || s_interrupt_finish_waiting.load() || s_interrupt_token_waiting.load())) - CoreTiming::ProcessFifoWaitEvents(); + if (IsOnThread() && (s_interrupt_waiting.load() || s_interrupt_finish_waiting.load() || + s_interrupt_token_waiting.load())) + CoreTiming::ProcessFifoWaitEvents(); } void Shutdown() { - } void SetCpStatusRegister() { - // Here always there is one fifo attached to the GPU - m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint; - m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || (fifo.CPReadPointer == fifo.CPWritePointer); - m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance || Fifo::AtBreakpoint() || !fifo.bFF_GPReadEnable; - m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark; - m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark; + // Here always there is one fifo attached to the GPU + m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint; + m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || (fifo.CPReadPointer == fifo.CPWritePointer); + m_CPStatusReg.CommandIdle = + !fifo.CPReadWriteDistance || Fifo::AtBreakpoint() || !fifo.bFF_GPReadEnable; + m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark; + m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark; - INFO_LOG(COMMANDPROCESSOR,"\t Read from STATUS_REGISTER : %04x", m_CPStatusReg.Hex); - DEBUG_LOG(COMMANDPROCESSOR, "(r) status: iBP %s | fReadIdle %s | fCmdIdle %s | iOvF %s | iUndF %s" - , m_CPStatusReg.Breakpoint ? "ON" : "OFF" - , m_CPStatusReg.ReadIdle ? "ON" : "OFF" - , m_CPStatusReg.CommandIdle ? "ON" : "OFF" - , m_CPStatusReg.OverflowHiWatermark ? "ON" : "OFF" - , m_CPStatusReg.UnderflowLoWatermark ? "ON" : "OFF" - ); + INFO_LOG(COMMANDPROCESSOR, "\t Read from STATUS_REGISTER : %04x", m_CPStatusReg.Hex); + DEBUG_LOG( + COMMANDPROCESSOR, "(r) status: iBP %s | fReadIdle %s | fCmdIdle %s | iOvF %s | iUndF %s", + m_CPStatusReg.Breakpoint ? "ON" : "OFF", m_CPStatusReg.ReadIdle ? "ON" : "OFF", + m_CPStatusReg.CommandIdle ? "ON" : "OFF", m_CPStatusReg.OverflowHiWatermark ? "ON" : "OFF", + m_CPStatusReg.UnderflowLoWatermark ? "ON" : "OFF"); } void SetCpControlRegister() { - fifo.bFF_BPInt = m_CPCtrlReg.BPInt; - fifo.bFF_BPEnable = m_CPCtrlReg.BPEnable; - fifo.bFF_HiWatermarkInt = m_CPCtrlReg.FifoOverflowIntEnable; - fifo.bFF_LoWatermarkInt = m_CPCtrlReg.FifoUnderflowIntEnable; - fifo.bFF_GPLinkEnable = m_CPCtrlReg.GPLinkEnable; + fifo.bFF_BPInt = m_CPCtrlReg.BPInt; + fifo.bFF_BPEnable = m_CPCtrlReg.BPEnable; + fifo.bFF_HiWatermarkInt = m_CPCtrlReg.FifoOverflowIntEnable; + fifo.bFF_LoWatermarkInt = m_CPCtrlReg.FifoUnderflowIntEnable; + fifo.bFF_GPLinkEnable = m_CPCtrlReg.GPLinkEnable; - if (fifo.bFF_GPReadEnable && !m_CPCtrlReg.GPReadEnable) - { - fifo.bFF_GPReadEnable = m_CPCtrlReg.GPReadEnable; - Fifo::FlushGpu(); - } - else - { - fifo.bFF_GPReadEnable = m_CPCtrlReg.GPReadEnable; - } - - DEBUG_LOG(COMMANDPROCESSOR, "\t GPREAD %s | BP %s | Int %s | OvF %s | UndF %s | LINK %s" - , fifo.bFF_GPReadEnable ? "ON" : "OFF" - , fifo.bFF_BPEnable ? "ON" : "OFF" - , fifo.bFF_BPInt ? "ON" : "OFF" - , m_CPCtrlReg.FifoOverflowIntEnable ? "ON" : "OFF" - , m_CPCtrlReg.FifoUnderflowIntEnable ? "ON" : "OFF" - , m_CPCtrlReg.GPLinkEnable ? "ON" : "OFF" - ); + if (fifo.bFF_GPReadEnable && !m_CPCtrlReg.GPReadEnable) + { + fifo.bFF_GPReadEnable = m_CPCtrlReg.GPReadEnable; + Fifo::FlushGpu(); + } + else + { + fifo.bFF_GPReadEnable = m_CPCtrlReg.GPReadEnable; + } + DEBUG_LOG(COMMANDPROCESSOR, "\t GPREAD %s | BP %s | Int %s | OvF %s | UndF %s | LINK %s", + fifo.bFF_GPReadEnable ? "ON" : "OFF", fifo.bFF_BPEnable ? "ON" : "OFF", + fifo.bFF_BPInt ? "ON" : "OFF", m_CPCtrlReg.FifoOverflowIntEnable ? "ON" : "OFF", + m_CPCtrlReg.FifoUnderflowIntEnable ? "ON" : "OFF", + m_CPCtrlReg.GPLinkEnable ? "ON" : "OFF"); } // NOTE: We intentionally don't emulate this function at the moment. @@ -539,4 +514,4 @@ void SetCpClearRegister() { } -} // end of namespace CommandProcessor +} // end of namespace CommandProcessor diff --git a/Source/Core/VideoCommon/CommandProcessor.h b/Source/Core/VideoCommon/CommandProcessor.h index e840c40bb1..2d9ce675e5 100644 --- a/Source/Core/VideoCommon/CommandProcessor.h +++ b/Source/Core/VideoCommon/CommandProcessor.h @@ -8,120 +8,119 @@ #include "VideoCommon/VideoBackendBase.h" class PointerWrap; -namespace MMIO { class Mapping; } +namespace MMIO +{ +class Mapping; +} namespace CommandProcessor { - -extern SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread. +extern SCPFifoStruct fifo; // This one is shared between gfx thread and emulator thread. // internal hardware addresses enum { - STATUS_REGISTER = 0x00, - CTRL_REGISTER = 0x02, - CLEAR_REGISTER = 0x04, - PERF_SELECT = 0x06, - FIFO_TOKEN_REGISTER = 0x0E, - FIFO_BOUNDING_BOX_LEFT = 0x10, - FIFO_BOUNDING_BOX_RIGHT = 0x12, - FIFO_BOUNDING_BOX_TOP = 0x14, - FIFO_BOUNDING_BOX_BOTTOM = 0x16, - FIFO_BASE_LO = 0x20, - FIFO_BASE_HI = 0x22, - FIFO_END_LO = 0x24, - FIFO_END_HI = 0x26, - FIFO_HI_WATERMARK_LO = 0x28, - FIFO_HI_WATERMARK_HI = 0x2a, - FIFO_LO_WATERMARK_LO = 0x2c, - FIFO_LO_WATERMARK_HI = 0x2e, - FIFO_RW_DISTANCE_LO = 0x30, - FIFO_RW_DISTANCE_HI = 0x32, - FIFO_WRITE_POINTER_LO = 0x34, - FIFO_WRITE_POINTER_HI = 0x36, - FIFO_READ_POINTER_LO = 0x38, - FIFO_READ_POINTER_HI = 0x3A, - FIFO_BP_LO = 0x3C, - FIFO_BP_HI = 0x3E, - XF_RASBUSY_L = 0x40, - XF_RASBUSY_H = 0x42, - XF_CLKS_L = 0x44, - XF_CLKS_H = 0x46, - XF_WAIT_IN_L = 0x48, - XF_WAIT_IN_H = 0x4a, - XF_WAIT_OUT_L = 0x4c, - XF_WAIT_OUT_H = 0x4e, - VCACHE_METRIC_CHECK_L = 0x50, - VCACHE_METRIC_CHECK_H = 0x52, - VCACHE_METRIC_MISS_L = 0x54, - VCACHE_METRIC_MISS_H = 0x56, - VCACHE_METRIC_STALL_L = 0x58, - VCACHE_METRIC_STALL_H = 0x5A, - CLKS_PER_VTX_IN_L = 0x60, - CLKS_PER_VTX_IN_H = 0x62, - CLKS_PER_VTX_OUT = 0x64, + STATUS_REGISTER = 0x00, + CTRL_REGISTER = 0x02, + CLEAR_REGISTER = 0x04, + PERF_SELECT = 0x06, + FIFO_TOKEN_REGISTER = 0x0E, + FIFO_BOUNDING_BOX_LEFT = 0x10, + FIFO_BOUNDING_BOX_RIGHT = 0x12, + FIFO_BOUNDING_BOX_TOP = 0x14, + FIFO_BOUNDING_BOX_BOTTOM = 0x16, + FIFO_BASE_LO = 0x20, + FIFO_BASE_HI = 0x22, + FIFO_END_LO = 0x24, + FIFO_END_HI = 0x26, + FIFO_HI_WATERMARK_LO = 0x28, + FIFO_HI_WATERMARK_HI = 0x2a, + FIFO_LO_WATERMARK_LO = 0x2c, + FIFO_LO_WATERMARK_HI = 0x2e, + FIFO_RW_DISTANCE_LO = 0x30, + FIFO_RW_DISTANCE_HI = 0x32, + FIFO_WRITE_POINTER_LO = 0x34, + FIFO_WRITE_POINTER_HI = 0x36, + FIFO_READ_POINTER_LO = 0x38, + FIFO_READ_POINTER_HI = 0x3A, + FIFO_BP_LO = 0x3C, + FIFO_BP_HI = 0x3E, + XF_RASBUSY_L = 0x40, + XF_RASBUSY_H = 0x42, + XF_CLKS_L = 0x44, + XF_CLKS_H = 0x46, + XF_WAIT_IN_L = 0x48, + XF_WAIT_IN_H = 0x4a, + XF_WAIT_OUT_L = 0x4c, + XF_WAIT_OUT_H = 0x4e, + VCACHE_METRIC_CHECK_L = 0x50, + VCACHE_METRIC_CHECK_H = 0x52, + VCACHE_METRIC_MISS_L = 0x54, + VCACHE_METRIC_MISS_H = 0x56, + VCACHE_METRIC_STALL_L = 0x58, + VCACHE_METRIC_STALL_H = 0x5A, + CLKS_PER_VTX_IN_L = 0x60, + CLKS_PER_VTX_IN_H = 0x62, + CLKS_PER_VTX_OUT = 0x64, }; enum { - GATHER_PIPE_SIZE = 32, - INT_CAUSE_CP = 0x800 + GATHER_PIPE_SIZE = 32, + INT_CAUSE_CP = 0x800 }; // Fifo Status Register -union UCPStatusReg -{ - struct - { - u16 OverflowHiWatermark : 1; - u16 UnderflowLoWatermark : 1; - u16 ReadIdle : 1; - u16 CommandIdle : 1; - u16 Breakpoint : 1; - u16 : 11; - }; - u16 Hex; - UCPStatusReg() {Hex = 0; } - UCPStatusReg(u16 _hex) {Hex = _hex; } +union UCPStatusReg { + struct + { + u16 OverflowHiWatermark : 1; + u16 UnderflowLoWatermark : 1; + u16 ReadIdle : 1; + u16 CommandIdle : 1; + u16 Breakpoint : 1; + u16 : 11; + }; + u16 Hex; + UCPStatusReg() { Hex = 0; } + UCPStatusReg(u16 _hex) { Hex = _hex; } }; // Fifo Control Register -union UCPCtrlReg -{ - struct - { - u16 GPReadEnable : 1; - u16 BPEnable : 1; - u16 FifoOverflowIntEnable : 1; - u16 FifoUnderflowIntEnable : 1; - u16 GPLinkEnable : 1; - u16 BPInt : 1; - u16 : 10; - }; - u16 Hex; - UCPCtrlReg() {Hex = 0; } - UCPCtrlReg(u16 _hex) {Hex = _hex; } +union UCPCtrlReg { + struct + { + u16 GPReadEnable : 1; + u16 BPEnable : 1; + u16 FifoOverflowIntEnable : 1; + u16 FifoUnderflowIntEnable : 1; + u16 GPLinkEnable : 1; + u16 BPInt : 1; + u16 : 10; + }; + u16 Hex; + UCPCtrlReg() { Hex = 0; } + UCPCtrlReg(u16 _hex) { Hex = _hex; } }; // Fifo Clear Register -union UCPClearReg -{ - struct - { - u16 ClearFifoOverflow : 1; - u16 ClearFifoUnderflow : 1; - u16 ClearMetrices : 1; - u16 : 13; - }; - u16 Hex; - UCPClearReg() {Hex = 0; } - UCPClearReg(u16 _hex) {Hex = _hex; } +union UCPClearReg { + struct + { + u16 ClearFifoOverflow : 1; + u16 ClearFifoUnderflow : 1; + u16 ClearMetrices : 1; + u16 : 13; + }; + u16 Hex; + UCPClearReg() { Hex = 0; } + UCPClearReg(u16 _hex) { Hex = _hex; } }; // Init void Init(); void Shutdown(); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); void RegisterMMIO(MMIO::Mapping* mmio, u32 base); @@ -140,4 +139,4 @@ void SetCpControlRegister(); void SetCpStatusRegister(); void ProcessFifoEvents(); -} // namespace CommandProcessor +} // namespace CommandProcessor diff --git a/Source/Core/VideoCommon/ConstantManager.h b/Source/Core/VideoCommon/ConstantManager.h index e44fd55424..cb12a1df07 100644 --- a/Source/Core/VideoCommon/ConstantManager.h +++ b/Source/Core/VideoCommon/ConstantManager.h @@ -13,43 +13,43 @@ typedef s32 int4[4]; struct PixelShaderConstants { - int4 colors[4]; - int4 kcolors[4]; - int4 alpha; - float4 texdims[8]; - int4 zbias[2]; - int4 indtexscale[2]; - int4 indtexmtx[6]; - int4 fogcolor; - int4 fogi; - float4 fogf[2]; - float4 zslope; - float4 efbscale; + int4 colors[4]; + int4 kcolors[4]; + int4 alpha; + float4 texdims[8]; + int4 zbias[2]; + int4 indtexscale[2]; + int4 indtexmtx[6]; + int4 fogcolor; + int4 fogi; + float4 fogf[2]; + float4 zslope; + float4 efbscale; }; struct VertexShaderConstants { - float4 posnormalmatrix[6]; - float4 projection[4]; - int4 materials[4]; - struct Light - { - int4 color; - float4 cosatt; - float4 distatt; - float4 pos; - float4 dir; - } lights [8]; - float4 texmatrices[24]; - float4 transformmatrices[64]; - float4 normalmatrices[32]; - float4 posttransformmatrices[64]; - float4 pixelcentercorrection; + float4 posnormalmatrix[6]; + float4 projection[4]; + int4 materials[4]; + struct Light + { + int4 color; + float4 cosatt; + float4 distatt; + float4 pos; + float4 dir; + } lights[8]; + float4 texmatrices[24]; + float4 transformmatrices[64]; + float4 normalmatrices[32]; + float4 posttransformmatrices[64]; + float4 pixelcentercorrection; }; struct GeometryShaderConstants { - float4 stereoparams; - float4 lineptparams; - int4 texoffset; + float4 stereoparams; + float4 lineptparams; + int4 texoffset; }; diff --git a/Source/Core/VideoCommon/DataReader.h b/Source/Core/VideoCommon/DataReader.h index 92f55b3c8d..08c02d64ba 100644 --- a/Source/Core/VideoCommon/DataReader.h +++ b/Source/Core/VideoCommon/DataReader.h @@ -12,61 +12,53 @@ class DataReader { public: - __forceinline DataReader() - : buffer(nullptr), end(nullptr) {} + __forceinline DataReader() : buffer(nullptr), end(nullptr) {} + __forceinline DataReader(u8* src, u8* _end) : buffer(src), end(_end) {} + __forceinline u8* GetPointer() { return buffer; } + __forceinline u8* operator=(u8* src) + { + buffer = src; + return src; + } - __forceinline DataReader(u8* src, u8* _end) - : buffer(src), end(_end) {} + __forceinline size_t size() { return end - buffer; } + template + __forceinline T Peek(int offset = 0) + { + T data; + std::memcpy(&data, &buffer[offset], sizeof(T)); - __forceinline u8* GetPointer() - { - return buffer; - } + if (swapped) + data = Common::FromBigEndian(data); - __forceinline u8* operator=(u8* src) - { - buffer = src; - return src; - } + return data; + } - __forceinline size_t size() - { - return end - buffer; - } + template + __forceinline T Read() + { + const T result = Peek(); + buffer += sizeof(T); + return result; + } - template __forceinline T Peek(int offset = 0) - { - T data; - std::memcpy(&data, &buffer[offset], sizeof(T)); + template + __forceinline void Write(T data) + { + if (swapped) + data = Common::FromBigEndian(data); - if (swapped) - data = Common::FromBigEndian(data); + std::memcpy(buffer, &data, sizeof(T)); + buffer += sizeof(T); + } - return data; - } - - template __forceinline T Read() - { - const T result = Peek(); - buffer += sizeof(T); - return result; - } - - template __forceinline void Write(T data) - { - if (swapped) - data = Common::FromBigEndian(data); - - std::memcpy(buffer, &data, sizeof(T)); - buffer += sizeof(T); - } - - template __forceinline void Skip(size_t data = 1) - { - buffer += sizeof(T) * data; - } + template + __forceinline void Skip(size_t data = 1) + { + buffer += sizeof(T) * data; + } private: - u8* __restrict buffer; - u8* end; + u8* __restrict buffer; + u8* end; }; diff --git a/Source/Core/VideoCommon/Debugger.cpp b/Source/Core/VideoCommon/Debugger.cpp index 039b38ba6e..86f3f99345 100644 --- a/Source/Core/VideoCommon/Debugger.cpp +++ b/Source/Core/VideoCommon/Debugger.cpp @@ -12,143 +12,152 @@ #include "VideoCommon/Debugger.h" #include "VideoCommon/VideoConfig.h" -GFXDebuggerBase *g_pdebugger = nullptr; -volatile bool GFXDebuggerPauseFlag = false; // if true, the GFX thread will be spin locked until it's false again -volatile PauseEvent GFXDebuggerToPauseAtNext = NOT_PAUSE; // Event which will trigger spin locking the GFX thread -volatile int GFXDebuggerEventToPauseCount = 0; // Number of events to wait for until GFX thread will be paused +GFXDebuggerBase* g_pdebugger = nullptr; +volatile bool GFXDebuggerPauseFlag = + false; // if true, the GFX thread will be spin locked until it's false again +volatile PauseEvent GFXDebuggerToPauseAtNext = + NOT_PAUSE; // Event which will trigger spin locking the GFX thread +volatile int GFXDebuggerEventToPauseCount = + 0; // Number of events to wait for until GFX thread will be paused void GFXDebuggerUpdateScreen() { - // TODO: Implement this in a backend-independent way -/* // update screen - if (D3D::bFrameInProgress) - { - D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); - D3D::dev->SetDepthStencilSurface(nullptr); + // TODO: Implement this in a backend-independent way + /* // update screen + if (D3D::bFrameInProgress) + { + D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); + D3D::dev->SetDepthStencilSurface(nullptr); - D3D::dev->StretchRect(FramebufferManager::GetEFBColorRTSurface(), nullptr, - D3D::GetBackBufferSurface(), nullptr, - D3DTEXF_LINEAR); + D3D::dev->StretchRect(FramebufferManager::GetEFBColorRTSurface(), nullptr, + D3D::GetBackBufferSurface(), nullptr, + D3DTEXF_LINEAR); - D3D::dev->EndScene(); - D3D::dev->Present(nullptr, nullptr, nullptr, nullptr); + D3D::dev->EndScene(); + D3D::dev->Present(nullptr, nullptr, nullptr, nullptr); - D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); - D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); - D3D::dev->BeginScene(); - } - else - { - D3D::dev->EndScene(); - D3D::dev->Present(nullptr, nullptr, nullptr, nullptr); - D3D::dev->BeginScene(); - }*/ + D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); + D3D::dev->BeginScene(); + } + else + { + D3D::dev->EndScene(); + D3D::dev->Present(nullptr, nullptr, nullptr, nullptr); + D3D::dev->BeginScene(); + }*/ } // GFX thread void GFXDebuggerCheckAndPause(bool update) { - if (GFXDebuggerPauseFlag) - { - g_pdebugger->OnPause(); - while ( GFXDebuggerPauseFlag ) - { - if (update) GFXDebuggerUpdateScreen(); - Common::SleepCurrentThread(5); - } - g_pdebugger->OnContinue(); - } + if (GFXDebuggerPauseFlag) + { + g_pdebugger->OnPause(); + while (GFXDebuggerPauseFlag) + { + if (update) + GFXDebuggerUpdateScreen(); + Common::SleepCurrentThread(5); + } + g_pdebugger->OnContinue(); + } } // GFX thread void GFXDebuggerToPause(bool update) { - GFXDebuggerToPauseAtNext = NOT_PAUSE; - GFXDebuggerPauseFlag = true; - GFXDebuggerCheckAndPause(update); + GFXDebuggerToPauseAtNext = NOT_PAUSE; + GFXDebuggerPauseFlag = true; + GFXDebuggerCheckAndPause(update); } void ContinueGFXDebugger() { - GFXDebuggerPauseFlag = false; + GFXDebuggerPauseFlag = false; } - void GFXDebuggerBase::DumpPixelShader(const std::string& path) { - const std::string filename = StringFromFormat("%sdump_ps.txt", path.c_str()); + const std::string filename = StringFromFormat("%sdump_ps.txt", path.c_str()); - std::string output; - bool useDstAlpha = bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate && bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; - if (!useDstAlpha) - { - output = "Destination alpha disabled:\n"; -/// output += GeneratePixelShaderCode(DSTALPHA_NONE, g_ActiveConfig.backend_info.APIType, g_nativeVertexFmt->m_components); - } - else - { - if (g_ActiveConfig.backend_info.bSupportsDualSourceBlend) - { - output = "Using dual source blending for destination alpha:\n"; -/// output += GeneratePixelShaderCode(DSTALPHA_DUAL_SOURCE_BLEND, g_ActiveConfig.backend_info.APIType, g_nativeVertexFmt->m_components); - } - else - { - output = "Using two passes for emulating destination alpha:\n"; -/// output += GeneratePixelShaderCode(DSTALPHA_NONE, g_ActiveConfig.backend_info.APIType, g_nativeVertexFmt->m_components); - output += "\n\nDestination alpha pass shader:\n"; -/// output += GeneratePixelShaderCode(DSTALPHA_ALPHA_PASS, g_ActiveConfig.backend_info.APIType, g_nativeVertexFmt->m_components); - } - } + std::string output; + bool useDstAlpha = bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate && + bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; + if (!useDstAlpha) + { + output = "Destination alpha disabled:\n"; + /// output += GeneratePixelShaderCode(DSTALPHA_NONE, g_ActiveConfig.backend_info.APIType, + ///g_nativeVertexFmt->m_components); + } + else + { + if (g_ActiveConfig.backend_info.bSupportsDualSourceBlend) + { + output = "Using dual source blending for destination alpha:\n"; + /// output += GeneratePixelShaderCode(DSTALPHA_DUAL_SOURCE_BLEND, + ///g_ActiveConfig.backend_info.APIType, g_nativeVertexFmt->m_components); + } + else + { + output = "Using two passes for emulating destination alpha:\n"; + /// output += GeneratePixelShaderCode(DSTALPHA_NONE, g_ActiveConfig.backend_info.APIType, + ///g_nativeVertexFmt->m_components); + output += "\n\nDestination alpha pass shader:\n"; + /// output += GeneratePixelShaderCode(DSTALPHA_ALPHA_PASS, + ///g_ActiveConfig.backend_info.APIType, g_nativeVertexFmt->m_components); + } + } - File::CreateEmptyFile(filename); - File::WriteStringToFile(output, filename); + File::CreateEmptyFile(filename); + File::WriteStringToFile(output, filename); } void GFXDebuggerBase::DumpVertexShader(const std::string& path) { - const std::string filename = StringFromFormat("%sdump_vs.txt", path.c_str()); + const std::string filename = StringFromFormat("%sdump_vs.txt", path.c_str()); - File::CreateEmptyFile(filename); -/// File::WriteStringToFile(GenerateVertexShaderCode(g_nativeVertexFmt->m_components, g_ActiveConfig.backend_info.APIType), filename); + File::CreateEmptyFile(filename); + /// File::WriteStringToFile(GenerateVertexShaderCode(g_nativeVertexFmt->m_components, + ///g_ActiveConfig.backend_info.APIType), filename); } void GFXDebuggerBase::DumpPixelShaderConstants(const std::string& path) { - // TODO + // TODO } void GFXDebuggerBase::DumpVertexShaderConstants(const std::string& path) { - // TODO + // TODO } void GFXDebuggerBase::DumpTextures(const std::string& path) { - // TODO + // TODO } void GFXDebuggerBase::DumpFrameBuffer(const std::string& path) { - // TODO + // TODO } void GFXDebuggerBase::DumpGeometry(const std::string& path) { - // TODO + // TODO } void GFXDebuggerBase::DumpVertexDecl(const std::string& path) { - // TODO + // TODO } void GFXDebuggerBase::DumpMatrices(const std::string& path) { - // TODO + // TODO } void GFXDebuggerBase::DumpStats(const std::string& path) { - // TODO + // TODO } diff --git a/Source/Core/VideoCommon/Debugger.h b/Source/Core/VideoCommon/Debugger.h index 4147758983..1c2d293edc 100644 --- a/Source/Core/VideoCommon/Debugger.h +++ b/Source/Core/VideoCommon/Debugger.h @@ -9,50 +9,48 @@ class GFXDebuggerBase { public: - virtual ~GFXDebuggerBase() {} - - // if paused, debugging functions can be enabled - virtual void OnPause() {} - virtual void OnContinue() {} - - void DumpPixelShader(const std::string& path); - void DumpVertexShader(const std::string& path); - void DumpPixelShaderConstants(const std::string& path); - void DumpVertexShaderConstants(const std::string& path); - void DumpTextures(const std::string& path); - void DumpFrameBuffer(const std::string& path); - void DumpGeometry(const std::string& path); - void DumpVertexDecl(const std::string& path); - void DumpMatrices(const std::string& path); - void DumpStats(const std::string& path); + virtual ~GFXDebuggerBase() {} + // if paused, debugging functions can be enabled + virtual void OnPause() {} + virtual void OnContinue() {} + void DumpPixelShader(const std::string& path); + void DumpVertexShader(const std::string& path); + void DumpPixelShaderConstants(const std::string& path); + void DumpVertexShaderConstants(const std::string& path); + void DumpTextures(const std::string& path); + void DumpFrameBuffer(const std::string& path); + void DumpGeometry(const std::string& path); + void DumpVertexDecl(const std::string& path); + void DumpMatrices(const std::string& path); + void DumpStats(const std::string& path); }; enum PauseEvent { - NOT_PAUSE = 0, - NEXT_FRAME = 1<<0, - NEXT_FLUSH = 1<<1, + NOT_PAUSE = 0, + NEXT_FRAME = 1 << 0, + NEXT_FLUSH = 1 << 1, - NEXT_PIXEL_SHADER_CHANGE = 1<<2, - NEXT_VERTEX_SHADER_CHANGE = 1<<3, - NEXT_TEXTURE_CHANGE = 1<<4, - NEXT_NEW_TEXTURE = 1<<5, + NEXT_PIXEL_SHADER_CHANGE = 1 << 2, + NEXT_VERTEX_SHADER_CHANGE = 1 << 3, + NEXT_TEXTURE_CHANGE = 1 << 4, + NEXT_NEW_TEXTURE = 1 << 5, - NEXT_XFB_CMD = 1<<6, // TODO - NEXT_EFB_CMD = 1<<7, // TODO + NEXT_XFB_CMD = 1 << 6, // TODO + NEXT_EFB_CMD = 1 << 7, // TODO - NEXT_MATRIX_CMD = 1<<8, // TODO - NEXT_VERTEX_CMD = 1<<9, // TODO - NEXT_TEXTURE_CMD = 1<<10, // TODO - NEXT_LIGHT_CMD = 1<<11, // TODO - NEXT_FOG_CMD = 1<<12, // TODO + NEXT_MATRIX_CMD = 1 << 8, // TODO + NEXT_VERTEX_CMD = 1 << 9, // TODO + NEXT_TEXTURE_CMD = 1 << 10, // TODO + NEXT_LIGHT_CMD = 1 << 11, // TODO + NEXT_FOG_CMD = 1 << 12, // TODO - NEXT_SET_TLUT = 1<<13, // TODO + NEXT_SET_TLUT = 1 << 13, // TODO - NEXT_ERROR = 1<<14, // TODO + NEXT_ERROR = 1 << 14, // TODO }; -extern GFXDebuggerBase *g_pdebugger; +extern GFXDebuggerBase* g_pdebugger; extern volatile bool GFXDebuggerPauseFlag; extern volatile PauseEvent GFXDebuggerToPauseAtNext; extern volatile int GFXDebuggerEventToPauseCount; @@ -61,6 +59,25 @@ void GFXDebuggerCheckAndPause(bool update); void GFXDebuggerToPause(bool update); void GFXDebuggerUpdateScreen(); -#define GFX_DEBUGGER_PAUSE_AT(event,update) {if (((GFXDebuggerToPauseAtNext & event) && --GFXDebuggerEventToPauseCount<=0) || GFXDebuggerPauseFlag) GFXDebuggerToPause(update);} -#define GFX_DEBUGGER_PAUSE_LOG_AT(event,update,dumpfunc) {if (((GFXDebuggerToPauseAtNext & event) && --GFXDebuggerEventToPauseCount<=0) || GFXDebuggerPauseFlag) {{dumpfunc};GFXDebuggerToPause(update);}} -#define GFX_DEBUGGER_LOG_AT(event,dumpfunc) {if (( GFXDebuggerToPauseAtNext & event ) ) {{dumpfunc};}} +#define GFX_DEBUGGER_PAUSE_AT(event, update) \ + { \ + if (((GFXDebuggerToPauseAtNext & event) && --GFXDebuggerEventToPauseCount <= 0) || \ + GFXDebuggerPauseFlag) \ + GFXDebuggerToPause(update); \ + } +#define GFX_DEBUGGER_PAUSE_LOG_AT(event, update, dumpfunc) \ + { \ + if (((GFXDebuggerToPauseAtNext & event) && --GFXDebuggerEventToPauseCount <= 0) || \ + GFXDebuggerPauseFlag) \ + { \ + {dumpfunc}; \ + GFXDebuggerToPause(update); \ + } \ + } +#define GFX_DEBUGGER_LOG_AT(event, dumpfunc) \ + { \ + if ((GFXDebuggerToPauseAtNext & event)) \ + { \ + {dumpfunc}; \ + } \ + } diff --git a/Source/Core/VideoCommon/DriverDetails.cpp b/Source/Core/VideoCommon/DriverDetails.cpp index 9e147aec6b..46e264353f 100644 --- a/Source/Core/VideoCommon/DriverDetails.cpp +++ b/Source/Core/VideoCommon/DriverDetails.cpp @@ -9,110 +9,119 @@ namespace DriverDetails { - struct BugInfo - { - u32 m_os; // Which OS has the issue - Vendor m_vendor; // Which vendor has the error - Driver m_driver; // Which driver has the error - Family m_family; // Which family of hardware has the issue - Bug m_bug; // Which bug it is - double m_versionstart; // When it started - double m_versionend; // When it ended - bool m_hasbug; // Does it have it? - }; +struct BugInfo +{ + u32 m_os; // Which OS has the issue + Vendor m_vendor; // Which vendor has the error + Driver m_driver; // Which driver has the error + Family m_family; // Which family of hardware has the issue + Bug m_bug; // Which bug it is + double m_versionstart; // When it started + double m_versionend; // When it ended + bool m_hasbug; // Does it have it? +}; - // Local members +// Local members #ifdef _WIN32 - const u32 m_os = OS_ALL | OS_WINDOWS; +const u32 m_os = OS_ALL | OS_WINDOWS; #elif ANDROID - const u32 m_os = OS_ALL | OS_ANDROID; +const u32 m_os = OS_ALL | OS_ANDROID; #elif __APPLE__ - const u32 m_os = OS_ALL | OS_OSX; +const u32 m_os = OS_ALL | OS_OSX; #elif __linux__ - const u32 m_os = OS_ALL | OS_LINUX; +const u32 m_os = OS_ALL | OS_LINUX; #elif __FreeBSD__ - const u32 m_os = OS_ALL | OS_FREEBSD; +const u32 m_os = OS_ALL | OS_FREEBSD; #endif - static Vendor m_vendor = VENDOR_UNKNOWN; - static Driver m_driver = DRIVER_UNKNOWN; - static Family m_family = Family::UNKNOWN; - static double m_version = 0.0; +static Vendor m_vendor = VENDOR_UNKNOWN; +static Driver m_driver = DRIVER_UNKNOWN; +static Family m_family = Family::UNKNOWN; +static double m_version = 0.0; - // This is a list of all known bugs for each vendor - // We use this to check if the device and driver has a issue - static BugInfo m_known_bugs[] = { - {OS_ALL, VENDOR_QUALCOMM, DRIVER_QUALCOMM, Family::UNKNOWN, BUG_BROKENBUFFERSTREAM, -1.0, -1.0, true}, - {OS_ALL, VENDOR_QUALCOMM, DRIVER_QUALCOMM, Family::UNKNOWN, BUG_BROKENNEGATEDBOOLEAN,-1.0, -1.0, true}, - {OS_ALL, VENDOR_QUALCOMM, DRIVER_QUALCOMM, Family::UNKNOWN, BUG_BROKENEXPLICITFLUSH, -1.0, -1.0, true}, - {OS_ALL, VENDOR_ARM, DRIVER_ARM, Family::UNKNOWN, BUG_BROKENBUFFERSTREAM, -1.0, -1.0, true}, - {OS_ALL, VENDOR_ARM, DRIVER_ARM, Family::UNKNOWN, BUG_BROKENVSYNC, -1.0, -1.0, true}, - {OS_ALL, VENDOR_IMGTEC, DRIVER_IMGTEC, Family::UNKNOWN, BUG_BROKENBUFFERSTREAM, -1.0, -1.0, true}, - {OS_ALL, VENDOR_MESA, DRIVER_NOUVEAU, Family::UNKNOWN, BUG_BROKENUBO, 900, 916, true}, - {OS_ALL, VENDOR_MESA, DRIVER_R600, Family::UNKNOWN, BUG_BROKENUBO, 900, 913, true}, - {OS_ALL, VENDOR_MESA, DRIVER_R600, Family::UNKNOWN, BUG_BROKENGEOMETRYSHADERS, -1.0, 1112.0, true}, - {OS_ALL, VENDOR_MESA, DRIVER_I965, Family::INTEL_SANDY, BUG_BROKENGEOMETRYSHADERS, -1.0, 1120.0, true}, - {OS_ALL, VENDOR_MESA, DRIVER_I965, Family::UNKNOWN, BUG_BROKENUBO, 900, 920, true}, - {OS_ALL, VENDOR_MESA, DRIVER_ALL, Family::UNKNOWN, BUG_BROKENCOPYIMAGE, -1.0, 1064.0, true}, - {OS_LINUX, VENDOR_ATI, DRIVER_ATI, Family::UNKNOWN, BUG_BROKENPINNEDMEMORY, -1.0, -1.0, true}, - {OS_LINUX, VENDOR_NVIDIA, DRIVER_NVIDIA, Family::UNKNOWN, BUG_BROKENBUFFERSTORAGE, -1.0, 33138.0, true}, - {OS_OSX, VENDOR_INTEL, DRIVER_INTEL, Family::INTEL_SANDY, BUG_PRIMITIVERESTART, -1.0, -1.0, true}, - {OS_WINDOWS,VENDOR_NVIDIA, DRIVER_NVIDIA, Family::UNKNOWN, BUG_BROKENUNSYNCMAPPING, -1.0, -1.0, true}, - {OS_LINUX, VENDOR_NVIDIA, DRIVER_NVIDIA, Family::UNKNOWN, BUG_BROKENUNSYNCMAPPING, -1.0, -1.0, true}, - {OS_WINDOWS,VENDOR_INTEL, DRIVER_INTEL, Family::UNKNOWN, BUG_INTELBROKENBUFFERSTORAGE, 101810.3907, 101810.3960, true}, - {OS_ALL, VENDOR_ATI, DRIVER_ATI, Family::UNKNOWN, BUG_SLOWGETBUFFERSUBDATA, -1.0, -1.0, true}, - }; +// This is a list of all known bugs for each vendor +// We use this to check if the device and driver has a issue +static BugInfo m_known_bugs[] = { + {OS_ALL, VENDOR_QUALCOMM, DRIVER_QUALCOMM, Family::UNKNOWN, BUG_BROKENBUFFERSTREAM, -1.0, -1.0, + true}, + {OS_ALL, VENDOR_QUALCOMM, DRIVER_QUALCOMM, Family::UNKNOWN, BUG_BROKENNEGATEDBOOLEAN, -1.0, + -1.0, true}, + {OS_ALL, VENDOR_QUALCOMM, DRIVER_QUALCOMM, Family::UNKNOWN, BUG_BROKENEXPLICITFLUSH, -1.0, -1.0, + true}, + {OS_ALL, VENDOR_ARM, DRIVER_ARM, Family::UNKNOWN, BUG_BROKENBUFFERSTREAM, -1.0, -1.0, true}, + {OS_ALL, VENDOR_ARM, DRIVER_ARM, Family::UNKNOWN, BUG_BROKENVSYNC, -1.0, -1.0, true}, + {OS_ALL, VENDOR_IMGTEC, DRIVER_IMGTEC, Family::UNKNOWN, BUG_BROKENBUFFERSTREAM, -1.0, -1.0, + true}, + {OS_ALL, VENDOR_MESA, DRIVER_NOUVEAU, Family::UNKNOWN, BUG_BROKENUBO, 900, 916, true}, + {OS_ALL, VENDOR_MESA, DRIVER_R600, Family::UNKNOWN, BUG_BROKENUBO, 900, 913, true}, + {OS_ALL, VENDOR_MESA, DRIVER_R600, Family::UNKNOWN, BUG_BROKENGEOMETRYSHADERS, -1.0, 1112.0, + true}, + {OS_ALL, VENDOR_MESA, DRIVER_I965, Family::INTEL_SANDY, BUG_BROKENGEOMETRYSHADERS, -1.0, 1120.0, + true}, + {OS_ALL, VENDOR_MESA, DRIVER_I965, Family::UNKNOWN, BUG_BROKENUBO, 900, 920, true}, + {OS_ALL, VENDOR_MESA, DRIVER_ALL, Family::UNKNOWN, BUG_BROKENCOPYIMAGE, -1.0, 1064.0, true}, + {OS_LINUX, VENDOR_ATI, DRIVER_ATI, Family::UNKNOWN, BUG_BROKENPINNEDMEMORY, -1.0, -1.0, true}, + {OS_LINUX, VENDOR_NVIDIA, DRIVER_NVIDIA, Family::UNKNOWN, BUG_BROKENBUFFERSTORAGE, -1.0, + 33138.0, true}, + {OS_OSX, VENDOR_INTEL, DRIVER_INTEL, Family::INTEL_SANDY, BUG_PRIMITIVERESTART, -1.0, -1.0, + true}, + {OS_WINDOWS, VENDOR_NVIDIA, DRIVER_NVIDIA, Family::UNKNOWN, BUG_BROKENUNSYNCMAPPING, -1.0, -1.0, + true}, + {OS_LINUX, VENDOR_NVIDIA, DRIVER_NVIDIA, Family::UNKNOWN, BUG_BROKENUNSYNCMAPPING, -1.0, -1.0, + true}, + {OS_WINDOWS, VENDOR_INTEL, DRIVER_INTEL, Family::UNKNOWN, BUG_INTELBROKENBUFFERSTORAGE, + 101810.3907, 101810.3960, true}, + {OS_ALL, VENDOR_ATI, DRIVER_ATI, Family::UNKNOWN, BUG_SLOWGETBUFFERSUBDATA, -1.0, -1.0, true}, +}; - static std::map m_bugs; +static std::map m_bugs; - void Init(Vendor vendor, Driver driver, const double version, const Family family) - { - m_vendor = vendor; - m_driver = driver; - m_version = version; - m_family = family; +void Init(Vendor vendor, Driver driver, const double version, const Family family) +{ + m_vendor = vendor; + m_driver = driver; + m_version = version; + m_family = family; - if (driver == DRIVER_UNKNOWN) - switch (vendor) - { - case VENDOR_NVIDIA: - case VENDOR_TEGRA: - m_driver = DRIVER_NVIDIA; - break; - case VENDOR_ATI: - m_driver = DRIVER_ATI; - break; - case VENDOR_INTEL: - m_driver = DRIVER_INTEL; - break; - case VENDOR_IMGTEC: - m_driver = DRIVER_IMGTEC; - break; - case VENDOR_VIVANTE: - m_driver = DRIVER_VIVANTE; - break; - default: - break; - } + if (driver == DRIVER_UNKNOWN) + switch (vendor) + { + case VENDOR_NVIDIA: + case VENDOR_TEGRA: + m_driver = DRIVER_NVIDIA; + break; + case VENDOR_ATI: + m_driver = DRIVER_ATI; + break; + case VENDOR_INTEL: + m_driver = DRIVER_INTEL; + break; + case VENDOR_IMGTEC: + m_driver = DRIVER_IMGTEC; + break; + case VENDOR_VIVANTE: + m_driver = DRIVER_VIVANTE; + break; + default: + break; + } - for (auto& bug : m_known_bugs) - { - if (( bug.m_os & m_os ) && - ( bug.m_vendor == m_vendor || bug.m_vendor == VENDOR_ALL ) && - ( bug.m_driver == m_driver || bug.m_driver == DRIVER_ALL ) && - ( bug.m_family == m_family || bug.m_family == Family::UNKNOWN) && - ( bug.m_versionstart <= m_version || bug.m_versionstart == -1 ) && - ( bug.m_versionend > m_version || bug.m_versionend == -1 ) - ) - m_bugs.emplace(bug.m_bug, bug); - } - } - - bool HasBug(Bug bug) - { - auto it = m_bugs.find(bug); - if (it == m_bugs.end()) - return false; - return it->second.m_hasbug; - } + for (auto& bug : m_known_bugs) + { + if ((bug.m_os & m_os) && (bug.m_vendor == m_vendor || bug.m_vendor == VENDOR_ALL) && + (bug.m_driver == m_driver || bug.m_driver == DRIVER_ALL) && + (bug.m_family == m_family || bug.m_family == Family::UNKNOWN) && + (bug.m_versionstart <= m_version || bug.m_versionstart == -1) && + (bug.m_versionend > m_version || bug.m_versionend == -1)) + m_bugs.emplace(bug.m_bug, bug); + } +} + +bool HasBug(Bug bug) +{ + auto it = m_bugs.find(bug); + if (it == m_bugs.end()) + return false; + return it->second.m_hasbug; +} } diff --git a/Source/Core/VideoCommon/DriverDetails.h b/Source/Core/VideoCommon/DriverDetails.h index 4f791b0816..3868eda77e 100644 --- a/Source/Core/VideoCommon/DriverDetails.h +++ b/Source/Core/VideoCommon/DriverDetails.h @@ -8,197 +8,207 @@ namespace DriverDetails { - // Enum of supported operating systems - enum OS - { - OS_ALL = (1 << 0), - OS_WINDOWS = (1 << 1), - OS_LINUX = (1 << 2), - OS_OSX = (1 << 3), - OS_ANDROID = (1 << 4), - OS_FREEBSD = (1 << 5), - }; - // Enum of known vendors - // Tegra and Nvidia are separated out due to such substantial differences - enum Vendor - { - VENDOR_ALL = 0, - VENDOR_NVIDIA, - VENDOR_ATI, - VENDOR_INTEL, - VENDOR_ARM, - VENDOR_QUALCOMM, - VENDOR_IMGTEC, - VENDOR_TEGRA, - VENDOR_VIVANTE, - VENDOR_MESA, - VENDOR_UNKNOWN - }; +// Enum of supported operating systems +enum OS +{ + OS_ALL = (1 << 0), + OS_WINDOWS = (1 << 1), + OS_LINUX = (1 << 2), + OS_OSX = (1 << 3), + OS_ANDROID = (1 << 4), + OS_FREEBSD = (1 << 5), +}; +// Enum of known vendors +// Tegra and Nvidia are separated out due to such substantial differences +enum Vendor +{ + VENDOR_ALL = 0, + VENDOR_NVIDIA, + VENDOR_ATI, + VENDOR_INTEL, + VENDOR_ARM, + VENDOR_QUALCOMM, + VENDOR_IMGTEC, + VENDOR_TEGRA, + VENDOR_VIVANTE, + VENDOR_MESA, + VENDOR_UNKNOWN +}; - // Enum of known drivers - enum Driver - { - DRIVER_ALL = 0, - DRIVER_NVIDIA, // Official Nvidia, including mobile GPU - DRIVER_NOUVEAU, // OSS nouveau - DRIVER_ATI, // Official ATI - DRIVER_R600, // OSS Radeon - DRIVER_INTEL, // Official Intel - DRIVER_I965, // OSS Intel - DRIVER_ARM, // Official Mali driver - DRIVER_LIMA, // OSS Mali driver - DRIVER_QUALCOMM, // Official Adreno driver - DRIVER_FREEDRENO, // OSS Adreno driver - DRIVER_IMGTEC, // Official PowerVR driver - DRIVER_VIVANTE, // Official Vivante driver - DRIVER_UNKNOWN // Unknown driver, default to official hardware driver - }; +// Enum of known drivers +enum Driver +{ + DRIVER_ALL = 0, + DRIVER_NVIDIA, // Official Nvidia, including mobile GPU + DRIVER_NOUVEAU, // OSS nouveau + DRIVER_ATI, // Official ATI + DRIVER_R600, // OSS Radeon + DRIVER_INTEL, // Official Intel + DRIVER_I965, // OSS Intel + DRIVER_ARM, // Official Mali driver + DRIVER_LIMA, // OSS Mali driver + DRIVER_QUALCOMM, // Official Adreno driver + DRIVER_FREEDRENO, // OSS Adreno driver + DRIVER_IMGTEC, // Official PowerVR driver + DRIVER_VIVANTE, // Official Vivante driver + DRIVER_UNKNOWN // Unknown driver, default to official hardware driver +}; - enum class Family - { - UNKNOWN, - INTEL_SANDY, - INTEL_IVY, - }; +enum class Family +{ + UNKNOWN, + INTEL_SANDY, + INTEL_IVY, +}; - // Enum of known bugs - // These can be vendor specific, but we put them all in here - // For putting a new bug in here, make sure to put a detailed comment above the enum - // This'll ensure we know exactly what the issue is. - enum Bug - { - // Bug: UBO buffer offset broken - // Affected devices: all mesa drivers - // Started Version: 9.0 (mesa doesn't support ubo before) - // Ended Version: up to 9.2 - // The offset of glBindBufferRange was ignored on all Mesa Gallium3D drivers until 9.1.3 - // Nouveau stored the offset as u16 which isn't enough for all cases with range until 9.1.6 - // I965 has broken data fetches from uniform buffers which results in a dithering until 9.2.0 - BUG_BROKENUBO, - // Bug: The pinned memory extension isn't working for index buffers - // Affected devices: AMD as they are the only vendor providing this extension - // Started Version: ? - // Ended Version: 13.9 working for me (neobrain). - // Affected OS: Linux - // Pinned memory is disabled for index buffer as the AMD driver (the only one with pinned memory support) seems - // to be broken. We just get flickering/black rendering when using pinned memory here -- degasus - 2013/08/20 - // This bug only happens when paired with base_vertex. - // Please see issue #6105. Let's hope buffer storage solves this issue. - // TODO: Detect broken drivers. - BUG_BROKENPINNEDMEMORY, - // Bug: glBufferSubData/glMapBufferRange stalls + OOM - // Affected devices: Adreno a3xx/Mali-t6xx - // Started Version: -1 - // Ended Version: -1 - // Both Adreno and Mali have issues when you call glBufferSubData or glMapBufferRange - // The driver stalls in each instance no matter what you do - // Apparently Mali and Adreno share code in this regard since it was wrote by the same person. - BUG_BROKENBUFFERSTREAM, - // Bug: ARB_buffer_storage doesn't work with ARRAY_BUFFER type streams - // Affected devices: GeForce 4xx+ - // Started Version: -1 - // Ended Version: 332.21 - // The buffer_storage streaming method is required for greater speed gains in our buffer streaming - // It reduces what is needed for streaming to basically a memcpy call - // It seems to work for all buffer types except GL_ARRAY_BUFFER - BUG_BROKENBUFFERSTORAGE, - // Bug: Intel HD 3000 on OS X has broken primitive restart - // Affected devices: Intel HD 3000 - // Affected OS: OS X - // Started Version: -1 - // Ended Version: -1 - // The drivers on OS X has broken primitive restart. - // Intel HD 4000 series isn't affected by the bug - BUG_PRIMITIVERESTART, - // Bug: unsync mapping doesn't work fine - // Affected devices: Nvidia driver - // Started Version: -1 - // Ended Version: -1 - // The Nvidia driver (both Windows + Linux) doesn't like unsync mapping performance wise. - // Because of their threaded behavior, they seem not to handle unsync mapping complete unsync, - // in fact, they serialize the driver which adds a much bigger overhead. - // Workaround: Use BufferSubData - // TODO: some Windows AMD driver/GPU combination seems also affected - // but as they all support pinned memory, it doesn't matter - BUG_BROKENUNSYNCMAPPING, - // Bug: Intel's Window driver broke buffer_storage with GL_ELEMENT_ARRAY_BUFFER - // Affected devices: Intel (Windows) - // Started Version: 15.36.3.64.3907 (10.18.10.3907) - // Ended Version: 15.36.7.64.3960 (10.18.10.3960) - // Intel implemented buffer_storage in their GL 4.3 driver. - // It works for all the buffer types we use except GL_ELEMENT_ARRAY_BUFFER. - // Causes complete blackscreen issues. - BUG_INTELBROKENBUFFERSTORAGE, - // Bug: Qualcomm has broken boolean negation - // Affected devices: Adreno - // Started Version: -1 - // Ended Version: -1 - // Qualcomm has the boolean negation broken in their shader compiler - // Instead of inverting the boolean value it does a binary negation on the full 32bit register - // This causes a compare against zero to fail in their shader since it is no longer a 0 or 1 value - // but 0xFFFFFFFF or 0xFFFFFFFE depending on what the boolean value was before the negation. - // - // This bug has a secondary issue tied to it unlike other bugs. - // The correction of this bug is to check the boolean value against false which results in us - // not doing a negation of the source but instead checking against the boolean value we want. - // The issue with this is that Intel's Window driver is broken when checking if a boolean value is - // equal to true or false, so one has to do a boolean negation of the source - // - // eg. - // Broken on Qualcomm - // Works on Windows Intel - // if (!cond) - // - // Works on Qualcomm - // Broken on Windows Intel - // if (cond == false) - BUG_BROKENNEGATEDBOOLEAN, +// Enum of known bugs +// These can be vendor specific, but we put them all in here +// For putting a new bug in here, make sure to put a detailed comment above the enum +// This'll ensure we know exactly what the issue is. +enum Bug +{ + // Bug: UBO buffer offset broken + // Affected devices: all mesa drivers + // Started Version: 9.0 (mesa doesn't support ubo before) + // Ended Version: up to 9.2 + // The offset of glBindBufferRange was ignored on all Mesa Gallium3D drivers until 9.1.3 + // Nouveau stored the offset as u16 which isn't enough for all cases with range until 9.1.6 + // I965 has broken data fetches from uniform buffers which results in a dithering until 9.2.0 + BUG_BROKENUBO, + // Bug: The pinned memory extension isn't working for index buffers + // Affected devices: AMD as they are the only vendor providing this extension + // Started Version: ? + // Ended Version: 13.9 working for me (neobrain). + // Affected OS: Linux + // Pinned memory is disabled for index buffer as the AMD driver (the only one with pinned memory + // support) seems + // to be broken. We just get flickering/black rendering when using pinned memory here -- degasus - + // 2013/08/20 + // This bug only happens when paired with base_vertex. + // Please see issue #6105. Let's hope buffer storage solves this issue. + // TODO: Detect broken drivers. + BUG_BROKENPINNEDMEMORY, + // Bug: glBufferSubData/glMapBufferRange stalls + OOM + // Affected devices: Adreno a3xx/Mali-t6xx + // Started Version: -1 + // Ended Version: -1 + // Both Adreno and Mali have issues when you call glBufferSubData or glMapBufferRange + // The driver stalls in each instance no matter what you do + // Apparently Mali and Adreno share code in this regard since it was wrote by the same person. + BUG_BROKENBUFFERSTREAM, + // Bug: ARB_buffer_storage doesn't work with ARRAY_BUFFER type streams + // Affected devices: GeForce 4xx+ + // Started Version: -1 + // Ended Version: 332.21 + // The buffer_storage streaming method is required for greater speed gains in our buffer streaming + // It reduces what is needed for streaming to basically a memcpy call + // It seems to work for all buffer types except GL_ARRAY_BUFFER + BUG_BROKENBUFFERSTORAGE, + // Bug: Intel HD 3000 on OS X has broken primitive restart + // Affected devices: Intel HD 3000 + // Affected OS: OS X + // Started Version: -1 + // Ended Version: -1 + // The drivers on OS X has broken primitive restart. + // Intel HD 4000 series isn't affected by the bug + BUG_PRIMITIVERESTART, + // Bug: unsync mapping doesn't work fine + // Affected devices: Nvidia driver + // Started Version: -1 + // Ended Version: -1 + // The Nvidia driver (both Windows + Linux) doesn't like unsync mapping performance wise. + // Because of their threaded behavior, they seem not to handle unsync mapping complete unsync, + // in fact, they serialize the driver which adds a much bigger overhead. + // Workaround: Use BufferSubData + // TODO: some Windows AMD driver/GPU combination seems also affected + // but as they all support pinned memory, it doesn't matter + BUG_BROKENUNSYNCMAPPING, + // Bug: Intel's Window driver broke buffer_storage with GL_ELEMENT_ARRAY_BUFFER + // Affected devices: Intel (Windows) + // Started Version: 15.36.3.64.3907 (10.18.10.3907) + // Ended Version: 15.36.7.64.3960 (10.18.10.3960) + // Intel implemented buffer_storage in their GL 4.3 driver. + // It works for all the buffer types we use except GL_ELEMENT_ARRAY_BUFFER. + // Causes complete blackscreen issues. + BUG_INTELBROKENBUFFERSTORAGE, + // Bug: Qualcomm has broken boolean negation + // Affected devices: Adreno + // Started Version: -1 + // Ended Version: -1 + // Qualcomm has the boolean negation broken in their shader compiler + // Instead of inverting the boolean value it does a binary negation on the full 32bit register + // This causes a compare against zero to fail in their shader since it is no longer a 0 or 1 value + // but 0xFFFFFFFF or 0xFFFFFFFE depending on what the boolean value was before the negation. + // + // This bug has a secondary issue tied to it unlike other bugs. + // The correction of this bug is to check the boolean value against false which results in us + // not doing a negation of the source but instead checking against the boolean value we want. + // The issue with this is that Intel's Window driver is broken when checking if a boolean value is + // equal to true or false, so one has to do a boolean negation of the source + // + // eg. + // Broken on Qualcomm + // Works on Windows Intel + // if (!cond) + // + // Works on Qualcomm + // Broken on Windows Intel + // if (cond == false) + BUG_BROKENNEGATEDBOOLEAN, - // Bug: glCopyImageSubData doesn't work on i965 - // Started Version: -1 - // Ended Version: 10.6.4 - // Mesa meta misses to disable the scissor test. - BUG_BROKENCOPYIMAGE, + // Bug: glCopyImageSubData doesn't work on i965 + // Started Version: -1 + // Ended Version: 10.6.4 + // Mesa meta misses to disable the scissor test. + BUG_BROKENCOPYIMAGE, - // Bug: ARM Mali managed to break disabling vsync - // Affected Devices: Mali - // Started Version: r5p0-rev2 - // Ended Version: -1 - // If we disable vsync with eglSwapInterval(dpy, 0) then the screen will stop showing new updates after a handful of swaps. - // This was noticed on a Samsung Galaxy S6 with its Android 5.1.1 update. - // The default Android 5.0 image didn't encounter this issue. - // We can't actually detect what the driver version is on Android, so until the driver version lands that displays the version in - // the GL_VERSION string, we will have to force vsync to be enabled at all times. - BUG_BROKENVSYNC, + // Bug: ARM Mali managed to break disabling vsync + // Affected Devices: Mali + // Started Version: r5p0-rev2 + // Ended Version: -1 + // If we disable vsync with eglSwapInterval(dpy, 0) then the screen will stop showing new updates + // after a handful of swaps. + // This was noticed on a Samsung Galaxy S6 with its Android 5.1.1 update. + // The default Android 5.0 image didn't encounter this issue. + // We can't actually detect what the driver version is on Android, so until the driver version + // lands that displays the version in + // the GL_VERSION string, we will have to force vsync to be enabled at all times. + BUG_BROKENVSYNC, - // Bug: Broken lines in geometry shaders - // Affected Devices: Mesa r600/radeonsi, Mesa Sandy Bridge - // Started Version: -1 - // Ended Version: 11.1.2 for radeon, -1 for Sandy - // Mesa introduced geometry shader support for radeon and sandy bridge devices and failed to test it with us. - // Causes misrenderings on a large amount of things that draw lines. - BUG_BROKENGEOMETRYSHADERS, + // Bug: Broken lines in geometry shaders + // Affected Devices: Mesa r600/radeonsi, Mesa Sandy Bridge + // Started Version: -1 + // Ended Version: 11.1.2 for radeon, -1 for Sandy + // Mesa introduced geometry shader support for radeon and sandy bridge devices and failed to test + // it with us. + // Causes misrenderings on a large amount of things that draw lines. + BUG_BROKENGEOMETRYSHADERS, - // Bug: Explicit flush is very slow on Qualcomm - // Started Version: -1 - // Ended Version: -1 - // Our ARB_buffer_storage code uses explicit flush to avoid coherent mapping. - // Qualcomm seems to have lots of overhead on exlicit flushing, but the coherent mapping path is fine. - // So let's use coherent mapping there. - BUG_BROKENEXPLICITFLUSH, + // Bug: Explicit flush is very slow on Qualcomm + // Started Version: -1 + // Ended Version: -1 + // Our ARB_buffer_storage code uses explicit flush to avoid coherent mapping. + // Qualcomm seems to have lots of overhead on exlicit flushing, but the coherent mapping path is + // fine. + // So let's use coherent mapping there. + BUG_BROKENEXPLICITFLUSH, - // Bug: glGetBufferSubData for bounding box reads is slow on AMD drivers - // Started Version: -1 - // Ended Version: -1 - // Bounding box reads use glGetBufferSubData to read back the contents of the SSBO, but this is slow on AMD drivers, compared to - // using glMapBufferRange. glMapBufferRange is slower on Nvidia drivers, we suspect due to the first call moving the buffer from - // GPU memory to system memory. Use glMapBufferRange for BBox reads on AMD, and glGetBufferSubData everywhere else. - BUG_SLOWGETBUFFERSUBDATA, - }; + // Bug: glGetBufferSubData for bounding box reads is slow on AMD drivers + // Started Version: -1 + // Ended Version: -1 + // Bounding box reads use glGetBufferSubData to read back the contents of the SSBO, but this is + // slow on AMD drivers, compared to + // using glMapBufferRange. glMapBufferRange is slower on Nvidia drivers, we suspect due to the + // first call moving the buffer from + // GPU memory to system memory. Use glMapBufferRange for BBox reads on AMD, and glGetBufferSubData + // everywhere else. + BUG_SLOWGETBUFFERSUBDATA, +}; - // Initializes our internal vendor, device family, and driver version - void Init(Vendor vendor, Driver driver, const double version, const Family family); +// Initializes our internal vendor, device family, and driver version +void Init(Vendor vendor, Driver driver, const double version, const Family family); - // Once Vendor and driver version is set, this will return if it has the applicable bug passed to it. - bool HasBug(Bug bug); +// Once Vendor and driver version is set, this will return if it has the applicable bug passed to +// it. +bool HasBug(Bug bug); } diff --git a/Source/Core/VideoCommon/FPSCounter.cpp b/Source/Core/VideoCommon/FPSCounter.cpp index 15fb28081c..2d17d00a41 100644 --- a/Source/Core/VideoCommon/FPSCounter.cpp +++ b/Source/Core/VideoCommon/FPSCounter.cpp @@ -14,33 +14,33 @@ static constexpr u64 FPS_REFRESH_INTERVAL = 1000; FPSCounter::FPSCounter() { - m_update_time.Update(); - m_render_time.Update(); + m_update_time.Update(); + m_render_time.Update(); } void FPSCounter::LogRenderTimeToFile(u64 val) { - if (!m_bench_file.is_open()) - m_bench_file.open(File::GetUserPath(D_LOGS_IDX) + "render_time.txt"); + if (!m_bench_file.is_open()) + m_bench_file.open(File::GetUserPath(D_LOGS_IDX) + "render_time.txt"); - m_bench_file << val << std::endl; + m_bench_file << val << std::endl; } void FPSCounter::Update() { - if (m_update_time.GetTimeDifference() >= FPS_REFRESH_INTERVAL) - { - m_update_time.Update(); - m_fps = m_counter - m_fps_last_counter; - m_fps_last_counter = m_counter; - m_bench_file.flush(); - } + if (m_update_time.GetTimeDifference() >= FPS_REFRESH_INTERVAL) + { + m_update_time.Update(); + m_fps = m_counter - m_fps_last_counter; + m_fps_last_counter = m_counter; + m_bench_file.flush(); + } - if (g_ActiveConfig.bLogRenderTimeToFile) - { - LogRenderTimeToFile(m_render_time.GetTimeDifference()); - m_render_time.Update(); - } + if (g_ActiveConfig.bLogRenderTimeToFile) + { + LogRenderTimeToFile(m_render_time.GetTimeDifference()); + m_render_time.Update(); + } - m_counter++; + m_counter++; } diff --git a/Source/Core/VideoCommon/FPSCounter.h b/Source/Core/VideoCommon/FPSCounter.h index a2ae49567b..860734d25b 100644 --- a/Source/Core/VideoCommon/FPSCounter.h +++ b/Source/Core/VideoCommon/FPSCounter.h @@ -11,22 +11,21 @@ class FPSCounter { public: - // Initializes the FPS counter. - FPSCounter(); + // Initializes the FPS counter. + FPSCounter(); - // Called when a frame is rendered (updated every second). - void Update(); - - unsigned int GetFPS() const { return m_fps; } + // Called when a frame is rendered (updated every second). + void Update(); + unsigned int GetFPS() const { return m_fps; } private: - unsigned int m_fps = 0; - unsigned int m_counter = 0; - unsigned int m_fps_last_counter = 0; - Common::Timer m_update_time; + unsigned int m_fps = 0; + unsigned int m_counter = 0; + unsigned int m_fps_last_counter = 0; + Common::Timer m_update_time; - Common::Timer m_render_time; - std::ofstream m_bench_file; + Common::Timer m_render_time; + std::ofstream m_bench_file; - void LogRenderTimeToFile(u64 val); + void LogRenderTimeToFile(u64 val); }; diff --git a/Source/Core/VideoCommon/Fifo.cpp b/Source/Core/VideoCommon/Fifo.cpp index 662e0cdd7b..8e14e58b35 100644 --- a/Source/Core/VideoCommon/Fifo.cpp +++ b/Source/Core/VideoCommon/Fifo.cpp @@ -16,12 +16,12 @@ #include "Core/ConfigManager.h" #include "Core/CoreTiming.h" -#include "Core/NetPlayProto.h" #include "Core/HW/Memmap.h" +#include "Core/NetPlayProto.h" #include "VideoCommon/AsyncRequests.h" -#include "VideoCommon/CommandProcessor.h" #include "VideoCommon/CPMemory.h" +#include "VideoCommon/CommandProcessor.h" #include "VideoCommon/DataReader.h" #include "VideoCommon/Fifo.h" #include "VideoCommon/OpcodeDecoding.h" @@ -30,7 +30,6 @@ namespace Fifo { - static constexpr u32 FIFO_SIZE = 2 * 1024 * 1024; static bool s_skip_current_frame = false; @@ -72,442 +71,450 @@ static u8* s_video_buffer_pp_read_ptr; static std::atomic s_sync_ticks; static Common::Event s_sync_wakeup_event; -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - p.DoArray(s_video_buffer, FIFO_SIZE); - u8* write_ptr = s_video_buffer_write_ptr; - p.DoPointer(write_ptr, s_video_buffer); - s_video_buffer_write_ptr = write_ptr; - p.DoPointer(s_video_buffer_read_ptr, s_video_buffer); - if (p.mode == PointerWrap::MODE_READ && s_use_deterministic_gpu_thread) - { - // We're good and paused, right? - s_video_buffer_seen_ptr = s_video_buffer_pp_read_ptr = s_video_buffer_read_ptr; - } + p.DoArray(s_video_buffer, FIFO_SIZE); + u8* write_ptr = s_video_buffer_write_ptr; + p.DoPointer(write_ptr, s_video_buffer); + s_video_buffer_write_ptr = write_ptr; + p.DoPointer(s_video_buffer_read_ptr, s_video_buffer); + if (p.mode == PointerWrap::MODE_READ && s_use_deterministic_gpu_thread) + { + // We're good and paused, right? + s_video_buffer_seen_ptr = s_video_buffer_pp_read_ptr = s_video_buffer_read_ptr; + } - p.Do(s_skip_current_frame); - p.Do(s_last_sync_gpu_tick); + p.Do(s_skip_current_frame); + p.Do(s_last_sync_gpu_tick); } void PauseAndLock(bool doLock, bool unpauseOnUnlock) { - if (doLock) - { - SyncGPU(SYNC_GPU_OTHER); - EmulatorState(false); - FlushGpu(); - } - else - { - if (unpauseOnUnlock) - EmulatorState(true); - } + if (doLock) + { + SyncGPU(SYNC_GPU_OTHER); + EmulatorState(false); + FlushGpu(); + } + else + { + if (unpauseOnUnlock) + EmulatorState(true); + } } - void Init() { - // Padded so that SIMD overreads in the vertex loader are safe - s_video_buffer = (u8*)AllocateMemoryPages(FIFO_SIZE + 4); - ResetVideoBuffer(); - if (SConfig::GetInstance().bCPUThread) - s_gpu_mainloop.Prepare(); - s_sync_ticks.store(0); + // Padded so that SIMD overreads in the vertex loader are safe + s_video_buffer = (u8*)AllocateMemoryPages(FIFO_SIZE + 4); + ResetVideoBuffer(); + if (SConfig::GetInstance().bCPUThread) + s_gpu_mainloop.Prepare(); + s_sync_ticks.store(0); } void Shutdown() { - if (s_gpu_mainloop.IsRunning()) - PanicAlert("Fifo shutting down while active"); + if (s_gpu_mainloop.IsRunning()) + PanicAlert("Fifo shutting down while active"); - FreeMemoryPages(s_video_buffer, FIFO_SIZE + 4); - s_video_buffer = nullptr; - s_video_buffer_write_ptr = nullptr; - s_video_buffer_pp_read_ptr = nullptr; - s_video_buffer_read_ptr = nullptr; - s_video_buffer_seen_ptr = nullptr; - s_fifo_aux_write_ptr = nullptr; - s_fifo_aux_read_ptr = nullptr; + FreeMemoryPages(s_video_buffer, FIFO_SIZE + 4); + s_video_buffer = nullptr; + s_video_buffer_write_ptr = nullptr; + s_video_buffer_pp_read_ptr = nullptr; + s_video_buffer_read_ptr = nullptr; + s_video_buffer_seen_ptr = nullptr; + s_fifo_aux_write_ptr = nullptr; + s_fifo_aux_read_ptr = nullptr; } void SetRendering(bool enabled) { - s_skip_current_frame = !enabled; + s_skip_current_frame = !enabled; } bool WillSkipCurrentFrame() { - return s_skip_current_frame; + return s_skip_current_frame; } // May be executed from any thread, even the graphics thread. // Created to allow for self shutdown. void ExitGpuLoop() { - // This should break the wait loop in CPU thread - CommandProcessor::fifo.bFF_GPReadEnable = false; - FlushGpu(); + // This should break the wait loop in CPU thread + CommandProcessor::fifo.bFF_GPReadEnable = false; + FlushGpu(); - // Terminate GPU thread loop - s_emu_running_state.store(true); - s_gpu_mainloop.Stop(false); + // Terminate GPU thread loop + s_emu_running_state.store(true); + s_gpu_mainloop.Stop(false); } void EmulatorState(bool running) { - s_emu_running_state.store(running); - s_gpu_mainloop.Wakeup(); + s_emu_running_state.store(running); + s_gpu_mainloop.Wakeup(); } void SyncGPU(SyncGPUReason reason, bool may_move_read_ptr) { - if (s_use_deterministic_gpu_thread) - { - s_gpu_mainloop.Wait(); - if (!s_gpu_mainloop.IsRunning()) - return; + if (s_use_deterministic_gpu_thread) + { + s_gpu_mainloop.Wait(); + if (!s_gpu_mainloop.IsRunning()) + return; - // Opportunistically reset FIFOs so we don't wrap around. - if (may_move_read_ptr && s_fifo_aux_write_ptr != s_fifo_aux_read_ptr) - PanicAlert("aux fifo not synced (%p, %p)", s_fifo_aux_write_ptr, s_fifo_aux_read_ptr); + // Opportunistically reset FIFOs so we don't wrap around. + if (may_move_read_ptr && s_fifo_aux_write_ptr != s_fifo_aux_read_ptr) + PanicAlert("aux fifo not synced (%p, %p)", s_fifo_aux_write_ptr, s_fifo_aux_read_ptr); - memmove(s_fifo_aux_data, s_fifo_aux_read_ptr, s_fifo_aux_write_ptr - s_fifo_aux_read_ptr); - s_fifo_aux_write_ptr -= (s_fifo_aux_read_ptr - s_fifo_aux_data); - s_fifo_aux_read_ptr = s_fifo_aux_data; + memmove(s_fifo_aux_data, s_fifo_aux_read_ptr, s_fifo_aux_write_ptr - s_fifo_aux_read_ptr); + s_fifo_aux_write_ptr -= (s_fifo_aux_read_ptr - s_fifo_aux_data); + s_fifo_aux_read_ptr = s_fifo_aux_data; - if (may_move_read_ptr) - { - u8* write_ptr = s_video_buffer_write_ptr; + if (may_move_read_ptr) + { + u8* write_ptr = s_video_buffer_write_ptr; - // what's left over in the buffer - size_t size = write_ptr - s_video_buffer_pp_read_ptr; + // what's left over in the buffer + size_t size = write_ptr - s_video_buffer_pp_read_ptr; - memmove(s_video_buffer, s_video_buffer_pp_read_ptr, size); - // This change always decreases the pointers. We write seen_ptr - // after write_ptr here, and read it before in RunGpuLoop, so - // 'write_ptr > seen_ptr' there cannot become spuriously true. - s_video_buffer_write_ptr = write_ptr = s_video_buffer + size; - s_video_buffer_pp_read_ptr = s_video_buffer; - s_video_buffer_read_ptr = s_video_buffer; - s_video_buffer_seen_ptr = write_ptr; - } - } + memmove(s_video_buffer, s_video_buffer_pp_read_ptr, size); + // This change always decreases the pointers. We write seen_ptr + // after write_ptr here, and read it before in RunGpuLoop, so + // 'write_ptr > seen_ptr' there cannot become spuriously true. + s_video_buffer_write_ptr = write_ptr = s_video_buffer + size; + s_video_buffer_pp_read_ptr = s_video_buffer; + s_video_buffer_read_ptr = s_video_buffer; + s_video_buffer_seen_ptr = write_ptr; + } + } } void PushFifoAuxBuffer(void* ptr, size_t size) { - if (size > (size_t) (s_fifo_aux_data + FIFO_SIZE - s_fifo_aux_write_ptr)) - { - SyncGPU(SYNC_GPU_AUX_SPACE, /* may_move_read_ptr */ false); - if (!s_gpu_mainloop.IsRunning()) - { - // GPU is shutting down - return; - } - if (size > (size_t) (s_fifo_aux_data + FIFO_SIZE - s_fifo_aux_write_ptr)) - { - // That will sync us up to the last 32 bytes, so this short region - // of FIFO would have to point to a 2MB display list or something. - PanicAlert("absurdly large aux buffer"); - return; - } - } - memcpy(s_fifo_aux_write_ptr, ptr, size); - s_fifo_aux_write_ptr += size; + if (size > (size_t)(s_fifo_aux_data + FIFO_SIZE - s_fifo_aux_write_ptr)) + { + SyncGPU(SYNC_GPU_AUX_SPACE, /* may_move_read_ptr */ false); + if (!s_gpu_mainloop.IsRunning()) + { + // GPU is shutting down + return; + } + if (size > (size_t)(s_fifo_aux_data + FIFO_SIZE - s_fifo_aux_write_ptr)) + { + // That will sync us up to the last 32 bytes, so this short region + // of FIFO would have to point to a 2MB display list or something. + PanicAlert("absurdly large aux buffer"); + return; + } + } + memcpy(s_fifo_aux_write_ptr, ptr, size); + s_fifo_aux_write_ptr += size; } void* PopFifoAuxBuffer(size_t size) { - void* ret = s_fifo_aux_read_ptr; - s_fifo_aux_read_ptr += size; - return ret; + void* ret = s_fifo_aux_read_ptr; + s_fifo_aux_read_ptr += size; + return ret; } // Description: RunGpuLoop() sends data through this function. static void ReadDataFromFifo(u32 readPtr) { - size_t len = 32; - if (len > (size_t)(s_video_buffer + FIFO_SIZE - s_video_buffer_write_ptr)) - { - size_t existing_len = s_video_buffer_write_ptr - s_video_buffer_read_ptr; - if (len > (size_t)(FIFO_SIZE - existing_len)) - { - PanicAlert("FIFO out of bounds (existing %zu + new %zu > %lu)", existing_len, len, (unsigned long) FIFO_SIZE); - return; - } - memmove(s_video_buffer, s_video_buffer_read_ptr, existing_len); - s_video_buffer_write_ptr = s_video_buffer + existing_len; - s_video_buffer_read_ptr = s_video_buffer; - } - // Copy new video instructions to s_video_buffer for future use in rendering the new picture - Memory::CopyFromEmu(s_video_buffer_write_ptr, readPtr, len); - s_video_buffer_write_ptr += len; + size_t len = 32; + if (len > (size_t)(s_video_buffer + FIFO_SIZE - s_video_buffer_write_ptr)) + { + size_t existing_len = s_video_buffer_write_ptr - s_video_buffer_read_ptr; + if (len > (size_t)(FIFO_SIZE - existing_len)) + { + PanicAlert("FIFO out of bounds (existing %zu + new %zu > %lu)", existing_len, len, + (unsigned long)FIFO_SIZE); + return; + } + memmove(s_video_buffer, s_video_buffer_read_ptr, existing_len); + s_video_buffer_write_ptr = s_video_buffer + existing_len; + s_video_buffer_read_ptr = s_video_buffer; + } + // Copy new video instructions to s_video_buffer for future use in rendering the new picture + Memory::CopyFromEmu(s_video_buffer_write_ptr, readPtr, len); + s_video_buffer_write_ptr += len; } // The deterministic_gpu_thread version. static void ReadDataFromFifoOnCPU(u32 readPtr) { - size_t len = 32; - u8 *write_ptr = s_video_buffer_write_ptr; - if (len > (size_t)(s_video_buffer + FIFO_SIZE - write_ptr)) - { - // We can't wrap around while the GPU is working on the data. - // This should be very rare due to the reset in SyncGPU. - SyncGPU(SYNC_GPU_WRAPAROUND); - if (!s_gpu_mainloop.IsRunning()) - { - // GPU is shutting down, so the next asserts may fail - return; - } + size_t len = 32; + u8* write_ptr = s_video_buffer_write_ptr; + if (len > (size_t)(s_video_buffer + FIFO_SIZE - write_ptr)) + { + // We can't wrap around while the GPU is working on the data. + // This should be very rare due to the reset in SyncGPU. + SyncGPU(SYNC_GPU_WRAPAROUND); + if (!s_gpu_mainloop.IsRunning()) + { + // GPU is shutting down, so the next asserts may fail + return; + } - if (s_video_buffer_pp_read_ptr != s_video_buffer_read_ptr) - { - PanicAlert("desynced read pointers"); - return; - } - write_ptr = s_video_buffer_write_ptr; - size_t existing_len = write_ptr - s_video_buffer_pp_read_ptr; - if (len > (size_t)(FIFO_SIZE - existing_len)) - { - PanicAlert("FIFO out of bounds (existing %zu + new %zu > %lu)", existing_len, len, (unsigned long) FIFO_SIZE); - return; - } - } - Memory::CopyFromEmu(s_video_buffer_write_ptr, readPtr, len); - s_video_buffer_pp_read_ptr = OpcodeDecoder::Run(DataReader(s_video_buffer_pp_read_ptr, write_ptr + len), nullptr, false); - // This would have to be locked if the GPU thread didn't spin. - s_video_buffer_write_ptr = write_ptr + len; + if (s_video_buffer_pp_read_ptr != s_video_buffer_read_ptr) + { + PanicAlert("desynced read pointers"); + return; + } + write_ptr = s_video_buffer_write_ptr; + size_t existing_len = write_ptr - s_video_buffer_pp_read_ptr; + if (len > (size_t)(FIFO_SIZE - existing_len)) + { + PanicAlert("FIFO out of bounds (existing %zu + new %zu > %lu)", existing_len, len, + (unsigned long)FIFO_SIZE); + return; + } + } + Memory::CopyFromEmu(s_video_buffer_write_ptr, readPtr, len); + s_video_buffer_pp_read_ptr = OpcodeDecoder::Run( + DataReader(s_video_buffer_pp_read_ptr, write_ptr + len), nullptr, false); + // This would have to be locked if the GPU thread didn't spin. + s_video_buffer_write_ptr = write_ptr + len; } void ResetVideoBuffer() { - s_video_buffer_read_ptr = s_video_buffer; - s_video_buffer_write_ptr = s_video_buffer; - s_video_buffer_seen_ptr = s_video_buffer; - s_video_buffer_pp_read_ptr = s_video_buffer; - s_fifo_aux_write_ptr = s_fifo_aux_data; - s_fifo_aux_read_ptr = s_fifo_aux_data; + s_video_buffer_read_ptr = s_video_buffer; + s_video_buffer_write_ptr = s_video_buffer; + s_video_buffer_seen_ptr = s_video_buffer; + s_video_buffer_pp_read_ptr = s_video_buffer; + s_fifo_aux_write_ptr = s_fifo_aux_data; + s_fifo_aux_read_ptr = s_fifo_aux_data; } - // Description: Main FIFO update loop // Purpose: Keep the Core HW updated about the CPU-GPU distance void RunGpuLoop() { + AsyncRequests::GetInstance()->SetEnable(true); + AsyncRequests::GetInstance()->SetPassthrough(false); - AsyncRequests::GetInstance()->SetEnable(true); - AsyncRequests::GetInstance()->SetPassthrough(false); + s_gpu_mainloop.Run( + [] { + const SConfig& param = SConfig::GetInstance(); - s_gpu_mainloop.Run( - [] { - const SConfig& param = SConfig::GetInstance(); + g_video_backend->PeekMessages(); - g_video_backend->PeekMessages(); + // Do nothing while paused + if (!s_emu_running_state.load()) + return; - // Do nothing while paused - if (!s_emu_running_state.load()) - return; + if (s_use_deterministic_gpu_thread) + { + AsyncRequests::GetInstance()->PullEvents(); - if (s_use_deterministic_gpu_thread) - { - AsyncRequests::GetInstance()->PullEvents(); + // All the fifo/CP stuff is on the CPU. We just need to run the opcode decoder. + u8* seen_ptr = s_video_buffer_seen_ptr; + u8* write_ptr = s_video_buffer_write_ptr; + // See comment in SyncGPU + if (write_ptr > seen_ptr) + { + s_video_buffer_read_ptr = + OpcodeDecoder::Run(DataReader(s_video_buffer_read_ptr, write_ptr), nullptr, false); + s_video_buffer_seen_ptr = write_ptr; + } + } + else + { + SCPFifoStruct& fifo = CommandProcessor::fifo; - // All the fifo/CP stuff is on the CPU. We just need to run the opcode decoder. - u8* seen_ptr = s_video_buffer_seen_ptr; - u8* write_ptr = s_video_buffer_write_ptr; - // See comment in SyncGPU - if (write_ptr > seen_ptr) - { - s_video_buffer_read_ptr = OpcodeDecoder::Run(DataReader(s_video_buffer_read_ptr, write_ptr), nullptr, false); - s_video_buffer_seen_ptr = write_ptr; - } - } - else - { - SCPFifoStruct &fifo = CommandProcessor::fifo; + AsyncRequests::GetInstance()->PullEvents(); - AsyncRequests::GetInstance()->PullEvents(); + CommandProcessor::SetCPStatusFromGPU(); - CommandProcessor::SetCPStatusFromGPU(); + // check if we are able to run this buffer + while (!CommandProcessor::IsInterruptWaiting() && fifo.bFF_GPReadEnable && + fifo.CPReadWriteDistance && !AtBreakpoint()) + { + if (param.bSyncGPU && s_sync_ticks.load() < param.iSyncGpuMinDistance) + break; - // check if we are able to run this buffer - while (!CommandProcessor::IsInterruptWaiting() && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint()) - { - if (param.bSyncGPU && s_sync_ticks.load() < param.iSyncGpuMinDistance) - break; + u32 cyclesExecuted = 0; + u32 readPtr = fifo.CPReadPointer; + ReadDataFromFifo(readPtr); - u32 cyclesExecuted = 0; - u32 readPtr = fifo.CPReadPointer; - ReadDataFromFifo(readPtr); + if (readPtr == fifo.CPEnd) + readPtr = fifo.CPBase; + else + readPtr += 32; - if (readPtr == fifo.CPEnd) - readPtr = fifo.CPBase; - else - readPtr += 32; + _assert_msg_(COMMANDPROCESSOR, (s32)fifo.CPReadWriteDistance - 32 >= 0, + "Negative fifo.CPReadWriteDistance = %i in FIFO Loop !\nThat can produce " + "instability in the game. Please report it.", + fifo.CPReadWriteDistance - 32); - _assert_msg_(COMMANDPROCESSOR, (s32)fifo.CPReadWriteDistance - 32 >= 0 , - "Negative fifo.CPReadWriteDistance = %i in FIFO Loop !\nThat can produce instability in the game. Please report it.", fifo.CPReadWriteDistance - 32); + u8* write_ptr = s_video_buffer_write_ptr; + s_video_buffer_read_ptr = OpcodeDecoder::Run( + DataReader(s_video_buffer_read_ptr, write_ptr), &cyclesExecuted, false); - u8* write_ptr = s_video_buffer_write_ptr; - s_video_buffer_read_ptr = OpcodeDecoder::Run(DataReader(s_video_buffer_read_ptr, write_ptr), &cyclesExecuted, false); + Common::AtomicStore(fifo.CPReadPointer, readPtr); + Common::AtomicAdd(fifo.CPReadWriteDistance, -32); + if ((write_ptr - s_video_buffer_read_ptr) == 0) + Common::AtomicStore(fifo.SafeCPReadPointer, fifo.CPReadPointer); - Common::AtomicStore(fifo.CPReadPointer, readPtr); - Common::AtomicAdd(fifo.CPReadWriteDistance, -32); - if ((write_ptr - s_video_buffer_read_ptr) == 0) - Common::AtomicStore(fifo.SafeCPReadPointer, fifo.CPReadPointer); + CommandProcessor::SetCPStatusFromGPU(); - CommandProcessor::SetCPStatusFromGPU(); + if (param.bSyncGPU) + { + cyclesExecuted = (int)(cyclesExecuted / param.fSyncGpuOverclock); + int old = s_sync_ticks.fetch_sub(cyclesExecuted); + if (old > 0 && old - (int)cyclesExecuted <= 0) + s_sync_wakeup_event.Set(); + } - if (param.bSyncGPU) - { - cyclesExecuted = (int)(cyclesExecuted / param.fSyncGpuOverclock); - int old = s_sync_ticks.fetch_sub(cyclesExecuted); - if (old > 0 && old - (int)cyclesExecuted <= 0) - s_sync_wakeup_event.Set(); - } + // This call is pretty important in DualCore mode and must be called in the FIFO Loop. + // If we don't, s_swapRequested or s_efbAccessRequested won't be set to false + // leading the CPU thread to wait in Video_BeginField or Video_AccessEFB thus slowing + // things down. + AsyncRequests::GetInstance()->PullEvents(); + } - // This call is pretty important in DualCore mode and must be called in the FIFO Loop. - // If we don't, s_swapRequested or s_efbAccessRequested won't be set to false - // leading the CPU thread to wait in Video_BeginField or Video_AccessEFB thus slowing things down. - AsyncRequests::GetInstance()->PullEvents(); - } + // fast skip remaining GPU time if fifo is empty + if (s_sync_ticks.load() > 0) + { + int old = s_sync_ticks.exchange(0); + if (old > 0) + s_sync_wakeup_event.Set(); + } - // fast skip remaining GPU time if fifo is empty - if (s_sync_ticks.load() > 0) - { - int old = s_sync_ticks.exchange(0); - if (old > 0) - s_sync_wakeup_event.Set(); - } + // The fifo is empty and it's unlikely we will get any more work in the near future. + // Make sure VertexManager finishes drawing any primitives it has stored in it's buffer. + VertexManagerBase::Flush(); + } + }, + 100); - // The fifo is empty and it's unlikely we will get any more work in the near future. - // Make sure VertexManager finishes drawing any primitives it has stored in it's buffer. - VertexManagerBase::Flush(); - } - }, 100); - - AsyncRequests::GetInstance()->SetEnable(false); - AsyncRequests::GetInstance()->SetPassthrough(true); + AsyncRequests::GetInstance()->SetEnable(false); + AsyncRequests::GetInstance()->SetPassthrough(true); } void FlushGpu() { - const SConfig& param = SConfig::GetInstance(); + const SConfig& param = SConfig::GetInstance(); - if (!param.bCPUThread || s_use_deterministic_gpu_thread) - return; + if (!param.bCPUThread || s_use_deterministic_gpu_thread) + return; - s_gpu_mainloop.Wait(); + s_gpu_mainloop.Wait(); } void GpuMaySleep() { - s_gpu_mainloop.AllowSleep(); + s_gpu_mainloop.AllowSleep(); } bool AtBreakpoint() { - SCPFifoStruct &fifo = CommandProcessor::fifo; - return fifo.bFF_BPEnable && (fifo.CPReadPointer == fifo.CPBreakpoint); + SCPFifoStruct& fifo = CommandProcessor::fifo; + return fifo.bFF_BPEnable && (fifo.CPReadPointer == fifo.CPBreakpoint); } void RunGpu() { - SCPFifoStruct &fifo = CommandProcessor::fifo; - const SConfig& param = SConfig::GetInstance(); + SCPFifoStruct& fifo = CommandProcessor::fifo; + const SConfig& param = SConfig::GetInstance(); - // execute GPU - if (!param.bCPUThread || s_use_deterministic_gpu_thread) - { - bool reset_simd_state = false; - while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() ) - { - if (s_use_deterministic_gpu_thread) - { - ReadDataFromFifoOnCPU(fifo.CPReadPointer); - s_gpu_mainloop.Wakeup(); - } - else - { - if (!reset_simd_state) - { - FPURoundMode::SaveSIMDState(); - FPURoundMode::LoadDefaultSIMDState(); - reset_simd_state = true; - } - ReadDataFromFifo(fifo.CPReadPointer); - s_video_buffer_read_ptr = OpcodeDecoder::Run(DataReader(s_video_buffer_read_ptr, s_video_buffer_write_ptr), nullptr, false); - } + // execute GPU + if (!param.bCPUThread || s_use_deterministic_gpu_thread) + { + bool reset_simd_state = false; + while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint()) + { + if (s_use_deterministic_gpu_thread) + { + ReadDataFromFifoOnCPU(fifo.CPReadPointer); + s_gpu_mainloop.Wakeup(); + } + else + { + if (!reset_simd_state) + { + FPURoundMode::SaveSIMDState(); + FPURoundMode::LoadDefaultSIMDState(); + reset_simd_state = true; + } + ReadDataFromFifo(fifo.CPReadPointer); + s_video_buffer_read_ptr = OpcodeDecoder::Run( + DataReader(s_video_buffer_read_ptr, s_video_buffer_write_ptr), nullptr, false); + } - //DEBUG_LOG(COMMANDPROCESSOR, "Fifo wraps to base"); + // DEBUG_LOG(COMMANDPROCESSOR, "Fifo wraps to base"); - if (fifo.CPReadPointer == fifo.CPEnd) - fifo.CPReadPointer = fifo.CPBase; - else - fifo.CPReadPointer += 32; + if (fifo.CPReadPointer == fifo.CPEnd) + fifo.CPReadPointer = fifo.CPBase; + else + fifo.CPReadPointer += 32; - fifo.CPReadWriteDistance -= 32; - } - CommandProcessor::SetCPStatusFromGPU(); + fifo.CPReadWriteDistance -= 32; + } + CommandProcessor::SetCPStatusFromGPU(); - if (reset_simd_state) - { - FPURoundMode::LoadSIMDState(); - } - } + if (reset_simd_state) + { + FPURoundMode::LoadSIMDState(); + } + } - // wake up GPU thread - if (param.bCPUThread) - { - s_gpu_mainloop.Wakeup(); - } + // wake up GPU thread + if (param.bCPUThread) + { + s_gpu_mainloop.Wakeup(); + } } void UpdateWantDeterminism(bool want) { - // We are paused (or not running at all yet), so - // it should be safe to change this. - const SConfig& param = SConfig::GetInstance(); - bool gpu_thread = false; - switch (param.m_GPUDeterminismMode) - { - case GPU_DETERMINISM_AUTO: - gpu_thread = want; + // We are paused (or not running at all yet), so + // it should be safe to change this. + const SConfig& param = SConfig::GetInstance(); + bool gpu_thread = false; + switch (param.m_GPUDeterminismMode) + { + case GPU_DETERMINISM_AUTO: + gpu_thread = want; - // Hack: For now movies are an exception to this being on (but not - // to wanting determinism in general). Once vertex arrays are - // fixed, there should be no reason to want this off for movies by - // default, so this can be removed. - if (!NetPlay::IsNetPlayRunning()) - gpu_thread = false; + // Hack: For now movies are an exception to this being on (but not + // to wanting determinism in general). Once vertex arrays are + // fixed, there should be no reason to want this off for movies by + // default, so this can be removed. + if (!NetPlay::IsNetPlayRunning()) + gpu_thread = false; - break; - case GPU_DETERMINISM_NONE: - gpu_thread = false; - break; - case GPU_DETERMINISM_FAKE_COMPLETION: - gpu_thread = true; - break; - } + break; + case GPU_DETERMINISM_NONE: + gpu_thread = false; + break; + case GPU_DETERMINISM_FAKE_COMPLETION: + gpu_thread = true; + break; + } - gpu_thread = gpu_thread && param.bCPUThread; + gpu_thread = gpu_thread && param.bCPUThread; - if (s_use_deterministic_gpu_thread != gpu_thread) - { - s_use_deterministic_gpu_thread = gpu_thread; - if (gpu_thread) - { - // These haven't been updated in non-deterministic mode. - s_video_buffer_seen_ptr = s_video_buffer_pp_read_ptr = s_video_buffer_read_ptr; - CopyPreprocessCPStateFromMain(); - VertexLoaderManager::MarkAllDirty(); - } - } + if (s_use_deterministic_gpu_thread != gpu_thread) + { + s_use_deterministic_gpu_thread = gpu_thread; + if (gpu_thread) + { + // These haven't been updated in non-deterministic mode. + s_video_buffer_seen_ptr = s_video_buffer_pp_read_ptr = s_video_buffer_read_ptr; + CopyPreprocessCPStateFromMain(); + VertexLoaderManager::MarkAllDirty(); + } + } } bool UseDeterministicGPUThread() { - return s_use_deterministic_gpu_thread; + return s_use_deterministic_gpu_thread; } /* This function checks the emulated CPU - GPU distance and may wake up the GPU, @@ -517,56 +524,55 @@ bool UseDeterministicGPUThread() */ static int Update(int ticks) { - const SConfig& param = SConfig::GetInstance(); + const SConfig& param = SConfig::GetInstance(); - // GPU is sleeping, so no need for synchronization - if (s_gpu_mainloop.IsDone() || s_use_deterministic_gpu_thread) - { - if (s_sync_ticks.load() < 0) - { - int old = s_sync_ticks.fetch_add(ticks); - if (old < param.iSyncGpuMinDistance && old + ticks >= param.iSyncGpuMinDistance) - RunGpu(); - } - return param.iSyncGpuMaxDistance; - } + // GPU is sleeping, so no need for synchronization + if (s_gpu_mainloop.IsDone() || s_use_deterministic_gpu_thread) + { + if (s_sync_ticks.load() < 0) + { + int old = s_sync_ticks.fetch_add(ticks); + if (old < param.iSyncGpuMinDistance && old + ticks >= param.iSyncGpuMinDistance) + RunGpu(); + } + return param.iSyncGpuMaxDistance; + } - // Wakeup GPU - int old = s_sync_ticks.fetch_add(ticks); - if (old < param.iSyncGpuMinDistance && old + ticks >= param.iSyncGpuMinDistance) - RunGpu(); + // Wakeup GPU + int old = s_sync_ticks.fetch_add(ticks); + if (old < param.iSyncGpuMinDistance && old + ticks >= param.iSyncGpuMinDistance) + RunGpu(); - // Wait for GPU - if (s_sync_ticks.load() >= param.iSyncGpuMaxDistance) - { - while (s_sync_ticks.load() > 0) - { - s_sync_wakeup_event.Wait(); - } - } + // Wait for GPU + if (s_sync_ticks.load() >= param.iSyncGpuMaxDistance) + { + while (s_sync_ticks.load() > 0) + { + s_sync_wakeup_event.Wait(); + } + } - return param.iSyncGpuMaxDistance - s_sync_ticks.load(); + return param.iSyncGpuMaxDistance - s_sync_ticks.load(); } static void SyncGPUCallback(u64 userdata, s64 cyclesLate) { - u64 now = CoreTiming::GetTicks(); - int next = Fifo::Update((int)(now - s_last_sync_gpu_tick)); - s_last_sync_gpu_tick = now; + u64 now = CoreTiming::GetTicks(); + int next = Fifo::Update((int)(now - s_last_sync_gpu_tick)); + s_last_sync_gpu_tick = now; - if (next > 0) - CoreTiming::ScheduleEvent(next, s_event_sync_gpu); + if (next > 0) + CoreTiming::ScheduleEvent(next, s_event_sync_gpu); } // Initialize GPU - CPU thread syncing, this gives us a deterministic way to start the GPU thread. void Prepare() { - if (SConfig::GetInstance().bCPUThread && SConfig::GetInstance().bSyncGPU) - { - s_event_sync_gpu = CoreTiming::RegisterEvent("SyncGPUCallback", SyncGPUCallback); - CoreTiming::ScheduleEvent(0, s_event_sync_gpu); - s_last_sync_gpu_tick = CoreTiming::GetTicks(); - } + if (SConfig::GetInstance().bCPUThread && SConfig::GetInstance().bSyncGPU) + { + s_event_sync_gpu = CoreTiming::RegisterEvent("SyncGPUCallback", SyncGPUCallback); + CoreTiming::ScheduleEvent(0, s_event_sync_gpu); + s_last_sync_gpu_tick = CoreTiming::GetTicks(); + } } - } diff --git a/Source/Core/VideoCommon/Fifo.h b/Source/Core/VideoCommon/Fifo.h index 68b9ac2eee..d2172df655 100644 --- a/Source/Core/VideoCommon/Fifo.h +++ b/Source/Core/VideoCommon/Fifo.h @@ -11,11 +11,10 @@ class PointerWrap; namespace Fifo { - void Init(); void Shutdown(); -void Prepare(); // Must be called from the CPU thread. -void DoState(PointerWrap &f); +void Prepare(); // Must be called from the CPU thread. +void DoState(PointerWrap& f); void PauseAndLock(bool doLock, bool unpauseOnUnlock); void UpdateWantDeterminism(bool want); bool UseDeterministicGPUThread(); @@ -23,13 +22,13 @@ bool UseDeterministicGPUThread(); // Used for diagnostics. enum SyncGPUReason { - SYNC_GPU_OTHER, - SYNC_GPU_WRAPAROUND, - SYNC_GPU_EFB_POKE, - SYNC_GPU_PERFQUERY, - SYNC_GPU_BBOX, - SYNC_GPU_SWAP, - SYNC_GPU_AUX_SPACE, + SYNC_GPU_OTHER, + SYNC_GPU_WRAPAROUND, + SYNC_GPU_EFB_POKE, + SYNC_GPU_PERFQUERY, + SYNC_GPU_BBOX, + SYNC_GPU_SWAP, + SYNC_GPU_AUX_SPACE, }; // In deterministic GPU thread mode this waits for the GPU to be done with pending work. void SyncGPU(SyncGPUReason reason, bool may_move_read_ptr = true); @@ -48,4 +47,4 @@ void ResetVideoBuffer(); void SetRendering(bool bEnabled); bool WillSkipCurrentFrame(); -} // namespace Fifo +} // namespace Fifo diff --git a/Source/Core/VideoCommon/FramebufferManagerBase.cpp b/Source/Core/VideoCommon/FramebufferManagerBase.cpp index ab095f1020..b9cf3eb4d6 100644 --- a/Source/Core/VideoCommon/FramebufferManagerBase.cpp +++ b/Source/Core/VideoCommon/FramebufferManagerBase.cpp @@ -2,18 +2,21 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoCommon/FramebufferManagerBase.h" #include #include #include -#include "VideoCommon/FramebufferManagerBase.h" #include "VideoCommon/RenderBase.h" #include "VideoCommon/VideoConfig.h" std::unique_ptr g_framebuffer_manager; -std::unique_ptr FramebufferManagerBase::m_realXFBSource; // Only used in Real XFB mode -FramebufferManagerBase::VirtualXFBListType FramebufferManagerBase::m_virtualXFBList; // Only used in Virtual XFB mode -std::array FramebufferManagerBase::m_overlappingXFBArray; +std::unique_ptr + FramebufferManagerBase::m_realXFBSource; // Only used in Real XFB mode +FramebufferManagerBase::VirtualXFBListType + FramebufferManagerBase::m_virtualXFBList; // Only used in Virtual XFB mode +std::array + FramebufferManagerBase::m_overlappingXFBArray; unsigned int FramebufferManagerBase::s_last_xfb_width = 1; unsigned int FramebufferManagerBase::s_last_xfb_height = 1; @@ -22,229 +25,240 @@ unsigned int FramebufferManagerBase::m_EFBLayers = 1; FramebufferManagerBase::FramebufferManagerBase() { - // Can't hurt - m_overlappingXFBArray.fill(nullptr); + // Can't hurt + m_overlappingXFBArray.fill(nullptr); } FramebufferManagerBase::~FramebufferManagerBase() { - // Necessary, as these are static members - // (they really shouldn't be and should be refactored at some point). - m_virtualXFBList.clear(); - m_realXFBSource.reset(); + // Necessary, as these are static members + // (they really shouldn't be and should be refactored at some point). + m_virtualXFBList.clear(); + m_realXFBSource.reset(); } -const XFBSourceBase* const* FramebufferManagerBase::GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32* xfbCountP) +const XFBSourceBase* const* FramebufferManagerBase::GetXFBSource(u32 xfbAddr, u32 fbWidth, + u32 fbHeight, u32* xfbCountP) { - if (!g_ActiveConfig.bUseXFB) - return nullptr; + if (!g_ActiveConfig.bUseXFB) + return nullptr; - if (g_ActiveConfig.bUseRealXFB) - return GetRealXFBSource(xfbAddr, fbWidth, fbHeight, xfbCountP); - else - return GetVirtualXFBSource(xfbAddr, fbWidth, fbHeight, xfbCountP); + if (g_ActiveConfig.bUseRealXFB) + return GetRealXFBSource(xfbAddr, fbWidth, fbHeight, xfbCountP); + else + return GetVirtualXFBSource(xfbAddr, fbWidth, fbHeight, xfbCountP); } -const XFBSourceBase* const* FramebufferManagerBase::GetRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32* xfbCountP) +const XFBSourceBase* const* FramebufferManagerBase::GetRealXFBSource(u32 xfbAddr, u32 fbWidth, + u32 fbHeight, u32* xfbCountP) { - *xfbCountP = 1; + *xfbCountP = 1; - // recreate if needed - if (m_realXFBSource && (m_realXFBSource->texWidth != fbWidth || m_realXFBSource->texHeight != fbHeight)) - m_realXFBSource.reset(); + // recreate if needed + if (m_realXFBSource && + (m_realXFBSource->texWidth != fbWidth || m_realXFBSource->texHeight != fbHeight)) + m_realXFBSource.reset(); - if (!m_realXFBSource && g_framebuffer_manager) - m_realXFBSource = g_framebuffer_manager->CreateXFBSource(fbWidth, fbHeight, 1); + if (!m_realXFBSource && g_framebuffer_manager) + m_realXFBSource = g_framebuffer_manager->CreateXFBSource(fbWidth, fbHeight, 1); - if (!m_realXFBSource) - return nullptr; + if (!m_realXFBSource) + return nullptr; - m_realXFBSource->srcAddr = xfbAddr; + m_realXFBSource->srcAddr = xfbAddr; - m_realXFBSource->srcWidth = MAX_XFB_WIDTH; - m_realXFBSource->srcHeight = MAX_XFB_HEIGHT; + m_realXFBSource->srcWidth = MAX_XFB_WIDTH; + m_realXFBSource->srcHeight = MAX_XFB_HEIGHT; - m_realXFBSource->texWidth = fbWidth; - m_realXFBSource->texHeight = fbHeight; + m_realXFBSource->texWidth = fbWidth; + m_realXFBSource->texHeight = fbHeight; - m_realXFBSource->sourceRc.left = 0; - m_realXFBSource->sourceRc.top = 0; - m_realXFBSource->sourceRc.right = fbWidth; - m_realXFBSource->sourceRc.bottom = fbHeight; + m_realXFBSource->sourceRc.left = 0; + m_realXFBSource->sourceRc.top = 0; + m_realXFBSource->sourceRc.right = fbWidth; + m_realXFBSource->sourceRc.bottom = fbHeight; - // Decode YUYV data from GameCube RAM - m_realXFBSource->DecodeToTexture(xfbAddr, fbWidth, fbHeight); + // Decode YUYV data from GameCube RAM + m_realXFBSource->DecodeToTexture(xfbAddr, fbWidth, fbHeight); - m_overlappingXFBArray[0] = m_realXFBSource.get(); - return &m_overlappingXFBArray[0]; + m_overlappingXFBArray[0] = m_realXFBSource.get(); + return &m_overlappingXFBArray[0]; } -const XFBSourceBase* const* FramebufferManagerBase::GetVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32* xfbCountP) +const XFBSourceBase* const* +FramebufferManagerBase::GetVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32* xfbCountP) { - u32 xfbCount = 0; + u32 xfbCount = 0; - if (m_virtualXFBList.empty()) // no Virtual XFBs available - return nullptr; + if (m_virtualXFBList.empty()) // no Virtual XFBs available + return nullptr; - u32 srcLower = xfbAddr; - u32 srcUpper = xfbAddr + 2 * fbWidth * fbHeight; + u32 srcLower = xfbAddr; + u32 srcUpper = xfbAddr + 2 * fbWidth * fbHeight; - VirtualXFBListType::reverse_iterator - it = m_virtualXFBList.rbegin(), - vlend = m_virtualXFBList.rend(); - for (; it != vlend; ++it) - { - VirtualXFB* vxfb = &*it; + VirtualXFBListType::reverse_iterator it = m_virtualXFBList.rbegin(), + vlend = m_virtualXFBList.rend(); + for (; it != vlend; ++it) + { + VirtualXFB* vxfb = &*it; - u32 dstLower = vxfb->xfbAddr; - u32 dstUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight; + u32 dstLower = vxfb->xfbAddr; + u32 dstUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight; - if (AddressRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) - { - m_overlappingXFBArray[xfbCount] = vxfb->xfbSource.get(); - ++xfbCount; - } - } + if (AddressRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) + { + m_overlappingXFBArray[xfbCount] = vxfb->xfbSource.get(); + ++xfbCount; + } + } - *xfbCountP = xfbCount; - return &m_overlappingXFBArray[0]; + *xfbCountP = xfbCount; + return &m_overlappingXFBArray[0]; } -void FramebufferManagerBase::CopyToXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma) +void FramebufferManagerBase::CopyToXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, + const EFBRectangle& sourceRc, float Gamma) { - if (g_ActiveConfig.bUseRealXFB) - { - if (g_framebuffer_manager) - g_framebuffer_manager->CopyToRealXFB(xfbAddr, fbStride, fbHeight, sourceRc, Gamma); - } - else - { - CopyToVirtualXFB(xfbAddr, fbStride, fbHeight, sourceRc, Gamma); - } + if (g_ActiveConfig.bUseRealXFB) + { + if (g_framebuffer_manager) + g_framebuffer_manager->CopyToRealXFB(xfbAddr, fbStride, fbHeight, sourceRc, Gamma); + } + else + { + CopyToVirtualXFB(xfbAddr, fbStride, fbHeight, sourceRc, Gamma); + } } -void FramebufferManagerBase::CopyToVirtualXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma) +void FramebufferManagerBase::CopyToVirtualXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, + const EFBRectangle& sourceRc, float Gamma) { - if (!g_framebuffer_manager) - return; + if (!g_framebuffer_manager) + return; - VirtualXFBListType::iterator vxfb = FindVirtualXFB(xfbAddr, sourceRc.GetWidth(), fbHeight); + VirtualXFBListType::iterator vxfb = FindVirtualXFB(xfbAddr, sourceRc.GetWidth(), fbHeight); - if (m_virtualXFBList.end() == vxfb) - { - if (m_virtualXFBList.size() < MAX_VIRTUAL_XFB) - { - // create a new Virtual XFB and place it at the front of the list - m_virtualXFBList.emplace_front(); - vxfb = m_virtualXFBList.begin(); - } - else - { - // Replace the last virtual XFB - --vxfb; - } - } - //else // replace existing virtual XFB + if (m_virtualXFBList.end() == vxfb) + { + if (m_virtualXFBList.size() < MAX_VIRTUAL_XFB) + { + // create a new Virtual XFB and place it at the front of the list + m_virtualXFBList.emplace_front(); + vxfb = m_virtualXFBList.begin(); + } + else + { + // Replace the last virtual XFB + --vxfb; + } + } + // else // replace existing virtual XFB - // move this Virtual XFB to the front of the list. - if (m_virtualXFBList.begin() != vxfb) - m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, vxfb); + // move this Virtual XFB to the front of the list. + if (m_virtualXFBList.begin() != vxfb) + m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, vxfb); - unsigned int target_width, target_height; - g_framebuffer_manager->GetTargetSize(&target_width, &target_height); + unsigned int target_width, target_height; + g_framebuffer_manager->GetTargetSize(&target_width, &target_height); - // recreate if needed - if (vxfb->xfbSource && (vxfb->xfbSource->texWidth != target_width || vxfb->xfbSource->texHeight != target_height)) - vxfb->xfbSource.reset(); + // recreate if needed + if (vxfb->xfbSource && + (vxfb->xfbSource->texWidth != target_width || vxfb->xfbSource->texHeight != target_height)) + vxfb->xfbSource.reset(); - if (!vxfb->xfbSource) - { - vxfb->xfbSource = g_framebuffer_manager->CreateXFBSource(target_width, target_height, m_EFBLayers); - if (!vxfb->xfbSource) - return; + if (!vxfb->xfbSource) + { + vxfb->xfbSource = + g_framebuffer_manager->CreateXFBSource(target_width, target_height, m_EFBLayers); + if (!vxfb->xfbSource) + return; - vxfb->xfbSource->texWidth = target_width; - vxfb->xfbSource->texHeight = target_height; - } + vxfb->xfbSource->texWidth = target_width; + vxfb->xfbSource->texHeight = target_height; + } - vxfb->xfbSource->srcAddr = vxfb->xfbAddr = xfbAddr; - vxfb->xfbSource->srcWidth = vxfb->xfbWidth = sourceRc.GetWidth(); - vxfb->xfbSource->srcHeight = vxfb->xfbHeight = fbHeight; + vxfb->xfbSource->srcAddr = vxfb->xfbAddr = xfbAddr; + vxfb->xfbSource->srcWidth = vxfb->xfbWidth = sourceRc.GetWidth(); + vxfb->xfbSource->srcHeight = vxfb->xfbHeight = fbHeight; - vxfb->xfbSource->sourceRc = g_renderer->ConvertEFBRectangle(sourceRc); + vxfb->xfbSource->sourceRc = g_renderer->ConvertEFBRectangle(sourceRc); - // keep stale XFB data from being used - ReplaceVirtualXFB(); + // keep stale XFB data from being used + ReplaceVirtualXFB(); - // Copy EFB data to XFB and restore render target again - vxfb->xfbSource->CopyEFB(Gamma); + // Copy EFB data to XFB and restore render target again + vxfb->xfbSource->CopyEFB(Gamma); } -FramebufferManagerBase::VirtualXFBListType::iterator FramebufferManagerBase::FindVirtualXFB(u32 xfbAddr, u32 width, u32 height) +FramebufferManagerBase::VirtualXFBListType::iterator +FramebufferManagerBase::FindVirtualXFB(u32 xfbAddr, u32 width, u32 height) { - const u32 srcLower = xfbAddr; - const u32 srcUpper = xfbAddr + 2 * width * height; + const u32 srcLower = xfbAddr; + const u32 srcUpper = xfbAddr + 2 * width * height; - return std::find_if(m_virtualXFBList.begin(), m_virtualXFBList.end(), [srcLower, srcUpper](const VirtualXFB& xfb) { - const u32 dstLower = xfb.xfbAddr; - const u32 dstUpper = xfb.xfbAddr + 2 * xfb.xfbWidth * xfb.xfbHeight; + return std::find_if(m_virtualXFBList.begin(), m_virtualXFBList.end(), + [srcLower, srcUpper](const VirtualXFB& xfb) { + const u32 dstLower = xfb.xfbAddr; + const u32 dstUpper = xfb.xfbAddr + 2 * xfb.xfbWidth * xfb.xfbHeight; - return dstLower >= srcLower && dstUpper <= srcUpper; - }); + return dstLower >= srcLower && dstUpper <= srcUpper; + }); } void FramebufferManagerBase::ReplaceVirtualXFB() { - VirtualXFBListType::iterator it = m_virtualXFBList.begin(); + VirtualXFBListType::iterator it = m_virtualXFBList.begin(); - const s32 srcLower = it->xfbAddr; - const s32 srcUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; - const s32 lineSize = 2 * it->xfbWidth; + const s32 srcLower = it->xfbAddr; + const s32 srcUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; + const s32 lineSize = 2 * it->xfbWidth; - ++it; + ++it; - for (; it != m_virtualXFBList.end(); ++it) - { - s32 dstLower = it->xfbAddr; - s32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; + for (; it != m_virtualXFBList.end(); ++it) + { + s32 dstLower = it->xfbAddr; + s32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; - if (dstLower >= srcLower && dstUpper <= srcUpper) - { - // Invalidate the data - it->xfbAddr = 0; - it->xfbHeight = 0; - it->xfbWidth = 0; - } - else if (AddressRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) - { - s32 upperOverlap = (srcUpper - dstLower) / lineSize; - s32 lowerOverlap = (dstUpper - srcLower) / lineSize; + if (dstLower >= srcLower && dstUpper <= srcUpper) + { + // Invalidate the data + it->xfbAddr = 0; + it->xfbHeight = 0; + it->xfbWidth = 0; + } + else if (AddressRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) + { + s32 upperOverlap = (srcUpper - dstLower) / lineSize; + s32 lowerOverlap = (dstUpper - srcLower) / lineSize; - if (upperOverlap > 0 && lowerOverlap < 0) - { - it->xfbAddr += lineSize * upperOverlap; - it->xfbHeight -= upperOverlap; - } - else if (lowerOverlap > 0) - { - it->xfbHeight -= lowerOverlap; - } - } - } + if (upperOverlap > 0 && lowerOverlap < 0) + { + it->xfbAddr += lineSize * upperOverlap; + it->xfbHeight -= upperOverlap; + } + else if (lowerOverlap > 0) + { + it->xfbHeight -= lowerOverlap; + } + } + } } int FramebufferManagerBase::ScaleToVirtualXfbWidth(int x) { - if (g_ActiveConfig.RealXFBEnabled()) - return x; + if (g_ActiveConfig.RealXFBEnabled()) + return x; - return x * (int)Renderer::GetTargetRectangle().GetWidth() / (int)FramebufferManagerBase::LastXfbWidth(); + return x * (int)Renderer::GetTargetRectangle().GetWidth() / + (int)FramebufferManagerBase::LastXfbWidth(); } int FramebufferManagerBase::ScaleToVirtualXfbHeight(int y) { - if (g_ActiveConfig.RealXFBEnabled()) - return y; + if (g_ActiveConfig.RealXFBEnabled()) + return y; - return y * (int)Renderer::GetTargetRectangle().GetHeight() / (int)FramebufferManagerBase::LastXfbHeight(); + return y * (int)Renderer::GetTargetRectangle().GetHeight() / + (int)FramebufferManagerBase::LastXfbHeight(); } diff --git a/Source/Core/VideoCommon/FramebufferManagerBase.h b/Source/Core/VideoCommon/FramebufferManagerBase.h index d8eda55b8e..2e932170a4 100644 --- a/Source/Core/VideoCommon/FramebufferManagerBase.h +++ b/Source/Core/VideoCommon/FramebufferManagerBase.h @@ -13,96 +13,97 @@ inline bool AddressRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) { - return !((aLower >= bUpper) || (bLower >= aUpper)); + return !((aLower >= bUpper) || (bLower >= aUpper)); } struct XFBSourceBase { - virtual ~XFBSourceBase() {} + virtual ~XFBSourceBase() {} + virtual void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) = 0; - virtual void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) = 0; + virtual void CopyEFB(float Gamma) = 0; - virtual void CopyEFB(float Gamma) = 0; + u32 srcAddr; + u32 srcWidth; + u32 srcHeight; - u32 srcAddr; - u32 srcWidth; - u32 srcHeight; + unsigned int texWidth; + unsigned int texHeight; - unsigned int texWidth; - unsigned int texHeight; - - // TODO: only used by OGL - TargetRectangle sourceRc; + // TODO: only used by OGL + TargetRectangle sourceRc; }; class FramebufferManagerBase { public: - enum - { - // There may be multiple XFBs in GameCube RAM. This is the maximum number to - // virtualize. - MAX_VIRTUAL_XFB = 8 - }; + enum + { + // There may be multiple XFBs in GameCube RAM. This is the maximum number to + // virtualize. + MAX_VIRTUAL_XFB = 8 + }; - FramebufferManagerBase(); - virtual ~FramebufferManagerBase(); + FramebufferManagerBase(); + virtual ~FramebufferManagerBase(); - static void CopyToXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma); - static const XFBSourceBase* const* GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32* xfbCount); + static void CopyToXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, + float Gamma); + static const XFBSourceBase* const* GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, + u32* xfbCount); - static void SetLastXfbWidth(unsigned int width) { s_last_xfb_width = width; } - static void SetLastXfbHeight(unsigned int height) { s_last_xfb_height = height; } - static unsigned int LastXfbWidth() { return s_last_xfb_width; } - static unsigned int LastXfbHeight() { return s_last_xfb_height; } - - static int ScaleToVirtualXfbWidth(int x); - static int ScaleToVirtualXfbHeight(int y); - - static unsigned int GetEFBLayers() { return m_EFBLayers; } + static void SetLastXfbWidth(unsigned int width) { s_last_xfb_width = width; } + static void SetLastXfbHeight(unsigned int height) { s_last_xfb_height = height; } + static unsigned int LastXfbWidth() { return s_last_xfb_width; } + static unsigned int LastXfbHeight() { return s_last_xfb_height; } + static int ScaleToVirtualXfbWidth(int x); + static int ScaleToVirtualXfbHeight(int y); + static unsigned int GetEFBLayers() { return m_EFBLayers; } protected: - struct VirtualXFB - { - VirtualXFB() - { - } + struct VirtualXFB + { + VirtualXFB() {} + // Address and size in GameCube RAM + u32 xfbAddr = 0; + u32 xfbWidth = 0; + u32 xfbHeight = 0; - // Address and size in GameCube RAM - u32 xfbAddr = 0; - u32 xfbWidth = 0; - u32 xfbHeight = 0; + std::unique_ptr xfbSource; + }; - std::unique_ptr xfbSource; - }; + typedef std::list VirtualXFBListType; - typedef std::list VirtualXFBListType; - - static unsigned int m_EFBLayers; + static unsigned int m_EFBLayers; private: - virtual std::unique_ptr CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) = 0; - // TODO: figure out why OGL is different for this guy - virtual void GetTargetSize(unsigned int *width, unsigned int *height) = 0; + virtual std::unique_ptr + CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) = 0; + // TODO: figure out why OGL is different for this guy + virtual void GetTargetSize(unsigned int* width, unsigned int* height) = 0; - static VirtualXFBListType::iterator FindVirtualXFB(u32 xfbAddr, u32 width, u32 height); + static VirtualXFBListType::iterator FindVirtualXFB(u32 xfbAddr, u32 width, u32 height); - static void ReplaceVirtualXFB(); + static void ReplaceVirtualXFB(); - // TODO: merge these virtual funcs, they are nearly all the same - virtual void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma = 1.0f) = 0; - static void CopyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma = 1.0f); + // TODO: merge these virtual funcs, they are nearly all the same + virtual void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, + float Gamma = 1.0f) = 0; + static void CopyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, + float Gamma = 1.0f); - static const XFBSourceBase* const* GetRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32* xfbCount); - static const XFBSourceBase* const* GetVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32* xfbCount); + static const XFBSourceBase* const* GetRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, + u32* xfbCount); + static const XFBSourceBase* const* GetVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, + u32* xfbCount); - static std::unique_ptr m_realXFBSource; // Only used in Real XFB mode - static VirtualXFBListType m_virtualXFBList; // Only used in Virtual XFB mode + static std::unique_ptr m_realXFBSource; // Only used in Real XFB mode + static VirtualXFBListType m_virtualXFBList; // Only used in Virtual XFB mode - static std::array m_overlappingXFBArray; + static std::array m_overlappingXFBArray; - static unsigned int s_last_xfb_width; - static unsigned int s_last_xfb_height; + static unsigned int s_last_xfb_width; + static unsigned int s_last_xfb_height; }; extern std::unique_ptr g_framebuffer_manager; diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index 4d551f5d16..02744c2889 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -11,321 +11,324 @@ #include "VideoCommon/LightingShaderGen.h" #include "VideoCommon/VideoConfig.h" +static const char* primitives_ogl[] = {"points", "lines", "triangles"}; -static const char* primitives_ogl[] = -{ - "points", - "lines", - "triangles" -}; +static const char* primitives_d3d[] = {"point", "line", "triangle"}; -static const char* primitives_d3d[] = -{ - "point", - "line", - "triangle" -}; +template +static void EmitVertex(T& out, const char* vertex, API_TYPE ApiType, bool first_vertex = false); +template +static void EndPrimitive(T& out, API_TYPE ApiType); -template static void EmitVertex(T& out, const char* vertex, API_TYPE ApiType, bool first_vertex = false); -template static void EndPrimitive(T& out, API_TYPE ApiType); - -template +template static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType) { - T out; - // Non-uid template parameters will write to the dummy data (=> gets optimized out) - geometry_shader_uid_data dummy_data; - geometry_shader_uid_data* uid_data = out.template GetUidData(); - if (uid_data != nullptr) - memset(uid_data, 0, sizeof(*uid_data)); - else - uid_data = &dummy_data; + T out; + // Non-uid template parameters will write to the dummy data (=> gets optimized out) + geometry_shader_uid_data dummy_data; + geometry_shader_uid_data* uid_data = out.template GetUidData(); + if (uid_data != nullptr) + memset(uid_data, 0, sizeof(*uid_data)); + else + uid_data = &dummy_data; - uid_data->primitive_type = primitive_type; - const unsigned int vertex_in = primitive_type + 1; - unsigned int vertex_out = primitive_type == PRIMITIVE_TRIANGLES ? 3 : 4; + uid_data->primitive_type = primitive_type; + const unsigned int vertex_in = primitive_type + 1; + unsigned int vertex_out = primitive_type == PRIMITIVE_TRIANGLES ? 3 : 4; - uid_data->wireframe = g_ActiveConfig.bWireFrame; - if (g_ActiveConfig.bWireFrame) - vertex_out++; + uid_data->wireframe = g_ActiveConfig.bWireFrame; + if (g_ActiveConfig.bWireFrame) + vertex_out++; - uid_data->stereo = g_ActiveConfig.iStereoMode > 0; - if (ApiType == API_OPENGL) - { - // Insert layout parameters - if (g_ActiveConfig.backend_info.bSupportsGSInstancing) - { - out.Write("layout(%s, invocations = %d) in;\n", primitives_ogl[primitive_type], g_ActiveConfig.iStereoMode > 0 ? 2 : 1); - out.Write("layout(%s_strip, max_vertices = %d) out;\n", g_ActiveConfig.bWireFrame ? "line" : "triangle", vertex_out); - } - else - { - out.Write("layout(%s) in;\n", primitives_ogl[primitive_type]); - out.Write("layout(%s_strip, max_vertices = %d) out;\n", g_ActiveConfig.bWireFrame ? "line" : "triangle", g_ActiveConfig.iStereoMode > 0 ? vertex_out * 2 : vertex_out); - } - } + uid_data->stereo = g_ActiveConfig.iStereoMode > 0; + if (ApiType == API_OPENGL) + { + // Insert layout parameters + if (g_ActiveConfig.backend_info.bSupportsGSInstancing) + { + out.Write("layout(%s, invocations = %d) in;\n", primitives_ogl[primitive_type], + g_ActiveConfig.iStereoMode > 0 ? 2 : 1); + out.Write("layout(%s_strip, max_vertices = %d) out;\n", + g_ActiveConfig.bWireFrame ? "line" : "triangle", vertex_out); + } + else + { + out.Write("layout(%s) in;\n", primitives_ogl[primitive_type]); + out.Write("layout(%s_strip, max_vertices = %d) out;\n", + g_ActiveConfig.bWireFrame ? "line" : "triangle", + g_ActiveConfig.iStereoMode > 0 ? vertex_out * 2 : vertex_out); + } + } - out.Write("%s", s_lighting_struct); + out.Write("%s", s_lighting_struct); - // uniforms - if (ApiType == API_OPENGL) - out.Write("layout(std140%s) uniform GSBlock {\n", g_ActiveConfig.backend_info.bSupportsBindingLayout ? ", binding = 3" : ""); - else - out.Write("cbuffer GSBlock {\n"); - out.Write( - "\tfloat4 " I_STEREOPARAMS";\n" - "\tfloat4 " I_LINEPTPARAMS";\n" - "\tint4 " I_TEXOFFSET";\n" - "};\n"); + // uniforms + if (ApiType == API_OPENGL) + out.Write("layout(std140%s) uniform GSBlock {\n", + g_ActiveConfig.backend_info.bSupportsBindingLayout ? ", binding = 3" : ""); + else + out.Write("cbuffer GSBlock {\n"); + out.Write("\tfloat4 " I_STEREOPARAMS ";\n" + "\tfloat4 " I_LINEPTPARAMS ";\n" + "\tint4 " I_TEXOFFSET ";\n" + "};\n"); - uid_data->numTexGens = xfmem.numTexGen.numTexGens; - uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting; + uid_data->numTexGens = xfmem.numTexGen.numTexGens; + uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting; - out.Write("struct VS_OUTPUT {\n"); - GenerateVSOutputMembers(out, ApiType, ""); - out.Write("};\n"); + out.Write("struct VS_OUTPUT {\n"); + GenerateVSOutputMembers(out, ApiType, ""); + out.Write("};\n"); - if (ApiType == API_OPENGL) - { - if (g_ActiveConfig.backend_info.bSupportsGSInstancing) - out.Write("#define InstanceID gl_InvocationID\n"); + if (ApiType == API_OPENGL) + { + if (g_ActiveConfig.backend_info.bSupportsGSInstancing) + out.Write("#define InstanceID gl_InvocationID\n"); - out.Write("in VertexData {\n"); - GenerateVSOutputMembers(out, ApiType, GetInterpolationQualifier(true, true)); - out.Write("} vs[%d];\n", vertex_in); + out.Write("in VertexData {\n"); + GenerateVSOutputMembers(out, ApiType, GetInterpolationQualifier(true, true)); + out.Write("} vs[%d];\n", vertex_in); - out.Write("out VertexData {\n"); - GenerateVSOutputMembers(out, ApiType, GetInterpolationQualifier(true, false)); + out.Write("out VertexData {\n"); + GenerateVSOutputMembers(out, ApiType, GetInterpolationQualifier(true, false)); - if (g_ActiveConfig.iStereoMode > 0) - out.Write("\tflat int layer;\n"); + if (g_ActiveConfig.iStereoMode > 0) + out.Write("\tflat int layer;\n"); - out.Write("} ps;\n"); + out.Write("} ps;\n"); - out.Write("void main()\n{\n"); - } - else // D3D - { - out.Write("struct VertexData {\n"); - out.Write("\tVS_OUTPUT o;\n"); + out.Write("void main()\n{\n"); + } + else // D3D + { + out.Write("struct VertexData {\n"); + out.Write("\tVS_OUTPUT o;\n"); - if (g_ActiveConfig.iStereoMode > 0) - out.Write("\tuint layer : SV_RenderTargetArrayIndex;\n"); + if (g_ActiveConfig.iStereoMode > 0) + out.Write("\tuint layer : SV_RenderTargetArrayIndex;\n"); - out.Write("};\n"); + out.Write("};\n"); - if (g_ActiveConfig.backend_info.bSupportsGSInstancing) - { - out.Write("[maxvertexcount(%d)]\n[instance(%d)]\n", vertex_out, g_ActiveConfig.iStereoMode > 0 ? 2 : 1); - out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream output, in uint InstanceID : SV_GSInstanceID)\n{\n", primitives_d3d[primitive_type], vertex_in, g_ActiveConfig.bWireFrame ? "Line" : "Triangle"); - } - else - { - out.Write("[maxvertexcount(%d)]\n", g_ActiveConfig.iStereoMode > 0 ? vertex_out * 2 : vertex_out); - out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream output)\n{\n", primitives_d3d[primitive_type], vertex_in, g_ActiveConfig.bWireFrame ? "Line" : "Triangle"); - } + if (g_ActiveConfig.backend_info.bSupportsGSInstancing) + { + out.Write("[maxvertexcount(%d)]\n[instance(%d)]\n", vertex_out, + g_ActiveConfig.iStereoMode > 0 ? 2 : 1); + out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream output, in uint " + "InstanceID : SV_GSInstanceID)\n{\n", + primitives_d3d[primitive_type], vertex_in, + g_ActiveConfig.bWireFrame ? "Line" : "Triangle"); + } + else + { + out.Write("[maxvertexcount(%d)]\n", + g_ActiveConfig.iStereoMode > 0 ? vertex_out * 2 : vertex_out); + out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream output)\n{\n", + primitives_d3d[primitive_type], vertex_in, + g_ActiveConfig.bWireFrame ? "Line" : "Triangle"); + } - out.Write("\tVertexData ps;\n"); - } + out.Write("\tVertexData ps;\n"); + } - if (primitive_type == PRIMITIVE_LINES) - { - if (ApiType == API_OPENGL) - { - out.Write("\tVS_OUTPUT start, end;\n"); - AssignVSOutputMembers(out, "start", "vs[0]"); - AssignVSOutputMembers(out, "end", "vs[1]"); - } - else - { - out.Write("\tVS_OUTPUT start = o[0];\n"); - out.Write("\tVS_OUTPUT end = o[1];\n"); - } + if (primitive_type == PRIMITIVE_LINES) + { + if (ApiType == API_OPENGL) + { + out.Write("\tVS_OUTPUT start, end;\n"); + AssignVSOutputMembers(out, "start", "vs[0]"); + AssignVSOutputMembers(out, "end", "vs[1]"); + } + else + { + out.Write("\tVS_OUTPUT start = o[0];\n"); + out.Write("\tVS_OUTPUT end = o[1];\n"); + } - // GameCube/Wii's line drawing algorithm is a little quirky. It does not - // use the correct line caps. Instead, the line caps are vertical or - // horizontal depending the slope of the line. - out.Write( - "\tfloat2 offset;\n" - "\tfloat2 to = abs(end.pos.xy / end.pos.w - start.pos.xy / start.pos.w);\n" - // FIXME: What does real hardware do when line is at a 45-degree angle? - // FIXME: Lines aren't drawn at the correct width. See Twilight Princess map. - "\tif (" I_LINEPTPARAMS".y * to.y > " I_LINEPTPARAMS".x * to.x) {\n" - // Line is more tall. Extend geometry left and right. - // Lerp LineWidth/2 from [0..VpWidth] to [-1..1] - "\t\toffset = float2(" I_LINEPTPARAMS".z / " I_LINEPTPARAMS".x, 0);\n" - "\t} else {\n" - // Line is more wide. Extend geometry up and down. - // Lerp LineWidth/2 from [0..VpHeight] to [1..-1] - "\t\toffset = float2(0, -" I_LINEPTPARAMS".z / " I_LINEPTPARAMS".y);\n" - "\t}\n"); - } - else if (primitive_type == PRIMITIVE_POINTS) - { - if (ApiType == API_OPENGL) - { - out.Write("\tVS_OUTPUT center;\n"); - AssignVSOutputMembers(out, "center", "vs[0]"); - } - else - { - out.Write("\tVS_OUTPUT center = o[0];\n"); - } + // GameCube/Wii's line drawing algorithm is a little quirky. It does not + // use the correct line caps. Instead, the line caps are vertical or + // horizontal depending the slope of the line. + out.Write("\tfloat2 offset;\n" + "\tfloat2 to = abs(end.pos.xy / end.pos.w - start.pos.xy / start.pos.w);\n" + // FIXME: What does real hardware do when line is at a 45-degree angle? + // FIXME: Lines aren't drawn at the correct width. See Twilight Princess map. + "\tif (" I_LINEPTPARAMS ".y * to.y > " I_LINEPTPARAMS ".x * to.x) {\n" + // Line is more tall. Extend geometry left and right. + // Lerp LineWidth/2 from [0..VpWidth] to [-1..1] + "\t\toffset = float2(" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".x, 0);\n" + "\t} else {\n" + // Line is more wide. Extend geometry up and down. + // Lerp LineWidth/2 from [0..VpHeight] to [1..-1] + "\t\toffset = float2(0, -" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\n" + "\t}\n"); + } + else if (primitive_type == PRIMITIVE_POINTS) + { + if (ApiType == API_OPENGL) + { + out.Write("\tVS_OUTPUT center;\n"); + AssignVSOutputMembers(out, "center", "vs[0]"); + } + else + { + out.Write("\tVS_OUTPUT center = o[0];\n"); + } - // Offset from center to upper right vertex - // Lerp PointSize/2 from [0,0..VpWidth,VpHeight] to [-1,1..1,-1] - out.Write("\tfloat2 offset = float2(" I_LINEPTPARAMS".w / " I_LINEPTPARAMS".x, -" I_LINEPTPARAMS".w / " I_LINEPTPARAMS".y) * center.pos.w;\n"); - } + // Offset from center to upper right vertex + // Lerp PointSize/2 from [0,0..VpWidth,VpHeight] to [-1,1..1,-1] + out.Write("\tfloat2 offset = float2(" I_LINEPTPARAMS ".w / " I_LINEPTPARAMS + ".x, -" I_LINEPTPARAMS ".w / " I_LINEPTPARAMS ".y) * center.pos.w;\n"); + } - if (g_ActiveConfig.iStereoMode > 0) - { - // If the GPU supports invocation we don't need a for loop and can simply use the - // invocation identifier to determine which layer we're rendering. - if (g_ActiveConfig.backend_info.bSupportsGSInstancing) - out.Write("\tint eye = InstanceID;\n"); - else - out.Write("\tfor (int eye = 0; eye < 2; ++eye) {\n"); - } + if (g_ActiveConfig.iStereoMode > 0) + { + // If the GPU supports invocation we don't need a for loop and can simply use the + // invocation identifier to determine which layer we're rendering. + if (g_ActiveConfig.backend_info.bSupportsGSInstancing) + out.Write("\tint eye = InstanceID;\n"); + else + out.Write("\tfor (int eye = 0; eye < 2; ++eye) {\n"); + } - if (g_ActiveConfig.bWireFrame) - out.Write("\tVS_OUTPUT first;\n"); + if (g_ActiveConfig.bWireFrame) + out.Write("\tVS_OUTPUT first;\n"); - out.Write("\tfor (int i = 0; i < %d; ++i) {\n", vertex_in); + out.Write("\tfor (int i = 0; i < %d; ++i) {\n", vertex_in); - if (ApiType == API_OPENGL) - { - out.Write("\tVS_OUTPUT f;\n"); - AssignVSOutputMembers(out, "f", "vs[i]"); - } - else - { - out.Write("\tVS_OUTPUT f = o[i];\n"); - } + if (ApiType == API_OPENGL) + { + out.Write("\tVS_OUTPUT f;\n"); + AssignVSOutputMembers(out, "f", "vs[i]"); + } + else + { + out.Write("\tVS_OUTPUT f = o[i];\n"); + } - if (g_ActiveConfig.iStereoMode > 0) - { - // Select the output layer - out.Write("\tps.layer = eye;\n"); - if (ApiType == API_OPENGL) - out.Write("\tgl_Layer = eye;\n"); + if (g_ActiveConfig.iStereoMode > 0) + { + // Select the output layer + out.Write("\tps.layer = eye;\n"); + if (ApiType == API_OPENGL) + out.Write("\tgl_Layer = eye;\n"); - // For stereoscopy add a small horizontal offset in Normalized Device Coordinates proportional - // to the depth of the vertex. We retrieve the depth value from the w-component of the projected - // vertex which contains the negated z-component of the original vertex. - // For negative parallax (out-of-screen effects) we subtract a convergence value from - // the depth value. This results in objects at a distance smaller than the convergence - // distance to seemingly appear in front of the screen. - // This formula is based on page 13 of the "Nvidia 3D Vision Automatic, Best Practices Guide" - out.Write("\tf.pos.x += " I_STEREOPARAMS"[eye] * (f.pos.w - " I_STEREOPARAMS"[2]);\n"); - } + // For stereoscopy add a small horizontal offset in Normalized Device Coordinates proportional + // to the depth of the vertex. We retrieve the depth value from the w-component of the projected + // vertex which contains the negated z-component of the original vertex. + // For negative parallax (out-of-screen effects) we subtract a convergence value from + // the depth value. This results in objects at a distance smaller than the convergence + // distance to seemingly appear in front of the screen. + // This formula is based on page 13 of the "Nvidia 3D Vision Automatic, Best Practices Guide" + out.Write("\tf.pos.x += " I_STEREOPARAMS "[eye] * (f.pos.w - " I_STEREOPARAMS "[2]);\n"); + } - if (primitive_type == PRIMITIVE_LINES) - { - out.Write("\tVS_OUTPUT l = f;\n" - "\tVS_OUTPUT r = f;\n"); + if (primitive_type == PRIMITIVE_LINES) + { + out.Write("\tVS_OUTPUT l = f;\n" + "\tVS_OUTPUT r = f;\n"); - out.Write("\tl.pos.xy -= offset * l.pos.w;\n" - "\tr.pos.xy += offset * r.pos.w;\n"); + out.Write("\tl.pos.xy -= offset * l.pos.w;\n" + "\tr.pos.xy += offset * r.pos.w;\n"); - out.Write("\tif (" I_TEXOFFSET"[2] != 0) {\n"); - out.Write("\tfloat texOffset = 1.0 / float(" I_TEXOFFSET"[2]);\n"); + out.Write("\tif (" I_TEXOFFSET "[2] != 0) {\n"); + out.Write("\tfloat texOffset = 1.0 / float(" I_TEXOFFSET "[2]);\n"); - for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) - { - out.Write("\tif (((" I_TEXOFFSET"[0] >> %d) & 0x1) != 0)\n", i); - out.Write("\t\tr.tex%d.x += texOffset;\n", i); - } - out.Write("\t}\n"); + for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) + { + out.Write("\tif (((" I_TEXOFFSET "[0] >> %d) & 0x1) != 0)\n", i); + out.Write("\t\tr.tex%d.x += texOffset;\n", i); + } + out.Write("\t}\n"); - EmitVertex(out, "l", ApiType, true); - EmitVertex(out, "r", ApiType); - } - else if (primitive_type == PRIMITIVE_POINTS) - { - out.Write("\tVS_OUTPUT ll = f;\n" - "\tVS_OUTPUT lr = f;\n" - "\tVS_OUTPUT ul = f;\n" - "\tVS_OUTPUT ur = f;\n"); + EmitVertex(out, "l", ApiType, true); + EmitVertex(out, "r", ApiType); + } + else if (primitive_type == PRIMITIVE_POINTS) + { + out.Write("\tVS_OUTPUT ll = f;\n" + "\tVS_OUTPUT lr = f;\n" + "\tVS_OUTPUT ul = f;\n" + "\tVS_OUTPUT ur = f;\n"); - out.Write("\tll.pos.xy += float2(-1,-1) * offset;\n" - "\tlr.pos.xy += float2(1,-1) * offset;\n" - "\tul.pos.xy += float2(-1,1) * offset;\n" - "\tur.pos.xy += offset;\n"); + out.Write("\tll.pos.xy += float2(-1,-1) * offset;\n" + "\tlr.pos.xy += float2(1,-1) * offset;\n" + "\tul.pos.xy += float2(-1,1) * offset;\n" + "\tur.pos.xy += offset;\n"); - out.Write("\tif (" I_TEXOFFSET"[3] != 0) {\n"); - out.Write("\tfloat2 texOffset = float2(1.0 / float(" I_TEXOFFSET"[3]), 1.0 / float(" I_TEXOFFSET"[3]));\n"); + out.Write("\tif (" I_TEXOFFSET "[3] != 0) {\n"); + out.Write("\tfloat2 texOffset = float2(1.0 / float(" I_TEXOFFSET + "[3]), 1.0 / float(" I_TEXOFFSET "[3]));\n"); - for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) - { - out.Write("\tif (((" I_TEXOFFSET"[1] >> %d) & 0x1) != 0) {\n", i); - out.Write("\t\tll.tex%d.xy += float2(0,1) * texOffset;\n", i); - out.Write("\t\tlr.tex%d.xy += texOffset;\n", i); - out.Write("\t\tur.tex%d.xy += float2(1,0) * texOffset;\n", i); - out.Write("\t}\n"); - } - out.Write("\t}\n"); + for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) + { + out.Write("\tif (((" I_TEXOFFSET "[1] >> %d) & 0x1) != 0) {\n", i); + out.Write("\t\tll.tex%d.xy += float2(0,1) * texOffset;\n", i); + out.Write("\t\tlr.tex%d.xy += texOffset;\n", i); + out.Write("\t\tur.tex%d.xy += float2(1,0) * texOffset;\n", i); + out.Write("\t}\n"); + } + out.Write("\t}\n"); - EmitVertex(out, "ll", ApiType, true); - EmitVertex(out, "lr", ApiType); - EmitVertex(out, "ul", ApiType); - EmitVertex(out, "ur", ApiType); - } - else - { - EmitVertex(out, "f", ApiType, true); - } + EmitVertex(out, "ll", ApiType, true); + EmitVertex(out, "lr", ApiType); + EmitVertex(out, "ul", ApiType); + EmitVertex(out, "ur", ApiType); + } + else + { + EmitVertex(out, "f", ApiType, true); + } - out.Write("\t}\n"); + out.Write("\t}\n"); - EndPrimitive(out, ApiType); + EndPrimitive(out, ApiType); - if (g_ActiveConfig.iStereoMode > 0 && !g_ActiveConfig.backend_info.bSupportsGSInstancing) - out.Write("\t}\n"); + if (g_ActiveConfig.iStereoMode > 0 && !g_ActiveConfig.backend_info.bSupportsGSInstancing) + out.Write("\t}\n"); - out.Write("}\n"); + out.Write("}\n"); - return out; + return out; } -template +template static void EmitVertex(T& out, const char* vertex, API_TYPE ApiType, bool first_vertex) { - if (g_ActiveConfig.bWireFrame && first_vertex) - out.Write("\tif (i == 0) first = %s;\n", vertex); + if (g_ActiveConfig.bWireFrame && first_vertex) + out.Write("\tif (i == 0) first = %s;\n", vertex); - if (ApiType == API_OPENGL) - { - out.Write("\tgl_Position = %s.pos;\n", vertex); - AssignVSOutputMembers(out, "ps", vertex); - } - else - { - out.Write("\tps.o = %s;\n", vertex); - } + if (ApiType == API_OPENGL) + { + out.Write("\tgl_Position = %s.pos;\n", vertex); + AssignVSOutputMembers(out, "ps", vertex); + } + else + { + out.Write("\tps.o = %s;\n", vertex); + } - if (ApiType == API_OPENGL) - out.Write("\tEmitVertex();\n"); - else - out.Write("\toutput.Append(ps);\n"); + if (ApiType == API_OPENGL) + out.Write("\tEmitVertex();\n"); + else + out.Write("\toutput.Append(ps);\n"); } -template +template static void EndPrimitive(T& out, API_TYPE ApiType) { - if (g_ActiveConfig.bWireFrame) - EmitVertex(out, "first", ApiType); + if (g_ActiveConfig.bWireFrame) + EmitVertex(out, "first", ApiType); - if (ApiType == API_OPENGL) - out.Write("\tEndPrimitive();\n"); - else - out.Write("\toutput.RestartStrip();\n"); + if (ApiType == API_OPENGL) + out.Write("\tEndPrimitive();\n"); + else + out.Write("\toutput.RestartStrip();\n"); } GeometryShaderUid GetGeometryShaderUid(u32 primitive_type, API_TYPE ApiType) { - return GenerateGeometryShader(primitive_type, ApiType); + return GenerateGeometryShader(primitive_type, ApiType); } ShaderCode GenerateGeometryShaderCode(u32 primitive_type, API_TYPE ApiType) { - return GenerateGeometryShader(primitive_type, ApiType); + return GenerateGeometryShader(primitive_type, ApiType); } diff --git a/Source/Core/VideoCommon/GeometryShaderGen.h b/Source/Core/VideoCommon/GeometryShaderGen.h index 5277e78774..961ab770c6 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.h +++ b/Source/Core/VideoCommon/GeometryShaderGen.h @@ -12,14 +12,17 @@ struct geometry_shader_uid_data { - u32 NumValues() const { return sizeof(geometry_shader_uid_data); } - bool IsPassthrough() const { return primitive_type == PRIMITIVE_TRIANGLES && !stereo && !wireframe; } + u32 NumValues() const { return sizeof(geometry_shader_uid_data); } + bool IsPassthrough() const + { + return primitive_type == PRIMITIVE_TRIANGLES && !stereo && !wireframe; + } - u32 stereo : 1; - u32 numTexGens : 4; - u32 pixel_lighting : 1; - u32 primitive_type : 2; - u32 wireframe : 1; + u32 stereo : 1; + u32 numTexGens : 4; + u32 pixel_lighting : 1; + u32 primitive_type : 2; + u32 wireframe : 1; }; #pragma pack() diff --git a/Source/Core/VideoCommon/GeometryShaderManager.cpp b/Source/Core/VideoCommon/GeometryShaderManager.cpp index b75a407817..533bed8ecd 100644 --- a/Source/Core/VideoCommon/GeometryShaderManager.cpp +++ b/Source/Core/VideoCommon/GeometryShaderManager.cpp @@ -11,9 +11,7 @@ #include "VideoCommon/VideoConfig.h" #include "VideoCommon/XFMemory.h" -static const int LINE_PT_TEX_OFFSETS[8] = { - 0, 16, 8, 4, 2, 1, 1, 1 -}; +static const int LINE_PT_TEX_OFFSETS[8] = {0, 16, 8, 4, 2, 1, 1, 1}; GeometryShaderConstants GeometryShaderManager::constants; bool GeometryShaderManager::dirty; @@ -23,13 +21,13 @@ static bool s_viewport_changed; void GeometryShaderManager::Init() { - memset(&constants, 0, sizeof(constants)); + memset(&constants, 0, sizeof(constants)); - // Init any intial constants which aren't zero when bpmem is zero. - SetViewportChanged(); - SetProjectionChanged(); + // Init any intial constants which aren't zero when bpmem is zero. + SetViewportChanged(); + SetProjectionChanged(); - dirty = true; + dirty = true; } void GeometryShaderManager::Shutdown() @@ -38,87 +36,89 @@ void GeometryShaderManager::Shutdown() void GeometryShaderManager::Dirty() { - // This function is called after a savestate is loaded. - // Any constants that can changed based on settings should be re-calculated - s_projection_changed = true; + // This function is called after a savestate is loaded. + // Any constants that can changed based on settings should be re-calculated + s_projection_changed = true; - dirty = true; + dirty = true; } void GeometryShaderManager::SetConstants() { - if (s_projection_changed && g_ActiveConfig.iStereoMode > 0) - { - s_projection_changed = false; + if (s_projection_changed && g_ActiveConfig.iStereoMode > 0) + { + s_projection_changed = false; - if (xfmem.projection.type == GX_PERSPECTIVE) - { - float offset = (g_ActiveConfig.iStereoDepth / 1000.0f) * (g_ActiveConfig.iStereoDepthPercentage / 100.0f); - constants.stereoparams[0] = g_ActiveConfig.bStereoSwapEyes ? offset : -offset; - constants.stereoparams[1] = g_ActiveConfig.bStereoSwapEyes ? -offset : offset; - } - else - { - constants.stereoparams[0] = constants.stereoparams[1] = 0; - } + if (xfmem.projection.type == GX_PERSPECTIVE) + { + float offset = (g_ActiveConfig.iStereoDepth / 1000.0f) * + (g_ActiveConfig.iStereoDepthPercentage / 100.0f); + constants.stereoparams[0] = g_ActiveConfig.bStereoSwapEyes ? offset : -offset; + constants.stereoparams[1] = g_ActiveConfig.bStereoSwapEyes ? -offset : offset; + } + else + { + constants.stereoparams[0] = constants.stereoparams[1] = 0; + } - constants.stereoparams[2] = (float)(g_ActiveConfig.iStereoConvergence * (g_ActiveConfig.iStereoConvergencePercentage / 100.0f)); + constants.stereoparams[2] = (float)(g_ActiveConfig.iStereoConvergence * + (g_ActiveConfig.iStereoConvergencePercentage / 100.0f)); - dirty = true; - } + dirty = true; + } - if (s_viewport_changed) - { - s_viewport_changed = false; + if (s_viewport_changed) + { + s_viewport_changed = false; - constants.lineptparams[0] = 2.0f * xfmem.viewport.wd; - constants.lineptparams[1] = -2.0f * xfmem.viewport.ht; + constants.lineptparams[0] = 2.0f * xfmem.viewport.wd; + constants.lineptparams[1] = -2.0f * xfmem.viewport.ht; - dirty = true; - } + dirty = true; + } } void GeometryShaderManager::SetViewportChanged() { - s_viewport_changed = true; + s_viewport_changed = true; } void GeometryShaderManager::SetProjectionChanged() { - s_projection_changed = true; + s_projection_changed = true; } void GeometryShaderManager::SetLinePtWidthChanged() { - constants.lineptparams[2] = bpmem.lineptwidth.linesize / 6.f; - constants.lineptparams[3] = bpmem.lineptwidth.pointsize / 6.f; - constants.texoffset[2] = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.lineoff]; - constants.texoffset[3] = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.pointoff]; - dirty = true; + constants.lineptparams[2] = bpmem.lineptwidth.linesize / 6.f; + constants.lineptparams[3] = bpmem.lineptwidth.pointsize / 6.f; + constants.texoffset[2] = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.lineoff]; + constants.texoffset[3] = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.pointoff]; + dirty = true; } void GeometryShaderManager::SetTexCoordChanged(u8 texmapid) { - TCoordInfo& tc = bpmem.texcoords[texmapid]; - int bitmask = 1 << texmapid; - constants.texoffset[0] &= ~bitmask; - constants.texoffset[0] |= tc.s.line_offset << texmapid; - constants.texoffset[1] &= ~bitmask; - constants.texoffset[1] |= tc.s.point_offset << texmapid; - dirty = true; + TCoordInfo& tc = bpmem.texcoords[texmapid]; + int bitmask = 1 << texmapid; + constants.texoffset[0] &= ~bitmask; + constants.texoffset[0] |= tc.s.line_offset << texmapid; + constants.texoffset[1] &= ~bitmask; + constants.texoffset[1] |= tc.s.point_offset << texmapid; + dirty = true; } -void GeometryShaderManager::DoState(PointerWrap &p) +void GeometryShaderManager::DoState(PointerWrap& p) { - p.Do(s_projection_changed); - p.Do(s_viewport_changed); + p.Do(s_projection_changed); + p.Do(s_viewport_changed); - p.Do(constants); + p.Do(constants); - if (p.GetMode() == PointerWrap::MODE_READ) - { - // Fixup the current state from global GPU state - // NOTE: This requires that all GPU memory has been loaded already. - Dirty(); - } + if (p.GetMode() == PointerWrap::MODE_READ) + { + // Fixup the current state from global GPU state + // NOTE: This requires that all GPU memory has been loaded already. + Dirty(); + } } diff --git a/Source/Core/VideoCommon/GeometryShaderManager.h b/Source/Core/VideoCommon/GeometryShaderManager.h index 4f80562391..878c6d72bd 100644 --- a/Source/Core/VideoCommon/GeometryShaderManager.h +++ b/Source/Core/VideoCommon/GeometryShaderManager.h @@ -13,17 +13,17 @@ class PointerWrap; class GeometryShaderManager { public: - static void Init(); - static void Dirty(); - static void Shutdown(); - static void DoState(PointerWrap &p); + static void Init(); + static void Dirty(); + static void Shutdown(); + static void DoState(PointerWrap& p); - static void SetConstants(); - static void SetViewportChanged(); - static void SetProjectionChanged(); - static void SetLinePtWidthChanged(); - static void SetTexCoordChanged(u8 texmapid); + static void SetConstants(); + static void SetViewportChanged(); + static void SetProjectionChanged(); + static void SetLinePtWidthChanged(); + static void SetTexCoordChanged(u8 texmapid); - static GeometryShaderConstants constants; - static bool dirty; + static GeometryShaderConstants constants; + static bool dirty; }; diff --git a/Source/Core/VideoCommon/HiresTextures.cpp b/Source/Core/VideoCommon/HiresTextures.cpp index 5d177a0257..400596121b 100644 --- a/Source/Core/VideoCommon/HiresTextures.cpp +++ b/Source/Core/VideoCommon/HiresTextures.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #include #include @@ -13,17 +14,16 @@ #include #include #include -#include #include "Common/FileSearch.h" #include "Common/FileUtil.h" #include "Common/Flag.h" #include "Common/Hash.h" +#include "Common/Logging/Log.h" #include "Common/MemoryUtil.h" #include "Common/StringUtil.h" #include "Common/Thread.h" #include "Common/Timer.h" -#include "Common/Logging/Log.h" #include "Core/ConfigManager.h" #include "VideoCommon/HiresTextures.h" #include "VideoCommon/OnScreenDisplay.h" @@ -32,7 +32,7 @@ static std::unordered_map s_textureMap; static std::unordered_map> s_textureCache; static std::mutex s_textureCacheMutex; -static std::mutex s_textureCacheAquireMutex; // for high priority access +static std::mutex s_textureCacheAquireMutex; // for high priority access static Common::Flag s_textureCacheAbortLoading; static bool s_check_native_format; static bool s_check_new_format; @@ -41,412 +41,442 @@ static std::thread s_prefetcher; static const std::string s_format_prefix = "tex1_"; -HiresTexture::Level::Level() - : data(nullptr, SOIL_free_image_data) +HiresTexture::Level::Level() : data(nullptr, SOIL_free_image_data) { } void HiresTexture::Init() { - s_check_native_format = false; - s_check_new_format = false; + s_check_native_format = false; + s_check_new_format = false; - Update(); + Update(); } void HiresTexture::Shutdown() { - if (s_prefetcher.joinable()) - { - s_textureCacheAbortLoading.Set(); - s_prefetcher.join(); - } + if (s_prefetcher.joinable()) + { + s_textureCacheAbortLoading.Set(); + s_prefetcher.join(); + } - s_textureMap.clear(); - s_textureCache.clear(); + s_textureMap.clear(); + s_textureCache.clear(); } void HiresTexture::Update() { - if (s_prefetcher.joinable()) - { - s_textureCacheAbortLoading.Set(); - s_prefetcher.join(); - } + if (s_prefetcher.joinable()) + { + s_textureCacheAbortLoading.Set(); + s_prefetcher.join(); + } - if (!g_ActiveConfig.bHiresTextures) - { - s_textureMap.clear(); - s_textureCache.clear(); - return; - } + if (!g_ActiveConfig.bHiresTextures) + { + s_textureMap.clear(); + s_textureCache.clear(); + return; + } - if (!g_ActiveConfig.bCacheHiresTextures) - { - s_textureCache.clear(); - } + if (!g_ActiveConfig.bCacheHiresTextures) + { + s_textureCache.clear(); + } - const std::string& game_id = SConfig::GetInstance().m_strUniqueID; - const std::string texture_directory = GetTextureDirectory(game_id); - std::vector extensions { - ".png", - ".bmp", - ".tga", - ".dds", - ".jpg" // Why not? Could be useful for large photo-like textures - }; + const std::string& game_id = SConfig::GetInstance().m_strUniqueID; + const std::string texture_directory = GetTextureDirectory(game_id); + std::vector extensions{ + ".png", ".bmp", ".tga", ".dds", + ".jpg" // Why not? Could be useful for large photo-like textures + }; - std::vector filenames = DoFileSearch(extensions, {texture_directory}, /*recursive*/ true); + std::vector filenames = + DoFileSearch(extensions, {texture_directory}, /*recursive*/ true); - const std::string code = game_id + "_"; + const std::string code = game_id + "_"; - for (auto& rFilename : filenames) - { - std::string FileName; - SplitPath(rFilename, nullptr, &FileName, nullptr); + for (auto& rFilename : filenames) + { + std::string FileName; + SplitPath(rFilename, nullptr, &FileName, nullptr); - if (FileName.substr(0, code.length()) == code) - { - s_textureMap[FileName] = rFilename; - s_check_native_format = true; - } + if (FileName.substr(0, code.length()) == code) + { + s_textureMap[FileName] = rFilename; + s_check_native_format = true; + } - if (FileName.substr(0, s_format_prefix.length()) == s_format_prefix) - { - s_textureMap[FileName] = rFilename; - s_check_new_format = true; - } - } + if (FileName.substr(0, s_format_prefix.length()) == s_format_prefix) + { + s_textureMap[FileName] = rFilename; + s_check_new_format = true; + } + } - if (g_ActiveConfig.bCacheHiresTextures) - { - // remove cached but deleted textures - auto iter = s_textureCache.begin(); - while (iter != s_textureCache.end()) - { - if (s_textureMap.find(iter->first) == s_textureMap.end()) - { - iter = s_textureCache.erase(iter); - } - else - { - iter++; - } - } + if (g_ActiveConfig.bCacheHiresTextures) + { + // remove cached but deleted textures + auto iter = s_textureCache.begin(); + while (iter != s_textureCache.end()) + { + if (s_textureMap.find(iter->first) == s_textureMap.end()) + { + iter = s_textureCache.erase(iter); + } + else + { + iter++; + } + } - s_textureCacheAbortLoading.Clear(); - s_prefetcher = std::thread(Prefetch); - } + s_textureCacheAbortLoading.Clear(); + s_prefetcher = std::thread(Prefetch); + } } void HiresTexture::Prefetch() { - Common::SetCurrentThreadName("Prefetcher"); + Common::SetCurrentThreadName("Prefetcher"); - size_t size_sum = 0; - size_t sys_mem = MemPhysical(); - size_t recommended_min_mem = 2 * size_t(1024 * 1024 * 1024); - // keep 2GB memory for system stability if system RAM is 4GB+ - use half of memory in other cases - size_t max_mem = (sys_mem / 2 < recommended_min_mem) ? (sys_mem / 2) : (sys_mem - recommended_min_mem); - u32 starttime = Common::Timer::GetTimeMs(); - for (const auto& entry : s_textureMap) - { - const std::string& base_filename = entry.first; + size_t size_sum = 0; + size_t sys_mem = MemPhysical(); + size_t recommended_min_mem = 2 * size_t(1024 * 1024 * 1024); + // keep 2GB memory for system stability if system RAM is 4GB+ - use half of memory in other cases + size_t max_mem = + (sys_mem / 2 < recommended_min_mem) ? (sys_mem / 2) : (sys_mem - recommended_min_mem); + u32 starttime = Common::Timer::GetTimeMs(); + for (const auto& entry : s_textureMap) + { + const std::string& base_filename = entry.first; - if (base_filename.find("_mip") == std::string::npos) - { - { - // try to get this mutex first, so the video thread is allow to get the real mutex faster - std::unique_lock lk(s_textureCacheAquireMutex); - } - std::unique_lock lk(s_textureCacheMutex); + if (base_filename.find("_mip") == std::string::npos) + { + { + // try to get this mutex first, so the video thread is allow to get the real mutex faster + std::unique_lock lk(s_textureCacheAquireMutex); + } + std::unique_lock lk(s_textureCacheMutex); - auto iter = s_textureCache.find(base_filename); - if (iter == s_textureCache.end()) - { - // unlock while loading a texture. This may result in a race condition where we'll load a texture twice, - // but it reduces the stuttering a lot. Notice: The loading library _must_ be thread safe now. - // But bad luck, SOIL isn't, so TODO: remove SOIL usage here and use libpng directly - // Also TODO: remove s_textureCacheAquireMutex afterwards. It won't be needed as the main mutex will be locked rarely - //lk.unlock(); - std::unique_ptr texture = Load(base_filename, 0, 0); - //lk.lock(); - if (texture) - { - std::shared_ptr ptr(std::move(texture)); - iter = s_textureCache.insert(iter, std::make_pair(base_filename, ptr)); - } - } - if (iter != s_textureCache.end()) - { - for (const Level& l : iter->second->m_levels) - { - size_sum += l.data_size; - } - } - } + auto iter = s_textureCache.find(base_filename); + if (iter == s_textureCache.end()) + { + // unlock while loading a texture. This may result in a race condition where we'll load a + // texture twice, + // but it reduces the stuttering a lot. Notice: The loading library _must_ be thread safe + // now. + // But bad luck, SOIL isn't, so TODO: remove SOIL usage here and use libpng directly + // Also TODO: remove s_textureCacheAquireMutex afterwards. It won't be needed as the main + // mutex will be locked rarely + // lk.unlock(); + std::unique_ptr texture = Load(base_filename, 0, 0); + // lk.lock(); + if (texture) + { + std::shared_ptr ptr(std::move(texture)); + iter = s_textureCache.insert(iter, std::make_pair(base_filename, ptr)); + } + } + if (iter != s_textureCache.end()) + { + for (const Level& l : iter->second->m_levels) + { + size_sum += l.data_size; + } + } + } - if (s_textureCacheAbortLoading.IsSet()) - { - return; - } + if (s_textureCacheAbortLoading.IsSet()) + { + return; + } - if (size_sum > max_mem) - { - g_Config.bCacheHiresTextures = false; + if (size_sum > max_mem) + { + g_Config.bCacheHiresTextures = false; - OSD::AddMessage(StringFromFormat("Custom Textures prefetching after %.1f MB aborted, not enough RAM available", size_sum / (1024.0 * 1024.0)), 10000); - return; - } - } - u32 stoptime = Common::Timer::GetTimeMs(); - OSD::AddMessage(StringFromFormat("Custom Textures loaded, %.1f MB in %.1f s", size_sum / (1024.0 * 1024.0), (stoptime - starttime) / 1000.0), 10000); + OSD::AddMessage( + StringFromFormat( + "Custom Textures prefetching after %.1f MB aborted, not enough RAM available", + size_sum / (1024.0 * 1024.0)), + 10000); + return; + } + } + u32 stoptime = Common::Timer::GetTimeMs(); + OSD::AddMessage(StringFromFormat("Custom Textures loaded, %.1f MB in %.1f s", + size_sum / (1024.0 * 1024.0), (stoptime - starttime) / 1000.0), + 10000); } -std::string HiresTexture::GenBaseName(const u8* texture, size_t texture_size, const u8* tlut, size_t tlut_size, u32 width, u32 height, int format, bool has_mipmaps, bool dump) +std::string HiresTexture::GenBaseName(const u8* texture, size_t texture_size, const u8* tlut, + size_t tlut_size, u32 width, u32 height, int format, + bool has_mipmaps, bool dump) { - std::string name = ""; - bool convert = false; - if (!dump && s_check_native_format) - { - // try to load the old format first - u64 tex_hash = GetHashHiresTexture(texture, (int)texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples); - u64 tlut_hash = tlut_size ? GetHashHiresTexture(tlut, (int)tlut_size, g_ActiveConfig.iSafeTextureCache_ColorSamples) : 0; - name = StringFromFormat("%s_%08x_%i", SConfig::GetInstance().m_strUniqueID.c_str(), (u32)(tex_hash ^ tlut_hash), (u16)format); - if (s_textureMap.find(name) != s_textureMap.end()) - { - if (g_ActiveConfig.bConvertHiresTextures) - convert = true; - else - return name; - } - } + std::string name = ""; + bool convert = false; + if (!dump && s_check_native_format) + { + // try to load the old format first + u64 tex_hash = GetHashHiresTexture(texture, (int)texture_size, + g_ActiveConfig.iSafeTextureCache_ColorSamples); + u64 tlut_hash = tlut_size ? GetHashHiresTexture(tlut, (int)tlut_size, + g_ActiveConfig.iSafeTextureCache_ColorSamples) : + 0; + name = StringFromFormat("%s_%08x_%i", SConfig::GetInstance().m_strUniqueID.c_str(), + (u32)(tex_hash ^ tlut_hash), (u16)format); + if (s_textureMap.find(name) != s_textureMap.end()) + { + if (g_ActiveConfig.bConvertHiresTextures) + convert = true; + else + return name; + } + } - if (dump || s_check_new_format || convert) - { - // checking for min/max on paletted textures - u32 min = 0xffff; - u32 max = 0; - switch(tlut_size) - { - case 0: break; - case 16 * 2: - for (size_t i = 0; i < texture_size; i++) - { - min = std::min(min, texture[i] & 0xf); - min = std::min(min, texture[i] >> 4); - max = std::max(max, texture[i] & 0xf); - max = std::max(max, texture[i] >> 4); - } - break; - case 256 * 2: - for (size_t i = 0; i < texture_size; i++) - { - min = std::min(min, texture[i]); - max = std::max(max, texture[i]); - } - break; - case 16384 * 2: - for (size_t i = 0; i < texture_size/2; i++) - { - min = std::min(min, Common::swap16(((u16*)texture)[i]) & 0x3fff); - max = std::max(max, Common::swap16(((u16*)texture)[i]) & 0x3fff); - } - break; - } - if (tlut_size > 0) - { - tlut_size = 2 * (max + 1 - min); - tlut += 2 * min; - } + if (dump || s_check_new_format || convert) + { + // checking for min/max on paletted textures + u32 min = 0xffff; + u32 max = 0; + switch (tlut_size) + { + case 0: + break; + case 16 * 2: + for (size_t i = 0; i < texture_size; i++) + { + min = std::min(min, texture[i] & 0xf); + min = std::min(min, texture[i] >> 4); + max = std::max(max, texture[i] & 0xf); + max = std::max(max, texture[i] >> 4); + } + break; + case 256 * 2: + for (size_t i = 0; i < texture_size; i++) + { + min = std::min(min, texture[i]); + max = std::max(max, texture[i]); + } + break; + case 16384 * 2: + for (size_t i = 0; i < texture_size / 2; i++) + { + min = std::min(min, Common::swap16(((u16*)texture)[i]) & 0x3fff); + max = std::max(max, Common::swap16(((u16*)texture)[i]) & 0x3fff); + } + break; + } + if (tlut_size > 0) + { + tlut_size = 2 * (max + 1 - min); + tlut += 2 * min; + } - u64 tex_hash = XXH64(texture, texture_size, 0); - u64 tlut_hash = tlut_size ? XXH64(tlut, tlut_size, 0) : 0; + u64 tex_hash = XXH64(texture, texture_size, 0); + u64 tlut_hash = tlut_size ? XXH64(tlut, tlut_size, 0) : 0; - std::string basename = s_format_prefix + StringFromFormat("%dx%d%s_%016" PRIx64, width, height, has_mipmaps ? "_m" : "", tex_hash); - std::string tlutname = tlut_size ? StringFromFormat("_%016" PRIx64, tlut_hash) : ""; - std::string formatname = StringFromFormat("_%d", format); - std::string fullname = basename + tlutname + formatname; + std::string basename = s_format_prefix + StringFromFormat("%dx%d%s_%016" PRIx64, width, height, + has_mipmaps ? "_m" : "", tex_hash); + std::string tlutname = tlut_size ? StringFromFormat("_%016" PRIx64, tlut_hash) : ""; + std::string formatname = StringFromFormat("_%d", format); + std::string fullname = basename + tlutname + formatname; - for (int level = 0; level < 10 && convert; level++) - { - std::string oldname = name; - if (level) - oldname += StringFromFormat("_mip%d", level); + for (int level = 0; level < 10 && convert; level++) + { + std::string oldname = name; + if (level) + oldname += StringFromFormat("_mip%d", level); - // skip not existing levels - if (s_textureMap.find(oldname) == s_textureMap.end()) - continue; + // skip not existing levels + if (s_textureMap.find(oldname) == s_textureMap.end()) + continue; - for (int i = 0;; i++) - { - // for hash collisions, padd with an integer - std::string newname = fullname; - if (level) - newname += StringFromFormat("_mip%d", level); - if (i) - newname += StringFromFormat(".%d", i); + for (int i = 0;; i++) + { + // for hash collisions, padd with an integer + std::string newname = fullname; + if (level) + newname += StringFromFormat("_mip%d", level); + if (i) + newname += StringFromFormat(".%d", i); - // new texture - if (s_textureMap.find(newname) == s_textureMap.end()) - { - std::string src = s_textureMap[oldname]; - size_t postfix = src.find_last_of('.'); - std::string dst = src.substr(0, postfix - oldname.length()) + newname + src.substr(postfix, src.length() - postfix); - if (File::Rename(src, dst)) - { - s_textureMap.erase(oldname); - s_textureMap[newname] = dst; - s_check_new_format = true; - OSD::AddMessage(StringFromFormat("Rename custom texture %s to %s", oldname.c_str(), newname.c_str()), 5000); - } - else - { - ERROR_LOG(VIDEO, "rename failed"); - } - break; - } - else - { - // dst fail already exist, compare content - std::string a, b; - File::ReadFileToString(s_textureMap[oldname], a); - File::ReadFileToString(s_textureMap[newname], b); + // new texture + if (s_textureMap.find(newname) == s_textureMap.end()) + { + std::string src = s_textureMap[oldname]; + size_t postfix = src.find_last_of('.'); + std::string dst = src.substr(0, postfix - oldname.length()) + newname + + src.substr(postfix, src.length() - postfix); + if (File::Rename(src, dst)) + { + s_textureMap.erase(oldname); + s_textureMap[newname] = dst; + s_check_new_format = true; + OSD::AddMessage(StringFromFormat("Rename custom texture %s to %s", oldname.c_str(), + newname.c_str()), + 5000); + } + else + { + ERROR_LOG(VIDEO, "rename failed"); + } + break; + } + else + { + // dst fail already exist, compare content + std::string a, b; + File::ReadFileToString(s_textureMap[oldname], a); + File::ReadFileToString(s_textureMap[newname], b); - if (a == b && a != "") - { - // equal, so remove - if (File::Delete(s_textureMap[oldname])) - { - s_textureMap.erase(oldname); - OSD::AddMessage(StringFromFormat("Delete double old custom texture %s", oldname.c_str()), 5000); - } - else - { - ERROR_LOG(VIDEO, "delete failed"); - } - break; - } + if (a == b && a != "") + { + // equal, so remove + if (File::Delete(s_textureMap[oldname])) + { + s_textureMap.erase(oldname); + OSD::AddMessage( + StringFromFormat("Delete double old custom texture %s", oldname.c_str()), 5000); + } + else + { + ERROR_LOG(VIDEO, "delete failed"); + } + break; + } - // else continue in this loop with the next higher padding variable - } - } - } + // else continue in this loop with the next higher padding variable + } + } + } - // try to match a wildcard template - if (!dump && s_textureMap.find(basename + "_*" + formatname) != s_textureMap.end()) - return basename + "_*" + formatname; + // try to match a wildcard template + if (!dump && s_textureMap.find(basename + "_*" + formatname) != s_textureMap.end()) + return basename + "_*" + formatname; - // else generate the complete texture - if (dump || s_textureMap.find(fullname) != s_textureMap.end()) - return fullname; - } + // else generate the complete texture + if (dump || s_textureMap.find(fullname) != s_textureMap.end()) + return fullname; + } - return name; + return name; } -std::shared_ptr HiresTexture::Search(const u8* texture, size_t texture_size, const u8* tlut, size_t tlut_size, u32 width, u32 height, int format, bool has_mipmaps) +std::shared_ptr HiresTexture::Search(const u8* texture, size_t texture_size, + const u8* tlut, size_t tlut_size, u32 width, + u32 height, int format, bool has_mipmaps) { - std::string base_filename = GenBaseName(texture, texture_size, tlut, tlut_size, width, height, format, has_mipmaps); + std::string base_filename = + GenBaseName(texture, texture_size, tlut, tlut_size, width, height, format, has_mipmaps); - std::lock_guard lk2(s_textureCacheAquireMutex); - std::lock_guard lk(s_textureCacheMutex); + std::lock_guard lk2(s_textureCacheAquireMutex); + std::lock_guard lk(s_textureCacheMutex); - auto iter = s_textureCache.find(base_filename); - if (iter != s_textureCache.end()) - { - return iter->second; - } + auto iter = s_textureCache.find(base_filename); + if (iter != s_textureCache.end()) + { + return iter->second; + } - std::shared_ptr ptr(Load(base_filename, width, height)); + std::shared_ptr ptr(Load(base_filename, width, height)); - if (ptr && g_ActiveConfig.bCacheHiresTextures) - { - s_textureCache[base_filename] = ptr; - } + if (ptr && g_ActiveConfig.bCacheHiresTextures) + { + s_textureCache[base_filename] = ptr; + } - return ptr; + return ptr; } -std::unique_ptr HiresTexture::Load(const std::string& base_filename, u32 width, u32 height) +std::unique_ptr HiresTexture::Load(const std::string& base_filename, u32 width, + u32 height) { - std::unique_ptr ret; - for (int level = 0;; level++) - { - std::string filename = base_filename; - if (level) - { - filename += StringFromFormat("_mip%u", level); - } + std::unique_ptr ret; + for (int level = 0;; level++) + { + std::string filename = base_filename; + if (level) + { + filename += StringFromFormat("_mip%u", level); + } - if (s_textureMap.find(filename) != s_textureMap.end()) - { - Level l; + if (s_textureMap.find(filename) != s_textureMap.end()) + { + Level l; - File::IOFile file; - file.Open(s_textureMap[filename], "rb"); - std::vector buffer(file.GetSize()); - file.ReadBytes(buffer.data(), file.GetSize()); + File::IOFile file; + file.Open(s_textureMap[filename], "rb"); + std::vector buffer(file.GetSize()); + file.ReadBytes(buffer.data(), file.GetSize()); - int channels; - l.data = SOILPointer(SOIL_load_image_from_memory(buffer.data(), (int)buffer.size(), (int*)&l.width, (int*)&l.height, &channels, SOIL_LOAD_RGBA), SOIL_free_image_data); - l.data_size = (size_t)l.width * l.height * 4; + int channels; + l.data = + SOILPointer(SOIL_load_image_from_memory(buffer.data(), (int)buffer.size(), (int*)&l.width, + (int*)&l.height, &channels, SOIL_LOAD_RGBA), + SOIL_free_image_data); + l.data_size = (size_t)l.width * l.height * 4; - if (l.data == nullptr) - { - ERROR_LOG(VIDEO, "Custom texture %s failed to load", filename.c_str()); - break; - } + if (l.data == nullptr) + { + ERROR_LOG(VIDEO, "Custom texture %s failed to load", filename.c_str()); + break; + } - if (!level) - { - if (l.width * height != l.height * width) - ERROR_LOG(VIDEO, "Invalid custom texture size %dx%d for texture %s. The aspect differs from the native size %dx%d.", - l.width, l.height, filename.c_str(), width, height); - if (width && height && (l.width % width || l.height % height)) - WARN_LOG(VIDEO, "Invalid custom texture size %dx%d for texture %s. Please use an integer upscaling factor based on the native size %dx%d.", - l.width, l.height, filename.c_str(), width, height); - width = l.width; - height = l.height; - } - else if (width != l.width || height != l.height) - { - ERROR_LOG(VIDEO, "Invalid custom texture size %dx%d for texture %s. This mipmap layer _must_ be %dx%d.", - l.width, l.height, filename.c_str(), width, height); - l.data.reset(); - break; - } + if (!level) + { + if (l.width * height != l.height * width) + ERROR_LOG(VIDEO, "Invalid custom texture size %dx%d for texture %s. The aspect differs " + "from the native size %dx%d.", + l.width, l.height, filename.c_str(), width, height); + if (width && height && (l.width % width || l.height % height)) + WARN_LOG(VIDEO, "Invalid custom texture size %dx%d for texture %s. Please use an integer " + "upscaling factor based on the native size %dx%d.", + l.width, l.height, filename.c_str(), width, height); + width = l.width; + height = l.height; + } + else if (width != l.width || height != l.height) + { + ERROR_LOG( + VIDEO, + "Invalid custom texture size %dx%d for texture %s. This mipmap layer _must_ be %dx%d.", + l.width, l.height, filename.c_str(), width, height); + l.data.reset(); + break; + } - if (!ret) - ret = std::unique_ptr(new HiresTexture); - ret->m_levels.push_back(std::move(l)); + if (!ret) + ret = std::unique_ptr(new HiresTexture); + ret->m_levels.push_back(std::move(l)); - // no more mipmaps available - if (width == 1 && height == 1) - break; + // no more mipmaps available + if (width == 1 && height == 1) + break; - // calculate the size of the next mipmap - width = std::max(1u, width >> 1); - height = std::max(1u, height >> 1); - } - else - { - break; - } - } + // calculate the size of the next mipmap + width = std::max(1u, width >> 1); + height = std::max(1u, height >> 1); + } + else + { + break; + } + } - return ret; + return ret; } std::string HiresTexture::GetTextureDirectory(const std::string& game_id) { - const std::string texture_directory = File::GetUserPath(D_HIRESTEXTURES_IDX) + game_id; + const std::string texture_directory = File::GetUserPath(D_HIRESTEXTURES_IDX) + game_id; - // If there's no directory with the region-specific ID, look for a 3-character region-free one - if (!File::Exists(texture_directory)) - return File::GetUserPath(D_HIRESTEXTURES_IDX) + game_id.substr(0, 3); + // If there's no directory with the region-specific ID, look for a 3-character region-free one + if (!File::Exists(texture_directory)) + return File::GetUserPath(D_HIRESTEXTURES_IDX) + game_id.substr(0, 3); - return texture_directory; + return texture_directory; } HiresTexture::~HiresTexture() diff --git a/Source/Core/VideoCommon/HiresTextures.h b/Source/Core/VideoCommon/HiresTextures.h index be5b14bc59..b9ddc3d793 100644 --- a/Source/Core/VideoCommon/HiresTextures.h +++ b/Source/Core/VideoCommon/HiresTextures.h @@ -13,46 +13,39 @@ class HiresTexture { public: - using SOILPointer = std::unique_ptr; + using SOILPointer = std::unique_ptr; - static void Init(); - static void Update(); - static void Shutdown(); + static void Init(); + static void Update(); + static void Shutdown(); - static std::shared_ptr Search( - const u8* texture, size_t texture_size, - const u8* tlut, size_t tlut_size, - u32 width, u32 height, - int format, bool has_mipmaps - ); + static std::shared_ptr Search(const u8* texture, size_t texture_size, + const u8* tlut, size_t tlut_size, u32 width, + u32 height, int format, bool has_mipmaps); - static std::string GenBaseName( - const u8* texture, size_t texture_size, - const u8* tlut, size_t tlut_size, - u32 width, u32 height, - int format, bool has_mipmaps, - bool dump = false - ); + static std::string GenBaseName(const u8* texture, size_t texture_size, const u8* tlut, + size_t tlut_size, u32 width, u32 height, int format, + bool has_mipmaps, bool dump = false); - ~HiresTexture(); + ~HiresTexture(); - struct Level - { - Level(); + struct Level + { + Level(); - SOILPointer data; - size_t data_size = 0; - u32 width = 0; - u32 height = 0; - }; - std::vector m_levels; + SOILPointer data; + size_t data_size = 0; + u32 width = 0; + u32 height = 0; + }; + std::vector m_levels; private: - static std::unique_ptr Load(const std::string& base_filename, u32 width, u32 height); - static void Prefetch(); + static std::unique_ptr Load(const std::string& base_filename, u32 width, + u32 height); + static void Prefetch(); - static std::string GetTextureDirectory(const std::string& game_id); - - HiresTexture() {} + static std::string GetTextureDirectory(const std::string& game_id); + HiresTexture() {} }; diff --git a/Source/Core/VideoCommon/ImageWrite.cpp b/Source/Core/VideoCommon/ImageWrite.cpp index 26cade5a21..c05fb9eef7 100644 --- a/Source/Core/VideoCommon/ImageWrite.cpp +++ b/Source/Core/VideoCommon/ImageWrite.cpp @@ -5,22 +5,21 @@ #include #include -#include "png.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/MsgHandler.h" #include "VideoCommon/ImageWrite.h" +#include "png.h" bool SaveData(const std::string& filename, const std::string& data) { - std::ofstream f; - OpenFStream(f, filename, std::ios::binary); - f << data; + std::ofstream f; + OpenFStream(f, filename, std::ios::binary); + f << data; - return true; + return true; } - /* TextureToPng @@ -28,86 +27,89 @@ Inputs: data : This is an array of RGBA with 8 bits per channel. 4 bytes for each pixel. row_stride: Determines the amount of bytes per row of pixels. */ -bool TextureToPng(u8* data, int row_stride, const std::string& filename, int width, int height, bool saveAlpha) +bool TextureToPng(u8* data, int row_stride, const std::string& filename, int width, int height, + bool saveAlpha) { - bool success = false; + bool success = false; - if (!data) - return false; + if (!data) + return false; - char title[] = "Dolphin Screenshot"; - char title_key[] = "Title"; - png_structp png_ptr = nullptr; - png_infop info_ptr = nullptr; + char title[] = "Dolphin Screenshot"; + char title_key[] = "Title"; + png_structp png_ptr = nullptr; + png_infop info_ptr = nullptr; - // Open file for writing (binary mode) - File::IOFile fp(filename, "wb"); - if (!fp.IsOpen()) - { - PanicAlertT("Screenshot failed: Could not open file \"%s\" (error %d)", filename.c_str(), errno); - goto finalise; - } + // Open file for writing (binary mode) + File::IOFile fp(filename, "wb"); + if (!fp.IsOpen()) + { + PanicAlertT("Screenshot failed: Could not open file \"%s\" (error %d)", filename.c_str(), + errno); + goto finalise; + } - // Initialize write structure - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - if (png_ptr == nullptr) - { - PanicAlert("Screenshot failed: Could not allocate write struct"); - goto finalise; - } + // Initialize write structure + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (png_ptr == nullptr) + { + PanicAlert("Screenshot failed: Could not allocate write struct"); + goto finalise; + } - // Initialize info structure - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == nullptr) - { - PanicAlert("Screenshot failed: Could not allocate info struct"); - goto finalise; - } + // Initialize info structure + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == nullptr) + { + PanicAlert("Screenshot failed: Could not allocate info struct"); + goto finalise; + } - // Setup Exception handling - if (setjmp(png_jmpbuf(png_ptr))) - { - PanicAlert("Screenshot failed: Error during PNG creation"); - goto finalise; - } + // Setup Exception handling + if (setjmp(png_jmpbuf(png_ptr))) + { + PanicAlert("Screenshot failed: Error during PNG creation"); + goto finalise; + } - png_init_io(png_ptr, fp.GetHandle()); + png_init_io(png_ptr, fp.GetHandle()); - // Write header (8 bit color depth) - png_set_IHDR(png_ptr, info_ptr, width, height, - 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + // Write header (8 bit color depth) + png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - png_text title_text; - title_text.compression = PNG_TEXT_COMPRESSION_NONE; - title_text.key = title_key; - title_text.text = title; - png_set_text(png_ptr, info_ptr, &title_text, 1); + png_text title_text; + title_text.compression = PNG_TEXT_COMPRESSION_NONE; + title_text.key = title_key; + title_text.text = title; + png_set_text(png_ptr, info_ptr, &title_text, 1); - png_write_info(png_ptr, info_ptr); + png_write_info(png_ptr, info_ptr); - // Write image data - for (auto y = 0; y < height; ++y) - { - u8* row_ptr = (u8*)data + y * row_stride; - u8* ptr = row_ptr; - for (auto x = 0; x < row_stride / 4; ++x) - { - if (!saveAlpha) - ptr[3] = 0xff; - ptr += 4; - } - png_write_row(png_ptr, row_ptr); - } + // Write image data + for (auto y = 0; y < height; ++y) + { + u8* row_ptr = (u8*)data + y * row_stride; + u8* ptr = row_ptr; + for (auto x = 0; x < row_stride / 4; ++x) + { + if (!saveAlpha) + ptr[3] = 0xff; + ptr += 4; + } + png_write_row(png_ptr, row_ptr); + } - // End write - png_write_end(png_ptr, nullptr); + // End write + png_write_end(png_ptr, nullptr); - success = true; + success = true; finalise: - if (info_ptr != nullptr) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); - if (png_ptr != nullptr) png_destroy_write_struct(&png_ptr, (png_infopp)nullptr); + if (info_ptr != nullptr) + png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); + if (png_ptr != nullptr) + png_destroy_write_struct(&png_ptr, (png_infopp) nullptr); - return success; + return success; } diff --git a/Source/Core/VideoCommon/ImageWrite.h b/Source/Core/VideoCommon/ImageWrite.h index 880d99e431..2a28ff9aad 100644 --- a/Source/Core/VideoCommon/ImageWrite.h +++ b/Source/Core/VideoCommon/ImageWrite.h @@ -8,4 +8,5 @@ #include "Common/CommonTypes.h" bool SaveData(const std::string& filename, const std::string& data); -bool TextureToPng(u8* data, int row_stride, const std::string& filename, int width, int height, bool saveAlpha = true); +bool TextureToPng(u8* data, int row_stride, const std::string& filename, int width, int height, + bool saveAlpha = true); diff --git a/Source/Core/VideoCommon/IndexGenerator.cpp b/Source/Core/VideoCommon/IndexGenerator.cpp index 2f25c97640..c2c85ca857 100644 --- a/Source/Core/VideoCommon/IndexGenerator.cpp +++ b/Source/Core/VideoCommon/IndexGenerator.cpp @@ -11,9 +11,9 @@ #include "VideoCommon/OpcodeDecoding.h" #include "VideoCommon/VideoConfig.h" -//Init -u16 *IndexGenerator::index_buffer_current; -u16 *IndexGenerator::BASEIptr; +// Init +u16* IndexGenerator::index_buffer_current; +u16* IndexGenerator::BASEIptr; u32 IndexGenerator::base_index; static const u16 s_primitive_restart = -1; @@ -22,85 +22,84 @@ static u16* (*primitive_table[8])(u16*, u32, u32); void IndexGenerator::Init() { - if (g_Config.backend_info.bSupportsPrimitiveRestart) - { - primitive_table[GX_DRAW_QUADS] = IndexGenerator::AddQuads; - primitive_table[GX_DRAW_QUADS_2] = IndexGenerator::AddQuads_nonstandard; - primitive_table[GX_DRAW_TRIANGLES] = IndexGenerator::AddList; - primitive_table[GX_DRAW_TRIANGLE_STRIP] = IndexGenerator::AddStrip; - primitive_table[GX_DRAW_TRIANGLE_FAN] = IndexGenerator::AddFan; - } - else - { - primitive_table[GX_DRAW_QUADS] = IndexGenerator::AddQuads; - primitive_table[GX_DRAW_QUADS_2] = IndexGenerator::AddQuads_nonstandard; - primitive_table[GX_DRAW_TRIANGLES] = IndexGenerator::AddList; - primitive_table[GX_DRAW_TRIANGLE_STRIP] = IndexGenerator::AddStrip; - primitive_table[GX_DRAW_TRIANGLE_FAN] = IndexGenerator::AddFan; - } - primitive_table[GX_DRAW_LINES] = &IndexGenerator::AddLineList; - primitive_table[GX_DRAW_LINE_STRIP] = &IndexGenerator::AddLineStrip; - primitive_table[GX_DRAW_POINTS] = &IndexGenerator::AddPoints; + if (g_Config.backend_info.bSupportsPrimitiveRestart) + { + primitive_table[GX_DRAW_QUADS] = IndexGenerator::AddQuads; + primitive_table[GX_DRAW_QUADS_2] = IndexGenerator::AddQuads_nonstandard; + primitive_table[GX_DRAW_TRIANGLES] = IndexGenerator::AddList; + primitive_table[GX_DRAW_TRIANGLE_STRIP] = IndexGenerator::AddStrip; + primitive_table[GX_DRAW_TRIANGLE_FAN] = IndexGenerator::AddFan; + } + else + { + primitive_table[GX_DRAW_QUADS] = IndexGenerator::AddQuads; + primitive_table[GX_DRAW_QUADS_2] = IndexGenerator::AddQuads_nonstandard; + primitive_table[GX_DRAW_TRIANGLES] = IndexGenerator::AddList; + primitive_table[GX_DRAW_TRIANGLE_STRIP] = IndexGenerator::AddStrip; + primitive_table[GX_DRAW_TRIANGLE_FAN] = IndexGenerator::AddFan; + } + primitive_table[GX_DRAW_LINES] = &IndexGenerator::AddLineList; + primitive_table[GX_DRAW_LINE_STRIP] = &IndexGenerator::AddLineStrip; + primitive_table[GX_DRAW_POINTS] = &IndexGenerator::AddPoints; } void IndexGenerator::Start(u16* Indexptr) { - index_buffer_current = Indexptr; - BASEIptr = Indexptr; - base_index = 0; + index_buffer_current = Indexptr; + BASEIptr = Indexptr; + base_index = 0; } void IndexGenerator::AddIndices(int primitive, u32 numVerts) { - index_buffer_current = primitive_table[primitive](index_buffer_current, numVerts, base_index); - base_index += numVerts; + index_buffer_current = primitive_table[primitive](index_buffer_current, numVerts, base_index); + base_index += numVerts; } // Triangles -template __forceinline u16* IndexGenerator::WriteTriangle(u16 *Iptr, u32 index1, u32 index2, u32 index3) +template +__forceinline u16* IndexGenerator::WriteTriangle(u16* Iptr, u32 index1, u32 index2, u32 index3) { - *Iptr++ = index1; - *Iptr++ = index2; - *Iptr++ = index3; - if (pr) - *Iptr++ = s_primitive_restart; - return Iptr; + *Iptr++ = index1; + *Iptr++ = index2; + *Iptr++ = index3; + if (pr) + *Iptr++ = s_primitive_restart; + return Iptr; } -template u16* IndexGenerator::AddList(u16 *Iptr, u32 const numVerts, u32 index) +template +u16* IndexGenerator::AddList(u16* Iptr, u32 const numVerts, u32 index) { - for (u32 i = 2; i < numVerts; i+=3) - { - Iptr = WriteTriangle(Iptr, index + i - 2, index + i - 1, index + i); - } - return Iptr; + for (u32 i = 2; i < numVerts; i += 3) + { + Iptr = WriteTriangle(Iptr, index + i - 2, index + i - 1, index + i); + } + return Iptr; } -template u16* IndexGenerator::AddStrip(u16 *Iptr, u32 const numVerts, u32 index) +template +u16* IndexGenerator::AddStrip(u16* Iptr, u32 const numVerts, u32 index) { - if (pr) - { - for (u32 i = 0; i < numVerts; ++i) - { - *Iptr++ = index + i; - } - *Iptr++ = s_primitive_restart; + if (pr) + { + for (u32 i = 0; i < numVerts; ++i) + { + *Iptr++ = index + i; + } + *Iptr++ = s_primitive_restart; + } + else + { + bool wind = false; + for (u32 i = 2; i < numVerts; ++i) + { + Iptr = WriteTriangle(Iptr, index + i - 2, index + i - !wind, index + i - wind); - } - else - { - bool wind = false; - for (u32 i = 2; i < numVerts; ++i) - { - Iptr = WriteTriangle(Iptr, - index + i - 2, - index + i - !wind, - index + i - wind); - - wind ^= true; - } - } - return Iptr; + wind ^= true; + } + } + return Iptr; } /** @@ -122,37 +121,38 @@ template u16* IndexGenerator::AddStrip(u16 *Iptr, u32 const numVerts, * so we use 6 indices for 3 triangles */ -template u16* IndexGenerator::AddFan(u16 *Iptr, u32 numVerts, u32 index) +template +u16* IndexGenerator::AddFan(u16* Iptr, u32 numVerts, u32 index) { - u32 i = 2; + u32 i = 2; - if (pr) - { - for (; i+3<=numVerts; i+=3) - { - *Iptr++ = index + i - 1; - *Iptr++ = index + i + 0; - *Iptr++ = index; - *Iptr++ = index + i + 1; - *Iptr++ = index + i + 2; - *Iptr++ = s_primitive_restart; - } + if (pr) + { + for (; i + 3 <= numVerts; i += 3) + { + *Iptr++ = index + i - 1; + *Iptr++ = index + i + 0; + *Iptr++ = index; + *Iptr++ = index + i + 1; + *Iptr++ = index + i + 2; + *Iptr++ = s_primitive_restart; + } - for (; i+2<=numVerts; i+=2) - { - *Iptr++ = index + i - 1; - *Iptr++ = index + i + 0; - *Iptr++ = index; - *Iptr++ = index + i + 1; - *Iptr++ = s_primitive_restart; - } - } + for (; i + 2 <= numVerts; i += 2) + { + *Iptr++ = index + i - 1; + *Iptr++ = index + i + 0; + *Iptr++ = index; + *Iptr++ = index + i + 1; + *Iptr++ = s_primitive_restart; + } + } - for (; i < numVerts; ++i) - { - Iptr = WriteTriangle(Iptr, index, index + i - 1, index + i); - } - return Iptr; + for (; i < numVerts; ++i) + { + Iptr = WriteTriangle(Iptr, index, index + i - 1, index + i); + } + return Iptr; } /* @@ -172,77 +172,78 @@ template u16* IndexGenerator::AddFan(u16 *Iptr, u32 numVerts, u32 inde * A simple triangle has to be rendered for three vertices. * ZWW do this for sun rays */ -template u16* IndexGenerator::AddQuads(u16 *Iptr, u32 numVerts, u32 index) +template +u16* IndexGenerator::AddQuads(u16* Iptr, u32 numVerts, u32 index) { - u32 i = 3; - for (; i < numVerts; i+=4) - { - if (pr) - { - *Iptr++ = index + i - 2; - *Iptr++ = index + i - 1; - *Iptr++ = index + i - 3; - *Iptr++ = index + i - 0; - *Iptr++ = s_primitive_restart; - } - else - { - Iptr = WriteTriangle(Iptr, index + i - 3, index + i - 2, index + i - 1); - Iptr = WriteTriangle(Iptr, index + i - 3, index + i - 1, index + i - 0); - } - } + u32 i = 3; + for (; i < numVerts; i += 4) + { + if (pr) + { + *Iptr++ = index + i - 2; + *Iptr++ = index + i - 1; + *Iptr++ = index + i - 3; + *Iptr++ = index + i - 0; + *Iptr++ = s_primitive_restart; + } + else + { + Iptr = WriteTriangle(Iptr, index + i - 3, index + i - 2, index + i - 1); + Iptr = WriteTriangle(Iptr, index + i - 3, index + i - 1, index + i - 0); + } + } - // three vertices remaining, so render a triangle - if (i == numVerts) - { - Iptr = WriteTriangle(Iptr, index+numVerts-3, index+numVerts-2, index+numVerts-1); - } - return Iptr; + // three vertices remaining, so render a triangle + if (i == numVerts) + { + Iptr = + WriteTriangle(Iptr, index + numVerts - 3, index + numVerts - 2, index + numVerts - 1); + } + return Iptr; } -template u16* IndexGenerator::AddQuads_nonstandard(u16 *Iptr, u32 numVerts, u32 index) +template +u16* IndexGenerator::AddQuads_nonstandard(u16* Iptr, u32 numVerts, u32 index) { - WARN_LOG(VIDEO, "Non-standard primitive drawing command GL_DRAW_QUADS_2"); - return AddQuads(Iptr, numVerts, index); + WARN_LOG(VIDEO, "Non-standard primitive drawing command GL_DRAW_QUADS_2"); + return AddQuads(Iptr, numVerts, index); } // Lines -u16* IndexGenerator::AddLineList(u16 *Iptr, u32 numVerts, u32 index) +u16* IndexGenerator::AddLineList(u16* Iptr, u32 numVerts, u32 index) { - for (u32 i = 1; i < numVerts; i+=2) - { - *Iptr++ = index + i - 1; - *Iptr++ = index + i; - } - return Iptr; - + for (u32 i = 1; i < numVerts; i += 2) + { + *Iptr++ = index + i - 1; + *Iptr++ = index + i; + } + return Iptr; } // shouldn't be used as strips as LineLists are much more common // so converting them to lists -u16* IndexGenerator::AddLineStrip(u16 *Iptr, u32 numVerts, u32 index) +u16* IndexGenerator::AddLineStrip(u16* Iptr, u32 numVerts, u32 index) { - for (u32 i = 1; i < numVerts; ++i) - { - *Iptr++ = index + i - 1; - *Iptr++ = index + i; - } - return Iptr; + for (u32 i = 1; i < numVerts; ++i) + { + *Iptr++ = index + i - 1; + *Iptr++ = index + i; + } + return Iptr; } // Points -u16* IndexGenerator::AddPoints(u16 *Iptr, u32 numVerts, u32 index) +u16* IndexGenerator::AddPoints(u16* Iptr, u32 numVerts, u32 index) { - for (u32 i = 0; i != numVerts; ++i) - { - *Iptr++ = index + i; - } - return Iptr; + for (u32 i = 0; i != numVerts; ++i) + { + *Iptr++ = index + i; + } + return Iptr; } - u32 IndexGenerator::GetRemainingIndices() { - u32 max_index = 65534; // -1 is reserved for primitive restart (ogl + dx11) - return max_index - base_index; + u32 max_index = 65534; // -1 is reserved for primitive restart (ogl + dx11) + return max_index - base_index; } diff --git a/Source/Core/VideoCommon/IndexGenerator.h b/Source/Core/VideoCommon/IndexGenerator.h index 8390935b46..8d2a5e8700 100644 --- a/Source/Core/VideoCommon/IndexGenerator.h +++ b/Source/Core/VideoCommon/IndexGenerator.h @@ -12,37 +12,41 @@ class IndexGenerator { public: - // Init - static void Init(); - static void Start(u16 *Indexptr); + // Init + static void Init(); + static void Start(u16* Indexptr); - static void AddIndices(int primitive, u32 numVertices); + static void AddIndices(int primitive, u32 numVertices); - // returns numprimitives - static u32 GetNumVerts() {return base_index;} - - static u32 GetIndexLen() {return (u32)(index_buffer_current - BASEIptr);} - - static u32 GetRemainingIndices(); + // returns numprimitives + static u32 GetNumVerts() { return base_index; } + static u32 GetIndexLen() { return (u32)(index_buffer_current - BASEIptr); } + static u32 GetRemainingIndices(); private: - // Triangles - template static u16* AddList(u16 *Iptr, u32 numVerts, u32 index); - template static u16* AddStrip(u16 *Iptr, u32 numVerts, u32 index); - template static u16* AddFan(u16 *Iptr, u32 numVerts, u32 index); - template static u16* AddQuads(u16 *Iptr, u32 numVerts, u32 index); - template static u16* AddQuads_nonstandard(u16 *Iptr, u32 numVerts, u32 index); + // Triangles + template + static u16* AddList(u16* Iptr, u32 numVerts, u32 index); + template + static u16* AddStrip(u16* Iptr, u32 numVerts, u32 index); + template + static u16* AddFan(u16* Iptr, u32 numVerts, u32 index); + template + static u16* AddQuads(u16* Iptr, u32 numVerts, u32 index); + template + static u16* AddQuads_nonstandard(u16* Iptr, u32 numVerts, u32 index); - // Lines - static u16* AddLineList(u16 *Iptr, u32 numVerts, u32 index); - static u16* AddLineStrip(u16 *Iptr, u32 numVerts, u32 index); + // Lines + static u16* AddLineList(u16* Iptr, u32 numVerts, u32 index); + static u16* AddLineStrip(u16* Iptr, u32 numVerts, u32 index); - // Points - static u16* AddPoints(u16 *Iptr, u32 numVerts, u32 index); + // Points + static u16* AddPoints(u16* Iptr, u32 numVerts, u32 index); - template static u16* WriteTriangle(u16 *Iptr, u32 index1, u32 index2, u32 index3); + template + static u16* WriteTriangle(u16* Iptr, u32 index1, u32 index2, u32 index3); - static u16 *index_buffer_current; - static u16 *BASEIptr; - static u32 base_index; + static u16* index_buffer_current; + static u16* BASEIptr; + static u32 base_index; }; diff --git a/Source/Core/VideoCommon/LightingShaderGen.h b/Source/Core/VideoCommon/LightingShaderGen.h index 9fe3510052..136e3ec50c 100644 --- a/Source/Core/VideoCommon/LightingShaderGen.h +++ b/Source/Core/VideoCommon/LightingShaderGen.h @@ -10,7 +10,6 @@ #include "VideoCommon/ShaderGenCommon.h" #include "VideoCommon/XFMemory.h" - #define LIGHT_COL "%s[%d].color.%s" #define LIGHT_COL_PARAMS(index, swizzle) (I_LIGHTS), (index), (swizzle) @@ -31,79 +30,88 @@ */ struct LightingUidData { - u32 matsource : 4; // 4x1 bit - u32 enablelighting : 4; // 4x1 bit - u32 ambsource : 4; // 4x1 bit - u32 diffusefunc : 8; // 4x2 bits - u32 attnfunc : 8; // 4x2 bits - u32 light_mask : 32; // 4x8 bits + u32 matsource : 4; // 4x1 bit + u32 enablelighting : 4; // 4x1 bit + u32 ambsource : 4; // 4x1 bit + u32 diffusefunc : 8; // 4x2 bits + u32 attnfunc : 8; // 4x2 bits + u32 light_mask : 32; // 4x8 bits }; -static const char s_lighting_struct[] = - "struct Light {\n" - "\tint4 color;\n" - "\tfloat4 cosatt;\n" - "\tfloat4 distatt;\n" - "\tfloat4 pos;\n" - "\tfloat4 dir;\n" - "};\n"; +static const char s_lighting_struct[] = "struct Light {\n" + "\tint4 color;\n" + "\tfloat4 cosatt;\n" + "\tfloat4 distatt;\n" + "\tfloat4 pos;\n" + "\tfloat4 dir;\n" + "};\n"; -template -static void GenerateLightShader(T& object, LightingUidData& uid_data, int index, int litchan_index, int coloralpha) +template +static void GenerateLightShader(T& object, LightingUidData& uid_data, int index, int litchan_index, + int coloralpha) { - const LitChannel& chan = (litchan_index > 1) ? xfmem.alpha[litchan_index-2] : xfmem.color[litchan_index]; - const char* swizzle = (coloralpha == 1) ? "xyz" : (coloralpha == 2) ? "w" : "xyzw"; - const char* swizzle_components = (coloralpha == 1) ? "3" : (coloralpha == 2) ? "" : "4"; + const LitChannel& chan = + (litchan_index > 1) ? xfmem.alpha[litchan_index - 2] : xfmem.color[litchan_index]; + const char* swizzle = (coloralpha == 1) ? "xyz" : (coloralpha == 2) ? "w" : "xyzw"; + const char* swizzle_components = (coloralpha == 1) ? "3" : (coloralpha == 2) ? "" : "4"; - uid_data.attnfunc |= chan.attnfunc << (2*litchan_index); - uid_data.diffusefunc |= chan.diffusefunc << (2*litchan_index); + uid_data.attnfunc |= chan.attnfunc << (2 * litchan_index); + uid_data.diffusefunc |= chan.diffusefunc << (2 * litchan_index); - switch (chan.attnfunc) - { - case LIGHTATTN_NONE: - case LIGHTATTN_DIR: - object.Write("ldir = normalize(" LIGHT_POS".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index)); - object.Write("attn = 1.0;\n"); - object.Write("if (length(ldir) == 0.0)\n\t ldir = _norm0;\n"); - break; - case LIGHTATTN_SPEC: - object.Write("ldir = normalize(" LIGHT_POS".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index)); - object.Write("attn = (dot(_norm0, ldir) >= 0.0) ? max(0.0, dot(_norm0, " LIGHT_DIR".xyz)) : 0.0;\n", LIGHT_DIR_PARAMS(index)); - object.Write("cosAttn = " LIGHT_COSATT".xyz;\n", LIGHT_COSATT_PARAMS(index)); - object.Write("distAttn = %s(" LIGHT_DISTATT".xyz);\n", (chan.diffusefunc == LIGHTDIF_NONE) ? "" : "normalize", LIGHT_DISTATT_PARAMS(index)); - object.Write("attn = max(0.0f, dot(cosAttn, float3(1.0, attn, attn*attn))) / dot(distAttn, float3(1.0, attn, attn*attn));\n"); - break; - case LIGHTATTN_SPOT: - object.Write("ldir = " LIGHT_POS".xyz - pos.xyz;\n", LIGHT_POS_PARAMS(index)); - object.Write("dist2 = dot(ldir, ldir);\n" - "dist = sqrt(dist2);\n" - "ldir = ldir / dist;\n" - "attn = max(0.0, dot(ldir, " LIGHT_DIR".xyz));\n", LIGHT_DIR_PARAMS(index)); - // attn*attn may overflow - object.Write("attn = max(0.0, " LIGHT_COSATT".x + " LIGHT_COSATT".y*attn + " LIGHT_COSATT".z*attn*attn) / dot(" LIGHT_DISTATT".xyz, float3(1.0,dist,dist2));\n", - LIGHT_COSATT_PARAMS(index), LIGHT_COSATT_PARAMS(index), LIGHT_COSATT_PARAMS(index), LIGHT_DISTATT_PARAMS(index)); - break; - default: _assert_(0); - } + switch (chan.attnfunc) + { + case LIGHTATTN_NONE: + case LIGHTATTN_DIR: + object.Write("ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index)); + object.Write("attn = 1.0;\n"); + object.Write("if (length(ldir) == 0.0)\n\t ldir = _norm0;\n"); + break; + case LIGHTATTN_SPEC: + object.Write("ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index)); + object.Write("attn = (dot(_norm0, ldir) >= 0.0) ? max(0.0, dot(_norm0, " LIGHT_DIR + ".xyz)) : 0.0;\n", + LIGHT_DIR_PARAMS(index)); + object.Write("cosAttn = " LIGHT_COSATT ".xyz;\n", LIGHT_COSATT_PARAMS(index)); + object.Write("distAttn = %s(" LIGHT_DISTATT ".xyz);\n", + (chan.diffusefunc == LIGHTDIF_NONE) ? "" : "normalize", + LIGHT_DISTATT_PARAMS(index)); + object.Write("attn = max(0.0f, dot(cosAttn, float3(1.0, attn, attn*attn))) / dot(distAttn, " + "float3(1.0, attn, attn*attn));\n"); + break; + case LIGHTATTN_SPOT: + object.Write("ldir = " LIGHT_POS ".xyz - pos.xyz;\n", LIGHT_POS_PARAMS(index)); + object.Write("dist2 = dot(ldir, ldir);\n" + "dist = sqrt(dist2);\n" + "ldir = ldir / dist;\n" + "attn = max(0.0, dot(ldir, " LIGHT_DIR ".xyz));\n", + LIGHT_DIR_PARAMS(index)); + // attn*attn may overflow + object.Write("attn = max(0.0, " LIGHT_COSATT ".x + " LIGHT_COSATT ".y*attn + " LIGHT_COSATT + ".z*attn*attn) / dot(" LIGHT_DISTATT ".xyz, float3(1.0,dist,dist2));\n", + LIGHT_COSATT_PARAMS(index), LIGHT_COSATT_PARAMS(index), LIGHT_COSATT_PARAMS(index), + LIGHT_DISTATT_PARAMS(index)); + break; + default: + _assert_(0); + } - switch (chan.diffusefunc) - { - case LIGHTDIF_NONE: - object.Write("lacc.%s += int%s(round(attn * float%s(" LIGHT_COL")));\n", - swizzle, swizzle_components, - swizzle_components, LIGHT_COL_PARAMS(index, swizzle)); - break; - case LIGHTDIF_SIGN: - case LIGHTDIF_CLAMP: - object.Write("lacc.%s += int%s(round(attn * %sdot(ldir, _norm0)) * float%s(" LIGHT_COL")));\n", - swizzle, swizzle_components, - chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0," :"(", - swizzle_components, LIGHT_COL_PARAMS(index, swizzle)); - break; - default: _assert_(0); - } + switch (chan.diffusefunc) + { + case LIGHTDIF_NONE: + object.Write("lacc.%s += int%s(round(attn * float%s(" LIGHT_COL ")));\n", swizzle, + swizzle_components, swizzle_components, LIGHT_COL_PARAMS(index, swizzle)); + break; + case LIGHTDIF_SIGN: + case LIGHTDIF_CLAMP: + object.Write("lacc.%s += int%s(round(attn * %sdot(ldir, _norm0)) * float%s(" LIGHT_COL ")));\n", + swizzle, swizzle_components, chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0," : "(", + swizzle_components, LIGHT_COL_PARAMS(index, swizzle)); + break; + default: + _assert_(0); + } - object.Write("\n"); + object.Write("\n"); } // vertex shader @@ -111,149 +119,151 @@ static void GenerateLightShader(T& object, LightingUidData& uid_data, int index, // materials name is I_MATERIALS in vs and I_PMATERIALS in ps // inColorName is color in vs and colors_ in ps // dest is o.colors_ in vs and colors_ in ps -template -static void GenerateLightingShader(T& object, LightingUidData& uid_data, int components, const char* inColorName, const char* dest) +template +static void GenerateLightingShader(T& object, LightingUidData& uid_data, int components, + const char* inColorName, const char* dest) { - for (unsigned int j = 0; j < xfmem.numChan.numColorChans; j++) - { - const LitChannel& color = xfmem.color[j]; - const LitChannel& alpha = xfmem.alpha[j]; + for (unsigned int j = 0; j < xfmem.numChan.numColorChans; j++) + { + const LitChannel& color = xfmem.color[j]; + const LitChannel& alpha = xfmem.alpha[j]; - object.Write("{\n"); + object.Write("{\n"); - uid_data.matsource |= xfmem.color[j].matsource << j; - if (color.matsource) // from vertex - { - if (components & (VB_HAS_COL0 << j)) - object.Write("int4 mat = int4(round(%s%d * 255.0));\n", inColorName, j); - else if (components & VB_HAS_COL0) - object.Write("int4 mat = int4(round(%s0 * 255.0));\n", inColorName); - else - object.Write("int4 mat = int4(255, 255, 255, 255);\n"); - } - else // from color - { - object.Write("int4 mat = %s[%d];\n", I_MATERIALS, j+2); - } + uid_data.matsource |= xfmem.color[j].matsource << j; + if (color.matsource) // from vertex + { + if (components & (VB_HAS_COL0 << j)) + object.Write("int4 mat = int4(round(%s%d * 255.0));\n", inColorName, j); + else if (components & VB_HAS_COL0) + object.Write("int4 mat = int4(round(%s0 * 255.0));\n", inColorName); + else + object.Write("int4 mat = int4(255, 255, 255, 255);\n"); + } + else // from color + { + object.Write("int4 mat = %s[%d];\n", I_MATERIALS, j + 2); + } - uid_data.enablelighting |= xfmem.color[j].enablelighting << j; - if (color.enablelighting) - { - uid_data.ambsource |= xfmem.color[j].ambsource << j; - if (color.ambsource) // from vertex - { - if (components & (VB_HAS_COL0<(object, uid_data, i, j, 3); - } - } - } - } + if (color.enablelighting && alpha.enablelighting) + { + // both have lighting, test if they use the same lights + int mask = 0; + uid_data.attnfunc |= color.attnfunc << (2 * j); + uid_data.attnfunc |= alpha.attnfunc << (2 * (j + 2)); + uid_data.diffusefunc |= color.diffusefunc << (2 * j); + uid_data.diffusefunc |= alpha.diffusefunc << (2 * (j + 2)); + uid_data.light_mask |= color.GetFullLightMask() << (8 * j); + uid_data.light_mask |= alpha.GetFullLightMask() << (8 * (j + 2)); + if (color.lightparams == alpha.lightparams) + { + mask = color.GetFullLightMask() & alpha.GetFullLightMask(); + if (mask) + { + for (int i = 0; i < 8; ++i) + { + if (mask & (1 << i)) + { + GenerateLightShader(object, uid_data, i, j, 3); + } + } + } + } - // no shared lights - for (int i = 0; i < 8; ++i) - { - if (!(mask&(1<(object, uid_data, i, j, 1); - if (!(mask&(1<(object, uid_data, i, j+2, 2); - } - } - else if (color.enablelighting || alpha.enablelighting) - { - // lights are disabled on one channel so process only the active ones - const LitChannel& workingchannel = color.enablelighting ? color : alpha; - const int lit_index = color.enablelighting ? j : (j+2); - int coloralpha = color.enablelighting ? 1 : 2; + // no shared lights + for (int i = 0; i < 8; ++i) + { + if (!(mask & (1 << i)) && (color.GetFullLightMask() & (1 << i))) + GenerateLightShader(object, uid_data, i, j, 1); + if (!(mask & (1 << i)) && (alpha.GetFullLightMask() & (1 << i))) + GenerateLightShader(object, uid_data, i, j + 2, 2); + } + } + else if (color.enablelighting || alpha.enablelighting) + { + // lights are disabled on one channel so process only the active ones + const LitChannel& workingchannel = color.enablelighting ? color : alpha; + const int lit_index = color.enablelighting ? j : (j + 2); + int coloralpha = color.enablelighting ? 1 : 2; - uid_data.light_mask |= workingchannel.GetFullLightMask() << (8*lit_index); - for (int i = 0; i < 8; ++i) - { - if (workingchannel.GetFullLightMask() & (1<(object, uid_data, i, lit_index, coloralpha); - } - } - object.Write("lacc = clamp(lacc, 0, 255);\n"); - object.Write("%s%d = float4((mat * (lacc + (lacc >> 7))) >> 8) / 255.0;\n", dest, j); - object.Write("}\n"); - } + uid_data.light_mask |= workingchannel.GetFullLightMask() << (8 * lit_index); + for (int i = 0; i < 8; ++i) + { + if (workingchannel.GetFullLightMask() & (1 << i)) + GenerateLightShader(object, uid_data, i, lit_index, coloralpha); + } + } + object.Write("lacc = clamp(lacc, 0, 255);\n"); + object.Write("%s%d = float4((mat * (lacc + (lacc >> 7))) >> 8) / 255.0;\n", dest, j); + object.Write("}\n"); + } } diff --git a/Source/Core/VideoCommon/LookUpTables.h b/Source/Core/VideoCommon/LookUpTables.h index 4bda199be5..07170eb5c9 100644 --- a/Source/Core/VideoCommon/LookUpTables.h +++ b/Source/Core/VideoCommon/LookUpTables.h @@ -8,24 +8,24 @@ constexpr u8 Convert3To8(u8 v) { - // Swizzle bits: 00000123 -> 12312312 - return (v << 5) | (v << 2) | (v >> 1); + // Swizzle bits: 00000123 -> 12312312 + return (v << 5) | (v << 2) | (v >> 1); } constexpr u8 Convert4To8(u8 v) { - // Swizzle bits: 00001234 -> 12341234 - return (v << 4) | v; + // Swizzle bits: 00001234 -> 12341234 + return (v << 4) | v; } constexpr u8 Convert5To8(u8 v) { - // Swizzle bits: 00012345 -> 12345123 - return (v << 3) | (v >> 2); + // Swizzle bits: 00012345 -> 12345123 + return (v << 3) | (v >> 2); } constexpr u8 Convert6To8(u8 v) { - // Swizzle bits: 00123456 -> 12345612 - return (v << 2) | (v >> 4); + // Swizzle bits: 00123456 -> 12345612 + return (v << 2) | (v >> 4); } diff --git a/Source/Core/VideoCommon/MainBase.cpp b/Source/Core/VideoCommon/MainBase.cpp index 9280a31074..6b2e3c91c3 100644 --- a/Source/Core/VideoCommon/MainBase.cpp +++ b/Source/Core/VideoCommon/MainBase.cpp @@ -23,172 +23,175 @@ static Common::Flag s_FifoShuttingDown; static volatile struct { - u32 xfbAddr; - u32 fbWidth; - u32 fbStride; - u32 fbHeight; + u32 xfbAddr; + u32 fbWidth; + u32 fbStride; + u32 fbHeight; } s_beginFieldArgs; void VideoBackendBase::Video_ExitLoop() { - Fifo::ExitGpuLoop(); - s_FifoShuttingDown.Set(); + Fifo::ExitGpuLoop(); + s_FifoShuttingDown.Set(); } // Run from the CPU thread (from VideoInterface.cpp) void VideoBackendBase::Video_BeginField(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight) { - if (m_initialized && g_ActiveConfig.bUseXFB) - { - s_beginFieldArgs.xfbAddr = xfbAddr; - s_beginFieldArgs.fbWidth = fbWidth; - s_beginFieldArgs.fbStride = fbStride; - s_beginFieldArgs.fbHeight = fbHeight; - } + if (m_initialized && g_ActiveConfig.bUseXFB) + { + s_beginFieldArgs.xfbAddr = xfbAddr; + s_beginFieldArgs.fbWidth = fbWidth; + s_beginFieldArgs.fbStride = fbStride; + s_beginFieldArgs.fbHeight = fbHeight; + } } // Run from the CPU thread (from VideoInterface.cpp) void VideoBackendBase::Video_EndField() { - if (m_initialized && g_ActiveConfig.bUseXFB && g_renderer) - { - Fifo::SyncGPU(Fifo::SYNC_GPU_SWAP); + if (m_initialized && g_ActiveConfig.bUseXFB && g_renderer) + { + Fifo::SyncGPU(Fifo::SYNC_GPU_SWAP); - AsyncRequests::Event e; - e.time = 0; - e.type = AsyncRequests::Event::SWAP_EVENT; + AsyncRequests::Event e; + e.time = 0; + e.type = AsyncRequests::Event::SWAP_EVENT; - e.swap_event.xfbAddr = s_beginFieldArgs.xfbAddr; - e.swap_event.fbWidth = s_beginFieldArgs.fbWidth; - e.swap_event.fbStride = s_beginFieldArgs.fbStride; - e.swap_event.fbHeight = s_beginFieldArgs.fbHeight; - AsyncRequests::GetInstance()->PushEvent(e, false); - } + e.swap_event.xfbAddr = s_beginFieldArgs.xfbAddr; + e.swap_event.fbWidth = s_beginFieldArgs.fbWidth; + e.swap_event.fbStride = s_beginFieldArgs.fbStride; + e.swap_event.fbHeight = s_beginFieldArgs.fbHeight; + AsyncRequests::GetInstance()->PushEvent(e, false); + } } u32 VideoBackendBase::Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData) { - if (!g_ActiveConfig.bEFBAccessEnable) - { - return 0; - } + if (!g_ActiveConfig.bEFBAccessEnable) + { + return 0; + } - if (type == POKE_COLOR || type == POKE_Z) - { - AsyncRequests::Event e; - e.type = type == POKE_COLOR ? AsyncRequests::Event::EFB_POKE_COLOR : AsyncRequests::Event::EFB_POKE_Z; - e.time = 0; - e.efb_poke.data = InputData; - e.efb_poke.x = x; - e.efb_poke.y = y; - AsyncRequests::GetInstance()->PushEvent(e, false); - return 0; - } - else - { - AsyncRequests::Event e; - u32 result; - e.type = type == PEEK_COLOR ? AsyncRequests::Event::EFB_PEEK_COLOR : AsyncRequests::Event::EFB_PEEK_Z; - e.time = 0; - e.efb_peek.x = x; - e.efb_peek.y = y; - e.efb_peek.data = &result; - AsyncRequests::GetInstance()->PushEvent(e, true); - return result; - } + if (type == POKE_COLOR || type == POKE_Z) + { + AsyncRequests::Event e; + e.type = type == POKE_COLOR ? AsyncRequests::Event::EFB_POKE_COLOR : + AsyncRequests::Event::EFB_POKE_Z; + e.time = 0; + e.efb_poke.data = InputData; + e.efb_poke.x = x; + e.efb_poke.y = y; + AsyncRequests::GetInstance()->PushEvent(e, false); + return 0; + } + else + { + AsyncRequests::Event e; + u32 result; + e.type = type == PEEK_COLOR ? AsyncRequests::Event::EFB_PEEK_COLOR : + AsyncRequests::Event::EFB_PEEK_Z; + e.time = 0; + e.efb_peek.x = x; + e.efb_peek.y = y; + e.efb_peek.data = &result; + AsyncRequests::GetInstance()->PushEvent(e, true); + return result; + } } u32 VideoBackendBase::Video_GetQueryResult(PerfQueryType type) { - if (!g_perf_query->ShouldEmulate()) - { - return 0; - } + if (!g_perf_query->ShouldEmulate()) + { + return 0; + } - Fifo::SyncGPU(Fifo::SYNC_GPU_PERFQUERY); + Fifo::SyncGPU(Fifo::SYNC_GPU_PERFQUERY); - AsyncRequests::Event e; - e.time = 0; - e.type = AsyncRequests::Event::PERF_QUERY; + AsyncRequests::Event e; + e.time = 0; + e.type = AsyncRequests::Event::PERF_QUERY; - if (!g_perf_query->IsFlushed()) - AsyncRequests::GetInstance()->PushEvent(e, true); + if (!g_perf_query->IsFlushed()) + AsyncRequests::GetInstance()->PushEvent(e, true); - return g_perf_query->GetQueryResult(type); + return g_perf_query->GetQueryResult(type); } u16 VideoBackendBase::Video_GetBoundingBox(int index) { - if (!g_ActiveConfig.backend_info.bSupportsBBox) - return 0; + if (!g_ActiveConfig.backend_info.bSupportsBBox) + return 0; - if (!g_ActiveConfig.bBBoxEnable) - { - static bool warn_once = true; - if (warn_once) - ERROR_LOG(VIDEO, "BBox shall be used but it is disabled. Please use a gameini to enable it for this game."); - warn_once = false; - return 0; - } + if (!g_ActiveConfig.bBBoxEnable) + { + static bool warn_once = true; + if (warn_once) + ERROR_LOG(VIDEO, "BBox shall be used but it is disabled. Please use a gameini to enable it " + "for this game."); + warn_once = false; + return 0; + } - Fifo::SyncGPU(Fifo::SYNC_GPU_BBOX); + Fifo::SyncGPU(Fifo::SYNC_GPU_BBOX); - AsyncRequests::Event e; - u16 result; - e.time = 0; - e.type = AsyncRequests::Event::BBOX_READ; - e.bbox.index = index; - e.bbox.data = &result; - AsyncRequests::GetInstance()->PushEvent(e, true); + AsyncRequests::Event e; + u16 result; + e.time = 0; + e.type = AsyncRequests::Event::BBOX_READ; + e.bbox.index = index; + e.bbox.data = &result; + AsyncRequests::GetInstance()->PushEvent(e, true); - return result; + return result; } void VideoBackendBase::InitializeShared() { - VideoCommon_Init(); + VideoCommon_Init(); - s_FifoShuttingDown.Clear(); - memset((void*)&s_beginFieldArgs, 0, sizeof(s_beginFieldArgs)); - m_invalid = false; + s_FifoShuttingDown.Clear(); + memset((void*)&s_beginFieldArgs, 0, sizeof(s_beginFieldArgs)); + m_invalid = false; } // Run from the CPU thread void VideoBackendBase::DoState(PointerWrap& p) { - bool software = false; - p.Do(software); + bool software = false; + p.Do(software); - if (p.GetMode() == PointerWrap::MODE_READ && software == true) - { - // change mode to abort load of incompatible save state. - p.SetMode(PointerWrap::MODE_VERIFY); - } + if (p.GetMode() == PointerWrap::MODE_READ && software == true) + { + // change mode to abort load of incompatible save state. + p.SetMode(PointerWrap::MODE_VERIFY); + } - VideoCommon_DoState(p); - p.DoMarker("VideoCommon"); + VideoCommon_DoState(p); + p.DoMarker("VideoCommon"); - p.Do(s_beginFieldArgs); - p.DoMarker("VideoBackendBase"); + p.Do(s_beginFieldArgs); + p.DoMarker("VideoBackendBase"); - // Refresh state. - if (p.GetMode() == PointerWrap::MODE_READ) - { - m_invalid = true; + // Refresh state. + if (p.GetMode() == PointerWrap::MODE_READ) + { + m_invalid = true; - // Clear all caches that touch RAM - // (? these don't appear to touch any emulation state that gets saved. moved to on load only.) - VertexLoaderManager::MarkAllDirty(); - } + // Clear all caches that touch RAM + // (? these don't appear to touch any emulation state that gets saved. moved to on load only.) + VertexLoaderManager::MarkAllDirty(); + } } void VideoBackendBase::CheckInvalidState() { - if (m_invalid) - { - m_invalid = false; + if (m_invalid) + { + m_invalid = false; - BPReload(); - TextureCacheBase::Invalidate(); - } + BPReload(); + TextureCacheBase::Invalidate(); + } } diff --git a/Source/Core/VideoCommon/NativeVertexFormat.h b/Source/Core/VideoCommon/NativeVertexFormat.h index ff461a02fd..b5d40bd54e 100644 --- a/Source/Core/VideoCommon/NativeVertexFormat.h +++ b/Source/Core/VideoCommon/NativeVertexFormat.h @@ -5,7 +5,7 @@ #pragma once #include -#include // for hash +#include // for hash #include "Common/CommonTypes.h" #include "Common/Hash.h" @@ -14,88 +14,86 @@ // m_components enum { - VB_HAS_POSMTXIDX =(1<<1), - VB_HAS_TEXMTXIDX0=(1<<2), - VB_HAS_TEXMTXIDX1=(1<<3), - VB_HAS_TEXMTXIDX2=(1<<4), - VB_HAS_TEXMTXIDX3=(1<<5), - VB_HAS_TEXMTXIDX4=(1<<6), - VB_HAS_TEXMTXIDX5=(1<<7), - VB_HAS_TEXMTXIDX6=(1<<8), - VB_HAS_TEXMTXIDX7=(1<<9), - VB_HAS_TEXMTXIDXALL=(0xff<<2), + VB_HAS_POSMTXIDX = (1 << 1), + VB_HAS_TEXMTXIDX0 = (1 << 2), + VB_HAS_TEXMTXIDX1 = (1 << 3), + VB_HAS_TEXMTXIDX2 = (1 << 4), + VB_HAS_TEXMTXIDX3 = (1 << 5), + VB_HAS_TEXMTXIDX4 = (1 << 6), + VB_HAS_TEXMTXIDX5 = (1 << 7), + VB_HAS_TEXMTXIDX6 = (1 << 8), + VB_HAS_TEXMTXIDX7 = (1 << 9), + VB_HAS_TEXMTXIDXALL = (0xff << 2), - //VB_HAS_POS=0, // Implied, it always has pos! don't bother testing - VB_HAS_NRM0=(1<<10), - VB_HAS_NRM1=(1<<11), - VB_HAS_NRM2=(1<<12), - VB_HAS_NRMALL=(7<<10), + // VB_HAS_POS=0, // Implied, it always has pos! don't bother testing + VB_HAS_NRM0 = (1 << 10), + VB_HAS_NRM1 = (1 << 11), + VB_HAS_NRM2 = (1 << 12), + VB_HAS_NRMALL = (7 << 10), - VB_HAS_COL0=(1<<13), - VB_HAS_COL1=(1<<14), + VB_HAS_COL0 = (1 << 13), + VB_HAS_COL1 = (1 << 14), - VB_HAS_UV0=(1<<15), - VB_HAS_UV1=(1<<16), - VB_HAS_UV2=(1<<17), - VB_HAS_UV3=(1<<18), - VB_HAS_UV4=(1<<19), - VB_HAS_UV5=(1<<20), - VB_HAS_UV6=(1<<21), - VB_HAS_UV7=(1<<22), - VB_HAS_UVALL=(0xff<<15), - VB_HAS_UVTEXMTXSHIFT=13, + VB_HAS_UV0 = (1 << 15), + VB_HAS_UV1 = (1 << 16), + VB_HAS_UV2 = (1 << 17), + VB_HAS_UV3 = (1 << 18), + VB_HAS_UV4 = (1 << 19), + VB_HAS_UV5 = (1 << 20), + VB_HAS_UV6 = (1 << 21), + VB_HAS_UV7 = (1 << 22), + VB_HAS_UVALL = (0xff << 15), + VB_HAS_UVTEXMTXSHIFT = 13, }; enum VarType { - VAR_UNSIGNED_BYTE, // GX_U8 = 0 - VAR_BYTE, // GX_S8 = 1 - VAR_UNSIGNED_SHORT, // GX_U16 = 2 - VAR_SHORT, // GX_S16 = 3 - VAR_FLOAT, // GX_F32 = 4 + VAR_UNSIGNED_BYTE, // GX_U8 = 0 + VAR_BYTE, // GX_S8 = 1 + VAR_UNSIGNED_SHORT, // GX_U16 = 2 + VAR_SHORT, // GX_S16 = 3 + VAR_FLOAT, // GX_F32 = 4 }; struct AttributeFormat { - VarType type; - int components; - int offset; - bool enable; - bool integer; + VarType type; + int components; + int offset; + bool enable; + bool integer; }; struct PortableVertexDeclaration { - int stride; + int stride; - AttributeFormat position; - AttributeFormat normals[3]; - AttributeFormat colors[2]; - AttributeFormat texcoords[8]; - AttributeFormat posmtx; + AttributeFormat position; + AttributeFormat normals[3]; + AttributeFormat colors[2]; + AttributeFormat texcoords[8]; + AttributeFormat posmtx; - inline bool operator<(const PortableVertexDeclaration& b) const - { - return memcmp(this, &b, sizeof(PortableVertexDeclaration)) < 0; - } - inline bool operator==(const PortableVertexDeclaration& b) const - { - return memcmp(this, &b, sizeof(PortableVertexDeclaration)) == 0; - } + inline bool operator<(const PortableVertexDeclaration& b) const + { + return memcmp(this, &b, sizeof(PortableVertexDeclaration)) < 0; + } + inline bool operator==(const PortableVertexDeclaration& b) const + { + return memcmp(this, &b, sizeof(PortableVertexDeclaration)) == 0; + } }; namespace std { - template <> struct hash { - size_t operator()(const PortableVertexDeclaration& decl) const - { - return HashFletcher((u8 *) &decl, sizeof(decl)); - } + size_t operator()(const PortableVertexDeclaration& decl) const + { + return HashFletcher((u8*)&decl, sizeof(decl)); + } }; - } // The implementation of this class is specific for GL/DX, so NativeVertexFormat.cpp @@ -106,16 +104,13 @@ struct hash class NativeVertexFormat : NonCopyable { public: - virtual ~NativeVertexFormat() {} - - virtual void SetupVertexPointers() = 0; - - u32 GetVertexStride() const { return vtx_decl.stride; } - const PortableVertexDeclaration& GetVertexDeclaration() const { return vtx_decl; } + virtual ~NativeVertexFormat() {} + virtual void SetupVertexPointers() = 0; + u32 GetVertexStride() const { return vtx_decl.stride; } + const PortableVertexDeclaration& GetVertexDeclaration() const { return vtx_decl; } protected: - // Let subclasses construct. - NativeVertexFormat() {} - - PortableVertexDeclaration vtx_decl; + // Let subclasses construct. + NativeVertexFormat() {} + PortableVertexDeclaration vtx_decl; }; diff --git a/Source/Core/VideoCommon/OnScreenDisplay.cpp b/Source/Core/VideoCommon/OnScreenDisplay.cpp index ebce4f79ea..3cc2e823d8 100644 --- a/Source/Core/VideoCommon/OnScreenDisplay.cpp +++ b/Source/Core/VideoCommon/OnScreenDisplay.cpp @@ -15,20 +15,15 @@ #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/RenderBase.h" - namespace OSD { - struct Message { - Message() {} - Message(const std::string& s, u32 ts, u32 rgba) : m_str(s), m_timestamp(ts), m_rgba(rgba) - { - } - - std::string m_str; - u32 m_timestamp; - u32 m_rgba; + Message() {} + Message(const std::string& s, u32 ts, u32 rgba) : m_str(s), m_timestamp(ts), m_rgba(rgba) {} + std::string m_str; + u32 m_timestamp; + u32 m_rgba; }; static std::multimap s_callbacks; @@ -36,55 +31,55 @@ static std::list s_msgList; void AddMessage(const std::string& str, u32 ms, u32 rgba) { - s_msgList.emplace_back(str, Common::Timer::GetTimeMs() + ms, rgba); + s_msgList.emplace_back(str, Common::Timer::GetTimeMs() + ms, rgba); } void DrawMessages() { - if (!SConfig::GetInstance().bOnScreenDisplayMessages) - return; + if (!SConfig::GetInstance().bOnScreenDisplayMessages) + return; - int left = 25, top = 15; - auto it = s_msgList.begin(); - while (it != s_msgList.end()) - { - int time_left = (int)(it->m_timestamp - Common::Timer::GetTimeMs()); - float alpha = std::max(1.0f, std::min(0.0f, time_left / 1024.0f)); - u32 color = (it->m_rgba & 0xFFFFFF) | ((u32)((it->m_rgba >> 24) * alpha) << 24); + int left = 25, top = 15; + auto it = s_msgList.begin(); + while (it != s_msgList.end()) + { + int time_left = (int)(it->m_timestamp - Common::Timer::GetTimeMs()); + float alpha = std::max(1.0f, std::min(0.0f, time_left / 1024.0f)); + u32 color = (it->m_rgba & 0xFFFFFF) | ((u32)((it->m_rgba >> 24) * alpha) << 24); - g_renderer->RenderText(it->m_str, left, top, color); + g_renderer->RenderText(it->m_str, left, top, color); - top += 15; + top += 15; - if (time_left <= 0) - it = s_msgList.erase(it); - else - ++it; - } + if (time_left <= 0) + it = s_msgList.erase(it); + else + ++it; + } } void ClearMessages() { - s_msgList.clear(); + s_msgList.clear(); } // On-Screen Display Callbacks void AddCallback(CallbackType type, Callback cb) { - s_callbacks.emplace(type, cb); + s_callbacks.emplace(type, cb); } void DoCallbacks(CallbackType type) { - auto it_bounds = s_callbacks.equal_range(type); - for (auto it = it_bounds.first; it != it_bounds.second; ++it) - { - it->second(); - } + auto it_bounds = s_callbacks.equal_range(type); + for (auto it = it_bounds.first; it != it_bounds.second; ++it) + { + it->second(); + } - // Wipe all callbacks on shutdown - if (type == CallbackType::Shutdown) - s_callbacks.clear(); + // Wipe all callbacks on shutdown + if (type == CallbackType::Shutdown) + s_callbacks.clear(); } } // namespace diff --git a/Source/Core/VideoCommon/OnScreenDisplay.h b/Source/Core/VideoCommon/OnScreenDisplay.h index 8bf6852061..ab74201bca 100644 --- a/Source/Core/VideoCommon/OnScreenDisplay.h +++ b/Source/Core/VideoCommon/OnScreenDisplay.h @@ -13,15 +13,15 @@ namespace OSD { // On-screen message display (colored yellow by default) void AddMessage(const std::string& str, u32 ms = 2000, u32 rgba = 0xFFFFFF30); -void DrawMessages(); // draw the current messages on the screen. Only call once per frame. +void DrawMessages(); // draw the current messages on the screen. Only call once per frame. void ClearMessages(); // On-screen callbacks enum class CallbackType { - Initialization, - OnFrame, - Shutdown + Initialization, + OnFrame, + Shutdown }; using Callback = std::function; diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 32a3782aaf..8932cde5fa 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -2,27 +2,29 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -//DL facts: +// DL facts: // Ikaruga uses (nearly) NO display lists! // Zelda WW uses TONS of display lists // Zelda TP uses almost 100% display lists except menus (we like this!) // Super Mario Galaxy has nearly all geometry and more than half of the state in DLs (great!) -// Note that it IS NOT GENERALLY POSSIBLE to precompile display lists! You can compile them as they are -// while interpreting them, and hope that the vertex format doesn't change, though, if you do it right +// Note that it IS NOT GENERALLY POSSIBLE to precompile display lists! You can compile them as they +// are +// while interpreting them, and hope that the vertex format doesn't change, though, if you do it +// right // when they are called. The reason is that the vertex format affects the sizes of the vertices. +#include "VideoCommon/OpcodeDecoding.h" #include "Common/CommonTypes.h" -#include "Common/MsgHandler.h" #include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" #include "Core/FifoPlayer/FifoRecorder.h" #include "Core/HW/Memmap.h" #include "VideoCommon/BPMemory.h" -#include "VideoCommon/CommandProcessor.h" #include "VideoCommon/CPMemory.h" +#include "VideoCommon/CommandProcessor.h" #include "VideoCommon/DataReader.h" #include "VideoCommon/Fifo.h" -#include "VideoCommon/OpcodeDecoding.h" #include "VideoCommon/Statistics.h" #include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VideoCommon.h" @@ -32,100 +34,91 @@ bool g_bRecordFifoData = false; namespace OpcodeDecoder { - static bool s_bFifoErrorSeen = false; static u32 InterpretDisplayList(u32 address, u32 size) { - u8* startAddress; + u8* startAddress; - if (Fifo::UseDeterministicGPUThread()) - startAddress = (u8*)Fifo::PopFifoAuxBuffer(size); - else - startAddress = Memory::GetPointer(address); + if (Fifo::UseDeterministicGPUThread()) + startAddress = (u8*)Fifo::PopFifoAuxBuffer(size); + else + startAddress = Memory::GetPointer(address); - u32 cycles = 0; + u32 cycles = 0; - // Avoid the crash if Memory::GetPointer failed .. - if (startAddress != nullptr) - { - // temporarily swap dl and non-dl (small "hack" for the stats) - Statistics::SwapDL(); + // Avoid the crash if Memory::GetPointer failed .. + if (startAddress != nullptr) + { + // temporarily swap dl and non-dl (small "hack" for the stats) + Statistics::SwapDL(); - Run(DataReader(startAddress, startAddress + size), &cycles, true); - INCSTAT(stats.thisFrame.numDListsCalled); + Run(DataReader(startAddress, startAddress + size), &cycles, true); + INCSTAT(stats.thisFrame.numDListsCalled); - // un-swap - Statistics::SwapDL(); - } + // un-swap + Statistics::SwapDL(); + } - return cycles; + return cycles; } static void InterpretDisplayListPreprocess(u32 address, u32 size) { - u8* startAddress = Memory::GetPointer(address); + u8* startAddress = Memory::GetPointer(address); - Fifo::PushFifoAuxBuffer(startAddress, size); + Fifo::PushFifoAuxBuffer(startAddress, size); - if (startAddress != nullptr) - { - Run(DataReader(startAddress, startAddress + size), nullptr, true); - } + if (startAddress != nullptr) + { + Run(DataReader(startAddress, startAddress + size), nullptr, true); + } } -static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) +static void UnknownOpcode(u8 cmd_byte, void* buffer, bool preprocess) { - // TODO(Omega): Maybe dump FIFO to file on this error - PanicAlertT( - "GFX FIFO: Unknown Opcode (0x%02x @ %p, %s).\n" - "This means one of the following:\n" - "* The emulated GPU got desynced, disabling dual core can help\n" - "* Command stream corrupted by some spurious memory bug\n" - "* This really is an unknown opcode (unlikely)\n" - "* Some other sort of bug\n\n" - "Further errors will be sent to the Video Backend log and\n" - "Dolphin will now likely crash or hang. Enjoy." , - cmd_byte, - buffer, - preprocess ? "preprocess=true" : "preprocess=false"); + // TODO(Omega): Maybe dump FIFO to file on this error + PanicAlertT("GFX FIFO: Unknown Opcode (0x%02x @ %p, %s).\n" + "This means one of the following:\n" + "* The emulated GPU got desynced, disabling dual core can help\n" + "* Command stream corrupted by some spurious memory bug\n" + "* This really is an unknown opcode (unlikely)\n" + "* Some other sort of bug\n\n" + "Further errors will be sent to the Video Backend log and\n" + "Dolphin will now likely crash or hang. Enjoy.", + cmd_byte, buffer, preprocess ? "preprocess=true" : "preprocess=false"); - { - SCPFifoStruct &fifo = CommandProcessor::fifo; + { + SCPFifoStruct& fifo = CommandProcessor::fifo; - PanicAlert( - "Illegal command %02x\n" - "CPBase: 0x%08x\n" - "CPEnd: 0x%08x\n" - "CPHiWatermark: 0x%08x\n" - "CPLoWatermark: 0x%08x\n" - "CPReadWriteDistance: 0x%08x\n" - "CPWritePointer: 0x%08x\n" - "CPReadPointer: 0x%08x\n" - "CPBreakpoint: 0x%08x\n" - "bFF_GPReadEnable: %s\n" - "bFF_BPEnable: %s\n" - "bFF_BPInt: %s\n" - "bFF_Breakpoint: %s\n" - "bFF_GPLinkEnable: %s\n" - "bFF_HiWatermarkInt: %s\n" - "bFF_LoWatermarkInt: %s\n" - ,cmd_byte, fifo.CPBase, fifo.CPEnd, fifo.CPHiWatermark, fifo.CPLoWatermark, fifo.CPReadWriteDistance - ,fifo.CPWritePointer, fifo.CPReadPointer, fifo.CPBreakpoint - ,fifo.bFF_GPReadEnable ? "true" : "false" - ,fifo.bFF_BPEnable ? "true" : "false" - ,fifo.bFF_BPInt ? "true" : "false" - ,fifo.bFF_Breakpoint ? "true" : "false" - ,fifo.bFF_GPLinkEnable ? "true" : "false" - ,fifo.bFF_HiWatermarkInt ? "true" : "false" - ,fifo.bFF_LoWatermarkInt ? "true" : "false" - ); - } + PanicAlert("Illegal command %02x\n" + "CPBase: 0x%08x\n" + "CPEnd: 0x%08x\n" + "CPHiWatermark: 0x%08x\n" + "CPLoWatermark: 0x%08x\n" + "CPReadWriteDistance: 0x%08x\n" + "CPWritePointer: 0x%08x\n" + "CPReadPointer: 0x%08x\n" + "CPBreakpoint: 0x%08x\n" + "bFF_GPReadEnable: %s\n" + "bFF_BPEnable: %s\n" + "bFF_BPInt: %s\n" + "bFF_Breakpoint: %s\n" + "bFF_GPLinkEnable: %s\n" + "bFF_HiWatermarkInt: %s\n" + "bFF_LoWatermarkInt: %s\n", + cmd_byte, fifo.CPBase, fifo.CPEnd, fifo.CPHiWatermark, fifo.CPLoWatermark, + fifo.CPReadWriteDistance, fifo.CPWritePointer, fifo.CPReadPointer, fifo.CPBreakpoint, + fifo.bFF_GPReadEnable ? "true" : "false", fifo.bFF_BPEnable ? "true" : "false", + fifo.bFF_BPInt ? "true" : "false", fifo.bFF_Breakpoint ? "true" : "false", + fifo.bFF_GPLinkEnable ? "true" : "false", fifo.bFF_HiWatermarkInt ? "true" : "false", + fifo.bFF_LoWatermarkInt ? "true" : "false"); + } } void Init() { - s_bFifoErrorSeen = false; + s_bFifoErrorSeen = false; } void Shutdown() @@ -135,188 +128,187 @@ void Shutdown() template u8* Run(DataReader src, u32* cycles, bool in_display_list) { - u32 totalCycles = 0; - u8* opcodeStart; - while (true) - { - opcodeStart = src.GetPointer(); + u32 totalCycles = 0; + u8* opcodeStart; + while (true) + { + opcodeStart = src.GetPointer(); - if (!src.size()) - goto end; + if (!src.size()) + goto end; - u8 cmd_byte = src.Read(); - int refarray; - switch (cmd_byte) - { - case GX_NOP: - totalCycles += 6; // Hm, this means that we scan over nop streams pretty slowly... - break; + u8 cmd_byte = src.Read(); + int refarray; + switch (cmd_byte) + { + case GX_NOP: + totalCycles += 6; // Hm, this means that we scan over nop streams pretty slowly... + break; - case GX_UNKNOWN_RESET: - totalCycles += 6; // Datel software uses this command - DEBUG_LOG(VIDEO, "GX Reset?: %08x", cmd_byte); - break; + case GX_UNKNOWN_RESET: + totalCycles += 6; // Datel software uses this command + DEBUG_LOG(VIDEO, "GX Reset?: %08x", cmd_byte); + break; - case GX_LOAD_CP_REG: - { - if (src.size() < 1 + 4) - goto end; - totalCycles += 12; - u8 sub_cmd = src.Read(); - u32 value = src.Read(); - LoadCPReg(sub_cmd, value, is_preprocess); - if (!is_preprocess) - INCSTAT(stats.thisFrame.numCPLoads); - } - break; + case GX_LOAD_CP_REG: + { + if (src.size() < 1 + 4) + goto end; + totalCycles += 12; + u8 sub_cmd = src.Read(); + u32 value = src.Read(); + LoadCPReg(sub_cmd, value, is_preprocess); + if (!is_preprocess) + INCSTAT(stats.thisFrame.numCPLoads); + } + break; - case GX_LOAD_XF_REG: - { - if (src.size() < 4) - goto end; - u32 Cmd2 = src.Read(); - int transfer_size = ((Cmd2 >> 16) & 15) + 1; - if (src.size() < transfer_size * sizeof(u32)) - goto end; - totalCycles += 18 + 6 * transfer_size; - if (!is_preprocess) - { - u32 xf_address = Cmd2 & 0xFFFF; - LoadXFReg(transfer_size, xf_address, src); + case GX_LOAD_XF_REG: + { + if (src.size() < 4) + goto end; + u32 Cmd2 = src.Read(); + int transfer_size = ((Cmd2 >> 16) & 15) + 1; + if (src.size() < transfer_size * sizeof(u32)) + goto end; + totalCycles += 18 + 6 * transfer_size; + if (!is_preprocess) + { + u32 xf_address = Cmd2 & 0xFFFF; + LoadXFReg(transfer_size, xf_address, src); - INCSTAT(stats.thisFrame.numXFLoads); - } - src.Skip(transfer_size); - } - break; + INCSTAT(stats.thisFrame.numXFLoads); + } + src.Skip(transfer_size); + } + break; - case GX_LOAD_INDX_A: //used for position matrices - refarray = 0xC; - goto load_indx; - case GX_LOAD_INDX_B: //used for normal matrices - refarray = 0xD; - goto load_indx; - case GX_LOAD_INDX_C: //used for postmatrices - refarray = 0xE; - goto load_indx; - case GX_LOAD_INDX_D: //used for lights - refarray = 0xF; - goto load_indx; - load_indx: - if (src.size() < 4) - goto end; - totalCycles += 6; - if (is_preprocess) - PreprocessIndexedXF(src.Read(), refarray); - else - LoadIndexedXF(src.Read(), refarray); - break; + case GX_LOAD_INDX_A: // used for position matrices + refarray = 0xC; + goto load_indx; + case GX_LOAD_INDX_B: // used for normal matrices + refarray = 0xD; + goto load_indx; + case GX_LOAD_INDX_C: // used for postmatrices + refarray = 0xE; + goto load_indx; + case GX_LOAD_INDX_D: // used for lights + refarray = 0xF; + goto load_indx; + load_indx: + if (src.size() < 4) + goto end; + totalCycles += 6; + if (is_preprocess) + PreprocessIndexedXF(src.Read(), refarray); + else + LoadIndexedXF(src.Read(), refarray); + break; - case GX_CMD_CALL_DL: - { - if (src.size() < 8) - goto end; - u32 address = src.Read(); - u32 count = src.Read(); + case GX_CMD_CALL_DL: + { + if (src.size() < 8) + goto end; + u32 address = src.Read(); + u32 count = src.Read(); - if (in_display_list) - { - totalCycles += 6; - WARN_LOG(VIDEO,"recursive display list detected"); - } - else - { - if (is_preprocess) - InterpretDisplayListPreprocess(address, count); - else - totalCycles += 6 + InterpretDisplayList(address, count); - } - } - break; + if (in_display_list) + { + totalCycles += 6; + WARN_LOG(VIDEO, "recursive display list detected"); + } + else + { + if (is_preprocess) + InterpretDisplayListPreprocess(address, count); + else + totalCycles += 6 + InterpretDisplayList(address, count); + } + } + break; - case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that - totalCycles += 6; - DEBUG_LOG(VIDEO, "GX 0x44: %08x", cmd_byte); - break; + case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after + // that + totalCycles += 6; + DEBUG_LOG(VIDEO, "GX 0x44: %08x", cmd_byte); + break; - case GX_CMD_INVL_VC: // Invalidate Vertex Cache - totalCycles += 6; - DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)"); - break; + case GX_CMD_INVL_VC: // Invalidate Vertex Cache + totalCycles += 6; + DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)"); + break; - case GX_LOAD_BP_REG: - // In skipped_frame case: We have to let BP writes through because they set - // tokens and stuff. TODO: Call a much simplified LoadBPReg instead. - { - if (src.size() < 4) - goto end; - totalCycles += 12; - u32 bp_cmd = src.Read(); - if (is_preprocess) - { - LoadBPRegPreprocess(bp_cmd); - } - else - { - LoadBPReg(bp_cmd); - INCSTAT(stats.thisFrame.numBPLoads); - } - } - break; + case GX_LOAD_BP_REG: + // In skipped_frame case: We have to let BP writes through because they set + // tokens and stuff. TODO: Call a much simplified LoadBPReg instead. + { + if (src.size() < 4) + goto end; + totalCycles += 12; + u32 bp_cmd = src.Read(); + if (is_preprocess) + { + LoadBPRegPreprocess(bp_cmd); + } + else + { + LoadBPReg(bp_cmd); + INCSTAT(stats.thisFrame.numBPLoads); + } + } + break; - // draw primitives - default: - if ((cmd_byte & 0xC0) == 0x80) - { - // load vertices - if (src.size() < 2) - goto end; - u16 num_vertices = src.Read(); - int bytes = VertexLoaderManager::RunVertices( - cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7) - (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, - num_vertices, - src, - Fifo::WillSkipCurrentFrame(), - is_preprocess); + // draw primitives + default: + if ((cmd_byte & 0xC0) == 0x80) + { + // load vertices + if (src.size() < 2) + goto end; + u16 num_vertices = src.Read(); + int bytes = VertexLoaderManager::RunVertices( + cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7) + (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, num_vertices, src, + Fifo::WillSkipCurrentFrame(), is_preprocess); - if (bytes < 0) - goto end; + if (bytes < 0) + goto end; - src.Skip(bytes); + src.Skip(bytes); - // 4 GPU ticks per vertex, 3 CPU ticks per GPU tick - totalCycles += num_vertices * 4 * 3 + 6; - } - else - { - if (!s_bFifoErrorSeen) - UnknownOpcode(cmd_byte, opcodeStart, is_preprocess); - ERROR_LOG(VIDEO, "FIFO: Unknown Opcode(0x%02x @ %p, preprocessing = %s)", cmd_byte, opcodeStart, is_preprocess ? "yes" : "no"); - s_bFifoErrorSeen = true; - totalCycles += 1; - } - break; - } + // 4 GPU ticks per vertex, 3 CPU ticks per GPU tick + totalCycles += num_vertices * 4 * 3 + 6; + } + else + { + if (!s_bFifoErrorSeen) + UnknownOpcode(cmd_byte, opcodeStart, is_preprocess); + ERROR_LOG(VIDEO, "FIFO: Unknown Opcode(0x%02x @ %p, preprocessing = %s)", cmd_byte, + opcodeStart, is_preprocess ? "yes" : "no"); + s_bFifoErrorSeen = true; + totalCycles += 1; + } + break; + } - // Display lists get added directly into the FIFO stream - if (!is_preprocess && g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL) - { - u8* opcodeEnd; - opcodeEnd = src.GetPointer(); - FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(opcodeEnd - opcodeStart)); - } - } + // Display lists get added directly into the FIFO stream + if (!is_preprocess && g_bRecordFifoData && cmd_byte != GX_CMD_CALL_DL) + { + u8* opcodeEnd; + opcodeEnd = src.GetPointer(); + FifoRecorder::GetInstance().WriteGPCommand(opcodeStart, u32(opcodeEnd - opcodeStart)); + } + } end: - if (cycles) - { - *cycles = totalCycles; - } - return opcodeStart; + if (cycles) + { + *cycles = totalCycles; + } + return opcodeStart; } template u8* Run(DataReader src, u32* cycles, bool in_display_list); template u8* Run(DataReader src, u32* cycles, bool in_display_list); -} // namespace OpcodeDecoder +} // namespace OpcodeDecoder diff --git a/Source/Core/VideoCommon/OpcodeDecoding.h b/Source/Core/VideoCommon/OpcodeDecoding.h index 0cebc13cf9..13a68548d2 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.h +++ b/Source/Core/VideoCommon/OpcodeDecoding.h @@ -8,44 +8,43 @@ class DataReader; -#define GX_NOP 0x00 -#define GX_UNKNOWN_RESET 0x01 +#define GX_NOP 0x00 +#define GX_UNKNOWN_RESET 0x01 -#define GX_LOAD_BP_REG 0x61 -#define GX_LOAD_CP_REG 0x08 -#define GX_LOAD_XF_REG 0x10 -#define GX_LOAD_INDX_A 0x20 -#define GX_LOAD_INDX_B 0x28 -#define GX_LOAD_INDX_C 0x30 -#define GX_LOAD_INDX_D 0x38 +#define GX_LOAD_BP_REG 0x61 +#define GX_LOAD_CP_REG 0x08 +#define GX_LOAD_XF_REG 0x10 +#define GX_LOAD_INDX_A 0x20 +#define GX_LOAD_INDX_B 0x28 +#define GX_LOAD_INDX_C 0x30 +#define GX_LOAD_INDX_D 0x38 -#define GX_CMD_CALL_DL 0x40 -#define GX_CMD_UNKNOWN_METRICS 0x44 -#define GX_CMD_INVL_VC 0x48 +#define GX_CMD_CALL_DL 0x40 +#define GX_CMD_UNKNOWN_METRICS 0x44 +#define GX_CMD_INVL_VC 0x48 -#define GX_PRIMITIVE_MASK 0x78 -#define GX_PRIMITIVE_SHIFT 3 -#define GX_VAT_MASK 0x07 +#define GX_PRIMITIVE_MASK 0x78 +#define GX_PRIMITIVE_SHIFT 3 +#define GX_VAT_MASK 0x07 // These values are the values extracted using GX_PRIMITIVE_MASK // and GX_PRIMITIVE_SHIFT. // GX_DRAW_QUADS_2 behaves the same way as GX_DRAW_QUADS. -#define GX_DRAW_QUADS 0x0 // 0x80 -#define GX_DRAW_QUADS_2 0x1 // 0x88 -#define GX_DRAW_TRIANGLES 0x2 // 0x90 -#define GX_DRAW_TRIANGLE_STRIP 0x3 // 0x98 -#define GX_DRAW_TRIANGLE_FAN 0x4 // 0xA0 -#define GX_DRAW_LINES 0x5 // 0xA8 -#define GX_DRAW_LINE_STRIP 0x6 // 0xB0 -#define GX_DRAW_POINTS 0x7 // 0xB8 +#define GX_DRAW_QUADS 0x0 // 0x80 +#define GX_DRAW_QUADS_2 0x1 // 0x88 +#define GX_DRAW_TRIANGLES 0x2 // 0x90 +#define GX_DRAW_TRIANGLE_STRIP 0x3 // 0x98 +#define GX_DRAW_TRIANGLE_FAN 0x4 // 0xA0 +#define GX_DRAW_LINES 0x5 // 0xA8 +#define GX_DRAW_LINE_STRIP 0x6 // 0xB0 +#define GX_DRAW_POINTS 0x7 // 0xB8 namespace OpcodeDecoder { - void Init(); void Shutdown(); template u8* Run(DataReader src, u32* cycles, bool in_display_list); -} // namespace OpcodeDecoder +} // namespace OpcodeDecoder diff --git a/Source/Core/VideoCommon/PerfQueryBase.cpp b/Source/Core/VideoCommon/PerfQueryBase.cpp index fc5e9dd38e..c87bb43499 100644 --- a/Source/Core/VideoCommon/PerfQueryBase.cpp +++ b/Source/Core/VideoCommon/PerfQueryBase.cpp @@ -2,13 +2,13 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include #include "VideoCommon/PerfQueryBase.h" +#include #include "VideoCommon/VideoConfig.h" std::unique_ptr g_perf_query; bool PerfQueryBase::ShouldEmulate() { - return g_ActiveConfig.bPerfQueriesEnable; + return g_ActiveConfig.bPerfQueriesEnable; } diff --git a/Source/Core/VideoCommon/PerfQueryBase.h b/Source/Core/VideoCommon/PerfQueryBase.h index 705a81621c..ea74c2d57a 100644 --- a/Source/Core/VideoCommon/PerfQueryBase.h +++ b/Source/Core/VideoCommon/PerfQueryBase.h @@ -9,61 +9,51 @@ enum PerfQueryType { - PQ_ZCOMP_INPUT_ZCOMPLOC = 0, - PQ_ZCOMP_OUTPUT_ZCOMPLOC, - PQ_ZCOMP_INPUT, - PQ_ZCOMP_OUTPUT, - PQ_BLEND_INPUT, - PQ_EFB_COPY_CLOCKS, - PQ_NUM_MEMBERS + PQ_ZCOMP_INPUT_ZCOMPLOC = 0, + PQ_ZCOMP_OUTPUT_ZCOMPLOC, + PQ_ZCOMP_INPUT, + PQ_ZCOMP_OUTPUT, + PQ_BLEND_INPUT, + PQ_EFB_COPY_CLOCKS, + PQ_NUM_MEMBERS }; enum PerfQueryGroup { - PQG_ZCOMP_ZCOMPLOC, - PQG_ZCOMP, - PQG_EFB_COPY_CLOCKS, - PQG_NUM_MEMBERS, + PQG_ZCOMP_ZCOMPLOC, + PQG_ZCOMP, + PQG_EFB_COPY_CLOCKS, + PQG_NUM_MEMBERS, }; class PerfQueryBase { public: - PerfQueryBase() - : m_query_count(0) - { - } - - virtual ~PerfQueryBase() {} - - // Checks if performance queries are enabled in the gameini configuration. - // NOTE: Called from CPU+GPU thread - static bool ShouldEmulate(); - - // Begin querying the specified value for the following host GPU commands - virtual void EnableQuery(PerfQueryGroup type) {} - - // Stop querying the specified value for the following host GPU commands - virtual void DisableQuery(PerfQueryGroup type) {} - - // Reset query counters to zero and drop any pending queries - virtual void ResetQuery() {} - - // Return the measured value for the specified query type - // NOTE: Called from CPU thread - virtual u32 GetQueryResult(PerfQueryType type) { return 0; } - - // Request the value of any pending queries - causes a pipeline flush and thus should be used carefully! - virtual void FlushResults() {} - - // True if there are no further pending query results - // NOTE: Called from CPU thread - virtual bool IsFlushed() const { return true; } + PerfQueryBase() : m_query_count(0) {} + virtual ~PerfQueryBase() {} + // Checks if performance queries are enabled in the gameini configuration. + // NOTE: Called from CPU+GPU thread + static bool ShouldEmulate(); + // Begin querying the specified value for the following host GPU commands + virtual void EnableQuery(PerfQueryGroup type) {} + // Stop querying the specified value for the following host GPU commands + virtual void DisableQuery(PerfQueryGroup type) {} + // Reset query counters to zero and drop any pending queries + virtual void ResetQuery() {} + // Return the measured value for the specified query type + // NOTE: Called from CPU thread + virtual u32 GetQueryResult(PerfQueryType type) { return 0; } + // Request the value of any pending queries - causes a pipeline flush and thus should be used + // carefully! + virtual void FlushResults() {} + // True if there are no further pending query results + // NOTE: Called from CPU thread + virtual bool IsFlushed() const { return true; } protected: - // TODO: sloppy - volatile u32 m_query_count; - volatile u32 m_results[PQG_NUM_MEMBERS]; + // TODO: sloppy + volatile u32 m_query_count; + volatile u32 m_results[PQG_NUM_MEMBERS]; }; extern std::unique_ptr g_perf_query; diff --git a/Source/Core/VideoCommon/PixelEngine.cpp b/Source/Core/VideoCommon/PixelEngine.cpp index 50620e22e3..3a223619c1 100644 --- a/Source/Core/VideoCommon/PixelEngine.cpp +++ b/Source/Core/VideoCommon/PixelEngine.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // http://www.nvidia.com/object/General_FAQ.html#t6 !!!!! #include @@ -23,81 +22,75 @@ namespace PixelEngine { - -union UPEZConfReg -{ - u16 Hex; - struct - { - u16 ZCompEnable : 1; // Z Comparator Enable - u16 Function : 3; - u16 ZUpdEnable : 1; - u16 : 11; - }; +union UPEZConfReg { + u16 Hex; + struct + { + u16 ZCompEnable : 1; // Z Comparator Enable + u16 Function : 3; + u16 ZUpdEnable : 1; + u16 : 11; + }; }; -union UPEAlphaConfReg -{ - u16 Hex; - struct - { - u16 BMMath : 1; // GX_BM_BLEND || GX_BM_SUBSTRACT - u16 BMLogic : 1; // GX_BM_LOGIC - u16 Dither : 1; - u16 ColorUpdEnable : 1; - u16 AlphaUpdEnable : 1; - u16 DstFactor : 3; - u16 SrcFactor : 3; - u16 Substract : 1; // Additive mode by default - u16 BlendOperator : 4; - }; +union UPEAlphaConfReg { + u16 Hex; + struct + { + u16 BMMath : 1; // GX_BM_BLEND || GX_BM_SUBSTRACT + u16 BMLogic : 1; // GX_BM_LOGIC + u16 Dither : 1; + u16 ColorUpdEnable : 1; + u16 AlphaUpdEnable : 1; + u16 DstFactor : 3; + u16 SrcFactor : 3; + u16 Substract : 1; // Additive mode by default + u16 BlendOperator : 4; + }; }; -union UPEDstAlphaConfReg -{ - u16 Hex; - struct - { - u16 DstAlpha : 8; - u16 Enable : 1; - u16 : 7; - }; +union UPEDstAlphaConfReg { + u16 Hex; + struct + { + u16 DstAlpha : 8; + u16 Enable : 1; + u16 : 7; + }; }; -union UPEAlphaModeConfReg -{ - u16 Hex; - struct - { - u16 Threshold : 8; - u16 CompareMode : 8; - }; +union UPEAlphaModeConfReg { + u16 Hex; + struct + { + u16 Threshold : 8; + u16 CompareMode : 8; + }; }; // fifo Control Register -union UPECtrlReg -{ - struct - { - u16 PETokenEnable : 1; - u16 PEFinishEnable : 1; - u16 PEToken : 1; // write only - u16 PEFinish : 1; // write only - u16 : 12; - }; - u16 Hex; - UPECtrlReg() {Hex = 0; } - UPECtrlReg(u16 _hex) {Hex = _hex; } +union UPECtrlReg { + struct + { + u16 PETokenEnable : 1; + u16 PEFinishEnable : 1; + u16 PEToken : 1; // write only + u16 PEFinish : 1; // write only + u16 : 12; + }; + u16 Hex; + UPECtrlReg() { Hex = 0; } + UPECtrlReg(u16 _hex) { Hex = _hex; } }; // STATE_TO_SAVE -static UPEZConfReg m_ZConf; -static UPEAlphaConfReg m_AlphaConf; -static UPEDstAlphaConfReg m_DstAlphaConf; +static UPEZConfReg m_ZConf; +static UPEAlphaConfReg m_AlphaConf; +static UPEDstAlphaConfReg m_DstAlphaConf; static UPEAlphaModeConfReg m_AlphaModeConf; -static UPEAlphaReadReg m_AlphaRead; -static UPECtrlReg m_Control; -//static u16 m_Token; // token value most recently encountered +static UPEAlphaReadReg m_AlphaRead; +static UPECtrlReg m_Control; +// static u16 m_Token; // token value most recently encountered static std::atomic s_signal_token_interrupt; static std::atomic s_signal_finish_interrupt; @@ -107,21 +100,21 @@ static int et_SetFinishOnMainThread; enum { - INT_CAUSE_PE_TOKEN = 0x200, // GP Token - INT_CAUSE_PE_FINISH = 0x400, // GP Finished + INT_CAUSE_PE_TOKEN = 0x200, // GP Token + INT_CAUSE_PE_FINISH = 0x400, // GP Finished }; -void DoState(PointerWrap &p) +void DoState(PointerWrap& p) { - p.Do(m_ZConf); - p.Do(m_AlphaConf); - p.Do(m_DstAlphaConf); - p.Do(m_AlphaModeConf); - p.Do(m_AlphaRead); - p.DoPOD(m_Control); + p.Do(m_ZConf); + p.Do(m_AlphaConf); + p.Do(m_DstAlphaConf); + p.Do(m_AlphaModeConf); + p.Do(m_AlphaRead); + p.DoPOD(m_Control); - p.Do(s_signal_token_interrupt); - p.Do(s_signal_finish_interrupt); + p.Do(s_signal_token_interrupt); + p.Do(s_signal_finish_interrupt); } static void UpdateInterrupts(); @@ -132,128 +125,118 @@ static void SetFinish_OnMainThread(u64 userdata, s64 cyclesLate); void Init() { - m_Control.Hex = 0; - m_ZConf.Hex = 0; - m_AlphaConf.Hex = 0; - m_DstAlphaConf.Hex = 0; - m_AlphaModeConf.Hex = 0; - m_AlphaRead.Hex = 0; + m_Control.Hex = 0; + m_ZConf.Hex = 0; + m_AlphaConf.Hex = 0; + m_DstAlphaConf.Hex = 0; + m_AlphaModeConf.Hex = 0; + m_AlphaRead.Hex = 0; - s_signal_token_interrupt.store(0); - s_signal_finish_interrupt.store(0); + s_signal_token_interrupt.store(0); + s_signal_finish_interrupt.store(0); - et_SetTokenOnMainThread = CoreTiming::RegisterEvent("SetToken", SetToken_OnMainThread); - et_SetFinishOnMainThread = CoreTiming::RegisterEvent("SetFinish", SetFinish_OnMainThread); + et_SetTokenOnMainThread = CoreTiming::RegisterEvent("SetToken", SetToken_OnMainThread); + et_SetFinishOnMainThread = CoreTiming::RegisterEvent("SetFinish", SetFinish_OnMainThread); } void RegisterMMIO(MMIO::Mapping* mmio, u32 base) { - // Directly mapped registers. - struct { - u32 addr; - u16* ptr; - } directly_mapped_vars[] = { - { PE_ZCONF, &m_ZConf.Hex }, - { PE_ALPHACONF, &m_AlphaConf.Hex }, - { PE_DSTALPHACONF, &m_DstAlphaConf.Hex }, - { PE_ALPHAMODE, &m_AlphaModeConf.Hex }, - { PE_ALPHAREAD, &m_AlphaRead.Hex }, - }; - for (auto& mapped_var : directly_mapped_vars) - { - mmio->Register(base | mapped_var.addr, - MMIO::DirectRead(mapped_var.ptr), - MMIO::DirectWrite(mapped_var.ptr) - ); - } + // Directly mapped registers. + struct + { + u32 addr; + u16* ptr; + } directly_mapped_vars[] = { + {PE_ZCONF, &m_ZConf.Hex}, + {PE_ALPHACONF, &m_AlphaConf.Hex}, + {PE_DSTALPHACONF, &m_DstAlphaConf.Hex}, + {PE_ALPHAMODE, &m_AlphaModeConf.Hex}, + {PE_ALPHAREAD, &m_AlphaRead.Hex}, + }; + for (auto& mapped_var : directly_mapped_vars) + { + mmio->Register(base | mapped_var.addr, MMIO::DirectRead(mapped_var.ptr), + MMIO::DirectWrite(mapped_var.ptr)); + } - // Performance queries registers: read only, need to call the video backend - // to get the results. - struct { - u32 addr; - PerfQueryType pqtype; - } pq_regs[] = { - { PE_PERF_ZCOMP_INPUT_ZCOMPLOC_L, PQ_ZCOMP_INPUT_ZCOMPLOC }, - { PE_PERF_ZCOMP_OUTPUT_ZCOMPLOC_L, PQ_ZCOMP_OUTPUT_ZCOMPLOC }, - { PE_PERF_ZCOMP_INPUT_L, PQ_ZCOMP_INPUT }, - { PE_PERF_ZCOMP_OUTPUT_L, PQ_ZCOMP_OUTPUT }, - { PE_PERF_BLEND_INPUT_L, PQ_BLEND_INPUT }, - { PE_PERF_EFB_COPY_CLOCKS_L, PQ_EFB_COPY_CLOCKS }, - }; - for (auto& pq_reg : pq_regs) - { - mmio->Register(base | pq_reg.addr, - MMIO::ComplexRead([pq_reg](u32) { - return g_video_backend->Video_GetQueryResult(pq_reg.pqtype) & 0xFFFF; - }), - MMIO::InvalidWrite() - ); - mmio->Register(base | (pq_reg.addr + 2), - MMIO::ComplexRead([pq_reg](u32) { - return g_video_backend->Video_GetQueryResult(pq_reg.pqtype) >> 16; - }), - MMIO::InvalidWrite() - ); - } + // Performance queries registers: read only, need to call the video backend + // to get the results. + struct + { + u32 addr; + PerfQueryType pqtype; + } pq_regs[] = { + {PE_PERF_ZCOMP_INPUT_ZCOMPLOC_L, PQ_ZCOMP_INPUT_ZCOMPLOC}, + {PE_PERF_ZCOMP_OUTPUT_ZCOMPLOC_L, PQ_ZCOMP_OUTPUT_ZCOMPLOC}, + {PE_PERF_ZCOMP_INPUT_L, PQ_ZCOMP_INPUT}, + {PE_PERF_ZCOMP_OUTPUT_L, PQ_ZCOMP_OUTPUT}, + {PE_PERF_BLEND_INPUT_L, PQ_BLEND_INPUT}, + {PE_PERF_EFB_COPY_CLOCKS_L, PQ_EFB_COPY_CLOCKS}, + }; + for (auto& pq_reg : pq_regs) + { + mmio->Register(base | pq_reg.addr, MMIO::ComplexRead([pq_reg](u32) { + return g_video_backend->Video_GetQueryResult(pq_reg.pqtype) & 0xFFFF; + }), + MMIO::InvalidWrite()); + mmio->Register(base | (pq_reg.addr + 2), MMIO::ComplexRead([pq_reg](u32) { + return g_video_backend->Video_GetQueryResult(pq_reg.pqtype) >> 16; + }), + MMIO::InvalidWrite()); + } - // Control register - mmio->Register(base | PE_CTRL_REGISTER, - MMIO::DirectRead(&m_Control.Hex), - MMIO::ComplexWrite([](u32, u16 val) { - UPECtrlReg tmpCtrl(val); + // Control register + mmio->Register(base | PE_CTRL_REGISTER, MMIO::DirectRead(&m_Control.Hex), + MMIO::ComplexWrite([](u32, u16 val) { + UPECtrlReg tmpCtrl(val); - if (tmpCtrl.PEToken) - s_signal_token_interrupt.store(0); + if (tmpCtrl.PEToken) + s_signal_token_interrupt.store(0); - if (tmpCtrl.PEFinish) - s_signal_finish_interrupt.store(0); + if (tmpCtrl.PEFinish) + s_signal_finish_interrupt.store(0); - m_Control.PETokenEnable = tmpCtrl.PETokenEnable; - m_Control.PEFinishEnable = tmpCtrl.PEFinishEnable; - m_Control.PEToken = 0; // this flag is write only - m_Control.PEFinish = 0; // this flag is write only + m_Control.PETokenEnable = tmpCtrl.PETokenEnable; + m_Control.PEFinishEnable = tmpCtrl.PEFinishEnable; + m_Control.PEToken = 0; // this flag is write only + m_Control.PEFinish = 0; // this flag is write only - DEBUG_LOG(PIXELENGINE, "(w16) CTRL_REGISTER: 0x%04x", val); - UpdateInterrupts(); - }) - ); + DEBUG_LOG(PIXELENGINE, "(w16) CTRL_REGISTER: 0x%04x", val); + UpdateInterrupts(); + })); - // Token register, readonly. - mmio->Register(base | PE_TOKEN_REG, - MMIO::DirectRead(&CommandProcessor::fifo.PEToken), - MMIO::InvalidWrite() - ); + // Token register, readonly. + mmio->Register(base | PE_TOKEN_REG, MMIO::DirectRead(&CommandProcessor::fifo.PEToken), + MMIO::InvalidWrite()); - // BBOX registers, readonly and need to update a flag. - for (int i = 0; i < 4; ++i) - { - mmio->Register(base | (PE_BBOX_LEFT + 2 * i), - MMIO::ComplexRead([i](u32) { - BoundingBox::active = false; - return g_video_backend->Video_GetBoundingBox(i); - }), - MMIO::InvalidWrite() - ); - } + // BBOX registers, readonly and need to update a flag. + for (int i = 0; i < 4; ++i) + { + mmio->Register(base | (PE_BBOX_LEFT + 2 * i), MMIO::ComplexRead([i](u32) { + BoundingBox::active = false; + return g_video_backend->Video_GetBoundingBox(i); + }), + MMIO::InvalidWrite()); + } } static void UpdateInterrupts() { - // check if there is a token-interrupt - UpdateTokenInterrupt((s_signal_token_interrupt.load() & m_Control.PETokenEnable) != 0); + // check if there is a token-interrupt + UpdateTokenInterrupt((s_signal_token_interrupt.load() & m_Control.PETokenEnable) != 0); - // check if there is a finish-interrupt - UpdateFinishInterrupt((s_signal_finish_interrupt.load() & m_Control.PEFinishEnable) != 0); + // check if there is a finish-interrupt + UpdateFinishInterrupt((s_signal_finish_interrupt.load() & m_Control.PEFinishEnable) != 0); } static void UpdateTokenInterrupt(bool active) { - ProcessorInterface::SetInterrupt(INT_CAUSE_PE_TOKEN, active); + ProcessorInterface::SetInterrupt(INT_CAUSE_PE_TOKEN, active); } static void UpdateFinishInterrupt(bool active) { - ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH, active); + ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH, active); } // TODO(mb2): Refactor SetTokenINT_OnMainThread(u64 userdata, int cyclesLate). @@ -263,62 +246,64 @@ static void UpdateFinishInterrupt(bool active) // Called only if BPMEM_PE_TOKEN_INT_ID is ack by GP static void SetToken_OnMainThread(u64 userdata, s64 cyclesLate) { - // XXX: No 16-bit atomic store available, so cheat and use 32-bit. - // That's what we've always done. We're counting on fifo.PEToken to be - // 4-byte padded. - Common::AtomicStore(*(volatile u32*)&CommandProcessor::fifo.PEToken, userdata & 0xffff); - INFO_LOG(PIXELENGINE, "VIDEO Backend raises INT_CAUSE_PE_TOKEN (btw, token: %04x)", CommandProcessor::fifo.PEToken); - if (userdata >> 16) - { - s_signal_token_interrupt.store(1); - UpdateInterrupts(); - } - CommandProcessor::SetInterruptTokenWaiting(false); + // XXX: No 16-bit atomic store available, so cheat and use 32-bit. + // That's what we've always done. We're counting on fifo.PEToken to be + // 4-byte padded. + Common::AtomicStore(*(volatile u32*)&CommandProcessor::fifo.PEToken, userdata & 0xffff); + INFO_LOG(PIXELENGINE, "VIDEO Backend raises INT_CAUSE_PE_TOKEN (btw, token: %04x)", + CommandProcessor::fifo.PEToken); + if (userdata >> 16) + { + s_signal_token_interrupt.store(1); + UpdateInterrupts(); + } + CommandProcessor::SetInterruptTokenWaiting(false); } static void SetFinish_OnMainThread(u64 userdata, s64 cyclesLate) { - s_signal_finish_interrupt.store(1); - UpdateInterrupts(); - CommandProcessor::SetInterruptFinishWaiting(false); + s_signal_finish_interrupt.store(1); + UpdateInterrupts(); + CommandProcessor::SetInterruptFinishWaiting(false); - Core::FrameUpdateOnCPUThread(); + Core::FrameUpdateOnCPUThread(); } // SetToken // THIS IS EXECUTED FROM VIDEO THREAD void SetToken(const u16 _token, const int _bSetTokenAcknowledge) { - if (_bSetTokenAcknowledge) // set token INT - { - s_signal_token_interrupt.store(1); - } + if (_bSetTokenAcknowledge) // set token INT + { + s_signal_token_interrupt.store(1); + } - CommandProcessor::SetInterruptTokenWaiting(true); + CommandProcessor::SetInterruptTokenWaiting(true); - if (!SConfig::GetInstance().bCPUThread || Fifo::UseDeterministicGPUThread()) - CoreTiming::ScheduleEvent(0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16)); - else - CoreTiming::ScheduleEvent_Threadsafe(0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16)); + if (!SConfig::GetInstance().bCPUThread || Fifo::UseDeterministicGPUThread()) + CoreTiming::ScheduleEvent(0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16)); + else + CoreTiming::ScheduleEvent_Threadsafe(0, et_SetTokenOnMainThread, + _token | (_bSetTokenAcknowledge << 16)); } // SetFinish // THIS IS EXECUTED FROM VIDEO THREAD (BPStructs.cpp) when a new frame has been drawn void SetFinish() { - CommandProcessor::SetInterruptFinishWaiting(true); + CommandProcessor::SetInterruptFinishWaiting(true); - if (!SConfig::GetInstance().bCPUThread || Fifo::UseDeterministicGPUThread()) - CoreTiming::ScheduleEvent(0, et_SetFinishOnMainThread, 0); - else - CoreTiming::ScheduleEvent_Threadsafe(0, et_SetFinishOnMainThread, 0); + if (!SConfig::GetInstance().bCPUThread || Fifo::UseDeterministicGPUThread()) + CoreTiming::ScheduleEvent(0, et_SetFinishOnMainThread, 0); + else + CoreTiming::ScheduleEvent_Threadsafe(0, et_SetFinishOnMainThread, 0); - INFO_LOG(PIXELENGINE, "VIDEO Set Finish"); + INFO_LOG(PIXELENGINE, "VIDEO Set Finish"); } UPEAlphaReadReg GetAlphaReadMode() { - return m_AlphaRead; + return m_AlphaRead; } -} // end of namespace PixelEngine +} // end of namespace PixelEngine diff --git a/Source/Core/VideoCommon/PixelEngine.h b/Source/Core/VideoCommon/PixelEngine.h index 501974ef2b..df978a2673 100644 --- a/Source/Core/VideoCommon/PixelEngine.h +++ b/Source/Core/VideoCommon/PixelEngine.h @@ -6,55 +6,57 @@ #include "Common/CommonTypes.h" class PointerWrap; -namespace MMIO { class Mapping; } +namespace MMIO +{ +class Mapping; +} // internal hardware addresses enum { - PE_ZCONF = 0x00, // Z Config - PE_ALPHACONF = 0x02, // Alpha Config - PE_DSTALPHACONF = 0x04, // Destination Alpha Config - PE_ALPHAMODE = 0x06, // Alpha Mode Config - PE_ALPHAREAD = 0x08, // Alpha Read - PE_CTRL_REGISTER = 0x0a, // Control - PE_TOKEN_REG = 0x0e, // Token - PE_BBOX_LEFT = 0x10, // Bounding Box Left Pixel - PE_BBOX_RIGHT = 0x12, // Bounding Box Right Pixel - PE_BBOX_TOP = 0x14, // Bounding Box Top Pixel - PE_BBOX_BOTTOM = 0x16, // Bounding Box Bottom Pixel + PE_ZCONF = 0x00, // Z Config + PE_ALPHACONF = 0x02, // Alpha Config + PE_DSTALPHACONF = 0x04, // Destination Alpha Config + PE_ALPHAMODE = 0x06, // Alpha Mode Config + PE_ALPHAREAD = 0x08, // Alpha Read + PE_CTRL_REGISTER = 0x0a, // Control + PE_TOKEN_REG = 0x0e, // Token + PE_BBOX_LEFT = 0x10, // Bounding Box Left Pixel + PE_BBOX_RIGHT = 0x12, // Bounding Box Right Pixel + PE_BBOX_TOP = 0x14, // Bounding Box Top Pixel + PE_BBOX_BOTTOM = 0x16, // Bounding Box Bottom Pixel - // NOTE: Order not verified - // These indicate the number of quads that are being used as input/output for each particular stage - PE_PERF_ZCOMP_INPUT_ZCOMPLOC_L = 0x18, - PE_PERF_ZCOMP_INPUT_ZCOMPLOC_H = 0x1a, - PE_PERF_ZCOMP_OUTPUT_ZCOMPLOC_L = 0x1c, - PE_PERF_ZCOMP_OUTPUT_ZCOMPLOC_H = 0x1e, - PE_PERF_ZCOMP_INPUT_L = 0x20, - PE_PERF_ZCOMP_INPUT_H = 0x22, - PE_PERF_ZCOMP_OUTPUT_L = 0x24, - PE_PERF_ZCOMP_OUTPUT_H = 0x26, - PE_PERF_BLEND_INPUT_L = 0x28, - PE_PERF_BLEND_INPUT_H = 0x2a, - PE_PERF_EFB_COPY_CLOCKS_L = 0x2c, - PE_PERF_EFB_COPY_CLOCKS_H = 0x2e, + // NOTE: Order not verified + // These indicate the number of quads that are being used as input/output for each particular + // stage + PE_PERF_ZCOMP_INPUT_ZCOMPLOC_L = 0x18, + PE_PERF_ZCOMP_INPUT_ZCOMPLOC_H = 0x1a, + PE_PERF_ZCOMP_OUTPUT_ZCOMPLOC_L = 0x1c, + PE_PERF_ZCOMP_OUTPUT_ZCOMPLOC_H = 0x1e, + PE_PERF_ZCOMP_INPUT_L = 0x20, + PE_PERF_ZCOMP_INPUT_H = 0x22, + PE_PERF_ZCOMP_OUTPUT_L = 0x24, + PE_PERF_ZCOMP_OUTPUT_H = 0x26, + PE_PERF_BLEND_INPUT_L = 0x28, + PE_PERF_BLEND_INPUT_H = 0x2a, + PE_PERF_EFB_COPY_CLOCKS_L = 0x2c, + PE_PERF_EFB_COPY_CLOCKS_H = 0x2e, }; namespace PixelEngine { - // ReadMode specifies the returned alpha channel for EFB peeks -union UPEAlphaReadReg -{ - u16 Hex; - struct - { - u16 ReadMode : 2; - u16 : 14; - }; +union UPEAlphaReadReg { + u16 Hex; + struct + { + u16 ReadMode : 2; + u16 : 14; + }; }; void Init(); -void DoState(PointerWrap &p); +void DoState(PointerWrap& p); void RegisterMMIO(MMIO::Mapping* mmio, u32 base); @@ -63,4 +65,4 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge); void SetFinish(); UPEAlphaReadReg GetAlphaReadMode(); -} // end of namespace PixelEngine +} // end of namespace PixelEngine diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index dafed0ded7..e284e58347 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -9,8 +9,8 @@ #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" -#include "VideoCommon/BoundingBox.h" #include "VideoCommon/BPMemory.h" +#include "VideoCommon/BoundingBox.h" #include "VideoCommon/DriverDetails.h" #include "VideoCommon/LightingShaderGen.h" #include "VideoCommon/PixelShaderGen.h" @@ -21,1151 +21,1196 @@ // TODO: Get rid of these enum : u32 { - C_COLORMATRIX = 0, // 0 - C_COLORS = 0, // 0 - C_KCOLORS = C_COLORS + 4, // 4 - C_ALPHA = C_KCOLORS + 4, // 8 - C_TEXDIMS = C_ALPHA + 1, // 9 - C_ZBIAS = C_TEXDIMS + 8, // 17 - C_INDTEXSCALE = C_ZBIAS + 2, // 19 - C_INDTEXMTX = C_INDTEXSCALE + 2, // 21 - C_FOGCOLOR = C_INDTEXMTX + 6, // 27 - C_FOGI = C_FOGCOLOR + 1, // 28 - C_FOGF = C_FOGI + 1, // 29 - C_ZSLOPE = C_FOGF + 2, // 31 - C_EFBSCALE = C_ZSLOPE + 1, // 32 - C_PENVCONST_END = C_EFBSCALE + 1 + C_COLORMATRIX = 0, // 0 + C_COLORS = 0, // 0 + C_KCOLORS = C_COLORS + 4, // 4 + C_ALPHA = C_KCOLORS + 4, // 8 + C_TEXDIMS = C_ALPHA + 1, // 9 + C_ZBIAS = C_TEXDIMS + 8, // 17 + C_INDTEXSCALE = C_ZBIAS + 2, // 19 + C_INDTEXMTX = C_INDTEXSCALE + 2, // 21 + C_FOGCOLOR = C_INDTEXMTX + 6, // 27 + C_FOGI = C_FOGCOLOR + 1, // 28 + C_FOGF = C_FOGI + 1, // 29 + C_ZSLOPE = C_FOGF + 2, // 31 + C_EFBSCALE = C_ZSLOPE + 1, // 32 + C_PENVCONST_END = C_EFBSCALE + 1 }; -static const char *tevKSelTableC[] = -{ - "255,255,255", // 1 = 0x00 - "223,223,223", // 7_8 = 0x01 - "191,191,191", // 3_4 = 0x02 - "159,159,159", // 5_8 = 0x03 - "128,128,128", // 1_2 = 0x04 - "96,96,96", // 3_8 = 0x05 - "64,64,64", // 1_4 = 0x06 - "32,32,32", // 1_8 = 0x07 - "0,0,0", // INVALID = 0x08 - "0,0,0", // INVALID = 0x09 - "0,0,0", // INVALID = 0x0a - "0,0,0", // INVALID = 0x0b - I_KCOLORS"[0].rgb", // K0 = 0x0C - I_KCOLORS"[1].rgb", // K1 = 0x0D - I_KCOLORS"[2].rgb", // K2 = 0x0E - I_KCOLORS"[3].rgb", // K3 = 0x0F - I_KCOLORS"[0].rrr", // K0_R = 0x10 - I_KCOLORS"[1].rrr", // K1_R = 0x11 - I_KCOLORS"[2].rrr", // K2_R = 0x12 - I_KCOLORS"[3].rrr", // K3_R = 0x13 - I_KCOLORS"[0].ggg", // K0_G = 0x14 - I_KCOLORS"[1].ggg", // K1_G = 0x15 - I_KCOLORS"[2].ggg", // K2_G = 0x16 - I_KCOLORS"[3].ggg", // K3_G = 0x17 - I_KCOLORS"[0].bbb", // K0_B = 0x18 - I_KCOLORS"[1].bbb", // K1_B = 0x19 - I_KCOLORS"[2].bbb", // K2_B = 0x1A - I_KCOLORS"[3].bbb", // K3_B = 0x1B - I_KCOLORS"[0].aaa", // K0_A = 0x1C - I_KCOLORS"[1].aaa", // K1_A = 0x1D - I_KCOLORS"[2].aaa", // K2_A = 0x1E - I_KCOLORS"[3].aaa", // K3_A = 0x1F +static const char* tevKSelTableC[] = { + "255,255,255", // 1 = 0x00 + "223,223,223", // 7_8 = 0x01 + "191,191,191", // 3_4 = 0x02 + "159,159,159", // 5_8 = 0x03 + "128,128,128", // 1_2 = 0x04 + "96,96,96", // 3_8 = 0x05 + "64,64,64", // 1_4 = 0x06 + "32,32,32", // 1_8 = 0x07 + "0,0,0", // INVALID = 0x08 + "0,0,0", // INVALID = 0x09 + "0,0,0", // INVALID = 0x0a + "0,0,0", // INVALID = 0x0b + I_KCOLORS "[0].rgb", // K0 = 0x0C + I_KCOLORS "[1].rgb", // K1 = 0x0D + I_KCOLORS "[2].rgb", // K2 = 0x0E + I_KCOLORS "[3].rgb", // K3 = 0x0F + I_KCOLORS "[0].rrr", // K0_R = 0x10 + I_KCOLORS "[1].rrr", // K1_R = 0x11 + I_KCOLORS "[2].rrr", // K2_R = 0x12 + I_KCOLORS "[3].rrr", // K3_R = 0x13 + I_KCOLORS "[0].ggg", // K0_G = 0x14 + I_KCOLORS "[1].ggg", // K1_G = 0x15 + I_KCOLORS "[2].ggg", // K2_G = 0x16 + I_KCOLORS "[3].ggg", // K3_G = 0x17 + I_KCOLORS "[0].bbb", // K0_B = 0x18 + I_KCOLORS "[1].bbb", // K1_B = 0x19 + I_KCOLORS "[2].bbb", // K2_B = 0x1A + I_KCOLORS "[3].bbb", // K3_B = 0x1B + I_KCOLORS "[0].aaa", // K0_A = 0x1C + I_KCOLORS "[1].aaa", // K1_A = 0x1D + I_KCOLORS "[2].aaa", // K2_A = 0x1E + I_KCOLORS "[3].aaa", // K3_A = 0x1F }; -static const char *tevKSelTableA[] = -{ - "255", // 1 = 0x00 - "223", // 7_8 = 0x01 - "191", // 3_4 = 0x02 - "159", // 5_8 = 0x03 - "128", // 1_2 = 0x04 - "96", // 3_8 = 0x05 - "64", // 1_4 = 0x06 - "32", // 1_8 = 0x07 - "0", // INVALID = 0x08 - "0", // INVALID = 0x09 - "0", // INVALID = 0x0a - "0", // INVALID = 0x0b - "0", // INVALID = 0x0c - "0", // INVALID = 0x0d - "0", // INVALID = 0x0e - "0", // INVALID = 0x0f - I_KCOLORS"[0].r", // K0_R = 0x10 - I_KCOLORS"[1].r", // K1_R = 0x11 - I_KCOLORS"[2].r", // K2_R = 0x12 - I_KCOLORS"[3].r", // K3_R = 0x13 - I_KCOLORS"[0].g", // K0_G = 0x14 - I_KCOLORS"[1].g", // K1_G = 0x15 - I_KCOLORS"[2].g", // K2_G = 0x16 - I_KCOLORS"[3].g", // K3_G = 0x17 - I_KCOLORS"[0].b", // K0_B = 0x18 - I_KCOLORS"[1].b", // K1_B = 0x19 - I_KCOLORS"[2].b", // K2_B = 0x1A - I_KCOLORS"[3].b", // K3_B = 0x1B - I_KCOLORS"[0].a", // K0_A = 0x1C - I_KCOLORS"[1].a", // K1_A = 0x1D - I_KCOLORS"[2].a", // K2_A = 0x1E - I_KCOLORS"[3].a", // K3_A = 0x1F +static const char* tevKSelTableA[] = { + "255", // 1 = 0x00 + "223", // 7_8 = 0x01 + "191", // 3_4 = 0x02 + "159", // 5_8 = 0x03 + "128", // 1_2 = 0x04 + "96", // 3_8 = 0x05 + "64", // 1_4 = 0x06 + "32", // 1_8 = 0x07 + "0", // INVALID = 0x08 + "0", // INVALID = 0x09 + "0", // INVALID = 0x0a + "0", // INVALID = 0x0b + "0", // INVALID = 0x0c + "0", // INVALID = 0x0d + "0", // INVALID = 0x0e + "0", // INVALID = 0x0f + I_KCOLORS "[0].r", // K0_R = 0x10 + I_KCOLORS "[1].r", // K1_R = 0x11 + I_KCOLORS "[2].r", // K2_R = 0x12 + I_KCOLORS "[3].r", // K3_R = 0x13 + I_KCOLORS "[0].g", // K0_G = 0x14 + I_KCOLORS "[1].g", // K1_G = 0x15 + I_KCOLORS "[2].g", // K2_G = 0x16 + I_KCOLORS "[3].g", // K3_G = 0x17 + I_KCOLORS "[0].b", // K0_B = 0x18 + I_KCOLORS "[1].b", // K1_B = 0x19 + I_KCOLORS "[2].b", // K2_B = 0x1A + I_KCOLORS "[3].b", // K3_B = 0x1B + I_KCOLORS "[0].a", // K0_A = 0x1C + I_KCOLORS "[1].a", // K1_A = 0x1D + I_KCOLORS "[2].a", // K2_A = 0x1E + I_KCOLORS "[3].a", // K3_A = 0x1F }; -static const char *tevCInputTable[] = -{ - "prev.rgb", // CPREV, - "prev.aaa", // APREV, - "c0.rgb", // C0, - "c0.aaa", // A0, - "c1.rgb", // C1, - "c1.aaa", // A1, - "c2.rgb", // C2, - "c2.aaa", // A2, - "textemp.rgb", // TEXC, - "textemp.aaa", // TEXA, - "rastemp.rgb", // RASC, - "rastemp.aaa", // RASA, - "int3(255,255,255)", // ONE - "int3(128,128,128)", // HALF - "konsttemp.rgb", // KONST - "int3(0,0,0)", // ZERO +static const char* tevCInputTable[] = { + "prev.rgb", // CPREV, + "prev.aaa", // APREV, + "c0.rgb", // C0, + "c0.aaa", // A0, + "c1.rgb", // C1, + "c1.aaa", // A1, + "c2.rgb", // C2, + "c2.aaa", // A2, + "textemp.rgb", // TEXC, + "textemp.aaa", // TEXA, + "rastemp.rgb", // RASC, + "rastemp.aaa", // RASA, + "int3(255,255,255)", // ONE + "int3(128,128,128)", // HALF + "konsttemp.rgb", // KONST + "int3(0,0,0)", // ZERO }; -static const char *tevAInputTable[] = -{ - "prev.a", // APREV, - "c0.a", // A0, - "c1.a", // A1, - "c2.a", // A2, - "textemp.a", // TEXA, - "rastemp.a", // RASA, - "konsttemp.a", // KONST, (hw1 had quarter) - "0", // ZERO +static const char* tevAInputTable[] = { + "prev.a", // APREV, + "c0.a", // A0, + "c1.a", // A1, + "c2.a", // A2, + "textemp.a", // TEXA, + "rastemp.a", // RASA, + "konsttemp.a", // KONST, (hw1 had quarter) + "0", // ZERO }; -static const char *tevRasTable[] = -{ - "iround(col0 * 255.0)", - "iround(col1 * 255.0)", - "ERROR13", //2 - "ERROR14", //3 - "ERROR15", //4 - "(int4(1, 1, 1, 1) * alphabump)", // bump alpha (0..248) - "(int4(1, 1, 1, 1) * (alphabump | (alphabump >> 5)))", // normalized bump alpha (0..255) - "int4(0, 0, 0, 0)", // zero +static const char* tevRasTable[] = { + "iround(col0 * 255.0)", + "iround(col1 * 255.0)", + "ERROR13", // 2 + "ERROR14", // 3 + "ERROR15", // 4 + "(int4(1, 1, 1, 1) * alphabump)", // bump alpha (0..248) + "(int4(1, 1, 1, 1) * (alphabump | (alphabump >> 5)))", // normalized bump alpha (0..255) + "int4(0, 0, 0, 0)", // zero }; -static const char *tevCOutputTable[] = { "prev.rgb", "c0.rgb", "c1.rgb", "c2.rgb" }; -static const char *tevAOutputTable[] = { "prev.a", "c0.a", "c1.a", "c2.a" }; +static const char* tevCOutputTable[] = {"prev.rgb", "c0.rgb", "c1.rgb", "c2.rgb"}; +static const char* tevAOutputTable[] = {"prev.a", "c0.a", "c1.a", "c2.a"}; -template static void WriteStage(T& out, pixel_shader_uid_data* uid_data, int n, API_TYPE ApiType, const char swapModeTable[4][5]); -template static void WriteTevRegular(T& out, const char* components, int bias, int op, int clamp, int shift); -template static void SampleTexture(T& out, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType); -template static void WriteAlphaTest(T& out, pixel_shader_uid_data* uid_data, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth); -template static void WriteFog(T& out, pixel_shader_uid_data* uid_data); +template +static void WriteStage(T& out, pixel_shader_uid_data* uid_data, int n, API_TYPE ApiType, + const char swapModeTable[4][5]); +template +static void WriteTevRegular(T& out, const char* components, int bias, int op, int clamp, int shift); +template +static void SampleTexture(T& out, const char* texcoords, const char* texswap, int texmap, + API_TYPE ApiType); +template +static void WriteAlphaTest(T& out, pixel_shader_uid_data* uid_data, API_TYPE ApiType, + DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth); +template +static void WriteFog(T& out, pixel_shader_uid_data* uid_data); -template +template static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType) { - T out; - const u32 components = VertexLoaderManager::g_current_components; - // Non-uid template parameters will write to the dummy data (=> gets optimized out) - pixel_shader_uid_data dummy_data; - pixel_shader_uid_data* uid_data = out.template GetUidData(); - if (uid_data != nullptr) - memset(uid_data, 0, sizeof(*uid_data)); - else - uid_data = &dummy_data; + T out; + const u32 components = VertexLoaderManager::g_current_components; + // Non-uid template parameters will write to the dummy data (=> gets optimized out) + pixel_shader_uid_data dummy_data; + pixel_shader_uid_data* uid_data = out.template GetUidData(); + if (uid_data != nullptr) + memset(uid_data, 0, sizeof(*uid_data)); + else + uid_data = &dummy_data; - unsigned int numStages = bpmem.genMode.numtevstages + 1; - unsigned int numTexgen = bpmem.genMode.numtexgens; + unsigned int numStages = bpmem.genMode.numtevstages + 1; + unsigned int numTexgen = bpmem.genMode.numtexgens; - out.Write("//Pixel Shader for TEV stages\n"); - out.Write("//%i TEV stages, %i texgens, %i IND stages\n", - numStages, numTexgen, bpmem.genMode.numindstages.Value()); + out.Write("//Pixel Shader for TEV stages\n"); + out.Write("//%i TEV stages, %i texgens, %i IND stages\n", numStages, numTexgen, + bpmem.genMode.numindstages.Value()); - uid_data->dstAlphaMode = dstAlphaMode; - uid_data->genMode_numindstages = bpmem.genMode.numindstages; - uid_data->genMode_numtevstages = bpmem.genMode.numtevstages; - uid_data->genMode_numtexgens = bpmem.genMode.numtexgens; + uid_data->dstAlphaMode = dstAlphaMode; + uid_data->genMode_numindstages = bpmem.genMode.numindstages; + uid_data->genMode_numtevstages = bpmem.genMode.numtevstages; + uid_data->genMode_numtexgens = bpmem.genMode.numtexgens; - // dot product for integer vectors - out.Write("int idot(int3 x, int3 y)\n" - "{\n" - "\tint3 tmp = x * y;\n" - "\treturn tmp.x + tmp.y + tmp.z;\n" - "}\n"); + // dot product for integer vectors + out.Write("int idot(int3 x, int3 y)\n" + "{\n" + "\tint3 tmp = x * y;\n" + "\treturn tmp.x + tmp.y + tmp.z;\n" + "}\n"); - out.Write("int idot(int4 x, int4 y)\n" - "{\n" - "\tint4 tmp = x * y;\n" - "\treturn tmp.x + tmp.y + tmp.z + tmp.w;\n" - "}\n\n"); + out.Write("int idot(int4 x, int4 y)\n" + "{\n" + "\tint4 tmp = x * y;\n" + "\treturn tmp.x + tmp.y + tmp.z + tmp.w;\n" + "}\n\n"); - // rounding + casting to integer at once in a single function - out.Write("int iround(float x) { return int (round(x)); }\n" - "int2 iround(float2 x) { return int2(round(x)); }\n" - "int3 iround(float3 x) { return int3(round(x)); }\n" - "int4 iround(float4 x) { return int4(round(x)); }\n\n"); + // rounding + casting to integer at once in a single function + out.Write("int iround(float x) { return int (round(x)); }\n" + "int2 iround(float2 x) { return int2(round(x)); }\n" + "int3 iround(float3 x) { return int3(round(x)); }\n" + "int4 iround(float4 x) { return int4(round(x)); }\n\n"); - out.Write("int itrunc(float x) { return int (trunc(x)); }\n" - "int2 itrunc(float2 x) { return int2(trunc(x)); }\n" - "int3 itrunc(float3 x) { return int3(trunc(x)); }\n" - "int4 itrunc(float4 x) { return int4(trunc(x)); }\n\n"); + out.Write("int itrunc(float x) { return int (trunc(x)); }\n" + "int2 itrunc(float2 x) { return int2(trunc(x)); }\n" + "int3 itrunc(float3 x) { return int3(trunc(x)); }\n" + "int4 itrunc(float4 x) { return int4(trunc(x)); }\n\n"); - if (ApiType == API_OPENGL) - { - out.Write("SAMPLER_BINDING(0) uniform sampler2DArray samp[8];\n"); - } - else // D3D - { - // Declare samplers - out.Write("SamplerState samp[8] : register(s0);\n"); - out.Write("\n"); - out.Write("Texture2DArray Tex[8] : register(t0);\n"); - } - out.Write("\n"); + if (ApiType == API_OPENGL) + { + out.Write("SAMPLER_BINDING(0) uniform sampler2DArray samp[8];\n"); + } + else // D3D + { + // Declare samplers + out.Write("SamplerState samp[8] : register(s0);\n"); + out.Write("\n"); + out.Write("Texture2DArray Tex[8] : register(t0);\n"); + } + out.Write("\n"); - if (ApiType == API_OPENGL) - { - out.Write("layout(std140%s) uniform PSBlock {\n", g_ActiveConfig.backend_info.bSupportsBindingLayout ? ", binding = 1" : ""); - } - else - { - out.Write("cbuffer PSBlock : register(b0) {\n"); - } - out.Write( - "\tint4 " I_COLORS"[4];\n" - "\tint4 " I_KCOLORS"[4];\n" - "\tint4 " I_ALPHA";\n" - "\tfloat4 " I_TEXDIMS"[8];\n" - "\tint4 " I_ZBIAS"[2];\n" - "\tint4 " I_INDTEXSCALE"[2];\n" - "\tint4 " I_INDTEXMTX"[6];\n" - "\tint4 " I_FOGCOLOR";\n" - "\tint4 " I_FOGI";\n" - "\tfloat4 " I_FOGF"[2];\n" - "\tfloat4 " I_ZSLOPE";\n" - "\tfloat4 " I_EFBSCALE";\n" - "};\n"); + if (ApiType == API_OPENGL) + { + out.Write("layout(std140%s) uniform PSBlock {\n", + g_ActiveConfig.backend_info.bSupportsBindingLayout ? ", binding = 1" : ""); + } + else + { + out.Write("cbuffer PSBlock : register(b0) {\n"); + } + out.Write("\tint4 " I_COLORS "[4];\n" + "\tint4 " I_KCOLORS "[4];\n" + "\tint4 " I_ALPHA ";\n" + "\tfloat4 " I_TEXDIMS "[8];\n" + "\tint4 " I_ZBIAS "[2];\n" + "\tint4 " I_INDTEXSCALE "[2];\n" + "\tint4 " I_INDTEXMTX "[6];\n" + "\tint4 " I_FOGCOLOR ";\n" + "\tint4 " I_FOGI ";\n" + "\tfloat4 " I_FOGF "[2];\n" + "\tfloat4 " I_ZSLOPE ";\n" + "\tfloat4 " I_EFBSCALE ";\n" + "};\n"); - if (g_ActiveConfig.bEnablePixelLighting) - { - out.Write("%s", s_lighting_struct); + if (g_ActiveConfig.bEnablePixelLighting) + { + out.Write("%s", s_lighting_struct); - if (ApiType == API_OPENGL) - { - out.Write("layout(std140%s) uniform VSBlock {\n", g_ActiveConfig.backend_info.bSupportsBindingLayout ? ", binding = 2" : ""); - } - else - { - out.Write("cbuffer VSBlock : register(b1) {\n"); - } - out.Write(s_shader_uniforms); - out.Write("};\n"); - } + if (ApiType == API_OPENGL) + { + out.Write("layout(std140%s) uniform VSBlock {\n", + g_ActiveConfig.backend_info.bSupportsBindingLayout ? ", binding = 2" : ""); + } + else + { + out.Write("cbuffer VSBlock : register(b1) {\n"); + } + out.Write(s_shader_uniforms); + out.Write("};\n"); + } - if (g_ActiveConfig.backend_info.bSupportsBBox && g_ActiveConfig.bBBoxEnable) - { - if (ApiType == API_OPENGL) - { - out.Write( - "layout(std140, binding = 3) buffer BBox {\n" - "\tint4 bbox_data;\n" - "};\n" - ); - } - else - { - out.Write( - "globallycoherent RWBuffer bbox_data : register(u2);\n" - ); - } - } + if (g_ActiveConfig.backend_info.bSupportsBBox && g_ActiveConfig.bBBoxEnable) + { + if (ApiType == API_OPENGL) + { + out.Write("layout(std140, binding = 3) buffer BBox {\n" + "\tint4 bbox_data;\n" + "};\n"); + } + else + { + out.Write("globallycoherent RWBuffer bbox_data : register(u2);\n"); + } + } - out.Write("struct VS_OUTPUT {\n"); - GenerateVSOutputMembers(out, ApiType, ""); - out.Write("};\n"); + out.Write("struct VS_OUTPUT {\n"); + GenerateVSOutputMembers(out, ApiType, ""); + out.Write("};\n"); - const bool forced_early_z = g_ActiveConfig.backend_info.bSupportsEarlyZ && bpmem.UseEarlyDepthTest() - && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED) - // We can't allow early_ztest for zfreeze because depth is overridden per-pixel. - // This means it's impossible for zcomploc to be emulated on a zfrozen polygon. - && !(bpmem.zmode.testenable && bpmem.genMode.zfreeze); - const bool per_pixel_depth = (bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) - || (!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !forced_early_z) - || (bpmem.zmode.testenable && bpmem.genMode.zfreeze); + const bool forced_early_z = + g_ActiveConfig.backend_info.bSupportsEarlyZ && bpmem.UseEarlyDepthTest() && + (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED) + // We can't allow early_ztest for zfreeze because depth is overridden per-pixel. + // This means it's impossible for zcomploc to be emulated on a zfrozen polygon. + && !(bpmem.zmode.testenable && bpmem.genMode.zfreeze); + const bool per_pixel_depth = + (bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) || + (!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !forced_early_z) || + (bpmem.zmode.testenable && bpmem.genMode.zfreeze); - if (forced_early_z) - { - // Zcomploc (aka early_ztest) is a way to control whether depth test is done before - // or after texturing and alpha test. PC graphics APIs used to provide no way to emulate - // this feature properly until 2012: Depth tests were always done after alpha testing. - // Most importantly, it was not possible to write to the depth buffer without also writing - // a color value (unless color writing was disabled altogether). + if (forced_early_z) + { + // Zcomploc (aka early_ztest) is a way to control whether depth test is done before + // or after texturing and alpha test. PC graphics APIs used to provide no way to emulate + // this feature properly until 2012: Depth tests were always done after alpha testing. + // Most importantly, it was not possible to write to the depth buffer without also writing + // a color value (unless color writing was disabled altogether). - // OpenGL 4.2 actually provides two extensions which can force an early z test: - // * ARB_image_load_store has 'layout(early_fragment_tests)' which forces the driver to do z and stencil tests early. - // * ARB_conservative_depth has 'layout(depth_unchanged) which signals to the driver that it can make optimisations - // which assume the pixel shader won't update the depth buffer. + // OpenGL 4.2 actually provides two extensions which can force an early z test: + // * ARB_image_load_store has 'layout(early_fragment_tests)' which forces the driver to do z + // and stencil tests early. + // * ARB_conservative_depth has 'layout(depth_unchanged) which signals to the driver that it + // can make optimisations + // which assume the pixel shader won't update the depth buffer. - // early_fragment_tests is the best option, as it requires the driver to do early-z and defines early-z exactly as - // we expect, with discard causing the shader to exit with only the depth buffer updated. + // early_fragment_tests is the best option, as it requires the driver to do early-z and defines + // early-z exactly as + // we expect, with discard causing the shader to exit with only the depth buffer updated. - // Conservative depth's 'depth_unchanged' only hints to the driver that an early-z optimisation can be made and - // doesn't define what will happen if we discard the fragment. But the way modern graphics hardware is implemented - // means it is not unreasonable to expect the the same behaviour as early_fragment_tests. - // We can also assume that if a driver has gone out of its way to support conservative depth and not image_load_store - // as required by OpenGL 4.2 that it will be doing the optimisation. - // If the driver doesn't actually do an early z optimisation, ZCompLoc will be broken and depth will only be written - // if the alpha test passes. + // Conservative depth's 'depth_unchanged' only hints to the driver that an early-z optimisation + // can be made and + // doesn't define what will happen if we discard the fragment. But the way modern graphics + // hardware is implemented + // means it is not unreasonable to expect the the same behaviour as early_fragment_tests. + // We can also assume that if a driver has gone out of its way to support conservative depth and + // not image_load_store + // as required by OpenGL 4.2 that it will be doing the optimisation. + // If the driver doesn't actually do an early z optimisation, ZCompLoc will be broken and depth + // will only be written + // if the alpha test passes. - // We support Conservative as a fallback, because many drivers based on Mesa haven't implemented all of the - // ARB_image_load_store extension yet. + // We support Conservative as a fallback, because many drivers based on Mesa haven't implemented + // all of the + // ARB_image_load_store extension yet. - // D3D11 also has a way to force the driver to enable early-z, so we're fine here. - if(ApiType == API_OPENGL) - { - // This is a #define which signals whatever early-z method the driver supports. - out.Write("FORCE_EARLY_Z; \n"); - } - else - { - out.Write("[earlydepthstencil]\n"); - } - } - else if (bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED)) - { - static bool warn_once = true; - if (warn_once) - WARN_LOG(VIDEO, "Early z test enabled but not possible to emulate with current configuration. Make sure to enable fast depth calculations. If this message still shows up your hardware isn't able to emulate the feature properly (a GPU with D3D 11.0 / OGL 4.2 support is required)."); - warn_once = false; - } + // D3D11 also has a way to force the driver to enable early-z, so we're fine here. + if (ApiType == API_OPENGL) + { + // This is a #define which signals whatever early-z method the driver supports. + out.Write("FORCE_EARLY_Z; \n"); + } + else + { + out.Write("[earlydepthstencil]\n"); + } + } + else if (bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc || + bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED)) + { + static bool warn_once = true; + if (warn_once) + WARN_LOG(VIDEO, "Early z test enabled but not possible to emulate with current " + "configuration. Make sure to enable fast depth calculations. If this message " + "still shows up your hardware isn't able to emulate the feature properly (a " + "GPU with D3D 11.0 / OGL 4.2 support is required)."); + warn_once = false; + } - uid_data->msaa = g_ActiveConfig.iMultisamples > 1; - uid_data->ssaa = g_ActiveConfig.iMultisamples > 1 && g_ActiveConfig.bSSAA; - if (ApiType == API_OPENGL) - { - out.Write("out vec4 ocol0;\n"); - if (dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) - out.Write("out vec4 ocol1;\n"); + uid_data->msaa = g_ActiveConfig.iMultisamples > 1; + uid_data->ssaa = g_ActiveConfig.iMultisamples > 1 && g_ActiveConfig.bSSAA; + if (ApiType == API_OPENGL) + { + out.Write("out vec4 ocol0;\n"); + if (dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) + out.Write("out vec4 ocol1;\n"); - if (per_pixel_depth) - out.Write("#define depth gl_FragDepth\n"); + if (per_pixel_depth) + out.Write("#define depth gl_FragDepth\n"); - uid_data->stereo = g_ActiveConfig.iStereoMode > 0; - if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) - { - out.Write("in VertexData {\n"); - GenerateVSOutputMembers(out, ApiType, GetInterpolationQualifier(true, true)); + uid_data->stereo = g_ActiveConfig.iStereoMode > 0; + if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) + { + out.Write("in VertexData {\n"); + GenerateVSOutputMembers(out, ApiType, GetInterpolationQualifier(true, true)); - if (g_ActiveConfig.iStereoMode > 0) - out.Write("\tflat int layer;\n"); + if (g_ActiveConfig.iStereoMode > 0) + out.Write("\tflat int layer;\n"); - out.Write("};\n"); - } - else - { - out.Write("%s in float4 colors_0;\n", GetInterpolationQualifier()); - out.Write("%s in float4 colors_1;\n", GetInterpolationQualifier()); - // compute window position if needed because binding semantic WPOS is not widely supported - // Let's set up attributes - for (unsigned int i = 0; i < numTexgen; ++i) - { - out.Write("%s in float3 uv%d;\n", GetInterpolationQualifier(), i); - } - out.Write("%s in float4 clipPos;\n", GetInterpolationQualifier()); - if (g_ActiveConfig.bEnablePixelLighting) - { - out.Write("%s in float3 Normal;\n", GetInterpolationQualifier()); - out.Write("%s in float3 WorldPos;\n", GetInterpolationQualifier()); - } - } + out.Write("};\n"); + } + else + { + out.Write("%s in float4 colors_0;\n", GetInterpolationQualifier()); + out.Write("%s in float4 colors_1;\n", GetInterpolationQualifier()); + // compute window position if needed because binding semantic WPOS is not widely supported + // Let's set up attributes + for (unsigned int i = 0; i < numTexgen; ++i) + { + out.Write("%s in float3 uv%d;\n", GetInterpolationQualifier(), i); + } + out.Write("%s in float4 clipPos;\n", GetInterpolationQualifier()); + if (g_ActiveConfig.bEnablePixelLighting) + { + out.Write("%s in float3 Normal;\n", GetInterpolationQualifier()); + out.Write("%s in float3 WorldPos;\n", GetInterpolationQualifier()); + } + } - out.Write("void main()\n{\n"); + out.Write("void main()\n{\n"); - if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) - { - for (unsigned int i = 0; i < numTexgen; ++i) - out.Write("\tfloat3 uv%d = tex%d;\n", i, i); - } + if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) + { + for (unsigned int i = 0; i < numTexgen; ++i) + out.Write("\tfloat3 uv%d = tex%d;\n", i, i); + } - out.Write("\tfloat4 rawpos = gl_FragCoord;\n"); - } - else // D3D - { - out.Write("void main(\n"); - out.Write(" out float4 ocol0 : SV_Target0,%s%s\n in float4 rawpos : SV_Position,\n", - dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : SV_Target1," : "", - per_pixel_depth ? "\n out float depth : SV_Depth," : ""); + out.Write("\tfloat4 rawpos = gl_FragCoord;\n"); + } + else // D3D + { + out.Write("void main(\n"); + out.Write(" out float4 ocol0 : SV_Target0,%s%s\n in float4 rawpos : SV_Position,\n", + dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : SV_Target1," : + "", + per_pixel_depth ? "\n out float depth : SV_Depth," : ""); - out.Write(" in %s float4 colors_0 : COLOR0,\n", GetInterpolationQualifier()); - out.Write(" in %s float4 colors_1 : COLOR1\n", GetInterpolationQualifier()); + out.Write(" in %s float4 colors_0 : COLOR0,\n", GetInterpolationQualifier()); + out.Write(" in %s float4 colors_1 : COLOR1\n", GetInterpolationQualifier()); - // compute window position if needed because binding semantic WPOS is not widely supported - for (unsigned int i = 0; i < numTexgen; ++i) - out.Write(",\n in %s float3 uv%d : TEXCOORD%d", GetInterpolationQualifier(), i, i); - out.Write(",\n in %s float4 clipPos : TEXCOORD%d", GetInterpolationQualifier(), numTexgen); - if (g_ActiveConfig.bEnablePixelLighting) - { - out.Write(",\n in %s float3 Normal : TEXCOORD%d", GetInterpolationQualifier(), numTexgen + 1); - out.Write(",\n in %s float3 WorldPos : TEXCOORD%d", GetInterpolationQualifier(), numTexgen + 2); - } - uid_data->stereo = g_ActiveConfig.iStereoMode > 0; - if (g_ActiveConfig.iStereoMode > 0) - out.Write(",\n in uint layer : SV_RenderTargetArrayIndex\n"); - out.Write(" ) {\n"); - } + // compute window position if needed because binding semantic WPOS is not widely supported + for (unsigned int i = 0; i < numTexgen; ++i) + out.Write(",\n in %s float3 uv%d : TEXCOORD%d", GetInterpolationQualifier(), i, i); + out.Write(",\n in %s float4 clipPos : TEXCOORD%d", GetInterpolationQualifier(), numTexgen); + if (g_ActiveConfig.bEnablePixelLighting) + { + out.Write(",\n in %s float3 Normal : TEXCOORD%d", GetInterpolationQualifier(), + numTexgen + 1); + out.Write(",\n in %s float3 WorldPos : TEXCOORD%d", GetInterpolationQualifier(), + numTexgen + 2); + } + uid_data->stereo = g_ActiveConfig.iStereoMode > 0; + if (g_ActiveConfig.iStereoMode > 0) + out.Write(",\n in uint layer : SV_RenderTargetArrayIndex\n"); + out.Write(" ) {\n"); + } - out.Write("\tint4 c0 = " I_COLORS"[1], c1 = " I_COLORS"[2], c2 = " I_COLORS"[3], prev = " I_COLORS"[0];\n" - "\tint4 rastemp = int4(0, 0, 0, 0), textemp = int4(0, 0, 0, 0), konsttemp = int4(0, 0, 0, 0);\n" - "\tint3 comp16 = int3(1, 256, 0), comp24 = int3(1, 256, 256*256);\n" - "\tint alphabump=0;\n" - "\tint3 tevcoord=int3(0, 0, 0);\n" - "\tint2 wrappedcoord=int2(0,0), tempcoord=int2(0,0);\n" - "\tint4 tevin_a=int4(0,0,0,0),tevin_b=int4(0,0,0,0),tevin_c=int4(0,0,0,0),tevin_d=int4(0,0,0,0);\n\n"); // tev combiner inputs + out.Write("\tint4 c0 = " I_COLORS "[1], c1 = " I_COLORS "[2], c2 = " I_COLORS + "[3], prev = " I_COLORS "[0];\n" + "\tint4 rastemp = int4(0, 0, 0, 0), textemp = int4(0, 0, 0, 0), konsttemp = int4(0, 0, " + "0, 0);\n" + "\tint3 comp16 = int3(1, 256, 0), comp24 = int3(1, 256, 256*256);\n" + "\tint alphabump=0;\n" + "\tint3 tevcoord=int3(0, 0, 0);\n" + "\tint2 wrappedcoord=int2(0,0), tempcoord=int2(0,0);\n" + "\tint4 " + "tevin_a=int4(0,0,0,0),tevin_b=int4(0,0,0,0),tevin_c=int4(0,0,0,0),tevin_d=int4(0,0,0," + "0);\n\n"); // tev combiner inputs - // On GLSL, input variables must not be assigned to. - // This is why we declare these variables locally instead. - out.Write("\tfloat4 col0 = colors_0;\n"); - out.Write("\tfloat4 col1 = colors_1;\n"); + // On GLSL, input variables must not be assigned to. + // This is why we declare these variables locally instead. + out.Write("\tfloat4 col0 = colors_0;\n"); + out.Write("\tfloat4 col1 = colors_1;\n"); - if (g_ActiveConfig.bEnablePixelLighting) - { - out.Write("\tfloat3 _norm0 = normalize(Normal.xyz);\n\n"); - out.Write("\tfloat3 pos = WorldPos;\n"); + if (g_ActiveConfig.bEnablePixelLighting) + { + out.Write("\tfloat3 _norm0 = normalize(Normal.xyz);\n\n"); + out.Write("\tfloat3 pos = WorldPos;\n"); - out.Write("\tint4 lacc;\n" - "\tfloat3 ldir, h, cosAttn, distAttn;\n" - "\tfloat dist, dist2, attn;\n"); + out.Write("\tint4 lacc;\n" + "\tfloat3 ldir, h, cosAttn, distAttn;\n" + "\tfloat dist, dist2, attn;\n"); - // TODO: Our current constant usage code isn't able to handle more than one buffer. - // So we can't mark the VS constant as used here. But keep them here as reference. - //out.SetConstantsUsed(C_PLIGHT_COLORS, C_PLIGHT_COLORS+7); // TODO: Can be optimized further - //out.SetConstantsUsed(C_PLIGHTS, C_PLIGHTS+31); // TODO: Can be optimized further - //out.SetConstantsUsed(C_PMATERIALS, C_PMATERIALS+3); - uid_data->components = components; - GenerateLightingShader(out, uid_data->lighting, components, "colors_", "col"); - } + // TODO: Our current constant usage code isn't able to handle more than one buffer. + // So we can't mark the VS constant as used here. But keep them here as reference. + // out.SetConstantsUsed(C_PLIGHT_COLORS, C_PLIGHT_COLORS+7); // TODO: Can be optimized further + // out.SetConstantsUsed(C_PLIGHTS, C_PLIGHTS+31); // TODO: Can be optimized further + // out.SetConstantsUsed(C_PMATERIALS, C_PMATERIALS+3); + uid_data->components = components; + GenerateLightingShader(out, uid_data->lighting, components, "colors_", "col"); + } - // HACK to handle cases where the tex gen is not enabled - if (numTexgen == 0) - { - out.Write("\tint2 fixpoint_uv0 = int2(0, 0);\n\n"); - } - else - { - out.SetConstantsUsed(C_TEXDIMS, C_TEXDIMS+numTexgen-1); - for (unsigned int i = 0; i < numTexgen; ++i) - { - out.Write("\tint2 fixpoint_uv%d = itrunc(", i); - // optional perspective divides - uid_data->texMtxInfo_n_projection |= xfmem.texMtxInfo[i].projection << i; - if (xfmem.texMtxInfo[i].projection == XF_TEXPROJ_STQ) - { - out.Write("(uv%d.z == 0.0 ? uv%d.xy : uv%d.xy / uv%d.z)", i, i, i, i); - } - else - { - out.Write("uv%d.xy", i); - } - out.Write(" * " I_TEXDIMS"[%d].zw);\n", i); - // TODO: S24 overflows here? - } - } + // HACK to handle cases where the tex gen is not enabled + if (numTexgen == 0) + { + out.Write("\tint2 fixpoint_uv0 = int2(0, 0);\n\n"); + } + else + { + out.SetConstantsUsed(C_TEXDIMS, C_TEXDIMS + numTexgen - 1); + for (unsigned int i = 0; i < numTexgen; ++i) + { + out.Write("\tint2 fixpoint_uv%d = itrunc(", i); + // optional perspective divides + uid_data->texMtxInfo_n_projection |= xfmem.texMtxInfo[i].projection << i; + if (xfmem.texMtxInfo[i].projection == XF_TEXPROJ_STQ) + { + out.Write("(uv%d.z == 0.0 ? uv%d.xy : uv%d.xy / uv%d.z)", i, i, i, i); + } + else + { + out.Write("uv%d.xy", i); + } + out.Write(" * " I_TEXDIMS "[%d].zw);\n", i); + // TODO: S24 overflows here? + } + } - // indirect texture map lookup - int nIndirectStagesUsed = 0; - if (bpmem.genMode.numindstages > 0) - { - for (unsigned int i = 0; i < numStages; ++i) - { - if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages) - nIndirectStagesUsed |= 1 << bpmem.tevind[i].bt; - } - } + // indirect texture map lookup + int nIndirectStagesUsed = 0; + if (bpmem.genMode.numindstages > 0) + { + for (unsigned int i = 0; i < numStages; ++i) + { + if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages) + nIndirectStagesUsed |= 1 << bpmem.tevind[i].bt; + } + } - uid_data->nIndirectStagesUsed = nIndirectStagesUsed; - for (u32 i = 0; i < bpmem.genMode.numindstages; ++i) - { - if (nIndirectStagesUsed & (1 << i)) - { - unsigned int texcoord = bpmem.tevindref.getTexCoord(i); - unsigned int texmap = bpmem.tevindref.getTexMap(i); + uid_data->nIndirectStagesUsed = nIndirectStagesUsed; + for (u32 i = 0; i < bpmem.genMode.numindstages; ++i) + { + if (nIndirectStagesUsed & (1 << i)) + { + unsigned int texcoord = bpmem.tevindref.getTexCoord(i); + unsigned int texmap = bpmem.tevindref.getTexMap(i); - uid_data->SetTevindrefValues(i, texcoord, texmap); - if (texcoord < numTexgen) - { - out.SetConstantsUsed(C_INDTEXSCALE+i/2,C_INDTEXSCALE+i/2); - out.Write("\ttempcoord = fixpoint_uv%d >> " I_INDTEXSCALE"[%d].%s;\n", texcoord, i / 2, (i & 1) ? "zw" : "xy"); - } - else - out.Write("\ttempcoord = int2(0, 0);\n"); + uid_data->SetTevindrefValues(i, texcoord, texmap); + if (texcoord < numTexgen) + { + out.SetConstantsUsed(C_INDTEXSCALE + i / 2, C_INDTEXSCALE + i / 2); + out.Write("\ttempcoord = fixpoint_uv%d >> " I_INDTEXSCALE "[%d].%s;\n", texcoord, i / 2, + (i & 1) ? "zw" : "xy"); + } + else + out.Write("\ttempcoord = int2(0, 0);\n"); - out.Write("\tint3 iindtex%d = ", i); - SampleTexture(out, "float2(tempcoord)", "abg", texmap, ApiType); - } - } + out.Write("\tint3 iindtex%d = ", i); + SampleTexture(out, "float2(tempcoord)", "abg", texmap, ApiType); + } + } - // Uid fields for BuildSwapModeTable are set in WriteStage - char swapModeTable[4][5]; - const char* swapColors = "rgba"; - for (int i = 0; i < 4; i++) - { - swapModeTable[i][0] = swapColors[bpmem.tevksel[i*2].swap1]; - swapModeTable[i][1] = swapColors[bpmem.tevksel[i*2].swap2]; - swapModeTable[i][2] = swapColors[bpmem.tevksel[i*2+1].swap1]; - swapModeTable[i][3] = swapColors[bpmem.tevksel[i*2+1].swap2]; - swapModeTable[i][4] = '\0'; - } + // Uid fields for BuildSwapModeTable are set in WriteStage + char swapModeTable[4][5]; + const char* swapColors = "rgba"; + for (int i = 0; i < 4; i++) + { + swapModeTable[i][0] = swapColors[bpmem.tevksel[i * 2].swap1]; + swapModeTable[i][1] = swapColors[bpmem.tevksel[i * 2].swap2]; + swapModeTable[i][2] = swapColors[bpmem.tevksel[i * 2 + 1].swap1]; + swapModeTable[i][3] = swapColors[bpmem.tevksel[i * 2 + 1].swap2]; + swapModeTable[i][4] = '\0'; + } - for (unsigned int i = 0; i < numStages; i++) - WriteStage(out, uid_data, i, ApiType, swapModeTable); // build the equation for this stage + for (unsigned int i = 0; i < numStages; i++) + WriteStage(out, uid_data, i, ApiType, swapModeTable); // build the equation for this stage -#define MY_STRUCT_OFFSET(str,elem) ((u32)((u64)&(str).elem-(u64)&(str))) - bool enable_pl = g_ActiveConfig.bEnablePixelLighting; - uid_data->num_values = (enable_pl) ? sizeof(*uid_data) : MY_STRUCT_OFFSET(*uid_data,stagehash[numStages]); +#define MY_STRUCT_OFFSET(str, elem) ((u32)((u64) & (str).elem - (u64) & (str))) + bool enable_pl = g_ActiveConfig.bEnablePixelLighting; + uid_data->num_values = + (enable_pl) ? sizeof(*uid_data) : MY_STRUCT_OFFSET(*uid_data, stagehash[numStages]); + if (numStages) + { + // The results of the last texenv stage are put onto the screen, + // regardless of the used destination register + if (bpmem.combiners[numStages - 1].colorC.dest != 0) + { + out.Write("\tprev.rgb = %s;\n", tevCOutputTable[bpmem.combiners[numStages - 1].colorC.dest]); + } + if (bpmem.combiners[numStages - 1].alphaC.dest != 0) + { + out.Write("\tprev.a = %s;\n", tevAOutputTable[bpmem.combiners[numStages - 1].alphaC.dest]); + } + } + out.Write("\tprev = prev & 255;\n"); - if (numStages) - { - // The results of the last texenv stage are put onto the screen, - // regardless of the used destination register - if (bpmem.combiners[numStages - 1].colorC.dest != 0) - { - out.Write("\tprev.rgb = %s;\n", tevCOutputTable[bpmem.combiners[numStages - 1].colorC.dest]); - } - if (bpmem.combiners[numStages - 1].alphaC.dest != 0) - { - out.Write("\tprev.a = %s;\n", tevAOutputTable[bpmem.combiners[numStages - 1].alphaC.dest]); - } - } - out.Write("\tprev = prev & 255;\n"); + AlphaTest::TEST_RESULT Pretest = bpmem.alpha_test.TestResult(); + uid_data->Pretest = Pretest; - AlphaTest::TEST_RESULT Pretest = bpmem.alpha_test.TestResult(); - uid_data->Pretest = Pretest; + // NOTE: Fragment may not be discarded if alpha test always fails and early depth test is enabled + // (in this case we need to write a depth value if depth test passes regardless of the alpha + // testing result) + if (Pretest == AlphaTest::UNDETERMINED || + (Pretest == AlphaTest::FAIL && bpmem.UseLateDepthTest())) + WriteAlphaTest(out, uid_data, ApiType, dstAlphaMode, per_pixel_depth); - // NOTE: Fragment may not be discarded if alpha test always fails and early depth test is enabled - // (in this case we need to write a depth value if depth test passes regardless of the alpha testing result) - if (Pretest == AlphaTest::UNDETERMINED || (Pretest == AlphaTest::FAIL && bpmem.UseLateDepthTest())) - WriteAlphaTest(out, uid_data, ApiType, dstAlphaMode, per_pixel_depth); + if (bpmem.genMode.zfreeze) + { + out.SetConstantsUsed(C_ZSLOPE, C_ZSLOPE); + out.SetConstantsUsed(C_EFBSCALE, C_EFBSCALE); - if (bpmem.genMode.zfreeze) - { - out.SetConstantsUsed(C_ZSLOPE, C_ZSLOPE); - out.SetConstantsUsed(C_EFBSCALE, C_EFBSCALE); + out.Write("\tfloat2 screenpos = rawpos.xy * " I_EFBSCALE ".xy;\n"); - out.Write("\tfloat2 screenpos = rawpos.xy * " I_EFBSCALE".xy;\n"); + // Opengl has reversed vertical screenspace coordiantes + if (ApiType == API_OPENGL) + out.Write("\tscreenpos.y = %i.0 - screenpos.y;\n", EFB_HEIGHT); - // Opengl has reversed vertical screenspace coordiantes - if (ApiType == API_OPENGL) - out.Write("\tscreenpos.y = %i.0 - screenpos.y;\n", EFB_HEIGHT); + out.Write("\tint zCoord = int(" I_ZSLOPE ".z + " I_ZSLOPE ".x * screenpos.x + " I_ZSLOPE + ".y * screenpos.y);\n"); + } + else if (!g_ActiveConfig.bFastDepthCalc) + { + // FastDepth means to trust the depth generated in perspective division. + // It should be correct, but it seems not to be as accurate as required. TODO: Find out why! + // For disabled FastDepth we just calculate the depth value again. + // The performance impact of this additional calculation doesn't matter, but it prevents + // the host GPU driver from performing any early depth test optimizations. + out.SetConstantsUsed(C_ZBIAS + 1, C_ZBIAS + 1); + // the screen space depth value = far z + (clip z / clip w) * z range + out.Write("\tint zCoord = " I_ZBIAS "[1].x + int((clipPos.z / clipPos.w) * float(" I_ZBIAS + "[1].y));\n"); + } + else + { + if (ApiType == API_D3D) + out.Write("\tint zCoord = int((1.0 - rawpos.z) * 16777216.0);\n"); + else + out.Write("\tint zCoord = int(rawpos.z * 16777216.0);\n"); + } + out.Write("\tzCoord = clamp(zCoord, 0, 0xFFFFFF);\n"); - out.Write("\tint zCoord = int(" I_ZSLOPE".z + " I_ZSLOPE".x * screenpos.x + " I_ZSLOPE".y * screenpos.y);\n"); - } - else if (!g_ActiveConfig.bFastDepthCalc) - { - // FastDepth means to trust the depth generated in perspective division. - // It should be correct, but it seems not to be as accurate as required. TODO: Find out why! - // For disabled FastDepth we just calculate the depth value again. - // The performance impact of this additional calculation doesn't matter, but it prevents - // the host GPU driver from performing any early depth test optimizations. - out.SetConstantsUsed(C_ZBIAS+1, C_ZBIAS+1); - // the screen space depth value = far z + (clip z / clip w) * z range - out.Write("\tint zCoord = " I_ZBIAS"[1].x + int((clipPos.z / clipPos.w) * float(" I_ZBIAS"[1].y));\n"); - } - else - { - if (ApiType == API_D3D) - out.Write("\tint zCoord = int((1.0 - rawpos.z) * 16777216.0);\n"); - else - out.Write("\tint zCoord = int(rawpos.z * 16777216.0);\n"); - } - out.Write("\tzCoord = clamp(zCoord, 0, 0xFFFFFF);\n"); + // depth texture can safely be ignored if the result won't be written to the depth buffer + // (early_ztest) and isn't used for fog either + const bool skip_ztexture = !per_pixel_depth && !bpmem.fog.c_proj_fsel.fsel; - // depth texture can safely be ignored if the result won't be written to the depth buffer (early_ztest) and isn't used for fog either - const bool skip_ztexture = !per_pixel_depth && !bpmem.fog.c_proj_fsel.fsel; + uid_data->ztex_op = bpmem.ztex2.op; + uid_data->per_pixel_depth = per_pixel_depth; + uid_data->forced_early_z = forced_early_z; + uid_data->fast_depth_calc = g_ActiveConfig.bFastDepthCalc; + uid_data->early_ztest = bpmem.UseEarlyDepthTest(); + uid_data->fog_fsel = bpmem.fog.c_proj_fsel.fsel; + uid_data->zfreeze = bpmem.genMode.zfreeze; - uid_data->ztex_op = bpmem.ztex2.op; - uid_data->per_pixel_depth = per_pixel_depth; - uid_data->forced_early_z = forced_early_z; - uid_data->fast_depth_calc = g_ActiveConfig.bFastDepthCalc; - uid_data->early_ztest = bpmem.UseEarlyDepthTest(); - uid_data->fog_fsel = bpmem.fog.c_proj_fsel.fsel; - uid_data->zfreeze = bpmem.genMode.zfreeze; + // Note: z-textures are not written to depth buffer if early depth test is used + if (per_pixel_depth && bpmem.UseEarlyDepthTest()) + { + if (ApiType == API_D3D) + out.Write("\tdepth = 1.0 - float(zCoord) / 16777216.0;\n"); + else + out.Write("\tdepth = float(zCoord) / 16777216.0;\n"); + } - // Note: z-textures are not written to depth buffer if early depth test is used - if (per_pixel_depth && bpmem.UseEarlyDepthTest()) - { - if (ApiType == API_D3D) - out.Write("\tdepth = 1.0 - float(zCoord) / 16777216.0;\n"); - else - out.Write("\tdepth = float(zCoord) / 16777216.0;\n"); - } + // Note: depth texture output is only written to depth buffer if late depth test is used + // theoretical final depth value is used for fog calculation, though, so we have to emulate + // ztextures anyway + if (bpmem.ztex2.op != ZTEXTURE_DISABLE && !skip_ztexture) + { + // use the texture input of the last texture stage (textemp), hopefully this has been read and + // is in correct format... + out.SetConstantsUsed(C_ZBIAS, C_ZBIAS + 1); + out.Write("\tzCoord = idot(" I_ZBIAS "[0].xyzw, textemp.xyzw) + " I_ZBIAS "[1].w %s;\n", + (bpmem.ztex2.op == ZTEXTURE_ADD) ? "+ zCoord" : ""); + out.Write("\tzCoord = zCoord & 0xFFFFFF;\n"); + } - // Note: depth texture output is only written to depth buffer if late depth test is used - // theoretical final depth value is used for fog calculation, though, so we have to emulate ztextures anyway - if (bpmem.ztex2.op != ZTEXTURE_DISABLE && !skip_ztexture) - { - // use the texture input of the last texture stage (textemp), hopefully this has been read and is in correct format... - out.SetConstantsUsed(C_ZBIAS, C_ZBIAS+1); - out.Write("\tzCoord = idot(" I_ZBIAS"[0].xyzw, textemp.xyzw) + " I_ZBIAS"[1].w %s;\n", - (bpmem.ztex2.op == ZTEXTURE_ADD) ? "+ zCoord" : ""); - out.Write("\tzCoord = zCoord & 0xFFFFFF;\n"); - } + if (per_pixel_depth && bpmem.UseLateDepthTest()) + { + if (ApiType == API_D3D) + out.Write("\tdepth = 1.0 - float(zCoord) / 16777216.0;\n"); + else + out.Write("\tdepth = float(zCoord) / 16777216.0;\n"); + } - if (per_pixel_depth && bpmem.UseLateDepthTest()) - { - if (ApiType == API_D3D) - out.Write("\tdepth = 1.0 - float(zCoord) / 16777216.0;\n"); - else - out.Write("\tdepth = float(zCoord) / 16777216.0;\n"); - } + if (dstAlphaMode == DSTALPHA_ALPHA_PASS) + { + out.SetConstantsUsed(C_ALPHA, C_ALPHA); + out.Write("\tocol0 = float4(float3(prev.rgb), float(" I_ALPHA ".a)) / 255.0;\n"); + } + else + { + WriteFog(out, uid_data); + out.Write("\tocol0 = float4(prev) / 255.0;\n"); + } - if (dstAlphaMode == DSTALPHA_ALPHA_PASS) - { - out.SetConstantsUsed(C_ALPHA, C_ALPHA); - out.Write("\tocol0 = float4(float3(prev.rgb), float(" I_ALPHA".a)) / 255.0;\n"); - } - else - { - WriteFog(out, uid_data); - out.Write("\tocol0 = float4(prev) / 255.0;\n"); - } + // Use dual-source color blending to perform dst alpha in a single pass + if (dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) + { + out.SetConstantsUsed(C_ALPHA, C_ALPHA); - // Use dual-source color blending to perform dst alpha in a single pass - if (dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) - { - out.SetConstantsUsed(C_ALPHA, C_ALPHA); + // Colors will be blended against the alpha from ocol1 and + // the alpha from ocol0 will be written to the framebuffer. + out.Write("\tocol1 = float4(prev) / 255.0;\n"); + out.Write("\tocol0.a = float(" I_ALPHA ".a) / 255.0;\n"); + } - // Colors will be blended against the alpha from ocol1 and - // the alpha from ocol0 will be written to the framebuffer. - out.Write("\tocol1 = float4(prev) / 255.0;\n"); - out.Write("\tocol0.a = float(" I_ALPHA".a) / 255.0;\n"); - } + if (g_ActiveConfig.backend_info.bSupportsBBox && g_ActiveConfig.bBBoxEnable && + BoundingBox::active) + { + uid_data->bounding_box = true; + const char* atomic_op = ApiType == API_OPENGL ? "atomic" : "Interlocked"; + out.Write("\tif(bbox_data[0] > int(rawpos.x)) %sMin(bbox_data[0], int(rawpos.x));\n" + "\tif(bbox_data[1] < int(rawpos.x)) %sMax(bbox_data[1], int(rawpos.x));\n" + "\tif(bbox_data[2] > int(rawpos.y)) %sMin(bbox_data[2], int(rawpos.y));\n" + "\tif(bbox_data[3] < int(rawpos.y)) %sMax(bbox_data[3], int(rawpos.y));\n", + atomic_op, atomic_op, atomic_op, atomic_op); + } - if (g_ActiveConfig.backend_info.bSupportsBBox && g_ActiveConfig.bBBoxEnable && BoundingBox::active) - { - uid_data->bounding_box = true; - const char* atomic_op = ApiType == API_OPENGL ? "atomic" : "Interlocked"; - out.Write( - "\tif(bbox_data[0] > int(rawpos.x)) %sMin(bbox_data[0], int(rawpos.x));\n" - "\tif(bbox_data[1] < int(rawpos.x)) %sMax(bbox_data[1], int(rawpos.x));\n" - "\tif(bbox_data[2] > int(rawpos.y)) %sMin(bbox_data[2], int(rawpos.y));\n" - "\tif(bbox_data[3] < int(rawpos.y)) %sMax(bbox_data[3], int(rawpos.y));\n", - atomic_op, atomic_op, atomic_op, atomic_op); - } + out.Write("}\n"); - out.Write("}\n"); - - return out; + return out; } - -template -static void WriteStage(T& out, pixel_shader_uid_data* uid_data, int n, API_TYPE ApiType, const char swapModeTable[4][5]) +template +static void WriteStage(T& out, pixel_shader_uid_data* uid_data, int n, API_TYPE ApiType, + const char swapModeTable[4][5]) { - int texcoord = bpmem.tevorders[n/2].getTexCoord(n&1); - bool bHasTexCoord = (u32)texcoord < bpmem.genMode.numtexgens; - bool bHasIndStage = bpmem.tevind[n].bt < bpmem.genMode.numindstages; - // HACK to handle cases where the tex gen is not enabled - if (!bHasTexCoord) - texcoord = 0; + int texcoord = bpmem.tevorders[n / 2].getTexCoord(n & 1); + bool bHasTexCoord = (u32)texcoord < bpmem.genMode.numtexgens; + bool bHasIndStage = bpmem.tevind[n].bt < bpmem.genMode.numindstages; + // HACK to handle cases where the tex gen is not enabled + if (!bHasTexCoord) + texcoord = 0; - out.Write("\n\t// TEV stage %d\n", n); + out.Write("\n\t// TEV stage %d\n", n); - uid_data->stagehash[n].hasindstage = bHasIndStage; - uid_data->stagehash[n].tevorders_texcoord = texcoord; - if (bHasIndStage) - { - uid_data->stagehash[n].tevind = bpmem.tevind[n].hex & 0x7FFFFF; + uid_data->stagehash[n].hasindstage = bHasIndStage; + uid_data->stagehash[n].tevorders_texcoord = texcoord; + if (bHasIndStage) + { + uid_data->stagehash[n].tevind = bpmem.tevind[n].hex & 0x7FFFFF; - out.Write("\t// indirect op\n"); - // perform the indirect op on the incoming regular coordinates using iindtex%d as the offset coords - if (bpmem.tevind[n].bs != ITBA_OFF) - { - const char *tevIndAlphaSel[] = {"", "x", "y", "z"}; - const char *tevIndAlphaMask[] = {"248", "224", "240", "248"}; // 0b11111000, 0b11100000, 0b11110000, 0b11111000 - out.Write("alphabump = iindtex%d.%s & %s;\n", - bpmem.tevind[n].bt, - tevIndAlphaSel[bpmem.tevind[n].bs], - tevIndAlphaMask[bpmem.tevind[n].fmt]); - } - else - { - // TODO: Should we reset alphabump to 0 here? - } + out.Write("\t// indirect op\n"); + // perform the indirect op on the incoming regular coordinates using iindtex%d as the offset + // coords + if (bpmem.tevind[n].bs != ITBA_OFF) + { + const char* tevIndAlphaSel[] = {"", "x", "y", "z"}; + const char* tevIndAlphaMask[] = {"248", "224", "240", + "248"}; // 0b11111000, 0b11100000, 0b11110000, 0b11111000 + out.Write("alphabump = iindtex%d.%s & %s;\n", bpmem.tevind[n].bt, + tevIndAlphaSel[bpmem.tevind[n].bs], tevIndAlphaMask[bpmem.tevind[n].fmt]); + } + else + { + // TODO: Should we reset alphabump to 0 here? + } - if (bpmem.tevind[n].mid != 0) - { - // format - const char *tevIndFmtMask[] = { "255", "31", "15", "7" }; - out.Write("\tint3 iindtevcrd%d = iindtex%d & %s;\n", n, bpmem.tevind[n].bt, tevIndFmtMask[bpmem.tevind[n].fmt]); + if (bpmem.tevind[n].mid != 0) + { + // format + const char* tevIndFmtMask[] = {"255", "31", "15", "7"}; + out.Write("\tint3 iindtevcrd%d = iindtex%d & %s;\n", n, bpmem.tevind[n].bt, + tevIndFmtMask[bpmem.tevind[n].fmt]); - // bias - TODO: Check if this needs to be this complicated.. - const char *tevIndBiasField[] = { "", "x", "y", "xy", "z", "xz", "yz", "xyz" }; // indexed by bias - const char *tevIndBiasAdd[] = { "-128", "1", "1", "1" }; // indexed by fmt - if (bpmem.tevind[n].bias == ITB_S || bpmem.tevind[n].bias == ITB_T || bpmem.tevind[n].bias == ITB_U) - out.Write("\tiindtevcrd%d.%s += int(%s);\n", n, tevIndBiasField[bpmem.tevind[n].bias], tevIndBiasAdd[bpmem.tevind[n].fmt]); - else if (bpmem.tevind[n].bias == ITB_ST || bpmem.tevind[n].bias == ITB_SU || bpmem.tevind[n].bias == ITB_TU) - out.Write("\tiindtevcrd%d.%s += int2(%s, %s);\n", n, tevIndBiasField[bpmem.tevind[n].bias], tevIndBiasAdd[bpmem.tevind[n].fmt], tevIndBiasAdd[bpmem.tevind[n].fmt]); - else if (bpmem.tevind[n].bias == ITB_STU) - out.Write("\tiindtevcrd%d.%s += int3(%s, %s, %s);\n", n, tevIndBiasField[bpmem.tevind[n].bias], tevIndBiasAdd[bpmem.tevind[n].fmt], tevIndBiasAdd[bpmem.tevind[n].fmt], tevIndBiasAdd[bpmem.tevind[n].fmt]); + // bias - TODO: Check if this needs to be this complicated.. + const char* tevIndBiasField[] = {"", "x", "y", "xy", + "z", "xz", "yz", "xyz"}; // indexed by bias + const char* tevIndBiasAdd[] = {"-128", "1", "1", "1"}; // indexed by fmt + if (bpmem.tevind[n].bias == ITB_S || bpmem.tevind[n].bias == ITB_T || + bpmem.tevind[n].bias == ITB_U) + out.Write("\tiindtevcrd%d.%s += int(%s);\n", n, tevIndBiasField[bpmem.tevind[n].bias], + tevIndBiasAdd[bpmem.tevind[n].fmt]); + else if (bpmem.tevind[n].bias == ITB_ST || bpmem.tevind[n].bias == ITB_SU || + bpmem.tevind[n].bias == ITB_TU) + out.Write("\tiindtevcrd%d.%s += int2(%s, %s);\n", n, tevIndBiasField[bpmem.tevind[n].bias], + tevIndBiasAdd[bpmem.tevind[n].fmt], tevIndBiasAdd[bpmem.tevind[n].fmt]); + else if (bpmem.tevind[n].bias == ITB_STU) + out.Write("\tiindtevcrd%d.%s += int3(%s, %s, %s);\n", n, + tevIndBiasField[bpmem.tevind[n].bias], tevIndBiasAdd[bpmem.tevind[n].fmt], + tevIndBiasAdd[bpmem.tevind[n].fmt], tevIndBiasAdd[bpmem.tevind[n].fmt]); - // multiply by offset matrix and scale - calculations are likely to overflow badly, - // yet it works out since we only care about the lower 23 bits (+1 sign bit) of the result - if (bpmem.tevind[n].mid <= 3) - { - int mtxidx = 2*(bpmem.tevind[n].mid-1); - out.SetConstantsUsed(C_INDTEXMTX+mtxidx, C_INDTEXMTX+mtxidx); + // multiply by offset matrix and scale - calculations are likely to overflow badly, + // yet it works out since we only care about the lower 23 bits (+1 sign bit) of the result + if (bpmem.tevind[n].mid <= 3) + { + int mtxidx = 2 * (bpmem.tevind[n].mid - 1); + out.SetConstantsUsed(C_INDTEXMTX + mtxidx, C_INDTEXMTX + mtxidx); - out.Write("\tint2 indtevtrans%d = int2(idot(" I_INDTEXMTX"[%d].xyz, iindtevcrd%d), idot(" I_INDTEXMTX"[%d].xyz, iindtevcrd%d)) >> 3;\n", n, mtxidx, n, mtxidx+1, n); + out.Write("\tint2 indtevtrans%d = int2(idot(" I_INDTEXMTX + "[%d].xyz, iindtevcrd%d), idot(" I_INDTEXMTX "[%d].xyz, iindtevcrd%d)) >> 3;\n", + n, mtxidx, n, mtxidx + 1, n); - // TODO: should use a shader uid branch for this for better performance - out.Write("\tif (" I_INDTEXMTX"[%d].w >= 0) indtevtrans%d >>= " I_INDTEXMTX"[%d].w;\n", mtxidx, n, mtxidx); - out.Write("\telse indtevtrans%d <<= (-" I_INDTEXMTX"[%d].w);\n", n, mtxidx); - } - else if (bpmem.tevind[n].mid <= 7 && bHasTexCoord) - { // s matrix - _assert_(bpmem.tevind[n].mid >= 5); - int mtxidx = 2*(bpmem.tevind[n].mid-5); - out.SetConstantsUsed(C_INDTEXMTX+mtxidx, C_INDTEXMTX+mtxidx); + // TODO: should use a shader uid branch for this for better performance + out.Write("\tif (" I_INDTEXMTX "[%d].w >= 0) indtevtrans%d >>= " I_INDTEXMTX "[%d].w;\n", + mtxidx, n, mtxidx); + out.Write("\telse indtevtrans%d <<= (-" I_INDTEXMTX "[%d].w);\n", n, mtxidx); + } + else if (bpmem.tevind[n].mid <= 7 && bHasTexCoord) + { // s matrix + _assert_(bpmem.tevind[n].mid >= 5); + int mtxidx = 2 * (bpmem.tevind[n].mid - 5); + out.SetConstantsUsed(C_INDTEXMTX + mtxidx, C_INDTEXMTX + mtxidx); - out.Write("\tint2 indtevtrans%d = int2(fixpoint_uv%d * iindtevcrd%d.xx) >> 8;\n", n, texcoord, n); + out.Write("\tint2 indtevtrans%d = int2(fixpoint_uv%d * iindtevcrd%d.xx) >> 8;\n", n, + texcoord, n); - out.Write("\tif (" I_INDTEXMTX"[%d].w >= 0) indtevtrans%d >>= " I_INDTEXMTX"[%d].w;\n", mtxidx, n, mtxidx); - out.Write("\telse indtevtrans%d <<= (-" I_INDTEXMTX"[%d].w);\n", n, mtxidx); - } - else if (bpmem.tevind[n].mid <= 11 && bHasTexCoord) - { // t matrix - _assert_(bpmem.tevind[n].mid >= 9); - int mtxidx = 2*(bpmem.tevind[n].mid-9); - out.SetConstantsUsed(C_INDTEXMTX+mtxidx, C_INDTEXMTX+mtxidx); + out.Write("\tif (" I_INDTEXMTX "[%d].w >= 0) indtevtrans%d >>= " I_INDTEXMTX "[%d].w;\n", + mtxidx, n, mtxidx); + out.Write("\telse indtevtrans%d <<= (-" I_INDTEXMTX "[%d].w);\n", n, mtxidx); + } + else if (bpmem.tevind[n].mid <= 11 && bHasTexCoord) + { // t matrix + _assert_(bpmem.tevind[n].mid >= 9); + int mtxidx = 2 * (bpmem.tevind[n].mid - 9); + out.SetConstantsUsed(C_INDTEXMTX + mtxidx, C_INDTEXMTX + mtxidx); - out.Write("\tint2 indtevtrans%d = int2(fixpoint_uv%d * iindtevcrd%d.yy) >> 8;\n", n, texcoord, n); + out.Write("\tint2 indtevtrans%d = int2(fixpoint_uv%d * iindtevcrd%d.yy) >> 8;\n", n, + texcoord, n); - out.Write("\tif (" I_INDTEXMTX"[%d].w >= 0) indtevtrans%d >>= " I_INDTEXMTX"[%d].w;\n", mtxidx, n, mtxidx); - out.Write("\telse indtevtrans%d <<= (-" I_INDTEXMTX"[%d].w);\n", n, mtxidx); - } - else - { - out.Write("\tint2 indtevtrans%d = int2(0, 0);\n", n); - } - } - else - { - out.Write("\tint2 indtevtrans%d = int2(0, 0);\n", n); - } + out.Write("\tif (" I_INDTEXMTX "[%d].w >= 0) indtevtrans%d >>= " I_INDTEXMTX "[%d].w;\n", + mtxidx, n, mtxidx); + out.Write("\telse indtevtrans%d <<= (-" I_INDTEXMTX "[%d].w);\n", n, mtxidx); + } + else + { + out.Write("\tint2 indtevtrans%d = int2(0, 0);\n", n); + } + } + else + { + out.Write("\tint2 indtevtrans%d = int2(0, 0);\n", n); + } - // --------- - // Wrapping - // --------- - const char *tevIndWrapStart[] = {"0", "(256<<7)", "(128<<7)", "(64<<7)", "(32<<7)", "(16<<7)", "1" }; // TODO: Should the last one be 1 or (1<<7)? + // --------- + // Wrapping + // --------- + const char* tevIndWrapStart[] = { + "0", "(256<<7)", "(128<<7)", "(64<<7)", + "(32<<7)", "(16<<7)", "1"}; // TODO: Should the last one be 1 or (1<<7)? - // wrap S - if (bpmem.tevind[n].sw == ITW_OFF) - out.Write("\twrappedcoord.x = fixpoint_uv%d.x;\n", texcoord); - else if (bpmem.tevind[n].sw == ITW_0) - out.Write("\twrappedcoord.x = 0;\n"); - else - out.Write("\twrappedcoord.x = fixpoint_uv%d.x & (%s - 1);\n", texcoord, tevIndWrapStart[bpmem.tevind[n].sw]); + // wrap S + if (bpmem.tevind[n].sw == ITW_OFF) + out.Write("\twrappedcoord.x = fixpoint_uv%d.x;\n", texcoord); + else if (bpmem.tevind[n].sw == ITW_0) + out.Write("\twrappedcoord.x = 0;\n"); + else + out.Write("\twrappedcoord.x = fixpoint_uv%d.x & (%s - 1);\n", texcoord, + tevIndWrapStart[bpmem.tevind[n].sw]); - // wrap T - if (bpmem.tevind[n].tw == ITW_OFF) - out.Write("\twrappedcoord.y = fixpoint_uv%d.y;\n", texcoord); - else if (bpmem.tevind[n].tw == ITW_0) - out.Write("\twrappedcoord.y = 0;\n"); - else - out.Write("\twrappedcoord.y = fixpoint_uv%d.y & (%s - 1);\n", texcoord, tevIndWrapStart[bpmem.tevind[n].tw]); + // wrap T + if (bpmem.tevind[n].tw == ITW_OFF) + out.Write("\twrappedcoord.y = fixpoint_uv%d.y;\n", texcoord); + else if (bpmem.tevind[n].tw == ITW_0) + out.Write("\twrappedcoord.y = 0;\n"); + else + out.Write("\twrappedcoord.y = fixpoint_uv%d.y & (%s - 1);\n", texcoord, + tevIndWrapStart[bpmem.tevind[n].tw]); - if (bpmem.tevind[n].fb_addprev) // add previous tevcoord - out.Write("\ttevcoord.xy += wrappedcoord + indtevtrans%d;\n", n); - else - out.Write("\ttevcoord.xy = wrappedcoord + indtevtrans%d;\n", n); + if (bpmem.tevind[n].fb_addprev) // add previous tevcoord + out.Write("\ttevcoord.xy += wrappedcoord + indtevtrans%d;\n", n); + else + out.Write("\ttevcoord.xy = wrappedcoord + indtevtrans%d;\n", n); - // Emulate s24 overflows - out.Write("\ttevcoord.xy = (tevcoord.xy << 8) >> 8;\n"); - } + // Emulate s24 overflows + out.Write("\ttevcoord.xy = (tevcoord.xy << 8) >> 8;\n"); + } - TevStageCombiner::ColorCombiner &cc = bpmem.combiners[n].colorC; - TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[n].alphaC; + TevStageCombiner::ColorCombiner& cc = bpmem.combiners[n].colorC; + TevStageCombiner::AlphaCombiner& ac = bpmem.combiners[n].alphaC; - uid_data->stagehash[n].cc = cc.hex & 0xFFFFFF; - uid_data->stagehash[n].ac = ac.hex & 0xFFFFF0; // Storing rswap and tswap later + uid_data->stagehash[n].cc = cc.hex & 0xFFFFFF; + uid_data->stagehash[n].ac = ac.hex & 0xFFFFF0; // Storing rswap and tswap later - if (cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC || - cc.b == TEVCOLORARG_RASA || cc.b == TEVCOLORARG_RASC || - cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC || - cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC || - ac.a == TEVALPHAARG_RASA || ac.b == TEVALPHAARG_RASA || - ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA) - { - const int i = bpmem.combiners[n].alphaC.rswap; - uid_data->stagehash[n].ac |= bpmem.combiners[n].alphaC.rswap; - uid_data->stagehash[n].tevksel_swap1a = bpmem.tevksel[i*2].swap1; - uid_data->stagehash[n].tevksel_swap2a = bpmem.tevksel[i*2].swap2; - uid_data->stagehash[n].tevksel_swap1b = bpmem.tevksel[i*2+1].swap1; - uid_data->stagehash[n].tevksel_swap2b = bpmem.tevksel[i*2+1].swap2; - uid_data->stagehash[n].tevorders_colorchan = bpmem.tevorders[n / 2].getColorChan(n & 1); + if (cc.a == TEVCOLORARG_RASA || cc.a == TEVCOLORARG_RASC || cc.b == TEVCOLORARG_RASA || + cc.b == TEVCOLORARG_RASC || cc.c == TEVCOLORARG_RASA || cc.c == TEVCOLORARG_RASC || + cc.d == TEVCOLORARG_RASA || cc.d == TEVCOLORARG_RASC || ac.a == TEVALPHAARG_RASA || + ac.b == TEVALPHAARG_RASA || ac.c == TEVALPHAARG_RASA || ac.d == TEVALPHAARG_RASA) + { + const int i = bpmem.combiners[n].alphaC.rswap; + uid_data->stagehash[n].ac |= bpmem.combiners[n].alphaC.rswap; + uid_data->stagehash[n].tevksel_swap1a = bpmem.tevksel[i * 2].swap1; + uid_data->stagehash[n].tevksel_swap2a = bpmem.tevksel[i * 2].swap2; + uid_data->stagehash[n].tevksel_swap1b = bpmem.tevksel[i * 2 + 1].swap1; + uid_data->stagehash[n].tevksel_swap2b = bpmem.tevksel[i * 2 + 1].swap2; + uid_data->stagehash[n].tevorders_colorchan = bpmem.tevorders[n / 2].getColorChan(n & 1); - const char *rasswap = swapModeTable[bpmem.combiners[n].alphaC.rswap]; - out.Write("\trastemp = %s.%s;\n", tevRasTable[bpmem.tevorders[n / 2].getColorChan(n & 1)], rasswap); - } + const char* rasswap = swapModeTable[bpmem.combiners[n].alphaC.rswap]; + out.Write("\trastemp = %s.%s;\n", tevRasTable[bpmem.tevorders[n / 2].getColorChan(n & 1)], + rasswap); + } - uid_data->stagehash[n].tevorders_enable = bpmem.tevorders[n / 2].getEnable(n & 1); - if (bpmem.tevorders[n/2].getEnable(n&1)) - { - int texmap = bpmem.tevorders[n/2].getTexMap(n&1); - if (!bHasIndStage) - { - // calc tevcord - if (bHasTexCoord) - out.Write("\ttevcoord.xy = fixpoint_uv%d;\n", texcoord); - else - out.Write("\ttevcoord.xy = int2(0, 0);\n"); - } + uid_data->stagehash[n].tevorders_enable = bpmem.tevorders[n / 2].getEnable(n & 1); + if (bpmem.tevorders[n / 2].getEnable(n & 1)) + { + int texmap = bpmem.tevorders[n / 2].getTexMap(n & 1); + if (!bHasIndStage) + { + // calc tevcord + if (bHasTexCoord) + out.Write("\ttevcoord.xy = fixpoint_uv%d;\n", texcoord); + else + out.Write("\ttevcoord.xy = int2(0, 0);\n"); + } - const int i = bpmem.combiners[n].alphaC.tswap; - uid_data->stagehash[n].ac |= bpmem.combiners[n].alphaC.tswap << 2; - uid_data->stagehash[n].tevksel_swap1c = bpmem.tevksel[i*2].swap1; - uid_data->stagehash[n].tevksel_swap2c = bpmem.tevksel[i*2].swap2; - uid_data->stagehash[n].tevksel_swap1d = bpmem.tevksel[i*2+1].swap1; - uid_data->stagehash[n].tevksel_swap2d = bpmem.tevksel[i*2+1].swap2; + const int i = bpmem.combiners[n].alphaC.tswap; + uid_data->stagehash[n].ac |= bpmem.combiners[n].alphaC.tswap << 2; + uid_data->stagehash[n].tevksel_swap1c = bpmem.tevksel[i * 2].swap1; + uid_data->stagehash[n].tevksel_swap2c = bpmem.tevksel[i * 2].swap2; + uid_data->stagehash[n].tevksel_swap1d = bpmem.tevksel[i * 2 + 1].swap1; + uid_data->stagehash[n].tevksel_swap2d = bpmem.tevksel[i * 2 + 1].swap2; - uid_data->stagehash[n].tevorders_texmap= bpmem.tevorders[n/2].getTexMap(n&1); + uid_data->stagehash[n].tevorders_texmap = bpmem.tevorders[n / 2].getTexMap(n & 1); - const char *texswap = swapModeTable[bpmem.combiners[n].alphaC.tswap]; - uid_data->SetTevindrefTexmap(i, texmap); + const char* texswap = swapModeTable[bpmem.combiners[n].alphaC.tswap]; + uid_data->SetTevindrefTexmap(i, texmap); - out.Write("\ttextemp = "); - SampleTexture(out, "float2(tevcoord.xy)", texswap, texmap, ApiType); - } - else - { - out.Write("\ttextemp = int4(255, 255, 255, 255);\n"); - } + out.Write("\ttextemp = "); + SampleTexture(out, "float2(tevcoord.xy)", texswap, texmap, ApiType); + } + else + { + out.Write("\ttextemp = int4(255, 255, 255, 255);\n"); + } + if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || cc.c == TEVCOLORARG_KONST || + cc.d == TEVCOLORARG_KONST || ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || + ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST) + { + int kc = bpmem.tevksel[n / 2].getKC(n & 1); + int ka = bpmem.tevksel[n / 2].getKA(n & 1); + uid_data->stagehash[n].tevksel_kc = kc; + uid_data->stagehash[n].tevksel_ka = ka; + out.Write("\tkonsttemp = int4(%s, %s);\n", tevKSelTableC[kc], tevKSelTableA[ka]); - if (cc.a == TEVCOLORARG_KONST || cc.b == TEVCOLORARG_KONST || - cc.c == TEVCOLORARG_KONST || cc.d == TEVCOLORARG_KONST || - ac.a == TEVALPHAARG_KONST || ac.b == TEVALPHAARG_KONST || - ac.c == TEVALPHAARG_KONST || ac.d == TEVALPHAARG_KONST) - { - int kc = bpmem.tevksel[n / 2].getKC(n & 1); - int ka = bpmem.tevksel[n / 2].getKA(n & 1); - uid_data->stagehash[n].tevksel_kc = kc; - uid_data->stagehash[n].tevksel_ka = ka; - out.Write("\tkonsttemp = int4(%s, %s);\n", tevKSelTableC[kc], tevKSelTableA[ka]); + if (kc > 7) + out.SetConstantsUsed(C_KCOLORS + ((kc - 0xc) % 4), C_KCOLORS + ((kc - 0xc) % 4)); + if (ka > 7) + out.SetConstantsUsed(C_KCOLORS + ((ka - 0xc) % 4), C_KCOLORS + ((ka - 0xc) % 4)); + } - if (kc > 7) - out.SetConstantsUsed(C_KCOLORS+((kc-0xc)%4),C_KCOLORS+((kc-0xc)%4)); - if (ka > 7) - out.SetConstantsUsed(C_KCOLORS+((ka-0xc)%4),C_KCOLORS+((ka-0xc)%4)); - } + if (cc.d == TEVCOLORARG_C0 || cc.d == TEVCOLORARG_A0 || ac.d == TEVALPHAARG_A0) + out.SetConstantsUsed(C_COLORS + 1, C_COLORS + 1); - if (cc.d == TEVCOLORARG_C0 || cc.d == TEVCOLORARG_A0 || ac.d == TEVALPHAARG_A0) - out.SetConstantsUsed(C_COLORS+1,C_COLORS+1); + if (cc.d == TEVCOLORARG_C1 || cc.d == TEVCOLORARG_A1 || ac.d == TEVALPHAARG_A1) + out.SetConstantsUsed(C_COLORS + 2, C_COLORS + 2); - if (cc.d == TEVCOLORARG_C1 || cc.d == TEVCOLORARG_A1 || ac.d == TEVALPHAARG_A1) - out.SetConstantsUsed(C_COLORS+2,C_COLORS+2); + if (cc.d == TEVCOLORARG_C2 || cc.d == TEVCOLORARG_A2 || ac.d == TEVALPHAARG_A2) + out.SetConstantsUsed(C_COLORS + 3, C_COLORS + 3); - if (cc.d == TEVCOLORARG_C2 || cc.d == TEVCOLORARG_A2 || ac.d == TEVALPHAARG_A2) - out.SetConstantsUsed(C_COLORS+3,C_COLORS+3); + if (cc.dest >= GX_TEVREG0 && cc.dest <= GX_TEVREG2) + out.SetConstantsUsed(C_COLORS + cc.dest, C_COLORS + cc.dest); - if (cc.dest >= GX_TEVREG0 && cc.dest <= GX_TEVREG2) - out.SetConstantsUsed(C_COLORS+cc.dest, C_COLORS+cc.dest); + if (ac.dest >= GX_TEVREG0 && ac.dest <= GX_TEVREG2) + out.SetConstantsUsed(C_COLORS + ac.dest, C_COLORS + ac.dest); - if (ac.dest >= GX_TEVREG0 && ac.dest <= GX_TEVREG2) - out.SetConstantsUsed(C_COLORS+ac.dest, C_COLORS+ac.dest); + out.Write("\ttevin_a = int4(%s, %s)&int4(255, 255, 255, 255);\n", tevCInputTable[cc.a], + tevAInputTable[ac.a]); + out.Write("\ttevin_b = int4(%s, %s)&int4(255, 255, 255, 255);\n", tevCInputTable[cc.b], + tevAInputTable[ac.b]); + out.Write("\ttevin_c = int4(%s, %s)&int4(255, 255, 255, 255);\n", tevCInputTable[cc.c], + tevAInputTable[ac.c]); + out.Write("\ttevin_d = int4(%s, %s);\n", tevCInputTable[cc.d], tevAInputTable[ac.d]); + out.Write("\t// color combine\n"); + out.Write("\t%s = clamp(", tevCOutputTable[cc.dest]); + if (cc.bias != TEVBIAS_COMPARE) + { + WriteTevRegular(out, "rgb", cc.bias, cc.op, cc.clamp, cc.shift); + } + else + { + const char* function_table[] = + { + "((tevin_a.r > tevin_b.r) ? tevin_c.rgb : int3(0,0,0))", // TEVCMP_R8_GT + "((tevin_a.r == tevin_b.r) ? tevin_c.rgb : int3(0,0,0))", // TEVCMP_R8_EQ + "((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.rgb : " + "int3(0,0,0))", // TEVCMP_GR16_GT + "((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.rgb : " + "int3(0,0,0))", // TEVCMP_GR16_EQ + "((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.rgb : " + "int3(0,0,0))", // TEVCMP_BGR24_GT + "((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.rgb : " + "int3(0,0,0))", // TEVCMP_BGR24_EQ + "(max(sign(tevin_a.rgb - tevin_b.rgb), int3(0,0,0)) * tevin_c.rgb)", // TEVCMP_RGB8_GT + "((int3(1,1,1) - sign(abs(tevin_a.rgb - tevin_b.rgb))) * tevin_c.rgb)" // TEVCMP_RGB8_EQ + }; - out.Write("\ttevin_a = int4(%s, %s)&int4(255, 255, 255, 255);\n", tevCInputTable[cc.a], tevAInputTable[ac.a]); - out.Write("\ttevin_b = int4(%s, %s)&int4(255, 255, 255, 255);\n", tevCInputTable[cc.b], tevAInputTable[ac.b]); - out.Write("\ttevin_c = int4(%s, %s)&int4(255, 255, 255, 255);\n", tevCInputTable[cc.c], tevAInputTable[ac.c]); - out.Write("\ttevin_d = int4(%s, %s);\n", tevCInputTable[cc.d], tevAInputTable[ac.d]); + int mode = (cc.shift << 1) | cc.op; + out.Write(" tevin_d.rgb + "); + out.Write("%s", function_table[mode]); + } + if (cc.clamp) + out.Write(", int3(0,0,0), int3(255,255,255))"); + else + out.Write(", int3(-1024,-1024,-1024), int3(1023,1023,1023))"); + out.Write(";\n"); - out.Write("\t// color combine\n"); - out.Write("\t%s = clamp(", tevCOutputTable[cc.dest]); - if (cc.bias != TEVBIAS_COMPARE) - { - WriteTevRegular(out, "rgb", cc.bias, cc.op, cc.clamp, cc.shift); - } - else - { - const char *function_table[] = - { - "((tevin_a.r > tevin_b.r) ? tevin_c.rgb : int3(0,0,0))", // TEVCMP_R8_GT - "((tevin_a.r == tevin_b.r) ? tevin_c.rgb : int3(0,0,0))", // TEVCMP_R8_EQ - "((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.rgb : int3(0,0,0))", // TEVCMP_GR16_GT - "((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.rgb : int3(0,0,0))", // TEVCMP_GR16_EQ - "((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.rgb : int3(0,0,0))", // TEVCMP_BGR24_GT - "((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.rgb : int3(0,0,0))", // TEVCMP_BGR24_EQ - "(max(sign(tevin_a.rgb - tevin_b.rgb), int3(0,0,0)) * tevin_c.rgb)", // TEVCMP_RGB8_GT - "((int3(1,1,1) - sign(abs(tevin_a.rgb - tevin_b.rgb))) * tevin_c.rgb)" // TEVCMP_RGB8_EQ - }; + out.Write("\t// alpha combine\n"); + out.Write("\t%s = clamp(", tevAOutputTable[ac.dest]); + if (ac.bias != TEVBIAS_COMPARE) + { + WriteTevRegular(out, "a", ac.bias, ac.op, ac.clamp, ac.shift); + } + else + { + const char* function_table[] = { + "((tevin_a.r > tevin_b.r) ? tevin_c.a : 0)", // TEVCMP_R8_GT + "((tevin_a.r == tevin_b.r) ? tevin_c.a : 0)", // TEVCMP_R8_EQ + "((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // TEVCMP_GR16_GT + "((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // TEVCMP_GR16_EQ + "((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // TEVCMP_BGR24_GT + "((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // TEVCMP_BGR24_EQ + "((tevin_a.a > tevin_b.a) ? tevin_c.a : 0)", // TEVCMP_A8_GT + "((tevin_a.a == tevin_b.a) ? tevin_c.a : 0)" // TEVCMP_A8_EQ + }; - int mode = (cc.shift<<1)|cc.op; - out.Write(" tevin_d.rgb + "); - out.Write("%s", function_table[mode]); - } - if (cc.clamp) - out.Write(", int3(0,0,0), int3(255,255,255))"); - else - out.Write(", int3(-1024,-1024,-1024), int3(1023,1023,1023))"); - out.Write(";\n"); + int mode = (ac.shift << 1) | ac.op; + out.Write(" tevin_d.a + "); + out.Write("%s", function_table[mode]); + } + if (ac.clamp) + out.Write(", 0, 255)"); + else + out.Write(", -1024, 1023)"); - out.Write("\t// alpha combine\n"); - out.Write("\t%s = clamp(", tevAOutputTable[ac.dest]); - if (ac.bias != TEVBIAS_COMPARE) - { - WriteTevRegular(out, "a", ac.bias, ac.op, ac.clamp, ac.shift); - } - else - { - const char *function_table[] = - { - "((tevin_a.r > tevin_b.r) ? tevin_c.a : 0)", // TEVCMP_R8_GT - "((tevin_a.r == tevin_b.r) ? tevin_c.a : 0)", // TEVCMP_R8_EQ - "((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // TEVCMP_GR16_GT - "((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0)", // TEVCMP_GR16_EQ - "((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // TEVCMP_BGR24_GT - "((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0)", // TEVCMP_BGR24_EQ - "((tevin_a.a > tevin_b.a) ? tevin_c.a : 0)", // TEVCMP_A8_GT - "((tevin_a.a == tevin_b.a) ? tevin_c.a : 0)" // TEVCMP_A8_EQ - }; - - int mode = (ac.shift<<1)|ac.op; - out.Write(" tevin_d.a + "); - out.Write("%s", function_table[mode]); - } - if (ac.clamp) - out.Write(", 0, 255)"); - else - out.Write(", -1024, 1023)"); - - out.Write(";\n"); + out.Write(";\n"); } -template +template static void WriteTevRegular(T& out, const char* components, int bias, int op, int clamp, int shift) { - const char *tevScaleTableLeft[] = - { - "", // SCALE_1 - " << 1", // SCALE_2 - " << 2", // SCALE_4 - "", // DIVIDE_2 - }; + const char* tevScaleTableLeft[] = { + "", // SCALE_1 + " << 1", // SCALE_2 + " << 2", // SCALE_4 + "", // DIVIDE_2 + }; - const char *tevScaleTableRight[] = - { - "", // SCALE_1 - "", // SCALE_2 - "", // SCALE_4 - " >> 1", // DIVIDE_2 - }; + const char* tevScaleTableRight[] = { + "", // SCALE_1 + "", // SCALE_2 + "", // SCALE_4 + " >> 1", // DIVIDE_2 + }; - const char *tevLerpBias[] = // indexed by 2*op+(shift==3) - { - "", - " + 128", - "", - " + 127", - }; + const char* tevLerpBias[] = // indexed by 2*op+(shift==3) + { + "", " + 128", "", " + 127", + }; - const char *tevBiasTable[] = - { - "", // ZERO, - " + 128", // ADDHALF, - " - 128", // SUBHALF, - "", - }; + const char* tevBiasTable[] = { + "", // ZERO, + " + 128", // ADDHALF, + " - 128", // SUBHALF, + "", + }; - const char *tevOpTable[] = { - "+", // TEVOP_ADD = 0, - "-", // TEVOP_SUB = 1, - }; + const char* tevOpTable[] = { + "+", // TEVOP_ADD = 0, + "-", // TEVOP_SUB = 1, + }; - // Regular TEV stage: (d + bias + lerp(a,b,c)) * scale - // The GameCube/Wii GPU uses a very sophisticated algorithm for scale-lerping: - // - c is scaled from 0..255 to 0..256, which allows dividing the result by 256 instead of 255 - // - if scale is bigger than one, it is moved inside the lerp calculation for increased accuracy - // - a rounding bias is added before dividing by 256 - out.Write("(((tevin_d.%s%s)%s)", components, tevBiasTable[bias], tevScaleTableLeft[shift]); - out.Write(" %s ", tevOpTable[op]); - out.Write("(((((tevin_a.%s<<8) + (tevin_b.%s-tevin_a.%s)*(tevin_c.%s+(tevin_c.%s>>7)))%s)%s)>>8)", - components, components, components, components, components, - tevScaleTableLeft[shift], tevLerpBias[2*op+(shift!=3)]); - out.Write(")%s", tevScaleTableRight[shift]); + // Regular TEV stage: (d + bias + lerp(a,b,c)) * scale + // The GameCube/Wii GPU uses a very sophisticated algorithm for scale-lerping: + // - c is scaled from 0..255 to 0..256, which allows dividing the result by 256 instead of 255 + // - if scale is bigger than one, it is moved inside the lerp calculation for increased accuracy + // - a rounding bias is added before dividing by 256 + out.Write("(((tevin_d.%s%s)%s)", components, tevBiasTable[bias], tevScaleTableLeft[shift]); + out.Write(" %s ", tevOpTable[op]); + out.Write("(((((tevin_a.%s<<8) + (tevin_b.%s-tevin_a.%s)*(tevin_c.%s+(tevin_c.%s>>7)))%s)%s)>>8)", + components, components, components, components, components, tevScaleTableLeft[shift], + tevLerpBias[2 * op + (shift != 3)]); + out.Write(")%s", tevScaleTableRight[shift]); } -template -static void SampleTexture(T& out, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType) +template +static void SampleTexture(T& out, const char* texcoords, const char* texswap, int texmap, + API_TYPE ApiType) { - out.SetConstantsUsed(C_TEXDIMS+texmap,C_TEXDIMS+texmap); + out.SetConstantsUsed(C_TEXDIMS + texmap, C_TEXDIMS + texmap); - if (ApiType == API_D3D) - out.Write("iround(255.0 * Tex[%d].Sample(samp[%d], float3(%s.xy * " I_TEXDIMS"[%d].xy, %s))).%s;\n", texmap, texmap, texcoords, texmap, g_ActiveConfig.iStereoMode > 0 ? "layer" : "0.0", texswap); - else - out.Write("iround(255.0 * texture(samp[%d], float3(%s.xy * " I_TEXDIMS"[%d].xy, %s))).%s;\n", texmap, texcoords, texmap, g_ActiveConfig.iStereoMode > 0 ? "layer" : "0.0", texswap); + if (ApiType == API_D3D) + out.Write("iround(255.0 * Tex[%d].Sample(samp[%d], float3(%s.xy * " I_TEXDIMS + "[%d].xy, %s))).%s;\n", + texmap, texmap, texcoords, texmap, g_ActiveConfig.iStereoMode > 0 ? "layer" : "0.0", + texswap); + else + out.Write("iround(255.0 * texture(samp[%d], float3(%s.xy * " I_TEXDIMS "[%d].xy, %s))).%s;\n", + texmap, texcoords, texmap, g_ActiveConfig.iStereoMode > 0 ? "layer" : "0.0", texswap); } -static const char *tevAlphaFuncsTable[] = -{ - "(false)", // NEVER - "(prev.a < %s)", // LESS - "(prev.a == %s)", // EQUAL - "(prev.a <= %s)", // LEQUAL - "(prev.a > %s)", // GREATER - "(prev.a != %s)", // NEQUAL - "(prev.a >= %s)", // GEQUAL - "(true)" // ALWAYS +static const char* tevAlphaFuncsTable[] = { + "(false)", // NEVER + "(prev.a < %s)", // LESS + "(prev.a == %s)", // EQUAL + "(prev.a <= %s)", // LEQUAL + "(prev.a > %s)", // GREATER + "(prev.a != %s)", // NEQUAL + "(prev.a >= %s)", // GEQUAL + "(true)" // ALWAYS }; -static const char *tevAlphaFunclogicTable[] = -{ - " && ", // and - " || ", // or - " != ", // xor - " == " // xnor +static const char* tevAlphaFunclogicTable[] = { + " && ", // and + " || ", // or + " != ", // xor + " == " // xnor }; -template -static void WriteAlphaTest(T& out, pixel_shader_uid_data* uid_data, API_TYPE ApiType, DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth) +template +static void WriteAlphaTest(T& out, pixel_shader_uid_data* uid_data, API_TYPE ApiType, + DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth) { - static const char *alphaRef[2] = - { - I_ALPHA".r", - I_ALPHA".g" - }; + static const char* alphaRef[2] = {I_ALPHA ".r", I_ALPHA ".g"}; - out.SetConstantsUsed(C_ALPHA, C_ALPHA); + out.SetConstantsUsed(C_ALPHA, C_ALPHA); - if (DriverDetails::HasBug(DriverDetails::BUG_BROKENNEGATEDBOOLEAN)) - out.Write("\tif(( "); - else - out.Write("\tif(!( "); + if (DriverDetails::HasBug(DriverDetails::BUG_BROKENNEGATEDBOOLEAN)) + out.Write("\tif(( "); + else + out.Write("\tif(!( "); - uid_data->alpha_test_comp0 = bpmem.alpha_test.comp0; - uid_data->alpha_test_comp1 = bpmem.alpha_test.comp1; - uid_data->alpha_test_logic = bpmem.alpha_test.logic; + uid_data->alpha_test_comp0 = bpmem.alpha_test.comp0; + uid_data->alpha_test_comp1 = bpmem.alpha_test.comp1; + uid_data->alpha_test_logic = bpmem.alpha_test.logic; - // Lookup the first component from the alpha function table - int compindex = bpmem.alpha_test.comp0; - out.Write(tevAlphaFuncsTable[compindex], alphaRef[0]); + // Lookup the first component from the alpha function table + int compindex = bpmem.alpha_test.comp0; + out.Write(tevAlphaFuncsTable[compindex], alphaRef[0]); - out.Write("%s", tevAlphaFunclogicTable[bpmem.alpha_test.logic]); // lookup the logic op + out.Write("%s", tevAlphaFunclogicTable[bpmem.alpha_test.logic]); // lookup the logic op - // Lookup the second component from the alpha function table - compindex = bpmem.alpha_test.comp1; - out.Write(tevAlphaFuncsTable[compindex], alphaRef[1]); + // Lookup the second component from the alpha function table + compindex = bpmem.alpha_test.comp1; + out.Write(tevAlphaFuncsTable[compindex], alphaRef[1]); - if (DriverDetails::HasBug(DriverDetails::BUG_BROKENNEGATEDBOOLEAN)) - out.Write(") == false) {\n"); - else - out.Write(")) {\n"); + if (DriverDetails::HasBug(DriverDetails::BUG_BROKENNEGATEDBOOLEAN)) + out.Write(") == false) {\n"); + else + out.Write(")) {\n"); - out.Write("\t\tocol0 = float4(0.0, 0.0, 0.0, 0.0);\n"); - if (dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) - out.Write("\t\tocol1 = float4(0.0, 0.0, 0.0, 0.0);\n"); - if (per_pixel_depth) - out.Write("\t\tdepth = %s;\n", (ApiType == API_D3D) ? "0.0" : "1.0"); + out.Write("\t\tocol0 = float4(0.0, 0.0, 0.0, 0.0);\n"); + if (dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) + out.Write("\t\tocol1 = float4(0.0, 0.0, 0.0, 0.0);\n"); + if (per_pixel_depth) + out.Write("\t\tdepth = %s;\n", (ApiType == API_D3D) ? "0.0" : "1.0"); - // ZCOMPLOC HACK: - // The only way to emulate alpha test + early-z is to force early-z in the shader. - // As this isn't available on all drivers and as we can't emulate this feature otherwise, - // we are only able to choose which one we want to respect more. - // Tests seem to have proven that writing depth even when the alpha test fails is more - // important that a reliable alpha test, so we just force the alpha test to always succeed. - // At least this seems to be less buggy. - uid_data->alpha_test_use_zcomploc_hack = bpmem.UseEarlyDepthTest() - && bpmem.zmode.updateenable - && !g_ActiveConfig.backend_info.bSupportsEarlyZ - && !bpmem.genMode.zfreeze; + // ZCOMPLOC HACK: + // The only way to emulate alpha test + early-z is to force early-z in the shader. + // As this isn't available on all drivers and as we can't emulate this feature otherwise, + // we are only able to choose which one we want to respect more. + // Tests seem to have proven that writing depth even when the alpha test fails is more + // important that a reliable alpha test, so we just force the alpha test to always succeed. + // At least this seems to be less buggy. + uid_data->alpha_test_use_zcomploc_hack = bpmem.UseEarlyDepthTest() && bpmem.zmode.updateenable && + !g_ActiveConfig.backend_info.bSupportsEarlyZ && + !bpmem.genMode.zfreeze; - if (!uid_data->alpha_test_use_zcomploc_hack) - { - out.Write("\t\tdiscard;\n"); - if (ApiType != API_D3D) - out.Write("\t\treturn;\n"); - } + if (!uid_data->alpha_test_use_zcomploc_hack) + { + out.Write("\t\tdiscard;\n"); + if (ApiType != API_D3D) + out.Write("\t\treturn;\n"); + } - out.Write("\t}\n"); + out.Write("\t}\n"); } -static const char *tevFogFuncsTable[] = -{ - "", // No Fog - "", // ? - "", // Linear - "", // ? - "\tfog = 1.0 - exp2(-8.0 * fog);\n", // exp - "\tfog = 1.0 - exp2(-8.0 * fog * fog);\n", // exp2 - "\tfog = exp2(-8.0 * (1.0 - fog));\n", // backward exp - "\tfog = 1.0 - fog;\n fog = exp2(-8.0 * fog * fog);\n" // backward exp2 +static const char* tevFogFuncsTable[] = { + "", // No Fog + "", // ? + "", // Linear + "", // ? + "\tfog = 1.0 - exp2(-8.0 * fog);\n", // exp + "\tfog = 1.0 - exp2(-8.0 * fog * fog);\n", // exp2 + "\tfog = exp2(-8.0 * (1.0 - fog));\n", // backward exp + "\tfog = 1.0 - fog;\n fog = exp2(-8.0 * fog * fog);\n" // backward exp2 }; -template +template static void WriteFog(T& out, pixel_shader_uid_data* uid_data) { - uid_data->fog_fsel = bpmem.fog.c_proj_fsel.fsel; - if (bpmem.fog.c_proj_fsel.fsel == 0) - return; // no Fog + uid_data->fog_fsel = bpmem.fog.c_proj_fsel.fsel; + if (bpmem.fog.c_proj_fsel.fsel == 0) + return; // no Fog - uid_data->fog_proj = bpmem.fog.c_proj_fsel.proj; + uid_data->fog_proj = bpmem.fog.c_proj_fsel.proj; - out.SetConstantsUsed(C_FOGCOLOR, C_FOGCOLOR); - out.SetConstantsUsed(C_FOGI, C_FOGI); - out.SetConstantsUsed(C_FOGF, C_FOGF+1); - if (bpmem.fog.c_proj_fsel.proj == 0) - { - // perspective - // ze = A/(B - (Zs >> B_SHF) - // TODO: Verify that we want to drop lower bits here! (currently taken over from software renderer) - // Maybe we want to use "ze = (A << B_SHF)/((B << B_SHF) - Zs)" instead? - // That's equivalent, but keeps the lower bits of Zs. - out.Write("\tfloat ze = (" I_FOGF"[1].x * 16777216.0) / float(" I_FOGI".y - (zCoord >> " I_FOGI".w));\n"); - } - else - { - // orthographic - // ze = a*Zs (here, no B_SHF) - out.Write("\tfloat ze = " I_FOGF"[1].x * float(zCoord) / 16777216.0;\n"); - } + out.SetConstantsUsed(C_FOGCOLOR, C_FOGCOLOR); + out.SetConstantsUsed(C_FOGI, C_FOGI); + out.SetConstantsUsed(C_FOGF, C_FOGF + 1); + if (bpmem.fog.c_proj_fsel.proj == 0) + { + // perspective + // ze = A/(B - (Zs >> B_SHF) + // TODO: Verify that we want to drop lower bits here! (currently taken over from software + // renderer) + // Maybe we want to use "ze = (A << B_SHF)/((B << B_SHF) - Zs)" instead? + // That's equivalent, but keeps the lower bits of Zs. + out.Write("\tfloat ze = (" I_FOGF "[1].x * 16777216.0) / float(" I_FOGI + ".y - (zCoord >> " I_FOGI ".w));\n"); + } + else + { + // orthographic + // ze = a*Zs (here, no B_SHF) + out.Write("\tfloat ze = " I_FOGF "[1].x * float(zCoord) / 16777216.0;\n"); + } - // x_adjust = sqrt((x-center)^2 + k^2)/k - // ze *= x_adjust - // TODO Instead of this theoretical calculation, we should use the - // coefficient table given in the fog range BP registers! - uid_data->fog_RangeBaseEnabled = bpmem.fogRange.Base.Enabled; - if (bpmem.fogRange.Base.Enabled) - { - out.SetConstantsUsed(C_FOGF, C_FOGF); - out.Write("\tfloat x_adjust = (2.0 * (rawpos.x / " I_FOGF"[0].y)) - 1.0 - " I_FOGF"[0].x;\n"); - out.Write("\tx_adjust = sqrt(x_adjust * x_adjust + " I_FOGF"[0].z * " I_FOGF"[0].z) / " I_FOGF"[0].z;\n"); - out.Write("\tze *= x_adjust;\n"); - } + // x_adjust = sqrt((x-center)^2 + k^2)/k + // ze *= x_adjust + // TODO Instead of this theoretical calculation, we should use the + // coefficient table given in the fog range BP registers! + uid_data->fog_RangeBaseEnabled = bpmem.fogRange.Base.Enabled; + if (bpmem.fogRange.Base.Enabled) + { + out.SetConstantsUsed(C_FOGF, C_FOGF); + out.Write("\tfloat x_adjust = (2.0 * (rawpos.x / " I_FOGF "[0].y)) - 1.0 - " I_FOGF "[0].x;\n"); + out.Write("\tx_adjust = sqrt(x_adjust * x_adjust + " I_FOGF "[0].z * " I_FOGF "[0].z) / " I_FOGF + "[0].z;\n"); + out.Write("\tze *= x_adjust;\n"); + } - out.Write("\tfloat fog = clamp(ze - " I_FOGF"[1].z, 0.0, 1.0);\n"); + out.Write("\tfloat fog = clamp(ze - " I_FOGF "[1].z, 0.0, 1.0);\n"); - if (bpmem.fog.c_proj_fsel.fsel > 3) - { - out.Write("%s", tevFogFuncsTable[bpmem.fog.c_proj_fsel.fsel]); - } - else - { - if (bpmem.fog.c_proj_fsel.fsel != 2) - WARN_LOG(VIDEO, "Unknown Fog Type! %08x", bpmem.fog.c_proj_fsel.fsel); - } + if (bpmem.fog.c_proj_fsel.fsel > 3) + { + out.Write("%s", tevFogFuncsTable[bpmem.fog.c_proj_fsel.fsel]); + } + else + { + if (bpmem.fog.c_proj_fsel.fsel != 2) + WARN_LOG(VIDEO, "Unknown Fog Type! %08x", bpmem.fog.c_proj_fsel.fsel); + } - out.Write("\tint ifog = iround(fog * 256.0);\n"); - out.Write("\tprev.rgb = (prev.rgb * (256 - ifog) + " I_FOGCOLOR".rgb * ifog) >> 8;\n"); + out.Write("\tint ifog = iround(fog * 256.0);\n"); + out.Write("\tprev.rgb = (prev.rgb * (256 - ifog) + " I_FOGCOLOR ".rgb * ifog) >> 8;\n"); } PixelShaderUid GetPixelShaderUid(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType) { - return GeneratePixelShader(dstAlphaMode, ApiType); + return GeneratePixelShader(dstAlphaMode, ApiType); } ShaderCode GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType) { - return GeneratePixelShader(dstAlphaMode, ApiType); + return GeneratePixelShader(dstAlphaMode, ApiType); } diff --git a/Source/Core/VideoCommon/PixelShaderGen.h b/Source/Core/VideoCommon/PixelShaderGen.h index 3cc8071ce9..8a62b6bb04 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.h +++ b/Source/Core/VideoCommon/PixelShaderGen.h @@ -12,104 +12,133 @@ // Different ways to achieve rendering with destination alpha enum DSTALPHA_MODE { - DSTALPHA_NONE, // Render normally, without destination alpha - DSTALPHA_ALPHA_PASS, // Render normally first, then render again for alpha - DSTALPHA_DUAL_SOURCE_BLEND // Use dual-source blending + DSTALPHA_NONE, // Render normally, without destination alpha + DSTALPHA_ALPHA_PASS, // Render normally first, then render again for alpha + DSTALPHA_DUAL_SOURCE_BLEND // Use dual-source blending }; #pragma pack(1) struct pixel_shader_uid_data { - // TODO: Optimize field order for easy access! + // TODO: Optimize field order for easy access! - u32 num_values; // TODO: Shouldn't be a u32 - u32 NumValues() const { return num_values; } + u32 num_values; // TODO: Shouldn't be a u32 + u32 NumValues() const { return num_values; } + u32 components : 23; + u32 dstAlphaMode : 2; + u32 Pretest : 2; + u32 nIndirectStagesUsed : 4; + u32 stereo : 1; - u32 components : 23; - u32 dstAlphaMode : 2; - u32 Pretest : 2; - u32 nIndirectStagesUsed : 4; - u32 stereo : 1; + u32 genMode_numtexgens : 4; + u32 genMode_numtevstages : 4; + u32 genMode_numindstages : 3; + u32 alpha_test_comp0 : 3; + u32 alpha_test_comp1 : 3; + u32 alpha_test_logic : 2; + u32 alpha_test_use_zcomploc_hack : 1; + u32 fog_proj : 1; + u32 fog_fsel : 3; + u32 fog_RangeBaseEnabled : 1; + u32 ztex_op : 2; + u32 fast_depth_calc : 1; + u32 per_pixel_depth : 1; + u32 forced_early_z : 1; + u32 early_ztest : 1; + u32 bounding_box : 1; - u32 genMode_numtexgens : 4; - u32 genMode_numtevstages : 4; - u32 genMode_numindstages : 3; - u32 alpha_test_comp0 : 3; - u32 alpha_test_comp1 : 3; - u32 alpha_test_logic : 2; - u32 alpha_test_use_zcomploc_hack : 1; - u32 fog_proj : 1; - u32 fog_fsel : 3; - u32 fog_RangeBaseEnabled : 1; - u32 ztex_op : 2; - u32 fast_depth_calc : 1; - u32 per_pixel_depth : 1; - u32 forced_early_z : 1; - u32 early_ztest : 1; - u32 bounding_box : 1; + // TODO: 29 bits of padding is a waste. Can we free up some bits elseware? + u32 zfreeze : 1; + u32 msaa : 1; + u32 ssaa : 1; + u32 pad : 29; - // TODO: 29 bits of padding is a waste. Can we free up some bits elseware? - u32 zfreeze : 1; - u32 msaa : 1; - u32 ssaa : 1; - u32 pad : 29; + u32 texMtxInfo_n_projection : 8; // 8x1 bit + u32 tevindref_bi0 : 3; + u32 tevindref_bc0 : 3; + u32 tevindref_bi1 : 3; + u32 tevindref_bc1 : 3; + u32 tevindref_bi2 : 3; + u32 tevindref_bc3 : 3; + u32 tevindref_bi4 : 3; + u32 tevindref_bc4 : 3; - u32 texMtxInfo_n_projection : 8; // 8x1 bit - u32 tevindref_bi0 : 3; - u32 tevindref_bc0 : 3; - u32 tevindref_bi1 : 3; - u32 tevindref_bc1 : 3; - u32 tevindref_bi2 : 3; - u32 tevindref_bc3 : 3; - u32 tevindref_bi4 : 3; - u32 tevindref_bc4 : 3; + inline void SetTevindrefValues(int index, u32 texcoord, u32 texmap) + { + if (index == 0) + { + tevindref_bc0 = texcoord; + tevindref_bi0 = texmap; + } + else if (index == 1) + { + tevindref_bc1 = texcoord; + tevindref_bi1 = texmap; + } + else if (index == 2) + { + tevindref_bc3 = texcoord; + tevindref_bi2 = texmap; + } + else if (index == 3) + { + tevindref_bc4 = texcoord; + tevindref_bi4 = texmap; + } + } + inline void SetTevindrefTexmap(int index, u32 texmap) + { + if (index == 0) + { + tevindref_bi0 = texmap; + } + else if (index == 1) + { + tevindref_bi1 = texmap; + } + else if (index == 2) + { + tevindref_bi2 = texmap; + } + else if (index == 3) + { + tevindref_bi4 = texmap; + } + } - inline void SetTevindrefValues(int index, u32 texcoord, u32 texmap) - { - if (index == 0) { tevindref_bc0 = texcoord; tevindref_bi0 = texmap; } - else if (index == 1) { tevindref_bc1 = texcoord; tevindref_bi1 = texmap; } - else if (index == 2) { tevindref_bc3 = texcoord; tevindref_bi2 = texmap; } - else if (index == 3) { tevindref_bc4 = texcoord; tevindref_bi4 = texmap; } - } - inline void SetTevindrefTexmap(int index, u32 texmap) - { - if (index == 0) { tevindref_bi0 = texmap; } - else if (index == 1) { tevindref_bi1 = texmap; } - else if (index == 2) { tevindref_bi2 = texmap; } - else if (index == 3) { tevindref_bi4 = texmap; } - } + struct + { + // TODO: Can save a lot space by removing the padding bits + u32 cc : 24; + u32 ac : 24; - struct { - // TODO: Can save a lot space by removing the padding bits - u32 cc : 24; - u32 ac : 24; + u32 tevorders_texmap : 3; + u32 tevorders_texcoord : 3; + u32 tevorders_enable : 1; + u32 tevorders_colorchan : 3; + u32 pad1 : 6; - u32 tevorders_texmap : 3; - u32 tevorders_texcoord : 3; - u32 tevorders_enable : 1; - u32 tevorders_colorchan : 3; - u32 pad1 : 6; + // TODO: Clean up the swapXY mess + u32 hasindstage : 1; + u32 tevind : 21; + u32 tevksel_swap1a : 2; + u32 tevksel_swap2a : 2; + u32 tevksel_swap1b : 2; + u32 tevksel_swap2b : 2; + u32 pad2 : 2; - // TODO: Clean up the swapXY mess - u32 hasindstage : 1; - u32 tevind : 21; - u32 tevksel_swap1a : 2; - u32 tevksel_swap2a : 2; - u32 tevksel_swap1b : 2; - u32 tevksel_swap2b : 2; - u32 pad2 : 2; + u32 tevksel_swap1c : 2; + u32 tevksel_swap2c : 2; + u32 tevksel_swap1d : 2; + u32 tevksel_swap2d : 2; + u32 tevksel_kc : 5; + u32 tevksel_ka : 5; + u32 pad3 : 14; + } stagehash[16]; - u32 tevksel_swap1c : 2; - u32 tevksel_swap2c : 2; - u32 tevksel_swap1d : 2; - u32 tevksel_swap2d : 2; - u32 tevksel_kc : 5; - u32 tevksel_ka : 5; - u32 pad3 : 14; - } stagehash[16]; - - // TODO: I think we're fine without an enablePixelLighting field, should probably double check, though.. - LightingUidData lighting; + // TODO: I think we're fine without an enablePixelLighting field, should probably double check, + // though.. + LightingUidData lighting; }; #pragma pack() diff --git a/Source/Core/VideoCommon/PixelShaderManager.cpp b/Source/Core/VideoCommon/PixelShaderManager.cpp index 2734f64827..be1a9cd1f3 100644 --- a/Source/Core/VideoCommon/PixelShaderManager.cpp +++ b/Source/Core/VideoCommon/PixelShaderManager.cpp @@ -21,280 +21,281 @@ bool PixelShaderManager::dirty; void PixelShaderManager::Init() { - memset(&constants, 0, sizeof(constants)); + memset(&constants, 0, sizeof(constants)); - // Init any intial constants which aren't zero when bpmem is zero. - s_bFogRangeAdjustChanged = true; - s_bViewPortChanged = false; + // Init any intial constants which aren't zero when bpmem is zero. + s_bFogRangeAdjustChanged = true; + s_bViewPortChanged = false; - SetEfbScaleChanged(); - SetIndMatrixChanged(0); - SetIndMatrixChanged(1); - SetIndMatrixChanged(2); - SetZTextureTypeChanged(); - SetTexCoordChanged(0); - SetTexCoordChanged(1); - SetTexCoordChanged(2); - SetTexCoordChanged(3); - SetTexCoordChanged(4); - SetTexCoordChanged(5); - SetTexCoordChanged(6); - SetTexCoordChanged(7); + SetEfbScaleChanged(); + SetIndMatrixChanged(0); + SetIndMatrixChanged(1); + SetIndMatrixChanged(2); + SetZTextureTypeChanged(); + SetTexCoordChanged(0); + SetTexCoordChanged(1); + SetTexCoordChanged(2); + SetTexCoordChanged(3); + SetTexCoordChanged(4); + SetTexCoordChanged(5); + SetTexCoordChanged(6); + SetTexCoordChanged(7); - dirty = true; + dirty = true; } void PixelShaderManager::Dirty() { - // This function is called after a savestate is loaded. - // Any constants that can changed based on settings should be re-calculated - s_bFogRangeAdjustChanged = true; + // This function is called after a savestate is loaded. + // Any constants that can changed based on settings should be re-calculated + s_bFogRangeAdjustChanged = true; - SetEfbScaleChanged(); - SetFogParamChanged(); + SetEfbScaleChanged(); + SetFogParamChanged(); - dirty = true; + dirty = true; } void PixelShaderManager::Shutdown() { - } void PixelShaderManager::SetConstants() { - if (s_bFogRangeAdjustChanged) - { - // set by two components, so keep changed flag here - // TODO: try to split both registers and move this logic to the shader - if (!g_ActiveConfig.bDisableFog && bpmem.fogRange.Base.Enabled == 1) - { - //bpmem.fogRange.Base.Center : center of the viewport in x axis. observation: bpmem.fogRange.Base.Center = realcenter + 342; - int center = ((u32)bpmem.fogRange.Base.Center) - 342; - // normalize center to make calculations easy - float ScreenSpaceCenter = center / (2.0f * xfmem.viewport.wd); - ScreenSpaceCenter = (ScreenSpaceCenter * 2.0f) - 1.0f; - //bpmem.fogRange.K seems to be a table of precalculated coefficients for the adjust factor - //observations: bpmem.fogRange.K[0].LO appears to be the lowest value and bpmem.fogRange.K[4].HI the largest - // they always seems to be larger than 256 so my theory is : - // they are the coefficients from the center to the border of the screen - // so to simplify I use the hi coefficient as K in the shader taking 256 as the scale - // TODO: Shouldn't this be EFBToScaledXf? - constants.fogf[0][0] = ScreenSpaceCenter; - constants.fogf[0][1] = (float)Renderer::EFBToScaledX((int)(2.0f * xfmem.viewport.wd)); - constants.fogf[0][2] = bpmem.fogRange.K[4].HI / 256.0f; - } - else - { - constants.fogf[0][0] = 0; - constants.fogf[0][1] = 1; - constants.fogf[0][2] = 1; - } - dirty = true; + if (s_bFogRangeAdjustChanged) + { + // set by two components, so keep changed flag here + // TODO: try to split both registers and move this logic to the shader + if (!g_ActiveConfig.bDisableFog && bpmem.fogRange.Base.Enabled == 1) + { + // bpmem.fogRange.Base.Center : center of the viewport in x axis. observation: + // bpmem.fogRange.Base.Center = realcenter + 342; + int center = ((u32)bpmem.fogRange.Base.Center) - 342; + // normalize center to make calculations easy + float ScreenSpaceCenter = center / (2.0f * xfmem.viewport.wd); + ScreenSpaceCenter = (ScreenSpaceCenter * 2.0f) - 1.0f; + // bpmem.fogRange.K seems to be a table of precalculated coefficients for the adjust factor + // observations: bpmem.fogRange.K[0].LO appears to be the lowest value and + // bpmem.fogRange.K[4].HI the largest + // they always seems to be larger than 256 so my theory is : + // they are the coefficients from the center to the border of the screen + // so to simplify I use the hi coefficient as K in the shader taking 256 as the scale + // TODO: Shouldn't this be EFBToScaledXf? + constants.fogf[0][0] = ScreenSpaceCenter; + constants.fogf[0][1] = (float)Renderer::EFBToScaledX((int)(2.0f * xfmem.viewport.wd)); + constants.fogf[0][2] = bpmem.fogRange.K[4].HI / 256.0f; + } + else + { + constants.fogf[0][0] = 0; + constants.fogf[0][1] = 1; + constants.fogf[0][2] = 1; + } + dirty = true; - s_bFogRangeAdjustChanged = false; - } + s_bFogRangeAdjustChanged = false; + } - if (s_bViewPortChanged) - { - constants.zbias[1][0] = (u32)xfmem.viewport.farZ; - constants.zbias[1][1] = (u32)xfmem.viewport.zRange; - dirty = true; - s_bViewPortChanged = false; - } + if (s_bViewPortChanged) + { + constants.zbias[1][0] = (u32)xfmem.viewport.farZ; + constants.zbias[1][1] = (u32)xfmem.viewport.zRange; + dirty = true; + s_bViewPortChanged = false; + } } void PixelShaderManager::SetTevColor(int index, int component, s32 value) { - auto& c = constants.colors[index]; - c[component] = value; - dirty = true; + auto& c = constants.colors[index]; + c[component] = value; + dirty = true; - PRIM_LOG("tev color%d: %d %d %d %d\n", index, c[0], c[1], c[2], c[3]); + PRIM_LOG("tev color%d: %d %d %d %d\n", index, c[0], c[1], c[2], c[3]); } void PixelShaderManager::SetTevKonstColor(int index, int component, s32 value) { - auto& c = constants.kcolors[index]; - c[component] = value; - dirty = true; + auto& c = constants.kcolors[index]; + c[component] = value; + dirty = true; - PRIM_LOG("tev konst color%d: %d %d %d %d\n", index, c[0], c[1], c[2], c[3]); + PRIM_LOG("tev konst color%d: %d %d %d %d\n", index, c[0], c[1], c[2], c[3]); } void PixelShaderManager::SetAlpha() { - constants.alpha[0] = bpmem.alpha_test.ref0; - constants.alpha[1] = bpmem.alpha_test.ref1; - dirty = true; + constants.alpha[0] = bpmem.alpha_test.ref0; + constants.alpha[1] = bpmem.alpha_test.ref1; + dirty = true; } void PixelShaderManager::SetDestAlpha() { - constants.alpha[3] = bpmem.dstalpha.alpha; - dirty = true; + constants.alpha[3] = bpmem.dstalpha.alpha; + dirty = true; } void PixelShaderManager::SetTexDims(int texmapid, u32 width, u32 height) { - float rwidth = 1.0f / (width * 128.0f); - float rheight = 1.0f / (height * 128.0f); + float rwidth = 1.0f / (width * 128.0f); + float rheight = 1.0f / (height * 128.0f); - // TODO: move this check out to callee. There we could just call this function on texture changes - // or better, use textureSize() in glsl - if (constants.texdims[texmapid][0] != rwidth || constants.texdims[texmapid][1] != rheight) - dirty = true; + // TODO: move this check out to callee. There we could just call this function on texture changes + // or better, use textureSize() in glsl + if (constants.texdims[texmapid][0] != rwidth || constants.texdims[texmapid][1] != rheight) + dirty = true; - constants.texdims[texmapid][0] = rwidth; - constants.texdims[texmapid][1] = rheight; + constants.texdims[texmapid][0] = rwidth; + constants.texdims[texmapid][1] = rheight; } void PixelShaderManager::SetZTextureBias() { - constants.zbias[1][3] = bpmem.ztex1.bias; - dirty = true; + constants.zbias[1][3] = bpmem.ztex1.bias; + dirty = true; } void PixelShaderManager::SetViewportChanged() { - s_bViewPortChanged = true; - s_bFogRangeAdjustChanged = true; // TODO: Shouldn't be necessary with an accurate fog range adjust implementation + s_bViewPortChanged = true; + s_bFogRangeAdjustChanged = + true; // TODO: Shouldn't be necessary with an accurate fog range adjust implementation } void PixelShaderManager::SetEfbScaleChanged() { - constants.efbscale[0] = 1.0f / Renderer::EFBToScaledXf(1); - constants.efbscale[1] = 1.0f / Renderer::EFBToScaledYf(1); - dirty = true; + constants.efbscale[0] = 1.0f / Renderer::EFBToScaledXf(1); + constants.efbscale[1] = 1.0f / Renderer::EFBToScaledYf(1); + dirty = true; } void PixelShaderManager::SetZSlope(float dfdx, float dfdy, float f0) { - constants.zslope[0] = dfdx; - constants.zslope[1] = dfdy; - constants.zslope[2] = f0; - dirty = true; + constants.zslope[0] = dfdx; + constants.zslope[1] = dfdy; + constants.zslope[2] = f0; + dirty = true; } void PixelShaderManager::SetIndTexScaleChanged(bool high) { - constants.indtexscale[high][0] = bpmem.texscale[high].ss0; - constants.indtexscale[high][1] = bpmem.texscale[high].ts0; - constants.indtexscale[high][2] = bpmem.texscale[high].ss1; - constants.indtexscale[high][3] = bpmem.texscale[high].ts1; - dirty = true; + constants.indtexscale[high][0] = bpmem.texscale[high].ss0; + constants.indtexscale[high][1] = bpmem.texscale[high].ts0; + constants.indtexscale[high][2] = bpmem.texscale[high].ss1; + constants.indtexscale[high][3] = bpmem.texscale[high].ts1; + dirty = true; } void PixelShaderManager::SetIndMatrixChanged(int matrixidx) { - int scale = ((u32)bpmem.indmtx[matrixidx].col0.s0 << 0) | - ((u32)bpmem.indmtx[matrixidx].col1.s1 << 2) | - ((u32)bpmem.indmtx[matrixidx].col2.s2 << 4); + int scale = ((u32)bpmem.indmtx[matrixidx].col0.s0 << 0) | + ((u32)bpmem.indmtx[matrixidx].col1.s1 << 2) | + ((u32)bpmem.indmtx[matrixidx].col2.s2 << 4); - // xyz - static matrix - // w - dynamic matrix scale / 128 - constants.indtexmtx[2*matrixidx ][0] = bpmem.indmtx[matrixidx].col0.ma; - constants.indtexmtx[2*matrixidx ][1] = bpmem.indmtx[matrixidx].col1.mc; - constants.indtexmtx[2*matrixidx ][2] = bpmem.indmtx[matrixidx].col2.me; - constants.indtexmtx[2*matrixidx ][3] = 17 - scale; - constants.indtexmtx[2*matrixidx+1][0] = bpmem.indmtx[matrixidx].col0.mb; - constants.indtexmtx[2*matrixidx+1][1] = bpmem.indmtx[matrixidx].col1.md; - constants.indtexmtx[2*matrixidx+1][2] = bpmem.indmtx[matrixidx].col2.mf; - constants.indtexmtx[2*matrixidx+1][3] = 17 - scale; - dirty = true; - - PRIM_LOG("indmtx%d: scale=%d, mat=(%d %d %d; %d %d %d)\n", - matrixidx, scale, - bpmem.indmtx[matrixidx].col0.ma, bpmem.indmtx[matrixidx].col1.mc, bpmem.indmtx[matrixidx].col2.me, - bpmem.indmtx[matrixidx].col0.mb, bpmem.indmtx[matrixidx].col1.md, bpmem.indmtx[matrixidx].col2.mf); + // xyz - static matrix + // w - dynamic matrix scale / 128 + constants.indtexmtx[2 * matrixidx][0] = bpmem.indmtx[matrixidx].col0.ma; + constants.indtexmtx[2 * matrixidx][1] = bpmem.indmtx[matrixidx].col1.mc; + constants.indtexmtx[2 * matrixidx][2] = bpmem.indmtx[matrixidx].col2.me; + constants.indtexmtx[2 * matrixidx][3] = 17 - scale; + constants.indtexmtx[2 * matrixidx + 1][0] = bpmem.indmtx[matrixidx].col0.mb; + constants.indtexmtx[2 * matrixidx + 1][1] = bpmem.indmtx[matrixidx].col1.md; + constants.indtexmtx[2 * matrixidx + 1][2] = bpmem.indmtx[matrixidx].col2.mf; + constants.indtexmtx[2 * matrixidx + 1][3] = 17 - scale; + dirty = true; + PRIM_LOG("indmtx%d: scale=%d, mat=(%d %d %d; %d %d %d)\n", matrixidx, scale, + bpmem.indmtx[matrixidx].col0.ma, bpmem.indmtx[matrixidx].col1.mc, + bpmem.indmtx[matrixidx].col2.me, bpmem.indmtx[matrixidx].col0.mb, + bpmem.indmtx[matrixidx].col1.md, bpmem.indmtx[matrixidx].col2.mf); } void PixelShaderManager::SetZTextureTypeChanged() { - switch (bpmem.ztex2.type) - { - case TEV_ZTEX_TYPE_U8: - constants.zbias[0][0] = 0; - constants.zbias[0][1] = 0; - constants.zbias[0][2] = 0; - constants.zbias[0][3] = 1; - break; - case TEV_ZTEX_TYPE_U16: - constants.zbias[0][0] = 1; - constants.zbias[0][1] = 0; - constants.zbias[0][2] = 0; - constants.zbias[0][3] = 256; - break; - case TEV_ZTEX_TYPE_U24: - constants.zbias[0][0] = 65536; - constants.zbias[0][1] = 256; - constants.zbias[0][2] = 1; - constants.zbias[0][3] = 0; - break; - default: - break; - } - dirty = true; + switch (bpmem.ztex2.type) + { + case TEV_ZTEX_TYPE_U8: + constants.zbias[0][0] = 0; + constants.zbias[0][1] = 0; + constants.zbias[0][2] = 0; + constants.zbias[0][3] = 1; + break; + case TEV_ZTEX_TYPE_U16: + constants.zbias[0][0] = 1; + constants.zbias[0][1] = 0; + constants.zbias[0][2] = 0; + constants.zbias[0][3] = 256; + break; + case TEV_ZTEX_TYPE_U24: + constants.zbias[0][0] = 65536; + constants.zbias[0][1] = 256; + constants.zbias[0][2] = 1; + constants.zbias[0][3] = 0; + break; + default: + break; + } + dirty = true; } void PixelShaderManager::SetTexCoordChanged(u8 texmapid) { - TCoordInfo& tc = bpmem.texcoords[texmapid]; - constants.texdims[texmapid][2] = (float)(tc.s.scale_minus_1 + 1) * 128.0f; - constants.texdims[texmapid][3] = (float)(tc.t.scale_minus_1 + 1) * 128.0f; - dirty = true; + TCoordInfo& tc = bpmem.texcoords[texmapid]; + constants.texdims[texmapid][2] = (float)(tc.s.scale_minus_1 + 1) * 128.0f; + constants.texdims[texmapid][3] = (float)(tc.t.scale_minus_1 + 1) * 128.0f; + dirty = true; } void PixelShaderManager::SetFogColorChanged() { - if (g_ActiveConfig.bDisableFog) - return; + if (g_ActiveConfig.bDisableFog) + return; - constants.fogcolor[0] = bpmem.fog.color.r; - constants.fogcolor[1] = bpmem.fog.color.g; - constants.fogcolor[2] = bpmem.fog.color.b; - dirty = true; + constants.fogcolor[0] = bpmem.fog.color.r; + constants.fogcolor[1] = bpmem.fog.color.g; + constants.fogcolor[2] = bpmem.fog.color.b; + dirty = true; } void PixelShaderManager::SetFogParamChanged() { - if (!g_ActiveConfig.bDisableFog) - { - constants.fogf[1][0] = bpmem.fog.a.GetA(); - constants.fogi[1] = bpmem.fog.b_magnitude; - constants.fogf[1][2] = bpmem.fog.c_proj_fsel.GetC(); - constants.fogi[3] = bpmem.fog.b_shift; - } - else - { - constants.fogf[1][0] = 0.f; - constants.fogi[1] = 1; - constants.fogf[1][2] = 0.f; - constants.fogi[3] = 1; - } - dirty = true; + if (!g_ActiveConfig.bDisableFog) + { + constants.fogf[1][0] = bpmem.fog.a.GetA(); + constants.fogi[1] = bpmem.fog.b_magnitude; + constants.fogf[1][2] = bpmem.fog.c_proj_fsel.GetC(); + constants.fogi[3] = bpmem.fog.b_shift; + } + else + { + constants.fogf[1][0] = 0.f; + constants.fogi[1] = 1; + constants.fogf[1][2] = 0.f; + constants.fogi[3] = 1; + } + dirty = true; } void PixelShaderManager::SetFogRangeAdjustChanged() { - if (g_ActiveConfig.bDisableFog) - return; + if (g_ActiveConfig.bDisableFog) + return; - s_bFogRangeAdjustChanged = true; + s_bFogRangeAdjustChanged = true; } -void PixelShaderManager::DoState(PointerWrap &p) +void PixelShaderManager::DoState(PointerWrap& p) { - p.Do(s_bFogRangeAdjustChanged); - p.Do(s_bViewPortChanged); + p.Do(s_bFogRangeAdjustChanged); + p.Do(s_bViewPortChanged); - p.Do(constants); + p.Do(constants); - if (p.GetMode() == PointerWrap::MODE_READ) - { - // Fixup the current state from global GPU state - // NOTE: This requires that all GPU memory has been loaded already. - Dirty(); - } + if (p.GetMode() == PointerWrap::MODE_READ) + { + // Fixup the current state from global GPU state + // NOTE: This requires that all GPU memory has been loaded already. + Dirty(); + } } diff --git a/Source/Core/VideoCommon/PixelShaderManager.h b/Source/Core/VideoCommon/PixelShaderManager.h index 5780c4533b..32493a6eec 100644 --- a/Source/Core/VideoCommon/PixelShaderManager.h +++ b/Source/Core/VideoCommon/PixelShaderManager.h @@ -13,36 +13,36 @@ class PointerWrap; class PixelShaderManager { public: - static void Init(); - static void Dirty(); - static void Shutdown(); - static void DoState(PointerWrap &p); + static void Init(); + static void Dirty(); + static void Shutdown(); + static void DoState(PointerWrap& p); - static void SetConstants(); // sets pixel shader constants + static void SetConstants(); // sets pixel shader constants - // constant management - // Some of these functions grab the constant values from global state, - // so make sure to call them after memory is committed - static void SetTevColor(int index, int component, s32 value); - static void SetTevKonstColor(int index, int component, s32 value); - static void SetAlpha(); - static void SetDestAlpha(); - static void SetTexDims(int texmapid, u32 width, u32 height); - static void SetZTextureBias(); - static void SetViewportChanged(); - static void SetEfbScaleChanged(); - static void SetZSlope(float dfdx, float dfdy, float f0); - static void SetIndMatrixChanged(int matrixidx); - static void SetZTextureTypeChanged(); - static void SetIndTexScaleChanged(bool high); - static void SetTexCoordChanged(u8 texmapid); - static void SetFogColorChanged(); - static void SetFogParamChanged(); - static void SetFogRangeAdjustChanged(); + // constant management + // Some of these functions grab the constant values from global state, + // so make sure to call them after memory is committed + static void SetTevColor(int index, int component, s32 value); + static void SetTevKonstColor(int index, int component, s32 value); + static void SetAlpha(); + static void SetDestAlpha(); + static void SetTexDims(int texmapid, u32 width, u32 height); + static void SetZTextureBias(); + static void SetViewportChanged(); + static void SetEfbScaleChanged(); + static void SetZSlope(float dfdx, float dfdy, float f0); + static void SetIndMatrixChanged(int matrixidx); + static void SetZTextureTypeChanged(); + static void SetIndTexScaleChanged(bool high); + static void SetTexCoordChanged(u8 texmapid); + static void SetFogColorChanged(); + static void SetFogParamChanged(); + static void SetFogRangeAdjustChanged(); - static PixelShaderConstants constants; - static bool dirty; + static PixelShaderConstants constants; + static bool dirty; - static bool s_bFogRangeAdjustChanged; - static bool s_bViewPortChanged; + static bool s_bFogRangeAdjustChanged; + static bool s_bViewPortChanged; }; diff --git a/Source/Core/VideoCommon/PostProcessing.cpp b/Source/Core/VideoCommon/PostProcessing.cpp index 1862bcde34..023b6ef8bc 100644 --- a/Source/Core/VideoCommon/PostProcessing.cpp +++ b/Source/Core/VideoCommon/PostProcessing.cpp @@ -9,316 +9,316 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/IniFile.h" -#include "Common/StringUtil.h" #include "Common/Logging/Log.h" +#include "Common/StringUtil.h" #include "VideoCommon/PostProcessing.h" #include "VideoCommon/VideoConfig.h" - static const char s_default_shader[] = "void main() { SetOutput(Sample()); }\n"; PostProcessingShaderImplementation::PostProcessingShaderImplementation() { - m_timer.Start(); + m_timer.Start(); } PostProcessingShaderImplementation::~PostProcessingShaderImplementation() { - m_timer.Stop(); + m_timer.Stop(); } std::string PostProcessingShaderConfiguration::LoadShader(std::string shader) { - // Load the shader from the configuration if there isn't one sent to us. - if (shader == "") - shader = g_ActiveConfig.sPostProcessingShader; - m_current_shader = shader; + // Load the shader from the configuration if there isn't one sent to us. + if (shader == "") + shader = g_ActiveConfig.sPostProcessingShader; + m_current_shader = shader; - const std::string sub_dir = (g_Config.iStereoMode == STEREO_ANAGLYPH) ? ANAGLYPH_DIR DIR_SEP : ""; + const std::string sub_dir = (g_Config.iStereoMode == STEREO_ANAGLYPH) ? ANAGLYPH_DIR DIR_SEP : ""; - // loading shader code - std::string code; - std::string path = File::GetUserPath(D_SHADERS_IDX) + sub_dir + shader + ".glsl"; + // loading shader code + std::string code; + std::string path = File::GetUserPath(D_SHADERS_IDX) + sub_dir + shader + ".glsl"; - if (shader == "") - { - code = s_default_shader; - } - else - { - if (!File::Exists(path)) - { - // Fallback to shared user dir - path = File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir + shader + ".glsl"; - } + if (shader == "") + { + code = s_default_shader; + } + else + { + if (!File::Exists(path)) + { + // Fallback to shared user dir + path = File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir + shader + ".glsl"; + } - if (!File::ReadFileToString(path, code)) - { - ERROR_LOG(VIDEO, "Post-processing shader not found: %s", path.c_str()); - code = s_default_shader; - } - } + if (!File::ReadFileToString(path, code)) + { + ERROR_LOG(VIDEO, "Post-processing shader not found: %s", path.c_str()); + code = s_default_shader; + } + } - LoadOptions(code); - LoadOptionsConfiguration(); + LoadOptions(code); + LoadOptionsConfiguration(); - return code; + return code; } void PostProcessingShaderConfiguration::LoadOptions(const std::string& code) { - const std::string config_start_delimiter = "[configuration]"; - const std::string config_end_delimiter = "[/configuration]"; - size_t configuration_start = code.find(config_start_delimiter); - size_t configuration_end = code.find(config_end_delimiter); + const std::string config_start_delimiter = "[configuration]"; + const std::string config_end_delimiter = "[/configuration]"; + size_t configuration_start = code.find(config_start_delimiter); + size_t configuration_end = code.find(config_end_delimiter); - m_options.clear(); - m_any_options_dirty = true; + m_options.clear(); + m_any_options_dirty = true; - if (configuration_start == std::string::npos || - configuration_end == std::string::npos) - { - // Issue loading configuration or there isn't one. - return; - } + if (configuration_start == std::string::npos || configuration_end == std::string::npos) + { + // Issue loading configuration or there isn't one. + return; + } - std::string configuration_string = code.substr(configuration_start + config_start_delimiter.size(), - configuration_end - configuration_start - config_start_delimiter.size()); + std::string configuration_string = + code.substr(configuration_start + config_start_delimiter.size(), + configuration_end - configuration_start - config_start_delimiter.size()); - std::istringstream in(configuration_string); + std::istringstream in(configuration_string); - struct GLSLStringOption - { - std::string m_type; - std::vector> m_options; - }; + struct GLSLStringOption + { + std::string m_type; + std::vector> m_options; + }; - std::vector option_strings; - GLSLStringOption* current_strings = nullptr; - while (!in.eof()) - { - std::string line; + std::vector option_strings; + GLSLStringOption* current_strings = nullptr; + while (!in.eof()) + { + std::string line; - if (std::getline(in, line)) - { + if (std::getline(in, line)) + { #ifndef _WIN32 - // Check for CRLF eol and convert it to LF - if (!line.empty() && line.at(line.size()-1) == '\r') - { - line.erase(line.size()-1); - } + // Check for CRLF eol and convert it to LF + if (!line.empty() && line.at(line.size() - 1) == '\r') + { + line.erase(line.size() - 1); + } #endif - if (line.size() > 0) - { - if (line[0] == '[') - { - size_t endpos = line.find("]"); + if (line.size() > 0) + { + if (line[0] == '[') + { + size_t endpos = line.find("]"); - if (endpos != std::string::npos) - { - // New section! - std::string sub = line.substr(1, endpos - 1); - option_strings.push_back({ sub }); - current_strings = &option_strings.back(); - } - } - else - { - if (current_strings) - { - std::string key, value; - IniFile::ParseLine(line, &key, &value); + if (endpos != std::string::npos) + { + // New section! + std::string sub = line.substr(1, endpos - 1); + option_strings.push_back({sub}); + current_strings = &option_strings.back(); + } + } + else + { + if (current_strings) + { + std::string key, value; + IniFile::ParseLine(line, &key, &value); - if (!(key == "" && value == "")) - current_strings->m_options.emplace_back(key, value); - } - } - } - } - } + if (!(key == "" && value == "")) + current_strings->m_options.emplace_back(key, value); + } + } + } + } + } - for (const auto& it : option_strings) - { - ConfigurationOption option; - option.m_dirty = true; + for (const auto& it : option_strings) + { + ConfigurationOption option; + option.m_dirty = true; - if (it.m_type == "OptionBool") - option.m_type = ConfigurationOption::OptionType::OPTION_BOOL; - else if (it.m_type == "OptionRangeFloat") - option.m_type = ConfigurationOption::OptionType::OPTION_FLOAT; - else if (it.m_type == "OptionRangeInteger") - option.m_type = ConfigurationOption::OptionType::OPTION_INTEGER; + if (it.m_type == "OptionBool") + option.m_type = ConfigurationOption::OptionType::OPTION_BOOL; + else if (it.m_type == "OptionRangeFloat") + option.m_type = ConfigurationOption::OptionType::OPTION_FLOAT; + else if (it.m_type == "OptionRangeInteger") + option.m_type = ConfigurationOption::OptionType::OPTION_INTEGER; - for (const auto& string_option : it.m_options) - { - if (string_option.first == "GUIName") - { - option.m_gui_name = string_option.second; - } - else if (string_option.first == "OptionName") - { - option.m_option_name = string_option.second; - } - else if (string_option.first == "DependentOption") - { - option.m_dependent_option = string_option.second; - } - else if (string_option.first == "MinValue" || - string_option.first == "MaxValue" || - string_option.first == "DefaultValue" || - string_option.first == "StepAmount") - { - std::vector* output_integer = nullptr; - std::vector* output_float = nullptr; + for (const auto& string_option : it.m_options) + { + if (string_option.first == "GUIName") + { + option.m_gui_name = string_option.second; + } + else if (string_option.first == "OptionName") + { + option.m_option_name = string_option.second; + } + else if (string_option.first == "DependentOption") + { + option.m_dependent_option = string_option.second; + } + else if (string_option.first == "MinValue" || string_option.first == "MaxValue" || + string_option.first == "DefaultValue" || string_option.first == "StepAmount") + { + std::vector* output_integer = nullptr; + std::vector* output_float = nullptr; - if (string_option.first == "MinValue") - { - output_integer = &option.m_integer_min_values; - output_float = &option.m_float_min_values; - } - else if (string_option.first == "MaxValue") - { - output_integer = &option.m_integer_max_values; - output_float = &option.m_float_max_values; - } - else if (string_option.first == "DefaultValue") - { - output_integer = &option.m_integer_values; - output_float = &option.m_float_values; - } - else if (string_option.first == "StepAmount") - { - output_integer = &option.m_integer_step_values; - output_float = &option.m_float_step_values; - } + if (string_option.first == "MinValue") + { + output_integer = &option.m_integer_min_values; + output_float = &option.m_float_min_values; + } + else if (string_option.first == "MaxValue") + { + output_integer = &option.m_integer_max_values; + output_float = &option.m_float_max_values; + } + else if (string_option.first == "DefaultValue") + { + output_integer = &option.m_integer_values; + output_float = &option.m_float_values; + } + else if (string_option.first == "StepAmount") + { + output_integer = &option.m_integer_step_values; + output_float = &option.m_float_step_values; + } - if (option.m_type == ConfigurationOption::OptionType::OPTION_BOOL) - { - TryParse(string_option.second, &option.m_bool_value); - } - else if (option.m_type == ConfigurationOption::OptionType::OPTION_INTEGER) - { - TryParseVector(string_option.second, output_integer); - if (output_integer->size() > 4) - output_integer->erase(output_integer->begin() + 4, output_integer->end()); - } - else if (option.m_type == ConfigurationOption::OptionType::OPTION_FLOAT) - { - TryParseVector(string_option.second, output_float); - if (output_float->size() > 4) - output_float->erase(output_float->begin() + 4, output_float->end()); - } - } - } - m_options[option.m_option_name] = option; - } + if (option.m_type == ConfigurationOption::OptionType::OPTION_BOOL) + { + TryParse(string_option.second, &option.m_bool_value); + } + else if (option.m_type == ConfigurationOption::OptionType::OPTION_INTEGER) + { + TryParseVector(string_option.second, output_integer); + if (output_integer->size() > 4) + output_integer->erase(output_integer->begin() + 4, output_integer->end()); + } + else if (option.m_type == ConfigurationOption::OptionType::OPTION_FLOAT) + { + TryParseVector(string_option.second, output_float); + if (output_float->size() > 4) + output_float->erase(output_float->begin() + 4, output_float->end()); + } + } + } + m_options[option.m_option_name] = option; + } } void PostProcessingShaderConfiguration::LoadOptionsConfiguration() { - IniFile ini; - ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); - std::string section = m_current_shader + "-options"; + IniFile ini; + ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); + std::string section = m_current_shader + "-options"; - for (auto& it : m_options) - { - switch (it.second.m_type) - { - case ConfigurationOption::OptionType::OPTION_BOOL: - ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &it.second.m_bool_value, it.second.m_bool_value); - break; - case ConfigurationOption::OptionType::OPTION_INTEGER: - { - std::string value; - ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &value); - if (value != "") - TryParseVector(value, &it.second.m_integer_values); - } - break; - case ConfigurationOption::OptionType::OPTION_FLOAT: - { - std::string value; - ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &value); - if (value != "") - TryParseVector(value, &it.second.m_float_values); - } - break; - } - } + for (auto& it : m_options) + { + switch (it.second.m_type) + { + case ConfigurationOption::OptionType::OPTION_BOOL: + ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &it.second.m_bool_value, + it.second.m_bool_value); + break; + case ConfigurationOption::OptionType::OPTION_INTEGER: + { + std::string value; + ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &value); + if (value != "") + TryParseVector(value, &it.second.m_integer_values); + } + break; + case ConfigurationOption::OptionType::OPTION_FLOAT: + { + std::string value; + ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &value); + if (value != "") + TryParseVector(value, &it.second.m_float_values); + } + break; + } + } } void PostProcessingShaderConfiguration::SaveOptionsConfiguration() { - IniFile ini; - ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); - std::string section = m_current_shader + "-options"; + IniFile ini; + ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); + std::string section = m_current_shader + "-options"; - for (auto& it : m_options) - { - switch (it.second.m_type) - { - case ConfigurationOption::OptionType::OPTION_BOOL: - { - ini.GetOrCreateSection(section)->Set(it.second.m_option_name, it.second.m_bool_value); - } - break; - case ConfigurationOption::OptionType::OPTION_INTEGER: - { - std::string value = ""; - for (size_t i = 0; i < it.second.m_integer_values.size(); ++i) - value += StringFromFormat("%d%s", it.second.m_integer_values[i], i == (it.second.m_integer_values.size() - 1) ? "": ", "); - ini.GetOrCreateSection(section)->Set(it.second.m_option_name, value); - } - break; - case ConfigurationOption::OptionType::OPTION_FLOAT: - { - std::ostringstream value; - value.imbue(std::locale("C")); + for (auto& it : m_options) + { + switch (it.second.m_type) + { + case ConfigurationOption::OptionType::OPTION_BOOL: + { + ini.GetOrCreateSection(section)->Set(it.second.m_option_name, it.second.m_bool_value); + } + break; + case ConfigurationOption::OptionType::OPTION_INTEGER: + { + std::string value = ""; + for (size_t i = 0; i < it.second.m_integer_values.size(); ++i) + value += StringFromFormat("%d%s", it.second.m_integer_values[i], + i == (it.second.m_integer_values.size() - 1) ? "" : ", "); + ini.GetOrCreateSection(section)->Set(it.second.m_option_name, value); + } + break; + case ConfigurationOption::OptionType::OPTION_FLOAT: + { + std::ostringstream value; + value.imbue(std::locale("C")); - for (size_t i = 0; i < it.second.m_float_values.size(); ++i) - { - value << it.second.m_float_values[i]; - if (i != (it.second.m_float_values.size() - 1)) - value << ", "; - } - ini.GetOrCreateSection(section)->Set(it.second.m_option_name, value.str()); - } - break; - } - } - ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX)); + for (size_t i = 0; i < it.second.m_float_values.size(); ++i) + { + value << it.second.m_float_values[i]; + if (i != (it.second.m_float_values.size() - 1)) + value << ", "; + } + ini.GetOrCreateSection(section)->Set(it.second.m_option_name, value.str()); + } + break; + } + } + ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX)); } void PostProcessingShaderConfiguration::ReloadShader() { - m_current_shader = ""; + m_current_shader = ""; } -void PostProcessingShaderConfiguration::SetOptionf(const std::string& option, int index, float value) +void PostProcessingShaderConfiguration::SetOptionf(const std::string& option, int index, + float value) { - auto it = m_options.find(option); + auto it = m_options.find(option); - it->second.m_float_values[index] = value; - it->second.m_dirty = true; - m_any_options_dirty = true; + it->second.m_float_values[index] = value; + it->second.m_dirty = true; + m_any_options_dirty = true; } void PostProcessingShaderConfiguration::SetOptioni(const std::string& option, int index, s32 value) { - auto it = m_options.find(option); + auto it = m_options.find(option); - it->second.m_integer_values[index] = value; - it->second.m_dirty = true; - m_any_options_dirty = true; + it->second.m_integer_values[index] = value; + it->second.m_dirty = true; + m_any_options_dirty = true; } void PostProcessingShaderConfiguration::SetOptionb(const std::string& option, bool value) { - auto it = m_options.find(option); + auto it = m_options.find(option); - it->second.m_bool_value = value; - it->second.m_dirty = true; - m_any_options_dirty = true; + it->second.m_bool_value = value; + it->second.m_dirty = true; + m_any_options_dirty = true; } diff --git a/Source/Core/VideoCommon/PostProcessing.h b/Source/Core/VideoCommon/PostProcessing.h index 681980925b..74628c3e54 100644 --- a/Source/Core/VideoCommon/PostProcessing.h +++ b/Source/Core/VideoCommon/PostProcessing.h @@ -15,87 +15,82 @@ class PostProcessingShaderConfiguration { public: - struct ConfigurationOption - { - enum OptionType - { - OPTION_BOOL = 0, - OPTION_FLOAT, - OPTION_INTEGER, - }; + struct ConfigurationOption + { + enum OptionType + { + OPTION_BOOL = 0, + OPTION_FLOAT, + OPTION_INTEGER, + }; - bool m_bool_value; + bool m_bool_value; - std::vector m_float_values; - std::vector m_integer_values; + std::vector m_float_values; + std::vector m_integer_values; - std::vector m_float_min_values; - std::vector m_integer_min_values; + std::vector m_float_min_values; + std::vector m_integer_min_values; - std::vector m_float_max_values; - std::vector m_integer_max_values; + std::vector m_float_max_values; + std::vector m_integer_max_values; - std::vector m_float_step_values; - std::vector m_integer_step_values; + std::vector m_float_step_values; + std::vector m_integer_step_values; - OptionType m_type; + OptionType m_type; - std::string m_gui_name; - std::string m_option_name; - std::string m_dependent_option; - bool m_dirty; - }; + std::string m_gui_name; + std::string m_option_name; + std::string m_dependent_option; + bool m_dirty; + }; - typedef std::map ConfigMap; + typedef std::map ConfigMap; - PostProcessingShaderConfiguration() : m_current_shader("") {} - virtual ~PostProcessingShaderConfiguration() {} - - // Loads the configuration with a shader - // If the argument is "" the class will load the shader from the g_activeConfig option. - // Returns the loaded shader source from file - std::string LoadShader(std::string shader = ""); - void SaveOptionsConfiguration(); - void ReloadShader(); - std::string GetShader() { return m_current_shader; } - - bool IsDirty() { return m_any_options_dirty; } - void SetDirty(bool dirty) { m_any_options_dirty = dirty; } - - bool HasOptions() { return m_options.size() > 0; } - ConfigMap& GetOptions() { return m_options; } - const ConfigurationOption& GetOption(const std::string& option) { return m_options[option]; } - - // For updating option's values - void SetOptionf(const std::string& option, int index, float value); - void SetOptioni(const std::string& option, int index, s32 value); - void SetOptionb(const std::string& option, bool value); + PostProcessingShaderConfiguration() : m_current_shader("") {} + virtual ~PostProcessingShaderConfiguration() {} + // Loads the configuration with a shader + // If the argument is "" the class will load the shader from the g_activeConfig option. + // Returns the loaded shader source from file + std::string LoadShader(std::string shader = ""); + void SaveOptionsConfiguration(); + void ReloadShader(); + std::string GetShader() { return m_current_shader; } + bool IsDirty() { return m_any_options_dirty; } + void SetDirty(bool dirty) { m_any_options_dirty = dirty; } + bool HasOptions() { return m_options.size() > 0; } + ConfigMap& GetOptions() { return m_options; } + const ConfigurationOption& GetOption(const std::string& option) { return m_options[option]; } + // For updating option's values + void SetOptionf(const std::string& option, int index, float value); + void SetOptioni(const std::string& option, int index, s32 value); + void SetOptionb(const std::string& option, bool value); private: - bool m_any_options_dirty; - std::string m_current_shader; - ConfigMap m_options; + bool m_any_options_dirty; + std::string m_current_shader; + ConfigMap m_options; - void LoadOptions(const std::string& code); - void LoadOptionsConfiguration(); + void LoadOptions(const std::string& code); + void LoadOptionsConfiguration(); }; class PostProcessingShaderImplementation { public: - PostProcessingShaderImplementation(); - virtual ~PostProcessingShaderImplementation(); + PostProcessingShaderImplementation(); + virtual ~PostProcessingShaderImplementation(); - PostProcessingShaderConfiguration* GetConfig() { return &m_config; } - - // Should be implemented by the backends for backend specific code - virtual void BlitFromTexture(TargetRectangle src, TargetRectangle dst, - int src_texture, int src_width, int src_height, int layer = 0) = 0; - virtual void ApplyShader() = 0; + PostProcessingShaderConfiguration* GetConfig() { return &m_config; } + // Should be implemented by the backends for backend specific code + virtual void BlitFromTexture(TargetRectangle src, TargetRectangle dst, int src_texture, + int src_width, int src_height, int layer = 0) = 0; + virtual void ApplyShader() = 0; protected: - // Timer for determining our time value - Common::Timer m_timer; + // Timer for determining our time value + Common::Timer m_timer; - PostProcessingShaderConfiguration m_config; + PostProcessingShaderConfiguration m_config; }; diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index bd187b855f..3492c48ab1 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -27,15 +27,15 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/Host.h" -#include "Core/Movie.h" #include "Core/FifoPlayer/FifoRecorder.h" #include "Core/HW/VideoInterface.h" +#include "Core/Host.h" +#include "Core/Movie.h" #include "VideoCommon/AVIDump.h" #include "VideoCommon/BPMemory.h" -#include "VideoCommon/CommandProcessor.h" #include "VideoCommon/CPMemory.h" +#include "VideoCommon/CommandProcessor.h" #include "VideoCommon/Debugger.h" #include "VideoCommon/FPSCounter.h" #include "VideoCommon/FramebufferManagerBase.h" @@ -61,7 +61,7 @@ Common::Event Renderer::s_screenshotCompleted; volatile bool Renderer::s_bScreenshot; // Final surface changing -Common::Flag Renderer::s_SurfaceNeedsChanged; +Common::Flag Renderer::s_SurfaceNeedsChanged; Common::Event Renderer::s_ChangedSurface; // The framebuffer size @@ -86,541 +86,554 @@ unsigned int Renderer::efb_scale_numeratorY = 1; unsigned int Renderer::efb_scale_denominatorX = 1; unsigned int Renderer::efb_scale_denominatorY = 1; -static float AspectToWidescreen(float aspect) { return aspect * ((16.0f / 9.0f) / (4.0f / 3.0f)); } - -Renderer::Renderer() - : frame_data() - , bLastFrameDumped(false) +static float AspectToWidescreen(float aspect) { - UpdateActiveConfig(); - TextureCacheBase::OnConfigChanged(g_ActiveConfig); + return aspect * ((16.0f / 9.0f) / (4.0f / 3.0f)); +} + +Renderer::Renderer() : frame_data(), bLastFrameDumped(false) +{ + UpdateActiveConfig(); + TextureCacheBase::OnConfigChanged(g_ActiveConfig); #if defined _WIN32 || defined HAVE_LIBAV - bAVIDumping = false; + bAVIDumping = false; #endif - OSDChoice = 0; - OSDTime = 0; + OSDChoice = 0; + OSDTime = 0; } Renderer::~Renderer() { - // invalidate previous efb format - prev_efb_format = PEControl::INVALID_FMT; + // invalidate previous efb format + prev_efb_format = PEControl::INVALID_FMT; - efb_scale_numeratorX = efb_scale_numeratorY = efb_scale_denominatorX = efb_scale_denominatorY = 1; + efb_scale_numeratorX = efb_scale_numeratorY = efb_scale_denominatorX = efb_scale_denominatorY = 1; #if defined _WIN32 || defined HAVE_LIBAV - if (SConfig::GetInstance().m_DumpFrames && bLastFrameDumped && bAVIDumping) - AVIDump::Stop(); + if (SConfig::GetInstance().m_DumpFrames && bLastFrameDumped && bAVIDumping) + AVIDump::Stop(); #endif } -void Renderer::RenderToXFB(u32 xfbAddr, const EFBRectangle& sourceRc, u32 fbStride, u32 fbHeight, float Gamma) +void Renderer::RenderToXFB(u32 xfbAddr, const EFBRectangle& sourceRc, u32 fbStride, u32 fbHeight, + float Gamma) { - CheckFifoRecording(); + CheckFifoRecording(); - if (!fbStride || !fbHeight) - return; + if (!fbStride || !fbHeight) + return; - XFBWrited = true; + XFBWrited = true; - if (g_ActiveConfig.bUseXFB) - { - FramebufferManagerBase::CopyToXFB(xfbAddr, fbStride, fbHeight, sourceRc, Gamma); - } - else - { - // below div two to convert from bytes to pixels - it expects width, not stride - Swap(xfbAddr, fbStride/2, fbStride/2, fbHeight, sourceRc, Gamma); - } + if (g_ActiveConfig.bUseXFB) + { + FramebufferManagerBase::CopyToXFB(xfbAddr, fbStride, fbHeight, sourceRc, Gamma); + } + else + { + // below div two to convert from bytes to pixels - it expects width, not stride + Swap(xfbAddr, fbStride / 2, fbStride / 2, fbHeight, sourceRc, Gamma); + } } int Renderer::EFBToScaledX(int x) { - switch (g_ActiveConfig.iEFBScale) - { - case SCALE_AUTO: // fractional - return FramebufferManagerBase::ScaleToVirtualXfbWidth(x); + switch (g_ActiveConfig.iEFBScale) + { + case SCALE_AUTO: // fractional + return FramebufferManagerBase::ScaleToVirtualXfbWidth(x); - default: - return x * (int)efb_scale_numeratorX / (int)efb_scale_denominatorX; - }; + default: + return x * (int)efb_scale_numeratorX / (int)efb_scale_denominatorX; + }; } int Renderer::EFBToScaledY(int y) { - switch (g_ActiveConfig.iEFBScale) - { - case SCALE_AUTO: // fractional - return FramebufferManagerBase::ScaleToVirtualXfbHeight(y); + switch (g_ActiveConfig.iEFBScale) + { + case SCALE_AUTO: // fractional + return FramebufferManagerBase::ScaleToVirtualXfbHeight(y); - default: - return y * (int)efb_scale_numeratorY / (int)efb_scale_denominatorY; - }; + default: + return y * (int)efb_scale_numeratorY / (int)efb_scale_denominatorY; + }; } void Renderer::CalculateTargetScale(int x, int y, int* scaledX, int* scaledY) { - if (g_ActiveConfig.iEFBScale == SCALE_AUTO || g_ActiveConfig.iEFBScale == SCALE_AUTO_INTEGRAL) - { - *scaledX = x; - *scaledY = y; - } - else - { - *scaledX = x * (int)efb_scale_numeratorX / (int)efb_scale_denominatorX; - *scaledY = y * (int)efb_scale_numeratorY / (int)efb_scale_denominatorY; - } + if (g_ActiveConfig.iEFBScale == SCALE_AUTO || g_ActiveConfig.iEFBScale == SCALE_AUTO_INTEGRAL) + { + *scaledX = x; + *scaledY = y; + } + else + { + *scaledX = x * (int)efb_scale_numeratorX / (int)efb_scale_denominatorX; + *scaledY = y * (int)efb_scale_numeratorY / (int)efb_scale_denominatorY; + } } // return true if target size changed bool Renderer::CalculateTargetSize(unsigned int framebuffer_width, unsigned int framebuffer_height) { - int newEFBWidth, newEFBHeight; - newEFBWidth = newEFBHeight = 0; + int newEFBWidth, newEFBHeight; + newEFBWidth = newEFBHeight = 0; - // TODO: Ugly. Clean up - switch (s_last_efb_scale) - { - case SCALE_AUTO: - case SCALE_AUTO_INTEGRAL: - newEFBWidth = FramebufferManagerBase::ScaleToVirtualXfbWidth(EFB_WIDTH); - newEFBHeight = FramebufferManagerBase::ScaleToVirtualXfbHeight(EFB_HEIGHT); + // TODO: Ugly. Clean up + switch (s_last_efb_scale) + { + case SCALE_AUTO: + case SCALE_AUTO_INTEGRAL: + newEFBWidth = FramebufferManagerBase::ScaleToVirtualXfbWidth(EFB_WIDTH); + newEFBHeight = FramebufferManagerBase::ScaleToVirtualXfbHeight(EFB_HEIGHT); - if (s_last_efb_scale == SCALE_AUTO_INTEGRAL) - { - efb_scale_numeratorX = efb_scale_numeratorY = std::max((newEFBWidth - 1) / EFB_WIDTH + 1, (newEFBHeight - 1) / EFB_HEIGHT + 1); - efb_scale_denominatorX = efb_scale_denominatorY = 1; - newEFBWidth = EFBToScaledX(EFB_WIDTH); - newEFBHeight = EFBToScaledY(EFB_HEIGHT); - } - else - { - efb_scale_numeratorX = newEFBWidth; - efb_scale_denominatorX = EFB_WIDTH; - efb_scale_numeratorY = newEFBHeight; - efb_scale_denominatorY = EFB_HEIGHT; - } - break; + if (s_last_efb_scale == SCALE_AUTO_INTEGRAL) + { + efb_scale_numeratorX = efb_scale_numeratorY = + std::max((newEFBWidth - 1) / EFB_WIDTH + 1, (newEFBHeight - 1) / EFB_HEIGHT + 1); + efb_scale_denominatorX = efb_scale_denominatorY = 1; + newEFBWidth = EFBToScaledX(EFB_WIDTH); + newEFBHeight = EFBToScaledY(EFB_HEIGHT); + } + else + { + efb_scale_numeratorX = newEFBWidth; + efb_scale_denominatorX = EFB_WIDTH; + efb_scale_numeratorY = newEFBHeight; + efb_scale_denominatorY = EFB_HEIGHT; + } + break; - case SCALE_1X: - efb_scale_numeratorX = efb_scale_numeratorY = 1; - efb_scale_denominatorX = efb_scale_denominatorY = 1; - break; + case SCALE_1X: + efb_scale_numeratorX = efb_scale_numeratorY = 1; + efb_scale_denominatorX = efb_scale_denominatorY = 1; + break; - case SCALE_1_5X: - efb_scale_numeratorX = efb_scale_numeratorY = 3; - efb_scale_denominatorX = efb_scale_denominatorY = 2; - break; + case SCALE_1_5X: + efb_scale_numeratorX = efb_scale_numeratorY = 3; + efb_scale_denominatorX = efb_scale_denominatorY = 2; + break; - case SCALE_2X: - efb_scale_numeratorX = efb_scale_numeratorY = 2; - efb_scale_denominatorX = efb_scale_denominatorY = 1; - break; + case SCALE_2X: + efb_scale_numeratorX = efb_scale_numeratorY = 2; + efb_scale_denominatorX = efb_scale_denominatorY = 1; + break; - case SCALE_2_5X: - efb_scale_numeratorX = efb_scale_numeratorY = 5; - efb_scale_denominatorX = efb_scale_denominatorY = 2; - break; + case SCALE_2_5X: + efb_scale_numeratorX = efb_scale_numeratorY = 5; + efb_scale_denominatorX = efb_scale_denominatorY = 2; + break; - default: - efb_scale_numeratorX = efb_scale_numeratorY = s_last_efb_scale - 3; - efb_scale_denominatorX = efb_scale_denominatorY = 1; + default: + efb_scale_numeratorX = efb_scale_numeratorY = s_last_efb_scale - 3; + efb_scale_denominatorX = efb_scale_denominatorY = 1; + int maxSize; + maxSize = GetMaxTextureSize(); + if ((unsigned)maxSize < EFB_WIDTH * efb_scale_numeratorX / efb_scale_denominatorX) + { + efb_scale_numeratorX = efb_scale_numeratorY = (maxSize / EFB_WIDTH); + efb_scale_denominatorX = efb_scale_denominatorY = 1; + } - int maxSize; - maxSize = GetMaxTextureSize(); - if ((unsigned)maxSize < EFB_WIDTH * efb_scale_numeratorX / efb_scale_denominatorX) - { - efb_scale_numeratorX = efb_scale_numeratorY = (maxSize / EFB_WIDTH); - efb_scale_denominatorX = efb_scale_denominatorY = 1; - } + break; + } + if (s_last_efb_scale > SCALE_AUTO_INTEGRAL) + CalculateTargetScale(EFB_WIDTH, EFB_HEIGHT, &newEFBWidth, &newEFBHeight); - break; - } - if (s_last_efb_scale > SCALE_AUTO_INTEGRAL) - CalculateTargetScale(EFB_WIDTH, EFB_HEIGHT, &newEFBWidth, &newEFBHeight); - - if (newEFBWidth != s_target_width || newEFBHeight != s_target_height) - { - s_target_width = newEFBWidth; - s_target_height = newEFBHeight; - return true; - } - return false; + if (newEFBWidth != s_target_width || newEFBHeight != s_target_height) + { + s_target_width = newEFBWidth; + s_target_height = newEFBHeight; + return true; + } + return false; } -void Renderer::ConvertStereoRectangle(const TargetRectangle& rc, TargetRectangle& leftRc, TargetRectangle& rightRc) +void Renderer::ConvertStereoRectangle(const TargetRectangle& rc, TargetRectangle& leftRc, + TargetRectangle& rightRc) { - // Resize target to half its original size - TargetRectangle drawRc = rc; - if (g_ActiveConfig.iStereoMode == STEREO_TAB) - { - // The height may be negative due to flipped rectangles - int height = rc.bottom - rc.top; - drawRc.top += height / 4; - drawRc.bottom -= height / 4; - } - else - { - int width = rc.right - rc.left; - drawRc.left += width / 4; - drawRc.right -= width / 4; - } + // Resize target to half its original size + TargetRectangle drawRc = rc; + if (g_ActiveConfig.iStereoMode == STEREO_TAB) + { + // The height may be negative due to flipped rectangles + int height = rc.bottom - rc.top; + drawRc.top += height / 4; + drawRc.bottom -= height / 4; + } + else + { + int width = rc.right - rc.left; + drawRc.left += width / 4; + drawRc.right -= width / 4; + } - // Create two target rectangle offset to the sides of the backbuffer - leftRc = drawRc, rightRc = drawRc; - if (g_ActiveConfig.iStereoMode == STEREO_TAB) - { - leftRc.top -= s_backbuffer_height / 4; - leftRc.bottom -= s_backbuffer_height / 4; - rightRc.top += s_backbuffer_height / 4; - rightRc.bottom += s_backbuffer_height / 4; - } - else - { - leftRc.left -= s_backbuffer_width / 4; - leftRc.right -= s_backbuffer_width / 4; - rightRc.left += s_backbuffer_width / 4; - rightRc.right += s_backbuffer_width / 4; - } + // Create two target rectangle offset to the sides of the backbuffer + leftRc = drawRc, rightRc = drawRc; + if (g_ActiveConfig.iStereoMode == STEREO_TAB) + { + leftRc.top -= s_backbuffer_height / 4; + leftRc.bottom -= s_backbuffer_height / 4; + rightRc.top += s_backbuffer_height / 4; + rightRc.bottom += s_backbuffer_height / 4; + } + else + { + leftRc.left -= s_backbuffer_width / 4; + leftRc.right -= s_backbuffer_width / 4; + rightRc.left += s_backbuffer_width / 4; + rightRc.right += s_backbuffer_width / 4; + } } void Renderer::SetScreenshot(const std::string& filename) { - std::lock_guard lk(s_criticalScreenshot); - s_sScreenshotName = filename; - s_bScreenshot = true; + std::lock_guard lk(s_criticalScreenshot); + s_sScreenshotName = filename; + s_bScreenshot = true; } // Create On-Screen-Messages void Renderer::DrawDebugText() { - std::string final_yellow, final_cyan; + std::string final_yellow, final_cyan; - if (g_ActiveConfig.bShowFPS || SConfig::GetInstance().m_ShowFrameCount) - { - if (g_ActiveConfig.bShowFPS) - final_cyan += StringFromFormat("FPS: %u", g_renderer->m_fps_counter.GetFPS()); + if (g_ActiveConfig.bShowFPS || SConfig::GetInstance().m_ShowFrameCount) + { + if (g_ActiveConfig.bShowFPS) + final_cyan += StringFromFormat("FPS: %u", g_renderer->m_fps_counter.GetFPS()); - if (g_ActiveConfig.bShowFPS && SConfig::GetInstance().m_ShowFrameCount) - final_cyan += " - "; - if (SConfig::GetInstance().m_ShowFrameCount) - { - final_cyan += StringFromFormat("Frame: %llu", (unsigned long long) Movie::g_currentFrame); - if (Movie::IsPlayingInput()) - final_cyan += StringFromFormat(" / %llu", (unsigned long long) Movie::g_totalFrames); - } + if (g_ActiveConfig.bShowFPS && SConfig::GetInstance().m_ShowFrameCount) + final_cyan += " - "; + if (SConfig::GetInstance().m_ShowFrameCount) + { + final_cyan += StringFromFormat("Frame: %llu", (unsigned long long)Movie::g_currentFrame); + if (Movie::IsPlayingInput()) + final_cyan += StringFromFormat(" / %llu", (unsigned long long)Movie::g_totalFrames); + } - final_cyan += "\n"; - final_yellow += "\n"; - } + final_cyan += "\n"; + final_yellow += "\n"; + } - if (SConfig::GetInstance().m_ShowLag) - { - final_cyan += StringFromFormat("Lag: %" PRIu64 "\n", Movie::g_currentLagCount); - final_yellow += "\n"; - } + if (SConfig::GetInstance().m_ShowLag) + { + final_cyan += StringFromFormat("Lag: %" PRIu64 "\n", Movie::g_currentLagCount); + final_yellow += "\n"; + } - if (SConfig::GetInstance().m_ShowInputDisplay) - { - final_cyan += Movie::GetInputDisplay(); - final_yellow += "\n"; - } + if (SConfig::GetInstance().m_ShowInputDisplay) + { + final_cyan += Movie::GetInputDisplay(); + final_yellow += "\n"; + } - // OSD Menu messages - if (OSDChoice > 0) - { - OSDTime = Common::Timer::GetTimeMs() + 3000; - OSDChoice = -OSDChoice; - } + // OSD Menu messages + if (OSDChoice > 0) + { + OSDTime = Common::Timer::GetTimeMs() + 3000; + OSDChoice = -OSDChoice; + } - if ((u32)OSDTime > Common::Timer::GetTimeMs()) - { - std::string res_text; - switch (g_ActiveConfig.iEFBScale) - { - case SCALE_AUTO: - res_text = "Auto (fractional)"; - break; - case SCALE_AUTO_INTEGRAL: - res_text = "Auto (integral)"; - break; - case SCALE_1X: - res_text = "Native"; - break; - case SCALE_1_5X: - res_text = "1.5x"; - break; - case SCALE_2X: - res_text = "2x"; - break; - case SCALE_2_5X: - res_text = "2.5x"; - break; - default: - res_text = StringFromFormat("%dx", g_ActiveConfig.iEFBScale - 3); - break; - } - const char* ar_text = ""; - switch (g_ActiveConfig.iAspectRatio) - { - case ASPECT_AUTO: - ar_text = "Auto"; - break; - case ASPECT_STRETCH: - ar_text = "Stretch"; - break; - case ASPECT_ANALOG: - ar_text = "Force 4:3"; - break; - case ASPECT_ANALOG_WIDE: - ar_text = "Force 16:9"; - } + if ((u32)OSDTime > Common::Timer::GetTimeMs()) + { + std::string res_text; + switch (g_ActiveConfig.iEFBScale) + { + case SCALE_AUTO: + res_text = "Auto (fractional)"; + break; + case SCALE_AUTO_INTEGRAL: + res_text = "Auto (integral)"; + break; + case SCALE_1X: + res_text = "Native"; + break; + case SCALE_1_5X: + res_text = "1.5x"; + break; + case SCALE_2X: + res_text = "2x"; + break; + case SCALE_2_5X: + res_text = "2.5x"; + break; + default: + res_text = StringFromFormat("%dx", g_ActiveConfig.iEFBScale - 3); + break; + } + const char* ar_text = ""; + switch (g_ActiveConfig.iAspectRatio) + { + case ASPECT_AUTO: + ar_text = "Auto"; + break; + case ASPECT_STRETCH: + ar_text = "Stretch"; + break; + case ASPECT_ANALOG: + ar_text = "Force 4:3"; + break; + case ASPECT_ANALOG_WIDE: + ar_text = "Force 16:9"; + } - const char* const efbcopy_text = g_ActiveConfig.bSkipEFBCopyToRam ? "to Texture" : "to RAM"; + const char* const efbcopy_text = g_ActiveConfig.bSkipEFBCopyToRam ? "to Texture" : "to RAM"; - // The rows - const std::string lines[] = - { - std::string("Internal Resolution: ") + res_text, - std::string("Aspect Ratio: ") + ar_text + (g_ActiveConfig.bCrop ? " (crop)" : ""), - std::string("Copy EFB: ") + efbcopy_text, - std::string("Fog: ") + (g_ActiveConfig.bDisableFog ? "Disabled" : "Enabled"), - SConfig::GetInstance().m_EmulationSpeed <= 0 ? "Speed Limit: Unlimited" : - StringFromFormat("Speed Limit: %li%%", std::lround(SConfig::GetInstance().m_EmulationSpeed * 100.f)), - }; + // The rows + const std::string lines[] = { + std::string("Internal Resolution: ") + res_text, + std::string("Aspect Ratio: ") + ar_text + (g_ActiveConfig.bCrop ? " (crop)" : ""), + std::string("Copy EFB: ") + efbcopy_text, + std::string("Fog: ") + (g_ActiveConfig.bDisableFog ? "Disabled" : "Enabled"), + SConfig::GetInstance().m_EmulationSpeed <= 0 ? + "Speed Limit: Unlimited" : + StringFromFormat("Speed Limit: %li%%", + std::lround(SConfig::GetInstance().m_EmulationSpeed * 100.f)), + }; - enum { lines_count = sizeof(lines) / sizeof(*lines) }; + enum + { + lines_count = sizeof(lines) / sizeof(*lines) + }; - // The latest changed setting in yellow - for (int i = 0; i != lines_count; ++i) - { - if (OSDChoice == -i - 1) - final_yellow += lines[i]; - final_yellow += '\n'; - } + // The latest changed setting in yellow + for (int i = 0; i != lines_count; ++i) + { + if (OSDChoice == -i - 1) + final_yellow += lines[i]; + final_yellow += '\n'; + } - // The other settings in cyan - for (int i = 0; i != lines_count; ++i) - { - if (OSDChoice != -i - 1) - final_cyan += lines[i]; - final_cyan += '\n'; - } - } + // The other settings in cyan + for (int i = 0; i != lines_count; ++i) + { + if (OSDChoice != -i - 1) + final_cyan += lines[i]; + final_cyan += '\n'; + } + } - final_cyan += Common::Profiler::ToString(); + final_cyan += Common::Profiler::ToString(); - if (g_ActiveConfig.bOverlayStats) - final_cyan += Statistics::ToString(); + if (g_ActiveConfig.bOverlayStats) + final_cyan += Statistics::ToString(); - if (g_ActiveConfig.bOverlayProjStats) - final_cyan += Statistics::ToStringProj(); + if (g_ActiveConfig.bOverlayProjStats) + final_cyan += Statistics::ToStringProj(); - //and then the text - g_renderer->RenderText(final_cyan, 20, 20, 0xFF00FFFF); - g_renderer->RenderText(final_yellow, 20, 20, 0xFFFFFF00); + // and then the text + g_renderer->RenderText(final_cyan, 20, 20, 0xFF00FFFF); + g_renderer->RenderText(final_yellow, 20, 20, 0xFFFFFF00); } void Renderer::UpdateDrawRectangle(int backbuffer_width, int backbuffer_height) { - float FloatGLWidth = (float)backbuffer_width; - float FloatGLHeight = (float)backbuffer_height; - float FloatXOffset = 0; - float FloatYOffset = 0; + float FloatGLWidth = (float)backbuffer_width; + float FloatGLHeight = (float)backbuffer_height; + float FloatXOffset = 0; + float FloatYOffset = 0; - // The rendering window size - const float WinWidth = FloatGLWidth; - const float WinHeight = FloatGLHeight; + // The rendering window size + const float WinWidth = FloatGLWidth; + const float WinHeight = FloatGLHeight; - // Update aspect ratio hack values - // Won't take effect until next frame - // Don't know if there is a better place for this code so there isn't a 1 frame delay - if (g_ActiveConfig.bWidescreenHack) - { - float source_aspect = VideoInterface::GetAspectRatio(); - if (Core::g_aspect_wide) - source_aspect = AspectToWidescreen(source_aspect); - float target_aspect; + // Update aspect ratio hack values + // Won't take effect until next frame + // Don't know if there is a better place for this code so there isn't a 1 frame delay + if (g_ActiveConfig.bWidescreenHack) + { + float source_aspect = VideoInterface::GetAspectRatio(); + if (Core::g_aspect_wide) + source_aspect = AspectToWidescreen(source_aspect); + float target_aspect; - switch (g_ActiveConfig.iAspectRatio) - { - case ASPECT_STRETCH: - target_aspect = WinWidth / WinHeight; - break; - case ASPECT_ANALOG: - target_aspect = VideoInterface::GetAspectRatio(); - break; - case ASPECT_ANALOG_WIDE: - target_aspect = AspectToWidescreen(VideoInterface::GetAspectRatio()); - break; - default: - // ASPECT_AUTO - target_aspect = source_aspect; - break; - } + switch (g_ActiveConfig.iAspectRatio) + { + case ASPECT_STRETCH: + target_aspect = WinWidth / WinHeight; + break; + case ASPECT_ANALOG: + target_aspect = VideoInterface::GetAspectRatio(); + break; + case ASPECT_ANALOG_WIDE: + target_aspect = AspectToWidescreen(VideoInterface::GetAspectRatio()); + break; + default: + // ASPECT_AUTO + target_aspect = source_aspect; + break; + } - float adjust = source_aspect / target_aspect; - if (adjust > 1) - { - // Vert+ - g_Config.fAspectRatioHackW = 1; - g_Config.fAspectRatioHackH = 1 / adjust; - } - else - { - // Hor+ - g_Config.fAspectRatioHackW = adjust; - g_Config.fAspectRatioHackH = 1; - } - } - else - { - // Hack is disabled - g_Config.fAspectRatioHackW = 1; - g_Config.fAspectRatioHackH = 1; - } + float adjust = source_aspect / target_aspect; + if (adjust > 1) + { + // Vert+ + g_Config.fAspectRatioHackW = 1; + g_Config.fAspectRatioHackH = 1 / adjust; + } + else + { + // Hor+ + g_Config.fAspectRatioHackW = adjust; + g_Config.fAspectRatioHackH = 1; + } + } + else + { + // Hack is disabled + g_Config.fAspectRatioHackW = 1; + g_Config.fAspectRatioHackH = 1; + } - // Check for force-settings and override. + // Check for force-settings and override. - // The rendering window aspect ratio as a proportion of the 4:3 or 16:9 ratio - float Ratio; - if (g_ActiveConfig.iAspectRatio == ASPECT_ANALOG_WIDE || (g_ActiveConfig.iAspectRatio != ASPECT_ANALOG && Core::g_aspect_wide)) - { - Ratio = (WinWidth / WinHeight) / AspectToWidescreen(VideoInterface::GetAspectRatio()); - } - else - { - Ratio = (WinWidth / WinHeight) / VideoInterface::GetAspectRatio(); - } + // The rendering window aspect ratio as a proportion of the 4:3 or 16:9 ratio + float Ratio; + if (g_ActiveConfig.iAspectRatio == ASPECT_ANALOG_WIDE || + (g_ActiveConfig.iAspectRatio != ASPECT_ANALOG && Core::g_aspect_wide)) + { + Ratio = (WinWidth / WinHeight) / AspectToWidescreen(VideoInterface::GetAspectRatio()); + } + else + { + Ratio = (WinWidth / WinHeight) / VideoInterface::GetAspectRatio(); + } - if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH) - { - if (Ratio > 1.0f) - { - // Scale down and center in the X direction. - FloatGLWidth /= Ratio; - FloatXOffset = (WinWidth - FloatGLWidth) / 2.0f; - } - // The window is too high, we have to limit the height - else - { - // Scale down and center in the Y direction. - FloatGLHeight *= Ratio; - FloatYOffset = FloatYOffset + (WinHeight - FloatGLHeight) / 2.0f; - } - } + if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH) + { + if (Ratio > 1.0f) + { + // Scale down and center in the X direction. + FloatGLWidth /= Ratio; + FloatXOffset = (WinWidth - FloatGLWidth) / 2.0f; + } + // The window is too high, we have to limit the height + else + { + // Scale down and center in the Y direction. + FloatGLHeight *= Ratio; + FloatYOffset = FloatYOffset + (WinHeight - FloatGLHeight) / 2.0f; + } + } - // ----------------------------------------------------------------------- - // Crop the picture from Analog to 4:3 or from Analog (Wide) to 16:9. - // Output: FloatGLWidth, FloatGLHeight, FloatXOffset, FloatYOffset - // ------------------ - if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH && g_ActiveConfig.bCrop) - { - Ratio = (4.0f / 3.0f) / VideoInterface::GetAspectRatio(); - if (Ratio <= 1.0f) - { - Ratio = 1.0f / Ratio; - } - // The width and height we will add (calculate this before FloatGLWidth and FloatGLHeight is adjusted) - float IncreasedWidth = (Ratio - 1.0f) * FloatGLWidth; - float IncreasedHeight = (Ratio - 1.0f) * FloatGLHeight; - // The new width and height - FloatGLWidth = FloatGLWidth * Ratio; - FloatGLHeight = FloatGLHeight * Ratio; - // Adjust the X and Y offset - FloatXOffset = FloatXOffset - (IncreasedWidth * 0.5f); - FloatYOffset = FloatYOffset - (IncreasedHeight * 0.5f); - } + // ----------------------------------------------------------------------- + // Crop the picture from Analog to 4:3 or from Analog (Wide) to 16:9. + // Output: FloatGLWidth, FloatGLHeight, FloatXOffset, FloatYOffset + // ------------------ + if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH && g_ActiveConfig.bCrop) + { + Ratio = (4.0f / 3.0f) / VideoInterface::GetAspectRatio(); + if (Ratio <= 1.0f) + { + Ratio = 1.0f / Ratio; + } + // The width and height we will add (calculate this before FloatGLWidth and FloatGLHeight is + // adjusted) + float IncreasedWidth = (Ratio - 1.0f) * FloatGLWidth; + float IncreasedHeight = (Ratio - 1.0f) * FloatGLHeight; + // The new width and height + FloatGLWidth = FloatGLWidth * Ratio; + FloatGLHeight = FloatGLHeight * Ratio; + // Adjust the X and Y offset + FloatXOffset = FloatXOffset - (IncreasedWidth * 0.5f); + FloatYOffset = FloatYOffset - (IncreasedHeight * 0.5f); + } - int XOffset = (int)(FloatXOffset + 0.5f); - int YOffset = (int)(FloatYOffset + 0.5f); - int iWhidth = (int)ceil(FloatGLWidth); - int iHeight = (int)ceil(FloatGLHeight); - iWhidth -= iWhidth % 4; // ensure divisibility by 4 to make it compatible with all the video encoders - iHeight -= iHeight % 4; + int XOffset = (int)(FloatXOffset + 0.5f); + int YOffset = (int)(FloatYOffset + 0.5f); + int iWhidth = (int)ceil(FloatGLWidth); + int iHeight = (int)ceil(FloatGLHeight); + iWhidth -= + iWhidth % 4; // ensure divisibility by 4 to make it compatible with all the video encoders + iHeight -= iHeight % 4; - target_rc.left = XOffset; - target_rc.top = YOffset; - target_rc.right = XOffset + iWhidth; - target_rc.bottom = YOffset + iHeight; + target_rc.left = XOffset; + target_rc.top = YOffset; + target_rc.right = XOffset + iWhidth; + target_rc.bottom = YOffset + iHeight; } void Renderer::SetWindowSize(int width, int height) { - if (width < 1) - width = 1; - if (height < 1) - height = 1; + if (width < 1) + width = 1; + if (height < 1) + height = 1; - // Scale the window size by the EFB scale. - CalculateTargetScale(width, height, &width, &height); + // Scale the window size by the EFB scale. + CalculateTargetScale(width, height, &width, &height); - Host_RequestRenderWindowSize(width, height); + Host_RequestRenderWindowSize(width, height); } void Renderer::CheckFifoRecording() { - bool wasRecording = g_bRecordFifoData; - g_bRecordFifoData = FifoRecorder::GetInstance().IsRecording(); + bool wasRecording = g_bRecordFifoData; + g_bRecordFifoData = FifoRecorder::GetInstance().IsRecording(); - if (g_bRecordFifoData) - { - if (!wasRecording) - { - RecordVideoMemory(); - } + if (g_bRecordFifoData) + { + if (!wasRecording) + { + RecordVideoMemory(); + } - FifoRecorder::GetInstance().EndFrame(CommandProcessor::fifo.CPBase, CommandProcessor::fifo.CPEnd); - } + FifoRecorder::GetInstance().EndFrame(CommandProcessor::fifo.CPBase, + CommandProcessor::fifo.CPEnd); + } } void Renderer::RecordVideoMemory() { - u32 *bpmem_ptr = (u32*)&bpmem; - u32 cpmem[256]; - // The FIFO recording format splits XF memory into xfmem and xfregs; follow - // that split here. - u32 *xfmem_ptr = (u32*)&xfmem; - u32 *xfregs_ptr = (u32*)&xfmem + FifoDataFile::XF_MEM_SIZE; - u32 xfregs_size = sizeof(XFMemory) / 4 - FifoDataFile::XF_MEM_SIZE; + u32* bpmem_ptr = (u32*)&bpmem; + u32 cpmem[256]; + // The FIFO recording format splits XF memory into xfmem and xfregs; follow + // that split here. + u32* xfmem_ptr = (u32*)&xfmem; + u32* xfregs_ptr = (u32*)&xfmem + FifoDataFile::XF_MEM_SIZE; + u32 xfregs_size = sizeof(XFMemory) / 4 - FifoDataFile::XF_MEM_SIZE; - memset(cpmem, 0, 256 * 4); - FillCPMemoryArray(cpmem); + memset(cpmem, 0, 256 * 4); + FillCPMemoryArray(cpmem); - FifoRecorder::GetInstance().SetVideoMemory(bpmem_ptr, cpmem, xfmem_ptr, xfregs_ptr, xfregs_size); + FifoRecorder::GetInstance().SetVideoMemory(bpmem_ptr, cpmem, xfmem_ptr, xfregs_ptr, xfregs_size); } -void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma) +void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, + float Gamma) { - // TODO: merge more generic parts into VideoCommon - g_renderer->SwapImpl(xfbAddr, fbWidth, fbStride, fbHeight, rc, Gamma); + // TODO: merge more generic parts into VideoCommon + g_renderer->SwapImpl(xfbAddr, fbWidth, fbStride, fbHeight, rc, Gamma); - if (XFBWrited) - g_renderer->m_fps_counter.Update(); + if (XFBWrited) + g_renderer->m_fps_counter.Update(); - frameCount++; - GFX_DEBUGGER_PAUSE_AT(NEXT_FRAME, true); + frameCount++; + GFX_DEBUGGER_PAUSE_AT(NEXT_FRAME, true); - // Begin new frame - // Set default viewport and scissor, for the clear to work correctly - // New frame - stats.ResetFrame(); + // Begin new frame + // Set default viewport and scissor, for the clear to work correctly + // New frame + stats.ResetFrame(); - Core::Callback_VideoCopiedToXFB(XFBWrited || (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB)); - XFBWrited = false; + Core::Callback_VideoCopiedToXFB(XFBWrited || + (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB)); + XFBWrited = false; } void Renderer::FlipImageData(u8* data, int w, int h, int pixel_width) { - for (int y = 0; y < h / 2; ++y) - { - for (int x = 0; x < w; ++x) - { - for (int delta = 0; delta < pixel_width; ++delta) - std::swap(data[(y * w + x) * pixel_width + delta], data[((h - 1 - y) * w + x) * pixel_width + delta]); - } - } + for (int y = 0; y < h / 2; ++y) + { + for (int x = 0; x < w; ++x) + { + for (int delta = 0; delta < pixel_width; ++delta) + std::swap(data[(y * w + x) * pixel_width + delta], + data[((h - 1 - y) * w + x) * pixel_width + delta]); + } + } } - diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 8ab99869b1..81554f5e78 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -32,8 +32,8 @@ class PostProcessingShaderImplementation; struct EfbPokeData { - u16 x,y; - u32 data; + u16 x, y; + u32 data; }; // TODO: Move these out of here. @@ -46,144 +46,142 @@ extern int OSDChoice; class Renderer { public: - Renderer(); - virtual ~Renderer(); + Renderer(); + virtual ~Renderer(); - enum PixelPerfQuery { - PP_ZCOMP_INPUT_ZCOMPLOC, - PP_ZCOMP_OUTPUT_ZCOMPLOC, - PP_ZCOMP_INPUT, - PP_ZCOMP_OUTPUT, - PP_BLEND_INPUT, - PP_EFB_COPY_CLOCKS - }; + enum PixelPerfQuery + { + PP_ZCOMP_INPUT_ZCOMPLOC, + PP_ZCOMP_OUTPUT_ZCOMPLOC, + PP_ZCOMP_INPUT, + PP_ZCOMP_OUTPUT, + PP_BLEND_INPUT, + PP_EFB_COPY_CLOCKS + }; - virtual void SetColorMask() {} - virtual void SetBlendMode(bool forceUpdate) {} - virtual void SetScissorRect(const EFBRectangle& rc) {} - virtual void SetGenerationMode() {} - virtual void SetDepthMode() {} - virtual void SetLogicOpMode() {} - virtual void SetDitherMode() {} - virtual void SetSamplerState(int stage, int texindex, bool custom_tex) {} - virtual void SetInterlacingMode() {} - virtual void SetViewport() {} + virtual void SetColorMask() {} + virtual void SetBlendMode(bool forceUpdate) {} + virtual void SetScissorRect(const EFBRectangle& rc) {} + virtual void SetGenerationMode() {} + virtual void SetDepthMode() {} + virtual void SetLogicOpMode() {} + virtual void SetDitherMode() {} + virtual void SetSamplerState(int stage, int texindex, bool custom_tex) {} + virtual void SetInterlacingMode() {} + virtual void SetViewport() {} + virtual void ApplyState(bool bUseDstAlpha) {} + virtual void RestoreState() {} + virtual void ResetAPIState() {} + virtual void RestoreAPIState() {} + // Ideal internal resolution - determined by display resolution (automatic scaling) and/or a + // multiple of the native EFB resolution + static int GetTargetWidth() { return s_target_width; } + static int GetTargetHeight() { return s_target_height; } + // Display resolution + static int GetBackbufferWidth() { return s_backbuffer_width; } + static int GetBackbufferHeight() { return s_backbuffer_height; } + static void SetWindowSize(int width, int height); - virtual void ApplyState(bool bUseDstAlpha) {} - virtual void RestoreState() {} + // EFB coordinate conversion functions - virtual void ResetAPIState() {} - virtual void RestoreAPIState() {} + // Use this to convert a whole native EFB rect to backbuffer coordinates + virtual TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) = 0; - // Ideal internal resolution - determined by display resolution (automatic scaling) and/or a multiple of the native EFB resolution - static int GetTargetWidth() { return s_target_width; } - static int GetTargetHeight() { return s_target_height; } + static const TargetRectangle& GetTargetRectangle() { return target_rc; } + static void UpdateDrawRectangle(int backbuffer_width, int backbuffer_height); - // Display resolution - static int GetBackbufferWidth() { return s_backbuffer_width; } - static int GetBackbufferHeight() { return s_backbuffer_height; } + // Use this to convert a single target rectangle to two stereo rectangles + static void ConvertStereoRectangle(const TargetRectangle& rc, TargetRectangle& leftRc, + TargetRectangle& rightRc); - static void SetWindowSize(int width, int height); + // Use this to upscale native EFB coordinates to IDEAL internal resolution + static int EFBToScaledX(int x); + static int EFBToScaledY(int y); - // EFB coordinate conversion functions + // Floating point versions of the above - only use them if really necessary + static float EFBToScaledXf(float x) { return x * ((float)GetTargetWidth() / (float)EFB_WIDTH); } + static float EFBToScaledYf(float y) { return y * ((float)GetTargetHeight() / (float)EFB_HEIGHT); } + // Random utilities + static void SetScreenshot(const std::string& filename); + static void DrawDebugText(); - // Use this to convert a whole native EFB rect to backbuffer coordinates - virtual TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) = 0; + virtual void RenderText(const std::string& text, int left, int top, u32 color) = 0; - static const TargetRectangle& GetTargetRectangle() { return target_rc; } - static void UpdateDrawRectangle(int backbuffer_width, int backbuffer_height); + virtual void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, + u32 color, u32 z) = 0; + virtual void ReinterpretPixelData(unsigned int convtype) = 0; + static void RenderToXFB(u32 xfbAddr, const EFBRectangle& sourceRc, u32 fbStride, u32 fbHeight, + float Gamma = 1.0f); - // Use this to convert a single target rectangle to two stereo rectangles - static void ConvertStereoRectangle(const TargetRectangle& rc, TargetRectangle& leftRc, TargetRectangle& rightRc); + virtual u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) = 0; + virtual void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) = 0; - // Use this to upscale native EFB coordinates to IDEAL internal resolution - static int EFBToScaledX(int x); - static int EFBToScaledY(int y); + virtual u16 BBoxRead(int index) = 0; + virtual void BBoxWrite(int index, u16 value) = 0; - // Floating point versions of the above - only use them if really necessary - static float EFBToScaledXf(float x) { return x * ((float)GetTargetWidth() / (float)EFB_WIDTH); } - static float EFBToScaledYf(float y) { return y * ((float)GetTargetHeight() / (float)EFB_HEIGHT); } + static void FlipImageData(u8* data, int w, int h, int pixel_width = 3); - // Random utilities - static void SetScreenshot(const std::string& filename); - static void DrawDebugText(); + // Finish up the current frame, print some stats + static void Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, + float Gamma = 1.0f); + virtual void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, + const EFBRectangle& rc, float Gamma = 1.0f) = 0; - virtual void RenderText(const std::string& text, int left, int top, u32 color) = 0; + virtual bool SaveScreenshot(const std::string& filename, const TargetRectangle& rc) = 0; - virtual void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) = 0; - virtual void ReinterpretPixelData(unsigned int convtype) = 0; - static void RenderToXFB(u32 xfbAddr, const EFBRectangle& sourceRc, u32 fbStride, u32 fbHeight, float Gamma = 1.0f); + static PEControl::PixelFormat GetPrevPixelFormat() { return prev_efb_format; } + static void StorePixelFormat(PEControl::PixelFormat new_format) { prev_efb_format = new_format; } + PostProcessingShaderImplementation* GetPostProcessor() { return m_post_processor.get(); } + // Max height/width + virtual int GetMaxTextureSize() = 0; - virtual u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) = 0; - virtual void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) = 0; + static Common::Event s_screenshotCompleted; - virtual u16 BBoxRead(int index) = 0; - virtual void BBoxWrite(int index, u16 value) = 0; - - static void FlipImageData(u8* data, int w, int h, int pixel_width = 3); - - // Finish up the current frame, print some stats - static void Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc,float Gamma = 1.0f); - virtual void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma = 1.0f) = 0; - - virtual bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc) = 0; - - static PEControl::PixelFormat GetPrevPixelFormat() { return prev_efb_format; } - static void StorePixelFormat(PEControl::PixelFormat new_format) { prev_efb_format = new_format; } - - PostProcessingShaderImplementation* GetPostProcessor() { return m_post_processor.get(); } - // Max height/width - virtual int GetMaxTextureSize() = 0; - - static Common::Event s_screenshotCompleted; - - // Final surface changing - static Common::Flag s_SurfaceNeedsChanged; - static Common::Event s_ChangedSurface; + // Final surface changing + static Common::Flag s_SurfaceNeedsChanged; + static Common::Event s_ChangedSurface; protected: + static void CalculateTargetScale(int x, int y, int* scaledX, int* scaledY); + bool CalculateTargetSize(unsigned int framebuffer_width, unsigned int framebuffer_height); - static void CalculateTargetScale(int x, int y, int* scaledX, int* scaledY); - bool CalculateTargetSize(unsigned int framebuffer_width, unsigned int framebuffer_height); + static void CheckFifoRecording(); + static void RecordVideoMemory(); - static void CheckFifoRecording(); - static void RecordVideoMemory(); + static volatile bool s_bScreenshot; + static std::mutex s_criticalScreenshot; + static std::string s_sScreenshotName; - static volatile bool s_bScreenshot; - static std::mutex s_criticalScreenshot; - static std::string s_sScreenshotName; + bool bAVIDumping; - bool bAVIDumping; + std::vector frame_data; + bool bLastFrameDumped; - std::vector frame_data; - bool bLastFrameDumped; + // The framebuffer size + static int s_target_width; + static int s_target_height; - // The framebuffer size - static int s_target_width; - static int s_target_height; + // TODO: Add functionality to reinit all the render targets when the window is resized. + static int s_backbuffer_width; + static int s_backbuffer_height; - // TODO: Add functionality to reinit all the render targets when the window is resized. - static int s_backbuffer_width; - static int s_backbuffer_height; + static TargetRectangle target_rc; - static TargetRectangle target_rc; + // TODO: Can probably eliminate this static var. + static int s_last_efb_scale; - // TODO: Can probably eliminate this static var. - static int s_last_efb_scale; + static bool XFBWrited; - static bool XFBWrited; + FPSCounter m_fps_counter; - FPSCounter m_fps_counter; - - static std::unique_ptr m_post_processor; + static std::unique_ptr m_post_processor; private: - static PEControl::PixelFormat prev_efb_format; - static unsigned int efb_scale_numeratorX; - static unsigned int efb_scale_numeratorY; - static unsigned int efb_scale_denominatorX; - static unsigned int efb_scale_denominatorY; + static PEControl::PixelFormat prev_efb_format; + static unsigned int efb_scale_numeratorX; + static unsigned int efb_scale_numeratorY; + static unsigned int efb_scale_denominatorX; + static unsigned int efb_scale_denominatorY; }; extern std::unique_ptr g_renderer; - diff --git a/Source/Core/VideoCommon/SamplerCommon.h b/Source/Core/VideoCommon/SamplerCommon.h index 0605fddd03..f0fdcf5767 100644 --- a/Source/Core/VideoCommon/SamplerCommon.h +++ b/Source/Core/VideoCommon/SamplerCommon.h @@ -6,7 +6,6 @@ namespace SamplerCommon { - // Helper for checking if a BPMemory TexMode0 register is set to Point // Filtering modes. This is used to decide whether Anisotropic enhancements // are (mostly) safe in the VideoBackends. @@ -14,17 +13,16 @@ namespace SamplerCommon // then applying anisotropic filtering is equivalent to forced filtering. Point // mode textures are usually some sort of 2D UI billboard which will end up // misaligned from the correct pixels when filtered anisotropically. -template +template constexpr bool IsBpTexMode0PointFiltering(const T& tm0) { - return tm0.min_filter < 4 && !tm0.mag_filter; + return tm0.min_filter < 4 && !tm0.mag_filter; } // Check if the minification filter has mipmap based filtering modes enabled. -template +template constexpr bool AreBpTexMode0MipmapsEnabled(const T& tm0) { - return (tm0.min_filter & 3) != 0; + return (tm0.min_filter & 3) != 0; } - } diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h index 18c40af41e..2668c8ea7d 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/ShaderGenCommon.h @@ -14,260 +14,275 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" -#include "Common/StringUtil.h" #include "Common/Logging/Log.h" +#include "Common/StringUtil.h" #include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" #include "VideoCommon/XFMemory.h" /** - * Common interface for classes that need to go through the shader generation path (GenerateVertexShader, GenerateGeometryShader, GeneratePixelShader) + * Common interface for classes that need to go through the shader generation path + * (GenerateVertexShader, GenerateGeometryShader, GeneratePixelShader) * In particular, this includes the shader code generator (ShaderCode). * A different class (ShaderUid) can be used to uniquely identify each ShaderCode object. - * More interesting things can be done with this, e.g. ShaderConstantProfile checks what shader constants are being used. This can be used to optimize buffer management. - * If the class does not use one or more of these methods (e.g. Uid class does not need code), the method will be defined as a no-op by the base class, and the call - * should be optimized out. The reason for this implementation is so that shader selection/generation can be done in two passes, with only a cache lookup being + * More interesting things can be done with this, e.g. ShaderConstantProfile checks what shader + * constants are being used. This can be used to optimize buffer management. + * If the class does not use one or more of these methods (e.g. Uid class does not need code), the + * method will be defined as a no-op by the base class, and the call + * should be optimized out. The reason for this implementation is so that shader + * selection/generation can be done in two passes, with only a cache lookup being * required if the shader has already been generated. */ class ShaderGeneratorInterface { public: - /* - * Used when the shader generator would write a piece of ShaderCode. - * Can be used like printf. - * @note In the ShaderCode implementation, this does indeed write the parameter string to an internal buffer. However, you're free to do whatever you like with the parameter. - */ - void Write(const char*, ...) + /* + * Used when the shader generator would write a piece of ShaderCode. + * Can be used like printf. + * @note In the ShaderCode implementation, this does indeed write the parameter string to an + * internal buffer. However, you're free to do whatever you like with the parameter. + */ + void Write(const char*, ...) #ifdef __GNUC__ - __attribute__((format(printf, 2, 3))) + __attribute__((format(printf, 2, 3))) #endif - { - } + { + } - /* - * Tells us that a specific constant range (including last_index) is being used by the shader - */ - void SetConstantsUsed(unsigned int first_index, unsigned int last_index) {} - - /* - * Returns a pointer to an internally stored object of the uid_data type. - * @warning since most child classes use the default implementation you shouldn't access this directly without adding precautions against nullptr access (e.g. via adding a dummy structure, cf. the vertex/pixel shader generators) - */ - template - uid_data* GetUidData() { return nullptr; } + /* + * Tells us that a specific constant range (including last_index) is being used by the shader + */ + void SetConstantsUsed(unsigned int first_index, unsigned int last_index) {} + /* + * Returns a pointer to an internally stored object of the uid_data type. + * @warning since most child classes use the default implementation you shouldn't access this + * directly without adding precautions against nullptr access (e.g. via adding a dummy structure, + * cf. the vertex/pixel shader generators) + */ + template + uid_data* GetUidData() + { + return nullptr; + } }; /* * Shader UID class used to uniquely identify the ShaderCode output written in the shader generator. * uid_data can be any struct of parameters that uniquely identify each shader code output. * Unless performance is not an issue, uid_data should be tightly packed to reduce memory footprint. - * Shader generators will write to specific uid_data fields; ShaderUid methods will only read raw u32 values from a union. - * NOTE: Because LinearDiskCache reads and writes the storage associated with a ShaderUid instance, ShaderUid must be trivially copyable. + * Shader generators will write to specific uid_data fields; ShaderUid methods will only read raw + * u32 values from a union. + * NOTE: Because LinearDiskCache reads and writes the storage associated with a ShaderUid instance, + * ShaderUid must be trivially copyable. */ -template +template class ShaderUid : public ShaderGeneratorInterface { public: - bool operator == (const ShaderUid& obj) const - { - return memcmp(this->values, obj.values, data.NumValues() * sizeof(*values)) == 0; - } + bool operator==(const ShaderUid& obj) const + { + return memcmp(this->values, obj.values, data.NumValues() * sizeof(*values)) == 0; + } - bool operator != (const ShaderUid& obj) const - { - return memcmp(this->values, obj.values, data.NumValues() * sizeof(*values)) != 0; - } + bool operator!=(const ShaderUid& obj) const + { + return memcmp(this->values, obj.values, data.NumValues() * sizeof(*values)) != 0; + } - // determines the storage order inside STL containers - bool operator < (const ShaderUid& obj) const - { - return memcmp(this->values, obj.values, data.NumValues() * sizeof(*values)) < 0; - } - - template - uid_data2* GetUidData() { return &data; } - const uid_data* GetUidData() const { return &data; } - const u8* GetUidDataRaw() const { return &values[0]; } - - size_t GetUidDataSize() const { return sizeof(values); } + // determines the storage order inside STL containers + bool operator<(const ShaderUid& obj) const + { + return memcmp(this->values, obj.values, data.NumValues() * sizeof(*values)) < 0; + } + template + uid_data2* GetUidData() + { + return &data; + } + const uid_data* GetUidData() const { return &data; } + const u8* GetUidDataRaw() const { return &values[0]; } + size_t GetUidDataSize() const { return sizeof(values); } private: - union - { - uid_data data; - u8 values[sizeof(uid_data)]; - }; + union { + uid_data data; + u8 values[sizeof(uid_data)]; + }; }; class ShaderCode : public ShaderGeneratorInterface { public: - ShaderCode() - { - m_buffer.reserve(16384); - } - - const std::string& GetBuffer() const { return m_buffer; } - - void Write(const char* fmt, ...) + ShaderCode() { m_buffer.reserve(16384); } + const std::string& GetBuffer() const { return m_buffer; } + void Write(const char* fmt, ...) #ifdef __GNUC__ - __attribute__((format(printf, 2, 3))) + __attribute__((format(printf, 2, 3))) #endif - { - va_list arglist; - va_start(arglist, fmt); - m_buffer += StringFromFormatV(fmt, arglist); - va_end(arglist); - } + { + va_list arglist; + va_start(arglist, fmt); + m_buffer += StringFromFormatV(fmt, arglist); + va_end(arglist); + } protected: - std::string m_buffer; + std::string m_buffer; }; /** - * Generates a shader constant profile which can be used to query which constants are used in a shader + * Generates a shader constant profile which can be used to query which constants are used in a + * shader */ class ShaderConstantProfile : public ShaderGeneratorInterface { public: - ShaderConstantProfile(int num_constants) { constant_usage.resize(num_constants); } + ShaderConstantProfile(int num_constants) { constant_usage.resize(num_constants); } + void SetConstantsUsed(unsigned int first_index, unsigned int last_index) + { + for (unsigned int i = first_index; i < last_index + 1; ++i) + constant_usage[i] = true; + } - void SetConstantsUsed(unsigned int first_index, unsigned int last_index) - { - for (unsigned int i = first_index; i < last_index + 1; ++i) - constant_usage[i] = true; - } - - bool ConstantIsUsed(unsigned int index) const - { - // TODO: Not ready for usage yet - return true; - //return constant_usage[index]; - } + bool ConstantIsUsed(unsigned int index) const + { + // TODO: Not ready for usage yet + return true; + // return constant_usage[index]; + } private: - std::vector constant_usage; // TODO: Is vector appropriate here? + std::vector constant_usage; // TODO: Is vector appropriate here? }; /** * Checks if there has been */ -template +template class UidChecker { public: - void Invalidate() - { - m_shaders.clear(); - m_uids.clear(); - } + void Invalidate() + { + m_shaders.clear(); + m_uids.clear(); + } - void AddToIndexAndCheck(CodeT& new_code, const UidT& new_uid, const char* shader_type, const char* dump_prefix) - { - bool uid_is_indexed = std::find(m_uids.begin(), m_uids.end(), new_uid) != m_uids.end(); - if (!uid_is_indexed) - { - m_uids.push_back(new_uid); - m_shaders[new_uid] = new_code.GetBuffer(); - } - else - { - // uid is already in the index => check if there's a shader with the same uid but different code - auto& old_code = m_shaders[new_uid]; - if (old_code != new_code.GetBuffer()) - { - static int num_failures = 0; + void AddToIndexAndCheck(CodeT& new_code, const UidT& new_uid, const char* shader_type, + const char* dump_prefix) + { + bool uid_is_indexed = std::find(m_uids.begin(), m_uids.end(), new_uid) != m_uids.end(); + if (!uid_is_indexed) + { + m_uids.push_back(new_uid); + m_shaders[new_uid] = new_code.GetBuffer(); + } + else + { + // uid is already in the index => check if there's a shader with the same uid but different + // code + auto& old_code = m_shaders[new_uid]; + if (old_code != new_code.GetBuffer()) + { + static int num_failures = 0; - std::string temp = StringFromFormat("%s%ssuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), - dump_prefix, ++num_failures); + std::string temp = + StringFromFormat("%s%ssuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), + dump_prefix, ++num_failures); - // TODO: Should also dump uids - std::ofstream file; - OpenFStream(file, temp, std::ios_base::out); - file << "Old shader code:\n" << old_code; - file << "\n\nNew shader code:\n" << new_code.GetBuffer(); - file << "\n\nShader uid:\n"; - for (unsigned int i = 0; i < new_uid.GetUidDataSize(); ++i) - { - u8 value = new_uid.GetUidDataRaw()[i]; - if ((i % 4) == 0) - { - auto last_value = (i + 3 < new_uid.GetUidDataSize() - 1) ? i + 3 : new_uid.GetUidDataSize(); - file << std::setfill(' ') << std::dec; - file << "Values " << std::setw(2) << i << " - " << last_value << ": "; - } + // TODO: Should also dump uids + std::ofstream file; + OpenFStream(file, temp, std::ios_base::out); + file << "Old shader code:\n" << old_code; + file << "\n\nNew shader code:\n" << new_code.GetBuffer(); + file << "\n\nShader uid:\n"; + for (unsigned int i = 0; i < new_uid.GetUidDataSize(); ++i) + { + u8 value = new_uid.GetUidDataRaw()[i]; + if ((i % 4) == 0) + { + auto last_value = + (i + 3 < new_uid.GetUidDataSize() - 1) ? i + 3 : new_uid.GetUidDataSize(); + file << std::setfill(' ') << std::dec; + file << "Values " << std::setw(2) << i << " - " << last_value << ": "; + } - file << std::setw(2) << std::setfill('0') << std::hex << value << std::setw(1); - if ((i % 4) < 3) - file << ' '; - else - file << std::endl; - } + file << std::setw(2) << std::setfill('0') << std::hex << value << std::setw(1); + if ((i % 4) < 3) + file << ' '; + else + file << std::endl; + } - ERROR_LOG(VIDEO, "%s shader uid mismatch! See %s for details", shader_type, temp.c_str()); - } - } - } + ERROR_LOG(VIDEO, "%s shader uid mismatch! See %s for details", shader_type, temp.c_str()); + } + } + } private: - std::map m_shaders; - std::vector m_uids; + std::map m_shaders; + std::vector m_uids; }; -template -inline void DefineOutputMember(T& object, API_TYPE api_type, const char* qualifier, const char* type, const char* name, int var_index, const char* semantic = "", int semantic_index = -1) +template +inline void DefineOutputMember(T& object, API_TYPE api_type, const char* qualifier, + const char* type, const char* name, int var_index, + const char* semantic = "", int semantic_index = -1) { - object.Write("\t%s %s %s", qualifier, type, name); + object.Write("\t%s %s %s", qualifier, type, name); - if (var_index != -1) - object.Write("%d", var_index); + if (var_index != -1) + object.Write("%d", var_index); - if (api_type == API_D3D && strlen(semantic) > 0) - { - if (semantic_index != -1) - object.Write(" : %s%d", semantic, semantic_index); - else - object.Write(" : %s", semantic); - } + if (api_type == API_D3D && strlen(semantic) > 0) + { + if (semantic_index != -1) + object.Write(" : %s%d", semantic, semantic_index); + else + object.Write(" : %s", semantic); + } - object.Write(";\n"); + object.Write(";\n"); } -template +template inline void GenerateVSOutputMembers(T& object, API_TYPE api_type, const char* qualifier) { - DefineOutputMember(object, api_type, qualifier, "float4", "pos", -1, "POSITION"); - DefineOutputMember(object, api_type, qualifier, "float4", "colors_", 0, "COLOR", 0); - DefineOutputMember(object, api_type, qualifier, "float4", "colors_", 1, "COLOR", 1); + DefineOutputMember(object, api_type, qualifier, "float4", "pos", -1, "POSITION"); + DefineOutputMember(object, api_type, qualifier, "float4", "colors_", 0, "COLOR", 0); + DefineOutputMember(object, api_type, qualifier, "float4", "colors_", 1, "COLOR", 1); - for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) - DefineOutputMember(object, api_type, qualifier, "float3", "tex", i, "TEXCOORD", i); + for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) + DefineOutputMember(object, api_type, qualifier, "float3", "tex", i, "TEXCOORD", i); - DefineOutputMember(object, api_type, qualifier, "float4", "clipPos", -1, "TEXCOORD", xfmem.numTexGen.numTexGens); + DefineOutputMember(object, api_type, qualifier, "float4", "clipPos", -1, "TEXCOORD", + xfmem.numTexGen.numTexGens); - if (g_ActiveConfig.bEnablePixelLighting) - { - DefineOutputMember(object, api_type, qualifier, "float3", "Normal", -1, "TEXCOORD", xfmem.numTexGen.numTexGens + 1); - DefineOutputMember(object, api_type, qualifier, "float3", "WorldPos", -1, "TEXCOORD", xfmem.numTexGen.numTexGens + 2); - } + if (g_ActiveConfig.bEnablePixelLighting) + { + DefineOutputMember(object, api_type, qualifier, "float3", "Normal", -1, "TEXCOORD", + xfmem.numTexGen.numTexGens + 1); + DefineOutputMember(object, api_type, qualifier, "float3", "WorldPos", -1, "TEXCOORD", + xfmem.numTexGen.numTexGens + 2); + } } -template +template inline void AssignVSOutputMembers(T& object, const char* a, const char* b) { - object.Write("\t%s.pos = %s.pos;\n", a, b); - object.Write("\t%s.colors_0 = %s.colors_0;\n", a, b); - object.Write("\t%s.colors_1 = %s.colors_1;\n", a, b); + object.Write("\t%s.pos = %s.pos;\n", a, b); + object.Write("\t%s.colors_0 = %s.colors_0;\n", a, b); + object.Write("\t%s.colors_1 = %s.colors_1;\n", a, b); - for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) - object.Write("\t%s.tex%d = %s.tex%d;\n", a, i, b, i); + for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) + object.Write("\t%s.tex%d = %s.tex%d;\n", a, i, b, i); - object.Write("\t%s.clipPos = %s.clipPos;\n", a, b); + object.Write("\t%s.clipPos = %s.clipPos;\n", a, b); - if (g_ActiveConfig.bEnablePixelLighting) - { - object.Write("\t%s.Normal = %s.Normal;\n", a, b); - object.Write("\t%s.WorldPos = %s.WorldPos;\n", a, b); - } + if (g_ActiveConfig.bEnablePixelLighting) + { + object.Write("\t%s.Normal = %s.Normal;\n", a, b); + object.Write("\t%s.WorldPos = %s.WorldPos;\n", a, b); + } } // We use the flag "centroid" to fix some MSAA rendering bugs. With MSAA, the @@ -280,62 +295,61 @@ inline void AssignVSOutputMembers(T& object, const char* a, const char* b) // Without MSAA, this flag is defined to have no effect. inline const char* GetInterpolationQualifier(bool in_glsl_interface_block = false, bool in = false) { - if (g_ActiveConfig.iMultisamples <= 1) - return ""; + if (g_ActiveConfig.iMultisamples <= 1) + return ""; - // Without GL_ARB_shading_language_420pack support, the interpolation qualifier must be - // "centroid in" and not "centroid", even within an interface block. - if (in_glsl_interface_block && !g_ActiveConfig.backend_info.bSupportsBindingLayout) - { - if (!g_ActiveConfig.bSSAA) - return in ? "centroid in" : "centroid out"; - else - return in ? "sample in" : "sample out"; - } - else - { - if (!g_ActiveConfig.bSSAA) - return "centroid"; - else - return "sample"; - } + // Without GL_ARB_shading_language_420pack support, the interpolation qualifier must be + // "centroid in" and not "centroid", even within an interface block. + if (in_glsl_interface_block && !g_ActiveConfig.backend_info.bSupportsBindingLayout) + { + if (!g_ActiveConfig.bSSAA) + return in ? "centroid in" : "centroid out"; + else + return in ? "sample in" : "sample out"; + } + else + { + if (!g_ActiveConfig.bSSAA) + return "centroid"; + else + return "sample"; + } } // Constant variable names -#define I_COLORS "color" -#define I_KCOLORS "k" -#define I_ALPHA "alphaRef" -#define I_TEXDIMS "texdim" -#define I_ZBIAS "czbias" -#define I_INDTEXSCALE "cindscale" -#define I_INDTEXMTX "cindmtx" -#define I_FOGCOLOR "cfogcolor" -#define I_FOGI "cfogi" -#define I_FOGF "cfogf" -#define I_ZSLOPE "czslope" -#define I_EFBSCALE "cefbscale" +#define I_COLORS "color" +#define I_KCOLORS "k" +#define I_ALPHA "alphaRef" +#define I_TEXDIMS "texdim" +#define I_ZBIAS "czbias" +#define I_INDTEXSCALE "cindscale" +#define I_INDTEXMTX "cindmtx" +#define I_FOGCOLOR "cfogcolor" +#define I_FOGI "cfogi" +#define I_FOGF "cfogf" +#define I_ZSLOPE "czslope" +#define I_EFBSCALE "cefbscale" -#define I_POSNORMALMATRIX "cpnmtx" -#define I_PROJECTION "cproj" -#define I_MATERIALS "cmtrl" -#define I_LIGHTS "clights" -#define I_TEXMATRICES "ctexmtx" -#define I_TRANSFORMMATRICES "ctrmtx" -#define I_NORMALMATRICES "cnmtx" +#define I_POSNORMALMATRIX "cpnmtx" +#define I_PROJECTION "cproj" +#define I_MATERIALS "cmtrl" +#define I_LIGHTS "clights" +#define I_TEXMATRICES "ctexmtx" +#define I_TRANSFORMMATRICES "ctrmtx" +#define I_NORMALMATRICES "cnmtx" #define I_POSTTRANSFORMMATRICES "cpostmtx" #define I_PIXELCENTERCORRECTION "cpixelcenter" -#define I_STEREOPARAMS "cstereo" -#define I_LINEPTPARAMS "clinept" -#define I_TEXOFFSET "ctexoffset" +#define I_STEREOPARAMS "cstereo" +#define I_LINEPTPARAMS "clinept" +#define I_TEXOFFSET "ctexoffset" -static const char s_shader_uniforms[] = - "\tfloat4 " I_POSNORMALMATRIX"[6];\n" - "\tfloat4 " I_PROJECTION"[4];\n" - "\tint4 " I_MATERIALS"[4];\n" - "\tLight " I_LIGHTS"[8];\n" - "\tfloat4 " I_TEXMATRICES"[24];\n" - "\tfloat4 " I_TRANSFORMMATRICES"[64];\n" - "\tfloat4 " I_NORMALMATRICES"[32];\n" - "\tfloat4 " I_POSTTRANSFORMMATRICES"[64];\n" - "\tfloat4 " I_PIXELCENTERCORRECTION";\n"; +static const char s_shader_uniforms[] = "\tfloat4 " I_POSNORMALMATRIX "[6];\n" + "\tfloat4 " I_PROJECTION "[4];\n" + "\tint4 " I_MATERIALS "[4];\n" + "\tLight " I_LIGHTS "[8];\n" + "\tfloat4 " I_TEXMATRICES "[24];\n" + "\tfloat4 " I_TRANSFORMMATRICES "[64];\n" + "\tfloat4 " I_NORMALMATRICES "[32];\n" + "\tfloat4 " I_POSTTRANSFORMMATRICES "[64];\n" + "\tfloat4 " I_PIXELCENTERCORRECTION ";\n"; diff --git a/Source/Core/VideoCommon/Statistics.cpp b/Source/Core/VideoCommon/Statistics.cpp index 2a80eb3a69..1cc7d8a7f7 100644 --- a/Source/Core/VideoCommon/Statistics.cpp +++ b/Source/Core/VideoCommon/Statistics.cpp @@ -15,95 +15,103 @@ Statistics stats; void Statistics::ResetFrame() { - memset(&thisFrame, 0, sizeof(ThisFrame)); + memset(&thisFrame, 0, sizeof(ThisFrame)); } void Statistics::SwapDL() { - std::swap(stats.thisFrame.numDLPrims, stats.thisFrame.numPrims); - std::swap(stats.thisFrame.numXFLoadsInDL, stats.thisFrame.numXFLoads); - std::swap(stats.thisFrame.numCPLoadsInDL, stats.thisFrame.numCPLoads); - std::swap(stats.thisFrame.numBPLoadsInDL, stats.thisFrame.numBPLoads); + std::swap(stats.thisFrame.numDLPrims, stats.thisFrame.numPrims); + std::swap(stats.thisFrame.numXFLoadsInDL, stats.thisFrame.numXFLoads); + std::swap(stats.thisFrame.numCPLoadsInDL, stats.thisFrame.numCPLoads); + std::swap(stats.thisFrame.numBPLoadsInDL, stats.thisFrame.numBPLoads); } std::string Statistics::ToString() { - std::string str; + std::string str; - if (g_ActiveConfig.backend_info.APIType == API_TYPE::API_NONE) - { - str += StringFromFormat("Objects: %i\n", stats.thisFrame.numDrawnObjects); - str += StringFromFormat("Vertices Loaded: %i\n", stats.thisFrame.numVerticesLoaded); - str += StringFromFormat("Triangles Input: %i\n", stats.thisFrame.numTrianglesIn); - str += StringFromFormat("Triangles Rejected: %i\n", stats.thisFrame.numTrianglesRejected); - str += StringFromFormat("Triangles Culled: %i\n", stats.thisFrame.numTrianglesCulled); - str += StringFromFormat("Triangles Clipped: %i\n", stats.thisFrame.numTrianglesClipped); - str += StringFromFormat("Triangles Drawn: %i\n", stats.thisFrame.numTrianglesDrawn); - str += StringFromFormat("Rasterized Pix: %i\n", stats.thisFrame.rasterizedPixels); - str += StringFromFormat("TEV Pix In: %i\n", stats.thisFrame.tevPixelsIn); - str += StringFromFormat("TEV Pix Out: %i\n", stats.thisFrame.tevPixelsOut); - } + if (g_ActiveConfig.backend_info.APIType == API_TYPE::API_NONE) + { + str += StringFromFormat("Objects: %i\n", stats.thisFrame.numDrawnObjects); + str += StringFromFormat("Vertices Loaded: %i\n", stats.thisFrame.numVerticesLoaded); + str += StringFromFormat("Triangles Input: %i\n", stats.thisFrame.numTrianglesIn); + str += StringFromFormat("Triangles Rejected: %i\n", stats.thisFrame.numTrianglesRejected); + str += StringFromFormat("Triangles Culled: %i\n", stats.thisFrame.numTrianglesCulled); + str += StringFromFormat("Triangles Clipped: %i\n", stats.thisFrame.numTrianglesClipped); + str += StringFromFormat("Triangles Drawn: %i\n", stats.thisFrame.numTrianglesDrawn); + str += StringFromFormat("Rasterized Pix: %i\n", stats.thisFrame.rasterizedPixels); + str += StringFromFormat("TEV Pix In: %i\n", stats.thisFrame.tevPixelsIn); + str += StringFromFormat("TEV Pix Out: %i\n", stats.thisFrame.tevPixelsOut); + } - str += StringFromFormat("Textures created: %i\n", stats.numTexturesCreated); - str += StringFromFormat("Textures uploaded: %i\n", stats.numTexturesUploaded); - str += StringFromFormat("Textures alive: %i\n", stats.numTexturesAlive); - str += StringFromFormat("pshaders created: %i\n", stats.numPixelShadersCreated); - str += StringFromFormat("pshaders alive: %i\n", stats.numPixelShadersAlive); - str += StringFromFormat("vshaders created: %i\n", stats.numVertexShadersCreated); - str += StringFromFormat("vshaders alive: %i\n", stats.numVertexShadersAlive); - str += StringFromFormat("shaders changes: %i\n", stats.thisFrame.numShaderChanges); - str += StringFromFormat("dlists called: %i\n", stats.thisFrame.numDListsCalled); - str += StringFromFormat("Primitive joins: %i\n", stats.thisFrame.numPrimitiveJoins); - str += StringFromFormat("Draw calls: %i\n", stats.thisFrame.numDrawCalls); - str += StringFromFormat("Primitives: %i\n", stats.thisFrame.numPrims); - str += StringFromFormat("Primitives (DL): %i\n", stats.thisFrame.numDLPrims); - str += StringFromFormat("XF loads: %i\n", stats.thisFrame.numXFLoads); - str += StringFromFormat("XF loads (DL): %i\n", stats.thisFrame.numXFLoadsInDL); - str += StringFromFormat("CP loads: %i\n", stats.thisFrame.numCPLoads); - str += StringFromFormat("CP loads (DL): %i\n", stats.thisFrame.numCPLoadsInDL); - str += StringFromFormat("BP loads: %i\n", stats.thisFrame.numBPLoads); - str += StringFromFormat("BP loads (DL): %i\n", stats.thisFrame.numBPLoadsInDL); - str += StringFromFormat("Vertex streamed: %i kB\n", stats.thisFrame.bytesVertexStreamed / 1024); - str += StringFromFormat("Index streamed: %i kB\n", stats.thisFrame.bytesIndexStreamed / 1024); - str += StringFromFormat("Uniform streamed: %i kB\n", stats.thisFrame.bytesUniformStreamed / 1024); - str += StringFromFormat("Vertex Loaders: %i\n", stats.numVertexLoaders); + str += StringFromFormat("Textures created: %i\n", stats.numTexturesCreated); + str += StringFromFormat("Textures uploaded: %i\n", stats.numTexturesUploaded); + str += StringFromFormat("Textures alive: %i\n", stats.numTexturesAlive); + str += StringFromFormat("pshaders created: %i\n", stats.numPixelShadersCreated); + str += StringFromFormat("pshaders alive: %i\n", stats.numPixelShadersAlive); + str += StringFromFormat("vshaders created: %i\n", stats.numVertexShadersCreated); + str += StringFromFormat("vshaders alive: %i\n", stats.numVertexShadersAlive); + str += StringFromFormat("shaders changes: %i\n", stats.thisFrame.numShaderChanges); + str += StringFromFormat("dlists called: %i\n", stats.thisFrame.numDListsCalled); + str += StringFromFormat("Primitive joins: %i\n", stats.thisFrame.numPrimitiveJoins); + str += StringFromFormat("Draw calls: %i\n", stats.thisFrame.numDrawCalls); + str += StringFromFormat("Primitives: %i\n", stats.thisFrame.numPrims); + str += StringFromFormat("Primitives (DL): %i\n", stats.thisFrame.numDLPrims); + str += StringFromFormat("XF loads: %i\n", stats.thisFrame.numXFLoads); + str += StringFromFormat("XF loads (DL): %i\n", stats.thisFrame.numXFLoadsInDL); + str += StringFromFormat("CP loads: %i\n", stats.thisFrame.numCPLoads); + str += StringFromFormat("CP loads (DL): %i\n", stats.thisFrame.numCPLoadsInDL); + str += StringFromFormat("BP loads: %i\n", stats.thisFrame.numBPLoads); + str += StringFromFormat("BP loads (DL): %i\n", stats.thisFrame.numBPLoadsInDL); + str += StringFromFormat("Vertex streamed: %i kB\n", stats.thisFrame.bytesVertexStreamed / 1024); + str += StringFromFormat("Index streamed: %i kB\n", stats.thisFrame.bytesIndexStreamed / 1024); + str += StringFromFormat("Uniform streamed: %i kB\n", stats.thisFrame.bytesUniformStreamed / 1024); + str += StringFromFormat("Vertex Loaders: %i\n", stats.numVertexLoaders); - std::string vertex_list; - VertexLoaderManager::AppendListToString(&vertex_list); + std::string vertex_list; + VertexLoaderManager::AppendListToString(&vertex_list); - // TODO : at some point text1 just becomes too huge and overflows, we can't even read the added stuff - // since it gets added at the far bottom of the screen anyway (actually outside the rendering window) - // we should really reset the list instead of using substr - if (vertex_list.size() + str.size() > 8170) - vertex_list = vertex_list.substr(0, 8170 - str.size()); + // TODO : at some point text1 just becomes too huge and overflows, we can't even read the added + // stuff + // since it gets added at the far bottom of the screen anyway (actually outside the rendering + // window) + // we should really reset the list instead of using substr + if (vertex_list.size() + str.size() > 8170) + vertex_list = vertex_list.substr(0, 8170 - str.size()); - str += vertex_list; + str += vertex_list; - return str; + return str; } // Is this really needed? std::string Statistics::ToStringProj() { - std::string projections; + std::string projections; - projections += "Projection #: X for Raw 6=0 (X for Raw 6!=0)\n\n"; - projections += StringFromFormat("Projection 0: %f (%f) Raw 0: %f\n", stats.gproj_0, stats.g2proj_0, stats.proj_0); - projections += StringFromFormat("Projection 1: %f (%f)\n", stats.gproj_1, stats.g2proj_1); - projections += StringFromFormat("Projection 2: %f (%f) Raw 1: %f\n", stats.gproj_2, stats.g2proj_2, stats.proj_1); - projections += StringFromFormat("Projection 3: %f (%f)\n\n", stats.gproj_3, stats.g2proj_3); - projections += StringFromFormat("Projection 4: %f (%f)\n", stats.gproj_4, stats.g2proj_4); - projections += StringFromFormat("Projection 5: %f (%f) Raw 2: %f\n", stats.gproj_5, stats.g2proj_5, stats.proj_2); - projections += StringFromFormat("Projection 6: %f (%f) Raw 3: %f\n", stats.gproj_6, stats.g2proj_6, stats.proj_3); - projections += StringFromFormat("Projection 7: %f (%f)\n\n", stats.gproj_7, stats.g2proj_7); - projections += StringFromFormat("Projection 8: %f (%f)\n", stats.gproj_8, stats.g2proj_8); - projections += StringFromFormat("Projection 9: %f (%f)\n", stats.gproj_9, stats.g2proj_9); - projections += StringFromFormat("Projection 10: %f (%f) Raw 4: %f\n\n", stats.gproj_10, stats.g2proj_10, stats.proj_4); - projections += StringFromFormat("Projection 11: %f (%f) Raw 5: %f\n\n", stats.gproj_11, stats.g2proj_11, stats.proj_5); - projections += StringFromFormat("Projection 12: %f (%f)\n", stats.gproj_12, stats.g2proj_12); - projections += StringFromFormat("Projection 13: %f (%f)\n", stats.gproj_13, stats.g2proj_13); - projections += StringFromFormat("Projection 14: %f (%f)\n", stats.gproj_14, stats.g2proj_14); - projections += StringFromFormat("Projection 15: %f (%f)\n", stats.gproj_15, stats.g2proj_15); + projections += "Projection #: X for Raw 6=0 (X for Raw 6!=0)\n\n"; + projections += StringFromFormat("Projection 0: %f (%f) Raw 0: %f\n", stats.gproj_0, + stats.g2proj_0, stats.proj_0); + projections += StringFromFormat("Projection 1: %f (%f)\n", stats.gproj_1, stats.g2proj_1); + projections += StringFromFormat("Projection 2: %f (%f) Raw 1: %f\n", stats.gproj_2, + stats.g2proj_2, stats.proj_1); + projections += StringFromFormat("Projection 3: %f (%f)\n\n", stats.gproj_3, stats.g2proj_3); + projections += StringFromFormat("Projection 4: %f (%f)\n", stats.gproj_4, stats.g2proj_4); + projections += StringFromFormat("Projection 5: %f (%f) Raw 2: %f\n", stats.gproj_5, + stats.g2proj_5, stats.proj_2); + projections += StringFromFormat("Projection 6: %f (%f) Raw 3: %f\n", stats.gproj_6, + stats.g2proj_6, stats.proj_3); + projections += StringFromFormat("Projection 7: %f (%f)\n\n", stats.gproj_7, stats.g2proj_7); + projections += StringFromFormat("Projection 8: %f (%f)\n", stats.gproj_8, stats.g2proj_8); + projections += StringFromFormat("Projection 9: %f (%f)\n", stats.gproj_9, stats.g2proj_9); + projections += StringFromFormat("Projection 10: %f (%f) Raw 4: %f\n\n", stats.gproj_10, + stats.g2proj_10, stats.proj_4); + projections += StringFromFormat("Projection 11: %f (%f) Raw 5: %f\n\n", stats.gproj_11, + stats.g2proj_11, stats.proj_5); + projections += StringFromFormat("Projection 12: %f (%f)\n", stats.gproj_12, stats.g2proj_12); + projections += StringFromFormat("Projection 13: %f (%f)\n", stats.gproj_13, stats.g2proj_13); + projections += StringFromFormat("Projection 14: %f (%f)\n", stats.gproj_14, stats.g2proj_14); + projections += StringFromFormat("Projection 15: %f (%f)\n", stats.gproj_15, stats.g2proj_15); - return projections; + return projections; } diff --git a/Source/Core/VideoCommon/Statistics.h b/Source/Core/VideoCommon/Statistics.h index df6b1a2a48..74ee317b82 100644 --- a/Source/Core/VideoCommon/Statistics.h +++ b/Source/Core/VideoCommon/Statistics.h @@ -8,64 +8,66 @@ struct Statistics { - int numPixelShadersCreated; - int numPixelShadersAlive; - int numVertexShadersCreated; - int numVertexShadersAlive; + int numPixelShadersCreated; + int numPixelShadersAlive; + int numVertexShadersCreated; + int numVertexShadersAlive; - int numTexturesCreated; - int numTexturesUploaded; - int numTexturesAlive; + int numTexturesCreated; + int numTexturesUploaded; + int numTexturesAlive; - int numVertexLoaders; + int numVertexLoaders; - float proj_0, proj_1, proj_2, proj_3, proj_4, proj_5; - float gproj_0, gproj_1, gproj_2, gproj_3, gproj_4, gproj_5; - float gproj_6, gproj_7, gproj_8, gproj_9, gproj_10, gproj_11, gproj_12, gproj_13, gproj_14, gproj_15; + float proj_0, proj_1, proj_2, proj_3, proj_4, proj_5; + float gproj_0, gproj_1, gproj_2, gproj_3, gproj_4, gproj_5; + float gproj_6, gproj_7, gproj_8, gproj_9, gproj_10, gproj_11, gproj_12, gproj_13, gproj_14, + gproj_15; - float g2proj_0, g2proj_1, g2proj_2, g2proj_3, g2proj_4, g2proj_5; - float g2proj_6, g2proj_7, g2proj_8, g2proj_9, g2proj_10, g2proj_11, g2proj_12, g2proj_13, g2proj_14, g2proj_15; + float g2proj_0, g2proj_1, g2proj_2, g2proj_3, g2proj_4, g2proj_5; + float g2proj_6, g2proj_7, g2proj_8, g2proj_9, g2proj_10, g2proj_11, g2proj_12, g2proj_13, + g2proj_14, g2proj_15; - struct ThisFrame - { - int numBPLoads; - int numCPLoads; - int numXFLoads; + struct ThisFrame + { + int numBPLoads; + int numCPLoads; + int numXFLoads; - int numBPLoadsInDL; - int numCPLoadsInDL; - int numXFLoadsInDL; + int numBPLoadsInDL; + int numCPLoadsInDL; + int numXFLoadsInDL; - int numPrims; - int numDLPrims; - int numShaderChanges; + int numPrims; + int numDLPrims; + int numShaderChanges; - int numPrimitiveJoins; - int numDrawCalls; + int numPrimitiveJoins; + int numDrawCalls; - int numDListsCalled; + int numDListsCalled; - int bytesVertexStreamed; - int bytesIndexStreamed; - int bytesUniformStreamed; + int bytesVertexStreamed; + int bytesIndexStreamed; + int bytesUniformStreamed; - int numTrianglesClipped; - int numTrianglesIn; - int numTrianglesRejected; - int numTrianglesCulled; - int numDrawnObjects; - int rasterizedPixels; - int numTrianglesDrawn; - int numVerticesLoaded; - int tevPixelsIn; - int tevPixelsOut; - }; - ThisFrame thisFrame; - void ResetFrame(); - static void SwapDL(); + int numTrianglesClipped; + int numTrianglesIn; + int numTrianglesRejected; + int numTrianglesCulled; + int numDrawnObjects; + int rasterizedPixels; + int numTrianglesDrawn; + int numVerticesLoaded; + int tevPixelsIn; + int tevPixelsOut; + }; + ThisFrame thisFrame; + void ResetFrame(); + static void SwapDL(); - static std::string ToString(); - static std::string ToStringProj(); + static std::string ToString(); + static std::string ToStringProj(); }; extern Statistics stats; @@ -75,12 +77,12 @@ extern Statistics stats; #ifdef STATISTICS #define INCSTAT(a) (a)++; #define DECSTAT(a) (a)--; -#define ADDSTAT(a,b) (a)+=(b); -#define SETSTAT(a,x) (a)=(int)(x); -#define SETSTAT_UINT(a,x) (a)=(u32)(x); -#define SETSTAT_FT(a,x) (a)=(float)(x); +#define ADDSTAT(a, b) (a) += (b); +#define SETSTAT(a, x) (a) = (int)(x); +#define SETSTAT_UINT(a, x) (a) = (u32)(x); +#define SETSTAT_FT(a, x) (a) = (float)(x); #else #define INCSTAT(a) ; -#define ADDSTAT(a,b) ; -#define SETSTAT(a,x) ; +#define ADDSTAT(a, b) ; +#define SETSTAT(a, x) ; #endif diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 7d77f48392..94095ecf95 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -12,9 +12,9 @@ #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/Hash.h" +#include "Common/Logging/Log.h" #include "Common/MemoryUtil.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "Core/ConfigManager.h" #include "Core/FifoPlayer/FifoPlayer.h" @@ -34,10 +34,12 @@ #include "VideoCommon/VideoConfig.h" static const u64 TEXHASH_INVALID = 0; -static const int TEXTURE_KILL_THRESHOLD = 64; // Sonic the Fighters (inside Sonic Gems Collection) loops a 64 frames animation +static const int TEXTURE_KILL_THRESHOLD = + 64; // Sonic the Fighters (inside Sonic Gems Collection) loops a 64 frames animation static const int TEXTURE_POOL_KILL_THRESHOLD = 3; static const int FRAMECOUNT_INVALID = 0; -static const u64 MAX_TEXTURE_BINARY_SIZE = 1024 * 1024 * 4; // 1024 x 1024 texel times 8 nibbles per texel +static const u64 MAX_TEXTURE_BINARY_SIZE = + 1024 * 1024 * 4; // 1024 x 1024 texel times 8 nibbles per texel std::unique_ptr g_texture_cache; @@ -57,1348 +59,1421 @@ TextureCacheBase::TCacheEntryBase::~TCacheEntryBase() void TextureCacheBase::CheckTempSize(size_t required_size) { - if (required_size <= temp_size) - return; + if (required_size <= temp_size) + return; - temp_size = required_size; - FreeAlignedMemory(temp); - temp = (u8*)AllocateAlignedMemory(temp_size, 16); + temp_size = required_size; + FreeAlignedMemory(temp); + temp = (u8*)AllocateAlignedMemory(temp_size, 16); } TextureCacheBase::TextureCacheBase() { - temp_size = 2048 * 2048 * 4; - if (!temp) - temp = (u8*)AllocateAlignedMemory(temp_size, 16); + temp_size = 2048 * 2048 * 4; + if (!temp) + temp = (u8*)AllocateAlignedMemory(temp_size, 16); - TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter); + TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, + g_ActiveConfig.bTexFmtOverlayCenter); - HiresTexture::Init(); + HiresTexture::Init(); - SetHash64Function(); + SetHash64Function(); } void TextureCacheBase::Invalidate() { - UnbindTextures(); + UnbindTextures(); - for (auto& tex : textures_by_address) - { - delete tex.second; - } - textures_by_address.clear(); - textures_by_hash.clear(); + for (auto& tex : textures_by_address) + { + delete tex.second; + } + textures_by_address.clear(); + textures_by_hash.clear(); - for (auto& rt : texture_pool) - { - delete rt.second; - } - texture_pool.clear(); + for (auto& rt : texture_pool) + { + delete rt.second; + } + texture_pool.clear(); } TextureCacheBase::~TextureCacheBase() { - HiresTexture::Shutdown(); - Invalidate(); - FreeAlignedMemory(temp); - temp = nullptr; + HiresTexture::Shutdown(); + Invalidate(); + FreeAlignedMemory(temp); + temp = nullptr; } void TextureCacheBase::OnConfigChanged(VideoConfig& config) { - if (g_texture_cache) - { - if (config.bHiresTextures != backup_config.s_hires_textures || - config.bCacheHiresTextures != backup_config.s_cache_hires_textures) - { - HiresTexture::Update(); - } + if (g_texture_cache) + { + if (config.bHiresTextures != backup_config.s_hires_textures || + config.bCacheHiresTextures != backup_config.s_cache_hires_textures) + { + HiresTexture::Update(); + } - // TODO: Invalidating texcache is really stupid in some of these cases - if (config.iSafeTextureCache_ColorSamples != backup_config.s_colorsamples || - config.bTexFmtOverlayEnable != backup_config.s_texfmt_overlay || - config.bTexFmtOverlayCenter != backup_config.s_texfmt_overlay_center || - config.bHiresTextures != backup_config.s_hires_textures) - { - g_texture_cache->Invalidate(); + // TODO: Invalidating texcache is really stupid in some of these cases + if (config.iSafeTextureCache_ColorSamples != backup_config.s_colorsamples || + config.bTexFmtOverlayEnable != backup_config.s_texfmt_overlay || + config.bTexFmtOverlayCenter != backup_config.s_texfmt_overlay_center || + config.bHiresTextures != backup_config.s_hires_textures) + { + g_texture_cache->Invalidate(); - TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter); - } + TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, + g_ActiveConfig.bTexFmtOverlayCenter); + } - if ((config.iStereoMode > 0) != backup_config.s_stereo_3d || - config.bStereoEFBMonoDepth != backup_config.s_efb_mono_depth) - { - g_texture_cache->DeleteShaders(); - g_texture_cache->CompileShaders(); - } - } + if ((config.iStereoMode > 0) != backup_config.s_stereo_3d || + config.bStereoEFBMonoDepth != backup_config.s_efb_mono_depth) + { + g_texture_cache->DeleteShaders(); + g_texture_cache->CompileShaders(); + } + } - backup_config.s_colorsamples = config.iSafeTextureCache_ColorSamples; - backup_config.s_texfmt_overlay = config.bTexFmtOverlayEnable; - backup_config.s_texfmt_overlay_center = config.bTexFmtOverlayCenter; - backup_config.s_hires_textures = config.bHiresTextures; - backup_config.s_cache_hires_textures = config.bCacheHiresTextures; - backup_config.s_stereo_3d = config.iStereoMode > 0; - backup_config.s_efb_mono_depth = config.bStereoEFBMonoDepth; + backup_config.s_colorsamples = config.iSafeTextureCache_ColorSamples; + backup_config.s_texfmt_overlay = config.bTexFmtOverlayEnable; + backup_config.s_texfmt_overlay_center = config.bTexFmtOverlayCenter; + backup_config.s_hires_textures = config.bHiresTextures; + backup_config.s_cache_hires_textures = config.bCacheHiresTextures; + backup_config.s_stereo_3d = config.iStereoMode > 0; + backup_config.s_efb_mono_depth = config.bStereoEFBMonoDepth; } void TextureCacheBase::Cleanup(int _frameCount) { - TexCache::iterator iter = textures_by_address.begin(); - TexCache::iterator tcend = textures_by_address.end(); - while (iter != tcend) - { - if (iter->second->frameCount == FRAMECOUNT_INVALID) - { - iter->second->frameCount = _frameCount; - ++iter; - } - else if (_frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount) - { - if (iter->second->IsEfbCopy()) - { - // Only remove EFB copies when they wouldn't be used anymore(changed hash), because EFB copies living on the - // host GPU are unrecoverable. Perform this check only every TEXTURE_KILL_THRESHOLD for performance reasons - if ((_frameCount - iter->second->frameCount) % TEXTURE_KILL_THRESHOLD == 1 && - iter->second->hash != iter->second->CalculateHash()) - { - iter = InvalidateTexture(iter); - } - else - { - ++iter; - } - } - else - { - iter = InvalidateTexture(iter); - } - } - else - { - ++iter; - } - } + TexCache::iterator iter = textures_by_address.begin(); + TexCache::iterator tcend = textures_by_address.end(); + while (iter != tcend) + { + if (iter->second->frameCount == FRAMECOUNT_INVALID) + { + iter->second->frameCount = _frameCount; + ++iter; + } + else if (_frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount) + { + if (iter->second->IsEfbCopy()) + { + // Only remove EFB copies when they wouldn't be used anymore(changed hash), because EFB + // copies living on the + // host GPU are unrecoverable. Perform this check only every TEXTURE_KILL_THRESHOLD for + // performance reasons + if ((_frameCount - iter->second->frameCount) % TEXTURE_KILL_THRESHOLD == 1 && + iter->second->hash != iter->second->CalculateHash()) + { + iter = InvalidateTexture(iter); + } + else + { + ++iter; + } + } + else + { + iter = InvalidateTexture(iter); + } + } + else + { + ++iter; + } + } - TexPool::iterator iter2 = texture_pool.begin(); - TexPool::iterator tcend2 = texture_pool.end(); - while (iter2 != tcend2) - { - if (iter2->second->frameCount == FRAMECOUNT_INVALID) - { - iter2->second->frameCount = _frameCount; - } - if (_frameCount > TEXTURE_POOL_KILL_THRESHOLD + iter2->second->frameCount) - { - delete iter2->second; - iter2 = texture_pool.erase(iter2); - } - else - { - ++iter2; - } - } + TexPool::iterator iter2 = texture_pool.begin(); + TexPool::iterator tcend2 = texture_pool.end(); + while (iter2 != tcend2) + { + if (iter2->second->frameCount == FRAMECOUNT_INVALID) + { + iter2->second->frameCount = _frameCount; + } + if (_frameCount > TEXTURE_POOL_KILL_THRESHOLD + iter2->second->frameCount) + { + delete iter2->second; + iter2 = texture_pool.erase(iter2); + } + else + { + ++iter2; + } + } } bool TextureCacheBase::TCacheEntryBase::OverlapsMemoryRange(u32 range_address, u32 range_size) const { - if (addr + size_in_bytes <= range_address) - return false; + if (addr + size_in_bytes <= range_address) + return false; - if (addr >= range_address + range_size) - return false; + if (addr >= range_address + range_size) + return false; - return true; + return true; } -TextureCacheBase::TCacheEntryBase* TextureCacheBase::TCacheEntryBase::ApplyPalette(u8* palette, u32 tlutfmt) +TextureCacheBase::TCacheEntryBase* TextureCacheBase::TCacheEntryBase::ApplyPalette(u8* palette, + u32 tlutfmt) { - TCacheEntryConfig newconfig; - newconfig.rendertarget = true; - newconfig.width = config.width; - newconfig.height = config.height; - newconfig.layers = config.layers; - TCacheEntryBase *decoded_entry = AllocateTexture(newconfig); + TCacheEntryConfig newconfig; + newconfig.rendertarget = true; + newconfig.width = config.width; + newconfig.height = config.height; + newconfig.layers = config.layers; + TCacheEntryBase* decoded_entry = AllocateTexture(newconfig); - if (decoded_entry) - { - decoded_entry->SetGeneralParameters(addr, size_in_bytes, format); - decoded_entry->SetDimensions(native_width, native_height, 1); - decoded_entry->SetHashes(base_hash, hash); - decoded_entry->frameCount = FRAMECOUNT_INVALID; - decoded_entry->is_efb_copy = false; + if (decoded_entry) + { + decoded_entry->SetGeneralParameters(addr, size_in_bytes, format); + decoded_entry->SetDimensions(native_width, native_height, 1); + decoded_entry->SetHashes(base_hash, hash); + decoded_entry->frameCount = FRAMECOUNT_INVALID; + decoded_entry->is_efb_copy = false; - g_texture_cache->ConvertTexture(decoded_entry, this, palette, static_cast(tlutfmt)); - textures_by_address.emplace(addr, decoded_entry); + g_texture_cache->ConvertTexture(decoded_entry, this, palette, static_cast(tlutfmt)); + textures_by_address.emplace(addr, decoded_entry); - return decoded_entry; - } + return decoded_entry; + } - return nullptr; + return nullptr; } -void TextureCacheBase::ScaleTextureCacheEntryTo(TextureCacheBase::TCacheEntryBase** entry, u32 new_width, u32 new_height) +void TextureCacheBase::ScaleTextureCacheEntryTo(TextureCacheBase::TCacheEntryBase** entry, + u32 new_width, u32 new_height) { - if ((*entry)->config.width == new_width && (*entry)->config.height == new_height) - { - return; - } + if ((*entry)->config.width == new_width && (*entry)->config.height == new_height) + { + return; + } - u32 max = g_renderer->GetMaxTextureSize(); - if (max < new_width || max < new_height) - { - ERROR_LOG(VIDEO, "Texture too big, width = %d, height = %d", new_width, new_height); - return; - } + u32 max = g_renderer->GetMaxTextureSize(); + if (max < new_width || max < new_height) + { + ERROR_LOG(VIDEO, "Texture too big, width = %d, height = %d", new_width, new_height); + return; + } - TextureCacheBase::TCacheEntryConfig newconfig; - newconfig.width = new_width; - newconfig.height = new_height; - newconfig.layers = (*entry)->config.layers; - newconfig.rendertarget = true; + TextureCacheBase::TCacheEntryConfig newconfig; + newconfig.width = new_width; + newconfig.height = new_height; + newconfig.layers = (*entry)->config.layers; + newconfig.rendertarget = true; - TCacheEntryBase* newentry = AllocateTexture(newconfig); - if (newentry) - { - newentry->SetGeneralParameters((*entry)->addr, (*entry)->size_in_bytes, (*entry)->format); - newentry->SetDimensions((*entry)->native_width, (*entry)->native_height, 1); - newentry->SetHashes((*entry)->base_hash, (*entry)->hash); - newentry->frameCount = frameCount; - newentry->is_efb_copy = (*entry)->is_efb_copy; - MathUtil::Rectangle srcrect, dstrect; - srcrect.left = 0; - srcrect.top = 0; - srcrect.right = (*entry)->config.width; - srcrect.bottom = (*entry)->config.height; - dstrect.left = 0; - dstrect.top = 0; - dstrect.right = new_width; - dstrect.bottom = new_height; - newentry->CopyRectangleFromTexture(*entry, srcrect, dstrect); + TCacheEntryBase* newentry = AllocateTexture(newconfig); + if (newentry) + { + newentry->SetGeneralParameters((*entry)->addr, (*entry)->size_in_bytes, (*entry)->format); + newentry->SetDimensions((*entry)->native_width, (*entry)->native_height, 1); + newentry->SetHashes((*entry)->base_hash, (*entry)->hash); + newentry->frameCount = frameCount; + newentry->is_efb_copy = (*entry)->is_efb_copy; + MathUtil::Rectangle srcrect, dstrect; + srcrect.left = 0; + srcrect.top = 0; + srcrect.right = (*entry)->config.width; + srcrect.bottom = (*entry)->config.height; + dstrect.left = 0; + dstrect.top = 0; + dstrect.right = new_width; + dstrect.bottom = new_height; + newentry->CopyRectangleFromTexture(*entry, srcrect, dstrect); - // Keep track of the pointer for textures_by_hash - if ((*entry)->textures_by_hash_iter != textures_by_hash.end()) - { - newentry->textures_by_hash_iter = textures_by_hash.emplace((*entry)->hash, newentry); - } + // Keep track of the pointer for textures_by_hash + if ((*entry)->textures_by_hash_iter != textures_by_hash.end()) + { + newentry->textures_by_hash_iter = textures_by_hash.emplace((*entry)->hash, newentry); + } - InvalidateTexture(GetTexCacheIter(*entry)); + InvalidateTexture(GetTexCacheIter(*entry)); - *entry = newentry; - textures_by_address.emplace((*entry)->addr, *entry); - } - else - { - ERROR_LOG(VIDEO, "Scaling failed"); - } + *entry = newentry; + textures_by_address.emplace((*entry)->addr, *entry); + } + else + { + ERROR_LOG(VIDEO, "Scaling failed"); + } } -TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(TexCache::iterator iter_t, u8* palette, u32 tlutfmt) +TextureCacheBase::TCacheEntryBase* +TextureCacheBase::DoPartialTextureUpdates(TexCache::iterator iter_t, u8* palette, u32 tlutfmt) { - TCacheEntryBase* entry_to_update = iter_t->second; - const bool isPaletteTexture = (entry_to_update->format == GX_TF_C4 - || entry_to_update->format == GX_TF_C8 - || entry_to_update->format == GX_TF_C14X2 - || entry_to_update->format >= 0x10000); + TCacheEntryBase* entry_to_update = iter_t->second; + const bool isPaletteTexture = + (entry_to_update->format == GX_TF_C4 || entry_to_update->format == GX_TF_C8 || + entry_to_update->format == GX_TF_C14X2 || entry_to_update->format >= 0x10000); - // EFB copies are excluded from these updates, until there's an example where a game would - // benefit from updating. This would require more work to be done. - if (entry_to_update->IsEfbCopy()) - return entry_to_update; + // EFB copies are excluded from these updates, until there's an example where a game would + // benefit from updating. This would require more work to be done. + if (entry_to_update->IsEfbCopy()) + return entry_to_update; - u32 block_width = TexDecoder_GetBlockWidthInTexels(entry_to_update->format & 0xf); - u32 block_height = TexDecoder_GetBlockHeightInTexels(entry_to_update->format & 0xf); - u32 block_size = block_width * block_height * TexDecoder_GetTexelSizeInNibbles(entry_to_update->format & 0xf) / 2; + u32 block_width = TexDecoder_GetBlockWidthInTexels(entry_to_update->format & 0xf); + u32 block_height = TexDecoder_GetBlockHeightInTexels(entry_to_update->format & 0xf); + u32 block_size = block_width * block_height * + TexDecoder_GetTexelSizeInNibbles(entry_to_update->format & 0xf) / 2; - u32 numBlocksX = (entry_to_update->native_width + block_width - 1) / block_width; + u32 numBlocksX = (entry_to_update->native_width + block_width - 1) / block_width; - TexCache::iterator iter = textures_by_address.lower_bound(entry_to_update->addr > MAX_TEXTURE_BINARY_SIZE ? entry_to_update->addr - MAX_TEXTURE_BINARY_SIZE : 0); - TexCache::iterator iterend = textures_by_address.upper_bound(entry_to_update->addr + entry_to_update->size_in_bytes); - while (iter != iterend) - { - TCacheEntryBase* entry = iter->second; - if (entry != entry_to_update - && entry->IsEfbCopy() - && entry->references.count(entry_to_update) == 0 - && entry->OverlapsMemoryRange(entry_to_update->addr, entry_to_update->size_in_bytes) - && entry->memory_stride == numBlocksX * block_size) - { - if (entry->hash == entry->CalculateHash()) - { - if (isPaletteTexture) - { - TCacheEntryBase *decoded_entry = entry->ApplyPalette(palette, tlutfmt); - if (decoded_entry) - { - // Link the efb copy with the partially updated texture, so we won't apply this partial update again - entry->CreateReference(entry_to_update); - // Mark the texture update as used, as if it was loaded directly - entry->frameCount = FRAMECOUNT_INVALID; - entry = decoded_entry; - } - else - { - ++iter; - continue; - } - } + TexCache::iterator iter = + textures_by_address.lower_bound(entry_to_update->addr > MAX_TEXTURE_BINARY_SIZE ? + entry_to_update->addr - MAX_TEXTURE_BINARY_SIZE : + 0); + TexCache::iterator iterend = + textures_by_address.upper_bound(entry_to_update->addr + entry_to_update->size_in_bytes); + while (iter != iterend) + { + TCacheEntryBase* entry = iter->second; + if (entry != entry_to_update && entry->IsEfbCopy() && + entry->references.count(entry_to_update) == 0 && + entry->OverlapsMemoryRange(entry_to_update->addr, entry_to_update->size_in_bytes) && + entry->memory_stride == numBlocksX * block_size) + { + if (entry->hash == entry->CalculateHash()) + { + if (isPaletteTexture) + { + TCacheEntryBase* decoded_entry = entry->ApplyPalette(palette, tlutfmt); + if (decoded_entry) + { + // Link the efb copy with the partially updated texture, so we won't apply this partial + // update again + entry->CreateReference(entry_to_update); + // Mark the texture update as used, as if it was loaded directly + entry->frameCount = FRAMECOUNT_INVALID; + entry = decoded_entry; + } + else + { + ++iter; + continue; + } + } - u32 src_x, src_y, dst_x, dst_y; + u32 src_x, src_y, dst_x, dst_y; - // Note for understanding the math: - // Normal textures can't be strided, so the 2 missing cases with src_x > 0 don't exist - if (entry->addr >= entry_to_update->addr) - { - u32 block_offset = (entry->addr - entry_to_update->addr) / block_size; - u32 block_x = block_offset % numBlocksX; - u32 block_y = block_offset / numBlocksX; - src_x = 0; - src_y = 0; - dst_x = block_x * block_width; - dst_y = block_y * block_height; - } - else - { - u32 block_offset = (entry_to_update->addr - entry->addr) / block_size; - u32 block_x = (~block_offset + 1) % numBlocksX; - u32 block_y = (block_offset + block_x) / numBlocksX; - src_x = 0; - src_y = block_y * block_height; - dst_x = block_x * block_width; - dst_y = 0; - } + // Note for understanding the math: + // Normal textures can't be strided, so the 2 missing cases with src_x > 0 don't exist + if (entry->addr >= entry_to_update->addr) + { + u32 block_offset = (entry->addr - entry_to_update->addr) / block_size; + u32 block_x = block_offset % numBlocksX; + u32 block_y = block_offset / numBlocksX; + src_x = 0; + src_y = 0; + dst_x = block_x * block_width; + dst_y = block_y * block_height; + } + else + { + u32 block_offset = (entry_to_update->addr - entry->addr) / block_size; + u32 block_x = (~block_offset + 1) % numBlocksX; + u32 block_y = (block_offset + block_x) / numBlocksX; + src_x = 0; + src_y = block_y * block_height; + dst_x = block_x * block_width; + dst_y = 0; + } - u32 copy_width = std::min(entry->native_width - src_x, entry_to_update->native_width - dst_x); - u32 copy_height = std::min(entry->native_height - src_y, entry_to_update->native_height - dst_y); + u32 copy_width = + std::min(entry->native_width - src_x, entry_to_update->native_width - dst_x); + u32 copy_height = + std::min(entry->native_height - src_y, entry_to_update->native_height - dst_y); - // If one of the textures is scaled, scale both with the current efb scaling factor - if (entry_to_update->native_width != entry_to_update->config.width - || entry_to_update->native_height != entry_to_update->config.height - || entry->native_width != entry->config.width || entry->native_height != entry->config.height) - { - ScaleTextureCacheEntryTo(&entry_to_update, Renderer::EFBToScaledX(entry_to_update->native_width), Renderer::EFBToScaledY(entry_to_update->native_height)); - ScaleTextureCacheEntryTo(&entry, Renderer::EFBToScaledX(entry->native_width), Renderer::EFBToScaledY(entry->native_height)); + // If one of the textures is scaled, scale both with the current efb scaling factor + if (entry_to_update->native_width != entry_to_update->config.width || + entry_to_update->native_height != entry_to_update->config.height || + entry->native_width != entry->config.width || + entry->native_height != entry->config.height) + { + ScaleTextureCacheEntryTo(&entry_to_update, + Renderer::EFBToScaledX(entry_to_update->native_width), + Renderer::EFBToScaledY(entry_to_update->native_height)); + ScaleTextureCacheEntryTo(&entry, Renderer::EFBToScaledX(entry->native_width), + Renderer::EFBToScaledY(entry->native_height)); - src_x = Renderer::EFBToScaledX(src_x); - src_y = Renderer::EFBToScaledY(src_y); - dst_x = Renderer::EFBToScaledX(dst_x); - dst_y = Renderer::EFBToScaledY(dst_y); - copy_width = Renderer::EFBToScaledX(copy_width); - copy_height = Renderer::EFBToScaledY(copy_height); - } + src_x = Renderer::EFBToScaledX(src_x); + src_y = Renderer::EFBToScaledY(src_y); + dst_x = Renderer::EFBToScaledX(dst_x); + dst_y = Renderer::EFBToScaledY(dst_y); + copy_width = Renderer::EFBToScaledX(copy_width); + copy_height = Renderer::EFBToScaledY(copy_height); + } - MathUtil::Rectangle srcrect, dstrect; - srcrect.left = src_x; - srcrect.top = src_y; - srcrect.right = (src_x + copy_width); - srcrect.bottom = (src_y + copy_height); - dstrect.left = dst_x; - dstrect.top = dst_y; - dstrect.right = (dst_x + copy_width); - dstrect.bottom = (dst_y + copy_height); - entry_to_update->CopyRectangleFromTexture(entry, srcrect, dstrect); + MathUtil::Rectangle srcrect, dstrect; + srcrect.left = src_x; + srcrect.top = src_y; + srcrect.right = (src_x + copy_width); + srcrect.bottom = (src_y + copy_height); + dstrect.left = dst_x; + dstrect.top = dst_y; + dstrect.right = (dst_x + copy_width); + dstrect.bottom = (dst_y + copy_height); + entry_to_update->CopyRectangleFromTexture(entry, srcrect, dstrect); - - if (isPaletteTexture) - { - // Remove the temporary converted texture, it won't be used anywhere else - // TODO: It would be nice to convert and copy in one step, but this code path isn't common - InvalidateTexture(GetTexCacheIter(entry)); - } - else - { - // Link the two textures together, so we won't apply this partial update again - entry->CreateReference(entry_to_update); - // Mark the texture update as used, as if it was loaded directly - entry->frameCount = FRAMECOUNT_INVALID; - } - } - else - { - // If the hash does not match, this EFB copy will not be used for anything, so remove it - iter = InvalidateTexture(iter); - continue; - } - } - ++iter; - } - return entry_to_update; + if (isPaletteTexture) + { + // Remove the temporary converted texture, it won't be used anywhere else + // TODO: It would be nice to convert and copy in one step, but this code path isn't common + InvalidateTexture(GetTexCacheIter(entry)); + } + else + { + // Link the two textures together, so we won't apply this partial update again + entry->CreateReference(entry_to_update); + // Mark the texture update as used, as if it was loaded directly + entry->frameCount = FRAMECOUNT_INVALID; + } + } + else + { + // If the hash does not match, this EFB copy will not be used for anything, so remove it + iter = InvalidateTexture(iter); + continue; + } + } + ++iter; + } + return entry_to_update; } void TextureCacheBase::DumpTexture(TCacheEntryBase* entry, std::string basename, unsigned int level) { - std::string szDir = File::GetUserPath(D_DUMPTEXTURES_IDX) + - SConfig::GetInstance().m_strUniqueID; + std::string szDir = File::GetUserPath(D_DUMPTEXTURES_IDX) + SConfig::GetInstance().m_strUniqueID; - // make sure that the directory exists - if (!File::Exists(szDir) || !File::IsDirectory(szDir)) - File::CreateDir(szDir); + // make sure that the directory exists + if (!File::Exists(szDir) || !File::IsDirectory(szDir)) + File::CreateDir(szDir); - if (level > 0) - { - basename += StringFromFormat("_mip%i", level); - } - std::string filename = szDir + "/" + basename + ".png"; + if (level > 0) + { + basename += StringFromFormat("_mip%i", level); + } + std::string filename = szDir + "/" + basename + ".png"; - if (!File::Exists(filename)) - entry->Save(filename, level); + if (!File::Exists(filename)) + entry->Save(filename, level); } static u32 CalculateLevelSize(u32 level_0_size, u32 level) { - return std::max(level_0_size >> level, 1u); + return std::max(level_0_size >> level, 1u); } // Used by TextureCacheBase::Load -TextureCacheBase::TCacheEntryBase* TextureCacheBase::ReturnEntry(unsigned int stage, TCacheEntryBase* entry) +TextureCacheBase::TCacheEntryBase* TextureCacheBase::ReturnEntry(unsigned int stage, + TCacheEntryBase* entry) { - entry->frameCount = FRAMECOUNT_INVALID; - bound_textures[stage] = entry; + entry->frameCount = FRAMECOUNT_INVALID; + bound_textures[stage] = entry; - GFX_DEBUGGER_PAUSE_AT(NEXT_TEXTURE_CHANGE, true); + GFX_DEBUGGER_PAUSE_AT(NEXT_TEXTURE_CHANGE, true); - return entry; + return entry; } void TextureCacheBase::BindTextures() { - for (int i = 0; i < 8; ++i) - { - if (bound_textures[i]) - bound_textures[i]->Bind(i); - } + for (int i = 0; i < 8; ++i) + { + if (bound_textures[i]) + bound_textures[i]->Bind(i); + } } void TextureCacheBase::UnbindTextures() { - std::fill(std::begin(bound_textures), std::end(bound_textures), nullptr); + std::fill(std::begin(bound_textures), std::end(bound_textures), nullptr); } TextureCacheBase::TCacheEntryBase* TextureCacheBase::Load(const u32 stage) { - const FourTexUnits &tex = bpmem.tex[stage >> 2]; - const u32 id = stage & 3; - const u32 address = (tex.texImage3[id].image_base/* & 0x1FFFFF*/) << 5; - u32 width = tex.texImage0[id].width + 1; - u32 height = tex.texImage0[id].height + 1; - const int texformat = tex.texImage0[id].format; - const u32 tlutaddr = tex.texTlut[id].tmem_offset << 9; - const u32 tlutfmt = tex.texTlut[id].tlut_format; - const bool use_mipmaps = SamplerCommon::AreBpTexMode0MipmapsEnabled(tex.texMode0[id]); - u32 tex_levels = use_mipmaps ? ((tex.texMode1[id].max_lod + 0xf) / 0x10 + 1) : 1; - const bool from_tmem = tex.texImage1[id].image_type != 0; + const FourTexUnits& tex = bpmem.tex[stage >> 2]; + const u32 id = stage & 3; + const u32 address = (tex.texImage3[id].image_base /* & 0x1FFFFF*/) << 5; + u32 width = tex.texImage0[id].width + 1; + u32 height = tex.texImage0[id].height + 1; + const int texformat = tex.texImage0[id].format; + const u32 tlutaddr = tex.texTlut[id].tmem_offset << 9; + const u32 tlutfmt = tex.texTlut[id].tlut_format; + const bool use_mipmaps = SamplerCommon::AreBpTexMode0MipmapsEnabled(tex.texMode0[id]); + u32 tex_levels = use_mipmaps ? ((tex.texMode1[id].max_lod + 0xf) / 0x10 + 1) : 1; + const bool from_tmem = tex.texImage1[id].image_type != 0; - if (0 == address) - return nullptr; + if (0 == address) + return nullptr; - // TexelSizeInNibbles(format) * width * height / 16; - const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat); - const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat); + // TexelSizeInNibbles(format) * width * height / 16; + const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat); + const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat); - unsigned int expandedWidth = ROUND_UP(width, bsw); - unsigned int expandedHeight = ROUND_UP(height, bsh); - const unsigned int nativeW = width; - const unsigned int nativeH = height; + unsigned int expandedWidth = ROUND_UP(width, bsw); + unsigned int expandedHeight = ROUND_UP(height, bsh); + const unsigned int nativeW = width; + const unsigned int nativeH = height; - // Hash assigned to texcache entry (also used to generate filenames used for texture dumping and custom texture lookup) - u64 base_hash = TEXHASH_INVALID; - u64 full_hash = TEXHASH_INVALID; + // Hash assigned to texcache entry (also used to generate filenames used for texture dumping and + // custom texture lookup) + u64 base_hash = TEXHASH_INVALID; + u64 full_hash = TEXHASH_INVALID; - u32 full_format = texformat; + u32 full_format = texformat; - const bool isPaletteTexture = (texformat == GX_TF_C4 || texformat == GX_TF_C8 || texformat == GX_TF_C14X2); + const bool isPaletteTexture = + (texformat == GX_TF_C4 || texformat == GX_TF_C8 || texformat == GX_TF_C14X2); - // Reject invalid tlut format. - if (isPaletteTexture && tlutfmt > GX_TL_RGB5A3) - return nullptr; + // Reject invalid tlut format. + if (isPaletteTexture && tlutfmt > GX_TL_RGB5A3) + return nullptr; - if (isPaletteTexture) - full_format = texformat | (tlutfmt << 16); + if (isPaletteTexture) + full_format = texformat | (tlutfmt << 16); - const u32 texture_size = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, texformat); - u32 additional_mips_size = 0; // not including level 0, which is texture_size + const u32 texture_size = + TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, texformat); + u32 additional_mips_size = 0; // not including level 0, which is texture_size - // GPUs don't like when the specified mipmap count would require more than one 1x1-sized LOD in the mipmap chain - // e.g. 64x64 with 7 LODs would have the mipmap chain 64x64,32x32,16x16,8x8,4x4,2x2,1x1,0x0, so we limit the mipmap count to 6 there - tex_levels = std::min(IntLog2(std::max(width, height)) + 1, tex_levels); + // GPUs don't like when the specified mipmap count would require more than one 1x1-sized LOD in + // the mipmap chain + // e.g. 64x64 with 7 LODs would have the mipmap chain 64x64,32x32,16x16,8x8,4x4,2x2,1x1,0x0, so we + // limit the mipmap count to 6 there + tex_levels = std::min(IntLog2(std::max(width, height)) + 1, tex_levels); - for (u32 level = 1; level != tex_levels; ++level) - { - // We still need to calculate the original size of the mips - const u32 expanded_mip_width = ROUND_UP(CalculateLevelSize(width, level), bsw); - const u32 expanded_mip_height = ROUND_UP(CalculateLevelSize(height, level), bsh); + for (u32 level = 1; level != tex_levels; ++level) + { + // We still need to calculate the original size of the mips + const u32 expanded_mip_width = ROUND_UP(CalculateLevelSize(width, level), bsw); + const u32 expanded_mip_height = ROUND_UP(CalculateLevelSize(height, level), bsh); - additional_mips_size += TexDecoder_GetTextureSizeInBytes(expanded_mip_width, expanded_mip_height, texformat); - } + additional_mips_size += + TexDecoder_GetTextureSizeInBytes(expanded_mip_width, expanded_mip_height, texformat); + } - const u8* src_data; - if (from_tmem) - src_data = &texMem[bpmem.tex[stage / 4].texImage1[stage % 4].tmem_even * TMEM_LINE_SIZE]; - else - src_data = Memory::GetPointer(address); + const u8* src_data; + if (from_tmem) + src_data = &texMem[bpmem.tex[stage / 4].texImage1[stage % 4].tmem_even * TMEM_LINE_SIZE]; + else + src_data = Memory::GetPointer(address); - if (!src_data) - { - ERROR_LOG(VIDEO, "Trying to use an invalid texture address 0x%8x", address); - return nullptr; - } + if (!src_data) + { + ERROR_LOG(VIDEO, "Trying to use an invalid texture address 0x%8x", address); + return nullptr; + } - // If we are recording a FifoLog, keep track of what memory we read. - // FifiRecorder does it's own memory modification tracking independant of the texture hashing below. - if (g_bRecordFifoData && !from_tmem) - FifoRecorder::GetInstance().UseMemory(address, texture_size + additional_mips_size, MemoryUpdate::TEXTURE_MAP); + // If we are recording a FifoLog, keep track of what memory we read. + // FifiRecorder does it's own memory modification tracking independant of the texture hashing + // below. + if (g_bRecordFifoData && !from_tmem) + FifoRecorder::GetInstance().UseMemory(address, texture_size + additional_mips_size, + MemoryUpdate::TEXTURE_MAP); - // TODO: This doesn't hash GB tiles for preloaded RGBA8 textures (instead, it's hashing more data from the low tmem bank than it should) - base_hash = GetHash64(src_data, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples); - u32 palette_size = 0; - if (isPaletteTexture) - { - palette_size = TexDecoder_GetPaletteSize(texformat); - full_hash = base_hash ^ GetHash64(&texMem[tlutaddr], palette_size, g_ActiveConfig.iSafeTextureCache_ColorSamples); - } - else - { - full_hash = base_hash; - } + // TODO: This doesn't hash GB tiles for preloaded RGBA8 textures (instead, it's hashing more data + // from the low tmem bank than it should) + base_hash = GetHash64(src_data, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples); + u32 palette_size = 0; + if (isPaletteTexture) + { + palette_size = TexDecoder_GetPaletteSize(texformat); + full_hash = base_hash ^ GetHash64(&texMem[tlutaddr], palette_size, + g_ActiveConfig.iSafeTextureCache_ColorSamples); + } + else + { + full_hash = base_hash; + } - // Search the texture cache for textures by address - // - // Find all texture cache entries for the current texture address, and decide whether to use one of - // them, or to create a new one - // - // In most cases, the fastest way is to use only one texture cache entry for the same address. Usually, - // when a texture changes, the old version of the texture is unlikely to be used again. If there were - // new cache entries created for normal texture updates, there would be a slowdown due to a huge amount - // of unused cache entries. Also thanks to texture pooling, overwriting an existing cache entry is - // faster than creating a new one from scratch. - // - // Some games use the same address for different textures though. If the same cache entry was used in - // this case, it would be constantly overwritten, and effectively there wouldn't be any caching for - // those textures. Examples for this are Metroid Prime and Castlevania 3. Metroid Prime has multiple - // sets of fonts on each other stored in a single texture and uses the palette to make different - // characters visible or invisible. In Castlevania 3 some textures are used for 2 different things or - // at least in 2 different ways(size 1024x1024 vs 1024x256). - // - // To determine whether to use multiple cache entries or a single entry, use the following heuristic: - // If the same texture address is used several times during the same frame, assume the address is used - // for different purposes and allow creating an additional cache entry. If there's at least one entry - // that hasn't been used for the same frame, then overwrite it, in order to keep the cache as small as - // possible. If the current texture is found in the cache, use that entry. - // - // For efb copies, the entry created in CopyRenderTargetToTexture always has to be used, or else it was - // done in vain. - std::pair iter_range = textures_by_address.equal_range((u64)address); - TexCache::iterator iter = iter_range.first; - TexCache::iterator oldest_entry = iter; - int temp_frameCount = 0x7fffffff; - TexCache::iterator unconverted_copy = textures_by_address.end(); + // Search the texture cache for textures by address + // + // Find all texture cache entries for the current texture address, and decide whether to use one + // of + // them, or to create a new one + // + // In most cases, the fastest way is to use only one texture cache entry for the same address. + // Usually, + // when a texture changes, the old version of the texture is unlikely to be used again. If there + // were + // new cache entries created for normal texture updates, there would be a slowdown due to a huge + // amount + // of unused cache entries. Also thanks to texture pooling, overwriting an existing cache entry is + // faster than creating a new one from scratch. + // + // Some games use the same address for different textures though. If the same cache entry was used + // in + // this case, it would be constantly overwritten, and effectively there wouldn't be any caching + // for + // those textures. Examples for this are Metroid Prime and Castlevania 3. Metroid Prime has + // multiple + // sets of fonts on each other stored in a single texture and uses the palette to make different + // characters visible or invisible. In Castlevania 3 some textures are used for 2 different things + // or + // at least in 2 different ways(size 1024x1024 vs 1024x256). + // + // To determine whether to use multiple cache entries or a single entry, use the following + // heuristic: + // If the same texture address is used several times during the same frame, assume the address is + // used + // for different purposes and allow creating an additional cache entry. If there's at least one + // entry + // that hasn't been used for the same frame, then overwrite it, in order to keep the cache as + // small as + // possible. If the current texture is found in the cache, use that entry. + // + // For efb copies, the entry created in CopyRenderTargetToTexture always has to be used, or else + // it was + // done in vain. + std::pair iter_range = + textures_by_address.equal_range((u64)address); + TexCache::iterator iter = iter_range.first; + TexCache::iterator oldest_entry = iter; + int temp_frameCount = 0x7fffffff; + TexCache::iterator unconverted_copy = textures_by_address.end(); - while (iter != iter_range.second) - { - TCacheEntryBase* entry = iter->second; - // Do not load strided EFB copies, they are not meant to be used directly - if (entry->IsEfbCopy() && entry->native_width == nativeW && entry->native_height == nativeH && - entry->memory_stride == entry->BytesPerRow()) - { - // EFB copies have slightly different rules as EFB copy formats have different - // meanings from texture formats. - if ((base_hash == entry->hash && (!isPaletteTexture || g_Config.backend_info.bSupportsPaletteConversion)) || - IsPlayingBackFifologWithBrokenEFBCopies) - { - // TODO: We should check format/width/height/levels for EFB copies. Checking - // format is complicated because EFB copy formats don't exactly match - // texture formats. I'm not sure what effect checking width/height/levels - // would have. - if (!isPaletteTexture || !g_Config.backend_info.bSupportsPaletteConversion) - return ReturnEntry(stage, entry); + while (iter != iter_range.second) + { + TCacheEntryBase* entry = iter->second; + // Do not load strided EFB copies, they are not meant to be used directly + if (entry->IsEfbCopy() && entry->native_width == nativeW && entry->native_height == nativeH && + entry->memory_stride == entry->BytesPerRow()) + { + // EFB copies have slightly different rules as EFB copy formats have different + // meanings from texture formats. + if ((base_hash == entry->hash && + (!isPaletteTexture || g_Config.backend_info.bSupportsPaletteConversion)) || + IsPlayingBackFifologWithBrokenEFBCopies) + { + // TODO: We should check format/width/height/levels for EFB copies. Checking + // format is complicated because EFB copy formats don't exactly match + // texture formats. I'm not sure what effect checking width/height/levels + // would have. + if (!isPaletteTexture || !g_Config.backend_info.bSupportsPaletteConversion) + return ReturnEntry(stage, entry); - // Note that we found an unconverted EFB copy, then continue. We'll - // perform the conversion later. Currently, we only convert EFB copies to - // palette textures; we could do other conversions if it proved to be - // beneficial. - unconverted_copy = iter; - } - else - { - // Aggressively prune EFB copies: if it isn't useful here, it will probably - // never be useful again. It's theoretically possible for a game to do - // something weird where the copy could become useful in the future, but in - // practice it doesn't happen. - iter = InvalidateTexture(iter); - continue; - } - } - else - { - // For normal textures, all texture parameters need to match - if (entry->hash == full_hash && entry->format == full_format && entry->native_levels >= tex_levels && - entry->native_width == nativeW && entry->native_height == nativeH) - { - entry = DoPartialTextureUpdates(iter, &texMem[tlutaddr], tlutfmt); + // Note that we found an unconverted EFB copy, then continue. We'll + // perform the conversion later. Currently, we only convert EFB copies to + // palette textures; we could do other conversions if it proved to be + // beneficial. + unconverted_copy = iter; + } + else + { + // Aggressively prune EFB copies: if it isn't useful here, it will probably + // never be useful again. It's theoretically possible for a game to do + // something weird where the copy could become useful in the future, but in + // practice it doesn't happen. + iter = InvalidateTexture(iter); + continue; + } + } + else + { + // For normal textures, all texture parameters need to match + if (entry->hash == full_hash && entry->format == full_format && + entry->native_levels >= tex_levels && entry->native_width == nativeW && + entry->native_height == nativeH) + { + entry = DoPartialTextureUpdates(iter, &texMem[tlutaddr], tlutfmt); - return ReturnEntry(stage, entry); - } - } + return ReturnEntry(stage, entry); + } + } - // Find the texture which hasn't been used for the longest time. Count paletted - // textures as the same texture here, when the texture itself is the same. This - // improves the performance a lot in some games that use paletted textures. - // Example: Sonic the Fighters (inside Sonic Gems Collection) - // Skip EFB copies here, so they can be used for partial texture updates - if (entry->frameCount != FRAMECOUNT_INVALID && entry->frameCount < temp_frameCount && - !entry->IsEfbCopy() && !(isPaletteTexture && entry->base_hash == base_hash)) - { - temp_frameCount = entry->frameCount; - oldest_entry = iter; - } - ++iter; - } + // Find the texture which hasn't been used for the longest time. Count paletted + // textures as the same texture here, when the texture itself is the same. This + // improves the performance a lot in some games that use paletted textures. + // Example: Sonic the Fighters (inside Sonic Gems Collection) + // Skip EFB copies here, so they can be used for partial texture updates + if (entry->frameCount != FRAMECOUNT_INVALID && entry->frameCount < temp_frameCount && + !entry->IsEfbCopy() && !(isPaletteTexture && entry->base_hash == base_hash)) + { + temp_frameCount = entry->frameCount; + oldest_entry = iter; + } + ++iter; + } - if (unconverted_copy != textures_by_address.end()) - { - TCacheEntryBase* decoded_entry = unconverted_copy->second->ApplyPalette(&texMem[tlutaddr], tlutfmt); + if (unconverted_copy != textures_by_address.end()) + { + TCacheEntryBase* decoded_entry = + unconverted_copy->second->ApplyPalette(&texMem[tlutaddr], tlutfmt); - if (decoded_entry) - { - return ReturnEntry(stage, decoded_entry); - } - } + if (decoded_entry) + { + return ReturnEntry(stage, decoded_entry); + } + } - // Search the texture cache for normal textures by hash - // - // If the texture was fully hashed, the address does not need to match. Identical duplicate textures cause unnecessary slowdowns - // Example: Tales of Symphonia (GC) uses over 500 small textures in menus, but only around 70 different ones - if (g_ActiveConfig.iSafeTextureCache_ColorSamples == 0 || - std::max(texture_size, palette_size) <= (u32)g_ActiveConfig.iSafeTextureCache_ColorSamples * 8) - { - iter_range = textures_by_hash.equal_range(full_hash); - iter = iter_range.first; - while (iter != iter_range.second) - { - TCacheEntryBase* entry = iter->second; - // All parameters, except the address, need to match here - if (entry->format == full_format && entry->native_levels >= tex_levels && - entry->native_width == nativeW && entry->native_height == nativeH) - { - entry = DoPartialTextureUpdates(iter, &texMem[tlutaddr], tlutfmt); + // Search the texture cache for normal textures by hash + // + // If the texture was fully hashed, the address does not need to match. Identical duplicate + // textures cause unnecessary slowdowns + // Example: Tales of Symphonia (GC) uses over 500 small textures in menus, but only around 70 + // different ones + if (g_ActiveConfig.iSafeTextureCache_ColorSamples == 0 || + std::max(texture_size, palette_size) <= + (u32)g_ActiveConfig.iSafeTextureCache_ColorSamples * 8) + { + iter_range = textures_by_hash.equal_range(full_hash); + iter = iter_range.first; + while (iter != iter_range.second) + { + TCacheEntryBase* entry = iter->second; + // All parameters, except the address, need to match here + if (entry->format == full_format && entry->native_levels >= tex_levels && + entry->native_width == nativeW && entry->native_height == nativeH) + { + entry = DoPartialTextureUpdates(iter, &texMem[tlutaddr], tlutfmt); - return ReturnEntry(stage, entry); - } - ++iter; - } - } + return ReturnEntry(stage, entry); + } + ++iter; + } + } - // If at least one entry was not used for the same frame, overwrite the oldest one - if (temp_frameCount != 0x7fffffff) - { - // pool this texture and make a new one later - InvalidateTexture(oldest_entry); - } + // If at least one entry was not used for the same frame, overwrite the oldest one + if (temp_frameCount != 0x7fffffff) + { + // pool this texture and make a new one later + InvalidateTexture(oldest_entry); + } - std::shared_ptr hires_tex; - if (g_ActiveConfig.bHiresTextures) - { - hires_tex = HiresTexture::Search( - src_data, texture_size, - &texMem[tlutaddr], palette_size, - width, height, - texformat, use_mipmaps - ); + std::shared_ptr hires_tex; + if (g_ActiveConfig.bHiresTextures) + { + hires_tex = HiresTexture::Search(src_data, texture_size, &texMem[tlutaddr], palette_size, width, + height, texformat, use_mipmaps); - if (hires_tex) - { - const auto& level = hires_tex->m_levels[0]; - if (level.width != width || level.height != height) - { - width = level.width; - height = level.height; - } - expandedWidth = level .width; - expandedHeight = level.height; - CheckTempSize(level.data_size); - memcpy(temp, level.data.get(), level.data_size); - } - } + if (hires_tex) + { + const auto& level = hires_tex->m_levels[0]; + if (level.width != width || level.height != height) + { + width = level.width; + height = level.height; + } + expandedWidth = level.width; + expandedHeight = level.height; + CheckTempSize(level.data_size); + memcpy(temp, level.data.get(), level.data_size); + } + } - // how many levels the allocated texture shall have - const u32 texLevels = hires_tex ? (u32)hires_tex->m_levels.size() : tex_levels; + // how many levels the allocated texture shall have + const u32 texLevels = hires_tex ? (u32)hires_tex->m_levels.size() : tex_levels; - // create the entry/texture - TCacheEntryConfig config; - config.width = width; - config.height = height; - config.levels = texLevels; + // create the entry/texture + TCacheEntryConfig config; + config.width = width; + config.height = height; + config.levels = texLevels; - TCacheEntryBase* entry = AllocateTexture(config); - GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true); + TCacheEntryBase* entry = AllocateTexture(config); + GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true); - if (!entry) - return nullptr; + if (!entry) + return nullptr; - if (!hires_tex) - { - if (!(texformat == GX_TF_RGBA8 && from_tmem)) - { - const u8* tlut = &texMem[tlutaddr]; - TexDecoder_Decode(temp, src_data, expandedWidth, expandedHeight, texformat, tlut, (TlutFormat)tlutfmt); - } - else - { - u8* src_data_gb = &texMem[bpmem.tex[stage / 4].texImage2[stage % 4].tmem_odd * TMEM_LINE_SIZE]; - TexDecoder_DecodeRGBA8FromTmem(temp, src_data, src_data_gb, expandedWidth, expandedHeight); - } - } + if (!hires_tex) + { + if (!(texformat == GX_TF_RGBA8 && from_tmem)) + { + const u8* tlut = &texMem[tlutaddr]; + TexDecoder_Decode(temp, src_data, expandedWidth, expandedHeight, texformat, tlut, + (TlutFormat)tlutfmt); + } + else + { + u8* src_data_gb = + &texMem[bpmem.tex[stage / 4].texImage2[stage % 4].tmem_odd * TMEM_LINE_SIZE]; + TexDecoder_DecodeRGBA8FromTmem(temp, src_data, src_data_gb, expandedWidth, expandedHeight); + } + } - iter = textures_by_address.emplace((u64)address, entry); - if (g_ActiveConfig.iSafeTextureCache_ColorSamples == 0 || - std::max(texture_size, palette_size) <= (u32)g_ActiveConfig.iSafeTextureCache_ColorSamples * 8) - { - entry->textures_by_hash_iter = textures_by_hash.emplace(full_hash, entry); - } + iter = textures_by_address.emplace((u64)address, entry); + if (g_ActiveConfig.iSafeTextureCache_ColorSamples == 0 || + std::max(texture_size, palette_size) <= + (u32)g_ActiveConfig.iSafeTextureCache_ColorSamples * 8) + { + entry->textures_by_hash_iter = textures_by_hash.emplace(full_hash, entry); + } - entry->SetGeneralParameters(address, texture_size, full_format); - entry->SetDimensions(nativeW, nativeH, tex_levels); - entry->SetHashes(base_hash, full_hash); - entry->is_efb_copy = false; - entry->is_custom_tex = hires_tex != nullptr; + entry->SetGeneralParameters(address, texture_size, full_format); + entry->SetDimensions(nativeW, nativeH, tex_levels); + entry->SetHashes(base_hash, full_hash); + entry->is_efb_copy = false; + entry->is_custom_tex = hires_tex != nullptr; - // load texture - entry->Load(width, height, expandedWidth, 0); + // load texture + entry->Load(width, height, expandedWidth, 0); - std::string basename = ""; - if (g_ActiveConfig.bDumpTextures && !hires_tex) - { - basename = HiresTexture::GenBaseName( - src_data, texture_size, - &texMem[tlutaddr], palette_size, - width, height, - texformat, use_mipmaps, - true - ); - DumpTexture(entry, basename, 0); - } + std::string basename = ""; + if (g_ActiveConfig.bDumpTextures && !hires_tex) + { + basename = HiresTexture::GenBaseName(src_data, texture_size, &texMem[tlutaddr], palette_size, + width, height, texformat, use_mipmaps, true); + DumpTexture(entry, basename, 0); + } - if (hires_tex) - { - for (u32 level_index = 1; level_index != texLevels; ++level_index) - { - const auto& level = hires_tex->m_levels[level_index]; - CheckTempSize(level.data_size); - memcpy(temp, level.data.get(), level.data_size); - entry->Load(level.width, level.height, level.width, level_index); - } - } - else - { - // load mips - TODO: Loading mipmaps from tmem is untested! - src_data += texture_size; + if (hires_tex) + { + for (u32 level_index = 1; level_index != texLevels; ++level_index) + { + const auto& level = hires_tex->m_levels[level_index]; + CheckTempSize(level.data_size); + memcpy(temp, level.data.get(), level.data_size); + entry->Load(level.width, level.height, level.width, level_index); + } + } + else + { + // load mips - TODO: Loading mipmaps from tmem is untested! + src_data += texture_size; - const u8* ptr_even = nullptr; - const u8* ptr_odd = nullptr; - if (from_tmem) - { - ptr_even = &texMem[bpmem.tex[stage / 4].texImage1[stage % 4].tmem_even * TMEM_LINE_SIZE + texture_size]; - ptr_odd = &texMem[bpmem.tex[stage / 4].texImage2[stage % 4].tmem_odd * TMEM_LINE_SIZE]; - } + const u8* ptr_even = nullptr; + const u8* ptr_odd = nullptr; + if (from_tmem) + { + ptr_even = &texMem[bpmem.tex[stage / 4].texImage1[stage % 4].tmem_even * TMEM_LINE_SIZE + + texture_size]; + ptr_odd = &texMem[bpmem.tex[stage / 4].texImage2[stage % 4].tmem_odd * TMEM_LINE_SIZE]; + } - for (u32 level = 1; level != texLevels; ++level) - { - const u32 mip_width = CalculateLevelSize(width, level); - const u32 mip_height = CalculateLevelSize(height, level); - const u32 expanded_mip_width = ROUND_UP(mip_width, bsw); - const u32 expanded_mip_height = ROUND_UP(mip_height, bsh); + for (u32 level = 1; level != texLevels; ++level) + { + const u32 mip_width = CalculateLevelSize(width, level); + const u32 mip_height = CalculateLevelSize(height, level); + const u32 expanded_mip_width = ROUND_UP(mip_width, bsw); + const u32 expanded_mip_height = ROUND_UP(mip_height, bsh); - const u8*& mip_src_data = from_tmem - ? ((level % 2) ? ptr_odd : ptr_even) - : src_data; - const u8* tlut = &texMem[tlutaddr]; - TexDecoder_Decode(temp, mip_src_data, expanded_mip_width, expanded_mip_height, texformat, tlut, (TlutFormat)tlutfmt); - mip_src_data += TexDecoder_GetTextureSizeInBytes(expanded_mip_width, expanded_mip_height, texformat); + const u8*& mip_src_data = from_tmem ? ((level % 2) ? ptr_odd : ptr_even) : src_data; + const u8* tlut = &texMem[tlutaddr]; + TexDecoder_Decode(temp, mip_src_data, expanded_mip_width, expanded_mip_height, texformat, + tlut, (TlutFormat)tlutfmt); + mip_src_data += + TexDecoder_GetTextureSizeInBytes(expanded_mip_width, expanded_mip_height, texformat); - entry->Load(mip_width, mip_height, expanded_mip_width, level); + entry->Load(mip_width, mip_height, expanded_mip_width, level); - if (g_ActiveConfig.bDumpTextures) - DumpTexture(entry, basename, level); - } - } + if (g_ActiveConfig.bDumpTextures) + DumpTexture(entry, basename, level); + } + } - INCSTAT(stats.numTexturesUploaded); - SETSTAT(stats.numTexturesAlive, textures_by_address.size()); + INCSTAT(stats.numTexturesUploaded); + SETSTAT(stats.numTexturesAlive, textures_by_address.size()); - entry = DoPartialTextureUpdates(iter, &texMem[tlutaddr], tlutfmt); + entry = DoPartialTextureUpdates(iter, &texMem[tlutaddr], tlutfmt); - return ReturnEntry(stage, entry); + return ReturnEntry(stage, entry); } -void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, u32 dstStride, PEControl::PixelFormat srcFormat, - const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) +void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, u32 dstStride, + PEControl::PixelFormat srcFormat, + const EFBRectangle& srcRect, bool isIntensity, + bool scaleByHalf) { - // Emulation methods: - // - // - EFB to RAM: - // Encodes the requested EFB data at its native resolution to the emulated RAM using shaders. - // Load() decodes the data from there again (using TextureDecoder) if the EFB copy is being used as a texture again. - // Advantage: CPU can read data from the EFB copy and we don't lose any important updates to the texture - // Disadvantage: Encoding+decoding steps often are redundant because only some games read or modify EFB copies before using them as textures. - // - // - EFB to texture: - // Copies the requested EFB data to a texture object in VRAM, performing any color conversion using shaders. - // Advantage: Works for many games, since in most cases EFB copies aren't read or modified at all before being used as a texture again. - // Since we don't do any further encoding or decoding here, this method is much faster. - // It also allows enhancing the visual quality by doing scaled EFB copies. - // - // - Hybrid EFB copies: - // 1a) Whenever this function gets called, encode the requested EFB data to RAM (like EFB to RAM) - // 1b) Set type to TCET_EC_DYNAMIC for all texture cache entries in the destination address range. - // If EFB copy caching is enabled, further checks will (try to) prevent redundant EFB copies. - // 2) Check if a texture cache entry for the specified dstAddr already exists (i.e. if an EFB copy was triggered to that address before): - // 2a) Entry doesn't exist: - // - Also copy the requested EFB data to a texture object in VRAM (like EFB to texture) - // - Create a texture cache entry for the target (type = TCET_EC_VRAM) - // - Store a hash of the encoded RAM data in the texcache entry. - // 2b) Entry exists AND type is TCET_EC_VRAM: - // - Like case 2a, but reuse the old texcache entry instead of creating a new one. - // 2c) Entry exists AND type is TCET_EC_DYNAMIC: - // - Only encode the texture to RAM (like EFB to RAM) and store a hash of the encoded data in the existing texcache entry. - // - Do NOT copy the requested EFB data to a VRAM object. Reason: the texture is dynamic, i.e. the CPU is modifying it. Storing a VRAM copy is useless, because we'd always end up deleting it and reloading the data from RAM anyway. - // 3) If the EFB copy gets used as a texture, compare the source RAM hash with the hash you stored when encoding the EFB data to RAM. - // 3a) If the two hashes match AND type is TCET_EC_VRAM, reuse the VRAM copy you created - // 3b) If the two hashes differ AND type is TCET_EC_VRAM, screw your existing VRAM copy. Set type to TCET_EC_DYNAMIC. - // Redecode the source RAM data to a VRAM object. The entry basically behaves like a normal texture now. - // 3c) If type is TCET_EC_DYNAMIC, treat the EFB copy like a normal texture. - // Advantage: Non-dynamic EFB copies can be visually enhanced like with EFB to texture. - // Compatibility is as good as EFB to RAM. - // Disadvantage: Slower than EFB to texture and often even slower than EFB to RAM. - // EFB copy cache depends on accurate texture hashing being enabled. However, with accurate hashing you end up being as slow as without a copy cache anyway. - // - // Disadvantage of all methods: Calling this function requires the GPU to perform a pipeline flush which stalls any further CPU processing. - // - // For historical reasons, Dolphin doesn't actually implement "pure" EFB to RAM emulation, but only EFB to texture and hybrid EFB copies. + // Emulation methods: + // + // - EFB to RAM: + // Encodes the requested EFB data at its native resolution to the emulated RAM using shaders. + // Load() decodes the data from there again (using TextureDecoder) if the EFB copy is being + // used as a texture again. + // Advantage: CPU can read data from the EFB copy and we don't lose any important updates to + // the texture + // Disadvantage: Encoding+decoding steps often are redundant because only some games read or + // modify EFB copies before using them as textures. + // + // - EFB to texture: + // Copies the requested EFB data to a texture object in VRAM, performing any color conversion + // using shaders. + // Advantage: Works for many games, since in most cases EFB copies aren't read or modified at + // all before being used as a texture again. + // Since we don't do any further encoding or decoding here, this method is much + // faster. + // It also allows enhancing the visual quality by doing scaled EFB copies. + // + // - Hybrid EFB copies: + // 1a) Whenever this function gets called, encode the requested EFB data to RAM (like EFB to + // RAM) + // 1b) Set type to TCET_EC_DYNAMIC for all texture cache entries in the destination address + // range. + // If EFB copy caching is enabled, further checks will (try to) prevent redundant EFB + // copies. + // 2) Check if a texture cache entry for the specified dstAddr already exists (i.e. if an EFB + // copy was triggered to that address before): + // 2a) Entry doesn't exist: + // - Also copy the requested EFB data to a texture object in VRAM (like EFB to texture) + // - Create a texture cache entry for the target (type = TCET_EC_VRAM) + // - Store a hash of the encoded RAM data in the texcache entry. + // 2b) Entry exists AND type is TCET_EC_VRAM: + // - Like case 2a, but reuse the old texcache entry instead of creating a new one. + // 2c) Entry exists AND type is TCET_EC_DYNAMIC: + // - Only encode the texture to RAM (like EFB to RAM) and store a hash of the encoded + // data in the existing texcache entry. + // - Do NOT copy the requested EFB data to a VRAM object. Reason: the texture is dynamic, + // i.e. the CPU is modifying it. Storing a VRAM copy is useless, because we'd always end + // up deleting it and reloading the data from RAM anyway. + // 3) If the EFB copy gets used as a texture, compare the source RAM hash with the hash you + // stored when encoding the EFB data to RAM. + // 3a) If the two hashes match AND type is TCET_EC_VRAM, reuse the VRAM copy you created + // 3b) If the two hashes differ AND type is TCET_EC_VRAM, screw your existing VRAM copy. Set + // type to TCET_EC_DYNAMIC. + // Redecode the source RAM data to a VRAM object. The entry basically behaves like a + // normal texture now. + // 3c) If type is TCET_EC_DYNAMIC, treat the EFB copy like a normal texture. + // Advantage: Non-dynamic EFB copies can be visually enhanced like with EFB to texture. + // Compatibility is as good as EFB to RAM. + // Disadvantage: Slower than EFB to texture and often even slower than EFB to RAM. + // EFB copy cache depends on accurate texture hashing being enabled. However, + // with accurate hashing you end up being as slow as without a copy cache + // anyway. + // + // Disadvantage of all methods: Calling this function requires the GPU to perform a pipeline flush + // which stalls any further CPU processing. + // + // For historical reasons, Dolphin doesn't actually implement "pure" EFB to RAM emulation, but + // only EFB to texture and hybrid EFB copies. - float colmat[28] = { 0 }; - float *const fConstAdd = colmat + 16; - float *const ColorMask = colmat + 20; - ColorMask[0] = ColorMask[1] = ColorMask[2] = ColorMask[3] = 255.0f; - ColorMask[4] = ColorMask[5] = ColorMask[6] = ColorMask[7] = 1.0f / 255.0f; - unsigned int cbufid = -1; - bool efbHasAlpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; + float colmat[28] = {0}; + float* const fConstAdd = colmat + 16; + float* const ColorMask = colmat + 20; + ColorMask[0] = ColorMask[1] = ColorMask[2] = ColorMask[3] = 255.0f; + ColorMask[4] = ColorMask[5] = ColorMask[6] = ColorMask[7] = 1.0f / 255.0f; + unsigned int cbufid = -1; + bool efbHasAlpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; - if (srcFormat == PEControl::Z24) - { - switch (dstFormat) - { - case 0: // Z4 - colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1.0f; - cbufid = 0; - dstFormat |= _GX_TF_CTF; - break; - case 8: // Z8H - dstFormat |= _GX_TF_CTF; - case 1: // Z8 - colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1.0f; - cbufid = 1; - break; + if (srcFormat == PEControl::Z24) + { + switch (dstFormat) + { + case 0: // Z4 + colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1.0f; + cbufid = 0; + dstFormat |= _GX_TF_CTF; + break; + case 8: // Z8H + dstFormat |= _GX_TF_CTF; + case 1: // Z8 + colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1.0f; + cbufid = 1; + break; - case 3: // Z16 - colmat[1] = colmat[5] = colmat[9] = colmat[12] = 1.0f; - cbufid = 2; - break; + case 3: // Z16 + colmat[1] = colmat[5] = colmat[9] = colmat[12] = 1.0f; + cbufid = 2; + break; - case 11: // Z16 (reverse order) - colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f; - cbufid = 3; - dstFormat |= _GX_TF_CTF; - break; + case 11: // Z16 (reverse order) + colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f; + cbufid = 3; + dstFormat |= _GX_TF_CTF; + break; - case 6: // Z24X8 - colmat[0] = colmat[5] = colmat[10] = 1.0f; - cbufid = 4; - break; + case 6: // Z24X8 + colmat[0] = colmat[5] = colmat[10] = 1.0f; + cbufid = 4; + break; - case 9: // Z8M - colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f; - cbufid = 5; - dstFormat |= _GX_TF_CTF; - break; + case 9: // Z8M + colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f; + cbufid = 5; + dstFormat |= _GX_TF_CTF; + break; - case 10: // Z8L - colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f; - cbufid = 6; - dstFormat |= _GX_TF_CTF; - break; + case 10: // Z8L + colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f; + cbufid = 6; + dstFormat |= _GX_TF_CTF; + break; - case 12: // Z16L - copy lower 16 depth bits - // expected to be used as an IA8 texture (upper 8 bits stored as intensity, lower 8 bits stored as alpha) - // Used e.g. in Zelda: Skyward Sword - colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1.0f; - cbufid = 7; - dstFormat |= _GX_TF_CTF; - break; + case 12: // Z16L - copy lower 16 depth bits + // expected to be used as an IA8 texture (upper 8 bits stored as intensity, lower 8 bits + // stored as alpha) + // Used e.g. in Zelda: Skyward Sword + colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1.0f; + cbufid = 7; + dstFormat |= _GX_TF_CTF; + break; - default: - ERROR_LOG(VIDEO, "Unknown copy zbuf format: 0x%x", dstFormat); - colmat[2] = colmat[5] = colmat[8] = 1.0f; - cbufid = 8; - break; - } + default: + ERROR_LOG(VIDEO, "Unknown copy zbuf format: 0x%x", dstFormat); + colmat[2] = colmat[5] = colmat[8] = 1.0f; + cbufid = 8; + break; + } - dstFormat |= _GX_TF_ZTF; - } - else if (isIntensity) - { - fConstAdd[0] = fConstAdd[1] = fConstAdd[2] = 16.0f / 255.0f; - switch (dstFormat) - { - case 0: // I4 - case 1: // I8 - case 2: // IA4 - case 3: // IA8 - case 8: // I8 - // TODO - verify these coefficients - colmat[0] = 0.257f; colmat[1] = 0.504f; colmat[2] = 0.098f; - colmat[4] = 0.257f; colmat[5] = 0.504f; colmat[6] = 0.098f; - colmat[8] = 0.257f; colmat[9] = 0.504f; colmat[10] = 0.098f; + dstFormat |= _GX_TF_ZTF; + } + else if (isIntensity) + { + fConstAdd[0] = fConstAdd[1] = fConstAdd[2] = 16.0f / 255.0f; + switch (dstFormat) + { + case 0: // I4 + case 1: // I8 + case 2: // IA4 + case 3: // IA8 + case 8: // I8 + // TODO - verify these coefficients + colmat[0] = 0.257f; + colmat[1] = 0.504f; + colmat[2] = 0.098f; + colmat[4] = 0.257f; + colmat[5] = 0.504f; + colmat[6] = 0.098f; + colmat[8] = 0.257f; + colmat[9] = 0.504f; + colmat[10] = 0.098f; - if (dstFormat < 2 || dstFormat == 8) - { - colmat[12] = 0.257f; colmat[13] = 0.504f; colmat[14] = 0.098f; - fConstAdd[3] = 16.0f / 255.0f; - if (dstFormat == 0) - { - ColorMask[0] = ColorMask[1] = ColorMask[2] = 15.0f; - ColorMask[4] = ColorMask[5] = ColorMask[6] = 1.0f / 15.0f; - cbufid = 9; - } - else - { - cbufid = 10; - } - } - else// alpha - { - colmat[15] = 1; - if (dstFormat == 2) - { - ColorMask[0] = ColorMask[1] = ColorMask[2] = ColorMask[3] = 15.0f; - ColorMask[4] = ColorMask[5] = ColorMask[6] = ColorMask[7] = 1.0f / 15.0f; - cbufid = 11; - } - else - { - cbufid = 12; - } + if (dstFormat < 2 || dstFormat == 8) + { + colmat[12] = 0.257f; + colmat[13] = 0.504f; + colmat[14] = 0.098f; + fConstAdd[3] = 16.0f / 255.0f; + if (dstFormat == 0) + { + ColorMask[0] = ColorMask[1] = ColorMask[2] = 15.0f; + ColorMask[4] = ColorMask[5] = ColorMask[6] = 1.0f / 15.0f; + cbufid = 9; + } + else + { + cbufid = 10; + } + } + else // alpha + { + colmat[15] = 1; + if (dstFormat == 2) + { + ColorMask[0] = ColorMask[1] = ColorMask[2] = ColorMask[3] = 15.0f; + ColorMask[4] = ColorMask[5] = ColorMask[6] = ColorMask[7] = 1.0f / 15.0f; + cbufid = 11; + } + else + { + cbufid = 12; + } + } + break; - } - break; + default: + ERROR_LOG(VIDEO, "Unknown copy intensity format: 0x%x", dstFormat); + colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1.0f; + cbufid = 13; + break; + } + } + else + { + switch (dstFormat) + { + case 0: // R4 + colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1; + ColorMask[0] = 15.0f; + ColorMask[4] = 1.0f / 15.0f; + cbufid = 14; + dstFormat |= _GX_TF_CTF; + break; + case 1: // R8 + case 8: // R8 + colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1; + cbufid = 15; + dstFormat = GX_CTF_R8; + break; - default: - ERROR_LOG(VIDEO, "Unknown copy intensity format: 0x%x", dstFormat); - colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1.0f; - cbufid = 13; - break; - } - } - else - { - switch (dstFormat) - { - case 0: // R4 - colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1; - ColorMask[0] = 15.0f; - ColorMask[4] = 1.0f / 15.0f; - cbufid = 14; - dstFormat |= _GX_TF_CTF; - break; - case 1: // R8 - case 8: // R8 - colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1; - cbufid = 15; - dstFormat = GX_CTF_R8; - break; + case 2: // RA4 + colmat[0] = colmat[4] = colmat[8] = colmat[15] = 1.0f; + ColorMask[0] = ColorMask[3] = 15.0f; + ColorMask[4] = ColorMask[7] = 1.0f / 15.0f; - case 2: // RA4 - colmat[0] = colmat[4] = colmat[8] = colmat[15] = 1.0f; - ColorMask[0] = ColorMask[3] = 15.0f; - ColorMask[4] = ColorMask[7] = 1.0f / 15.0f; + cbufid = 16; + if (!efbHasAlpha) + { + ColorMask[3] = 0.0f; + fConstAdd[3] = 1.0f; + cbufid = 17; + } + dstFormat |= _GX_TF_CTF; + break; + case 3: // RA8 + colmat[0] = colmat[4] = colmat[8] = colmat[15] = 1.0f; - cbufid = 16; - if (!efbHasAlpha) - { - ColorMask[3] = 0.0f; - fConstAdd[3] = 1.0f; - cbufid = 17; - } - dstFormat |= _GX_TF_CTF; - break; - case 3: // RA8 - colmat[0] = colmat[4] = colmat[8] = colmat[15] = 1.0f; + cbufid = 18; + if (!efbHasAlpha) + { + ColorMask[3] = 0.0f; + fConstAdd[3] = 1.0f; + cbufid = 19; + } + dstFormat |= _GX_TF_CTF; + break; - cbufid = 18; - if (!efbHasAlpha) - { - ColorMask[3] = 0.0f; - fConstAdd[3] = 1.0f; - cbufid = 19; - } - dstFormat |= _GX_TF_CTF; - break; + case 7: // A8 + colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1.0f; - case 7: // A8 - colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1.0f; + cbufid = 20; + if (!efbHasAlpha) + { + ColorMask[3] = 0.0f; + fConstAdd[0] = 1.0f; + fConstAdd[1] = 1.0f; + fConstAdd[2] = 1.0f; + fConstAdd[3] = 1.0f; + cbufid = 21; + } + dstFormat |= _GX_TF_CTF; + break; - cbufid = 20; - if (!efbHasAlpha) - { - ColorMask[3] = 0.0f; - fConstAdd[0] = 1.0f; - fConstAdd[1] = 1.0f; - fConstAdd[2] = 1.0f; - fConstAdd[3] = 1.0f; - cbufid = 21; - } - dstFormat |= _GX_TF_CTF; - break; + case 9: // G8 + colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f; + cbufid = 22; + dstFormat |= _GX_TF_CTF; + break; + case 10: // B8 + colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f; + cbufid = 23; + dstFormat |= _GX_TF_CTF; + break; - case 9: // G8 - colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f; - cbufid = 22; - dstFormat |= _GX_TF_CTF; - break; - case 10: // B8 - colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f; - cbufid = 23; - dstFormat |= _GX_TF_CTF; - break; + case 11: // RG8 + colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f; + cbufid = 24; + dstFormat |= _GX_TF_CTF; + break; - case 11: // RG8 - colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f; - cbufid = 24; - dstFormat |= _GX_TF_CTF; - break; + case 12: // GB8 + colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1.0f; + cbufid = 25; + dstFormat |= _GX_TF_CTF; + break; - case 12: // GB8 - colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1.0f; - cbufid = 25; - dstFormat |= _GX_TF_CTF; - break; + case 4: // RGB565 + colmat[0] = colmat[5] = colmat[10] = 1.0f; + ColorMask[0] = ColorMask[2] = 31.0f; + ColorMask[4] = ColorMask[6] = 1.0f / 31.0f; + ColorMask[1] = 63.0f; + ColorMask[5] = 1.0f / 63.0f; + fConstAdd[3] = 1.0f; // set alpha to 1 + cbufid = 26; + break; - case 4: // RGB565 - colmat[0] = colmat[5] = colmat[10] = 1.0f; - ColorMask[0] = ColorMask[2] = 31.0f; - ColorMask[4] = ColorMask[6] = 1.0f / 31.0f; - ColorMask[1] = 63.0f; - ColorMask[5] = 1.0f / 63.0f; - fConstAdd[3] = 1.0f; // set alpha to 1 - cbufid = 26; - break; + case 5: // RGB5A3 + colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1.0f; + ColorMask[0] = ColorMask[1] = ColorMask[2] = 31.0f; + ColorMask[4] = ColorMask[5] = ColorMask[6] = 1.0f / 31.0f; + ColorMask[3] = 7.0f; + ColorMask[7] = 1.0f / 7.0f; - case 5: // RGB5A3 - colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1.0f; - ColorMask[0] = ColorMask[1] = ColorMask[2] = 31.0f; - ColorMask[4] = ColorMask[5] = ColorMask[6] = 1.0f / 31.0f; - ColorMask[3] = 7.0f; - ColorMask[7] = 1.0f / 7.0f; + cbufid = 27; + if (!efbHasAlpha) + { + ColorMask[3] = 0.0f; + fConstAdd[3] = 1.0f; + cbufid = 28; + } + break; + case 6: // RGBA8 + colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1.0f; - cbufid = 27; - if (!efbHasAlpha) - { - ColorMask[3] = 0.0f; - fConstAdd[3] = 1.0f; - cbufid = 28; - } - break; - case 6: // RGBA8 - colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1.0f; + cbufid = 29; + if (!efbHasAlpha) + { + ColorMask[3] = 0.0f; + fConstAdd[3] = 1.0f; + cbufid = 30; + } + break; - cbufid = 29; - if (!efbHasAlpha) - { - ColorMask[3] = 0.0f; - fConstAdd[3] = 1.0f; - cbufid = 30; - } - break; + default: + ERROR_LOG(VIDEO, "Unknown copy color format: 0x%x", dstFormat); + colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1.0f; + cbufid = 31; + break; + } + } - default: - ERROR_LOG(VIDEO, "Unknown copy color format: 0x%x", dstFormat); - colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1.0f; - cbufid = 31; - break; - } - } + u8* dst = Memory::GetPointer(dstAddr); + if (dst == nullptr) + { + ERROR_LOG(VIDEO, "Trying to copy from EFB to invalid address 0x%8x", dstAddr); + return; + } - u8* dst = Memory::GetPointer(dstAddr); - if (dst == nullptr) - { - ERROR_LOG(VIDEO, "Trying to copy from EFB to invalid address 0x%8x", dstAddr); - return; - } + const unsigned int tex_w = scaleByHalf ? srcRect.GetWidth() / 2 : srcRect.GetWidth(); + const unsigned int tex_h = scaleByHalf ? srcRect.GetHeight() / 2 : srcRect.GetHeight(); - const unsigned int tex_w = scaleByHalf ? srcRect.GetWidth() / 2 : srcRect.GetWidth(); - const unsigned int tex_h = scaleByHalf ? srcRect.GetHeight() / 2 : srcRect.GetHeight(); + unsigned int scaled_tex_w = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledX(tex_w) : tex_w; + unsigned int scaled_tex_h = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledY(tex_h) : tex_h; - unsigned int scaled_tex_w = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledX(tex_w) : tex_w; - unsigned int scaled_tex_h = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledY(tex_h) : tex_h; + // Remove all texture cache entries at dstAddr + // It's not possible to have two EFB copies at the same address, this makes sure any old efb + // copies + // (or normal textures) are removed from texture cache. They are also un-linked from any + // partially + // updated textures, which forces that partially updated texture to be updated. + // TODO: This also wipes out non-efb copies, which is counterproductive. + { + std::pair iter_range = + textures_by_address.equal_range((u64)dstAddr); + TexCache::iterator iter = iter_range.first; + while (iter != iter_range.second) + { + iter = InvalidateTexture(iter); + } + } - // Remove all texture cache entries at dstAddr - // It's not possible to have two EFB copies at the same address, this makes sure any old efb copies - // (or normal textures) are removed from texture cache. They are also un-linked from any partially - // updated textures, which forces that partially updated texture to be updated. - // TODO: This also wipes out non-efb copies, which is counterproductive. - { - std::pair iter_range = textures_by_address.equal_range((u64)dstAddr); - TexCache::iterator iter = iter_range.first; - while (iter != iter_range.second) - { - iter = InvalidateTexture(iter); - } - } + // Get the base (in memory) format of this efb copy. + int baseFormat = TexDecoder_GetEfbCopyBaseFormat(dstFormat); - // Get the base (in memory) format of this efb copy. - int baseFormat = TexDecoder_GetEfbCopyBaseFormat(dstFormat); + u32 blockH = TexDecoder_GetBlockHeightInTexels(baseFormat); + const u32 blockW = TexDecoder_GetBlockWidthInTexels(baseFormat); - u32 blockH = TexDecoder_GetBlockHeightInTexels(baseFormat); - const u32 blockW = TexDecoder_GetBlockWidthInTexels(baseFormat); + // Round up source height to multiple of block size + u32 actualHeight = ROUND_UP(tex_h, blockH); + const u32 actualWidth = ROUND_UP(tex_w, blockW); - // Round up source height to multiple of block size - u32 actualHeight = ROUND_UP(tex_h, blockH); - const u32 actualWidth = ROUND_UP(tex_w, blockW); + u32 num_blocks_y = actualHeight / blockH; + const u32 num_blocks_x = actualWidth / blockW; - u32 num_blocks_y = actualHeight / blockH; - const u32 num_blocks_x = actualWidth / blockW; + // RGBA takes two cache lines per block; all others take one + const u32 bytes_per_block = baseFormat == GX_TF_RGBA8 ? 64 : 32; - // RGBA takes two cache lines per block; all others take one - const u32 bytes_per_block = baseFormat == GX_TF_RGBA8 ? 64 : 32; + u32 bytes_per_row = num_blocks_x * bytes_per_block; - u32 bytes_per_row = num_blocks_x * bytes_per_block; + bool copy_to_ram = !g_ActiveConfig.bSkipEFBCopyToRam; + bool copy_to_vram = true; - bool copy_to_ram = !g_ActiveConfig.bSkipEFBCopyToRam; - bool copy_to_vram = true; + if (copy_to_ram) + { + g_texture_cache->CopyEFB(dst, dstFormat, tex_w, bytes_per_row, num_blocks_y, dstStride, + srcFormat, srcRect, isIntensity, scaleByHalf); + } + else + { + // Hack: Most games don't actually need the correct texture data in RAM + // and we can just keep a copy in VRAM. We zero the memory so we + // can check it hasn't changed before using our copy in VRAM. + u8* ptr = dst; + for (u32 i = 0; i < num_blocks_y; i++) + { + memset(ptr, 0, bytes_per_row); + ptr += dstStride; + } + } - if (copy_to_ram) - { - g_texture_cache->CopyEFB( - dst, - dstFormat, - tex_w, - bytes_per_row, - num_blocks_y, - dstStride, - srcFormat, - srcRect, - isIntensity, - scaleByHalf); - } - else - { - // Hack: Most games don't actually need the correct texture data in RAM - // and we can just keep a copy in VRAM. We zero the memory so we - // can check it hasn't changed before using our copy in VRAM. - u8* ptr = dst; - for (u32 i = 0; i < num_blocks_y; i++) - { - memset(ptr, 0, bytes_per_row); - ptr += dstStride; - } - } + if (g_bRecordFifoData) + { + // Mark the memory behind this efb copy as dynamicly generated for the Fifo log + u32 address = dstAddr; + for (u32 i = 0; i < num_blocks_y; i++) + { + FifoRecorder::GetInstance().UseMemory(address, bytes_per_row, MemoryUpdate::TEXTURE_MAP, + true); + address += dstStride; + } + } - if (g_bRecordFifoData) - { - // Mark the memory behind this efb copy as dynamicly generated for the Fifo log - u32 address = dstAddr; - for (u32 i = 0; i < num_blocks_y; i++) - { - FifoRecorder::GetInstance().UseMemory(address, bytes_per_row, MemoryUpdate::TEXTURE_MAP, true); - address += dstStride; - } - } + if (dstStride < bytes_per_row) + { + // This kind of efb copy results in a scrambled image. + // I'm pretty sure no game actually wants to do this, it might be caused by a + // programming bug in the game, or a CPU/Bounding box emulation issue with dolphin. + // The copy_to_ram code path above handles this "correctly" and scrambles the image + // but the copy_to_vram code path just saves and uses unscrambled texture instead. - if (dstStride < bytes_per_row) - { - // This kind of efb copy results in a scrambled image. - // I'm pretty sure no game actually wants to do this, it might be caused by a - // programming bug in the game, or a CPU/Bounding box emulation issue with dolphin. - // The copy_to_ram code path above handles this "correctly" and scrambles the image - // but the copy_to_vram code path just saves and uses unscrambled texture instead. + // To avoid a "incorrect" result, we simply skip doing the copy_to_vram code path + // so if the game does try to use the scrambled texture, dolphin will grab the scrambled + // texture (or black if copy_to_ram is also disabled) out of ram. + ERROR_LOG(VIDEO, "Memory stride too small (%i < %i)", dstStride, bytes_per_row); + copy_to_vram = false; + } - // To avoid a "incorrect" result, we simply skip doing the copy_to_vram code path - // so if the game does try to use the scrambled texture, dolphin will grab the scrambled - // texture (or black if copy_to_ram is also disabled) out of ram. - ERROR_LOG(VIDEO, "Memory stride too small (%i < %i)", dstStride, bytes_per_row); - copy_to_vram = false; - } + // Invalidate all textures that overlap the range of our efb copy. + // Unless our efb copy has a weird stride, then we want avoid invalidating textures which + // we might be able to do a partial texture update on. + // TODO: This also invalidates partial overlaps, which we currently don't have a better way + // of dealing with. + if (dstStride == bytes_per_row || !copy_to_vram) + { + TexCache::iterator iter = textures_by_address.begin(); + while (iter != textures_by_address.end()) + { + if (iter->second->addr + iter->second->size_in_bytes <= dstAddr || + iter->second->addr >= dstAddr + num_blocks_y * dstStride) + ++iter; + else + iter = InvalidateTexture(iter); + } + } - // Invalidate all textures that overlap the range of our efb copy. - // Unless our efb copy has a weird stride, then we want avoid invalidating textures which - // we might be able to do a partial texture update on. - // TODO: This also invalidates partial overlaps, which we currently don't have a better way - // of dealing with. - if (dstStride == bytes_per_row || !copy_to_vram) - { - TexCache::iterator iter = textures_by_address.begin(); - while (iter != textures_by_address.end()) - { - if (iter->second->addr + iter->second->size_in_bytes <= dstAddr || iter->second->addr >= dstAddr + num_blocks_y * dstStride) - ++iter; - else - iter = InvalidateTexture(iter); - } - } + if (copy_to_vram) + { + // create the texture + TCacheEntryConfig config; + config.rendertarget = true; + config.width = scaled_tex_w; + config.height = scaled_tex_h; + config.layers = FramebufferManagerBase::GetEFBLayers(); - if (copy_to_vram) - { - // create the texture - TCacheEntryConfig config; - config.rendertarget = true; - config.width = scaled_tex_w; - config.height = scaled_tex_h; - config.layers = FramebufferManagerBase::GetEFBLayers(); + TCacheEntryBase* entry = AllocateTexture(config); - TCacheEntryBase* entry = AllocateTexture(config); + if (entry) + { + entry->SetGeneralParameters(dstAddr, 0, baseFormat); + entry->SetDimensions(tex_w, tex_h, 1); - if (entry) - { - entry->SetGeneralParameters(dstAddr, 0, baseFormat); - entry->SetDimensions(tex_w, tex_h, 1); + entry->frameCount = FRAMECOUNT_INVALID; + entry->SetEfbCopy(dstStride); + entry->is_custom_tex = false; - entry->frameCount = FRAMECOUNT_INVALID; - entry->SetEfbCopy(dstStride); - entry->is_custom_tex = false; + entry->FromRenderTarget(dst, srcFormat, srcRect, scaleByHalf, cbufid, colmat); - entry->FromRenderTarget(dst, srcFormat, srcRect, scaleByHalf, cbufid, colmat); + u64 hash = entry->CalculateHash(); + entry->SetHashes(hash, hash); - u64 hash = entry->CalculateHash(); - entry->SetHashes(hash, hash); + if (g_ActiveConfig.bDumpEFBTarget) + { + static int count = 0; + entry->Save(StringFromFormat("%sefb_frame_%i.png", + File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(), count++), + 0); + } - if (g_ActiveConfig.bDumpEFBTarget) - { - static int count = 0; - entry->Save(StringFromFormat("%sefb_frame_%i.png", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(), - count++), 0); - } - - textures_by_address.emplace((u64)dstAddr, entry); - } - } + textures_by_address.emplace((u64)dstAddr, entry); + } + } } -TextureCacheBase::TCacheEntryBase* TextureCacheBase::AllocateTexture(const TCacheEntryConfig& config) +TextureCacheBase::TCacheEntryBase* +TextureCacheBase::AllocateTexture(const TCacheEntryConfig& config) { - TexPool::iterator iter = texture_pool.find(config); - TextureCacheBase::TCacheEntryBase* entry; - if (iter != texture_pool.end()) - { - entry = iter->second; - texture_pool.erase(iter); - } - else - { - entry = g_texture_cache->CreateTexture(config); - if (!entry) - return nullptr; + TexPool::iterator iter = texture_pool.find(config); + TextureCacheBase::TCacheEntryBase* entry; + if (iter != texture_pool.end()) + { + entry = iter->second; + texture_pool.erase(iter); + } + else + { + entry = g_texture_cache->CreateTexture(config); + if (!entry) + return nullptr; - INCSTAT(stats.numTexturesCreated); - } + INCSTAT(stats.numTexturesCreated); + } - entry->textures_by_hash_iter = textures_by_hash.end(); - return entry; + entry->textures_by_hash_iter = textures_by_hash.end(); + return entry; } -TextureCacheBase::TexCache::iterator TextureCacheBase::GetTexCacheIter(TextureCacheBase::TCacheEntryBase* entry) +TextureCacheBase::TexCache::iterator +TextureCacheBase::GetTexCacheIter(TextureCacheBase::TCacheEntryBase* entry) { - std::pairiter_range = textures_by_address.equal_range(entry->addr); - TexCache::iterator iter = iter_range.first; - while (iter != iter_range.second) - { - if (iter->second == entry) - { - return iter; - } - ++iter; - } - return textures_by_address.end(); + std::pair iter_range = + textures_by_address.equal_range(entry->addr); + TexCache::iterator iter = iter_range.first; + while (iter != iter_range.second) + { + if (iter->second == entry) + { + return iter; + } + ++iter; + } + return textures_by_address.end(); } TextureCacheBase::TexCache::iterator TextureCacheBase::InvalidateTexture(TexCache::iterator iter) { - if (iter == textures_by_address.end()) - return textures_by_address.end(); + if (iter == textures_by_address.end()) + return textures_by_address.end(); - TCacheEntryBase* entry = iter->second; + TCacheEntryBase* entry = iter->second; - if (entry->textures_by_hash_iter != textures_by_hash.end()) - { - textures_by_hash.erase(entry->textures_by_hash_iter); - entry->textures_by_hash_iter = textures_by_hash.end(); - } + if (entry->textures_by_hash_iter != textures_by_hash.end()) + { + textures_by_hash.erase(entry->textures_by_hash_iter); + entry->textures_by_hash_iter = textures_by_hash.end(); + } - entry->DestroyAllReferences(); + entry->DestroyAllReferences(); - entry->frameCount = FRAMECOUNT_INVALID; - texture_pool.emplace(entry->config, entry); + entry->frameCount = FRAMECOUNT_INVALID; + texture_pool.emplace(entry->config, entry); - return textures_by_address.erase(iter); + return textures_by_address.erase(iter); } u32 TextureCacheBase::TCacheEntryBase::BytesPerRow() const { - const u32 blockW = TexDecoder_GetBlockWidthInTexels(format); + const u32 blockW = TexDecoder_GetBlockWidthInTexels(format); - // Round up source height to multiple of block size - const u32 actualWidth = ROUND_UP(native_width, blockW); + // Round up source height to multiple of block size + const u32 actualWidth = ROUND_UP(native_width, blockW); - const u32 numBlocksX = actualWidth / blockW; + const u32 numBlocksX = actualWidth / blockW; - // RGBA takes two cache lines per block; all others take one - const u32 bytes_per_block = format == GX_TF_RGBA8 ? 64 : 32; + // RGBA takes two cache lines per block; all others take one + const u32 bytes_per_block = format == GX_TF_RGBA8 ? 64 : 32; - return numBlocksX * bytes_per_block; + return numBlocksX * bytes_per_block; } u32 TextureCacheBase::TCacheEntryBase::NumBlocksY() const { - u32 blockH = TexDecoder_GetBlockHeightInTexels(format); - // Round up source height to multiple of block size - u32 actualHeight = ROUND_UP(native_height, blockH); + u32 blockH = TexDecoder_GetBlockHeightInTexels(format); + // Round up source height to multiple of block size + u32 actualHeight = ROUND_UP(native_height, blockH); - return actualHeight / blockH; + return actualHeight / blockH; } void TextureCacheBase::TCacheEntryBase::SetEfbCopy(u32 stride) { - is_efb_copy = true; - memory_stride = stride; + is_efb_copy = true; + memory_stride = stride; - _assert_msg_(VIDEO, memory_stride >= BytesPerRow(), "Memory stride is too small"); + _assert_msg_(VIDEO, memory_stride >= BytesPerRow(), "Memory stride is too small"); - size_in_bytes = memory_stride * NumBlocksY(); + size_in_bytes = memory_stride * NumBlocksY(); } u64 TextureCacheBase::TCacheEntryBase::CalculateHash() const { - u8* ptr = Memory::GetPointer(addr); - if (memory_stride == BytesPerRow()) - { - return GetHash64(ptr, size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); - } - else - { - u32 blocks = NumBlocksY(); - u64 temp_hash = size_in_bytes; + u8* ptr = Memory::GetPointer(addr); + if (memory_stride == BytesPerRow()) + { + return GetHash64(ptr, size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); + } + else + { + u32 blocks = NumBlocksY(); + u64 temp_hash = size_in_bytes; - u32 samples_per_row = 0; - if (g_ActiveConfig.iSafeTextureCache_ColorSamples != 0) - { - // Hash at least 4 samples per row to avoid hashing in a bad pattern, like just on the left side of the efb copy - samples_per_row = std::max(g_ActiveConfig.iSafeTextureCache_ColorSamples / blocks, 4u); - } + u32 samples_per_row = 0; + if (g_ActiveConfig.iSafeTextureCache_ColorSamples != 0) + { + // Hash at least 4 samples per row to avoid hashing in a bad pattern, like just on the left + // side of the efb copy + samples_per_row = std::max(g_ActiveConfig.iSafeTextureCache_ColorSamples / blocks, 4u); + } - for (u32 i = 0; i < blocks; i++) - { - // Multiply by a prime number to mix the hash up a bit. This prevents identical blocks from canceling each other out - temp_hash = (temp_hash * 397) ^ GetHash64(ptr, BytesPerRow(), samples_per_row); - ptr += memory_stride; - } - return temp_hash; - } + for (u32 i = 0; i < blocks; i++) + { + // Multiply by a prime number to mix the hash up a bit. This prevents identical blocks from + // canceling each other out + temp_hash = (temp_hash * 397) ^ GetHash64(ptr, BytesPerRow(), samples_per_row); + ptr += memory_stride; + } + return temp_hash; + } } diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h index 0acbdfb361..b3bde3bb0d 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.h +++ b/Source/Core/VideoCommon/TextureCacheBase.h @@ -20,194 +20,202 @@ struct VideoConfig; class TextureCacheBase { public: - struct TCacheEntryConfig - { - constexpr TCacheEntryConfig() = default; + struct TCacheEntryConfig + { + constexpr TCacheEntryConfig() = default; - bool operator==(const TCacheEntryConfig& o) const - { - return std::tie(width, height, levels, layers, rendertarget) == - std::tie(o.width, o.height, o.levels, o.layers, o.rendertarget); - } + bool operator==(const TCacheEntryConfig& o) const + { + return std::tie(width, height, levels, layers, rendertarget) == + std::tie(o.width, o.height, o.levels, o.layers, o.rendertarget); + } - struct Hasher : std::hash - { - size_t operator()(const TCacheEntryConfig& c) const - { - u64 id = (u64)c.rendertarget << 63 | (u64)c.layers << 48 | (u64)c.levels << 32 | (u64)c.height << 16 | (u64)c.width; - return std::hash::operator()(id); - } - }; + struct Hasher : std::hash + { + size_t operator()(const TCacheEntryConfig& c) const + { + u64 id = (u64)c.rendertarget << 63 | (u64)c.layers << 48 | (u64)c.levels << 32 | + (u64)c.height << 16 | (u64)c.width; + return std::hash::operator()(id); + } + }; - u32 width = 0; - u32 height = 0; - u32 levels = 1; - u32 layers = 1; - bool rendertarget = false; - }; + u32 width = 0; + u32 height = 0; + u32 levels = 1; + u32 layers = 1; + bool rendertarget = false; + }; - struct TCacheEntryBase - { - const TCacheEntryConfig config; + struct TCacheEntryBase + { + const TCacheEntryConfig config; - // common members - u32 addr; - u32 size_in_bytes; - u64 base_hash; - u64 hash; // for paletted textures, hash = base_hash ^ palette_hash - u32 format; // bits 0-3 will contain the in-memory format. - bool is_efb_copy; - bool is_custom_tex; - u32 memory_stride; + // common members + u32 addr; + u32 size_in_bytes; + u64 base_hash; + u64 hash; // for paletted textures, hash = base_hash ^ palette_hash + u32 format; // bits 0-3 will contain the in-memory format. + bool is_efb_copy; + bool is_custom_tex; + u32 memory_stride; - unsigned int native_width, native_height; // Texture dimensions from the GameCube's point of view - unsigned int native_levels; + unsigned int native_width, + native_height; // Texture dimensions from the GameCube's point of view + unsigned int native_levels; - // used to delete textures which haven't been used for TEXTURE_KILL_THRESHOLD frames - int frameCount; + // used to delete textures which haven't been used for TEXTURE_KILL_THRESHOLD frames + int frameCount; - // Keep an iterator to the entry in textures_by_hash, so it does not need to be searched when removing the cache entry - std::multimap::iterator textures_by_hash_iter; + // Keep an iterator to the entry in textures_by_hash, so it does not need to be searched when + // removing the cache entry + std::multimap::iterator textures_by_hash_iter; - // This is used to keep track of both: - // * efb copies used by this partially updated texture - // * partially updated textures which refer to this efb copy - std::unordered_set references; + // This is used to keep track of both: + // * efb copies used by this partially updated texture + // * partially updated textures which refer to this efb copy + std::unordered_set references; - void SetGeneralParameters(u32 _addr, u32 _size, u32 _format) - { - addr = _addr; - size_in_bytes = _size; - format = _format; - } + void SetGeneralParameters(u32 _addr, u32 _size, u32 _format) + { + addr = _addr; + size_in_bytes = _size; + format = _format; + } - void SetDimensions(unsigned int _native_width, unsigned int _native_height, unsigned int _native_levels) - { - native_width = _native_width; - native_height = _native_height; - native_levels = _native_levels; - memory_stride = _native_width; - } + void SetDimensions(unsigned int _native_width, unsigned int _native_height, + unsigned int _native_levels) + { + native_width = _native_width; + native_height = _native_height; + native_levels = _native_levels; + memory_stride = _native_width; + } - void SetHashes(u64 _base_hash, u64 _hash) - { - base_hash = _base_hash; - hash = _hash; - } + void SetHashes(u64 _base_hash, u64 _hash) + { + base_hash = _base_hash; + hash = _hash; + } - // This texture entry is used by the other entry as a sub-texture - void CreateReference(TCacheEntryBase* other_entry) - { - // References are two-way, so they can easily be destroyed later - this->references.emplace(other_entry); - other_entry->references.emplace(this); - } + // This texture entry is used by the other entry as a sub-texture + void CreateReference(TCacheEntryBase* other_entry) + { + // References are two-way, so they can easily be destroyed later + this->references.emplace(other_entry); + other_entry->references.emplace(this); + } - void DestroyAllReferences() - { - for (auto& reference : references) - reference->references.erase(this); + void DestroyAllReferences() + { + for (auto& reference : references) + reference->references.erase(this); - references.clear(); - } + references.clear(); + } - void SetEfbCopy(u32 stride); + void SetEfbCopy(u32 stride); - TCacheEntryBase(const TCacheEntryConfig& c) : config(c) {} - virtual ~TCacheEntryBase(); + TCacheEntryBase(const TCacheEntryConfig& c) : config(c) {} + virtual ~TCacheEntryBase(); - virtual void Bind(unsigned int stage) = 0; - virtual bool Save(const std::string& filename, unsigned int level) = 0; + virtual void Bind(unsigned int stage) = 0; + virtual bool Save(const std::string& filename, unsigned int level) = 0; - virtual void CopyRectangleFromTexture( - const TCacheEntryBase* source, - const MathUtil::Rectangle &srcrect, - const MathUtil::Rectangle &dstrect) = 0; + virtual void CopyRectangleFromTexture(const TCacheEntryBase* source, + const MathUtil::Rectangle& srcrect, + const MathUtil::Rectangle& dstrect) = 0; - virtual void Load(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int level) = 0; - virtual void FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool scaleByHalf, unsigned int cbufid, const float *colmat) = 0; + virtual void Load(unsigned int width, unsigned int height, unsigned int expanded_width, + unsigned int level) = 0; + virtual void FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat, + const EFBRectangle& srcRect, bool scaleByHalf, + unsigned int cbufid, const float* colmat) = 0; - bool OverlapsMemoryRange(u32 range_address, u32 range_size) const; + bool OverlapsMemoryRange(u32 range_address, u32 range_size) const; - TextureCacheBase::TCacheEntryBase* ApplyPalette(u8* palette, u32 tlutfmt); + TextureCacheBase::TCacheEntryBase* ApplyPalette(u8* palette, u32 tlutfmt); - bool IsEfbCopy() const { return is_efb_copy; } + bool IsEfbCopy() const { return is_efb_copy; } + u32 NumBlocksY() const; + u32 BytesPerRow() const; - u32 NumBlocksY() const; - u32 BytesPerRow() const; + u64 CalculateHash() const; + }; - u64 CalculateHash() const; - }; + virtual ~TextureCacheBase(); // needs virtual for DX11 dtor - virtual ~TextureCacheBase(); // needs virtual for DX11 dtor + static void OnConfigChanged(VideoConfig& config); - static void OnConfigChanged(VideoConfig& config); + // Removes textures which aren't used for more than TEXTURE_KILL_THRESHOLD frames, + // frameCount is the current frame number. + static void Cleanup(int _frameCount); - // Removes textures which aren't used for more than TEXTURE_KILL_THRESHOLD frames, - // frameCount is the current frame number. - static void Cleanup(int _frameCount); + static void Invalidate(); - static void Invalidate(); + virtual TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) = 0; - virtual TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) = 0; + virtual void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, + u32 memory_stride, PEControl::PixelFormat srcFormat, + const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) = 0; - virtual void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, - bool isIntensity, bool scaleByHalf) = 0; + virtual void CompileShaders() = 0; // currently only implemented by OGL + virtual void DeleteShaders() = 0; // currently only implemented by OGL - virtual void CompileShaders() = 0; // currently only implemented by OGL - virtual void DeleteShaders() = 0; // currently only implemented by OGL + static TCacheEntryBase* Load(const u32 stage); + static void UnbindTextures(); + virtual void BindTextures(); + static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, u32 dstStride, + PEControl::PixelFormat srcFormat, + const EFBRectangle& srcRect, bool isIntensity, + bool scaleByHalf); - static TCacheEntryBase* Load(const u32 stage); - static void UnbindTextures(); - virtual void BindTextures(); - static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, u32 dstStride, - PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf); - - virtual void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format) = 0; + virtual void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, + TlutFormat format) = 0; protected: - TextureCacheBase(); + TextureCacheBase(); - alignas(16) static u8* temp; - static size_t temp_size; + alignas(16) static u8* temp; + static size_t temp_size; - static TCacheEntryBase* bound_textures[8]; + static TCacheEntryBase* bound_textures[8]; private: - typedef std::multimap TexCache; - typedef std::unordered_multimap TexPool; - static void ScaleTextureCacheEntryTo(TCacheEntryBase** entry, u32 new_width, u32 new_height); - static TCacheEntryBase* DoPartialTextureUpdates(TexCache::iterator iter, u8* palette, u32 tlutfmt); - static void DumpTexture(TCacheEntryBase* entry, std::string basename, unsigned int level); - static void CheckTempSize(size_t required_size); + typedef std::multimap TexCache; + typedef std::unordered_multimap + TexPool; + static void ScaleTextureCacheEntryTo(TCacheEntryBase** entry, u32 new_width, u32 new_height); + static TCacheEntryBase* DoPartialTextureUpdates(TexCache::iterator iter, u8* palette, + u32 tlutfmt); + static void DumpTexture(TCacheEntryBase* entry, std::string basename, unsigned int level); + static void CheckTempSize(size_t required_size); - static TCacheEntryBase* AllocateTexture(const TCacheEntryConfig& config); - static TexCache::iterator GetTexCacheIter(TCacheEntryBase* entry); + static TCacheEntryBase* AllocateTexture(const TCacheEntryConfig& config); + static TexCache::iterator GetTexCacheIter(TCacheEntryBase* entry); - // Removes and unlinks texture from texture cache and returns it to the pool - static TexCache::iterator InvalidateTexture(TexCache::iterator t_iter); + // Removes and unlinks texture from texture cache and returns it to the pool + static TexCache::iterator InvalidateTexture(TexCache::iterator t_iter); - static TCacheEntryBase* ReturnEntry(unsigned int stage, TCacheEntryBase* entry); + static TCacheEntryBase* ReturnEntry(unsigned int stage, TCacheEntryBase* entry); - static TexCache textures_by_address; - static TexCache textures_by_hash; - static TexPool texture_pool; + static TexCache textures_by_address; + static TexCache textures_by_hash; + static TexPool texture_pool; - // Backup configuration values - static struct BackupConfig - { - int s_colorsamples; - bool s_texfmt_overlay; - bool s_texfmt_overlay_center; - bool s_hires_textures; - bool s_cache_hires_textures; - bool s_copy_cache_enable; - bool s_stereo_3d; - bool s_efb_mono_depth; - } backup_config; + // Backup configuration values + static struct BackupConfig + { + int s_colorsamples; + bool s_texfmt_overlay; + bool s_texfmt_overlay_center; + bool s_hires_textures; + bool s_cache_hires_textures; + bool s_copy_cache_enable; + bool s_stereo_3d; + bool s_efb_mono_depth; + } backup_config; }; extern std::unique_ptr g_texture_cache; diff --git a/Source/Core/VideoCommon/TextureConversionShader.cpp b/Source/Core/VideoCommon/TextureConversionShader.cpp index 0358fb0075..fcc9fb60d2 100644 --- a/Source/Core/VideoCommon/TextureConversionShader.cpp +++ b/Source/Core/VideoCommon/TextureConversionShader.cpp @@ -12,670 +12,694 @@ #include "VideoCommon/TextureConversionShader.h" #include "VideoCommon/TextureDecoder.h" -#define WRITE p+=sprintf +#define WRITE p += sprintf static char text[16384]; -static bool IntensityConstantAdded = false; +static bool IntensityConstantAdded = false; namespace TextureConversionShader { - u16 GetEncodedSampleCount(u32 format) { - switch (format) - { - case GX_TF_I4: return 8; - case GX_TF_I8: return 4; - case GX_TF_IA4: return 4; - case GX_TF_IA8: return 2; - case GX_TF_RGB565: return 2; - case GX_TF_RGB5A3: return 2; - case GX_TF_RGBA8: return 1; - case GX_CTF_R4: return 8; - case GX_CTF_RA4: return 4; - case GX_CTF_RA8: return 2; - case GX_CTF_A8: return 4; - case GX_CTF_R8: return 4; - case GX_CTF_G8: return 4; - case GX_CTF_B8: return 4; - case GX_CTF_RG8: return 2; - case GX_CTF_GB8: return 2; - case GX_TF_Z8: return 4; - case GX_TF_Z16: return 2; - case GX_TF_Z24X8: return 1; - case GX_CTF_Z4: return 8; - case GX_CTF_Z8M: return 4; - case GX_CTF_Z8L: return 4; - case GX_CTF_Z16L: return 2; - default: return 1; - } + switch (format) + { + case GX_TF_I4: + return 8; + case GX_TF_I8: + return 4; + case GX_TF_IA4: + return 4; + case GX_TF_IA8: + return 2; + case GX_TF_RGB565: + return 2; + case GX_TF_RGB5A3: + return 2; + case GX_TF_RGBA8: + return 1; + case GX_CTF_R4: + return 8; + case GX_CTF_RA4: + return 4; + case GX_CTF_RA8: + return 2; + case GX_CTF_A8: + return 4; + case GX_CTF_R8: + return 4; + case GX_CTF_G8: + return 4; + case GX_CTF_B8: + return 4; + case GX_CTF_RG8: + return 2; + case GX_CTF_GB8: + return 2; + case GX_TF_Z8: + return 4; + case GX_TF_Z16: + return 2; + case GX_TF_Z24X8: + return 1; + case GX_CTF_Z4: + return 8; + case GX_CTF_Z8M: + return 4; + case GX_CTF_Z8L: + return 4; + case GX_CTF_Z16L: + return 2; + default: + return 1; + } } // block dimensions : widthStride, heightStride // texture dims : width, height, x offset, y offset static void WriteSwizzler(char*& p, u32 format, API_TYPE ApiType) { - // left, top, of source rectangle within source texture - // width of the destination rectangle, scale_factor (1 or 2) - WRITE(p, "uniform int4 position;\n"); + // left, top, of source rectangle within source texture + // width of the destination rectangle, scale_factor (1 or 2) + WRITE(p, "uniform int4 position;\n"); - int blkW = TexDecoder_GetBlockWidthInTexels(format); - int blkH = TexDecoder_GetBlockHeightInTexels(format); - int samples = GetEncodedSampleCount(format); + int blkW = TexDecoder_GetBlockWidthInTexels(format); + int blkH = TexDecoder_GetBlockHeightInTexels(format); + int samples = GetEncodedSampleCount(format); - if (ApiType == API_OPENGL) - { - WRITE(p, "#define samp0 samp9\n"); - WRITE(p, "SAMPLER_BINDING(9) uniform sampler2DArray samp0;\n"); + if (ApiType == API_OPENGL) + { + WRITE(p, "#define samp0 samp9\n"); + WRITE(p, "SAMPLER_BINDING(9) uniform sampler2DArray samp0;\n"); - WRITE(p, " out vec4 ocol0;\n"); - WRITE(p, "void main()\n"); - WRITE(p, "{\n" - " int2 sampleUv;\n" - " int2 uv1 = int2(gl_FragCoord.xy);\n" - ); - } - else // D3D - { - WRITE(p, "sampler samp0 : register(s0);\n"); - WRITE(p, "Texture2DArray Tex0 : register(t0);\n"); + WRITE(p, " out vec4 ocol0;\n"); + WRITE(p, "void main()\n"); + WRITE(p, "{\n" + " int2 sampleUv;\n" + " int2 uv1 = int2(gl_FragCoord.xy);\n"); + } + else // D3D + { + WRITE(p, "sampler samp0 : register(s0);\n"); + WRITE(p, "Texture2DArray Tex0 : register(t0);\n"); - WRITE(p, "void main(\n"); - WRITE(p, " out float4 ocol0 : SV_Target, in float4 rawpos : SV_Position)\n"); - WRITE(p, "{\n" - " int2 sampleUv;\n" - " int2 uv1 = int2(rawpos.xy);\n" - ); - } + WRITE(p, "void main(\n"); + WRITE(p, " out float4 ocol0 : SV_Target, in float4 rawpos : SV_Position)\n"); + WRITE(p, "{\n" + " int2 sampleUv;\n" + " int2 uv1 = int2(rawpos.xy);\n"); + } - WRITE(p, " int x_block_position = (uv1.x >> %d) << %d;\n", IntLog2(blkH * blkW / samples), IntLog2(blkW)); - WRITE(p, " int y_block_position = uv1.y << %d;\n", IntLog2(blkH)); - if (samples == 1) - { - // With samples == 1, we write out pairs of blocks; one A8R8, one G8B8. - WRITE(p, " bool first = (uv1.x & %d) == 0;\n", blkH * blkW / 2); - samples = 2; - } - WRITE(p, " int offset_in_block = uv1.x & %d;\n", (blkH * blkW / samples) - 1); - WRITE(p, " int y_offset_in_block = offset_in_block >> %d;\n", IntLog2(blkW / samples)); - WRITE(p, " int x_offset_in_block = (offset_in_block & %d) << %d;\n", (blkW / samples) - 1, IntLog2(samples)); + WRITE(p, " int x_block_position = (uv1.x >> %d) << %d;\n", IntLog2(blkH * blkW / samples), + IntLog2(blkW)); + WRITE(p, " int y_block_position = uv1.y << %d;\n", IntLog2(blkH)); + if (samples == 1) + { + // With samples == 1, we write out pairs of blocks; one A8R8, one G8B8. + WRITE(p, " bool first = (uv1.x & %d) == 0;\n", blkH * blkW / 2); + samples = 2; + } + WRITE(p, " int offset_in_block = uv1.x & %d;\n", (blkH * blkW / samples) - 1); + WRITE(p, " int y_offset_in_block = offset_in_block >> %d;\n", IntLog2(blkW / samples)); + WRITE(p, " int x_offset_in_block = (offset_in_block & %d) << %d;\n", (blkW / samples) - 1, + IntLog2(samples)); - WRITE(p, " sampleUv.x = x_block_position + x_offset_in_block;\n"); - WRITE(p, " sampleUv.y = y_block_position + y_offset_in_block;\n"); + WRITE(p, " sampleUv.x = x_block_position + x_offset_in_block;\n"); + WRITE(p, " sampleUv.y = y_block_position + y_offset_in_block;\n"); - WRITE(p, " float2 uv0 = float2(sampleUv);\n"); // sampleUv is the sample position in (int)gx_coords - WRITE(p, " uv0 += float2(0.5, 0.5);\n"); // move to center of pixel - WRITE(p, " uv0 *= float(position.w);\n"); // scale by two if needed (also move to pixel borders so that linear filtering will average adjacent pixel) - WRITE(p, " uv0 += float2(position.xy);\n"); // move to copied rect - WRITE(p, " uv0 /= float2(%d, %d);\n", EFB_WIDTH, EFB_HEIGHT); // normalize to [0:1] - if (ApiType == API_OPENGL) // ogl has to flip up and down - { - WRITE(p, " uv0.y = 1.0-uv0.y;\n"); - } + WRITE(p, + " float2 uv0 = float2(sampleUv);\n"); // sampleUv is the sample position in (int)gx_coords + WRITE(p, " uv0 += float2(0.5, 0.5);\n"); // move to center of pixel + WRITE(p, " uv0 *= float(position.w);\n"); // scale by two if needed (also move to pixel borders + // so that linear filtering will average adjacent + // pixel) + WRITE(p, " uv0 += float2(position.xy);\n"); // move to copied rect + WRITE(p, " uv0 /= float2(%d, %d);\n", EFB_WIDTH, EFB_HEIGHT); // normalize to [0:1] + if (ApiType == API_OPENGL) // ogl has to flip up and down + { + WRITE(p, " uv0.y = 1.0-uv0.y;\n"); + } - WRITE(p, " float sample_offset = float(position.w) / float(%d);\n", EFB_WIDTH); + WRITE(p, " float sample_offset = float(position.w) / float(%d);\n", EFB_WIDTH); } -static void WriteSampleColor(char*& p, const char* colorComp, const char* dest, int xoffset, API_TYPE ApiType, bool depth = false) +static void WriteSampleColor(char*& p, const char* colorComp, const char* dest, int xoffset, + API_TYPE ApiType, bool depth = false) { - if (ApiType == API_OPENGL) - { - WRITE(p, " %s = texture(samp0, float3(uv0 + float2(%d, 0) * sample_offset, 0.0)).%s;\n", - dest, xoffset, colorComp - ); - } - else - { - WRITE(p, " %s = Tex0.Sample(samp0, float3(uv0 + float2(%d, 0) * sample_offset, 0.0)).%s;\n", - dest, xoffset, colorComp - ); + if (ApiType == API_OPENGL) + { + WRITE(p, " %s = texture(samp0, float3(uv0 + float2(%d, 0) * sample_offset, 0.0)).%s;\n", dest, + xoffset, colorComp); + } + else + { + WRITE(p, " %s = Tex0.Sample(samp0, float3(uv0 + float2(%d, 0) * sample_offset, 0.0)).%s;\n", + dest, xoffset, colorComp); - // Handle D3D depth inversion. - if (depth) - WRITE(p, " %s = 1.0f - %s;\n", dest, dest); - } + // Handle D3D depth inversion. + if (depth) + WRITE(p, " %s = 1.0f - %s;\n", dest, dest); + } } static void WriteColorToIntensity(char*& p, const char* src, const char* dest) { - if (!IntensityConstantAdded) - { - WRITE(p, " float4 IntensityConst = float4(0.257f,0.504f,0.098f,0.0625f);\n"); - IntensityConstantAdded = true; - } - WRITE(p, " %s = dot(IntensityConst.rgb, %s.rgb);\n", dest, src); - // don't add IntensityConst.a yet, because doing it later is faster and uses less instructions, due to vectorization + if (!IntensityConstantAdded) + { + WRITE(p, " float4 IntensityConst = float4(0.257f,0.504f,0.098f,0.0625f);\n"); + IntensityConstantAdded = true; + } + WRITE(p, " %s = dot(IntensityConst.rgb, %s.rgb);\n", dest, src); + // don't add IntensityConst.a yet, because doing it later is faster and uses less instructions, + // due to vectorization } static void WriteToBitDepth(char*& p, u8 depth, const char* src, const char* dest) { - WRITE(p, " %s = floor(%s * 255.0 / exp2(8.0 - %d.0));\n", dest, src, depth); + WRITE(p, " %s = floor(%s * 255.0 / exp2(8.0 - %d.0));\n", dest, src, depth); } static void WriteEncoderEnd(char*& p) { - WRITE(p, "}\n"); - IntensityConstantAdded = false; + WRITE(p, "}\n"); + IntensityConstantAdded = false; } static void WriteI8Encoder(char*& p, API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_I8, ApiType); - WRITE(p, " float3 texSample;\n"); + WriteSwizzler(p, GX_TF_I8, ApiType); + WRITE(p, " float3 texSample;\n"); - WriteSampleColor(p, "rgb", "texSample", 0, ApiType); - WriteColorToIntensity(p, "texSample", "ocol0.b"); + WriteSampleColor(p, "rgb", "texSample", 0, ApiType); + WriteColorToIntensity(p, "texSample", "ocol0.b"); - WriteSampleColor(p, "rgb", "texSample", 1, ApiType); - WriteColorToIntensity(p, "texSample", "ocol0.g"); + WriteSampleColor(p, "rgb", "texSample", 1, ApiType); + WriteColorToIntensity(p, "texSample", "ocol0.g"); - WriteSampleColor(p, "rgb", "texSample", 2, ApiType); - WriteColorToIntensity(p, "texSample", "ocol0.r"); + WriteSampleColor(p, "rgb", "texSample", 2, ApiType); + WriteColorToIntensity(p, "texSample", "ocol0.r"); - WriteSampleColor(p, "rgb", "texSample", 3, ApiType); - WriteColorToIntensity(p, "texSample", "ocol0.a"); + WriteSampleColor(p, "rgb", "texSample", 3, ApiType); + WriteColorToIntensity(p, "texSample", "ocol0.a"); - WRITE(p, " ocol0.rgba += IntensityConst.aaaa;\n"); // see WriteColorToIntensity + WRITE(p, " ocol0.rgba += IntensityConst.aaaa;\n"); // see WriteColorToIntensity - WriteEncoderEnd(p); + WriteEncoderEnd(p); } static void WriteI4Encoder(char*& p, API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_I4, ApiType); - WRITE(p, " float3 texSample;\n"); - WRITE(p, " float4 color0;\n"); - WRITE(p, " float4 color1;\n"); + WriteSwizzler(p, GX_TF_I4, ApiType); + WRITE(p, " float3 texSample;\n"); + WRITE(p, " float4 color0;\n"); + WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, "rgb", "texSample", 0, ApiType); - WriteColorToIntensity(p, "texSample", "color0.b"); + WriteSampleColor(p, "rgb", "texSample", 0, ApiType); + WriteColorToIntensity(p, "texSample", "color0.b"); - WriteSampleColor(p, "rgb", "texSample", 1, ApiType); - WriteColorToIntensity(p, "texSample", "color1.b"); + WriteSampleColor(p, "rgb", "texSample", 1, ApiType); + WriteColorToIntensity(p, "texSample", "color1.b"); - WriteSampleColor(p, "rgb", "texSample", 2, ApiType); - WriteColorToIntensity(p, "texSample", "color0.g"); + WriteSampleColor(p, "rgb", "texSample", 2, ApiType); + WriteColorToIntensity(p, "texSample", "color0.g"); - WriteSampleColor(p, "rgb", "texSample", 3, ApiType); - WriteColorToIntensity(p, "texSample", "color1.g"); + WriteSampleColor(p, "rgb", "texSample", 3, ApiType); + WriteColorToIntensity(p, "texSample", "color1.g"); - WriteSampleColor(p, "rgb", "texSample", 4, ApiType); - WriteColorToIntensity(p, "texSample", "color0.r"); + WriteSampleColor(p, "rgb", "texSample", 4, ApiType); + WriteColorToIntensity(p, "texSample", "color0.r"); - WriteSampleColor(p, "rgb", "texSample", 5, ApiType); - WriteColorToIntensity(p, "texSample", "color1.r"); + WriteSampleColor(p, "rgb", "texSample", 5, ApiType); + WriteColorToIntensity(p, "texSample", "color1.r"); - WriteSampleColor(p, "rgb", "texSample", 6, ApiType); - WriteColorToIntensity(p, "texSample", "color0.a"); + WriteSampleColor(p, "rgb", "texSample", 6, ApiType); + WriteColorToIntensity(p, "texSample", "color0.a"); - WriteSampleColor(p, "rgb", "texSample", 7, ApiType); - WriteColorToIntensity(p, "texSample", "color1.a"); + WriteSampleColor(p, "rgb", "texSample", 7, ApiType); + WriteColorToIntensity(p, "texSample", "color1.a"); - WRITE(p, " color0.rgba += IntensityConst.aaaa;\n"); - WRITE(p, " color1.rgba += IntensityConst.aaaa;\n"); + WRITE(p, " color0.rgba += IntensityConst.aaaa;\n"); + WRITE(p, " color1.rgba += IntensityConst.aaaa;\n"); - WriteToBitDepth(p, 4, "color0", "color0"); - WriteToBitDepth(p, 4, "color1", "color1"); + WriteToBitDepth(p, 4, "color0", "color0"); + WriteToBitDepth(p, 4, "color1", "color1"); - WRITE(p, " ocol0 = (color0 * 16.0 + color1) / 255.0;\n"); - WriteEncoderEnd(p); + WRITE(p, " ocol0 = (color0 * 16.0 + color1) / 255.0;\n"); + WriteEncoderEnd(p); } -static void WriteIA8Encoder(char*& p,API_TYPE ApiType) +static void WriteIA8Encoder(char*& p, API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_IA8, ApiType); - WRITE(p, " float4 texSample;\n"); + WriteSwizzler(p, GX_TF_IA8, ApiType); + WRITE(p, " float4 texSample;\n"); - WriteSampleColor(p, "rgba", "texSample", 0, ApiType); - WRITE(p, " ocol0.b = texSample.a;\n"); - WriteColorToIntensity(p, "texSample", "ocol0.g"); + WriteSampleColor(p, "rgba", "texSample", 0, ApiType); + WRITE(p, " ocol0.b = texSample.a;\n"); + WriteColorToIntensity(p, "texSample", "ocol0.g"); - WriteSampleColor(p, "rgba", "texSample", 1, ApiType); - WRITE(p, " ocol0.r = texSample.a;\n"); - WriteColorToIntensity(p, "texSample", "ocol0.a"); + WriteSampleColor(p, "rgba", "texSample", 1, ApiType); + WRITE(p, " ocol0.r = texSample.a;\n"); + WriteColorToIntensity(p, "texSample", "ocol0.a"); - WRITE(p, " ocol0.ga += IntensityConst.aa;\n"); + WRITE(p, " ocol0.ga += IntensityConst.aa;\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p); } -static void WriteIA4Encoder(char*& p,API_TYPE ApiType) +static void WriteIA4Encoder(char*& p, API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_IA4, ApiType); - WRITE(p, " float4 texSample;\n"); - WRITE(p, " float4 color0;\n"); - WRITE(p, " float4 color1;\n"); + WriteSwizzler(p, GX_TF_IA4, ApiType); + WRITE(p, " float4 texSample;\n"); + WRITE(p, " float4 color0;\n"); + WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, "rgba", "texSample", 0, ApiType); - WRITE(p, " color0.b = texSample.a;\n"); - WriteColorToIntensity(p, "texSample", "color1.b"); + WriteSampleColor(p, "rgba", "texSample", 0, ApiType); + WRITE(p, " color0.b = texSample.a;\n"); + WriteColorToIntensity(p, "texSample", "color1.b"); - WriteSampleColor(p, "rgba", "texSample", 1, ApiType); - WRITE(p, " color0.g = texSample.a;\n"); - WriteColorToIntensity(p, "texSample", "color1.g"); + WriteSampleColor(p, "rgba", "texSample", 1, ApiType); + WRITE(p, " color0.g = texSample.a;\n"); + WriteColorToIntensity(p, "texSample", "color1.g"); - WriteSampleColor(p, "rgba", "texSample", 2, ApiType); - WRITE(p, " color0.r = texSample.a;\n"); - WriteColorToIntensity(p, "texSample", "color1.r"); + WriteSampleColor(p, "rgba", "texSample", 2, ApiType); + WRITE(p, " color0.r = texSample.a;\n"); + WriteColorToIntensity(p, "texSample", "color1.r"); - WriteSampleColor(p, "rgba", "texSample", 3, ApiType); - WRITE(p, " color0.a = texSample.a;\n"); - WriteColorToIntensity(p, "texSample", "color1.a"); + WriteSampleColor(p, "rgba", "texSample", 3, ApiType); + WRITE(p, " color0.a = texSample.a;\n"); + WriteColorToIntensity(p, "texSample", "color1.a"); - WRITE(p, " color1.rgba += IntensityConst.aaaa;\n"); + WRITE(p, " color1.rgba += IntensityConst.aaaa;\n"); - WriteToBitDepth(p, 4, "color0", "color0"); - WriteToBitDepth(p, 4, "color1", "color1"); + WriteToBitDepth(p, 4, "color0", "color0"); + WriteToBitDepth(p, 4, "color1", "color1"); - WRITE(p, " ocol0 = (color0 * 16.0 + color1) / 255.0;\n"); - WriteEncoderEnd(p); + WRITE(p, " ocol0 = (color0 * 16.0 + color1) / 255.0;\n"); + WriteEncoderEnd(p); } -static void WriteRGB565Encoder(char*& p,API_TYPE ApiType) +static void WriteRGB565Encoder(char*& p, API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_RGB565, ApiType); + WriteSwizzler(p, GX_TF_RGB565, ApiType); - WriteSampleColor(p, "rgb", "float3 texSample0", 0, ApiType); - WriteSampleColor(p, "rgb", "float3 texSample1", 1, ApiType); - WRITE(p, " float2 texRs = float2(texSample0.r, texSample1.r);\n"); - WRITE(p, " float2 texGs = float2(texSample0.g, texSample1.g);\n"); - WRITE(p, " float2 texBs = float2(texSample0.b, texSample1.b);\n"); + WriteSampleColor(p, "rgb", "float3 texSample0", 0, ApiType); + WriteSampleColor(p, "rgb", "float3 texSample1", 1, ApiType); + WRITE(p, " float2 texRs = float2(texSample0.r, texSample1.r);\n"); + WRITE(p, " float2 texGs = float2(texSample0.g, texSample1.g);\n"); + WRITE(p, " float2 texBs = float2(texSample0.b, texSample1.b);\n"); - WriteToBitDepth(p, 6, "texGs", "float2 gInt"); - WRITE(p, " float2 gUpper = floor(gInt / 8.0);\n"); - WRITE(p, " float2 gLower = gInt - gUpper * 8.0;\n"); + WriteToBitDepth(p, 6, "texGs", "float2 gInt"); + WRITE(p, " float2 gUpper = floor(gInt / 8.0);\n"); + WRITE(p, " float2 gLower = gInt - gUpper * 8.0;\n"); - WriteToBitDepth(p, 5, "texRs", "ocol0.br"); - WRITE(p, " ocol0.br = ocol0.br * 8.0 + gUpper;\n"); - WriteToBitDepth(p, 5, "texBs", "ocol0.ga"); - WRITE(p, " ocol0.ga = ocol0.ga + gLower * 32.0;\n"); + WriteToBitDepth(p, 5, "texRs", "ocol0.br"); + WRITE(p, " ocol0.br = ocol0.br * 8.0 + gUpper;\n"); + WriteToBitDepth(p, 5, "texBs", "ocol0.ga"); + WRITE(p, " ocol0.ga = ocol0.ga + gLower * 32.0;\n"); - WRITE(p, " ocol0 = ocol0 / 255.0;\n"); - WriteEncoderEnd(p); + WRITE(p, " ocol0 = ocol0 / 255.0;\n"); + WriteEncoderEnd(p); } -static void WriteRGB5A3Encoder(char*& p,API_TYPE ApiType) +static void WriteRGB5A3Encoder(char*& p, API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_RGB5A3, ApiType); + WriteSwizzler(p, GX_TF_RGB5A3, ApiType); - WRITE(p, " float4 texSample;\n"); - WRITE(p, " float color0;\n"); - WRITE(p, " float gUpper;\n"); - WRITE(p, " float gLower;\n"); + WRITE(p, " float4 texSample;\n"); + WRITE(p, " float color0;\n"); + WRITE(p, " float gUpper;\n"); + WRITE(p, " float gLower;\n"); - WriteSampleColor(p, "rgba", "texSample", 0, ApiType); + WriteSampleColor(p, "rgba", "texSample", 0, ApiType); - // 0.8784 = 224 / 255 which is the maximum alpha value that can be represented in 3 bits - WRITE(p, "if(texSample.a > 0.878f) {\n"); + // 0.8784 = 224 / 255 which is the maximum alpha value that can be represented in 3 bits + WRITE(p, "if(texSample.a > 0.878f) {\n"); - WriteToBitDepth(p, 5, "texSample.g", "color0"); - WRITE(p, " gUpper = floor(color0 / 8.0);\n"); - WRITE(p, " gLower = color0 - gUpper * 8.0;\n"); + WriteToBitDepth(p, 5, "texSample.g", "color0"); + WRITE(p, " gUpper = floor(color0 / 8.0);\n"); + WRITE(p, " gLower = color0 - gUpper * 8.0;\n"); - WriteToBitDepth(p, 5, "texSample.r", "ocol0.b"); - WRITE(p, " ocol0.b = ocol0.b * 4.0 + gUpper + 128.0;\n"); - WriteToBitDepth(p, 5, "texSample.b", "ocol0.g"); - WRITE(p, " ocol0.g = ocol0.g + gLower * 32.0;\n"); + WriteToBitDepth(p, 5, "texSample.r", "ocol0.b"); + WRITE(p, " ocol0.b = ocol0.b * 4.0 + gUpper + 128.0;\n"); + WriteToBitDepth(p, 5, "texSample.b", "ocol0.g"); + WRITE(p, " ocol0.g = ocol0.g + gLower * 32.0;\n"); - WRITE(p, "} else {\n"); + WRITE(p, "} else {\n"); - WriteToBitDepth(p, 4, "texSample.r", "ocol0.b"); - WriteToBitDepth(p, 4, "texSample.b", "ocol0.g"); + WriteToBitDepth(p, 4, "texSample.r", "ocol0.b"); + WriteToBitDepth(p, 4, "texSample.b", "ocol0.g"); - WriteToBitDepth(p, 3, "texSample.a", "color0"); - WRITE(p, "ocol0.b = ocol0.b + color0 * 16.0;\n"); - WriteToBitDepth(p, 4, "texSample.g", "color0"); - WRITE(p, "ocol0.g = ocol0.g + color0 * 16.0;\n"); + WriteToBitDepth(p, 3, "texSample.a", "color0"); + WRITE(p, "ocol0.b = ocol0.b + color0 * 16.0;\n"); + WriteToBitDepth(p, 4, "texSample.g", "color0"); + WRITE(p, "ocol0.g = ocol0.g + color0 * 16.0;\n"); - WRITE(p, "}\n"); + WRITE(p, "}\n"); + WriteSampleColor(p, "rgba", "texSample", 1, ApiType); + WRITE(p, "if(texSample.a > 0.878f) {\n"); - WriteSampleColor(p, "rgba", "texSample", 1, ApiType); + WriteToBitDepth(p, 5, "texSample.g", "color0"); + WRITE(p, " gUpper = floor(color0 / 8.0);\n"); + WRITE(p, " gLower = color0 - gUpper * 8.0;\n"); - WRITE(p, "if(texSample.a > 0.878f) {\n"); + WriteToBitDepth(p, 5, "texSample.r", "ocol0.r"); + WRITE(p, " ocol0.r = ocol0.r * 4.0 + gUpper + 128.0;\n"); + WriteToBitDepth(p, 5, "texSample.b", "ocol0.a"); + WRITE(p, " ocol0.a = ocol0.a + gLower * 32.0;\n"); - WriteToBitDepth(p, 5, "texSample.g", "color0"); - WRITE(p, " gUpper = floor(color0 / 8.0);\n"); - WRITE(p, " gLower = color0 - gUpper * 8.0;\n"); + WRITE(p, "} else {\n"); - WriteToBitDepth(p, 5, "texSample.r", "ocol0.r"); - WRITE(p, " ocol0.r = ocol0.r * 4.0 + gUpper + 128.0;\n"); - WriteToBitDepth(p, 5, "texSample.b", "ocol0.a"); - WRITE(p, " ocol0.a = ocol0.a + gLower * 32.0;\n"); + WriteToBitDepth(p, 4, "texSample.r", "ocol0.r"); + WriteToBitDepth(p, 4, "texSample.b", "ocol0.a"); - WRITE(p, "} else {\n"); + WriteToBitDepth(p, 3, "texSample.a", "color0"); + WRITE(p, "ocol0.r = ocol0.r + color0 * 16.0;\n"); + WriteToBitDepth(p, 4, "texSample.g", "color0"); + WRITE(p, "ocol0.a = ocol0.a + color0 * 16.0;\n"); - WriteToBitDepth(p, 4, "texSample.r", "ocol0.r"); - WriteToBitDepth(p, 4, "texSample.b", "ocol0.a"); + WRITE(p, "}\n"); - WriteToBitDepth(p, 3, "texSample.a", "color0"); - WRITE(p, "ocol0.r = ocol0.r + color0 * 16.0;\n"); - WriteToBitDepth(p, 4, "texSample.g", "color0"); - WRITE(p, "ocol0.a = ocol0.a + color0 * 16.0;\n"); - - WRITE(p, "}\n"); - - WRITE(p, " ocol0 = ocol0 / 255.0;\n"); - WriteEncoderEnd(p); + WRITE(p, " ocol0 = ocol0 / 255.0;\n"); + WriteEncoderEnd(p); } -static void WriteRGBA8Encoder(char*& p,API_TYPE ApiType) +static void WriteRGBA8Encoder(char*& p, API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_RGBA8, ApiType); + WriteSwizzler(p, GX_TF_RGBA8, ApiType); - WRITE(p, " float4 texSample;\n"); - WRITE(p, " float4 color0;\n"); - WRITE(p, " float4 color1;\n"); + WRITE(p, " float4 texSample;\n"); + WRITE(p, " float4 color0;\n"); + WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, "rgba", "texSample", 0, ApiType); - WRITE(p, " color0.b = texSample.a;\n"); - WRITE(p, " color0.g = texSample.r;\n"); - WRITE(p, " color1.b = texSample.g;\n"); - WRITE(p, " color1.g = texSample.b;\n"); + WriteSampleColor(p, "rgba", "texSample", 0, ApiType); + WRITE(p, " color0.b = texSample.a;\n"); + WRITE(p, " color0.g = texSample.r;\n"); + WRITE(p, " color1.b = texSample.g;\n"); + WRITE(p, " color1.g = texSample.b;\n"); - WriteSampleColor(p, "rgba", "texSample", 1, ApiType); - WRITE(p, " color0.r = texSample.a;\n"); - WRITE(p, " color0.a = texSample.r;\n"); - WRITE(p, " color1.r = texSample.g;\n"); - WRITE(p, " color1.a = texSample.b;\n"); + WriteSampleColor(p, "rgba", "texSample", 1, ApiType); + WRITE(p, " color0.r = texSample.a;\n"); + WRITE(p, " color0.a = texSample.r;\n"); + WRITE(p, " color1.r = texSample.g;\n"); + WRITE(p, " color1.a = texSample.b;\n"); - WRITE(p, " ocol0 = first ? color0 : color1;\n"); + WRITE(p, " ocol0 = first ? color0 : color1;\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p); } static void WriteC4Encoder(char*& p, const char* comp, API_TYPE ApiType, bool depth = false) { - WriteSwizzler(p, GX_CTF_R4, ApiType); - WRITE(p, " float4 color0;\n"); - WRITE(p, " float4 color1;\n"); + WriteSwizzler(p, GX_CTF_R4, ApiType); + WRITE(p, " float4 color0;\n"); + WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, comp, "color0.b", 0, ApiType, depth); - WriteSampleColor(p, comp, "color1.b", 1, ApiType, depth); - WriteSampleColor(p, comp, "color0.g", 2, ApiType, depth); - WriteSampleColor(p, comp, "color1.g", 3, ApiType, depth); - WriteSampleColor(p, comp, "color0.r", 4, ApiType, depth); - WriteSampleColor(p, comp, "color1.r", 5, ApiType, depth); - WriteSampleColor(p, comp, "color0.a", 6, ApiType, depth); - WriteSampleColor(p, comp, "color1.a", 7, ApiType, depth); + WriteSampleColor(p, comp, "color0.b", 0, ApiType, depth); + WriteSampleColor(p, comp, "color1.b", 1, ApiType, depth); + WriteSampleColor(p, comp, "color0.g", 2, ApiType, depth); + WriteSampleColor(p, comp, "color1.g", 3, ApiType, depth); + WriteSampleColor(p, comp, "color0.r", 4, ApiType, depth); + WriteSampleColor(p, comp, "color1.r", 5, ApiType, depth); + WriteSampleColor(p, comp, "color0.a", 6, ApiType, depth); + WriteSampleColor(p, comp, "color1.a", 7, ApiType, depth); - WriteToBitDepth(p, 4, "color0", "color0"); - WriteToBitDepth(p, 4, "color1", "color1"); + WriteToBitDepth(p, 4, "color0", "color0"); + WriteToBitDepth(p, 4, "color1", "color1"); - WRITE(p, " ocol0 = (color0 * 16.0 + color1) / 255.0;\n"); - WriteEncoderEnd(p); + WRITE(p, " ocol0 = (color0 * 16.0 + color1) / 255.0;\n"); + WriteEncoderEnd(p); } static void WriteC8Encoder(char*& p, const char* comp, API_TYPE ApiType, bool depth = false) { - WriteSwizzler(p, GX_CTF_R8, ApiType); + WriteSwizzler(p, GX_CTF_R8, ApiType); - WriteSampleColor(p, comp, "ocol0.b", 0, ApiType, depth); - WriteSampleColor(p, comp, "ocol0.g", 1, ApiType, depth); - WriteSampleColor(p, comp, "ocol0.r", 2, ApiType, depth); - WriteSampleColor(p, comp, "ocol0.a", 3, ApiType, depth); + WriteSampleColor(p, comp, "ocol0.b", 0, ApiType, depth); + WriteSampleColor(p, comp, "ocol0.g", 1, ApiType, depth); + WriteSampleColor(p, comp, "ocol0.r", 2, ApiType, depth); + WriteSampleColor(p, comp, "ocol0.a", 3, ApiType, depth); - WriteEncoderEnd(p); + WriteEncoderEnd(p); } -static void WriteCC4Encoder(char*& p, const char* comp,API_TYPE ApiType) +static void WriteCC4Encoder(char*& p, const char* comp, API_TYPE ApiType) { - WriteSwizzler(p, GX_CTF_RA4, ApiType); - WRITE(p, " float2 texSample;\n"); - WRITE(p, " float4 color0;\n"); - WRITE(p, " float4 color1;\n"); + WriteSwizzler(p, GX_CTF_RA4, ApiType); + WRITE(p, " float2 texSample;\n"); + WRITE(p, " float4 color0;\n"); + WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, comp, "texSample", 0, ApiType); - WRITE(p, " color0.b = texSample.x;\n"); - WRITE(p, " color1.b = texSample.y;\n"); + WriteSampleColor(p, comp, "texSample", 0, ApiType); + WRITE(p, " color0.b = texSample.x;\n"); + WRITE(p, " color1.b = texSample.y;\n"); - WriteSampleColor(p, comp, "texSample", 1, ApiType); - WRITE(p, " color0.g = texSample.x;\n"); - WRITE(p, " color1.g = texSample.y;\n"); + WriteSampleColor(p, comp, "texSample", 1, ApiType); + WRITE(p, " color0.g = texSample.x;\n"); + WRITE(p, " color1.g = texSample.y;\n"); - WriteSampleColor(p, comp, "texSample", 2, ApiType); - WRITE(p, " color0.r = texSample.x;\n"); - WRITE(p, " color1.r = texSample.y;\n"); + WriteSampleColor(p, comp, "texSample", 2, ApiType); + WRITE(p, " color0.r = texSample.x;\n"); + WRITE(p, " color1.r = texSample.y;\n"); - WriteSampleColor(p, comp, "texSample", 3, ApiType); - WRITE(p, " color0.a = texSample.x;\n"); - WRITE(p, " color1.a = texSample.y;\n"); + WriteSampleColor(p, comp, "texSample", 3, ApiType); + WRITE(p, " color0.a = texSample.x;\n"); + WRITE(p, " color1.a = texSample.y;\n"); - WriteToBitDepth(p, 4, "color0", "color0"); - WriteToBitDepth(p, 4, "color1", "color1"); + WriteToBitDepth(p, 4, "color0", "color0"); + WriteToBitDepth(p, 4, "color1", "color1"); - WRITE(p, " ocol0 = (color0 * 16.0 + color1) / 255.0;\n"); - WriteEncoderEnd(p); + WRITE(p, " ocol0 = (color0 * 16.0 + color1) / 255.0;\n"); + WriteEncoderEnd(p); } static void WriteCC8Encoder(char*& p, const char* comp, API_TYPE ApiType) { - WriteSwizzler(p, GX_CTF_RA8, ApiType); + WriteSwizzler(p, GX_CTF_RA8, ApiType); - WriteSampleColor(p, comp, "ocol0.bg", 0, ApiType); - WriteSampleColor(p, comp, "ocol0.ra", 1, ApiType); + WriteSampleColor(p, comp, "ocol0.bg", 0, ApiType); + WriteSampleColor(p, comp, "ocol0.ra", 1, ApiType); - WriteEncoderEnd(p); + WriteEncoderEnd(p); } -static void WriteZ8Encoder(char*& p, const char* multiplier,API_TYPE ApiType) +static void WriteZ8Encoder(char*& p, const char* multiplier, API_TYPE ApiType) { - WriteSwizzler(p, GX_CTF_Z8M, ApiType); + WriteSwizzler(p, GX_CTF_Z8M, ApiType); - WRITE(p, " float depth;\n"); + WRITE(p, " float depth;\n"); - WriteSampleColor(p, "r", "depth", 0, ApiType, true); - WRITE(p, "ocol0.b = frac(depth * %s);\n", multiplier); + WriteSampleColor(p, "r", "depth", 0, ApiType, true); + WRITE(p, "ocol0.b = frac(depth * %s);\n", multiplier); - WriteSampleColor(p, "r", "depth", 1, ApiType, true); - WRITE(p, "ocol0.g = frac(depth * %s);\n", multiplier); + WriteSampleColor(p, "r", "depth", 1, ApiType, true); + WRITE(p, "ocol0.g = frac(depth * %s);\n", multiplier); - WriteSampleColor(p, "r", "depth", 2, ApiType, true); - WRITE(p, "ocol0.r = frac(depth * %s);\n", multiplier); + WriteSampleColor(p, "r", "depth", 2, ApiType, true); + WRITE(p, "ocol0.r = frac(depth * %s);\n", multiplier); - WriteSampleColor(p, "r", "depth", 3, ApiType, true); - WRITE(p, "ocol0.a = frac(depth * %s);\n", multiplier); + WriteSampleColor(p, "r", "depth", 3, ApiType, true); + WRITE(p, "ocol0.a = frac(depth * %s);\n", multiplier); - WriteEncoderEnd(p); + WriteEncoderEnd(p); } -static void WriteZ16Encoder(char*& p,API_TYPE ApiType) +static void WriteZ16Encoder(char*& p, API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_Z16, ApiType); + WriteSwizzler(p, GX_TF_Z16, ApiType); - WRITE(p, " float depth;\n"); - WRITE(p, " float3 expanded;\n"); + WRITE(p, " float depth;\n"); + WRITE(p, " float3 expanded;\n"); - // byte order is reversed + // byte order is reversed - WriteSampleColor(p, "r", "depth", 0, ApiType, true); + WriteSampleColor(p, "r", "depth", 0, ApiType, true); - WRITE(p, " depth *= 16777216.0;\n"); - WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n"); - WRITE(p, " depth -= expanded.r * 256.0 * 256.0;\n"); - WRITE(p, " expanded.g = floor(depth / 256.0);\n"); + WRITE(p, " depth *= 16777216.0;\n"); + WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n"); + WRITE(p, " depth -= expanded.r * 256.0 * 256.0;\n"); + WRITE(p, " expanded.g = floor(depth / 256.0);\n"); - WRITE(p, " ocol0.b = expanded.g / 255.0;\n"); - WRITE(p, " ocol0.g = expanded.r / 255.0;\n"); + WRITE(p, " ocol0.b = expanded.g / 255.0;\n"); + WRITE(p, " ocol0.g = expanded.r / 255.0;\n"); - WriteSampleColor(p, "r", "depth", 1, ApiType, true); + WriteSampleColor(p, "r", "depth", 1, ApiType, true); - WRITE(p, " depth *= 16777216.0;\n"); - WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n"); - WRITE(p, " depth -= expanded.r * 256.0 * 256.0;\n"); - WRITE(p, " expanded.g = floor(depth / 256.0);\n"); + WRITE(p, " depth *= 16777216.0;\n"); + WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n"); + WRITE(p, " depth -= expanded.r * 256.0 * 256.0;\n"); + WRITE(p, " expanded.g = floor(depth / 256.0);\n"); - WRITE(p, " ocol0.r = expanded.g / 255.0;\n"); - WRITE(p, " ocol0.a = expanded.r / 255.0;\n"); + WRITE(p, " ocol0.r = expanded.g / 255.0;\n"); + WRITE(p, " ocol0.a = expanded.r / 255.0;\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p); } -static void WriteZ16LEncoder(char*& p,API_TYPE ApiType) +static void WriteZ16LEncoder(char*& p, API_TYPE ApiType) { - WriteSwizzler(p, GX_CTF_Z16L, ApiType); + WriteSwizzler(p, GX_CTF_Z16L, ApiType); - WRITE(p, " float depth;\n"); - WRITE(p, " float3 expanded;\n"); + WRITE(p, " float depth;\n"); + WRITE(p, " float3 expanded;\n"); - // byte order is reversed + // byte order is reversed - WriteSampleColor(p, "r", "depth", 0, ApiType, true); + WriteSampleColor(p, "r", "depth", 0, ApiType, true); - WRITE(p, " depth *= 16777216.0;\n"); - WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n"); - WRITE(p, " depth -= expanded.r * 256.0 * 256.0;\n"); - WRITE(p, " expanded.g = floor(depth / 256.0);\n"); - WRITE(p, " depth -= expanded.g * 256.0;\n"); - WRITE(p, " expanded.b = depth;\n"); + WRITE(p, " depth *= 16777216.0;\n"); + WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n"); + WRITE(p, " depth -= expanded.r * 256.0 * 256.0;\n"); + WRITE(p, " expanded.g = floor(depth / 256.0);\n"); + WRITE(p, " depth -= expanded.g * 256.0;\n"); + WRITE(p, " expanded.b = depth;\n"); - WRITE(p, " ocol0.b = expanded.b / 255.0;\n"); - WRITE(p, " ocol0.g = expanded.g / 255.0;\n"); + WRITE(p, " ocol0.b = expanded.b / 255.0;\n"); + WRITE(p, " ocol0.g = expanded.g / 255.0;\n"); - WriteSampleColor(p, "r", "depth", 1, ApiType, true); + WriteSampleColor(p, "r", "depth", 1, ApiType, true); - WRITE(p, " depth *= 16777216.0;\n"); - WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n"); - WRITE(p, " depth -= expanded.r * 256.0 * 256.0;\n"); - WRITE(p, " expanded.g = floor(depth / 256.0);\n"); - WRITE(p, " depth -= expanded.g * 256.0;\n"); - WRITE(p, " expanded.b = depth;\n"); + WRITE(p, " depth *= 16777216.0;\n"); + WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n"); + WRITE(p, " depth -= expanded.r * 256.0 * 256.0;\n"); + WRITE(p, " expanded.g = floor(depth / 256.0);\n"); + WRITE(p, " depth -= expanded.g * 256.0;\n"); + WRITE(p, " expanded.b = depth;\n"); - WRITE(p, " ocol0.r = expanded.b / 255.0;\n"); - WRITE(p, " ocol0.a = expanded.g / 255.0;\n"); + WRITE(p, " ocol0.r = expanded.b / 255.0;\n"); + WRITE(p, " ocol0.a = expanded.g / 255.0;\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p); } static void WriteZ24Encoder(char*& p, API_TYPE ApiType) { - WriteSwizzler(p, GX_TF_Z24X8, ApiType); + WriteSwizzler(p, GX_TF_Z24X8, ApiType); - WRITE(p, " float depth0;\n"); - WRITE(p, " float depth1;\n"); - WRITE(p, " float3 expanded0;\n"); - WRITE(p, " float3 expanded1;\n"); + WRITE(p, " float depth0;\n"); + WRITE(p, " float depth1;\n"); + WRITE(p, " float3 expanded0;\n"); + WRITE(p, " float3 expanded1;\n"); - WriteSampleColor(p, "r", "depth0", 0, ApiType, true); - WriteSampleColor(p, "r", "depth1", 1, ApiType, true); + WriteSampleColor(p, "r", "depth0", 0, ApiType, true); + WriteSampleColor(p, "r", "depth1", 1, ApiType, true); - for (int i = 0; i < 2; i++) - { - WRITE(p, " depth%i *= 16777216.0;\n", i); + for (int i = 0; i < 2; i++) + { + WRITE(p, " depth%i *= 16777216.0;\n", i); - WRITE(p, " expanded%i.r = floor(depth%i / (256.0 * 256.0));\n", i, i); - WRITE(p, " depth%i -= expanded%i.r * 256.0 * 256.0;\n", i, i); - WRITE(p, " expanded%i.g = floor(depth%i / 256.0);\n", i, i); - WRITE(p, " depth%i -= expanded%i.g * 256.0;\n", i, i); - WRITE(p, " expanded%i.b = depth%i;\n", i, i); - } + WRITE(p, " expanded%i.r = floor(depth%i / (256.0 * 256.0));\n", i, i); + WRITE(p, " depth%i -= expanded%i.r * 256.0 * 256.0;\n", i, i); + WRITE(p, " expanded%i.g = floor(depth%i / 256.0);\n", i, i); + WRITE(p, " depth%i -= expanded%i.g * 256.0;\n", i, i); + WRITE(p, " expanded%i.b = depth%i;\n", i, i); + } - WRITE(p, " if (!first) {\n"); - // upper 16 - WRITE(p, " ocol0.b = expanded0.g / 255.0;\n"); - WRITE(p, " ocol0.g = expanded0.b / 255.0;\n"); - WRITE(p, " ocol0.r = expanded1.g / 255.0;\n"); - WRITE(p, " ocol0.a = expanded1.b / 255.0;\n"); - WRITE(p, " } else {\n"); - // lower 8 - WRITE(p, " ocol0.b = 1.0;\n"); - WRITE(p, " ocol0.g = expanded0.r / 255.0;\n"); - WRITE(p, " ocol0.r = 1.0;\n"); - WRITE(p, " ocol0.a = expanded1.r / 255.0;\n"); - WRITE(p, " }\n"); + WRITE(p, " if (!first) {\n"); + // upper 16 + WRITE(p, " ocol0.b = expanded0.g / 255.0;\n"); + WRITE(p, " ocol0.g = expanded0.b / 255.0;\n"); + WRITE(p, " ocol0.r = expanded1.g / 255.0;\n"); + WRITE(p, " ocol0.a = expanded1.b / 255.0;\n"); + WRITE(p, " } else {\n"); + // lower 8 + WRITE(p, " ocol0.b = 1.0;\n"); + WRITE(p, " ocol0.g = expanded0.r / 255.0;\n"); + WRITE(p, " ocol0.r = 1.0;\n"); + WRITE(p, " ocol0.a = expanded1.r / 255.0;\n"); + WRITE(p, " }\n"); - WriteEncoderEnd(p); + WriteEncoderEnd(p); } -const char *GenerateEncodingShader(u32 format,API_TYPE ApiType) +const char* GenerateEncodingShader(u32 format, API_TYPE ApiType) { - text[sizeof(text) - 1] = 0x7C; // canary + text[sizeof(text) - 1] = 0x7C; // canary - char *p = text; + char* p = text; - switch (format) - { - case GX_TF_I4: - WriteI4Encoder(p, ApiType); - break; - case GX_TF_I8: - WriteI8Encoder(p, ApiType); - break; - case GX_TF_IA4: - WriteIA4Encoder(p, ApiType); - break; - case GX_TF_IA8: - WriteIA8Encoder(p, ApiType); - break; - case GX_TF_RGB565: - WriteRGB565Encoder(p, ApiType); - break; - case GX_TF_RGB5A3: - WriteRGB5A3Encoder(p, ApiType); - break; - case GX_TF_RGBA8: - WriteRGBA8Encoder(p, ApiType); - break; - case GX_CTF_R4: - WriteC4Encoder(p, "r", ApiType); - break; - case GX_CTF_RA4: - WriteCC4Encoder(p, "ar", ApiType); - break; - case GX_CTF_RA8: - WriteCC8Encoder(p, "ar", ApiType); - break; - case GX_CTF_A8: - WriteC8Encoder(p, "a", ApiType); - break; - case GX_CTF_R8: - WriteC8Encoder(p, "r", ApiType); - break; - case GX_CTF_G8: - WriteC8Encoder(p, "g", ApiType); - break; - case GX_CTF_B8: - WriteC8Encoder(p, "b", ApiType); - break; - case GX_CTF_RG8: - WriteCC8Encoder(p, "rg", ApiType); - break; - case GX_CTF_GB8: - WriteCC8Encoder(p, "gb", ApiType); - break; - case GX_CTF_Z8H: - case GX_TF_Z8: - WriteC8Encoder(p, "r", ApiType, true); - break; - case GX_CTF_Z16R: - case GX_TF_Z16: - WriteZ16Encoder(p, ApiType); - break; - case GX_TF_Z24X8: - WriteZ24Encoder(p, ApiType); - break; - case GX_CTF_Z4: - WriteC4Encoder(p, "r", ApiType, true); - break; - case GX_CTF_Z8M: - WriteZ8Encoder(p, "256.0", ApiType); - break; - case GX_CTF_Z8L: - WriteZ8Encoder(p, "65536.0" , ApiType); - break; - case GX_CTF_Z16L: - WriteZ16LEncoder(p, ApiType); - break; - default: - PanicAlert("Unknown texture copy format: 0x%x\n", format); - break; - } + switch (format) + { + case GX_TF_I4: + WriteI4Encoder(p, ApiType); + break; + case GX_TF_I8: + WriteI8Encoder(p, ApiType); + break; + case GX_TF_IA4: + WriteIA4Encoder(p, ApiType); + break; + case GX_TF_IA8: + WriteIA8Encoder(p, ApiType); + break; + case GX_TF_RGB565: + WriteRGB565Encoder(p, ApiType); + break; + case GX_TF_RGB5A3: + WriteRGB5A3Encoder(p, ApiType); + break; + case GX_TF_RGBA8: + WriteRGBA8Encoder(p, ApiType); + break; + case GX_CTF_R4: + WriteC4Encoder(p, "r", ApiType); + break; + case GX_CTF_RA4: + WriteCC4Encoder(p, "ar", ApiType); + break; + case GX_CTF_RA8: + WriteCC8Encoder(p, "ar", ApiType); + break; + case GX_CTF_A8: + WriteC8Encoder(p, "a", ApiType); + break; + case GX_CTF_R8: + WriteC8Encoder(p, "r", ApiType); + break; + case GX_CTF_G8: + WriteC8Encoder(p, "g", ApiType); + break; + case GX_CTF_B8: + WriteC8Encoder(p, "b", ApiType); + break; + case GX_CTF_RG8: + WriteCC8Encoder(p, "rg", ApiType); + break; + case GX_CTF_GB8: + WriteCC8Encoder(p, "gb", ApiType); + break; + case GX_CTF_Z8H: + case GX_TF_Z8: + WriteC8Encoder(p, "r", ApiType, true); + break; + case GX_CTF_Z16R: + case GX_TF_Z16: + WriteZ16Encoder(p, ApiType); + break; + case GX_TF_Z24X8: + WriteZ24Encoder(p, ApiType); + break; + case GX_CTF_Z4: + WriteC4Encoder(p, "r", ApiType, true); + break; + case GX_CTF_Z8M: + WriteZ8Encoder(p, "256.0", ApiType); + break; + case GX_CTF_Z8L: + WriteZ8Encoder(p, "65536.0", ApiType); + break; + case GX_CTF_Z16L: + WriteZ16LEncoder(p, ApiType); + break; + default: + PanicAlert("Unknown texture copy format: 0x%x\n", format); + break; + } - if (text[sizeof(text) - 1] != 0x7C) - PanicAlert("TextureConversionShader generator - buffer too small, canary has been eaten!"); + if (text[sizeof(text) - 1] != 0x7C) + PanicAlert("TextureConversionShader generator - buffer too small, canary has been eaten!"); - return text; + return text; } } // namespace diff --git a/Source/Core/VideoCommon/TextureConversionShader.h b/Source/Core/VideoCommon/TextureConversionShader.h index 22b89114bd..085771e4f1 100644 --- a/Source/Core/VideoCommon/TextureConversionShader.h +++ b/Source/Core/VideoCommon/TextureConversionShader.h @@ -11,6 +11,5 @@ namespace TextureConversionShader { u16 GetEncodedSampleCount(u32 format); -const char *GenerateEncodingShader(u32 format, API_TYPE ApiType = API_OPENGL); - +const char* GenerateEncodingShader(u32 format, API_TYPE ApiType = API_OPENGL); } diff --git a/Source/Core/VideoCommon/TextureDecoder.h b/Source/Core/VideoCommon/TextureDecoder.h index fe88838ec3..44834c0623 100644 --- a/Source/Core/VideoCommon/TextureDecoder.h +++ b/Source/Core/VideoCommon/TextureDecoder.h @@ -8,62 +8,63 @@ enum { - TMEM_SIZE = 1024 * 1024, - TMEM_LINE_SIZE = 32, + TMEM_SIZE = 1024 * 1024, + TMEM_LINE_SIZE = 32, }; alignas(16) extern u8 texMem[TMEM_SIZE]; enum TextureFormat { - // These are the texture formats that can be read by the texture mapper. - GX_TF_I4 = 0x0, - GX_TF_I8 = 0x1, - GX_TF_IA4 = 0x2, - GX_TF_IA8 = 0x3, - GX_TF_RGB565 = 0x4, - GX_TF_RGB5A3 = 0x5, - GX_TF_RGBA8 = 0x6, - GX_TF_C4 = 0x8, - GX_TF_C8 = 0x9, - GX_TF_C14X2 = 0xA, - GX_TF_CMPR = 0xE, + // These are the texture formats that can be read by the texture mapper. + GX_TF_I4 = 0x0, + GX_TF_I8 = 0x1, + GX_TF_IA4 = 0x2, + GX_TF_IA8 = 0x3, + GX_TF_RGB565 = 0x4, + GX_TF_RGB5A3 = 0x5, + GX_TF_RGBA8 = 0x6, + GX_TF_C4 = 0x8, + GX_TF_C8 = 0x9, + GX_TF_C14X2 = 0xA, + GX_TF_CMPR = 0xE, - _GX_TF_ZTF = 0x10, // flag for Z texture formats (used internally by dolphin) + _GX_TF_ZTF = 0x10, // flag for Z texture formats (used internally by dolphin) - // Depth texture formats (which directly map to the equivalent colour format above.) - GX_TF_Z8 = 0x1 | _GX_TF_ZTF, - GX_TF_Z16 = 0x3 | _GX_TF_ZTF, - GX_TF_Z24X8 = 0x6 | _GX_TF_ZTF, + // Depth texture formats (which directly map to the equivalent colour format above.) + GX_TF_Z8 = 0x1 | _GX_TF_ZTF, + GX_TF_Z16 = 0x3 | _GX_TF_ZTF, + GX_TF_Z24X8 = 0x6 | _GX_TF_ZTF, - _GX_TF_CTF = 0x20, // flag for copy-texture-format only (used internally by dolphin) + _GX_TF_CTF = 0x20, // flag for copy-texture-format only (used internally by dolphin) - // These are extra formats that can be used when copying from efb, - // they use one of texel formats from above, but pack diffrent data into them. - GX_CTF_R4 = 0x0 | _GX_TF_CTF, - GX_CTF_RA4 = 0x2 | _GX_TF_CTF, - GX_CTF_RA8 = 0x3 | _GX_TF_CTF, - GX_CTF_YUVA8 = 0x6 | _GX_TF_CTF, // YUV 4:4:4 - Dolphin doesn't implement this format as no commercial games use it - GX_CTF_A8 = 0x7 | _GX_TF_CTF, - GX_CTF_R8 = 0x8 | _GX_TF_CTF, - GX_CTF_G8 = 0x9 | _GX_TF_CTF, - GX_CTF_B8 = 0xA | _GX_TF_CTF, - GX_CTF_RG8 = 0xB | _GX_TF_CTF, - GX_CTF_GB8 = 0xC | _GX_TF_CTF, + // These are extra formats that can be used when copying from efb, + // they use one of texel formats from above, but pack diffrent data into them. + GX_CTF_R4 = 0x0 | _GX_TF_CTF, + GX_CTF_RA4 = 0x2 | _GX_TF_CTF, + GX_CTF_RA8 = 0x3 | _GX_TF_CTF, + GX_CTF_YUVA8 = 0x6 | _GX_TF_CTF, // YUV 4:4:4 - Dolphin doesn't implement this format as no + // commercial games use it + GX_CTF_A8 = 0x7 | _GX_TF_CTF, + GX_CTF_R8 = 0x8 | _GX_TF_CTF, + GX_CTF_G8 = 0x9 | _GX_TF_CTF, + GX_CTF_B8 = 0xA | _GX_TF_CTF, + GX_CTF_RG8 = 0xB | _GX_TF_CTF, + GX_CTF_GB8 = 0xC | _GX_TF_CTF, - // extra depth texture formats that can be used for efb copies. - GX_CTF_Z4 = 0x0 | _GX_TF_ZTF | _GX_TF_CTF, - GX_CTF_Z8H = 0x8 | _GX_TF_ZTF | _GX_TF_CTF, // This produces an identical result to to GX_TF_Z8 - GX_CTF_Z8M = 0x9 | _GX_TF_ZTF | _GX_TF_CTF, - GX_CTF_Z8L = 0xA | _GX_TF_ZTF | _GX_TF_CTF, - GX_CTF_Z16R = 0xB | _GX_TF_ZTF | _GX_TF_CTF, // Reversed version of GX_TF_Z16 - GX_CTF_Z16L = 0xC | _GX_TF_ZTF | _GX_TF_CTF, + // extra depth texture formats that can be used for efb copies. + GX_CTF_Z4 = 0x0 | _GX_TF_ZTF | _GX_TF_CTF, + GX_CTF_Z8H = 0x8 | _GX_TF_ZTF | _GX_TF_CTF, // This produces an identical result to to GX_TF_Z8 + GX_CTF_Z8M = 0x9 | _GX_TF_ZTF | _GX_TF_CTF, + GX_CTF_Z8L = 0xA | _GX_TF_ZTF | _GX_TF_CTF, + GX_CTF_Z16R = 0xB | _GX_TF_ZTF | _GX_TF_CTF, // Reversed version of GX_TF_Z16 + GX_CTF_Z16L = 0xC | _GX_TF_ZTF | _GX_TF_CTF, }; enum TlutFormat { - GX_TL_IA8 = 0x0, - GX_TL_RGB565 = 0x1, - GX_TL_RGB5A3 = 0x2, + GX_TL_IA8 = 0x0, + GX_TL_RGB565 = 0x1, + GX_TL_RGB5A3 = 0x2, }; int TexDecoder_GetTexelSizeInNibbles(int format); @@ -73,12 +74,17 @@ int TexDecoder_GetBlockHeightInTexels(u32 format); int TexDecoder_GetPaletteSize(int fmt); int TexDecoder_GetEfbCopyBaseFormat(int format); -void TexDecoder_Decode(u8 *dst, const u8 *src, int width, int height, int texformat, const u8* tlut, TlutFormat tlutfmt); -void TexDecoder_DecodeRGBA8FromTmem(u8* dst, const u8 *src_ar, const u8 *src_gb, int width, int height); -void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth, int texformat, const u8* tlut, TlutFormat tlutfmt); -void TexDecoder_DecodeTexelRGBA8FromTmem(u8 *dst, const u8 *src_ar, const u8* src_gb, int s, int t, int imageWidth); +void TexDecoder_Decode(u8* dst, const u8* src, int width, int height, int texformat, const u8* tlut, + TlutFormat tlutfmt); +void TexDecoder_DecodeRGBA8FromTmem(u8* dst, const u8* src_ar, const u8* src_gb, int width, + int height); +void TexDecoder_DecodeTexel(u8* dst, const u8* src, int s, int t, int imageWidth, int texformat, + const u8* tlut, TlutFormat tlutfmt); +void TexDecoder_DecodeTexelRGBA8FromTmem(u8* dst, const u8* src_ar, const u8* src_gb, int s, int t, + int imageWidth); void TexDecoder_SetTexFmtOverlayOptions(bool enable, bool center); /* Internal method, implemented by TextureDecoder_Generic and TextureDecoder_x64. */ -void _TexDecoder_DecodeImpl(u32 * dst, const u8 * src, int width, int height, int texformat, const u8* tlut, TlutFormat tlutfmt); +void _TexDecoder_DecodeImpl(u32* dst, const u8* src, int width, int height, int texformat, + const u8* tlut, TlutFormat tlutfmt); diff --git a/Source/Core/VideoCommon/TextureDecoder_Common.cpp b/Source/Core/VideoCommon/TextureDecoder_Common.cpp index 3cd8f208be..ad58980bfb 100644 --- a/Source/Core/VideoCommon/TextureDecoder_Common.cpp +++ b/Source/Core/VideoCommon/TextureDecoder_Common.cpp @@ -9,8 +9,8 @@ #include "Common/CommonTypes.h" #include "Common/MsgHandler.h" #include "VideoCommon/LookUpTables.h" -#include "VideoCommon/sfont.inc" #include "VideoCommon/TextureDecoder.h" +#include "VideoCommon/sfont.inc" static bool TexFmt_Overlay_Enable = false; static bool TexFmt_Overlay_Center = false; @@ -21,138 +21,229 @@ alignas(16) u8 texMem[TMEM_SIZE]; int TexDecoder_GetTexelSizeInNibbles(int format) { - switch (format & 0x3f) { - case GX_TF_I4: return 1; - case GX_TF_I8: return 2; - case GX_TF_IA4: return 2; - case GX_TF_IA8: return 4; - case GX_TF_RGB565: return 4; - case GX_TF_RGB5A3: return 4; - case GX_TF_RGBA8: return 8; - case GX_TF_C4: return 1; - case GX_TF_C8: return 2; - case GX_TF_C14X2: return 4; - case GX_TF_CMPR: return 1; - case GX_CTF_R4: return 1; - case GX_CTF_RA4: return 2; - case GX_CTF_RA8: return 4; - case GX_CTF_A8: return 2; - case GX_CTF_R8: return 2; - case GX_CTF_G8: return 2; - case GX_CTF_B8: return 2; - case GX_CTF_RG8: return 4; - case GX_CTF_GB8: return 4; + switch (format & 0x3f) + { + case GX_TF_I4: + return 1; + case GX_TF_I8: + return 2; + case GX_TF_IA4: + return 2; + case GX_TF_IA8: + return 4; + case GX_TF_RGB565: + return 4; + case GX_TF_RGB5A3: + return 4; + case GX_TF_RGBA8: + return 8; + case GX_TF_C4: + return 1; + case GX_TF_C8: + return 2; + case GX_TF_C14X2: + return 4; + case GX_TF_CMPR: + return 1; + case GX_CTF_R4: + return 1; + case GX_CTF_RA4: + return 2; + case GX_CTF_RA8: + return 4; + case GX_CTF_A8: + return 2; + case GX_CTF_R8: + return 2; + case GX_CTF_G8: + return 2; + case GX_CTF_B8: + return 2; + case GX_CTF_RG8: + return 4; + case GX_CTF_GB8: + return 4; - case GX_TF_Z8: return 2; - case GX_TF_Z16: return 4; - case GX_TF_Z24X8: return 8; + case GX_TF_Z8: + return 2; + case GX_TF_Z16: + return 4; + case GX_TF_Z24X8: + return 8; - case GX_CTF_Z4: return 1; - case GX_CTF_Z8H: return 2; - case GX_CTF_Z8M: return 2; - case GX_CTF_Z8L: return 2; - case GX_CTF_Z16R: return 4; - case GX_CTF_Z16L: return 4; - default: - PanicAlert("Unsupported Texture Format (%08x)! (GetTexelSizeInNibbles)", format); - return 1; - } + case GX_CTF_Z4: + return 1; + case GX_CTF_Z8H: + return 2; + case GX_CTF_Z8M: + return 2; + case GX_CTF_Z8L: + return 2; + case GX_CTF_Z16R: + return 4; + case GX_CTF_Z16L: + return 4; + default: + PanicAlert("Unsupported Texture Format (%08x)! (GetTexelSizeInNibbles)", format); + return 1; + } } int TexDecoder_GetTextureSizeInBytes(int width, int height, int format) { - return (width * height * TexDecoder_GetTexelSizeInNibbles(format)) / 2; + return (width * height * TexDecoder_GetTexelSizeInNibbles(format)) / 2; } int TexDecoder_GetBlockWidthInTexels(u32 format) { - switch (format) - { - case GX_TF_I4: return 8; - case GX_TF_I8: return 8; - case GX_TF_IA4: return 8; - case GX_TF_IA8: return 4; - case GX_TF_RGB565: return 4; - case GX_TF_RGB5A3: return 4; - case GX_TF_RGBA8: return 4; - case GX_TF_C4: return 8; - case GX_TF_C8: return 8; - case GX_TF_C14X2: return 4; - case GX_TF_CMPR: return 8; - case GX_CTF_R4: return 8; - case GX_CTF_RA4: return 8; - case GX_CTF_RA8: return 4; - case GX_CTF_A8: return 8; - case GX_CTF_R8: return 8; - case GX_CTF_G8: return 8; - case GX_CTF_B8: return 8; - case GX_CTF_RG8: return 4; - case GX_CTF_GB8: return 4; - case GX_TF_Z8: return 8; - case GX_TF_Z16: return 4; - case GX_TF_Z24X8: return 4; - case GX_CTF_Z4: return 8; - case GX_CTF_Z8H: return 8; - case GX_CTF_Z8M: return 8; - case GX_CTF_Z8L: return 8; - case GX_CTF_Z16R: return 4; - case GX_CTF_Z16L: return 4; - default: - PanicAlert("Unsupported Texture Format (%08x)! (GetBlockWidthInTexels)", format); - return 8; - } + switch (format) + { + case GX_TF_I4: + return 8; + case GX_TF_I8: + return 8; + case GX_TF_IA4: + return 8; + case GX_TF_IA8: + return 4; + case GX_TF_RGB565: + return 4; + case GX_TF_RGB5A3: + return 4; + case GX_TF_RGBA8: + return 4; + case GX_TF_C4: + return 8; + case GX_TF_C8: + return 8; + case GX_TF_C14X2: + return 4; + case GX_TF_CMPR: + return 8; + case GX_CTF_R4: + return 8; + case GX_CTF_RA4: + return 8; + case GX_CTF_RA8: + return 4; + case GX_CTF_A8: + return 8; + case GX_CTF_R8: + return 8; + case GX_CTF_G8: + return 8; + case GX_CTF_B8: + return 8; + case GX_CTF_RG8: + return 4; + case GX_CTF_GB8: + return 4; + case GX_TF_Z8: + return 8; + case GX_TF_Z16: + return 4; + case GX_TF_Z24X8: + return 4; + case GX_CTF_Z4: + return 8; + case GX_CTF_Z8H: + return 8; + case GX_CTF_Z8M: + return 8; + case GX_CTF_Z8L: + return 8; + case GX_CTF_Z16R: + return 4; + case GX_CTF_Z16L: + return 4; + default: + PanicAlert("Unsupported Texture Format (%08x)! (GetBlockWidthInTexels)", format); + return 8; + } } int TexDecoder_GetBlockHeightInTexels(u32 format) { - switch (format) - { - case GX_TF_I4: return 8; - case GX_TF_I8: return 4; - case GX_TF_IA4: return 4; - case GX_TF_IA8: return 4; - case GX_TF_RGB565: return 4; - case GX_TF_RGB5A3: return 4; - case GX_TF_RGBA8: return 4; - case GX_TF_C4: return 8; - case GX_TF_C8: return 4; - case GX_TF_C14X2: return 4; - case GX_TF_CMPR: return 8; - case GX_CTF_R4: return 8; - case GX_CTF_RA4: return 4; - case GX_CTF_RA8: return 4; - case GX_CTF_A8: return 4; - case GX_CTF_R8: return 4; - case GX_CTF_G8: return 4; - case GX_CTF_B8: return 4; - case GX_CTF_RG8: return 4; - case GX_CTF_GB8: return 4; - case GX_TF_Z8: return 4; - case GX_TF_Z16: return 4; - case GX_TF_Z24X8: return 4; - case GX_CTF_Z4: return 8; - case GX_CTF_Z8H: return 4; - case GX_CTF_Z8M: return 4; - case GX_CTF_Z8L: return 4; - case GX_CTF_Z16R: return 4; - case GX_CTF_Z16L: return 4; - default: - PanicAlert("Unsupported Texture Format (%08x)! (GetBlockHeightInTexels)", format); - return 4; - } + switch (format) + { + case GX_TF_I4: + return 8; + case GX_TF_I8: + return 4; + case GX_TF_IA4: + return 4; + case GX_TF_IA8: + return 4; + case GX_TF_RGB565: + return 4; + case GX_TF_RGB5A3: + return 4; + case GX_TF_RGBA8: + return 4; + case GX_TF_C4: + return 8; + case GX_TF_C8: + return 4; + case GX_TF_C14X2: + return 4; + case GX_TF_CMPR: + return 8; + case GX_CTF_R4: + return 8; + case GX_CTF_RA4: + return 4; + case GX_CTF_RA8: + return 4; + case GX_CTF_A8: + return 4; + case GX_CTF_R8: + return 4; + case GX_CTF_G8: + return 4; + case GX_CTF_B8: + return 4; + case GX_CTF_RG8: + return 4; + case GX_CTF_GB8: + return 4; + case GX_TF_Z8: + return 4; + case GX_TF_Z16: + return 4; + case GX_TF_Z24X8: + return 4; + case GX_CTF_Z4: + return 8; + case GX_CTF_Z8H: + return 4; + case GX_CTF_Z8M: + return 4; + case GX_CTF_Z8L: + return 4; + case GX_CTF_Z16R: + return 4; + case GX_CTF_Z16L: + return 4; + default: + PanicAlert("Unsupported Texture Format (%08x)! (GetBlockHeightInTexels)", format); + return 4; + } } -//returns bytes +// returns bytes int TexDecoder_GetPaletteSize(int format) { - switch (format) - { - case GX_TF_C4: return 16 * 2; - case GX_TF_C8: return 256 * 2; - case GX_TF_C14X2: return 16384 * 2; - default: - return 0; - } + switch (format) + { + case GX_TF_C4: + return 16 * 2; + case GX_TF_C8: + return 256 * 2; + case GX_TF_C14X2: + return 16384 * 2; + default: + return 0; + } } // Get the "in memory" texture format of an EFB copy's format. @@ -160,490 +251,489 @@ int TexDecoder_GetPaletteSize(int format) // this is the format the game should be using when it is drawing an EFB copy back. int TexDecoder_GetEfbCopyBaseFormat(int format) { - switch (format) - { - case GX_TF_I4: - case GX_CTF_Z4: - case GX_CTF_R4: - return GX_TF_I4; - case GX_TF_I8: - case GX_CTF_A8: - case GX_CTF_R8: - case GX_CTF_G8: - case GX_CTF_B8: - case GX_TF_Z8: - case GX_CTF_Z8H: - case GX_CTF_Z8M: - case GX_CTF_Z8L: - return GX_TF_I8; - case GX_TF_IA4: - case GX_CTF_RA4: - return GX_TF_IA4; - case GX_TF_IA8: - case GX_TF_Z16: - case GX_CTF_RA8: - case GX_CTF_RG8: - case GX_CTF_GB8: - case GX_CTF_Z16R: - case GX_CTF_Z16L: - return GX_TF_IA8; - case GX_TF_RGB565: - return GX_TF_RGB565; - case GX_TF_RGB5A3: - return GX_TF_RGB5A3; - case GX_TF_RGBA8: - case GX_TF_Z24X8: - case GX_CTF_YUVA8: - return GX_TF_RGBA8; - // These formats can't be (directly) generated by EFB copies - case GX_TF_C4: - case GX_TF_C8: - case GX_TF_C14X2: - case GX_TF_CMPR: - default: - PanicAlert("Unsupported Texture Format (%08x)! (GetEfbCopyBaseFormat)", format); - return format & 0xf; - } + switch (format) + { + case GX_TF_I4: + case GX_CTF_Z4: + case GX_CTF_R4: + return GX_TF_I4; + case GX_TF_I8: + case GX_CTF_A8: + case GX_CTF_R8: + case GX_CTF_G8: + case GX_CTF_B8: + case GX_TF_Z8: + case GX_CTF_Z8H: + case GX_CTF_Z8M: + case GX_CTF_Z8L: + return GX_TF_I8; + case GX_TF_IA4: + case GX_CTF_RA4: + return GX_TF_IA4; + case GX_TF_IA8: + case GX_TF_Z16: + case GX_CTF_RA8: + case GX_CTF_RG8: + case GX_CTF_GB8: + case GX_CTF_Z16R: + case GX_CTF_Z16L: + return GX_TF_IA8; + case GX_TF_RGB565: + return GX_TF_RGB565; + case GX_TF_RGB5A3: + return GX_TF_RGB5A3; + case GX_TF_RGBA8: + case GX_TF_Z24X8: + case GX_CTF_YUVA8: + return GX_TF_RGBA8; + // These formats can't be (directly) generated by EFB copies + case GX_TF_C4: + case GX_TF_C8: + case GX_TF_C14X2: + case GX_TF_CMPR: + default: + PanicAlert("Unsupported Texture Format (%08x)! (GetEfbCopyBaseFormat)", format); + return format & 0xf; + } } - void TexDecoder_SetTexFmtOverlayOptions(bool enable, bool center) { - TexFmt_Overlay_Enable = enable; - TexFmt_Overlay_Center = center; + TexFmt_Overlay_Enable = enable; + TexFmt_Overlay_Center = center; } static const char* texfmt[] = { - // pixel - "I4", "I8", "IA4", "IA8", - "RGB565", "RGB5A3", "RGBA8", "0x07", - "C4", "C8", "C14X2", "0x0B", - "0x0C", "0x0D", "CMPR", "0x0F", - // Z-buffer - "0x10", "Z8", "0x12", "Z16", - "0x14", "0x15", "Z24X8", "0x17", - "0x18", "0x19", "0x1A", "0x1B", - "0x1C", "0x1D", "0x1E", "0x1F", - // pixel + copy - "CR4", "0x21", "CRA4", "CRA8", - "0x24", "0x25", "CYUVA8", "CA8", - "CR8", "CG8", "CB8", "CRG8", - "CGB8", "0x2D", "0x2E", "0x2F", - // Z + copy - "CZ4", "0x31", "0x32", "0x33", - "0x34", "0x35", "0x36", "0x37", - "0x38", "CZ8M", "CZ8L", "0x3B", - "CZ16L", "0x3D", "0x3E", "0x3F", + // pixel + "I4", "I8", "IA4", "IA8", "RGB565", "RGB5A3", "RGBA8", "0x07", "C4", "C8", "C14X2", "0x0B", + "0x0C", "0x0D", "CMPR", "0x0F", + // Z-buffer + "0x10", "Z8", "0x12", "Z16", "0x14", "0x15", "Z24X8", "0x17", "0x18", "0x19", "0x1A", "0x1B", + "0x1C", "0x1D", "0x1E", "0x1F", + // pixel + copy + "CR4", "0x21", "CRA4", "CRA8", "0x24", "0x25", "CYUVA8", "CA8", "CR8", "CG8", "CB8", "CRG8", + "CGB8", "0x2D", "0x2E", "0x2F", + // Z + copy + "CZ4", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37", "0x38", "CZ8M", "CZ8L", "0x3B", + "CZ16L", "0x3D", "0x3E", "0x3F", }; -static void TexDecoder_DrawOverlay(u8 *dst, int width, int height, int texformat) +static void TexDecoder_DrawOverlay(u8* dst, int width, int height, int texformat) { - int w = std::min(width, 40); - int h = std::min(height, 10); + int w = std::min(width, 40); + int h = std::min(height, 10); - int xoff = (width - w) >> 1; - int yoff = (height - h) >> 1; + int xoff = (width - w) >> 1; + int yoff = (height - h) >> 1; - if (!TexFmt_Overlay_Center) - { - xoff = 0; - yoff = 0; - } + if (!TexFmt_Overlay_Center) + { + xoff = 0; + yoff = 0; + } - const char* fmt = texfmt[texformat & 15]; - while (*fmt) - { - int xcnt = 0; - int nchar = sfont_map[(int)*fmt]; + const char* fmt = texfmt[texformat & 15]; + while (*fmt) + { + int xcnt = 0; + int nchar = sfont_map[(int)*fmt]; - const unsigned char *ptr = sfont_raw[nchar]; // each char is up to 9x10 + const unsigned char* ptr = sfont_raw[nchar]; // each char is up to 9x10 - for (int x = 0; x < 9; x++) - { - if (ptr[x] == 0x78) - break; - xcnt++; - } + for (int x = 0; x < 9; x++) + { + if (ptr[x] == 0x78) + break; + xcnt++; + } - for (int y = 0; y < 10; y++) - { - for (int x = 0; x < xcnt; x++) - { - int *dtp = (int*)dst; - dtp[(y + yoff) * width + x + xoff] = ptr[x] ? 0xFFFFFFFF : 0xFF000000; - } - ptr += 9; - } - xoff += xcnt; - fmt++; - } + for (int y = 0; y < 10; y++) + { + for (int x = 0; x < xcnt; x++) + { + int* dtp = (int*)dst; + dtp[(y + yoff) * width + x + xoff] = ptr[x] ? 0xFFFFFFFF : 0xFF000000; + } + ptr += 9; + } + xoff += xcnt; + fmt++; + } } -void TexDecoder_Decode(u8 *dst, const u8 *src, int width, int height, int texformat, const u8* tlut, TlutFormat tlutfmt) +void TexDecoder_Decode(u8* dst, const u8* src, int width, int height, int texformat, const u8* tlut, + TlutFormat tlutfmt) { - _TexDecoder_DecodeImpl((u32*)dst, src, width, height, texformat, tlut, tlutfmt); + _TexDecoder_DecodeImpl((u32*)dst, src, width, height, texformat, tlut, tlutfmt); - if (TexFmt_Overlay_Enable) - TexDecoder_DrawOverlay(dst, width, height, texformat); + if (TexFmt_Overlay_Enable) + TexDecoder_DrawOverlay(dst, width, height, texformat); } static inline u32 DecodePixel_IA8(u16 val) { - int a = val & 0xFF; - int i = val >> 8; - return i | (i << 8) | (i << 16) | (a << 24); + int a = val & 0xFF; + int i = val >> 8; + return i | (i << 8) | (i << 16) | (a << 24); } static inline u32 DecodePixel_RGB565(u16 val) { - int r,g,b,a; - r=Convert5To8((val>>11) & 0x1f); - g=Convert6To8((val>>5 ) & 0x3f); - b=Convert5To8((val ) & 0x1f); - a=0xFF; - return r | (g<<8) | (b << 16) | (a << 24); + int r, g, b, a; + r = Convert5To8((val >> 11) & 0x1f); + g = Convert6To8((val >> 5) & 0x3f); + b = Convert5To8((val)&0x1f); + a = 0xFF; + return r | (g << 8) | (b << 16) | (a << 24); } static inline u32 DecodePixel_RGB5A3(u16 val) { - int r,g,b,a; - if ((val&0x8000)) - { - r=Convert5To8((val>>10) & 0x1f); - g=Convert5To8((val>>5 ) & 0x1f); - b=Convert5To8((val ) & 0x1f); - a=0xFF; - } - else - { - a=Convert3To8((val>>12) & 0x7); - r=Convert4To8((val>>8 ) & 0xf); - g=Convert4To8((val>>4 ) & 0xf); - b=Convert4To8((val ) & 0xf); - } - return r | (g<<8) | (b << 16) | (a << 24); + int r, g, b, a; + if ((val & 0x8000)) + { + r = Convert5To8((val >> 10) & 0x1f); + g = Convert5To8((val >> 5) & 0x1f); + b = Convert5To8((val)&0x1f); + a = 0xFF; + } + else + { + a = Convert3To8((val >> 12) & 0x7); + r = Convert4To8((val >> 8) & 0xf); + g = Convert4To8((val >> 4) & 0xf); + b = Convert4To8((val)&0xf); + } + return r | (g << 8) | (b << 16) | (a << 24); } static inline u32 DecodePixel_Paletted(u16 pixel, TlutFormat tlutfmt) { - switch (tlutfmt) - { - case GX_TL_IA8: - return DecodePixel_IA8(pixel); - case GX_TL_RGB565: - return DecodePixel_RGB565(Common::swap16(pixel)); - case GX_TL_RGB5A3: - return DecodePixel_RGB5A3(Common::swap16(pixel)); - default: - return 0; - } + switch (tlutfmt) + { + case GX_TL_IA8: + return DecodePixel_IA8(pixel); + case GX_TL_RGB565: + return DecodePixel_RGB565(Common::swap16(pixel)); + case GX_TL_RGB5A3: + return DecodePixel_RGB5A3(Common::swap16(pixel)); + default: + return 0; + } } struct DXTBlock { - u16 color1; - u16 color2; - u8 lines[4]; + u16 color1; + u16 color2; + u8 lines[4]; }; static inline u32 MakeRGBA(int r, int g, int b, int a) { - return (a<<24)|(b<<16)|(g<<8)|r; + return (a << 24) | (b << 16) | (g << 8) | r; } -void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth, int texformat, const u8* tlut_, TlutFormat tlutfmt) +void TexDecoder_DecodeTexel(u8* dst, const u8* src, int s, int t, int imageWidth, int texformat, + const u8* tlut_, TlutFormat tlutfmt) { - /* General formula for computing texture offset - // - u16 sBlk = s / blockWidth; - u16 tBlk = t / blockHeight; - u16 widthBlks = (width / blockWidth) + 1; - u32 base = (tBlk * widthBlks + sBlk) * blockWidth * blockHeight; - u16 blkS = s & (blockWidth - 1); - u16 blkT = t & (blockHeight - 1); - u32 blkOff = blkT * blockWidth + blkS; - */ + /* General formula for computing texture offset + // + u16 sBlk = s / blockWidth; + u16 tBlk = t / blockHeight; + u16 widthBlks = (width / blockWidth) + 1; + u32 base = (tBlk * widthBlks + sBlk) * blockWidth * blockHeight; + u16 blkS = s & (blockWidth - 1); + u16 blkT = t & (blockHeight - 1); + u32 blkOff = blkT * blockWidth + blkS; + */ - switch (texformat) - { - case GX_TF_C4: - { - u16 sBlk = s >> 3; - u16 tBlk = t >> 3; - u16 widthBlks = (imageWidth >> 3) + 1; - u32 base = (tBlk * widthBlks + sBlk) << 5; - u16 blkS = s & 7; - u16 blkT = t & 7; - u32 blkOff = (blkT << 3) + blkS; + switch (texformat) + { + case GX_TF_C4: + { + u16 sBlk = s >> 3; + u16 tBlk = t >> 3; + u16 widthBlks = (imageWidth >> 3) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 5; + u16 blkS = s & 7; + u16 blkT = t & 7; + u32 blkOff = (blkT << 3) + blkS; - int rs = (blkOff & 1)?0:4; - u32 offset = base + (blkOff >> 1); + int rs = (blkOff & 1) ? 0 : 4; + u32 offset = base + (blkOff >> 1); - u8 val = (*(src + offset) >> rs) & 0xF; - u16 *tlut = (u16*) tlut_; + u8 val = (*(src + offset) >> rs) & 0xF; + u16* tlut = (u16*)tlut_; - *((u32*)dst) = DecodePixel_Paletted(tlut[val], tlutfmt); - } - break; - case GX_TF_I4: - { - u16 sBlk = s >> 3; - u16 tBlk = t >> 3; - u16 widthBlks = (imageWidth >> 3) + 1; - u32 base = (tBlk * widthBlks + sBlk) << 5; - u16 blkS = s & 7; - u16 blkT = t & 7; - u32 blkOff = (blkT << 3) + blkS; + *((u32*)dst) = DecodePixel_Paletted(tlut[val], tlutfmt); + } + break; + case GX_TF_I4: + { + u16 sBlk = s >> 3; + u16 tBlk = t >> 3; + u16 widthBlks = (imageWidth >> 3) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 5; + u16 blkS = s & 7; + u16 blkT = t & 7; + u32 blkOff = (blkT << 3) + blkS; - int rs = (blkOff & 1)?0:4; - u32 offset = base + (blkOff >> 1); + int rs = (blkOff & 1) ? 0 : 4; + u32 offset = base + (blkOff >> 1); - u8 val = (*(src + offset) >> rs) & 0xF; - val = Convert4To8(val); - dst[0] = val; - dst[1] = val; - dst[2] = val; - dst[3] = val; - } - break; - case GX_TF_I8: - { - u16 sBlk = s >> 3; - u16 tBlk = t >> 2; - u16 widthBlks = (imageWidth >> 3) + 1; - u32 base = (tBlk * widthBlks + sBlk) << 5; - u16 blkS = s & 7; - u16 blkT = t & 3; - u32 blkOff = (blkT << 3) + blkS; + u8 val = (*(src + offset) >> rs) & 0xF; + val = Convert4To8(val); + dst[0] = val; + dst[1] = val; + dst[2] = val; + dst[3] = val; + } + break; + case GX_TF_I8: + { + u16 sBlk = s >> 3; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 3) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 5; + u16 blkS = s & 7; + u16 blkT = t & 3; + u32 blkOff = (blkT << 3) + blkS; - u8 val = *(src + base + blkOff); - dst[0] = val; - dst[1] = val; - dst[2] = val; - dst[3] = val; - } - break; - case GX_TF_C8: - { - u16 sBlk = s >> 3; - u16 tBlk = t >> 2; - u16 widthBlks = (imageWidth >> 3) + 1; - u32 base = (tBlk * widthBlks + sBlk) << 5; - u16 blkS = s & 7; - u16 blkT = t & 3; - u32 blkOff = (blkT << 3) + blkS; + u8 val = *(src + base + blkOff); + dst[0] = val; + dst[1] = val; + dst[2] = val; + dst[3] = val; + } + break; + case GX_TF_C8: + { + u16 sBlk = s >> 3; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 3) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 5; + u16 blkS = s & 7; + u16 blkT = t & 3; + u32 blkOff = (blkT << 3) + blkS; - u8 val = *(src + base + blkOff); - u16 *tlut = (u16*) tlut_; + u8 val = *(src + base + blkOff); + u16* tlut = (u16*)tlut_; - *((u32*)dst) = DecodePixel_Paletted(tlut[val], tlutfmt); - } - break; - case GX_TF_IA4: - { - u16 sBlk = s >> 3; - u16 tBlk = t >> 2; - u16 widthBlks = (imageWidth >> 3) + 1; - u32 base = (tBlk * widthBlks + sBlk) << 5; - u16 blkS = s & 7; - u16 blkT = t & 3; - u32 blkOff = (blkT << 3) + blkS; + *((u32*)dst) = DecodePixel_Paletted(tlut[val], tlutfmt); + } + break; + case GX_TF_IA4: + { + u16 sBlk = s >> 3; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 3) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 5; + u16 blkS = s & 7; + u16 blkT = t & 3; + u32 blkOff = (blkT << 3) + blkS; - u8 val = *(src + base + blkOff); - const u8 a = Convert4To8(val>>4); - const u8 l = Convert4To8(val&0xF); - dst[0] = l; - dst[1] = l; - dst[2] = l; - dst[3] = a; - } - break; - case GX_TF_IA8: - { - u16 sBlk = s >> 2; - u16 tBlk = t >> 2; - u16 widthBlks = (imageWidth >> 2) + 1; - u32 base = (tBlk * widthBlks + sBlk) << 4; - u16 blkS = s & 3; - u16 blkT = t & 3; - u32 blkOff = (blkT << 2) + blkS; + u8 val = *(src + base + blkOff); + const u8 a = Convert4To8(val >> 4); + const u8 l = Convert4To8(val & 0xF); + dst[0] = l; + dst[1] = l; + dst[2] = l; + dst[3] = a; + } + break; + case GX_TF_IA8: + { + u16 sBlk = s >> 2; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 2) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 4; + u16 blkS = s & 3; + u16 blkT = t & 3; + u32 blkOff = (blkT << 2) + blkS; - u32 offset = (base + blkOff) << 1; - const u16* valAddr = (u16*)(src + offset); + u32 offset = (base + blkOff) << 1; + const u16* valAddr = (u16*)(src + offset); - *((u32*)dst) = DecodePixel_IA8(*valAddr); - } - break; - case GX_TF_C14X2: - { - u16 sBlk = s >> 2; - u16 tBlk = t >> 2; - u16 widthBlks = (imageWidth >> 2) + 1; - u32 base = (tBlk * widthBlks + sBlk) << 4; - u16 blkS = s & 3; - u16 blkT = t & 3; - u32 blkOff = (blkT << 2) + blkS; + *((u32*)dst) = DecodePixel_IA8(*valAddr); + } + break; + case GX_TF_C14X2: + { + u16 sBlk = s >> 2; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 2) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 4; + u16 blkS = s & 3; + u16 blkT = t & 3; + u32 blkOff = (blkT << 2) + blkS; - u32 offset = (base + blkOff) << 1; - const u16* valAddr = (u16*)(src + offset); + u32 offset = (base + blkOff) << 1; + const u16* valAddr = (u16*)(src + offset); - u16 val = Common::swap16(*valAddr) & 0x3FFF; - u16 *tlut = (u16*) tlut_; + u16 val = Common::swap16(*valAddr) & 0x3FFF; + u16* tlut = (u16*)tlut_; - *((u32*)dst) = DecodePixel_Paletted(tlut[val], tlutfmt); - } - break; - case GX_TF_RGB565: - { - u16 sBlk = s >> 2; - u16 tBlk = t >> 2; - u16 widthBlks = (imageWidth >> 2) + 1; - u32 base = (tBlk * widthBlks + sBlk) << 4; - u16 blkS = s & 3; - u16 blkT = t & 3; - u32 blkOff = (blkT << 2) + blkS; + *((u32*)dst) = DecodePixel_Paletted(tlut[val], tlutfmt); + } + break; + case GX_TF_RGB565: + { + u16 sBlk = s >> 2; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 2) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 4; + u16 blkS = s & 3; + u16 blkT = t & 3; + u32 blkOff = (blkT << 2) + blkS; - u32 offset = (base + blkOff) << 1; - const u16* valAddr = (u16*)(src + offset); + u32 offset = (base + blkOff) << 1; + const u16* valAddr = (u16*)(src + offset); - *((u32*)dst) = DecodePixel_RGB565(Common::swap16(*valAddr)); - } - break; - case GX_TF_RGB5A3: - { - u16 sBlk = s >> 2; - u16 tBlk = t >> 2; - u16 widthBlks = (imageWidth >> 2) + 1; - u32 base = (tBlk * widthBlks + sBlk) << 4; - u16 blkS = s & 3; - u16 blkT = t & 3; - u32 blkOff = (blkT << 2) + blkS; + *((u32*)dst) = DecodePixel_RGB565(Common::swap16(*valAddr)); + } + break; + case GX_TF_RGB5A3: + { + u16 sBlk = s >> 2; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 2) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 4; + u16 blkS = s & 3; + u16 blkT = t & 3; + u32 blkOff = (blkT << 2) + blkS; - u32 offset = (base + blkOff) << 1; - const u16* valAddr = (u16*)(src + offset); + u32 offset = (base + blkOff) << 1; + const u16* valAddr = (u16*)(src + offset); - *((u32*)dst) = DecodePixel_RGB5A3(Common::swap16(*valAddr)); - } - break; - case GX_TF_RGBA8: - { - u16 sBlk = s >> 2; - u16 tBlk = t >> 2; - u16 widthBlks = (imageWidth >> 2) + 1; - u32 base = (tBlk * widthBlks + sBlk) << 5; // shift by 5 is correct - u16 blkS = s & 3; - u16 blkT = t & 3; - u32 blkOff = (blkT << 2) + blkS; + *((u32*)dst) = DecodePixel_RGB5A3(Common::swap16(*valAddr)); + } + break; + case GX_TF_RGBA8: + { + u16 sBlk = s >> 2; + u16 tBlk = t >> 2; + u16 widthBlks = (imageWidth >> 2) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 5; // shift by 5 is correct + u16 blkS = s & 3; + u16 blkT = t & 3; + u32 blkOff = (blkT << 2) + blkS; - u32 offset = (base + blkOff) << 1 ; - const u8* valAddr = src + offset; + u32 offset = (base + blkOff) << 1; + const u8* valAddr = src + offset; - dst[3] = valAddr[0]; - dst[0] = valAddr[1]; - dst[1] = valAddr[32]; - dst[2] = valAddr[33]; - } - break; - case GX_TF_CMPR: - { - u16 sDxt = s >> 2; - u16 tDxt = t >> 2; + dst[3] = valAddr[0]; + dst[0] = valAddr[1]; + dst[1] = valAddr[32]; + dst[2] = valAddr[33]; + } + break; + case GX_TF_CMPR: + { + u16 sDxt = s >> 2; + u16 tDxt = t >> 2; - u16 sBlk = sDxt >> 1; - u16 tBlk = tDxt >> 1; - u16 widthBlks = (imageWidth >> 3) + 1; - u32 base = (tBlk * widthBlks + sBlk) << 2; - u16 blkS = sDxt & 1; - u16 blkT = tDxt & 1; - u32 blkOff = (blkT << 1) + blkS; + u16 sBlk = sDxt >> 1; + u16 tBlk = tDxt >> 1; + u16 widthBlks = (imageWidth >> 3) + 1; + u32 base = (tBlk * widthBlks + sBlk) << 2; + u16 blkS = sDxt & 1; + u16 blkT = tDxt & 1; + u32 blkOff = (blkT << 1) + blkS; - u32 offset = (base + blkOff) << 3; + u32 offset = (base + blkOff) << 3; - const DXTBlock* dxtBlock = (const DXTBlock*)(src + offset); + const DXTBlock* dxtBlock = (const DXTBlock*)(src + offset); - u16 c1 = Common::swap16(dxtBlock->color1); - u16 c2 = Common::swap16(dxtBlock->color2); - int blue1 = Convert5To8(c1 & 0x1F); - int blue2 = Convert5To8(c2 & 0x1F); - int green1 = Convert6To8((c1 >> 5) & 0x3F); - int green2 = Convert6To8((c2 >> 5) & 0x3F); - int red1 = Convert5To8((c1 >> 11) & 0x1F); - int red2 = Convert5To8((c2 >> 11) & 0x1F); + u16 c1 = Common::swap16(dxtBlock->color1); + u16 c2 = Common::swap16(dxtBlock->color2); + int blue1 = Convert5To8(c1 & 0x1F); + int blue2 = Convert5To8(c2 & 0x1F); + int green1 = Convert6To8((c1 >> 5) & 0x3F); + int green2 = Convert6To8((c2 >> 5) & 0x3F); + int red1 = Convert5To8((c1 >> 11) & 0x1F); + int red2 = Convert5To8((c2 >> 11) & 0x1F); - u16 ss = s & 3; - u16 tt = t & 3; + u16 ss = s & 3; + u16 tt = t & 3; - int colorSel = dxtBlock->lines[tt]; - int rs = 6 - (ss << 1); - colorSel = (colorSel >> rs) & 3; - colorSel |= c1 > c2?0:4; + int colorSel = dxtBlock->lines[tt]; + int rs = 6 - (ss << 1); + colorSel = (colorSel >> rs) & 3; + colorSel |= c1 > c2 ? 0 : 4; - u32 color = 0; + u32 color = 0; - switch (colorSel) - { - case 0: - case 4: - color = MakeRGBA(red1, green1, blue1, 255); - break; - case 1: - case 5: - color = MakeRGBA(red2, green2, blue2, 255); - break; - case 2: - color = MakeRGBA(red1+(red2-red1)/3, green1+(green2-green1)/3, blue1+(blue2-blue1)/3, 255); - break; - case 3: - color = MakeRGBA(red2+(red1-red2)/3, green2+(green1-green2)/3, blue2+(blue1-blue2)/3, 255); - break; - case 6: - color = MakeRGBA((int)ceil((float)(red1+red2)/2), (int)ceil((float)(green1+green2)/2), (int)ceil((float)(blue1+blue2)/2), 255); - break; - case 7: - color = MakeRGBA(red2, green2, blue2, 0); - break; - default: - color = 0; - break; - } + switch (colorSel) + { + case 0: + case 4: + color = MakeRGBA(red1, green1, blue1, 255); + break; + case 1: + case 5: + color = MakeRGBA(red2, green2, blue2, 255); + break; + case 2: + color = MakeRGBA(red1 + (red2 - red1) / 3, green1 + (green2 - green1) / 3, + blue1 + (blue2 - blue1) / 3, 255); + break; + case 3: + color = MakeRGBA(red2 + (red1 - red2) / 3, green2 + (green1 - green2) / 3, + blue2 + (blue1 - blue2) / 3, 255); + break; + case 6: + color = MakeRGBA((int)ceil((float)(red1 + red2) / 2), (int)ceil((float)(green1 + green2) / 2), + (int)ceil((float)(blue1 + blue2) / 2), 255); + break; + case 7: + color = MakeRGBA(red2, green2, blue2, 0); + break; + default: + color = 0; + break; + } - *((u32*)dst) = color; - } - break; - } + *((u32*)dst) = color; + } + break; + } } -void TexDecoder_DecodeTexelRGBA8FromTmem(u8 *dst, const u8 *src_ar, const u8* src_gb, int s, int t, int imageWidth) +void TexDecoder_DecodeTexelRGBA8FromTmem(u8* dst, const u8* src_ar, const u8* src_gb, int s, int t, + int imageWidth) { - u16 sBlk = s >> 2; - u16 tBlk = t >> 2; - u16 widthBlks = (imageWidth >> 2) + 1; // TODO: Looks wrong. Shouldn't this be ((imageWidth-1)>>2)+1 ? - u32 base_ar = (tBlk * widthBlks + sBlk) << 4; - u32 base_gb = (tBlk * widthBlks + sBlk) << 4; - u16 blkS = s & 3; - u16 blkT = t & 3; - u32 blk_off = (blkT << 2) + blkS; + u16 sBlk = s >> 2; + u16 tBlk = t >> 2; + u16 widthBlks = + (imageWidth >> 2) + 1; // TODO: Looks wrong. Shouldn't this be ((imageWidth-1)>>2)+1 ? + u32 base_ar = (tBlk * widthBlks + sBlk) << 4; + u32 base_gb = (tBlk * widthBlks + sBlk) << 4; + u16 blkS = s & 3; + u16 blkT = t & 3; + u32 blk_off = (blkT << 2) + blkS; - u32 offset_ar = (base_ar + blk_off) << 1; - u32 offset_gb = (base_gb + blk_off) << 1; - const u8* val_addr_ar = src_ar + offset_ar; - const u8* val_addr_gb = src_gb + offset_gb; + u32 offset_ar = (base_ar + blk_off) << 1; + u32 offset_gb = (base_gb + blk_off) << 1; + const u8* val_addr_ar = src_ar + offset_ar; + const u8* val_addr_gb = src_gb + offset_gb; - dst[3] = val_addr_ar[0]; // A - dst[0] = val_addr_ar[1]; // R - dst[1] = val_addr_gb[0]; // G - dst[2] = val_addr_gb[1]; // B + dst[3] = val_addr_ar[0]; // A + dst[0] = val_addr_ar[1]; // R + dst[1] = val_addr_gb[0]; // G + dst[2] = val_addr_gb[1]; // B } -void TexDecoder_DecodeRGBA8FromTmem(u8* dst, const u8 *src_ar, const u8 *src_gb, int width, int height) +void TexDecoder_DecodeRGBA8FromTmem(u8* dst, const u8* src_ar, const u8* src_gb, int width, + int height) { - // TODO for someone who cares: Make this less slow! - for (int y = 0; y < height; ++y) - { - for (int x = 0; x < width; ++x) - { - TexDecoder_DecodeTexelRGBA8FromTmem(dst, src_ar, src_gb, x, y, width-1); - dst += 4; - } - } + // TODO for someone who cares: Make this less slow! + for (int y = 0; y < height; ++y) + { + for (int x = 0; x < width; ++x) + { + TexDecoder_DecodeTexelRGBA8FromTmem(dst, src_ar, src_gb, x, y, width - 1); + dst += 4; + } + } } diff --git a/Source/Core/VideoCommon/TextureDecoder_Generic.cpp b/Source/Core/VideoCommon/TextureDecoder_Generic.cpp index d5d9280b87..fe0f53c845 100644 --- a/Source/Core/VideoCommon/TextureDecoder_Generic.cpp +++ b/Source/Core/VideoCommon/TextureDecoder_Generic.cpp @@ -5,9 +5,9 @@ #include #include +#include "Common/CPUDetect.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" -#include "Common/CPUDetect.h" #include "VideoCommon/LookUpTables.h" #include "VideoCommon/TextureDecoder.h" //#include "VideoCommon/VideoCommon.h" // to get debug logs @@ -20,112 +20,112 @@ static inline u32 DecodePixel_IA8(u16 val) { - int a = val & 0xFF; - int i = val >> 8; - return i | (i<<8) | (i<<16) | (a<<24); + int a = val & 0xFF; + int i = val >> 8; + return i | (i << 8) | (i << 16) | (a << 24); } static inline u32 DecodePixel_RGB565(u16 val) { - int r,g,b,a; - r=Convert5To8((val>>11) & 0x1f); - g=Convert6To8((val>>5 ) & 0x3f); - b=Convert5To8((val ) & 0x1f); - a=0xFF; - return r | (g<<8) | (b << 16) | (a << 24); + int r, g, b, a; + r = Convert5To8((val >> 11) & 0x1f); + g = Convert6To8((val >> 5) & 0x3f); + b = Convert5To8((val)&0x1f); + a = 0xFF; + return r | (g << 8) | (b << 16) | (a << 24); } static inline u32 DecodePixel_RGB5A3(u16 val) { - int r,g,b,a; - if ((val&0x8000)) - { - r=Convert5To8((val>>10) & 0x1f); - g=Convert5To8((val>>5 ) & 0x1f); - b=Convert5To8((val ) & 0x1f); - a=0xFF; - } - else - { - a=Convert3To8((val>>12) & 0x7); - r=Convert4To8((val>>8 ) & 0xf); - g=Convert4To8((val>>4 ) & 0xf); - b=Convert4To8((val ) & 0xf); - } - return r | (g<<8) | (b << 16) | (a << 24); + int r, g, b, a; + if ((val & 0x8000)) + { + r = Convert5To8((val >> 10) & 0x1f); + g = Convert5To8((val >> 5) & 0x1f); + b = Convert5To8((val)&0x1f); + a = 0xFF; + } + else + { + a = Convert3To8((val >> 12) & 0x7); + r = Convert4To8((val >> 8) & 0xf); + g = Convert4To8((val >> 4) & 0xf); + b = Convert4To8((val)&0xf); + } + return r | (g << 8) | (b << 16) | (a << 24); } static inline u32 DecodePixel_Paletted(u16 pixel, TlutFormat tlutfmt) { - switch (tlutfmt) - { - case GX_TL_IA8: - return DecodePixel_IA8(pixel); - case GX_TL_RGB565: - return DecodePixel_RGB565(Common::swap16(pixel)); - case GX_TL_RGB5A3: - return DecodePixel_RGB5A3(Common::swap16(pixel)); - default: - return 0; - } + switch (tlutfmt) + { + case GX_TL_IA8: + return DecodePixel_IA8(pixel); + case GX_TL_RGB565: + return DecodePixel_RGB565(Common::swap16(pixel)); + case GX_TL_RGB5A3: + return DecodePixel_RGB5A3(Common::swap16(pixel)); + default: + return 0; + } } -static inline void DecodeBytes_C4(u32 *dst, const u8 *src, const u8* tlut_, TlutFormat tlutfmt) +static inline void DecodeBytes_C4(u32* dst, const u8* src, const u8* tlut_, TlutFormat tlutfmt) { - const u16* tlut = (u16*) tlut_; - for (int x = 0; x < 4; x++) - { - u8 val = src[x]; - *dst++ = DecodePixel_Paletted(tlut[val >> 4], tlutfmt); - *dst++ = DecodePixel_Paletted(tlut[val & 0xF], tlutfmt); - } + const u16* tlut = (u16*)tlut_; + for (int x = 0; x < 4; x++) + { + u8 val = src[x]; + *dst++ = DecodePixel_Paletted(tlut[val >> 4], tlutfmt); + *dst++ = DecodePixel_Paletted(tlut[val & 0xF], tlutfmt); + } } -static inline void DecodeBytes_C8(u32 *dst, const u8 *src, const u8* tlut_, TlutFormat tlutfmt) +static inline void DecodeBytes_C8(u32* dst, const u8* src, const u8* tlut_, TlutFormat tlutfmt) { - const u16* tlut = (u16*) tlut_; - for (int x = 0; x < 8; x++) - { - u8 val = src[x]; - *dst++ = DecodePixel_Paletted(tlut[val], tlutfmt); - } + const u16* tlut = (u16*)tlut_; + for (int x = 0; x < 8; x++) + { + u8 val = src[x]; + *dst++ = DecodePixel_Paletted(tlut[val], tlutfmt); + } } -static inline void DecodeBytes_C14X2(u32 *dst, const u16 *src, const u8* tlut_, TlutFormat tlutfmt) +static inline void DecodeBytes_C14X2(u32* dst, const u16* src, const u8* tlut_, TlutFormat tlutfmt) { - const u16* tlut = (u16*) tlut_; - for (int x = 0; x < 4; x++) - { - u16 val = Common::swap16(src[x]); - *dst++ = DecodePixel_Paletted(tlut[(val & 0x3FFF)], tlutfmt); - } + const u16* tlut = (u16*)tlut_; + for (int x = 0; x < 4; x++) + { + u16 val = Common::swap16(src[x]); + *dst++ = DecodePixel_Paletted(tlut[(val & 0x3FFF)], tlutfmt); + } } -static inline void DecodeBytes_IA4(u32 *dst, const u8 *src) +static inline void DecodeBytes_IA4(u32* dst, const u8* src) { - for (int x = 0; x < 8; x++) - { - const u8 val = src[x]; - u8 a = Convert4To8(val >> 4); - u8 l = Convert4To8(val & 0xF); - dst[x] = (a << 24) | l << 16 | l << 8 | l; - } + for (int x = 0; x < 8; x++) + { + const u8 val = src[x]; + u8 a = Convert4To8(val >> 4); + u8 l = Convert4To8(val & 0xF); + dst[x] = (a << 24) | l << 16 | l << 8 | l; + } } -static inline void DecodeBytes_RGB5A3(u32 *dst, const u16 *src) +static inline void DecodeBytes_RGB5A3(u32* dst, const u16* src) { #if 0 for (int x = 0; x < 4; x++) dst[x] = DecodePixel_RGB5A3(Common::swap16(src[x])); #else - dst[0] = DecodePixel_RGB5A3(Common::swap16(src[0])); - dst[1] = DecodePixel_RGB5A3(Common::swap16(src[1])); - dst[2] = DecodePixel_RGB5A3(Common::swap16(src[2])); - dst[3] = DecodePixel_RGB5A3(Common::swap16(src[3])); + dst[0] = DecodePixel_RGB5A3(Common::swap16(src[0])); + dst[1] = DecodePixel_RGB5A3(Common::swap16(src[1])); + dst[2] = DecodePixel_RGB5A3(Common::swap16(src[2])); + dst[3] = DecodePixel_RGB5A3(Common::swap16(src[3])); #endif } -static inline void DecodeBytes_RGBA8(u32 *dst, const u16 *src, const u16 * src2) +static inline void DecodeBytes_RGBA8(u32* dst, const u16* src, const u16* src2) { #if 0 for (int x = 0; x < 4; x++) @@ -133,216 +133,228 @@ static inline void DecodeBytes_RGBA8(u32 *dst, const u16 *src, const u16 * src2) dst[x] = ((src[x] & 0xFF) << 24) | ((src[x] & 0xFF00)>>8) | (src2[x] << 8); } #else - dst[0] = ((src[0] & 0xFF) << 24) | ((src[0] & 0xFF00)>>8) | (src2[0] << 8); - dst[1] = ((src[1] & 0xFF) << 24) | ((src[1] & 0xFF00)>>8) | (src2[1] << 8); - dst[2] = ((src[2] & 0xFF) << 24) | ((src[2] & 0xFF00)>>8) | (src2[2] << 8); - dst[3] = ((src[3] & 0xFF) << 24) | ((src[3] & 0xFF00)>>8) | (src2[3] << 8); + dst[0] = ((src[0] & 0xFF) << 24) | ((src[0] & 0xFF00) >> 8) | (src2[0] << 8); + dst[1] = ((src[1] & 0xFF) << 24) | ((src[1] & 0xFF00) >> 8) | (src2[1] << 8); + dst[2] = ((src[2] & 0xFF) << 24) | ((src[2] & 0xFF00) >> 8) | (src2[2] << 8); + dst[3] = ((src[3] & 0xFF) << 24) | ((src[3] & 0xFF00) >> 8) | (src2[3] << 8); #endif } struct DXTBlock { - u16 color1; - u16 color2; - u8 lines[4]; + u16 color1; + u16 color2; + u8 lines[4]; }; static inline u32 MakeRGBA(int r, int g, int b, int a) { - return (a<<24)|(b<<16)|(g<<8)|r; + return (a << 24) | (b << 16) | (g << 8) | r; } -static void DecodeDXTBlock(u32 *dst, const DXTBlock *src, int pitch) +static void DecodeDXTBlock(u32* dst, const DXTBlock* src, int pitch) { - // S3TC Decoder (Note: GCN decodes differently from PC so we can't use native support) - // Needs more speed. - u16 c1 = Common::swap16(src->color1); - u16 c2 = Common::swap16(src->color2); - int blue1 = Convert5To8(c1 & 0x1F); - int blue2 = Convert5To8(c2 & 0x1F); - int green1 = Convert6To8((c1 >> 5) & 0x3F); - int green2 = Convert6To8((c2 >> 5) & 0x3F); - int red1 = Convert5To8((c1 >> 11) & 0x1F); - int red2 = Convert5To8((c2 >> 11) & 0x1F); - int colors[4]; - colors[0] = MakeRGBA(red1, green1, blue1, 255); - colors[1] = MakeRGBA(red2, green2, blue2, 255); - if (c1 > c2) - { - int blue3 = ((blue2 - blue1) >> 1) - ((blue2 - blue1) >> 3); - int green3 = ((green2 - green1) >> 1) - ((green2 - green1) >> 3); - int red3 = ((red2 - red1) >> 1) - ((red2 - red1) >> 3); - colors[2] = MakeRGBA(red1 + red3, green1 + green3, blue1 + blue3, 255); - colors[3] = MakeRGBA(red2 - red3, green2 - green3, blue2 - blue3, 255); - } - else - { - colors[2] = MakeRGBA((red1 + red2 + 1) / 2, // Average - (green1 + green2 + 1) / 2, - (blue1 + blue2 + 1) / 2, 255); - colors[3] = MakeRGBA(red2, green2, blue2, 0); // Color2 but transparent - } + // S3TC Decoder (Note: GCN decodes differently from PC so we can't use native support) + // Needs more speed. + u16 c1 = Common::swap16(src->color1); + u16 c2 = Common::swap16(src->color2); + int blue1 = Convert5To8(c1 & 0x1F); + int blue2 = Convert5To8(c2 & 0x1F); + int green1 = Convert6To8((c1 >> 5) & 0x3F); + int green2 = Convert6To8((c2 >> 5) & 0x3F); + int red1 = Convert5To8((c1 >> 11) & 0x1F); + int red2 = Convert5To8((c2 >> 11) & 0x1F); + int colors[4]; + colors[0] = MakeRGBA(red1, green1, blue1, 255); + colors[1] = MakeRGBA(red2, green2, blue2, 255); + if (c1 > c2) + { + int blue3 = ((blue2 - blue1) >> 1) - ((blue2 - blue1) >> 3); + int green3 = ((green2 - green1) >> 1) - ((green2 - green1) >> 3); + int red3 = ((red2 - red1) >> 1) - ((red2 - red1) >> 3); + colors[2] = MakeRGBA(red1 + red3, green1 + green3, blue1 + blue3, 255); + colors[3] = MakeRGBA(red2 - red3, green2 - green3, blue2 - blue3, 255); + } + else + { + colors[2] = MakeRGBA((red1 + red2 + 1) / 2, // Average + (green1 + green2 + 1) / 2, (blue1 + blue2 + 1) / 2, 255); + colors[3] = MakeRGBA(red2, green2, blue2, 0); // Color2 but transparent + } - for (int y = 0; y < 4; y++) - { - int val = src->lines[y]; - for (int x = 0; x < 4; x++) - { - dst[x] = colors[(val >> 6) & 3]; - val <<= 2; - } - dst += pitch; - } + for (int y = 0; y < 4; y++) + { + int val = src->lines[y]; + for (int x = 0; x < 4; x++) + { + dst[x] = colors[(val >> 6) & 3]; + val <<= 2; + } + dst += pitch; + } } // JSD 01/06/11: -// TODO: we really should ensure BOTH the source and destination addresses are aligned to 16-byte boundaries to -// squeeze out a little more performance. _mm_loadu_si128/_mm_storeu_si128 is slower than _mm_load_si128/_mm_store_si128 -// because they work on unaligned addresses. The processor is free to make the assumption that addresses are multiples +// TODO: we really should ensure BOTH the source and destination addresses are aligned to 16-byte +// boundaries to +// squeeze out a little more performance. _mm_loadu_si128/_mm_storeu_si128 is slower than +// _mm_load_si128/_mm_store_si128 +// because they work on unaligned addresses. The processor is free to make the assumption that +// addresses are multiples // of 16 in the aligned case. // TODO: complete SSE2 optimization of less often used texture formats. // TODO: refactor algorithms using _mm_loadl_epi64 unaligned loads to prefer 128-bit aligned loads. -void _TexDecoder_DecodeImpl(u32 * dst, const u8 * src, int width, int height, int texformat, const u8* tlut, TlutFormat tlutfmt) +void _TexDecoder_DecodeImpl(u32* dst, const u8* src, int width, int height, int texformat, + const u8* tlut, TlutFormat tlutfmt) { - const int Wsteps4 = (width + 3) / 4; - const int Wsteps8 = (width + 7) / 8; + const int Wsteps4 = (width + 3) / 4; + const int Wsteps8 = (width + 7) / 8; - switch (texformat) - { - case GX_TF_C4: - for (int y = 0; y < height; y += 8) - for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8,yStep++) - for (int iy = 0, xStep = 8 * yStep; iy < 8; iy++,xStep++) - DecodeBytes_C4(dst + (y + iy) * width + x, src + 4 * xStep, tlut, tlutfmt); - break; - case GX_TF_I4: - { - // Reference C implementation: - for (int y = 0; y < height; y += 8) - for (int x = 0; x < width; x += 8) - for (int iy = 0; iy < 8; iy++, src += 4) - for (int ix = 0; ix < 4; ix++) - { - int val = src[ix]; - u8 i1 = Convert4To8(val >> 4); - u8 i2 = Convert4To8(val & 0xF); - memset(dst+(y + iy) * width + x + ix * 2 , i1,4); - memset(dst+(y + iy) * width + x + ix * 2 + 1 , i2,4); - } - } - break; - case GX_TF_I8: // speed critical - { - // Reference C implementation - for (int y = 0; y < height; y += 4) - for (int x = 0; x < width; x += 8) - for (int iy = 0; iy < 4; ++iy, src += 8) - { - u32 * newdst = dst + (y + iy)*width+x; - const u8 * newsrc = src; - u8 srcval; + switch (texformat) + { + case GX_TF_C4: + for (int y = 0; y < height; y += 8) + for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 8 * yStep; iy < 8; iy++, xStep++) + DecodeBytes_C4(dst + (y + iy) * width + x, src + 4 * xStep, tlut, tlutfmt); + break; + case GX_TF_I4: + { + // Reference C implementation: + for (int y = 0; y < height; y += 8) + for (int x = 0; x < width; x += 8) + for (int iy = 0; iy < 8; iy++, src += 4) + for (int ix = 0; ix < 4; ix++) + { + int val = src[ix]; + u8 i1 = Convert4To8(val >> 4); + u8 i2 = Convert4To8(val & 0xF); + memset(dst + (y + iy) * width + x + ix * 2, i1, 4); + memset(dst + (y + iy) * width + x + ix * 2 + 1, i2, 4); + } + } + break; + case GX_TF_I8: // speed critical + { + // Reference C implementation + for (int y = 0; y < height; y += 4) + for (int x = 0; x < width; x += 8) + for (int iy = 0; iy < 4; ++iy, src += 8) + { + u32* newdst = dst + (y + iy) * width + x; + const u8* newsrc = src; + u8 srcval; - srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - srcval = (newsrc++)[0]; (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - srcval = newsrc[0]; newdst[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); - } - } - break; - case GX_TF_C8: - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) - DecodeBytes_C8((u32*)dst + (y + iy) * width + x, src + 8 * xStep, tlut, tlutfmt); - break; - case GX_TF_IA4: - { - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) - DecodeBytes_IA4(dst + (y + iy) * width + x, src + 8 * xStep); - } - break; - case GX_TF_IA8: - { - // Reference C implementation: - for (int y = 0; y < height; y += 4) - for (int x = 0; x < width; x += 4) - for (int iy = 0; iy < 4; iy++, src += 8) - { - u32 *ptr = dst + (y + iy) * width + x; - u16 *s = (u16 *)src; - ptr[0] = DecodePixel_IA8(s[0]); - ptr[1] = DecodePixel_IA8(s[1]); - ptr[2] = DecodePixel_IA8(s[2]); - ptr[3] = DecodePixel_IA8(s[3]); - } - } - break; - case GX_TF_C14X2: - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) - DecodeBytes_C14X2(dst + (y + iy) * width + x, (u16*)(src + 8 * xStep), tlut, tlutfmt); - break; - case GX_TF_RGB565: - { - // Reference C implementation. - for (int y = 0; y < height; y += 4) - for (int x = 0; x < width; x += 4) - for (int iy = 0; iy < 4; iy++, src += 8) - { - u32 *ptr = dst + (y + iy) * width + x; - u16 *s = (u16 *)src; - for (int j = 0; j < 4; j++) - *ptr++ = DecodePixel_RGB565(Common::swap16(*s++)); - } - } - break; - case GX_TF_RGB5A3: - { - // Reference C implementation: - for (int y = 0; y < height; y += 4) - for (int x = 0; x < width; x += 4) - for (int iy = 0; iy < 4; iy++, src += 8) - DecodeBytes_RGB5A3(dst+(y+iy)*width+x, (u16*)src); - } - break; - case GX_TF_RGBA8: // speed critical - { - // Reference C implementation. - for (int y = 0; y < height; y += 4) - for (int x = 0; x < width; x += 4) - { - for (int iy = 0; iy < 4; iy++) - DecodeBytes_RGBA8(dst + (y+iy)*width + x, (u16*)src + 4 * iy, (u16*)src + 4 * iy + 16); - src += 64; - } - } - break; - case GX_TF_CMPR: // speed critical - // The metroid games use this format almost exclusively. - { - for (int y = 0; y < height; y += 8) - { - for (int x = 0; x < width; x += 8) - { - DecodeDXTBlock((u32*)dst + y * width + x, (DXTBlock*)src, width); - src += sizeof(DXTBlock); - DecodeDXTBlock((u32*)dst + y * width + x + 4, (DXTBlock*)src, width); - src += sizeof(DXTBlock); - DecodeDXTBlock((u32*)dst + (y + 4) * width + x, (DXTBlock*)src, width); - src += sizeof(DXTBlock); - DecodeDXTBlock((u32*)dst + (y + 4) * width + x + 4, (DXTBlock*)src, width); - src += sizeof(DXTBlock); - } - } - break; - } - } + srcval = (newsrc++)[0]; + (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + srcval = (newsrc++)[0]; + (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + srcval = (newsrc++)[0]; + (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + srcval = (newsrc++)[0]; + (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + srcval = (newsrc++)[0]; + (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + srcval = (newsrc++)[0]; + (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + srcval = (newsrc++)[0]; + (newdst++)[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + srcval = newsrc[0]; + newdst[0] = srcval | (srcval << 8) | (srcval << 16) | (srcval << 24); + } + } + break; + case GX_TF_C8: + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + DecodeBytes_C8((u32*)dst + (y + iy) * width + x, src + 8 * xStep, tlut, tlutfmt); + break; + case GX_TF_IA4: + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + DecodeBytes_IA4(dst + (y + iy) * width + x, src + 8 * xStep); + } + break; + case GX_TF_IA8: + { + // Reference C implementation: + for (int y = 0; y < height; y += 4) + for (int x = 0; x < width; x += 4) + for (int iy = 0; iy < 4; iy++, src += 8) + { + u32* ptr = dst + (y + iy) * width + x; + u16* s = (u16*)src; + ptr[0] = DecodePixel_IA8(s[0]); + ptr[1] = DecodePixel_IA8(s[1]); + ptr[2] = DecodePixel_IA8(s[2]); + ptr[3] = DecodePixel_IA8(s[3]); + } + } + break; + case GX_TF_C14X2: + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + DecodeBytes_C14X2(dst + (y + iy) * width + x, (u16*)(src + 8 * xStep), tlut, tlutfmt); + break; + case GX_TF_RGB565: + { + // Reference C implementation. + for (int y = 0; y < height; y += 4) + for (int x = 0; x < width; x += 4) + for (int iy = 0; iy < 4; iy++, src += 8) + { + u32* ptr = dst + (y + iy) * width + x; + u16* s = (u16*)src; + for (int j = 0; j < 4; j++) + *ptr++ = DecodePixel_RGB565(Common::swap16(*s++)); + } + } + break; + case GX_TF_RGB5A3: + { + // Reference C implementation: + for (int y = 0; y < height; y += 4) + for (int x = 0; x < width; x += 4) + for (int iy = 0; iy < 4; iy++, src += 8) + DecodeBytes_RGB5A3(dst + (y + iy) * width + x, (u16*)src); + } + break; + case GX_TF_RGBA8: // speed critical + { + // Reference C implementation. + for (int y = 0; y < height; y += 4) + for (int x = 0; x < width; x += 4) + { + for (int iy = 0; iy < 4; iy++) + DecodeBytes_RGBA8(dst + (y + iy) * width + x, (u16*)src + 4 * iy, + (u16*)src + 4 * iy + 16); + src += 64; + } + } + break; + case GX_TF_CMPR: // speed critical + // The metroid games use this format almost exclusively. + { + for (int y = 0; y < height; y += 8) + { + for (int x = 0; x < width; x += 8) + { + DecodeDXTBlock((u32*)dst + y * width + x, (DXTBlock*)src, width); + src += sizeof(DXTBlock); + DecodeDXTBlock((u32*)dst + y * width + x + 4, (DXTBlock*)src, width); + src += sizeof(DXTBlock); + DecodeDXTBlock((u32*)dst + (y + 4) * width + x, (DXTBlock*)src, width); + src += sizeof(DXTBlock); + DecodeDXTBlock((u32*)dst + (y + 4) * width + x + 4, (DXTBlock*)src, width); + src += sizeof(DXTBlock); + } + } + break; + } + } } diff --git a/Source/Core/VideoCommon/TextureDecoder_x64.cpp b/Source/Core/VideoCommon/TextureDecoder_x64.cpp index 7a4b0c9906..12e44a677d 100644 --- a/Source/Core/VideoCommon/TextureDecoder_x64.cpp +++ b/Source/Core/VideoCommon/TextureDecoder_x64.cpp @@ -6,9 +6,9 @@ #include #include +#include "Common/CPUDetect.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" -#include "Common/CPUDetect.h" #include "Common/Intrinsics.h" #include "VideoCommon/LookUpTables.h" @@ -21,1244 +21,1337 @@ static inline u32 DecodePixel_IA8(u16 val) { - int a = val & 0xFF; - int i = val >> 8; - return i | (i<<8) | (i<<16) | (a<<24); + int a = val & 0xFF; + int i = val >> 8; + return i | (i << 8) | (i << 16) | (a << 24); } static inline u32 DecodePixel_RGB565(u16 val) { - int r,g,b,a; - r=Convert5To8((val>>11) & 0x1f); - g=Convert6To8((val>>5 ) & 0x3f); - b=Convert5To8((val ) & 0x1f); - a=0xFF; - return r | (g<<8) | (b << 16) | (a << 24); + int r, g, b, a; + r = Convert5To8((val >> 11) & 0x1f); + g = Convert6To8((val >> 5) & 0x3f); + b = Convert5To8((val)&0x1f); + a = 0xFF; + return r | (g << 8) | (b << 16) | (a << 24); } static inline u32 DecodePixel_RGB5A3(u16 val) { - int r,g,b,a; - if ((val&0x8000)) - { - r=Convert5To8((val>>10) & 0x1f); - g=Convert5To8((val>>5 ) & 0x1f); - b=Convert5To8((val ) & 0x1f); - a=0xFF; - } - else - { - a=Convert3To8((val>>12) & 0x7); - r=Convert4To8((val>>8 ) & 0xf); - g=Convert4To8((val>>4 ) & 0xf); - b=Convert4To8((val ) & 0xf); - } - return r | (g<<8) | (b << 16) | (a << 24); + int r, g, b, a; + if ((val & 0x8000)) + { + r = Convert5To8((val >> 10) & 0x1f); + g = Convert5To8((val >> 5) & 0x1f); + b = Convert5To8((val)&0x1f); + a = 0xFF; + } + else + { + a = Convert3To8((val >> 12) & 0x7); + r = Convert4To8((val >> 8) & 0xf); + g = Convert4To8((val >> 4) & 0xf); + b = Convert4To8((val)&0xf); + } + return r | (g << 8) | (b << 16) | (a << 24); } struct DXTBlock { - u16 color1; - u16 color2; - u8 lines[4]; + u16 color1; + u16 color2; + u8 lines[4]; }; static inline void DecodeBytes_C4_IA8(u32* dst, const u8* src, const u8* tlut_) { - const u16* tlut = (u16*) tlut_; - for (int x = 0; x < 4; x++) - { - u8 val = src[x]; - *dst++ = DecodePixel_IA8(tlut[val >> 4]); - *dst++ = DecodePixel_IA8(tlut[val & 0xF]); - } + const u16* tlut = (u16*)tlut_; + for (int x = 0; x < 4; x++) + { + u8 val = src[x]; + *dst++ = DecodePixel_IA8(tlut[val >> 4]); + *dst++ = DecodePixel_IA8(tlut[val & 0xF]); + } } static inline void DecodeBytes_C4_RGB565(u32* dst, const u8* src, const u8* tlut_) { - const u16* tlut = (u16*) tlut_; - for (int x = 0; x < 4; x++) - { - u8 val = src[x]; - *dst++ = DecodePixel_RGB565(Common::swap16(tlut[val >> 4])); - *dst++ = DecodePixel_RGB565(Common::swap16(tlut[val & 0xF])); - } + const u16* tlut = (u16*)tlut_; + for (int x = 0; x < 4; x++) + { + u8 val = src[x]; + *dst++ = DecodePixel_RGB565(Common::swap16(tlut[val >> 4])); + *dst++ = DecodePixel_RGB565(Common::swap16(tlut[val & 0xF])); + } } -static inline void DecodeBytes_C4_RGB5A3(u32 *dst, const u8 *src, const u8* tlut_) +static inline void DecodeBytes_C4_RGB5A3(u32* dst, const u8* src, const u8* tlut_) { - const u16* tlut = (u16*) tlut_; - for (int x = 0; x < 4; x++) - { - u8 val = src[x]; - *dst++ = DecodePixel_RGB5A3(Common::swap16(tlut[val >> 4])); - *dst++ = DecodePixel_RGB5A3(Common::swap16(tlut[val & 0xF])); - } + const u16* tlut = (u16*)tlut_; + for (int x = 0; x < 4; x++) + { + u8 val = src[x]; + *dst++ = DecodePixel_RGB5A3(Common::swap16(tlut[val >> 4])); + *dst++ = DecodePixel_RGB5A3(Common::swap16(tlut[val & 0xF])); + } } static inline void DecodeBytes_C8_IA8(u32* dst, const u8* src, const u8* tlut_) { - const u16* tlut = (u16*) tlut_; - for (int x = 0; x < 8; x++) - { - *dst++ = DecodePixel_IA8(tlut[src[x]]); - } + const u16* tlut = (u16*)tlut_; + for (int x = 0; x < 8; x++) + { + *dst++ = DecodePixel_IA8(tlut[src[x]]); + } } static inline void DecodeBytes_C8_RGB565(u32* dst, const u8* src, const u8* tlut_) { - const u16* tlut = (u16*) tlut_; - for (int x = 0; x < 8; x++) - { - u8 val = src[x]; - *dst++ = DecodePixel_RGB565(Common::swap16(tlut[val])); - } + const u16* tlut = (u16*)tlut_; + for (int x = 0; x < 8; x++) + { + u8 val = src[x]; + *dst++ = DecodePixel_RGB565(Common::swap16(tlut[val])); + } } -static inline void DecodeBytes_C8_RGB5A3(u32 *dst, const u8 *src, const u8* tlut_) +static inline void DecodeBytes_C8_RGB5A3(u32* dst, const u8* src, const u8* tlut_) { - const u16* tlut = (u16*) tlut_; - for (int x = 0; x < 8; x++) - { - u8 val = src[x]; - *dst++ = DecodePixel_RGB5A3(Common::swap16(tlut[val])); - } + const u16* tlut = (u16*)tlut_; + for (int x = 0; x < 8; x++) + { + u8 val = src[x]; + *dst++ = DecodePixel_RGB5A3(Common::swap16(tlut[val])); + } } static inline void DecodeBytes_C14X2_IA8(u32* dst, const u16* src, const u8* tlut_) { - const u16* tlut = (u16*) tlut_; - for (int x = 0; x < 4; x++) - { - u16 val = Common::swap16(src[x]); - *dst++ = DecodePixel_IA8(tlut[(val & 0x3FFF)]); - } + const u16* tlut = (u16*)tlut_; + for (int x = 0; x < 4; x++) + { + u16 val = Common::swap16(src[x]); + *dst++ = DecodePixel_IA8(tlut[(val & 0x3FFF)]); + } } static inline void DecodeBytes_C14X2_RGB565(u32* dst, const u16* src, const u8* tlut_) { - const u16* tlut = (u16*) tlut_; - for (int x = 0; x < 4; x++) - { - u16 val = Common::swap16(src[x]); - *dst++ = DecodePixel_RGB565(Common::swap16(tlut[(val & 0x3FFF)])); - } + const u16* tlut = (u16*)tlut_; + for (int x = 0; x < 4; x++) + { + u16 val = Common::swap16(src[x]); + *dst++ = DecodePixel_RGB565(Common::swap16(tlut[(val & 0x3FFF)])); + } } -static inline void DecodeBytes_C14X2_RGB5A3(u32 *dst, const u16 *src, const u8* tlut_) +static inline void DecodeBytes_C14X2_RGB5A3(u32* dst, const u16* src, const u8* tlut_) { - const u16* tlut = (u16*) tlut_; - for (int x = 0; x < 4; x++) - { - u16 val = Common::swap16(src[x]); - *dst++ = DecodePixel_RGB5A3(Common::swap16(tlut[(val & 0x3FFF)])); - } + const u16* tlut = (u16*)tlut_; + for (int x = 0; x < 4; x++) + { + u16 val = Common::swap16(src[x]); + *dst++ = DecodePixel_RGB5A3(Common::swap16(tlut[(val & 0x3FFF)])); + } } -static inline void DecodeBytes_IA4(u32 *dst, const u8 *src) +static inline void DecodeBytes_IA4(u32* dst, const u8* src) { - for (int x = 0; x < 8; x++) - { - const u8 val = src[x]; - u8 a = Convert4To8(val >> 4); - u8 l = Convert4To8(val & 0xF); - dst[x] = (a << 24) | l << 16 | l << 8 | l; - } + for (int x = 0; x < 8; x++) + { + const u8 val = src[x]; + u8 a = Convert4To8(val >> 4); + u8 l = Convert4To8(val & 0xF); + dst[x] = (a << 24) | l << 16 | l << 8 | l; + } } #ifdef CHECK static inline u32 makeRGBA(int r, int g, int b, int a) { - return (a<<24)|(b<<16)|(g<<8)|r; + return (a << 24) | (b << 16) | (g << 8) | r; } -static void DecodeDXTBlock(u32 *dst, const DXTBlock *src, int pitch) +static void DecodeDXTBlock(u32* dst, const DXTBlock* src, int pitch) { - // S3TC Decoder (Note: GCN decodes differently from PC so we can't use native support) - // Needs more speed. - u16 c1 = Common::swap16(src->color1); - u16 c2 = Common::swap16(src->color2); - int blue1 = Convert5To8(c1 & 0x1F); - int blue2 = Convert5To8(c2 & 0x1F); - int green1 = Convert6To8((c1 >> 5) & 0x3F); - int green2 = Convert6To8((c2 >> 5) & 0x3F); - int red1 = Convert5To8((c1 >> 11) & 0x1F); - int red2 = Convert5To8((c2 >> 11) & 0x1F); - int colors[4]; - colors[0] = MakeRGBA(red1, green1, blue1, 255); - colors[1] = MakeRGBA(red2, green2, blue2, 255); - if (c1 > c2) - { - int blue3 = ((blue2 - blue1) >> 1) - ((blue2 - blue1) >> 3); - int green3 = ((green2 - green1) >> 1) - ((green2 - green1) >> 3); - int red3 = ((red2 - red1) >> 1) - ((red2 - red1) >> 3); - colors[2] = MakeRGBA(red1 + red3, green1 + green3, blue1 + blue3, 255); - colors[3] = MakeRGBA(red2 - red3, green2 - green3, blue2 - blue3, 255); - } - else - { - colors[2] = MakeRGBA((red1 + red2 + 1) / 2, // Average - (green1 + green2 + 1) / 2, - (blue1 + blue2 + 1) / 2, 255); - colors[3] = MakeRGBA(red2, green2, blue2, 0); // Color2 but transparent - } + // S3TC Decoder (Note: GCN decodes differently from PC so we can't use native support) + // Needs more speed. + u16 c1 = Common::swap16(src->color1); + u16 c2 = Common::swap16(src->color2); + int blue1 = Convert5To8(c1 & 0x1F); + int blue2 = Convert5To8(c2 & 0x1F); + int green1 = Convert6To8((c1 >> 5) & 0x3F); + int green2 = Convert6To8((c2 >> 5) & 0x3F); + int red1 = Convert5To8((c1 >> 11) & 0x1F); + int red2 = Convert5To8((c2 >> 11) & 0x1F); + int colors[4]; + colors[0] = MakeRGBA(red1, green1, blue1, 255); + colors[1] = MakeRGBA(red2, green2, blue2, 255); + if (c1 > c2) + { + int blue3 = ((blue2 - blue1) >> 1) - ((blue2 - blue1) >> 3); + int green3 = ((green2 - green1) >> 1) - ((green2 - green1) >> 3); + int red3 = ((red2 - red1) >> 1) - ((red2 - red1) >> 3); + colors[2] = MakeRGBA(red1 + red3, green1 + green3, blue1 + blue3, 255); + colors[3] = MakeRGBA(red2 - red3, green2 - green3, blue2 - blue3, 255); + } + else + { + colors[2] = MakeRGBA((red1 + red2 + 1) / 2, // Average + (green1 + green2 + 1) / 2, (blue1 + blue2 + 1) / 2, 255); + colors[3] = MakeRGBA(red2, green2, blue2, 0); // Color2 but transparent + } - for (int y = 0; y < 4; y++) - { - int val = src->lines[y]; - for (int x = 0; x < 4; x++) - { - dst[x] = colors[(val >> 6) & 3]; - val <<= 2; - } - dst += pitch; - } + for (int y = 0; y < 4; y++) + { + int val = src->lines[y]; + for (int x = 0; x < 4; x++) + { + dst[x] = colors[(val >> 6) & 3]; + val <<= 2; + } + dst += pitch; + } } #endif // JSD 01/06/11: -// TODO: we really should ensure BOTH the source and destination addresses are aligned to 16-byte boundaries to -// squeeze out a little more performance. _mm_loadu_si128/_mm_storeu_si128 is slower than _mm_load_si128/_mm_store_si128 -// because they work on unaligned addresses. The processor is free to make the assumption that addresses are multiples +// TODO: we really should ensure BOTH the source and destination addresses are aligned to 16-byte +// boundaries to +// squeeze out a little more performance. _mm_loadu_si128/_mm_storeu_si128 is slower than +// _mm_load_si128/_mm_store_si128 +// because they work on unaligned addresses. The processor is free to make the assumption that +// addresses are multiples // of 16 in the aligned case. // TODO: complete SSE2 optimization of less often used texture formats. // TODO: refactor algorithms using _mm_loadl_epi64 unaligned loads to prefer 128-bit aligned loads. -void _TexDecoder_DecodeImpl(u32 * dst, const u8 * src, int width, int height, int texformat, const u8* tlut, TlutFormat tlutfmt) +void _TexDecoder_DecodeImpl(u32* dst, const u8* src, int width, int height, int texformat, + const u8* tlut, TlutFormat tlutfmt) { - const int Wsteps4 = (width + 3) / 4; - const int Wsteps8 = (width + 7) / 8; + const int Wsteps4 = (width + 3) / 4; + const int Wsteps8 = (width + 7) / 8; - switch (texformat) - { - case GX_TF_C4: - if (tlutfmt == GX_TL_RGB5A3) - { - for (int y = 0; y < height; y += 8) - for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8,yStep++) - for (int iy = 0, xStep = 8 * yStep; iy < 8; iy++,xStep++) - DecodeBytes_C4_RGB5A3(dst + (y + iy) * width + x, src + 4 * xStep, tlut); - } - else if (tlutfmt == GX_TL_IA8) - { - for (int y = 0; y < height; y += 8) - for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8,yStep++) - for (int iy = 0, xStep = 8 * yStep; iy < 8; iy++,xStep++) - DecodeBytes_C4_IA8(dst + (y + iy) * width + x, src + 4 * xStep, tlut); - - } - else if (tlutfmt == GX_TL_RGB565) - { - for (int y = 0; y < height; y += 8) - for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8,yStep++) - for (int iy = 0, xStep = 8 * yStep; iy < 8; iy++,xStep++) - DecodeBytes_C4_RGB565(dst + (y + iy) * width + x, src + 4 * xStep, tlut); - } - break; - case GX_TF_I4: - { - const __m128i kMask_x0f = _mm_set1_epi32(0x0f0f0f0fL); - const __m128i kMask_xf0 = _mm_set1_epi32(0xf0f0f0f0L); + switch (texformat) + { + case GX_TF_C4: + if (tlutfmt == GX_TL_RGB5A3) + { + for (int y = 0; y < height; y += 8) + for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 8 * yStep; iy < 8; iy++, xStep++) + DecodeBytes_C4_RGB5A3(dst + (y + iy) * width + x, src + 4 * xStep, tlut); + } + else if (tlutfmt == GX_TL_IA8) + { + for (int y = 0; y < height; y += 8) + for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 8 * yStep; iy < 8; iy++, xStep++) + DecodeBytes_C4_IA8(dst + (y + iy) * width + x, src + 4 * xStep, tlut); + } + else if (tlutfmt == GX_TL_RGB565) + { + for (int y = 0; y < height; y += 8) + for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 8 * yStep; iy < 8; iy++, xStep++) + DecodeBytes_C4_RGB565(dst + (y + iy) * width + x, src + 4 * xStep, tlut); + } + break; + case GX_TF_I4: + { + const __m128i kMask_x0f = _mm_set1_epi32(0x0f0f0f0fL); + const __m128i kMask_xf0 = _mm_set1_epi32(0xf0f0f0f0L); #if _M_SSE >= 0x301 - // xsacha optimized with SSSE3 intrinsics - // Produces a ~40% speed improvement over SSE2 implementation - if (cpu_info.bSSSE3) - { - const __m128i mask9180 = _mm_set_epi8(9,9,9,9,1,1,1,1,8,8,8,8,0,0,0,0); - const __m128i maskB3A2 = _mm_set_epi8(11,11,11,11,3,3,3,3,10,10,10,10,2,2,2,2); - const __m128i maskD5C4 = _mm_set_epi8(13,13,13,13,5,5,5,5,12,12,12,12,4,4,4,4); - const __m128i maskF7E6 = _mm_set_epi8(15,15,15,15,7,7,7,7,14,14,14,14,6,6,6,6); - for (int y = 0; y < height; y += 8) - for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8,yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 8; iy += 2,xStep++) - { - const __m128i r0 = _mm_loadl_epi64((const __m128i *)(src + 8 * xStep)); - // We want the hi 4 bits of each 8-bit word replicated to 32-bit words: - // (00000000 00000000 HhGgFfEe DdCcBbAa) -> (00000000 00000000 HHGGFFEE DDCCBBAA) - const __m128i i1 = _mm_and_si128(r0, kMask_xf0); - const __m128i i11 = _mm_or_si128(i1, _mm_srli_epi16(i1, 4)); + // xsacha optimized with SSSE3 intrinsics + // Produces a ~40% speed improvement over SSE2 implementation + if (cpu_info.bSSSE3) + { + const __m128i mask9180 = _mm_set_epi8(9, 9, 9, 9, 1, 1, 1, 1, 8, 8, 8, 8, 0, 0, 0, 0); + const __m128i maskB3A2 = _mm_set_epi8(11, 11, 11, 11, 3, 3, 3, 3, 10, 10, 10, 10, 2, 2, 2, 2); + const __m128i maskD5C4 = _mm_set_epi8(13, 13, 13, 13, 5, 5, 5, 5, 12, 12, 12, 12, 4, 4, 4, 4); + const __m128i maskF7E6 = _mm_set_epi8(15, 15, 15, 15, 7, 7, 7, 7, 14, 14, 14, 14, 6, 6, 6, 6); + for (int y = 0; y < height; y += 8) + for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 8; iy += 2, xStep++) + { + const __m128i r0 = _mm_loadl_epi64((const __m128i*)(src + 8 * xStep)); + // We want the hi 4 bits of each 8-bit word replicated to 32-bit words: + // (00000000 00000000 HhGgFfEe DdCcBbAa) -> (00000000 00000000 HHGGFFEE DDCCBBAA) + const __m128i i1 = _mm_and_si128(r0, kMask_xf0); + const __m128i i11 = _mm_or_si128(i1, _mm_srli_epi16(i1, 4)); - // Now we do same as above for the second half of the byte - const __m128i i2 = _mm_and_si128(r0, kMask_x0f); - const __m128i i22 = _mm_or_si128(i2, _mm_slli_epi16(i2,4)); + // Now we do same as above for the second half of the byte + const __m128i i2 = _mm_and_si128(r0, kMask_x0f); + const __m128i i22 = _mm_or_si128(i2, _mm_slli_epi16(i2, 4)); - // Combine both sides - const __m128i base = _mm_unpacklo_epi64(i11,i22); - // Achieve the pattern visible in the masks. - const __m128i o1 = _mm_shuffle_epi8(base, mask9180); - const __m128i o2 = _mm_shuffle_epi8(base, maskB3A2); - const __m128i o3 = _mm_shuffle_epi8(base, maskD5C4); - const __m128i o4 = _mm_shuffle_epi8(base, maskF7E6); + // Combine both sides + const __m128i base = _mm_unpacklo_epi64(i11, i22); + // Achieve the pattern visible in the masks. + const __m128i o1 = _mm_shuffle_epi8(base, mask9180); + const __m128i o2 = _mm_shuffle_epi8(base, maskB3A2); + const __m128i o3 = _mm_shuffle_epi8(base, maskD5C4); + const __m128i o4 = _mm_shuffle_epi8(base, maskF7E6); - // Write row 0: - _mm_storeu_si128( (__m128i*)( dst+(y + iy) * width + x ), o1 ); - _mm_storeu_si128( (__m128i*)( dst+(y + iy) * width + x + 4 ), o2 ); - // Write row 1: - _mm_storeu_si128( (__m128i*)( dst+(y + iy+1) * width + x ), o3 ); - _mm_storeu_si128( (__m128i*)( dst+(y + iy+1) * width + x + 4 ), o4 ); - } - } - else + // Write row 0: + _mm_storeu_si128((__m128i*)(dst + (y + iy) * width + x), o1); + _mm_storeu_si128((__m128i*)(dst + (y + iy) * width + x + 4), o2); + // Write row 1: + _mm_storeu_si128((__m128i*)(dst + (y + iy + 1) * width + x), o3); + _mm_storeu_si128((__m128i*)(dst + (y + iy + 1) * width + x + 4), o4); + } + } + else #endif - // JSD optimized with SSE2 intrinsics. - // Produces a ~76% speed improvement over reference C implementation. - { - for (int y = 0; y < height; y += 8) - for (int x = 0, yStep = (y / 8) * Wsteps8 ; x < width; x += 8, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 8; iy += 2, xStep++) - { - const __m128i r0 = _mm_loadl_epi64((const __m128i *)(src + 8 * xStep)); - // Shuffle low 64-bits with itself to expand from (0000 0000 hgfe dcba) to (hhgg ffee ddcc bbaa) - const __m128i r1 = _mm_unpacklo_epi8(r0, r0); + // JSD optimized with SSE2 intrinsics. + // Produces a ~76% speed improvement over reference C implementation. + { + for (int y = 0; y < height; y += 8) + for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 8; iy += 2, xStep++) + { + const __m128i r0 = _mm_loadl_epi64((const __m128i*)(src + 8 * xStep)); + // Shuffle low 64-bits with itself to expand from (0000 0000 hgfe dcba) to (hhgg ffee + // ddcc bbaa) + const __m128i r1 = _mm_unpacklo_epi8(r0, r0); - // We want the hi 4 bits of each 8-bit word replicated to 32-bit words: - // (HhHhGgGg FfFfEeEe DdDdCcCc BbBbAaAa) & kMask_xf0 -> (H0H0G0G0 F0F0E0E0 D0D0C0C0 B0B0A0A0) - const __m128i i1 = _mm_and_si128(r1, kMask_xf0); - // -> (HHHHGGGG FFFFEEEE DDDDCCCC BBBBAAAA) - const __m128i i11 = _mm_or_si128(i1, _mm_srli_epi16(i1, 4)); + // We want the hi 4 bits of each 8-bit word replicated to 32-bit words: + // (HhHhGgGg FfFfEeEe DdDdCcCc BbBbAaAa) & kMask_xf0 -> (H0H0G0G0 F0F0E0E0 D0D0C0C0 + // B0B0A0A0) + const __m128i i1 = _mm_and_si128(r1, kMask_xf0); + // -> (HHHHGGGG FFFFEEEE DDDDCCCC BBBBAAAA) + const __m128i i11 = _mm_or_si128(i1, _mm_srli_epi16(i1, 4)); - // Shuffle low 64-bits with itself to expand from (HHHHGGGG FFFFEEEE DDDDCCCC BBBBAAAA) to (DDDDDDDD CCCCCCCC BBBBBBBB AAAAAAAA) - const __m128i i15 = _mm_unpacklo_epi8(i11, i11); - // (DDDDDDDD CCCCCCCC BBBBBBBB AAAAAAAA) -> (BBBBBBBB BBBBBBBB AAAAAAAA AAAAAAAA) - const __m128i i151 = _mm_unpacklo_epi8(i15, i15); - // (DDDDDDDD CCCCCCCC BBBBBBBB AAAAAAAA) -> (DDDDDDDD DDDDDDDD CCCCCCCC CCCCCCCC) - const __m128i i152 = _mm_unpackhi_epi8(i15, i15); + // Shuffle low 64-bits with itself to expand from (HHHHGGGG FFFFEEEE DDDDCCCC BBBBAAAA) + // to (DDDDDDDD CCCCCCCC BBBBBBBB AAAAAAAA) + const __m128i i15 = _mm_unpacklo_epi8(i11, i11); + // (DDDDDDDD CCCCCCCC BBBBBBBB AAAAAAAA) -> (BBBBBBBB BBBBBBBB AAAAAAAA AAAAAAAA) + const __m128i i151 = _mm_unpacklo_epi8(i15, i15); + // (DDDDDDDD CCCCCCCC BBBBBBBB AAAAAAAA) -> (DDDDDDDD DDDDDDDD CCCCCCCC CCCCCCCC) + const __m128i i152 = _mm_unpackhi_epi8(i15, i15); - // Shuffle hi 64-bits with itself to expand from (HHHHGGGG FFFFEEEE DDDDCCCC BBBBAAAA) to (HHHHHHHH GGGGGGGG FFFFFFFF EEEEEEEE) - const __m128i i16 = _mm_unpackhi_epi8(i11, i11); - // (HHHHHHHH GGGGGGGG FFFFFFFF EEEEEEEE) -> (FFFFFFFF FFFFFFFF EEEEEEEE EEEEEEEE) - const __m128i i161 = _mm_unpacklo_epi8(i16, i16); - // (HHHHHHHH GGGGGGGG FFFFFFFF EEEEEEEE) -> (HHHHHHHH HHHHHHHH GGGGGGGG GGGGGGGG) - const __m128i i162 = _mm_unpackhi_epi8(i16, i16); + // Shuffle hi 64-bits with itself to expand from (HHHHGGGG FFFFEEEE DDDDCCCC BBBBAAAA) + // to (HHHHHHHH GGGGGGGG FFFFFFFF EEEEEEEE) + const __m128i i16 = _mm_unpackhi_epi8(i11, i11); + // (HHHHHHHH GGGGGGGG FFFFFFFF EEEEEEEE) -> (FFFFFFFF FFFFFFFF EEEEEEEE EEEEEEEE) + const __m128i i161 = _mm_unpacklo_epi8(i16, i16); + // (HHHHHHHH GGGGGGGG FFFFFFFF EEEEEEEE) -> (HHHHHHHH HHHHHHHH GGGGGGGG GGGGGGGG) + const __m128i i162 = _mm_unpackhi_epi8(i16, i16); - // Now find the lo 4 bits of each input 8-bit word: - const __m128i i2 = _mm_and_si128(r1, kMask_x0f); - const __m128i i22 = _mm_or_si128(i2, _mm_slli_epi16(i2,4)); + // Now find the lo 4 bits of each input 8-bit word: + const __m128i i2 = _mm_and_si128(r1, kMask_x0f); + const __m128i i22 = _mm_or_si128(i2, _mm_slli_epi16(i2, 4)); - const __m128i i25 = _mm_unpacklo_epi8(i22, i22); - const __m128i i251 = _mm_unpacklo_epi8(i25, i25); - const __m128i i252 = _mm_unpackhi_epi8(i25, i25); + const __m128i i25 = _mm_unpacklo_epi8(i22, i22); + const __m128i i251 = _mm_unpacklo_epi8(i25, i25); + const __m128i i252 = _mm_unpackhi_epi8(i25, i25); - const __m128i i26 = _mm_unpackhi_epi8(i22, i22); - const __m128i i261 = _mm_unpacklo_epi8(i26, i26); - const __m128i i262 = _mm_unpackhi_epi8(i26, i26); + const __m128i i26 = _mm_unpackhi_epi8(i22, i22); + const __m128i i261 = _mm_unpacklo_epi8(i26, i26); + const __m128i i262 = _mm_unpackhi_epi8(i26, i26); - // _mm_and_si128(i151, kMask_x00000000ffffffff) takes i151 and masks off 1st and 3rd 32-bit words - // (BBBBBBBB BBBBBBBB AAAAAAAA AAAAAAAA) -> (00000000 BBBBBBBB 00000000 AAAAAAAA) - // _mm_and_si128(i251, kMask_xffffffff00000000) takes i251 and masks off 2nd and 4th 32-bit words - // (bbbbbbbb bbbbbbbb aaaaaaaa aaaaaaaa) -> (bbbbbbbb 00000000 aaaaaaaa 00000000) - // And last but not least, _mm_or_si128 ORs those two together, giving us the interleaving we desire: - // (00000000 BBBBBBBB 00000000 AAAAAAAA) | (bbbbbbbb 00000000 aaaaaaaa 00000000) -> (bbbbbbbb BBBBBBBB aaaaaaaa AAAAAAAA) - const __m128i kMask_x00000000ffffffff = _mm_set_epi32(0x00000000L, 0xffffffffL, 0x00000000L, 0xffffffffL); - const __m128i kMask_xffffffff00000000 = _mm_set_epi32(0xffffffffL, 0x00000000L, 0xffffffffL, 0x00000000L); - const __m128i o1 = _mm_or_si128(_mm_and_si128(i151, kMask_x00000000ffffffff), _mm_and_si128(i251, kMask_xffffffff00000000)); - const __m128i o2 = _mm_or_si128(_mm_and_si128(i152, kMask_x00000000ffffffff), _mm_and_si128(i252, kMask_xffffffff00000000)); + // _mm_and_si128(i151, kMask_x00000000ffffffff) takes i151 and masks off 1st and 3rd + // 32-bit words + // (BBBBBBBB BBBBBBBB AAAAAAAA AAAAAAAA) -> (00000000 BBBBBBBB 00000000 AAAAAAAA) + // _mm_and_si128(i251, kMask_xffffffff00000000) takes i251 and masks off 2nd and 4th + // 32-bit words + // (bbbbbbbb bbbbbbbb aaaaaaaa aaaaaaaa) -> (bbbbbbbb 00000000 aaaaaaaa 00000000) + // And last but not least, _mm_or_si128 ORs those two together, giving us the + // interleaving we desire: + // (00000000 BBBBBBBB 00000000 AAAAAAAA) | (bbbbbbbb 00000000 aaaaaaaa 00000000) -> + // (bbbbbbbb BBBBBBBB aaaaaaaa AAAAAAAA) + const __m128i kMask_x00000000ffffffff = + _mm_set_epi32(0x00000000L, 0xffffffffL, 0x00000000L, 0xffffffffL); + const __m128i kMask_xffffffff00000000 = + _mm_set_epi32(0xffffffffL, 0x00000000L, 0xffffffffL, 0x00000000L); + const __m128i o1 = _mm_or_si128(_mm_and_si128(i151, kMask_x00000000ffffffff), + _mm_and_si128(i251, kMask_xffffffff00000000)); + const __m128i o2 = _mm_or_si128(_mm_and_si128(i152, kMask_x00000000ffffffff), + _mm_and_si128(i252, kMask_xffffffff00000000)); - // These two are for the next row; same pattern as above. We batched up two rows because our input was 64 bits. - const __m128i o3 = _mm_or_si128(_mm_and_si128(i161, kMask_x00000000ffffffff), _mm_and_si128(i261, kMask_xffffffff00000000)); - const __m128i o4 = _mm_or_si128(_mm_and_si128(i162, kMask_x00000000ffffffff), _mm_and_si128(i262, kMask_xffffffff00000000)); - // Write row 0: - _mm_storeu_si128( (__m128i*)( dst+(y + iy) * width + x ), o1 ); - _mm_storeu_si128( (__m128i*)( dst+(y + iy) * width + x + 4 ), o2 ); - // Write row 1: - _mm_storeu_si128( (__m128i*)( dst+(y + iy+1) * width + x ), o3 ); - _mm_storeu_si128( (__m128i*)( dst+(y + iy+1) * width + x + 4 ), o4 ); - } - } - } - break; - case GX_TF_I8: // speed critical - { + // These two are for the next row; same pattern as above. We batched up two rows because + // our input was 64 bits. + const __m128i o3 = _mm_or_si128(_mm_and_si128(i161, kMask_x00000000ffffffff), + _mm_and_si128(i261, kMask_xffffffff00000000)); + const __m128i o4 = _mm_or_si128(_mm_and_si128(i162, kMask_x00000000ffffffff), + _mm_and_si128(i262, kMask_xffffffff00000000)); + // Write row 0: + _mm_storeu_si128((__m128i*)(dst + (y + iy) * width + x), o1); + _mm_storeu_si128((__m128i*)(dst + (y + iy) * width + x + 4), o2); + // Write row 1: + _mm_storeu_si128((__m128i*)(dst + (y + iy + 1) * width + x), o3); + _mm_storeu_si128((__m128i*)(dst + (y + iy + 1) * width + x + 4), o4); + } + } + } + break; + case GX_TF_I8: // speed critical + { #if _M_SSE >= 0x301 - // xsacha optimized with SSSE3 intrinsics - // Produces a ~10% speed improvement over SSE2 implementation - if (cpu_info.bSSSE3) - { - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8,yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; ++iy, xStep++) - { - const __m128i mask3210 = _mm_set_epi8(3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0); + // xsacha optimized with SSSE3 intrinsics + // Produces a ~10% speed improvement over SSE2 implementation + if (cpu_info.bSSSE3) + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; ++iy, xStep++) + { + const __m128i mask3210 = _mm_set_epi8(3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0); - const __m128i mask7654 = _mm_set_epi8(7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4); - __m128i *quaddst, r, rgba0, rgba1; - // Load 64 bits from `src` into an __m128i with upper 64 bits zeroed: (0000 0000 hgfe dcba) - r = _mm_loadl_epi64((const __m128i *)(src + 8 * xStep)); - // Shuffle select bytes to expand from (0000 0000 hgfe dcba) to: - rgba0 = _mm_shuffle_epi8(r, mask3210); // (dddd cccc bbbb aaaa) - rgba1 = _mm_shuffle_epi8(r, mask7654); // (hhhh gggg ffff eeee) + const __m128i mask7654 = _mm_set_epi8(7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4); + __m128i *quaddst, r, rgba0, rgba1; + // Load 64 bits from `src` into an __m128i with upper 64 bits zeroed: (0000 0000 hgfe + // dcba) + r = _mm_loadl_epi64((const __m128i*)(src + 8 * xStep)); + // Shuffle select bytes to expand from (0000 0000 hgfe dcba) to: + rgba0 = _mm_shuffle_epi8(r, mask3210); // (dddd cccc bbbb aaaa) + rgba1 = _mm_shuffle_epi8(r, mask7654); // (hhhh gggg ffff eeee) - quaddst = (__m128i *)(dst + (y + iy)*width + x); - _mm_storeu_si128(quaddst, rgba0); - _mm_storeu_si128(quaddst+1, rgba1); - } - - } - else + quaddst = (__m128i*)(dst + (y + iy) * width + x); + _mm_storeu_si128(quaddst, rgba0); + _mm_storeu_si128(quaddst + 1, rgba1); + } + } + else #endif - // JSD optimized with SSE2 intrinsics. - // Produces an ~86% speed improvement over reference C implementation. - { - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8,yStep++) - { - // Each loop iteration processes 4 rows from 4 64-bit reads. - const u8* src2 = src + 32 * yStep; - // TODO: is it more efficient to group the loads together sequentially and also the stores at the end? - // _mm_stream instead of _mm_store on my AMD Phenom II x410 made performance significantly WORSE, so I - // went with _mm_stores. Perhaps there is some edge case here creating the terrible performance or we're - // not aligned to 16-byte boundaries. I don't know. - __m128i *quaddst; + // JSD optimized with SSE2 intrinsics. + // Produces an ~86% speed improvement over reference C implementation. + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + { + // Each loop iteration processes 4 rows from 4 64-bit reads. + const u8* src2 = src + 32 * yStep; + // TODO: is it more efficient to group the loads together sequentially and also the stores + // at the end? + // _mm_stream instead of _mm_store on my AMD Phenom II x410 made performance significantly + // WORSE, so I + // went with _mm_stores. Perhaps there is some edge case here creating the terrible + // performance or we're + // not aligned to 16-byte boundaries. I don't know. + __m128i* quaddst; - // Load 64 bits from `src` into an __m128i with upper 64 bits zeroed: (0000 0000 hgfe dcba) - const __m128i r0 = _mm_loadl_epi64((const __m128i *)src2); - // Shuffle low 64-bits with itself to expand from (0000 0000 hgfe dcba) to (hhgg ffee ddcc bbaa) - const __m128i r1 = _mm_unpacklo_epi8(r0, r0); + // Load 64 bits from `src` into an __m128i with upper 64 bits zeroed: (0000 0000 hgfe + // dcba) + const __m128i r0 = _mm_loadl_epi64((const __m128i*)src2); + // Shuffle low 64-bits with itself to expand from (0000 0000 hgfe dcba) to (hhgg ffee ddcc + // bbaa) + const __m128i r1 = _mm_unpacklo_epi8(r0, r0); - // Shuffle low 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (dddd cccc bbbb aaaa) - const __m128i rgba0 = _mm_unpacklo_epi8(r1, r1); - // Shuffle hi 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (hhhh gggg ffff eeee) - const __m128i rgba1 = _mm_unpackhi_epi8(r1, r1); + // Shuffle low 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (dddd cccc bbbb + // aaaa) + const __m128i rgba0 = _mm_unpacklo_epi8(r1, r1); + // Shuffle hi 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (hhhh gggg ffff + // eeee) + const __m128i rgba1 = _mm_unpackhi_epi8(r1, r1); - // Store (dddd cccc bbbb aaaa) out: - quaddst = (__m128i *)(dst + (y + 0)*width + x); - _mm_storeu_si128(quaddst, rgba0); - // Store (hhhh gggg ffff eeee) out: - _mm_storeu_si128(quaddst+1, rgba1); + // Store (dddd cccc bbbb aaaa) out: + quaddst = (__m128i*)(dst + (y + 0) * width + x); + _mm_storeu_si128(quaddst, rgba0); + // Store (hhhh gggg ffff eeee) out: + _mm_storeu_si128(quaddst + 1, rgba1); - // Load 64 bits from `src` into an __m128i with upper 64 bits zeroed: (0000 0000 hgfe dcba) - src2 += 8; - const __m128i r2 = _mm_loadl_epi64((const __m128i *)src2); - // Shuffle low 64-bits with itself to expand from (0000 0000 hgfe dcba) to (hhgg ffee ddcc bbaa) - const __m128i r3 = _mm_unpacklo_epi8(r2, r2); + // Load 64 bits from `src` into an __m128i with upper 64 bits zeroed: (0000 0000 hgfe + // dcba) + src2 += 8; + const __m128i r2 = _mm_loadl_epi64((const __m128i*)src2); + // Shuffle low 64-bits with itself to expand from (0000 0000 hgfe dcba) to (hhgg ffee ddcc + // bbaa) + const __m128i r3 = _mm_unpacklo_epi8(r2, r2); - // Shuffle low 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (dddd cccc bbbb aaaa) - const __m128i rgba2 = _mm_unpacklo_epi8(r3, r3); - // Shuffle hi 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (hhhh gggg ffff eeee) - const __m128i rgba3 = _mm_unpackhi_epi8(r3, r3); + // Shuffle low 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (dddd cccc bbbb + // aaaa) + const __m128i rgba2 = _mm_unpacklo_epi8(r3, r3); + // Shuffle hi 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (hhhh gggg ffff + // eeee) + const __m128i rgba3 = _mm_unpackhi_epi8(r3, r3); - // Store (dddd cccc bbbb aaaa) out: - quaddst = (__m128i *)(dst + (y + 1)*width + x); - _mm_storeu_si128(quaddst, rgba2); - // Store (hhhh gggg ffff eeee) out: - _mm_storeu_si128(quaddst+1, rgba3); + // Store (dddd cccc bbbb aaaa) out: + quaddst = (__m128i*)(dst + (y + 1) * width + x); + _mm_storeu_si128(quaddst, rgba2); + // Store (hhhh gggg ffff eeee) out: + _mm_storeu_si128(quaddst + 1, rgba3); - // Load 64 bits from `src` into an __m128i with upper 64 bits zeroed: (0000 0000 hgfe dcba) - src2 += 8; - const __m128i r4 = _mm_loadl_epi64((const __m128i *)src2); - // Shuffle low 64-bits with itself to expand from (0000 0000 hgfe dcba) to (hhgg ffee ddcc bbaa) - const __m128i r5 = _mm_unpacklo_epi8(r4, r4); + // Load 64 bits from `src` into an __m128i with upper 64 bits zeroed: (0000 0000 hgfe + // dcba) + src2 += 8; + const __m128i r4 = _mm_loadl_epi64((const __m128i*)src2); + // Shuffle low 64-bits with itself to expand from (0000 0000 hgfe dcba) to (hhgg ffee ddcc + // bbaa) + const __m128i r5 = _mm_unpacklo_epi8(r4, r4); - // Shuffle low 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (dddd cccc bbbb aaaa) - const __m128i rgba4 = _mm_unpacklo_epi8(r5, r5); - // Shuffle hi 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (hhhh gggg ffff eeee) - const __m128i rgba5 = _mm_unpackhi_epi8(r5, r5); + // Shuffle low 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (dddd cccc bbbb + // aaaa) + const __m128i rgba4 = _mm_unpacklo_epi8(r5, r5); + // Shuffle hi 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (hhhh gggg ffff + // eeee) + const __m128i rgba5 = _mm_unpackhi_epi8(r5, r5); - // Store (dddd cccc bbbb aaaa) out: - quaddst = (__m128i *)(dst + (y + 2)*width + x); - _mm_storeu_si128(quaddst, rgba4); - // Store (hhhh gggg ffff eeee) out: - _mm_storeu_si128(quaddst+1, rgba5); + // Store (dddd cccc bbbb aaaa) out: + quaddst = (__m128i*)(dst + (y + 2) * width + x); + _mm_storeu_si128(quaddst, rgba4); + // Store (hhhh gggg ffff eeee) out: + _mm_storeu_si128(quaddst + 1, rgba5); - // Load 64 bits from `src` into an __m128i with upper 64 bits zeroed: (0000 0000 hgfe dcba) - src2 += 8; - const __m128i r6 = _mm_loadl_epi64((const __m128i *)src2); - // Shuffle low 64-bits with itself to expand from (0000 0000 hgfe dcba) to (hhgg ffee ddcc bbaa) - const __m128i r7 = _mm_unpacklo_epi8(r6, r6); + // Load 64 bits from `src` into an __m128i with upper 64 bits zeroed: (0000 0000 hgfe + // dcba) + src2 += 8; + const __m128i r6 = _mm_loadl_epi64((const __m128i*)src2); + // Shuffle low 64-bits with itself to expand from (0000 0000 hgfe dcba) to (hhgg ffee ddcc + // bbaa) + const __m128i r7 = _mm_unpacklo_epi8(r6, r6); - // Shuffle low 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (dddd cccc bbbb aaaa) - const __m128i rgba6 = _mm_unpacklo_epi8(r7, r7); - // Shuffle hi 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (hhhh gggg ffff eeee) - const __m128i rgba7 = _mm_unpackhi_epi8(r7, r7); + // Shuffle low 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (dddd cccc bbbb + // aaaa) + const __m128i rgba6 = _mm_unpacklo_epi8(r7, r7); + // Shuffle hi 64-bits with itself to expand from (hhgg ffee ddcc bbaa) to (hhhh gggg ffff + // eeee) + const __m128i rgba7 = _mm_unpackhi_epi8(r7, r7); - // Store (dddd cccc bbbb aaaa) out: - quaddst = (__m128i *)(dst + (y + 3)*width + x); - _mm_storeu_si128(quaddst, rgba6); - // Store (hhhh gggg ffff eeee) out: - _mm_storeu_si128(quaddst+1, rgba7); - - } - } - } - break; - case GX_TF_C8: - if (tlutfmt == GX_TL_RGB5A3) - { - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) - DecodeBytes_C8_RGB5A3((u32*)dst + (y + iy) * width + x, src + 8 * xStep, tlut); - } - else if (tlutfmt == GX_TL_IA8) - { - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) - DecodeBytes_C8_IA8(dst + (y + iy) * width + x, src + 8 * xStep, tlut); - - } - else if (tlutfmt == GX_TL_RGB565) - { - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) - DecodeBytes_C8_RGB565(dst + (y + iy) * width + x, src + 8 * xStep, tlut); - - } - break; - case GX_TF_IA4: - { - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) - DecodeBytes_IA4(dst + (y + iy) * width + x, src + 8 * xStep); - } - break; - case GX_TF_IA8: - { + // Store (dddd cccc bbbb aaaa) out: + quaddst = (__m128i*)(dst + (y + 3) * width + x); + _mm_storeu_si128(quaddst, rgba6); + // Store (hhhh gggg ffff eeee) out: + _mm_storeu_si128(quaddst + 1, rgba7); + } + } + } + break; + case GX_TF_C8: + if (tlutfmt == GX_TL_RGB5A3) + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + DecodeBytes_C8_RGB5A3((u32*)dst + (y + iy) * width + x, src + 8 * xStep, tlut); + } + else if (tlutfmt == GX_TL_IA8) + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + DecodeBytes_C8_IA8(dst + (y + iy) * width + x, src + 8 * xStep, tlut); + } + else if (tlutfmt == GX_TL_RGB565) + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + DecodeBytes_C8_RGB565(dst + (y + iy) * width + x, src + 8 * xStep, tlut); + } + break; + case GX_TF_IA4: + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps8; x < width; x += 8, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + DecodeBytes_IA4(dst + (y + iy) * width + x, src + 8 * xStep); + } + break; + case GX_TF_IA8: + { #if _M_SSE >= 0x301 - // xsacha optimized with SSSE3 intrinsics. - // Produces an ~50% speed improvement over SSE2 implementation. - if (cpu_info.bSSSE3) - { - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) - { - const __m128i mask = _mm_set_epi8(6, 7, 7, 7, 4, 5, 5, 5, 2, 3, 3, 3, 0, 1, 1, 1); - // Load 4x 16-bit IA8 samples from `src` into an __m128i with upper 64 bits zeroed: (0000 0000 hgfe dcba) - const __m128i r0 = _mm_loadl_epi64((const __m128i *)(src + 8 * xStep)); - // Shuffle to (ghhh efff cddd abbb) - const __m128i r1 = _mm_shuffle_epi8(r0, mask); - _mm_storeu_si128( (__m128i*)(dst + (y + iy) * width + x), r1 ); - } - } - else + // xsacha optimized with SSSE3 intrinsics. + // Produces an ~50% speed improvement over SSE2 implementation. + if (cpu_info.bSSSE3) + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + { + const __m128i mask = _mm_set_epi8(6, 7, 7, 7, 4, 5, 5, 5, 2, 3, 3, 3, 0, 1, 1, 1); + // Load 4x 16-bit IA8 samples from `src` into an __m128i with upper 64 bits zeroed: + // (0000 0000 hgfe dcba) + const __m128i r0 = _mm_loadl_epi64((const __m128i*)(src + 8 * xStep)); + // Shuffle to (ghhh efff cddd abbb) + const __m128i r1 = _mm_shuffle_epi8(r0, mask); + _mm_storeu_si128((__m128i*)(dst + (y + iy) * width + x), r1); + } + } + else #endif - // JSD optimized with SSE2 intrinsics. - // Produces an ~80% speed improvement over reference C implementation. - { - const __m128i kMask_xf0 = _mm_set_epi32(0x00000000L, 0x00000000L, 0xff00ff00L, 0xff00ff00L); - const __m128i kMask_x0f = _mm_set_epi32(0x00000000L, 0x00000000L, 0x00ff00ffL, 0x00ff00ffL); - const __m128i kMask_xf000 = _mm_set_epi32(0xff000000L, 0xff000000L, 0xff000000L, 0xff000000L); - const __m128i kMask_x0fff = _mm_set_epi32(0x00ffffffL, 0x00ffffffL, 0x00ffffffL, 0x00ffffffL); - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) - { - // Expands a 16-bit "IA" to a 32-bit "AIII". Each char is an 8-bit value. + // JSD optimized with SSE2 intrinsics. + // Produces an ~80% speed improvement over reference C implementation. + { + const __m128i kMask_xf0 = _mm_set_epi32(0x00000000L, 0x00000000L, 0xff00ff00L, 0xff00ff00L); + const __m128i kMask_x0f = _mm_set_epi32(0x00000000L, 0x00000000L, 0x00ff00ffL, 0x00ff00ffL); + const __m128i kMask_xf000 = _mm_set_epi32(0xff000000L, 0xff000000L, 0xff000000L, 0xff000000L); + const __m128i kMask_x0fff = _mm_set_epi32(0x00ffffffL, 0x00ffffffL, 0x00ffffffL, 0x00ffffffL); + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + { + // Expands a 16-bit "IA" to a 32-bit "AIII". Each char is an 8-bit value. - // Load 4x 16-bit IA8 samples from `src` into an __m128i with upper 64 bits zeroed: (0000 0000 hgfe dcba) - const __m128i r0 = _mm_loadl_epi64((const __m128i *)(src+ 8 * xStep)); + // Load 4x 16-bit IA8 samples from `src` into an __m128i with upper 64 bits zeroed: + // (0000 0000 hgfe dcba) + const __m128i r0 = _mm_loadl_epi64((const __m128i*)(src + 8 * xStep)); - // Logical shift all 16-bit words right by 8 bits (0000 0000 hgfe dcba) to (0000 0000 0h0f 0d0b) - // This gets us only the I components. - const __m128i i0 = _mm_srli_epi16(r0, 8); + // Logical shift all 16-bit words right by 8 bits (0000 0000 hgfe dcba) to (0000 0000 + // 0h0f 0d0b) + // This gets us only the I components. + const __m128i i0 = _mm_srli_epi16(r0, 8); - // Now join up the I components from their original positions but mask out the A components. - // (0000 0000 hgfe dcba) & kMask_xFF00 -> (0000 0000 h0f0 d0b0) - // (0000 0000 h0f0 d0b0) | (0000 0000 0h0f 0d0b) -> (0000 0000 hhff ddbb) - const __m128i i1 = _mm_or_si128(_mm_and_si128(r0, kMask_xf0), i0); + // Now join up the I components from their original positions but mask out the A + // components. + // (0000 0000 hgfe dcba) & kMask_xFF00 -> (0000 0000 h0f0 d0b0) + // (0000 0000 h0f0 d0b0) | (0000 0000 0h0f 0d0b) -> (0000 0000 hhff ddbb) + const __m128i i1 = _mm_or_si128(_mm_and_si128(r0, kMask_xf0), i0); - // Shuffle low 64-bits with itself to expand from (0000 0000 hhff ddbb) to (hhhh ffff dddd bbbb) - const __m128i i2 = _mm_unpacklo_epi8(i1, i1); - // (hhhh ffff dddd bbbb) & kMask_x0fff -> (0hhh 0fff 0ddd 0bbb) - const __m128i i3 = _mm_and_si128(i2, kMask_x0fff); + // Shuffle low 64-bits with itself to expand from (0000 0000 hhff ddbb) to (hhhh ffff + // dddd bbbb) + const __m128i i2 = _mm_unpacklo_epi8(i1, i1); + // (hhhh ffff dddd bbbb) & kMask_x0fff -> (0hhh 0fff 0ddd 0bbb) + const __m128i i3 = _mm_and_si128(i2, kMask_x0fff); - // Now that we have the I components in 32-bit word form, time work out the A components into - // their final positions. + // Now that we have the I components in 32-bit word form, time work out the A components + // into + // their final positions. - // (0000 0000 hgfe dcba) & kMask_x00FF -> (0000 0000 0g0e 0c0a) - const __m128i a0 = _mm_and_si128(r0, kMask_x0f); - // (0000 0000 0g0e 0c0a) -> (00gg 00ee 00cc 00aa) - const __m128i a1 = _mm_unpacklo_epi8(a0, a0); - // (00gg 00ee 00cc 00aa) << 16 -> (gg00 ee00 cc00 aa00) - const __m128i a2 = _mm_slli_epi32(a1, 16); - // (gg00 ee00 cc00 aa00) & kMask_xf000 -> (g000 e000 c000 a000) - const __m128i a3 = _mm_and_si128(a2, kMask_xf000); + // (0000 0000 hgfe dcba) & kMask_x00FF -> (0000 0000 0g0e 0c0a) + const __m128i a0 = _mm_and_si128(r0, kMask_x0f); + // (0000 0000 0g0e 0c0a) -> (00gg 00ee 00cc 00aa) + const __m128i a1 = _mm_unpacklo_epi8(a0, a0); + // (00gg 00ee 00cc 00aa) << 16 -> (gg00 ee00 cc00 aa00) + const __m128i a2 = _mm_slli_epi32(a1, 16); + // (gg00 ee00 cc00 aa00) & kMask_xf000 -> (g000 e000 c000 a000) + const __m128i a3 = _mm_and_si128(a2, kMask_xf000); - // Simply OR up i3 and a3 now and that's our result: - // (0hhh 0fff 0ddd 0bbb) | (g000 e000 c000 a000) -> (ghhh efff cddd abbb) - const __m128i r1 = _mm_or_si128(i3, a3); + // Simply OR up i3 and a3 now and that's our result: + // (0hhh 0fff 0ddd 0bbb) | (g000 e000 c000 a000) -> (ghhh efff cddd abbb) + const __m128i r1 = _mm_or_si128(i3, a3); - // write out the 128-bit result: - _mm_storeu_si128( (__m128i*)(dst + (y + iy) * width + x), r1 ); - } - } - } - break; - case GX_TF_C14X2: - if (tlutfmt == GX_TL_RGB5A3) - { - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) - DecodeBytes_C14X2_RGB5A3(dst + (y + iy) * width + x, (u16*)(src + 8 * xStep), tlut); - } - else if (tlutfmt == GX_TL_IA8) - { - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) - DecodeBytes_C14X2_IA8(dst + (y + iy) * width + x, (u16*)(src + 8 * xStep), tlut); - } - else if (tlutfmt == GX_TL_RGB565) - { - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) - DecodeBytes_C14X2_RGB565(dst + (y + iy) * width + x, (u16*)(src + 8 * xStep), tlut); - } - break; - case GX_TF_RGB565: - { - // JSD optimized with SSE2 intrinsics. - // Produces an ~78% speed improvement over reference C implementation. - const __m128i kMaskR0 = _mm_set1_epi32(0x000000F8); - const __m128i kMaskG0 = _mm_set1_epi32(0x0000FC00); - const __m128i kMaskG1 = _mm_set1_epi32(0x00000300); - const __m128i kMaskB0 = _mm_set1_epi32(0x00F80000); - const __m128i kAlpha = _mm_set1_epi32(0xFF000000); - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) - { - __m128i *dxtsrc = (__m128i *)(src + 8 * xStep); - // Load 4x 16-bit colors: (0000 0000 hgfe dcba) - // where hg, fe, ba, and dc are 16-bit colors in big-endian order - const __m128i rgb565x4 = _mm_loadl_epi64(dxtsrc); + // write out the 128-bit result: + _mm_storeu_si128((__m128i*)(dst + (y + iy) * width + x), r1); + } + } + } + break; + case GX_TF_C14X2: + if (tlutfmt == GX_TL_RGB5A3) + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + DecodeBytes_C14X2_RGB5A3(dst + (y + iy) * width + x, (u16*)(src + 8 * xStep), tlut); + } + else if (tlutfmt == GX_TL_IA8) + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + DecodeBytes_C14X2_IA8(dst + (y + iy) * width + x, (u16*)(src + 8 * xStep), tlut); + } + else if (tlutfmt == GX_TL_RGB565) + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + DecodeBytes_C14X2_RGB565(dst + (y + iy) * width + x, (u16*)(src + 8 * xStep), tlut); + } + break; + case GX_TF_RGB565: + { + // JSD optimized with SSE2 intrinsics. + // Produces an ~78% speed improvement over reference C implementation. + const __m128i kMaskR0 = _mm_set1_epi32(0x000000F8); + const __m128i kMaskG0 = _mm_set1_epi32(0x0000FC00); + const __m128i kMaskG1 = _mm_set1_epi32(0x00000300); + const __m128i kMaskB0 = _mm_set1_epi32(0x00F80000); + const __m128i kAlpha = _mm_set1_epi32(0xFF000000); + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + { + __m128i* dxtsrc = (__m128i*)(src + 8 * xStep); + // Load 4x 16-bit colors: (0000 0000 hgfe dcba) + // where hg, fe, ba, and dc are 16-bit colors in big-endian order + const __m128i rgb565x4 = _mm_loadl_epi64(dxtsrc); - // The big-endian 16-bit colors `ba` and `dc` look like 0b_gggBBBbb_RRRrrGGg in a little endian xmm register - // Unpack `hgfe dcba` to `hhgg ffee ddcc bbaa`, where each 32-bit word is now 0b_gggBBBbb_RRRrrGGg_gggBBBbb_RRRrrGGg - const __m128i c0 = _mm_unpacklo_epi16(rgb565x4, rgb565x4); + // The big-endian 16-bit colors `ba` and `dc` look like 0b_gggBBBbb_RRRrrGGg in a little + // endian xmm register + // Unpack `hgfe dcba` to `hhgg ffee ddcc bbaa`, where each 32-bit word is now + // 0b_gggBBBbb_RRRrrGGg_gggBBBbb_RRRrrGGg + const __m128i c0 = _mm_unpacklo_epi16(rgb565x4, rgb565x4); - // swizzle 0b_gggBBBbb_RRRrrGGg_gggBBBbb_RRRrrGGg - // to 0b_11111111_BBBbbBBB_GGggggGG_RRRrrRRR + // swizzle 0b_gggBBBbb_RRRrrGGg_gggBBBbb_RRRrrGGg + // to 0b_11111111_BBBbbBBB_GGggggGG_RRRrrRRR - // 0b_gggBBBbb_RRRrrGGg_gggBBBbb_RRRrrGGg & - // 0b_00000000_00000000_00000000_11111000 = - // 0b_00000000_00000000_00000000_RRRrr000 - const __m128i r0 = _mm_and_si128(c0, kMaskR0); - // 0b_00000000_00000000_00000000_RRRrr000 >> 5 [32] = - // 0b_00000000_00000000_00000000_00000RRR - const __m128i r1 = _mm_srli_epi32(r0, 5); + // 0b_gggBBBbb_RRRrrGGg_gggBBBbb_RRRrrGGg & + // 0b_00000000_00000000_00000000_11111000 = + // 0b_00000000_00000000_00000000_RRRrr000 + const __m128i r0 = _mm_and_si128(c0, kMaskR0); + // 0b_00000000_00000000_00000000_RRRrr000 >> 5 [32] = + // 0b_00000000_00000000_00000000_00000RRR + const __m128i r1 = _mm_srli_epi32(r0, 5); - // 0b_gggBBBbb_RRRrrGGg_gggBBBbb_RRRrrGGg >> 3 [32] = - // 0b_000gggBB_BbbRRRrr_GGggggBB_BbbRRRrr & - // 0b_00000000_00000000_11111100_00000000 = - // 0b_00000000_00000000_GGgggg00_00000000 - const __m128i gtmp = _mm_srli_epi32(c0, 3); - const __m128i g0 = _mm_and_si128(gtmp, kMaskG0); - // 0b_GGggggBB_BbbRRRrr_GGggggBB_Bbb00000 >> 6 [32] = - // 0b_000000GG_ggggBBBb_bRRRrrGG_ggggBBBb & - // 0b_00000000_00000000_00000011_00000000 = - // 0b_00000000_00000000_000000GG_00000000 = - const __m128i g1 = _mm_and_si128(_mm_srli_epi32(gtmp, 6), kMaskG1); + // 0b_gggBBBbb_RRRrrGGg_gggBBBbb_RRRrrGGg >> 3 [32] = + // 0b_000gggBB_BbbRRRrr_GGggggBB_BbbRRRrr & + // 0b_00000000_00000000_11111100_00000000 = + // 0b_00000000_00000000_GGgggg00_00000000 + const __m128i gtmp = _mm_srli_epi32(c0, 3); + const __m128i g0 = _mm_and_si128(gtmp, kMaskG0); + // 0b_GGggggBB_BbbRRRrr_GGggggBB_Bbb00000 >> 6 [32] = + // 0b_000000GG_ggggBBBb_bRRRrrGG_ggggBBBb & + // 0b_00000000_00000000_00000011_00000000 = + // 0b_00000000_00000000_000000GG_00000000 = + const __m128i g1 = _mm_and_si128(_mm_srli_epi32(gtmp, 6), kMaskG1); - // 0b_gggBBBbb_RRRrrGGg_gggBBBbb_RRRrrGGg >> 5 [32] = - // 0b_00000ggg_BBBbbRRR_rrGGgggg_BBBbbRRR & - // 0b_00000000_11111000_00000000_00000000 = - // 0b_00000000_BBBbb000_00000000_00000000 - const __m128i b0 = _mm_and_si128(_mm_srli_epi32(c0, 5), kMaskB0); - // 0b_00000000_BBBbb000_00000000_00000000 >> 5 [16] = - // 0b_00000000_00000BBB_00000000_00000000 - const __m128i b1 = _mm_srli_epi16(b0, 5); + // 0b_gggBBBbb_RRRrrGGg_gggBBBbb_RRRrrGGg >> 5 [32] = + // 0b_00000ggg_BBBbbRRR_rrGGgggg_BBBbbRRR & + // 0b_00000000_11111000_00000000_00000000 = + // 0b_00000000_BBBbb000_00000000_00000000 + const __m128i b0 = _mm_and_si128(_mm_srli_epi32(c0, 5), kMaskB0); + // 0b_00000000_BBBbb000_00000000_00000000 >> 5 [16] = + // 0b_00000000_00000BBB_00000000_00000000 + const __m128i b1 = _mm_srli_epi16(b0, 5); - // OR together the final RGB bits and the alpha component: - const __m128i abgr888x4 = _mm_or_si128( - _mm_or_si128( - _mm_or_si128(r0, r1), - _mm_or_si128(g0, g1) - ), - _mm_or_si128( - _mm_or_si128(b0, b1), - kAlpha - ) - ); + // OR together the final RGB bits and the alpha component: + const __m128i abgr888x4 = + _mm_or_si128(_mm_or_si128(_mm_or_si128(r0, r1), _mm_or_si128(g0, g1)), + _mm_or_si128(_mm_or_si128(b0, b1), kAlpha)); - __m128i *ptr = (__m128i *)(dst + (y + iy) * width + x); - _mm_storeu_si128(ptr, abgr888x4); - } - } - break; - case GX_TF_RGB5A3: - { - const __m128i kMask_x1f = _mm_set1_epi32(0x0000001fL); - const __m128i kMask_x0f = _mm_set1_epi32(0x0000000fL); - const __m128i kMask_x07 = _mm_set1_epi32(0x00000007L); - // This is the hard-coded 0xFF alpha constant that is ORed in place after the RGB are calculated - // for the RGB555 case when (s[x] & 0x8000) is true for all pixels. - const __m128i aVxff00 = _mm_set1_epi32(0xFF000000L); + __m128i* ptr = (__m128i*)(dst + (y + iy) * width + x); + _mm_storeu_si128(ptr, abgr888x4); + } + } + break; + case GX_TF_RGB5A3: + { + const __m128i kMask_x1f = _mm_set1_epi32(0x0000001fL); + const __m128i kMask_x0f = _mm_set1_epi32(0x0000000fL); + const __m128i kMask_x07 = _mm_set1_epi32(0x00000007L); + // This is the hard-coded 0xFF alpha constant that is ORed in place after the RGB are calculated + // for the RGB555 case when (s[x] & 0x8000) is true for all pixels. + const __m128i aVxff00 = _mm_set1_epi32(0xFF000000L); #if _M_SSE >= 0x301 - // xsacha optimized with SSSE3 intrinsics (2 in 4 cases) - // Produces a ~10% speed improvement over SSE2 implementation - if (cpu_info.bSSSE3) - { - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) - { - u32 *newdst = dst+(y+iy)*width+x; - const __m128i mask = _mm_set_epi8(-128,-128,6,7,-128,-128,4,5,-128,-128,2,3,-128,-128,0,1); - const __m128i valV = _mm_shuffle_epi8(_mm_loadl_epi64((const __m128i*)(src + 8 * xStep)),mask); - int cmp = _mm_movemask_epi8(valV); //MSB: 0x2 = val0; 0x20=val1; 0x200 = val2; 0x2000=val3 - if ((cmp&0x2222)==0x2222) // SSSE3 case #1: all 4 pixels are in RGB555 and alpha = 0xFF. - { - // Swizzle bits: 00012345 -> 12345123 + // xsacha optimized with SSSE3 intrinsics (2 in 4 cases) + // Produces a ~10% speed improvement over SSE2 implementation + if (cpu_info.bSSSE3) + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + { + u32* newdst = dst + (y + iy) * width + x; + const __m128i mask = _mm_set_epi8(-128, -128, 6, 7, -128, -128, 4, 5, -128, -128, 2, 3, + -128, -128, 0, 1); + const __m128i valV = + _mm_shuffle_epi8(_mm_loadl_epi64((const __m128i*)(src + 8 * xStep)), mask); + int cmp = + _mm_movemask_epi8(valV); // MSB: 0x2 = val0; 0x20=val1; 0x200 = val2; 0x2000=val3 + if ((cmp & 0x2222) == + 0x2222) // SSSE3 case #1: all 4 pixels are in RGB555 and alpha = 0xFF. + { + // Swizzle bits: 00012345 -> 12345123 - //r0 = (((val0>>10) & 0x1f) << 3) | (((val0>>10) & 0x1f) >> 2); - const __m128i tmprV = _mm_and_si128(_mm_srli_epi16(valV, 10), kMask_x1f); - const __m128i rV = _mm_or_si128( _mm_slli_epi16(tmprV, 3), _mm_srli_epi16(tmprV, 2) ); + // r0 = (((val0>>10) & 0x1f) << 3) | (((val0>>10) & 0x1f) >> 2); + const __m128i tmprV = _mm_and_si128(_mm_srli_epi16(valV, 10), kMask_x1f); + const __m128i rV = _mm_or_si128(_mm_slli_epi16(tmprV, 3), _mm_srli_epi16(tmprV, 2)); - //g0 = (((val0>>5 ) & 0x1f) << 3) | (((val0>>5 ) & 0x1f) >> 2); - const __m128i tmpgV = _mm_and_si128(_mm_srli_epi16(valV, 5), kMask_x1f); - const __m128i gV = _mm_or_si128( _mm_slli_epi16(tmpgV, 3), _mm_srli_epi16(tmpgV, 2) ); + // g0 = (((val0>>5 ) & 0x1f) << 3) | (((val0>>5 ) & 0x1f) >> 2); + const __m128i tmpgV = _mm_and_si128(_mm_srli_epi16(valV, 5), kMask_x1f); + const __m128i gV = _mm_or_si128(_mm_slli_epi16(tmpgV, 3), _mm_srli_epi16(tmpgV, 2)); - //b0 = (((val0 ) & 0x1f) << 3) | (((val0 ) & 0x1f) >> 2); - const __m128i tmpbV = _mm_and_si128(valV, kMask_x1f); - const __m128i bV = _mm_or_si128( _mm_slli_epi16(tmpbV, 3), _mm_srli_epi16(tmpbV, 2) ); + // b0 = (((val0 ) & 0x1f) << 3) | (((val0 ) & 0x1f) >> 2); + const __m128i tmpbV = _mm_and_si128(valV, kMask_x1f); + const __m128i bV = _mm_or_si128(_mm_slli_epi16(tmpbV, 3), _mm_srli_epi16(tmpbV, 2)); - //newdst[0] = r0 | (g0 << 8) | (b0 << 16) | (a0 << 24); - const __m128i final = _mm_or_si128(_mm_or_si128(rV,_mm_slli_epi32(gV, 8)), - _mm_or_si128(_mm_slli_epi32(bV, 16), aVxff00)); - _mm_storeu_si128( (__m128i*)newdst, final ); - } - else if (!(cmp&0x2222)) // SSSE3 case #2: all 4 pixels are in RGBA4443. - { - // Swizzle bits: 00001234 -> 12341234 + // newdst[0] = r0 | (g0 << 8) | (b0 << 16) | (a0 << 24); + const __m128i final = _mm_or_si128(_mm_or_si128(rV, _mm_slli_epi32(gV, 8)), + _mm_or_si128(_mm_slli_epi32(bV, 16), aVxff00)); + _mm_storeu_si128((__m128i*)newdst, final); + } + else if (!(cmp & 0x2222)) // SSSE3 case #2: all 4 pixels are in RGBA4443. + { + // Swizzle bits: 00001234 -> 12341234 - //r0 = (((val0>>8 ) & 0xf) << 4) | ((val0>>8 ) & 0xf); - const __m128i tmprV = _mm_and_si128(_mm_srli_epi16(valV, 8), kMask_x0f); - const __m128i rV = _mm_or_si128( _mm_slli_epi16(tmprV, 4), tmprV ); + // r0 = (((val0>>8 ) & 0xf) << 4) | ((val0>>8 ) & 0xf); + const __m128i tmprV = _mm_and_si128(_mm_srli_epi16(valV, 8), kMask_x0f); + const __m128i rV = _mm_or_si128(_mm_slli_epi16(tmprV, 4), tmprV); - //g0 = (((val0>>4 ) & 0xf) << 4) | ((val0>>4 ) & 0xf); - const __m128i tmpgV = _mm_and_si128(_mm_srli_epi16(valV, 4), kMask_x0f); - const __m128i gV = _mm_or_si128( _mm_slli_epi16(tmpgV, 4), tmpgV ); + // g0 = (((val0>>4 ) & 0xf) << 4) | ((val0>>4 ) & 0xf); + const __m128i tmpgV = _mm_and_si128(_mm_srli_epi16(valV, 4), kMask_x0f); + const __m128i gV = _mm_or_si128(_mm_slli_epi16(tmpgV, 4), tmpgV); - //b0 = (((val0 ) & 0xf) << 4) | ((val0 ) & 0xf); - const __m128i tmpbV = _mm_and_si128(valV, kMask_x0f); - const __m128i bV = _mm_or_si128( _mm_slli_epi16(tmpbV, 4), tmpbV ); - //a0 = (((val0>>12) & 0x7) << 5) | (((val0>>12) & 0x7) << 2) | (((val0>>12) & 0x7) >> 1); - const __m128i tmpaV = _mm_and_si128(_mm_srli_epi16(valV, 12), kMask_x07); - const __m128i aV = _mm_or_si128( - _mm_slli_epi16(tmpaV, 5), - _mm_or_si128( - _mm_slli_epi16(tmpaV, 2), - _mm_srli_epi16(tmpaV, 1) - ) - ); + // b0 = (((val0 ) & 0xf) << 4) | ((val0 ) & 0xf); + const __m128i tmpbV = _mm_and_si128(valV, kMask_x0f); + const __m128i bV = _mm_or_si128(_mm_slli_epi16(tmpbV, 4), tmpbV); + // a0 = (((val0>>12) & 0x7) << 5) | (((val0>>12) & 0x7) << 2) | (((val0>>12) & 0x7) >> + // 1); + const __m128i tmpaV = _mm_and_si128(_mm_srli_epi16(valV, 12), kMask_x07); + const __m128i aV = + _mm_or_si128(_mm_slli_epi16(tmpaV, 5), + _mm_or_si128(_mm_slli_epi16(tmpaV, 2), _mm_srli_epi16(tmpaV, 1))); - //newdst[0] = r0 | (g0 << 8) | (b0 << 16) | (a0 << 24); - const __m128i final = _mm_or_si128(_mm_or_si128(rV,_mm_slli_epi32(gV, 8)), - _mm_or_si128(_mm_slli_epi32(bV, 16), _mm_slli_epi32(aV, 24))); - _mm_storeu_si128( (__m128i*)newdst, final ); - } - else - { - // TODO: Vectorise (Either 4-way branch or do both and select is better than this) - u32 *vals = (u32*) &valV; - int r,g,b,a; - for (int i=0; i < 4; ++i) - { - if (vals[i] & 0x8000) - { - // Swizzle bits: 00012345 -> 12345123 - r = (((vals[i]>>10) & 0x1f) << 3) | (((vals[i]>>10) & 0x1f) >> 2); - g = (((vals[i]>>5 ) & 0x1f) << 3) | (((vals[i]>>5 ) & 0x1f) >> 2); - b = (((vals[i] ) & 0x1f) << 3) | (((vals[i] ) & 0x1f) >> 2); - a = 0xFF; - } - else - { - a = (((vals[i]>>12) & 0x7) << 5) | (((vals[i]>>12) & 0x7) << 2) | (((vals[i]>>12) & 0x7) >> 1); - // Swizzle bits: 00001234 -> 12341234 - r = (((vals[i]>>8 ) & 0xf) << 4) | ((vals[i]>>8 ) & 0xf); - g = (((vals[i]>>4 ) & 0xf) << 4) | ((vals[i]>>4 ) & 0xf); - b = (((vals[i] ) & 0xf) << 4) | ((vals[i] ) & 0xf); - } - newdst[i] = r | (g << 8) | (b << 16) | (a << 24); - } - } - } - } - else + // newdst[0] = r0 | (g0 << 8) | (b0 << 16) | (a0 << 24); + const __m128i final = + _mm_or_si128(_mm_or_si128(rV, _mm_slli_epi32(gV, 8)), + _mm_or_si128(_mm_slli_epi32(bV, 16), _mm_slli_epi32(aV, 24))); + _mm_storeu_si128((__m128i*)newdst, final); + } + else + { + // TODO: Vectorise (Either 4-way branch or do both and select is better than this) + u32* vals = (u32*)&valV; + int r, g, b, a; + for (int i = 0; i < 4; ++i) + { + if (vals[i] & 0x8000) + { + // Swizzle bits: 00012345 -> 12345123 + r = (((vals[i] >> 10) & 0x1f) << 3) | (((vals[i] >> 10) & 0x1f) >> 2); + g = (((vals[i] >> 5) & 0x1f) << 3) | (((vals[i] >> 5) & 0x1f) >> 2); + b = (((vals[i]) & 0x1f) << 3) | (((vals[i]) & 0x1f) >> 2); + a = 0xFF; + } + else + { + a = (((vals[i] >> 12) & 0x7) << 5) | (((vals[i] >> 12) & 0x7) << 2) | + (((vals[i] >> 12) & 0x7) >> 1); + // Swizzle bits: 00001234 -> 12341234 + r = (((vals[i] >> 8) & 0xf) << 4) | ((vals[i] >> 8) & 0xf); + g = (((vals[i] >> 4) & 0xf) << 4) | ((vals[i] >> 4) & 0xf); + b = (((vals[i]) & 0xf) << 4) | ((vals[i]) & 0xf); + } + newdst[i] = r | (g << 8) | (b << 16) | (a << 24); + } + } + } + } + else #endif - // JSD optimized with SSE2 intrinsics (2 in 4 cases) - // Produces a ~25% speed improvement over reference C implementation. - { - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) - for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) - { - u32 *newdst = dst+(y+iy)*width+x; - const u16 *newsrc = (const u16*)(src + 8 * xStep); + // JSD optimized with SSE2 intrinsics (2 in 4 cases) + // Produces a ~25% speed improvement over reference C implementation. + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + for (int iy = 0, xStep = 4 * yStep; iy < 4; iy++, xStep++) + { + u32* newdst = dst + (y + iy) * width + x; + const u16* newsrc = (const u16*)(src + 8 * xStep); - // TODO: weak point - const u16 val0 = Common::swap16(newsrc[0]); - const u16 val1 = Common::swap16(newsrc[1]); - const u16 val2 = Common::swap16(newsrc[2]); - const u16 val3 = Common::swap16(newsrc[3]); + // TODO: weak point + const u16 val0 = Common::swap16(newsrc[0]); + const u16 val1 = Common::swap16(newsrc[1]); + const u16 val2 = Common::swap16(newsrc[2]); + const u16 val3 = Common::swap16(newsrc[3]); - const __m128i valV = _mm_set_epi16(0, val3, 0, val2, 0, val1, 0, val0); + const __m128i valV = _mm_set_epi16(0, val3, 0, val2, 0, val1, 0, val0); - // Need to check all 4 pixels' MSBs to ensure we can do data-parallelism: - if (((val0 & 0x8000) & (val1 & 0x8000) & (val2 & 0x8000) & (val3 & 0x8000)) == 0x8000) - { - // SSE2 case #1: all 4 pixels are in RGB555 and alpha = 0xFF. + // Need to check all 4 pixels' MSBs to ensure we can do data-parallelism: + if (((val0 & 0x8000) & (val1 & 0x8000) & (val2 & 0x8000) & (val3 & 0x8000)) == 0x8000) + { + // SSE2 case #1: all 4 pixels are in RGB555 and alpha = 0xFF. - // Swizzle bits: 00012345 -> 12345123 + // Swizzle bits: 00012345 -> 12345123 - //r0 = (((val0>>10) & 0x1f) << 3) | (((val0>>10) & 0x1f) >> 2); - const __m128i tmprV = _mm_and_si128(_mm_srli_epi16(valV, 10), kMask_x1f); - const __m128i rV = _mm_or_si128( _mm_slli_epi16(tmprV, 3), _mm_srli_epi16(tmprV, 2) ); + // r0 = (((val0>>10) & 0x1f) << 3) | (((val0>>10) & 0x1f) >> 2); + const __m128i tmprV = _mm_and_si128(_mm_srli_epi16(valV, 10), kMask_x1f); + const __m128i rV = _mm_or_si128(_mm_slli_epi16(tmprV, 3), _mm_srli_epi16(tmprV, 2)); - //g0 = (((val0>>5 ) & 0x1f) << 3) | (((val0>>5 ) & 0x1f) >> 2); - const __m128i tmpgV = _mm_and_si128(_mm_srli_epi16(valV, 5), kMask_x1f); - const __m128i gV = _mm_or_si128( _mm_slli_epi16(tmpgV, 3), _mm_srli_epi16(tmpgV, 2) ); + // g0 = (((val0>>5 ) & 0x1f) << 3) | (((val0>>5 ) & 0x1f) >> 2); + const __m128i tmpgV = _mm_and_si128(_mm_srli_epi16(valV, 5), kMask_x1f); + const __m128i gV = _mm_or_si128(_mm_slli_epi16(tmpgV, 3), _mm_srli_epi16(tmpgV, 2)); - //b0 = (((val0 ) & 0x1f) << 3) | (((val0 ) & 0x1f) >> 2); - const __m128i tmpbV = _mm_and_si128(valV, kMask_x1f); - const __m128i bV = _mm_or_si128( _mm_slli_epi16(tmpbV, 3), _mm_srli_epi16(tmpbV, 2) ); + // b0 = (((val0 ) & 0x1f) << 3) | (((val0 ) & 0x1f) >> 2); + const __m128i tmpbV = _mm_and_si128(valV, kMask_x1f); + const __m128i bV = _mm_or_si128(_mm_slli_epi16(tmpbV, 3), _mm_srli_epi16(tmpbV, 2)); - //newdst[0] = r0 | (g0 << 8) | (b0 << 16) | (a0 << 24); - const __m128i final = _mm_or_si128(_mm_or_si128(rV,_mm_slli_epi32(gV, 8)), - _mm_or_si128(_mm_slli_epi32(bV, 16), aVxff00)); + // newdst[0] = r0 | (g0 << 8) | (b0 << 16) | (a0 << 24); + const __m128i final = _mm_or_si128(_mm_or_si128(rV, _mm_slli_epi32(gV, 8)), + _mm_or_si128(_mm_slli_epi32(bV, 16), aVxff00)); - // write the final result: - _mm_storeu_si128( (__m128i*)newdst, final ); - } - else if (((val0 & 0x8000) | (val1 & 0x8000) | (val2 & 0x8000) | (val3 & 0x8000)) == 0x0000) - { - // SSE2 case #2: all 4 pixels are in RGBA4443. + // write the final result: + _mm_storeu_si128((__m128i*)newdst, final); + } + else if (((val0 & 0x8000) | (val1 & 0x8000) | (val2 & 0x8000) | (val3 & 0x8000)) == + 0x0000) + { + // SSE2 case #2: all 4 pixels are in RGBA4443. - // Swizzle bits: 00001234 -> 12341234 + // Swizzle bits: 00001234 -> 12341234 - //r0 = (((val0>>8 ) & 0xf) << 4) | ((val0>>8 ) & 0xf); - const __m128i tmprV = _mm_and_si128(_mm_srli_epi16(valV, 8), kMask_x0f); - const __m128i rV = _mm_or_si128( _mm_slli_epi16(tmprV, 4), tmprV ); + // r0 = (((val0>>8 ) & 0xf) << 4) | ((val0>>8 ) & 0xf); + const __m128i tmprV = _mm_and_si128(_mm_srli_epi16(valV, 8), kMask_x0f); + const __m128i rV = _mm_or_si128(_mm_slli_epi16(tmprV, 4), tmprV); - //g0 = (((val0>>4 ) & 0xf) << 4) | ((val0>>4 ) & 0xf); - const __m128i tmpgV = _mm_and_si128(_mm_srli_epi16(valV, 4), kMask_x0f); - const __m128i gV = _mm_or_si128( _mm_slli_epi16(tmpgV, 4), tmpgV ); + // g0 = (((val0>>4 ) & 0xf) << 4) | ((val0>>4 ) & 0xf); + const __m128i tmpgV = _mm_and_si128(_mm_srli_epi16(valV, 4), kMask_x0f); + const __m128i gV = _mm_or_si128(_mm_slli_epi16(tmpgV, 4), tmpgV); - //b0 = (((val0 ) & 0xf) << 4) | ((val0 ) & 0xf); - const __m128i tmpbV = _mm_and_si128(valV, kMask_x0f); - const __m128i bV = _mm_or_si128( _mm_slli_epi16(tmpbV, 4), tmpbV ); + // b0 = (((val0 ) & 0xf) << 4) | ((val0 ) & 0xf); + const __m128i tmpbV = _mm_and_si128(valV, kMask_x0f); + const __m128i bV = _mm_or_si128(_mm_slli_epi16(tmpbV, 4), tmpbV); - //a0 = (((val0>>12) & 0x7) << 5) | (((val0>>12) & 0x7) << 2) | (((val0>>12) & 0x7) >> 1); - const __m128i tmpaV = _mm_and_si128(_mm_srli_epi16(valV, 12), kMask_x07); - const __m128i aV = _mm_or_si128( - _mm_slli_epi16(tmpaV, 5), - _mm_or_si128( - _mm_slli_epi16(tmpaV, 2), - _mm_srli_epi16(tmpaV, 1) - ) - ); + // a0 = (((val0>>12) & 0x7) << 5) | (((val0>>12) & 0x7) << 2) | (((val0>>12) & 0x7) >> + // 1); + const __m128i tmpaV = _mm_and_si128(_mm_srli_epi16(valV, 12), kMask_x07); + const __m128i aV = + _mm_or_si128(_mm_slli_epi16(tmpaV, 5), + _mm_or_si128(_mm_slli_epi16(tmpaV, 2), _mm_srli_epi16(tmpaV, 1))); - //newdst[0] = r0 | (g0 << 8) | (b0 << 16) | (a0 << 24); - const __m128i final = _mm_or_si128(_mm_or_si128(rV,_mm_slli_epi32(gV, 8)), - _mm_or_si128(_mm_slli_epi32(bV, 16), _mm_slli_epi32(aV, 24))); + // newdst[0] = r0 | (g0 << 8) | (b0 << 16) | (a0 << 24); + const __m128i final = + _mm_or_si128(_mm_or_si128(rV, _mm_slli_epi32(gV, 8)), + _mm_or_si128(_mm_slli_epi32(bV, 16), _mm_slli_epi32(aV, 24))); - // write the final result: - _mm_storeu_si128( (__m128i*)newdst, final ); - } - else - { - // TODO: Vectorise (Either 4-way branch or do both and select is better than this) - u32 *vals = (u32*) &valV; - int r,g,b,a; - for (int i=0; i < 4; ++i) - { - if (vals[i] & 0x8000) - { - // Swizzle bits: 00012345 -> 12345123 - r = (((vals[i]>>10) & 0x1f) << 3) | (((vals[i]>>10) & 0x1f) >> 2); - g = (((vals[i]>>5 ) & 0x1f) << 3) | (((vals[i]>>5 ) & 0x1f) >> 2); - b = (((vals[i] ) & 0x1f) << 3) | (((vals[i] ) & 0x1f) >> 2); - a = 0xFF; - } - else - { - a = (((vals[i]>>12) & 0x7) << 5) | (((vals[i]>>12) & 0x7) << 2) | (((vals[i]>>12) & 0x7) >> 1); - // Swizzle bits: 00001234 -> 12341234 - r = (((vals[i]>>8 ) & 0xf) << 4) | ((vals[i]>>8 ) & 0xf); - g = (((vals[i]>>4 ) & 0xf) << 4) | ((vals[i]>>4 ) & 0xf); - b = (((vals[i] ) & 0xf) << 4) | ((vals[i] ) & 0xf); - } - newdst[i] = r | (g << 8) | (b << 16) | (a << 24); - } - } - } - } - } - break; - case GX_TF_RGBA8: // speed critical - { + // write the final result: + _mm_storeu_si128((__m128i*)newdst, final); + } + else + { + // TODO: Vectorise (Either 4-way branch or do both and select is better than this) + u32* vals = (u32*)&valV; + int r, g, b, a; + for (int i = 0; i < 4; ++i) + { + if (vals[i] & 0x8000) + { + // Swizzle bits: 00012345 -> 12345123 + r = (((vals[i] >> 10) & 0x1f) << 3) | (((vals[i] >> 10) & 0x1f) >> 2); + g = (((vals[i] >> 5) & 0x1f) << 3) | (((vals[i] >> 5) & 0x1f) >> 2); + b = (((vals[i]) & 0x1f) << 3) | (((vals[i]) & 0x1f) >> 2); + a = 0xFF; + } + else + { + a = (((vals[i] >> 12) & 0x7) << 5) | (((vals[i] >> 12) & 0x7) << 2) | + (((vals[i] >> 12) & 0x7) >> 1); + // Swizzle bits: 00001234 -> 12341234 + r = (((vals[i] >> 8) & 0xf) << 4) | ((vals[i] >> 8) & 0xf); + g = (((vals[i] >> 4) & 0xf) << 4) | ((vals[i] >> 4) & 0xf); + b = (((vals[i]) & 0xf) << 4) | ((vals[i]) & 0xf); + } + newdst[i] = r | (g << 8) | (b << 16) | (a << 24); + } + } + } + } + } + break; + case GX_TF_RGBA8: // speed critical + { #if _M_SSE >= 0x301 - // xsacha optimized with SSSE3 instrinsics - // Produces a ~30% speed improvement over SSE2 implementation - if (cpu_info.bSSSE3) - { - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) - { - const u8* src2 = src + 64 * yStep; - const __m128i mask0312 = _mm_set_epi8(12,15,13,14,8,11,9,10,4,7,5,6,0,3,1,2); - const __m128i ar0 = _mm_loadu_si128((__m128i*)src2); - const __m128i ar1 = _mm_loadu_si128((__m128i*)src2+1); - const __m128i gb0 = _mm_loadu_si128((__m128i*)src2+2); - const __m128i gb1 = _mm_loadu_si128((__m128i*)src2+3); + // xsacha optimized with SSSE3 instrinsics + // Produces a ~30% speed improvement over SSE2 implementation + if (cpu_info.bSSSE3) + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + { + const u8* src2 = src + 64 * yStep; + const __m128i mask0312 = + _mm_set_epi8(12, 15, 13, 14, 8, 11, 9, 10, 4, 7, 5, 6, 0, 3, 1, 2); + const __m128i ar0 = _mm_loadu_si128((__m128i*)src2); + const __m128i ar1 = _mm_loadu_si128((__m128i*)src2 + 1); + const __m128i gb0 = _mm_loadu_si128((__m128i*)src2 + 2); + const __m128i gb1 = _mm_loadu_si128((__m128i*)src2 + 3); + const __m128i rgba00 = _mm_shuffle_epi8(_mm_unpacklo_epi8(ar0, gb0), mask0312); + const __m128i rgba01 = _mm_shuffle_epi8(_mm_unpackhi_epi8(ar0, gb0), mask0312); + const __m128i rgba10 = _mm_shuffle_epi8(_mm_unpacklo_epi8(ar1, gb1), mask0312); + const __m128i rgba11 = _mm_shuffle_epi8(_mm_unpackhi_epi8(ar1, gb1), mask0312); - const __m128i rgba00 = _mm_shuffle_epi8(_mm_unpacklo_epi8(ar0,gb0),mask0312); - const __m128i rgba01 = _mm_shuffle_epi8(_mm_unpackhi_epi8(ar0,gb0),mask0312); - const __m128i rgba10 = _mm_shuffle_epi8(_mm_unpacklo_epi8(ar1,gb1),mask0312); - const __m128i rgba11 = _mm_shuffle_epi8(_mm_unpackhi_epi8(ar1,gb1),mask0312); - - __m128i *dst128 = (__m128i*)( dst + (y + 0) * width + x ); - _mm_storeu_si128(dst128, rgba00); - dst128 = (__m128i*)( dst + (y + 1) * width + x ); - _mm_storeu_si128(dst128, rgba01); - dst128 = (__m128i*)( dst + (y + 2) * width + x ); - _mm_storeu_si128(dst128, rgba10); - dst128 = (__m128i*)( dst + (y + 3) * width + x ); - _mm_storeu_si128(dst128, rgba11); - } - } - else + __m128i* dst128 = (__m128i*)(dst + (y + 0) * width + x); + _mm_storeu_si128(dst128, rgba00); + dst128 = (__m128i*)(dst + (y + 1) * width + x); + _mm_storeu_si128(dst128, rgba01); + dst128 = (__m128i*)(dst + (y + 2) * width + x); + _mm_storeu_si128(dst128, rgba10); + dst128 = (__m128i*)(dst + (y + 3) * width + x); + _mm_storeu_si128(dst128, rgba11); + } + } + else #endif - // JSD optimized with SSE2 intrinsics - // Produces a ~68% speed improvement over reference C implementation. - { - for (int y = 0; y < height; y += 4) - for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) - { - // Input is divided up into 16-bit words. The texels are split up into AR and GB components where all - // AR components come grouped up first in 32 bytes followed by the GB components in 32 bytes. We are - // processing 16 texels per each loop iteration, numbered from 0-f. - // - // Convention is: - // one byte is [component-name texel-number] - // __m128i is (4-bytes 4-bytes 4-bytes 4-bytes) - // - // Input is ([A 7][R 7][A 6][R 6] [A 5][R 5][A 4][R 4] [A 3][R 3][A 2][R 2] [A 1][R 1][A 0][R 0]) - // ([A f][R f][A e][R e] [A d][R d][A c][R c] [A b][R b][A a][R a] [A 9][R 9][A 8][R 8]) - // ([G 7][B 7][G 6][B 6] [G 5][B 5][G 4][B 4] [G 3][B 3][G 2][B 2] [G 1][B 1][G 0][B 0]) - // ([G f][B f][G e][B e] [G d][B d][G c][B c] [G b][B b][G a][B a] [G 9][B 9][G 8][B 8]) - // - // Output is (RGBA3 RGBA2 RGBA1 RGBA0) - // (RGBA7 RGBA6 RGBA5 RGBA4) - // (RGBAb RGBAa RGBA9 RGBA8) - // (RGBAf RGBAe RGBAd RGBAc) - const u8* src2 = src + 64 * yStep; - // Loads the 1st half of AR components ([A 7][R 7][A 6][R 6] [A 5][R 5][A 4][R 4] [A 3][R 3][A 2][R 2] [A 1][R 1][A 0][R 0]) - const __m128i ar0 = _mm_loadu_si128((__m128i*)src2); - // Loads the 2nd half of AR components ([A f][R f][A e][R e] [A d][R d][A c][R c] [A b][R b][A a][R a] [A 9][R 9][A 8][R 8]) - const __m128i ar1 = _mm_loadu_si128((__m128i*)src2+1); - // Loads the 1st half of GB components ([G 7][B 7][G 6][B 6] [G 5][B 5][G 4][B 4] [G 3][B 3][G 2][B 2] [G 1][B 1][G 0][B 0]) - const __m128i gb0 = _mm_loadu_si128((__m128i*)src2+2); - // Loads the 2nd half of GB components ([G f][B f][G e][B e] [G d][B d][G c][B c] [G b][B b][G a][B a] [G 9][B 9][G 8][B 8]) - const __m128i gb1 = _mm_loadu_si128((__m128i*)src2+3); - __m128i rgba00, rgba01, rgba10, rgba11; - const __m128i kMask_x000f = _mm_set_epi32(0x000000FFL, 0x000000FFL, 0x000000FFL, 0x000000FFL); - const __m128i kMask_xf000 = _mm_set_epi32(0xFF000000L, 0xFF000000L, 0xFF000000L, 0xFF000000L); - const __m128i kMask_x0ff0 = _mm_set_epi32(0x00FFFF00L, 0x00FFFF00L, 0x00FFFF00L, 0x00FFFF00L); - // Expand the AR components to fill out 32-bit words: - // ([A 7][R 7][A 6][R 6] [A 5][R 5][A 4][R 4] [A 3][R 3][A 2][R 2] [A 1][R 1][A 0][R 0]) -> ([A 3][A 3][R 3][R 3] [A 2][A 2][R 2][R 2] [A 1][A 1][R 1][R 1] [A 0][A 0][R 0][R 0]) - const __m128i aarr00 = _mm_unpacklo_epi8(ar0, ar0); - // ([A 7][R 7][A 6][R 6] [A 5][R 5][A 4][R 4] [A 3][R 3][A 2][R 2] [A 1][R 1][A 0][R 0]) -> ([A 7][A 7][R 7][R 7] [A 6][A 6][R 6][R 6] [A 5][A 5][R 5][R 5] [A 4][A 4][R 4][R 4]) - const __m128i aarr01 = _mm_unpackhi_epi8(ar0, ar0); - // ([A f][R f][A e][R e] [A d][R d][A c][R c] [A b][R b][A a][R a] [A 9][R 9][A 8][R 8]) -> ([A b][A b][R b][R b] [A a][A a][R a][R a] [A 9][A 9][R 9][R 9] [A 8][A 8][R 8][R 8]) - const __m128i aarr10 = _mm_unpacklo_epi8(ar1, ar1); - // ([A f][R f][A e][R e] [A d][R d][A c][R c] [A b][R b][A a][R a] [A 9][R 9][A 8][R 8]) -> ([A f][A f][R f][R f] [A e][A e][R e][R e] [A d][A d][R d][R d] [A c][A c][R c][R c]) - const __m128i aarr11 = _mm_unpackhi_epi8(ar1, ar1); + // JSD optimized with SSE2 intrinsics + // Produces a ~68% speed improvement over reference C implementation. + { + for (int y = 0; y < height; y += 4) + for (int x = 0, yStep = (y / 4) * Wsteps4; x < width; x += 4, yStep++) + { + // Input is divided up into 16-bit words. The texels are split up into AR and GB + // components where all + // AR components come grouped up first in 32 bytes followed by the GB components in 32 + // bytes. We are + // processing 16 texels per each loop iteration, numbered from 0-f. + // + // Convention is: + // one byte is [component-name texel-number] + // __m128i is (4-bytes 4-bytes 4-bytes 4-bytes) + // + // Input is ([A 7][R 7][A 6][R 6] [A 5][R 5][A 4][R 4] [A 3][R 3][A 2][R 2] [A 1][R 1][A + // 0][R 0]) + // ([A f][R f][A e][R e] [A d][R d][A c][R c] [A b][R b][A a][R a] [A 9][R 9][A + // 8][R 8]) + // ([G 7][B 7][G 6][B 6] [G 5][B 5][G 4][B 4] [G 3][B 3][G 2][B 2] [G 1][B 1][G + // 0][B 0]) + // ([G f][B f][G e][B e] [G d][B d][G c][B c] [G b][B b][G a][B a] [G 9][B 9][G + // 8][B 8]) + // + // Output is (RGBA3 RGBA2 RGBA1 RGBA0) + // (RGBA7 RGBA6 RGBA5 RGBA4) + // (RGBAb RGBAa RGBA9 RGBA8) + // (RGBAf RGBAe RGBAd RGBAc) + const u8* src2 = src + 64 * yStep; + // Loads the 1st half of AR components ([A 7][R 7][A 6][R 6] [A 5][R 5][A 4][R 4] [A 3][R + // 3][A 2][R 2] [A 1][R 1][A 0][R 0]) + const __m128i ar0 = _mm_loadu_si128((__m128i*)src2); + // Loads the 2nd half of AR components ([A f][R f][A e][R e] [A d][R d][A c][R c] [A b][R + // b][A a][R a] [A 9][R 9][A 8][R 8]) + const __m128i ar1 = _mm_loadu_si128((__m128i*)src2 + 1); + // Loads the 1st half of GB components ([G 7][B 7][G 6][B 6] [G 5][B 5][G 4][B 4] [G 3][B + // 3][G 2][B 2] [G 1][B 1][G 0][B 0]) + const __m128i gb0 = _mm_loadu_si128((__m128i*)src2 + 2); + // Loads the 2nd half of GB components ([G f][B f][G e][B e] [G d][B d][G c][B c] [G b][B + // b][G a][B a] [G 9][B 9][G 8][B 8]) + const __m128i gb1 = _mm_loadu_si128((__m128i*)src2 + 3); + __m128i rgba00, rgba01, rgba10, rgba11; + const __m128i kMask_x000f = + _mm_set_epi32(0x000000FFL, 0x000000FFL, 0x000000FFL, 0x000000FFL); + const __m128i kMask_xf000 = + _mm_set_epi32(0xFF000000L, 0xFF000000L, 0xFF000000L, 0xFF000000L); + const __m128i kMask_x0ff0 = + _mm_set_epi32(0x00FFFF00L, 0x00FFFF00L, 0x00FFFF00L, 0x00FFFF00L); + // Expand the AR components to fill out 32-bit words: + // ([A 7][R 7][A 6][R 6] [A 5][R 5][A 4][R 4] [A 3][R 3][A 2][R 2] [A 1][R 1][A 0][R 0]) + // -> ([A 3][A 3][R 3][R 3] [A 2][A 2][R 2][R 2] [A 1][A 1][R 1][R 1] [A 0][A 0][R 0][R + // 0]) + const __m128i aarr00 = _mm_unpacklo_epi8(ar0, ar0); + // ([A 7][R 7][A 6][R 6] [A 5][R 5][A 4][R 4] [A 3][R 3][A 2][R 2] [A 1][R 1][A 0][R 0]) + // -> ([A 7][A 7][R 7][R 7] [A 6][A 6][R 6][R 6] [A 5][A 5][R 5][R 5] [A 4][A 4][R 4][R + // 4]) + const __m128i aarr01 = _mm_unpackhi_epi8(ar0, ar0); + // ([A f][R f][A e][R e] [A d][R d][A c][R c] [A b][R b][A a][R a] [A 9][R 9][A 8][R 8]) + // -> ([A b][A b][R b][R b] [A a][A a][R a][R a] [A 9][A 9][R 9][R 9] [A 8][A 8][R 8][R + // 8]) + const __m128i aarr10 = _mm_unpacklo_epi8(ar1, ar1); + // ([A f][R f][A e][R e] [A d][R d][A c][R c] [A b][R b][A a][R a] [A 9][R 9][A 8][R 8]) + // -> ([A f][A f][R f][R f] [A e][A e][R e][R e] [A d][A d][R d][R d] [A c][A c][R c][R + // c]) + const __m128i aarr11 = _mm_unpackhi_epi8(ar1, ar1); - // Move A right 16 bits and mask off everything but the lowest 8 bits to get A in its final place: - const __m128i ___a00 = _mm_and_si128(_mm_srli_epi32(aarr00, 16), kMask_x000f); - // Move R left 16 bits and mask off everything but the highest 8 bits to get R in its final place: - const __m128i r___00 = _mm_and_si128(_mm_slli_epi32(aarr00, 16), kMask_xf000); - // OR the two together to get R and A in their final places: - const __m128i r__a00 = _mm_or_si128(r___00, ___a00); + // Move A right 16 bits and mask off everything but the lowest 8 bits to get A in its + // final place: + const __m128i ___a00 = _mm_and_si128(_mm_srli_epi32(aarr00, 16), kMask_x000f); + // Move R left 16 bits and mask off everything but the highest 8 bits to get R in its + // final place: + const __m128i r___00 = _mm_and_si128(_mm_slli_epi32(aarr00, 16), kMask_xf000); + // OR the two together to get R and A in their final places: + const __m128i r__a00 = _mm_or_si128(r___00, ___a00); - const __m128i ___a01 = _mm_and_si128(_mm_srli_epi32(aarr01, 16), kMask_x000f); - const __m128i r___01 = _mm_and_si128(_mm_slli_epi32(aarr01, 16), kMask_xf000); - const __m128i r__a01 = _mm_or_si128(r___01, ___a01); + const __m128i ___a01 = _mm_and_si128(_mm_srli_epi32(aarr01, 16), kMask_x000f); + const __m128i r___01 = _mm_and_si128(_mm_slli_epi32(aarr01, 16), kMask_xf000); + const __m128i r__a01 = _mm_or_si128(r___01, ___a01); - const __m128i ___a10 = _mm_and_si128(_mm_srli_epi32(aarr10, 16), kMask_x000f); - const __m128i r___10 = _mm_and_si128(_mm_slli_epi32(aarr10, 16), kMask_xf000); - const __m128i r__a10 = _mm_or_si128(r___10, ___a10); + const __m128i ___a10 = _mm_and_si128(_mm_srli_epi32(aarr10, 16), kMask_x000f); + const __m128i r___10 = _mm_and_si128(_mm_slli_epi32(aarr10, 16), kMask_xf000); + const __m128i r__a10 = _mm_or_si128(r___10, ___a10); - const __m128i ___a11 = _mm_and_si128(_mm_srli_epi32(aarr11, 16), kMask_x000f); - const __m128i r___11 = _mm_and_si128(_mm_slli_epi32(aarr11, 16), kMask_xf000); - const __m128i r__a11 = _mm_or_si128(r___11, ___a11); + const __m128i ___a11 = _mm_and_si128(_mm_srli_epi32(aarr11, 16), kMask_x000f); + const __m128i r___11 = _mm_and_si128(_mm_slli_epi32(aarr11, 16), kMask_xf000); + const __m128i r__a11 = _mm_or_si128(r___11, ___a11); - // Expand the GB components to fill out 32-bit words: - // ([G 7][B 7][G 6][B 6] [G 5][B 5][G 4][B 4] [G 3][B 3][G 2][B 2] [G 1][B 1][G 0][B 0]) -> ([G 3][G 3][B 3][B 3] [G 2][G 2][B 2][B 2] [G 1][G 1][B 1][B 1] [G 0][G 0][B 0][B 0]) - const __m128i ggbb00 = _mm_unpacklo_epi8(gb0, gb0); - // ([G 7][B 7][G 6][B 6] [G 5][B 5][G 4][B 4] [G 3][B 3][G 2][B 2] [G 1][B 1][G 0][B 0]) -> ([G 7][G 7][B 7][B 7] [G 6][G 6][B 6][B 6] [G 5][G 5][B 5][B 5] [G 4][G 4][B 4][B 4]) - const __m128i ggbb01 = _mm_unpackhi_epi8(gb0, gb0); - // ([G f][B f][G e][B e] [G d][B d][G c][B c] [G b][B b][G a][B a] [G 9][B 9][G 8][B 8]) -> ([G b][G b][B b][B b] [G a][G a][B a][B a] [G 9][G 9][B 9][B 9] [G 8][G 8][B 8][B 8]) - const __m128i ggbb10 = _mm_unpacklo_epi8(gb1, gb1); - // ([G f][B f][G e][B e] [G d][B d][G c][B c] [G b][B b][G a][B a] [G 9][B 9][G 8][B 8]) -> ([G f][G f][B f][B f] [G e][G e][B e][B e] [G d][G d][B d][B d] [G c][G c][B c][B c]) - const __m128i ggbb11 = _mm_unpackhi_epi8(gb1, gb1); + // Expand the GB components to fill out 32-bit words: + // ([G 7][B 7][G 6][B 6] [G 5][B 5][G 4][B 4] [G 3][B 3][G 2][B 2] [G 1][B 1][G 0][B 0]) + // -> ([G 3][G 3][B 3][B 3] [G 2][G 2][B 2][B 2] [G 1][G 1][B 1][B 1] [G 0][G 0][B 0][B + // 0]) + const __m128i ggbb00 = _mm_unpacklo_epi8(gb0, gb0); + // ([G 7][B 7][G 6][B 6] [G 5][B 5][G 4][B 4] [G 3][B 3][G 2][B 2] [G 1][B 1][G 0][B 0]) + // -> ([G 7][G 7][B 7][B 7] [G 6][G 6][B 6][B 6] [G 5][G 5][B 5][B 5] [G 4][G 4][B 4][B + // 4]) + const __m128i ggbb01 = _mm_unpackhi_epi8(gb0, gb0); + // ([G f][B f][G e][B e] [G d][B d][G c][B c] [G b][B b][G a][B a] [G 9][B 9][G 8][B 8]) + // -> ([G b][G b][B b][B b] [G a][G a][B a][B a] [G 9][G 9][B 9][B 9] [G 8][G 8][B 8][B + // 8]) + const __m128i ggbb10 = _mm_unpacklo_epi8(gb1, gb1); + // ([G f][B f][G e][B e] [G d][B d][G c][B c] [G b][B b][G a][B a] [G 9][B 9][G 8][B 8]) + // -> ([G f][G f][B f][B f] [G e][G e][B e][B e] [G d][G d][B d][B d] [G c][G c][B c][B + // c]) + const __m128i ggbb11 = _mm_unpackhi_epi8(gb1, gb1); - // G and B are already in perfect spots in the center, just remove the extra copies in the 1st and 4th positions: - const __m128i _gb_00 = _mm_and_si128(ggbb00, kMask_x0ff0); - const __m128i _gb_01 = _mm_and_si128(ggbb01, kMask_x0ff0); - const __m128i _gb_10 = _mm_and_si128(ggbb10, kMask_x0ff0); - const __m128i _gb_11 = _mm_and_si128(ggbb11, kMask_x0ff0); + // G and B are already in perfect spots in the center, just remove the extra copies in the + // 1st and 4th positions: + const __m128i _gb_00 = _mm_and_si128(ggbb00, kMask_x0ff0); + const __m128i _gb_01 = _mm_and_si128(ggbb01, kMask_x0ff0); + const __m128i _gb_10 = _mm_and_si128(ggbb10, kMask_x0ff0); + const __m128i _gb_11 = _mm_and_si128(ggbb11, kMask_x0ff0); - // Now join up R__A and _GB_ to get RGBA! - rgba00 = _mm_or_si128(r__a00, _gb_00); - rgba01 = _mm_or_si128(r__a01, _gb_01); - rgba10 = _mm_or_si128(r__a10, _gb_10); - rgba11 = _mm_or_si128(r__a11, _gb_11); - // Write em out! - __m128i *dst128 = (__m128i*)( dst + (y + 0) * width + x ); - _mm_storeu_si128(dst128, rgba00); - dst128 = (__m128i*)( dst + (y + 1) * width + x ); - _mm_storeu_si128(dst128, rgba01); - dst128 = (__m128i*)( dst + (y + 2) * width + x ); - _mm_storeu_si128(dst128, rgba10); - dst128 = (__m128i*)( dst + (y + 3) * width + x ); - _mm_storeu_si128(dst128, rgba11); - } - } - } - break; - case GX_TF_CMPR: // speed critical - // The metroid games use this format almost exclusively. - { - // JSD optimized with SSE2 intrinsics. - // Produces a ~50% improvement for x86 and a ~40% improvement for x64 in speed over reference C implementation. - // The x64 compiled reference C code is faster than the x86 compiled reference C code, but the SSE2 is - // faster than both. - for (int y = 0; y < height; y += 8) - { - for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8,yStep++) - { - // We handle two DXT blocks simultaneously to take full advantage of SSE2's 128-bit registers. - // This is ideal because a single DXT block contains 2 RGBA colors when decoded from their 16-bit. - // Two DXT blocks therefore contain 4 RGBA colors to be processed. The processing is parallelizable - // at this level, so we do. - for (int z = 0, xStep = 2 * yStep; z < 2; ++z, xStep++) - { - // JSD NOTE: You may see many strange patterns of behavior in the below code, but they - // are for performance reasons. Sometimes, calculating what should be obvious hard-coded - // constants is faster than loading their values from memory. Unfortunately, there is no - // way to inline 128-bit constants from opcodes so they must be loaded from memory. This - // seems a little ridiculous to me in that you can't even generate a constant value of 1 without - // having to load it from memory. So, I stored the minimal constant I could, 128-bits worth - // of 1s :). Then I use sequences of shifts to squash it to the appropriate size and bit - // positions that I need. + // Now join up R__A and _GB_ to get RGBA! + rgba00 = _mm_or_si128(r__a00, _gb_00); + rgba01 = _mm_or_si128(r__a01, _gb_01); + rgba10 = _mm_or_si128(r__a10, _gb_10); + rgba11 = _mm_or_si128(r__a11, _gb_11); + // Write em out! + __m128i* dst128 = (__m128i*)(dst + (y + 0) * width + x); + _mm_storeu_si128(dst128, rgba00); + dst128 = (__m128i*)(dst + (y + 1) * width + x); + _mm_storeu_si128(dst128, rgba01); + dst128 = (__m128i*)(dst + (y + 2) * width + x); + _mm_storeu_si128(dst128, rgba10); + dst128 = (__m128i*)(dst + (y + 3) * width + x); + _mm_storeu_si128(dst128, rgba11); + } + } + } + break; + case GX_TF_CMPR: // speed critical + // The metroid games use this format almost exclusively. + { + // JSD optimized with SSE2 intrinsics. + // Produces a ~50% improvement for x86 and a ~40% improvement for x64 in speed over reference + // C implementation. + // The x64 compiled reference C code is faster than the x86 compiled reference C code, but the + // SSE2 is + // faster than both. + for (int y = 0; y < height; y += 8) + { + for (int x = 0, yStep = (y / 8) * Wsteps8; x < width; x += 8, yStep++) + { + // We handle two DXT blocks simultaneously to take full advantage of SSE2's 128-bit + // registers. + // This is ideal because a single DXT block contains 2 RGBA colors when decoded from their + // 16-bit. + // Two DXT blocks therefore contain 4 RGBA colors to be processed. The processing is + // parallelizable + // at this level, so we do. + for (int z = 0, xStep = 2 * yStep; z < 2; ++z, xStep++) + { + // JSD NOTE: You may see many strange patterns of behavior in the below code, but they + // are for performance reasons. Sometimes, calculating what should be obvious hard-coded + // constants is faster than loading their values from memory. Unfortunately, there is no + // way to inline 128-bit constants from opcodes so they must be loaded from memory. This + // seems a little ridiculous to me in that you can't even generate a constant value of 1 + // without + // having to load it from memory. So, I stored the minimal constant I could, 128-bits + // worth + // of 1s :). Then I use sequences of shifts to squash it to the appropriate size and bit + // positions that I need. - const __m128i allFFs128 = _mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128()); + const __m128i allFFs128 = _mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128()); - // Load 128 bits, i.e. two DXTBlocks (64-bits each) - const __m128i dxt = _mm_loadu_si128((__m128i *)(src + sizeof(struct DXTBlock) * 2 * xStep)); + // Load 128 bits, i.e. two DXTBlocks (64-bits each) + const __m128i dxt = + _mm_loadu_si128((__m128i*)(src + sizeof(struct DXTBlock) * 2 * xStep)); - // Copy the 2-bit indices from each DXT block: - alignas(16) u32 dxttmp[4]; - _mm_store_si128((__m128i*)dxttmp, dxt); + // Copy the 2-bit indices from each DXT block: + alignas(16) u32 dxttmp[4]; + _mm_store_si128((__m128i*)dxttmp, dxt); - u32 dxt0sel = dxttmp[1]; - u32 dxt1sel = dxttmp[3]; + u32 dxt0sel = dxttmp[1]; + u32 dxt1sel = dxttmp[3]; - __m128i argb888x4; - __m128i c1 = _mm_unpackhi_epi16(dxt, dxt); - c1 = _mm_slli_si128(c1, 8); - const __m128i c0 = _mm_or_si128(c1, _mm_srli_si128(_mm_slli_si128(_mm_unpacklo_epi16(dxt, dxt), 8), 8)); + __m128i argb888x4; + __m128i c1 = _mm_unpackhi_epi16(dxt, dxt); + c1 = _mm_slli_si128(c1, 8); + const __m128i c0 = _mm_or_si128( + c1, _mm_srli_si128(_mm_slli_si128(_mm_unpacklo_epi16(dxt, dxt), 8), 8)); - // Compare rgb0 to rgb1: - // Each 32-bit word will contain either 0xFFFFFFFF or 0x00000000 for true/false. - const __m128i c0cmp = _mm_srli_epi32(_mm_slli_epi32(_mm_srli_epi64(c0, 8), 16), 16); - const __m128i c0shr = _mm_srli_epi64(c0cmp, 32); - const __m128i cmprgb0rgb1 = _mm_cmpgt_epi32(c0cmp, c0shr); + // Compare rgb0 to rgb1: + // Each 32-bit word will contain either 0xFFFFFFFF or 0x00000000 for true/false. + const __m128i c0cmp = _mm_srli_epi32(_mm_slli_epi32(_mm_srli_epi64(c0, 8), 16), 16); + const __m128i c0shr = _mm_srli_epi64(c0cmp, 32); + const __m128i cmprgb0rgb1 = _mm_cmpgt_epi32(c0cmp, c0shr); - int cmp0 = _mm_extract_epi16(cmprgb0rgb1, 0); - int cmp1 = _mm_extract_epi16(cmprgb0rgb1, 4); + int cmp0 = _mm_extract_epi16(cmprgb0rgb1, 0); + int cmp1 = _mm_extract_epi16(cmprgb0rgb1, 4); - // green: - // NOTE: We start with the larger number of bits (6) firts for G and shift the mask down 1 bit to get a 5-bit mask - // later for R and B components. - // low6mask == _mm_set_epi32(0x0000FC00, 0x0000FC00, 0x0000FC00, 0x0000FC00) - const __m128i low6mask = _mm_slli_epi32( _mm_srli_epi32(allFFs128, 24 + 2), 8 + 2); - const __m128i gtmp = _mm_srli_epi32(c0, 3); - const __m128i g0 = _mm_and_si128(gtmp, low6mask); - // low3mask == _mm_set_epi32(0x00000300, 0x00000300, 0x00000300, 0x00000300) - const __m128i g1 = _mm_and_si128(_mm_srli_epi32(gtmp, 6), _mm_set_epi32(0x00000300, 0x00000300, 0x00000300, 0x00000300)); - argb888x4 = _mm_or_si128(g0, g1); - // red: - // low5mask == _mm_set_epi32(0x000000F8, 0x000000F8, 0x000000F8, 0x000000F8) - const __m128i low5mask = _mm_slli_epi32( _mm_srli_epi32(low6mask, 8 + 3), 3); - const __m128i r0 = _mm_and_si128(c0, low5mask); - const __m128i r1 = _mm_srli_epi32(r0, 5); - argb888x4 = _mm_or_si128(argb888x4, _mm_or_si128(r0, r1)); - // blue: - // _mm_slli_epi32(low5mask, 16) == _mm_set_epi32(0x00F80000, 0x00F80000, 0x00F80000, 0x00F80000) - const __m128i b0 = _mm_and_si128(_mm_srli_epi32(c0, 5), _mm_slli_epi32(low5mask, 16)); - const __m128i b1 = _mm_srli_epi16(b0, 5); - // OR in the fixed alpha component - // _mm_slli_epi32( allFFs128, 24 ) == _mm_set_epi32(0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000) - argb888x4 = _mm_or_si128(_mm_or_si128(argb888x4, _mm_slli_epi32( allFFs128, 24 ) ), _mm_or_si128(b0, b1)); - // calculate RGB2 and RGB3: - const __m128i rgb0 = _mm_shuffle_epi32(argb888x4, _MM_SHUFFLE(2, 2, 0, 0)); - const __m128i rgb1 = _mm_shuffle_epi32(argb888x4, _MM_SHUFFLE(3, 3, 1, 1)); - const __m128i rrggbb0 = _mm_and_si128(_mm_unpacklo_epi8(rgb0, rgb0), _mm_srli_epi16( allFFs128, 8 )); - const __m128i rrggbb1 = _mm_and_si128(_mm_unpacklo_epi8(rgb1, rgb1), _mm_srli_epi16( allFFs128, 8 )); - const __m128i rrggbb01 = _mm_and_si128(_mm_unpackhi_epi8(rgb0, rgb0), _mm_srli_epi16( allFFs128, 8 )); - const __m128i rrggbb11 = _mm_and_si128(_mm_unpackhi_epi8(rgb1, rgb1), _mm_srli_epi16( allFFs128, 8 )); + // green: + // NOTE: We start with the larger number of bits (6) firts for G and shift the mask down + // 1 bit to get a 5-bit mask + // later for R and B components. + // low6mask == _mm_set_epi32(0x0000FC00, 0x0000FC00, 0x0000FC00, 0x0000FC00) + const __m128i low6mask = _mm_slli_epi32(_mm_srli_epi32(allFFs128, 24 + 2), 8 + 2); + const __m128i gtmp = _mm_srli_epi32(c0, 3); + const __m128i g0 = _mm_and_si128(gtmp, low6mask); + // low3mask == _mm_set_epi32(0x00000300, 0x00000300, 0x00000300, 0x00000300) + const __m128i g1 = + _mm_and_si128(_mm_srli_epi32(gtmp, 6), + _mm_set_epi32(0x00000300, 0x00000300, 0x00000300, 0x00000300)); + argb888x4 = _mm_or_si128(g0, g1); + // red: + // low5mask == _mm_set_epi32(0x000000F8, 0x000000F8, 0x000000F8, 0x000000F8) + const __m128i low5mask = _mm_slli_epi32(_mm_srli_epi32(low6mask, 8 + 3), 3); + const __m128i r0 = _mm_and_si128(c0, low5mask); + const __m128i r1 = _mm_srli_epi32(r0, 5); + argb888x4 = _mm_or_si128(argb888x4, _mm_or_si128(r0, r1)); + // blue: + // _mm_slli_epi32(low5mask, 16) == _mm_set_epi32(0x00F80000, 0x00F80000, 0x00F80000, + // 0x00F80000) + const __m128i b0 = _mm_and_si128(_mm_srli_epi32(c0, 5), _mm_slli_epi32(low5mask, 16)); + const __m128i b1 = _mm_srli_epi16(b0, 5); + // OR in the fixed alpha component + // _mm_slli_epi32( allFFs128, 24 ) == _mm_set_epi32(0xFF000000, 0xFF000000, 0xFF000000, + // 0xFF000000) + argb888x4 = _mm_or_si128(_mm_or_si128(argb888x4, _mm_slli_epi32(allFFs128, 24)), + _mm_or_si128(b0, b1)); + // calculate RGB2 and RGB3: + const __m128i rgb0 = _mm_shuffle_epi32(argb888x4, _MM_SHUFFLE(2, 2, 0, 0)); + const __m128i rgb1 = _mm_shuffle_epi32(argb888x4, _MM_SHUFFLE(3, 3, 1, 1)); + const __m128i rrggbb0 = + _mm_and_si128(_mm_unpacklo_epi8(rgb0, rgb0), _mm_srli_epi16(allFFs128, 8)); + const __m128i rrggbb1 = + _mm_and_si128(_mm_unpacklo_epi8(rgb1, rgb1), _mm_srli_epi16(allFFs128, 8)); + const __m128i rrggbb01 = + _mm_and_si128(_mm_unpackhi_epi8(rgb0, rgb0), _mm_srli_epi16(allFFs128, 8)); + const __m128i rrggbb11 = + _mm_and_si128(_mm_unpackhi_epi8(rgb1, rgb1), _mm_srli_epi16(allFFs128, 8)); - __m128i rgb2, rgb3; + __m128i rgb2, rgb3; - // if (rgb0 > rgb1): - if (cmp0 != 0) - { - // RGB2a = ((RGB1 - RGB0) >> 1) - ((RGB1 - RGB0) >> 3) using arithmetic shifts to extend sign (not logical shifts) - const __m128i rrggbbsub = _mm_subs_epi16(rrggbb1, rrggbb0); - const __m128i rrggbbsubshr1 = _mm_srai_epi16(rrggbbsub, 1); - const __m128i rrggbbsubshr3 = _mm_srai_epi16(rrggbbsub, 3); - const __m128i shr1subshr3 = _mm_sub_epi16(rrggbbsubshr1, rrggbbsubshr3); - // low8mask16 == _mm_set_epi16(0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff) - const __m128i low8mask16 = _mm_srli_epi16( allFFs128, 8 ); - const __m128i rrggbbdelta = _mm_and_si128(shr1subshr3, low8mask16); - const __m128i rgbdeltadup = _mm_packus_epi16(rrggbbdelta, rrggbbdelta); - const __m128i rgbdelta = _mm_srli_si128(_mm_slli_si128(rgbdeltadup, 8), 8); + // if (rgb0 > rgb1): + if (cmp0 != 0) + { + // RGB2a = ((RGB1 - RGB0) >> 1) - ((RGB1 - RGB0) >> 3) using arithmetic shifts to + // extend sign (not logical shifts) + const __m128i rrggbbsub = _mm_subs_epi16(rrggbb1, rrggbb0); + const __m128i rrggbbsubshr1 = _mm_srai_epi16(rrggbbsub, 1); + const __m128i rrggbbsubshr3 = _mm_srai_epi16(rrggbbsub, 3); + const __m128i shr1subshr3 = _mm_sub_epi16(rrggbbsubshr1, rrggbbsubshr3); + // low8mask16 == _mm_set_epi16(0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, + // 0x00ff) + const __m128i low8mask16 = _mm_srli_epi16(allFFs128, 8); + const __m128i rrggbbdelta = _mm_and_si128(shr1subshr3, low8mask16); + const __m128i rgbdeltadup = _mm_packus_epi16(rrggbbdelta, rrggbbdelta); + const __m128i rgbdelta = _mm_srli_si128(_mm_slli_si128(rgbdeltadup, 8), 8); - rgb2 = _mm_and_si128(_mm_add_epi8(rgb0, rgbdelta), _mm_srli_si128(allFFs128, 8)); - rgb3 = _mm_and_si128(_mm_sub_epi8(rgb1, rgbdelta), _mm_srli_si128(allFFs128, 8)); - } - else - { - // RGB2b = avg(RGB0, RGB1) - const __m128i rrggbb21 = _mm_avg_epu16(rrggbb0, rrggbb1); - const __m128i rgb210 = _mm_srli_si128(_mm_packus_epi16(rrggbb21, rrggbb21), 8); - rgb2 = rgb210; - rgb3 = _mm_and_si128(_mm_srli_si128(_mm_shuffle_epi32(argb888x4, _MM_SHUFFLE(1, 1, 1, 1)), 8), _mm_srli_epi32( allFFs128, 8 )); - } + rgb2 = _mm_and_si128(_mm_add_epi8(rgb0, rgbdelta), _mm_srli_si128(allFFs128, 8)); + rgb3 = _mm_and_si128(_mm_sub_epi8(rgb1, rgbdelta), _mm_srli_si128(allFFs128, 8)); + } + else + { + // RGB2b = avg(RGB0, RGB1) + const __m128i rrggbb21 = _mm_avg_epu16(rrggbb0, rrggbb1); + const __m128i rgb210 = _mm_srli_si128(_mm_packus_epi16(rrggbb21, rrggbb21), 8); + rgb2 = rgb210; + rgb3 = _mm_and_si128( + _mm_srli_si128(_mm_shuffle_epi32(argb888x4, _MM_SHUFFLE(1, 1, 1, 1)), 8), + _mm_srli_epi32(allFFs128, 8)); + } - // if (rgb0 > rgb1): - if (cmp1 != 0) - { - // RGB2a = ((RGB1 - RGB0) >> 1) - ((RGB1 - RGB0) >> 3) using arithmetic shifts to extend sign (not logical shifts) - const __m128i rrggbbsub1 = _mm_subs_epi16(rrggbb11, rrggbb01); - const __m128i rrggbbsubshr11 = _mm_srai_epi16(rrggbbsub1, 1); - const __m128i rrggbbsubshr31 = _mm_srai_epi16(rrggbbsub1, 3); - const __m128i shr1subshr31 = _mm_sub_epi16(rrggbbsubshr11, rrggbbsubshr31); - // low8mask16 == _mm_set_epi16(0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff) - const __m128i low8mask16 = _mm_srli_epi16( allFFs128, 8 ); - const __m128i rrggbbdelta1 = _mm_and_si128(shr1subshr31, low8mask16); - __m128i rgbdelta1 = _mm_packus_epi16(rrggbbdelta1, rrggbbdelta1); - rgbdelta1 = _mm_slli_si128(rgbdelta1, 8); + // if (rgb0 > rgb1): + if (cmp1 != 0) + { + // RGB2a = ((RGB1 - RGB0) >> 1) - ((RGB1 - RGB0) >> 3) using arithmetic shifts to + // extend sign (not logical shifts) + const __m128i rrggbbsub1 = _mm_subs_epi16(rrggbb11, rrggbb01); + const __m128i rrggbbsubshr11 = _mm_srai_epi16(rrggbbsub1, 1); + const __m128i rrggbbsubshr31 = _mm_srai_epi16(rrggbbsub1, 3); + const __m128i shr1subshr31 = _mm_sub_epi16(rrggbbsubshr11, rrggbbsubshr31); + // low8mask16 == _mm_set_epi16(0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, + // 0x00ff) + const __m128i low8mask16 = _mm_srli_epi16(allFFs128, 8); + const __m128i rrggbbdelta1 = _mm_and_si128(shr1subshr31, low8mask16); + __m128i rgbdelta1 = _mm_packus_epi16(rrggbbdelta1, rrggbbdelta1); + rgbdelta1 = _mm_slli_si128(rgbdelta1, 8); - rgb2 = _mm_or_si128(rgb2, _mm_and_si128(_mm_add_epi8(rgb0, rgbdelta1), _mm_slli_si128(allFFs128, 8))); - rgb3 = _mm_or_si128(rgb3, _mm_and_si128(_mm_sub_epi8(rgb1, rgbdelta1), _mm_slli_si128(allFFs128, 8))); - } - else - { - // RGB2b = avg(RGB0, RGB1) - const __m128i rrggbb211 = _mm_avg_epu16(rrggbb01, rrggbb11); - const __m128i rgb211 = _mm_slli_si128(_mm_packus_epi16(rrggbb211, rrggbb211), 8); - rgb2 = _mm_or_si128(rgb2, rgb211); + rgb2 = _mm_or_si128( + rgb2, _mm_and_si128(_mm_add_epi8(rgb0, rgbdelta1), _mm_slli_si128(allFFs128, 8))); + rgb3 = _mm_or_si128( + rgb3, _mm_and_si128(_mm_sub_epi8(rgb1, rgbdelta1), _mm_slli_si128(allFFs128, 8))); + } + else + { + // RGB2b = avg(RGB0, RGB1) + const __m128i rrggbb211 = _mm_avg_epu16(rrggbb01, rrggbb11); + const __m128i rgb211 = _mm_slli_si128(_mm_packus_epi16(rrggbb211, rrggbb211), 8); + rgb2 = _mm_or_si128(rgb2, rgb211); - // _mm_srli_epi32( allFFs128, 8 ) == _mm_set_epi32(0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF) - // Make this color fully transparent: - rgb3 = _mm_or_si128(rgb3, _mm_and_si128(_mm_and_si128(rgb1, _mm_srli_epi32( allFFs128, 8 ) ), _mm_slli_si128(allFFs128, 8))); - } + // _mm_srli_epi32( allFFs128, 8 ) == _mm_set_epi32(0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, + // 0x00FFFFFF) + // Make this color fully transparent: + rgb3 = _mm_or_si128(rgb3, + _mm_and_si128(_mm_and_si128(rgb1, _mm_srli_epi32(allFFs128, 8)), + _mm_slli_si128(allFFs128, 8))); + } - // Create an array for color lookups for DXT0 so we can use the 2-bit indices: - const __m128i mmcolors0 = _mm_or_si128( - _mm_or_si128( - _mm_srli_si128(_mm_slli_si128(argb888x4, 8), 8), - _mm_slli_si128(_mm_srli_si128(_mm_slli_si128(rgb2, 8), 8 + 4), 8) - ), - _mm_slli_si128(_mm_srli_si128(rgb3, 4), 8 + 4) - ); + // Create an array for color lookups for DXT0 so we can use the 2-bit indices: + const __m128i mmcolors0 = _mm_or_si128( + _mm_or_si128(_mm_srli_si128(_mm_slli_si128(argb888x4, 8), 8), + _mm_slli_si128(_mm_srli_si128(_mm_slli_si128(rgb2, 8), 8 + 4), 8)), + _mm_slli_si128(_mm_srli_si128(rgb3, 4), 8 + 4)); - // Create an array for color lookups for DXT1 so we can use the 2-bit indices: - const __m128i mmcolors1 = _mm_or_si128( - _mm_or_si128( - _mm_srli_si128(argb888x4, 8), - _mm_slli_si128(_mm_srli_si128(rgb2, 8 + 4), 8) - ), - _mm_slli_si128(_mm_srli_si128(rgb3, 8 + 4), 8 + 4) - ); + // Create an array for color lookups for DXT1 so we can use the 2-bit indices: + const __m128i mmcolors1 = + _mm_or_si128(_mm_or_si128(_mm_srli_si128(argb888x4, 8), + _mm_slli_si128(_mm_srli_si128(rgb2, 8 + 4), 8)), + _mm_slli_si128(_mm_srli_si128(rgb3, 8 + 4), 8 + 4)); - // The #ifdef CHECKs here and below are to compare correctness of output against the reference code. - // Don't use them in a normal build. +// The #ifdef CHECKs here and below are to compare correctness of output against the reference code. +// Don't use them in a normal build. #ifdef CHECK - // REFERENCE: - u32 tmp0[4][4], tmp1[4][4]; + // REFERENCE: + u32 tmp0[4][4], tmp1[4][4]; - DecodeDXTBlock(&(tmp0[0][0]), (const DXTBlock *)src, 4); - DecodeDXTBlock(&(tmp1[0][0]), (const DXTBlock *)(src + 8), 4); + DecodeDXTBlock(&(tmp0[0][0]), (const DXTBlock*)src, 4); + DecodeDXTBlock(&(tmp1[0][0]), (const DXTBlock*)(src + 8), 4); #endif - u32 *dst32 = ( dst + (y + z*4) * width + x ); + u32* dst32 = (dst + (y + z * 4) * width + x); - // Copy the colors here: - alignas(16) u32 colors0[4]; - alignas(16) u32 colors1[4]; - _mm_store_si128((__m128i*)colors0, mmcolors0); - _mm_store_si128((__m128i*)colors1, mmcolors1); + // Copy the colors here: + alignas(16) u32 colors0[4]; + alignas(16) u32 colors1[4]; + _mm_store_si128((__m128i*)colors0, mmcolors0); + _mm_store_si128((__m128i*)colors1, mmcolors1); - // Row 0: - dst32[(width * 0) + 0] = colors0[(dxt0sel >> ((0*8)+6)) & 3]; - dst32[(width * 0) + 1] = colors0[(dxt0sel >> ((0*8)+4)) & 3]; - dst32[(width * 0) + 2] = colors0[(dxt0sel >> ((0*8)+2)) & 3]; - dst32[(width * 0) + 3] = colors0[(dxt0sel >> ((0*8)+0)) & 3]; - dst32[(width * 0) + 4] = colors1[(dxt1sel >> ((0*8)+6)) & 3]; - dst32[(width * 0) + 5] = colors1[(dxt1sel >> ((0*8)+4)) & 3]; - dst32[(width * 0) + 6] = colors1[(dxt1sel >> ((0*8)+2)) & 3]; - dst32[(width * 0) + 7] = colors1[(dxt1sel >> ((0*8)+0)) & 3]; + // Row 0: + dst32[(width * 0) + 0] = colors0[(dxt0sel >> ((0 * 8) + 6)) & 3]; + dst32[(width * 0) + 1] = colors0[(dxt0sel >> ((0 * 8) + 4)) & 3]; + dst32[(width * 0) + 2] = colors0[(dxt0sel >> ((0 * 8) + 2)) & 3]; + dst32[(width * 0) + 3] = colors0[(dxt0sel >> ((0 * 8) + 0)) & 3]; + dst32[(width * 0) + 4] = colors1[(dxt1sel >> ((0 * 8) + 6)) & 3]; + dst32[(width * 0) + 5] = colors1[(dxt1sel >> ((0 * 8) + 4)) & 3]; + dst32[(width * 0) + 6] = colors1[(dxt1sel >> ((0 * 8) + 2)) & 3]; + dst32[(width * 0) + 7] = colors1[(dxt1sel >> ((0 * 8) + 0)) & 3]; #ifdef CHECK - assert( memcmp(&(tmp0[0]), &dst32[(width * 0)], 16) == 0 ); - assert( memcmp(&(tmp1[0]), &dst32[(width * 0) + 4], 16) == 0 ); + assert(memcmp(&(tmp0[0]), &dst32[(width * 0)], 16) == 0); + assert(memcmp(&(tmp1[0]), &dst32[(width * 0) + 4], 16) == 0); #endif - // Row 1: - dst32[(width * 1) + 0] = colors0[(dxt0sel >> ((1*8)+6)) & 3]; - dst32[(width * 1) + 1] = colors0[(dxt0sel >> ((1*8)+4)) & 3]; - dst32[(width * 1) + 2] = colors0[(dxt0sel >> ((1*8)+2)) & 3]; - dst32[(width * 1) + 3] = colors0[(dxt0sel >> ((1*8)+0)) & 3]; - dst32[(width * 1) + 4] = colors1[(dxt1sel >> ((1*8)+6)) & 3]; - dst32[(width * 1) + 5] = colors1[(dxt1sel >> ((1*8)+4)) & 3]; - dst32[(width * 1) + 6] = colors1[(dxt1sel >> ((1*8)+2)) & 3]; - dst32[(width * 1) + 7] = colors1[(dxt1sel >> ((1*8)+0)) & 3]; + // Row 1: + dst32[(width * 1) + 0] = colors0[(dxt0sel >> ((1 * 8) + 6)) & 3]; + dst32[(width * 1) + 1] = colors0[(dxt0sel >> ((1 * 8) + 4)) & 3]; + dst32[(width * 1) + 2] = colors0[(dxt0sel >> ((1 * 8) + 2)) & 3]; + dst32[(width * 1) + 3] = colors0[(dxt0sel >> ((1 * 8) + 0)) & 3]; + dst32[(width * 1) + 4] = colors1[(dxt1sel >> ((1 * 8) + 6)) & 3]; + dst32[(width * 1) + 5] = colors1[(dxt1sel >> ((1 * 8) + 4)) & 3]; + dst32[(width * 1) + 6] = colors1[(dxt1sel >> ((1 * 8) + 2)) & 3]; + dst32[(width * 1) + 7] = colors1[(dxt1sel >> ((1 * 8) + 0)) & 3]; #ifdef CHECK - assert( memcmp(&(tmp0[1]), &dst32[(width * 1)], 16) == 0 ); - assert( memcmp(&(tmp1[1]), &dst32[(width * 1) + 4], 16) == 0 ); + assert(memcmp(&(tmp0[1]), &dst32[(width * 1)], 16) == 0); + assert(memcmp(&(tmp1[1]), &dst32[(width * 1) + 4], 16) == 0); #endif - // Row 2: - dst32[(width * 2) + 0] = colors0[(dxt0sel >> ((2*8)+6)) & 3]; - dst32[(width * 2) + 1] = colors0[(dxt0sel >> ((2*8)+4)) & 3]; - dst32[(width * 2) + 2] = colors0[(dxt0sel >> ((2*8)+2)) & 3]; - dst32[(width * 2) + 3] = colors0[(dxt0sel >> ((2*8)+0)) & 3]; - dst32[(width * 2) + 4] = colors1[(dxt1sel >> ((2*8)+6)) & 3]; - dst32[(width * 2) + 5] = colors1[(dxt1sel >> ((2*8)+4)) & 3]; - dst32[(width * 2) + 6] = colors1[(dxt1sel >> ((2*8)+2)) & 3]; - dst32[(width * 2) + 7] = colors1[(dxt1sel >> ((2*8)+0)) & 3]; + // Row 2: + dst32[(width * 2) + 0] = colors0[(dxt0sel >> ((2 * 8) + 6)) & 3]; + dst32[(width * 2) + 1] = colors0[(dxt0sel >> ((2 * 8) + 4)) & 3]; + dst32[(width * 2) + 2] = colors0[(dxt0sel >> ((2 * 8) + 2)) & 3]; + dst32[(width * 2) + 3] = colors0[(dxt0sel >> ((2 * 8) + 0)) & 3]; + dst32[(width * 2) + 4] = colors1[(dxt1sel >> ((2 * 8) + 6)) & 3]; + dst32[(width * 2) + 5] = colors1[(dxt1sel >> ((2 * 8) + 4)) & 3]; + dst32[(width * 2) + 6] = colors1[(dxt1sel >> ((2 * 8) + 2)) & 3]; + dst32[(width * 2) + 7] = colors1[(dxt1sel >> ((2 * 8) + 0)) & 3]; #ifdef CHECK - assert( memcmp(&(tmp0[2]), &dst32[(width * 2)], 16) == 0 ); - assert( memcmp(&(tmp1[2]), &dst32[(width * 2) + 4], 16) == 0 ); + assert(memcmp(&(tmp0[2]), &dst32[(width * 2)], 16) == 0); + assert(memcmp(&(tmp1[2]), &dst32[(width * 2) + 4], 16) == 0); #endif - // Row 3: - dst32[(width * 3) + 0] = colors0[(dxt0sel >> ((3*8)+6)) & 3]; - dst32[(width * 3) + 1] = colors0[(dxt0sel >> ((3*8)+4)) & 3]; - dst32[(width * 3) + 2] = colors0[(dxt0sel >> ((3*8)+2)) & 3]; - dst32[(width * 3) + 3] = colors0[(dxt0sel >> ((3*8)+0)) & 3]; - dst32[(width * 3) + 4] = colors1[(dxt1sel >> ((3*8)+6)) & 3]; - dst32[(width * 3) + 5] = colors1[(dxt1sel >> ((3*8)+4)) & 3]; - dst32[(width * 3) + 6] = colors1[(dxt1sel >> ((3*8)+2)) & 3]; - dst32[(width * 3) + 7] = colors1[(dxt1sel >> ((3*8)+0)) & 3]; + // Row 3: + dst32[(width * 3) + 0] = colors0[(dxt0sel >> ((3 * 8) + 6)) & 3]; + dst32[(width * 3) + 1] = colors0[(dxt0sel >> ((3 * 8) + 4)) & 3]; + dst32[(width * 3) + 2] = colors0[(dxt0sel >> ((3 * 8) + 2)) & 3]; + dst32[(width * 3) + 3] = colors0[(dxt0sel >> ((3 * 8) + 0)) & 3]; + dst32[(width * 3) + 4] = colors1[(dxt1sel >> ((3 * 8) + 6)) & 3]; + dst32[(width * 3) + 5] = colors1[(dxt1sel >> ((3 * 8) + 4)) & 3]; + dst32[(width * 3) + 6] = colors1[(dxt1sel >> ((3 * 8) + 2)) & 3]; + dst32[(width * 3) + 7] = colors1[(dxt1sel >> ((3 * 8) + 0)) & 3]; #ifdef CHECK - assert( memcmp(&(tmp0[3]), &dst32[(width * 3)], 16) == 0 ); - assert( memcmp(&(tmp1[3]), &dst32[(width * 3) + 4], 16) == 0 ); + assert(memcmp(&(tmp0[3]), &dst32[(width * 3)], 16) == 0); + assert(memcmp(&(tmp1[3]), &dst32[(width * 3) + 4], 16) == 0); #endif - } - } - } - break; - } - } + } + } + } + break; + } + } } diff --git a/Source/Core/VideoCommon/VertexLoader.cpp b/Source/Core/VideoCommon/VertexLoader.cpp index 7846103f5a..e1410b49f2 100644 --- a/Source/Core/VideoCommon/VertexLoader.cpp +++ b/Source/Core/VideoCommon/VertexLoader.cpp @@ -7,12 +7,12 @@ #include "VideoCommon/DataReader.h" #include "VideoCommon/VertexLoader.h" +#include "VideoCommon/VertexLoaderManager.h" +#include "VideoCommon/VertexLoaderUtils.h" #include "VideoCommon/VertexLoader_Color.h" #include "VideoCommon/VertexLoader_Normal.h" #include "VideoCommon/VertexLoader_Position.h" #include "VideoCommon/VertexLoader_TextCoord.h" -#include "VideoCommon/VertexLoaderManager.h" -#include "VideoCommon/VertexLoaderUtils.h" #include "VideoCommon/VideoCommon.h" // This pointer is used as the source/dst for all fixed function loader calls @@ -21,310 +21,402 @@ u8* g_vertex_manager_write_ptr; static void PosMtx_ReadDirect_UByte(VertexLoader* loader) { - u32 posmtx = DataRead() & 0x3f; - if (loader->m_counter < 3) - VertexLoaderManager::position_matrix_index[loader->m_counter] = posmtx; - DataWrite(posmtx); - PRIM_LOG("posmtx: %d, ", posmtx); + u32 posmtx = DataRead() & 0x3f; + if (loader->m_counter < 3) + VertexLoaderManager::position_matrix_index[loader->m_counter] = posmtx; + DataWrite(posmtx); + PRIM_LOG("posmtx: %d, ", posmtx); } static void TexMtx_ReadDirect_UByte(VertexLoader* loader) { - loader->m_curtexmtx[loader->m_texmtxread] = DataRead() & 0x3f; + loader->m_curtexmtx[loader->m_texmtxread] = DataRead() & 0x3f; - PRIM_LOG("texmtx%d: %d, ", loader->m_texmtxread, loader->m_curtexmtx[loader->m_texmtxread]); - loader->m_texmtxread++; + PRIM_LOG("texmtx%d: %d, ", loader->m_texmtxread, loader->m_curtexmtx[loader->m_texmtxread]); + loader->m_texmtxread++; } static void TexMtx_Write_Float(VertexLoader* loader) { - DataWrite(float(loader->m_curtexmtx[loader->m_texmtxwrite++])); + DataWrite(float(loader->m_curtexmtx[loader->m_texmtxwrite++])); } static void TexMtx_Write_Float2(VertexLoader* loader) { - DataWrite(0.f); - DataWrite(float(loader->m_curtexmtx[loader->m_texmtxwrite++])); + DataWrite(0.f); + DataWrite(float(loader->m_curtexmtx[loader->m_texmtxwrite++])); } static void TexMtx_Write_Float3(VertexLoader* loader) { - DataWrite(0.f); - DataWrite(0.f); - DataWrite(float(loader->m_curtexmtx[loader->m_texmtxwrite++])); + DataWrite(0.f); + DataWrite(0.f); + DataWrite(float(loader->m_curtexmtx[loader->m_texmtxwrite++])); } static void SkipVertex(VertexLoader* loader) { - if (loader->m_vertexSkip) - { - // reset the output buffer - g_vertex_manager_write_ptr -= loader->m_native_vtx_decl.stride; + if (loader->m_vertexSkip) + { + // reset the output buffer + g_vertex_manager_write_ptr -= loader->m_native_vtx_decl.stride; - loader->m_skippedVertices++; - } + loader->m_skippedVertices++; + } } -VertexLoader::VertexLoader(const TVtxDesc &vtx_desc, const VAT &vtx_attr) -: VertexLoaderBase(vtx_desc, vtx_attr) +VertexLoader::VertexLoader(const TVtxDesc& vtx_desc, const VAT& vtx_attr) + : VertexLoaderBase(vtx_desc, vtx_attr) { - VertexLoader_Normal::Init(); + VertexLoader_Normal::Init(); - CompileVertexTranslator(); + CompileVertexTranslator(); - // generate frac factors - m_posScale = 1.0f / (1U << m_VtxAttr.PosFrac); - for (int i = 0; i < 8; i++) - m_tcScale[i] = 1.0f / (1U << m_VtxAttr.texCoord[i].Frac); + // generate frac factors + m_posScale = 1.0f / (1U << m_VtxAttr.PosFrac); + for (int i = 0; i < 8; i++) + m_tcScale[i] = 1.0f / (1U << m_VtxAttr.texCoord[i].Frac); } void VertexLoader::CompileVertexTranslator() { - m_VertexSize = 0; - const TVtxAttr &vtx_attr = m_VtxAttr; + m_VertexSize = 0; + const TVtxAttr& vtx_attr = m_VtxAttr; - // Reset pipeline - m_numPipelineStages = 0; + // Reset pipeline + m_numPipelineStages = 0; - // Colors - const u64 col[2] = { m_VtxDesc.Color0, m_VtxDesc.Color1 }; - // TextureCoord - const u64 tc[8] = { - m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord, m_VtxDesc.Tex3Coord, - m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, m_VtxDesc.Tex6Coord, m_VtxDesc.Tex7Coord - }; + // Colors + const u64 col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1}; + // TextureCoord + const u64 tc[8] = {m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord, + m_VtxDesc.Tex3Coord, m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, + m_VtxDesc.Tex6Coord, m_VtxDesc.Tex7Coord}; - u32 components = 0; + u32 components = 0; - // Position in pc vertex format. - int nat_offset = 0; + // Position in pc vertex format. + int nat_offset = 0; - // Position Matrix Index - if (m_VtxDesc.PosMatIdx) - { - WriteCall(PosMtx_ReadDirect_UByte); - components |= VB_HAS_POSMTXIDX; - m_native_vtx_decl.posmtx.components = 4; - m_native_vtx_decl.posmtx.enable = true; - m_native_vtx_decl.posmtx.offset = nat_offset; - m_native_vtx_decl.posmtx.type = VAR_UNSIGNED_BYTE; - m_native_vtx_decl.posmtx.integer = true; - nat_offset += 4; - m_VertexSize += 1; - } + // Position Matrix Index + if (m_VtxDesc.PosMatIdx) + { + WriteCall(PosMtx_ReadDirect_UByte); + components |= VB_HAS_POSMTXIDX; + m_native_vtx_decl.posmtx.components = 4; + m_native_vtx_decl.posmtx.enable = true; + m_native_vtx_decl.posmtx.offset = nat_offset; + m_native_vtx_decl.posmtx.type = VAR_UNSIGNED_BYTE; + m_native_vtx_decl.posmtx.integer = true; + nat_offset += 4; + m_VertexSize += 1; + } - if (m_VtxDesc.Tex0MatIdx) { m_VertexSize += 1; components |= VB_HAS_TEXMTXIDX0; WriteCall(TexMtx_ReadDirect_UByte); } - if (m_VtxDesc.Tex1MatIdx) { m_VertexSize += 1; components |= VB_HAS_TEXMTXIDX1; WriteCall(TexMtx_ReadDirect_UByte); } - if (m_VtxDesc.Tex2MatIdx) { m_VertexSize += 1; components |= VB_HAS_TEXMTXIDX2; WriteCall(TexMtx_ReadDirect_UByte); } - if (m_VtxDesc.Tex3MatIdx) { m_VertexSize += 1; components |= VB_HAS_TEXMTXIDX3; WriteCall(TexMtx_ReadDirect_UByte); } - if (m_VtxDesc.Tex4MatIdx) { m_VertexSize += 1; components |= VB_HAS_TEXMTXIDX4; WriteCall(TexMtx_ReadDirect_UByte); } - if (m_VtxDesc.Tex5MatIdx) { m_VertexSize += 1; components |= VB_HAS_TEXMTXIDX5; WriteCall(TexMtx_ReadDirect_UByte); } - if (m_VtxDesc.Tex6MatIdx) { m_VertexSize += 1; components |= VB_HAS_TEXMTXIDX6; WriteCall(TexMtx_ReadDirect_UByte); } - if (m_VtxDesc.Tex7MatIdx) { m_VertexSize += 1; components |= VB_HAS_TEXMTXIDX7; WriteCall(TexMtx_ReadDirect_UByte); } + if (m_VtxDesc.Tex0MatIdx) + { + m_VertexSize += 1; + components |= VB_HAS_TEXMTXIDX0; + WriteCall(TexMtx_ReadDirect_UByte); + } + if (m_VtxDesc.Tex1MatIdx) + { + m_VertexSize += 1; + components |= VB_HAS_TEXMTXIDX1; + WriteCall(TexMtx_ReadDirect_UByte); + } + if (m_VtxDesc.Tex2MatIdx) + { + m_VertexSize += 1; + components |= VB_HAS_TEXMTXIDX2; + WriteCall(TexMtx_ReadDirect_UByte); + } + if (m_VtxDesc.Tex3MatIdx) + { + m_VertexSize += 1; + components |= VB_HAS_TEXMTXIDX3; + WriteCall(TexMtx_ReadDirect_UByte); + } + if (m_VtxDesc.Tex4MatIdx) + { + m_VertexSize += 1; + components |= VB_HAS_TEXMTXIDX4; + WriteCall(TexMtx_ReadDirect_UByte); + } + if (m_VtxDesc.Tex5MatIdx) + { + m_VertexSize += 1; + components |= VB_HAS_TEXMTXIDX5; + WriteCall(TexMtx_ReadDirect_UByte); + } + if (m_VtxDesc.Tex6MatIdx) + { + m_VertexSize += 1; + components |= VB_HAS_TEXMTXIDX6; + WriteCall(TexMtx_ReadDirect_UByte); + } + if (m_VtxDesc.Tex7MatIdx) + { + m_VertexSize += 1; + components |= VB_HAS_TEXMTXIDX7; + WriteCall(TexMtx_ReadDirect_UByte); + } - // Write vertex position loader - WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.Position, m_VtxAttr.PosFormat, m_VtxAttr.PosElements)); + // Write vertex position loader + WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.Position, m_VtxAttr.PosFormat, + m_VtxAttr.PosElements)); - m_VertexSize += VertexLoader_Position::GetSize(m_VtxDesc.Position, m_VtxAttr.PosFormat, m_VtxAttr.PosElements); - int pos_elements = m_VtxAttr.PosElements + 2; - m_native_vtx_decl.position.components = pos_elements; - m_native_vtx_decl.position.enable = true; - m_native_vtx_decl.position.offset = nat_offset; - m_native_vtx_decl.position.type = VAR_FLOAT; - m_native_vtx_decl.position.integer = false; - nat_offset += pos_elements * sizeof(float); + m_VertexSize += VertexLoader_Position::GetSize(m_VtxDesc.Position, m_VtxAttr.PosFormat, + m_VtxAttr.PosElements); + int pos_elements = m_VtxAttr.PosElements + 2; + m_native_vtx_decl.position.components = pos_elements; + m_native_vtx_decl.position.enable = true; + m_native_vtx_decl.position.offset = nat_offset; + m_native_vtx_decl.position.type = VAR_FLOAT; + m_native_vtx_decl.position.integer = false; + nat_offset += pos_elements * sizeof(float); - // Normals - if (m_VtxDesc.Normal != NOT_PRESENT) - { - m_VertexSize += VertexLoader_Normal::GetSize(m_VtxDesc.Normal, - m_VtxAttr.NormalFormat, m_VtxAttr.NormalElements, m_VtxAttr.NormalIndex3); + // Normals + if (m_VtxDesc.Normal != NOT_PRESENT) + { + m_VertexSize += VertexLoader_Normal::GetSize(m_VtxDesc.Normal, m_VtxAttr.NormalFormat, + m_VtxAttr.NormalElements, m_VtxAttr.NormalIndex3); - TPipelineFunction pFunc = VertexLoader_Normal::GetFunction(m_VtxDesc.Normal, - m_VtxAttr.NormalFormat, m_VtxAttr.NormalElements, m_VtxAttr.NormalIndex3); + TPipelineFunction pFunc = VertexLoader_Normal::GetFunction( + m_VtxDesc.Normal, m_VtxAttr.NormalFormat, m_VtxAttr.NormalElements, m_VtxAttr.NormalIndex3); - if (pFunc == nullptr) - { - PanicAlert("VertexLoader_Normal::GetFunction(%i %i %i %i) returned zero!", - (u32)m_VtxDesc.Normal, m_VtxAttr.NormalFormat, - m_VtxAttr.NormalElements, m_VtxAttr.NormalIndex3); - } - WriteCall(pFunc); + if (pFunc == nullptr) + { + PanicAlert("VertexLoader_Normal::GetFunction(%i %i %i %i) returned zero!", + (u32)m_VtxDesc.Normal, m_VtxAttr.NormalFormat, m_VtxAttr.NormalElements, + m_VtxAttr.NormalIndex3); + } + WriteCall(pFunc); - for (int i = 0; i < (vtx_attr.NormalElements ? 3 : 1); i++) - { - m_native_vtx_decl.normals[i].components = 3; - m_native_vtx_decl.normals[i].enable = true; - m_native_vtx_decl.normals[i].offset = nat_offset; - m_native_vtx_decl.normals[i].type = VAR_FLOAT; - m_native_vtx_decl.normals[i].integer = false; - nat_offset += 12; - } + for (int i = 0; i < (vtx_attr.NormalElements ? 3 : 1); i++) + { + m_native_vtx_decl.normals[i].components = 3; + m_native_vtx_decl.normals[i].enable = true; + m_native_vtx_decl.normals[i].offset = nat_offset; + m_native_vtx_decl.normals[i].type = VAR_FLOAT; + m_native_vtx_decl.normals[i].integer = false; + nat_offset += 12; + } - components |= VB_HAS_NRM0; - if (m_VtxAttr.NormalElements == 1) - components |= VB_HAS_NRM1 | VB_HAS_NRM2; - } + components |= VB_HAS_NRM0; + if (m_VtxAttr.NormalElements == 1) + components |= VB_HAS_NRM1 | VB_HAS_NRM2; + } - for (int i = 0; i < 2; i++) - { - m_native_vtx_decl.colors[i].components = 4; - m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE; - m_native_vtx_decl.colors[i].integer = false; - switch (col[i]) - { - case NOT_PRESENT: - break; - case DIRECT: - switch (m_VtxAttr.color[i].Comp) - { - case FORMAT_16B_565: m_VertexSize += 2; WriteCall(Color_ReadDirect_16b_565); break; - case FORMAT_24B_888: m_VertexSize += 3; WriteCall(Color_ReadDirect_24b_888); break; - case FORMAT_32B_888x: m_VertexSize += 4; WriteCall(Color_ReadDirect_32b_888x); break; - case FORMAT_16B_4444: m_VertexSize += 2; WriteCall(Color_ReadDirect_16b_4444); break; - case FORMAT_24B_6666: m_VertexSize += 3; WriteCall(Color_ReadDirect_24b_6666); break; - case FORMAT_32B_8888: m_VertexSize += 4; WriteCall(Color_ReadDirect_32b_8888); break; - default: _assert_(0); break; - } - break; - case INDEX8: - m_VertexSize += 1; - switch (m_VtxAttr.color[i].Comp) - { - case FORMAT_16B_565: WriteCall(Color_ReadIndex8_16b_565); break; - case FORMAT_24B_888: WriteCall(Color_ReadIndex8_24b_888); break; - case FORMAT_32B_888x: WriteCall(Color_ReadIndex8_32b_888x); break; - case FORMAT_16B_4444: WriteCall(Color_ReadIndex8_16b_4444); break; - case FORMAT_24B_6666: WriteCall(Color_ReadIndex8_24b_6666); break; - case FORMAT_32B_8888: WriteCall(Color_ReadIndex8_32b_8888); break; - default: _assert_(0); break; - } - break; - case INDEX16: - m_VertexSize += 2; - switch (m_VtxAttr.color[i].Comp) - { - case FORMAT_16B_565: WriteCall(Color_ReadIndex16_16b_565); break; - case FORMAT_24B_888: WriteCall(Color_ReadIndex16_24b_888); break; - case FORMAT_32B_888x: WriteCall(Color_ReadIndex16_32b_888x); break; - case FORMAT_16B_4444: WriteCall(Color_ReadIndex16_16b_4444); break; - case FORMAT_24B_6666: WriteCall(Color_ReadIndex16_24b_6666); break; - case FORMAT_32B_8888: WriteCall(Color_ReadIndex16_32b_8888); break; - default: _assert_(0); break; - } - break; - } - // Common for the three bottom cases - if (col[i] != NOT_PRESENT) - { - components |= VB_HAS_COL0 << i; - m_native_vtx_decl.colors[i].offset = nat_offset; - m_native_vtx_decl.colors[i].enable = true; - nat_offset += 4; - } - } + for (int i = 0; i < 2; i++) + { + m_native_vtx_decl.colors[i].components = 4; + m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE; + m_native_vtx_decl.colors[i].integer = false; + switch (col[i]) + { + case NOT_PRESENT: + break; + case DIRECT: + switch (m_VtxAttr.color[i].Comp) + { + case FORMAT_16B_565: + m_VertexSize += 2; + WriteCall(Color_ReadDirect_16b_565); + break; + case FORMAT_24B_888: + m_VertexSize += 3; + WriteCall(Color_ReadDirect_24b_888); + break; + case FORMAT_32B_888x: + m_VertexSize += 4; + WriteCall(Color_ReadDirect_32b_888x); + break; + case FORMAT_16B_4444: + m_VertexSize += 2; + WriteCall(Color_ReadDirect_16b_4444); + break; + case FORMAT_24B_6666: + m_VertexSize += 3; + WriteCall(Color_ReadDirect_24b_6666); + break; + case FORMAT_32B_8888: + m_VertexSize += 4; + WriteCall(Color_ReadDirect_32b_8888); + break; + default: + _assert_(0); + break; + } + break; + case INDEX8: + m_VertexSize += 1; + switch (m_VtxAttr.color[i].Comp) + { + case FORMAT_16B_565: + WriteCall(Color_ReadIndex8_16b_565); + break; + case FORMAT_24B_888: + WriteCall(Color_ReadIndex8_24b_888); + break; + case FORMAT_32B_888x: + WriteCall(Color_ReadIndex8_32b_888x); + break; + case FORMAT_16B_4444: + WriteCall(Color_ReadIndex8_16b_4444); + break; + case FORMAT_24B_6666: + WriteCall(Color_ReadIndex8_24b_6666); + break; + case FORMAT_32B_8888: + WriteCall(Color_ReadIndex8_32b_8888); + break; + default: + _assert_(0); + break; + } + break; + case INDEX16: + m_VertexSize += 2; + switch (m_VtxAttr.color[i].Comp) + { + case FORMAT_16B_565: + WriteCall(Color_ReadIndex16_16b_565); + break; + case FORMAT_24B_888: + WriteCall(Color_ReadIndex16_24b_888); + break; + case FORMAT_32B_888x: + WriteCall(Color_ReadIndex16_32b_888x); + break; + case FORMAT_16B_4444: + WriteCall(Color_ReadIndex16_16b_4444); + break; + case FORMAT_24B_6666: + WriteCall(Color_ReadIndex16_24b_6666); + break; + case FORMAT_32B_8888: + WriteCall(Color_ReadIndex16_32b_8888); + break; + default: + _assert_(0); + break; + } + break; + } + // Common for the three bottom cases + if (col[i] != NOT_PRESENT) + { + components |= VB_HAS_COL0 << i; + m_native_vtx_decl.colors[i].offset = nat_offset; + m_native_vtx_decl.colors[i].enable = true; + nat_offset += 4; + } + } - // Texture matrix indices (remove if corresponding texture coordinate isn't enabled) - for (int i = 0; i < 8; i++) - { - m_native_vtx_decl.texcoords[i].offset = nat_offset; - m_native_vtx_decl.texcoords[i].type = VAR_FLOAT; - m_native_vtx_decl.texcoords[i].integer = false; + // Texture matrix indices (remove if corresponding texture coordinate isn't enabled) + for (int i = 0; i < 8; i++) + { + m_native_vtx_decl.texcoords[i].offset = nat_offset; + m_native_vtx_decl.texcoords[i].type = VAR_FLOAT; + m_native_vtx_decl.texcoords[i].integer = false; - const int format = m_VtxAttr.texCoord[i].Format; - const int elements = m_VtxAttr.texCoord[i].Elements; + const int format = m_VtxAttr.texCoord[i].Format; + const int elements = m_VtxAttr.texCoord[i].Elements; - if (tc[i] != NOT_PRESENT) - { - _assert_msg_(VIDEO, DIRECT <= tc[i] && tc[i] <= INDEX16, "Invalid texture coordinates!\n(tc[i] = %d)", (u32)tc[i]); - _assert_msg_(VIDEO, FORMAT_UBYTE <= format && format <= FORMAT_FLOAT, "Invalid texture coordinates format!\n(format = %d)", format); - _assert_msg_(VIDEO, 0 <= elements && elements <= 1, "Invalid number of texture coordinates elements!\n(elements = %d)", elements); + if (tc[i] != NOT_PRESENT) + { + _assert_msg_(VIDEO, DIRECT <= tc[i] && tc[i] <= INDEX16, + "Invalid texture coordinates!\n(tc[i] = %d)", (u32)tc[i]); + _assert_msg_(VIDEO, FORMAT_UBYTE <= format && format <= FORMAT_FLOAT, + "Invalid texture coordinates format!\n(format = %d)", format); + _assert_msg_(VIDEO, 0 <= elements && elements <= 1, + "Invalid number of texture coordinates elements!\n(elements = %d)", elements); - components |= VB_HAS_UV0 << i; - WriteCall(VertexLoader_TextCoord::GetFunction(tc[i], format, elements)); - m_VertexSize += VertexLoader_TextCoord::GetSize(tc[i], format, elements); - } + components |= VB_HAS_UV0 << i; + WriteCall(VertexLoader_TextCoord::GetFunction(tc[i], format, elements)); + m_VertexSize += VertexLoader_TextCoord::GetSize(tc[i], format, elements); + } - if (components & (VB_HAS_TEXMTXIDX0 << i)) - { - m_native_vtx_decl.texcoords[i].enable = true; - if (tc[i] != NOT_PRESENT) - { - // if texmtx is included, texcoord will always be 3 floats, z will be the texmtx index - m_native_vtx_decl.texcoords[i].components = 3; - nat_offset += 12; - WriteCall(m_VtxAttr.texCoord[i].Elements ? TexMtx_Write_Float : TexMtx_Write_Float2); - } - else - { - m_native_vtx_decl.texcoords[i].components = 3; - nat_offset += 12; - WriteCall(TexMtx_Write_Float3); - } - } - else - { - if (tc[i] != NOT_PRESENT) - { - m_native_vtx_decl.texcoords[i].enable = true; - m_native_vtx_decl.texcoords[i].components = vtx_attr.texCoord[i].Elements ? 2 : 1; - nat_offset += 4 * (vtx_attr.texCoord[i].Elements ? 2 : 1); - } - } + if (components & (VB_HAS_TEXMTXIDX0 << i)) + { + m_native_vtx_decl.texcoords[i].enable = true; + if (tc[i] != NOT_PRESENT) + { + // if texmtx is included, texcoord will always be 3 floats, z will be the texmtx index + m_native_vtx_decl.texcoords[i].components = 3; + nat_offset += 12; + WriteCall(m_VtxAttr.texCoord[i].Elements ? TexMtx_Write_Float : TexMtx_Write_Float2); + } + else + { + m_native_vtx_decl.texcoords[i].components = 3; + nat_offset += 12; + WriteCall(TexMtx_Write_Float3); + } + } + else + { + if (tc[i] != NOT_PRESENT) + { + m_native_vtx_decl.texcoords[i].enable = true; + m_native_vtx_decl.texcoords[i].components = vtx_attr.texCoord[i].Elements ? 2 : 1; + nat_offset += 4 * (vtx_attr.texCoord[i].Elements ? 2 : 1); + } + } - if (tc[i] == NOT_PRESENT) - { - // if there's more tex coords later, have to write a dummy call - int j = i + 1; - for (; j < 8; ++j) - { - if (tc[j] != NOT_PRESENT) - { - WriteCall(VertexLoader_TextCoord::GetDummyFunction()); // important to get indices right! - break; - } - } - // tricky! - if (j == 8 && !((components & VB_HAS_TEXMTXIDXALL) & (VB_HAS_TEXMTXIDXALL << (i + 1)))) - { - // no more tex coords and tex matrices, so exit loop - break; - } - } - } + if (tc[i] == NOT_PRESENT) + { + // if there's more tex coords later, have to write a dummy call + int j = i + 1; + for (; j < 8; ++j) + { + if (tc[j] != NOT_PRESENT) + { + WriteCall(VertexLoader_TextCoord::GetDummyFunction()); // important to get indices right! + break; + } + } + // tricky! + if (j == 8 && !((components & VB_HAS_TEXMTXIDXALL) & (VB_HAS_TEXMTXIDXALL << (i + 1)))) + { + // no more tex coords and tex matrices, so exit loop + break; + } + } + } - // indexed position formats may skip a the vertex - if (m_VtxDesc.Position & 2) - { - WriteCall(SkipVertex); - } + // indexed position formats may skip a the vertex + if (m_VtxDesc.Position & 2) + { + WriteCall(SkipVertex); + } - m_native_components = components; - m_native_vtx_decl.stride = nat_offset; + m_native_components = components; + m_native_vtx_decl.stride = nat_offset; } void VertexLoader::WriteCall(TPipelineFunction func) { - m_PipelineStages[m_numPipelineStages++] = func; + m_PipelineStages[m_numPipelineStages++] = func; } int VertexLoader::RunVertices(DataReader src, DataReader dst, int count) { - g_vertex_manager_write_ptr = dst.GetPointer(); - g_video_buffer_read_ptr = src.GetPointer(); + g_vertex_manager_write_ptr = dst.GetPointer(); + g_video_buffer_read_ptr = src.GetPointer(); - m_numLoadedVertices += count; - m_skippedVertices = 0; + m_numLoadedVertices += count; + m_skippedVertices = 0; - for (m_counter = count - 1; m_counter >= 0; m_counter--) - { - m_tcIndex = 0; - m_colIndex = 0; - m_texmtxwrite = m_texmtxread = 0; - for (int i = 0; i < m_numPipelineStages; i++) - m_PipelineStages[i](this); - PRIM_LOG("\n"); - } + for (m_counter = count - 1; m_counter >= 0; m_counter--) + { + m_tcIndex = 0; + m_colIndex = 0; + m_texmtxwrite = m_texmtxread = 0; + for (int i = 0; i < m_numPipelineStages; i++) + m_PipelineStages[i](this); + PRIM_LOG("\n"); + } - return count - m_skippedVertices; + return count - m_skippedVertices; } diff --git a/Source/Core/VideoCommon/VertexLoader.h b/Source/Core/VideoCommon/VertexLoader.h index 5cbc4071b0..2caae086d3 100644 --- a/Source/Core/VideoCommon/VertexLoader.h +++ b/Source/Core/VideoCommon/VertexLoader.h @@ -19,33 +19,33 @@ typedef void (*TPipelineFunction)(VertexLoader* loader); class VertexLoader : public VertexLoaderBase { public: - VertexLoader(const TVtxDesc &vtx_desc, const VAT &vtx_attr); + VertexLoader(const TVtxDesc& vtx_desc, const VAT& vtx_attr); - int RunVertices(DataReader src, DataReader dst, int count) override; - std::string GetName() const override { return "OldLoader"; } - bool IsInitialized() override { return true; } // This vertex loader supports all formats + int RunVertices(DataReader src, DataReader dst, int count) override; + std::string GetName() const override { return "OldLoader"; } + bool IsInitialized() override { return true; } // This vertex loader supports all formats + // They are used for the communication with the loader functions + float m_posScale; + float m_tcScale[8]; + int m_tcIndex; + int m_colIndex; - // They are used for the communication with the loader functions - float m_posScale; - float m_tcScale[8]; - int m_tcIndex; - int m_colIndex; - - // Matrix components are first in GC format but later in PC format - we need to store it temporarily - // when decoding each vertex. - u8 m_curtexmtx[8]; - int m_texmtxwrite; - int m_texmtxread; - bool m_vertexSkip; - int m_skippedVertices; - int m_counter; + // Matrix components are first in GC format but later in PC format - we need to store it + // temporarily + // when decoding each vertex. + u8 m_curtexmtx[8]; + int m_texmtxwrite; + int m_texmtxread; + bool m_vertexSkip; + int m_skippedVertices; + int m_counter; private: - // Pipeline. - TPipelineFunction m_PipelineStages[64]; // TODO - figure out real max. it's lower. - int m_numPipelineStages; + // Pipeline. + TPipelineFunction m_PipelineStages[64]; // TODO - figure out real max. it's lower. + int m_numPipelineStages; - void CompileVertexTranslator(); + void CompileVertexTranslator(); - void WriteCall(TPipelineFunction); + void WriteCall(TPipelineFunction); }; diff --git a/Source/Core/VideoCommon/VertexLoaderARM64.cpp b/Source/Core/VideoCommon/VertexLoaderARM64.cpp index e068a9abac..cf0fd576f4 100644 --- a/Source/Core/VideoCommon/VertexLoaderARM64.cpp +++ b/Source/Core/VideoCommon/VertexLoaderARM64.cpp @@ -2,9 +2,9 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "VideoCommon/VertexLoaderARM64.h" #include "Common/CommonTypes.h" #include "VideoCommon/DataReader.h" -#include "VideoCommon/VertexLoaderARM64.h" #include "VideoCommon/VertexLoaderManager.h" using namespace Arm64Gen; @@ -23,588 +23,596 @@ ARM64Reg stride_reg = X11; ARM64Reg arraybase_reg = X10; ARM64Reg scale_reg = X9; -alignas(16) static const float scale_factors[] = -{ - 1.0 / (1ULL << 0), 1.0 / (1ULL << 1), 1.0 / (1ULL << 2), 1.0 / (1ULL << 3), - 1.0 / (1ULL << 4), 1.0 / (1ULL << 5), 1.0 / (1ULL << 6), 1.0 / (1ULL << 7), - 1.0 / (1ULL << 8), 1.0 / (1ULL << 9), 1.0 / (1ULL << 10), 1.0 / (1ULL << 11), - 1.0 / (1ULL << 12), 1.0 / (1ULL << 13), 1.0 / (1ULL << 14), 1.0 / (1ULL << 15), - 1.0 / (1ULL << 16), 1.0 / (1ULL << 17), 1.0 / (1ULL << 18), 1.0 / (1ULL << 19), - 1.0 / (1ULL << 20), 1.0 / (1ULL << 21), 1.0 / (1ULL << 22), 1.0 / (1ULL << 23), - 1.0 / (1ULL << 24), 1.0 / (1ULL << 25), 1.0 / (1ULL << 26), 1.0 / (1ULL << 27), - 1.0 / (1ULL << 28), 1.0 / (1ULL << 29), 1.0 / (1ULL << 30), 1.0 / (1ULL << 31), +alignas(16) static const float scale_factors[] = { + 1.0 / (1ULL << 0), 1.0 / (1ULL << 1), 1.0 / (1ULL << 2), 1.0 / (1ULL << 3), + 1.0 / (1ULL << 4), 1.0 / (1ULL << 5), 1.0 / (1ULL << 6), 1.0 / (1ULL << 7), + 1.0 / (1ULL << 8), 1.0 / (1ULL << 9), 1.0 / (1ULL << 10), 1.0 / (1ULL << 11), + 1.0 / (1ULL << 12), 1.0 / (1ULL << 13), 1.0 / (1ULL << 14), 1.0 / (1ULL << 15), + 1.0 / (1ULL << 16), 1.0 / (1ULL << 17), 1.0 / (1ULL << 18), 1.0 / (1ULL << 19), + 1.0 / (1ULL << 20), 1.0 / (1ULL << 21), 1.0 / (1ULL << 22), 1.0 / (1ULL << 23), + 1.0 / (1ULL << 24), 1.0 / (1ULL << 25), 1.0 / (1ULL << 26), 1.0 / (1ULL << 27), + 1.0 / (1ULL << 28), 1.0 / (1ULL << 29), 1.0 / (1ULL << 30), 1.0 / (1ULL << 31), }; VertexLoaderARM64::VertexLoaderARM64(const TVtxDesc& vtx_desc, const VAT& vtx_att) - : VertexLoaderBase(vtx_desc, vtx_att), m_float_emit(this) + : VertexLoaderBase(vtx_desc, vtx_att), m_float_emit(this) { - if (!IsInitialized()) - return; + if (!IsInitialized()) + return; - AllocCodeSpace(4096); - ClearCodeSpace(); - GenerateVertexLoader(); - WriteProtect(); + AllocCodeSpace(4096); + ClearCodeSpace(); + GenerateVertexLoader(); + WriteProtect(); } void VertexLoaderARM64::GetVertexAddr(int array, u64 attribute, ARM64Reg reg) { - if (attribute & MASK_INDEXED) - { - if (attribute == INDEX8) - { - if (m_src_ofs < 4096) - { - LDRB(INDEX_UNSIGNED, scratch1_reg, src_reg, m_src_ofs); - } - else - { - ADD(reg, src_reg, m_src_ofs); - LDRB(INDEX_UNSIGNED, scratch1_reg, reg, 0); - } - m_src_ofs += 1; - } - else - { - if (m_src_ofs < 256) - { - LDURH(scratch1_reg, src_reg, m_src_ofs); - } - else if (m_src_ofs <= 8190 && !(m_src_ofs & 1)) - { - LDRH(INDEX_UNSIGNED, scratch1_reg, src_reg, m_src_ofs); - } - else - { - ADD(reg, src_reg, m_src_ofs); - LDRH(INDEX_UNSIGNED, scratch1_reg, reg, 0); - } - m_src_ofs += 2; - REV16(scratch1_reg, scratch1_reg); - } + if (attribute & MASK_INDEXED) + { + if (attribute == INDEX8) + { + if (m_src_ofs < 4096) + { + LDRB(INDEX_UNSIGNED, scratch1_reg, src_reg, m_src_ofs); + } + else + { + ADD(reg, src_reg, m_src_ofs); + LDRB(INDEX_UNSIGNED, scratch1_reg, reg, 0); + } + m_src_ofs += 1; + } + else + { + if (m_src_ofs < 256) + { + LDURH(scratch1_reg, src_reg, m_src_ofs); + } + else if (m_src_ofs <= 8190 && !(m_src_ofs & 1)) + { + LDRH(INDEX_UNSIGNED, scratch1_reg, src_reg, m_src_ofs); + } + else + { + ADD(reg, src_reg, m_src_ofs); + LDRH(INDEX_UNSIGNED, scratch1_reg, reg, 0); + } + m_src_ofs += 2; + REV16(scratch1_reg, scratch1_reg); + } - if (array == ARRAY_POSITION) - { - EOR(scratch2_reg, scratch1_reg, 0, attribute == INDEX8 ? 7 : 15); // 0xFF : 0xFFFF - m_skip_vertex = CBZ(scratch2_reg); - } + if (array == ARRAY_POSITION) + { + EOR(scratch2_reg, scratch1_reg, 0, attribute == INDEX8 ? 7 : 15); // 0xFF : 0xFFFF + m_skip_vertex = CBZ(scratch2_reg); + } - LDR(INDEX_UNSIGNED, scratch2_reg, stride_reg, array * 4); - MUL(scratch1_reg, scratch1_reg, scratch2_reg); + LDR(INDEX_UNSIGNED, scratch2_reg, stride_reg, array * 4); + MUL(scratch1_reg, scratch1_reg, scratch2_reg); - LDR(INDEX_UNSIGNED, EncodeRegTo64(scratch2_reg), arraybase_reg, array * 8); - ADD(EncodeRegTo64(reg), EncodeRegTo64(scratch1_reg), EncodeRegTo64(scratch2_reg)); - } - else - ADD(reg, src_reg, m_src_ofs); + LDR(INDEX_UNSIGNED, EncodeRegTo64(scratch2_reg), arraybase_reg, array * 8); + ADD(EncodeRegTo64(reg), EncodeRegTo64(scratch1_reg), EncodeRegTo64(scratch2_reg)); + } + else + ADD(reg, src_reg, m_src_ofs); } s32 VertexLoaderARM64::GetAddressImm(int array, u64 attribute, Arm64Gen::ARM64Reg reg, u32 align) { - if (attribute & MASK_INDEXED || - (m_src_ofs > 255 && (m_src_ofs & (align - 1)))) - GetVertexAddr(array, attribute, reg); - else - return m_src_ofs; - return -1; + if (attribute & MASK_INDEXED || (m_src_ofs > 255 && (m_src_ofs & (align - 1)))) + GetVertexAddr(array, attribute, reg); + else + return m_src_ofs; + return -1; } -int VertexLoaderARM64::ReadVertex(u64 attribute, int format, int count_in, int count_out, bool dequantize, u8 scaling_exponent, AttributeFormat* native_format, s32 offset) +int VertexLoaderARM64::ReadVertex(u64 attribute, int format, int count_in, int count_out, + bool dequantize, u8 scaling_exponent, + AttributeFormat* native_format, s32 offset) { - ARM64Reg coords = count_in == 3 ? Q31 : D31; - ARM64Reg scale = count_in == 3 ? Q30 : D30; + ARM64Reg coords = count_in == 3 ? Q31 : D31; + ARM64Reg scale = count_in == 3 ? Q30 : D30; - int elem_size = 1 << (format / 2); - int load_bytes = elem_size * count_in; - int load_size = load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16; - load_size <<= 3; - elem_size <<= 3; + int elem_size = 1 << (format / 2); + int load_bytes = elem_size * count_in; + int load_size = + load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16; + load_size <<= 3; + elem_size <<= 3; - if (offset == -1) - { - if (count_in == 1) - m_float_emit.LDR(elem_size, INDEX_UNSIGNED, coords, EncodeRegTo64(scratch1_reg), 0); - else - m_float_emit.LD1(elem_size, 1, coords, EncodeRegTo64(scratch1_reg)); - } - else if (offset & (load_size - 1)) // Not aligned - unscaled - { - m_float_emit.LDUR(load_size, coords, src_reg, offset); - } - else - { - m_float_emit.LDR(load_size, INDEX_UNSIGNED, coords, src_reg, offset); - } + if (offset == -1) + { + if (count_in == 1) + m_float_emit.LDR(elem_size, INDEX_UNSIGNED, coords, EncodeRegTo64(scratch1_reg), 0); + else + m_float_emit.LD1(elem_size, 1, coords, EncodeRegTo64(scratch1_reg)); + } + else if (offset & (load_size - 1)) // Not aligned - unscaled + { + m_float_emit.LDUR(load_size, coords, src_reg, offset); + } + else + { + m_float_emit.LDR(load_size, INDEX_UNSIGNED, coords, src_reg, offset); + } - if (format != FORMAT_FLOAT) - { - // Extend and convert to float - switch (format) - { - case FORMAT_UBYTE: - m_float_emit.UXTL(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); - m_float_emit.UXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); - break; - case FORMAT_BYTE: - m_float_emit.SXTL(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); - m_float_emit.SXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); - break; - case FORMAT_USHORT: - m_float_emit.REV16(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); - m_float_emit.UXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); - break; - case FORMAT_SHORT: - m_float_emit.REV16(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); - m_float_emit.SXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); - break; - } + if (format != FORMAT_FLOAT) + { + // Extend and convert to float + switch (format) + { + case FORMAT_UBYTE: + m_float_emit.UXTL(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); + m_float_emit.UXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); + break; + case FORMAT_BYTE: + m_float_emit.SXTL(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); + m_float_emit.SXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); + break; + case FORMAT_USHORT: + m_float_emit.REV16(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); + m_float_emit.UXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); + break; + case FORMAT_SHORT: + m_float_emit.REV16(8, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); + m_float_emit.SXTL(16, EncodeRegToDouble(coords), EncodeRegToDouble(coords)); + break; + } - m_float_emit.SCVTF(32, coords, coords); + m_float_emit.SCVTF(32, coords, coords); - if (dequantize && scaling_exponent) - { - m_float_emit.LDR(32, INDEX_UNSIGNED, scale, scale_reg, scaling_exponent * 4); - m_float_emit.FMUL(32, coords, coords, scale, 0); - } - } - else - { - m_float_emit.REV32(8, coords, coords); - } + if (dequantize && scaling_exponent) + { + m_float_emit.LDR(32, INDEX_UNSIGNED, scale, scale_reg, scaling_exponent * 4); + m_float_emit.FMUL(32, coords, coords, scale, 0); + } + } + else + { + m_float_emit.REV32(8, coords, coords); + } - const u32 write_size = count_out == 3 ? 128 : count_out * 32; - const u32 mask = count_out == 3 ? 0xF : count_out == 2 ? 0x7 : 0x3; - if (m_dst_ofs < 256) - { - m_float_emit.STUR(write_size, coords, dst_reg, m_dst_ofs); - } - else if (!(m_dst_ofs & mask)) - { - m_float_emit.STR(write_size, INDEX_UNSIGNED, coords, dst_reg, m_dst_ofs); - } - else - { - ADD(EncodeRegTo64(scratch2_reg), dst_reg, m_dst_ofs); - m_float_emit.ST1(32, 1, coords, EncodeRegTo64(scratch2_reg)); - } + const u32 write_size = count_out == 3 ? 128 : count_out * 32; + const u32 mask = count_out == 3 ? 0xF : count_out == 2 ? 0x7 : 0x3; + if (m_dst_ofs < 256) + { + m_float_emit.STUR(write_size, coords, dst_reg, m_dst_ofs); + } + else if (!(m_dst_ofs & mask)) + { + m_float_emit.STR(write_size, INDEX_UNSIGNED, coords, dst_reg, m_dst_ofs); + } + else + { + ADD(EncodeRegTo64(scratch2_reg), dst_reg, m_dst_ofs); + m_float_emit.ST1(32, 1, coords, EncodeRegTo64(scratch2_reg)); + } - // Z-Freeze - if (native_format == &m_native_vtx_decl.position) - { - CMP(count_reg, 3); - FixupBranch dont_store = B(CC_GT); - MOVI2R(EncodeRegTo64(scratch2_reg), (u64)VertexLoaderManager::position_cache); - ADD(EncodeRegTo64(scratch1_reg), EncodeRegTo64(scratch2_reg), EncodeRegTo64(count_reg), ArithOption(EncodeRegTo64(count_reg), ST_LSL, 4)); - m_float_emit.STUR(write_size, coords, EncodeRegTo64(scratch1_reg), -16); - SetJumpTarget(dont_store); - } + // Z-Freeze + if (native_format == &m_native_vtx_decl.position) + { + CMP(count_reg, 3); + FixupBranch dont_store = B(CC_GT); + MOVI2R(EncodeRegTo64(scratch2_reg), (u64)VertexLoaderManager::position_cache); + ADD(EncodeRegTo64(scratch1_reg), EncodeRegTo64(scratch2_reg), EncodeRegTo64(count_reg), + ArithOption(EncodeRegTo64(count_reg), ST_LSL, 4)); + m_float_emit.STUR(write_size, coords, EncodeRegTo64(scratch1_reg), -16); + SetJumpTarget(dont_store); + } - native_format->components = count_out; - native_format->enable = true; - native_format->offset = m_dst_ofs; - native_format->type = VAR_FLOAT; - native_format->integer = false; - m_dst_ofs += sizeof(float) * count_out; + native_format->components = count_out; + native_format->enable = true; + native_format->offset = m_dst_ofs; + native_format->type = VAR_FLOAT; + native_format->integer = false; + m_dst_ofs += sizeof(float) * count_out; - if (attribute == DIRECT) - m_src_ofs += load_bytes; + if (attribute == DIRECT) + m_src_ofs += load_bytes; - return load_bytes; + return load_bytes; } void VertexLoaderARM64::ReadColor(u64 attribute, int format, s32 offset) { - int load_bytes = 0; - switch (format) - { - case FORMAT_24B_888: - case FORMAT_32B_888x: - case FORMAT_32B_8888: - if (offset == -1) - LDR(INDEX_UNSIGNED, scratch2_reg, EncodeRegTo64(scratch1_reg), 0); - else if (offset & 3) // Not aligned - unscaled - LDUR(scratch2_reg, src_reg, offset); - else - LDR(INDEX_UNSIGNED, scratch2_reg, src_reg, offset); + int load_bytes = 0; + switch (format) + { + case FORMAT_24B_888: + case FORMAT_32B_888x: + case FORMAT_32B_8888: + if (offset == -1) + LDR(INDEX_UNSIGNED, scratch2_reg, EncodeRegTo64(scratch1_reg), 0); + else if (offset & 3) // Not aligned - unscaled + LDUR(scratch2_reg, src_reg, offset); + else + LDR(INDEX_UNSIGNED, scratch2_reg, src_reg, offset); - if (format != FORMAT_32B_8888) - ORR(scratch2_reg, scratch2_reg, 8, 7); // 0xFF000000 - STR(INDEX_UNSIGNED, scratch2_reg, dst_reg, m_dst_ofs); - load_bytes = 3 + (format != FORMAT_24B_888); - break; + if (format != FORMAT_32B_8888) + ORR(scratch2_reg, scratch2_reg, 8, 7); // 0xFF000000 + STR(INDEX_UNSIGNED, scratch2_reg, dst_reg, m_dst_ofs); + load_bytes = 3 + (format != FORMAT_24B_888); + break; - case FORMAT_16B_565: - // RRRRRGGG GGGBBBBB - // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR - if (offset == -1) - LDRH(INDEX_UNSIGNED, scratch3_reg, EncodeRegTo64(scratch1_reg), 0); - else if (offset & 1) // Not aligned - unscaled - LDURH(scratch3_reg, src_reg, offset); - else - LDRH(INDEX_UNSIGNED, scratch3_reg, src_reg, offset); + case FORMAT_16B_565: + // RRRRRGGG GGGBBBBB + // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR + if (offset == -1) + LDRH(INDEX_UNSIGNED, scratch3_reg, EncodeRegTo64(scratch1_reg), 0); + else if (offset & 1) // Not aligned - unscaled + LDURH(scratch3_reg, src_reg, offset); + else + LDRH(INDEX_UNSIGNED, scratch3_reg, src_reg, offset); - REV16(scratch3_reg, scratch3_reg); + REV16(scratch3_reg, scratch3_reg); - // B - AND(scratch2_reg, scratch3_reg, 32, 4); - ORR(scratch2_reg, WSP, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 3)); - ORR(scratch2_reg, scratch2_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSR, 5)); - ORR(scratch1_reg, WSP, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 16)); + // B + AND(scratch2_reg, scratch3_reg, 32, 4); + ORR(scratch2_reg, WSP, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 3)); + ORR(scratch2_reg, scratch2_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSR, 5)); + ORR(scratch1_reg, WSP, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 16)); - // G - UBFM(scratch2_reg, scratch3_reg, 5, 10); - ORR(scratch2_reg, WSP, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 2)); - ORR(scratch2_reg, scratch2_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSR, 6)); - ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 8)); + // G + UBFM(scratch2_reg, scratch3_reg, 5, 10); + ORR(scratch2_reg, WSP, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 2)); + ORR(scratch2_reg, scratch2_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSR, 6)); + ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 8)); - // R - UBFM(scratch2_reg, scratch3_reg, 11, 15); - ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 3)); - ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSR, 2)); + // R + UBFM(scratch2_reg, scratch3_reg, 11, 15); + ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 3)); + ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSR, 2)); - // A - ORR(scratch2_reg, scratch2_reg, 8, 7); // 0xFF000000 + // A + ORR(scratch2_reg, scratch2_reg, 8, 7); // 0xFF000000 - STR(INDEX_UNSIGNED, scratch1_reg, dst_reg, m_dst_ofs); - load_bytes = 2; - break; + STR(INDEX_UNSIGNED, scratch1_reg, dst_reg, m_dst_ofs); + load_bytes = 2; + break; - case FORMAT_16B_4444: - // BBBBAAAA RRRRGGGG - // REV16 - RRRRGGGG BBBBAAAA - // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR - if (offset == -1) - LDRH(INDEX_UNSIGNED, scratch3_reg, EncodeRegTo64(scratch1_reg), 0); - else if (offset & 1) // Not aligned - unscaled - LDURH(scratch3_reg, src_reg, offset); - else - LDRH(INDEX_UNSIGNED, scratch3_reg, src_reg, offset); + case FORMAT_16B_4444: + // BBBBAAAA RRRRGGGG + // REV16 - RRRRGGGG BBBBAAAA + // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR + if (offset == -1) + LDRH(INDEX_UNSIGNED, scratch3_reg, EncodeRegTo64(scratch1_reg), 0); + else if (offset & 1) // Not aligned - unscaled + LDURH(scratch3_reg, src_reg, offset); + else + LDRH(INDEX_UNSIGNED, scratch3_reg, src_reg, offset); - // R - UBFM(scratch1_reg, scratch3_reg, 4, 7); + // R + UBFM(scratch1_reg, scratch3_reg, 4, 7); - // G - AND(scratch2_reg, scratch3_reg, 32, 3); - ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 8)); + // G + AND(scratch2_reg, scratch3_reg, 32, 3); + ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 8)); - // B - UBFM(scratch2_reg, scratch3_reg, 12, 15); - ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 16)); + // B + UBFM(scratch2_reg, scratch3_reg, 12, 15); + ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 16)); - // A - UBFM(scratch2_reg, scratch3_reg, 8, 11); - ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 24)); + // A + UBFM(scratch2_reg, scratch3_reg, 8, 11); + ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 24)); - // Final duplication - ORR(scratch1_reg, scratch1_reg, scratch1_reg, ArithOption(scratch1_reg, ST_LSL, 4)); + // Final duplication + ORR(scratch1_reg, scratch1_reg, scratch1_reg, ArithOption(scratch1_reg, ST_LSL, 4)); - STR(INDEX_UNSIGNED, scratch1_reg, dst_reg, m_dst_ofs); - load_bytes = 2; - break; + STR(INDEX_UNSIGNED, scratch1_reg, dst_reg, m_dst_ofs); + load_bytes = 2; + break; - case FORMAT_24B_6666: - // RRRRRRGG GGGGBBBB BBAAAAAA - // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR - if (offset == -1) - { - LDUR(scratch3_reg, EncodeRegTo64(scratch1_reg), -1); - } - else - { - offset -= 1; - if (offset & 3) // Not aligned - unscaled - LDUR(scratch3_reg, src_reg, offset); - else - LDR(INDEX_UNSIGNED, scratch3_reg, src_reg, offset); - } + case FORMAT_24B_6666: + // RRRRRRGG GGGGBBBB BBAAAAAA + // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR + if (offset == -1) + { + LDUR(scratch3_reg, EncodeRegTo64(scratch1_reg), -1); + } + else + { + offset -= 1; + if (offset & 3) // Not aligned - unscaled + LDUR(scratch3_reg, src_reg, offset); + else + LDR(INDEX_UNSIGNED, scratch3_reg, src_reg, offset); + } - REV32(scratch3_reg, scratch3_reg); + REV32(scratch3_reg, scratch3_reg); - // A - UBFM(scratch2_reg, scratch3_reg, 0, 5); - ORR(scratch2_reg, WSP, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 2)); - ORR(scratch2_reg, scratch2_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSR, 6)); - ORR(scratch1_reg, WSP, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 24)); + // A + UBFM(scratch2_reg, scratch3_reg, 0, 5); + ORR(scratch2_reg, WSP, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 2)); + ORR(scratch2_reg, scratch2_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSR, 6)); + ORR(scratch1_reg, WSP, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 24)); - // B - UBFM(scratch2_reg, scratch3_reg, 6, 11); - ORR(scratch2_reg, WSP, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 2)); - ORR(scratch2_reg, scratch2_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSR, 6)); - ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 16)); + // B + UBFM(scratch2_reg, scratch3_reg, 6, 11); + ORR(scratch2_reg, WSP, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 2)); + ORR(scratch2_reg, scratch2_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSR, 6)); + ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 16)); - // G - UBFM(scratch2_reg, scratch3_reg, 12, 17); - ORR(scratch2_reg, WSP, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 2)); - ORR(scratch2_reg, scratch2_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSR, 6)); - ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 8)); + // G + UBFM(scratch2_reg, scratch3_reg, 12, 17); + ORR(scratch2_reg, WSP, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 2)); + ORR(scratch2_reg, scratch2_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSR, 6)); + ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 8)); - // R - UBFM(scratch2_reg, scratch3_reg, 18, 23); - ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 2)); - ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSR, 4)); + // R + UBFM(scratch2_reg, scratch3_reg, 18, 23); + ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSL, 2)); + ORR(scratch1_reg, scratch1_reg, scratch2_reg, ArithOption(scratch2_reg, ST_LSR, 4)); - STR(INDEX_UNSIGNED, scratch1_reg, dst_reg, m_dst_ofs); + STR(INDEX_UNSIGNED, scratch1_reg, dst_reg, m_dst_ofs); - load_bytes = 3; - break; - } - if (attribute == DIRECT) - m_src_ofs += load_bytes; + load_bytes = 3; + break; + } + if (attribute == DIRECT) + m_src_ofs += load_bytes; } void VertexLoaderARM64::GenerateVertexLoader() { - // R0 - Source pointer - // R1 - Destination pointer - // R2 - Count - // R30 - LR - // - // R0 return how many - // - // Registers we don't have to worry about saving - // R9-R17 are caller saved temporaries - // R18 is a temporary or platform specific register(iOS) - // - // VFP registers - // We can touch all except v8-v15 - // If we need to use those, we need to retain the lower 64bits(!) of the register + // R0 - Source pointer + // R1 - Destination pointer + // R2 - Count + // R30 - LR + // + // R0 return how many + // + // Registers we don't have to worry about saving + // R9-R17 are caller saved temporaries + // R18 is a temporary or platform specific register(iOS) + // + // VFP registers + // We can touch all except v8-v15 + // If we need to use those, we need to retain the lower 64bits(!) of the register - const u64 tc[8] = { - m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord, m_VtxDesc.Tex3Coord, - m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, m_VtxDesc.Tex6Coord, m_VtxDesc.Tex7Coord, - }; + const u64 tc[8] = { + m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord, m_VtxDesc.Tex3Coord, + m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, m_VtxDesc.Tex6Coord, m_VtxDesc.Tex7Coord, + }; - bool has_tc = false; - bool has_tc_scale = false; - for (int i = 0; i < 8; i++) - { - has_tc |= tc[i]; - has_tc_scale |= !!m_VtxAttr.texCoord[i].Frac; - } + bool has_tc = false; + bool has_tc_scale = false; + for (int i = 0; i < 8; i++) + { + has_tc |= tc[i]; + has_tc_scale |= !!m_VtxAttr.texCoord[i].Frac; + } - bool need_scale = (m_VtxAttr.ByteDequant && m_VtxAttr.PosFrac) || - (has_tc && has_tc_scale) || - m_VtxDesc.Normal; + bool need_scale = + (m_VtxAttr.ByteDequant && m_VtxAttr.PosFrac) || (has_tc && has_tc_scale) || m_VtxDesc.Normal; - AlignCode16(); - if (m_VtxDesc.Position & MASK_INDEXED) - MOV(skipped_reg, WZR); - MOV(saved_count, count_reg); + AlignCode16(); + if (m_VtxDesc.Position & MASK_INDEXED) + MOV(skipped_reg, WZR); + MOV(saved_count, count_reg); - MOVI2R(stride_reg, (u64)&g_main_cp_state.array_strides); - MOVI2R(arraybase_reg, (u64)&VertexLoaderManager::cached_arraybases); + MOVI2R(stride_reg, (u64)&g_main_cp_state.array_strides); + MOVI2R(arraybase_reg, (u64)&VertexLoaderManager::cached_arraybases); - if (need_scale) - MOVI2R(scale_reg, (u64)&scale_factors); + if (need_scale) + MOVI2R(scale_reg, (u64)&scale_factors); - const u8* loop_start = GetCodePtr(); + const u8* loop_start = GetCodePtr(); - if (m_VtxDesc.PosMatIdx) - { - LDRB(INDEX_UNSIGNED, scratch1_reg, src_reg, m_src_ofs); - AND(scratch1_reg, scratch1_reg, 0, 5); - STR(INDEX_UNSIGNED, scratch1_reg, dst_reg, m_dst_ofs); + if (m_VtxDesc.PosMatIdx) + { + LDRB(INDEX_UNSIGNED, scratch1_reg, src_reg, m_src_ofs); + AND(scratch1_reg, scratch1_reg, 0, 5); + STR(INDEX_UNSIGNED, scratch1_reg, dst_reg, m_dst_ofs); - // Z-Freeze - CMP(count_reg, 3); - FixupBranch dont_store = B(CC_GT); - MOVI2R(EncodeRegTo64(scratch2_reg), (u64)VertexLoaderManager::position_matrix_index - sizeof(u32)); - STR(INDEX_UNSIGNED, scratch1_reg, EncodeRegTo64(scratch2_reg), 0); - SetJumpTarget(dont_store); + // Z-Freeze + CMP(count_reg, 3); + FixupBranch dont_store = B(CC_GT); + MOVI2R(EncodeRegTo64(scratch2_reg), + (u64)VertexLoaderManager::position_matrix_index - sizeof(u32)); + STR(INDEX_UNSIGNED, scratch1_reg, EncodeRegTo64(scratch2_reg), 0); + SetJumpTarget(dont_store); - m_native_components |= VB_HAS_POSMTXIDX; - m_native_vtx_decl.posmtx.components = 4; - m_native_vtx_decl.posmtx.enable = true; - m_native_vtx_decl.posmtx.offset = m_dst_ofs; - m_native_vtx_decl.posmtx.type = VAR_UNSIGNED_BYTE; - m_native_vtx_decl.posmtx.integer = true; - m_src_ofs += sizeof(u8); - m_dst_ofs += sizeof(u32); - } + m_native_components |= VB_HAS_POSMTXIDX; + m_native_vtx_decl.posmtx.components = 4; + m_native_vtx_decl.posmtx.enable = true; + m_native_vtx_decl.posmtx.offset = m_dst_ofs; + m_native_vtx_decl.posmtx.type = VAR_UNSIGNED_BYTE; + m_native_vtx_decl.posmtx.integer = true; + m_src_ofs += sizeof(u8); + m_dst_ofs += sizeof(u32); + } - u32 texmatidx_ofs[8]; - const u64 tm[8] = { - m_VtxDesc.Tex0MatIdx, m_VtxDesc.Tex1MatIdx, m_VtxDesc.Tex2MatIdx, m_VtxDesc.Tex3MatIdx, - m_VtxDesc.Tex4MatIdx, m_VtxDesc.Tex5MatIdx, m_VtxDesc.Tex6MatIdx, m_VtxDesc.Tex7MatIdx, - }; - for (int i = 0; i < 8; i++) - { - if (tm[i]) - texmatidx_ofs[i] = m_src_ofs++; - } + u32 texmatidx_ofs[8]; + const u64 tm[8] = { + m_VtxDesc.Tex0MatIdx, m_VtxDesc.Tex1MatIdx, m_VtxDesc.Tex2MatIdx, m_VtxDesc.Tex3MatIdx, + m_VtxDesc.Tex4MatIdx, m_VtxDesc.Tex5MatIdx, m_VtxDesc.Tex6MatIdx, m_VtxDesc.Tex7MatIdx, + }; + for (int i = 0; i < 8; i++) + { + if (tm[i]) + texmatidx_ofs[i] = m_src_ofs++; + } - // Position - { - int elem_size = 1 << (m_VtxAttr.PosFormat / 2); - int load_bytes = elem_size * (m_VtxAttr.PosElements + 2); - int load_size = load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16; - load_size <<= 3; + // Position + { + int elem_size = 1 << (m_VtxAttr.PosFormat / 2); + int load_bytes = elem_size * (m_VtxAttr.PosElements + 2); + int load_size = + load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16; + load_size <<= 3; - s32 offset = GetAddressImm(ARRAY_POSITION, m_VtxDesc.Position, EncodeRegTo64(scratch1_reg), load_size); - int pos_elements = m_VtxAttr.PosElements + 2; - ReadVertex(m_VtxDesc.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements, - m_VtxAttr.ByteDequant, m_VtxAttr.PosFrac, &m_native_vtx_decl.position, offset); - } + s32 offset = + GetAddressImm(ARRAY_POSITION, m_VtxDesc.Position, EncodeRegTo64(scratch1_reg), load_size); + int pos_elements = m_VtxAttr.PosElements + 2; + ReadVertex(m_VtxDesc.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements, + m_VtxAttr.ByteDequant, m_VtxAttr.PosFrac, &m_native_vtx_decl.position, offset); + } - if (m_VtxDesc.Normal) - { - static const u8 map[8] = {7, 6, 15, 14}; - u8 scaling_exponent = map[m_VtxAttr.NormalFormat]; + if (m_VtxDesc.Normal) + { + static const u8 map[8] = {7, 6, 15, 14}; + u8 scaling_exponent = map[m_VtxAttr.NormalFormat]; - s32 offset = -1; - for (int i = 0; i < (m_VtxAttr.NormalElements ? 3 : 1); i++) - { - if (!i || m_VtxAttr.NormalIndex3) - { - int elem_size = 1 << (m_VtxAttr.NormalFormat / 2); + s32 offset = -1; + for (int i = 0; i < (m_VtxAttr.NormalElements ? 3 : 1); i++) + { + if (!i || m_VtxAttr.NormalIndex3) + { + int elem_size = 1 << (m_VtxAttr.NormalFormat / 2); - int load_bytes = elem_size * 3; - int load_size = load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16; + int load_bytes = elem_size * 3; + int load_size = load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? + 4 : + load_bytes <= 8 ? 8 : 16; - offset = GetAddressImm(ARRAY_NORMAL, m_VtxDesc.Normal, EncodeRegTo64(scratch1_reg), load_size << 3); + offset = GetAddressImm(ARRAY_NORMAL, m_VtxDesc.Normal, EncodeRegTo64(scratch1_reg), + load_size << 3); - if (offset == -1) - ADD(EncodeRegTo64(scratch1_reg), EncodeRegTo64(scratch1_reg), i * elem_size * 3); - else - offset += i * elem_size * 3; - } - int bytes_read = ReadVertex(m_VtxDesc.Normal, m_VtxAttr.NormalFormat, 3, 3, - true, scaling_exponent, &m_native_vtx_decl.normals[i], offset); + if (offset == -1) + ADD(EncodeRegTo64(scratch1_reg), EncodeRegTo64(scratch1_reg), i * elem_size * 3); + else + offset += i * elem_size * 3; + } + int bytes_read = ReadVertex(m_VtxDesc.Normal, m_VtxAttr.NormalFormat, 3, 3, true, + scaling_exponent, &m_native_vtx_decl.normals[i], offset); - if (offset == -1) - ADD(EncodeRegTo64(scratch1_reg), EncodeRegTo64(scratch1_reg), bytes_read); - else - offset += bytes_read; - } + if (offset == -1) + ADD(EncodeRegTo64(scratch1_reg), EncodeRegTo64(scratch1_reg), bytes_read); + else + offset += bytes_read; + } - m_native_components |= VB_HAS_NRM0; - if (m_VtxAttr.NormalElements) - m_native_components |= VB_HAS_NRM1 | VB_HAS_NRM2; - } + m_native_components |= VB_HAS_NRM0; + if (m_VtxAttr.NormalElements) + m_native_components |= VB_HAS_NRM1 | VB_HAS_NRM2; + } - const u64 col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1}; - for (int i = 0; i < 2; i++) - { - m_native_vtx_decl.colors[i].components = 4; - m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE; - m_native_vtx_decl.colors[i].integer = false; + const u64 col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1}; + for (int i = 0; i < 2; i++) + { + m_native_vtx_decl.colors[i].components = 4; + m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE; + m_native_vtx_decl.colors[i].integer = false; - if (col[i]) - { - u32 align = 4; - if (m_VtxAttr.color[i].Comp == FORMAT_16B_565 || - m_VtxAttr.color[i].Comp == FORMAT_16B_4444) - align = 2; + if (col[i]) + { + u32 align = 4; + if (m_VtxAttr.color[i].Comp == FORMAT_16B_565 || m_VtxAttr.color[i].Comp == FORMAT_16B_4444) + align = 2; - s32 offset = GetAddressImm(ARRAY_COLOR + i, col[i], EncodeRegTo64(scratch1_reg), align); - ReadColor(col[i], m_VtxAttr.color[i].Comp, offset); - m_native_components |= VB_HAS_COL0 << i; - m_native_vtx_decl.colors[i].components = 4; - m_native_vtx_decl.colors[i].enable = true; - m_native_vtx_decl.colors[i].offset = m_dst_ofs; - m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE; - m_native_vtx_decl.colors[i].integer = false; - m_dst_ofs += 4; - } - } + s32 offset = GetAddressImm(ARRAY_COLOR + i, col[i], EncodeRegTo64(scratch1_reg), align); + ReadColor(col[i], m_VtxAttr.color[i].Comp, offset); + m_native_components |= VB_HAS_COL0 << i; + m_native_vtx_decl.colors[i].components = 4; + m_native_vtx_decl.colors[i].enable = true; + m_native_vtx_decl.colors[i].offset = m_dst_ofs; + m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE; + m_native_vtx_decl.colors[i].integer = false; + m_dst_ofs += 4; + } + } + for (int i = 0; i < 8; i++) + { + m_native_vtx_decl.texcoords[i].offset = m_dst_ofs; + m_native_vtx_decl.texcoords[i].type = VAR_FLOAT; + m_native_vtx_decl.texcoords[i].integer = false; + int elements = m_VtxAttr.texCoord[i].Elements + 1; + if (tc[i]) + { + m_native_components |= VB_HAS_UV0 << i; - for (int i = 0; i < 8; i++) - { - m_native_vtx_decl.texcoords[i].offset = m_dst_ofs; - m_native_vtx_decl.texcoords[i].type = VAR_FLOAT; - m_native_vtx_decl.texcoords[i].integer = false; + int elem_size = 1 << (m_VtxAttr.texCoord[i].Format / 2); + int load_bytes = elem_size * (elements + 2); + int load_size = load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? + 4 : + load_bytes <= 8 ? 8 : 16; + load_size <<= 3; - int elements = m_VtxAttr.texCoord[i].Elements + 1; - if (tc[i]) - { - m_native_components |= VB_HAS_UV0 << i; + s32 offset = + GetAddressImm(ARRAY_TEXCOORD0 + i, tc[i], EncodeRegTo64(scratch1_reg), load_size); + u8 scaling_exponent = m_VtxAttr.texCoord[i].Frac; + ReadVertex(tc[i], m_VtxAttr.texCoord[i].Format, elements, tm[i] ? 2 : elements, + m_VtxAttr.ByteDequant, scaling_exponent, &m_native_vtx_decl.texcoords[i], offset); + } + if (tm[i]) + { + m_native_components |= VB_HAS_TEXMTXIDX0 << i; + m_native_vtx_decl.texcoords[i].components = 3; + m_native_vtx_decl.texcoords[i].enable = true; + m_native_vtx_decl.texcoords[i].type = VAR_FLOAT; + m_native_vtx_decl.texcoords[i].integer = false; - int elem_size = 1 << (m_VtxAttr.texCoord[i].Format / 2); - int load_bytes = elem_size * (elements + 2); - int load_size = load_bytes == 1 ? 1 : load_bytes <= 2 ? 2 : load_bytes <= 4 ? 4 : load_bytes <= 8 ? 8 : 16; - load_size <<= 3; + LDRB(INDEX_UNSIGNED, scratch2_reg, src_reg, texmatidx_ofs[i]); + m_float_emit.UCVTF(S31, scratch2_reg); - s32 offset = GetAddressImm(ARRAY_TEXCOORD0 + i, tc[i], EncodeRegTo64(scratch1_reg), load_size); - u8 scaling_exponent = m_VtxAttr.texCoord[i].Frac; - ReadVertex(tc[i], m_VtxAttr.texCoord[i].Format, elements, tm[i] ? 2 : elements, - m_VtxAttr.ByteDequant, scaling_exponent, &m_native_vtx_decl.texcoords[i], offset); - } - if (tm[i]) - { - m_native_components |= VB_HAS_TEXMTXIDX0 << i; - m_native_vtx_decl.texcoords[i].components = 3; - m_native_vtx_decl.texcoords[i].enable = true; - m_native_vtx_decl.texcoords[i].type = VAR_FLOAT; - m_native_vtx_decl.texcoords[i].integer = false; + if (tc[i]) + { + m_float_emit.STR(32, INDEX_UNSIGNED, D31, dst_reg, m_dst_ofs); + m_dst_ofs += sizeof(float); + } + else + { + m_native_vtx_decl.texcoords[i].offset = m_dst_ofs; - LDRB(INDEX_UNSIGNED, scratch2_reg, src_reg, texmatidx_ofs[i]); - m_float_emit.UCVTF(S31, scratch2_reg); + if (m_dst_ofs < 256) + { + STUR(SP, dst_reg, m_dst_ofs); + } + else if (!(m_dst_ofs & 7)) + { + // If m_dst_ofs isn't 8byte aligned we can't store an 8byte zero register + // So store two 4byte zero registers + // The destination is always 4byte aligned + STR(INDEX_UNSIGNED, WSP, dst_reg, m_dst_ofs); + STR(INDEX_UNSIGNED, WSP, dst_reg, m_dst_ofs + 4); + } + else + { + STR(INDEX_UNSIGNED, SP, dst_reg, m_dst_ofs); + } + m_float_emit.STR(32, INDEX_UNSIGNED, D31, dst_reg, m_dst_ofs + 8); - if (tc[i]) - { - m_float_emit.STR(32, INDEX_UNSIGNED, D31, dst_reg, m_dst_ofs); - m_dst_ofs += sizeof(float); - } - else - { - m_native_vtx_decl.texcoords[i].offset = m_dst_ofs; + m_dst_ofs += sizeof(float) * 3; + } + } + } - if (m_dst_ofs < 256) - { - STUR(SP, dst_reg, m_dst_ofs); - } - else if (!(m_dst_ofs & 7)) - { - // If m_dst_ofs isn't 8byte aligned we can't store an 8byte zero register - // So store two 4byte zero registers - // The destination is always 4byte aligned - STR(INDEX_UNSIGNED, WSP, dst_reg, m_dst_ofs); - STR(INDEX_UNSIGNED, WSP, dst_reg, m_dst_ofs + 4); - } - else - { - STR(INDEX_UNSIGNED, SP, dst_reg, m_dst_ofs); - } - m_float_emit.STR(32, INDEX_UNSIGNED, D31, dst_reg, m_dst_ofs + 8); + // Prepare for the next vertex. + ADD(dst_reg, dst_reg, m_dst_ofs); + const u8* cont = GetCodePtr(); + ADD(src_reg, src_reg, m_src_ofs); - m_dst_ofs += sizeof(float) * 3; - } - } - } + SUB(count_reg, count_reg, 1); + CBNZ(count_reg, loop_start); - // Prepare for the next vertex. - ADD(dst_reg, dst_reg, m_dst_ofs); - const u8* cont = GetCodePtr(); - ADD(src_reg, src_reg, m_src_ofs); + if (m_VtxDesc.Position & MASK_INDEXED) + { + SUB(W0, saved_count, skipped_reg); + RET(X30); - SUB(count_reg, count_reg, 1); - CBNZ(count_reg, loop_start); + SetJumpTarget(m_skip_vertex); + ADD(skipped_reg, skipped_reg, 1); + B(cont); + } + else + { + MOV(W0, saved_count); + RET(X30); + } - if (m_VtxDesc.Position & MASK_INDEXED) - { - SUB(W0, saved_count, skipped_reg); - RET(X30); + FlushIcache(); - SetJumpTarget(m_skip_vertex); - ADD(skipped_reg, skipped_reg, 1); - B(cont); - } - else - { - MOV(W0, saved_count); - RET(X30); - } - - FlushIcache(); - - m_VertexSize = m_src_ofs; - m_native_vtx_decl.stride = m_dst_ofs; + m_VertexSize = m_src_ofs; + m_native_vtx_decl.stride = m_dst_ofs; } int VertexLoaderARM64::RunVertices(DataReader src, DataReader dst, int count) { - m_numLoadedVertices += count; - return ((int (*)(u8* src, u8* dst, int count))region)(src.GetPointer(), dst.GetPointer(), count); + m_numLoadedVertices += count; + return ((int (*)(u8 * src, u8 * dst, int count))region)(src.GetPointer(), dst.GetPointer(), + count); } diff --git a/Source/Core/VideoCommon/VertexLoaderARM64.h b/Source/Core/VideoCommon/VertexLoaderARM64.h index 9adff8372f..3df60a9685 100644 --- a/Source/Core/VideoCommon/VertexLoaderARM64.h +++ b/Source/Core/VideoCommon/VertexLoaderARM64.h @@ -13,21 +13,22 @@ class DataReader; class VertexLoaderARM64 : public VertexLoaderBase, public Arm64Gen::ARM64CodeBlock { public: - VertexLoaderARM64(const TVtxDesc& vtx_desc, const VAT& vtx_att); + VertexLoaderARM64(const TVtxDesc& vtx_desc, const VAT& vtx_att); protected: - std::string GetName() const override { return "VertexLoaderARM64"; } - bool IsInitialized() override { return true; } - int RunVertices(DataReader src, DataReader dst, int count) override; + std::string GetName() const override { return "VertexLoaderARM64"; } + bool IsInitialized() override { return true; } + int RunVertices(DataReader src, DataReader dst, int count) override; private: - u32 m_src_ofs = 0; - u32 m_dst_ofs = 0; - Arm64Gen::FixupBranch m_skip_vertex; - Arm64Gen::ARM64FloatEmitter m_float_emit; - void GetVertexAddr(int array, u64 attribute, Arm64Gen::ARM64Reg reg); - s32 GetAddressImm(int array, u64 attribute, Arm64Gen::ARM64Reg reg, u32 align); - int ReadVertex(u64 attribute, int format, int count_in, int count_out, bool dequantize, u8 scaling_exponent, AttributeFormat* native_format, s32 offset = -1); - void ReadColor(u64 attribute, int format, s32 offset); - void GenerateVertexLoader(); + u32 m_src_ofs = 0; + u32 m_dst_ofs = 0; + Arm64Gen::FixupBranch m_skip_vertex; + Arm64Gen::ARM64FloatEmitter m_float_emit; + void GetVertexAddr(int array, u64 attribute, Arm64Gen::ARM64Reg reg); + s32 GetAddressImm(int array, u64 attribute, Arm64Gen::ARM64Reg reg, u32 align); + int ReadVertex(u64 attribute, int format, int count_in, int count_out, bool dequantize, + u8 scaling_exponent, AttributeFormat* native_format, s32 offset = -1); + void ReadColor(u64 attribute, int format, s32 offset); + void GenerateVertexLoader(); }; diff --git a/Source/Core/VideoCommon/VertexLoaderBase.cpp b/Source/Core/VideoCommon/VertexLoaderBase.cpp index e6bc8d1b4d..0975b2c172 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.cpp +++ b/Source/Core/VideoCommon/VertexLoaderBase.cpp @@ -9,9 +9,9 @@ #include #include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" -#include "Common/Logging/Log.h" #include "VideoCommon/DataReader.h" #include "VideoCommon/VertexLoader.h" @@ -23,210 +23,211 @@ #include "VideoCommon/VertexLoaderARM64.h" #endif -VertexLoaderBase::VertexLoaderBase(const TVtxDesc &vtx_desc, const VAT &vtx_attr) +VertexLoaderBase::VertexLoaderBase(const TVtxDesc& vtx_desc, const VAT& vtx_attr) { - m_numLoadedVertices = 0; - m_VertexSize = 0; - m_native_vertex_format = nullptr; - m_native_components = 0; - memset(&m_native_vtx_decl, 0, sizeof(m_native_vtx_decl)); + m_numLoadedVertices = 0; + m_VertexSize = 0; + m_native_vertex_format = nullptr; + m_native_components = 0; + memset(&m_native_vtx_decl, 0, sizeof(m_native_vtx_decl)); - SetVAT(vtx_attr); - m_VtxDesc = vtx_desc; - m_vat = vtx_attr; + SetVAT(vtx_attr); + m_VtxDesc = vtx_desc; + m_vat = vtx_attr; } void VertexLoaderBase::SetVAT(const VAT& vat) { - m_VtxAttr.PosElements = vat.g0.PosElements; - m_VtxAttr.PosFormat = vat.g0.PosFormat; - m_VtxAttr.PosFrac = vat.g0.PosFrac; - m_VtxAttr.NormalElements = vat.g0.NormalElements; - m_VtxAttr.NormalFormat = vat.g0.NormalFormat; - m_VtxAttr.color[0].Elements = vat.g0.Color0Elements; - m_VtxAttr.color[0].Comp = vat.g0.Color0Comp; - m_VtxAttr.color[1].Elements = vat.g0.Color1Elements; - m_VtxAttr.color[1].Comp = vat.g0.Color1Comp; - m_VtxAttr.texCoord[0].Elements = vat.g0.Tex0CoordElements; - m_VtxAttr.texCoord[0].Format = vat.g0.Tex0CoordFormat; - m_VtxAttr.texCoord[0].Frac = vat.g0.Tex0Frac; - m_VtxAttr.ByteDequant = vat.g0.ByteDequant; - m_VtxAttr.NormalIndex3 = vat.g0.NormalIndex3; + m_VtxAttr.PosElements = vat.g0.PosElements; + m_VtxAttr.PosFormat = vat.g0.PosFormat; + m_VtxAttr.PosFrac = vat.g0.PosFrac; + m_VtxAttr.NormalElements = vat.g0.NormalElements; + m_VtxAttr.NormalFormat = vat.g0.NormalFormat; + m_VtxAttr.color[0].Elements = vat.g0.Color0Elements; + m_VtxAttr.color[0].Comp = vat.g0.Color0Comp; + m_VtxAttr.color[1].Elements = vat.g0.Color1Elements; + m_VtxAttr.color[1].Comp = vat.g0.Color1Comp; + m_VtxAttr.texCoord[0].Elements = vat.g0.Tex0CoordElements; + m_VtxAttr.texCoord[0].Format = vat.g0.Tex0CoordFormat; + m_VtxAttr.texCoord[0].Frac = vat.g0.Tex0Frac; + m_VtxAttr.ByteDequant = vat.g0.ByteDequant; + m_VtxAttr.NormalIndex3 = vat.g0.NormalIndex3; - m_VtxAttr.texCoord[1].Elements = vat.g1.Tex1CoordElements; - m_VtxAttr.texCoord[1].Format = vat.g1.Tex1CoordFormat; - m_VtxAttr.texCoord[1].Frac = vat.g1.Tex1Frac; - m_VtxAttr.texCoord[2].Elements = vat.g1.Tex2CoordElements; - m_VtxAttr.texCoord[2].Format = vat.g1.Tex2CoordFormat; - m_VtxAttr.texCoord[2].Frac = vat.g1.Tex2Frac; - m_VtxAttr.texCoord[3].Elements = vat.g1.Tex3CoordElements; - m_VtxAttr.texCoord[3].Format = vat.g1.Tex3CoordFormat; - m_VtxAttr.texCoord[3].Frac = vat.g1.Tex3Frac; - m_VtxAttr.texCoord[4].Elements = vat.g1.Tex4CoordElements; - m_VtxAttr.texCoord[4].Format = vat.g1.Tex4CoordFormat; + m_VtxAttr.texCoord[1].Elements = vat.g1.Tex1CoordElements; + m_VtxAttr.texCoord[1].Format = vat.g1.Tex1CoordFormat; + m_VtxAttr.texCoord[1].Frac = vat.g1.Tex1Frac; + m_VtxAttr.texCoord[2].Elements = vat.g1.Tex2CoordElements; + m_VtxAttr.texCoord[2].Format = vat.g1.Tex2CoordFormat; + m_VtxAttr.texCoord[2].Frac = vat.g1.Tex2Frac; + m_VtxAttr.texCoord[3].Elements = vat.g1.Tex3CoordElements; + m_VtxAttr.texCoord[3].Format = vat.g1.Tex3CoordFormat; + m_VtxAttr.texCoord[3].Frac = vat.g1.Tex3Frac; + m_VtxAttr.texCoord[4].Elements = vat.g1.Tex4CoordElements; + m_VtxAttr.texCoord[4].Format = vat.g1.Tex4CoordFormat; - m_VtxAttr.texCoord[4].Frac = vat.g2.Tex4Frac; - m_VtxAttr.texCoord[5].Elements = vat.g2.Tex5CoordElements; - m_VtxAttr.texCoord[5].Format = vat.g2.Tex5CoordFormat; - m_VtxAttr.texCoord[5].Frac = vat.g2.Tex5Frac; - m_VtxAttr.texCoord[6].Elements = vat.g2.Tex6CoordElements; - m_VtxAttr.texCoord[6].Format = vat.g2.Tex6CoordFormat; - m_VtxAttr.texCoord[6].Frac = vat.g2.Tex6Frac; - m_VtxAttr.texCoord[7].Elements = vat.g2.Tex7CoordElements; - m_VtxAttr.texCoord[7].Format = vat.g2.Tex7CoordFormat; - m_VtxAttr.texCoord[7].Frac = vat.g2.Tex7Frac; + m_VtxAttr.texCoord[4].Frac = vat.g2.Tex4Frac; + m_VtxAttr.texCoord[5].Elements = vat.g2.Tex5CoordElements; + m_VtxAttr.texCoord[5].Format = vat.g2.Tex5CoordFormat; + m_VtxAttr.texCoord[5].Frac = vat.g2.Tex5Frac; + m_VtxAttr.texCoord[6].Elements = vat.g2.Tex6CoordElements; + m_VtxAttr.texCoord[6].Format = vat.g2.Tex6CoordFormat; + m_VtxAttr.texCoord[6].Frac = vat.g2.Tex6Frac; + m_VtxAttr.texCoord[7].Elements = vat.g2.Tex7CoordElements; + m_VtxAttr.texCoord[7].Format = vat.g2.Tex7CoordFormat; + m_VtxAttr.texCoord[7].Frac = vat.g2.Tex7Frac; }; -void VertexLoaderBase::AppendToString(std::string *dest) const +void VertexLoaderBase::AppendToString(std::string* dest) const { - dest->reserve(250); + dest->reserve(250); - dest->append(GetName()); - dest->append(": "); + dest->append(GetName()); + dest->append(": "); - static const char *posMode[4] = { - "Inv", - "Dir", "I8", "I16", - }; - static const char *posFormats[8] = { - "u8", "s8", "u16", "s16", "flt", - "Inv", "Inv", "Inv", - }; - static const char *colorFormat[8] = { - "565", "888", "888x", "4444", "6666", "8888", - "Inv", "Inv", - }; + static const char* posMode[4] = { + "Inv", "Dir", "I8", "I16", + }; + static const char* posFormats[8] = { + "u8", "s8", "u16", "s16", "flt", "Inv", "Inv", "Inv", + }; + static const char* colorFormat[8] = { + "565", "888", "888x", "4444", "6666", "8888", "Inv", "Inv", + }; - dest->append(StringFromFormat("%ib skin: %i P: %i %s-%s ", - m_VertexSize, (u32)m_VtxDesc.PosMatIdx, - m_VtxAttr.PosElements ? 3 : 2, posMode[m_VtxDesc.Position], posFormats[m_VtxAttr.PosFormat])); + dest->append(StringFromFormat("%ib skin: %i P: %i %s-%s ", m_VertexSize, (u32)m_VtxDesc.PosMatIdx, + m_VtxAttr.PosElements ? 3 : 2, posMode[m_VtxDesc.Position], + posFormats[m_VtxAttr.PosFormat])); - if (m_VtxDesc.Normal) - { - dest->append(StringFromFormat("Nrm: %i %s-%s ", - m_VtxAttr.NormalElements, posMode[m_VtxDesc.Normal], posFormats[m_VtxAttr.NormalFormat])); - } + if (m_VtxDesc.Normal) + { + dest->append(StringFromFormat("Nrm: %i %s-%s ", m_VtxAttr.NormalElements, + posMode[m_VtxDesc.Normal], posFormats[m_VtxAttr.NormalFormat])); + } - u64 color_mode[2] = { m_VtxDesc.Color0, m_VtxDesc.Color1 }; - for (int i = 0; i < 2; i++) - { - if (color_mode[i]) - { - dest->append(StringFromFormat("C%i: %i %s-%s ", i, m_VtxAttr.color[i].Elements, posMode[color_mode[i]], colorFormat[m_VtxAttr.color[i].Comp])); - } - } - u64 tex_mode[8] = { - m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord, m_VtxDesc.Tex3Coord, - m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, m_VtxDesc.Tex6Coord, m_VtxDesc.Tex7Coord - }; - for (int i = 0; i < 8; i++) - { - if (tex_mode[i]) - { - dest->append(StringFromFormat("T%i: %i %s-%s ", - i, m_VtxAttr.texCoord[i].Elements, posMode[tex_mode[i]], posFormats[m_VtxAttr.texCoord[i].Format])); - } - } - dest->append(StringFromFormat(" - %i v", m_numLoadedVertices)); + u64 color_mode[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1}; + for (int i = 0; i < 2; i++) + { + if (color_mode[i]) + { + dest->append(StringFromFormat("C%i: %i %s-%s ", i, m_VtxAttr.color[i].Elements, + posMode[color_mode[i]], colorFormat[m_VtxAttr.color[i].Comp])); + } + } + u64 tex_mode[8] = {m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord, + m_VtxDesc.Tex3Coord, m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, + m_VtxDesc.Tex6Coord, m_VtxDesc.Tex7Coord}; + for (int i = 0; i < 8; i++) + { + if (tex_mode[i]) + { + dest->append(StringFromFormat("T%i: %i %s-%s ", i, m_VtxAttr.texCoord[i].Elements, + posMode[tex_mode[i]], + posFormats[m_VtxAttr.texCoord[i].Format])); + } + } + dest->append(StringFromFormat(" - %i v", m_numLoadedVertices)); } // a hacky implementation to compare two vertex loaders class VertexLoaderTester : public VertexLoaderBase { public: - VertexLoaderTester(std::unique_ptr a_, std::unique_ptr b_, const TVtxDesc& vtx_desc, const VAT& vtx_attr) - : VertexLoaderBase(vtx_desc, vtx_attr), a(std::move(a_)), b(std::move(b_)) - { - m_initialized = a && b && a->IsInitialized() && b->IsInitialized(); + VertexLoaderTester(std::unique_ptr a_, std::unique_ptr b_, + const TVtxDesc& vtx_desc, const VAT& vtx_attr) + : VertexLoaderBase(vtx_desc, vtx_attr), a(std::move(a_)), b(std::move(b_)) + { + m_initialized = a && b && a->IsInitialized() && b->IsInitialized(); - if (m_initialized) - { - m_initialized = a->m_VertexSize == b->m_VertexSize && - a->m_native_components == b->m_native_components && - a->m_native_vtx_decl.stride == b->m_native_vtx_decl.stride; + if (m_initialized) + { + m_initialized = a->m_VertexSize == b->m_VertexSize && + a->m_native_components == b->m_native_components && + a->m_native_vtx_decl.stride == b->m_native_vtx_decl.stride; - if (m_initialized) - { - m_VertexSize = a->m_VertexSize; - m_native_components = a->m_native_components; - memcpy(&m_native_vtx_decl, &a->m_native_vtx_decl, sizeof(PortableVertexDeclaration)); - } - else - { - ERROR_LOG(VIDEO, "Can't compare vertex loaders that expect different vertex formats!"); - ERROR_LOG(VIDEO, "a: m_VertexSize %d, m_native_components 0x%08x, stride %d", - a->m_VertexSize, a->m_native_components, a->m_native_vtx_decl.stride); - ERROR_LOG(VIDEO, "b: m_VertexSize %d, m_native_components 0x%08x, stride %d", - b->m_VertexSize, b->m_native_components, b->m_native_vtx_decl.stride); - } - } - } - ~VertexLoaderTester() override - { - } + if (m_initialized) + { + m_VertexSize = a->m_VertexSize; + m_native_components = a->m_native_components; + memcpy(&m_native_vtx_decl, &a->m_native_vtx_decl, sizeof(PortableVertexDeclaration)); + } + else + { + ERROR_LOG(VIDEO, "Can't compare vertex loaders that expect different vertex formats!"); + ERROR_LOG(VIDEO, "a: m_VertexSize %d, m_native_components 0x%08x, stride %d", + a->m_VertexSize, a->m_native_components, a->m_native_vtx_decl.stride); + ERROR_LOG(VIDEO, "b: m_VertexSize %d, m_native_components 0x%08x, stride %d", + b->m_VertexSize, b->m_native_components, b->m_native_vtx_decl.stride); + } + } + } + ~VertexLoaderTester() override {} + int RunVertices(DataReader src, DataReader dst, int count) override + { + buffer_a.resize(count * a->m_native_vtx_decl.stride + 4); + buffer_b.resize(count * b->m_native_vtx_decl.stride + 4); - int RunVertices(DataReader src, DataReader dst, int count) override - { - buffer_a.resize(count * a->m_native_vtx_decl.stride + 4); - buffer_b.resize(count * b->m_native_vtx_decl.stride + 4); + int count_a = + a->RunVertices(src, DataReader(buffer_a.data(), buffer_a.data() + buffer_a.size()), count); + int count_b = + b->RunVertices(src, DataReader(buffer_b.data(), buffer_b.data() + buffer_b.size()), count); - int count_a = a->RunVertices(src, DataReader(buffer_a.data(), buffer_a.data()+buffer_a.size()), count); - int count_b = b->RunVertices(src, DataReader(buffer_b.data(), buffer_b.data()+buffer_b.size()), count); + if (count_a != count_b) + ERROR_LOG(VIDEO, + "The two vertex loaders have loaded a different amount of vertices (a: %d, b: %d).", + count_a, count_b); - if (count_a != count_b) - ERROR_LOG(VIDEO, "The two vertex loaders have loaded a different amount of vertices (a: %d, b: %d).", count_a, count_b); - - if (memcmp(buffer_a.data(), buffer_b.data(), std::min(count_a, count_b) * m_native_vtx_decl.stride)) - ERROR_LOG(VIDEO, "The two vertex loaders have loaded different data " - "(guru meditation 0x%016" PRIx64 ", 0x%08x, 0x%08x, 0x%08x).", - m_VtxDesc.Hex, m_vat.g0.Hex, m_vat.g1.Hex, m_vat.g2.Hex); - - memcpy(dst.GetPointer(), buffer_a.data(), count_a * m_native_vtx_decl.stride); - m_numLoadedVertices += count; - return count_a; - } - std::string GetName() const override { return "CompareLoader"; } - bool IsInitialized() override { return m_initialized; } + if (memcmp(buffer_a.data(), buffer_b.data(), + std::min(count_a, count_b) * m_native_vtx_decl.stride)) + ERROR_LOG(VIDEO, "The two vertex loaders have loaded different data " + "(guru meditation 0x%016" PRIx64 ", 0x%08x, 0x%08x, 0x%08x).", + m_VtxDesc.Hex, m_vat.g0.Hex, m_vat.g1.Hex, m_vat.g2.Hex); + memcpy(dst.GetPointer(), buffer_a.data(), count_a * m_native_vtx_decl.stride); + m_numLoadedVertices += count; + return count_a; + } + std::string GetName() const override { return "CompareLoader"; } + bool IsInitialized() override { return m_initialized; } private: - bool m_initialized; + bool m_initialized; - std::unique_ptr a; - std::unique_ptr b; + std::unique_ptr a; + std::unique_ptr b; - std::vector buffer_a; - std::vector buffer_b; + std::vector buffer_a; + std::vector buffer_b; }; -std::unique_ptr VertexLoaderBase::CreateVertexLoader(const TVtxDesc& vtx_desc, const VAT& vtx_attr) +std::unique_ptr VertexLoaderBase::CreateVertexLoader(const TVtxDesc& vtx_desc, + const VAT& vtx_attr) { - std::unique_ptr loader; + std::unique_ptr loader; //#define COMPARE_VERTEXLOADERS #if defined(COMPARE_VERTEXLOADERS) && defined(_M_X86_64) - // first try: Any new VertexLoader vs the old one - loader = std::make_unique( - std::make_unique(vtx_desc, vtx_attr), // the software one - std::make_unique(vtx_desc, vtx_attr), // the new one to compare - vtx_desc, vtx_attr); - if (loader->IsInitialized()) - return loader; + // first try: Any new VertexLoader vs the old one + loader = std::make_unique( + std::make_unique(vtx_desc, vtx_attr), // the software one + std::make_unique(vtx_desc, vtx_attr), // the new one to compare + vtx_desc, vtx_attr); + if (loader->IsInitialized()) + return loader; #elif defined(_M_X86_64) - loader = std::make_unique(vtx_desc, vtx_attr); - if (loader->IsInitialized()) - return loader; + loader = std::make_unique(vtx_desc, vtx_attr); + if (loader->IsInitialized()) + return loader; #elif defined(_M_ARM_64) - loader = std::make_unique(vtx_desc, vtx_attr); - if (loader->IsInitialized()) - return loader; + loader = std::make_unique(vtx_desc, vtx_attr); + if (loader->IsInitialized()) + return loader; #endif - // last try: The old VertexLoader - loader = std::make_unique(vtx_desc, vtx_attr); - if (loader->IsInitialized()) - return loader; + // last try: The old VertexLoader + loader = std::make_unique(vtx_desc, vtx_attr); + if (loader->IsInitialized()) + return loader; - PanicAlert("No Vertex Loader found."); - return nullptr; + PanicAlert("No Vertex Loader found."); + return nullptr; } diff --git a/Source/Core/VideoCommon/VertexLoaderBase.h b/Source/Core/VideoCommon/VertexLoaderBase.h index b0a3cb3794..38fa66c371 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.h +++ b/Source/Core/VideoCommon/VertexLoaderBase.h @@ -16,89 +16,76 @@ class DataReader; class VertexLoaderUID { - std::array vid; - size_t hash; + std::array vid; + size_t hash; + public: - VertexLoaderUID() - { - } - - VertexLoaderUID(const TVtxDesc& vtx_desc, const VAT& vat) - { - vid[0] = vtx_desc.Hex & 0xFFFFFFFF; - vid[1] = vtx_desc.Hex >> 32; - vid[2] = vat.g0.Hex; - vid[3] = vat.g1.Hex; - vid[4] = vat.g2.Hex; - hash = CalculateHash(); - } - - bool operator == (const VertexLoaderUID& rh) const - { - return vid == rh.vid; - } - - size_t GetHash() const - { - return hash; - } + VertexLoaderUID() {} + VertexLoaderUID(const TVtxDesc& vtx_desc, const VAT& vat) + { + vid[0] = vtx_desc.Hex & 0xFFFFFFFF; + vid[1] = vtx_desc.Hex >> 32; + vid[2] = vat.g0.Hex; + vid[3] = vat.g1.Hex; + vid[4] = vat.g2.Hex; + hash = CalculateHash(); + } + bool operator==(const VertexLoaderUID& rh) const { return vid == rh.vid; } + size_t GetHash() const { return hash; } private: + size_t CalculateHash() const + { + size_t h = -1; - size_t CalculateHash() const - { - size_t h = -1; + for (auto word : vid) + { + h = h * 137 + word; + } - for (auto word : vid) - { - h = h * 137 + word; - } - - return h; - } + return h; + } }; namespace std { -template <> struct hash +template <> +struct hash { - size_t operator()(const VertexLoaderUID& uid) const - { - return uid.GetHash(); - } + size_t operator()(const VertexLoaderUID& uid) const { return uid.GetHash(); } }; } class VertexLoaderBase { public: - static std::unique_ptr CreateVertexLoader(const TVtxDesc &vtx_desc, const VAT &vtx_attr); - virtual ~VertexLoaderBase() {} + static std::unique_ptr CreateVertexLoader(const TVtxDesc& vtx_desc, + const VAT& vtx_attr); + virtual ~VertexLoaderBase() {} + virtual int RunVertices(DataReader src, DataReader dst, int count) = 0; - virtual int RunVertices(DataReader src, DataReader dst, int count) = 0; + virtual bool IsInitialized() = 0; - virtual bool IsInitialized() = 0; + // For debugging / profiling + void AppendToString(std::string* dest) const; - // For debugging / profiling - void AppendToString(std::string *dest) const; + virtual std::string GetName() const = 0; - virtual std::string GetName() const = 0; + // per loader public state + int m_VertexSize; // number of bytes of a raw GC vertex + PortableVertexDeclaration m_native_vtx_decl; + u32 m_native_components; - // per loader public state - int m_VertexSize; // number of bytes of a raw GC vertex - PortableVertexDeclaration m_native_vtx_decl; - u32 m_native_components; - - // used by VertexLoaderManager - NativeVertexFormat* m_native_vertex_format; - int m_numLoadedVertices; + // used by VertexLoaderManager + NativeVertexFormat* m_native_vertex_format; + int m_numLoadedVertices; protected: - VertexLoaderBase(const TVtxDesc &vtx_desc, const VAT &vtx_attr); - void SetVAT(const VAT& vat); + VertexLoaderBase(const TVtxDesc& vtx_desc, const VAT& vtx_attr); + void SetVAT(const VAT& vat); - // GC vertex format - TVtxAttr m_VtxAttr; // VAT decoded into easy format - TVtxDesc m_VtxDesc; // Not really used currently - or well it is, but could be easily avoided. - VAT m_vat; + // GC vertex format + TVtxAttr m_VtxAttr; // VAT decoded into easy format + TVtxDesc m_VtxDesc; // Not really used currently - or well it is, but could be easily avoided. + VAT m_vat; }; diff --git a/Source/Core/VideoCommon/VertexLoaderManager.cpp b/Source/Core/VideoCommon/VertexLoaderManager.cpp index f04112e184..c8fa5485a9 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/VertexLoaderManager.cpp @@ -27,7 +27,6 @@ namespace VertexLoaderManager { - float position_cache[3][4]; u32 position_matrix_index[3]; @@ -40,268 +39,271 @@ static std::mutex s_vertex_loader_map_lock; static VertexLoaderMap s_vertex_loader_map; // TODO - change into array of pointers. Keep a map of all seen so far. -u8 *cached_arraybases[12]; +u8* cached_arraybases[12]; // Used in D3D12 backend, to populate input layouts used by cached-to-disk PSOs. NativeVertexFormatMap* GetNativeVertexFormatMap() { - return &s_native_vertex_map; + return &s_native_vertex_map; } void Init() { - MarkAllDirty(); - for (auto& map_entry : g_main_cp_state.vertex_loaders) - map_entry = nullptr; - for (auto& map_entry : g_preprocess_cp_state.vertex_loaders) - map_entry = nullptr; - SETSTAT(stats.numVertexLoaders, 0); + MarkAllDirty(); + for (auto& map_entry : g_main_cp_state.vertex_loaders) + map_entry = nullptr; + for (auto& map_entry : g_preprocess_cp_state.vertex_loaders) + map_entry = nullptr; + SETSTAT(stats.numVertexLoaders, 0); } void Shutdown() { - std::lock_guard lk(s_vertex_loader_map_lock); - s_vertex_loader_map.clear(); - s_native_vertex_map.clear(); + std::lock_guard lk(s_vertex_loader_map_lock); + s_vertex_loader_map.clear(); + s_native_vertex_map.clear(); } void UpdateVertexArrayPointers() { - // Anything to update? - if (!g_main_cp_state.bases_dirty) - return; + // Anything to update? + if (!g_main_cp_state.bases_dirty) + return; - // Some games such as Burnout 2 can put invalid addresses into - // the array base registers. (see issue 8591) - // But the vertex arrays with invalid addresses aren't actually enabled. - // Note: Only array bases 0 through 11 are used by the Vertex loaders. - // 12 through 15 are used for loading data into xfmem. - for (int i = 0; i < 12; i++) - { - // Only update the array base if the vertex description states we are going to use it. - if (g_main_cp_state.vtx_desc.GetVertexArrayStatus(i) & MASK_INDEXED) - cached_arraybases[i] = Memory::GetPointer(g_main_cp_state.array_bases[i]); - } + // Some games such as Burnout 2 can put invalid addresses into + // the array base registers. (see issue 8591) + // But the vertex arrays with invalid addresses aren't actually enabled. + // Note: Only array bases 0 through 11 are used by the Vertex loaders. + // 12 through 15 are used for loading data into xfmem. + for (int i = 0; i < 12; i++) + { + // Only update the array base if the vertex description states we are going to use it. + if (g_main_cp_state.vtx_desc.GetVertexArrayStatus(i) & MASK_INDEXED) + cached_arraybases[i] = Memory::GetPointer(g_main_cp_state.array_bases[i]); + } - g_main_cp_state.bases_dirty = false; + g_main_cp_state.bases_dirty = false; } namespace { struct entry { - std::string text; - u64 num_verts; - bool operator < (const entry &other) const - { - return num_verts > other.num_verts; - } + std::string text; + u64 num_verts; + bool operator<(const entry& other) const { return num_verts > other.num_verts; } }; } -void AppendListToString(std::string *dest) +void AppendListToString(std::string* dest) { - std::lock_guard lk(s_vertex_loader_map_lock); - std::vector entries; + std::lock_guard lk(s_vertex_loader_map_lock); + std::vector entries; - size_t total_size = 0; - for (const auto& map_entry : s_vertex_loader_map) - { - entry e; - map_entry.second->AppendToString(&e.text); - e.num_verts = map_entry.second->m_numLoadedVertices; - entries.push_back(e); - total_size += e.text.size() + 1; - } - sort(entries.begin(), entries.end()); - dest->reserve(dest->size() + total_size); - for (const entry& entry : entries) - { - *dest += entry.text; - *dest += '\n'; - } + size_t total_size = 0; + for (const auto& map_entry : s_vertex_loader_map) + { + entry e; + map_entry.second->AppendToString(&e.text); + e.num_verts = map_entry.second->m_numLoadedVertices; + entries.push_back(e); + total_size += e.text.size() + 1; + } + sort(entries.begin(), entries.end()); + dest->reserve(dest->size() + total_size); + for (const entry& entry : entries) + { + *dest += entry.text; + *dest += '\n'; + } } void MarkAllDirty() { - g_main_cp_state.attr_dirty = BitSet32::AllTrue(8); - g_preprocess_cp_state.attr_dirty = BitSet32::AllTrue(8); + g_main_cp_state.attr_dirty = BitSet32::AllTrue(8); + g_preprocess_cp_state.attr_dirty = BitSet32::AllTrue(8); } static VertexLoaderBase* RefreshLoader(int vtx_attr_group, bool preprocess = false) { - CPState* state = preprocess ? &g_preprocess_cp_state : &g_main_cp_state; - state->last_id = vtx_attr_group; + CPState* state = preprocess ? &g_preprocess_cp_state : &g_main_cp_state; + state->last_id = vtx_attr_group; - VertexLoaderBase* loader; - if (state->attr_dirty[vtx_attr_group]) - { - // We are not allowed to create a native vertex format on preprocessing as this is on the wrong thread - bool check_for_native_format = !preprocess; + VertexLoaderBase* loader; + if (state->attr_dirty[vtx_attr_group]) + { + // We are not allowed to create a native vertex format on preprocessing as this is on the wrong + // thread + bool check_for_native_format = !preprocess; - VertexLoaderUID uid(state->vtx_desc, state->vtx_attr[vtx_attr_group]); - std::lock_guard lk(s_vertex_loader_map_lock); - VertexLoaderMap::iterator iter = s_vertex_loader_map.find(uid); - if (iter != s_vertex_loader_map.end()) - { - loader = iter->second.get(); - check_for_native_format &= !loader->m_native_vertex_format; - } - else - { - s_vertex_loader_map[uid] = VertexLoaderBase::CreateVertexLoader(state->vtx_desc, state->vtx_attr[vtx_attr_group]); - loader = s_vertex_loader_map[uid].get(); - INCSTAT(stats.numVertexLoaders); - } - if (check_for_native_format) - { - // search for a cached native vertex format - const PortableVertexDeclaration& format = loader->m_native_vtx_decl; - std::unique_ptr& native = s_native_vertex_map[format]; - if (!native) - { - native.reset(g_vertex_manager->CreateNativeVertexFormat(format)); - } - loader->m_native_vertex_format = native.get(); - } - state->vertex_loaders[vtx_attr_group] = loader; - state->attr_dirty[vtx_attr_group] = false; - } else { - loader = state->vertex_loaders[vtx_attr_group]; - } + VertexLoaderUID uid(state->vtx_desc, state->vtx_attr[vtx_attr_group]); + std::lock_guard lk(s_vertex_loader_map_lock); + VertexLoaderMap::iterator iter = s_vertex_loader_map.find(uid); + if (iter != s_vertex_loader_map.end()) + { + loader = iter->second.get(); + check_for_native_format &= !loader->m_native_vertex_format; + } + else + { + s_vertex_loader_map[uid] = + VertexLoaderBase::CreateVertexLoader(state->vtx_desc, state->vtx_attr[vtx_attr_group]); + loader = s_vertex_loader_map[uid].get(); + INCSTAT(stats.numVertexLoaders); + } + if (check_for_native_format) + { + // search for a cached native vertex format + const PortableVertexDeclaration& format = loader->m_native_vtx_decl; + std::unique_ptr& native = s_native_vertex_map[format]; + if (!native) + { + native.reset(g_vertex_manager->CreateNativeVertexFormat(format)); + } + loader->m_native_vertex_format = native.get(); + } + state->vertex_loaders[vtx_attr_group] = loader; + state->attr_dirty[vtx_attr_group] = false; + } + else + { + loader = state->vertex_loaders[vtx_attr_group]; + } - // Lookup pointers for any vertex arrays. - if (!preprocess) - UpdateVertexArrayPointers(); + // Lookup pointers for any vertex arrays. + if (!preprocess) + UpdateVertexArrayPointers(); - return loader; + return loader; } -int RunVertices(int vtx_attr_group, int primitive, int count, DataReader src, bool skip_drawing, bool is_preprocess) +int RunVertices(int vtx_attr_group, int primitive, int count, DataReader src, bool skip_drawing, + bool is_preprocess) { - if (!count) - return 0; + if (!count) + return 0; - VertexLoaderBase* loader = RefreshLoader(vtx_attr_group, is_preprocess); + VertexLoaderBase* loader = RefreshLoader(vtx_attr_group, is_preprocess); - int size = count * loader->m_VertexSize; - if ((int)src.size() < size) - return -1; + int size = count * loader->m_VertexSize; + if ((int)src.size() < size) + return -1; - if (skip_drawing || is_preprocess) - return size; + if (skip_drawing || is_preprocess) + return size; - // If the native vertex format changed, force a flush. - if (loader->m_native_vertex_format != s_current_vtx_fmt || - loader->m_native_components != g_current_components) - { - VertexManagerBase::Flush(); - } - s_current_vtx_fmt = loader->m_native_vertex_format; - g_current_components = loader->m_native_components; + // If the native vertex format changed, force a flush. + if (loader->m_native_vertex_format != s_current_vtx_fmt || + loader->m_native_components != g_current_components) + { + VertexManagerBase::Flush(); + } + s_current_vtx_fmt = loader->m_native_vertex_format; + g_current_components = loader->m_native_components; - // if cull mode is CULL_ALL, tell VertexManager to skip triangles and quads. - // They still need to go through vertex loading, because we need to calculate a zfreeze refrence slope. - bool cullall = (bpmem.genMode.cullmode == GenMode::CULL_ALL && primitive < 5); + // if cull mode is CULL_ALL, tell VertexManager to skip triangles and quads. + // They still need to go through vertex loading, because we need to calculate a zfreeze refrence + // slope. + bool cullall = (bpmem.genMode.cullmode == GenMode::CULL_ALL && primitive < 5); - DataReader dst = VertexManagerBase::PrepareForAdditionalData(primitive, count, - loader->m_native_vtx_decl.stride, cullall); + DataReader dst = VertexManagerBase::PrepareForAdditionalData( + primitive, count, loader->m_native_vtx_decl.stride, cullall); - count = loader->RunVertices(src, dst, count); + count = loader->RunVertices(src, dst, count); - IndexGenerator::AddIndices(primitive, count); + IndexGenerator::AddIndices(primitive, count); - VertexManagerBase::FlushData(count, loader->m_native_vtx_decl.stride); + VertexManagerBase::FlushData(count, loader->m_native_vtx_decl.stride); - ADDSTAT(stats.thisFrame.numPrims, count); - INCSTAT(stats.thisFrame.numPrimitiveJoins); - return size; + ADDSTAT(stats.thisFrame.numPrims, count); + INCSTAT(stats.thisFrame.numPrimitiveJoins); + return size; } NativeVertexFormat* GetCurrentVertexFormat() { - return s_current_vtx_fmt; + return s_current_vtx_fmt; } } // namespace void LoadCPReg(u32 sub_cmd, u32 value, bool is_preprocess) { - bool update_global_state = !is_preprocess; - CPState* state = is_preprocess ? &g_preprocess_cp_state : &g_main_cp_state; - switch (sub_cmd & 0xF0) - { - case 0x30: - if (update_global_state) - VertexShaderManager::SetTexMatrixChangedA(value); - break; + bool update_global_state = !is_preprocess; + CPState* state = is_preprocess ? &g_preprocess_cp_state : &g_main_cp_state; + switch (sub_cmd & 0xF0) + { + case 0x30: + if (update_global_state) + VertexShaderManager::SetTexMatrixChangedA(value); + break; - case 0x40: - if (update_global_state) - VertexShaderManager::SetTexMatrixChangedB(value); - break; + case 0x40: + if (update_global_state) + VertexShaderManager::SetTexMatrixChangedB(value); + break; - case 0x50: - state->vtx_desc.Hex &= ~0x1FFFF; // keep the Upper bits - state->vtx_desc.Hex |= value; - state->attr_dirty = BitSet32::AllTrue(8); - state->bases_dirty = true; - break; + case 0x50: + state->vtx_desc.Hex &= ~0x1FFFF; // keep the Upper bits + state->vtx_desc.Hex |= value; + state->attr_dirty = BitSet32::AllTrue(8); + state->bases_dirty = true; + break; - case 0x60: - state->vtx_desc.Hex &= 0x1FFFF; // keep the lower 17Bits - state->vtx_desc.Hex |= (u64)value << 17; - state->attr_dirty = BitSet32::AllTrue(8); - state->bases_dirty = true; - break; + case 0x60: + state->vtx_desc.Hex &= 0x1FFFF; // keep the lower 17Bits + state->vtx_desc.Hex |= (u64)value << 17; + state->attr_dirty = BitSet32::AllTrue(8); + state->bases_dirty = true; + break; - case 0x70: - _assert_((sub_cmd & 0x0F) < 8); - state->vtx_attr[sub_cmd & 7].g0.Hex = value; - state->attr_dirty[sub_cmd & 7] = true; - break; + case 0x70: + _assert_((sub_cmd & 0x0F) < 8); + state->vtx_attr[sub_cmd & 7].g0.Hex = value; + state->attr_dirty[sub_cmd & 7] = true; + break; - case 0x80: - _assert_((sub_cmd & 0x0F) < 8); - state->vtx_attr[sub_cmd & 7].g1.Hex = value; - state->attr_dirty[sub_cmd & 7] = true; - break; + case 0x80: + _assert_((sub_cmd & 0x0F) < 8); + state->vtx_attr[sub_cmd & 7].g1.Hex = value; + state->attr_dirty[sub_cmd & 7] = true; + break; - case 0x90: - _assert_((sub_cmd & 0x0F) < 8); - state->vtx_attr[sub_cmd & 7].g2.Hex = value; - state->attr_dirty[sub_cmd & 7] = true; - break; + case 0x90: + _assert_((sub_cmd & 0x0F) < 8); + state->vtx_attr[sub_cmd & 7].g2.Hex = value; + state->attr_dirty[sub_cmd & 7] = true; + break; - // Pointers to vertex arrays in GC RAM - case 0xA0: - state->array_bases[sub_cmd & 0xF] = value; - state->bases_dirty = true; - break; + // Pointers to vertex arrays in GC RAM + case 0xA0: + state->array_bases[sub_cmd & 0xF] = value; + state->bases_dirty = true; + break; - case 0xB0: - state->array_strides[sub_cmd & 0xF] = value & 0xFF; - break; - } + case 0xB0: + state->array_strides[sub_cmd & 0xF] = value & 0xFF; + break; + } } -void FillCPMemoryArray(u32 *memory) +void FillCPMemoryArray(u32* memory) { - memory[0x30] = g_main_cp_state.matrix_index_a.Hex; - memory[0x40] = g_main_cp_state.matrix_index_b.Hex; - memory[0x50] = (u32)g_main_cp_state.vtx_desc.Hex; - memory[0x60] = (u32)(g_main_cp_state.vtx_desc.Hex >> 17); + memory[0x30] = g_main_cp_state.matrix_index_a.Hex; + memory[0x40] = g_main_cp_state.matrix_index_b.Hex; + memory[0x50] = (u32)g_main_cp_state.vtx_desc.Hex; + memory[0x60] = (u32)(g_main_cp_state.vtx_desc.Hex >> 17); - for (int i = 0; i < 8; ++i) - { - memory[0x70 + i] = g_main_cp_state.vtx_attr[i].g0.Hex; - memory[0x80 + i] = g_main_cp_state.vtx_attr[i].g1.Hex; - memory[0x90 + i] = g_main_cp_state.vtx_attr[i].g2.Hex; - } + for (int i = 0; i < 8; ++i) + { + memory[0x70 + i] = g_main_cp_state.vtx_attr[i].g0.Hex; + memory[0x80 + i] = g_main_cp_state.vtx_attr[i].g1.Hex; + memory[0x90 + i] = g_main_cp_state.vtx_attr[i].g2.Hex; + } - for (int i = 0; i < 16; ++i) - { - memory[0xA0 + i] = g_main_cp_state.array_bases[i]; - memory[0xB0 + i] = g_main_cp_state.array_strides[i]; - } + for (int i = 0; i < 16; ++i) + { + memory[0xA0 + i] = g_main_cp_state.array_bases[i]; + memory[0xB0 + i] = g_main_cp_state.array_strides[i]; + } } diff --git a/Source/Core/VideoCommon/VertexLoaderManager.h b/Source/Core/VideoCommon/VertexLoaderManager.h index c8fdf67163..1386df2381 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.h +++ b/Source/Core/VideoCommon/VertexLoaderManager.h @@ -16,33 +16,34 @@ struct PortableVertexDeclaration; namespace VertexLoaderManager { - using NativeVertexFormatMap = std::unordered_map>; +using NativeVertexFormatMap = + std::unordered_map>; - void Init(); - void Shutdown(); +void Init(); +void Shutdown(); - void MarkAllDirty(); +void MarkAllDirty(); - NativeVertexFormatMap* GetNativeVertexFormatMap(); +NativeVertexFormatMap* GetNativeVertexFormatMap(); - // Returns -1 if buf_size is insufficient, else the amount of bytes consumed - int RunVertices(int vtx_attr_group, int primitive, int count, DataReader src, bool skip_drawing, bool is_preprocess); +// Returns -1 if buf_size is insufficient, else the amount of bytes consumed +int RunVertices(int vtx_attr_group, int primitive, int count, DataReader src, bool skip_drawing, + bool is_preprocess); - // For debugging - void AppendListToString(std::string *dest); +// For debugging +void AppendListToString(std::string* dest); - NativeVertexFormat* GetCurrentVertexFormat(); +NativeVertexFormat* GetCurrentVertexFormat(); - // Resolved pointers to array bases. Used by vertex loaders. - extern u8 *cached_arraybases[12]; - void UpdateVertexArrayPointers(); +// Resolved pointers to array bases. Used by vertex loaders. +extern u8* cached_arraybases[12]; +void UpdateVertexArrayPointers(); - // Position cache for zfreeze (3 vertices, 4 floats each to allow SIMD overwrite). - // These arrays are in reverse order. - extern float position_cache[3][4]; - extern u32 position_matrix_index[3]; +// Position cache for zfreeze (3 vertices, 4 floats each to allow SIMD overwrite). +// These arrays are in reverse order. +extern float position_cache[3][4]; +extern u32 position_matrix_index[3]; - // VB_HAS_X. Bitmask telling what vertex components are present. - extern u32 g_current_components; +// VB_HAS_X. Bitmask telling what vertex components are present. +extern u32 g_current_components; } - diff --git a/Source/Core/VideoCommon/VertexLoaderUtils.h b/Source/Core/VideoCommon/VertexLoaderUtils.h index 7f18101f93..c8b1e2e54a 100644 --- a/Source/Core/VideoCommon/VertexLoaderUtils.h +++ b/Source/Core/VideoCommon/VertexLoaderUtils.h @@ -14,48 +14,48 @@ extern u8* g_vertex_manager_write_ptr; __forceinline void DataSkip(u32 skip) { - g_video_buffer_read_ptr += skip; + g_video_buffer_read_ptr += skip; } // probably unnecessary template __forceinline void DataSkip() { - g_video_buffer_read_ptr += count; + g_video_buffer_read_ptr += count; } template __forceinline T DataPeek(int _uOffset, u8* bufp = g_video_buffer_read_ptr) { - T result; - std::memcpy(&result, &bufp[_uOffset], sizeof(T)); - return Common::FromBigEndian(result); + T result; + std::memcpy(&result, &bufp[_uOffset], sizeof(T)); + return Common::FromBigEndian(result); } template __forceinline T DataRead(u8** bufp = &g_video_buffer_read_ptr) { - auto const result = DataPeek(0, *bufp); - *bufp += sizeof(T); - return result; + auto const result = DataPeek(0, *bufp); + *bufp += sizeof(T); + return result; } __forceinline u32 DataReadU32Unswapped() { - u32 result; - std::memcpy(&result, g_video_buffer_read_ptr, sizeof(u32)); - g_video_buffer_read_ptr += sizeof(u32); - return result; + u32 result; + std::memcpy(&result, g_video_buffer_read_ptr, sizeof(u32)); + g_video_buffer_read_ptr += sizeof(u32); + return result; } __forceinline u8* DataGetPosition() { - return g_video_buffer_read_ptr; + return g_video_buffer_read_ptr; } template __forceinline void DataWrite(T data) { - std::memcpy(g_vertex_manager_write_ptr, &data, sizeof(T)); - g_vertex_manager_write_ptr += sizeof(T); + std::memcpy(g_vertex_manager_write_ptr, &data, sizeof(T)); + g_vertex_manager_write_ptr += sizeof(T); } diff --git a/Source/Core/VideoCommon/VertexLoaderX64.cpp b/Source/Core/VideoCommon/VertexLoaderX64.cpp index 9fc5346290..4aa6802e41 100644 --- a/Source/Core/VideoCommon/VertexLoaderX64.cpp +++ b/Source/Core/VideoCommon/VertexLoaderX64.cpp @@ -6,9 +6,9 @@ #include #include "Common/BitSet.h" +#include "Common/CPUDetect.h" #include "Common/Common.h" #include "Common/CommonTypes.h" -#include "Common/CPUDetect.h" #include "Common/Intrinsics.h" #include "Common/JitRegister.h" #include "Common/x64ABI.h" @@ -32,523 +32,533 @@ static const u8* memory_base_ptr = (u8*)&g_main_cp_state.array_strides; static OpArg MPIC(const void* ptr, X64Reg scale_reg, int scale = SCALE_1) { - return MComplex(base_reg, scale_reg, scale, (s32)((u8*)ptr - memory_base_ptr)); + return MComplex(base_reg, scale_reg, scale, (s32)((u8*)ptr - memory_base_ptr)); } static OpArg MPIC(const void* ptr) { - return MDisp(base_reg, (s32)((u8*)ptr - memory_base_ptr)); + return MDisp(base_reg, (s32)((u8*)ptr - memory_base_ptr)); } -VertexLoaderX64::VertexLoaderX64(const TVtxDesc& vtx_desc, const VAT& vtx_att) : VertexLoaderBase(vtx_desc, vtx_att) +VertexLoaderX64::VertexLoaderX64(const TVtxDesc& vtx_desc, const VAT& vtx_att) + : VertexLoaderBase(vtx_desc, vtx_att) { - if (!IsInitialized()) - return; + if (!IsInitialized()) + return; - AllocCodeSpace(4096, false); - ClearCodeSpace(); - GenerateVertexLoader(); - WriteProtect(); + AllocCodeSpace(4096, false); + ClearCodeSpace(); + GenerateVertexLoader(); + WriteProtect(); - std::string name; - AppendToString(&name); - JitRegister::Register(region, GetCodePtr(), name.c_str()); + std::string name; + AppendToString(&name); + JitRegister::Register(region, GetCodePtr(), name.c_str()); } OpArg VertexLoaderX64::GetVertexAddr(int array, u64 attribute) { - OpArg data = MDisp(src_reg, m_src_ofs); - if (attribute & MASK_INDEXED) - { - int bits = attribute == INDEX8 ? 8 : 16; - LoadAndSwap(bits, scratch1, data); - m_src_ofs += bits / 8; - if (array == ARRAY_POSITION) - { - CMP(bits, R(scratch1), Imm8(-1)); - m_skip_vertex = J_CC(CC_E, true); - } - IMUL(32, scratch1, MPIC(&g_main_cp_state.array_strides[array])); - MOV(64, R(scratch2), MPIC(&VertexLoaderManager::cached_arraybases[array])); - return MRegSum(scratch1, scratch2); - } - else - { - return data; - } + OpArg data = MDisp(src_reg, m_src_ofs); + if (attribute & MASK_INDEXED) + { + int bits = attribute == INDEX8 ? 8 : 16; + LoadAndSwap(bits, scratch1, data); + m_src_ofs += bits / 8; + if (array == ARRAY_POSITION) + { + CMP(bits, R(scratch1), Imm8(-1)); + m_skip_vertex = J_CC(CC_E, true); + } + IMUL(32, scratch1, MPIC(&g_main_cp_state.array_strides[array])); + MOV(64, R(scratch2), MPIC(&VertexLoaderManager::cached_arraybases[array])); + return MRegSum(scratch1, scratch2); + } + else + { + return data; + } } -int VertexLoaderX64::ReadVertex(OpArg data, u64 attribute, int format, int count_in, int count_out, bool dequantize, u8 scaling_exponent, AttributeFormat* native_format) +int VertexLoaderX64::ReadVertex(OpArg data, u64 attribute, int format, int count_in, int count_out, + bool dequantize, u8 scaling_exponent, + AttributeFormat* native_format) { - static const __m128i shuffle_lut[5][3] = { - {_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFF00L), // 1x u8 - _mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFF01L, 0xFFFFFF00L), // 2x u8 - _mm_set_epi32(0xFFFFFFFFL, 0xFFFFFF02L, 0xFFFFFF01L, 0xFFFFFF00L)}, // 3x u8 - {_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x00FFFFFFL), // 1x s8 - _mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x01FFFFFFL, 0x00FFFFFFL), // 2x s8 - _mm_set_epi32(0xFFFFFFFFL, 0x02FFFFFFL, 0x01FFFFFFL, 0x00FFFFFFL)}, // 3x s8 - {_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFF0001L), // 1x u16 - _mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFF0203L, 0xFFFF0001L), // 2x u16 - _mm_set_epi32(0xFFFFFFFFL, 0xFFFF0405L, 0xFFFF0203L, 0xFFFF0001L)}, // 3x u16 - {_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x0001FFFFL), // 1x s16 - _mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x0203FFFFL, 0x0001FFFFL), // 2x s16 - _mm_set_epi32(0xFFFFFFFFL, 0x0405FFFFL, 0x0203FFFFL, 0x0001FFFFL)}, // 3x s16 - {_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x00010203L), // 1x float - _mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x04050607L, 0x00010203L), // 2x float - _mm_set_epi32(0xFFFFFFFFL, 0x08090A0BL, 0x04050607L, 0x00010203L)}, // 3x float - }; - static const __m128 scale_factors[32] = { - _mm_set_ps1(1./(1u<< 0)), _mm_set_ps1(1./(1u<< 1)), _mm_set_ps1(1./(1u<< 2)), _mm_set_ps1(1./(1u<< 3)), - _mm_set_ps1(1./(1u<< 4)), _mm_set_ps1(1./(1u<< 5)), _mm_set_ps1(1./(1u<< 6)), _mm_set_ps1(1./(1u<< 7)), - _mm_set_ps1(1./(1u<< 8)), _mm_set_ps1(1./(1u<< 9)), _mm_set_ps1(1./(1u<<10)), _mm_set_ps1(1./(1u<<11)), - _mm_set_ps1(1./(1u<<12)), _mm_set_ps1(1./(1u<<13)), _mm_set_ps1(1./(1u<<14)), _mm_set_ps1(1./(1u<<15)), - _mm_set_ps1(1./(1u<<16)), _mm_set_ps1(1./(1u<<17)), _mm_set_ps1(1./(1u<<18)), _mm_set_ps1(1./(1u<<19)), - _mm_set_ps1(1./(1u<<20)), _mm_set_ps1(1./(1u<<21)), _mm_set_ps1(1./(1u<<22)), _mm_set_ps1(1./(1u<<23)), - _mm_set_ps1(1./(1u<<24)), _mm_set_ps1(1./(1u<<25)), _mm_set_ps1(1./(1u<<26)), _mm_set_ps1(1./(1u<<27)), - _mm_set_ps1(1./(1u<<28)), _mm_set_ps1(1./(1u<<29)), _mm_set_ps1(1./(1u<<30)), _mm_set_ps1(1./(1u<<31)), - }; + static const __m128i shuffle_lut[5][3] = { + {_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFF00L), // 1x u8 + _mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFF01L, 0xFFFFFF00L), // 2x u8 + _mm_set_epi32(0xFFFFFFFFL, 0xFFFFFF02L, 0xFFFFFF01L, 0xFFFFFF00L)}, // 3x u8 + {_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x00FFFFFFL), // 1x s8 + _mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x01FFFFFFL, 0x00FFFFFFL), // 2x s8 + _mm_set_epi32(0xFFFFFFFFL, 0x02FFFFFFL, 0x01FFFFFFL, 0x00FFFFFFL)}, // 3x s8 + {_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFF0001L), // 1x u16 + _mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFF0203L, 0xFFFF0001L), // 2x u16 + _mm_set_epi32(0xFFFFFFFFL, 0xFFFF0405L, 0xFFFF0203L, 0xFFFF0001L)}, // 3x u16 + {_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x0001FFFFL), // 1x s16 + _mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x0203FFFFL, 0x0001FFFFL), // 2x s16 + _mm_set_epi32(0xFFFFFFFFL, 0x0405FFFFL, 0x0203FFFFL, 0x0001FFFFL)}, // 3x s16 + {_mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFL, 0x00010203L), // 1x float + _mm_set_epi32(0xFFFFFFFFL, 0xFFFFFFFFL, 0x04050607L, 0x00010203L), // 2x float + _mm_set_epi32(0xFFFFFFFFL, 0x08090A0BL, 0x04050607L, 0x00010203L)}, // 3x float + }; + static const __m128 scale_factors[32] = { + _mm_set_ps1(1. / (1u << 0)), _mm_set_ps1(1. / (1u << 1)), _mm_set_ps1(1. / (1u << 2)), + _mm_set_ps1(1. / (1u << 3)), _mm_set_ps1(1. / (1u << 4)), _mm_set_ps1(1. / (1u << 5)), + _mm_set_ps1(1. / (1u << 6)), _mm_set_ps1(1. / (1u << 7)), _mm_set_ps1(1. / (1u << 8)), + _mm_set_ps1(1. / (1u << 9)), _mm_set_ps1(1. / (1u << 10)), _mm_set_ps1(1. / (1u << 11)), + _mm_set_ps1(1. / (1u << 12)), _mm_set_ps1(1. / (1u << 13)), _mm_set_ps1(1. / (1u << 14)), + _mm_set_ps1(1. / (1u << 15)), _mm_set_ps1(1. / (1u << 16)), _mm_set_ps1(1. / (1u << 17)), + _mm_set_ps1(1. / (1u << 18)), _mm_set_ps1(1. / (1u << 19)), _mm_set_ps1(1. / (1u << 20)), + _mm_set_ps1(1. / (1u << 21)), _mm_set_ps1(1. / (1u << 22)), _mm_set_ps1(1. / (1u << 23)), + _mm_set_ps1(1. / (1u << 24)), _mm_set_ps1(1. / (1u << 25)), _mm_set_ps1(1. / (1u << 26)), + _mm_set_ps1(1. / (1u << 27)), _mm_set_ps1(1. / (1u << 28)), _mm_set_ps1(1. / (1u << 29)), + _mm_set_ps1(1. / (1u << 30)), _mm_set_ps1(1. / (1u << 31)), + }; - X64Reg coords = XMM0; + X64Reg coords = XMM0; - int elem_size = 1 << (format / 2); - int load_bytes = elem_size * count_in; - OpArg dest = MDisp(dst_reg, m_dst_ofs); + int elem_size = 1 << (format / 2); + int load_bytes = elem_size * count_in; + OpArg dest = MDisp(dst_reg, m_dst_ofs); - native_format->components = count_out; - native_format->enable = true; - native_format->offset = m_dst_ofs; - native_format->type = VAR_FLOAT; - native_format->integer = false; + native_format->components = count_out; + native_format->enable = true; + native_format->offset = m_dst_ofs; + native_format->type = VAR_FLOAT; + native_format->integer = false; - m_dst_ofs += sizeof(float) * count_out; + m_dst_ofs += sizeof(float) * count_out; - if (attribute == DIRECT) - m_src_ofs += load_bytes; + if (attribute == DIRECT) + m_src_ofs += load_bytes; - if (cpu_info.bSSSE3) - { - if (load_bytes > 8) - MOVDQU(coords, data); - else if (load_bytes > 4) - MOVQ_xmm(coords, data); - else - MOVD_xmm(coords, data); + if (cpu_info.bSSSE3) + { + if (load_bytes > 8) + MOVDQU(coords, data); + else if (load_bytes > 4) + MOVQ_xmm(coords, data); + else + MOVD_xmm(coords, data); - PSHUFB(coords, MPIC(&shuffle_lut[format][count_in - 1])); + PSHUFB(coords, MPIC(&shuffle_lut[format][count_in - 1])); - // Sign-extend. - if (format == FORMAT_BYTE) - PSRAD(coords, 24); - if (format == FORMAT_SHORT) - PSRAD(coords, 16); - } - else - { - // SSE2 - X64Reg temp = XMM1; - switch (format) - { - case FORMAT_UBYTE: - MOVD_xmm(coords, data); - PXOR(temp, R(temp)); - PUNPCKLBW(coords, R(temp)); - PUNPCKLWD(coords, R(temp)); - break; - case FORMAT_BYTE: - MOVD_xmm(coords, data); - PUNPCKLBW(coords, R(coords)); - PUNPCKLWD(coords, R(coords)); - PSRAD(coords, 24); - break; - case FORMAT_USHORT: - case FORMAT_SHORT: - switch (count_in) - { - case 1: - LoadAndSwap(32, scratch3, data); - MOVD_xmm(coords, R(scratch3)); // ......X. - break; - case 2: - LoadAndSwap(32, scratch3, data); - MOVD_xmm(coords, R(scratch3)); // ......XY - PSHUFLW(coords, R(coords), 0x24); // ....Y.X. - break; - case 3: - LoadAndSwap(64, scratch3, data); - MOVQ_xmm(coords, R(scratch3)); // ....XYZ. - PUNPCKLQDQ(coords, R(coords)); // ..Z.XYZ. - PSHUFLW(coords, R(coords), 0xAC); // ..Z.Y.X. - break; - } - if (format == FORMAT_SHORT) - PSRAD(coords, 16); - else - PSRLD(coords, 16); - break; - case FORMAT_FLOAT: - // Floats don't need to be scaled or converted, - // so we can just load/swap/store them directly - // and return early. - // (In SSSE3 we still need to store them.) - for (int i = 0; i < count_in; i++) - { - LoadAndSwap(32, scratch3, data); - MOV(32, dest, R(scratch3)); - data.AddMemOffset(sizeof(float)); - dest.AddMemOffset(sizeof(float)); + // Sign-extend. + if (format == FORMAT_BYTE) + PSRAD(coords, 24); + if (format == FORMAT_SHORT) + PSRAD(coords, 16); + } + else + { + // SSE2 + X64Reg temp = XMM1; + switch (format) + { + case FORMAT_UBYTE: + MOVD_xmm(coords, data); + PXOR(temp, R(temp)); + PUNPCKLBW(coords, R(temp)); + PUNPCKLWD(coords, R(temp)); + break; + case FORMAT_BYTE: + MOVD_xmm(coords, data); + PUNPCKLBW(coords, R(coords)); + PUNPCKLWD(coords, R(coords)); + PSRAD(coords, 24); + break; + case FORMAT_USHORT: + case FORMAT_SHORT: + switch (count_in) + { + case 1: + LoadAndSwap(32, scratch3, data); + MOVD_xmm(coords, R(scratch3)); // ......X. + break; + case 2: + LoadAndSwap(32, scratch3, data); + MOVD_xmm(coords, R(scratch3)); // ......XY + PSHUFLW(coords, R(coords), 0x24); // ....Y.X. + break; + case 3: + LoadAndSwap(64, scratch3, data); + MOVQ_xmm(coords, R(scratch3)); // ....XYZ. + PUNPCKLQDQ(coords, R(coords)); // ..Z.XYZ. + PSHUFLW(coords, R(coords), 0xAC); // ..Z.Y.X. + break; + } + if (format == FORMAT_SHORT) + PSRAD(coords, 16); + else + PSRLD(coords, 16); + break; + case FORMAT_FLOAT: + // Floats don't need to be scaled or converted, + // so we can just load/swap/store them directly + // and return early. + // (In SSSE3 we still need to store them.) + for (int i = 0; i < count_in; i++) + { + LoadAndSwap(32, scratch3, data); + MOV(32, dest, R(scratch3)); + data.AddMemOffset(sizeof(float)); + dest.AddMemOffset(sizeof(float)); - // zfreeze - if (native_format == &m_native_vtx_decl.position) - { - if (cpu_info.bSSE4_1) - { - PINSRD(coords, R(scratch3), i); - } - else - { - PINSRW(coords, R(scratch3), 2 * i + 0); - SHR(32, R(scratch3), Imm8(16)); - PINSRW(coords, R(scratch3), 2 * i + 1); - } - } - } + // zfreeze + if (native_format == &m_native_vtx_decl.position) + { + if (cpu_info.bSSE4_1) + { + PINSRD(coords, R(scratch3), i); + } + else + { + PINSRW(coords, R(scratch3), 2 * i + 0); + SHR(32, R(scratch3), Imm8(16)); + PINSRW(coords, R(scratch3), 2 * i + 1); + } + } + } - // zfreeze - if (native_format == &m_native_vtx_decl.position) - { - CMP(32, R(count_reg), Imm8(3)); - FixupBranch dont_store = J_CC(CC_A); - LEA(32, scratch3, MScaled(count_reg, SCALE_4, -4)); - MOVUPS(MPIC(VertexLoaderManager::position_cache, scratch3, SCALE_4), coords); - SetJumpTarget(dont_store); - } - return load_bytes; - } - } + // zfreeze + if (native_format == &m_native_vtx_decl.position) + { + CMP(32, R(count_reg), Imm8(3)); + FixupBranch dont_store = J_CC(CC_A); + LEA(32, scratch3, MScaled(count_reg, SCALE_4, -4)); + MOVUPS(MPIC(VertexLoaderManager::position_cache, scratch3, SCALE_4), coords); + SetJumpTarget(dont_store); + } + return load_bytes; + } + } - if (format != FORMAT_FLOAT) - { - CVTDQ2PS(coords, R(coords)); + if (format != FORMAT_FLOAT) + { + CVTDQ2PS(coords, R(coords)); - if (dequantize && scaling_exponent) - MULPS(coords, MPIC(&scale_factors[scaling_exponent])); - } + if (dequantize && scaling_exponent) + MULPS(coords, MPIC(&scale_factors[scaling_exponent])); + } - switch (count_out) - { - case 1: MOVSS(dest, coords); break; - case 2: MOVLPS(dest, coords); break; - case 3: MOVUPS(dest, coords); break; - } + switch (count_out) + { + case 1: + MOVSS(dest, coords); + break; + case 2: + MOVLPS(dest, coords); + break; + case 3: + MOVUPS(dest, coords); + break; + } - // zfreeze - if (native_format == &m_native_vtx_decl.position) - { - CMP(32, R(count_reg), Imm8(3)); - FixupBranch dont_store = J_CC(CC_A); - LEA(32, scratch3, MScaled(count_reg, SCALE_4, -4)); - MOVUPS(MPIC(VertexLoaderManager::position_cache, scratch3, SCALE_4), coords); - SetJumpTarget(dont_store); - } + // zfreeze + if (native_format == &m_native_vtx_decl.position) + { + CMP(32, R(count_reg), Imm8(3)); + FixupBranch dont_store = J_CC(CC_A); + LEA(32, scratch3, MScaled(count_reg, SCALE_4, -4)); + MOVUPS(MPIC(VertexLoaderManager::position_cache, scratch3, SCALE_4), coords); + SetJumpTarget(dont_store); + } - return load_bytes; + return load_bytes; } void VertexLoaderX64::ReadColor(OpArg data, u64 attribute, int format) { - int load_bytes = 0; - switch (format) - { - case FORMAT_24B_888: - case FORMAT_32B_888x: - case FORMAT_32B_8888: - MOV(32, R(scratch1), data); - if (format != FORMAT_32B_8888) - OR(32, R(scratch1), Imm32(0xFF000000)); - MOV(32, MDisp(dst_reg, m_dst_ofs), R(scratch1)); - load_bytes = 3 + (format != FORMAT_24B_888); - break; + int load_bytes = 0; + switch (format) + { + case FORMAT_24B_888: + case FORMAT_32B_888x: + case FORMAT_32B_8888: + MOV(32, R(scratch1), data); + if (format != FORMAT_32B_8888) + OR(32, R(scratch1), Imm32(0xFF000000)); + MOV(32, MDisp(dst_reg, m_dst_ofs), R(scratch1)); + load_bytes = 3 + (format != FORMAT_24B_888); + break; - case FORMAT_16B_565: - // RRRRRGGG GGGBBBBB - // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR - LoadAndSwap(16, scratch1, data); - if (cpu_info.bBMI1 && cpu_info.bBMI2) - { - MOV(32, R(scratch2), Imm32(0x07C3F7C0)); - PDEP(32, scratch3, scratch1, R(scratch2)); + case FORMAT_16B_565: + // RRRRRGGG GGGBBBBB + // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR + LoadAndSwap(16, scratch1, data); + if (cpu_info.bBMI1 && cpu_info.bBMI2) + { + MOV(32, R(scratch2), Imm32(0x07C3F7C0)); + PDEP(32, scratch3, scratch1, R(scratch2)); - MOV(32, R(scratch2), Imm32(0xF8FCF800)); - PDEP(32, scratch1, scratch1, R(scratch2)); - ANDN(32, scratch2, scratch2, R(scratch3)); + MOV(32, R(scratch2), Imm32(0xF8FCF800)); + PDEP(32, scratch1, scratch1, R(scratch2)); + ANDN(32, scratch2, scratch2, R(scratch3)); - OR(32, R(scratch1), R(scratch2)); - } - else - { - SHL(32, R(scratch1), Imm8(11)); - LEA(32, scratch2, MScaled(scratch1, SCALE_4, 0)); - LEA(32, scratch3, MScaled(scratch2, SCALE_8, 0)); - AND(32, R(scratch1), Imm32(0x0000F800)); - AND(32, R(scratch2), Imm32(0x00FC0000)); - AND(32, R(scratch3), Imm32(0xF8000000)); - OR(32, R(scratch1), R(scratch2)); - OR(32, R(scratch1), R(scratch3)); + OR(32, R(scratch1), R(scratch2)); + } + else + { + SHL(32, R(scratch1), Imm8(11)); + LEA(32, scratch2, MScaled(scratch1, SCALE_4, 0)); + LEA(32, scratch3, MScaled(scratch2, SCALE_8, 0)); + AND(32, R(scratch1), Imm32(0x0000F800)); + AND(32, R(scratch2), Imm32(0x00FC0000)); + AND(32, R(scratch3), Imm32(0xF8000000)); + OR(32, R(scratch1), R(scratch2)); + OR(32, R(scratch1), R(scratch3)); - MOV(32, R(scratch2), R(scratch1)); - SHR(32, R(scratch1), Imm8(5)); - AND(32, R(scratch1), Imm32(0x07000700)); - OR(32, R(scratch1), R(scratch2)); + MOV(32, R(scratch2), R(scratch1)); + SHR(32, R(scratch1), Imm8(5)); + AND(32, R(scratch1), Imm32(0x07000700)); + OR(32, R(scratch1), R(scratch2)); - SHR(32, R(scratch2), Imm8(6)); - AND(32, R(scratch2), Imm32(0x00030000)); - OR(32, R(scratch1), R(scratch2)); - } - OR(32, R(scratch1), Imm32(0x000000FF)); - SwapAndStore(32, MDisp(dst_reg, m_dst_ofs), scratch1); - load_bytes = 2; - break; + SHR(32, R(scratch2), Imm8(6)); + AND(32, R(scratch2), Imm32(0x00030000)); + OR(32, R(scratch1), R(scratch2)); + } + OR(32, R(scratch1), Imm32(0x000000FF)); + SwapAndStore(32, MDisp(dst_reg, m_dst_ofs), scratch1); + load_bytes = 2; + break; - case FORMAT_16B_4444: - // RRRRGGGG BBBBAAAA - // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR - LoadAndSwap(16, scratch1, data); - if (cpu_info.bBMI2) - { - MOV(32, R(scratch2), Imm32(0x0F0F0F0F)); - PDEP(32, scratch1, scratch1, R(scratch2)); - } - else - { - MOV(32, R(scratch2), R(scratch1)); - SHL(32, R(scratch1), Imm8(8)); - OR(32, R(scratch1), R(scratch2)); - AND(32, R(scratch1), Imm32(0x00FF00FF)); + case FORMAT_16B_4444: + // RRRRGGGG BBBBAAAA + // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR + LoadAndSwap(16, scratch1, data); + if (cpu_info.bBMI2) + { + MOV(32, R(scratch2), Imm32(0x0F0F0F0F)); + PDEP(32, scratch1, scratch1, R(scratch2)); + } + else + { + MOV(32, R(scratch2), R(scratch1)); + SHL(32, R(scratch1), Imm8(8)); + OR(32, R(scratch1), R(scratch2)); + AND(32, R(scratch1), Imm32(0x00FF00FF)); - MOV(32, R(scratch2), R(scratch1)); - SHL(32, R(scratch1), Imm8(4)); - OR(32, R(scratch1), R(scratch2)); - AND(32, R(scratch1), Imm32(0x0F0F0F0F)); - } - MOV(32, R(scratch2), R(scratch1)); - SHL(32, R(scratch1), Imm8(4)); - OR(32, R(scratch1), R(scratch2)); - SwapAndStore(32, MDisp(dst_reg, m_dst_ofs), scratch1); - load_bytes = 2; - break; + MOV(32, R(scratch2), R(scratch1)); + SHL(32, R(scratch1), Imm8(4)); + OR(32, R(scratch1), R(scratch2)); + AND(32, R(scratch1), Imm32(0x0F0F0F0F)); + } + MOV(32, R(scratch2), R(scratch1)); + SHL(32, R(scratch1), Imm8(4)); + OR(32, R(scratch1), R(scratch2)); + SwapAndStore(32, MDisp(dst_reg, m_dst_ofs), scratch1); + load_bytes = 2; + break; - case FORMAT_24B_6666: - // RRRRRRGG GGGGBBBB BBAAAAAA - // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR - data.AddMemOffset(-1); // subtract one from address so we can use a 32bit load and bswap - LoadAndSwap(32, scratch1, data); - if (cpu_info.bBMI2) - { - MOV(32, R(scratch2), Imm32(0xFCFCFCFC)); - PDEP(32, scratch1, scratch1, R(scratch2)); - MOV(32, R(scratch2), R(scratch1)); - } - else - { - LEA(32, scratch2, MScaled(scratch1, SCALE_4, 0)); // ______RR RRRRGGGG GGBBBBBB AAAAAA__ - AND(32, R(scratch2), Imm32(0x00003FFC)); // ________ ________ __BBBBBB AAAAAA__ - SHL(32, R(scratch1), Imm8(6)); // __RRRRRR GGGGGGBB BBBBAAAA AA______ - AND(32, R(scratch1), Imm32(0x3FFC0000)); // __RRRRRR GGGGGG__ ________ ________ - OR(32, R(scratch1), R(scratch2)); // __RRRRRR GGGGGG__ __BBBBBB AAAAAA__ + case FORMAT_24B_6666: + // RRRRRRGG GGGGBBBB BBAAAAAA + // AAAAAAAA BBBBBBBB GGGGGGGG RRRRRRRR + data.AddMemOffset(-1); // subtract one from address so we can use a 32bit load and bswap + LoadAndSwap(32, scratch1, data); + if (cpu_info.bBMI2) + { + MOV(32, R(scratch2), Imm32(0xFCFCFCFC)); + PDEP(32, scratch1, scratch1, R(scratch2)); + MOV(32, R(scratch2), R(scratch1)); + } + else + { + LEA(32, scratch2, MScaled(scratch1, SCALE_4, 0)); // ______RR RRRRGGGG GGBBBBBB AAAAAA__ + AND(32, R(scratch2), Imm32(0x00003FFC)); // ________ ________ __BBBBBB AAAAAA__ + SHL(32, R(scratch1), Imm8(6)); // __RRRRRR GGGGGGBB BBBBAAAA AA______ + AND(32, R(scratch1), Imm32(0x3FFC0000)); // __RRRRRR GGGGGG__ ________ ________ + OR(32, R(scratch1), R(scratch2)); // __RRRRRR GGGGGG__ __BBBBBB AAAAAA__ - LEA(32, scratch2, MScaled(scratch1, SCALE_4, 0)); // RRRRRRGG GGGG____ BBBBBBAA AAAA____ - AND(32, R(scratch2), Imm32(0xFC00FC00)); // RRRRRR__ ________ BBBBBB__ ________ - AND(32, R(scratch1), Imm32(0x00FC00FC)); // ________ GGGGGG__ ________ AAAAAA__ - OR(32, R(scratch1), R(scratch2)); // RRRRRR__ GGGGGG__ BBBBBB__ AAAAAA__ - MOV(32, R(scratch2), R(scratch1)); - } - SHR(32, R(scratch1), Imm8(6)); - AND(32, R(scratch1), Imm32(0x03030303)); - OR(32, R(scratch1), R(scratch2)); - SwapAndStore(32, MDisp(dst_reg, m_dst_ofs), scratch1); - load_bytes = 3; - break; - } - if (attribute == DIRECT) - m_src_ofs += load_bytes; + LEA(32, scratch2, MScaled(scratch1, SCALE_4, 0)); // RRRRRRGG GGGG____ BBBBBBAA AAAA____ + AND(32, R(scratch2), Imm32(0xFC00FC00)); // RRRRRR__ ________ BBBBBB__ ________ + AND(32, R(scratch1), Imm32(0x00FC00FC)); // ________ GGGGGG__ ________ AAAAAA__ + OR(32, R(scratch1), R(scratch2)); // RRRRRR__ GGGGGG__ BBBBBB__ AAAAAA__ + MOV(32, R(scratch2), R(scratch1)); + } + SHR(32, R(scratch1), Imm8(6)); + AND(32, R(scratch1), Imm32(0x03030303)); + OR(32, R(scratch1), R(scratch2)); + SwapAndStore(32, MDisp(dst_reg, m_dst_ofs), scratch1); + load_bytes = 3; + break; + } + if (attribute == DIRECT) + m_src_ofs += load_bytes; } void VertexLoaderX64::GenerateVertexLoader() { - BitSet32 regs = {src_reg, dst_reg, scratch1, scratch2, scratch3, count_reg, skipped_reg, base_reg}; - regs &= ABI_ALL_CALLEE_SAVED; - ABI_PushRegistersAndAdjustStack(regs, 0); + BitSet32 regs = {src_reg, dst_reg, scratch1, scratch2, + scratch3, count_reg, skipped_reg, base_reg}; + regs &= ABI_ALL_CALLEE_SAVED; + ABI_PushRegistersAndAdjustStack(regs, 0); - // Backup count since we're going to count it down. - PUSH(32, R(ABI_PARAM3)); + // Backup count since we're going to count it down. + PUSH(32, R(ABI_PARAM3)); - // ABI_PARAM3 is one of the lower registers, so free it for scratch2. - MOV(32, R(count_reg), R(ABI_PARAM3)); + // ABI_PARAM3 is one of the lower registers, so free it for scratch2. + MOV(32, R(count_reg), R(ABI_PARAM3)); - MOV(64, R(base_reg), R(ABI_PARAM4)); + MOV(64, R(base_reg), R(ABI_PARAM4)); - if (m_VtxDesc.Position & MASK_INDEXED) - XOR(32, R(skipped_reg), R(skipped_reg)); + if (m_VtxDesc.Position & MASK_INDEXED) + XOR(32, R(skipped_reg), R(skipped_reg)); - // TODO: load constants into registers outside the main loop + // TODO: load constants into registers outside the main loop - const u8* loop_start = GetCodePtr(); + const u8* loop_start = GetCodePtr(); - if (m_VtxDesc.PosMatIdx) - { - MOVZX(32, 8, scratch1, MDisp(src_reg, m_src_ofs)); - AND(32, R(scratch1), Imm8(0x3F)); - MOV(32, MDisp(dst_reg, m_dst_ofs), R(scratch1)); + if (m_VtxDesc.PosMatIdx) + { + MOVZX(32, 8, scratch1, MDisp(src_reg, m_src_ofs)); + AND(32, R(scratch1), Imm8(0x3F)); + MOV(32, MDisp(dst_reg, m_dst_ofs), R(scratch1)); - // zfreeze - CMP(32, R(count_reg), Imm8(3)); - FixupBranch dont_store = J_CC(CC_A); - MOV(32, MPIC(VertexLoaderManager::position_matrix_index - 1, count_reg, SCALE_4), R(scratch1)); - SetJumpTarget(dont_store); + // zfreeze + CMP(32, R(count_reg), Imm8(3)); + FixupBranch dont_store = J_CC(CC_A); + MOV(32, MPIC(VertexLoaderManager::position_matrix_index - 1, count_reg, SCALE_4), R(scratch1)); + SetJumpTarget(dont_store); - m_native_components |= VB_HAS_POSMTXIDX; - m_native_vtx_decl.posmtx.components = 4; - m_native_vtx_decl.posmtx.enable = true; - m_native_vtx_decl.posmtx.offset = m_dst_ofs; - m_native_vtx_decl.posmtx.type = VAR_UNSIGNED_BYTE; - m_native_vtx_decl.posmtx.integer = true; - m_src_ofs += sizeof(u8); - m_dst_ofs += sizeof(u32); - } + m_native_components |= VB_HAS_POSMTXIDX; + m_native_vtx_decl.posmtx.components = 4; + m_native_vtx_decl.posmtx.enable = true; + m_native_vtx_decl.posmtx.offset = m_dst_ofs; + m_native_vtx_decl.posmtx.type = VAR_UNSIGNED_BYTE; + m_native_vtx_decl.posmtx.integer = true; + m_src_ofs += sizeof(u8); + m_dst_ofs += sizeof(u32); + } - u32 texmatidx_ofs[8]; - const u64 tm[8] = { - m_VtxDesc.Tex0MatIdx, m_VtxDesc.Tex1MatIdx, m_VtxDesc.Tex2MatIdx, m_VtxDesc.Tex3MatIdx, - m_VtxDesc.Tex4MatIdx, m_VtxDesc.Tex5MatIdx, m_VtxDesc.Tex6MatIdx, m_VtxDesc.Tex7MatIdx, - }; - for (int i = 0; i < 8; i++) - { - if (tm[i]) - texmatidx_ofs[i] = m_src_ofs++; - } + u32 texmatidx_ofs[8]; + const u64 tm[8] = { + m_VtxDesc.Tex0MatIdx, m_VtxDesc.Tex1MatIdx, m_VtxDesc.Tex2MatIdx, m_VtxDesc.Tex3MatIdx, + m_VtxDesc.Tex4MatIdx, m_VtxDesc.Tex5MatIdx, m_VtxDesc.Tex6MatIdx, m_VtxDesc.Tex7MatIdx, + }; + for (int i = 0; i < 8; i++) + { + if (tm[i]) + texmatidx_ofs[i] = m_src_ofs++; + } - OpArg data = GetVertexAddr(ARRAY_POSITION, m_VtxDesc.Position); - int pos_elements = 2 + m_VtxAttr.PosElements; - ReadVertex(data, m_VtxDesc.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements, - m_VtxAttr.ByteDequant, m_VtxAttr.PosFrac, &m_native_vtx_decl.position); + OpArg data = GetVertexAddr(ARRAY_POSITION, m_VtxDesc.Position); + int pos_elements = 2 + m_VtxAttr.PosElements; + ReadVertex(data, m_VtxDesc.Position, m_VtxAttr.PosFormat, pos_elements, pos_elements, + m_VtxAttr.ByteDequant, m_VtxAttr.PosFrac, &m_native_vtx_decl.position); - if (m_VtxDesc.Normal) - { - static const u8 map[8] = { 7, 6, 15, 14 }; - u8 scaling_exponent = map[m_VtxAttr.NormalFormat]; + if (m_VtxDesc.Normal) + { + static const u8 map[8] = {7, 6, 15, 14}; + u8 scaling_exponent = map[m_VtxAttr.NormalFormat]; - for (int i = 0; i < (m_VtxAttr.NormalElements ? 3 : 1); i++) - { - if (!i || m_VtxAttr.NormalIndex3) - { - data = GetVertexAddr(ARRAY_NORMAL, m_VtxDesc.Normal); - int elem_size = 1 << (m_VtxAttr.NormalFormat / 2); - data.AddMemOffset(i * elem_size * 3); - } - data.AddMemOffset(ReadVertex(data, m_VtxDesc.Normal, m_VtxAttr.NormalFormat, 3, 3, - true, scaling_exponent, &m_native_vtx_decl.normals[i])); - } + for (int i = 0; i < (m_VtxAttr.NormalElements ? 3 : 1); i++) + { + if (!i || m_VtxAttr.NormalIndex3) + { + data = GetVertexAddr(ARRAY_NORMAL, m_VtxDesc.Normal); + int elem_size = 1 << (m_VtxAttr.NormalFormat / 2); + data.AddMemOffset(i * elem_size * 3); + } + data.AddMemOffset(ReadVertex(data, m_VtxDesc.Normal, m_VtxAttr.NormalFormat, 3, 3, true, + scaling_exponent, &m_native_vtx_decl.normals[i])); + } - m_native_components |= VB_HAS_NRM0; - if (m_VtxAttr.NormalElements) - m_native_components |= VB_HAS_NRM1 | VB_HAS_NRM2; - } + m_native_components |= VB_HAS_NRM0; + if (m_VtxAttr.NormalElements) + m_native_components |= VB_HAS_NRM1 | VB_HAS_NRM2; + } - const u64 col[2] = { m_VtxDesc.Color0, m_VtxDesc.Color1 }; - for (int i = 0; i < 2; i++) - { - if (col[i]) - { - data = GetVertexAddr(ARRAY_COLOR + i, col[i]); - ReadColor(data, col[i], m_VtxAttr.color[i].Comp); - m_native_components |= VB_HAS_COL0 << i; - m_native_vtx_decl.colors[i].components = 4; - m_native_vtx_decl.colors[i].enable = true; - m_native_vtx_decl.colors[i].offset = m_dst_ofs; - m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE; - m_native_vtx_decl.colors[i].integer = false; - m_dst_ofs += 4; - } - } + const u64 col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1}; + for (int i = 0; i < 2; i++) + { + if (col[i]) + { + data = GetVertexAddr(ARRAY_COLOR + i, col[i]); + ReadColor(data, col[i], m_VtxAttr.color[i].Comp); + m_native_components |= VB_HAS_COL0 << i; + m_native_vtx_decl.colors[i].components = 4; + m_native_vtx_decl.colors[i].enable = true; + m_native_vtx_decl.colors[i].offset = m_dst_ofs; + m_native_vtx_decl.colors[i].type = VAR_UNSIGNED_BYTE; + m_native_vtx_decl.colors[i].integer = false; + m_dst_ofs += 4; + } + } - const u64 tc[8] = { - m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord, m_VtxDesc.Tex3Coord, - m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, m_VtxDesc.Tex6Coord, m_VtxDesc.Tex7Coord, - }; - for (int i = 0; i < 8; i++) - { - int elements = m_VtxAttr.texCoord[i].Elements + 1; - if (tc[i]) - { - data = GetVertexAddr(ARRAY_TEXCOORD0 + i, tc[i]); - u8 scaling_exponent = m_VtxAttr.texCoord[i].Frac; - ReadVertex(data, tc[i], m_VtxAttr.texCoord[i].Format, elements, tm[i] ? 2 : elements, - m_VtxAttr.ByteDequant, scaling_exponent, &m_native_vtx_decl.texcoords[i]); - m_native_components |= VB_HAS_UV0 << i; - } - if (tm[i]) - { - m_native_components |= VB_HAS_TEXMTXIDX0 << i; - m_native_vtx_decl.texcoords[i].components = 3; - m_native_vtx_decl.texcoords[i].enable = true; - m_native_vtx_decl.texcoords[i].type = VAR_FLOAT; - m_native_vtx_decl.texcoords[i].integer = false; - MOVZX(64, 8, scratch1, MDisp(src_reg, texmatidx_ofs[i])); - if (tc[i]) - { - CVTSI2SS(XMM0, R(scratch1)); - MOVSS(MDisp(dst_reg, m_dst_ofs), XMM0); - m_dst_ofs += sizeof(float); - } - else - { - m_native_vtx_decl.texcoords[i].offset = m_dst_ofs; - PXOR(XMM0, R(XMM0)); - CVTSI2SS(XMM0, R(scratch1)); - SHUFPS(XMM0, R(XMM0), 0x45); // 000X -> 0X00 - MOVUPS(MDisp(dst_reg, m_dst_ofs), XMM0); - m_dst_ofs += sizeof(float) * 3; - } - } - } + const u64 tc[8] = { + m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord, m_VtxDesc.Tex3Coord, + m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, m_VtxDesc.Tex6Coord, m_VtxDesc.Tex7Coord, + }; + for (int i = 0; i < 8; i++) + { + int elements = m_VtxAttr.texCoord[i].Elements + 1; + if (tc[i]) + { + data = GetVertexAddr(ARRAY_TEXCOORD0 + i, tc[i]); + u8 scaling_exponent = m_VtxAttr.texCoord[i].Frac; + ReadVertex(data, tc[i], m_VtxAttr.texCoord[i].Format, elements, tm[i] ? 2 : elements, + m_VtxAttr.ByteDequant, scaling_exponent, &m_native_vtx_decl.texcoords[i]); + m_native_components |= VB_HAS_UV0 << i; + } + if (tm[i]) + { + m_native_components |= VB_HAS_TEXMTXIDX0 << i; + m_native_vtx_decl.texcoords[i].components = 3; + m_native_vtx_decl.texcoords[i].enable = true; + m_native_vtx_decl.texcoords[i].type = VAR_FLOAT; + m_native_vtx_decl.texcoords[i].integer = false; + MOVZX(64, 8, scratch1, MDisp(src_reg, texmatidx_ofs[i])); + if (tc[i]) + { + CVTSI2SS(XMM0, R(scratch1)); + MOVSS(MDisp(dst_reg, m_dst_ofs), XMM0); + m_dst_ofs += sizeof(float); + } + else + { + m_native_vtx_decl.texcoords[i].offset = m_dst_ofs; + PXOR(XMM0, R(XMM0)); + CVTSI2SS(XMM0, R(scratch1)); + SHUFPS(XMM0, R(XMM0), 0x45); // 000X -> 0X00 + MOVUPS(MDisp(dst_reg, m_dst_ofs), XMM0); + m_dst_ofs += sizeof(float) * 3; + } + } + } - // Prepare for the next vertex. - ADD(64, R(dst_reg), Imm32(m_dst_ofs)); - const u8* cont = GetCodePtr(); - ADD(64, R(src_reg), Imm32(m_src_ofs)); + // Prepare for the next vertex. + ADD(64, R(dst_reg), Imm32(m_dst_ofs)); + const u8* cont = GetCodePtr(); + ADD(64, R(src_reg), Imm32(m_src_ofs)); - SUB(32, R(count_reg), Imm8(1)); - J_CC(CC_NZ, loop_start); + SUB(32, R(count_reg), Imm8(1)); + J_CC(CC_NZ, loop_start); - // Get the original count. - POP(32, R(ABI_RETURN)); + // Get the original count. + POP(32, R(ABI_RETURN)); - ABI_PopRegistersAndAdjustStack(regs, 0); + ABI_PopRegistersAndAdjustStack(regs, 0); - if (m_VtxDesc.Position & MASK_INDEXED) - { - SUB(32, R(ABI_RETURN), R(skipped_reg)); - RET(); + if (m_VtxDesc.Position & MASK_INDEXED) + { + SUB(32, R(ABI_RETURN), R(skipped_reg)); + RET(); - SetJumpTarget(m_skip_vertex); - ADD(32, R(skipped_reg), Imm8(1)); - JMP(cont); - } - else - { - RET(); - } + SetJumpTarget(m_skip_vertex); + ADD(32, R(skipped_reg), Imm8(1)); + JMP(cont); + } + else + { + RET(); + } - m_VertexSize = m_src_ofs; - m_native_vtx_decl.stride = m_dst_ofs; + m_VertexSize = m_src_ofs; + m_native_vtx_decl.stride = m_dst_ofs; } int VertexLoaderX64::RunVertices(DataReader src, DataReader dst, int count) { - m_numLoadedVertices += count; - return ((int (*)(u8*, u8*, int, const void*))region)( - src.GetPointer(), - dst.GetPointer(), - count, - memory_base_ptr); + m_numLoadedVertices += count; + return ((int (*)(u8*, u8*, int, const void*))region)(src.GetPointer(), dst.GetPointer(), count, + memory_base_ptr); } diff --git a/Source/Core/VideoCommon/VertexLoaderX64.h b/Source/Core/VideoCommon/VertexLoaderX64.h index 87539acaaf..811b2e4427 100644 --- a/Source/Core/VideoCommon/VertexLoaderX64.h +++ b/Source/Core/VideoCommon/VertexLoaderX64.h @@ -9,19 +9,20 @@ class VertexLoaderX64 : public VertexLoaderBase, public Gen::X64CodeBlock { public: - VertexLoaderX64(const TVtxDesc& vtx_desc, const VAT& vtx_att); + VertexLoaderX64(const TVtxDesc& vtx_desc, const VAT& vtx_att); protected: - std::string GetName() const override { return "VertexLoaderX64"; } - bool IsInitialized() override { return true; } - int RunVertices(DataReader src, DataReader dst, int count) override; + std::string GetName() const override { return "VertexLoaderX64"; } + bool IsInitialized() override { return true; } + int RunVertices(DataReader src, DataReader dst, int count) override; private: - u32 m_src_ofs = 0; - u32 m_dst_ofs = 0; - Gen::FixupBranch m_skip_vertex; - Gen::OpArg GetVertexAddr(int array, u64 attribute); - int ReadVertex(Gen::OpArg data, u64 attribute, int format, int count_in, int count_out, bool dequantize, u8 scaling_exponent, AttributeFormat* native_format); - void ReadColor(Gen::OpArg data, u64 attribute, int format); - void GenerateVertexLoader(); + u32 m_src_ofs = 0; + u32 m_dst_ofs = 0; + Gen::FixupBranch m_skip_vertex; + Gen::OpArg GetVertexAddr(int array, u64 attribute); + int ReadVertex(Gen::OpArg data, u64 attribute, int format, int count_in, int count_out, + bool dequantize, u8 scaling_exponent, AttributeFormat* native_format); + void ReadColor(Gen::OpArg data, u64 attribute, int format); + void GenerateVertexLoader(); }; diff --git a/Source/Core/VideoCommon/VertexLoader_Color.cpp b/Source/Core/VideoCommon/VertexLoader_Color.cpp index 5d8d4e8bd2..8ae672f6e0 100644 --- a/Source/Core/VideoCommon/VertexLoader_Color.cpp +++ b/Source/Core/VideoCommon/VertexLoader_Color.cpp @@ -7,168 +7,212 @@ #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" #include "VideoCommon/VertexLoader.h" -#include "VideoCommon/VertexLoader_Color.h" #include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexLoaderUtils.h" +#include "VideoCommon/VertexLoader_Color.h" #define AMASK 0xFF000000 static void SetCol(VertexLoader* loader, u32 val) { - DataWrite(val); - loader->m_colIndex++; + DataWrite(val); + loader->m_colIndex++; } // Color comes in format BARG in 16 bits // BARG -> AABBGGRR static void SetCol4444(VertexLoader* loader, u16 val_) { - u32 col, val = val_; - col = val & 0x00F0; // col = 000000R0; - col |= (val & 0x000F) << 12; // col |= 0000G000; - col |= (val & 0xF000) << 8; // col |= 00B00000; - col |= (val & 0x0F00) << 20; // col |= A0000000; - col |= col >> 4; // col = A0B0G0R0 | 0A0B0G0R; - SetCol(loader, col); + u32 col, val = val_; + col = val & 0x00F0; // col = 000000R0; + col |= (val & 0x000F) << 12; // col |= 0000G000; + col |= (val & 0xF000) << 8; // col |= 00B00000; + col |= (val & 0x0F00) << 20; // col |= A0000000; + col |= col >> 4; // col = A0B0G0R0 | 0A0B0G0R; + SetCol(loader, col); } // Color comes in format RGBA // RRRRRRGG GGGGBBBB BBAAAAAA static void SetCol6666(VertexLoader* loader, u32 val) { - u32 col = (val >> 16) & 0x000000FC; - col |= (val >> 2) & 0x0000FC00; - col |= (val << 12) & 0x00FC0000; - col |= (val << 26) & 0xFC000000; - col |= (col >> 6) & 0x03030303; - SetCol(loader, col); + u32 col = (val >> 16) & 0x000000FC; + col |= (val >> 2) & 0x0000FC00; + col |= (val << 12) & 0x00FC0000; + col |= (val << 26) & 0xFC000000; + col |= (col >> 6) & 0x03030303; + SetCol(loader, col); } // Color comes in RGB // RRRRRGGG GGGBBBBB static void SetCol565(VertexLoader* loader, u16 val_) { - u32 col, val = val_; - col = (val >> 8) & 0x0000F8; - col |= (val << 5) & 0x00FC00; - col |= (val << 19) & 0xF80000; - col |= (col >> 5) & 0x070007; - col |= (col >> 6) & 0x000300; - SetCol(loader, col | AMASK); + u32 col, val = val_; + col = (val >> 8) & 0x0000F8; + col |= (val << 5) & 0x00FC00; + col |= (val << 19) & 0xF80000; + col |= (col >> 5) & 0x070007; + col |= (col >> 6) & 0x000300; + SetCol(loader, col | AMASK); } static u32 Read32(const u8* addr) { - u32 value; - std::memcpy(&value, addr, sizeof(u32)); - return value; + u32 value; + std::memcpy(&value, addr, sizeof(u32)); + return value; } static u32 Read24(const u8* addr) { - return Read32(addr) | AMASK; + return Read32(addr) | AMASK; } void Color_ReadDirect_24b_888(VertexLoader* loader) { - SetCol(loader, Read24(DataGetPosition())); - DataSkip(3); + SetCol(loader, Read24(DataGetPosition())); + DataSkip(3); } void Color_ReadDirect_32b_888x(VertexLoader* loader) { - SetCol(loader, Read24(DataGetPosition())); - DataSkip(4); + SetCol(loader, Read24(DataGetPosition())); + DataSkip(4); } void Color_ReadDirect_16b_565(VertexLoader* loader) { - SetCol565(loader, DataRead()); + SetCol565(loader, DataRead()); } void Color_ReadDirect_16b_4444(VertexLoader* loader) { - u16 value; - std::memcpy(&value, DataGetPosition(), sizeof(u16)); + u16 value; + std::memcpy(&value, DataGetPosition(), sizeof(u16)); - SetCol4444(loader, value); - DataSkip(2); + SetCol4444(loader, value); + DataSkip(2); } void Color_ReadDirect_24b_6666(VertexLoader* loader) { - SetCol6666(loader, Common::swap32(DataGetPosition() - 1)); - DataSkip(3); + SetCol6666(loader, Common::swap32(DataGetPosition() - 1)); + DataSkip(3); } void Color_ReadDirect_32b_8888(VertexLoader* loader) { - SetCol(loader, DataReadU32Unswapped()); + SetCol(loader, DataReadU32Unswapped()); } template void Color_ReadIndex_16b_565(VertexLoader* loader) { - auto const Index = DataRead(); - const u8* const address = VertexLoaderManager::cached_arraybases[ARRAY_COLOR + loader->m_colIndex] + (Index * g_main_cp_state.array_strides[ARRAY_COLOR + loader->m_colIndex]); + auto const Index = DataRead(); + const u8* const address = + VertexLoaderManager::cached_arraybases[ARRAY_COLOR + loader->m_colIndex] + + (Index * g_main_cp_state.array_strides[ARRAY_COLOR + loader->m_colIndex]); - u16 value; - std::memcpy(&value, address, sizeof(u16)); + u16 value; + std::memcpy(&value, address, sizeof(u16)); - SetCol565(loader, Common::swap16(value)); + SetCol565(loader, Common::swap16(value)); } template void Color_ReadIndex_24b_888(VertexLoader* loader) { - auto const Index = DataRead(); - const u8 *iAddress = VertexLoaderManager::cached_arraybases[ARRAY_COLOR + loader->m_colIndex] + (Index * g_main_cp_state.array_strides[ARRAY_COLOR + loader->m_colIndex]); - SetCol(loader, Read24(iAddress)); + auto const Index = DataRead(); + const u8* iAddress = VertexLoaderManager::cached_arraybases[ARRAY_COLOR + loader->m_colIndex] + + (Index * g_main_cp_state.array_strides[ARRAY_COLOR + loader->m_colIndex]); + SetCol(loader, Read24(iAddress)); } template void Color_ReadIndex_32b_888x(VertexLoader* loader) { - auto const Index = DataRead(); - const u8 *iAddress = VertexLoaderManager::cached_arraybases[ARRAY_COLOR + loader->m_colIndex] + (Index * g_main_cp_state.array_strides[ARRAY_COLOR + loader->m_colIndex]); - SetCol(loader, Read24(iAddress)); + auto const Index = DataRead(); + const u8* iAddress = VertexLoaderManager::cached_arraybases[ARRAY_COLOR + loader->m_colIndex] + + (Index * g_main_cp_state.array_strides[ARRAY_COLOR + loader->m_colIndex]); + SetCol(loader, Read24(iAddress)); } template void Color_ReadIndex_16b_4444(VertexLoader* loader) { - auto const Index = DataRead(); - const u8* const address = VertexLoaderManager::cached_arraybases[ARRAY_COLOR + loader->m_colIndex] + (Index * g_main_cp_state.array_strides[ARRAY_COLOR + loader->m_colIndex]); + auto const Index = DataRead(); + const u8* const address = + VertexLoaderManager::cached_arraybases[ARRAY_COLOR + loader->m_colIndex] + + (Index * g_main_cp_state.array_strides[ARRAY_COLOR + loader->m_colIndex]); - u16 value; - std::memcpy(&value, address, sizeof(u16)); + u16 value; + std::memcpy(&value, address, sizeof(u16)); - SetCol4444(loader, value); + SetCol4444(loader, value); } template void Color_ReadIndex_24b_6666(VertexLoader* loader) { - auto const Index = DataRead(); - const u8* pData = VertexLoaderManager::cached_arraybases[ARRAY_COLOR + loader->m_colIndex] + (Index * g_main_cp_state.array_strides[ARRAY_COLOR + loader->m_colIndex]) - 1; - u32 val = Common::swap32(pData); - SetCol6666(loader, val); + auto const Index = DataRead(); + const u8* pData = VertexLoaderManager::cached_arraybases[ARRAY_COLOR + loader->m_colIndex] + + (Index * g_main_cp_state.array_strides[ARRAY_COLOR + loader->m_colIndex]) - 1; + u32 val = Common::swap32(pData); + SetCol6666(loader, val); } template void Color_ReadIndex_32b_8888(VertexLoader* loader) { - auto const Index = DataRead(); - const u8 *iAddress = VertexLoaderManager::cached_arraybases[ARRAY_COLOR + loader->m_colIndex] + (Index * g_main_cp_state.array_strides[ARRAY_COLOR + loader->m_colIndex]); - SetCol(loader, Read32(iAddress)); + auto const Index = DataRead(); + const u8* iAddress = VertexLoaderManager::cached_arraybases[ARRAY_COLOR + loader->m_colIndex] + + (Index * g_main_cp_state.array_strides[ARRAY_COLOR + loader->m_colIndex]); + SetCol(loader, Read32(iAddress)); } -void Color_ReadIndex8_16b_565(VertexLoader* loader) { Color_ReadIndex_16b_565(loader); } -void Color_ReadIndex8_24b_888(VertexLoader* loader) { Color_ReadIndex_24b_888(loader); } -void Color_ReadIndex8_32b_888x(VertexLoader* loader) { Color_ReadIndex_32b_888x(loader); } -void Color_ReadIndex8_16b_4444(VertexLoader* loader) { Color_ReadIndex_16b_4444(loader); } -void Color_ReadIndex8_24b_6666(VertexLoader* loader) { Color_ReadIndex_24b_6666(loader); } -void Color_ReadIndex8_32b_8888(VertexLoader* loader) { Color_ReadIndex_32b_8888(loader); } +void Color_ReadIndex8_16b_565(VertexLoader* loader) +{ + Color_ReadIndex_16b_565(loader); +} +void Color_ReadIndex8_24b_888(VertexLoader* loader) +{ + Color_ReadIndex_24b_888(loader); +} +void Color_ReadIndex8_32b_888x(VertexLoader* loader) +{ + Color_ReadIndex_32b_888x(loader); +} +void Color_ReadIndex8_16b_4444(VertexLoader* loader) +{ + Color_ReadIndex_16b_4444(loader); +} +void Color_ReadIndex8_24b_6666(VertexLoader* loader) +{ + Color_ReadIndex_24b_6666(loader); +} +void Color_ReadIndex8_32b_8888(VertexLoader* loader) +{ + Color_ReadIndex_32b_8888(loader); +} -void Color_ReadIndex16_16b_565(VertexLoader* loader) { Color_ReadIndex_16b_565(loader); } -void Color_ReadIndex16_24b_888(VertexLoader* loader) { Color_ReadIndex_24b_888(loader); } -void Color_ReadIndex16_32b_888x(VertexLoader* loader) { Color_ReadIndex_32b_888x(loader); } -void Color_ReadIndex16_16b_4444(VertexLoader* loader) { Color_ReadIndex_16b_4444(loader); } -void Color_ReadIndex16_24b_6666(VertexLoader* loader) { Color_ReadIndex_24b_6666(loader); } -void Color_ReadIndex16_32b_8888(VertexLoader* loader) { Color_ReadIndex_32b_8888(loader); } +void Color_ReadIndex16_16b_565(VertexLoader* loader) +{ + Color_ReadIndex_16b_565(loader); +} +void Color_ReadIndex16_24b_888(VertexLoader* loader) +{ + Color_ReadIndex_24b_888(loader); +} +void Color_ReadIndex16_32b_888x(VertexLoader* loader) +{ + Color_ReadIndex_32b_888x(loader); +} +void Color_ReadIndex16_16b_4444(VertexLoader* loader) +{ + Color_ReadIndex_16b_4444(loader); +} +void Color_ReadIndex16_24b_6666(VertexLoader* loader) +{ + Color_ReadIndex_24b_6666(loader); +} +void Color_ReadIndex16_32b_8888(VertexLoader* loader) +{ + Color_ReadIndex_32b_8888(loader); +} diff --git a/Source/Core/VideoCommon/VertexLoader_Normal.cpp b/Source/Core/VideoCommon/VertexLoader_Normal.cpp index 12c9cbca71..c780d88cf7 100644 --- a/Source/Core/VideoCommon/VertexLoader_Normal.cpp +++ b/Source/Core/VideoCommon/VertexLoader_Normal.cpp @@ -10,182 +10,180 @@ #include "Common/CommonTypes.h" #include "VideoCommon/DataReader.h" #include "VideoCommon/VertexLoader.h" -#include "VideoCommon/VertexLoader_Normal.h" #include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexLoaderUtils.h" +#include "VideoCommon/VertexLoader_Normal.h" // warning: mapping buffer should be disabled to use this -#define LOG_NORM() // PRIM_LOG("norm: %f %f %f, ", ((float*)g_vertex_manager_write_ptr)[-3], ((float*)g_vertex_manager_write_ptr)[-2], ((float*)g_vertex_manager_write_ptr)[-1]); +#define LOG_NORM() // PRIM_LOG("norm: %f %f %f, ", ((float*)g_vertex_manager_write_ptr)[-3], + // ((float*)g_vertex_manager_write_ptr)[-2], + // ((float*)g_vertex_manager_write_ptr)[-1]); -VertexLoader_Normal::Set VertexLoader_Normal::m_Table[NUM_NRM_TYPE][NUM_NRM_INDICES][NUM_NRM_ELEMENTS][NUM_NRM_FORMAT]; +VertexLoader_Normal::Set VertexLoader_Normal::m_Table[NUM_NRM_TYPE][NUM_NRM_INDICES] + [NUM_NRM_ELEMENTS][NUM_NRM_FORMAT]; namespace { - template __forceinline float FracAdjust(T val) { - //auto const S8FRAC = 1.f / (1u << 6); - //auto const U8FRAC = 1.f / (1u << 7); - //auto const S16FRAC = 1.f / (1u << 14); - //auto const U16FRAC = 1.f / (1u << 15); + // auto const S8FRAC = 1.f / (1u << 6); + // auto const U8FRAC = 1.f / (1u << 7); + // auto const S16FRAC = 1.f / (1u << 14); + // auto const U16FRAC = 1.f / (1u << 15); - // TODO: is this right? - return val / float(1u << (sizeof(T) * 8 - std::is_signed::value - 1)); + // TODO: is this right? + return val / float(1u << (sizeof(T) * 8 - std::is_signed::value - 1)); } template <> __forceinline float FracAdjust(float val) { - return val; + return val; } template __forceinline void ReadIndirect(const T* data) { - static_assert(3 == N || 9 == N, "N is only sane as 3 or 9!"); - DataReader dst(g_vertex_manager_write_ptr, nullptr); + static_assert(3 == N || 9 == N, "N is only sane as 3 or 9!"); + DataReader dst(g_vertex_manager_write_ptr, nullptr); - for (int i = 0; i != N; ++i) - { - dst.Write(FracAdjust(Common::FromBigEndian(data[i]))); - } + for (int i = 0; i != N; ++i) + { + dst.Write(FracAdjust(Common::FromBigEndian(data[i]))); + } - g_vertex_manager_write_ptr = dst.GetPointer(); - LOG_NORM(); + g_vertex_manager_write_ptr = dst.GetPointer(); + LOG_NORM(); } template struct Normal_Direct { - static void function(VertexLoader* loader) - { - auto const source = reinterpret_cast(DataGetPosition()); - ReadIndirect(source); - DataSkip(); - } + static void function(VertexLoader* loader) + { + auto const source = reinterpret_cast(DataGetPosition()); + ReadIndirect(source); + DataSkip(); + } - static const int size = sizeof(T) * N * 3; + static const int size = sizeof(T) * N * 3; }; template __forceinline void Normal_Index_Offset() { - static_assert(std::is_unsigned::value, "Only unsigned I is sane!"); + static_assert(std::is_unsigned::value, "Only unsigned I is sane!"); - auto const index = DataRead(); - auto const data = reinterpret_cast(VertexLoaderManager::cached_arraybases[ARRAY_NORMAL] - + (index * g_main_cp_state.array_strides[ARRAY_NORMAL]) + sizeof(T) * 3 * Offset); - ReadIndirect(data); + auto const index = DataRead(); + auto const data = reinterpret_cast( + VertexLoaderManager::cached_arraybases[ARRAY_NORMAL] + + (index * g_main_cp_state.array_strides[ARRAY_NORMAL]) + sizeof(T) * 3 * Offset); + ReadIndirect(data); } template struct Normal_Index { - static void function(VertexLoader* loader) - { - Normal_Index_Offset(); - } - - static const int size = sizeof(I); + static void function(VertexLoader* loader) { Normal_Index_Offset(); } + static const int size = sizeof(I); }; template struct Normal_Index_Indices3 { - static void function(VertexLoader* loader) - { - Normal_Index_Offset(); - Normal_Index_Offset(); - Normal_Index_Offset(); - } + static void function(VertexLoader* loader) + { + Normal_Index_Offset(); + Normal_Index_Offset(); + Normal_Index_Offset(); + } - static const int size = sizeof(I) * 3; + static const int size = sizeof(I) * 3; }; - } void VertexLoader_Normal::Init() { - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT] [FORMAT_UBYTE] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT] [FORMAT_BYTE] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT] [FORMAT_USHORT] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT] [FORMAT_SHORT] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT] [FORMAT_FLOAT] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT3][FORMAT_UBYTE] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT3][FORMAT_BYTE] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT3][FORMAT_USHORT] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT3][FORMAT_SHORT] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES1][NRM_NBT3][FORMAT_FLOAT] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES1][NRM_NBT][FORMAT_UBYTE] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES1][NRM_NBT][FORMAT_BYTE] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES1][NRM_NBT][FORMAT_USHORT] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES1][NRM_NBT][FORMAT_SHORT] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES1][NRM_NBT][FORMAT_FLOAT] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES1][NRM_NBT3][FORMAT_UBYTE] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES1][NRM_NBT3][FORMAT_BYTE] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES1][NRM_NBT3][FORMAT_USHORT] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES1][NRM_NBT3][FORMAT_SHORT] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES1][NRM_NBT3][FORMAT_FLOAT] = Normal_Direct(); - // Same as above - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT] [FORMAT_UBYTE] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT] [FORMAT_BYTE] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT] [FORMAT_USHORT] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT] [FORMAT_SHORT] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT] [FORMAT_FLOAT] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT3][FORMAT_UBYTE] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT3][FORMAT_BYTE] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT3][FORMAT_USHORT] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT3][FORMAT_SHORT] = Normal_Direct(); - m_Table[NRM_DIRECT] [NRM_INDICES3][NRM_NBT3][FORMAT_FLOAT] = Normal_Direct(); + // Same as above + m_Table[NRM_DIRECT][NRM_INDICES3][NRM_NBT][FORMAT_UBYTE] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES3][NRM_NBT][FORMAT_BYTE] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES3][NRM_NBT][FORMAT_USHORT] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES3][NRM_NBT][FORMAT_SHORT] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES3][NRM_NBT][FORMAT_FLOAT] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES3][NRM_NBT3][FORMAT_UBYTE] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES3][NRM_NBT3][FORMAT_BYTE] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES3][NRM_NBT3][FORMAT_USHORT] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES3][NRM_NBT3][FORMAT_SHORT] = Normal_Direct(); + m_Table[NRM_DIRECT][NRM_INDICES3][NRM_NBT3][FORMAT_FLOAT] = Normal_Direct(); - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT] [FORMAT_UBYTE] = Normal_Index(); - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT] [FORMAT_BYTE] = Normal_Index(); - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT] [FORMAT_USHORT] = Normal_Index(); - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT] [FORMAT_SHORT] = Normal_Index(); - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT] [FORMAT_FLOAT] = Normal_Index(); - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT3][FORMAT_UBYTE] = Normal_Index(); - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT3][FORMAT_BYTE] = Normal_Index(); - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT3][FORMAT_USHORT] = Normal_Index(); - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT3][FORMAT_SHORT] = Normal_Index(); - m_Table[NRM_INDEX8] [NRM_INDICES1][NRM_NBT3][FORMAT_FLOAT] = Normal_Index(); + m_Table[NRM_INDEX8][NRM_INDICES1][NRM_NBT][FORMAT_UBYTE] = Normal_Index(); + m_Table[NRM_INDEX8][NRM_INDICES1][NRM_NBT][FORMAT_BYTE] = Normal_Index(); + m_Table[NRM_INDEX8][NRM_INDICES1][NRM_NBT][FORMAT_USHORT] = Normal_Index(); + m_Table[NRM_INDEX8][NRM_INDICES1][NRM_NBT][FORMAT_SHORT] = Normal_Index(); + m_Table[NRM_INDEX8][NRM_INDICES1][NRM_NBT][FORMAT_FLOAT] = Normal_Index(); + m_Table[NRM_INDEX8][NRM_INDICES1][NRM_NBT3][FORMAT_UBYTE] = Normal_Index(); + m_Table[NRM_INDEX8][NRM_INDICES1][NRM_NBT3][FORMAT_BYTE] = Normal_Index(); + m_Table[NRM_INDEX8][NRM_INDICES1][NRM_NBT3][FORMAT_USHORT] = Normal_Index(); + m_Table[NRM_INDEX8][NRM_INDICES1][NRM_NBT3][FORMAT_SHORT] = Normal_Index(); + m_Table[NRM_INDEX8][NRM_INDICES1][NRM_NBT3][FORMAT_FLOAT] = Normal_Index(); - // Same as above for NRM_NBT - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT] [FORMAT_UBYTE] = Normal_Index(); - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT] [FORMAT_BYTE] = Normal_Index(); - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT] [FORMAT_USHORT] = Normal_Index(); - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT] [FORMAT_SHORT] = Normal_Index(); - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT] [FORMAT_FLOAT] = Normal_Index(); - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT3][FORMAT_UBYTE] = Normal_Index_Indices3(); - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT3][FORMAT_BYTE] = Normal_Index_Indices3(); - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT3][FORMAT_USHORT] = Normal_Index_Indices3(); - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT3][FORMAT_SHORT] = Normal_Index_Indices3(); - m_Table[NRM_INDEX8] [NRM_INDICES3][NRM_NBT3][FORMAT_FLOAT] = Normal_Index_Indices3(); + // Same as above for NRM_NBT + m_Table[NRM_INDEX8][NRM_INDICES3][NRM_NBT][FORMAT_UBYTE] = Normal_Index(); + m_Table[NRM_INDEX8][NRM_INDICES3][NRM_NBT][FORMAT_BYTE] = Normal_Index(); + m_Table[NRM_INDEX8][NRM_INDICES3][NRM_NBT][FORMAT_USHORT] = Normal_Index(); + m_Table[NRM_INDEX8][NRM_INDICES3][NRM_NBT][FORMAT_SHORT] = Normal_Index(); + m_Table[NRM_INDEX8][NRM_INDICES3][NRM_NBT][FORMAT_FLOAT] = Normal_Index(); + m_Table[NRM_INDEX8][NRM_INDICES3][NRM_NBT3][FORMAT_UBYTE] = Normal_Index_Indices3(); + m_Table[NRM_INDEX8][NRM_INDICES3][NRM_NBT3][FORMAT_BYTE] = Normal_Index_Indices3(); + m_Table[NRM_INDEX8][NRM_INDICES3][NRM_NBT3][FORMAT_USHORT] = Normal_Index_Indices3(); + m_Table[NRM_INDEX8][NRM_INDICES3][NRM_NBT3][FORMAT_SHORT] = Normal_Index_Indices3(); + m_Table[NRM_INDEX8][NRM_INDICES3][NRM_NBT3][FORMAT_FLOAT] = Normal_Index_Indices3(); - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT] [FORMAT_UBYTE] = Normal_Index(); - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT] [FORMAT_BYTE] = Normal_Index(); - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT] [FORMAT_USHORT] = Normal_Index(); - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT] [FORMAT_SHORT] = Normal_Index(); - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT] [FORMAT_FLOAT] = Normal_Index(); - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_UBYTE] = Normal_Index(); - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_BYTE] = Normal_Index(); - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_USHORT] = Normal_Index(); - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_SHORT] = Normal_Index(); - m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_FLOAT] = Normal_Index(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT][FORMAT_UBYTE] = Normal_Index(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT][FORMAT_BYTE] = Normal_Index(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT][FORMAT_USHORT] = Normal_Index(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT][FORMAT_SHORT] = Normal_Index(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT][FORMAT_FLOAT] = Normal_Index(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_UBYTE] = Normal_Index(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_BYTE] = Normal_Index(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_USHORT] = Normal_Index(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_SHORT] = Normal_Index(); + m_Table[NRM_INDEX16][NRM_INDICES1][NRM_NBT3][FORMAT_FLOAT] = Normal_Index(); - // Same as above for NRM_NBT - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT] [FORMAT_UBYTE] = Normal_Index(); - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT] [FORMAT_BYTE] = Normal_Index(); - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT] [FORMAT_USHORT] = Normal_Index(); - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT] [FORMAT_SHORT] = Normal_Index(); - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT] [FORMAT_FLOAT] = Normal_Index(); - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_UBYTE] = Normal_Index_Indices3(); - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_BYTE] = Normal_Index_Indices3(); - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_USHORT] = Normal_Index_Indices3(); - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_SHORT] = Normal_Index_Indices3(); - m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_FLOAT] = Normal_Index_Indices3(); + // Same as above for NRM_NBT + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT][FORMAT_UBYTE] = Normal_Index(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT][FORMAT_BYTE] = Normal_Index(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT][FORMAT_USHORT] = Normal_Index(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT][FORMAT_SHORT] = Normal_Index(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT][FORMAT_FLOAT] = Normal_Index(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_UBYTE] = Normal_Index_Indices3(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_BYTE] = Normal_Index_Indices3(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_USHORT] = Normal_Index_Indices3(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_SHORT] = Normal_Index_Indices3(); + m_Table[NRM_INDEX16][NRM_INDICES3][NRM_NBT3][FORMAT_FLOAT] = Normal_Index_Indices3(); } -unsigned int VertexLoader_Normal::GetSize(u64 _type, - unsigned int _format, unsigned int _elements, unsigned int _index3) +unsigned int VertexLoader_Normal::GetSize(u64 _type, unsigned int _format, unsigned int _elements, + unsigned int _index3) { - return m_Table[_type][_index3][_elements][_format].gc_size; + return m_Table[_type][_index3][_elements][_format].gc_size; } -TPipelineFunction VertexLoader_Normal::GetFunction(u64 _type, - unsigned int _format, unsigned int _elements, unsigned int _index3) +TPipelineFunction VertexLoader_Normal::GetFunction(u64 _type, unsigned int _format, + unsigned int _elements, unsigned int _index3) { - TPipelineFunction pFunc = m_Table[_type][_index3][_elements][_format].function; - return pFunc; + TPipelineFunction pFunc = m_Table[_type][_index3][_elements][_format].function; + return pFunc; } diff --git a/Source/Core/VideoCommon/VertexLoader_Normal.h b/Source/Core/VideoCommon/VertexLoader_Normal.h index d2a817eaeb..811d2d05a7 100644 --- a/Source/Core/VideoCommon/VertexLoader_Normal.h +++ b/Source/Core/VideoCommon/VertexLoader_Normal.h @@ -9,64 +9,63 @@ class VertexLoader_Normal { public: + // Init + static void Init(); - // Init - static void Init(); + // GetSize + static unsigned int GetSize(u64 _type, unsigned int _format, unsigned int _elements, + unsigned int _index3); - // GetSize - static unsigned int GetSize(u64 _type, unsigned int _format, - unsigned int _elements, unsigned int _index3); - - // GetFunction - static TPipelineFunction GetFunction(u64 _type, - unsigned int _format, unsigned int _elements, unsigned int _index3); + // GetFunction + static TPipelineFunction GetFunction(u64 _type, unsigned int _format, unsigned int _elements, + unsigned int _index3); private: - enum ENormalType - { - NRM_NOT_PRESENT = 0, - NRM_DIRECT = 1, - NRM_INDEX8 = 2, - NRM_INDEX16 = 3, - NUM_NRM_TYPE - }; + enum ENormalType + { + NRM_NOT_PRESENT = 0, + NRM_DIRECT = 1, + NRM_INDEX8 = 2, + NRM_INDEX16 = 3, + NUM_NRM_TYPE + }; - enum ENormalFormat - { - FORMAT_UBYTE = 0, - FORMAT_BYTE = 1, - FORMAT_USHORT = 2, - FORMAT_SHORT = 3, - FORMAT_FLOAT = 4, - NUM_NRM_FORMAT - }; + enum ENormalFormat + { + FORMAT_UBYTE = 0, + FORMAT_BYTE = 1, + FORMAT_USHORT = 2, + FORMAT_SHORT = 3, + FORMAT_FLOAT = 4, + NUM_NRM_FORMAT + }; - enum ENormalElements - { - NRM_NBT = 0, - NRM_NBT3 = 1, - NUM_NRM_ELEMENTS - }; + enum ENormalElements + { + NRM_NBT = 0, + NRM_NBT3 = 1, + NUM_NRM_ELEMENTS + }; - enum ENormalIndices - { - NRM_INDICES1 = 0, - NRM_INDICES3 = 1, - NUM_NRM_INDICES - }; + enum ENormalIndices + { + NRM_INDICES1 = 0, + NRM_INDICES3 = 1, + NUM_NRM_INDICES + }; - struct Set - { - template - void operator=(const T&) - { - gc_size = T::size; - function = T::function; - } + struct Set + { + template + void operator=(const T&) + { + gc_size = T::size; + function = T::function; + } - int gc_size; - TPipelineFunction function; - }; + int gc_size; + TPipelineFunction function; + }; - static Set m_Table[NUM_NRM_TYPE][NUM_NRM_INDICES][NUM_NRM_ELEMENTS][NUM_NRM_FORMAT]; + static Set m_Table[NUM_NRM_TYPE][NUM_NRM_INDICES][NUM_NRM_ELEMENTS][NUM_NRM_FORMAT]; }; diff --git a/Source/Core/VideoCommon/VertexLoader_Position.cpp b/Source/Core/VideoCommon/VertexLoader_Position.cpp index 75e954d269..4b52861122 100644 --- a/Source/Core/VideoCommon/VertexLoader_Position.cpp +++ b/Source/Core/VideoCommon/VertexLoader_Position.cpp @@ -9,120 +9,219 @@ #include "Common/CommonTypes.h" #include "VideoCommon/DataReader.h" #include "VideoCommon/VertexLoader.h" -#include "VideoCommon/VertexLoader_Position.h" #include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexLoaderUtils.h" +#include "VideoCommon/VertexLoader_Position.h" #include "VideoCommon/VideoCommon.h" template float PosScale(T val, float scale) { - return val * scale; + return val * scale; } template <> float PosScale(float val, float scale) { - return val; + return val; } template void Pos_ReadDirect(VertexLoader* loader) { - static_assert(N <= 3, "N > 3 is not sane!"); - auto const scale = loader->m_posScale; - DataReader dst(g_vertex_manager_write_ptr, nullptr); - DataReader src(g_video_buffer_read_ptr, nullptr); + static_assert(N <= 3, "N > 3 is not sane!"); + auto const scale = loader->m_posScale; + DataReader dst(g_vertex_manager_write_ptr, nullptr); + DataReader src(g_video_buffer_read_ptr, nullptr); - for (int i = 0; i < N; ++i) - { - float value = PosScale(src.Read(), scale); - if (loader->m_counter < 3) - VertexLoaderManager::position_cache[loader->m_counter][i] = value; - dst.Write(value); - } + for (int i = 0; i < N; ++i) + { + float value = PosScale(src.Read(), scale); + if (loader->m_counter < 3) + VertexLoaderManager::position_cache[loader->m_counter][i] = value; + dst.Write(value); + } - g_vertex_manager_write_ptr = dst.GetPointer(); - g_video_buffer_read_ptr = src.GetPointer(); - LOG_VTX(); + g_vertex_manager_write_ptr = dst.GetPointer(); + g_video_buffer_read_ptr = src.GetPointer(); + LOG_VTX(); } template void Pos_ReadIndex(VertexLoader* loader) { - static_assert(std::is_unsigned::value, "Only unsigned I is sane!"); - static_assert(N <= 3, "N > 3 is not sane!"); + static_assert(std::is_unsigned::value, "Only unsigned I is sane!"); + static_assert(N <= 3, "N > 3 is not sane!"); - auto const index = DataRead(); - loader->m_vertexSkip = index == std::numeric_limits::max(); - auto const data = reinterpret_cast(VertexLoaderManager::cached_arraybases[ARRAY_POSITION] + (index * g_main_cp_state.array_strides[ARRAY_POSITION])); - auto const scale = loader->m_posScale; - DataReader dst(g_vertex_manager_write_ptr, nullptr); + auto const index = DataRead(); + loader->m_vertexSkip = index == std::numeric_limits::max(); + auto const data = + reinterpret_cast(VertexLoaderManager::cached_arraybases[ARRAY_POSITION] + + (index * g_main_cp_state.array_strides[ARRAY_POSITION])); + auto const scale = loader->m_posScale; + DataReader dst(g_vertex_manager_write_ptr, nullptr); - for (int i = 0; i < N; ++i) - { - float value = PosScale(Common::FromBigEndian(data[i]), scale); - if (loader->m_counter < 3) - VertexLoaderManager::position_cache[loader->m_counter][i] = value; - dst.Write(value); - } + for (int i = 0; i < N; ++i) + { + float value = PosScale(Common::FromBigEndian(data[i]), scale); + if (loader->m_counter < 3) + VertexLoaderManager::position_cache[loader->m_counter][i] = value; + dst.Write(value); + } - g_vertex_manager_write_ptr = dst.GetPointer(); - LOG_VTX(); + g_vertex_manager_write_ptr = dst.GetPointer(); + LOG_VTX(); } static TPipelineFunction tableReadPosition[4][8][2] = { - { - {nullptr, nullptr,}, - {nullptr, nullptr,}, - {nullptr, nullptr,}, - {nullptr, nullptr,}, - {nullptr, nullptr,}, - }, - { - {Pos_ReadDirect, Pos_ReadDirect,}, - {Pos_ReadDirect, Pos_ReadDirect,}, - {Pos_ReadDirect, Pos_ReadDirect,}, - {Pos_ReadDirect, Pos_ReadDirect,}, - {Pos_ReadDirect, Pos_ReadDirect,}, - }, - { - {Pos_ReadIndex, Pos_ReadIndex,}, - {Pos_ReadIndex, Pos_ReadIndex,}, - {Pos_ReadIndex, Pos_ReadIndex,}, - {Pos_ReadIndex, Pos_ReadIndex,}, - {Pos_ReadIndex, Pos_ReadIndex,}, - }, - { - {Pos_ReadIndex, Pos_ReadIndex,}, - {Pos_ReadIndex, Pos_ReadIndex,}, - {Pos_ReadIndex, Pos_ReadIndex,}, - {Pos_ReadIndex, Pos_ReadIndex,}, - {Pos_ReadIndex, Pos_ReadIndex,}, - }, + { + { + nullptr, nullptr, + }, + { + nullptr, nullptr, + }, + { + nullptr, nullptr, + }, + { + nullptr, nullptr, + }, + { + nullptr, nullptr, + }, + }, + { + { + Pos_ReadDirect, Pos_ReadDirect, + }, + { + Pos_ReadDirect, Pos_ReadDirect, + }, + { + Pos_ReadDirect, Pos_ReadDirect, + }, + { + Pos_ReadDirect, Pos_ReadDirect, + }, + { + Pos_ReadDirect, Pos_ReadDirect, + }, + }, + { + { + Pos_ReadIndex, Pos_ReadIndex, + }, + { + Pos_ReadIndex, Pos_ReadIndex, + }, + { + Pos_ReadIndex, Pos_ReadIndex, + }, + { + Pos_ReadIndex, Pos_ReadIndex, + }, + { + Pos_ReadIndex, Pos_ReadIndex, + }, + }, + { + { + Pos_ReadIndex, Pos_ReadIndex, + }, + { + Pos_ReadIndex, Pos_ReadIndex, + }, + { + Pos_ReadIndex, Pos_ReadIndex, + }, + { + Pos_ReadIndex, Pos_ReadIndex, + }, + { + Pos_ReadIndex, Pos_ReadIndex, + }, + }, }; static int tableReadPositionVertexSize[4][8][2] = { - { - {0, 0,}, {0, 0,}, {0, 0,}, {0, 0,}, {0, 0,}, - }, - { - {2, 3,}, {2, 3,}, {4, 6,}, {4, 6,}, {8, 12,}, - }, - { - {1, 1,}, {1, 1,}, {1, 1,}, {1, 1,}, {1, 1,}, - }, - { - {2, 2,}, {2, 2,}, {2, 2,}, {2, 2,}, {2, 2,}, - }, + { + { + 0, 0, + }, + { + 0, 0, + }, + { + 0, 0, + }, + { + 0, 0, + }, + { + 0, 0, + }, + }, + { + { + 2, 3, + }, + { + 2, 3, + }, + { + 4, 6, + }, + { + 4, 6, + }, + { + 8, 12, + }, + }, + { + { + 1, 1, + }, + { + 1, 1, + }, + { + 1, 1, + }, + { + 1, 1, + }, + { + 1, 1, + }, + }, + { + { + 2, 2, + }, + { + 2, 2, + }, + { + 2, 2, + }, + { + 2, 2, + }, + { + 2, 2, + }, + }, }; unsigned int VertexLoader_Position::GetSize(u64 _type, unsigned int _format, unsigned int _elements) { - return tableReadPositionVertexSize[_type][_format][_elements]; + return tableReadPositionVertexSize[_type][_format][_elements]; } -TPipelineFunction VertexLoader_Position::GetFunction(u64 _type, unsigned int _format, unsigned int _elements) +TPipelineFunction VertexLoader_Position::GetFunction(u64 _type, unsigned int _format, + unsigned int _elements) { - return tableReadPosition[_type][_format][_elements]; + return tableReadPosition[_type][_format][_elements]; } diff --git a/Source/Core/VideoCommon/VertexLoader_Position.h b/Source/Core/VideoCommon/VertexLoader_Position.h index 644fee5785..b34542128f 100644 --- a/Source/Core/VideoCommon/VertexLoader_Position.h +++ b/Source/Core/VideoCommon/VertexLoader_Position.h @@ -9,10 +9,9 @@ class VertexLoader_Position { public: - // GetSize - static unsigned int GetSize(u64 _type, unsigned int _format, unsigned int _elements); + // GetSize + static unsigned int GetSize(u64 _type, unsigned int _format, unsigned int _elements); - // GetFunction - static TPipelineFunction GetFunction(u64 _type, unsigned int _format, unsigned int _elements); + // GetFunction + static TPipelineFunction GetFunction(u64 _type, unsigned int _format, unsigned int _elements); }; - diff --git a/Source/Core/VideoCommon/VertexLoader_TextCoord.cpp b/Source/Core/VideoCommon/VertexLoader_TextCoord.cpp index 6b7de6a38c..aa4e87415c 100644 --- a/Source/Core/VideoCommon/VertexLoader_TextCoord.cpp +++ b/Source/Core/VideoCommon/VertexLoader_TextCoord.cpp @@ -8,9 +8,9 @@ #include "Common/CommonTypes.h" #include "VideoCommon/DataReader.h" #include "VideoCommon/VertexLoader.h" -#include "VideoCommon/VertexLoader_TextCoord.h" #include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexLoaderUtils.h" +#include "VideoCommon/VertexLoader_TextCoord.h" template void LOG_TEX(); @@ -18,127 +18,227 @@ void LOG_TEX(); template <> void LOG_TEX<1>() { - // warning: mapping buffer should be disabled to use this - // PRIM_LOG("tex: %f, ", ((float*)g_vertex_manager_write_ptr)[-1]); + // warning: mapping buffer should be disabled to use this + // PRIM_LOG("tex: %f, ", ((float*)g_vertex_manager_write_ptr)[-1]); } template <> void LOG_TEX<2>() { - // warning: mapping buffer should be disabled to use this - // PRIM_LOG("tex: %f %f, ", ((float*)g_vertex_manager_write_ptr)[-2], ((float*)g_vertex_manager_write_ptr)[-1]); + // warning: mapping buffer should be disabled to use this + // PRIM_LOG("tex: %f %f, ", ((float*)g_vertex_manager_write_ptr)[-2], + // ((float*)g_vertex_manager_write_ptr)[-1]); } static void TexCoord_Read_Dummy(VertexLoader* loader) { - loader->m_tcIndex++; + loader->m_tcIndex++; } template float TCScale(T val, float scale) { - return val * scale; + return val * scale; } template <> float TCScale(float val, float scale) { - return val; + return val; } template void TexCoord_ReadDirect(VertexLoader* loader) { - auto const scale = loader->m_tcScale[loader->m_tcIndex]; - DataReader dst(g_vertex_manager_write_ptr, nullptr); - DataReader src(g_video_buffer_read_ptr, nullptr); + auto const scale = loader->m_tcScale[loader->m_tcIndex]; + DataReader dst(g_vertex_manager_write_ptr, nullptr); + DataReader src(g_video_buffer_read_ptr, nullptr); - for (int i = 0; i != N; ++i) - dst.Write(TCScale(src.Read(), scale)); + for (int i = 0; i != N; ++i) + dst.Write(TCScale(src.Read(), scale)); - g_vertex_manager_write_ptr = dst.GetPointer(); - g_video_buffer_read_ptr = src.GetPointer(); - LOG_TEX(); + g_vertex_manager_write_ptr = dst.GetPointer(); + g_video_buffer_read_ptr = src.GetPointer(); + LOG_TEX(); - ++loader->m_tcIndex; + ++loader->m_tcIndex; } template void TexCoord_ReadIndex(VertexLoader* loader) { - static_assert(std::is_unsigned::value, "Only unsigned I is sane!"); + static_assert(std::is_unsigned::value, "Only unsigned I is sane!"); - auto const index = DataRead(); - auto const data = reinterpret_cast(VertexLoaderManager::cached_arraybases[ARRAY_TEXCOORD0 + loader->m_tcIndex] - + (index * g_main_cp_state.array_strides[ARRAY_TEXCOORD0 + loader->m_tcIndex])); - auto const scale = loader->m_tcScale[loader->m_tcIndex]; - DataReader dst(g_vertex_manager_write_ptr, nullptr); + auto const index = DataRead(); + auto const data = reinterpret_cast( + VertexLoaderManager::cached_arraybases[ARRAY_TEXCOORD0 + loader->m_tcIndex] + + (index * g_main_cp_state.array_strides[ARRAY_TEXCOORD0 + loader->m_tcIndex])); + auto const scale = loader->m_tcScale[loader->m_tcIndex]; + DataReader dst(g_vertex_manager_write_ptr, nullptr); - for (int i = 0; i != N; ++i) - dst.Write(TCScale(Common::FromBigEndian(data[i]), scale)); + for (int i = 0; i != N; ++i) + dst.Write(TCScale(Common::FromBigEndian(data[i]), scale)); - g_vertex_manager_write_ptr = dst.GetPointer(); - LOG_TEX(); - ++loader->m_tcIndex; + g_vertex_manager_write_ptr = dst.GetPointer(); + LOG_TEX(); + ++loader->m_tcIndex; } static TPipelineFunction tableReadTexCoord[4][8][2] = { - { - {nullptr, nullptr,}, - {nullptr, nullptr,}, - {nullptr, nullptr,}, - {nullptr, nullptr,}, - {nullptr, nullptr,}, - }, - { - {TexCoord_ReadDirect, TexCoord_ReadDirect,}, - {TexCoord_ReadDirect, TexCoord_ReadDirect,}, - {TexCoord_ReadDirect, TexCoord_ReadDirect,}, - {TexCoord_ReadDirect, TexCoord_ReadDirect,}, - {TexCoord_ReadDirect, TexCoord_ReadDirect,}, - }, - { - {TexCoord_ReadIndex, TexCoord_ReadIndex,}, - {TexCoord_ReadIndex, TexCoord_ReadIndex,}, - {TexCoord_ReadIndex, TexCoord_ReadIndex,}, - {TexCoord_ReadIndex, TexCoord_ReadIndex,}, - {TexCoord_ReadIndex, TexCoord_ReadIndex,}, - }, - { - {TexCoord_ReadIndex, TexCoord_ReadIndex,}, - {TexCoord_ReadIndex, TexCoord_ReadIndex,}, - {TexCoord_ReadIndex, TexCoord_ReadIndex,}, - {TexCoord_ReadIndex, TexCoord_ReadIndex,}, - {TexCoord_ReadIndex, TexCoord_ReadIndex,}, - }, + { + { + nullptr, nullptr, + }, + { + nullptr, nullptr, + }, + { + nullptr, nullptr, + }, + { + nullptr, nullptr, + }, + { + nullptr, nullptr, + }, + }, + { + { + TexCoord_ReadDirect, TexCoord_ReadDirect, + }, + { + TexCoord_ReadDirect, TexCoord_ReadDirect, + }, + { + TexCoord_ReadDirect, TexCoord_ReadDirect, + }, + { + TexCoord_ReadDirect, TexCoord_ReadDirect, + }, + { + TexCoord_ReadDirect, TexCoord_ReadDirect, + }, + }, + { + { + TexCoord_ReadIndex, TexCoord_ReadIndex, + }, + { + TexCoord_ReadIndex, TexCoord_ReadIndex, + }, + { + TexCoord_ReadIndex, TexCoord_ReadIndex, + }, + { + TexCoord_ReadIndex, TexCoord_ReadIndex, + }, + { + TexCoord_ReadIndex, TexCoord_ReadIndex, + }, + }, + { + { + TexCoord_ReadIndex, TexCoord_ReadIndex, + }, + { + TexCoord_ReadIndex, TexCoord_ReadIndex, + }, + { + TexCoord_ReadIndex, TexCoord_ReadIndex, + }, + { + TexCoord_ReadIndex, TexCoord_ReadIndex, + }, + { + TexCoord_ReadIndex, TexCoord_ReadIndex, + }, + }, }; static int tableReadTexCoordVertexSize[4][8][2] = { - { - {0, 0,}, {0, 0,}, {0, 0,}, {0, 0,}, {0, 0,}, - }, - { - {1, 2,}, {1, 2,}, {2, 4,}, {2, 4,}, {4, 8,}, - }, - { - {1, 1,}, {1, 1,}, {1, 1,}, {1, 1,}, {1, 1,}, - }, - { - {2, 2,}, {2, 2,}, {2, 2,}, {2, 2,}, {2, 2,}, - }, + { + { + 0, 0, + }, + { + 0, 0, + }, + { + 0, 0, + }, + { + 0, 0, + }, + { + 0, 0, + }, + }, + { + { + 1, 2, + }, + { + 1, 2, + }, + { + 2, 4, + }, + { + 2, 4, + }, + { + 4, 8, + }, + }, + { + { + 1, 1, + }, + { + 1, 1, + }, + { + 1, 1, + }, + { + 1, 1, + }, + { + 1, 1, + }, + }, + { + { + 2, 2, + }, + { + 2, 2, + }, + { + 2, 2, + }, + { + 2, 2, + }, + { + 2, 2, + }, + }, }; -unsigned int VertexLoader_TextCoord::GetSize(u64 _type, unsigned int _format, unsigned int _elements) +unsigned int VertexLoader_TextCoord::GetSize(u64 _type, unsigned int _format, + unsigned int _elements) { - return tableReadTexCoordVertexSize[_type][_format][_elements]; + return tableReadTexCoordVertexSize[_type][_format][_elements]; } -TPipelineFunction VertexLoader_TextCoord::GetFunction(u64 _type, unsigned int _format, unsigned int _elements) +TPipelineFunction VertexLoader_TextCoord::GetFunction(u64 _type, unsigned int _format, + unsigned int _elements) { - return tableReadTexCoord[_type][_format][_elements]; + return tableReadTexCoord[_type][_format][_elements]; } TPipelineFunction VertexLoader_TextCoord::GetDummyFunction() { - return TexCoord_Read_Dummy; + return TexCoord_Read_Dummy; } diff --git a/Source/Core/VideoCommon/VertexLoader_TextCoord.h b/Source/Core/VideoCommon/VertexLoader_TextCoord.h index b8d413f3a0..fe04e5670f 100644 --- a/Source/Core/VideoCommon/VertexLoader_TextCoord.h +++ b/Source/Core/VideoCommon/VertexLoader_TextCoord.h @@ -9,13 +9,13 @@ class VertexLoader_TextCoord { public: - // GetSize - static unsigned int GetSize(u64 _type, unsigned int _format, unsigned int _elements); + // GetSize + static unsigned int GetSize(u64 _type, unsigned int _format, unsigned int _elements); - // GetFunction - static TPipelineFunction GetFunction(u64 _type, unsigned int _format, unsigned int _elements); + // GetFunction + static TPipelineFunction GetFunction(u64 _type, unsigned int _format, unsigned int _elements); - // GetDummyFunction - // It is important to synchronize tcIndex. - static TPipelineFunction GetDummyFunction(); + // GetDummyFunction + // It is important to synchronize tcIndex. + static TPipelineFunction GetDummyFunction(); }; diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp index faee28c545..05e64eddb3 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/VertexManagerBase.cpp @@ -40,20 +40,20 @@ bool VertexManagerBase::s_is_flushed; bool VertexManagerBase::s_cull_all; static const PrimitiveType primitive_from_gx[8] = { - PRIMITIVE_TRIANGLES, // GX_DRAW_QUADS - PRIMITIVE_TRIANGLES, // GX_DRAW_QUADS_2 - PRIMITIVE_TRIANGLES, // GX_DRAW_TRIANGLES - PRIMITIVE_TRIANGLES, // GX_DRAW_TRIANGLE_STRIP - PRIMITIVE_TRIANGLES, // GX_DRAW_TRIANGLE_FAN - PRIMITIVE_LINES, // GX_DRAW_LINES - PRIMITIVE_LINES, // GX_DRAW_LINE_STRIP - PRIMITIVE_POINTS, // GX_DRAW_POINTS + PRIMITIVE_TRIANGLES, // GX_DRAW_QUADS + PRIMITIVE_TRIANGLES, // GX_DRAW_QUADS_2 + PRIMITIVE_TRIANGLES, // GX_DRAW_TRIANGLES + PRIMITIVE_TRIANGLES, // GX_DRAW_TRIANGLE_STRIP + PRIMITIVE_TRIANGLES, // GX_DRAW_TRIANGLE_FAN + PRIMITIVE_LINES, // GX_DRAW_LINES + PRIMITIVE_LINES, // GX_DRAW_LINE_STRIP + PRIMITIVE_POINTS, // GX_DRAW_POINTS }; VertexManagerBase::VertexManagerBase() { - s_is_flushed = true; - s_cull_all = false; + s_is_flushed = true; + s_cull_all = false; } VertexManagerBase::~VertexManagerBase() @@ -62,280 +62,294 @@ VertexManagerBase::~VertexManagerBase() u32 VertexManagerBase::GetRemainingSize() { - return (u32)(s_pEndBufferPointer - s_pCurBufferPointer); + return (u32)(s_pEndBufferPointer - s_pCurBufferPointer); } -DataReader VertexManagerBase::PrepareForAdditionalData(int primitive, u32 count, u32 stride, bool cullall) +DataReader VertexManagerBase::PrepareForAdditionalData(int primitive, u32 count, u32 stride, + bool cullall) { - // The SSE vertex loader can write up to 4 bytes past the end - u32 const needed_vertex_bytes = count * stride + 4; + // The SSE vertex loader can write up to 4 bytes past the end + u32 const needed_vertex_bytes = count * stride + 4; - // We can't merge different kinds of primitives, so we have to flush here - if (current_primitive_type != primitive_from_gx[primitive]) - Flush(); - current_primitive_type = primitive_from_gx[primitive]; + // We can't merge different kinds of primitives, so we have to flush here + if (current_primitive_type != primitive_from_gx[primitive]) + Flush(); + current_primitive_type = primitive_from_gx[primitive]; - // Check for size in buffer, if the buffer gets full, call Flush() - if (!s_is_flushed && ( count > IndexGenerator::GetRemainingIndices() || - count > GetRemainingIndices(primitive) || needed_vertex_bytes > GetRemainingSize())) - { - Flush(); + // Check for size in buffer, if the buffer gets full, call Flush() + if (!s_is_flushed && + (count > IndexGenerator::GetRemainingIndices() || count > GetRemainingIndices(primitive) || + needed_vertex_bytes > GetRemainingSize())) + { + Flush(); - if (count > IndexGenerator::GetRemainingIndices()) - ERROR_LOG(VIDEO, "Too little remaining index values. Use 32-bit or reset them on flush."); - if (count > GetRemainingIndices(primitive)) - ERROR_LOG(VIDEO, "VertexManager: Buffer not large enough for all indices! " - "Increase MAXIBUFFERSIZE or we need primitive breaking after all."); - if (needed_vertex_bytes > GetRemainingSize()) - ERROR_LOG(VIDEO, "VertexManager: Buffer not large enough for all vertices! " - "Increase MAXVBUFFERSIZE or we need primitive breaking after all."); - } + if (count > IndexGenerator::GetRemainingIndices()) + ERROR_LOG(VIDEO, "Too little remaining index values. Use 32-bit or reset them on flush."); + if (count > GetRemainingIndices(primitive)) + ERROR_LOG(VIDEO, "VertexManager: Buffer not large enough for all indices! " + "Increase MAXIBUFFERSIZE or we need primitive breaking after all."); + if (needed_vertex_bytes > GetRemainingSize()) + ERROR_LOG(VIDEO, "VertexManager: Buffer not large enough for all vertices! " + "Increase MAXVBUFFERSIZE or we need primitive breaking after all."); + } - s_cull_all = cullall; + s_cull_all = cullall; - // need to alloc new buffer - if (s_is_flushed) - { - g_vertex_manager->ResetBuffer(stride); - s_is_flushed = false; - } + // need to alloc new buffer + if (s_is_flushed) + { + g_vertex_manager->ResetBuffer(stride); + s_is_flushed = false; + } - return DataReader(s_pCurBufferPointer, s_pEndBufferPointer); + return DataReader(s_pCurBufferPointer, s_pEndBufferPointer); } void VertexManagerBase::FlushData(u32 count, u32 stride) { - s_pCurBufferPointer += count * stride; + s_pCurBufferPointer += count * stride; } u32 VertexManagerBase::GetRemainingIndices(int primitive) { - u32 index_len = MAXIBUFFERSIZE - IndexGenerator::GetIndexLen(); + u32 index_len = MAXIBUFFERSIZE - IndexGenerator::GetIndexLen(); - if (g_Config.backend_info.bSupportsPrimitiveRestart) - { - switch (primitive) - { - case GX_DRAW_QUADS: - case GX_DRAW_QUADS_2: - return index_len / 5 * 4; - case GX_DRAW_TRIANGLES: - return index_len / 4 * 3; - case GX_DRAW_TRIANGLE_STRIP: - return index_len / 1 - 1; - case GX_DRAW_TRIANGLE_FAN: - return index_len / 6 * 4 + 1; + if (g_Config.backend_info.bSupportsPrimitiveRestart) + { + switch (primitive) + { + case GX_DRAW_QUADS: + case GX_DRAW_QUADS_2: + return index_len / 5 * 4; + case GX_DRAW_TRIANGLES: + return index_len / 4 * 3; + case GX_DRAW_TRIANGLE_STRIP: + return index_len / 1 - 1; + case GX_DRAW_TRIANGLE_FAN: + return index_len / 6 * 4 + 1; - case GX_DRAW_LINES: - return index_len; - case GX_DRAW_LINE_STRIP: - return index_len / 2 + 1; + case GX_DRAW_LINES: + return index_len; + case GX_DRAW_LINE_STRIP: + return index_len / 2 + 1; - case GX_DRAW_POINTS: - return index_len; + case GX_DRAW_POINTS: + return index_len; - default: - return 0; - } - } - else - { - switch (primitive) - { - case GX_DRAW_QUADS: - case GX_DRAW_QUADS_2: - return index_len / 6 * 4; - case GX_DRAW_TRIANGLES: - return index_len; - case GX_DRAW_TRIANGLE_STRIP: - return index_len / 3 + 2; - case GX_DRAW_TRIANGLE_FAN: - return index_len / 3 + 2; + default: + return 0; + } + } + else + { + switch (primitive) + { + case GX_DRAW_QUADS: + case GX_DRAW_QUADS_2: + return index_len / 6 * 4; + case GX_DRAW_TRIANGLES: + return index_len; + case GX_DRAW_TRIANGLE_STRIP: + return index_len / 3 + 2; + case GX_DRAW_TRIANGLE_FAN: + return index_len / 3 + 2; - case GX_DRAW_LINES: - return index_len; - case GX_DRAW_LINE_STRIP: - return index_len / 2 + 1; + case GX_DRAW_LINES: + return index_len; + case GX_DRAW_LINE_STRIP: + return index_len / 2 + 1; - case GX_DRAW_POINTS: - return index_len; + case GX_DRAW_POINTS: + return index_len; - default: - return 0; - } - } + default: + return 0; + } + } } void VertexManagerBase::Flush() { - if (s_is_flushed) - return; + if (s_is_flushed) + return; - // loading a state will invalidate BP, so check for it - g_video_backend->CheckInvalidState(); + // loading a state will invalidate BP, so check for it + g_video_backend->CheckInvalidState(); #if defined(_DEBUG) || defined(DEBUGFAST) - PRIM_LOG("frame%d:\n texgen=%d, numchan=%d, dualtex=%d, ztex=%d, cole=%d, alpe=%d, ze=%d", g_ActiveConfig.iSaveTargetId, xfmem.numTexGen.numTexGens, - xfmem.numChan.numColorChans, xfmem.dualTexTrans.enabled, bpmem.ztex2.op, - (int)bpmem.blendmode.colorupdate, (int)bpmem.blendmode.alphaupdate, (int)bpmem.zmode.updateenable); + PRIM_LOG("frame%d:\n texgen=%d, numchan=%d, dualtex=%d, ztex=%d, cole=%d, alpe=%d, ze=%d", + g_ActiveConfig.iSaveTargetId, xfmem.numTexGen.numTexGens, xfmem.numChan.numColorChans, + xfmem.dualTexTrans.enabled, bpmem.ztex2.op, (int)bpmem.blendmode.colorupdate, + (int)bpmem.blendmode.alphaupdate, (int)bpmem.zmode.updateenable); - for (unsigned int i = 0; i < xfmem.numChan.numColorChans; ++i) - { - LitChannel* ch = &xfmem.color[i]; - PRIM_LOG("colchan%d: matsrc=%d, light=0x%x, ambsrc=%d, diffunc=%d, attfunc=%d", i, ch->matsource, ch->GetFullLightMask(), ch->ambsource, ch->diffusefunc, ch->attnfunc); - ch = &xfmem.alpha[i]; - PRIM_LOG("alpchan%d: matsrc=%d, light=0x%x, ambsrc=%d, diffunc=%d, attfunc=%d", i, ch->matsource, ch->GetFullLightMask(), ch->ambsource, ch->diffusefunc, ch->attnfunc); - } + for (unsigned int i = 0; i < xfmem.numChan.numColorChans; ++i) + { + LitChannel* ch = &xfmem.color[i]; + PRIM_LOG("colchan%d: matsrc=%d, light=0x%x, ambsrc=%d, diffunc=%d, attfunc=%d", i, + ch->matsource, ch->GetFullLightMask(), ch->ambsource, ch->diffusefunc, ch->attnfunc); + ch = &xfmem.alpha[i]; + PRIM_LOG("alpchan%d: matsrc=%d, light=0x%x, ambsrc=%d, diffunc=%d, attfunc=%d", i, + ch->matsource, ch->GetFullLightMask(), ch->ambsource, ch->diffusefunc, ch->attnfunc); + } - for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) - { - TexMtxInfo tinfo = xfmem.texMtxInfo[i]; - if (tinfo.texgentype != XF_TEXGEN_EMBOSS_MAP) tinfo.hex &= 0x7ff; - if (tinfo.texgentype != XF_TEXGEN_REGULAR) tinfo.projection = 0; + for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) + { + TexMtxInfo tinfo = xfmem.texMtxInfo[i]; + if (tinfo.texgentype != XF_TEXGEN_EMBOSS_MAP) + tinfo.hex &= 0x7ff; + if (tinfo.texgentype != XF_TEXGEN_REGULAR) + tinfo.projection = 0; - PRIM_LOG("txgen%d: proj=%d, input=%d, gentype=%d, srcrow=%d, embsrc=%d, emblght=%d, postmtx=%d, postnorm=%d", - i, tinfo.projection, tinfo.inputform, tinfo.texgentype, tinfo.sourcerow, tinfo.embosssourceshift, tinfo.embosslightshift, - xfmem.postMtxInfo[i].index, xfmem.postMtxInfo[i].normalize); - } + PRIM_LOG("txgen%d: proj=%d, input=%d, gentype=%d, srcrow=%d, embsrc=%d, emblght=%d, " + "postmtx=%d, postnorm=%d", + i, tinfo.projection, tinfo.inputform, tinfo.texgentype, tinfo.sourcerow, + tinfo.embosssourceshift, tinfo.embosslightshift, xfmem.postMtxInfo[i].index, + xfmem.postMtxInfo[i].normalize); + } - PRIM_LOG("pixel: tev=%d, ind=%d, texgen=%d, dstalpha=%d, alphatest=0x%x", (int)bpmem.genMode.numtevstages+1, (int)bpmem.genMode.numindstages, - (int)bpmem.genMode.numtexgens, (u32)bpmem.dstalpha.enable, (bpmem.alpha_test.hex>>16)&0xff); + PRIM_LOG("pixel: tev=%d, ind=%d, texgen=%d, dstalpha=%d, alphatest=0x%x", + (int)bpmem.genMode.numtevstages + 1, (int)bpmem.genMode.numindstages, + (int)bpmem.genMode.numtexgens, (u32)bpmem.dstalpha.enable, + (bpmem.alpha_test.hex >> 16) & 0xff); #endif - // If the primitave is marked CullAll. All we need to do is update the vertex constants and calculate the zfreeze refrence slope - if (!s_cull_all) - { - BitSet32 usedtextures; - for (u32 i = 0; i < bpmem.genMode.numtevstages + 1u; ++i) - if (bpmem.tevorders[i / 2].getEnable(i & 1)) - usedtextures[bpmem.tevorders[i/2].getTexMap(i & 1)] = true; + // If the primitave is marked CullAll. All we need to do is update the vertex constants and + // calculate the zfreeze refrence slope + if (!s_cull_all) + { + BitSet32 usedtextures; + for (u32 i = 0; i < bpmem.genMode.numtevstages + 1u; ++i) + if (bpmem.tevorders[i / 2].getEnable(i & 1)) + usedtextures[bpmem.tevorders[i / 2].getTexMap(i & 1)] = true; - if (bpmem.genMode.numindstages > 0) - for (unsigned int i = 0; i < bpmem.genMode.numtevstages + 1u; ++i) - if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages) - usedtextures[bpmem.tevindref.getTexMap(bpmem.tevind[i].bt)] = true; + if (bpmem.genMode.numindstages > 0) + for (unsigned int i = 0; i < bpmem.genMode.numtevstages + 1u; ++i) + if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages) + usedtextures[bpmem.tevindref.getTexMap(bpmem.tevind[i].bt)] = true; - TextureCacheBase::UnbindTextures(); - for (unsigned int i : usedtextures) - { - const TextureCacheBase::TCacheEntryBase* tentry = TextureCacheBase::Load(i); + TextureCacheBase::UnbindTextures(); + for (unsigned int i : usedtextures) + { + const TextureCacheBase::TCacheEntryBase* tentry = TextureCacheBase::Load(i); - if (tentry) - { - g_renderer->SetSamplerState(i & 3, i >> 2, tentry->is_custom_tex); - PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height); - } - else - { - ERROR_LOG(VIDEO, "error loading texture"); - } - } - g_texture_cache->BindTextures(); - } + if (tentry) + { + g_renderer->SetSamplerState(i & 3, i >> 2, tentry->is_custom_tex); + PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height); + } + else + { + ERROR_LOG(VIDEO, "error loading texture"); + } + } + g_texture_cache->BindTextures(); + } - // set global vertex constants - VertexShaderManager::SetConstants(); + // set global vertex constants + VertexShaderManager::SetConstants(); - // Calculate ZSlope for zfreeze - if (!bpmem.genMode.zfreeze) - { - // Must be done after VertexShaderManager::SetConstants() - CalculateZSlope(VertexLoaderManager::GetCurrentVertexFormat()); - } - else if (s_zslope.dirty && !s_cull_all) // or apply any dirty ZSlopes - { - PixelShaderManager::SetZSlope(s_zslope.dfdx, s_zslope.dfdy, s_zslope.f0); - s_zslope.dirty = false; - } + // Calculate ZSlope for zfreeze + if (!bpmem.genMode.zfreeze) + { + // Must be done after VertexShaderManager::SetConstants() + CalculateZSlope(VertexLoaderManager::GetCurrentVertexFormat()); + } + else if (s_zslope.dirty && !s_cull_all) // or apply any dirty ZSlopes + { + PixelShaderManager::SetZSlope(s_zslope.dfdx, s_zslope.dfdy, s_zslope.f0); + s_zslope.dirty = false; + } - if (!s_cull_all) - { - // set the rest of the global constants - GeometryShaderManager::SetConstants(); - PixelShaderManager::SetConstants(); + if (!s_cull_all) + { + // set the rest of the global constants + GeometryShaderManager::SetConstants(); + PixelShaderManager::SetConstants(); - bool useDstAlpha = bpmem.dstalpha.enable && - bpmem.blendmode.alphaupdate && - bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; + bool useDstAlpha = bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate && + bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; - if (PerfQueryBase::ShouldEmulate()) - g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP); - g_vertex_manager->vFlush(useDstAlpha); - if (PerfQueryBase::ShouldEmulate()) - g_perf_query->DisableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP); - } + if (PerfQueryBase::ShouldEmulate()) + g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP); + g_vertex_manager->vFlush(useDstAlpha); + if (PerfQueryBase::ShouldEmulate()) + g_perf_query->DisableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP); + } - GFX_DEBUGGER_PAUSE_AT(NEXT_FLUSH, true); + GFX_DEBUGGER_PAUSE_AT(NEXT_FLUSH, true); - if (xfmem.numTexGen.numTexGens != bpmem.genMode.numtexgens) - ERROR_LOG(VIDEO, "xf.numtexgens (%d) does not match bp.numtexgens (%d). Error in command stream.", xfmem.numTexGen.numTexGens, bpmem.genMode.numtexgens.Value()); + if (xfmem.numTexGen.numTexGens != bpmem.genMode.numtexgens) + ERROR_LOG(VIDEO, + "xf.numtexgens (%d) does not match bp.numtexgens (%d). Error in command stream.", + xfmem.numTexGen.numTexGens, bpmem.genMode.numtexgens.Value()); - s_is_flushed = true; - s_cull_all = false; + s_is_flushed = true; + s_cull_all = false; } void VertexManagerBase::DoState(PointerWrap& p) { - p.Do(s_zslope); - g_vertex_manager->vDoState(p); + p.Do(s_zslope); + g_vertex_manager->vDoState(p); } void VertexManagerBase::CalculateZSlope(NativeVertexFormat* format) { - float out[12]; - float viewOffset[2] = { xfmem.viewport.xOrig - bpmem.scissorOffset.x * 2, - xfmem.viewport.yOrig - bpmem.scissorOffset.y * 2}; + float out[12]; + float viewOffset[2] = {xfmem.viewport.xOrig - bpmem.scissorOffset.x * 2, + xfmem.viewport.yOrig - bpmem.scissorOffset.y * 2}; - if (current_primitive_type != PRIMITIVE_TRIANGLES) - return; + if (current_primitive_type != PRIMITIVE_TRIANGLES) + return; - // Global matrix ID. - u32 mtxIdx = g_main_cp_state.matrix_index_a.PosNormalMtxIdx; - const PortableVertexDeclaration vert_decl = format->GetVertexDeclaration(); + // Global matrix ID. + u32 mtxIdx = g_main_cp_state.matrix_index_a.PosNormalMtxIdx; + const PortableVertexDeclaration vert_decl = format->GetVertexDeclaration(); - // Make sure the buffer contains at least 3 vertices. - if ((s_pCurBufferPointer - s_pBaseBufferPointer) < (vert_decl.stride * 3)) - return; + // Make sure the buffer contains at least 3 vertices. + if ((s_pCurBufferPointer - s_pBaseBufferPointer) < (vert_decl.stride * 3)) + return; - // Lookup vertices of the last rendered triangle and software-transform them - // This allows us to determine the depth slope, which will be used if z-freeze - // is enabled in the following flush. - for (unsigned int i = 0; i < 3; ++i) - { - // If this vertex format has per-vertex position matrix IDs, look it up. - if (vert_decl.posmtx.enable) - mtxIdx = VertexLoaderManager::position_matrix_index[2 - i]; + // Lookup vertices of the last rendered triangle and software-transform them + // This allows us to determine the depth slope, which will be used if z-freeze + // is enabled in the following flush. + for (unsigned int i = 0; i < 3; ++i) + { + // If this vertex format has per-vertex position matrix IDs, look it up. + if (vert_decl.posmtx.enable) + mtxIdx = VertexLoaderManager::position_matrix_index[2 - i]; - if (vert_decl.position.components == 2) - VertexLoaderManager::position_cache[2 - i][2] = 0; + if (vert_decl.position.components == 2) + VertexLoaderManager::position_cache[2 - i][2] = 0; - VertexShaderManager::TransformToClipSpace(&VertexLoaderManager::position_cache[2 - i][0], &out[i * 4], mtxIdx); + VertexShaderManager::TransformToClipSpace(&VertexLoaderManager::position_cache[2 - i][0], + &out[i * 4], mtxIdx); - // Transform to Screenspace - float inv_w = 1.0f / out[3 + i * 4]; + // Transform to Screenspace + float inv_w = 1.0f / out[3 + i * 4]; - out[0 + i * 4] = out[0 + i * 4] * inv_w * xfmem.viewport.wd + viewOffset[0]; - out[1 + i * 4] = out[1 + i * 4] * inv_w * xfmem.viewport.ht + viewOffset[1]; - out[2 + i * 4] = out[2 + i * 4] * inv_w * xfmem.viewport.zRange + xfmem.viewport.farZ; - } + out[0 + i * 4] = out[0 + i * 4] * inv_w * xfmem.viewport.wd + viewOffset[0]; + out[1 + i * 4] = out[1 + i * 4] * inv_w * xfmem.viewport.ht + viewOffset[1]; + out[2 + i * 4] = out[2 + i * 4] * inv_w * xfmem.viewport.zRange + xfmem.viewport.farZ; + } - float dx31 = out[8] - out[0]; - float dx12 = out[0] - out[4]; - float dy12 = out[1] - out[5]; - float dy31 = out[9] - out[1]; + float dx31 = out[8] - out[0]; + float dx12 = out[0] - out[4]; + float dy12 = out[1] - out[5]; + float dy31 = out[9] - out[1]; - float DF31 = out[10] - out[2]; - float DF21 = out[6] - out[2]; - float a = DF31 * -dy12 - DF21 * dy31; - float b = dx31 * DF21 + dx12 * DF31; - float c = -dx12 * dy31 - dx31 * -dy12; + float DF31 = out[10] - out[2]; + float DF21 = out[6] - out[2]; + float a = DF31 * -dy12 - DF21 * dy31; + float b = dx31 * DF21 + dx12 * DF31; + float c = -dx12 * dy31 - dx31 * -dy12; - // Sometimes we process de-generate triangles. Stop any divide by zeros - if (c == 0) - return; + // Sometimes we process de-generate triangles. Stop any divide by zeros + if (c == 0) + return; - s_zslope.dfdx = -a / c; - s_zslope.dfdy = -b / c; - s_zslope.f0 = out[2] - (out[0] * s_zslope.dfdx + out[1] * s_zslope.dfdy); - s_zslope.dirty = true; + s_zslope.dfdx = -a / c; + s_zslope.dfdy = -b / c; + s_zslope.f0 = out[2] - (out[0] * s_zslope.dfdx + out[1] * s_zslope.dfdy); + s_zslope.dirty = true; } diff --git a/Source/Core/VideoCommon/VertexManagerBase.h b/Source/Core/VideoCommon/VertexManagerBase.h index 593732eab0..f99f7e15fc 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.h +++ b/Source/Core/VideoCommon/VertexManagerBase.h @@ -15,73 +15,76 @@ class NativeVertexFormat; class PointerWrap; struct PortableVertexDeclaration; -enum PrimitiveType { - PRIMITIVE_POINTS, - PRIMITIVE_LINES, - PRIMITIVE_TRIANGLES, +enum PrimitiveType +{ + PRIMITIVE_POINTS, + PRIMITIVE_LINES, + PRIMITIVE_TRIANGLES, }; struct Slope { - float dfdx; - float dfdy; - float f0; - bool dirty; + float dfdx; + float dfdy; + float f0; + bool dirty; }; class VertexManagerBase { private: - static const u32 SMALLEST_POSSIBLE_VERTEX = sizeof(float)*3; // 3 pos - static const u32 LARGEST_POSSIBLE_VERTEX = sizeof(float)*45 + sizeof(u32)*2; // 3 pos, 3*3 normal, 2*u32 color, 8*4 tex, 1 posMat + static const u32 SMALLEST_POSSIBLE_VERTEX = sizeof(float) * 3; // 3 pos + static const u32 LARGEST_POSSIBLE_VERTEX = + sizeof(float) * 45 + sizeof(u32) * 2; // 3 pos, 3*3 normal, 2*u32 color, 8*4 tex, 1 posMat - static const u32 MAX_PRIMITIVES_PER_COMMAND = (u16)-1; + static const u32 MAX_PRIMITIVES_PER_COMMAND = (u16)-1; public: - static const u32 MAXVBUFFERSIZE = ROUND_UP_POW2(MAX_PRIMITIVES_PER_COMMAND * LARGEST_POSSIBLE_VERTEX); + static const u32 MAXVBUFFERSIZE = + ROUND_UP_POW2(MAX_PRIMITIVES_PER_COMMAND * LARGEST_POSSIBLE_VERTEX); - // We may convert triangle-fans to triangle-lists, almost 3x as many indices. - static const u32 MAXIBUFFERSIZE = ROUND_UP_POW2(MAX_PRIMITIVES_PER_COMMAND * 3); + // We may convert triangle-fans to triangle-lists, almost 3x as many indices. + static const u32 MAXIBUFFERSIZE = ROUND_UP_POW2(MAX_PRIMITIVES_PER_COMMAND * 3); - VertexManagerBase(); - // needs to be virtual for DX11's dtor - virtual ~VertexManagerBase(); + VertexManagerBase(); + // needs to be virtual for DX11's dtor + virtual ~VertexManagerBase(); - static DataReader PrepareForAdditionalData(int primitive, u32 count, u32 stride, bool cullall); - static void FlushData(u32 count, u32 stride); + static DataReader PrepareForAdditionalData(int primitive, u32 count, u32 stride, bool cullall); + static void FlushData(u32 count, u32 stride); - static void Flush(); + static void Flush(); - virtual NativeVertexFormat* CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) = 0; + virtual NativeVertexFormat* + CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) = 0; - static void DoState(PointerWrap& p); + static void DoState(PointerWrap& p); protected: - virtual void vDoState(PointerWrap& p) { } + virtual void vDoState(PointerWrap& p) {} + static PrimitiveType current_primitive_type; - static PrimitiveType current_primitive_type; + virtual void ResetBuffer(u32 stride) = 0; - virtual void ResetBuffer(u32 stride) = 0; + static u8* s_pCurBufferPointer; + static u8* s_pBaseBufferPointer; + static u8* s_pEndBufferPointer; - static u8* s_pCurBufferPointer; - static u8* s_pBaseBufferPointer; - static u8* s_pEndBufferPointer; + static u32 GetRemainingSize(); + static u32 GetRemainingIndices(int primitive); - static u32 GetRemainingSize(); - static u32 GetRemainingIndices(int primitive); + static Slope s_zslope; + static void CalculateZSlope(NativeVertexFormat* format); - static Slope s_zslope; - static void CalculateZSlope(NativeVertexFormat* format); - - static bool s_cull_all; + static bool s_cull_all; private: - static bool s_is_flushed; + static bool s_is_flushed; - virtual void vFlush(bool useDstAlpha) = 0; + virtual void vFlush(bool useDstAlpha) = 0; - virtual void CreateDeviceObjects() {} - virtual void DestroyDeviceObjects() {} + virtual void CreateDeviceObjects() {} + virtual void DestroyDeviceObjects() {} }; extern std::unique_ptr g_vertex_manager; diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 5a31a6e16c..618d097370 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -14,383 +14,417 @@ #include "VideoCommon/VertexShaderGen.h" #include "VideoCommon/VideoConfig.h" -template +template static T GenerateVertexShader(API_TYPE api_type) { - T out; - const u32 components = VertexLoaderManager::g_current_components; - // Non-uid template parameters will write to the dummy data (=> gets optimized out) - vertex_shader_uid_data dummy_data; - vertex_shader_uid_data* uid_data = out.template GetUidData(); - if (uid_data != nullptr) - memset(uid_data, 0, sizeof(*uid_data)); - else - uid_data = &dummy_data; + T out; + const u32 components = VertexLoaderManager::g_current_components; + // Non-uid template parameters will write to the dummy data (=> gets optimized out) + vertex_shader_uid_data dummy_data; + vertex_shader_uid_data* uid_data = out.template GetUidData(); + if (uid_data != nullptr) + memset(uid_data, 0, sizeof(*uid_data)); + else + uid_data = &dummy_data; - _assert_(bpmem.genMode.numtexgens == xfmem.numTexGen.numTexGens); - _assert_(bpmem.genMode.numcolchans == xfmem.numChan.numColorChans); + _assert_(bpmem.genMode.numtexgens == xfmem.numTexGen.numTexGens); + _assert_(bpmem.genMode.numcolchans == xfmem.numChan.numColorChans); - out.Write("%s", s_lighting_struct); + out.Write("%s", s_lighting_struct); - // uniforms - if (api_type == API_OPENGL) - out.Write("layout(std140%s) uniform VSBlock {\n", g_ActiveConfig.backend_info.bSupportsBindingLayout ? ", binding = 2" : ""); - else - out.Write("cbuffer VSBlock {\n"); - out.Write(s_shader_uniforms); - out.Write("};\n"); + // uniforms + if (api_type == API_OPENGL) + out.Write("layout(std140%s) uniform VSBlock {\n", + g_ActiveConfig.backend_info.bSupportsBindingLayout ? ", binding = 2" : ""); + else + out.Write("cbuffer VSBlock {\n"); + out.Write(s_shader_uniforms); + out.Write("};\n"); - out.Write("struct VS_OUTPUT {\n"); - GenerateVSOutputMembers(out, api_type, ""); - out.Write("};\n"); + out.Write("struct VS_OUTPUT {\n"); + GenerateVSOutputMembers(out, api_type, ""); + out.Write("};\n"); - uid_data->numTexGens = xfmem.numTexGen.numTexGens; - uid_data->components = components; - uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting; + uid_data->numTexGens = xfmem.numTexGen.numTexGens; + uid_data->components = components; + uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting; - if (api_type == API_OPENGL) - { - out.Write("in float4 rawpos; // ATTR%d,\n", SHADER_POSITION_ATTRIB); - if (components & VB_HAS_POSMTXIDX) - out.Write("in int posmtx; // ATTR%d,\n", SHADER_POSMTX_ATTRIB); - if (components & VB_HAS_NRM0) - out.Write("in float3 rawnorm0; // ATTR%d,\n", SHADER_NORM0_ATTRIB); - if (components & VB_HAS_NRM1) - out.Write("in float3 rawnorm1; // ATTR%d,\n", SHADER_NORM1_ATTRIB); - if (components & VB_HAS_NRM2) - out.Write("in float3 rawnorm2; // ATTR%d,\n", SHADER_NORM2_ATTRIB); + if (api_type == API_OPENGL) + { + out.Write("in float4 rawpos; // ATTR%d,\n", SHADER_POSITION_ATTRIB); + if (components & VB_HAS_POSMTXIDX) + out.Write("in int posmtx; // ATTR%d,\n", SHADER_POSMTX_ATTRIB); + if (components & VB_HAS_NRM0) + out.Write("in float3 rawnorm0; // ATTR%d,\n", SHADER_NORM0_ATTRIB); + if (components & VB_HAS_NRM1) + out.Write("in float3 rawnorm1; // ATTR%d,\n", SHADER_NORM1_ATTRIB); + if (components & VB_HAS_NRM2) + out.Write("in float3 rawnorm2; // ATTR%d,\n", SHADER_NORM2_ATTRIB); - if (components & VB_HAS_COL0) - out.Write("in float4 color0; // ATTR%d,\n", SHADER_COLOR0_ATTRIB); - if (components & VB_HAS_COL1) - out.Write("in float4 color1; // ATTR%d,\n", SHADER_COLOR1_ATTRIB); + if (components & VB_HAS_COL0) + out.Write("in float4 color0; // ATTR%d,\n", SHADER_COLOR0_ATTRIB); + if (components & VB_HAS_COL1) + out.Write("in float4 color1; // ATTR%d,\n", SHADER_COLOR1_ATTRIB); - for (int i = 0; i < 8; ++i) - { - u32 hastexmtx = (components & (VB_HAS_TEXMTXIDX0<(out, api_type, GetInterpolationQualifier(true, false)); - out.Write("} vs;\n"); - } - else - { - // Let's set up attributes - for (u32 i = 0; i < 8; ++i) - { - if (i < xfmem.numTexGen.numTexGens) - { - out.Write("%s out float3 uv%u;\n", GetInterpolationQualifier(), i); - } - } - out.Write("%s out float4 clipPos;\n", GetInterpolationQualifier()); - if (g_ActiveConfig.bEnablePixelLighting) - { - out.Write("%s out float3 Normal;\n", GetInterpolationQualifier()); - out.Write("%s out float3 WorldPos;\n", GetInterpolationQualifier()); - } - out.Write("%s out float4 colors_0;\n", GetInterpolationQualifier()); - out.Write("%s out float4 colors_1;\n", GetInterpolationQualifier()); - } + if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) + { + out.Write("out VertexData {\n"); + GenerateVSOutputMembers(out, api_type, GetInterpolationQualifier(true, false)); + out.Write("} vs;\n"); + } + else + { + // Let's set up attributes + for (u32 i = 0; i < 8; ++i) + { + if (i < xfmem.numTexGen.numTexGens) + { + out.Write("%s out float3 uv%u;\n", GetInterpolationQualifier(), i); + } + } + out.Write("%s out float4 clipPos;\n", GetInterpolationQualifier()); + if (g_ActiveConfig.bEnablePixelLighting) + { + out.Write("%s out float3 Normal;\n", GetInterpolationQualifier()); + out.Write("%s out float3 WorldPos;\n", GetInterpolationQualifier()); + } + out.Write("%s out float4 colors_0;\n", GetInterpolationQualifier()); + out.Write("%s out float4 colors_1;\n", GetInterpolationQualifier()); + } - out.Write("void main()\n{\n"); - } - else // D3D - { - out.Write("VS_OUTPUT main(\n"); + out.Write("void main()\n{\n"); + } + else // D3D + { + out.Write("VS_OUTPUT main(\n"); - // inputs - if (components & VB_HAS_NRM0) - out.Write(" float3 rawnorm0 : NORMAL0,\n"); - if (components & VB_HAS_NRM1) - out.Write(" float3 rawnorm1 : NORMAL1,\n"); - if (components & VB_HAS_NRM2) - out.Write(" float3 rawnorm2 : NORMAL2,\n"); - if (components & VB_HAS_COL0) - out.Write(" float4 color0 : COLOR0,\n"); - if (components & VB_HAS_COL1) - out.Write(" float4 color1 : COLOR1,\n"); - for (int i = 0; i < 8; ++i) - { - u32 hastexmtx = (components & (VB_HAS_TEXMTXIDX0<numColorChans = xfmem.numChan.numColorChans; + if (xfmem.numChan.numColorChans == 0) + { + if (components & VB_HAS_COL0) + out.Write("o.colors_0 = color0;\n"); + else + out.Write("o.colors_0 = float4(1.0, 1.0, 1.0, 1.0);\n"); + } - uid_data->numColorChans = xfmem.numChan.numColorChans; - if (xfmem.numChan.numColorChans == 0) - { - if (components & VB_HAS_COL0) - out.Write("o.colors_0 = color0;\n"); - else - out.Write("o.colors_0 = float4(1.0, 1.0, 1.0, 1.0);\n"); - } + GenerateLightingShader(out, uid_data->lighting, components, "color", "o.colors_"); - GenerateLightingShader(out, uid_data->lighting, components, "color", "o.colors_"); + if (xfmem.numChan.numColorChans < 2) + { + if (components & VB_HAS_COL1) + out.Write("o.colors_1 = color1;\n"); + else + out.Write("o.colors_1 = o.colors_0;\n"); + } - if (xfmem.numChan.numColorChans < 2) - { - if (components & VB_HAS_COL1) - out.Write("o.colors_1 = color1;\n"); - else - out.Write("o.colors_1 = o.colors_0;\n"); - } + // transform texcoords + out.Write("float4 coord = float4(0.0, 0.0, 1.0, 1.0);\n"); + for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) + { + TexMtxInfo& texinfo = xfmem.texMtxInfo[i]; - // transform texcoords - out.Write("float4 coord = float4(0.0, 0.0, 1.0, 1.0);\n"); - for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) - { - TexMtxInfo& texinfo = xfmem.texMtxInfo[i]; + out.Write("{\n"); + out.Write("coord = float4(0.0, 0.0, 1.0, 1.0);\n"); + uid_data->texMtxInfo[i].sourcerow = xfmem.texMtxInfo[i].sourcerow; + switch (texinfo.sourcerow) + { + case XF_SRCGEOM_INROW: + out.Write("coord.xyz = rawpos.xyz;\n"); + break; + case XF_SRCNORMAL_INROW: + if (components & VB_HAS_NRM0) + { + out.Write("coord.xyz = rawnorm0.xyz;\n"); + } + break; + case XF_SRCCOLORS_INROW: + _assert_(texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC0 || + texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC1); + break; + case XF_SRCBINORMAL_T_INROW: + if (components & VB_HAS_NRM1) + { + out.Write("coord.xyz = rawnorm1.xyz;\n"); + } + break; + case XF_SRCBINORMAL_B_INROW: + if (components & VB_HAS_NRM2) + { + out.Write("coord.xyz = rawnorm2.xyz;\n"); + } + break; + default: + _assert_(texinfo.sourcerow <= XF_SRCTEX7_INROW); + if (components & (VB_HAS_UV0 << (texinfo.sourcerow - XF_SRCTEX0_INROW))) + out.Write("coord = float4(tex%d.x, tex%d.y, 1.0, 1.0);\n", + texinfo.sourcerow - XF_SRCTEX0_INROW, texinfo.sourcerow - XF_SRCTEX0_INROW); + break; + } + // Input form of AB11 sets z element to 1.0 + uid_data->texMtxInfo[i].inputform = xfmem.texMtxInfo[i].inputform; + if (texinfo.inputform == XF_TEXINPUT_AB11) + out.Write("coord.z = 1.0;\n"); - out.Write("{\n"); - out.Write("coord = float4(0.0, 0.0, 1.0, 1.0);\n"); - uid_data->texMtxInfo[i].sourcerow = xfmem.texMtxInfo[i].sourcerow; - switch (texinfo.sourcerow) - { - case XF_SRCGEOM_INROW: - out.Write("coord.xyz = rawpos.xyz;\n"); - break; - case XF_SRCNORMAL_INROW: - if (components & VB_HAS_NRM0) - { - out.Write("coord.xyz = rawnorm0.xyz;\n"); - } - break; - case XF_SRCCOLORS_INROW: - _assert_(texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC0 || texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC1); - break; - case XF_SRCBINORMAL_T_INROW: - if (components & VB_HAS_NRM1) - { - out.Write("coord.xyz = rawnorm1.xyz;\n"); - } - break; - case XF_SRCBINORMAL_B_INROW: - if (components & VB_HAS_NRM2) - { - out.Write("coord.xyz = rawnorm2.xyz;\n"); - } - break; - default: - _assert_(texinfo.sourcerow <= XF_SRCTEX7_INROW); - if (components & (VB_HAS_UV0 << (texinfo.sourcerow - XF_SRCTEX0_INROW))) - out.Write("coord = float4(tex%d.x, tex%d.y, 1.0, 1.0);\n", texinfo.sourcerow - XF_SRCTEX0_INROW, texinfo.sourcerow - XF_SRCTEX0_INROW); - break; - } - // Input form of AB11 sets z element to 1.0 - uid_data->texMtxInfo[i].inputform = xfmem.texMtxInfo[i].inputform; - if (texinfo.inputform == XF_TEXINPUT_AB11) - out.Write("coord.z = 1.0;\n"); + // first transformation + uid_data->texMtxInfo[i].texgentype = xfmem.texMtxInfo[i].texgentype; + switch (texinfo.texgentype) + { + case XF_TEXGEN_EMBOSS_MAP: // calculate tex coords into bump map - // first transformation - uid_data->texMtxInfo[i].texgentype = xfmem.texMtxInfo[i].texgentype; - switch (texinfo.texgentype) - { - case XF_TEXGEN_EMBOSS_MAP: // calculate tex coords into bump map + if (components & (VB_HAS_NRM1 | VB_HAS_NRM2)) + { + // transform the light dir into tangent space + uid_data->texMtxInfo[i].embosslightshift = xfmem.texMtxInfo[i].embosslightshift; + uid_data->texMtxInfo[i].embosssourceshift = xfmem.texMtxInfo[i].embosssourceshift; + out.Write("ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n", + LIGHT_POS_PARAMS(texinfo.embosslightshift)); + out.Write( + "o.tex%d.xyz = o.tex%d.xyz + float3(dot(ldir, _norm1), dot(ldir, _norm2), 0.0);\n", i, + texinfo.embosssourceshift); + } + else + { + // The following assert was triggered in House of the Dead Overkill and Star Wars Rogue + // Squadron 2 + //_assert_(0); // should have normals + uid_data->texMtxInfo[i].embosssourceshift = xfmem.texMtxInfo[i].embosssourceshift; + out.Write("o.tex%d.xyz = o.tex%d.xyz;\n", i, texinfo.embosssourceshift); + } - if (components & (VB_HAS_NRM1|VB_HAS_NRM2)) - { - // transform the light dir into tangent space - uid_data->texMtxInfo[i].embosslightshift = xfmem.texMtxInfo[i].embosslightshift; - uid_data->texMtxInfo[i].embosssourceshift = xfmem.texMtxInfo[i].embosssourceshift; - out.Write("ldir = normalize(" LIGHT_POS".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(texinfo.embosslightshift)); - out.Write("o.tex%d.xyz = o.tex%d.xyz + float3(dot(ldir, _norm1), dot(ldir, _norm2), 0.0);\n", i, texinfo.embosssourceshift); - } - else - { - // The following assert was triggered in House of the Dead Overkill and Star Wars Rogue Squadron 2 - //_assert_(0); // should have normals - uid_data->texMtxInfo[i].embosssourceshift = xfmem.texMtxInfo[i].embosssourceshift; - out.Write("o.tex%d.xyz = o.tex%d.xyz;\n", i, texinfo.embosssourceshift); - } + break; + case XF_TEXGEN_COLOR_STRGBC0: + out.Write("o.tex%d.xyz = float3(o.colors_0.x, o.colors_0.y, 1);\n", i); + break; + case XF_TEXGEN_COLOR_STRGBC1: + out.Write("o.tex%d.xyz = float3(o.colors_1.x, o.colors_1.y, 1);\n", i); + break; + case XF_TEXGEN_REGULAR: + default: + uid_data->texMtxInfo_n_projection |= xfmem.texMtxInfo[i].projection << i; + if (components & (VB_HAS_TEXMTXIDX0 << i)) + { + out.Write("int tmp = int(tex%d.z);\n", i); + if (texinfo.projection == XF_TEXPROJ_STQ) + out.Write("o.tex%d.xyz = float3(dot(coord, " I_TRANSFORMMATRICES + "[tmp]), dot(coord, " I_TRANSFORMMATRICES + "[tmp+1]), dot(coord, " I_TRANSFORMMATRICES "[tmp+2]));\n", + i); + else + out.Write("o.tex%d.xyz = float3(dot(coord, " I_TRANSFORMMATRICES + "[tmp]), dot(coord, " I_TRANSFORMMATRICES "[tmp+1]), 1);\n", + i); + } + else + { + if (texinfo.projection == XF_TEXPROJ_STQ) + out.Write("o.tex%d.xyz = float3(dot(coord, " I_TEXMATRICES + "[%d]), dot(coord, " I_TEXMATRICES "[%d]), dot(coord, " I_TEXMATRICES + "[%d]));\n", + i, 3 * i, 3 * i + 1, 3 * i + 2); + else + out.Write("o.tex%d.xyz = float3(dot(coord, " I_TEXMATRICES + "[%d]), dot(coord, " I_TEXMATRICES "[%d]), 1);\n", + i, 3 * i, 3 * i + 1); + } + break; + } - break; - case XF_TEXGEN_COLOR_STRGBC0: - out.Write("o.tex%d.xyz = float3(o.colors_0.x, o.colors_0.y, 1);\n", i); - break; - case XF_TEXGEN_COLOR_STRGBC1: - out.Write("o.tex%d.xyz = float3(o.colors_1.x, o.colors_1.y, 1);\n", i); - break; - case XF_TEXGEN_REGULAR: - default: - uid_data->texMtxInfo_n_projection |= xfmem.texMtxInfo[i].projection << i; - if (components & (VB_HAS_TEXMTXIDX0<dualTexTrans_enabled = xfmem.dualTexTrans.enabled; + // CHECKME: does this only work for regular tex gen types? + if (xfmem.dualTexTrans.enabled && texinfo.texgentype == XF_TEXGEN_REGULAR) + { + const PostMtxInfo& postInfo = xfmem.postMtxInfo[i]; - uid_data->dualTexTrans_enabled = xfmem.dualTexTrans.enabled; - // CHECKME: does this only work for regular tex gen types? - if (xfmem.dualTexTrans.enabled && texinfo.texgentype == XF_TEXGEN_REGULAR) - { - const PostMtxInfo& postInfo = xfmem.postMtxInfo[i]; + uid_data->postMtxInfo[i].index = xfmem.postMtxInfo[i].index; + int postidx = postInfo.index; + out.Write("float4 P0 = " I_POSTTRANSFORMMATRICES "[%d];\n" + "float4 P1 = " I_POSTTRANSFORMMATRICES "[%d];\n" + "float4 P2 = " I_POSTTRANSFORMMATRICES "[%d];\n", + postidx & 0x3f, (postidx + 1) & 0x3f, (postidx + 2) & 0x3f); - uid_data->postMtxInfo[i].index = xfmem.postMtxInfo[i].index; - int postidx = postInfo.index; - out.Write("float4 P0 = " I_POSTTRANSFORMMATRICES"[%d];\n" - "float4 P1 = " I_POSTTRANSFORMMATRICES"[%d];\n" - "float4 P2 = " I_POSTTRANSFORMMATRICES"[%d];\n", - postidx & 0x3f, (postidx + 1) & 0x3f, (postidx + 2) & 0x3f); + uid_data->postMtxInfo[i].normalize = xfmem.postMtxInfo[i].normalize; + if (postInfo.normalize) + out.Write("o.tex%d.xyz = normalize(o.tex%d.xyz);\n", i, i); - uid_data->postMtxInfo[i].normalize = xfmem.postMtxInfo[i].normalize; - if (postInfo.normalize) - out.Write("o.tex%d.xyz = normalize(o.tex%d.xyz);\n", i, i); + // multiply by postmatrix + out.Write("o.tex%d.xyz = float3(dot(P0.xyz, o.tex%d.xyz) + P0.w, dot(P1.xyz, o.tex%d.xyz) + " + "P1.w, dot(P2.xyz, o.tex%d.xyz) + P2.w);\n", + i, i, i, i); + } - // multiply by postmatrix - out.Write("o.tex%d.xyz = float3(dot(P0.xyz, o.tex%d.xyz) + P0.w, dot(P1.xyz, o.tex%d.xyz) + P1.w, dot(P2.xyz, o.tex%d.xyz) + P2.w);\n", i, i, i, i); - } + out.Write("}\n"); + } - out.Write("}\n"); - } + // clipPos/w needs to be done in pixel shader, not here + out.Write("o.clipPos = o.pos;\n"); - // clipPos/w needs to be done in pixel shader, not here - out.Write("o.clipPos = o.pos;\n"); + if (g_ActiveConfig.bEnablePixelLighting) + { + out.Write("o.Normal = _norm0;\n"); + out.Write("o.WorldPos = pos.xyz;\n"); - if (g_ActiveConfig.bEnablePixelLighting) - { - out.Write("o.Normal = _norm0;\n"); - out.Write("o.WorldPos = pos.xyz;\n"); + if (components & VB_HAS_COL0) + out.Write("o.colors_0 = color0;\n"); - if (components & VB_HAS_COL0) - out.Write("o.colors_0 = color0;\n"); + if (components & VB_HAS_COL1) + out.Write("o.colors_1 = color1;\n"); + } - if (components & VB_HAS_COL1) - out.Write("o.colors_1 = color1;\n"); - } + // write the true depth value, if the game uses depth textures pixel shaders will override with + // the correct values + // if not early z culling will improve speed + if (g_ActiveConfig.backend_info.bSupportsClipControl) + { + out.Write("o.pos.z = -o.pos.z;\n"); + } + else // OGL + { + // this results in a scale from -1..0 to -1..1 after perspective + // divide + out.Write("o.pos.z = o.pos.z * -2.0 - o.pos.w;\n"); - //write the true depth value, if the game uses depth textures pixel shaders will override with the correct values - //if not early z culling will improve speed - if (g_ActiveConfig.backend_info.bSupportsClipControl) - { - out.Write("o.pos.z = -o.pos.z;\n"); - } - else // OGL - { - // this results in a scale from -1..0 to -1..1 after perspective - // divide - out.Write("o.pos.z = o.pos.z * -2.0 - o.pos.w;\n"); + // the next steps of the OGL pipeline are: + // (x_c,y_c,z_c,w_c) = o.pos //switch to OGL spec terminology + // clipping to -w_c <= (x_c,y_c,z_c) <= w_c + // (x_d,y_d,z_d) = (x_c,y_c,z_c)/w_c//perspective divide + // z_w = (f-n)/2*z_d + (n+f)/2 + // z_w now contains the value to go to the 0..1 depth buffer - // the next steps of the OGL pipeline are: - // (x_c,y_c,z_c,w_c) = o.pos //switch to OGL spec terminology - // clipping to -w_c <= (x_c,y_c,z_c) <= w_c - // (x_d,y_d,z_d) = (x_c,y_c,z_c)/w_c//perspective divide - // z_w = (f-n)/2*z_d + (n+f)/2 - // z_w now contains the value to go to the 0..1 depth buffer + // trying to get the correct semantic while not using glDepthRange + // seems to get rather complicated + } - //trying to get the correct semantic while not using glDepthRange - //seems to get rather complicated - } + // The console GPU places the pixel center at 7/12 in screen space unless + // antialiasing is enabled, while D3D and OpenGL place it at 0.5. This results + // in some primitives being placed one pixel too far to the bottom-right, + // which in turn can be critical if it happens for clear quads. + // Hence, we compensate for this pixel center difference so that primitives + // get rasterized correctly. + out.Write("o.pos.xy = o.pos.xy - o.pos.w * " I_PIXELCENTERCORRECTION ".xy;\n"); - // The console GPU places the pixel center at 7/12 in screen space unless - // antialiasing is enabled, while D3D and OpenGL place it at 0.5. This results - // in some primitives being placed one pixel too far to the bottom-right, - // which in turn can be critical if it happens for clear quads. - // Hence, we compensate for this pixel center difference so that primitives - // get rasterized correctly. - out.Write("o.pos.xy = o.pos.xy - o.pos.w * " I_PIXELCENTERCORRECTION".xy;\n"); + if (api_type == API_OPENGL) + { + if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) + { + AssignVSOutputMembers(out, "vs", "o"); + } + else + { + // TODO: Pass interface blocks between shader stages even if geometry shaders + // are not supported, however that will require at least OpenGL 3.2 support. + for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) + out.Write("uv%d.xyz = o.tex%d;\n", i, i); + out.Write("clipPos = o.clipPos;\n"); + if (g_ActiveConfig.bEnablePixelLighting) + { + out.Write("Normal = o.Normal;\n"); + out.Write("WorldPos = o.WorldPos;\n"); + } + out.Write("colors_0 = o.colors_0;\n"); + out.Write("colors_1 = o.colors_1;\n"); + } - if (api_type == API_OPENGL) - { - if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) - { - AssignVSOutputMembers(out, "vs", "o"); - } - else - { - // TODO: Pass interface blocks between shader stages even if geometry shaders - // are not supported, however that will require at least OpenGL 3.2 support. - for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) - out.Write("uv%d.xyz = o.tex%d;\n", i, i); - out.Write("clipPos = o.clipPos;\n"); - if (g_ActiveConfig.bEnablePixelLighting) - { - out.Write("Normal = o.Normal;\n"); - out.Write("WorldPos = o.WorldPos;\n"); - } - out.Write("colors_0 = o.colors_0;\n"); - out.Write("colors_1 = o.colors_1;\n"); - } + out.Write("gl_Position = o.pos;\n"); + } + else // D3D + { + out.Write("return o;\n"); + } + out.Write("}\n"); - out.Write("gl_Position = o.pos;\n"); - } - else // D3D - { - out.Write("return o;\n"); - } - out.Write("}\n"); - - return out; + return out; } VertexShaderUid GetVertexShaderUid(API_TYPE api_type) { - return GenerateVertexShader(api_type); + return GenerateVertexShader(api_type); } ShaderCode GenerateVertexShaderCode(API_TYPE api_type) { - return GenerateVertexShader(api_type); + return GenerateVertexShader(api_type); } diff --git a/Source/Core/VideoCommon/VertexShaderGen.h b/Source/Core/VideoCommon/VertexShaderGen.h index e98a6a4bc2..959226ea15 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.h +++ b/Source/Core/VideoCommon/VertexShaderGen.h @@ -10,52 +10,54 @@ #include "VideoCommon/VideoCommon.h" // TODO should be reordered -#define SHADER_POSITION_ATTRIB 0 -#define SHADER_POSMTX_ATTRIB 1 -#define SHADER_NORM0_ATTRIB 2 -#define SHADER_NORM1_ATTRIB 3 -#define SHADER_NORM2_ATTRIB 4 -#define SHADER_COLOR0_ATTRIB 5 -#define SHADER_COLOR1_ATTRIB 6 +#define SHADER_POSITION_ATTRIB 0 +#define SHADER_POSMTX_ATTRIB 1 +#define SHADER_NORM0_ATTRIB 2 +#define SHADER_NORM1_ATTRIB 3 +#define SHADER_NORM2_ATTRIB 4 +#define SHADER_COLOR0_ATTRIB 5 +#define SHADER_COLOR1_ATTRIB 6 -#define SHADER_TEXTURE0_ATTRIB 8 -#define SHADER_TEXTURE1_ATTRIB 9 -#define SHADER_TEXTURE2_ATTRIB 10 -#define SHADER_TEXTURE3_ATTRIB 11 -#define SHADER_TEXTURE4_ATTRIB 12 -#define SHADER_TEXTURE5_ATTRIB 13 -#define SHADER_TEXTURE6_ATTRIB 14 -#define SHADER_TEXTURE7_ATTRIB 15 +#define SHADER_TEXTURE0_ATTRIB 8 +#define SHADER_TEXTURE1_ATTRIB 9 +#define SHADER_TEXTURE2_ATTRIB 10 +#define SHADER_TEXTURE3_ATTRIB 11 +#define SHADER_TEXTURE4_ATTRIB 12 +#define SHADER_TEXTURE5_ATTRIB 13 +#define SHADER_TEXTURE6_ATTRIB 14 +#define SHADER_TEXTURE7_ATTRIB 15 #pragma pack(1) struct vertex_shader_uid_data { - u32 NumValues() const { return sizeof(vertex_shader_uid_data); } + u32 NumValues() const { return sizeof(vertex_shader_uid_data); } + u32 components : 23; + u32 numTexGens : 4; + u32 numColorChans : 2; + u32 dualTexTrans_enabled : 1; + u32 pixel_lighting : 1; + u32 pad : 1; - u32 components : 23; - u32 numTexGens : 4; - u32 numColorChans : 2; - u32 dualTexTrans_enabled : 1; - u32 pixel_lighting : 1; - u32 pad : 1; + u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is + // 8 bits wide + struct + { + u32 inputform : 2; + u32 texgentype : 3; + u32 sourcerow : 5; + u32 embosssourceshift : 3; + u32 embosslightshift : 3; + } texMtxInfo[8]; - u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is 8 bits wide - struct { - u32 inputform : 2; - u32 texgentype : 3; - u32 sourcerow : 5; - u32 embosssourceshift : 3; - u32 embosslightshift : 3; - } texMtxInfo[8]; + struct + { + u32 index : 6; + u32 normalize : 1; + u32 pad : 1; + } postMtxInfo[8]; - struct { - u32 index : 6; - u32 normalize : 1; - u32 pad : 1; - } postMtxInfo[8]; - - LightingUidData lighting; + LightingUidData lighting; }; #pragma pack() diff --git a/Source/Core/VideoCommon/VertexShaderManager.cpp b/Source/Core/VideoCommon/VertexShaderManager.cpp index 54c4f77029..c90195f13e 100644 --- a/Source/Core/VideoCommon/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/VertexShaderManager.cpp @@ -12,8 +12,8 @@ #include "Common/ChunkFile.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" -#include "Common/MathUtil.h" #include "Common/Logging/Log.h" +#include "Common/MathUtil.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "VideoCommon/BPMemory.h" @@ -31,10 +31,10 @@ alignas(16) static float g_fProjectionMatrix[16]; // track changes static bool bTexMatricesChanged[2], bPosNormalMatrixChanged, bProjectionChanged, bViewportChanged; static BitSet32 nMaterialsChanged; -static int nTransformMatricesChanged[2]; // min,max -static int nNormalMatricesChanged[2]; // min,max -static int nPostTransformMatricesChanged[2]; // min,max -static int nLightsChanged[2]; // min,max +static int nTransformMatricesChanged[2]; // min,max +static int nNormalMatricesChanged[2]; // min,max +static int nPostTransformMatricesChanged[2]; // min,max +static int nLightsChanged[2]; // min,max static Matrix44 s_viewportCorrection; static Matrix33 s_viewRotationMatrix; @@ -47,11 +47,10 @@ bool VertexShaderManager::dirty; struct ProjectionHack { - float sign; - float value; - ProjectionHack() { } - ProjectionHack(float new_sign, float new_value) - : sign(new_sign), value(new_value) {} + float sign; + float value; + ProjectionHack() {} + ProjectionHack(float new_sign, float new_value) : sign(new_sign), value(new_value) {} }; namespace @@ -59,38 +58,38 @@ namespace // Control Variables static ProjectionHack g_ProjHack1; static ProjectionHack g_ProjHack2; -} // Namespace +} // Namespace static float PHackValue(std::string sValue) { - float f = 0; - bool fp = false; - const char *cStr = sValue.c_str(); - char *c = new char[strlen(cStr) + 1]; - std::istringstream sTof(""); + float f = 0; + bool fp = false; + const char* cStr = sValue.c_str(); + char* c = new char[strlen(cStr) + 1]; + std::istringstream sTof(""); - for (unsigned int i = 0; i <= strlen(cStr); ++i) - { - if (i == 20) - { - c[i] = '\0'; - break; - } + for (unsigned int i = 0; i <= strlen(cStr); ++i) + { + if (i == 20) + { + c[i] = '\0'; + break; + } - c[i] = (cStr[i] == ',') ? '.' : *(cStr + i); - if (c[i] == '.') - fp = true; - } + c[i] = (cStr[i] == ',') ? '.' : *(cStr + i); + if (c[i] == '.') + fp = true; + } - cStr = c; - sTof.str(cStr); - sTof >> f; + cStr = c; + sTof.str(cStr); + sTof >> f; - if (!fp) - f /= 0xF4240; + if (!fp) + f /= 0xF4240; - delete[] c; - return f; + delete[] c; + return f; } // Due to the BT.601 standard which the GameCube is based on being a compromise @@ -100,45 +99,43 @@ static float PHackValue(std::string sValue) // tests with a large amount of slop. static bool AspectIs4_3(float width, float height) { - float aspect = fabsf(width / height); - return fabsf(aspect - 4.0f / 3.0f) < 4.0f / 3.0f * 0.11; // within 11% of 4:3 + float aspect = fabsf(width / height); + return fabsf(aspect - 4.0f / 3.0f) < 4.0f / 3.0f * 0.11; // within 11% of 4:3 } static bool AspectIs16_9(float width, float height) { - float aspect = fabsf(width / height); - return fabsf(aspect - 16.0f / 9.0f) < 16.0f / 9.0f * 0.11; // within 11% of 16:9 + float aspect = fabsf(width / height); + return fabsf(aspect - 16.0f / 9.0f) < 16.0f / 9.0f * 0.11; // within 11% of 16:9 } void UpdateProjectionHack(int iPhackvalue[], std::string sPhackvalue[]) { - float fhackvalue1 = 0, fhackvalue2 = 0; - float fhacksign1 = 1.0, fhacksign2 = 1.0; - const char *sTemp[2]; + float fhackvalue1 = 0, fhackvalue2 = 0; + float fhacksign1 = 1.0, fhacksign2 = 1.0; + const char* sTemp[2]; - if (iPhackvalue[0] == 1) - { - NOTICE_LOG(VIDEO, "\t\t--- Orthographic Projection Hack ON ---"); + if (iPhackvalue[0] == 1) + { + NOTICE_LOG(VIDEO, "\t\t--- Orthographic Projection Hack ON ---"); - fhacksign1 *= (iPhackvalue[1] == 1) ? -1.0f : fhacksign1; - sTemp[0] = (iPhackvalue[1] == 1) ? " * (-1)" : ""; - fhacksign2 *= (iPhackvalue[2] == 1) ? -1.0f : fhacksign2; - sTemp[1] = (iPhackvalue[2] == 1) ? " * (-1)" : ""; + fhacksign1 *= (iPhackvalue[1] == 1) ? -1.0f : fhacksign1; + sTemp[0] = (iPhackvalue[1] == 1) ? " * (-1)" : ""; + fhacksign2 *= (iPhackvalue[2] == 1) ? -1.0f : fhacksign2; + sTemp[1] = (iPhackvalue[2] == 1) ? " * (-1)" : ""; - fhackvalue1 = PHackValue(sPhackvalue[0]); - NOTICE_LOG(VIDEO, "- zNear Correction = (%f + zNear)%s", fhackvalue1, sTemp[0]); + fhackvalue1 = PHackValue(sPhackvalue[0]); + NOTICE_LOG(VIDEO, "- zNear Correction = (%f + zNear)%s", fhackvalue1, sTemp[0]); - fhackvalue2 = PHackValue(sPhackvalue[1]); - NOTICE_LOG(VIDEO, "- zFar Correction = (%f + zFar)%s", fhackvalue2, sTemp[1]); + fhackvalue2 = PHackValue(sPhackvalue[1]); + NOTICE_LOG(VIDEO, "- zFar Correction = (%f + zFar)%s", fhackvalue2, sTemp[1]); + } - } - - // Set the projections hacks - g_ProjHack1 = ProjectionHack(fhacksign1, fhackvalue1); - g_ProjHack2 = ProjectionHack(fhacksign2, fhackvalue2); + // Set the projections hacks + g_ProjHack1 = ProjectionHack(fhacksign1, fhackvalue1); + g_ProjHack2 = ProjectionHack(fhacksign2, fhackvalue2); } - // Viewport correction: // In D3D, the viewport rectangle must fit within the render target. // Say you want a viewport at (ix, iy) with size (iw, ih), @@ -151,72 +148,72 @@ void UpdateProjectionHack(int iPhackvalue[], std::string sPhackvalue[]) // [ 0 0 0 1 ] static void ViewportCorrectionMatrix(Matrix44& result) { - int scissorXOff = bpmem.scissorOffset.x * 2; - int scissorYOff = bpmem.scissorOffset.y * 2; + int scissorXOff = bpmem.scissorOffset.x * 2; + int scissorYOff = bpmem.scissorOffset.y * 2; - // TODO: ceil, floor or just cast to int? - // TODO: Directly use the floats instead of rounding them? - float intendedX = xfmem.viewport.xOrig - xfmem.viewport.wd - scissorXOff; - float intendedY = xfmem.viewport.yOrig + xfmem.viewport.ht - scissorYOff; - float intendedWd = 2.0f * xfmem.viewport.wd; - float intendedHt = -2.0f * xfmem.viewport.ht; + // TODO: ceil, floor or just cast to int? + // TODO: Directly use the floats instead of rounding them? + float intendedX = xfmem.viewport.xOrig - xfmem.viewport.wd - scissorXOff; + float intendedY = xfmem.viewport.yOrig + xfmem.viewport.ht - scissorYOff; + float intendedWd = 2.0f * xfmem.viewport.wd; + float intendedHt = -2.0f * xfmem.viewport.ht; - if (intendedWd < 0.f) - { - intendedX += intendedWd; - intendedWd = -intendedWd; - } - if (intendedHt < 0.f) - { - intendedY += intendedHt; - intendedHt = -intendedHt; - } + if (intendedWd < 0.f) + { + intendedX += intendedWd; + intendedWd = -intendedWd; + } + if (intendedHt < 0.f) + { + intendedY += intendedHt; + intendedHt = -intendedHt; + } - // fit to EFB size - float X = (intendedX >= 0.f) ? intendedX : 0.f; - float Y = (intendedY >= 0.f) ? intendedY : 0.f; - float Wd = (X + intendedWd <= EFB_WIDTH) ? intendedWd : (EFB_WIDTH - X); - float Ht = (Y + intendedHt <= EFB_HEIGHT) ? intendedHt : (EFB_HEIGHT - Y); + // fit to EFB size + float X = (intendedX >= 0.f) ? intendedX : 0.f; + float Y = (intendedY >= 0.f) ? intendedY : 0.f; + float Wd = (X + intendedWd <= EFB_WIDTH) ? intendedWd : (EFB_WIDTH - X); + float Ht = (Y + intendedHt <= EFB_HEIGHT) ? intendedHt : (EFB_HEIGHT - Y); - Matrix44::LoadIdentity(result); - if (Wd == 0 || Ht == 0) - return; + Matrix44::LoadIdentity(result); + if (Wd == 0 || Ht == 0) + return; - result.data[4*0 + 0] = intendedWd / Wd; - result.data[4*0 + 3] = (intendedWd - 2.f * (X - intendedX)) / Wd - 1.f; - result.data[4*1 + 1] = intendedHt / Ht; - result.data[4*1 + 3] = (-intendedHt + 2.f * (Y - intendedY)) / Ht + 1.f; + result.data[4 * 0 + 0] = intendedWd / Wd; + result.data[4 * 0 + 3] = (intendedWd - 2.f * (X - intendedX)) / Wd - 1.f; + result.data[4 * 1 + 1] = intendedHt / Ht; + result.data[4 * 1 + 3] = (-intendedHt + 2.f * (Y - intendedY)) / Ht + 1.f; } void VertexShaderManager::Init() { - // Initialize state tracking variables - nTransformMatricesChanged[0] = -1; - nTransformMatricesChanged[1] = -1; - nNormalMatricesChanged[0] = -1; - nNormalMatricesChanged[1] = -1; - nPostTransformMatricesChanged[0] = -1; - nPostTransformMatricesChanged[1] = -1; - nLightsChanged[0] = -1; - nLightsChanged[1] = -1; - nMaterialsChanged = BitSet32(0); - bTexMatricesChanged[0] = false; - bTexMatricesChanged[1] = false; - bPosNormalMatrixChanged = false; - bProjectionChanged = true; - bViewportChanged = false; + // Initialize state tracking variables + nTransformMatricesChanged[0] = -1; + nTransformMatricesChanged[1] = -1; + nNormalMatricesChanged[0] = -1; + nNormalMatricesChanged[1] = -1; + nPostTransformMatricesChanged[0] = -1; + nPostTransformMatricesChanged[1] = -1; + nLightsChanged[0] = -1; + nLightsChanged[1] = -1; + nMaterialsChanged = BitSet32(0); + bTexMatricesChanged[0] = false; + bTexMatricesChanged[1] = false; + bPosNormalMatrixChanged = false; + bProjectionChanged = true; + bViewportChanged = false; - memset(&xfmem, 0, sizeof(xfmem)); - memset(&constants, 0, sizeof(constants)); - ResetView(); + memset(&xfmem, 0, sizeof(xfmem)); + memset(&constants, 0, sizeof(constants)); + ResetView(); - // TODO: should these go inside ResetView()? - Matrix44::LoadIdentity(s_viewportCorrection); - memset(g_fProjectionMatrix, 0, sizeof(g_fProjectionMatrix)); - for (int i = 0; i < 4; ++i) - g_fProjectionMatrix[i*5] = 1.0f; + // TODO: should these go inside ResetView()? + Matrix44::LoadIdentity(s_viewportCorrection); + memset(g_fProjectionMatrix, 0, sizeof(g_fProjectionMatrix)); + for (int i = 0; i < 4; ++i) + g_fProjectionMatrix[i * 5] = 1.0f; - dirty = true; + dirty = true; } void VertexShaderManager::Shutdown() @@ -225,559 +222,577 @@ void VertexShaderManager::Shutdown() void VertexShaderManager::Dirty() { - // This function is called after a savestate is loaded. - // Any constants that can changed based on settings should be re-calculated - bProjectionChanged = true; + // This function is called after a savestate is loaded. + // Any constants that can changed based on settings should be re-calculated + bProjectionChanged = true; - dirty = true; + dirty = true; } // Syncs the shader constant buffers with xfmem // TODO: A cleaner way to control the matrices without making a mess in the parameters field void VertexShaderManager::SetConstants() { - if (nTransformMatricesChanged[0] >= 0) - { - int startn = nTransformMatricesChanged[0] / 4; - int endn = (nTransformMatricesChanged[1] + 3) / 4; - memcpy(constants.transformmatrices[startn], &xfmem.posMatrices[startn * 4], (endn - startn) * sizeof(float4)); - dirty = true; - nTransformMatricesChanged[0] = nTransformMatricesChanged[1] = -1; - } + if (nTransformMatricesChanged[0] >= 0) + { + int startn = nTransformMatricesChanged[0] / 4; + int endn = (nTransformMatricesChanged[1] + 3) / 4; + memcpy(constants.transformmatrices[startn], &xfmem.posMatrices[startn * 4], + (endn - startn) * sizeof(float4)); + dirty = true; + nTransformMatricesChanged[0] = nTransformMatricesChanged[1] = -1; + } - if (nNormalMatricesChanged[0] >= 0) - { - int startn = nNormalMatricesChanged[0] / 3; - int endn = (nNormalMatricesChanged[1] + 2) / 3; - for (int i = startn; i < endn; i++) - { - memcpy(constants.normalmatrices[i], &xfmem.normalMatrices[3*i], 12); - } - dirty = true; - nNormalMatricesChanged[0] = nNormalMatricesChanged[1] = -1; - } + if (nNormalMatricesChanged[0] >= 0) + { + int startn = nNormalMatricesChanged[0] / 3; + int endn = (nNormalMatricesChanged[1] + 2) / 3; + for (int i = startn; i < endn; i++) + { + memcpy(constants.normalmatrices[i], &xfmem.normalMatrices[3 * i], 12); + } + dirty = true; + nNormalMatricesChanged[0] = nNormalMatricesChanged[1] = -1; + } - if (nPostTransformMatricesChanged[0] >= 0) - { - int startn = nPostTransformMatricesChanged[0] / 4; - int endn = (nPostTransformMatricesChanged[1] + 3) / 4; - memcpy(constants.posttransformmatrices[startn], &xfmem.postMatrices[startn * 4], (endn - startn) * sizeof(float4)); - dirty = true; - nPostTransformMatricesChanged[0] = nPostTransformMatricesChanged[1] = -1; - } + if (nPostTransformMatricesChanged[0] >= 0) + { + int startn = nPostTransformMatricesChanged[0] / 4; + int endn = (nPostTransformMatricesChanged[1] + 3) / 4; + memcpy(constants.posttransformmatrices[startn], &xfmem.postMatrices[startn * 4], + (endn - startn) * sizeof(float4)); + dirty = true; + nPostTransformMatricesChanged[0] = nPostTransformMatricesChanged[1] = -1; + } - if (nLightsChanged[0] >= 0) - { - // TODO: Outdated comment - // lights don't have a 1 to 1 mapping, the color component needs to be converted to 4 floats - int istart = nLightsChanged[0] / 0x10; - int iend = (nLightsChanged[1] + 15) / 0x10; + if (nLightsChanged[0] >= 0) + { + // TODO: Outdated comment + // lights don't have a 1 to 1 mapping, the color component needs to be converted to 4 floats + int istart = nLightsChanged[0] / 0x10; + int iend = (nLightsChanged[1] + 15) / 0x10; - for (int i = istart; i < iend; ++i) - { - const Light& light = xfmem.lights[i]; - VertexShaderConstants::Light& dstlight = constants.lights[i]; + for (int i = istart; i < iend; ++i) + { + const Light& light = xfmem.lights[i]; + VertexShaderConstants::Light& dstlight = constants.lights[i]; - // xfmem.light.color is packed as abgr in u8[4], so we have to swap the order - dstlight.color[0] = light.color[3]; - dstlight.color[1] = light.color[2]; - dstlight.color[2] = light.color[1]; - dstlight.color[3] = light.color[0]; + // xfmem.light.color is packed as abgr in u8[4], so we have to swap the order + dstlight.color[0] = light.color[3]; + dstlight.color[1] = light.color[2]; + dstlight.color[2] = light.color[1]; + dstlight.color[3] = light.color[0]; - dstlight.cosatt[0] = light.cosatt[0]; - dstlight.cosatt[1] = light.cosatt[1]; - dstlight.cosatt[2] = light.cosatt[2]; + dstlight.cosatt[0] = light.cosatt[0]; + dstlight.cosatt[1] = light.cosatt[1]; + dstlight.cosatt[2] = light.cosatt[2]; - if (fabs(light.distatt[0]) < 0.00001f && - fabs(light.distatt[1]) < 0.00001f && - fabs(light.distatt[2]) < 0.00001f) - { - // dist attenuation, make sure not equal to 0!!! - dstlight.distatt[0] = .00001f; - } - else - { - dstlight.distatt[0] = light.distatt[0]; - } - dstlight.distatt[1] = light.distatt[1]; - dstlight.distatt[2] = light.distatt[2]; + if (fabs(light.distatt[0]) < 0.00001f && fabs(light.distatt[1]) < 0.00001f && + fabs(light.distatt[2]) < 0.00001f) + { + // dist attenuation, make sure not equal to 0!!! + dstlight.distatt[0] = .00001f; + } + else + { + dstlight.distatt[0] = light.distatt[0]; + } + dstlight.distatt[1] = light.distatt[1]; + dstlight.distatt[2] = light.distatt[2]; - dstlight.pos[0] = light.dpos[0]; - dstlight.pos[1] = light.dpos[1]; - dstlight.pos[2] = light.dpos[2]; + dstlight.pos[0] = light.dpos[0]; + dstlight.pos[1] = light.dpos[1]; + dstlight.pos[2] = light.dpos[2]; - double norm = double(light.ddir[0]) * double(light.ddir[0]) + - double(light.ddir[1]) * double(light.ddir[1]) + - double(light.ddir[2]) * double(light.ddir[2]); - norm = 1.0 / sqrt(norm); - float norm_float = static_cast(norm); - dstlight.dir[0] = light.ddir[0] * norm_float; - dstlight.dir[1] = light.ddir[1] * norm_float; - dstlight.dir[2] = light.ddir[2] * norm_float; - } - dirty = true; + double norm = double(light.ddir[0]) * double(light.ddir[0]) + + double(light.ddir[1]) * double(light.ddir[1]) + + double(light.ddir[2]) * double(light.ddir[2]); + norm = 1.0 / sqrt(norm); + float norm_float = static_cast(norm); + dstlight.dir[0] = light.ddir[0] * norm_float; + dstlight.dir[1] = light.ddir[1] * norm_float; + dstlight.dir[2] = light.ddir[2] * norm_float; + } + dirty = true; - nLightsChanged[0] = nLightsChanged[1] = -1; - } + nLightsChanged[0] = nLightsChanged[1] = -1; + } - for (int i : nMaterialsChanged) - { - u32 data = i >= 2 ? xfmem.matColor[i - 2] : xfmem.ambColor[i]; - constants.materials[i][0] = (data >> 24) & 0xFF; - constants.materials[i][1] = (data >> 16) & 0xFF; - constants.materials[i][2] = (data >> 8) & 0xFF; - constants.materials[i][3] = data & 0xFF; - dirty = true; - } - nMaterialsChanged = BitSet32(0); + for (int i : nMaterialsChanged) + { + u32 data = i >= 2 ? xfmem.matColor[i - 2] : xfmem.ambColor[i]; + constants.materials[i][0] = (data >> 24) & 0xFF; + constants.materials[i][1] = (data >> 16) & 0xFF; + constants.materials[i][2] = (data >> 8) & 0xFF; + constants.materials[i][3] = data & 0xFF; + dirty = true; + } + nMaterialsChanged = BitSet32(0); - if (bPosNormalMatrixChanged) - { - bPosNormalMatrixChanged = false; + if (bPosNormalMatrixChanged) + { + bPosNormalMatrixChanged = false; - const float* pos = &xfmem.posMatrices[g_main_cp_state.matrix_index_a.PosNormalMtxIdx * 4]; - const float* norm = &xfmem.normalMatrices[3 * (g_main_cp_state.matrix_index_a.PosNormalMtxIdx & 31)]; + const float* pos = &xfmem.posMatrices[g_main_cp_state.matrix_index_a.PosNormalMtxIdx * 4]; + const float* norm = + &xfmem.normalMatrices[3 * (g_main_cp_state.matrix_index_a.PosNormalMtxIdx & 31)]; - memcpy(constants.posnormalmatrix, pos, 3 * sizeof(float4)); - memcpy(constants.posnormalmatrix[3], norm, 3 * sizeof(float)); - memcpy(constants.posnormalmatrix[4], norm + 3, 3 * sizeof(float)); - memcpy(constants.posnormalmatrix[5], norm + 6, 3 * sizeof(float)); - dirty = true; - } + memcpy(constants.posnormalmatrix, pos, 3 * sizeof(float4)); + memcpy(constants.posnormalmatrix[3], norm, 3 * sizeof(float)); + memcpy(constants.posnormalmatrix[4], norm + 3, 3 * sizeof(float)); + memcpy(constants.posnormalmatrix[5], norm + 6, 3 * sizeof(float)); + dirty = true; + } - if (bTexMatricesChanged[0]) - { - bTexMatricesChanged[0] = false; - const float* pos_matrix_ptrs[] = - { - &xfmem.posMatrices[g_main_cp_state.matrix_index_a.Tex0MtxIdx * 4], - &xfmem.posMatrices[g_main_cp_state.matrix_index_a.Tex1MtxIdx * 4], - &xfmem.posMatrices[g_main_cp_state.matrix_index_a.Tex2MtxIdx * 4], - &xfmem.posMatrices[g_main_cp_state.matrix_index_a.Tex3MtxIdx * 4] - }; + if (bTexMatricesChanged[0]) + { + bTexMatricesChanged[0] = false; + const float* pos_matrix_ptrs[] = { + &xfmem.posMatrices[g_main_cp_state.matrix_index_a.Tex0MtxIdx * 4], + &xfmem.posMatrices[g_main_cp_state.matrix_index_a.Tex1MtxIdx * 4], + &xfmem.posMatrices[g_main_cp_state.matrix_index_a.Tex2MtxIdx * 4], + &xfmem.posMatrices[g_main_cp_state.matrix_index_a.Tex3MtxIdx * 4]}; - for (size_t i = 0; i < ArraySize(pos_matrix_ptrs); ++i) - { - memcpy(constants.texmatrices[3 * i], pos_matrix_ptrs[i], 3 * sizeof(float4)); - } - dirty = true; - } + for (size_t i = 0; i < ArraySize(pos_matrix_ptrs); ++i) + { + memcpy(constants.texmatrices[3 * i], pos_matrix_ptrs[i], 3 * sizeof(float4)); + } + dirty = true; + } - if (bTexMatricesChanged[1]) - { - bTexMatricesChanged[1] = false; - const float* pos_matrix_ptrs[] = { - &xfmem.posMatrices[g_main_cp_state.matrix_index_b.Tex4MtxIdx * 4], - &xfmem.posMatrices[g_main_cp_state.matrix_index_b.Tex5MtxIdx * 4], - &xfmem.posMatrices[g_main_cp_state.matrix_index_b.Tex6MtxIdx * 4], - &xfmem.posMatrices[g_main_cp_state.matrix_index_b.Tex7MtxIdx * 4] - }; + if (bTexMatricesChanged[1]) + { + bTexMatricesChanged[1] = false; + const float* pos_matrix_ptrs[] = { + &xfmem.posMatrices[g_main_cp_state.matrix_index_b.Tex4MtxIdx * 4], + &xfmem.posMatrices[g_main_cp_state.matrix_index_b.Tex5MtxIdx * 4], + &xfmem.posMatrices[g_main_cp_state.matrix_index_b.Tex6MtxIdx * 4], + &xfmem.posMatrices[g_main_cp_state.matrix_index_b.Tex7MtxIdx * 4]}; - for (size_t i = 0; i < ArraySize(pos_matrix_ptrs); ++i) - { - memcpy(constants.texmatrices[3*i + 12], pos_matrix_ptrs[i], 3 * sizeof(float4)); - } - dirty = true; - } + for (size_t i = 0; i < ArraySize(pos_matrix_ptrs); ++i) + { + memcpy(constants.texmatrices[3 * i + 12], pos_matrix_ptrs[i], 3 * sizeof(float4)); + } + dirty = true; + } - if (bViewportChanged) - { - bViewportChanged = false; + if (bViewportChanged) + { + bViewportChanged = false; - // The console GPU places the pixel center at 7/12 unless antialiasing - // is enabled, while D3D and OpenGL place it at 0.5. See the comment - // in VertexShaderGen.cpp for details. - // NOTE: If we ever emulate antialiasing, the sample locations set by - // BP registers 0x01-0x04 need to be considered here. - const float pixel_center_correction = 7.0f / 12.0f - 0.5f; - const float pixel_size_x = 2.f / Renderer::EFBToScaledXf(2.f * xfmem.viewport.wd); - const float pixel_size_y = 2.f / Renderer::EFBToScaledXf(2.f * xfmem.viewport.ht); - constants.pixelcentercorrection[0] = pixel_center_correction * pixel_size_x; - constants.pixelcentercorrection[1] = pixel_center_correction * pixel_size_y; - dirty = true; - // This is so implementation-dependent that we can't have it here. - g_renderer->SetViewport(); + // The console GPU places the pixel center at 7/12 unless antialiasing + // is enabled, while D3D and OpenGL place it at 0.5. See the comment + // in VertexShaderGen.cpp for details. + // NOTE: If we ever emulate antialiasing, the sample locations set by + // BP registers 0x01-0x04 need to be considered here. + const float pixel_center_correction = 7.0f / 12.0f - 0.5f; + const float pixel_size_x = 2.f / Renderer::EFBToScaledXf(2.f * xfmem.viewport.wd); + const float pixel_size_y = 2.f / Renderer::EFBToScaledXf(2.f * xfmem.viewport.ht); + constants.pixelcentercorrection[0] = pixel_center_correction * pixel_size_x; + constants.pixelcentercorrection[1] = pixel_center_correction * pixel_size_y; + dirty = true; + // This is so implementation-dependent that we can't have it here. + g_renderer->SetViewport(); - // Update projection if the viewport isn't 1:1 useable - if (!g_ActiveConfig.backend_info.bSupportsOversizedViewports) - { - ViewportCorrectionMatrix(s_viewportCorrection); - bProjectionChanged = true; - } - } + // Update projection if the viewport isn't 1:1 useable + if (!g_ActiveConfig.backend_info.bSupportsOversizedViewports) + { + ViewportCorrectionMatrix(s_viewportCorrection); + bProjectionChanged = true; + } + } - if (bProjectionChanged) - { - bProjectionChanged = false; + if (bProjectionChanged) + { + bProjectionChanged = false; - float *rawProjection = xfmem.projection.rawProjection; + float* rawProjection = xfmem.projection.rawProjection; - switch (xfmem.projection.type) - { - case GX_PERSPECTIVE: + switch (xfmem.projection.type) + { + case GX_PERSPECTIVE: - g_fProjectionMatrix[0] = rawProjection[0] * g_ActiveConfig.fAspectRatioHackW; - g_fProjectionMatrix[1] = 0.0f; - g_fProjectionMatrix[2] = rawProjection[1]; - g_fProjectionMatrix[3] = 0.0f; + g_fProjectionMatrix[0] = rawProjection[0] * g_ActiveConfig.fAspectRatioHackW; + g_fProjectionMatrix[1] = 0.0f; + g_fProjectionMatrix[2] = rawProjection[1]; + g_fProjectionMatrix[3] = 0.0f; - g_fProjectionMatrix[4] = 0.0f; - g_fProjectionMatrix[5] = rawProjection[2] * g_ActiveConfig.fAspectRatioHackH; - g_fProjectionMatrix[6] = rawProjection[3]; - g_fProjectionMatrix[7] = 0.0f; + g_fProjectionMatrix[4] = 0.0f; + g_fProjectionMatrix[5] = rawProjection[2] * g_ActiveConfig.fAspectRatioHackH; + g_fProjectionMatrix[6] = rawProjection[3]; + g_fProjectionMatrix[7] = 0.0f; - g_fProjectionMatrix[8] = 0.0f; - g_fProjectionMatrix[9] = 0.0f; - g_fProjectionMatrix[10] = rawProjection[4]; + g_fProjectionMatrix[8] = 0.0f; + g_fProjectionMatrix[9] = 0.0f; + g_fProjectionMatrix[10] = rawProjection[4]; - g_fProjectionMatrix[11] = rawProjection[5]; + g_fProjectionMatrix[11] = rawProjection[5]; - g_fProjectionMatrix[12] = 0.0f; - g_fProjectionMatrix[13] = 0.0f; + g_fProjectionMatrix[12] = 0.0f; + g_fProjectionMatrix[13] = 0.0f; - // Hack to fix depth clipping precision issues (such as Sonic Adventure UI) - g_fProjectionMatrix[14] = -(1.0f + FLT_EPSILON); - g_fProjectionMatrix[15] = 0.0f; + // Hack to fix depth clipping precision issues (such as Sonic Adventure UI) + g_fProjectionMatrix[14] = -(1.0f + FLT_EPSILON); + g_fProjectionMatrix[15] = 0.0f; - // Heuristic to detect if a GameCube game is in 16:9 anamorphic widescreen mode. - if (!SConfig::GetInstance().bWii) - { - bool viewport_is_4_3 = AspectIs4_3(xfmem.viewport.wd, xfmem.viewport.ht); - if (AspectIs16_9(rawProjection[2], rawProjection[0]) && viewport_is_4_3) - Core::g_aspect_wide = true; // Projection is 16:9 and viewport is 4:3, we are rendering an anamorphic widescreen picture - else if (AspectIs4_3(rawProjection[2], rawProjection[0]) && viewport_is_4_3) - Core::g_aspect_wide = false; // Project and viewports are both 4:3, we are rendering a normal image. - } + // Heuristic to detect if a GameCube game is in 16:9 anamorphic widescreen mode. + if (!SConfig::GetInstance().bWii) + { + bool viewport_is_4_3 = AspectIs4_3(xfmem.viewport.wd, xfmem.viewport.ht); + if (AspectIs16_9(rawProjection[2], rawProjection[0]) && viewport_is_4_3) + Core::g_aspect_wide = true; // Projection is 16:9 and viewport is 4:3, we are rendering + // an anamorphic widescreen picture + else if (AspectIs4_3(rawProjection[2], rawProjection[0]) && viewport_is_4_3) + Core::g_aspect_wide = + false; // Project and viewports are both 4:3, we are rendering a normal image. + } - SETSTAT_FT(stats.gproj_0, g_fProjectionMatrix[0]); - SETSTAT_FT(stats.gproj_1, g_fProjectionMatrix[1]); - SETSTAT_FT(stats.gproj_2, g_fProjectionMatrix[2]); - SETSTAT_FT(stats.gproj_3, g_fProjectionMatrix[3]); - SETSTAT_FT(stats.gproj_4, g_fProjectionMatrix[4]); - SETSTAT_FT(stats.gproj_5, g_fProjectionMatrix[5]); - SETSTAT_FT(stats.gproj_6, g_fProjectionMatrix[6]); - SETSTAT_FT(stats.gproj_7, g_fProjectionMatrix[7]); - SETSTAT_FT(stats.gproj_8, g_fProjectionMatrix[8]); - SETSTAT_FT(stats.gproj_9, g_fProjectionMatrix[9]); - SETSTAT_FT(stats.gproj_10, g_fProjectionMatrix[10]); - SETSTAT_FT(stats.gproj_11, g_fProjectionMatrix[11]); - SETSTAT_FT(stats.gproj_12, g_fProjectionMatrix[12]); - SETSTAT_FT(stats.gproj_13, g_fProjectionMatrix[13]); - SETSTAT_FT(stats.gproj_14, g_fProjectionMatrix[14]); - SETSTAT_FT(stats.gproj_15, g_fProjectionMatrix[15]); - break; + SETSTAT_FT(stats.gproj_0, g_fProjectionMatrix[0]); + SETSTAT_FT(stats.gproj_1, g_fProjectionMatrix[1]); + SETSTAT_FT(stats.gproj_2, g_fProjectionMatrix[2]); + SETSTAT_FT(stats.gproj_3, g_fProjectionMatrix[3]); + SETSTAT_FT(stats.gproj_4, g_fProjectionMatrix[4]); + SETSTAT_FT(stats.gproj_5, g_fProjectionMatrix[5]); + SETSTAT_FT(stats.gproj_6, g_fProjectionMatrix[6]); + SETSTAT_FT(stats.gproj_7, g_fProjectionMatrix[7]); + SETSTAT_FT(stats.gproj_8, g_fProjectionMatrix[8]); + SETSTAT_FT(stats.gproj_9, g_fProjectionMatrix[9]); + SETSTAT_FT(stats.gproj_10, g_fProjectionMatrix[10]); + SETSTAT_FT(stats.gproj_11, g_fProjectionMatrix[11]); + SETSTAT_FT(stats.gproj_12, g_fProjectionMatrix[12]); + SETSTAT_FT(stats.gproj_13, g_fProjectionMatrix[13]); + SETSTAT_FT(stats.gproj_14, g_fProjectionMatrix[14]); + SETSTAT_FT(stats.gproj_15, g_fProjectionMatrix[15]); + break; - case GX_ORTHOGRAPHIC: + case GX_ORTHOGRAPHIC: - g_fProjectionMatrix[0] = rawProjection[0]; - g_fProjectionMatrix[1] = 0.0f; - g_fProjectionMatrix[2] = 0.0f; - g_fProjectionMatrix[3] = rawProjection[1]; + g_fProjectionMatrix[0] = rawProjection[0]; + g_fProjectionMatrix[1] = 0.0f; + g_fProjectionMatrix[2] = 0.0f; + g_fProjectionMatrix[3] = rawProjection[1]; - g_fProjectionMatrix[4] = 0.0f; - g_fProjectionMatrix[5] = rawProjection[2]; - g_fProjectionMatrix[6] = 0.0f; - g_fProjectionMatrix[7] = rawProjection[3]; + g_fProjectionMatrix[4] = 0.0f; + g_fProjectionMatrix[5] = rawProjection[2]; + g_fProjectionMatrix[6] = 0.0f; + g_fProjectionMatrix[7] = rawProjection[3]; - g_fProjectionMatrix[8] = 0.0f; - g_fProjectionMatrix[9] = 0.0f; - g_fProjectionMatrix[10] = (g_ProjHack1.value + rawProjection[4]) * ((g_ProjHack1.sign == 0) ? 1.0f : g_ProjHack1.sign); - g_fProjectionMatrix[11] = (g_ProjHack2.value + rawProjection[5]) * ((g_ProjHack2.sign == 0) ? 1.0f : g_ProjHack2.sign); + g_fProjectionMatrix[8] = 0.0f; + g_fProjectionMatrix[9] = 0.0f; + g_fProjectionMatrix[10] = (g_ProjHack1.value + rawProjection[4]) * + ((g_ProjHack1.sign == 0) ? 1.0f : g_ProjHack1.sign); + g_fProjectionMatrix[11] = (g_ProjHack2.value + rawProjection[5]) * + ((g_ProjHack2.sign == 0) ? 1.0f : g_ProjHack2.sign); - g_fProjectionMatrix[12] = 0.0f; - g_fProjectionMatrix[13] = 0.0f; + g_fProjectionMatrix[12] = 0.0f; + g_fProjectionMatrix[13] = 0.0f; - g_fProjectionMatrix[14] = 0.0f; + g_fProjectionMatrix[14] = 0.0f; - // Hack to fix depth clipping precision issues (such as Sonic Unleashed UI) - g_fProjectionMatrix[15] = 1.0f + FLT_EPSILON; + // Hack to fix depth clipping precision issues (such as Sonic Unleashed UI) + g_fProjectionMatrix[15] = 1.0f + FLT_EPSILON; - SETSTAT_FT(stats.g2proj_0, g_fProjectionMatrix[0]); - SETSTAT_FT(stats.g2proj_1, g_fProjectionMatrix[1]); - SETSTAT_FT(stats.g2proj_2, g_fProjectionMatrix[2]); - SETSTAT_FT(stats.g2proj_3, g_fProjectionMatrix[3]); - SETSTAT_FT(stats.g2proj_4, g_fProjectionMatrix[4]); - SETSTAT_FT(stats.g2proj_5, g_fProjectionMatrix[5]); - SETSTAT_FT(stats.g2proj_6, g_fProjectionMatrix[6]); - SETSTAT_FT(stats.g2proj_7, g_fProjectionMatrix[7]); - SETSTAT_FT(stats.g2proj_8, g_fProjectionMatrix[8]); - SETSTAT_FT(stats.g2proj_9, g_fProjectionMatrix[9]); - SETSTAT_FT(stats.g2proj_10, g_fProjectionMatrix[10]); - SETSTAT_FT(stats.g2proj_11, g_fProjectionMatrix[11]); - SETSTAT_FT(stats.g2proj_12, g_fProjectionMatrix[12]); - SETSTAT_FT(stats.g2proj_13, g_fProjectionMatrix[13]); - SETSTAT_FT(stats.g2proj_14, g_fProjectionMatrix[14]); - SETSTAT_FT(stats.g2proj_15, g_fProjectionMatrix[15]); - SETSTAT_FT(stats.proj_0, rawProjection[0]); - SETSTAT_FT(stats.proj_1, rawProjection[1]); - SETSTAT_FT(stats.proj_2, rawProjection[2]); - SETSTAT_FT(stats.proj_3, rawProjection[3]); - SETSTAT_FT(stats.proj_4, rawProjection[4]); - SETSTAT_FT(stats.proj_5, rawProjection[5]); - break; + SETSTAT_FT(stats.g2proj_0, g_fProjectionMatrix[0]); + SETSTAT_FT(stats.g2proj_1, g_fProjectionMatrix[1]); + SETSTAT_FT(stats.g2proj_2, g_fProjectionMatrix[2]); + SETSTAT_FT(stats.g2proj_3, g_fProjectionMatrix[3]); + SETSTAT_FT(stats.g2proj_4, g_fProjectionMatrix[4]); + SETSTAT_FT(stats.g2proj_5, g_fProjectionMatrix[5]); + SETSTAT_FT(stats.g2proj_6, g_fProjectionMatrix[6]); + SETSTAT_FT(stats.g2proj_7, g_fProjectionMatrix[7]); + SETSTAT_FT(stats.g2proj_8, g_fProjectionMatrix[8]); + SETSTAT_FT(stats.g2proj_9, g_fProjectionMatrix[9]); + SETSTAT_FT(stats.g2proj_10, g_fProjectionMatrix[10]); + SETSTAT_FT(stats.g2proj_11, g_fProjectionMatrix[11]); + SETSTAT_FT(stats.g2proj_12, g_fProjectionMatrix[12]); + SETSTAT_FT(stats.g2proj_13, g_fProjectionMatrix[13]); + SETSTAT_FT(stats.g2proj_14, g_fProjectionMatrix[14]); + SETSTAT_FT(stats.g2proj_15, g_fProjectionMatrix[15]); + SETSTAT_FT(stats.proj_0, rawProjection[0]); + SETSTAT_FT(stats.proj_1, rawProjection[1]); + SETSTAT_FT(stats.proj_2, rawProjection[2]); + SETSTAT_FT(stats.proj_3, rawProjection[3]); + SETSTAT_FT(stats.proj_4, rawProjection[4]); + SETSTAT_FT(stats.proj_5, rawProjection[5]); + break; - default: - ERROR_LOG(VIDEO, "Unknown projection type: %d", xfmem.projection.type); - } + default: + ERROR_LOG(VIDEO, "Unknown projection type: %d", xfmem.projection.type); + } - PRIM_LOG("Projection: %f %f %f %f %f %f\n", rawProjection[0], rawProjection[1], rawProjection[2], rawProjection[3], rawProjection[4], rawProjection[5]); + PRIM_LOG("Projection: %f %f %f %f %f %f\n", rawProjection[0], rawProjection[1], + rawProjection[2], rawProjection[3], rawProjection[4], rawProjection[5]); - if (g_ActiveConfig.bFreeLook && xfmem.projection.type == GX_PERSPECTIVE) - { - Matrix44 mtxA; - Matrix44 mtxB; - Matrix44 viewMtx; + if (g_ActiveConfig.bFreeLook && xfmem.projection.type == GX_PERSPECTIVE) + { + Matrix44 mtxA; + Matrix44 mtxB; + Matrix44 viewMtx; - Matrix44::Translate(mtxA, s_fViewTranslationVector); - Matrix44::LoadMatrix33(mtxB, s_viewRotationMatrix); - Matrix44::Multiply(mtxB, mtxA, viewMtx); // view = rotation x translation - Matrix44::Set(mtxB, g_fProjectionMatrix); - Matrix44::Multiply(mtxB, viewMtx, mtxA); // mtxA = projection x view - Matrix44::Multiply(s_viewportCorrection, mtxA, mtxB); // mtxB = viewportCorrection x mtxA - memcpy(constants.projection, mtxB.data, 4 * sizeof(float4)); - } - else - { - Matrix44 projMtx; - Matrix44::Set(projMtx, g_fProjectionMatrix); + Matrix44::Translate(mtxA, s_fViewTranslationVector); + Matrix44::LoadMatrix33(mtxB, s_viewRotationMatrix); + Matrix44::Multiply(mtxB, mtxA, viewMtx); // view = rotation x translation + Matrix44::Set(mtxB, g_fProjectionMatrix); + Matrix44::Multiply(mtxB, viewMtx, mtxA); // mtxA = projection x view + Matrix44::Multiply(s_viewportCorrection, mtxA, mtxB); // mtxB = viewportCorrection x mtxA + memcpy(constants.projection, mtxB.data, 4 * sizeof(float4)); + } + else + { + Matrix44 projMtx; + Matrix44::Set(projMtx, g_fProjectionMatrix); - Matrix44 correctedMtx; - Matrix44::Multiply(s_viewportCorrection, projMtx, correctedMtx); - memcpy(constants.projection, correctedMtx.data, 4 * sizeof(float4)); - } + Matrix44 correctedMtx; + Matrix44::Multiply(s_viewportCorrection, projMtx, correctedMtx); + memcpy(constants.projection, correctedMtx.data, 4 * sizeof(float4)); + } - dirty = true; - } + dirty = true; + } } void VertexShaderManager::InvalidateXFRange(int start, int end) { - if (((u32)start >= (u32)g_main_cp_state.matrix_index_a.PosNormalMtxIdx * 4 && - (u32)start < (u32)g_main_cp_state.matrix_index_a.PosNormalMtxIdx * 4 + 12) || - ((u32)start >= XFMEM_NORMALMATRICES + ((u32)g_main_cp_state.matrix_index_a.PosNormalMtxIdx & 31) * 3 && - (u32)start < XFMEM_NORMALMATRICES + ((u32)g_main_cp_state.matrix_index_a.PosNormalMtxIdx & 31) * 3 + 9)) - { - bPosNormalMatrixChanged = true; - } + if (((u32)start >= (u32)g_main_cp_state.matrix_index_a.PosNormalMtxIdx * 4 && + (u32)start < (u32)g_main_cp_state.matrix_index_a.PosNormalMtxIdx * 4 + 12) || + ((u32)start >= + XFMEM_NORMALMATRICES + ((u32)g_main_cp_state.matrix_index_a.PosNormalMtxIdx & 31) * 3 && + (u32)start < XFMEM_NORMALMATRICES + + ((u32)g_main_cp_state.matrix_index_a.PosNormalMtxIdx & 31) * 3 + 9)) + { + bPosNormalMatrixChanged = true; + } - if (((u32)start >= (u32)g_main_cp_state.matrix_index_a.Tex0MtxIdx*4 && (u32)start < (u32)g_main_cp_state.matrix_index_a.Tex0MtxIdx*4+12) || - ((u32)start >= (u32)g_main_cp_state.matrix_index_a.Tex1MtxIdx*4 && (u32)start < (u32)g_main_cp_state.matrix_index_a.Tex1MtxIdx*4+12) || - ((u32)start >= (u32)g_main_cp_state.matrix_index_a.Tex2MtxIdx*4 && (u32)start < (u32)g_main_cp_state.matrix_index_a.Tex2MtxIdx*4+12) || - ((u32)start >= (u32)g_main_cp_state.matrix_index_a.Tex3MtxIdx*4 && (u32)start < (u32)g_main_cp_state.matrix_index_a.Tex3MtxIdx*4+12)) - { - bTexMatricesChanged[0] = true; - } + if (((u32)start >= (u32)g_main_cp_state.matrix_index_a.Tex0MtxIdx * 4 && + (u32)start < (u32)g_main_cp_state.matrix_index_a.Tex0MtxIdx * 4 + 12) || + ((u32)start >= (u32)g_main_cp_state.matrix_index_a.Tex1MtxIdx * 4 && + (u32)start < (u32)g_main_cp_state.matrix_index_a.Tex1MtxIdx * 4 + 12) || + ((u32)start >= (u32)g_main_cp_state.matrix_index_a.Tex2MtxIdx * 4 && + (u32)start < (u32)g_main_cp_state.matrix_index_a.Tex2MtxIdx * 4 + 12) || + ((u32)start >= (u32)g_main_cp_state.matrix_index_a.Tex3MtxIdx * 4 && + (u32)start < (u32)g_main_cp_state.matrix_index_a.Tex3MtxIdx * 4 + 12)) + { + bTexMatricesChanged[0] = true; + } - if (((u32)start >= (u32)g_main_cp_state.matrix_index_b.Tex4MtxIdx*4 && (u32)start < (u32)g_main_cp_state.matrix_index_b.Tex4MtxIdx*4+12) || - ((u32)start >= (u32)g_main_cp_state.matrix_index_b.Tex5MtxIdx*4 && (u32)start < (u32)g_main_cp_state.matrix_index_b.Tex5MtxIdx*4+12) || - ((u32)start >= (u32)g_main_cp_state.matrix_index_b.Tex6MtxIdx*4 && (u32)start < (u32)g_main_cp_state.matrix_index_b.Tex6MtxIdx*4+12) || - ((u32)start >= (u32)g_main_cp_state.matrix_index_b.Tex7MtxIdx*4 && (u32)start < (u32)g_main_cp_state.matrix_index_b.Tex7MtxIdx*4+12)) - { - bTexMatricesChanged[1] = true; - } + if (((u32)start >= (u32)g_main_cp_state.matrix_index_b.Tex4MtxIdx * 4 && + (u32)start < (u32)g_main_cp_state.matrix_index_b.Tex4MtxIdx * 4 + 12) || + ((u32)start >= (u32)g_main_cp_state.matrix_index_b.Tex5MtxIdx * 4 && + (u32)start < (u32)g_main_cp_state.matrix_index_b.Tex5MtxIdx * 4 + 12) || + ((u32)start >= (u32)g_main_cp_state.matrix_index_b.Tex6MtxIdx * 4 && + (u32)start < (u32)g_main_cp_state.matrix_index_b.Tex6MtxIdx * 4 + 12) || + ((u32)start >= (u32)g_main_cp_state.matrix_index_b.Tex7MtxIdx * 4 && + (u32)start < (u32)g_main_cp_state.matrix_index_b.Tex7MtxIdx * 4 + 12)) + { + bTexMatricesChanged[1] = true; + } - if (start < XFMEM_POSMATRICES_END) - { - if (nTransformMatricesChanged[0] == -1) - { - nTransformMatricesChanged[0] = start; - nTransformMatricesChanged[1] = end > XFMEM_POSMATRICES_END ? XFMEM_POSMATRICES_END : end; - } - else - { - if (nTransformMatricesChanged[0] > start) - nTransformMatricesChanged[0] = start; + if (start < XFMEM_POSMATRICES_END) + { + if (nTransformMatricesChanged[0] == -1) + { + nTransformMatricesChanged[0] = start; + nTransformMatricesChanged[1] = end > XFMEM_POSMATRICES_END ? XFMEM_POSMATRICES_END : end; + } + else + { + if (nTransformMatricesChanged[0] > start) + nTransformMatricesChanged[0] = start; - if (nTransformMatricesChanged[1] < end) - nTransformMatricesChanged[1] = end>XFMEM_POSMATRICES_END ? XFMEM_POSMATRICES_END : end; - } - } + if (nTransformMatricesChanged[1] < end) + nTransformMatricesChanged[1] = end > XFMEM_POSMATRICES_END ? XFMEM_POSMATRICES_END : end; + } + } - if (start < XFMEM_NORMALMATRICES_END && end > XFMEM_NORMALMATRICES) - { - int _start = start < XFMEM_NORMALMATRICES ? 0 : start-XFMEM_NORMALMATRICES; - int _end = end < XFMEM_NORMALMATRICES_END ? end-XFMEM_NORMALMATRICES : XFMEM_NORMALMATRICES_END-XFMEM_NORMALMATRICES; + if (start < XFMEM_NORMALMATRICES_END && end > XFMEM_NORMALMATRICES) + { + int _start = start < XFMEM_NORMALMATRICES ? 0 : start - XFMEM_NORMALMATRICES; + int _end = end < XFMEM_NORMALMATRICES_END ? end - XFMEM_NORMALMATRICES : + XFMEM_NORMALMATRICES_END - XFMEM_NORMALMATRICES; - if (nNormalMatricesChanged[0] == -1) - { - nNormalMatricesChanged[0] = _start; - nNormalMatricesChanged[1] = _end; - } - else - { - if (nNormalMatricesChanged[0] > _start) - nNormalMatricesChanged[0] = _start; + if (nNormalMatricesChanged[0] == -1) + { + nNormalMatricesChanged[0] = _start; + nNormalMatricesChanged[1] = _end; + } + else + { + if (nNormalMatricesChanged[0] > _start) + nNormalMatricesChanged[0] = _start; - if (nNormalMatricesChanged[1] < _end) - nNormalMatricesChanged[1] = _end; - } - } + if (nNormalMatricesChanged[1] < _end) + nNormalMatricesChanged[1] = _end; + } + } - if (start < XFMEM_POSTMATRICES_END && end > XFMEM_POSTMATRICES) - { - int _start = start < XFMEM_POSTMATRICES ? XFMEM_POSTMATRICES : start-XFMEM_POSTMATRICES; - int _end = end < XFMEM_POSTMATRICES_END ? end-XFMEM_POSTMATRICES : XFMEM_POSTMATRICES_END-XFMEM_POSTMATRICES; + if (start < XFMEM_POSTMATRICES_END && end > XFMEM_POSTMATRICES) + { + int _start = start < XFMEM_POSTMATRICES ? XFMEM_POSTMATRICES : start - XFMEM_POSTMATRICES; + int _end = end < XFMEM_POSTMATRICES_END ? end - XFMEM_POSTMATRICES : + XFMEM_POSTMATRICES_END - XFMEM_POSTMATRICES; - if (nPostTransformMatricesChanged[0] == -1) - { - nPostTransformMatricesChanged[0] = _start; - nPostTransformMatricesChanged[1] = _end; - } - else - { - if (nPostTransformMatricesChanged[0] > _start) - nPostTransformMatricesChanged[0] = _start; + if (nPostTransformMatricesChanged[0] == -1) + { + nPostTransformMatricesChanged[0] = _start; + nPostTransformMatricesChanged[1] = _end; + } + else + { + if (nPostTransformMatricesChanged[0] > _start) + nPostTransformMatricesChanged[0] = _start; - if (nPostTransformMatricesChanged[1] < _end) - nPostTransformMatricesChanged[1] = _end; - } - } + if (nPostTransformMatricesChanged[1] < _end) + nPostTransformMatricesChanged[1] = _end; + } + } - if (start < XFMEM_LIGHTS_END && end > XFMEM_LIGHTS) - { - int _start = start < XFMEM_LIGHTS ? XFMEM_LIGHTS : start-XFMEM_LIGHTS; - int _end = end < XFMEM_LIGHTS_END ? end-XFMEM_LIGHTS : XFMEM_LIGHTS_END-XFMEM_LIGHTS; + if (start < XFMEM_LIGHTS_END && end > XFMEM_LIGHTS) + { + int _start = start < XFMEM_LIGHTS ? XFMEM_LIGHTS : start - XFMEM_LIGHTS; + int _end = end < XFMEM_LIGHTS_END ? end - XFMEM_LIGHTS : XFMEM_LIGHTS_END - XFMEM_LIGHTS; - if (nLightsChanged[0] == -1) - { - nLightsChanged[0] = _start; - nLightsChanged[1] = _end; - } - else - { - if (nLightsChanged[0] > _start) - nLightsChanged[0] = _start; + if (nLightsChanged[0] == -1) + { + nLightsChanged[0] = _start; + nLightsChanged[1] = _end; + } + else + { + if (nLightsChanged[0] > _start) + nLightsChanged[0] = _start; - if (nLightsChanged[1] < _end) - nLightsChanged[1] = _end; - } - } + if (nLightsChanged[1] < _end) + nLightsChanged[1] = _end; + } + } } void VertexShaderManager::SetTexMatrixChangedA(u32 Value) { - if (g_main_cp_state.matrix_index_a.Hex != Value) - { - VertexManagerBase::Flush(); - if (g_main_cp_state.matrix_index_a.PosNormalMtxIdx != (Value & 0x3f)) - bPosNormalMatrixChanged = true; - bTexMatricesChanged[0] = true; - g_main_cp_state.matrix_index_a.Hex = Value; - } + if (g_main_cp_state.matrix_index_a.Hex != Value) + { + VertexManagerBase::Flush(); + if (g_main_cp_state.matrix_index_a.PosNormalMtxIdx != (Value & 0x3f)) + bPosNormalMatrixChanged = true; + bTexMatricesChanged[0] = true; + g_main_cp_state.matrix_index_a.Hex = Value; + } } void VertexShaderManager::SetTexMatrixChangedB(u32 Value) { - if (g_main_cp_state.matrix_index_b.Hex != Value) - { - VertexManagerBase::Flush(); - bTexMatricesChanged[1] = true; - g_main_cp_state.matrix_index_b.Hex = Value; - } + if (g_main_cp_state.matrix_index_b.Hex != Value) + { + VertexManagerBase::Flush(); + bTexMatricesChanged[1] = true; + g_main_cp_state.matrix_index_b.Hex = Value; + } } void VertexShaderManager::SetViewportChanged() { - bViewportChanged = true; + bViewportChanged = true; } void VertexShaderManager::SetProjectionChanged() { - bProjectionChanged = true; + bProjectionChanged = true; } void VertexShaderManager::SetMaterialColorChanged(int index) { - nMaterialsChanged[index] = true; + nMaterialsChanged[index] = true; } void VertexShaderManager::TranslateView(float x, float y, float z) { - float result[3]; - float vector[3] = { x, z, y }; + float result[3]; + float vector[3] = {x, z, y}; - Matrix33::Multiply(s_viewInvRotationMatrix, vector, result); + Matrix33::Multiply(s_viewInvRotationMatrix, vector, result); - for (size_t i = 0; i < ArraySize(result); i++) - s_fViewTranslationVector[i] += result[i]; + for (size_t i = 0; i < ArraySize(result); i++) + s_fViewTranslationVector[i] += result[i]; - bProjectionChanged = true; + bProjectionChanged = true; } void VertexShaderManager::RotateView(float x, float y) { - s_fViewRotation[0] += x; - s_fViewRotation[1] += y; + s_fViewRotation[0] += x; + s_fViewRotation[1] += y; - Matrix33 mx; - Matrix33 my; - Matrix33::RotateX(mx, s_fViewRotation[1]); - Matrix33::RotateY(my, s_fViewRotation[0]); - Matrix33::Multiply(mx, my, s_viewRotationMatrix); + Matrix33 mx; + Matrix33 my; + Matrix33::RotateX(mx, s_fViewRotation[1]); + Matrix33::RotateY(my, s_fViewRotation[0]); + Matrix33::Multiply(mx, my, s_viewRotationMatrix); - // reverse rotation - Matrix33::RotateX(mx, -s_fViewRotation[1]); - Matrix33::RotateY(my, -s_fViewRotation[0]); - Matrix33::Multiply(my, mx, s_viewInvRotationMatrix); + // reverse rotation + Matrix33::RotateX(mx, -s_fViewRotation[1]); + Matrix33::RotateY(my, -s_fViewRotation[0]); + Matrix33::Multiply(my, mx, s_viewInvRotationMatrix); - bProjectionChanged = true; + bProjectionChanged = true; } void VertexShaderManager::ResetView() { - memset(s_fViewTranslationVector, 0, sizeof(s_fViewTranslationVector)); - Matrix33::LoadIdentity(s_viewRotationMatrix); - Matrix33::LoadIdentity(s_viewInvRotationMatrix); - s_fViewRotation[0] = s_fViewRotation[1] = 0.0f; + memset(s_fViewTranslationVector, 0, sizeof(s_fViewTranslationVector)); + Matrix33::LoadIdentity(s_viewRotationMatrix); + Matrix33::LoadIdentity(s_viewInvRotationMatrix); + s_fViewRotation[0] = s_fViewRotation[1] = 0.0f; - bProjectionChanged = true; + bProjectionChanged = true; } void VertexShaderManager::TransformToClipSpace(const float* data, float* out, u32 MtxIdx) { - const float* world_matrix = &xfmem.posMatrices[(MtxIdx & 0x3f) * 4]; + const float* world_matrix = &xfmem.posMatrices[(MtxIdx & 0x3f) * 4]; - // We use the projection matrix calculated by VertexShaderManager, because it - // includes any free look transformations. - // Make sure VertexShaderManager::SetConstants() has been called first. - const float* proj_matrix = &g_fProjectionMatrix[0]; + // We use the projection matrix calculated by VertexShaderManager, because it + // includes any free look transformations. + // Make sure VertexShaderManager::SetConstants() has been called first. + const float* proj_matrix = &g_fProjectionMatrix[0]; - const float t[3] = { - data[0] * world_matrix[0] + data[1] * world_matrix[1] + data[2] * world_matrix[2] + world_matrix[3], - data[0] * world_matrix[4] + data[1] * world_matrix[5] + data[2] * world_matrix[6] + world_matrix[7], - data[0] * world_matrix[8] + data[1] * world_matrix[9] + data[2] * world_matrix[10] + world_matrix[11] - }; + const float t[3] = {data[0] * world_matrix[0] + data[1] * world_matrix[1] + + data[2] * world_matrix[2] + world_matrix[3], + data[0] * world_matrix[4] + data[1] * world_matrix[5] + + data[2] * world_matrix[6] + world_matrix[7], + data[0] * world_matrix[8] + data[1] * world_matrix[9] + + data[2] * world_matrix[10] + world_matrix[11]}; - out[0] = t[0] * proj_matrix[0] + t[1] * proj_matrix[1] + t[2] * proj_matrix[2] + proj_matrix[3]; - out[1] = t[0] * proj_matrix[4] + t[1] * proj_matrix[5] + t[2] * proj_matrix[6] + proj_matrix[7]; - out[2] = t[0] * proj_matrix[8] + t[1] * proj_matrix[9] + t[2] * proj_matrix[10] + proj_matrix[11]; - out[3] = t[0] * proj_matrix[12] + t[1] * proj_matrix[13] + t[2] * proj_matrix[14] + proj_matrix[15]; + out[0] = t[0] * proj_matrix[0] + t[1] * proj_matrix[1] + t[2] * proj_matrix[2] + proj_matrix[3]; + out[1] = t[0] * proj_matrix[4] + t[1] * proj_matrix[5] + t[2] * proj_matrix[6] + proj_matrix[7]; + out[2] = t[0] * proj_matrix[8] + t[1] * proj_matrix[9] + t[2] * proj_matrix[10] + proj_matrix[11]; + out[3] = + t[0] * proj_matrix[12] + t[1] * proj_matrix[13] + t[2] * proj_matrix[14] + proj_matrix[15]; } -void VertexShaderManager::DoState(PointerWrap &p) +void VertexShaderManager::DoState(PointerWrap& p) { - p.Do(g_fProjectionMatrix); - p.Do(s_viewportCorrection); - p.Do(s_viewRotationMatrix); - p.Do(s_viewInvRotationMatrix); - p.Do(s_fViewTranslationVector); - p.Do(s_fViewRotation); + p.Do(g_fProjectionMatrix); + p.Do(s_viewportCorrection); + p.Do(s_viewRotationMatrix); + p.Do(s_viewInvRotationMatrix); + p.Do(s_fViewTranslationVector); + p.Do(s_fViewRotation); - p.Do(nTransformMatricesChanged); - p.Do(nNormalMatricesChanged); - p.Do(nPostTransformMatricesChanged); - p.Do(nLightsChanged); + p.Do(nTransformMatricesChanged); + p.Do(nNormalMatricesChanged); + p.Do(nPostTransformMatricesChanged); + p.Do(nLightsChanged); - p.Do(nMaterialsChanged); - p.Do(bTexMatricesChanged); - p.Do(bPosNormalMatrixChanged); - p.Do(bProjectionChanged); - p.Do(bViewportChanged); + p.Do(nMaterialsChanged); + p.Do(bTexMatricesChanged); + p.Do(bPosNormalMatrixChanged); + p.Do(bProjectionChanged); + p.Do(bViewportChanged); - p.Do(constants); + p.Do(constants); - if (p.GetMode() == PointerWrap::MODE_READ) - { - Dirty(); - } + if (p.GetMode() == PointerWrap::MODE_READ) + { + Dirty(); + } } diff --git a/Source/Core/VideoCommon/VertexShaderManager.h b/Source/Core/VideoCommon/VertexShaderManager.h index ad3d128432..1820a7fa71 100644 --- a/Source/Core/VideoCommon/VertexShaderManager.h +++ b/Source/Core/VideoCommon/VertexShaderManager.h @@ -17,31 +17,31 @@ void UpdateProjectionHack(int iParams[], std::string sParams[]); class VertexShaderManager { public: - static void Init(); - static void Dirty(); - static void Shutdown(); - static void DoState(PointerWrap &p); + static void Init(); + static void Dirty(); + static void Shutdown(); + static void DoState(PointerWrap& p); - // constant management - static void SetConstants(); + // constant management + static void SetConstants(); - static void InvalidateXFRange(int start, int end); - static void SetTexMatrixChangedA(u32 value); - static void SetTexMatrixChangedB(u32 value); - static void SetViewportChanged(); - static void SetProjectionChanged(); - static void SetMaterialColorChanged(int index); + static void InvalidateXFRange(int start, int end); + static void SetTexMatrixChangedA(u32 value); + static void SetTexMatrixChangedB(u32 value); + static void SetViewportChanged(); + static void SetProjectionChanged(); + static void SetMaterialColorChanged(int index); - static void TranslateView(float x, float y, float z = 0.0f); - static void RotateView(float x, float y); - static void ResetView(); + static void TranslateView(float x, float y, float z = 0.0f); + static void RotateView(float x, float y); + static void ResetView(); - // data: 3 floats representing the X, Y and Z vertex model coordinates and the posmatrix index. - // out: 4 floats which will be initialized with the corresponding clip space coordinates - // NOTE: g_fProjectionMatrix must be up to date when this is called - // (i.e. VertexShaderManager::SetConstants needs to be called before using this!) - static void TransformToClipSpace(const float* data, float* out, u32 mtxIdx); + // data: 3 floats representing the X, Y and Z vertex model coordinates and the posmatrix index. + // out: 4 floats which will be initialized with the corresponding clip space coordinates + // NOTE: g_fProjectionMatrix must be up to date when this is called + // (i.e. VertexShaderManager::SetConstants needs to be called before using this!) + static void TransformToClipSpace(const float* data, float* out, u32 mtxIdx); - static VertexShaderConstants constants; - static bool dirty; + static VertexShaderConstants constants; + static bool dirty; }; diff --git a/Source/Core/VideoCommon/VideoBackendBase.cpp b/Source/Core/VideoCommon/VideoBackendBase.cpp index 717a9e3be6..f3fbb074fb 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.cpp +++ b/Source/Core/VideoCommon/VideoBackendBase.cpp @@ -34,49 +34,49 @@ __declspec(dllexport) DWORD NvOptimusEnablement = 1; void VideoBackendBase::PopulateList() { - // OGL > D3D11 > D3D12 > SW - g_available_video_backends.push_back(std::make_unique()); + // OGL > D3D11 > D3D12 > SW + g_available_video_backends.push_back(std::make_unique()); #ifdef _WIN32 - g_available_video_backends.push_back(std::make_unique()); + g_available_video_backends.push_back(std::make_unique()); - // More robust way to check for D3D12 support than (unreliable) OS version checks. - HMODULE d3d12_module = LoadLibraryA("d3d12.dll"); - if (d3d12_module != nullptr) - { - FreeLibrary(d3d12_module); - g_available_video_backends.push_back(std::make_unique()); - } + // More robust way to check for D3D12 support than (unreliable) OS version checks. + HMODULE d3d12_module = LoadLibraryA("d3d12.dll"); + if (d3d12_module != nullptr) + { + FreeLibrary(d3d12_module); + g_available_video_backends.push_back(std::make_unique()); + } #endif - g_available_video_backends.push_back(std::make_unique()); + g_available_video_backends.push_back(std::make_unique()); - const auto iter = std::find_if(g_available_video_backends.begin(), g_available_video_backends.end(), [](const auto& backend) { - return backend != nullptr; - }); + const auto iter = + std::find_if(g_available_video_backends.begin(), g_available_video_backends.end(), + [](const auto& backend) { return backend != nullptr; }); - if (iter == g_available_video_backends.end()) - return; + if (iter == g_available_video_backends.end()) + return; - s_default_backend = iter->get(); - g_video_backend = iter->get(); + s_default_backend = iter->get(); + g_video_backend = iter->get(); } void VideoBackendBase::ClearList() { - g_available_video_backends.clear(); + g_available_video_backends.clear(); } void VideoBackendBase::ActivateBackend(const std::string& name) { - // If empty, set it to the default backend (expected behavior) - if (name.empty()) - g_video_backend = s_default_backend; + // If empty, set it to the default backend (expected behavior) + if (name.empty()) + g_video_backend = s_default_backend; - const auto iter = std::find_if(g_available_video_backends.begin(), g_available_video_backends.end(), [&name](const auto& backend) { - return name == backend->GetName(); - }); + const auto iter = + std::find_if(g_available_video_backends.begin(), g_available_video_backends.end(), + [&name](const auto& backend) { return name == backend->GetName(); }); - if (iter == g_available_video_backends.end()) - return; + if (iter == g_available_video_backends.end()) + return; - g_video_backend = iter->get(); + g_video_backend = iter->get(); } diff --git a/Source/Core/VideoCommon/VideoBackendBase.h b/Source/Core/VideoCommon/VideoBackendBase.h index e60403a104..bc08469002 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.h +++ b/Source/Core/VideoCommon/VideoBackendBase.h @@ -11,93 +11,96 @@ #include "Common/CommonTypes.h" #include "VideoCommon/PerfQueryBase.h" -namespace MMIO { class Mapping; } +namespace MMIO +{ +class Mapping; +} class PointerWrap; enum FieldType { - FIELD_ODD = 0, - FIELD_EVEN = 1, + FIELD_ODD = 0, + FIELD_EVEN = 1, }; enum EFBAccessType { - PEEK_Z = 0, - POKE_Z, - PEEK_COLOR, - POKE_COLOR + PEEK_Z = 0, + POKE_Z, + PEEK_COLOR, + POKE_COLOR }; struct SCPFifoStruct { - // fifo registers - volatile u32 CPBase; - volatile u32 CPEnd; - u32 CPHiWatermark; - u32 CPLoWatermark; - volatile u32 CPReadWriteDistance; - volatile u32 CPWritePointer; - volatile u32 CPReadPointer; - volatile u32 CPBreakpoint; - volatile u32 SafeCPReadPointer; - // Super Monkey Ball Adventure require this. - // Because the read&check-PEToken-loop stays in its JITed block I suppose. - // So no possiblity to ack the Token irq by the scheduler until some sort of PPC watchdog do its mess. - volatile u16 PEToken; + // fifo registers + volatile u32 CPBase; + volatile u32 CPEnd; + u32 CPHiWatermark; + u32 CPLoWatermark; + volatile u32 CPReadWriteDistance; + volatile u32 CPWritePointer; + volatile u32 CPReadPointer; + volatile u32 CPBreakpoint; + volatile u32 SafeCPReadPointer; + // Super Monkey Ball Adventure require this. + // Because the read&check-PEToken-loop stays in its JITed block I suppose. + // So no possiblity to ack the Token irq by the scheduler until some sort of PPC watchdog do its + // mess. + volatile u16 PEToken; - volatile u32 bFF_GPLinkEnable; - volatile u32 bFF_GPReadEnable; - volatile u32 bFF_BPEnable; - volatile u32 bFF_BPInt; - volatile u32 bFF_Breakpoint; + volatile u32 bFF_GPLinkEnable; + volatile u32 bFF_GPReadEnable; + volatile u32 bFF_BPEnable; + volatile u32 bFF_BPInt; + volatile u32 bFF_Breakpoint; - volatile u32 bFF_LoWatermarkInt; - volatile u32 bFF_HiWatermarkInt; + volatile u32 bFF_LoWatermarkInt; + volatile u32 bFF_HiWatermarkInt; - volatile u32 bFF_LoWatermark; - volatile u32 bFF_HiWatermark; + volatile u32 bFF_LoWatermark; + volatile u32 bFF_HiWatermark; }; class VideoBackendBase { public: - virtual ~VideoBackendBase() {} + virtual ~VideoBackendBase() {} + virtual unsigned int PeekMessages() = 0; - virtual unsigned int PeekMessages() = 0; + virtual bool Initialize(void* window_handle) = 0; + virtual void Shutdown() = 0; - virtual bool Initialize(void* window_handle) = 0; - virtual void Shutdown() = 0; + virtual std::string GetName() const = 0; + virtual std::string GetDisplayName() const { return GetName(); } + virtual void ShowConfig(void*) = 0; - virtual std::string GetName() const = 0; - virtual std::string GetDisplayName() const { return GetName(); } + virtual void Video_Prepare() = 0; + void Video_ExitLoop(); + virtual void Video_Cleanup() = 0; // called from gl/d3d thread - virtual void ShowConfig(void*) = 0; + void Video_BeginField(u32, u32, u32, u32); + void Video_EndField(); - virtual void Video_Prepare() = 0; - void Video_ExitLoop(); - virtual void Video_Cleanup() = 0; // called from gl/d3d thread + u32 Video_AccessEFB(EFBAccessType, u32, u32, u32); + u32 Video_GetQueryResult(PerfQueryType type); + u16 Video_GetBoundingBox(int index); - void Video_BeginField(u32, u32, u32, u32); - void Video_EndField(); + static void PopulateList(); + static void ClearList(); + static void ActivateBackend(const std::string& name); - u32 Video_AccessEFB(EFBAccessType, u32, u32, u32); - u32 Video_GetQueryResult(PerfQueryType type); - u16 Video_GetBoundingBox(int index); + // the implementation needs not do synchronization logic, because calls to it are surrounded by + // PauseAndLock now + void DoState(PointerWrap& p); - static void PopulateList(); - static void ClearList(); - static void ActivateBackend(const std::string& name); - - // the implementation needs not do synchronization logic, because calls to it are surrounded by PauseAndLock now - void DoState(PointerWrap &p); - - void CheckInvalidState(); + void CheckInvalidState(); protected: - void InitializeShared(); + void InitializeShared(); - bool m_initialized = false; - bool m_invalid = false; + bool m_initialized = false; + bool m_invalid = false; }; extern std::vector> g_available_video_backends; diff --git a/Source/Core/VideoCommon/VideoCommon.h b/Source/Core/VideoCommon/VideoCommon.h index 637cd69e2d..754e074d3b 100644 --- a/Source/Core/VideoCommon/VideoCommon.h +++ b/Source/Core/VideoCommon/VideoCommon.h @@ -17,8 +17,8 @@ extern bool g_bRecordFifoData; // These are accurate (disregarding AA modes). enum { - EFB_WIDTH = 640, - EFB_HEIGHT = 528, + EFB_WIDTH = 640, + EFB_HEIGHT = 528, }; // Max XFB width is 720. You can only copy out 640 wide areas of efb to XFB @@ -43,17 +43,17 @@ typedef MathUtil::Rectangle EFBRectangle; struct TargetRectangle : public MathUtil::Rectangle { #ifdef _WIN32 - // Only used by D3D backend. - const RECT *AsRECT() const - { - // The types are binary compatible so this works. - return (const RECT *)this; - } - RECT *AsRECT() - { - // The types are binary compatible so this works. - return (RECT *)this; - } + // Only used by D3D backend. + const RECT* AsRECT() const + { + // The types are binary compatible so this works. + return (const RECT*)this; + } + RECT* AsRECT() + { + // The types are binary compatible so this works. + return (RECT*)this; + } #endif }; @@ -64,35 +64,36 @@ struct TargetRectangle : public MathUtil::Rectangle #endif // warning: mapping buffer should be disabled to use this -// #define LOG_VTX() DEBUG_LOG(VIDEO, "vtx: %f %f %f, ", ((float*)g_vertex_manager_write_ptr)[-3], ((float*)g_vertex_manager_write_ptr)[-2], ((float*)g_vertex_manager_write_ptr)[-1]); +// #define LOG_VTX() DEBUG_LOG(VIDEO, "vtx: %f %f %f, ", ((float*)g_vertex_manager_write_ptr)[-3], +// ((float*)g_vertex_manager_write_ptr)[-2], ((float*)g_vertex_manager_write_ptr)[-1]); #define LOG_VTX() enum API_TYPE { - API_OPENGL = 1, - API_D3D = 2, - API_NONE = 3 + API_OPENGL = 1, + API_D3D = 2, + API_NONE = 3 }; inline u32 RGBA8ToRGBA6ToRGBA8(u32 src) { - u32 color = src; - color &= 0xFCFCFCFC; - color |= (color >> 6) & 0x03030303; - return color; + u32 color = src; + color &= 0xFCFCFCFC; + color |= (color >> 6) & 0x03030303; + return color; } inline u32 RGBA8ToRGB565ToRGBA8(u32 src) { - u32 color = (src & 0xF8FCF8); - color |= (color >> 5) & 0x070007; - color |= (color >> 6) & 0x000300; - color |= 0xFF000000; - return color; + u32 color = (src & 0xF8FCF8); + color |= (color >> 5) & 0x070007; + color |= (color >> 6) & 0x000300; + color |= 0xFF000000; + return color; } inline u32 Z24ToZ16ToZ24(u32 src) { - return (src & 0xFFFF00) | (src >> 16); + return (src & 0xFFFF00) | (src >> 16); } diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index 257cc61fc6..753a65f9eb 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -21,309 +21,318 @@ VideoConfig g_ActiveConfig; void UpdateActiveConfig() { - if (Movie::IsPlayingInput() && Movie::IsConfigSaved()) - Movie::SetGraphicsConfig(); - g_ActiveConfig = g_Config; + if (Movie::IsPlayingInput() && Movie::IsConfigSaved()) + Movie::SetGraphicsConfig(); + g_ActiveConfig = g_Config; } VideoConfig::VideoConfig() { - bRunning = false; + bRunning = false; - // Exclusive fullscreen flags - bFullscreen = false; - bExclusiveMode = false; + // Exclusive fullscreen flags + bFullscreen = false; + bExclusiveMode = false; - // Needed for the first frame, I think - fAspectRatioHackW = 1; - fAspectRatioHackH = 1; + // Needed for the first frame, I think + fAspectRatioHackW = 1; + fAspectRatioHackH = 1; - // disable all features by default - backend_info.APIType = API_NONE; - backend_info.bSupportsExclusiveFullscreen = false; + // disable all features by default + backend_info.APIType = API_NONE; + backend_info.bSupportsExclusiveFullscreen = false; } void VideoConfig::Load(const std::string& ini_file) { - IniFile iniFile; - iniFile.Load(ini_file); + IniFile iniFile; + iniFile.Load(ini_file); - IniFile::Section* hardware = iniFile.GetOrCreateSection("Hardware"); - hardware->Get("VSync", &bVSync, 0); - hardware->Get("Adapter", &iAdapter, 0); + IniFile::Section* hardware = iniFile.GetOrCreateSection("Hardware"); + hardware->Get("VSync", &bVSync, 0); + hardware->Get("Adapter", &iAdapter, 0); - IniFile::Section* settings = iniFile.GetOrCreateSection("Settings"); - settings->Get("wideScreenHack", &bWidescreenHack, false); - settings->Get("AspectRatio", &iAspectRatio, (int)ASPECT_AUTO); - settings->Get("Crop", &bCrop, false); - settings->Get("UseXFB", &bUseXFB, 0); - settings->Get("UseRealXFB", &bUseRealXFB, 0); - settings->Get("SafeTextureCacheColorSamples", &iSafeTextureCache_ColorSamples, 128); - settings->Get("ShowFPS", &bShowFPS, false); - settings->Get("LogRenderTimeToFile", &bLogRenderTimeToFile, false); - settings->Get("OverlayStats", &bOverlayStats, false); - settings->Get("OverlayProjStats", &bOverlayProjStats, false); - settings->Get("DumpTextures", &bDumpTextures, 0); - settings->Get("HiresTextures", &bHiresTextures, 0); - settings->Get("ConvertHiresTextures", &bConvertHiresTextures, 0); - settings->Get("CacheHiresTextures", &bCacheHiresTextures, 0); - settings->Get("DumpEFBTarget", &bDumpEFBTarget, 0); - settings->Get("FreeLook", &bFreeLook, 0); - settings->Get("UseFFV1", &bUseFFV1, 0); - settings->Get("EnablePixelLighting", &bEnablePixelLighting, 0); - settings->Get("FastDepthCalc", &bFastDepthCalc, true); - settings->Get("MSAA", &iMultisamples, 1); - settings->Get("SSAA", &bSSAA, false); - settings->Get("EFBScale", &iEFBScale, (int)SCALE_1X); // native - settings->Get("TexFmtOverlayEnable", &bTexFmtOverlayEnable, 0); - settings->Get("TexFmtOverlayCenter", &bTexFmtOverlayCenter, 0); - settings->Get("WireFrame", &bWireFrame, 0); - settings->Get("DisableFog", &bDisableFog, 0); - settings->Get("EnableShaderDebugging", &bEnableShaderDebugging, false); - settings->Get("BorderlessFullscreen", &bBorderlessFullscreen, false); + IniFile::Section* settings = iniFile.GetOrCreateSection("Settings"); + settings->Get("wideScreenHack", &bWidescreenHack, false); + settings->Get("AspectRatio", &iAspectRatio, (int)ASPECT_AUTO); + settings->Get("Crop", &bCrop, false); + settings->Get("UseXFB", &bUseXFB, 0); + settings->Get("UseRealXFB", &bUseRealXFB, 0); + settings->Get("SafeTextureCacheColorSamples", &iSafeTextureCache_ColorSamples, 128); + settings->Get("ShowFPS", &bShowFPS, false); + settings->Get("LogRenderTimeToFile", &bLogRenderTimeToFile, false); + settings->Get("OverlayStats", &bOverlayStats, false); + settings->Get("OverlayProjStats", &bOverlayProjStats, false); + settings->Get("DumpTextures", &bDumpTextures, 0); + settings->Get("HiresTextures", &bHiresTextures, 0); + settings->Get("ConvertHiresTextures", &bConvertHiresTextures, 0); + settings->Get("CacheHiresTextures", &bCacheHiresTextures, 0); + settings->Get("DumpEFBTarget", &bDumpEFBTarget, 0); + settings->Get("FreeLook", &bFreeLook, 0); + settings->Get("UseFFV1", &bUseFFV1, 0); + settings->Get("EnablePixelLighting", &bEnablePixelLighting, 0); + settings->Get("FastDepthCalc", &bFastDepthCalc, true); + settings->Get("MSAA", &iMultisamples, 1); + settings->Get("SSAA", &bSSAA, false); + settings->Get("EFBScale", &iEFBScale, (int)SCALE_1X); // native + settings->Get("TexFmtOverlayEnable", &bTexFmtOverlayEnable, 0); + settings->Get("TexFmtOverlayCenter", &bTexFmtOverlayCenter, 0); + settings->Get("WireFrame", &bWireFrame, 0); + settings->Get("DisableFog", &bDisableFog, 0); + settings->Get("EnableShaderDebugging", &bEnableShaderDebugging, false); + settings->Get("BorderlessFullscreen", &bBorderlessFullscreen, false); - settings->Get("SWZComploc", &bZComploc, true); - settings->Get("SWZFreeze", &bZFreeze, true); - settings->Get("SWDumpObjects", &bDumpObjects, false); - settings->Get("SWDumpTevStages", &bDumpTevStages, false); - settings->Get("SWDumpTevTexFetches", &bDumpTevTextureFetches, false); - settings->Get("SWDrawStart", &drawStart, 0); - settings->Get("SWDrawEnd", &drawEnd, 100000); + settings->Get("SWZComploc", &bZComploc, true); + settings->Get("SWZFreeze", &bZFreeze, true); + settings->Get("SWDumpObjects", &bDumpObjects, false); + settings->Get("SWDumpTevStages", &bDumpTevStages, false); + settings->Get("SWDumpTevTexFetches", &bDumpTevTextureFetches, false); + settings->Get("SWDrawStart", &drawStart, 0); + settings->Get("SWDrawEnd", &drawEnd, 100000); + IniFile::Section* enhancements = iniFile.GetOrCreateSection("Enhancements"); + enhancements->Get("ForceFiltering", &bForceFiltering, 0); + enhancements->Get("MaxAnisotropy", &iMaxAnisotropy, 0); // NOTE - this is x in (1 << x) + enhancements->Get("PostProcessingShader", &sPostProcessingShader, ""); - IniFile::Section* enhancements = iniFile.GetOrCreateSection("Enhancements"); - enhancements->Get("ForceFiltering", &bForceFiltering, 0); - enhancements->Get("MaxAnisotropy", &iMaxAnisotropy, 0); // NOTE - this is x in (1 << x) - enhancements->Get("PostProcessingShader", &sPostProcessingShader, ""); + IniFile::Section* stereoscopy = iniFile.GetOrCreateSection("Stereoscopy"); + stereoscopy->Get("StereoMode", &iStereoMode, 0); + stereoscopy->Get("StereoDepth", &iStereoDepth, 20); + stereoscopy->Get("StereoConvergencePercentage", &iStereoConvergencePercentage, 100); + stereoscopy->Get("StereoSwapEyes", &bStereoSwapEyes, false); - IniFile::Section* stereoscopy = iniFile.GetOrCreateSection("Stereoscopy"); - stereoscopy->Get("StereoMode", &iStereoMode, 0); - stereoscopy->Get("StereoDepth", &iStereoDepth, 20); - stereoscopy->Get("StereoConvergencePercentage", &iStereoConvergencePercentage, 100); - stereoscopy->Get("StereoSwapEyes", &bStereoSwapEyes, false); + IniFile::Section* hacks = iniFile.GetOrCreateSection("Hacks"); + hacks->Get("EFBAccessEnable", &bEFBAccessEnable, true); + hacks->Get("BBoxEnable", &bBBoxEnable, false); + hacks->Get("ForceProgressive", &bForceProgressive, true); + hacks->Get("EFBToTextureEnable", &bSkipEFBCopyToRam, true); + hacks->Get("EFBScaledCopy", &bCopyEFBScaled, true); + hacks->Get("EFBEmulateFormatChanges", &bEFBEmulateFormatChanges, false); - IniFile::Section* hacks = iniFile.GetOrCreateSection("Hacks"); - hacks->Get("EFBAccessEnable", &bEFBAccessEnable, true); - hacks->Get("BBoxEnable", &bBBoxEnable, false); - hacks->Get("ForceProgressive", &bForceProgressive, true); - hacks->Get("EFBToTextureEnable", &bSkipEFBCopyToRam, true); - hacks->Get("EFBScaledCopy", &bCopyEFBScaled, true); - hacks->Get("EFBEmulateFormatChanges", &bEFBEmulateFormatChanges, false); + // hacks which are disabled by default + iPhackvalue[0] = 0; + bPerfQueriesEnable = false; - // hacks which are disabled by default - iPhackvalue[0] = 0; - bPerfQueriesEnable = false; + // Load common settings + iniFile.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); + IniFile::Section* interface = iniFile.GetOrCreateSection("Interface"); + bool bTmp; + interface->Get("UsePanicHandlers", &bTmp, true); + SetEnableAlert(bTmp); - // Load common settings - iniFile.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); - IniFile::Section* interface = iniFile.GetOrCreateSection("Interface"); - bool bTmp; - interface->Get("UsePanicHandlers", &bTmp, true); - SetEnableAlert(bTmp); + // Shader Debugging causes a huge slowdown and it's easy to forget about it + // since it's not exposed in the settings dialog. It's only used by + // developers, so displaying an obnoxious message avoids some confusion and + // is not too annoying/confusing for users. + // + // XXX(delroth): This is kind of a bad place to put this, but the current + // VideoCommon is a mess and we don't have a central initialization + // function to do these kind of checks. Instead, the init code is + // triplicated for each video backend. + if (bEnableShaderDebugging) + OSD::AddMessage("Warning: Shader Debugging is enabled, performance will suffer heavily", 15000); - // Shader Debugging causes a huge slowdown and it's easy to forget about it - // since it's not exposed in the settings dialog. It's only used by - // developers, so displaying an obnoxious message avoids some confusion and - // is not too annoying/confusing for users. - // - // XXX(delroth): This is kind of a bad place to put this, but the current - // VideoCommon is a mess and we don't have a central initialization - // function to do these kind of checks. Instead, the init code is - // triplicated for each video backend. - if (bEnableShaderDebugging) - OSD::AddMessage("Warning: Shader Debugging is enabled, performance will suffer heavily", 15000); - - VerifyValidity(); + VerifyValidity(); } void VideoConfig::GameIniLoad() { - bool gfx_override_exists = false; + bool gfx_override_exists = false; - // XXX: Again, bad place to put OSD messages at (see delroth's comment above) - // XXX: This will add an OSD message for each projection hack value... meh -#define CHECK_SETTING(section, key, var) do { \ - decltype(var) temp = var; \ - if (iniFile.GetIfExists(section, key, &var) && var != temp) { \ - std::string msg = StringFromFormat("Note: Option \"%s\" is overridden by game ini.", key); \ - OSD::AddMessage(msg, 7500); \ - gfx_override_exists = true; \ - } \ - } while (0) +// XXX: Again, bad place to put OSD messages at (see delroth's comment above) +// XXX: This will add an OSD message for each projection hack value... meh +#define CHECK_SETTING(section, key, var) \ + do \ + { \ + decltype(var) temp = var; \ + if (iniFile.GetIfExists(section, key, &var) && var != temp) \ + { \ + std::string msg = StringFromFormat("Note: Option \"%s\" is overridden by game ini.", key); \ + OSD::AddMessage(msg, 7500); \ + gfx_override_exists = true; \ + } \ + } while (0) - IniFile iniFile = SConfig::GetInstance().LoadGameIni(); + IniFile iniFile = SConfig::GetInstance().LoadGameIni(); - CHECK_SETTING("Video_Hardware", "VSync", bVSync); + CHECK_SETTING("Video_Hardware", "VSync", bVSync); - CHECK_SETTING("Video_Settings", "wideScreenHack", bWidescreenHack); - CHECK_SETTING("Video_Settings", "AspectRatio", iAspectRatio); - CHECK_SETTING("Video_Settings", "Crop", bCrop); - CHECK_SETTING("Video_Settings", "UseXFB", bUseXFB); - CHECK_SETTING("Video_Settings", "UseRealXFB", bUseRealXFB); - CHECK_SETTING("Video_Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples); - CHECK_SETTING("Video_Settings", "HiresTextures", bHiresTextures); - CHECK_SETTING("Video_Settings", "ConvertHiresTextures", bConvertHiresTextures); - CHECK_SETTING("Video_Settings", "CacheHiresTextures", bCacheHiresTextures); - CHECK_SETTING("Video_Settings", "EnablePixelLighting", bEnablePixelLighting); - CHECK_SETTING("Video_Settings", "FastDepthCalc", bFastDepthCalc); - CHECK_SETTING("Video_Settings", "MSAA", iMultisamples); - CHECK_SETTING("Video_Settings", "SSAA", bSSAA); + CHECK_SETTING("Video_Settings", "wideScreenHack", bWidescreenHack); + CHECK_SETTING("Video_Settings", "AspectRatio", iAspectRatio); + CHECK_SETTING("Video_Settings", "Crop", bCrop); + CHECK_SETTING("Video_Settings", "UseXFB", bUseXFB); + CHECK_SETTING("Video_Settings", "UseRealXFB", bUseRealXFB); + CHECK_SETTING("Video_Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples); + CHECK_SETTING("Video_Settings", "HiresTextures", bHiresTextures); + CHECK_SETTING("Video_Settings", "ConvertHiresTextures", bConvertHiresTextures); + CHECK_SETTING("Video_Settings", "CacheHiresTextures", bCacheHiresTextures); + CHECK_SETTING("Video_Settings", "EnablePixelLighting", bEnablePixelLighting); + CHECK_SETTING("Video_Settings", "FastDepthCalc", bFastDepthCalc); + CHECK_SETTING("Video_Settings", "MSAA", iMultisamples); + CHECK_SETTING("Video_Settings", "SSAA", bSSAA); - int tmp = -9000; - CHECK_SETTING("Video_Settings", "EFBScale", tmp); // integral - if (tmp != -9000) - { - if (tmp != SCALE_FORCE_INTEGRAL) - { - iEFBScale = tmp; - } - else // Round down to multiple of native IR - { - switch (iEFBScale) - { - case SCALE_AUTO: - iEFBScale = SCALE_AUTO_INTEGRAL; - break; - case SCALE_1_5X: - iEFBScale = SCALE_1X; - break; - case SCALE_2_5X: - iEFBScale = SCALE_2X; - break; - default: - break; - } - } - } + int tmp = -9000; + CHECK_SETTING("Video_Settings", "EFBScale", tmp); // integral + if (tmp != -9000) + { + if (tmp != SCALE_FORCE_INTEGRAL) + { + iEFBScale = tmp; + } + else // Round down to multiple of native IR + { + switch (iEFBScale) + { + case SCALE_AUTO: + iEFBScale = SCALE_AUTO_INTEGRAL; + break; + case SCALE_1_5X: + iEFBScale = SCALE_1X; + break; + case SCALE_2_5X: + iEFBScale = SCALE_2X; + break; + default: + break; + } + } + } - CHECK_SETTING("Video_Settings", "DisableFog", bDisableFog); + CHECK_SETTING("Video_Settings", "DisableFog", bDisableFog); - CHECK_SETTING("Video_Enhancements", "ForceFiltering", bForceFiltering); - CHECK_SETTING("Video_Enhancements", "MaxAnisotropy", iMaxAnisotropy); // NOTE - this is x in (1 << x) - CHECK_SETTING("Video_Enhancements", "PostProcessingShader", sPostProcessingShader); + CHECK_SETTING("Video_Enhancements", "ForceFiltering", bForceFiltering); + CHECK_SETTING("Video_Enhancements", "MaxAnisotropy", + iMaxAnisotropy); // NOTE - this is x in (1 << x) + CHECK_SETTING("Video_Enhancements", "PostProcessingShader", sPostProcessingShader); - // These are not overrides, they are per-game stereoscopy parameters, hence no warning - iniFile.GetIfExists("Video_Stereoscopy", "StereoConvergence", &iStereoConvergence, 20); - iniFile.GetIfExists("Video_Stereoscopy", "StereoEFBMonoDepth", &bStereoEFBMonoDepth, false); - iniFile.GetIfExists("Video_Stereoscopy", "StereoDepthPercentage", &iStereoDepthPercentage, 100); + // These are not overrides, they are per-game stereoscopy parameters, hence no warning + iniFile.GetIfExists("Video_Stereoscopy", "StereoConvergence", &iStereoConvergence, 20); + iniFile.GetIfExists("Video_Stereoscopy", "StereoEFBMonoDepth", &bStereoEFBMonoDepth, false); + iniFile.GetIfExists("Video_Stereoscopy", "StereoDepthPercentage", &iStereoDepthPercentage, 100); - CHECK_SETTING("Video_Stereoscopy", "StereoMode", iStereoMode); - CHECK_SETTING("Video_Stereoscopy", "StereoDepth", iStereoDepth); - CHECK_SETTING("Video_Stereoscopy", "StereoSwapEyes", bStereoSwapEyes); + CHECK_SETTING("Video_Stereoscopy", "StereoMode", iStereoMode); + CHECK_SETTING("Video_Stereoscopy", "StereoDepth", iStereoDepth); + CHECK_SETTING("Video_Stereoscopy", "StereoSwapEyes", bStereoSwapEyes); - CHECK_SETTING("Video_Hacks", "EFBAccessEnable", bEFBAccessEnable); - CHECK_SETTING("Video_Hacks", "BBoxEnable", bBBoxEnable); - CHECK_SETTING("Video_Hacks", "ForceProgressive", bForceProgressive); - CHECK_SETTING("Video_Hacks", "EFBToTextureEnable", bSkipEFBCopyToRam); - CHECK_SETTING("Video_Hacks", "EFBScaledCopy", bCopyEFBScaled); - CHECK_SETTING("Video_Hacks", "EFBEmulateFormatChanges", bEFBEmulateFormatChanges); + CHECK_SETTING("Video_Hacks", "EFBAccessEnable", bEFBAccessEnable); + CHECK_SETTING("Video_Hacks", "BBoxEnable", bBBoxEnable); + CHECK_SETTING("Video_Hacks", "ForceProgressive", bForceProgressive); + CHECK_SETTING("Video_Hacks", "EFBToTextureEnable", bSkipEFBCopyToRam); + CHECK_SETTING("Video_Hacks", "EFBScaledCopy", bCopyEFBScaled); + CHECK_SETTING("Video_Hacks", "EFBEmulateFormatChanges", bEFBEmulateFormatChanges); - CHECK_SETTING("Video", "ProjectionHack", iPhackvalue[0]); - CHECK_SETTING("Video", "PH_SZNear", iPhackvalue[1]); - CHECK_SETTING("Video", "PH_SZFar", iPhackvalue[2]); - CHECK_SETTING("Video", "PH_ZNear", sPhackvalue[0]); - CHECK_SETTING("Video", "PH_ZFar", sPhackvalue[1]); - CHECK_SETTING("Video", "PerfQueriesEnable", bPerfQueriesEnable); + CHECK_SETTING("Video", "ProjectionHack", iPhackvalue[0]); + CHECK_SETTING("Video", "PH_SZNear", iPhackvalue[1]); + CHECK_SETTING("Video", "PH_SZFar", iPhackvalue[2]); + CHECK_SETTING("Video", "PH_ZNear", sPhackvalue[0]); + CHECK_SETTING("Video", "PH_ZFar", sPhackvalue[1]); + CHECK_SETTING("Video", "PerfQueriesEnable", bPerfQueriesEnable); - if (gfx_override_exists) - OSD::AddMessage("Warning: Opening the graphics configuration will reset settings and might cause issues!", 10000); + if (gfx_override_exists) + OSD::AddMessage( + "Warning: Opening the graphics configuration will reset settings and might cause issues!", + 10000); } void VideoConfig::VerifyValidity() { - // TODO: Check iMaxAnisotropy value - if (iAdapter < 0 || iAdapter > ((int)backend_info.Adapters.size() - 1)) - iAdapter = 0; + // TODO: Check iMaxAnisotropy value + if (iAdapter < 0 || iAdapter > ((int)backend_info.Adapters.size() - 1)) + iAdapter = 0; - if (std::find(backend_info.AAModes.begin(), backend_info.AAModes.end(), iMultisamples) == backend_info.AAModes.end()) - iMultisamples = 1; + if (std::find(backend_info.AAModes.begin(), backend_info.AAModes.end(), iMultisamples) == + backend_info.AAModes.end()) + iMultisamples = 1; - if (iStereoMode > 0) - { - if (!backend_info.bSupportsGeometryShaders) - { - OSD::AddMessage("Stereoscopic 3D isn't supported by your GPU, support for OpenGL 3.2 is required.", 10000); - iStereoMode = 0; - } + if (iStereoMode > 0) + { + if (!backend_info.bSupportsGeometryShaders) + { + OSD::AddMessage( + "Stereoscopic 3D isn't supported by your GPU, support for OpenGL 3.2 is required.", + 10000); + iStereoMode = 0; + } - if (bUseXFB && bUseRealXFB) - { - OSD::AddMessage("Stereoscopic 3D isn't supported with Real XFB, turning off stereoscopy.", 10000); - iStereoMode = 0; - } - } + if (bUseXFB && bUseRealXFB) + { + OSD::AddMessage("Stereoscopic 3D isn't supported with Real XFB, turning off stereoscopy.", + 10000); + iStereoMode = 0; + } + } } void VideoConfig::Save(const std::string& ini_file) { - IniFile iniFile; - iniFile.Load(ini_file); + IniFile iniFile; + iniFile.Load(ini_file); - IniFile::Section* hardware = iniFile.GetOrCreateSection("Hardware"); - hardware->Set("VSync", bVSync); - hardware->Set("Adapter", iAdapter); + IniFile::Section* hardware = iniFile.GetOrCreateSection("Hardware"); + hardware->Set("VSync", bVSync); + hardware->Set("Adapter", iAdapter); - IniFile::Section* settings = iniFile.GetOrCreateSection("Settings"); - settings->Set("AspectRatio", iAspectRatio); - settings->Set("Crop", bCrop); - settings->Set("wideScreenHack", bWidescreenHack); - settings->Set("UseXFB", bUseXFB); - settings->Set("UseRealXFB", bUseRealXFB); - settings->Set("SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples); - settings->Set("ShowFPS", bShowFPS); - settings->Set("LogRenderTimeToFile", bLogRenderTimeToFile); - settings->Set("OverlayStats", bOverlayStats); - settings->Set("OverlayProjStats", bOverlayProjStats); - settings->Set("DumpTextures", bDumpTextures); - settings->Set("HiresTextures", bHiresTextures); - settings->Set("ConvertHiresTextures", bConvertHiresTextures); - settings->Set("CacheHiresTextures", bCacheHiresTextures); - settings->Set("DumpEFBTarget", bDumpEFBTarget); - settings->Set("FreeLook", bFreeLook); - settings->Set("UseFFV1", bUseFFV1); - settings->Set("EnablePixelLighting", bEnablePixelLighting); - settings->Set("FastDepthCalc", bFastDepthCalc); - settings->Set("MSAA", iMultisamples); - settings->Set("SSAA", bSSAA); - settings->Set("EFBScale", iEFBScale); - settings->Set("TexFmtOverlayEnable", bTexFmtOverlayEnable); - settings->Set("TexFmtOverlayCenter", bTexFmtOverlayCenter); - settings->Set("Wireframe", bWireFrame); - settings->Set("DisableFog", bDisableFog); - settings->Set("EnableShaderDebugging", bEnableShaderDebugging); - settings->Set("BorderlessFullscreen", bBorderlessFullscreen); + IniFile::Section* settings = iniFile.GetOrCreateSection("Settings"); + settings->Set("AspectRatio", iAspectRatio); + settings->Set("Crop", bCrop); + settings->Set("wideScreenHack", bWidescreenHack); + settings->Set("UseXFB", bUseXFB); + settings->Set("UseRealXFB", bUseRealXFB); + settings->Set("SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples); + settings->Set("ShowFPS", bShowFPS); + settings->Set("LogRenderTimeToFile", bLogRenderTimeToFile); + settings->Set("OverlayStats", bOverlayStats); + settings->Set("OverlayProjStats", bOverlayProjStats); + settings->Set("DumpTextures", bDumpTextures); + settings->Set("HiresTextures", bHiresTextures); + settings->Set("ConvertHiresTextures", bConvertHiresTextures); + settings->Set("CacheHiresTextures", bCacheHiresTextures); + settings->Set("DumpEFBTarget", bDumpEFBTarget); + settings->Set("FreeLook", bFreeLook); + settings->Set("UseFFV1", bUseFFV1); + settings->Set("EnablePixelLighting", bEnablePixelLighting); + settings->Set("FastDepthCalc", bFastDepthCalc); + settings->Set("MSAA", iMultisamples); + settings->Set("SSAA", bSSAA); + settings->Set("EFBScale", iEFBScale); + settings->Set("TexFmtOverlayEnable", bTexFmtOverlayEnable); + settings->Set("TexFmtOverlayCenter", bTexFmtOverlayCenter); + settings->Set("Wireframe", bWireFrame); + settings->Set("DisableFog", bDisableFog); + settings->Set("EnableShaderDebugging", bEnableShaderDebugging); + settings->Set("BorderlessFullscreen", bBorderlessFullscreen); - settings->Set("SWZComploc", bZComploc); - settings->Set("SWZFreeze", bZFreeze); - settings->Set("SWDumpObjects", bDumpObjects); - settings->Set("SWDumpTevStages", bDumpTevStages); - settings->Set("SWDumpTevTexFetches", bDumpTevTextureFetches); - settings->Set("SWDrawStart", drawStart); - settings->Set("SWDrawEnd", drawEnd); + settings->Set("SWZComploc", bZComploc); + settings->Set("SWZFreeze", bZFreeze); + settings->Set("SWDumpObjects", bDumpObjects); + settings->Set("SWDumpTevStages", bDumpTevStages); + settings->Set("SWDumpTevTexFetches", bDumpTevTextureFetches); + settings->Set("SWDrawStart", drawStart); + settings->Set("SWDrawEnd", drawEnd); - IniFile::Section* enhancements = iniFile.GetOrCreateSection("Enhancements"); - enhancements->Set("ForceFiltering", bForceFiltering); - enhancements->Set("MaxAnisotropy", iMaxAnisotropy); - enhancements->Set("PostProcessingShader", sPostProcessingShader); + IniFile::Section* enhancements = iniFile.GetOrCreateSection("Enhancements"); + enhancements->Set("ForceFiltering", bForceFiltering); + enhancements->Set("MaxAnisotropy", iMaxAnisotropy); + enhancements->Set("PostProcessingShader", sPostProcessingShader); - IniFile::Section* stereoscopy = iniFile.GetOrCreateSection("Stereoscopy"); - stereoscopy->Set("StereoMode", iStereoMode); - stereoscopy->Set("StereoDepth", iStereoDepth); - stereoscopy->Set("StereoConvergencePercentage", iStereoConvergencePercentage); - stereoscopy->Set("StereoSwapEyes", bStereoSwapEyes); + IniFile::Section* stereoscopy = iniFile.GetOrCreateSection("Stereoscopy"); + stereoscopy->Set("StereoMode", iStereoMode); + stereoscopy->Set("StereoDepth", iStereoDepth); + stereoscopy->Set("StereoConvergencePercentage", iStereoConvergencePercentage); + stereoscopy->Set("StereoSwapEyes", bStereoSwapEyes); - IniFile::Section* hacks = iniFile.GetOrCreateSection("Hacks"); - hacks->Set("EFBAccessEnable", bEFBAccessEnable); - hacks->Set("BBoxEnable", bBBoxEnable); - hacks->Set("ForceProgressive", bForceProgressive); - hacks->Set("EFBToTextureEnable", bSkipEFBCopyToRam); - hacks->Set("EFBScaledCopy", bCopyEFBScaled); - hacks->Set("EFBEmulateFormatChanges", bEFBEmulateFormatChanges); + IniFile::Section* hacks = iniFile.GetOrCreateSection("Hacks"); + hacks->Set("EFBAccessEnable", bEFBAccessEnable); + hacks->Set("BBoxEnable", bBBoxEnable); + hacks->Set("ForceProgressive", bForceProgressive); + hacks->Set("EFBToTextureEnable", bSkipEFBCopyToRam); + hacks->Set("EFBScaledCopy", bCopyEFBScaled); + hacks->Set("EFBEmulateFormatChanges", bEFBEmulateFormatChanges); - iniFile.Save(ini_file); + iniFile.Save(ini_file); } bool VideoConfig::IsVSync() { - return bVSync && !Core::GetIsThrottlerTempDisabled(); + return bVSync && !Core::GetIsThrottlerTempDisabled(); } diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index fdb96d823c..d39bfdd118 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -2,7 +2,6 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. - // IMPORTANT: UI etc should modify g_Config. Graphics code should read g_ActiveConfig. // The reason for this is to get rid of race conditions etc when the configuration // changes in the middle of a frame. This is done by copying g_Config to g_ActiveConfig @@ -18,167 +17,170 @@ #include "VideoCommon/VideoCommon.h" // Log in two categories, and save three other options in the same byte -#define CONF_LOG 1 -#define CONF_PRIMLOG 2 -#define CONF_SAVETARGETS 8 -#define CONF_SAVESHADERS 16 +#define CONF_LOG 1 +#define CONF_PRIMLOG 2 +#define CONF_SAVETARGETS 8 +#define CONF_SAVESHADERS 16 enum AspectMode { - ASPECT_AUTO = 0, - ASPECT_ANALOG_WIDE = 1, - ASPECT_ANALOG = 2, - ASPECT_STRETCH = 3, + ASPECT_AUTO = 0, + ASPECT_ANALOG_WIDE = 1, + ASPECT_ANALOG = 2, + ASPECT_STRETCH = 3, }; enum EFBScale { - SCALE_FORCE_INTEGRAL = -1, - SCALE_AUTO, - SCALE_AUTO_INTEGRAL, - SCALE_1X, - SCALE_1_5X, - SCALE_2X, - SCALE_2_5X, + SCALE_FORCE_INTEGRAL = -1, + SCALE_AUTO, + SCALE_AUTO_INTEGRAL, + SCALE_1X, + SCALE_1_5X, + SCALE_2X, + SCALE_2_5X, }; enum StereoMode { - STEREO_OFF = 0, - STEREO_SBS, - STEREO_TAB, - STEREO_ANAGLYPH, - STEREO_3DVISION + STEREO_OFF = 0, + STEREO_SBS, + STEREO_TAB, + STEREO_ANAGLYPH, + STEREO_3DVISION }; // NEVER inherit from this class. struct VideoConfig final { - VideoConfig(); - void Load(const std::string& ini_file); - void GameIniLoad(); - void VerifyValidity(); - void Save(const std::string& ini_file); - void UpdateProjectionHack(); - bool IsVSync(); + VideoConfig(); + void Load(const std::string& ini_file); + void GameIniLoad(); + void VerifyValidity(); + void Save(const std::string& ini_file); + void UpdateProjectionHack(); + bool IsVSync(); - // General - bool bVSync; - bool bFullscreen; - bool bExclusiveMode; - bool bRunning; - bool bWidescreenHack; - int iAspectRatio; - bool bCrop; // Aspect ratio controls. - bool bUseXFB; - bool bUseRealXFB; + // General + bool bVSync; + bool bFullscreen; + bool bExclusiveMode; + bool bRunning; + bool bWidescreenHack; + int iAspectRatio; + bool bCrop; // Aspect ratio controls. + bool bUseXFB; + bool bUseRealXFB; - // Enhancements - int iMultisamples; - bool bSSAA; - int iEFBScale; - bool bForceFiltering; - int iMaxAnisotropy; - std::string sPostProcessingShader; + // Enhancements + int iMultisamples; + bool bSSAA; + int iEFBScale; + bool bForceFiltering; + int iMaxAnisotropy; + std::string sPostProcessingShader; - // Information - bool bShowFPS; - bool bOverlayStats; - bool bOverlayProjStats; - bool bTexFmtOverlayEnable; - bool bTexFmtOverlayCenter; - bool bLogRenderTimeToFile; + // Information + bool bShowFPS; + bool bOverlayStats; + bool bOverlayProjStats; + bool bTexFmtOverlayEnable; + bool bTexFmtOverlayCenter; + bool bLogRenderTimeToFile; - // Render - bool bWireFrame; - bool bDisableFog; + // Render + bool bWireFrame; + bool bDisableFog; - // Utility - bool bDumpTextures; - bool bHiresTextures; - bool bConvertHiresTextures; - bool bCacheHiresTextures; - bool bDumpEFBTarget; - bool bUseFFV1; - bool bFreeLook; - bool bBorderlessFullscreen; + // Utility + bool bDumpTextures; + bool bHiresTextures; + bool bConvertHiresTextures; + bool bCacheHiresTextures; + bool bDumpEFBTarget; + bool bUseFFV1; + bool bFreeLook; + bool bBorderlessFullscreen; - // Hacks - bool bEFBAccessEnable; - bool bPerfQueriesEnable; - bool bBBoxEnable; - bool bForceProgressive; + // Hacks + bool bEFBAccessEnable; + bool bPerfQueriesEnable; + bool bBBoxEnable; + bool bForceProgressive; - bool bEFBEmulateFormatChanges; - bool bSkipEFBCopyToRam; - bool bCopyEFBScaled; - int iSafeTextureCache_ColorSamples; - int iPhackvalue[3]; - std::string sPhackvalue[2]; - float fAspectRatioHackW, fAspectRatioHackH; - bool bEnablePixelLighting; - bool bFastDepthCalc; - int iLog; // CONF_ bits - int iSaveTargetId; // TODO: Should be dropped + bool bEFBEmulateFormatChanges; + bool bSkipEFBCopyToRam; + bool bCopyEFBScaled; + int iSafeTextureCache_ColorSamples; + int iPhackvalue[3]; + std::string sPhackvalue[2]; + float fAspectRatioHackW, fAspectRatioHackH; + bool bEnablePixelLighting; + bool bFastDepthCalc; + int iLog; // CONF_ bits + int iSaveTargetId; // TODO: Should be dropped - // Stereoscopy - int iStereoMode; - int iStereoDepth; - int iStereoConvergence; - int iStereoConvergencePercentage; - bool bStereoSwapEyes; - bool bStereoEFBMonoDepth; - int iStereoDepthPercentage; + // Stereoscopy + int iStereoMode; + int iStereoDepth; + int iStereoConvergence; + int iStereoConvergencePercentage; + bool bStereoSwapEyes; + bool bStereoEFBMonoDepth; + int iStereoDepthPercentage; - // D3D only config, mostly to be merged into the above - int iAdapter; + // D3D only config, mostly to be merged into the above + int iAdapter; - // Debugging - bool bEnableShaderDebugging; + // Debugging + bool bEnableShaderDebugging; - // VideoSW Debugging - int drawStart; - int drawEnd; - bool bZComploc; - bool bZFreeze; - bool bDumpObjects; - bool bDumpTevStages; - bool bDumpTevTextureFetches; + // VideoSW Debugging + int drawStart; + int drawEnd; + bool bZComploc; + bool bZFreeze; + bool bDumpObjects; + bool bDumpTevStages; + bool bDumpTevTextureFetches; - // Static config per API - // TODO: Move this out of VideoConfig - struct - { - API_TYPE APIType; + // Static config per API + // TODO: Move this out of VideoConfig + struct + { + API_TYPE APIType; - std::vector Adapters; // for D3D - std::vector AAModes; - std::vector PPShaders; // post-processing shaders - std::vector AnaglyphShaders; // anaglyph shaders + std::vector Adapters; // for D3D + std::vector AAModes; + std::vector PPShaders; // post-processing shaders + std::vector AnaglyphShaders; // anaglyph shaders - // TODO: merge AdapterName and Adapters array - std::string AdapterName; // for OpenGL + // TODO: merge AdapterName and Adapters array + std::string AdapterName; // for OpenGL - bool bSupportsExclusiveFullscreen; - bool bSupportsDualSourceBlend; - bool bSupportsPrimitiveRestart; - bool bSupportsOversizedViewports; - bool bSupportsGeometryShaders; - bool bSupports3DVision; - bool bSupportsEarlyZ; // needed by PixelShaderGen, so must stay in VideoCommon - bool bSupportsBindingLayout; // Needed by ShaderGen, so must stay in VideoCommon - bool bSupportsBBox; - bool bSupportsGSInstancing; // Needed by GeometryShaderGen, so must stay in VideoCommon - bool bSupportsPostProcessing; - bool bSupportsPaletteConversion; - bool bSupportsClipControl; // Needed by VertexShaderGen, so must stay in VideoCommon - bool bSupportsSSAA; - } backend_info; + bool bSupportsExclusiveFullscreen; + bool bSupportsDualSourceBlend; + bool bSupportsPrimitiveRestart; + bool bSupportsOversizedViewports; + bool bSupportsGeometryShaders; + bool bSupports3DVision; + bool bSupportsEarlyZ; // needed by PixelShaderGen, so must stay in VideoCommon + bool bSupportsBindingLayout; // Needed by ShaderGen, so must stay in VideoCommon + bool bSupportsBBox; + bool bSupportsGSInstancing; // Needed by GeometryShaderGen, so must stay in VideoCommon + bool bSupportsPostProcessing; + bool bSupportsPaletteConversion; + bool bSupportsClipControl; // Needed by VertexShaderGen, so must stay in VideoCommon + bool bSupportsSSAA; + } backend_info; - // Utility - bool RealXFBEnabled() const { return bUseXFB && bUseRealXFB; } - bool VirtualXFBEnabled() const { return bUseXFB && !bUseRealXFB; } - bool ExclusiveFullscreenEnabled() const { return backend_info.bSupportsExclusiveFullscreen && !bBorderlessFullscreen; } + // Utility + bool RealXFBEnabled() const { return bUseXFB && bUseRealXFB; } + bool VirtualXFBEnabled() const { return bUseXFB && !bUseRealXFB; } + bool ExclusiveFullscreenEnabled() const + { + return backend_info.bSupportsExclusiveFullscreen && !bBorderlessFullscreen; + } }; extern VideoConfig g_Config; diff --git a/Source/Core/VideoCommon/VideoState.cpp b/Source/Core/VideoCommon/VideoState.cpp index 90c18a0368..6caccd5fd9 100644 --- a/Source/Core/VideoCommon/VideoState.cpp +++ b/Source/Core/VideoCommon/VideoState.cpp @@ -5,10 +5,10 @@ #include #include "Common/ChunkFile.h" -#include "VideoCommon/BoundingBox.h" #include "VideoCommon/BPMemory.h" -#include "VideoCommon/CommandProcessor.h" +#include "VideoCommon/BoundingBox.h" #include "VideoCommon/CPMemory.h" +#include "VideoCommon/CommandProcessor.h" #include "VideoCommon/Fifo.h" #include "VideoCommon/GeometryShaderManager.h" #include "VideoCommon/PixelEngine.h" @@ -19,56 +19,56 @@ #include "VideoCommon/VideoState.h" #include "VideoCommon/XFMemory.h" -void VideoCommon_DoState(PointerWrap &p) +void VideoCommon_DoState(PointerWrap& p) { - // BP Memory - p.Do(bpmem); - p.DoMarker("BP Memory"); + // BP Memory + p.Do(bpmem); + p.DoMarker("BP Memory"); - // CP Memory - DoCPState(p); + // CP Memory + DoCPState(p); - // XF Memory - p.Do(xfmem); - p.DoMarker("XF Memory"); + // XF Memory + p.Do(xfmem); + p.DoMarker("XF Memory"); - // Texture decoder - p.DoArray(texMem); - p.DoMarker("texMem"); + // Texture decoder + p.DoArray(texMem); + p.DoMarker("texMem"); - // FIFO - Fifo::DoState(p); - p.DoMarker("Fifo"); + // FIFO + Fifo::DoState(p); + p.DoMarker("Fifo"); - CommandProcessor::DoState(p); - p.DoMarker("CommandProcessor"); + CommandProcessor::DoState(p); + p.DoMarker("CommandProcessor"); - PixelEngine::DoState(p); - p.DoMarker("PixelEngine"); + PixelEngine::DoState(p); + p.DoMarker("PixelEngine"); - // the old way of replaying current bpmem as writes to push side effects to pixel shader manager doesn't really work. - PixelShaderManager::DoState(p); - p.DoMarker("PixelShaderManager"); + // the old way of replaying current bpmem as writes to push side effects to pixel shader manager + // doesn't really work. + PixelShaderManager::DoState(p); + p.DoMarker("PixelShaderManager"); - VertexShaderManager::DoState(p); - p.DoMarker("VertexShaderManager"); + VertexShaderManager::DoState(p); + p.DoMarker("VertexShaderManager"); - GeometryShaderManager::DoState(p); - p.DoMarker("GeometryShaderManager"); + GeometryShaderManager::DoState(p); + p.DoMarker("GeometryShaderManager"); - VertexManagerBase::DoState(p); - p.DoMarker("VertexManager"); + VertexManagerBase::DoState(p); + p.DoMarker("VertexManager"); - BoundingBox::DoState(p); - p.DoMarker("BoundingBox"); + BoundingBox::DoState(p); + p.DoMarker("BoundingBox"); - - // TODO: search for more data that should be saved and add it here + // TODO: search for more data that should be saved and add it here } void VideoCommon_Init() { - memset(&g_main_cp_state, 0, sizeof(g_main_cp_state)); - memset(&g_preprocess_cp_state, 0, sizeof(g_preprocess_cp_state)); - memset(texMem, 0, TMEM_SIZE); + memset(&g_main_cp_state, 0, sizeof(g_main_cp_state)); + memset(&g_preprocess_cp_state, 0, sizeof(g_preprocess_cp_state)); + memset(texMem, 0, TMEM_SIZE); } diff --git a/Source/Core/VideoCommon/VideoState.h b/Source/Core/VideoCommon/VideoState.h index ec25cdca5d..0f15c977f7 100644 --- a/Source/Core/VideoCommon/VideoState.h +++ b/Source/Core/VideoCommon/VideoState.h @@ -6,5 +6,5 @@ class PointerWrap; -void VideoCommon_DoState(PointerWrap &p); +void VideoCommon_DoState(PointerWrap& p); void VideoCommon_Init(); diff --git a/Source/Core/VideoCommon/XFMemory.h b/Source/Core/VideoCommon/XFMemory.h index 99d01f2d45..a90d00fbc1 100644 --- a/Source/Core/VideoCommon/XFMemory.h +++ b/Source/Core/VideoCommon/XFMemory.h @@ -14,300 +14,288 @@ class DataReader; // Projection enum : u32 { - XF_TEXPROJ_ST = 0, - XF_TEXPROJ_STQ = 1 + XF_TEXPROJ_ST = 0, + XF_TEXPROJ_STQ = 1 }; // Input form enum : u32 { - XF_TEXINPUT_AB11 = 0, - XF_TEXINPUT_ABC1 = 1 + XF_TEXINPUT_AB11 = 0, + XF_TEXINPUT_ABC1 = 1 }; // Texture generation type enum : u32 { - XF_TEXGEN_REGULAR = 0, - XF_TEXGEN_EMBOSS_MAP = 1, // Used when bump mapping - XF_TEXGEN_COLOR_STRGBC0 = 2, - XF_TEXGEN_COLOR_STRGBC1 = 3 + XF_TEXGEN_REGULAR = 0, + XF_TEXGEN_EMBOSS_MAP = 1, // Used when bump mapping + XF_TEXGEN_COLOR_STRGBC0 = 2, + XF_TEXGEN_COLOR_STRGBC1 = 3 }; // Source row enum : u32 { - XF_SRCGEOM_INROW = 0, // Input is abc - XF_SRCNORMAL_INROW = 1, // Input is abc - XF_SRCCOLORS_INROW = 2, - XF_SRCBINORMAL_T_INROW = 3, // Input is abc - XF_SRCBINORMAL_B_INROW = 4, // Input is abc - XF_SRCTEX0_INROW = 5, - XF_SRCTEX1_INROW = 6, - XF_SRCTEX2_INROW = 7, - XF_SRCTEX3_INROW = 8, - XF_SRCTEX4_INROW = 9, - XF_SRCTEX5_INROW = 10, - XF_SRCTEX6_INROW = 11, - XF_SRCTEX7_INROW = 12 + XF_SRCGEOM_INROW = 0, // Input is abc + XF_SRCNORMAL_INROW = 1, // Input is abc + XF_SRCCOLORS_INROW = 2, + XF_SRCBINORMAL_T_INROW = 3, // Input is abc + XF_SRCBINORMAL_B_INROW = 4, // Input is abc + XF_SRCTEX0_INROW = 5, + XF_SRCTEX1_INROW = 6, + XF_SRCTEX2_INROW = 7, + XF_SRCTEX3_INROW = 8, + XF_SRCTEX4_INROW = 9, + XF_SRCTEX5_INROW = 10, + XF_SRCTEX6_INROW = 11, + XF_SRCTEX7_INROW = 12 }; // Control source enum : u32 { - GX_SRC_REG = 0, - GX_SRC_VTX = 1 + GX_SRC_REG = 0, + GX_SRC_VTX = 1 }; // Light diffuse attenuation function enum : u32 { - LIGHTDIF_NONE = 0, - LIGHTDIF_SIGN = 1, - LIGHTDIF_CLAMP = 2 + LIGHTDIF_NONE = 0, + LIGHTDIF_SIGN = 1, + LIGHTDIF_CLAMP = 2 }; // Light attenuation function enum : u32 { - LIGHTATTN_NONE = 0, // No attenuation - LIGHTATTN_SPEC = 1, // Point light attenuation - LIGHTATTN_DIR = 2, // Directional light attenuation - LIGHTATTN_SPOT = 3 // Spot light attenuation + LIGHTATTN_NONE = 0, // No attenuation + LIGHTATTN_SPEC = 1, // Point light attenuation + LIGHTATTN_DIR = 2, // Directional light attenuation + LIGHTATTN_SPOT = 3 // Spot light attenuation }; // Projection type enum : u32 { - GX_PERSPECTIVE = 0, - GX_ORTHOGRAPHIC = 1 + GX_PERSPECTIVE = 0, + GX_ORTHOGRAPHIC = 1 }; // Registers and register ranges enum { - XFMEM_POSMATRICES = 0x000, - XFMEM_POSMATRICES_END = 0x100, - XFMEM_NORMALMATRICES = 0x400, - XFMEM_NORMALMATRICES_END = 0x460, - XFMEM_POSTMATRICES = 0x500, - XFMEM_POSTMATRICES_END = 0x600, - XFMEM_LIGHTS = 0x600, - XFMEM_LIGHTS_END = 0x680, - XFMEM_ERROR = 0x1000, - XFMEM_DIAG = 0x1001, - XFMEM_STATE0 = 0x1002, - XFMEM_STATE1 = 0x1003, - XFMEM_CLOCK = 0x1004, - XFMEM_CLIPDISABLE = 0x1005, - XFMEM_SETGPMETRIC = 0x1006, - XFMEM_VTXSPECS = 0x1008, - XFMEM_SETNUMCHAN = 0x1009, - XFMEM_SETCHAN0_AMBCOLOR = 0x100a, - XFMEM_SETCHAN1_AMBCOLOR = 0x100b, - XFMEM_SETCHAN0_MATCOLOR = 0x100c, - XFMEM_SETCHAN1_MATCOLOR = 0x100d, - XFMEM_SETCHAN0_COLOR = 0x100e, - XFMEM_SETCHAN1_COLOR = 0x100f, - XFMEM_SETCHAN0_ALPHA = 0x1010, - XFMEM_SETCHAN1_ALPHA = 0x1011, - XFMEM_DUALTEX = 0x1012, - XFMEM_SETMATRIXINDA = 0x1018, - XFMEM_SETMATRIXINDB = 0x1019, - XFMEM_SETVIEWPORT = 0x101a, - XFMEM_SETZSCALE = 0x101c, - XFMEM_SETZOFFSET = 0x101f, - XFMEM_SETPROJECTION = 0x1020, - // XFMEM_SETPROJECTIONB = 0x1021, - // XFMEM_SETPROJECTIONC = 0x1022, - // XFMEM_SETPROJECTIOND = 0x1023, - // XFMEM_SETPROJECTIONE = 0x1024, - // XFMEM_SETPROJECTIONF = 0x1025, - // XFMEM_SETPROJECTIONORTHO1 = 0x1026, - // XFMEM_SETPROJECTIONORTHO2 = 0x1027, - XFMEM_SETNUMTEXGENS = 0x103f, - XFMEM_SETTEXMTXINFO = 0x1040, - XFMEM_SETPOSMTXINFO = 0x1050, + XFMEM_POSMATRICES = 0x000, + XFMEM_POSMATRICES_END = 0x100, + XFMEM_NORMALMATRICES = 0x400, + XFMEM_NORMALMATRICES_END = 0x460, + XFMEM_POSTMATRICES = 0x500, + XFMEM_POSTMATRICES_END = 0x600, + XFMEM_LIGHTS = 0x600, + XFMEM_LIGHTS_END = 0x680, + XFMEM_ERROR = 0x1000, + XFMEM_DIAG = 0x1001, + XFMEM_STATE0 = 0x1002, + XFMEM_STATE1 = 0x1003, + XFMEM_CLOCK = 0x1004, + XFMEM_CLIPDISABLE = 0x1005, + XFMEM_SETGPMETRIC = 0x1006, + XFMEM_VTXSPECS = 0x1008, + XFMEM_SETNUMCHAN = 0x1009, + XFMEM_SETCHAN0_AMBCOLOR = 0x100a, + XFMEM_SETCHAN1_AMBCOLOR = 0x100b, + XFMEM_SETCHAN0_MATCOLOR = 0x100c, + XFMEM_SETCHAN1_MATCOLOR = 0x100d, + XFMEM_SETCHAN0_COLOR = 0x100e, + XFMEM_SETCHAN1_COLOR = 0x100f, + XFMEM_SETCHAN0_ALPHA = 0x1010, + XFMEM_SETCHAN1_ALPHA = 0x1011, + XFMEM_DUALTEX = 0x1012, + XFMEM_SETMATRIXINDA = 0x1018, + XFMEM_SETMATRIXINDB = 0x1019, + XFMEM_SETVIEWPORT = 0x101a, + XFMEM_SETZSCALE = 0x101c, + XFMEM_SETZOFFSET = 0x101f, + XFMEM_SETPROJECTION = 0x1020, + // XFMEM_SETPROJECTIONB = 0x1021, + // XFMEM_SETPROJECTIONC = 0x1022, + // XFMEM_SETPROJECTIOND = 0x1023, + // XFMEM_SETPROJECTIONE = 0x1024, + // XFMEM_SETPROJECTIONF = 0x1025, + // XFMEM_SETPROJECTIONORTHO1 = 0x1026, + // XFMEM_SETPROJECTIONORTHO2 = 0x1027, + XFMEM_SETNUMTEXGENS = 0x103f, + XFMEM_SETTEXMTXINFO = 0x1040, + XFMEM_SETPOSMTXINFO = 0x1050, }; -union LitChannel -{ - struct - { - u32 matsource : 1; - u32 enablelighting : 1; - u32 lightMask0_3 : 4; - u32 ambsource : 1; - u32 diffusefunc : 2; // LIGHTDIF_X - u32 attnfunc : 2; // LIGHTATTN_X - u32 lightMask4_7 : 4; - }; - struct - { - u32 hex : 15; - u32 unused : 17; - }; - struct - { - u32 dummy0 : 7; - u32 lightparams : 4; - u32 dummy1 : 21; - }; - unsigned int GetFullLightMask() const - { - return enablelighting ? (lightMask0_3 | (lightMask4_7 << 4)) : 0; - } +union LitChannel { + struct + { + u32 matsource : 1; + u32 enablelighting : 1; + u32 lightMask0_3 : 4; + u32 ambsource : 1; + u32 diffusefunc : 2; // LIGHTDIF_X + u32 attnfunc : 2; // LIGHTATTN_X + u32 lightMask4_7 : 4; + }; + struct + { + u32 hex : 15; + u32 unused : 17; + }; + struct + { + u32 dummy0 : 7; + u32 lightparams : 4; + u32 dummy1 : 21; + }; + unsigned int GetFullLightMask() const + { + return enablelighting ? (lightMask0_3 | (lightMask4_7 << 4)) : 0; + } }; - -union INVTXSPEC -{ - struct - { - u32 numcolors : 2; - u32 numnormals : 2; // 0 - nothing, 1 - just normal, 2 - normals and binormals - u32 numtextures : 4; - u32 unused : 24; - }; - u32 hex; +union INVTXSPEC { + struct + { + u32 numcolors : 2; + u32 numnormals : 2; // 0 - nothing, 1 - just normal, 2 - normals and binormals + u32 numtextures : 4; + u32 unused : 24; + }; + u32 hex; }; -union TexMtxInfo -{ - struct - { - u32 unknown : 1; - u32 projection : 1; // XF_TEXPROJ_X - u32 inputform : 1; // XF_TEXINPUT_X - u32 unknown2 : 1; - u32 texgentype : 3; // XF_TEXGEN_X - u32 sourcerow : 5; // XF_SRCGEOM_X - u32 embosssourceshift : 3; // what generated texcoord to use - u32 embosslightshift : 3; // light index that is used - }; - u32 hex; +union TexMtxInfo { + struct + { + u32 unknown : 1; + u32 projection : 1; // XF_TEXPROJ_X + u32 inputform : 1; // XF_TEXINPUT_X + u32 unknown2 : 1; + u32 texgentype : 3; // XF_TEXGEN_X + u32 sourcerow : 5; // XF_SRCGEOM_X + u32 embosssourceshift : 3; // what generated texcoord to use + u32 embosslightshift : 3; // light index that is used + }; + u32 hex; }; -union PostMtxInfo -{ - struct - { - u32 index : 6; // base row of dual transform matrix - u32 unused : 2; - u32 normalize : 1; // normalize before send operation - }; - u32 hex; +union PostMtxInfo { + struct + { + u32 index : 6; // base row of dual transform matrix + u32 unused : 2; + u32 normalize : 1; // normalize before send operation + }; + u32 hex; }; -union NumColorChannel -{ - struct - { - u32 numColorChans : 2; - }; - u32 hex; +union NumColorChannel { + struct + { + u32 numColorChans : 2; + }; + u32 hex; }; -union NumTexGen -{ - struct - { - u32 numTexGens : 4; - }; - u32 hex; +union NumTexGen { + struct + { + u32 numTexGens : 4; + }; + u32 hex; }; -union DualTexInfo -{ - struct - { - u32 enabled : 1; - }; - u32 hex; +union DualTexInfo { + struct + { + u32 enabled : 1; + }; + u32 hex; }; - - struct Light { - u32 useless[3]; - u8 color[4]; - float cosatt[3]; // cos attenuation - float distatt[3]; // dist attenuation + u32 useless[3]; + u8 color[4]; + float cosatt[3]; // cos attenuation + float distatt[3]; // dist attenuation - union - { - struct - { - float dpos[3]; - float ddir[3]; // specular lights only - }; + union { + struct + { + float dpos[3]; + float ddir[3]; // specular lights only + }; - struct - { - float sdir[3]; - float shalfangle[3]; // specular lights only - }; - }; + struct + { + float sdir[3]; + float shalfangle[3]; // specular lights only + }; + }; }; struct Viewport { - float wd; - float ht; - float zRange; - float xOrig; - float yOrig; - float farZ; + float wd; + float ht; + float zRange; + float xOrig; + float yOrig; + float farZ; }; struct Projection { - float rawProjection[6]; - u32 type; // only GX_PERSPECTIVE or GX_ORTHOGRAPHIC are allowed + float rawProjection[6]; + u32 type; // only GX_PERSPECTIVE or GX_ORTHOGRAPHIC are allowed }; struct XFMemory { - float posMatrices[256]; // 0x0000 - 0x00ff - u32 unk0[768]; // 0x0100 - 0x03ff - float normalMatrices[96]; // 0x0400 - 0x045f - u32 unk1[160]; // 0x0460 - 0x04ff - float postMatrices[256]; // 0x0500 - 0x05ff - Light lights[8]; // 0x0600 - 0x067f - u32 unk2[2432]; // 0x0680 - 0x0fff - u32 error; // 0x1000 - u32 diag; // 0x1001 - u32 state0; // 0x1002 - u32 state1; // 0x1003 - u32 xfClock; // 0x1004 - u32 clipDisable; // 0x1005 - u32 perf0; // 0x1006 - u32 perf1; // 0x1007 - INVTXSPEC hostinfo; // 0x1008 number of textures,colors,normals from vertex input - NumColorChannel numChan; // 0x1009 - u32 ambColor[2]; // 0x100a, 0x100b - u32 matColor[2]; // 0x100c, 0x100d - LitChannel color[2]; // 0x100e, 0x100f - LitChannel alpha[2]; // 0x1010, 0x1011 - DualTexInfo dualTexTrans; // 0x1012 - u32 unk3; // 0x1013 - u32 unk4; // 0x1014 - u32 unk5; // 0x1015 - u32 unk6; // 0x1016 - u32 unk7; // 0x1017 - TMatrixIndexA MatrixIndexA; // 0x1018 - TMatrixIndexB MatrixIndexB; // 0x1019 - Viewport viewport; // 0x101a - 0x101f - Projection projection; // 0x1020 - 0x1026 - u32 unk8[24]; // 0x1027 - 0x103e - NumTexGen numTexGen; // 0x103f - TexMtxInfo texMtxInfo[8]; // 0x1040 - 0x1047 - u32 unk9[8]; // 0x1048 - 0x104f - PostMtxInfo postMtxInfo[8]; // 0x1050 - 0x1057 + float posMatrices[256]; // 0x0000 - 0x00ff + u32 unk0[768]; // 0x0100 - 0x03ff + float normalMatrices[96]; // 0x0400 - 0x045f + u32 unk1[160]; // 0x0460 - 0x04ff + float postMatrices[256]; // 0x0500 - 0x05ff + Light lights[8]; // 0x0600 - 0x067f + u32 unk2[2432]; // 0x0680 - 0x0fff + u32 error; // 0x1000 + u32 diag; // 0x1001 + u32 state0; // 0x1002 + u32 state1; // 0x1003 + u32 xfClock; // 0x1004 + u32 clipDisable; // 0x1005 + u32 perf0; // 0x1006 + u32 perf1; // 0x1007 + INVTXSPEC hostinfo; // 0x1008 number of textures,colors,normals from vertex input + NumColorChannel numChan; // 0x1009 + u32 ambColor[2]; // 0x100a, 0x100b + u32 matColor[2]; // 0x100c, 0x100d + LitChannel color[2]; // 0x100e, 0x100f + LitChannel alpha[2]; // 0x1010, 0x1011 + DualTexInfo dualTexTrans; // 0x1012 + u32 unk3; // 0x1013 + u32 unk4; // 0x1014 + u32 unk5; // 0x1015 + u32 unk6; // 0x1016 + u32 unk7; // 0x1017 + TMatrixIndexA MatrixIndexA; // 0x1018 + TMatrixIndexB MatrixIndexB; // 0x1019 + Viewport viewport; // 0x101a - 0x101f + Projection projection; // 0x1020 - 0x1026 + u32 unk8[24]; // 0x1027 - 0x103e + NumTexGen numTexGen; // 0x103f + TexMtxInfo texMtxInfo[8]; // 0x1040 - 0x1047 + u32 unk9[8]; // 0x1048 - 0x104f + PostMtxInfo postMtxInfo[8]; // 0x1050 - 0x1057 }; - extern XFMemory xfmem; void LoadXFReg(u32 transferSize, u32 address, DataReader src); diff --git a/Source/Core/VideoCommon/XFStructs.cpp b/Source/Core/VideoCommon/XFStructs.cpp index 964dc15355..3ade3ffbd2 100644 --- a/Source/Core/VideoCommon/XFStructs.cpp +++ b/Source/Core/VideoCommon/XFStructs.cpp @@ -17,280 +17,281 @@ static void XFMemWritten(u32 transferSize, u32 baseAddress) { - VertexManagerBase::Flush(); - VertexShaderManager::InvalidateXFRange(baseAddress, baseAddress + transferSize); + VertexManagerBase::Flush(); + VertexShaderManager::InvalidateXFRange(baseAddress, baseAddress + transferSize); } static void XFRegWritten(int transferSize, u32 baseAddress, DataReader src) { - u32 address = baseAddress; - u32 dataIndex = 0; + u32 address = baseAddress; + u32 dataIndex = 0; - while (transferSize > 0 && address < 0x1058) - { - u32 newValue = src.Peek(dataIndex * sizeof(u32)); - u32 nextAddress = address + 1; + while (transferSize > 0 && address < 0x1058) + { + u32 newValue = src.Peek(dataIndex * sizeof(u32)); + u32 nextAddress = address + 1; - switch (address) - { - case XFMEM_ERROR: - case XFMEM_DIAG: - case XFMEM_STATE0: // internal state 0 - case XFMEM_STATE1: // internal state 1 - case XFMEM_CLOCK: - case XFMEM_SETGPMETRIC: - nextAddress = 0x1007; - break; + switch (address) + { + case XFMEM_ERROR: + case XFMEM_DIAG: + case XFMEM_STATE0: // internal state 0 + case XFMEM_STATE1: // internal state 1 + case XFMEM_CLOCK: + case XFMEM_SETGPMETRIC: + nextAddress = 0x1007; + break; - case XFMEM_CLIPDISABLE: - //if (data & 1) {} // disable clipping detection - //if (data & 2) {} // disable trivial rejection - //if (data & 4) {} // disable cpoly clipping acceleration - break; + case XFMEM_CLIPDISABLE: + // if (data & 1) {} // disable clipping detection + // if (data & 2) {} // disable trivial rejection + // if (data & 4) {} // disable cpoly clipping acceleration + break; - case XFMEM_VTXSPECS: //__GXXfVtxSpecs, wrote 0004 - break; + case XFMEM_VTXSPECS: //__GXXfVtxSpecs, wrote 0004 + break; - case XFMEM_SETNUMCHAN: - if (xfmem.numChan.numColorChans != (newValue & 3)) - VertexManagerBase::Flush(); - break; + case XFMEM_SETNUMCHAN: + if (xfmem.numChan.numColorChans != (newValue & 3)) + VertexManagerBase::Flush(); + break; - case XFMEM_SETCHAN0_AMBCOLOR: // Channel Ambient Color - case XFMEM_SETCHAN1_AMBCOLOR: - { - u8 chan = address - XFMEM_SETCHAN0_AMBCOLOR; - if (xfmem.ambColor[chan] != newValue) - { - VertexManagerBase::Flush(); - VertexShaderManager::SetMaterialColorChanged(chan); - } - break; - } + case XFMEM_SETCHAN0_AMBCOLOR: // Channel Ambient Color + case XFMEM_SETCHAN1_AMBCOLOR: + { + u8 chan = address - XFMEM_SETCHAN0_AMBCOLOR; + if (xfmem.ambColor[chan] != newValue) + { + VertexManagerBase::Flush(); + VertexShaderManager::SetMaterialColorChanged(chan); + } + break; + } - case XFMEM_SETCHAN0_MATCOLOR: // Channel Material Color - case XFMEM_SETCHAN1_MATCOLOR: - { - u8 chan = address - XFMEM_SETCHAN0_MATCOLOR; - if (xfmem.matColor[chan] != newValue) - { - VertexManagerBase::Flush(); - VertexShaderManager::SetMaterialColorChanged(chan + 2); - } - break; - } + case XFMEM_SETCHAN0_MATCOLOR: // Channel Material Color + case XFMEM_SETCHAN1_MATCOLOR: + { + u8 chan = address - XFMEM_SETCHAN0_MATCOLOR; + if (xfmem.matColor[chan] != newValue) + { + VertexManagerBase::Flush(); + VertexShaderManager::SetMaterialColorChanged(chan + 2); + } + break; + } - case XFMEM_SETCHAN0_COLOR: // Channel Color - case XFMEM_SETCHAN1_COLOR: - case XFMEM_SETCHAN0_ALPHA: // Channel Alpha - case XFMEM_SETCHAN1_ALPHA: - if (((u32*)&xfmem)[address] != (newValue & 0x7fff)) - VertexManagerBase::Flush(); - break; + case XFMEM_SETCHAN0_COLOR: // Channel Color + case XFMEM_SETCHAN1_COLOR: + case XFMEM_SETCHAN0_ALPHA: // Channel Alpha + case XFMEM_SETCHAN1_ALPHA: + if (((u32*)&xfmem)[address] != (newValue & 0x7fff)) + VertexManagerBase::Flush(); + break; - case XFMEM_DUALTEX: - if (xfmem.dualTexTrans.enabled != (newValue & 1)) - VertexManagerBase::Flush(); - break; + case XFMEM_DUALTEX: + if (xfmem.dualTexTrans.enabled != (newValue & 1)) + VertexManagerBase::Flush(); + break; + case XFMEM_SETMATRIXINDA: + //_assert_msg_(GX_XF, 0, "XF matrixindex0"); + VertexShaderManager::SetTexMatrixChangedA(newValue); + break; + case XFMEM_SETMATRIXINDB: + //_assert_msg_(GX_XF, 0, "XF matrixindex1"); + VertexShaderManager::SetTexMatrixChangedB(newValue); + break; - case XFMEM_SETMATRIXINDA: - //_assert_msg_(GX_XF, 0, "XF matrixindex0"); - VertexShaderManager::SetTexMatrixChangedA(newValue); - break; - case XFMEM_SETMATRIXINDB: - //_assert_msg_(GX_XF, 0, "XF matrixindex1"); - VertexShaderManager::SetTexMatrixChangedB(newValue); - break; + case XFMEM_SETVIEWPORT: + case XFMEM_SETVIEWPORT + 1: + case XFMEM_SETVIEWPORT + 2: + case XFMEM_SETVIEWPORT + 3: + case XFMEM_SETVIEWPORT + 4: + case XFMEM_SETVIEWPORT + 5: + VertexManagerBase::Flush(); + VertexShaderManager::SetViewportChanged(); + PixelShaderManager::SetViewportChanged(); + GeometryShaderManager::SetViewportChanged(); - case XFMEM_SETVIEWPORT: - case XFMEM_SETVIEWPORT+1: - case XFMEM_SETVIEWPORT+2: - case XFMEM_SETVIEWPORT+3: - case XFMEM_SETVIEWPORT+4: - case XFMEM_SETVIEWPORT+5: - VertexManagerBase::Flush(); - VertexShaderManager::SetViewportChanged(); - PixelShaderManager::SetViewportChanged(); - GeometryShaderManager::SetViewportChanged(); + nextAddress = XFMEM_SETVIEWPORT + 6; + break; - nextAddress = XFMEM_SETVIEWPORT + 6; - break; + case XFMEM_SETPROJECTION: + case XFMEM_SETPROJECTION + 1: + case XFMEM_SETPROJECTION + 2: + case XFMEM_SETPROJECTION + 3: + case XFMEM_SETPROJECTION + 4: + case XFMEM_SETPROJECTION + 5: + case XFMEM_SETPROJECTION + 6: + VertexManagerBase::Flush(); + VertexShaderManager::SetProjectionChanged(); + GeometryShaderManager::SetProjectionChanged(); - case XFMEM_SETPROJECTION: - case XFMEM_SETPROJECTION+1: - case XFMEM_SETPROJECTION+2: - case XFMEM_SETPROJECTION+3: - case XFMEM_SETPROJECTION+4: - case XFMEM_SETPROJECTION+5: - case XFMEM_SETPROJECTION+6: - VertexManagerBase::Flush(); - VertexShaderManager::SetProjectionChanged(); - GeometryShaderManager::SetProjectionChanged(); + nextAddress = XFMEM_SETPROJECTION + 7; + break; - nextAddress = XFMEM_SETPROJECTION + 7; - break; + case XFMEM_SETNUMTEXGENS: // GXSetNumTexGens + if (xfmem.numTexGen.numTexGens != (newValue & 15)) + VertexManagerBase::Flush(); + break; - case XFMEM_SETNUMTEXGENS: // GXSetNumTexGens - if (xfmem.numTexGen.numTexGens != (newValue & 15)) - VertexManagerBase::Flush(); - break; + case XFMEM_SETTEXMTXINFO: + case XFMEM_SETTEXMTXINFO + 1: + case XFMEM_SETTEXMTXINFO + 2: + case XFMEM_SETTEXMTXINFO + 3: + case XFMEM_SETTEXMTXINFO + 4: + case XFMEM_SETTEXMTXINFO + 5: + case XFMEM_SETTEXMTXINFO + 6: + case XFMEM_SETTEXMTXINFO + 7: + VertexManagerBase::Flush(); - case XFMEM_SETTEXMTXINFO: - case XFMEM_SETTEXMTXINFO+1: - case XFMEM_SETTEXMTXINFO+2: - case XFMEM_SETTEXMTXINFO+3: - case XFMEM_SETTEXMTXINFO+4: - case XFMEM_SETTEXMTXINFO+5: - case XFMEM_SETTEXMTXINFO+6: - case XFMEM_SETTEXMTXINFO+7: - VertexManagerBase::Flush(); + nextAddress = XFMEM_SETTEXMTXINFO + 8; + break; - nextAddress = XFMEM_SETTEXMTXINFO + 8; - break; + case XFMEM_SETPOSMTXINFO: + case XFMEM_SETPOSMTXINFO + 1: + case XFMEM_SETPOSMTXINFO + 2: + case XFMEM_SETPOSMTXINFO + 3: + case XFMEM_SETPOSMTXINFO + 4: + case XFMEM_SETPOSMTXINFO + 5: + case XFMEM_SETPOSMTXINFO + 6: + case XFMEM_SETPOSMTXINFO + 7: + VertexManagerBase::Flush(); - case XFMEM_SETPOSMTXINFO: - case XFMEM_SETPOSMTXINFO+1: - case XFMEM_SETPOSMTXINFO+2: - case XFMEM_SETPOSMTXINFO+3: - case XFMEM_SETPOSMTXINFO+4: - case XFMEM_SETPOSMTXINFO+5: - case XFMEM_SETPOSMTXINFO+6: - case XFMEM_SETPOSMTXINFO+7: - VertexManagerBase::Flush(); + nextAddress = XFMEM_SETPOSMTXINFO + 8; + break; - nextAddress = XFMEM_SETPOSMTXINFO + 8; - break; + // -------------- + // Unknown Regs + // -------------- - // -------------- - // Unknown Regs - // -------------- + // Maybe these are for Normals? + case 0x1048: // xfmem.texcoords[0].nrmmtxinfo.hex = data; break; ?? + case 0x1049: + case 0x104a: + case 0x104b: + case 0x104c: + case 0x104d: + case 0x104e: + case 0x104f: + DEBUG_LOG(VIDEO, "Possible Normal Mtx XF reg?: %x=%x", address, newValue); + break; - // Maybe these are for Normals? - case 0x1048: //xfmem.texcoords[0].nrmmtxinfo.hex = data; break; ?? - case 0x1049: - case 0x104a: - case 0x104b: - case 0x104c: - case 0x104d: - case 0x104e: - case 0x104f: - DEBUG_LOG(VIDEO, "Possible Normal Mtx XF reg?: %x=%x", address, newValue); - break; + case 0x1013: + case 0x1014: + case 0x1015: + case 0x1016: + case 0x1017: - case 0x1013: - case 0x1014: - case 0x1015: - case 0x1016: - case 0x1017: + default: + if (newValue != 0) // Ignore writes of zero. + WARN_LOG(VIDEO, "Unknown XF Reg: %x=%x", address, newValue); + break; + } - default: - if (newValue != 0) // Ignore writes of zero. - WARN_LOG(VIDEO, "Unknown XF Reg: %x=%x", address, newValue); - break; - } + int transferred = nextAddress - address; + address = nextAddress; - int transferred = nextAddress - address; - address = nextAddress; - - transferSize -= transferred; - dataIndex += transferred; - } + transferSize -= transferred; + dataIndex += transferred; + } } void LoadXFReg(u32 transferSize, u32 baseAddress, DataReader src) { - // do not allow writes past registers - if (baseAddress + transferSize > 0x1058) - { - INFO_LOG(VIDEO, "XF load exceeds address space: %x %d bytes", baseAddress, transferSize); + // do not allow writes past registers + if (baseAddress + transferSize > 0x1058) + { + INFO_LOG(VIDEO, "XF load exceeds address space: %x %d bytes", baseAddress, transferSize); - if (baseAddress >= 0x1058) - transferSize = 0; - else - transferSize = 0x1058 - baseAddress; - } + if (baseAddress >= 0x1058) + transferSize = 0; + else + transferSize = 0x1058 - baseAddress; + } - // write to XF mem - if (baseAddress < 0x1000 && transferSize > 0) - { - u32 end = baseAddress + transferSize; + // write to XF mem + if (baseAddress < 0x1000 && transferSize > 0) + { + u32 end = baseAddress + transferSize; - u32 xfMemBase = baseAddress; - u32 xfMemTransferSize = transferSize; + u32 xfMemBase = baseAddress; + u32 xfMemTransferSize = transferSize; - if (end >= 0x1000) - { - xfMemTransferSize = 0x1000 - baseAddress; + if (end >= 0x1000) + { + xfMemTransferSize = 0x1000 - baseAddress; - baseAddress = 0x1000; - transferSize = end - 0x1000; - } - else - { - transferSize = 0; - } + baseAddress = 0x1000; + transferSize = end - 0x1000; + } + else + { + transferSize = 0; + } - XFMemWritten(xfMemTransferSize, xfMemBase); - for (u32 i = 0; i < xfMemTransferSize; i++) - { - ((u32*)&xfmem)[xfMemBase + i] = src.Read(); - } - } + XFMemWritten(xfMemTransferSize, xfMemBase); + for (u32 i = 0; i < xfMemTransferSize; i++) + { + ((u32*)&xfmem)[xfMemBase + i] = src.Read(); + } + } - // write to XF regs - if (transferSize > 0) - { - XFRegWritten(transferSize, baseAddress, src); - for (u32 i = 0; i < transferSize; i++) - { - ((u32*)&xfmem)[baseAddress + i] = src.Read(); - } - } + // write to XF regs + if (transferSize > 0) + { + XFRegWritten(transferSize, baseAddress, src); + for (u32 i = 0; i < transferSize; i++) + { + ((u32*)&xfmem)[baseAddress + i] = src.Read(); + } + } } // TODO - verify that it is correct. Seems to work, though. void LoadIndexedXF(u32 val, int refarray) { - int index = val >> 16; - int address = val & 0xFFF; // check mask - int size = ((val >> 12) & 0xF) + 1; - //load stuff from array to address in xf mem + int index = val >> 16; + int address = val & 0xFFF; // check mask + int size = ((val >> 12) & 0xF) + 1; + // load stuff from array to address in xf mem - u32* currData = (u32*)(&xfmem) + address; - u32* newData; - if (Fifo::UseDeterministicGPUThread()) - { - newData = (u32*)Fifo::PopFifoAuxBuffer(size * sizeof(u32)); - } - else - { - newData = (u32*)Memory::GetPointer(g_main_cp_state.array_bases[refarray] + g_main_cp_state.array_strides[refarray] * index); - } - bool changed = false; - for (int i = 0; i < size; ++i) - { - if (currData[i] != Common::swap32(newData[i])) - { - changed = true; - XFMemWritten(size, address); - break; - } - } - if (changed) - { - for (int i = 0; i < size; ++i) - currData[i] = Common::swap32(newData[i]); - } + u32* currData = (u32*)(&xfmem) + address; + u32* newData; + if (Fifo::UseDeterministicGPUThread()) + { + newData = (u32*)Fifo::PopFifoAuxBuffer(size * sizeof(u32)); + } + else + { + newData = (u32*)Memory::GetPointer(g_main_cp_state.array_bases[refarray] + + g_main_cp_state.array_strides[refarray] * index); + } + bool changed = false; + for (int i = 0; i < size; ++i) + { + if (currData[i] != Common::swap32(newData[i])) + { + changed = true; + XFMemWritten(size, address); + break; + } + } + if (changed) + { + for (int i = 0; i < size; ++i) + currData[i] = Common::swap32(newData[i]); + } } void PreprocessIndexedXF(u32 val, int refarray) { - int index = val >> 16; - int size = ((val >> 12) & 0xF) + 1; + int index = val >> 16; + int size = ((val >> 12) & 0xF) + 1; - u32* new_data = (u32*)Memory::GetPointer(g_preprocess_cp_state.array_bases[refarray] + g_preprocess_cp_state.array_strides[refarray] * index); + u32* new_data = (u32*)Memory::GetPointer(g_preprocess_cp_state.array_bases[refarray] + + g_preprocess_cp_state.array_strides[refarray] * index); - size_t buf_size = size * sizeof(u32); - Fifo::PushFifoAuxBuffer(new_data, buf_size); + size_t buf_size = size * sizeof(u32); + Fifo::PushFifoAuxBuffer(new_data, buf_size); } diff --git a/Source/DSPSpy/ConsoleHelper.h b/Source/DSPSpy/ConsoleHelper.h index 129adb401c..18ee8d458e 100644 --- a/Source/DSPSpy/ConsoleHelper.h +++ b/Source/DSPSpy/ConsoleHelper.h @@ -9,66 +9,65 @@ #include #include -#define CON_BLACK 0 -#define CON_RED 1 -#define CON_GREEN 2 -#define CON_YELLOW 3 -#define CON_BLUE 4 -#define CON_MAGENTA 5 -#define CON_CYAN 6 -#define CON_WHITE 7 -#define CON_BRIGHT 8 -#define CON_BRIGHT_BLACK CON_BLACK | CON_BRIGHT -#define CON_BRIGHT_RED CON_RED | CON_BRIGHT -#define CON_BRIGHT_GREEN CON_GREEN | CON_BRIGHT -#define CON_BRIGHT_YELLOW CON_YELLOW | CON_BRIGHT -#define CON_BRIGHT_BLUE CON_BLUE | CON_BRIGHT -#define CON_BRIGHT_MAGENTA CON_MAGENTA | CON_BRIGHT -#define CON_BRIGHT_CYAN CON_CYAN | CON_BRIGHT -#define CON_BRIGHT_WHITE CON_WHITE | CON_BRIGHT - +#define CON_BLACK 0 +#define CON_RED 1 +#define CON_GREEN 2 +#define CON_YELLOW 3 +#define CON_BLUE 4 +#define CON_MAGENTA 5 +#define CON_CYAN 6 +#define CON_WHITE 7 +#define CON_BRIGHT 8 +#define CON_BRIGHT_BLACK CON_BLACK | CON_BRIGHT +#define CON_BRIGHT_RED CON_RED | CON_BRIGHT +#define CON_BRIGHT_GREEN CON_GREEN | CON_BRIGHT +#define CON_BRIGHT_YELLOW CON_YELLOW | CON_BRIGHT +#define CON_BRIGHT_BLUE CON_BLUE | CON_BRIGHT +#define CON_BRIGHT_MAGENTA CON_MAGENTA | CON_BRIGHT +#define CON_BRIGHT_CYAN CON_CYAN | CON_BRIGHT +#define CON_BRIGHT_WHITE CON_WHITE | CON_BRIGHT inline void CON_Printf(const int x, const int y, const char* fmt, ...) { - char tmpbuf[255]; + char tmpbuf[255]; - va_list marker; - va_start(marker,fmt); - vsprintf(tmpbuf, fmt, marker); - va_end(marker); + va_list marker; + va_start(marker, fmt); + vsprintf(tmpbuf, fmt, marker); + va_end(marker); - printf("\x1b[%d;%dH%s", y, x, tmpbuf); + printf("\x1b[%d;%dH%s", y, x, tmpbuf); } inline void CON_SetColor(u8 foreground, u8 background = CON_BLACK) { - u8 bright = foreground & CON_BRIGHT ? 1 : 0; + u8 bright = foreground & CON_BRIGHT ? 1 : 0; - if (bright) - foreground &= ~CON_BRIGHT; + if (bright) + foreground &= ~CON_BRIGHT; - printf("\x1b[%d;%d;%dm", 30+foreground, bright, 40+background); + printf("\x1b[%d;%d;%dm", 30 + foreground, bright, 40 + background); } inline void CON_Clear() { - // Escape code to clear the whole screen. - printf("\x1b[2J"); + // Escape code to clear the whole screen. + printf("\x1b[2J"); } // libogc's clear escape codes are crappy inline void CON_BlankRow(const int y) { - int columns = 0, rows = 0; - CON_GetMetrics(&columns, &rows); - char blank[columns]; - std::fill(blank, blank + columns, ' '); - blank[columns-1] = '\0'; - CON_Printf(0, y, "%s", blank); + int columns = 0, rows = 0; + CON_GetMetrics(&columns, &rows); + char blank[columns]; + std::fill(blank, blank + columns, ' '); + blank[columns - 1] = '\0'; + CON_Printf(0, y, "%s", blank); } -#define CON_PrintRow(x, y, ...) \ -{ \ - CON_BlankRow(y); \ - CON_Printf(x, y, __VA_ARGS__); \ -} +#define CON_PrintRow(x, y, ...) \ + { \ + CON_BlankRow(y); \ + CON_Printf(x, y, __VA_ARGS__); \ + } diff --git a/Source/DSPSpy/Stubs.cpp b/Source/DSPSpy/Stubs.cpp index 83f1bc1444..0d5fd36d41 100644 --- a/Source/DSPSpy/Stubs.cpp +++ b/Source/DSPSpy/Stubs.cpp @@ -14,12 +14,12 @@ void *AllocateMemoryPages(size_t size) { - return malloc(size); + return malloc(size); } void FreeMemoryPages(void *pages, size_t size) { - free(pages); + free(pages); } void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) @@ -32,14 +32,14 @@ void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) bool DSPHost_OnThread() { - return false; + return false; } // Well, it's just RAM right? :) u8 DSPHost_ReadHostMemory(u32 address) { - u8 *ptr = (u8*)address; - return *ptr; + u8 *ptr = (u8*)address; + return *ptr; } void DSPHost_WriteHostMemory(u8 value, u32 addr) {} @@ -75,33 +75,33 @@ namespace File bool WriteStringToFile(bool text_file, const std::string &str, const char *filename) { - FILE *f = fopen(filename, text_file ? "w" : "wb"); - if (!f) - return false; - size_t len = str.size(); - if (len != fwrite(str.data(), 1, str.size(), f)) - { - fclose(f); - return false; - } - fclose(f); - return true; + FILE *f = fopen(filename, text_file ? "w" : "wb"); + if (!f) + return false; + size_t len = str.size(); + if (len != fwrite(str.data(), 1, str.size(), f)) + { + fclose(f); + return false; + } + fclose(f); + return true; } bool ReadFileToString(bool text_file, const char *filename, std::string &str) { - FILE *f = fopen(filename, text_file ? "r" : "rb"); - if (!f) - return false; - fseeko(f, 0, SEEK_END); - size_t len = ftello(f); - fseeko(f, 0, SEEK_SET); - char *buf = new char[len + 1]; - buf[fread(buf, 1, len, f)] = 0; - str = std::string(buf, len); - fclose(f); - delete [] buf; - return true; + FILE *f = fopen(filename, text_file ? "r" : "rb"); + if (!f) + return false; + fseeko(f, 0, SEEK_END); + size_t len = ftello(f); + fseeko(f, 0, SEEK_SET); + char *buf = new char[len + 1]; + buf[fread(buf, 1, len, f)] = 0; + str = std::string(buf, len); + fclose(f); + delete [] buf; + return true; } } diff --git a/Source/DSPSpy/dsp_interface.cpp b/Source/DSPSpy/dsp_interface.cpp index f960b6d6f0..f78acbcc87 100644 --- a/Source/DSPSpy/dsp_interface.cpp +++ b/Source/DSPSpy/dsp_interface.cpp @@ -4,32 +4,44 @@ #include "dsp_interface.h" -void IDSP::SendTask(void *addr, u16 iram_addr, u16 len, u16 start) +void IDSP::SendTask(void* addr, u16 iram_addr, u16 len, u16 start) { - // addr main ram addr 4byte aligned (1 Gekko word) - // iram_addr dsp addr 4byte aligned (2 DSP words) - // len block length in bytes multiple of 4 (wtf? if you want to fill whole iram, you need 8191) - // (8191 % 4 = 3) wtffff - // start dsp iram entry point - while (CheckMailTo()); - SendMailTo(0x80F3A001); - while (CheckMailTo()); - SendMailTo((u32)addr); - while (CheckMailTo()); - SendMailTo(0x80F3C002); - while (CheckMailTo()); - SendMailTo(iram_addr); - while (CheckMailTo()); - SendMailTo(0x80F3A002); - while (CheckMailTo()); - SendMailTo(len); - while (CheckMailTo()); - SendMailTo(0x80F3B002); - while (CheckMailTo()); - SendMailTo(0); - while (CheckMailTo()); - SendMailTo(0x80F3D001); - while (CheckMailTo()); - SendMailTo(start); - while (CheckMailTo()); + // addr main ram addr 4byte aligned (1 Gekko word) + // iram_addr dsp addr 4byte aligned (2 DSP words) + // len block length in bytes multiple of 4 (wtf? if you want to fill whole iram, you need + // 8191) + // (8191 % 4 = 3) wtffff + // start dsp iram entry point + while (CheckMailTo()) + ; + SendMailTo(0x80F3A001); + while (CheckMailTo()) + ; + SendMailTo((u32)addr); + while (CheckMailTo()) + ; + SendMailTo(0x80F3C002); + while (CheckMailTo()) + ; + SendMailTo(iram_addr); + while (CheckMailTo()) + ; + SendMailTo(0x80F3A002); + while (CheckMailTo()) + ; + SendMailTo(len); + while (CheckMailTo()) + ; + SendMailTo(0x80F3B002); + while (CheckMailTo()) + ; + SendMailTo(0); + while (CheckMailTo()) + ; + SendMailTo(0x80F3D001); + while (CheckMailTo()) + ; + SendMailTo(start); + while (CheckMailTo()) + ; } diff --git a/Source/DSPSpy/dsp_interface.h b/Source/DSPSpy/dsp_interface.h index 94d3e4404d..c0cbb48e06 100644 --- a/Source/DSPSpy/dsp_interface.h +++ b/Source/DSPSpy/dsp_interface.h @@ -7,28 +7,28 @@ #include // DSPCR bits -#define DSPCR_DSPRESET 0x0800 // Reset DSP -#define DSPCR_ARDMA 0x0200 // ARAM DMA in progress, if set -#define DSPCR_DSPINTMSK 0x0100 // * interrupt mask (RW) -#define DSPCR_DSPINT 0x0080 // * interrupt active (RWC) -#define DSPCR_ARINTMSK 0x0040 -#define DSPCR_ARINT 0x0020 -#define DSPCR_AIINTMSK 0x0010 -#define DSPCR_AIINT 0x0008 -#define DSPCR_HALT 0x0004 // halt DSP -#define DSPCR_PIINT 0x0002 // assert DSP PI interrupt -#define DSPCR_RES 0x0001 // reset DSP +#define DSPCR_DSPRESET 0x0800 // Reset DSP +#define DSPCR_ARDMA 0x0200 // ARAM DMA in progress, if set +#define DSPCR_DSPINTMSK 0x0100 // * interrupt mask (RW) +#define DSPCR_DSPINT 0x0080 // * interrupt active (RWC) +#define DSPCR_ARINTMSK 0x0040 +#define DSPCR_ARINT 0x0020 +#define DSPCR_AIINTMSK 0x0010 +#define DSPCR_AIINT 0x0008 +#define DSPCR_HALT 0x0004 // halt DSP +#define DSPCR_PIINT 0x0002 // assert DSP PI interrupt +#define DSPCR_RES 0x0001 // reset DSP -class IDSP { +class IDSP +{ public: - virtual ~IDSP() {} + virtual ~IDSP() {} + virtual void Init() = 0; + virtual void Reset() = 0; + virtual u32 CheckMailTo() = 0; + virtual void SendMailTo(u32 mail) = 0; - virtual void Init() = 0; - virtual void Reset() = 0; - virtual u32 CheckMailTo() = 0; - virtual void SendMailTo(u32 mail) = 0; - - // Yeah, yeah, having a method here makes this not a pure interface - but - // the implementation does nothing but calling the virtual methods above. - void SendTask(void *addr, u16 iram_addr, u16 len, u16 start); + // Yeah, yeah, having a method here makes this not a pure interface - but + // the implementation does nothing but calling the virtual methods above. + void SendTask(void* addr, u16 iram_addr, u16 len, u16 start); }; diff --git a/Source/DSPSpy/dspregs.h b/Source/DSPSpy/dspregs.h index bcaf099c52..af98b27421 100644 --- a/Source/DSPSpy/dspregs.h +++ b/Source/DSPSpy/dspregs.h @@ -4,45 +4,46 @@ #pragma once -#define DSP_REG_AR0 0x00 // address registers -#define DSP_REG_AR1 0x01 -#define DSP_REG_AR2 0x02 -#define DSP_REG_AR3 0x03 +#define DSP_REG_AR0 0x00 // address registers +#define DSP_REG_AR1 0x01 +#define DSP_REG_AR2 0x02 +#define DSP_REG_AR3 0x03 -#define DSP_REG_IX0 0x04 // indexing registers (actually, mostly used as increments) -#define DSP_REG_IX1 0x05 -#define DSP_REG_IX2 0x06 -#define DSP_REG_IX3 0x07 +#define DSP_REG_IX0 0x04 // indexing registers (actually, mostly used as increments) +#define DSP_REG_IX1 0x05 +#define DSP_REG_IX2 0x06 +#define DSP_REG_IX3 0x07 -#define DSP_REG_WR0 0x08 // address wrapping registers. should be initialized to 0xFFFF if not used. -#define DSP_REG_WR1 0x09 -#define DSP_REG_WR2 0x0a -#define DSP_REG_WR3 0x0b +#define DSP_REG_WR0 \ + 0x08 // address wrapping registers. should be initialized to 0xFFFF if not used. +#define DSP_REG_WR1 0x09 +#define DSP_REG_WR2 0x0a +#define DSP_REG_WR3 0x0b -#define DSP_REG_ST0 0x0c // stacks. -#define DSP_REG_ST1 0x0d -#define DSP_REG_ST2 0x0e -#define DSP_REG_ST3 0x0f +#define DSP_REG_ST0 0x0c // stacks. +#define DSP_REG_ST1 0x0d +#define DSP_REG_ST2 0x0e +#define DSP_REG_ST3 0x0f -#define DSP_REG_CR 0x12 // Seems to be the top 8 bits of LRS/SRS. -#define DSP_REG_SR 0x13 +#define DSP_REG_CR 0x12 // Seems to be the top 8 bits of LRS/SRS. +#define DSP_REG_SR 0x13 -#define DSP_REG_PRODL 0x14 // product. -#define DSP_REG_PRODM 0x15 -#define DSP_REG_PRODH 0x16 -#define DSP_REG_PRODM2 0x17 +#define DSP_REG_PRODL 0x14 // product. +#define DSP_REG_PRODM 0x15 +#define DSP_REG_PRODH 0x16 +#define DSP_REG_PRODM2 0x17 -#define DSP_REG_AXL0 0x18 -#define DSP_REG_AXL1 0x19 -#define DSP_REG_AXH0 0x1a -#define DSP_REG_AXH1 0x1b +#define DSP_REG_AXL0 0x18 +#define DSP_REG_AXL1 0x19 +#define DSP_REG_AXH0 0x1a +#define DSP_REG_AXH1 0x1b -#define DSP_REG_ACC0 0x1c // accumulator (global) -#define DSP_REG_ACC1 0x1d +#define DSP_REG_ACC0 0x1c // accumulator (global) +#define DSP_REG_ACC1 0x1d -#define DSP_REG_ACL0 0x1c // Low accumulator -#define DSP_REG_ACL1 0x1d -#define DSP_REG_ACM0 0x1e // Mid accumulator -#define DSP_REG_ACM1 0x1f -#define DSP_REG_ACH0 0x10 // Sign extended 8 bit register 0 -#define DSP_REG_ACH1 0x11 // Sign extended 8 bit register 1 +#define DSP_REG_ACL0 0x1c // Low accumulator +#define DSP_REG_ACL1 0x1d +#define DSP_REG_ACM0 0x1e // Mid accumulator +#define DSP_REG_ACM1 0x1f +#define DSP_REG_ACH0 0x10 // Sign extended 8 bit register 0 +#define DSP_REG_ACH1 0x11 // Sign extended 8 bit register 1 diff --git a/Source/DSPSpy/main_spy.cpp b/Source/DSPSpy/main_spy.cpp index b19e7afe16..10516dc252 100644 --- a/Source/DSPSpy/main_spy.cpp +++ b/Source/DSPSpy/main_spy.cpp @@ -21,18 +21,18 @@ #include #include -#include #include #include +#include #ifdef _MSC_VER // Just for easy looking :) -#define HW_RVL //HW_DOL +#define HW_RVL // HW_DOL #endif #ifdef HW_RVL -#include #include +#include #else #include #endif @@ -51,24 +51,23 @@ // #include "virtual_dsp.h" // Used for communications with the DSP, such as dumping registers etc. -u16 dspbuffer[16 * 1024] __attribute__ ((aligned (0x4000))); +u16 dspbuffer[16 * 1024] __attribute__((aligned(0x4000))); -static void *xfb = nullptr; -void (*reboot)() = (void(*)())0x80001800; -GXRModeObj *rmode; +static void* xfb = nullptr; +void (*reboot)() = (void (*)())0x80001800; +GXRModeObj* rmode; static vu16* const _dspReg = (u16*)0xCC005000; -u16 *dspbufP; -u16 *dspbufC; -u32 *dspbufU; +u16* dspbufP; +u16* dspbufC; +u32* dspbufU; u16 dspreg_in[32] = { - 0x0410, 0x0510, 0x0610, 0x0710, 0x0810, 0x0910, 0x0a10, 0x0b10, - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0855, 0x0966, 0x0a77, 0x0b88, - 0x0014, 0xfff5, 0x00ff, 0x2200, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0003, 0x0004, 0x8000, 0x000C, 0x0007, 0x0008, 0x0009, 0x000a, -}; /// ax_h_1 ax_h_1 + 0x0410, 0x0510, 0x0610, 0x0710, 0x0810, 0x0910, 0x0a10, 0x0b10, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0x0855, 0x0966, 0x0a77, 0x0b88, 0x0014, 0xfff5, 0x00ff, 0x2200, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0003, 0x0004, 0x8000, 0x000C, 0x0007, 0x0008, 0x0009, 0x000a, +}; /// ax_h_1 ax_h_1 /* ttt ? @@ -85,7 +84,8 @@ u16 dspreg_in[32] = { // zelda 0x00da u16 dspreg_in[32] = { 0x0a50, 0x0ca2, 0x04f8, 0x0ab0, 0x8039, 0x0000, 0x0000, 0x0000, -0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x03d1, 0x0000, 0x0418, 0x0002, // r08 must have a value ... no idea why (ector: it's the looped addressing regs) +0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x03d1, 0x0000, 0x0418, 0x0002, // r08 must have a value ... no +idea why (ector: it's the looped addressing regs) 0x0000, 0x0000, 0x00ff, 0x1804, 0xdb70, 0x4ddb, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xde6d, 0x0000, 0x0000, 0x0000, 0x004e, };*/ @@ -95,31 +95,32 @@ u16 dspreg_out[1000][32]; /* // gba ucode dmas result here u32 SecParams_out[2] __attribute__ ((aligned (0x20))) = { - 0x11223344, // key - 0x55667788 // bootinfo + 0x11223344, // key + 0x55667788 // bootinfo }; // ripped from demo u32 SecParams_in[8] __attribute__ ((aligned (0x20))) = { - 0xDB967E0F, // key from gba - 0x00000002, - 0x00000002, - 0x00001078, - (u32)SecParams_out, //0x80075060, // ptr to receiving buffer - // padding? - 0x00000000, - 0x00000000, - 0x00000000 + 0xDB967E0F, // key from gba + 0x00000002, + 0x00000002, + 0x00001078, + (u32)SecParams_out, //0x80075060, // ptr to receiving buffer + // padding? + 0x00000000, + 0x00000000, + 0x00000000 }; */ // UI (interactive register editing) u32 ui_mode; -enum { - UIM_SEL = 1, - UIM_EDIT_REG = 2, - UIM_EDIT_BIN = 4, +enum +{ + UIM_SEL = 1, + UIM_EDIT_REG = 2, + UIM_EDIT_BIN = 4, }; // Currently selected register. @@ -127,7 +128,7 @@ s32 cursor_reg = 0; // Currently selected digit. s32 small_cursor_x; // Value currently being edited. -u16 *reg_value; +u16* reg_value; RealDSP real_dsp; @@ -136,598 +137,618 @@ int curUcode = 0, runningUcode = 1; int dsp_steps = 0; - // When comparing regs, ignore the loop stack registers. bool regs_equal(int reg, u16 value1, u16 value2) { - if (reg >= DSP_REG_ST0 && reg <= DSP_REG_ST3) - return true; - else - return value1 == value2; + if (reg >= DSP_REG_ST0 && reg <= DSP_REG_ST3) + return true; + else + return value1 == value2; } -void print_reg_block(int x, int y, int sel, const u16 *regs, const u16 *compare_regs) +void print_reg_block(int x, int y, int sel, const u16* regs, const u16* compare_regs) { - for (int j = 0; j < 4 ; j++) - { - for (int i = 0; i < 8 ; i++) - { - // Do not even display the loop stack registers. - const int reg = j * 8 + i; - CON_SetColor(sel == reg ? CON_BRIGHT_YELLOW : CON_GREEN); - CON_Printf(x + j * 8, i + y, "%02x ", reg); - if (j != 1 || i < 4) - { - u8 color1 = regs_equal(reg, regs[reg], compare_regs[reg]) ? CON_BRIGHT_WHITE : CON_BRIGHT_RED; - for (int k = 0; k < 4; k++) - { - if (sel == reg && k == small_cursor_x && ui_mode == UIM_EDIT_REG) - CON_SetColor(CON_BRIGHT_CYAN); - else - CON_SetColor(color1); - CON_Printf(x + 3 + j * 8 + k, i + y, "%01x", (regs[reg] >> ((3 - k) * 4)) & 0xf); - } - } - } - } - CON_SetColor(CON_WHITE); + for (int j = 0; j < 4; j++) + { + for (int i = 0; i < 8; i++) + { + // Do not even display the loop stack registers. + const int reg = j * 8 + i; + CON_SetColor(sel == reg ? CON_BRIGHT_YELLOW : CON_GREEN); + CON_Printf(x + j * 8, i + y, "%02x ", reg); + if (j != 1 || i < 4) + { + u8 color1 = + regs_equal(reg, regs[reg], compare_regs[reg]) ? CON_BRIGHT_WHITE : CON_BRIGHT_RED; + for (int k = 0; k < 4; k++) + { + if (sel == reg && k == small_cursor_x && ui_mode == UIM_EDIT_REG) + CON_SetColor(CON_BRIGHT_CYAN); + else + CON_SetColor(color1); + CON_Printf(x + 3 + j * 8 + k, i + y, "%01x", (regs[reg] >> ((3 - k) * 4)) & 0xf); + } + } + } + } + CON_SetColor(CON_WHITE); - CON_Printf(x+2, y+9, "ACC0: %02x %04x %04x", regs[DSP_REG_ACH0]&0xff, regs[DSP_REG_ACM0], regs[DSP_REG_ACL0]); - CON_Printf(x+2, y+10, "ACC1: %02x %04x %04x", regs[DSP_REG_ACH1]&0xff, regs[DSP_REG_ACM1], regs[DSP_REG_ACL1]); - CON_Printf(x+2, y+11, "AX0: %04x %04x", regs[DSP_REG_AXH0], regs[DSP_REG_AXL0]); - CON_Printf(x+2, y+12, "AX1: %04x %04x", regs[DSP_REG_AXH1], regs[DSP_REG_AXL1]); + CON_Printf(x + 2, y + 9, "ACC0: %02x %04x %04x", regs[DSP_REG_ACH0] & 0xff, regs[DSP_REG_ACM0], + regs[DSP_REG_ACL0]); + CON_Printf(x + 2, y + 10, "ACC1: %02x %04x %04x", regs[DSP_REG_ACH1] & 0xff, regs[DSP_REG_ACM1], + regs[DSP_REG_ACL1]); + CON_Printf(x + 2, y + 11, "AX0: %04x %04x", regs[DSP_REG_AXH0], regs[DSP_REG_AXL0]); + CON_Printf(x + 2, y + 12, "AX1: %04x %04x", regs[DSP_REG_AXH1], regs[DSP_REG_AXL1]); } void print_regs(int _step, int _dsp_steps) { - const u16 *regs = _step == 0 ? dspreg_in : dspreg_out[_step - 1]; - const u16 *regs2 = dspreg_out[_step]; + const u16* regs = _step == 0 ? dspreg_in : dspreg_out[_step - 1]; + const u16* regs2 = dspreg_out[_step]; - print_reg_block(0, 2, _step == 0 ? cursor_reg : -1, regs, regs2); - print_reg_block(33, 2, -1, regs2, regs); + print_reg_block(0, 2, _step == 0 ? cursor_reg : -1, regs, regs2); + print_reg_block(33, 2, -1, regs2, regs); - CON_SetColor(CON_WHITE); - CON_Printf(33, 17, "%i / %i ", _step + 1, _dsp_steps); + CON_SetColor(CON_WHITE); + CON_Printf(33, 17, "%i / %i ", _step + 1, _dsp_steps); - return; + return; - static int count = 0; - int x = 0, y = 16; - if (count > 2) - CON_Clear(); - count = 0; - CON_SetColor(CON_WHITE); - for (int i = 0x0; i < 0xf70 ; i++) - { - if (dspbufC[i] != mem_dump[i]) - { - CON_Printf(x, y, "%04x=%04x", i, dspbufC[i]); - count++; - x += 10; - if (x >= 60) { - x = 0; - y++; - } - } - } - CON_Printf(4, 25, "%08x", count); + static int count = 0; + int x = 0, y = 16; + if (count > 2) + CON_Clear(); + count = 0; + CON_SetColor(CON_WHITE); + for (int i = 0x0; i < 0xf70; i++) + { + if (dspbufC[i] != mem_dump[i]) + { + CON_Printf(x, y, "%04x=%04x", i, dspbufC[i]); + count++; + x += 10; + if (x >= 60) + { + x = 0; + y++; + } + } + } + CON_Printf(4, 25, "%08x", count); } void UpdateLastMessage(const char* msg) { - CON_PrintRow(4, 24, msg); + CON_PrintRow(4, 24, msg); } void DumpDSP_ROMs(const u16* rom, const u16* coef) { - char filename[260] = {0}; - sprintf(filename, "sd:/dsp_rom.bin"); - FILE *fROM = fopen(filename, "wb"); - sprintf(filename, "sd:/dsp_coef.bin"); - FILE *fCOEF = fopen(filename, "wb"); + char filename[260] = {0}; + sprintf(filename, "sd:/dsp_rom.bin"); + FILE* fROM = fopen(filename, "wb"); + sprintf(filename, "sd:/dsp_coef.bin"); + FILE* fCOEF = fopen(filename, "wb"); - if (fROM && fCOEF) - { - fwrite(MEM_PHYSICAL_TO_K0(rom), 0x2000, 1, fROM); - fwrite(MEM_PHYSICAL_TO_K0(coef), 0x1000, 1, fCOEF); + if (fROM && fCOEF) + { + fwrite(MEM_PHYSICAL_TO_K0(rom), 0x2000, 1, fROM); + fwrite(MEM_PHYSICAL_TO_K0(coef), 0x1000, 1, fCOEF); - UpdateLastMessage("DSP ROMs dumped to SD"); - } - else - { - UpdateLastMessage("SD Write Error"); - } + UpdateLastMessage("DSP ROMs dumped to SD"); + } + else + { + UpdateLastMessage("SD Write Error"); + } - if (fROM) - fclose(fROM); - if (fCOEF) - fclose(fCOEF); + if (fROM) + fclose(fROM); + if (fCOEF) + fclose(fCOEF); } void ui_pad_sel(void) { #ifdef HW_RVL - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_RIGHT) - cursor_reg += 8; - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_LEFT) - cursor_reg -= 8; - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_UP) - cursor_reg--; - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_DOWN) - cursor_reg++; - cursor_reg &= 0x1f; - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A) - { - ui_mode = UIM_EDIT_REG; - reg_value = &dspreg_in[cursor_reg]; - } + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_RIGHT) + cursor_reg += 8; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_LEFT) + cursor_reg -= 8; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_UP) + cursor_reg--; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_DOWN) + cursor_reg++; + cursor_reg &= 0x1f; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A) + { + ui_mode = UIM_EDIT_REG; + reg_value = &dspreg_in[cursor_reg]; + } #else - if (PAD_ButtonsDown(0) & PAD_BUTTON_RIGHT) - cursor_reg += 8; - if (PAD_ButtonsDown(0) & PAD_BUTTON_LEFT) - cursor_reg -= 8; - if (PAD_ButtonsDown(0) & PAD_BUTTON_UP) - cursor_reg--; - if (PAD_ButtonsDown(0) & PAD_BUTTON_DOWN) - cursor_reg++; - cursor_reg &= 0x1f; - if (PAD_ButtonsDown(0) & PAD_BUTTON_A) - { - ui_mode = UIM_EDIT_REG; - reg_value = &dspreg_in[cursor_reg]; - } + if (PAD_ButtonsDown(0) & PAD_BUTTON_RIGHT) + cursor_reg += 8; + if (PAD_ButtonsDown(0) & PAD_BUTTON_LEFT) + cursor_reg -= 8; + if (PAD_ButtonsDown(0) & PAD_BUTTON_UP) + cursor_reg--; + if (PAD_ButtonsDown(0) & PAD_BUTTON_DOWN) + cursor_reg++; + cursor_reg &= 0x1f; + if (PAD_ButtonsDown(0) & PAD_BUTTON_A) + { + ui_mode = UIM_EDIT_REG; + reg_value = &dspreg_in[cursor_reg]; + } #endif } void ui_pad_edit_reg(void) { #ifdef HW_RVL - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_RIGHT) - small_cursor_x++; - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_LEFT) - small_cursor_x--; - small_cursor_x &= 0x3; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_RIGHT) + small_cursor_x++; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_LEFT) + small_cursor_x--; + small_cursor_x &= 0x3; - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_UP) - *reg_value += 0x1 << (4 * (3 - small_cursor_x)); - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_DOWN) - *reg_value -= 0x1 << (4 * (3 - small_cursor_x)); - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A) - ui_mode = UIM_SEL; - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_1) - *reg_value = 0; - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_2) - *reg_value = 0xffff; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_UP) + *reg_value += 0x1 << (4 * (3 - small_cursor_x)); + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_DOWN) + *reg_value -= 0x1 << (4 * (3 - small_cursor_x)); + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A) + ui_mode = UIM_SEL; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_1) + *reg_value = 0; + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_2) + *reg_value = 0xffff; #else - if (PAD_ButtonsDown(0) & PAD_BUTTON_RIGHT) - small_cursor_x++; - if (PAD_ButtonsDown(0) & PAD_BUTTON_LEFT) - small_cursor_x--; - small_cursor_x &= 0x3; + if (PAD_ButtonsDown(0) & PAD_BUTTON_RIGHT) + small_cursor_x++; + if (PAD_ButtonsDown(0) & PAD_BUTTON_LEFT) + small_cursor_x--; + small_cursor_x &= 0x3; - if (PAD_ButtonsDown(0) & PAD_BUTTON_UP) - *reg_value += 0x1 << (4 * (3 - small_cursor_x)); - if (PAD_ButtonsDown(0) & PAD_BUTTON_DOWN) - *reg_value -= 0x1 << (4 * (3 - small_cursor_x)); - if (PAD_ButtonsDown(0) & PAD_BUTTON_A) - ui_mode = UIM_SEL; - if (PAD_ButtonsDown(0) & PAD_BUTTON_X) - *reg_value = 0; - if (PAD_ButtonsDown(0) & PAD_BUTTON_Y) - *reg_value = 0xffff; + if (PAD_ButtonsDown(0) & PAD_BUTTON_UP) + *reg_value += 0x1 << (4 * (3 - small_cursor_x)); + if (PAD_ButtonsDown(0) & PAD_BUTTON_DOWN) + *reg_value -= 0x1 << (4 * (3 - small_cursor_x)); + if (PAD_ButtonsDown(0) & PAD_BUTTON_A) + ui_mode = UIM_SEL; + if (PAD_ButtonsDown(0) & PAD_BUTTON_X) + *reg_value = 0; + if (PAD_ButtonsDown(0) & PAD_BUTTON_Y) + *reg_value = 0xffff; #endif } void handle_dsp_mail(void) { - // Should put a loop around this too. - if (DSP_CheckMailFrom()) - { - u32 mail = DSP_ReadMailFrom(); + // Should put a loop around this too. + if (DSP_CheckMailFrom()) + { + u32 mail = DSP_ReadMailFrom(); - if (mail == 0x8071feed) - { - // DSP ready for task. Let's send one. - // First, prepare data. - for (int n = 0 ; n < 32 ; n++) - dspbufC[0x00 + n] = dspreg_in[n]; - DCFlushRange(dspbufC, 0x2000); - // Then send the code. - DCFlushRange((void *)dsp_code[curUcode], 0x2000); - // DMA ucode to iram base, entry point is just after exception vectors...0x10 - // NOTE: for any ucode made by dsptool, the block length will be 8191 - real_dsp.SendTask((void *)MEM_VIRTUAL_TO_PHYSICAL(dsp_code[curUcode]), 0, sizeof(dsp_code[curUcode])-1, 0x10); + if (mail == 0x8071feed) + { + // DSP ready for task. Let's send one. + // First, prepare data. + for (int n = 0; n < 32; n++) + dspbufC[0x00 + n] = dspreg_in[n]; + DCFlushRange(dspbufC, 0x2000); + // Then send the code. + DCFlushRange((void*)dsp_code[curUcode], 0x2000); + // DMA ucode to iram base, entry point is just after exception vectors...0x10 + // NOTE: for any ucode made by dsptool, the block length will be 8191 + real_dsp.SendTask((void*)MEM_VIRTUAL_TO_PHYSICAL(dsp_code[curUcode]), 0, + sizeof(dsp_code[curUcode]) - 1, 0x10); - runningUcode = curUcode + 1; + runningUcode = curUcode + 1; - // Clear exception status since we've loaded a new ucode - CON_BlankRow(25); - } - else if ((mail & 0xffff0000) == 0x8bad0000) - { - // dsp_base.inc is reporting an exception happened - CON_PrintRow(4, 25, "%s caused exception %x at step %i", UCODE_NAMES[curUcode], mail & 0xff, dsp_steps); - } - else if (mail == 0x8888dead) - { - // Send memory dump (DSP DRAM from someone's GameCube?) - // not really sure why this is important - I guess just to try to keep tests predictable - u16* tmpBuf = (u16 *)MEM_VIRTUAL_TO_PHYSICAL(mem_dump); + // Clear exception status since we've loaded a new ucode + CON_BlankRow(25); + } + else if ((mail & 0xffff0000) == 0x8bad0000) + { + // dsp_base.inc is reporting an exception happened + CON_PrintRow(4, 25, "%s caused exception %x at step %i", UCODE_NAMES[curUcode], mail & 0xff, + dsp_steps); + } + else if (mail == 0x8888dead) + { + // Send memory dump (DSP DRAM from someone's GameCube?) + // not really sure why this is important - I guess just to try to keep tests predictable + u16* tmpBuf = (u16*)MEM_VIRTUAL_TO_PHYSICAL(mem_dump); - while (real_dsp.CheckMailTo()); - real_dsp.SendMailTo((u32)tmpBuf); - while (real_dsp.CheckMailTo()); - } - else if (mail == 0x8888beef) - { - // Provide register base to DSP (if using dsp_base.inc, it will DMA them to the correct place) - while (real_dsp.CheckMailTo()); - real_dsp.SendMailTo((u32)dspbufP); - while (real_dsp.CheckMailTo()); - } - else if (mail == 0x8888feeb) - { - // We got a stepful of registers. - DCInvalidateRange(dspbufC, 0x2000); - for (int i = 0 ; i < 32 ; i++) - dspreg_out[dsp_steps][i] = dspbufC[0xf80 + i]; + while (real_dsp.CheckMailTo()) + ; + real_dsp.SendMailTo((u32)tmpBuf); + while (real_dsp.CheckMailTo()) + ; + } + else if (mail == 0x8888beef) + { + // Provide register base to DSP (if using dsp_base.inc, it will DMA them to the correct place) + while (real_dsp.CheckMailTo()) + ; + real_dsp.SendMailTo((u32)dspbufP); + while (real_dsp.CheckMailTo()) + ; + } + else if (mail == 0x8888feeb) + { + // We got a stepful of registers. + DCInvalidateRange(dspbufC, 0x2000); + for (int i = 0; i < 32; i++) + dspreg_out[dsp_steps][i] = dspbufC[0xf80 + i]; - dsp_steps++; + dsp_steps++; - while (real_dsp.CheckMailTo()); - real_dsp.SendMailTo(0x8000dead); - while (real_dsp.CheckMailTo()); - } + while (real_dsp.CheckMailTo()) + ; + real_dsp.SendMailTo(0x8000dead); + while (real_dsp.CheckMailTo()) + ; + } - // ROM dumping mails - else if (mail == 0x8888c0de) - { - // DSP has copied irom to its DRAM...send address so it can dma it back - while (real_dsp.CheckMailTo()); - real_dsp.SendMailTo((u32)dspbufP); - while (real_dsp.CheckMailTo()); - } - else if (mail == 0x8888da7a) - { - // DSP has copied coef to its DRAM...send address so it can DMA it back - while (real_dsp.CheckMailTo()); - real_dsp.SendMailTo((u32)&dspbufP[0x1000]); - while (real_dsp.CheckMailTo()); + // ROM dumping mails + else if (mail == 0x8888c0de) + { + // DSP has copied irom to its DRAM...send address so it can dma it back + while (real_dsp.CheckMailTo()) + ; + real_dsp.SendMailTo((u32)dspbufP); + while (real_dsp.CheckMailTo()) + ; + } + else if (mail == 0x8888da7a) + { + // DSP has copied coef to its DRAM...send address so it can DMA it back + while (real_dsp.CheckMailTo()) + ; + real_dsp.SendMailTo((u32)&dspbufP[0x1000]); + while (real_dsp.CheckMailTo()) + ; - // Now we can do something useful with the buffer :) - DumpDSP_ROMs(dspbufP, &dspbufP[0x1000]); - } + // Now we can do something useful with the buffer :) + DumpDSP_ROMs(dspbufP, &dspbufP[0x1000]); + } - // SDK status mails - /* - // GBA ucode - else if (mail == 0xdcd10000) // DSP_INIT - { - real_dsp.SendMailTo(0xabba0000); - while (real_dsp.CheckMailTo()); - DCFlushRange(SecParams_in, sizeof(SecParams_in)); - CON_PrintRow(4, 25, "SecParams_out = %x", SecParams_in[4]); - real_dsp.SendMailTo((u32)SecParams_in); - while (real_dsp.CheckMailTo()); - } - else if (mail == 0xdcd10003) // DSP_DONE - { - real_dsp.SendMailTo(0xcdd1babe); // custom mail to tell DSP to halt (calls end_of_test) - while (real_dsp.CheckMailTo()); + // SDK status mails + /* + // GBA ucode + else if (mail == 0xdcd10000) // DSP_INIT + { + real_dsp.SendMailTo(0xabba0000); + while (real_dsp.CheckMailTo()); + DCFlushRange(SecParams_in, sizeof(SecParams_in)); + CON_PrintRow(4, 25, "SecParams_out = %x", SecParams_in[4]); + real_dsp.SendMailTo((u32)SecParams_in); + while (real_dsp.CheckMailTo()); + } + else if (mail == 0xdcd10003) // DSP_DONE + { + real_dsp.SendMailTo(0xcdd1babe); // custom mail to tell DSP to halt (calls end_of_test) + while (real_dsp.CheckMailTo()); - DCInvalidateRange(SecParams_out, sizeof(SecParams_out)); - CON_PrintRow(4, 26, "SecParams_out: %08x %08x", - SecParams_out[0], SecParams_out[1]); - } - */ + DCInvalidateRange(SecParams_out, sizeof(SecParams_out)); + CON_PrintRow(4, 26, "SecParams_out: %08x %08x", + SecParams_out[0], SecParams_out[1]); + } + */ - CON_PrintRow(2, 1, "UCode: %d/%d %s, Last mail: %08x", - curUcode + 1, NUM_UCODES, UCODE_NAMES[curUcode], mail); - } + CON_PrintRow(2, 1, "UCode: %d/%d %s, Last mail: %08x", curUcode + 1, NUM_UCODES, + UCODE_NAMES[curUcode], mail); + } } void dump_all_ucodes(bool fastmode) { - char filename[260] = {0}; - char temp[100]; - u32 written; + char filename[260] = {0}; + char temp[100]; + u32 written; - sprintf(filename, "sd:/dsp_dump_all.bin"); - FILE *f2 = fopen(filename, "wb"); - fclose(f2); + sprintf(filename, "sd:/dsp_dump_all.bin"); + FILE* f2 = fopen(filename, "wb"); + fclose(f2); - for (int UCodeToDump = 0; UCodeToDump < NUM_UCODES; UCodeToDump++) - { - // First, change the microcode - dsp_steps = 0; - curUcode = UCodeToDump; - runningUcode = 0; + for (int UCodeToDump = 0; UCodeToDump < NUM_UCODES; UCodeToDump++) + { + // First, change the microcode + dsp_steps = 0; + curUcode = UCodeToDump; + runningUcode = 0; - DCInvalidateRange(dspbufC, 0x2000); - DCFlushRange(dspbufC, 0x2000); + DCInvalidateRange(dspbufC, 0x2000); + DCFlushRange(dspbufC, 0x2000); - real_dsp.Reset(); + real_dsp.Reset(); - VIDEO_WaitVSync(); - // Loop over handling mail until we've stopped stepping - // dsp_steps-3 compensates for mails to setup the ucode - for (int steps_cache = dsp_steps-3; steps_cache <= dsp_steps; steps_cache++) - handle_dsp_mail(); - VIDEO_WaitVSync(); + VIDEO_WaitVSync(); + // Loop over handling mail until we've stopped stepping + // dsp_steps-3 compensates for mails to setup the ucode + for (int steps_cache = dsp_steps - 3; steps_cache <= dsp_steps; steps_cache++) + handle_dsp_mail(); + VIDEO_WaitVSync(); - sprintf(filename, "sd:/dsp_dump_all.bin"); - FILE *f2 = fopen(filename, "ab"); + sprintf(filename, "sd:/dsp_dump_all.bin"); + FILE* f2 = fopen(filename, "ab"); - if (fastmode == false) - { - // Then write microcode dump to file - sprintf(filename, "sd:/dsp_dump%d.bin", UCodeToDump); - FILE *f = fopen(filename, "wb"); - if (f) - { - // First write initial regs - written = fwrite(dspreg_in, 1, 32 * 2, f); + if (fastmode == false) + { + // Then write microcode dump to file + sprintf(filename, "sd:/dsp_dump%d.bin", UCodeToDump); + FILE* f = fopen(filename, "wb"); + if (f) + { + // First write initial regs + written = fwrite(dspreg_in, 1, 32 * 2, f); - // Then write all the dumps. - written += fwrite(dspreg_out, 1, dsp_steps * 32 * 2, f); - fclose(f); - } - else - { - UpdateLastMessage("SD Write Error"); - break; - } - } + // Then write all the dumps. + written += fwrite(dspreg_out, 1, dsp_steps * 32 * 2, f); + fclose(f); + } + else + { + UpdateLastMessage("SD Write Error"); + break; + } + } - if (f2) //all in 1 dump file (extra) - { - if (UCodeToDump == 0) { - // First write initial regs - written = fwrite(dspreg_in, 1, 32 * 2, f2); - written += fwrite(dspreg_out, 1, dsp_steps * 32 * 2, f2); - } - else { - written = fwrite(dspreg_out, 1, dsp_steps * 32 * 2, f2); - } + if (f2) // all in 1 dump file (extra) + { + if (UCodeToDump == 0) + { + // First write initial regs + written = fwrite(dspreg_in, 1, 32 * 2, f2); + written += fwrite(dspreg_out, 1, dsp_steps * 32 * 2, f2); + } + else + { + written = fwrite(dspreg_out, 1, dsp_steps * 32 * 2, f2); + } - fclose(f2); + fclose(f2); - if (UCodeToDump < NUM_UCODES-1) - { - sprintf(temp, "Dump %d Successful. Wrote %d bytes, steps: %d", UCodeToDump+1, written, dsp_steps); - UpdateLastMessage(temp); - } - else { - UpdateLastMessage("DUMPING DONE!"); - } - } - else - { - UpdateLastMessage("SD Write Error"); - break; - } - } + if (UCodeToDump < NUM_UCODES - 1) + { + sprintf(temp, "Dump %d Successful. Wrote %d bytes, steps: %d", UCodeToDump + 1, written, + dsp_steps); + UpdateLastMessage(temp); + } + else + { + UpdateLastMessage("DUMPING DONE!"); + } + } + else + { + UpdateLastMessage("SD Write Error"); + break; + } + } } // Shove common, un-dsp-ish init things here void InitGeneral() { - // Initialize the video system - VIDEO_Init(); + // Initialize the video system + VIDEO_Init(); - // This function initializes the attached controllers - PAD_Init(); + // This function initializes the attached controllers + PAD_Init(); #ifdef HW_RVL - WPAD_Init(); + WPAD_Init(); #endif - // Obtain the preferred video mode from the system - // This will correspond to the settings in the Wii Menu - rmode = VIDEO_GetPreferredMode(nullptr); + // Obtain the preferred video mode from the system + // This will correspond to the settings in the Wii Menu + rmode = VIDEO_GetPreferredMode(nullptr); - // Allocate memory for the display in the uncached region - xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); + // Allocate memory for the display in the uncached region + xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); - // Set up the video registers with the chosen mode - VIDEO_Configure(rmode); - // Tell the video hardware where our display memory is - VIDEO_SetNextFramebuffer(xfb); - // Make the display visible - VIDEO_SetBlack(FALSE); - // Flush the video register changes to the hardware - VIDEO_Flush(); - // Wait for Video setup to complete - VIDEO_WaitVSync(); - if (rmode->viTVMode & VI_NON_INTERLACE) - VIDEO_WaitVSync(); + // Set up the video registers with the chosen mode + VIDEO_Configure(rmode); + // Tell the video hardware where our display memory is + VIDEO_SetNextFramebuffer(xfb); + // Make the display visible + VIDEO_SetBlack(FALSE); + // Flush the video register changes to the hardware + VIDEO_Flush(); + // Wait for Video setup to complete + VIDEO_WaitVSync(); + if (rmode->viTVMode & VI_NON_INTERLACE) + VIDEO_WaitVSync(); - // Initialize the console, required for printf - CON_Init(xfb, 20, 64, rmode->fbWidth, rmode->xfbHeight, rmode->fbWidth * VI_DISPLAY_PIX_SZ); + // Initialize the console, required for printf + CON_Init(xfb, 20, 64, rmode->fbWidth, rmode->xfbHeight, rmode->fbWidth * VI_DISPLAY_PIX_SZ); #ifdef HW_RVL - // Initialize FAT so we can write to SD. - __io_wiisd.startup(); - fatMountSimple("sd", &__io_wiisd); + // Initialize FAT so we can write to SD. + __io_wiisd.startup(); + fatMountSimple("sd", &__io_wiisd); #else - // Initialize FAT so we can write to SD Gecko in slot B. - fatMountSimple("sd", &__io_gcsdb); + // Initialize FAT so we can write to SD Gecko in slot B. + fatMountSimple("sd", &__io_gcsdb); - // Init debug over BBA...change IPs to suite your needs - tcp_localip="192.168.1.103"; - tcp_netmask="255.255.255.0"; - tcp_gateway="192.168.1.2"; - DEBUG_Init(GDBSTUB_DEVICE_TCP, GDBSTUB_DEF_TCPPORT); + // Init debug over BBA...change IPs to suite your needs + tcp_localip = "192.168.1.103"; + tcp_netmask = "255.255.255.0"; + tcp_gateway = "192.168.1.2"; + DEBUG_Init(GDBSTUB_DEVICE_TCP, GDBSTUB_DEF_TCPPORT); #endif } void ExitToLoader() { - fatUnmount("sd"); + fatUnmount("sd"); #ifdef HW_RVL - __io_wiisd.shutdown(); + __io_wiisd.shutdown(); #endif - UpdateLastMessage("Exiting..."); - real_dsp.Reset(); - reboot(); + UpdateLastMessage("Exiting..."); + real_dsp.Reset(); + reboot(); } int main() { - InitGeneral(); + InitGeneral(); - ui_mode = UIM_SEL; + ui_mode = UIM_SEL; - dspbufP = (u16 *)MEM_VIRTUAL_TO_PHYSICAL(dspbuffer); // physical - dspbufC = dspbuffer; // cached - dspbufU = (u32 *)(MEM_K0_TO_K1(dspbuffer)); // uncached + dspbufP = (u16*)MEM_VIRTUAL_TO_PHYSICAL(dspbuffer); // physical + dspbufC = dspbuffer; // cached + dspbufU = (u32*)(MEM_K0_TO_K1(dspbuffer)); // uncached - DCInvalidateRange(dspbuffer, 0x2000); - for (int j = 0; j < 0x800; j++) - dspbufU[j] = 0xffffffff; + DCInvalidateRange(dspbuffer, 0x2000); + for (int j = 0; j < 0x800; j++) + dspbufU[j] = 0xffffffff; - // Initialize DSP. - real_dsp.Init(); + // Initialize DSP. + real_dsp.Init(); + int show_step = 0; + while (true) + { + handle_dsp_mail(); - int show_step = 0; - while (true) - { - handle_dsp_mail(); + VIDEO_WaitVSync(); - VIDEO_WaitVSync(); - - PAD_ScanPads(); - if (PAD_ButtonsDown(0) & PAD_BUTTON_START) - ExitToLoader(); + PAD_ScanPads(); + if (PAD_ButtonsDown(0) & PAD_BUTTON_START) + ExitToLoader(); #ifdef HW_RVL - WPAD_ScanPads(); - if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME) - ExitToLoader(); + WPAD_ScanPads(); + if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME) + ExitToLoader(); - CON_Printf(2, 18, "Controls:"); - CON_Printf(4, 19, "+/- (GC:'L'/'R') to move"); - CON_Printf(4, 20, "A (GC:'A') to edit register; B (GC:'B') to start over"); - CON_Printf(4, 21, "1 (GC:'Z') to move next microcode"); - CON_Printf(4, 22, "2 (GC:'X') dump results to SD; UP (GC:'Y') dump results to SD (SINGLE FILE)"); - CON_Printf(4, 23, "Home (GC:'START') to exit"); + CON_Printf(2, 18, "Controls:"); + CON_Printf(4, 19, "+/- (GC:'L'/'R') to move"); + CON_Printf(4, 20, "A (GC:'A') to edit register; B (GC:'B') to start over"); + CON_Printf(4, 21, "1 (GC:'Z') to move next microcode"); + CON_Printf(4, 22, + "2 (GC:'X') dump results to SD; UP (GC:'Y') dump results to SD (SINGLE FILE)"); + CON_Printf(4, 23, "Home (GC:'START') to exit"); #else - CON_Printf(2, 18, "Controls:"); - CON_Printf(4, 19, "L/R to move"); - CON_Printf(4, 20, "A to edit register, B to start over"); - CON_Printf(4, 21, "Z to move to next microcode"); - CON_Printf(4, 22, "Start to exit"); + CON_Printf(2, 18, "Controls:"); + CON_Printf(4, 19, "L/R to move"); + CON_Printf(4, 20, "A to edit register, B to start over"); + CON_Printf(4, 21, "Z to move to next microcode"); + CON_Printf(4, 22, "Start to exit"); #endif - print_regs(show_step, dsp_steps); + print_regs(show_step, dsp_steps); - switch (ui_mode) - { - case UIM_SEL: - ui_pad_sel(); - break; - case UIM_EDIT_REG: - ui_pad_edit_reg(); - break; - case UIM_EDIT_BIN: - // ui_pad_edit_bin(); - break; - default: - break; - } - DCFlushRange(xfb, 0x200000); + switch (ui_mode) + { + case UIM_SEL: + ui_pad_sel(); + break; + case UIM_EDIT_REG: + ui_pad_edit_reg(); + break; + case UIM_EDIT_BIN: + // ui_pad_edit_bin(); + break; + default: + break; + } + DCFlushRange(xfb, 0x200000); - - // Use B to start over. +// Use B to start over. #ifdef HW_RVL - if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_B) || (PAD_ButtonsDown(0) & PAD_BUTTON_B)) + if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_B) || (PAD_ButtonsDown(0) & PAD_BUTTON_B)) #else - if (PAD_ButtonsDown(0) & PAD_BUTTON_B) + if (PAD_ButtonsDown(0) & PAD_BUTTON_B) #endif - { - dsp_steps = 0; // Let's not add the new steps after the original ones. That was just annoying. + { + dsp_steps = + 0; // Let's not add the new steps after the original ones. That was just annoying. - DCInvalidateRange(dspbufC, 0x2000); - DCFlushRange(dspbufC, 0x2000); + DCInvalidateRange(dspbufC, 0x2000); + DCFlushRange(dspbufC, 0x2000); - // Reset the DSP. - real_dsp.Reset(); - UpdateLastMessage("OK"); - } + // Reset the DSP. + real_dsp.Reset(); + UpdateLastMessage("OK"); + } - // Navigate between results using + and - buttons. +// Navigate between results using + and - buttons. #ifdef HW_RVL - if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_PLUS) || (PAD_ButtonsDown(0) & PAD_TRIGGER_R)) + if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_PLUS) || (PAD_ButtonsDown(0) & PAD_TRIGGER_R)) #else - if (PAD_ButtonsDown(0) & PAD_TRIGGER_R) + if (PAD_ButtonsDown(0) & PAD_TRIGGER_R) #endif - { - show_step++; - if (show_step >= dsp_steps) - show_step = 0; - UpdateLastMessage("OK"); - } + { + show_step++; + if (show_step >= dsp_steps) + show_step = 0; + UpdateLastMessage("OK"); + } #ifdef HW_RVL - if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_MINUS) || (PAD_ButtonsDown(0) & PAD_TRIGGER_L)) + if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_MINUS) || (PAD_ButtonsDown(0) & PAD_TRIGGER_L)) #else - if (PAD_ButtonsDown(0) & PAD_TRIGGER_L) + if (PAD_ButtonsDown(0) & PAD_TRIGGER_L) #endif - { - show_step--; - if (show_step < 0) - show_step = dsp_steps - 1; - UpdateLastMessage("OK"); - } + { + show_step--; + if (show_step < 0) + show_step = dsp_steps - 1; + UpdateLastMessage("OK"); + } #ifdef HW_RVL - if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_1) || (PAD_ButtonsDown(0) & PAD_TRIGGER_Z)) + if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_1) || (PAD_ButtonsDown(0) & PAD_TRIGGER_Z)) #else - if (PAD_ButtonsDown(0) & PAD_TRIGGER_Z) + if (PAD_ButtonsDown(0) & PAD_TRIGGER_Z) #endif - { - curUcode++; - if (curUcode == NUM_UCODES) - curUcode = 0; + { + curUcode++; + if (curUcode == NUM_UCODES) + curUcode = 0; - // Reset step counters since we're in a new ucode. - show_step = 0; - dsp_steps = 0; + // Reset step counters since we're in a new ucode. + show_step = 0; + dsp_steps = 0; - DCInvalidateRange(dspbufC, 0x2000); - for (int n = 0 ; n < 0x2000 ; n++) - { - // dspbufU[n/2] = 0; dspbufC[n] = 0; - } - DCFlushRange(dspbufC, 0x2000); + DCInvalidateRange(dspbufC, 0x2000); + for (int n = 0; n < 0x2000; n++) + { + // dspbufU[n/2] = 0; dspbufC[n] = 0; + } + DCFlushRange(dspbufC, 0x2000); - // Reset the DSP. - real_dsp.Reset(); - UpdateLastMessage("OK"); + // Reset the DSP. + real_dsp.Reset(); + UpdateLastMessage("OK"); - // Waiting for video to synchronize (enough time to set our new microcode) - VIDEO_WaitVSync(); - } + // Waiting for video to synchronize (enough time to set our new microcode) + VIDEO_WaitVSync(); + } #ifdef HW_RVL - // Probably could offer to save to sd gecko or something on gc... - // The future is web-based reporting ;) - if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_2) || (PAD_ButtonsDown(0) & PAD_BUTTON_X)) - { - dump_all_ucodes(false); - } + // Probably could offer to save to sd gecko or something on gc... + // The future is web-based reporting ;) + if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_2) || (PAD_ButtonsDown(0) & PAD_BUTTON_X)) + { + dump_all_ucodes(false); + } - // Dump all results into 1 file (skip file per ucode part) = FAST because of LIBFAT filecreate bug - if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_UP) || (PAD_ButtonsDown(0) & PAD_BUTTON_Y)) - { - dump_all_ucodes(true); - } + // Dump all results into 1 file (skip file per ucode part) = FAST because of LIBFAT filecreate + // bug + if ((WPAD_ButtonsDown(0) & WPAD_BUTTON_UP) || (PAD_ButtonsDown(0) & PAD_BUTTON_Y)) + { + dump_all_ucodes(true); + } #endif - } // end main loop + } // end main loop - ExitToLoader(); + ExitToLoader(); - // Will never reach here, but just to be sure.. - exit(0); - return 0; + // Will never reach here, but just to be sure.. + exit(0); + return 0; } diff --git a/Source/DSPSpy/mem_dump.h b/Source/DSPSpy/mem_dump.h index 418064627e..15ea485392 100644 --- a/Source/DSPSpy/mem_dump.h +++ b/Source/DSPSpy/mem_dump.h @@ -4,518 +4,261 @@ #pragma once -unsigned int mem_dump[] __attribute__ ((aligned (64))) = -{ - 0x0c3966ad, 0x0d46ffdf, 0x0b396696, 0x0e5fffd8, - 0x0a446669, 0x0f83ffd0, 0x095a6626, 0x10b4ffc8, - 0x087d65cd, 0x11f0ffbf, 0x07ab655e, 0x1338ffb6, - 0x06e464d9, 0x148cffac, 0x0628643f, 0x15ebffa1, - 0x0577638f, 0x1756ff96, 0x04d162cb, 0x18cbff8a, - 0x043561f3, 0x1a4cff7e, 0x03a46106, 0x1bd7ff71, - 0x031c6007, 0x1d6cff64, 0x029f5ef5, 0x1f0bff56, - 0x022a5dd0, 0x20b3ff48, 0x01be5c9a, 0x2264ff3a, - 0x015b5b53, 0x241eff2c, 0x010159fc, 0x25e0ff1e, - 0x00ae5896, 0x27a9ff10, 0x00635720, 0x297aff02, - 0x001f559d, 0x2b50fef4, 0xffe2540d, 0x2d2cfee8, - 0xffac5270, 0x2f0dfedb, 0xff7c50c7, 0x30f3fed0, - 0xff534f14, 0x32dcfec6, 0xff2e4d57, 0x34c8febd, - 0xff0f4b91, 0x36b6feb6, 0xfef549c2, 0x38a5feb0, - 0xfedf47ed, 0x3a95feac, 0xfece4611, 0x3c85feab, - 0xfec04430, 0x3e74feac, 0xfeb6424a, 0x4060feaf, - 0xfeaf4060, 0x424afeb6, 0xfeac3e74, 0x4430fec0, - 0xfeab3c85, 0x4611fece, 0xfeac3a95, 0x47edfedf, - 0xfeb038a5, 0x49c2fef5, 0xfeb636b6, 0x4b91ff0f, - 0xfebd34c8, 0x4d57ff2e, 0xfec632dc, 0x4f14ff53, - 0xfed030f3, 0x50c7ff7c, 0xfedb2f0d, 0x5270ffac, - 0xfee82d2c, 0x540dffe2, 0xfef42b50, 0x559d001f, - 0xff02297a, 0x57200063, 0xff1027a9, 0x589600ae, - 0xff1e25e0, 0x59fc0101, 0xff2c241e, 0x5b53015b, - 0xff3a2264, 0x5c9a01be, 0xff4820b3, 0x5dd0022a, - 0xff561f0b, 0x5ef5029f, 0xff641d6c, 0x6007031c, - 0xff711bd7, 0x610603a4, 0xff7e1a4c, 0x61f30435, - 0xff8a18cb, 0x62cb04d1, 0xff961756, 0x638f0577, - 0xffa115eb, 0x643f0628, 0xffac148c, 0x64d906e4, - 0xffb61338, 0x655e07ab, 0xffbf11f0, 0x65cd087d, - 0xffc810b4, 0x6626095a, 0xffd00f83, 0x66690a44, - 0xffd80e5f, 0x66960b39, 0xffdf0d46, 0x66ad0c39, - 0x00000c8b, 0x18f82527, 0x30fb3c56, 0x471c5133, - 0x5a8262f1, 0x6a6d70e2, 0x76417a7c, 0x7d897f61, - 0x7fff7f61, 0x7d897a7c, 0x764170e2, 0x6a6d62f1, - 0x5a825133, 0x471c3c56, 0x30fb2527, 0x18f80c8b, - 0x0000f375, 0xe708dad9, 0xcf05c3aa, 0xb8e4aecd, - 0xa57e9d0f, 0x95938f1e, 0x89bf8584, 0x8277809f, - 0x8001809f, 0x82778584, 0x89bf8f1e, 0x95939d0f, - 0xa57eaecd, 0xb8e4c3aa, 0xcf05dad9, 0xe708f375, - 0x000007ff, 0x0fff17ff, 0x1fff27ff, 0x2fff37ff, - 0x3fff47ff, 0x4fff57ff, 0x5fff67ff, 0x6fff77ff, - 0x7fff7800, 0x70006800, 0x60005800, 0x50004800, - 0x40003800, 0x30002800, 0x20001800, 0x10000800, - 0x0000f801, 0xf001e801, 0xe001d801, 0xd001c801, - 0xc001b801, 0xb001a801, 0xa0019801, 0x90018801, - 0x80018800, 0x90009800, 0xa000a800, 0xb000b800, - 0xc000c800, 0xd000d800, 0xe000e800, 0xf000f800, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x682e469b, 0x25080375, 0xe1e2c04f, 0x9ebc7d29, - 0x5b963a03, 0x1870f6dd, 0xd54ab3b7, 0x92247091, - 0x4efe2d6b, 0x0bd8ea45, 0xc8b2a71f, 0x858c63f9, - 0x426620d3, 0xff40ddad, 0xbc1a9a87, 0x78f45761, - 0x35ce143b, 0xf2a8d115, 0xaf828def, 0x6c5c4ac9, - 0x293607a3, 0xe610c47d, 0xa2ea8157, 0x5fc43e31, - 0x1c9efb0b, 0xd978b7e5, 0x965274bf, 0x532c3199, - 0x1006ee73, 0xcce0ab4d, 0x89ba6827, 0x46942501, - 0x00000001, 0x00020003, 0x00040005, 0x00060007, - 0x00080009, 0x000a000b, 0x000c000d, 0x000e000f, - 0x00000001, 0x00020003, 0x00040005, 0x00060007, - 0x00080009, 0x000a000b, 0x000c000d, 0x000e000f, - 0x00000001, 0x00020003, 0x00040005, 0x00060007, - 0x00080009, 0x000a000b, 0x000c000d, 0x000e000f, - 0x00000001, 0x00020003, 0x00040005, 0x00060007, - 0x00080009, 0x000a000b, 0x000c000d, 0x000e000f, - 0x5a825b9c, 0x5cb35dc7, 0x5ed75fe3, 0x60eb61f0, - 0x62f163ee, 0x64e865dd, 0x66cf67bc, 0x68a6698b, - 0x6a6d6b4a, 0x6c236cf8, 0x6dc96e96, 0x6f5e7022, - 0x70e2719d, 0x72547307, 0x73b5745f, 0x750475a5, - 0x764176d8, 0x776b77fa, 0x78847909, 0x79897a05, - 0x7a7c7aee, 0x7b5c7bc5, 0x7c297c88, 0x7ce37d39, - 0x7d897dd5, 0x7e1d7e5f, 0x7e9c7ed5, 0x7f097f37, - 0x7f617f86, 0x7fa67fc1, 0x7fd87fe9, 0x7ff57ffd, - 0x00058100, 0x0040806a, 0x19e08039, 0x8f208039, - 0x8ee0806a, 0x79e00002, 0x8d00000a, 0x803ea5e0, - 0x00038207, 0x5ffb8069, 0xffa0806a, 0x04000003, - 0x82075ffb, 0x806a0860, 0x806a0cc0, 0x00038207, - 0x5ffb806a, 0x1120806a, 0x15800003, 0x82075ffb, - 0x8069ffa0, 0x806a0400, 0x00038207, 0x5ffb806a, - 0x0860806a, 0x0cc00003, 0x82075ffb, 0x806a1120, - 0x806a1580, 0x00038207, 0x5ffb8069, 0xffa0806a, - 0x04000003, 0x82075ffb, 0x806a0860, 0x806a0cc0, - 0x00038207, 0x5ffb806a, 0x1120806a, 0x15800003, - 0x82075ffb, 0x8069ffa0, 0x806a0400, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x08000000, 0x00000800, 0x04000400, - 0x1000f800, 0x0e00fa00, 0x0c00fc00, 0x1200f600, - 0x1068f738, 0x12c0f704, 0x1400f400, 0x0800f800, - 0x0400fc00, 0xfc000400, 0xfc000000, 0xf8000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000002, 0x00400004, 0x00075ffb, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00400000, - 0x02d602d6, 0x00000000, 0x00400006, 0x82075ffb, - 0x8069ffa0, 0x806a0400, 0x80398ee0, 0x806a79e0, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x803ea5e0, 0x000a0001, - 0x00000000, 0x00000000, 0x00010000, 0x00000000, - 0x806a19e0, 0x80398f20, 0x80398ee0, 0x806a79e0, - 0x806a02c0, 0x806a0720, 0x00000000, 0x5ffb0000, - 0x00010038, 0x80758e80, 0x0d000000, 0x0d604000, - 0x00000000, 0x00000000, 0x00000000, 0x58000000, - 0x03a80f40, 0x03e80000, 0x003d003d, 0x003d003d, - 0x00010020, 0x80754380, 0x0d002000, 0x0d600000, - 0x00000000, 0x00000000, 0x00000000, 0x3fff0000, - 0x00010020, 0x80755780, 0x0d000000, 0x0d602000, - 0x00000000, 0x00000000, 0x00000000, 0x3fff0000, - 0x00010038, 0x80756b80, 0x0d004000, 0x0d600000, - 0x00000000, 0x00000000, 0x00000000, 0x58000000, - 0x00010038, 0x80758e80, 0x0d000000, 0x0d604000, - 0x00000000, 0x00000000, 0x00000000, 0x58000000, - 0x00000000, 0x00000000, 0x00000000, 0x58000000, - 0x00501568, 0xffff0030, 0x00107f00, 0x08000100, - 0x0000002d, 0xabb80500, 0xffff0000, 0xff06f000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x82407fff, 0x7dbf843f, 0x00000000, 0x00000000, - 0xb23b7fff, 0x4dc4d808, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, +unsigned int mem_dump[] __attribute__((aligned(64))) = { + 0x0c3966ad, 0x0d46ffdf, 0x0b396696, 0x0e5fffd8, 0x0a446669, 0x0f83ffd0, 0x095a6626, 0x10b4ffc8, + 0x087d65cd, 0x11f0ffbf, 0x07ab655e, 0x1338ffb6, 0x06e464d9, 0x148cffac, 0x0628643f, 0x15ebffa1, + 0x0577638f, 0x1756ff96, 0x04d162cb, 0x18cbff8a, 0x043561f3, 0x1a4cff7e, 0x03a46106, 0x1bd7ff71, + 0x031c6007, 0x1d6cff64, 0x029f5ef5, 0x1f0bff56, 0x022a5dd0, 0x20b3ff48, 0x01be5c9a, 0x2264ff3a, + 0x015b5b53, 0x241eff2c, 0x010159fc, 0x25e0ff1e, 0x00ae5896, 0x27a9ff10, 0x00635720, 0x297aff02, + 0x001f559d, 0x2b50fef4, 0xffe2540d, 0x2d2cfee8, 0xffac5270, 0x2f0dfedb, 0xff7c50c7, 0x30f3fed0, + 0xff534f14, 0x32dcfec6, 0xff2e4d57, 0x34c8febd, 0xff0f4b91, 0x36b6feb6, 0xfef549c2, 0x38a5feb0, + 0xfedf47ed, 0x3a95feac, 0xfece4611, 0x3c85feab, 0xfec04430, 0x3e74feac, 0xfeb6424a, 0x4060feaf, + 0xfeaf4060, 0x424afeb6, 0xfeac3e74, 0x4430fec0, 0xfeab3c85, 0x4611fece, 0xfeac3a95, 0x47edfedf, + 0xfeb038a5, 0x49c2fef5, 0xfeb636b6, 0x4b91ff0f, 0xfebd34c8, 0x4d57ff2e, 0xfec632dc, 0x4f14ff53, + 0xfed030f3, 0x50c7ff7c, 0xfedb2f0d, 0x5270ffac, 0xfee82d2c, 0x540dffe2, 0xfef42b50, 0x559d001f, + 0xff02297a, 0x57200063, 0xff1027a9, 0x589600ae, 0xff1e25e0, 0x59fc0101, 0xff2c241e, 0x5b53015b, + 0xff3a2264, 0x5c9a01be, 0xff4820b3, 0x5dd0022a, 0xff561f0b, 0x5ef5029f, 0xff641d6c, 0x6007031c, + 0xff711bd7, 0x610603a4, 0xff7e1a4c, 0x61f30435, 0xff8a18cb, 0x62cb04d1, 0xff961756, 0x638f0577, + 0xffa115eb, 0x643f0628, 0xffac148c, 0x64d906e4, 0xffb61338, 0x655e07ab, 0xffbf11f0, 0x65cd087d, + 0xffc810b4, 0x6626095a, 0xffd00f83, 0x66690a44, 0xffd80e5f, 0x66960b39, 0xffdf0d46, 0x66ad0c39, + 0x00000c8b, 0x18f82527, 0x30fb3c56, 0x471c5133, 0x5a8262f1, 0x6a6d70e2, 0x76417a7c, 0x7d897f61, + 0x7fff7f61, 0x7d897a7c, 0x764170e2, 0x6a6d62f1, 0x5a825133, 0x471c3c56, 0x30fb2527, 0x18f80c8b, + 0x0000f375, 0xe708dad9, 0xcf05c3aa, 0xb8e4aecd, 0xa57e9d0f, 0x95938f1e, 0x89bf8584, 0x8277809f, + 0x8001809f, 0x82778584, 0x89bf8f1e, 0x95939d0f, 0xa57eaecd, 0xb8e4c3aa, 0xcf05dad9, 0xe708f375, + 0x000007ff, 0x0fff17ff, 0x1fff27ff, 0x2fff37ff, 0x3fff47ff, 0x4fff57ff, 0x5fff67ff, 0x6fff77ff, + 0x7fff7800, 0x70006800, 0x60005800, 0x50004800, 0x40003800, 0x30002800, 0x20001800, 0x10000800, + 0x0000f801, 0xf001e801, 0xe001d801, 0xd001c801, 0xc001b801, 0xb001a801, 0xa0019801, 0x90018801, + 0x80018800, 0x90009800, 0xa000a800, 0xb000b800, 0xc000c800, 0xd000d800, 0xe000e800, 0xf000f800, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x682e469b, 0x25080375, 0xe1e2c04f, 0x9ebc7d29, 0x5b963a03, 0x1870f6dd, 0xd54ab3b7, 0x92247091, + 0x4efe2d6b, 0x0bd8ea45, 0xc8b2a71f, 0x858c63f9, 0x426620d3, 0xff40ddad, 0xbc1a9a87, 0x78f45761, + 0x35ce143b, 0xf2a8d115, 0xaf828def, 0x6c5c4ac9, 0x293607a3, 0xe610c47d, 0xa2ea8157, 0x5fc43e31, + 0x1c9efb0b, 0xd978b7e5, 0x965274bf, 0x532c3199, 0x1006ee73, 0xcce0ab4d, 0x89ba6827, 0x46942501, + 0x00000001, 0x00020003, 0x00040005, 0x00060007, 0x00080009, 0x000a000b, 0x000c000d, 0x000e000f, + 0x00000001, 0x00020003, 0x00040005, 0x00060007, 0x00080009, 0x000a000b, 0x000c000d, 0x000e000f, + 0x00000001, 0x00020003, 0x00040005, 0x00060007, 0x00080009, 0x000a000b, 0x000c000d, 0x000e000f, + 0x00000001, 0x00020003, 0x00040005, 0x00060007, 0x00080009, 0x000a000b, 0x000c000d, 0x000e000f, + 0x5a825b9c, 0x5cb35dc7, 0x5ed75fe3, 0x60eb61f0, 0x62f163ee, 0x64e865dd, 0x66cf67bc, 0x68a6698b, + 0x6a6d6b4a, 0x6c236cf8, 0x6dc96e96, 0x6f5e7022, 0x70e2719d, 0x72547307, 0x73b5745f, 0x750475a5, + 0x764176d8, 0x776b77fa, 0x78847909, 0x79897a05, 0x7a7c7aee, 0x7b5c7bc5, 0x7c297c88, 0x7ce37d39, + 0x7d897dd5, 0x7e1d7e5f, 0x7e9c7ed5, 0x7f097f37, 0x7f617f86, 0x7fa67fc1, 0x7fd87fe9, 0x7ff57ffd, + 0x00058100, 0x0040806a, 0x19e08039, 0x8f208039, 0x8ee0806a, 0x79e00002, 0x8d00000a, 0x803ea5e0, + 0x00038207, 0x5ffb8069, 0xffa0806a, 0x04000003, 0x82075ffb, 0x806a0860, 0x806a0cc0, 0x00038207, + 0x5ffb806a, 0x1120806a, 0x15800003, 0x82075ffb, 0x8069ffa0, 0x806a0400, 0x00038207, 0x5ffb806a, + 0x0860806a, 0x0cc00003, 0x82075ffb, 0x806a1120, 0x806a1580, 0x00038207, 0x5ffb8069, 0xffa0806a, + 0x04000003, 0x82075ffb, 0x806a0860, 0x806a0cc0, 0x00038207, 0x5ffb806a, 0x1120806a, 0x15800003, + 0x82075ffb, 0x8069ffa0, 0x806a0400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x08000000, 0x00000800, 0x04000400, 0x1000f800, 0x0e00fa00, 0x0c00fc00, 0x1200f600, + 0x1068f738, 0x12c0f704, 0x1400f400, 0x0800f800, 0x0400fc00, 0xfc000400, 0xfc000000, 0xf8000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000002, 0x00400004, 0x00075ffb, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00400000, + 0x02d602d6, 0x00000000, 0x00400006, 0x82075ffb, 0x8069ffa0, 0x806a0400, 0x80398ee0, 0x806a79e0, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x803ea5e0, 0x000a0001, 0x00000000, 0x00000000, 0x00010000, 0x00000000, + 0x806a19e0, 0x80398f20, 0x80398ee0, 0x806a79e0, 0x806a02c0, 0x806a0720, 0x00000000, 0x5ffb0000, + 0x00010038, 0x80758e80, 0x0d000000, 0x0d604000, 0x00000000, 0x00000000, 0x00000000, 0x58000000, + 0x03a80f40, 0x03e80000, 0x003d003d, 0x003d003d, 0x00010020, 0x80754380, 0x0d002000, 0x0d600000, + 0x00000000, 0x00000000, 0x00000000, 0x3fff0000, 0x00010020, 0x80755780, 0x0d000000, 0x0d602000, + 0x00000000, 0x00000000, 0x00000000, 0x3fff0000, 0x00010038, 0x80756b80, 0x0d004000, 0x0d600000, + 0x00000000, 0x00000000, 0x00000000, 0x58000000, 0x00010038, 0x80758e80, 0x0d000000, 0x0d604000, + 0x00000000, 0x00000000, 0x00000000, 0x58000000, 0x00000000, 0x00000000, 0x00000000, 0x58000000, + 0x00501568, 0xffff0030, 0x00107f00, 0x08000100, 0x0000002d, 0xabb80500, 0xffff0000, 0xff06f000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x82407fff, 0x7dbf843f, 0x00000000, 0x00000000, + 0xb23b7fff, 0x4dc4d808, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }; diff --git a/Source/DSPSpy/real_dsp.cpp b/Source/DSPSpy/real_dsp.cpp index 4df33fcb57..9c37c55704 100644 --- a/Source/DSPSpy/real_dsp.cpp +++ b/Source/DSPSpy/real_dsp.cpp @@ -3,11 +3,11 @@ // Refer to the license.txt file included. #include -#include #include #include #include #include +#include #include "dsp_interface.h" #include "real_dsp.h" @@ -15,40 +15,40 @@ static vu16* const _dspReg = (u16*)0xCC005000; // Handler for DSP interrupt. -static void dsp_irq_handler(u32 nIrq, void *pCtx) +static void dsp_irq_handler(u32 nIrq, void* pCtx) { - // Acknowledge interrupt? - _dspReg[5] = (_dspReg[5] & ~(DSPCR_AIINT|DSPCR_ARINT)) | DSPCR_DSPINT; + // Acknowledge interrupt? + _dspReg[5] = (_dspReg[5] & ~(DSPCR_AIINT | DSPCR_ARINT)) | DSPCR_DSPINT; } void RealDSP::Init() { - _dspReg[5] = (_dspReg[5] & ~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT)) | DSPCR_DSPRESET; - _dspReg[5] = (_dspReg[5] & ~(DSPCR_HALT|DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT)); + _dspReg[5] = (_dspReg[5] & ~(DSPCR_AIINT | DSPCR_ARINT | DSPCR_DSPINT)) | DSPCR_DSPRESET; + _dspReg[5] = (_dspReg[5] & ~(DSPCR_HALT | DSPCR_AIINT | DSPCR_ARINT | DSPCR_DSPINT)); - u32 level; - _CPU_ISR_Disable(level); - IRQ_Request(IRQ_DSP_DSP, dsp_irq_handler, nullptr); - _CPU_ISR_Restore(level); + u32 level; + _CPU_ISR_Disable(level); + IRQ_Request(IRQ_DSP_DSP, dsp_irq_handler, nullptr); + _CPU_ISR_Restore(level); } void RealDSP::Reset() { - // Reset the DSP. - _dspReg[5] = (_dspReg[5] & ~(DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT)) | DSPCR_DSPRESET; - _dspReg[5] = (_dspReg[5] & ~(DSPCR_HALT|DSPCR_AIINT|DSPCR_ARINT|DSPCR_DSPINT)); - _dspReg[5] |= DSPCR_RES; - while (_dspReg[5] & DSPCR_RES) - ; - _dspReg[9] = 0x63; + // Reset the DSP. + _dspReg[5] = (_dspReg[5] & ~(DSPCR_AIINT | DSPCR_ARINT | DSPCR_DSPINT)) | DSPCR_DSPRESET; + _dspReg[5] = (_dspReg[5] & ~(DSPCR_HALT | DSPCR_AIINT | DSPCR_ARINT | DSPCR_DSPINT)); + _dspReg[5] |= DSPCR_RES; + while (_dspReg[5] & DSPCR_RES) + ; + _dspReg[9] = 0x63; } u32 RealDSP::CheckMailTo() { - return DSP_CheckMailTo(); + return DSP_CheckMailTo(); } void RealDSP::SendMailTo(u32 mail) { - DSP_SendMailTo(mail); + DSP_SendMailTo(mail); } diff --git a/Source/DSPSpy/real_dsp.h b/Source/DSPSpy/real_dsp.h index cc43e88622..c4535c6991 100644 --- a/Source/DSPSpy/real_dsp.h +++ b/Source/DSPSpy/real_dsp.h @@ -9,8 +9,8 @@ class RealDSP : public IDSP { public: - virtual void Init(); - virtual void Reset(); - virtual u32 CheckMailTo(); - virtual void SendMailTo(u32 mail); + virtual void Init(); + virtual void Reset(); + virtual u32 CheckMailTo(); + virtual void SendMailTo(u32 mail); }; diff --git a/Source/DSPTool/DSPTool.cpp b/Source/DSPTool/DSPTool.cpp index 163af14e09..5dc8b6b68e 100644 --- a/Source/DSPTool/DSPTool.cpp +++ b/Source/DSPTool/DSPTool.cpp @@ -10,181 +10,201 @@ #include "Core/DSP/DSPTables.h" // Stub out the dsplib host stuff, since this is just a simple cmdline tools. -u8 DSPHost::ReadHostMemory(u32 addr) { return 0; } -void DSPHost::WriteHostMemory(u8 value, u32 addr) {} -void DSPHost::OSD_AddMessage(const std::string& str, u32 ms) {} -bool DSPHost::OnThread() { return false; } -bool DSPHost::IsWiiHost() { return false; } -void DSPHost::CodeLoaded(const u8 *ptr, int size) {} -void DSPHost::InterruptRequest() {} -void DSPHost::UpdateDebugger() {} +u8 DSPHost::ReadHostMemory(u32 addr) +{ + return 0; +} +void DSPHost::WriteHostMemory(u8 value, u32 addr) +{ +} +void DSPHost::OSD_AddMessage(const std::string& str, u32 ms) +{ +} +bool DSPHost::OnThread() +{ + return false; +} +bool DSPHost::IsWiiHost() +{ + return false; +} +void DSPHost::CodeLoaded(const u8* ptr, int size) +{ +} +void DSPHost::InterruptRequest() +{ +} +void DSPHost::UpdateDebugger() +{ +} // This test goes from text ASM to binary to text ASM and once again back to binary. // Then the two binaries are compared. -static bool RoundTrip(const std::vector &code1) +static bool RoundTrip(const std::vector& code1) { - std::vector code2; - std::string text; - if (!Disassemble(code1, false, text)) - { - printf("RoundTrip: Disassembly failed.\n"); - return false; - } - if (!Assemble(text.c_str(), code2)) - { - printf("RoundTrip: Assembly failed.\n"); - return false; - } - if (!Compare(code1, code2)) - { - Disassemble(code1, true, text); - printf("%s", text.c_str()); - } - return true; + std::vector code2; + std::string text; + if (!Disassemble(code1, false, text)) + { + printf("RoundTrip: Disassembly failed.\n"); + return false; + } + if (!Assemble(text.c_str(), code2)) + { + printf("RoundTrip: Assembly failed.\n"); + return false; + } + if (!Compare(code1, code2)) + { + Disassemble(code1, true, text); + printf("%s", text.c_str()); + } + return true; } // This test goes from text ASM to binary to text ASM and once again back to binary. // Very convenient for testing. Then the two binaries are compared. -static bool SuperTrip(const char *asm_code) +static bool SuperTrip(const char* asm_code) { - std::vector code1, code2; - std::string text; - if (!Assemble(asm_code, code1)) - { - printf("SuperTrip: First assembly failed\n"); - return false; - } - printf("First assembly: %i words\n", (int)code1.size()); - if (!Disassemble(code1, false, text)) - { - printf("SuperTrip: Disassembly failed\n"); - return false; - } - else - { - printf("Disass:\n"); - printf("%s", text.c_str()); - } - if (!Assemble(text.c_str(), code2)) - { - printf("SuperTrip: Second assembly failed\n"); - return false; - } - /* - std::string text2; - Disassemble(code1, true, &text1); - Disassemble(code2, true, &text2); - File::WriteStringToFile(text1, "code1.txt"); - File::WriteStringToFile(text2, "code2.txt"); - */ - return true; + std::vector code1, code2; + std::string text; + if (!Assemble(asm_code, code1)) + { + printf("SuperTrip: First assembly failed\n"); + return false; + } + printf("First assembly: %i words\n", (int)code1.size()); + if (!Disassemble(code1, false, text)) + { + printf("SuperTrip: Disassembly failed\n"); + return false; + } + else + { + printf("Disass:\n"); + printf("%s", text.c_str()); + } + if (!Assemble(text.c_str(), code2)) + { + printf("SuperTrip: Second assembly failed\n"); + return false; + } + /* + std::string text2; + Disassemble(code1, true, &text1); + Disassemble(code2, true, &text2); + File::WriteStringToFile(text1, "code1.txt"); + File::WriteStringToFile(text2, "code2.txt"); + */ + return true; } static void RunAsmTests() { - bool fail = false; -#define CHK(a) if (!SuperTrip(a)) printf("FAIL\n%s\n", a), fail = true; + bool fail = false; +#define CHK(a) \ + if (!SuperTrip(a)) \ + printf("FAIL\n%s\n", a), fail = true; - // Let's start out easy - a trivial instruction.. - CHK(" NOP\n"); + // Let's start out easy - a trivial instruction.. + CHK(" NOP\n"); - // Now let's do several. - CHK(" NOP\n" - " NOP\n" - " NOP\n"); + // Now let's do several. + CHK(" NOP\n" + " NOP\n" + " NOP\n"); - // Turning it up a notch. - CHK(" SET16\n" - " SET40\n" - " CLR15\n" - " M0\n" - " M2\n"); + // Turning it up a notch. + CHK(" SET16\n" + " SET40\n" + " CLR15\n" + " M0\n" + " M2\n"); - // Time to try labels and parameters, and comments. - CHK("DIRQ_TEST: equ 0xfffb ; DSP Irq Request\n" - " si @0xfffc, #0x8888\n" - " si @0xfffd, #0xbeef\n" - " si @DIRQ_TEST, #0x0001\n"); + // Time to try labels and parameters, and comments. + CHK("DIRQ_TEST: equ 0xfffb ; DSP Irq Request\n" + " si @0xfffc, #0x8888\n" + " si @0xfffd, #0xbeef\n" + " si @DIRQ_TEST, #0x0001\n"); - // Let's see if registers roundtrip. Also try predefined labels. - CHK(" si @0xfffc, #0x8888\n" - " si @0xfffd, #0xbeef\n" - " si @DIRQ, #0x0001\n"); + // Let's see if registers roundtrip. Also try predefined labels. + CHK(" si @0xfffc, #0x8888\n" + " si @0xfffd, #0xbeef\n" + " si @DIRQ, #0x0001\n"); - // Let's try some messy extended instructions. - //CHK(" MULMV'SN $AX0.L, $AX0.H, $ACC0 : @$AR2, $AC1.M\n"); + // Let's try some messy extended instructions. + // CHK(" MULMV'SN $AX0.L, $AX0.H, $ACC0 : @$AR2, $AC1.M\n"); - //" ADDAXL'MV $ACC1, $AX1.L : $AX1.H, $AC1.M\n"); - // Let's get brutal. We generate random code bytes and make sure that they can - // be roundtripped. We don't expect it to always succeed but it'll be sure to generate + //" ADDAXL'MV $ACC1, $AX1.L : $AX1.H, $AC1.M\n"); + // Let's get brutal. We generate random code bytes and make sure that they can + // be roundtripped. We don't expect it to always succeed but it'll be sure to generate - // interesting test cases. - /* - std::vector hermes; - if (!LoadBinary("testdata/hermes.bin", &hermes)) - PanicAlert("Failed to load hermes rom"); - RoundTrip(hermes); - */ - /* - std::vector code; - std::string text_orig; - File::ReadFileToString("testdata/dsp_test.S", &text_orig); - if (!Assemble(text_orig.c_str(), &code)) - { - printf("SuperTrip: First assembly failed\n"); - return; - }*/ + // interesting test cases. + /* + std::vector hermes; + if (!LoadBinary("testdata/hermes.bin", &hermes)) + PanicAlert("Failed to load hermes rom"); + RoundTrip(hermes); + */ + /* + std::vector code; + std::string text_orig; + File::ReadFileToString("testdata/dsp_test.S", &text_orig); + if (!Assemble(text_orig.c_str(), &code)) + { + printf("SuperTrip: First assembly failed\n"); + return; + }*/ - /* - { - std::vector code; - code.clear(); - for (int i = 0; i < sizeof(dsp_test)/4; i++) - { - code.push_back(dsp_test[i] >> 16); - code.push_back(dsp_test[i] & 0xFFFF); - } + /* + { + std::vector code; + code.clear(); + for (int i = 0; i < sizeof(dsp_test)/4; i++) + { + code.push_back(dsp_test[i] >> 16); + code.push_back(dsp_test[i] & 0xFFFF); + } - SaveBinary(code, "dsp_test2.bin"); - RoundTrip(code); - }*/ - //if (Compare(code, hermes)) - // printf("Successs\n"); -/* - { - std::vector code; - std::string text; - LoadBinary("testdata/dsp_test.bin", &code); - Disassemble(code, true, &text); - Assemble(text.c_str(), &code); - Disassemble(code, true, &text); - printf("%s", text.c_str()); - }*/ - /* - puts("Insane Random Code Test\n"); - std::vector rand_code; - GenRandomCode(30, &rand_code); - std::string rand_code_text; - Disassemble(rand_code, true, &rand_code_text); - printf("%s", rand_code_text.c_str()); - RoundTrip(rand_code); + SaveBinary(code, "dsp_test2.bin"); + RoundTrip(code); + }*/ + // if (Compare(code, hermes)) + // printf("Successs\n"); + /* + { + std::vector code; + std::string text; + LoadBinary("testdata/dsp_test.bin", &code); + Disassemble(code, true, &text); + Assemble(text.c_str(), &code); + Disassemble(code, true, &text); + printf("%s", text.c_str()); + }*/ + /* + puts("Insane Random Code Test\n"); + std::vector rand_code; + GenRandomCode(30, &rand_code); + std::string rand_code_text; + Disassemble(rand_code, true, &rand_code_text); + printf("%s", rand_code_text.c_str()); + RoundTrip(rand_code); - if (File::ReadFileToString("C:/devkitPro/examples/wii/asndlib/dsptest/dsp_test.ds", &dsp_test)) - SuperTrip(dsp_test.c_str()); + if (File::ReadFileToString("C:/devkitPro/examples/wii/asndlib/dsptest/dsp_test.ds", &dsp_test)) + SuperTrip(dsp_test.c_str()); - //.File::ReadFileToString("C:/devkitPro/trunk/libogc/libasnd/dsp_mixer/dsp_mixer.s", &dsp_test); - // This is CLOSE to working. Sorry about the local path btw. This is preliminary code. + //.File::ReadFileToString("C:/devkitPro/trunk/libogc/libasnd/dsp_mixer/dsp_mixer.s", &dsp_test); + // This is CLOSE to working. Sorry about the local path btw. This is preliminary code. */ - std::string dsp_test; - if (File::ReadFileToString("Testdata/dsp_test.s", dsp_test)) - fail = fail || !SuperTrip(dsp_test.c_str()); - if (!fail) - printf("All passed!\n"); + std::string dsp_test; + if (File::ReadFileToString("Testdata/dsp_test.s", dsp_test)) + fail = fail || !SuperTrip(dsp_test.c_str()); + if (!fail) + printf("All passed!\n"); } - // Usage: // Run internal tests: // dsptool test @@ -199,302 +219,321 @@ static void RunAsmTests() // Print results from DSPSpy register dump // dsptool -p dsp_dump0.bin // So far, all this binary can do is test partially that itself works correctly. -int main(int argc, const char *argv[]) +int main(int argc, const char* argv[]) { - if (argc == 1 || (argc == 2 && (!strcmp(argv[1], "--help") || (!strcmp(argv[1], "-?"))))) - { - printf("USAGE: DSPTool [-?] [--help] [-f] [-d] [-m] [-p ] [-o ] [-h ] \n"); - printf("-? / --help: Prints this message\n"); - printf("-d: Disassemble\n"); - printf("-m: Input file contains a list of files (Header assembly only)\n"); - printf("-s: Print the final size in bytes (only)\n"); - printf("-f: Force assembly (errors are not critical)\n"); - printf("-o : Results from stdout redirected to a file\n"); - printf("-h

: Output assembly results to a header\n"); - printf("-p : Print results of DSPSpy register dump\n"); - printf("-ps : Print results of DSPSpy register dump (disable SR output)\n"); - printf("-pm : Print results of DSPSpy register dump (convert PROD values)\n"); - printf("-psm : Print results of DSPSpy register dump (convert PROD values/disable SR output)\n"); + if (argc == 1 || (argc == 2 && (!strcmp(argv[1], "--help") || (!strcmp(argv[1], "-?"))))) + { + printf("USAGE: DSPTool [-?] [--help] [-f] [-d] [-m] [-p ] [-o ] [-h ] \n"); + printf("-? / --help: Prints this message\n"); + printf("-d: Disassemble\n"); + printf("-m: Input file contains a list of files (Header assembly only)\n"); + printf("-s: Print the final size in bytes (only)\n"); + printf("-f: Force assembly (errors are not critical)\n"); + printf("-o : Results from stdout redirected to a file\n"); + printf("-h
: Output assembly results to a header\n"); + printf("-p : Print results of DSPSpy register dump\n"); + printf("-ps : Print results of DSPSpy register dump (disable SR output)\n"); + printf("-pm : Print results of DSPSpy register dump (convert PROD values)\n"); + printf("-psm : Print results of DSPSpy register dump (convert PROD values/disable " + "SR output)\n"); - return 0; - } + return 0; + } - if (argc == 2 && !strcmp(argv[1], "test")) - { - RunAsmTests(); - return 0; - } + if (argc == 2 && !strcmp(argv[1], "test")) + { + RunAsmTests(); + return 0; + } - std::string input_name; - std::string output_header_name; - std::string output_name; + std::string input_name; + std::string output_header_name; + std::string output_name; - bool disassemble = false, compare = false, multiple = false, outputSize = false, - force = false, print_results = false, print_results_prodhack = false, print_results_srhack = false; - for (int i = 1; i < argc; i++) - { - if (!strcmp(argv[i], "-d")) - disassemble = true; - else if (!strcmp(argv[i], "-o")) - output_name = argv[++i]; - else if (!strcmp(argv[i], "-h")) - output_header_name = argv[++i]; - else if (!strcmp(argv[i], "-c")) - compare = true; - else if (!strcmp(argv[i], "-s")) - outputSize = true; - else if (!strcmp(argv[i], "-m")) - multiple = true; - else if (!strcmp(argv[i], "-f")) - force = true; - else if (!strcmp(argv[i], "-p")) - print_results = true; - else if (!strcmp(argv[i], "-ps")) { - print_results = true; - print_results_srhack = true; - } - else if (!strcmp(argv[i], "-pm")) { - print_results = true; - print_results_prodhack = true; - } - else if (!strcmp(argv[i], "-psm")) { - print_results = true; - print_results_srhack = true; - print_results_prodhack = true; - } - else - { - if (!input_name.empty()) - { - printf("ERROR: Can only take one input file.\n"); - return 1; - } - input_name = argv[i]; - if (!File::Exists(input_name)) - { - printf("ERROR: Input path does not exist.\n"); - return 1; - } - } - } + bool disassemble = false, compare = false, multiple = false, outputSize = false, force = false, + print_results = false, print_results_prodhack = false, print_results_srhack = false; + for (int i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "-d")) + disassemble = true; + else if (!strcmp(argv[i], "-o")) + output_name = argv[++i]; + else if (!strcmp(argv[i], "-h")) + output_header_name = argv[++i]; + else if (!strcmp(argv[i], "-c")) + compare = true; + else if (!strcmp(argv[i], "-s")) + outputSize = true; + else if (!strcmp(argv[i], "-m")) + multiple = true; + else if (!strcmp(argv[i], "-f")) + force = true; + else if (!strcmp(argv[i], "-p")) + print_results = true; + else if (!strcmp(argv[i], "-ps")) + { + print_results = true; + print_results_srhack = true; + } + else if (!strcmp(argv[i], "-pm")) + { + print_results = true; + print_results_prodhack = true; + } + else if (!strcmp(argv[i], "-psm")) + { + print_results = true; + print_results_srhack = true; + print_results_prodhack = true; + } + else + { + if (!input_name.empty()) + { + printf("ERROR: Can only take one input file.\n"); + return 1; + } + input_name = argv[i]; + if (!File::Exists(input_name)) + { + printf("ERROR: Input path does not exist.\n"); + return 1; + } + } + } - if (multiple && (compare || disassemble || !output_name.empty() || - input_name.empty())) { - printf("ERROR: Multiple files can only be used with assembly " - "and must compile a header file.\n"); - return 1; - } + if (multiple && (compare || disassemble || !output_name.empty() || input_name.empty())) + { + printf("ERROR: Multiple files can only be used with assembly " + "and must compile a header file.\n"); + return 1; + } - if (compare) - { - // Two binary inputs, let's diff. - std::string binary_code; - std::vector code1, code2; - File::ReadFileToString(input_name.c_str(), binary_code); - BinaryStringBEToCode(binary_code, code1); - File::ReadFileToString(output_name.c_str(), binary_code); - BinaryStringBEToCode(binary_code, code2); - Compare(code1, code2); - return 0; - } + if (compare) + { + // Two binary inputs, let's diff. + std::string binary_code; + std::vector code1, code2; + File::ReadFileToString(input_name.c_str(), binary_code); + BinaryStringBEToCode(binary_code, code1); + File::ReadFileToString(output_name.c_str(), binary_code); + BinaryStringBEToCode(binary_code, code2); + Compare(code1, code2); + return 0; + } - if (print_results) - { - std::string dumpfile, results; - std::vector reg_vector; + if (print_results) + { + std::string dumpfile, results; + std::vector reg_vector; - File::ReadFileToString(input_name.c_str(), dumpfile); - BinaryStringBEToCode(dumpfile, reg_vector); + File::ReadFileToString(input_name.c_str(), dumpfile); + BinaryStringBEToCode(dumpfile, reg_vector); - results.append("Start:\n"); - for (int initial_reg = 0; initial_reg < 32; initial_reg++) - { - results.append(StringFromFormat("%02x %04x ", initial_reg, reg_vector.at(initial_reg))); - if ((initial_reg + 1) % 8 == 0) - results.append("\n"); - } - results.append("\n"); - results.append("Step [number]:\n[Reg] [last value] [current value]\n\n"); - for (unsigned int step = 1; step < reg_vector.size()/32; step++) - { - bool changed = false; - u16 current_reg; - u16 last_reg; - u32 htemp; - //results.append(StringFromFormat("Step %3d: (CW 0x%04x) UC:%03d\n", step, 0x8fff+step, (step-1)/32)); - results.append(StringFromFormat("Step %3d:\n", step)); - for (int reg = 0; reg < 32; reg++) - { - if ((reg >= 0x0c) && (reg <= 0x0f)) continue; - if (print_results_srhack && (reg == 0x13)) continue; + results.append("Start:\n"); + for (int initial_reg = 0; initial_reg < 32; initial_reg++) + { + results.append(StringFromFormat("%02x %04x ", initial_reg, reg_vector.at(initial_reg))); + if ((initial_reg + 1) % 8 == 0) + results.append("\n"); + } + results.append("\n"); + results.append("Step [number]:\n[Reg] [last value] [current value]\n\n"); + for (unsigned int step = 1; step < reg_vector.size() / 32; step++) + { + bool changed = false; + u16 current_reg; + u16 last_reg; + u32 htemp; + // results.append(StringFromFormat("Step %3d: (CW 0x%04x) UC:%03d\n", step, 0x8fff+step, + // (step-1)/32)); + results.append(StringFromFormat("Step %3d:\n", step)); + for (int reg = 0; reg < 32; reg++) + { + if ((reg >= 0x0c) && (reg <= 0x0f)) + continue; + if (print_results_srhack && (reg == 0x13)) + continue; - if ((print_results_prodhack) && (reg >= 0x15) && (reg <= 0x17)) { - switch (reg) { - case 0x15: //DSP_REG_PRODM - last_reg = reg_vector.at((step*32-32)+reg) + reg_vector.at((step*32-32)+reg+2); - current_reg = reg_vector.at(step*32+reg) + reg_vector.at(step*32+reg+2); - break; - case 0x16: //DSP_REG_PRODH - htemp = ((reg_vector.at(step*32+reg-1) + reg_vector.at(step*32+reg+1))&~0xffff)>>16; - current_reg = (u8)(reg_vector.at(step*32+reg) + htemp); - htemp = ((reg_vector.at(step*32-32+reg-1) + reg_vector.at(step*32-32+reg+1))&~0xffff)>>16; - last_reg = (u8)(reg_vector.at(step*32-32+reg) + htemp); - break; - case 0x17: //DSP_REG_PRODM2 - default: - current_reg = 0; - last_reg = 0; - break; - } - } - else { - current_reg = reg_vector.at(step*32+reg); - last_reg = reg_vector.at((step*32-32)+reg); - } - if (last_reg != current_reg) - { - results.append(StringFromFormat("%02x %-7s: %04x %04x\n", reg, pdregname(reg), last_reg, current_reg)); - changed = true; - } - } - if (!changed) - results.append("No Change\n\n"); - else - results.append("\n"); - } + if ((print_results_prodhack) && (reg >= 0x15) && (reg <= 0x17)) + { + switch (reg) + { + case 0x15: // DSP_REG_PRODM + last_reg = + reg_vector.at((step * 32 - 32) + reg) + reg_vector.at((step * 32 - 32) + reg + 2); + current_reg = reg_vector.at(step * 32 + reg) + reg_vector.at(step * 32 + reg + 2); + break; + case 0x16: // DSP_REG_PRODH + htemp = ((reg_vector.at(step * 32 + reg - 1) + reg_vector.at(step * 32 + reg + 1)) & + ~0xffff) >> + 16; + current_reg = (u8)(reg_vector.at(step * 32 + reg) + htemp); + htemp = ((reg_vector.at(step * 32 - 32 + reg - 1) + + reg_vector.at(step * 32 - 32 + reg + 1)) & + ~0xffff) >> + 16; + last_reg = (u8)(reg_vector.at(step * 32 - 32 + reg) + htemp); + break; + case 0x17: // DSP_REG_PRODM2 + default: + current_reg = 0; + last_reg = 0; + break; + } + } + else + { + current_reg = reg_vector.at(step * 32 + reg); + last_reg = reg_vector.at((step * 32 - 32) + reg); + } + if (last_reg != current_reg) + { + results.append(StringFromFormat("%02x %-7s: %04x %04x\n", reg, pdregname(reg), last_reg, + current_reg)); + changed = true; + } + } + if (!changed) + results.append("No Change\n\n"); + else + results.append("\n"); + } - if (!output_name.empty()) - File::WriteStringToFile(results, output_name.c_str()); - else - printf("%s", results.c_str()); - return 0; - } + if (!output_name.empty()) + File::WriteStringToFile(results, output_name.c_str()); + else + printf("%s", results.c_str()); + return 0; + } - if (disassemble) - { - if (input_name.empty()) - { - printf("Disassemble: Must specify input.\n"); - return 1; - } - std::string binary_code; - std::vector code; - File::ReadFileToString(input_name.c_str(), binary_code); - BinaryStringBEToCode(binary_code, code); - std::string text; - Disassemble(code, true, text); - if (!output_name.empty()) - File::WriteStringToFile(text, output_name.c_str()); - else - printf("%s", text.c_str()); - } - else - { - if (input_name.empty()) - { - printf("Assemble: Must specify input.\n"); - return 1; - } - std::string source; - if (File::ReadFileToString(input_name.c_str(), source)) - { - if (multiple) - { - // When specifying a list of files we must compile a header - // (we can't assemble multiple files to one binary) - // since we checked it before, we assume output_header_name isn't empty - int lines; - std::vector *codes; - std::vector files; - std::string header, currentSource; - size_t lastPos = 0, pos = 0; + if (disassemble) + { + if (input_name.empty()) + { + printf("Disassemble: Must specify input.\n"); + return 1; + } + std::string binary_code; + std::vector code; + File::ReadFileToString(input_name.c_str(), binary_code); + BinaryStringBEToCode(binary_code, code); + std::string text; + Disassemble(code, true, text); + if (!output_name.empty()) + File::WriteStringToFile(text, output_name.c_str()); + else + printf("%s", text.c_str()); + } + else + { + if (input_name.empty()) + { + printf("Assemble: Must specify input.\n"); + return 1; + } + std::string source; + if (File::ReadFileToString(input_name.c_str(), source)) + { + if (multiple) + { + // When specifying a list of files we must compile a header + // (we can't assemble multiple files to one binary) + // since we checked it before, we assume output_header_name isn't empty + int lines; + std::vector* codes; + std::vector files; + std::string header, currentSource; + size_t lastPos = 0, pos = 0; - source.append("\n"); + source.append("\n"); - while ((pos = source.find('\n', lastPos)) != std::string::npos) - { - std::string temp = source.substr(lastPos, pos - lastPos); - if (!temp.empty()) - files.push_back(temp); - lastPos = pos + 1; - } + while ((pos = source.find('\n', lastPos)) != std::string::npos) + { + std::string temp = source.substr(lastPos, pos - lastPos); + if (!temp.empty()) + files.push_back(temp); + lastPos = pos + 1; + } - lines = (int)files.size(); + lines = (int)files.size(); - if (lines == 0) - { - printf("ERROR: Must specify at least one file\n"); - return 1; - } + if (lines == 0) + { + printf("ERROR: Must specify at least one file\n"); + return 1; + } - codes = new std::vector[lines]; + codes = new std::vector[lines]; - for (int i = 0; i < lines; i++) - { - if (!File::ReadFileToString(files[i].c_str(), currentSource)) - { - printf("ERROR reading %s, skipping...\n", files[i].c_str()); - lines--; - } - else - { - if (!Assemble(currentSource.c_str(), codes[i], force)) - { - printf("Assemble: Assembly of %s failed due to errors\n", - files[i].c_str()); - lines--; - } - if (outputSize) { - printf("%s: %d\n", files[i].c_str(), (int)codes[i].size()); - } - } - } + for (int i = 0; i < lines; i++) + { + if (!File::ReadFileToString(files[i].c_str(), currentSource)) + { + printf("ERROR reading %s, skipping...\n", files[i].c_str()); + lines--; + } + else + { + if (!Assemble(currentSource.c_str(), codes[i], force)) + { + printf("Assemble: Assembly of %s failed due to errors\n", files[i].c_str()); + lines--; + } + if (outputSize) + { + printf("%s: %d\n", files[i].c_str(), (int)codes[i].size()); + } + } + } + CodesToHeader(codes, &files, lines, output_header_name.c_str(), header); + File::WriteStringToFile(header, (output_header_name + ".h").c_str()); - CodesToHeader(codes, &files, lines, output_header_name.c_str(), header); - File::WriteStringToFile(header, (output_header_name + ".h").c_str()); + delete[] codes; + } + else + { + std::vector code; - delete[] codes; - } - else - { - std::vector code; + if (!Assemble(source.c_str(), code, force)) + { + printf("Assemble: Assembly failed due to errors\n"); + return 1; + } - if (!Assemble(source.c_str(), code, force)) { - printf("Assemble: Assembly failed due to errors\n"); - return 1; - } + if (outputSize) + { + printf("%s: %d\n", input_name.c_str(), (int)code.size()); + } - if (outputSize) { - printf("%s: %d\n", input_name.c_str(), (int)code.size()); - } + if (!output_name.empty()) + { + std::string binary_code; + CodeToBinaryStringBE(code, binary_code); + File::WriteStringToFile(binary_code, output_name.c_str()); + } + if (!output_header_name.empty()) + { + std::string header; + CodeToHeader(code, input_name, output_header_name.c_str(), header); + File::WriteStringToFile(header, (output_header_name + ".h").c_str()); + } + } + } + source.clear(); + } - if (!output_name.empty()) - { - std::string binary_code; - CodeToBinaryStringBE(code, binary_code); - File::WriteStringToFile(binary_code, output_name.c_str()); - } - if (!output_header_name.empty()) - { - std::string header; - CodeToHeader(code, input_name, output_header_name.c_str(), header); - File::WriteStringToFile(header, (output_header_name + ".h").c_str()); - } - } - } - source.clear(); - } + if (disassemble) + { + printf("Disassembly completed successfully!\n"); + } + else + { + if (!outputSize) + printf("Assembly completed successfully!\n"); + } - if (disassemble) - { - printf("Disassembly completed successfully!\n"); - } - else - { - if (!outputSize) - printf("Assembly completed successfully!\n"); - } - - return 0; + return 0; } diff --git a/Source/PCH/pch.h b/Source/PCH/pch.h index 1ea2279f39..992a15ef29 100644 --- a/Source/PCH/pch.h +++ b/Source/PCH/pch.h @@ -31,14 +31,14 @@ #endif #include #include -#include #include +#include #include #include #include #include -#include #include +#include #include #include #ifndef _WIN32 diff --git a/Source/UnitTests/Common/BitFieldTest.cpp b/Source/UnitTests/Common/BitFieldTest.cpp index cb49e24cf3..5c7e4a0ccf 100644 --- a/Source/UnitTests/Common/BitFieldTest.cpp +++ b/Source/UnitTests/Common/BitFieldTest.cpp @@ -7,164 +7,159 @@ #include "Common/BitField.h" #include "Common/CommonTypes.h" -union TestUnion -{ - u64 hex; +union TestUnion { + u64 hex; - BitField< 0,64,u64> full_u64; // spans whole storage - BitField< 0,64,s64> full_s64; // spans whole storage + BitField<0, 64, u64> full_u64; // spans whole storage + BitField<0, 64, s64> full_s64; // spans whole storage - BitField< 9, 3,u64> regular_field_unsigned; // a plain bitfield - BitField< 9, 3,u64> regular_field_unsigned2; // Just the very same bitfield again - BitField< 9, 3,s64> regular_field_signed; // Same bitfield, but different sign + BitField<9, 3, u64> regular_field_unsigned; // a plain bitfield + BitField<9, 3, u64> regular_field_unsigned2; // Just the very same bitfield again + BitField<9, 3, s64> regular_field_signed; // Same bitfield, but different sign - BitField<30, 4,s64> at_dword_boundary; // goes over the boundary of two u32 values + BitField<30, 4, s64> at_dword_boundary; // goes over the boundary of two u32 values - BitField<15, 1,s64> signed_1bit; // allowed values: -1 and 0 + BitField<15, 1, s64> signed_1bit; // allowed values: -1 and 0 }; // table of raw numbers to test with -static u64 table[] = -{ - 0x0000000000000000ull, // all zero - 0xffffffffffffffffull, // all one - 0x7fffffffffffffffull, // all one apart from the sign bit - 0x8000000000000000ull, // all zero apart from the sign bit - 0x8000000000000048ull, // regular_field = 0b1001 +static u64 table[] = { + 0x0000000000000000ull, // all zero + 0xffffffffffffffffull, // all one + 0x7fffffffffffffffull, // all one apart from the sign bit + 0x8000000000000000ull, // all zero apart from the sign bit + 0x8000000000000048ull, // regular_field = 0b1001 - // "random" numbers - 0x0F7B8B1ABD9B8D3Full, - 0xA8B86F73FDAADD2Dull, - 0x1B17A557BFEB351Dull, - 0xE3354268B0C2395Bull, + // "random" numbers + 0x0F7B8B1ABD9B8D3Full, 0xA8B86F73FDAADD2Dull, 0x1B17A557BFEB351Dull, 0xE3354268B0C2395Bull, }; // Verify that bitfields in a union have the same underlying data TEST(BitField, Storage) { - TestUnion object; + TestUnion object; - EXPECT_EQ((void*)&object.hex, (void*)&object.regular_field_unsigned); - EXPECT_EQ(sizeof(TestUnion), sizeof(object.hex)); - EXPECT_EQ(sizeof(TestUnion), sizeof(object.full_u64)); - EXPECT_EQ(sizeof(TestUnion), sizeof(object.full_s64)); - EXPECT_EQ(sizeof(TestUnion), sizeof(object.regular_field_unsigned)); - EXPECT_EQ(sizeof(TestUnion), sizeof(object.regular_field_signed)); - EXPECT_EQ(sizeof(TestUnion), sizeof(object.at_dword_boundary)); - EXPECT_EQ(sizeof(TestUnion), sizeof(object.signed_1bit)); + EXPECT_EQ((void*)&object.hex, (void*)&object.regular_field_unsigned); + EXPECT_EQ(sizeof(TestUnion), sizeof(object.hex)); + EXPECT_EQ(sizeof(TestUnion), sizeof(object.full_u64)); + EXPECT_EQ(sizeof(TestUnion), sizeof(object.full_s64)); + EXPECT_EQ(sizeof(TestUnion), sizeof(object.regular_field_unsigned)); + EXPECT_EQ(sizeof(TestUnion), sizeof(object.regular_field_signed)); + EXPECT_EQ(sizeof(TestUnion), sizeof(object.at_dword_boundary)); + EXPECT_EQ(sizeof(TestUnion), sizeof(object.signed_1bit)); - // Now write some values to one field and check if this reflects properly - // in the others. - for (u64 val : table) - { - object.hex = val; - EXPECT_EQ(object.hex, object.full_u64); - EXPECT_EQ(object.regular_field_unsigned, object.regular_field_unsigned2); + // Now write some values to one field and check if this reflects properly + // in the others. + for (u64 val : table) + { + object.hex = val; + EXPECT_EQ(object.hex, object.full_u64); + EXPECT_EQ(object.regular_field_unsigned, object.regular_field_unsigned2); - object.regular_field_unsigned = val & 0x3; - EXPECT_EQ(object.hex, object.full_u64); - EXPECT_EQ(object.regular_field_unsigned, object.regular_field_unsigned2); - } + object.regular_field_unsigned = val & 0x3; + EXPECT_EQ(object.hex, object.full_u64); + EXPECT_EQ(object.regular_field_unsigned, object.regular_field_unsigned2); + } } TEST(BitField, Read) { - TestUnion object; + TestUnion object; - for (u64 val : table) - { - object.hex = val; + for (u64 val : table) + { + object.hex = val; - // Make sure reading/casting does not behave completely idiotic - EXPECT_EQ(object.full_u64, (u64)object.full_u64); - EXPECT_EQ(object.full_s64, (s64)object.full_s64); - EXPECT_EQ(object.regular_field_unsigned, (u64)object.regular_field_unsigned); - EXPECT_EQ(object.regular_field_unsigned2, (u64)object.regular_field_unsigned2); - EXPECT_EQ(object.regular_field_signed, (s64)object.regular_field_signed); - EXPECT_EQ(object.at_dword_boundary, (s64)object.at_dword_boundary); - EXPECT_EQ(object.signed_1bit, (s64)object.signed_1bit); + // Make sure reading/casting does not behave completely idiotic + EXPECT_EQ(object.full_u64, (u64)object.full_u64); + EXPECT_EQ(object.full_s64, (s64)object.full_s64); + EXPECT_EQ(object.regular_field_unsigned, (u64)object.regular_field_unsigned); + EXPECT_EQ(object.regular_field_unsigned2, (u64)object.regular_field_unsigned2); + EXPECT_EQ(object.regular_field_signed, (s64)object.regular_field_signed); + EXPECT_EQ(object.at_dword_boundary, (s64)object.at_dword_boundary); + EXPECT_EQ(object.signed_1bit, (s64)object.signed_1bit); - // Now make sure the value is indeed correct - EXPECT_EQ(val, object.full_u64); - EXPECT_EQ(*(s64*)&val, object.full_s64); - EXPECT_EQ((val >> 9) & 0x7, object.regular_field_unsigned); - EXPECT_EQ((val >> 9) & 0x7, object.regular_field_unsigned2); - EXPECT_EQ(((s64)(object.hex << 52)) >> 61, object.regular_field_signed); - EXPECT_EQ(((s64)(object.hex << 30)) >> 60, object.at_dword_boundary); - EXPECT_EQ(((object.hex >> 15) & 1) ? -1 : 0, object.signed_1bit); - } + // Now make sure the value is indeed correct + EXPECT_EQ(val, object.full_u64); + EXPECT_EQ(*(s64*)&val, object.full_s64); + EXPECT_EQ((val >> 9) & 0x7, object.regular_field_unsigned); + EXPECT_EQ((val >> 9) & 0x7, object.regular_field_unsigned2); + EXPECT_EQ(((s64)(object.hex << 52)) >> 61, object.regular_field_signed); + EXPECT_EQ(((s64)(object.hex << 30)) >> 60, object.at_dword_boundary); + EXPECT_EQ(((object.hex >> 15) & 1) ? -1 : 0, object.signed_1bit); + } } TEST(BitField, Assignment) { - TestUnion object; + TestUnion object; - for (u64 val : table) - { - // Assignments with fixed values - object.full_u64 = val; - EXPECT_EQ(val, object.full_u64); + for (u64 val : table) + { + // Assignments with fixed values + object.full_u64 = val; + EXPECT_EQ(val, object.full_u64); - object.full_s64 = (s64)val; - EXPECT_EQ(val, object.full_u64); + object.full_s64 = (s64)val; + EXPECT_EQ(val, object.full_u64); - object.regular_field_unsigned = val; - EXPECT_EQ(val & 0x7, object.regular_field_unsigned); + object.regular_field_unsigned = val; + EXPECT_EQ(val & 0x7, object.regular_field_unsigned); - object.at_dword_boundary = val; - EXPECT_EQ(((s64)(val << 60)) >> 60, object.at_dword_boundary); + object.at_dword_boundary = val; + EXPECT_EQ(((s64)(val << 60)) >> 60, object.at_dword_boundary); - object.signed_1bit = val; - EXPECT_EQ((val & 1) ? -1 : 0, object.signed_1bit); + object.signed_1bit = val; + EXPECT_EQ((val & 1) ? -1 : 0, object.signed_1bit); - object.regular_field_signed = val; - EXPECT_EQ(((s64)(object.hex << 61)) >> 61, object.regular_field_signed); + object.regular_field_signed = val; + EXPECT_EQ(((s64)(object.hex << 61)) >> 61, object.regular_field_signed); - // Assignment from other BitField - object.at_dword_boundary = object.regular_field_signed; - EXPECT_EQ(object.regular_field_signed, object.at_dword_boundary); - } + // Assignment from other BitField + object.at_dword_boundary = object.regular_field_signed; + EXPECT_EQ(object.regular_field_signed, object.at_dword_boundary); + } } // Test class behavior on oddly aligned structures. TEST(BitField, Alignment) { - #pragma pack(1) - struct OddlyAlignedTestStruct - { - u8 padding; - TestUnion obj; - }; - #pragma pack() +#pragma pack(1) + struct OddlyAlignedTestStruct + { + u8 padding; + TestUnion obj; + }; +#pragma pack() - alignas(16) OddlyAlignedTestStruct test_struct; - TestUnion& object = test_struct.obj; - static_assert(alignof(decltype(test_struct.obj.signed_1bit)) == 1, - "Incorrect variable alignment"); + alignas(16) OddlyAlignedTestStruct test_struct; + TestUnion& object = test_struct.obj; + static_assert(alignof(decltype(test_struct.obj.signed_1bit)) == 1, + "Incorrect variable alignment"); - for (u64 val : table) - { - // Assignments with fixed values - object.full_u64 = val; - EXPECT_EQ(val, object.full_u64); + for (u64 val : table) + { + // Assignments with fixed values + object.full_u64 = val; + EXPECT_EQ(val, object.full_u64); - object.full_s64 = (s64)val; - EXPECT_EQ(val, object.full_u64); + object.full_s64 = (s64)val; + EXPECT_EQ(val, object.full_u64); - object.regular_field_unsigned = val; - EXPECT_EQ(val & 0x7, object.regular_field_unsigned); + object.regular_field_unsigned = val; + EXPECT_EQ(val & 0x7, object.regular_field_unsigned); - object.at_dword_boundary = val; - EXPECT_EQ(((s64)(val << 60)) >> 60, object.at_dword_boundary); + object.at_dword_boundary = val; + EXPECT_EQ(((s64)(val << 60)) >> 60, object.at_dword_boundary); - object.signed_1bit = val; - EXPECT_EQ((val & 1) ? -1 : 0, object.signed_1bit); + object.signed_1bit = val; + EXPECT_EQ((val & 1) ? -1 : 0, object.signed_1bit); - object.regular_field_signed = val; - EXPECT_EQ(((s64)(object.hex << 61)) >> 61, object.regular_field_signed); + object.regular_field_signed = val; + EXPECT_EQ(((s64)(object.hex << 61)) >> 61, object.regular_field_signed); - // Assignment from other BitField - object.at_dword_boundary = object.regular_field_signed; - EXPECT_EQ(object.regular_field_signed, object.at_dword_boundary); - } + // Assignment from other BitField + object.at_dword_boundary = object.regular_field_signed; + EXPECT_EQ(object.regular_field_signed, object.at_dword_boundary); + } } diff --git a/Source/UnitTests/Common/BitSetTest.cpp b/Source/UnitTests/Common/BitSetTest.cpp index bac48eff76..dddd8f49d5 100644 --- a/Source/UnitTests/Common/BitSetTest.cpp +++ b/Source/UnitTests/Common/BitSetTest.cpp @@ -8,77 +8,75 @@ TEST(BitSet, Basics) { - BitSet32 bs; - BitSet64 bs2(1); - BitSet64 bs3(2); - EXPECT_EQ(true, !!bs2); - EXPECT_EQ(false, !!bs); - EXPECT_EQ(bs2, bs2); - EXPECT_NE(bs2, bs3); - EXPECT_EQ(BitSet32(0xfff), BitSet32::AllTrue(12)); - EXPECT_EQ(BitSet64(0xffffffffffffffff), BitSet64::AllTrue(64)); + BitSet32 bs; + BitSet64 bs2(1); + BitSet64 bs3(2); + EXPECT_EQ(true, !!bs2); + EXPECT_EQ(false, !!bs); + EXPECT_EQ(bs2, bs2); + EXPECT_NE(bs2, bs3); + EXPECT_EQ(BitSet32(0xfff), BitSet32::AllTrue(12)); + EXPECT_EQ(BitSet64(0xffffffffffffffff), BitSet64::AllTrue(64)); } TEST(BitSet, BitGetSet) { - BitSet32 bs; - bs[3] = bs[8] = bs[11] = true; - EXPECT_EQ(true, bs[3]); - EXPECT_EQ(false, bs[4]); - EXPECT_EQ((u32)((1 << 3) | (1 << 8) | (1 << 11)), bs.m_val); + BitSet32 bs; + bs[3] = bs[8] = bs[11] = true; + EXPECT_EQ(true, bs[3]); + EXPECT_EQ(false, bs[4]); + EXPECT_EQ((u32)((1 << 3) | (1 << 8) | (1 << 11)), bs.m_val); } TEST(BitSet, Count) { - u32 random_numbers[] = { - 0x2cb0b5f3, 0x81ab32a6, 0xd9030dc5, 0x325ffe26, 0xb2fcaee3, - 0x4ccf188a, 0xf8be36dc, 0xb2fcecd5, 0xb750c2e5, 0x31d19074, - 0xf267644a, 0xac00a719, 0x6d45f19b, 0xf7e91c5b, 0xf687e694, - 0x9057c24e, 0x5eb65c39, 0x85d3038b, 0x101f4e66, 0xc202d136 - }; - u32 counts[] = { - 17, 14, 14, 19, 20, 14, 20, 20, 16, 13, 16, 12, 18, 20, 18, 14, 18, 14, 14, 12 - }; - for (size_t i = 0; i < 20; i++) - { - EXPECT_EQ(counts[i], BitSet32(random_numbers[i]).Count()); - } + u32 random_numbers[] = {0x2cb0b5f3, 0x81ab32a6, 0xd9030dc5, 0x325ffe26, 0xb2fcaee3, + 0x4ccf188a, 0xf8be36dc, 0xb2fcecd5, 0xb750c2e5, 0x31d19074, + 0xf267644a, 0xac00a719, 0x6d45f19b, 0xf7e91c5b, 0xf687e694, + 0x9057c24e, 0x5eb65c39, 0x85d3038b, 0x101f4e66, 0xc202d136}; + u32 counts[] = {17, 14, 14, 19, 20, 14, 20, 20, 16, 13, 16, 12, 18, 20, 18, 14, 18, 14, 14, 12}; + for (size_t i = 0; i < 20; i++) + { + EXPECT_EQ(counts[i], BitSet32(random_numbers[i]).Count()); + } - u64 random_numbers_64[] = { - 0xf86cd6f6ef09d7d4ULL, 0x6f2d8533255ead3cULL, 0x9da7941e0e52b345ULL, - 0x06e4189be67d2b17ULL, 0x3eb0681f65cb6d25ULL, 0xccab8a7c74a51203ULL, - 0x09d470516694c64bULL, 0x38cd077e075c778fULL, 0xd69ebfa6355ebfdeULL - }; - u32 counts_64[] = { - 39, 34, 31, 32, 33, 29, 27, 35, 43 - }; - for (size_t i = 0; i < 9; i++) - { - EXPECT_EQ(counts_64[i], BitSet64(random_numbers_64[i]).Count()); - } + u64 random_numbers_64[] = {0xf86cd6f6ef09d7d4ULL, 0x6f2d8533255ead3cULL, 0x9da7941e0e52b345ULL, + 0x06e4189be67d2b17ULL, 0x3eb0681f65cb6d25ULL, 0xccab8a7c74a51203ULL, + 0x09d470516694c64bULL, 0x38cd077e075c778fULL, 0xd69ebfa6355ebfdeULL}; + u32 counts_64[] = {39, 34, 31, 32, 33, 29, 27, 35, 43}; + for (size_t i = 0; i < 9; i++) + { + EXPECT_EQ(counts_64[i], BitSet64(random_numbers_64[i]).Count()); + } } TEST(BitSet, BitOps) { - BitSet32 a(3), b(5), c; - EXPECT_EQ(BitSet32(7), a | b); - EXPECT_EQ(BitSet32(6), a ^ b); - EXPECT_EQ(BitSet32(1), a & b); - EXPECT_EQ(BitSet32(0xfffffffc), ~a); - c = a; c |= b; EXPECT_EQ(BitSet32(7), c); - c = a; c ^= b; EXPECT_EQ(BitSet32(6), c); - c = a; c &= b; EXPECT_EQ(BitSet32(1), c); + BitSet32 a(3), b(5), c; + EXPECT_EQ(BitSet32(7), a | b); + EXPECT_EQ(BitSet32(6), a ^ b); + EXPECT_EQ(BitSet32(1), a & b); + EXPECT_EQ(BitSet32(0xfffffffc), ~a); + c = a; + c |= b; + EXPECT_EQ(BitSet32(7), c); + c = a; + c ^= b; + EXPECT_EQ(BitSet32(6), c); + c = a; + c &= b; + EXPECT_EQ(BitSet32(1), c); } TEST(BitSet, InitializerListsAndIteration) { - std::vector bits { 1, 10, 15, 17, 20, 30 }; - BitSet32 bs { 1, 10, 15, 17, 20, 30 }; - auto vit = bits.begin(); - for (auto i : bs) - { - EXPECT_NE(vit, bits.end()); - EXPECT_EQ(i, *vit++); - } - EXPECT_EQ(vit, bits.end()); + std::vector bits{1, 10, 15, 17, 20, 30}; + BitSet32 bs{1, 10, 15, 17, 20, 30}; + auto vit = bits.begin(); + for (auto i : bs) + { + EXPECT_NE(vit, bits.end()); + EXPECT_EQ(i, *vit++); + } + EXPECT_EQ(vit, bits.end()); } diff --git a/Source/UnitTests/Common/BlockingLoopTest.cpp b/Source/UnitTests/Common/BlockingLoopTest.cpp index 805aca446c..a131e1546e 100644 --- a/Source/UnitTests/Common/BlockingLoopTest.cpp +++ b/Source/UnitTests/Common/BlockingLoopTest.cpp @@ -11,74 +11,70 @@ TEST(BlockingLoop, MultiThreaded) { - Common::BlockingLoop loop; - std::atomic signaled_a(0); - std::atomic received_a(0); - std::atomic signaled_b(0); - std::atomic received_b(0); - for (int i = 0; i < 100; i++) - { - // Invalidate the current state. - received_a.store(signaled_a.load() + 1); - received_b.store(signaled_b.load() + 123); + Common::BlockingLoop loop; + std::atomic signaled_a(0); + std::atomic received_a(0); + std::atomic signaled_b(0); + std::atomic received_b(0); + for (int i = 0; i < 100; i++) + { + // Invalidate the current state. + received_a.store(signaled_a.load() + 1); + received_b.store(signaled_b.load() + 123); - // Must not block as the loop is stopped. - loop.Wait(); + // Must not block as the loop is stopped. + loop.Wait(); - std::thread loop_thread( - [&]() { - loop.Run( - [&]() { - received_a.store(signaled_a.load()); - received_b.store(signaled_b.load()); - }); - }); + std::thread loop_thread([&]() { + loop.Run([&]() { + received_a.store(signaled_a.load()); + received_b.store(signaled_b.load()); + }); + }); - // Now Wait must block. - loop.Prepare(); + // Now Wait must block. + loop.Prepare(); - // The payload must run at least once on startup. - loop.Wait(); - EXPECT_EQ(signaled_a.load(), received_a.load()); - EXPECT_EQ(signaled_b.load(), received_b.load()); + // The payload must run at least once on startup. + loop.Wait(); + EXPECT_EQ(signaled_a.load(), received_a.load()); + EXPECT_EQ(signaled_b.load(), received_b.load()); - std::thread run_a_thread( - [&]() { - for (int j = 0; j < 100; j++) - { - for (int k = 0; k < 100; k++) - { - signaled_a++; - loop.Wakeup(); - } + std::thread run_a_thread([&]() { + for (int j = 0; j < 100; j++) + { + for (int k = 0; k < 100; k++) + { + signaled_a++; + loop.Wakeup(); + } - loop.Wait(); - EXPECT_EQ(signaled_a.load(), received_a.load()); - } - }); - std::thread run_b_thread( - [&]() { - for (int j = 0; j < 100; j++) - { - for (int k = 0; k < 100; k++) - { - signaled_b++; - loop.Wakeup(); - } + loop.Wait(); + EXPECT_EQ(signaled_a.load(), received_a.load()); + } + }); + std::thread run_b_thread([&]() { + for (int j = 0; j < 100; j++) + { + for (int k = 0; k < 100; k++) + { + signaled_b++; + loop.Wakeup(); + } - loop.Wait(); - EXPECT_EQ(signaled_b.load(), received_b.load()); - } - }); + loop.Wait(); + EXPECT_EQ(signaled_b.load(), received_b.load()); + } + }); - run_a_thread.join(); - run_b_thread.join(); + run_a_thread.join(); + run_b_thread.join(); - loop.Stop(); + loop.Stop(); - // Must not block - loop.Wait(); + // Must not block + loop.Wait(); - loop_thread.join(); - } + loop_thread.join(); + } } diff --git a/Source/UnitTests/Common/BusyLoopTest.cpp b/Source/UnitTests/Common/BusyLoopTest.cpp index 50d11acb31..efa13fec6c 100644 --- a/Source/UnitTests/Common/BusyLoopTest.cpp +++ b/Source/UnitTests/Common/BusyLoopTest.cpp @@ -12,40 +12,34 @@ TEST(BusyLoopTest, MultiThreaded) { - Common::BlockingLoop loop; - Common::Event e; - for (int i = 0; i < 100; i++) - { - loop.Prepare(); - std::thread loop_thread( - [&]() { - loop.Run( - [&]() { - e.Set(); - }); - }); + Common::BlockingLoop loop; + Common::Event e; + for (int i = 0; i < 100; i++) + { + loop.Prepare(); + std::thread loop_thread([&]() { loop.Run([&]() { e.Set(); }); }); - // Ping - Pong - for (int j = 0; j < 10; j++) - { - loop.Wakeup(); - e.Wait(); + // Ping - Pong + for (int j = 0; j < 10; j++) + { + loop.Wakeup(); + e.Wait(); - // Just waste some time. So the main loop did fall back to the sleep state much more likely. - Common::SleepCurrentThread(1); - } + // Just waste some time. So the main loop did fall back to the sleep state much more likely. + Common::SleepCurrentThread(1); + } - for (int j = 0; j < 100; j++) - { - // We normally have to call Wakeup to assure the Event is triggered. - // But this check is for an internal feature of the BlockingLoop. - // It's implemented to fall back to a busy loop regulary. - // If we're in the busy loop, the payload (and so the Event) is called all the time. - //loop.Wakeup(); - e.Wait(); - } + for (int j = 0; j < 100; j++) + { + // We normally have to call Wakeup to assure the Event is triggered. + // But this check is for an internal feature of the BlockingLoop. + // It's implemented to fall back to a busy loop regulary. + // If we're in the busy loop, the payload (and so the Event) is called all the time. + // loop.Wakeup(); + e.Wait(); + } - loop.Stop(); - loop_thread.join(); - } + loop.Stop(); + loop_thread.join(); + } } diff --git a/Source/UnitTests/Common/CommonFuncsTest.cpp b/Source/UnitTests/Common/CommonFuncsTest.cpp index 14762cbc7b..c33dbda8c6 100644 --- a/Source/UnitTests/Common/CommonFuncsTest.cpp +++ b/Source/UnitTests/Common/CommonFuncsTest.cpp @@ -8,33 +8,33 @@ TEST(CommonFuncs, ArraySizeFunction) { - char test[4]; - u32 test2[42]; + char test[4]; + u32 test2[42]; - EXPECT_EQ(4u, ArraySize(test)); - EXPECT_EQ(42u, ArraySize(test2)); + EXPECT_EQ(4u, ArraySize(test)); + EXPECT_EQ(42u, ArraySize(test2)); - (void)test; - (void)test2; + (void)test; + (void)test2; } TEST(CommonFuncs, RoundUpPow2Macro) { - EXPECT_EQ(4, ROUND_UP_POW2(3)); - EXPECT_EQ(4, ROUND_UP_POW2(4)); - EXPECT_EQ(8, ROUND_UP_POW2(6)); - EXPECT_EQ(0x40000000, ROUND_UP_POW2(0x23456789)); + EXPECT_EQ(4, ROUND_UP_POW2(3)); + EXPECT_EQ(4, ROUND_UP_POW2(4)); + EXPECT_EQ(8, ROUND_UP_POW2(6)); + EXPECT_EQ(0x40000000, ROUND_UP_POW2(0x23456789)); } TEST(CommonFuncs, CrashMacro) { - EXPECT_DEATH({ Crash(); }, ""); + EXPECT_DEATH({ Crash(); }, ""); } TEST(CommonFuncs, Swap) { - EXPECT_EQ(0xf0, Common::swap8(0xf0)); - EXPECT_EQ(0x1234, Common::swap16(0x3412)); - EXPECT_EQ(0x12345678u, Common::swap32(0x78563412)); - EXPECT_EQ(0x123456789abcdef0ull, Common::swap64(0xf0debc9a78563412ull)); + EXPECT_EQ(0xf0, Common::swap8(0xf0)); + EXPECT_EQ(0x1234, Common::swap16(0x3412)); + EXPECT_EQ(0x12345678u, Common::swap32(0x78563412)); + EXPECT_EQ(0x123456789abcdef0ull, Common::swap64(0xf0debc9a78563412ull)); } diff --git a/Source/UnitTests/Common/EventTest.cpp b/Source/UnitTests/Common/EventTest.cpp index b3536f7655..aee9a56760 100644 --- a/Source/UnitTests/Common/EventTest.cpp +++ b/Source/UnitTests/Common/EventTest.cpp @@ -2,8 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include #include +#include #include "Common/Event.h" @@ -11,32 +11,33 @@ using Common::Event; TEST(Event, MultiThreaded) { - Event has_sent, can_send; - int shared_obj; - const int ITERATIONS_COUNT = 100000; + Event has_sent, can_send; + int shared_obj; + const int ITERATIONS_COUNT = 100000; - auto sender = [&]() { - for (int i = 0; i < ITERATIONS_COUNT; ++i) - { - can_send.Wait(); - shared_obj = i; - has_sent.Set(); - } - }; + auto sender = [&]() { + for (int i = 0; i < ITERATIONS_COUNT; ++i) + { + can_send.Wait(); + shared_obj = i; + has_sent.Set(); + } + }; - auto receiver = [&]() { - for (int i = 0; i < ITERATIONS_COUNT; ++i) { - has_sent.Wait(); - EXPECT_EQ(i, shared_obj); - can_send.Set(); - } - }; + auto receiver = [&]() { + for (int i = 0; i < ITERATIONS_COUNT; ++i) + { + has_sent.Wait(); + EXPECT_EQ(i, shared_obj); + can_send.Set(); + } + }; - std::thread sender_thread(sender); - std::thread receiver_thread(receiver); + std::thread sender_thread(sender); + std::thread receiver_thread(receiver); - can_send.Set(); + can_send.Set(); - sender_thread.join(); - receiver_thread.join(); + sender_thread.join(); + receiver_thread.join(); } diff --git a/Source/UnitTests/Common/FifoQueueTest.cpp b/Source/UnitTests/Common/FifoQueueTest.cpp index 9fbddfa8a0..e4f3c913c1 100644 --- a/Source/UnitTests/Common/FifoQueueTest.cpp +++ b/Source/UnitTests/Common/FifoQueueTest.cpp @@ -2,66 +2,70 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include #include +#include #include "Common/FifoQueue.h" TEST(FifoQueue, Simple) { - Common::FifoQueue q; + Common::FifoQueue q; - EXPECT_EQ(0u, q.Size()); - EXPECT_TRUE(q.Empty()); + EXPECT_EQ(0u, q.Size()); + EXPECT_TRUE(q.Empty()); - q.Push(1); - EXPECT_EQ(1u, q.Size()); - EXPECT_FALSE(q.Empty()); + q.Push(1); + EXPECT_EQ(1u, q.Size()); + EXPECT_FALSE(q.Empty()); - u32 v; q.Pop(v); - EXPECT_EQ(1u, v); - EXPECT_EQ(0u, q.Size()); - EXPECT_TRUE(q.Empty()); + u32 v; + q.Pop(v); + EXPECT_EQ(1u, v); + EXPECT_EQ(0u, q.Size()); + EXPECT_TRUE(q.Empty()); - // Test the FIFO order. - for (u32 i = 0; i < 1000; ++i) - q.Push(i); - EXPECT_EQ(1000u, q.Size()); - for (u32 i = 0; i < 1000; ++i) - { - u32 v2; q.Pop(v2); - EXPECT_EQ(i, v2); - } - EXPECT_TRUE(q.Empty()); + // Test the FIFO order. + for (u32 i = 0; i < 1000; ++i) + q.Push(i); + EXPECT_EQ(1000u, q.Size()); + for (u32 i = 0; i < 1000; ++i) + { + u32 v2; + q.Pop(v2); + EXPECT_EQ(i, v2); + } + EXPECT_TRUE(q.Empty()); - for (u32 i = 0; i < 1000; ++i) - q.Push(i); - EXPECT_FALSE(q.Empty()); - q.Clear(); - EXPECT_TRUE(q.Empty()); + for (u32 i = 0; i < 1000; ++i) + q.Push(i); + EXPECT_FALSE(q.Empty()); + q.Clear(); + EXPECT_TRUE(q.Empty()); } TEST(FifoQueue, MultiThreaded) { - Common::FifoQueue q; + Common::FifoQueue q; - auto inserter = [&q]() { - for (u32 i = 0; i < 100000; ++i) - q.Push(i); - }; + auto inserter = [&q]() { + for (u32 i = 0; i < 100000; ++i) + q.Push(i); + }; - auto popper = [&q]() { - for (u32 i = 0; i < 100000; ++i) - { - while (q.Empty()); - u32 v; q.Pop(v); - EXPECT_EQ(i, v); - } - }; + auto popper = [&q]() { + for (u32 i = 0; i < 100000; ++i) + { + while (q.Empty()) + ; + u32 v; + q.Pop(v); + EXPECT_EQ(i, v); + } + }; - std::thread popper_thread(popper); - std::thread inserter_thread(inserter); + std::thread popper_thread(popper); + std::thread inserter_thread(inserter); - popper_thread.join(); - inserter_thread.join(); + popper_thread.join(); + inserter_thread.join(); } diff --git a/Source/UnitTests/Common/FixedSizeQueueTest.cpp b/Source/UnitTests/Common/FixedSizeQueueTest.cpp index 370eb0e7e7..1461ad672f 100644 --- a/Source/UnitTests/Common/FixedSizeQueueTest.cpp +++ b/Source/UnitTests/Common/FixedSizeQueueTest.cpp @@ -8,26 +8,26 @@ TEST(FixedSizeQueue, Simple) { - FixedSizeQueue q; + FixedSizeQueue q; - EXPECT_EQ(0u, q.size()); + EXPECT_EQ(0u, q.size()); - q.push(0); - q.push(1); - q.push(2); - q.push(3); - q.push(4); - for (int i = 0; i < 1000; ++i) - { - EXPECT_EQ(i, q.front()); - EXPECT_EQ(i, q.pop_front()); - q.push(i + 5); - } - EXPECT_EQ(1000, q.pop_front()); - EXPECT_EQ(1001, q.pop_front()); - EXPECT_EQ(1002, q.pop_front()); - EXPECT_EQ(1003, q.pop_front()); - EXPECT_EQ(1004, q.pop_front()); + q.push(0); + q.push(1); + q.push(2); + q.push(3); + q.push(4); + for (int i = 0; i < 1000; ++i) + { + EXPECT_EQ(i, q.front()); + EXPECT_EQ(i, q.pop_front()); + q.push(i + 5); + } + EXPECT_EQ(1000, q.pop_front()); + EXPECT_EQ(1001, q.pop_front()); + EXPECT_EQ(1002, q.pop_front()); + EXPECT_EQ(1003, q.pop_front()); + EXPECT_EQ(1004, q.pop_front()); - EXPECT_EQ(0u, q.size()); + EXPECT_EQ(0u, q.size()); } diff --git a/Source/UnitTests/Common/FlagTest.cpp b/Source/UnitTests/Common/FlagTest.cpp index 8d43d10791..ae750029f4 100644 --- a/Source/UnitTests/Common/FlagTest.cpp +++ b/Source/UnitTests/Common/FlagTest.cpp @@ -3,8 +3,8 @@ // Refer to the license.txt file included. #include -#include #include +#include #include "Common/Flag.h" @@ -12,80 +12,83 @@ using Common::Flag; TEST(Flag, Simple) { - Flag f; - EXPECT_FALSE(f.IsSet()); + Flag f; + EXPECT_FALSE(f.IsSet()); - f.Set(); - EXPECT_TRUE(f.IsSet()); + f.Set(); + EXPECT_TRUE(f.IsSet()); - f.Clear(); - EXPECT_FALSE(f.IsSet()); + f.Clear(); + EXPECT_FALSE(f.IsSet()); - f.Set(false); - EXPECT_FALSE(f.IsSet()); + f.Set(false); + EXPECT_FALSE(f.IsSet()); - EXPECT_TRUE(f.TestAndSet()); - EXPECT_TRUE(f.TestAndClear()); + EXPECT_TRUE(f.TestAndSet()); + EXPECT_TRUE(f.TestAndClear()); - Flag f2(true); - EXPECT_TRUE(f2.IsSet()); + Flag f2(true); + EXPECT_TRUE(f2.IsSet()); } TEST(Flag, MultiThreaded) { - Flag f; - int count = 0; - const int ITERATIONS_COUNT = 100000; + Flag f; + int count = 0; + const int ITERATIONS_COUNT = 100000; - auto setter = [&]() { - for (int i = 0; i < ITERATIONS_COUNT; ++i) - { - while (f.IsSet()); - f.Set(); - } - }; + auto setter = [&]() { + for (int i = 0; i < ITERATIONS_COUNT; ++i) + { + while (f.IsSet()) + ; + f.Set(); + } + }; - auto clearer = [&]() { - for (int i = 0; i < ITERATIONS_COUNT; ++i) - { - while (!f.IsSet()); - count++; - f.Clear(); - } - }; + auto clearer = [&]() { + for (int i = 0; i < ITERATIONS_COUNT; ++i) + { + while (!f.IsSet()) + ; + count++; + f.Clear(); + } + }; - std::thread setter_thread(setter); - std::thread clearer_thread(clearer); + std::thread setter_thread(setter); + std::thread clearer_thread(clearer); - setter_thread.join(); - clearer_thread.join(); + setter_thread.join(); + clearer_thread.join(); - EXPECT_EQ(ITERATIONS_COUNT, count); + EXPECT_EQ(ITERATIONS_COUNT, count); } TEST(Flag, SpinLock) { - // Uses a flag to implement basic spinlocking using TestAndSet. - Flag f; - int count = 0; - const int ITERATIONS_COUNT = 5000; - const int THREADS_COUNT = 50; + // Uses a flag to implement basic spinlocking using TestAndSet. + Flag f; + int count = 0; + const int ITERATIONS_COUNT = 5000; + const int THREADS_COUNT = 50; - auto adder_func = [&]() { - for (int i = 0; i < ITERATIONS_COUNT; ++i) - { - // Acquire the spinlock. - while (!f.TestAndSet()); - count++; - f.Clear(); - } - }; + auto adder_func = [&]() { + for (int i = 0; i < ITERATIONS_COUNT; ++i) + { + // Acquire the spinlock. + while (!f.TestAndSet()) + ; + count++; + f.Clear(); + } + }; - std::array threads; - for (auto& th : threads) - th = std::thread(adder_func); - for (auto& th : threads) - th.join(); + std::array threads; + for (auto& th : threads) + th = std::thread(adder_func); + for (auto& th : threads) + th.join(); - EXPECT_EQ(ITERATIONS_COUNT * THREADS_COUNT, count); + EXPECT_EQ(ITERATIONS_COUNT * THREADS_COUNT, count); } diff --git a/Source/UnitTests/Common/MathUtilTest.cpp b/Source/UnitTests/Common/MathUtilTest.cpp index 0eabd14694..9c84ad6f0a 100644 --- a/Source/UnitTests/Common/MathUtilTest.cpp +++ b/Source/UnitTests/Common/MathUtilTest.cpp @@ -2,87 +2,91 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #include -#include #include "Common/MathUtil.h" TEST(MathUtil, Clamp) { - EXPECT_EQ(1, MathUtil::Clamp(1, 0, 2)); - EXPECT_EQ(1.0, MathUtil::Clamp(1.0, 0.0, 2.0)); + EXPECT_EQ(1, MathUtil::Clamp(1, 0, 2)); + EXPECT_EQ(1.0, MathUtil::Clamp(1.0, 0.0, 2.0)); - EXPECT_EQ(2, MathUtil::Clamp(4, 0, 2)); - EXPECT_EQ(2.0, MathUtil::Clamp(4.0, 0.0, 2.0)); + EXPECT_EQ(2, MathUtil::Clamp(4, 0, 2)); + EXPECT_EQ(2.0, MathUtil::Clamp(4.0, 0.0, 2.0)); - EXPECT_EQ(0, MathUtil::Clamp(-1, 0, 2)); - EXPECT_EQ(0.0, MathUtil::Clamp(-1.0, 0.0, 2.0)); + EXPECT_EQ(0, MathUtil::Clamp(-1, 0, 2)); + EXPECT_EQ(0.0, MathUtil::Clamp(-1.0, 0.0, 2.0)); } TEST(MathUtil, IsQNAN) { - EXPECT_TRUE(MathUtil::IsQNAN(std::numeric_limits::quiet_NaN())); - EXPECT_FALSE(MathUtil::IsQNAN(MathUtil::SNANConstant())); + EXPECT_TRUE(MathUtil::IsQNAN(std::numeric_limits::quiet_NaN())); + EXPECT_FALSE(MathUtil::IsQNAN(MathUtil::SNANConstant())); } TEST(MathUtil, IsSNAN) { - EXPECT_FALSE(MathUtil::IsSNAN(std::numeric_limits::quiet_NaN())); - EXPECT_TRUE(MathUtil::IsSNAN(MathUtil::SNANConstant())); + EXPECT_FALSE(MathUtil::IsSNAN(std::numeric_limits::quiet_NaN())); + EXPECT_TRUE(MathUtil::IsSNAN(MathUtil::SNANConstant())); } TEST(MathUtil, IntLog2) { - EXPECT_EQ(0, IntLog2(1)); - EXPECT_EQ(1, IntLog2(2)); - EXPECT_EQ(2, IntLog2(4)); - EXPECT_EQ(3, IntLog2(8)); - EXPECT_EQ(63, IntLog2(0x8000000000000000ull)); + EXPECT_EQ(0, IntLog2(1)); + EXPECT_EQ(1, IntLog2(2)); + EXPECT_EQ(2, IntLog2(4)); + EXPECT_EQ(3, IntLog2(8)); + EXPECT_EQ(63, IntLog2(0x8000000000000000ull)); - // Rounding behavior. - EXPECT_EQ(3, IntLog2(15)); - EXPECT_EQ(63, IntLog2(0xFFFFFFFFFFFFFFFFull)); + // Rounding behavior. + EXPECT_EQ(3, IntLog2(15)); + EXPECT_EQ(63, IntLog2(0xFFFFFFFFFFFFFFFFull)); } TEST(MathUtil, FlushToZero) { - // To test the software implementation we need to make sure FTZ and DAZ are disabled. - // Using volatile here to ensure the compiler doesn't constant-fold it, - // we want the multiplication to occur at test runtime. - volatile float s = std::numeric_limits::denorm_min(); - volatile double d = std::numeric_limits::denorm_min(); - // Casting away the volatile attribute is required in order for msvc to resolve this to the - // correct instance of the comparison function. - EXPECT_LT(0.f, (float)(s * 2)); - EXPECT_LT(0.0, (double)(d * 2)); + // To test the software implementation we need to make sure FTZ and DAZ are disabled. + // Using volatile here to ensure the compiler doesn't constant-fold it, + // we want the multiplication to occur at test runtime. + volatile float s = std::numeric_limits::denorm_min(); + volatile double d = std::numeric_limits::denorm_min(); + // Casting away the volatile attribute is required in order for msvc to resolve this to the + // correct instance of the comparison function. + EXPECT_LT(0.f, (float)(s * 2)); + EXPECT_LT(0.0, (double)(d * 2)); - EXPECT_EQ(+0.0, MathUtil::FlushToZero(+std::numeric_limits::denorm_min())); - EXPECT_EQ(-0.0, MathUtil::FlushToZero(-std::numeric_limits::denorm_min())); - EXPECT_EQ(+0.0, MathUtil::FlushToZero(+std::numeric_limits::min() / 2)); - EXPECT_EQ(-0.0, MathUtil::FlushToZero(-std::numeric_limits::min() / 2)); - EXPECT_EQ(std::numeric_limits::min(), MathUtil::FlushToZero(std::numeric_limits::min())); - EXPECT_EQ(std::numeric_limits::max(), MathUtil::FlushToZero(std::numeric_limits::max())); - EXPECT_EQ(+std::numeric_limits::infinity(), MathUtil::FlushToZero(+std::numeric_limits::infinity())); - EXPECT_EQ(-std::numeric_limits::infinity(), MathUtil::FlushToZero(-std::numeric_limits::infinity())); + EXPECT_EQ(+0.0, MathUtil::FlushToZero(+std::numeric_limits::denorm_min())); + EXPECT_EQ(-0.0, MathUtil::FlushToZero(-std::numeric_limits::denorm_min())); + EXPECT_EQ(+0.0, MathUtil::FlushToZero(+std::numeric_limits::min() / 2)); + EXPECT_EQ(-0.0, MathUtil::FlushToZero(-std::numeric_limits::min() / 2)); + EXPECT_EQ(std::numeric_limits::min(), + MathUtil::FlushToZero(std::numeric_limits::min())); + EXPECT_EQ(std::numeric_limits::max(), + MathUtil::FlushToZero(std::numeric_limits::max())); + EXPECT_EQ(+std::numeric_limits::infinity(), + MathUtil::FlushToZero(+std::numeric_limits::infinity())); + EXPECT_EQ(-std::numeric_limits::infinity(), + MathUtil::FlushToZero(-std::numeric_limits::infinity())); - // Test all subnormals as well as an equally large set of random normal floats. - std::default_random_engine engine(0); - std::uniform_int_distribution dist(0x00800000u, 0x7fffffffu); - for (u32 i = 0; i <= 0x007fffffu; ++i) - { - MathUtil::IntFloat x(i); - EXPECT_EQ(+0.f, MathUtil::FlushToZero(x.f)); + // Test all subnormals as well as an equally large set of random normal floats. + std::default_random_engine engine(0); + std::uniform_int_distribution dist(0x00800000u, 0x7fffffffu); + for (u32 i = 0; i <= 0x007fffffu; ++i) + { + MathUtil::IntFloat x(i); + EXPECT_EQ(+0.f, MathUtil::FlushToZero(x.f)); - x.i = i | 0x80000000u; - EXPECT_EQ(-0.f, MathUtil::FlushToZero(x.f)); + x.i = i | 0x80000000u; + EXPECT_EQ(-0.f, MathUtil::FlushToZero(x.f)); - x.i = dist(engine); - MathUtil::IntFloat y(MathUtil::FlushToZero(x.f)); - EXPECT_EQ(x.i, y.i); + x.i = dist(engine); + MathUtil::IntFloat y(MathUtil::FlushToZero(x.f)); + EXPECT_EQ(x.i, y.i); - x.i |= 0x80000000u; - y.f = MathUtil::FlushToZero(x.f); - EXPECT_EQ(x.i, y.i); - } + x.i |= 0x80000000u; + y.f = MathUtil::FlushToZero(x.f); + EXPECT_EQ(x.i, y.i); + } } diff --git a/Source/UnitTests/Common/x64EmitterTest.cpp b/Source/UnitTests/Common/x64EmitterTest.cpp index b6fe971546..648f9cdf34 100644 --- a/Source/UnitTests/Common/x64EmitterTest.cpp +++ b/Source/UnitTests/Common/x64EmitterTest.cpp @@ -5,10 +5,10 @@ #include #include #include // From Bochs, fallback included in Externals. +#include #include #include #include -#include // gtest defines the TEST macro to generate test case functions. It conflicts // with the TEST method in the x64Emitter. @@ -22,164 +22,153 @@ namespace Gen { - struct NamedReg { - X64Reg reg; - std::string name; + X64Reg reg; + std::string name; }; -const std::vector reg8names { - { RAX, "al" }, { RBX, "bl" }, { RCX, "cl" }, { RDX, "dl" }, - { RSI, "sil" }, { RDI, "dil" }, { RBP, "bpl" }, { RSP, "spl" }, - { R8, "r8b" }, { R9, "r9b" }, { R10, "r10b" }, { R11, "r11b" }, - { R12, "r12b" }, { R13, "r13b" }, { R14, "r14b" }, { R15, "r15b" }, +const std::vector reg8names{ + {RAX, "al"}, {RBX, "bl"}, {RCX, "cl"}, {RDX, "dl"}, {RSI, "sil"}, {RDI, "dil"}, + {RBP, "bpl"}, {RSP, "spl"}, {R8, "r8b"}, {R9, "r9b"}, {R10, "r10b"}, {R11, "r11b"}, + {R12, "r12b"}, {R13, "r13b"}, {R14, "r14b"}, {R15, "r15b"}, }; -const std::vector reg8hnames { - { AH, "ah" }, { BH, "bh" }, { CH, "ch" }, { DH, "dh" }, +const std::vector reg8hnames{ + {AH, "ah"}, {BH, "bh"}, {CH, "ch"}, {DH, "dh"}, }; -const std::vector reg16names { - { RAX, "ax" }, { RBX, "bx" }, { RCX, "cx" }, { RDX, "dx" }, - { RSI, "si" }, { RDI, "di" }, { RBP, "bp" }, { RSP, "sp" }, - { R8, "r8w" }, { R9, "r9w" }, { R10, "r10w" }, { R11, "r11w" }, - { R12, "r12w" }, { R13, "r13w" }, { R14, "r14w" }, { R15, "r15w" }, +const std::vector reg16names{ + {RAX, "ax"}, {RBX, "bx"}, {RCX, "cx"}, {RDX, "dx"}, {RSI, "si"}, {RDI, "di"}, + {RBP, "bp"}, {RSP, "sp"}, {R8, "r8w"}, {R9, "r9w"}, {R10, "r10w"}, {R11, "r11w"}, + {R12, "r12w"}, {R13, "r13w"}, {R14, "r14w"}, {R15, "r15w"}, }; -const std::vector reg32names { - { RAX, "eax" }, { RBX, "ebx" }, { RCX, "ecx" }, { RDX, "edx" }, - { RSI, "esi" }, { RDI, "edi" }, { RBP, "ebp" }, { RSP, "esp" }, - { R8, "r8d" }, { R9, "r9d" }, { R10, "r10d" }, { R11, "r11d" }, - { R12, "r12d" }, { R13, "r13d" }, { R14, "r14d" }, { R15, "r15d" }, +const std::vector reg32names{ + {RAX, "eax"}, {RBX, "ebx"}, {RCX, "ecx"}, {RDX, "edx"}, {RSI, "esi"}, {RDI, "edi"}, + {RBP, "ebp"}, {RSP, "esp"}, {R8, "r8d"}, {R9, "r9d"}, {R10, "r10d"}, {R11, "r11d"}, + {R12, "r12d"}, {R13, "r13d"}, {R14, "r14d"}, {R15, "r15d"}, }; -const std::vector reg64names { - { RAX, "rax" }, { RBX, "rbx" }, { RCX, "rcx" }, { RDX, "rdx" }, - { RSI, "rsi" }, { RDI, "rdi" }, { RBP, "rbp" }, { RSP, "rsp" }, - { R8, "r8" }, { R9, "r9" }, { R10, "r10" }, { R11, "r11" }, - { R12, "r12" }, { R13, "r13" }, { R14, "r14" }, { R15, "r15" }, +const std::vector reg64names{ + {RAX, "rax"}, {RBX, "rbx"}, {RCX, "rcx"}, {RDX, "rdx"}, {RSI, "rsi"}, {RDI, "rdi"}, + {RBP, "rbp"}, {RSP, "rsp"}, {R8, "r8"}, {R9, "r9"}, {R10, "r10"}, {R11, "r11"}, + {R12, "r12"}, {R13, "r13"}, {R14, "r14"}, {R15, "r15"}, }; -const std::vector xmmnames { - { XMM0, "xmm0" }, { XMM1, "xmm1" }, { XMM2, "xmm2" }, { XMM3, "xmm3" }, - { XMM4, "xmm4" }, { XMM5, "xmm5" }, { XMM6, "xmm6" }, { XMM7, "xmm7" }, - { XMM8, "xmm8" }, { XMM9, "xmm9" }, { XMM10, "xmm10" }, { XMM11, "xmm11" }, - { XMM12, "xmm12" }, { XMM13, "xmm13" }, { XMM14, "xmm14" }, { XMM15, "xmm15" }, +const std::vector xmmnames{ + {XMM0, "xmm0"}, {XMM1, "xmm1"}, {XMM2, "xmm2"}, {XMM3, "xmm3"}, + {XMM4, "xmm4"}, {XMM5, "xmm5"}, {XMM6, "xmm6"}, {XMM7, "xmm7"}, + {XMM8, "xmm8"}, {XMM9, "xmm9"}, {XMM10, "xmm10"}, {XMM11, "xmm11"}, + {XMM12, "xmm12"}, {XMM13, "xmm13"}, {XMM14, "xmm14"}, {XMM15, "xmm15"}, }; -const std::vector ymmnames { - { YMM0, "ymm0" }, { YMM1, "ymm1" }, { YMM2, "ymm2" }, { YMM3, "ymm3" }, - { YMM4, "ymm4" }, { YMM5, "ymm5" }, { YMM6, "ymm6" }, { YMM7, "ymm7" }, - { YMM8, "ymm8" }, { YMM9, "ymm9" }, { YMM10, "ymm10" }, { YMM11, "ymm11" }, - { YMM12, "ymm12" }, { YMM13, "ymm13" }, { YMM14, "ymm14" }, { YMM15, "ymm15" }, +const std::vector ymmnames{ + {YMM0, "ymm0"}, {YMM1, "ymm1"}, {YMM2, "ymm2"}, {YMM3, "ymm3"}, + {YMM4, "ymm4"}, {YMM5, "ymm5"}, {YMM6, "ymm6"}, {YMM7, "ymm7"}, + {YMM8, "ymm8"}, {YMM9, "ymm9"}, {YMM10, "ymm10"}, {YMM11, "ymm11"}, + {YMM12, "ymm12"}, {YMM13, "ymm13"}, {YMM14, "ymm14"}, {YMM15, "ymm15"}, }; -struct { CCFlags cc; std::string name; } ccnames[] = { - { CC_O, "o" }, { CC_NO, "no" }, - { CC_B, "b" }, { CC_NB, "nb" }, - { CC_Z, "z" }, { CC_NZ, "nz" }, - { CC_BE, "be" }, { CC_NBE, "nbe" }, - { CC_S, "s" }, { CC_NS, "ns" }, - { CC_P, "p" }, { CC_NP, "np" }, - { CC_L, "l" }, { CC_NL, "nl" }, - { CC_LE, "le" }, { CC_NLE, "nle" }, +struct +{ + CCFlags cc; + std::string name; +} ccnames[] = { + {CC_O, "o"}, {CC_NO, "no"}, {CC_B, "b"}, {CC_NB, "nb"}, {CC_Z, "z"}, {CC_NZ, "nz"}, + {CC_BE, "be"}, {CC_NBE, "nbe"}, {CC_S, "s"}, {CC_NS, "ns"}, {CC_P, "p"}, {CC_NP, "np"}, + {CC_L, "l"}, {CC_NL, "nl"}, {CC_LE, "le"}, {CC_NLE, "nle"}, }; class x64EmitterTest : public testing::Test { protected: - void SetUp() override - { - memset(&cpu_info, 0xFF, sizeof (cpu_info)); + void SetUp() override + { + memset(&cpu_info, 0xFF, sizeof(cpu_info)); - emitter.reset(new X64CodeBlock()); - emitter->AllocCodeSpace(4096); - code_buffer = emitter->GetWritableCodePtr(); + emitter.reset(new X64CodeBlock()); + emitter->AllocCodeSpace(4096); + code_buffer = emitter->GetWritableCodePtr(); - disasm.reset(new disassembler); - disasm->set_syntax_intel(); - } + disasm.reset(new disassembler); + disasm->set_syntax_intel(); + } - void TearDown() override - { - cpu_info = CPUInfo(); - } + void TearDown() override { cpu_info = CPUInfo(); } + void ExpectDisassembly(const std::string& expected) + { + std::string disasmed; + const u8* generated_code_iterator = code_buffer; + while (generated_code_iterator < emitter->GetCodePtr()) + { + char instr_buffer[1024] = ""; + generated_code_iterator += + disasm->disasm64((u64)generated_code_iterator, (u64)generated_code_iterator, + generated_code_iterator, instr_buffer); + disasmed += instr_buffer; + disasmed += "\n"; + } - void ExpectDisassembly(const std::string& expected) - { - std::string disasmed; - const u8* generated_code_iterator = code_buffer; - while (generated_code_iterator < emitter->GetCodePtr()) - { - char instr_buffer[1024] = ""; - generated_code_iterator += disasm->disasm64( - (u64)generated_code_iterator, - (u64)generated_code_iterator, - generated_code_iterator, instr_buffer); - disasmed += instr_buffer; - disasmed += "\n"; - } + auto NormalizeAssembly = [](const std::string& str) -> std::string { + // Normalize assembly code to make it suitable for equality checks. + // In particular: + // * Replace all whitespace characters by a single space. + // * Remove leading and trailing whitespaces. + // * Lowercase everything. + // * Remove all (0x...) addresses. + std::string out; + bool previous_was_space = false; + bool inside_parens = false; + for (auto c : str) + { + c = tolower(c); + if (c == '(') + { + inside_parens = true; + continue; + } + else if (inside_parens) + { + if (c == ')') + inside_parens = false; + continue; + } + else if (isspace(c)) + { + previous_was_space = true; + continue; + } + else if (previous_was_space) + { + previous_was_space = false; + if (!out.empty()) + out += ' '; + } + out += c; + } + return out; + }; + std::string expected_norm = NormalizeAssembly(expected); + std::string disasmed_norm = NormalizeAssembly(disasmed); - auto NormalizeAssembly = [](const std::string& str) -> std::string { - // Normalize assembly code to make it suitable for equality checks. - // In particular: - // * Replace all whitespace characters by a single space. - // * Remove leading and trailing whitespaces. - // * Lowercase everything. - // * Remove all (0x...) addresses. - std::string out; - bool previous_was_space = false; - bool inside_parens = false; - for (auto c : str) - { - c = tolower(c); - if (c == '(') - { - inside_parens = true; - continue; - } - else if (inside_parens) - { - if (c == ')') - inside_parens = false; - continue; - } - else if (isspace(c)) - { - previous_was_space = true; - continue; - } - else if (previous_was_space) - { - previous_was_space = false; - if (!out.empty()) - out += ' '; - } - out += c; - } - return out; - }; - std::string expected_norm = NormalizeAssembly(expected); - std::string disasmed_norm = NormalizeAssembly(disasmed); + EXPECT_EQ(expected_norm, disasmed_norm); - EXPECT_EQ(expected_norm, disasmed_norm); + // Reset code buffer afterwards. + emitter->SetCodePtr(code_buffer); + } - // Reset code buffer afterwards. - emitter->SetCodePtr(code_buffer); - } - - std::unique_ptr emitter; - std::unique_ptr disasm; - u8* code_buffer; + std::unique_ptr emitter; + std::unique_ptr disasm; + u8* code_buffer; }; -#define TEST_INSTR_NO_OPERANDS(Name, ExpectedDisasm) \ - TEST_F(x64EmitterTest, Name) \ - { \ - emitter->Name(); \ - ExpectDisassembly(ExpectedDisasm); \ - } +#define TEST_INSTR_NO_OPERANDS(Name, ExpectedDisasm) \ + TEST_F(x64EmitterTest, Name) \ + { \ + emitter->Name(); \ + ExpectDisassembly(ExpectedDisasm); \ + } TEST_INSTR_NO_OPERANDS(INT3, "int3") TEST_INSTR_NO_OPERANDS(NOP, "nop") @@ -211,79 +200,79 @@ TEST_INSTR_NO_OPERANDS(RDTSC, "rdtsc") TEST_F(x64EmitterTest, NOP_MultiByte) { - // 2 bytes is "rep nop", still a simple nop. - emitter->NOP(2); - ExpectDisassembly("nop"); + // 2 bytes is "rep nop", still a simple nop. + emitter->NOP(2); + ExpectDisassembly("nop"); - for (int i = 3; i <= 11; ++i) - { - emitter->NOP(i); - ExpectDisassembly("multibyte nop"); - } + for (int i = 3; i <= 11; ++i) + { + emitter->NOP(i); + ExpectDisassembly("multibyte nop"); + } - // Larger NOPs are split into several NOPs. - emitter->NOP(20); - ExpectDisassembly("multibyte nop " - "multibyte nop"); + // Larger NOPs are split into several NOPs. + emitter->NOP(20); + ExpectDisassembly("multibyte nop " + "multibyte nop"); } TEST_F(x64EmitterTest, PUSH_Register) { - for (const auto& r : reg64names) - { - emitter->PUSH(r.reg); - ExpectDisassembly("push " + r.name); - } + for (const auto& r : reg64names) + { + emitter->PUSH(r.reg); + ExpectDisassembly("push " + r.name); + } } TEST_F(x64EmitterTest, PUSH_Immediate) { - emitter->PUSH(64, Imm8(0xf0)); - ExpectDisassembly("push 0xfffffffffffffff0"); + emitter->PUSH(64, Imm8(0xf0)); + ExpectDisassembly("push 0xfffffffffffffff0"); - // X64 is weird like that... this pushes 2 bytes, not 8 bytes with sext. - emitter->PUSH(64, Imm16(0xe0f0)); - ExpectDisassembly("push 0xe0f0"); + // X64 is weird like that... this pushes 2 bytes, not 8 bytes with sext. + emitter->PUSH(64, Imm16(0xe0f0)); + ExpectDisassembly("push 0xe0f0"); - emitter->PUSH(64, Imm32(0xc0d0e0f0)); - ExpectDisassembly("push 0xffffffffc0d0e0f0"); + emitter->PUSH(64, Imm32(0xc0d0e0f0)); + ExpectDisassembly("push 0xffffffffc0d0e0f0"); } TEST_F(x64EmitterTest, PUSH_MComplex) { - emitter->PUSH(64, MComplex(RAX, RBX, SCALE_2, 4)); - ExpectDisassembly("push qword ptr ds:[rax+rbx*2+4]"); + emitter->PUSH(64, MComplex(RAX, RBX, SCALE_2, 4)); + ExpectDisassembly("push qword ptr ds:[rax+rbx*2+4]"); } TEST_F(x64EmitterTest, POP_Register) { - for (const auto& r : reg64names) - { - emitter->POP(r.reg); - ExpectDisassembly("pop " + r.name); - } + for (const auto& r : reg64names) + { + emitter->POP(r.reg); + ExpectDisassembly("pop " + r.name); + } } TEST_F(x64EmitterTest, JMP) { - emitter->NOP(6); - emitter->JMP(code_buffer); - ExpectDisassembly("multibyte nop " - "jmp .-8"); + emitter->NOP(6); + emitter->JMP(code_buffer); + ExpectDisassembly("multibyte nop " + "jmp .-8"); - emitter->NOP(6); - emitter->JMP(code_buffer, true); - ExpectDisassembly("multibyte nop " - "jmp .-11"); + emitter->NOP(6); + emitter->JMP(code_buffer, true); + ExpectDisassembly("multibyte nop " + "jmp .-11"); } TEST_F(x64EmitterTest, JMPptr_Register) { - for (const auto& r : reg64names) - { - emitter->JMPptr(R(r.reg)); - ExpectDisassembly("jmp " + r.name); - } + for (const auto& r : reg64names) + { + emitter->JMPptr(R(r.reg)); + ExpectDisassembly("jmp " + r.name); + } } // TODO: J/SetJumpTarget @@ -294,59 +283,62 @@ TEST_F(x64EmitterTest, JMPptr_Register) TEST_F(x64EmitterTest, SETcc) { - for (const auto& cc : ccnames) - { - for (const auto& r : reg8names) - { - emitter->SETcc(cc.cc, R(r.reg)); - ExpectDisassembly("set" + cc.name + " " + r.name); - } - for (const auto& r : reg8hnames) - { - emitter->SETcc(cc.cc, R(r.reg)); - ExpectDisassembly("set" + cc.name + " " + r.name); - } - } + for (const auto& cc : ccnames) + { + for (const auto& r : reg8names) + { + emitter->SETcc(cc.cc, R(r.reg)); + ExpectDisassembly("set" + cc.name + " " + r.name); + } + for (const auto& r : reg8hnames) + { + emitter->SETcc(cc.cc, R(r.reg)); + ExpectDisassembly("set" + cc.name + " " + r.name); + } + } } TEST_F(x64EmitterTest, CMOVcc_Register) { - for (const auto& cc : ccnames) - { - emitter->CMOVcc(64, RAX, R(R12), cc.cc); - emitter->CMOVcc(32, RAX, R(R12), cc.cc); - emitter->CMOVcc(16, RAX, R(R12), cc.cc); + for (const auto& cc : ccnames) + { + emitter->CMOVcc(64, RAX, R(R12), cc.cc); + emitter->CMOVcc(32, RAX, R(R12), cc.cc); + emitter->CMOVcc(16, RAX, R(R12), cc.cc); - ExpectDisassembly("cmov" + cc.name + " rax, r12 " - "cmov" + cc.name + " eax, r12d " - "cmov" + cc.name + " ax, r12w"); - } + ExpectDisassembly("cmov" + cc.name + " rax, r12 " + "cmov" + + cc.name + " eax, r12d " + "cmov" + + cc.name + " ax, r12w"); + } } -#define BITSEARCH_TEST(Name) \ - TEST_F(x64EmitterTest, Name) \ - { \ - struct { \ - int bits; \ - std::vector regs; \ - std::string size; \ - std::string rax_name; \ - } regsets[] = { \ - { 16, reg16names, "word", "ax" }, \ - { 32, reg32names, "dword", "eax" }, \ - { 64, reg64names, "qword", "rax" }, \ - }; \ - for (const auto& regset : regsets) \ - for (const auto& r : regset.regs) \ - { \ - emitter->Name(regset.bits, r.reg, R(RAX)); \ - emitter->Name(regset.bits, RAX, R(r.reg)); \ - emitter->Name(regset.bits, r.reg, MatR(RAX)); \ - ExpectDisassembly(#Name " " + r.name + ", " + regset.rax_name + " " \ - #Name " " + regset.rax_name + ", " + r.name + " " \ - #Name " " + r.name + ", " + regset.size + " ptr ds:[rax] " ); \ - } \ - } +#define BITSEARCH_TEST(Name) \ + TEST_F(x64EmitterTest, Name) \ + { \ + struct \ + { \ + int bits; \ + std::vector regs; \ + std::string size; \ + std::string rax_name; \ + } regsets[] = { \ + {16, reg16names, "word", "ax"}, \ + {32, reg32names, "dword", "eax"}, \ + {64, reg64names, "qword", "rax"}, \ + }; \ + for (const auto& regset : regsets) \ + for (const auto& r : regset.regs) \ + { \ + emitter->Name(regset.bits, r.reg, R(RAX)); \ + emitter->Name(regset.bits, RAX, R(r.reg)); \ + emitter->Name(regset.bits, r.reg, MatR(RAX)); \ + ExpectDisassembly(#Name " " + r.name + ", " + regset.rax_name + " " #Name " " + \ + regset.rax_name + ", " + r.name + " " #Name " " + r.name + ", " + \ + regset.size + " ptr ds:[rax] "); \ + } \ + } BITSEARCH_TEST(BSR); BITSEARCH_TEST(BSF); @@ -355,65 +347,65 @@ BITSEARCH_TEST(TZCNT); TEST_F(x64EmitterTest, PREFETCH) { - emitter->PREFETCH(XEmitter::PF_NTA, MatR(R12)); - emitter->PREFETCH(XEmitter::PF_T0, MatR(R12)); - emitter->PREFETCH(XEmitter::PF_T1, MatR(R12)); - emitter->PREFETCH(XEmitter::PF_T2, MatR(R12)); + emitter->PREFETCH(XEmitter::PF_NTA, MatR(R12)); + emitter->PREFETCH(XEmitter::PF_T0, MatR(R12)); + emitter->PREFETCH(XEmitter::PF_T1, MatR(R12)); + emitter->PREFETCH(XEmitter::PF_T2, MatR(R12)); - ExpectDisassembly("prefetchnta byte ptr ds:[r12] " - "prefetcht0 byte ptr ds:[r12] " - "prefetcht1 byte ptr ds:[r12] " - "prefetcht2 byte ptr ds:[r12]"); + ExpectDisassembly("prefetchnta byte ptr ds:[r12] " + "prefetcht0 byte ptr ds:[r12] " + "prefetcht1 byte ptr ds:[r12] " + "prefetcht2 byte ptr ds:[r12]"); } TEST_F(x64EmitterTest, MOVNTI) { - emitter->MOVNTI(32, MatR(RAX), R12); - emitter->MOVNTI(32, M(code_buffer), R12); - emitter->MOVNTI(64, MatR(RAX), R12); - emitter->MOVNTI(64, M(code_buffer), R12); + emitter->MOVNTI(32, MatR(RAX), R12); + emitter->MOVNTI(32, M(code_buffer), R12); + emitter->MOVNTI(64, MatR(RAX), R12); + emitter->MOVNTI(64, M(code_buffer), R12); - ExpectDisassembly("movnti dword ptr ds:[rax], r12d " - "movnti dword ptr ds:[rip-12], r12d " - "movnti qword ptr ds:[rax], r12 " - "movnti qword ptr ds:[rip-24], r12"); + ExpectDisassembly("movnti dword ptr ds:[rax], r12d " + "movnti dword ptr ds:[rip-12], r12d " + "movnti qword ptr ds:[rax], r12 " + "movnti qword ptr ds:[rip-24], r12"); } // Grouped together since these 3 instructions do exactly the same thing. TEST_F(x64EmitterTest, MOVNT_DQ_PS_PD) { - for (const auto& r : xmmnames) - { - emitter->MOVNTDQ(MatR(RAX), r.reg); - emitter->MOVNTPS(MatR(RAX), r.reg); - emitter->MOVNTPD(MatR(RAX), r.reg); - ExpectDisassembly("movntdq dqword ptr ds:[rax], " + r.name + " " - "movntps dqword ptr ds:[rax], " + r.name + " " - "movntpd dqword ptr ds:[rax], " + r.name); - } + for (const auto& r : xmmnames) + { + emitter->MOVNTDQ(MatR(RAX), r.reg); + emitter->MOVNTPS(MatR(RAX), r.reg); + emitter->MOVNTPD(MatR(RAX), r.reg); + ExpectDisassembly("movntdq dqword ptr ds:[rax], " + r.name + " " + "movntps dqword ptr ds:[rax], " + + r.name + " " + "movntpd dqword ptr ds:[rax], " + + r.name); + } } -#define MUL_DIV_TEST(Name) \ - TEST_F(x64EmitterTest, Name) \ - { \ - struct { \ - int bits; \ - std::vector regs; \ - std::string out_name; \ - } regsets[] = { \ - { 8, reg8names, "al" }, \ - { 8, reg8hnames, "al" }, \ - { 16, reg16names, "ax" }, \ - { 32, reg32names, "eax" }, \ - { 64, reg64names, "rax" }, \ - }; \ - for (const auto& regset : regsets) \ - for (const auto& r : regset.regs) \ - { \ - emitter->Name(regset.bits, R(r.reg)); \ - ExpectDisassembly(#Name " " + regset.out_name + ", " + r.name); \ - } \ - } +#define MUL_DIV_TEST(Name) \ + TEST_F(x64EmitterTest, Name) \ + { \ + struct \ + { \ + int bits; \ + std::vector regs; \ + std::string out_name; \ + } regsets[] = { \ + {8, reg8names, "al"}, {8, reg8hnames, "al"}, {16, reg16names, "ax"}, \ + {32, reg32names, "eax"}, {64, reg64names, "rax"}, \ + }; \ + for (const auto& regset : regsets) \ + for (const auto& r : regset.regs) \ + { \ + emitter->Name(regset.bits, R(r.reg)); \ + ExpectDisassembly(#Name " " + regset.out_name + ", " + r.name); \ + } \ + } MUL_DIV_TEST(MUL) MUL_DIV_TEST(IMUL) @@ -422,30 +414,26 @@ MUL_DIV_TEST(IDIV) // TODO: More complex IMUL variants. -#define SHIFT_TEST(Name) \ - TEST_F(x64EmitterTest, Name) \ - { \ - struct { \ - int bits; \ - std::vector regs; \ - } regsets[] = { \ - { 8, reg8names }, \ - { 8, reg8hnames }, \ - { 16, reg16names }, \ - { 32, reg32names }, \ - { 64, reg64names }, \ - }; \ - for (const auto& regset : regsets) \ - for (const auto& r : regset.regs) \ - { \ - emitter->Name(regset.bits, R(r.reg), Imm8(1)); \ - emitter->Name(regset.bits, R(r.reg), Imm8(4)); \ - emitter->Name(regset.bits, R(r.reg), R(CL)); \ - ExpectDisassembly(#Name " " + r.name + ", 1 " \ - #Name " " + r.name + ", 0x04 " \ - #Name " " + r.name + ", cl"); \ - } \ - } +#define SHIFT_TEST(Name) \ + TEST_F(x64EmitterTest, Name) \ + { \ + struct \ + { \ + int bits; \ + std::vector regs; \ + } regsets[] = { \ + {8, reg8names}, {8, reg8hnames}, {16, reg16names}, {32, reg32names}, {64, reg64names}, \ + }; \ + for (const auto& regset : regsets) \ + for (const auto& r : regset.regs) \ + { \ + emitter->Name(regset.bits, R(r.reg), Imm8(1)); \ + emitter->Name(regset.bits, R(r.reg), Imm8(4)); \ + emitter->Name(regset.bits, R(r.reg), R(CL)); \ + ExpectDisassembly(#Name " " + r.name + ", 1 " #Name " " + r.name + ", 0x04 " #Name " " + \ + r.name + ", cl"); \ + } \ + } SHIFT_TEST(ROL) SHIFT_TEST(ROR) @@ -455,32 +443,32 @@ SHIFT_TEST(SHL) SHIFT_TEST(SHR) SHIFT_TEST(SAR) -#define BT_TEST(Name) \ - TEST_F(x64EmitterTest, Name) \ - { \ - struct { \ - int bits; \ - std::vector regs; \ - std::string out_name; \ - std::string size; \ - } regsets[] = { \ - { 16, reg16names, "ax", "word" }, \ - { 32, reg32names, "eax", "dword" }, \ - { 64, reg64names, "rax", "qword" }, \ - }; \ - for (const auto& regset : regsets) \ - for (const auto& r : regset.regs) \ - { \ - emitter->Name(regset.bits, R(r.reg), R(RAX)); \ - emitter->Name(regset.bits, R(RAX), R(r.reg)); \ - emitter->Name(regset.bits, R(r.reg), Imm8(0x42)); \ - emitter->Name(regset.bits, MatR(R12), R(r.reg)); \ - ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + " " \ - #Name " " + regset.out_name + ", " + r.name + " " \ - #Name " " + r.name + ", 0x42 " \ - #Name " " + regset.size + " ptr ds:[r12], " + r.name); \ - } \ - } +#define BT_TEST(Name) \ + TEST_F(x64EmitterTest, Name) \ + { \ + struct \ + { \ + int bits; \ + std::vector regs; \ + std::string out_name; \ + std::string size; \ + } regsets[] = { \ + {16, reg16names, "ax", "word"}, \ + {32, reg32names, "eax", "dword"}, \ + {64, reg64names, "rax", "qword"}, \ + }; \ + for (const auto& regset : regsets) \ + for (const auto& r : regset.regs) \ + { \ + emitter->Name(regset.bits, R(r.reg), R(RAX)); \ + emitter->Name(regset.bits, R(RAX), R(r.reg)); \ + emitter->Name(regset.bits, R(r.reg), Imm8(0x42)); \ + emitter->Name(regset.bits, MatR(R12), R(r.reg)); \ + ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + " " #Name " " + \ + regset.out_name + ", " + r.name + " " #Name " " + r.name + \ + ", 0x42 " #Name " " + regset.size + " ptr ds:[r12], " + r.name); \ + } \ + } BT_TEST(BT) BT_TEST(BTS) @@ -489,67 +477,65 @@ BT_TEST(BTC) // TODO: LEA tests -#define ONE_OP_ARITH_TEST(Name) \ - TEST_F(x64EmitterTest, Name) \ - { \ - struct { \ - int bits; \ - std::vector regs; \ - std::string size; \ - } regsets[] = { \ - { 8, reg8names, "byte" }, \ - { 8, reg8hnames, "byte" }, \ - { 16, reg16names, "word" }, \ - { 32, reg32names, "dword" }, \ - { 64, reg64names, "qword" }, \ - }; \ - for (const auto& regset : regsets) \ - for (const auto& r : regset.regs) \ - { \ - emitter->Name(regset.bits, R(r.reg)); \ - emitter->Name(regset.bits, MatR(RAX)); \ - emitter->Name(regset.bits, MatR(R12)); \ - ExpectDisassembly(#Name " " + r.name + " " \ - #Name " " + regset.size + " ptr ds:[rax] " \ - #Name " " + regset.size + " ptr ds:[r12]"); \ - } \ - } +#define ONE_OP_ARITH_TEST(Name) \ + TEST_F(x64EmitterTest, Name) \ + { \ + struct \ + { \ + int bits; \ + std::vector regs; \ + std::string size; \ + } regsets[] = { \ + {8, reg8names, "byte"}, {8, reg8hnames, "byte"}, {16, reg16names, "word"}, \ + {32, reg32names, "dword"}, {64, reg64names, "qword"}, \ + }; \ + for (const auto& regset : regsets) \ + for (const auto& r : regset.regs) \ + { \ + emitter->Name(regset.bits, R(r.reg)); \ + emitter->Name(regset.bits, MatR(RAX)); \ + emitter->Name(regset.bits, MatR(R12)); \ + ExpectDisassembly(#Name " " + r.name + " " #Name " " + regset.size + \ + " ptr ds:[rax] " #Name " " + regset.size + " ptr ds:[r12]"); \ + } \ + } ONE_OP_ARITH_TEST(NOT) ONE_OP_ARITH_TEST(NEG) -#define TWO_OP_ARITH_TEST(Name) \ - TEST_F(x64EmitterTest, Name) \ - { \ - struct { \ - int bits; \ - std::vector regs; \ - std::string size; \ - std::string rax_name; \ - Gen::OpArg imm; \ - std::string immname; \ - } regsets[] = { \ - { 8, reg8names, "byte", "al", Imm8(0xEF), "0xef" }, \ - { 8, reg8hnames, "byte", "al", Imm8(0xEF), "0xef" }, \ - { 16, reg16names, "word", "ax", Imm16(0xBEEF), "0xbeef" }, \ - { 32, reg32names, "dword", "eax", Imm32(0xDEADBEEF), "0xdeadbeef" }, \ - { 64, reg64names, "qword", "rax", Imm32(0xDEADBEEF), "0xffffffffdeadbeef" }, \ - }; \ - for (const auto& regset : regsets) \ - for (const auto& r : regset.regs) \ - { \ - emitter->Name(regset.bits, R(r.reg), R(RAX)); \ - emitter->Name(regset.bits, R(RAX), R(r.reg)); \ - emitter->Name(regset.bits, R(r.reg), MatR(RAX)); \ - emitter->Name(regset.bits, MatR(RAX), R(r.reg)); \ - emitter->Name(regset.bits, R(r.reg), regset.imm); \ - ExpectDisassembly(#Name " " + r.name + ", " + regset.rax_name + " " \ - #Name " " + regset.rax_name + ", " + r.name + " " \ - #Name " " + r.name + ", " + regset.size + " ptr ds:[rax] " \ - #Name " " + regset.size + " ptr ds:[rax], " + r.name + " " \ - #Name " " + r.name + ", " + regset.immname ); \ - } \ - } +#define TWO_OP_ARITH_TEST(Name) \ + TEST_F(x64EmitterTest, Name) \ + { \ + struct \ + { \ + int bits; \ + std::vector regs; \ + std::string size; \ + std::string rax_name; \ + Gen::OpArg imm; \ + std::string immname; \ + } regsets[] = { \ + {8, reg8names, "byte", "al", Imm8(0xEF), "0xef"}, \ + {8, reg8hnames, "byte", "al", Imm8(0xEF), "0xef"}, \ + {16, reg16names, "word", "ax", Imm16(0xBEEF), "0xbeef"}, \ + {32, reg32names, "dword", "eax", Imm32(0xDEADBEEF), "0xdeadbeef"}, \ + {64, reg64names, "qword", "rax", Imm32(0xDEADBEEF), "0xffffffffdeadbeef"}, \ + }; \ + for (const auto& regset : regsets) \ + for (const auto& r : regset.regs) \ + { \ + emitter->Name(regset.bits, R(r.reg), R(RAX)); \ + emitter->Name(regset.bits, R(RAX), R(r.reg)); \ + emitter->Name(regset.bits, R(r.reg), MatR(RAX)); \ + emitter->Name(regset.bits, MatR(RAX), R(r.reg)); \ + emitter->Name(regset.bits, R(r.reg), regset.imm); \ + ExpectDisassembly(#Name " " + r.name + ", " + regset.rax_name + " " #Name " " + \ + regset.rax_name + ", " + r.name + " " #Name " " + r.name + ", " + \ + regset.size + " ptr ds:[rax] " #Name " " + regset.size + \ + " ptr ds:[rax], " + r.name + " " #Name " " + r.name + ", " + \ + regset.immname); \ + } \ + } TWO_OP_ARITH_TEST(ADD) TWO_OP_ARITH_TEST(ADC) @@ -567,117 +553,117 @@ TWO_OP_ARITH_TEST(MOV) TEST_F(x64EmitterTest, BSWAP) { - struct { - int bits; - std::vector regs; - } regsets[] = { - { 32, reg32names }, - { 64, reg64names }, - }; - for (const auto& regset : regsets) - for (const auto& r : regset.regs) - { - emitter->BSWAP(regset.bits, r.reg); - ExpectDisassembly("bswap " + r.name); - } + struct + { + int bits; + std::vector regs; + } regsets[] = { + {32, reg32names}, {64, reg64names}, + }; + for (const auto& regset : regsets) + for (const auto& r : regset.regs) + { + emitter->BSWAP(regset.bits, r.reg); + ExpectDisassembly("bswap " + r.name); + } } TEST_F(x64EmitterTest, MOVSX) { - emitter->MOVSX(16, 8, RAX, R(AH)); - emitter->MOVSX(32, 8, RAX, R(R12)); - emitter->MOVSX(32, 16, R12, R(RBX)); - emitter->MOVSX(64, 8, R12, R(RBX)); - emitter->MOVSX(64, 16, RAX, R(R12)); - emitter->MOVSX(64, 32, R12, R(RSP)); - ExpectDisassembly("movsx ax, ah " - "movsx eax, r12b " - "movsx r12d, bx " - "movsx r12, bl " - "movsx rax, r12w " - "movsxd r12, esp"); + emitter->MOVSX(16, 8, RAX, R(AH)); + emitter->MOVSX(32, 8, RAX, R(R12)); + emitter->MOVSX(32, 16, R12, R(RBX)); + emitter->MOVSX(64, 8, R12, R(RBX)); + emitter->MOVSX(64, 16, RAX, R(R12)); + emitter->MOVSX(64, 32, R12, R(RSP)); + ExpectDisassembly("movsx ax, ah " + "movsx eax, r12b " + "movsx r12d, bx " + "movsx r12, bl " + "movsx rax, r12w " + "movsxd r12, esp"); } TEST_F(x64EmitterTest, MOVZX) { - emitter->MOVZX(16, 8, RAX, R(AH)); - emitter->MOVZX(32, 8, R12, R(RBP)); - emitter->MOVZX(64, 8, R12, R(RDI)); - emitter->MOVZX(32, 16, RAX, R(R12)); - emitter->MOVZX(64, 16, RCX, R(RSI)); - ExpectDisassembly("movzx ax, ah " - "movzx r12d, bpl " - "movzx r12d, dil " // Generates 32 bit movzx - "movzx eax, r12w " - "movzx ecx, si"); + emitter->MOVZX(16, 8, RAX, R(AH)); + emitter->MOVZX(32, 8, R12, R(RBP)); + emitter->MOVZX(64, 8, R12, R(RDI)); + emitter->MOVZX(32, 16, RAX, R(R12)); + emitter->MOVZX(64, 16, RCX, R(RSI)); + ExpectDisassembly("movzx ax, ah " + "movzx r12d, bpl " + "movzx r12d, dil " // Generates 32 bit movzx + "movzx eax, r12w " + "movzx ecx, si"); } TEST_F(x64EmitterTest, MOVBE) { - emitter->MOVBE(16, RAX, MatR(R12)); - emitter->MOVBE(16, MatR(RAX), R12); - emitter->MOVBE(32, RAX, MatR(R12)); - emitter->MOVBE(32, MatR(RAX), R12); - emitter->MOVBE(64, RAX, MatR(R12)); - emitter->MOVBE(64, MatR(RAX), R12); - ExpectDisassembly("movbe ax, word ptr ds:[r12] " - "movbe word ptr ds:[rax], r12w " - "movbe eax, dword ptr ds:[r12] " - "movbe dword ptr ds:[rax], r12d " - "movbe rax, qword ptr ds:[r12] " - "movbe qword ptr ds:[rax], r12"); + emitter->MOVBE(16, RAX, MatR(R12)); + emitter->MOVBE(16, MatR(RAX), R12); + emitter->MOVBE(32, RAX, MatR(R12)); + emitter->MOVBE(32, MatR(RAX), R12); + emitter->MOVBE(64, RAX, MatR(R12)); + emitter->MOVBE(64, MatR(RAX), R12); + ExpectDisassembly("movbe ax, word ptr ds:[r12] " + "movbe word ptr ds:[rax], r12w " + "movbe eax, dword ptr ds:[r12] " + "movbe dword ptr ds:[rax], r12d " + "movbe rax, qword ptr ds:[r12] " + "movbe qword ptr ds:[rax], r12"); } TEST_F(x64EmitterTest, STMXCSR) { - emitter->STMXCSR(MatR(R12)); - ExpectDisassembly("stmxcsr dword ptr ds:[r12]"); + emitter->STMXCSR(MatR(R12)); + ExpectDisassembly("stmxcsr dword ptr ds:[r12]"); } TEST_F(x64EmitterTest, LDMXCSR) { - emitter->LDMXCSR(MatR(R12)); - ExpectDisassembly("ldmxcsr dword ptr ds:[r12]"); + emitter->LDMXCSR(MatR(R12)); + ExpectDisassembly("ldmxcsr dword ptr ds:[r12]"); } TEST_F(x64EmitterTest, FLD_FST_FSTP) { - emitter->FLD(32, MatR(RBP)); - emitter->FLD(64, MatR(RBP)); - emitter->FLD(80, MatR(RBP)); + emitter->FLD(32, MatR(RBP)); + emitter->FLD(64, MatR(RBP)); + emitter->FLD(80, MatR(RBP)); - emitter->FST(32, MatR(RBP)); - emitter->FST(64, MatR(RBP)); - // No 80 bit version of FST + emitter->FST(32, MatR(RBP)); + emitter->FST(64, MatR(RBP)); + // No 80 bit version of FST - emitter->FSTP(32, MatR(RBP)); - emitter->FSTP(64, MatR(RBP)); - emitter->FSTP(80, MatR(RBP)); + emitter->FSTP(32, MatR(RBP)); + emitter->FSTP(64, MatR(RBP)); + emitter->FSTP(80, MatR(RBP)); - ExpectDisassembly("fld dword ptr ss:[rbp] " - "fld qword ptr ss:[rbp] " - "fld tbyte ptr ss:[rbp] " - "fst dword ptr ss:[rbp] " - "fst qword ptr ss:[rbp] " - "fstp dword ptr ss:[rbp] " - "fstp qword ptr ss:[rbp] " - "fstp tbyte ptr ss:[rbp]"); + ExpectDisassembly("fld dword ptr ss:[rbp] " + "fld qword ptr ss:[rbp] " + "fld tbyte ptr ss:[rbp] " + "fst dword ptr ss:[rbp] " + "fst qword ptr ss:[rbp] " + "fstp dword ptr ss:[rbp] " + "fstp qword ptr ss:[rbp] " + "fstp tbyte ptr ss:[rbp]"); } -#define TWO_OP_SSE_TEST(Name, MemBits) \ - TEST_F(x64EmitterTest, Name) \ - { \ - for (const auto& r1 : xmmnames) \ - { \ - for (const auto& r2 : xmmnames) \ - { \ - emitter->Name(r1.reg, R(r2.reg)); \ - ExpectDisassembly(#Name " " + r1.name + ", " + r2.name); \ - } \ - emitter->Name(r1.reg, MatR(R12)); \ - ExpectDisassembly(#Name " " + r1.name + ", " MemBits " ptr ds:[r12]"); \ - } \ - } +#define TWO_OP_SSE_TEST(Name, MemBits) \ + TEST_F(x64EmitterTest, Name) \ + { \ + for (const auto& r1 : xmmnames) \ + { \ + for (const auto& r2 : xmmnames) \ + { \ + emitter->Name(r1.reg, R(r2.reg)); \ + ExpectDisassembly(#Name " " + r1.name + ", " + r2.name); \ + } \ + emitter->Name(r1.reg, MatR(R12)); \ + ExpectDisassembly(#Name " " + r1.name + ", " MemBits " ptr ds:[r12]"); \ + } \ + } TWO_OP_SSE_TEST(ADDSS, "dword") TWO_OP_SSE_TEST(SUBSS, "dword") @@ -736,34 +722,34 @@ TWO_OP_SSE_TEST(COMISD, "qword") TWO_OP_SSE_TEST(UCOMISD, "qword") // register-only instructions -#define TWO_OP_SSE_REG_TEST(Name, MemBits) \ - TEST_F(x64EmitterTest, Name) \ - { \ - for (const auto& r1 : xmmnames) \ - { \ - for (const auto& r2 : xmmnames) \ - { \ - emitter->Name(r1.reg, r2.reg); \ - ExpectDisassembly(#Name " " + r1.name + ", " + r2.name); \ - } \ - } \ - } +#define TWO_OP_SSE_REG_TEST(Name, MemBits) \ + TEST_F(x64EmitterTest, Name) \ + { \ + for (const auto& r1 : xmmnames) \ + { \ + for (const auto& r2 : xmmnames) \ + { \ + emitter->Name(r1.reg, r2.reg); \ + ExpectDisassembly(#Name " " + r1.name + ", " + r2.name); \ + } \ + } \ + } TWO_OP_SSE_REG_TEST(MOVHLPS, "qword") TWO_OP_SSE_REG_TEST(MOVLHPS, "qword") // "register + memory"-only instructions -#define TWO_OP_SSE_MEM_TEST(Name, MemBits) \ - TEST_F(x64EmitterTest, Name) \ - { \ - for (const auto& r1 : xmmnames) \ - { \ - emitter->Name(r1.reg, MatR(R12)); \ - ExpectDisassembly(#Name " " + r1.name + ", " MemBits " ptr ds:[r12]"); \ - emitter->Name(MatR(R12), r1.reg); \ - ExpectDisassembly(#Name " " MemBits " ptr ds:[r12], " + r1.name); \ - } \ - } +#define TWO_OP_SSE_MEM_TEST(Name, MemBits) \ + TEST_F(x64EmitterTest, Name) \ + { \ + for (const auto& r1 : xmmnames) \ + { \ + emitter->Name(r1.reg, MatR(R12)); \ + ExpectDisassembly(#Name " " + r1.name + ", " MemBits " ptr ds:[r12]"); \ + emitter->Name(MatR(R12), r1.reg); \ + ExpectDisassembly(#Name " " MemBits " ptr ds:[r12], " + r1.name); \ + } \ + } TWO_OP_SSE_MEM_TEST(MOVLPS, "qword") TWO_OP_SSE_MEM_TEST(MOVHPS, "qword") @@ -777,23 +763,23 @@ TWO_OP_SSE_MEM_TEST(MOVHPD, "qword") TEST_F(x64EmitterTest, MASKMOVDQU) { - for (const auto& r1 : xmmnames) - { - for (const auto& r2 : xmmnames) - { - emitter->MASKMOVDQU(r1.reg, r2.reg); - ExpectDisassembly("maskmovdqu " + r1.name + ", " + r2.name + ", dqword ptr ds:[rdi]"); - } - } + for (const auto& r1 : xmmnames) + { + for (const auto& r2 : xmmnames) + { + emitter->MASKMOVDQU(r1.reg, r2.reg); + ExpectDisassembly("maskmovdqu " + r1.name + ", " + r2.name + ", dqword ptr ds:[rdi]"); + } + } } TEST_F(x64EmitterTest, LDDQU) { - for (const auto& r : xmmnames) - { - emitter->LDDQU(r.reg, MatR(R12)); - ExpectDisassembly("lddqu " + r.name + ", dqword ptr ds:[r12]"); - } + for (const auto& r : xmmnames) + { + emitter->LDDQU(r.reg, MatR(R12)); + ExpectDisassembly("lddqu " + r.name + ", dqword ptr ds:[r12]"); + } } TWO_OP_SSE_TEST(CVTPS2PD, "dqword") @@ -875,29 +861,30 @@ TWO_OP_SSE_TEST(PMOVZXDQ, "qword") // TODO: AVX // for VEX GPR instructions that take the form op reg, r/m, reg -#define VEX_RMR_TEST(Name) \ - TEST_F(x64EmitterTest, Name) \ - { \ - struct { \ - int bits; \ - std::vector regs; \ - std::string out_name; \ - std::string size; \ - } regsets[] = { \ - { 32, reg32names, "eax", "dword" }, \ - { 64, reg64names, "rax", "qword" }, \ - }; \ - for (const auto& regset : regsets) \ - for (const auto& r : regset.regs) \ - { \ - emitter->Name(regset.bits, r.reg, R(RAX), RAX); \ - emitter->Name(regset.bits, RAX, R(r.reg), RAX); \ - emitter->Name(regset.bits, RAX, MatR(R12), r.reg); \ - ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + ", " + regset.out_name + " " \ - #Name " " + regset.out_name + ", " + r.name + ", " + regset.out_name + " " \ - #Name " " + regset.out_name + ", " + regset.size + " ptr ds:[r12], " + r.name + " "); \ - } \ - } +#define VEX_RMR_TEST(Name) \ + TEST_F(x64EmitterTest, Name) \ + { \ + struct \ + { \ + int bits; \ + std::vector regs; \ + std::string out_name; \ + std::string size; \ + } regsets[] = { \ + {32, reg32names, "eax", "dword"}, {64, reg64names, "rax", "qword"}, \ + }; \ + for (const auto& regset : regsets) \ + for (const auto& r : regset.regs) \ + { \ + emitter->Name(regset.bits, r.reg, R(RAX), RAX); \ + emitter->Name(regset.bits, RAX, R(r.reg), RAX); \ + emitter->Name(regset.bits, RAX, MatR(R12), r.reg); \ + ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + ", " + regset.out_name + \ + " " #Name " " + regset.out_name + ", " + r.name + ", " + \ + regset.out_name + " " #Name " " + regset.out_name + ", " + regset.size + \ + " ptr ds:[r12], " + r.name + " "); \ + } \ + } VEX_RMR_TEST(SHRX) VEX_RMR_TEST(SARX) @@ -906,29 +893,30 @@ VEX_RMR_TEST(BEXTR) VEX_RMR_TEST(BZHI) // for VEX GPR instructions that take the form op reg, reg, r/m -#define VEX_RRM_TEST(Name) \ - TEST_F(x64EmitterTest, Name) \ - { \ - struct { \ - int bits; \ - std::vector regs; \ - std::string out_name; \ - std::string size; \ - } regsets[] = { \ - { 32, reg32names, "eax", "dword" }, \ - { 64, reg64names, "rax", "qword" }, \ - }; \ - for (const auto& regset : regsets) \ - for (const auto& r : regset.regs) \ - { \ - emitter->Name(regset.bits, r.reg, RAX, R(RAX)); \ - emitter->Name(regset.bits, RAX, RAX, R(r.reg)); \ - emitter->Name(regset.bits, RAX, r.reg, MatR(R12)); \ - ExpectDisassembly(#Name " " + r.name+ ", " + regset.out_name + ", " + regset.out_name + " " \ - #Name " " + regset.out_name + ", " + regset.out_name + ", " + r.name + " " \ - #Name " " + regset.out_name + ", " + r.name + ", " + regset.size + " ptr ds:[r12] "); \ - } \ - } +#define VEX_RRM_TEST(Name) \ + TEST_F(x64EmitterTest, Name) \ + { \ + struct \ + { \ + int bits; \ + std::vector regs; \ + std::string out_name; \ + std::string size; \ + } regsets[] = { \ + {32, reg32names, "eax", "dword"}, {64, reg64names, "rax", "qword"}, \ + }; \ + for (const auto& regset : regsets) \ + for (const auto& r : regset.regs) \ + { \ + emitter->Name(regset.bits, r.reg, RAX, R(RAX)); \ + emitter->Name(regset.bits, RAX, RAX, R(r.reg)); \ + emitter->Name(regset.bits, RAX, r.reg, MatR(R12)); \ + ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + ", " + regset.out_name + \ + " " #Name " " + regset.out_name + ", " + regset.out_name + ", " + \ + r.name + " " #Name " " + regset.out_name + ", " + r.name + ", " + \ + regset.size + " ptr ds:[r12] "); \ + } \ + } VEX_RRM_TEST(PEXT) VEX_RRM_TEST(PDEP) @@ -936,105 +924,107 @@ VEX_RRM_TEST(MULX) VEX_RRM_TEST(ANDN) // for VEX GPR instructions that take the form op reg, r/m -#define VEX_RM_TEST(Name) \ - TEST_F(x64EmitterTest, Name) \ - { \ - struct { \ - int bits; \ - std::vector regs; \ - std::string out_name; \ - std::string size; \ - } regsets[] = { \ - { 32, reg32names, "eax", "dword" }, \ - { 64, reg64names, "rax", "qword" }, \ - }; \ - for (const auto& regset : regsets) \ - for (const auto& r : regset.regs) \ - { \ - emitter->Name(regset.bits, r.reg, R(RAX)); \ - emitter->Name(regset.bits, RAX, R(r.reg)); \ - emitter->Name(regset.bits, r.reg, MatR(R12)); \ - ExpectDisassembly(#Name " " + r.name+ ", " + regset.out_name + " " \ - #Name " " + regset.out_name + ", " + r.name + " " \ - #Name " " + r.name + ", " + regset.size + " ptr ds:[r12] "); \ - } \ - } +#define VEX_RM_TEST(Name) \ + TEST_F(x64EmitterTest, Name) \ + { \ + struct \ + { \ + int bits; \ + std::vector regs; \ + std::string out_name; \ + std::string size; \ + } regsets[] = { \ + {32, reg32names, "eax", "dword"}, {64, reg64names, "rax", "qword"}, \ + }; \ + for (const auto& regset : regsets) \ + for (const auto& r : regset.regs) \ + { \ + emitter->Name(regset.bits, r.reg, R(RAX)); \ + emitter->Name(regset.bits, RAX, R(r.reg)); \ + emitter->Name(regset.bits, r.reg, MatR(R12)); \ + ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + " " #Name " " + \ + regset.out_name + ", " + r.name + " " #Name " " + r.name + ", " + \ + regset.size + " ptr ds:[r12] "); \ + } \ + } VEX_RM_TEST(BLSR) VEX_RM_TEST(BLSMSK) VEX_RM_TEST(BLSI) // for VEX GPR instructions that take the form op reg, r/m, imm -#define VEX_RMI_TEST(Name) \ - TEST_F(x64EmitterTest, Name) \ - { \ - struct { \ - int bits; \ - std::vector regs; \ - std::string out_name; \ - std::string size; \ - } regsets[] = { \ - { 32, reg32names, "eax", "dword" }, \ - { 64, reg64names, "rax", "qword" }, \ - }; \ - for (const auto& regset : regsets) \ - for (const auto& r : regset.regs) \ - { \ - emitter->Name(regset.bits, r.reg, R(RAX), 4); \ - emitter->Name(regset.bits, RAX, R(r.reg), 4); \ - emitter->Name(regset.bits, r.reg, MatR(R12), 4); \ - ExpectDisassembly(#Name " " + r.name+ ", " + regset.out_name + ", 0x04 " \ - #Name " " + regset.out_name + ", " + r.name + ", 0x04 " \ - #Name " " + r.name + ", " + regset.size + " ptr ds:[r12], 0x04 "); \ - } \ - } +#define VEX_RMI_TEST(Name) \ + TEST_F(x64EmitterTest, Name) \ + { \ + struct \ + { \ + int bits; \ + std::vector regs; \ + std::string out_name; \ + std::string size; \ + } regsets[] = { \ + {32, reg32names, "eax", "dword"}, {64, reg64names, "rax", "qword"}, \ + }; \ + for (const auto& regset : regsets) \ + for (const auto& r : regset.regs) \ + { \ + emitter->Name(regset.bits, r.reg, R(RAX), 4); \ + emitter->Name(regset.bits, RAX, R(r.reg), 4); \ + emitter->Name(regset.bits, r.reg, MatR(R12), 4); \ + ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + ", 0x04 " #Name " " + \ + regset.out_name + ", " + r.name + ", 0x04 " #Name " " + r.name + ", " + \ + regset.size + " ptr ds:[r12], 0x04 "); \ + } \ + } VEX_RMI_TEST(RORX) // for AVX instructions that take the form op reg, reg, r/m -#define AVX_RRM_TEST(Name, sizename) \ - TEST_F(x64EmitterTest, Name) \ - { \ - struct { \ - int bits; \ - std::vector regs; \ - std::string out_name; \ - std::string size; \ - } regsets[] = { \ - { 64, xmmnames, "xmm0", sizename }, \ - }; \ - for (const auto& regset : regsets) \ - for (const auto& r : regset.regs) \ - { \ - emitter->Name(r.reg, XMM0, R(XMM0)); \ - emitter->Name(XMM0, XMM0, R(r.reg)); \ - emitter->Name(XMM0, r.reg, MatR(R12)); \ - ExpectDisassembly(#Name " " + r.name+ ", " + regset.out_name + ", " + regset.out_name + " " \ - #Name " " + regset.out_name + ", " + regset.out_name + ", " + r.name + " " \ - #Name " " + regset.out_name + ", " + r.name + ", " + regset.size + " ptr ds:[r12] "); \ - } \ - } +#define AVX_RRM_TEST(Name, sizename) \ + TEST_F(x64EmitterTest, Name) \ + { \ + struct \ + { \ + int bits; \ + std::vector regs; \ + std::string out_name; \ + std::string size; \ + } regsets[] = { \ + {64, xmmnames, "xmm0", sizename}, \ + }; \ + for (const auto& regset : regsets) \ + for (const auto& r : regset.regs) \ + { \ + emitter->Name(r.reg, XMM0, R(XMM0)); \ + emitter->Name(XMM0, XMM0, R(r.reg)); \ + emitter->Name(XMM0, r.reg, MatR(R12)); \ + ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + ", " + regset.out_name + \ + " " #Name " " + regset.out_name + ", " + regset.out_name + ", " + \ + r.name + " " #Name " " + regset.out_name + ", " + r.name + ", " + \ + regset.size + " ptr ds:[r12] "); \ + } \ + } -AVX_RRM_TEST(VANDPS, "dqword") -AVX_RRM_TEST(VANDPD, "dqword") +AVX_RRM_TEST(VANDPS, "dqword") +AVX_RRM_TEST(VANDPD, "dqword") AVX_RRM_TEST(VANDNPS, "dqword") AVX_RRM_TEST(VANDNPD, "dqword") -AVX_RRM_TEST(VORPS, "dqword") -AVX_RRM_TEST(VORPD, "dqword") -AVX_RRM_TEST(VXORPS, "dqword") -AVX_RRM_TEST(VXORPD, "dqword") -AVX_RRM_TEST(VPAND, "dqword") -AVX_RRM_TEST(VPANDN, "dqword") -AVX_RRM_TEST(VPOR, "dqword") -AVX_RRM_TEST(VPXOR, "dqword") +AVX_RRM_TEST(VORPS, "dqword") +AVX_RRM_TEST(VORPD, "dqword") +AVX_RRM_TEST(VXORPS, "dqword") +AVX_RRM_TEST(VXORPD, "dqword") +AVX_RRM_TEST(VPAND, "dqword") +AVX_RRM_TEST(VPANDN, "dqword") +AVX_RRM_TEST(VPOR, "dqword") +AVX_RRM_TEST(VPXOR, "dqword") -#define FMA3_TEST(Name, P, packed) \ - AVX_RRM_TEST(Name ## 132 ## P ## S, packed ? "dqword" : "dword") \ - AVX_RRM_TEST(Name ## 213 ## P ## S, packed ? "dqword" : "dword") \ - AVX_RRM_TEST(Name ## 231 ## P ## S, packed ? "dqword" : "dword") \ - AVX_RRM_TEST(Name ## 132 ## P ## D, packed ? "dqword" : "qword") \ - AVX_RRM_TEST(Name ## 213 ## P ## D, packed ? "dqword" : "qword") \ - AVX_RRM_TEST(Name ## 231 ## P ## D, packed ? "dqword" : "qword") +#define FMA3_TEST(Name, P, packed) \ + AVX_RRM_TEST(Name##132##P##S, packed ? "dqword" : "dword") \ + AVX_RRM_TEST(Name##213##P##S, packed ? "dqword" : "dword") \ + AVX_RRM_TEST(Name##231##P##S, packed ? "dqword" : "dword") \ + AVX_RRM_TEST(Name##132##P##D, packed ? "dqword" : "qword") \ + AVX_RRM_TEST(Name##213##P##D, packed ? "dqword" : "qword") \ + AVX_RRM_TEST(Name##231##P##D, packed ? "dqword" : "qword") FMA3_TEST(VFMADD, P, true) FMA3_TEST(VFMADD, S, false) @@ -1048,32 +1038,35 @@ FMA3_TEST(VFMADDSUB, P, true) FMA3_TEST(VFMSUBADD, P, true) // for VEX instructions that take the form op reg, reg, r/m, reg OR reg, reg, reg, r/m -#define VEX_RRMR_RRRM_TEST(Name, sizename) \ - TEST_F(x64EmitterTest, Name) \ - { \ - struct { \ - int bits; \ - std::vector regs; \ - std::string out_name; \ - std::string size; \ - } regsets[] = { \ - { 64, xmmnames, "xmm0", sizename }, \ - }; \ - for (const auto& regset : regsets) \ - for (const auto& r : regset.regs) \ - { \ - emitter->Name(r.reg, XMM0, R(XMM0), r.reg); \ - emitter->Name(XMM0, XMM0, r.reg, MatR(R12)); \ - emitter->Name(XMM0, r.reg, MatR(R12), XMM0); \ - ExpectDisassembly(#Name " " + r.name+ ", " + regset.out_name + ", " + regset.out_name + ", " + r.name + " " \ - #Name " " + regset.out_name + ", " + regset.out_name + ", " + r.name + ", " + regset.size + " ptr ds:[r12] " \ - #Name " " + regset.out_name + ", " + r.name + ", " + regset.size + " ptr ds:[r12], " + regset.out_name); \ - } \ - } +#define VEX_RRMR_RRRM_TEST(Name, sizename) \ + TEST_F(x64EmitterTest, Name) \ + { \ + struct \ + { \ + int bits; \ + std::vector regs; \ + std::string out_name; \ + std::string size; \ + } regsets[] = { \ + {64, xmmnames, "xmm0", sizename}, \ + }; \ + for (const auto& regset : regsets) \ + for (const auto& r : regset.regs) \ + { \ + emitter->Name(r.reg, XMM0, R(XMM0), r.reg); \ + emitter->Name(XMM0, XMM0, r.reg, MatR(R12)); \ + emitter->Name(XMM0, r.reg, MatR(R12), XMM0); \ + ExpectDisassembly(#Name " " + r.name + ", " + regset.out_name + ", " + regset.out_name + \ + ", " + r.name + " " #Name " " + regset.out_name + ", " + \ + regset.out_name + ", " + r.name + ", " + regset.size + \ + " ptr ds:[r12] " #Name " " + regset.out_name + ", " + r.name + ", " + \ + regset.size + " ptr ds:[r12], " + regset.out_name); \ + } \ + } -#define FMA4_TEST(Name, P, packed) \ - VEX_RRMR_RRRM_TEST(Name ## P ## S, packed ? "dqword" : "dword") \ - VEX_RRMR_RRRM_TEST(Name ## P ## D, packed ? "dqword" : "qword") +#define FMA4_TEST(Name, P, packed) \ + VEX_RRMR_RRRM_TEST(Name##P##S, packed ? "dqword" : "dword") \ + VEX_RRMR_RRRM_TEST(Name##P##D, packed ? "dqword" : "qword") FMA4_TEST(VFMADD, P, true) FMA4_TEST(VFMADD, S, false) diff --git a/Source/UnitTests/Core/MMIOTest.cpp b/Source/UnitTests/Core/MMIOTest.cpp index 0d198acc84..fd48c786b2 100644 --- a/Source/UnitTests/Core/MMIOTest.cpp +++ b/Source/UnitTests/Core/MMIOTest.cpp @@ -2,8 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include #include +#include #include "Common/CommonTypes.h" #include "Core/HW/MMIO.h" @@ -12,120 +12,120 @@ // number: that is, it is unique in the address ranges we care about. TEST(UniqueID, UniqueEnough) { - std::unordered_set ids; - for (u32 i = 0x0C000000; i < 0x0C010000; ++i) - { - u32 unique_id = MMIO::UniqueID(i); - EXPECT_EQ(ids.end(), ids.find(unique_id)); - ids.insert(unique_id); - } - for (u32 i = 0x0D000000; i < 0x0D010000; ++i) - { - u32 unique_id = MMIO::UniqueID(i); - EXPECT_EQ(ids.end(), ids.find(unique_id)); - ids.insert(unique_id); - } + std::unordered_set ids; + for (u32 i = 0x0C000000; i < 0x0C010000; ++i) + { + u32 unique_id = MMIO::UniqueID(i); + EXPECT_EQ(ids.end(), ids.find(unique_id)); + ids.insert(unique_id); + } + for (u32 i = 0x0D000000; i < 0x0D010000; ++i) + { + u32 unique_id = MMIO::UniqueID(i); + EXPECT_EQ(ids.end(), ids.find(unique_id)); + ids.insert(unique_id); + } } TEST(IsMMIOAddress, SpecialAddresses) { - SConfig::Init(); - SConfig::GetInstance().bWii = true; + SConfig::Init(); + SConfig::GetInstance().bWii = true; - // WG Pipe address, should not be handled by MMIO. - EXPECT_FALSE(MMIO::IsMMIOAddress(0x0C008000)); + // WG Pipe address, should not be handled by MMIO. + EXPECT_FALSE(MMIO::IsMMIOAddress(0x0C008000)); - // Locked L1 cache allocation. - EXPECT_FALSE(MMIO::IsMMIOAddress(0xE0000000)); + // Locked L1 cache allocation. + EXPECT_FALSE(MMIO::IsMMIOAddress(0xE0000000)); - // Uncached mirror of MEM1, shouldn't be handled by MMIO - EXPECT_FALSE(MMIO::IsMMIOAddress(0xC0000000)); + // Uncached mirror of MEM1, shouldn't be handled by MMIO + EXPECT_FALSE(MMIO::IsMMIOAddress(0xC0000000)); - // Effective address of an MMIO register; MMIO only deals with physical - // addresses. - EXPECT_FALSE(MMIO::IsMMIOAddress(0xCC0000E0)); + // Effective address of an MMIO register; MMIO only deals with physical + // addresses. + EXPECT_FALSE(MMIO::IsMMIOAddress(0xCC0000E0)); - // And lets check some valid addresses too - EXPECT_TRUE(MMIO::IsMMIOAddress(0x0C0000E0)); // Gamecube MMIOs - EXPECT_TRUE(MMIO::IsMMIOAddress(0x0D00008C)); // Wii MMIOs - EXPECT_TRUE(MMIO::IsMMIOAddress(0x0D800F10)); // Mirror of Wii MMIOs + // And lets check some valid addresses too + EXPECT_TRUE(MMIO::IsMMIOAddress(0x0C0000E0)); // Gamecube MMIOs + EXPECT_TRUE(MMIO::IsMMIOAddress(0x0D00008C)); // Wii MMIOs + EXPECT_TRUE(MMIO::IsMMIOAddress(0x0D800F10)); // Mirror of Wii MMIOs - SConfig::Shutdown(); + SConfig::Shutdown(); } class MappingTest : public testing::Test { protected: - virtual void SetUp() override - { - m_mapping = new MMIO::Mapping(); - } - - virtual void TearDown() override - { - delete m_mapping; - } - - MMIO::Mapping* m_mapping; + virtual void SetUp() override { m_mapping = new MMIO::Mapping(); } + virtual void TearDown() override { delete m_mapping; } + MMIO::Mapping* m_mapping; }; TEST_F(MappingTest, ReadConstant) { - m_mapping->Register(0x0C001234, MMIO::Constant(0x42), MMIO::Nop()); - m_mapping->Register(0x0C001234, MMIO::Constant(0x1234), MMIO::Nop()); - m_mapping->Register(0x0C001234, MMIO::Constant(0xdeadbeef), MMIO::Nop()); + m_mapping->Register(0x0C001234, MMIO::Constant(0x42), MMIO::Nop()); + m_mapping->Register(0x0C001234, MMIO::Constant(0x1234), MMIO::Nop()); + m_mapping->Register(0x0C001234, MMIO::Constant(0xdeadbeef), MMIO::Nop()); - u8 val8 = m_mapping->Read(0x0C001234); - u16 val16 = m_mapping->Read(0x0C001234); - u32 val32 = m_mapping->Read(0x0C001234); + u8 val8 = m_mapping->Read(0x0C001234); + u16 val16 = m_mapping->Read(0x0C001234); + u32 val32 = m_mapping->Read(0x0C001234); - EXPECT_EQ(0x42, val8); - EXPECT_EQ(0x1234, val16); - EXPECT_EQ(0xdeadbeef, val32); + EXPECT_EQ(0x42, val8); + EXPECT_EQ(0x1234, val16); + EXPECT_EQ(0xdeadbeef, val32); } TEST_F(MappingTest, ReadWriteDirect) { - u8 target_8 = 0; - u16 target_16 = 0; - u32 target_32 = 0; + u8 target_8 = 0; + u16 target_16 = 0; + u32 target_32 = 0; - m_mapping->Register(0x0C001234, MMIO::DirectRead(&target_8), MMIO::DirectWrite(&target_8)); - m_mapping->Register(0x0C001234, MMIO::DirectRead(&target_16), MMIO::DirectWrite(&target_16)); - m_mapping->Register(0x0C001234, MMIO::DirectRead(&target_32), MMIO::DirectWrite(&target_32)); + m_mapping->Register(0x0C001234, MMIO::DirectRead(&target_8), + MMIO::DirectWrite(&target_8)); + m_mapping->Register(0x0C001234, MMIO::DirectRead(&target_16), + MMIO::DirectWrite(&target_16)); + m_mapping->Register(0x0C001234, MMIO::DirectRead(&target_32), + MMIO::DirectWrite(&target_32)); - for (u32 i = 0; i < 100; ++i) - { - u8 val8 = m_mapping->Read(0x0C001234); EXPECT_EQ(i, val8); - u16 val16 = m_mapping->Read(0x0C001234); EXPECT_EQ(i, val16); - u32 val32 = m_mapping->Read(0x0C001234); EXPECT_EQ(i, val32); + for (u32 i = 0; i < 100; ++i) + { + u8 val8 = m_mapping->Read(0x0C001234); + EXPECT_EQ(i, val8); + u16 val16 = m_mapping->Read(0x0C001234); + EXPECT_EQ(i, val16); + u32 val32 = m_mapping->Read(0x0C001234); + EXPECT_EQ(i, val32); - val8 += 1; m_mapping->Write(0x0C001234, val8); - val16 += 1; m_mapping->Write(0x0C001234, val16); - val32 += 1; m_mapping->Write(0x0C001234, val32); - } + val8 += 1; + m_mapping->Write(0x0C001234, val8); + val16 += 1; + m_mapping->Write(0x0C001234, val16); + val32 += 1; + m_mapping->Write(0x0C001234, val32); + } } TEST_F(MappingTest, ReadWriteComplex) { - bool read_called = false, write_called = false; + bool read_called = false, write_called = false; - m_mapping->Register(0x0C001234, - MMIO::ComplexRead([&read_called](u32 addr) { - EXPECT_EQ(0x0C001234u, addr); - read_called = true; - return 0x12; - }), - MMIO::ComplexWrite([&write_called](u32 addr, u8 val) { - EXPECT_EQ(0x0C001234u, addr); - EXPECT_EQ(0x34, val); - write_called = true; - }) - ); + m_mapping->Register(0x0C001234, MMIO::ComplexRead([&read_called](u32 addr) { + EXPECT_EQ(0x0C001234u, addr); + read_called = true; + return 0x12; + }), + MMIO::ComplexWrite([&write_called](u32 addr, u8 val) { + EXPECT_EQ(0x0C001234u, addr); + EXPECT_EQ(0x34, val); + write_called = true; + })); - u8 val = m_mapping->Read(0x0C001234); EXPECT_EQ(0x12, val); - m_mapping->Write(0x0C001234, (u8)0x34); + u8 val = m_mapping->Read(0x0C001234); + EXPECT_EQ(0x12, val); + m_mapping->Write(0x0C001234, (u8)0x34); - EXPECT_TRUE(read_called); - EXPECT_TRUE(write_called); + EXPECT_TRUE(read_called); + EXPECT_TRUE(write_called); } diff --git a/Source/UnitTests/Core/PageFaultTest.cpp b/Source/UnitTests/Core/PageFaultTest.cpp index 1dc0b4752d..63990f7a6f 100644 --- a/Source/UnitTests/Core/PageFaultTest.cpp +++ b/Source/UnitTests/Core/PageFaultTest.cpp @@ -10,70 +10,69 @@ #include "Core/PowerPC/JitCommon/JitBase.h" // include order is important -#include // NOLINT +#include // NOLINT enum { #ifdef _WIN32 - PAGE_GRAN = 0x10000 + PAGE_GRAN = 0x10000 #else - PAGE_GRAN = 0x1000 + PAGE_GRAN = 0x1000 #endif }; class PageFaultFakeJit : public JitBase { public: - // CPUCoreBase methods - void Init() override {} - void Shutdown() override {} - void ClearCache() override {} - void Run() override {} - void SingleStep() override {} - const char *GetName() override { return nullptr; } + // CPUCoreBase methods + void Init() override {} + void Shutdown() override {} + void ClearCache() override {} + void Run() override {} + void SingleStep() override {} + const char* GetName() override { return nullptr; } + // JitBase methods + JitBaseBlockCache* GetBlockCache() override { return nullptr; } + void Jit(u32 em_address) override {} + const CommonAsmRoutinesBase* GetAsmRoutines() override { return nullptr; } + virtual bool HandleFault(uintptr_t access_address, SContext* ctx) override + { + m_pre_unprotect_time = std::chrono::high_resolution_clock::now(); + UnWriteProtectMemory(m_data, PAGE_GRAN, /*allowExecute*/ false); + m_post_unprotect_time = std::chrono::high_resolution_clock::now(); + return true; + } - // JitBase methods - JitBaseBlockCache *GetBlockCache() override { return nullptr; } - void Jit(u32 em_address) override {} - const CommonAsmRoutinesBase *GetAsmRoutines() override { return nullptr; } - - virtual bool HandleFault(uintptr_t access_address, SContext* ctx) override - { - m_pre_unprotect_time = std::chrono::high_resolution_clock::now(); - UnWriteProtectMemory(m_data, PAGE_GRAN, /*allowExecute*/ false); - m_post_unprotect_time = std::chrono::high_resolution_clock::now(); - return true; - } - - void* m_data; - std::chrono::time_point - m_pre_unprotect_time, m_post_unprotect_time; + void* m_data; + std::chrono::time_point m_pre_unprotect_time, + m_post_unprotect_time; }; - TEST(PageFault, PageFault) { - EMM::InstallExceptionHandler(); - void* data = AllocateMemoryPages(PAGE_GRAN); - EXPECT_NE(data, nullptr); - WriteProtectMemory(data, PAGE_GRAN, false); + EMM::InstallExceptionHandler(); + void* data = AllocateMemoryPages(PAGE_GRAN); + EXPECT_NE(data, nullptr); + WriteProtectMemory(data, PAGE_GRAN, false); - PageFaultFakeJit pfjit; - jit = &pfjit; - pfjit.m_data = data; + PageFaultFakeJit pfjit; + jit = &pfjit; + pfjit.m_data = data; - auto start = std::chrono::high_resolution_clock::now(); - *(volatile int*) data = 5; - auto end = std::chrono::high_resolution_clock::now(); + auto start = std::chrono::high_resolution_clock::now(); + *(volatile int*)data = 5; + auto end = std::chrono::high_resolution_clock::now(); - #define AS_NS(diff) ((unsigned long long)std::chrono::duration_cast(diff).count()) +#define AS_NS(diff) \ + ((unsigned long long)std::chrono::duration_cast(diff).count()) - EMM::UninstallExceptionHandler(); - jit = nullptr; + EMM::UninstallExceptionHandler(); + jit = nullptr; - printf("page fault timing:\n"); - printf("start->HandleFault %llu ns\n", AS_NS(pfjit.m_pre_unprotect_time - start)); - printf("UnWriteProtectMemory %llu ns\n", AS_NS(pfjit.m_post_unprotect_time - pfjit.m_pre_unprotect_time)); - printf("HandleFault->end %llu ns\n", AS_NS(end - pfjit.m_post_unprotect_time)); - printf("total %llu ns\n", AS_NS(end - start)); + printf("page fault timing:\n"); + printf("start->HandleFault %llu ns\n", AS_NS(pfjit.m_pre_unprotect_time - start)); + printf("UnWriteProtectMemory %llu ns\n", + AS_NS(pfjit.m_post_unprotect_time - pfjit.m_pre_unprotect_time)); + printf("HandleFault->end %llu ns\n", AS_NS(end - pfjit.m_post_unprotect_time)); + printf("total %llu ns\n", AS_NS(end - start)); } diff --git a/Source/UnitTests/TestUtils/StubHost.cpp b/Source/UnitTests/TestUtils/StubHost.cpp index ac83093b9f..cf2f4453fc 100644 --- a/Source/UnitTests/TestUtils/StubHost.cpp +++ b/Source/UnitTests/TestUtils/StubHost.cpp @@ -11,20 +11,59 @@ #include "Common/GL/GLInterfaceBase.h" #include "Core/Host.h" -void Host_NotifyMapLoaded() {} -void Host_RefreshDSPDebuggerWindow() {} -void Host_Message(int) {} -void* Host_GetRenderHandle() { return nullptr; } -void Host_UpdateTitle(const std::string&) {} -void Host_UpdateDisasmDialog() {} -void Host_UpdateMainFrame() {} -void Host_RequestRenderWindowSize(int, int) {} -void Host_RequestFullscreen(bool) {} -void Host_SetStartupDebuggingParameters() {} -bool Host_UIHasFocus() { return false; } -bool Host_RendererHasFocus() { return false; } -bool Host_RendererIsFullscreen() { return false; } -void Host_ConnectWiimote(int, bool) {} -void Host_SetWiiMoteConnectionState(int) {} -void Host_ShowVideoConfig(void*, const std::string&, const std::string&) {} -std::unique_ptr HostGL_CreateGLInterface() { return nullptr; } +void Host_NotifyMapLoaded() +{ +} +void Host_RefreshDSPDebuggerWindow() +{ +} +void Host_Message(int) +{ +} +void* Host_GetRenderHandle() +{ + return nullptr; +} +void Host_UpdateTitle(const std::string&) +{ +} +void Host_UpdateDisasmDialog() +{ +} +void Host_UpdateMainFrame() +{ +} +void Host_RequestRenderWindowSize(int, int) +{ +} +void Host_RequestFullscreen(bool) +{ +} +void Host_SetStartupDebuggingParameters() +{ +} +bool Host_UIHasFocus() +{ + return false; +} +bool Host_RendererHasFocus() +{ + return false; +} +bool Host_RendererIsFullscreen() +{ + return false; +} +void Host_ConnectWiimote(int, bool) +{ +} +void Host_SetWiiMoteConnectionState(int) +{ +} +void Host_ShowVideoConfig(void*, const std::string&, const std::string&) +{ +} +std::unique_ptr HostGL_CreateGLInterface() +{ + return nullptr; +} diff --git a/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp b/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp index fd0b23b0d4..d96694fbb8 100644 --- a/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp +++ b/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp @@ -20,23 +20,23 @@ TEST(VertexLoaderUID, UniqueEnough) { - std::unordered_set uids; + std::unordered_set uids; - TVtxDesc vtx_desc; - memset(&vtx_desc, 0, sizeof(vtx_desc)); - VAT vat; - memset(&vat, 0, sizeof(vat)); - uids.insert(VertexLoaderUID(vtx_desc, vat)); + TVtxDesc vtx_desc; + memset(&vtx_desc, 0, sizeof(vtx_desc)); + VAT vat; + memset(&vat, 0, sizeof(vat)); + uids.insert(VertexLoaderUID(vtx_desc, vat)); - vtx_desc.Hex = 0xFEDCBA9876543210ull; - EXPECT_EQ(uids.end(), uids.find(VertexLoaderUID(vtx_desc, vat))); - uids.insert(VertexLoaderUID(vtx_desc, vat)); + vtx_desc.Hex = 0xFEDCBA9876543210ull; + EXPECT_EQ(uids.end(), uids.find(VertexLoaderUID(vtx_desc, vat))); + uids.insert(VertexLoaderUID(vtx_desc, vat)); - vat.g0.Hex = 0xFFFFFFFF; - vat.g1.Hex = 0xFFFFFFFF; - vat.g2.Hex = 0xFFFFFFFF; - EXPECT_EQ(uids.end(), uids.find(VertexLoaderUID(vtx_desc, vat))); - uids.insert(VertexLoaderUID(vtx_desc, vat)); + vat.g0.Hex = 0xFFFFFFFF; + vat.g1.Hex = 0xFFFFFFFF; + vat.g2.Hex = 0xFFFFFFFF; + EXPECT_EQ(uids.end(), uids.find(VertexLoaderUID(vtx_desc, vat))); + uids.insert(VertexLoaderUID(vtx_desc, vat)); } static u8 input_memory[16 * 1024 * 1024]; @@ -45,267 +45,311 @@ static u8 output_memory[16 * 1024 * 1024]; class VertexLoaderTest : public testing::Test { protected: + void SetUp() override + { + memset(input_memory, 0, sizeof(input_memory)); + memset(output_memory, 0xFF, sizeof(input_memory)); - void SetUp() override - { - memset(input_memory, 0, sizeof(input_memory)); - memset(output_memory, 0xFF, sizeof(input_memory)); + memset(&m_vtx_desc, 0, sizeof(m_vtx_desc)); + memset(&m_vtx_attr, 0, sizeof(m_vtx_attr)); - memset(&m_vtx_desc, 0, sizeof(m_vtx_desc)); - memset(&m_vtx_attr, 0, sizeof(m_vtx_attr)); + m_loader = nullptr; - m_loader = nullptr; + ResetPointers(); + } - ResetPointers(); - } + void CreateAndCheckSizes(size_t input_size, size_t output_size) + { + m_loader = VertexLoaderBase::CreateVertexLoader(m_vtx_desc, m_vtx_attr); + ASSERT_EQ((int)input_size, m_loader->m_VertexSize); + ASSERT_EQ((int)output_size, m_loader->m_native_vtx_decl.stride); + } - void CreateAndCheckSizes(size_t input_size, size_t output_size) - { - m_loader = VertexLoaderBase::CreateVertexLoader(m_vtx_desc, m_vtx_attr); - ASSERT_EQ((int)input_size, m_loader->m_VertexSize); - ASSERT_EQ((int)output_size, m_loader->m_native_vtx_decl.stride); - } + template + void Input(T val) + { + // Write swapped. + m_src.Write(val); + } - template - void Input(T val) - { - // Write swapped. - m_src.Write(val); - } + void ExpectOut(float val) + { + // Read unswapped. + MathUtil::IntFloat expected(val), actual(m_dst.Read()); + if (!actual.f || actual.f != actual.f) + EXPECT_EQ(expected.i, actual.i); + else + EXPECT_EQ(expected.f, actual.f); + } - void ExpectOut(float val) - { - // Read unswapped. - MathUtil::IntFloat expected(val), actual(m_dst.Read()); - if (!actual.f || actual.f != actual.f) - EXPECT_EQ(expected.i, actual.i); - else - EXPECT_EQ(expected.f, actual.f); - } + void RunVertices(int count, int expected_count = -1) + { + if (expected_count == -1) + expected_count = count; + ResetPointers(); + int actual_count = m_loader->RunVertices(m_src, m_dst, count); + EXPECT_EQ(actual_count, expected_count); + } - void RunVertices(int count, int expected_count = -1) - { - if (expected_count == -1) - expected_count = count; - ResetPointers(); - int actual_count = m_loader->RunVertices(m_src, m_dst, count); - EXPECT_EQ(actual_count, expected_count); - } + void ResetPointers() + { + m_src = DataReader(input_memory, input_memory + sizeof(input_memory)); + m_dst = DataReader(output_memory, output_memory + sizeof(output_memory)); + } - void ResetPointers() - { - m_src = DataReader(input_memory, input_memory + sizeof(input_memory)); - m_dst = DataReader(output_memory, output_memory + sizeof(output_memory)); - } + DataReader m_src; + DataReader m_dst; - DataReader m_src; - DataReader m_dst; - - TVtxDesc m_vtx_desc; - VAT m_vtx_attr; - std::unique_ptr m_loader; + TVtxDesc m_vtx_desc; + VAT m_vtx_attr; + std::unique_ptr m_loader; }; -class VertexLoaderParamTest : public VertexLoaderTest, public ::testing::WithParamInterface> {}; +class VertexLoaderParamTest : public VertexLoaderTest, + public ::testing::WithParamInterface> +{ +}; extern int gtest_AllCombinationsVertexLoaderParamTest_dummy_; -INSTANTIATE_TEST_CASE_P( - AllCombinations, VertexLoaderParamTest, - ::testing::Combine( - ::testing::Values(DIRECT, INDEX8, INDEX16), - ::testing::Values(FORMAT_UBYTE, FORMAT_BYTE, FORMAT_USHORT, FORMAT_SHORT, FORMAT_FLOAT), - ::testing::Values(0, 1), // elements - ::testing::Values(0, 1, 31) // frac - ) -); +INSTANTIATE_TEST_CASE_P(AllCombinations, VertexLoaderParamTest, + ::testing::Combine(::testing::Values(DIRECT, INDEX8, INDEX16), + ::testing::Values(FORMAT_UBYTE, FORMAT_BYTE, + FORMAT_USHORT, FORMAT_SHORT, + FORMAT_FLOAT), + ::testing::Values(0, 1), // elements + ::testing::Values(0, 1, 31) // frac + )); TEST_P(VertexLoaderParamTest, PositionAll) { - int addr, format, elements, frac; - std::tie(addr, format, elements, frac) = GetParam(); - this->m_vtx_desc.Position = addr; - this->m_vtx_attr.g0.PosFormat = format; - this->m_vtx_attr.g0.PosElements = elements; - this->m_vtx_attr.g0.PosFrac = frac; - this->m_vtx_attr.g0.ByteDequant = true; - elements += 2; + int addr, format, elements, frac; + std::tie(addr, format, elements, frac) = GetParam(); + this->m_vtx_desc.Position = addr; + this->m_vtx_attr.g0.PosFormat = format; + this->m_vtx_attr.g0.PosElements = elements; + this->m_vtx_attr.g0.PosFrac = frac; + this->m_vtx_attr.g0.ByteDequant = true; + elements += 2; - std::vector values = { - std::numeric_limits::lowest(), - std::numeric_limits::denorm_min(), - std::numeric_limits::min(), - std::numeric_limits::max(), - std::numeric_limits::quiet_NaN(), - std::numeric_limits::infinity(), - -0x8000, -0x80, -1, -0, 0, 1, 123, 0x7F, 0xFF, 0x7FFF, 0xFFFF, 12345678, - }; - ASSERT_EQ(0u, values.size() % 2); - ASSERT_EQ(0u, values.size() % 3); + std::vector values = { + std::numeric_limits::lowest(), + std::numeric_limits::denorm_min(), + std::numeric_limits::min(), + std::numeric_limits::max(), + std::numeric_limits::quiet_NaN(), + std::numeric_limits::infinity(), + -0x8000, + -0x80, + -1, + -0, + 0, + 1, + 123, + 0x7F, + 0xFF, + 0x7FFF, + 0xFFFF, + 12345678, + }; + ASSERT_EQ(0u, values.size() % 2); + ASSERT_EQ(0u, values.size() % 3); - int count = (int)values.size() / elements; - u32 elem_size = 1 << (format / 2); - size_t input_size = elements * elem_size; - if (addr & MASK_INDEXED) - { - input_size = addr - 1; - for (int i = 0; i < count; i++) - if (addr == INDEX8) - Input(i); - else - Input(i); - VertexLoaderManager::cached_arraybases[ARRAY_POSITION] = m_src.GetPointer(); - g_main_cp_state.array_strides[ARRAY_POSITION] = elements * elem_size; - } - CreateAndCheckSizes(input_size, elements * sizeof(float)); - for (float value : values) - { - switch (format) - { - case FORMAT_UBYTE: Input((u8)value); break; - case FORMAT_BYTE: Input((s8)value); break; - case FORMAT_USHORT: Input((u16)value); break; - case FORMAT_SHORT: Input((s16)value); break; - case FORMAT_FLOAT: Input(value); break; - } - } + int count = (int)values.size() / elements; + u32 elem_size = 1 << (format / 2); + size_t input_size = elements * elem_size; + if (addr & MASK_INDEXED) + { + input_size = addr - 1; + for (int i = 0; i < count; i++) + if (addr == INDEX8) + Input(i); + else + Input(i); + VertexLoaderManager::cached_arraybases[ARRAY_POSITION] = m_src.GetPointer(); + g_main_cp_state.array_strides[ARRAY_POSITION] = elements * elem_size; + } + CreateAndCheckSizes(input_size, elements * sizeof(float)); + for (float value : values) + { + switch (format) + { + case FORMAT_UBYTE: + Input((u8)value); + break; + case FORMAT_BYTE: + Input((s8)value); + break; + case FORMAT_USHORT: + Input((u16)value); + break; + case FORMAT_SHORT: + Input((s16)value); + break; + case FORMAT_FLOAT: + Input(value); + break; + } + } - RunVertices(count); + RunVertices(count); - float scale = 1.f / (1u << (format == FORMAT_FLOAT ? 0 : frac)); - for (auto iter = values.begin(); iter != values.end();) - { - float f, g; - switch (format) - { - case FORMAT_UBYTE: f = (u8)*iter++; g = (u8)*iter++; break; - case FORMAT_BYTE: f = (s8)*iter++; g = (s8)*iter++; break; - case FORMAT_USHORT: f = (u16)*iter++; g = (u16)*iter++; break; - case FORMAT_SHORT: f = (s16)*iter++; g = (s16)*iter++; break; - case FORMAT_FLOAT: f = *iter++; g = *iter++; break; - } - ExpectOut(f * scale); - ExpectOut(g * scale); - } + float scale = 1.f / (1u << (format == FORMAT_FLOAT ? 0 : frac)); + for (auto iter = values.begin(); iter != values.end();) + { + float f, g; + switch (format) + { + case FORMAT_UBYTE: + f = (u8)*iter++; + g = (u8)*iter++; + break; + case FORMAT_BYTE: + f = (s8)*iter++; + g = (s8)*iter++; + break; + case FORMAT_USHORT: + f = (u16)*iter++; + g = (u16)*iter++; + break; + case FORMAT_SHORT: + f = (s16)*iter++; + g = (s16)*iter++; + break; + case FORMAT_FLOAT: + f = *iter++; + g = *iter++; + break; + } + ExpectOut(f * scale); + ExpectOut(g * scale); + } } TEST_F(VertexLoaderTest, PositionIndex16FloatXY) { - m_vtx_desc.Position = INDEX16; - m_vtx_attr.g0.PosFormat = FORMAT_FLOAT; - CreateAndCheckSizes(sizeof(u16), 2 * sizeof(float)); - Input(1); Input(0); - VertexLoaderManager::cached_arraybases[ARRAY_POSITION] = m_src.GetPointer(); - g_main_cp_state.array_strides[ARRAY_POSITION] = sizeof(float); // ;) - Input(1.f); Input(2.f); Input(3.f); - RunVertices(2); - ExpectOut(2); ExpectOut(3); - ExpectOut(1); ExpectOut(2); + m_vtx_desc.Position = INDEX16; + m_vtx_attr.g0.PosFormat = FORMAT_FLOAT; + CreateAndCheckSizes(sizeof(u16), 2 * sizeof(float)); + Input(1); + Input(0); + VertexLoaderManager::cached_arraybases[ARRAY_POSITION] = m_src.GetPointer(); + g_main_cp_state.array_strides[ARRAY_POSITION] = sizeof(float); // ;) + Input(1.f); + Input(2.f); + Input(3.f); + RunVertices(2); + ExpectOut(2); + ExpectOut(3); + ExpectOut(1); + ExpectOut(2); } -class VertexLoaderSpeedTest : public VertexLoaderTest, public ::testing::WithParamInterface> {}; +class VertexLoaderSpeedTest : public VertexLoaderTest, + public ::testing::WithParamInterface> +{ +}; extern int gtest_FormatsAndElementsVertexLoaderSpeedTest_dummy_; -INSTANTIATE_TEST_CASE_P( - FormatsAndElements, VertexLoaderSpeedTest, - ::testing::Combine( - ::testing::Values(FORMAT_UBYTE, FORMAT_BYTE, FORMAT_USHORT, FORMAT_SHORT, FORMAT_FLOAT), - ::testing::Values(0, 1) // elements - ) -); +INSTANTIATE_TEST_CASE_P(FormatsAndElements, VertexLoaderSpeedTest, + ::testing::Combine(::testing::Values(FORMAT_UBYTE, FORMAT_BYTE, + FORMAT_USHORT, FORMAT_SHORT, + FORMAT_FLOAT), + ::testing::Values(0, 1) // elements + )); TEST_P(VertexLoaderSpeedTest, PositionDirectAll) { - int format, elements; - std::tie(format, elements) = GetParam(); - const char* map[] = { "u8", "s8", "u16", "s16", "float" }; - printf("format: %s, elements: %d\n", map[format], elements); - m_vtx_desc.Position = DIRECT; - m_vtx_attr.g0.PosFormat = format; - m_vtx_attr.g0.PosElements = elements; - elements += 2; - size_t elem_size = static_cast(1) << (format / 2); - CreateAndCheckSizes(elements * elem_size, elements * sizeof(float)); - for (int i = 0; i < 1000; ++i) - RunVertices(100000); + int format, elements; + std::tie(format, elements) = GetParam(); + const char* map[] = {"u8", "s8", "u16", "s16", "float"}; + printf("format: %s, elements: %d\n", map[format], elements); + m_vtx_desc.Position = DIRECT; + m_vtx_attr.g0.PosFormat = format; + m_vtx_attr.g0.PosElements = elements; + elements += 2; + size_t elem_size = static_cast(1) << (format / 2); + CreateAndCheckSizes(elements * elem_size, elements * sizeof(float)); + for (int i = 0; i < 1000; ++i) + RunVertices(100000); } TEST_P(VertexLoaderSpeedTest, TexCoordSingleElement) { - int format, elements; - std::tie(format, elements) = GetParam(); - const char* map[] = { "u8", "s8", "u16", "s16", "float" }; - printf("format: %s, elements: %d\n", map[format], elements); - m_vtx_desc.Position = DIRECT; - m_vtx_attr.g0.PosFormat = FORMAT_BYTE; - m_vtx_desc.Tex0Coord = DIRECT; - m_vtx_attr.g0.Tex0CoordFormat = format; - m_vtx_attr.g0.Tex0CoordElements = elements; - elements += 1; - size_t elem_size = static_cast(1) << (format / 2); - CreateAndCheckSizes(2 * sizeof(s8) + elements * elem_size, - 2 * sizeof(float) + elements * sizeof(float)); - for (int i = 0; i < 1000; ++i) - RunVertices(100000); + int format, elements; + std::tie(format, elements) = GetParam(); + const char* map[] = {"u8", "s8", "u16", "s16", "float"}; + printf("format: %s, elements: %d\n", map[format], elements); + m_vtx_desc.Position = DIRECT; + m_vtx_attr.g0.PosFormat = FORMAT_BYTE; + m_vtx_desc.Tex0Coord = DIRECT; + m_vtx_attr.g0.Tex0CoordFormat = format; + m_vtx_attr.g0.Tex0CoordElements = elements; + elements += 1; + size_t elem_size = static_cast(1) << (format / 2); + CreateAndCheckSizes(2 * sizeof(s8) + elements * elem_size, + 2 * sizeof(float) + elements * sizeof(float)); + for (int i = 0; i < 1000; ++i) + RunVertices(100000); } TEST_F(VertexLoaderTest, LargeFloatVertexSpeed) { - // Enables most attributes in floating point indexed mode to test speed. - m_vtx_desc.PosMatIdx = 1; - m_vtx_desc.Tex0MatIdx = 1; - m_vtx_desc.Tex1MatIdx = 1; - m_vtx_desc.Tex2MatIdx = 1; - m_vtx_desc.Tex3MatIdx = 1; - m_vtx_desc.Tex4MatIdx = 1; - m_vtx_desc.Tex5MatIdx = 1; - m_vtx_desc.Tex6MatIdx = 1; - m_vtx_desc.Tex7MatIdx = 1; - m_vtx_desc.Position = INDEX16; - m_vtx_desc.Normal = INDEX16; - m_vtx_desc.Color0 = INDEX16; - m_vtx_desc.Color1 = INDEX16; - m_vtx_desc.Tex0Coord = INDEX16; - m_vtx_desc.Tex1Coord = INDEX16; - m_vtx_desc.Tex2Coord = INDEX16; - m_vtx_desc.Tex3Coord = INDEX16; - m_vtx_desc.Tex4Coord = INDEX16; - m_vtx_desc.Tex5Coord = INDEX16; - m_vtx_desc.Tex6Coord = INDEX16; - m_vtx_desc.Tex7Coord = INDEX16; + // Enables most attributes in floating point indexed mode to test speed. + m_vtx_desc.PosMatIdx = 1; + m_vtx_desc.Tex0MatIdx = 1; + m_vtx_desc.Tex1MatIdx = 1; + m_vtx_desc.Tex2MatIdx = 1; + m_vtx_desc.Tex3MatIdx = 1; + m_vtx_desc.Tex4MatIdx = 1; + m_vtx_desc.Tex5MatIdx = 1; + m_vtx_desc.Tex6MatIdx = 1; + m_vtx_desc.Tex7MatIdx = 1; + m_vtx_desc.Position = INDEX16; + m_vtx_desc.Normal = INDEX16; + m_vtx_desc.Color0 = INDEX16; + m_vtx_desc.Color1 = INDEX16; + m_vtx_desc.Tex0Coord = INDEX16; + m_vtx_desc.Tex1Coord = INDEX16; + m_vtx_desc.Tex2Coord = INDEX16; + m_vtx_desc.Tex3Coord = INDEX16; + m_vtx_desc.Tex4Coord = INDEX16; + m_vtx_desc.Tex5Coord = INDEX16; + m_vtx_desc.Tex6Coord = INDEX16; + m_vtx_desc.Tex7Coord = INDEX16; - m_vtx_attr.g0.PosElements = 1; // XYZ - m_vtx_attr.g0.PosFormat = FORMAT_FLOAT; - m_vtx_attr.g0.NormalElements = 1; // NBT - m_vtx_attr.g0.NormalFormat = FORMAT_FLOAT; - m_vtx_attr.g0.Color0Elements = 1; // Has Alpha - m_vtx_attr.g0.Color0Comp = FORMAT_32B_8888; - m_vtx_attr.g0.Color1Elements = 1; // Has Alpha - m_vtx_attr.g0.Color1Comp = FORMAT_32B_8888; - m_vtx_attr.g0.Tex0CoordElements = 1; // ST - m_vtx_attr.g0.Tex0CoordFormat = FORMAT_FLOAT; - m_vtx_attr.g1.Tex1CoordElements = 1; // ST - m_vtx_attr.g1.Tex1CoordFormat = FORMAT_FLOAT; - m_vtx_attr.g1.Tex2CoordElements = 1; // ST - m_vtx_attr.g1.Tex2CoordFormat = FORMAT_FLOAT; - m_vtx_attr.g1.Tex3CoordElements = 1; // ST - m_vtx_attr.g1.Tex3CoordFormat = FORMAT_FLOAT; - m_vtx_attr.g1.Tex4CoordElements = 1; // ST - m_vtx_attr.g1.Tex4CoordFormat = FORMAT_FLOAT; - m_vtx_attr.g2.Tex5CoordElements = 1; // ST - m_vtx_attr.g2.Tex5CoordFormat = FORMAT_FLOAT; - m_vtx_attr.g2.Tex6CoordElements = 1; // ST - m_vtx_attr.g2.Tex6CoordFormat = FORMAT_FLOAT; - m_vtx_attr.g2.Tex7CoordElements = 1; // ST - m_vtx_attr.g2.Tex7CoordFormat = FORMAT_FLOAT; + m_vtx_attr.g0.PosElements = 1; // XYZ + m_vtx_attr.g0.PosFormat = FORMAT_FLOAT; + m_vtx_attr.g0.NormalElements = 1; // NBT + m_vtx_attr.g0.NormalFormat = FORMAT_FLOAT; + m_vtx_attr.g0.Color0Elements = 1; // Has Alpha + m_vtx_attr.g0.Color0Comp = FORMAT_32B_8888; + m_vtx_attr.g0.Color1Elements = 1; // Has Alpha + m_vtx_attr.g0.Color1Comp = FORMAT_32B_8888; + m_vtx_attr.g0.Tex0CoordElements = 1; // ST + m_vtx_attr.g0.Tex0CoordFormat = FORMAT_FLOAT; + m_vtx_attr.g1.Tex1CoordElements = 1; // ST + m_vtx_attr.g1.Tex1CoordFormat = FORMAT_FLOAT; + m_vtx_attr.g1.Tex2CoordElements = 1; // ST + m_vtx_attr.g1.Tex2CoordFormat = FORMAT_FLOAT; + m_vtx_attr.g1.Tex3CoordElements = 1; // ST + m_vtx_attr.g1.Tex3CoordFormat = FORMAT_FLOAT; + m_vtx_attr.g1.Tex4CoordElements = 1; // ST + m_vtx_attr.g1.Tex4CoordFormat = FORMAT_FLOAT; + m_vtx_attr.g2.Tex5CoordElements = 1; // ST + m_vtx_attr.g2.Tex5CoordFormat = FORMAT_FLOAT; + m_vtx_attr.g2.Tex6CoordElements = 1; // ST + m_vtx_attr.g2.Tex6CoordFormat = FORMAT_FLOAT; + m_vtx_attr.g2.Tex7CoordElements = 1; // ST + m_vtx_attr.g2.Tex7CoordFormat = FORMAT_FLOAT; - CreateAndCheckSizes(33, 156); + CreateAndCheckSizes(33, 156); - for (int i = 0; i < 12; i++) - { - VertexLoaderManager::cached_arraybases[i] = m_src.GetPointer(); - g_main_cp_state.array_strides[i] = 129; - } + for (int i = 0; i < 12; i++) + { + VertexLoaderManager::cached_arraybases[i] = m_src.GetPointer(); + g_main_cp_state.array_strides[i] = 129; + } - // This test is only done 100x in a row since it's ~20x slower using the - // current vertex loader implementation. - for (int i = 0; i < 100; ++i) - RunVertices(100000); + // This test is only done 100x in a row since it's ~20x slower using the + // current vertex loader implementation. + for (int i = 0; i < 100; ++i) + RunVertices(100000); }